概要
Kaggleの任意のコンペのPrivate Leaderboardの情報をpd.DataFrameにまとめるスクリプトを作成しました.
このスクリプトを用いて逆転が起きやすいコンペを調査したいと思います.
Private Leaderboardとは
コンペ開催期間中はKaggleのコンペでは与えられているtestデータに対する予測結果をKaggleサーバに送信することで,以下の情報が得られます.
- テストデータの一部(以下テストデータA)で計算される予測精度(public score)
- コンペ参加者全体での上記予測精度の順位(public leaderboard)
コンペ参加者はこの2つの指標をもとに自身の作成したモデルの良し悪しを判断したりするわけです.
しかしコンペ終了時に確定される最終的な順位は,テストデータA以外のテストデータ(以下テストデータB)から計算される予測精度に基づき決定されます.
このテストデータBから計算される予測精度をprivate score,その値から決められる順位をprivate leaderboardと言います.
メダルや賞金が与えられるかどうかもprivate leaderboardの順位で決まるため,Kagglerはpublic scoreが過適合したものでないかどうか常に気にするわけですね.
スクレイピング対象
private leaderboard(下記画像)のうち,以下の項目をpd.DataFrameにまとめるスクリプトを記述しました.
- 順位(#)
- public leaderboardからの変化(△pub)
- チーム名(Team Name)
- 予測精度(Score)
- Submitの回数(Entries)
- 最後にsubmitした時期(Last)
これらの情報のうち,自分は順位とpublic leaderboardの変化(下記画像赤枠部)について今後取り扱っていく予定です.
コード
SeleniumをPythonで実行するためにはwebブラウザのドライバをあらかじめダウンロードしておく必要があります.
Seleniumの環境構築については様々な方が解説してくださっているためそちらをご覧ください.
ちなみに私はgoogle chromeのwebDriverを利用しています.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import pandas as pd
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
# private leaderboardの要素を引数とする.private leaderboardの内容の一部をpd.dataFrameに格納する
def get_private_lb_info(private_lb):
ranklist = []
changelist = []
teamnamelist = []
scorelist = []
entrieslist = []
lastlist = []
for row in private_lb.find_elements_by_tag_name("tr"):
tds = row.find_elements_by_tag_name("td")
if(len(tds) > 7):
ranklist.append(tds[0].text)
if len(tds[1].find_elements_by_class_name("position-change__risen")) > 0:
changelist.append(int(tds[1].find_element_by_class_name("position-change__risen").text))
elif len(tds[1].find_elements_by_class_name("position-change__fallen")) > 0:
changelist.append(-1 * int(tds[1].find_element_by_class_name("position-change__fallen").text))
else:
changelist.append(0)
teamnamelist.append(tds[2].text)
scorelist.append(tds[5].text)
entrieslist.append(tds[6].text)
last_spans = tds[7].find_elements_by_tag_name("span")
if(len(last_spans)> 0):
lastlist.append(last_spans[0].text)
else:
lastlist.append("None")
lb_df = pd.DataFrame([ranklist,changelist,teamnamelist,scorelist,entrieslist,lastlist])
lb_df = lb_df.T
lb_df.columns = ["rank","change","teamname","score","entries","last"]
return lb_df
## main
# あらかじめ用意しているdriverの読み込み
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome('/usr/local/bin/chromedriver',chrome_options=options)
# URLの読み込み
driver.get("https://www.kaggle.com/c/data-science-bowl-2017/leaderboard")
# Private Leaderboardボタンを押し画面表示を切り替える
private_btn = driver.find_element_by_css_selector("[title^='Private Leaderboard']")
private_btn.click()
# 50位以下を表示するボタンを押す処理
load_btn= driver.find_element_by_xpath("//*[@id='site-content']/div[2]/div/div[2]/div/div[2]/div/table/tbody/tr[51]/td/span[2]")
driver.execute_script("arguments[0].click();", load_btn)
# private leaderboardの要素を取得
private_lb = driver.find_element_by_class_name("competition-leaderboard__table")
# private leaderboardの内容をpd.DataFrameに格納する関数の実行
private_lb_df = get_private_lb_info(private_lb)
結果
以下のtableのようなpd.DataFrameが得られます.金メダル圏内かといった情報が入ってないのが今更ながら不便かもと思いました.
rank | change | teamname | score | entries | last |
---|---|---|---|---|---|
1 | 136 | grt123 | 0.39975 | 2 | 3y |
2 | 87 | Julian de Wit & Daniel Hammack | 0.40117 | 2 | 3y |
3 | 23 | Aidence | 0.40127 | 2 | 3y |
4 | 157 | qfpxfd | 0.40183 | 3 | 3y |
5 | 349 | Pierre Fillard (Therapixel) | 0.40409 | 8 | 3y |
6 | 206 | MDai | 0.41629 | 2 | 3y |
7 | 96 | DL Munich | 0.42751 | 2 | 3y |
8 | 78 | Alex |Andre |Gilberto |Shize | 0.43019 | 5 | 3y |
9 | 343 | Deep Breath | 0.43872 | 2 | 3y |
10 | 262 | Owkin Team | 0.44068 | 9 | 3y |
11 | 318 | Cowboy Bebop | 0.44189 | 6 | 3y |
12 | 62 | Daniel FG | 0.44387 | 2 | 3y |
13 | 78 | alex 3 | 0.45555 | 5 | 3y |
14 | 110 | HBIL | 0.45872 | 8 | 3y |
15 | 21 | rmldj | 0.46284 | 2 | 3y |
16 | 311 | Wei Dong & Yuanfang Guan | 0.46481 | 2 | 3y |
17 | 210 | Orion42 | 0.46627 | 7 | 3y |
18 | 252 | jacobkie | 0.46649 | 2 | 3y |
19 | -5 | Magpie | 0.46788 | 5 | 3y |
20 | 22 | jingchenma | 0.46854 | 3 | 3y |