Есть ли способ рассчитать асимметричное среднее (например, от процентиля 0,05 до 0,5) по группе с помощью команды агрегата? Р-СТУДИО

Я рассчитываю алгоритм обнаружения выбросов Тьюки на наборе данных о ценах.

Дело в том, что мне нужно, чтобы он вычислялся по группе (другая переменная, включенная в тот же набор данных), которая отлично работает с командой aggregate до тех пор, пока мне не нужно вычислить среднее значение, используя только данные между процентилем 5 до медианы и один использует только данные от медианы до процентиля 95.

Насколько я знаю, команда идет так: aggregate(doc$x, by=list(doc$group), FUN=mean, trim = 0.05), если среднее было обрезано симметрично, взяв верхние и нижние 5% (итого 10%) из данных перед печатью результата. Я не знаю, как выполнить следующие шаги, где мне нужно рассчитать верхнее и нижнее среднее значение, взяв медиану в качестве точки деления, сохраняя при этом верхнее и нижнее значение со скидкой 5%.

medlow <- aggregate(doc1$`rp`, by=list(doc1$`Código Artículo`), FUN=mean,trim =c(0.05,0.5))
medup <- aggregate(doc1$`rp`, by=list(doc1$`Código Artículo`), FUN=mean,trim =c(0.5,0.95))

medtrunc <- aggregate(doc1$`rp`, by=list(doc1$`Código Artículo`), FUN=mean,trim = 0.05)

Я ожидаю, что на выходе будет номер, который мне нужен для каждой группы, но он идет

Ошибка в mean.default(X[[i]], ...) : 'trim' должен быть числовым и иметь длину один.


person Melania CB    schedule 24.08.2019    source источник


Ответы (1)


Во-первых, я думаю, что вы используете aggregate и trim неправильно. 'trim' must be numeric of length one означает, что вы можете исключить только определенную часть данных как из верхних, так и из нижних хвостов распределения:

df = data.frame(
  gender = c(
    "male","male","male","male","female","female","female", "female"
    ),
  score = rnorm(8, 10, 2)
  )
aggregate(score ~ gender, data = df, mean, trim = 0.1)

  gender     score
1 female 11.385263
2   male  9.954465

Для разделения на основе медианы и вычисления усеченного среднего для разделенных данных вы можете легко разделить свой фрейм данных, создав новую переменную MedianSplit с помощью простого цикла for:

df$MedianSplit <- 0
for (i in 1:nrow(df)) {
  if (df$score[i] <= median(df$score)) {
    df$MedianSplit[i] = "lower" 
  } else {
    df$MedianSplit[i] = "upper"
  }
}

df



gender     score MedianSplit
1   male  7.062605       lower
2   male  9.373052       upper
3   male  6.592681       lower
4   male  7.298971       lower
5 female  7.795813       lower
6 female  7.800914       upper
7 female 12.431028       upper
8 female 10.661753       upper

Затем используйте aggregate для вычисления усеченных средних значений:

Для данных ниже медианы (т.е., [0, 0.5])

aggregate(
  score ~ gender, 
  data = df[ which(df$MedianSplit == "lower"), ], 
  mean, trim = 0.05
)

  gender    score
1 female 7.795813
2   male 6.984752

а для тех, кто выше медианы (т. е. [0,5, 1]):

совокупность (оценка ~ пол, данные = df [который (df $ MedianSplit == «верхний»), ], среднее значение, обрезка = 0,05)

  gender     score
1 female 10.297898
2   male  9.373052
person maaniB    schedule 24.08.2019
comment
Чтобы уместить его, представьте, что у вас есть самцы и самки из разных мест, всего 270. Итак, вы хотите получить все эти числа для каждого места, и именно поэтому я пытался использовать «агрегат», чтобы упростить кодирование. Кроме того, в конце обрезка не будет совпадать, потому что мне нужно среднее значение от 0,05 до медианы (0,5), а не 0,45, и то же самое для верхней стороны. - person Melania CB; 25.08.2019
comment
@MelaniaCB, пожалуйста, отредактируйте свой вопрос и приведите минимальный пример, используя dput. Если у вас есть две или более категориальных переменных, использование dplyr и group_by, а затем mutate_at поможет вам больше, чем вы можете себе представить. Я думаю, что подход tidyverse подходит для вашего состояния - person maaniB; 25.08.2019
comment
Можно сделать это, создав функцию infmean ‹- function( x ){ sort(x) inf ‹- mean(quantile(x, 0.05):median(x)) return(inf) } и используя агрегатный метод medinf ‹-aggregate(doc $x, by=list(doc$Group), FUN=infmean) - person Melania CB; 28.08.2019