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

时间序列数据外推的正确方法:基于R语言预测2050年车辆数量

嘿,我懂你这份纠结——攥着1990到2016年27组车辆数的时序数据,想一口气预测到2050年,本来打定主意用机器学习,结果先试了HoltWinters和TBATS这些传统时序方法,总觉得没贴合自己最初的想法对吧?刚好咱全程用R,那我给你捋捋怎么用机器学习来搞定这个预测,还能和你现有的结果做个对比~

用机器学习处理长跨度时间序列预测(R语言实现)

一、先把时序数据转成机器学习能“消化”的格式

传统时序方法靠序列本身的依赖关系吃饭,但机器学习需要明确的特征。你可以基于现有数据构造这些核心特征:

  • 基础时间特征:年份与起始年的差值(比如year_diff = year - 1990),帮模型捕捉长期趋势
  • 滑动窗口特征:过去1/3/5年的车辆数均值、最大值,用来提取短期波动规律
  • 融合传统方法特征:把你已经用HoltWinters得到的趋势成分加进来,让模型兼顾传统方法的优势

代码示例:

library(tidyverse)
library(zoo)

# 假设你的数据是带year和vehicle_count列的data.frame
df <- data.frame(
  year = 1990:2016,
  vehicle_count = c(...) # 替换成你的27组实际数据
)

# 构造特征集
df <- df %>%
  mutate(
    year_diff = year - 1990,
    lag_1 = lag(vehicle_count, 1), # 上一年的车辆数
    rolling_mean_3 = rollmean(vehicle_count, k=3, fill=NA, align="right"), # 过去3年均值
    rolling_max_5 = rollmax(vehicle_count, k=5, fill=NA, align="right") # 过去5年最大值
  ) %>%
  drop_na() # 去掉滑动窗口产生的缺失值行

二、选合适的机器学习模型落地

1. 正则化回归(简单易解释,适合初步验证)

glmnet做LASSO回归,既能捕捉线性趋势,又能避免过拟合:

library(glmnet)

# 准备特征矩阵和目标变量
x <- model.matrix(vehicle_count ~ . - year, data = df)
y <- df$vehicle_count

# 训练LASSO模型
lasso_model <- cv.glmnet(x, y, alpha=1)

# 构造2017-2050年的特征矩阵(用递归预测处理多步误差)
future_df <- data.frame(
  year = 2017:2050,
  year_diff = 2017:2050 - 1990
)

# 初始化滑动窗口特征(用历史最后一批数据)
last_value <- df$vehicle_count[nrow(df)]
last_3_mean <- mean(tail(df$vehicle_count, 3))
last_5_max <- max(tail(df$vehicle_count, 5))

future_df <- future_df %>%
  mutate(
    lag_1 = c(last_value, rep(NA, nrow(future_df)-1)),
    rolling_mean_3 = c(last_3_mean, rep(NA, nrow(future_df)-1)),
    rolling_max_5 = c(last_5_max, rep(NA, nrow(future_df)-1))
  )

# 递归预测:每预测一个值,就把它加入特征库预测下一个
for(i in 2:nrow(future_df)){
  future_df$lag_1[i] <- predict(lasso_model, newx = model.matrix(~ . - year, data = future_df[i-1, ]))
  future_df$rolling_mean_3[i] <- mean(c(tail(df$vehicle_count, 2), future_df$lag_1[i-1]))
}

# 生成最终预测结果
future_df$predicted_count <- predict(lasso_model, newx = model.matrix(~ . - year, data = future_df))

2. 树模型(捕捉非线性趋势,鲁棒性强)

比如随机森林,能处理复杂的时序依赖,不需要太多特征调优:

library(randomForest)

# 训练随机森林模型
rf_model <- randomForest(vehicle_count ~ . - year, data = df, ntree=500)

# 同样用递归预测处理长跨度
future_df_rf <- future_df %>% select(-predicted_count)
current_pred <- NULL

for(i in 1:nrow(future_df_rf)){
  if(i == 1){
    current_pred <- predict(rf_model, newdata = future_df_rf[i, ])
  } else {
    future_df_rf$lag_1[i] <- current_pred
    future_df_rf$rolling_mean_3[i] <- mean(c(tail(df$vehicle_count, 2), future_df_rf$lag_1[1:(i-1)]))
    current_pred <- predict(rf_model, newdata = future_df_rf[i, ])
  }
  future_df_rf$predicted_count[i] <- current_pred
}

3. LSTM深度学习(贴合时序依赖,适合复杂趋势)

如果想更精准捕捉时序的长期依赖,用Keras在R里搭个简单的LSTM模型:

library(keras)

# 转成LSTM需要的三维输入格式:(样本数, 时间步长, 特征数)
time_steps <- 3 # 用过去3年数据预测下一年
x_lstm <- list()
y_lstm <- list()

for(i in time_steps:(nrow(df)-1)){
  x_lstm[[i - time_steps +1]] <- df$vehicle_count[(i - time_steps +1):i]
  y_lstm[[i - time_steps +1]] <- df$vehicle_count[i+1]
}

x_lstm <- array(unlist(x_lstm), dim = c(length(x_lstm), time_steps, 1))
y_lstm <- unlist(y_lstm)

# 构建LSTM模型
model <- keras_model_sequential() %>%
  layer_lstm(units=32, input_shape=c(time_steps, 1)) %>%
  layer_dense(units=1)

model %>% compile(optimizer="adam", loss="mse")
model %>% fit(x_lstm, y_lstm, epochs=50, batch_size=2, validation_split=0.2)

# 递归预测到2050年
last_sequence <- tail(df$vehicle_count, time_steps)
predictions <- c()

for(i in 1:(2050-2016)){
  pred <- model %>% predict(array(last_sequence, dim=c(1, time_steps, 1)))
  predictions <- c(predictions, pred)
  last_sequence <- c(last_sequence[-1], pred)
}

future_df_lstm <- data.frame(
  year = 2017:2050,
  predicted_count = predictions
)

三、和HoltWinters结果做对比

你已经有了传统方法的预测结果,可以把机器学习的预测和它画在同一张图里,直观看看差异:

library(forecast)

# 假设你的HoltWinters模型是hw_model
hw_forecast <- forecast(hw_model, h=2050-2016)

# 绘制对比图
plot(hw_forecast, main="车辆数量预测(2017-2050)", xlab="年份", ylab="车辆数量")
lines(future_df$year, future_df$predicted_count, col="red", lwd=2)
lines(future_df_rf$year, future_df_rf$predicted_count, col="blue", lwd=2)
lines(future_df_lstm$year, future_df_lstm$predicted_count, col="green", lwd=2)
legend("topleft", legend=c("HoltWinters", "LASSO回归", "随机森林", "LSTM"), 
       col=c("black", "red", "blue", "green"), lwd=2)

四、长跨度预测的重要提醒

你也提到这个预测跨度极大,不管用哪种方法都得注意:

  • 机器学习模型依赖特征的延续性,如果未来出现重大政策(比如燃油车禁售)、经济波动,预测结果会偏差很大
  • 递归预测会累积误差,跨度越长误差越明显,可以结合情景假设(比如设定不同的增长率场景)来调整结果
  • 可以把传统时序方法的预测结果作为一个特征加入机器学习模型,融合两种方法的优势

内容的提问来源于stack exchange,提问作者Abdul Basit Khan

火山引擎 最新活动