1. 目标
线性回归是希望通过对样本集进行有监督的学习之后,找出特征属性与标签属性之间的线性关系
Θ
\Theta
Θ。从而在获取没有标签值的新数据时,根据特征值和线性关系,对标签值进行预测。
2. 算法原理
2.1 线性模型(Linear Model)
在二维平面坐标系中,一条直线可表示为:
f
(
x
)
=
θ
1
x
+
θ
0
f(x) = \theta_1x + \theta_0
f(x)=θ1x+θ0
扩展到n维空间中,则表示为:
f
(
x
)
=
θ
0
+
θ
1
x
1
+
θ
2
x
2
+
.
.
.
+
θ
n
x
n
f(x) = \theta_0+\theta_1x_1+\theta_2x_2+...+\theta_nx_n
f(x)=θ0+θ1x1+θ2x2+...+θnxn
同时可写成向量的形式:
f
(
x
)
=
Θ
T
X
f(x) = \Theta^TX
f(x)=ΘTX
其中
X
=
[
x
0
,
x
1
,
x
2
,
.
.
.
,
x
n
]
T
(
x
0
=
1
)
;
Θ
=
[
θ
0
,
θ
1
,
θ
2
,
.
.
.
,
θ
n
]
T
X = [x_0,x_1,x_2,...,x_n]^T(x_0=1);\Theta = [\theta_0,\theta_1,\theta_2,...,\theta_n]^T
X=[x0,x1,x2,...,xn]T(x0=1);Θ=[θ0,θ1,θ2,...,θn]T
2.2 损失函数(Loss Function)
当有了样本集
D
=
{
(
X
i
,
y
i
)
}
i
=
1
n
D = \{(X_i,y_i)\}^n_{i=1}
D={(Xi,yi)}i=1n,即视作空间中的n个离散点之后,如何对这些点进行拟合,形成一个曲面方程,则成为需要解决的问题。
根据线性模型可知,想要改变曲面拟合的形状,我们可以调整的是特征属性前的系数
Θ
\Theta
Θ。
为了使曲面与样本集中的点拟合的更好,需要设定一个评判标准,即损失函数:
J
(
θ
0
,
θ
1
,
.
.
.
,
θ
m
)
=
1
2
n
∑
i
=
1
n
(
h
θ
(
X
i
)
−
y
i
)
2
J(\theta_0,\theta_1,...,\theta_m) = \frac{1}{2n}\sum^n_{i=1}(h_\theta(X_i)-y_i)^2
J(θ0,θ1,...,θm)=2n1i=1∑n(hθ(Xi)−yi)2
其中:
h
θ
(
X
)
=
f
(
X
)
h_\theta(X) = f(X)
hθ(X)=f(X),只不过
h
θ
(
X
)
h_\theta(X)
hθ(X)是根据变量
θ
\theta
θ变化的。
损失函数的意思是,在
Θ
\Theta
Θ 确定时,每组属性
X
i
X_i
Xi均能根据线性函数获取到相应的
f
(
X
i
)
f(X_i)
f(Xi)即
h
θ
(
X
i
)
h_\theta(X_i)
hθ(Xi),而
y
i
y_i
yi是样本集中给出的标签值,将二者相减再取平方,获取到某一组特征拟合结果与标签值的差异。然后对每组求得得差异求和后除以
2
n
2n
2n计算出数值,作为当前
Θ
\Theta
Θ 前提下得损失值。
而损失函数本身如果画出来是一条关于
Θ
\Theta
Θ 的曲线。
问题就转化成了求损失函数的最小值
2.3 梯度下降
梯度下降是一种求凸函数极值的方法,这种方法是求取函数在某一个点的斜率,并根据设定的学习率
α
\alpha
α,调整
Θ
\Theta
Θ ,迭代的向损失函数的极小值靠近,最终求得
Θ
\Theta
Θ。公式如下:
θ
j
=
θ
j
−
α
d
d
θ
j
J
(
θ
j
)
\theta_j = \theta_j - \alpha\frac{d}{d\theta_j}J(\theta_j)
θj=θj−αdθjdJ(θj)
其中
d
d
θ
j
J
(
θ
j
)
\frac{d}{d\theta_j}J(\theta_j)
dθjdJ(θj)是损失函数关于
θ
j
\theta_j
θj的斜率,乘上设定的系数后,迭代递减。
至此 Θ \Theta Θ 可求,问题也得以解决,但其实还存在两个问题:
- 引入的 α \alpha α 如何给值,太小会导致收敛速度慢,太大又会导致震荡或者不收敛?
- 当模型复杂的时候, J ( Θ ) J(\Theta) J(Θ)是一个高阶函数,会把样本中的噪声特性也学习下来,虽然能完美的拟合样本集,却泛化能力差,即过拟合
2.4 通过正则化减小过拟合风险
损失函数变为:
J
(
Θ
)
=
1
2
n
[
∑
i
=
1
n
(
h
θ
(
X
i
)
−
y
i
)
2
+
λ
∑
j
=
1
m
θ
j
2
]
J(\Theta) = \frac{1}{2n}[\sum^n_{i=1}(h_\theta(X_i)-y_i)^2+\lambda\sum^m_{j=1}\theta_j^2]
J(Θ)=2n1[i=1∑n(hθ(Xi)−yi)2+λj=1∑mθj2]
其中
λ
∑
j
=
1
m
θ
j
2
\lambda\sum^m_{j=1}\theta_j^2
λ∑j=1mθj2是正则项,用于控制大量参数对拟合的影响。
2.5 学习率的选取
结论是通常会尝试一系列学习率的取值:0.001, 0.003,0.01, 0.03,0.1, 0.3,1,
初始值0.001, 如此循环直至找到最合适的
α
\alpha
α。然后对于这些不同的
α
\alpha
α 值,绘制
J
(
Θ
)
J(\Theta)
J(Θ) 随迭代步数变化的曲线,然后选择看上去使其快速下降的值。
3. Python实例 - 波士顿房价
sklearn库中提供了几种数据集,load_boston是波士顿房价的数据集,以此进行实验。
3.1 双变量拟合 - 模拟算法原理
import numpy as np
from sklearn.datasets import load_boston
import matplotlib.pyplot as plt
# 解决中文乱码问题
import matplotlib.font_manager as fm
chinesefont = fm.FontProperties(fname='C:/Windows/Fonts/msyh.ttc')
# 获取数据
boston = load_boston()
# 仅以LSTAT属性作为特征的散点图
# 人口中低下人群所占比例
# x = [x1,x2,...,xn]; y = [y1,y2,...,yn]
x = boston.data[:,12]
y = boston.target
plt.scatter(x,y,s=10, c='r')
plt.xlabel('人口中地下人群所占比例',fontproperties=chinesefont)
plt.ylabel('房价,单位$1000',fontproperties=chinesefont)
plt.show()
# 转换X向量和Y向量
# X = [[1,x1],[1,x2],...,[1,xn]]
# Y = [[y1],[y2],...,[yn]]
X = np.c_[np.ones(x.shape[0]),x]
Y = y.reshape(y.shape[0],1)
# 定义以上损失函数cost
# cost = theta0 + theta1 * x
def cost(X, Y, theta=[[0],[0]]):
J = 0
m = Y.size
h = X.dot(theta)
J = 1.0/(2*m)*(np.sum(np.square(h-y)))
# 加入正则项 lambda = 1 时
# J = 1.0/(2*m)*((np.sum(np.square(h-y)))+ 1 * np.sum(np.square(theta)))
return J
# 定义梯度下降函数
# 此处用的是最大迭代次数限制进行循环,也可以使用下降判断进行循环
def gradientDescent(X, Y, theta=[[0],[0]], alpha=0.009, num_iters=1500):
m = Y.size
J_history = np.zeros(num_iters)
for iter in np.arange(num_iters):
h = X.dot(theta)
theta = theta - alpha*(1.0/m)*(X.T.dot(h-Y))
J_history[iter] = cost(X, Y, theta)
return(theta, J_history)
# 执行梯度下降函数获得最终theta以及损失值列表CostJ
theta, CostJ = gradientDescent(X,Y)
# 绘制损失值列表,即损失函数
plt.plot(CostJ)
plt.xlabel('迭代次数',fontproperties=chinesefont)
plt.ylabel('损失函数值',fontproperties=chinesefont)
plt.show()
# 根据求得得theta,得到线性方程,进行拟合显示
y_predict = theta[0] + theta[1] * x
plt.scatter(x,y,s=10, c='r')
plt.xlabel('人口中地下人群所占比例',fontproperties=chinesefont)
plt.ylabel('房价,单位$1000',fontproperties=chinesefont)
plt.plot(x,y_predict )
3.2 sklearn中的LinearRegression 与 多变量拟合
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import sklearn.metrics
# 按照30%的比例对样本集进行拆分
X_train,X_test,y_train,y_test = train_test_split(boston.data,boston.target,test_size=0.3)
# 利用 sklearn 库 进行线性拟合
regr = LinearRegression()
regr.fit(X_train, y_train)
print(regr.intercept_,regr.coef_)
'''
> 37.160773310177426 [-1.07867550e-01 3.97141277e-02 1.99087321e-02 2.97904968e+00
-1.46457678e+01 3.47666820e+00 7.33405297e-05 -1.34668768e+00
2.85031315e-01 -1.16980362e-02 -9.81568374e-01 8.75851883e-03
-5.37797404e-01]
'''
# 对训练集和测试集进行预测
y_train_pred = regr.predict(X_train)
y_test_pred = regr.predict(X_test)
# 计算相应的MAE和RMSE,填入计算需要的值到括号中
print("Train MAE: ", sklearn.metrics.mean_absolute_error(y_train,y_train_pred))
print("Train RMSE: ", np.sqrt(sklearn.metrics.mean_squared_error(y_train,y_train_pred )))
print("Test MAE: ", sklearn.metrics.mean_absolute_error(y_test,y_test_pred ))
print("Test RMSE: ", np.sqrt(sklearn.metrics.mean_squared_error(y_test,y_test_pred )))
'''
> Train MAE: 3.141770205845444
Train RMSE: 4.575911160428769
Test MAE: 3.514234225409807
Test RMSE: 4.959841655342295
'''
学习不易,贵在坚持