Эффективное объединение данных по группам в R - PullRequest
0 голосов
/ 24 января 2019

У меня относительно большой (~ 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 решений, если они значительно быстрее.

1 Ответ

0 голосов
/ 24 января 2019

Как насчет использования data.table и ntile из dplyr?

library(dplyr)
library(data.table)
df <- as.data.table(df)
df[, bucket:=ntile(value,4), by=year]

Вы можете также использовать ntile со своим кодом, но я считаю, что data.table быстрее и чище

Использование квантиля:

library(dplyr) 
library(data.table)
df <- as.data.table(df)
df[, bucket:= as.integer(cut(value, 
                            breaks = quantile(value, probs = c(0, .25, .5, .75, 1)), 
                            include.lowest = T)), by=year]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...