Pour une matrice mxn , quelle est la façon optimale (la plus rapide) de calculer les informations mutuelles pour toutes les paires de colonnes ( nxn )?
Par information mutuelle , je veux dire:
I (X, Y) = H(X) + H(Y) - H (X, Y)
où H (X) fait référence à l'entropie de Shannon de [~ # ~] x [~ # ~] .
J'utilise actuellement np.histogram2d
et np.histogram
pour calculer l'articulation (X, Y) et individuelle (X ou Y) compte. Pour une matrice donnée A
(par exemple une matrice de flottants 250000 X 1000), je fais une boucle imbriquée for
,
n = A.shape[1]
for ix = arange(n)
for jx = arange(ix+1,n):
matMI[ix,jx]= calc_MI(A[:,ix],A[:,jx])
Il doit sûrement y avoir des moyens meilleurs/plus rapides de le faire?
En passant, j'ai également cherché des fonctions de mappage sur les colonnes (opérations colonne par ligne ou ligne par ligne) sur les tableaux, mais je n'ai pas encore trouvé de bonne réponse générale.
Voici mon implémentation complète, en suivant les conventions de la page Wiki :
import numpy as np
def calc_MI(X,Y,bins):
c_XY = np.histogram2d(X,Y,bins)[0]
c_X = np.histogram(X,bins)[0]
c_Y = np.histogram(Y,bins)[0]
H_X = shan_entropy(c_X)
H_Y = shan_entropy(c_Y)
H_XY = shan_entropy(c_XY)
MI = H_X + H_Y - H_XY
return MI
def shan_entropy(c):
c_normalized = c / float(np.sum(c))
c_normalized = c_normalized[np.nonzero(c_normalized)]
H = -sum(c_normalized* np.log2(c_normalized))
return H
A = np.array([[ 2.0, 140.0, 128.23, -150.5, -5.4 ],
[ 2.4, 153.11, 130.34, -130.1, -9.5 ],
[ 1.2, 156.9, 120.11, -110.45,-1.12 ]])
bins = 5 # ?
n = A.shape[1]
matMI = np.zeros((n, n))
for ix in np.arange(n):
for jx in np.arange(ix+1,n):
matMI[ix,jx] = calc_MI(A[:,ix], A[:,jx], bins)
Bien que ma version de travail avec des boucles imbriquées for
le fasse à une vitesse raisonnable, j'aimerais savoir s'il existe un moyen plus optimal d'appliquer calc_MI
sur toutes les colonnes de A
(pour calculer leurs informations mutuelles par paire)?
J'aimerais aussi savoir:
Existe-t-il des moyens efficaces de mapper les fonctions pour qu'elles fonctionnent sur les colonnes (ou lignes) de np.arrays
(peut-être comme np.vectorize
, qui ressemble plus à un décorateur)?
Existe-t-il d'autres implémentations optimales pour ce calcul spécifique (informations mutuelles)?
Je ne peux pas suggérer un calcul plus rapide pour la boucle externe sur les vecteurs n * (n-1)/2, mais votre implémentation de calc_MI(x, y, bins)
peut être simplifiée si vous pouvez utiliser scipy version 0.13 ou scikit-learn .
Dans 0.13 scipy, le lambda_
l'argument a été ajouté à scipy.stats.chi2_contingency
Cet argument contrôle la statistique calculée par la fonction. Si tu utilises lambda_="log-likelihood"
(ou lambda_=0
), le rapport log-vraisemblance est renvoyé. Ceci est aussi souvent appelé le G ou G2 statistique. Autre qu'un facteur de 2 * n (où n est le nombre total d'échantillons dans le tableau de contingence), c'est c'est l'information mutuelle. Vous pouvez donc implémenter calc_MI
comme:
from scipy.stats import chi2_contingency
def calc_MI(x, y, bins):
c_xy = np.histogram2d(x, y, bins)[0]
g, p, dof, expected = chi2_contingency(c_xy, lambda_="log-likelihood")
mi = 0.5 * g / c_xy.sum()
return mi
La seule différence entre cela et votre implémentation est que cette implémentation utilise le logarithme naturel au lieu du logarithme en base 2 (elle exprime donc les informations en "nats" au lieu de "bits"). Si vous préférez vraiment les bits, divisez simplement mi
par log (2).
Si vous avez (ou pouvez installer) sklearn
(c'est-à-dire scikit-learn), vous pouvez utiliser sklearn.metrics.mutual_info_score
, et implémentez calc_MI
comme:
from sklearn.metrics import mutual_info_score
def calc_MI(x, y, bins):
c_xy = np.histogram2d(x, y, bins)[0]
mi = mutual_info_score(None, None, contingency=c_xy)
return mi