学习《机器学习实战》四

送分小仙女□ 提交于 2020-01-27 15:59:51

训练模型

训练模型就是搜寻使成本函数(在训练集上)最小化的参数组合。
有助于快速定位到合适的模型、正确的训练算法,以及一套适当的超参数。
在这里插入图片描述

一、线性回归(LinearRegression)

线性模型就是对输入特征加权求和,再加上一个偏置项的常数,以此进行预测。
线性回归模型预测:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
衡量一个回归模型性能指标:均方根误差(RMSE),但求均方误差(MSE)更方便
在这里插入图片描述
我们生成一些线性数据来测试这个公式

import numpy as np

X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)

X表示100个数据的1个特征属性
以点的形式来表示100个数据:
生成的线性函数是y=4+3x

from matplotlib import pyplot as plt

plt.xlabel("X") 
plt.ylabel("y")
plt.scatter(X, y, marker = 'o', color = 'green', s = 40)
plt.show()

在这里插入图片描述
现在,我们使用标准方程来计算θ。使用Numpy的线性代数模块(np.linalg)中的inv()函数来对矩阵求逆,并用dot()方法计算矩阵内积:

X_b = np.c_[np.ones((100, 1)), X]
theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
theta_best

得到
array([[3.86709543],
[3.16372488]])
现在可以用θ做预测了

X_new = np.array([[0],[2]])
X_new_b = np.c_[np.ones((2,1)), X_new]
y_predict = X_new_b.dot(theta_best)
y_predict

这是预测X=0和X=2的值
得到
array([[ 3.86709543],
[10.19454519]])
在这里插入图片描述
绘制模型的预测结果

plt.plot(X_new, y_predict, "r-")
plt.plot(X, y, "b.")
plt.axis([0, 2, 0, 15])
plt.show()

在这里插入图片描述
Scikit-Learn的等效代码

from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X, y)
lin_reg.intercept_, lin_reg.coef_

注意:Scikit-Learn将偏置项(intercept_)和特征权重(coef_)分离开了。
得到
(array([3.86709543]), array([[3.16372488]]))
结果与上面得到的结果一致。

二、梯度下降

适合于特征数或者训练实例数量大到内存无法满足要求的场景
梯度下降的中心思想就是迭代地调整参数从而使成本函数最小化
梯度下降的做法是:通过测量参数向量θ相关的误差函数的局部梯度,来不断沿着降低梯度的方向调整,直到梯度下降为0,到达最小值!
梯度下降存在的问题:
在这里插入图片描述
但本例使用的成本函数(MSE)是凸函数,不会存在局部最小值,只有一个全局最小值。它同时也是一个连续函数,所以斜率不会发生陡峭的变化。这两件事保证的结论是:即便是乱走,梯度下降都可以趋近到全局最小值(只要等待时间够长,学习率也不是太高)。
tips:应用梯度下降时,需保证所以特征值的大小比例都差不多(使用StandardScaler类)标准化数据、否则收敛时间会长很多。
1、批量梯度下降(基于整个训练集)
在这里插入图片描述
我们来看看这个算法的快速实现:

eta = 0.1
n_iterations = 1000
m = 100

theta = np.random.randn(2, 1)

for iteration in range(n_iterations):
    gradients = 2/m * X_b.T.dot(X_b.dot(theta) - y)
    theta = theta - eta * gradients
theta

结果:
array([[3.86709543],
[3.16372488]])
那么应该如何确定合适的学习率呢?
通过网格搜索(GridSearchCV)来找到合适的学习率。
2、随机梯度下降(基于单个实例)
算法停下来的参数值肯定是足够好的,但不是最优的。针对前面提及的成本函数不规则时,随机梯度下降帮助算法跳出局部最小值,更有利于找到全局最小值。
随机性可以逃离局部最优,却永远定位不出最小值→逐步降低学习率→确定学习计划

下面这段代码使用了一个简单的学习计划实现的随机梯度下降:

n_epochs = 50
t0, t1 = 5, 50

def learning_schedule(t):
    return t0 / (t + t1)

theta = np.random.randn(2, 1)

for epoch in range(n_epochs):
    for i in range(m):
        random_index = np.random.randint(m)
        xi = X_b[random_index: random_index + 1]
        yi = y[random_index: random_index + 1]
        gradients = 2 * xi.T.dot(xi.dot(theta) - yi)
        eta = learning_schedule(epoch * m + i)
        theta = theta - eta * gradients
theta

结果:
array([[3.87888407],
[3.1284594 ]])
Scikit-Learn等效代码:
SGDRegressor类默认优先的成本函数是平方误差,使用默认学习计划。

from sklearn.linear_model import SGDRegressor
sgd_reg = SGDRegressor( penalty = None, eta0 = 0.1)
sgd_reg.fit(X, y.ravel())

再次得到了一个跟标准方程的解非常相近的解决方案:

sgd_reg.intercept_, sgd_reg.coef_

结果:
(array([3.81047188]), array([3.18206684]))
3、小批量梯度下降(基于一小部分随机实例)
线性回归算法比较:
在这里插入图片描述

三、多项式回归

当有些数据呈现出非线性时,可以用线性模型来拟合非线性数据。一个简单的方法就是将每个特征的幂次方添加为一个新特征,然后在这个拓展过的特征集上训练线性模型。这就是多项式回归。
首先,我们生成一些非线性数据:

import numpy as np
m = 100
X = 6 * np.random.rand(m, 1) - 3
y = 0.5 * X**2 + X + 2 + np.random.randn(m, 1)

表示二次方程:y=0.5x^2+x+2
用散点图来显现有:

from matplotlib import pyplot as plt

plt.xlabel("X") 
plt.ylabel("y")
plt.scatter(X, y, marker = 'o', color = 'green', s = 40)
plt.show()

在这里插入图片描述
显然。直线不可能拟合这个数据。所以我们将每个特征的平方(二次多项式)作为新特征加入训练集

from sklearn.preprocessing import PolynomialFeatures
poly_features = PolynomialFeatures(degree = 2, include_bias = False)
X_poly = poly_features.fit_transform(X)
X[0]

得到
array([-2.06772161])

X_poly[0]

得到
array([-2.06772161, 4.27547266])
可见。X_poly包含原本的特征X和该特征的平方。
用线性回归来训练非线性数据:

from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X_poly, y)
lin_reg.intercept_, lin_reg.coef_

得到
(array([2.02797834]), array([[0.86536773, 0.49630806]]))
第一个数字是θ0,第二个是θ1,第三个是θ2
在现实生活中,不知道数据的函数是几次项的,那么如何确定模型的复杂度呢?怎么才能判断模型是过度拟合还是拟合不足呢?
第一:使用交叉验证法:如果模型在训练集上表现良好,但是交叉验证的泛化表现非常糟糕,那么模型就是过度拟合。如果在二者表现上都不佳,那就是拟合不足。
第二:观察学习曲线
绘制学习曲线代码:

from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

def plot_learning_curves(model, X, y):
    X_train, X_val, y_train, y_val = train_test_split(X, y, test_size = 0.2)
    train_errors, val_errors = [],[]
    for m in range(1, len(X_train)):
        model.fit(X_train[:m], y_train[:m])
        y_train_predict = model.predict(X_train[:m])
        y_val_predict = model.predict(X_val)
        train_errors.append(mean_squared_error(y_train_predict, y_train[:m]))
        val_errors.append(mean_squared_error(y_val_predict, y_val))
    plt.plot(np.sqrt(train_errors), "r-+", linewidth = 2, label = "train")
    plt.plot(np.sqrt(val_errors),"b-", linewidth = 3, label = "val")

纯线性回归模型(一条直线)的学习曲线

lin_reg = LinearRegression()
plot_learning_curves(lin_reg, X, y)

在这里插入图片描述
典型的模型拟合不足曲线。两条曲线均到达高地(说明平均误差都挺大),非常接近。而且相当高。
再看看同意的数据集上,一个10阶多项式模型的学习曲线

from sklearn.pipeline import Pipeline

polynomial_regression = Pipeline((
    ("poly_features", PolynomialFeatures(degree = 10, include_bias = False)),
    ("sgd_reg", LinearRegression()),
))
    
plot_learning_curves(polynomial_regression, X, y)
    

在这里插入图片描述
关于偏差/方差权衡
在这里插入图片描述

四、正则线性模型

正则线性模型是减少过度拟合的方法
在这里插入图片描述
1、岭回归(吉洪诺夫正则化)
在这里插入图片描述
超参数α控制的是对模型进行正则化的程度。如果α=0,J(θ)=MSE(θ)。岭回归就是纯线性回归。如果α非常大,那么所有的权重都将非常接近于零,结果是一条穿过数据平均值的水平线。
tips:再执行岭回归之前,必须对数据进行缩放(使用StandardScaler).大多数正则化模型都是对输入特征的大小非常敏感。
在这里插入图片描述
使用Scikit-Learn执行闭式解的岭回归。

from sklearn.linear_model import Ridge
ridge_reg = Ridge(alpha = 1, solver = "cholesky")
ridge_reg.fit(X, y)
ridge_reg.predict([[1.5]])

得到:
array([[4.92734372]])
使用随机梯度下降岭回归正则化:

from sklearn.linear_model import SGDRegressor
sgd_reg = SGDRegressor(penalty = "l2")
sgd_reg.fit(X, y.ravel())
sgd_reg.predict([[1.5]])

得到:
array([4.91440582])
超参数penalty设置的是使用正则项的lei’x 。设置为”l2“表示希望SGD在成本函数中添加一个正则项,等于权重向量的l2范数的平方的一半,即岭回归。
2、套索回归(最小绝对收缩和选择算子回归)
在这里插入图片描述
Lasso回归的一个重要特点是它倾向于完全消除掉最不重要特征的权重(将它们设置为零)
Lasso回归会自动执行,特征选择并输出一个稀疏模型(只有很少的特征有非零权重)
在这里插入图片描述
直接Lasso回归:

from sklearn.linear_model import Lasso
lasso_reg = Lasso(alpha = 0.1)
lasso_reg.fit(X, y)
lasso_reg.predict([[1.5]])

得到;
array([4.88483817])
使用随机梯度下降Lasso回归正则化:

sgd_reg = SGDRegressor(penalty = "l1")
sgd_reg.fit(X, y.ravel())
sgd_reg.predict([[1.5]])

3、弹性网络
在这里插入图片描述
当r=0时,弹性网络等于岭回归,而当r=1时,相当于Lasso回归。
如何选择正则化?
默认选择岭回归,当如果实际用到的特征少数,更倾向于Lasso回归或者弹性网络。但弹性网络优于Lasso回归。
下面是使用Scikit-Learn的ElasticNet的小例子(l1_ratio对应混合比例r):

from sklearn.linear_model import ElasticNet
elastic_net = ElasticNet(alpha = 0.1, l1_ratio = 0.5)
elastic_net.fit(X, y)
elastic_net.predict([[1.5]])

得到:
array([4.88730375])

五、分类任务模型

一些回归算法也可用于分类(反之亦然)
1、逻辑回归(Logistic回归、罗吉思回归)
在这里插入图片描述
现在知道逻辑回归模型是如何估算概率并做出预测了。但是要怎么训练呢?训练的目的就是设置参数向量θ,使模型对正类实例做出高概率估算(y=1),对负类实例做出低概率估算(y=0)
在这里插入图片描述在这里插入图片描述
这里用到的数据集是鸢尾植物。我们仅基于花瓣宽度这个特征。

from sklearn import datasets
iris = datasets.load_iris()
list(iris.keys())

[‘data’, ‘target’, ‘target_names’, ‘DESCR’, ‘feature_names’, ‘filename’]

X = iris["data"][:,3:]
y = (iris["target"] == 2 ).astype(np.int)

训练逻辑回归模型

from sklearn.linear_model import LogisticRegression

log_reg = LogisticRegression()
log_reg.fit(X, y)

我们看看对于花瓣宽度在0到3厘米之间的鸢尾花,模型估算出的概率:

X_new = np.linspace(0, 3, 1000).reshape(-1, 1)
y_proba = log_reg.predict_proba(X_new)
plt.plot(X_new, y_proba[:, 1], "g-", label = "Iris-Virginica")
plt.plot(X_new, y_proba[:, 0], "b--", label = "Not Iris-Virginica")

在这里插入图片描述
predict_proba()返回二的是一个n行k列的数组,第i行第j列上的数值是模型预测第i个预测样本为某个标签的概率。

log_reg.predict([[1.7], [1.5]])

得到
array([1, 0])
表示大约在1.6厘米是一个决策边界,如果花瓣宽度大于1.6厘米,分类器就预测它是Virginica鸢尾花,否则就预测不是。
2、Softmax回归(多元逻辑回归)
逻辑回归推广得到Softmax回归(直接支持多个类别分类器)
原理:给定实例X→计算每个类别k的分数Sk(x)→应用于Softmax函数(归一化指数)得到每个类别的概率。
在这里插入图片描述返回使σ(s(x))k最大化的k值(即返回的是类别k)
现在知道Softmax回归模型是如何估算概率并做出预测了。但是要怎么训练呢?
在这里插入图片描述
使用Softmax回归将鸢尾花分为三类。当用两个以上的类别训练时,Scikit-Learn的LogisticRegression默认选择使用的是一对多的训练方式,不过将超参数multi_class设置为“multinomial”,可以将其切换成Softmax回归。你还必须指定一个支持Softmax回归的求解器,比如“lbfgs”求解器。默认使用l2正则化,你可以通过超参数C进行控制。

X = iris["data"][:, (2, 3)]
y = iris["target"]

softmax_reg = LogisticRegression(multi_class = "multinomial", solver = "lbfgs", C = 10)
softmax_reg.fit(X, y)
softmax_reg.predict([[5, 2]])

得到
array([2])
表示花瓣长5厘米宽2厘米的鸢尾花被预测为第2类Virginica鸢尾花。

softmax_reg.predict_proba([[5, 2]])

得到
array([[6.38014896e-07, 5.74929995e-02, 9.42506362e-01]])
表示预测的概率。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!