こんにちは!なんだかんだ久しぶりの投稿になりました。
今回はカテゴリーデータの前処理について書いていきます。
機械学習において分類問題や回帰問題を扱うにしてもトレーニングデータがすべて数値であれば扱いやすいです。
しかし必ずしもそうとは限りません。文字列などが出てくることも当然あります。
例えば服を例にしましょう。特徴量としていろいろあると思いますが数値特徴量の例は値段ですね。
しかし服の特徴量は当然それ以外にもあります。例えばサイズ。Sサイズ、Mサイズ、Lサイズなどです。
でもこれは数値じゃないだけで並べ替えや順位付けが可能な値です。そのようなものを「順序特徴量」といったりします。
それ以外にも服の色という特徴量もあります。これは赤色、青色、黄色などです。これに関しては順序はありません。そのような特徴量を「名義特徴量」といいます。
このようなものを機械学習で正しく理解させるためには整数に変換させる必要があります。今回はどのようにして変換すればいいのかscikit-learnを使って紹介します
まずはサンプルデータから
1 2 3 4 5 6 7 8 9 |
import pandas as pd sample = pd.DataFrame([ ['yellow', 'S', 1000, 'class1'], ['red', 'M', 2400, 'class2'], ['blue', 'M', 1200, 'class3'], ['green', 'XL', 1400, 'class1']]) sample.columns = ['color', 'size', 'price', 'classlabel'] print(sample) |
結果は以下のように表示されます
1 2 3 4 5 |
color size price classlabel 0 yellow S 1000 class1 1 red M 2400 class2 2 blue M 1200 class3 3 green XL 1400 class1 |
今回はこのサンプルを使ってやっていきます
順序特徴量の場合
今回のサンプルの場合ではsizeにあたる部分です。残念ながら今の機械学習のライブラリーの中で順序特徴量を正しく変換してくれるものは私が知る限り存在しません。
なので明示的にしてあげなければなりません。サイズの場合ですと例えばXL = L + 1 = M + 2 = S + 3のような形です
では変換していきましょう
1 2 3 |
size_mapping = {'XL':4, 'L':3, 'M':2, 'S':1} sample['size'] = sample['size'].map(size_mapping) print(sample) |
結果以下のようになります
1 2 3 4 5 |
color size price classlabel 0 yellow 1 1000 class1 1 red 2 2400 class2 2 blue 2 1200 class3 3 green 4 1400 class1 |
また元に戻したい場合逆マッピングをしてあげればいいです。
1 2 |
inv_size_mapping = {size_int:size_str for size_str, size_int in size_mapping.items()} print(sample['size'].map(inv_size_mapping)) |
クラスラベルのエンコーディングについて
大体の機械学習ではクラスラベルは数字であるほうが好ましいです。scikit-learnの分類用の推定器には内部で整数変換するものもありますがクラスラベルを整数の配列として提供して変換させてあげるほうが技術的ミスを回避してあげられていい方法になります。ではやってみましょう
1 2 3 4 |
import numpy as np class_label_mapping = {label:idx for idx, label in enumerate(np.unique(sample['classlabel']))} sample['classlabel'] = sample['classlabel'].map(class_label_mapping) print(sample) |
結果は以下のようになります
1 2 3 4 5 |
color size price classlabel 0 yellow 1 1000 0 1 red 2 2400 1 2 blue 2 1200 2 3 green 4 1400 0 |
名義特徴量の場合
最後に名義特徴量の場合を見ていきましょう。2つの方法を紹介します
1つ目はOneHotEncoderを使う方法です
1 2 3 4 5 |
from sklearn.preprocessing import LabelEncoder color_le = LabelEncoder() sample_color = sample.values sample_color[:, 0] = color_le.fit_transform(sample_color[:, 0]) print(sample_color) |
この時点の結果は以下のようになる
1 2 3 4 |
[[3 1 1000 0] [2 2 2400 1] [0 2 1200 2] [1 4 1400 0]] |
このままだとyellow > red > green > blueと勘違いしてしまう。そこで以下の処理をする
1 2 3 |
from sklearn.preprocessing import OneHotEncoder ohe = OneHotEncoder(categorical_features=[0]) print(ohe.fit_transform(sample_color).toarray()) |
結果は以下のようになる
1 2 3 4 |
[[0 0 0 1 1 1000 0] [0 0 1 0 2 2400 1] [1 0 0 0 2 1200 2] [0 1 0 0 4 1400 0]] |
となり、左からblule,green,red,yellowの順で該当するものが1、それ以外が0の値を持つようになった。
同じような結果を得るにはもう一つpandasを使ったやり方がある
1 |
print(pd.get_dummies(sample)) |
以下が結果です
1 2 3 4 5 |
size price classlabel ... color_green color_red color_yellow 0 1 1000 0 ... 0 0 1 1 2 2400 1 ... 0 1 0 2 2 1200 2 ... 0 0 0 3 4 1400 0 ... 1 0 0 |
今回はカテゴリーデータの前処理についてでした。これがちゃんとできないと機械学習がうまく分類できない、回帰できないということになりますね。
参考にしていただければと思います