基于center列过滤多个data frame并拆分保存的R语言问题
问题描述
我有3个均包含center列的data frame,该列有6种不同取值,需要基于这些取值分组并保存为不同的data frame。其中一个data frame的结构如下:
structure(list(NR = c("DBD-0006", "DBD-0057", "DBD-0095", "GHP-0169", "GHP-0237", "NNB-0243", "NNB-0303", "NNB-0306", "NNB-0359", "NNB-0364"), DATE = c("13-07-2011", "15-12-2010", "09-03-2011", "14-09-2011", "30-06-2010", "16-05-2016", "04-07-2012", "11-07-2012", "05-12-2012", "12-12-2012"), CODE= c("1", "1", "1", "1", "1", "1", "1", "1", "1", "1"), DATE2 = c("18-07-2011", "15-12-2010", "09-03-2011", "14-09-2011", "05-01-2012", "11-05-2016", "05-07-2012", "11-07-2012", "06-12-2012", "12-12-2012"), type = c("YY.90.01", "50.19", "50.37", "50.37", "50.37", "YY.90.00", "50.37", "YY.50.01", "YY.82.01", "YY.50.02"), center = c("DBD", "DBD", "DBD", "GHP", "GHP", "NNB", "NNB", "NNB", "NNB", "NNB")), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"))
另外两个data frame的行列数不同,但center和NR(唯一标识列)为所有data frame共有。我将这3个data frame存入列表cnt,尝试用嵌套循环实现过滤,代码如下:
output <- list () for (table in names(cnt)) { #print(table) df1, df2, df3 for (name in names(cnt[[table]])) { #print(name) returns the variable names per df center_name <- c("DBD", "GHP", "NNB") output[[table]] <- cnt[[table]][[name]] %>% filter(center == center_name) } }
运行后出现错误:
Error in UseMethod("filter") : no applicable method for 'filter' applied to an object of class "character"
需要解决该问题,同时希望得到更简洁的非循环实现方案。
错误原因
内层循环for (name in names(cnt[[table]]))遍历的是单个data frame的列名,cnt[[table]][[name]]取出的是某一列的字符向量,而dplyr::filter()是用于处理data frame的函数,无法作用在字符向量上,因此报错。
解决方案
方案1:修复循环实现
去掉多余的内层循环,直接对每个data frame按center取值过滤,将每个分组结果存入嵌套列表:
library(dplyr) # 获取所有唯一的center取值(从任意一个data frame提取即可) all_centers <- unique(cnt[[1]]$center) output <- list() for (df_name in names(cnt)) { current_df <- cnt[[df_name]] # 对每个center值过滤,生成子列表 output[[df_name]] <- lapply(all_centers, function(ct) { current_df %>% filter(center == ct) }) # 给子列表命名,方便后续调用 names(output[[df_name]]) <- all_centers }
此时output是嵌套列表,output$df1$DBD就是第一个data frame中center为"DBD"的子集。
方案2:非循环的简洁实现(推荐)
使用purrr包的函数实现批量处理,代码更简洁:
library(dplyr) library(purrr) # 获取所有唯一的center取值 all_centers <- unique(cnt[[1]]$center) # 对列表中的每个data frame,按center分组拆分 output <- map(cnt, ~group_split(.x, center, .keep = TRUE)) # 给每个分组的子列表命名 output <- map(output, ~set_names(.x, all_centers))
或者如果需要按每个center值单独过滤(和循环逻辑一致):
output <- map(cnt, function(df) { map(all_centers, ~filter(df, center == .x)) %>% set_names(all_centers) })
这样处理后,output的结构和方案1完全一致,无需手动写循环,代码更易读和维护。
内容的提问来源于stack exchange,提问作者Rara
相关产品推荐
相关产品推荐

