1.线性回归
线性回归是源于统计学,是结合机器学习和统计学的重要算法。本文是从机器学习角度,阐述线性回归算法。
1.1 基本形式
给定数据集D={( x 1 x_1 x1, y 1 y_1 y1),(( x 2 x_2 x2, y 2 y_2 y2),…,(( x m x_m xm, y m y_m ym)},其中 x i x_i xi=( x i 1 x_{i1} xi1; x i 2 . . . x_{i2}... xi2... x i n x_{in} xin), y i y_i yi ∈ \in ∈R,【线性回归】试图学得一个线性模型以尽可能准确地预测实值输出标记。
一般表示形式:
f
(
x
)
f(x)
f(x) =
θ
0
+
θ
1
x
1
+
θ
2
x
2
⋯
+
θ
n
x
n
\theta_0 +\theta_1x_1+\theta_2x_2\cdots+\theta_nx_n
θ0+θ1x1+θ2x2⋯+θnxn
如果变量只有一个,即 f ( x ) f(x) f(x) = θ 0 + θ 1 x 1 \theta_0 +\theta_1x_1 θ0+θ1x1,则是一元线性回归;变量有多个,则是多元线性回归。
1.2 如何求参数 θ \theta θ
有了基本表达式,x是已知的,参数 θ \theta θ未知,我们希望求出一组参数 θ \theta θ,使得预测的 f ( x ) f(x) f(x)越接近真实值y越好,那如何衡量 f ( x ) f(x) f(x)与y的差别呢?可以使用误差平方和,也可以称为残差平方和,表示为:
∑ i = 1 m ( f ( x i ) − y ) 2 \sum_{i=1}^m(f(x_i)-y)^2 ∑i=1m(f(xi)−y)2
-
我们希望误差平方和越小越好,越小表明预测的越准确;当误差平方和为0时,表示预测值与真实值完全一致。
-
误差平方和也有几何意义,它对应的是欧几里得距离(欧式距离)。
所以我们问题转化为当 θ \theta θ为多少时,可使得误差平方和最小。
总结上述过程:
- 提出假设(Hypothesis)函数:
f ( x ) f(x) f(x) = θ 0 + θ 1 x 1 + θ 2 x 2 ⋯ + θ n x n \theta_0 +\theta_1x_1+\theta_2x_2\cdots+\theta_nx_n θ0+θ1x1+θ2x2⋯+θnxn - 待估计参数(Parameters):
θ 0 \theta_0 θ0, θ 1 \theta_1 θ1,…, θ n \theta_n θn - 确定损失函数(Cost Funciton):
J ( θ ) J( \theta) J(θ) = 1 2 m ∑ i = 1 m ( f ( x i ) − y ) 2 \frac{1}{2m}\sum_{i=1}^m(f(x_i)-y)^2 2m1∑i=1m(f(xi)−y)2
(比均方误差多成了系数 1 2 m \frac{1}{2m} 2m1,只是为了求导方便) - 目标(Goal):
最小化 J ( θ ) J( \theta) J(θ)
1.3 求解参数 θ \theta θ方法
1.3.1 最小二乘法矩阵求解
损失函数 J ( θ ) J( \theta) J(θ) = 1 2 m ∑ i = 1 m ( f ( x i ) − y ) 2 \frac{1}{2m}\sum_{i=1}^m(f(x_i)-y)^2 2m1∑i=1m(f(xi)−y)2是关于参数 θ \theta θ的凸函数,当参数 θ \theta θ的导数为0时,得到 θ \theta θ的最优解。
f
(
x
)
f(x)
f(x) =
θ
0
+
θ
1
x
1
+
θ
2
x
2
⋯
+
θ
n
x
n
\theta_0 +\theta_1x_1+\theta_2x_2\cdots+\theta_nx_n
θ0+θ1x1+θ2x2⋯+θnxn ,按照矩阵写法可表示为:
f
(
x
)
f(x)
f(x) =
X
θ
X\theta
Xθ ,
X
X
X是特征矩阵。
损失函数表示为:
J ( θ ) J( \theta) J(θ) = ∑ i = 1 m ( f ( x i ) − y ) 2 \sum_{i=1}^m(f(x_i)-y)^2 ∑i=1m(f(xi)−y)2 = ∑ i = 1 m ( X θ − y ) 2 \sum_{i=1}^m(X\theta-y)^2 ∑i=1m(Xθ−y)2
求导过程:
∂ ∂ θ ( X θ − y ) 2 \frac{\partial}{\partial\theta}(X\theta-y)^2 ∂θ∂(Xθ−y)2
= ∂ ∂ θ ( X θ − y ) T ( X θ − y ) =\frac{\partial}{\partial\theta}(X\theta-y)^T(X\theta-y) =∂θ∂(Xθ−y)T(Xθ−y)
∵ ( A − B ) T = A T − B T \because(A-B)^T= A^T-B^T ∵(A−B)T=AT−BT, ( A B ) T = B T ∗ A T (AB)^T=B^T*A^T (AB)T=BT∗AT
∴ = ∂ ∂ θ ( θ T X T − y T ) ( X θ − y ) \therefore=\frac{\partial}{\partial\theta}(\theta^TX^T-y^T)(X\theta-y) ∴=∂θ∂(θTXT−yT)(Xθ−y)
= ∂ ∂ θ ( θ T X T X θ − θ T X T y − y T X θ + y T y ) =\frac{\partial}{\partial\theta}(\theta^TX^TX\theta-\theta^TX^Ty-y^TX\theta+y^Ty) =∂θ∂(θTXTXθ−θTXTy−yTXθ+yTy)
= 2 X T X θ − 2 X T y =2X^TX\theta-2X^Ty =2XTXθ−2XTy
令 ∂ ∂ θ J ( θ ) = 0 \frac{\partial}{\partial\theta}J(\theta)=0 ∂θ∂J(θ)=0,即
2 X T X θ − 2 X T y = 0 2X^TX\theta-2X^Ty=0 2XTXθ−2XTy=0
⇒ X T X θ = X T y \Rightarrow X^TX\theta=X^Ty ⇒XTXθ=XTy
⇒ θ = ( X T X ) − 1 X T y \Rightarrow \theta=(X^TX)^{-1}X^Ty ⇒θ=(XTX)−1XTy
注意:上式 θ \theta θ有解的前提是 X T X X^TX XTX的逆矩阵存在。
1.3.2 梯度下降法
-
随机找一点,可确定初始 θ \theta θ参数值
-
不断迭代变动 θ \theta θ,来减小 J ( θ ) J(\theta) J(θ)一直到最小:
θ j : = θ j − α ∗ ∂ ∂ θ j J ( θ ) \theta_j:=\theta_j-\alpha*\frac{\partial}{\partial\theta_j}J(\theta) θj:=θj−α∗∂θj∂J(θ)
∂ ∂ θ j J ( θ ) = ∂ ∂ θ ( 1 2 m ∑ i = 1 m f θ ( x ) ( i ) − y ( i ) ) 2 \frac{\partial}{\partial\theta_j}J(\theta)=\frac{\partial}{\partial\theta}(\frac{1}{2m}\sum_{i=1}^{m}f_\theta(x)^{(i)}-y^{(i)})^2 ∂θj∂J(θ)=∂θ∂(2m1∑i=1mfθ(x)(i)−y(i))2
= 2 ∗ 1 2 m ∑ i = 1 m [ ( f θ ( x ) ( i ) − y ( i ) ) ∗ ∂ ∂ θ j ( θ j x j ( i ) − y ( i ) ) ] = 2* \frac{1}{2m}\sum_{i=1}^{m}[(f_\theta(x)^{(i)}-y^{(i)})*\frac{\partial}{\partial\theta_j}(\theta_jx_j^{(i)}-y^{(i)})] =2∗2m1∑i=1m[(fθ(x)(i)−y(i))∗∂θj∂(θjxj(i)−y(i))]
= 1 m ∑ i = 1 m ( f θ ( x ) ( i ) − y ( i ) ) ∗ x j ( i ) =\frac{1}{m}\sum_{i=1}^{m}(f_\theta(x)^{(i)}-y^{(i)})*x_j^{(i)} =m1∑i=1m(fθ(x)(i)−y(i))∗xj(i)
即:
θ
j
:
=
θ
j
−
α
∗
1
m
∑
i
=
1
m
(
f
θ
(
x
)
(
i
)
−
y
(
i
)
)
∗
x
j
(
i
)
\theta_j:=\theta_j-\alpha*\frac{1}{m}\sum_{i=1}^{m}(f_\theta(x)^{(i)}-y^{(i)})*x_j^{(i)}
θj:=θj−α∗m1i=1∑m(fθ(x)(i)−y(i))∗xj(i)
注意: θ j ( θ 0 , θ 1 , . . . ) \theta_j(\theta_0,\theta_1,...) θj(θ0,θ1,...)同时一起变动,直到收敛,达到局部最优。(对于线性回归损失函数,只有一个最优,局部最优即全局最优)
1.4 线性回归评价指标
- 均方误差(MSE): 1 m ∑ i = 1 m ( y i − y ^ i ) 2 \frac{1}{m}\sum_{i=1}^m(y_i-\hat y_i)^2 m1∑i=1m(yi−y^i)2
- 均方根误差(RMSE): M S E = 1 m ∑ i = 1 m ( y i − y ^ i ) 2 \sqrt {MSE}=\sqrt {\frac{1}{m}\sum_{i=1}^m(y_i-\hat y_i)^2} MSE=m1∑i=1m(yi−y^i)2
- 平均绝对误差(MAE): 1 m ∑ i = 1 m ∣ y i − y ^ i ∣ \frac{1}{m}\sum_{i=1}^m\vert y_i-\hat y_i\vert m1∑i=1m∣yi−y^i∣
- R方: R 2 = E S S S S T = 1 − R S S S S T = 1 − ∑ i = 1 m ( y i − y ^ i ) 2 ∑ i = 1 m ( y i − y ˉ ) 2 R^2 =\frac{ESS}{SST}=1-\frac{RSS}{SST}=1-\frac{\sum_{i=1}^m(y_i-\hat y_i)^2}{\sum_{i=1}^m(y_i-\bar y)^2} R2=SSTESS=1−SSTRSS=1−∑i=1m(yi−yˉ)2∑i=1m(yi−y^i)2 ( R 2 R^2 R2越接近1越好)
1.5 代码实现
1.5.1 sklearn.linear_model.LinearRegression
sklearn.linear_model.LinearRegression(fit_intercept=True,normalize=False,copy_X=True,n_jobs=None)
参数 | 含义 |
---|---|
fit_intercept | 是否计算截距项;布尔值,默认为True |
normalize | 是否在回归前将特征矩阵标准化处理:减去均值并除以L2范式;布尔值,默认为False;当it_intercept为False时忽略此参数。建议如需标准化处理,请在训练模型前使用sklearn.preprocessing中的StandardScaler处理。 |
copy_X | 布尔值,默认为True ,将在X.copy()上操作,否则X会被改写 |
n_job | 整数值,默认为None表示为1;用于计算的线程数;-1表示使用全部的CPU来计算 |
属性 | 含义 |
---|---|
coef_ | 返回估计系数 θ \theta θ,数组形式;如果标签为1未,返回数组形状是(n_featrures,),如果标签为二维,返回数组形式为(n_targets,n_features)二维数组 |
intercept_ | 返回截距项 |
方法 | 含义 |
---|---|
fit(X,y,sample_weight) | X代表训练样本数据,y代表目标数据即标签,sample为样本标签设置权重 |
get_params() | 返回模型的参数设置 |
predict(X) | 返回模型预测的结果 |
score | 返回模型评估指标,为 R 2 R^2 R2 |
例子:
import numpy as np
from sklearn.linear_model import LinearRegression
# 生成数据
np.random.seed(1234)
x = np.random.rand(500,3)
#构建映射关系,模拟真实的数据待预测值,映射关系为y = 4.2 + 5.7*x1 + 10.8*x2,可自行设置值进行尝试
y = x.dot(np.array([4.2,5.7,10.8]))
# 调用sklearn模型
lr = LinearRegression()
# 训练模型
lr.fit(x,y)
print("估计的参数值为:%s" %(lr.coef_))
# 计算R平方
print('R2:%s' %(lr.score(x,y)))
# 任意设定变量,预测目标值
x_test = np.array([2,4,5]).reshape(1,-1)
y_hat = lr.predict(x_test)
print("预测值为: %s" %(y_hat))
1.5.2 最小二乘矩阵求解代码实现
class LR_LS():
def __init__(self):
self.w = None
def fit(self, X, y):
# 最小二乘法矩阵求解
#============================= show me your code =======================
self.w = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)
#============================= show me your code =======================
def predict(self, X):
# 用已经拟合的参数值预测新自变量
#============================= show me your code =======================
y_pred = X.dot(self.w)
#============================= show me your code =======================
return y_pred
if __name__ == "__main__":
lr_ls = LR_LS()
lr_ls.fit(x,y)
print("估计的参数值:%s" %(lr_ls.w))
x_test = np.array([2,4,5]).reshape(1,-1)
print("预测值为: %s" %(lr_ls.predict(x_test)))
1.5.3 梯度下降法代码实现
class LR_GD():
def __init__(self):
self.w = None
def fit(self,X,y,alpha=0.02,loss = 1e-10): # 设定步长为0.002,判断是否收敛的条件为1e-10
y = y.reshape(-1,1) #重塑y值的维度以便矩阵运算
[m,d] = np.shape(X) #自变量的维度
self.w = np.zeros((d)) #将参数的初始值定为0
tol = 1e5
#============================= show me your code =======================
while tol > loss:
h_f = X.dot(self.w).reshape(-1,1)
theta = self.w + alpha*np.mean(X*(y - h_f),axis=0) #计算迭代的参数值
tol = np.sum(np.abs(theta - self.w))
self.w = theta
#============================= show me your code =======================
def predict(self, X):
# 用已经拟合的参数值预测新自变量
y_pred = X.dot(self.w)
return y_pred
if __name__ == "__main__":
lr_gd = LR_GD()
lr_gd.fit(x,y)
print("估计的参数值为:%s" %(lr_gd.w))
x_test = np.array([2,4,5]).reshape(1,-1)
print("预测值为:%s" %(lr_gd.predict(x_test)))
后续,希望把Lasso,Ridge也补充进来。
【参考资料】
- 吴恩达机器学习
- 菜菜的sklearn课堂
- DataWhale开源学习项目