在一个内部生成统一的点米m-维球
机器算法验证
r
模拟
均匀分布
功能
2022-03-26 05:42:41
2个回答
解决这个问题的一种简单有效的方法是使用著名的Box-Mueller 变换的变体,它将正态分布与球上的均匀分布联系起来。如果我们生成一个由 IID 标准正态随机变量和一个随机变量(独立于第一个随机向量),那么我们可以将统一的兴趣点构造为:
在下面的代码中,我们创建了一个实现此方法的R函数。runifball该功能允许用户生成n随机矢量,这些矢量是球上具有任意中心、半径和尺寸的点。
runifball <- function(n, centre = 0, center = centre, radius = 1) {
#Check inputs
if (!missing(centre) && !missing(center)) {
if (sum((centre - center)^2) < 1e-15) {
warning("specify 'centre' or 'center' but not both") } else {
stop("Error: specify 'centre' or 'center' but not both") } }
if (radius < 0) { stop("Error: radius must be non-negative") }
#Create output matrix
m <- length(center)
OUT <- matrix(0, nrow = m, ncol = n)
rownames(OUT) <- sprintf("x[%s]", 1:m)
#Generate uniform values on circle
UU <- runif(n, min = 0, max = radius)
ZZ <- matrix(rnorm(n*m), nrow = m, ncol = n)
for (i in 1:n) {
OUT[, i] <- center + radius*UU[i]^(1/m)*ZZ[, i]/sqrt(sum(ZZ[, i]^2)) }
OUT }
这是一个使用此函数在二维磁盘上均匀生成随机点的示例。该图显示,这些点在指定球上确实是均匀的。
#Generate points uniformly on a disk
set.seed(1)
n <- 10^5
CENTRE <- c(5, 3)
RADIUS <- 3
UNIF <- runifball(n, centre = CENTRE, radius = RADIUS)
#Plot the points
plot(UNIF,
col = rgb(0, 0, 0, 0.05), pch = 16, asp = 1,
main = 'Points distributed uniformly over a circle', xlab = 'x', ylab = 'y')
points(x = CENTRE[1], y = CENTRE[2], col = 'red', pch = 16)
最简单且最不容易出错的方法 - 对于低维(见下文!) - 仍然是拒绝采样维超立方体中挑选均匀分布的点,然后拒绝所有落在球外的点。
runifball <- function(n, centre = 0, center = centre, radius = 1) {
#Check inputs
if (!missing(centre) && !missing(center)) {
if (sum((centre - center)^2) < 1e-15) {
warning("specify 'centre' or 'center' but not both") } else {
stop("Error: specify 'centre' or 'center' but not both") } }
if (radius < 0) { stop("Error: radius must be non-negative") }
n_to_generate <- 2^length(center)*gamma(length(center)/2+1)*n/pi^(length(center)/2) # see below
original_sample_around_origin <-
matrix(replicate(length(center),runif(n_to_generate ,-radius,radius)),nrow=n_to_generate )
index_to_keep <- rowSums(original_sample_around_origin^2)<radius^2
original_sample_around_origin[index_to_keep,]+
matrix(center,nrow=sum(index_to_keep),ncol=length(center),byrow=TRUE)
}
这是维磁盘的应用程序:
#Generate points uniformly on a disk
set.seed(1)
n <- 10^5
CENTRE <- c(5, 3)
RADIUS <- 3
UNIF <- runifball(n, centre = CENTRE, radius = RADIUS)
#Plot the points
plot(UNIF,
col = rgb(0, 0, 0, 0.05), pch = 16, asp = 1,
main = 'Points distributed uniformly over a circle', xlab = 'x', ylab = 'y')
points(x = CENTRE[1], y = CENTRE[2], col = 'red', pch = 16)
再一次,我们将需要最初生成更多的点,因为我们会拒绝一些。具体来说,我们希望保持,即维球到包围它维超立方体的体积。所以我们可以从生成开始,期望得到个点(这是上面代码采用的方法),或者只是开始生成直到我们保留。
在任何一种情况下,我们最初需要在超立方体中绘制的点数,以便(期望)最终在球中得到一个点,随着维数的增加而迅速增加:
(注意对数垂直轴!)
m <- 2:20
plot(m,2^m*gamma(m/2+1)/pi^(m/2),type="o",pch=19,log="y",
xlab="Dimension (m)")
这只是一个事实的结果,对于大,维超立方体的大部分体积在角落,而不是在中心(球所在的位置)。所以拒绝抽样可能只是低维度的一种选择。
其它你可能感兴趣的问题


