Р: самый быстрый способ подвести итоги по группам?

Какой самый быстрый способ подвести итоги по группам в 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]

Трудно превзойти data.table - на R или любом другом языке. Эти тесты от H2O.AI показывают, что data.table побеждает или находится почти на первом месте в зависимости от размера данных / количества групп для сгруппированных сумм по сравнению с dplyr или несколькими другими языковыми альтернативами, известными своей производительностью. Можете ли вы сначала установить ключ в data.table? Особенно, если вы выполняете другие сгруппированные операции, которые должны несколько ускорить процесс.

Gregor Thomas 15.12.2020 15:56

Никакой разницы с DT[, lapply(.SD, function(x) {mean(x^3)}), by = key(DT)]. Тем не менее, хорошо знать, что кто-то еще пришел к такому же выводу

Jeff Bezos 15.12.2020 16:17

Если вы действительно пытаетесь выжать из этого немного скорости, я только что сравнил x*x*x и x^3 с 1000 чисел, и первый работал примерно в 5 раз быстрее. Если вы суммируете менее 1000 чисел за раз, он никогда не будет медленнее, чем x^3, и начинает показывать даже небольшое улучшение скорости всего лишь с 20+ числами.

r2evans 15.12.2020 16:36

Используйте подробное описание, чтобы убедиться, что оптимизация GForce запущена. Я не уверен, что он не будет отключен x^3 внутри. Затем вычислите это как новый столбец, а затем вызовите среднее значение для материализованного столбца.

jangorecki 16.12.2020 10:57
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
802
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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.tablesgmean, а второй — нет. В зависимости от размера ваших данных один подход может быть быстрее, чем другой.

Вы правы, v2() работает примерно в 2 раза быстрее, используя мой реальный набор данных. Интересно, что результаты v1 и v2 отличаются примерно на 2,740863e-16. Я предполагаю, что это связано с gmean

Jeff Bezos 21.12.2020 03:52

Другие вопросы по теме