前回はとりあえずベースラインの分類を行い、F1値にして0.7くらいの性能を得た。
ここで自然言語処理的なアプローチで手法の改良に進むのもありだと思うが、とりあえずmin_dfをパラメタチューニングしてみるか、という方向に傾いている。前回は恣意的に決めたので、色々調整する余地はあると思う。max_dfは前回の結果で影響が少ないことがわかっているので触らない。
前回のコードを使い回せばできる。クソ真面目にグリッドサーチとかやる気概はないので、あくまでも大雑把にやる。傾向がざっくりわかれば良いので、10回やって平均を取るとかいう時間のかかることもやらない。
ついでにRandomForestのn_estimatorsを1000まで増やし、性能向上を狙う。
# coding: UTF-8 import numpy as np from sklearn.datasets import fetch_20newsgroups from sklearn.ensemble import RandomForestClassifier as RFC from sklearn.feature_extraction.text import CountVectorizer as CV from sklearn.model_selection import StratifiedKFold from sklearn.metrics import precision_recall_fscore_support as prf def test_func(min_df, max_df=0.5): news20 = fetch_20newsgroups() cv = CV(min_df=min_df, max_df=max_df) matrix = cv.fit_transform(news20.data) rfc = RFC(n_estimators=1000, n_jobs=-1) scores = [] for i in range(1): trues = [] preds = [] for train_index, test_index in StratifiedKFold().split(matrix, news20.target): rfc.fit(matrix[train_index], news20.target[train_index]) trues.append(news20.target[test_index]) preds.append(rfc.predict(matrix[test_index])) scores.append(prf(np.hstack(trues), np.hstack(preds), average="macro")[:3]) score_mean = np.array(scores).mean(axis=0) print("p:{0:.6f} r:{1:.6f} f1:{2:.6f}".format(score_mean[0], score_mean[1], score_mean[2])) def main(): for min_df in [0.005, 0.01, 0.02, 0.03]: print("min:{0} max:{1}".format(min_df, 0.5)) test_func(min_df) if __name__ == "__main__": main()
走らせるとシェルにゆっくり結果が出てくる。PCのスペックにもよるが時間がかかるので、気長に待つ。
そして出てきた結果がこちら。
min:0.005 max:0.5 p:0.821038 r:0.807844 f1:0.810116 min:0.01 max:0.5 p:0.789673 r:0.775514 f1:0.777242 min:0.02 max:0.5 p:0.743468 r:0.726968 f1:0.728776 min:0.03 max:0.5 p:0.684627 r:0.663533 f1:0.665255
本当に0.1以上変わるとは、笑える。そしてmin_dfは小さければ小さいほど有利という結論が得られる訳だが、これは計算コストがかさむことを意味するのでとても良くない。ちなみに0.005で4000次元くらいだった。
こうなるとNLP的なアプローチに行くより先に、ちゃんと特徴選択をして計算コストの削減と性能向上を両立させるべきかな、という気がするので、とりあえずそっちの方向で考える。