在R中向ARIMA/LM输入分组数据并还原原列的最优方法
首先,先帮你修正下原代码里的几个小问题:一是你创建df时用了<-给列赋值,这会导致列名变成类似id <- rep(...)的无效名称,应该用=;二是代码里用到的taxonomy列没有在数据框里定义,我假设你是想基于cat1和cat2组合成分类标识,先补上这部分。
回到你的核心问题:多类别数据聚合后预测,再还原回原数据集结构。这里有几个更优的思路和实现方法:
1. 分组时保留完整的类别元数据
在聚合分组的时候,不要只保留时间序列数值,同时记录每个分组对应的所有类别属性(event, cat1, cat2, venue等),这样预测完成后,可以直接把预测结果和这些属性关联,再扩展到对应的时间维度,轻松还原到原始数据结构。
优化后的代码示例:
library(plyr) library(xts) library(forecast) # 修正数据框创建,添加taxonomy列,修正列赋值方式 df <- data.frame( id = rep(seq(2694065, length=62, by = 1),10), listing_date = rep(seq(as.Date("2017-06-01"), length=62, by = "day"),10), event = sample(c("Baseball","Minors","Music",NA), 620, replace = TRUE), event_date = rep(seq(as.Date("2017-09-01"), length=62, by = "day"),10), ticket_ct = sample(10:11000, size=620, replace = TRUE), price = sample(10:600, size=620, replace = TRUE), cat1 = sample(c("Sox", "Twins", "Phil", "Band1", "Band2"),620,replace = TRUE), cat2 = sample(c("Mets", "Hops", NA, "Phil"),620, replace = TRUE), venue = sample(c("Stadium","BallPark", "Concert Hall"),620, replace = TRUE) ) # 定义taxonomy(这里用cat1+cat2组合,你可以根据实际需求调整) df$taxonomy <- paste(df$cat1, df$cat2, sep = "_") # 分组时保留所有列,而不是只取时间序列数据 list1 <- dlply(df, .(id, taxonomy), function(group) { # 保存分组的元数据和时间序列数据 list( meta = group[1, c("event", "cat1", "cat2", "venue")], # 每个分组的类别属性(同组内一致) ts_data = xts(x=group[,c("ticket_ct","price")], order.by=group[,"listing_date"]) ) }) # 调整ARIMA预测函数,同时返回分组元数据和预测结果 arimafunc <- function(group_obj) { fity <- auto.arima(group_obj$ts_data$ticket_ct) forecast_result <- forecast(fity, h=31) # 将预测结果转换为数据框,方便后续合并 forecast_df <- as.data.frame(forecast_result) forecast_df$listing_date <- seq(max(index(group_obj$ts_data)) + 1, by = "day", length.out = 31) # 提取当前分组的id和taxonomy group_key <- strsplit(names(group_obj), "\\.")[[1]] forecast_df$id <- as.numeric(group_key[1]) forecast_df$taxonomy <- group_key[2] # 合并元数据 forecast_df <- cbind(forecast_df, group_obj$meta) # 重命名预测列为ticket_ct,和原始数据统一 forecast_df$ticket_ct <- forecast_df$`Point Forecast` return(forecast_df[, c("id", "listing_date", "taxonomy", "ticket_ct", "event", "cat1", "cat2", "venue")]) } # 运行预测 forecasts <- lapply(list1, arimafunc) # 将所有预测结果合并成一个数据框,再和原始数据合并,得到完整的数据集 full_forecast_df <- do.call(rbind, forecasts) original_with_forecast <- rbind( df[, c("id", "listing_date", "taxonomy", "ticket_ct", "event", "cat1", "cat2", "venue", "price")], full_forecast_df )
2. 采用分层时间序列(Hierarchical Time Series)方法
如果你的类别之间存在层级关系(比如cat1是一级分类,cat2是二级分类),可以使用分层时间序列的专用工具,比如hts包或者fable包,这类工具可以帮你在不同层级上做预测,同时保证预测结果的一致性,并且可以直接还原到最细粒度的分组。
比如用fable的示例(更现代的时间序列工具):
library(fable) library(tsibble) library(dplyr) # 将数据转换为tsibble格式(时间序列专用数据框) df_ts <- df %>% as_tsibble(key = c(id, taxonomy), index = listing_date) # 分层时间序列预测 hier_forecast <- df_ts %>% model(arima = ARIMA(ticket_ct)) %>% forecast(h = 31) # 直接得到细粒度的预测结果,可以和原始数据合并 full_data <- bind_rows( df_ts %>% select(id, listing_date, taxonomy, ticket_ct, price, event, cat1, cat2, venue), hier_forecast %>% select(id, listing_date, taxonomy, ticket_ct = .mean, event, cat1, cat2, venue) )
这种方法不需要手动处理分组和还原,工具会自动帮你处理层级关系,预测结果直接对应到每个原始分组。
3. 针对缺失值的预处理建议
在聚合前,建议先对每个分组的缺失值做简单处理(比如用同组的均值/中位数填充,或者用插值法),这样ARIMA模型的输入数据质量更高,预测结果更可靠。比如用dplyr的分组填充:
df_clean <- df %>% group_by(id, taxonomy) %>% mutate(ticket_ct = ifelse(is.na(ticket_ct), mean(ticket_ct, na.rm = TRUE), ticket_ct)) %>% ungroup()
后续线性模型预测price的注意事项
当你还原得到包含预测ticket_ct的完整数据集后,可以把ticket_ct(包括原始值和预测值)作为特征,结合event, cat1, cat2, venue等类别特征,用线性模型(比如lm或者正则化模型glmnet)来预测price。注意要区分训练数据(原始有price的部分)和预测数据(只有ticket_ct和类别特征的部分)。
内容的提问来源于stack exchange,提问作者user3889389

