R // Объединение применяется с условной функцией поиска в R // суммирование значения в столбце A при условии, что Col B и Col C удовлетворяют требованию - PullRequest
1 голос
/ 02 марта 2020

У меня большой набор данных (40 млн. Строк), и я хотел бы сделать 2 вычисления для каждой строки набора данных. (1) как часто человек (с данным идентификатором) инвестировал до этого - временная метка условия <метка времени данной строки и ID == id данной строки (2) кумулятивная сумма, которую человек инвестировал в каждую данную инвестицию - - таким образом, условия те же, что и выше, но суммируют столбец с именем «Значение» вместо подсчета вхождений. Цикл и подмножество фрейма данных было бы вариантом, но это занимает очень много времени, учитывая размер набора данных, поэтому я ищу решение с эффективным использованием ресурсов. Я пытался объединить функцию apply с условным поиском, однако я не могу заставить его работать (см. Попытку ниже). Любая помощь очень ценится. </p>

Пример даты:

timestamp = c("2018-10-04 00:39:02", "2018-10-04 00:50:22", "2018-10-04 03:07:29", "2018-10-04 02:15:57") 
ID = c(1,1,2,3)
Value = c(100, 150, 50, 200)
sample = as.data.frame(cbind(timestamp, ID, Value))
sample$timestamp = as.POSIXct(sample$timestamp)

Подход с применением:

sample$prior_investments = apply(sample, 2, function (x) length(which(sample$ID == ID & sample$timestamp < timestamp)))
sample$invested_amount = apply(sample, 2, function (x) sum(which(sample$ID == ID & sample$timestamp < timestamp)))

Желаемый вывод:

            timestamp ID Value prior_invest invested_amount
1 2018-10-04 00:39:02  1   100       0             0
2 2018-10-04 00:50:22  1   150       1            100
3 2018-10-04 03:07:29  2    50       0             0
4 2018-10-04 02:15:57  3   200       0             0

Ответы [ 3 ]

4 голосов
/ 02 марта 2020

Вы можете просто сделать:

library(data.table)

setDT(sample)
setorder(sample, ID, timestamp)

sample[, Value := as.numeric(as.character(Value))][
  , `:=` (prior_invest = cumsum(Value > 0) - 1,
          invested_amount = cumsum(Value) - Value
          ), 
  by = ID
]

Вывод:

             timestamp ID Value prior_invest invested_amount
1: 2018-10-04 00:39:02  1   100            0               0
2: 2018-10-04 00:50:22  1   150            1             100
3: 2018-10-04 03:07:29  2    50            0               0
4: 2018-10-04 02:15:57  3   200            0               0

С другой стороны, я бы предпочел не использовать sample в качестве имени чего-либо, поскольку оно довольно часто используемая функция.

1 голос
/ 02 марта 2020

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

library(dplyr)

sample %>%
  arrange(ID, timestamp) %>%
  group_by(ID) %>%
  mutate(prior_invest=row_number()-1, 
         invested_amount=cumsum(Value)-Value) 

# A tibble: 4 x 5
# Groups:   ID [3]
  timestamp              ID Value prior_invest invested_amount
  <dttm>              <dbl> <dbl>        <dbl>           <dbl>
1 2018-10-04 00:39:02     1   100            0               0
2 2018-10-04 00:50:22     1   150            1             100
3 2018-10-04 03:07:29     2    50            0               0
4 2018-10-04 02:15:57     3   200            0               0
1 голос
/ 02 марта 2020

может быть, это для вашего первого столбца. Использование data.table обычно является хорошей идеей, когда вы работаете с очень большими таблицами. Обратите внимание, что у вас было apply(sample, 2, ...), где 2 обозначает столбцы, но вы должны go по строкам (1). Также столбец ID представляет собой строку, поэтому вы хотите использовать %in% вместо ==

library(data.table)
sample <- as.data.table(sample)
sample$prior_investments = apply(sample, 1, function(x) nrow(subset(sample, ID %in% x[2] & timestamp < x[1])))
...