numpy KL-两个高斯的发散

s5a0g9ez  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(106)

我有两个GARCH,我用它来拟合同一空间中的两组不同的数据,我想计算它们之间的KL散度。
目前,我正在使用sklearn(http://scikit-learn.org/stable/modules/generated/sklearn.mixture.GMM.html)中定义的GSTIM和KL-发散(http://docs.scipy.org/doc/scipy-dev/reference/generated/scipy.stats.entropy.html)的SciPy实现。
我该怎么做呢?我想创建大量的随机点,得到它们在两个模型(称为P和Q)上的概率,然后使用这些概率作为我的输入吗?或者在SciPy/SKLearn环境中有没有更规范的方法来做到这一点?

flvtvl50

flvtvl501#

没有封闭的形式的KL分歧之间的甘精胰岛素。你可以很容易地做蒙特卡洛。记住KL(p||q) = \int p(x) log(p(x) / q(x)) dx = E_p[ log(p(x) / q(x))。所以:

def gmm_kl(gmm_p, gmm_q, n_samples=10**5):
    X = gmm_p.sample(n_samples)
    log_p_X, _ = gmm_p.score_samples(X)
    log_q_X, _ = gmm_q.score_samples(X)
    return log_p_X.mean() - log_q_X.mean()

mean(log(p(x) / q(x))) = mean(log(p(x)) - log(q(x))) = mean(log(p(x))) - mean(log(q(x)))在计算上稍微便宜一些。
您不想使用scipy.stats.entropy;这是离散分布的情况
如果你想要对称和平滑的Jensen-Shannon divergenceKL(p||(p+q)/2) + KL(q||(p+q)/2),它非常相似:

def gmm_js(gmm_p, gmm_q, n_samples=10**5):
    X = gmm_p.sample(n_samples)
    log_p_X, _ = gmm_p.score_samples(X)
    log_q_X, _ = gmm_q.score_samples(X)
    log_mix_X = np.logaddexp(log_p_X, log_q_X)

    Y = gmm_q.sample(n_samples)
    log_p_Y, _ = gmm_p.score_samples(Y)
    log_q_Y, _ = gmm_q.score_samples(Y)
    log_mix_Y = np.logaddexp(log_p_Y, log_q_Y)

    return (log_p_X.mean() - (log_mix_X.mean() - np.log(2))
            + log_q_Y.mean() - (log_mix_Y.mean() - np.log(2))) / 2

log_mix_X/log_mix_Y实际上是混合物密度的两倍的对数;把它从平均操作中拉出来可以节省一些失败。)

hrysbysz

hrysbysz2#

Danica的回答逻辑正确。我尝试了sklearn 1.3.0,但结果不可靠(特别是评分功能)。所以我写的代码的帮助下ChatGPT计算KL。

import numpy as np
from scipy.stats import multivariate_normal
from sklearn.mixture import GaussianMixture

def gmm_pdf(x, weights, means, covariances):

    K = len(weights)
    pdf = 0.0
    
    for k in range(K):
        # Calculate the PDF for each Gaussian component
        component_pdf = weights[k] * multivariate_normal.pdf(x, mean=means[k], cov=covariances[k])
        pdf += component_pdf

    return pdf

def gmm_kl(gmm_p, gmm_q, n_samples=1e7):
    X = gmm_p.sample(n_samples)[0]
    p_X = (gmm_pdf(X, gmm_p.weights_, gmm_p.means_, gmm_p.covariances_))
    q_X = (gmm_pdf(X, gmm_q.weights_, gmm_q.means_, gmm_q.covariances_))
    return np.mean(np.log(p_X/q_X))

相关问题