つい最近 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 の分類器と何ら違いはない。 違いがあるとすれば与えた教師データに含まれる説明変数を学習しないという点。
教師データの目的変数の確率分布を再現する
動作を確認するためのサンプルコードとして以下を用意した。 デフォルトでは、教師データに含まれる目的変数の確率分布を再現するように動作する。
#!/usr/bin/env python # -*- coding: utf-8 -*- import numpy as np from sklearn.dummy import DummyClassifier def main(): # ダミーの分類器 (デフォルトの strategy は 'stratified') 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 ]
試しに、もっとたくさんの検証用データを予測させてみよう。 数が多くなれば、大数の法則で教師データの確率分布に近づくはずだ。
#!/usr/bin/env python # -*- coding: utf-8 -*- 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'
を指定する。
#!/usr/bin/env python # -*- coding: utf-8 -*- 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()
メソッドの返す結果が、元の確率分布にもとづいたものになる。
#!/usr/bin/env python # -*- coding: utf-8 -*- 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
を返している。
#!/usr/bin/env python # -*- coding: utf-8 -*- 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'
を指定する。
#!/usr/bin/env python # -*- coding: utf-8 -*- 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 はデフォルトで目的変数の平均値を常に返すようになっている。
#!/usr/bin/env python # -*- coding: utf-8 -*- import numpy as np from sklearn.dummy import DummyRegressor def main(): # ダミーの回帰 (デフォルトの strategy は 'mean' なので平均を返す) 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'
を指定する。
#!/usr/bin/env python # -*- coding: utf-8 -*- 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
を返している。
#!/usr/bin/env python # -*- coding: utf-8 -*- 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}
を使うと、既存のデータパイプラインのコードを流用して確認できるので便利そうだ。
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログ (1件) を見る