
不知道大家有没有过类似的经历,在很多针对数据类处理的项目中,我们常常遇到这样的困境,模型在训练数据上表现不佳,或者相反,在训练数据上表现完美却在真实场景中一败涂地。这些问题的根源往往在于模型拟合的两种极端状态—欠拟合和过拟合。
首先了解,什么是拟合,拟合是指将一个模型或函数与实际数据相匹配,以得到一个能够描述或预测这些数据的最佳模型或函数。通俗的讲,想象一下你正在学习一门新课程:

1. 基本概念
MSE(均方误差) 是机器学习中最常用的回归问题评估指标,用于衡量模型预测值与真实值之间的差异程度。
2. 计算公式
MSE = (1/n) × Σ(预测值 - 真实值)²
其中:
3. 核心特点
3.1 优点:
3.2 缺点:
4. 实际意义
5. 在拟合问题中的应用
MSE就像模型的"成绩单",数值直接反映了预测的精准程度,是模型优化过程中最重要的指导指标之一。
定义:模型过于简单,无法捕捉数据中的基本模式和规律,导致在训练数据和测试数据上都表现不佳。
直观理解:就像用直尺去测量弯曲的线条,总是存在很大的误差。
1.1 训练集表现差
1.2 测试集同样糟糕
1.3 学习曲线特征
2.1 模型复杂度不足
2.2 特征工程不充分
2.3 训练不充分
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成示例数据
np.random.seed(42)
X = np.linspace(0, 10, 100).reshape(-1, 1)
y_true = 2 * np.sin(X.ravel()) + 0.5 * X.ravel() # 真实关系
y_noisy = y_true + np.random.normal(0, 0.5, 100) # 添加噪声
# 使用过于简单的模型(线性回归)拟合非线性数据
linear_model = LinearRegression()
linear_model.fit(X, y_noisy)
y_pred_linear = linear_model.predict(X)
plt.figure(figsize=(12, 5))
plt.scatter(X, y_noisy, alpha=0.6, label='观测数据')
plt.plot(X, y_true, 'g-', linewidth=2, label='真实关系')
plt.plot(X, y_pred_linear, 'r-', linewidth=2, label='线性模型预测')
plt.title('欠拟合示例:线性模型无法捕捉非线性关系')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"线性模型训练MSE: {mean_squared_error(y_noisy, y_pred_linear):.4f}")线性模型训练MSE: 1.9636

这张图展示了欠拟合的典型特征:
3.2.1.1 散点图(观测数据)
3.2.1.2 绿色曲线(真实关系)
3.2.1.3 红色直线(线性模型预测)
3.2.2.1 形态差异
3.2.2.2 拟合质量
3.2.3.1 模型假设与数据本质的冲突
3.2.3.2 模型复杂度不足
3.2.3.3 偏差-方差分解角度
3.2.3.4 线性模型的局限性
错误方法(当前使用)
# 欠拟合的线性模型
model = LinearRegression() # 过于简单正确方法示例
# 方法1:多项式回归
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
poly_model = Pipeline([
('poly', PolynomialFeatures(degree=4)), # 增加复杂度
('linear', LinearRegression())
])
# 方法2:使用非线性模型
from sklearn.tree import DecisionTreeRegressor
tree_model = DecisionTreeRegressor(max_depth=5)
# 方法3:添加正弦特征
X_enhanced = np.column_stack([X, np.sin(X), np.cos(X)])
enhanced_model = LinearRegression()3.3.2.1 改进代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error, r2_score
import warnings
warnings.filterwarnings('ignore')
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成示例数据
np.random.seed(42)
X = np.linspace(0, 10, 100).reshape(-1, 1)
y_true = 2 * np.sin(X.ravel()) + 0.5 * X.ravel() # 真实关系
y_noisy = y_true + np.random.normal(0, 0.5, 100) # 添加噪声
print("=" * 70)
print("原始线性模型(欠拟合)")
print("=" * 70)
# 使用过于简单的模型(线性回归)拟合非线性数据
linear_model = LinearRegression()
linear_model.fit(X, y_noisy)
y_pred_linear = linear_model.predict(X)
# 计算性能指标
linear_mse = mean_squared_error(y_noisy, y_pred_linear)
linear_r2 = r2_score(y_noisy, y_pred_linear)
plt.figure(figsize=(12, 5))
plt.scatter(X, y_noisy, alpha=0.6, label='观测数据')
plt.plot(X, y_true, 'g-', linewidth=2, label='真实关系')
plt.plot(X, y_pred_linear, 'r-', linewidth=2, label='线性模型预测')
plt.title(f'欠拟合示例:线性模型无法捕捉非线性关系\nMSE: {linear_mse:.4f}, R²: {linear_r2:.4f}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"线性模型训练MSE: {linear_mse:.4f}")
print(f"线性模型R²分数: {linear_r2:.4f}")
print()
# ============================================================================
# 方法1:多项式回归
# ============================================================================
print("=" * 70)
print("方法1: 多项式回归")
print("=" * 70)
# 创建多项式回归模型
poly_model = Pipeline([
('poly', PolynomialFeatures(degree=4)), # 4次多项式,增加复杂度
('linear', LinearRegression())
])
poly_model.fit(X, y_noisy)
y_pred_poly = poly_model.predict(X)
# 计算性能指标
poly_mse = mean_squared_error(y_noisy, y_pred_poly)
poly_r2 = r2_score(y_noisy, y_pred_poly)
# 生成平滑曲线用于更好的可视化
X_smooth = np.linspace(0, 10, 300).reshape(-1, 1)
y_smooth_poly = poly_model.predict(X_smooth)
plt.figure(figsize=(12, 5))
plt.scatter(X, y_noisy, alpha=0.6, label='观测数据')
plt.plot(X, y_true, 'g-', linewidth=2, label='真实关系')
plt.plot(X_smooth, y_smooth_poly, 'r-', linewidth=2, label='4次多项式预测')
plt.title(f'多项式回归改进\nMSE: {poly_mse:.4f}, R²: {poly_r2:.4f}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"多项式回归MSE: {poly_mse:.4f} (改进: {((linear_mse - poly_mse) / linear_mse * 100):.1f}%)")
print(f"多项式回归R²分数: {poly_r2:.4f}")
print()
# ============================================================================
# 方法2:决策树回归
# ============================================================================
print("=" * 70)
print("方法2: 决策树回归")
print("=" * 70)
# 创建决策树模型
tree_model = DecisionTreeRegressor(max_depth=5, random_state=42)
tree_model.fit(X, y_noisy)
y_pred_tree = tree_model.predict(X)
# 计算性能指标
tree_mse = mean_squared_error(y_noisy, y_pred_tree)
tree_r2 = r2_score(y_noisy, y_pred_tree)
# 生成平滑曲线
y_smooth_tree = tree_model.predict(X_smooth)
plt.figure(figsize=(12, 5))
plt.scatter(X, y_noisy, alpha=0.6, label='观测数据')
plt.plot(X, y_true, 'g-', linewidth=2, label='真实关系')
plt.plot(X_smooth, y_smooth_tree, 'r-', linewidth=2, label='决策树预测 (max_depth=5)')
plt.title(f'决策树回归改进\nMSE: {tree_mse:.4f}, R²: {tree_r2:.4f}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"决策树回归MSE: {tree_mse:.4f} (改进: {((linear_mse - tree_mse) / linear_mse * 100):.1f}%)")
print(f"决策树回归R²分数: {tree_r2:.4f}")
print()
# ============================================================================
# 方法3:添加正弦特征的线性回归
# ============================================================================
print("=" * 70)
print("方法3: 特征工程 - 添加三角函数特征")
print("=" * 70)
# 添加正弦和余弦特征
X_enhanced = np.column_stack([X, np.sin(X), np.cos(X)])
enhanced_model = LinearRegression()
enhanced_model.fit(X_enhanced, y_noisy)
y_pred_enhanced = enhanced_model.predict(X_enhanced)
# 计算性能指标
enhanced_mse = mean_squared_error(y_noisy, y_pred_enhanced)
enhanced_r2 = r2_score(y_noisy, y_pred_enhanced)
# 生成平滑曲线
X_smooth_enhanced = np.column_stack([X_smooth, np.sin(X_smooth), np.cos(X_smooth)])
y_smooth_enhanced = enhanced_model.predict(X_smooth_enhanced)
plt.figure(figsize=(12, 5))
plt.scatter(X, y_noisy, alpha=0.6, label='观测数据')
plt.plot(X, y_true, 'g-', linewidth=2, label='真实关系')
plt.plot(X_smooth, y_smooth_enhanced, 'r-', linewidth=2, label='增强特征线性回归预测')
plt.title(f'特征工程改进\nMSE: {enhanced_mse:.4f}, R²: {enhanced_r2:.4f}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"增强特征线性回归MSE: {enhanced_mse:.4f} (改进: {((linear_mse - enhanced_mse) / linear_mse * 100):.1f}%)")
print(f"增强特征线性回归R²分数: {enhanced_r2:.4f}")
print()
# ============================================================================
# 综合对比
# ============================================================================
print("=" * 70)
print("所有方法性能对比")
print("=" * 70)
methods = {
'线性回归 (欠拟合)': linear_mse,
'4次多项式回归': poly_mse,
'决策树回归': tree_mse,
'增强特征线性回归': enhanced_mse
}
# 按MSE排序
sorted_methods = sorted(methods.items(), key=lambda x: x[1])
print("按MSE从低到高排序:")
print("-" * 50)
for name, mse in sorted_methods:
improvement = ((linear_mse - mse) / linear_mse * 100)
print(f"{name:<25}: MSE = {mse:.4f} | 改进 = {improvement:>6.1f}%")
# 绘制所有方法的对比图
plt.figure(figsize=(15, 10))
# 准备预测曲线
predictions = {
'真实关系': (X_smooth, 2 * np.sin(X_smooth.ravel()) + 0.5 * X_smooth.ravel(), 'g-'),
'线性回归': (X_smooth, linear_model.predict(X_smooth), 'r-'),
'4次多项式': (X_smooth, y_smooth_poly, 'b-'),
'决策树': (X_smooth, y_smooth_tree, 'orange'),
'增强特征': (X_smooth, y_smooth_enhanced, 'purple')
}
colors = ['red', 'blue', 'orange', 'purple']
models_names = ['线性回归', '4次多项式', '决策树', '增强特征']
plt.subplot(2, 1, 1)
plt.scatter(X, y_noisy, alpha=0.3, color='gray', label='观测数据')
for i, (name, (x_vals, y_vals, style)) in enumerate(predictions.items()):
if name != '真实关系':
plt.plot(x_vals, y_vals, color=colors[i-1], linewidth=2, label=name)
plt.plot(X_smooth, predictions['真实关系'][1], 'g-', linewidth=3, label='真实关系')
plt.title('所有方法预测曲线对比')
plt.legend()
plt.grid(True, alpha=0.3)
plt.subplot(2, 1, 2)
# 绘制性能对比条形图
names = list(methods.keys())
mses = list(methods.values())
colors_bar = ['red', 'blue', 'orange', 'purple']
bars = plt.bar(names, mses, color=colors_bar, alpha=0.7)
plt.title('各方法MSE对比')
plt.ylabel('均方误差 (MSE)')
plt.xticks(rotation=45)
# 在条形图上添加数值标签
for bar, mse in zip(bars, mses):
plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.01,
f'{mse:.4f}', ha='center', va='bottom')
plt.tight_layout()
plt.show()3.3.2.2 输出结果
===================================================================== 原始线性模型(欠拟合) ===================================================================== 线性模型训练MSE: 1.9636 线性模型R²分数: 0.4913 ===================================================================== 方法1: 多项式回归 ===================================================================== 多项式回归MSE: 0.3658 (改进: 81.4%) 多项式回归R²分数: 0.9052 ===================================================================== 方法2: 决策树回归 ===================================================================== 决策树回归MSE: 0.1023 (改进: 94.8%) 决策树回归R²分数: 0.9735 ===================================================================== 方法3: 特征工程 - 添加三角函数特征 ===================================================================== 增强特征线性回归MSE: 0.1966 (改进: 90.0%) 增强特征线性回归R²分数: 0.9491 ===================================================================== 方法4: 随机森林回归 ===================================================================== 随机森林回归MSE: 0.1056 (改进: 94.6%) 随机森林回归R²分数: 0.9727 ===================================================================== 所有方法性能对比 ===================================================================== -------------------------------------------------- 决策树回归 : MSE = 0.1023 | 改进 = 94.8% 随机森林回归 : MSE = 0.1056 | 改进 = 94.6% 增强特征线性回归 : MSE = 0.1966 | 改进 = 90.0% 4次多项式回归 : MSE = 0.3658 | 改进 = 81.4% 线性回归 (欠拟合) : MSE = 1.9636 | 改进 = 0.0%
方法1:多项式回归改进

关键改进原理:
改进效果说明:
方法2:决策树回归改进

关键改进原理:
# 原理:通过树结构学习分段常数函数
if x < 2.5:
if x < 1.2:
y = 值1
else:
y = 值2
else:
# 更多分支...改进效果说明:
方法3:特征工程改进

关键改进原理:
改进效果说明:
所有方法性能对比

通过这三种方法,我们成功地将欠拟合模型的MSE从1.84降低到0.05-0.12的范围,改进幅度达到88%-97%。这证明了:
修复欠拟合的关键要点总结
这个例子提醒我们,在模型处理中,选择与数据特性匹配的模型是成功的第一步。盲目使用简单模型处理复杂问题,必然导致欠拟合和性能损失。
定义:模型过于复杂,过度学习了训练数据中的噪声和细节,导致在训练数据上表现很好,但在新数据上泛化能力差。
直观理解:就像死记硬背考试答案,遇到原题能得高分,但题目稍作变化就不会做了。
1.1 训练集表现极好
1.2 测试集表现差
1.3 学习曲线特征
2.1 模型复杂度过高
2.2 训练数据不足
2.3 缺乏正则化
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成示例数据
np.random.seed(42)
X = np.linspace(0, 10, 100).reshape(-1, 1)
y_true = 2 * np.sin(X.ravel()) + 0.5 * X.ravel() # 真实关系
y_noisy = y_true + np.random.normal(0, 0.5, 100) # 添加噪声
# 使用过于复杂的模型(深度决策树)拟合数据
deep_tree = DecisionTreeRegressor(max_depth=20, random_state=42)
deep_tree.fit(X, y_noisy)
y_pred_tree = deep_tree.predict(X)
plt.figure(figsize=(12, 5))
plt.scatter(X, y_noisy, alpha=0.6, label='观测数据')
plt.plot(X, y_true, 'g-', linewidth=2, label='真实关系')
plt.plot(X, y_pred_tree, 'r-', linewidth=2, label='深度决策树预测')
plt.title('过拟合示例:模型过度拟合噪声')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"深度决策树训练MSE: {mean_squared_error(y_noisy, y_pred_tree):.4f}")深度决策树训练MSE: 0.0000

这张图片展示了过拟合的典型特征:
3.2.1.1 散点图(观测数据)
3.2.1.2 绿色曲线(真实关系)
3.2.1.3 红色曲线(深度决策树预测)
3.2.2.1 拟合程度
3.2.2.2 曲线平滑度
3.2.2.3 局部vs全局模式
3.2.3.1 模型复杂度过高
# 问题代码:过度复杂的模型
deep_tree = DecisionTreeRegressor(max_depth=20, random_state=42)
# 参数分析:
# - max_depth=20:树深度极大
# - 100个数据点,深度20意味着极端细分
# - 每个叶节点可能只包含1-2个样本3.2.3.2 决策树的工作原理导致
决策树通过不断分裂来拟合数据
3.2.3.3 偏差-方差分解角度
3.2.3.4 训练误差与泛化误差的差距
方法1:限制模型复杂度
# 修复:适当限制树深度
proper_tree = DecisionTreeRegressor(max_depth=5, random_state=42)方法2:增加正则化
# 决策树的正则化参数
good_tree = DecisionTreeRegressor(
max_depth=5,
min_samples_split=10, # 节点最少样本数
min_samples_leaf=5, # 叶节点最少样本数
random_state=42
)方法3:使用集成方法
# 随机森林通过平均减少过拟合
from sklearn.ensemble import RandomForestRegressor
forest = RandomForestRegressor(
n_estimators=100,
max_depth=5,
random_state=42
)方法4:增加数据量
# 如果可能,收集更多数据
# 更多数据可以约束复杂模型
X_large = np.linspace(0, 10, 1000).reshape(-1, 1)
y_large = 2 * np.sin(X_large.ravel()) + 0.5 * X_large.ravel() + np.random.normal(0, 0.5, 1000)3.3.2.1 改进代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成示例数据
np.random.seed(42)
X = np.linspace(0, 10, 100).reshape(-1, 1)
y_true = 2 * np.sin(X.ravel()) + 0.5 * X.ravel() # 真实关系
y_noisy = y_true + np.random.normal(0, 0.5, 100) # 添加噪声
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y_noisy, test_size=0.3, random_state=42)
print("=" * 70)
print("原始过拟合模型(深度决策树)")
print("=" * 70)
# 使用过于复杂的模型(深度决策树)拟合数据
deep_tree = DecisionTreeRegressor(max_depth=20, random_state=42)
deep_tree.fit(X_train, y_train)
y_pred_train = deep_tree.predict(X_train)
y_pred_test = deep_tree.predict(X_test)
# 计算性能指标
train_mse_deep = mean_squared_error(y_train, y_pred_train)
test_mse_deep = mean_squared_error(y_test, y_pred_test)
train_r2_deep = r2_score(y_train, y_pred_train)
test_r2_deep = r2_score(y_test, y_pred_test)
# 生成平滑曲线用于可视化
X_smooth = np.linspace(0, 10, 300).reshape(-1, 1)
y_smooth_deep = deep_tree.predict(X_smooth)
plt.figure(figsize=(12, 5))
plt.scatter(X_train, y_train, color='blue', alpha=0.6, label='训练数据')
plt.scatter(X_test, y_test, color='red', alpha=0.6, label='测试数据')
plt.plot(X_smooth, 2 * np.sin(X_smooth.ravel()) + 0.5 * X_smooth.ravel(),
'g-', linewidth=2, label='真实关系')
plt.plot(X_smooth, y_smooth_deep, 'r-', linewidth=2, label='深度决策树预测')
plt.title(f'过拟合示例:模型过度拟合噪声\n训练MSE: {train_mse_deep:.4f}, 测试MSE: {test_mse_deep:.4f}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"深度决策树训练MSE: {train_mse_deep:.4f}")
print(f"深度决策树测试MSE: {test_mse_deep:.4f}")
print(f"深度决策树训练R²: {train_r2_deep:.4f}")
print(f"深度决策树测试R²: {test_r2_deep:.4f}")
print(f"泛化差距: {test_mse_deep - train_mse_deep:.4f}")
print()
# ============================================================================
# 方法1:限制模型复杂度(减小树深度)
# ============================================================================
print("=" * 70)
print("方法1: 限制模型复杂度")
print("=" * 70)
# 创建适当深度的决策树
proper_tree = DecisionTreeRegressor(max_depth=5, random_state=42)
proper_tree.fit(X_train, y_train)
y_pred_train_proper = proper_tree.predict(X_train)
y_pred_test_proper = proper_tree.predict(X_test)
# 计算性能指标
train_mse_proper = mean_squared_error(y_train, y_pred_train_proper)
test_mse_proper = mean_squared_error(y_test, y_pred_test_proper)
train_r2_proper = r2_score(y_train, y_pred_train_proper)
test_r2_proper = r2_score(y_test, y_pred_test_proper)
# 生成平滑曲线
y_smooth_proper = proper_tree.predict(X_smooth)
plt.figure(figsize=(12, 5))
plt.scatter(X_train, y_train, color='blue', alpha=0.6, label='训练数据')
plt.scatter(X_test, y_test, color='red', alpha=0.6, label='测试数据')
plt.plot(X_smooth, 2 * np.sin(X_smooth.ravel()) + 0.5 * X_smooth.ravel(),
'g-', linewidth=2, label='真实关系')
plt.plot(X_smooth, y_smooth_proper, 'r-', linewidth=2, label='适当深度决策树预测 (max_depth=5)')
plt.title(f'限制复杂度改进\n训练MSE: {train_mse_proper:.4f}, 测试MSE: {test_mse_proper:.4f}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"适当深度决策树训练MSE: {train_mse_proper:.4f}")
print(f"适当深度决策树测试MSE: {test_mse_proper:.4f}")
print(f"适当深度决策树训练R²: {train_r2_proper:.4f}")
print(f"适当深度决策树测试R²: {test_r2_proper:.4f}")
print(f"泛化差距: {test_mse_proper - train_mse_proper:.4f}")
print(f"测试MSE改进: {((test_mse_deep - test_mse_proper) / test_mse_deep * 100):.1f}%")
print()
# ============================================================================
# 方法2:增加正则化(决策树的正则化参数)
# ============================================================================
print("=" * 70)
print("方法2: 增加正则化")
print("=" * 70)
# 创建带有正则化的决策树
regularized_tree = DecisionTreeRegressor(
max_depth=10,
min_samples_split=10, # 节点最少需要10个样本才分裂
min_samples_leaf=5, # 叶节点最少需要5个样本
max_features=0.8, # 每次分裂考虑80%的特征
random_state=42
)
regularized_tree.fit(X_train, y_train)
y_pred_train_reg = regularized_tree.predict(X_train)
y_pred_test_reg = regularized_tree.predict(X_test)
# 计算性能指标
train_mse_reg = mean_squared_error(y_train, y_pred_train_reg)
test_mse_reg = mean_squared_error(y_test, y_pred_test_reg)
train_r2_reg = r2_score(y_train, y_pred_train_reg)
test_r2_reg = r2_score(y_test, y_pred_test_reg)
# 生成平滑曲线
y_smooth_reg = regularized_tree.predict(X_smooth)
plt.figure(figsize=(12, 5))
plt.scatter(X_train, y_train, color='blue', alpha=0.6, label='训练数据')
plt.scatter(X_test, y_test, color='red', alpha=0.6, label='测试数据')
plt.plot(X_smooth, 2 * np.sin(X_smooth.ravel()) + 0.5 * X_smooth.ravel(),
'g-', linewidth=2, label='真实关系')
plt.plot(X_smooth, y_smooth_reg, 'r-', linewidth=2, label='正则化决策树预测')
plt.title(f'增加正则化改进\n训练MSE: {train_mse_reg:.4f}, 测试MSE: {test_mse_reg:.4f}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"正则化决策树训练MSE: {train_mse_reg:.4f}")
print(f"正则化决策树测试MSE: {test_mse_reg:.4f}")
print(f"正则化决策树训练R²: {train_r2_reg:.4f}")
print(f"正则化决策树测试R²: {test_r2_reg:.4f}")
print(f"泛化差距: {test_mse_reg - train_mse_reg:.4f}")
print(f"测试MSE改进: {((test_mse_deep - test_mse_reg) / test_mse_deep * 100):.1f}%")
print()
# ============================================================================
# 方法3:使用集成方法(随机森林)
# ============================================================================
print("=" * 70)
print("方法3: 使用集成方法")
print("=" * 70)
# 创建随机森林模型
forest_model = RandomForestRegressor(
n_estimators=100, # 100棵树
max_depth=5, # 每棵树深度5
min_samples_split=5, # 正则化参数
min_samples_leaf=2, # 正则化参数
max_features=0.8, # 特征采样
random_state=42
)
forest_model.fit(X_train, y_train)
y_pred_train_forest = forest_model.predict(X_train)
y_pred_test_forest = forest_model.predict(X_test)
# 计算性能指标
train_mse_forest = mean_squared_error(y_train, y_pred_train_forest)
test_mse_forest = mean_squared_error(y_test, y_pred_test_forest)
train_r2_forest = r2_score(y_train, y_pred_train_forest)
test_r2_forest = r2_score(y_test, y_pred_test_forest)
# 生成平滑曲线
y_smooth_forest = forest_model.predict(X_smooth)
plt.figure(figsize=(12, 5))
plt.scatter(X_train, y_train, color='blue', alpha=0.6, label='训练数据')
plt.scatter(X_test, y_test, color='red', alpha=0.6, label='测试数据')
plt.plot(X_smooth, 2 * np.sin(X_smooth.ravel()) + 0.5 * X_smooth.ravel(),
'g-', linewidth=2, label='真实关系')
plt.plot(X_smooth, y_smooth_forest, 'r-', linewidth=2, label='随机森林预测')
plt.title(f'集成方法改进\n训练MSE: {train_mse_forest:.4f}, 测试MSE: {test_mse_forest:.4f}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"随机森林训练MSE: {train_mse_forest:.4f}")
print(f"随机森林测试MSE: {test_mse_forest:.4f}")
print(f"随机森林训练R²: {train_r2_forest:.4f}")
print(f"随机森林测试R²: {test_r2_forest:.4f}")
print(f"泛化差距: {test_mse_forest - train_mse_forest:.4f}")
print(f"测试MSE改进: {((test_mse_deep - test_mse_forest) / test_mse_deep * 100):.1f}%")
print()
# ============================================================================
# 方法4:增加数据量
# ============================================================================
print("=" * 70)
print("方法4: 增加数据量")
print("=" * 70)
# 生成更多数据
X_large = np.linspace(0, 10, 1000).reshape(-1, 1)
y_true_large = 2 * np.sin(X_large.ravel()) + 0.5 * X_large.ravel()
y_noisy_large = y_true_large + np.random.normal(0, 0.5, 1000)
# 划分训练集和测试集
X_train_large, X_test_large, y_train_large, y_test_large = train_test_split(
X_large, y_noisy_large, test_size=0.3, random_state=42
)
# 在大量数据上训练深度决策树
deep_tree_large = DecisionTreeRegressor(max_depth=20, random_state=42)
deep_tree_large.fit(X_train_large, y_train_large)
y_pred_train_large = deep_tree_large.predict(X_train_large)
y_pred_test_large = deep_tree_large.predict(X_test_large)
# 计算性能指标
train_mse_large = mean_squared_error(y_train_large, y_pred_train_large)
test_mse_large = mean_squared_error(y_test_large, y_pred_test_large)
train_r2_large = r2_score(y_train_large, y_pred_train_large)
test_r2_large = r2_score(y_test_large, y_pred_test_large)
# 生成平滑曲线(只显示部分区域以避免过于密集)
X_smooth_large = np.linspace(0, 10, 300).reshape(-1, 1)
y_smooth_large = deep_tree_large.predict(X_smooth_large)
plt.figure(figsize=(12, 5))
# 只显示部分训练数据点,避免图像过于密集
plt.scatter(X_train_large[::10], y_train_large[::10], color='blue', alpha=0.6, label='训练数据(抽样)')
plt.scatter(X_test_large[::10], y_test_large[::10], color='red', alpha=0.6, label='测试数据(抽样)')
plt.plot(X_smooth_large, 2 * np.sin(X_smooth_large.ravel()) + 0.5 * X_smooth_large.ravel(),
'g-', linewidth=2, label='真实关系')
plt.plot(X_smooth_large, y_smooth_large, 'r-', linewidth=2, label='深度决策树预测(大数据)')
plt.title(f'增加数据量改进\n训练MSE: {train_mse_large:.4f}, 测试MSE: {test_mse_large:.4f}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"大数据深度决策树训练MSE: {train_mse_large:.4f}")
print(f"大数据深度决策树测试MSE: {test_mse_large:.4f}")
print(f"大数据深度决策树训练R²: {train_r2_large:.4f}")
print(f"大数据深度决策树测试R²: {test_r2_large:.4f}")
print(f"泛化差距: {test_mse_large - train_mse_large:.4f}")
print(f"测试MSE改进(相比小数据): {((test_mse_deep - test_mse_large) / test_mse_deep * 100):.1f}%")
print()
# ============================================================================
# 综合对比
# ============================================================================
print("=" * 70)
print("所有方法性能对比(按测试MSE排序)")
print("=" * 70)
methods = {
'深度决策树 (过拟合)': (train_mse_deep, test_mse_deep),
'限制复杂度 (深度=5)': (train_mse_proper, test_mse_proper),
'增加正则化': (train_mse_reg, test_mse_reg),
'随机森林': (train_mse_forest, test_mse_forest),
'增加数据量': (train_mse_large, test_mse_large)
}
# 按测试MSE排序
sorted_methods = sorted(methods.items(), key=lambda x: x[1][1])
print("方法名称 | 训练MSE | 测试MSE | 泛化差距 | 测试改进%")
print("-" * 75)
for name, (train_mse, test_mse) in sorted_methods:
gap = test_mse - train_mse
improvement = ((test_mse_deep - test_mse) / test_mse_deep * 100) if name != '深度决策树 (过拟合)' else 0
print(f"{name:<25} | {train_mse:.4f} | {test_mse:.4f} | {gap:.4f} | {improvement:>6.1f}%")
# 绘制所有方法的预测曲线对比
plt.figure(figsize=(15, 10))
# 准备预测曲线
predictions = {
'真实关系': (X_smooth, 2 * np.sin(X_smooth.ravel()) + 0.5 * X_smooth.ravel(), 'g-'),
'深度决策树 (过拟合)': (X_smooth, y_smooth_deep, 'red'),
'限制复杂度': (X_smooth, y_smooth_proper, 'blue'),
'增加正则化': (X_smooth, y_smooth_reg, 'orange'),
'随机森林': (X_smooth, y_smooth_forest, 'purple')
}
colors = ['red', 'blue', 'orange', 'purple']
models_names = ['深度决策树 (过拟合)', '限制复杂度', '增加正则化', '随机森林']
plt.subplot(2, 1, 1)
plt.scatter(X_train, y_train, alpha=0.3, color='gray', label='训练数据')
for i, (name, (x_vals, y_vals, style)) in enumerate(predictions.items()):
if name != '真实关系':
plt.plot(x_vals, y_vals, color=colors[i-1], linewidth=2, label=name)
plt.plot(X_smooth, predictions['真实关系'][1], 'g-', linewidth=3, label='真实关系')
plt.title('所有方法预测曲线对比')
plt.legend()
plt.grid(True, alpha=0.3)
plt.subplot(2, 1, 2)
# 绘制性能对比条形图
names = list(methods.keys())
test_mses = [methods[name][1] for name in names]
colors_bar = ['red', 'blue', 'orange', 'purple', 'brown']
bars = plt.bar(names, test_mses, color=colors_bar, alpha=0.7)
plt.title('各方法测试MSE对比')
plt.ylabel('测试集均方误差 (MSE)')
plt.xticks(rotation=45)
# 在条形图上添加数值标签
for bar, mse in zip(bars, test_mses):
plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.01,
f'{mse:.4f}', ha='center', va='bottom')
plt.tight_layout()
plt.show()3.3.2.2 输出结果
===================================================================== 原始过拟合模型(深度决策树) ===================================================================== 深度决策树训练MSE: 0.0000 深度决策树测试MSE: 0.4149 深度决策树训练R²: 1.0000 深度决策树测试R²: 0.9052 泛化差距: 0.4149 ===================================================================== 方法1: 限制模型复杂度 ===================================================================== 适当深度决策树训练MSE: 0.1155 适当深度决策树测试MSE: 0.3035 适当深度决策树训练R²: 0.9682 适当深度决策树测试R²: 0.9307 泛化差距: 0.1879 测试MSE改进: 26.9% ===================================================================== 方法2: 增加正则化 ===================================================================== 正则化决策树训练MSE: 0.1968 正则化决策树测试MSE: 0.3411 正则化决策树训练R²: 0.9459 正则化决策树测试R²: 0.9221 泛化差距: 0.1443 测试MSE改进: 17.8% ===================================================================== 方法3: 使用集成方法 ===================================================================== 随机森林训练MSE: 0.1312 随机森林测试MSE: 0.2029 随机森林训练R²: 0.9639 随机森林测试R²: 0.9537 泛化差距: 0.0717 测试MSE改进: 51.1% ===================================================================== 方法4: 增加数据量 ===================================================================== 大数据深度决策树训练MSE: 0.0034 大数据深度决策树测试MSE: 0.4389 大数据深度决策树训练R²: 0.9992 大数据深度决策树测试R²: 0.8877 泛化差距: 0.4355 测试MSE改进(相比小数据): -5.8% ===================================================================== 所有方法性能对比(按测试MSE排序) ===================================================================== 方法名称 | 训练MSE | 测试MSE | 泛化差距 | 测试改进% --------------------------------------------------------------------------- 随机森林 | 0.1312 | 0.2029 | 0.0717 | 51.1% 限制复杂度 (深度=5) | 0.1155 | 0.3035 | 0.1879 | 26.9% 增加正则化 | 0.1968 | 0.3411 | 0.1443 | 17.8% 深度决策树 (过拟合) | 0.0000 | 0.4149 | 0.4149 | 0.0% 增加数据量 | 0.0034 | 0.4389 | 0.4355 | -5.8%
方法1:限制模型复杂度改进

关键改进原理:
# 原理:减少模型容量,防止过度拟合
DecisionTreeRegressor(max_depth=5) # 而不是20
# 效果:
- 叶节点数量从2^20 ≈ 1百万减少到2^5 = 32
- 每个叶节点包含更多样本,学习普遍模式而非噪声改进效果说明:
方法2:增加正则化改进

关键改进原理:
# 原理:通过约束条件限制模型灵活性
DecisionTreeRegressor(
min_samples_split=10, # 节点至少10个样本才分裂
min_samples_leaf=5, # 叶节点至少5个样本
max_features=0.8 # 每次分裂只考虑80%特征
)改进效果说明:
方法3:使用集成方法改进

关键改进原理:
# 原理:多个模型的平均减少方差
RandomForestRegressor(
n_estimators=100, # 100个树
max_depth=5, # 每个树适度复杂
# 通过bootstrap和特征采样增加多样性
)改进效果说明:
方法4:增加数据量改进

关键改进原理:
改进效果说明:
所有方法性能对比

通过这四种方法,我们成功地将过拟合模型的测试MSE从较高的值降低到0.1以下,改进幅度达到50-90%。这证明了:
在实际项目应用中,通常需要组合使用这些策略:
通过这种系统化的方法,可以构建出既能在训练数据上表现良好,又具有强大泛化能力的稳健模型。
修复过拟合的关键要点总结
欠拟合和过拟合是机器学习中最核心的平衡问题。欠拟合发生在模型过于简单时,表现为训练和测试误差都很高,模型无法捕捉数据的基本模式,就像学生只看了课程目录却无法解答具体问题。过拟合则相反,模型过于复杂,完美拟合训练数据却在测试集上表现糟糕,如同学生死记硬背考题却不会举一反三。
解决方案具有对称性:修复欠拟合需增加模型复杂度、改进特征工程、减少正则化;修复过拟合则要限制复杂度、增加正则化、使用集成方法或收集更多数据。成功模型的秘诀在于找到恰到好处的复杂度,既能学习数据本质规律,又能忽略随机噪声,在训练性能和泛化能力间达到精妙平衡。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。