как ускорить этот код R - PullRequest
       10

как ускорить этот код R

8 голосов
/ 19 октября 2010

У меня есть data.frame ( ссылка на файл ) с 18 столбцами и 11520 строками, которые я преобразую следующим образом:

library(plyr)
df.median<-ddply(data, .(groupname,starttime,fPhase,fCycle), 
                 numcolwise(median), na.rm=TRUE)

в соответствии с system.time (), этоЗапуск занимает около этого времени:

   user  system elapsed 
   5.16    0.00    5.17

Этот вызов является частью веб-приложения, поэтому время выполнения довольно важно.Есть ли способ ускорить этот вызов?

Ответы [ 6 ]

9 голосов
/ 19 октября 2010

Просто использовать aggregate немного быстрее ...

> groupVars <- c("groupname","starttime","fPhase","fCycle")
> dataVars <- colnames(data)[ !(colnames(data) %in% c("location",groupVars)) ]
> 
> system.time(ag.median <- aggregate(data[,dataVars], data[,groupVars], median))
   user  system elapsed 
   1.89    0.00    1.89 
> system.time(df.median <- ddply(data, .(groupname,starttime,fPhase,fCycle), numcolwise(median), na.rm=TRUE))
   user  system elapsed 
   5.06    0.00    5.06 
> 
> ag.median <- ag.median[ do.call(order, ag.median[,groupVars]), colnames(df.median)]
> rownames(ag.median) <- 1:NROW(ag.median)
> 
> identical(ag.median, df.median)
[1] TRUE
7 голосов
/ 19 октября 2010

Просто суммируем некоторые моменты из комментариев:

  1. Перед тем, как приступить к оптимизации, вы должны иметь некоторое представление о «приемлемой» производительности.В зависимости от требуемой производительности, вы можете более конкретно рассказать о том, как улучшить код.Например, при некотором пороге вам нужно будет прекратить использовать R и перейти на скомпилированный язык.
  2. Как только вы получите ожидаемое время выполнения, вы можете профилировать существующий код, чтобы найти потенциальные узкие места.R имеет несколько механизмов для этого, в том числе Rprof (есть примеры для стекопотока, если вы ищете [r] + rprof ).
  3. plyr предназначен в основном для простоты использования, не для производительности (хотя в последней версии были некоторые хорошие улучшения производительности).Некоторые из базовых функций быстрее, потому что они имеют меньше накладных расходов.@JDLong указал на замечательную ветку , которая охватывает некоторые из этих проблем, включая некоторые специализированные приемы от Хэдли.
4 голосов
/ 20 октября 2010

Порядок данных имеет значение при расчете медиан: если данные расположены в порядке от наименьшего к наибольшему, то вычисление выполняется немного быстрее.

x <- 1:1e6
y <- sample(x)
system.time(for(i in 1:1e2) median(x))
   user  system elapsed 
   3.47    0.33    3.80

system.time(for(i in 1:1e2) median(y))
   user  system elapsed 
   5.03    0.26    5.29

Для новых наборов данных сортируйте данные по соответствующему столбцу при импорте. Для существующих наборов данных вы можете отсортировать их как пакетное задание (вне веб-приложения).

3 голосов
/ 16 апреля 2014

Работа с этими данными значительно быстрее с dplyr:

library(dplyr)

system.time({
  data %>% 
    group_by(groupname, starttime, fPhase, fCycle) %>%
    summarise_each(funs(median(., na.rm = TRUE)), inadist:larct)
})
#>    user  system elapsed 
#>   0.391   0.004   0.395

(вам понадобится dplyr 0.2, чтобы получить %>% и summarise_each)

Это выгодно для plyr:

library(plyr)
system.time({
  df.median <- ddply(data, .(groupname, starttime, fPhase, fCycle), 
    numcolwise(median), na.rm = TRUE)
})
#>    user  system elapsed 
#>   0.991   0.004   0.996

И aggregate() (код от @ joshua-ulrich)

groupVars <- c("groupname", "starttime", "fPhase", "fCycle")
dataVars <- colnames(data)[ !(colnames(data) %in% c("location", groupVars))]
system.time({
  ag.median <- aggregate(data[,dataVars], data[,groupVars], median)
})
#>    user  system elapsed 
#>   0.532   0.005   0.537
3 голосов
/ 20 октября 2010

Добавить к решению Джошуа. Если вы решите использовать среднее вместо среднего, вы можете ускорить вычисления еще в 4 раза:

> system.time(ag.median <- aggregate(data[,dataVars], data[,groupVars], median))
   user  system elapsed 
   3.472   0.020   3.615 
> system.time(ag.mean <- aggregate(data[,dataVars], data[,groupVars], mean))
   user  system elapsed 
   0.936   0.008   1.006 
2 голосов
/ 20 октября 2010

Ну, я просто сделал несколько простых преобразований для большого фрейма данных (набор данных бейсбола в пакете plyr), используя стандартные библиотечные функции (например, «таблица», «tapply», «агрегат» и т. Д.) Ианалогичная функция plyr - в каждом случае я обнаружил, что plyr значительно медленнее.Например,

> system.time(table(BB$year))
    user  system elapsed 
   0.007   0.002   0.009 

> system.time(ddply(BB, .(year), 'nrow'))
    user  system elapsed 
   0.183   0.005   0.189 

Во-вторых, и я не выяснил, может ли это улучшить производительность в вашем случае, но для фреймов данных того размера, с которым вы работаете сейчас и больше, я используюбиблиотека data.table , доступная в CRAN.Создать объекты data.table просто, а также преобразовать существующие data.frames в data.tables - просто вызовите data.table на data.frame, который вы хотите преобразовать:

dt1 = data.table(my_dataframe)
...