1、机器学习的一些概念
- 有监督、无监督:
有监督机器学习又被称为“有老师的学习”,所谓的老师是指标签。监督学习就是最常见的分类(注意和聚类区分)问题,通过已有的训练样本(即已知数据及其对应的输出)去训练得到一个最优模型(这个模型属于某个函数的集合,最优表示某个评价准则下是最佳的),再利用这个模型将所有的输入映射为相应的输出,对输出进行简单的判断从而实现分类的目的。也就具有了对未知数据分类的能力。
无监督机器学习被称为“没有老师的学习”,无监督相比于有监督,输入数据没有被标记,也没有确定的结果。样本数据类别未知,需要根据样本间的相似性对样本集进行分类(聚类,clustering)试图使类内差距最小化,类间差距最大化。通俗点将就是实际应用中,不少情况下无法预先知道样本的标签,也就是说没有训练样本对应的类别,因而只能从原先没有样本标签的样本集开始学习分类器设计。 - 泛化能力:
泛化能力(generalization ability)是指一个机器学习算法对于没有见过的样本的识别能力。我们也叫做举一反三的能力,或者叫做学以致用的能力。举个例子,小学生先通过学习十以内的加减乘除,知道什么是四则运算和怎么具体去算数,以后遇到百以内或者千以内的数字也知道怎么去做四则运算。我们只教会他十以内的运算,他自己就能推广到百以内或者千以内的运算,这种能力就是泛化能力。
- 过拟合与欠拟合(方差和偏差以及各自的解决办法):
过拟合:小学生学习四则运算,老师教过1+1=2,那么学生只记住了1+1=2,以后做题的时候碰到1+1知道答案是2,但是碰到10+10就不知道怎么计算答案,学生只是死记硬背1+1的答案是2,没理解四则运算的规律,不会推广到10+10,也就是泛化能力非常低,同时我们也把这种现象叫做过拟合(over-fitting)了。
过拟合是一种分类器会发生的现象,而泛化能力可以理解为对分类器的一种性能的评价,过拟合表现为算法模型的高方差,模型训练时的结果很好,但是在预测时结果不好。
产生过拟合的原因:模型的复杂度太高,比如:网络太深;过多的变量(特征);训练数据非常少。
避免过拟合的方法有很多:(1)尽量减少特征的数量、(2)early stopping、(3)数据集扩增、(4)dropout、(5)正则化包括L1、L2、(6)清洗数据。
欠拟合under-fitting)是和过拟合相对的现象,可以说是模型的复杂度较低,没法很好的学习到数据背后的规律。就好像开普勒在总结天体运行规律之前,他的老师第谷记录了很多的运行数据,但是都没法用数据去解释天体运行的规律并预测,这就是在天体运行数据上,人们一直处于欠拟合的状态,只知道记录过的过去是这样运行的,但是不知道道理是什么。
欠拟合指的是模型不够复杂,没有很好地捕捉到数据特征,不能够很好地拟合数据,对应模型的高偏差。
解决欠拟合可以从寻找更好的特征(具有代表性的)和使用更多的特征(增大输入向量的维度)。具体的方法:1、添加更多的特征项(比如上下文特征、位置特征等);2、添加多项式特征(例如将线性模型通过添加二次项或者三次项使模型泛化能力更强);3、减少正则化参数,正则化的目的是用来防止过拟合的,但是现在模型出现了欠拟合,则需要减少正则化参数。 - 交叉验证:
一个交叉验证将样本数据集分成两个互补的子集,一个子集用于训练(分类器或模型)称为训练集(training set);另一个子集用于验证(分类器或模型的)分析的有效性称为测试集(testing set)。利用测试集来测试训练得到的分类器或模型,以此作为分类器或模型的性能指标。得到高度预测精确度和低的预测误差,是研究的期望。为了减少交叉验证结果的可变性,对一个样本数据集进行多次不同的划分,得到不同的互补子集,进行多次交叉验证。取多次验证的平均值作为验证结果。
用交叉验证的目的是为了得到可靠稳定的模型。
2、线性回归的原理
线性回归为何叫线性?实际上,像在处理Google的股票统计数据时,我们使用线性回归是在这堆数据所在的N维空间中找到一条线来描述这些数据的规律,因此才叫线性回归。这个过程称为拟合,这条线成为拟合线。
这条拟合线上的某个数据点或多或少都会偏离实际统计的值。实际统计数据和拟合线对应数据的差叫残差。很明显,残差可以反映模型的预测误差。
但是残差有正有负的,不方便计算。而且实际运用中我们不需要关注残差的正负,因为正负并不能描述误差的大小程度。为了降低计算复杂性,我们使用这个差值的平方进行计算。你可能会想到,差值的平方不是把差值给改了吗,没关系吗?答案是:数据确实变了,但没影响。因为我们真正使用的是残差的绝对值,用它描述误差大小的程度,而对这个绝对值进行平方后有同样的效果,毕竟
y
=
∣
x
∣
{y = |x|}
y=∣x∣ 与
y
=
x
2
{y = x^2}
y=x2有同样的单调性。
结合上述平方的想法,为了让预测更加准确,我们应该选择一条线,能够使得线上每个点与实际数据的残差平方的总和最小。这样的线才能叫最佳拟合线。直观理解,线性回归其实就是这么一条直线。
3、线性回归的目标函数、损失函数(代价函数)
线性回归试图学得
f
(
x
i
)
=
w
∗
x
i
+
b
{f(x_i) = w*x_i + b}
f(xi)=w∗xi+b(目标函数)使得
f
(
x
i
)
≃
y
i
{f(x_i)\simeq y_i}
f(xi)≃yi,如何确定
w
{w}
w和
b
{b}
b呢?关键在于如何衡量
f
(
x
)
{f(x)}
f(x)与
y
{y}
y之间的差别。
均方误差是回归任务中常用的性能度量,因此我们试图让均方误差(损失函数,或代价函数)最小化,即
(
w
∗
,
b
∗
)
=
a
r
g
m
i
n
(
w
,
b
)
∑
i
=
1
m
(
f
(
x
i
)
−
y
i
)
2
=
a
r
g
m
i
n
(
w
,
b
)
∑
i
=
1
m
(
y
i
−
w
x
i
−
b
)
2
{(w^*,b^*)=argmin_{(w,b)} \sum_{i=1}^{m}(f(x_i)-y_i)^2=argmin_{(w,b)} \sum_{i=1}^{m}(y_i-wx_i-b)^2}
(w∗,b∗)=argmin(w,b)∑i=1m(f(xi)−yi)2=argmin(w,b)∑i=1m(yi−wxi−b)2
均方误差有非常好的几何意义,它对应了常用的欧几里得距离(欧氏距离),基于均方误差最小化来进行模型求解的方法称为“最小二乘法”。
在线性回归中,最小二乘法就是试图找到一条直线,使得所有样本到直线上的欧氏距离之和最小。
求解
w
{w}
w和
b
{b}
b使
∑
(
w
,
b
)
=
∑
i
=
1
m
(
y
i
−
w
x
i
−
b
)
2
{\sum_{(w,b)}=\sum_{i=1}^{m}(y_i-wx_i-b)^2}
∑(w,b)=∑i=1m(yi−wxi−b)2最小化的过程,称为线性回归模型的最小二乘“参数估计”。这里暂不推广到其它模型(多元线性回归和逻辑回归)。
注意: 我们为了求导计算方便,往往将损失函数写成下面的形式:
J ( w ) = J ( w 0 , w 1 ) = 1 2 m ∑ i = 1 m ( h ( x i ) − y i ) 2 {J(w)=J(w_0,w_1)=\frac {1}{2m} \sum_{i=1}^{m}(h(x^i)-y^i)^2} J(w)=J(w0,w1)=2m1∑i=1m(h(xi)−yi)2,
其中, h ( x i ) − y i {h(x^i)-y^i} h(xi)−yi是预测值和实际值的差,所以损失(成本代价)就是预测值和实际值的差的平方的平均值,之所以乘以 1 2 {\frac {1}{2}} 21是为了计算方便,这个函数也被称为均方差方程。有了损失函数,就可以精确地测量模型对训练样本拟合的好坏程度。
4、优化方法(梯度下降法、牛顿法等)
有了目标函数(预测函数),也可以精确地测量预测函数对训练样本的拟合情况,我们要怎样求解模型的参数的值呢?这时,梯度下降算法就派上用场了。
梯度下降法
我们希望能找到
w
{w}
w使得
J
(
w
)
{J(w)}
J(w)达到最小,于是我们可以使一个搜索算法,初始化
w
{w}
w为一个任意值,在迭代过程中不断地更新
w
{w}
w使得
J
(
w
)
{J(w)}
J(w)更小,直到收敛为止(可以认为
J
(
w
)
{J(w)}
J(w)不再改变)。下面我们来考虑梯度下降算法,它先给
w
{w}
w一个初始化值,然后通过下面公式来更新
w
{w}
w。
w
j
:
=
w
j
−
η
∂
J
(
w
)
∂
w
j
{w_j:= w_j-\eta \ \frac{\partial J(w)}{\partial w_j}}
wj:=wj−η ∂wj∂J(w),其中
j
=
0
,
1
,
2
,
.
.
.
,
n
{j=0,1,2,...,n}
j=0,1,2,...,n
上式中,
η
{\eta}
η是学习率,为了理解上面的算法,我们需要推导一下偏微分部分,推导过程中我们只考虑一个样例
(
x
,
y
)
{(x,y)}
(x,y),然后只需要把所有的样例加起来就可以了。
∂
J
(
w
)
∂
w
j
=
1
2
∂
(
h
w
(
x
)
−
y
)
2
∂
w
j
=
(
h
w
(
x
)
−
y
)
∂
(
∑
i
=
0
n
w
i
x
i
−
y
)
∂
w
j
=
(
h
w
(
x
)
−
y
)
x
j
{\frac{\partial J(w)}{\partial w_j}=\frac{1}{2} \frac{\partial (h_w(x)-y)^2}{\partial w_j} = (h_w(x)-y)\frac{\partial (\sum_{i=0}^{n}w_ix_i-y)}{\partial w_j}=(h_w(x)-y)x_j}
∂wj∂J(w)=21∂wj∂(hw(x)−y)2=(hw(x)−y)∂wj∂(∑i=0nwixi−y)=(hw(x)−y)xj
对于单独的第i个样本,更新规则为:
w
j
:
=
w
j
−
η
(
h
w
(
x
i
)
−
y
i
)
x
j
i
{w_j:= w_j-\eta (h_w(x^{i})-y^i)x_{j}^{i}}
wj:=wj−η(hw(xi)−yi)xji,其中
j
=
0
,
1
,
2
,
.
.
.
.
,
n
{j=0,1,2,....,n}
j=0,1,2,....,n
当有m个样本时,更新规则为:
w
j
:
=
w
j
−
η
∑
i
=
1
m
(
h
w
(
x
i
)
−
y
i
)
x
j
i
{w_j:= w_j-\eta \sum_{i=1}^{m}(h_w(x^{i})-y^i)x_{j}^{i}}
wj:=wj−η∑i=1m(hw(xi)−yi)xji,其中
j
=
0
,
1
,
2
,
.
.
.
,
n
{j=0,1,2,...,n}
j=0,1,2,...,n
上式每次迭代将所有样本考虑进来更新
w
{w}
w,这种方法叫做批量梯度下降。梯度下降容易陷入一个局部的最优解,事实上
J
(
w
)
{J(w)}
J(w)是一个凸函数,所以没有所谓的局部最优解,它只有一个全局最优解,凸函数的这种性质非常好用。
之后又出现了随机梯度下降(或增量梯度下降)SGD,该算法每一个样例都更新了
w
{w}
w一次,当m很大的时候,批量梯度下会很耗时,通常,随机梯度下降比批量梯度下降要快很多,然而它可能永远达不到最小值,并在最小值附近震荡,而实际上这种近似最小值已经够了。在样本量比较大的情况下,随机梯度下降比梯度下降更实用。
牛顿法
牛顿法的思想就是通过迭代来找到函数的零点。牛顿法是二阶收敛,梯度下降是一阶收敛,牛顿法通常比梯度下降算法收敛速度要快,只需要更少的迭代次数就能获得最小值。然而一次牛顿迭代要比一次梯度下降更昂贵,因为它需要计算 H e s s a n {Hessan} Hessan矩阵并且求它的逆,这将花费不少时间。但是当参数个数 n {n} n不是太大时,总体来说速度还是要快很多。
5、线性回归的评估指标
在预测任务中,给定样例集
D
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
m
,
y
m
)
}
{D=\{(x_1,y_1),(x_2,y_2),...,(x_m,y_m)\}}
D={(x1,y1),(x2,y2),...,(xm,ym)},其中
y
i
{y_i}
yi是示例
x
i
{x_i}
xi的真实标记。要评估学习器
f
{f}
f的性能,就要把学习器预测结果
f
{f}
f与真实标记
y
{y}
y进行比较。
回归任务最常用的性能度量(评估指标)是“均方误差”(mean squared error,MSE):
E
(
f
;
D
)
=
1
m
∑
i
=
1
m
(
f
(
x
i
)
−
y
i
)
2
{E(f;D)=\frac{1}{m} \sum_{i=1}^{m}(f(x_i)-y_i)^2}
E(f;D)=m1∑i=1m(f(xi)−yi)2。
拓展一些分类任务中常用的性能度量,以后再来作详细补充。
错误率与精度;查全率、查准率与 F 1 {F_1} F1值; R O C {ROC} ROC与 A U C {AUC} AUC;代价敏感错误率与代价曲线等。
6、sklearn参数详解(示例)
在scikit-learn里,LinearRegression类实现了线性回归算法。我们这一节使用scikit-learn自带地波士顿房价数据集来训练模型,然后用模型来测算房价。
在sklearn的波士顿房价数据集里,总共收集了13个特征,具体如下:
- CRIM:城镇人均犯罪率
- ZN:城镇超过25,000平方英尺的住宅区域的占地比例
- INDUS:城镇非零售用地占地比例
- CHAS:是否靠近河边,1为靠近,0为远离
- NOX:一氧化氮浓度
- RM:每套房产的平均房间个数
- AGE:在1940年之前就盖好,且业主自住的房子的比例
- DIS:与波士顿市中心的距离
- RAD:周边高速公路的便利性指数
- TAX:每10,000美元的财产税率
- PTRATIO:小学老师的比例
- B:城镇黑人的比例
- LSTAT:地位较低的人口比例
这些指标中可以看出中美文化的一些差异。当然,这个数据是在1993年之前收集的,可能和现在会有差异。实际上一个模型的好坏和输入特征的选择是关系密切的。开一下脑洞,如果在中国预测房价,应该收集哪些特征数据?收集成本有多高?特征数据的可获得性怎么样?
废话不多说,开始撸代码。 - 我们导入数据
from sklearn.datasets import load_boston
boston = load_boston() #加载数据集
X, y = boston.data, boston.target # 获得数据集X和标签(真实值)y
print(X.shape) # 看一下数据集的形状,其输出为(506,13),表明这个数据集有506个样本,每个样本有13个特征。
print(y.shape)
"""
整个训练样本放在一个506 * 13的矩阵里。可以通过X[0]来看一个样本数据:
"""
print(X[0])
"""输出:
[6.320e-03 1.800e+01 2.310e+00 0.000e+00 5.380e-01 6.575e+00 6.520e+01
4.090e+00 1.000e+00 2.960e+02 1.530e+01 3.969e+02 4.980e+00]
"""
boston.feature_names # 查看这些特征的标签
"""
array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
'TAX', 'PTRATIO', 'B', 'LSTAT'], dtype='<U7')
"""
- 模型训练
# 在对模型进行训练之前,我们需要先把数据集分成两份,以便评估算法的准确性。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=3)
"""
由于数据集较小,我们只选取了20%(参数test_size)的样本作为测试集。
接着,训练模型并测试模型的准确性评分。
"""
import time
from sklearn.linear_model import LinearRegression
model = LinearRegression()
start = time.clock()
model.fit(X_train, y_train)
train_score = model.score(X_train, y_train)
cv_score = model.score(X_test, y_test)
print("elaspe: {0:.6f}; train_score: {1:0.6f}; cv_score: {2:.6f}".format(time.clock()-start, train_score, cv_score))
"""输出:
elaspe: 0.063014; train_score: 0.723941; cv_score: 0.794958
我们顺便统计了模型的训练时间,除此之外,统计模型针对训练样本的准确性得分(即对训练样本拟合的好坏程度)train_score,
还统计了模型针对测试样本的得分cv_score
从得分情况来看,模型的拟合效果一般,还有没有办法来优化模型的拟合效果呢?
"""
- 模型优化
"""
首先观察一下数据,特征数据的范围相差比较大,最小的在10的13次方级别,而最大的在10的2次方级别,看来我们需要先把数据进行归一化处理。
归一化处理最简单的方式是,创建线性回归模型的时候增加normalize=True参数。
model = LinearRegression(normalize=True)
当然,数据归一化处理只会加快算法收敛速度,优化算法训练的效率,无法提升算法的准确性。
怎么样优化模型准确性呢?我们回到训练分数上来,可以观察到数据针对训练样本的评分较低(train_score: 0.723941),
即模型对训练数据的拟合成本(损失,或者误差)比较高,这是典型的欠拟合现象。大家可以往上翻一下如何处理欠拟合的办法:
一是挖掘更多的输入特征,二是增加多项式特征。这里我们使用低成本的方案,即增加多项式特征来看看能否优化模型的性能。
增加多项式特征,其实就是增加模型的复杂度。
下面我们写一个创建多项式模型的函数
"""
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
def polynomial_model(degree=1):
polynomial_features = PolynomialFeatures(degree = degree,
include_bias = False)
linear_regression = LinearRegression(normalize = True)
pipeline = Pipeline([("polynomial_features", polynomial_features), ("linear_regression", linear_regression)])
return pipeline
"""
接着,我们使用二阶多项式来拟合数据。
"""
model = polynomial_model(degree=2) # 二阶多项式
start = time.clock()
model.fit(X_train, y_train)
train_score = model.score(X_train, y_train)
cv_score = model.score(X_test, y_test)
print("elaspe: {0:.6f}; train_score: {1:0.6f}; cv_score: {2:.6f}".format(time.clock()-start, train_score, cv_score))
"""输出
elaspe: 0.049655; train_score: 0.930547; cv_score: 0.860465
可以看到,训练样本分数和测试分数都提高了,看来模型确实得到了优化。我们还可以把多项式改成三阶看一下结果。
其实改为三阶后,针对训练样本的分数达到了1,而针对测试样本的分数却为负数,说明这个模型过拟合了。
"""
==============================================================