Можно ли работать с агрегированными значениями dcast?

dcast.data.table имеет функцию агрегирования по нескольким value.var. Можно ли каким-то образом ссылаться на создаваемые агрегированные значения, а затем выполнять операцию в рамках развлечения?

Это создает 4 переменные

DT = data.table(x=sample(5,20,TRUE), y=sample(2,20,TRUE),
                z=sample(letters[1:2], 20,TRUE), d1 = runif (20), d2=1L)

> head(DT)
   x y z        d1 d2
1: 3 2 a 0.6166590  1
2: 3 1 a 0.1891611  1
3: 5 2 a 0.3061658  1
4: 3 1 a 0.7233832  1
5: 2 1 b 0.6799675  1
6: 2 1 b 0.5144392  1

dcast(DT, x + y ~ z, fun=sum, value.var=c("d1", "d2"))

   x y      d1_a      d1_b d2_a d2_b
1: 1 1 1.0400277 0.3835004    2    1
2: 2 1 0.7032111 1.3713884    1    2
3: 3 1 0.9759893 2.0853103    1    3
4: 3 2 0.5210792 0.0000000    1    0
5: 4 1 1.0971931 0.4417819    2    1
6: 4 2 0.5009533 0.0000000    1    0
7: 5 1 0.9372943 0.0000000    4    0
8: 5 2 0.7671728 0.0000000    1    0

И операции над агрегированными значениями могут быть выполнены на втором этапе.

dcast(DT, x + y ~ z, fun=sum, value.var=c("d1", "d2"))[,.(div1 = d1_a/d2_a
                                                          ,div2 = d1_b/d2_b)]

        div1      div2
1: 0.5200139 0.3835004
2: 0.7032111 0.6856942
3: 0.9759893 0.6951034
4: 0.5210792       NaN
5: 0.5485965 0.4417819
6: 0.5009533       NaN
7: 0.2343236       NaN
8: 0.7671728       NaN

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это немного запутанно, но для этой проблемы я думаю, вы могли бы сделать следующее:

zs <- unique(DT$z)

sum_div <- function(dt) {
  ans <- dt[, .(div = sum(d1) / sum(d2)), by = .(z)]
  split(ans$div, factor(ans$z, levels = zs), drop = FALSE)
}

DT[, sum_div(.SD), by = .(x, y), .SDcols = c("z", "d1", "d2")]

Что происходит, так это то, что .SD имеет 3 столбца, указанные в .SDcols, но с разными подмножествами для возможных комбинаций значений x и y. Затем sum_div выполняет желаемую операцию только с этим подмножеством, и splits возвращает список, так что каждое возможное значение z получает свой собственный столбец в конечном data.table.

Важно сделать factor(ans$z, levels = zs), чтобы каждый раз получать одинаковое количество элементов списка (data.table ожидает этого); указав, сколько levels мы ожидаем, split вернет пустой вектор, если для level нет значений, но он обязательно вернет что-то для каждого.

Обратите внимание, что вы можете добиться того же с помощью:

dcast(DT[, .(div = sum(d1) / sum(d2)), by = .(x, y, z)], x + y ~ z, value.var = "div")

Я не уверен, что вы получите значительную производительность, делая все за один шаг.

Обновлено: вы, вероятно, нет:

library(data.table)
library(microbenchmark)

n <- 2e5
DT = data.table(x = sample(5L, n, TRUE),
                y = sample(3L, n, TRUE),
                z = sample(letters[1:2], n, TRUE),
                d1 = runif (n),
                d2 = 1L)

zs <- sort(unique(DT$z))

sum_div <- function(dt) {
  ans <- dt[, .(div = sum(d1) / sum(d2)), by = .(z)]
  split(ans$div, factor(ans$z, levels = zs), drop = FALSE)
}

microbenchmark(
  one = DT[, sum_div(.SD), keyby = .(x, y), .SDcols = c("z", "d1", "d2")],
  two = dcast(DT[, .(div = sum(d1) / sum(d2)), by = .(x, y, z)], x + y ~ z, value.var = "div"),
  times = 10L
)
Unit: milliseconds
 expr      min       lq     mean   median       uq      max neval
  one 24.37323 25.74273 26.72413 25.99279 26.62943 34.40309    10
  two 11.31050 11.91650 12.66345 12.51094 13.01364 15.35549    10

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