Python'da KL Ayrışmasının Hesaplanması


22

Bunun için yeniyim ve bunun arkasındaki teorik kavramları tam olarak anladığımı söyleyemem. Python'daki birkaç nokta listesi arasındaki KL Diverjansını hesaplamaya çalışıyorum. Bunu denemek ve yapmak için http://scikit-learn.org/stable/modules/generated/sklearn.metrics.mutual_info_score.html adresini kullanıyorum . Karşılaştığım sorun, döndürülen değerin 2 sayı listesi için aynı olması (bunun 1.3862943611198906). Burada bir çeşit teorik hata yapıyorum ama farkedemiyorum.

values1 = [1.346112,1.337432,1.246655]
values2 = [1.033836,1.082015,1.117323]
metrics.mutual_info_score(values1,values2)

Bu neye çalıştığımın bir örneği - sadece herhangi bir 2 giriş için aynı çıktıyı alıyorum. Herhangi bir öneri / yardım takdir edilecektir!


KL, Kullback-Leibler ıraksama demek istiyorsun?
Dawny33

Evet, aynen öyle!
Nanda

Koşarak sklearn.metrics.mutual_info_score([1.346112,1.337432,1.246655], [1.033836,1.082015,1.117323]), değeri alıyorum 1.0986122886681096.
Dawny33

Maalesef, 1 değerini [1, 1.346112,1.337432,1.246655] ve 2 değerini 2 olarak [1,1.033836,1.082015,1,17323] olarak kullandım ve dolayısıyla fark değerini kullandım.
Nanda,

Yanıtlar:


18

Her şeyden önce, sklearn.metrics.mutual_info_scoreuygular karşılıklı bilgi kümeleme sonuçları değerlendirmek için değil, saf Kullback-Leibler sapma!

Bu, Kullback-Leibler’in, marjinallerin ürün dağılımı ile birlikte eklem dağılımının farklılığına eşittir.

KL farklılaşması (ve bu tür başka herhangi bir önlem) giriş verilerinin toplamın 1 olmasını bekler . Aksi takdirde, uygun olasılık dağılımları değildir . Verilerinizin toplamı 1 değilse, büyük olasılıkla KL sapma kullanmak uygun değildir! (Bazı durumlarda, örneğin eksik veri olması durumunda 1'den daha az bir miktara sahip olmak kabul edilebilir.)

Ayrıca, baz 2 logaritmalarının kullanılmasının yaygın olduğuna dikkat edin. Bu, sadece fark olarak sabit bir ölçeklendirme faktörü verir, ancak temel 2 logaritmalarının yorumlanması daha kolaydır ve daha sezgisel bir ölçeğe sahiptir (0'dan log2 yerine 0 - 1 = 0.69314 ... bilgiyi nats yerine bit cinsinden ölçerek).

> sklearn.metrics.mutual_info_score([0,1],[1,0])
0.69314718055994529

Gördüğümüz gibi sklearn'ün MI sonucu log2 yerine doğal logaritmalar kullanılarak ölçeklendirilir. Bu yukarıda açıklandığı gibi talihsiz bir seçimdir.

Kullback-Leibler ıraksaklığı ne yazık ki kırılgan. Yukarıdaki örnekte iyi tanımlanmamıştır: KL([0,1],[1,0])sıfıra bölünmeye neden olur ve sonsuzluğa meyillidir. Aynı zamanda asimetriktir .


Ne zaman geldiğini hatırlatırız scipy.stats.entropykullanılır, bu birine olasılıkları düzeni sağlayacaktır. Belgelerden ( scipy.github.io/devdocs/generated/scipy.stats.entropy.html ): "Bu rutin pk ve qk'yi 1'e toplamazlarsa normalleştirir."
Itamar Mushkin

15

Scipy'nin entropi işlevi , her biri bir olasılık dağılımını temsil eden iki vektör p ve q beslerse KL ayrışmasını hesaplar. İki vektör pdfs değilse, önce normalleşir.

Karşılıklı bilgi KL Divergence ile aynıdır, ancak aynı değildir .

"Bu ağırlıklı karşılıklı bilgi, bazı girdiler için negatif değerler aldığı bilinen, ağırlıklı bir KL-Diverjans şeklidir ve ağırlıklı karşılıklı bilginin de negatif değerler aldığı örnekler vardır"


6

ScikitLearn uygulamasından emin değilim, ancak işte Python'daki KL ayrışmasının hızlı bir uygulaması:

import numpy as np

def KL(a, b):
    a = np.asarray(a, dtype=np.float)
    b = np.asarray(b, dtype=np.float)

    return np.sum(np.where(a != 0, a * np.log(a / b), 0))


values1 = [1.346112,1.337432,1.246655]
values2 = [1.033836,1.082015,1.117323]

print KL(values1, values2)

Çıktı: 0.775279624079

Bazı kütüphanelerde uygulama çakışması olabilir , bu yüzden kullanmadan önce dokümanlarını okuduğunuzdan emin olun.


1
Bunu da denedim ama bu, geçerli bir değer olmadığını düşünüyorum, negatif değerler döndürüyordu. Daha sonra biraz araştırma yaptım bu sonuç beni mathoverflow.net/questions/43849/… 'ye getirdi ve bu da girdilerin olasılık dağılımının nasıl olması gerektiği hakkında konuşuyor. Sanırım hatamı burada yaptım.
Nanda

@Nanda Link için teşekkürler. Maden 0.775279624079girdileriniz için döner ve sklearn metrikleri geri döner 1.3862943611198906. Hala karıştı! Ancak,
qn'ye

1
Ne demek istediğini biliyorum! Sonuçta "doğru" hissetmemek olduğu için ortak olan tek şey ile 3 farklı değer elde etmek için 3 farklı işlevi denedim. Giriş değerleri kesinlikle mantıklı bir hatadır, bu yüzden yaklaşımımı tamamen değiştirmek!
Nanda

@Nanda Ahh, şimdi açık :) Açıklama için teşekkürler
Dawny33

2

Bu numara koşullu koddan kaçınır ve bu nedenle daha iyi performans sağlayabilir.

import numpy as np

def KL(P,Q):
""" Epsilon is used here to avoid conditional code for
checking that neither P nor Q is equal to 0. """
     epsilon = 0.00001

     # You may want to instead make copies to avoid changing the np arrays.
     P = P+epsilon
     Q = Q+epsilon

     divergence = np.sum(P*np.log(P/Q))
     return divergence

# Should be normalized though
values1 = np.asarray([1.346112,1.337432,1.246655])
values2 = np.asarray([1.033836,1.082015,1.117323])

# Note slight difference in the final result compared to Dawny33
print KL(values1, values2) # 0.775278939433

İyi numara! Bunun bir zaman ölçütünde diğer çözümle nasıl karşılaştırıldığını görmek isterim.
kesinlikle

0

Bir dağıtımdan aşağıdaki üç örneği göz önünde bulundurun.

values1 = np.asarray([1.3,1.3,1.2])
values2 = np.asarray([1.0,1.1,1.1])
values3 = np.array([1.8,0.7,1.7])

Açıkçası, değerler1 ve değerler2 daha yakındır, bu yüzden ölçünün surpriseveya entropinin ölçüsünün değerler 3 ile karşılaştırıldığında daha düşük olmasını bekliyoruz.

from scipy.stats import entropy
print("\nIndividual Entropy\n")
print(entropy(values1))
print(entropy(values2))
print(entropy(values3))

print("\nPairwise Kullback Leibler divergence\n")
print(entropy(values1, qk=values2))
print(entropy(values1, qk=values3))
print(entropy(values2, qk=values3))

Aşağıdaki çıktıyı görüyoruz:

Individual Entropy

1.097913446793334
1.0976250611902076
1.0278436769863724 #<--- this one had the lowest, but doesn't mean much.

Pairwise Kullback Leibler divergence

0.002533297351606588
0.09053972625203921 #<-- makes sense
0.09397968199352116 #<-- makes sense

Bunun mantıklı olduğunu görüyoruz, çünkü değerler1 ve değerler3 ile değerler 2 ve değerler 3 arasındaki değerler, değer1'den değer 2'ye göre değişimden çok daha şiddetlidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.