今回はseabornライブラリを使用して、Titanicデータセットの各列が生死とどのような関係にあるかを(少しだけ)確認してみました。それだけで、スコアはアップ!
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
前回は、Kaggleのコンペティションに初参加ということで、皆さんの多くが手始めに触るであろうTitanicコンペティションに自分も参加して、取りあえずデータをDNN(Deep Neural Network)に突っ込んでみました。その後、コードの再利用を念頭に置いたプログラムの構造化というちょっとズレた方向に進んだり、k-fold交差検証をしたりしてみました。
今回はちょっと方向性をまた変えて、探索的データ分析(Explanatory Data Analysis、EDA)の初歩の初歩を体験してみることにしました。seabornというデータ視覚化ライブラリを使用して、Titanicのデータを少々分析して、その結果から、テストデータのSurvived列の値を推測するという感じです。
前回に最後に触れた「PyTorchのrandom_split関数があれば、scikit-learnのKFoldクラスを使わずとも、K-fold交差検証を行うコードを書けるんじゃないか」という話についても最後に簡単に触れようかなぁ。結果だけいえばできるんですが、まあだからナニ? という話にしかなりませんでした(笑)。[かわさき]
PyTorchで交差検証するときも、scikit-learnのKFoldクラスを使うのが一般的なのですかね。Google検索したらそのサンプルコードばかりヒットしたので。[一色]
本稿の最後に示すget_kfold_datasets2関数のコードに出てくるように、(random_split関数などを使って)データセットを複数のSubsetクラスのインスタンスに分割して、それらをConcatDatasetクラスでまとめるという方法もあるみたいです。
まずは今回のスコアの変遷について、まとめておきます。以下のスコアは前回に作成したDNNのようなモデルを使わずに、EDAから得られたデータ特性を基に「○○という条件の下では××の生死はこうなる」ということをそのままベタに予測して得られたものです。
条件 | スコア |
---|---|
女性は全員生存/男性は全員死亡 | 0.76555 |
女性は全員生存/男性で旅客運賃のレンジが一番上の人は生存 | 0.76555 |
女性は全員生存/男性で年齢のレンジが最小または最大の人は生存 | 0.76794 |
旅客クラスが3、出港地が'S'の女性は死亡 | 0.77990 |
探索的データ分析を簡単にまとめると「何らかの課題を解決するためにそろえられたデータから、それらがどんな意味を持つのか、本当に必要なデータは何か、課題を解決する上で無視すべきデータ(外れ値)はどれか、データにどんな相関が見られるか」などの情報を見いだすことといえます。
Titanicコンペであれば、以下のようなデータがそろえられています。
Kaggleではこうした情報が事前にまとめられていることもあれば、そうではないこともあるようです。Titanicコンペであれば、コンペページの[Data]タブにこうした情報がまとめられています。
以下では、このデータセットをざっくりと眺めてみることにしましょう。
ここではpandasを使ってTitanicのデータセット(CSVファイル)を読み込んでいます。その後、上で「直接は関係ない」と述べた列を削除しています。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df0 = pd.read_csv('../input/titanic/train.csv')
droprows = ['PassengerId', 'Name', 'Ticket', 'Cabin']
df0 = df0.drop(droprows, axis=1)
この後に何をすればよいかと考えましたが、まずは各列が生死情報とどの程度の相関を持っているかを計算してみることにしました。というと難しそうですが、実際にはpandasのデータフレームが持つcorrメソッドを呼び出すだけです。
df1 = df0.replace('male', 0).replace('female', 1)
df1 = df1.replace('S', 0).replace('C', 1).replace('Q', 2)
df1.corr()
注意したいのは、corrメソッドは数値型の値だけを対象とすることと、欠損値があればその値は無視されることです。上のコードで、'male'や'female'あるいは'S'や'C'などの値を数値に置き換えているのはこのためです。また、ここでは欠損値については無視しています。
欠損値については、それをDNNに入力するようなときには何らかの形で対応する必要がありますが、今回はそこまでたどり着いていないので、無視したままとしましょう。
これを実行した結果が以下です。
各列の相関関係はこれを見ても分かりますが、より分かりやすくするにはseabornのheatmap関数を使うとよいようです。
_, ax = plt.subplots(figsize=(10, 8))
sns.heatmap(df1.corr(), annot=True, ax=ax)
1行目は表示領域の指定で、2行目が実際にヒートマップを表示するコードとなっています(annot=Trueを指定すると、上の画像に表示されていた数値群がヒートマップにも表示されます)。
相関関係が色を使って分かりやすく表示されました。右側のバーを見ると分かる通り、相関関係相関関係は黒(負の相関)〜赤紫(無相関)〜クリーム色(正の相関)のようになっています。そして、生死情報に関連する項目を知りたいのですから、注目すべきは一番上の行(Survived行)でしょう。パッと見には、オレンジ色で表示されているSex列と、明るめの赤で表示されているFare列の相関が強そうです。まずは性別の違いが生死にどう関係しているかを確認してみましょう。
Titanic号からは女性と子どもが優先して脱出したという話を聞いたことがあるので、年齢がそれほど強く出てこないのが意外でした。
おお ! 確かにSex列とFare列は正の相関が高いですね。でもPclass列は負の相関が高いので、こちらも確認した方がよかったかもと思いました。
このように相関を可視化すれば、有効な特徴量が分かりやすいですね。これは必須な作業だと思えました。今度やろう。
ここではseabornのcatplot関数を使って、男女で生死がどう違っているかをプロットしました。
sns.catplot(x='Survived', col='Sex', kind='count', data=df0)
その結果は以下の通りです。
大きく分けて、左側が男性の死者数と生存者数、右側が女性の死者数と生存者数です。一目で女性の生前率の方が高いことが分かりますね。そこで、テストデータに対して、女性が全員生存、男性は全員死亡と予測して、その結果を保存、提出してみました。
dft = pd.read_csv('../input/titanic/test.csv')
dft['Survived'] = dft['Sex'] == 'female'
dft['Survived'] = dft['Survived'].astype(int)
dft[['PassengerId', 'Survived']].to_csv('onlygender_submission.csv', index=False)
この予測のスコアはなんと「0.76555」でした。前回のモデル4(3種類のモデルを使って、K-fold交差検証を行ったもの)のスコアが「0.76794」だったことを考えると、たったこれだけのことでそこまでのスコアが出てしまうというのが……。
むやみやたらとDNNに突っ込んでみる方針がいとも簡単に否定された(笑)。データの分析と前処理はきちんとやらないとダメってことですね。
うんうん。やっぱり探索的データ分析とか特徴量選択とか特徴量エンジニアリングとか機械学習では大切だな、と実感できます。
ところで、この結果をもって「Titanicの機械学習では、性別(Sex)の特徴量を使った方がいい」という理解でいいのかな?
次回にそれは考えることにしましょう。指摘のあったPclassなど、ちゃんと話に上がってきていないものもありますし。この後出てくる連続量の離散化など以外にもまだやることはあるっぽいので(ぐっ)。
次に旅客運賃の差が、生存率にどのように関連しているかを見てみます。高いお金を払ったお客さんが優先して救助されていそうな気はしますね。ただし、その前に旅客運賃の範囲を調べておく必要があるでしょう。
df0['Fare'].describe()
このコードを実行すると、以下のような出力が表示されます。
ここからはデータ数、平均、標準偏差、最小値、最大値などの情報が得られます。ここでは最小値と最大値を知ることを目的でした。また、以下のコードでデータの分布を確認できます。
sns.histplot(df0['Fare'])
実行結果は以下の通りです。
運賃は低い方に集中して、高い運賃を支払った人は少ないようです。ところで、この分布が生存率とどの程度関係しているかを調べるには、少し工夫が必要です。運賃は連続する浮動小数点数値なので、それらの値を価格帯ごとにまとめた方がよいでしょう。
ビニング(binning:ビンにグループ化)とか離散化(discretization)とか言われている特徴量エンジニアリングのテクニックですよね。
Copyright© Digital Advantage Corp. All Rights Reserved.