R语言中如何将聚合层级时间序列转换为hts对象?
构建层级时间序列(hts)对象的实用解决方案
我来帮你搞定这个hts对象构建的问题——其实核心是把你的长格式层级数据转成符合hts要求的结构,再动态生成所需参数,不用硬编码适配可变的类别数量。
步骤1:把长格式数据转成宽格式
hts要求每个层级组合对应时间序列的一列,所以首先得把你的长表转成宽表,缺失的时间-层级组合用0填充:
library(tidyr) library(hts) # 假设你的原始数据框名为df df_wide <- df %>% pivot_wider( names_from = c(level1, level2), values_from = n, values_fill = 0 # 填充没有数据的组合为0 )
步骤2:动态生成nodes参数
nodes参数用来定义层级结构,是一个列表:第一个元素是顶层(level1)的类别数量,第二个元素是每个顶层类别对应的底层(level2)类别数量。我们可以从数据里动态计算,不用手动写死:
# 计算每个level1对应的level2唯一值数量 level2_counts <- df %>% dplyr::group_by(level1) %>% dplyr::summarise(count = dplyr::n_distinct(level2)) %>% dplyr::pull(count) # 生成nodes列表 nodes <- list( length(unique(df$level1)), # level1的类别总数 level2_counts # 每个level1下的level2数量 )
比如你的数据里,level1有A、B两个类别,A对应1个level2,B对应3个,所以nodes会自动生成list(2, c(1,3)),完美适配数据变化。
步骤3:转换为时间序列对象
注意小时级别的时间序列,frequency参数设为24(每天24小时)更合理,同时要指定起始时间:
# 提取起始时间的年、月、日、小时 start_time <- min(df$TIME) start_params <- c(lubridate::year(start_time), lubridate::month(start_time), lubridate::day(start_time), lubridate::hour(start_time)) # 转换为ts对象(去掉TIME列) df_ts <- ts( data = df_wide[, -which(names(df_wide) == "TIME")], start = start_params, frequency = 24 )
步骤4:构建hts对象
最后用hts()函数组合起来,colnames直接用宽表的列名就可以(已经是level1_level2的格式,清晰明了):
hts_obj <- hts(df_ts, nodes = nodes)
额外注意事项
- 如果你的时间序列有缺失的小时点,记得先补全时间序列(比如用
tidyr::complete(TIME = seq(min(TIME), max(TIME), by = "hour"))),否则ts对象会不连续。 - 如果你想自定义层级名称,可以修改宽表的列名,或者在
hts()里用characters参数指定层级标签。
内容的提问来源于stack exchange,提问作者Praveen
相关产品推荐
相关产品推荐

