kaggle Titanicに挑戦!
初めに
この記事では、kaggleのTitanicコンペについて初心者にも分かりやすいように説明していきます!(自分も初心者ですが...)なお、コードは以下を参考にして下さい。
まずはkaggleの登録をしよう
まず、kaggleの登録方法を説明します。ブラウザでkaggleと検索し、一番上のページを開くと、おそらく下のような画面になるかと思います。右上のRegisterから登録します。Googleアカウントをお持ちの方は左下のREGISTER WITH GOOGLEから登録することもできます。
kaggleの登録を終えたらサインインします。左上に三本線のメニューがあり、そこをクリックすると下のような画面になります。Competitionsをクリックすると、開催中のコンペがたくさん表示されます。Codeをクリックすると、他の人が書いたコードを見たり、自分のコードを書いたりできます。Coursesをクリックすると、初心者向けの学習コンテンツがたくさん用意されています。自分もいくつか取り組んでいます。
kaggle Titanicコンペに参加しよう
次に、kaggleのTitanicコンペに参加します。メニューのCompetitionsをクリックすると上の方に検索バーがあるので、そこから検索していきます。
検索バーにTitanicと入力すると、下の画面のように2つのコンペが出てきます。Titanic - Machine Learning from Disasterを選択します。
Titanic - Machine Learning from Disasterを選択すると、下の画面のようにTitanicコンペのページに行くことができます。Overviewではコンペの概要、評価方法が書かれています。Dataでは本コンペで使用するデータを取得することができます。Codeでは他の人が本コンペに用いたコードを見たり、自分のコードを見たり書いたりできます。Discussionでは本コンペについて他の人と議論できます。(自分はまだしたことがないです。)Leaderboardではコンペの順位を確認することができます。Rulesには色々なルールが書かれています。
Rulesをクリックし、I Understand and Acceptをクリックすると、コンペに参加できます。(自分は既にTitanicコンペに参加しているため、下の画面は別のコンペの画面を表示しています。どのコンペでも参加方法は大体同じです。)
kaggle notebookを使おう
続いて、実際にコードを書いていきます。コーディングする環境としてはkaggle notebookを用います。(google colaboratoryを用いる場合はデータをダウンロードする必要があります。)コンペのページのCodeをクリックします。すると、右側にNew Notebookというボタンが出てくるので、そこをクリックします。
すると、下のような画面になります。まず、左上の箇所からnotebookの名前を変更します。notebookの名前の下に色々なボタンがあります。+はセルを追加するボタン、ゴミ箱はセルを削除するボタン、はさみマークはセルを切り取るボタン、その右側はセルをコピーするボタン、さらにその右側は、切り取ったりコピーしたセルを貼り付けるためのボタンになっています。また、右矢印のボタンは1つのセルに書かれたコードを実行するためのボタンで、Run Allは全てのセルを実行するためのボタンになっています。また、Codeという部分をクリックすることで、CodeとMarkdownを切り替えることができます。なお、セルはドラッグすることで位置を入れ替えることができます。
さらに、画面の右側がフォルダ構成を表しています。kaggle notebookを用いると、既にコンペに用いるデータが用意されているため便利です。google colaboratoryを用いる場合は、自分でデータを適切なフォルダに配置する必要があります。
Titanicコンペの概要
Titanicコンペの目標、性能指標は、OverviewのEvaluationという部分に書かれています。
本コンペの目標は、Titanic号の乗客に関する様々な情報から、その乗客が最終的に亡くなったかどうかを予測することです。Survivedカラムの値が1であれば生存した、0であれば死亡したということに対応しています。性能は正解率という指標によって測られます。Titanicコンペの変数は以下のようになっています。
予測する対象である変数を目的変数といい、TitanicコンペではSurvivedになります。Survived以外の変数を説明変数といいます。次の節から実際にコードを書いていきます。
ライブラリの読み込み
まずは、使用するライブラリを読み込みます。ライブラリは、便利なプログラムの部品を集めてひとまとめにしたファイルのことです。
# ライブラリの読み込み
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn
# モデル作成のためのライブラリ
from sklearn.ensemble import RandomForestClassifier
# モデル作成に役立つライブラリ
from sklearn.model_selection import train_test_split
# 性能指標(正解率)
from sklearn.metrics import accuracy_score
# 不要な警告を無視する
import warnings
warnings.filterwarnings('ignore')
データの読み込みと確認
今回使用するデータはtrain.csv, test.csv, gender_submission.csvという3つのファイルになります。train.csvは学習用データであり、説明変数と目的変数のデータが与えられます。このデータから説明変数と目的変数の関係を学習します。一方、test.csvはテストデータであり、説明変数のみが与えられます。学習用データから説明変数と目的変数の関係性を学習しているので、それを用いることで説明変数のみのデータから目的変数を予測します。なお、gender_submission.csvは提出方法を表すファイルであり、このファイルの形式に沿って、提出ファイルを作成します。
では、実際にデータを読み込みます。pandasのread_csvを用いて訓練データとテストデータを読み込みます。ファイルのパスは画面右側のInputの部分からコピーすることができます。
# 学習用データ、テストデータ、提出サンプルデータの読み込み
train = pd.read_csv('../input/titanic/train.csv')
test = pd.read_csv('../input/titanic/test.csv')
sample = pd.read_csv('../input/titanic/gender_submission.csv')
次に、pandasのinfoやheadを用いて、データの基本的な情報を確認をします。(詳しくはコードを参照して下さい。)
さらに、学習用データを説明変数と目的変数に分けます。この際、説明変数には_x、目的変数には_yをつけました。テストデータは説明変数のみなので分ける必要はなく、学習用データと同じように_xをつけました。
# 学習用データを特徴量と目的変数に分ける
train_x = train.drop(['Survived'], axis=1)
train_y = train['Survived']
# テストデータは特徴量のみなのでそのままで良い
test_x = test.copy()
特徴量の作成
データの前処理をしていきます。まず、PassengerIdは乗客に番号を振っているだけであり、目的変数に影響を与えないと考えられるので、削除します。この際、pandasのdropを用います。
train_x = train_x.drop(['PassengerId'], axis=1)
test_x = test_x.drop(['PassengerId'], axis=1)
また、Name, Ticket, Cabinも上手く使えば予測に有用そうですが、煩雑な処理が必要そうなので、今回はこれらの変数を使わないことにします。
drop_col = ['Name','Ticket', 'Cabin']
train_x = train_x.drop(drop_col, axis=1)
test_x = test_x.drop(drop_col, axis=1)
次に、欠損値の処理をします。データにはしばしば欠損が存在し、モデルの多くは欠損値を含むデータを扱うことができないため、欠損値を何らかの値で埋める必要があります。ここでは、数値変数については平均値で補完し、カテゴリ変数については最頻値で補完します。
まずは、学習用データとテストデータの欠損値を確認します。train_x.isnull().sum()とすると、学習用データの説明変数ごとの欠損数を出力することができます。さらにtrain_x.isnull().sum().sort_values(ascending=False)を加えることで、欠損数が多い順に並び替えることができます。
#学習データの欠損値を確認する
print('訓練データの欠損値:\n', train_x.isnull().sum().sort_values(ascending=False), '\n')
#テストデータの欠損値を確認する
print('テストデータの欠損値:\n', test_x.isnull().sum().sort_values(ascending=False))
出力からAge, Embarked, Fareに欠損があることが分かります。Age, Embarked, Fareのデータの型を確認します。
print(train_x.info())
出力からAgeは数値変数、Embarkedはカテゴリ変数、Fareは数値変数であることが分かります。数値変数であるAge, Fareは平均値、カテゴリ変数であるEmbarkedは最頻値で補完します。Embarkedについては、分布を確認した上で最も頻度の高いカテゴリで補完しました。
# Ageカラムの欠損値を平均値で補完する
train_x['Age'] = train_x['Age'].fillna(train_x['Age'].mean())
test_x['Age'] = test_x['Age'].fillna(test_x['Age'].mean())
# 'Embarked'の分布
sns.countplot(data=train_x, x='Embarked')
# Embarkedカラムの欠損値を最頻値で補完する
train_x['Embarked'] = train_x['Embarked'].fillna('S')
test_x['Embarked'] = test_x['Embarked'].fillna('S')
# Fareカラムの欠損値を平均値で補完する
train_x['Fare'] = train_x['Fare'].fillna(train_x['Fare'].mean())
test_x['Fare'] = test_x['Fare'].fillna(test_x['Fare'].mean())
以上で欠損値の処理が完了しました。次に、カテゴリ変数の処理をします。カテゴリ変数は数値で表されていない変数であり、多くの機械学習モデルではそのまま分析に用いることができず、適した形に変換する必要があります。カテゴリ変数の変換として代表的なものが2つあり、1つ目はワンホットエンコーディングです。ワンホットエンコーディングは、カテゴリ変数の各カテゴリに対して、そのカテゴリかどうかを表す0,1の二値変数を作成します。つまり、説明変数の数がカテゴリ変数のカテゴリ数に応じて増加します。2つ目はラベルエンコーディングで、カテゴリ変数の各カテゴリを整数に置き換えます。今回はこちらを使います。
まず、データの型を確認します。
# データの情報の確認
print(train_x.info(), '\n')
print(test_x.info())
Dtypeがobjectとなっている変数がカテゴリ変数です。したがって、Sex, Embarkedについてラベルエンコーディングする必要があります。まず、Sexに含まれるカテゴリを確認します。
print(train_x['Sex'].unique())
print(test_x['Sex'].unique())
Sexにはmale, femaleが含まれることが分かりました。maleは0、femaleは1に変換したいと思います。
# 'Sex'をマッピング male:0, female:1
sex_mapping = {"male":0, "female":1}
train_x["Sex"] = train_x["Sex"].map(sex_mapping)
test_x["Sex"] = test_x["Sex"].map(sex_mapping)
次に、Embarkedに含まれるカテゴリを確認します。
print(train_x['Embarked'].unique())
print(test_x['Embarked'].unique())
EmbarkedにはS, C, Qが含まれることが分かりました。Sは0、Cは1,Qは2に変換します。
# Embarkedをマッピング S:0, C:1, Q:2
embarked_mapping = {'S':0, 'C':1, 'Q':2}
train_x['Embarked'] = train_x['Embarked'].map(embarked_mapping)
test_x['Embarked'] = test_x['Embarked'].map(embarked_mapping)
これで全ての変数を数値変数に変換することができました。
モデリングの流れ
次にモデリングを行っていきます。モデル作成の流れとしては、まずモデルの種類とハイパーパラメータを指定し、次に学習用データ(特徴量 + 目的変数)を与えて学習させ、最後にテストデータ(特徴量)を与えて予測させるという形になります。
モデルの評価
未知のデータに対する予測能力のことを、モデルの汎化性能といいます。モデルの汎化性能を良くするには、そのモデルの汎化性能を知る方法が必要です。学習用データ全体で学習させてしまうと、モデルを評価するためのデータがなくなってしまうので、一部のデータを評価用のデータとして分けておき、評価のために使用します。分け方にいくつか種類がありますが、ここではホールドアウト検証を用います。ホールドアウト検証では、学習用のデータの一部を学習に使わず、評価用にとっておきます。残りの学習用データでモデルを学習した上で、評価用データでモデルを評価します。こうすることで、未知のデータに対する予測能力を測ることができます。
モデリング
実際にコードを書いていきます。まず、学習用データを訓練用データと評価用データに分けます。データの分割にはtrain_test_splitを用います。引数test_sizeで評価用データの割合を指定しています。
# 分割方法の指定
tr_x, va_x, tr_y, va_y = train_test_split(train_x, train_y, test_size=0.3, random_state=0)
次にモデルを作成します。例としてRandomForestClassifierを用います。また、モデルの評価にはaccuracyを用います。どちらもsklearnに関数が用意されています。
# モデルの作成と評価(RandomForestClassifier)
rfc = RandomForestClassifier(random_state=0)
rfc.fit(tr_x, tr_y)
va_pred = rfc.predict(va_x)
score = accuracy_score(va_y, va_pred)
score
提出物の作成
ホールドアウト検証で性能を測りました。その結果、最も性能が高かったモデルを使用します。(今回はRandomForestClassifierのみ用いましたが、本来は様々な前処理、モデルを用い、その中で最も精度が高かった手法を選択します。)まず、学習用データ全てを用いてモデルの学習を行い、その後テストデータに対して予測します。
# 学習データ全体でモデルの学習をする
rfc.fit(train_x, train_y)
# テストデータに対して予測する
predict = rfc.predict(test_x)
gender_submission.csvの形に整えます。
submit = pd.DataFrame({'PassengerId': test['PassengerId'], 'Survived': predict})
最後に提出用ファイルを作成します。
# 提出用ファイルの作成
submit.to_csv('submission.csv', index=False)
提出
最後のセルを実行すると、画面の右側のOutputにsubmission.csvというファイルが現れます。このファイルをダウンロードしてから提出することも可能ですが、せっかくなのでこのnotebook上で提出します。画面の右側のCompetitionsという部分を開き、Submitをクリックすると提出することができます。
最後にスコアを確認します。My Submissionsというボタンから結果を確認することができます。スコアは0.75598だったようです。(ひくい...)
前処理やモデリングで工夫することで、さらに精度を向上させることができます!
最後に
本記事を最後まで読んで下さりありがとうございました!
Discussion