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
- 組み込みの sorted() https://github.com/scikit-learn/scikit-learn/blob/a2ebb8cfd2d126ad8e6fb36e0bdadba7de8fcd9f/sklearn/utils/multiclass.py#L105
もっと調べた
なんと、バイナリクラスの場合、逆転させていた。
liblinear 内の学習では、0 以上かどうかで判定している。
では、この prob_col->y
はいつどこで決められているのだろう。
prob->y
にて。
Y
→ y_ind
y
これが入力。
よって、次の fit_transform
がポイントになるが、
ためしに、[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の方の重みである。