この記事は、タイトルにある通り、
「桁の乱数を個作るとき、人が作った乱数ととコンピュータが生成した乱数を見分けることは可能か」
を深夜テンションで思いつき、実際にやってみた結果を述べる記事です。
ちなみに、vol.1はこちら、vol.2はこちら
vol.1の振り返り
- ことの始まり
- 環境、条件の確認
- データの作成
- 分類1回目
- 分類2回目~データ増加~
vol.2の振り返り
- 分類3回目~新しい特徴量を考える~
環境
Windows 10 Python: 3.7.3 jupyter lab: 0.35.4 pandas: 0.25.3 numpy: 1.17.0 scikit-learn: 0.23.1 matplotlib: 3.1.1 Optuna: 1.5.0
条件
- 乱数の範囲は、データの個数はそれぞれ1000個
- 人側のサンプルは私のみ
- コンピュータ側はプログラムで作成
分類4回目~モデルのハイパーパラメータを最適な値に設定しよう~
分類2回目、3回目の方法に加え、モデルのハイパーパラメータを最適な値に設定することでモデルの性能を高めたいと思います。と、その前にハイパーパラメータとは何かについて話していませんでしたね。簡単に触れたいと思います。
ハイパーパラメータとは?
ハイパーパラメータとは、機械学習アルゴリズムの挙動を設定するパラメータのことです。通常、学習器は学習中にパラメータを更新していきますが、このハイパーパラメータというものに関しては学習で求めることが出来ません。そのためこのハイパーパラメータは学習前に我々が手動で設定する必要があります。ハイパーパラメータの値を調整することをハイパーパラメータチューニングと言います。
ランダムフォレストで言えば、n_estimatorsがハイパーパラメータにあたります。もちろん、ランダムフォレストのハイパーパラメータはn_estimatorsだけではなく、criterionや、max_depthなどもあります。ランダムフォレストがもつハイパーパラメータやその意味はこちらに詳しく書かれています。その他モデルのハイパーパラメータに関しては各自調べてみると良いでしょう。
ハイパーパラメータチューニングによって学習器の性能を上げることも可能ですが、反対に下がってしまうこともあります。また、ハイパーパラメータチューニングは専門家の経験則などを頼りに行うところもあり、複数のハイパーパラメータをチューニングするのは機械学習初心者からすれば非常に難しいです。
そのため、ハイパーパラメータを自動でチューニングする手法がいくつか提案されています。今回はOptunaというハイパーパラメータチューニングを自動で行ってくれるモジュールを使用します。
Optunaを使用したハイパーパラメータチューニング
今回はランダムフォレストのハイパーパラメータに対し、Optunaを使用してチューニングを行い、モデルの性能を上げたいと思います。
Optunaの基本的な使い方に関しての記事はこちら
Optunaでハイパーパラメータの自動チューニング -Pytorch Lightning編-
本来であればRandomForestClassifierに様々なハイパーパラメータがあるのですが、今回チューニングするハイパーパラメータはn_estimatorsとmax_depthとします。また、n_estimatorsのパラメータの探索範囲は50, 100, 150, 200、max_depthのパラメータの探索範囲は10, 20, 30, 40, Noneとしています。
下のようにコードを書いて実行すれば後は自動でハイパーパラメータチューニングを行い、最適なハイパーパラメータを出力してくれます。Optunaに関してあまり詳しい使い方は分かっていないので、各自でお調べください。
from sklearn.ensemble import RandomForestClassifier import optuna def objective(trial): #n_estimators estimators = trial.suggest_categorical("estimators", [50, 100, 150, 200]) #max_depth depth = trial.suggest_categorical("max_depth", [10, 20, 30, 40, None]) rfc = RandomForestClassifier(n_estimators = estimators, max_depth = depth) rfc.fit(X_train, Y_train) Y_pred = rfc.predict(X_test) return rfc.score(X_test, Y_test) study = optuna.create_study() study.optimize(objective, n_trials=100) print(study.best_params) print(study.best_value) print(study.best_trial)
出力結果(省略バージョン)は以下のように出ました。ハイパーパラメータはn_estimatorsが50、max_depthが30の時に学習器の性能が最も高くなるようです。
ちなみに、下の0.7675という値はobjective関数のreturnに書かれているrfc.score(X_test, Y_test)
の値です。
{'n_estimators': 100, 'max_depth': None} 0.7675
出力結果をもとにハイパーパラメータの値を設定して学習させてみることにします。
rfc = RandomForestClassifier(n_estimators = 50, max_depth = 30) rfc.fit(X_train, Y_train) Y_pred = rfc.predict(X_test) print('confusion matrix = \n', confusion_matrix(y_true=Y_test, y_pred=Y_pred))#混合行列 print('accuracy = ', accuracy_score(y_true=Y_test, y_pred=Y_pred))#正解率 print('precision = ', precision_score(y_true=Y_test, y_pred=Y_pred))#適合率 print('recall = ', recall_score(y_true=Y_test, y_pred=Y_pred))#再現率 print('f1 score = ', f1_score(y_true=Y_test, y_pred=Y_pred))#F値
結果は以下のようになりました。
confusion matrix = [[163 37] [ 56 144]] accuracy = 0.7675 precision = 0.7955801104972375 recall = 0.72 f1 score = 0.7559055118110236
分類3回目の結果はこちら
confusion matrix = [[171 29] [ 54 146]] accuracy = 0.7925 precision = 0.8342857142857143 recall = 0.73 f1 score = 0.7786666666666667
...なんか下がっちゃいましたね。まぁ、本来なら学習を行って平均を計算してそれを比較するべきなので、高々1回しか学習していない結果を比較しても意味がないように思います。
とはいえ、Optunaを使って自動でハイパーパラメータチューニングを行うことが出来ましたので、これから学習器のハイパーパラメータチューニングを行う人はOptunaを使ってみるといいでしょう。結構早く結果を出してくれるのでおススメです。
まとめ
今回は深夜テンションから始まった「桁の乱数を個作るとき、人が作った乱数ととコンピュータが生成した乱数を見分けることは可能か」ということを調査してきました。結果としては、
7割後半程度の性能で私が作った乱数かコンピュータが作った乱数かを見分けることが出来る
となりました。個人的にはもっと高い性能で見分けられるんじゃないかと思っていましたが、深夜テンションで考えた条件が曖昧だったことなどもあり、割と妥当な結果だったのではないかなと思っています。もし、性能を上げるとすればランダムフォレスト以外の学習モデルの使用や、他の特徴量を考えることになるかと思います。
また、そもそものデータを乱数ではなくaからzまでの文字列から長さ10の文字列を作るというものだったらまた違いが出てきたりしたのかなとも思います。このあたりは深夜テンションで考えるべきではなかったですね。しっかりと考えるべきでした。
とはいえ、新しい特徴量を考えたり、Optunaを使ってハイパーパラメータチューニングの自動化を行ったりと個人的には非常に面白く、また勉強にもなりました。皆さんもすでに公開されているデータを用いて機械学習に触れていただければと思います。