使用逻辑 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
是因为向量的第二个位置有两个(至少一个,any
)TRUE
。
我可以将我的数据结构更改为 matrix
或 data.frame
或其他更好的东西,我只是从 lapply
得到这个。
【问题讨论】:
【参考方案1】:使用 pmap() 和 any() 的解决方案,以及一些额外的基准测试
我也喜欢使用purrr
s pmap
,作为按行操作的一般方法。
pmap 绝对不是最快的,如下面的基准测试所示(未矢量化为 Reduce() 或 reduce() 或 rowSums()),但我发现它非常通用且一致。
在这种情况下,您可以将其与any
一起使用,这比嵌套/顺序|
更快,对我来说更直观。
library(purrr)
opts%>%pmap_lgl(., any)
purrr
s 版本的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_lgl
和 any>"|"
【讨论】:
【参考方案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 组合列表中的逻辑向量的主要内容,如果未能解决你的问题,请参考以下文章