R语言:如何基于两列值优雅删除数据框指定行?
基于年份和ID批量删除数据框行的简洁实现
问题背景
有一个包含35列、约25万行的data frame,需要根据year和network_id列的值删除指定行,删除规则由以下列表定义:
remove.nets <- list(r19=c(14, 31), r21=c(31), r23=c(32), r24=c(1, 4, 8, 24, 30, 59))
规则对应关系:
- 2019年(对应
r19):删除network_id为14、31的行 - 2021年(对应
r21):删除network_id为31的行 - 2023年(对应
r23):删除network_id为32的行 - 2024年(对应
r24):删除network_id为1、4、8、24、30、59的行
原尝试代码报错:
test.data2 <- test.data %>% {if (year==2019) filter(., !network_id %in% remove.nets$r19)}
错误信息:
Error in year == 2019 : comparison (==) is possible only for atomic and list types
目前已通过anti_join实现需求,但希望获得更简洁优雅的方案。
简洁实现方法
方法1:dplyr的case_when+filter直接筛选
直接在filter中通过case_when匹配年份对应的删除ID列表,筛选出不符合删除条件的行:
library(dplyr) test.data2 <- test.data %>% filter(!case_when( year == 2019 ~ network_id %in% remove.nets$r19, year == 2021 ~ network_id %in% remove.nets$r21, year == 2023 ~ network_id %in% remove.nets$r23, year == 2024 ~ network_id %in% remove.nets$r24, TRUE ~ FALSE # 其他年份不执行删除 ))
方法2:自动转换规则列表后用anti_join
无需手动构造删除规则的data frame,通过代码自动转换原列表为结构化数据,再执行anti_join:
library(dplyr) library(tibble) # 自动转换规则列表为年份-ID对应的数据框 remove_df <- enframe(remove.nets, name = "year_code", value = "network_id") %>% mutate(year = as.integer(sub("r", "", year_code))) %>% unnest(network_id) %>% select(year, network_id) # 筛选保留数据 test.data2 <- test.data %>% anti_join(remove_df, by = c("year", "network_id"))
这种方法适配规则列表的变动,无需手动维护年份和ID的对应关系。
方法3:base R向量化实现
如果不依赖tidyverse包,可使用base R的向量化判断完成筛选:
# 构建年份与删除ID的映射 year_map <- list( "2019" = remove.nets$r19, "2021" = remove.nets$r21, "2023" = remove.nets$r23, "2024" = remove.nets$r24 ) # 生成需要删除的行的判断逻辑 to_remove <- mapply( function(y, ids) test.data$year == y & test.data$network_id %in% ids, y = as.integer(names(year_map)), ids = year_map ) %>% rowSums() > 0 # 筛选保留数据 test.data2 <- test.data[!to_remove, ]
内容的提问来源于stack exchange,提问作者Stuart
相关产品推荐
相关产品推荐

