[python]カテゴリ変数についても相関を求める方法
はじめに
データ分析の際には与えられたデータにおいて変数間の相関関係を調べると思います。数値同士の相関は相関係数を調べればよいですが、一方または両方がカテゴリの場合はどうしたらいいのかな?と思って調べたのでまとめます。
数値 vs 数値
この場合は有名で、相関係数を調べればよいです。相関係数の定義は以下の通りです。
pythonで相関係数を求めるにはpandas.DataFrameのcorr()メソッドを使います。
import numpy as np
import pandas as pd
x=np.random.randint(1, 10, 100)
y=np.random.randint(1, 10, 100)
data=pd.DataFrame({'x':x, 'y': y})
data.corr()
値が0ならば相関なし、1に近ければ正の相関、-1に近ければ負の相関があります。
カテゴリ vs 数値
相関比という統計量で表されます。定義は以下の通りです。
具体例はここを参照してください。 分子は「各カテゴリがどれだけ離れているか」を表しています。カテゴリ同士が離れているほど分子が大きくなり、相関が強いと言えます。
この相関比も、0の場合は相関なし、1に近づくと強い正の相関を意味します。
pythonでは以下のように計算します(こちらを参照)。
def correlation_ratio(cat_key, num_key, data):
categorical=data[cat_key]
numerical=data[num_key]
mean=numerical.dropna().mean()
all_var=((numerical-mean)**2).sum() #全体の偏差の平方和
unique_cat=pd.Series(categorical.unique())
unique_cat=list(unique_cat.dropna())
categorical_num=[numerical[categorical==cat] for cat in unique_cat]
categorical_var=[len(x.dropna())*(x.dropna().mean()-mean)**2 for x in categorical_num]
#カテゴリ件数×(カテゴリの平均-全体の平均)^2
r=sum(categorical_var)/all_var
return r
カテゴリ vs カテゴリ
クラメールの連関係数という統計量を用いて調べます。定義は
ただし、χ2はχ2乗分布、nはデータ件数、kはカテゴリ数の少ない方です。χ2乗分布についてはこちらなどを参照ください。ざっくり言うと、各カテゴリの分布が全体の分布とどれだけ異なるか、を表す量です。これについても0近ければ相関なし、1に近ければ正の相関あり、となります。
pythonで計算するには以下のようにします(こちらを参照)。
import scipy.stats as st
def cramerV(x, y, data):
table=pd.crosstab(data[x], data[y])
x2, p, dof, e=st.chi2_contingency(table, False)
n=table.sum().sum()
r=np.sqrt(x2/(n*(np.min(table.shape)-1)))
return r
各指標をまとめて求める
と、これだけだとこれまでの記事の2番煎じになってしまうので、DataFrameに対して各指標をまとめて求めるメソッドを作りました。これでいちいち調べなくても良いです!
def is_categorical(data, key):
col_type=data[key].dtype
if col_type=='int':
nunique=data[key].nunique()
return nunique<6
elif col_type=="float":
return False
else:
return True
def get_corr(data, categorical_keys=None):
keys=data.keys()
if categorical_keys is None:
categorical_keys=keys[[is_categorycal(data, key) for key in keys]]
corr=pd.DataFrame({})
corr_ratio=pd.DataFrame({})
corr_cramer=pd.DataFrame({})
for key1 in keys:
for key2 in keys:
if (key1 in categorical_keys) and (key2 in categorical_keys):
r=cramerV(key1, key2, data)
corr_cramer.loc[key1, key2]=r
elif (key1 in categorical_keys) and (key2 not in categorical_keys):
r=correlation_ratio(cat_key=key1, num_key=key2, data=data)
corr_ratio.loc[key1, key2]=r
elif (key1 not in categorical_keys) and (key2 in categorical_keys):
r=correlation_ratio(cat_key=key2, num_key=key1, data=data)
corr_ratio.loc[key1, key2]=r
else:
r=data.corr().loc[key1, key2]
corr.loc[key1, key2]=r
return corr, corr_ratio, corr_cramer
どのキーがカテゴリ変数なのかは指定がなければ変数型から自動で判定します。
titanicのデータに適用してみます。
data=pd.read_csv(r"train.csv")
data=data.drop(["PassengerId", "Name", "Ticket", "Cabin"], axis=1)
category=["Survived", "Pclass", "Sex", "Embarked"]
corr, corr_ratio, corr_cramer=get_corr(data, category)
corr
corr_ratio
corr_cramer
さらに、seabornのheatmapで可視化できます。
import seaborn as sns
sns.heatmap(corr_cramer, vmin=-1, vmax=1)
最後に
各統計量の説明は雑になってしまったので、参照に記したページをご覧ください。自分はまとめても結局忘れて調べるはめになるのでできるだけ自動化するメソッドを作るようにしています。
記事内で扱ったメソッドはgithubに上げてあります。
参照
最新記事
すべて表示概要 pythonでデータ解析を行っている。解析自体はpandasを用いて行い、最終結果はpandas.DataFrameの形式で保持されている。 この結果を他のアプリケーションで利用するため、json形式でファイル出力したい。 やり方 1...
現象 raspberry piでfirestoreをimportしようとするとタイトルのエラーが発生。 from from firebase_admin import firestore ImportError: Failed to import the Cloud...
概要 フィッティングを行いたい場合、pythonならばscipy.optimize.leastsqなどでできます。 しかし、フィッティングを行う場合、フィッティングパラメータに条件を付けたい場合も多々あります。 例えば、下記のようにパラメータa、bは共に正の範囲で最適な値を...
Comments