データの理解の後半パートは目的変数と説明変数の関係性を中心にして集計や可視化をしていきたいと思います。
今回は生存するかどうかを当てるモデルを作成するつもりなので、目的変数は生存有無フラグ(Survived)にします。
分析の目的により対象変数は変わります。例えば年齢を当てるモデルを作成したいとき、目的変数はAgeになります。
さて、生存するかどうかに関係がありそうな変数は何でしょうか?
② データの理解
データ俯瞰の続き
クロス集計用の関数の作成
毎回、同様の長いコードを書くと見にくくなるため、処理を使い回せるように関数化しました。
cross_tab_statsという関数を作成しました。
引数は dataframe、atarget、variablesになります。
cross_tab_stats(data, atarget="target", variables="var")
Return cross tabulated results with given target variable and explanatory variable(s) in DataFrame.
Parameters
- data: DataFrame
- atarget: str
- variables: str or list of str
# 目的変数と説明変数の関係性を確認するための関数
def cross_tab_stats(dataframe,atarget,variables):
select_cols=[]
if type(variables) is str:
select_cols.extend([variables])
else:
select_cols.extend(variables)
groupby_cols=select_cols.copy() # shallow copy
select_cols.extend([atarget])
print("select_cols:",select_cols)
print("groupby_cols:",groupby_cols)
return dataframe[select_cols].groupby(groupby_cols, as_index=False).agg(
{ "Survived": [ "sum"
,"count"
,lambda x: x.sum() / x.count()
,"mean"
,"median"
,"std"
]
}).rename(columns={"<lambda_0>": "sum/count"}).reset_index()
Survived x Pclassのクロス集計
# Survived x Pclassのクロス集計
cross_tab_stats(df,"Survived","Pclass")
select_cols: ['Pclass', 'Survived'] groupby_cols: ['Pclass']
index Pclass Survived sum count sum/count mean median std 0 0 1 136 216 0.629630 0.629630 1.0 0.484026 1 1 2 87 184 0.472826 0.472826 0.0 0.500623 2 2 3 119 491 0.242363 0.242363 0.0 0.428949
3rdクラスの生存者は24%のようです。
一方で1stクラスは63%が生存しているようです。
ただ、実数でみると1stクラスは136人が生存し3rdクラスは119人が生存しています。母数で確認しないと分かりませんが、訓練データ上では何となくそれぞれのクラスから近しい人数が助かったのではないかと数値上は見えました。(生存者数がそれぞれのクラスである程度等しくなるようにバランスデータを作成してる可能性もありますね。)
Survived x Sexのクロス集計
# Survived x Sexのクロス集計
cross_tab_stats(df,"Survived","Sex")
select_cols: ['Sex', 'Survived'] groupby_cols: ['Sex']
index Sex Survived sum count sum/count mean median std 0 0 female 233 314 0.742038 0.742038 1.0 0.438211 1 1 male 109 577 0.188908 0.188908 0.0 0.391775
女性の75%が生存したという結果が出ました。
映画のように女性と子供が優先で救命ボートに乗ることが出来たからでしょうか?
それとも1stクラスや2ndクラスの方が多く女性が乗船していたのでしょうか?
色々仮説は立てられそうです。
Survived x Ageのクロス集計
from IPython.display import HTML
# Survived x Ageのクロス集計
HTML(cross_tab_stats(df,"Survived","Age").to_html())
select_cols: ['Age', 'Survived'] groupby_cols: ['Age']
index Age Survived sum count sum/count mean median std 0 0 0.42 1 1 1.000000 1.000000 1.0 NaN 1 1 0.67 1 1 1.000000 1.000000 1.0 NaN 2 2 0.75 2 2 1.000000 1.000000 1.0 0.000000 3 3 0.83 2 2 1.000000 1.000000 1.0 0.000000 4 4 0.92 1 1 1.000000 1.000000 1.0 NaN 5 5 1.00 5 7 0.714286 0.714286 1.0 0.487950 6 6 2.00 3 10 0.300000 0.300000 0.0 0.483046 7 7 3.00 5 6 0.833333 0.833333 1.0 0.408248 8 8 4.00 7 10 0.700000 0.700000 1.0 0.483046 9 9 5.00 4 4 1.000000 1.000000 1.0 0.000000 10 10 6.00 2 3 0.666667 0.666667 1.0 0.577350 11 11 7.00 1 3 0.333333 0.333333 0.0 0.577350 12 12 8.00 2 4 0.500000 0.500000 0.5 0.577350 13 13 9.00 2 8 0.250000 0.250000 0.0 0.462910 14 14 10.00 0 2 0.000000 0.000000 0.0 0.000000 15 15 11.00 1 4 0.250000 0.250000 0.0 0.500000 16 16 12.00 1 1 1.000000 1.000000 1.0 NaN 17 17 13.00 2 2 1.000000 1.000000 1.0 0.000000 18 18 14.00 3 6 0.500000 0.500000 0.5 0.547723 19 19 14.50 0 1 0.000000 0.000000 0.0 NaN 20 20 15.00 4 5 0.800000 0.800000 1.0 0.447214 21 21 16.00 6 17 0.352941 0.352941 0.0 0.492592 22 22 17.00 6 13 0.461538 0.461538 0.0 0.518875 23 23 18.00 9 26 0.346154 0.346154 0.0 0.485165 24 24 19.00 9 25 0.360000 0.360000 0.0 0.489898 25 25 20.00 3 15 0.200000 0.200000 0.0 0.414039 26 26 20.50 0 1 0.000000 0.000000 0.0 NaN 27 27 21.00 5 24 0.208333 0.208333 0.0 0.414851 28 28 22.00 11 27 0.407407 0.407407 0.0 0.500712 29 29 23.00 5 15 0.333333 0.333333 0.0 0.487950 30 30 23.50 0 1 0.000000 0.000000 0.0 NaN 31 31 24.00 15 30 0.500000 0.500000 0.5 0.508548 32 32 24.50 0 1 0.000000 0.000000 0.0 NaN 33 33 25.00 6 23 0.260870 0.260870 0.0 0.448978 34 34 26.00 6 18 0.333333 0.333333 0.0 0.485071 35 35 27.00 11 18 0.611111 0.611111 1.0 0.501631 36 36 28.00 7 25 0.280000 0.280000 0.0 0.458258 37 37 28.50 0 2 0.000000 0.000000 0.0 0.000000 38 38 29.00 8 20 0.400000 0.400000 0.0 0.502625 39 39 30.00 10 25 0.400000 0.400000 0.0 0.500000 40 40 30.50 0 2 0.000000 0.000000 0.0 0.000000 41 41 31.00 8 17 0.470588 0.470588 0.0 0.514496 42 42 32.00 9 18 0.500000 0.500000 0.5 0.514496 43 43 32.50 1 2 0.500000 0.500000 0.5 0.707107 44 44 33.00 6 15 0.400000 0.400000 0.0 0.507093 45 45 34.00 6 15 0.400000 0.400000 0.0 0.507093 46 46 34.50 0 1 0.000000 0.000000 0.0 NaN 47 47 35.00 11 18 0.611111 0.611111 1.0 0.501631 48 48 36.00 11 22 0.500000 0.500000 0.5 0.511766 49 49 36.50 0 1 0.000000 0.000000 0.0 NaN 50 50 37.00 1 6 0.166667 0.166667 0.0 0.408248 51 51 38.00 5 11 0.454545 0.454545 0.0 0.522233 52 52 39.00 5 14 0.357143 0.357143 0.0 0.497245 53 53 40.00 6 13 0.461538 0.461538 0.0 0.518875 54 54 40.50 0 2 0.000000 0.000000 0.0 0.000000 55 55 41.00 2 6 0.333333 0.333333 0.0 0.516398 56 56 42.00 6 13 0.461538 0.461538 0.0 0.518875 57 57 43.00 1 5 0.200000 0.200000 0.0 0.447214 58 58 44.00 3 9 0.333333 0.333333 0.0 0.500000 59 59 45.00 5 12 0.416667 0.416667 0.0 0.514929 60 60 45.50 0 2 0.000000 0.000000 0.0 0.000000 61 61 46.00 0 3 0.000000 0.000000 0.0 0.000000 62 62 47.00 1 9 0.111111 0.111111 0.0 0.333333 63 63 48.00 6 9 0.666667 0.666667 1.0 0.500000 64 64 49.00 4 6 0.666667 0.666667 1.0 0.516398 65 65 50.00 5 10 0.500000 0.500000 0.5 0.527046 66 66 51.00 2 7 0.285714 0.285714 0.0 0.487950 67 67 52.00 3 6 0.500000 0.500000 0.5 0.547723 68 68 53.00 1 1 1.000000 1.000000 1.0 NaN 69 69 54.00 3 8 0.375000 0.375000 0.0 0.517549 70 70 55.00 1 2 0.500000 0.500000 0.5 0.707107 71 71 55.50 0 1 0.000000 0.000000 0.0 NaN 72 72 56.00 2 4 0.500000 0.500000 0.5 0.577350 73 73 57.00 0 2 0.000000 0.000000 0.0 0.000000 74 74 58.00 3 5 0.600000 0.600000 1.0 0.547723 75 75 59.00 0 2 0.000000 0.000000 0.0 0.000000 76 76 60.00 2 4 0.500000 0.500000 0.5 0.577350 77 77 61.00 0 3 0.000000 0.000000 0.0 0.000000 78 78 62.00 2 4 0.500000 0.500000 0.5 0.577350 79 79 63.00 2 2 1.000000 1.000000 1.0 0.000000 80 80 64.00 0 2 0.000000 0.000000 0.0 0.000000 81 81 65.00 0 3 0.000000 0.000000 0.0 0.000000 82 82 66.00 0 1 0.000000 0.000000 0.0 NaN 83 83 70.00 0 2 0.000000 0.000000 0.0 0.000000 84 84 70.50 0 1 0.000000 0.000000 0.0 NaN 85 85 71.00 0 2 0.000000 0.000000 0.0 0.000000 86 86 74.00 0 1 0.000000 0.000000 0.0 NaN 87 87 80.00 1 1 1.000000 1.000000 1.0 NaN
結果を見るだけだとよく分からないです。こういう場合は10代、20代など区分を作成して再度クロス集計するかヒストグラムで見た方が理解しやすいかもしれません。
Survived x Pclass・Ageのクロス集計
# Survived x Pclass・Ageのクロス集計
HTML(cross_tab_stats(df,"Survived",["Pclass","Age"]).to_html())
select_cols: ['Pclass', 'Age', 'Survived'] groupby_cols: ['Pclass', 'Age']
さらに見にくくなったので結果は省略します 笑
Survived x SibSpのクロス集計
# Survived x SibSpのクロス集計
cross_tab_stats(df,"Survived","SibSp")
select_cols: ['SibSp', 'Survived'] groupby_cols: ['SibSp']
index SibSp Survived sum count sum/count mean median std 0 0 0 210 608 0.345395 0.345395 0.0 0.475888 1 1 1 112 209 0.535885 0.535885 1.0 0.499908 2 2 2 13 28 0.464286 0.464286 0.0 0.507875 3 3 3 4 16 0.250000 0.250000 0.0 0.447214 4 4 4 3 18 0.166667 0.166667 0.0 0.383482 5 5 5 0 5 0.000000 0.000000 0.0 0.000000 6 6 8 0 7 0.000000 0.000000 0.0 0.000000
SibSp=1の場合、生存者の割合が比較的高めです。
これはもしかすると配偶者と乗船している女性であることが生存率と関係しているのかも知れません。
性別と相関している可能性はあるかも知れません。
Survived x Parchのクロス集計
# Survived x Parchのクロス集計
cross_tab_stats(df,"Survived","Parch")
select_cols: ['Parch', 'Survived'] groupby_cols: ['Parch']
index Parch Survived sum count sum/count mean median std 0 0 0 233 678 0.343658 0.343658 0.0 0.475279 1 1 1 65 118 0.550847 0.550847 1.0 0.499529 2 2 2 40 80 0.500000 0.500000 0.5 0.503155 3 3 3 3 5 0.600000 0.600000 1.0 0.547723 4 4 4 0 4 0.000000 0.000000 0.0 0.000000 5 5 5 1 5 0.200000 0.200000 0.0 0.447214 6 6 6 0 1 0.000000 0.000000 0.0 NaN
こちらもParch>=1の場合、生存者の割合が比較的高めのようです。
映画の通りだとしたら子供は優先して救命ボートに乗ることが出来たと考えられるので、生存率が高めなのかと考察出来ました。
Survived x Embarkedのクロス集計
# Survived x Embarkedのクロス集計
cross_tab_stats(df,"Survived","Embarked")
select_cols: ['Embarked', 'Survived'] groupby_cols: ['Embarked']
index Embarked Survived sum count sum/count mean median std 0 0 C 93 168 0.553571 0.553571 1.0 0.498608 1 1 Q 30 77 0.389610 0.389610 0.0 0.490860 2 2 S 217 644 0.336957 0.336957 0.0 0.473037
Cherbourgが一番生存者割合が他の港から乗船した客より高いようです。これだけの結果だと何とも言えませんが、3rdクラスの乗客が少ないとかですかね?こちらはなぜなのかもっとデータを見る必要がありそうですね。
まとめ
次はデータを可視化して色々俯瞰してみようと思います。
クロス集計の結果で分かっていることを視覚化してみてみることになると思いますが、表形式で見るより直感的なので私はいつも可視化してみることにしています。