【sklearn】LabelEncoderの使い方を丁寧に
はじめに
本記事ではsklearn.preprocessing.LabelEncoder()について丁寧に説明します.
公式ドキュメント:
LabelEncoderの役割
LabelEncoder()
は,文字列や数値で表されたラベルを,0~(ラベル種類数-1)
までの数値に変換してくれるものです.機械学習で分類系のタスクを扱う場合,正解のラベルが文字列で表されることはよくあります.このようなとき,LabelEncoder()
を使うと簡単に数値に変換できるという感じです.
LabelEncoderの基本的な入出力
エンコーダを想定した入出力です.
- 入力
入力は,各要素がラベルであるような一次元リストです.データ型はpythonの生のリストはもちろん,numpyの'numpy.ndarray'
,pandasのpandas.core.series.Series
も受け付けます.リストの各要素は文字列でも良いですし,数値でも良いです.
例:['positive', 'negative', 'positive']
- 出力
出力は,入力の各ラベルが0~(ラベル種類数-1)
の数値に変換された一次元リストです.
例:[0, 1, 0]
例では,positive
と0
,negative
と1
が対応していることが分かります.以降,本記事では入力側をラベル,出力側をラベルIDと呼ぶことにします.
LabelEncoderの宣言
宣言は簡単です.特にオプションも必要ありません.
from sklearn import preprocessing le = preprocessing.LabelEncoder()
fit()
まずは,ラベルとラベルIDの対応づけを行います.positiveは0にしよう,みたいなことを決めるのです.これはle.fit(ラベルの一次元リスト)
で行います.
from sklearn import preprocessing le = preprocessing.LabelEncoder() labels = ['positive', 'negative', 'positive'] le.fit(labels)
transform() (ラベル→ラベルID)
ラベルとラベルIDの対応づけができれば,それに従って変換することができます.これはtransform(ラベルの一次元リスト)
で行います.fitはle.fit()
を書くだけですが,transformはhoge = le.transform()
のように返り値を保存する必要があります.
from sklearn import preprocessing le = preprocessing.LabelEncoder() labels = ['positive', 'negative', 'positive'] le.fit(labels) labels_id = le.transform(labels) print(labels_id) # [1 0 1]
これで変換が完了しました.
fit_transform()
fit()
とtransform()
を一気に行う場合,fit_transform()
を使うと楽です.
入力がラベルの一次元リスト,出力がラベルIDの一次元リストになっています.
from sklearn import preprocessing le = preprocessing.LabelEncoder() labels = ['positive', 'negative', 'positive'] labels_id = le.fit_transform(labels) print(labels_id) # [1 0 1]
inverse_transform() (ラベルID→ラベル)
transformがエンコードだとすると,これはデコードする処理になります.
入力がラベルIDの一次元リスト,出力がラベルのリストです.
あくまでもエンコードができないとデコードもできないため,必ずfit()
した後に行います.
from sklearn import preprocessing le = preprocessing.LabelEncoder() labels = ['positive', 'negative', 'positive'] # とりあえずfitしてから le.fit(labels) ids = [1, 1, 0] # デコード decoded_labels = le.inverse_transform(ids) print(ids, '->', decoded_labels) # [1, 1, 0] -> ['positive' 'positive' 'negative']
classes_(どのラベルがどのIDなのかを取得)
le.classes_
で, fit()
によって各ラベルがどのラベルIDと対応づけられたのかを取得できます.
le.classes_
は一次元リストになっていて,各要素について,値がラベル,その添字がラベルIDと解釈できます.例えば['negative' 'positive']
という一次元リストであれば,negative
の添字は0
なので,negative
と0
が対応していることが分かります.
from sklearn import preprocessing le = preprocessing.LabelEncoder() labels = ['positive', 'negative', 'positive'] le.fit(labels) print(le.classes_) # ['negative' 'positive']
使い所としては,評価系のライブラリを使った時に,オプションとしてラベル名を渡すような場面が考えられます.例えば,sklearnのclassification_report
のtarget_names=
引数みたいなものです.
2次元以上のラベル列をエンコードする時
こういう場合があるか分かりませんが,2次元リストの形式で保存されたラベル列をIDに変換したいときの話です.これは間違いの方法ですが,とりあえず,for文で一つずつ処理することを考えます.
# !!! バグが発生しうる例 !!! from sklearn import preprocessing le = preprocessing.LabelEncoder() labels_list = [['positive', 'negative'], ['negative', 'positive']] ids_list = [le.fit_transform(labels).tolist() for labels in labels_list] print(ids_list) """ [[1, 0], [0, 1]] """
ただし,上の例は偶然うまくいっているものの,少し安直で,バグを生みます.というのは,変換をfit_transform()
で行なっているため,変換するたびにfit()
もされてしまいます.これにより,ラベルとIDの対応づけが変換のたびに更新されてしまいます.
バグを生む例を作るとこうなります.
# !!! バグがある例 !!! from sklearn import preprocessing le = preprocessing.LabelEncoder() labels_list = [['a', 'b'], ['b', 'c']] ids_list = [le.fit_transform(labels).tolist() for labels in labels_list] print(ids_list) """ [[0, 1], [0, 1]] ('b'が0と1に変換されているし,'b'と'c'が1に変換されている.本当は [[0, 1], [1, 2]] であるはず) """
というわけで,2次元以上のラベル列を変換する場合,fit()
は全てのラベルが含まれるようなリストで一度だけ行いましょう.どのようなラベルが存在するかは事前に分かるはずなので,そのようなリストは準備できるはずです.
from sklearn import preprocessing le = preprocessing.LabelEncoder() # 全てのラベルを並べてfit()だけしておく all_labels = ['a', 'b', 'c'] le.fit(all_labels) labels_list = [['a', 'b'], ['b', 'c']] # 変換処理はfit_transform()ではなくて,transform()で ids_list = [le.transform(labels).tolist() for labels in labels_list] print(ids_list) """ [[0, 1], [1, 2]] """