本文目录导读:

我来详细介绍如何使用Scikit-learn绘制学习曲线(Learning Curve):
学习曲线的基本概念
学习曲线展示了模型性能随训练样本数量变化的趋势,可以帮助我们:
- 判断模型是否存在过拟合或欠拟合
- 确定是否需要收集更多数据
- 评估模型的学习能力
完整案例代码
1 基础实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import learning_curve
from sklearn.svm import SVC
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
# 加载数据集
digits = load_digits()
X, y = digits.data, digits.target
# 创建学习曲线
def plot_learning_curve(estimator, X, y, cv=5, train_sizes=np.linspace(0.1, 1.0, 10)):
"""
绘制学习曲线
"""
# 计算学习曲线
train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv,
train_sizes=train_sizes,
scoring='accuracy',
n_jobs=-1
)
# 计算平均值和标准差
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# 绘制图形
plt.figure(figsize=(10, 6))
# 绘制训练集曲线
plt.plot(train_sizes, train_mean, 'o-', color='blue', label='Training score')
plt.fill_between(train_sizes, train_mean - train_std,
train_mean + train_std, alpha=0.1, color='blue')
# 绘制验证集曲线
plt.plot(train_sizes, test_mean, 'o-', color='red', label='Cross-validation score')
plt.fill_between(train_sizes, test_mean - test_std,
test_mean + test_std, alpha=0.1, color='red')
plt.title('Learning Curve')
plt.xlabel('Training examples')
plt.ylabel('Score')
plt.legend(loc='best')
plt.grid(True)
return plt
# 使用SVM模型
svm = SVC(kernel='rbf', gamma=0.001)
plot_learning_curve(svm, X, y)
plt.show()
2 比较不同模型的學習曲线
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
# 定义要比较的模型
models = {
'SVM (RBF)': SVC(kernel='rbf', gamma=0.001),
'Logistic Regression': LogisticRegression(max_iter=1000),
'Random Forest': RandomForestClassifier(n_estimators=100)
}
# 绘制多个学习曲线进行比较
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
for idx, (name, model) in enumerate(models.items()):
train_sizes, train_scores, test_scores = learning_curve(
model, X, y, cv=5,
train_sizes=np.linspace(0.1, 1.0, 10),
scoring='accuracy',
n_jobs=-1
)
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
ax = axes[idx]
ax.plot(train_sizes, train_mean, 'o-', color='blue', label='Training')
ax.fill_between(train_sizes, train_mean - train_std,
train_mean + train_std, alpha=0.1, color='blue')
ax.plot(train_sizes, test_mean, 'o-', color='red', label='Validation')
ax.fill_between(train_sizes, test_mean - test_std,
test_mean + test_std, alpha=0.1, color='red')
ax.set_title(f'{name}\nLearning Curve')
ax.set_xlabel('Training examples')
ax.set_ylabel('Accuracy')
ax.legend(loc='best')
ax.grid(True)
plt.tight_layout()
plt.show()
3 参数调优与学习曲线
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# 创建包含预处理的pipeline
pipeline = Pipeline([
('scaler', StandardScaler()),
('svm', SVC(kernel='rbf'))
])
# 不同gamma值的学习曲线
gamma_values = [0.001, 0.01, 0.1]
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
for idx, gamma in enumerate(gamma_values):
pipeline.set_params(svm__gamma=gamma)
train_sizes, train_scores, test_scores = learning_curve(
pipeline, X, y, cv=5,
train_sizes=np.linspace(0.1, 1.0, 10),
scoring='accuracy',
n_jobs=-1
)
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
ax = axes[idx]
ax.plot(train_sizes, train_mean, 'o-', color='blue', label='Training')
ax.fill_between(train_sizes, train_mean - train_std,
train_mean + train_std, alpha=0.1, color='blue')
ax.plot(train_sizes, test_mean, 'o-', color='red', label='Validation')
ax.fill_between(train_sizes, test_mean - test_std,
test_mean + test_std, alpha=0.1, color='red')
ax.set_title(f'gamma={gamma}')
ax.set_xlabel('Training examples')
ax.set_ylabel('Accuracy')
ax.legend(loc='best')
ax.grid(True)
ax.set_ylim([0, 1.1])
plt.suptitle('SVM with different gamma values', fontsize=14)
plt.tight_layout()
plt.show()
4 实际应用示例 - 房价预测
from sklearn.datasets import fetch_california_housing
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score
# 加载房价数据集
housing = fetch_california_housing()
X_housing, y_housing = housing.data, housing.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X_housing, y_housing, test_size=0.2, random_state=42
)
# 标准化数据
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 创建学习曲线
from sklearn.linear_model import Ridge
def plot_learning_curve_with_rmse(estimator, X, y, cv=5):
"""绘制学习曲线(使用RMSE)"""
train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv,
train_sizes=np.linspace(0.1, 1.0, 10),
scoring='neg_mean_squared_error',
n_jobs=-1
)
# 转换为RMSE
train_rmse = np.sqrt(-train_scores)
test_rmse = np.sqrt(-test_scores)
train_mean = np.mean(train_rmse, axis=1)
train_std = np.std(train_rmse, axis=1)
test_mean = np.mean(test_rmse, axis=1)
test_std = np.std(test_rmse, axis=1)
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, train_mean, 'o-', color='blue', label='Training RMSE')
plt.fill_between(train_sizes, train_mean - train_std,
train_mean + train_std, alpha=0.1, color='blue')
plt.plot(train_sizes, test_mean, 'o-', color='red', label='Validation RMSE')
plt.fill_between(train_sizes, test_mean - test_std,
test_mean + test_std, alpha=0.1, color='red')
plt.title('Learning Curve (RMSE) - Ridge Regression')
plt.xlabel('Training examples')
plt.ylabel('RMSE')
plt.legend(loc='best')
plt.grid(True)
return plt
# 使用Ridge回归
ridge = Ridge(alpha=1.0)
plot_learning_curve_with_rmse(ridge, X_train_scaled, y_train)
plt.show()
自定义学习曲线分析器
class LearningCurveAnalyzer:
"""学习曲线分析器"""
def __init__(self, estimator, cv=5, train_sizes=np.linspace(0.1, 1.0, 10)):
self.estimator = estimator
self.cv = cv
self.train_sizes = train_sizes
self.results = {}
def fit(self, X, y, scoring='accuracy'):
"""拟合学习曲线"""
train_sizes, train_scores, test_scores = learning_curve(
self.estimator, X, y, cv=self.cv,
train_sizes=self.train_sizes,
scoring=scoring,
n_jobs=-1
)
self.results = {
'train_sizes': train_sizes,
'train_scores': train_scores,
'test_scores': test_scores,
'train_mean': np.mean(train_scores, axis=1),
'train_std': np.std(train_scores, axis=1),
'test_mean': np.mean(test_scores, axis=1),
'test_std': np.std(test_scores, axis=1)
}
return self
def assess_bias_variance(self):
"""评估偏差和方差"""
final_test_score = self.results['test_mean'][-1]
final_train_score = self.results['train_mean'][-1]
# 计算偏差(1减去最终测试分数)
bias = 1 - final_test_score
# 计算方差(训练分数和测试分数的差距)
variance = final_train_score - final_test_score
return {
'bias': bias,
'variance': variance,
'final_train_score': final_train_score,
'final_test_score': final_test_score
}
def plot(self, title='Learning Curve'):
"""绘制学习曲线"""
plt.figure(figsize=(10, 6))
plt.plot(self.results['train_sizes'], self.results['train_mean'],
'o-', color='blue', label='Training score')
plt.fill_between(self.results['train_sizes'],
self.results['train_mean'] - self.results['train_std'],
self.results['train_mean'] + self.results['train_std'],
alpha=0.1, color='blue')
plt.plot(self.results['train_sizes'], self.results['test_mean'],
'o-', color='red', label='Cross-validation score')
plt.fill_between(self.results['train_sizes'],
self.results['test_mean'] - self.results['test_std'],
self.results['test_mean'] + self.results['test_std'],
alpha=0.1, color='red')
plt.title(title)
plt.xlabel('Training examples')
plt.ylabel('Score')
plt.legend(loc='best')
plt.grid(True)
return plt
# 使用示例
analyzer = LearningCurveAnalyzer(SVC(kernel='rbf', gamma=0.001))
analyzer.fit(X, y)
analyzer.plot(title='SVM Learning Curve')
# 分析偏差和方差
assess = analyzer.assess_bias_variance()
print("偏差-方差分析结果:")
print(f"偏差 (Bias): {assess['bias']:.3f}")
print(f"方差 (Variance): {assess['variance']:.3f}")
print(f"最终训练分数: {assess['final_train_score']:.3f}")
print(f"最终测试分数: {assess['final_test_score']:.3f}")
# 自动判断
if assess['bias'] > 0.3:
print("建议: 模型存在高偏差(欠拟合)")
elif assess['variance'] > 0.2:
print("建议: 模型存在高方差(过拟合)")
else:
print("建议: 模型拟合情况良好")
学习曲线分析技巧
def analyze_learning_curve_patterns(train_scores, test_scores):
"""分析学习曲线模式"""
train_final = train_scores[:, -1].mean()
test_final = test_scores[:, -1].mean()
gap = train_final - test_final
# 判断曲线趋势
test_trend = test_scores.mean(axis=0)
if test_trend[-1] - test_trend[0] > 0.05:
trend = "上升"
elif test_trend[-1] - test_trend[0] < -0.05:
trend = "下降"
else:
trend = "稳定"
print(f"训练集最终分数: {train_final:.3f}")
print(f"验证集最终分数: {test_final:.3f}")
print(f"分数差距: {gap:.3f}")
print(f"验证曲线趋势: {trend}")
if gap > 0.2:
print("⚠️ 模型可能过拟合")
print("建议: 增加正则化或减少模型复杂度")
elif test_final < 0.6:
print("⚠️ 模型可能欠拟合")
print("建议: 增加模型复杂度或特征工程")
else:
print("✅ 模型表现良好")
# 使用示例
from sklearn.model_selection import learning_curve
train_sizes, train_scores, test_scores = learning_curve(
SVC(kernel='rbf', gamma=0.001), X, y, cv=5,
train_sizes=np.linspace(0.1, 1.0, 10), scoring='accuracy'
)
analyze_learning_curve_patterns(train_scores, test_scores)
注意事项
- 训练集大小选择:通常从10%到100%,步长均匀
- 交叉验证折数:一般使用5折或10折
- 评分指标选择:根据问题类型选择(准确率、RMSE、F1分数等)
- 正则化参数:过拟合时增加正则化,欠拟合时减少
- 数据预处理:确保在交叉验证中正确处理数据标准化
通过这些代码示例,你可以灵活地使用Scikit-learn创建和分析学习曲线,从而更好地理解模型的学习行为和性能特征。