質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

PyTorch

PyTorchは、オープンソースのPython向けの機械学習ライブラリ。Facebookの人工知能研究グループが開発を主導しています。強力なGPUサポートを備えたテンソル計算、テープベースの自動微分による柔軟なニューラルネットワークの記述が可能です。

XGBoost

XGBoostは、アンサンブル学習と決定木を組み合わせた手法です。弱学習器の構築時に、以前構築された弱学習器の結果を用いて弱学習器を構築。高度な汎化能力を持ち、勾配ブースティングとも呼ばれています。

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3922閲覧

学習データでの精度がいいのに、未知データに対する予測が悪い場合の対策方法が知りたい

TakoyakiOishii

総合スコア16

Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

PyTorch

PyTorchは、オープンソースのPython向けの機械学習ライブラリ。Facebookの人工知能研究グループが開発を主導しています。強力なGPUサポートを備えたテンソル計算、テープベースの自動微分による柔軟なニューラルネットワークの記述が可能です。

XGBoost

XGBoostは、アンサンブル学習と決定木を組み合わせた手法です。弱学習器の構築時に、以前構築された弱学習器の結果を用いて弱学習器を構築。高度な汎化能力を持ち、勾配ブースティングとも呼ばれています。

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2021/03/24 15:54

編集2021/03/27 03:53

前提・実現したいこと

学習データでの精度がいいのに、未知データに対する予測が悪い場合の対策方法が知りたいです。

何をしているのか

現在、練習のため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ほどとなっています。

最後に

はじめに戻りますが、学習データでの精度がいいのに、未知データの精度が悪い場合、どうやって改善すればいいでしょうか?学習データ、テストデータ、評価データを見てもか学習している感じではないのですが...
お力添えよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2021/03/24 15:57

> 結局学習データ、評価データ、テストデータの精度がいいのに それぞれの精度はいくつでしょうか?
TakoyakiOishii

2021/03/24 16:10

test,train,valのf-meansをそれぞれ足している値が、2.4795091949823407となっていました。 ただ、今megさんに言われて気がついたのですが、これ、test,train,valの合計f-meansが、2.4でも1,0、0.7,0.7の場合がありえますね....
TakoyakiOishii

2021/03/24 16:17

追記しましたが、一方この後に、学習データを増やすために、valを消してoptunaででたハイパーパラメータを入れて学習データ、testデータで訓練してますが、その時のf1-measureは0.8ほどとなっています。
meg_

2021/03/24 16:26

>>> 結局学習データ、評価データ、テストデータの精度がいいのに >> それぞれの精度はいくつでしょうか? > test,train,valのf-meansをそれぞれ足している値が、2.4795091949823407となっていました。 それぞれ独立した精度を見た方が良いのではないでしょうか?
TakoyakiOishii

2021/03/24 17:41

ありがとうございます。おっしゃる通りですね。見れるようにしてみます。
TakoyakiOishii

2021/03/25 13:33

一応、f1スコアを全ての場合見れるように致しました。 だいたい0.8ほどなのですが、このハイパーパラメータを入れても、0.4のf1スコアとなってしまいました。。。
toast-uz

2021/03/25 22:47

前処理の部分までコードを示してください。できれば、データ読み込み時点からのコード全体を示してください。
TakoyakiOishii

2021/03/26 06:29

toast-uz様、コード全体を入れさせていただきました。ご不明部分あれば、いつでもおっしゃっていただけますと幸いです。
toast-uz

2021/03/26 12:29 編集

この問題は、リーダーボードのトップで0.76、100位で0.6台のf1値であることから予想は難しく、かつサンプル数が1500程度なので、NNではオーバーフィッティングしやすいものと思います。1つ不思議なのが、学習データのtest成績もよくなっていることです。これを解き明かすため、optunaでの最適化の詳細を確認したいです。 optunaを使用して学習、とありますが、使用しているコードがありませんので、該当部分のコード提示をお願いします。
toast-uz

2021/03/26 23:24

もう1点確認です。途中にアンダーサンプリングとオーバーサンプリングのコードがありますが、今回の結果はどれによるものでしょうか? オーバーサンプリングをしたデータだと、そこから切り出したtrain/val/test全てに対してオーバーフィッティングする傾向があり、今回の結果を説明できるものと思います。
TakoyakiOishii

2021/03/27 03:28 編集

toast-uz様 リーダーボードのトップで0.76、100位で0.6台のf1値であることから予想は難しく、かつサンプル数が1500程度なので、NNではオーバーフィッティングしやすいものと思います >>ありがとうございます。ということは、別のモデルを使用してみます。普通のロジスティック回帰...の方がいいとはならないですよね。でもxgboostingがダメだったので決定木は決定木でか学習しやすい気も...試してみます。 optunaを使用して学習、とありますが、使用しているコードがありませんので、該当部分のコード提示をお願いします。 >> bayesOptが、optunaでベイズ最適化をしたコードになります。わかりずらくて申し訳ございません。 途中にアンダーサンプリングとオーバーサンプリングのコードがありますが、今回の結果はどれによるものでしょうか? >>おっしゃる通り、オーバーサンプリングしたものの結果でございました。こちら質問に追記しておきます。 加えて、通常の正則化しただけの結果、アンダーサンプリングの結果も記述しておきます。
TakoyakiOishii

2021/03/27 03:36

>>optunaを使用して学習、とありますが、使用しているコードがありませんので、該当部分のコード提示をお願いします。 すいません。今知りましたが、BayesianOptimizationと、optunaって別のものなのですね。失礼いたしました。
guest

回答1

0

ベストアンサー

学習データでの精度がいいのに、未知データの精度が悪い原因は、オーバーフィッティングであると思われます。
対策として、今回のデータの場合は、深層学習ではない機械学習モデル(GBDT、ランダムフォレスト、ロジスティクス回帰、SVM等)を用い、必要に応じてそれらのアンサンブルをするとよいでしょう。

  1. 今回のデータの特徴

SIGNATEの規約に抵触するのでデータの詳細は説明できませんが、リーダーボードのトップで0.76、100位で0.6台のf1値であることから予想は難しく、質問者様が80%以上のスコアを出したということはオーバーフィッティングの可能性が高いです。

また、そもそも、サンプル数が1500程度でしかなく、深層学習の潜在能力が発揮できないようです。

なお、クラス1(botである)の比率は約15%であるため、普通に学習してしまうと、85%の正解率である「全て0とする推論」に最適化されてしまいます。そのため、不均衡データ学習が必要です。リーダーボードの基準がf1スコアであること、質問者様がオーバーサンプリングを試みたことは、この不均衡性に由来するものと思います。

  1. オーバーフィッティングの原因推定

なぜオーバーフィッティングしてしまったか、およびオーバーフィッティングがx_testまで波及したのはなぜか、について推定します。

2-1) ベイズ最適化の影響

1つはベイズ最適化の影響です。score = score_valid+score_test+score_trainとなっており、x_testの評価結果も一気に最適化してしまっています。score_testはベイズ最適化の評価に含めない方がよいでしょう。

2-2) オーバーサンプリングの影響

SMOTEは、同じ説明変数のペアをコピーするわけではありませんが、それでも、「類似の」説明変数のペアを生成することで、オーバーサンプリングを行います。そもそも、予想が難しい問題というのは、説明変数をもとにした単純な分類が通用しないという特性を持っています。そのため、学習データをもとにした「単純な類似性」によるデータ拡張は、未知データに有効ではなく、学習データにオーバーフィッティングしてしまうことになります。(あくまでも、今回のデータの場合、ということで一般的にはオーバーサンプリングが正しい打ち手であることも多いです)

例えば、アパートの住人が201号室と203号室が男性である場合に、「202号室も男性である」というデータ拡張をしているようなものです。実はもっと複雑な条件から推定すべきなのに、無関係な説明変数の補間でデータを「捏造」してしまうため、推論を間違った方向に誘導してしまいます。

  1. 対策

冒頭に記述したとおり、今回のSIGNATEのデータの場合は、深層学習ではない機械学習モデル(GBDT、ランダムフォレスト、ロジスティクス回帰、SVM等)を用い、必要に応じてそれらのアンサンブルをするとよいでしょう。また、不均衡データの対策としては、オーバーサンプリングはやめて、損失関数をカスタマイズしたりクラス重み付けすることを試してみましょう。

なお、今回のデータは、kaggleの有名な初級課題であるtitanicと類似した特徴があるようです。titanicもサンプル数が約900と少ない2値分類問題です。私自身、titanicでNNで学習を試みましたがオーバーフィッティングしてしまい、手元のデータだと好成績を出しているはずが未知データの推論結果は思わしくない、ということに遭遇しました。一方、GBDTを使うとそのような影響は軽微になりました。実際、titanicで好成績を上げた人の解説記事を見ると、みなさん、NNは使われていません

参考: タイタニック号の乗客の生存予測〜80%以上の予測精度を超える方法(モデル構築&推論編)

なお、titanicの場合は前処理も重要なのですが、今回のSIGNATEのデータは比較的きれいなので、その点は異なります。titanicよりも平易であると言えるでしょう。

投稿2021/03/27 04:57

編集2021/03/27 05:03
toast-uz

総合スコア3266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakoyakiOishii

2021/03/27 08:04

toast-uz様 ありがとうございます。toast-uz様は、知識が豊富+説明力があると言う点からかなりすごい人なんじゃないかと自分の少ない経験というデータから予測してしまっています。毎度のことながら、大変わかりやすく説明していただきありがとうございます。 また、似たような例をkaggleで探してそれで実装すると言うことをやれていなかったので、参考にさせていただきます。 ありがとうございました。
toast-uz

2021/03/27 14:15

> 自分の少ない経験というデータから予測してしまっています。 オーバーフィッティングです笑笑
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問