Подмножество кадра данных на основе квантилей - PullRequest
1 голос
/ 31 мая 2019

Если у меня есть этот фрейм данных:

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 ]

5 голосов
/ 31 мая 2019

Вот подход dplyr:

library(dplyr)

df %>% 
  mutate_at(vars(a:e), function(x) if_else(between(percent_rank(x), .1, .9), x, NA_real_))
3 голосов
/ 31 мая 2019

Используйте 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)))
...