【问题标题】:Is there an R idiom for obtainig the index of the minimum element in a vector after filtering by a boolean index vector?通过布尔索引向量过滤后,是否有 R 成语用于获取向量中最小元素的索引?
【发布时间】:2021-08-07 08:00:19
【问题描述】:

假设我有一个向量,例如

x <- c(7,2,8,1,6,5)

和一个布尔向量,例如

b <- c(TRUE,FALSE,FALSE,FALSE,TRUE,FALSE)

我想找到x 中最小元素的索引,b 中的对应元素是TRUE。但是,如果我写

which.min(x[b])

它返回 2,因为 x[b] 的计算结果为 c(7,6)。相反,我想在b 索引之前获得5,向量x 的相应索引。我会写

(1:6)[b][which.min(x[b])]

但这不是很可读!有没有更易读的方式?

【问题讨论】:

  • 在标题中寻找 maximum,但在文本中寻找 smallest 元素。
  • 已编辑以修复标题。谢谢:-)

标签: r indexing boolean


【解决方案1】:

我建议replace()

which.min(replace(x, !b, NA))

这类似于GKi's 的一个很好的解决方案,但如果所有b 都是FALSE,它仍然有效。

【讨论】:

    【解决方案2】:

    可以使用[&lt;-FALSE 位置设置为NA,而不是将xb 子集。

    which.min("[<-"(x, !b, NA))
    #[1] 5
    

    或者,它也可以设置为例如Inf,正如@mrflick 的回答中所给出的,但这将限制一般适用性,要用于which.max,它需要设置为-Inf,如果没有TRUE,它将返回一个索引。

    使用which可以将逻辑向量转换为索引,这些索引可以用于子集和子集,类似于@mrflick的解决方案,但避免使用which两次。

    i <- which(b)
    i[which.min(x[i])]
    #[1] 5
    

    如果x 中的值都是正数,您可以除以b 给出b == FALSE Inf 的情况(如果是负数x @ 987654339@) - 这种方式不推荐

    which.min(x / b)
    #[1] 5
    

    bench::mark比较:

    n <- 1e6
    set.seed(42)
    x <- sample(0:99, n, TRUE)
    b <- sample(c(TRUE,FALSE), n, TRUE)
    
    bench::mark(which.min(ifelse(b, x, Inf))
    , which(b)[which.min(x[b])]
    #, which(x == min(x[b]))             #Result not equal to others
    #, which(x == min(x[b]) & b)         #Result not equal to others
    , which.min("[<-"(x, !b, NA))
    , which.min("[<-"(x, !b, Inf))
    , which.min(x / b)
    )
    #  expression                        min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
    #  <bch:expr>                   <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
    #1 which.min(ifelse(b, x, Inf))  13.75ms  13.95ms      70.6   30.52MB     61.2    15    13      212ms
    #2 which(b)[which.min(x[b])]      5.13ms    5.2ms     192.    19.07MB     92.5    58    28      303ms
    #3 which.min(`[<-`(x, !b, NA))    3.58ms   3.67ms     271.    11.44MB     51.2   106    20      391ms
    #4 which.min(`[<-`(x, !b, Inf))   4.85ms   4.96ms     200.    19.07MB    100.     50    25      250ms
    #5 which.min(x/b)                 3.99ms   4.05ms     246.     7.63MB     22.6   109    10      442ms
    
    b <- logical(n) #No True
    bench::mark(#which.min(ifelse(b, x, Inf)) #Wrong result
      which(b)[which.min(x[b])]
    , which.min("[<-"(x, !b, NA))
    #, which.min("[<-"(x, !b, Inf))           #Wrong result
    #, which.min(x / b)                       #Wrong result
    )
    #  expression                     min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result
    #  <bch:expr>                  <bch:> <bch:>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list>
    #1 which(b)[which.min(x[b])]   1.18ms 1.21ms      826.    7.63MB     72.9   340    30      412ms <int …
    #2 which.min(`[<-`(x, !b, NA)) 5.36ms 5.49ms      181.   15.26MB     38.3    71    15      392ms <int …
    
    b <- !logical(n) #All True
    bench::mark(which(b)[which.min(x[b])]
    , which.min("[<-"(x, !b, NA))
    )
    #  expression                     min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result
    #  <bch:expr>                  <bch:> <bch:>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list>
    #1 which(b)[which.min(x[b])]   5.06ms 5.25ms      184.    19.1MB     92.0    54    27      293ms <int …
    #2 which.min(`[<-`(x, !b, NA)) 3.59ms 3.81ms      261.    11.4MB     48.5   102    19      391ms <int …
    

    【讨论】:

    • “纳秒”基准测试并不是很有用;你能把xb 放大吗?
    • @SymbolixAU 感谢您的评论!我更新了比较。
    • 如果所有b 都是FALSE,它将失败。
    【解决方案3】:

    如果您在 x 中有唯一值:

    which(x == min(x[b]))
    #[1] 5
    

    如果x 中可能有重复项:

    which(x == min(x[b]) & b)
    #[1] 5
    

    【讨论】:

      【解决方案4】:

      在您执行x[b] 之后,生成的向量没有值的原始索引的内存。该信息丢失。另一种方法是将 FALSE 的值更改为非常大的值。例如

      which.min(ifelse(b, x, Inf))
      # [1] 5
      

      另一种选择是

      which(b)[which.min(x[b])] 
      

      因为which(b)(1:6)[b]基本相同

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多