R 生成N个和为1的均匀随机数

R 生成N个和为1的均匀随机数,r,random-sample,R,Random Sample,我试图生成100个范围为[0.005,0.008]的均匀随机数,其和为1。我想问几个与我的担忧相关的问题,但我没有找到答案。 有人能给我一个建议吗?首先,我将稍微修改一下您的示例,假设100个变量的范围为[0.008,0.012],并且它们的总和为1(这确保了您正在采样的集合中存在可行点) 在n维空间的有界子集上均匀采样。对于你的情况,我们有n=100个维度;让我们定义相应的变量x_1,x_2,…,x_100。然后,我们有三种类型的约束来约束我们要从中采样的空间区域 变量的下限为0.008——这

我试图生成100个范围为[0.005,0.008]的均匀随机数,其和为1。我想问几个与我的担忧相关的问题,但我没有找到答案。
有人能给我一个建议吗?

首先,我将稍微修改一下您的示例,假设100个变量的范围为[0.008,0.012],并且它们的总和为1(这确保了您正在采样的集合中存在可行点)

在n维空间的有界子集上均匀采样。对于你的情况,我们有n=100个维度;让我们定义相应的变量
x_1,x_2,…,x_100
。然后,我们有三种类型的约束来约束我们要从中采样的空间区域

变量的下限为0.008——这可以通过以下线性不等式得到:

x_1 >= 0.008
x_2 >= 0.008
...
x_100 >= 0.008
x_1 <= 0.012
x_2 <= 0.012
...
x_100 <= 0.012
变量的上限为0.012——这可以通过以下线性不等式得到:

x_1 >= 0.008
x_2 >= 0.008
...
x_100 >= 0.008
x_1 <= 0.012
x_2 <= 0.012
...
x_100 <= 0.012
假设我们想要得到10组均匀分布在空间中的变量。然后我们可以按以下方式在R中使用
hitandrun
包:

library(hitandrun)
n <- 100
lower <- 0.008
upper <- 0.012
s <- 1
constr <- list(constr = rbind(-diag(n), diag(n), rep(1, n), rep(-1, n)),
               dir = rep("<=", 2*n+2),
               rhs = c(rep(-lower, n), rep(upper, n), s, -s))
samples <- hitandrun(constr, n.samples=10)
dim(samples)
# [1]  10 100
库(hitandrun)

我的想法是一步一步地生成随机数。在每一步中,要注意剩余的金额不要太大,也不要太小。在最后一步中,这些随机数随机排列:

N <- 100

lowerBound <- 0.008
upperBound <- 0.012
Sum        <- 1

X <- rep(NA,N)
remainingSum <- Sum

for (i in 1:(N-1))
{
  a <- max( lowerBound, remainingSum-(N-i)*upperBound )
  b <- min( upperBound, remainingSum-(N-i)*lowerBound )

  A <- ceiling(1e+8*a)
  B <- floor(1e+8*b)

  X[i] <- ifelse( A==B, A, sample(A:B,1)) / 1e+8

  remainingSum <- remainingSum - X[i]
}

X[N] <- remainingSum

X <- sample(X,N)

分布不完全,但几乎是均匀的。我重复了5000次计算,并将第n个样本存储在
X[,n]

所有职位加在一起:

在下限和上限附近,频率增加,但在边界之间间隔的其余部分,频率几乎恒定

下面是一个如何使分布更加均匀的想法: 将上下边界附近的一些数字组合起来,然后“将它们放到中间”:

  • 在下边界附近拾取
    x1
    ,在上边界附近拾取
    x2
    。它们的平均值约为间隔的中心
  • 绘制一个随机数
    y
    ,以便间隔中包含
    y
    x1+x2-y
  • x1
    x2
    替换为
    y
    x1+x2-y
  • 重复此操作,直到边界处的峰值消失

如果没有关于这些数字将用于什么的更多信息,问题就不明确了。通过探索一些低维的例子,我们可以看到“统一”在这里的含义不幸是模糊的。如果计划将其用于某种基于蒙特卡罗的模拟,那么得到的结果很可能没有用处

让我们看看
n=4
、约束
[210300]
和总计为
1000
的问题

我们(低效地)生成了一个匹配标准的所有离散值的详尽列表

values <- 210:300
df <- subset(expand.grid(a=values, b=values, c=values, d=values), a+b+c+d==1000)

随着维度的增加,这个问题只会变得更糟。“求和为1”要求的效果是将采样限制在N-1维超平面上,单个组件约束用于将可行子集切割成多面体(基于N维超立方体与嵌入N空间的平面的交点)

在三维空间中,子空间看起来像平面和立方体的交点;中间有六边形,两端有三角形。通过查看前两个主成分的图,可以轻松验证

> values <- 100:150; df <- subset(expand.grid(a=values, b=values, c=values), a + b + c==370); df2 <- as.data.frame(predict(princomp(df)))
> plot(df2$Comp.1, df2$Comp.2)

>值这是一个基于Metropolis Hastings的改进解决方案。请注意,我还没有用您的约束实现收敛;但是,非常接近:

simple_MH <- function(n= 100, low= 0.005, up= 0.02, max_iter= 1000000) {
  x <- runif(n, low, up)
  sum_x <- sum(x)
  iter <- 0

  if (sum_x == 1) return(x)
  else {
    while (sum_x != 1 & iter < max_iter) {
      iter <- iter + 1
      if (sum_x > 1) {
        xt <- sample(which(x > mean(x)), 1)  
      } else {
        xt <- sample(which(x < mean(x)), 1)
      }

      propose <- runif(1, low, up)
      d_prop <- dnorm(propose, 1 / n, sqrt(1/12 *(up - low)^2))
      d_xt   <- dnorm(x[xt], 1 / n, sqrt(1/12 *(up - low)^2))
      alpha <- d_prop / d_xt

      if (alpha >= 1) {
        x[xt] <- propose
        sum_x <- sum(x)
      } else {
        acc <- sample(c(TRUE, FALSE), 1, prob= c(alpha, 1-alpha))
        if (acc) {
          x[xt] <- propose
          sum_x <- sum(x)
        }
      }
    }
  }
  return(list(x=x, iter= iter))
}

# try it out:
test <- simple_MH() # using defaults (note not [0.005, 0.008])
test2 <- simple_MH(max_iter= 5e6)
R> sum(test[[1]]) # = 1.003529
R> test[[2]] # hit max of 1M iterations
R> sum(test2[[1]]) # = 0.9988
R> test2[[2]] # hit max of 5M iterations

simple\u MH假设您有100个数字,每个数字的最大值为0.008,最大和为0.8,这小于所需的和1。这里需要注意的重要一点是求和约束意味着变量不是独立的。你能更具体地说明你需要这些数字做什么吗?这似乎是一个合理的启发(比我的解决方案快得多!),但值得注意的是,它通常不会从可行的n维向量集中统一采样。要知道为什么,考虑采样100个元素与目标和1.196。根据对称性,每个元素的平均值应为0.01196(非常接近最大值),低于0.01的元素将非常罕见。但是,您的第一个元素的预期值为0.01,其值低于0.01,概率为50%。平均值是整个样本的属性,而不是单个元素。也许您希望重复实验1000000次,然后计算位置1处元素的平均值。因为数字最终被置换,所以这个平均值等于整个样本的平均值。最后的排列使位置难以区分。位置1处的“随机过程”与位置2处的“随机过程”相同,依此类推。如果你不相信它,检查它。好的,考虑一个简单的情况,n=3,界(0, 1),和2。通过积分,如果我们从满足边界和求和条件的可能(x,y,z)元组集中均匀采样,则三个值中任何一个低于0.1的概率为3%。在100k样本中,我的方法返回了3029个样本(3.029%),其中一个值低于0.1。在100k个样本中,您的方法返回10947个样本(10.947%),其中一个值低于0.1。另一个快速评论——使用
runif
a
b
之间进行统一采样会更有效。感谢您添加了关于采样统一性的讨论以及如何解决它(+1)!我认为这是一个很好的方法,因为它比我的解决方案有更好的渐近运行时间。我不确定我是否理解你为什么说
,我们可以看出“统一”在这里的意思很模糊。通常,当人们谈论从一个空间进行均匀采样时,他们的意思是,具有相同度量的每个区域都具有sa
simple_MH <- function(n= 100, low= 0.005, up= 0.02, max_iter= 1000000) {
  x <- runif(n, low, up)
  sum_x <- sum(x)
  iter <- 0

  if (sum_x == 1) return(x)
  else {
    while (sum_x != 1 & iter < max_iter) {
      iter <- iter + 1
      if (sum_x > 1) {
        xt <- sample(which(x > mean(x)), 1)  
      } else {
        xt <- sample(which(x < mean(x)), 1)
      }

      propose <- runif(1, low, up)
      d_prop <- dnorm(propose, 1 / n, sqrt(1/12 *(up - low)^2))
      d_xt   <- dnorm(x[xt], 1 / n, sqrt(1/12 *(up - low)^2))
      alpha <- d_prop / d_xt

      if (alpha >= 1) {
        x[xt] <- propose
        sum_x <- sum(x)
      } else {
        acc <- sample(c(TRUE, FALSE), 1, prob= c(alpha, 1-alpha))
        if (acc) {
          x[xt] <- propose
          sum_x <- sum(x)
        }
      }
    }
  }
  return(list(x=x, iter= iter))
}

# try it out:
test <- simple_MH() # using defaults (note not [0.005, 0.008])
test2 <- simple_MH(max_iter= 5e6)
R> sum(test[[1]]) # = 1.003529
R> test[[2]] # hit max of 1M iterations
R> sum(test2[[1]]) # = 0.9988
R> test2[[2]] # hit max of 5M iterations