R中如何按类型(day)删除data.frame中每组前10%的行并保留排序
提问内容
抱歉我来自俄罗斯,英语不好。我刚开始学习R,目前遇到一个问题,恳请大家帮忙。我有一个已按V3列升序、V4列降序排序的data.frame,数据由多个文件合并汇总得到。我需要为每个类型(day)删除/过滤掉前10%的行,同时保留原有排序。
我的数据处理代码如下:
library(gdata) myfiles <- list.files("G:/YA_3D/119_211124", pattern = ".txt", full.names = TRUE, recursive = TRUE) myfiles1 <- lapply(myfiles, read_csv)%>% plyr::rbind.fill(myfiles1) write.fwf(myfiles1,file="G:/DD_1-125_cor.x",sep=" ", quote=F, rownames=T) TILER <- read.table("G:/DD_1-125_cor.x", fill = TRUE, skip = 1) TILER$V1 <- sequence(rle(as.character(TILER$V3))$lengths)
在执行上述操作前,我的data.frame如下(已将行数缩减到8行作为示例):
V1 V2 V3 V4 1 hg 2410 96 2 hg 2410 92 3 hg 2410 91 1 hg 2411 98 2 hg 2411 95 1 hg 2501 36 2 hg 2501 30
接下来我统计了每个类型的行数,将得到的数值除以100再乘以10(尝试通过V1列结合ifelse删除所有小于新表对应值的行)
TILER1 <- TILER %>% select(V3, V4)
TILER1结构如下:
V3 V4 2410 96 2410 92 2410 91 2411 98 2411 95 2501 36 2501 30
随后我执行了如下操作:
TILER.Prod_A <- desc_statby(TILER1, measure.var = "V4", grps = "V3") %>% mutate(YYY3 = ifelse(length >2000, 1, 2)) %>% filter(YYY3 == "1") %>% mutate(Proz = round(length/100)*10) %>% select(V3, length, Proz)
执行上述操作后得到的新data.frame如下(示例中的Proz为模拟值,实际场景下由于行数很多,该值大于1000):
V3 length Proz 2410 3 0.3 2411 2 0.2 2501 2 0.2
最后我尝试在两个表之间应用ifelse语句实现匹配过滤:
TILER3 <- TILER %>% mutate(T1 = ifelse(V3 == TILER.Prod_A$V3 & V1 < TILER.Prod_A$Proz, "1", "2")) %>% filter(T1 == 2)
但ifelse没有按我的预期运行,我无法筛选T1列,因为T1的取值不正确。有没有人可以提供其他可行的实现思路?
问题解答
错误原因
你之前的逻辑不符合预期,核心是跨表直接对比V3 == TILER.Prod_A$V3时,两个向量长度不匹配,R的向量循环规则会导致匹配错乱,无法实现按V3分组对应阈值的效果。你不需要单独生成阈值表再匹配,用dplyr分组操作可以一步完成过滤:
library(dplyr) TILER3 <- TILER %>% # 按V3分组计算 group_by(V3) %>% # 保留你原有规则:仅分组行数>2000时计算前10%截断阈值,不足2000行的分组不删除数据 mutate(cut_line = ifelse(n() > 2000, round(n() * 0.1), 0)) %>% # 过滤掉前cut_line行,保留原有排序 filter(V1 > cut_line) %>% # 移除临时辅助列 ungroup() %>% select(-cut_line)
可选调整
如果你不需要行数>2000的限制,所有分组都删除前10%的行,把cut_line的计算逻辑换成cut_line = ceiling(n() * 0.1)即可,ceiling函数会自动将不足1的阈值向上取整为1,避免小样本分组无法过滤的问题。
内容的提问来源于stack exchange,提问作者user16073844
相关产品推荐
相关产品推荐

