一个模型在训练集上精度较高,而在测试集上表现(泛化性能)不佳,称为过拟合。为什么会出现过拟合?这是因为模型将样本的特征训练的“太好了”,以至于将一些样本中特有的现象当作了“一般规律”。过拟合是机器学习算法需要解决的核心问题,不同的算法实际上是采用不同的手段缓解过拟合。在存在过拟合问题的情况下,发展出了一系列用于评价模型泛化能力的方法。
from sklearn.model_selection import train_test_split
x1,x2,y1,y2 = train_test_split(X,Y,0.25)
将数据集划分成 k k k 个大小相似的互斥子集,每次用 k − 1 k-1 k−1 个作为训练集,剩下的一个作为测试集,这样就有 k k k 次测试,取平均就得到最终的泛化误差。这一做法的好处在于,所有的样本都纳入训练了,若采用留出法,即使重复许多次,也可能有样本没有纳入训练。
from sklearn.model_selection import cross_val_score
scores = cross_val_score(estimator, X, Y, cv=10)
对数据集 D D D 做 m m m ( m m m 就是样本数) 次有放回抽样得到 D ′ D' D′,某个样本 x i x_i xi 不在 D ′ D' D′ 中的概率是
( 1 − 1 m ) m (1-\frac{1}{m})^{m} (1−m1)m
取极限得到
( 1 − 1 m ) m → e − 1 ≈ 0.368 a s n → ∞ (1-\frac{1}{m})^{m} \rightarrow e^{-1} \approx 0.368 \;\;as\;\; n \rightarrow \infty (1−m1)m→e−1≈0.368asn→∞
这就是说,初始数据集 D D D 中约有 36.8% 的样本未出现在采样数据集 D ′ D' D′中。于是我们可将 D ′ D' D′ 用作训练集, D / D ′ D/D' D/D′ 用作测试集。这样,实际评估的模型与期望评估的模型都使用 m m m 个训练样本,而我们仍有数据总量约 1/3 的、没在训练集中出现的样本用于测试。
可以这样理解自助法2:理想的抽样估计是从总体(真实分布)中抽取多个样本,计算参数估计量
F ⟶ i i d X ⟶ s θ ^ F \overset{iid}{\longrightarrow} X \overset{s}{\longrightarrow} \hat{\theta}\\ F⟶iidX⟶sθ^
然而实际中只能得到一个样本,因此对样本(经验分布)进行再抽样,得到bootstrap估计
F ^ ⟶ i i d X ∗ ⟶ s θ ^ ∗ \hat{F} \overset{iid}{\longrightarrow} X^* \overset{s}{\longrightarrow} \hat{\theta}^* F^⟶iidX∗⟶sθ^∗
自助法在数据集较小时比较有用,但是会改变初始数据集的分布,可能引入估计偏差。
from sklearn.model_selection import GridSearchCV
parameters = {'beta': [0.001, 0.01, 0.1, 1],
'gamma':[0.001, 0.01, 0.1, 1]}
# 输出每一次搜索结果,并行计算,自动为估计器配置最优参数
gs = GridSearchCV(estimator, parameters,
refit = True, cv = 5, verbose = 2, n_jobs = -1)
gs.fit(X,y)
print(gs.best_params_)
print(gs.best_score_)
主要使用均方误差(MSE)
M S E = 1 m ∑ i m ( f ( x i ) − y i ) 2 MSE = \frac{1}{m}\sum_{i}^{m} (f(x_i)-y_i)^2 MSE=m1i∑m(f(xi)−yi)2
用OLS来理解,实际上就是使得MSE最小化。
分类精度
a c c = 1 m ∑ i m I ( f ( x i ) = y i ) acc = \frac{1}{m}\sum_{i}^{m} \mathbb{I}(f(x_{i})=y_{i}) acc=m1i∑mI(f(xi)=yi)
但这个函数不太好求导做优化,所以算法里一般会用交叉熵损失作为目标函数
c e = − 1 m ∑ i m ∑ j T δ j i log 2 f ( x i ) ce = -\frac{1}{m}\sum_{i}^{m}\sum_{j}^{T}\delta_{ji}\log_2{f(x_i)} ce=−m1i∑mj∑Tδjilog2f(xi)
当样本 x i x_i xi 属于第 j j j 类时, δ j i = 1 \delta_{ji}=1 δji=1,否则为 0 0 0。
精度无法完整反映模型的性能!考虑如下案例:已知100名贷款人中有一位会违约,现有一个模型的预测模式为预测所有人都不会违约。这样,虽然模型的精度能达到99%,但是没有什么用。为此,需要引入混淆矩阵及查准率、查全率的概念。
考虑如下混淆矩阵
预测为正例 | 预测为反例 | |
---|---|---|
真实为正例 | TP | FN |
真实为反例 | FP | TN |
定义查准率(precision)、查全率(recall)分别为:
P = T P T P + F P R = T P T P + F N P = \frac{TP}{TP+FP}\\[3mm] R = \frac{TP}{TP+FN} P=TP+FPTPR=TP+FNTP
查准率表示预测为正例的有多少确实是正例,查全率表示真实的正例中,有多少被预测出来了。注意,这两个值一定是针对某一个类别定义的,不能说某个模型的查准率是多少,只能说这个模型在某一类别上的查准率为多少。在开头举得例子中,违约的 R = 0 R=0 R=0,查全率表现不佳。
一般来说, P P P 和 R R R 是一对互斥的指标,一个高了另一个就低。考虑一种极端的情况:将所有类别预测为正例,那么真实正例的 R = 1 R=1 R=1,而 P P P 可能比较低。
可以绘制P-R图直观地展示模型的预测能力。根据学习器的预测结果(一个0-1之间的概率值)对样例进行排序,排在前面的是学习器认为“最可能”是正例的样本,排在最后的则是学习器认为“最不可能”是正例的样本。按此顺序逐个把样本作为正例进行预测 ,则每次可以计算出当前的查全率、 查准率。以每一次的查准率为纵轴、查全率为横轴作图,就得到P-R图。基于P-R图可以定义一些综合考虑查准率、查全率的指标,如BEP, F 1 F_1 F1, F β F_{\beta} Fβ 等。
如果进行多次检验,就会得到多个混淆矩阵,此时可以基于每一次的结果定义宏/微查准率、查全率等。
与P-R曲线类似,根据学习器预测结果对样例进行排序,将分类阈值依次设定为1、每个样本的预测概率,每次计算两个值作为横纵坐标,就画出了受试工作者特征(ROC)曲线,这两个值为“真正例率”(TPR)和“假正例率”(FPR)
T P R = T P T P + F N = R F P R = F P T N + F P TPR = \frac{TP}{TP+FN} = R\\[3mm] FPR = \frac{FP}{TN+FP} TPR=TP+FNTP=RFPR=TN+FPFP
AUC是ROC曲线下面积,它反映了样本预测的排序质量,AUC越大,认为模型分类性能越好。
注意,ROC曲线的绘制是基于混淆矩阵的,而混淆矩阵默认两类的分类错误代价的权重是相等的。而在非均等代价下,ROC 曲线不能直接反映出学习器的期望总体代价,需要用“代价曲线”(cost curve) 。
画ROC曲线的例子
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve
from sklearn.metrics import auc
# 计算 FPR,TPR 与 AUC 面积
fpr, tpr, thresholds = roc_curve(true_label, predict_label)
roc_auc = auc(fpr, tpr)
# 绘制 ROC 曲线
plt.figure(figsize=(16,9))
lw = 2
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic (ROC)')
plt.legend(loc="lower right")
plt.show()
周志华,《机器学习》,第二章,2.1-2.3 ↩︎
吕晓玲等,《数据科学统计基础》,第五章 ↩︎