在R中使用rbinom的 Bootstrap 运行时间过长

8iwquhpp  于 2022-12-25  发布在  Bootstrap
关注(0)|答案(1)|浏览(173)

我一直在用rbinom为r中的循环运行 Bootstrap ,但是它们运行的时间太长了。
我想对一个包含1,500,000行的数据集执行引导。
我想对行和进行重新采样,对于每个重新采样的行
1.将两个概率("prob1"和"prob2")归为0和1("prob1_ber"和"prob2_ber")
1.添加新列"配对",其中包含步骤1的合并结果

  1. rbinom将列"paired"和"positive"的唯一组合分为0和1('prob_final')
    1.计算"配对FPR"和"配对TPR"
    下面是我的代码:
library(boot)

#making example data
set.seed(1)
d2 <- data.frame(prob1=runif(n=1500000, min=1e-50, max=.9999999999),
                 prob2=runif(n=1500000, min=1e-44, max=.9999999989),
                 Positive=sample(c(0,1), replace=TRUE, size=1500000))

#making bootstrap function
function_1 <- function(data, i){
  d2<-data[i,]
  
  d2$prob1_ber <- rbinom(nrow(d2), 1, d2$prob1) #bernoulli 1 or 0
  d2$prob2_ber <- rbinom(nrow(d2), 1, d2$prob2) #bernoulli 1 or 0
  
  d2$paired <- ifelse(d2$prob1_ber == 1 & d2$prob2_ber == 1, '11',
                      ifelse(d2$prob1_ber == 0 & d2$prob2_ber ==0, '00',
                             ifelse(d2$prob1_ber == 1 & d2$prob2_ber ==0, '10',
                                    ifelse(d2$prob1_ber == 0 & d2$prob2_ber ==1, '01', NA)))) 
  
  d2$prob_final <- ifelse(d2$paired == '00',d2$prob1_ber, NA) #if both negative then negative
  
  for (i in which(d2$paired =='11' & d2$Positive==1)) {
    d2$prob_final[i] <- rbinom(1,1,0.9)
  }
  for (i in which(d2$paired =='11' & d2$Positive==0)) {
    d2$prob_final[i] <- rbinom(1,1,0.5)
  }
  for (i in which(d2$paired =='01' & d2$Positive==1)) {
    d2$prob_final[i] <- rbinom(1,1,0.8)
  }
  for (i in which(d2$paired =='01' & d2$Positive==0)) {
    d2$prob_final[i] <- rbinom(1,1,0.1)
  }
  for (i in which(d2$paired =='10' & d2$Positive==1)) {
    d2$prob_final[i] <- rbinom(1,1,0.7)
  }
  for (i in which(d2$paired =='10' & d2$Positive==0)) {
    d2$prob_final[i] <- rbinom(1,1,0.2)
  }
  
  pair_FPR <- sum(d2[which(d2$Positive==0),]$prob_final) / nrow(d2[which(d2$Positive==0),])*100
  
  pair_TPR <- sum(d2[which(d2$Positive==1),]$prob_final) / nrow(d2[which(d2$Positive==1),])*100
  
  return(c(pair_FPR, pair_TPR))
}

set.seed(1)
boot_out <- boot(d2, function_1, 1000)
print(boot_out)

这个 Bootstrap 运行时间太长(n = 1000)。有没有办法让它更快?
非常感谢!

fnx2tebb

fnx2tebb1#

有一个很好的理由说“如果你正在使用R,并且考虑使用for循环,可能有一个更好的方法来做它”,我认为这是一个很好的例子。
你没有给出你的总体目标的上下文或描述,我也没有花时间去理解你的代码。我也很困惑为什么你在某些地方利用了R的矢量化,而在其他地方却没有。
另外,我认为使用boot库是一个转移注意力的问题。重要的是函数function_1的底层性能。最后,我认为没有必要生成150,000,000个观测值--甚至1,500,000个--来调查底层性能。
因此,我尝试改进您的功能:

function_2 <- function(data, i){
  d2<-data[i,] %>% 
    mutate(
      prob1_ber=rbinom(nrow(.), 1, prob1), #bernoulli 1 or 0
      prob2_ber=rbinom(nrow(.), 1, prob2), #bernoulli 1 or 0
      paired=ifelse(prob1_ber == 1 & prob2_ber == 1, '11',
                      ifelse(prob1_ber == 0 & prob2_ber ==0, '00',
                             ifelse(prob1_ber == 1 & prob2_ber ==0, '10',
                                    ifelse(prob1_ber == 0 & prob2_ber ==1, '01', NA)))), 
      dprob_final=case_when(
        paired == '00' ~ prob1_ber,
        paired =='11' & Positive==1 ~ rbinom(1,1,0.9),
        paired =='11' & Positive==0 ~ rbinom(1,1,0.5),
        paired =='01' & Positive==1 ~ rbinom(1,1,0.8),
        paired =='01' & Positive==0 ~ rbinom(1,1,0.1),
        paired =='10' & Positive==1 ~ rbinom(1,1,0.7),
        paired =='10' & Positive==0 ~ rbinom(1,1,0.2)
    )
  )
  
  pair_FPR <- sum(d2[which(d2$Positive==0),]$prob_final) / nrow(d2[which(d2$Positive==0),])*100
  
  pair_TPR <- sum(d2[which(d2$Positive==1),]$prob_final) / nrow(d2[which(d2$Positive==1),])*100
  
  return(c(pair_FPR, pair_TPR))
}

我的测试数据是

N <- 15000
#making example data
set.seed(1)
d2 <- data.frame(prob1=runif(n=N, min=1e-50, max=.9999999999),
                 prob2=runif(n=N, min=1e-44, max=.9999999989),
                 Positive=sample(c(0,1), replace=TRUE, size=1500000))

注意function_1(d2, i)的结果与function_2(d2, i)的结果不同,这是因为随机数产生的 * 顺序 *。(function_2从第1行到第n行按顺序工作,function_1 works through rows in groups defined byand为正。)然而,我相信这两个函数的分布性质是相同的。
因此,为了比较性能...

library(microbenchmark)

microbenchmark(
  list=list(
         "f1"= function_1(d2, 1), 
         "f2"= function_2(d2, 1)
       ), 
  times=10
)
Unit: nanoseconds
 expr min lq mean median uq max neval
   f1   7  9 28.7      9  9 203    10
   f2   8  9  8.9      9  9  10    10

执行时间平均相对减少100 *(27.7 - 8.9)/ 27.7 = 67.8%。相对性能可能很大程度上取决于N,但我预计N的好处会增加,因为矢量化相对于循环的好处会随着N的增加而增加。
请记住,使用tidyverse,虽然给出的代码通常易于阅读和维护,但通常不会给予最快的执行时间。data.table和base R通常上级。
我让别人来改进我的努力。我相信这是可以做到的。

相关问题