【问题标题】:How to look up specific indices of vectors in a list of vectors, where the indices are given in a vector? (without a for loop)如何在向量列表中查找向量的特定索引,其中索引在向量中给出? (没有 for 循环)
【发布时间】:2022-10-18 00:43:41
【问题描述】:

我想找到一种有效的操作来在列表中进行以下查找:

L = list(10:15,11:20)
a = c(3,7)
b = numeric()
for(i in 1:length(a)) b[i] = L[[i]][a[i]]

我认为for 循环效率低下,我想这可以使用例如sapply 更快地完成。我的主要目标是在L 很长时有效地做到这一点。

【问题讨论】:

    标签: r list performance lookup


    【解决方案1】:

    我们可以使用

    library(dplyr)
    stack(setNames(L, a)) %>%
       group_by(ind) %>% 
       summarise(out = values[[as.numeric(as.character(first(ind)))]]) %>%
       pull(out)
    [1] 12 17
    

    或者在base R 中使用vapply 会更快

    vapply(seq_along(L), (i) L[[i]][a[i]], numeric(1))
    [1] 12 17
    

    或使用 imap 作为紧凑选项

    library(purrr)
    imap_dbl(setNames(L, a), ~ .x[as.numeric(.y)])
     3  7 
    12 17 
    

    【讨论】:

    • 对于dplyr 解决方案,我只能得到一个最大大小为 10 的向量,而且这些值并不全正确。
    • @jblood94 你注意到我用了as.numeric(as.character
    • @jblood94 即,如果您在没有它们的情况下这样做,它是一个因子列,然后它根据整数强制值进行匹配
    • 另外,我注意到您的大数据有重复的值,这不是我在 dplyr 解决方案中使用的假设
    • 我逐字尝试了有和没有as.numeric(as.character 的代码。它可能是我的 R 版本 (4.0.2),但它也不适用于 rdrr.io/snippets
    【解决方案2】:

    另一个apply 方法是sapply()

    sapply(1:length(a), function(x) L[[x]][a[x]])
    [1] 12 17
    

    【讨论】:

      【解决方案3】:

      更新:

      您对for 循环的厌恶可能是没有根据的。我发现它可能非常依赖机器。在我当前的机器上,b 已正确初始化,基本 R for 循环仅比 Rcpp 解决方案慢,而且几乎没有。请参阅下面的更新基准。 loop1 解决方案已正确初始化。


      使用 unlistcumsumlengths 的基本 R 矢量化解决方案:

      b <- unlist(L)[a + c(0, cumsum(lengths(L)[1:(length(L) - 1L)]))]
      

      基准测试(在Rcpp 解决方案中折腾)*

      library(purrr)
      
      L <- lapply(sample(4:10, 1e5, TRUE), seq)
      a <- sapply(lengths(L), function(x) sample(x, 1))
      
      Rcpp::cppFunction("IntegerVector ListIndex(const List& L, const IntegerVector& a) {
      const int n = a.size();
      IntegerVector b (n);
      for (int i = 0; i < n; i++) b(i) = as<IntegerVector>(L[i])(a(i) - 1);
      return b;
      }")
          
      microbenchmark::microbenchmark(sapply = sapply(1:length(a), function(x) L[[x]][a[x]]),
                                     vapply = vapply(seq_along(L), function(i) L[[i]][a[i]], numeric(1)),
                                     purr = imap_dbl(setNames(L, a), ~ .x[as.numeric(.y)]),
                                     unlist = unlist(L)[a + c(0, cumsum(lengths(L)[1:(length(L) - 1L)]))],
                                     rcpp = ListIndex(L, a),
                                     loop1 = {b <- integer(length(a)); for(i in seq_along(a)) b[i] <- L[[i]][a[i]]},
                                     loop2 = {b <- integer(); for(i in seq_along(a)) b[i] <- L[[i]][a[i]]})
      
      #> Unit: milliseconds
      #>    expr      min       lq      mean    median       uq      max neval
      #> sapply 102.4199 113.72450 125.21764 119.72455 130.41480 291.5465   100
      #> vapply  97.8447 107.33390 116.41775 112.33445 119.01680 189.9191   100
      #>   purr 226.9039 241.02305 258.34032 246.81175 257.87370 502.3446   100
      #> unlist  29.4186  29.97935  32.05529  30.86130  33.02160  44.6751   100
      #>   rcpp  22.3468  22.78460  25.47667  23.48495  26.63935  37.2362   100
      #>  loop1  25.5240  27.34865  28.94650  28.02920  29.32110  42.9779   100
      #>  loop2  41.4726  46.04130  52.58843  51.00240  56.54375  88.3444   100
      

      *我无法让 akrun 的 dplyr 解决方案与更大的向量一起使用。

      【讨论】:

      • 感谢您的有效解决方案
      • 我更新了我的基准测试以包含for 循环解决方案。我建议看看。
      • 我确实很惊讶。
      【解决方案4】:

      您可以使用Mapmapply。由于mapply 可以自动简化为向量,我们可以在这里使用它一次性得到b

      b <- mapply(function(list_members, indices) list_members[indices],
             list_members = L, indices = a, SIMPLIFY = TRUE)
      
      b
      #> [1] 12 17
      

      【讨论】:

      • 请问在这种情况下使用mapplysapply(例如sapply(1:length(a), function(x) L[[x]][a[x]]))有什么优势吗?
      • 在这种情况下不是@benson23。它可能更通用,但如果设置始终如 OP 所述,我可能会自己使用更简单的sapply。当然,这实际上只是编写循环的一种简便方法,不一定更快或更有效。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-03
      • 2016-02-03
      • 2020-09-02
      • 1970-01-01
      • 2019-04-28
      • 2013-06-09
      相关资源
      最近更新 更多