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


160

在R中,对TRUE逻辑向量中的值数进行计数的最有效/惯用方式是什么?我可以想到两种方式:

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

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

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

Answers:


174

逻辑向量包含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)

所以我认为最安全的是使用na.rm = TRUE

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

(给出1)。我认为该table解决方案效率较低(请看table功能代码)。

另外,如果逻辑向量中没有TRUE值,则应谨慎使用“表”解决方案。假设z <- c(NA, FALSE, NA)或者干脆z <- c(FALSE, FALSE),然后table(z)["TRUE"]给你NA的这两种情况。


table(c(FALSE))["TRUE"]给人NA,不是0
贝纳Farjoun

@YossiFarjoun是的,这就是我的回答。这是为什么它不起作用的示例。我的解决方案是sum(z, na.rm = TRUE)
马立克

84

另一个未提及的选择是使用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逻辑值,因此它实际上会忽略非逻辑值。


:BTW,有一个好的技巧,在德克的回答时间stackoverflow.com/questions/1748590/revolution-for-r/...
马立克

12

另一种方法是

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

虽然sum(z) 又好又矮,但对我来说length(z[z==TRUE])却是更多的自我解释。不过,我认为使用这样的简单任务并没有真正的改变...

如果向量很大,则可能应采用最快的解决方案sum(z)。比慢length(z[z==TRUE])10倍,慢table(z)[TRUE]200 倍sum(z)

总结,sum(z)是最快的键入和执行。


6

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一个结果,但如果传递na.rm = TRUEsum功能,你会得到的结果是你想要的。

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

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


我正在尝试对测验进行评分。在应用中执行诸如sum(youranswer == rightanswer)之类的操作。
Jyotirmoy Bhattacharya 2010年

我的回复太长,因此我发布了一个新答案,因为它与以前的答案有所不同。
aL3xa 2010年

6

另一种选择是使用摘要功能。它给出了Ts,Fs和NA的摘要。

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

1
另外,为了只得到“真”的结果(这将是作为字符串输出,而且还包括在输出“TRUE”):summary(hival)["TRUE"];
迈克尔

0

几周前我一直在做类似的事情。这是一个可能的解决方案,它是从头开始编写的,因此它是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)
}

我将尝试通过一些* ply函数以一种更加优雅的方式进行此操作。请注意,我没有提出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。我将尝试修复此问题……希望对您有所帮助!


6
一线:rowSums(t(t(d)==sol), na.rm=TRUE)。R循环矢量进行比较。如果您d是矩阵,矩阵中的列为例,则其简化为rowSums(d==sol, na.rm=TRUE)
Marek

0

我有一个特殊的问题,我必须计算逻辑向量中的真实语句的数量,这对我来说最有效。

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

因此,这采用了gene.rep.matrix对象的子集,并应用了逻辑测试,并返回了逻辑向量。该向量作为grep的参数放置,该参数返回任何TRUE条目的位置。然后,Length计算grep找到多少个条目,从而给出TRUE条目的数量。


0

还有一个名为的软件包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
})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.