野球データの可視化

野球データを可視化するチュートリアルです。

このチュートリアルでは、野球データを可視化します。以下の点を学習することができます。

  • トポロジーをどのように分析するか

Requirement

In [1]:
import numpy as np

import pandas as pd

from renom_tda.topology import Topology
from renom_tda.lens import PCA

野球データのインポート

https://github.com/nyk510/baseball_dataset/tree/master/data から2016年度のプロ野球の打撃成績を取得します。
取得した打撃成績をもとにセイバーメトリクスの指標を計算します。
  • OPS :打者が得点増に有効な打撃をしているかどうかを表す指標。数値が高いほどチームの得点増に貢献している打者だと判断できる。

OPS = 出塁率 + 長打率
出塁率 = (安打数 + 四球数 + 死球数 ) ÷ (打数 + 四球数 + 死球数 + 犠飛数 )
長打率 = 塁打 / 打数 塁打 = 単打数x1 + 二塁打数x2 + 三塁打数x3 + 本塁打数x4
  • IsoP :打者の長打力を表す指標。安打が全てシングルヒットの場合は0になる。

IsoP = 長打率 - 打率

  • BABIP:本塁打を除くフェア打球が安打になった割合。

BABIP = ( 安打数 - 本塁打数 ) / ( 打数 + 犠飛数 - 本塁打数 - 三振数 )

  • BB/K :四球と三振の割合から打者の選球眼を見る指標。BB/K = 四球数 / 三振数

  • PA/K :1三振するまでに掛かる打席数。PA/K = 打数 / 三振数

  • AB/HR:1本塁打を記録するまでに掛かる打数。AB/HR = 打数 / 本塁打数

  • SecA :打率から長打の要素を抽出したもの。

SecA = ( 塁打 - 安打数 + 四球数 + 盗塁数 - 盗塁失敗数 ) / 打数

  • TA :打者が1アウト当たりにどれだけの塁打を得ることが出来たかを示す指標。

TA = ( 塁打数 + 四球数 + 死球数 + 盗塁数 - 盗塁失敗数 ) / ( 打数 - 安打数 + 盗塁失敗数 + 併殺打数 )

  • PS :パワー・機動力を兼ね揃えた選手かを見るための指標。

PS = ( 本塁打数 × 盗塁数 × 2) / ( 本塁打数 + 盗塁数 )

  • RC27 :ある打者が一人で打線を組んだ場合の1試合(27アウト)あたりの得点数。

RC = ( 2.4 × C + A ) × ( 3 × C + B ) ÷ (9 × C) - 0.9 × C
A = 安打数 + 四球数 + 死球数 - 盗塁失敗数 - 併殺打数
B = 塁打 + 0.26 ×(四球数 + 死球数) + 0.53 ×(犠飛数 + 犠打数) + 0.64 × 盗塁数 - 0.03 × 三振数
C = 打数 + 四球数 + 死球数 + 犠飛数 + 犠打数
In [2]:
file_path = "hitter_metrics.csv"
pdata = pd.read_csv(file_path).dropna()

テキストデータと数値データの分割

チーム名や選手名などのテキストデータと、数値データを抽出します。

In [3]:
text_data = np.array(pdata.loc[:, pdata.dtypes=="object"])
number_data = np.array(pdata.loc[:, np.logical_or(pdata.dtypes=="float", pdata.dtypes=="int")])

インスタンス作成

In [4]:
topology = Topology()

Load data

もしデータを標準化して入力したい場合は、standardize引数にTrueを入力します。

In [5]:
topology.load_data(number_data, text_data=text_data, standardize=True)

ポイントクラウド作成

In [6]:
metric = None
lens = [PCA(components=[0,1])]
topology.fit_transform(metric=metric, lens=lens)
projected by PCA.

位相空間へマッピング

In [7]:
topology.map(resolution=25, overlap=0.7, eps=0.3, min_samples=1)
created 145 nodes.
created 457 edges.

色付け & 表示

次にトポロジーを色付けし、表示します。

In [8]:
target = topology.number_data[:, 0]
topology.color(target, color_method="mean", color_type="rgb")
topology.show(fig_size=(10,10), node_size=10, edge_width=0.5)
../../../_images/notebooks_tda-case-study_baseball-data-mapping_notebook_16_0.png

選手の検索

In [9]:
search_dicts = [{
    "data_type": "text",
    "operator": "like",
    "column": 1,
    "value": "大谷"
}]

target = topology.number_data[:, 0]
topology.color(target, color_method="mean", color_type="rgb")
node_index = topology.search_from_values(search_dicts=search_dicts, target=None, search_type="index")
topology.show(fig_size=(10,10), node_size=10, edge_width=0.5)
../../../_images/notebooks_tda-case-study_baseball-data-mapping_notebook_18_0.png

チームの検索

In [10]:
search_dicts = [{
    "data_type": "text",
    "operator": "like",
    "column": 0,
    "value": "ヤクルト"
}]

target = topology.number_data[:, 0]
topology.color(target, color_method="mean", color_type="rgb")
node_index = topology.search_from_values(search_dicts=search_dicts, target=None, search_type="index")
topology.show(fig_size=(10,10), node_size=10, edge_width=0.5)
../../../_images/notebooks_tda-case-study_baseball-data-mapping_notebook_20_0.png

入力データからの検索

In [11]:
search_dicts = [{
    "data_type": "number",
    "operator": ">",
    "column": 0,
    "value": 0.9
}]

target = topology.number_data[:, 0]
topology.color(target, color_method="mean", color_type="rgb")
node_index = topology.search_from_values(search_dicts=search_dicts, target=None, search_type="index")
topology.show(fig_size=(10,10), node_size=10, edge_width=0.5)
../../../_images/notebooks_tda-case-study_baseball-data-mapping_notebook_22_0.png
色が付いているノードはOPSが0.9以上のプレイヤーが所属しています。
search_from_values関数の帰り値で検索結果のノードのidを受け取ることができます。
In [12]:
node_index
Out[12]:
[137, 138, 139, 140, 141, 142, 143, 144]

csvファイルに出力

トポロジーインスタンスはノードIDから、ノード内に含むデータをcsvファイルに出力することができます。
text_data_columnsと、number_data_columns変数がNoneでないとき、skip_headerにFalseを入力すると出力ファイルにヘッダーをつけることができます。
In [13]:
topology.output_csv_from_node_ids("output.csv", node_ids=node_index, skip_header=True)