Python案例如何用Scikit-learn做平均绝对误差

wen python案例 2

本文目录导读:

Python案例如何用Scikit-learn做平均绝对误差

  1. 基本用法
  2. 完整案例:线性回归模型评估
  3. 多模型对比案例
  4. 交叉验证中的MAE
  5. 实际应用案例:房价预测
  6. 自定义MAE函数(理解原理)
  7. 网格搜索优化模型(使用MAE作为指标)
  8. 关键要点

我来详细说明如何使用Scikit-learn计算平均绝对误差(MAE)。

基本用法

from sklearn.metrics import mean_absolute_error
import numpy as np
# 示例数据
y_true = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y_pred = np.array([1.1, 1.9, 3.2, 3.8, 5.1])
# 计算MAE
mae = mean_absolute_error(y_true, y_pred)
print(f"MAE: {mae:.4f}")  # 输出: MAE: 0.1200

完整案例:线性回归模型评估

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
# 1. 生成模拟数据
np.random.seed(42)
X = np.random.rand(100, 1) * 10  # 特征值 0-10
y = 2 * X + 1 + np.random.randn(100, 1) * 0.5  # y = 2x + 1 + 噪声
# 2. 分割数据
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
# 3. 训练模型
model = LinearRegression()
model.fit(X_train, y_train)
# 4. 预测
y_pred = model.predict(X_test)
# 5. 计算各项指标
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, y_pred)
print(f"模型评估结果:")
print(f"MAE  (平均绝对误差): {mae:.4f}")
print(f"MSE  (均方误差): {mse:.4f}")
print(f"RMSE (均方根误差): {rmse:.4f}")
print(f"R²   (决定系数): {r2:.4f}")

多模型对比案例

from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# 准备数据
X = np.random.rand(200, 5)  # 5个特征
true_coef = [1.5, -2.0, 0.8, -1.2, 0.5]
y = X @ true_coef + np.random.randn(200) * 0.3
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)
# 定义多个模型
models = {
    'Linear Regression': LinearRegression(),
    'Decision Tree': DecisionTreeRegressor(max_depth=5, random_state=42),
    'Random Forest': RandomForestRegressor(n_estimators=100, random_state=42)
}
# 训练并评估
results = []
for name, model in models.items():
    # 创建管道(包括标准化)
    pipeline = Pipeline([
        ('scaler', StandardScaler()),
        ('model', model)
    ])
    # 训练
    pipeline.fit(X_train, y_train)
    # 预测
    y_pred = pipeline.predict(X_test)
    # 计算MAE
    mae = mean_absolute_error(y_test, y_pred)
    results.append({'Model': name, 'MAE': mae})
    print(f"{name}: MAE = {mae:.4f}")
# 创建结果DataFrame
results_df = pd.DataFrame(results)
print("\n模型对比结果:")
print(results_df.to_string(index=False))

交叉验证中的MAE

from sklearn.model_selection import cross_val_score, cross_validate
from sklearn.linear_model import Ridge
# 准备数据
X, y = np.random.rand(150, 10), np.random.rand(150)
# 使用交叉验证评估模型
model = Ridge(alpha=1.0)
# 计算各折的MAE
mae_scores = cross_val_score(
    model, X, y, 
    cv=5, 
    scoring='neg_mean_absolute_error'  # 注意:sklearn返回负值
)
# 转换为正值
mae_scores = -mae_scores
print(f"5折交叉验证MAE:")
print(f"各折MAE: {mae_scores}")
print(f"平均MAE: {mae_scores.mean():.4f}")
print(f"MAE标准差: {mae_scores.std():.4f}")
# 获取更多详细信息
cv_results = cross_validate(
    model, X, y,
    cv=5,
    scoring=['neg_mean_absolute_error', 'neg_mean_squared_error'],
    return_train_score=True
)
print("\n详细交叉验证结果:")
print(f"测试集MAE: {-cv_results['test_neg_mean_absolute_error']}")
print(f"训练集MAE: {-cv_results['train_neg_mean_absolute_error']}")

实际应用案例:房价预测

from sklearn.datasets import fetch_california_housing
from sklearn.ensemble import GradientBoostingRegressor
# 加载加州房价数据集
housing = fetch_california_housing()
X, y = housing.data[:1000], housing.target[:1000]  # 取前1000条
# 分割数据
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
# 训练梯度提升回归模型
gbr = GradientBoostingRegressor(
    n_estimators=100,
    learning_rate=0.1,
    max_depth=3,
    random_state=42
)
gbr.fit(X_train, y_train)
# 预测
y_pred = gbr.predict(X_test)
# 计算MAE
mae = mean_absolute_error(y_test, y_pred)
# 可视化结果
plt.figure(figsize=(10, 6))
# 绘制预测值与真实值的对比
plt.subplot(1, 2, 1)
plt.scatter(y_test, y_pred, alpha=0.5)
plt.plot([y_test.min(), y_test.max()], 
         [y_test.min(), y_test.max()], 
         'r--', lw=2)
plt.xlabel('True Values')
plt.ylabel('Predictions')f'House Price Prediction (MAE: ${mae*100000:.0f})')
# 绘制误差分布
plt.subplot(1, 2, 2)
errors = y_test - y_pred
plt.hist(errors, bins=30, edgecolor='black')
plt.xlabel('Prediction Error')
plt.ylabel('Frequency')'Error Distribution')
plt.axvline(x=0, color='r', linestyle='--')
print(f"加州房价预测结果:")
print(f"平均绝对误差: ${mae*100000:.0f}")
print(f"平均真实价格: ${np.mean(y_test)*100000:.0f}")
print(f"相对误差: {mae/np.mean(y_test)*100:.2f}%")
plt.tight_layout()
plt.show()

自定义MAE函数(理解原理)

def calculate_mae_manual(y_true, y_pred):
    """
    手动计算平均绝对误差
    """
    # 计算绝对误差
    absolute_errors = np.abs(y_true - y_pred)
    # 计算平均值
    mae = np.mean(absolute_errors)
    return mae
# 与sklearn对比
y_true = np.array([2.0, 3.5, 5.0, 7.2])
y_pred = np.array([2.1, 3.3, 5.2, 7.0])
mae_manual = calculate_mae_manual(y_true, y_pred)
mae_sklearn = mean_absolute_error(y_true, y_pred)
print(f"手动计算MAE: {mae_manual:.4f}")
print(f"Sklearn MAE: {mae_sklearn:.4f}")
print(f"结果一致: {np.isclose(mae_manual, mae_sklearn)}")

网格搜索优化模型(使用MAE作为指标)

from sklearn.model_selection import GridSearchCV
# 定义参数网格
param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [3, 5, 7],
    'learning_rate': [0.01, 0.1, 0.2]
}
# 创建模型
gbr = GradientBoostingRegressor(random_state=42)
# 网格搜索
grid_search = GridSearchCV(
    gbr, param_grid,
    cv=5,
    scoring='neg_mean_absolute_error',
    n_jobs=-1
)
grid_search.fit(X_train, y_train)
print("最优参数:", grid_search.best_params_)
print(f"最优MAE: {-grid_search.best_score_:.4f}")
# 使用最优模型
best_gbr = grid_search.best_estimator_
y_pred_best = best_gbr.predict(X_test)
test_mae = mean_absolute_error(y_test, y_pred_best)
print(f"测试集MAE: {test_mae:.4f}")

关键要点

  1. MAE是绝对值:计算预测值与真实值之差的绝对值平均
  2. sklearn返回负值:在交叉验证中,sklearn返回负的MAE,因为sklearn总是最大化的分数
  3. 对异常值不敏感:相比于MSE,MAE对异常值更加鲁棒
  4. 单位相同:MAE的单位与原始数据相同,易于解释
  5. 用于回归问题:MAE主要用于回归任务的评估

希望这些案例能帮助你掌握Scikit-learn中MAE的使用方法!

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