在我们构建模型以预测结果或发现模式的过程中,会遇到各种挑战。其中一个常见难题是创建一个能够准确捕捉数据底层趋势的模型。有时,模型过于简单,无法学到其中的复杂性,导致表现不佳。这种现象被称为欠拟合(Underfitting)。
欠拟合模型不仅在其训练数据上表现不佳,也无法泛化到新的、未见过的数据上。这意味着在真实场景中的预测可能不可靠。识别并解决欠拟合,是构建健壮且有效的机器学习模型的重要一步。
图片作者自制
在本文中,我们将探讨什么是欠拟合、为何会发生、如何识别,最重要的是,如何修复欠拟合。如果您希望动手实践机器学习,欢迎查看我们的 Python 机器学习基础学习路径 。
什么是欠拟合?
让我们更深入地理解欠拟合这一概念,并与其对应的过拟合加以对比。理解这一区别对模型诊断与改进至关重要。
图片作者自制
简而言之,当机器学习模型过于简单,无法捕捉训练数据中的底层模式时,就会发生欠拟合。想象用一条直线去拟合明显呈曲线分布的数据点,而这条线(我们的模型)不够复杂。欠拟合模型具有高偏差(high bias),这意味着它对数据做出了强假设(例如在不存在的情况下假设线性关系)。
由于它无法很好地学习数据,它不仅在训练数据上表现糟糕,在新的未见数据(测试数据)上同样表现不佳。不过,这类模型通常方差较低,即当在不同的数据子集上训练时,其预测变化不大。简单性让它们一致,但往往是一致地错误。
从数学上,这与模型期望误差的偏差-方差分解有关。模型的期望误差可分解为三个部分:偏差平方、方差和不可约误差:
其中:
E[(y - f̂(x))²] 是预测的期望平方误差。
Bias(f̂(x)) 衡量用模型近似真实函数 f(x) 所引入的误差。
Var(f̂(x)) 是针对不同训练数据集时模型预测的变动性。
σ² 表示不可约误差——数据中固有的、无法被预测的噪声。
在欠拟合中,Bias(f̂(x)) 项主导误差。模型过于简单,导致系统性误差,无法捕捉真实的数据关系。
欠拟合与过拟合的对比
将欠拟合与过拟合进行比较,有助于更清楚地理解欠拟合。欠拟合模型过于简单,而过拟合模型则过于复杂。它们对训练数据学得 太 好,不仅捕捉了底层模式,也把噪声和随机波动一并学了进去。
偏差-方差权衡——图片作者自制
下面来看欠拟合与过拟合的关键差异:
特征
欠拟合
过拟合
训练误差
高
很低
测试误差
高
高
模型复杂度
低
高
预测行为
一致但不准确
对训练数据准确,对新数据表现差
这引出了一个关键概念:偏差-方差权衡。
高偏差(欠拟合): 简单模型偏差高但方差低。它们往往持续出错,但在不同训练数据间变化不大。
高方差(过拟合): 复杂模型偏差低但方差高。它们对训练数据拟合很好(低偏差),但对训练数据的具体细节非常敏感,导致对新数据泛化差。您可以在我们的文章 什么是过拟合? 中了解更多。
目标是找到一个“甜蜜点”:模型足够复杂以捕捉真实模式(低偏差),但又不过分复杂以至于学习到噪声(低方差)。
示例:
欠拟合示例: 仅使用“房间数”来预测受面积、地段、楼龄等影响的房价。该模型过于简单(高偏差),很可能对大多数房屋做出糟糕预测。
过拟合示例: 构建一个高度复杂的多项式回归模型,使其完美穿过房价训练集中的每一个点。该模型在训练数据上几乎零误差,但在新房源上表现糟糕,因为它学到了训练集特有的噪声(高方差)。
了解您的模型位于这一谱系的何处,对于开发有效的机器学习方案非常重要。接下来我们将介绍如何检测并处理欠拟合。
欠拟合的成因与诊断指标
既然我们已经理解了什么是欠拟合,接下来看看它为何发生,以及如何在您的项目中检测它。找准根因对于选择正确的缓解策略至关重要。
欠拟合的主要原因
多种因素都可能导致欠拟合模型:
模型复杂度不足
所选算法可能对数据的底层结构而言过于简单。例如,当特征与目标变量之间存在显著非线性关系时却使用线性回归。模型本身缺乏捕捉复杂性的能力。
训练不足
模型的训练时间可能不够(例如神经网络的 epoch 过少),或学习参数设置不当。如果训练过早停止,即便模型有能力,它也没有足够机会学习模式。
特征表征不佳
用于训练模型的特征可能无法充分代表影响目标变量的底层因素,这可能意味着:
缺少重要特征: 关键预测因子未被纳入数据集。
存在无关特征: 数据集中包含噪声或与结果无关的特征,可能误导简单模型。
特征需要变换: 特征可能需要缩放、归一化或编码(如分类变量)后才对模型有用。
正则化过强
正则化技术(如 L1 或 L2 惩罚)主要用于通过对复杂度加罚来防止过拟合。但如果正则化强度(例如 lambda 参数)设置过高,会对模型过度约束,迫使其过于简单,从而导致欠拟合。关于正则化的更多内容,参见 走向防止过拟合:正则化 。
数据质量低或数量不足
数据不够: 如果训练集过小,模型可能没有足够样本去有效学习底层模式。
噪声较高: 如果数据噪声很大,尤其对简单模型而言,可能难以分辨信号与噪声。
缺失值多: 大量缺失数据会妨碍模型学习,尤其在未妥善处理时。处理技巧详见 R 中通过插补处理缺失数据 。
检测方法
如何判断模型是否欠拟合?以下是一些常见诊断技巧:
分析性能指标
最直接的信号是 训练集 与 验证/测试集 上均表现不佳。如果模型在其训练数据上就已高误差(或低准确率、低 R² 等),这强烈表明它尚未有效学习模式。与过拟合(训练表现极佳、测试表现差)不同,欠拟合在各数据集上都表现不佳。
学习曲线
绘制模型在训练集和验证集上的性能(例如误差或准确率)随训练时间或数据规模变化的曲线,往往很有启发意义。对欠拟合模型,学习曲线通常表现为:
训练误差高且很早就趋于平稳。
验证误差高且接近训练误差,同样趋于平稳。
两条曲线在较高误差水平收敛,表明即便增加数据或训练,模型也没有显著改进。
特征分析
回顾已用特征:它们是否相关?是否存在未捕捉的交互?数值特征是否已缩放?类别特征是否恰当编码?
有时,重新审视特征工程就能揭示模型为何挣扎。基础概念可参考 R 语言机器学习基础 。若想深入理解统计关系,可参考 R 语言统计推断 等资源。
对比建模
在相同数据上训练一个更复杂的模型(例如当初使用线性回归时,尝试决策树或梯度提升机)。如果更复杂的模型在训练与验证集上都显著优于最初模型,说明原模型很可能由于复杂度不足而欠拟合。
您可以使用 机器学习实验入门:Weights & Biases 中提到的工具来跟踪此类对比。
通过理解这些成因与检测方法,您可以有效诊断欠拟合模型,并采取措施提升其性能。
欠拟合的缓解策略与最佳实践
一旦确认存在欠拟合,下一步就是知道如何修复欠拟合。幸运的是,有多种有效策略可提升模型对数据底层模式的学习能力。下面来看几种方法:
提升模型复杂度
如果您的模型过于简单(高偏差),提高其复杂度常能缓解欠拟合。可以通过以下方式实现:
算法选择
切换到更强大的模型。如果线性回归欠拟合,可尝试多项式回归、决策树、随机森林、梯度提升(如 XGBoost 或 LightGBM),或使用带非线性核的支持向量机(SVM)。这些模型天生具备更强的捕捉复杂关系的能力。
多项式特征扩展
对于回归问题,您可以从现有数值特征创建多项式特征,这使线性模型能拟合更复杂的曲线关系。例如,对于特征 x,可添加 x2、x3 等新特征。Scikit-learn 提供了 PolynomialFeatures 用于此目的。
超参数调优
许多复杂模型拥有控制其复杂度的超参数(例如决策树的深度、神经网络层的神经元数、SVM 的 C 参数)。通过调大这些超参数以允许更高复杂度,可以降低偏差。
网格搜索或随机搜索等技术在此非常关键。可通过课程 Python 超参数调优 或 R 超参数调优 了解更多。另见我们的教程 机器学习模型的超参数优化 。
特征工程与数据增强
有时问题不在模型,而在数据表征。改进特征能带来显著帮助。可通过以下方式实现:
面向领域的特征构造
利用您对问题领域的理解创建更具信息量的新特征。例如预测房价时,将“卧室数量”和“浴室数量”合并为“总房间数”,或由“建成年份”计算“房龄”。
交互特征
创建表示现有特征间交互的新特征(如将两个特征相乘)。这有助于模型捕捉协同效应。
数据充实
如有可能,用外部数据源增强数据集。例如在客户信息中加入人口统计数据,或在销量预测中加入天气数据。
数据增强(主要用于非结构化数据)
对于图像或文本数据,可以通过图像旋转/翻转、文本同义词替换等方法,人工增加训练集的规模与多样性,帮助模型学习更稳健的模式。
调整正则化
如果欠拟合是由旨在防止过拟合的 过强 正则化引起,需要适当降低其强度。降低正则化参数(如 Ridge/Lasso 中的 alpha,SVM 中的 C——注意对 SVM 而言, 更小 的 C 表示 更强 正则化,因此应 增大 C)。
若使用 dropout,降低 dropout 率(训练中被丢弃的神经元比例)。较低的比例能保留更多网络容量。
找到合适平衡常需仔细调参,这也再次凸显超参数优化的重要性。
集成方法
集成方法将多个个体模型(弱学习器)的预测进行组合,以产生更强大、更稳健的最终预测。它们常常能有效降低偏差与方差。部分集成方法包括:
Bagging(如随机森林) :在不同的自助采样数据上独立训练多个模型(如决策树),并对它们的预测取平均。主要降低方差,但若基学习器稍有偏差,也能有所帮助。更多信息请参阅我们的 Bagging 教程 。
Boosting(如 AdaBoost、梯度提升) :顺序训练模型,每个新模型侧重纠正前一个模型的错误。Boosting 尤其擅长降低偏差,将弱学习器转变为强学习器,是对抗欠拟合的强力工具。我们有一份 Boosting 指南 进行详细说明。
Stacking :训练多种不同类型的模型,并使用另一个模型(元学习器)来学习如何最佳组合它们的预测。
通过应用这些策略(常常是组合使用),您可以有效应对欠拟合,构建更能捕捉数据复杂性的模型。
实践应用与案例研究
借助数据集与代码直观地观察欠拟合,可以显著加深理解。下面通过实践示例展示欠拟合模型的表现,以及如何改进其性能。
线性回归欠拟合示例
当用简单线性模型描述非线性关系时,常会出现欠拟合。我们用一个服从二次模式的数据,尝试拟合线性回归模型来说明这一点。
我们将生成一个合成数据,使目标变量 y 与特征 X 呈二次关系。首先拟合一个简单线性回归模型,观察其糟糕表现(高均方误差 MSE),并可视化其如何未能捕捉数据曲线。
随后,我们通过添加多项式项来扩展特征,并拟合一个多项式回归模型。这将展示如何通过增加模型复杂度来降低偏差,并显著提升模型精度。
首先导入所需库:
import numpy as np
import matplotlib. pyplot as plt
from sklearn. linear_model import LinearRegression
from sklearn. preprocessing import PolynomialFeatures
from sklearn. pipeline import make_pipeline
from sklearn. metrics import mean_squared_error技术支持
接着生成非线性合成数据。我们创建一个二次关系:y = 0.5*X^2 + X + 2 + 噪声。
np. random. seed( 42 )
num_samples = 100
X = np. sort( 10 * np. random. rand( num_samples, 1 ) - 5 , axis= 0 )
y_true = 0.5 * X** 2 + X + 2
y = y_true + np. random. randn( num_samples, 1 ) * 5 技术支持
现在拟合一个简单线性回归模型(欠拟合模型):
linear_model = LinearRegression( )
linear_model. fit( X, y)
y_pred_linear = linear_model. predict( X)
mse_linear = mean_squared_error( y, y_pred_linear)
print ( f"--- Simple Linear Regression (Potential Underfitting Model) ---" )
print ( f"Mean Squared Error (MSE): { mse_linear: .2f } " )
print ( f"Model Coefficients (slope): { linear_model. coef_[ 0 ] [ 0 ] : .2f } " )
print ( f"Model Intercept: { linear_model. intercept_[ 0 ] : .2f } " ) 技术支持
输出:
- - - Simple Linear Regression ( Potential Underfitting Model) - - -
Mean Squared Error ( MSE) : 34.03
Model Coefficients ( slope) : 1.00
Model Intercept: 6.42 技术支持
然后拟合一个多项式回归模型(改进模型)。为此,我们创建二次多项式特征并对其拟合线性模型。PolynomialFeatures 步骤会添加新特征,LinearRegression 则为每个特征学习系数。
对于二次项,我们预期会有 X 与 X^2 的系数。使用流水线能让流程更清晰。通过流水线的 named_steps 属性可访问各个步骤,如下:
polynomial_model = make_pipeline( PolynomialFeatures( degree= 2 , include_bias= False ) , LinearRegression( ) )
polynomial_model. fit( X, y)
y_pred_poly = polynomial_model. predict( X)
mse_poly = mean_squared_error( y, y_pred_poly)
print ( f"\n--- Polynomial Regression (Degree 2) ---" )
print ( f"Mean Squared Error (MSE): { mse_poly: .2f } " )
poly_reg_coeffs = polynomial_model. named_steps[ 'linearregression' ] . coef_[ 0 ]
poly_reg_intercept = polynomial_model. named_steps[ 'linearregression' ] . intercept_[ 0 ]
print ( f"Model Coefficients (for X, X^2): { poly_reg_coeffs[ 0 ] : .2f } , { poly_reg_coeffs[ 1 ] : .2f } " )
print ( f"Model Intercept: { poly_reg_intercept: .2f } " ) 技术支持
输出:
- - - Polynomial Regression ( Degree 2 ) - - -
Mean Squared Error ( MSE) : 20.48
Model Coefficients ( for X, X^ 2 ) : 1.13 , 0.50
Model Intercept: 2.04 技术支持
现在按如下方式可视化拟合结果:
plt. figure( figsize= ( 10 , 4 ) )
plt. scatter( X, y, s= 30 , label= "Actual Data Points" , alpha= 0.7 , edgecolors= 'k' )
plt. plot( X, y_pred_linear, color= 'red' , linewidth= 2 , label= f'Linear Fit (Underfitting)\nMSE: { mse_linear: .2f } ' )
plt. plot( X, y_pred_poly, color= 'green' , linewidth= 2 , label= f'Polynomial Fit (Degree 2)\nMSE: { mse_poly: .2f } ' )
plt. title( 'Demonstrating Underfitting with Linear vs. Polynomial Regression' , fontsize= 16 )
plt. xlabel( 'Feature X' , fontsize= 14 )
plt. ylabel( 'Target y' , fontsize= 14 )
plt. legend( fontsize= 12 )
plt. grid( True , linestyle= '--' , alpha= 0.7 )
plt. show( ) 技术支持
输出:
该图直观地验证了简单线性模型的欠拟合:它未能捕捉数据中的曲线。通过引入 X^2 项的多项式回归提供了更好的拟合,其更低的 MSE 也印证了这一点。
这表明当底层关系是非线性时,通过扩展特征(提高模型复杂度)可以降低偏差并提升精度。接下来看一个医疗诊断案例。
医疗诊断案例研究
我们使用 scikit-learn 提供的著名 Breast Cancer Wisconsin(Diagnostic)数据集,来模拟医疗诊断场景。
我们首先仅使用非常有限的特征子集来构建分类模型,这可能导致欠拟合。随后,使用更全面的特征集以及可能更复杂的算法来展示改进。
先导入必要的库:
import numpy as np
import pandas as pd
import matplotlib. pyplot as plt
from sklearn. datasets import load_breast_cancer
from sklearn. model_selection import train_test_split
from sklearn. preprocessing import StandardScaler
from sklearn. linear_model import LogisticRegression
from sklearn. ensemble import RandomForestClassifier
from sklearn. metrics import accuracy_score, roc_auc_score, confusion_matrix, ConfusionMatrixDisplay技术支持
现在加载并准备数据:
cancer = load_breast_cancer( )
X = pd. DataFrame( cancer. data, columns= cancer. feature_names)
y = cancer. target 技术支持
为了演示,在欠拟合场景下我们只选择非常有限的特征子集。这些特征单独来看可能并非最具预测力:
features_limited = [ 'mean texture' , 'mean symmetry' ]
X_limited = X[ features_limited] 技术支持
对于改进模型,我们使用更大的特征子集(或全部特征)。这里选择前 10 个特征作为更全面的集合:
features_comprehensive = cancer. feature_names[ : 10 ]
X_comprehensive = X[ features_comprehensive] 技术支持
分别对每个特征集划分数据,以便清晰对比:
X_train_lim, X_test_lim, y_train, y_test = train_test_split( X_limited, y, test_size= 0.3 , random_state= 42 , stratify= y)
X_train_comp, X_test_comp, _, _ = train_test_split( X_comprehensive, y, test_size= 0.3 , random_state= 42 , stratify= y) 技术支持
对特征做缩放,这对逻辑回归及许多算法都很重要:
scaler_lim = StandardScaler( ) . fit( X_train_lim)
X_train_lim_scaled = scaler_lim. transform( X_train_lim)
X_test_lim_scaled = scaler_lim. transform( X_test_lim)
scaler_comp = StandardScaler( ) . fit( X_train_comp)
X_train_comp_scaled = scaler_comp. transform( X_train_comp)
X_test_comp_scaled = scaler_comp. transform( X_test_comp) 技术支持
先用有限特征训练逻辑回归:
print ( "Scenario 1: Logistic Regression (Limited Features - Potential Underfitting)" )
log_reg_limited = LogisticRegression( random_state= 42 , solver= 'liblinear' )
log_reg_limited. fit( X_train_lim_scaled, y_train)
y_pred_lim = log_reg_limited. predict( X_test_lim_scaled)
y_proba_lim = log_reg_limited. predict_proba( X_test_lim_scaled) [ : , 1 ]
acc_lim = accuracy_score( y_test, y_pred_lim)
auc_lim = roc_auc_score( y_test, y_proba_lim)
print ( f"Features used: { features_limited} " )
print ( f"Accuracy: { acc_lim: .4f } " )
print ( f"AUC: { auc_lim: .4f } " ) 技术支持
输出:
Scenario 1 : Logistic Regression ( Limited Features - Potential Underfitting)
Features used: [ 'mean texture' , 'mean symmetry' ]
Accuracy: 0.7544
AUC: 0.8151 技术支持
采用缓解策略。我们用更多特征训练逻辑回归模型:
print ( "Scenario 2: Logistic Regression (Comprehensive Features)" )
log_reg_comp = LogisticRegression( random_state= 42 , solver= 'liblinear' )
log_reg_comp. fit( X_train_comp_scaled, y_train)
y_pred_comp_lr = log_reg_comp. predict( X_test_comp_scaled)
y_proba_comp_lr = log_reg_comp. predict_proba( X_test_comp_scaled) [ : , 1 ]
acc_comp_lr = accuracy_score( y_test, y_pred_comp_lr)
auc_comp_lr = roc_auc_score( y_test, y_proba_comp_lr)
print ( f"Features used: First 10 features" )
print ( f"Accuracy: { acc_comp_lr: .4f } " )
print ( f"AUC: { auc_comp_lr: .4f } " ) 技术支持
输出:
Scenario 2 : Logistic Regression ( Comprehensive Features)
Features used: First 10 features
Accuracy: 0.9181
AUC: 0.9831 技术支持
接着,在更多特征的基础上拟合更复杂的模型,如随机森林:
print ( "Scenario 3: Random Forest (Comprehensive Features)" )
rf_comp = RandomForestClassifier( random_state= 42 , n_estimators= 100 )
rf_comp. fit( X_train_comp_scaled, y_train)
y_pred_comp_rf = rf_comp. predict( X_test_comp_scaled)
y_proba_comp_rf = rf_comp. predict_proba( X_test_comp_scaled) [ : , 1 ]
acc_comp_rf = accuracy_score( y_test, y_pred_comp_rf)
auc_comp_rf = roc_auc_score( y_test, y_proba_comp_rf)
print ( f"Features used: First 10 features" )
print ( f"Accuracy: { acc_comp_rf: .4f } " )
print ( f"AUC: { auc_comp_rf: .4f } " ) 技术支持
输出:
Scenario 3 : Random Forest ( Comprehensive Features)
Features used: First 10 features
Accuracy: 0.9415
AUC: 0.9878 技术支持
最后,绘制并比较各情境的混淆矩阵:
fig, axes = plt. subplots( 1 , 3 , figsize= ( 20 , 5 ) )
fig. suptitle( 'Comparison of Model Performance (Confusion Matrices on Test Set)' , fontsize= 16 )
cm_lim = confusion_matrix( y_test, y_pred_lim)
disp_lim = ConfusionMatrixDisplay( confusion_matrix= cm_lim, display_labels= cancer. target_names)
disp_lim. plot( ax= axes[ 0 ] , cmap= 'Blues' )
axes[ 0 ] . set_title( f'LogReg (Limited Features)\nAcc: { acc_lim: .2f } , AUC: { auc_lim: .2f } ' )
cm_comp_lr = confusion_matrix( y_test, y_pred_comp_lr)
disp_comp_lr = ConfusionMatrixDisplay( confusion_matrix= cm_comp_lr, display_labels= cancer. target_names)
disp_comp_lr. plot( ax= axes[ 1 ] , cmap= 'Greens' )
axes[ 1 ] . set_title( f'LogReg (Comprehensive Features)\nAcc: { acc_comp_lr: .2f } , AUC: { auc_comp_lr: .2f } ' )
cm_comp_rf = confusion_matrix( y_test, y_pred_comp_rf)
disp_comp_rf = ConfusionMatrixDisplay( confusion_matrix= cm_comp_rf, display_labels= cancer. target_names)
disp_comp_rf. plot( ax= axes[ 2 ] , cmap= 'Oranges' )
axes[ 2 ] . set_title( f'Random Forest (Comprehensive Features)\nAcc: { acc_comp_rf: .2f } , AUC: { auc_comp_rf: .2f } ' )
plt. tight_layout( rect= [ 0 , 0 , 1 , 0.96 ] )
plt. show( ) 技术支持
输出:
在此案例中,仅使用两个特征训练的 LogisticRegression(情境 1)预期会因信息不足而欠拟合,导致较差的准确率与 AUC。
当使用更全面的特征集、但保持相同算法时(情境 2),通常性能会提升,因为模型可学习的信息更多,从而降低偏差。
进一步的改进常见于使用更复杂的算法,如在全面特征集上训练 RandomForestClassifier(情境 3),因为它更有效地捕捉非线性与特征交互,进一步降低偏差并提升对数据的拟合。
前沿主题与未来方向
尽管我们已覆盖基础知识,但机器学习领域始终在演进。以下简要介绍欠拟合与更前沿领域的关联。
深度学习的角色
深度学习模型,尤其是拥有多层的深度神经网络,具有很高的容量,理论上能逼近非常复杂的函数。
得益于其复杂性,只要训练充分且数据充足,深度学习模型通常较不易欠拟合。它们的结构能从原始数据(如图像像素或文本词语)中自动学习复杂的特征表征。
然而,深度学习也并非对看似欠拟合的问题免疫。如果网络设计不佳(如深度/宽度不足)、训练不够长,或使用了不合适的激活函数或优化算法,它仍可能无法收敛并表现出高训练误差。
诸如残差连接(ResNet)与归一化技术(批量归一化)等架构创新,帮助有效训练非常深的网络,缓解梯度消失/爆炸问题,使其发挥全部容量,从而避免类似欠拟合的收敛问题。
自动化机器学习(AutoML)
为避免欠拟合与过拟合而寻找合适的模型、特征与超参数,可能十分耗时。AutoML 致力于自动化这一过程。
AutoML 框架可自动探索不同模型类型(从线性模型到复杂集成与神经网络)、执行特征工程与选择,并优化超参数。通过系统地搜索庞大的可能空间,AutoML 能识别出具备足够复杂度、避免对数据欠拟合的模型配置。
诸如神经架构搜索(NAS)的方法可自动设计网络结构,而贝叶斯优化等先进的超参数优化技术能高效找到良好的超参数设置。这些工具可显著加速找到良好拟合模型的过程,减少诊断与修复欠拟合所需的人工投入。
结论
理解欠拟合与过拟合的权衡是成功开展机器学习的基础。我们看到,欠拟合源于模型过于简单(高偏差),无法捕捉数据底层趋势,导致在训练数据与未见数据上皆表现不佳。关键成因包括模型复杂度不足、特征不佳、训练不足与正则化过强。
诊断欠拟合需要检视性能指标、绘制学习曲线并进行模型对比,往往辅以代码支持。幸运的是,修复欠拟合的策略有很多:提高模型复杂度(更优算法、特征扩展、超参数调优)、改进特征(特征工程、数据充实)、调整正则化,以及采用强大的集成方法,正如我们的代码示例所示。
想通过动手示例学习这些技术及更多内容,请查看我们的 Python 机器学习基础技能路径 。
在我们构建模型以预测结果或发现模式的过程中,会遇到各种挑战。其中一个常见难题是创建一个能够准确捕捉数据底层趋势的模型。有时,模型过于简单,无法学到其中的复杂性,导致表现不佳。这种现象被称为欠拟合(Underfitting)。
欠拟合模型不仅在其训练数据上表现不佳,也无法泛化到新的、未见过的数据上。这意味着在真实场景中的预测可能不可靠。识别并解决欠拟合,是构建健壮且有效的机器学习模型的重要一步。
图片作者自制
在本文中,我们将探讨什么是欠拟合、为何会发生、如何识别,最重要的是,如何修复欠拟合。如果您希望动手实践机器学习,欢迎查看我们的Python 机器学习基础学习路径。
什么是欠拟合?
让我们更深入地理解欠拟合这一概念,并与其对应的过拟合加以对比。理解这一区别对模型诊断与改进至关重要。
图片作者自制
简而言之,当机器学习模型过于简单,无法捕捉训练数据中的底层模式时,就会发生欠拟合。想象用一条直线去拟合明显呈曲线分布的数据点,而这条线(我们的模型)不够复杂。欠拟合模型具有高偏差(high bias),这意味着它对数据做出了强假设(例如在不存在的情况下假设线性关系)。
由于它无法很好地学习数据,它不仅在训练数据上表现糟糕,在新的未见数据(测试数据)上同样表现不佳。不过,这类模型通常方差较低,即当在不同的数据子集上训练时,其预测变化不大。简单性让它们一致,但往往是一致地错误。
从数学上,这与模型期望误差的偏差-方差分解有关。模型的期望误差可分解为三个部分:偏差平方、方差和不可约误差:
其中:
E[(y - f̂(x))²]是预测的期望平方误差。Bias(f̂(x))衡量用模型近似真实函数f(x)所引入的误差。Var(f̂(x))是针对不同训练数据集时模型预测的变动性。σ²表示不可约误差——数据中固有的、无法被预测的噪声。在欠拟合中,
Bias(f̂(x))项主导误差。模型过于简单,导致系统性误差,无法捕捉真实的数据关系。欠拟合与过拟合的对比
将欠拟合与过拟合进行比较,有助于更清楚地理解欠拟合。欠拟合模型过于简单,而过拟合模型则过于复杂。它们对训练数据学得太好,不仅捕捉了底层模式,也把噪声和随机波动一并学了进去。
偏差-方差权衡——图片作者自制
下面来看欠拟合与过拟合的关键差异:
特征
欠拟合
过拟合
训练误差
高
很低
测试误差
高
高
模型复杂度
低
高
预测行为
一致但不准确
对训练数据准确,对新数据表现差
这引出了一个关键概念:偏差-方差权衡。
目标是找到一个“甜蜜点”:模型足够复杂以捕捉真实模式(低偏差),但又不过分复杂以至于学习到噪声(低方差)。
示例:
了解您的模型位于这一谱系的何处,对于开发有效的机器学习方案非常重要。接下来我们将介绍如何检测并处理欠拟合。
欠拟合的成因与诊断指标
既然我们已经理解了什么是欠拟合,接下来看看它为何发生,以及如何在您的项目中检测它。找准根因对于选择正确的缓解策略至关重要。
欠拟合的主要原因
多种因素都可能导致欠拟合模型:
模型复杂度不足
所选算法可能对数据的底层结构而言过于简单。例如,当特征与目标变量之间存在显著非线性关系时却使用线性回归。模型本身缺乏捕捉复杂性的能力。
训练不足
模型的训练时间可能不够(例如神经网络的 epoch 过少),或学习参数设置不当。如果训练过早停止,即便模型有能力,它也没有足够机会学习模式。
特征表征不佳
用于训练模型的特征可能无法充分代表影响目标变量的底层因素,这可能意味着:
正则化过强
正则化技术(如 L1 或 L2 惩罚)主要用于通过对复杂度加罚来防止过拟合。但如果正则化强度(例如 lambda 参数)设置过高,会对模型过度约束,迫使其过于简单,从而导致欠拟合。关于正则化的更多内容,参见走向防止过拟合:正则化。
数据质量低或数量不足
检测方法
如何判断模型是否欠拟合?以下是一些常见诊断技巧:
分析性能指标
最直接的信号是训练集与验证/测试集上均表现不佳。如果模型在其训练数据上就已高误差(或低准确率、低 R² 等),这强烈表明它尚未有效学习模式。与过拟合(训练表现极佳、测试表现差)不同,欠拟合在各数据集上都表现不佳。
学习曲线
绘制模型在训练集和验证集上的性能(例如误差或准确率)随训练时间或数据规模变化的曲线,往往很有启发意义。对欠拟合模型,学习曲线通常表现为:
特征分析
回顾已用特征:它们是否相关?是否存在未捕捉的交互?数值特征是否已缩放?类别特征是否恰当编码?
有时,重新审视特征工程就能揭示模型为何挣扎。基础概念可参考R 语言机器学习基础。若想深入理解统计关系,可参考R 语言统计推断等资源。
对比建模
在相同数据上训练一个更复杂的模型(例如当初使用线性回归时,尝试决策树或梯度提升机)。如果更复杂的模型在训练与验证集上都显著优于最初模型,说明原模型很可能由于复杂度不足而欠拟合。
您可以使用机器学习实验入门:Weights & Biases中提到的工具来跟踪此类对比。
通过理解这些成因与检测方法,您可以有效诊断欠拟合模型,并采取措施提升其性能。
欠拟合的缓解策略与最佳实践
一旦确认存在欠拟合,下一步就是知道如何修复欠拟合。幸运的是,有多种有效策略可提升模型对数据底层模式的学习能力。下面来看几种方法:
提升模型复杂度
如果您的模型过于简单(高偏差),提高其复杂度常能缓解欠拟合。可以通过以下方式实现:
算法选择
切换到更强大的模型。如果线性回归欠拟合,可尝试多项式回归、决策树、随机森林、梯度提升(如XGBoost 或 LightGBM),或使用带非线性核的支持向量机(SVM)。这些模型天生具备更强的捕捉复杂关系的能力。
多项式特征扩展
对于回归问题,您可以从现有数值特征创建多项式特征,这使线性模型能拟合更复杂的曲线关系。例如,对于特征 x,可添加 x2、x3 等新特征。Scikit-learn 提供了
PolynomialFeatures用于此目的。超参数调优
许多复杂模型拥有控制其复杂度的超参数(例如决策树的深度、神经网络层的神经元数、SVM 的 C 参数)。通过调大这些超参数以允许更高复杂度,可以降低偏差。
网格搜索或随机搜索等技术在此非常关键。可通过课程Python 超参数调优或R 超参数调优了解更多。另见我们的教程机器学习模型的超参数优化。
特征工程与数据增强
有时问题不在模型,而在数据表征。改进特征能带来显著帮助。可通过以下方式实现:
面向领域的特征构造
利用您对问题领域的理解创建更具信息量的新特征。例如预测房价时,将“卧室数量”和“浴室数量”合并为“总房间数”,或由“建成年份”计算“房龄”。
交互特征
创建表示现有特征间交互的新特征(如将两个特征相乘)。这有助于模型捕捉协同效应。
数据充实
如有可能,用外部数据源增强数据集。例如在客户信息中加入人口统计数据,或在销量预测中加入天气数据。
数据增强(主要用于非结构化数据)
对于图像或文本数据,可以通过图像旋转/翻转、文本同义词替换等方法,人工增加训练集的规模与多样性,帮助模型学习更稳健的模式。
调整正则化
如果欠拟合是由旨在防止过拟合的过强正则化引起,需要适当降低其强度。降低正则化参数(如 Ridge/Lasso 中的 alpha,SVM 中的 C——注意对 SVM 而言,更小的 C 表示更强正则化,因此应增大 C)。
若使用 dropout,降低 dropout 率(训练中被丢弃的神经元比例)。较低的比例能保留更多网络容量。
找到合适平衡常需仔细调参,这也再次凸显超参数优化的重要性。
集成方法
集成方法将多个个体模型(弱学习器)的预测进行组合,以产生更强大、更稳健的最终预测。它们常常能有效降低偏差与方差。部分集成方法包括:
通过应用这些策略(常常是组合使用),您可以有效应对欠拟合,构建更能捕捉数据复杂性的模型。
实践应用与案例研究
借助数据集与代码直观地观察欠拟合,可以显著加深理解。下面通过实践示例展示欠拟合模型的表现,以及如何改进其性能。
线性回归欠拟合示例
当用简单线性模型描述非线性关系时,常会出现欠拟合。我们用一个服从二次模式的数据,尝试拟合线性回归模型来说明这一点。
我们将生成一个合成数据,使目标变量y 与特征X 呈二次关系。首先拟合一个简单线性回归模型,观察其糟糕表现(高均方误差 MSE),并可视化其如何未能捕捉数据曲线。
随后,我们通过添加多项式项来扩展特征,并拟合一个多项式回归模型。这将展示如何通过增加模型复杂度来降低偏差,并显著提升模型精度。
首先导入所需库:
接着生成非线性合成数据。我们创建一个二次关系:y = 0.5*X^2 + X + 2 + 噪声。
现在拟合一个简单线性回归模型(欠拟合模型):
输出:
然后拟合一个多项式回归模型(改进模型)。为此,我们创建二次多项式特征并对其拟合线性模型。
PolynomialFeatures步骤会添加新特征,LinearRegression则为每个特征学习系数。对于二次项,我们预期会有 X 与 X^2 的系数。使用流水线能让流程更清晰。通过流水线的
named_steps属性可访问各个步骤,如下:输出:
现在按如下方式可视化拟合结果:
输出:
该图直观地验证了简单线性模型的欠拟合:它未能捕捉数据中的曲线。通过引入 X^2 项的多项式回归提供了更好的拟合,其更低的 MSE 也印证了这一点。
这表明当底层关系是非线性时,通过扩展特征(提高模型复杂度)可以降低偏差并提升精度。接下来看一个医疗诊断案例。
医疗诊断案例研究
我们使用
scikit-learn提供的著名 Breast Cancer Wisconsin(Diagnostic)数据集,来模拟医疗诊断场景。我们首先仅使用非常有限的特征子集来构建分类模型,这可能导致欠拟合。随后,使用更全面的特征集以及可能更复杂的算法来展示改进。
先导入必要的库:
现在加载并准备数据:
为了演示,在欠拟合场景下我们只选择非常有限的特征子集。这些特征单独来看可能并非最具预测力:
对于改进模型,我们使用更大的特征子集(或全部特征)。这里选择前 10 个特征作为更全面的集合:
分别对每个特征集划分数据,以便清晰对比:
对特征做缩放,这对逻辑回归及许多算法都很重要:
先用有限特征训练逻辑回归:
输出:
采用缓解策略。我们用更多特征训练逻辑回归模型:
输出:
接着,在更多特征的基础上拟合更复杂的模型,如随机森林:
输出:
最后,绘制并比较各情境的混淆矩阵:
输出:
在此案例中,仅使用两个特征训练的
LogisticRegression(情境 1)预期会因信息不足而欠拟合,导致较差的准确率与 AUC。当使用更全面的特征集、但保持相同算法时(情境 2),通常性能会提升,因为模型可学习的信息更多,从而降低偏差。
进一步的改进常见于使用更复杂的算法,如在全面特征集上训练
RandomForestClassifier(情境 3),因为它更有效地捕捉非线性与特征交互,进一步降低偏差并提升对数据的拟合。前沿主题与未来方向
尽管我们已覆盖基础知识,但机器学习领域始终在演进。以下简要介绍欠拟合与更前沿领域的关联。
深度学习的角色
深度学习模型,尤其是拥有多层的深度神经网络,具有很高的容量,理论上能逼近非常复杂的函数。
得益于其复杂性,只要训练充分且数据充足,深度学习模型通常较不易欠拟合。它们的结构能从原始数据(如图像像素或文本词语)中自动学习复杂的特征表征。
然而,深度学习也并非对看似欠拟合的问题免疫。如果网络设计不佳(如深度/宽度不足)、训练不够长,或使用了不合适的激活函数或优化算法,它仍可能无法收敛并表现出高训练误差。
诸如残差连接(ResNet)与归一化技术(批量归一化)等架构创新,帮助有效训练非常深的网络,缓解梯度消失/爆炸问题,使其发挥全部容量,从而避免类似欠拟合的收敛问题。
自动化机器学习(AutoML)
为避免欠拟合与过拟合而寻找合适的模型、特征与超参数,可能十分耗时。AutoML 致力于自动化这一过程。
AutoML 框架可自动探索不同模型类型(从线性模型到复杂集成与神经网络)、执行特征工程与选择,并优化超参数。通过系统地搜索庞大的可能空间,AutoML 能识别出具备足够复杂度、避免对数据欠拟合的模型配置。
诸如神经架构搜索(NAS)的方法可自动设计网络结构,而贝叶斯优化等先进的超参数优化技术能高效找到良好的超参数设置。这些工具可显著加速找到良好拟合模型的过程,减少诊断与修复欠拟合所需的人工投入。
结论
理解欠拟合与过拟合的权衡是成功开展机器学习的基础。我们看到,欠拟合源于模型过于简单(高偏差),无法捕捉数据底层趋势,导致在训练数据与未见数据上皆表现不佳。关键成因包括模型复杂度不足、特征不佳、训练不足与正则化过强。
诊断欠拟合需要检视性能指标、绘制学习曲线并进行模型对比,往往辅以代码支持。幸运的是,修复欠拟合的策略有很多:提高模型复杂度(更优算法、特征扩展、超参数调优)、改进特征(特征工程、数据充实)、调整正则化,以及采用强大的集成方法,正如我们的代码示例所示。
想通过动手示例学习这些技术及更多内容,请查看我们的Python 机器学习基础技能路径。