Boy Meets ML

機械工出身者が機械学習やその界隈の知識を考える

統計的因果探索について #1:相関をみてみる

はじめに

データ分析を行うとき、対象データをグラフに書きまくる、さらに変数間の相関をみることはとても当たり前に行うと思います。 でも、相関が高いからといって軽々と変数間が影響しあっていると考えることは時期尚早です。 これはデータを生成している事象の因果関係をしっかり捉えないと間違えてしまうので、意外に注意が必要なわけです。 以下の記事は、自分なりのメモとしてまとめることを第一にしているので、わかりにくい点や間違いがあるかもしれません。 メインの参考文献はMLPシリーズの「統計的因果探索」1です。 まずは基本中の基本である、データの相関について手を動かしながら見ていきます。

Hands on

相関

相関 R(x_1,x_2)とはあるデータに対して、一つの特徴量を説明変数 x_1、また他の特徴量を目的変数 x_2としたとき、 これらの変数どうしが互いに関わり合うように変化しているのか?を調べるものです。  R(x_1,x_2)\lt0として正の相関があれば、 x_1が増加すると x_2も増加する傾向がある。 逆に R(x_1,x_2)\gt0として負の相関があれば、 x_1が増加すると x_2は減少する傾向があることになります。 しかし、相関があるからといって、互いの変数が直接影響しあっているといえるわけではなく、 データ分析で簡単に求められる値ですが奥が深いものです。

データセットの特徴をつかむ

以下では例を示しながら進めたほうが楽しいので、pythonのseabornを利用することで簡単に利用できるtitanicのデータを見ながらすすめることにします。 kaggle2でも利用されているので、seabornを利用しなくても入手できるものです。

import seaborn as sns

dataset_name = sns.get_dataset_names()
dataset = sns.load_dataset(dataset_name[-1])

titanicデータセットを覗いてみると次のようなカラムから構成されています。 どうやら意味が類似するカラムがあるためか、kaggleのcsvとは少しだけ異なるみたいです。

dataset.head()

titanic dataset
top 5 data of titanic dataset
各カラムの意味は次の通りで、typeはdataset.ftypesで参照したもの。 columnに取り消し線を引いているものは今回の解析では使わないため、delして扱います。

column type description
survived int64 生存者であるか
pclass int64 チケットのクラス
sex object 性別
age float64 年齢
sibsp int64 同乗した兄弟/配偶者の数
parch int64 同乗した親/子供の数
fare float64 運賃
embarked object 出港した港の名前
class category チケットのクラス、Fisrt/Second/Third
who object sexがmaleならman, femaleならwoman
adult_male bool sexがmaleならTrueだと思う
deck category 客室番号?A~Gまである
embark_town object 出港した街、{nan, 'Southampton', 'Queenstown', 'Cherbourg'}のいずれか
alive object 生きているかどうか
alone bool ぼっちかどうか、sibspが0かつparchが0ならばTrue

このデータをいくつかグラフ化してみます。 ただし注意が必要な点は現実データと同様にtitanicデータにも欠損値が存在しており、ageなどが抜けているところがあります。 欠損値を補完する方法を考え始めると一大テーマになってしまうので、pandas.DataFrame.dropna()メソッドを使いNaN(欠損値)が含まれるデータは捨ててしまうことにしました。 なぜ注意が必要なのかというと、一部のカラムが欠損しているかといってそのサンプルを捨てると、データセットの傾向を歪ませる可能性があるからです。 例えば、欠損値を含むデータセットのまま基本統計量を見ると、

dataset.describe()

Statistical Variables
Statistical Variables
となりますが、欠損値を含むサンプルを捨ててしまうことにすると、

dataset.dropna().describe()

Statistical Variables without NaN
Statistical Variables without NaN
となります。 見比べると明らかですが、データセットの全体のサンプル数は、891から182に激減してしまい、 平均Ageは29.699118から35.623187へ、 平均Fareは32.204208から78.919735と倍以上の値になってしまいました。 Fareの標準偏差1 {\sigma}は49.693429から76.490774となり、幅広く分布している可能性がわかります。

年齢Ageが上がれば稼ぎも増える気がするので運賃Fareも高くなるかも?という仮説を立てて、この2変数間の関係を見てることにしました。 欠損値をdropしてからAgeとFareのプロットを行い、Sexによって色分けをおこなってみます。 sns.pairplot()で行うと縦軸の表記がおかしかったため、それぞれを別個に作図しました。

dataset_wona = dataset.dropna()

g = sns.FacetGrid(pd.DataFrame([dataset_wona.age, dataset_wona.sex]).T, hue='sex')
g = g.map(sns.distplot, 'age')
plt.legend()
plt.show()
g = sns.FacetGrid(pd.DataFrame([dataset_wona.fare, dataset_wona.sex]).T, hue='sex')
g = g.map(sns.distplot, 'fare')
plt.legend()
plt.show()

Histogram of Fare, colorized by SexHistogram of Age, colorized by Sex
Histogram of Fare(left) and Age(right), colorized by Sex

sns.scatterplot(x=dataset_wona.fare, y=dataset_wona.age, hue=dataset_wona.sex)
plt.show()

Scatter plot between Fare and Age, colorized by Sex
Scatter plot between Fare and Age, colorized by Sex

欠損を含むサンプルを除去したデータであること念頭にいれつつ結果を眺めると、 性別のヒストグラムからほぼ同等の比率でタイタニック号に乗船していたことがわかります。 若干Femaleのほうが若いことから当時の外国人男性は自身の年齢よりも年下の女性を好んでいたのかもしれません。 一方で、Fareのヒストグラムからは一部に富裕層の影が見て取れますが、多くの乗客は同等の運賃を払っているようです。 ただし運賃だけでなく出港地も鑑みないと、これも富裕層であるのか、はたまた他の人より長距離乗船しているだけなのかわかりません。 データ分析をおこなう上では、非観測変数の存在を考えて、あらゆる可能性を踏まえておくことが重要です。 さて、AgeとFareの散布図を見てみるとこの2変数のデータに相関はないように見えます。 実際に、AgeとFareの相関値は-0.0907と非常に相関値が低く、ほぼ無相関と言えます。

dataset_wona.corr()['fare']['age']

見るからに相関もないので無駄かもしれませんが、説明変数をFare、目的変数をAgeとして線形回帰モデルをフィットさせて、回帰係数と決定係数の様子を確認します。 回帰係数は線形回帰を行うときの傾きであり、これは説明変数の重みを意味することになります。 決定係数は予測式(ここでは線形回帰)がどれだけデータにうまくフィットしているのかを示し、大きいほど当てはまりがよく、小さいほど悪い。 なお決定係数と相関係数の関係はこちらのサイト3にわかりやすくまとめられています。

from sklearn import linear_model
clf = linear_model.LinearRegression(normalize=True)
 
x1 = dataset_wona.fare.values.reshape(-1, 1)
x2 = dataset_wona.age.values.reshape(-1, 1)

clf.fit(x1, x2)

print(clf.coef_)  # 回帰係数
print(clf.score(x1, x2))  # 決定係数

A Result of Linear Regression
A Result of Linear Regression

回帰係数は-0.01858906、決定係数は0.00823となりました。 つまり説明変数としたFareはあまりAgeを説明できているとはいえず、 線形回帰モデルも適していないことが言えます。 検定を行うことで有意に相関がないことを示す必要もありますが、思いの外長くなってしまったので、 今回は"年齢Ageが上がれば稼ぎも増える気がするので運賃Fareも高くなるかも?という仮説"は誤っていそう、というところで止めにしておきます。 しかし、例えばですが、年齢が上がると、稼ぎも増えるかもしれませんが、遠出することが億劫になり運賃は大して上がらないかもしれません。 次回は多変数間の因果関係にまで踏み込んで見たいと思います。

まとめ

今回はtitanicデータセットを使い簡単なデータ分析を行いました。 相関はかんたんな値ですが、事象の因果関係や非観測変数の存在を加味しながら眺めなければいけません。 次回は、擬似相関や多変数間の因果関係の話を考えてみます。

参考文献