如何生成满足和为1、带上下限的均匀分布三元随机概率?
带边界约束的三概率均匀分布生成问题
需求与现有实现问题
需要生成三个随机概率值 (p_1, p_2, p_3),满足:
- 三者之和为1:(p_1 + p_2 + p_3 = 1)
- 每个概率服从指定范围的均匀分布:示例中 (p_1 \sim U(0.25, 0.75)),(p_2 \sim U(0.25, 0.75)),(p_3 \sim U(0.00, 0.25))
现有R代码实现了约束条件,但生成的(p_2)与(p_3)分布呈左偏:
n_draws <- 1e5 set.seed(1) p <- data.frame(p1 = runif(n_draws, 0.25, 0.75)) p$p2 <- runif(n_draws, ifelse(p$p1 >= 0.5, 0.25, 0.75 - p$p1), 1 - p$p1) p$p3 <- 1 - (p$p1 + p$p2)
核心问题:如何高效生成满足约束、且每个概率在可行域内服从均匀分布的样本?
可行解决方案
问题本质分析
三个概率满足(p_1+p_2+p_3=1),因此只需考虑(p_1)和(p_2)的二维可行区域((p_3=1-p_1-p_2)可直接推导)。我们需要在这个二维多边形区域内生成均匀分布的点,才能保证三个概率在各自可行范围内的分布均匀。
方法1:多边形区域均匀采样(高效且分布均匀)
利用空间采样工具直接在可行多边形内生成均匀点,步骤如下:
- 确定可行区域的顶点:根据示例的约束,推导得到(p_1-p_2)平面的可行多边形顶点为((0.25,0.5))、((0.25,0.75))、((0.5,0.75))、((0.75,0.25))、((0.5,0.25))、((0.25,0.5))。
- 使用
sf包生成多边形内的均匀随机点:
library(sf) n_draws <- 1e5 set.seed(1) # 定义可行区域顶点 vertices <- matrix( c(0.25,0.5, 0.25,0.75, 0.5,0.75, 0.75,0.25, 0.5,0.25, 0.25,0.5), ncol=2, byrow=TRUE ) # 创建多边形对象 poly <- st_polygon(list(vertices)) # 在多边形内生成均匀随机点 points <- st_sample(poly, size = n_draws, type = "random") # 转换为概率数据框 p_valid <- data.frame( p1 = st_coordinates(points)[,1], p2 = st_coordinates(points)[,2] ) p_valid$p3 <- 1 - p_valid$p1 - p_valid$p2
该方法生成的样本严格满足所有约束,且(p_1,p_2,p_3)在各自可行范围内服从均匀分布,解决了原代码的分布偏斜问题。
方法2:拒绝采样(简单易实现)
如果不想依赖空间包,可采用拒绝采样:先生成满足单个边界的样本,再筛选出满足和为1的有效样本。代码示例:
n_draws <- 1e5 set.seed(1) p_valid <- data.frame(p1 = numeric(0), p2 = numeric(0), p3 = numeric(0)) # 循环生成直到获得足够有效样本 while(nrow(p_valid) < n_draws) { # 生成单个边界内的样本 temp <- data.frame( p1 = runif(n_draws, 0.25, 0.75), p2 = runif(n_draws, 0.25, 0.75), p3 = runif(n_draws, 0.00, 0.25) ) # 筛选满足和为1的样本(容忍浮点误差) valid_idx <- abs(temp$p1 + temp$p2 + temp$p3 - 1) < 1e-6 p_valid <- rbind(p_valid, temp[valid_idx, ]) } # 截取目标数量的样本 p_valid <- p_valid[1:n_draws, ]
该方法逻辑简单,但拒绝率较高(示例中可行域占总采样空间比例低),效率不如多边形采样方法。
原代码问题说明
原代码先固定(p_1)的均匀分布,再根据(p_1)的取值动态调整(p_2)的采样范围。由于不同(p_1)对应的(p_2)可行区间长度不同,最终导致(p_2)和(p_3)的整体分布偏斜,无法实现真正的均匀分布。
内容的提问来源于stack exchange,提问作者altfi_SU
相关产品推荐
相关产品推荐

