การสุ่มตัวอย่างจากการแจกแจง von Mises-Fisher ใน Python?


14

ฉันกำลังมองหาวิธีง่ายๆในการสุ่มตัวอย่างจากการแจกแจงหลายตัวแปร von Mises-Fisherใน Python ฉันได้ดูในโมดูลสถิติใน scipyและโมดูล numpyแต่พบการกระจาย von Mises univariate เท่านั้น มีรหัสอะไรบ้าง? ฉันยังไม่พบ

เห็นได้ชัดว่า Wood (1994) ได้ออกแบบอัลกอริทึมสำหรับการสุ่มตัวอย่างจากการกระจาย vMF ตามลิงค์นี้แต่ฉันไม่พบกระดาษ

- แก้ไขเพื่อความแม่นยำฉันสนใจอัลกอริทึมที่หายากในวรรณกรรม (เอกสารส่วนใหญ่เน้นที่ ) บทความ seminal (Wood, 1994) ไม่สามารถพบได้ฟรีสำหรับความรู้ของฉันS2


1
การป้อนข้อมูลที่จะสามารถเป็นอาร์เรย์เช่นเพื่อให้คุณสามารถระบุกระจายนั้นscipy.stats.vonmises arrayดูตัวอย่าง
rightskewed

K = vonmises.pdf([x,x], kappa=[[1],[10]])κ

ฉันกำลังมองหาอัลกอริทึม VM * แต่เดิมในการจำลองการกระจาย von Mises Fisher (Wood, 1994) ใคร?
ไมค์

3
ฉันพบคำตอบในกระทู้นี้ที่นี่มีประโยชน์จริงๆ ฉันได้ให้ฟังก์ชั่นยูทิลิตี้ที่ได้รับการทำความสะอาดเล็กน้อยเพื่อทำสิ่งนี้เป็นส่วนหนึ่งของแพ็คเกจนี้: https://github.com/clara-labs/spherecluster/blob/develop/spherecluster/util.pyสำหรับผู้ที่ยังคงต้องการสร้างสิ่งนี้ ข้อมูล.
Jaska

คำตอบ:


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

โวลต์1-W2+Wμที่ไหน W เป็นผลมาจากรูปแบบการสุ่มตัวอย่างการปฏิเสธและ โวลต์ มีการสุ่มตัวอย่างอย่างสม่ำเสมอเหนือ hypersphere

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) ขอบคุณสำหรับการแบ่งปันคำตอบของคุณ (โดยเฉพาะอย่างยิ่งแม้จะมีความท้อใจที่อาจปิดคำถามของคุณในตอนแรก)!
whuber

4

(ฉันขอโทษสำหรับการจัดรูปแบบที่นี่ฉันสร้างบัญชีเพียงเพื่อตอบคำถามนี้เนื่องจากฉันกำลังพยายามหาสิ่งนี้เมื่อเร็ว ๆ นี้)

คำตอบของไมค์ไม่ถูกต้องเวกเตอร์ โวลต์ ต้องมาจาก Sพี-2 ในพื้นที่แทนเจนต์ถึง μ, นั่นคือ, โวลต์ ควรเป็นหน่วยเวกเตอร์มุมฉากถึง μ. มิฉะนั้นเวกเตอร์โวลต์1-W2+Wμจะไม่มีบรรทัดฐานหนึ่ง คุณสามารถเห็นสิ่งนี้ในตัวอย่างที่มีให้โดย mic ในการแก้ไขปัญหานี้ให้ใช้สิ่งต่อไปนี้:

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)

ในตัวอย่างของ mic ด้วยการโทรไป

v = sample_tangent_unit(mu)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.