- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- 機械学習/Pythonで前処理する へ行く。
目次 †
はじめに †
Pythonの機械学習ライブラリーscikit-learnを用いて機械学習を行うには、入力をNumPy行列にする必要があります。
scikit-learnを使うととても簡単に機械学習ができますが、実際にscikit-learnを使って機械学習をしようとすると、scikit-learnに入力するNumPy行列を作る前処理の方が大変です。
ここでは、前処理(カテゴリー変数の変換、欠損値の処理、標準化)について説明します。
環境はこれまでと同じです。
例として、銀行マーケティングのデータセットを用います。
データの読み込み †
データは、Excelなどの表計算ソフトを使って用意し、CSVファイルとして書き出します。
このCSVファイルを、Pandasを使って読み込みます。
import pandas as pd df_bank = pd.read_csv('bank.csv')
ここでは、bank.csvがCSVファイルの名前です。
最初の列が事例IDの場合は、index_col オプションに列番号を指定します。(列番号は 0 から始まります。)
df_bank = pd.read_csv('bank.csv', index_col=0)
カテゴリー変数の変換 †
scikit-learnは、NumPy行列を入力とします。 このため、scikit-learnには数値しか入力できません。
一般的なカテゴリー変数は文字列で表されているため、これを変換する必要があります。
ここでは、二つの方法を説明します。
- カテゴリー変数を数値に置換する
- カテゴリー変数をダミー変数に変換する
数値に置換 †
カテゴリー変数の値を数値に置き換えるには、map()メソッドやreplace()メソッドを使います。
例えば、銀行マーケティングのデータセットには month という名前のカテゴリー変数があり、値として jan, feb, ... という月の名前を取っています。
map()メソッドを用いて、月を表す名前を数値に置き換えます。
df_bank['month'] = df_bank['month'].map({'jan':1, 'feb':2, 'mar':3, 'apr':4, 'may':5, 'jun':6, 'jul':7, 'aug':8, 'sep':9, 'oct':10, 'nov':11, 'dec':12})
ダミー変数に変換 †
カテゴリー変数の値ごと変数を作り、その値なら 1、そうでないなら 0 とする変数に変換します。 このようにして作成された変数をダミー変数といいます。
例えば、銀行マーケティングのデータセットには、maritalという名前の説明変数があり、値として married, single, divorced という値を取っています。
age | marital |
39 | married |
51 | married |
36 | single |
34 | divorced |
maritalをダミー変数にすると次のようになります。
age | marital_married | marital_single | marital_divorced |
39 | 1 | 0 | 0 |
51 | 1 | 0 | 0 |
36 | 0 | 1 | 0 |
34 | 0 | 0 | 1 |
実際には、married でも single でもなければ divorced であることがわかるので、一つを取り除き、[math]k[/math] 種類の値を取るカテゴリー変数から [math]k - 1[/math] 個のダミー変数を作成します。
age | marital_married | marital_single |
39 | 1 | 0 |
51 | 1 | 0 |
36 | 0 | 1 |
34 | 0 | 0 |
ダミー変数は、Pandasの get_dummies 関数を用いて作成します。
dummy = pd.get_dummies(df_bank[['marital']], drop_first=True)
drop_first オプションは、ダミー変数の数を一つ減らすためのものです。 (get_dummiesの結果はデータフレームになります。)
get_dummiesメソッドには複数のカテゴリー変数を指定できるので、実際には、全てのカテゴリー変数をまとめて変換します。
df_bank = pd.get_dummies(df_bank, drop_first=True)
ダミー変数を作成したら、データフレームにダミー変数をマージして、カテゴリー変数を取り除きます。
import numpy as np import pandas as pd df_bank = pd.read_csv('bank.csv') df_bank = df.bank.replace('unknown', np.NaN)
欠損値の処理 †
一般的なデータには欠損値(値がない項目)があります。
欠損値に対応していない機械学習手法を使うときには、欠損値を処理しておく必要があります。
ここでは、二つの方法を説明します。
- 欠損値を含むデータの除去
- 値の補完
欠損値を含むデータをPandasのread.csv()メソッドで読み込むと、numpy.NaN になります。
今回、例に用いている銀行マーケティングのデータセットでは、欠損値が 'unknown' となっています。 そこで、まず初めに、CSVファイルを読み込んだ直後に 'unknown' を numpy.NaN に置換し、欠損値とします。
df_bank = df_bank.drop('poutcome', axis=1)
欠損値を含むデータの除去 †
データの数が十分に多く、かつ、欠損値を含むデータが少ないときは、欠損値を含むデータを取り除いても学習される予測モデルには大きな影響がないことが期待できます。
欠損値を含むデータを取り除くには、dropna()メソッドを用います。
df_bank = df_bank.dropna(how='any')
オプションの how='any' は、NumPy.NaN を一つでも含む行を削除します。
値の補完 †
データの数が少ないときや欠損値を含むデータが多いときは、欠損値を含むデータを取り除いてしまうと、学習される予測モデルが悪くなってしまいます。
そこで、このような場合には、欠損値に平均値、中央値、最頻値などを補完します。
今回の銀行マーケティングのデータセットでは、欠損値は全てカテゴリー変数に含まれているので、例として、poutcomeのsuccessを 1、failureを 0 にカテゴリー変数を変換します。
df_bank['poutcome'] = df_bank['poutcome'].map({'success':1, 'failure':0})
欠損値に値を補完するには、sklearn.preprocessingのImputerを使います。
from sklearn.impute import SimpleImputer imputer = SimpleImputer(missing_values=np.nan, strategy='median') df_bank['poutcome'] = imputer.fit_transform(df_bank['poutcome'].values.reshape(-1, 1))
Imputerを作成するときの missing_valueオプションには欠損値の値を指定します。 strategyオプションには補完する値を指定し、平均値を補完するときは 'mean'、中央値を補完するときは 'median'、最頻値を補完するときは 'most_frequent' とします。 axis=0 は列ごとに補完することを表します。
Imputerによる補完は、fit()メソッドで補完する値を求め、transform()メソッドで欠損値を補完する、という手順で行います。 上の例では、この手順を一度に行うfit_transform()メソッドを用いています。
標準化 †
説明変数の値域のスケールが大きく異なると、学習された予測モデルのパラメーター(例えば、線形回帰分析の係数)を比較することが難しくなります。
そこで、説明変数が平均 0、標準偏差 1 となるように説明変数の値 [math]x[/math] をzスコア [math]z[/math] に変換します。 \[ z = \frac{x - \mu}{\sigma} \] ここで、[math]\mu[/math] は平均値、[math]\sigma[/math]は標準偏差を表します。
zスコアに標準化することによって、説明変数が正規分布にしたがっているとき、[math][-1, 1][/math] の範囲に約68.3%のデータが、[math][-2, 2][/math] の範囲に約95.5%のデータが、[math][-3, 3][/math] の範囲に約99.7%のデータが含まれるようになります。
標準化するには、sklearn.preprocessingのStandardScalerを使います。
from sklearn.preprocessing import StandardScaler sc = StandardScaler() df_bank['age'] = sc.fit_transform(df_bank['age'].values.reshape(-1, 1))
StandardScalerによる標準化も、Imputerによる補完と同じように、fit()メソッドを用いて平均と標準偏差を求め、transform()メソッドを用いてzスコアに変換します。 この例でも、fitとtransformを一度に行うfit_transform()メソッドを用いています。
ageは整数なので、実際に標準化すると int64 が float64 になっちゃったよという警告が出ます。