算法梳理(一)线性回归原理及实现
机器学习相关概念
监督学习
监督学习(supervised learning )利用训练数据集学习一个模型, 再用模型对测试样本集进行预测。且这个训练集是人工给出的并且是带有标签的,因此成为监督学习。(包括参数 /非参数算法,支持向量机,核函神经网络 )
非监督学习
无监督学习(unspuervised learning)是指训练样本的标记信息是未知的,目标是通过无标记训练样本的学习来揭示数据的内在性质和规律。常见的有聚类算法等。
泛化能力
泛化能力(generalization ability)是指由该方法学习到的模型对未知数据的预测能力,是学习方法本质上重要性质。(参考统计学习方法1.6)
现实中多采用测试误差来评价学习方法的泛化能力。但过于依赖测试集,评价结果往往不准确。
其他一些泛化性能的评估方法有,查准率,查全率,ROC和AUC等。
过拟合和欠拟合
当学习器将训练样本学得“太好”了的时候, 很可能已经把训练样本本身的一些特点当作了所有潜在样本都会有一般性质,导致泛化性能下降,则为“过拟合”(overfitting),与之相对的则为“欠拟合”。
偏差,方差与噪声(参考机器学习2.5):
- 偏差 度量了学习算法的期望预测与真实结果的偏离程度,即刻画了学习算法本身的拟合能力;
- 方差 度量了同样大小的训练集的变动所导致的学习性能的变化,即刻画了数据扰动所构成的影响。
- 噪声 则表达了在当前任务上任何学习算法所能达到的期望泛化误差的下界,即刻画了学习任务本身的难度。
因此,为了取得好的泛化性能,则需使偏差较小,即能充分拟合数据,并使方差较小,即能使数据扰动产生的影响小。
交叉验证
在现实生活中往往有多个学习算法模型可供选择,甚至对同一个学习算法,当使用不同的参数时,也会产生不同的模型。如何选择?便涉及到机器学习中“模型选择”(model selection)的问题。
“交叉验证法”(cross validation)先将数据集D划分为K个大小相似的互斥子集。每个子集都尽可能保持数据分布的一致性,即从D中分层采样得到。然后每次有用k-1个子集的并集作为训练集,预想的那个子集作为测试集。(详细参照机器学习2.2.2)
线性回归算法
原理
线性回归主要的用途是解决线性问题,蕴含着许多机器学习中的重要思想,是许多强大的非线性模型的基础。本文用来重点梳理一下自己理解的线性回归模型的一些知识,如有不当之处,还请指正。
首先理清一下代价函数,损失函数,目标函数的概念(具体可参考文章1 ) (文章2)
- 损失函数:计算的是一个样本的误差
- 代价函数:是整个训练集上所有样本误差的平均
- 目标函数:代价函数 + 正则化项
线性回归(Linear Regression)是利用称为线性回归方程的最小平方函数对一个或多个自变量和因变量之间关系进行建模的一种回归分析。这种函数是一个或多个称为回归系数的模型参数的线性组合(自变量都是一次方)。只有一个自变量的情况称为简单回归,大于一个自变量情况的叫做多元回归。
优点:思想简单,容易实现,具有良好的可解释性
模型分析:
寻找一条直线最大程度的拟合样本特征和输出标记之间的关系
假设: 预测值为
y
^
(
i
)
=
a
x
(
i
)
+
b
\widehat{y}^{(i)}=ax^{(i)}+b
y
(i)=ax(i)+b
真实值为
y
y
y
y
^
(
i
)
\widehat{y}^{(i)}
y
(i)与
y
y
y之间的误差的平方可写为
(
y
^
(
i
)
−
y
)
2
\left (\widehat{y}^{(i)}-y \right )^{2}
(y
(i)−y)2
则所有样本差距的和
J=
∑
1
m
(
y
−
y
^
(
i
)
)
2
\sum_{1}^{m}\left (y-\widehat{y}^{(i)} \right )^{2}
∑1m(y−y
(i))2
此时我们可以称J为此线性回归的损失函数
要使
1
2
m
∑
1
m
(
y
−
y
^
(
i
)
)
2
\frac{1}{2m}\sum_{1}^{m}\left (y-\widehat{y}^{(i)} \right )^{2}
2m1∑1m(y−y
(i))2最小
目标: 找到(a,b)使得
1
2
m
∑
1
m
(
y
−
a
x
(
i
)
−
b
)
2
\frac{1}{2m}\sum_{1}^{m}\left (y-ax^{(i)}-b \right )^{2}
2m1∑1m(y−ax(i)−b)2
均方误差有非常好的几何意义,它对应了常用的欧几里得距离
下面将介绍一下求参数的方法
最小二乘法
基于均方误差的最小化来进行模型求解的方法称为“最小二乘法”。在线性回归中最小二乘法就是找到一条直线,使得所有样本到直线上的欧式距离最小。
目标:找出(a,b)令
J
(
a
,
b
)
=
1
2
m
∑
1
m
(
y
−
a
x
(
i
)
−
b
)
2
J\left ( a,b \right )=\frac{1}{2m}\sum_{1}^{m}\left (y-ax^{(i)}-b \right )^{2}
J(a,b)=2m1∑1m(y−ax(i)−b)2尽可能小
则
{
∂
J
(
a
,
b
)
∂
a
=
0
∂
J
(
a
,
b
)
∂
b
=
0
\begin{cases}& \text{ } \frac{\partial J\left ( a,b \right ) }{\partial a}=0 \\ & \text{ } \frac{\partial J\left ( a,b \right ) }{\partial b}=0 \end{cases}
{ ∂a∂J(a,b)=0 ∂b∂J(a,b)=0
则可求出a和b的最优解的闭式解
{
a
=
∑
1
m
y
(
i
)
(
x
(
i
)
−
x
‾
)
∑
1
m
x
(
i
)
2
−
1
m
(
∑
1
m
x
(
i
)
)
2
b
=
1
m
∑
1
m
(
y
(
i
)
−
a
x
(
i
)
)
\begin{cases} & \text{ } a= \frac{\sum_{1}^{m}y^{(i)}(x^{(i)}-\overline{x})}{ \sum_{1}^{m}x^{(i)2}-\frac{1}{m}\left ( \sum_{1}^{m}x^{(i)} \right )^{2}}\\ & \text{ } b= \frac{1}{m} \sum_{1}^{m}(y^{(i)}-ax^{(i)}) \end{cases}
⎩⎨⎧ a=∑1mx(i)2−m1(∑1mx(i))2∑1my(i)(x(i)−x) b=m1∑1m(y(i)−ax(i))
其中
x
‾
\overline{x}
x是所有x的均值
优化方法
常见的优化方法有牛顿法,梯度下降法,拟牛顿法,此处将简单介绍梯度下降法。
梯度下降法不是一种机器学习算法,是一种基于搜索的最优化方法。为了方便我们直接将多元线性回归向量化。
目标:找出(a,b)令
J
(
a
,
b
)
=
∑
1
m
(
y
−
a
x
(
i
)
−
b
)
2
J\left ( a,b \right )=\sum_{1}^{m}\left (y-ax^{(i)}-b \right )^{2}
J(a,b)=∑1m(y−ax(i)−b)2尽可能小
使得
1
2
m
∑
1
m
(
y
(
i
)
−
θ
0
−
θ
1
x
1
(
i
)
−
θ
2
x
2
(
i
)
−
.
.
.
−
θ
n
x
n
(
i
)
)
2
\frac{1}{2m}\sum_{1}^{m}\left ( y^{(i)} -\theta _{0}-\theta _{1}x_{1}^{(i)}-\theta _{2}x_{2}^{(i)}-...-\theta _{n}x_{n}^{(i)}\right )^{2}
2m1∑1m(y(i)−θ0−θ1x1(i)−θ2x2(i)−...−θnxn(i))2
Δ
J
(
θ
)
=
(
∂
J
∂
θ
0
∂
J
∂
θ
1
∂
J
∂
θ
2
.
.
.
∂
J
∂
θ
n
)
=
(
∑
1
m
2
(
y
(
i
)
−
x
b
(
i
)
⋅
θ
)
⋅
(
−
1
)
∑
1
m
2
(
y
(
i
)
−
x
b
(
i
)
⋅
θ
)
⋅
(
−
x
1
(
i
)
)
∑
1
m
2
(
y
(
i
)
−
x
b
(
i
)
⋅
θ
)
⋅
(
−
x
2
(
i
)
)
.
.
.
∑
1
m
2
(
y
(
i
)
−
x
b
(
i
)
⋅
θ
)
⋅
(
−
x
n
(
i
)
)
)
\Delta J\left ( \theta \right )=\begin{pmatrix} \frac{\partial J}{\partial \theta _{0}}\\ \frac{\partial J}{\partial \theta _{1}}\\ \frac{\partial J}{\partial \theta _{2}}\\ ...\\ \frac{\partial J}{\partial \theta _{n}} \end{pmatrix} = \begin{pmatrix} \sum_{1}^{m}2\left ( y^{(i)}-x_{b}^{(i)}\cdot\theta \right )\cdot \left ( -1 \right )\\ \sum_{1}^{m}2\left ( y^{(i)}-x_{b}^{(i)}\cdot\theta \right )\cdot \left ( -x_{1}^{(i)} \right )\\ \sum_{1}^{m}2\left ( y^{(i)}-x_{b}^{(i)}\cdot\theta \right )\cdot \left ( -x_{2}^{(i)} \right )\\ ...\\ \sum_{1}^{m}2\left ( y^{(i)}-x_{b}^{(i)}\cdot\theta \right )\cdot \left ( -x_{n}^{(i)} \right ) \end{pmatrix}
ΔJ(θ)=⎝⎜⎜⎜⎜⎜⎛∂θ0∂J∂θ1∂J∂θ2∂J...∂θn∂J⎠⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛∑1m2(y(i)−xb(i)⋅θ)⋅(−1)∑1m2(y(i)−xb(i)⋅θ)⋅(−x1(i))∑1m2(y(i)−xb(i)⋅θ)⋅(−x2(i))...∑1m2(y(i)−xb(i)⋅θ)⋅(−xn(i))⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞
其中
x
b
x_{b}
xb 是x的增广矩阵
为了便于计算我们取 J ( θ ) = 1 2 m ∑ 1 m ( y − y ^ ( i ) ) 2 J\left ( \theta \right )=\frac{1}{2m}\sum_{1}^{m}\left (y-\widehat{y}^{(i)} \right )^{2} J(θ)=2m1∑1m(y−y (i))2
则 Δ J ( θ ) = 2 m ⋅ ( ∑ 1 m ( x b ( i ) ⋅ θ − y ( i ) ) ⋅ ( 1 ) ∑ 1 m ( x b ( i ) ⋅ θ − y ( i ) ) ⋅ ( x 1 ( i ) ) ∑ 1 m ( x b ( i ) ⋅ θ − y ( i ) ) ⋅ ( x 2 ( i ) ) . . . ∑ 1 m ( x b ( i ) ⋅ θ − y ( i ) ) ⋅ ( x n ( i ) ) ) \Delta J\left ( \theta \right )=\frac{2}{m}\cdot \begin{pmatrix} \sum_{1}^{m}\left ( x_{b}^{(i)}\cdot\theta-y^{(i)} \right )\cdot \left ( 1 \right )\\ \sum_{1}^{m}\left ( x_{b}^{(i)}\cdot\theta -y^{(i)} \right )\cdot \left ( x_{1}^{(i)} \right )\\ \sum_{1}^{m}\left ( x_{b}^{(i)}\cdot\theta -y^{(i)} \right )\cdot \left ( x_{2}^{(i)} \right )\\ ...\\ \sum_{1}^{m}\left ( x_{b}^{(i)}\cdot\theta - y^{(i)} \right )\cdot \left ( x_{n}^{(i)} \right ) \end{pmatrix} ΔJ(θ)=m2⋅⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛∑1m(xb(i)⋅θ−y(i))⋅(1)∑1m(xb(i)⋅θ−y(i))⋅(x1(i))∑1m(xb(i)⋅θ−y(i))⋅(x2(i))...∑1m(xb(i)⋅θ−y(i))⋅(xn(i))⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞
可表示为
Δ
J
(
θ
)
=
2
m
(
x
b
(
1
)
−
y
(
1
)
,
x
b
(
2
)
−
y
(
2
)
,
x
b
(
3
)
−
y
(
3
)
,
.
.
.
,
x
b
(
n
)
−
y
(
n
)
)
⋅
(
x
0
(
1
)
,
x
1
(
1
)
,
x
2
(
1
)
,
.
.
.
,
x
n
(
1
)
x
0
(
2
)
,
x
1
(
2
)
,
x
2
(
2
)
,
.
.
.
,
x
n
(
2
)
x
0
(
3
)
,
x
1
(
3
)
,
x
2
(
3
)
,
.
.
.
,
x
n
(
3
)
.
.
.
x
0
(
m
)
,
x
1
(
m
)
,
x
2
(
m
)
,
.
.
.
,
x
n
(
m
)
)
\Delta J\left ( \theta \right )=\frac{2}{m}\left ( x_{b}^{(1)}-y^{(1)},x_{b}^{(2)}-y^{(2)},x_{b}^{(3)}-y^{(3)},...,x_{b}^{(n)}-y^{(n)} \right )\cdot \begin{pmatrix} x_{0}^{(1)},x_{1}^{(1)},x_{2}^{(1)},...,x_{n}^{(1)}\\ x_{0}^{(2)},x_{1}^{(2)},x_{2}^{(2)},...,x_{n}^{(2)}\\ x_{0}^{(3)},x_{1}^{(3)},x_{2}^{(3)},...,x_{n}^{(3)}\\ ...\\ x_{0}^{(m)},x_{1}^{(m)},x_{2}^{(m)},...,x_{n}^{(m)} \end{pmatrix}
ΔJ(θ)=m2(xb(1)−y(1),xb(2)−y(2),xb(3)−y(3),...,xb(n)−y(n))⋅⎝⎜⎜⎜⎜⎜⎛x0(1),x1(1),x2(1),...,xn(1)x0(2),x1(2),x2(2),...,xn(2)x0(3),x1(3),x2(3),...,xn(3)...x0(m),x1(m),x2(m),...,xn(m)⎠⎟⎟⎟⎟⎟⎞
=
2
m
⋅
(
x
b
θ
−
y
)
T
⋅
x
b
=\frac{2}{m}\cdot \left ( x_{b}\theta -y \right )^{T}\cdot x_{b}
=m2⋅(xbθ−y)T⋅xb
则迭代求梯度为 θ : = θ − α Δ J \theta := \theta - \alpha \Delta J θ:=θ−αΔJ 其中 α \alpha α为每次迭代的步长
梯度下降法的优点是相对于常规计算来说耗时少,但是要计算每一个元素,样本大则很耗时。针对这种情况我们可以使用随机梯度下降法,批量梯度下降法等。
线性回归衡量方式
1.均方误差MSE
1
m
∑
1
m
(
y
t
e
s
t
(
i
)
−
y
^
t
e
s
t
(
i
)
)
2
\frac{1}{m}\sum_{1}^{m}\left (y_{test}^{(i)}-\widehat{y}_{test}^{(i)} \right )^{2}
m1∑1m(ytest(i)−y
test(i))2
2.均方根误差RMSE
1
m
∑
1
m
(
y
t
e
s
t
(
i
)
−
y
^
t
e
s
t
(
i
)
)
2
\sqrt{\frac{1}{m}\sum_{1}^{m}\left (y_{test}^{(i)}-\widehat{y}_{test}^{(i)} \right )^{2}}
m1∑1m(ytest(i)−y
test(i))2
3.平均绝对误差MAE
1
m
∑
1
m
∣
y
t
e
s
t
(
i
)
−
y
^
t
e
s
t
(
i
)
∣
\frac{1}{m}\sum_{1}^{m}\left | y_{test}^{(i)}-\widehat{y}_{test}^{(i)}\right |
m1∑1m∣∣∣ytest(i)−y
test(i)∣∣∣
4.R_squared(使用最广效果最好)
R
2
=
1
−
∑
1
m
(
y
t
e
s
t
(
i
)
−
y
^
t
e
s
t
(
i
)
)
2
∑
1
m
(
y
t
e
s
t
(
i
)
−
y
‾
t
e
s
t
)
2
R^{2}=1-\frac{\sum_{1}^{m}\left (y_{test}^{(i)}-\widehat{y}_{test}^{(i)} \right )^{2}}{\sum_{1}^{m}\left (y_{test}^{(i)}-\overline{y}_{test} \right )^{2}}
R2=1−∑1m(ytest(i)−ytest)2∑1m(ytest(i)−y
test(i))2
*
R
2
R^{2}
R2<=1
*
R
2
R^{2}
R2越大越好,当我们的预测模型不出错时,
R
2
R^{2}
R2为最大值1
*
R
2
R^{2}
R2<0说明我们的学习模型还不如基准模型。此时,很有可能我们的数据不
存在任何的线性关系
数据归一化
数据的标准化(normalization)是将数据按比例缩放,使之落入一个小的特定区间。在某些比较和评价的指标处理中经常会用到,去除数据的单位限制,将其转化为无量纲的纯数值,便于不同单位或量级的指标能够进行比较和加权。其中最典型的就是数据的归一化处理,即将数据统一映射到[0,1]区间上。
一下将介绍两种简单的方法
1.最值归一化
把所有的数据映射到0-1之间,适用于分布有明显的边界的情况;受边界影响较大的。
x
s
c
a
l
e
=
x
−
x
m
i
n
x
m
a
x
−
x
m
i
n
x_{scale} = \frac{x-x_{min}}{x_{max}-x_{min}}
xscale=xmax−xminx−xmin
2.均值方差归一化
把所有的数据归一到均值为0方差为1的分布中。适用于数据没有明显的边界的;可能存在极端数据值的。
x
s
c
a
l
e
=
x
−
x
m
e
a
n
S
x_{scale} = \frac{x-x_{mean}}{S}
xscale=Sx−xmean
scikit-learn 中的参数详解
sklearn中的sklearn.linear_model.LinearRegression是调用线性回归的实现。
参数
-
fit_intercept: boolean,可选,默认为true。
计算此模型的截距。 如果设置为False,则不会在计算中使用截距。 -
normalize : boolean,可选,默认为False
当fit_intercept设置为False时,将忽略此参数。 如果为真,则X将在回归之前通过减去平均值并除以l2范数来归一化。 如果您希望标准化,请在使用normalize = False的估算器调用fit之前使用sklearn.preprocessing.StandardScaler。 -
copy_X : boolean, 可选, 默认 True
如果为True,则将复制X; 否则,它可能会被覆盖。 -
n_jobs : 调用处理器, -1表示全部
内置属性(Attributes)
-
coef_ : array, shape (n_features, ) or (n_targets, n_features)
线性回归问题的估计系数。 如果在拟合期间传递多个目标(y 2D),则这是形状的二维数组(n_targets,n_features),而如果仅传递一个目标,则这是长度为n_features的一维数组。 -
intercept_:array
截距。
内置方法(Methods)
- fit(X, y[, sample_weight])--------拟合
- get_params(deep=True)--------获取此分类器的参数
- predict(X)--------预测
- score(X, y, sample_weight=None)--------返回预测的确定系数R ^ 2。
系数R ^ 2定义为(1-u / v),其中u是残差平方和((y_true-y_pred)^ 2).sum()和v是平方和的总和((y_true - y_true.mean())^2).sum()。 最好的分数是1.0,它可能是负的(因为模型可以任意更差)。 总是预测y的期望值的常数模型,忽略输入特征,将得到R ^ 2得分为0.0。 - **set_params(params) --------设置此估算器的参数。
该方法适用于简单估计器以及嵌套对象(例如管道)。 后者具有 __ 形式的参数,因此可以更新嵌套对象的每个组件。
示例(linearRegression 在波士顿房价中的运用)
线性回归的代码实现
import numpy as np
from machine_learning.metrics import r2_score
class LinearRegression:
def __init__(self):
"""初始化LinearRegression 模块"""
self.coef_ = None
self.interception_ = None
self._theta = None
def fit_normal(self, x_train, y_train):
"""根据训练数据集X_train, y_train 训练LinearRegression模型"""
## 利用直接运算的方式拟合求解系数和截距的值
assert x_train.shape[0] == y_train.shape[0]
x_b = np.hstack([np.ones((len(x_train), 1)), x_train])
self._theta = (np.linalg.inv(x_b.T.dot(x_b))).dot(x_b.T).dot(y_train)
self.interception_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
def fit_gradient(self,x_train, y_train, eta=0.01, n_iters=1e4):
"""梯度下降法"""
assert x_train.shape[0] == y_train.shape[0]
def J(theta, x_b, y):
try:
return ((y - x_b.dot(theta)) ** 2) / len(x_b)
# np.dot(A, B):对于二维矩阵,计算真正意义上的矩阵乘积,同线性代数中矩阵乘法的定义。对于一维矩阵,计算两者的内积
except:
return float('inf')
def dJ(theta, x_b, y): # dot函数矩阵乘
"""res = np.empty(len(theta))
# empty一样,它所常见的数组内所有元素均为空
res[0] = np.sum(x_b.dot(theta) - y)
for i in range(1, len(theta)):
res[i] = (x_b.dot(theta) - y).dot(x_b[:, 1])
return res * 2 / len(x_b)"""
return x_b.T.dot(x_b.dot(theta) - y)*2./len(x_b)
def gradient_descent(x_b, y, initial_theta, eta, n_iters=1e4):
theta = initial_theta
i_iter = 0
esplion = 1e-8
while i_iter < n_iters:
gradient = dJ(theta, x_b, y)
last_theta = theta
theta = theta - eta * gradient ###迭代 让theta每次都能向导数的负方向移一步
if (abs((J(last_theta, x_b, y) - J(theta, x_b, y)).any()) < esplion):
break
i_iter += 1
return theta
x_b = np.hstack([np.ones((len(x_train), 1)), x_train])
initial_theta = np.zeros(x_b.shape[1])
self._theta = gradient_descent(x_b, y_train, initial_theta, eta, n_iters=n_iters )
self.interception_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
def fit_sgd(self, x_train, y_train, n_iters=5, t0=5, t1=50):
"""利用随机梯度下降法"""
assert x_train.shape[0] == y_train.shape[0]
assert n_iters >= 1
def dJ_sgd(theta, x_b_i, y_i): # dot函数矩阵乘
return x_b_i.T.dot(x_b_i.dot(theta) - y_i) * 2.
def sgd(x_b, y, initial_theta, n_iters=n_iters,t0=t0,t1=t1):
def learning_rate(t):
return t0 / (t + t1)
theta = initial_theta
m = len(x_b)
for cur_iter in range(n_iters):
indexs = np.random.permutation(m)
x_b_new = x_b[indexs]
y_new = y[indexs]
for i in range(m):
gradient = dJ_sgd(theta, x_b_new[i], y_new[i])
theta = theta - learning_rate(cur_iter*m+i) * gradient
return theta
x_b = np.hstack([np.ones((len(x_train), 1)), x_train])
initial_theta = np.zeros(x_b.shape[1])
self._theta = sgd(x_b, y_train, initial_theta, n_iters, t0, t1)
self.interception_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
def predict(self, x_predict):
"""给定待预测数据集x_predict, 返回表示x_predict的结果向量"""
x_b = np.hstack([np.ones((len(x_predict), 1)), x_predict])
return x_b.dot(self._theta)
def score(self,x_test,y_test):
"""根据测试数据集x_test 和 y_test 确定当前模型的准确度"""
y_predict = self.predict(x_test)
return r2_score(y_test, y_predict)
def __repr__(self):
return "LinearRegression()"