来源:原始 Jupyter Notebook。内容已转换为网页阅读格式;下载原文件

在上一节中我们学到,为了避免模型在数据集上过度训练导致过拟合,通常将数据集划分为训练集和测试集。

数据集划分方法

假设我们有一个包含 m 个样例的数据集 D={(x1,y1),(x2,y2),...,(xm,ym)} D = \{(\bf{x_1}, y_1), (\bf{x_2}, y_2), ..., (\bf{x_m}, y_m)\} ,得想办法对数据集进行划分,分成训练和测试两类,训练集记为 S S ,测试集记为 T T 。这样的划分方法有很多,常见的有:留出法(hold-out)、交叉验证法(cross validation)、自助法(bootstrapping)等。

留出法非常简单,直接将数据集划分成两个互斥的集合,分别作为训练集和测试集,D=ST,ST= D = S \cup T, S \cap T = \emptyset ,常见的做法是将大约 2/3 ~ 4/5 的数据用于训练,剩余的数据用于测试,注意划分的时候尽可能保持数据分布的一致性。

交叉验证法先将数据集划分成 k 个大小相似的互斥子集,D=D1D2Dk,DiDj=(ij) D = D_1 \cup D_2 \cup \dots \cup D_k, D_i \cap D_j = \emptyset(i \ne j) ,同样划分时尽可能保持数据分布的一致性。然后,用其中的 k-1 个子集的并集作为训练集,剩下的那个子集作为测试集,这样可以进行 k 次训练和测试,最终计算这 k 次测试结果的均值。交叉验证法又叫 k 折交叉验证(k-fold cross validation)。

自助法是以 自助采样(bootstrap sampling,也称为 可重复采样)为基础的样本划分方法,所谓自助采样,指的是从数据集 D D 中随机挑选一个样本,将其拷贝放入一个新集合 D D' 中,然后将样本重新放回集合 D D 中,重复 m 次,得到一个包含 m 个样本的数据集 D D' 。很显然,D D 中有些样本在 D D' 中会出现多次,还有一些样本不会出现,样本不会出现的概率是:

limm+(11m)m=1e0.368 \lim\limits_{m \to +\infty}(1-\frac{1}{m})^m = \frac{1}{e} \approx 0.368

我们将 D D' 用作训练集,D D' 中没有出现的样本 D\D D \backslash D' 用作测试集,这样的测试结果也叫做 包外估计(out-of-bag estimate)。

模型评估方法

通过上面的方法,把样本数据分成训练集和测试集之后,就可以使用你的机器学习算法对训练集进行训练生成一个模型,然后再拿着这个模型在测试集上进行验证,评估这个模型的效果。

其实,在前面介绍损失函数时提到了两种损失函数,一种是 绝对损失(Absolute Loss),一种是 平方损失(Squared Loss)

绝对损失函数:

loss=yy^ loss = |y - \hat{y}|

平方损失函数:

loss=(yy^)2 loss = (y - \hat{y})^2

这实际上也是两种评估模型的指标,分别是:平均绝对误差(Mean Absolute Error,MAE) 和 均方误差(Mean Squared Error,MSE)。

MAE=1Ni=1Nyiyi^ MAE = \frac{1}{N} \sum_{i=1}^{N} \left| y_i - \hat{y_i} \right| MSE=1Ni=1N(yiyi^)2 MSE = \frac{1}{N} \sum_{i=1}^{N} (y_i - \hat{y_i})^2

除此之外,从 MAE 还可以演变成一个新的指标,平均绝对百分误差(Mean Absolute Percentage Error,MAPE):

MAPE=100Ni=1Nyiyi^yi,yi0 MAPE = \frac{100}{N} \sum_{i=1}^{N} \left| \frac{y_i - \hat{y_i}}{y_i} \right|, y_i \ne 0

MAPE 通过计算绝对误差的百分比来表示预测效果,其取值越小越好,如果 MAPE = 10,这表明预测平均偏离真实值 10%。

从 MSE 也可以演变成一个新的指标,均方根误差(Root Mean Squared Error,RMSE),它就是对 MSE 求开方:

RMSE=1Ni=1N(yiyi^)2=MSE RMSE = \sqrt{\frac{1}{N} \sum_{i=1}^{N} (y_i - \hat{y_i})^2} = \sqrt{MSE}

基于 RMSE 还有一个变种指标,叫均方根对数误差(Root Mean Squared Logarithmic Error,RMSLE),将上面公式中的 yiy_iyi^\hat{y_i} 换成对数形式:

RMSLE=1Ni=1N(log(yi+1)log(yi^+1))2 RMSLE = \sqrt{\frac{1}{N} \sum_{i=1}^{N} (log(y_i+1) - log(\hat{y_i}+1))^2}

最后,R2R^2(R-Square)也是一个常见的评估指标,它的公式如下:

R2=1i=1N(yiyi^)2i=1N(yiyiˉ)2 R^2 = 1 - \frac{\sum_{i=1}^{N} (y_i - \hat{y_i})^2}{\sum_{i=1}^{N} (y_i - \bar{y_i})^2}

R2R^2 用于度量因变量的变异中可由自变量解释部分所占的比例,一般取值范围是 0~1,R2R^2 越接近 1,表明回归平方和占总平方和的比例越大,回归线与各观测点越接近,用 x 的变化来解释 y 值变差的部分就越多,回归的拟合程度就越好。

使用 sklearn 评估模型

sklearn 中的 metrics 模块提供了几个方法来计算模型评估的指标值,譬如 mean_absolute_error() 用于计算 MAE,mean_squared_error() 用于计算 MSE,r2_score() 用于计算 R2R^2

import numpy as np
from sklearn import metrics

expected = np.array([10,20,30,40,50,60,70,80,90,100])
predicted = np.array([10,21,33,41,49,55,70,82,90,102])

print('MAE = ', metrics.mean_absolute_error(expected, predicted))
print('MSE = ', metrics.mean_squared_error(expected, predicted))
print('R-Square = ', metrics.r2_score(expected, predicted))

运行结果

MSE =  4.5
MAE =  1.5
R-Square =  0.9945454545454545

模型选择

上面介绍了多种数据集划分的方法和模型评估的方法,看起来我们只要挑一个评估结果最好的模型就可以了,但是实际上,模型选择可能要比想象中复杂的多。这里面涉及几个重要因素:

  • 首先,我们希望比较的是泛化性能,而我们通过评估方法得到的是测试集上的性能,两者的对比结果未必相同;
  • 第二,测试集上的性能和测试集本身的选择有很大关系,使用大小不同的测试集,或者使用大小相同但数据不同的测试集,测试结果也会有不同;
  • 第三,很多机器学习算法本身具有一定的随机性,即便相同的参数在相同的测试集上运行多次,测试结果也可能不同;

那么,有没有适当的方法对学习器的性能进行比较呢?统计学中的 假设检验(hypothesis test)为此提供了重要依据,根据假设检验,我们可以推断出,若在测试集上观察到学习器 A 比 B 好,则 A 的泛化性能是否在统计意义上优于 B,以及这个结论的把握有多大。

二项检验(binomial test)和 t 检验(t-test)是两种最基本的假设检验方法,可以对单个学习器泛化性能的假设进行检验;如果需要对多个学习器性能进行比较,可以使用 交叉验证 t 检验McNemar 检验,这两个方法都是在同一个数据集上进行检验,Fredman 检验Nemenyi 后续检验 可以在一组数据集上对学习器的性能进行检验。

参考

TODO

  • 为什么需要这么多的评估指标?
  • 每一种评估指标的优缺点,举例说明
  • 还有没有其他的评估指标?
  • RMSE 代表的是预测值和真实值差值的样本标准差?