You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

R语言中能否让auto.arima采用MAPE等样本外指标选择最优模型?

用样本外MAPE选择最优ARIMA模型(替代auto.arima默认信息准则)

当然可以实现!auto.arima()本身确实默认用AICc/AIC/BIC这些样本内信息准则选模型,但如果你想改用样本外MAPE这类更贴近真实预测效果的指标,需要手动实现一套参数搜索+样本外评估的流程。下面是具体的步骤和代码示例:

核心思路

  1. 拆分数据集:把一部分数据留作测试集(比如最后12个月的月度数据),剩下的作为训练集。
  2. 遍历ARIMA参数空间:覆盖可能的非季节性(p,d,q)和季节性(P,D,Q,s)参数组合。
  3. 对每个参数组合:拟合模型→预测测试集→计算MAPE。
  4. 选择MAPE最小的模型作为最优模型。

具体代码实现

1. 加载依赖包并准备数据

我们用经典的月度航空乘客数据AirPassengers作为示例,你可以替换成自己的月度数据集:

library(forecast)

# 加载月度数据
data <- AirPassengers
# 拆分训练集和测试集:留最后12个月作为测试集
train_size <- length(data) - 12
train_data <- window(data, end = c(1959, 12))  # 训练集到1959年12月
test_data <- window(data, start = c(1960, 1))   # 测试集为1960年全年

2. 定义MAPE计算函数

MAPE是平均绝对百分比误差,公式为:$\text{MAPE} = \frac{1}{n}\sum_{i=1}^n \left|\frac{\text{actual}_i - \text{predicted}_i}{\text{actual}_i}\right| \times 100$

calculate_mape <- function(actual, predicted) {
  # 避免实际值为0的情况(如果你的数据有0,可以加判断跳过或替换)
  if (any(actual == 0)) {
    warning("实际值包含0,MAPE计算可能失真,建议改用MAE或RMSE")
  }
  mean(abs((actual - predicted)/actual)) * 100
}

3. 遍历参数空间并评估

我们定义合理的参数范围(你可以根据自己的数据调整,比如扩大p/q的范围):

# 参数范围定义(月度数据季节性周期s=12)
p_values <- 0:3    # 非季节性AR阶数
d_values <- 0:1    # 差分阶数
q_values <- 0:3    # 非季节性MA阶数
P_values <- 0:2    # 季节性AR阶数
D_values <- 0:1    # 季节性差分阶数
Q_values <- 0:2    # 季节性MA阶数
s <- 12            # 月度数据的季节性周期

# 存储每个参数组合的结果
results <- list()

# 遍历所有参数组合
for (p in p_values) {
  for (d in d_values) {
    for (q in q_values) {
      for (P in P_values) {
        for (D in D_values) {
          for (Q in Q_values) {
            # 用tryCatch跳过无法拟合的无效参数组合
            tryCatch({
              # 拟合ARIMA模型
              model <- Arima(train_data, order = c(p, d, q), seasonal = c(P, D, Q, s))
              # 预测测试集
              forecast_result <- forecast(model, h = length(test_data))
              # 计算MAPE
              mape_score <- calculate_mape(test_data, forecast_result$mean)
              # 保存参数和MAPE
              param_key <- paste0("ARIMA(",p,",",d,",",q,")(",P,",",D,",",Q,")",s)
              results[[param_key]] <- list(
                order = c(p,d,q),
                seasonal = c(P,D,Q,s),
                mape = mape_score
              )
            }, error = function(e) {
              # 跳过报错的参数组合(比如过度差分的情况)
              NULL
            })
          }
        }
      }
    }
  }
}

4. 选择最优模型

从所有结果中筛选出MAPE最小的模型:

# 提取所有MAPE值
mape_scores <- sapply(results, function(x) x$mape)
# 找到MAPE最小的模型索引
best_model_key <- names(which.min(mape_scores))
best_model_info <- results[[best_model_key]]

# 输出最优模型信息
cat("最优模型:", best_model_key, "\n")
cat("测试集MAPE:", round(best_model_info$mape, 2), "%\n")

# 用完整数据集拟合最优模型
final_model <- Arima(data, order = best_model_info$order, seasonal = best_model_info$seasonal)
summary(final_model)

进阶优化:滚动窗口验证

如果想让评估更稳健,可以用滚动窗口的方式:每次用前k个月的数据训练,预测第k+1个月,然后滚动窗口(加入新的真实值,去掉最旧的),重复直到遍历完测试集,最后计算平均MAPE。这种方式能避免单次拆分的随机性,结果更可靠。

注意事项

  • MAPE对接近0的实际值非常敏感,如果你的数据包含0或极小值,建议改用MAE(平均绝对误差)或RMSE(均方根误差)。
  • 参数范围不要设置得过大,否则计算时间会很长(尤其是大数据集)。可以参考auto.arima()的默认参数范围来调整。
  • 样本外评估的测试集大小建议根据数据频率调整:月度数据一般留12-24个月,季度数据留4-8个季度。

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

火山引擎 最新活动