R Как условно суммировать двоичные данные временных рядов для больших фреймов данных

Я слишком долго пытался решить эту проблему. У меня есть бинарные данные о вспышках насекомых в годовом формате временных рядов за 300+ лет (строки) и 70+ деревьев (столбцы).

Я хотел бы условно заполнить таблицу данных/матрицу/данные тех же размеров кумулятивными суммами и сбросить ее до 0 в конце каждого периода вспышки. Я нашел множество похожих вопросов/ответов, которые я просто не могу перевести на свою проблему.

У меня будет фрагмент кадра данных, например, который выглядит так:

      t1 t2 t3 t4 t5
2000   1  0  0  1  0
2001   1  0  0  0  1
2002   1  1  0  0  1
2003   0  1  0  1  1
2004   1  1  1  1  1

И я хочу создать новый df, который выглядит так:

      t1 t2 t3 t4 t5
2000   1  0  0  1  0
2001   2  0  0  0  1
2002   3  1  0  0  2
2003   0  2  0  1  3
2004   1  3  1  2  4

Я чувствовал, что приблизился к обоим пакетам data.table и rle, хотя я также ходил по множеству кругов (почти уверен, что однажды сделал это для одного столбца, но теперь не могу вспомнить, что я сделал, или почему я не мог заставить его работать в цикле для всех столбцов...).

Я всегда добивался, чтобы следующие методы работали в некоторой степени, обычно только с одним столбцом или добавляя один 1 df поверх сдвинутого df, чтобы один столбец мог выглядеть как 0 1 2 2 1 0 вместо 0 1 2 3 4 0 . Некоторые попытки, если это поможет, были вариациями кода, выглядящего так:

setDT(dt)[, new := t1 + shift(t1, fill = 0)]


apply(
  rle( matrix)$lengths
  , 2, seq)
rle( matrix[,1])$lengths 


for( i in 1:dim(dt)[1]) {
  for( j in 1:dim(dt)[2]) {
    cols <- names(dt) # tried in place of .SD with negative results
    if( dt[i,j] == 1) {
      dt[, new := .SD + shift(.SD, 1L, fill = 0, type = "lag", give.names = TRUE)]
    } else { dt }
  }
}

Некоторые из основных источников SO, которые я использовал, включают следующие страницы: data.table, dplyr, rle

Дайте мне знать, если я пропущу какую-либо важную информацию (я новичок!). И большое спасибо за любую помощь!


person alaskayo    schedule 15.09.2016    source источник


Ответы (2)


Мы можем использовать rle с sequence из base R

df2 <- df1 #create a copy of df1
#loop through the columns of 'df2', apply the `rle`, get the 'sequence'
#of 'lengths' and multiply with the column values.
df2[] <- lapply(df2, function(x) sequence(rle(x)$lengths)*x)
df2
#     t1 t2 t3 t4 t5    
#2000  1  0  0  1  0
#2001  2  0  0  0  1
#2002  3  1  0  0  2
#2003  0  2  0  1  3
#2004  1  3  1  2  4
person akrun    schedule 16.09.2016
comment
Это работает быстро и легко. Спасибо; неделю рвать на себе волосы, и это так просто! Я никогда не осознавал, что могу оставить скобки df2 полностью пустыми от ссылок на строки/столбцы. Я также никогда раньше не играл с функцией (x), плавающей внутри функции, определенной без {}. Это действительно ново/непонятно для меня. - person alaskayo; 16.09.2016

Вы можете использовать data.table в сочетании с функцией ave для вычисления общей суммы каждого столбца, сгруппированного по rleid самого столбца:

library(data.table)
setDT(dt)[, names(dt) := lapply(.SD, function(col) ave(col, rleid(col), FUN = cumsum))][]

#   t1 t2 t3 t4 t5
#1:  1  0  0  1  0
#2:  2  0  0  0  1
#3:  3  1  0  0  2
#4:  0  2  0  1  3
#5:  1  3  1  2  4
person Psidom    schedule 15.09.2016