线性回归
本系列重点在浅显易懂,快速上手。不进行过多的理论讲解:也就是不去深究what,而是关注how。全文围绕以下三个问题展开:
1)长什么样?
2)解决什么问题?
3)怎么实现?
3.1)从数学讲,原理
3.2)从代码上讲,如何掉包实现
长什么样
通俗的说就是解方程,先来回忆初中的二元一次方程组:
{ a ∗ x 11 + b ∗ x 21 = y 1 a ∗ x 12 + b ∗ x 22 = y 2 \begin{cases} a*x_{11} + b*x_{21} = y_1 \\ a*x_{12} + b*x_{22} = y_2 \end{cases} {a∗x11+b∗x21=y1a∗x12+b∗x22=y2
已知两组数
( x 11 = 1 x 21 = 2 y 1 = 3 ) , ( x 12 = 3 x 22 = 1 y 2 = 4 ) (x_{11}=1\ x_{21}=2\ y_1=3),(x_{12}=3\ x_{22}=1\ y_2=4) (x11=1 x21=2 y1=3),(x12=3 x22=1 y2=4)
求解a和b,很容易求的a=1,b=1。
上面是一个二元一次方程的例子,只不过线性回归的方程更加复杂,是m元n次(一般都是一次,效果不好的可以考虑多项式融合,就是多次方的)的方程:
{ a ∗ x 11 + b ∗ x 21 + . . . + z ∗ x m 1 + c = y 1 a ∗ x 12 + b ∗ x 22 + . . . + z ∗ x m 2 + c = y 2 . . . a ∗ x 1 n + b ∗ x 2 n + . . . + z ∗ x m n + c = y n \begin{cases} a*x_{11} + b*x_{21} + ... + z*x_{m1} + c = y_1 \\ a*x_{12} + b*x_{22} + ... + z*x_{m2} + c = y_2\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ .\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ .\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ .\\ a*x_{1n} + b*x_{2n} + ... + z*x_{mn} + c = y_n\\ \end{cases} ⎩ ⎨ ⎧a∗x11+b∗x21+...+z∗xm1+c=y1a∗x12+b∗x22+...+z∗xm2+c=y2 . . .a∗x1n+b∗x2n+...+z∗xmn+c=yn
解决什么问题
先看一组数据(一组sklearn中公开的数据集,波士顿的房价预测,共有13个特征,最后一列y是房价,这里只展示了5条数据,实际数据有506条):
采用线性回归建模,最终的目的就是为了找到一组θ_1,θ_2,…,θ_{13},θ_0(除了13个系数,还包含一个常数项θ_0),使得下式成立。
θ 1 ∗ x 1 + θ 2 ∗ x 2 + . . . . . . + θ 13 ∗ x 13 + θ 0 = y θ_1*x1+θ_2*x2+......+θ_{13}*x13+θ_0=y θ1∗x1+θ2∗x2+......+θ13∗x13+θ0=y
怎么实现
其实就是如何求解
θ
1
,
θ
2
,
.
.
.
,
θ
13
,
θ
0
θ_1,θ_2,...,θ_{13},θ_0
θ1,θ2,...,θ13,θ0,有两种方法:
1)最小二乘法(有缺陷,一般都是梯度下降法,具体看下文)
2)梯度下降法
最小二乘法
设
y i = θ T ∗ x i + ξ i y^i = θ^T*x^i+ξ^i yi=θT∗xi+ξi
python默认一个一维的向量,时列向量, x i x^i xi的格式是(13,1), θ T θ^T θT的格式是(1,13),(先不考虑常熟项), ξ i ξ^i ξi表示 y i y^i yi和 θ T ∗ x i θ^T*x^i θT∗xi之间的误差(机器学习不能求解到百分百准确的θ值,只能使得ξ^i值不断减小,也就是让预测值不断的逼近真实值y。
ξ i ξ^i ξi,假设是独立同分布的,服从均值为0,方差为 σ 2 σ^2 σ2的高斯分布,即:
他的联合分布概率是:
L ( θ ) L(θ) L(θ)就是样本的似然函数,转化为数学中求解θ最大似然估计值的问题,即:最大似然估计法(这里有兴趣的可以去补习数学上这块的知识,不想学习,可以只看下面的求解过程能看懂就行)
首先向将似然函数 L ( θ ) L(θ) L(θ)转换为对数似然函数 l o g ( L ( θ ) ) log(L(θ)) log(L(θ)):
要求
l
(
θ
)
l(θ)
l(θ)的最大值,转化为求
1
2
∑
i
=
1
m
(
y
i
−
θ
T
x
i
)
2
\frac{1}{2}\sum_{i=1}^{m}(y^i-θ^Tx^i)^2
21i=1∑m(yi−θTxi)2
的最小值,这就是目标函数(或者叫损失函数):
这就是最小二乘法的结果是一样的。
求解J(θ)的最小值,可以采用求解导函数,并使导函数为0的方式实现。
先将J(θ)转换为矩阵的形式:
具体的求解过程如下(这里需要用到矩阵求导的知识)直接维基百科有公式套用就行了,千万不要去过多的引入(学习一项新技能,最忌讳的就是,遇到一点不会的就恨不得把它祖宗三代都抛出来学习一边,一次性进行过于深入的学习,而深陷其中不能自拔,慢慢消磨殆尽学习的兴趣,应该是,就先学到会用的地步能解决当下的问题就赶紧停止,先学how怎么用,有机会了再去学what具体原理是怎么样的):
再求解:
X T X θ − X T Y = 0 X^TXθ-X^TY=0 XTXθ−XTY=0 得: θ = ( X T X ) − 1 X T Y θ=(X^TX)^{-1}X^TY θ=(XTX)−1XTY
到此最小二乘法,求解θ得过程讲解完毕,最小二乘法得缺陷也很明显了,首先要求X^TX是可逆的,为了防止不可逆,做如下更改,
θ = ( X T X + λ I ) − 1 X T Y θ=(X^TX+λI)^{-1}X^TY θ=(XTX+λI)−1XTY
最小二乘法直接求解的难处在于,逆矩阵的求解是个难点。
梯度下降法
1)确定目标函数,
2)初始化θ,(随机初始化或者初始化为0),
3)求解J(θ)的梯度,
∂ J ( θ ) ∂ θ = X T X θ − X T Y \frac{\partial J(θ)}{\partial θ} = X^TXθ-X^TY ∂θ∂J(θ)=XTXθ−XTY
4)沿着负梯度的方向更显θ,
θ = θ − α ∗ ∂ J ( θ ) ∂ θ , α 是学利率 θ = θ -α*\frac{\partial J(θ)}{\partial θ},α是学利率 θ=θ−α∗∂θ∂J(θ),α是学利率
迭代一定的轮次,直到损失函数的值不在下降为止。
手动代码实现
#coding=utf8
import numpy as np
import pandas as pd
from sklearn import datasets
from tqdm import tqdm, trange
import matplotlib.pyplot as plt
'''原函数'''
def F(theta,X):
return np.dot(X, theta)
'''损失函数'''
def J(theta, X, Y):
return float(1/2*np.dot((np.dot(X,theta)-Y).T, (np.dot(X,theta)-Y))[0][0])/len(X)
'''偏导数'''
def H(theta, X, Y):
return np.dot(X.T, np.dot(X,theta)-Y)/X.shape[0]
'''标准化'''
def standard_scaler(X):
#mean_ = np.mean(X,axis=0)
#std_ = np.std(X,axis=0)
#X = (X-mean_)/std_
max_ = np.max(X,axis=0)
min_ = np.min(X,axis=0)
X = (X-min_)/(max_-min_)
return X
if __name__ == "__main__":
data = datasets.load_boston()
X = data.data
X = standard_scaler(X)
Y = data.target.reshape(-1,1)
loss_list = []
theta = np.random.rand(X.shape[1], 1) # 初始化参数
eta = 0.01
with trange(100000) as T:
for i in T:
loss = J(theta, X, Y)
loss_list.append(loss)
theta = theta - eta*H(theta, X, Y)
T.set_postfix(loss=loss)
print(theta)
plt.plot(loss_list)
plt.show()
sklearn调包实现
这里直接讲解,如何调用sklearn实现。
from sklearn.linear_model import LinearRegression #sklearn中,线性回归模型在linear_model模块中
# 调取sklearn中自带的数据集
from sklearn.datasets import load_boston #调用上文一开始提到大波士顿房价数据集
X, y = load_boston(return_X_y=True) #获取X,y数据
LR = LinearRegression() #初始化一个线性回归模型
LR.fit(X,y) #fit函数用于训练
LR.predict(X) #predict函数用于预测
LR.coef_ #coef_用于返回θ的值
LR.intercept_ #intercept_用于返回常数项的值(截距)
更多内容可以参考sklearn的官方文档
sklearn.linear_model.LinearRegression — scikit-learn 1.3.0 documentation