Как сделать сгруппированную сводную статистику на основе плотностей в R - PullRequest
0 голосов
/ 25 января 2020

Цель: я хотел бы сгруппировать процентили для каждой группы (hrzn)

У меня есть следующие данные

# A tibble: 3,500 x 3
    hrzn parameter density
   <dbl>     <dbl>   <dbl>
 1     1    0.0183 0.00914
 2     1    0.0185 0.00905
 3     1    0.0187 0.00897
 4     1    0.0189 0.00888
 5     1    0.0191 0.00880
 6     1    0.0193 0.00872
 7     1    0.0194 0.00864
 8     1    0.0196 0.00855
 9     1    0.0198 0.00847
10     1    0.0200 0.00839

hrzn - это группа, parameter - это сетка пространства параметров, а density - плотность значения в столбце parameter.

Я бы хотел сгенерировать итоговые процентили статистики от 10 до 90 на 10 к hrzn. Я пытаюсь сохранить эффективность вычислений. Я знаю, что мог бы сэмплировать параметр с плотностью в виде весов, но мне любопытно, что есть более быстрый способ генерирования процентилей из плотности без выборки.

Данные могут быть получены с помощью следующих

df <- readr::read_csv("https://raw.githubusercontent.com/alexhallam/density_data/master/data.csv")

1 Ответ

2 голосов
/ 25 января 2020

Когда я загружаю данные из вашего CSV, каждая из 5 групп имеет идентичные значения для параметра и плотности:

df
#># A tibble: 3,500 x 3
#>    hrzn parameter density
#>   <int>     <dbl>   <dbl>
#> 1     1    0.0183 0.00914
#> 2     1    0.0185 0.00905
#> 3     1    0.0187 0.00897
#> 4     1    0.0189 0.00888
#> 5     1    0.0191 0.00880
#> 6     1    0.0193 0.00872
#> 7     1    0.0194 0.00864
#> 8     1    0.0196 0.00855
#> 9     1    0.0198 0.00847
#>10     1    0.0200 0.00839
#># ... with 3,490 more rows

sapply(1:5, function(x) all(df$parameter[df$hrzn == x] == df$parameter[df$hrzn == 1]))
# [1] TRUE TRUE TRUE TRUE TRUE

sapply(1:5, function(x) all(df$density[df$hrzn == x] == df$density[df$hrzn == 1]))
# [1] TRUE TRUE TRUE TRUE TRUE

Я не уверен, является ли это ошибкой или нет, но ясно, если Вы беспокоитесь о вычислениях, все, что вы хотите сделать во всех группах, можно сделать в 5 раз быстрее, если делать это только в одной группе.

В любом случае, чтобы получить 10-й и 90-й центили для каждой гривны вам просто нужно увидеть, какой параметр находится рядом с 0,1 и 0,9 в интегральной функции распределения. Давайте обобщим, чтобы проработать это для всех групп в случае, если есть проблема с данными или вы хотите повторить это с другими данными:

library(dplyr)

df %>% 
  mutate(hrzn = factor(hrzn)) %>%
  group_by(hrzn) %>% 
  summarise(centile_10 = parameter[which(cumsum(density) > .1)[1]],
            centile_90 = parameter[which(cumsum(density) > .9)[1]] )

#># A tibble: 5 x 3
#>  hrzn  centile_10 centile_90
#>  <fct>      <dbl>      <dbl>
#>1 1         0.0204      0.200
#>2 2         0.0204      0.200
#>3 3         0.0204      0.200
#>4 4         0.0204      0.200
#>5 5         0.0204      0.200

Конечно, они все одинаковы по упомянутым причинам выше.

Если вас беспокоит время вычислений (хотя вышеприведенное занимает всего несколько миллисекунд), и вы не возражаете против непрозрачного кода, вы можете воспользоваться порядком cut the cumsum всего вашего столбца density в диапазоне от 0 до 5 с шагом 0,1, чтобы получить все 10-ые процентили, например:

summary <- df[which((diff(as.numeric(cut(cumsum(df$density), seq(0,5,.1))) - 1) != 0)) + 1,]
summary <- summary[-(1:5)*10,]
summary$centile <- rep(1:9*10, 5)
summary
#> # A tibble: 45 x 4
#>     hrzn parameter density centile
#>    <int>     <dbl>   <dbl>   <dbl>
#>  1     1    0.0204 0.00824      10
#>  2     1    0.0233 0.00729      20
#>  3     1    0.0271 0.00634      30
#>  4     1    0.0321 0.00542      40
#>  5     1    0.0392 0.00453      50
#>  6     1    0.0498 0.00366      60
#>  7     1    0.0679 0.00281      70
#>  8     1    0.103  0.00199      80
#>  9     1    0.200  0.00114      90
#> 10     2    0.0204 0.00824      10
#> # ... with 35 more rows

Возможно, я вас неправильно понял, и вы на самом деле работаете в пространство параметров и хотите знать значения параметров в 10-м и 90-м центилях 5-й плотности. В этом случае вы можете воспользоваться тем фактом, что все группы одинаковы для вычисления 10-го и 90-го центилей для 5-й плотности, просто взяв 5-й root из этих двух центилей:

df %>% 
  mutate(hrzn = factor(hrzn)) %>%
  group_by(hrzn) %>% 
  summarise(centile_10 = parameter[which(cumsum(density) > .1^.2)[1]],
            centile_90 = parameter[which(cumsum(density) > .9^.2)[1]] )

#> # A tibble: 5 x 3
#>   hrzn  centile_10 centile_90
#>   <fct>      <dbl>      <dbl>
#> 1 1         0.0545      0.664
#> 2 2         0.0545      0.664
#> 3 3         0.0545      0.664
#> 4 4         0.0545      0.664
#> 5 5         0.0545      0.664
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...