注意:
この記事で取り扱ったモデルの仕様がsklearn 0.20から変更された結果、この記事の内容はもはやあまり役に立たなくなっています。
この記事は記録として残しますが、最新の仕様については下リンクの記事を御覧ください。
以下のこの記事の記述は古い仕様に基づいており、また内容的にも若干不完全な部分があります。お読みになる方は、その点についてご承知くださいますようお願いします。
2018年12月2日
スポンサーリンク
はじめに
sklearnのLabelEncoderとOneHotEncoderは、カテゴリデータを取り扱うときに大活躍します。シチュエーションとしては、
- なんかぐちゃぐちゃとカテゴリデータがある特徴量をとにかくなんとかしてしまいたい
- 教師ラベルがカテゴリデータなので数値ラベルにしたい
こんなとき使えます。
使い方は簡単なのですが、備忘録としてまとめておきます。
LabelEncoderの使い方
厳密にはsklearn.preprocessing.LabelEncoderですね。
sklearn.preprocessing.LabelEncoder — scikit-learn 0.20.2 documentation
必要なことは公式サンプルにぜんぶ書いてあるのですが、自分でも使ってみましょう。
>>> from sklearn.preprocessing import LabelEncoder >>> week_breakfast = ["パン","ご飯","なし","パン","シリアル","なし","なし"] >>> le = LabelEncoder() >>> labels = le.fit_transform(week_breakfast) >>> labels array([3, 0, 1, 3, 2, 1, 1])
このように変換できます。
ラベルから元のカテゴリに変換するには?
>>> le.classes_ # indexとカテゴリが対応したnumpy配列になっていることを確認 array(['ご飯', 'なし', 'シリアル', 'パン'], dtype='<U4') >>> [le.classes_[x] for x in labels] # リスト内包表記を活用する(最速かどうかはよくわからない) ['パン', 'ご飯', 'なし', 'パン', 'シリアル', 'なし', 'なし'] >>> week_breakfast # 確認のため再掲(私の食生活とかではありません) ['パン', 'ご飯', 'なし', 'パン', 'シリアル', 'なし', 'なし']
普通にできますね。
実際にはこういうことはしないと思います。その代わり、le.classes_をいろいろなものに渡して使うことができます。
たとえば、分類をしてsklearn.metrics.classification_reportで見てみたいと思ったときに、
>>> from sklearn.metrics import classification_report >>> print(classification_report(labels, labels)) # とりあえず両方同じlabelsを渡している precision recall f1-score support 0 1.00 1.00 1.00 1 1 1.00 1.00 1.00 3 2 1.00 1.00 1.00 1 3 1.00 1.00 1.00 2 avg / total 1.00 1.00 1.00 7
0,1,2,3だとわかりづらいですね。でもclassification_reportにはtarget_namesという引数があり、
>>> print(classification_report(labels, labels, target_names=le.classes_)) precision recall f1-score support ご飯 1.00 1.00 1.00 1 なし 1.00 1.00 1.00 3 シリアル 1.00 1.00 1.00 1 パン 1.00 1.00 1.00 2 avg / total 1.00 1.00 1.00 7
こうしてやることができる訳です。なので、LabelEncoderのインスタンスは、大切に(プログラムのスコープ上とかに)取っておきましょう。
参考:
sklearn.metrics.classification_report — scikit-learn 0.20.2 documentation
sklearnのclassification_reportで多クラス分類の結果を簡単に見る - 静かなる名辞
(二番目は自分の記事)
OneHotEncoderの使い方
これはいわゆるOne-hot表現を得るものです。いろいろな機械学習フレームワークに類似の機能があると思いますが、sklearnではsklearn.preprocessing.OneHotEncoderが対応します。
使い方は以下の通りです。
>>> import numpy as np >>> data = np.arange(9).reshape(9,1) >>> data array([[0], [1], [2], [3], [4], [5], [6], [7], [8]]) >>> from sklearn.preprocessing import OneHotEncoder >>> ohe = OneHotEncoder() >>> ohe.fit_transform(data).A # sparse matrixを返しやがるのでdenseにして見ている array([[1., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 1., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 1., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 1.]])
注意点として、ndim=1の配列を渡すとエラーになるので、ベクトル風の表現に直して渡してやる必要があります。
>>> ohe.fit_transform(np.arange(10)) # 中略 ValueError: Expected 2D array, got 1D array instead: array=[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]. Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample. >>> ohe.fit_transform(np.arange(10).reshape(-1, 1)).A array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])
ところで、ベクトル風にして渡すということは、こういうことになります。
>>> np.arange(10).reshape(5,2) array([[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]) >>> ohe.fit_transform(np.arange(10).reshape(5,2)).A array([[1., 0., 0., 0., 0., 1., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 1., 0., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 0., 1., 0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0., 1.]])
なるほど、こうなるのか。
文字列でもいけるかな?
>>> week_breakfast = ["パン","ご飯","なし","パン","シリアル","なし","なし"] >>> ohe.fit_transform(np.array(week_breakfast).reshape(-1, 1)) # 中略 ValueError: could not convert string to float: 'パン'
ダメでした。LabelEncoderと併用して数値ラベルにしておく必要があるということだと思います(ドキュメントにもそんな感じのことが書いてある)。
おまけ:CategoricalEncoder
これは開発中のscikit-learn 0.20の機能です。なので、まだ使えません。リリース待ちです(2018年6月現在)。
http://scikit-learn.org/dev/modules/generated/sklearn.preprocessing.CategoricalEncoder.html
いろいろと柔軟に使えるような機能が追加されているようです。リリースされたら、こっちも使ってみましょう(つっても、まだまだ時間かかりそうよねぇ)。
2018年11月15日追記:sklearn 0.20はリリースされましたが、CategoricalEncoderはなくなっちゃったみたいです・・・。残念。