Am 18. Juni 2014 warf Dodgers Pitcher Clayton Kershaw im Match Colorado Rockies gegen Los Angeles Dodgers neun Innings und erzielte 15 Treffer und keine Treffer. Dieses Mal werden wir es mit dem Pitcher der gegnerischen Rockies vergleichen und analysieren, warum Pitcher Clayton Kershaw einen No-Hit No-Run erzielen konnte.
・ Python 3.7.5 ・ Windows10 ・ Jupyter-Notizbuch (Anaconda3)
$ jupyter notebook
baseball_analysis.ipynb
%matplotlib inline
import requests
import xml.etree.ElementTree as ET
import os
import pandas as pd
baseball_analysis.ipynb
#Datenrahmenerstellung
pitchDF = pd.DataFrame(columns = ['pitchIdx', 'inning', 'frame', 'ab', 'abIdx', 'batter', 'stand', 'speed',
'pitchtype', 'px', 'pz', 'szTop', 'szBottom', 'des'], dtype=object)
#Erstellen Sie ein Balltyp-Wörterbuch
pitchDictionary = { "FA":"fastball", "FF":"4-seam fb", "FT": "2-seam fb", "FC": "fb-cutter", "":"unknown", None: "none",
"FS":"fb-splitter", "SL":"slider", "CH":"changeup","CU":"curveball","KC":"knuckle-curve",
"KN":"knuckleball","EP":"eephus", "UN":"unidentified", "PO":"pitchout", "SI":"sinker", "SF":"split-finger"
}
# top=Tabelle unten=zurück
frames = ["top", "bottom"]
baseball_analysis.ipynb
#Lesen Sie die von MLB Advanced Media verteilten Player-Informationen
url = 'https://gd2.mlb.com/components/game/mlb/year_2014/month_06/day_18/gid_2014_06_18_colmlb_lanmlb_1/players.xml'
resp = requests.get(url)
xmlfile = "myplayers.xml"
with open(xmlfile, mode='wb') as f:
f.write(resp.content)
statinfo = os.stat(xmlfile)
#XML-Datei analysieren
tree = ET.parse(xmlfile)
game = tree.getroot()
teams = game.findall("./team")
playerDict = {}
for team in teams:
players = team.findall("./player")
for player in players:
#Fügen Sie dem Wörterbuch die Spieler-ID und den Spielernamen hinzu
playerDict[ player.attrib.get("id") ] = player.attrib.get("first") + " " + player.attrib.get("last")
baseball_analysis.ipynb
#Lesen Sie die Daten für jedes von MLB Advanced Media verteilte Inning
url = 'https://gd2.mlb.com/components/game/mlb/year_2014/month_06/day_18/gid_2014_06_18_colmlb_lanmlb_1/inning/inning_all.xml'
resp = requests.get(url)
xmlfile = "mygame.xml"
with open(xmlfile, 'wb') as f:
f.write(resp.content)
statinfo = os.stat(xmlfile)
#XML-Datei analysieren
tree = ET.parse(xmlfile)
root = tree.getroot()
innings = root.findall("./inning")
totalPitchCount = 0
topPitchCount = 0
bottomPitchCount = 0
for inning in innings:
for i in range(len(frames)):
fr = inning.find(frames[i])
if fr is not None:
for ab in fr.iter('atbat'):
battername = playerDict[ab.get('batter')]
standside = ab.get('stand')
abIdx = ab.get('num')
abPitchCount = 0
pitches = ab.findall("pitch")
for pitch in pitches:
if pitch.attrib.get("start_speed") is None:
speed == 0
else:
speed = float(pitch.attrib.get("start_speed"))
pxFloat = 0.0 if pitch.attrib.get("px") == None else float('{0:.2f}'.format(float(pitch.attrib.get("px"))))
pzFloat = 0.0 if pitch.attrib.get("pz") == None else float('{0:.2f}'.format(float(pitch.attrib.get("pz"))))
szTop = 0.0 if pitch.attrib.get("sz_top") == None else float('{0:.2f}'.format(float(pitch.attrib.get("sz_top"))))
szBot = 0.0 if pitch.attrib.get("sz_bot") == None else float('{0:.2f}'.format(float(pitch.attrib.get("sz_bot"))))
abPitchCount = abPitchCount + 1
totalPitchCount = totalPitchCount + 1
if frames[i]=='top':
topPitchCount = topPitchCount + 1
else:
bottomPitchCount = bottomPitchCount + 1
inn = inning.attrib.get("num")
verbosePitch = pitchDictionary[pitch.get("pitch_type")]
desPitch = pitch.get("des")
#Zum Datenrahmen hinzufügen
pitchDF.loc[totalPitchCount] = [float(totalPitchCount), inn, frames[i], abIdx, abPitchCount, battername, standside, speed,
verbosePitch, pxFloat, pzFloat, szTop, szBot, desPitch]
baseball_analysis.ipynb
pitchDF
# pitchIdx=Ordnungsnummer
# inning=Inning
# frame=Vorne und Hinten
# ab=Batter ID
# abIdx=Anzahl der Bälle pro Schlag
# batter=Batter Name
# stand=Eine Fledermaus(R → Rechtshänder, L → Linkshänder)
# speed=Ballgeschwindigkeit
# pitchtype=Balltyp
# px=Home Base Passing Position(Links und rechts)(Rechts → positiv, links → negativ)
# pz=Home Base Passing Position(Hoch niedrig)
# szTop=Entfernung vom Boden zum höchsten Wert der Schlagzone des Schlägers
# szBottom=Entfernung vom Boden zum niedrigsten Wert der Schlagzone des Schlägers
# des=Ergebnis
baseball_analysis.ipynb
import matplotlib.pyplot as plt
import matplotlib.patches as patches
#Zeichne ein neues Fenster
fig1 = plt.figure()
#Untergrund hinzufügen
ax1 = fig1.add_subplot(111, aspect='equal')
#Die Breite der Streikzone beträgt 17 Zoll= 1.4 Fuß
#Die Höhe der Streikzone beträgt 1.5~3.5 Fuß
#Baseballballgröße ist 3 Zoll= 0.25 Fuß
#Wie man Füße findet=Zoll/ 12
#Streikzonenerstellung
#Der blaue Rahmen ist die Streikzone
platewidthInFeet = 17 / 12
szHeightInFeet = 3.5 - 1.5
#Erstellen Sie eine Trefferzone außerhalb eines Balls
#Der hellblaue Rahmen ist eine Schlagzone außerhalb einer Kugel
expandedPlateInFeet = 20 / 12
ballInFeet = 3 / 12
halfBallInFeet = ballInFeet / 2
ax1.add_patch(patches.Rectangle((expandedPlateInFeet/-2, 1.5 - halfBallInFeet), expandedPlateInFeet, szHeightInFeet + ballInFeet, color='lightblue'))
ax1.add_patch(patches.Rectangle((platewidthInFeet/-2, 1.5), platewidthInFeet, szHeightInFeet))
plt.ylim(0, 5)
plt.xlim(-2, 2)
plt.show()
baseball_analysis.ipynb
uniqDesList = pitchDF.des.unique()
ballColList = []
strikeColList = []
ballCount = 0
strikeCount = 0
for index, row in pitchDF.iterrows():
des = row['des']
if row['abIdx'] == 1:
ballCount = 0
strikeCount = 0
ballColList.append(ballCount)
strikeColList.append(strikeCount)
if 'Ball' in des:
ballCount = ballCount + 1
elif 'Foul' in des:
if strikeCount is not 2:
strikeCount = strikeCount + 1
elif 'Strike' in des:
strikeCount = strikeCount + 1
#Zum Datenrahmen hinzufügen
pitchDF['ballCount'] = ballColList
pitchDF['strikeCount'] = strikeColList
baseball_analysis.ipynb
pitchDF
baseball_analysis.ipynb
df= pitchDF.loc[pitchDF['frame']=='top']
ax1 = df.plot(kind='scatter', x='px', y='pz', marker='o', color='red', figsize=[8,8], ylim=[0,4], xlim=[-2,2])
ax1.set_xlabel('horizontal location')
ax1.set_ylabel('vertical location')
ax1.set_title('Clayton Kershaws Wurfneigung')
ax1.set_aspect(aspect=1)
platewidthInFeet = 17 / 12
expandedPlateInFeet = 20 / 12
szTop = df["szTop"].iloc[0]
szBottom = df["szBottom"].iloc[0]
szHeightInFeet = szTop - szBottom
ballInFeet = 3 / 12
halfBallInFeet = ballInFeet / 2
outrect = ax1.add_patch(patches.Rectangle((expandedPlateInFeet/-2, szBottom - halfBallInFeet), expandedPlateInFeet, szHeightInFeet + ballInFeet, color='lightblue'))
rect = ax1.add_patch(patches.Rectangle((platewidthInFeet/-2, szBottom), platewidthInFeet, szHeightInFeet))
outrect.zorder=-2
rect.zorder=-1
plt.ylim(0, 5)
plt.xlim(-2.5, 2.5)
plt.show()
baseball_analysis.ipynb
df= pitchDF.loc[pitchDF['frame']=='bottom']
ax1 = df.plot(kind='scatter', x='px', y='pz', marker='o', color='red', figsize=[8,8], ylim=[0,4], xlim=[-2,2])
ax1.set_xlabel('horizontal location')
ax1.set_ylabel('vertical location')
ax1.set_title('Rockies werfen Tendenz')
ax1.set_aspect(aspect=1)
platewidthInFeet = 17 / 12
expandedPlateInFeet = 20 / 12
szTop = df["szTop"].iloc[0]
szBottom = df["szBottom"].iloc[0]
szHeightInFeet = szTop - szBottom
ballInFeet = 3 / 12
halfBallInFeet = ballInFeet / 2
outrect = ax1.add_patch(patches.Rectangle((expandedPlateInFeet/-2, szBottom - halfBallInFeet), expandedPlateInFeet, szHeightInFeet + ballInFeet, color='lightblue'))
rect = ax1.add_patch(patches.Rectangle((platewidthInFeet/-2, szBottom), platewidthInFeet, szHeightInFeet))
outrect.zorder=-2
rect.zorder=-1
plt.ylim(0, 5)
plt.xlim(-2.5, 2.5)
plt.show()
Vergleich beider Krüge, ** Clayton-Trefferquote: 65% ** ** Rockies Streikrate: 56% ** Ich habe herausgefunden, dass. Ich habe das Gefühl, dass Clayton weniger seitlich verfehlte Bälle hat als Rockies Pitcher. Ist es der Einfluss des Schiebereglers oder der Geraden, der hüpft, dass es in vertikaler Richtung große Abweichungen gibt?
Als nächstes schauen wir uns die Tendenz des ersten Balls an.
baseball_analysis.ipynb
df= pitchDF.loc[pitchDF['frame']=='top'].loc[pitchDF['abIdx']==1]
ax1 = df.plot(kind='scatter', x='px', y='pz', marker='o', color='red', figsize=[8,8], ylim=[0,4], xlim=[-2,2])
ax1.set_xlabel('horizontal location')
ax1.set_ylabel('vertical location')
ax1.set_title('Clayton Kershaws erste Balltendenz')
ax1.set_aspect(aspect=1)
platewidthInFeet = 17 / 12
expandedPlateInFeet = 20 / 12
szTop = df["szTop"].iloc[0]
szBottom = df["szBottom"].iloc[0]
szHeightInFeet = szTop - szBottom
ballInFeet = 3 / 12
halfBallInFeet = ballInFeet / 2
outrect = ax1.add_patch(patches.Rectangle((expandedPlateInFeet/-2, szBottom - halfBallInFeet), expandedPlateInFeet, szHeightInFeet + ballInFeet, color='lightblue'))
rect = ax1.add_patch(patches.Rectangle((platewidthInFeet/-2, szBottom), platewidthInFeet, szHeightInFeet))
outrect.zorder=-2
rect.zorder=-1
plt.ylim(0, 5)
plt.xlim(-2.5, 2.5)
plt.show()
baseball_analysis.ipynb
df= pitchDF.loc[pitchDF['frame']=='bottom'].loc[pitchDF['abIdx']==1]
ax1 = df.plot(kind='scatter', x='px', y='pz', marker='o', color='red', figsize=[8,8], ylim=[0,4], xlim=[-2,2])
ax1.set_xlabel('horizontal location')
ax1.set_ylabel('vertical location')
ax1.set_title('Rockies erste Balltendenz')
ax1.set_aspect(aspect=1)
platewidthInFeet = 17 / 12
expandedPlateInFeet = 20 / 12
szTop = df["szTop"].iloc[0]
szBottom = df["szBottom"].iloc[0]
szHeightInFeet = szTop - szBottom
ballInFeet = 3 / 12
halfBallInFeet = ballInFeet / 2
outrect = ax1.add_patch(patches.Rectangle((expandedPlateInFeet/-2, szBottom - halfBallInFeet), expandedPlateInFeet, szHeightInFeet + ballInFeet, color='lightblue'))
rect = ax1.add_patch(patches.Rectangle((platewidthInFeet/-2, szBottom), platewidthInFeet, szHeightInFeet))
outrect.zorder=-2
rect.zorder=-1
plt.ylim(0, 5)
plt.xlim(-2.5, 2.5)
plt.show()
Vergleich beider Krüge, ** Claytons erste Ballschlagrate: 71% ** ** Rockies First Ball Strike Rate: 64% ** Ich habe herausgefunden, dass.
Pitcher Clayton hat eine kleine Anzahl von Bällen und ist dem Schlag voraus.
Als nächstes schauen wir uns die Änderung der Ballgeschwindigkeit an.
baseball_analysis.ipynb
df = pitchDF.loc[(pitchDF['frame']=='top')]
speed = df['speed']
print(sum(speed) / len(speed))
print(max(speed))
print(min(speed))
print(max(speed) - min(speed))
ax = df.plot(x='pitchIdx', y='speed', color='blue', figsize=[12,6])
ax.set_ylabel('speed')
ax.set_title('Rockies Ball Geschwindigkeitsänderung')
plt.savefig('pitch_rockies_speed.png')
plt.show()
>>>>>>>>>>>>>>>>>>>>>>>>>
#Durchschnittliche Ballgeschwindigkeit: 87.88504672897201
#Am schnellsten: 95.0
#Das Neueste: 72.4
#Langsamer / schneller Unterschied: 22.599999999999994
baseball_analysis.ipynb
df = pitchDF.loc[(pitchDF['frame']=='bottom')]
speed = df['speed']
print(sum(speed) / len(speed))
print(max(speed))
print(min(speed))
print(max(speed) - min(speed))
ax = df.plot(x='pitchIdx', y='speed', color='blue', figsize=[12,6])
ax.set_ylabel('speed')
ax.set_title('Rockies Ball Geschwindigkeitsänderung')
plt.savefig('pitch_rockies_speed.png')
plt.show()
>>>>>>>>>>>>>>>>>>>>>>>>>
#Durchschnittliche Ballgeschwindigkeit: 89.13599999999998
#Am schnellsten: 96.3
#Das Neueste: 71.8
#Langsamer / schneller Unterschied: 24.5
Vergleich beider Krüge, Clayton ** Durchschnittliche Ballgeschwindigkeit: 87 Meilen ** ** Schnellste: 95 Meilen ** ** Spät: 72 Meilen ** ** Geschwindigkeitsunterschied: 22 Meilen **
Rockies ** Durchschnittliche Ballgeschwindigkeit: 89 Meilen ** ** Schnellste: 96 Meilen ** ** Spät: 71 Meilen ** ** Geschwindigkeitsunterschied: 24 Meilen ** Ich habe herausgefunden, dass.
Rockies beschäftigt fünf Pitcher, daher gibt es natürlich unterschiedliche Trends.
Als nächstes schauen wir uns die Änderung der Ballgeschwindigkeit an.
baseball_analysis.ipynb
df = pitchDF.loc[(pitchDF['frame']=='top')]
df.pitchtype.value_counts().plot(kind='pie', autopct="%.1f%%", pctdistance=0.8)
plt.axis('equal')
plt.axis('off')
plt.title('Kugelartenverhältnis')
plt.show()
baseball_analysis.ipynb
df = pitchDF.loc[(pitchDF['pitchtype']=='4-seam fb') & (pitchDF['frame']=='top')]
df.des.value_counts().plot(kind='pie', autopct="%.1f%%", pctdistance=0.8)
plt.axis('equal')
plt.axis('off')
plt.title('4-Ergebnis des Nahtereignisses')
plt.show()
baseball_analysis.ipynb
df = pitchDF.loc[(pitchDF['pitchtype']=='slider') & (pitchDF['frame']=='top')]
df.des.value_counts().plot(kind='pie', autopct="%.1f%%", pctdistance=0.8)
plt.axis('equal')
plt.axis('off')
plt.title('Ergebnis des Schiebereglerereignisses')
plt.show()
baseball_analysis.ipynb
df = pitchDF.loc[(pitchDF['pitchtype']=='curveball') & (pitchDF['frame']=='top')]
df.des.value_counts().plot(kind='pie', autopct="%.1f%%", pctdistance=0.8)
plt.axis('equal')
plt.axis('off')
plt.title('Ergebnis des Curveball-Ereignisses')
plt.show()
baseball_analysis.ipynb
df = pitchDF.loc[(pitchDF['pitchtype']=='changeup') & (pitchDF['frame']=='top')]
df.des.value_counts().plot(kind='pie', autopct="%.1f%%", pctdistance=0.8)
plt.axis('equal')
plt.axis('off')
plt.title('Ergebnis des Änderungsereignisses')
plt.show()
Vergleichen der Out-Raten für jede Art von Ball, ** 4 Nähte: 35,7% ** ** Schieberegler: 18,8% ** ** Kurve: 22,3% ** ** Änderung: 0% ** Ich habe herausgefunden, dass.
Die vier Nähte, die die Hälfte der Anzahl der Würfe ausmachen, sind ziemlich gut.
Als nächstes betrachten wir die Ballverteilung nach Anzahl.
baseball_analysis.ipynb
titleList = []
dataList = []
fig, axes = plt.subplots(4, 3, figsize=(12,16))
#Zählen Sie die Erstellung
for b in range(4):
for s in range(3):
df = pitchDF.loc[(pitchDF['ballCount']==b) & (pitchDF['strikeCount']==s) & (pitchDF['frame']=='top')]
title = "Count:" + str(b) + "-" + str(s) + " (" + str(len(df)) + ")"
titleList.append(title)
dataList.append(df)
for i, ax in enumerate(axes.flatten()):
x = dataList[i].pitchtype.value_counts()
l = dataList[i].pitchtype.unique()
ax.pie(x, autopct="%.1f%%", pctdistance=0.9, labels=l)
ax.set_title(titleList[i])
plt.show()
Na ja, fast 4 Nähte.
Als nächstes schauen wir uns die Ergebnisse nach Anzahl an.
baseball_analysis.ipynb
titleList = []
dataList = []
fig, axes = plt.subplots(4, 3, figsize=(12,16))
for b in range(4):
for s in range(3):
df = pitchDF.loc[(pitchDF['ballCount']==b) & (pitchDF['strikeCount']==s) & pitchDF['des'] & (pitchDF['frame']=='top')]
title = "Count:" + str(b) + "-" + str(s) + " (" + str(len(df)) + ")"
titleList.append(title)
dataList.append(df)
for i, ax in enumerate(axes.flatten()):
x = dataList[i].des.value_counts()
l = dataList[i].des.unique()
ax.pie(x, autopct="%.1f%%", pctdistance=0.9, labels=l)
ax.set_title(titleList[i])
plt.show()
Sie können sehen, dass bei jeder Zählung eine hohe Wahrscheinlichkeit für ein Streikurteil und In-Play-Outs (Out als Ergebnis des Balls, der zum Feld fliegt) besteht.
――Es gibt viele erste Ballschläge, und wir haben eine günstige Zählung (wir haben ziemlich viel gebraucht, bevor es vorteilhaft wurde)
Es besteht eine starke Tendenz, dass vier Nähte verteilt werden.
Vorsicht vor unerwarteten Schiebereglern (wahrscheinlich vertikale Risse)
Ich war bis zu einem gewissen Grad mit den Eigenschaften von Pitcher Clayton vertraut, aber ich konnte den Grund nicht verstehen, warum er ohne Vergleich mit anderen Spielen einen No-Hit-No-Run bekam. Sie benötigen auch eine Aufzeichnung vergangener Kämpfe mit Gegnern. Pitcher Clayton war gut kontrolliert und nur 107 Pitches wurden in diesem Match geworfen. MLB hat mehr Spiele als NPB und wirft die Saison in der Mitte des 4. Durchgangs. Selbst wenn der Pitcher gut wirft, besteht aufgrund des Wurflimits die Tendenz, bei etwa 120 Bällen zu fallen. Daher kann eine gute Kontrolle der wichtigste Faktor sein, um in wichtigen Ligen einen No-Hit-No-Run zu erzielen. Es ist lange her, aber danke, dass Sie so weit gelesen haben. Wenn Sie Fehler finden, wäre ich Ihnen sehr dankbar, wenn Sie in den Kommentaren darauf hinweisen könnten.
Recommended Posts