数据帧中连续零的计数

问题描述 投票:0回答:2

以下是我的数据框。它有行名和列名。

       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 

我想基于连续的零推导出一个列测试(从最后一列开始,每行的列。下面是一个例子。对于第一行,有8个连续的零,所以测试行中的值应该是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

实现这一目标的最佳方法是什么?

r dataframe
2个回答
4
投票

使用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值,然后将所有内容转换为FALSEx[1:tail(which(!x), 1)] <- FALSE),然后使用sum从末尾计算零值。

结果:

#      a 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 test
# 1 row1 0 0 0 1 0 0 1 0 0  0  0  0  0  0  0    8
# 2 row2 0 0 0 1 1 1 1 1 1  1  1  1  1  1  0    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-ing的情况下做到这一点,我提出了一个(公认的复杂)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。如果是,那么我们停止计数,否则继续计数。

© www.soinside.com 2019 - 2024. All rights reserved.