Получить значения из столбца, в котором порог впервые пройден для каждой группы в R - PullRequest
0 голосов
/ 25 мая 2018

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

Вот пример того, что я уже сделал: Пример набора данных:

df <- data.frame(name = rep(c("a","b"),4), 
    dates = seq(as.Date("2017-01-01"), by = "month", length.out = 8), amt = 11:18)
setorderv(df, "name")

Это даетмне следующий кадр данных

  name      dates amt
1    a 2017-01-01  11
3    a 2017-03-01  13
5    a 2017-05-01  15
7    a 2017-07-01  17
2    b 2017-02-01  12
4    b 2017-04-01  14
6    b 2017-06-01  16
8    b 2017-08-01  18

Затем я написал следующий код, чтобы найти совокупные суммы

df$cumsum <- ave(df$amt, df$name, FUN = cumsum)

Это дает мне следующий кадр данных:

  name      dates amt cumsum
1    a 2017-01-01  11     11
3    a 2017-03-01  13     24
5    a 2017-05-01  15     39
7    a 2017-07-01  17     56
2    b 2017-02-01  12     12
4    b 2017-04-01  14     26
6    b 2017-06-01  16     42
8    b 2017-08-01  18     60

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

names <- unique(df$name)    
for (i in seq_along(names)){
    x1 <- Position(function(x) x >= 20, df$cumsum[df$name == names[i]])
    x2 <- Position(function(x) x >= 40, df$cumsum[df$name == names[i]])

    result_df[i,] <- c(df$name[i], 
                         df[df$name == names[i],2][x1],
                         df[df$name == names[i],2][x2])
}

Этот код проверяет, где были пересечены пороги, и сохраняет номер строки в переменной.Затем извлекает значение из этой строки второго столбца и сохраняет его в другом фрейме данных.

Проблема в том, что этот код действительно медленный.В моем наборе данных более 200 000 человек и более 10 миллионов строк.Выполнение этого кода занимает около 25 секунд для первых 50 пользователей, что означает, что для всего набора данных может потребоваться около 30 часов.

Есть ли более быстрый способ сделать это?

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Использование таблицы данных может выглядеть примерно так:

library(data.table)

dt <- data.table(df[order(df$dates), ])

dt[ ,':='(minDate20 = min(dates[cumsum(amt) > 20]), minDate40 = min(dates[cumsum(amt) > 40])), by = .(name)]


dt[dates == minDate20, ]
dt[dates == minDate40, ]
0 голосов
/ 25 мая 2018

С помощью dplyr вы можете группировать по отдельным лицам, фильтровать, когда cumsum выше> 20 или выше> 40, а затем использовать slice (1), чтобы выбрать первую соответствующую строку для каждого человека.Должно быть намного быстрее, чем для зацикливания.

df <- read.table(text = '
name      dates amt cumsum
a 2017-01-01  11     11
a 2017-03-01  13     24
a 2017-05-01  15     39
a 2017-07-01  17     56
b 2017-02-01  12     12
b 2017-04-01  14     26
b 2017-06-01  16     42
b 2017-08-01  18     60', header = T)

df %>% 
  group_by(name) %>% 
  filter(cumsum > 20) %>% 
  slice(1)

       name      dates   amt cumsum
      <fctr> <fctr> <int>  <int>
1      a 2017-03-01    13     24
2      b 2017-04-01    14     26

df %>% 
  group_by(name) %>% 
  filter(cumsum > 40) %>% 
  slice(1)

   name      dates   amt cumsum
  <fctr>     <fctr> <int>  <int>
      a 2017-07-01    17     56
      b 2017-06-01    16     42

Конечно, вы можете впоследствии связать эти кадры данных и договориться о человеке.Это помогает?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...