Regression 回归分析
线性回归
单变量线性回归
单变量的意思是只有一个自变量。
比如,我们想要根据明天的最高温度预测明天某城市的峰值用电量。我们不可能平白无故地预测明天的数据,而是需要根据以往的数据来预测以后的数据。因此,我们需要收集以往的数据,如下表:
最高温度(℉) | 峰值用电量 |
---|---|
76.7 | 1.87 |
72.7 | 1.92 |
71.5 | 1.96 |
86.0 | 2.43 |
90.0 | 4.69 |
87.7 | 2.50 |
… | … |
散点图:
对于单变量线性回归,可表示为如下模型:
当天峰值用电量=θ0+θ1⋅(当天最高温度)
当天峰值用电量=\theta_0+\theta_1·(当天最高温度)
当天峰值用电量=θ0+θ1⋅(当天最高温度)
如果我们把这个模型函数放在上面的散点图中(三条直线的参数值不同):
很显然,根据明天的最高温度预测明天的峰值用电量的问题,就转化成了在上面的图中找一条最吻合训练数据的直线,“最吻合”也就等价于选择合适的 θ0\theta_0θ0和θ1\theta_1θ1.
那么,我们应该怎么衡量“最吻合”呢?这就需要用到Loss Function(损失函数)了。
损失函数
L(f(x)−y)=∑i=1n(f(xi)−yi)2=∑i=1n((θ1x+θ0)−yi)2 L(f(x)-y)=\sum_{i=1}^n(f(x_i)-y_i)^2=\sum_{i=1}^n((\theta_1x+\theta_0)-y_i)^2 L(f(x)−y)=i=1∑n(f(xi)−yi)2=i=1∑n((θ1x+θ0)−yi)2
对于损失函数,我们需要注意以下两点:
- 损失函数值越小,越吻合(预测值与实际值差别越小)
- 损失函数值是非负的
因此这个问题就转换成了一个优化问题:
minJ(θ0,θ1)=min(12m∑i=1n((θ1x+θ0)−yi)2)(m为样本个数)
minJ(\theta_0, \theta_1)=min(\frac{1}{2m}\sum_{i=1}^n((\theta_1x+\theta_0)-y_i)^2)\quad (m为样本个数)
minJ(θ0,θ1)=min(2m1i=1∑n((θ1x+θ0)−yi)2)(m为样本个数)
解决上面的优化问题主要用梯度下降法。
梯度下降法
上面说到:“最吻合”也就等价于选择合适的 θ0\theta_0θ0和θ1\theta_1θ1.在梯度下降法中,我们需要对 θ0\theta_0θ0和θ1\theta_1θ1 进行多次迭代计算,逐步逼近J(θ0,θ1)J(\theta_0, \theta_1)J(θ0,θ1)的最小值。
那么,在每一次迭代中,我们应如何计算 θ0\theta_0θ0和θ1\theta_1θ1呢?需要用到如下算法:
注意:θ0\theta_0θ0和θ1\theta_1θ1是同步更新的。(也就是 批处理:梯度下降的每一步都使用所 有的训练样本)
附:相关计算步骤:
∂J∂θ1=∂12n∑i=0n(yi−yi^)2∂θ1=1n∑i=0n(yi−θ1xi−θ0)∂(yi−θ1xi−θ0)(−xi)∂θ1=1n∑i=0n(yi−θ1xi−θ0)(−xi)=1n∑i=0nx(yi^−yi)
\frac{\partial J}{\partial \theta_1}=\frac{\partial\frac{1}{2n}\displaystyle \sum_{i=0}^n(y_i- \hat{y_i})^2}{\partial \theta_1}=\frac{1}{n}\displaystyle \sum_{i=0}^n(y_i-\theta_1x_i-\theta_0)\frac{\partial(y_i-\theta_1x_i-\theta_0)(-x_i)}{\partial \theta_1}\\=\frac{1}{n}\displaystyle \sum_{i=0}^n(y_i-\theta_1x_i-\theta_0)(-x_i)=\frac{1}{n} \displaystyle \sum_{i=0}^nx(\hat{y_i}-y_i)
∂θ1∂J=∂θ1∂2n1i=0∑n(yi−yi^)2=n1i=0∑n(yi−θ1xi−θ0)∂θ1∂(yi−θ1xi−θ0)(−xi)=n1i=0∑n(yi−θ1xi−θ0)(−xi)=n1i=0∑nx(yi^−yi)
∂J∂θ0=∂12n∑i=0n(yi−yi^)2∂θ0=1n∑i=0n(yi−θ1xi−θ0)∂(yi−θ1xi−θ0)(−xi)∂θ0=1n∑i=0n(yi−θ1xi−θ0)(−1)=1n∑i=0n(yi^−yi) \frac{\partial J}{\partial \theta_0}=\frac{\partial\frac{1}{2n}\displaystyle \sum_{i=0}^n(y_i- \hat{y_i})^2}{\partial \theta_0}=\frac{1}{n}\displaystyle \sum_{i=0}^n(y_i-\theta_1x_i-\theta_0)\frac{\partial(y_i-\theta_1x_i-\theta_0)(-x_i)}{\partial \theta_0}\\=\frac{1}{n}\displaystyle \sum_{i=0}^n(y_i-\theta_1x_i-\theta_0)(-1)=\frac{1}{n} \displaystyle \sum_{i=0}^n(\hat{y_i}-y_i) ∂θ0∂J=∂θ0∂2n1i=0∑n(yi−yi^)2=n1i=0∑n(yi−θ1xi−θ0)∂θ0∂(yi−θ1xi−θ0)(−xi)=n1i=0∑n(yi−θ1xi−θ0)(−1)=n1i=0∑n(yi^−yi)
θ0=θ0−α∂J∂θ0 \theta_0=\theta_0-\alpha\frac{\partial J}{\partial \theta_0} θ0=θ0−α∂θ0∂J
θ1=θ1−α∂J∂θ1 \theta_1=\theta_1-\alpha\frac{\partial J}{\partial \theta_1} θ1=θ1−α∂θ1∂J
你可能会对式中的α\alphaα 很疑惑,不用担心,下面我们会讲到。
学习率 α\alphaα
对于学习率,它代表了J(θ0,θ1)J(\theta_0,\theta_1)J(θ0,θ1)在每一次迭代中的减小程度。
-
对于合适的α\alphaα,J(θ0,θ1)J(\theta_0,\theta_1)J(θ0,θ1)应该在每一次迭代中都减小
-
如果α\alphaα太小,梯度下降算法则会收敛很慢
-
如果α\alphaα太大,梯度下降算法则不会收敛:发散或震荡
为了找到合适的α\alphaα,我们可以不断尝试。
练习
拟合xxx和yyy
xxx | yyy |
---|---|
1 | 2 |
3 | 8 |
5 | 14 |
代码如下(python):
'''
Description:
Author: Weijian Ma
Date: 2020-09-16 18:47:40
LastEditTime: 2020-09-17 16:59:55
LastEditors: Weijian Ma
'''
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
## 数据及参数的初始化
x = [1, 3, 5]
x = np.reshape(x,newshape=(len(x),1))
y = [3, 6, 16]
y = np.reshape(y,newshape=(len(y),1))
a = 1
b = 1
alpha = 0.1
n = len(x)
## 损失函数
def costFunction(a, b):
return 0.5/n*(np.square(a*x+b-y)).sum()
## 优化
def opt(a, b):
da = (1/n) * ((a*x+b-y)*x).sum()
db = (1/n) * ((a*x+b-y).sum())
a = a-alpha*da
b = b-alpha*db
return a, b
## 训练模型
fig = plt.figure(figsize=(12,8))
sub01 = plt.subplot(221)
sub02 = plt.subplot(222)
sub03 = plt.subplot(223)
sub04 = plt.subplot(224)
costList = []
aList = []
bList = []
for i in range(100):
print('训练次数:{} a={:.4f} b={:.4f}'.format(i+1, a, b))
cost = costFunction(a, b)
costList.append(cost)
a, b = opt(a, b)
aList.append(a)
bList.append(b)
sub01.cla()
sub02.cla()
sub03.cla()
sub04.cla()
sub01.plot(x, a*x+b)
sub01.scatter(x, y)
sub01.set_xlabel('x')
sub01.set_ylabel('y')
sub01.set_title('a={:.6f}, b={:.6f}'.format(a, b))
sub02.set_xlabel('训练次数')
sub02.set_ylabel('损失函数值')
sub02.set_title('当前损失函数值:{:.6f}'.format(cost))
sub02.plot(costList)
sub03.plot(aList)
sub04.plot(bList)
sub03.set_xlabel('训练次数')
sub03.set_ylabel('a')
sub04.set_xlabel('训练次数')
sub04.set_ylabel('b')
plt.pause(0.001)
plt.show()
结果(学习率为0.1,迭代次数100次):