#r #performance #optimization #data.table
#r #Производительность #оптимизация #данные.таблица
Вопрос:
Какой самый быстрый способ суммирования по группам R
? Я использовал data.table
для оптимизации этого шага столько, сколько мог, но это по-прежнему основное узкое место в моем коде, поскольку его приходится запускать тысячи раз.
library(data.table)
data <- matrix(rnorm(5e6 * 16), ncol = 16)
colnames(data) <- paste0("mark", 1:16)
group <- gl(10, 5e5, labels = paste0("sample", 1:10))
DT <- data.table(group, data) # 1/10 actual row #
out <- DT[, lapply(.SD, function(x) {mean(x^3)}), by = group]
Комментарии:
1. Трудно превзойти
data.table
— на R или любом другом языке. Эти тесты из H2O.AI покажите, чтоdata.table
выигрывает или находится ближе к вершине в зависимости от размера данных / количества групп для сгруппированных сумм по сравнению сdplyr
несколькими другими языковыми альтернативами, известными своей производительностью. Можете ли вы сначала установить ключ для data.table? Особенно, если вы выполняете другие сгруппированные операции, которые должны немного ускорить процесс.2. Нет разницы с
DT[, lapply(.SD, function(x) {mean(x^3)}), by = key(DT)]
. Однако приятно знать, что кто-то еще пришел к такому же выводу3. Если вы действительно пытаетесь выжать из этого некоторую скорость, я просто
x*x*x
сравнилx^3
с 1000 числами, и первый работал примерно в 5 раз быстрее. Если вы суммируете менее 1000 чисел за раз, это никогда не будет медленнее, чемx^3
, и начинает показывать даже незначительные улучшения скорости всего с 20 числами.4. Используйте verbose, чтобы убедиться, что оптимизация GForce запущена. Я не уверен, что он не будет отключен x ^ 3 внутри. Затем вычислите это как новый столбец, а затем вызовите среднее значение для материализованного столбца.
Ответ №1:
Как упоминает r2evans, mean
функция не является самой медленной частью. Это функция мощности x^3
для всех данных.
Мы можем увидеть это, если разделим вызовы и измерим время.
system.time(x <- lapply(seq_along(DT)[-1], function(i) DT[[i]]^3)) # 4.7
system.time(setDT(x)) # 0
system.time(x[, lapply(.SD, mean), by = DT$group]) # 0.41
В этом конкретном случае я могу предложить:
v2 <- function() {
x <- lapply(seq_along(DT)[-1], function(i) DT[[i]]*DT[[i]]*DT[[i]])
setDT(x)
x[, lapply(.SD, mean), by = DT$group]
}
время:
v1 <- function() {
DT[, lapply(.SD, function(x) {mean(x^3)}), by = group]
}
system.time(v1()) # 4.92
system.time(v2()) # 0.84
Также,
x[, lapply(.SD, mean), by = DT$group]
x[, lapply(.SD, function(i) mean(i)), by = DT$group]
отличаются. Первый вызов выполняется data.tables
gmean
, а второй — нет. В зависимости от размера ваших данных один может быть быстрее, чем другой подход.
Комментарии:
1. Вы правы,
v2()
примерно в 2 раза быстрее, используя мой фактический набор данных. Интересно, что результаты v1 и v2 отличаются примерно на 2.740863e-16. Я предполагаю, что это связано сgmean