Python案例如何用Scikit-learn做学习曲线

wen python案例 1

本文目录导读:

Python案例如何用Scikit-learn做学习曲线

  1. 学习曲线的基本概念
  2. 完整案例代码
  3. 自定义学习曲线分析器
  4. 学习曲线分析技巧
  5. 注意事项

我来详细介绍如何使用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)

注意事项

  1. 训练集大小选择:通常从10%到100%,步长均匀
  2. 交叉验证折数:一般使用5折或10折
  3. 评分指标选择:根据问题类型选择(准确率、RMSE、F1分数等)
  4. 正则化参数:过拟合时增加正则化,欠拟合时减少
  5. 数据预处理:确保在交叉验证中正确处理数据标准化

通过这些代码示例,你可以灵活地使用Scikit-learn创建和分析学习曲线,从而更好地理解模型的学习行为和性能特征。

抱歉,评论功能暂时关闭!