R概率模拟不会终止?

时间:2013-10-30 15:49:35

标签: r probability simulation

我正在教一个统计课,我让学生通过使用R的模拟来探索概率和统计学方面的问题。最近,在滚动5个骰子时获得正好两个6的可能性存在一些混淆。答案是选择(5,2)* 5 ^ 3/6 ^ 5,但有些学生确信“顺序不重要”;即答案应选择(5,2)*选择(25,3)/选择(30,5)。我认为让它们模拟滚动5个骰子数千次,跟踪每个实验的经验概率,然后多次重复实验将会很有趣。问题是上面的两个数字足够接近,很难得到模拟以统计上显着的方式梳理出差异(当然我可能只是做错了)。我尝试滚动5个骰子100000次,然后重复实验10000次。这需要一个小时左右才能在我的i7 linux机器上运行,并且仍然有25%的几率选择正确的答案(5,2)*选择(25,3)/选择(30,5)。所以我将每个实验的骰子数量增加到10 ^ 6。现在代码已运行超过2天,并且没有显示完成的迹象。我对此感到困惑,因为我只增加了一个数量级的操作次数,这意味着运行时间应该接近10小时。

第二个问题:有更好的方法吗?见下面发布的代码:

probdist = rep(0,10000)

for (j in 1:length(probdist))
{
   outcome = rep(0,1000000)
   for (k in 1:1000000)
   {
      rolls = sample(1:6, 5, replace=T)
      if (length(rolls[rolls == 6]) == 2) outcome[k] = 1
   }

   probdist[j] = sum(outcome)/length(outcome)
}

3 个答案:

答案 0 :(得分:3)

一个好的经验法则是永远不要在for 中写一个R循环。这是另一种解决方案:

doSample <- function()
{
   sum(sample(1:6,size=5,replace=TRUE)==6)==2
}

> system.time(samples <- replicate(n=10000,expr=doSample()))
user  system elapsed 
0.06    0.00    0.06 
> mean(samples)
[1] 0.1588
> choose(5,2)*5^3/6^5
[1] 0.160751

$ 10,000 $样本似乎不太准确。好的$ 100,000 $:

> system.time(samples <- replicate(n=100000,expr=doSample()))
user  system elapsed 
0.61    0.02    0.61 
> mean(samples)
[1] 0.16135

答案 1 :(得分:2)

我最初给M. Berk的正确答案检查是因为他/她建议使用R replicate()函数。进一步的调查已被迫取消我之前的认可。事实证明,replicate()只是sapply()的包装器,它实际上并没有为for循环提供任何性能优势(这似乎是一种常见的误解)。无论如何,我准备了3个版本的模拟,2个使用for循环,1个使用replicate,如建议的那样,并且每次从一个新的R会话开始一个接一个地运行它们,以便比较执行时间:

# dice26dist1.r: For () loop version with unnecessary array allocation
probdist = rep(0,100)

for (j in 1:length(probdist))
{
  outcome = rep(0,1000000)
  for (k in 1:1000000)
  {
    rolls = sample(1:6, 5, replace=T)
    if (length(rolls[rolls == 6]) == 2) outcome[k] = 1
  }
  probdist[j] = sum(outcome)/length(outcome)
}

system.time(源( 'dice26dist1.r'))
  用户系统已过 596.365 0.240 598.614

# dice26dist2.r: For () loop version
probdist = rep(0,100)

for (j in 1:length(probdist))
{
  outcomes = 0
  for (k in 1:1000000)
  {
    rolls = sample(1:6, 5, replace=T)
    if (length(rolls[rolls == 6]) == 2) outcomes = outcomes + 1
  }
  probdist[j] = outcomes/1000000
}

system.time(源( 'dice26dist2.r'))
  用户系统已过 506.331 0.076 508.104

# dice26dist3.r:  replicate() version
doSample <- function()
{
   sum(sample(1:6,size=5,replace=TRUE)==6)==2
}

probdist = rep(0,100)

for (j in 1:length(probdist))
{
  samples = replicate(n=1000000,expr=doSample())
  probdist[j] = mean(samples)
}

system.time(源( 'dice26dist3.r'))
  用户系统已过 804.042 0.472 807.250

通过任何system.time指标,您可以看到replicate()版本比任何for循环版本更慢。我原本以为我的问题主要是由于缓存未命中,分配了百万字符结果[]数组,但是比较dice26dist1.r和dice26dist2.r的时间表明这只会对性能产生名义上的影响(尽管对系统的影响很大)时间相当可观:> 300%差异。

有人可能会说我在所有三个模拟中仍然使用for循环,但据我所知,这在模拟随机过程时是完全不可避免的;我必须每次模拟实际经历随机过程(在这种情况下,滚动5个模具)。我很想知道任何可以避免使用for循环的技术(当然,这种技术可以提高性能)。我知道这个问题可以非常有效地用于并行化,但我说的是使用单个R会话 - 有没有办法让它更快?

答案 2 :(得分:2)

矢量化几乎总是优于任何for循环。在这种情况下,您应该首先通过生成所有骰子投掷,然后检查每组中五个等于6的数量来看到实质性的加速。

set.seed(5)
N <- 1e6
foo <- matrix(sample(1:6, 5*N, replace=TRUE), ncol=5)
p <- mean(rowSums(foo==6)==2)
se <- sqrt(p*(1-p)/N)
p
## [1] 0.160382

这是一个95%的置信区间:

p + se*qnorm(0.975)*c(-1,1)
## [1] 0.1596628 0.1611012

我们可以看到真正的答案(ans1)在区间内,但是错误的答案(ans2)不是,或者我们可以进行显着性测试;测试真实答案时的p值是0.31,但假答案是0.0057。

(ans1 <- choose(5,2)*5^3/6^5)
## [1] 0.160751
pnorm(abs((ans1-p)/se), lower=FALSE)*2
## [1] 0.3145898

ans2 <- choose(5,2)*choose(25,3)/choose(30,5)
## [1] 0.1613967
pnorm(abs((ans2-p)/se), lower=FALSE)*2
## [1] 0.005689008

请注意,我立即生成所有掷骰子;如果记忆是一个问题,你可以把它分成碎片并组合,就像你在原始帖子中所做的那样。这可能是导致您意外加速的原因;如果有必要使用交换内存,这将大大减慢它。如果是这样,最好增加运行循环的时间,而不是循环内的滚动次数。