RandomForestRegressor.predict()始终输出相同预测值的原因及解决方法
问题描述
给定示例数据集df_example:
X Y 0 65000 1 67000 2 69000 3 65000 4 68000 5 65000 6 78000 7 80000 8 73000 9 75000 10 79000 . . . 51 78000
使用以下代码训练随机森林回归模型:
from sklearn.ensemble import RandomForestRegressor regr = RandomForestRegressor(max_depth=8, random_state=0, n_estimators=500, criterion='squared_error', min_samples_split=3, oob_score=True) X=df_example['X'].values.reshape(-1,1) y=df_example['Y'].values.reshape(-1,1) regr.fit(X,y) Y_pred=regr.predict(X) from sklearn.metrics import r2_score, explained_variance_score, mean_squared_error print('MSE regr', mean_squared_error(y, Y_pred)) print('r2 regr', r2_score(y, Y_pred)) print('variance regr', 100-100*(explained_variance_score(y, Y_pred)), '%')
模型评估输出:
MSE: regr: 1215189.74 r2 regr: 0.933 variance regr: 6.65%
预测X=51时结果正常:
pred_list=[51] a= np.array(pred_list) a=np.expand_dims(a,0) pred=regr.predict(a) print('pred value is:', pred)
输出:
76562.67
但预测X=52、X=53甚至X=100时,预测值完全相同:
pred_list=[100] a= np.array(pred_list) a=np.expand_dims(a,0) pred=regr.predict(a) print('pred value is:', pred)
输出:
76562.67
拆分训练集和测试集重新训练后问题依旧:
X_train=X[0:44] X_test=X[44:] y_train=y[0:44] regr.fit(X_train,y_train)
原因分析
- 随机森林回归器无外推能力:随机森林本质是基于训练数据中的样本做区间内拟合,对于训练数据中最大
X值(此处为51)之外的输入,所有决策树会将其归类到训练集最大的叶子节点,最终输出该节点的平均Y值,因此所有大于51的X预测结果一致。 - 未学习到趋势关联:尽管
X是连续序列特征,但随机森林仅关注训练数据已有的X区间内的分布,无法捕捉X与Y之间的趋势性规律,自然无法对超出区间的样本给出合理外推结果。
解决方法
- 更换具备外推能力的模型
选择线性回归、支持趋势学习的梯度提升树(如LightGBM设置monotonic_constraints)或时间序列专用模型,这类模型能学习特征与目标的趋势关系,对超区间样本输出合理预测。示例代码(线性回归):from sklearn.linear_model import LinearRegression import numpy as np lr = LinearRegression() lr.fit(X_train, y_train) # 预测X=100 pred_100 = lr.predict(np.array([[100]])) print(pred_100) - 扩展训练数据区间
若可获取X>51的真实样本,将其加入训练集,让模型学习更大X区间内的Y分布规律,即可得到对应区间的有效预测。 - 特征工程辅助(序列场景)
若X代表时间步或连续序列,可添加时间趋势项、滑动窗口统计特征等,帮助模型捕捉潜在变化规律,但该方法对随机森林外推能力提升有限,更适合搭配具备外推能力的模型使用。
内容的提问来源于stack exchange,提问作者Chubiblan
相关产品推荐
相关产品推荐

