深入探索Python呆板学习算法:(加州房价预测)XGBoost 与贝叶斯优化驱动的 ...

打印 上一主题 下一主题

主题 997|帖子 997|积分 2991

深入探索Python呆板学习算法:(加州房价预测)XGBoost 与贝叶斯优化驱动的鲁棒性集成模子

一、弁言

在房地产市场分析和预测范畴,准确预测房价不停是研究的热门和难点。加州作为美国经济发达且房地产市场活泼的地区,其房价受到多种因素的综合影响,如地理位置、房屋特性、周边配套等。通过呆板学习方法构建房价预测模子,可以资助投资者、购房者和政策制定者更好地了解市场动态,做出公道的决策。
本文将详细介绍一个基于Python实现的加州房价预测全流程模子,涵盖数据加载与预处理、特性工程、特性选择、超参数调优、模子训练、评估以及可视化等多个关键步骤。通过对这些步骤的深入分析,我们可以了解如何运用呆板学习技能解决实际的房价预测问题,并学习到一些实用的本事和方法。
数据文件

20640条数据

  1. longitude经度       
  2. latitude纬度       
  3. housing_median_age住房年龄中位数       
  4. total_rooms总房间数       
  5. total_bedrooms总卧室数       
  6. population人口数       
  7. households家庭数       
  8. median_income收入中位数       
  9. median_house_value房屋价值中位数       
  10. ocean_proximity海洋邻近性
复制代码
二、环境预备与依靠库介绍

2.1 环境预备

在开始实现加州房价预测模子之前,我们必要搭建相应的Python环境。建议利用Anaconda来管理Python环境和安装依靠库,由于Anaconda提供了丰富的科学计算和数据分析库,而且可以方便地创建和管理虚拟环境。
以下是创建和激活虚拟环境的命令:
  1. conda create -n housing_prediction python=3.8
  2. conda activate housing_prediction
复制代码
我用的Pycharm,但是用jupyter notebook会方便操作
2.2 依靠库介绍

本项目利用了多个Python库,下面临这些库的功能和作用进行简要介绍:


  • NumPy:是Python中用于科学计算的底子库,提供了高效的多维数组对象和各种数学函数,可用于处理和计算大规模的数值数据。
  • Pandas:是一个强大的数据处理和分析库,提供了DataFrame和Series等数据结构,方便进行数据的读取、洗濯、转换和分析。
  • Matplotlib:是Python中常用的绘图库,可用于创建各种静态、交互式的图表,如折线图、柱状图、散点图等。
  • Seaborn:是基于Matplotlib的高级数据可视化库,提供了更美观、更简洁的绘图风格和接口,能够快速创建高质量的统计图表。
  • SHAP:是一个用于解释呆板学习模子预测效果的库,通过计算特性的SHAP值,可以直观地了解每个特性对模子预测效果的影响水平。
  • Joblib:是Python中用于并行计算和持久化的库,可用于生存和加载呆板学习模子,方便模子的复用和部署。
  • Scikit-learn:是Python中最常用的呆板学习库,提供了丰富的呆板学习算法和工具,如数据预处理、特性选择、模子训练、评估等。
  • XGBoost:是一个高效的梯度提升库,在呆板学习角逐和实际应用中都有广泛的应用,具有快速、准确、可扩展性强等优点。
  • Bayes_opt:是一个用于贝叶斯优化的库,可用于自动调整呆板学习模子的超参数,提高模子的性能。
以下是安装这些依靠库的命令:
requirements.txt
  1. numpy==2.1.3
  2. pandas==2.2.3
  3. matplotlib==3.10.1
  4. seaborn==0.13.2
  5. shap==0.47.0
  6. joblib==1.4.2
  7. scikit-learn==1.6.1
  8. xgboost==2.1.4
  9. bayes_opt==2.0.3
复制代码
pip install -r requirements.txt
三、数据加载与预处理

3.1 数据加载

在代码中,我们利用pandas库的read_csv函数从CSV文件中加载加州房价数据集。数据加载部门的代码如下:
  1. def load_data(self) -> pd.DataFrame:
  2.     """数据加载与预处理"""
  3.     try:
  4.         df = pd.read_csv(DATA_PATHS["raw_data"])
  5.         logger.info(" 初始数据行数: %d", len(df))
  6.         # 数据校验
  7.         expected_cols = ['longitude', 'latitude', 'housing_median_age', 'total_rooms',
  8.                          'total_bedrooms', 'population', 'households', 'median_income',
  9.                          'median_house_value', 'ocean_proximity']
  10.         if list(df.columns) != expected_cols:
  11.             raise ValueError(f"CSV列名不匹配,期待顺序:{expected_cols}")
  12.         # 处理异常值(动态分位数)
  13.         df = self._handle_outliers(df)
  14.         logger.info(" 异常值处理后行数: %d", len(df))
  15.         # 填补缺失值
  16.         df = self._impute_missing(df)
  17.         logger.info(" 缺失值填补后行数: %d", len(df))
  18.         return df
  19.     except Exception as e:
  20.         logger.error(" 数据加载失败: %s", str(e))
  21.         raise
复制代码
在数据加载过程中,我们起首记录了初始数据的行数,然后对数据的列名进行了校验,确保数据的列名与预期一致。如果列名不匹配,将抛出ValueError异常。
3.2 异常值处理

异常值是指数据会合与其他数据点显着不同的值,可能会对模子的训练和预测效果产生负面影响。在本项目中,我们利用动态分位数的方法处理房价的异常值。详细来说,我们计算房价的0.01和0.99分位数,然后过滤掉低于0.01分位数和高于0.99分位数的数据点。异常值处理部门的代码如下:
  1. def _handle_outliers(self, df: pd.DataFrame) -> pd.DataFrame:
  2.     """动态异常值处理"""
  3.     # 房价过滤(基于分位数)
  4.     price_q_low = df['median_house_value'].quantile(0.01)
  5.     price_q_high = df['median_house_value'].quantile(0.99)
  6.     df = df[(df['median_house_value'] >= price_q_low) &
  7.             (df['median_house_value'] <= price_q_high)]
  8.     return df
复制代码
3.3 缺失值填补

数据会合可能存在缺失值,必要进行填补处理。在本项目中,我们利用IterativeImputer进行多重填补,该方法基于迭代的方式,通过创建一个回归模子来预测缺失值。详细来说,我们利用RandomForestRegressor作为估计器,将max_iter参数从默认的10增长到20,以解决收敛问题。同时,我们还添加了维度检查,确保填补后的数据维度与原始数据维度一致。缺失值填补部门的代码如下:
  1. def _impute_missing(self, df: pd.DataFrame) -> pd.DataFrame:
  2.     """高级缺失值填补(关键修正部分)"""
  3.     if df['total_bedrooms'].isnull().sum() > 0:
  4.         logger.info(" 检测到缺失值,开始多重填补...")
  5.         # 修正1:增加迭代次数解决收敛问题
  6.         imputer = IterativeImputer(
  7.             estimator=RandomForestRegressor(n_estimators=50),
  8.             max_iter=20,  # 从10增加到20
  9.             random_state=42
  10.         )
  11.         # 修正2:添加维度检查
  12.         imputed_values = imputer.fit_transform(
  13.             df[['total_bedrooms', 'total_rooms', 'households']]
  14.         )
  15.         # 检查维度一致性
  16.         if imputed_values.shape[0] != df.shape[0]:
  17.             logger.error(" 填补维度不匹配: 输入数据%d行,输出%d行",
  18.                          df.shape[0], imputed_values.shape[0])
  19.             raise ValueError("填补维度不一致")
  20.         # 修正3:正确维度转换
  21.         df['total_bedrooms'] = imputed_values[:, 0]
  22.         logger.info(" 缺失值填补完成,剩余缺失值数量: %d",
  23.                     df['total_bedrooms'].isnull().sum())
  24.     return df
复制代码
四、特性工程

特性工程是呆板学习中非常告急的一步,它可以通过对原始数据进行转换和组合,提取出更有价值的特性,从而提高模子的性能。在本项目中,我们进行了以下几个方面的特性工程:
4.1 底子特性构建

我们计算了每个家庭的房间数和每个房间的卧室数,以反映房屋的居住密度和空间利用环境。为了防止除零错误,我们对total_rooms和total_bedrooms进行了处理。底子特性构建部门的代码如下:
  1. # 防止除零错误
  2. df['total_rooms'] = df['total_rooms'].replace(0, 1e-6)
  3. df['total_bedrooms'] = df['total_bedrooms'].clip(lower=0.1)
  4. # 基础特征
  5. df['rooms_per_household'] = df['total_rooms'] / df['households']
  6. df['bedrooms_per_room'] = df['total_bedrooms'] / df['total_rooms']
复制代码
4.2 地理特性计算

地理位置是影响房价的告急因素之一。我们利用Haversine公式计算每个房屋到旧金山的距离,作为地理特性。地理特性计算部门的代码如下:
  1. def _add_geo_features(self, df: pd.DataFrame) -> pd.DataFrame:
  2.     """精确地理特征计算"""
  3.     san_francisco_coord = (37.7749, -122.4194)
  4.     R = 6371  # 地球半径(千米)
  5.     lat1 = np.radians(df['latitude'])
  6.     lon1 = np.radians(df['longitude'])
  7.     lat2, lon2 = np.radians(san_francisco_coord[0]), np.radians(san_francisco_coord[1])
  8.     dlon = lon2 - lon1
  9.     dlat = lat2 - lat1
  10.     a = np.sin(dlat / 2) ** 2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon / 2) ** 2
  11.     c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))
  12.     df['dist_to_sf_km'] = R * c
  13.     return df
复制代码
4.3 分箱处理

分箱处理是将连续变量离散化的一种方法,可以减少数据的噪声和异常值的影响。我们利用KBinsDiscretizer对房屋的中位年事进行分箱处理,将其分为5个等级。分箱处理部门的代码如下:
  1. def _binning_features(self, df: pd.DataFrame) -> pd.DataFrame:
  2.     """安全分箱处理"""
  3.     try:
  4.         binner = KBinsDiscretizer(n_bins=5, encode='ordinal', strategy='quantile')
  5.         df['housing_age_bin'] = binner.fit_transform(
  6.             df[['housing_median_age']]
  7.         ).astype(int)
  8.     except ValueError as e:
  9.         logger.warning("分箱失败: %s,使用原始特征", str(e))
  10.     return df
复制代码
4.4 分类变量编码

数据会合的ocean_proximity是一个分类变量,我们利用pandas的get_dummies函数对其进行独热编码,将其转换为数值特性。分类变量编码部门的代码如下:
  1. # 分类变量编码
  2. return pd.get_dummies(df, columns=['ocean_proximity'], drop_first=True)
复制代码
五、特性选择

特性选择是从原始特性中选择出最相关、最有价值的特性,以减少特性维度,提高模子的训练效率和泛化本领。在本项目中,我们利用递归特性消除(Recursive Feature Elimination,RFE)方法进行特性选择。详细来说,我们利用RFECV类,以XGBRegressor作为估计器,通过交织验证选择最优的特性子集。特性选择部门的代码如下:
  1. def feature_selection(self, X: pd.DataFrame, y: pd.Series) -> pd.DataFrame:
  2.     """递归特征消除(带异常处理)"""
  3.     try:
  4.         self.feature_selector = RFECV(
  5.             estimator=XGBRegressor(),
  6.             step=1,
  7.             cv=5,
  8.             scoring='neg_mean_absolute_error',
  9.             min_features_to_select=10
  10.         )
  11.         X_selected = self.feature_selector.fit_transform(X, y)
  12.         self.feature_names = X.columns[self.feature_selector.support_]
  13.         logger.info("特征选择完成,保留特征数:%d", len(self.feature_names))
  14.         return X_selected
  15.     except Exception as e:
  16.         logger.error("特征选择失败: %s,使用原始特征", str(e))
  17.         return X.values
复制代码
六、超参数调优

超参数是呆板学习模子中必要手动设置的参数,不同的超参数组合会对模子的性能产生显著影响。在本项目中,我们利用贝叶斯优化方法对XGBRegressor的超参数进行调优。贝叶斯优化是一种基于概率模子的优化方法,通过不断地探索超参数空间,找到最优的超参数组合。超参数调优部门的代码如下:
  1. def hyperparameter_tuning(self, X: np.ndarray, y: np.ndarray) -> Dict:
  2.     """鲁棒的贝叶斯优化"""
  3.     def xgb_cv(max_depth, learning_rate, n_estimators, subsample):
  4.         params = {
  5.             'max_depth': int(round(max_depth)),
  6.             'learning_rate': max(learning_rate, 0.001),
  7.             'n_estimators': int(round(n_estimators)),
  8.             'subsample': max(min(subsample, 1), 0.1),
  9.             'eval_metric': 'mae'
  10.         }
  11.         try:
  12.             cv_scores = cross_val_score(
  13.                 XGBRegressor(**params), X, y,
  14.                 cv=5, scoring='neg_mean_absolute_error', n_jobs=-1
  15.             )
  16.             return cv_scores.mean()
  17.         except Exception as e:
  18.             logger.warning("参数调优失败: %s", str(e))
  19.             return -np.inf
  20.     optimizer = BayesianOptimization(
  21.         f=xgb_cv,
  22.         pbounds={
  23.             'max_depth': (3, 10),
  24.             'learning_rate': (0.01, 0.3),
  25.             'n_estimators': (100, 1000),
  26.             'subsample': (0.5, 1)
  27.         },
  28.         random_state=42,
  29.         allow_duplicate_points=True
  30.     )
  31.     # 移除不支持的参数设置
  32.     # optimizer.set_gp_params(n_jobs=-1)
  33.     optimizer.maximize(init_points=5, n_iter=5)
  34.     if not optimizer.res:
  35.         raise RuntimeError("贝叶斯优化失败,无有效结果")
  36.     self.best_params = optimizer.max['params']
  37.     logger.info("最佳参数:%s", self.best_params)
  38.     return self.best_params
复制代码
七、模子训练

在完成特性选择和超参数调优后,我们利用集成学习的方法训练一个堆叠模子(Stacking Model)。堆叠模子是一种将多个底子模子的预测效果作为输入,再通过一个元模子进行最终预测的模子。在本项目中,我们利用XGBRegressor和RandomForestRegressor作为底子模子,LassoCV作为元模子。模子训练部门的代码如下:
  1. def train_stacking_model(self, X: np.ndarray, y: np.ndarray):
  2.     """训练集成模型"""
  3.     try:
  4.         base_models = [
  5.             ('xgb', XGBRegressor(**{
  6.                 'max_depth': int(self.best_params['max_depth']),
  7.                 'learning_rate': self.best_params['learning_rate'],
  8.                 'n_estimators': int(self.best_params['n_estimators']),
  9.                 'subsample': self.best_params['subsample']
  10.             })),
  11.             ('rf', RandomForestRegressor(
  12.                 n_estimators=200,
  13.                 max_depth=8,
  14.                 n_jobs=-1
  15.             ))
  16.         ]
  17.         self.model = StackingRegressor(
  18.             estimators=base_models,
  19.             final_estimator=LassoCV(cv=5),
  20.             cv=3,
  21.             n_jobs=-1
  22.         )
  23.         logger.info("开始训练Stacking模型...")
  24.         self.model.fit(X, y)
  25.         self._is_trained = True
  26.         return self.model
  27.     except Exception as e:
  28.         logger.error("模型训练失败: %s", str(e))
  29.         self._is_trained = False
  30.         raise
复制代码
八、模子评估

模子评估是衡量模子性能的告急步骤,通过计算不同的评估指标,我们可以了解模子的预测本领和泛化本领。在本项目中,我们利用以下几个评估指标来评估模子的性能:


  • 匀称绝对偏差(MAE):预测值与真实值之间的匀称绝对偏差,反映了模子预测的匀称偏差水平。
  • 均方根偏差(RMSE):预测值与真实值之间的均方根偏差,对异常值比力敏感,反映了模子预测的团体偏差水平。
  • 决定系数(R²):体现模子对数据的拟合水平,取值范围为[0, 1],越靠近1体现模子拟合效果越好。
  • 匀称绝对百分比偏差(MAPE):预测值与真实值之间的匀称绝对百分比偏差,反映了模子预测的相对偏差水平。
  • 准确率(偏差≤20%):预测值与真实值之间的偏差在20%以内的样本占总样本的比例,反映了模子的预测准确性。
模子评估部门的代码如下:
  1. def evaluate(self, y_true: np.ndarray, y_pred: np.ndarray) -> Dict:
  2.     """综合模型评估"""
  3.     if not self._is_trained:
  4.         raise RuntimeError("模型未训练")
  5.     metrics = {
  6.             'MAE': mean_absolute_error(y_true, y_pred),
  7.             'RMSE': np.sqrt(mean_squared_error(y_true, y_pred)),
  8.             'R²': r2_score(y_true, y_pred),
  9.             'MAPE': mean_absolute_percentage_error(y_true, y_pred),
  10.             '准确率(误差≤20%)': np.mean(np.abs((y_pred - y_true) / y_true) <= 0.2) * 100
  11.         }
复制代码
九、运行效果



  1. MAE: 28651.010141975672
  2. RMSE: 44915.080348747775
  3. R²: 0.8543913449901033
  4. MAPE: 0.1496618109522733
  5. 准确率(误差≤20%): 76.40009782342871
  6. 示例预测结果:171846.38 vs 真实值:178100.00
复制代码
可以调参重新运利用模子准确率更高(本文只给出了部门代码



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

罪恶克星

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表