用python实现多元学生t分布

用python实现多元学生t分布,python,statistics,scipy,probability-density,Python,Statistics,Scipy,Probability Density,要生成具有多元t分布的样本,我使用此函数: def多变量(mu,Sigma,N,M): ''' 输出: 产生d维多元t分布的M个样本 输入: mu=平均值(d维numpy数组或标量) Sigma=比例矩阵(dxd numpy阵列) N=自由度 M=要生产的样品数量 ''' d=len(西格玛) g=np.tile(np.random.gamma(N/2,2./N,M)、(d,1)).T Z=np.随机多变量正态分布(np.零(d),σ,M) 返回mu+Z/np.sqrt(g) 但我现在寻找的是

要生成具有多元t分布的样本,我使用此函数:

def多变量(mu,Sigma,N,M):
'''
输出:
产生d维多元t分布的M个样本
输入:
mu=平均值(d维numpy数组或标量)
Sigma=比例矩阵(dxd numpy阵列)
N=自由度
M=要生产的样品数量
'''
d=len(西格玛)
g=np.tile(np.random.gamma(N/2,2./N,M)、(d,1)).T
Z=np.随机多变量正态分布(np.零(d),σ,M)
返回mu+Z/np.sqrt(g)
但我现在寻找的是it本身,因此我可以计算
维度>1
的元素密度


这将类似于包的
stats.t.pdf(x,df,loc,scale)
,但在多维空间中。

我自己对密度进行了编码:

将numpy导入为np
从数学导入*
def多元t分布(x,mu,Sigma,df,d):
'''
多元t-学生密度:
输出:
给定元素的密度
输入:
x=参数(d维numpy数组或标量)
mu=平均值(d维numpy数组或标量)
Sigma=比例矩阵(dxd numpy阵列)
df=自由度
d:尺寸
'''
Num=伽马(1.*(d+df)/2)
Denom=(伽马(1.*df/2)*功率(df*pi,1.*d/2)*功率(np.linalg.det(Sigma),1./2)*功率(1+(1./df)*np.dot(np.dot((x-mu),np.linalg.inv(Sigma)),1.*(d+df)/2))
d=1。*Num/Denom
返回d

这评估了n×d数据矩阵X的多元student-T分布的对数pdf:

from scipy.special import gamma
from numpy.linalg import slogdet

def multivariate_student_t(X, mu, Sigma, df):    
    #multivariate student T distribution

    [n,d] = X.shape
    Xm = X-mu
    V = df * Sigma
    V_inv = np.linalg.inv(V)
    (sign, logdet) = slogdet(np.pi * V)

    logz = -gamma(df/2.0 + d/2.0) + gamma(df/2.0) + 0.5*logdet
    logp = -0.5*(df+d)*np.log(1+ np.sum(np.dot(Xm,V_inv)*Xm,axis=1))

    logp = logp - logz            

    return logp

我推广了@farhawa的代码,允许在
x
中有多个条目(我发现我想一次查询多个点)


我尝试了以上的答案,每个答案都得到了不同的结果,但我不确定为什么/什么可能是错的。以下是我基于高斯混合的,我认为是有效的(对于任意大小的输入numpy数组X和c t分布,参数在列表均值和covars中):


我注意到Sigma的维度至少应该是2x2,否则np.linalg会呕吐。为什么在
pycopula
包中会出现完全相同的代码?而
x
的含义是什么,它所说的只是“参数”,我认为它不是。我没有解释为什么代码会出现在别处,但我知道这个答案写在2015年,github代码是在2018年推出的。。也就是说,这里的X是你想要应用t分布的值,这里似乎有点不对劲。我得到的log_pdf大约是df的一个系数。你能解释一下多变量的工作原理吗?你似乎把student-t分布和一元伽马和多元正态联系起来,我不明白为什么它会起作用?谢谢
x
的含义是什么,它所说的只是“参数”,我认为它不是
import numpy as np
from math import gamma

def multivariate_t_distribution(x, mu, Sigma, df):
    '''
    Multivariate t-student density. Returns the density
    of the function at points specified by x.

    input:
        x = parameter (n-d numpy array; will be forced to 2d)
        mu = mean (d dimensional numpy array)
        Sigma = scale matrix (dxd numpy array)
        df = degrees of freedom

    Edited from: http://stackoverflow.com/a/29804411/3521179
    '''

    x = np.atleast_2d(x) # requires x as 2d
    nD = Sigma.shape[0] # dimensionality

    numerator = gamma(1.0 * (nD + df) / 2.0)

    denominator = (
            gamma(1.0 * df / 2.0) * 
            np.power(df * np.pi, 1.0 * nD / 2.0) *  
            np.power(np.linalg.det(Sigma), 1.0 / 2.0) * 
            np.power(
                1.0 + (1.0 / df) *
                np.diagonal(
                    np.dot( np.dot(x - mu, np.linalg.inv(Sigma)), (x - mu).T)
                ), 
                1.0 * (nD + df) / 2.0
                )
            )

    return 1.0 * numerator / denominator 
import numpy as np
from scipy import linalg
try:  # SciPy >= 0.19
    from scipy.special import gammaln as sp_gammaln
except ImportError:
    from scipy.misc import gammaln as sp_gammaln

def log_multivariate_t_density(X, means, covars, nu = 1):
    n_samples, n_dim = X.shape
    nmix = len(means)
    log_prob = np.empty((n_samples, nmix))
    for c, (mu, cv) in enumerate(zip(means, covars)):
        try:
            cv_chol = linalg.cholesky(cv, lower=True)
        except linalg.LinAlgError:

            try:
                cv_chol = linalg.cholesky(cv + min_covar * np.eye(n_dim),
                                  lower=True)
            except linalg.LinAlgError:
                raise ValueError("'covars' must be symmetric, "
                         "positive-definite")

        cv_log_det = 2 * np.sum(np.log(np.diagonal(cv_chol)))
        cv_sol = linalg.solve_triangular(cv_chol, (X - mu).T, lower=True).T

        norm = (sp_gammaln((nu + n_dim) / 2.) - sp_gammaln(nu / 2.)
                - 0.5 * n_dim * np.log(nu * np.pi))
        inner = - (nu + n_dim) / 2. * np.log1p(np.sum(cv_sol ** 2, axis=1) / nu)
        log_prob[:, c] = norm + inner - cv_log_det

    return log_prob