Tính toán phân kỳ KL trong Python


22

Tôi còn khá mới mẻ với điều này và không thể nói rằng tôi hoàn toàn hiểu về các khái niệm lý thuyết đằng sau điều này. Tôi đang cố gắng tính phân kỳ KL giữa một số danh sách các điểm trong Python. Tôi đang sử dụng http://scikit-learn.org/urdy/modules/generated/sklearn.metrics.mutual_info_score.html để thử và làm điều này. Vấn đề mà tôi gặp phải là giá trị được trả về là giống nhau cho bất kỳ 2 danh sách số nào (1.3862943611198906). Tôi có cảm giác rằng tôi đang mắc một số sai lầm lý thuyết ở đây nhưng không thể phát hiện ra.

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

Đó là một ví dụ về những gì tôi đang chạy - chỉ là tôi đang nhận được cùng một đầu ra cho bất kỳ 2 đầu vào nào. Bất kỳ lời khuyên / giúp đỡ sẽ được đánh giá cao!


Theo KL, bạn có nghĩa là phân kỳ Kullback-Leibler?
Dawny33

Vâng, chính xác đó!
Nanda

Bằng cách chạy sklearn.metrics.mutual_info_score([1.346112,1.337432,1.246655], [1.033836,1.082015,1.117323]), tôi nhận được giá trị 1.0986122886681096.
Dawny33

Xin lỗi, tôi đã sử dụng các giá trị1 là [1, 1.346112,1.337432,1.246655] và giá trị2 là giá trị2 là [1,1.033836,1.082015,1.117323] và do đó giá trị chênh lệch.
Nanda

Câu trả lời:


18

Trước hết, sklearn.metrics.mutual_info_scorethực hiện thông tin lẫn nhau để đánh giá kết quả phân cụm, chứ không phải phân kỳ Kullback-Leibler thuần túy !

Điều này tương đương với phân kỳ Kullback-Leibler của phân phối chung với phân phối sản phẩm của các lề.

Phân kỳ KL (và bất kỳ biện pháp nào khác) mong muốn dữ liệu đầu vào có tổng bằng 1 . Mặt khác, chúng không phảiphân phối xác suất thích hợp . Nếu dữ liệu của bạn không có tổng bằng 1, rất có thể việc sử dụng phân kỳ KL là không phù hợp! (Trong một số trường hợp, có thể chấp nhận có tổng nhỏ hơn 1, ví dụ trong trường hợp thiếu dữ liệu.)

Cũng lưu ý rằng thông thường sử dụng logarit cơ sở 2. Điều này chỉ mang lại một hệ số tỷ lệ không đổi khác nhau, nhưng logarit cơ sở 2 dễ hiểu hơn và có thang đo trực quan hơn (0 đến 1 thay vì 0 đến log2 = 0,69314 ..., đo thông tin theo bit thay vì nats).

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

như chúng ta có thể thấy rõ, kết quả MI của sklearn được chia tỷ lệ bằng cách sử dụng logarit tự nhiên thay vì log2. Đây là một lựa chọn không may, như đã giải thích ở trên.

Thật không may, phân kỳ Kullback-Leibler rất mong manh. Trong ví dụ trên, nó không được xác định rõ: KL([0,1],[1,0])gây ra sự phân chia bằng 0 và có xu hướng vô cùng. Nó cũng không đối xứng .


Lưu ý rằng khi scipy.stats.entropyđược sử dụng, nó sẽ bình thường hóa xác suất thành một. Từ các tài liệu ( scipy.github.io/devdocs/generated/scipy.stats.entropy.html ): "Thói quen này sẽ bình thường hóa pk và qk nếu chúng không tổng hợp thành 1."
Nấm Itamar

15

Hàm entropy của Scipy sẽ tính toán phân kỳ KL nếu cung cấp hai vectơ p và q, mỗi vectơ đại diện cho một phân phối xác suất. Nếu hai vectơ không phải là pdf, nó sẽ bình thường hóa trước.

Thông tin lẫn nhau có liên quan đến, nhưng không giống với Phân kỳ KL.

"Thông tin lẫn nhau có trọng số này là một dạng của Phân kỳ KL có trọng số, được biết là lấy giá trị âm cho một số đầu vào, và có những ví dụ trong đó thông tin lẫn nhau có trọng số cũng lấy giá trị âm"


6

Tôi không chắc chắn với việc triển khai ScikitLearn, nhưng đây là một triển khai nhanh về phân kỳ KL trong Python:

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)

Đầu ra: 0.775279624079

Có thể có xung đột triển khai trong một số thư viện, vì vậy hãy đảm bảo bạn đã đọc tài liệu của họ trước khi sử dụng.


1
Tôi cũng đã thử điều này nhưng điều này đã trả về các giá trị âm mà theo tôi không phải là giá trị hợp lệ. Một chút nghiên cứu sau đó đã đưa tôi đến kết quả mathoverflow.net/questions/43849/ này nói về cách đầu vào phải là một phân phối xác suất. Đoán đó là nơi tôi đã phạm sai lầm của tôi.
Nanda

@Nanda Cảm ơn đã liên kết. Trả về của tôi 0.775279624079cho đầu vào của bạn và trả về số liệu sklearn 1.3862943611198906. Bối rối vẫn còn! Nhưng, có vẻ như bao gồm các kiểm tra giá trị theo qn, vào kịch bản nên làm :)
Dawny33

1
Tôi hiểu bạn muốn nói gì! Tôi đã thử 3 chức năng khác nhau để có được 3 giá trị khác nhau với điểm chung duy nhất giữa chúng là kết quả không "cảm thấy" đúng. Các giá trị đầu vào chắc chắn là một lỗi logic vì vậy thay đổi hoàn toàn cách tiếp cận của tôi!
Nanda

@Nanda Ahh, giờ thì rõ rồi :) Cảm ơn bạn đã giải thích
Dawny33

2

Thủ thuật này tránh mã có điều kiện và do đó có thể cung cấp hiệu suất tốt hơn.

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

Bí quyết đẹp! Tôi muốn biết làm thế nào để so sánh với giải pháp khác trên điểm chuẩn thời gian.
chắc chắn là

0

Hãy xem xét ba mẫu sau từ một (các) phân phối.

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

Rõ ràng, giá trị1 và giá trị2 gần hơn, vì vậy chúng tôi hy vọng số đo surprisehoặc entropy sẽ thấp hơn khi so sánh với giá trị3.

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

Chúng tôi thấy đầu ra sau đây:

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

Chúng tôi thấy điều này có ý nghĩa bởi vì các giá trị giữa giá trị1 và giá trị 3 và giá trị 2 và giá trị 3 đơn giản là thay đổi mạnh hơn giá trị1 thành giá trị 2. Đây là xác thực của tôi để hiểu về KL-D và các gói có thể được sử dụng cho nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.