給与推定

給与推定により人事の赤池くんの窮地を救おう

賞金: 100,000 参加ユーザー数: 569 5年弱前に終了

コンペティション概要

ある会社の人事担当である赤池くんは社員の給与を定めるための給与規定を紛失してしまいました。 それと同時に通帳を紛失してしまったため、 一部の社員の給与の額がわからなくなってしまいました。

社員の情報と給与のデータが与えられるので困っている赤池くん助けるために失われた社員の給与情報を予測してあげましょう。

賞金

1位 100,000円

ダウンロード

データをダウンロードするにはログインまたはユーザー登録して下さい

概要

データは2つのグループに分けられます。

  • 訓練データ(train_data.csv)
  • テストデータ(test_data.csv)

なお訓練データセットとテストデータセットにはそれぞれ21,000と9,000のサンプルが含まれています。
訓練データセットは、機械学習モデルを構築するために使用してください。訓練データセットについては、給与の値が振られています。
テストデータセットを使用して、どの程度新しいデータに対してモデルが実行されているかを確認する必要があるので、テストデータセットについては、
社員ごとの給与データは存在しません。
なので、テストデータセットを使用して、各社員の給与を予測してください。

また、提出ファイルの例に関しては 評価方法 のタグを参照してください。

データの形式

データセットのカラムは以下の通りになっています。

カラム名 説明
position 役職(0=役職なし, 1=主任, 2=係長, 3=課長, 4=部長)
age 年齢(歳)
area 勤務地
sex 性別(1=男性, 2=女性)
partner 配偶者の有無(0=なし, 1=あり)
num_child 子供の人数(人)
education 教育(0=高校, 1=短大専門学校, 2=大学, 3=修士, 4=博士)
service_length 勤続年数(年)
study_time 一週間あたりの勉強時間(h)
commute 通勤時間(h)
overtime 一ヶ月あたりの残業時間(h)
ラベル 説明
salary 給与月額(千円)

目標

目標は、テストデータセットの社員のデータに基づき、社員の給与額を予測することです。y(給与)を実数値で予測してくだい。

メトリック

モデルの予測性能は9,000のテストデータセットのうち、予測値と真値のMAE(mean absolute error)で評価されます。

$ MAE = \frac{1}{N} \sum^{N}_{i=1} | y - \hat{y}|$

ここで$y$は真の値, $\hat{y}$は予測値です。

提出ファイルの形式

回答用のsubmission.csvを用意する(9,000のエントリーとヘッダー行を含む) 。
提出されたファイルに余分な行や列(idとy以外)が含まれていた場合はエラーとなります。

提出ファイルは以下の列のみを必ず含んでください:

  • id(テストデータセットと同じ順序)
  • y(予測された給与額)

以下は提出ファイルの例です。

id,y
0, 324.5
1, 694.3
2, 495.2
3, 200.4
■Open Review Competition

本コンペでは、開催期間終了後 賞金対象者のコードを公開し、ユーザーの皆様にチーティング有無をレビューしていただき順位確定させる、オープンレビュー方式のコンペティションを行います。

賞金対象ユーザー
コンペ終了後1週間以内:
トピックにて、学習過程の分かるコードの公開をお願いいたします。
(簡易解説までつけていただけると助かります。)
1.5か月以内:
レビュアー(ユーザー)より、チーティングの疑いに関するコメントがある場合は、ご回答をお願いいたします。
※チーティングとは無関係のコメント(ノウハウに関する質疑 等)についてもご回答いただけると幸いですが、順位確定の判断材料とは致しません。

レビュアー(ユーザーの皆様)
コンペ終了後1か月以内:
公開コードを確認いただき、チーティングが疑われる場合は、トピックを通して質疑の投稿をお願いいたします。

レビュアーからの質疑と、回答状況をふまえて、最終的に運営側で順位確定を判断します。

■順位の繰上げ

不正発覚の場合は失格とし、リーダーボードの順位を繰上げます。
順位繰上げにより賞金対象者となられた場合は、繰上げ日より一週間以内に、トピックにてコードを公開いただき、「Open Review Competition」と同様のフローにて順位を確定させていただきます。

■タイムライン

開始日 2019/11/6 0:00 JST
終了日 2010/12/23 0:00 JST
エントリー締め切り なし

■システム利用

・参加者ごとに1つのアカウントでご参加ください
・チーム参加にの場合は、最大5名での参加が可能です
・1日あたり、最大5回までの提出が可能です

■禁止事項

・ユーザー間での情報共有
コンペティションに関連するコード・データを、チーム外のユーザーと共有することはできません。全参加者が利用できる場合に限り、共有可能です。
・外部データの使用
本コンペティションで公開されているデータのみを用いてチャレンジして下さい。コンペ外データを用いて学習されたモデルの使用も禁止とします。

■運営からのお願い

公平性の担保、チーティング等の不正防止のため、予告なくルールの追加・変更を行う場合がございます。
ご不便をおかけすることもあるかと思いますが、サービス向上のためご了承ください。

FAQ

このコンペティションでは賞金はでますか?

はい。最も精度の高い学習モデルを作成した優勝者には、賞金10万円を贈呈します。
順位確定までのプロセスについては、ルール「Open Review Competition」を参照ください。

チームで参加できますか?

可能です。チームページから作成いただけます。

どこでアカウントをつくればいいですか?

こちらから作成いただけます。

コンペティション参加にはアカウント登録が必要となりますのでご注意ください。

外部データを使うことは可能ですか?

本コンペティションで公開されているデータのみを用いてチャレンジして下さい。コンペ外データを用いて学習されたモデルの使用も禁止とします。

コードを提出するにあたって Seed を固定する必要はありますか?

Seed を固定することが推奨です。ただし、Seed を固定しなくても提出用コードとしては認めていく方針です。

同スコアの場合は順位はどうなりますか?

全く同じスコアの場合、提出時間の早いユーザーが上位となります。

このチュートリアルでは給与データに対して

  • データの読み込み
  • 前処理
  • skleanを用いてランダムフォレストモデルの作成、学習
  • モデルの評価
  • 提出ファイルの作成
  • 誤識別したデータを確認

を行います。

データの読み込み

まずはデータを読み込んで見ましょう。csvデータの読み込みは複数のやり方がありえますが、pandasread_csv関数はその中でも機能が豊富で、扱いやすいためこれを使います。
これを使うと、csvデータを読み込み、pandas.DataFrameにして返してくれます。

import pandas as pd

train_df = pd.read_csv('train_data.csv', index_col=0)
test_df = pd.read_csv('test_data.csv', index_col=0)
train_data_df = train_df.iloc[:, :-1]
train_target_df = train_df.iloc[:, -1:]
test_data_df = test_df

また、DataFrameには.head()というメソッドが定義されており、これを呼び出すとDataFrameの先頭の数行を確認できます。

train_data_df.head()
id position age area partner num_child education service_length commute overtime
0 1 44 愛知県 1 2 1 24 1.6 9.2
1 2 31 奈良県 0 0 0 13 0.7 12.4
2 2 36 山口県 0 0 2 14 0.4 16.9
3 0 22 東京都 0 0 0 4 0.4 6.1
4 0 25 鹿児島県 0 0 1 5 0.2 4.9

データの前処理

このデータにはいくつかのカテゴリカルデータが含まれているので今のままでは機械学習モデルで扱いづらいです。そこで、 カテゴリカルデータに対してget_dummies関数を使いone hotベクトルに変換することができます。

ここではareaeducationpositionについてone hotベクトル化を行います。 drop_firstを用いることで多重共線性を減らすことができます。

train_data_df = pd.get_dummies(train_data_df, columns=['area', 'education', 'position'], drop_first=True)
test_data_df = pd.get_dummies(test_data_df, columns=['area', 'education', 'position'], drop_first=True)

データの確認

訓練データにおける給与がどのような分布になっているか見てみましょう。各収入階級ごとの度数をヒストグラムを用いてプロットするのが以下のコードです。

import matplotlib.pyplot as plt
%matplotlib inline
plt.hist(train_target_df['salary'], bins=20)

salary_histgram.png

中間層にピークのある、 格差の少ない会社だということがわかります。

識別モデルの作成

ここでは試しに、 ランダムフォレスト回帰を作成してみましょう。 sklearnはは多くの機械学習モデルが実装されたライブラリであり、これを使って実装してみます。

from sklearn.ensemble import RandomForestRegressor
model = RandomForestRegressor(n_jobs=-1, random_state=2525)
model.fit(train_data_df,train_target_df)
# RandomForestRegressor(bootstrap=True, criterion='mse', max_depth=None,
#                      max_features='auto', max_leaf_nodes=None,
#                      min_impurity_decrease=0.0, min_impurity_split=None,
#                      min_samples_leaf=1, min_samples_split=2,
#                      min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=-1,
#                      oob_score=False, random_state=2525, verbose=0,
#                      warm_start=False)

モデルの評価

sklearnの識別モデルには、.predict()メソッドが定義されており、これを使うと与えられたデータに対して、給与の予測額を出力してくれます。

from sklearn.metrics import mean_absolute_error 
predicted = model.predict(train_data_df)
print(mean_absolute_error(predicted, train_target_df))
# 9.381901130006629

また、予測結果と実際の結果がどの程度異なるかを評価する関数がsklearn.metricsに定義されています。ここではmean_absolute_errorを確認してみましょう。

提出ファイルの作成

与えられているテストデータに対して予測を行い、 提出ファイルを作成します。

test_predicted = model.predict(test_data_df)
submit_df = pd.DataFrame({'y': test_predicted})
submit_df.index.name = 'id'
submit_df.to_csv('submission.csv')

これをベースにして、モデルのパラメータを変える、 モデルを変える、 有用な特徴量を探るなど試行錯誤して、モデルの性能を上げていきましょう。

誤識別したデータを確認

import numpy as np

plt.hist(np.abs(predicted - train_target_df['salary'].values), log=True)

まずは誤差の分布をプロットしてみましょう。

error.png

もっとも誤差の大きなデータはこちらになります。

worst_index = np.argmax(predicted - train_target_df['salary'])
train_df.iloc[worst_index, :]
# position                2
# age                    49
# area                  大阪府
# sex                     1
# partner                 0
# num_child               0
# education               4
# service_length         22
# study_time              3
# commute               1.5
# overtime               12
# salary            421.522
# Name: 5986, dtype: object
print(predicted[worst_index], train_target_df['salary'].iloc[worst_index])
# 669.5488881368135 421.52210195900886