目指せ"Another" バトル優勝!
pop-ketle
すみません、文字数の制限なのかどうしても該当のフォーラムのコメント欄に書き込めなかったので、わざわざ新しくトピックを開いて質問させていただきます。ご迷惑ご容赦ください。
Target Encodingを初めて使ってみようと、以下のフォーラムの実装を参考にコードを書いたのですが、この例だと各行のTarget Encodingをかけた列が全て同じ値になってしまい、特徴量が消えてしまっている気がするのですが、これは実装としてうまくいっているのでしょうか?https://prob.space/competitions/game_winner/discussions/Oregin-Post344b005eb605a8777141
import pandas as pd import numpy as np import re import matplotlib.pyplot as plt import seaborn as sns import lightgbm as lgb from sklearn.model_selection import train_test_split from sklearn.model_selection import KFold from sklearn.metrics import accuracy_score import warnings warnings.filterwarnings('ignore') # データの読込 train = pd.read_csv("./features/train_data.csv") test = pd.read_csv('./features/test_data.csv') # 欠損値は、全て「-1」とする。 def fill_all_null(df): for col_name in df.columns[df.isnull().sum()!=0]: df[col_name] = df[col_name].fillna(-1) # 訓練データ、テストデータの欠損値を補完 fill_all_null(train) fill_all_null(test) # ターゲットエンコーディングの関数定義 def change_to_target2(train_df,test_df,input_column_name,output_column_name): from sklearn.model_selection import KFold # nan埋め処理 train[input_column_name] = train[input_column_name].fillna('-1').isnull().sum() test[input_column_name] = test[input_column_name].fillna('-1').isnull().sum() kf = KFold(n_splits=5, shuffle=True, random_state=71) #=========================================================# c=input_column_name # 学習データ全体で各カテゴリにおけるyの平均を計算 data_tmp = pd.DataFrame({c: train_df[c],'target':train_df['y']}) target_mean = data_tmp.groupby(c)['target'].mean() #テストデータのカテゴリを置換 test_df[output_column_name] = test_df[c].map(target_mean) # 変換後の値を格納する配列を準備 tmp = np.repeat(np.nan, train_df.shape[0]) for i, (train_index, test_index) in enumerate(kf.split(train_df)): # NFOLDS回まわる #学習データについて、各カテゴリにおける目的変数の平均を計算 target_mean = data_tmp.iloc[train_index].groupby(c)['target'].mean() #バリデーションデータについて、変換後の値を一時配列に格納 tmp[test_index] = train_df[c].iloc[test_index].map(target_mean) #変換後のデータで元の変数を置換 train_df[output_column_name] = tmp #========================================================# # オブジェクトの列のリストを作成 object_col_list = train.select_dtypes(include=object).columns # オブジェクトの列は全てターゲットエンコーディング実施 for col in object_col_list: change_to_target2(train,test,col,"enc_"+col) # 変換前の列を削除 train = train.drop(object_col_list,axis=1) test = test.drop(object_col_list,axis=1) # 'id'の列を削除 train = train.drop('id',axis=1) test = test.drop('id',axis=1) enc_obj_list = ['enc_'+s for s in object_col_list.tolist()] print(train[enc_obj_list].head())
enc_period enc_game-ver enc_lobby-mode enc_lobby enc_mode enc_stage \ 0 0.525161 0.525161 0.525161 0.525161 0.525161 0.525161 1 0.524499 0.524499 0.524499 0.524499 0.524499 0.524499 2 0.525747 0.525747 0.525747 0.525747 0.525747 0.525747 3 0.523781 0.523781 0.523781 0.523781 0.523781 0.523781 4 0.524329 0.524329 0.524329 0.524329 0.524329 0.524329 enc_A1-weapon enc_A1-rank enc_A2-weapon enc_A2-rank ... \ 0 0.525161 0.525161 0.525161 0.525161 ... 1 0.524499 0.524499 0.524499 0.524499 ... 2 0.525747 0.525747 0.525747 0.525747 ... 3 0.523781 0.523781 0.523781 0.523781 ... 4 0.524329 0.524329 0.524329 0.524329 ... enc_A4-weapon enc_A4-rank enc_B1-weapon enc_B1-rank enc_B2-weapon \ 0 0.525161 0.525161 0.525161 0.525161 0.525161 1 0.524499 0.524499 0.524499 0.524499 0.524499 2 0.525747 0.525747 0.525747 0.525747 0.525747 3 0.523781 0.523781 0.523781 0.523781 0.523781 4 0.524329 0.524329 0.524329 0.524329 0.524329 enc_B2-rank enc_B3-weapon enc_B3-rank enc_B4-weapon enc_B4-rank 0 0.525161 0.525161 0.525161 0.525161 0.525161 1 0.524499 0.524499 0.524499 0.524499 0.524499 2 0.525747 0.525747 0.525747 0.525747 0.525747 3 0.523781 0.523781 0.523781 0.523781 0.523781 4 0.524329 0.524329 0.524329 0.524329 0.524329 [5 rows x 22 columns]
関数の途中にある、「# nan埋め処理」がプログラムミスと思われます。元のカテゴリ変数の値を、target encodingの前にすべて0に置き換えてしまっています。※「# 変換前の列を削除」の処理を実行せずに関数を適用したデータフレームを確認すると分かるかと思います。
関数外で「# 欠損値は、全て「-1」とする。」処理をしているので、「# nan埋め処理」のプログラムは削除して良いかと思います。
確かに「# nan埋め処理」の部分がまずそうです。ループのたびに、欠損値を-1で埋めるようにみせかけつつ、欠損値の数をカウントしてその合計をinput_column_nameに入れるというよくわからない処理になっています。すでに欠損値を-1で埋めているので、input_column_nameの列がすべて欠損値の合計値0に入れ替わっています。
そのため、結果的に毎度全ての値が0の列に対してtarget encodingを行う結果となり、各行の各列が同じ値になっていて、行ごとに値が違うのは、バリデーションを切ってるので、どの時のバリデーションデータに入るかで値が変わっているようです。
ありがとうございます。プログラムのミスの箇所がわかり、処理している内容についての理解も深まりました。