CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: scikit-learn の LabelEncoder を説明変数の変換に使うのは誤り

scikit-learn の LabelEncoder を説明変数の変換に使っている例はたくさん見つかる。 しかし、実は本来 LabelEncoder は目的変数の変換に使うことが想定されていることは、あまり知られていない。 これは公式のドキュメントで確認できる。

scikit-learn.org

上記から一部を引用する。

This transformer should be used to encode target values, i.e. y, and not the input X.

このように、入力として想定されているのが本来は目的変数であることが読み取れる。 ようするに Iris データセットでいう setosa とか versicolor を 0 とか 1 に変換するのが本来の目的ということ。

メソッドの引数名を見ても X ではなく y になっている。 なので Pipeline と併用した場合には X の内容は渡ってこない。

scikit-learn.org

説明変数の変換には、代わりに OrdinalEncoder を使うのが良い。

scikit-learn.org

OrdinalEncoder を使うと、未知の値がテストデータにあったときに指定した値に変換できる。 この機能は LabelEncoder には含まれていない。 ただし、デフォルトでは LabelEncoder と同じように未知の値に遭遇したときは例外を上げるようになっている。 そのため、明示的に handle_unknown パラメータと unknown_value を指定する。 サンプルコードを以下に示す。

import numpy as np
from sklearn.preprocessing import OrdinalEncoder


def main():
    # 説明変数を仮定しているため 2D 配列の必要がある
    train = np.array(["apple", "banana", "cherry"]).reshape(-1, 1)

    # 未知の値は -1 に変換する
    # デフォルトでは例外になるので LabelEncoder と変わらない
    ordinal_encoder = OrdinalEncoder(
        handle_unknown="use_encoded_value",
        unknown_value=-1,
    )
    ordinal_encoder.fit(train)

    train_transformed = ordinal_encoder.transform(train)
    print(train_transformed)

    # 未知の値は -1 に変換される
    test = np.array(["dates", "fig"]).reshape(-1, 1)
    test_transformed = ordinal_encoder.transform(test)
    print(test_transformed)


if __name__ == "__main__":
    main()

上記を実行してみよう。

$ python example.py
[[0.]
 [1.]
 [2.]]
[[-1.]
 [-1.]]

未知のデータが含まれた配列が例外にならず -1 に変換できていることが確認できる。

いじょう。