如何在python或R中均匀地生成半圆内的一组随机点?

时间:2019-03-25 08:07:07

标签: python r numpy

我试图在半圆内均匀地生成一组点。

size = 1000
t  = np.random.random(size)*np.pi*2
u  = np.random.random(size) + np.random.random(size)
r = np.where(u > 1, 2 - u, u)
x = r*cos(t)
y = r*sin(t)
coor = (x,y)
for idx, value in enumerate(y):
    if value<0:
        x[idx]=-3
        y[idx]=-3
f, ax = plt.subplots(figsize = (3,3))
plt.scatter(x, y)

这段代码有2个错误。

  1. 该地块有很多(-3,-3)点需要删除
  2. 它似乎效率低下。

由于点比其他点更位于中心,因此以下所示的图不是统一的。

enter image description here

另一个如下所示的图可以看作是统一的。

enter image description here

任何解决错误的想法都会受到赞赏。

6 个答案:

答案 0 :(得分:6)

您应生成均匀分布的角度phi,并考虑均匀生成的半径sqrt的{​​{1}}(考虑到我们要在区域均匀采样< / em>,请参见下面的说明),以确保您在半圆上均匀地采样点。

r

Uniform samples in a cirlce

说明

要在(半)圆上生成均匀分布的点,我们必须确保每个无限小区域或线段都以相同的概率“命中”。我们可以简单地从均匀随机分布import numpy as np import matplotlib.pyplot as plt # sample size = 10000 R = 1 phi = np.random.random(size=size) * np.pi r = np.sqrt(np.random.random(size=size)) * R # transform x = r * np.cos(phi) y = r * np.sin(phi) # plot f = plt.figure(figsize=(12,12)) a = f.add_subplot(111) a.scatter(x, y, marker='.') a.set_aspect('equal') plt.show() 乘以phi(所以[0, 1))中抽取np.pi,因为所有角度都应具有相同的概率被采样。但是,如果我们从[0, pi)中的均匀随机分布中采样r,则由于 area 的生长像{ {1}}。考虑到这一事实,我们必须相应地对采样的半径进行偏置,在这种情况下,我们可以通过简单地取平方根([0, 1))来应用偏置,以将正确的权重应用于采样的半径值,并考虑到较大的外圈面积。

在这里可以找到更好,更详尽的解释:https://stackoverflow.com/a/50746409/1170207

性能与拒绝采样方法的比较

由于此方法基本上是一种反转采样方法,因此我们对其进行比较 性能的拒绝采样算法。

r**2

使用拒绝抽样方法,我们还不能确保我们选择一定数量的变量,因此我们必须重复该过程,直到有了为止。除非我们接受对太多的值进行采样并丢弃其他值,否则不能很好地将其向量化。

答案 1 :(得分:2)

在R中:

runif_in_semicircle <- function(n, radius=1){
  theta <- runif(n, 0, pi)
  r <- radius * sqrt(runif(n))
  cbind(r*cos(theta), r*sin(theta))
}

sims <- runif_in_semicircle(1000)
plot(sims[,1], sims[,2], asp=1, pch=19)

enter image description here

我们可以通过评估一个积分来检查它是否有效。

# integrand example
f <- function(x) x[1]^2 + exp(x[2])

set.seed(666)
sims <- runif_in_semicircle(10000)
fsims <- apply(sims, 1, f)
mean(fsims)*pi/2 # approximates the integral of f over the half-disk
# 2.890905

现在,我们用数字评估f的积分。

library(SphericalCubature)
adaptIntegrateBallPolar(f, n=2, lowerLimit = 0, upperLimit = pi)
# $integral
# [1] 2.880598

答案 2 :(得分:1)

您应该在封闭的矩形中生成点,并删除不在半圆中的点

# generate about n points in a half-circle with
# given center (x, y) and given radius, and y>0

points <- function(x, y, radius, n) {
    n2 = n * 4 / pi # each point has pi/4 probability to survive

    # make [-1, 1] * [-1, 1] square
    xs = runif(n2, -1, 1)
    ys = runif(n2, 0, 1)  # or just runif(n2)
    points = cbind(xs, ys)

    # keep only points in circle with center (0,0) and radius 1 with y>0
    ind = (xs**2 + ys**2 <= 1) # the condition ys>=0 is obeyed already
    points = points[ind,]

    # move/stretch to given center and radius
    points = points * radius
    points[,1] = points[,1] + x
    points[,2] = points[,2] + y
}

# generate about 1000 points with center(1,1) and radius 3
points = f(1, 1, 3, 1000)

# plot them, making them smaller for better visibility
plot(points, cex=0.3)

答案 3 :(得分:0)

您可以在R中尝试以下方法:

size <- 1000
maxRad <- 1 #maximum radius of the half-circle
r <- runif(1000,0,maxRad) #generate random radius
phi <- runif(size,0,pi) #generate angle for polarcoordinates (between 0 and pi since you want a halfcircle)
x <- r*cos(phi) #polarcoordinates
y <- r*sin(phi)
plot(x,y)

您可以将其放在函数中

halfCircle <- function(size, maxRad) {
 r <- runif(1000,0,maxRad)
 phi <- runif(size,0,1)*pi
 x <- r*cos(phi)
 y <- r*sin(phi)
 plot(x,y)
}

并尝试它是否可以为您提供“更可接受的随机”结果。

答案 4 :(得分:0)

此方法使用Python和拒绝算法。

首先在一个正方形中创建均匀分布的变量。然后拒绝所有您感兴趣的半圆之外的点。在这里,我选择了最简单的情况,但是如果您添加这些点的旋转,缩放和平移,它可以扩展到任何半圆。

代码如下:

import numpy as np
import matplotlib.pyplot as plt

n = 10000
r = 3  # radius

uniform_square = np.random.uniform(-r,r,(int(2.65*n),2))
radius = np.sqrt(uniform_square[:,0]**2 + uniform_square[:,1]**2)

uniform_circle = uniform_square[radius<=r,:]

uniform_half_circle = uniform_circle[uniform_circle[:,0]>=0,:]

final_points = uniform_half_circle[0:n,:]

fig, axs = plt.subplots(1, 1)
axs.scatter(final_points[:,0], final_points[:,1], marker='.')
axs.set_aspect('equal', 'box')
plt.show()

由于它对所有步骤都使用numpy,因此相对较快。要获得固定数量的点,请生成比您最初需要的更多的内容,并缩小数组的大小。由于我从一个完美的正方形(面积= 4)开始并且只需要一个半圆(面积= pi / 2),所以我们需要生成的点数是最后所需的大约2.6倍。

python中的for循环不是很快,因此请尝试仅使用numpy函数和操作。

答案 5 :(得分:0)

不确定您的意思是“统一”。

这是一种沿x和y轴生成“均匀”分布点的方法,但效率不高

import numpy as np
import matplotlib.pyplot as plt

x = np.random.random(size) * 2 - 1
y = np.random.random(size)
r = np.sqrt(x**2 + y**2)
x[r > 1] = -3
y[r > 1] = -3
plt.plot(x, y, 'o')
plt.show()