我一直在编写一些代码,迭代地执行二项式绘制(使用rbinom
),对于一些被调用者的参数,我最终可能会大到大,导致R(3.1.1,这两个官方或者自制软件构建测试 - 因此不太可能与编译器相关)返回意外的NA
。例如:
rbinom(1,2^32,0.95)
是我期望的工作方式,但是会回复NA
。但是,使用size=2^31
或prob≤0.5
运行。
当size < .Machine$integer.max
为假时,使用精细的手册提到反转,这可能是问题吗?
答案 0 :(得分:4)
查看the source rbinom
对于如此大的尺寸执行以下等效(在C代码中):
qbinom(runif(n), size, prob, FALSE)
确实:
set.seed(42)
rbinom(1,2^31,0.95)
#[1] 2040095619
set.seed(42)
qbinom(runif(1), 2^31, 0.95, F)
#[1] 2040095619
然而:
set.seed(42)
rbinom(1,2^32,0.95)
#[1] NA
set.seed(42)
qbinom(runif(1), 2^32, 0.95, F)
#[1] 4080199349
@BenBolker指出rbinom
返回一个整数,如果返回值大于.Machine$integer.max
,例如,我的机器上大于2147483647
,则返回NA
。相反,qbinom
返回一个双精度数。我不知道为什么,似乎没有记录。
因此,似乎至少存在无证件行为,您应该报告它。
答案 1 :(得分:2)
我同意(在没有文件证明这是一个问题的情况下),这是一个错误。一个合理的解决方法是使用Normal近似,对于如此大的值,它应该非常非常好(并且更快)。 (我本来的意思是简短而简单,但结果有点失控。)
rbinom_safe <- function(n,size,prob,max.size=2^31) {
maxlen <- max(length(size),length(prob),n)
prob <- rep(prob,length.out=maxlen)
size <- rep(size,length.out=maxlen)
res <- numeric(n)
bigvals <- size>max.size
if (nbig <- sum(bigvals>0)) {
m <- (size*prob)[bigvals]
sd <- sqrt(size*prob*(1-prob))[bigvals]
res[bigvals] <- round(rnorm(nbig,mean=m,sd=sd))
}
if (nbig<n) {
res[!bigvals] <- rbinom(n-nbig,size[!bigvals],prob[!bigvals])
}
return(res)
}
set.seed(101)
size <- c(1,5,10,2^31,2^32)
rbinom_safe(5,size,prob=0.95)
rbinom_safe(5,3,prob=0.95)
rbinom_safe(5,2^32,prob=0.95)
当平均值远离0或1(以较近者为准)的许多标准差时,法线近似应该相当好。对于大N,这应该没问题,除非p 非常极端。例如:
n <- 2^31
p <- 0.95
m <- n*p
sd <- sqrt(n*p*(1-p))
set.seed(101)![enter image description here][1]
rr <- rbinom_safe(10000,n,prob=p)
hist(rr,freq=FALSE,col="gray",breaks=50)
curve(dnorm(x,mean=m,sd=sd),col=2,add=TRUE)
dd <- round(seq(m-5*sd,m+5*sd,length.out=101))
midpts <- (dd[-1]+dd[-length(dd)])/2
lines(midpts,c(diff(sapply(dd,pbinom,size=n,prob=p))/diff(dd)[1]),
col="blue",lty=2)
答案 2 :(得分:2)
这是预期的行为,但有两个问题: 1)胁迫引起的NA应该发出警告 2)应记录离散随机变量具有存储模式整数的事实。
我已修复1)并将修改文档以修复2)当我有更多时间。