とりあえず
KaggleのTitanicチュートリアルにおいて、精度を上げるために何をやっていけば良いのか?を上位者のアイディアを参考に前処理フローを整理する。
前処理フロー
データを読み込む
兎にも角にもデータを読み込む。やり方はPandasでDataFrameとして読み込む。
使うコマンド:pd.read_csv()
データを見る
- 観点1:項目名の意味を書き出す。
- 観点2:項目毎の欠損データを書き出す。
- 観点3:数値データと文字データを分類する。(把握するだけでOK)(型:objectが文字データ扱い)
ココが割と重要。欠損データは”消すでは無く”、”補完し利用する”事を優先する。
項目毎の意味を理解しないと欠損データの補完のアイディアが出ない。よって”意味”も大事。
使うコマンド:pd.info()
第一欠損値補完
初めは中央値、平均、ゼロ。から適切なものを入れてみる。
文字データの取り扱いを決める(型:object)
文字データの意味を考え適切な数値データを導出する。
- 観点1:文字->数値の単一変換ができそうなモノはそのまま変換する。
- 観点2:複雑なモノは、必要要素だけ抜き出し成分値を導出する。
- 観点3:わからないモノは、一旦除外する。(最終手段)
Titanicの場合
[Name]・・・名前 =>観点2
[Sex]・・・性別 =>観点1
[Ticket]・・・チケット番号 =>観点2
[Cabin]・・・部屋番号 =>観点2
[Embarked]・・・乗船した港 =>観点1
<観点1>
[Sex]・・・性別
male/femaleを数値に置き換える(0,1)
[Embarked]・・・乗船した港
Cherbourg、Queenstown、Southamptonの頭文字C,Q,Sを数値に置き換える(0,1,2)
<観点2>
[Name]・・・名前
パッと見わからない。。。敬称で分類する。(敬称もMr,Miss,Msだけじゃない・・・ 英語だけじゃなく多国語における貴族敬称とかも考えたらしい。)
[Capt,Col,Countess,Don,Dr,Jonkheer,Lady,Major,Master,Miss,Mlle,Mme,Mr,Mrs,Ms,Rev,Sir]
手順
1.まずは名前を単語に分類し、タイトルの一覧を見てみる。
def get_title(name):
title_search = re.search(' ([A-Za-z]+)\.', name)
if title_search:
return title_search.group(1)
return ""
for row in train:
row['honorific'] = row['Name'].apply(get_title)
print(pd.crosstab(train['honorific'], train['Sex']))
2.同じ意味合いのモノはまとめる。
train['honorific'] = train['honorific'].replace(['Lady', 'Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
train['honorific'] = train['honorific'].replace('Mlle', 'Miss')
train['honorific'] = train['honorific'].replace('Ms', 'Miss')
train['honorific'] = train['honorific'].replace('Mme', 'Mrs')
3.敬称を分類し数値に変える。
honorific_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
for row in train:
row['honorific'] = row['honorific'].map(honorific_mapping)
row['honorific'] = row['honorific'].fillna(0)
[Ticket]・・・チケット番号
パッと見わからない。。。チケットの頭文字で分類する。
手順
1.頭文字を取ってきてグループ化。
for row in train:
row['Ticket_Lett'] = row['Ticket'].apply(lambda x: str(x)[0])
row['Ticket_Lett'] = row['Ticket_Lett'].apply(lambda x: str(x))
row['Ticket_Lett'] = np.where((row['Ticket_Lett']).isin(['1', '2', '3', 'S', 'P', 'C', 'A']), row['Ticket_Lett'], np.where((row['Ticket_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']), '0','0'))
row['Ticket_Len'] = row['Ticket'].apply(lambda x: len(x))
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)
[Cabin]・・・部屋番号
パッと見わからない。。。チケットの頭文字で分類する。
手順
1.頭文字を取ってきてグループ化。
for row in train:
row['Cabin_Lett'] = row['Cabin'].apply(lambda x: str(x)[0])
row['Cabin_Lett'] = row['Cabin_Lett'].apply(lambda x: str(x))
row['Cabin_Lett'] = np.where((row['Cabin_Lett']).isin([ 'F', 'E', 'D', 'C', 'B', 'A']),row['Cabin_Lett'], np.where((row['Cabin_Lett']).isin(['W', '4', '7', '6', 'L', '5', '8']), '0','0'))
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)
他に関連性がありそうなデータを作る
Titanicの場合
Pclass、Sibsp、Parchに注目。
- Pclassは何等級のところに乗っていたかを表す。
- Sibspは乗っていた夫婦と兄弟の人数を表す。
- Parchは乗っていた親と子供の人数を表す。
これを元に以下を導出する
FamilySize(家族の人数) = Sibsp+Parch+1が
IsAlone(一人かどうか) = FamilySizeが1なら1
train["FamilySize"] = train["SibSp"] + train["Parch"] + 1
for row in train:
row['IsAlone'] = 0
row.loc[row['FamilySize'] == 1, 'IsAlone'] = 1
モデリング
前処理を行ったモノの内数値データのみを使う。