Вычислить средние значения ограниченного диапазона числовой переменной c, сгруппированной по уровням фактора - PullRequest
1 голос
/ 24 марта 2020

У меня есть фрейм данных с числовой переменной V1 и факторной переменной Effect:

set.seed(123)
df <- data.frame(
  V1 = c(rnorm(100)),
  Effect = sample(LETTERS[1:4], 100, replace = T)
)

Для каждого уровня Effect я хотел бы вычислить средние значения этих значений V1, которые попадают между первым и третьим квартилем. Я знаю, как рассчитать квартили для всех уровней факторов:

quants <- aggregate(V1 ~ Effect, data = df, quantile) 
quants
  Effect       V1.0%      V1.25%      V1.50%      V1.75%     V1.100%
1      A -2.30916888 -0.55815839 -0.02854676  0.55115731  1.53261063
2      B -1.96661716 -0.37066003  0.33178196  0.68864025  1.36860228
3      C -1.13813694 -0.42358228  0.01381897  0.92773709  2.16895597
4      D -1.02642090 -0.49385424 -0.22407620  0.72100821  2.18733299

Но сейчас я борюсь с тем, как использовать информацию в quants для вычисления соответствующих средних для всех уровней факторов в одном * 1031. *.

Я пробовал это до сих пор:

Я преобразовал quants, чтобы сделать его столбцы более доступными:

quants <- as.data.frame.list(quants)

Затем я использовал этот оператор tapply:

tapply(df$V1, df$Effect, function(x)  mean(x[x >= quants_new$V1.25. & x <= quants_new$V1.75.]))

Но результаты неверны, и есть предупреждения:

           A            B            C            D 
 0.172908276  0.167233413  0.002957323 -0.108590409 
Warning messages:
1: In x >= quants_new$V1.25. :
  longer object length is not a multiple of shorter object length
2: In x <= quants_new$V1.75. :
  longer object length is not a multiple of shorter object length
3: In x >= quants_new$V1.25. :
  longer object length is not a multiple of shorter object length
4: In x <= quants_new$V1.75. :
  longer object length is not a multiple of shorter object length

Как можно исправить оператор tapply для вычисления средства, ограниченные межквартильным диапазоном для всех уровней факторов? Другие решения также приветствуются.

Ответы [ 2 ]

1 голос
/ 24 марта 2020

Мы можем сделать это в пределах aggregate:

aggregate(V1~Effect, df, function(x) 
         mean(x[x >= quantile(x, 0.25) & x <= quantile(x, 0.75)], na.rm = TRUE))

Используя dplyr, которое может быть:

library(dplyr)

df %>%
  group_by(Effect) %>%
  summarise(mean_val = mean(V1[between(V1, quantile(V1, 0.25), 
                              quantile(V1, 0.75))], na.rm = TRUE))
1 голос
/ 24 марта 2020

Я не проверял, верны ли цифры, но это, используя data.table() из пакета data.table вместо data.frame, должно работать на то, что, я думаю, вы ищете ...

dt1[V1 > quantile(V1, 0.25) & V1 < quantile(V1, 0.75), 
  mean(V1), keyby = Effect]

Это группирует ваши данные по «Эффекту», внутри этих групп, принимая значения в пределах 50% средних значений и принимая их среднее значение.


Редактировать, код выше сначала взял подмножество перед группировкой (извините, тестирование пропустило это), чтобы взять квантиль каждой группы:

dt1[dcast(dt1[, .(unlist(lapply(.SD, quantile, c(0.25, 0.75))), qt = c("lo", "up")), by = Effect], ... ~ qt, value.var = "V1"), on = "Effect"][V1 >= lo & V1 <= up, mean(V1), keyby = Effect]

Это дает те же значения, что и ответ Ронака. Он получает квантиль каждой группы, расширяет его dcast, объединяет его с исходной таблицей data.table, затем поднастраивает, используя новые переменные lo и up (нижняя и верхняя границы квантиля), и получает среднее значение для каждой группы оставшихся значений. .

...