接着剤の精進日記

競プロでの精進や研究に関係したことを書いていきます。

Kaggleのtitanic問題に挑戦

はじめに

機械学習やデータサイエンスの勉強をし始めてなんとなくわかってきたので、
アウトプットとしてKaggle初心者がTitanicチュートリアルに挑戦してみました。

Kaggleとは

Kaggleは、世界中のデータサイエンティストに対し、企業からコンペ形式でお題を与えられます。
お題に関するデータが与えられるのでデータサイエンティスト達はそれらを分析して、予測結果を提出します。
その予測結果が高かったものが、上位者となり、順位によっては賞金がもらえるというものです。
https://www.kaggle.com/

Titanicチュートリアル

今回は、Titanicチュートリアルに挑戦しました。
あの有名なタイタニック号の乗船者たちのデータから、
生存者たちを予測するというものです。

分析環境

言語:Python3.6.1(anaconda4.4.0)
環境:jupyter notebook

データの前処理

各問題では、train.csvファイルとtest.csvファイルが提供されるので、それらをダウンロードした後、データを読み込みます。

import pandas as pd
import numpy as np
df_train = pd.read_csv("train.csv")
df_test = pd.read_csv("test.csv")
df_train.head(3)

f:id:tkm-kyudo:20171203160257p:plain

一先ず欠損データの確認をします。

df_train.isnull().sum()
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64

上記のようにAge,Cabin,Embarkedに欠損値があることがわかりました。
今回は、Cabinを除外、Embarkedの欠損値がある行を除外、Ageは平均値で補完することにしました。

Cabinの除外

df_train = df_train.drop('Cabin',axis=1)
df_test = df_test.drop('Cabin', axis=1)

Embarkedの欠損値がある行を除外

df_train = df_train.dropna(subset=['Embarked'])
df_test = df_test.dropna(subset=['Embarked'])

Ageの欠損値を平均値で補完

df_train['Age'].fillna(df_train['Age'].mean(),inplace=True)
df_test['Age'].fillna(df_test['Age'].mean(),inplace=True)

欠損値の確認

df_train.head(3)
PassengerId    0
Survived       0
Pclass         0
Name           0
Sex            0
Age            0
SibSp          0
Parch          0
Ticket         0
Fare           0
Embarked       0
dtype: int64

これで欠損値はなくなりました。

先程のデータを確認すると、Name,Sex,Ticketが文字データなので
これらも処理しなければいけません。
まず、male=0,female=1と置き換えます。

df_train= df_train.replace("male",0).replace("female",1).replace("S",0).replace("C",1).replace("Q",2)
df_test= df_test.replace("male",0).replace("female",1).replace("S",0).replace("C",1).replace("Q",2)

NameとTicketについては、今回は除外することにしました。
NameとTicketの列を除外

df_train = df_train.drop('Name',axis=1)
df_test = df_test.drop('Name', axis=1)
df_train = df_train.drop('Ticket',axis=1)
df_test = df_test.drop('Ticket', axis=1)

以上で、trainデータは以下のようになりました。
f:id:tkm-kyudo:20171203162231p:plain
trainデータは大丈夫そうです。

念のためtestデータを確認しておきましょう。

df_test.isnull().sum()
PassengerId    0
Pclass         0
Sex            0
Age            0
SibSp          0
Parch          0
Fare           1
Embarked       0
dtype: int64

testデータではFareが1つ欠けていたので、これも補完します。

df_test["Fare"].fillna(df_test["Fare"].mean(),inplace=True)
<||

*データの読み込み
前処理が完了したので、データを読み込ませます。
>||
x_train = df_train.values[:, 2:]#Pclass以降の変数
y_train  = df_train.values[:, 1]#正解データ
x_test = df_test.values[:, 1:]

データ解析・モデリング

データの処理、読み込みが終わったので、モデリングして、データの解析をします。
今回は線形SVMをしようしました。
ランダムフォレストやK近傍法なども試しましたが、線形SVMが一番精度が高く出ました。
線形SVMでは入力データを標準化(平均0,標準偏差1)します。

from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(x_train)
x_train_std = sc.transform(x_train)
x_test_std = sc.transform(x_test)

標準化したデータを線形SVMに適用し、生存を予測する。

svm = SVC(kernel='linear', random_state=0, gamma=0.05, C=1.0)
svm.fit(x_train_std, y_train)
svm_accuracy = svm.predict(x_test_std)

予測したものをCSVファイルに書き出す

import csv
with open("svm_predict_result_data.csv", "w") as f:
    writer = csv.writer(f, lineterminator='\n')
    writer.writerow(["PassengerId", "Survived"])
    for pid, survived in zip(df_test.values[:,0].astype(int), svm_accuracy.astype(int)):
        writer.writerow([pid, survived])

予測結果

先程のCSVデータをKaggleに提出すると、
f:id:tkm-kyudo:20171203163751p:plain
正答率0.79904,順位1766(9525人中)と上位18.5%に入ることができました。(2017/12/03時点)

やってみた感想

今回は、初めてということで、拙くてもいいのでデータ分析した結果を提出するということを目標にやってみた。
これまでの過程を見て分かる通りそれほど難しいことはしておらず、データもかなり除外している。
しかし、それでも上位18.5%と悪くない結果を得ることができた。

今後の挑戦について

今回は自力でやることを重視していたので、Kernelには目を通していない。
Kernelとは、Kaglleの強い人達が、どう分析したらスコアが上がったなどの情報を共有してくれているものである。
今後は、コンペなどに参加しつつ、Kernelを見ながら、上位者たちの考え方、解法を学んでいく。
一先ずの目標として、コンペでメダルを1つ取るのを目標に頑張りたい。