詹森 - 香农发散(Jensen-Shannon Divergence)

2019-08-20 07:04发布

我有我希望有人能帮助我一个问题。

我使用的是詹森 - 香农散度来衡量两个概率分布之间的相似性。 的相似性得分似乎是正确的,即它们属于1和0给定一个使用在基体2的对数之间,其中0是指该分布是相等的。

但是,我不知道是否有事实上的某处错误,并想知道是否有人也许能说“是的,它是正确的”或“不,你做错了什么。”

下面是代码:

from numpy import zeros, array
from math import sqrt, log


class JSD(object):
    def __init__(self):
        self.log2 = log(2)


    def KL_divergence(self, p, q):
        """ Compute KL divergence of two vectors, K(p || q)."""
        return sum(p[x] * log((p[x]) / (q[x])) for x in range(len(p)) if p[x] != 0.0 or p[x] != 0)

    def Jensen_Shannon_divergence(self, p, q):
        """ Returns the Jensen-Shannon divergence. """
        self.JSD = 0.0
        weight = 0.5
        average = zeros(len(p)) #Average
        for x in range(len(p)):
            average[x] = weight * p[x] + (1 - weight) * q[x]
            self.JSD = (weight * self.KL_divergence(array(p), average)) + ((1 - weight) * self.KL_divergence(array(q), average))
        return 1-(self.JSD/sqrt(2 * self.log2))

if __name__ == '__main__':
    J = JSD()
    p = [1.0/10, 9.0/10, 0]
    q = [0, 1.0/10, 9.0/10]
    print J.Jensen_Shannon_divergence(p, q)

问题是,我觉得成绩比较两个文本文档时,例如不够高。 然而,这纯粹是一种主观感觉。

任何帮助,一如既往地赞赏。

Answer 1:

请注意,下面的SciPy的熵调用是相对熵。

请参阅: http://en.wikipedia.org/wiki/Jensen%E2%80%93Shannon_divergence

#!/usr/bin/env python
from scipy.stats import entropy
from numpy.linalg import norm
import numpy as np

def JSD(P, Q):
    _P = P / norm(P, ord=1)
    _Q = Q / norm(Q, ord=1)
    _M = 0.5 * (_P + _Q)
    return 0.5 * (entropy(_P, _M) + entropy(_Q, _M))

还要注意的是测试用例的问题看起来犯错? 在p分布的总和不增加1.0。

请参阅: http://www.itl.nist.gov/div898/handbook/eda/section3/eda361.htm



Answer 2:

获取与已知的发散分布的一些数据与那些已知值比较结果。

BTW:在KL_divergence总和可以使用被改写拉链内置函数是这样的:

sum(_p * log(_p / _q) for _p, _q in zip(p, q) if _p != 0)

这摒弃了大量的“噪音”,也是更“Python化”。 与双对比0.00是没有必要的。



Answer 3:

一般的版本,对于n概率分布,在蟒蛇

import numpy as np
from scipy.stats import entropy as H


def JSD(prob_distributions, weights, logbase=2):
    # left term: entropy of misture
    wprobs = weights * prob_distributions
    mixture = wprobs.sum(axis=0)
    entropy_of_mixture = H(mixture, base=logbase)

    # right term: sum of entropies
    entropies = np.array([H(P_i, base=logbase) for P_i in prob_distributions])
    wentropies = weights * entropies
    sum_of_entropies = wentropies.sum()

    divergence = entropy_of_mixture - sum_of_entropies
    return(divergence)

# From the original example with three distributions:
P_1 = np.array([1/2, 1/2, 0])
P_2 = np.array([0, 1/10, 9/10])
P_3 = np.array([1/3, 1/3, 1/3])

prob_distributions = np.array([P_1, P_2, P_3])
n = len(prob_distributions)
weights = np.empty(n)
weights.fill(1/n)

print(JSD(prob_distributions, weights))
#0.546621319446


Answer 4:

由于詹森-香农 距离distance.jensenshannon )已被列入Scipy 1.2詹森-香农 散度可以作为詹森-香农距离的平方来获得:

from scipy.spatial import distance

distance.jensenshannon([1.0/10, 9.0/10, 0], [0, 1.0/10, 9.0/10]) ** 2
# 0.5306056938642212


Answer 5:

明确地跟随在数学维基百科的文章 :

def jsdiv(P, Q):
    """Compute the Jensen-Shannon divergence between two probability distributions.

    Input
    -----
    P, Q : array-like
        Probability distributions of equal length that sum to 1
    """

    def _kldiv(A, B):
        return np.sum([v for v in A * np.log2(A/B) if not np.isnan(v)])

    P = np.array(P)
    Q = np.array(Q)

    M = 0.5 * (P + Q)

    return 0.5 * (_kldiv(P, M) +_kldiv(Q, M))


文章来源: Jensen-Shannon Divergence