时间序列数据外推的正确方法:基于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




