R语言:基于年份条件用lapply优化数值列批量取整的方法问询
批量处理指定年份后的数值列取整方案
问题背景
你有一个包含城市名称、年份及50+数值列的数据框,需要仅对2018年及以后的行,将所有数值列用plyr::round_any(x, 3)取整为3的倍数。现有拆分合并数据框的方法可行,但手动指定列索引效率极低,需要更简洁的批量处理方案,且不能修改年份列。
优化方案(Tidyverse 风格)
利用dplyr的across()函数可以自动批量处理目标列,无需拆分数据框,代码更简洁易维护:
library(tidyverse) library(plyr) # 需加载plyr包提供round_any函数 # 原始数据构建(你的代码) names <- rep(c("City A", "City B"), each = 11) year <- rep(c(2010:2020), times = 2) col_1 <- c(1, 17, 34, 788, 3, 4, 78, 98, 650, 45, 20, 23, 45, 56, 877, 54, 12, 109, 167, 12, 19, 908) col_2 <- c(3, 4, 23, 433, 2, 45, 34, 123, 98, 76, 342, 760, 123, 145, 892, 23, 5, 90, 40, 12, 67, 98) df <- as.data.frame(cbind(names, year, col_1, col_2)) %>% mutate(across(c(col_1, col_2), as.numeric)) # 核心优化代码 df <- df %>% mutate( across( # 自动选择所有数值列,排除year列 .cols = where(is.numeric) & !matches("year"), # 仅对2018年及以后的行应用取整,其余保持原样 .fns = ~ ifelse(year >= 2018, plyr::round_any(.x, 3), .x) ) )
代码说明
- 列选择逻辑:
where(is.numeric) & !matches("year")会自动识别所有数值类型的列,同时排除年份列,无需手动罗列50多列的名称或索引。 - 条件修改:通过
ifelse实现行级判断,仅对符合年份条件的行修改数值,避免拆分合并数据框的繁琐操作。 - 灵活性扩展:如果你的数值列有统一命名前缀(比如都以
col_开头),可以用starts_with("col_")替代where(is.numeric) & !matches("year"),更精准:df <- df %>% mutate( across( .cols = starts_with("col_"), .fns = ~ ifelse(year >= 2018, plyr::round_any(.x, 3), .x) ) )
大数据场景备选方案(data.table)
如果数据量较大,data.table的操作效率更高:
library(data.table) library(plyr) setDT(df) # 筛选出所有数值列(排除year) num_cols <- setdiff(names(df)[sapply(df, is.numeric)], "year") # 仅对2018年及以后的行批量修改 df[year >= 2018, (num_cols) := lapply(.SD, plyr::round_any, 3), .SDcols = num_cols]
内容的提问来源于stack exchange,提问作者evam
相关产品推荐
相关产品推荐

