You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用R中XGBoost进行时间序列预测时出现常数预测值问题

问题

我尝试在R中使用梯度提升(Gradient Boosting)的XGBoost模型进行时间序列预测,遇到了如下问题:

  • 92条观测数据划分为75条训练集、17条测试集,测试集预测结果尚可
  • 但预测未来12个季度时,模型返回恒定的预测值(水平线)

数据量较小(92条观测、10个自变量),但不清楚常数预测值的成因,以下是我的代码:

数据预处理与划分

# Load data
a = diff(log(UnempRate$LRUN64TTBEQ156S))
b = diff(log(GDP$CPMNACSCAB1GQBE))
c = diff(log(URateUS$UNRATE))
d = diff(log(AirT$PCU481481))
e = diff(log(DGoods$PITGCD02BEQ661N))
f = diff(log(GCredit$QBEGAMUSDA))
g = diff(log(HWage$LCWRMN01BEQ661N))
h = diff(log(Sales$SLRTTO02BEQ661S))
i = diff(log(ActRate$LRAC64TTBEQ156S))
j = diff(log(Imports$Imports))
k = diff(log(Exports$XTEXVA01BEM667S))

dset2 = data.frame(a,b,c, d,e,f,g,h,i,j,k)

# Split data
train = head(dset2,75)
test = dset2[76:92, ]

训练XGBoost模型并测试

# XGBoost
grid_tune = expand.grid(nrounds = 1000, max_depth = 8, eta = 0.1, gamma = 0.00, colsample_bytree = 1, min_child_weight = 1, subsample = 1)

train_control = trainControl(method = "cv", number = 3, verboseIter = TRUE, allowParallel = TRUE)

xgb_tune = caret::train(x = train[, -1], y = train[,1], trControl = train_control, tuneGrid = grid_tune, method = "xgbTree", verbose = TRUE)

# 测试集预测
xgb_pred = predict(xgb_tune, test)
ts.plot(test$a, xlab = "Quarters 76 to 92", ylab = "Diff(log()) value", main = "XGB predictions on testing data", col = "#009999")
lines(xgb_pred, col = "red")

未来12季度预测(出现常数结果)

# 添加空行准备预测
empty_df <- data.frame(matrix(nrow = 12, ncol = 11))
colnames(empty_df) <- c("a","b","c","d","e","f","g","h","i","j","k")
dset3 = rbind(dset2, empty_df)
train2 = head(dset3, 92)
test2 = dset3[93: 104, ]

# 重新训练模型
grid_tune = expand.grid(nrounds = 1000, max_depth = 8, eta = 0.1, gamma = 0.00, colsample_bytree = 1, min_child_weight = 1, subsample = 1)
train_control = trainControl(method = "cv", number = 3, verboseIter = TRUE, allowParallel = TRUE)
xgb_tune = caret::train(x = train2[, -1], y = train2[,1], trControl = train_control, tuneGrid = grid_tune, method = "xgbTree", verbose = TRUE)

# 预测结果为常数
xgb_pred = predict(xgb_tune, test2)
# 输出:[1] 0.0709851 0.0709851 ...(共12个相同值)

原因分析与解决方案

核心原因:未来预测的自变量全为缺失值

你用来预测未来的test2数据中,10个自变量(b到k)全是NA。XGBoost遇到所有输入特征都缺失的样本时,会默认输出模型训练时目标变量的全局基准值(通常是均值),因此所有预测结果都是同一个常数。

另外,你的时间序列预测逻辑存在误区:未来的自变量(b到k)本身也是未知的,不能直接留空等待模型预测,必须先对这些自变量做预测,或者改用不需要同期自变量的时间序列建模方式。

具体解决步骤

1. 先预测未来的自变量值

针对每个自变量(b到k),单独用时间序列模型(如ARIMA、ETS)预测未来12个季度的值,填充到test2中:

library(forecast)
# 示例:用ARIMA预测自变量b的未来值(季度数据频率设为4)
b_ts <- ts(dset2$b, frequency = 4)
b_fit <- auto.arima(b_ts)
b_forecast <- forecast(b_fit, h=12)$mean

# 对c-k重复上述操作,得到各自的预测值
# c_forecast <- ...
# d_forecast <- ...

# 填充test2的自变量
test2$b <- b_forecast
test2$c <- c_forecast
# ... 依次填充d到k

# 再进行预测
xgb_pred <- predict(xgb_tune, test2)

2. 重构时间序列特征(更合理的建模方式)

对于时间序列预测,更合理的方式是用历史特征预测未来,而非依赖同期未知的自变量。可以构造滞后特征、滚动统计特征:

library(dplyr)
# 构造滞后特征:a的滞后1-4期(对应季度数据的历史值)、b的滞后1期等
dset2 <- dset2 %>%
  mutate(
    a_lag1 = lag(a, 1),
    a_lag2 = lag(a, 2),
    a_lag3 = lag(a, 3),
    a_lag4 = lag(a, 4),
    b_lag1 = lag(b, 1),
    # 可添加滚动统计特征:比如过去4期a的均值
    a_roll_mean4 = zoo::rollmean(a, k=4, fill=NA, align="right")
  ) %>%
  na.omit() # 去掉因滞后产生的NA行

# 重新划分训练集和测试集
train <- head(dset2, nrow(dset2)-17)
test <- tail(dset2, 17)

# 训练模型:用历史特征预测当前的a
xgb_tune <- caret::train(
  x = train[, !colnames(train) %in% "a"],
  y = train$a,
  trControl = train_control,
  tuneGrid = grid_tune,
  method = "xgbTree",
  verbose = TRUE
)

这种方式下,预测未来时可以用递归预测:先用第92期的特征预测第93期的a,再把第93期的a作为滞后特征加入,预测第94期,以此类推。

3. 调整模型参数避免过拟合

你的数据量仅92条,nrounds=1000极易导致过拟合,尝试减小模型复杂度:

grid_tune <- expand.grid(
  nrounds = 200,
  max_depth = 3, # 减小树深度,降低复杂度
  eta = 0.1,
  gamma = 0.1, # 加入正则化,减少不必要的分裂
  colsample_bytree = 0.8,
  min_child_weight = 2,
  subsample = 0.8
)

内容的提问来源于stack exchange,提问作者Skurt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 16:25:21