机器学习监督学习实战四:九种回归算法对波士顿房价数据进行回归预测和评估方法可视化

本项目代码在个人github链接:https://github.com/KLWU07/Machine-learning-Project-practice/tree/main

处理流程

  • 1.导入波士顿房价数据集并进行预处理。
  • 2.使用 GradientBoostingRegressor 模型进行回归分析。
  • 3.通过交叉验证评估模型的性能,计算 MAE、MSE、MBE、RMSE 和 R^2 分数。
  • 4.使用 matplotlib 绘制训练集和测试集的真实值与预测值的折线图和散点图,直观展示模型的预测效果。

九种回归算法

英文名称 (代码调用) 中文名称 说明
LinearRegression 线性回归 最简单的回归算法,假设目标变量与特征之间存在线性关系。适用于线性可分的数据集。
ElasticNet 弹性网络回归 结合了 L1 和 L2 正则化,是 Lasso 和 Ridge 的结合。适用于特征数量较多且存在多重共线性的数据集。
Lasso Lasso 回归 使用 L1 正则化,可以进行特征选择,使一些特征的系数为零。适用于特征数量较多且需要稀疏解的数据集。
Ridge 岭回归 使用 L2 正则化,可以处理多重共线性问题。适用于特征数量较多且存在多重共线性的数据集。
DecisionTreeRegressor 决策树回归器 基于决策树的回归算法,可以处理非线性关系。适用于特征数量较少且数据分布不均匀的数据集。
KNeighborsRegressor K 近邻回归器 基于 K 近邻的回归算法,预测目标值是其最近邻点的平均值。适用于数据点分布较为均匀的数据集。
SVR 支持向量回归器 基于支持向量机的回归算法,可以处理非线性关系。适用于特征数量较多且数据分布复杂的数据集。
GradientBoostingRegressor 梯度提升回归器 基于梯度提升的回归算法,通过组合多个弱学习器来提高预测性能。适用于特征数量较多且数据分布复杂的数据集。
ExtraTreesRegressor 额外树回归器 基于随机森林的回归算法,通过组合多个决策树来提高预测性能。适用于特征数量较多且数据分布复杂的数据集。

一、数据集介绍

波士顿房价数据集是机器学习领域中经典的回归分析数据集,用于房价预测,监督学习中的回归问题,目标是通过多个特征预测波士顿地区的房屋中位数价格(MEDV)。共 506 条样本(观测值),每条样本对应一个波士顿城镇的统计数据。典型的单变量回归任务,目标是通过 13 个特征预测MEDV。数据集字段(特征)说明如下

序号 特征名称 名称中文 说明
1 CRIM 人均犯罪率 城镇每千人犯罪次数
2 ZN 住宅用地比例 25,000 平方英尺以上住宅用地比例(规划限制,非住宅用地比例)
3 INDUS 非零售商业用地比例 城镇非零售商业用地比例(商业活动密度)
4 CHAS 查尔斯河虚拟变量 1 = 邻近河流,0 = 不邻近
5 NOX 氮氧化物浓度 ppm,空气质量指标
6 RM 平均房间数 每套住宅的平均房间数
7 AGE 房龄较老房屋占比 1940 年前建成的自住房屋比例
8 DIS 就业中心加权距离 到波士顿 5 个就业中心的加权距离(通勤便利性)
9 RAD 辐射状公路可达性指数 交通便利程度,指数越高表示越容易到达高速公路
10 TAX 房产税税率 每 1 万美元房产的年税额
11 PRTATIO 师生比 城镇师生比(教育资源指标)
12 B 黑人比例计算值 公式:B = 1000(Bk - 0.63)^2,其中Bk为黑人比例
13 LSTAT 低收入人群比例 %,社会经济地位指标
14 MEDV 房屋中位数价格 单位:千美元,目标变量

1.各特征分布情况

二、算法评估

尝试了数据标准化没有很大提升。

1.九种回归算法RMSE 和 R^2 比较

图中的蓝色柱子表示 RMSE,红色柱子表示 R^2 分数。通过这个图,可以直观地比较不同模型的性能。

2.训练集和测试集预测值和真实值可视化

梯度提升回归树模型GradientBoostingRegressor和随机搜索最佳参数,均方根误差RMSE为2.725 (0.540),决定系数R2为 0.903 (0.035)。

3.训练集和测试集预测值和真实值散点图

bash 复制代码
Best parameters: {'learning_rate': 0.12829684257109286, 'max_depth': 5, 'max_features': 'log2', 'min_samples_leaf': 3, 'min_samples_split': 5, 'n_estimators': 122, 'random_state': 42}
Best cross-validation score: -7.715896901281501
MAE: -1.943 (0.285)
MSE: -7.716 (3.060)
MBE: 0.008 (0.223)
RMSE: 2.725 (0.540)
R2: 0.903 (0.035)

4.特征重要性

5.加入主成分分析PCA降维

**  评估结果不好,不适合使用降维方法。(pca = PCA
  n_components=3 # 降维到 3 个主成分
  X_pca = pca.fit_transform(X))**


bash 复制代码
Model: GradientBoostingRegressor
MAE: -4.632 (0.564)
MSE: -48.134 (15.559)
MBE: -0.023 (0.886)
RMSE: 6.845 (1.202)
R2: 0.413 (0.152)

6.网格搜索(Grid Search)最佳参数组合



bash 复制代码
Best parameters: {'learning_rate': 0.1, 'max_depth': 6, 'max_features': 'sqrt', 'n_estimators': 160, 'random_state': 7}
Best cross-validation score: -8.265665640433037
MAE: -1.951 (0.287)
MSE: -8.266 (3.460)
MBE: -0.011 (0.315)
RMSE: 2.813 (0.595)
R2: 0.897 (0.039)

7.随机搜索(Random Search)

在前参数范围基础上寻找更好一点参数。结果在最前面1

三、完整代码

python 复制代码
from pandas import read_csv
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression, ElasticNet, Lasso, Ridge
from sklearn.tree import DecisionTreeRegressor
from sklearn.neighbors import KNeighborsRegressor
from sklearn.svm import SVR
from sklearn.ensemble import GradientBoostingRegressor, ExtraTreesRegressor
from sklearn.metrics import mean_squared_error
import numpy as np
import matplotlib.pyplot as plt

# 导入数据
filename = 'housing.csv'
names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS',
         'RAD', 'TAX', 'PRTATIO', 'B', 'LSTAT', 'MEDV']
data = read_csv(filename, names=names, delim_whitespace=True)

# 将数据分为输入数据和输出结果
array = data.values
X = array[:, 0:13]  # 输入特征
Y = array[:, 13]    # 输出目标变量

# 设置交叉验证参数
n_splits = 10
seed = 7
kfold = KFold(n_splits=n_splits, shuffle=True, random_state=seed)

# 定义多个回归模型
models = {
    'LinearRegression': LinearRegression(),
    'ElasticNet': ElasticNet(),
    'Lasso': Lasso(),
    'Ridge': Ridge(),
    'DecisionTreeRegressor': DecisionTreeRegressor(),
    'KNeighborsRegressor': KNeighborsRegressor(),
    'SVR': SVR(),
    'GradientBoostingRegressor': GradientBoostingRegressor(),
    'ExtraTreesRegressor': ExtraTreesRegressor()
}

# 定义评分标准
scoring = ['neg_mean_absolute_error', 'neg_mean_squared_error', 'r2']

# 定义自定义评分函数
def mean_bias_error(y_true, y_pred):
    return np.mean(y_pred - y_true)

def root_mean_squared_error(y_true, y_pred):
    return np.sqrt(mean_squared_error(y_true, y_pred))

# 评估每个模型
model_names = []
rmse_scores = []
r2_scores = []

for name, model in models.items():
    print(f"Model: {name}")

    # 计算MAE
    result_mae = cross_val_score(model, X, Y, cv=kfold, scoring=scoring[0])
    print('MAE: %.3f (%.3f)' % (result_mae.mean(), result_mae.std()))

    # 计算MSE
    result_mse = cross_val_score(model, X, Y, cv=kfold, scoring=scoring[1])
    print('MSE: %.3f (%.3f)' % (result_mse.mean(), result_mse.std()))

    # 计算R^2
    result_r2 = cross_val_score(model, X, Y, cv=kfold, scoring=scoring[2])
    print('R2: %.3f (%.3f)' % (result_r2.mean(), result_r2.std()))

    # 计算MBE和RMSE
    mbe_scores = []
    rmse_scores_temp = []
    for train_index, test_index in kfold.split(X):
        X_train, X_test = X[train_index], X[test_index]
        Y_train, Y_test = Y[train_index], Y[test_index]

        model.fit(X_train, Y_train)
        Y_pred = model.predict(X_test)

        mbe_scores.append(mean_bias_error(Y_test, Y_pred))
        rmse_scores_temp.append(root_mean_squared_error(Y_test, Y_pred))

    print('MBE: %.3f (%.3f)' % (np.mean(mbe_scores), np.std(mbe_scores)))
    print('RMSE: %.3f (%.3f)' % (np.mean(rmse_scores_temp), np.std(rmse_scores_temp)))
    print("-" * 50)

    # 保存模型名称、RMSE 和 R^2 分数
    model_names.append(name)
    rmse_scores.append(np.mean(rmse_scores_temp))
    r2_scores.append(np.mean(result_r2))

# 绘制柱状图
fig, ax1 = plt.subplots(figsize=(12, 8))

# 设置柱状图的位置
bar_width = 0.35
index = np.arange(len(model_names))

# 绘制 RMSE 柱状图
ax1.bar(index, rmse_scores, bar_width, label='RMSE', color='tab:blue')
ax1.set_xlabel('Model')
ax1.set_ylabel('RMSE', color='tab:blue')
ax1.tick_params(axis='y', labelcolor='tab:blue')

# 创建第二个坐标轴
ax2 = ax1.twinx()

# 绘制 R^2 柱状图
ax2.bar(index + bar_width, r2_scores, bar_width, label='R^2', color='tab:red')
ax2.set_ylabel('R^2', color='tab:red')
ax2.tick_params(axis='y', labelcolor='tab:red')

# 添加标题和标签
ax1.set_title('Comparison of RMSE and R^2 for Different Models')
ax1.set_xticks(index + bar_width / 2)
ax1.set_xticklabels(model_names, rotation=45, ha='right')
ax1.legend(loc='upper left')
ax2.legend(loc='upper right')

plt.tight_layout()
plt.show()