R分组/聚合,其中条件涉及表中的其他行,而不仅仅是当前行

R分组/聚合,其中条件涉及表中的其他行,而不仅仅是当前行,r,R,使用R,在跨多行的条件下聚合行的最佳方式是什么。 例如,将z=0的任何行聚合n次或更多次 在下面的示例表上运行,n=3 样本表x: x y z 0 0 6 5 5 0 40 2 0 4 0 0 10 0 1 0 0 2 11 7 0 0 4 0 0 0 0 0 0 0 0 0 2 18 0 4 结果表: x y z 0 0 6 49 7 0 <- Above two ro

使用R,在跨多行的条件下聚合行的最佳方式是什么。 例如,将z=0的任何行聚合n次或更多次

在下面的示例表上运行,n=3

样本表x:

x   y   z
0   0   6
5   5   0
40  2   0
4   0   0
10  0   1
0   0   2
11  7   0
0   4   0
0   0   0
0   0   0
0   0   2
18  0   4
结果表:

x   y   z
0   0   6
49  7   0 <- Above two rows got aggregated
10  0   1
0   0   2
11  11  0 <- Above three rows got aggregated
0   0   2
18  0   4
xyz
0   0   6

49 7 0这是我用来生成结果的代码。如果你有任何问题,马上回答

mmf <- read.table(textConnection("x   y   z # read in your example data
0   0   6
5   5   0
40  2   0
4   0   0
10  0   1
0   0   2
11  7   0
0   4   0
0   0   0
0   0   0
0   0   2
18  0   4"), header = TRUE)

# see where there are zeros in the y column
mmf.rle <- rle(mmf$z) 
mmf.rle <- data.frame(lengths = mmf.rle$lengths, values = mmf.rle$values)

merge.rows <- 3
# select rows that have more or equal to three zeros
mmf.zero <- which(mmf.rle$values == 0 & mmf.rle$lengths >= merge.rows)

for (i in mmf.zero) {
# find which positions are zero, calculate sums and insert the result into a data.frame where the rows in question were turned to NA
    m.mmf <- mmf.rle$lengths[1:i] # select elements from 1 to where the zero appears
    select.rows <- (sum(m.mmf[1:length(m.mmf) - 1])+1):sum(m.mmf) # magic
    mmf.sum <- colSums(mmf[select.rows, ]) # sum values column-wise for rows that have at least three zeros in z
    mmf[select.rows,] <- NA # now that we have a sum by columns, we turn those numbers into NAs...
    mmf[select.rows[1], ] <- mmf.sum # ... and insert summed result into the first NA row       
}

# remove any left over NA rows
mmf <- mmf[complete.cases(mmf),]

mmf由于您似乎仍处于“学习阶段”,我认为使用该软件包的示例会有所帮助。plyr是一个非常方便的库,它允许您以灵活的方式(以及简洁的方式,如您将在下面看到的)对数据集进行切片/切分,并总结它们的子组,因此可能值得您花时间去了解。如果你发现自己需要在非常大的数据集上进行类似的操作,你也可以考虑查看这个包。
我假设您已经完成了Roman的
textConnection
技巧,将数据放入名为
mmf
的data.frame中。 我正在向
mmf
添加一个
idx
列,以便您可以对其进行子集划分,并按组处理结果:

library(plyr)
# mmf <- read.table(textConnection( ...
rle.idx <- rle(mmf$z)
mmf$idx <- rep(seq(RLE$lengths), RLE$lengths)
ans <- ddply(mmf, .(idx), colwise(sum))
只需删除
idx
列,即可完成,例如:

ans <- ans[, -4]
ans数据


mmf必须将合并的数据放在“零”块之前的位置,或者可以将其追加到末尾?最好将数据添加到位,但这是我自己尝试解决此问题时遇到的问题之一。我正在考虑附加一个索引,以便以后可以将表重新排序。您的解决方案非常有效,我需要花一些时间来解析您的代码,以便我自己理解所有部分。这是基本的想法吗?计算符合条件的行数(在本例中为0)查找大于允许的连续行数(在本例中为3)检查所有匹配项聚合结果标记为稍后删除而聚合的行删除所有已从删除中标记的内容我的上述评论中没有空白格式,因此如果没有意义,请随意忽略。@themartinmcfly您基本了解了。您可以通过将
browser()
放置在第一行,逐步完成
for
循环。运行循环时,执行将在
browser
所在的行暂停。您可以通过键入
n
转到下一行,也可以通过手动发送所需行来执行代码。有关详细信息,请参见
?浏览器
。这是一个好把戏!但是,如果存在长度>=3的连续非零数序列,则代码将失败。修改代码以考虑这种可能性应该很容易。我不确定我是否遵循了您描述的场景。。。确切地说,“长度>=3的连续序列”在哪里会有问题?你是说如果
z
列是连续的,
rle
技巧就不起作用了吗?这确实需要一种不同的方法,但我不认为这是你所说的。谢谢你的plyr推荐。通过查看它的文档,对于那些有c语言背景的人来说(我自己还不太习惯在集合中思考)似乎更容易理解。虽然为这些rle技巧交换循环似乎是我的下一个学习曲线。我将不得不逐步了解这一点,并在分割数据时看一看(这就是我目前所做的:D)。@Thermatinmcfly:实际上,我不同意你的观点,即“plyr对于具有c背景的人来说更容易”。我认为对于有函数式编程背景的人来说,这比命令式编程(比如C)更直观。了解C可能会使它更难!使用plyr(以及R的“正常”应用函数),程序员不再像C程序员那样关心循环的机制(例如,
for(i=0;i
),而是将重点放在“应用”上,而不是其他事物的集合(列表或数据帧组等)哦,这就是我的意思,对不起,史蒂夫。我有C的背景,倾向于反复思考,发现这是R的一个障碍。
ans <- ans[, -4]
agg_n <- function(dat=mmf,coln="z",n=3){
    agg <- function(.x) {
        # Sum values if first n=3 records in column coln="z" are 0 
        if(all(.x[[coln]][seq(n)] == 0)) {
            y <- rbind(colSums(.x[seq(n),]),.x[-1*seq(n),])
        } else y <- .x
        return(y)
    }
    # Groups of records starting with 0 in column coln="z"
    G <- cumsum(diff(c(0L,dat[[coln]] == 0))==1)
    new_dat <- do.call(rbind,lapply(split(dat,G),agg))
    return(new_dat)
}
> agg_n()
      x  y z
0     0  0 6
1.1  49  7 0
1.5  10  0 1
1.6   0  0 2
2.1  11 11 0
2.10  0  0 0
2.11  0  0 2
2.12 18  0 4