一元线性回归
目的
有一些样本点,点有自变量x和因变量y构成坐标。要用一条直线拟合也就是 y = θ 0 + θ 1 x y = \theta_0+\theta_1x y=θ0+θ1x
我们要找到两个系数使得其最符合这条直线。
代价函数
J
(
θ
0
,
θ
1
)
=
1
2
m
∑
i
=
1
m
(
y
i
−
h
θ
(
x
i
)
)
2
J(\theta_0,\theta_1) = \frac{1}{2m}\sum_{i=1}^{m}{(y^i-h_\theta(x^i))^2}
J(θ0,θ1)=2m1i=1∑m(yi−hθ(xi))2
我们的要找到最合适的两个θ使得代价函数J最小,使得J最小的这两个参数我们认为它是拟合的最好的。
为什么是这个函数呢?很好理解。1/2先不管,平方也能改成绝对值,那么这个公式的意思也就是所有样本点到这条直线的平均距离,找到一条平均距离最小的直线当然也就说明了这条直线是拟合的最好的。
相关系数
r
=
∑
(
X
i
−
X
均
)
(
Y
i
−
Y
均
)
∑
(
X
i
−
X
均
)
2
∑
(
Y
i
−
Y
均
)
2
r = \frac{\sum{(X_i-X_均)(Y_i-Y_均)}}{\sqrt{\sum{(X_i-X_均)^2}\sum{(Y_i-Y_均)^2}}}
r=∑(Xi−X均)2∑(Yi−Y均)2∑(Xi−X均)(Yi−Y均)
这个公式代表样本点的线性相关性。说白了就是这些点像不像一条直线。如果这些点全在一条直线上,那么r就为1,反正r的值域是在0到1之间的。
为什么这个公式管用呢?证明一下很简单,只要说明是直线的时候r取到最大值1就行了,那么不是直线的时候r就小于1,线性相关性就没那么高了。
当所有样本点都是在一条直线上的时候,所有Y都能写成aX+b的形式,往里面一带,b都减掉了,a都约分约掉了,r=1 。
下面只要证明r小于等于1就行了,也就是分子<=分母。直接柯西不等式就完事儿了:
∑
i
=
1
n
a
i
2
∑
i
=
1
n
b
i
2
≥
(
∑
i
=
1
n
a
i
b
i
)
2
\sum_{i=1}^{n}{a_i^2}\sum_{i=1}^{n}{b_i^2}\geq(\sum_{i=1}^{n}{a_ib_i})^2
i=1∑nai2i=1∑nbi2≥(i=1∑naibi)2
决定系数
这个东西是用来说明拟合的好不好的一个指标,不是一元的,不是线性的都可以。
-
总平方和: S S T = ∑ i = 1 n ( y i − y 均 ) 2 SST = \sum_{i=1}^{n}(y_i-y_均)^2 SST=∑i=1n(yi−y均)2
-
回归平方和: S S R = ∑ i = 1 n ( y 预 − y 均 ) 2 SSR = \sum_{i=1}^{n}(y_预-y_均)^2 SSR=∑i=1n(y预−y均)2
-
残差平方和: S S E = ∑ i = 1 n ( y i − y 预 ) 2 SSE = \sum_{i=1}^{n}(y_i-y_预)^2 SSE=∑i=1n(yi−y预)2
由此可以得到决定系数:
R 2 = S S R S S T = 1 − S S E S S T R^2 = \frac{SSR}{SST} = 1 - \frac{SSE}{SST} R2=SSTSSR=1−SSTSSE
至于为什么SST = SSR + SSE,经过我的百度,是这样的:
y i − y 均 = y i − y 预 + y 预 − y 均 y_i - y_均 = y_i - y_预 + y_预 - y_均 yi−y均=yi−y预+y预−y均
∑ i = 1 n ( y i − y 均 ) 2 = ∑ i = 1 n ( y 预 − y 均 ) 2 + ∑ i = 1 n ( y i − y 预 ) 2 + 2 ∑ i = 1 n ( y i − y 预 ) ( y 预 − y 均 ) \sum_{i=1}^{n}(y_i-y_均)^2 = \sum_{i=1}^{n}(y_预-y_均)^2 + \sum_{i=1}^{n}(y_i-y_预)^2 + 2\sum_{i=1}^{n}{(y_i-y_预)(y_预-y_均)} ∑i=1n(yi−y均)2=∑i=1n(y预−y均)2+∑i=1n(yi−y预)2+2∑i=1n(yi−y预)(y预−y均)
只要说明 ∑ i = 1 n ( y i − y 预 ) ( y 预 − y 均 ) \sum_{i=1}^{n}{(y_i-y_预)(y_预-y_均)} ∑i=1n(yi−y预)(y预−y均)为0就可以了
∑ i = 1 n ( y i − y 预 ) ( y 预 − y 均 ) = ∑ i = 1 n ( y i − y 预 ) ( θ 0 + θ 1 x i − y 均 ) \sum_{i=1}^{n}{(y_i-y_预)(y_预-y_均)} = \sum_{i=1}^{n}{(y_i-y_预)(\theta_0+\theta_1x_i-y_均)} ∑i=1n(yi−y预)(y预−y均)=∑i=1n(yi−y预)(θ0+θ1xi−y均)
= ( θ 0 − y 均 ) ∑ i = 1 n ( y 预 − y 均 ) + θ 1 ∑ i = 1 n ( y 预 − y 均 ) x i =(\theta_0-y_均)\sum_{i=1}^{n}{(y_预-y_均)}+\theta_1\sum_{i=1}^{n}{(y_预-y_均)}x_i =(θ0−y均)∑i=1n(y预−y均)+θ1∑i=1n(y预−y均)xi
要使残差平方和最小或者代价函数最小,那么 J ( θ 0 , θ 1 ) J(\theta_0,\theta_1) J(θ0,θ1)在 θ 0 \theta_0 θ0, θ 1 \theta_1 θ1处的偏导数为0
对 θ 0 \theta_0 θ0求导得 ∑ i = 1 n ( y 预 − y 均 ) = 0 \sum_{i=1}^{n}{(y_预-y_均)}=0 ∑i=1n(y预−y均)=0
对 θ 1 \theta_1 θ1求导得 ∑ i = 1 n ( y 预 − y 均 ) x i = 0 \sum_{i=1}^{n}{(y_预-y_均)}x_i=0 ∑i=1n(y预−y均)xi=0
因此SST = SSR + SSE。
梯度下降
现在目的明确,也就是说我们要找到两个数 θ 0 \theta_0 θ0和 θ 1 \theta_1 θ1使得损失函数达到最小值。
极小值怎么求?求偏导,沿着导数方向下降肯定是降得最快的嘛。
那我们就可以先随便取个
θ
0
\theta_0
θ0和
θ
1
\theta_1
θ1,然后不断迭代直至找到局部极小值。
θ
j
:
=
θ
j
−
α
∂
∂
θ
j
J
(
θ
0
,
θ
1
)
\theta_j := \theta_j - \alpha\frac{∂}{∂\theta_j}J(\theta_0,\theta_1)
θj:=θj−α∂θj∂J(θ0,θ1)
其中
α
\alpha
α代表步长,也称为学习率。
负号保证了 θ \theta θ永远是朝着J变小的方向移动:
如果偏导是正的,那么函数是增大趋势,添负号向减小方向移动;
如果偏导是负的,那就要沿数轴正向移动使J减小,刚好负负得正。
这个公式很好理解。
但是这个方法也是有一点问题的,可能会陷入局部极小值,局部极小值不一定是全局最小值。
那我们分别对
θ
0
\theta_0
θ0和
θ
1
\theta_1
θ1求偏导得到:
θ
0
:
=
θ
0
−
α
1
m
∑
i
=
1
m
(
θ
0
+
θ
1
x
i
−
y
i
)
\theta_0 := \theta_0 - \alpha\frac{1}{m}\sum_{i=1}^{m}{(\theta_0+\theta_1x_i-y_i)}
θ0:=θ0−αm1i=1∑m(θ0+θ1xi−yi)
θ 1 : = θ 1 − α 1 m ∑ i = 1 m ( θ 0 + θ 1 x i − y i ) x i \theta_1 := \theta_1 - \alpha\frac{1}{m}\sum_{i=1}^{m}{(\theta_0+\theta_1x_i-y_i)x_i} θ1:=θ1−αm1i=1∑m(θ0+θ1xi−yi)xi
除了 θ \theta θ是未知的外,其他都是已知,就根据这两个式子来迭代求出 θ \theta θ。
梯度下降实现一元线性回归
# encoding:utf-8
import numpy as np
import matplotlib.pyplot as plt
# 读入数据
data = np.genfromtxt("../data/data.csv", delimiter=",")
x_data = data[:, 0]
y_data = data[:, 1]
# 学习率learning rate
lr = 0.0001
# 截距
b = 0
# 斜率
k = 0
# 迭代次数
epochs = 50
# 定义代价函数
def compute_loss(b, k, x_data, y_data):
total_loss = 0
for i in range(0, len(x_data)):
# 真实值减预测值平方后求和
total_loss += (y_data[i] - (k * x_data[i] + b)) ** 2
return total_loss / 2.0 / float(len(x_data))
# 用梯度下降法求出最好的k和b
def gradient_descent_runner(x_data, y_data, b, k, lr, epochs):
# 总数据量m
m = float(len(x_data))
# 开始迭代计算
for i in range(epochs):
# 这两个临时变量用来存当前的“梯度”
b_grad = 0
k_grad = 0
# 计算“梯度”
for j in range(0, len(x_data)):
b_grad += (1 / m) * ((k * x_data[j] + b) - y_data[j])
k_grad += (1 / m) * x_data[j] * ((k * x_data[j] + b) - y_data[j])
# 更新k和b
b = b - (lr * b_grad)
k = k - (lr * k_grad)
return b, k
# 输出相关信息
print("初始 b = {0},k = {1} 代价函数的值为 {2}".format(b, k, compute_loss(b, k, x_data, y_data)))
b, k = gradient_descent_runner(x_data, y_data, b, k, lr, epochs)
print("现在 b = {0},k = {1} 代价函数的值为 {2}".format(b, k, compute_loss(b, k, x_data, y_data)))
# 画图
plt.plot(x_data, y_data, 'b.')
plt.plot(x_data, k * x_data + b, 'r')
plt.show()
调库实现一元线性回归
# encoding:utf-8
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt
# 载入数据
data = np.genfromtxt("../data/data.csv", delimiter=",")
# LinearRegression要求传入的数据是两维
x_data = data[:, 0, np.newaxis]
y_data = data[:, 1, np.newaxis]
# 创建并拟合模型
model = LinearRegression()
model.fit(x_data, y_data)
# 画图
plt.plot(x_data, y_data, 'g.')
plt.plot(x_data, model.predict(x_data), 'brown')
plt.show()