【データ解析入門】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()
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()
データ前処理
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)