函数传入DataFrame时跨多列处理及按年龄组汇总非NA行数方案
问题描述
我有多个结构完全一致的DataFrame,想通过函数将每个输入的DataFrame按指定年龄组汇总个体级数据,生成每行对应一个年龄组的输出DataFrame,统计regularVar_names中各变量的非NA行数。
目前尝试的代码因无法正确传入DataFrame报错,具体信息如下:
数据示例
input.ds.2018 = data.frame(Var1 = c(1,1,NA,NA,1,2),Var2 = rep(c(1,2),3),V3 = c(NA,rep(2,4),1), y_4 = c(NA,"y","z","l","m","n"),X_AGE80 = c(17,18,NA,84,21,72))
尝试的代码
calc_unwt_n_regularVar_fn = function(df,VAR){ df %>% filter(!is.na(eval(parse(text = VAR)))) %>% nrow } # apply calc_unwt_n_regularVar_fn to age-group 18 to 84 for regular variables called Var1 and Var2 regularVar_names = c("Var1","Var2") output = input.ds.2018 %>% filter(X_AGE80 <= 84) %>% filter(X_AGE80 >= 18) %>% summarize(across(all_of(regularVar_names), ~ calc_unwt_n_regularVar_fn(.,cur_column()),.names = "unwt_denom_{.col}"))
报错信息
Error in `summarize()`: i In argument: `across(...)`. Caused by error in `across()`: ! Can't compute column `unwt_denom_Var1`. Caused by error in `UseMethod()`: ! no applicable method for 'filter' applied to an object of class "c('double', 'numeric')"
咨询两个问题:
- 如何将DataFrame作为参数传入自定义函数
calc_unwt_n_regularVar_fn? - 若当前思路不佳,如何优雅实现多DataFrame、多年龄组的汇总需求?
解答
问题1:正确传入DataFrame到自定义函数
报错根源是across调用函数时,传递的是单个列的向量而非整个DataFrame,针对这个问题有两种解决方式:
方式1:简化函数,直接处理向量
既然across传递的是列向量,函数无需处理整个DataFrame,直接统计非NA值数量即可:
calc_unwt_n_regularVar_fn = function(vec){ sum(!is.na(vec)) }
调用时无需传列名,直接使用:
output = input.ds.2018 %>% filter(between(X_AGE80, 18, 84)) %>% summarize(across(all_of(regularVar_names), ~ calc_unwt_n_regularVar_fn(.), .names = "unwt_denom_{.col}"))
方式2:传递完整DataFrame与列名
如果要保留原函数处理整个DataFrame的逻辑,需用cur_data()获取当前分组的完整数据,同时用.data[[VAR]]替代不安全的eval(parse(...)):
calc_unwt_n_regularVar_fn = function(df, VAR){ df %>% filter(!is.na(.data[[VAR]])) %>% nrow() } output = input.ds.2018 %>% filter(between(X_AGE80, 18, 84)) %>% summarize(across(all_of(regularVar_names), ~ calc_unwt_n_regularVar_fn(cur_data(), cur_column()), .names = "unwt_denom_{.col}"))
问题2:优雅实现多DataFrame、多年龄组的汇总
推荐用purrr结合分组操作批量处理,步骤如下:
步骤1:定义年龄组规则
将需要的年龄组整理为列表:
age_groups = list( "18-44" = c(18,44), "45-64" = c(45,64), "65-84" = c(65,84), "18-84" = c(18,84) )
步骤2:编写通用汇总函数
输入单个DataFrame和年龄组范围,输出对应汇总结果:
summarize_by_age = function(df, age_min, age_max, var_names){ df %>% filter(between(X_AGE80, age_min, age_max)) %>% summarize( age_group = paste0(age_min, "-", age_max), across(all_of(var_names), ~ sum(!is.na(.)), .names = "unwt_denom_{.col}") ) }
步骤3:批量处理多DataFrame与年龄组
将所有待处理的DataFrame放入列表,用purrr::map_dfr批量生成并合并结果:
library(purrr) library(dplyr) # 假设还有2019、2020年的数据集 df_list = list( "2018" = input.ds.2018, "2019" = input.ds.2019, "2020" = input.ds.2020 ) all_results = map_dfr(df_list, function(df){ map_dfr(age_groups, function(age_range){ summarize_by_age(df, age_range[1], age_range[2], regularVar_names) }) }, .id = "year")
最终all_results会包含所有年份、所有年龄组的汇总数据,结构清晰便于后续分析。
内容的提问来源于stack exchange,提问作者abrar
相关产品推荐
相关产品推荐

