データ分析に挑戦してみます!
SIGNATEの練習問題にある銀行の定期預金予測です。
https://signate.jp/competitions/1
データのダウンロードを行ってからスタートします。
Contents
データの読み込み
まずは、よく使うライブラリをimportするところから。もうこれ今後のテンプレートとして使っていこうかな・・・?
# データ操作系
import pandas as pd
import numpy as np
import collections
# グラフ描画系
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
# 前処理
import sklearn.preprocessing as sp
# データ分割
from sklearn.model_selection import KFold
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_validate
# 機械学習モデル
from sklearn.linear_model import LogisticRegression # ロジスティック回帰
from sklearn.ensemble import RandomForestClassifier # ランダムフォレスト
from sklearn.svm import SVC # SVM
import lightgbm as lgb #LightGBM
import xgboost as xgb
from catboost import CatBoost
from catboost import CatBoostClassifier
from catboost import Pool
# チューニング
from sklearn import metrics
import optuna
# 制御系
import warnings
warnings.simplefilter('ignore')
import gc
そして、データを読み込んでデータを把握するところをやってみます。
!ls
# submit_sample.csv test.csv train.csv
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
sample = pd.read_csv("submit_sample.csv")
読み込んだらすかさずデータの把握をしに行きましょう。
# 先頭5行の表示
train.head()
test.head()
sample.head()
# データの大きさチェック
train.shape
test.shape
sample.shape
# 欠損値の確認
train.isnull().sum()
test.isnull().sum()
sample.isnull().sum()
実際に上記で確認すると、カラムは以下のようになっていました。
変数 | 内容 |
id | インデックス |
age | 年齢 |
job | 職業 |
material | 結婚しているか? |
education | 学歴 |
default | 債務不履行があるか? |
balance | 年間平均残高 |
housing | 住宅ローン |
loan | 個人ローン |
contact | 連絡方法 |
day | 最終接触日 |
month | 最終接触月 |
duration | 最終接触時間 |
campaign | 現キャンペーンの接触回数 |
pdays | 前キャンペーン接触からの日数 |
previous | 現キャンペーン前に顧客に接触した回数 |
poutcome | 前回キャンペーンの成果 |
y | (目的変数)定額預金申し込みするか? |
目的変数であるyはtrainには存在していて、testには存在していません。今回はこのyを予測することになります。
特徴量エンジニアリング
データの結合
trainとtestを同時に処理するために一時的に結合します。
data = pd.concat([train, test], sort=False)
print(len(train), len(test), len(data))
data.isnull().sum()
長さの検算と欠損の検算も忘れずにやっておいたほうが良いみたいです。
まずはデータの全体像を確認します。
train.describe()
train.describe(include='O')
今回は、年齢が60歳かどうか?のカラムだけ追加してやってみます。
data['isRetire'] = 0
data.loc[data['age'] == 60, 'isRetire'] = 1
あとは、LabelEncoder()というものを使って、文字列を数値に変換しておきます。
categorical_features = ['job', 'marital', 'education','default','housing','loan','contact','month','poutcome']
for i in categorical_features:
label_encoder = sp.LabelEncoder()
label_encoder.fit(data[i])
label_encoder.transform(data[i])
data[i]=label_encoder.transform(data[i])
相関の確認
相関はここら辺で確認します。
data.corr()
sns.heatmap(data.corr(),cmap="Reds")
sns.clustermap(data.corr())
採用するカラムの決定
相関からblanceとpdaysとidとdefaultはあまりyに関係なさそうだったので、採用しないことにしました。
同時にカテゴリ変数だけ集めてcategorical_featuresに入れておきます。
adopt_columns = ['age', 'job', 'marital', 'education',
'housing', 'loan', 'contact', 'day', 'month', 'duration', 'campaign',
'previous', 'poutcome', 'y',"isRetire"]
categorical_features = ['job', 'marital', 'education','housing','loan','contact','month','poutcome',"isRetire"]
adopt_data = data[adopt_columns]
adopt_data.head()
機械学習モデルの作成
データ分割
まずは、データを元に戻しておきます。
train = adopt_data[:len(train)]
test = adopt_data[len(train):]
次に、データに名前をつけます。
y_train = train['y']
X_train = train.drop('y', axis=1)
X_test = test.drop('y', axis=1)
評価関数
def get_evaluate(y_test, predict):
fpr, tpr, thr_arr = metrics.roc_curve(y_test, predict)
accuracy = metrics.auc(fpr, tpr)
roc = metrics.roc_auc_score(y_test, predict)
return roc
評価関数を定義しています。詳しくは次のブログで紹介しています。
LightGBT
今回はLightGBTとXGboostとCatboostという3つの勾配ブースティングを用い、最後にアンサンブルします。
cv = StratifiedKFold(n_splits=4, shuffle=True, random_state=0)
roc_list = []
for train_index, test_index in cv.split(X_train, y_train):
X_tr = X_train.iloc[train_index]
y_tr = y_train.iloc[train_index]
X_va = X_train.iloc[test_index]
y_va = y_train.iloc[test_index]
lgb_train = lgb.Dataset(X_tr, y_tr, categorical_feature=categorical_features)
lgb_test = lgb.Dataset(X_test)
params = {
'metric' :'auc',
'objective': 'binary'
}
clf = lgb.train(params, lgb_train,100)
y_predict = clf.predict(X_va, num_iteration=clf.best_iteration)
roc= get_evaluate(y_va, y_predict)
print('roc:{}'.format(roc))
roc_list.append(roc)
print('Kfold平均 roc:{}'.format(np.mean(roc_list)))
y_predict
xgboost
cv = StratifiedKFold(n_splits=4, shuffle=True, random_state=0)
roc_list = []
for train_index, test_index in cv.split(X_train, y_train):
X_tr = X_train.iloc[train_index]
y_tr = y_train.iloc[train_index]
X_va = X_train.iloc[test_index]
y_va = y_train.iloc[test_index]
dtrain = xgb.DMatrix(X_tr, label=y_tr)
dvalid = xgb.DMatrix(X_va, label=y_va)
param = {'objective': 'binary:logistic'}
clf = xgb.train(param, dtrain, 100)
y_predict = clf.predict(dvalid)
print(y_predict[:20])
print(y_predict.__class__)
print(y_predict.shape)
print(y_va.shape)
roc= get_evaluate(y_va, y_predict)
print('roc:{}'.format(roc))
roc_list.append(roc)
print('Kfold平均 roc:{}'.format(np.mean(roc_list)))
y_predict
Catboost
cv = StratifiedKFold(n_splits=4, shuffle=True, random_state=0)
roc_list = []
for train_index, test_index in cv.split(X_train, y_train):
X_tr = X_train.iloc[train_index]
y_tr = y_train.iloc[train_index]
X_va = X_train.iloc[test_index]
y_va = y_train.iloc[test_index]
ctrain = Pool(X_tr, label=y_tr)
cvalid = Pool(X_va, label=y_va)
clf = CatBoost()
clf.fit(ctrain)
y_predict = clf.predict(cvalid,prediction_type='RawFormulaVal')
roc= get_evaluate(y_va, y_predict)
print('roc:{}'.format(roc))
roc_list.append(roc)
print('Kfold平均 roc:{}'.format(np.mean(roc_list)))
catboostについてはこちら
アンサンブル
# emsanble
## datas
lgb_train = lgb.Dataset(X_train, y_train, categorical_feature=categorical_features)
dtrain = xgb.DMatrix(X_train, label=y_train)
ctrain = Pool(X_train, label=y_train)
lgb_test = lgb.Dataset(X_test)
d_test = xgb.DMatrix(X_test)
c_test = Pool(X_test)
## params
lgb_params = {'objective': 'binary'}
xgb_params = {'objective': 'binary:logitraw'}
cat_params = {'iterations' : 100}
## train fit
lgb_clf= lgb.train(best_params, lgb_train)
xgb_clf = xgb.train(xgb_params, dtrain, 100)
cat_clf = CatBoost(cat_params)
cat_clf.fit(ctrain)
## predict
y_p1 = lgb_clf.predict(X_test, num_iteration=lgb_clf.best_iteration)
y_p2 = xgb_clf.predict(d_test)
y_p3 = cat_clf.predict(c_test,prediction_type='RawFormulaVal')
## emsamble
def get_one(bin):
return np.max(bin)
emsamble = [get_one([y_p1[i],y_p2[i],y_p3[i]]) for i in range(len(y_p1))]
今回は検出率が高い方が良い成績になるようなので、一番高い評価をしたモデルの結果を採用しました。
提出準備
test["y"] = emsamble
test["y"].to_csv("sub.csv", index=True, header=False)
!cat sub.csv
ここで内容に問題なければ提出です。
上記のコードで、スコアは0.8537626でした!
コメント