3 প্রো বিতরণের জন্য জেনসন-শ্যানন ডাইভার্জেন্স গণনা: এটি কি ঠিক আছে?


12

আমি তার 3 টি বিতরণ অনুসরণ করার জন্য জেনসেন-শ্যানন ডাইভার্জেন্স গণনা করতে চাই। নীচের হিসাবটি কি সঠিক? (আমি উইকিপিডিয়া থেকে জেএসডি সূত্র অনুসরণ করেছি ):

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
ভাল পাইথন কোড ওয়ে!
gui11aume

উত্তর:


13

মিশ্রণ বিতরণে ভুল রয়েছে। এটি হওয়া উচিত পরিবর্তে যা 1 এর সমান নয় । আপনার অন্যান্য এনট্রপি শর্তাবলী ভুল।( 1 / 6 , 1 / 5 , 9 / 30 )(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 = 0.378889


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
হুশিয়ার

1
এত নোংরা নয় ... ;-)
gui11aume

4
(1) গণিতটি আবার করুন। (২) আপনি যতক্ষণ না সামঞ্জস্য থাকুন ততক্ষণ আপনার পছন্দ মতো লোগারিথমের কোনও বেস ব্যবহার করে এন্ট্রপি পরিমাপ করা যেতে পারে। প্রাকৃতিক, সাধারণ এবং বেস -2 লগগুলি প্রচলিত। (3) এটি সত্যিই বিতরণ এবং তাদের গড়ের মধ্যে গড় পার্থক্য। আপনি যদি প্রতিটি বিতরণকে একটি বিন্দু হিসাবে মনে করেন তবে তারা মেঘ গঠন করে। আপনি মেঘের কেন্দ্র এবং এর পয়েন্টগুলির মাঝে গড় "দূরত্ব" দেখছেন, এক ধরণের গড় ব্যাসার্ধের মতো। স্বজ্ঞাতভাবে, এটি মেঘের আকার পরিমাপ করে।
হোয়াট

1
@ কিংবদন্তি আমি মনে করি আপনি ঠিক বলেছেন। আমি অন্য পরীক্ষায় যে উত্তর পেয়েছি তার সাথে একমত হয়েছিল বলে আবিষ্কার করার পরে আমি পর্যাপ্ত পরীক্ষা করিনি ( ম্যাথমেটিকার সাথে )।
whuber

1
@dmck আমার মন্তব্যে প্রকৃতপক্ষে টাইপগুলি রয়েছে: (1) এই শব্দগুচ্ছটি h <- function(x) {দুটি বার আটকানো হয়েছিল। কেবল এটি মুছুন: অন্য সবকিছু কাজ করে এবং আমি উদ্ধৃত করা ফলাফলগুলি উত্পাদন করে। তারপর সংশোধন apply(p, 2, h)করতে apply(p, 1, h)যেমন নির্দিষ্ট Legend দ্বারা মন্তব্যে
শুক্র

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

সাধারণ সংস্করণ, জন্য এন সম্ভাব্যতা ডিস্ট্রিবিউশন, পাইথন উইকিপিডিয়ার সূত্র এবং ওজন (এর ভেক্টর সাথে এই পোস্টটি মন্তব্য ভিত্তিক পাই ) পরামিতি এবং কাস্টম যেমন logbase :

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))

0,546621319446

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.