いろいろ倉庫

KNIME、EXCEL、R、Pythonなどの備忘録

【Python】相関のネットワークの図を描きたい

・お題:それぞれの変数に関して、相関係数をもとに、ネットワーク図を描いてみたい。

 

・変数間の相関係数をもとにネットワークを描くことがあるらしい。偽相関の懸念や因果関係を表すわけではないなどの注意点があるが、せっかくなのでやってみたい。

・とりあえず、データセットを作成する。

import random
random.seed(0)
A=[n*0.1 for n in range(100)]
B=[n + random.random()*2 for n in A]
C=[0.5*n + random.random()*5 for n in A]
D=[-n + random.random()*10 for n in A]
E=[random.random() for n in A]
F=[0.7*n + random.random() for n in E]
G=[-n + random.random() for n in F]

import pandas as pd
df=pd.DataFrame({"A":A,"B":B,"C":C,"D":D,"E":E,"F":F,"G":G})

・次に、相関係数を求める。

df_corr=df.corr()

・ついでに、ヒートマップぽくしてみる。

df_corr.style.background_gradient(cmap="bwr",vmin=-1, vmax=1)

・この相関係数を使ってグラフを描いてみたい。今回は閾値を設けず、すべての特徴量をエッジで結ぶ。エッジの色と太さで相関がなんとなくわかるようにしたい。とりあえず、先ほど算出した相関係数からエッジのリストを作成する。

edges=[]
for n in range(len(df.columns)):
    for m in range(n+1,len(df.columns)):
        edges.append*1

・edgesをネットワークとして読み込ませ、pyvisに投げる。

import networkx as nx
G = nx.Graph()

G.add_weighted_edges_from(edges)
 from pyvis.network import Network
g = Network()
g.from_nx(G)
 

・これで、g.edgesは以下になる。

[{'width': 0.9840713121597259, 'from': 'A', 'to': 'B'},
 {'width': 0.7117259071284598, 'from': 'A', 'to': 'C'},
 {'width': -0.7365553964358992, 'from': 'A', 'to': 'D'},
 {'width': 0.10888187692282489, 'from': 'A', 'to': 'E'},
……

・次に、edgeの色のセットを用意する。

from matplotlib.colors import rgb2hex
import matplotlib.pyplot as plt
cmap = plt.get_cmap("bwr")
colorcodes=[rgb2hex(cmap*2 for n in g.edges]

・エッジの太さと色を設定する。相関係数をwidthにそのまま使うと、負値はゼロ扱いになるし、最大で太さ1になるので、つまらない。2倍して2乗することで、太さに緩急をつけたい。

for n in range(len(g.edges)):
    g.edges[n]["width"] = (g.edges[n]["width"] *2)**2
    g.edges[n]["color"] = colorcodes[n]

・これで、g.edgesは以下になる。

[{'width': 3.8735853896630585, 'from': 'A', 'to': 'B', 'color': '#ff0404'},
 {'width': 2.026215067511316, 'from': 'A', 'to': 'C', 'color': '#ff4848'},
 {'width': 2.1700554080753784, 'from': 'A', 'to': 'D', 'color': '#4242ff'},
 {'width': 0.04742105248894875, 'from': 'A', 'to': 'E', 'color': '#ffe4e4'},

……

・あとは、グラフを作成する。もちろんインタラクティブにプルプル動かすことができるので、気になるノードをつまんで引っ張れば、他のノードとの関係がなんとなくわかる。

g.show("test.html")

・何はともあれぷるんぷるんしているのが楽しい。

 

おわり。

 

 

 

*1:df_corr.index[n],df_corr.columns[m],df_corr.iloc[n,m]

*2:n["width"]+1)/2