如何计算逻辑向量中的 TRUE 值

在 R 中,计算逻辑向量中 TRUE值的数目的最有效/最惯用的方法是什么?我能想到两种方法:

z <- sample(c(TRUE, FALSE), 1000, rep = TRUE)
sum(z)
# [1] 498


table(z)["TRUE"]
# TRUE
#  498

你更喜欢哪个? 还有更好的吗?

348561 次浏览

另一种方式是

> length(z[z==TRUE])
[1] 498

虽然 sum(z)是很好的和短,对我来说 length(z[z==TRUE])是更自我解释。虽然,我认为这样一个简单的任务,它并不真的有什么不同..。

如果它是一个大的向量,您可能应该使用最快的解决方案,即 sum(z)length(z[z==TRUE])sum(z)慢10倍,table(z)[TRUE]sum(z)慢200倍。

总之,sum(z)是输入和执行速度最快的。

最安全的方法是与 na.rm = TRUE一起使用 sum:

sum(z, na.rm = TRUE) # best way to count TRUE values

得到1。

当逻辑向量包含 NA值时,其他解决方案存在一些问题。

例如:

z <- c(TRUE, FALSE, NA)


sum(z) # gives you NA
table(z)["TRUE"] # gives you 1
length(z[z == TRUE]) # f3lix answer, gives you 2 (because NA indexing returns values)

此外,table解决方案效率较低(请看 table函数的代码)。

另外,在使用“表”解决方案时应该小心,以防逻辑向量中没有 TRUE 值。例如:

z <- c(FALSE, FALSE)
table(z)["TRUE"] # gives you `NA`

或者

z <- c(NA, FALSE)
table(z)["TRUE"] # gives you `NA`

另一个没有提到的选项是使用 which:

length(which(z))

只是为了提供一些关于“哪个是更快的问题”的上下文,测试自己总是最容易的。为了比较,我把矢量放大了很多:

z <- sample(c(TRUE,FALSE),1000000,rep=TRUE)
system.time(sum(z))
user  system elapsed
0.03    0.00    0.03
system.time(length(z[z==TRUE]))
user  system elapsed
0.75    0.07    0.83
system.time(length(which(z)))
user  system elapsed
1.34    0.28    1.64
system.time(table(z)["TRUE"])
user  system elapsed
10.62    0.52   11.19

因此,在这种情况下,显然使用 sum是最好的方法。您可能还需要检查 NA值,正如 Marek 建议的那样。

只是要补充一点关于 NA 值和 which函数的注意事项:

> which(c(T, F, NA, NULL, T, F))
[1] 1 4
> which(!c(T, F, NA, NULL, T, F))
[1] 2 5

注意,它只检查逻辑 TRUE,因此它基本上忽略了非逻辑值。

which是一个很好的选择,特别是当您操作矩阵时(检查 ?which并注意 arr.ind参数)。但是我建议您坚持使用 sum,因为 na.rm参数可以在逻辑向量中处理 NA。 例如:

# create dummy variable
set.seed(100)
x <- round(runif(100, 0, 1))
x <- x == 1
# create NA's
x[seq(1, length(x), 7)] <- NA

如果键入 sum(x),您将得到结果 NA,但是如果在 sum函数中传递 na.rm = TRUE,您将得到所需的结果。

> sum(x)
[1] NA
> sum(x, na.rm=TRUE)
[1] 43

你的问题是严格的理论问题,还是有一些关于逻辑向量的实际问题?

我几周前也做过类似的事。这里有一个可能的解决方案,它是从头开始编写的,所以它是一种 beta 版本或类似的东西。我将尝试通过删除代码中的循环来改进它..。

主要思想是编写一个接受2个(或3个)参数的函数。第一个是 data.frame,它包含从问卷中收集的数据,第二个是带有正确答案的数字向量(这只适用于单一选择问卷)。或者,您可以添加第三个参数,它将返回带有最终得分的数值向量,或者带有嵌入得分的 data.frame。

fscore <- function(x, sol, output = 'numeric') {
if (ncol(x) != length(sol)) {
stop('Number of items differs from length of correct answers!')
} else {
inc <- matrix(ncol=ncol(x), nrow=nrow(x))
for (i in 1:ncol(x)) {
inc[,i] <- x[,i] == sol[i]
}
if (output == 'numeric') {
res <- rowSums(inc)
} else if (output == 'data.frame') {
res <- data.frame(x, result = rowSums(inc))
} else {
stop('Type not supported!')
}
}
return(res)
}

我将尝试使用一些 * 铺层函数以更优雅的方式完成此操作。请注意,我没有把 na.rm参数... 将做到这一点

# create dummy data frame - values from 1 to 5
set.seed(100)
d <- as.data.frame(matrix(round(runif(200,1,5)), 10))
# create solution vector
sol <- round(runif(20, 1, 5))

现在应用一个函数:

> fscore(d, sol)
[1] 6 4 2 4 4 3 3 6 2 6

如果传递 data.frame 参数,它将返回修改后的 data.frame。 我会试着修好这个... 希望能有帮助!

我遇到了一个特殊的问题,我必须从一个逻辑向量中计算真语句的数量,这对我来说效果最好..。

length(grep(TRUE, (gene.rep.matrix[i,1:6] > 1))) > 5

因此,它接受 gene.rep.Matrix 对象的一个子集,并应用一个逻辑测试,返回一个逻辑向量。这个向量作为 grep 的一个参数,它返回所有 TRUE 条目的位置。Llength 然后计算 grep 找到了多少条目,从而给出 TRUE 条目的数量。

另一种选择是使用汇总函数,它给出 T、 Fs 和 NAs 的汇总。

> summary(hival)
Mode   FALSE    TRUE    NA's
logical    4367      53    2076
>

还有一个称为 bit的包,专门为快速布尔操作设计。如果您有很大的向量或者需要执行很多布尔运算,那么它就特别有用。

z <- sample(c(TRUE, FALSE), 1e8, rep = TRUE)


system.time({
sum(z) # 0.170s
})


system.time({
bit::sum.bit(z) # 0.021s, ~10x improvement in speed
})