【问题标题】:Subset list of vectors by position in a vectorized way以矢量化方式按位置排列的矢量子集列表
【发布时间】:2019-09-16 07:07:11
【问题描述】:

我有一个向量列表,我正在尝试选择(例如)每个向量中的第二个和第四个元素。我可以使用lapply

list_of_vec <- list(c(1:10), c(10:1), c(1:10), c(10:1), c(1:10))
lapply(1:length(list_of_vec), function(i) list_of_vec[[i]][c(2,4)])

[[1]]
[1] 2 4

[[2]]
[1] 9 7

[[3]]
[1] 2 4

[[4]]
[1] 9 7

[[5]]
[1] 2 4

但是有没有办法以矢量化的方式做到这一点——避免使用其中一个应用函数?我的问题是我的实际list_of_vec 相当长,所以lapply 需要一段时间。

【问题讨论】:

    标签: r list vector subset lapply


    【解决方案1】:

    解决方案:

    选项 1 @Athe 使用 do.call 的巧妙解决方案?:

    do.call(rbind, list_of_vec)[ ,c(2,4)]

    选项 2 更有效地使用lapply

    lapply(list_of_vec, `[`, c(2, 4))

    选项 3矢量化解决方案:

    starts <- c(0, cumsum(lengths(list_of_vec)[-1]))
    matrix(unlist(list_of_vec)[c(starts + 2, starts + 4)], ncol = 2)
    

    选项 4 您想要改进的 lapply 解决方案:

    lapply(1:length(list_of_vec), function(i) list_of_vec[[i]][c(2,4)])
    

    数据:

    我将在几个数据集上对其进行测试:

    # The original data
    list_of_vec <- list(c(1:10), c(10:1), c(1:10), c(10:1), c(1:10))
    
    # A long list with short elements
    list_of_vec2 <- rep(list_of_vec, 1e5)
    
    # A long list with long elements
    list_of_vec3 <- lapply(list_of_vec, rep, 1e3)
    list_of_vec3 <- rep(list_of_vec3, 1e4)
    

    基准测试:

    原始列表

    Unit: microseconds
     expr   min     lq     mean median    uq      max neval cld
       o1 2.276 2.8450  3.00417  2.845 3.129   10.809   100   a
       o2 2.845 3.1300  3.59018  3.414 3.414   23.325   100   a
       o3 3.698 4.1250  4.60558  4.267 4.552   20.480   100   a
       o4 5.689 5.9735 17.52222  5.974 6.258 1144.606   100   a
    

    较长的列表,较短的元素

    Unit: milliseconds
     expr       min        lq      mean    median        uq       max neval  cld
       o1 146.30778 146.88037 155.04077 149.89164 159.52194 184.92028    10  b  
       o2 185.40526 187.85717 192.83834 188.42749 190.32103 213.79226    10   c 
       o3  26.55091  27.27596  28.46781  27.48915  28.84041  32.19998    10 a   
       o4 407.66430 411.58054 426.87020 415.82161 437.19193 473.64265    10    d
    

    较长的列表,较长的元素

    Unit: milliseconds
     expr        min         lq      mean     median        uq       max neval cld
       o1 4855.59146 4978.31167 5012.0429 5025.97619 5072.9350 5095.7566    10   c
       o2   17.88133   18.60524  103.2154   21.28613  195.0087  311.4122    10 a  
       o3  855.63128  872.15011  953.8423  892.96193 1069.7526 1106.1980    10  b 
       o4   37.92927   38.87704  135.6707  124.05127  214.6217  276.5814    10 a  
    

    总结:

    看起来如果列表很长且元素很短,则矢量化解决方案会胜出,但lapply 显然是具有较长元素的长列表的赢家。一些选项输出一个列表,其他选项输出一个矩阵。所以请记住你想要你的输出是什么。祝你好运!!!

    【讨论】:

      【解决方案2】:

      如果您的列表由相同长度的向量组成,您可以先将其转换为矩阵,然后获取所需的列。

      matrix_of_vec <- do.call(rbind,list_of_vec)
      matrix_of_vec[ ,c(2,4)]
      

      否则恐怕您将不得不坚持申请家庭。最有效的方法是使用并行包进行并行计算(令人惊讶)。

      corenum <- parallel::detectCores()-1
      cl<-parallel::makeCluster(corenum)
      parallel::clusterExport(cl,"list_of_vec"))
      parallel::parSapply(cl,list_of_vec, '[', c(2,4) )
      

      在这段代码中,'[' 是子集函数的名称,c(2,4) 是您传递给它的参数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-07
        • 1970-01-01
        • 2016-05-02
        • 1970-01-01
        相关资源
        最近更新 更多