从von Mises-Fisher发行版的Python中采样吗?


14

我正在寻找一种简单的方法来从Python中的多元von Mises-Fisher分布中采样。我在scipynumpy模块中查看了stats模块,但只发现了单变量von Mises分布。有没有可用的代码?我还没找到。

显然,Wood(1994)根据该链接设计了一种从vMF分布进行采样的算法,但我找不到该论文。

-对于精度,我对在文献中很难找到的算法很感兴趣(大多数论文都集中在)。据我所知,开创性的文章(Wood,1994年)无法免费找到。小号2


1
输入scipy.stats.vonmises可以是类似数组的,因此您可以将分布指定为array。看到这个例子
rightkewed

感谢您的回答。但是,似乎它是真正的nD von Mises-Fisher而不是1-D von Mises的产物K = vonmises.pdf([x,x], kappa=[[1],[10]])。二维vMF应该仅包含一个实作为参数。你同意吗?κ
麦克风

我正在最初在von Mises Fisher发行版的Simulation(伍德,1994年)中寻找算法VM *。任何人?
麦克风

3
我发现此线程中的答案非常有用。作为此软件包的一部分,我提供了一个稍作清理的实用程序功能:https : //github.com/clara-labs/spherecluster/blob/develop/spherecluster/util.py,对于仍希望生成此功能的用户数据。
Jaska

Answers:


11

终于我明白了。这是我的答案。

最后,我介绍了方向统计(Mardia和Jupp,1999年)和Ulrich-Wood的采样算法。我在这里发布了我的理解,即我的代码(在Python中)。

拒绝采样方案:

def rW(n, kappa, m):
    dim = m-1
    b = dim / (np.sqrt(4*kappa*kappa + dim*dim) + 2*kappa)
    x = (1-b) / (1+b)
    c = kappa*x + dim*np.log(1-x*x)

    y = []
    for i in range(0,n):
        done = False
        while not done:
            z = sc.stats.beta.rvs(dim/2,dim/2)
            w = (1 - (1+b)*z) / (1 - (1-b)*z)
            u = sc.stats.uniform.rvs()
            if kappa*w + dim*np.log(1-x*w) - c >= np.log(u):
                done = True
        y.append(w)
    return y

然后,所需的采样是,其中瓦特是从排斥采样方案的结果,和v是在超球面均匀采样的。v1个-w2+wμwv

def rvMF(n,theta):
    dim = len(theta)
    kappa = np.linalg.norm(theta)
    mu = theta / kappa

    result = []
    for sample in range(0,n):
        w = rW(n, kappa, dim)
        v = np.random.randn(dim)
        v = v / np.linalg.norm(v)

        result.append(np.sqrt(1-w**2)*v + w*mu)

    return result

并且,为了使用此代码进行有效采样,下面是一个示例:

import numpy as np
import scipy as sc
import scipy.stats

n = 10
kappa = 100000
direction = np.array([1,-1,1])
direction = direction / np.linalg.norm(direction)

res_sampling = rvMF(n, kappa * direction)

3
(+1)感谢您分享您的答案(尤其是尽管最初提出问题可能会令您沮丧)!
ub

4

(我为此处的格式表示歉意,我创建了一个帐户来回答这个问题,因为我最近也在试图弄清楚这一点)。

v小号p-2μvμv1个-w2+wμ

import scipy.linalg as la
def sample_tangent_unit(mu):
    mat = np.matrix(mu)

    if mat.shape[1]>mat.shape[0]:
        mat = mat.T

    U,_,_ = la.svd(mat)
    nu = np.matrix(np.random.randn(mat.shape[0])).T
    x = np.dot(U[:,1:],nu[1:,:])
    return x/la.norm(x)

并更换

v = np.random.randn(dim)
v = v / np.linalg.norm(v)

在麦克风的示例中,

v = sample_tangent_unit(mu)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.