如何在R中没有for循环的非常大的数据帧中计算累积的非零变量?

时间:2017-02-03 23:35:48

标签: r

我有一个巨大的df并且尝试执行跟随代码需要太长时间。无论如何要加快速度?

df$col2 <- 0
for (i in 2:nrow(df)) {
    if (df$col1 > 0) {
        df$col2[i] <- df$col2[i-1] + 1
    }
    else {
        df$col2[i] <- 0
    }
}

示例数据

df <- data.frame(col1 = c(1, 0, 10, 28, 0, 0, 2))

预期结果

col1 col2
   1    1
   0    0
  10    1
  28    2
   0    0
   0    0
   2    1

我正在尝试使用col2计算col1中的累计非零变量,并在0中点击col1时重置计数。

3 个答案:

答案 0 :(得分:2)

以下是使用rleid()包中的data.table函数的解决方案:

library(data.table)
setDT(df)[, .(col1, col2 = cumsum(col1 != 0)), by = rleid(col1 != 0)][, rleid := NULL][]
#   col1 col2
#1:    1    1
#2:    0    0
#3:   10    1
#4:   28    2
#5:    0    0
#6:    0    0
#7:    2    1

rleid()函数是一个便捷函数,用于生成在分组操作中使用的游程长度类型id列?rleid)。它应用于由col1 != 0创建的逻辑值序列,该序列对于零和非零值进行预测。在每个组中,cumsum()用于计算非零值。最后,从结果中删除rleid列。

作为替代方案,cumsum()可以用简单的序列代替。

setDT(df)[, .(col1, col2 = seq_len(.N)), by = rleid(col1 != 0)][col1 == 0, col2 := 0][
  , rleid := NULL][]

然而,这也会计算未被请求的后续零值。因此,对于col2为零的所有行,col1中的这些计数必须重置为零。

答案 1 :(得分:0)

我会注释我认为错误的内容并显示我认为会更快的等价物:

df$col2 <- 0
for (i in 2:nrow(df)) { 
    if (df$col1 > 0) {   # at least a "semantic" error
        df$col2[i] <- df$col2[i-1] + 1}
    else { df$col2[i] <- 0 }
}

要求if (df$col1 > 0)将向量与单个值进行比较,而不索引应测试多个值中的哪一个。因此,将其称为“语义错误”,因为R将仅在每次循环中测试df $ col1的第一个值。我猜你想要这些东西:

df$col2 <- cumsum( c(0, head(df$col1, -1) > 0 ) )
df$col2[ c(TRUE, head(df$col1 == 0)]  <- 0

这将构建您要求的运行计数,然后将没有增量的条目归零。

答案 2 :(得分:0)

this answer中有一个快速(但棘手)的解决方案。

所以在你的情况下:

df <- data.frame(col1 = c(1, 0, 10, 28, 0, 0, 2))

f7 <- function(x) { tmp <- cumsum(x) ; tmp - cummax((!x)*tmp) }

df$col2 <- f7(df$col1 > 0)

df
#   col1 col2
# 1    1    1
# 2    0    0
# 3   10    1
# 4   28    2
# 5    0    0
# 6    0    0
# 7    2    1