【Kaggle入門ー二値分類】Santander Customer Transaction Prediction-lightgbm

※アフィリエイト広告を利用しています。

はじめに

Kaggleは、英語のページしかありません。そこで、日本語で読みたい方向けに記事を作成しました。

Santander Customer Transaction Predictionの概要の説明が前の記事で済みました。

実際にGoogle Colabを動かしてみましょう!

データのインポート

ドライブをマウントしてください。

from google.colab import drive
drive.mount('/content/drive')

必要なものをインポートします。

import datetime
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns 
import lightgbm as lgb


import warnings
warnings.filterwarnings('ignore')
%matplotlib inline

from sklearn.metrics import roc_auc_score, roc_curve
from sklearn.model_selection import StratifiedKFold

そして、データをインポートします。

train_df = pd.read_csv('/content/drive/MyDrive/kaggle/Santander/train.csv')
test_df = pd.read_csv ('/content/drive/MyDrive/kaggle/Santander/test.csv')

注意‘/kaggle/Santander/train.csv’←の部分はドライブのフォルダ構成によって内容が異なるので注意してください。

train_df.shape, test_df.shape

データは非正規化されており、各行には数字だけで識別された200個の数値var_0~var_199)が含まれています。

データの確認

データの欠落データの種類を確認します。

missing_dataという関数を作成します。

def missing_data(data):
    total = data.isnull().sum()
    percent = (data.isnull().sum()/data.isnull().count()*100)
    tt = pd.concat([total,percent],axis=1,keys=['Total','Percent'])
    types = []
    for col in data.columns:
        dtype = str(data[col].dtype)
        types.append(dtype)
    tt['Types'] = types
    return(np.transpose(tt))
missing_data(train_df)

データの欠落はありません。

また、データの種類は、ID_codeobject型targetint64型var_float64型です。

EDA

データの統計量をみてみましょう。

train_df.describe()
test_df.describe()

散布図で確認します。

def plot_feature_scatter(df1,df2,features):
    i = 0
    sns.set_style('darkgrid')
    plt.figure()
    fig,ax = plt.subplots(4,4,figsize=(14,14))

    for feature in features:
        i += 1
        plt.subplot(4,4,i)
        plt.scatter(df1[feature],df2[feature],marker='+')
        plt.xlabel(feature,fontsize=9)
    plt.show();

データの5%(var_0~var_15)だけ、散布図を表示します。

features = ['var_0', 'var_1','var_2','var_3', 'var_4', 'var_5', 'var_6', 'var_7', 
           'var_8', 'var_9', 'var_10','var_11','var_12', 'var_13', 'var_14', 'var_15', 
           ]
plot_feature_scatter(train_df[::20],test_df[::20], features)

‘target’を0と1の総数を確認します。

sns.countplot(train_df['target'],palette='Set3')

データの変数の密度を示す関数を作成します。

def plot_feature_distribution(df1, df2, label1, label2, features):
    i = 0
    sns.set_style('whitegrid')
    plt.figure()
    fig, ax = plt.subplots(10,10,figsize=(18,22))

    for feature in features:
        i += 1
        plt.subplot(10,10,i)
        sns.distplot(df1[feature], hist=False,label=label1)
        sns.distplot(df2[feature], hist=False,label=label2)
        plt.xlabel(feature, fontsize=9)
        locs, labels = plt.xticks()
        plt.tick_params(axis='x', which='major', labelsize=6, pad=-6)
        plt.tick_params(axis='y', which='major', labelsize=6)
    plt.show();

最初の100個(var_0~var_99)を表示します。

t0 = train_df.loc[train_df['target']==0]
t1 = train_df.loc[train_df['target']==1]
features = train_df.columns.values[2:102]
plot_feature_distribution(t0,t1,'0','1',features)
一部抜粋

次の100個(var_100~var_199)を表示します。

features = train_df.columns.values[102:202]
plot_feature_distribution(t0, t1, '0', '1', features)
一部抜粋

2つの目標値(targetの0,1)に対して、著しく分布が異なる特徴量相当数存在することがわかる。

例えば、var_0, var_1, var_2, var_5, var_9, var_13, var_106, var_109, var_139などである。

特徴量の作成

trainデータのカラムから、ID_codetargetを落として、特徴量とする。

features = [c for c in train_df.columns if c not in ['ID_code', 'target']]
target = train_df['target']

モデルの作成と実行

param = {
    'bagging_freq': 5,
    'bagging_fraction': 0.4,
    'boost_from_average':'false',
    'boost': 'gbdt',
    'feature_fraction': 0.05,
    'learning_rate': 0.01,
    'max_depth': -1,  
    'metric':'auc',
    'min_data_in_leaf': 80,
    'min_sum_hessian_in_leaf': 10.0,
    'num_leaves': 13,
    'num_threads': 8,
    'tree_learner': 'serial',
    'objective': 'binary', 
    'verbosity': 1
}
folds = StratifiedKFold(n_splits=10, shuffle=True, random_state=44000)
oof = np.zeros(len(train_df))
predictions = np.zeros(len(test_df))
feature_importance_df = pd.DataFrame()

for fold_, (trn_idx, val_idx) in enumerate(folds.split(train_df.values, target.values)):
    print("Fold {}".format(fold_))
    trn_data = lgb.Dataset(train_df.iloc[trn_idx][features], label=target.iloc[trn_idx])
    val_data = lgb.Dataset(train_df.iloc[val_idx][features], label=target.iloc[val_idx])

    num_round = 1000000
    clf = lgb.train(param, trn_data, num_round, valid_sets = [trn_data, val_data], verbose_eval=1000, early_stopping_rounds = 3000)
    oof[val_idx] = clf.predict(train_df.iloc[val_idx][features], num_iteration=clf.best_iteration)
    
    fold_importance_df = pd.DataFrame()
    fold_importance_df["Feature"] = features
    fold_importance_df["importance"] = clf.feature_importance()
    fold_importance_df["fold"] = fold_ + 1
    feature_importance_df = pd.concat([feature_importance_df, fold_importance_df], axis=0)
    
    predictions += clf.predict(test_df[features], num_iteration=clf.best_iteration) / folds.n_splits

print("CV score: {:<8.5f}".format(roc_auc_score(target, oof)))

特徴量の重要性をみてみます。

cols = (feature_importance_df[["Feature", "importance"]]
        .groupby("Feature")
        .mean()
        .sort_values(by="importance", ascending=False)[:150].index)
best_features = feature_importance_df.loc[feature_importance_df.Feature.isin(cols)]

plt.figure(figsize=(14,28))
sns.barplot(x="importance", y="Feature", data=best_features.sort_values(by="importance",ascending=False))
plt.title('Features importance (averaged/folds)')
plt.tight_layout()
plt.savefig('FI.png')
*一部抜粋

ファイルの提出

sub_df = pd.DataFrame({'ID_code':test_df['ID_code'].values})
sub_df['target'] = predictions
sub_df.to_csv('submission.csv',index=False)

Kaggleで悩んだら

「Kaggle で勝つデータ分析の技術」

データ分析の最も有名なコンペティションプラットフォームであるKaggleにおけるテクニックや事例を、現時点で最新のものを整理した書籍。特徴量の作り方バリデーションパラメータチューニングなどについて、一般的な書籍ではあまり言及されないポイント等に解説。
>>【書評】Kaggleで勝つデータ分析の技術

以下の書籍は、Kaggleを始める方には本当にオススメの書籍です。Kaggleわからないこと悩んだことがあった方は、購入を検討してみください。

本だけでは物足りないという方は、動画のプラットフォームで学ぶこともオススメです。興味がございましたら、以下の無料オンライン説明会に参加してみてはいかがでしょうか。