中野智文のブログ

データ・マエショリストのメモ

scikit learn の 確率推定のクラスの順序はソートされている。※ただしバイナリクラスの重みは…

背景

liblinear libsvm の重みや、確率推定の配列は、訓練データのクラスラベルの出現順で、決まるという恐ろしい仕様。 出現順というのは、1行目の事例のほうが2行目の事例より前、という出現順。 もちろん学習後、その順序が参照できるように、モデルの出力ファイルにはその出力クラスラベルの順序が書かれてるのだが、 それを読み取るのが面倒だったりするので、学習前に訓練データをクラスラベルでソートしたり tips があったりする[要出典]。

では liblinear libsvm を使っている、scikit learn はどうか?

調査

次のドキュメントを読むと、 sklearn.linear_model.LogisticRegression — scikit-learn 0.19.1 documentation self.classes_ にあるらしい。

そして、 - numpy の unique() https://github.com/scikit-learn/scikit-learn/blob/a2ebb8cfd2d126ad8e6fb36e0bdadba7de8fcd9f/sklearn/preprocessing/label.py#L96

もっと調べた

なんと、バイナリクラスの場合、逆転させていた。

https://github.com/scikit-learn/scikit-learn/blob/ac1b04875331fc291a437025a18ddfefd4051d7c/sklearn/linear_model/base.py#L343-L344

liblinear 内の学習では、0 以上かどうかで判定している。

https://github.com/scikit-learn/scikit-learn/blob/ac1b04875331fc291a437025a18ddfefd4051d7c/sklearn/svm/src/liblinear/linear.cpp#L1760-L1763

では、この prob_col->y はいつどこで決められているのだろう。

https://github.com/scikit-learn/scikit-learn/blob/ac1b04875331fc291a437025a18ddfefd4051d7c/sklearn/svm/src/liblinear/linear.cpp#L2094-L2095

prob->y にて。

https://github.com/scikit-learn/scikit-learn/blob/ac1b04875331fc291a437025a18ddfefd4051d7c/sklearn/svm/src/liblinear/liblinear_helper.c#L141

Yy_ind

https://github.com/scikit-learn/scikit-learn/blob/ac1b04875331fc291a437025a18ddfefd4051d7c/sklearn/svm/base.py#L847-L848

y これが入力。

よって、次の fit_transform がポイントになるが、

https://github.com/scikit-learn/scikit-learn/blob/a2ebb8cfd2d126ad8e6fb36e0bdadba7de8fcd9f/sklearn/preprocessing/label.py#L111-L112

ためしに、[2, 2, 0, 0, 2]unique で呼び出してみた。

>>> import numpy as np
>>> np.unique([2, 2, 0, 0, 2], return_inverse=True)
(array([0, 2]), array([1, 1, 0, 0, 1]))

すなわち、二値(バイナリ)の場合は後者のラベルが、prob_col->y で0以上となることから、後者の重みを学習していることが分かる。

結論

sklearn の係数重みの出力順は、ラベルのソート順(昇順)になっている。

ただし、バイナリクラスの [0, 1] の重みを取ってくる場合は、coef_[0] や、intercept_[0] を取ってくるとラベルが1の方の重みである。