线性回归

线性回归是一种被广泛应用的回归技术,也是机器学习里面最简单的一个模型,它有很多种推广形式,本质上它是一系列特征的线性组合,在二维空间中,你可以把它视作一条直线,在三维空间中可以视作是一个平面。
线性回归最普通的形式是

Liner Regression-线性回归 - 图1

其中x向量代表一条样本{x1,x2,x3….xn},其中x1,x2,x3代表样本的各个特征,w是一条向量代表了每个特征所占的权重,b是一个标量代表特征都为0时的预测值,可以视为模型的basis或者bias。看起来很简单的。

这里的w乘以x在线性代数中其实代表的是两个向量的内积,假设w和x均为列向量,即代表了w和x向量的内积w’x。同样的这里的x也可以是一个矩阵X,w与X也可以写成w’X,但是b也要相应的写为向量的形式。

  1. #w是列向量 矩阵由一个个列向量构成 y = dot(w_t,X)+b
  2. import numpy as np
  3. w_t,b = np.array([1,2,3,4,5]),1
  4. X = np.array([[1,1,1,1,1],[1,2,5,3,4],[5,5,5,5,5]]).T
  5. y_hat = np.dot(w,X) + b

损失函数

线性回归的模型就是这么简单,困难的地方在于我们如何获得w和b这两个向量,在李航老师的统计学习方法中把一个学习过程分为了三部分,模型、策略、算法,为了获得w和b我们需要制定一定的策略,而这个策略在机器学习的领域中,往往描述为真实值与回归值的偏差。
Liner Regression-线性回归 - 图2

我们希望的是能够减少在测试集上的预测值f(x)与真实值y的差别,从而获得一个最佳的权重参数,因此这里采用最小二乘估计。

这里复习一下之前《数学估计方法》中留下的问题,最小方差无偏估计和最小二乘估计是不一样的,那么他们的区别在哪?最直观的地方是这里表示的是估计点与真实点的差别,而最小方差无偏估计表示的是估计点与真实数据期望的差别。

  1. y = np.array([1.5, 3, 6])
  2. loss = (y_hat - y)**2

优化方法

知道了策略,下一步就是要动手去做,那么怎样调整w才能使估计值与真实值的差别尽可能小呢?这里提供并实现两种经常使用的凸优化方法,最小二乘优化与梯度下降优化,详细可以参考《数学优化方法》。

最小二乘

最小二乘优化的思路是线性代数中的矩阵求导,学过导数的人都知道,如果我们想要让loss取到最小,只需要对这个式子进行求导,导数为0的地方就是极值点,也就是使loss最大或者最小的点(实际上是最小的点,因为loss一般是一个往下突的函数,w无限大的时候随便带进去一个值估计出来的值loss都很大,其实求2阶导数也可以看出来)。
任务变成了求这个 Liner Regression-线性回归 - 图3 的数学问题。
这里可以参考《矩阵求导公式》里的求导方法,总之求出来是 Liner Regression-线性回归 - 图4 ,然后求出来 Liner Regression-线性回归 - 图5 ,这里如果XX^T可逆的话,可以变成 ,这里矩阵求导公式我也记不住,但是凭感觉应该是对的吧。

  1. w_t = np.dot(np.dot(y,X.T), np.linalg.inv(np.dot(X,X.T)))


梯度下降**
梯度下降的策略与最小二乘优化不同,它采用的不是用数学方法一步求出解析解,而是一步一步的往让loss变到最小值的方向走,直到走到那个点。

可是那个方向怎么确定呢?这里我们引入梯度的概念。

More precisely, the gradient points in the direction of the greatest rate of increase of the function, and its > magnitude is the slope of the graph in that direction.——Wikipedia

梯度方向就是增长最快的方向,如果我们想要函数值减小,只需要沿着负梯度方向走就行了。具体求这个grad的方法就是,对loss求偏导就可以啦,具体还是看《数学优化方法》。
Liner Regression-线性回归 - 图6
之后沿着这个方向走一小步。
Liner Regression-线性回归 - 图7
然后再重复求偏导、走、求偏导、走就可以得到最终的权重向量w。当然这里有一点需要解释,对于一个连续可导的函数而言,越靠近我们想要的那个极值点的地方,它的梯度就越小,想象一下你蚁人在浴缸里走的时候,发现在浴缸边缘陡峭,浴缸中间平缓。因此我们在实现时只需要在走的很慢的时候停下就好啦~

  1. while True:
  2. grad = np.dot((np.dot(w_t,X)-y), X.t)
  3. w_t -= 0.1 * grad
  4. if np.linalg.norm(w_t, ord = 2) < 1e-3:
  5. break