Частотно-взвешенный процентиль в кадре данных с dplyr - PullRequest
2 голосов
/ 18 июня 2020

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

Например:

groceries <- tribble(
  ~item, ~price, ~freq,
  "apple",   1, 20,
  "banana",   2, 5,
  "carrot",   3, 1
)

groceries %>% 
    mutate(reg_ptile = percent_rank(price),
           wtd_ptile = weighted_percent_rank(price, wt = freq))

# the expected result would be:

# A tibble: 3 x 5
  item   price  freq reg_ptile wtd_ptile
  <chr>  <dbl> <dbl> <dbl>     <dbl>
1 apple      1    20  0.0      0.0
2 banana     2     5  0.5      0.8
3 carrot     3     1  1.0      1.0

percent_rank() - это фактическая функция dplyr. Как бы была написана функция weighted_percent_rank()? Не уверен, как заставить это работать в кадре данных и каналах. Было бы здорово, если бы решение могло также работать с группами.

Изменить: Использование uncount() на самом деле не работает, потому что разложение данных, которые я использую, приведет к 800 миллиардам строк. Есть еще идеи?

1 Ответ

2 голосов
/ 18 июня 2020

Вы можете использовать tidyr::uncount, чтобы увеличить количество строк в соответствии с частотой, чтобы получить взвешенный процентиль, а затем уменьшите их обратно с помощью summarize в соответствии с этим регулярным выражением:

library(dplyr)

groceries <- tribble(
  ~item, ~price, ~freq,
  "apple",   1, 10,
  "banana",   2, 5,
  "carrot",   3, 1
)

groceries %>% 
  tidyr::uncount(freq) %>% 
  mutate(wtd_ptile = percent_rank(price)) %>%
  group_by(item) %>%
  summarize_all(~.[1]) %>%
  mutate(ptile = percent_rank(price))
#> # A tibble: 3 x 4
#>   item   price wtd_ptile ptile
#>   <chr>  <dbl>     <dbl> <dbl>
#> 1 apple      1     0       0  
#> 2 banana     2     0.667   0.5
#> 3 carrot     3     1       1

Обратите внимание на вы можете выбрать разные функции ранжирования, хотя в этом случае взвешенный процентиль равен 0,667 (10/(16 - 1)), а не 0,8


EDIT

Альтернатива, не требует создания миллиардов строк:

groceries %>% 
  arrange(price) %>% 
  mutate(wtd_ptile = lag(cumsum(freq), default = 0)/(sum(freq) - 1))
#> # A tibble: 3 x 4
#>   item   price  freq wtd_ptile
#>   <chr>  <dbl> <dbl>     <dbl>
#> 1 apple      1    10     0    
#> 2 banana     2     5     0.667
#> 3 carrot     3     1     1  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...