tag:crieit.net,2005:https://crieit.net/tags/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E8%B7%9D%E9%9B%A2/feed 「ユークリッド距離」の記事 - Crieit Crieitでタグ「ユークリッド距離」に投稿された最近の記事 2019-04-23T15:51:13+09:00 https://crieit.net/tags/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E8%B7%9D%E9%9B%A2/feed tag:crieit.net,2005:PublicArticle/14939 2019-04-21T19:39:23+09:00 2019-04-23T15:51:13+09:00 https://crieit.net/posts/5308d8a3ed140ecc15e1310dad28e9e9 野球のデータを用いて選手間の「類似度」を計算する <h1 id="背景"><a href="#%E8%83%8C%E6%99%AF">背景</a></h1> <p>今回は統計の話に近くなってしまうのですが、選手を傾向に応じてグループ化できると面白いなーと思っていて、「野球 似ている 選手」などでググってみると、Baseball LABのコラムを見つけました。<br /> <a target="_blank" rel="nofollow noopener" href="http://www.baseball-lab.jp/column/entry/14/">コラム:「近い」選手とは?</a></p> <h1 id="類似度の計算について"><a href="#%E9%A1%9E%E4%BC%BC%E5%BA%A6%E3%81%AE%E8%A8%88%E7%AE%97%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">類似度の計算について</a></h1> <p>現在データを集めている野球リーグでは、選手によって打席数の差がかなりあり、グラフを描いたときの二点間の距離(<strong>ユークリッド距離</strong>)の算出に打席数の偏りが反映されてしまうため、x,y軸に割合を採用することにしました。</p> <h2 id="ユークリッド距離とは"><a href="#%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E8%B7%9D%E9%9B%A2%E3%81%A8%E3%81%AF">ユークリッド距離とは</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://ja.wikipedia.org/wiki/ユークリッド距離">ユークリッド距離 - wikipedia</a><br /> 要は2点間の距離です。今回は二次元を扱うので、皆さんご存知の三平方の定理を使います。</p> <h2 id="x,y軸に採用するもの"><a href="#x%2Cy%E8%BB%B8%E3%81%AB%E6%8E%A1%E7%94%A8%E3%81%99%E3%82%8B%E3%82%82%E3%81%AE">x,y軸に採用するもの</a></h2> <p>どのような指標を採用するかによって、類似度の現れ方が異なるので、<br /> 事前にChart.jsなどでグラフを書いていくつか検討した結果です。</p> <h3 id="打者の場合"><a href="#%E6%89%93%E8%80%85%E3%81%AE%E5%A0%B4%E5%90%88">打者の場合</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://ja.wikipedia.org/wiki/長打率">長打率(SLG)</a>:塁打の合計数を打席数で割った指標。</li> <li><a target="_blank" rel="nofollow noopener" href="https://ja.wikipedia.org/wiki/三振#打数_/_三振比率_%28At_Bats_per_Strikeout_:_AB/K%29">打数 / 三振比率 (At Bats per Strikeout : 三振のしにくさ)</a></li> </ul> <h3 id="MySQLでのユークリッド距離の計算"><a href="#MySQL%E3%81%A7%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E8%B7%9D%E9%9B%A2%E3%81%AE%E8%A8%88%E7%AE%97">MySQLでのユークリッド距離の計算</a></h3> <p><strong>SELECT</strong><br /> 全体の成績を計算したものからselectして、ある選手のAB/Kと長打率の数値を渡して類似度が近い順に5つのレコードを取り出します。<br /> <strong>WHERE</strong><br /> 選手自身が類似度0として取れてしまうのでwhere句で除外します。<br /> 代表的な選手を類似度の候補として挙げるために条件を42打席以上としています。</p> <pre><code class="sql">select name, player_id, tpa, not_strike_out, SLG, SQRT(POW(?-not_strike_out,2)+POW(?-SLG,2)) as distance from( SELECT player_id, name, p.team_id as teamId, team_name, CASE WHEN (sum(hit)/sum(at_bats)) is null THEN 0 WHEN (sum(hit)/sum(at_bats)) is not null THEN (sum(hit)/sum(at_bats)) END as average, CASE WHEN ((sum(hit)+sum(twobase)*1+sum(homerun)*2)/sum(at_bats)) is null THEN 0 WHEN ((sum(hit)+sum(twobase)*1+sum(homerun)*2)/sum(at_bats)) is not null THEN ((sum(hit)+sum(twobase)*1+sum(homerun)*2)/sum(at_bats)) END as SLG, CASE WHEN ((sum(hit)+sum(four_ball))/sum(tpa))+((sum(hit)+sum(twobase)*1+sum(homerun)*2)/sum(at_bats)) is null THEN 0 WHEN ((sum(hit)+sum(four_ball))/sum(tpa))+((sum(hit)+sum(twobase)*1+sum(homerun)*2)/sum(at_bats)) is not null THEN ((sum(hit)+sum(four_ball))/sum(tpa))+((sum(hit)+sum(twobase)*1+sum(homerun)*2)/sum(at_bats)) END as OPS, (sum(hit)+sum(four_ball))/sum(tpa) as OBP, ((((sum(hit)+sum(twobase)*1+sum(homerun)*2)+0.26*sum(four_ball)-0.03*sum(strike_out)+3*sum(tpa))*(sum(hit)+sum(four_ball)+2.4*sum(tpa)))/(9*sum(tpa))-0.9*sum(tpa))*27/(sum(at_bats)-sum(hit)) as RC27, CASE WHEN sum(at_bats)/sum(strike_out) is null THEN 0 WHEN sum(at_bats)/sum(strike_out) is not null THEN sum(at_bats)/sum(strike_out) END as not_strike_out, CASE WHEN sum(four_ball)/sum(strike_out) is null THEN 0 WHEN sum(four_ball)/sum(strike_out) is not null THEN sum(four_ball)/sum(strike_out) END as bbk, CASE WHEN sum(at_bats)/sum(homerun) is null THEN 0 WHEN sum(at_bats)/sum(homerun) is not null THEN sum(at_bats)/sum(homerun) END as avg_homerun, CASE WHEN sum(rbi)/sum(at_bats) is null THEN 0 WHEN sum(rbi)/sum(at_bats) is not null THEN sum(rbi)/sum(at_bats) END as avgRbi, sum(tpa) as tpa, sum(at_bats) as at_bats, sum(hit) as hit, sum(rbi) as rbi, sum(four_ball) as four_ball, sum(strike_out) as strike_out, sum(twobase) as twobase, sum(homerun) as homerun FROM batting_sum b INNER JOIN game g on b.game_id=g.game_id INNER JOIN player p on b.player_id=p.id INNER JOIN team t on t.team_id=p.team_id group by player_id)p where tpa>=42 and player_id <> ? order by distance asc limit 5 </code></pre> <h3 id="投手の場合"><a href="#%E6%8A%95%E6%89%8B%E3%81%AE%E5%A0%B4%E5%90%88">投手の場合</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://ja.wikipedia.org/wiki/WHIP">WHIP(Walks plus Hits per Inning Pitched)</a>:与四球・被安打数合計の合計を投球回数で割ったもの。</li> <li><a target="_blank" rel="nofollow noopener" href="https://ja.wikipedia.org/wiki/三振#奪三振率">奪三振率</a>:奪三振率=奪三振数× <strong>5</strong> ÷投球回</li> </ul> <h3 id="MySQLでのユークリッド距離の計算"><a href="#MySQL%E3%81%A7%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E8%B7%9D%E9%9B%A2%E3%81%AE%E8%A8%88%E7%AE%97">MySQLでのユークリッド距離の計算</a></h3> <pre><code class="sql">select player_id, name, WHIP, strike_avg, inning, SQRT(POW(?-WHIP,2)+POW(?-strike_avg,2)) as distance from ( SELECT p.player_id, name, pl.team_id as teamId, team_name, sum(runs)/sum(inning)*5 as era, (sum(hit)+sum(four_ball))/sum(inning) as WHIP, sum(four_ball)/sum(inning)*5 as BB5, sum(strike_out)/sum(inning)*5 as strike_avg, sum(inning) as inning, sum(pa) as pa, sum(hit) as hit, sum(homerun) as homerun, sum(four_ball) as four_ball, sum(strike_out) as strike_out, sum(runs) as runs, sum(complete) as complete, sum(shutout) as shutout, sum(win) as win, sum(lose) as lose, sum(save) as save, p3.run_support FROM pitching p inner join game g on g.game_id=p.game_id inner join player pl on p.player_id=pl.id inner join team t on t.team_id=pl.team_id left outer join( SELECT p.player_id as player_id, sum(p2.runs)/sum(p2.inning)*5 as run_support FROM pitching p inner join game g on p.game_id=g.game_id inner join pitching p2 on p.game_id=p2.game_id and p.myteam_id!=p2.myteam_id group by player_id)p3 on p3.player_id=p.PLAYER_ID group by player_id)p where player_id<>? and inning >= 18 order by distance asc limit 5 </code></pre> <h1 id="実装結果"><a href="#%E5%AE%9F%E8%A3%85%E7%B5%90%E6%9E%9C">実装結果</a></h1> <p><a target="_blank" rel="nofollow noopener" href="https://jcblscore-react.netlify.com/player/show/1">野球リーグスコア管理システム</a>の方に改修内容を反映しています。</p> <h2 id="選手例1"><a href="#%E9%81%B8%E6%89%8B%E4%BE%8B1">選手例1</a></h2> <p>この選手の場合は投球は軟投派の投手との類似度が高いことが示せています。<br /> <strong>軟投派の場合は奪三振率が低めになる傾向があります。</strong><br /> 打者としてはパワーヒッターで三振のしにくい選手が類似選手として挙がっています。<br /> <a href="https://crieit.now.sh/upload_images/c757f121bd19245f1a30d36c3424b0625cbc467eab1ef.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c757f121bd19245f1a30d36c3424b0625cbc467eab1ef.jpg?mw=700" alt="image" /></a></p> <h2 id="選手例2"><a href="#%E9%81%B8%E6%89%8B%E4%BE%8B2">選手例2</a></h2> <p>この選手の場合は<strong>速球派</strong>で<strong>長打力</strong>のある選手が類似度が高いことを示しています。<br /> <a href="https://crieit.now.sh/upload_images/c3dfcfa14baac17d4d2396730359de445cbc47f573614.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c3dfcfa14baac17d4d2396730359de445cbc47f573614.jpg?mw=700" alt="image" /></a></p> ckoshien