#r #tidyverse
#r #tidyverse
Вопрос:
В настоящее время я испытываю экспоненциальное увеличение времени, необходимого для выполнения команды с использованием пакета tidyverse.
Рассмотрим следующую структуру (упрощенную):
data <- data.frame(name = c("a","b","c","d","e","f"),
ID =c(1,1,1,2,2,2),
sales = c(100, 250, 300, 50, 600, 390),
t = c(0.1,0.3,0.4,0.05,0.15,0.2),
n=c(1,2,3,1,2,3),
correct_result = c(-221.4,-27.8,69.1,-143.71,-19.11,43.19))
data$ID <- как целое число (data $ID)
Я обнаружил, что более эффективно группировать по идентификатору как целое число, а не как фактор.
Формула, которую я пытаюсь вычислить, подразумевает, что для данного имени, скажем, «a», я хочу взять сумму продаж всех других связанных имен (по их идентификатору) и разделить на 1-t для соответствующих имен. Чтобы получить представление о том, что я пытаюсь вычислить для каждого идентификатора и имени:
(data$sales[2]/(1-data$t[2]))*(data$t[1]-data$t[2]) (data$sales[3]/(1-data$t[3]))*(data$t[1]-data$t[3])
(data$sales[1]/(1-data$t[1]))*(data$t[2]-data$t[1]) (data$sales[3]/(1-data$t[3]))*(data$t[2]-data$t[3])
(data$sales[1]/(1-data$t[1]))*(data$t[3]-data$t[1]) (data$sales[1]/(1-data$t[1]))*(data$t[3]-data$t[1])
library(tidyverse)
# The Model:
data <- data %>%
mutate(ovt=sales/(1-t))
sumforgoup1 <-function(forname , groupid){ # Create the function:
key_t <- dplyr::filter(data,
ID == groupid,
name==forname) %>% pull(t)
temp <- dplyr::filter(data,
ID == groupid,
name!=forname) %>% mutate(diff_key_t=
key_t - t)
sum(temp$ovt*temp$diff_key_t)
}
mutate(rowwise(data),
result = sumforgoup1(name,ID)) # Store result in a new column.
Итак, функция отлично работает в этом наборе данных. Однако, когда я применяю эту функцию к большему набору данных, скажем, с 300 строками, формула занимает примерно 6 секунд. Увеличение количества строк еще на 300 (т. Е. На 600 строк) занимает около 35 секунд..
У меня около 30.000 строк, так что это займет несколько часов..
В полном наборе данных я преобразовал ID в factor, чтобы вы могли получить представление об уровнях (sub здесь = name):
$ ID : Factor w/ 9097 levels "1","2","3","4",..: 1 2 2 3 4 5 5 5 5 5 ...
$ sub : Factor w/ 40 levels "1","2","3","4",..: 1 1 2 1 1 1 2 3 4 5 ...
Приветствуются любые рекомендации / советы,
Спасибо!
Комментарии:
1. Еще один хороший совет — использовать dtplyr (есть ли причина, по которой люди продолжают использовать dplyr вместо dtplyr?) Или data.table . Улучшение скорости реально.
Ответ №1:
Ваш подход медленный, потому что многократная фильтрация данных приводит к большим накладным расходам, в которых нет необходимости. Вместо этого вы можете попробовать:
library(dplyr)
library(purrr)
data %>%
group_by(ID) %>%
mutate(result = map_dbl(seq_along(ID), ~ sum((sales[-.x] / (1 - t[-.x]) * (t[.x] - t[-.x])))))
# A tibble: 6 x 8
# Groups: ID [2]
name ID sales t n correct_result ovt result
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 a 1 100 0.1 1 -221. 111. -221.
2 b 1 250 0.3 2 -27.8 357. -27.8
3 c 1 300 0.4 3 69.1 500 69.0
4 d 2 50 0.05 1 -144. 52.6 -144.
5 e 2 600 0.15 2 -19.1 706. -19.1
6 f 2 390 0.2 3 43.2 488. 43.2
Комментарии:
1. Это сработало! Спасибо! После нескольких недель разочарования было приятно получить ответ.