线性回归(Linear Regression)是采用线性方程作为预测函数,对特定的数据集进行回归拟合,从而得到一个线性模型。比如最简单的线性回归模型:一元线性方程,它的因变量 y 随着自变量 x 的变化而变化,故回归拟合的目的是找到最优参数 w 、 b ,使得此线性函数能最好地拟合已知的数据集(此处假设数据集中只有两列数据,即只有一个属性 x 和它对应的真实值 y )。而由于一元线性方程代表的是一条直线,故当样本数目达到一定数量时,它不可能完美地拟合整个数据集。那么,如何才能选出最优的参数 w 、 b ,使得该简单的线性模型能最好地拟合已知的数据集呢?这里就需要找到模型的损失函数,然后用梯度下降算法来不断学习得到最优参数。本节将详细介绍简单线性回归模型训练的基本步骤。
1. 一元线性模型
已知数据集 X ,对应的结果集 Y ,我们假设预测函数式为:
其中, θ 0 、 θ 1 为待确定的参数。
公式3.23是一元线性模型的预测函数。我们要做的是使用数据集 X 和对应的结果集 Y ,通过不断调整参数 θ 0 、 θ 1 ,使得输入数据集 X 后,预测函数计算得到对应的值 h ( x )与真实的结果集 Y 的整体误差最小,此时找到的参数 θ 0 、 θ 1 为最佳参数,它们确定了预测函数 h θ ( x )的表达式,从而使输入未知数据点 x * 时,模型能够更加自信地计算出它对应的 h ( x * )。下面用一个例子更形象地进行说明。
假如存在如下数据集:
我们假设 h ( x )=1+2 x ,那么当输入 x =1时,计算出 h (1)=3,与已知结果 y 相符。同理,可以算出,当输入 x =2、4时,计算出预测值 h ( x )同样与已知结果y相符。而当输入 x =3、5时,计算出 h ( x )与结果 y 不相符,线性回归就是通过已知数据集来确定预测函数的参数,它的目标是使得预测值与已知的结果集的整体误差最小,从而对于新的数据 x ,能够更加精确地预测出它对应的 y 值应该为多少。
怎样判断预测函数已经最好地拟合了数据集呢?通过回顾之前学习到的知识,其实不难猜出,当预测值 h ( x * )与真实值 y 之间差距最小时,即找到了最好的拟合参数。因此,最直接地定义它们之间差距的方式就是计算它们的差值的平方。
2. 损失函数
损失函数(Loss Function)的公式是:
已知一元线性模型的预测函数为公式3.23,则它对应的损失函数为:
在公式3.24和公式3.25中, m 是数据集的样本量。可以看出,损失函数其实就是计算所有样本点的预测值与它的真实值之间“距离”的平方后求平均。所以,为了更好地拟合已知数据集,需要损失函数 L θ ( x )的值越小越好。因此,我们的目标就是找到一组 θ 0 、 θ 1 ,使得它所对应的预测函数 h θ ( x )计算出每个数据点的预测值与对应的真实值之间的差距的平方的均值最小,即 L θ ( x )最小,此时的 θ 0 、 θ 1 为我们要找到的参数。为了实现这个目标,需要通过梯度下降算法不断地更新参数 θ 0 、 θ 1 的值,使得损失函数 L θ ( x )的值越来越小,直到迭代次数达到一定数量或者损失函数 L θ ( x )的值接近甚至等于0为止,此时的参数 θ 0 、 θ 1 为所找的参数值。有了损失函数,就能精确地测量模型对训练样本拟合的好坏程度。
3. 梯度下降算法
梯度下降(Gradient Descent)算法是一个最优化算法,在机器学习中常被用来递归性地逼近最小偏差模型。梯度下降算法属于迭代法中的一种,它常被用于求解线性或非线性的最小二乘问题。求解机器学习算法的模型参数属于无约束优化问题,而梯度下降是其最常采用的方法之一,还有另一种常用的方法是最小二乘法。在求解损失函数的最小值时,可以通过梯度下降法来一步步地迭代求解,得到最小化的损失函数和模型参数值。反过来,如果我们需要求解损失函数的最大值,这时就需要用梯度上升法来迭代了。
因此,对于上面提到的简单线性回归模型,为了找出使得损失函数值最小时的参数 θ 0 、 θ 1 ,需要使用梯度下降算法。
梯度下降算法的原理是:取一个点( a , b )为起始点,即为 θ 0 、 θ 1 赋初值为 a 、 b ,从这个点出发,往某个方向踏一步,而这一步需要能最快到达 L θ ( x )为最小值的位置。为了便于理解,我们可以假设在一个三维空间里,以 θ 0 作为 x 轴,以 θ 1 作为 y 轴,以损失函数 L θ ( x )作为 z 轴,那么我们的目标就是找到 L θ ( x )取得最小值的点所对应的 x 轴上的值和 y 轴上的值,即找到 z 轴方向上的最低点。由于损失函数 L θ ( x )是凸函数,它存在最低点,我们把三维空间的图转化为等高线图,可以画出类似图3.4所示的图形。
图3.4 梯度下降等高线图
梯度下降算法的思想是:首先随机初始化 θ 0 、 θ 1 的值分别为 a 、 b ,然后可以想象当一个人站在初始( a , b )的位置上,向四周看一圈,找到最陡的下坡方向,然后向此方向前进一步,在新的位置上再环顾四周,然后向着最陡的下坡方向迈进一步,一直循环此操作,直到到达 z 轴方向的最低点,也就是损失函数取得最小值为止。每次找的最陡的下坡方向就是该位置的切线方向,可以通过在该点求偏微分得到,而迈出的步伐大小可以通过调节参数 η 来确定,也叫学习率,一般取值较小。
对于一元线性模型,我们的目标就是找到一组 θ 0 、 θ 1 ,它所对应的预测函数 h θ ( x )计算出每个数据点的预测值与对应的真实值之间的差值平方的均值最小,即损失函数 L θ ( x )最小,此时的 θ 0 、 θ 1 为我们要找到的参数。为了实现这个目标,需要通过梯度下降算法不断地更新参数 θ 0 、 θ 1 的值,使得损失函数 L θ ( x )的值越来越小。因为梯度下降算法需要用到偏微分,由公式3.23和公式3.24结合一阶导数的求导公式可知:
结合公式3.26、公式3.27和公式3.28,化简后可得:
使用梯度下降算法,首先需要给 θ 0 和 θ 1 赋初值,然后每一轮同时更新 θ 0 和 θ 1 的值。一般来说,将 θ 0 和 θ 1 赋初值为0,然后通过梯度下降算法不断地更新它们的值,使得损失函数值越来越小,其中更新参数 θ 0 、 θ 1 的公式为:
将公式3.29和公式3.30分别代入公式3.31和公式3.32中,可得到一元线性模型中,更新参数 θ 0 、 θ 1 的公式为:
其中, η 为学习率,每轮需要给 θ 0 和 θ 1 同时更新值,直到迭代次数达到一定数量或者损失函数 L θ ( x )的值足够小甚至等于0为止。
4. 二元线性回归模型
前面的章节介绍了最简单的线性回归模型,它只有一个因变量 x 与对应的结果 y 。如果数据集中有两个特征 x 1 、 x 2 ,那么此时需要用到二元线性回归模型,它的预测函数为:
对应的损失函数为:
故,用公式3.36对3个参数求导可得:
同样地,二元线性回归模型也是使用梯度下降算法,通过多次迭代更新参数 θ 0 、 θ 1 、 θ 2 的值,从而使得它的损失函数值越来越小。因此,首先需要给 θ 0 、 θ 1 、 θ 2 赋初值,一般都赋值为0,然后每一轮都同时更新 θ 0 、 θ 1 、 θ 2 的值。通过多次迭代更新后,使得损失函数 L θ ( x )的值越来越接近0。其中,更新参数 θ 0 、 θ 1 、 θ 2 的公式分别为:
其中, η 为学习率,每轮需要给 θ 0 、 θ 1 、 θ 2 同时更新值,直到迭代次数达到一定数量,或者损失函数 L θ ( x )的值足够小甚至等于0为止。
5. 多元线性回归模型
同样的道理,当每笔数据有两个以上的特征时,可以使用多元线性回归模型来拟合数据集。多元线性模型的预测函数为:
在现实案例中,每笔数据一般都有很多特征,故常用多元线性模型来进行回归拟合。在进行多元线性回归拟合之前,还需要对数据进行预处理等。关于多元线性回归模型请查阅相关书籍。
6. 用简单线性回归模型预测考试成绩
本示例是一个非常简单的例子。数据集由一个特征:学习时长(time),与其对应的 y 值:考试成绩(score)组成。通过一个简单线性回归模型,使用已知数据集对模型进行训练,训练后得出线性回归模型的参数,从而得到学习时长与考试成绩之间的关系。通过训练好的模型,输入学习时长,就能预测出对应的考试成绩。
1)创建数据集并提取特征和标签
首先需要导入相关的模块,然后创建数据集,这里使用Pandas数据分析包。具体代码如下:
【例3.1】简单线性回归模型预测考试成绩。
将数据集的散点图画出来,可以看一下数据的分布,代码如下:
结果输出如图3.5所示。
图3.5 案例数据分布图
下一步需要将数据集拆分为训练集和测试集,训练集用于训练模型,然后用测试集计算模型的得分。这里使用sklearn中的train_test_split函数实现对数据集的拆分。然后输出拆分后的训练集、测试集的大小。
输出结果如下:
接着画出训练数据和测试数据的图像,代码如下:
结果输出如图3.6所示。
图3.6 训练集和测试集的数据点分布图
2)模型训练
在sklearn中,LinearRegression类实现了线性回归算法。前面已经将数据集拆分为训练集和测试集,这里将训练集中的数据输入模型中进行训练,具体代码如下:
这样线性回归模型就训练好了,由于数据集只含有一个特征值,故该案例的预测函数为:
训练后即得到了最佳拟合线,故它的参数 θ 0 、 θ 1 的值可以通过model.intercept_和model.coef_得到,具体代码如下:
#截距 a = model.intercept_ #回归系数 b = model.coef_ print('最佳拟合线:截距a=',a,'回归系数b=',b)
其中 θ 0 、 θ 1 分别对应截距 a 和回归系数 b 。运行代码,输出结果如下:
最佳拟合线:截距a= [ 9.09387798] 回归系数b= [[ 15.07109838]]
下面绘制最佳拟合曲线图像,代码如下:
输出的拟合曲线如图3.7所示。
图3.7 最佳拟合曲线图
下面将测试集数据点也画出来,看看最佳拟合曲线是否能在测试集上也表现不错,代码如下:
结果输出如图3.8所示。
图3.8 通过数据评估模型
可以看到,测试数据点也是围绕在最佳拟合曲线附近,证明拟合曲线还是不错的。这个训练好的线性回归模型在训练集和测试集上的得分是多少呢?可以通过model.score()函数来计算,这个函数可以在官网API中查到详细信息,它是通过公式:
来计算得到的。其中:
sum()为求和函数,mean()为均值函数, u 和 v 都是非负数,故得分最高为1。具体代码如下:
X_test = X_test.reshape(-1,1) y_test = y_test.reshape(-1,1) trainData_score = model.score(X_train,y_train) testData_score = model.score(X_test,y_test) print('trainData_score:',trainData_score) print('testData_score:',testData_score)
输出结果如下:
trainData_score: 0.845515661166 testData_score: 0.890717012244
我们也可以用这个训练好的模型预测成绩,输入一个学习时长,比如3.7,然后调用model.predict()函数即可,代码如下:
y_pred = model.predict(3.7) print('y_realValue:',y_pred)
输出结果如下:
y_realValue: [[ 64.78608188]]
如果读者自己运行一下代码,可能得到不一样的结果,这是因为训练集和测试集是打乱顺序的,因此最终训练后的参数可能有些不同。
这个例子用的数据集比较少,而且是只有一个特征的简单模型。现实中的模型数据量会比这个数据集大很多,特征也复杂多样。