【问题标题】:algorithm for generating uniformly distributed random points on the N-sphere在 N 球上生成均匀分布的随机点的算法
【发布时间】:2018-10-15 02:11:50
【问题描述】:

我还没有在 Python 上找到这种算法的实现

类似这样的:

有两个输入参数:

  • n - 空间维度。
  • m - n-1 球体上的点数。

我需要将它们大致均匀地排列在 n 球的表面上。

坐标轴位于 n-1 个球体的中心。 例如,在常规球体上的 3d 中,可以定位点 like this

在我看来,斐波那契算法在视觉上非常好。 我不知道n-sphere是否有类似的东西。 我有 512D 的空间,我要在里面放置 1000 甚至 10,000 个点。

如何在 python 中做到这一点?

【问题讨论】:

  • (1) 从均值 0、方差 1 的高斯分布生成样本的 n 个 d 元组,并将每个 d 元组标准化为长度 1。然后您的 n 个 d 元组在(d - 1)-球体的表面。 (通过 d,我假设您的意思是球体的嵌入维度,而不是球体本身的维度。例如,2 球体是局部二维的东西,它存在于 3 维空间中。)这种方法与什么是相同的下面由另一位受访者发布,但我认为这样解释更清楚。
  • (2)分层抽样:将球体分成若干等面积的块,从每一块中采样。您提到您的 n 不会比 d 大太多,这意味着纯随机抽样会留下很多空白。我的猜测是分层抽样,或另一种更均匀抽样的方法,在这个问题上会更好地工作。至于其他更均匀采样的方法,也许您可​​以在球体上找到一些关于低差异序列(又名准随机数)的信息。
  • 同超球面。来自你的链接:An n-sphere embedded in an (n + 1)-dimensional Euclidean space is called a hypersphere. 你只需要避免一个错误。 (2-sphere 是 3d 空间中的表面等)
  • 我会从反转和移植到 ND 开始:Procedural generation of stars with skybox 所以只需 n 次生成伪随机 ND 向量 v,坐标在 <-1,+1> 范围内,然后将向量的长度更改为rv = v*r/|v|。这里也有一个很好的副本(不确定有多老,但至少有一两年)但现在找不到(关于生成点正态分布的伪随机超球面)
  • OP,另一种方法是生成非均匀分布,然后对点进行不同的加权(即,对密度较小的区域中的点给予更大的权重)。这是否是一种可行的方法取决于你想要做什么。也许你可以在这里多谈谈你的更大目标。

标签: python math


【解决方案1】:

有一种简单的Muller and Marsaglia 方法可以在超球体表面生成均匀分布。

生成 n 个具有高斯分布的变量(在此处列出 l)。它们形成了一些向量。

找到该向量的长度并对其分量进行归一化以提供单位长度结果

示例显示了在 10d 空间中球体上的一个点的生成,并且还直观地检查了圆上点包的均匀性(2d 中的球体,柱状图值应该接近)

import random, math

#muller-marsaglia method
def spherepicking(n):
    while True:           #to get rid off [0,0,0,0] case
        l = [random.gauss(0, 1) for i in range(n)]
        sumsq = sum([x * x for x in l])
        if sumsq > 0:
            break
    norm = 1.0 / math.sqrt(sumsq)
    pt = [x * norm for x in l]
    return pt

print(spherepicking(10))

cnt = [0] * 18
for i in range(10000):
   pt = spherepicking(2)
   an = math.atan2(pt[1], pt[0]) + math.pi / 2
   cnt[math.floor(an * 9 / math.pi)] += 1
print(cnt)

-0.31811419572739935, 0.2845442135156396, -0.2849019746359018,
-0.1326796017012003, 0.7388447238721524, -0.287062305232526, 
-0.08794741714783766, 0.131707880836534, 0.22059937624019868, 
-0.13047162618106062]

[554, 560, 529, 589, 534, 538, 550, 558, 578, 556, 522, 553, 561, 513, 592, 583, 593, 537]

【讨论】:

    【解决方案2】:

    使用与 MBo 相同的参数:(Muller 1959,Marsaglia 1972)-[https://mathworld.wolfram.com/HyperspherePointPicking.html] 我使用 numpy 在 python 中实现我的实现:

    import numpy as np
    
    def getRandomSamplesOnNSphere(N , R , numberOfSamples):
        # Return 'numberOfSamples' samples of vectors of dimension N 
        # with an uniform distribution on the (N-1)-Sphere surface of radius R.
        # RATIONALE: https://mathworld.wolfram.com/HyperspherePointPicking.html
        
        X = np.random.default_rng().normal(size=(numberOfSamples , N))
    
        return R / np.sqrt(np.sum(X**2, 1, keepdims=True)) * X
    

    如果您需要在inside N-Sphere 中生成点,您可以这样做(参考:https://math.stackexchange.com/q/87238

    import numpy as np
    
    def getRandomSamplesInNSphere(N , R , numberOfSamples):
        # Return 'numberOfSamples' samples of vectors of dimension N 
        # with an uniform distribution inside the N-Sphere of radius R.
        # RATIONALE: https://math.stackexchange.com/q/87238
        
        randomnessGenerator = np.random.default_rng()
        
        X = randomnessGenerator.normal(size=(numberOfSamples , N))
        U = randomnessGenerator.random((numberOfSamples , 1)) 
        
        return R * U**(1/N) / np.sqrt(np.sum(X**2, 1, keepdims=True)) * X
    

    【讨论】:

    • 能否提供性能比较?
    猜你喜欢
    • 2019-06-13
    • 2012-03-24
    • 1970-01-01
    • 2019-06-29
    • 2020-09-23
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多