У меня относительно большой (~ 2,5 миллиона записей) фрейм данных, более или менее структурированный следующим образом:
df <- tibble(year = rep(2000:2009, times = 10), value = sample(0:1000, 100)) %>%
arrange(year)
Я хочу назначить каждое значение в интервал на основе квантилей в течение каждого года (например, наблюдения1 находится в нижнем квартиле значений в 2000 году).Для моего тривиального примера это прекрасно работает:
df %>%
group_by(year) %>%
mutate(bucket = as.numeric(cut(value,
breaks = quantile(value, probs = c(0, .25, .5, .75, 1)),
include.lowest = T)))
df
# A tibble: 100 x 3
# Groups: year [10]
year value bucket
<int> <int> <dbl>
1 2000 281 1
2 2000 336 2
3 2000 873 4
4 2000 41 1
5 2000 335 1
6 2000 939 4
7 2000 746 3
8 2000 762 4
9 2000 345 2
10 2000 628 3
Но в моем полном наборе данных это (что неудивительно) занимает вечность.Чтобы ускорить процесс, я рассчитал квантили для каждого года в отдельном фрейме данных:
break_calc <- function(yr) {
library(magrittr)
df %>%
filter(year == yr) %$%
quantile(value, probs = c(0, .25, .5, .75, 1))
}
df_quants <- tibble(year = 2000:2009) %>%
mutate(breaks = map(year, ~break_calc(.x)))
Но даже при этом я изо всех сил пытаюсь найти решение, которое не требует вечности.Это было очень медленно для моих полных данных:
df %>%
mutate(bucket = map2_dbl(value, year,
~cut(.x, breaks = unlist(df_quants$breaks[df_quants$year == .y]), include.lowest = T)))
Это может быть немного быстрее, но не очень хорошо:
df %>%
left_join(df_quants, by = "year") %>%
mutate(bucket = map2_dbl(value, breaks, ~cut(.x, breaks = unlist(.y), include.lowest = T)))
Есть идеи, как это оптимизировать?Сильное предпочтение для сохранения его в юниверсе dplyr / tidyverse, хотя я открыт для применения / data.table решений, если они значительно быстрее.