とあるお兄さんの雑記

基本的に技術系の内容を書きますが、何を書くかは私の気分です。

SIGNATEのBeginner限定コンペに参加~参加登録から提出まで~

SIGNATEに新設されたBeginner限定コンペに参加してみました。結果はどうあれ、提出方法など一連の流れを忘れてしまった時に参考になるものが欲しいと思って今回の記事を書いてます。

そのため、データを整理し、仮説を通して新しい特徴量を考えたり、モデルのパラメータチューニングを行ったりなどは一切やっていません。加えて、必要最低限の説明もありません

あくまで、参加登録から提出までの一連の流れまで分かればいいので、大多数の方にはあまり役に立たない記事です。そのうえで、お読みください。

SIGNATEとは

一言で言えば、Kaggleの日本版です。
将来データサイエンティストを目指す人や、データ分析に興味がある人、Kaggleをやりたいけど英語だらけでもう少し低い難易度でやりたい人などはちょうどいいかなと思います。
アカウント作成自体は無料で、Googleアカウントからもアカウントの作成は可能です。

SIGNATE

コンペティションに参加

アカウントを作成したら興味のあるコンペティションを探し参加します。今回は、Beginner限定コンペと書かれた下のコンペに参加します。

f:id:kurasher:20200811184438p:plain



参加するコンペティションをクリックしたら、以下のような画面が出てくるかと思います(一部抜粋)。コンペティションのルールや評価方法などが書いてありますので目を通しておきましょう。

f:id:kurasher:20200811184734p:plain



上の画像からデータという項目を押すと以下の画面に行きます。それぞれ必要なデータをダウンロードします。 f:id:kurasher:20200811185122p:plain

データをダウンロードする場合、利用規約がでてきます。利用規約に同意する場合はチェックをつけます。その後、データのダウンロードが可能です。



簡単ではありますが、以上でSIGNATEの参加からデータの入手までを一通り説明しました。
次からは取得したデータを用いて実際に提出するまでを見てみましょう。

SIGNATEに提出する

ここからは取得したデータから学習モデルを作成し、実際に提出するまでを見ていきましょう。

実行環境

私の場合jupyter labを使っていますが、使うものは何でもいいと思います。

Windows10  Pro
Python: 3.7.7
jupyter lab: 2.1.5
pandas: 1.0.5
xgboost:0.90
Optuna:1.5.0
scikit-learn:0.23.1



ファイル構成

私はclient_targetingというフォルダを作成し、その中に先ほど入手したcsvファイルを置きました。

C:.
│  submit_sample.csv
│  test.csv
│  train.csv
│



データを読み込む

以下のようにして取得したデータを読み込みます。

import pandas as pd

train = pd.read_csv("train.csv", encoding="utf-8")
test = pd.read_csv("test.csv", encoding="utf-8")



データの型を確認する

データの型を確認しておきましょう。というのも、モデルの学習では型が数値のものしか計算してくれないからです。データの型の中にstring型やobject型があればそれらを数値に直す必要があります。

以下のようにして、型を調べることが出来ます。

print(train.dtypes)

出力

id            int64
age           int64
job          object
marital      object
education    object
default      object
balance       int64
housing      object
loan         object
contact      object
day           int64
month        object
duration      int64
campaign      int64
pdays         int64
previous      int64
poutcome     object
y             int64
dtype: object

左がデータのカラム名、右が左のカラム名の型になります。何個かobject型のものがありますね。次ではobject型を数値に変換する方法を見ていきます。

データのobject型を数値の型に変換する

本来であれば、各カラムに何が入っているのかをちゃんと調査したうえで、どんな数値に変換すべきかを考えます。

しかし、今回は時間がないため(コンペティション終了まで残り2時間の時、このあたりをやってました。調べる時間なんてなかったんです......)、なんでもいいので適当な数値に直してくれるLabelEncoderというものを使います。

使い方は以下のような感じ

from sklearn.preprocessing import LabelEncoder
lbl = LabelEncoder()

nonNumList = ["job", "marital", "education", "default", "housing", "loan", "contact", "month", "poutcome"]

for nonNum in nonNumList:
    lbl.fit( list(train[nonNum].unique()) )
    train[nonNum] = lbl.transform(train[nonNum])
    lbl.fit( list(test[nonNum].unique()) )
    test[nonNum] = lbl.transform(test[nonNum])

これで、先ほどのようにデータの型を調べると

print(train.dtypes)
id           int64
age          int64
job          int32
marital      int32
education    int32
default      int32
balance      int64
housing      int32
loan         int32
contact      int32
day          int64
month        int32
duration     int64
campaign     int64
pdays        int64
previous     int64
poutcome     int32
y            int64
dtype: object

見事に数値の型だけになりましたね。

欠損値が無いかを調べる

続いて、欠損値が無いかを調べてみましょう。

train.isnull().sum()

.isnull().sum()で各カラムごとの欠損値の数を出してくれます。

id           0
age          0
job          0
marital      0
education    0
default      0
balance      0
housing      0
loan         0
contact      0
day          0
month        0
duration     0
campaign     0
pdays        0
previous     0
poutcome     0
y            0
dtype: int64

今回は奇跡的にありませんでした。とはいえ、もし仮にあった場合はどうするかというと、そのカラムの平均値や中央値を代入するなどして、対応します。
このあたりは、実際にデータを詳しく調べてみないと分かりません。場合によっては、他の値で代入することも考えられます。

学習する

さて、ある程度データが整理出来たらモデルを学習させます。
そのためにまず、訓練データであるtrainを説明変数と目的変数に分けます。

X = train.drop(["id", "y"], axis = 1)
y = train["y"]

.dropで指定したカラム以外を説明変数としてXに入れます。trainのカラムにあるidはただの番号で、特徴量ではありませんので省きます。また、yは目的変数のため、これも省きます(私はidを省くのを忘れていました。そのため、結果が芳しくなかったのではないかといまさら考えています)。
反対に、yには目的変数だけを入れるため、train["y"]で指定します。

これで、学習の準備は整ったので、早速学習していきましょう。

モデルを作成する

それでは実際にモデルを作成していきましょう。実際、作るモデルはKerasだろうが、PyTorchだろうが、なんでもいいのですが、私は以前にXGBoostOptunaを使ったことがあるので、これらを使って学習を行います。もし入っていなければ、pip installしましょう。
XGBoostはモデル、Optunaはハイパーパラメータチューニング用ですね。


$ pip install xgboost
$ pip install optuna


Optunaの使い方は以前の記事雑に書いてます。個人的には、さらに下にある記事を読んでいただければ、Optunaの大枠は理解できるかと思います。



また、scikit-learntrain_test_splitで訓練データとテストデータを生成します。その後、訓練データはモデルの学習用、テストデータはモデルの精度評価用として使用されます。
学習部分は以下のようなコードになります。

##学習
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import optuna

X = train.drop(["y"], axis = 1)
y = train["y"]

def objective(trial):
    x_train, x_test, y_train, y_test = train_test_split(X_resampled, y_resampled, test_size=.3) # 訓練データ・テストデータの生成
    estimators = trial.suggest_categorical("n_estimators", [6, 10, 15, 20, 30])
    learning_rate = trial.suggest_uniform('eta', 0.1, 0.2) # 0.2~0.5
    reg_lambda = trial.suggest_uniform('lambda', 0.1, 0.2) # 0.2~0.5
    

    clf = xgb.XGBClassifier(objective='binary:logistic', eval_metric = 'rmse',
                            n_estimators = estimators, 
                            learning_rate = learning_rate, 
                            reg_lambda = reg_lambda)
    clf.fit(x_train, y_train)
    y_pred = clf.predict(x_test)
    
    return clf.score(x_test, y_test)
    
    
study = optuna.create_study()
study.optimize(objective, n_trials=100)
print(study.best_params)
print(study.best_value)
print(study.best_trial)

Optunaでハイパーパラメータチューニングを行っているので、パラメータのチューニングに時間はかかりますが、すぐに終わるかと思います。
次は、Optunaで採択されたパラメータで予測を行いましょう。

予測する

先ほど、Optunaを使ってパラメータチューニングを行いました。しかし、先ほどの学習で作られたモデルは保存していませんので、再度モデルを作る必要があります。
加えて、先ほどの学習で得られたパラメータを用いて、予測を行いましょう。

ソースコードは以下になります。予測した結果はcsvファイルに書き込んでいます。

clf = xgb.XGBClassifier(objective='binary:logistic', eval_metric = 'rmse',
                        n_estimators = 6, 
                        learning_rate = 0.1144182440680572, 
                        reg_lambda = 0.10741801759629138)
clf.fit(x_train, y_train) # 学習

# test = pd.read_csv("test.csv", encoding="utf-8") # ブログ冒頭で予測したい本番データを読み込んでいる
y_pred = clf.predict(test)
sub = pd.read_csv('submit_sample.csv', encoding = 'UTF-8', names=['id', 'ans'])
sub['ans'] = list(map(int, y_pred))
sub.to_csv("clientTargeting_XGBoost_0831.csv", header=False, index=False)#ヘッダー無しでcsvに書き込み

提出する

ここまでくれば、後は提出するだけです。

SIGNATEの参加しているコンペティションのWebページに移動し、下図の投稿を押します。 f:id:kurasher:20200902220521p:plain

すると、下のような画面が出てくるかと思います。この画面のフォルダを選択を押して、先ほど書き込んだcsvファイルを選択します。選択したら、同じ画面の投稿ボタンを押すことで、提出できます。 f:id:kurasher:20200902220531p:plain

後は結果を待つだけです。結果は登録してあるメールアドレスに届きますし、しばらくすれば、Webページにも結果が出ます。
ちなみに、提出は1日につき5回までになります。あまり精度が上がらない場合は、無理に提出するのではなく、他の特徴量を考えたりするなどして、工夫を施していきましょう!

1回目の提出結果↓
f:id:kurasher:20200902222549j:plain

ちょこちょこ調整して4回目の提出結果↓
f:id:kurasher:20200902222608j:plain

終結果は70%程度ですね。残り2時間から一応ここまで頑張れました。

コラム:フォーラムを見よう

コンペティションにはフォーラムというところがあります。
f:id:kurasher:20200902220521p:plain

ここでは、今回のコンペティションに参加している方が運営の方へ質問したり、参加者同士で情報を共有するような場所です。もし詰まっていることがあれば、このフォーラムに疑問点を投稿したり、相談したりしてみましょう。

まとめ

もっと、早めに取り組めば昇格が狙えたかもしれません。また次の機会に頑張ります。

ソースコード全体

本記事では記載していない部分もありますが、そこはご容赦ください。

import pandas as pd

train = pd.read_csv("train.csv", encoding="utf-8")
test = pd.read_csv("test.csv", encoding="utf-8")

print(train.dtypes)#型を調べる

from sklearn.preprocessing import LabelEncoder
lbl = LabelEncoder()

nonNumList = ["job", "marital", "education", "default", "housing", "loan", "contact", "month", "poutcome"]

for nonNum in nonNumList:
    lbl.fit( list(train[nonNum].unique()) )
    train[nonNum] = lbl.transform(train[nonNum])
    lbl.fit( list(test[nonNum].unique()) )
    test[nonNum] = lbl.transform(test[nonNum])

# 要素を調べる
print(train.y.unique()) 

# 欠損値を調べる
train.isnull().sum()


##学習
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import optuna
from imblearn.under_sampling import RandomUnderSampler

X = train.drop(["y"], axis = 1)
y = train["y"]

def objective(trial):
    sampler = RandomUnderSampler()
    X_resampled, y_resampled = sampler.fit_resample(X, y)
    #n_estimators
    x_train, x_test, y_train, y_test = train_test_split(X_resampled, y_resampled, test_size=.3) # 訓練データ・テストデータの生成
    estimators = trial.suggest_categorical("n_estimators", [6, 10, 15, 20, 30])
    learning_rate = trial.suggest_uniform('eta', 0.1, 0.2) # 0.2~0.5
    reg_lambda = trial.suggest_uniform('lambda', 0.1, 0.2) # 0.2~0.5
    

    clf = xgb.XGBClassifier(objective='binary:logistic', eval_metric = 'rmse',
                            n_estimators = estimators, 
                            learning_rate = learning_rate, 
                            reg_lambda = reg_lambda)
    clf.fit(x_train, y_train)
    y_pred = clf.predict(x_test)
    
    return clf.score(x_test, y_test)
    
    
study = optuna.create_study()
study.optimize(objective, n_trials=100)
print(study.best_params)
print(study.best_value)
print(study.best_trial)

sampler = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = sampler.fit_resample(X, y)


clf = xgb.XGBClassifier(objective='binary:logistic', eval_metric = 'rmse',
                        n_estimators = 6, 
                        learning_rate = 0.1144182440680572, 
                        reg_lambda = 0.10741801759629138)
clf.fit(X_resampled, y_resampled)

# submmit
y_pred = clf.predict(test)
sub = pd.read_csv('submit_sample.csv', encoding = 'UTF-8', names=['id', 'ans'])
sub['ans'] = list(map(int, y_pred))
sub.to_csv("clientTargeting_XGBoost_0831.csv", header=False, index=False)#ヘッダー無しでcsvに書き込み

参考記事