赞
踩
我们先来看一个例子,如下图:给定x和y的关系
x | 3 | 5 | 7 | 8 | 13 |
---|---|---|---|---|---|
y | 3 | 5 | 7 | 8 | ? |
求x=13时,y的值为多少?
这里,很容易想到方程为y=x ,然后解得y=13
这就是线性回归。
线性回归说白了,就是给我们一些数据,让我们找一条直线来拟合这些数据。
但是,实际问题中,x,y的分布,可能是这样的
x | 3 | 5 | 7 | 8 | 13 |
---|---|---|---|---|---|
y | 2 | 6 | 9 | 11 | ? |
这时,我们该如何计算y的值?
设此时的方程为y=kx+b
我们可能会找到很多方程,假设我们找到其中一条的方程的 k=0 ,b=4
当然我们也可能找 k=1 ,b= 3 的直线。
下图是 k=2,b= -5 时的拟合效果,即
y
=
2
∗
x
−
5
y=2*x-5
y=2∗x−5
那么,到底如何判断我们找的直线的拟合效果呢?
我们可以这样做:
计算所有点与该点的欧式距离 :
例如当x=3时 对应方程
y
=
2
∗
x
−
5
y=2*x-5
y=2∗x−5 的 y坐标为(3,1),
计算 (3,2) 与 (3,1) 点的距离 为 1
然后计算 x=5 时,(5,5) (5,6)两个点距离,
最后把所有点的距离相加
总距离 = ( 2 − 1 ) 2 + ( 6 − 5 ) 2 + ( 9 − 9 ) 2 + ( 11 − 11 ) 2 \sqrt{(2-1)^2}+\sqrt{(6-5)^2}+\sqrt{(9-9)^2}+\sqrt{(11-11)^2} (2−1)2 +(6−5)2 +(9−9)2 +(11−11)2
我们以这个值的大小作为判断该曲线是否拟合的好
不过,数学家用 残差平方和(RSS) 来衡量:
即 刚刚的式子不开根号
RSS=
(
2
−
1
)
2
+
(
6
−
5
)
2
+
(
9
−
9
)
2
+
(
11
−
11
)
2
{(2-1)^2}+{(6-5)^2}+{(9-9)^2}+{(11-11)^2}
(2−1)2+(6−5)2+(9−9)2+(11−11)2
RSS的值越小,表明该函数与原数据拟合的越好。
这里我们对RSS进行一般化表示,在方程
y
^
=
k
∗
x
^
+
b
\hat{y}=k*\hat{x}+b
y^=k∗x^+b 中:
RSS=
(
y
1
^
−
y
1
)
2
+
(
y
2
^
−
y
2
)
2
+
(
y
3
^
−
y
3
)
2
+
.
.
.
.
+
(
y
n
^
−
y
n
)
2
{(\hat{y_1}-y_1)^2}+{(\hat{y_2}-y_2)^2}+{(\hat{y_3}-y_3)^2}+....+{(\hat{y_n}-y_n)^2}
(y1^−y1)2+(y2^−y2)2+(y3^−y3)2+....+(yn^−yn)2 =
∑
i
=
1
n
(
y
i
^
−
y
i
)
2
\displaystyle \sum^{n}_{i=1 }{(\hat{y_i}-y_i)^2}
i=1∑n(yi^−yi)2
由于 y i ^ = k ∗ x i ^ + b \hat{y_i}=k*\hat{x_i}+b yi^=k∗xi^+b ,所以
RSS= ( k ∗ x 1 ^ + b − y 1 ) 2 + ( k ∗ x 2 ^ + b − y 2 ) 2 + . . . . + ( k ∗ x n ^ + b − y n ) 2 {(k*\hat{x_1}+b-y_1)^2}+{(k*\hat{x_2}+b-y_2)^2}+....+{(k*\hat{x_n}+b-y_n)^2} (k∗x1^+b−y1)2+(k∗x2^+b−y2)2+....+(k∗xn^+b−yn)2 = ∑ i = 1 n ( k ∗ x i ^ + b − y i ) 2 \displaystyle \sum^{n}_{i=1 }{(k*\hat{x_i}+b-y_i)^2} i=1∑n(k∗xi^+b−yi)2
现在要求RSS的最小值,我们只要算得RSS方程中导数为0的点即可
令
f
(
k
,
b
)
=
∑
i
=
1
n
(
k
∗
x
i
^
+
b
−
y
i
)
2
f(k,b)=\displaystyle \sum^{n}_{i=1 }{(k*\hat{x_i}+b-y_i)^2}
f(k,b)=i=1∑n(k∗xi^+b−yi)2
只要求出导数最为0的点就可求出 k,b
第一步
首先对k求偏导
∂
f
(
k
,
b
)
∂
k
=
2
∑
i
=
1
n
(
k
∗
x
i
^
+
b
−
y
i
)
x
i
^
=
2
k
∑
i
=
1
n
x
i
^
2
+
2
b
∑
i
=
1
n
x
i
^
−
2
∑
i
=
1
n
y
i
x
i
^
\frac{\partial f(k,b)}{\partial k}=2\displaystyle \sum^{n}_{i=1 }{(k*\hat{x_i}+b-y_i)}\hat{x_i}=2k\sum^{n}_{i=1 }\hat{x_i}^2+2b\sum^{n}_{i=1 }\hat{x_i}-2\sum^{n}_{i=1 }y_i\hat{x_i}
∂k∂f(k,b)=2i=1∑n(k∗xi^+b−yi)xi^=2ki=1∑nxi^2+2bi=1∑nxi^−2i=1∑nyixi^
令偏导为0
可得
2
k
∑
i
=
1
n
x
i
^
2
+
2
b
∑
i
=
1
n
x
i
^
=
2
∑
i
=
1
n
y
i
x
i
^
2k\sum^{n}_{i=1 }\hat{x_i}^2+2b\sum^{n}_{i=1 }\hat{x_i}=2\sum^{n}_{i=1 }y_i\hat{x_i}
2k∑i=1nxi^2+2b∑i=1nxi^=2∑i=1nyixi^
第二步
对b求偏导
∂
f
(
k
,
b
)
∂
b
=
2
∑
i
=
1
n
(
k
∗
x
i
^
+
b
−
y
i
)
=
2
∑
i
=
1
n
k
∗
x
i
^
+
2
n
b
−
2
∑
i
=
1
n
y
i
\frac{\partial f(k,b)}{\partial b}=2\displaystyle \sum^{n}_{i=1 }{(k*\hat{x_i}+b-y_i)}=2\displaystyle \sum^{n}_{i=1 }k*\hat{x_i}+2nb-2\displaystyle \sum^{n}_{i=1 }y_i
∂b∂f(k,b)=2i=1∑n(k∗xi^+b−yi)=2i=1∑nk∗xi^+2nb−2i=1∑nyi
令偏导为0
2
∑
i
=
1
n
k
∗
x
i
^
+
2
n
b
=
2
∑
i
=
1
n
y
i
2\displaystyle \sum^{n}_{i=1 }k*\hat{x_i}+2nb=2\displaystyle \sum^{n}_{i=1 }y_i
2i=1∑nk∗xi^+2nb=2i=1∑nyi
同除2n
⇒
k
x
ˉ
+
b
=
y
ˉ
\Rightarrow k\bar{x}+b=\bar{y}
⇒kxˉ+b=yˉ
第三步
将
b
=
y
ˉ
−
k
x
ˉ
b=\bar{y}-k\bar{x}
b=yˉ−kxˉ 带入第一步我们所求的式子中
可得
k
∑
i
=
1
n
x
i
^
2
+
(
y
ˉ
−
k
x
ˉ
)
∗
∑
i
=
1
n
x
i
^
=
∑
i
=
1
n
y
i
x
i
^
k\sum^{n}_{i=1 }\hat{x_i}^2+(\bar{y}-k\bar{x})*\sum^{n}_{i=1 }\hat{x_i}=\sum^{n}_{i=1 }y_i\hat{x_i}
k∑i=1nxi^2+(yˉ−kxˉ)∗∑i=1nxi^=∑i=1nyixi^
⇒
k
∑
i
=
1
n
x
i
^
2
+
y
ˉ
∗
∑
i
=
1
n
x
i
^
−
k
x
ˉ
∗
∑
i
=
1
n
x
i
^
=
∑
i
=
1
n
y
i
x
i
^
\Rightarrow k\sum^{n}_{i=1 }\hat{x_i}^2+\bar{y}*\sum^{n}_{i=1 }\hat{x_i}-k\bar{x}*\sum^{n}_{i=1 }\hat{x_i}=\sum^{n}_{i=1 }y_i\hat{x_i}
⇒k∑i=1nxi^2+yˉ∗∑i=1nxi^−kxˉ∗∑i=1nxi^=∑i=1nyixi^
⇒
k
(
∑
i
=
1
n
x
i
^
2
−
x
ˉ
∗
∑
i
=
1
n
x
i
^
)
=
∑
i
=
1
n
y
i
x
i
^
−
y
ˉ
∗
∑
i
=
1
n
x
i
^
\Rightarrow k(\sum^{n}_{i=1 }\hat{x_i}^2-\bar{x}*\sum^{n}_{i=1 }\hat{x_i})=\sum^{n}_{i=1 }y_i\hat{x_i}-\bar{y}*\sum^{n}_{i=1 }\hat{x_i}
⇒k(∑i=1nxi^2−xˉ∗∑i=1nxi^)=∑i=1nyixi^−yˉ∗∑i=1nxi^
⇒ k = ( ∑ i = 1 n y i x i ^ − y ˉ ∗ ∑ i = 1 n x i ^ ) ( ∑ i = 1 n x i ^ 2 − x ˉ ∗ ∑ i = 1 n x i ^ ) \Rightarrow k=\frac {(\sum^{n}_{i=1 }y_i\hat{x_i}-\bar{y}*\sum^{n}_{i=1 }\hat{x_i})} {(\sum^{n}_{i=1 }\hat{x_i}^2-\bar{x}*\sum^{n}_{i=1 }\hat{x_i})} ⇒k=(∑i=1nxi^2−xˉ∗∑i=1nxi^)(∑i=1nyixi^−yˉ∗∑i=1nxi^)
到此我们已经把k求出来了,将k带回 b = y ˉ − k x ˉ b=\bar{y}-k\bar{x} b=yˉ−kxˉ 可以求出b
虽然上面已经求出k和b,但是这只是一元函数。但是,如过方程有三个变量,四个变量,那该如何下手?
例如一个三元方程:
f
(
x
1
,
x
2
,
x
3
)
=
k
1
∗
x
1
+
k
2
∗
x
2
+
k
3
∗
x
3
+
b
f(x_1,x_2,x_3)=k_1*x_1+k_2*x_2+k_3*x_3+b
f(x1,x2,x3)=k1∗x1+k2∗x2+k3∗x3+b
再用上述方法来求解会非常复杂
于是我们将上述方程转换成矩阵形式
f
(
k
,
b
)
=
(
k
∗
x
1
^
+
b
−
y
1
)
2
+
(
k
∗
x
2
^
+
b
−
y
2
)
2
+
.
.
.
+
(
k
∗
x
n
^
+
b
−
y
n
)
2
f(k,b)={(k*\hat{x_1}+b-y_1)^2}+{(k*\hat{x_2}+b-y_2)^2}+...+{(k*\hat{x_n}+b-y_n)^2}
f(k,b)=(k∗x1^+b−y1)2+(k∗x2^+b−y2)2+...+(k∗xn^+b−yn)2
=
=
=
[
(
k
∗
x
1
^
+
b
−
y
1
)
,
(
k
∗
x
2
^
+
b
−
y
2
)
,
⋯
,
(
k
∗
x
n
^
+
b
−
y
n
)
]
∗
[
(
k
∗
x
1
^
+
b
−
y
1
)
(
k
∗
x
2
^
+
b
−
y
2
)
⋮
(
k
∗
x
n
^
+
b
−
y
n
)
]
\left[
令
θ
=
[
k
b
]
\theta=\left[
令
X
=
[
x
1
^
,
1
x
2
^
,
1
⋮
x
n
^
,
1
]
X=\left[
令
Y
=
[
y
1
y
2
⋮
y
n
]
Y=\left[
原方程=
(
(
(
X
θ
−
Y
)
T
(
X
θ
−
Y
)
X\theta - Y)^T(X\theta - Y)
Xθ−Y)T(Xθ−Y)
接下来,只要对
θ
\theta
θ求导,我们就可以得到正规方程
那么,如何对一个矩阵求导?矩阵求导到底是什么?
在介绍矩阵求导前,先了解一下标量函数与向量函数
标量函数:
f
(
x
)
=
x
2
f(x)= x^2
f(x)=x2 即输出为一个值
向量函数:
f
(
x
)
=
[
x
x
2
]
f(x)=\left[
矩阵求导的本质:
d
A
d
B
\frac {dA} {dB}
dBdA矩阵A中的每个元素对矩阵B中的每一个元素求导
标量函数对向量求导
求
d
f
(
x
)
d
X
\frac {df(x)} {dX}
dXdf(x):
其中
f
(
x
)
=
f
(
x
1
,
x
2
,
.
.
.
x
n
)
f(x)=f(x_1,x_2,...x_n)
f(x)=f(x1,x2,...xn)
X
=
[
x
1
x
2
⋮
x
n
]
X=\left[
标量函数对矩阵的结果为
d
f
(
x
)
d
X
=
[
d
f
(
x
)
d
x
1
d
f
(
x
)
d
x
2
⋮
d
f
(
x
)
d
x
n
]
\frac {df(x)} {dX}=\left[
向量函数对标量求导
f
(
x
)
=
[
f
1
(
x
)
f
2
(
x
)
⋮
f
n
(
x
)
]
f(x)=\left[
向量函数对标量求导的结果为
d
f
(
x
)
d
x
=
[
d
f
1
(
x
)
d
x
,
d
f
2
(
x
)
d
x
,
⋯
,
d
f
n
(
x
)
d
x
]
\frac {df(x)} {dx}=\left[
向量函数对向量求导
f
(
x
)
=
[
f
1
(
x
)
f
2
(
x
)
⋮
f
n
(
x
)
]
f(x)=\left[
更具标量对向量以及向量对标量,我们可得向量函数对向量求导的结果为
X
=
[
x
1
x
2
⋮
x
n
]
X=\left[
d
f
(
x
)
d
X
=
[
d
f
1
(
x
)
d
x
1
,
d
f
2
(
x
)
d
x
1
,
⋯
,
d
f
n
(
x
)
d
x
1
d
f
2
(
x
)
d
x
2
,
d
f
2
(
x
)
d
x
2
,
⋯
,
d
f
n
(
x
)
d
x
2
⋮
d
f
n
(
x
)
d
x
n
,
d
f
2
(
x
)
d
x
n
,
⋯
,
d
f
n
(
x
)
d
x
n
]
\frac {df(x)} {dX}=\left[
f
(
x
)
=
A
T
X
=
∑
i
=
1
n
a
i
x
i
f(x)=A^TX=\displaystyle \sum^{n}_{i=1 }a_ix_i
f(x)=ATX=i=1∑naixi
求
d
f
(
x
)
d
X
\frac {df(x)} {dX}
dXdf(x) 对X求导
其中
A
=
[
a
1
,
a
2
,
.
.
.
,
a
n
]
A=[a_1,a_2,...,a_n]
A=[a1,a2,...,an]
很明显,这里 f(x)为标量,X为向量
所以,结果为
d
f
(
x
)
d
X
=
[
d
f
(
x
)
d
x
1
d
f
(
x
)
d
x
2
⋮
d
f
(
x
)
d
x
n
]
=
[
d
(
a
1
x
1
)
d
x
1
d
(
a
2
x
2
)
d
x
2
⋮
d
a
n
x
n
d
x
n
]
=
[
a
1
a
2
⋮
a
n
]
=
A
\frac {df(x)} {dX}=\left[
由于
f
(
x
)
=
X
T
A
=
∑
i
=
1
n
a
i
x
i
f(x)=X^TA=\displaystyle \sum^{n}_{i=1 }a_ix_i
f(x)=XTA=i=1∑naixi
所以
f
(
x
)
=
X
T
A
,
和
f
(
x
)
=
A
T
X
对
矩
阵
X
的
导
为
A
f(x)=X^TA,和f(x)=A^TX对矩阵X的导为A
f(x)=XTA,和f(x)=ATX对矩阵X的导为A
由于原方程=
(
(
(
X
θ
−
Y
)
T
(
X
θ
−
Y
)
=
(
θ
T
X
T
−
Y
T
)
(
X
θ
−
Y
)
=
θ
T
X
T
X
θ
−
θ
T
X
T
Y
−
Y
T
X
θ
+
Y
T
Y
X\theta - Y)^T(X\theta - Y)=(\theta^TX^T-Y^T)(X\theta-Y)=\theta^T X^TX\theta-\theta^T X^TY-Y^TX\theta+Y^TY
Xθ−Y)T(Xθ−Y)=(θTXT−YT)(Xθ−Y)=θTXTXθ−θTXTY−YTXθ+YTY
对
θ
\theta
θ求导数的结果为
2
X
T
X
θ
−
2
X
T
Y
2X^TX\theta-2X^TY
2XTXθ−2XTY
令原始为 0
可以求得
θ
=
(
X
T
X
)
−
1
X
T
Y
\theta=(X^TX)^{-1}X^TY
θ=(XTX)−1XTY (正规方程)
现在,即使是多元函数,我们也可以方便求解了
知道了原理,接下来,使用代码来实现一下回归。
import numpy as np from sklearn.model_selection import train_test_split from numpy.linalg import inv date = np.loadtxt("./date/aqi.csv", delimiter=",", skiprows=1, dtype=np.float32) # delimiter: 以逗号分开 dtype:加载时的数据类型 # skiprows:删除第一条数据(标题) index = np.ones((date.shape[0], 1)) # 生成一列全部为1的数据 (正规方程需要多一列的数据) date = np.hstack((date, index)) # 插入一列 x = date[:, 1:] # 截取行(第0行到最后一行),列(第1行到最后一列) y = date[:, 0] # 截取行(第0行到最后一行),列(第0列) # print(x) # 将数据分隔为训练集和验证集 train_x, test_x, train_y, test_y = train_test_split(x, y, train_size = 0.7) # 百分之80的数据为训练集,20为验证集 theta = np.dot(np.dot(inv(np.dot(train_x.T, train_x)), train_x.T), train_y) # 正规方程 # np.dot()矩阵相乘 inv() 求逆 .T 转置 predict = np.dot(test_x, theta) print(test_x[:, 0]) print(predict) import matplotlib.pyplot as plt # 对预测结果与实际结果进行显示,比较 plt.plot(range(len(test_y)), test_y, c="red", alpha=0.5) plt.plot(range(len(test_y)), predict, c="blue", alpha=0.5) plt.show()
其中aqi.csv的数据为
x,y
1,1.1
2,2.3
3,3.1
4,4.5
5,5.4
6,6.7
7,7.8
8,9
9,9.7
10,11
举个例子,在方程
y
=
x
2
y=x^2
y=x2中,我们如何求该函数的最小值?
由于该方程比较简单。我们可以直接得出,当x为0 时,y最小为0
但是,在方程
y
=
−
x
1
2
+
6
x
2
2
+
3
x
3
2
−
5
x
4
2
y=-x_1^2+6x_2^2+3x_3^2-5x_4^2
y=−x12+6x22+3x32−5x42中,我们如何求他的最小值呢?
这时候,梯度下降的优势就体现出来了。
还是从
y
=
x
2
y=x^2
y=x2开始,要求得y的最小值,我们可以给x随机取一个值,判断在改点的导数大小,如果导数大于0,说明y在增大,我们后退一点;如果导数小于0,说明y在减小,就对x增大一些。
具体的方程为:
x
x
x的更新值=上一次
x
的
值
−
k
∗
d
y
d
x
x的值-k*\frac {dy} {dx}
x的值−k∗dxdy,然后对该方程进行迭代
其中k为我们随机取的一个小数。
实现过程:
第一步 首先我们随机取x,令x=-10,随机取k,令k=0.1,
很明显
d
y
d
x
=
2
x
\frac {dy} {dx}=2x
dxdy=2x,带入更新方程:
x
x
x的更新值=上一次
x
的
值
−
k
∗
d
y
d
x
x的值-k*\frac {dy} {dx}
x的值−k∗dxdy
X
=
−
10
−
0.1
∗
2
∗
(
−
10
)
=
−
8
X=-10-0.1*2*(-10)=-8
X=−10−0.1∗2∗(−10)=−8
第二步 对方程进行迭代,刚刚得到的x为-8,所以新的x值为
X
=
−
8
−
0.1
∗
2
∗
(
−
8
)
=
−
6.4
X=-8-0.1*2*(-8)=-6.4
X=−8−0.1∗2∗(−8)=−6.4
迭代5次后,得到的图像为上图所示
方程代码如下:
import numpy as np import matplotlib.pyplot as plt x = -10 A = [-10] B = [100] for i in range(5): # 迭代5次 y = 2*x # 导数为2x x = x-0.1*y # 更新方程 A.append(round(x, 2)) B.append(round(x*x, 2)) x = np.arange(-10, 10, 0.01) y = x*x fig = plt.figure() ax = fig.add_subplot(111) for xy in zip(A, B): ax.annotate('(%s, %s)' % xy, xy=xy, textcoords='data') # 绘制(x,y) plt.plot(A, B, "ro") # 绘制点 plt.plot(x, y) plt.title("") plt.show()
下图是迭代10次后的结果:
这里,可以发现,随着迭代次数的增加,方程会越来越接近最小值。
好了,现在回到原来的问题,如何求方程
y
=
−
x
1
2
+
6
x
2
2
+
3
x
3
2
−
5
x
4
2
y=-x_1^2+6x_2^2+3x_3^2-5x_4^2
y=−x12+6x22+3x32−5x42的最小值。这个问题似乎还是有点难!
知道了一元函数,我们还是从二元函数入手。
现在,求
z
=
x
2
+
y
2
z=x^2+y^2
z=x2+y2的最小值
第一步 随机取,x和y的值 ,这里 我们 取 (x=3,y=4) ,取k为0.1,
d
z
d
x
=
2
x
\frac {dz} {dx}=2x
dxdz=2x,
d
z
d
y
=
2
y
\frac {dz} {dy}=2y
dydz=2y ,
(x,y)=(3,4)-0.1(6,8)=(2.4,3.2)
第二步 对x,y进行迭代,刚刚求得的(x,y)=(2.4,3.2),
新一轮的结果为(x,y)=(2.4,3.2)-0.1(4.8,6.4)=(1.92,2.56)
迭代5次的效果图为下图所示:
我们发现红点渐渐向最低点移动了
迭代源码:
from matplotlib import pyplot as plot # 用来绘制图形 import numpy as np # 用来处理数据 from mpl_toolkits.mplot3d import Axes3D # 用来给出三维坐标系。 figure = plot.figure() # 画出三维坐标系: axes = Axes3D(figure) X = np.arange(-5, 5, 0.25) Y = np.arange(-5, 5, 0.25) x = 3 y = 4 # 初始 x 与 y 的坐标 A = [3] B = [4] C = [25] # A B C 存放 x,y,z的坐标变化 for i in range(5): # 循环5次 x = x-0.1*2*x y = y-0.1*2*y A.append(round(x, 2)) B.append(round(y, 2)) C.append(round(x*x+y*y, 2)) # 限定图形的样式是网格线的样式: X, Y = np.meshgrid(X, Y) Z = (X) ** 2 + (Y) ** 2 # 绘制曲面,采用彩虹色着色: axes.scatter(A, B, C, c='r', marker='o') axes.plot_surface(X, Y, Z, cmap='rainbow') # 图形可视化: plot.show()
下图为迭代100次的效果图:
在这里,k有个专业的名称,称之为学习率,一般用
a
a
a代替
原方程为
f
(
k
,
b
)
=
∑
i
=
1
n
(
k
∗
x
i
^
+
b
−
y
i
)
2
f(k,b)=\displaystyle \sum^{n}_{i=1 }{(k*\hat{x_i}+b-y_i)^2}
f(k,b)=i=1∑n(k∗xi^+b−yi)2
要求f(k,b)的最小值,
第一步 和之前的做法类似,首先任意取k和b的值,取a为0.1,求得
∂
f
(
k
,
b
)
∂
k
,
∂
f
(
k
,
b
)
∂
k
\frac{\partial f(k,b)}{\partial k}, \frac{\partial f(k,b)}{\partial k}
∂k∂f(k,b),∂k∂f(k,b)后,带入
(
x
i
^
,
y
i
)
(\hat{x_i},y_i)
(xi^,yi),设带入后的结果为 A,B
根据之前的梯度下降算法,得(k,b)=(k,b)-0.1(A,B)
第二步 对(k,b)做反复迭代。
还是之前的x,y分布
x | 3 | 5 | 7 | 8 | 13 |
---|---|---|---|---|---|
y | 2 | 6 | 9 | 11 | ? |
现在,用梯度下降来拟合
第一步 任意取k和b,令 k=1,b=6,这里a要取的稍微小些,取a=0.001,
首先对k求偏导
∂
f
(
k
,
b
)
∂
k
=
2
∑
i
=
1
n
(
k
∗
x
i
^
+
b
−
y
i
)
x
i
^
=
2
k
∑
i
=
1
n
x
i
^
2
+
2
b
∑
i
=
1
n
x
i
^
−
2
∑
i
=
1
n
y
i
x
i
^
\frac{\partial f(k,b)}{\partial k}=2\displaystyle \sum^{n}_{i=1 }{(k*\hat{x_i}+b-y_i)}\hat{x_i}=2k\sum^{n}_{i=1 }\hat{x_i}^2+2b\sum^{n}_{i=1 }\hat{x_i}-2\sum^{n}_{i=1 }y_i\hat{x_i}
∂k∂f(k,b)=2i=1∑n(k∗xi^+b−yi)xi^=2ki=1∑nxi^2+2bi=1∑nxi^−2i=1∑nyixi^
然后对b求偏导
∂
f
(
k
,
b
)
∂
b
=
2
∑
i
=
1
n
(
k
∗
x
i
^
+
b
−
y
i
)
=
2
∑
i
=
1
n
k
∗
x
i
^
+
2
n
b
−
2
∑
i
=
1
n
y
i
\frac{\partial f(k,b)}{\partial b}=2\displaystyle \sum^{n}_{i=1 }{(k*\hat{x_i}+b-y_i)}=2\displaystyle \sum^{n}_{i=1 }k*\hat{x_i}+2nb-2\displaystyle \sum^{n}_{i=1 }y_i
∂b∂f(k,b)=2i=1∑n(k∗xi^+b−yi)=2i=1∑nk∗xi^+2nb−2i=1∑nyi
k和更新后的值为(k,b)=
(
1
,
6
)
−
0.001
∗
(
(
2
∗
1
∗
(
3
2
+
5
2
+
7
2
+
8
2
)
+
2
∗
6
∗
(
3
+
5
+
7
+
8
)
−
2
∗
(
2
∗
3
+
5
∗
6
+
7
∗
9
+
8
∗
11
)
,
(
2
∗
k
∗
(
3
+
5
+
7
+
8
)
+
2
∗
4
∗
6
−
2
∗
(
2
+
6
+
9
+
11
)
(1,6)-0.001*((2*1*(3^2+5^2+7^2+8^2)+2*6*(3+5+7+8)-2*(2*3+5*6+7*9+8*11),(2*k*(3+5+7+8)+2*4*6-2*(2+6+9+11)
(1,6)−0.001∗((2∗1∗(32+52+72+82)+2∗6∗(3+5+7+8)−2∗(2∗3+5∗6+7∗9+8∗11),(2∗k∗(3+5+7+8)+2∗4∗6−2∗(2+6+9+11)=(0.804,5.971)
第二步 对k和b的值进行反复的迭代
迭代到50次的k为0.39,b为5.57,图像如下图所示
迭代50次的python源码
import numpy as np import matplotlib.pyplot as plt k = 1 b = 6 x = [3, 5, 7, 8] y = [2, 6, 9, 11] A = [] B = [] xsum = 0 # x1*x1+x2*x2+... xxsum = 0 # x1+x2+x3+x4.. ysum = 0 yysum = 0 xysum = 0 # x1*y1+x2*y2+... f=0 for i in x: xsum += i*i for i in x: xxsum += i for i in y: ysum += i*i for i in y: yysum += i for i in range(len(x)): xysum += x[i]*y[i] for i in range(50): # 循环50次 k = k-0.001*(2*k*xsum+2*b*xxsum-2*xysum) b = b-0.001*(2*k*xxsum+2*4*b-2*yysum) A.append(round(k, 2)) B.append(round(b, 2)) f = 0 for i in range(len(x)): f += (k * x[i] + b - y[i]) ** 2 print("loss={},k={},b={}".format(f, k, b)) fig = plt.figure() ax = fig.add_subplot(111) for xy in zip(x, y): ax.annotate('(%s, %s)' % xy, xy=xy, textcoords='data') # 绘制(x,y) x1 = np.arange(0, 10, 0.01) y1 = k * x1 + b plt.plot(x1, y1) plt.plot(x, y, "ro") # 绘制点 plt.title("") plt.show()
当迭代到1000次时,k,b如下图所示:
此时k=1.11,b=0.98
当迭代到10000次时,可以看出,已经和直线非常拟合了,
此时的k=1.76,b= -3.13
from sklearn.model_selection import train_test_split from sklearn import linear_model #线性模型 import numpy as np date = np.loadtxt("./date/aqi.csv", delimiter=",", skiprows=1, dtype=np.float32) # delimiter:以,分开 dtype:加载时的数据类型 x = date[:, 1:] y = date[:, 0] train_x, test_x, train_y, test_y = train_test_split(x, y, train_size=0.7) model = linear_model.LinearRegression() # 线性回归模型对象 model.fit(train_x, train_y) print(model.coef_) # 系数 (权重) print(model.intercept_) # 截距 (偏置) y_predict = model.predict(test_x) import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ["SimHei"] # 支持中文 plt.title("预测") plt.xlabel("x 轴") plt.ylabel("y 轴") plt.scatter(test_x, test_y, c="r") # 画点 plt.plot(test_x, y_predict, c="blue") # 画直线 plt.show()
如何把训练好的模型保存下来?
from sklearn.model_selection import train_test_split
from sklearn import linear_model #线性模型
import numpy as np
import pickle
date = np.loadtxt("./date/aqi.csv", delimiter=",", skiprows=1, dtype=np.float32) # delimiter:以,分开 dtype:加载时的数据类型
x = date[:, 1:]
y = date[:, 0]
train_x, test_x, train_y, test_y = train_test_split(x, y, train_size=0.7)
model = linear_model.LinearRegression() # 线性回归模型对象
model.fit(train_x, train_y)
with open("model.pickle", "wb") as f: # 模型的保存
pickle.dump(model, f)
调用自己训练好的模型
import pickle
with open("model.pickle", "rb") as f:
model = pickle.load(f)
test = [[23]]
y_predict = model.predict(test)
print(y_predict)
假设有一批数据,让你求x=13时,y的值为多少。其中y的值只为0或者1
x | 3 | 5 | 7 | 8 | 13 |
---|---|---|---|---|---|
y | 0 | 0 | 1 | 1 | ? |
我们首先用刚刚的线性回归的方法,进行拟合直线
然后把x=13带入方程,这里求得的k为0.23,b为-0.86,求得y为2.13。
现在,如何判断y的值呢?
首先,我们刚刚的拟合方法是有些问题的,因为y不是连续函数。
在这里,我们显然只要找一条直线,只要将两类数据划分开来就行了。我们随机划分一条直线,
上图为,k=0.15,b=-0.4 时
y
^
=
k
x
+
b
\hat{y}=kx+b
y^=kx+b的图像。接下来如何算x=13时,y的值呢?
我们可以这样,首先分别计算,x为3,5,7,8时 ,
y
^
\hat{y}
y^的取值
x=3时,
y
^
=
0.15
∗
3
−
0.4
=
0.05
\hat{y}=0.15*3-0.4=0.05
y^=0.15∗3−0.4=0.05
x=5时,
y
^
=
0.15
∗
5
−
0.4
=
0.35
\hat{y}=0.15*5-0.4=0.35
y^=0.15∗5−0.4=0.35
x=7时,
y
^
=
0.15
∗
7
−
0.4
=
0.65
\hat{y}=0.15*7-0.4=0.65
y^=0.15∗7−0.4=0.65
x=8时,
y
^
=
0.15
∗
8
−
0.4
=
0.8
\hat{y}=0.15*8-0.4=0.8
y^=0.15∗8−0.4=0.8
然后,我们现在取一个在x=5和x=7时,
y
^
\hat{y}
y^的值作为分界线(0.35,0.65)
我们随机取值为 0.5,即
y
^
\hat{y}
y^大于0.5,y为1;
y
^
\hat{y}
y^小于0.5,y为0
接下来算x=13时,
y
^
\hat{y}
y^=0.15*13-0.4=1.55
因为
y
^
\hat{y}
y^>0.5所以y的值为 1
但是,我们画出的图像却是这样的
我们原本是想用这条直线来划分两类,但是由于数据的增加,我们不得不重新选择k与b的值了。
那么有没有什么办法把这条直线映射到另一个方便观察的线条呢?
数学家把他映射到了
y
=
1
1
+
e
−
z
y=\frac{1}{1+e^{-z}}
y=1+e−z1
上图,我们可以看出,该线条很好的映射出了
y
^
\hat{y}
y^与y的映射关系。该函数称为sigmoid函数,也叫logistic函数。
逻辑回归实际上解决的是分类问题,即如何把离散的点映射到线段。那么为什么不叫逻辑"分类"。据说因为它是从线性回归推导过来的。
在线性回归中我们的损失函数为,RSS=
∑
i
=
1
n
(
y
^
−
y
i
)
2
\displaystyle \sum^{n}_{i=1 }{(\hat{y}-y_i)^2}
i=1∑n(y^−yi)2 其中
y
^
=
k
∗
x
i
^
+
b
\hat{y}=k*\hat{x_i}+b
y^=k∗xi^+b
在逻辑回归中,我们的
y
^
=
1
1
+
e
−
y
\hat{y}=\frac{1}{1+e^{-y}}
y^=1+e−y1其中
y
=
k
∗
x
i
^
+
b
{y}=k*\hat{x_i}+b
y=k∗xi^+b,如果我们也用RSS。
R
S
S
=
(
1
−
0.78
)
2
+
(
1
−
0.66
)
2
+
(
1
−
0.63
)
2
+
0.5
7
2
+
0.5
1
2
RSS = (1-0.78)^2+(1-0.66)^2+(1-0.63)^2+0.57^2+0.51^2
RSS=(1−0.78)2+(1−0.66)2+(1−0.63)2+0.572+0.512
看起来用这个损失函数,似乎也没有什么问题。但是使用该函数作为损失函数,如果使用梯度下降法的话,会产生多个局部最优解。为什么还会有多个局部优?
设损失函数为f(k,b)=
∑
i
=
1
n
(
1
1
+
e
−
(
k
∗
x
i
^
+
b
)
−
y
i
)
2
\displaystyle \sum^{n}_{i=1 }{(\frac{1}{1+e^{-(k*\hat{x_i}+b)}}-y_i)^2}
i=1∑n(1+e−(k∗xi^+b)1−yi)2 ,要求出
∂
f
(
k
,
b
)
∂
k
\frac{\partial f(k,b)}{\partial k}
∂k∂f(k,b)
我们先化简方程
y
^
=
1
1
+
e
−
y
\hat{y}=\frac{1}{1+e^{-y}}
y^=1+e−y1的导数,
∂
y
^
∂
y
=
e
−
y
(
1
+
e
−
y
)
2
=
1
+
e
−
y
−
1
(
1
+
e
−
y
)
2
=
y
^
−
y
^
2
\frac{\partial \hat{y}}{\partial y}=\frac{e^{-y}}{(1+e^{-y})^2}=\frac{1+e^{-y}-1}{(1+e^{-y})^2}=\hat{y}-\hat{y}^2
∂y∂y^=(1+e−y)2e−y=(1+e−y)21+e−y−1=y^−y^2,求出
y
^
\hat{y}
y^导后, 这里只是其中一个项的导数
∂
f
(
k
,
b
)
∂
k
=
2
(
y
^
−
y
i
)
∗
(
y
^
−
y
^
2
)
∗
x
i
^
\frac{\partial f(k,b)}{\partial k}=2{({\hat{y}}-y_i)}*(\hat{y}-\hat{y}^2)*\hat{x_i}
∂k∂f(k,b)=2(y^−yi)∗(y^−y^2)∗xi^
想要判断其凹凸性,我们需要对其做二阶导数=
∂
(
2
(
y
^
−
y
i
)
(
y
^
−
y
^
2
)
∗
x
i
^
)
∂
k
=
∂
(
2
(
y
^
2
−
y
^
3
−
y
^
y
i
+
y
^
2
y
i
)
∗
x
i
^
)
∂
k
=
2
x
i
^
(
2
y
^
−
3
y
^
2
−
y
i
+
2
y
^
y
i
)
∗
(
y
^
−
y
^
2
)
∗
x
i
^
\frac{\partial (2{({\hat{y}}-y_i)}(\hat{y}-\hat{y}^2)*\hat{x_i})}{\partial k}=\frac{\partial(2{({\hat{y}}^2-{\hat{y}}^3}-\hat{y}y_i+\hat{y}^2y_i)*\hat{x_i})}{\partial k}=2\hat{x_i}(2\hat{y}-3{\hat{y}}^2-y_i+2\hat{y}y_i)*(\hat{y}-\hat{y}^2)*\hat{x_i}
∂k∂(2(y^−yi)(y^−y^2)∗xi^)=∂k∂(2(y^2−y^3−y^yi+y^2yi)∗xi^)=2xi^(2y^−3y^2−yi+2y^yi)∗(y^−y^2)∗xi^
函数的二阶导数有什么特性呢?
例如方程
y
=
x
2
y=x^2
y=x2中,函数的一阶导为2x,所以在左半轴,导数小于0,y值逐渐减小;在右半轴,导数大于0,y值逐渐变大。函数的二阶导为2,所以无论x取何值,二阶导恒大于0,
我们可以看到,二阶导大于0时,为凸函数,
接下来,我们对刚刚的导数
2
x
i
^
(
2
y
^
−
3
y
^
2
−
y
i
+
2
y
^
y
i
)
∗
(
y
^
−
y
^
2
)
∗
x
i
^
2\hat{x_i}(2\hat{y}-3{\hat{y}}^2-y_i+2\hat{y}y_i)*(\hat{y}-\hat{y}^2)*\hat{x_i}
2xi^(2y^−3y^2−yi+2y^yi)∗(y^−y^2)∗xi^进行分析,
假设
y
i
=
0
,
y
^
{y}_i=0,\hat{y}
yi=0,y^在(0,1)内时,方程=
2
x
i
^
2
(
2
y
^
−
3
y
^
2
)
∗
(
y
^
−
y
^
2
)
2\hat{x_i}^2(2\hat{y}-3{\hat{y}}^2)*(\hat{y}-\hat{y}^2)
2xi^2(2y^−3y^2)∗(y^−y^2)
由于
y
^
\hat{y}
y^在(0,1)时,
2
x
i
^
2
2\hat{x_i}^2
2xi^2恒大于0,
(
y
^
−
y
^
2
)
(\hat{y}-\hat{y}^2)
(y^−y^2)恒大于0,
2
y
^
−
3
y
^
2
2\hat{y}-3{\hat{y}}^2
2y^−3y^2有正有负,所以凹凸性都存在。所以使用残差平方和不能作为逻辑回归的损失函数。
为了求逻辑回归的损失函数,我们需要知道什么是最大似然估计
什么是最大似然估计?
举一个别人博客的一个例子。
假如有一个罐子,里面有黑白两种颜色的球,数目多少不知,两种颜色的比例也不知。我们想知道罐中白球和黑球的比例,但我们不能把罐中的球全部拿出来数。现在我们可以每次任意从已经摇匀的罐中拿一个球出来,记录球的颜色,然后把拿出来的球 再放回罐中。这个过程可以重复,我们可以用记录的球的颜色来估计罐中黑白球的比例。假如在前面的4次重复记录中,有1次是白球,请问罐中白球所占的比例最有可能是多少?
很多人马上就有答案了:
1
4
\frac{1}{4}
41
为什么大家都会想到
1
4
\frac{1}{4}
41
假设罐中白球的比例是p,那么黑球的比例就是1-p。
极大似然函数的思想就是:使之前出现的场景概率最大。
例如刚刚的场景:取到3次黑球,一次白球,写成函数即:
y
=
(
1
−
p
)
∗
(
1
−
p
)
∗
(
1
−
p
)
∗
p
y=(1-p)*(1-p)*(1-p)*p
y=(1−p)∗(1−p)∗(1−p)∗p, 我们画出它的图像
从图像可以看出,p为0.25时,y的最大值为0.10546875。
这不是我们刚刚估计的结果值嘛,不过这是刚刚用计算机跑出来的结果!
现在,再用方程的思想来解y的最大值,由于ln()函数具有很好的单调性,而且可以把连乘拆分。
所以要求
y
=
(
1
−
p
)
∗
(
1
−
p
)
∗
(
1
−
p
)
∗
p
y=(1-p)*(1-p)*(1-p)*p
y=(1−p)∗(1−p)∗(1−p)∗p的最大值,就等价与求
l
n
(
y
)
=
l
n
(
(
1
−
p
)
∗
(
1
−
p
)
∗
(
1
−
p
)
∗
p
)
ln(y)=ln((1-p)*(1-p)*(1-p)*p)
ln(y)=ln((1−p)∗(1−p)∗(1−p)∗p)的最大值。
求
l
n
(
y
)
ln(y)
ln(y)的最大值,只需要对p求导,并且让其导数为0即可。
原始=
l
n
(
1
−
p
)
+
l
n
(
1
−
p
)
+
l
n
(
1
−
p
)
+
l
n
(
p
)
ln(1-p)+ln(1-p)+ln(1-p)+ln(p)
ln(1−p)+ln(1−p)+ln(1−p)+ln(p),求导后=
−
3
1
−
p
+
1
p
-\frac{3}{1-p}+\frac{1}{p}
−1−p3+p1
令其为0,解得p为0.25,这与之前用计算机跑出的结果一致。
了解了极大似然估计,理解逻辑回归的损失函数就很简单了。
首先,logistic函数表示的是一个概率值,
y
^
=
1
1
+
e
−
y
\hat{y}=\frac{1}{1+e^{-y}}
y^=1+e−y1,如果真实值为1,那么
y
^
\hat{y}
y^越大,表明效果越好;如果真实值为0,那么
y
^
\hat{y}
y^越小,表明效果越好。
我们随机找一个函数:
f
(
y
^
,
y
i
)
f(\hat{y},y_i)
f(y^,yi),当
y
i
y_i
yi为1时,损失函数为
1
−
y
^
1-\hat{y}
1−y^,当
y
i
y_i
yi为0时,损失函数为
y
^
\hat{y}
y^。
写出最大似然函数
=
∏
i
=
1
n
(
1
−
y
^
)
1
−
y
i
∗
y
^
y
i
=\prod_{i=1}^n(1-\hat{y})^{1-y_i}*{\hat{y}}^{y_i}
=∏i=1n(1−y^)1−yi∗y^yi,当
y
i
y_i
yi为1时,
y
^
\hat{y}
y^有效,且
y
^
\hat{y}
y^越大,似然函数越大
根据最大似然函数的值,我们可以知道似然函数的最大值,就是最接近结果的真实值,对似然函数取log的话,
∑
i
=
1
n
[
(
1
−
y
i
)
l
o
g
(
(
1
−
y
^
)
)
+
y
i
l
o
g
(
y
^
)
]
\displaystyle \sum^{n}_{i=1 }[({1-y_i})log((1-\hat{y}))+{y_i}log({\hat{y}})]
i=1∑n[(1−yi)log((1−y^))+yilog(y^)],加负号的话就成了损失函数。因为损失值的话是越小越好,所以logistic的损失函数为loss=
−
∑
i
=
1
n
[
(
1
−
y
i
)
l
o
g
(
(
1
−
y
^
)
)
+
y
i
l
o
g
(
y
^
)
]
-\displaystyle \sum^{n}_{i=1 }[({1-y_i})log((1-\hat{y}))+{y_i}log({\hat{y}})]
−i=1∑n[(1−yi)log((1−y^))+yilog(y^)]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。