семантика ссылок на data.table: внутренняя часть итерации по столбцам и группам строк - PullRequest
0 голосов
/ 06 сентября 2018

Этот вопрос похож на

семантика ссылки на data.table: использование памяти для итерации по всем столбцам

, но обсуждается немного другая настройка, поэтому я решил оставить их отдельно.

При замене всех столбцов в таблице data.table путем применения функции my_fun к каждому столбцу в сочетании с группировкой строк с использованием аргумента by, что примерно происходит в параметре типа

library(data.table)
dt <- data.table(a = 1L:10L, b = 11L:20L, c = rep(LETTERS[1:2], each = 5))
my_fun <- function(x) x + 1L

dt[, c("a", "b") := lapply(.SD, my_fun), by = "c", .SDcols = c("a", "b")]

(1) Проблема сначала разбивается на группы, и для каждой группы оценивается lapply(.SD, my_fun). Прежде чем перейти к следующей группе, результаты записываются в dt. Согласно указанному вопросу , объем памяти в этом случае составляет приблизительно max (n_rows на группу) x (n_cols in .SD) x sizeof (data_type)

(2) Проблема разбита на группы и для каждой группы оценивается lapply(.SD, my_fun). По завершении итерации по всем группам результат записывается в соответствующие столбцы в dt. В этом случае накладные расходы памяти составляют приблизительно (n_rows в dt) x (n_cols in .SD) x sizeof (data_type)

(3) Проблема решается по принципу столбец за столбцом, и для каждого столбца столбец разбивается, и для каждого подмножества текущего столбца вызывается my_fun. После завершения с полным столбцом результаты записываются в dt. Это может привести к накладным расходам (примерно n_rows in dt) x sizeof (data_type).

(4) Что-то еще?

Из ответа в вопрос, упомянутый выше , (3), может быть включен в будущем посредством оптимизации, аналогичной описанной в ?datatable.optimize в разделе уровня 1, но в настоящее время (v1.11.4 ) недоступен.

Причина, по которой я задаю этот вопрос, заключается в том, что, особенно если в настройке (2), а в некоторых случаях, возможно, также в настройке (1), имеет смысл каким-то образом принудительно применять подход столбец за столбцом.

К сожалению, в дальнейшем не работает, так как set() не поддерживает группировку.

for (col in c("a", "b")) set(dt, j = col, value = my_fun(dt[[col]]), by = "c")

Кроме того, что-то вроде

lapply(c("a", "b"), function(col) dt[, (col) := my_fun(dt[[col]]), by = "c"])

не работает, так как вложенное подмножество dt[[col]] не разбивается. Есть ли другой способ добиться того, что я пытаюсь сделать, используя data.table?

1 Ответ

0 голосов
/ 12 сентября 2018

Теперь я думаю, что (1) наиболее точно описывает, как столбцы обновляются в сгруппированной форме. Я пришел к такому выводу из следующего наблюдения: если при обновлении столбцов по ссылке используется аргумент by, новый тип данных должен соответствовать старому. Это не тот случай, когда обновляется весь столбец по ссылке.

Чтобы принудительно использовать подход «столбец за столбцом», я думаю, что можно было бы выполнить поднабор групп строк вручную и иметь вложенный двойной цикл: один перебирает столбцы и один перебирает группы строк. Чтобы определить порядок групп, используемый data.table, лучше всего придумать что-то вроде

grouping <- split(
  seq_len(nrow(tbl)),
  tbl[, list(GroupIndex = rep(.GRP, .N)), by = group_by][["GroupIndex"]]
)
...