search
LoginSignup
18

More than 1 year has passed since last update.

posted at

updated at

【Kaggle】とあることから2か月弱でkaggle Expertへ

この記事は、Kaggle Advent Calender 2021 の16日目の記事です

0.はじめに

Advent Calender へは初めて参加いたします。
kaggle を題材に何らか執筆するのも初めてですので、大変神妙な気分です。

今日はみなさまに向けて、私がとあることを始めて2か月弱でkaggle Expert になった経緯を記します。
これからkaggleを始める方、始めて間も無い方や、なかなかメダルが獲得できずにモチベーション維持に悩みを持つ方々に参考になれば。

1.背景

kaggleには2021年7月にアカウントを作成していましたが、チュートリアルの流れで、タイタニック号の生存者予測をしたくらいでした。
そこから約ひと月は何もせずに放置状態でしたし、8月も中旬に入ってからも当時開催中であったコンペにて公開notebookをそのままcopy&submitするというくらいでした。

本格的に?kaggleに向き合ったのは 「30days of ML」 が開催された9月。
ここでも、予測結果はLeaders Board(以下、LB)の遥か下のほうに載る程度です。
続いて参加したコンペも、同様にpublic scoreを上げられずに、LBでは下位を彷徨うのが精いっぱいでした。

2.転機

kaggleを始めてすぐに購入していた、『Kaggleで勝つデータ分析の技術』(技術評論社) を再度読み込んだことです。

章ごとにコンパクトにポイントがまとめられており、かつ、サンプルコードも記載されていることで、kaggleにおけるテーブルデータ・コンペの対策について理解を深めるに至りました。

それまでは、公開notebookをcopyしてきては充分にコードの内容を理解もせずに、僅かにコードを修正しただけでsubmitしていましたので、public scoreも上がる訳がありません。
scoreが上がらなければ、モチベーションの維持も難しくなります。

しかし、上述の書籍を読み込み、サンプルコードを参考にしつつも自身でイチからコードを組むことにより、コードへの理解もすすみ、scoreはなかなか上がらなかったものの、コンペに参加するモチベーションを維持できるようになりました。

3.きっかけ

公開notebookに対して、コンペ参加者からupvoteすることができます。
コンペの後半にLB上位に入るnotebookを公開すると、瞬く間にupvoteされていき、そのnotebookにbronze→silver→goldとメダルの色が変わっていきます。
この仕組みをしっかり理解した際に、ダメ元で自身が作成したnotebookを公開してみようと思ったのが、標題に至ったきっかけです。

さすがに、kaggleをはじめて3か月ほど、かつ、大学も文系学部出身で統計学や情報工学を学んだ訳でもなく、データ分析の初心者の初心者に、LBで上位に食い込むようなnotebookは作れません!🥺

ならば、コンペの序盤に、何の工夫も特徴も無いベースまたはプロトタイプといったnotebookを公開しても、少しではあれどupvoteしてもらえるのではと考えました。
(事実、コンペの序盤にはそういったnotebookでもupvoteされていることには気付いていました。)

4.結果

9月の後半に、恐る恐るでしたが、とあるコンペにて実際に自身でイチから作成したベースと言うべきnotebookを公開してみました。
本当に簡単なつくりの特段の工夫も無いnotebookです。

しかしながら、公開して数日間でupvote=6を記録してbrozeメダル 🥉を獲得するに至りました。
コンペではメダルを獲得していませんでしたので、(discussion以外では)初のメダル獲得 🥉です! ヤッタネ!!🙌

続けて、同じコンペでCross Validationを加えたり、学習器を変えたり(GBDT、線形回帰、ニューラルネットワーク)したnotebookを公開すると、それらも日をかけて徐々にupvoteが増えていきました。

また、予測結果ファイル(例:submission.csv)のみ提出するタイプのコンペでは、Google Collaboratoryで学習・予測を実行するための特別な処理・設定を入れたnotebookも公開しました。
※kaggle APIを利用して、予測ファイルの提出を自動化しました。
嬉しいことに、こちらも少しずつupvoteを頂きました。

 

別のコンペに入っても、序盤に幾つかのベースとなるnotebookを公開することで、upvoteを得ることができました。

11月の中旬、bronzeメダル 5つ🥉🥉🥉🥉🥉を獲得して、Notebooks Expert への昇格を果たしました!!

⇒ 2021年12月1日現在、公開したnotebook:11本、総獲得upvote:101

 
notebookを公開しはじめてからここまで、2か月弱。

Conpetition Expert ではありませんが、立派な Expert です! (自惚れ💧)

まだコンペでメダルを獲得していない方は、notebookを公開することでメダルを獲得してみませんか?

5.今後の目標

もちろん、コンペでのメダル獲得×2 ⇒ Conpetition Expert昇格 です!

より一層、機械学習の理解を深め、コンペの対策を詰めて、LB上位に登れるよう精進いたします。

 

kaggle_profile_20211201.png

 

-参考-

公開したnotebookの一部  ★private sharingに抵触しないよう、一部、コンペ固有の情報は伏せてあります。
  • kaggle kernel用
# Libraries
!pip install -U lightautoml

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import torch
from lightautoml.automl.presets.tabular_presets import TabularAutoML
from lightautoml.tasks import Task

import os
for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

# Warningの無効化
import warnings
warnings.filterwarnings("ignore")

# データフレームcolumの全表示
pd.set_option("display.max_columns", None)

# for reproducibility
np.random.seed(RANDOM_STATE)
torch.set_num_threads(N_THREADS)


# Load Data
DEBUG = False
train = pd.read_csv("../input/xxxxxxxxxx/train.csv")
test  = pd.read_csv("../input/xxxxxxxxxx/test.csv")
submission = pd.read_csv("../input/xxxxxxxxxx/sample_submission.csv")
if DEBUG:
    train = train[:80*1000]

train.shape, test.shape, submission.shape

display(train)

test["pressure"] = 0
display(test)


# Add Feature
def add_features(df):
    # (省略)
    return df

train = add_features(train)
test = add_features(test)


# LightAutoML model building
task = Task("reg", loss="mae", metric="mae")

roles = {
    'drop': "id",
    'group': "breath_id", # for group k-fold
    'target': TARGET_NAME
}

%%time
# Fitting
automl = TabularAutoML(task=task, 
                       timeout=TIMEOUT,
                       cpu_limit=N_THREADS,
                       reader_params={"n_jobs": N_THREADS, "cv": N_FOLDS, "random_state": RANDOM_STATE},
                       general_params={"use_algos": [["lgb", "lgb_tuned", "linear_l2"]]},
                       tuning_params={"max_tuning_time": 1800}
                      )
automl.fit_predict(train, roles=roles)

# Prediction
test_pred = automl.predict(test)

display(test_pred)

submission[TARGET_NAME] = test_pred.data[:, 0]

fi_score = automl.get_feature_scores("fast").sort_values("Importance", ascending=True)

plt.figure(figsize=(10, 30))
fi_score.set_index("Feature")["Importance"].plot.barh(fontsize=16)
plt.title("Feature importance", fontsize=18)
plt.show()

display(submission)

submission.to_csv("submission.csv", index=False)

 

  • Google Colaboratory用
# Libraries
!pip install kaggle

import numpy as np
import pandas as pd
import tensorflow as tf
import gc
import matplotlib.pyplot as plt
%matplotlib inline
from tensorflow import keras
from tensorflow.keras.layers import *
from tensorflow.keras import *
from tensorflow.keras.callbacks import LearningRateScheduler
from tensorflow.keras.optimizers.schedules import ExponentialDecay
from sklearn.preprocessing import RobustScaler, normalize
from sklearn.model_selection import train_test_split, KFold
from sklearn.metrics import mean_absolute_error
from pickle import load

import os

# Warningの無効化
import warnings
warnings.filterwarnings("ignore")

# データフレームcolumの全表示
pd.set_option("display.max_columns", None)


# Load Data
from google.colab import files

uploaded = files.upload()

for fn in uploaded.keys():
    print("User uploaded file '{name}' with length {length} bytes".format(
        name=fn, length=len(uploaded[fn])))

# Then move kaggle.json into the folder where the API expects to find it. ##
!mkdir -p ~/.kaggle/ && mv kaggle.json ~/.kaggle/ && chmod 600 ~/.kaggle/kaggle.json

!kaggle competitions list

!kaggle competitions download -c xxxxxxxxxx


DEBUG = False
train = pd.read_csv(r"../content/train.csv.zip")
test  = pd.read_csv(r"../content/test.csv.zip")
submission = pd.read_csv(r"../content/sample_submission.csv.zip")
if DEBUG:
    train = train[:80*1000]

train.shape, test.shape, submission.shape

display(train)

display(test)


# Add Feature
def add_features(df):
    # (省略)
    return df

train = add_features(train)
test = add_features(test)


targets = train["pressure"].to_numpy().reshape(-1, 80)
train.drop(labels="pressure", axis=1, inplace=True)
train = add_features(train)
# normalize the dataset
RS = RobustScaler()
train = RS.fit_transform(train)

# Reshape to group 80 timesteps for each breath ID
train = train.reshape(-1, 80, train.shape[-1])

test = add_features(test)
test = RS.transform(test)
test = test.reshape(-1, 80, test.shape[-1])

train.shape, test.shape


# Model Creation
def create_lstm_model():

    x0 = tf.keras.layers.Input(shape=(train.shape[-2], train.shape[-1]))  

    lstm_layers = 4 # number of LSTM layers
    lstm_units = [320, 305, 304, 229]
    lstm = Bidirectional(keras.layers.LSTM(lstm_units[0], return_sequences=True))(x0)
    for i in range(lstm_layers-1):
        lstm = Bidirectional(keras.layers.LSTM(lstm_units[i+1], return_sequences=True))(lstm)    
    lstm = Dropout(0.001)(lstm)
    lstm = Dense(100, activation='relu')(lstm)
    lstm = Dense(1)(lstm)

    model = keras.Model(inputs=x0, outputs=lstm)
    model.compile(optimizer="adam", loss="mae")

    return model


# Training
# Function to get hardware strategy
def get_hardware_strategy():
    try:
        # TPU detection. No parameters necessary if TPU_NAME environment variable is
        # set: this is always the case on Kaggle.
        tpu = tf.distribute.cluster_resolver.TPUClusterResolver()
        print("Running on TPU ", tpu.master())
    except ValueError:
        tpu = None

    if tpu:
        tf.config.experimental_connect_to_cluster(tpu)
        tf.tpu.experimental.initialize_tpu_system(tpu)
        strategy = tf.distribute.experimental.TPUStrategy(tpu)
        tf.config.optimizer.set_jit(True)
    else:
        # Default distribution strategy in Tensorflow. Works on CPU and single GPU.
        strategy = tf.distribute.get_strategy()

    return tpu, strategy

tpu, strategy = get_hardware_strategy()


EPOCH = 350
BATCH_SIZE = 512
NFOLDS = 5

with strategy.scope():
    kf = KFold(n_splits=NFOLDS, shuffle=True, random_state=2021)
    history = []
    test_preds = []
    for fold, (train_idx, test_idx) in enumerate(kf.split(train, targets)):
        print("-"*15, ">", f"Fold {fold+1}", "<", "-"*15)
        X_train, X_valid = train[train_idx], train[test_idx]
        y_train, y_valid = targets[train_idx], targets[test_idx]
        model = create_lstm_model()
        model.compile(optimizer="adam", loss="mae", metrics=[tf.keras.metrics.MeanAbsolutePercentageError()])

        scheduler = ExponentialDecay(1e-3, 400*((len(train)*0.8)/BATCH_SIZE), 1e-5)
        lr = LearningRateScheduler(scheduler, verbose=0)

        history.append(model.fit(X_train, y_train, 
                                 validation_data=(X_valid, y_valid), 
                                 epochs=EPOCH, batch_size=BATCH_SIZE, callbacks=[lr]))
        test_pred = model.predict(test).squeeze().reshape(-1, 1).squeeze()
        test_preds.append(test_pred)    

        # save model
        #model.save("lstm_model_fold_{}".format(fold))

        del X_train, X_valid, y_train, y_valid, model
        gc.collect()


# Export && Submission
submission["pressure"] = sum(test_preds)/5
submission.to_csv('submission.csv', index=False)
print('./submission.csv')

display(submission)

!kaggle competitions submit -c ventilator-pressure-prediction -f submission.csv -m "xxxxx Message xxxxx"

参考書籍

以上

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
18