机器学习 - 一元简单线性回归与梯度下降

回归问题主要是用来预测,比如说你有一组【面积-房价】的数据,这些数据是离散的,通过线性回归,可以找到一个函数尽可能的表述你的数据,从而来预测房价。

线性回归

线性回归属于监督学习,因此方法和监督学习应该是一样的,先给定一个训练集,根据这个训练集学习出一个线性函数。


要通过已知的 y - x 的数据,求得一个 y = kx + b 的式子。

通常为了方便计算并不会直接定义 y = kx + b ,而是定义成 令 x0 = 1:

$$ y = \theta _0 x _0 + \theta _1 x _1 $$

求两个 θ 的值,就等价于求 k 和 b。

那么上面的式子,转换成矩阵的写法就成了:

$$ y = \theta ^ T x $$

θ 和 x 都为矩阵,变成矩阵的形式方便程序的编写。


我们如何判断求得的 y = kx + b 和真实的数据的拟合程度的好坏?

可以通过方差的方式,求 y' - y 的方差。

$$
J({\theta _ 0 - \theta _ n}) = \frac{1}{2m} \sum _{i = 1} ^ m (h _ {\theta}(x ^ i) - y ^ i) ^2
$$

如果我们把 J 的值尽可能的缩到最小,就说明求得的函数拟合程度好。


如何让 J 满满变小呢?答案就是梯度下降。

梯度下降

在上一篇中有提到如何求梯度 机器学习 - 数学理论:迭代法统一论

这里最终求 θ 的公式为:

$$
\theta _1 := \alpha \frac {d} {d\theta _1}J({\theta _ 1})
$$

α为步长,即梯度下降的步长,通常我们不希望步长太大,一般取 0.01。

举例

我现在有一组数据如下:

1
2
1,1
2,2

当然我们凭肉眼看就能知道这个函数是 y = x,实际场景中肯定不可能这样,我们为了方便演示。

下面我们用代码的方式 让程序一步一步找到 一条合适的函数来拟合 给出的两个点。


令 x0 = 1,有方程:

$$ y = \theta _0 x _0 + \theta _1 x _1 $$
$$ y = \theta ^ T x $$

生成 x0 x1 的矩阵

1
2
| 1,1 |
| 1,2 |

生成 θ0 θ1 的矩阵,因为未知,从 0,0好了。

1
2
| 0 |
| 0 |

带入方程可得到 y’

1
2
| 0 |
| 0 |

梯度下降:

$$
\theta _1 := \alpha \frac {d} {d\theta _1}J({\theta _ 1})
$$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 这里 θ x y 都是矩阵
θ = θ - 0.001 * x * (y' - y) / m
y' - y :
| 0 | | 1 | | -1 |
- =
| 0 | | 2 | | -2 |
θ :
| 0 | | 1,1 | | -1 | | 1.5 | | 0.015 |
- * / 2 = * 0.001 =
| 0 | | 1,2 | | -2 | | 2.5 | | 0.025 |

这个时候我们第一次求得

$$
\theta _ 0 = 0.015 , \theta _ 1 = 0.025
$$

也就是:

$$ y = 0.015 + 0.025 x $$

这条函数,离目标貌似还有点远,没有关系,我们继续循环梯度下降。


重复一遍梯度下降:

1
2
| 0.029475 |
| 0.04915 |

$$ y = 0.029475 + 0.04915 x $$

可以看到第二次得到的函数,斜率明显变高,正面我们的算法是正确的。


执行10遍梯度下降:

$$ y = 0.12841063 + 0.21504377 x $$


执行100遍梯度下降:

$$ y = 0.40206094 + 0.72092479 x $$


执行5000遍梯度下降:

$$ y = 0.01163775 + 0.99280747 x $$


此时我们注意到执行5000次后,得到的方程,虽然不是 y = x 但是已经无限接近了。

源码

data.txt
1
2
1,1
2,2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np
data = np.loadtxt('data.txt', delimiter=',')
X = np.c_[np.ones(data.shape[0]), data[:, 0]]
y = np.c_[data[:, 1]]
def gradientDescent(X, y, theta=[[0], [0]], alpha=0.01, num_iters=100):
m = y.size
for iter in np.arange(num_iters):
h = X.dot(theta)
theta = theta - alpha * (1.0 / m) * (X.T.dot(h - y))
return theta
theta = gradientDescent(X, y)
print(theta)

相关资料

一元线性回归的细节

机器学习入门:线性回归及梯度下降

Gavin Liu wechat
欢迎您扫一扫上面的二维码,订阅我的微信公众号!