如何在R中按ID过滤掉与负值数量匹配的正值行?
解决方案
你可以通过分组计算每个ID的负值数量,再对正值行进行抽样保留指定数量的方式实现需求,最终满足nrow(df) == sum(df$count)的条件。具体代码如下:
library(tidyverse) set.seed(1) # 生成示例数据 df <- tibble( count = sample(c(-1,1),80,replace = TRUE,prob=c(.2,.8)), id = rep(1:4,20) ) # 处理数据:移除所有负值行,同时移除与负值数量相等的正值行 result <- df %>% group_by(id) %>% # 计算当前ID的负值数量和需要保留的正值数量(即sum(count)) mutate( neg_count = sum(count == -1), keep_pos = sum(count) ) %>% # 仅保留正值行 filter(count == 1) %>% # 随机抽取需要保留的正值行数量(若不需要随机,可改用slice_head/slice_tail) slice_sample(n = first(keep_pos)) %>% ungroup() %>% # 移除辅助计算列 select(-neg_count, -keep_pos) # 验证条件 nrow(result) == sum(result$count) # 返回TRUE,说明满足要求 # 查看处理后每个ID的结果统计 result %>% group_by(id) %>% summarize(保留行数 = n(), count总和 = sum(count))
逻辑说明
- 按
id分组后,统计每个组内的负值行数量neg_count,以及需要保留的正值行数量keep_pos(即该组count的总和,等于原正值数减去负值数)。 - 筛选出所有正值行,通过
slice_sample随机抽取keep_pos行,确保保留的正值行数量恰好抵消退款后的有效计数。 - 最终保留的数据集仅包含未被退款抵消的正值行,行数等于
count总和,完全满足nrow(df) == sum(df$count)的要求。
如果业务场景需要保留负值行(仅移除对应数量的正值行),可调整代码如下,但此时nrow(df) == sum(df$count)的条件不再成立(负值行的count为-1会拉低总和):
# 保留负值行的版本 result_with_neg <- df %>% group_by(id) %>% mutate( neg_count = sum(count == -1), keep_pos = sum(count) ) %>% # 保留所有负值行 + 指定数量的正值行 filter(count == -1 | (count == 1 & row_number() <= keep_pos)) %>% ungroup() %>% select(-neg_count, -keep_pos)
内容的提问来源于stack exchange,提问作者Hmil
相关产品推荐
相关产品推荐

