根据其他变量组R使用rle()

时间:2014-05-13 14:25:57

标签: r time-series tapply

这是我几周前在这里发布的another question的后续内容,并得到了答案。

在我最初的问题中,我想找到数据集中径流事件之间的天数。如下面的数据示例所示:

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)

这一切都适用于单个数据集,即一个组的一个时间序列。然而,我现在正在努力的是如何操纵上面的代码来为同一data.table中的多个时间序列数据集做同样的事情。根据分组变量(土壤)得到例如:

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()首先根据土壤分组,但我无法找到任何方法,这将有效。

所以有任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:3)

如果您使用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]

答案 1 :(得分:1)

如果您有兴趣在基础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))