2016-03-07 109 views
1

我環顧四周,並出人意料地沒有像儘管Scikit學習,爲全面互信息(直方圖)度量庫中找到了逐點互信息(Wiki PMI)計算的易用性框架或現有的代碼。這是Python和熊貓的背景!Pandas DataFrame可以有效地計算PMI(Pointwise Mutual Information)嗎?

我的問題:

我有一系列[X,Y]每行中示例的數據幀,並希望計算一系列PMI值的按式(或更簡單的一個):

PMI(x, y) = log(p(x,y)/p(x) * p(y))

到目前爲止,我的做法是:

def pmi_func(df, x, y): 
    df['freq_x'] = df.groupby(x).transform('count') 
    df['freq_y'] = df.groupby(y).transform('count') 
    df['freq_x_y'] = df.groupby([x, y]).transform('count') 
    df['pmi'] = np.log(df['freq_x_y']/(df['freq_x'] * df['freq_y'])) 

這會給出一個有效的和/或有效的計算?

樣品I/O:

x y PMI 
0 0 0.176 
0 0 0.176 
0 1 0 
+0

你能證明你的樣本數據和預期的輸出可能? – Zero

+0

嗨,我添加了一個簡單的例子,感謝您的幫助@JohnGalt – jfive

+0

,我認爲,你應該就地cacl'ing概率頻率:'np.log(DF [「freq_x_y」] /(DF [「freq_x」 ] * DF [ 'freq_y']))'應該成爲'np.log(LEN(df.index)* DF [ 'freq_x_y'] /(DF [ 'freq_x'] * DF [ 'freq_y']))',通過考慮總記錄? – Zero

回答

4

發表評論我要補充三位。

def pmi(dff, x, y): 
    df = dff.copy() 
    df['f_x'] = df.groupby(x)[x].transform('count') 
    df['f_y'] = df.groupby(y)[y].transform('count') 
    df['f_xy'] = df.groupby([x, y])[x].transform('count') 
    df['pmi'] = np.log(len(df.index) * df['f_xy']/(df['f_x'] * df['f_y'])) 
    return df 
  1. df.groupby(x)[x].transform('count')df.groupby(y)[y].transform('count')應該使用這樣只有 計數retured。要使用
  2. np.log(len(df.index) * df['f_xy']/(df['f_x'] * df['f_y'])概率。
  3. 在數據幀的拷貝工作,而不是修改輸入數據幀。
0

解決方案(與SKlearn KDE替代者):

請審查

from sklearn.neighbors.kde import KernelDensity 

# pmi function 
def pmi_func(df, x, y): 
    freq_x = df.groupby(x).transform('count') 
    freq_y = df.groupby(y).transform('count') 
    freq_x_y = df.groupby([x, y]).transform('count') 
    df['pmi'] = np.log(len(df.index) * (freq_x_y/(freq_x * freq_y))) 

# pmi with kernel density estimation  
def kernel_pmi_func(df, x, y): 
    # reshape data 
    x = np.array(df[x]) 
    y = np.array(df[y]) 
    x_y = np.stack((x, y), axis=-1) 

    # kernel density estimation 
    kde_x = KernelDensity(kernel='gaussian', bandwidth=0.1).fit(x[:, np.newaxis]) 
    kde_y = KernelDensity(kernel='gaussian', bandwidth=0.1).fit(y[:, np.newaxis]) 
    kde_x_y = KernelDensity(kernel='gaussian', bandwidth=0.1).fit(x_y) 

    # score 
    p_x = pd.Series(np.exp(kde_x.score_samples(x[:, np.newaxis]))) 
    p_y = pd.Series(np.exp(kde_y.score_samples(y[:, np.newaxis]))) 
    p_x_y = pd.Series(np.exp(kde_x_y.score_samples(x_y))) 

    df['pmi'] = np.log(p_x_y/(p_x * p_y))