如何在R的tidy数据集里对多分组变长数据做变换/重采样/插值归一化?
解决tidyverse中使用
approx重采样向量长度不匹配的问题 问题回顾
你想要对每个id, event组内的sub_event序列进行重采样,让所有sub_event的长度等于该组内最长sub_event的长度,但运行尝试代码时出现了以下错误:
Error in mutate_impl(.data, dots) : 列
var1必须为190(分组大小)或1,而非110
In addition: Warning messages:
1: In if (n <= 0) stop("'approx' requires n >= 1") : 条件长度大于1,仅使用第一个元素
2: In seq.int(x[1L], x[nx], length.out = n) : 'length.out'参数仅使用第一个元素
问题原因分析
这个错误的核心是分组层级与mutate的工作逻辑不匹配:
- 当你按
id, event分组后,每个分组包含两个sub_event的所有行(共190行),而approx(var1, n = max_sub_event_time)$y生成的是长度为110的向量(对应该组的最大长度)。mutate需要给分组内的每一行都分配一个值,110和190的长度不匹配,因此触发报错。 - 另外,
max_sub_event_time是每个id, event组的常量,但approx的n参数如果传入长度大于1的向量,只会取第一个元素,这就是警告信息的来源。
正确解决方案:按子事件分组重采样,再扩展到目标长度
我们需要先按id, event, sub_event分组处理每个子序列,再根据对应组的最大长度进行重采样,最后重新生成时间序列。下面是用tidyverse工具实现的高效方案:
library(tidyverse) # 1. 先计算每个(id, event)组的最长时间长度 max_length_df <- df %>% group_by(id, event) %>% summarise(max_len = max(sub_event_time), .groups = "drop") # 2. 对每个sub_event子组进行重采样,并整理成tidy格式 resampled_df <- df %>% # 嵌套每个sub_event的子数据集 nest_by(id, event, sub_event) %>% # 关联对应组的最大长度 left_join(max_length_df, by = c("id", "event")) %>% # 对每个子数据集执行重采样 mutate( resampled_data = list( tibble( sub_event_time = seq(1, max_len, length.out = max_len), var1 = approx(data$var1, n = max_len)$y, var2 = approx(data$var2, n = max_len)$y ) ) ) %>% # 展开嵌套的重采样结果 unnest(resampled_data) %>% # 移除不再需要的原始嵌套数据列 select(-data) # 查看处理后的数据结构 glimpse(resampled_df) # 绘制验证图,确认所有sub_event长度一致 ggplot(resampled_df, aes(x=sub_event_time, y=var1, colour = sub_event)) + geom_point(size = 0.8) + geom_line() + facet_wrap(id~event)
代码逻辑说明
- 提取最大长度:先单独计算每个
id, event组的最长时间长度,确保后续重采样的目标长度统一。 - 嵌套子组数据:使用
nest_by将每个id, event, sub_event的原始数据嵌套成单独的数据框,这样我们可以对每个子序列独立操作。 - 执行重采样:在
mutate中,对每个子数据框的var1和var2调用approx,采样到目标长度max_len,同时生成对应的新时间序列。 - 恢复tidy格式:用
unnest展开嵌套的重采样结果,得到结构整齐的最终数据集。
处理完成后,每个sub_event的序列长度都会匹配对应id, event组的最长长度,你可以顺利进行后续的均值计算等操作了。
内容的提问来源于stack exchange,提问作者dambach
相关产品推荐
相关产品推荐

