R语言tidyverse:如何为分组数据框创建多列滞后变量?
解决分组DataFrame生成多列滞后变量的问题
你的问题核心是没有在分组内部正确计算滞后值,原来的代码跨组取了数据,而尝试用group_by+map时又因为环境问题找不到变量。下面给你最简洁的tidyverse解决方案:
正确实现代码
先重现你的数据(补全了部分行方便测试):
library(tidyverse) df <- tribble( ~year, ~country, ~variable, 1997, "USA", 28, 1998, "USA", 40, 1999, "USA", 45, 2000, "USA", 53, 1997, "France", 13, 1998, "France", 20, 1999, "France", 35, 2000, "France", 50 ) nlags <- 1:3 # 示例用1-3,你可以改成1:10
然后用分组+mutate+purrr的组合生成正确的滞后列:
df_with_lags <- df %>% group_by(country) %>% mutate( # 生成每个滞后列并命名 !!!set_names( map(nlags, ~ lag(variable, .x)), paste0("lag_", nlags) ) ) %>% ungroup() # 可选,不需要分组时取消 print(df_with_lags)
运行后你会看到:
- 美国1997年的所有滞后列都是
NA,1998年的lag_1是28(正确取美国上一年的值) - 法国1997年的所有滞后列都是
NA,1998年的lag_1是13(正确取法国上一年的值)
完全不会出现跨组取值的问题。
代码原理解释
group_by(country):把数据按国家分组,确保后续的滞后计算只在每个分组内部进行。map(nlags, ~ lag(variable, .x)):对每个滞后步数,生成当前分组内variable的滞后向量。set_names(..., paste0("lag_", nlags)):给每个滞后向量命名为lag_1、lag_2...,方便后续合并。!!!:这是tidyverse的解引用操作符,把命名好的滞后向量列表拆分成mutate的多个列,相当于手动写lag_1 = lag(variable,1), lag_2=lag(variable,2)...,非常高效。
为什么你的尝试报错?
你写的df %>% group_by(country) %>% map(.x = nlags, .f = ~ lag(variable, .x))有两个问题:
map作用于分组后的grouped_df时,它的迭代对象是每个分组的DataFrame,而不是直接的列。所以你直接写lag(variable, .x)会找不到variable——它不在当前函数的环境里,而是在每个分组的DataFrame中。- 就算修复了变量引用(比如写成
function(group_df) lag(group_df$variable, .x)),最后得到的是一个列表,还需要手动合并回原数据框,远不如mutate的方法简洁。
如果你非要用group_map的方式实现,代码会是这样(不推荐,仅作参考):
lag_cols <- df %>% group_by(country) %>% group_map(function(group_df, .) { map_dfc(nlags, ~lag(group_df$variable, .x)) %>% set_names(paste0("lag_", nlags)) }) %>% bind_rows() df_with_lags <- df %>% bind_cols(lag_cols)
内容的提问来源于stack exchange,提问作者ulima2_
相关产品推荐
相关产品推荐

