2010-10-19 3 views
8

У меня есть data.frame (link to file) с 18 колоннами и 11520 строк, которые я трансформируют так:как ускорить этот код R

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 

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

+2

Можете ли вы кешировать результаты? – Shane

+0

'ddply()' в первую очередь * удобный *. Если вам нужно что-то быстро, вам может потребоваться повторить логику. –

+0

@Shane: В настоящее время доступны 3 * 400 возможных наборов данных (и ежедневно), которые пользователь может запросить. Вряд ли один пользователь попадет в тот же набор данных, что и другой. Таким образом, кэширование будет полезно только в сеансе. Поскольку вывод webapp - это, по сути, консервированный отчет, я не думаю, что пользователь обычно запрашивал его более одного раза. Не могли бы вы реализовать кэширование ситуации, описанной мной? Я никогда не делал этого раньше, так что я немного потерял. – dnagirl

ответ

9

Только с помощью 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 
+0

'aggregate' исправляет эту проблему удобно. – dnagirl

7

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

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

Спасибо за резюме. И благодаря всем, кто внес такую ​​полезную информацию. У меня есть много чтения! – dnagirl

2

Ну я просто сделал несколько простых преобразований на большой кадр данных (данные бейсбол набор в пакете plyr) с использованием стандарта библиотечные функции (например, «таблица», «tapply», «aggregate» и т. д.) и аналогичная функция 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) 
3

Чтобы добавить Джошуа решение. Если вы решили использовать в виду вместо медианы, вы можете ускорить вычисления еще 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 
+1

очень интересно! Я буду помнить об этом. К сожалению, эти данные должны сравнивать медианы. – dnagirl

4

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

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 

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

2

Работа с этими данными значительно быстрее с 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 
Смежные вопросы