这个平方和计算公式也叫损失函数(loss function),损失的意思就是指没有拟合到真实值的部分。
另外,这里的未知数不再是 x 和 y (x y 都是已知样本值)而是斜率 a 和 截距 b,相当于是关于 a 和 b 的二次方程。我们知道它是一条抛物线,有最小值。
所以,我们的目的从找到一条最大化拟合住所有红色样本点的直线,转变成找到一条损失函数值最小的直线 。
寻找这条直线显然不能靠手动划线去找,因为穷举不完。可以换个思路:求出该损失函数的最小值,反解出未知数 a 和 b,就可以找到这条直线。
如何求该函数的最小值呢?这就可以用到中学学过的函数求导来解决,让导函数等于 0 就能找到函数最小值。
到这儿,我们的找直线问题最终变成了数学求导。
求导不难高中数学知识就够,下面来一步步写下:
[h2]03 线性回归公式推导[/h2]为了方便求导,令该损失函数等于 J(a,b),分别对 a 和 b 求偏导,令其等于 0 求解 a 和 b 的值:
b 的形式简单些,所以先对 b 求导:
很容易就能求出 b 的值:y 的均值减去 a 乘以 x 的均值:
由于,我们已有全部样本点的 x 和 y 值,所以均值很容易计算,只需要求出 a。
下面来推导 a ,会稍微复杂点:
把 b 代入:
分别乘入 x^{(i)}:
将 a 整理合并:
最后就能求出 a:
不过该公式略复杂,还可以进一步整理让 a 跟 x 和 y 的均值产生联系。对分子第二项做变换:
变换后,发现 x 和 y 对调后上式也成立,接着再从另一个角度变换:
这样就可以对 a 的表达式做替换,分子和分母都加一项再减去相等的一项(等于没加没减):
凑成这样的形式是为了变换:分子可以合并因式分解项,分母可以写成完全平方公式:
到这里, a 和 b 的计算公式就都和 x 和 y 的均值产生联系,很容易能求出来:
数学公式推导出来后,简单的几行 Python 代码就可以计算出 a 和 b,有了 a 和 b 就能解出直线 y 的表达式,从而绘制出前面的最佳拟合直线。
[h2]04 Python 手写线性回归[/h2]
可以看到,数学是编程的基础很重要,如果觉得推导过程难可以不用管它,只需记住 a 和 b 的表达式就可以编程实现。
到这儿我们介绍了线性回归算法,并用简单的 Python 代码实现了它,解决了房价为什么是 125 万的问题。
进一步地我们还可以像调用 sklearn 库一样,把这些代码封装成一个名为 SimpleLinearRegression 的库方便快速调用:
可以看到我们得到了一样的 a 和 b 以及房价,初步完整地实现了线性回归算法代码。
不过发现了一个问题就是前面在计算斜率 a 的值时,使用了 for 循环这种低效率计算方法,当数据量很大时算法运行会变慢。
那么有什么优化方法么?有的,就是使用:向量化运算,它可以将算法运行效率提升一到两个数量级。
下面具体介绍下如何使用向量化运算改进,只需要两行代码。
[h2]05 向量化加速线性回归运算[/h2]我们换个角度来看上面的斜率 a 计算公式,可以把 a 的分子和分母都看成是两个向量 w v 的每一个元素相乘再相加 :
即分子分母都看成是这样的形式:
这里的 w 和 v 向量都有 m 个元素:
其实向量相乘再相加,就是向量的点积公式即:
这样就可以不用 for 循环而直接用 numpy 的向量点积公式 np.dot 计算分子分母的值:
# np.dot 向量化计算分子分母
num = (x-x_mean).dot(y-y_mean)
dom = (x-x_mean).dot(x-x_mean)
进而求出 a 和 b:
可以看到,a 和 b 的值和 for 循环结果相同,两行代码就解决了。
刚才说当数据量很大时,for 循环计算效率很低,而向量化运算则会快很多,由于我们例举的数据集很小所以体现不出二者性能区别。下面重新生成一个 100 万的大数据集测试一下:
上面模拟生成了一个在 y = 3*x + 1 直线附近的数据集,首先使用 for 循环拟合(lr.fit),程序平均运行时间在 1.41s,接着使用向量化拟合(lr.fit2),平均运行时间只有 24.2 ms,二者相差了 50 倍!性能差距很大。
所以,线性回归算法实现时尽量使用向量化运算这种方式。
[h2]06 调用 sklearn 线性回归算法[/h2]最后,我们来熟悉使用下 sklearn 中的线性回归算法,只需要 5 行代码:
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(x,y)
x_predict = np.array([55, 80])
y_predict = lr.predict(x_predict)
# [out]:
array([[ 76.94915254],
[124.40677966]])
从 sklearn 的 linear_model 方法中调用线性回归库 LinearRegression,实例化之后在训练集(x,y)上 fit 拟合,然后在预测集上 (x_predict) 预测得到 y 值(预测房价),结果和我们刚才手写的一样。
sklearn 库调用起来很简单,但是只有自己动手去写一遍才能更深刻理解该算法。
以上就是线性回归算法的第一篇文章,算法介绍完了我们还需要知道如何评价其效果好坏,下一篇文章将介绍线性回归的几个评价指标。
本文的 jupyter notebook 代码,可以在公众号后台回复「LR1」得到,加油! (*本文仅代表作者观点,转载请联系原作者)