KaggleチュートリアルTitanicで上位3%以内に入るには。(0.82297)

まだ機械学習の勉強を初めて4ヶ月ですが、色々やってみた結果、約7000人のうち200位ぐらいの0.82297という記録を出せたので、色々振り返りながら書いていきます。

目次

1.Kaggleとは

2.Titanicチュートリアル

3.生存予測

4.データ分析

5.まとめ

6.感想

7.用いたコード

参考文献

1. Kaggleとは

 初心者にとってはデータ分析の練習をするサイトです。実際は様々な問題を解くのを競い合って自分の腕を試すサイトです。データセットがもらえ、さらに他の人の解説(カーネル)を見ることができるので非常に学べるサイトだと思います。 https://www.kaggle.com

2. Titanicチュートリアル

 Kaggleのコンペティションは普通は開催期間が決まっていますが、チュートリアルは常時開催されています。その中でももっとも初心者向けじゃないかと思われるものがこのタイタニック問題です。ここでは891人分のデータを用いて他の418人の生存予測を行います。

3.生存予測

 ここからは実際にコードを交えて生存予測をして行いたいと思います。おそらく無駄に助長なコードがあるとは思いますが、ご了承ください。 はじめに必要なライブラリをimportします。

import pandas as pd 
import numpy as np
from sklearn.ensemble import RandomForestClassifier
.py

とりあえずはじめにtrainデータを見てみます。私は、jupyterをエディターとして使っています。初めてKaggleをやったときはまずこのデータを見ることすらできませんでした。ですがやり方は簡単でした。Kaggleからtrain.csvとtest.csvをダウンロードしてきて、それをjupyterのフォルダ?がいっぱい並んでいる所にドロップして、次のコードを打つだけでした。この方法以外だとtrain.csvにアクセスするのがとても面倒ではじめはできませんでした。

train= pd.read_csv("train.csv")
test= pd.read_csv("test.csv")
train.head(3)
.py

今回はデータの上から3つ目までを見てみます。さてデータを見てみると明らかにNameとTicketがめんどくさくてこのままでは学習させるのが難しそうだなと思います。 次に、trainの情報を見てみます。

train.info()
.py

<class ‘pandas.core.frame.DataFrame’>

RangeIndex: 891 entries, 0 to 890

Data columns (total 12 columns):

PassengerId 891 non-null int64

Survived 891 non-null int64

Pclass 891 non-null int64

Name 891 non-null object

Sex 891 non-null object

Age 714 non-null float64

SibSp 891 non-null int64

Parch 891 non-null int64

Ticket 891 non-null object

Fare 891 non-null float64

Cabin 204 non-null object

Embarked 889 non-null object

dtypes: float64(2), int64(5), object(5)

memory usage: 83.6+ KB

これから何がわかるでしょうか? わかることは「891のデータがあること。Age、CabinとEmbarkedにnullがあること。データの型が色々あること。」などでしょうか。 次にやることは、sexのmaleを0に、femaleを1に置き換える。また、EmbarkedのSを0、Cを1、Qを2に置き換えます。これはobjectだと今後学習させるときに問題があるからやります。 Embarkedは搭乗した場所で、SはSouthampton、CはCherbourg、QはQueenstownです。wikipediaに地図があるので見てみると面白いかもしれません。

train= pd.read_csv("train.csv").replace("male",0).replace("female",1).replace("S",0).replace("C",1).replace("Q",2)
test= pd.read_csv("test.csv").replace("male",0).replace("female",1).replace("S",0).replace("C",1).replace("Q",2)
.py

次にやりたいことは欠損値を埋めることです。Cabinは無視して、AgeとEmbarkedの欠損値を埋めます。そのコードは下のようになります。今回はそれぞれの平均値meanで埋めました。他にも中央値で埋める方法などもありましたが何度か試した所、結局平均値がいいという結果に私は至りました。

train["Age"].fillna(train.Age.mean(), inplace=True) 
train["Embarked"].fillna(train.Embarked.mean(), inplace=True)
.py

さてここからが問題です。 ここまでは比較的に簡単な処理を行ってきました。今処理できていないのはName、TicketとCabinでしょう。それぞれNameは全くみんなバラバラでどう処理の仕方がわからない。Ticketも同様。Cabinは欠損値が多すぎる。これらの骨が折れる奴らを処理しなければなりません。私には全く思いつきません。では、どうするのか?Kaggleにはカーネルがありますので参考にしながら進めて行きましょう。ここまでも参考にしてきましたが… はじめにNameを処理して行きます。Nameを眺めてなんとなく共通しているものに気がつくでしょうか?Mr、Mrs、Missなどの敬称があると思います。これで分類してみましょう。Salutationは挨拶という意味らしいです。そして今は女性に対して使うMissとMrsがMsに統合されているそうです。

combine1 = [train]

for train in combine1: 
        train['Salutation'] = train.Name.str.extract(' ([A-Za-z]+).', expand=False) 
for train in combine1: 
        train['Salutation'] = train['Salutation'].replace(['Lady', 'Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
        train['Salutation'] = train['Salutation'].replace('Mlle', 'Miss')
        train['Salutation'] = train['Salutation'].replace('Ms', 'Miss')
        train['Salutation'] = train['Salutation'].replace('Mme', 'Mrs')
        del train['Name']
Salutation_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5} 
for train in combine1: 
        train['Salutation'] = train['Salutation'].map(Salutation_mapping) 
        train['Salutation'] = train['Salutation'].fillna(0)
.py

次に、Ticketの処理です。今度はTicketの先頭の文字で分けていきます。また、文字列の長さでも分けていきます。そして、その後にそれらの文字を数字に直します。

for train in combine1: 
        train['Ticket_Lett'] = train['Ticket'].apply(lambda x: str(x)[0])
        train['Ticket_Lett'] = train['Ticket_Lett'].apply(lambda x: str(x)) 
        train['Ticket_Lett'] = np.where((train['Ticket_Lett']).isin(['1', '2', '3', 'S', 'P', 'C', 'A']), train['Ticket_Lett'], np.where((train['Ticket_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']), '0','0')) 
        train['Ticket_Len'] = train['Ticket'].apply(lambda x: len(x)) 
        del train['Ticket'] 
train['Ticket_Lett']=train['Ticket_Lett'].replace("1",1).replace("2",2).replace("3",3).replace("0",0).replace("S",3).replace("P",0).replace("C",3).replace("A",3)
.py

同様にCabinも先頭の文字で分けていきます。

for train in combine1: 
    train['Cabin_Lett'] = train['Cabin'].apply(lambda x: str(x)[0]) 
    train['Cabin_Lett'] = train['Cabin_Lett'].apply(lambda x: str(x)) 
    train['Cabin_Lett'] = np.where((train['Cabin_Lett']).isin([ 'F', 'E', 'D', 'C', 'B', 'A']),train['Cabin_Lett'], np.where((train['Cabin_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']), '0','0'))
del train['Cabin'] 
train['Cabin_Lett']=train['Cabin_Lett'].replace("A",1).replace("B",2).replace("C",1).replace("0",0).replace("D",2).replace("E",2).replace("F",1)
.py

ここで一度trainを見てみましょう。 一応全て数字になりました。ここからは、さらに生存予測の精度を高めるために新たな変数を追加していきます。 FamilySizeとIsAloneです。なぜなら一緒に乗船している人数によって生存に大きく差が出るからです。ここまででまだ使われていないものはPclass、SibspとParchです。Pclassは何等級のところに乗っていたかを表すものなのでこのままでいいです。Sibspは乗っていた夫婦と兄弟の人数を表したものです。Parchは乗っていた親と子供の人数を表したものです。よってSibsp+Parch+1がFamilySizeとなります。また、FamilySizeが1だとIsAlone一人で乗っているかどうかが1となります。

train.head(10)
.py

train["FamilySize"] = train["SibSp"] + train["Parch"] + 1
for train in combine1:
    train['IsAlone'] = 0
    train.loc[train['FamilySize'] == 1, 'IsAlone'] = 1
.py

ここまででtrainの処理は終わりました。次に、trainのデータを機械学習にかけるために加工します。はじめにtrainの値だけを取り出し、次にそれを正解データと学習用のデータに分けます。

train_data = train.values
xs = train_data[:, 2:] # Pclass以降の変数
y  = train_data[:, 1]  # 正解データ
py

次に、testの処理をしていきたいと思います。ほぼtrainと一緒のことをします。ですが気をつけなければいけないことがあります。testのデータをみてみましょう。

test.info()
.py

<class ‘pandas.core.frame.DataFrame’>

RangeIndex: 418 entries, 0 to 417

Data columns (total 11 columns):

PassengerId 418 non-null int64

Pclass 418 non-null int64

Name 418 non-null object

Sex 418 non-null int64

Age 332 non-null float64

SibSp 418 non-null int64

Parch 418 non-null int64

Ticket 418 non-null object

Fare 417 non-null float64

Cabin 91 non-null object

Embarked 418 non-null int64

dtypes: float64(2), int64(6), object(3)

memory usage: 36.0+ KB

わかりますでしょうか? 姑息なことにFareが一つ欠損しております。これを埋めなかったが為に何度エラーが起きたことでしょう。気をつけてください。こういうところでもチュートリアルなのかもしれません。

test["Age"].fillna(train.Age.mean(), inplace=True)
test["Fare"].fillna(train.Fare.mean(), inplace=True)

combine = [test]
for test in combine:
    test['Salutation'] = test.Name.str.extract(' ([A-Za-z]+)\.', expand=False)
for test in combine:
    test['Salutation'] = test['Salutation'].replace(['Lady', 'Countess','Capt', 'Col',\
         'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')

    test['Salutation'] = test['Salutation'].replace('Mlle', 'Miss')
    test['Salutation'] = test['Salutation'].replace('Ms', 'Miss')
    test['Salutation'] = test['Salutation'].replace('Mme', 'Mrs')
    del test['Name']
Salutation_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}

for test in combine:
    test['Salutation'] = test['Salutation'].map(Salutation_mapping)
    test['Salutation'] = test['Salutation'].fillna(0)

for test in combine:
        test['Ticket_Lett'] = test['Ticket'].apply(lambda x: str(x)[0])
        test['Ticket_Lett'] = test['Ticket_Lett'].apply(lambda x: str(x))
        test['Ticket_Lett'] = np.where((test['Ticket_Lett']).isin(['1', '2', '3', 'S', 'P', 'C', 'A']), test['Ticket_Lett'],
                                   np.where((test['Ticket_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']),
                                            '0', '0'))
        test['Ticket_Len'] = test['Ticket'].apply(lambda x: len(x))
        del test['Ticket']
test['Ticket_Lett']=test['Ticket_Lett'].replace("1",1).replace("2",2).replace("3",3).replace("0",0).replace("S",3).replace("P",0).replace("C",3).replace("A",3) 

for test in combine:
        test['Cabin_Lett'] = test['Cabin'].apply(lambda x: str(x)[0])
        test['Cabin_Lett'] = test['Cabin_Lett'].apply(lambda x: str(x))
        test['Cabin_Lett'] = np.where((test['Cabin_Lett']).isin(['T', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']),test['Cabin_Lett'],
                                   np.where((test['Cabin_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']),
                                            '0','0'))        
        del test['Cabin']
test['Cabin_Lett']=test['Cabin_Lett'].replace("A",1).replace("B",2).replace("C",1).replace("0",0).replace("D",2).replace("E",2).replace("F",1).replace("G",1) 

test["FamilySize"] = train["SibSp"] + train["Parch"] + 1

for test in combine:
    test['IsAlone'] = 0
    test.loc[test['FamilySize'] == 1, 'IsAlone'] = 1
    
test_data = test.values
xs_test = test_data[:, 1:]
.py

さて、ここまでで面倒だった前処理が終わりました。もちろんもっといい処理の方法があったと思いますが、初心者ではこんなもんです。ここからがメインの学習タイムです。様々な学習方法を試した結果RandomForestClassifierを使うのが一番結果が私的には良かったです。ではやってみましょう。

from sklearn.ensemble import RandomForestClassifier

random_forest=RandomForestClassifier()
random_forest.fit(xs, y)
Y_pred = random_forest.predict(xs_test)

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

from sklearn.ensemble import RandomForestClassifier

random_forest=RandomForestClassifier() random_forest.fit(xs, y) Y_pred = random_forest.predict(xs_test)

import csv with open("predict_result_data.csv", "w") as f: writer = csv.writer(f, lineterminator=’\n’) writer.writerow(["PassengerId", "Survived"]) for pid, survived in zip(test_data[:,0].astype(int), Y_pred.astype(int)): writer.writerow([pid, survived])

提出してみたでしょうか?どういう結果になったでしょうか?0.8を超えられたでしょうか?きっと超えていないと思います。0.82297なんてなっていないと思います。 タイトル詐欺?いえ、違います。色々な学習方法を試しているうちに気がつきました。「あれ?毎回結果変わってないか?」そうです。RandomForestClassifierには自由に変えられるパラメータがたくさんあります。これをいじっていくことでどんどん結果が変わります。最初の壁は0.8を超えられるかです。 その後は1つ結果を更新するのもしんどくなっていきます。私は、0.82297で止まりました。これ以上はもっとデータ処理を変えるか、もっといいパラメータを見つけるかしかないと思います。パラメータの探索方法をお教えしましょう。

from sklearn.ensemble import RandomForestClassifier
from sklearn import grid_search
from sklearn.grid_search import GridSearchCV

"""
parameters = {
        'n_estimators'      : [10,25,50,75,100],
        'random_state'      : [0],
        'n_jobs'            : [4],
        'min_samples_split' : [5,10, 15, 20,25, 30],
        'max_depth'         : [5, 10, 15,20,25,30]
}

clf = grid_search.GridSearchCV(RandomForestClassifier(), parameters)
clf.fit(xs, y)
 
print(clf.best_estimator_)
"""
.py

今回いじるのはn_estimators、min_samples_splitとmax_depthです。ちなみに上のコードを走らせると時間がかなりかかります。random_stateは初期状態を固定するためのものなのでとりあえず0にしました。n_jobsは計算に使うCPUの数なので適切のものにしてください。 パラメータをいじりながら最適なものを探し、それを提出し、結果を確認する。これを何度も繰り返していいものを見つけてください。今現在私の最高を出したパラメータを下に示します。ただ、これが再現性があるのかどうかは知りません。

random_forest=RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=25, max_features='auto', max_leaf_nodes=None,
            min_samples_leaf=1, min_samples_split=15,
            min_weight_fraction_leaf=0.0, n_estimators=51, n_jobs=4,
            oob_score=False, random_state=0, verbose=0, warm_start=False)
.py

4.データ分析

 ここからはデータの分析をして行きたいと思います。タイタニックでは、約1500人が犠牲となり、生存者は約700人であるそうです。なぜこれほどまで死者が出たのか?その原因の一つには救命ボートが船に乗っていた人の半分を載せられるぐらいしかなかったことでしょう。
それでは実際にデータをみていきましょう。はじめに、性別によってどれほど生存に違いが出たかをみてみましょう。下の図をみてください。0が男性、1が女性です。明らかに女性の生存率が高いですね。そして男性の人数がかなり多いですね。これは推測ですが、乗組員に男性が多かったからではないでしょうか。

%matplotlib inline 
import matplotlib.pyplot as plt
import seaborn as sns
g = sns.factorplot(x="Sex", y="Survived",  data=train,
                   size=6, kind="bar", palette="muted")
g.despine(left=True)
g = g.set_ylabels("survival probability")
.py

sns.countplot(x='Sex', data = train)
.py

次に乗っていた等級による生存率をみてみましょう。明らかに等級がいい順に生存率が高いです。ただ、ここで気がついたことがあります。今回のデータは全てこのPclassの分類があるため乗組員はデータに含まれていないのではないでしょうか。先ほどの推測は間違いでした。

g = sns.factorplot(x="Pclass",y="Survived",data=train,kind="bar", size = 6 , 
palette = "muted")
g.despine(left=True)
g = g.set_ylabels("survival probability")
.py

次は等級と性別を複合した時の生存率をみてみましょう。1等と2等の女性の生存率が高く、2等と3等の男性の生存率が低いです。

g = sns.factorplot(x="Pclass", y="Survived", hue="Sex", data=train,
                   size=6, kind="bar", palette="muted")
g.despine(left=True)
g = g.set_ylabels("survival probability")
.py

次に敬称による生存率をみてみましょう。ここで0と5は珍しいもので数が少ないので無視します。注目するべきは他のものです。1のMrは大人の男性に使われるものです。だから生存率が少ないのですね。次に、2と3はMissとMrsなので女性に使われるものなので生存率が高いです。4はMasterです。誰に使われるものかと言いますと、青年や若い男性です。 以上からこの敬称は結局性別の言い換えに近いものなのではないでしょうか?一つ違うのは男性を年齢で分けているMasterがあるところではないでしょうか。

g = sns.factorplot(x="Salutation", y="Survived",  data=train,
                   size=6, kind="bar", palette="muted")
g.despine(left=True)
g = g.set_ylabels("survival probability")
.py

ここでデータの生存率に対する相関をみます。先ほどみてきた通り性別(Sex,Salutation)による相関、属している社会階級つまりお金をどれだけ持っているか(Pclass,Fare)に対する相関が高いです。 Cabin_LettとTicket_Lettの相関も高いです、これも社会的地位ではないでしょうか?高いFareであればいいTicketを取れ、乗るCabinの生存率も上がるはずです。他にはIsAloneも相関が高いです。次からは一緒に乗船した人数による生存率をみてみましょう。

colormap = plt.cm.viridis
plt.figure(figsize=(12,12))
plt.title('Pearson Correlation of Features', y=1.05, size=15)
del train['PassengerId']
sns.heatmap(train.astype(float).corr(),linewidths=0.1,vmax=1.0, square=True, cmap=colormap, linecolor='white', annot=True)
.py

はじめに、何人ぐらいで乗っていたのか、また、どのくらい生存したのかをみていきましょう。圧倒的に一人で乗っていた人が多かったです。そして、1人か5人以上で乗っていると生存率が悪かったこともわかります。

sns.countplot(x='FamilySize', data = train, hue = 'Survived')
.py

ではなぜ大家族か一人で乗ると死亡率が高かったのか?大家族であると当然お金もたくさんかかるので3等に乗った人が多かったようです。一人の方々も3等が多かった。家族が多いとそもそも非難するのも難しいし、3等なので救出の優先度も低かったのでしょう。

sns.countplot(x='FamilySize', data = train,hue = 'Pclass')
py

次に、乗船場所による生存率の違いを見てみます。タイタニックの航路はイギリスのサウサンプトン→フランスのシェルブール→アイルランドのクイーンズタウンの順番でした。 下の図を見るとシェルブールから乗った人の生存率が高かったことがわかります。その理由は一つ下の図を見るとわかります。1等に乗った人の割合が高かったからでしょう。しかし、そのように考えるとクイーンズタウンから乗った人は3等ばかりなのに生存率が少し高いです。その理由のうち少しはさらに下の図の男女比だと思いますが、正確な理由はわかりません。

t=pd.read_csv("train.csv").replace("S",0).replace("C",1).replace("Q",2)
train['Embarked']= t['Embarked']
g = sns.factorplot(x="Embarked", y="Survived",  data=train,
                   size=6, kind="bar", palette="muted")
g.despine(left=True)
g = g.set_ylabels("survival probability")
.py

sns.countplot(x='Embarked', data = train,hue = 'Pclass')
.py

sns.countplot(x='Embarked', data = train,hue = 'Sex')
py

最後は年齢による違いをみて行きたいと思います。下の図をみてみると10代後半から30代ほどまでは死亡率が高く、子供の死亡率は低いです。どうやらこのころは15歳より上だとほとんど成人とみなされていたようです。また、老人の死亡率も高いです。

plt.figure()
sns.FacetGrid(data=t, hue="Survived", aspect=4).map(sns.kdeplot, "Age", shade=True)
plt.ylabel('Passenger Density')
plt.title('KDE of Age against Survival')
plt.legend()
.py

for t in combine1: 
    t.loc[ t['Age'] <= 15, 'Age']                                                = 0
    t.loc[(t['Age'] > 15) & (t['Age'] <= 25), 'Age'] = 1
    t.loc[(t['Age'] > 25) & (t['Age'] <= 48), 'Age'] = 2
    t.loc[(t['Age'] > 48) & (t['Age'] <= 64), 'Age'] = 3
    t.loc[ t['Age'] > 64, 'Age'] =4
g = sns.factorplot(x="Age", y="Survived",  data=t,
                   size=6, kind="bar", palette="muted")
g.despine(left=True)
g = g.set_ylabels("survival probability")
.py

そして面白いのは、男女比と生存の数がほぼ一緒であることです。下の2つの図はほとんど一緒に見えます。

sns.countplot(x='Age', data = t,hue = 'Sex')
.py

sns.countplot(x='Age', data = t,hue = 'Survived')
.py

5.まとめ

以上からどのような人が生き残りやすいのかというと15歳以下の子供あるいは女性であればかなり助かります。また、それで1等に乗っていて3人か4人家族だとほぼ生き残れるでしょう。逆に、私のような男でお金のない学生で一人旅が好きな奴は死にます。私は乗らなくてよかったです。タイタニックのおかげで救命ボートがたくさん積まれるようになり、無線も常備されたりなどして今の航海の安全に繋がっているそうです。

6.感想

とりあえずKaggleをやってみて実際にどのように機械学習をやって行けば良いのかわかった。そのためにカーネルが非常に役に立つこともわかった。今後他のKaggleの問題にも挑戦していく。この記事を書いたことによって今まではただいい結果を出すことに集中しているだけでデータの意味とかを考えなかったが今後はそれらを考慮に入れつつデータ分析を行って行きたい。また、実際はそもそもデータの加工を自分でしなければならずこのように綺麗なデータが与えられることは少ないのでSQLを勉強したい。そして、今度はHousePrices問題をやりたい。

7.用いたコード

import pandas as pd 
import numpy as np
from sklearn.ensemble import RandomForestClassifier 
train= pd.read_csv("train.csv").replace("male",0).replace("female",1).replace("S",0).replace("C",1).replace("Q",2)
test= pd.read_csv("test.csv").replace("male",0).replace("female",1).replace("S",0).replace("C",1).replace("Q",2) 
train["Age"].fillna(train.Age.mean(), inplace=True) 
train["Embarked"].fillna(train.Embarked.mean(), inplace=True) 
combine1 = [train]

for train in combine1: 
        train['Salutation'] = train.Name.str.extract(' ([A-Za-z]+).', expand=False) 
for train in combine1: 
        train['Salutation'] = train['Salutation'].replace(['Lady', 'Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
        train['Salutation'] = train['Salutation'].replace('Mlle', 'Miss')
        train['Salutation'] = train['Salutation'].replace('Ms', 'Miss')
        train['Salutation'] = train['Salutation'].replace('Mme', 'Mrs')
        del train['Name']
Salutation_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5} 

for train in combine1: 
        train['Salutation'] = train['Salutation'].map(Salutation_mapping) 
        train['Salutation'] = train['Salutation'].fillna(0) 
    
for train in combine1: 
        train['Ticket_Lett'] = train['Ticket'].apply(lambda x: str(x)[0])
        train['Ticket_Lett'] = train['Ticket_Lett'].apply(lambda x: str(x)) 
        train['Ticket_Lett'] = np.where((train['Ticket_Lett']).isin(['1', '2', '3', 'S', 'P', 'C', 'A']), train['Ticket_Lett'], np.where((train['Ticket_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']), '0','0')) 
        train['Ticket_Len'] = train['Ticket'].apply(lambda x: len(x)) 
        del train['Ticket'] 
train['Ticket_Lett']=train['Ticket_Lett'].replace("1",1).replace("2",2).replace("3",3).replace("0",0).replace("S",3).replace("P",0).replace("C",3).replace("A",3) 

    
for train in combine1: 
    train['Cabin_Lett'] = train['Cabin'].apply(lambda x: str(x)[0]) 
    train['Cabin_Lett'] = train['Cabin_Lett'].apply(lambda x: str(x)) 
    train['Cabin_Lett'] = np.where((train['Cabin_Lett']).isin([ 'F', 'E', 'D', 'C', 'B', 'A']),train['Cabin_Lett'], np.where((train['Cabin_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']), '0','0'))
del train['Cabin'] 
train['Cabin_Lett']=train['Cabin_Lett'].replace("A",1).replace("B",2).replace("C",1).replace("0",0).replace("D",2).replace("E",2).replace("F",1) 
train["FamilySize"] = train["SibSp"] + train["Parch"] + 1
for train in combine1:
    train['IsAlone'] = 0
    train.loc[train['FamilySize'] == 1, 'IsAlone'] = 1
train_data = train.values
xs = train_data[:, 2:] # Pclass以降の変数
y  = train_data[:, 1]  # 正解データ
test["Age"].fillna(train.Age.mean(), inplace=True)
test["Fare"].fillna(train.Fare.mean(), inplace=True)

combine = [test]
for test in combine:
    test['Salutation'] = test.Name.str.extract(' ([A-Za-z]+)\.', expand=False)
for test in combine:
    test['Salutation'] = test['Salutation'].replace(['Lady', 'Countess','Capt', 'Col',\
         'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')

    test['Salutation'] = test['Salutation'].replace('Mlle', 'Miss')
    test['Salutation'] = test['Salutation'].replace('Ms', 'Miss')
    test['Salutation'] = test['Salutation'].replace('Mme', 'Mrs')
    del test['Name']
Salutation_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}

for test in combine:
    test['Salutation'] = test['Salutation'].map(Salutation_mapping)
    test['Salutation'] = test['Salutation'].fillna(0)

for test in combine:
        test['Ticket_Lett'] = test['Ticket'].apply(lambda x: str(x)[0])
        test['Ticket_Lett'] = test['Ticket_Lett'].apply(lambda x: str(x))
        test['Ticket_Lett'] = np.where((test['Ticket_Lett']).isin(['1', '2', '3', 'S', 'P', 'C', 'A']), test['Ticket_Lett'],
                                   np.where((test['Ticket_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']),
                                            '0', '0'))
        test['Ticket_Len'] = test['Ticket'].apply(lambda x: len(x))
        del test['Ticket']
test['Ticket_Lett']=test['Ticket_Lett'].replace("1",1).replace("2",2).replace("3",3).replace("0",0).replace("S",3).replace("P",0).replace("C",3).replace("A",3) 

for test in combine:
        test['Cabin_Lett'] = test['Cabin'].apply(lambda x: str(x)[0])
        test['Cabin_Lett'] = test['Cabin_Lett'].apply(lambda x: str(x))
        test['Cabin_Lett'] = np.where((test['Cabin_Lett']).isin(['T', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']),test['Cabin_Lett'],
                                   np.where((test['Cabin_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']),
                                            '0','0'))        
        del test['Cabin']
test['Cabin_Lett']=test['Cabin_Lett'].replace("A",1).replace("B",2).replace("C",1).replace("0",0).replace("D",2).replace("E",2).replace("F",1).replace("G",1) 
test["FamilySize"] = train["SibSp"] + train["Parch"] + 1

for test in combine:
    test['IsAlone'] = 0
    test.loc[test['FamilySize'] == 1, 'IsAlone'] = 1
    
test_data = test.values
xs_test = test_data[:, 1:]
from sklearn.ensemble import RandomForestClassifier

random_forest=RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=25, max_features='auto', max_leaf_nodes=None,
            min_samples_leaf=1, min_samples_split=15,
            min_weight_fraction_leaf=0.0, n_estimators=51, n_jobs=4,
            oob_score=False, random_state=0, verbose=0, warm_start=False)

random_forest.fit(xs, y)
Y_pred = random_forest.predict(xs_test)
"""random_forest.score(xs,y)
acc_random_forest = round(random_forest.score(xs,y) * 100, 2)
acc_random_forest
"""

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

参考文献

https://ja.wikipedia.org/wiki/%E3%82%BF%E3%82%A4%E3%82%BF%E3%83%8B%E3%83%83%E3%82%AF%E5%8F%B7%E6%B2%88%E6%B2%A1%E4%BA%8B%E6%95%85

https://www.kaggle.com/yassineghouzam/titanic-top-4-with-ensemble-modeling

https://www.kaggle.com/jamsterjai/pythanic-please-critique-0-79904

https://www.kaggle.com/arthurtok/introduction-to-ensembling-stacking-in-python

https://www.kaggle.com/headsortails/pytanic

http://www.statisticalconsultants.co.nz/blog/titanic-survival-data.html

http://www.mirandora.com/?p=1804

http://blog.tatsushim.com/?p=63