Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 球形体积内均匀分布随机点的采样_Python_Matlab_Random_Geometry_Uniform Distribution - Fatal编程技术网

Python 球形体积内均匀分布随机点的采样

Python 球形体积内均匀分布随机点的采样,python,matlab,random,geometry,uniform-distribution,Python,Matlab,Random,Geometry,Uniform Distribution,我希望能够生成球形体积内粒子位置的随机均匀样本 下面的图片(由提供)显示了我正在寻找的内容。这是一个穿过球体的切片,显示了点的均匀分布: 这是我目前得到的: 您可以看到,由于球面坐标和笛卡尔坐标之间的转换,中心有一组点 我使用的代码是: def new_positions_spherical_coordinates(self): radius = numpy.random.uniform(0.0,1.0, (self.number_of_particles,1)) theta

我希望能够生成球形体积内粒子位置的随机均匀样本

下面的图片(由提供)显示了我正在寻找的内容。这是一个穿过球体的切片,显示了点的均匀分布:

这是我目前得到的:

您可以看到,由于球面坐标和笛卡尔坐标之间的转换,中心有一组点

我使用的代码是:

def new_positions_spherical_coordinates(self):
   radius = numpy.random.uniform(0.0,1.0, (self.number_of_particles,1)) 
   theta = numpy.random.uniform(0.,1.,(self.number_of_particles,1))*pi
   phi = numpy.arccos(1-2*numpy.random.uniform(0.0,1.,(self.number_of_particles,1)))
   x = radius * numpy.sin( theta ) * numpy.cos( phi )
   y = radius * numpy.sin( theta ) * numpy.sin( phi )
   z = radius * numpy.cos( theta )
   return (x,y,z)
下面是一些MATLAB代码,假设它创建了一个均匀的球形样本,这与。我似乎无法解读,也无法理解他们做了什么

function X = randsphere(m,n,r)

% This function returns an m by n array, X, in which 
% each of the m rows has the n Cartesian coordinates 
% of a random point uniformly-distributed over the 
% interior of an n-dimensional hypersphere with 
% radius r and center at the origin.  The function 
% 'randn' is initially used to generate m sets of n 
% random variables with independent multivariate 
% normal distribution, with mean 0 and variance 1.
% Then the incomplete gamma function, 'gammainc', 
% is used to map these points radially to fit in the 
% hypersphere of finite radius r with a uniform % spatial distribution.
% Roger Stafford - 12/23/05

X = randn(m,n);
s2 = sum(X.^2,2);
X = X.*repmat(r*(gammainc(s2/2,n/2).^(1/n))./sqrt(s2),1,n);
我非常感谢任何关于从Python中的球形体积生成真正统一的样本的建议

似乎有很多例子显示了如何从一个均匀的球壳中取样,但这似乎是一个更容易的问题。问题与缩放有关-半径为0.1的粒子应少于半径为1.0的粒子,以便从球体的体积生成均匀的样本


编辑:修复并删除了我通常要求的事实,我的意思是统一的。

生成一组均匀分布在立方体中的点,然后丢弃距离中心超过所需球体半径的点。

这对于您的目的是否足够统一

In []: p= 2* rand(3, 1e4)- 1
In []: p= p[:, sum(p* p, 0)** .5<= 1]
In []: p.shape
Out[]: (3, 5216)
看起来像:
您可以在(假设您在3D中工作)中生成随机点:S(r,θ,φ),其中r∈ [0,R),θ∈ [0, π ], φ ∈ [0,2π),其中R是球体的半径。这也允许您直接控制生成的点的数量(即,您不需要丢弃任何点)

为了用半径补偿密度损失,您将按照幂律分布生成径向坐标(有关如何进行此操作的说明,请参见dmckee的答案)


如果您的代码需要(x,y,z)(即笛卡尔坐标),那么您只需将球面中随机生成的点转换为笛卡尔坐标,如前所述。

为了完整性,我更喜欢球面的丢弃方法

在球坐标系中,利用:

现在有了一个
(r,θ,phi)
组,它可以按照通常的方式转换为
(x,y,z)

x = r * sin( theta) * cos( phi )
y = r * sin( theta) * sin( phi )
z = r * cos( theta )

在n维空间中,有一种在球体上均匀生成点的绝妙方法,您在问题中已经指出了这一点(我指的是MATLAB代码)

为什么它会起作用?答案是:让我们看看n维正态分布的概率密度。它是相等的(直到常数)

exp(-x_1*x_1/2)*exp(-x_2*x_2/2)..=exp(-r*r/2), 所以它不取决于方向,只取决于距离!这意味着,在归一化向量后,结果分布的密度将在整个球体上保持不变

由于该方法简单、通用、高效(且美观),因此绝对应首选该方法。 该代码在三维球体上生成1000个事件:

size = 1000
n = 3 # or any positive integer
x = numpy.random.normal(size=(size, n)) 
x /= numpy.linalg.norm(x, axis=1)[:, numpy.newaxis]
顺便说一句,好的链接是:


至于在一个球体内均匀分布,而不是规范化一个向量,你应该将vercor乘以一些f(r):f(r)*r在[0,1]上以与r^n成比例的密度分布,这是在你发布的代码中完成的规范化高斯3d向量均匀分布在球体上,请参见

例如:

N = 1000
v = numpy.random.uniform(size=(3,N)) 
vn = v / numpy.sqrt(numpy.sum(v**2, 0))

我同意Alleo的观点。我将你的Matlab代码翻译成Python,它可以非常快地生成数千个点(在我的计算机中,2D和3D的生成速度只有几分之一秒)。我甚至运行了多达5D的超球体。 我发现你的代码非常有用,因此我将其应用于一项研究。Tim McJilton,我应该添加谁作为参考?

import numpy as np
from scipy.special import gammainc
from matplotlib import pyplot as plt
def sample(center,radius,n_per_sphere):
    r = radius
    ndim = center.size
    x = np.random.normal(size=(n_per_sphere, ndim))
    ssq = np.sum(x**2,axis=1)
    fr = r*gammainc(ndim/2,ssq/2)**(1/ndim)/np.sqrt(ssq)
    frtiled = np.tile(fr.reshape(n_per_sphere,1),(1,ndim))
    p = center + np.multiply(x,frtiled)
    return p

fig1 = plt.figure(1)
ax1 = fig1.gca()
center = np.array([0,0])
radius = 1
p = sample(center,radius,10000)
ax1.scatter(p[:,0],p[:,1],s=0.5)
ax1.add_artist(plt.Circle(center,radius,fill=False,color='0.5'))
ax1.set_xlim(-1.5,1.5)
ax1.set_ylim(-1.5,1.5)
ax1.set_aspect('equal')

将numpy导入为np
将matplotlib.pyplot作为plt导入
r=30.*np.sqrt(np.rand.rand(1000))
#r=30.*np.rand.rand(1000)
φ=2.*np.pi*np.rand.rand(1000)
x=r*np.cos(φ)
y=r*np.sin(φ)
plt.图()
plt.绘图(x,y,'。)
plt.show()

好主意。对于球体,丢弃是相当有效的,并且在许多文本中被推荐为比精确采样所需的转换速度更快。我想到了这个想法,但这将损失约50%的创建点。因此,要创建16000个粒子,它将创建约32000个。因为立方体的面积为r^3,球体的面积为4/3*pi*(r/2)^3=所以比率=~4/8=.5这不会产生正态分布,@Tim要求的正态分布。正态分布和均匀分布不一样。哦@Juanchopanza我搞砸了。我是说均匀分布。我现在要去解决这个问题。注意,这对于高维空间来说是无效的,因为单位球的体积为零(=在球内对点进行采样的概率).这和吉姆·刘易斯建议的一样,对吗?创建一个统一的立方体,扔掉球体以外的任何东西?@Tim McJilton:是的,我在吉姆的答案出来的时候输入了它,因为它是代码,所以我决定无论如何发布它。无论如何,你的问题中没有任何建议说生成更多实际需要的点会成为某种问题ic.想详细说明一下吗?谢谢,我正在运行一个16000多颗恒星的模拟,速度和位置都要一致。我希望有一种方法,我可以设置要保留的点数,因为我需要16000或其他什么。你的方法会行得通的,我想我可以继续逐1添加点数,直到我们得到16,000随函附上。@Tim McJilton:FWIW,在我(非常)普通的机器中,生成1e5 3d均匀随机点并丢弃外来者(屈服于约5.3e4点),需要大约35毫秒。如果这种性能不适用于您,请提供更多详细信息。Thanks@Tim麦克吉尔顿:现在看到《代码》杂志的答案,我想是《化学需氧量》
N = 1000
v = numpy.random.uniform(size=(3,N)) 
vn = v / numpy.sqrt(numpy.sum(v**2, 0))
import numpy as np
from scipy.special import gammainc
from matplotlib import pyplot as plt
def sample(center,radius,n_per_sphere):
    r = radius
    ndim = center.size
    x = np.random.normal(size=(n_per_sphere, ndim))
    ssq = np.sum(x**2,axis=1)
    fr = r*gammainc(ndim/2,ssq/2)**(1/ndim)/np.sqrt(ssq)
    frtiled = np.tile(fr.reshape(n_per_sphere,1),(1,ndim))
    p = center + np.multiply(x,frtiled)
    return p

fig1 = plt.figure(1)
ax1 = fig1.gca()
center = np.array([0,0])
radius = 1
p = sample(center,radius,10000)
ax1.scatter(p[:,0],p[:,1],s=0.5)
ax1.add_artist(plt.Circle(center,radius,fill=False,color='0.5'))
ax1.set_xlim(-1.5,1.5)
ax1.set_ylim(-1.5,1.5)
ax1.set_aspect('equal')
import random
R = 2

def sample_circle(center):
    a = random.random() * 2 * np.pi
    r = R * np.sqrt(random.random())
    x = center[0]+ (r * np.cos(a))
    y = center[1] + (r * np.sin(a))
    return x,y

ps = np.array([sample_circle((0,0)) for i in range(100)])

plt.plot(ps[:,0],ps[:,1],'.')
plt.xlim(-3,3)
plt.ylim(-3,3)
plt.show()