Работать с определенным количеством строк в data.table

Я работаю с таблицей данных, которая имеет группы данных и для каждой позиции (от -1000 до +1000) и подсчет для каждой позиции. Небольшой пример выглядит так:

dt.ex <- data.table(newID=rep(c("A","B"), each = 6), pos=rep(c(-2:3), 2), count= sample(c(1:100), 12))
    newID pos count
 1:     A  -2    29
 2:     A  -1    32
 3:     A   0    33
 4:     A   1    45
 5:     A   2    51
 6:     A   3    26
 7:     B  -2    22
 8:     B  -1    79
 9:     B   0     2
10:     B   1    48
11:     B   2    87
12:     B   3    38

Что я хочу сделать, это рассчитать среднее (или сумму) между каждыми n строками для каждой группы newID. То есть разбить на n строк и агрегировать результаты. Это будет вывод при условии n=3 и суммировании:

newID pos count
    A  -2    94
    A   1   122
    B  -2   103 
    B   1   173

И я, честно говоря, понятия не имею, с чего начать, не прибегая к каким-либо циклам - не рекомендуется для таблицы 67094000 x 3. Если бы я хотел рассчитывать только по новым идентификаторам, что-то вроде этого помогло бы, но я еще не нашел решение, которое было бы близко к ответу на мой вопрос. Решения Plyr также приветствуются, хотя я чувствую, что это может быть слишком медленным для этого.

2 ответа

Решение

Альтернативный способ (без использования .SD) было бы:

dt.ex[, seq := (seq_len(.N)-1) %/% 3, by=newID][, 
      list(pos = mean(pos), count=sum(count)), list(newID, seq)]

Сравнительный анализ (относительно) больших данных:

set.seed(45)
get_grps <- function() paste(sample(letters, 5, TRUE), collapse="")
grps <- unique(replicate(1e4, get_grps()))

dt.in <- data.table(newID = sample(grps, 6e6, TRUE), 
                 pos = sample(-1000:1000, 6e6, TRUE), 
                 count = runif(6e6))
setkey(dt.in, newID)

require(microbenchmark)
eddi <- function(dt) {
   dt[, .SD[, list(pos = mean(pos), count = sum(count)), 
          by = seq(0, .N-1) %/% 3], by = newID]
}

arun <- function(dt) {
    dt[, seq := (seq_len(.N)-1) %/% 3, by=newID][, 
      list(pos = mean(pos), count=sum(count)), list(newID, seq)]
}

microbenchmark(o1 <- eddi(copy(dt.in)), o2 <- arun(copy(dt.in)), times=2)


Unit: seconds
                    expr      min       lq   median       uq      max neval
 o1 <- eddi(copy(dt.in)) 25.23282 25.23282 26.16009 27.08736 27.08736     2
 o2 <- arun(copy(dt.in)) 13.59597 13.59597 14.41190 15.22783 15.22783     2

Попробуй это:

dt.ex[, .SD[, list(pos = mean(pos), count = sum(count)),
              by = seq(0, .N-1) %/% 3],
        by = newID]

Обратите внимание, что родитель data.table"s .N используется во вложенных by, так как .N существует только в j-expression,

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