使用示例功能删除for循环

时间:2019-05-09 13:16:17

标签: r

我具有以下数据结构:

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的多列,所以我需要很快。

3 个答案:

答案 0 :(得分:2)

这是一种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

答案 1 :(得分:0)

在基数R中,我们可以将"smp"和weigths的列分开,并使用mapply(BTW在内部仍然是一个循环)来采样值。

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
#...

答案 2 :(得分:0)

这里是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))