随机森林和一般的基于树的模型不能很好地处理趋势。
原因很简单:在任何决策树内部,都有离散规则,例如:
这是深度为 1 的树(所谓的“茎”),但更深的树遵循相同的逻辑。变量和常量、、适合训练数据。这就是问题所在:如果在训练数据中从未高于,那么即使明显增加,您的树也永远不会预测
y={y1,y2,if x>cif x<=c
xy1y2cyy1y>y1y
另一方面,线性模型(例如 XARIMA 及其特殊情况)可以很好地捕捉趋势。但是它们在数据中的非线性和特征相互作用很差。根据我自己的经验,以下堆叠方法效果最好:
- 为您的数据拟合一个简单的基于时间的线性模型。
- 将基于树的模型(随机森林或提升)拟合到线性模型的残差。
如果正确指定了线性模型,它将捕获并消除数据中的非平稳性。因此,基于树的模型将预测静态残差并找到比线性模型更精细的依赖关系。
这个 Python 示例说明了这个问题:
import numpy as np
from sklearn.datasets import make_friedman2
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import HuberRegressor
from sklearn.metrics import r2_score
from sklearn.model_selection import cross_val_predict
# make a difficult dataset with a linear trend
X, y = make_friedman2(n_samples=1000, random_state=1, noise=10)
time = np.arange(1000)
y += time * 1.5
X = np.hstack([X, time[:, np.newaxis]])
X_train, y_train = X[:700], y[:700]
X_test, y_test = X[700:], y[700:]
# build a pure Random Forest
rf = RandomForestRegressor(random_state=1, n_jobs=-1).fit(X_train, y_train)
y_rf = rf.predict(X_test)
# build a pure linear model
linear = HuberRegressor().fit(X_train, y_train)
y_lin = linear.predict(X_test)
# build a stack of two models
lin_resid = y_train - cross_val_predict(linear, X_train, y_train)
rf.fit(X_train, lin_resid)
y_stack = y_lin + rf.predict(X_test)
print(r2_score(y_test, y_rf)) # R2 on test data is only 0.34
print(r2_score(y_test, y_lin)) # R2 due to time trend is 0.86
print(r2_score(y_test, y_stack)) # R2 of combined model is 0.95