以下是我的数据框。它有行名和列名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
row1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0
row2 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0
我想基于连续的零(来自最后一列,每行的列)派生一个 test 列。下面是一个示例。对于第一行,有8个连续的零,所以 test 行中的值应为8.对于第二行,结果应该是1只有一个零。(我想从15开始考虑并回到零开始的地方) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 test
row1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 8
row2 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1
实现这一目标的最佳方式是什么?
答案 0 :(得分:4)
使用 SELECT i.eventtype, i.evtdate , i.tod , COUNT( * ) AS count
FROM eventinfo AS i
LEFT JOIN entries as e On e.eventcat = i.eventtype
GROUP BY i.eventtype, i.evtdate , i.tod ;
的解决方案:
rle
说明:
使用getConsecZeroRle <- function(x) {
foo <- rle(x)
foo$lengths[tail(which(foo$values), 1)]
}
result <- apply(df[, -1] == 0, 1, function(x) getConsecZeroRle(x))
df$test <- as.numeric(result)
df$test[is.na(df$test)] <- 0
迭代数据框的子集。对于每一行,计算连续零(apply
)的长度,并使用rle
提取最后一个值。没有零的行将生成tail
(使用NA
)以零替换它们。
使用is.na(df$test)
的解决方案:
sum
说明:
提取每行中的最后getConsecZeroSum <- function(x) {
x[1:tail(which(!x), 1)] <- FALSE
sum(x)
}
df$test <- apply(df[, -1] == 0, 1, function(x) getConsecZeroSum(x))
值,然后将所有内容转换为FALSE
(FALSE
),然后使用x[1:tail(which(!x), 1)] <- FALSE
从最后计算零值。
结果:
sum
答案 1 :(得分:1)
你可以简单地找到不等于0
的第一个值的索引(从最后一列开始)然后减去一个:
df$test2 <- apply(df[,ncol(df):1]==0, 1, which.min) - 1
df
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 test2
#1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 8
#2 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1
另一个答案:
由于我对没有apply
行的方法感到好奇,因此我提出了一个(公认的复杂)Reduce
解决方案。不是我推荐的解决方案,但我有兴趣看看是否有办法做到这一点:
iniCol <- setNames(df[,ncol(df)] == 0, as.numeric(df[,ncol(df)] == 0))
df$test2 <- Reduce(function(ini, add) {temp <- ifelse(pmin(as.numeric(names(ini)), add==0) == 0, ini, rowSums(cbind(ini, add == 0)))
ini <- setNames(temp, pmin(as.numeric(names(ini)), add==0))},
df[,(ncol(df)-1):1],
ini = iniCol)
这背后的想法是使用names
属性来跟踪列是否曾0
。如果是,那么我们就停止计数,否则继续计数。