深入探索Python呆板学习算法:(加州房价预测)XGBoost 与贝叶斯优化驱动的鲁棒性集成模子
一、弁言
在房地产市场分析和预测范畴,准确预测房价不停是研究的热门和难点。加州作为美国经济发达且房地产市场活泼的地区,其房价受到多种因素的综合影响,如地理位置、房屋特性、周边配套等。通过呆板学习方法构建房价预测模子,可以资助投资者、购房者和政策制定者更好地了解市场动态,做出公道的决策。
本文将详细介绍一个基于Python实现的加州房价预测全流程模子,涵盖数据加载与预处理、特性工程、特性选择、超参数调优、模子训练、评估以及可视化等多个关键步骤。通过对这些步骤的深入分析,我们可以了解如何运用呆板学习技能解决实际的房价预测问题,并学习到一些实用的本事和方法。
数据文件
20640条数据
- longitude经度
- latitude纬度
- housing_median_age住房年龄中位数
- total_rooms总房间数
- total_bedrooms总卧室数
- population人口数
- households家庭数
- median_income收入中位数
- median_house_value房屋价值中位数
- ocean_proximity海洋邻近性
复制代码 二、环境预备与依靠库介绍
2.1 环境预备
在开始实现加州房价预测模子之前,我们必要搭建相应的Python环境。建议利用Anaconda来管理Python环境和安装依靠库,由于Anaconda提供了丰富的科学计算和数据分析库,而且可以方便地创建和管理虚拟环境。
以下是创建和激活虚拟环境的命令:
- conda create -n housing_prediction python=3.8
- 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
- numpy==2.1.3
- pandas==2.2.3
- matplotlib==3.10.1
- seaborn==0.13.2
- shap==0.47.0
- joblib==1.4.2
- scikit-learn==1.6.1
- xgboost==2.1.4
- bayes_opt==2.0.3
复制代码 pip install -r requirements.txt
三、数据加载与预处理
3.1 数据加载
在代码中,我们利用pandas库的read_csv函数从CSV文件中加载加州房价数据集。数据加载部门的代码如下:
- def load_data(self) -> pd.DataFrame:
- """数据加载与预处理"""
- try:
- df = pd.read_csv(DATA_PATHS["raw_data"])
- logger.info(" 初始数据行数: %d", len(df))
- # 数据校验
- expected_cols = ['longitude', 'latitude', 'housing_median_age', 'total_rooms',
- 'total_bedrooms', 'population', 'households', 'median_income',
- 'median_house_value', 'ocean_proximity']
- if list(df.columns) != expected_cols:
- raise ValueError(f"CSV列名不匹配,期待顺序:{expected_cols}")
- # 处理异常值(动态分位数)
- df = self._handle_outliers(df)
- logger.info(" 异常值处理后行数: %d", len(df))
- # 填补缺失值
- df = self._impute_missing(df)
- logger.info(" 缺失值填补后行数: %d", len(df))
- return df
- except Exception as e:
- logger.error(" 数据加载失败: %s", str(e))
- raise
复制代码 在数据加载过程中,我们起首记录了初始数据的行数,然后对数据的列名进行了校验,确保数据的列名与预期一致。如果列名不匹配,将抛出ValueError异常。
3.2 异常值处理
异常值是指数据会合与其他数据点显着不同的值,可能会对模子的训练和预测效果产生负面影响。在本项目中,我们利用动态分位数的方法处理房价的异常值。详细来说,我们计算房价的0.01和0.99分位数,然后过滤掉低于0.01分位数和高于0.99分位数的数据点。异常值处理部门的代码如下:
- def _handle_outliers(self, df: pd.DataFrame) -> pd.DataFrame:
- """动态异常值处理"""
- # 房价过滤(基于分位数)
- price_q_low = df['median_house_value'].quantile(0.01)
- price_q_high = df['median_house_value'].quantile(0.99)
- df = df[(df['median_house_value'] >= price_q_low) &
- (df['median_house_value'] <= price_q_high)]
- return df
复制代码 3.3 缺失值填补
数据会合可能存在缺失值,必要进行填补处理。在本项目中,我们利用IterativeImputer进行多重填补,该方法基于迭代的方式,通过创建一个回归模子来预测缺失值。详细来说,我们利用RandomForestRegressor作为估计器,将max_iter参数从默认的10增长到20,以解决收敛问题。同时,我们还添加了维度检查,确保填补后的数据维度与原始数据维度一致。缺失值填补部门的代码如下:
- def _impute_missing(self, df: pd.DataFrame) -> pd.DataFrame:
- """高级缺失值填补(关键修正部分)"""
- if df['total_bedrooms'].isnull().sum() > 0:
- logger.info(" 检测到缺失值,开始多重填补...")
- # 修正1:增加迭代次数解决收敛问题
- imputer = IterativeImputer(
- estimator=RandomForestRegressor(n_estimators=50),
- max_iter=20, # 从10增加到20
- random_state=42
- )
- # 修正2:添加维度检查
- imputed_values = imputer.fit_transform(
- df[['total_bedrooms', 'total_rooms', 'households']]
- )
- # 检查维度一致性
- if imputed_values.shape[0] != df.shape[0]:
- logger.error(" 填补维度不匹配: 输入数据%d行,输出%d行",
- df.shape[0], imputed_values.shape[0])
- raise ValueError("填补维度不一致")
- # 修正3:正确维度转换
- df['total_bedrooms'] = imputed_values[:, 0]
- logger.info(" 缺失值填补完成,剩余缺失值数量: %d",
- df['total_bedrooms'].isnull().sum())
- return df
复制代码 四、特性工程
特性工程是呆板学习中非常告急的一步,它可以通过对原始数据进行转换和组合,提取出更有价值的特性,从而提高模子的性能。在本项目中,我们进行了以下几个方面的特性工程:
4.1 底子特性构建
我们计算了每个家庭的房间数和每个房间的卧室数,以反映房屋的居住密度和空间利用环境。为了防止除零错误,我们对total_rooms和total_bedrooms进行了处理。底子特性构建部门的代码如下:
- # 防止除零错误
- df['total_rooms'] = df['total_rooms'].replace(0, 1e-6)
- df['total_bedrooms'] = df['total_bedrooms'].clip(lower=0.1)
- # 基础特征
- df['rooms_per_household'] = df['total_rooms'] / df['households']
- df['bedrooms_per_room'] = df['total_bedrooms'] / df['total_rooms']
复制代码 4.2 地理特性计算
地理位置是影响房价的告急因素之一。我们利用Haversine公式计算每个房屋到旧金山的距离,作为地理特性。地理特性计算部门的代码如下:
- def _add_geo_features(self, df: pd.DataFrame) -> pd.DataFrame:
- """精确地理特征计算"""
- san_francisco_coord = (37.7749, -122.4194)
- R = 6371 # 地球半径(千米)
- lat1 = np.radians(df['latitude'])
- lon1 = np.radians(df['longitude'])
- lat2, lon2 = np.radians(san_francisco_coord[0]), np.radians(san_francisco_coord[1])
- dlon = lon2 - lon1
- dlat = lat2 - lat1
- a = np.sin(dlat / 2) ** 2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon / 2) ** 2
- c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))
- df['dist_to_sf_km'] = R * c
- return df
复制代码 4.3 分箱处理
分箱处理是将连续变量离散化的一种方法,可以减少数据的噪声和异常值的影响。我们利用KBinsDiscretizer对房屋的中位年事进行分箱处理,将其分为5个等级。分箱处理部门的代码如下:
- def _binning_features(self, df: pd.DataFrame) -> pd.DataFrame:
- """安全分箱处理"""
- try:
- binner = KBinsDiscretizer(n_bins=5, encode='ordinal', strategy='quantile')
- df['housing_age_bin'] = binner.fit_transform(
- df[['housing_median_age']]
- ).astype(int)
- except ValueError as e:
- logger.warning("分箱失败: %s,使用原始特征", str(e))
- return df
复制代码 4.4 分类变量编码
数据会合的ocean_proximity是一个分类变量,我们利用pandas的get_dummies函数对其进行独热编码,将其转换为数值特性。分类变量编码部门的代码如下:
- # 分类变量编码
- return pd.get_dummies(df, columns=['ocean_proximity'], drop_first=True)
复制代码 五、特性选择
特性选择是从原始特性中选择出最相关、最有价值的特性,以减少特性维度,提高模子的训练效率和泛化本领。在本项目中,我们利用递归特性消除(Recursive Feature Elimination,RFE)方法进行特性选择。详细来说,我们利用RFECV类,以XGBRegressor作为估计器,通过交织验证选择最优的特性子集。特性选择部门的代码如下:
- def feature_selection(self, X: pd.DataFrame, y: pd.Series) -> pd.DataFrame:
- """递归特征消除(带异常处理)"""
- try:
- self.feature_selector = RFECV(
- estimator=XGBRegressor(),
- step=1,
- cv=5,
- scoring='neg_mean_absolute_error',
- min_features_to_select=10
- )
- X_selected = self.feature_selector.fit_transform(X, y)
- self.feature_names = X.columns[self.feature_selector.support_]
- logger.info("特征选择完成,保留特征数:%d", len(self.feature_names))
- return X_selected
- except Exception as e:
- logger.error("特征选择失败: %s,使用原始特征", str(e))
- return X.values
复制代码 六、超参数调优
超参数是呆板学习模子中必要手动设置的参数,不同的超参数组合会对模子的性能产生显著影响。在本项目中,我们利用贝叶斯优化方法对XGBRegressor的超参数进行调优。贝叶斯优化是一种基于概率模子的优化方法,通过不断地探索超参数空间,找到最优的超参数组合。超参数调优部门的代码如下:
- def hyperparameter_tuning(self, X: np.ndarray, y: np.ndarray) -> Dict:
- """鲁棒的贝叶斯优化"""
- def xgb_cv(max_depth, learning_rate, n_estimators, subsample):
- params = {
- 'max_depth': int(round(max_depth)),
- 'learning_rate': max(learning_rate, 0.001),
- 'n_estimators': int(round(n_estimators)),
- 'subsample': max(min(subsample, 1), 0.1),
- 'eval_metric': 'mae'
- }
- try:
- cv_scores = cross_val_score(
- XGBRegressor(**params), X, y,
- cv=5, scoring='neg_mean_absolute_error', n_jobs=-1
- )
- return cv_scores.mean()
- except Exception as e:
- logger.warning("参数调优失败: %s", str(e))
- return -np.inf
- optimizer = BayesianOptimization(
- f=xgb_cv,
- pbounds={
- 'max_depth': (3, 10),
- 'learning_rate': (0.01, 0.3),
- 'n_estimators': (100, 1000),
- 'subsample': (0.5, 1)
- },
- random_state=42,
- allow_duplicate_points=True
- )
- # 移除不支持的参数设置
- # optimizer.set_gp_params(n_jobs=-1)
- optimizer.maximize(init_points=5, n_iter=5)
- if not optimizer.res:
- raise RuntimeError("贝叶斯优化失败,无有效结果")
- self.best_params = optimizer.max['params']
- logger.info("最佳参数:%s", self.best_params)
- return self.best_params
复制代码 七、模子训练
在完成特性选择和超参数调优后,我们利用集成学习的方法训练一个堆叠模子(Stacking Model)。堆叠模子是一种将多个底子模子的预测效果作为输入,再通过一个元模子进行最终预测的模子。在本项目中,我们利用XGBRegressor和RandomForestRegressor作为底子模子,LassoCV作为元模子。模子训练部门的代码如下:
- def train_stacking_model(self, X: np.ndarray, y: np.ndarray):
- """训练集成模型"""
- try:
- base_models = [
- ('xgb', XGBRegressor(**{
- 'max_depth': int(self.best_params['max_depth']),
- 'learning_rate': self.best_params['learning_rate'],
- 'n_estimators': int(self.best_params['n_estimators']),
- 'subsample': self.best_params['subsample']
- })),
- ('rf', RandomForestRegressor(
- n_estimators=200,
- max_depth=8,
- n_jobs=-1
- ))
- ]
- self.model = StackingRegressor(
- estimators=base_models,
- final_estimator=LassoCV(cv=5),
- cv=3,
- n_jobs=-1
- )
- logger.info("开始训练Stacking模型...")
- self.model.fit(X, y)
- self._is_trained = True
- return self.model
- except Exception as e:
- logger.error("模型训练失败: %s", str(e))
- self._is_trained = False
- raise
复制代码 八、模子评估
模子评估是衡量模子性能的告急步骤,通过计算不同的评估指标,我们可以了解模子的预测本领和泛化本领。在本项目中,我们利用以下几个评估指标来评估模子的性能:
- 匀称绝对偏差(MAE):预测值与真实值之间的匀称绝对偏差,反映了模子预测的匀称偏差水平。
- 均方根偏差(RMSE):预测值与真实值之间的均方根偏差,对异常值比力敏感,反映了模子预测的团体偏差水平。
- 决定系数(R²):体现模子对数据的拟合水平,取值范围为[0, 1],越靠近1体现模子拟合效果越好。
- 匀称绝对百分比偏差(MAPE):预测值与真实值之间的匀称绝对百分比偏差,反映了模子预测的相对偏差水平。
- 准确率(偏差≤20%):预测值与真实值之间的偏差在20%以内的样本占总样本的比例,反映了模子的预测准确性。
模子评估部门的代码如下:
- def evaluate(self, y_true: np.ndarray, y_pred: np.ndarray) -> Dict:
- """综合模型评估"""
- if not self._is_trained:
- raise RuntimeError("模型未训练")
- metrics = {
- 'MAE': mean_absolute_error(y_true, y_pred),
- 'RMSE': np.sqrt(mean_squared_error(y_true, y_pred)),
- 'R²': r2_score(y_true, y_pred),
- 'MAPE': mean_absolute_percentage_error(y_true, y_pred),
- '准确率(误差≤20%)': np.mean(np.abs((y_pred - y_true) / y_true) <= 0.2) * 100
- }
复制代码 九、运行效果
- MAE: 28651.010141975672
- RMSE: 44915.080348747775
- R²: 0.8543913449901033
- MAPE: 0.1496618109522733
- 准确率(误差≤20%): 76.40009782342871
- 示例预测结果:171846.38 vs 真实值:178100.00
复制代码 可以调参重新运利用模子准确率更高(本文只给出了部门代码)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |