根据分位数对数据框进行分组

时间:2019-05-31 07:01:55

标签: r function dplyr subset

如果我有此数据框:

df <- data.frame(time = seq(as.Date('2000-01-01'), length.out = 200, by = 'days'),
             a = rnorm(200,8.4, 22), b=rnorm(200,8.4, 22), d= rnorm(200,8.4, 22), 
e=rnorm(200,8.4, 22))

最简单的方法是将此df子集化,以使每一列中的值都大于一个百分位数的10%,但小于一个百分位数的90%?

我可以使用循环来做到这一点,即:

for (i in names(df[,2:5])){
  print(i)
  column <- df[,c('time', i)]
  q <- unname(quantile(column[,2], probs = c(0.1, 0.9))) # just for one column
  column <- column[column[,2] > q[1] &column[,2] < q[2],]
  df <- merge(df, column, by = 'time', all.x = T)
}

但是,使用dplyr之类的函数或包可以更简单,更优雅地完成此任务。谢谢!

2 个答案:

答案 0 :(得分:5)

这是一种dplyr的方法:

library(dplyr)

df %>% 
  mutate_at(vars(a:e), function(x) if_else(between(percent_rank(x), .1, .9), x, NA_real_))

答案 1 :(得分:3)

在列上使用sapply并过滤范围内的值。

sapply(df[-1], function(x) x[x > quantile(x, 0.1) & x < quantile(x, 0.9)])

要向后添加time列可能很棘手,因为我们已经过滤了每行可能代表不同time的值。

@Sotos建议的更好的选择是将这些值转换为NA而不是过滤

cbind(df[1], sapply(df[-1], function(i) 
            replace(i, i < quantile(i, 0.1) | i > quantile(i, 0.9), NA)))