使用LightGBM进行房价回归时RMSE过高的问题排查及优化
房价预测模型误差异常过高问题排查
问题背景
使用比利时房产数据集,目标是通过房屋面积、房间数、邮政编码等特征预测price列,但训练LightGBM模型后得到的误差值(6053845952.2186775)异常偏高,需排查原因并解决。
我的操作步骤
- 加载数据
workspace = Workspace(subscription_id, resource_group, workspace_name) dataset = Dataset.get_by_name(workspace, name='BelgiumRealEstate') data = dataset.to_pandas_dataframe() data.sample(5)
数据样例:
| Column1 | postal_code | city_name | type_of_property | price | number_of_rooms | house_area | fully_equipped_kitchen | open_fire | terrace | garden | surface_of_the_land | number_of_facades | swimming_pool | state_of_the_building | lattitude | longitude | province | region |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 33580 | 9850 | Landegem | 1 | 380000 | 3 | 127 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | as new | 3.588809 | 51.054637 | Flandre-Orientale | Flandre |
| 11576 | 9000 | Gent | 1 | 319000 | 2 | 89 | 1 | 0 | 1 | 0 | 0 | 2 | 0 | as new | 3.714155 | 51.039713 | Flandre-Orientale | Flandre |
| 12830 | 3300 | Bost | 0 | 170000 | 3 | 140 | 1 | 0 | 1 | 1 | 160 | 2 | 0 | to renovate | 4.933924 | 50.784632 | Brabant flamand | Flandre |
| 20736 | 6880 | Cugnon | 0 | 270000 | 4 | 218 | 0 | 0 | 0 | 0 | 3000 | 4 | 0 | unknown | 5.203308 | 49.802043 | Luxembourg | Wallonie |
| 11416 | 9000 | Gent | 0 | 875000 | 6 | 232 | 1 | 0 | 0 | 1 | 0 | 2 | 0 | good | 3.714155 | 51.039713 | Flandre-Orientale | Flandre |
- 类别特征独热编码
one_hot_state_of_the_building = pd.get_dummies(data.state_of_the_building) one_hot_city = pd.get_dummies(data.city_name, prefix='city') one_hot_province = pd.get_dummies(data.province, prefix='province') one_hot_region = pd.get_dummies(data.region, prefix="region")
- 合并编码特征
# 移除原类别特征 data.drop(['city_name','state_of_the_building','province','region'], axis=1, inplace=True) # 合并编码后特征 data = pd.concat([data, one_hot_city, one_hot_state_of_the_building, one_hot_province, one_hot_region], axis=1)
- 划分特征与标签
x = data.drop('price', axis=1) y = data.price
- 划分训练集与测试集
from sklearn.model_selection import train_test_split x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=.3)
- 训练LightGBM模型
x_df = DataFrame(x, columns= data.columns) x_train, x_test, y_train, y_test = train_test_split(x_df, y, test_size=0.15) # 转换为LightGBM数据集格式 d_train = lgb.Dataset(x_train, label=y_train) # 模型参数 params = { 'task': 'train', 'boosting': 'gbdt', 'objective': 'regression', 'num_leaves': 10, 'learnnig_rate': 0.05, 'metric': {'l2','l1'}, 'verbose': -1 } # 训练模型 clf = lgb.train(params, d_train, 10000) # 预测 y_pred = clf.predict(x_test) # 计算误差 mean_squared_error(y_pred, y_test)
问题分析与解决建议
1. 误差计算混淆:MSE vs RMSE
你当前计算的是均方误差(MSE),而非预期的均方根误差(RMSE)。房价本身是几十万级别的数值,MSE是误差的平方,因此数值会异常大。正确的RMSE计算需要对MSE开根号:
import numpy as np rmse = np.sqrt(mean_squared_error(y_pred, y_test))
2. 训练集/测试集重复划分+特征构造错误
- 步骤5已经完成训练集与测试集的划分,但步骤6又重新执行
train_test_split,打乱了原有划分逻辑。 x_df = DataFrame(x, columns= data.columns)存在严重错误:x是去掉price后的特征集,而data.columns包含price列,导致x_df新增一列全为NaN的price无效特征,直接干扰模型训练。
修正方案:直接使用步骤5划分好的数据集,无需重新构造x_df:
# 替换步骤6的代码 d_train = lgb.Dataset(x_train, label=y_train) params = { 'task': 'train', 'boosting': 'gbdt', 'objective': 'regression', 'num_leaves': 10, 'learning_rate': 0.05, # 修正拼写错误 'metric': {'l2','l1'}, 'verbose': 1 # 打开日志监控训练过程 } # 添加早停机制防止过拟合 clf = lgb.train(params, d_train, 10000, valid_sets=[lgb.Dataset(x_test, label=y_test)], early_stopping_rounds=50) y_pred = clf.predict(x_test, num_iteration=clf.best_iteration) rmse = np.sqrt(mean_squared_error(y_pred, y_test))
3. 参数拼写错误
learnnig_rate应为learning_rate,少了字母r导致该参数未生效,模型使用默认学习率(0.1),可能引发训练不稳定。
4. 冗余与无效特征处理
Column1是重复的行索引,无预测价值,数据加载后应删除:
data.drop('Column1', axis=1, inplace=True)
postal_code被当作连续特征处理,但本质是类别特征,建议用目标编码或嵌入编码替代,避免独热编码的维度爆炸问题。
5. 高基数类别特征编码优化
city_name属于高基数类别(城市数量多),独热编码会导致特征维度急剧增加,引发维度灾难。建议改用LightGBM原生类别特征支持:
# 恢复原类别列,设为类别类型 data['city_name'] = data['city_name'].astype('category') data['province'] = data['province'].astype('category') data['region'] = data['region'].astype('category') data['state_of_the_building'] = data['state_of_the_building'].astype('category') # 训练时指定类别特征参数 params['categorical_feature'] = ['city_name', 'province', 'region', 'state_of_the_building']
6. 数据异常值过滤
检查price、house_area等特征的极端值,用四分位数法过滤:
# 过滤房价极端值 q1 = data['price'].quantile(0.01) q3 = data['price'].quantile(0.99) data = data[(data['price'] >= q1) & (data['price'] <= q3)]
内容的提问来源于stack exchange,提问作者Luis Valencia
相关产品推荐
相关产品推荐

