macbook pro beside papers

Pythonで相関係数とp値を計算するクラス

以前の記事(下記)で書いたコードを1つのクラスにまとめたので、載せておこうと思います。

Pythonで有意な偏相関だけを取り出す方法

CorrelationAnalyticsクラス

使い方

CorrelationAnalyticsインスタンスを作成し、analyze()メソッドを呼び出すと勝手に相関を計算します。偏相関を計算する場合は、CorrelationAnalysis(partial=True)としてインスタンスを作成します。結果は、r_values, p_values, significants関数で取り出すこともできますし、print文で表示することもできます。

mport pandas as pd
import corr_analysis as ca #corr_analysis.pyというファイル名にした場合

d   = pd.read_csv("data08-01.csv",index_col=0) #データ読み込み
cor = ca.CorrelationAnalysis() #インスタンス作成
#cor = ca.CorrelationAnalysis(partial=True) #偏相関を計算する
sigs= cor.analyze(d) # 相関分析
print(cor) # 分析結果表示

結果は次のように表示されます。

Computing Method   : pearson
Significant Level  : alpha = 0.05
Enable Partial     : False

Correlations:
          外向性       社交性       積極性        知性       信頼性       素直さ
外向性  1.000000  0.486598  0.597427  0.242365  0.276316  0.218862
社交性  0.486598  1.000000  0.557963  0.125065  0.316855  0.172543
積極性  0.597427  0.557963  1.000000  0.240722  0.037339  0.146644
知性   0.242365  0.125065  0.240722  1.000000  0.436256  0.627103
信頼性  0.276316  0.316855  0.037339  0.436256  1.000000  0.583632
素直さ  0.218862  0.172543  0.146644  0.627103  0.583632  1.000000

p-Values:
          外向性       社交性       積極性        知性       信頼性       素直さ
外向性  0.000000  0.029579  0.005409  0.303221  0.238283  0.353892
社交性  0.029579  0.000000  0.010573  0.599329  0.173464  0.466959
積極性  0.005409  0.010573  0.000000  0.306612  0.875806  0.537277
知性   0.303221  0.599329  0.306612  0.000000  0.054482  0.003083
信頼性  0.238283  0.173464  0.875806  0.054482  0.000000  0.006902
素直さ  0.353892  0.466959  0.537277  0.003083  0.006902  0.000000

List of Significant Values:
r=0.49, p=0.0296 :              外向性 <-> 社交性             
r=0.60, p=0.0054 :              外向性 <-> 積極性             
r=0.56, p=0.0106 :              社交性 <-> 積極性             
r=0.63, p=0.0031 :               知性 <-> 素直さ             
r=0.58, p=0.0069 :              信頼性 <-> 素直さ      

メソッド

CorrelationAnalysisクラスのメソッドの一覧は次の通りです。

CorrelationAnalysis(
 method=”pearson”,
 alpha=0.05, partial=False)
コンストラクタ
method : 相関の計算方法。[“pearson”|”kendall”|”spearman”]
alpha:有意水準
partial:偏相関使用フラグ
analyze(df)相関分析を計算する
df :相関を計算するデータ。pandas.DataFrame型。
戻り値:list型。有意な相関のリスト
r_values()相関行列を取り出す
戻り値:pandas.DataFrame型
p_values()p値行列を取り出す
戻り値:pandas.DataFrame型
significants()有意な相関のリストを取り出す
戻り値:list型。有意な相関のリスト

これらの他に静的メソッドがありますが、それらは前回の記事で記載した関数をそのまま静的メソッドにしたものです。

ソースコード

import itertools as itr
import pandas as pd
import scipy as sp
import numpy as np
import scipy.stats as ss

class CorrelationAnalysis:

        # 相関関数のコマンドテーブル
        __CORRFUNC = { 'pearson':ss.pearsonr,
                       'kendall':ss.kendalltau,
                       'spearman':ss.spearmanr }

        def __init__(self,
                     method='pearson',
                     alpha =0.05,
                     partial=False ):
                self.method_  = method  # {'pearson'|'kendall'|'spearman'}
                self.alpha_   = alpha   # significant level (default:0.05)
                self.partial_ = partial # computing partial correlation
                self.r_       = None    # correlation matrix @ Array
                self.p_       = None    # p-value matrix @ Array
                self.sigs_    = None    # significant correlation coefficients


        # 相関係数とp値を計算する
        def analyze(self,df):
                std_df = self.standardize(df)
                if self.partial_ is True :
                        r,p = self.pcorr(std_df,method=self.method_)
                else:
                        r,p = self.corr(std_df,method=self.method_)
                self.r_ = r
                self.p_ = p
                self.sigs_ = self.siglist(r,p,alpha=self.alpha_)
                return self.sigs_

        # 相関行列を返す
        def r_values(self):
                if self.r_ is not None :
                        return self.r_
                else:
                        print("c_coefs() call error : r is None")

        # p値行列を返す
        def p_values(self):
                if self.p_ is not None :
                        return self.p_
                else:
                        print("p_values() call error : p is None")

        # 有意な値だけをリストにする
        def significants(self):
                if self.sigs_ is not None :
                        return self.sigs_
                else:
                        print("significants() call error : p is None")

        #標準化
        #https://note.nkmk.me/python-list-ndarray-dataframe-normalize-standardize/
        @staticmethod
        def standardize(df,ddof=False):
                stddat = ( df - df.mean() ) / df.std(ddof=ddof)
                stddat.index = df.index
                stddat.columns = df.columns
                return stddat

        # p値付き相関係数行列の計算
        #
        # ARGS
        #  df   : pandas.DataFrame型のデータ
        #  method: 相関のタイプ {'pearson'|'kendall'|'spearman'}
        #
        # RETURN
        #  r_df  : 相関係数行列(pandas.DataFrame)
        #  p_df  : p値行列(pandas.DataFrame)
        #
        @staticmethod
        def corr(df,method="pearson"):
                # 空のDataFrameを用意する
                r_df = pd.DataFrame(index=df.columns, columns=df.columns)
                p_df = pd.DataFrame(index=df.columns, columns=df.columns)
                # ゼロで初期化する
                r_df.fillna(0.0,inplace=True)
                p_df.fillna(0.0,inplace=True)
                # 対角成分を1.0にする
                for i in r_df.columns:
                        r_df.loc[[i],[i]] = 1.0
                # 非対角成分を計算する
                corrfunc = CorrelationAnalysis.__CORRFUNC[method]
                for i,j in itr.combinations(df,2):
                        x = df.loc[:,[i]].values
                        y = df.loc[:,[j]].values
                        r,p = corrfunc(np.ravel(x),np.ravel(y))
                        r_df.loc[[i],[j]] = r
                        r_df.loc[[j],[i]] = r
                        p_df.loc[[i],[j]] = p
                        p_df.loc[[j],[i]] = p
                # 相関とp値を返却
                return r_df,p_df

        #p値つき編相関係数行列の計算
        #
        # ARGS
        #  df     : pandas.DataFrame型のデータ
        #  method : 相関のタイプ {'pearson'|'kendall'|'spearman'}
        #
        # RETURN
        #  pcor_df: 偏相関係数行列(pandas.DataFrame)
        #  p_df   : p値行列(pandas.DataFrame)
        #
        @staticmethod
        def pcorr(df,method="pearson"):
                cor = df.corr(method=method)
                n   = df.shape[0] # number of data
                l   = df.shape[1] # number of labels
                # 偏相関係数の計算
                cor_inv = sp.linalg.pinv(cor) # 従属変数が存在する場合に備えて、擬逆行列pinvを使用
                denom = 1 / np.sqrt(np.diag(cor_inv))
                numer = np.repeat(denom,l).reshape(l,l)
                pcor  = (-cor_inv) * denom * numer
                np.fill_diagonal(pcor,0) #ゼロ割防止のため対角成分を0にする
                # 統計検定量(t)の計算
                t = np.abs(pcor) * np.sqrt(n-3) / np.sqrt(1-pcor*pcor)#3変数間の相関なのでn-3
                np.fill_diagonal(pcor,1) #対角成分を自己相関値=1にする
                # p値の計算
                p = 2*sp.stats.t.cdf(-t,n-3) #両側、Array型
                # pandas.DataFrameへ変換
                pcor_df = pd.DataFrame(data=pcor,index=cor.index,columns=cor.columns)
                p_df=pd.DataFrame(data=p,index=cor.index,columns=cor.columns)
                return pcor_df,p_df

        # 相関行列とp値行列から有意な相関係数リストを生成する
        #  r     : correlation matrix @ pandas.DataFrame
        #  p     : p-value matrix @ pandas.DataFrame
        #  alpha : significant level
        @staticmethod
        def siglist(r,p,alpha=0.05):
                clist = []
                n = r.columns.size
                j = 0
                while j < n:
                        i = 0
                        while i < j:
                                if( p.iloc[i,j] < alpha ):
                                        first = r.columns[i]
                                        second= r.columns[j]
                                        rvalue= r.iloc[i,j]
                                        pvalue= p.iloc[i,j]
                                        dat = { 'first':first, 'second':second, 'r':rvalue, 'p':pvalue }
                                        clist.append(dat)
                                i+=1
                        j+=1
                return clist

        # 有意な相関のリスト
        #  df : pandas dataFrame format
        #  alpha : max of p-value
        @staticmethod
        def corlist_fast(df,alpha=0.05,method='pearson'):
                corrfunc = CorrelationAnalysis.__CORRFUNC[method]
                clist=[]
                for i,j in itr.combinations(df,2):
                        x = df.loc[:,[i]].values
                        y = df.loc[:,[j]].values
                        r,p = corrfunc(np.ravel(x),np.ravel(y))
                        if p < alpha :
                                cpair = { 'first':i, 'second':j, 'r':r, 'p':p }
                                clist.append(cpair)
                return clist

        # 有意な相関のリスト
        #  df : pandas dataFrame format
        #  alpha : max of p-value
        @staticmethod
        def corlist(df,alpha=0.05,method='pearson'):
                r,p = CorrelationAnalysis.corr(df,method=method)
                return CorrelationAnalysis.siglist(r,p,alpha)

        #有意な偏相関係数リスト
        #  df : pandas dataFrame format
        #  alpha : max of p-value
        @staticmethod
        def pcorlist(df,alpha=0.05,method="pearson"):
                r,p = CorrelationAnalysis.pcorr(df,method=method)
                return CorrelationAnalysis.siglist(r,p,alpha)

        # 有意な相関係数リストを表示する
        @staticmethod
        def print_clist(clist):
            for item in clist:
                print("r=%.2f, p=%.4f : %-16s <-> %-16s"%(item['r'],item['p'],item['first'],item['second']))

        # 分析結果を表示する
        def __str__(self):
                x  = "\n"
                x += "Computing Method   : " + self.method_ + "\n"
                x += "Significant Level  : alpha = " + str(self.alpha_) + "\n"
                x += "Enable Partial     : " + str(self.partial_) + "\n"
                x += "\n"
                if self.r_ is not None:
                        pd.set_option('display.max_columns', len(self.r_.columns))
                        pd.set_option('display.max_rows', len(self.r_.index))
                        x += "Correlations:\n" + str(self.r_) + "\n\n"
                if self.p_ is not None:
                        pd.set_option('display.max_columns', len(self.p_.columns))
                        pd.set_option('display.max_rows', len(self.p_.index))
                        x += "p-Values:\n" + str(self.p_) + "\n\n"
                if self.sigs_ is not None:
                        x += "List of Significant Values:\n"
                        for item in self.sigs_ :
                                x += "r={0:.2f}, p={1:.4f} : {2:>16s} <-> {3:<16s}\n".format(item['r'],item['p'],item['first'],item['second'])
                return x

コメントを残す