Lean Baseball

No Engineering, No Baseball.

打者の成績を数字で理解する三つの視点 - データサイエンスから学ぶセイバーメトリクス

私達が大好きなプロ野球, どうやら開幕の目処が立ちそうです⚾

www.nikkansports.com

とはいえ(この記事を書いてる5/10時点では)正式発表ではないかつ, 仮に6/19開幕としてもあと一ヶ月と少し時間がありますね...ということでまだまだ #StayHome をやってく必要がありそうです.*1

このエントリーでは前回同様,

「野球データで遊ぶならずっと #StayHome なまま野球ができるじゃん⚾」

というお気持ちの元,

  • 野球の統計学である「セイバーメトリクス」を「データサイエンス」の文脈で解釈しつつ
  • データサイエンスで大事な「特徴量」の事を学びながら
  • 野球をデータという切り口で楽しもう

以上をテーマとして野球のデータ, 特に「セイバーメトリクス」「データサイエンス」の視点で面白さを紹介できたらと思います.

なお, 初回であった前回は「野球のための特徴量エンジニアリング」という話をしました.

shinyorke.hatenablog.com

今回のテーマは,

「打者の成績(打撃成績)を普通の指標・得点能力・LWTSと三つの視点でみてみよう」

です.

このエントリーのダイジェスト

  • 統計的(もしくは特徴量として)打者の成績を数字で解釈するなら, 「平均的な打者と比べてどれだけ貢献してるか」が見えるLWTSが最も筋が良いアプローチであると言えそう
  • 野球の得点構造を, 「(出塁能力 + 進塁能力) / 出塁機会」で表現した「得点能力(RC)」は統計的な野球の数字の読み方の原点
  • とはいえ目的とか好み, そして算出・評価の難易度もあるのでその時々の「程度」で読むのがベスト.

という話を,

  • 世界の野球史に刻まれる大バッターであるIchiro Suzuki氏の通算成績
  • 世界中でよく使われているデータ操作言語であるSQL
  • データ分析を手っ取り早くやる道具として愛用者が多い「BigQuery」「Data Portal(旧データスタジオ)*2

を活用して解説します.

f:id:shinyorke:20200510220825j:plain
本日の教材です

これが理解できたらゴールです.

スターティングメンバー

この連載の対象読者&前提条件

以下は前回と同じです.

  • 何かしらのデータサイエンス・データ分析を自分で考え手を動かしてやっている方. 仕事・学業・趣味問わず.
  • SpreadsheetやSQL, プログラミング言語(Python/Rなど)など何かしらの道具でデータを加工したり抽出できたりできる
  • 野球のルール・記録の意味を把握していること. レベル感的には野球に興味なくても夏の甲子園とか日本シリーズを楽しめればOK

プロ野球やメジャーリーグに対するマニアックな知識は必要ありません.*3

今回に限れば,

「Ichiro Suzukiという大打者を数字という視点で見たらどうなんだろう?」

野球に興味ない方も, この記事を読んでる間は野球の世界のスーパースターに対する興味と関心を持ってもらえればと.*4

打者の成績を数字で理解する三つの視点

ここで言う「打者の成績」は,

打率, 打点, ホームランetc... スコアブックとして成績に残ってるもの

を指します.

「球種」「打球の種別(フライ・ライナー・ゴロ)といった, 投球・打球の記録(Batted Ball)や, 「打球速度」「打球角度」といった, トラッキングデータは含みません.*5

  • 一般的によく知られている成績・指標
  • セイバーメトリクスの代表的な打者評価モデル「得点能力」
  • 得点を起点とし, 各イベント・プレーに対して加重(重み)をつけて評価する「LWTS」

この三つの視点でイチローさんを眺めます.

1. よく知られている成績から眺める

まずは頭の体操がてら, よく知られている

  • 打率(Batting Average)
  • 出塁率(On-Base Percentage)
  • 長打率(Slugging)
  • 本塁打数(Home Run)

から見てみましょう.

f:id:shinyorke:20200510221016p:plain
よく知られている成績から見るイチロー

MLBにおける通算打率.311, 通算出塁率.355. MLB屈指の一番バッターであることを証明するように, (スタメンで出続けていた)2012年までの成績は圧巻の一言です.

一方, 「快速を駆使して内野安打」「ホームランは狙って打つ」スタイルが影響しているのか, 長打率とホームランは控えめな数字です.

ただまあ, MLB通算3089安打(日本を含めると4367本*6), 殿堂入り待ったなしの大打者として十分すぎる成績です.

...という所までは, ウィキペディアを見れば秒でわかる話ではありますが,

圧倒的なヒットメーカーであり, 一番バッターであったイチローはどこまで得点に絡んでいたのか?

という事を理解したい!と思った場合, どうやらこの数字だけでは解釈できそうにありません.

セイバーメトリクスではこのクエスチョンの解き方として,

  • スコアブック上の成績を元に, 「得点能力」を算出し「得点量」として評価する
  • 「プレーから産まれるイベント・事象」を元に, 「得点増加に寄与したかどうか」を積み上げて評価する

という代表的な方法を取ることが多いです(っていうことをこの先の事例で紹介します).

2. 得点能力から眺める

セイバーメトリクスが生まれて間もないころに生まれた指標で, RC(Run Created)というものがあります.

RC (野球) - Wikipedia

考え方の基本は,

RC = (出塁能力 + 進塁能力) / 出塁機会

で, もうちょっと詳しく言うと,

「出塁した機会を分母として, どれだけ出塁(アウトにならず, 塁に出ること)と進塁(一つでも多くの塁に出ること)を決めたか?」

という「野球のスコアブックにある成績を出塁・進塁・出場機会に置き換えてやりました!」という特徴量の作り込みをしています.

なおRCは得点能力という「量」で示します.

RC = (((A + 2.4C) * (B + 3C)) / 9C) - 0.9 * C

※変数A, B, Cは以下の通り

A = 安打 + 四死球 - 盗塁死 - 併殺

B = 塁打 + (0.26 * 四死球) + 0.53 * (犠打 + 犠飛) + 0.64 * 盗塁 - 0.03 * 三振

C = 打数 + 四死球 + 犠打 + 犠飛

  • RCそのものは, 得点に例えている. チーム全員のRCを合計するとチーム総得点に近くなるように調整されている.
  • ただ, RCそのものは出場数が増えると数字も増える*7ので純粋な得点能力は一試合(3アウト×9回 = 27アウト)あたりの数字に均した「RC27」を用いる.

ちなみにRC27の数式はこちらです.

RC27 = (27 * RC) / (打数 - 安打 + 犠打 + 犠飛 + 盗塁死 + 併殺)

そんなRC27と, 同じくセイバーメトリクスが生まれて間もない頃の指標(かつだいぶ一般化した)OPS(On-Base Plus Slugging, 出塁率に長打率を足したもの)でイチローを見るとこんな感じです.

f:id:shinyorke:20200510221151p:plain
OPSとRC(Run Created)から見るイチロー

引退前の2018, 2019がマイナスなのは式の構成上しょうがない感あります.*8

OPSとRC27の推移, ほとんど変わらないのことに皆さんお気づきでしょうか?

これには理由(と同時にRC/RC27を使う際の欠点)があって,

  • すごく雑に言うと, RCもOPSも結局のところ「出場機会に対して, 塁打をどれだけ稼いだか?」という構図である.
  • それぞれを説明すると,
    • OPSは, 長打率が「塁打 / 打数」で表現, 数字の比率的に長打率の方が強めに効くので塁打数の影響を受けやすい.*9
    • RCは, 「進塁能力(数式の変数B)の塁打が大きい比重を占めている(四死球などと異なり減じられていない)

「複雑なRCを計算しなくても, OPSで説明できちゃうじゃん」と言われるとぐうの音も出ません.

また, OPSもRCも「どんな場面で点を上げた(もしくはアウトになった)」など, イベント・場面が反映されない欠点もあります.

良くも悪くも塁打に均しちゃうため,

  • ノーアウトランナーなしからツーベースで出塁
  • ツーアウト満塁から走者一掃のツーベースで得点

後者のイベントの方が圧倒的に価値がある(点を上げているから)はずなのに, OPSもRCもすべて「塁打2」で記録されておしまいです.

このクエスチョンに対して答えるものがこの後紹介するLWTSになります.

なお, 「野球の得点のしくみ」を理解する上でRCは欠かせないので覚えておいて損はないでしょう.*10

3. LWTS - 得点価値で評価する

LWTS(Liner Weights)は一言で言うと, 「野球のプレー・イベントに加重を掛けて得点・勝利数に換算して比べるよー」という評価方法・概念です.

数々の書籍で紹介されていますが, ウィキペディアが読みやすいと思います.

Linear Weights - Wikipedia

LWTSはアウトカウント×ランナー状況の24通りごとに得られる平均得点を出した「得点期待値」と, プレーの結果である「得点価値」を元に様々な指標を算出...というアプローチを取ります(なお今回は紹介しません*11).

LWTSを元にした代表的な指標は,

  • wOBA(打席辺りの得点貢献. この後紹介)
  • DIPS(投手の自責と思われるイベント・プレーの特徴量から評価する手法. 次回連載で紹介予定)

があります.

wOBAの特徴は,

  • OPSやRCと異なり, 安打を種類(単打・二塁打・三塁打・本塁打)ごとに係数(加重)を用いて評価
  • 出塁率っぽい数字にスケールするようにできているため, 直感的に評価ができる(見慣れた数字と一緒という意味で)
  • 打席数やリーグ平均値を用いて, 得点(wRAA, wRC)として評価できる

という長所があります.

ちなみに数式はこちらです.

wOBA = (0.7 * (四死球-敬遠) + 0.9 * (単打 + 失策出塁) + 1.3 * (二塁打 + 三塁打) + 2.0 * 本塁打) / (打席 - 敬遠 - 犠打)

論より証拠ということで, wOBA, wRAAのグラフです.

f:id:shinyorke:20200510221315p:plain
LWTSで加重を付けて評価したイチロー

wOBA(折れ線グラフ)は言い方を変えると「プレーの質に合わせて調整した出塁率」なので推移が出塁率に似ています.

面白いのがwRAA(棒グラフ)の方で, (成績が悪化した)2011年から数値がマイナスになっています.

なぜマイナスになるか?のからくりはwRAAの数式にヒントがあります.

wRAA = (自分のwOBA - リーグ平均wOBA) / wOBA Scale) * 打席数

※wOBA Scaleは固定値(MLBの場合は1.15)

上記を見て分かる通り, 自分のwOBAがリーグ平均値を下回るとマイナスになります.

もうちょっというと,

  • 自分のwOBAがリーグ平均値より上回ると, 「平均的な打者より得点を稼いでる」といえる.
  • リーグ平均値と同じであればゼロになる
  • 下回ると, 「リーグ平均打者より下回る攻撃力」という意味になる. 直接的に言えばスタメンで使うのは危険.*12

2011年以降のイチローは様々な衰え?でバットのほうが湿っています(ちなみに守備走塁は現役終盤まで一流だった).

wRAAで見る限り, 徐々に出番がスタメンから控えになるのも理解できます.

どれで見るのが正解なのか?

「打者の成績を数字で理解する三つの視点」ということで,

  • よく知られている成績
  • OPS/RC/RC27
  • LWTS(wOBA, wRAA)

三つの例を上げました. じゃあどれが正解なの?っていう話ですが,

  • 「平均的な打者と比べてどれだけ貢献してるか」が見えるLWTS(wOBA, wRAA)が最も筋が良さそう.
  • 他の選手と比べる, みたいな目的じゃなければOPSやRCでもだいぶ説明ができるし良さそう.
  • 自分が何を知りたいか?によって使い分けるのがベスト!

かなと思います.

shinyorke.hatenablog.com

以前こちらでも紹介しましたが,

対象とするもの, ほしい結果に対する「精度」を元に「ほどほど(ある程度)」に測ることも大切.

これに尽きるかなあと思います.

結び&次回予告

今回は打者の成績の視点という紹介をしました.

プロ野球もメジャーリーグも開幕まで少なくとも一ヶ月は時間ありそうなので, 数字で楽しむ野球を知る機会になると嬉しいです.

また, スポーツデータサイエンスをやってるかた, いつかスポーツ業界のデータサイエンスをしたい!というかたへのアドバイスな視点だと,

  • 野球で攻めるならRCにあるような得点構造の理解
  • LWTSの意味と意義
  • これらをSpreadsheetでもSQLでもプログラミング(得意な言語でいい, 無ければRかPythonで)でもなんでもいいので自分で操れる

ようになると良い感じだと思います.

次回は投手編ということで, 先ほど少し紹介したこちらをやります.

DIPS (野球) - Wikipedia

個人的にはセイバーメトリクスで一番好きな考え方であり指標であります.

色々準備してやりたいと思います!

Appendix - 参考書籍

RCは野球本だとマネーボールが初出っぽいです.

ちなみに映画で見てもRCは出てきません.

数式や意味的なモノはこちらを参考にすると良いです(ちょっと古いですが良著です).

LWTSはこの辺を攻めるといい感じです.

*1:個人的にはずっとリモートでイケるのは良かったりしましたが流石に野球が無いのはぼちぼち応えますね. 競馬もダービー終わると一息ついちゃうので...

*2:これは別の機会でエントリーにしようと思いますが, 現在自分の野球データ分析環境はすべてBigQueryに統一, ちょっとした絵図とか可視化はData Portalを活用しています. 雰囲気的には所属しているJX通信社でやってるアプローチとほぼ一緒です.

*3:野球, チーム, 選手などなどから来る「ファン心理」「思い込みというバイアス」を抜くという意味でも重要な条件でございます(と前回も似たような注釈を書いた気が).

*4:念の為断っておくと, 統計とかセイバーメトリクスを使うまでも無く, イチローは大打者すぎます(Disろうとも重箱の隅をつこうとも思わない). データとして程よいサンプルであること, 日本に限らず世界的に有名なつい最近まで現役だったスーパースターということでイチローを選択しました.

*5:トラッキングデータを説明変数として統計的に出せるwOBAなどをチューニングする手段が最近のトレンドですが, 複雑なので今回は解説しません.

*6:これは意味分かんない数字で若干引く. いやホント大打者でした.

*7:数式の構造上, 打数や安打数が増えると上がりやすくなります.

*8:ホントはゼロ基準なのですが, RCおよびRC27の式の構成上, ヒット0本だとマイナスになります(これがRC系の欠点でもある)

*9:もうちょっと詳しく言うと, 出塁率は「出場機会に対して如何にアウトにならなかったか?」というパーセンテージなのに対して, 長打率は「打数に対して塁打をどれだけ稼いだか?率」という4百分率(故に厳密にはパーセンテージではない)の指標の為, このような事態が発生します.

*10:特徴量エンジニアリング, という視点では「分析で使う数字・特徴量がどんなイベントどんな原点で生まれたか?」を知ることはすごく重要じゃないですか, そういうことです.

*11:考え方と数式の意味がわかればこの辺は深堀りしなくても大丈夫だからです. なおデータサイエンス, 特に野球を仕事にする場合は理解したほうが絶対いいやつです.

*12:なぜなら打席に立てば経つほどマイナスが大きくなるからです

野球のための特徴量エンジニアリング - データサイエンスから学ぶセイバーメトリクス

新型コロナウイルスに我々はかならず勝つ!というお気持ちでずっと #StayHome している私達ですが, 野球が待ち遠しい事は変わりありません.*1

お家にいながら野球どうやってやろう :thinkingface: ...と考えた結果,

「野球データで遊ぶならずっと #StayHome なまま野球ができるじゃん⚾」

ということで,

  • 野球の統計学である「セイバーメトリクス」を「データサイエンス」の文脈で解釈しつつ
  • データサイエンスで大事な「特徴量」の事を学びながら
  • 野球をデータという切り口で楽しもう

っていうコンテンツを何回かに分けて紹介したいと思います(つまり連載です).

連載初回となるこのエントリーでは

  • 特徴量エンジニアリング
  • セイバーメトリクス
  • 野球の成績(打撃成績・投球成績)

にフォーカスした話をします.

スターティングメンバー

この連載の対象読者

  • 何かしらのデータサイエンス・データ分析を自分で考え手を動かしてやっている方. 仕事・学業・趣味問わず.
  • SpreadsheetやSQL, プログラミング言語(Python/Rなど)など何かしらの道具でデータを加工したり抽出できたりできる
  • 野球のルール・記録の意味を把握していること. レベル感的には野球に興味なくても夏の甲子園とか日本シリーズを楽しめればOK

連載としてはこの先もこの条件はブレないつもりです.*2

TL;DR

  • スポーツ, 特に野球のデータ分析をするなら記録が「自責」なのか「他責」なのかを正しく理解する所からはじめよう.
  • やるべきタスク・テーマによって, 「自責」な特徴量を使うか「他責」な特徴量を使うか分かれてくる.
  • 打者の場合はOPS(もしくは塁打)の仕組み・構造を, 投手の場合はDIPSを理解すると良いでしょう.

おさらいその1 - 特徴量エンジニアリング is 何

本題の野球の話に入る前に, 特徴量の話を少々します.

これについて名著「機械学習のための特徴量エンジニアリング」の表現が一番しっくりくるのでこちらから引用して紹介いたします.

まず特徴量の意味ですが一言で言うと,

特徴量(feature)は生データを数値として表現したものです。

※1.4「特徴量」より引用

です. 数値にすることにより, 比較したり計算したりと色々できるようになります.

...というのは簡単ですが,

生データを数値へと変換する方法はたくさんあるので、特徴量を作るために手間暇がかかることもあります。

(中略)

特徴量がモデル自体と結びついているということも忘れてはなりません。 あるモデルがある種の特徴量により適したモデルということもありますし、また、逆にあまり適していないという場合もあり得るのです。

※同じく1.4「特徴量」より引用

特徴量エンジニアリングという視点では,

  • 分析屋さん・分析マンにとって「意味がある特徴量を作る」事が重要
  • 意味がある特徴量は言い換えると「特徴量とモデルの結びつき」がバッチリなこと.
  • これらを実現するスキルとして, ドメイン知識(特徴量を作る・磨く), (分析・統計手法的な意味での)モデルを使いこなすテクニック

と言えるかなと思います(という解釈で私はいます).

なお, 「機械学習のための特徴量エンジニアリング」の特徴量についての説明はこんな感じで閉じています.

特徴量エンジニアリング(feature engineering)とは、与えられたデータ、モデル、タスクに最も適した特徴量を作り上げるプロセスなのです。

やみくもにデータを触る・作るじゃなくて, 「今あるデータとモデル, そして解きたいタスクを作り上げる」事が大事.

っていうのを抑えた上でセイバーメトリクスを見てみましょう.

おさらいその2 - セイバーメトリクス #とは

これもおさらいということで簡単に.

セイバーメトリクスは野球において発生するデータを統計学的なアプローチで分析を行い、選手の能力・チームの強さなどといった事を定量的に指標化・言語化し、チーム・選手に役立てるための手法・考え方である.

30分で理解するセイバーメトリクスの教科書 - 野球を統計的に楽しもうより引用.

ちなみに引用元はこのブログの記事です, 気になる方はぜひご一読ください.

shinyorke.hatenablog.com

野球(に限らずボールを扱うスポーツ全般)は,

  • 誰が見ても客観的に残る記録. 本塁打⚾, シュート⚽, トライ🏈などなど.
  • 見た人・プレーした人の主観・印象に残るもの. チャンスに強い/弱い, 逆境○, 的な.

見たもの・触れているものは大雑把に主観と客観で分かれると思いますが, その中でも

「記録」という客観的なモノにフォーカスして統計的に何かやるのがスポーツアナリティクスでありセイバーメトリクスであります.

なお, 記録にも「主観」に頼っているなんとも言えない罠があったりしますが...それはすぐ次の章で触れます.

野球の記録における, 特徴量の考え方

分析するテーマや使うモデルによって異なる所はありますよという前提を踏まえた上で.

スポーツデータ, 特に野球については「自責」「他責」を正しく理解することにより, 特徴量をいい感じに使いこなすことができます.

自責と他責

自責とは「自分の責任」の略で言い換えると「自分自身がコントロールできる」こと.

他責というのは「他の事に影響を受けやすい」ことで言い換えると「自分自身だけではコントロールできない」こと.

って書くと野球好きの人は,

???「自責ってアレやろ?自責点の事やろワイ知ってるやで!」

ってなると思いますが, 「自責点」の考え方とは実は違います.

「自責」「他責」をまとめるとこんな感じです(「例」がわかりやすいかも).

意味 特徴
自責 選手(チーム)の個々の実力によるイベントで決まる記録の事. パワー, スピードなど個々の能力が影響 本塁打, 三振など
他責 選手(チーム)の個々の実力だけでなく, 何かしらの外的要因やイベントが影響しやすい記録のこと. チームメイト, 審判, 球場の広さ等の変数に影響されやすい エラー, 防御率(自責点)など

「本塁打」「防御率(自責点)」をそれぞれ解説すると,

自責の例「本塁打」

  • 投手と打者のガチンコ勝負の結果である. 球場の広さがちょっと影響する程度.
  • 「フェンスを超えたら決まる」という点では, 野手の守備が上手/下手だろうが, 打者の足が速い/遅いは関係ない(=これらの変数は意味をなさない).
  • 「本塁打」というイベントは「投手」「打者」の「実力」で決まりやすい「自責の記録」と言える

ちなみにランニング本塁打は守備や球場に影響するのでこの限りではないですが, プロ野球レベルだと年に数本出るか出ないかレベルなので無視して良い範囲です.

他責の例「防御率(自責点)」

これは「防御率」の数式および, 「自責点」の成立条件を確認するとわかりやすいです.

防御率の数式は以下のとおりです.

防御率 = (自責点 * 9 * 3) / (投球回数 * 3)

防御率は, 自責点(投手の失点)に9(一試合分の投球回数)と3(野球は0, 1, 2アウトまで投げる)を掛けた数を投球回数×3アウト分の値で割ることにより, 「一試合投げきった時の自責点」という平均値です.

重要な説明変数である自責点の定義ですが,

自責点は、安打、犠飛*3、犠打*4、刺殺、四死球(故意四球*5を含む)、暴投、ボーク、野手選択*6、盗塁によって進塁した走者が得点したときに、失点とともに記録される。

※ウィキペディア「自責点」より.

これを紐解くと,

  • 自責点の成立条件である「安打. 特に長打以外のシングルヒットとか内野安打」「犠打・犠飛」「野手選択」などは, 投手(もしくは相手打者)の実力だけではなく, 後ろを守る野手に影響する.
  • 野手の守備が上手い(下手)は, 投手(もしくは対戦打者)の責任ではない. なぜなら彼らが自らやることではない(かつ, 自分たちが選ぶことができない).
  • その他の成立条件(説明変数)もかなり多く, 自責点は自責の記録とは言えない.

そんな自責点を重要な変数として採用している防御率も同様に他責の記録となります.

「自責」「他責」の特徴量を使い分ける

ここまで来るとオチは見えてると思います.

  • 分析対象の記録が「自責」なのか「他責」なのかを見極める
  • 選手やチームの実力にフォーカスするなら「自責」の特徴量を採用する(事が多い).
  • 「運」とか「流れ」みたいにふわっとしたモノにフォーカスするなら「他責」の特徴量の使い方がミソになる.

という感じで, 「やりたいテーマ・採用するモデルによって使う特徴量を変える」が基本となります.

なお先程ちょっとふれた,

記録にも「主観」に頼っているなんとも言えない罠があったりします

これは野球で言うと「エラー」の事で,

  • 数値化されてるので一見すると客観的な記録ではあるが, 記録員が「あのボールは普通の野手ならとれたハズ」っていう主観で記録が決まる
  • 記録員の力量に左右される. エラーばっかり記録する記録員(またはその逆)もいるかもしれない

という意味で罠だったりします(ので純粋な守備力評価でエラーを使うことが少ないのはそのせいです).

打撃成績の場合

打撃成績の特徴量をセイバーメトリクス的に解釈する方法は結構ありますが,

  • 実力で塁に出た回数である「塁打」にフォーカスする. 具体的には「長打率」「OPS」などに着目する.
  • 打者のプレー(安打, 四球, 三振etc...)をチームが稼ぐ得点に置き換えて評価する.

方法によっていい感じになります.

特にOPSは筋が良いかつ直感的なのでおすすめです, 野球データをSQLにまとめられるならこんな感じでいけます.

f:id:shinyorke:20200420215814p:plain
【例】BigQueryでOPSを算出

OPSの解説はOPS (野球) - Wikipediaにもありますが, 次回改めて紹介します.

投球成績の場合

先ほど触れたとおり, 投手成績でよく使う「防御率」は(重要な変数である自責点の)説明変数が多すぎるので, 統計・データサイエンス的な解釈には向いていません.

代わりに, DIPS (野球) - Wikipediaという概念・評価手法を元に成績の分析を行うことが多いです.

この考え方はシンプルで,

  • 投手の成績を「投手自身でコントロールできる部門」と「投手自身ではコントロールできない部門」に分ける
  • たとえば, 「奪三振」「与四球」「被本塁打」は投手の自己努力で改善ができる(=コントロールができる)*7
  • たとえば, 「エラー」「内野安打」「野手選択」って投手自身の努力ではどうにもならない部分が多いよね(=コントロールができない)

DIPS自体が, 野球における重要な特徴量エンジニアリングの思想と言っても過言ではありません.(ので私はこの考え方が大好物です*8

守備・走塁は?

守備および走塁は記録されるものが少ないかつ, 「エラー」のように怪しい記録もあるため評価が最も難しいテーマです.

ので,

  • 正規なスコアではなく, 打球の記録であるBatted Ballを用いる.*9
  • 最近ではトラッキングデータ*10を用いる.

ことにより実現する例が多いです.

結び&次回予告

色々好き勝手書きましたが, 言いたいこととしては,

  • 新型コロナウイルスに打ち勝った後の野球の楽しみ方として, 「数字」にフォーカスすると面白いと思うよ?
  • 記録の意味・特徴量的な解釈を知ると野球・スポーツの違う一面が見える
  • 機械学習とかデータサイエンスやりたいマン的には題材的にもちょうどいいぜ!

ってことです. 野球の試合無いなら数字でニヤニヤしようぜっていう.

そんな楽しい連載になるよう頑張りたいと思います.

次回は最もデータが揃っていてわかりやすい「打者の成績」にフォーカスして解説します.

GW中に出せればいいかな...がんばります.

【Appendix】今回の参考資料&予習するなら

このエントリーの参考資料です, どれもオススメ(手前味噌含む)です, GWの時間つぶしになると嬉しいです!

特徴量エンジニアリングの強い本.

セイバーメトリクス入門  脱常識で野球を科学する

セイバーメトリクス入門  脱常識で野球を科学する

  • 作者:蛭川 皓平
  • 発売日: 2019/11/20
  • メディア: 単行本(ソフトカバー)

最近出た野球本の中でも一番セイバーメトリクスにガッツリ取り組んでいる本.

DIPSの件の説明はマネーボールがわかりやすいかも, チャド・ブラッドフォードの件あたりがそう.

shinyorke.hatenablog.com

手前味噌ですがセイバーメトリクスの30分要約です.

*1:待ち遠しいので野球ユニフォームという「正装」を自宅で着用しながらこのブログ書いてます

*2:なので選手とかチームとかその辺のファン心理・ドメイン知識は不要です.

*3:犠牲フライ

*4:犠牲バント

*5:いわゆる敬遠です

*6:フィルダースチョイス

*7:もちろん, 捕手の影響もあります. 捕手のフレーミング(平たく言うとストライクを取る能力)能力によって影響する所もありますが, 捕手がどんなによくても球速が上がったり変化球がより曲がるとかないですよね?そういうことやぞ.

*8:真面目な話, 自分はDIPSそしてこれの原点であるLWTSが好きになってセイバーメトリクスにハマりました

*9:打球がゴロなのかフライなのかライナーなのか, 速度と角度はどれぐらいか?などを記録するものです. 昔は人力でつけることが多いですが今は後述するトラッキングデータに置き換わりつつあります(その方がある意味正しい).

*10:いわゆるトラックマン, ラプソードといったレーダーやカメラで計測した座標情報です.

小さいプロダクト開発におけるGCP利用の勘どころ - 個人的なプロダクトを三日でローンチした話

私個人の話なのですが.

最近は仕事でAWSやGCPのサーバレスアーキテクチャにふれる機会が増えた*1と同時に,

  • 自分が気になる世の中のニュース(グルメとかいろいろ)だけをいい感じに集めてまとめて読みたい
  • その中でも特に⚾, 速報とかいい感じに通知させたい

という怠け者欲ライフハック欲が高まってきたので, GCP(とちょっとしたPythonスクリプト)でSlack Botを作りました.

趣味開発で雑にはじめた結果, 三日程度でできちゃった*2のでその知見をメモ代わりに残します.

おしながき

TL;DR

  • GCPでクローラーを軸にしたBot作るなら「Cloud Functions」「Cloud Pub/Sub」「Cloud Scheduler」三つの組み合わせで爆速でイケる!
  • 気になる料金は...これからわかるが試算した結果, (今回の使い方だと)月額$1.0程度
  • 個人開発を楽しんでいこう, イベントがない今時期だからこそ

対象読者

「GCPとはなんぞや?」「Slackなにそれおいしいの?」的な解説はしません, わかってる前提で話を進めます.

  • 情報を収集したり使ったりする手段をいい感じにして怠けたい人,
  • 何でも良いのでプログラミングができる人かつ, 個人とか趣味で開発とかが好き・苦にならない人. ちなみに出てくる言語はPythonです.*3
  • サーバレスアーキテクチャ覚えたいなあー, とかGCP使ったサーバレスってどんな感じなん?っていうエンジニアな人.*4

作ったもの

全体像は絵で描くとこんな感じです.

f:id:shinyorke:20200314152038p:plain
この絵がすべてです.

左から順を追って説明すると,

  1. Cloud Scheduler」が毎日の活動時間中に10分間隔で発火, 「Cloud Pub/Sub」の指定したトピックにメッセージを送付
  2. Cloud Pub/Sub」のメッセージをトリガーにして「Cloud Functions」が起動
  3. Functions内の関数(Pythonで実装)がサイトのクローリングとクレンジングをした上でメッセにまとめてSlackにPost.

なお, 通知の制御(主に重複とか, 何回も通知が来るのはウザい)は「Cloud Firestore」に通知の状態を持っておくことによって実現しています.*5

割となんてことは無いSlack Botだと思ってくれればと思います.

GCPをフル活用して実質三日でBotをローンチした

Bot自体は先週の土日(3/7, 3/8)のそれぞれ半日でコードを書いて完成.*6

GCPへのローンチは, 一昨日(3/13)に仕事終わりのオフィスに居残ってビール片手にGCPのサービスを検証しまくった結果, 3時間くらいでできました.*7

Gitのコミットログ + GCP上の作業時間を合計すると多分12時間ちょいです, ハッカソンで作品作ったぐらいのボリュームですね.

Bot本体の開発

元々うっすらと, 「やきう⚾の情報をまとめるBot欲しいなー」と思っていて*8, いつ作ろうかと思案していた矢先に,

というやりとり*9&ウチ(JX通信社)のつよつよマンから聞いたrequests-htmlを(ちょっとドキュメントとコードを読んだ後に)おすすめしたのですが,

ワイ「使ったこと無いモノを薦めるのもアレだしちょっと遊びでコード書くか*10

というモチベーションの元, サクッと仕様を決めて開発をスタートしました.

なお, 開発そのものはrequests-htmlを程よく使うことによりアッサリいけました*11&大人にクローラーを開発する話は過去のエントリーに結構書いたので今回は省略します.

shinyorke.hatenablog.com

物足りない方は是非クローラー本をご参考に :bow:*12

GCPの何を使うかで試行錯誤

このエントリーの肝はむしろここです.

運用は最初からGCPと決めていました.

理由としては,

  • 自分自身のお勉強・知見を得る目的で, 「経験ほぼゼロのGCPでサーバレス」な開発に挑戦したかった.*13
  • プライベートで使っている分析環境およびデータセットはGCP上にまとめている
  • AWS Lambdaでやればきっと瞬殺で終わる&Lambdaも良いサービスだがGCP上での経験が積みたくて(大切なので二度言う)

サーバレスなモノは(GCPに限らず他のクラウドプラットフォームも)従量課金でSlackのBot一個程度ならたかがしれてるだろう.

というのもあり, やりたいモノであったGCPに振り切りました.

今回は,

  • 動かすのはPythonスクリプト
  • Cron的なJOBに従い動くバッチである
  • Web(HTTP)でオープンにするようなAPIとかはナシ

というシンプルな条件の元,

  • プランA「GCE(Google Compute Engine)」上でDockerのContainerとして定期実行
  • プランB「Cloud Run + Cloud Scheduler」の組み合わせでやる
  • プランC「Cloud Functions + Cloud Scheduler」←今回採用した構成

この3つのプランから考え, プランB・プランCをどっちも動かしてお試ししました(プランAは既にやったことあるので考えただけ).

プランA「GCEを使う」

まず真っ先に思いついたのが,

  • 開発したBotをDocker imageにしてGCR(Google Container Registry)にpush
  • GCRに上げたimageからGCEのVMを起動, バッチとして動かす

でした.

これについては既に個人の野球分析でやった実績*14があり楽っちゃ楽なのですが,

  • 言うてもVMなのでずっと立ち上げっぱなしにする必要がある.
  • Botを動かす時間はせいぜい一日10時間ちょい, 残りの14時間はリソースを遊ばせることに.
  • (なんとなくの)試算で$1/日, 一ヶ月で$30前後と予想, 払える金額だが遊んでる時間が長いのでもったいない!

こっちとしては使った時間だけお金を払いたい感じなので即効で却下しました.

プランB「Cloud Run + Cloud Scheduler」

次に考えた&試したのが,

  • 開発したBotをDocker imageにしてGCR(Google Container Registry)にpush
  • Cloud Runのサービスとして起動, Cloud Schedulerからトリガーを出して動かす

でした.

これは実際に公式のクイックスタートを追いながらWeb APIとして立ち上げ, Cloud SchedulerからAPIを叩いて実行してうまくいきました, これは楽だし便利.

ただ,

  • 別にWebアプリを作りたいわけではない
  • 現時点ではCloud RunはWebのトリガーでしか動かないと思ってました. Pub/Sub対応してたのにこのエントリーを書いてる途中に気がついたorz*15
  • 言うてもBotなコードなので別にDocker化するほどでも無いのでは(今更)

若干の勘違いと調査不足は置いておいて, 原点に立ち直った私は「Botとしてもっとシンプルな方法でいこうぜ!」って事で舵を切り直しました.

採用した構成「Cloud Functions + Cloud Scheduler」

というわけで今回採用した構成はこちらになりました.

f:id:shinyorke:20200314152038p:plain
【再掲】この絵がすべてです.

Cloud FunctionsのPub/Sub使うよチュートリアルに従いサンプルを作成, Cloud SchedulerからのトリガーでPub/Subのトピックにメッセしたら今までの試行錯誤は何だったのか?的な感じでうまくいきました👍

使った感想としては,

  • requirements.txtを用意するだけでライブラリのインストールとかよしなにしてくれるのすごく楽.*16
  • 運用後のデバッグがくっそ楽.エラーレポーティングが詳細でわかりやすい(Sentryとかいらない).

ちなみにエラーレポーティングはこんな感じでリンク先を掘るとかなり詳細に追えて素晴らしいです.

f:id:shinyorke:20200315124215p:plain
かなり助かる

さて気になるお値段は?

個人プロジェクトそしてもちろん仕事もコスト管理大事です.

ということで今回の構成(Functions + Pub/Sub + Scheduler + Firestore)において,

「Botが10,000回/月 APIをコール」したときのコスト(月額)を試算してみました.

サービス 試算した金額 根拠
Cloud Functions $1.0 回数は無料枠内, 送信は5GB未満, 関数の実行時間を60秒未満とした時のリソース金額のみ上乗せ, ちなみにメモリは128MB
Cloud Pub/Sub $0 TiB単位で課金, 流石にそこまでいかない
Cloud Scheduler $0 請求アカウント全体で1つのJobのみ, 無料枠に収まる
Firestore $0 100,000ものドキュメントは無い, 行って10,000程度なので無料枠内

一ヶ月あたりたった$1.0, 見誤ったとしても$3.0ぐらいだなとわかりました.

毎日飲んでいるりんご黒酢と胡麻麦茶のほうが高い*17くらいです, やった.

先ほどのGCEを使った例の試算だと(状況にもよりますが)少なくとも$20以上はかかるので全然お安いといえます.

世の中サーバレスなアーキテクチャで開発することが流行っていますが, コスト面ではかなり美味しいのがわかります.*18

結び - 個人的プロジェクトのすすめ

昨今の新型肺炎の騒ぎで色々と辛かったりきついこともあるかと思いますが!

こういう時にふと時間ができたら個人開発をオススメしたいなと.

  • スキルや経験といった自己投資として. 例えばサーバレスなアーキテクチャは実際使わないとわからないモノも多いのでこういうときに試すといいよとか.*19
  • 自分自身の生活や仕事の効率化・ライフハックとして. 普段めんどくさいことを1日2日かけてプログラミングで楽できるのは良いことだし, そこで空いた時間で別のこともできます.*20
  • 結果的に仕事に活きたり次のチャンスに繋がる.

最近は個人開発も結構フォーカスされてる&事例も増えているのでキャッチアップすると良いかなと.

というわけで, GCPを使った小さいプロダクト開発の記録でした.

*1:それはなぜかというと, 現在在籍しているJX通信社がサーバレスアーキテクチャな会社だからです.

*2:ちなみにすべての情報ソースに対して開発終わったわけではないです&今回は野球のソースを中心に紹介します.

*3:Cloud Functionsがサポートしている言語ならどれでもいいです, 現時点ではNode.js, Go langそしてPythonの三択となります.

*4:個人ブログなので会社の見解とか諸々関係ないですが, 弊社を気にしてくださる方は読んでくれたほうが嬉しいです.

*5:これは書くと長いので端折りますが控えめに言って便利でした.

*6:自宅, カフェ, 外の居酒屋と場所を転々としながらクローラー作った

*7:ちなみにウチの会社は金曜日の夜や週末などに自発的に仕事以外のもくもくをする人がいたり, 有志でボードゲームとかを嗜んだりとTGIFチックな活動がとても雰囲気良いです.

*8:開幕に間に合わせましたが肝心の開幕がいつなのかっていうツラミ

*9:その後のむーむーさんの成果は大変素晴らしいまとめなブログとしてまとまっているのでご興味ある方是非&このエントリーでやってることとほぼ被っています(AWSかGCPの違いですね).

*10:人にオススメするものは事後でもいいので触っておく, が私の基本的なスタンスです.

*11:これはまた別の機会に書きたい

*12:これはマジ名著です.

*13:過去にGAEや後述するGCE(Compute Engine)および今はBigQueryやGKEとか使っていますが, サーバレスの小さいSaaSは普段AWSでやってたのでほぼ未経験

*14:昨年検証した, 類似性スコアの算出に使いました, 全選手を総当りで計算する必要があった&半日回せば後は用済みっていう使い方でした(こういう使い方をする分にはVMは大変素晴らしいです).

*15:Pub/Sub無理かーって思ってたらブログ書いてる最中にPub/Subイケるよって見つけました.

*16:個人的にはここがAWS Lambdaより楽で助かるな感あります, まあserverlessとか使えばいいんですけど.

*17:合わせて270円くらいです, これが毎日.

*18:エンジニアリングの基本は「限られたリソースを上手く使い切る」だと思っていてそれがサーバレスな仕組みのピタゴラスイッチでできるのはかなり良いことだと思います.

*19:最初の方に述べた通り今回は自分がGCPに慣れるためにやりました.

*20:いわゆる, 「退屈なこと」「仕事ごっこ」をいい感じにするってことです.