変数間の関係性が見たい(偏相関とGraphical Lasso)

はじめに

データの変数間の関係性を明らかにしたいというケースは多いと思います。 その場合相関や散布図をみるのが一般的ですが、交絡やノイズが多いケースなど それだけでは不十分な場合もあるため、その場合にも対応できそうな手法を試してみます。 試す手法は偏相関行列とGraphical Lassoです。

参考資料

統計: 偏相関係数で擬似(無)相関の有無を調べる - CUBE SUGAR CONTAINER

【PyStan】Graphical LassoをStanでやってみる。 - Qiita

岩波データサイエンス Vol.5

データの準備

NPBのサイトから2013~18年の5年分の打者個人成績をスクレイピングします。

initflag=1
for year, league in itertools.product(range(2014, 2019), ['p', 'c']):
    url=f'http://npb.jp/bis/{year}/stats/bat_{league}.html'
    tables = pd.read_html(url)
    df_with_header = tables[0]
    df = df_with_header.iloc[2:,:] #使用カラム
    df.columns=df_with_header.iloc[1,:] #列名
    df["year"]=year
    df["league"]=league
    if initflag==1:
        output=df
        initflag=0
    else:
        output=pd.concat([output,df])
    time.sleep(1) #サーバに気をつかう

output.to_csv("baseball_stats.csv",index=False)

取得したデータ以下のような感じ。

f:id:rmizutaa:20190721110852p:plain

相関と偏相関

塁打や出塁率など他の変数から算出が可能な変数を省き、変数の相関をみてみます。

f:id:rmizutaa:20190721110914p:plain

結構それぞれの変数間の関係性は妥当に見えますが、 得点と三振や、盗塁と盗塁刺の相関が高いなど解釈が難しい数値もあります。

これらは実際は他の共通変数が相関している影響による疑似相関ではないかと考えられます。 前者では打席数の影響が、後者は盗塁企画数みたいなものの影響で これらの変数に相関があるように見えている可能性が高いです。

他の変数の影響を考慮した場合の相関関係をみる偏相関係数というものがあります。 式としては以下のような形で表されます。

p_{ij} = \frac{-\lambda_{ij}}{\sqrt{\lambda_{ii}\lambda_{jj}}}

ここで、p_{ij}は偏相関行列の要素で、\lambda_{ij},\lambda_{ii},\lambda_{jj}は精度行列(分散共分散行列の逆行列)の要素になります。

計算した偏相関行列は以下のようになりました。

f:id:rmizutaa:20190721110936p:plain

得点と三振については相関が小さくなり、盗塁と盗塁刺については負の相関があるという結果になりました。 盗塁企画数は今回のデータには含まれていませんが、3塁打や犠打の数である程度代用できたのではないかと思います。 一方で、打点と本塁打に負の相関があるなど偏相関行列にすることで直感的におかしな部分も生じています。

Graphical Lassoを使ってみる

本当に関係性の高い特徴量だけを使えば少し違った結果が出るのではないかと思いGraphical Lassoも使ってみます。Graphical Lassoは変数間の関係を推定するために、ガウシアングラフィカルモデルにL1正則化の考え方を応用したものになります。

lassoを使うため標準化を行い、またGraphical Lassoは多変量正規分布を仮定しているため変数にboxcox変換をかけて正規分布に近づけます。

X_gl = pd.DataFrame(StandardScaler().fit_transform(df.iloc[:,3:-2].drop(["塁 打","打 数","長打率","出塁率","試 合"],axis=1)))
pt = PowerTransformer()
df_gl = pd.DataFrame(pt.fit_transform(X_gl))

Graphical Lassoを使用します。

alpha = 0.2 # L1正則化パラメーター
model = GraphLasso(alpha=alpha,
                     max_iter=100,                     
                     verbose=True,
                     assume_centered = True)
model.fit(X_gl)
cov_ = model.covariance_ # 分散共分散行列
prec_ = model.precision_ # 精度行列

相関は以下のような形に。色が暗い領域が増え関係性の強い項目がみやすくなりました。

f:id:rmizutaa:20190721111018p:plain

交絡の影響を除くため先ほどと同様に計算を行い、偏相関行列は以下のようになりました。

f:id:rmizutaa:20190721111030p:plain

問題とした部分はGraphical Lassoを用いない場合とあまり変わりませんでした。 相関値で確認すると打点と本塁打の項目は共に犠打と負の相関が、三振と正の相関があるためこれらの影響による疑似相関だと判定されている気がします。 犠打を減らすと打点や本塁打が増えるはずはないので、偏相関係数の算出も機械的に行うのではなく 疑似相関にあたりをつけて個別に実施するのが良さそうです。

まとめ

・今回のように変数の意味がわかるデータセットの場合は、全体の変数で偏相関行列を作っても不自然な部分が出るため、疑似相関が出ている変数とその原因にあたりをつけてその変数のみで処理を行った方が良いと思った。
・Graphical Lassoは多変量正規分布を仮定していることを考えると、センサデータ等の変数同士の関係性の理解が難しく、ノイズが乗りやすいデータに適用が向いていそうだと思った。

使用したコードは以下になります。

github.com