まだまだKaggleは続きます!
前回ようやく結果が出せましたが、なんだか結果に違和感...精度が高すぎる!単純なモデルなのに!
ということで何かが間違っているのですが
みなさんはわかりましたか?
正解は...
説明変数の中に入れてはいけない変数があったからでしたー^^;;;
Leakageとは
これはLeakageという問題で、「漏れ」という意味です。この問題は比較的よく起こる問題だそうです。
その変数は正解に直接関連しているのに、訓練データに入っている(漏れている)ため
モデルの精度は当たり前に良くなってしまうのです。
今回の事例で言うと、
クラウドファンディングの各プロジェクトが成功するかを予測するのですが、
・pledged:集まった資金
・usd pledged: 集まった資金の米ドル換算
・backer:集まった支援者
これらはプロジェクト立上げ時には知りえない情報なので
新たに立ち上げられたプロジェクトにはこれらの変数はありません。
これらの変数を訓練データに入れたら、ヒントどころか答えを教えているようなものです!
コード修正
それでは以上の変数を削除して、再学習した結果を表示します。精度が下がりました!悲しいですがこれが現実です...
精度を上げるには
機械学習で最も困難なのは、基本が出来上がったところから精度を上げていくことかもしれません。
ここからが戦いの始まりです!!今までも十分戦ったけど...
まず精度を上げるにはどうしたらよいのでしょうか?
Google先生に問い合わせたところ、以下のような回答でした。
・トレーニングデータの量を増やす
・特徴選択をする
・アンサンブル学習をする
などなど。
今回はこの中から特徴選択をしてみたいと思います。
特徴選択
特徴選択とは?説明変数の中から正解データにより強い関連があるものを取捨選択することで
予測制度の向上を図ります。
学習にあんまり関係ない変数は無くしちゃいましょーってことです。
特徴選択には主に3つあります。
今回は精度重視でラッパー法を使って特徴選択します。
コード変更
では実際にコードを変更していきます。コードは前処理が終わったところから変えていきます。
まずは必要なライブラリを取り込みます。
from sklearn.feature_selection import RFECV
estimatorにモデルをセットします。前回から変わらずロジスティック回帰です。
estimator = SGDClassifier(loss='log', penalty='none', fit_intercept=True)
rfecvにラッパー法のモデルをセットします。
cvというのは学習と特徴選択を繰り返す回数です。
scoringは評価指標で回帰はneg_mean_absolute_error、分類はaccurasyを指定します。
rfecv = RFECV(estimator, cv=10, scoring='accuracy')
モデルの準備ができたら、
今までと同様にyに正解である'state'、Xに'state'以外の変数を代入します。
そして.fitで特徴選択を実行します。
y = df["state"].values X = df.drop("state", axis=1).values rfecv.fit(X, y)
計算が終了したら、特徴の重要度ランキングを表示します。
1が最も重要な特徴です。
print('Feature ranking: \n{}'.format(rfecv.ranking_))
下記のようにランキングが表示されました。
1が6つあることがわかります。
次に特徴数とスコアの変化をグラフに表示します。
特徴(=説明変数)の数がいくつの時に正答率(Accuracy)が高いかを確認します。
回帰の場合は評価指標が負のMAEなので、ゼロに近いほど汎化誤差は小くなります。
plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_) plt.show()
グラフを見てみると特徴の数が6で最大になっていることがわかります。
以上のことから、ランキングで1以外の変数を削除していきます。
.supportはランキング1のものはTrue、それ以外はFalseを返します。
それに~を付けるとその逆が返されます。TrueはFalseに、FalseがTrueになります。
それをremove_idxという変数に入れて、削除する変数のindexを抽出します。
remove_idx = ~rfecv.support_
説明変数からcolumns(列名)が削除されるindexであるものを
remove_featureに代入します。
remove_feature = df_crdf.drop("state", axis=1).columns[remove_idx]
ようやく削除する変数名を抽出できたので、
.dropで削除を実行し、残った変数をselected_train_dataに代入します。
残った変数も表示させます。
selected_train_data = train_data.drop(remove_feature, axis=1)
selected_train_data
これらの変数が選択されました。
意外にもmain_categoryの中のいくつかのカテゴリーが変数に選択され
これで良い結果が出せるのか不安です..
選択した変数で学習を実行させます。
Xに選択された変数を代入します。
実行の方法は前回と同様にホールドアウト法でデータを分割後、
それぞれ標準化を行ってから、訓練データでの学習を実行します。
X = selected_train_data test_size = 0.3 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=1234) stdsc = StandardScaler() X_train = stdsc.fit_transform(X_train) X_test = stdsc.transform(X_test) clf = SGDClassifier(loss='log', penalty='none', fit_intercept=True) clf.fit(X_train, y_train)
学習が終わったら前回同様、対数尤度・正答率・適合率・再現率・F1値を表示します。
コードに変更は無いので省略します。
結果は・・・
んー少し!良くなりましたね^^;
今回の特徴選択では、特徴選択と評価を繰り返す回数を、変数CVに指定することができました。
そこで、cv=10をcv=20に変更すると以下のようになりました。
回数を上げると、結果が少し良くなりました。
精度を上げるには地道な作業が必要なようです...
次回は各説明変数が、どのように目的変数に関わっているか、
どうして今回のような特徴が選択されたのかを解明したいと思います(できれば)!