二. 模型评估与选择
2.1 经验误差
误差
我们把分类错误的样本数占总样本数的比例称为“错误率”(error rate),那么精度(accuracy)就为1-错误率。我们把模型的实际预测输出与样本的真实输出之间的差异称为“误差(error)”,对于训练集的误差我们称为“训练误差”,在新样本的误差称为“泛化误差(generalization)”。
那么如果想要得到好的模型,我们肯定要使得这个误差最小化,为了在新样本上表现的很好的模型,应该从训练样本中尽可能学出适用于所有潜在样本的普遍规律,这样子就会在遇到新样本的时候做出相对应正确的判断。
过拟合和欠拟合
上述的学习中,经常会出现一些问题,比如说模型在训练数据上表现很好,但在新数据(测试数据)上表现很差。也就是说,模型过于“拟合”训练数据,记住了训练数据的噪声和细节,而没有学到数据的真正规律,这个现象叫做过拟合(overfitting)。
- 过拟合的特征
- 训练误差很低:模型在训练集上的表现非常好,误差很低。
- 测试误差较高:模型在测试集上的表现不好,误差较高。
- 复杂模型:模型参数过多或结构过于复杂,能够记住训练数据中的每一个细节和噪声。
- 原因
- 模型过于复杂:使用了过多的特征或高阶多项式,模型复杂度过高。
- 训练数据不足:训练数据量不足,导致模型只能记住有限的训练样本。
- 噪声数据:训练数据中存在噪声,模型把这些噪声也当成了有用的模式。
相反还有一个词叫做“欠拟合”(underfitting),这表示模型在训练数据和测试数据上的表现都很差。也就是说,模型过于简单,无法捕捉数据中的主要模式或规律。欠拟合通常发生在模型的复杂度不足、特征选择不当或训练数据不足的情况下。
- 欠拟合的特征
- 高训练误差:模型在训练集上的表现不好,误差很高。
- 高测试误差:模型在测试集上的表现也不好,误差同样很高。
- 简单模型:模型的复杂度过低,无法有效地学习数据中的模式。
- 原因
- 模型过于简单:模型的参数或结构过于简单,无法捕捉数据的复杂模式。例如,用线性模型拟合非线性数据。
- 特征不足:用于训练的数据特征不足,无法提供足够的信息来学习数据的模式。
- 数据不足:训练数据量不足,无法有效训练模型。
- 正则化过强:过度的正则化约束导致模型过于简单,无法学习数据中的复杂关系。
图1 数据点
图2 欠拟合/过拟合/适中拟合
图3 过拟合、欠拟合的直观类比
2.2 评估方法
做评估的时候,需要使用到测试集(test set),我们用测试集来测试模型对新样本的判别能力,然后以测试集上的测试误差作为泛化误差的近似。注意测试集和训练集的数据要不一样,不能有相同的。
那么怎么得到测试集呢?
比如说我们总共有m个样例数据集,既要训练又要测试。那么有几种常见的方法,对数据集进行处理,产生出训练集和测试集。
-
留出法 (Holdout Method)
概念:
- 将数据集随机划分为两个互斥的子集:训练集和测试集。
- 训练集用于训练模型,测试集用于评估模型性能。
优点:
- 简单易行,计算速度快。
缺点:
- 结果依赖于数据的随机划分方式,可能导致不稳定的结果。
- 测试集上的性能可能不代表模型在实际应用中的性能。
#留出法
from sklearn.model_selection import train_test_split
# 假设X是特征矩阵,y是标签向量
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
-
交叉验证法 (Cross-Validation)
概念:
- 将数据集划分为k个等大小的互斥子集(fold)。
- 每次用k-1个子集训练模型,用剩下的一个子集测试模型。
- 重复k次,每次选择不同的子集作为测试集,最终结果是k次测试结果的平均值。(通常我们把交叉验证法也称为k折交叉验证(k-fold cross validation))
优点:
- 充分利用数据集,评估结果更加稳定和可靠。
- 适用于数据量较小的情况。
缺点:
- 计算开销较大,尤其是当k值较大时。
常用的k值为10,此时称为10折交叉验证,其他常用的有5,20等。下图给出了10折交叉验证的示意图
图4 10折交叉验证示意图
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression
# 假设X是特征矩阵,y是标签向量
model = LinearRegression()
scores = cross_val_score(model, X, y, cv=10) # 10-fold 交叉验证
print("Cross-validation scores:", scores)
假定数据集中包含m个样本,若令k=m,则得到了交叉验证法的一样特例,也就是每次只留一个样本作为测试集,其余样本作为训练集。重复m次,每次选择不同的一个样本作为测试集,这个叫做留一法(Leave-One-Out,简称LOO),优点是充分利用数据集,评估结果更加稳定和可靠。缺点是计算开销极大,不适用于大数据集。
from sklearn.model_selection import LeaveOneOut
from sklearn.linear_model import LinearRegression
from sklearn.metrics import accuracy_score
# 假设X是特征矩阵,y是标签向量
loo = LeaveOneOut()
model = LinearRegression()
accuracies = []
for train_index, test_index in loo.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
accuracies.append(accuracy_score(y_test, y_pred))
print("LOOCV accuracy:", np.mean(accuracies))
在留出法和交叉验证法中,由于保留了一部分样本用于测试,所以实际评估的模型所使用的训练集比数据集要小,这会引入一些因训练样本规模不同而导致的估计偏差,留一法受训练样本规模变化的影响较小,但计算复杂度又高,所以接下来的这种方法可以减少训练样本规模不同造成的影响,同时还能比较高效地进行实验估计。
-
自助法 (Bootstrap)
概念:
- 给定包含m个样本的数据集D,我们对它进行采样生成数据集 D ′ D' D′:每次随机从D中挑选一个样本,将其拷贝放入 D ′ D' D′中,然后再将该样本放回初始数据集D中,使得该样本在瞎猜采样时仍有可能被采到;这个过程重复执行m次后,我们就得到了包含m个样本的数据集 D ′ D' D′,这就是自助采样的结果。显然,D中有一部分样本会在 D ′ D' D′中多次出现,而另一部分样本不出现,可以做个简单的估计,样本在m次采样中始终不被采到的概率是 ( 1 − 1 m ) m (1-\frac{1}{m})^m (1−m1)m,那么取极限得到:
lim m → ∞ ( 1 − 1 m ) m = 1 e ≈ 0.368 \lim_{m \to \infty} \left(1 - \frac{1}{m}\right)^m = \frac{1}{e} \approx 0.368 m→∞lim(1−m1)m=e1≈0.368
这样可以发现通过自助采样,初始数据集D中约35.8%的样本没有出现在采样数据集 D ′ D' D′中。于是我们可将 D ′ D' D′用作训练集,D\ D ′ D' D′用作测试集;这样,实际评估的模型与期望评估的模型都是用m个训练样本,而我们仍有数据总量约1/3的、没在训练集中出现的样本用于测试。这样的测试结果,也称为“包外估计(out-of-bag estimate)”
优点:
- 适用于数据量较小的情况,且可以估计模型的泛化误差。
- 每次抽样结果不同,可以用于模型不确定性的估计。
缺点:
- 部分样本可能多次出现在训练集中,而部分样本可能完全不在训练集中。
from sklearn.utils import resample
# 假设X是特征矩阵,y是标签向量
X_train, y_train = resample(X, y, n_samples=len(X), random_state=42)
X_test = X[~np.in1d(np.arange(len(X)), X_train)]
y_test = y[~np.in1d(np.arange(len(y)), y_train)]
2.3 性能度量
对学习器的泛化性能进行评估,不仅需要有效可行的实验估计方法,还要有衡量模型泛化能力的评估标准,这就是性能度量(performance measure)。
性能度量反映了任务需求,在对比不同模型的能力时,使用不同的性能度量往往会导致不同的评判结果。所以模型的好坏取决于算法和数据以及任务需求。
在预测任务中,给定样例集
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
(
x
)
f(x)
f(x)与真实标记
y
y
y进行比较。
回归任务最常用的性能度量是“ 均方误差(mean squared error)”
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)=m1i=1∑m(f(xi)−yi)2
更一般的,对于数据分布
D
D
D 和概率密度函数
p
(
.
)
p(.)
p(.),均方误差可描述为
E
(
f
;
D
)
=
∫
x
=
D
(
f
(
x
)
−
y
)
2
p
(
x
)
d
x
E(f;D) = \int_{x=D}(f(x)-y)^2p(x)\,dx
E(f;D)=∫x=D(f(x)−y)2p(x)dx
2.3.1 错误率与精度
错误率和精度是分类任务中最常用的两种性能度量,适用于二分类任务,也适用于多分类任务,错误率是分类错误的样本数占样本总数的比例,精度则是分类正确的样本数占样本总数的比例,对样例集
D
D
D, 分类错误率定义为:
E
(
f
;
D
)
=
1
m
∑
i
=
1
m
I
(
f
(
x
i
)
≠
y
i
)
E(f;D)=\frac{1}{m} \sum_{i=1}^{m}\mathbb{I}(f(x_i)\neq y_{i})
E(f;D)=m1i=1∑mI(f(xi)=yi)
精度则定义为
a c c ( f ; D ) = 1 m ∑ i = 1 m I ( f ( x i ) = y i ) = 1 − E ( f ; D ) acc(f;D)=\frac{1}{m} \sum_{i=1}^{m}\mathbb{I}(f(x_{i})=y_{i}) =1-E(f;D) acc(f;D)=m1i=1∑mI(f(xi)=yi)=1−E(f;D)
2.3.2 查准率、查全率与F1
在机器学习和信息检索领域,查准率(Precision)、查全率(Recall)和 F1 分数(F1 Score)是用于评估分类模型性能的重要指标。
-
查准率(Precision):
查准率衡量的是模型预测的正样本中实际为正样本的比例。它关注的是预测结果的准确性。公式:
Precision = TP TP + FP \text{Precision} = \frac{\text{TP}}{\text{TP} + \text{FP}} Precision=TP+FPTP
其中,TP(True Positive)是预测为正且实际为正的样本数,FP(False Positive)是预测为正但实际为负的样本数。 -
查全率(Recall):
查全率衡量的是实际正样本中被正确预测为正样本的比例。它关注的是实际正样本被识别的程度。公式:
Recall = TP TP + FN \text{Recall} = \frac{\text{TP}}{\text{TP} + \text{FN}} Recall=TP+FNTP
其中,FN(False Negative)是预测为负但实际为正的样本数。 -
F1 分数(F1 Score):
F1 分数是 Precision 和 Recall 的调和平均,用于在这两者之间取得平衡。当需要兼顾查准率和查全率时,F1 分数是一个很好的评估指标。公式:
F1 Score = 2 ⋅ Precision ⋅ Recall Precision + Recall \text{F1 Score} = 2 \cdot \frac{\text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}} F1 Score=2⋅Precision+RecallPrecision⋅Recall
以上的几种情形我们可以表示在混淆
预测结果 | |||
---|---|---|---|
正例 | 反例 | ||
真实情况 | 正例 | TP (真正例) | FN (假反例) |
反例 | FP (假正例) | TN (真反例) |
查准率和查全率是一对矛盾的度量,查准率高,查全率往往就会比较低。例如,如希望将好瓜尽可能多地选出来,则可通过增加选瓜的数量来实现,如果将所有西瓜都选上,那么所有的好瓜也必然都被选上,但是这样查准率就会比较低。若希望选出的瓜中好瓜比例尽可能高,则可只挑选最有把握的瓜,但这样就难免会漏掉不少好瓜,使得查全率较低,通常只有在一些简单任务中,才可能使查全率和查准率都很高。
图5 P-R曲线与平衡点示意图
在P-R图直观地显示出学习器在样本总体上的查全率、查准率。在进行比较时,若一个学习器的P-R曲线被另一个学习器的曲线完全包住,则表示后者的性能优于前者,比如在图5中学习器A的性能优于学习器C;如果两个学习器的P-R曲线发生了交叉,比如A和B,则难以一般性地断言两者的孰优孰劣,只能在具体的查准率或查全率条件下进行比较。然而,有些时候人们还是想要把A和B进行一个比较,这时候一个比较合理的判断依据是比较P-R曲线下面积的大小,但是这个值不大容易估算。
所以有一种新的性能度量。
“平衡点(Break-Even Point,简称BEP)” 是“查准率=查全率”时的取值,例如图5种学习器C的BEP时0.64,而基于BEP的比较,可认为学习器A优于B。
BEP还是过度简化了,更常用的还是F1度量。
2.3.3 ROC 与 AUC
ROC 曲线(Receiver Operating Characteristic Curve,受试者工作特征曲线)和 AUC(Area Under Curve,曲线下面积)是评估二分类模型性能的重要工具。
ROC 曲线展示了不同阈值下分类器的表现。它通过绘制真正例率(True Positive Rate, TPR)对假正例率(False Positive Rate, FPR)的曲线来评估模型的性能。
-
真正例率 (TPR),也称为查全率(Recall):
TPR = TP TP + FN \text{TPR} = \frac{\text{TP}}{\text{TP} + \text{FN}} TPR=TP+FNTP
表示所有实际为正的样本中被正确预测为正的比例。 -
假正例率 (FPR):
FPR = FP FP + TN \text{FPR} = \frac{\text{FP}}{\text{FP} + \text{TN}} FPR=FP+TNFP
表示所有实际为负的样本中被错误预测为正的比例。
AUC 是 ROC 曲线下的面积,用于量化模型的整体性能。AUC 的取值范围在 0 到 1 之间:
- AUC = 1:完美的分类器
- AUC = 0.5:随机分类器
- AUC < 0.5:比随机分类器还差(通常表示模型反向)
AUC 值越高,模型的分类性能越好。
ROC 曲线:曲线越靠近左上角(高 TPR,低 FPR),表示模型性能越好。
对角线:对角线表示随机分类器的表现,AUC 为 0.5。
AUC:曲线下面积,AUC 值越大,表示模型的整体分类性能越好。