【问题标题】:Combine logical vectors in list using logical OR使用逻辑 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 得到这个。

【问题讨论】:

    标签: r list boolean boolean-logic


    【解决方案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_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。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-27
        • 1970-01-01
        相关资源
        最近更新 更多