Tak's Notebook

Kaggle, Machine Learning, Data Analytics

Slack と Google Spreadsheet で家計簿管理する

TOC

Slack と Google Spreadsheet で家計簿管理する

Slack に使ったお金を書くと、それが Spreadsheet に記録されるようにしている。

これまでは Zapier を利用していた。一定の利用範囲内で無料で Slack の特定チャンネルに投稿されると その内容を Spreadsheet に転記することができて 便利だった。

ただ、自分の支出管理目的から妻との共同利用目的に移行したため、最近利用頻度が増えてきて 無料枠内では制限に頻繁に引っかかるようになってしまった。

そこで Zapier からの移行を考えたのが 今回の記事を書くきっかけになった。

ちなみに以下のような Slack での投稿が Zapier を通して Spreadsheet に新しい行として書き込まれる

f:id:takaishikawa42:20220216231425p:plain
Slack 投稿画面例

f:id:takaishikawa42:20220216231604p:plain
Spreadsheet への転記例

既存のアプリや共同口座・家族カードではダメな理由

家計は折半で、家のものは基本的には自分が買って 月末にまとめてかかった額の半分を妻に請求する形を取っていた。

しかし、子供が生まれてから妻が家のものを買う機会がそれまで以上に増えたため これまでとはやり方を変える必要が出てきた。

折半するので「何に いくら使って それは誰がどの程度負担するか」を把握する必要がある。

この時点で 既存のアプリで要求を満たすことは難しそうだった。

また、共同口座は自分が調べた限りだと どちらか一方の名義で作る必要があり 不便そうな気がした。(そもそも新規口座開設も面倒...)

家族カードは検討したが、家のものを買うときはこのカード、自分のものを買うときはまた別のカード......とするのも煩雑なので これも気が進む選択肢でなかった。

そのため妻にも、それまで独自の支出管理に使ってた方法に参加してもらうことになった。

実装

Slack の特定チャンネルに送信されたメッセージを Spreadsheet に転記する。

そのために 以下を定期実行したい。

  1. Slack API を利用して Slack メッセージを取得する
  2. 特定期間に投稿されたメッセージのみに絞る
  3. IFTTT の Webhook URL を利用して Google Sheet に上記の絞られた投稿内容を追加する

フローチャートにすると以下のようなイメージ。さっそく Mermaid 記法を試してみた(ref. Include diagrams in your Markdown files with Mermaid | The GitHub Blog)。

f:id:takaishikawa42:20220216205505p:plain
takaiyuk/kakeibo

実装は以下のリポジトリにまとめている。

github.com

Slack メッセージの取得

Web API メソッドのうち conversations.history を利用して特定チャンネルのメッセージを取得する。以下に詳細やその他のメソッドがまとめられている。

Web API methods | Slack

SlackMessage という適当なデータクラスを用意して、以下のようにしてメッセージを取得する。

Pagination のため最新100件のみ取得するが、今回は投稿されるメッセージの頻度は多くないので これで問題ない。

日付の取得はレスポンスが持ってるタイムスタンプを利用して Spreadsheet 側で日付に変換する。そのため データとしてはタイムスタンプで持っておく。

from dataclasses import dataclass

import requests


@dataclass
class SlackMessage:
    ts: float
    text: str


def get_slack_messages(config: Config) -> list[SlackMessage]:
    url = "https://slack.com/api/conversations.history"
    token = config.slack_token
    header = {"Authorization": f"Bearer {token}"}
    channel_id = config.slack_channel_id
    payload = {"channel": channel_id}
    response = requests.get(url, headers=header, params=payload)
    messages = response.json().get("messages")
    slack_messages = [
        SlackMessage(ts=float(message.get("ts")), text=message.get("text"))
        for message in messages
    ]
    return slack_messages

IFTTT の Webhook URL 経由で Spreadsheet に行を追加する

IFTTT が用意した Web API を利用して、何かしらの動作を発火させることができる。

Webhooks works better with IFTTT

ここでは上記の SlackMessage の値をパラメータに持たせて Spreadsheet にそれらをもとにした文字列を書き込ませる。

当然 IFTTT 側での設定も必要だが、実行コードとしては以下のようなイメージになる。

def post_ifttt_webhook(config: Config, slack_messages: list[SlackMessage]) -> None:
    event = config.ifttt_event_name
    token = config.ifttt_webhook_token
    url = f"https://maker.ifttt.com/trigger/{event}/with/key/{token}"
    for message in slack_messages:
        payload = {"value1": message.ts, "value2": message.text}
        requests.post(url, data=payload)

これで Slack で コンビニ,1000,1 といった文字列をそのまま Spreadsheet の特定シートに転記することができる。

AWS Lambda

ここまでで Slack からメッセージを取得し、IFTTT の Webhook API に投げる機能まで出来た。

あとは これを定期実行できるようにするために AWS Lambda を利用する。Event Bridge をトリガーにして簡単に定期的なプラグラムの実行ができる上に、軽い処理なので頻繁に実行しても無料枠に十分収まるため。

ただし requests ライブラリはサードパーティなので別途ローカルディレクトリに用意が必要。Lambda Layer を利用すると、依存パッケージとコードを分離できるので良い。

Lambda レイヤーの作成と共有 - AWS Lambda

python ディレクトリにインストールすると 特別にパスを指定しなくても import できるようになるらしい。

$ mkdir python
$ pip install -t python requests
$ zip -r9 layer.zip python
$ rm -r python

おわりに

IFTTT 側での Google アカウントへの連携が知らぬ間に切れていたエラーにハマったりもしたが、すぐに解決できた。

ということで、難しいこともほとんどなく、Zapier から IFTTT へ移行しても それまでと同等の処理をお金をかけずに実現することができた。

育休取得で1ヶ月経った

概要

2020年末から約6ヶ月の育休を取得した。

そこから約1ヶ月経過したので 思ったことなどを雑多にまとめる。

感想

「もしも一人だったら 育児と家事の両方をどうやって回すんだ、これ」

育休は取った方がいいというよりも取らないとやっていけないのでは?とまで個人的には思った。

会社

育休の相談をしたときにノータイムでいいですよと言ってくれた上長をはじめ、チーム・会社には圧倒的感謝。

買ってよかったもの

電気ケトル

こちらのブログ(Googleに転職していきなり3ヶ月の育休を貰った - Software Transactional Memo)で勧められてるのを見て 購入。温度調節のできる湯沸かし器が欲しかったので。

自動掃除機

食洗機・乾燥機付き洗濯機の他に 自動掃除機があると家事がだいぶ楽になると聞いて購入。

ベビーモニター

こちらのブログ(男性インフラエンジニアが育児休業を取得した話 - エニグモ開発者ブログ)で勧められてるのを見て 相談して購入。安心して寝かしつけができて、夫婦の時間が取れるようになった。

加湿器

www.dainichi-net.co.jp

友人に冬生まれの子供の場合は加湿器必須という助言をもらって購入。

泣きぐずり

泣きぐずりの対策

Work

  • オムツ替え
  • 空腹にさせない
  • 部屋を暗くする
  • 暑過ぎないか
  • 丸まった姿勢

Not work

  • スワルドアップ
  • ホワイトノイズ

気になること・違和感

母乳神話

  • 夜時間帯は母親しか面倒が見ることができなくなる
  • どうしても「母親像」にとらわれてしまう
  • 母乳がミルクよりも優れているのか同程度なのか そのあたりの話の根拠がいまいち分からなかった

育児書は「ママ」が読むものなのか

  • 育児書の主語は親ではなく「ママ」が多い
  • 助産師訪問で電話番号は奥様じゃないけど大丈夫?という質問をされた

読んだブログ

言葉の端々に苦労が垣間見えた。

育休の雰囲気、育児に役立つアイテム、育休中には本当に余裕がないこと、ある程度の諦めが必要なことなどについて事前に知ることができた。

ふむふむと思ったフレーズをメモしていたのでまとめた。

育児休業を支えるあれこれ - エムスリーテックブログ

「育休はバカンスではない」
「完璧を諦める」

パパになったので4か月の育休をとってみた - Adwaysエンジニアブログ

「赤ちゃんには5つの泣き方のパターンがある」
5パターンは分からなかったけど、泣き方から何に対して不快を感じているかが分かるようになってきた感じがする。

一年間の育休から復帰しました - Feedforce Developer Blog

スワドルは自分の子供には今のところフィットしていない。

娘が生まれたので育休をとっています|ばんくし|note

育休取得にあたってのキャリアの悩み、育児の奮闘が率直に書かれている。
引用が多いので参考になった。

仕事大好きエンジニアが半年間パパだけの育休をとった話 - ikuo’s blog

育休中の様子が事細かに書いていて興味深かった。
父親コミュニティがないあたりの話が印象的。

Googleに転職していきなり3ヶ月の育休を貰った - Software Transactional Memo

育児はデバッグ作業に似ているが、3割くらいは根気でなだめるしかない時もあるらしい。

日本のパパに、育休のススメ~私の育休体験記~ - BASEプロダクトチームブログ

「育休はバケーションじゃない」
「育休期間中に育児以外のことをする時間はないと思って間違いないと思います」


2021年良かったもの

2021年良かったもの

ガジェット系

音楽

ラジオ

その他

Bリーグ選手の3Pショットの決め方 アシストと非アシスト


先日 Kirk Goldsberry氏のインスタグラムを見ていたら下記の投稿を見かけた。

これは2013−14シーズン以降のNBA選手の非アシストによる3Pショットの成功数とアシストによる3Pショットの成功数をプロットした画像である。

ここからハーデンはアシストを受けずに3Pを決めていること、一方でトンプソンやJJレディック、カイル・コーバー、ダニー・グリーンのような選手はアシストを受けて3Pを決めていることが読み取れる。

ハーデンは自らのドリブルからショットクリエイトしていること、一方で後者の選手はスクリーンなどを利用してパスを受けてキャッチアンドシュートをしていそうだと解釈できる。

同じことをBリーグでやったらどうなるかが気になったので Play by Play のデータを利用して確認してみた。


Play by Playからのアシスト・非アシストの3Pショットの成功数の抽出方法


Play by Play の記録方法は以下のようになっている。


f:id:takaishikawa42:20210403174527p:plain
Play by Playからの非アシストの3Pショットの成功数


f:id:takaishikawa42:20210403174505p:plain
Play by Playからのアシストの3Pショットの成功数


全てがこのパターンでちゃんと記録されていることを前提に、アシスト・非アシストの3Pショットの成功数は以下の方法で抽出可能そう。

  • 「3Pシュート○」というテキストが入ってると3Pショットが成功したことが分かる
  • 残り時間が少ない順に昇順で並べた場合、「3Pシュート」のひとつ上の項目に「アシスト」があればそのシュートはアシストによる3Pショットの成功であることが分かる

これを利用してアシスト・非アシストのそれぞれの3Pショットの成功数を集計する。


散布図にプロットする


結果は以下のようになった。

f:id:takaishikawa42:20210403174358p:plain
Bリーグ選手の3Pショットの決め方


アシスト・非アシストのそれぞれの3Pショットの成功数が多い選手名を取り上げて図に表示している。赤字の選手は3P成功率上位5名を表している。

また 青線は切片0の線形回帰直線で、平均的なアシスト・非アシストの3Pショットのライン。この青線より右下にいる選手は非アシストの3Pショットが多い、左上にいる選手はアシストの3Pショットが多いことを表す。


ここから読み取れることは以下のとおり

  • 富樫が非アシストの3Pショット成功数が一番多く、アシストの3Pショット成功数に対する非アシストの3Pショット成功数もダントツに多そう。
    • 富樫のドリブルとスクリーンを利用したショットクリエイト力が高いことが分かる(千葉がそういうオフェンスを多用していることもありそう)
  • 金丸の3P成功数はダントツに多い。また、三河の選手はキャッチアンドシュートが多い(ちなみに三河のチームアシスト数は2位)
  • 成功率の高い選手(赤字)はキャッチアンドシュートが多い
    • 成功率の高い選手の中でもディージェイ・ニュービルは非アシストの3Pショット成功数が多いのは特筆すべき点と言えそう
  • 安藤誓哉レイヴォンテ・ライスは成功数こそ少ないものの、非アシストの3Pショット成功数の割合が多い


終わりに


以下で引用したツイートおよび自分のツイートに書かれているとおり、ボックススコアなどでは潰れてしまっている情報が Play by Play のデータには色々記録されている。

例えば「Play by Playからのアシスト・非アシストの3Pショットの成功数の抽出方法」でのPlay by Playのデータ例を見ても、どの段階でどの項目がどれくらいに達したのか(例えば 残り何分・何点差で誰がシュートを決めてその選手が何点目の得点を記録したか など)が分かる。

これを見ても Play by Play データを上手く使いこなせるようになると結構面白いことができそう。


Bリーグでクラッチタイムに強い選手は誰なのか? Part2(TS%)

f:id:takaishikawa42:20210401233610p:plain
クラッチタイムに強い選手 Part2


先日『Bリーグでクラッチタイムに強い選手は誰か?』という記事を書いたが、2Pと3Pを一緒くたにしたフィールドゴールパーセント(FGP)のリフトを見て「クラッチタイムに強い」・「クラッチタイムに弱い」を定義していた。

しかし下記のように、これには課題が浮かんできたので「Bリーグクラッチタイムに強い選手は誰か?」Part2を書く。


クラッチタイムに強い選手」とはどういう選手か?


前回の記事と同様にクラッチタイム」の定義は以下。

  • 4Qの残り5分以降(延長戦までもつれれば延長戦も含む) かつ
  • 得点差が5点差以内

クラッチタイムに強い」を前回はFGPを見て判断していたが、今回はこれをTS%に置き換えて考える。

そこでクラッチタイムに強い」は以下のように定義することにする。

  • 平均TS%に対するクラッチタイムのTS%の比率(TSP_clucth / TSP)

TS%とは True Shooting Percentage の略で、2Pフィールドゴール・3Pシュートフィールドゴールに加えてフリースローも考慮したシュート効率を表した指標のこと。

一般的に以下の計算式で表される。

TS% = (PTS) / (2 * (FGA + 0.44 * FTA)) * 100

ここで注意したいのが FTA の係数の 0.44 という数値。これはあくまで慣例的なもので その数値の根拠が現代のBリーグにも当てはまるかは疑問が残るところだが、ここでは一旦議論せず慣例的な計算式を利用する。

詳しい議論やBリーグ版のTS%の求め方については、こちらのブログを参照すると良さそう。

『Bリーグ版TS%を作りたい!』

また、今回は成功率だけでなく、チームの中でクラッチタイムにショットを任されている選手を見たいので 試投数も集計する。


細かいデータや集計条件について


データはBリーグの試合結果のPlay by Playを利用した。

またデータの集計条件を以下のように定めた。今回はシュート成功率で見るので出場試合数やシュート試投数が少ない選手を除いた。

  • 集計データは2020-21シーズンの3/21までのデータに限る
  • そのうち36試合(消化試合数の80%)以上に出場、かつFG試投数が72本(試合平均2本以上)以上の選手
  • さらにクラッチタイムのFG試投数が10本以上の選手


クラッチタイムのTS%が高い選手・低い選手


結果は以下のようになった。


クラッチタイムのTS%が高い選手


TSP_lift
Player NameShort
晴山 ケビン 滋賀 1.52
大崎 裕太 信州 1.50
篠山 竜青 川崎 1.47
安藤 周人 名古屋D 1.44
ジョナサン・オクテウス 滋賀 1.41
藤井 祐眞 川崎 1.37
長野 誠史 三河 1.34
多嶋 朝飛 北海道 1.34
古川 孝敏 秋田 1.31
ジェフ・エアーズ 名古屋D 1.29
ジャワッド・ウィリアムズ 北海道 1.28
五十嵐 圭 新潟 1.25
金丸 晃輔 三河 1.25
宇都 直輝 富山 1.25
パトリック・アウダ 横浜 1.24
並里 成 琉球 1.24
レオ・ライオンズ 名古屋D 1.23
ロスコ・アレン 新潟 1.22
納見 悠仁 新潟 1.21
西山 達哉 信州 1.21


詳細なデータは以下(画像)

...
クラッチタイムのTS%が高い選手


前回に比べて、3P・フリースローが加味されているので、フリースローが苦手な選手の順位が落ち、逆に3Pが得意な選手の順位が伸びているように見える。

五十嵐や金丸が前回は上位20名には入っていなかったが、今回のランキングには入ってきた。


クラッチタイムのTS%が低い選手


TSP_lift
Player NameShort
アイラ・ブラウン 大阪 0.83
前田 悟 富山 0.83
齋藤 拓実 名古屋D 0.82
シャノン・ショーター 千葉 0.80
パブロ・アギラール 川崎 0.79
ライアン・ロシター 宇都宮 0.77
アキ・チェンバース 横浜 0.77
ベンドラメ 礼生 SR渋谷 0.77
狩俣 昌也 滋賀 0.74
ザック・バランスキー A東京 0.74
安藤 誓哉 A東京 0.72
トーマス・ケネディ 広島 0.72
アレックス・デイビス 秋田 0.70
岡田 侑大 富山 0.67
大浦 颯太 秋田 0.65
林 翔太郎 新潟 0.56
遠藤 祐亮 宇都宮 0.50
セバスチャン・サイズ 千葉 0.49
朝山 正悟 広島 0.47
ジョシュ・ハレルソン 大阪 0.44


詳細なデータは以下(画像)

...
クラッチタイムのTS%が低い選手


クラッチタイムのフィールドゴール試投数・フリースロー試投数が多い選手


チームの中でクラッチタイムにショットを任されている選手は、成功率にかかわらず注目に値するので試投数に着目してランクを付けてみる。


クラッチタイムのフィールドゴール試投数が多い選手


TSP_lift TSP_clutch TSP FGA_clutch
Player NameShort
ニック・メイヨ 北海道 1.13 69.645441 61.743516 50
レイヴォンテ・ライス 京都 1.08 63.338301 58.741156 44
ジョーダン・ハミルトン 滋賀 1.10 61.022121 55.275407 41
ジョーダン・テイラー 北海道 1.06 55.038103 51.732906 38
古川 孝敏 秋田 1.31 69.311663 52.787162 37
デイヴィッド・サイモン 京都 0.97 53.990610 55.422237 36
ベンドラメ 礼生 SR渋谷 0.77 37.217659 48.320341 35
ダバンテ・ガードナー 三河 1.19 76.863951 64.355452 34
富樫 勇樹 千葉 0.91 49.634274 54.262877 33
ニック・ファジーカス 川崎 0.92 58.106576 63.416509 30
安藤 誓哉 A東京 0.72 38.296569 52.874313 30
トーマス・ケネディ 広島 0.72 40.419162 55.995585 29
ディージェイ・ニュービル 大阪 1.11 76.479438 68.833717 28
パトリック・アウダ 横浜 1.24 76.149425 61.352289 26
齋藤 拓実 名古屋D 0.82 50.066756 60.830794 26
森川 正明 横浜 1.01 58.459422 57.730924 26
橋本 拓哉 大阪 0.94 56.980057 60.413104 25
アレックス・デイビス 秋田 0.70 41.139241 58.468664 25
チャールズ・ジャクソン SR渋谷 1.08 72.089227 66.967535 24
シャノン・ショーター 千葉 0.80 43.741588 54.372349 24


フィールドゴール試投数になると さすがに各チームのエースが名を連ねている。

中でも、インサイドプレーヤーよりも、ドリブルの1on1で自らシュートチャンスを作れる選手の方がやや多い印象がある。


クラッチタイムのフリースロー試投数が多い選手


TSP_lift TSP_clutch TSP FTA_clutch
Player NameShort
ダバンテ・ガードナー 三河 1.19 76.863951 64.355452 41
チャールズ・ジャクソン SR渋谷 1.08 72.089227 66.967535 29
ディージェイ・ニュービル 大阪 1.11 76.479438 68.833717 27
ジョーダン・ハミルトン 滋賀 1.10 61.022121 55.275407 26
ステヴァン・イェロヴァツ 三遠 1.12 64.915459 57.882374 23
レイヴォンテ・ライス 京都 1.08 63.338301 58.741156 22
ジュリアン・マブンガ 富山 1.02 59.970015 58.913309 22
川嶋 勇人 三遠 1.01 51.345609 50.871397 21
レオ・ライオンズ 名古屋D 1.23 74.190647 60.120024 21
ジョーダン・テイラー 北海道 1.06 55.038103 51.732906 21
パトリック・アウダ 横浜 1.24 76.149425 61.352289 20
ロスコ・アレン 新潟 1.22 69.786535 57.099055 19
ジェフ・エアーズ 名古屋D 1.29 80.645161 62.412602 15
デイヴィッド・サイモン 京都 0.97 53.990610 55.422237 15
アレックス・デイビス 秋田 0.70 41.139241 58.468664 15
多嶋 朝飛 北海道 1.34 69.915254 52.234175 15
ウェイン・マーシャル 信州 1.20 75.561313 63.170580 14
グレゴリー・エチェニケ 広島 0.92 60.920578 66.138033 14
アンガス・ブラント 滋賀 1.01 60.920578 60.363348 14
シャノン・ショーター 千葉 0.80 43.741588 54.372349 13


フリースロー試投数が多いのはさすがの3年連続得点王のダバンテ・ガードナー。

インサイドで圧倒的な支配力・得点力を兼ね備えたスコアラーの実力が数値に表れている。

渋谷のインサイドを支える屋台骨的存在のチャールズ・ジャクソンも2位につけ、目立っている。

続くのがニュービル・ハミルトン・ライス・マブンガと各チームの得点もアシストもできるオールラウンダープレイヤーたち。

技術力が高く、終盤でのファールを引き出す力はまさにチームの大黒柱たちらしい。


クラッチタイムにおけるチーム内でのシュート試投数・得点割合


最後に単純に試投数の多さではなく、各選手がチーム内でどれだけの割合を占めているかを見る。

チームごとにクラッチタイムの時間帯が異なる場合に、単純な合計値だとクラッチタイムの時間帯が長いチームに属する選手がランクの上に来やすくなる影響を除くため。


クラッチタイムにおけるチーム内でのシュート試投数・得点割合


TSP_lift TSP_clutch TSP FGA_clutch_rate FGA_clutch FGA_clutch_team
Player NameShort
ベンドラメ 礼生 SR渋谷 0.77 37.217659 48.320341 48.61 35 72
ダバンテ・ガードナー 三河 1.19 76.863951 64.355452 43.59 34 78
富樫 勇樹 千葉 0.91 49.634274 54.262877 41.77 33 79
ジョーダン・ハミルトン 滋賀 1.10 61.022121 55.275407 41.41 41 99
トーマス・ケネディ 広島 0.72 40.419162 55.995585 40.85 29 71
齋藤 拓実 名古屋D 0.82 50.066756 60.830794 40.62 26 64
安藤 誓哉 A東京 0.72 38.296569 52.874313 39.47 30 76
レイヴォンテ・ライス 京都 1.08 63.338301 58.741156 37.93 44 116
古川 孝敏 秋田 1.31 69.311663 52.787162 37.37 37 99
ジャック・クーリー 琉球 1.02 66.585956 64.983356 37.14 13 35
ニック・メイヨ 北海道 1.13 69.645441 61.743516 36.23 50 138
ステヴァン・イェロヴァツ 三遠 1.12 64.915459 57.882374 34.33 23 67
並里 成 琉球 1.24 58.060109 46.640723 34.29 12 35
ディージェイ・ニュービル 大阪 1.11 76.479438 68.833717 34.15 28 82
チャールズ・ジャクソン SR渋谷 1.08 72.089227 66.967535 33.33 24 72
デモン・ブルックス 島根 0.92 53.462322 57.875936 32.69 17 52
ロスコ・アレン 新潟 1.22 69.786535 57.099055 32.00 16 50
デイヴィッド・サイモン 京都 0.97 53.990610 55.422237 31.03 36 116
ライアン・ロシター 宇都宮 0.77 41.534810 53.884415 30.77 20 65
橋本 拓哉 大阪 0.94 56.980057 60.413104 30.49 25 82


割合になると渋谷のベンドラメが1位になる。クラッチタイムにベンドラメがアタックしている渋谷の試合はよく見る気がしていたが、実際にそのようである。同じことは千葉の富樫でも言えそう。

上位の選手はチームの信頼度が高い証拠のように思える。


クラッチタイムにおけるチーム内での得点割合


TSP_lift TSP_clutch TSP PTS_clutch_rate PTS_clutch PTS_clutch_team
Player NameShort
チャールズ・ジャクソン SR渋谷 1.08 72.089227 66.967535 55.79 53 95
ダバンテ・ガードナー 三河 1.19 76.863951 64.355452 54.79 80 146
ディージェイ・ニュービル 大阪 1.11 76.479438 68.833717 51.69 61 118
古川 孝敏 秋田 1.31 69.311663 52.787162 47.15 58 123
ロスコ・アレン 新潟 1.22 69.786535 57.099055 45.95 34 74
パトリック・アウダ 横浜 1.24 76.149425 61.352289 42.74 53 124
ステヴァン・イェロヴァツ 三遠 1.12 64.915459 57.882374 42.16 43 102
レイヴォンテ・ライス 京都 1.08 63.338301 58.741156 41.72 68 163
ジョーダン・ハミルトン 滋賀 1.10 61.022121 55.275407 41.03 64 156
富樫 勇樹 千葉 0.91 49.634274 54.262877 40.00 38 95
グレゴリー・エチェニケ 広島 0.92 60.920578 66.138033 37.50 27 72
トーマス・ケネディ 広島 0.72 40.419162 55.995585 37.50 27 72
ニック・メイヨ 北海道 1.13 69.645441 61.743516 37.38 77 206
ジャック・クーリー 琉球 1.02 66.585956 64.983356 37.29 22 59
ドウェイン・エバンス 琉球 1.18 73.964497 62.924924 33.90 20 59
安藤 誓哉 A東京 0.72 38.296569 52.874313 33.78 25 74
田中 大貴 A東京 0.94 50.484653 53.675101 33.78 25 74
デモン・ブルックス 島根 0.92 53.462322 57.875936 33.33 21 63
リード・トラビス 島根 0.97 54.460581 55.899784 33.33 21 63
ベンドラメ 礼生 SR渋谷 0.77 37.217659 48.320341 30.53 29 95


終わりに

前回の記事をアップしてから それなりの反響・コメントを頂いた中で見直すべき点が多くあった。

そのため今回の記事のように別視点から似た内容を書く機会が得られた。

確かにデータで見るだけでは至らない点も多いとはいえ、バスケットボールをデータで見ることの楽しみがあるのもまた事実。

この楽しみがバスケ好きのみならず広がっていくと嬉しい。最後にrintaromasudaさんのツイートの引用で締めくくります。良いスレッドでした。


[追記]

Bleague Stats Analysis というサイトでBリーグの試合結果・チームスタッツ・個人スタッツなど色々まとめています。バスケ関連の記事もまとめています。よかったらご覧ください。

bleague-stats-analysis.com


Bリーグでクラッチタイムに強い選手は誰か?


先日、『65,000本以上のデータから、クラッチタイムのフリースロー成功率を調べてみた』という記事を読んで、それではクラッチタイムのシュート(フィールドゴールシュート)の成功率はどうなんだろうと疑問に思って調べてみた。


クラッチタイムに強い選手」とはどういう選手か?


クラッチタイムに強い選手」を考える上で、「クラッチタイム」と「クラッチタイムに強い」の定義を考える必要がある。

クラッチタイム」上述の記事の中で定義されてるものを引用する。

  • 4Qの残り5分以降(延長戦までもつれれば延長戦も含む) かつ
  • 得点差が5点差以内

またクラッチタイムに強い」の定義は普段のフィールドゴール成功率(FGP)に比べてクラッチタイムのFGPはどれほど高いか(低いか)を考えるのが良さそうである。

そこでクラッチタイムに強い」は以下のように定義することにする。


細かいデータや集計条件について


データはBリーグの試合結果のPlay by Playを利用した。

またデータの集計条件を以下のように定めた。今回はシュート成功率で見るので出場試合数やシュート試投数が少ない選手を除いた。

  • 集計データは2020-21シーズンの3/21までのデータに限る
  • そのうち36試合(消化試合数の80%)以上に出場、かつFG試投数が72本(試合平均2本以上)以上の選手
  • さらにクラッチタイムのFG試投数が10本以上の選手


クラッチタイムのシュート成功率が高い選手・低い選手


結果は以下のようになった。

クラッチタイムのシュート成功率が高い選手


クラッチタイムのFG成功率/FG成功率
Player Team
大崎 裕太 信州 1.68
長野 誠史 三河 1.60
安藤 周人 名古屋D 1.56
藤井 祐眞 川崎 1.50
晴山 ケビン 滋賀 1.49
宇都 直輝 富山 1.45
パトリック・アウダ 横浜 1.35
古川 孝敏 秋田 1.34
ジョナサン・オクテウス 滋賀 1.32
篠山 竜青 川崎 1.25
多嶋 朝飛 北海道 1.23
アンソニー・マクヘンリー 信州 1.22
並里 成 琉球 1.21
ジョシュア・スミス 富山 1.21
松井 啓十郎 京都 1.21
ジェフ・エアーズ 名古屋D 1.21
ウェイン・マーシャル 信州 1.21
ジャワッド・ウィリアムズ 北海道 1.20
ダバンテ・ガードナー 三河 1.20
山下 泰弘 島根 1.19


詳細なデータは以下(画像)

...
クラッチタイムのシュート成功率が高い選手


個人的に川崎を応援しているので、上位に藤井祐眞が入ってくるのは納得感がある。2/28の横浜戦でのブザービーターは記憶に新しい。

宇都直輝・古川孝敏・篠山竜青・並里成・松井啓十郎などの勝負強そうなベテランも上位にランクインしているのは興味深い。

ゴール下で押し込む形が多いのもあるだろうが、ジョシュア・スミスのFGPが85%近くになっているのは驚くべきスタッツ。


クラッチタイムのシュート成功率が低い選手


クラッチタイムのFG成功率/FG成功率
Player Team
田中 成也 広島 0.78
シェーン・ウィティングトン 三河 0.77
寺園 脩斗 三遠 0.74
アレックス・デイビス 秋田 0.74
ザック・バランスキー A東京 0.71
アキ・チェンバース 横浜 0.71
トーマス・ケネディ 広島 0.69
前田 悟 富山 0.68
北川 弘 島根 0.66
安藤 誓哉 A東京 0.63
パブロ・アギラール 川崎 0.60
ベンドラメ 礼生 SR渋谷 0.60
シャノン・ショーター 千葉 0.56
狩俣 昌也 滋賀 0.55
遠藤 祐亮 宇都宮 0.53
ジョシュ・ハレルソン 大阪 0.52
林 翔太郎 新潟 0.51
大浦 颯太 秋田 0.50
セバスチャン・サイズ 千葉 0.37
朝山 正悟 広島 0.16


詳細なデータは以下(画像)

...
クラッチタイムのシュート成功率が低い選手


ここでのクラッチタイムのシュート成功率が高い・低いはあくまで上記の集計方法によることを留意したい。

実際、普段のFGPが高い選手ほど比率を伸ばしづらいこともあるだろうし、そういった選手の方が厳しいディフェンスを受けることや特別な対策をされるケースもあるに違いない。また、時間がない中でパスが回ってきて打たざるを得ないケースもあるかもしれない。あるいは、試投数も全試合を通した本数に比べて格段に少ないので数値がブレやすいこともあるだろう。

繰り返しになるが、あくまで上記の集計方法によるクラッチタイムでのシュート成功率の上昇・下落率を表しているだけである。


まとめ

クラッチタイムのシュート成功率の上昇率について詳しく見てみた。ここでまとめたものはあくまで数値でしかないので どういった形でシュートを打っているのか、シュートで終わるのではなく上手にファールを引き出しているのかなど もう少し細かく見る必要がある。

とはいえ、1点を争うヒリヒリした一連の攻防こそバスケの醍醐味の一つなので、ぜひ試合を観戦してみてほしい。


[追記]

Bleague Stats Analysis というサイトでBリーグの試合結果・チームスタッツ・個人スタッツなど色々まとめています。バスケ関連の記事もまとめています。よかったらご覧ください。

bleague-stats-analysis.com

[追記2]

下記のツイートで指摘されたように、クラッチタイムのショット成功率が低い=「弱い」という表現は適切ではなかったので そのままシュート成功率が高い・低いという表現に修正しました。Yan さん、ご指摘ありがとうございます。

Kaggle API とシェルスクリプトで Kaggle のデータ周りを簡単に操作したい

はじめに

Kaggle API を使うと便利にアレコレをダウンロードしたりアップロードしたりできますが、コマンドオプションが覚えられなかったり、設定をアレコレ書くのが難しいので 出来る限り シェルスクリプトを使って簡単にしたものを整理しておこうと思い、書きました。

事前準備

Kaggle API が使える前提です。詳細はドキュメントを参照してください。

github.com

ディレクトリ構成

大体以下のようになっている前提で以下のスクリプトを書いています。

.
├── input
│   └── tabular-playground-series-jan-2021
├── kaggle-notebook.py
├── kernel-metadata.json
├── output
│   ├── confusion
│   ├── feature
│   ├── importance
│   ├── log
│   ├── model
│   ├── optuna
│   ├── result
│   └── submission
├── run.py
├── scripts
│   └── kaggle
├── src
│   ├── __init__.py
│   ├── __pycache__
│   ├── data
│   ├── exp
│   ├── fe
│   ├── features
│   ├── kfold.py
│   ├── models
│   ├── tests
│   ├── types.py
│   └── utils
└── transform-kaggle-notebook.sh

コンペデータセットのダウンロード

コンペ名だけベタ書きして実行すると input ディレクトリ以下に $COMPETITION_NAMEディレクトリが新たに生成され、そのディレクトリ以下にデータセットが展開される。

$COMPETITION_NAME が空文字だとエラーを吐くようにしています。

#!/bin/bash
COMPETITION_NAME="tabular-playground-series-jan-2021"  # Fill comepetiton name

COMPETITION_PATH="input/${COMPETITION_NAME}"
if [ -n "$COMPETITION_NAME" ]; then
  echo ${COMPETITION_NAME}
  kaggle competitions download -c ${COMPETITION_NAME} -p .
  mkdir -p ${COMPETITION_PATH}
  unzip ${COMPETITION_NAME}.zip -d ${COMPETITION_PATH}
  rm ${COMPETITION_NAME}.zip
else
  echo "COMPETITION_NAME should be provided"
  exit 1
fi

コンペにサブミット

こちらも事前にコンペ名だけベタ書きしておく必要があります。実験ごとにサブミットファイルが生成されているのと、CVのスコアがログにあることを前提にしています。

#!/bin/bash
COMPETITION_NAME="tabular-playground-series-jan-2021"  # Fill comepetiton name

RUN_NAME=$1
FILEPATH=./output/submission/${RUN_NAME}.csv
MESSAGE=$(cat ./output/log/result.log | grep ${RUN_NAME} | tail -n 1)
echo ${RUN_NAME}
echo filepath: ${FILEPATH}
echo message: ${MESSAGE}

kaggle competitions submit -c ${COMPETITION_NAME} -f ${FILEPATH} -m "${MESSAGE}"

自前データセットをアップロード

Kaggle Dataset にDATASE_DIR 以下をアップロードしようとしています。

kaggle datasets init で dataset-metadata.json を作成し、その json ファイルを書き換えて kaggle datasets create するとデータセットがアップロードされます。

ここでは手元で作っていた特徴量のデータセットをアップロードすることを想定して書いています。json ファイルの書き換えは sed コマンドで無理やり行っています。

ドキュメントを見ると もう少し詳細に説明等を書けるようですが、自前で使う分にはこれで十分そうです。

#!/bin/bash
DATASE_DIR="output/feature"
TITLE="tak-tps-jan2021-feature"
SLUG="tak-tps-jan2021-feature"

kaggle datasets init -p $DATASE_DIR
sed -i "s/INSERT_TITLE_HERE/$TITLE/g" $DATASE_DIR/dataset-metadata.json
sed -i "s/INSERT_SLUG_HERE/$SLUG/g" $DATASE_DIR/dataset-metadata.json
kaggle datasets create -p $DATASE_DIR

github.com

コードをアップロード

Kaggle Code に自身コードをアップロードしようとしています。

コードの場合も kaggle kernel init で kernel-metadata.json が作成され、その json ファイルを書き換えて kaggle kernel push するとコードがアップロードされます(同時に実行もされる)。

タイトルのユニーク性を保ちたいので実験名を引数に取るようにしています。自分の場合は exp00 のような命名規則で書いているので それを引数で要求しています。ベタ書きで書かないといけないところも多く もう少し改善の余地がありそうです。

作成中は sed コマンドのエスケープ周りなどにハマりました。

#!/bin/bash
function sed_kernel_metajson() {
    sed -i "s*${1}*${2}*g" kernel-metadata.json
}

if [ ! $1 == "exp*" ] & [ $# != 1 ]; then
    echo "argument must be string which begins with exp (e.g. exp00), but actual: $1"
    exit 0
fi

TITLE="tak-tps-jan2021-"$1  # Fill expmeriment number
KERNEL_SLUG=${TITLE}
CODE_FILE_PATH="kaggle-notebook.py"
LANGUAGE="python"
KERNEL_TYPE="script"

kaggle kernels init
sed_kernel_metajson "INSERT_KERNEL_SLUG_HERE" $KERNEL_SLUG
sed_kernel_metajson "INSERT_TITLE_HERE" $TITLE
sed_kernel_metajson "INSERT_CODE_FILE_PATH_HERE" $CODE_FILE_PATH
sed_kernel_metajson "Pick one of: {python,r,rmarkdown}" $LANGUAGE
sed_kernel_metajson "Pick one of: {script,notebook}" $KERNEL_TYPE
sed_kernel_metajson '\"enable_gpu\": \"false\",' '\"enable_gpu\": \"true\",'
sed_kernel_metajson '\"enable_internet\": \"false\",' '\"enable_internet\": \"true\",'
sed_kernel_metajson '\"dataset_sources\": \[\],' '\"dataset_sources\": \[\"takaishikawa/tak-tps-jan2021-feature\"\],'
sed_kernel_metajson '\"competition_sources\": \[\],' '\"competition_sources\": \[\"tabular-playground-series-jan-2021\"\],'
kaggle kernels push

github.com

終わりに

改善できる箇所は十分ありそうだし、そもそももっと単純な方法がありそうです。あるいは config とかを置いておくとよしなに書き換えてくれるみたいな機能あったりするのかなと思いました。