python - सुपीरियर का उपयोग करके जोड़ीदार आपसी जानकारी की गणना करने का इष्टतम तरीका



performance numpy (1)

एक mxn मैट्रिक्स के लिए, सभी जोड़े कॉलम ( nxn ) के लिए पारस्परिक जानकारी की गणना करने का सबसे इष्टतम (सबसे तेज़) तरीका क्या है?

आपसी जानकारी से मेरा मतलब है:

I (X, Y) = H (X) + H (Y) - H (X, Y)

जहाँ H (X) X की शैनन एंट्रोपी को संदर्भित करता है।

वर्तमान में मैं संयुक्त (एक्स, वाई) और व्यक्ति (एक्स या वाई) की गणना करने के लिए np.histogram2d और np.histogram का उपयोग कर रहा हूं। दिए गए मैट्रिक्स A (उदाहरण के लिए, एक 250000 एक्स 1000 फ़्लोट्स का मैट्रिक्स), मैं लूप के for नेस्टेड कर रहा हूं,

    n = A.shape[1]
    for ix = arange(n)  
        for jx = arange(ix+1,n):
           matMI[ix,jx]= calc_MI(A[:,ix],A[:,jx])

निश्चित रूप से ऐसा करने के लिए बेहतर / तेज तरीके होने चाहिए?

एक तरफ, मैंने एरेज़ पर कॉलम (कॉलम-वार या पंक्ति-वार संचालन) पर मैपिंग फ़ंक्शंस के लिए भी देखा है, लेकिन अभी तक एक अच्छा सामान्य उत्तर नहीं मिला है।

विकी पेज में सम्मेलनों के बाद यहाँ मेरा पूरा कार्यान्वयन है:

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)

यद्यपि छोरों के for नेस्टेड for साथ मेरा काम करने वाला संस्करण उचित गति से करता है, मैं यह जानना चाहूंगा कि क्या A सभी स्तंभों पर calc_MI लागू करने का एक अधिक इष्टतम तरीका है (उनकी जोड़ीदार पारस्परिक जानकारी की गणना करने के लिए)?

मैं भी जानना चाहूंगा:

  1. क्या np.arrays स्तंभों (या पंक्तियों) पर कार्य करने के लिए मैप करने के लिए कुशल तरीके हैं (शायद np.vectorize तरह, जो डेकोरेटर की तरह दिखता है)?

  2. क्या इस विशिष्ट गणना (पारस्परिक जानकारी) के लिए अन्य इष्टतम कार्यान्वयन हैं?


मैं n * (n-1) / 2 वैक्टर पर बाहरी लूप के लिए तेज़ गणना का सुझाव नहीं दे सकता, लेकिन यदि आप scipy संस्करण 0.13 या scikit-learn

0.13 scipy में, lambda_ तर्क को lambda_ में जोड़ा गया था। यह तर्क उस आंकड़े को नियंत्रित करता है जो फ़ंक्शन द्वारा गणना की जाती है। यदि आप lambda_=0 lambda_="log-likelihood" lambda_=0 lambda_="log-likelihood" (या lambda_=0 ) का उपयोग करते हैं, तो लॉग- lambda_=0 अनुपात वापस आ जाता है। इसे अक्सर G या G 2 स्टेटिस्टिक भी कहा जाता है। 2 * n के कारक के अलावा (जहाँ n आकस्मिकता तालिका में नमूनों की कुल संख्या है), यह पारस्परिक जानकारी है। तो आप के रूप में calc_MI लागू कर सकते हैं:

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

इस और आपके कार्यान्वयन के बीच एकमात्र अंतर यह है कि यह कार्यान्वयन बेस -2 लॉगरिथम के बजाय प्राकृतिक लघुगणक का उपयोग करता है (इसलिए यह "बिट्स" के बजाय "nats" में जानकारी व्यक्त कर रहा है)। यदि आप वास्तव में बिट्स पसंद करते हैं, तो बस mi को लॉग (2) से विभाजित करें।

यदि आपके पास sklearn (यानी स्किकिट-लर्न) स्थापित कर सकते हैं, तो आप sklearn.metrics.mutual_info_score उपयोग कर सकते हैं, और calc_MI को इस प्रकार लागू कर सकते हैं:

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




information-theory