Scikit-learn 对加州房价数据集(回归任务)进行全面分析

发布于:2025-09-15 ⋅ 阅读:(16) ⋅ 点赞:(0)

背景

加利福尼亚房价数据集 fetch_california_housing,20640个样本,8个特征(人口、收入等),目标为房价中位数
该数据集是一个回归问题,需要运用回归任务的分析方法进行分析

分析方法

  • 线性回归
  • K 近邻(K-NN)
  • 决策树
  • 支持向量机
  • 随机森林
  • 多层感知机(MLP)
  • Lasso 回归
  • Ridge 回归
  • 梯度提升回归
  • AdaBoost 回归
  • Huber 回归

分析步骤

  1. 加载数据集
  2. 拆分训练集、测试集
  3. 数据预处理(标准化)
  4. 选择模型
  5. 模型训练(拟合)
  6. 测试模型效果
  7. 评估模型

分析结果

不同模型的预测值 vs 真实值

预测值 vs 真实值

残差图

残差图

特征重要性对比

特征重要性对比

预测值分布

预测值分布

不同模型评估明细

--- 正在加载加州房价数据集 ---

--- 数据集概览 ---
数据形状: (20640, 8)
特征名称: ['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude']
目标变量名称: MedHouseVal

--- 数据划分结果 ---
训练集形状: (14448, 8)
测试集形状: (6192, 8)

--- 正在对数据进行标准化处理 ---

--- 模型训练与评估 ---

--- 正在训练 线性回归 模型 ---
线性回归 模型的均方误差 (MSE): 0.5306
线性回归 模型的 R^2 得分: 0.5958

--- 正在训练 K近邻 (K-NN) 模型 ---
K近邻 (K-NN) 模型的均方误差 (MSE): 0.4295
K近邻 (K-NN) 模型的 R^2 得分: 0.6728

--- 正在训练 决策树 模型 ---
决策树 模型的均方误差 (MSE): 0.5250
决策树 模型的 R^2 得分: 0.6000

--- 正在训练 支持向量机 (SVR) 模型 ---
支持向量机 (SVR) 模型的均方误差 (MSE): 0.3099
支持向量机 (SVR) 模型的 R^2 得分: 0.7639

--- 正在训练 随机森林 模型 ---
随机森林 模型的均方误差 (MSE): 0.2573
随机森林 模型的 R^2 得分: 0.8040

--- 正在训练 多层感知器 (MLP) 模型 ---
多层感知器 (MLP) 模型的均方误差 (MSE): 0.2897
多层感知器 (MLP) 模型的 R^2 得分: 0.7793

--- 正在训练 Lasso 回归 模型 ---
Lasso 回归 模型的均方误差 (MSE): 0.6648
Lasso 回归 模型的 R^2 得分: 0.4935

--- 正在训练 Ridge 回归 模型 ---
Ridge 回归 模型的均方误差 (MSE): 0.5305
Ridge 回归 模型的 R^2 得分: 0.5958

--- 正在训练 梯度提升回归 模型 ---
梯度提升回归 模型的均方误差 (MSE): 0.2883
梯度提升回归 模型的 R^2 得分: 0.7803

--- 正在训练 AdaBoost 回归 模型 ---
AdaBoost 回归 模型的均方误差 (MSE): 0.6830
AdaBoost 回归 模型的 R^2 得分: 0.4797

--- 正在训练 Huber 回归 模型 ---
Huber 回归 模型的均方误差 (MSE): 0.5515
Huber 回归 模型的 R^2 得分: 0.5798

所有模型的分析已完成。

代码

注:如果遇到下载数据集失败(HTTP 403),可参考此博文 https://blog.csdn.net/xchenhao/article/details/151373379

from sklearn.datasets import fetch_california_housing

from sklearn.model_selection import train_test_split

from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.svm import SVR
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.neural_network import MLPRegressor
from sklearn.linear_model import Lasso, Ridge
from sklearn.ensemble import GradientBoostingRegressor, AdaBoostRegressor
from sklearn.linear_model import HuberRegressor

from sklearn.metrics import mean_squared_error, r2_score

import numpy as np
import matplotlib.pyplot as plt

# 设置 Matplotlib 字体以正确显示中文
plt.rcParams['font.sans-serif'] = ['SimHei', 'WenQuanYi Zen Hei', 'STHeiti', 'Arial Unicode MS']
# 解决保存图像时负号'-'显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False 

def perform_housing_analysis():
    """
    使用 scikit-learn 对加州房价数据集进行全面的分析。
    该函数包含数据加载、预处理、模型训练、评估和结果可视化。
    """
    print("--- 正在加载加州房价数据集 ---")
    # 加载加州房价数据集
    housing = fetch_california_housing(as_frame=True)
    
    # 获取数据特征和目标标签
    X = housing.data
    y = housing.target
    feature_names = list(X.columns)

    print("\n--- 数据集概览 ---")
    print(f"数据形状: {X.shape}")
    print(f"特征名称: {feature_names}")
    print(f"目标变量名称: {housing.target.name}")

    # 将数据集划分为训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

    print("\n--- 数据划分结果 ---")
    print(f"训练集形状: {X_train.shape}")
    print(f"测试集形状: {X_test.shape}")
    
    # 数据标准化
    print("\n--- 正在对数据进行标准化处理 ---")
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    
    # 定义并训练多个回归器模型
    models = {
        "线性回归": LinearRegression(),
        "K近邻 (K-NN)": KNeighborsRegressor(n_neighbors=5),
        "决策树": DecisionTreeRegressor(random_state=42),
        "支持向量机 (SVR)": SVR(kernel='rbf', C=100),
        "随机森林": RandomForestRegressor(random_state=42),
        "多层感知器 (MLP)": MLPRegressor(random_state=42, max_iter=10000),
        "Lasso 回归": Lasso(alpha=0.1, max_iter=10000),
        "Ridge 回归": Ridge(alpha=1.0, max_iter=10000),
        "梯度提升回归": GradientBoostingRegressor(random_state=42),
        "AdaBoost 回归": AdaBoostRegressor(random_state=42),
        "Huber 回归": HuberRegressor(max_iter=10000)
    }

    # 用于存储所有模型的预测结果
    predictions = {}
    
    # 用于存储树模型的特征重要性
    feature_importances = {}

    print("\n--- 模型训练与评估 ---")
    for name, model in models.items():
        print(f"\n--- 正在训练 {name} 模型 ---")
        model.fit(X_train_scaled, y_train)
        y_pred = model.predict(X_test_scaled)
        
        # 计算回归指标
        mse = mean_squared_error(y_test, y_pred)
        r2 = r2_score(y_test, y_pred)
        
        print(f"{name} 模型的均方误差 (MSE): {mse:.4f}")
        print(f"{name} 模型的 R^2 得分: {r2:.4f}")
        
        # 存储预测结果以用于后续可视化
        predictions[name] = y_pred

        # 检查模型是否具有特征重要性属性
        if hasattr(model, 'feature_importances_'):
            feature_importances[name] = model.feature_importances_
        
    print("\n所有模型的分析已完成。")

    # --- 预测值 vs. 实际值可视化 ---
    print("\n--- 预测值 vs. 实际值散点图 ---")
    num_models = len(models)
    cols = 3
    rows = (num_models + cols - 1) // cols
    fig, axes = plt.subplots(rows, cols, figsize=(18, 6 * rows))
    axes = axes.flatten()

    for i, name in enumerate(models.keys()):
        ax = axes[i]
        y_pred = predictions[name]
        
        ax.scatter(y_test, y_pred, alpha=0.6, label='预测值')
        lims = [
            np.min([ax.get_xlim(), ax.get_ylim()]),
            np.max([ax.get_xlim(), ax.get_ylim()]),
        ]
        ax.plot(lims, lims, 'k--', alpha=0.75, zorder=0, label='理想预测')
        
        ax.set_title(f'{name} - 预测值 vs. 实际值', fontsize=14)
        ax.set_xlabel('实际房价中位数', fontsize=12)
        ax.set_ylabel('预测房价中位数', fontsize=12)
        ax.legend()
        ax.grid(True)
    
    for j in range(num_models, len(axes)):
        axes[j].axis('off')

    plt.tight_layout()
    plt.show()

    # --- 残差图可视化 ---
    print("\n--- 残差图可视化 ---")
    fig, axes = plt.subplots(rows, cols, figsize=(18, 6 * rows))
    axes = axes.flatten()
    
    for i, name in enumerate(models.keys()):
        ax = axes[i]
        y_pred = predictions[name]
        # 计算残差 (实际值 - 预测值)
        residuals = y_test - y_pred
        
        ax.scatter(y_pred, residuals, alpha=0.6)
        ax.axhline(y=0, color='r', linestyle='--', linewidth=2)
        
        ax.set_title(f'{name} - 残差图', fontsize=14)
        ax.set_xlabel('预测值', fontsize=12)
        ax.set_ylabel('残差 (实际值 - 预测值)', fontsize=12)
        ax.grid(True)
    
    for j in range(num_models, len(axes)):
        axes[j].axis('off')

    plt.tight_layout()
    plt.show()

    # --- 特征重要性可视化 (仅限树模型) ---
    if feature_importances:
        print("\n--- 特征重要性可视化 ---")
        num_tree_models = len(feature_importances)
        rows_tree = (num_tree_models + cols - 1) // cols
        fig, axes = plt.subplots(rows_tree, cols, figsize=(18, 6 * rows_tree))
        axes = axes.flatten()

        for i, (name, importances) in enumerate(feature_importances.items()):
            ax = axes[i]
            # 根据重要性降序排序
            sorted_indices = np.argsort(importances)[::-1]
            sorted_importances = importances[sorted_indices]
            sorted_feature_names = [feature_names[j] for j in sorted_indices]

            ax.barh(sorted_feature_names, sorted_importances, color='skyblue')
            ax.set_title(f'{name} - 特征重要性', fontsize=14)
            ax.set_xlabel('重要性', fontsize=12)
            ax.set_ylabel('特征', fontsize=12)
            ax.grid(axis='x')
        
        for j in range(num_tree_models, len(axes)):
            axes[j].axis('off')
            
        plt.tight_layout()
        plt.show()

    # --- 预测值分布图可视化 ---
    print("\n--- 预测值分布图 ---")
    fig, axes = plt.subplots(rows, cols, figsize=(18, 6 * rows))
    axes = axes.flatten()
    
    # 找到所有预测值和实际值的全局范围,以便所有子图的X轴一致
    all_values = np.concatenate([y_test] + list(predictions.values()))
    bins = np.linspace(min(all_values), max(all_values), 50)

    for i, name in enumerate(models.keys()):
        ax = axes[i]
        y_pred = predictions[name]
        
        # 绘制实际值和预测值的直方图
        ax.hist(y_test, bins=bins, alpha=0.6, label='实际值', color='b', edgecolor='k')
        ax.hist(y_pred, bins=bins, alpha=0.6, label='预测值', color='r', edgecolor='k')
        
        ax.set_title(f'{name} - 分布图', fontsize=14)
        ax.set_xlabel('房价中位数', fontsize=12)
        ax.set_ylabel('频率', fontsize=12)
        ax.legend()
        ax.grid(True)
    
    for j in range(num_models, len(axes)):
        axes[j].axis('off')

    plt.tight_layout()
    plt.show()

if __name__ == "__main__":
    perform_housing_analysis()