使用逻辑 OR 组合列表中的逻辑向量

Posted

技术标签:

【中文标题】使用逻辑 OR 组合列表中的逻辑向量【英文标题】:Combine logical vectors in list using logical OR 【发布时间】:2013-10-15 13:03:02 【问题描述】:

问题

如何使用元素比较与逻辑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 是因为向量的第二个位置有两个(至少一个anyTRUE

我可以将我的数据结构更改为 matrixdata.frame 或其他更好的东西,我只是从 lapply 得到这个。

【问题讨论】:

【参考方案1】:

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

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

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

purrrs 版本的Reduce()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_lglany>"|"

【讨论】:

【参考方案2】:

如果所有列表的长度相同,则可以将其强制转换为数据框,然后使用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

【讨论】:

从 microbenchmark 包 (microbenchmark(apply(data.frame(opts),1,any))) 来看:这是 far 最快的解决方案。 (这是有道理的,因为any 会在找到第一个 TRUE 值时短路)。 嗯,当我对它进行基准测试时,这个解决方案似乎是迄今为止最慢的。 您使用的是什么尺寸的opts? TRUE 和 FALSE 的组成是什么? (我在下面的帖子中使用了这种方法) 我将在几秒钟内将输出添加到我的解决方案中。 奇怪的是,在我的机器上,我的表达速度(略)比 Reduce 快。但同意了。【参考方案3】:

Reduce 怎么样:

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

【讨论】:

+1 这是最干净的解决方案,根据我的基准测试,也是最快的。 谢谢!我不知道Reduce存在。这正是我想要的。 我试图获取案例的sum(以评估哪个更频繁地是真还是假)并且正确的函数不是"sum",而是"+"...以防万一其他人带着同样的问题来到这里。【参考方案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。

【讨论】:

以上是关于使用逻辑 OR 组合列表中的逻辑向量的主要内容,如果未能解决你的问题,请参考以下文章

如何获得逻辑回归中的权重向量?

R数据类型

组合列表中的向量以创建数据框 R [重复]

为啥 R 中的逻辑(布尔值)需要 4 个字节?

逻辑组合布尔值列表的最“pythonic”方式是啥?

奇怪的大于逻辑与字符向量中的数字