データ分析　タイタニック号2

[Aidemy](https://aidemy.net/)　2020/10/30
#はじめに
　こんにちは、んがょぺです！バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます！
　今回は、「データ分析　タイタニック号」の2つ目の投稿になります。どうぞよろしくお願いします。

＊本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・④パターンの分析,データの分析(前回の続き)
・③データの整形、作成、クレンジング(戻ります)→__新しい特徴量の作成__


#④パターンの分析,データの分析
##前回のピボットテーブル（相関）の分析
・__Pclass=1__のとき、Survivedの平均が__0.62__であり、0.5を超えた__有意な（正の）相関がある__と言えるので、Pclassはモデルの特徴量として使うこととする。
・同様に、__Sex=Female__のとき、Survivedの平均が__0.74__なので、これもモデルの特徴量として使う。
・__SibSpとParchについては有意な相関がなかった__ので、この2つを組み合わせた__新しい特徴量を作成する__。

##データを可視化
###Ageの範囲を指定してヒストグラム化
・__「子供は生存率が高い」__という仮説を確かめるため、__Ageのデータを範囲指定して分割する__。これを使用して、データの分布を__ヒストグラムを使って作成する__。
・このヒストグラムについて、横軸はAgeであるが、縦軸はデータの個数、つまり乗客数であるので注意が必要。

・ヒストグラムは__「df.hist()」__で作れる。階級を何個作るか（データを何分割するか）は引数に__「bins=」__で指定すればよく、Surviveが0と1のそれぞれのデータ数を見たいときは引数に__「by=」__でそのパラメータを指定すれば良い。
・また、Chapter1で見たとおり__Ageには欠損値が含まれている__ので、__dropna__で最初に欠損値を削除しておく。

・コード
![スクリーンショット 2020-10-22 15.12.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/d52c0604-8f15-28f3-28a8-0007c8dc74fd.png)

・結果（グラフ）
![スクリーンショット 2020-10-22 15.13.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/21de6f8c-6ee5-c5d5-9e7f-36a4f74ca02f.png)

・結果を見ると、__「0~5才」の生存率が高い__ことがわかる。
・また、データの総数を見ると__「15~35才」の数が多い__こともわかる。

##「カテゴリ値と数値」を持つ特徴量の相関
・次は、前項で作ったAgeごとのヒストグラムについて、さらに__Pclassごとにわけて可視化__する。
・コードは__SurvivedとAgeについてヒストグラム化__し、それを__「by=train_df['Pclass']」__で分割するように記述する。

・コード
![スクリーンショット 2020-10-22 15.29.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/d031c7be-7aa0-973e-dea4-9beea99e9a47.png)
・グラフ（死亡者）
![スクリーンショット 2020-10-22 15.30.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/e3174104-dd48-8c5e-f745-1765c5f73ab8.png)
・グラフ（生存者）
![スクリーンショット 2020-10-22 15.30.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/4da4dd95-c37a-5b5b-a1b7-3bc7da79b32a.png)

・このグラフから、__「Pclass=3の死亡者が圧倒的に多い」「Pclass=1の生存者が多い」「Pclass=2,3のAgeが0~5才の生存者が多い」__ということがわかる。いずれも仮説の通りであると言える。

##「カテゴリ値」を持つ特徴量の相関
・__「Embarked」__が__['C','Q','S']__のときの「Survived」と「Pclass/Sex」の関係をピボットテーブルで作成し、__「plt.plot()」__で図示する。

・ピボットテーブルの作成はChapter1と同様に行う。今回は__Embarkedの中身を条件式で指定するのも忘れないようにする__。また、グループ化（集計）するのは__PclassとSex__の二つなので、リストで渡す。
・作成したピボットテーブルを、Sexが__maleとfemale__で分割し、__Pclassの順でソート__する。
・これを、__「plt.plot()」__で図示する。x軸は__['1','2','3']__で、y軸はデータの__Survivedの数__にする。

・コード（__Embarked='C'__のとき。他2つは同様に作成したものとする）(切れているところは前回と同じ)
![スクリーンショット 2020-10-22 16.21.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/fdc8ac09-fcd4-37e3-6b94-0ea66089e488.png)

・グラフ(Embarked='C'のときのみ、他二つも同じようなグラフ)
![スクリーンショット 2020-10-22 16.22.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/be867e8b-2f6b-9c28-cf5d-e597578c43cd.png)

・このグラフから__「女性の生存率が圧倒的に高い」__ということができる。これも仮説の通りである。また、ここでは図示していないが、__「Embarked='Q'の男性の生存率がとても低い」__ということもわかった。

##「カテゴリ値」を持つ特徴量と「数値」を持つ特徴量間の相関
・今度は、前項の__「Pclass」の部分を「Survived」に、「Survived」の部分を「Fare」に置き換えて__、全く同じように図示する。
・「Fare」と「Survived/Sex」の関係をピボットテーブルで作成したら、次はそれをSurvivedが0か1かで分割する。今回は、それを__サブプロット__で表す。__「plt.subplot()」__でできる。横軸には__「Sex」__縦軸には__「Fare」__の棒グラフ（__plt.bar()__）をセットし、左が__「Survived==0」__、右が__「Survived==1」__となるようにセットする。

#③データの整形、作成、クレンジング
・ここからは、__特徴量の変換・作成・補完__を行う。
##データの削除
・まずはChapter1の方針で決めたように、欠損や重複の多い__「Ticket」と「Cabin」を削除する__。
・列の削除なので__「drop(axis=1)」__を使う。

##新しい特徴量の作成
・同様に、Survivedと明らかに相関のない__「Name」と「PassengerId」も削除していく__が、「Name」に含まれる__敬称（Mr,Mrs,Drなど）とSurvivedとの相関がある可能性がある__ので、確認する。
・敬称をNameから抽出するには、__正規表現を使う__。str型のデータから正規表現にマッチする部分を抽出するには、__「str.extract('正規表現')」__を使う。今回の正規表現は__'([A-Za-z]+)\.'__となる。これは「Dr.」など、敬称は「.」の前に大文字小文字が複数あるため、このように表現される。また、この第二引数には__「expand=False」__を指定するが、これは抽出したものを__DataFrameで返す__ことを示している。
・この抽出したものは、__'Title'__という新しい列（特徴量）に格納する。
・この__'Title'と'Sex'__の関係を__「クロス集計」__する。これは、今回の例で言えばDr.やMrs.などのTitleのカテゴリごとにSexの要素が__どれぐらい出現したか__を集計するものである。
・クロス集計を行うには__「pd.crosstab()」__関数を使う。第一引数には結果の行にあたるデータ（今回は__'Title'__）、第二引数には結果の列にあたるデータ（__'Sex'__）を渡す。

・コード![スクリーンショット 2020-10-23 15.28.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/3a3d54fa-669e-ec58-d0cd-c0463cabf909.png)

・結果（一部のみ）![スクリーンショット 2020-10-23 15.29.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/b946ce52-b42c-6610-b702-733193b204d0.png)

・ここで出てきた敬称のうち、頻度の少ないものを__「'Rare'」__というその他枠にまとめる。また、同様の意味を持つ'Mile'は'Miss'に、'Mme'は'Mrs'に置き換える。これらの置き換えは__「replace()」__で行えば良い。
・ここまで行ったらピボットテーブル化し、相関を調べる。

・コード![スクリーンショット 2020-10-23 15.53.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/f5fbcf9e-4689-7002-c398-1e91950f9a23.png)

・このTitleについて、各要素を数値として扱いたいので、__{"Mr":1,"Miss":2,"Mrs":3,"Master":4,"Rare":5}__に変換する。
・方法は、上記対応表（辞書）を準備しておき、dataset['Title']に対して__「map()」__関数を適用させることで変換できる。
・以下の実行が終わったら、当初の想定どおり__「Name」と「PassengerId」を削除する__。

・コード![スクリーンショット 2020-10-23 16.06.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/5943862b-98ea-c3c3-5043-4354df7e6780.png)

・結果![スクリーンショット 2020-10-23 16.06.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/5943862b-98ea-c3c3-5043-4354df7e6780.png)

##多値データを二値データに変換
・前項で使用した__map()__関数を使って、次は__多値データを二値データに変換する__。
・ここでは__'Sex'__が__male:0,female:1__となるように変換する。
・__astype()__メソッドの引数に__データ型__を指定すると、全ての列の指定したデータ型が全て変更された、新しいDataFrameが返される。今回は全てint型にしたいので、引数には__int__と指定する。

・コード
![スクリーンショット 2020-10-24 10.52.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/fc9e3536-e9a6-ff47-c7b5-e4cd14f6bb4b.png)

##特徴量の補完　Age
・データの削除、変換、作成を行ったら、次に__補完__を行う。補完はNullまたはNaNに対して__値を推測して代入する__ことである。
・まずは連続的な数値データである__「Age」__を補完する。補完の方法は以下の3つがある。
　1：平均を参考にして__乱数を生成__する
　2：相関のある__他の特徴量を参考にする__
　3：1と2を__組み合わせる__、具体的には、平均と標準偏差を参考にして乱数を生成する

・今回は__「2」__の手法を用いる。具体的に「Age」と相関のある特徴量とは__「Sex」と「Pclass」__の二つが挙げられる。この二つの特徴量を参考にして、Ageの推測値（__中間年齢__）を取得する。
・まずはAgeの値を格納する__2行3列の空の配列を用意する__。このように具体的な行列の大きさがわかっているからの配列を作るときは__「np.zeros()」__を使うと良い。引数に行列の形を指定することで、値が全て0の（__実質的に空の__）配列を作成することができる。

・次に、Ageの推測値（__中間年齢__）を算出する。まずは'Sex'と'Pclass'の全ての組み合わせの場合の'Age'の値を（NaNを除外して）抽出する。組み合わせは__「2*3通り」__あるので、行列の大きさを__(2,3)__と指定した。これに対して__「median()」__を使って__中央値を取得__すると、これが中間年齢となる。
・このそれぞれの場合における中央値を(2,3)の配列に格納して終了。

・コード![スクリーンショット 2020-10-24 11.45.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/8635098f-1cc3-b47d-3fde-5d38456d4077.png)

・結果
![スクリーンショット 2020-10-24 11.46.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/490326b3-f4d0-33e4-80ce-228e9bfc3e93.png)

##連続値を離散値に変換
###AgeBand
・Ageの補完を行ったら、連続値である__Age__全体について、__離散値に変換する__。これはChapter1の指針「作成」の項で示した通り、__範囲を指定して分割する__（＝離散データに変換する）ことで予測しやすくするために行う。
・離散値に変換することを__「ビニング処理」__あるいは__「ビン分割」__という。行う方法は、__「pd.cut()」__を使う。第一引数にはデータを渡し、第二引数にはデータを__何分割するか__を指定する。今回は5分割とし、離散データとして__「AgeBand」__という新しい特徴量に格納する。

・また、AgeBandとSurvivedとの相関を確認したいので、__ピボットテーブルも作成する__。

・コード![スクリーンショット 2020-10-24 15.05.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/7e4a2eb9-9049-f7bf-089f-9bc99492ab70.png)

・次に、離散値に変換したAgeを__順序データに変換する__。具体的には、AgeBandを参考にして、Ageが__「0~16」なら0、「16~32」なら1、「32~48」なら2、「48~64」なら3__に変換する。
・変換方法は、__loc[条件式,変換する列]__で'Age'の範囲を抽出してそれを上記の数値に置き換えれば良い。
・ここまで終えたらAgeBandは__drop()__で削除する。

・コード![スクリーンショット 2020-10-24 15.06.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/91f81220-3eec-8b5e-a75e-54730478ecb5.png)

##新しい特徴量の作成
###FamilySize
・方針の「作成」で示した通り、同系統の特徴量__「Parch」「Sibsp」__を組み合わせて__「FamilySize」__という新しい特徴量を作成する。この特徴量は__「家族の数」__を表す。
・方法は、普通に__二つの列を抽出して足し合わせれば良い__。ただし、自分も「家族の数」に入るので、その分の__「+1」__も忘れないようにする。
・新しい特徴量を作成したときは、これまで通りSurvivedとの平均をとって__相関を調べる__。

・コード![スクリーンショット 2020-10-24 15.07.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/20905888-8aa5-75a6-c0de-58a3afe6aa48.png)

###IsAlone
・上記FamilySizeについて、より抽象化するために__「独身か家族もちか」__という分類を行う。すなわち、FamilySizeが1なら「__IsAlone__=1」、それ以外は全て「__IsAlone__=0」というように変換する。
・作り方としては、__まず全ての値を「0」として__IsAloneという特徴量を作成し、FamilySize=1の時のみ「1」に変換するように行う(__loc()__を使う)。
・ここまで行ったら、__Parch,SibSp,FamilySizeを削除する__。

・コード![スクリーンショット 2020-10-24 15.07.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/0bac092b-b650-d823-22d6-f72c14bf151b.png)

###Age*Class
・ここでは「年齢」に「船室のグレード」を掛けて重み付けした__「Age*Class」__という人工的な特徴を作成する。作り方はそのままAgeとPclassを抽出してかければ良い。

##最頻値で補完　Embarked
・Chapter1で見た通り、訓練データの__Embarkedには2つ欠損値がある__。この欠損値について、まずは__削除__し、その部分を__最頻値で置き換える__。ちなみに最頻値は__「S」__である。
・最頻値は__「mode()」__で取得できる。また、最頻値のみを取得したい（indexは必要ない）ので[0]でcolumnのみ取得する。
・取得した最頻値を変数__freq_port__に格納し、__「fillna(freq_port)」__で補完する。

・コード
![スクリーンショット 2020-10-24 15.41.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/c10b7e3d-f4a5-42cc-7758-448aad377c44.png)

・また、Sexなどと同様に、Embarkedはカテゴリ値であるので、__{'S':0,'C':1,'Q':2}__のように__数値に変換する__。__map()__関数を使う。また、__astype(int)__とする。

・コード
![スクリーンショット 2020-10-24 15.54.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/486ad141-04db-d7ba-830d-8c814894977d.png)

##数値データの補完　Fare
・テストデータの__Fareには1つだけ欠損値が存在する__。この欠損値には中央値（__median__）を代入する。
・さらに、Ageと同様に連続値である__Fareを離散値に変換する__。変換したものを__FareBand__という新しい特徴量に格納する。離散値はFareを4分割にして算出する。
・Ageのときは__「cut()」__で範囲を分けたが、これは__「範囲が均等になるように分割する」__ときに使うものである。一方今回のFareでは「範囲に含まれる__要素の数__が均等になるように分割する」ときに使用する「__qcut()__」を使う。

・コード![スクリーンショット 2020-10-24 17.00.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/2e191c9f-1baf-a732-b0c1-cebc72c7d1e8.png)

・このFareBandを参照して、Fareを離散値に置き換える。今回は__「~7.91」が0、「7.91~14.454」が1、「14.454~31」が2、「31~」が3__というように変換する。
・変換方法はAgeの時と同じく__「loc[条件式,変換する列]」__で行う。

・コード
![スクリーンショット 2020-10-24 16.59.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/e5787f40-ce6a-b5be-22e3-8219ddca9213.png)

#まとめ
・予測の目的となる変数__「Survived」との相関を調べ__、有意な相関があるものについてはそのまま使用し、有意な相関が見られないものについては、Nameから敬称Tirleを抽出したように、その変数の__一部分を取り出して新しい特徴量を作成__したり、ParchとSibSpを__組み合わせて__FamilySizeにしたように、新しい特徴量を作成したりする。
・また、AgeやFareなどの__連続値は離散値に変換__して特徴量を変換する。__欠損値を含む場合は中央値や最頻値を使って値を補完する__。
・SexやEmbarkedは[male,female][S,C,Q]のようなデータになっているので、__[0,1][0,1,2]__のように数値データに置き換える。

今回は以上です。最後まで読んでいただき、ありがとうございました。