18 votes

Information mutuelle continue en Python

[Frontmatter] (sautez cette étape si vous ne voulez que la question) :

J'envisage actuellement d'utiliser Information mutuelle Shannon-Weaver y redondance normalisée pour mesurer le degré de masquage de l'information entre des sacs de valeurs de caractéristiques discrètes et continues, organisés par caractéristique. En utilisant cette méthode, mon objectif est de construire un algorithme qui ressemble beaucoup à ID3 mais au lieu d'utiliser entropie de Shannon l'algorithme cherchera (en tant que contrainte de boucle) à maximiser ou minimiser l'information partagée entre une seule caractéristique et une collection de caractéristiques basées sur l'espace complet des caractéristiques d'entrée, en ajoutant de nouvelles caractéristiques à cette dernière collection si (et seulement si) elles augmentent ou diminuent l'information mutuelle, respectivement. En fait, cela déplace l'algorithme de décision d'ID3 dans l'espace des paires, en y agrafant une approche d'ensemble avec toutes les complexités temporelles et spatiales attendues des deux méthodes.

[/Frontmatter]

Venons-en à la question : J'essaye d'obtenir un continu intégrateur travailler en Python en utilisant SciPy . Étant donné que je travaille avec des comparaisons de variables discrètes et continues, ma stratégie actuelle pour chaque comparaison de paires de caractéristiques est la suivante :

  • Caractéristique discrète contre caractéristique discrète : utiliser la forme discrète de l'information mutuelle. Cela entraîne une double sommation des probabilités, que mon code gère sans problème.

  • Tous les autres cas (discret contre continu, l'inverse et continu contre continu) : utiliser la forme continue, en utilisant un Estimateur gaussien pour lisser le fonctions de densité de probabilité .

Il m'est possible d'effectuer une sorte de discrétisation pour ces derniers cas, mais comme mes ensembles de données d'entrée ne sont pas intrinsèquement linéaires, cela pourrait être inutilement complexe.

Voici le code le plus important :

import math
import numpy
import scipy
from scipy.stats import gaussian_kde
from scipy.integrate import dblquad

# Constants
MIN_DOUBLE = 4.9406564584124654e-324 
                    # The minimum size of a Float64; used here to prevent the
                    #  logarithmic function from hitting its undefined region
                    #  at its asymptote of 0.
INF = float('inf')  # The floating-point representation for "infinity"

# x and y are previously defined as collections of 
# floating point values with the same length

# Kernel estimation
gkde_x = gaussian_kde(x)
gkde_y = gaussian_kde(y)

if len(binned_x) != len(binned_y) and len(binned_x) != len(x):
    x.append(x[0])
    y.append(y[0])

gkde_xy = gaussian_kde([x,y])
mutual_info = lambda a,b: gkde_xy([a,b]) * \
           math.log((gkde_xy([a,b]) / (gkde_x(a) * gkde_y(b))) + MIN_DOUBLE)

# Compute MI(X,Y)
(minfo_xy, err_xy) = \
    dblquad(mutual_info, -INF, INF, lambda a: 0, lambda a: INF)

print 'minfo_xy = ', minfo_xy

Notez que le surcomptage d'un seul point est fait délibérément pour éviter une singularité dans la fonction de SciPy kde gaussien classe. Au fur et à mesure que la taille de x et y s'approche de l'infini, cet effet devient négligeable.

Mon problème actuel est d'essayer d'obtenir intégration multiple travaillant contre un Estimation de la densité du noyau gaussien dans SciPy. J'ai essayé d'utiliser la fonction SciPy dblquad pour effectuer l'intégration, mais dans ce dernier cas, je reçois une avalanche stupéfiante des messages suivants.

Quand j'ai mis numpy.seterr ( all='ignore' ) :

Avertissement : L'ocurrence d'erreur d'arrondi est détectée, ce qui empêche la tolérance demandée d'être atteinte. L'erreur peut être sous-estimée.

Et quand je l'ai réglé sur 'call' en utilisant un gestionnaire d'erreurs :

Erreur de virgule flottante (underflow), avec drapeau 4

Erreur de virgule flottante (valeur invalide), avec drapeau 8

Plutôt facile de comprendre ce qui se passe, non ? Eh bien, presque : IEEE 754-2008 et SciPy me disent seulement ce qui se passe ici, pas pourquoi ou comment le contourner .

Le résultat : minfo_xy se résout généralement à nan ; son échantillonnage est insuffisant pour éviter la perte ou l'invalidité d'informations lors de l'exécution de calculs en Float64.

Existe-t-il une solution générale pour résoudre ce problème lorsque vous utilisez SciPy ?

Encore mieux : S'il existe une implémentation robuste et standardisée de l'information mutuelle continue pour Python avec une interface qui prend deux collections de valeurs à virgule flottante ou une collection fusionnée de paires, cela résoudrait ce problème complet. Veuillez créer un lien si vous en connaissez un.

Merci d'avance.


Edit : cela résout le problème de nan problème de propagation dans l'exemple ci-dessus :

mutual_info = lambda a,b: gkde_xy([a,b]) * \
    math.log((gkde_xy([a,b]) / ((gkde_x(a) * gkde_y(b)) + MIN_DOUBLE)) \
        + MIN_DOUBLE)

Cependant, la question de la correction des arrondis reste posée, tout comme la demande d'une mise en œuvre plus robuste. Toute aide dans l'un ou l'autre domaine serait grandement appréciée.

4voto

Raymond Hettinger Points 50330

Avant d'essayer des solutions plus radicales comme le recadrage du problème ou l'utilisation de différents outils d'intégration, voyez si cela peut vous aider. Remplacer INF=float('INF') con INF=1E12 ou un autre grand nombre - qui peut éliminer NaN les résultats créés par de simples opérations arithmétiques sur les variables d'entrée.

Je ne vous promets rien sur ce point, mais il est parfois utile d'essayer une solution rapide avant de s'engager dans une réécriture algorithmique importante ou dans le remplacement d'autres outils.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X