多维环中无排斥的均匀抽样

2024-10-01 00:21:30 发布

您现在位置:Python中文网/ 问答频道 /正文

这个question中的算法告诉我们如何有效地从多维球中采样。有没有一种方法可以同样有效地从多维环中进行采样,例如,r1<r<r2

我希望对这个标度函数做一个不太复杂的修改 r*(gammainc(s2/2,n/2).^(1/n))./sqrt(s2)是可能的。(平庸免责声明:甚至还没有为原始缩放函数计算代数/几何)。在

原始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);

包含来自Daniel's answer的演示的等效python代码:

^{pr2}$

Tags: oftheto函数代码inanwith
3条回答

经过一番反复试验,我终于用gammainc方法完成了。它背后的数学是我无法理解的,但我基本上把gammainc中的系数2改为幂z来提高一致性。在

还测试了它在三维和似乎工作良好。在

(这在我的待办事项列表中已经有一段时间了,谢谢你的建议!)在

import numpy as np
from scipy.special import gammainc
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def sample_ring(center,r1,r2,n_points):
    nd = center.size
    x = np.random.normal(size=(n_points, nd))
    sq = np.sum(x**2,axis=1)
    z = (r2-r1)/r2
    fr = (r2-r1)*gammainc(nd/2**z,sq/2**z)**(1/nd)/np.sqrt(sq) + r1/np.sqrt(sq)
    frtiled = np.tile(fr.reshape(n_points,1),(1,nd))
    p = center + np.multiply(x,frtiled)
    return p

fig1 = plt.figure(1)
ax1 = fig1.gca()
center = np.array([0,0])
r1 = 1.5
R2 = 3
p = sample_ring(center,r1,R2,5000)
ax1.scatter(p[:,0],p[:,1],s=0.5)
ax1.add_artist(plt.Circle(center,r1,fill=False,color='0.5'))
ax1.add_artist(plt.Circle(center,R2,fill=False,color='0.5'))
ax1.set_xlim(-4,4)
ax1.set_ylim(-4,4)
ax1.set_aspect('equal')

fig3 = plt.figure(3)
ax3 = plt.gca(projection='3d')
ax3.set_aspect("equal")
theta, phi = np.mgrid[0:2*np.pi:10j, 0:np.pi:10j]
c_3d = np.array([0,0,0])
r1_3d = 0.5
x1 = c_3d[0] + r1_3d*np.cos(theta)*np.sin(phi)
y1 = c_3d[1] + r1_3d*np.sin(theta)*np.sin(phi)
z1 = c_3d[2] + r1_3d*np.cos(phi)
r2_3d = 1.4
x2 = c_3d[0] + r2_3d*np.cos(theta)*np.sin(phi)
y2 = c_3d[1] + r2_3d*np.sin(theta)*np.sin(phi)
z2 = c_3d[2] + r2_3d*np.cos(phi)
ax3.plot_wireframe(x1, y1, z1, color="r")
ax3.plot_wireframe(x2, y2, z2, color="r")
p = sample_ring(c_3d,r1_3d,r2_3d,1000)
ax3.scatter(p[:,0],p[:,1],p[:,2], c='b', marker='o')
ax3.set_xlim(-1.5, 1.5)
ax3.set_ylim(-1.5, 1.5)
ax3.set_zlim(-1.5, 1.5)

uniform sample in ring

uniform sample 3d ring

最后一种方法here(1)适用于任何维度的球体:

在球体上随机选取一个点:
-生成N个高斯随机变量x1,x2..xN
-求x的范数[i]

 L = Sqrt(x1*x1 + x2*x2 + .. + xn*xn)
 ux1 = x1 / L
 ux2 = x2 / L
 ...

则矢量ux[i]在曲面SN-1上的分布是均匀的

在环内提供均匀分布:
-在范围内生成均匀随机

R_NPow = RandomUniform(R_InnerN, R_OuterN

得到半径(比如this 2D case

R = R_NPow1/N

然后计算得到的点坐标:

^{pr2}$

(1)Muller,M.E.“关于在维球面上均匀生成点的一种方法的注记”,通讯协会计算机。机器。1959年4月2日19-20日。在

实际上,我最后使用了反cdf方法来处理均匀分布在球体上的点

像这样

def random_uniform_ring(center=np.array([0,0]),R=1,r=0,nsamples=1):
    """
    generate point uniformly distributed in a ring
    """
    nd = len(center)
    x = np.random.normal(size = (nsamples,nd))
    x /=np.linalg.norm(x,axis=1)[:,np.newaxis] #generate on unit sphere
    # using the inverse cdf method
    u = np.random.uniform(size=(nsamples))
    sc = (u*(R**nd-r**nd)+r**nd)**(1/nd) #this is inverse the cdf of ring volume as a function of radius
    return x*sc[:,None]+center

测试

^{pr2}$

sampling_uniformly_in_a_ring

这可能相当于@Mbo的答案,但不幸的是我没有时间去测试。如果有人能验证他的答案,我很乐意接受。在

相关问题 更多 >