Включая все перестановки при использовании data.table [, by =...]

У меня есть большой data.table, который я сжимаю до уровня месяца, используя ,by.

Есть 5 по vars, С# уровней: c(4,3,106,3,1380). 106 месяцев, 1380 - это географическая единица. Как оказалось, есть некоторые 0, в том, что некоторые ячейки не имеют значений. by опускает их, но я бы хотел, чтобы они сохраняли их.

Воспроизводимый пример:

require(data.table)

set.seed(1)
n <- 1000
s <- function(n,l=5) sample(letters[seq(l)],n,replace=TRUE)
dat <- data.table( x=runif(n), g1=s(n), g2=s(n), g3=s(n,25) )
datCollapsed <- dat[ , list(nv=.N), by=list(g1,g2,g3) ]
datCollapsed[ , prod(dim(table(g1,g2,g3))) ] # how many there should be: 5*5*25=625
nrow(datCollapsed) # how many there are

Есть ли эффективный способ заполнить эти пропущенные значения с помощью 0, так что все перестановки из vars находятся в результирующем сложенном data.table?

Ответ 1

Я бы тоже пошел с перекрестным соединением, но использовал бы его в i -слоте исходного вызова [.data.table:

keycols <- c("g1", "g2", "g3")                              ## Grouping columns
setkeyv(dat, keycols)                                       ## Set dat key
ii <- do.call(CJ, sapply(dat[,keycols,with=FALSE], unique)) ## CJ() to form index
datCollapsed <- dat[ii, list(nv=.N)]                        ## Aggregate

## Check that it worked
nrow(datCollapsed)
# [1] 625
table(datCollapsed$nv)
#   0   1   2   3   4   5   6 
# 135 191 162  82  39  13   3 

Этот подход называется "by-without-by" и, как описано в ?data.table, он так же эффективен и быстр, как передача инструкций группировки через аргумент by:

Дополнительно: Агрегация для подмножества известных групп особенно эффективны при передаче этих групп в "i". когда "i" - это "data.table", "DT [i, j]" оценивает "j" для каждой строки из 'i'. Мы называем это без или группированием по i. Следовательно, self join 'DT [data.table(unique (colA)), j]' является идентичный 'DT [, j, by = colA]'.

Ответ 2

Сделайте декартовое объединение уникальных значений и используйте это, чтобы присоединиться к вашим результатам

dat.keys <- dat[,CJ(g1=unique(g1), g2=unique(g2), g3=unique(g3))]
setkey(datCollapsed, g1, g2, g3)
nrow(datCollapsed[dat.keys])  # effectively a left join of datCollapsed onto dat.keys
# [1] 625

Обратите внимание, что отсутствующие значения являются NA прямо сейчас, но вы можете легко изменить это на 0s, если хотите.