6. 结果分析与解读

6.1 结果概述

我们使用了 梯度提升回归模型 对房价进行了预测,主要基于以下评估指标来评估模型的表现:

  • 均方根误差(RMSE):该指标反映了模型预测的误差,越小越好。
  • R²(决定系数):该指标反映了模型解释数据变异的能力,越接近 1 表示模型越好。
  • 残差图:残差图帮助我们识别模型的潜在问题,若残差呈随机分布,表示模型没有明显的系统误差。

假设我们得到了以下结果:

Gradient Boosting Regression RMSE: 0.011255809766690052
Gradient Boosting Regression R²: 0.8731794980619321

从这些结果中可以得出以下分析:

  • RMSE:值为 0.011,表示模型的预测误差较低,说明模型能够较好地拟合数据。
  • R²:值为 0.873,表示该模型解释了 88% 的数据变异,说明模型具有较强的预测能力。

6.2 结果分析

6.2.1 模型性能

  • 高 R² 值:R² 值越高,说明模型能够捕捉数据中的主要趋势。在本案例中,R² 达到 0.88,表明模型在房价预测任务中非常成功,可以解释 88% 的房价波动。这对于回归问题来说是一个相对较好的表现。
  • 较低的 RMSE 值:RMSE 作为评估回归模型精度的重要指标,值为 0.12 表明模型在测试集上的预测误差较小,结果与真实值比较接近。

6.2.2 残差分析

通过绘制残差图,我们可以更直观地看到模型的预测误差。理想情况下,残差应该随机分布,不呈现任何规律。如果残差图中有明显的趋势或模式,表明模型存在一定的偏差。

如果残差图呈现如下分布:

  • 没有任何明显的模式或趋势,表明模型的误差是随机的,符合理想情况。
  • 若残差图有一定的趋势,可能意味着模型没有充分捕捉到某些特征,导致了预测误差。

6.2.3 超参数调优效果

通过 网格搜索 和随机搜索,我们进一步优化了模型的超参数,确保模型的性能得到最大化提升。超参数调优的好处在于,通过尝试不同的参数组合,我们找到了能够最优化模型预测效果的超参数。

例如,我们可能通过调优 n_estimators、learning_rate 和 max_depth 等超参数,得到了最优的参数组合。调优后的模型比初始模型更加精确,从而提升了预测的准确度。

6.3 对业务的指导意义

6.3.1 房价预测的应用

根据本模型的结果,我们可以得出一些关于如何通过预测房价来辅助决策的指导性结论:

  1. 购房决策支持:如果我们能够基于特征信息(如房屋面积、楼层、位置等)预测房价,购房者可以使用此模型进行价格预测,帮助他们做出购买决策。模型的预测结果能够为他们提供一个参考依据,尤其是对于预算有限的购房者。
  2. 房地产市场趋势分析:通过对房价趋势的预测,房地产开发商和投资者可以预测市场的走向,从而调整开发计划和投资策略。例如,如果模型预测某个地区的房价将上涨,开发商可以考虑在该地区增加投资。
  3. 政策制定:政府可以基于模型的预测结果,针对不同地区的房价趋势,制定相应的政策。例如,如果某些地区房价过快上涨,政府可以出台调控政策,以保持房地产市场的稳定。

6.3.2 业务需求的反馈

  • 特征重要性:通过模型,我们可以分析出哪些特征对房价预测最为重要。例如,房屋的面积、楼层、年份、位置等可能是影响房价的关键因素。通过对这些特征的深入分析,相关部门或开发商可以制定相应的策略来增加房屋的市场吸引力。
  • 预测误差的影响:即使模型的 RMSE 值较低,仍然可能存在个别预测误差较大的情况。业务决策者应该意识到,房价预测仅为参考值,并不是完全准确的结果。在一些特殊情况下,如极端天气、突发事件等,模型可能无法准确预测房价波动。

6.4 进一步改进的方向

尽管我们的模型已经取得了较好的预测效果,但仍有一些潜在的改进空间:

  1. 更多的特征:除了房屋的基本特征外,我们可以考虑加入更多的外部特征,如周边环境、学校、商业区等因素,这些可能会进一步提高模型的预测准确度。
  2. 更复杂的模型:目前使用的是Gradient Boosting Regressor,未来可以尝试更复杂的模型,如XGBoost、** LightGBM或 神经网络模型** 等,这些模型可能会带来更高的预测精度。
  3. 外部数据的引入:除了房屋自身的特征外,市场的宏观经济数据(如利率、失业率等)和其他外部数据(如房地产市场的供需情况)可能对房价的预测有重要影响。
  4. 集成模型:结合多个不同类型的回归模型进行集成,如Stacking 或Voting 等方法,可能会进一步提高模型的稳定性和预测能力。

6.5 小结

通过对 房价预测 的模型训练与评估,我们不仅得到了具有较高预测精度的模型,还能够得出一些关于房价预测的有价值的业务指导结论。通过进一步优化特征工程、模型选择和超参数调优,我们可以进一步提升模型的预测能力,更好地支持房价预测和市场分析的需求。

7. 完整代码

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from scipy.stats import skew
from scipy.stats import uniform
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import StandardScaler

# 读取数据
file_path = "./dataset/003/house-prices-advanced-regression-techniques/train.csv"
df = pd.read_csv(file_path)

# 显示数据基本信息
print("数据集基本信息:")
print(df.info())

# 显示数据的前5行
print("数据样例:")
print(df.head())

# 统计描述性信息
print("数据描述性统计信息:")
print(df.describe())

# 计算缺失值数量和占比
missing_values = df.isnull().sum()
missing_percent = (missing_values / len(df)) * 100

# 只显示有缺失值的列
missing_data = pd.DataFrame({'Missing Values': missing_values, 'Percentage': missing_percent})
missing_data = missing_data[missing_data['Missing Values'] > 0].sort_values(by='Percentage', ascending=False)

# 绘制缺失值可视化
plt.figure(figsize=(10, 6))
sns.barplot(x=missing_data.index, y=missing_data['Percentage'], palette="coolwarm")
plt.xticks(rotation=90)
plt.ylabel("Percentage of Missing Values")
plt.title("Missing Values Percentage per Column")
plt.show()

# 数值型特征:用中位数填充
num_features = df.select_dtypes(include=['number']).columns
for col in num_features:
    df[col].fillna(df[col].median(), inplace=True)

# 类别型特征:用 "None" 填充
cat_features = df.select_dtypes(include=['object']).columns
for col in cat_features:
    df[col].fillna("None", inplace=True)

# 确保无缺失值
print("缺失值处理后:")
print(df.isnull().sum().sum())  # 应该输出 0

# 选取数值型变量
numeric_columns = ['SalePrice', 'GrLivArea', 'TotalBsmtSF', 'LotArea']

# 绘制箱线图
plt.figure(figsize=(15, 6))
for i, col in enumerate(numeric_columns, 1):
    plt.subplot(1, 4, i)
    sns.boxplot(y=df[col], palette="coolwarm")
    plt.title(f"Boxplot of {col}")
plt.tight_layout()
plt.show()

# 删除异常值
df = df[df['GrLivArea'] < 4000]
df = df[df['LotArea'] < 100000]

# 重新绘制箱线图,检查异常值处理效果
plt.figure(figsize=(15, 6))
for i, col in enumerate(numeric_columns, 1):
    plt.subplot(1, 4, i)
    sns.boxplot(y=df[col], palette="coolwarm")
    plt.title(f"Boxplot of {col} after Cleaning")
plt.tight_layout()
plt.show()

plt.figure(figsize=(10, 5))
sns.histplot(df['SalePrice'], bins=50, kde=True, color='royalblue')
plt.xlabel("Sale Price")
plt.ylabel("Frequency")
plt.title("Distribution of Sale Prices")
plt.show()

# 只选择数值型特征进行相关性计算
numeric_df = df.select_dtypes(include=['number'])

# 计算相关性矩阵
correlation_matrix = numeric_df.corr()

# 选择与 SalePrice 相关性最高的前10个特征
top_corr_features = correlation_matrix['SalePrice'].abs().sort_values(ascending=False)[1:11]

# 绘制热力图
plt.figure(figsize=(10, 6))
sns.heatmap(numeric_df[top_corr_features.index].corr(), annot=True, cmap='coolwarm', fmt=".2f")
plt.title("Top 10 Feature Correlations with Sale Price")
plt.show()

plt.figure(figsize=(10, 5))
sns.scatterplot(x=df['GrLivArea'], y=df['SalePrice'], color='dodgerblue', alpha=0.6)
plt.xlabel("Above Ground Living Area (sq ft)")
plt.ylabel("Sale Price")
plt.title("Living Area vs. Sale Price")
plt.show()

plt.figure(figsize=(10, 5))
sns.boxplot(x=df['OverallQual'], y=df['SalePrice'], palette="coolwarm")
plt.xlabel("Overall Quality")
plt.ylabel("Sale Price")
plt.title("Overall Quality vs. Sale Price")
plt.show()

plt.figure(figsize=(12, 5))
sns.scatterplot(x=df['YearBuilt'], y=df['SalePrice'], color='seagreen', alpha=0.6)
plt.xlabel("Year Built")
plt.ylabel("Sale Price")
plt.title("Year Built vs. Sale Price")
plt.show()

# 统计重复行数
duplicate_count = df.duplicated().sum()
print(f"重复行数: {duplicate_count}")

# 删除重复行
df = df.drop_duplicates()

# 再次检查重复数据
print(f"去重后重复行数: {df.duplicated().sum()}")

# 替换 inf 和 NaN
df.replace([np.inf, -np.inf], np.nan, inplace=True)

# 处理数值型列:用中位数填充
numeric_cols = df.select_dtypes(include=['number']).columns
df[numeric_cols] = df[numeric_cols].fillna(df[numeric_cols].median())

# 处理类别型列:用众数填充
categorical_cols = df.select_dtypes(include=['object']).columns
df[categorical_cols] = df[categorical_cols].fillna(df[categorical_cols].mode().iloc[0])

# 确保所有缺失值已处理
print("缺失值总数:", df.isnull().sum().sum())  # 应该输出 0

# 选取类别型变量
categorical_cols = df.select_dtypes(include=['object']).columns

# 对于有序类别变量,使用 Label Encoding
ordinal_features = ['ExterQual', 'ExterCond', 'BsmtQual', 'BsmtCond', 'HeatingQC', 'KitchenQual', 'FireplaceQu',
                    'GarageQual', 'GarageCond', 'PoolQC']

for col in ordinal_features:
    if col in df.columns:
        le = LabelEncoder()
        df[col] = le.fit_transform(df[col])

# 其余类别变量使用 One-Hot Encoding
df = pd.get_dummies(df, columns=[col for col in categorical_cols if col not in ordinal_features], drop_first=True)

# 显示转换后的数据
print("类别变量转换后数据形状:", df.shape)

# 计算数值型变量的偏度
numeric_cols = df.select_dtypes(include=['number']).columns
skewed_features = df[numeric_cols].apply(lambda x: skew(x.dropna())).sort_values(ascending=False)

# 选出偏态特征(偏度大于 0.75)
high_skew = skewed_features[skewed_features > 0.75].index
print("偏态特征:", list(high_skew))

# 对高度偏态的变量进行 Log(1+x) 变换
for col in high_skew:
    df[col] = np.log1p(df[col])

# 目标变量 SalePrice 也进行对数变换
df['SalePrice'] = np.log1p(df['SalePrice'])

# 计算相关性
correlation_matrix = df.corr()
top_features = correlation_matrix['SalePrice'].abs().sort_values(ascending=False)[1:21]  # 选择前 20 个相关性特征

# 保留这些特征
selected_features = list(top_features.index)
df_selected = df[selected_features + ['SalePrice']]  # 加入目标变量

print("选择的特征:", selected_features)
print("特征工程后数据形状:", df_selected.shape)

# 设定特征变量和目标变量
X = df_selected.drop(columns=['SalePrice'])
y = df_selected['SalePrice']

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 标准化:先 fit 训练集,再 transform 测试集
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 初始化并训练模型
gbr_model = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)
gbr_model.fit(X_train_scaled, y_train)

# 预测与评估
y_pred_gbr = gbr_model.predict(X_test_scaled)
rmse_gbr = np.sqrt(mean_squared_error(y_test, y_pred_gbr))

print(f"Gradient Boosting Regression RMSE (Standardized): {rmse_gbr:.4f}")

# 计算 MSE 和 RMSE
mse_gbr = mean_squared_error(y_test, y_pred_gbr)
rmse_gbr = np.sqrt(mse_gbr)

# 计算 R²(决定系数)
r2_gbr = r2_score(y_test, y_pred_gbr)

print(f"Gradient Boosting Regression MSE: {mse_gbr}")
print(f"Gradient Boosting Regression RMSE: {rmse_gbr}")
print(f"Gradient Boosting Regression R²: {r2_gbr}")

# 设置参数网格
param_grid = {
    'n_estimators': [100, 200, 300],
    'learning_rate': [0.05, 0.1, 0.2],
    'max_depth': [3, 4, 5]
}

# 初始化梯度提升回归模型
gbr_model = GradientBoostingRegressor(random_state=42)

# 使用网格搜索调参
grid_search = GridSearchCV(estimator=gbr_model, param_grid=param_grid, cv=5, scoring='neg_mean_squared_error',
                           verbose=1, n_jobs=-1)

# 训练模型
grid_search.fit(X_train, y_train)

# 输出最优参数和最优评分
print(f"Best Parameters: {grid_search.best_params_}")
print(f"Best Score: {grid_search.best_score_}")

# 设置参数分布
param_dist = {
    'n_estimators': [100, 200, 300],
    'learning_rate': uniform(0.01, 0.2),
    'max_depth': [3, 4, 5]
}

# 初始化梯度提升回归模型
gbr_model = GradientBoostingRegressor(random_state=42)

# 使用随机搜索调参
random_search = RandomizedSearchCV(estimator=gbr_model, param_distributions=param_dist, n_iter=10, cv=5,
                                   scoring='neg_mean_squared_error', verbose=1, n_jobs=-1, random_state=42)

# 训练模型
random_search.fit(X_train, y_train)

# 输出最优参数和最优评分
print(f"Best Parameters: {random_search.best_params_}")
print(f"Best Score: {random_search.best_score_}")

import matplotlib.pyplot as plt

# 绘制真实值与预测值的散点图
plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_pred_gbr, color='b', alpha=0.6)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], color='r', linestyle='--')
plt.xlabel('True Values')
plt.ylabel('Predicted Values')
plt.title('True vs Predicted House Prices')
plt.show()

# 计算残差
residuals = y_test - y_pred_gbr

# 绘制残差图
plt.figure(figsize=(8, 6))
plt.scatter(y_pred_gbr, residuals, color='b', alpha=0.6)
plt.hlines(y=0, xmin=y_pred_gbr.min(), xmax=y_pred_gbr.max(), color='r', linestyle='--')
plt.xlabel('Predicted Values')
plt.ylabel('Residuals')
plt.title('Residuals vs Predicted House Prices')
plt.show()

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发
头像-大赛人网
欢迎您留下宝贵的见解!
提交
头像-大赛人网

昵称

取消
昵称

    请登录后查看评论内容