LoginSignup
4
3

More than 5 years have passed since last update.

[kaggle翻訳]Titanic Data Science Solutions(Manav Sehgal) (3)

Last updated at Posted at 2018-07-15

Kaggleのチュートリアルとして公開されているTitanic問題に対する素敵な解答を提出されている方がいたので、(データ分析と英語の)勉強を兼ねて翻訳してみます。

私はデータ分析も英語も特に出来るわけではないので、いろいろ誤りがあるかと思います。
もしお気づきの点があればお知らせくだされば幸いです。

なお、訳出は適宜抜粋しつつ行うものとします。全文訳ではないことをご承知おきください。

本記事は3記事目となります。前回記事などをお読みでなければ先にそちらをご覧ください。

前回のまとめ(翻訳者による)

特徴名 意味 判明した主な事実 今後の方針
Pclass 乗船クラス 1の乗客は最も生存率が高かった。3の乗客は最も多いが、最も生存率が低かった
Sex 性別 女性の生存率が高かった
Age 年齢 4歳以下の幼児は生存率が高かった 年齢帯による区別を設ける
Fare 料金 高額な料金を払った乗客は生存率が高い 料金帯による区別を設ける
Embarked 乗船地 Pclassが3である人々および男性乗客者に対して生存率を変化させる要因である。

データのまとめ

私たちはここまでデータセットと答えが要求することを観察し、いくつもの仮定と決定を手に入れてきた。ここまでは一つの特徴もしくはその値を変化させるということをしてこなかった。ここからは、データの修正、特徴の作成及び補完などを行い、私たちの仮定と決定を実行していこうと思う。

特徴削除による修正

これを実行することは、目標に近づくためのよいスタートだ。特徴を削除することにより、私たちはより少ないデータによって分析処理を行うことができる。これは処理の早くすると同時に、分析を楽にする。

私たちの仮定と決定に基づけば、Cabin特徴とTicket特徴は削除することができる。

ここで注意するのは、データの一貫性を保つためにも、行う削除処理は訓練用データと本番用データの両方に対して行わなければいけないということだ。

15.客室特徴とチケット特徴の削除
print("Before", train_df.shape, test_df.shape, combime[0].shape, combine[1].shape)

train_df = train_df.frop(['Ticket', 'Cabin'], axis=1)
test_df =  test_df.frop(['Ticket', 'Cabin'], axis=1)
combine = [train_df, test_df]

print("After", train_df.shape, test_df.shape, combime[0].shape, combine[1].shape)


>>>
Before (891, 12) (418, 11) (891, 12) (418, 11)
After  (891, 10) (418, 9)  (891, 10) (418, 9)

既存の特徴から新たな特徴を作る

私たちは名前特徴から敬称を抜き出して再設計することができたならばそれを分析したいし、そしてその敬称と生存率との間の相関についてテストしたい。これは名前特徴と乗客IDを削除を行う前に実行する。

正規表現を用いることによって、敬称特徴を抽出していく。正規表現のパターンで「¥w+¥.」は名前特徴の中でドット文字で終了している最初の単語にマッチする。expand=False というフラグにより、データはDataFrame型として返却される。

観察結果

敬称、年齢、そして生存率についてプロットしてみると、次の観察結果が得られる。

  • ほとんどの敬称は年齢を明確に区別する。例えば、Masterという敬称は平均年齢が5歳である。
  • 敬称と年齢間の生存率の違いは軽微なものである。
  • 特定の敬称を持つ人々は、より生存率が高い(Mme,Lady,Sir)傾向があるか、またはより生存率が低い(Don,Rev,Jonkheer)傾向を示している。

決定

  • 敬称という新たな特徴をモデルの訓練用に残すこととする。
16.敬称と性別の可視化
for dataset in combine:
    dataset['Title'] = dataset.Name.str.extract(([A-Za-z+]¥.', 
    expand=False)

pd.crosstab(train_df['Title'], train_df['Sex'])


>>>

        Sex female  male
Title       
Capt        0       1
Col         0       2
Countess    1       0
Don         0       1
Dr          1       6
Jonkheer    0       1
Lady        1       0
Major       0       2
Master      0       40
Miss        182     0
Mlle        2       0
Mme         1       0
Mr          0       517
Mrs         125     0
Ms          1       0
Rev         0       6
Sir         0       1

もっと一般的な名前もしくはそれらに分類されるようなものについては、'Rare'という名前に置き換えることができる。

17.敬称と生存率の相関の可視化
for dataset in combine:
    dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess', 
            'Capt', 'Col', 'Don', 'Dr', 'Major', 'Rec', 'Sir', 
            'Jonkheer', 'Dona'],'Rare')
    dataset['Title'] = dataset['Title'].replace('Mile', 'Miss')
    dataset['Title'] = dataset['Title'].replace('Ms', 'Miss')
    dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')

train_df[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()


>>>
    Title   Survived
0   Master  0.575000
1   Miss    0.702703
2   Mr      0.156673
3   Mrs     0.793651
4   Rare    0.347826    

このカテゴリ特徴である敬称項目は、順序特徴へと変換できる。

18.敬称特徴の変換(カテゴリ→順序数値)
title_mapping = {"Mr":1, "Miss":2, "Mrs":3, "Master":4, "Rare":5}

for dataset in combine:
    dataset['Title'] = dataset['Title'].map(title_mapping)
    dataset['Title'] = dataset['Title'].fillna(0)



>>>
    PassengerId Survived    Pclass  Name    Sex Age SibSp   Parch   Fare    Embarked    Title
0   1   0   3   Braund, Mr. Owen Harris male    22.0    1   0   7.2500  S   1
1   2   1   1   Cumings, Mrs. John Bradley (Florence Briggs Th...   female  38.0    1   0   71.2833 C   3
2   3   1   3   Heikkinen, Miss. Laina  female  26.0    0   0   7.9250  S   2
3   4   1   1   Futrelle, Mrs. Jacques Heath (Lily May Peel)    female  35.0    1   0   53.1000 S   3
4   5   0   3   Allen, Mr. William Henry    male    35.0    0   0   8.0500  S   1

いま、私たちは訓練用データと本番用データから憂いなく名前特徴を削除することができる。また、訓練用データの中の乗客ID特徴も不要である。

19.名前と乗客ID特徴の削除
train_df = train_df.drop(['Name', 'PassengerId'], axis=1)
test_df  = test_df.drop(['Name'], axis=1)
combine = [train_df, test_df]
train_df.shape, test_df.shape


>>>
((891, 9), (418, 9))

カテゴリ特徴の変換

文字列を含む特徴を数的値に変換することができる。これは、最も優れたアルゴリズムを選定するうえで必要なことである。そのようにすることはまた、特徴を補完する上でも役立つ。

ではSex特徴を、男性ならば0、女性ならば1の値を持つGenderという新しい特徴に変換することから始めよう。

20.性別特徴の変換
for dataset in combine:
    dataset['Sex'] = dataset['Sex'].map({'female':1, 'male':0}).astype(int)

train_df.head()


>>>
    Survived    Pclass  Sex Age     SibSp   Parch   Fare    Embarked    Title
0   0           3       0   22.0    1       0       7.2500  S           1
1   1           1       1   38.0    1       0       71.2833 C           3
2   1           3       1   26.0    0       0       7.9250  S           2
3   1           1       1   35.0    1       0       53.1000 S           3
4   0           3       0   35.0    0       0       8.0500  S           1

連続数的特徴の補完

ここでは欠損または空白を持つ特徴について、予測補完を行う。まずは年齢特徴に対してこの作業を行う。

連続的数的な特徴を補完するにあたっては3つの方法を考えることができる。

  1. 平均と標準偏差の間で乱数を生成するという簡単な方法
  2. より正確な欠損値推測を行う方法として、他の特徴のとの相関を用いる方法もある。今回の例において私たちは、年齢と性別、そして乗船クラスの間に相関があることを知っている。そこで、年齢と乗船クラス及び性別をまたいだ中央値を用いることで、年齢を推測することができる。例えば、乗船クラスが1かつ性別が0であるときの年齢の中央値、また乗船クラスが1で性別が1であるときの中央値、などのように。
  3. 3つ目の方法は1と2の方法を合わせたものである。中央値に基づいて年齢値を推測する代わりに、乗船クラスと性別を合わせたものに基づき算出された平均と標準偏差を用いて、その間の乱数を生成させる方法である。

1と3の方法はモデルの中にノイズを招くことにもなる。複合的に実行した結果はおそらく変化してしまうことだろう。ここでは2の方法を用いることとする。

21.年齢、性別、乗船クラスの相関の可視化
grid = sns.FacetGrid(train_df, row='Pclass', col='Sex', size=2.2, aspect=1.6)
grid.map(plt.hist, 'Age', alpha=.5, bins=20)
grid.add_legend()

image.png

乗船クラスと性別を合わせたものに基づいた推測値で年齢を満たすためにも、まずは空白の配列を用意する。

22.空白の配列作成
guess_ages = np.array((2,3))
guess_ages

>>>
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])

性別と乗船クラスを繰り返し演算し、6つの組み合わせの年齢の推測値を計算する。

23.年齢の推測値を算出する
for dataset in combine:
  for i in range(0,2):
    for j in range(0,3):
      guess_df = dataset[(dataset['Sex'] == i) %
                          (dataset['Pclass] == j+1)['Age'].dronpa()

      age_guess = guess_df.median()
      guess_ages[i,j] = int(age_guess/0.5+0.5)*0.5

  for i in range(0,2):
    for j in range(0,3):
      dataset.loc[(dataset.Age.isnull()) & (dataset.Sex == i) &
                  (datset.Pclass == j+1), 'Age'] = guess_ages[i,j]

  dataset['Age'] = datset['Age'].astype(int)


train_df.head()


>>>

Survived Pclass Sex Age SibSp   Parch   Fare    Embarked Title
0        0      3   0   22      1   0   7.2500  S        1
1        1      1   1   38      1   0   71.2833 C        3
2        1      3   1   26      0   0   7.9250  S        2
3        1      1   1   35      1   0   53.1000 S        3
4        0      3   0   35      0   0   8.0500  S        1

次に年齢帯についての特徴を作り出し、生存率との関連性を決定しよう。

24.年齢帯の作成
train_df['AgeBand'] = pd.cut(train_df['Age'], 5)
train_df[['AgeBand', 'Survived']].groupby(['AgeBand'], 
as_index=False).mean().sort_values(by='AgeBand', ascending=True)


>>>

    AgeBand         Survived
0   (-0.08, 16.0]   0.550000
1   (16.0, 32.0]    0.337374
2   (32.0, 48.0]    0.412037
3   (48.0, 64.0]    0.434783
4   (64.0, 80.0]

ここまで来たら、年齢をこれらの値に基づいて順序付けしていく。

25.年齢帯の作成2
for dataset in combine:    
    dataset.loc[ dataset['Age'] <= 16, 'Age'] = 0
    dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <= 32), 'Age'] = 1
    dataset.loc[(dataset['Age'] > 32) & (dataset['Age'] <= 48), 'Age'] = 2
    dataset.loc[(dataset['Age'] > 48) & (dataset['Age'] <= 64), 'Age'] = 3
    dataset.loc[ dataset['Age'] > 64, 'Age']
train_df.head()


>>>
    Survived    Pclass  Sex Age SibSp   Parch   Fare    Embarked    Title   AgeBand
0   0           3       0   1   1       0       7.2500  S           1       (16.0, 32.0]
1   1           1       1   2   1       0       71.2833 C           3       (32.0, 48.0]
2   1           3       1   1   0       0       7.9250  S           2       (16.0, 32.0]
3   1           1       1   2   1       0       53.1000 S           3       (32.0, 48.0]
4   0           3       0   2   0       0       8.0500  S           1       (32.0, 48.0]

年齢帯の特徴は取り除かなければいけない。

26.年齢帯の削除
train_df = train_df.drop(['AgeBand'], axis=1)
combine = [train_df, test_df]
train_df.head()


>>>
    Survived    Pclass  Sex Age SibSp   Parch   Fare    Embarked    Title
0   0           3       0   1   1       0       7.2500  S           1 
1   1           1       1   2   1       0       71.2833 C           3   
2   1           3       1   1   0       0       7.9250  S           2    
3   1           1       1   2   1       0       53.1000 S           3 
4   0           3       0   2   0       0       8.0500  S           1    

既存の特徴を組み合わせて特徴を作り出す

Parch特徴とSibSp特徴を組み合わせて、新たにFamilySizeという特徴を作り出すことができる。これによりデータセットから上記2項目を削除することができるようになる。

27.FamiliSize特徴の作成
for dataset in combine:
    dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1

train_df[['FamilySize', 'Survived']].groupby(['FamilySize'], as_index=False).mean().sort_values(by='Survived', ascending=False)


>>>
    FamilySize  Survived
3   4           0.724138
2   3           0.578431
1   2           0.552795
6   7           0.333333
0   1           0.303538
4   5           0.200000
5   6           0.136364
7   8           0.000000
8   11          0.000000

また私たちは、isAlone(独身者)という項目も作り出すことができる。

28.isAlone特徴の作成
for dataset in combine:
    dataset['isAlone'] = 0
    dataset.loc[dataset['FamilySize'] == 1, 'isAlone'] = 1

train_df[['isALone'], 'Survived']].groupby(['isAlone'], as_index=False).mean()


>>>
    IsAlone Survived
0   0       0.505650
1   1       0.303538

ではここまできたら、ParchとSibSpの特徴を削除するとともに、FamilySizeの特徴の座もisAloneに譲り削除しましょう。

29.不要な特徴の削除
train_df = train_df.drop(['Parch', 'SibSp', 'FamilySize'], axis=1)
test_df = test_df.drop(['Parch', 'SibSp', 'FamilySize'], axis=1)
combine = [train_df, test_df]

train_df.head()


>>>


    Survived    Pclass  Sex Age Fare    Embarked    Title   IsAlone
0   0           3       0   1   7.2500  S           1       0
1   1           1       1   2   71.2833 C           3       0
2   1           3       1   1   7.9250  S           2       1
3   1           1       1   2   53.1000 S           3       0
4   0           3       0   2   8.0500  S           1       
1

またここで、PclassとAgeを組み合わせて特徴を作り出すこともできます。

30.年齢と乗船クラスの乗算
for dataset in combine:
    dataset['Age*Class'] = dataset.Age * dataset.Pclass

train_df.loc[:, ['Age*Class', 'Age', 'Pclass']].head(10)


>>>

         Age*Class  Age Pclass
0        3          1   3
1        2          2   1
2        3          1   3
3        2          2   1
4        6          2   3
5        3          1   3
6        3          3   1
7        0          0   3
8        3          1   3
9        0          0   2  

カテゴリ特徴の補完

Embarkedは乗船地に基づいて、S/Q/Cいずれかの値を持っている。私たちの訓練用データからは2つの値が失われている。簡単にこれを満たすには、最も多い出現頻度を用いるのがよいだろう。

31.乗船地の欠損地補完
freq_port = train_df.Embarked.dronpa().mode()[0]
freq_port

>>>
'S'


for dataset in combine:
    dataset['Embarked'] = dataset['Embarked'].fillna(freq_port)

train_df[['Embarked', 'Survived']].groupby(['Embarked'], as_index=False).mean().sort_values(by='Survived', ascending=False)


>>>

    Embarked    Survived
0   C           0.553571
1   Q           0.389610
2   S           0.339009

カテゴリ特徴の数値変換

いま欠損のなくなったEmbarked特徴は、Portという新しい数値特徴に変換することができる。

31.乗船地特徴の数値変換
for dataset in combine:
    dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int)

train_df.head()


>>>

    Survived    Pclass  Sex Age Fare    Embarked    Title   IsAlone Age*Class
0   0           3       0   1   7.2500  0           1       0       3
1   1           1       1   2   71.2833 1           3       0       2
2   1           3       1   1   7.9250  0           2       1       3
3   1           1       1   2   53.1000 0           3       0       2
4   0           3       0   2   8.0500  0           1       1       6

数値の迅速な補完及び変換

料金特徴の中で最も多く出現する値を取得するためにモードを使うことにより、本番用データの中の料金特徴の一つの欠損を補完することができる。これは一行のコードで行うことができる。

ここでは、一つの欠損を置き換えるために中間となる新しい特徴を作ったり欠損を推測するために深い分析をおこなったりしないことに注意する。このコンペの目標に望まれているのは、モデルのアルゴリズムが欠損のない状態で機能させるということだ。

32.本番用データの補完
test_df['Fare'].fillna(test_df['Fare'].dropna().median(), inplace=True)
test_df.head()


>>>

    PassengerId Pclass  Sex Age Fare    Embarked    Title   IsAlone Age*Class
0   892         3   0   2   7.8292      2           1       1       6
1   893         3   1   2   7.0000      0           3       0       6
2   894         2   0   3   9.6875      2           1       1       6
3   895         3   0   1   8.6625      0           1       1       3
4   896         3   1   1   12.2875     0           3       0       3

料金帯を作る。

33.料金帯の作成
train_df['FareBand'] = pd.qcut(train_df['Fare'], 4)
train_df[['FareBand', 'Survived']].groupby(['FareBand'], as_index=False).mean().sort_values(by='FareBand', ascending=True)


>>>

        FareBand        Survived
0       (-0.001, 7.91]  0.197309
1       (7.91, 14.454]  0.303571
2       (14.454, 31.0]  0.454955
3       (31.0, 512.329] 0.581081

料金特徴を、料金帯に基づいて順序的な特徴に変換する。

34.料金特徴の変換
for dataset in combine:
    dataset.loc[ dataset['Fare'] <= 7.91, 'Fare'] = 0
    dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
    dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare']   = 2
    dataset.loc[ dataset['Fare'] > 31, 'Fare'] = 3
    dataset['Fare'] = dataset['Fare'].astype(int)

train_df = train_df.drop(['FareBand'], axis=1)
combine = [train_df, test_df]

train_df.head(10)


>>>
    Survived    Pclass  Sex Age Fare    Embarked    Title   IsAlone Age*Class
0   0           3       0   1   0       0           1       0       3
1   1           1       1   2   3       1           3       0       2
2   1           3       1   1   1       0           2       1       3
3   1           1       1   2   3       0           3       0       2
4   0           3       0   2   1       0           1       1       6
5   0           3       0   1   1       2           1       1       3
6   0           1       0   3   3       0           1       1       3
7   0           3       0   0   2       0           4       0       0
8   1           3       1   1   1       0           3       0       3
9   1           2       1   0   2       1           3       0       0




---------原文ここまで----------

ここまでのまとめ(翻訳者による)

訓練用データに存在していた特徴についての処理まとめ

特徴名 意味 処理の結果
PassengerID 乗客ID 訓練用データからは削除
Survived 生存 特に処理はなし
Pclass 乗船クラス 特に処理はなし
Name 名前 敬称で分けられ、その所属による数値に変換
Sex 性別 文字列から数値に変換
Age 年齢 年齢帯に分けられ、その所属による数値に変換
SibSip 兄弟姉妹、配偶者 FamilySizeという特徴に統合され、この特徴は削除された
Parch 親、子供 FamilySizeという特徴に統合され、この特徴は削除された
Ticket チケット 削除された
Fare 料金 料金帯に分けられ、その所属による数値に変換
Cabin 客室 削除された
Embarked 乗船地 乗船地が数値に変換され、その所属による数値に変換

最終的に残った特徴についてのまとめ

特徴名 意味 説明
Survived 生存 生存の成否についての情報。特に処理はされていない
Pclass 乗船クラス 乗船した階級についての情報。特に処理はされていない
Sex 性別 乗客の性別についての情報。元々文字列で表されていたが、数値に変換されている
Age 年齢 乗客の年齢帯についての情報。元々年齢そのものを表していたが、年齢帯に分けられている
Fare 料金 乗客が支払った料金帯についての情報。元々料金そのものを表していたが、料金帯に分けられている
Embarked 乗船地 乗船地についての情報。元々文字列で表されていたが、数値に変換されている
Title 敬称 乗客の名前についている敬称についての情報。名前項目から抽出して作成され、数値に変換されている
isAlone 家族構成 乗客の家族構成についての情報。親、子供、兄弟姉妹、配偶者などの情報が統合され作り出された
Age*Class 年齢と乗船クラスの乗算結果 年齢と乗船クラスを乗算したもの

原文

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3