【问题标题】:ifelse function instead of for loopifelse 函数而不是 for 循环
【发布时间】:2018-11-24 10:19:55
【问题描述】:

我有如下的原始 R 代码。

 Bernoulli <- rbinom(1000, 1, 0.5)
 mix.sample <- rep(0, 1000)  #reserve storage
 for (i in 1:1000) { #for each Bernoulli realization
   if (Bernoulli[i] == 1){ #sample corresponding normal component
     mix.sample[i] <- rnorm(1, mean=10, sd=1)
   }
   else {
     mix.sample[i] <- rnorm(1, mean=0, sd=1)
   }
 }
 plot(density(mix.sample))

我尝试了以下代码而不是 for 循环,但生成的结果似乎有问题,有人可以帮我吗?

 Bernorm <- ifelse(Bernoulli == 1, rnorm(1, mean=10, sd=1), rnorm(1, mean=0, sd=1))

【问题讨论】:

    标签: r for-loop if-statement


    【解决方案1】:

    您可以使用 for 循环代替

    set.seed(42)
    sim.fun <- function(x) {
      if (x == 1) {
        rnorm(1, 10, 1)
      } else {
        rnorm(1, 0, 1)
      }
    }
    
    P <- sapply(Bernoulli, sim.fun)
    plot(density(P))
    

    或者,如果您依赖 ifelse(),请将其与 sapply() 一起使用:

    P <- sapply(Bernoulli, function(x) ifelse(x == 1, rnorm(1, 10, 1), rnorm(1, 0, 1)))
    

    虽然功能更快。

    microbenchmark() 产生:

    Unit: milliseconds
        expr      min       lq     mean   median       uq      max neval cld
    for-loop 8.015976 8.232972 8.712522 8.316147 8.475865 14.65216   100   c
     sim.fun 3.622982 3.672990 4.493131 3.700290 3.752339 54.14139   100 a  
      sapply 5.932761 6.016319 6.479058 6.070026 6.115951 12.38065   100  b 
    

    【讨论】:

      【解决方案2】:

      就我个人而言,我认为您可以立即将Binomial 转换为logical

        Bernoulli <- as.logical(rbinom(1e3, 1, 0.5))
        samp <- numeric(1e3)
        n <- sum(Bernoulli)
        samp[Bernoulli] <- rnorm(n, 10, 1)
        samp[!Bernoulli] <- rnorm(1e3 - n)
        samp
      

      【讨论】:

        【解决方案3】:

        就像您一次创建整个测试向量 (rbinom) 一样,您可以一次创建两个 rnorm 向量的所有值。将所有内容放在一个矩阵中,使用测试向量的值选择两个值列中的任何一个。

        set.seed(1)
        n <- 8
        m <- cbind(test = rbinom(n, 1, 0.5),
                   norm0 = rnorm(n, mean = 0, sd = 1),
                   norm10 = rnorm(n, mean = 10, sd = 1))
        
        m <- cbind(m, res = m[cbind(1:nrow(m), (m[ , "test"] == 1) + 2)])
        #     test      norm0    norm10        res
        # [1,]   0  0.3295078  9.378759  0.3295078
        # [2,]   0 -0.8204684  7.785300 -0.8204684
        # [3,]   1  0.4874291 11.124931 11.1249309
        # [4,]   1  0.7383247  9.955066  9.9550664
        # [5,]   0  0.5757814  9.983810  0.5757814
        # [6,]   1 -0.3053884 10.943836 10.9438362
        # [7,]   1  1.5117812 10.821221 10.8212212
        # [8,]   1  0.3898432 10.593901 10.5939013
        # [10,]  0  1.1249309 10.619826  1.1249309  
        

        【讨论】:

          【解决方案4】:

          另一种选择是将值放入数据框中,然后使用 ifelse 添加变量,就像您在开始时尝试的那样。在这里,我也只是绘制了数据,但您可以将其分配回以存储值。

          library(tidyverse)
          
          set.seed(81)
          df <- data_frame(Bernoulli = rbinom(1000, 1, 0.5))
          
          df %>% 
            mutate(mix.sample = if_else(Bernoulli == 1, 
                                        rnorm(1, mean=10, sd=1), 
                                        rnorm(1, mean=0, sd=1))) %>%
            ggplot(aes(mix.sample))+
            geom_density()+
            scale_x_continuous(limits = c(-5, 15))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-10
            • 1970-01-01
            • 2016-11-17
            相关资源
            最近更新 更多