在磁盘上均匀生成随机点

机器算法验证 自习 模拟 蒙特卡洛 均匀分布 雅可比
2022-02-08 00:24:27

我必须在一个单位磁盘上随机生成 1000 个点,以便均匀分布在该磁盘上。现在,为此,我选择一个半径和角方向,使得半径是一个来自的均匀分布变量,而是一个来自使用以下代码rαrr[0,1]αα[0,2π]

r <- runif(1000, min=0, max=1) 
alpha <- runif(1000, min=0, max=2*pi)
x <- r*cos(alpha)
y <- r*sin(alpha)
plot(x,y, pch=19, col=rgb(0,0,0,0.05), asp=1)

然后我查看我的样本空间,它看起来像这样:

样品空间_1

这显然不像磁盘上均匀分布的样本。之间缺乏独立性而导致它们在计算上是如何联系起来的。rα

为了解决这个问题,我编写了一个新代码。

rm(list=ls())
r <- runif(32, min=0, max=1)
df_res <- data.frame(matrix(c(-Inf, Inf), byrow = T, nrow = 1))
for (i in 1:32) {
  for (j in 1:32) {
    alpha <- runif(32, min=0, max=2*pi)
    r <- runif(32, min=0, max=1)
    df <- data.frame(matrix(c(r[i],alpha[j]), byrow = T, nrow = 1))
    df_res <- rbind(df_res,df)
  }
}
df_res <- subset(df_res, df_res$X1 != -Inf)
x<- df_res$X1 *cos(df_res$X2)
y <- df_res$X1 *sin(df_res$X2)
plot(x,y, pch=19, col=rgb(0,0,0,0.05), asp=1)

而且,该样本再次看起来在磁盘上分布不均匀

样品空间_2

我开始怀疑附近有更深层次的数学问题。有人可以帮我编写代码来创建一个均匀分布在磁盘上的样本空间,或者在我的推理中解释数学谬误吗?

3个回答

问题是由于半径不是均匀分布的。即如果均匀分布在 上,则变量的(极坐标)变化 的密度为 使用导致 因此,角度均匀分布在(X,Y)

{(x,y); x2+y21}
R=(X2+Y2)1/2A=sign(Y)arccos(X/R)
1πI(0,1)(r)|d(X,Y)d(R,A)(r,α)|I(0,2π)(α)
x=rcosαy=rsinα
|d(X,Y)d(R,A)(r,α)|=r(sin2α+cos2α)=r
A(0,2π)但是半径在(0,1)上具有密度和 cdf正如一个可以通过运行检查Rf(r)=2rI(0,1)(r)F(r)=r2(0,1)

r <- sqrt(runif(1000, min=0, max=1) )
alpha <- runif(1000, min=0, max=2*pi)
x <- r*cos(alpha)
y <- r*sin(alpha)
plot(x,y, pch=19, col=rgb(0,0,0,0.05), asp=1)

其中半径由逆 cdf 表示模拟,这使其成为 Uniform 变量的平方根,10³ 模拟点的随机重新分配与统一兼容:

在此处输入图像描述

最简单且最不容易出错的方法是拒绝采样:在圆圈周围的正方形中生成均匀分布的点,并且只保留那些在圆圈中的点。

圆圈

nn <- 1e4
radius <- 1
set.seed(1) # for reproducibility
foo <- cbind(runif(nn,-radius,radius),runif(nn,-radius,radius))
plot(foo[rowSums(foo^2)<radius^2,],pch=19,cex=0.6,xlab="x",ylab="y")

当然,您只会保留一小部分生成的数据点,大约π4(即外接正方形与圆盘的面积之比)。所以你可以从4nπ积分,或生成积分,直到您保持目标数量n其中。

您可以在此处的相关问题中找到这种情况的数学计算方法在西安的优秀答案中有所阐述,可以总结为以下要求:

R2U(0,1)  X=Rcos(θ),θU(0,2π)Y=Rsin(θ).

继另一个答案之后,当您提出这些解决方案时,尝试将它们概括为可以为特定类别的问题生成随机值的函数通常很有用。在这种情况下,一个自然的概括是查看具有任意中心和半径的圆上随机生成的点。使用与现有答案相同的基本方法,这是一个通用函数,可以在具有任意中心和半径的圆上均匀地生成随机点。

runifcircle <- function(n, centre = c(0, 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
  OUT      <- matrix(0, nrow = 2, ncol = n)
  rownames(OUT) <- c('x', 'y')
  
  #Generate uniform values on circle
  r2       <- runif(n, min = 0, max = radius^2)
  theta    <- runif(n, min = 0, max = 2*pi)
  OUT[1, ] <- center[1] + sqrt(r2)*cos(theta)
  OUT[2, ] <- center[2] + sqrt(r2)*sin(theta)
  
  OUT }

创建此函数可让您轻松地在任意圆上生成任意数量的点。(如果您想要扩展这个问题的有趣练习,请尝试修改上述函数以创建一个新函数,该函数在具有任意中心和半径的超球runifball面上生成均匀随机值。)我们可以通过绘制大量样本值的结果。

#Generate points uniformly on a circle
set.seed(1)
n      <- 10^5
CENTRE <- c(5, 3)
RADIUS <- 3
UNIF   <- runifcircle(n, centre = CENTRE, radius = RADIUS)

#Plot the points
plot(UNIF[1, ], UNIF[2, ], 
     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)

在此处输入图像描述