R语言如何对列表内多个数据框批量应用case_when函数转换列值
R列表批量处理数据框转换方案
首先先修正两处原有代码的问题:
- 单数据框转换逻辑中
FLOOR列的判断条件笔误:"FLOOR" == 1是字符串和数值比较,永远返回FALSE,需改为列名调用FLOOR == 1 - 示例列表构建代码错误:
as.list(df1, df2)无法生成包含两个数据框的列表,需改为sample_list <- list(df1, df2),同时不建议用sample做变量名,会和R内置的抽样函数sample()冲突。
方案1:base R + dplyr 实现(无额外依赖)
列表批量处理的核心逻辑是遍历列表内每个数据框元素,套用已经写好的mutate+case_when逻辑即可,用base R的lapply()就能实现:
library(dplyr) # 构建正确的输入列表 df1 <- structure(list(FLOOR = c(1, 3, 3, 3, 3, 3), LIGHTING = c(1, 1, 1, 1, 4, 1), COOKING = c(3, 5, 5, 5, 5, 3), DRINKING_W = c(1,2, 2, 5, 7, 8), TOILET = c(1, 1, 1, 1, 1, 4), SEPTIC_TAN = c(1,2, 2, 3, 1, 0), TELEPHONE = c(2, 4, 4, 4, 4, 2), TENURE = c(1,1, 1, 4, 1, 1)), row.names = c(7L, 9L, 10L, 65L, 66L, 10578L), class = "data.frame") df2 <- structure(list(FLOOR = c(3, 3, 3, 3, 6, 3), LIGHTING = c(1, 1,1, 1, 2, 1), COOKING = c(5, 5, 5, 5, 5, 5), DRINKING_W = c(7,7, 7, 7, 8, 8), TOILET = c(3, 3, 3, 3, 4, 4), SEPTIC_TAN = c(3,3, 3, 3, 0, 0), TELEPHONE = c(2, 2, 2, 2, 4, 2), TENURE = c(1,1, 1, 1, 2, 2)), row.names = 252098:252103, class = "data.frame") sample_list <- list(df1, df2) # 批量转换 processed_list <- lapply(sample_list, function(current_df) { current_df %>% mutate(FLOOR = case_when(FLOOR == 1 ~ "1", TRUE ~ "0"), LIGHTING = case_when(LIGHTING == 1 ~ "1", TRUE ~ "0"), COOKING = case_when(COOKING == 1 ~ "1", TRUE ~ "0"), DRINKING_W = case_when(DRINKING_W == 1 ~ "1", TRUE ~ "0"), TOILET = case_when(TOILET == 1 ~ "1", TRUE ~ "0")) })
返回的processed_list和原列表顺序、结构完全一致,每个元素都是完成转换的数据框。
方案2:purrr 实现(适配tidyverse工作流)
如果你日常使用tidyverse生态的函数,用purrr::map()实现遍历语法更统一,逻辑和lapply完全一致:
library(dplyr) library(purrr) processed_list <- map(sample_list, ~.x %>% mutate(FLOOR = case_when(FLOOR == 1 ~ "1", TRUE ~ "0"), LIGHTING = case_when(LIGHTING == 1 ~ "1", TRUE ~ "0"), COOKING = case_when(COOKING == 1 ~ "1", TRUE ~ "0"), DRINKING_W = case_when(DRINKING_W == 1 ~ "1", TRUE ~ "0"), TOILET = case_when(TOILET == 1 ~ "1", TRUE ~ "0")))
优化写法:消除重复代码
观察转换规则可以发现,5个目标列的判断逻辑完全相同:值等于1则返回字符串"1",否则返回"0",不需要重复写5次case_when,可以借助dplyr::across()一次性处理所有指定列,后续要增减转换列只需要修改目标列向量即可,维护成本更低:
# 把需要转换的列统一存在向量里 target_cols <- c("FLOOR", "LIGHTING", "COOKING", "DRINKING_W", "TOILET") processed_list <- lapply(sample_list, function(current_df) { current_df %>% mutate(across(all_of(target_cols), ~case_when(.x == 1 ~ "1", TRUE ~ "0"))) })
如果你需要转换后的结果是数值型而非字符型,只需要去掉返回值的引号,写为
~case_when(.x == 1 ~ 1, TRUE ~ 0)即可。
内容的提问来源于stack exchange,提问作者Kian
相关产品推荐
相关产品推荐

