目次
Pandasのデータフレーム(DataFrame)
Pandasには2つの主要なデータ構造があります。
Series(シリーズ)が1次元、DataFrame(データフレーム)が2次元です。
ようするに、データフレームは、EXCEL表みたいに行と列でデータを保持し、列は「列名」、行数は「行インデックス」として管理します。
このデータの内容を確認したり、統計をとったり、学習データに適しているかどうかを検査したりします。
その結果を踏まえてもろもろの加工を行って、学習データをしあげていきます。
今回はデータフレームの加工方法についてまとめます。
なお、コード例は、以下がインポートされている前提とします。
import pandas as pd
例のデータは 以下の要領でCSVファイルを読み込んだ「t」というDataFrameがある想定で例を書いていきます。
例では kaggleのtitanicデータを一部使わせていただいてます。
t = pd.read_csv('./csvdata/a.csv')
データの置換え
不適切なデータ(外れ値などのごみデータ)が含まれているときは、学習データとして適切な値に置き換えてやる必要があります。
その方法をいくつかまとめます。
置き換え:文字列データを数字にする
機械学習に使えない文字列データを、数字に置き換えるときとかに使います。
対象の文字列がわかっている場合は、DataFrameの組み込みメソッド(replace)を使っても簡単にできます。
例えば、上記「sex」列の「male」「famale」を「0」「1」にするには。
tdf['Sex'].replace(['male','female'],[0,1], inplace=True)
です。
結果は、以下のようになります。
置き換え:正規表現を使う
DataFrameの組み込みメソッド(replace)は「regex=True」にすると、置き換え対象の指定に正規表現が使えます。
例えば。
上記の[Cabin」列のように、「C35」「D」「C33 E45」などのように、大文字の英数字で始まり、単独で終わる場合もあれば、後ろに英数字空白が続く場合もあるようなものをすべて「1」に置き換えるとすると。
tdf['Cabin'].replace('[A-Z].*',1, regex=True, inplace=True)
のように正規表現を使うと一発でできます。
置き換え:カテゴリデータを数値にする
変換対象の文字列がすべてわからない場合は、replaceで条件を書くのではなく、「factorise」を使います。
例えば、以下の「Embarked」列は「S・C」以外に文字があります。
そういう時は
tdf['Embarked'] = pd.factorize(t'Embarked'])[0]
のようにすると、きっちり数値返還してくれます。
欠損値の補完
データには欠損値(NaN)もありえます。
欠損値を扱う方針としては
- 欠損値を修正せずそのまま使う
- 代表的な値または他の特徴量から予測した値で欠損値を補完する
- 欠損値か否かの情報(0or1)で新しい特徴量を作る
の3パターンが考えられますので、それぞれのやり方を整理します。
欠損値の補完:代表的な値または他の特徴量から予測した値で補完
DataFrameの組み込みメソッドの「fillna」を使います。
上記の「Cabin」列にある、NaN(欠損値)を「0」に置き換えます。
tdf['Cabin'].fillna(0, inplace=True)
で、以下のようになります。
上記の「0」のところを、
np.mean(t['Fare'])のような式に置き換えると、平均値や最小値などいろいろな値に置き換えることもできます。
欠損値の補完:欠損値か否かの情報(0or1)で新しい特徴量を作る
例えば。
のようにNaN(欠損値)を含む「Age」列で欠損値を置き換えてしまう前に、ここが欠損値であったという情報を「AgeIsNull」みたいな列を追加して残しておきたいような場合には、以下のよう組み込みメソッド「loc」を使います。
tdf.loc[~(tdf['Age'].isnull()), 'AgeIsNull']= 0
tdf.loc[(tdf['Age'].isnull()), 'AgeIsNull']= 1
~は否定演算子です。
Age列が「NaN」でない行は、「AgeIsNull」列に「0」をセットし、そのあとでAge列が「NaN」である行の「AgeIsNull」列に「1」をセットしてます。
欠損値の補完:欠損値を0、欠損値以外を1にする
titanicにはないのですが、たまに欠損値と、それ以外がバラバラのデータ(なんかのIDとか)が混在しています的なデータがあります。
それを欠損値を「0」、それ以外を「1」に置き換えたい場合があります。
それを「uid」という列でやると、こんな感じです。
tdf.loc[(tdf['uid'].notnull()), 'uid'] = 1
tdf['uid'].fillna(0, inplace=True)
列追加
新しい列を追加する場合もあります。
例えば、A列とB列をくっつけてC列を作ったり、A列とB列の値の組み合わせを表すカテゴリを作ったりもしますので。
そんな列追加の方法をまとめてみます。
列追加:カテゴライズデータをダミー列にする
以下のEmbarked列は、「S,・C・Q」の3つのカテゴリに分かれているデータです。
これを単純に数字にする変換(上でfactorizeしたみたいな)は、その数字の大小関係まで特徴ととらえられてしまって、よくない場合があります。
そういう時は、0,1の2値でカテゴリの違いを表現できるようなダミー列を作るというのが良いといわれてます。
こういうときに便利なのが「get_dummies」です。
t_emb = pd.get_dummies(t['Embarked'], prefix='Emb')
のように実行すると「t_emb」に以下のようにできます。
これを元のDataFrameにくっつけるには「merge」を使います。
train = pd.merge(t, t_emp, right_index=True, left_index=True)
上記でもとの「t」の後ろに、「t_emp」がくっつきます。
列追加:条件式で新しい「one-hot」列を作る
機械学習用データで、1つの列に「1,2,3,4,5」のように3つ以上の選択肢があるとき、そのまま学習すると単なるコードなのに、数値の差に意味があるように学習してしまって精度があがらないことがあります。
そんなとき、IsOne、isTwo・・のように、0,1の二値(one-hot)に変換した特徴量の列を追加する場合にも、上記の新しい特徴量を作る手段は使えます。
例えば。
上記の「Pclass」列のように「1 = 1st, 2 = 2nd, 3 = 3rd」という3つの選択肢があるものを、Is1st、Is2nd、Is3rdのような0と1の2値の列を追加するような場合、以下のようにします。
t.loc[(train_org['Pclass']==1), 'Is1st'] = 1
t.loc[~(train_org['Pclass']==1), 'Is1st'] = 0
t.loc[(train_org['Pclass']==2), 'Is2nd'] = 1
t.loc[~(train_org['Pclass']==2), 'Is2nd'] = 0
t.loc[(train_org['Pclass']==3), 'Is3rd'] = 1
t.loc[~(train_org['Pclass']==3), 'Is3rd'] = 0
すると、以下のようにより特徴量が明確になります。
列削除
機械学習で使用しない列を切り落とすときに使います。
例えば、「Name」と「PassengerId」列を切り落として、学習用データを作るときは以下のようにします。
delete_cols = ['Name','PassengerId']
train = train_org.drop(delete_cols,axis=1)
axis=1は必須です。
おまけ:kaggleのsubmit用フォーマットに、評価結果を更新
kaggleのsubmit用フォーマットに、評価結果を更新するパターンです。
y_pred = clf.predict(x_test)
で評価結果が「y_pred」にある想定で、更新先はこんなPandasのDataFrameです。
この「Survived」列を、上記の評価結果で置き換えるのは。
sub['Survived'] = list(map(int, y_pred))
です。
mapで、y_predの要素をすべて「int()」で数値に変換して、listにして渡します。
今回はこんなところで。
ではでは。