[PYTHON] Vérifier l'exactitude de la formule de notation «RC» à l'aide des données réelles du baseball professionnel

  1. Introduction

Écrivain sportif aux États-Unis et pionnier des mesures de sauvegarde du baseball [Bill James](https://ja.wikipedia.org/wiki/%E3%83%93%E3%83%AB%E3%83 % BB% E3% 82% B8% E3% 82% A7% E3% 83% BC% E3% 83% A0% E3% 82% BA) a créé une formule pour prédire le score de l'équipe.

Nombre de points=  (Nombre de visites+Nombre de quatre balles)× Nombre de coups de base ÷(Nombre de coups+Nombre de quatre balles)

Le score estimé par cette formule a été nommé ** RC (Runs Created) **. James a remplacé les records de la saison passée de diverses équipes de la MLB sur le côté droit de cette formule pour voir si cela correspondait au score réel. En conséquence, cette formule était valable quelle que soit l'équipe appliquée, et le score pouvait être prédit avec une précision extrêmement élevée. Mais il y a une question.

Par conséquent, cette fois, nous avons vérifié l'exactitude de cette formule de score RC en utilisant les données réelles de l'équipe de la CNLC.

  1. Data and Program 2.1. Data Les données utilisées sont les résultats de la saison des 12 équipes de baseball professionnel japonais (NPB) de 2005 à 2016. Les données sont la page d'accueil de l'organisation japonaise de baseball http://npb.jp/ Obtenu à partir de. Par exemple, les résultats de la saison 2016 de la Se League http://npb.jp/bis/2016/stats/tmb_c.html Obtenu à partir de, traité le format comme suit et enregistré.

2016C_bat.csv


Carp, .272, 143, 5582, 4914, 684, 1338, 203, 35, 153, 2070, 649, 118, 52, 91, 29, 500, 13, 47, 1063, 85, .421, .343
Yakult, .256, 143, 5509, 4828, 594, 1234, 210, 20, 113, 1823, 565, 82, 24, 85, 33, 524, 10, 39, 907, 117, .378, .331
Giants, .251, 143, 5356, 4797, 519, 1203, 217, 19, 128, 1842, 497, 62, 26, 112, 23, 389, 11, 35, 961, 100, .384, .310
DeNA, .249, 143, 5364, 4838, 572, 1205, 194, 21, 140, 1861, 548, 67, 34, 81, 18, 373, 7, 54, 1049, 92, .385, .309
Dragons, .245, 143, 5405, 4813, 500, 1180, 209, 21, 89, 1698, 473, 60, 28, 108, 28, 410, 7, 46, 1001, 103, .353, .309
Tigers, .245, 143, 5401, 4789, 506, 1171, 204, 17, 90, 1679, 475, 59, 25, 88, 38, 435, 17, 51, 1149, 99, .351, .312

(Les données sont https://github.com/AnchorBlues/python/tree/master/baseballdata J'ai mis celui traité dans

2.2. Program Le langage de programmation Python a été utilisé pour lire, analyser et visualiser les données.

NPB.py


#coding:utf - 8

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

fy = 2005
ly = 2016
Yn = ly - fy + 1

Bat_Column = ['Average', 'Game', 'PA', 'AB', 'Score', 'Hit', \
			  'TwoBase', 'ThreeBase', 'HR', 'TB', 'RBI', 'Steel', \
			  'MissSteal', 'Bunt', 'SF', 'BB', 'IntentionalWalk', \
			  'DeadBall', 'StrikeOut', 'DoublePlay', 'SLG', 'OBP']

# PA :Aspect de la plaque Nombre de places
# AB :Aux coups de chauve-souris
# TB :Total des bases Nombre de bases
# RBI :Point de point
# SF :Sacrifice Fly Sacrifice Fly
# IntentionalWalk :Quatre balles intentionnelles

N = len(Bat_Column)

class Bat_Data():
	def __init__(self, Data, Year, Team):
		self.Year = Year
		self.Team = Team
		for i in range(0, N):
			setattr(self, Bat_Column[i], Data[:, i])

		self.OPS = self.SLG + self.OBP
		self.NOI = (self.SLG / 3.0 + self.OBP) * 1000
		self.BABIP = (self.Hit - self.HR) / (self.AB + self.SF - self.HR - self.StrikeOut)
		self.RC = (self.Hit + self.BB) * self.TB / (self.AB + self.BB)
		self.IsoP = self.SLG - self.Average
		self.IsoD = self.OBP - self.Average



class TEAM:
	def __init__(self, ID, Name, maker):
		self.ID = ID
		self.Name = Name
		self.maker = maker


team = [0] * 12
team[0] = TEAM(0, 'Carp', '>')
team[1] = TEAM(1, 'Tigers', '<')
team[2]= TEAM(2, 'Giants', '^')
team[3] = TEAM(3, 'Dragons', 'v')
team[4] = TEAM(4, 'DeNA', 'd')
team[5] = TEAM(5, 'Yakult', 'D')
team[6] = TEAM(6, 'Fighters', '8')
team[7] = TEAM(7, 'Lotte', 'H')
team[8] = TEAM(8, 'Lions', 'h')
team[9] = TEAM(9, 'Eagles', '*')
team[10] = TEAM(10, 'Orix', 'p')
team[11] = TEAM(11, 'Hawks', 's')


#Deux chauve-souris_Consolider les instances de données en une seule instance
def Docking(Data1, Data2):

	data = np.zeros((Data1.Average.shape[0] + Data2.Average.shape[0], N))
	for i in range(0, N):
		data[:, i] = np.r_[getattr(Data1, Bat_Column[i]), getattr(Data2, Bat_Column[i])]

	year = np.r_[Data1.Year, Data2.Year]
	team = np.r_[Data1.Team, Data2.Team]
	Data_new = Bat_Data(data, year, team)
	return Data_new


def get_data(League, year):
	fname = './baseballdata/' + str(year) + League + '_bat.csv'
	Data = np.loadtxt(fname, delimiter = ',', usecols = range(1, N + 1))
	Year = np.ones(6) * year
	Team = np.loadtxt(fname, delimiter = ',', usecols = range(0, 1), dtype = str)
	Data = Bat_Data(Data, Year, Team)
	return Data


def get_all_data(League):
	for i in range(Yn):
		year = i + fy
		tmp = get_data(League, year)
		if i == 0:
			Data = tmp
		else:
			Data = Docking(Data, tmp)

	return Data

# Data.Column_D'après le nom, le nom de l'équipe est Team_Extrayez uniquement celui avec le nom.
def PickUp_Data_of_a_team(Data, Column_name, Team_name):
	return getattr(Data, Column_name)[np.where(getattr(Data, 'Team') == Team_name)]


def draw_scatter(plt, Data, X_name, Y_name, regression_flg = 0, Y_eq_X_line_flg = 0, \
				 title = 'Scatter plot', fsizex = 10, fsizey = 8):

	fig, ax = plt.subplots(figsize = (fsizex, fsizey))
	plt.rcParams['font.size'] = 16

	for i in range(0, len(team)):
		x = PickUp_Data_of_a_team(Data, X_name, team[i].Name)
		y = PickUp_Data_of_a_team(Data, Y_name, team[i].Name)
		year = PickUp_Data_of_a_team(Data, 'Year', team[i].Name)
		if x != np.array([]):
			CF = ax.scatter(x, y, c = year, s = 50, marker = team[i].maker, \
							label = team[i].Name, vmin = fy, vmax = ly)

		if i == 0:
			X = x
			Y = y
		else:
			X = np.r_[X, x]
			Y = np.r_[Y, y]

	plt.colorbar(CF, ticks = list(np.arange(fy, ly + 1)), label = 'year')
	plt.legend(bbox_to_anchor = (1.35, 1), loc = 2, borderaxespad = 0., scatterpoints = 1)
	ax.set_title(title)
	ax.set_xlabel(X_name)
	ax.set_ylabel(Y_name)

	#Tracez une ligne de régression
	if regression_flg == 1:
		slope, intercept, r_value, _, _ = stats.linregress(X, Y)
		xx = np.arange(450, 750, 1)
		yy = slope * xx + intercept
		ax.plot(xx, yy, linewidth = 2)

	# y=Tracez une ligne droite de x
	if Y_eq_X_line_flg == 1:
		xx = np.arange(450, 750, 1)
		yy_d = xx
		ax.plot(xx, yy_d, color = 'k')

	print 'Correlation=', np.corrcoef(X, Y)[0, 1]
	return plt

Par exemple, si vous souhaitez récupérer les données de la Ligue SE 2016, procédez comme suit.

In [1]:import NPB
In [2]:Data_2016C=NPB.get_data('C',2016)   #Quand tu veux être une ligue pa'C'À'P'À.
In [3]:Data_2016C.Average  #Afficher le taux de réussite de chacune des 6 équipes de la Ligue centrale 2016

Out[3]: array([ 0.272,  0.256,  0.251,  0.249,  0.245,  0.245])
  1. Result 3.1. Average vs Score Tout d'abord, examinons la corrélation entre l'indice de réussite le plus courant, le «taux de réussite» et le nombre de points marqués. Retirez les données de l'équipe (144 échantillons au total) des 12 équipes de 2005 à 2016 et tracez un diagramme de dispersion avec «Moyenne» sur l'axe horizontal et «Score» sur l'axe vertical. Essayer.
In [1]:import matplotlib.pyplot as plt
In [2]:Data_C=NPB.get_all_data('C')   #Extraire toutes les données de la ligue
In [3]:Data_P=NPB.get_all_data('P')   #Extraire toutes les données de Pa League
In [4]:Data=NPB.Docking(Data_C,Data_P) #Intégrez les données des deux ligues
In [5]:plt=NPB.draw_scatter(plt,Data,'Average','Score') #Dessinez un nuage de points du taux et du score au bâton
In [6]:plt.show()

Le chiffre de sortie est le suivant. image

De plus, le coefficient de corrélation est Correlation= 0.825987845723 Le résultat était que.

3.2. RC vs Score Pour les mêmes données que 3.1., Dessinez maintenant un diagramme de dispersion avec "RC" sur l'axe horizontal et "Score" sur l'axe vertical.

In [7]:plt=NPB.draw_scatter(plt,Data,'RC','Score',regression_flg=1,Y_eq_X_line_flg=1) #Dessinez un diagramme de dispersion de RC et des scores. De plus, la droite de régression et y=Tracez une ligne droite de x.
In [8]:plt.show()

Le chiffre de sortie est le suivant. image

De plus, le coefficient de corrélation est Correlation= 0.953524104544 Le résultat était que. A partir de la valeur du coefficient de corrélation, on peut voir qu'il existe une corrélation extrêmement forte entre RC et le score. De plus, la ligne de régression (ligne bleue dans la figure ci-dessus) est très proche de la ligne droite de "y = x" (ligne noire dans la figure ci-dessus). (La droite de régression était «y = 0,95 * x-6,3»)

  1. Conclusion À la suite de la vérification avec les données de l'équipe précédente de la CNLC, il a été constaté que le RC officiel de notation peut prédire le nombre de points de l'équipe de la CNLC avec une précision extrêmement élevée. La formule RC élaborée par Bill James a maintenant été améliorée, comme la valeur du coefficient, et le nombre de bases volées est également utilisé comme variable explicative (voir la page Wikipédia [voir ci-dessous]). Cependant, le grand avantage de la formule de score conçue par Bill James est que le score ne peut être estimé avec précision que par ** capacité de base (= nombre de coups + nombre de quatre balles) x capacité d'avance (= nombre de coups de base) **. Je pense. Chaque variable explicative n'a pas de coefficient et la forme de l'équation est très simple. Le fait que nous ayons découvert que nous pouvons estimer le nombre de points avec une formule aussi simple est toujours à noter.

References

Recommended Posts

Vérifier l'exactitude de la formule de notation «RC» à l'aide des données réelles du baseball professionnel
Déterminez le nombre de classes à l'aide de la formule Starges
Transition du baseball vue à partir des données
Vérifiez l'état des données à l'aide de pandas_profiling
Gratter les données gagnantes de Numbers à l'aide de Docker
J'ai essayé d'utiliser l'API de Sakenowa Data Project
[Python] J'ai essayé de collecter des données en utilisant l'API de wikipedia