【问题标题】:Selecting a random number within a range with a discontinuity in R在R中不连续的范围内选择一个随机数
【发布时间】:2018-07-13 06:23:57
【问题描述】:

我想生成一个介于 0 和 1 之间但不在 0.4 和 0.6 之间的随机数。在 R 中有没有比以下更好的方法来做到这一点?

sample(c(runif(1,0,.4), runif(1,.6,1)), 1, prob=c(.5,.5))

【问题讨论】:

标签: r random


【解决方案1】:

与 TC Zhang 类似,但快了大约 3 倍(因为 ifelse 很慢):

mysample_axe <- function(n = 1){
    tmp <- runif(n, max = 0.8)
    tmp + (tmp > 0.4) * 0.2
}

对比 TC Zhang (mysample) 和 Cath (samp_runif):

microbenchmark::microbenchmark(mysample(1e5), mysample_axe(1e5), samp_runif(1e5))
Unit: milliseconds
                expr       min        lq      mean    median        uq       max neval cld
     mysample(1e+05) 12.684764 13.193528 17.313560 13.420470 19.692859 130.23693   100   c
 mysample_axe(1e+05)  4.897770  5.159778  5.751177  5.187718  5.218367  14.60607   100 a  
   samp_runif(1e+05)  7.615363  8.101890  9.266797  8.139951  8.194121  25.44451   100  b
ggplot2::qplot(mysample_axe(1e5), breaks = I(seq(0, 1, 0.02)))

【讨论】:

    【解决方案2】:

    从任何分布中抽取随机数的基本思路是inverse transform sampling。

    mysample <- function(n = 1){
      tmp <- runif(n)
      ifelse (tmp > 0.5, 0.8 * tmp + 0.2, 0.8 * tmp)
    }
    
    library(ggplot2)
    ## A density plot for confirmation
    df <- data.frame(x= mysample(1000000))
    
    gg <- ggplot(df, aes(x=x)) +
      geom_density()
    
    gg
    

    由reprex package (v0.2.0.9000) 于 2018 年 7 月 10 日创建。

    【讨论】:

      【解决方案3】:

      您可以在 [0,1] 上对均匀分布进行采样,直到您使用递归函数在约束后有一个数字(它比 @Axeman 解决方案慢两倍):

      samp_runif <- function(n){
          x <- runif(n, 0, 1)
          wh_pb <- which(x>0.4 & x<0.6)
          if(length(wh_pb)){x[wh_pb] <- samp_runif(length(wh_pb)) ; return(x)} else return(x)
      }
      
      samp_runif(5)
      # [1] 0.3633319 0.9586853 0.6766313 0.6903275 0.8090996
      

      可视化:

      test <- samp_runif(1e6)
      plot(density(test))
      


      概括:

      您可以修改上述函数以将阈值(示例中为 0.4 和 0.6)作为参数,下限和上限(示例中分别为 0 和 1)相同:

      samp_runif <- function(n, a=0.4, b=0.6){
          x <- runif(n, 0, 1)
          wh_pb <- which(x>a & x<b)
          if(length(wh_pb)){x[wh_pb] <- samp_runif(length(wh_pb), a=a, b=b) ; return(x)} else return(x)
      }
      samp_runif(5, 0.2, 0.8)
      #[1] 0.80316178 0.99624724 0.89554995 0.05928052 0.17771131
      

      【讨论】:

        【解决方案4】:

        是的,这个想法完全是个废话,所以我删除了它。感谢 Axeman 提供有用的反馈。

        这是另一个想法(这次经过更好的测试):

        fx <- function() {y <- runif(1); if (y > 0.4 & y < 0.6) fx() else y}
        

        与其纠正 0.4 和 0.6 之间的值,不如换一个。

        【讨论】:

        • 是的,这基本上是 Cath 的解决方案。
        • 在R中,最好使用Recall递归调用函数。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-09
        • 1970-01-01
        • 1970-01-01
        • 2020-07-14
        • 1970-01-01
        相关资源
        最近更新 更多