前提・実現したいこと
学習データでの精度がいいのに、未知データに対する予測が悪い場合の対策方法が知りたいです。
何をしているのか
現在、練習のためSIGNATEの練習問題(ボットの判別:https://signate.jp/competitions/124/data)
を解いています。なお、不均衡データです。
目標値がF1-Scoreなのですが、学習データでの精度がいいのにも関わらず、未知データに対して精度が出ないと言うことが起こってしまっています。
該当のソースコード
色々試しましたので、最後に試した場合を記述します。
(色々手探りで1週間ほどやっていたので、最終がこれです。一番良かったのは、xgBoostingでやった場合でしたが、精度が上がらなかったので、kerasに変えて再挑戦しました。)
return の値は、3がMAXになるようにしています。
#コード全容(追記部分)
###データの準備
python
1 2import numpy as np 3import pandas as pd 4from pandas import Series, DataFrame 5import sklearn 6from sklearn.model_selection import train_test_split 7import tensorflow as tf 8from tensorflow import keras 9import pathlib 10from keras import optimizers 11from tensorflow.keras import layers 12from sklearn import datasets 13from keras.models import Sequential 14from keras.layers.core import Dense, Activation 15from bayes_opt import BayesianOptimization 16import pandas as pd 17 18test = pd.read_csv("/content/drive/MyDrive/competition/ツイッターのボット/test.tsv",index_col="id",sep='\t') 19train = pd.read_csv("/content/drive/MyDrive/competition/ツイッターのボット/train.tsv",index_col="id",sep='\t')
###ダミー変数化
python
1 2#GetDummiesで数値をダミー変数化 3train = pd.get_dummies(train, columns=['default_profile', 'default_profile_image',"geo_enabled"]) 4##互いに相関が高いものを排除 5train = train.drop(columns=["default_profile_0","default_profile_image_0","geo_enabled_0"]) 6 7test = pd.get_dummies(test, columns=['default_profile', 'default_profile_image',"geo_enabled"]) 8##互いに相関が高いものを排除 9test = test.drop(columns=["default_profile_0","default_profile_image_0","geo_enabled_0"])
###学習データを教師データと、学習データに分類
python
1 2train_ = train.drop(columns="bot") 3test_ = train["bot"]
###正則化
python
1def normalization(x,y): 2 return (x - y['mean']) / y['std'] 3 4#学習データに対して 5train_stats = train_.describe() 6train_stats_T = train_stats.transpose() 7normed_train_X = normalization(train_,train_stats_T) 8 9#テストデータに対して 10test_stats = test.describe() 11test_stats_T = test_stats.transpose() 12normed_test = normalization(test,test_stats_T) 13 14normed_train = pd.concat([normed_train_X,test_],axis=1)
###アンダーサンプリング
python
1test_df=pd.DataFrame(test_) 2 3# Class count 4count_class_0, count_class_1 = normed_train["bot"].value_counts() 5#1345 243 6 7# Divide by class 8df_class_0 = normed_train[normed_train['bot'] == 0] 9df_class_1 = normed_train[normed_train['bot'] == 1] 10 11#ここで、一気にアンダー化する。 12df_class_0_under = df_class_0.sample(count_class_1) 13 14df_test_under = pd.concat([df_class_0_under, df_class_1], axis=0) 15 16print('Random under-sampling:') 17print(df_test_under["bot"].value_counts()) 18 19train_under_train=df_test_under.drop(columns="bot") 20train_under_test=df_test_under["bot"]
###オーバーサンプリングの場合
python
1!pip install imblearn 2from imblearn.over_sampling import SMOTE 3sm = SMOTE() 4x_resampled, y_resampled = sm.fit_resample(normed_train_X, test_)
###学習データと、教師データ、評価データに分類
python
1#normed_train_X test_は、普通の正則化しただけのデータ 2#train_under_train、train_under_testは、アンダーサンプリング 3#x_resampled,y_resampledは、オーバーサンプリングの場合のデータ 4#上記のいずれかを使う 5 6from sklearn.model_selection import train_test_split 7x_train, x_test, y_train, y_test = train_test_split(normed_train_X, test_, test_size = 0.2,random_state=0,stratify=pd.DataFrame(test_).bot) 8 9x_train, x_valid, y_train, y_valid = train_test_split(x_train, y_train, test_size = 0.2,random_state=0,stratify=pd.DataFrame(y_train).bot)
###ベイズ最適化(optunaから修正)を使用して学習
python
1 2#空のレイヤー作成 3df = pd.DataFrame(index=[]) 4 5from sklearn.model_selection import StratifiedKFold 6from sklearn.metrics import f1_score 7 8 9f1_list=[] 10score_valid_list =[] 11score_test_list =[] 12score_train_list =[] 13score_list =[] 14 15N_list=[] 16batch_size_list=[] 17lr_list=[] 18layer_list=[] 19ur_list=[] 20target_list=[] 21 22def buildModel(lr, batch_size,N,layer): 23 24 model = Sequential() 25 model.add(Dense(10, activation="relu", input_shape=[len(x_train.keys(),)])) 26 for i in range(int(layer)): 27 model.add(Dense(3, activation="relu")) 28 29 model.add(Dense(1,activation="sigmoid")) 30 31 optimizer = optimizers.Adam(lr) 32 33 model.compile(loss='binary_crossentropy', optimizer=optimizer,metrics=["accuracy"]) 34 35 model.fit(x_train, y_train,epochs=int(N),batch_size=int(batch_size)) 36 37 #テストデータで精度を確認 38 for i in range(10): 39 score_valid = f1_score(model.predict(x_valid)>i*0.1, y_valid) 40 score_test = f1_score(model.predict(x_test)>i*0.1, y_test) 41 score_train= f1_score(model.predict(x_train)>i*0.1, y_train) 42 43 print("------------------------------") 44 print("score_train",score_train,"score_valid:",score_valid,"score_test",score_test) 45 46 47 48 score = score_valid+score_test+score_train 49 if(score!=0): 50 score_train_list.append(score_train) 51 score_valid_list.append(score_valid) 52 score_test_list.append(score_test) 53 score_list.append(score) 54 N_list.append(N) 55 batch_size_list.append(batch_size) 56 lr_list.append(lr) 57 layer_list.append(layer) 58 ur_list.append(i*0.1) 59 60 return score 61 62def bayesOpt(): 63 pbounds = { 64 'batch_size' : (10,100), 65 'lr' : (0.0001, 0.01), 66 "N":(50, 150), 67 "layer":(0,8) 68 } 69 optimizer = BayesianOptimization(f=buildModel, pbounds=pbounds) 70 optimizer.maximize(init_points=5, n_iter=100, acq='ucb') 71 return optimizer 72 73 74study = bayesOpt()
###ここでデータフレームに、lr、layer_listなど、入れていつでも観れるようにする。
python
1val_train_matchlist =pd.Series(score_valid_list).round(1)==pd.Series(score_train_list).round(1) 2test_val_matchlist =pd.Series(score_test_list).round(1)==pd.Series(score_valid_list).round(1) 3#val_train_matchlist =(pd.Series(score_valid_list)-pd.Series(score_train_list)).abs() 4#test_val_matchlist =(pd.Series(score_test_list)-pd.Series(score_valid_list)).abs() 5 6 7df["score"]=pd.Series(score_list) 8df["score_train"]=pd.Series(score_train_list) 9df["score_valid"]=pd.Series(score_valid_list) 10df["score_test"]=pd.Series(score_test_list) 11df["unoverfitting_val_train"]=val_train_matchlist 12df["unoverfitting_test_val"]=test_val_matchlist 13 14df["unoverfitting"]=val_train_matchlist==test_val_matchlist 15#df["overfitting"]=(val_train_matchlist+test_val_matchlist)/2 16 17df["batch_size"]=pd.Series(batch_size_list) 18df["N"]=pd.Series(N_list) 19df["layer"]=pd.Series(layer_list) 20df["ur"]=pd.Series(ur_list) 21df["lr_list"]=pd.Series(lr_list)
###上記で、入れたものデータフレームを視覚化
python
1pd.set_option('display.max_rows', 1600) 2Overfitting_check=df[df["unoverfitting"]==True].sort_values("score",ascending=False) 3Overfitting_check[Overfitting_check["unoverfitting_val_train"]==True]
###学習データを増やす+先ほど得られたハイパーパラメータを記述。
python
1from sklearn.model_selection import train_test_split 2import matplotlib.pyplot as plt 3from sklearn.metrics import confusion_matrix 4 5loss_list=[] 6x_train, x_test, y_train, y_test = train_test_split(train_under_train, train_under_test, test_size = 0.1,random_state=0) 7lr=0.002052 8batch_size=44.888441 9N=90.036519 10ur=0.5 11layer=5.056227 12model2 = Sequential() 13model2.add(Dense(10, activation="relu", input_shape=[len(x_train.keys(),)])) 14for i in range(int(layer)): 15 model2.add(Dense(3, activation="relu")) 16model2.add(Dense(1,activation="sigmoid")) 17 18optimizer = optimizers.Adam(lr) 19 20model2.compile(loss='binary_crossentropy', optimizer=optimizer,metrics=["accuracy"]) 21 22history=model2.fit(x_train, y_train,epochs=int(N),batch_size=int(batch_size),validation_split=0.1) 23 24#テストデータで精度を確認 25score_test = f1_score(model2.predict(x_test)>ur, y_test) 26print(confusion_matrix(y_test, model2.predict(x_test)>ur)) 27print("------------------------------") 28print(score_test) 29 30 31#plt.plot(history.history['accuracy']) 32plt.plot(history.history['loss']) 33plt.plot(history.history['val_loss']) 34 35 36plt.show()
###ここで、未知データ(testのデータ)に対して学習
python
1pd.set_option('display.max_rows', 1600) 2 3pred=model.predict(normed_test)>ur 4test_data =pd.DataFrame(pred.astype(np.int)) 5 6print(test_data) 7
##--------------------------------追記-------------------------------------
以下のように設定し、それぞれのf1スコアを見れるようにしました。
###オーバーサンプリング
一番上が、ほとんど0.8台ですが、これでえられたハイパーパラメータを使用しても、0.4台のf1-scoreとなりました。
###アンダーサンプリング
後ほど追加
###正則化しただけ(オーバーフィッティング、アンダーサンプリングなし)
#####---------------追記終わり---------------
試したこと
xGBoosting、keras、pytorch、その他downsizing、1に重み付け、k-fold等を行いました。
が、結局学習データ、評価データ、テストデータの精度がいいのに、SIGNATEに置いてある未知データの精度が悪いと言うことが起こってしまっています。学習データに対するアウトプットは、未知データに対するoutputは、0.5~0.6程のf1値なので困っています。
一応この後に、学習データを増すためにテストデータと学習データにわけて訓練してますが、そこでのテストデータのf1-measureは、0.8ほどとなっています。
最後に
はじめに戻りますが、学習データでの精度がいいのに、未知データの精度が悪い場合、どうやって改善すればいいでしょうか?学習データ、テストデータ、評価データを見てもか学習している感じではないのですが...
お力添えよろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー