多类别列中filter()函数无法正确过滤的问题排查
按类别移除首尾指定百分比数据的函数修正方案
问题根源
你的函数在分组过滤阶段出错,核心原因是在group_by后的filter中直接引用外部数据集summary_data$n_to_remove,无法实现每个组匹配对应类别的移除行数。summary_data是独立的汇总表,其n_to_remove是一个向量,在分组环境中无法自动与当前组绑定,导致所有组误用了向量的第一个值,逻辑完全错误。
修正方案(简洁版)
直接在分组内计算每个类别的移除行数,避免外部对象的引用问题:
remove_percentile_by_category <- function(data, measurement_column, category_column, date_column, percent_to_remove) { data_filtered <- data %>% # 按类别和指定度量列排序(确保数据顺序正确) arrange({{category_column}}, {{measurement_column}}) %>% group_by({{category_column}}) %>% # 分组计算当前类别需要移除的首尾行数 mutate(n_to_remove = ceiling(n() * percent_to_remove / 100)) %>% # 过滤掉首尾指定行数:保留行号大于移除数,且小于等于总行数减移除数的行 filter(row_number() > n_to_remove & row_number() <= n() - n_to_remove) %>% # 清理临时计算列 select(-n_to_remove) %>% ungroup() %>% # 最终按类别和日期排序 arrange({{category_column}}, {{date_column}}) return(data_filtered) }
验证测试
用你的数据集测试移除2%的情况:
# 加载依赖包 library(dplyr) # 原始数据集 set.seed(3994) val <- seq(1:60) cat <- rep(c("A", "B", "C"), times=c(30, 20, 10)) date <- as.Date(sample(seq(as.Date('2000/01/01'), as.Date('2020/01/01'), by="day"), 60)) df <- data.frame(val, cat, date) %>% arrange(cat, val) # 执行函数 df_filtered <- remove_percentile_by_category(df, val, cat, date, 2) # 查看每个类别的剩余行数 df_filtered %>% count(cat)
输出结果符合预期:
cat n 1 A 28 (30 - 1*2 = 28,30*2%=0.6,ceiling后取1) 2 B 18 (20 - 1*2 = 18,20*2%=0.4,ceiling后取1) 3 C 8 (10 - 1*2 = 8,10*2%=0.2,ceiling后取1)
备选方案(基于汇总表合并)
如果你坚持要先生成汇总表,可以通过left_join将移除行数合并到原数据,再进行过滤:
remove_percentile_by_category <- function(data, measurement_column, category_column, date_column, percent_to_remove) { data_sorted <- data %>% arrange({{category_column}}, {{measurement_column}}) # 生成每个类别的汇总信息 summary_data <- data_sorted %>% group_by({{category_column}}) %>% summarize(n = n()) %>% mutate(n_to_remove = ceiling(n * percent_to_remove / 100)) # 将汇总信息合并到原数据 data_merged <- left_join( data_sorted, summary_data, by = rlang::as_name(enquo(category_column)) ) # 分组过滤 data_filtered <- data_merged %>% group_by({{category_column}}) %>% filter(row_number() > n_to_remove & row_number() <= n - n_to_remove) %>% select(-n, -n_to_remove) %>% ungroup() %>% arrange({{category_column}}, {{date_column}}) return(data_filtered) }
内容的提问来源于stack exchange,提问作者Joe the Second
相关产品推荐
相关产品推荐

