本文共 4199 字,大约阅读时间需要 13 分钟。
摘要: 线性回归是众所周知的非常基本的算法,但也存在很多不足。为了是算法模型能够具有更好的泛化能够,不至于模型过拟合,当前研究就传统的线性回归算法的基础上增加正则项,添加 l 1 l_1 l1正则就是LASSO回归,添加 l 2 l_2 l2正则就是岭回归,本文通过对这几个算法进行比较来说明各自的特点。
关键字: 线性回归,岭回归,LASSO回归。
线性回归算法是机器学习算法中的一个入门算法,简单容易理解,但是传统的线性回归算法有很多缺点,容易过拟合等等。为了克服这种缺点,当前研究提出增加正则项(很多机器学习方法都使用)的方式降低模型的过拟合,提高模型的泛化能力。
传统对于有一个有 n n n个特征的数据 x x x的线性回归模型如下,也可参考我之前的文章:。
h ( x ) = w 1 x 1 + w 2 x 2 + ⋯ + w n x n + b h\left( x \right) =w_1x_1+w_2x_2+\cdots +w_nx_n+b h(x)=w1x1+w2x2+⋯+wnxn+b 对于一些线性回归的任务可以做,但是不采取一些方式容易过拟合(机器学习算法都是如此)。我们使用波斯顿房价数据集看看,处理过的波斯顿房价数据集的特征增加到了105个。from sklearn.linear_model import LinearRegressionfrom sklearn.datasets import load_bostonfrom sklearn.preprocessing import MinMaxScaler, PolynomialFeaturesfrom sklearn.model_selection import train_test_splitdef load_extended_boston(): boston = load_boston() X = boston.data X = MinMaxScaler().fit_transform(boston.data) # 数据归一化处理 # 使用多项式的方法来进行的,如果有a,b两个特征,那么它的2次多项式为(1,a,b,a^2,ab, b^2),degree:控制多项式的度 # interaction_only: 默认为False,如果指定为True,那么就不会有特征自己和自己结合的项,上面的二次项中没有a^2和b^2。 # include_bias:默认为True。如果为True的话,那么就会有上面的 1那一项。 X = PolynomialFeatures(degree=2, include_bias=False).fit_transform(X) return X, boston.targetX, y = load_extended_boston()X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)lr = LinearRegression().fit(X_train, y_train)print("Training set score:{:.2f}".format(lr.score(X_train, y_train))) # 训练集的测试分数print("Training set score:{:.2f}".format(lr.score(X_test, y_test))) # 测试集的测试分数"""Training set score:0.95Training set score:0.61"""
从测试得分可以看出,在训练集得分较高而测试集分数较低,也就是说过拟合了。
补充: 如何查看训练好模型中的权重参数 w w w和截距 b b b呢?其分布保存在:coef_
和intercept_
,查看方式如下: print("lr.coef_:{}".format(lr.coef_))print("lr.intercept_:{}".format(lr.intercept_))"""lr.coef_:[-4.12710947e+02 -5.22432068e+01 -1.31898815e+02 -1.20041365e+01 -1.55107129e+01 2.87163342e+01 5.47040992e+01 -4.95346659e+01.... 1.19553429e+01 6.77025947e-01 2.73452009e+00 3.03720012e+01]lr.intercept_:30.934563673637694"""
岭回归也是一种用于回归的线性模型,与传统的线性模型有很多相似之处。为了降低过拟合的情况,也就是说不仅要在训练集上的数据效果好,在测试集上的数据也要好,这样模型才具有不错的泛化能力。这里是希望特征数据的权重尽可能小,减小数据受权重的制约,一般来说,我们是权重参数 w w w接近于0。这里就引入正则化(regularization),避免模型过拟合。岭回归就是具有 l 2 l_2 l2正则化的回归,相关内容可以参考:。下面我们来看看如何使用sklearn实现岭回归。
from sklearn.linear_model import Ridgeridge = Ridge().fit(X_train, y_train)print("Training set score:{:.2f}".format(ridge.score(X_train, y_train))) # 训练集的测试分数print("Training set score:{:.2f}".format(ridge.score(X_test, y_test))) # 测试集的测试分数"""Training set score:0.89Training set score:0.75"""
从结果可以看出Ridge训练集的分数低于LinerRegression,在测试集上的分数更高。这就是使用正则降低过拟合的结果。当然我们也可以通过修改参数alpha指定正则化项的系数,Ridge默认是1。当然,alpha过大过小都不好,这也是需要进行模型调参了,因为这是需要根据数据集进行处理的。例如我们使用alpha=0.5来测试一下模型的性能:
ridge = Ridge(alpha=0.5).fit(X_train, y_train)print("Training set score:{:.2f}".format(ridge.score(X_train, y_train))) # 训练集的测试分数print("Training set score:{:.2f}".format(ridge.score(X_test, y_test))) # 测试集的测试分数"""Training set score:0.90Training set score:0.77"""
注意,减小alpha可以让系数(w)受到的限制更小,当alpha特别小的时候就可以普通的LinearRegression没什么区别了。使用正则化进行优化模型的相关概念在已经介绍,不再赘述。
这种方法是 l 1 l_1 l1正则化(就是系数绝对值之和)。使用lasso时某些系数刚好为0(这是一个最优化问题,可参考文献1),也就是一些特征就会被模型忽略了。下面我们做一下实验:
from sklearn.linear_model import Lassoimport numpy as nplasso = Lasso().fit(X_train, y_train)print("Training set score:{:.2f}".format(lasso.score(X_train, y_train)))print("Test set score:{:.2f}".format(lasso.score(X_test, y_test)))print("Number of features used:{}".format(np.sum(lasso.coef_ != 0)))"""Training set score:0.29Test set score:0.21Number of features used:4"""
可以看出这个结果惨不忍睹,使用的特征也仅仅只有4个。这时我们就需要通过控制正则化的系数alpha(默认为1.0)来改变这个状况。同时,为了降低欠拟合,可以尝试较小alpha,这个和Ridge相似,并且还需要增加max_iter的值,即增加运行迭代的最大次数。修改如下:
lasso001 = Lasso(alpha=0.01, max_iter=100000).fit(X_train, y_train)print("Training set score:{:.2f}".format(lasso001.score(X_train, y_train)))print("Test set score:{:.2f}".format(lasso001.score(X_test, y_test)))print("Number of features used:{}".format(np.sum(lasso001.coef_ != 0)))"""Training set score:0.90Test set score:0.77Number of features used:33"""
这个时候我们就可以看出,不管是在训练集上还是测试集上表现得都挺不错,同时也只是用了105个特征中的33个。当然如果将alpha这个参数调得太小也就和传统得LinearRegression类似了。