Lấy mẫu từ phân phối von Mises-Fisher trong Python?


14

Tôi đang tìm kiếm một cách đơn giản để lấy mẫu từ bản phân phối von Mise-Fisher đa biến trong Python. Tôi đã xem xét mô-đun thống kê trong mô-đun scipynumpy nhưng chỉ tìm thấy phân phối von Mise đơn biến. Có bất kỳ mã có sẵn? Tôi chưa tìm thấy.

Rõ ràng, Wood (1994) đã thiết kế một thuật toán để lấy mẫu từ bản phân phối vMF theo liên kết này , nhưng tôi không thể tìm thấy bài báo.

- chỉnh sửa Để chính xác, tôi quan tâm đến thuật toán khó tìm thấy trong tài liệu (hầu hết các bài viết tập trung vào ). Theo tôi, bài báo chuyên đề (Wood, 1994) không thể tìm thấy miễn phí.S2


1
Đầu vào scipy.stats.vonmisescó thể là mảng như thế, vì vậy bạn có thể chỉ định phân phối là một array. Xem ví dụ
Rightskewed

Cảm ơn câu trả lời của bạn. Nhưng, có vẻ như đó là một sản phẩm của 1-D von Mises hơn là một nD von Mises-Fisher thực sự : K = vonmises.pdf([x,x], kappa=[[1],[10]]). A 2-D VMF nên chỉ có một thực là tham số. Bạn có đồng ý không? κ
mic

Tôi đang tìm kiếm thuật toán VM * ban đầu trong Mô phỏng phân phối von Mises Fisher (Wood, 1994). Bất kỳ ai?
mic

3
Tôi tìm thấy câu trả lời trong chủ đề này ở đây thực sự hữu ích. Tôi đã cung cấp một chức năng tiện ích được làm sạch một chút để thực hiện điều này như là một phần của gói này: https://github.com/clara-labs/spherecluster/blob/develop/spherecluster/util.py , cho những ai vẫn muốn tạo ra điều này dữ liệu.
Jaska

Câu trả lời:


11

Cuối cùng, tôi đã nhận được nó. Đây là câu trả lời của tôi.

Cuối cùng tôi đã đặt tay vào Thống kê định hướng (Mardia và Jupp, 1999) và trên thuật toán của Ulrich-Wood để lấy mẫu. Tôi đăng ở đây những gì tôi hiểu từ nó, tức là mã của tôi (bằng Python).

Sơ đồ lấy mẫu từ chối:

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

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

Và, để lấy mẫu hiệu quả với mã này, đây là một ví dụ:

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) Cảm ơn bạn đã chia sẻ câu trả lời của bạn (đặc biệt là mặc dù có thể không khuyến khích câu hỏi của bạn ban đầu đóng lại)!
whuber

4

(Tôi xin lỗi vì định dạng ở đây, tôi đã tạo một tài khoản chỉ để trả lời câu hỏi này, vì tôi cũng đang cố gắng tìm ra điều này gần đây).

Câu trả lời của mic không hoàn toàn đúng, vectơ v cần phải đến từ Sp-2 trong không gian tiếp tuyến μ, đó là, v nên là một vector đơn vị trực giao để μ. Mặt khác, vectơv1-w2+wμsẽ không có định mức một. Bạn có thể thấy điều này trong ví dụ được cung cấp bởi mic. Để khắc phục điều này, hãy sử dụng một cái gì đó như:

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à thay thế

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

trong ví dụ của mic với một cuộc gọi đến

v = sample_tangent_unit(mu)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.