イチローの安打数とサッカー1試合あたり得点数とポアソン分布

イチローの1試合あたり安打数はポアソン分布に従いそうに思われるが従わないという記事が少し前に話題になったようだ。
rikei-logistics.com
これに対し、ポアソン分布に従わないのは当たり前と指摘する記事も出ていた。
www.anlyznews.com

安打数の分布に関する論点の整理

まず、もとの記事では1994年のパ・リーグ規定打席以上の打者の安打数が試合数より少ない(安打数/試合数=0.93)ことをもって「これくらいだと、1試合当たりの安打数は「滅多に起こらない事象の確率分布」であるポアソン分布に従」うとしているが、これは自明ではないように思う。

ポアソン分布はめったに起こらない事象に当てはまりがよい確率分布とされるが、ここでのめったに起こらないとは、試行回数に対して事象が起きる回数が極めて少ないことをいう。
数学的にいえば、二項分布のnを∞に飛ばすとポアソン分布に収束する。
では安打という事象に対応する試行は何かというと打席に立つことだろう。1試合フル出場した選手1人に回ってくる打席数はだいたい4か5、多くても6、7である。この程度の試行回数に対して規定打席到達選手が平均で0.93本、イチローが1.62本のヒットを打っているのだから、めったに起こらない事象ではない。ゆえにポアソン分布に従わないのではないか。
もとの記事では2021年セ・リーグ首位打者鈴木誠也の安打数の分布のほうがイチローよりポアソン分布に近いと指摘しているが、これも1994年イチロー(.385)より2021年鈴木誠也(.317)の打率(≒安打を打つ確率)のほうが低いことから自明だと思われる。

サッカーではどうか

一方で、サッカーで1試合あたりの得点数がポアソン分布に従うことは定説のように扱われていて、検索すると数多くの記事がヒットする。
つまりサッカーの得点は試行回数のわりに起きにくい事象ということになるが、ここでの試行とは何か。
以下のページの説明を引用してみる。

サッカーは得点の少ないスポーツです.その一方,得点が決まる最小単位の時間,10秒くらいを考えればよいでしょうか,に対して試合時間は90分と非常に長いです.すると,サッカーでの得点は,「挑戦回数が多いものの成功回数が少ないできごと」と解釈できます.

プロサッカーの場合,1試合1チーム当たりの平均得点は1.30(2017年J1)くらいで,試合時間の最小単位を10秒とすると,成功確率が0.0024のできごとに対して540回(=90*60/10)挑戦したときの成功回数が得点となります.成否は確率的なので,成功回数(つまり,得点)も確率的にばらつくことになります.

www-ie.meijo-u.ac.jp

この仮定は妥当なのだろうか。最終的には得点することを目標にしてプレーしているとはいえ、あらゆる10秒単位の時間を得点に対する試行と考えることに無理はないか。
もっと単純に、野球における打席のような試行をサッカーで考えてみれば、シュートになるのではないか。
1試合のシュート数くらいの大きさをパラメータに設定した二項分布は、ぱっと見にはポアソン分布に近いかもしれない。
上のページにあわせ2017年J1リーグのデータを使うと、以下によれば1試合1チーム当たりの平均得点は1.30、平均シュート数は12.95である。
www.football-lab.jp
そこで12.95と1.30/12.95をパラメータとする二項分布をパラメータ1.30のポアソン分布とあわせて描画してみる。

試行回数13くらいで二項分布はポアソン分布とそう変わらない形状になっているように見える。
一方、実データへの当てはまりはどちらがよりよいのか。
集計データが入手できなかったので、上のページと目視で比較するくらいしかできないのだが、得点数0、1ではポアソン分布の当てはまりがよく、2では二項分布の当てはまりがよいか。

これだけの結果で断言はできないが、シュート数を試行回数にすることも単純に過ぎるのだろう。実際、シュートではないが得点に結びつきうるプレーは数多くあるはずだ。
実用上、得点数の近似はポアソン分布で十分なのだろうが、より真に迫った分布と試行回数が解明されれば、スポーツアナリティクスへの貢献になるのかもしれない。

会社員をやりながら英国の大学のオンライン修士課程を修了した

昨年の11月にエディンバラ大学の以下のコースを修了した。専攻はデータサイエンス系である。
関心がある人向けの情報共有を兼ねて、個人的な体験から大変だったことや学んだことをまとめておく。

www.ed.ac.uk

事務とのやりとり

大学の事務は冷淡でお役所仕事という話ではない。そもそも事務仕事が適切に処理されていないので、こちらから積極的に働きかけて適切に処理してもらわなければならなかった。
半期ごとに履修登録した科目に関する請求書が届く(学期単位でなく科目単位で学費を納める)のだが、登録していない科目の学費が請求されたり、反対に登録したはずの科目が受講できないことになっていたりと、毎回のように登録内容が間違っていた。
また修士論文の提出には専用プラットフォームへのアカウント登録が必要で、内容がメールで周知されていたのだが、私は送信先から漏れていてプラットフォームの存在も知らなかった。
たまたま〆切の3、4日前に指導教員と雑談していたとき、あれメールきてないの?と指摘され、大慌てでアカウント登録の手続きを進めた。
システム管理者の承認待ちなどもあって、提出が完了したのは〆切の2時間前だった。
率直にいって日本で在籍した大学よりも事務仕事の質は低かったが、一方で事務的なことであっても融通が利く場合が多かった。
実際、修論の提出も〆切の時刻を過ぎる恐れがあったので、この遅れは私の責任ではないのでなんとかならないかと交渉したところ、アカウント登録完了後すぐに提出してくれれば〆切までに提出した扱いとするとの了承を得た。
これはカナダの大学に留学した(オンラインでなく、現地へ行った)ときにも感じた。提出物の期限や採点基準に細かい基準が設けられているわりに、これ無理なんで〆切延ばしてもらえませんか?などと学生が提案するとあっさり通ることがよくあった。

LaTeXでの論文執筆

レポートではLaTeXを使わなくてよかったが、修士論文ではLaTeXによる文書作成が求められた。
もともとの専攻が人文・社会科学系だったので、はじめて泥縄式にLaTeXを使って苦しめられた。
それでなくても書きたいことを英語に訳すという一つ目のハードルがあるのに、さらに書きたい数式のLaTeX記法を調べて、コンパイルに失敗したらエラーメッセージを読んで、を繰り返すので、書く内容が頭に浮かんでから画面上で文章になるまでの時間がものすごくかかった。
いわゆるプログラミング言語LaTeXは似てもいないし非なるものだと使ってよくわかったが、やりたいことのやり方を調べて、動かしてみて、エラーが出たらメッセージを読んで対処法を調べる、というサイクルを回すにはプログラミングの経験が活きたとは思う。

英語

英国の大学なので、すべての講義は英語で行われるし、修士論文も英語で書く。
エディンバラ大学の大学院は入学要件にIELTS6.5以上のスコアが求められるのだが、これがクリアできていれば英語に関してはなんとかなるのではないか。
なんとかなるは余裕という意味ではなく、講義の聴き取りや会話でうまくいかないことはざらにあった。修了にこぎつけられるくらいの意味合いだ。
また私の指導教員はインド人だったので、独特の訛りがあってとくに聴き取りに苦労した。何度も聞き直したり、後で書面で送ってくださいと頼んだりした。
情報系だとさまざまな国籍の人が教員をやっているので、いろんな訛りの英語に触れる機会は多い方だと思われる。
一方で英語の読解はそんなに大変だと感じなかった。
人文・社会科学系の科目だと1週間で論文や本の1章を何本も読んだことに比べると、パワポのスライドで講義資料を配布されることも多く、内容の理解に時間がかかることがあっても英語でなく数式やアルゴリズムに起因するものだった。

情報系の知識

もともと人文・社会科学系の専攻だったので、情報系の知識は仕事をしながら覚えたものがほぼすべてだった。
英国の修士課程の多くがそうみたいだが、私のように情報系以外の専攻だった人を多く受け入れており、日本のように院試で分野の基礎学力を確認することもないので、そういったレベルにも配慮されたカリキュラムが組まれていると思われる。
その分、学部より明確にレベルの高いことが学べるとは限らないかもしれない。
そうはいっても、大学教養レベルの数学やアルゴリズムとデータ構造の練度が高ければと思うことはあった。
また専門外に配慮しているとはいえ、Linuxサーバにリモート接続してプログラムを配置して動かしてください、くらいの指示は当たり前のようにされるので、実務系のITスキルもなければ相応の労力はかかる。

本業や家庭との両立

これはその人が置かれた環境によって異なるので一般的なことは何も言えないのだが、私の在学中は残業が少なく両立しやすかった。
また在学中に結婚したのだが、妻の理解があったおかげで自由にやらせてもらえた。
そうはいっても月単位や週単位で普段飲まない栄養ドリンクを買い込むくらいのことはあったが。
社会人コースの多くは長期履修制度があるので、各人の忙しさに応じた計画を立てるのがよいのだろう。
強制的に時間を天引きされることにより修了した後にも時間の使い方を見直すきっかけになると思う。

オンライン環境

2019年9月に入学した当時、オンラインの大学院って正直どうなんだろうかという疑念を持っていたのだが、半年も経たないうちに新型コロナウィルスの流行で仕事も学業もオンラインがめずらしくない世の中になってしまった。
このため、特別な形態で学業をやっているという意識は薄くなった。
事務の不備を別とすれば、与えられた課題をこなすのにオンラインが大きな障害となったことはなかった。
一方でカリキュラム外だが大学に所属することで得られる学びは少ないと思う。
これはバイト、サークルに代表される課外活動のような話に限らず、たとえばLaTeXの使い方にしても物理的な研究室に属していればさくっと教えてもらったり、tipsが代々伝わっていたり、といったことがあるのではないか。
こういったノウハウもどんどんドキュメント化・オンライン化すればよいと思うが、費用や時間の問題でなんでもかんでもというわけにはいかず、ある種のスキルの習得においては対面が最も効率的な場合もあるのかもしれない。

何を学んだのか

データサイエンスの教材は山のようにある。能力とやる気さえれば、修士レベルの知識は独学で十分に得られると思う。
そのうえであえて大学院に入るなら独学では学べないことを学ぶべきと考えた。
人によって能力ややる気のある分野が異なるので、独学では学べないことも異なるはずだ。
私の場合、ロボット工学やメタヒューリスティクス、Cによるプログラミングといった、このまま仕事を続けても触れないであろう分野の科目を重点的に受講した。
また、ビジネス系の科目で単位を取得することもできたが、ずっと文系の人間で文系科目は散々履修したので全単位をいわゆる理工情報系でそろえた。
一度社会科学系で書いたことがあるとはいえ修士論文もよい経験になったと思う。
主語が大きいことを恐れずに書くと、情報系と欧米の文化の特徴としてアウトプットを重んじることがあるのではないか。
それゆえに、いかにアウトプットを出すか、アウトプットを形式的にも内容的にもよくするかという観点からの指導が多かったと感じた。

Pythonでスクレイピングを並列処理する

並列処理について調べていたら、スクレイピングはサーバのレスポンス待ちなどでデータ受信に時間がかかるので、並列処理すると効率がよいという話を読んだ。
確かに納得感のある説明だが、実際のところどのくらいの効果があるのか気になり簡単な実験をしてみた。

実験内容

以下の4つのURLをスクレイピングする。

並列処理は組み込みモジュールのmultiprocessingで実行している。実行環境(MacBook Pro 2017モデル)のコア数が4であることから同時処理数は4にした。なおプロセッサは2.3 GHz Intel Core i5、メモリは8GBである。

実験に使ったプログラムは以下にアップロードしてある。Pythonとモジュールのバージョンに関する情報も出力した。
https://github.com/ryo101/blog/blob/master/20220827/scraping_with_multiprocessing.ipynb


スクレイピングと並列処理に関する実装を転記すると、

def get_html(url):
    return requests.get(url)

スクレイピング関数を定義したうえで、

for u in urls:
    htmls.append(get_html(u))

で単一処理を、

p = Pool(multiprocessing.cpu_count())
htmls = p.map(get_html, urls)
p.close()

で並列処理を実行している。

なお、はじめget_html内でhtmlsにappendするように書いたところ、並列処理では結果がhtmlsに入らなかった。
リクエスト結果をget_htmlで返すようにしたら単一処理でも並列処理でもうまくいった。

実験結果

各々10回ずつ実行して得られた実行時間である(単位秒、小数点第2位)。

  • 単一処理:平均0.58、最小0.44、最大0.95
  • 並列処理:平均0.33、最小0.27、最大0.43

URLが4つだけでも、さすがに1/4の実行時間にはならないものの、およそ半分になっている。
4つ程度だと並列のほうが時間がかかるのではと予想していたのでこの結果は意外だった。

スクレイピングの並列処理の実装について検索するともっと凝った実装例も出てくるが、上に載せた書き方だとコード量は単一処理とほぼ変わらないし、これでも十分に時短の効果がある。使える場面では積極的に活用していきたい。

null判定を含むSQLのcaseの書き方

SQLのcaseは列の値によって結果を出し分けたいときに便利な書き方である。
列名がwhenの外側かにくるか内側にくるかで大きく分けて2つの書き方があり、前者をcase式、後者をcase文と呼ぶ向きもある。*1

case <列名>
  when <条件1(「= 特定の値」など)> then <表示したい値1>
  when <条件2> then <表示したい値2>
  …
  else <その他の場合に表示したい値>
end as <表示したい列名>
case
  when <列名> <条件1> then <表示したい値1>
  when <列名> <条件2> then <表示したい値2>
  …
  else <その他の場合に表示したい値>
end as <表示したい列名>


対象の列に対してnull判定をしたい場合、「<列名> is null」という条件をひと続きで書かなければならない。
このため、null判定のほかにも列の値によって結果を出し分けたいなら、普通に考えると列名がwhenの内側にくる書き方にすることになる。

case
  when <列名> is null then <表示したい値1>
  when <列名> <条件2> then <表示したい値2>
  …
  else <その他の場合に表示したい値>
end as <表示したい列名>


この書き方だと、列名を繰り返す書くことになり、条件が増えれば増えるほど煩雑になってしまう。
たとえば、近畿地方の府県を表す数値に応じて都道府県名を表示し、nullの場合は「不明」と表示したい場合、次のようにprefecture_idが6回繰り返される。

case
  when prefecture_id = 1 then '大阪府'
  when prefecture_id = 2 then '兵庫県'
  when prefecture_id = 3 then '京都府'
  when prefecture_id = 4 then '滋賀県'
  when prefecture_id = 5 then '奈良県'
  when prefecture_id = 6 then '和歌山県'
  when prefecture_id is null then '不明'
end as 'prefecture_name'


なんとかprefecture_idを繰り返す回数を減らせないかと調べたところ、二重caseを使えばやりたいことに近いことができた。

case prefecture_id is null
  when 1 then '不明'
  else
  case prefecture_id
    when 1 then '大阪府'
    when 2 then '兵庫県'
    when 3 then '京都府'
    when 4 then '滋賀県'
    when 5 then '奈良県'
    when 6 then '和歌山県'
  end
end as 'prefecture_name'


さて、これで見た目がすっきりして可読性が上がるかと思ったのだが、二重caseになっているし微妙か…
どちらかというと、caseの後ろにくる条件式の真偽で場合分けができる点を押さえておきたい。

*1:厳密にいえば「条件」とは以下での「列名」と「条件」を合わせたものである

Jupyter Notebookでローカルモジュールの更新を反映するときの注意点

ローカルモジュールを更新したとき、Jupyter Notebookを再起動しなければ更新内容が挙動に反映されない。以下のリンク先にもそのような説明がある。

qiita.com

tm23forest.com

ここで気をつけたいのは、更新内容が出力セルには反映される点だ。

たとえばJupyter Notebookのプログラムが呼び出すローカルモジュールのうち、ある行の処理に問題がある場合を考えよう。出力セルにはその行とエラーメッセージが表示される。

ここでその行を正しい処理に書き直し、再起動しないままJupyter Notebookを実行すると、前述のように更新内容が挙動に反映されていないので、再びエラーメッセージが表示される。ところが、出力セルにエラーメッセージとともに表示される該当行は、正しい処理に書き直されたものなのだ。

どういう理由でそのように表示されるのかはよくわからないのだが、私はこれのせいで正しく書き直せていないと思い、時間を溶かしてしまった。
みなさんはぜひ気をつけていただきたい。

(随時更新)2022年に読んだ本のメモ

1月

データサイエンス関連

www.kspub.co.jp
ベイズ統計の本をまともに読んだことがなかったのでざっと通読した。

ソースコードが多くを占める本としては、理論的な解説がかなりしっかりされていると思う。とくに状態空間モデルに関する記述が分厚い。大事なことは繰り返しを厭わず何度も説明するスタイル。ソースコードはどうしてもR以外がいい、という人でなければ、最初の1冊として申し分ないのではないか。

その他

www.msz.co.jp
時代的なものなのか、構造主義っぽい話だなという印象を受けた。本文中にそのような記述はないが。

著者によれば、科学の当事者である科学者は同時代のパラダイムを完全に理解しないまま研究しているらしい。会社のことをよくわかっていなくても仕事を進められるように、科学者の仕事である科学もそういうものなのかもしれないと思った。

www.saiensu.co.jp
経済の歴史的発展を解き明かすために文献調査だけでなく計量的手法やゲーム理論などさまざまな道具が使われてきたことがわかる。

株仲間が市場経済の発展に寄与していた話などは雑学的にもおもしろい。

マルクスウェーバーでは宗教と経済の因果の向きが逆という指摘は、単純化されているものの言われてみればと思った。


www.diamond.co.jp
網羅的な内容。インデックスとして、ここから興味のあるトピックを見つけて進んでいくのに使えそう。

相関係数と正規性

最近、相関係数における2変数の正規性の必要性について考えることがあり、そのときに調べたことをまとめた。確証の持てる結論は得られず、ややお気持ち的なまとめになっている。

推測統計の文脈で相関係数を使う場合

相関係数の検定や区間推定をする場合、事前に正規性の検定をすべきだろう。というより、データに何らかの分布を仮定しないとパラメトリックな検定や区間推定はできないので、定義上当たり前ではある。逆にいうと、検定や区間推定をするための都合で相関係数に正規性が要請されるようにもとれる。

なお、正規性が成り立たない場合に検定をしたいなら順位相関係数で代用することがセオリーだそうだ。とはいえ、(ピアソンの)相関係数と順位相関係数では用途によっては別物になってしまわないか、という気もした。

記述統計の文脈で相関係数を使う場合

検定や区間推定の結果をもとに最終的な意思決定をするのではなく、EDAの一環で相関係数を算出することがある。私見だと相関係数はこのように使われる場面のほうが多いのではないかと思う。この場合、正規性の検定は必ずしもしなくてよいと考える。

定番の統計学の教科書でも相関係数はまず記述統計の章で解説される。そこでは正規性について触れられていない。
www.amazon.co.jp

そもそも正規性の問題がなくても、線形な関係からの乖離を表現するにすぎない相関係数を数値単体で見ることにあまり意味はないと考えている。散布図を描いたりしてある程度定性的に分析することが基本だし、先の本にもそのような指示がある。その際の分析軸のひとつとして正規性が有用なことはあるだろう。

定義から考える

相関係数は共分散を各変数の標準偏差で割ったもの、言い換えれば正規化された共分散である。定義上、変数が連続値であれば算出できるもので、正規性は一切要求されていない。

ベクトルの言葉を使えば、相関係数は2本のベクトルの内積を各ベクトルの長さで割ったもの、すなわち2本のベクトルがなす角のコサインである。だから相関係数が0、無相関のときは2変数が「直交」しているし、相関係数の絶対値が1、完全に相関しているときは「平行」であると幾何的には捉えられる。このような見方は正規分布しているか否かによって妨げられるものではないのではないか。

なお、二次元正規分布のパラメータのひとつの最尤推定量が相関係数になるという事実はあるらしい。
www.bananarian.net
www.jstage.jst.go.jp

回帰分析との比較

回帰分析にも似たような話がある。回帰分析では通常、次の4つの仮定が置かれる。

  • 誤差項の平均が0
  • 誤差項の分散が均一
  • 異なるデータの誤差項の共分散が0
  • 誤差項が正規分布に従う

このうち、誤差の正規性だけはなくてもガウス・マルコフの定理が成立する。すなわち、最小二乗推定量がBLUEとなる。

一方で回帰係数の検定や区間推定をするには正規性が求められる。相関係数と同じ話で、分布の仮定なしには検定も区間推定もやりようがないからだ。回帰分析をするからには係数の有意性が気になるので、結局正規性が要求されるという考え方もあるが、ビッグデータモデリングは検定の必要性が薄く、データサイズによりけりではないか?