机器学习理论基础以及代码实现
第3章 机器学习理论基础
本章涵盖主要内容如下:
(1)模型过拟合和欠拟合
(2)模型的成本及成本函数的含义
(3)评价一个模型好坏的标准
(4)学习曲线,以及用学习曲线来对模型进行诊断
(5)通用的模型优化方法
(6)其他模型评价标准
3.1 过拟合和欠拟合
过拟合:模型能够很好拟合训练样本,对新数据的预测准确性差
欠拟合:模型无法很好拟合训练样本,对新数据的预测准确性也不好。
#生成一个20个点的训练样本
import numpy as np
n_dots = 20
x = np.linspace(0,1,n_dots) #在[0,1]之间创建20个点
y = np.sqrt(x) + 0.2*np.random.rand(n_dots) - 0.1 #后面表示[-0.1,0.1]之间的随机数
训练样本为 y = √x + r
采用一阶、三阶和十阶多项式进行拟合,得到图形为
如上图所示,散点表示训练样本,虚线表示实际模型,实线表示采用训练样本拟合出的模型。
左边是欠拟合(高偏差)右边是过拟合(访察)中间为拟合较好的模型
3.2 成本函数
成本:衡量模型与训练样本符合程度的指标,是模型拟合出来值与训练样本真实值的误差平均值。
成本函数:成本与模型参数的函数关系,关键在于找出合适的模型参数降低成本函数的值。
针对一个数据集,我们可以选择很多个模型来拟合数据,一旦确定某个模型就要从这个模型的无穷多个参数中找到最优的参数,使得成本函数的值最小。
3.1 模型准确性
J(θ)(测试数据集的成本)是评估模型准确性的最直观指标,数值越小说明新数据的预测准确性越好。(用来测试模型的数据集必须是模型之前没有使用过的数据)
3.3.1 模型性能的不同表述方式
scikit-learn采用分数来表达模型性能,分数在[0,1]之间,数值越大准确性越高。
调用score(X_test,y_test)计算模型的分数值,X_test和y_test代表测试数据集样本。
模型分数(准确性)与成本成反比,即分数越大,准确性越高,误差越小,成本越低。
3.3.2 交叉验证数据集
之前提到过对数据集更加科学的分法应该是分为训练数据集、交叉验证数据集和测试数据集。(推荐比例为6:2:2)
上述多项式拟合数据的例子中,我们需要创建一类数据集来选择多项式的阶数,以便让测试数据集仅仅做测试模型准确性的工作,所以就有了交叉验证数据集。(原因衡量模型准确性时我们需要采用模型没有见过的测试数据)
3.4 学习曲线
学习曲线就是描述成本函数和训练数据集m的大小关系的曲线。
假设数据集的大小为m,画出学习曲线的步骤如下:
(1)把数据分为训练数据集和交叉验证数据集
(2)取训练数据集的20%作为训练样本,训练出模型参数
(3)使用交叉验证数据集来计算训练出来的模型的准确性
(4)以训练数据集的准确性,交叉验证的准确性作为纵坐标,训练数据集个数作为横坐标,在坐标轴上画出上述步骤计算出来的模型准确性。
(5)训练数据集增加10%,跳到步骤3继续执行,指导训练数据集大小为100%为止。
学习曲线需要表达出当训练数据集增加时,模型对训练数据集拟合的准确性以及交叉验证数据集预测的准确性的变化规律。
3.4.1 实例:画出学习曲线
使用本章开头的例子,生成一个在y = √x 附近波动的点来作为训练样本,多生成点观察模型准确性的变化。
import numpy as np
n_dots = 200
X = np.linspace (0 ,1, n_dots)
y = np.sqrt(X) + 0.2*np.random.rand(n_dots) - 0.1
#因为sklearn的接口里,需要用到n_sample x n_feature 的矩阵
#所以需要转化为200 × 1 的矩阵
X = X.reshape(-1,1) #-1的目的是让X数组变成一列。
y = y.reshape(-1,1)
(1)用Pipeline构造多项式模型,Pipeline内部包含多个数据处理模型。
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
def polynomial_model(degree =1):
polynomial_features = PolynomialFeatures(degree = degree,include_bias =False)
linear_regression = LinearRegression()
#这是一个流水线,先增加多项式阶数,然后再采用线性回归算法来拟合数据
pipeline = Pipeline([("polynomial_features",polynomial_features),("line_regression",linear_regression)])
return pipeline
这样我们就创建好了生成多项式模型的函数polynomial_model,degree可以控制多项式的阶数。
在scikit_learn中,我们只需要使用sklearn.model_selection.learning_curve()函数就能画出学习曲线,它能够自动把训练样本的数量按照预定的规则逐渐增加,画出不同训练样本数量时模型的准确性。
from sklearn.model_selection import learning_curve
from sklearn.model_selection import ShuffleSplit
import matplotlib.pyplot as plt
def plot_learning_curve(estimator,title,X,y,ylim = None,cv = None,n_jobs = 1,train_sizes = np.linspace(.1,1.0,5)):
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
plt.xlabel("Training examples")
plt.ylabel("Score")
train_sizes,train_scores,test_scores = learning_curve(estimator,X,y,cv = cv,n_jobs = n_jobs,train_sizes = train_sizes)
train_scores_mean = np.mean(train_scores,axis = 1)
train_scores_std = np.std(train_scores,axis = 1)
test_scores_mean = np.mean(test_scores,axis = 1)
test_scores_std = np.std(test_scores,axis = 1)
plt.grid()
plt.fill_between(train_sizes,train_scores_mean - train_scores_std,train_scores_mean + train_scores_std,alpha = 0.1,color = 'r')
plt.fill_between(train_sizes,test_scores_mean - test_scores_std,test_scores_mean + test_scores_std,alpha = 0.1,color = 'g')
plt.plot(train_sizes,train_scores_mean,'o-',color = 'r',label = 'Training score')
plt.plot(train_sizes,test_scores_mean,'o-',color = 'g',label = 'Cross-validation score')
plt.legend(loc = 'best')
return plt
此函数实现的功能是绘制出模型的学习曲线。
plt.fill_between()函数把模型准确性的平均值的上下方差的空间里用颜色填充。plt.plot()函数画出模型准确性的平均值。
注意:当计算模型准确性时,是随即从数据集中分配出训练样本和交叉验证样本,这样会导致数据分配不均,进而导致每次计算出来的准确性都不一样。因此我们在计算模型的准确性时需要多次计算,并求准确性的平均值和方差。
(2)使用ploynomial_model()函数构造出3个模型,分别是一阶多项式、三阶多项式、十阶多项式,
分别画出这3个模型的学习曲线。
#为了让学习曲线更平滑,计算10次交叉验证数据集的分数
cv = ShuffleSplit(n_splits = 10,test_size = 0.2,random_state = 0)
titles = ['Learning Curves (Under Fitting)','Learning Curves','Learning Curves (Over Fitting)']
degrees = [1,3,10]
plt.figure(figsize = (18,4),dpi = 200)
for i in range(len(degrees)):
plt.subplot(1,3,i+1)
plot_learning_curve(polynomial_model(degrees[i]),titles[i],X,y, ylim=(0.75 ,1.01 ),cv=cv)
plt.show()
如图所示,中图的三阶多项式能够较好的拟合数据。
虚线:针对训练数据集计算出的分数,即针对训练数据集你和的准确性。
实线:针对交叉验证数据计算出的分数,即针对交叉验证数据集预测的准确性。
左图的欠拟合可以发现发生高偏差时,增加训练样本数量不会对算法准确性有较大改善。
当需要改进学习算法时,可以画出学习曲线以便判断算法是处在高偏差还是高方差问题。
3.4.2 过拟合和欠拟合的特征
总结过拟合和欠拟合特点如下:
(1)过拟合:模型对训练数据集准确性较高,成本Jtrain较低,交叉验证数据集准确性较低,成本Jcv较高。
(2)欠拟合:模型对训练数据集准确性较低,成本Jtrain较高,交叉验证数据集准确性较低,成本Jcv较高。
好的机器学习算法应当保证对两个数据集的准确性都高并且还能保持较低成本,即对未知数据有良好的预测性。
3.5 算法模型性能优化
对于过拟合算法采取的措施:
(1)获取更多的训练数据:更多数据有助于改善过拟合问题。
(2)减少输入的特征数量:通过减小特征数量从而减小模型复杂度和计算量,改善过拟合问题。
对于欠拟合算法采取的措施:
(1)增加有价值的特征:尝试增加过去没有的特征,达到更好的预测效果。
(2)增加多项式特征:上述例子中三阶多项式比一阶多项式拟合数据更好,就是采用了增加多项式特征这个方法。
3.6 查准率和召回率
背景:有时候模型准确性并不能评价算法的好坏。例如预测得癌症的概率,从模型准确性的指标上很难判断到底是变好了还是变坏了,因为提前成功预测得概率太低了。
对于这类模型引入查准率和召回率
以癌症筛查为例:
查准率和召回率在此处得定义:
上述定义中:True/False表示预测结果是否正确。Positive/Negative表示预测结果是恶心肿瘤(1)/良性肿瘤(0)。TruePositive表示正确预测出恶心肿瘤得数量,FalsePositive表示正确预测出恶性肿瘤得数量,FalseNegative表示错误地预测出良性肿瘤的数量。
在scikit-learn中,计算查准率和召回率的API分别为sklearn.metrics.precision_score()和sklearn.metrics.recall_score()。
3.7 F1 Score
通过查准率和召回率判断算法的好坏
引入F1Score概念:
P为查准率,R为召回率,在scikit-learn中计算F1Score的函数为sklearn.metrics.f1_score(),理想状态下查准率和召回率都会1,即F1Score为1。