线性回归,其实我们在高中时期就已经学习过——最小二乘法,这也正是本文中提到的正规方程。本文从单变量、多变量两个方面介绍线性回归,并指出模型评估的标准——损失函数,以及如何求出损失函数最小时的解——梯度下降、正规方程。
在数据集中,特征(这里指自变量)x 的类数为1,从 x 到 y 建立线性回归方程。它是一种监督学习,因为对于每个数据,我们给出了“正确的答案”。为了描述回归问题,有以下常见变量:
如何表达假设函数h,对于单变量线性而言,一般应为:
h θ ( ) = θ 0 + θ 1 x ℎ_θ() = θ_0 + θ_1x hθ(x)=θ0+θ1x
代价函数也称之为平方误差(代价)函数。我们将模型所预测的值与训练集中实际值之间的差距称为建模误差,通过平均误差来反映模型好坏。于是就有了代价函数:
( θ 0 , θ 1 ) = 1 2 m ∑ ( h θ ( ) − i ) (θ_0, θ_1) =\frac{1}{2m}∑ (ℎ_θ(^) − ^i) J(θ0,θ1)=2m1∑(hθ(xi)−yi)
为什么是 1 / 2m:这里的目标是要求出代价函数最小时,对应的 θ 的解,因此乘一个常数是不影响结果的。而之所以是这个,是因为后面的求和项,在求导以会出现2m。
梯度下降是一个用来求函数最小值的算法,我们将使用梯度下降算法来求出代价函数 (0, 1) 的最小值。
梯度下降背后的思想是:开始时我们随机选择一个参数的组合(0, 1, . . . . . . , ),计算代价函数,然后我们寻找下一个能让代价函数值下降最多的参数组合。我们持续这么做直到找到一个局部最小值。梯度下降的公式为:
r e p e a t u n t i l c o n v e r g e n c e { θ j : = θ j − α ∂ ∂ θ j J ( θ 0 , θ 1 ) ( f o r j = 0 a n d j = 1 ) } repeat \ until \ convergence \{\ \\ θ_j:=θ_j- α \frac{∂}{∂θ_j} J(θ_0,θ_1) \quad (for \ j=0 \ and \ j = 1) \} repeat until convergence{ θj:=θj−α∂θj∂J(θ0,θ1)(for j=0 and j=1)}
对于单变量线性回归,每一次迭代应该表示为:
t e m p 0 : = θ 0 − α ∂ ∂ θ 0 J ( θ 0 , θ 1 ) t e m p 1 : = θ 1 − α ∂ ∂ θ 1 J ( θ 0 , θ 1 ) θ 0 : = t e m p 0 θ 1 : = t e m p 1 temp_0:=θ_0- α \frac{∂}{∂θ_0} J(θ_0,θ_1) \\ temp_1:=θ_1- α \frac{∂}{∂θ_1} J(θ_0,θ_1) \\ θ_0:=temp_0 \\ θ_1:=temp_1 temp0:=θ0−α∂θ0∂J(θ0,θ1)temp1:=θ1−α∂θ1∂J(θ0,θ1)θ0:=temp0θ1:=temp1
值得注意的是,我们需要同时更新两个 θ 的值。同步更新是更加自然的实现方法,即使不同步程序也能正常运行。实现梯度下降算法的代码如下所示:
def gradient_descent(f, init_x, lr=0.01, step_num=100):
# lr代表学习率,step_num是梯度下降的重复次数
x = init_x
for i in range(step_num):
grad = numerical_gradient(f, x)
x -= lr * grad
return x
numerical_gradient()是求偏导或者导数的函数,对于线性回归,我们可以直接得到它的导数公式;但对于一些深度学习回归,可能就只有通过导数的定义来求解了。
上述公式中,其中 α 是学习率(learning rate),它决定了我们沿着能让代价函数下降程度最大的方向 向下迈出的步子有多大,在批量梯度下降中,我们每一次都同时让所有的参数减去学习速率 乘以代价函数的导数。
如果 α 太小,程序移动的速度会非常慢;而如果 α 太大,则梯度下降法可能会越过最低点,甚至无法收敛。
在代价函数接近局部最低点时,导数值会自动变得越来越小,即使学习率保持不变,梯度下降也会自动采取较小的幅度,所以实际上没有必要再另外减小学习率 α 。
当原始数据有更多特征时,即拥有更多自变量 x ,对应的便是多变量线性回归。此时的假设函数如下:
h θ ( ) = θ T x = θ 0 + θ 1 1 + θ 2 2 + . . . + θ n ℎθ() = θ^T x = θ_0 + θ_1_1 + θ_2_2+. . . +θ__n hθ(x)=θTx=θ0+θ1x1+θ2x2+...+θnxn
多变量回归的损失函数,也是所有建模误差的平均平方和:
( θ 0 , θ 1 , . . . , θ n ) = 1 2 m ∑ ( h θ ( ) − i ) (θ_0, θ_1,...,θ_n) =\frac{1}{2m} ∑ (ℎ_θ(^) − ^i) J(θ0,θ1,...,θn)=2m1∑(hθ(xi)−yi)
批量梯度下降算法本质也与上述相同,初步求导以后,公式为:
r e p e a t { θ j : = θ j − α 1 m Σ [ ( h θ ( x i ) − y i ) ⋅ x i ] ( s i m u l t a n e o u s l y u p d a t e θ j f o r j = 0 , 1 , 2 , . . . , n ) } repeat \{\ \\ θ_j:=θ_j- α \frac{1}{m} Σ[\ (h_θ(x^i)-y^i) \ · \ x^i\ ] \ \\ (simultaneously \quad update \quad θ_j \\ for \quad j=0,1,2,...,n) \} repeat{ θj:=θj−αm1Σ[ (hθ(xi)−yi) ⋅ xi ] (simultaneouslyupdateθjforj=0,1,2,...,n)}
在我们面对多维特征问题的时候,我们要保证这些特征都具有相近的尺度,这将帮助梯度下降算法更快地收敛。
解决的方法是尝试将所有特征的尺度都尽量缩放到 -1 到 1 之间。
(1)最大最小值归一化:将数值映射到[0, 1]上。
x n e w = x − m i n ( x ) m a x ( x ) − m i n ( x ) x^{new} = \frac{x-min(x)}{max(x)-min(x)} xnew=max(x)−min(x)x−min(x)
(2)z标准化:将数值缩放到0附近,且数据的分布变为均值为0,标准差为1的标准正态分布。
x n e w = x − x ˉ σ x^{new} = \frac{x-\bar x}{σ} xnew=σx−xˉ
正规方程,其实是通过求解下面方程,找出使得代价函数最小的参数:
∂ ∂ θ j J ( θ j ) = 0 \frac{∂}{∂θ_j}\ J(θ_j) = 0 ∂θj∂ J(θj)=0
其实本质上似乎就是最小二乘法,不过这里在运算时进行了向量化。利用正规方程求解出结果为:
θ = ( X T X ) − 1 X T y θ = (X^TX)^{-1}X^Ty θ=(XTX)−1XTy
正规方程的代码实现如下:
# 正规方程
def normalEqn(X, y):
X_T = np.transpose(X)
theta = numpy.linalg.inv(X_T*X)*X_T*y
return theta
梯度下降与正规方程进行比较:
梯度下降 | 正规方程 |
---|---|
需要选择学习率 α | 不需要 |
需要多次迭代 | 一次运算得出 |
适用于n各种情况 | n较大时运算代价大 |
适用各种模型 | 只适用于线性模型 |
本文所做的,只是以机器学习初学者视角,对线性回归做出比较基础的解释。事实上,回归,即使仅仅说是线性回归,都是一个非常深的数学领域,像回归的决定系数、均方误差,多元回归的异方差、共线性,t检验F检验等等等等,这些依旧不算很深入,都值得我们去做进一步的学习。