自分のキャリアをあれこれ考えながら、Pythonで様々なデータを分析していくブログです

(その2-2) タイタニックのデータ俯瞰 クロス集計

Data Analytics
Data Analytics

データの理解の後半パートは目的変数と説明変数の関係性を中心にして集計や可視化をしていきたいと思います。

今回は生存するかどうかを当てるモデルを作成するつもりなので、目的変数は生存有無フラグ(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

  1. data: DataFrame
  2. atarget: str
  3. 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")
Out[0]

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")
Out[0]

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())
Out[0]

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())
Out[0]

select_cols: ['Pclass', 'Age', 'Survived']
groupby_cols: ['Pclass', 'Age']

さらに見にくくなったので結果は省略します 笑

Survived x SibSpのクロス集計

# Survived x SibSpのクロス集計
cross_tab_stats(df,"Survived","SibSp")
Out[0]

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")
Out[0]

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")
Out[0]

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クラスの乗客が少ないとかですかね?こちらはなぜなのかもっとデータを見る必要がありそうですね。

スポンサーリンク

まとめ

次はデータを可視化して色々俯瞰してみようと思います。

クロス集計の結果で分かっていることを視覚化してみてみることになると思いますが、表形式で見るより直感的なので私はいつも可視化してみることにしています。

タイトルとURLをコピーしました