[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)

相関分析

相関比

カイ2乗検定・クラメール連関係数

最新記事

すべて表示

概要 フィッティングを行いたい場合、pythonならばscipy.optimize.leastsqなどでできます。 しかし、フィッティングを行う場合、フィッティングパラメータに条件を付けたい場合も多々あります。 例えば、下記のようにパラメータa、bは共に正の範囲で最適な値を求める、という感じです。 f(x, a, b)=a*x^2+b (a>0 and b>0) 今回はそんな手法についてご紹介しま

靴を大切にしよう!靴管理アプリ SHOES_KEEP

納品:iPhone6.5①.png

靴の履いた回数、お手入れ回数を管理するアプリです。

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

テーマ日記:テーマを決めてジャンルごとに記録

訂正①2040×1152.jpg

ジャンルごとにテーマ、サブテーマをつけて投稿、記録できる日記アプリです。

google-play-badge.png