You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按类别裁剪data frame指定百分比的首尾数据?R语言疑问

问题描述

数据准备

我有如下数据框:

set.seed(3994)
val <- round(runif(n=30, min = 5, max= 300), digits=0)
cat <- rep(c("A", "B", "C"), each= 10)
date <- as.Date(sample(seq(as.Date('2000/01/01'), as.Date('2020/01/01'), by="day"), 30))

df <- data.frame(val, cat, date)
df <- df %>%  
  arrange(cat, val)

需求

希望按cat列的类别,分别裁剪每个类别数据中基于val列排序后的顶部X%和底部X%数据,例如移除类别"A"、"B"、"C"各自的顶部2%和底部2%数据。

自行编写的代码

我编写了如下代码:

trimTopBottomByCategory <- function(dataframe, category_col, numeric_col, date_column,  x) {
  trimmed_dataframes <- list()
  
  categories <- unique(dataframe[[category_col]])
  for (category in categories) {
    subset_df <- dataframe[dataframe[[category_col]] == category, ]
    
    n <- nrow(subset_df)
    num_to_trim <- ceiling(x / 100 * n)
    
    sorted_subset <- subset_df[order(subset_df[[numeric_col]]), ]
    trimmed_dataframes[[category]] <- sorted_subset[(num_to_trim + 1):(n - num_to_trim), ]
  }

  trimmed_combined <- do.call(rbind, trimmed_dataframes)
  return(trimmed_combined <- trimmed_combined %>% 
             arrange(category_col, date_column))
}

疑问

  • 我认为自己的代码能实现需求,但想知道R中是否有现成的方法可以完成该操作?
  • 额外问题:我不理解为什么最终数据的date列没有被排序?

回答

1. R中现成的实现方法

当然有,用dplyr的分组操作就能更简洁地完成,不用写循环:

方法一:基于百分位数排名裁剪

library(dplyr)

trim_by_group <- function(df, group_col, num_col, x) {
  df %>%
    group_by({{group_col}}) %>%
    mutate(rank = percent_rank({{num_col}})) %>%
    filter(rank > x/100 & rank < 1 - x/100) %>%
    select(-rank) %>%
    ungroup()
}

调用示例:trimmed_df <- trim_by_group(df, cat, val, 2)

方法二:和你原逻辑一致(按数量裁剪)

如果要和你原代码一样用ceiling计算每个组需要裁剪的行数,代码可以写成:

trim_by_group <- function(df, group_col, num_col, x) {
  df %>%
    group_by({{group_col}}) %>%
    arrange({{num_col}}) %>%
    slice((ceiling(x/100*n())+1):(n() - ceiling(x/100*n()))) %>%
    ungroup()
}

大数据集推荐:data.table实现

如果处理的是大数据集,data.table的效率更高:

library(data.table)
setDT(df)
trimmed_df <- df[, .SD[(ceiling(0.02*.N)+1):(.N - ceiling(0.02*.N))], by = cat]

2. date列未排序的原因及解决方法

问题出在你最后arrange的参数上:你传入的category_col和date_column是字符串变量,但dplyr的arrange默认识别的是直接写的列名,不是字符串。你原代码相当于在尝试对名为category_col和date_column的列排序,而不是你实际传入的cat和date,所以自然不会按date列排序。

修改方法很简单,用.data代词引用字符串形式的列名即可:

return(trimmed_combined %>% arrange(.data[[category_col]], .data[[date_column]]))

内容的提问来源于stack exchange,提问作者Joe the Second

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 23:26:01