【问题标题】:removing for loop with sample function使用示例函数删除 for 循环
【发布时间】:2019-05-09 13:16:16
【问题描述】:

我有以下数据结构:

set.seed(100)
x <- data.frame("smp_1"=runif(20)*100,"smp_2"=runif(20)*99)
x["weight_1"] = x$smp_1/sum(x$smp_1)
x["weight_2"] = x$smp_2/sum(x$smp_2)


> head(x)
     smp_1     smp_2   weight_1    weight_2
1 66.61718 68.976341 0.05721288 0.061115678
2 24.65804 77.966842 0.02117709 0.069081607
3 66.10397  1.611913 0.05677212 0.001428216
4 93.95866  1.793973 0.08069459 0.001589529
5 19.96638 31.008240 0.01714774 0.027474488
6 66.35187 97.033923 0.05698502 0.085975770

现在我想创建一个新的数据框,该数据框使用权重列作为概率从每个 smp 列中采样,并将每个列样本添加到新数据框和新列中。我可以使用 for 循环来做到这一点:

tempdf <- data.frame(matrix(0,ncol=0,nrow=1000))
for (k in 1:2){
  tempdf[,paste0("sim_",k)] <- sample(x[,paste0("smp_",k)],size=1000, replace=T, prob = x[,paste0("weight_",k)])
}

我的问题是如何以更有效的方式在没有 for 循环的情况下做到这一点?我将采样 100k 的多列,所以我需要一些非常快的东西。

【问题讨论】:

    标签: r


    【解决方案1】:

    这是data.table 方法。

    在答案 ans 中,变量值(1 或 2)是您的 k

    library(data.table)
    #melt to long format
    DT <- melt( setDT(x) , 
                id.vars = NULL, 
                measure.vars = patterns( smp = "^smp", 
                                         weight = "^weight"))
    #pull samples
    ans <- DT[ , .( sim = sample( smp, 
                                  size = 1000, 
                                  replace = TRUE, 
                                  prob = weight)), 
               by = .(variable) ]
    
    
    #    variable      sim
    # 1:        1 69.02905
    # 2:        1 30.77661
    # 3:        1 37.03205
    # 4:        1 35.75249
    # 5:        1 48.37707
    # 6:        1 55.23224
    

    【讨论】:

    • “.(”在您过滤答案时有什么作用?
    【解决方案2】:

    在基础 R 中,我们可以将 "smp" 和重量的列分开,并使用 mapply(顺便说一句,在内部仍然是一个循环)来采样值。

    sample_col <- grep("^smp", names(x))
    weigth_col <- grep("^weight", names(x))
    
    mapply(function(p, q) sample(p, size = 1000, replace = TRUE, prob = q), 
                           x[,sample_col], x[,weigth_col])
    
    
    #          smp_1     smp_2
    # [1,] 62.499648 74.148250
    # [2,] 88.216552 94.461613
    # [3,] 55.232243 70.369581
    # [4,] 28.035384 74.148250
    # [5,] 39.848790 76.259859
    # [6,] 39.848790 97.966850
    # [7,] 88.216552 91.922002
    # [8,] 20.461216 97.966850
    # [9,] 66.902171 53.045304
    #[10,] 54.655860 76.259859
    #...
    

    【讨论】:

      【解决方案3】:

      这是tidyverse 使用map2 的一个选项,我们将列'smp'、'weight' 子集,并使用对应的'weight' 到sample 'smp' 列

      library(tidyverse)
      map2_df(x %>% 
                dplyr::select(matches("^smp")), 
             x %>% 
                dplyr::select(matches("^weight")), ~ 
           sample(.x, size = 1000, replace = TRUE, prob = .y))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-05
        • 1970-01-01
        • 1970-01-01
        • 2020-02-08
        • 2012-05-31
        • 2016-04-25
        • 2023-04-10
        • 2019-03-05
        相关资源
        最近更新 更多