机器学习模型的性能可以用模型的偏差和方差来描述。
高偏差模型对将数据集中的输入映射到输出的未知底层函数的形式做出强假设,例如线性回归。高方差模型高度依赖于训练数据集的具体细节,例如未修剪的决策树。我们希望模型具有低偏差和低方差,尽管这两者之间通常存在权衡。
偏差-方差权衡是选择和配置模型的有用概念,尽管通常无法直接计算,因为它需要对问题域的全面了解,而我们并不具备。然而,在某些情况下,我们可以估计模型的误差,并将误差分解为偏差和方差分量,这可能有助于深入了解给定模型的行为。
在本教程中,您将学习如何计算机器学习模型的偏差和方差。
完成本教程后,您将了解:
- 模型误差由模型方差、模型偏差和不可约误差组成。
- 我们寻求具有低偏差和低方差的模型,尽管通常减少其中一个会导致另一个的增加。
- 如何将均方误差分解为模型偏差和方差项。
使用我的新书《使用 Python 进行机器学习掌握》启动您的项目,包括分步教程和所有示例的 Python 源代码文件。
让我们开始吧。

如何在 Python 中计算偏差-方差权衡
图片由 Nathalie 拍摄,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 偏差、方差和不可约误差
- 偏差-方差权衡
- 计算偏差和方差
偏差、方差和不可约误差
考虑一个用于预测建模任务(例如回归或分类)进行预测的机器学习模型。
模型在该任务上的性能可以用所有未用于训练模型的示例上的预测误差来描述。我们将此称为模型误差。
- 误差(模型)
模型误差可以分解为三个误差来源:模型的方差、模型的偏差以及数据中不可约误差的方差。
- 误差(模型) = 方差(模型) + 偏差(模型) + 方差(不可约误差)
让我们仔细看看这三个术语。
模型偏差
偏差衡量模型能多接近地捕捉输入和输出之间的映射函数。
它捕获了模型的刚性:模型对输入和输出之间映射函数形式的假设强度。
这反映了模型的功能形式能多接近地接近预测变量和结果之间的真实关系。
— 第 97 页,《应用预测建模》,2013 年。
当偏差与预测建模问题的真实但未知的底层映射函数相匹配时,高偏差模型很有用。然而,当问题的功能形式与模型的假设不匹配时,例如假设具有高度非线性关系的数据存在线性关系时,具有大偏差的模型将完全无用。
- 低偏差:对输入到输出映射的功能形式做出弱假设。
- 高偏差:对输入到输出映射的功能形式做出强假设。
偏差总是正的。
模型方差
模型方差是模型在不同训练数据上拟合时性能变化的程度。
它捕获了数据细节对模型的影响。
方差指的是如果使用不同的训练数据集进行估计,[模型]会改变多少。
— 第 34 页,《R 应用统计学习导论》,2014 年。
高方差模型会随着训练数据集的微小变化而发生很大变化。相反,低方差模型会随着训练数据集的微小甚至较大变化而发生很少变化。
- 低方差:训练数据集发生变化时,模型变化很小。
- 高方差:训练数据集发生变化时,模型变化很大。
方差总是正的。
不可约误差
总体而言,模型的误差由可约误差和不可约误差组成。
- 模型误差 = 可约误差 + 不可约误差
可约误差是我们可以改进的部分。它是模型在训练数据集上学习时我们减少的量,我们试图使这个数字尽可能接近零。
不可约误差是我们的模型或任何模型都无法消除的误差。
该误差是由我们无法控制的因素造成的,例如观测中的统计噪声。
……通常称为“不可约噪声”,无法通过建模消除。
— 第 97 页,《应用预测建模》,2013 年。
因此,尽管我们可能能够将可约误差压制到非常小的值(接近零,甚至在某些情况下为零),但我们总会存在一些不可约误差。它定义了问题性能的下限。
重要的是要记住,不可约误差将始终为我们对 Y 的预测准确性提供一个上限。这个上限在实践中几乎总是未知的。
— 第 19 页,《R 应用统计学习导论》,2014 年。
这提醒我们,没有完美的模型。
偏差-方差权衡
模型的性能偏差和方差是相互关联的。
理想情况下,我们更喜欢低偏差和低方差的模型,但在实践中,这非常具有挑战性。事实上,这可以被描述为给定预测建模问题应用机器学习的目标,
减少偏差可以通过增加方差轻松实现。反之,减少方差可以通过增加偏差轻松实现。
这被称为权衡,因为很容易获得一个偏差极低但方差高的方法 […] 或一个方差极低但偏差高的方法 …
— 第 36 页,《R 应用统计学习导论》,2014 年。
这种关系通常被称为偏差-方差权衡。它是一个用于思考如何选择模型和模型配置的概念框架。
我们可以根据模型的偏差或方差来选择模型。简单的模型,例如线性回归和逻辑回归,通常具有高偏差和低方差。复杂的模型,例如随机森林,通常具有低偏差但高方差。
我们还可以根据模型配置对模型偏差和方差的影响来选择。k-近邻中的超参数 k 控制着偏差-方差权衡。小值,例如 k=1,会导致低偏差和高方差,而大 k 值,例如 k=21,会导致高偏差和低方差。
高偏差不总是坏事,高方差也不是,但它们可能导致糟糕的结果。
我们通常必须测试一系列不同的模型和模型配置,以发现哪种最适合给定数据集。具有大偏差的模型可能过于僵硬并使问题欠拟合。相反,大方差可能使问题过拟合。
只要它减少模型误差的总体估计,我们就可以决定增加偏差或方差。
计算偏差和方差
我经常收到这个问题
我如何计算我的算法在我的数据集上的偏差-方差权衡?
从技术上讲,我们无法执行此计算。
我们无法计算预测建模问题的实际偏差和方差。
这是因为我们不知道预测建模问题的真实映射函数。
相反,我们使用偏差、方差、不可约误差和偏差-方差权衡作为工具,帮助选择模型、配置模型和解释结果。
在无法观察到 f 的实际情况下,通常不可能显式计算统计学习方法的测试 MSE、偏差或方差。尽管如此,我们应该始终牢记偏差-方差权衡。
— 第 36 页,《R 应用统计学习导论》,2014 年。
尽管偏差-方差权衡是一个概念性工具,但在某些情况下我们可以对其进行估计。
mlxtend 库由 Sebastian Raschka 提供 bias_variance_decomp() 函数,该函数可以估算模型在多个引导样本上的偏差和方差。
首先,您必须安装 mlxtend 库;例如
1 |
sudo pip install mlxtend |
以下示例直接通过 URL 加载波士顿房价数据集,将其拆分为训练集和测试集,然后估算线性回归的均方误差(MSE)以及模型在 200 个引导样本上的误差偏差和方差。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 估算回归模型的偏差和方差 from pandas import read_csv from sklearn.model_selection import train_test_split 来自 sklearn.linear_model 导入 LinearRegression from mlxtend.evaluate import bias_variance_decomp # 加载数据集 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv' dataframe = read_csv(url, header=None) # 分离输入和输出 data = dataframe.values X, y = data[:, :-1], data[:, -1] # 拆分数据 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1) # 定义模型 模型 = LinearRegression() # 估计偏差和方差 mse, bias, var = bias_variance_decomp(model, X_train, y_train, X_test, y_test, loss='mse', num_rounds=200, random_seed=1) # 总结结果 print('MSE: %.3f' % mse) print('Bias: %.3f' % bias) print('Variance: %.3f' % var) |
运行示例将报告估计误差以及模型误差的估计偏差和方差。
注意:您的结果可能会有所不同,因为算法或评估过程的随机性,或数值精度的差异。考虑运行几次示例并比较平均结果。
在这种情况下,我们可以看到模型具有高偏差和低方差。考虑到我们使用的是线性回归模型,这是可以预期的。我们还可以看到,估计均值和方差之和等于模型的估计误差,例如 20.726 + 1.761 = 22.487。
1 2 3 |
MSE:22.487 偏差:20.726 方差:1.761 |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
教程
书籍
- 统计学习导论:R语言应用, 2014.
- 应用预测建模, 2013.
文章
总结
在本教程中,您学习了如何计算机器学习模型的偏差和方差。
具体来说,你学到了:
- 模型误差由模型方差、模型偏差和不可约误差组成。
- 我们寻求具有低偏差和低方差的模型,尽管通常减少其中一个会导致另一个的增加。
- 如何将均方误差分解为模型偏差和方差项。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
嗨,Jason,
这是一篇很棒的文章。非常喜欢。以前不知道我们可以从模型中获得偏差和方差。
我有一个问题,使用 mlxtend 库,就像您计算线性回归的偏差、方差并与 (mse) 进行比较一样,是否也可以获得分类模型(逻辑或基于树的模型)的偏差、方差——如果是,我们应该与什么进行比较(与哪个误差项进行比较)?
谢谢,
纳拉
谢谢!
我相信这是可能的,但不简单。也许 mlxtend 也有分类的实现?
也许您可以查阅文献并尝试实现它?
嗨,Jason,
这是一篇很棒的文章。喜欢你的解释方式,
我有一个小疑问。你写道,减少偏差不容易通过增加方差实现。难道不应该是减少偏差可以通过增加方差轻松实现吗?
你说得对,这似乎是一个打字错误。已修正,谢谢!
嗨,Jason,
很棒的文章,感谢您提供的所有文章和书籍!
我尝试在经过超调和使用 early_stopping 的 XGBRegressor() 上使用 bias_variance_decomp()。以下是一些指标。我们可以说我们正在使模型过拟合吗?如果是这样,有哪些技术可以降低偏差并增加方差?减少超调或 early_stopping 吗?
最佳参数:{'subsample': 0.7, 'n_estimators': 250, 'max_depth': 10, 'learning_rate': 0.2, 'colsample_bynode': 0.6}
RMSE 1.5669 MSE 2.4553 MAE 1.0522 R2 0.8716
MSE: 4.2508 Bias: 3.2046 Variance: 1.0463
谢谢,
Bill
不客气,比尔!
不确定我们是否能这样使用这个工具。我需要考虑一下。
如果在训练集上的性能提高反而对保持/测试集上的性能产生负面影响,则说明您过拟合了。
更少的树会增加方差,尽管通常对于 xgboost,我们想要更多的偏差,而不是更多的方差。例如,尝试更多的正则化。
嗨,Jason,
我正在按照你的脚本操作,但我收到了这个错误
—————————————————————————
ImportError 回溯 (最近一次调用)
in ()
3 from sklearn.model_selection import train_test_split
4 from sklearn.linear_model import LinearRegression
—-> 5 from mlxtend.evaluate import bias_variance_decomp
ImportError: cannot import name ‘bias_variance_decomp’
—————————————————————————
有什么建议吗?
提前谢谢,JL
看起来你没有安装 mlxtend 库。
尊敬的Jason博士,
我不太确定从 mlxtend 包中确定一个模型的 mse、偏差和方差能得到什么。
所以我做的是查看您在另一个教程 https://machinelearning.org.cn/stacking-ensemble-machine-learning-with-python/ 中使用的各种模型,我修改了代码以包含偏差、方差和 mse 的度量。
代码来自您的网站。
使用的数据集不是 housing.csv,而是合成生成的数据。
我包含了这些模型。
我进行了一些进一步的修改以包含到 evaluate_models 中
我得到了以下结果,不仅有 mean(scores)、std(scores),还有 mse、方差和偏差。
下表列出了从最高到最低得分的模型
从以上结果来看,SVM 的平均得分最高。它的标准差、均方误差 (MSE)、偏差和方差也最低。
同时,偏差和方差之间似乎没有权衡。
最终,您不能仅仅根据偏差、方差和均方误差来选择模型。还需要查看其他评分方法,否则 LR 可能会成为候选模型。但是 LR 的得分低于 SVM。
谢谢你,
悉尼的Anthony
做得很好。
同意,仅凭偏差/方差选择模型是不够的。应以 MSE 为重点。
嗨,Jason,
使用 Keras 顺序模型
Keras_fit = Sequential()
Keras_fit.add….
Keras_fit.compile(optimizer = optimizer, loss = 'binary_crossentropy', metrics = ['accuracy'])
mse, bias, var = bias_variance_decomp(Keras_fit, X_train, y_train, X_valid, y_valid, loss='mse', num_rounds=200, random_seed=1)
由于 keras_fit 没有模型,如果我只传递 keras_fit,我会得到
AttributeError: 'History' object has no attribute 'predict'
即使传递模型,它也不起作用
Keras_model = Keras_fit.fit(X_train, y_train, validation_data=(X_valid, y_valid), batch_size = batch_size, epochs = epoch, verbose = 2)
请问如何获得它
谢谢
fit() 函数返回历史记录,而不是模型。
在模型对象本身上调用 fit()。
这是一个例子
https://machinelearning.org.cn/tutorial-first-neural-network-python-keras/
对于 SVM 模型,您的“损失”不能是“mse”。它应该是“0-1”或“hinge loss”。SVM 解决的不是回归问题,而是分类问题。因此,使用“0-1 loss”或“hinge loss”更合理(我不确定该库是否支持 hinge loss)
有一个用于回归的 SVM 版本,称为 SVR,您可以在这里了解更多信息
https://scikit-learn.cn/stable/modules/generated/sklearn.svm.SVR.html
杰森,好文章。我正在运行你提供的相同代码。但我似乎遇到了这个错误。任何修复此问题的想法都将非常有帮助。提前致谢。–
KeyError 回溯(最近的调用在最后)
in
1 # 估计偏差和方差
2 mse=0
—-> 3 mse, bias, var = bias_variance_decomp(model, X_train, y_train, X_test, y_test, loss='mse', num_rounds=200, random_seed=1)
C:\ProgramData\Anaconda3\lib\site-packages\mlxtend\evaluate\bias_variance_decomp.py in bias_variance_decomp(estimator, X_train, y_train, X_test, y_test, loss, num_rounds, random_seed, **fit_params)
84
85 for i in range(num_rounds)
—> 86 X_boot, y_boot = _draw_bootstrap_sample(rng, X_train, y_train)
87
88 # Keras 支持
C:\ProgramData\Anaconda3\lib\site-packages\mlxtend\evaluate\bias_variance_decomp.py in _draw_bootstrap_sample(rng, X, y)
14 size=sample_indices.shape[0],
15 replace=True)
—> 16 return X[bootstrap_indices], y[bootstrap_indices]
17
18
C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\frame.py in __getitem__(self, key)
2804 if is_iterator(key)
2805 key = list(key)
-> 2806 indexer = self.loc._get_listlike_indexer(key, axis=1, raise_missing=True)[1]
2807
2808 # take() 不接受布尔索引器
C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\indexing.py in _get_listlike_indexer(self, key, axis, raise_missing)
1550
1551 self._validate_read_indexer(
-> 1552 keyarr, indexer, o._get_axis_number(axis), raise_missing=raise_missing
1553 )
1554 return keyarr, indexer
C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\indexing.py in _validate_read_indexer(self, key, indexer, axis, raise_missing)
1637 if missing == len(indexer)
1638 axis_name = self.obj._get_axis_name(axis)
-> 1639 raise KeyError(f”None of [{key}] are in the [{axis_name}]”)
1640
1641 # 我们(暂时)允许 .loc 缺少一些键,但
KeyError: “None of [Int64Index([ 37, 235, 908, 72, 767, 905, 715, 645, 847, 144,\n …\n 110, 434, 502, 132, 265, 124, 384, 218, 405, 507],\n dtype='int64', length=919)] are in the [columns]”
谢谢。
很抱歉您遇到了问题,也许这些技巧会有所帮助
https://machinelearning.org.cn/faq/single-faq/why-does-the-code-in-the-tutorial-not-work-for-me
你好,你解决这个问题了吗?我遇到了同样的错误。
在应用 bias_variance_decomp 之前,您是否将这段代码用于您的 DataFrame?
data = dataframe.values
X, y = data[:, :-1], data[:, -1]
它帮助我解决了同样的问题。
感谢 Jason 撰写这篇关于比较模型误差的文章。
它解开了我的一些疑惑。
是否有办法运行类似于网格搜索的误差的偏差和方差分量的搜索?
也许,您可能需要进行实验。
好文章!
我有一个问题,bias_variance_decomp() 的结果中不可约误差在哪里?
我在 GitHub 上找到了源代码:“https://github.com/rasbt/mlxtend/blob/master/mlxtend/evaluate/bias_variance_decomp.py”
似乎使用“main_predictions – y_test”(第 154 行)计算偏差与偏差的原始定义相矛盾。
你为什么认为它矛盾?
偏差和方差的范围是多少?偏差是否有任何最大值?
你好 Ashwini...你能重新措辞你的问题,使其引用特定的代码清单,以便我们能更好地帮助你吗?
嗨,Jason,
有没有考虑偏差和方差的损失函数?