3 संभावित वितरण के लिए जेनसेन-शैनन विचलन गणना: क्या यह ठीक है?


12

मैं 3 डिस्ट्रीब्यूशन के बाद जेनसेन-शैनन डायवर्जन की गणना करना चाहूंगा। क्या गणना नीचे सही है? (मैंने विकिपीडिया से JSD के फॉर्मूले का पालन ​​किया ):

P1  a:1/2  b:1/2    c:0
P2  a:0    b:1/10   c:9/10
P3  a:1/3  b:1/3    c:1/3
All distributions have equal weights, ie 1/3.

JSD(P1, P2, P3) = H[(1/6, 1/6, 0) + (0, 1/30, 9/30) + (1/9,1/9,1/9)] - 
                 [1/3*H[(1/2,1/2,0)] + 1/3*H[(0,1/10,9/10)] + 1/3*H[(1/3,1/3,1/3)]]

JSD(P1, P2, P3) = H[(1/6, 1/5, 9/30)] - [0 + 1/3*0.693 + 0] = 1.098-0.693 = 0.867

अग्रिम में धन्यवाद...

संपादित करें यहाँ कुछ सरल गंदे पायथन कोड हैं जो इसकी गणना करता है:

    def entropy(prob_dist, base=math.e):
        return -sum([p * math.log(p,base) for p in prob_dist if p != 0])

    def jsd(prob_dists, base=math.e):
        weight = 1/len(prob_dists) #all same weight
        js_left = [0,0,0]
        js_right = 0    
        for pd in prob_dists:
            js_left[0] += pd[0]*weight
            js_left[1] += pd[1]*weight
            js_left[2] += pd[2]*weight
            js_right += weight*entropy(pd,base)
        return entropy(js_left)-js_right

usage: jsd([[1/2,1/2,0],[0,1/10,9/10],[1/3,1/3,1/3]])

2
वैसे अच्छा पायथन कोड!
गुई ११

जवाबों:


13

मिश्रण वितरण में गलती है। यह बजाय होना चाहिए योग 1 तक नहीं है। उस की एंट्रोपी (प्राकृतिक लॉग के साथ) 1.084503 है । आपकी अन्य एंट्रोपी शर्तें गलत हैं।(5/18,28/90,37/90)(1/6,1/5,9/30)

मैं एक गणना का विवरण दूंगा:

H(1/2,1/2,0)=1/2log(1/2)1/2log(1/2)+0=0.6931472

इसी तरह से, अन्य शब्द 0.325083 और 1.098612 हैं। तो अंतिम परिणाम 1.084503 - (0.6931472 + 0.325083 + 1.098612) / 3 = 3373789 है


3
+1। त्वरित और गंदा आर गणना h <- function(x) {h <- function(x) {y <- x[x > 0]; -sum(y * log(y))}; jsd <- function(p,q) {h(q %*% p) - q %*% apply(p, 2, h)}:। तर्क pएक मैट्रिक्स है जिसकी पंक्तियाँ वितरण और तर्क qवजन के वेक्टर हैं। उदाहरण के लिए, p <- matrix(c(1/2,1/2,0, 0,1/10,9/10, 1/3,1/3,1/3), ncol=3, byrow=TRUE); q <- c(1/3,1/3,1/3); jsd(p,q)रिटर्न (जिनमें से लॉग का अनुमान लगाती है )। 3 34 / 15 5 1 / 9 2 - 13 / 45 7 - 14 / 45 37 - 37 / 900.378889334/1551/9213/45714/453737/90
whuber

1
इतना गंदा नहीं ... ;-)
gui11aume

4
(1) गणित को फिर से करें। (2) जब तक आप संगत हैं, तब तक लॉगरिदम के किसी भी आधार का उपयोग करके एन्ट्रापी को मापा जा सकता है। प्राकृतिक, सामान्य और आधार -2 लॉग सभी पारंपरिक हैं। (३) यह वास्तव में वितरण और उनके औसत के बीच एक विसंगति है। यदि आप प्रत्येक वितरण को एक बिंदु मानते हैं, तो वे एक बादल बनाते हैं। आप क्लाउड के केंद्र और उसके बिंदुओं के बीच की औसत "दूरी" को देख रहे हैं, जो एक औसत त्रिज्या की तरह है। सहज रूप से, यह बादल के आकार को मापता है।
whuber

1
@ मुझे लगता है कि तुम सही हो। मैंने यह पता लगाने के बाद पर्याप्त परीक्षण नहीं किया कि एक परिणाम मुझे दूसरे तरीके से प्राप्त उत्तर ( मैथेमेटिका के साथ ) से सहमत है ।
whuber

1
@ मेक मेरी टिप्पणी में वास्तव में टाइपोस हैं: (1) वाक्यांश h <- function(x) {दो बार चिपकाया गया था। बस इसे हटा दें: बाकी सब कुछ काम करता है और मेरे द्वारा उद्धृत परिणामों का उत्पादन करता है। फिर संशोधित apply(p, 2, h)करने के लिए apply(p, 1, h)के रूप में बताया लीजेंड द्वारा टिप्पणी में
whuber

6

अजगर:

import numpy as np
# @author: jonathanfriedman

def jsd(x,y): #Jensen-shannon divergence
    import warnings
    warnings.filterwarnings("ignore", category = RuntimeWarning)
    x = np.array(x)
    y = np.array(y)
    d1 = x*np.log2(2*x/(x+y))
    d2 = y*np.log2(2*y/(x+y))
    d1[np.isnan(d1)] = 0
    d2[np.isnan(d2)] = 0
    d = 0.5*np.sum(d1+d2)    
    return d

jsd(np.array([0.5,0.5,0]),np.array([0,0.1,0.9]))

जावा:

/**
 * Returns the Jensen-Shannon divergence.
 */
public static double jensenShannonDivergence(final double[] p1,
        final double[] p2) {
    assert (p1.length == p2.length);
    double[] average = new double[p1.length];
    for (int i = 0; i < p1.length; ++i) {
        average[i] += (p1[i] + p2[i]) / 2;
    }
    return (klDivergence(p1, average) + klDivergence(p2, average)) / 2;
}

public static final double log2 = Math.log(2);

/**
 * Returns the KL divergence, K(p1 || p2).
 * 
 * The log is w.r.t. base 2.
 * <p>
 * *Note*: If any value in <tt>p2</tt> is <tt>0.0</tt> then the
 * KL-divergence is <tt>infinite</tt>. Limin changes it to zero instead of
 * infinite.
 */
public static double klDivergence(final double[] p1, final double[] p2) {
    double klDiv = 0.0;
    for (int i = 0; i < p1.length; ++i) {
        if (p1[i] == 0) {
            continue;
        }
        if (p2[i] == 0.0) {
            continue;
        } // Limin

        klDiv += p1[i] * Math.log(p1[i] / p2[i]);
    }
    return klDiv / log2; // moved this division out of the loop -DM
}

0

आपने विकिपीडिया संदर्भ दिया। यहाँ मैं कई संभावना वितरण के साथ जेनसन-शैनन विचलन के लिए पूर्ण अभिव्यक्ति देता हूं:

JSmetric(p1,...,pm)=H(p1+...+pmm)j=1mH(pj)m

बहु-वितरण जेएस विचलन के गणितीय अभिव्यक्ति के बिना मूल प्रश्न पोस्ट किया गया था जो प्रदान की गई गणना को समझने में भ्रम पैदा करता है। इसके अलावा, शब्द weightका उपयोग किया गया था जो फिर से भ्रम पैदा करता है कि आप गुणन के लिए उपयुक्त भार का चयन कैसे करते हैं। उपरोक्त अभिव्यक्ति इन भ्रमों को स्पष्ट करती है। उपरोक्त अभिव्यक्ति से स्पष्ट है, वज़न स्वचालित रूप से वितरण की संख्या के आधार पर चुना जाता है।


यह स्वचालित रूप से निम्न गुणवत्ता के रूप में चिह्नित किया जा रहा है, शायद इसलिए कि यह बहुत कम है। वर्तमान में यह हमारे मानकों के जवाब की तुलना में अधिक टिप्पणी है। क्या आप इसका विस्तार कर सकते हैं? हम इसे टिप्पणी में भी बदल सकते हैं।
गुंग - को पुनः स्थापित मोनिका

यह एक जवाब के बजाय एक स्पष्ट टिप्पणी की तरह लगता है। यह सवाल में एक संपादित किया जाना चाहिए?
गुंग - को पुनः स्थापित मोनिका

@ गंग, मेरे जवाब को संशोधित किया। आशा करता हूँ की ये काम करेगा।
हैलो वर्ल्ड

0

दो मनमाने ढंग से लंबाई अनुक्रमों के जेएस विचलन का स्काला संस्करण:

def entropy(dist: WrappedArray[Double]) = -(dist.filter(_ != 0.0).map(i => i * Math.log(i)).sum)


val jsDivergence = (dist1: WrappedArray[Double], dist2: WrappedArray[Double]) => {
    val weights = 0.5 //since we are considering inly two sequences
    val left = dist1.zip(dist2).map(x => x._1 * weights + x._2 * weights)
    // println(left)
    // println(entropy(left))
    val right = (entropy(dist1) * weights) + (entropy(dist2) * weights)
    // println(right)
    entropy(left) - right

}

jsDivergence(Array(0.5,0.5,0), Array(0,0.1,0.9))

res0: Double = 0.557978817900054

इस प्रश्न को कोड को प्रश्न संपादित अनुभाग में कोड के साथ जांचें:

jsd([np.array([0.5,0.5,0]), np.array([0,0.1,0.9])])
0.55797881790005399

0

एक सामान्य संस्करण, n प्रायिकता वितरण के लिए, विकिपीडिया सूत्र में पायथन में और इस पोस्ट में वेटर्स ( pi ) के पैरामीटर और कस्टम लॉगबेस के रूप में टिप्पणियों के साथ :

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


def JSD(prob_distributions, weights, logbase=2):
    # left term: entropy of mixture
    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
    # wentropies = np.dot(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))

.५४६६२१३१९४४६

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.