我有一个数据框,我在其上计算特定列的运行长度编码。列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代码。我觉得好像应该有另一种方法来做这个没有循环。
答案 0 :(得分:12)
这可以分解为两步问题。首先,如果我们根据rle
创建索引列,那么我们可以使用它来分组并运行cumsum
。然后可以通过任何数量的聚合技术来执行group by。我将展示两个选项,一个使用data.table
,另一个使用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))
答案 1 :(得分:4)
Spacedman&amp; Chase提出了一个关键点,即分组变量简化了所有事情(Chase提出了两种很好的方法从那里开始)。
我将提出另一种方法来形成该分组变量。它不使用rle
,至少对我来说,感觉更直观。基本上,在diff()
检测到值更改的每个点,将形成您的分组变量的cumsum
增加1:
df$group <- c(0, cumsum(!(diff(df$dir)==0)))
# Or, equivalently
df$group <- c(0, cumsum(as.logical(diff(df$dir))))
答案 2 :(得分: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)