【データ解析入門】Pandasでデータ処理・Kaggle/Titanicを題材に

 

今日は、Python表計算ライブラリであるPandasによるデータ処理について説明します。データの読み込み・可視化・簡単な穴埋めを行います。

Pandasは非常に高機能ですが、使い勝手が独特なので、練習して慣れましょう。

Kaggle: Your Home for Data Science の練習問題である

Titanic: Machine Learning from Disaster | Kaggle を題材に練習します。Titanicの乗客リストから死者か生存者かを予測する問題です。なんだか不謹慎な気もしますが、これが風化ということなのでしょうか。

 

乗客リストのデータはkaggle公式サイトからダウンロードできます。

 データをまずは読み込む・可視化

ライブラリのインポート


# pandas
import pandas as pd
import numpy as np

# visualization
import seaborn as sns
import matplotlib.pyplot as plt

import pickle

ファイルの読み込み

train_df = pd.read_csv('./train.csv')
test_df = pd.read_csv('./test.csv')
combine = [train_df, test_df]

後で見るように、combineしておくとfor文による一括処理が可能です。

データをざっと見てみる

print('='*100)
print('Train data')
print(train_df.describe())
print('='*100)
print(train_df.describe(include='O'))
print('='*100)
print('Test data')
print(test_df.describe())
print('='*100)
print(test_df.describe(include='O'))
print('='*100)

出力結果


====================================================================================================
Train data
       PassengerId    Survived      Pclass         Age       SibSp       Parch        Fare
count   891.000000  891.000000  891.000000  714.000000  891.000000  891.000000  891.000000
mean    446.000000    0.383838    2.308642   29.699118    0.523008    0.381594   32.204208
std     257.353842    0.486592    0.836071   14.526497    1.102743    0.806057   49.693429
min       1.000000    0.000000    1.000000    0.420000    0.000000    0.000000    0.000000
25%     223.500000    0.000000    2.000000   20.125000    0.000000    0.000000    7.910400
50%     446.000000    0.000000    3.000000   28.000000    0.000000    0.000000   14.454200
75%     668.500000    1.000000    3.000000   38.000000    1.000000    0.000000   31.000000
max     891.000000    1.000000    3.000000   80.000000    8.000000    6.000000  512.329200
====================================================================================================
                     Name   Sex  Ticket Cabin Embarked
count                 891   891     891   204      889
unique                891     2     681   147        3
top     Webber, Mr. James  male  347082    G6        S
freq                    1   577       7     4      644
====================================================================================================
Test data
       PassengerId      Pclass         Age       SibSp       Parch        Fare
count   418.000000  418.000000  332.000000  418.000000  418.000000  417.000000
mean   1100.500000    2.265550   30.272590    0.447368    0.392344   35.627188
std     120.810458    0.841838   14.181209    0.896760    0.981429   55.907576
min     892.000000    1.000000    0.170000    0.000000    0.000000    0.000000
25%     996.250000    1.000000   21.000000    0.000000    0.000000    7.895800
50%    1100.500000    3.000000   27.000000    0.000000    0.000000   14.454200
75%    1204.750000    3.000000   39.000000    1.000000    0.000000   31.500000
max    1309.000000    3.000000   76.000000    8.000000    9.000000  512.329200
====================================================================================================
                                                     Name   Sex    Ticket            Cabin Embarked
count                                                 418   418       418               91      418
unique                                                418     2       363               76        3
top     Cardeza, Mrs. James Warburton Martinez (Charlo...  male  PC 17608  B57 B59 B63 B66        S
freq                                                    1   266         5                3      270
====================================================================================================

読みづらい人はコピペするか、右下にある三角を引っ張って広げてください。include='O'で数値以外のサマリを表示できます

head関数は表の上の方をパッと出してくれて見やすくて便利です。お尻を出すにはtail関数を使います。

print('='*100)
print(train_df.head())
print('='*100)
print(test_df.head())
print('='*100)

====================================================================================================
Train data
       PassengerId    Survived      Pclass         Age       SibSp       Parch        Fare
count   891.000000  891.000000  891.000000  714.000000  891.000000  891.000000  891.000000
mean    446.000000    0.383838    2.308642   29.699118    0.523008    0.381594   32.204208
std     257.353842    0.486592    0.836071   14.526497    1.102743    0.806057   49.693429
min       1.000000    0.000000    1.000000    0.420000    0.000000    0.000000    0.000000
25%     223.500000    0.000000    2.000000   20.125000    0.000000    0.000000    7.910400
50%     446.000000    0.000000    3.000000   28.000000    0.000000    0.000000   14.454200
75%     668.500000    1.000000    3.000000   38.000000    1.000000    0.000000   31.000000
max     891.000000    1.000000    3.000000   80.000000    8.000000    6.000000  512.329200
====================================================================================================
                              Name   Sex Ticket        Cabin Embarked
count                          891   891    891          204      889
unique                         891     2    681          147        3
top     Ryerson, Miss. Emily Borie  male   1601  C23 C25 C27        S
freq                             1   577      7            4      644
====================================================================================================
Test data
       PassengerId      Pclass         Age       SibSp       Parch        Fare
count   418.000000  418.000000  332.000000  418.000000  418.000000  417.000000
mean   1100.500000    2.265550   30.272590    0.447368    0.392344   35.627188
std     120.810458    0.841838   14.181209    0.896760    0.981429   55.907576
min     892.000000    1.000000    0.170000    0.000000    0.000000    0.000000
25%     996.250000    1.000000   21.000000    0.000000    0.000000    7.895800
50%    1100.500000    3.000000   27.000000    0.000000    0.000000   14.454200
75%    1204.750000    3.000000   39.000000    1.000000    0.000000   31.500000
max    1309.000000    3.000000   76.000000    8.000000    9.000000  512.329200
====================================================================================================
                        Name   Sex    Ticket            Cabin Embarked
count                    418   418       418               91      418
unique                   418     2       363               76        3
top     Watt, Miss. Bertha J  male  PC 17608  B57 B59 B63 B66        S
freq                       1   266         5                3      270
====================================================================================================

グラフ化

grid = sns.FacetGrid(train_df, col='Survived', row='Pclass', height=2.2, aspect=2.0)
grid.map(plt.hist, 'Age', alpha=.5, bins=20)
grid.add_legend();
plt.show()

f:id:WoodyWoodpecker:20180915145937p:plain

grid = sns.FacetGrid(train_df, col='Embarked', height=2.2, aspect=1.6)
grid.map(sns.pointplot, 'Pclass', 'Survived', 'Sex', palette='deep')
grid.add_legend()
plt.show()

f:id:WoodyWoodpecker:20180915150923p:plain

データ前処理

Embarkedはどのように生存率に影響しているのか

print(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.336957

というわけでSが一番生存率が低く、Cが高いので、そのようにmapしてみようと思います。

非数データを数値データに変換

for dataset in combine:
    dataset['Sexvalue'] = dataset['Sex'].map({'male': 0, 'female': 1})
    dataset['Embarked'] = dataset['Embarked'].map({'S': 0, 'Q': 1, 'C': 2})
    dataset.drop(['Cabin', 'Sex', 'Ticket', 'Name'], axis=1, inplace=True)

map関数は辞書内の適用をします。 drop関数は第一引数がリストで、その内容を落とします。軸が0だと各行、1だと各列を取り除きます。今回は1なので、Cabin,Sex,……といった情報そのものが表(Dataframe)から取り除かれます。ただし、inplace引数をつけないと取り除かれないので注意しましょう。(取り除いたDataframeを戻り値として返すようになります。inplaceをつけると戻り値が無くなる代わりにそのものから取り除きます)

またここで扱いづらいCabin名とかチケット名とかを落とします。

データの欠損を確認

もう一度describeし、countを調べます。足りていないのがあればそれはデータが不足しているので、埋めることが必要になります。


Train data
       PassengerId    Survived      Pclass         Age       SibSp       Parch        Fare    Embarked    Sexvalue
count   891.000000  891.000000  891.000000  714.000000  891.000000  891.000000  891.000000  889.000000  891.000000
〜中略〜
Test data
       PassengerId      Pclass         Age       SibSp       Parch        Fare    Embarked    Sexvalue
count   418.000000  418.000000  332.000000  418.000000  418.000000  417.000000  418.000000  418.000000

というわけで、AgeとFareとEmbarkedが欠けています。

運賃データを修正

# Fare and Embarked completion
for dataset in combine:
    dataset.loc[(dataset.Fare.isnull()), 'Fare'] = dataset.Fare.dropna().median()
    dataset.loc[(dataset.Embarked.isna()), 'Embarked'] = dataset.Embarked.dropna().median()

中央値を空いているところにとりあえず代入しておきます。

年齢データを訂正

# age data completion
age_guess = np.zeros([2, 3])
for dataset in combine:
    for i in range(2):
        for j in range(3):
            guess_df = dataset[(dataset['Sexvalue'] == i) & (
                dataset['Pclass'] == j+1)]['Age'].dropna()
    age_guess[i, j] = guess_df.median()
    age_guess[i, j] = int(age_guess[i, j]*2)/2

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

ちょっと長くてわかりにくいですが、age_guessは性別とPclass別に推定年齢を格納する変数です。推定とはいっても、中央値を入れているだけです。中央値を求めた後で、isnullなものにその中央値を代入しています。

 

保存

combine = [train_df, test_df]
with open("combine.pkl", 'wb') as f:
    pickle.dump(combine,f)