4

我有一个数据框,我在其上计算特定列的运行长度编码。列的值为dir-1、0 或 1。

dir.rle <- rle(df$dir)

然后,我获取运行长度并计算数据框中另一列的分段累积总和。我正在使用 for 循环,但我觉得应该有一种方法可以更智能地做到这一点。

ndx <- 1
for(i in 1:length(dir.rle$lengths)) {
    l <- dir.rle$lengths[i] - 1
    s <- ndx
    e <- ndx+l
    tmp[s:e,]$cumval <- cumsum(df[s:e,]$val)
    ndx <- e + 1
}

的运行长度dir定义每次运行的开始s和结束e。上面的代码有效,但感觉不像是惯用的 R 代码。我觉得好像应该有另一种没有循环的方法。

4

3 回答 3

12

这可以分解为两步问题。首先,如果我们创建一个基于 的索引列rle,那么我们可以使用它来分组并运行cumsum. 然后可以通过任意数量的聚合技术来执行分组。我将展示两个选项,一个 using data.table,另一个 using plyr

library(data.table)
library(plyr)
#data.table is the same thing as a data.frame for most purposes
#Fake data
dat <- data.table(dir = sample(-1:1, 20, TRUE), value = rnorm(20))
dir.rle <- rle(dat$dir)
#Compute an indexing column to group by
dat <- transform(dat, indexer = rep(1:length(dir.rle$lengths), dir.rle$lengths))


#What does the indexer column look like?
> head(dat)
     dir      value indexer
[1,]   1  0.5045807       1
[2,]   0  0.2660617       2
[3,]   1  1.0369641       3
[4,]   1 -0.4514342       3
[5,]  -1 -0.3968631       4
[6,]  -1 -2.1517093       4


#data.table approach
dat[, cumsum(value), by = indexer]

#plyr approach
ddply(dat, "indexer", summarize, V1 = cumsum(value))
于 2011-11-17T17:16:01.583 回答
4

Spacedman 和 Chase 都强调了分组变量可以简化一切的关键点(并且 Chase 提出了两种从那里开始的好方法)。

我将提出另一种方法来形成该分组变量。它不使用rle,至少对我来说,感觉更直观。基本上,在diff()检测到值变化的每个点cumsum,将形成您的分组变量的值都会增加一:

df$group <- c(0, cumsum(!(diff(df$dir)==0)))

# Or, equivalently
df$group <- c(0, cumsum(as.logical(diff(df$dir))))
于 2011-11-17T17:33:31.513 回答
2

将“组”列添加到数据框中。就像是:

df=data.frame(z=rnorm(100)) # dummy data
df$dir = sign(df$z) # dummy +/- 1
rl = rle(df$dir)
df$group = rep(1:length(rl$lengths),times=rl$lengths)

然后使用 tapply 在组内求和:

tapply(df$z,df$group,sum)
于 2011-11-17T17:17:06.573 回答