16

问题

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

例子

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

> 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, 是因为向量的第二个位置有两个(至少一个, anyTRUE

matrix如果我data.frame只是从lapply.

4

4 回答 4

36

减少怎么样:

Reduce("&", opts)
Reduce("|", opts)
于 2013-10-08T14:38:19.447 回答
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
于 2013-10-08T14:36:34.837 回答
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)创建一个 TRUE 和 FALSE 的 1000x10 矩阵:

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。

于 2013-10-08T14:32:30.177 回答
0

使用 pmap() 和 any() 的解决方案,以及一些额外的基准测试

我也喜欢使用purrrspmap作为按行操作的一般方法。
pmap 绝对不是最快的,如下面的基准测试所示(未矢量化为 Reduce() 或 reduce() 或 rowSums()),但我发现它非常通用且一致。在这种情况下,您可以使用它any,它比 nested/sequential 更快,对我来说更直观|

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

purrrReduce()的, ,的版本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>"|"

于 2021-05-14T20:56:23.130 回答