模型评估-评估方法

通常通过实验测试来对学习器的泛化误差进行评估并进而做出选择。为此,需要使用一个“测试集”(testing set)来测试学习器对新样本的判别能力,然后以测试集上的“测试误差”(testing error)作为泛化误差的近似。

【重要假设】:测试样本也是从样本真实分布中独立同分布采样而得。举个简单的例子,假设你要检验新研发的药对人的作用,你肯定是选择小白鼠,而不是红鲤鱼。因为红鲤鱼是鱼类,而小白鼠与人同属于哺乳动物。

下面将介绍机器学习中常用的评估方法,主要通过 sklearn 和鸢尾花数据集来进行说明。

from sklearn.datasets import load_iris


dataset = load_iris()
data_iris = dataset.data
target_iris = dataset.target
feature_iris = dataset.feature_names

留出法

留出法将测试数据集和训练数据集完全分开,采用测试数据集来评估算法模型。也就是说,我们可以简单地将原始数据集分为两部分:

  • 第一部分作为训练数据集,用来训练算法生成模型;
  • 第二部分作为测试数据集,通过模型来预测结果并与已知的结果进行比较,最终评估算法模型的准确度。

【数学表示】:将数据集 D 划分为两个互斥的集合,其中一个集合作为训练集 S,另一个作为测试集 T。S 和 T 满足条件 D = S ∪ T , S ∩ T = ∅ D = S \cup T, \quad S \cap T = \emptyset D=ST,ST=。在 S 上训练出模型后,用 T 来评估其测试误差,作为对泛化误差的估计。

以二分类任务为例,假设有 1000 条记录,训练集 S 700 条,测试集 T 300 条。在模型训练完成后,测试集 T 上有 90 条记录分类错误,则错误率为 90 / 300 = 0.3,则准确率为 0.7。

训练集和测试集的划分对最终模型的泛化能力存在一定的影响。考虑这样一种情况,测试集远大于训练集。在该情况下,“喂给”模型训练的数据集太少了,这就好比你在看一篇讲述模型评估的博客,但这篇博客的内容太少了,你看完之后还是云里雾里没能搞懂什么是模型评估。此时训练出来的模型会出现欠拟合现象。

再考虑这样一种情况,训练集远大于测试集。在该情况下,可供模型训练的数据集十分充足,模型训练得非常好,但测试集太小了,不具有代表性。举个极端的例子,假设现在只有 3 个测试数据,那么只要有一个测试数据不通过,正确率就只有 66%,到底是模型的拟合能力还是测试集中存在噪声(可以理解为测试数据本身存在错误)。因此,训练集和测试集的划分是一项非常考究的工作,对后续模型的训练起到重要的影响。

除了上述两种极端的情况,我们也可以从偏差-方差角度来思考这个问题。训练集越多,则模型学习得也越好,但很有可能导致模型学习得过好以至于在测试集上表现得不好,这就是过拟合问题,体现在偏差-方差中就是低偏差高方差;若训练集较少,则模型学习得不够好,并且在测试集上表现得也不好,这就是欠拟合问题,体现在偏差-方差中就是高偏差高方差。

此外,训练集和测试集的划分要尽可能保持数据分布的一致性,避免因数据划分过程引入额外的偏差而对最终结果产生影响。例如,在分类任务中至少要保持样本的类别比例相似。基于该情况考虑的采样方式称为“分层采样”。

原始数据集   训练集       测试集
X1  X2  Y    X1  X2  Y   X1  X2  Y
1   1   0    1   1   0   1   2   0
1   2   0    2   2   1   2   3   1
2   2   1
2   3   1

留出法的划分问题被称为划分窘境,接下来我们就来谈谈如何减轻划分窘境所产生的负面影响。

【分割规则】:如何分割数据集取决于数据集的规模:

  • 通常会将 67% 的数据作为训练集,将 33% 的数据作为评估数据集。
  • 《机器学习》中指出“一般而言,测试集至少应含 30 个样例”。
  • 吴恩达老师的深度学习课程中也提到在传统机器学习中训练集和测试集的划分问题,他认为原始数据集应分为三部分,训练集、验证集和测试集,并按 6:2:2 的比例进行划分。

综上考虑,若数据集规模较小,我们应该要满足测试集至少应含 30 个样例。若数据集规模较大,则 60%~80% 作为训练集都是可以的。

【使用场合】:通常在具有大量数据且数据分布比较平衡,或者对问题的展示比较平均的情况下非常有效。该非常简洁、快速,对某些执行比较慢的算法非常有效。

【代码实现】:

from sklearn.model_selection import train_test_split


# 先查看原先数据集的尺寸
print(data_iris.shape)  # 输出 (150, 4)

# 按照 67& 训练集 33% 测试集进行划分
data_iris_train, data_iris_test, target_iris_train, target_iris_test = \
train_test_split(data_iris, target_iris, test_size=0.33, random_state=4)
print(data_iris_train.shape)  # 输出 (100, 4)
print(data_iris_test.shape)  # 输出 (50, 4)

【注意】:为了让算法模型具有良好的可复用性,在指定分离数据大小的同时,还指定了数据随机的粒度(seed=4),将数据随机进行分离。通过指定随机的粒度,可以确保每次执行程序得到相同的结果,这有助于比较两个不同的算法生成的模型的结果。除此之外,还必须保证训练数据集和评估数据集是相同的。

关于 train_test_split() 方法更多的介绍,可参考官方文档 传送门

即便给定训练集和测试集的样本比例后,仍存在多种划分方式对原始数据集进行分割。且不同的划分将导致不同的训练集和测试集,模型评估的结果也会有差别。假设原始数据集满足正态分布,第一次划分过程中将正态分布边缘部分数据划分给了训练集,而第二划分过程则是将核心部分数据划分给了训练集,这两种划分训练所得的模型的评估结果差距会很明显。交叉验证法能够在一定程度上缓解因不同划分引入的误差问题。

交叉验证法

交叉验证法(cross validation)先将数据集 D 划分为 k 个大小相似的互斥子集,即 D = D 1 ∪ D 2 ∪ ⋯ ∪ D k , D i ∩ D j = ∅ ( i ≠ j ) D = D_1 \cup D_2 \cup \cdots \cup D_k, D_i \cap D_j = \emptyset(i \neq j) D=D1D2Dk,DiDj=(i̸=j)。每个子集 D i D_i Di 都尽可能保持数据分布的一致性,即从 D 中通过分层采样得到。然后,每次用 k - 1 个子集的并集作为训练集,余下的那个子集作为测试集;这样就可获得 k 组训练/测试集,从而可进行 k 次训练和测试,最终返回的是这 k 个测试结果的均值。

交叉验证法评估结果的稳定性和保真性在很大程度上取决于 k 的取值,为强调这一点,通常把交叉验证法称为“k 折交叉验证(k-fold cross validation)”。

【黄金准则】:

  • K 折交叉验证是用来评估机器学习算法的黄金准则。通常会取 K 为 3、5、10 来分离数据,只有在原始数据集和数据量很小时,才会尝试取 2。
  • 当不知道如何选择分离数据集的方法时,请选择 K 折交叉验证来分离数据集;当不知道如何设定 K 值时,请将 K 值设为 10。

与留出法相似,将原始数据集划分为 k 个子集同样存在多种划分方式,但相比留出法要好一些,毕竟我们对原始数据集做了十次不同的采样。

为进一步减小因样本划分不同而引入的差别,k 折交叉验证通常要随机使用不同的划分重复 p 次,最终的评估结果是这 p 次 k 折交叉验证结果的均值。

【代码实现】:

from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeClassifier


kfold = KFold(n_splits=10, random_state=7)
score = cross_val_score(DecisionTreeClassifier(), data_iris, target_iris, cv=kfold)
print("%.3f%% (%.3f)" % (score.mean() * 100, score.std() * 100))  # 输出:94.000% (6.960)

交叉验证另外一种用途是随机多次分离原始数据集为训练数据集和评估数据集。具体代码如下:

from sklearn.model_selection import ShuffleSplit


ss = ShuffleSplit(n_splits=10, test_size=0.33, random_state=7)
score = cross_val_score(DecisionTreeClassifier(), data_iris, target_iris, cv=ss)
print("%.3f%% (%.3f)" % (score.mean() * 100, score.std() * 100)) # 输出 94.200% (2.750)

留一法

留一法(Leave-One-Out,简称 LOO),假定数据集 D 中包含 m 个样本,若令 k = m,则得到交叉验证法的一个特例,即留一法,又被称为“弃一交叉验证”。

【优点】:

  • 不受随机样本划分方式的影响,因为 m 个样本只有唯一的方式划分为 m 个子集——每个子集包含一个样本。
  • 由于留一法使用的训练集与原始数据集相比只少了一个样本,这就使得在绝大多数情况下,留一法评估结果往往被认为比较准确。

【缺陷】:

  • 数据集较大时,训练 m 个模型的计算开销太大。
  • 留一法的估计结果也未必永远比其他评估方法准确,没有免费的午餐定理对实验评估方法同样适用。

【代码实现】:

from sklearn.model_selection import LeaveOneOut
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeClassifier


loo = LeaveOneOut()
score = cross_val_score(DecisionTreeClassifier(), data_iris, target_iris, cv=loo)
print("%.3f%% (%.3f)" % (score.mean() * 100, score.std() * 100))  # 输出:95.333% (21.092)
print(score)
# 输出:
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
       1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
       1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
       1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
       1., 1., 0., 1., 1., 1., 1., 1., 1., 0., 1., 1., 1., 1., 1., 0., 1.,
       1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
       1., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
       0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.,
       1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])

自助法

自助法(bootstraping)直接以自助采样法(bootstrap sampling)为基础。给定包含 m 个样本的数据集 D,对其进行采样产生数据集 D’:

  • 每次随机从 D 中挑选一个样本,将其拷贝放入 D’;
  • 然后再将该样本放回初始数据集 D 中,使得该样本在下次采样时仍有可能被采到,其实就是有放回地采样;
  • 该过程重复执行 m 次后,就得到包含 m 个样本的数据集 D’。

【特点】:原始数据集 D 中有一部分样本会在 D’ 中多次出现,而另一部分样本不出现。假设,样本在 m 次采样中始终不被采到的概率是 ( 1 − 1 m ) m (1 - \frac{1}{m})^m (1m1)m,取极限得
l i m m − > ∞ ( 1 − 1 m ) m = 1 m ≈ 0.368 lim_{m->\infty}(1-\frac{1}{m})^m = \frac{1}{m} \approx 0.368 limm>(1m1)m=m10.368
即通过自助采样,原始数据集 D 中约有 36.8% 的样本未出现在采样数据集 D’ 中。于是可将 D’ 用作训练集,余下的数据用作测试集。这样,实际评估的模型与期望评估的模型都使用 m 个训练样本,而我们仍有数据总量约 1 / 3 的、没在训练集中出现的样本用于测试。这样的测试结果,亦称“包外估计”(out-of-bag estimate)。

【适合场景】:

  • 在数据集较小、难以有效划分训练集和测试集时很有用;因为将数据集进行划分会让训练集进一步减小,这可能会影响模型训练效果,而自助法能够维持训练集规模。
  • 自助法能从原始数据集中产生多个不同的训练集,这对集成学习等方法有很大好处,尤其是在减小方差问题方面。

【缺陷】:自助法产生的数据集改变了原始数据集的分布,这会引入估计偏差。因此,在原始数据集足够大时,留出法和交叉验证法更常用一些。

总结

sklearn 中还有许多评估方法,这些评估方法有的是上述所讲方法的进阶版,有的则是一些新的概念,大家可以去查阅官方文档做进一步的了解 传送门

模型评估=评估方法思维导图.png

参考

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值