Pregunta

Soy bastante nuevo en esto y no puedo decir que tenga una comprensión completa de los conceptos teóricos detrás de esto. Estoy tratando de calcular la divergencia KL entre varias listas de puntos en Python. estoy usando http://scikit-learn.org/stable/modules/generated/sklearn.metrics.mutual_info_score.html para intentar hacer esto. El problema con el que me estoy encontrando es que el valor devuelto es el mismo para las 2 listas de números (su 1.3862943611198906). Tengo la sensación de que estoy cometiendo algún tipo de error teórico aquí, pero no puedo detectarlo.

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

Ese es un ejemplo de lo que estoy ejecutando, solo que obtengo la misma salida para cualquier entrada de 2. ¡Se agradecería cualquier consejo/ayuda!

¿Fue útil?

Solución

Ante todo, sklearn.metrics.mutual_info_score implementos información mutua para evaluar los resultados de la agrupación, no puro ¡Divergencia Kullback-Lebler!

Esto es igual a la divergencia de Kullback-Leibbler de la distribución conjunta con la distribución del producto de los marginales.

Divergencia de KL (y cualquier otra medida similar) espera que los datos de entrada tener una suma de 1. De lo contrario, son no correcto distribuciones de probabilidad. Si sus datos no tienen una suma de 1, lo más probable es que generalmente no sea apropiado usar divergencia KL. (En algunos casos, puede ser admisible tener una suma de menos de 1, por ejemplo, en el caso de los datos faltantes).

También tenga en cuenta que es común usar logaritmos Base 2. Esto solo produce un factor de escala constante en la diferencia, pero los logaritmos Base 2 son más fáciles de interpretar y tienen una escala más intuitiva (0 a 1 en lugar de 0 a Log2 = 0.69314 ..., midiendo la información en bits en lugar de nats).

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

Como podemos ver claramente, el resultado de MI de Sklearn se escala utilizando logaritmos naturales en lugar de log2. Esta es una elección desafortunada, como se explicó anteriormente.

La divergencia de Kullback-Leíbler es frágil, desafortunadamente. En el ejemplo anterior no está bien definido: KL([0,1],[1,0]) causa una división por cero y tiende al infinito. Tambien es asimétrico.

Otros consejos

Scipy función de entropía Calculará la divergencia de KL si alimenta dos vectores P y Q, cada uno representando una distribución de probabilidad. Si los dos vectores no son PDFS, se normalizará y luego primero.

La información mutua es relacionado con, pero no lo mismo como KL Divergencia.

"Esta información mutua ponderada es una forma de divergencia KL ponderada, que se sabe que toma valores negativos para algunas entradas, y hay ejemplos en los que la información mutua ponderada también toma valores negativos"

No estoy seguro con la implementación de Scikitlearn, pero aquí hay una implementación rápida de la divergencia KL en 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)

Producción: 0.775279624079

Podría haber conflicto de implementación En algunas bibliotecas, asegúrese de leer sus documentos antes de usar.

Este truco evita el código condicional y, por lo tanto, puede proporcionar un mejor rendimiento.

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

Considere las tres muestras siguientes de una (s) distribución (s).

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

Claramente, los valores1 y los valores2 están más cerca, por lo que esperamos la medida de surprise o entropía, para ser más bajo en comparación con los valores3.

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

Vemos la siguiente salida:

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

Vemos que esto tiene sentido porque los valores entre los valores1 y los valores 3 y los valores 2 y los valores 3 son simplemente más drásticos en el cambio que los valores1 a los valores 2. Esta es mi validación para comprender KL-D y los paquetes que se pueden aprovechar para ello.

Licenciado bajo: CC-BY-SA con atribución
scroll top