使用逻辑“或”组合列表中的逻辑向量

18

问题

如何使用逐元素比较和逻辑 OR (|) 有效地组合列表中的逻辑向量。结果应该是与输入向量相同长度的逻辑向量。如果任何一个输入值为TRUE,则结果为TRUE,否则结果为FALSE

示例

我有一个名为 opts 的列表,其中包含一组相同长度的逻辑向量。

> str(opts)
List of 5
 $ option1: logi [1:608247] FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ option2: logi [1:608247] FALSE TRUE  FALSE TRUE  TRUE  TRUE  ...
 $ option3: logi [1:608247] FALSE TRUE  FALSE FALSE TRUE  FALSE ...
 $ option4: logi [1:608247] FALSE FALSE FALSE FALSE FALSE FALSE ...

我希望您可以将这个作为结果:

logi [1:608247] FALSE TRUE FALSE TRUE TRUE TRUE ...

因此,结果的第一个值FALSE是因为在列表的所有向量的第一个位置上都没有TRUE。结果的第二个值TRUE是因为在向量的第二个位置上有两个(至少一个any),TRUE

如果可以更好地使用matrixdata.frame或其他什么数据结构来获取这个结果,我可以更改我的数据结构,只要我能从lapply中获得它就可以。

4个回答

38

如何减少:

Reduce("&", opts)
Reduce("|", opts)

3
这是最清晰的解决方案,而且根据我的基准测试,也是最快的。 - mrip
1
谢谢!我不知道Reduce的存在。它正是我正在寻找的东西。 - while
我尝试获取案例的“总和”(以评估TRUE与FALSE哪个更频繁),但正确的函数不是“sum”,而是“+”...以防其他人有同样的问题。 - Antonio Canepa
据我所知,这样的特殊函数(如 &|+)只有在反引号(`)中而不是在引号(")中才能起作用。 - Matteo
@Matteo,如果您正在调用_object_,那么是的,您需要使用反引号。但是,如果您是指对象的名称(如上例),则应使用引号(单引号或双引号)。例如,\&`(var1, var2)`是正确的,因为我们正在调用名称为“&” 的对象。在这种情况下,该对象是一个函数。 - Ricardo Saporta

8

如果所有列表的长度相同,您可以将其转换为数据框,然后使用any

apply(data.frame(opts),1,any)

编辑:虽然我认为这可能很快,因为它避免了cbind,但根据我的基准测试,这是三种解决方案中最慢的:

set.seed(123)
opts = as.list(as.data.frame(matrix(sample(c(TRUE, FALSE), 10000, replace=TRUE), nrow=1000)))

require(microbenchmark)
microbenchmark(Reduce("|",opts),rowSums(do.call(cbind, opts)) > 0,
               apply(as.data.frame(opts),1,any))


Unit: microseconds
                               expr      min        lq   median        uq
                  Reduce("|", opts)   99.200  101.0780  106.596  110.3725
  rowSums(do.call(cbind, opts)) > 0  209.326  211.9665  217.329  224.0505
 apply(as.data.frame(opts), 1, any) 4130.429 4245.7380 4308.054 4438.2485
     max neval
  120.63   100
  237.19   100
 6949.19   100

嗯,当我对其进行基准测试时,这个解决方案似乎是迄今为止最慢的。 - mrip
你使用的 opts 大小是多少?以及 TRUE 和 FALSE 的组合方式是什么?(我在下面的帖子中使用了这种方法) - David Robinson
啊:我怕我在输出从毫秒到微秒的切换上错过了,真是太愚蠢了!看起来我的解决方案是最快的。预计时间:或者看起来确实是Reduce。 - David Robinson
你的和 Reduce 很接近,但我的速度要慢得多。 - mrip
1
奇怪的是,在我的机器上,我的表达式比Reduce(略微)更快。但同意。 - David Robinson
显示剩余2条评论

4

您可以进行以下操作:

(rowSums(do.call(cbind, opts)) > 0)

例如:

opts = as.list(as.data.frame(matrix(sample(c(TRUE, FALSE), 10000, replace=TRUE), nrow=1000)))
str(opts)

do.call(cbind, opts) 创建了一个1000x10的由TRUE和FALSE组成的矩阵:

dim(do.call(cbind, opts))
# [1] 1000   10
head(do.call(cbind, opts))
#        V1    V2    V3    V4    V5    V6    V7    V8    V9   V10
#[1,]  TRUE  TRUE FALSE FALSE  TRUE  TRUE FALSE  TRUE  TRUE FALSE
#[2,] FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE
#[3,] FALSE  TRUE  TRUE FALSE  TRUE FALSE FALSE FALSE  TRUE  TRUE
#[4,] FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE  TRUE
#[5,] FALSE  TRUE FALSE  TRUE  TRUE  TRUE FALSE FALSE  TRUE FALSE
#[6,] FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE

rowSums会创建一个向量,显示每行中TRUE值的数量:在任何一行中,如果该行总和大于0,逻辑或将返回TRUE。


0

pmap()和any()的解决方案以及一些附加基准测试

我还喜欢使用purrrpmap,作为一般的逐行操作方法。
如下所示的基准测试结果显示,pmap绝对不是最快的(没有向量化,例如Reduce()、reduce()或rowSums()),但我觉得它非常灵活和一致。 在这种情况下,您可以与any一起使用,这比嵌套/顺序的|更快,并且对我来说更直观。

library(purrr)
opts%>%pmap_lgl(., any)

purrr的版本reduce()类似于@Ricardo Saporta的答案,但保持了我们在purrr中看到的语法一致性:

library(purrr)
opts%>%reduce(., `|`)

我也进行了一些基准测试。

microbenchmark(Reduce("|",opts),
               Reduce(any, opts),
               rowSums(do.call(cbind, opts)) > 0,
               apply(as.data.frame(opts),1,any),
               pmap_lgl(opts, any),
               reduce(opts, any),
               reduce(opts, `|`)
               )

Unit: microseconds
                               expr      min         lq        mean     median         uq        max neval
                  Reduce("|", opts)   40.303    59.3935    87.71092    77.5005   107.3490    461.228   100
                  Reduce(any, opts)    8.576    15.6625    29.48404    23.6775    31.9965    185.628   100
  rowSums(do.call(cbind, opts)) > 0   70.458    94.8565   133.39620   130.3765   154.3775    675.701   100
 apply(as.data.frame(opts), 1, any) 2580.162  3642.5935  4848.82291  4725.7095  5476.0935  19805.711   100
                pmap_lgl(opts, any) 7420.634 11071.3780 14972.01035 13362.0735 14820.2190 164536.018   100
                  reduce(opts, any)  229.924   388.0765   515.31035   524.9820   629.1945   1052.248   100
                  reduce(opts, `|`)  277.262   485.9855   688.35137   699.9830   790.6440   1717.872   100

基准测试清楚地显示Reduce()是最快的Reduce>rowSums+cbind>reduce>apply>pmap_lgl,而且any>"|"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接