파이썬에서 KL 분기 계산


22

나는 이것에 익숙하지 않으며 이것 뒤에 이론적 개념을 완전히 이해하고 있다고 말할 수 없습니다. 파이썬에서 여러 포인트 목록 사이의 KL 분기를 계산하려고합니다. 이것을 시도하기 위해 http://scikit-learn.org/stable/modules/generated/sklearn.metrics.mutual_info_score.html 을 사용 하고 있습니다. 내가 겪고있는 문제는 반환 된 값이 두 숫자 목록 (1.3862943611198906)과 동일하다는 것입니다. 나는 여기서 어떤 종류의 이론적 실수를 저지르고 있지만 그것을 발견 할 수 없다고 생각합니다.

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

이것이 내가 실행중인 것의 예입니다-2 개의 입력에 대해 동일한 출력을 얻는다는 것입니다. 조언이나 도움을 주시면 감사하겠습니다.


KL이란, Kullback-Leibler 발산을 의미합니까?
Dawny33

그렇습니다.
Nanda

실행함으로써 sklearn.metrics.mutual_info_score([1.346112,1.337432,1.246655], [1.033836,1.082015,1.117323])나는 가치를 얻는다 1.0986122886681096.
Dawny33

죄송합니다. values1을 [1, 1.346112,1.337432,1.246655]로 사용하고 values2를 [1,1.033836,1.082015,1.117323]으로 value2를 사용하여 차이 값을 사용했습니다.
Nanda

답변:


18

우선 순수한 Kullback-Leibler 분기가 아닌 클러스터링 결과를 평가하기위한 상호 정보sklearn.metrics.mutual_info_score구현합니다 !

이는 한계 분포의 생산 분포와 결합 분포의 Kullback-Leibler 분기와 같습니다.

KL 발산 (및 기타 측정 값)은 입력 데이터 의 합이 1 일 것으로 예상합니다 . 그렇지 않으면 적절한 확률 분포아닙니다 . 데이터의 합이 1이 아닌 경우 대개 KL 분기를 사용하는 것이 적절하지 않습니다! (예를 들어 데이터가 누락 된 경우) 합계가 1 미만인 것이 허용 될 수 있습니다.

또한 밑이 2 인 로그를 사용하는 것이 일반적입니다. 이것은 단지 일정한 스케일링 계수 차이를 가져 오지만, 기본 2 로그는 해석하기 쉽고보다 직관적 인 스케일을 갖습니다 (0에서 log2 = 0.69314 대신 0에서 1로 nat 대신 비트로 정보를 측정).

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

우리가 명확하게 볼 수 있듯이 sklearn의 MI 결과는 log2 대신 자연 로그를 사용하여 조정됩니다. 위에서 설명한 것처럼 이것은 불행한 선택입니다.

Kullback-Leibler 발산은 불행히도 깨지기 쉽습니다. 위의 예에서는 잘 정의되어 있지 않습니다. KL([0,1],[1,0])0으로 나누고 무한대 경향이 있습니다. 또한 비대칭 입니다.


때 참고 scipy.stats.entropy사용, 그것은 하나에 확률을 정상화됩니다. 문서에서 ( scipy.github.io/devdocs/generated/scipy.stats.entropy.html ) : "이 루틴은 pk 및 qk가 1이 아닌 경우 정규화합니다."
Itamar Mushkin

15

Scipy의 엔트로피 함수 는 각각 확률 분포를 나타내는 두 개의 벡터 p와 q를 공급하면 KL 발산을 계산합니다. 두 벡터가 pdf가 아닌 경우 먼저 정규화됩니다.

상호 정보는 KL Divergence 와 관련이 있지만 KL Divergence 와 동일하지는 않습니다 .

"이 가중 된 상호 정보는 일부 입력에 대해 음의 값을 취하는 것으로 알려진 가중 KL-Divergence의 한 형태이며, 가중 된 상호 정보도 음의 값을 취하는 예가 있습니다"


6

ScikitLearn 구현에 대해서는 잘 모르겠지만 다음은 Python에서 KL 분기의 빠른 구현입니다.

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)

산출: 0.775279624079

일부 라이브러리에서는 구현충돌 할 수 있으므로 사용하기 전에 해당 문서를 읽으십시오.


1
나도 이것을 시도했지만 이것은 유효한 값이 아닌 음수 값을 반환하고 있다고 생각합니다. 그런 다음 약간의 연구를 통해이 결과 mathoverflow.net/questions/43849/…에 도달 했습니다.이 결과 는 입력이 확률 분포 여야하는 방법에 대해 설명합니다. 내가 실수 한 곳인 것 같아
난다

@Nanda 링크 주셔서 감사합니다. 0.775279624079입력에 대한 광산 반환 및 sklearn 메트릭 반환 1.3862943611198906. 아직도 혼란스러워! 그러나 qn에 따른 값 검사를 스크립트에 포함시키는 것처럼 보입니다 :)
Dawny33

1
무슨 말인지 알 겠어! 나는 결과가 "느끼지 않았다"는 것 사이에 공통적 인 3 가지 값을 얻기 위해 3 가지 기능을 시도했습니다. 입력 값은 논리적 오류이므로 내 접근 방식을 완전히 변경하십시오!
Nanda

@ Nanda Ahh, 그것은 분명합니다 :) 설명해 주셔서 감사합니다
Dawny33

2

이 트릭은 조건부 코드를 피하므로 더 나은 성능을 제공 할 수 있습니다.

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

좋은 트릭! 시간 벤치 마크에서 이것이 다른 솔루션과 어떻게 비교되는지 알고 싶습니다.
surelyourejoking

0

분포에서 다음 세 가지 표본을 고려하십시오.

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

분명히 values1과 values2는 더 가깝기 때문에 우리는 surprisevalues3과 비교할 때 측정 또는 엔트로피가 더 낮을 것으로 예상합니다 .

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

다음과 같은 결과가 나타납니다.

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

값 1과 값 3과 값 2와 값 3 사이의 값이 값 1과 값 2 사이의 변화보다 더 급격히 변하기 때문에 이것이 의미가 있음을 알 수 있습니다. 이것은 KL-D와이를 활용할 수있는 패키지를 이해하는 나의 검증입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.