俺人〜OREGIN〜俺、バカだから人工知能に代わりに頑張ってもらうまでのお話

俺って、おバカさんなので、とっても優秀な人工知能を作って代わりに頑張ってもらうことにしました。世界の端っこでおバカな俺が夢の達成に向けてチマチマ頑張る、そんな小さなお話です。現在はG検定、E資格に合格し、KaggleやProbSpaceのコンペに参画しながら、Pythonや機械学習、統計学、Dockerなどの勉強中です。学習したことをブログにアウトプットすることで、自分の身に着けていきたいと思います。まだまだ道半ばですが、お時間がありましたら見て行ってください。

ProbSpace給与推定コンペ振り返り

先日、「ProbSpace」というプラットフォームで開催された「給与推定」コンペに参戦したので、振り返っていきたいと思います。

私にとって、初めて公式の結果が確定したコンペとなり、最終順位は参加310チーム中、46位でした。全体の15%以内に入れたので、まずまずの出来だったと思います。

f:id:kanriyou_h004:20191230142705p:plain

ただ、上位陣の解法を拝見すると、自分のコードは、まだまだ、全然できていないなぁと感じました。

では、さっそく時系列に取り組みを振り返っていきます。

(あえて、時系列にしたのは、計画的にとりくめなかった自分の反省を込めて・・。)

特徴量(その1)

1.欠損値を確認

データを読み込んで、とりあえず欠損値の有無を確認しました。

# Read Data
train_df = pd.read_csv('train_data.csv', index_col=0)
test_df = pd.read_csv('test_data.csv', index_col=0)

#Check Null
print(train_df.isnull().sum())
print('='*20)
print(test_df.isnull().sum())

position 0
age 0
area 0
sex 0
partner 0
num_child 0
education 0
service_length 0
study_time 0
commute 0
overtime 0
salary 0
dtype: int64
====================
position 0
age 0
area 0
sex 0
partner 0
num_child 0
education 0
service_length 0
study_time 0
commute 0
overtime 0
dtype: int64

確認したところ、欠損値がなく、補完の処理も不要であったので、ここは楽でした。

2.ラベルエンコーディング

「Area」の列が、「東京都」、「大阪」など文字列の情報になっているので、数値データに置き換えました。

# Area
from sklearn import preprocessing
le = preprocessing.LabelEncoder()
df['area'] = le.fit_transform(df['area'])

 

アンサンブル学習(スタッキング)のモデルを作成(その1)

1.1層目の作成

1層目は、まず、RandomForet,AdaBoost,GradientBoosting,ExtraTree,Baggingの5つをつかってみました。

 from sklearn.ensemble import (RandomForestRegressor, AdaBoostRegressor, 
GradientBoostingRegressor, ExtraTreesRegressor,BaggingRegressor)

2.2層目の作成

2層目は、LightGBMを使ってみました。

import lightgbm as lgb 

3.全体構成その1

 全体としては、以下のような感じです。 

f:id:kanriyou_h004:20191230150437p:plain

 

特徴量(その2)

特徴量(その2)では、いくつかの特徴量を新たに追加したのですが、効果を発することなく終わってしまいました。

1.Areaカウントを追加

「Area」について、単純にコード化するのではなく、エリアごとのレコード数をコードの代わりにする列を作ってみました。

# 'area'
train_df['area_count_enc'] = train_df.groupby('area')['overtime'].transform('count')
test_df['area_count_enc'] = test_df.groupby('area')['overtime'].transform('count')

 

2.Educationを分割

また、「Education」が、2以下と3以上でSalaryの傾向が異なっていたので、2分割にしてみました。

#education を 2以下と3以上の区分に分ける。
train_df['education_2under_3over']=[3 if i >=3 else 1 for i in train_df['education']]
test_df['education_2under_3over']=[3 if i >=3 else 1 for i in test_df['education']]

 

 

3.Service_length,commute,study_timeをビンニング

「Service_length」,「commute」,「study_time」については、それぞれ、5、5、4にビンニング処理を実施。

train_df['Categorical_length']=pd.qcut(train_df['service_length'],5)
test_df['Categorical_length']=pd.qcut(test_df['service_length'],5)
train_df['Categorical_length'] = le.fit_transform(train_df['Categorical_length'])
test_df['Categorical_length'] = le.fit_transform(test_df['Categorical_length'])

#以下同様にcommute,study_time

特徴量(その3)

特徴量(その3)では、複数の特徴量を組み合わせたり、対数をとったりしてみました。

これによって、MAEが24を切ることができました。

1.交差項追加

いろいろな列の掛け算をとって、モデルに投入して、精度が上がる組み合わせをOptuna等をつかって探索しました。

 #cros_Feature
df['commute_x_partner'] = df['commute'] * df['partner']
df['commute_x_num_child'] = df['commute'] * df['num_child']
df['position_x_age'] = df['position'] * df['age']
#などなどいろいろ追加して試す

 

2.対数変換

数値の列については、対数をとってみました。

def to_Log(df):
continuas_col=['age','service_length','study_time','commute','overtime']
for i,col in enumerate(continuas_col):
df['Log_'+col]=np.log1p(df[col]+1)

to_Log(train_df)
to_Log(test_df)

 

 ついでに、Salaryも対数変換しました。

うっかり、提出用のデータも対数のまま提出してしまい、提出データの精度がガタ落ちして、何が起こったかわからず、プチパニックになりました。

# 入力データの作成
y_train = np.log1p(train_df['salary'].ravel())

train = train_df.drop(['salary'], axis=1)
x_train = train.values # 学習データ
x_test = test_df.values # テストデータ

 提出時は以下を忘れてはいけない。

predicts = np.expm1(model.predict(input_test_df))

3.「東京」、「大阪」は特別扱い

トピックに「東京」、「大阪」を特別扱いするとよいとの記事があったので、さっそく参考にさせていただきました。

  df["Live_in_Tokyo_or_Osaka"] = [1 if (i ==9) | (i==26) else 0 for i in df['area']]

  

4.Target Encording

Kaggleで勝つデータ分析の技術 [ 門脇大輔 ]」を拝見して、Target Encordingにも挑戦してみました。

リークとならないように、平均につかったレコード以外を置き換えていくのがポイントですね。

from sklearn.cross_validation import KFold

kf = KFold(ntrain, n_folds=7, random_state=42)
#=========================================================#
cat_col=['position','area','sex','partner','education']

for c in cat_col:
  # 学習データ全体で各カテゴリにおける給料の平均を計算
  data_tmp = pd.DataFrame({c: train_df[c],'target':train_df['salary']})
  target_mean = data_tmp.groupby(c)['target'].mean()
  #テストデータのカテゴリを置換
  test_df[c] = test_df[c].map(target_mean)

  # 変換後の値を格納する配列を準備
  tmp = np.repeat(np.nan, train_df.shape[0])

  for i, (train_index, test_index) in enumerate(kf): # 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[c] = tmp

#========================================================#

 

 

アンサンブル学習(スタッキング)のモデルを作成(その2)

1.1層目の予測パターンを作成

1層目について、 特徴量として「①対数変換を行う前」「➁対数変換を行った後」「➁にTargetEncording実施」の3つそれぞれに、予測モデルとしてRandomForet、AdaBoost、GradientBoosting、ExtraTree、Baggingの5つを使った、合計

15個の予測パターンを作成しました。

2.2層目の作成

2層目は、LightGBMで、1層目の15個の予測パターンのうち、どのパターンを使うと最も精度が高くなるかをOptunaを使って探索しました。 

3.全体構成その2

 探索した結果、以下のような構成となりました。 

f:id:kanriyou_h004:20191230161600p:plain

アンサンブル学習(スタッキング)のモデルを作成(その3) 

1.3層目を作ってみる

モデルを作成(その2)で行き詰まってしまったので、その2のOptunaで、精度が良かった組み合わせをいくつかピックアップして、2層目の出力の平均をとる3層目をつくってみました。

ここからは、いろんなパターンを作成して、少しでも精度が良かったモデルができたら出力ファイルをためておいて毎日提出するという力技になってしまいました。

f:id:kanriyou_h004:20191230162419p:plain

結果

 最終結果としては、提出回数109回、ベストスコア:22.539、順位:46位でフィニッシュできました。

f:id:kanriyou_h004:20191230163029p:plain

最後までやり切った初めてのコンペでした。

充実感もありましたが、やはり、全体的な計画ができていなかったので、特徴量を検討するのか、モデルを検討するのか、どっちつかずで、おろおろしている間に終わってしまったのが反省点でした。

また、今回は木モデルを中心に構成しましたが、上位陣の方々の解法を拝見するとニューラルネットワークを使いこなしていらっしゃったので、もっと勉強して手札を増やしていく必要があると感じました。

 次のコンペはもっと、計画的にいろいろなパターンを試して、さらに順位アップを狙っていきたいと思います。

 

[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

Kaggleで勝つデータ分析の技術 [ 門脇大輔 ]
価格:3608円(税込、送料無料) (2019/12/30時点)

 【参考記事】E資格、G検定 合格記

2019年8月31日(土)にE資格を受験して、合格しました!

E資格対策として勉強の進め方や、参考書などをまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

oregin-ai.hatenablog.com 

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 【E資格対策に使った参考書】