つい最近 scikit-learn に DummyClassifier と DummyRegressor という実装があることを知ったので試してみた。
これらの実装は、説明変数の内容は使わず、主に目的変数の内容を代わりに使って、その名の通りダミーの結果を返す。
特定のデータセットと評価指標を使ったときの、最低ラインの性能を確認するのに便利そう。
使った環境は次の通り。
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.5
BuildVersion: 18F132
$ python -V
Python 3.7.3
下準備
まずは scikit-learn をインストールしておく。
$ pip install scikit-learn
DummyClassifier
DummyClassifier は、その名の通りダミーの分類器となる。
使い方は一般的な scikit-learn の分類器と何ら違いはない。
違いがあるとすれば与えた教師データに含まれる説明変数を学習しないという点。
教師データの目的変数の確率分布を再現する
動作を確認するためのサンプルコードとして以下を用意した。
デフォルトでは、教師データに含まれる目的変数の確率分布を再現するように動作する。
import numpy as np
from sklearn.dummy import DummyClassifier
def main():
clf = DummyClassifier()
X_train = np.arange(6)
y_train = np.array([0, 1, 2, 2, 1, 2])
clf.fit(X_train, y_train)
X_test = np.arange(6, 12)
y_pred = clf.predict(X_test)
y_pred_proba = clf.predict_proba(X_test)
print('Prediction:', y_pred)
print('Prediction (probability):')
print(y_pred_proba)
print('Class probabilities:', clf.class_prior_)
if __name__ == '__main__':
main()
上記を実行してみよう。
教師データとして与えた目的変数は 0
が 1 件、1
が 2 件、2
が 3 件だった。
得られる結果は毎回異なるものの、今回は 0
が 1 件、1
が 1 件、2
が 4 件と、わずかに異なっている。
また、predict_proba()
メソッドから得られる確率は一つが 1.0
で残りが 0.0
となっている。
$ python dummy.py
Prediction: [2 2 1 2 2 0]
Prediction (probability):
[[1. 0. 0.]
[0. 0. 1.]
[0. 0. 1.]
[0. 0. 1.]
[0. 0. 1.]
[0. 0. 1.]]
Class probabilities: [0.16666667 0.33333333 0.5 ]
試しに、もっとたくさんの検証用データを予測させてみよう。
数が多くなれば、大数の法則で教師データの確率分布に近づくはずだ。
import numpy as np
from sklearn.dummy import DummyClassifier
def main():
clf = DummyClassifier()
X_train = np.arange(6)
y_train = np.array([0, 1, 2, 2, 1, 2])
clf.fit(X_train, y_train)
X_test = np.arange(6, 100000)
y_pred = clf.predict(X_test)
values, count = np.unique(y_pred, return_counts=True)
print('Prediction frequency', count / np.sum(count))
print('Class probabilities:', clf.class_prior_)
if __name__ == '__main__':
main()
上記を実行してみる。
今度は理論値にかなり近い結果が得られた。
$ python dummy.py
Prediction frequency [0.16611997 0.33404004 0.49983999]
Class probabilities: [0.16666667 0.33333333 0.5 ]
最頻値を常に返す
DummyClassifier は、返す値を色々とカスタマイズできる。
例えば、最頻値を常に返したいときはインスタンス化するときの strategy
オプションに 'most_frequent'
を指定する。
import numpy as np
from sklearn.dummy import DummyClassifier
def main():
clf = DummyClassifier(strategy='most_frequent')
X_train = np.arange(6)
y_train = np.array([0, 1, 2, 2, 1, 2])
clf.fit(X_train, y_train)
X_test = np.arange(6, 12)
y_pred = clf.predict(X_test)
y_pred_proba = clf.predict_proba(X_test)
print('Prediction:', y_pred)
print('Prediction (probability):')
print(y_pred_proba)
if __name__ == '__main__':
main()
上記を実行してみよう。
たしかに、最頻値である 2
が常に返されるようになっている。
$ python dummy.py
Prediction: [2 2 2 2 2 2]
Prediction (probability):
[[0. 0. 1.]
[0. 0. 1.]
[0. 0. 1.]
[0. 0. 1.]
[0. 0. 1.]
[0. 0. 1.]]
最頻値を常に返す (確率については教師データに準拠する)
'most_frequent'
に近いものの、確率の返し方が異なるのが 'prior'
となる。
こちらでは predict_proba()
メソッドの返す結果が、元の確率分布にもとづいたものになる。
import numpy as np
from sklearn.dummy import DummyClassifier
def main():
clf = DummyClassifier(strategy='prior')
X_train = np.arange(6)
y_train = np.array([0, 1, 2, 2, 1, 2])
clf.fit(X_train, y_train)
X_test = np.arange(6, 12)
y_pred = clf.predict(X_test)
y_pred_proba = clf.predict_proba(X_test)
print('Prediction:', y_pred)
print('Prediction (probability):')
print(y_pred_proba)
if __name__ == '__main__':
main()
上記を実行してみよう。
たしかに predict()
メソッドが最頻値を返す点は変わらないものの、predict_proba()
の結果が変わっている。
$ python dummy.py
Prediction: [2 2 2 2 2 2]
Prediction (probability):
[[0.16666667 0.33333333 0.5 ]
[0.16666667 0.33333333 0.5 ]
[0.16666667 0.33333333 0.5 ]
[0.16666667 0.33333333 0.5 ]
[0.16666667 0.33333333 0.5 ]
[0.16666667 0.33333333 0.5 ]]
指定した固定値を返す
任意の定数を返したいときは 'constant'
を指定する。
以下では例として常に 1
を返している。
import numpy as np
from sklearn.dummy import DummyClassifier
def main():
clf = DummyClassifier(strategy='constant', constant=1)
X_train = np.arange(6)
y_train = np.array([0, 1, 2, 2, 1, 2])
clf.fit(X_train, y_train)
X_test = np.arange(6, 12)
y_pred = clf.predict(X_test)
y_pred_proba = clf.predict_proba(X_test)
print('Prediction:', y_pred)
print('Prediction (probability):')
print(y_pred_proba)
if __name__ == '__main__':
main()
上記を実行してみよう。
たしかに、常に 1
が返っている。
$ python dummy.py
Prediction: [1 1 1 1 1 1]
Prediction (probability):
[[0. 1. 0.]
[0. 1. 0.]
[0. 1. 0.]
[0. 1. 0.]
[0. 1. 0.]
[0. 1. 0.]]
ランダム (一様分布) に返す
また、目的変数の元の確率分布に依存せず、一様分布にしたいときは 'uniform'
を指定する。
import numpy as np
from sklearn.dummy import DummyClassifier
def main():
clf = DummyClassifier(strategy='uniform')
X_train = np.arange(6)
y_train = np.array([0, 1, 2, 2, 1, 2])
clf.fit(X_train, y_train)
X_test = np.arange(6, 12)
y_pred = clf.predict(X_test)
y_pred_proba = clf.predict_proba(X_test)
print('Prediction:', y_pred)
print('Prediction (probability):')
print(y_pred_proba)
if __name__ == '__main__':
main()
上記を実行してみよう。
predict()
の結果は試行回数が少ないので偏ってしまっているが predict_proba()
は全てのクラスが均等な値になっている。
$ python dummy.py
Prediction: [2 2 2 2 0 0]
Prediction (probability):
[[0.33333333 0.33333333 0.33333333]
[0.33333333 0.33333333 0.33333333]
[0.33333333 0.33333333 0.33333333]
[0.33333333 0.33333333 0.33333333]
[0.33333333 0.33333333 0.33333333]
[0.33333333 0.33333333 0.33333333]]
DummyRegressor
同様に回帰問題であれば DummyRegressor を用いる。
平均値を常に返す
DummyRegressor はデフォルトで目的変数の平均値を常に返すようになっている。
import numpy as np
from sklearn.dummy import DummyRegressor
def main():
reg = DummyRegressor()
X_train = np.arange(6)
y_train = np.array([-1.0, 0.0, 1.0, 2.0, 4.0, 8.0])
reg.fit(X_train, y_train)
X_test = np.arange(6, 12)
y_pred = reg.predict(X_test)
print('Prediction', y_pred)
if __name__ == '__main__':
main()
上記を実行してみよう。
$ python dummy.py
Prediction [2.33333333 2.33333333 2.33333333 2.33333333 2.33333333 2.33333333]
中央値を常に返す
DummyRegressor も返す値をカスタマイズできる。
例えば中央値を返したいのであれば 'median'
を指定する。
import numpy as np
from sklearn.dummy import DummyRegressor
def main():
reg = DummyRegressor(strategy='median')
X_train = np.arange(6)
y_train = np.array([-1.0, 0.0, 1.0, 2.0, 4.0, 8.0])
reg.fit(X_train, y_train)
X_test = np.arange(6, 12)
y_pred = reg.predict(X_test)
print('Prediction', y_pred)
if __name__ == '__main__':
main()
上記を実行してみよう。
ちゃんと中央値を返している。
$ python dummy.py
Prediction [1.5 1.5 1.5 1.5 1.5 1.5]
指定した値を常に返す
特定の値を返したいときは 'constant'
を指定する。
以下では例として -999
を返している。
import numpy as np
from sklearn.dummy import DummyRegressor
def main():
reg = DummyRegressor(strategy='constant', constant=-999)
X_train = np.arange(6)
y_train = np.array([-1.0, 0.0, 1.0, 2.0, 4.0, 8.0])
reg.fit(X_train, y_train)
X_test = np.arange(6, 12)
y_pred = reg.predict(X_test)
print('Prediction', y_pred)
if __name__ == '__main__':
main()
上記を実行してみよう。
ちゃんと指定した値を返している。
$ python dummy.py
Prediction [-999 -999 -999 -999 -999 -999]
まとめ
機械学習において最低ラインの性能というのは使うデータセットと評価指標に依存する。
得られた結果がどれくらい良いものなのかを検討する上で、最低ラインの性能は確認しておきたいもの。
そんなとき Dummy{Classifier,Regressor}
を使うと、既存のデータパイプラインのコードを流用して確認できるので便利そうだ。