我有一个巨大的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
时重置计数。
答案 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