LoginSignup
8
5

More than 5 years have passed since last update.

KaggleのKernelを通知する

Last updated at Posted at 2019-04-10

概要

最近のKaggleのコンペティションでは、コンペ終了直前に上位者が激強Kernelや激強DiscussionでLeaderboardを荒らすことがたまにあります。

Kernelが公開されてからなるべく早く反応できるよう、Line Notifyを利用して、通知システムを作ろうと思いました。今回はu++さんのKaggle APIとLINE APIを用いたKernelの新規投稿を通知する仕組みの構築を参考に、システムを構築しました。

通知例

全体の流れ

  • Kaggle APIを使ってKernelのリストを取得する
  • 取得したKernelのリストをGoogleスプレッドシートに保存する
  • 新しいKernelが増えている場合はLine Notifyで通知を行う

この記事では、コードを部分的に紹介するので、全てのコードが欲しい場合はGitHubから取っていってください。

Kaggle API

今回はKaggleが公式で提供しているKaggle APIを使用します。使い方はGitHubのREADMEに詳しく書いてあります。
https://github.com/Kaggle/kaggle-api

pip install kaggleでインストールできます。

APIを使用するには、更にAPI Tokenを設定する必要があります。

Kaggleの自分のプロフィールページのAccountにあるCreate New API Tokenを押すとjsonファイルがダウンロードされます。
スクリーンショット 2019-04-10 9.22.17.png

ダウンロードされたjsonファイルには、自分のユーザ名とトークンが記述されています。このjsonファイルを~/.kaggleというディレクトリを作って入れるだけでAPIが使えるようになります。

今回使用するのは、Kernelsに関するAPIです。例えば、santanderのコンペのカーネルを新しい順に表示したい場合、以下のようなコマンドを入力します。

$ kaggle kernels list --competition santander-customer-transaction-prediction --sort-by 'dateCreated'

ref                                                           title                                               author              lastRunTime          totalVotes  
------------------------------------------------------------  --------------------------------------------------  ------------------  -------------------  ----------  
kanugeete/5-fold-classification-on-a-simple-neural-network    5-fold Classification on a Simple Neural network    kanugeete           2019-04-09 18:54:34           0  
darbin/logit-for-200-pca-features                             Logit for 200 PCA features                          Ilya Khristoforov   2019-04-09 06:01:56           4  
tasnimfatima/lgbm-with-no-augmentation                        LGBM with no Augmentation                           Tasnim              2019-04-09 05:55:02           1  
mhviraf/what-a-decision-tree-cannot-see                       What a decision tree cannot see?                    mhviraf             2019-04-09 06:43:10          52  
elcaiseri/simple-gnb-and-pipeline-model-with-eda              Simple gnb And pipeline Model With EDA              Kassem              2019-04-08 23:18:18           6  
manishks/kernelee24d12c85                                     kernelee24d12c85                                    manish kumar singh  2019-04-08 13:16:40           0  
sandeepkumar121995/santander-customer-transaction-prediction  Santander Customer Transaction Prediction           Sandeep Kumar       2019-04-08 11:19:28           5  
subodanirodrigo/xgboost-for-santander-customer-transaction    XGBoost for Santander Customer Transaction          Subodani Rodrigo    2019-04-08 09:59:12           0  
leonyang/blending-all                                         blending_all                                        leonyang            2019-04-09 02:04:12           0  
danmoller/funny-pattern-with-non-perfectly-round-numbers      Funny pattern with non-perfectly round numbers      Daniel Möller       2019-04-08 08:34:07           5  
kmezhoud/a-simple-xgboost-application                         A simple xgboost application                        Karim Mezhoud       2019-04-09 19:06:45           8  
vikasmalhotra08/feature-binning-using-bayesian-blocks         Feature Binning using Bayesian Blocks               Vikas Malhotra      2019-04-07 16:17:25           8  
pranaydugar/dense-net-2-gaussian-difference-features          Dense Net 2 (Gaussian Difference Features)          PranayDugar         2019-04-07 11:48:45           1  
rsaund/sant-model-check                                       sant_model_check                                    RSaund              2019-04-07 11:10:02           0  
fuhang/weighted-kernel-naive-bayes-with-lasso-elimination     Weighted Kernel Naive Bayes with Lasso Elimination  Horizon@AI酱         2019-04-08 10:41:07          56  
stevexyu/kfold-convolutional-neural-network                   Kfold Convolutional Neural Network                  Stephen             2019-04-09 15:02:48          21  
lzsraja/kernal-fe-gp-lgbm-keras                               Kernal_fe(GP)+LGBM+Keras                            Zhusong Liu         2019-04-09 18:56:53           0  
maheshak04/simpl                                              Simpl                                               MaheshKulkarni      2019-04-07 10:53:22           0  
yoheiii/bayesian-optimization-for-santandar                   Bayesian Optimization for Santandar                 YOHEI               2019-04-07 06:28:57           7  
dmacgirr/naive-bayes-normalized                               Naive Bayes - normalized                            Dan MacGirr         2019-04-06 15:31:40           0  

これをいい感じに整形します。ぱっと見スペース2つとかでsplitすれば良さそうなので、こんな感じで整形します。とりあえず、記事のurlとタイトルだけ保存します。

import subprocess
proc = subprocess.run("kaggle kernels list --competition santander-customer-transaction-prediction --sort-by 'dateCreated'", shell=True,stdout = subprocess.PIPE, stderr = subprocess.PIPE)
s = proc.stdout.decode("utf8")

kernels = []
rows = s.split("\n")

# スペース2つでlist化、先頭/末尾のスペースを削除
for i in range(len(rows )):
    row = rows[i].split("  ")
    row = [x.strip(" ") for x in row if x]
    kernels.append(row)

# ヘッダとフッタを除外
kernels = kernels[2:-1]
# 使用するパラメータ
use_params = ["url", "title"]
# 古い順にする
kernels = kernels[::-1]
# dictに変える
tmp = [{} for i in range(len(kernels))]
for i, kernel in enumerate(kernels):
    for j, param in enumerate(use_params):
        tmp[i][param] = "https://kaggle.com/" + kernel[j] if param == "url" else kernel[j]
kernels = tmp
print(kernels)

結果を見るといい感じに分けることができています。

[{'url': 'https://kaggle.com/dmacgirr/naive-bayes-normalized',
  'title': 'Naive Bayes - normalized'},
 {'url': 'https://kaggle.com/yoheiii/bayesian-optimization-for-santandar',
  'title': 'Bayesian Optimization for Santandar'},
 {'url': 'https://kaggle.com/maheshak04/simpl', 'title': 'Simpl'},
 {'url': 'https://kaggle.com/lzsraja/kernal-fe-gp-lgbm-keras',
  'title': 'Kernal_fe(GP)+LGBM+Keras'},
 {'url': 'https://kaggle.com/stevexyu/kfold-convolutional-neural-network',
  'title': 'Kfold Convolutional Neural Network'},
 {'url': 'https://kaggle.com/fuhang/weighted-kernel-naive-bayes-with-lasso-elimination',
  'title': 'Weighted Kernel Naive Bayes with Lasso Elimination'},
 {'url': 'https://kaggle.com/rsaund/sant-model-check',
  'title': 'sant_model_check'},
 {'url': 'https://kaggle.com/pranaydugar/dense-net-2-gaussian-difference-features',
  'title': 'Dense Net 2 (Gaussian Difference Features)'},
 {'url': 'https://kaggle.com/vikasmalhotra08/feature-binning-using-bayesian-blocks',
  'title': 'Feature Binning using Bayesian Blocks'},
 {'url': 'https://kaggle.com/kmezhoud/a-simple-xgboost-application',
  'title': 'A simple xgboost application'},
 {'url': 'https://kaggle.com/danmoller/funny-pattern-with-non-perfectly-round-numbers',
  'title': 'Funny pattern with non-perfectly round numbers'},
 {'url': 'https://kaggle.com/leonyang/blending-all', 'title': 'blending_all'},
 {'url': 'https://kaggle.com/subodanirodrigo/xgboost-for-santander-customer-transaction',
  'title': 'XGBoost for Santander Customer Transaction'},
 {'url': 'https://kaggle.com/sandeepkumar121995/santander-customer-transaction-prediction',
  'title': 'Santander Customer Transaction Prediction'},
 {'url': 'https://kaggle.com/manishks/kernelee24d12c85',
  'title': 'kernelee24d12c85'},
 {'url': 'https://kaggle.com/elcaiseri/simple-gnb-and-pipeline-model-with-eda',
  'title': 'Simple gnb And pipeline Model With EDA'},
 {'url': 'https://kaggle.com/mhviraf/what-a-decision-tree-cannot-see',
  'title': 'What a decision tree cannot see?'},
 {'url': 'https://kaggle.com/tasnimfatima/lgbm-with-no-augmentation',
  'title': 'LGBM with no Augmentation'},
 {'url': 'https://kaggle.com/darbin/logit-for-200-pca-features',
  'title': 'Logit for 200 PCA features'},
 {'url': 'https://kaggle.com/kanugeete/5-fold-classification-on-a-simple-neural-network',
  'title': '5-fold Classification on a Simple Neural network'}]

次に取得したカーネルのデータをGoogleスプレッドシートに保存します。

Googleスプレッドシートに保存する

PythonでGoogleスプレッドシートをいじる場合、この記事がわかりやすいと思います。
https://qiita.com/akabei/items/0eac37cb852ad476c6b9
同じような手順でやってみます。

プロジェクト作成

コンソールからプロジェクトを作成します。
https://console.developers.google.com/cloud-resource-manager
プロジェクト名は適当にkaggle-api-notifyにしておきます。

スクリーンショット 2019-04-10 10.12.45.png

プロジェクトにAPIを追加する

左上のナビゲーションメニューから、APIとサービスに移動し、Google DriveとGoogle SheetsのAPIを有効にします。

スクリーンショット 2019-04-10 10.13.29.png

サービスアカウントキー作成

APIとサービスから認証情報に移動し、認証情報を作成、サービスアカウントキーを選択します。

スクリーンショット 2019-04-10 10.15.26.png

サービスアカウント名を適当に決め、役割をProject編集者にします。

スクリーンショット 2019-04-10 20.50.24.png

作成のボタンを押すと、アカウントの情報が記載されたjsonファイルがダウンロードされます。

このファイルで必要なのは、client_emailの項目です。今回の場合、kaggle-api-account@kaggle-api-notify.iam.gserviceaccount.comのようなアカウント名@プロジェクト名.iam.gserviceaccount.comの形式で保存されます。

{
  "type": "service_account",
  "project_id": "kaggle-api-notify",
  "private_key_id": "XXXXXX",
  "private_key": "-----BEGIN PRIVATE KEY-----...,
  "client_email": "kaggle-api-account@kaggle-api-notify.iam.gserviceaccount.com",
  ...
}

読み込んだデータを保存しておく、スプレッドシートを作成します。

jsonファイルから取得したclient_emailをスプレッドシートの右上の共有から編集者として追加します。
スクリーンショット 2019-04-10 20.58.25.png

これでスプレッドシートの設定は完了です。

スプレッドシートをpythonで操作する場合、gspreadをインストールする必要があります。

gspreadのリファレンス
https://gspread.readthedocs.io/en/latest/

今回使用したのは、以下のメソッドです。

メソッド 効果
get_all_values 全ての値をlist形式でもらえる
update_acell 単一セルの編集
update_cells 複数セルの編集

注:update_cellsの引数では、編集する領域を設定し、セル単位で値を入れないといけないので少し面倒

get_all_valuesで保存してあるデータを読み込み、今Kaggle APIで入手した最新の投稿と保存されている最新のKernelが違う場合、スプレッドシートの更新とLineの通知を入れるようにしました。

Line Notifyで通知

Line Notifyというサービスを使用すると、プログラムからLineを簡単に送ることができます。

上のサイトからLineアカウントでログインし、右上のマイページから、アクセストークンを発行することができます。

トークンを発行するボタンを押すと、トークン名(通知の際に表示される名前)と通知を入れたいトークルームを選択することができるので、個人用のトークルームを設定します。チームで参加している場合、チームのトークルームを作成し、通知を入れるといいかもしれません。

スクリーンショット 2019-04-10 21.17.36.png

pythonファイルからは以下のように呼び出します。YOUR TOKENの部分は発行したトークンを入力します。

https://upura.hatenablog.com/entry/kaggle-notification より引用

line.py
def line(Me):
    line_notify_token = 'YOUR TOKEN'
    line_notify_api = 'https://notify-api.line.me/api/notify'
    message = '\n' + Me
    payload = {'message': message}
    headers = {'Authorization': 'Bearer ' + line_notify_token}
    line_notify = requests.post(line_notify_api, data=payload, headers=headers)

Kaggleの通知をする場合、line()の引数に1.で取得したカーネルのタイトルとURLを入力し、通知を行います。

運用

常に通知を受け取れるようにするには、上記の処理をpython等で書いて、n分間隔で実行する必要があります。

私は5分間隔でチェックするようにしましたが、コンペ終盤になると1分間隔とかにした方が良いのかもしれません。

常に起動している必要があるので、Raspberry Piのシェル上で実行するようにしました。以下のように実行しました。

kaggle_api_notify.sh
#!/bin/bash
while true
do
  python3 kaggle_notify.py
  sleep 300
done

この記事の中で一番面倒だった作業がRaspberry Pi上でPythonの環境構築をする部分でした。詳しくはまたの機会に。

Discussionについて

今のKaggleでは、Discussionの投稿やコメントが削除できるので、一部の人だけが有効な情報を手に入れることがあります。今(2019年4月)の段階では、Kaggle APIからDiscussionを取得できないので、
https://www.kaggle.com/forums/130117/topics.json?sortBy=recent&group=all&page=1&pageSize=20&category=allのようなリクエストを飛ばし、json形式で取得するしかありません。しかし、Kaggleの利用規約の4章h,i節あたりがグレーな気がしています。(Kaggle APIを叩いて情報収拾するのもグレーな気がしますが...)

スクリーンショット 2019-04-10 21.33.05.png

Kaggle APIにDiscussionを取得する機能が追加されるか、上記のようなリクエストを飛ばして良いのがわかったらDiscussionの通知/保存機能も検討したいと思います。

GitHub

いろいろ整理中なのでしばしおまちを...
https://github.com/reo11/Kaggle-notify
とりあえず作りました。READMEとこの記事を読めば使えると思います。

使い辛かったり、バグがあったらプルリクお願いします。

8
5
0

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
  3. You can use dark theme
What you can do with signing up
8
5