Использование rle() в соответствии с другой группой переменных R

Это действительно продолжение другого вопроса, который я разместил на здесь несколько недель назад и получил ответ.

В моем первоначальном вопросе я хотел найти количество дней между событиями стока в наборе данных. Как показано в примере данных ниже:

Date        Runoff   No_Days
01/01/1980  0        4
02/01/1980  0        3
03/01/1980  0        2
04/01/1980  0        1
05/01/1980  4.5      0
06/01/1980  2        0
07/01/1980  0        6
08/01/1980  0        5
09/01/1980  0        4
10/01/1980  0        3
11/01/1980  0        2
12/01/1980  0        1  
13/01/1980  1.2      0
14/01/1980  0        4      
15/01/1980  0        3
16/01/1980  0        2
17/01/1980  0        1
18/01/1980  0.8      0

Мне удалось добраться до этого, используя следующий код:

DF$No_Days <-unlist(lapply(rle(DF$Runoff>0.05)$lengths,function(x) rev(seq(x:1))))
DF$No_Days <-ifelse(DF$Runoff>0.05,0,DF$No_Days)

Все это хорошо работает для одного набора данных, то есть одного временного ряда для одной группы. Однако сейчас я борюсь с тем, как манипулировать приведенным выше кодом, чтобы делать одни и те же действия для ряда наборов данных временных рядов в одной и той же таблице данных в соответствии с группирующей переменной (Soil), чтобы получить, например:

Date        Runoff   No_Days  Soil
01/01/1980  0        4        Clay
02/01/1980  0        3        Clay    
03/01/1980  0        2        Clay    
04/01/1980  0        1        Clay    
05/01/1980  4.5      0        Clay
06/01/1980  2        0        Clay
07/01/1980  0        6        Clay
08/01/1980  0        5        Clay
09/01/1980  0        4        Clay
10/01/1980  0        3        Clay
11/01/1980  0        2        Clay
12/01/1980  0        1        Clay
13/01/1980  1.2      0        Clay
14/01/1980  0        4        Clay  
15/01/1980  0        3        Clay
16/01/1980  0        2        Clay
17/01/1980  0        1        Clay
18/01/1980  0.8      0        Clay
01/01/1980  0        5        Sand
02/01/1980  0        4        Sand
03/01/1980  0        3        Sand
04/01/1980  0        2        Sand
05/01/1980  0        1        Sand
06/01/1980  2        0        Sand
07/01/1980  0        11       Sand
08/01/1980  0        10       Sand
09/01/1980  0        9        Sand
10/01/1980  0        8        Sand
11/01/1980  0        7        Sand
12/01/1980  0        6        Sand
13/01/1980  0        5        Sand
14/01/1980  0        4        Sand    
15/01/1980  0        3        Sand
16/01/1980  0        2        Sand
17/01/1980  0        1        Sand
18/01/1980  0.8      0        Sand

В настоящее время, если я запускаю код, он не различает разные типы почвы и, следовательно, не «перезапускает» последовательность после каждого временного ряда.

Из чтения кажется, что мне может понадобиться заменить lapply() в исходном коде на by(). Я думаю, что это будет работать, пока rle() в первую очередь сгруппировано в соответствии с почвой, но я не могу найти никакого способа сделать это.

Поэтому любая помощь приветствуется, пожалуйста!


person Catchment_Jack    schedule 13.05.2014    source источник


Ответы (2)


Если вы используете пакет data.table, это очень просто:

install.packages("data.table")
library(data.table)
DF = data.table(DF)

DF[,No_Days:=unlist(lapply(rle(Runoff>0.05)$lengths,function(x) rev(seq(x:1)))),by=Soil]
DF[Runoff <= 0.05, No_Days:=0]
person Señor O    schedule 13.05.2014
comment
Это работает удовольствие. Я не знаю, как я этого не заметил, поскольку я работал с data.table для других вещей. Спасибо! - person Catchment_Jack; 13.05.2014

Если вы заинтересованы в том, чтобы сделать это и в базе R, вы можете использовать ave, чтобы получить тот же результат. Для удобства я определю

countdown <- function(events) {
    unlist(with(rle(events), 
        Map(function(v,l) {
            if(v) rep.int(0,l)
            else l:1}
        , values, lengths)
    ))
}

Тогда вы найдете ответ без типа почвы с

DF <- transform(DF, No_Days=countdown(Runoff>0.05))

а затем сделать группировку по типу почвы вы могли бы

DF <- transform(DF, No_Days=ave(Runoff>0.05, Soil, FUN=countdown))
person MrFlick    schedule 13.05.2014