y = a + bx 的目标函数
上一篇文章,我们解释了线性,本文我们回到求解线性回归目标函数的问题上。前面已知,线性回归的目标函数为:
J(a,b) 是一个二元函数。我们要求的是:两个参数 a 和 b 的值。要满足的条件是:a 和 b 取这个值的时候,J(a,b) 的值达到最小。
我们现在就来用之前讲过的算法:梯度下降法,来对其进行求解。
斜率、导数和偏微分
梯度下降法我们前面也讲过步骤,总结起来就是:从任意点开始,在该点对目标函数求导,沿着导数方向(梯度)“走”(下降)一个给定步长,如此循环迭代,直至“走”到导数为0的位置,则达到极小值。
为什么要求导呢?从下图可以看到:曲线表示一个函数,它在一个点处的导数值就是经过这个点的函数曲线的切线的斜率。
一元函数在某一点处沿 x 轴正方向的变化率称为导数
。但如果是二元或更多元的函数(自变量维度 >=2),则某一点处沿某一维度坐标轴正方向的变化率称为偏导数
。
导数/偏导数表现的是变化率
,而变化本身,用另一个概念来表示,这个概念就是微分
(对应偏导数,二元及以上函数有偏微分)。
(偏)导数是针对函数上的一个点而言的,是一个值。而(偏)微分则是一个函数,其中的每个点表达的是原函数上各点沿着(偏)导数方向的变化。
直观而不严格的来说,(偏)微分就是沿着(偏)导数的方向,产生了一个无穷小的增量。
想想我们的梯度下降算法,我们要做的不就是在一个个点上(沿着导数方向)向前走一小步吗?
当我们求出了一个函数的(偏)微分函数后,将某个变量带入其中,得出的(偏)微分函数对应的函数值,就是原函数在该点处,对该自变量求导的导数值。
所以,只要我们求出了目标函数的(偏)微分函数,那么目标函数自变量值域内每一点的导数值也就都可以求了。
如何求一个函数的(偏)微分函数呢?这个我们只需要记住最基本的求导规则就好,函数(整体,而非在一个点处)求导的结果,就是微分函数了。
本文会用到的仅仅是常用规则中最最常用的几条:
梯度下降求解目标函数
通用线性回归模型的目标函数求解
y = a + bx 是一个线性回归模型,这个没问题。不过,反过来,线性回归模型只能是 y = a + bx 形式吗?当然不是。
y = a + bx => f(x) = a + bx 实际上是线性回归模型的一个特例——自变量只有一个维度的特例,在这个模型中,自变量 x 是一个一维向量,可写作 [x]。
线性回归的超参数
在模型类型和训练数据确定的情况下,超参数的设置就成了影响模型最终质量的关键。
而往往一个模型会涉及到多个超参数,如何制定策略在最少尝试的情况下让所有超参数设置的结果达到最佳,是一个在实践中非常重要又没有统一方法可以解决的问题。
编写线性回归训练/预测程序
如果我们要用代码实现线性回归程序应该怎样做呢?当然,你可以按照上面的描述,自己从头用代码实现一遍。
不过,其实不必。因为我们已经有很多现成的方法库,可以直接调用了。
最常见的是 sklearn 库。下面的例子就对应最开始的经验和工资的问题。我们用前6个数据作为训练集,后面5个作为测试集,来看看结果:
import matplotlib.pyplot as plt
import numpy as np
from sklearn import datasets, linear_model
from sklearn.metrics import mean_squared_error, r2_score
experiences = np.array([0,1,2,3,4,5,6,7,8,9,10])
salaries = np.array([103100, 104900, 106800, 108700, 110400, 112300, 114200, 116100, 117800, 119700, 121600])
# 将特征数据集分为训练集和测试集,除了最后5个作为测试用例,其他都用于训练
X_train = experiences[:7]
X_train = X_train.reshape(-1,1)
X_test = experiences[7:]
X_test = X_test.reshape(-1,1)
# 把目标数据(特征对应的真实值)也分为训练集和测试集
y_train = salaries[:7]
y_test = salaries[7:]
# 创建线性回归模型
regr = linear_model.LinearRegression()
# 用训练集训练模型——看就这么简单,一行搞定训练过程
regr.fit(X_train, y_train)
# 用训练得出的模型进行预测
diabetes_y_pred = regr.predict(X_test)
# 将测试结果以图标的方式显示出来
plt.scatter(X_test, y_test, color='black')
plt.plot(X_test, diabetes_y_pred, color='blue', linewidth=3)
plt.xticks(())
plt.yticks(())
plt.show()
运行结果: