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

时间:2013-10-08 14:30:34

标签: r

问题

如何使用or在列表中以元素方式有效地组合逻辑向量,以便获得相同长度的向量?

实施例

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

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

我希望这样做:

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

我可以将我的数据结构更改为matrixdata.frame或其他更好的东西,如果它更好,我只是从lapply获取此内容。

4 个答案:

答案 0 :(得分:26)

如何减少:

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

答案 1 :(得分:6)

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

答案 2 :(得分:3)

你可以这样做:

(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。

答案 3 :(得分:0)

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

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

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>"|"