LASSO回归原理和Python代码 | 线性回归 | 交叉验证
背景回顾:
- 线性回归的基本概念,应用场景?
- 回顾Coursera上ML的基本概念,什么是hypothesis?什么是cost function?什么是objective function?
- LASSO回归的基本概念,跟普通回归有什么区别?解决了模型的哪些缺陷?
- 构建LASSO回归模型的基本步骤?
- Python代码实现,搞清楚函数所在的包,以及每个函数参数的意义
- 搞清楚每种模型里面的核心参数,如何得到最佳参数?如LASSO就一个alpha参数,数据集小CV即可,数据集大就看在验证集上的表现。
- 数据:训练集、验证集、测试集
更大的问题:
- 关于ML和DL你要学习到什么程度?死扣数学,还是会copy代码,跑出结果?根据自己的定位找到一个balance
- 如何根据自己的问题去找高质量的数据,并且选择合适的model,最后给出一个漂亮的endpoint结果
- 因为现在割Python包做得越来越好了,很多ML和DL的model很快就可以建立起来跑通,并且效果不错
- 所以关键就落在:问题、高质量数据集、选择模型、模型评估、高阶内容(confounder)
线性回归
以基因表达矩阵举例,可以拿来预测很多内容:比如proliferation和migration ability,还有age,这本质就是一个监督学习的模型,用来预测指定的指标。
数学上的表示也很简单,y = aX + b,这里 X 就是一个 m x n 的矩阵,我们就是要求得 a 和 b 这些参数来确定这个线性模型。
LASSO回归
是线性回归的一种
出现的原因:参数a是一个n维的向量,对于基因表达矩阵,这个n可能是2万到3万,其中某些基因可能是高度相关的【correlated】,另外有些基因可能是毫无关联的,这时我们就要去除掉一些基因。LASSO应运而生!
这里来直接看看scikit的sklearn里面对Lasso的介绍,https://scikit-learn.org/stable/modules/linear_model.html#lasso。
The Lasso is a linear model that estimates sparse coefficients估计稀疏系数. It is useful in some contexts due to its tendency to prefer solutions with fewer non-zero coefficients由于它倾向于选择具有较少非零系数的解决方案, effectively reducing the number of features upon which the given solution is dependent. For this reason, Lasso and its variants are fundamental to the field of compressed sensing压缩感知. Under certain conditions, it can recover the exact set of non-zero coefficients恢复非零系数的精确集合
Lasso也叫 L1,这里需要了解一下范数,通俗理解就是计算距离的方式,类似不同维度空间坐标系。
ML基础知识回顾
y = aX + b,就是模型表示,也叫做hypothesis
Cost function(也叫做Objective function)就是关于a和b的函数,目的就是检验predicted_y和real_y之间的差距,数学形式就是 1/2m ∑(predicted_y - real_y)2. 参考:Cost Function
我们的目标就是最小cost function下,求得的a和b的具体值,argmin (cost function)
求解的方法很多,梯度下降算法就是其中的一种,核心原理就是类似山顶下山,初始化参数,选择斜度(偏导数)最大的地方往下走,然后同步更新参数,直到最后斜率为0,此时即为局部最优解或全局最优解,其中一个核心参数就是步长。【凸凹函数只有全局最优解】
LASSO的数学实现
参见sklearn的教程,看数学公式,链接如上,把维度n看作了一个参数,将其范数加进了cost function里,同时也加了一个weight(α)用于控制权重。
Python代码实现
import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import r2_score # ############################################################################# # Generate some sparse data to play with np.random.seed(42) n_samples, n_features = 50, 100 X = np.random.randn(n_samples, n_features) # Decreasing coef w. alternated signs for visualization idx = np.arange(n_features) coef = (-1) ** idx * np.exp(-idx / 10) coef[10:] = 0 # sparsify coef y = np.dot(X, coef) # Add noise y += 0.01 * np.random.normal(size=n_samples) # Split data in train set and test set n_samples = X.shape[0] X_train, y_train = X[: n_samples // 2], y[: n_samples // 2] X_test, y_test = X[n_samples // 2 :], y[n_samples // 2 :] # ############################################################################# # Lasso from sklearn.linear_model import Lasso alpha = 0.1 lasso = Lasso(alpha=alpha) y_pred_lasso = lasso.fit(X_train, y_train).predict(X_test) r2_score_lasso = r2_score(y_test, y_pred_lasso) print(lasso) print("r^2 on test data : %f" % r2_score_lasso)
优化后的代码
优化内容:
- 加入了交叉验证,防止模型过拟合,也选出了最优的系数外参数,即Lasso的权重α,根据MSE选择最佳的α
- 观察最终线性模型系数的分布,线性模型的就是一堆系数,没有任何多余技巧,LASSO就是选择特征的一种技巧,系数确定还是靠的cost function
from sklearn.linear_model import LassoCV # LassoCV from sklearn.model_selection import StratifiedShuffleSplit # StratifiedShuffleSplit lassocv = LassoCV(alphas=numpy.logspace(-3.5,-0.5,500), fit_intercept=False, positive=True, cv=5) # cv=StratifiedShuffleSplit(n_splits=10, test_size=0.2) lassocv.fit(X_train, y_train) import matplotlib from matplotlib.pyplot import * from numpy import * from pandas import * alpha_df = DataFrame({"alpha":lassocv.alphas_, "mse":lassocv.mse_path_.mean(1)}) best_alpha = alpha_df[alpha_df.mse == alpha_df.mse.max()].alpha matplotlib.pyplot.figure(figsize=(3,2)) axvline(best_alpha.values[0]) plot(lassocv.alphas_, lassocv.mse_path_.mean(1))
# ############################################################################# # Lasso from sklearn.linear_model import Lasso alpha = best_alpha.values[0] lasso = Lasso(alpha=alpha) y_pred_lasso = lasso.fit(X_train, y_train).predict(X_test) r2_score_lasso = r2_score(y_test, y_pred_lasso) print(lasso) print("r^2 on test data : %f" % r2_score_lasso)
plt.hist(lasso.coef_, bins=50)
模型评估
正常情况系,必须要留出一部分数据,或者选一些新数据来独立评估模型的好坏。
参考Alex那篇文章
- Pearson correlation coefficient,r
- Coefficient of determination,R2
- Mean absolute error: MAE
- ε - accuracy
We used multiclass.roc function from the pROC R package to calculate multiclass area under the receiver operating characteristic curve for the accuracy (mAUC) of age bin prediction. 分类模型
AIC BIC
交叉验证
交叉验证是在机器学习建立模型和验证模型参数时常用的办法。交叉验证,顾名思义,就是重复的使用数据,把得到的样本数据进行切分,组合为不同的训练集和测试集,用训练集来训练模型,用测试集来评估模型预测的好坏。在此基础上可以得到多组不同的训练集和测试集,某次训练集中的某样本在下次可能成为测试集中的样本,即所谓“交叉”。
交叉验证的应用场景
交叉验证用在数据不是很充足的时候。比如在我日常项目里面,对于普通适中问题,如果数据样本量小于一万条,我们就会采用交叉验证来训练优化选择模型。如果样本大于一万条的话,我们一般随机的把数据分成三份,一份为训练集(Training Set),一份为验证集(Validation Set),最后一份为测试集(Test Set)。用训练集来训练模型,用验证集来评估模型预测的好坏和选择模型及其对应的参数。把最终得到的模型再用于测试集,最终决定使用哪个模型以及对应参数。
交叉验证种类
第一种是简单交叉验证,所谓的简单,是和其他交叉验证方法相对而言的。首先,我们随机的将样本数据分为两部分(比如: 70%的训练集,30%的测试集),然后用训练集来训练模型,在测试集上验证模型及参数。接着,我们再把样本打乱,重新选择训练集和测试集,继续训练数据和检验模型。最后我们选择损失函数评估最优的模型和参数。
第二种是S折交叉验证(S-Folder Cross Validation)。和第一种方法不同,S折交叉验证会把样本数据随机的分成S份,每次随机的选择S-1份作为训练集,剩下的1份做测试集。当这一轮完成后,重新随机选择S-1份来训练数据。若干轮(小于S)之后,选择损失函数评估最优的模型和参数。
第三种是留一交叉验证(Leave-one-out Cross Validation),它是第二种情况的特例,此时S等于样本数N,这样对于N个样本,每次选择N-1个样本来训练数据,留一个样本来验证模型预测的好坏。此方法主要用于样本量非常少的情况,比如对于普通适中问题,N小于50时,我一般采用留一交叉验证。
一些问题
Q:为什么CV选出来的model不一定有最佳的表现,如R2指标?
CV的目的只是为了防止模型过拟合,它会在拟合模型后,根据留下来的那个数据集来计算MSE(Mean squared error),比如cv=5就会算5次,我们就可以根据这个来选最优的alpha,因为已经防止过拟合了,所以R2指标不好看,但是在新数据上表现肯定会更好。
模型应用实例
lamanno2016-proliferation
Alex的paper
其他线性模型
普通最小二乘法(Ordinary least squares):
以模型预测值与样本观测值的残差平方和最小作为优化目标。
岭回归(Ridge regression)
在普通最小二乘法的基础上增加惩罚因子以减少共线性的影响,以带惩罚项(L2正则化)的残差平方和最小作为优化目标。在指标中同时考虑了较好的学习能力以及较小的惯性能量,以避免过拟合而导致模型泛化能力差。
Lasso 回归(Least absolute shrinkage and selection operator)
在普通最小二乘法的基础上增加绝对值偏差作为惩罚项(L1正则化)以减少共线性的影响,在拟合广义线性模型的同时进行变量筛选和复杂度调整,适用于稀疏系数模型。
多元 Lasso 回归(Multi-task Lasso)
用于估计多元回归稀疏系数的线性模型。注意不是指多线程或多任务,而是指对多个输出变量筛选出相同的特征变量(也即回归系数整列为 0,因此该列对应的输入变量可以被删除)。
弹性网络回归(Elastic-Net)
引入L1和L2范数正则化而构成带有两种惩罚项的模型,相当于岭回归和 Lasso 回归的组合。
Multi-task Elastic-Net
用于估计多元回归稀疏系数线性模型的弹性网络回归方法。
最小角回归算法(Least Angle Regression)
结合前向梯度算法和前向选择算法,在保留前向梯度算法的精确性的同时简化迭代过程。每次选择都加入一个与相关度最高的自变量,最多 m步就可以完成求解。特别适合于特征维度远高于样本数的情况。
LARS Lasso
使用最小角回归算法求解 Lasso模型。
正交匹配追踪法(Orthogonal Matching Pursuit)
用于具有非零系数变量数约束的近似线性模型。在分解的每一步进行正交化处理,选择删除与当前残差最大相关的列,反复迭代达到所需的稀疏程度。
贝叶斯回归(Bayesian Regression)
用贝叶斯推断方法求解的线性回归模型,具有贝叶斯统计模型的基本性质,可以求解权重系数的概率密度函数。可以被用于观测数据较少但要求提供后验分布的问题,例如对物理常数的精确估计;也可以用于变量筛选和降维。
逻辑回归(Logistic Regression)
逻辑回归是一种广义线性模型,研究顺序变量或属性变量作为输出的问题,实际是一种分类方法。通过线性模型加Sigmoid映射函数,将线性模型连续型输出变换为离散值。常用于估计某种事物的可能性,如寻找危险因素、预测发病概率、判断患病概率,是流行病学和医学中最常用的分析方法。
广义线性回归(Generalized Linear Regression)
广义线性回归是线性回归模型的推广,实际上是非线性模型。通过单调可微的联结函数,建立输出变量与输入变量的线性关系,将问题简洁直接地转化为线性模型来处理。
随机梯度下降(Stochastic Gradient Descent)
梯度下降是一种基于搜索的最优化方法,用梯度下降法来求损失函数最小时的参数估计值,适用样本数(和特征数)非常非常大的情况。随机梯度下降法在计算下降方向时,随机选一个数据进行计算,而不是扫描全部训练数据集,加快了迭代速度。
感知机(Perceptron)
感知机是一种适合大规模学习的简单分类算法。训练速度比SGD稍快,并且产生的模型更稀疏。
被动攻击算法(Passive Aggressive Algorithms)
被动攻击算法是一类用于大规模学习的算法。
鲁棒性回归(Robustness regression)
鲁棒性回归的目的是在存在损坏数据的情况下拟合回归模型,如存在异常值或错误的情况。
多项式回归(Polynomial regression)
多项式回归通过构造特征变量的多项式来扩展简单的线性回归模型。例如将特征变量组合成二阶多项式,可以将抛物面拟合到数据中,从而具有更广泛的灵活性和适应性。
逻辑回归到底是线性的还是非线性的?
逻辑回归的模型引入了sigmoid函数映射,是非线性模型,但本质上又是一个线性回归模型,因为除去sigmoid映射函数关系,其他的步骤,算法都是线性回归的。可以说,逻辑回归,都是以线性回归为理论支持的。
只要系数是线性的(没有平方立方啥的),那模型就算是线性的。
学习的核心资源:
- 发表的paper
- scikit-learn,简称sklearn,现成的代码
- Coursera上的ML教程
参考