** Dies ist der Artikel am 18. Tag des ADVENT CALENDER der NTT Docomo Service Innovation Department. ** ** **
Hallo! Dies ist Osugi von NTT Docomo.
Als ich Student war, habe ich Zeit im Fußball und im Futsal verbracht und jetzt mache ich Marketing-bezogene Datenanalyse.
Heute möchte ich Fußball-Action vorstellen, ein Python-Paket zum Thema Fußball, und gleichzeitig die Spieldaten beim FIFA Fussball-Weltmeisterschaft Russland-Turnier 2018 analysieren.
Socceraction wird in ** "Aktionen sprechen lauter als Ziele: Bewertung von Spieleraktionen im Fußball" ** [^ 1] vorgestellt, der mit dem Best Paper Award des KDD2019 Appried Data Sciense Track ausgezeichnet wurde.
[^1 ]: Decroos, Tom, et al. "Actions speak louder than goals: Valuing player actions in soccer." Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. ACM, 2019.
Dieses Papier schlägt einen neuen Index vor, um das Verhalten von Fußballspielern während eines Spiels zu bewerten, und enthält insbesondere die folgenden Inhalte.
Und was Fußball-Action betrifft, können Sie mit diesem Paket Folgendes tun.
Mit anderen Worten, Socceraction macht es einfach, die in diesem Artikel beschriebenen Analysemethoden auszuprobieren. Sie können auch eine Reihe von Analysen durchführen, indem Sie auf die auf [github] veröffentlichten öffentlichen Notizbücher (https://github.com/ML-KULeuven/socceraction) verweisen. Dieses Mal möchte ich die Daten berühren, die auf diesem öffentlichen Notizbuch basieren.
Der in diesem Artikel verwendete Code befindet sich am Ende dieses Artikels. Ich hoffe, jeder wird es versuchen.
Sie können Fußballaktion mit pip wie folgt installieren.
pip install socceraction
--Referenz
In dem Artikel werden die Daten von Wyscout verwendet, aber im öffentlichen Notizbuch für Fußballaktionen werden die Daten von StatsBomb erfasst. Ich mache. In Socceraction können Sie auch [Opta] -Daten (https://www.optasports.com/) in SPADL verarbeiten.
Dieses Mal verwende ich auch die Daten von StatsBomb.
[Bildquelle]: https://github.com/statsbomb/open-data/blob/master/README.md
Offene Daten wurden auf StatsBomb veröffentlicht [^ 3], und ab dem 17. Dezember 2019 wurden die Daten für die folgenden Turniere veröffentlicht.
Wenn Sie es so betrachten, können Sie sehen, dass es eine Fülle von Daten über La Liga (Liga Espanola: Spanien) gibt. Dieses Mal werden wir die Daten der Russland-Weltmeisterschaft 2018 verwenden, an der auch die japanische Nationalmannschaft teilgenommen hat.
Eine Zip-Datei wie in [1-download-statsbomb-data.ipynb] gezeigt (https://github.com/ML-KULeuven/socceraction/blob/master/public-notebooks/1-download-statsbomb-data.ipynb) Daten können durch Erfassen / Erweitern erhalten werden. Dieses Mal, um in SPADL zu konvertieren und VAEP genau zu berechnen, habe ich es auch unter Bezugnahme auf das obige Notizbuch erhalten.
Eine andere Möglichkeit, die StatsBomb-Daten abzurufen, ist die Verwendung des Python-Pakets statsbomb.
Sie können die StatsBomb-Daten auch mit dem folgenden Code abrufen.
# https://pypi.org/project/statsbomb/
import statsbomb as sb
# Competitions
comps = sb.Competitions()
comps_df = comps.get_dataframe() #Turnierliste
# Matches(FIFA World Cup : competition_id(event_id) = 43, session_id = 3)
matches = sb.Matches(event_id='43', season_id='3')
matches_df = matches.get_dataframe() #Übereinstimmungsliste
# Events(Japan VS Belgium : event_id = '7584')
# event_Details zum Typ sind unten verlinkt
# https://github.com/imrankhan17/statsbomb-parser/blob/master/statsbomb/events.yaml
events = sb.Events(event_id='7584')
events.get_dataframe(event_type='substitution') #Daten zum Zeitpunkt des Spielerwechsels
--Referenz
Das Format von SPADL (Soccer Player Action Description Language) ist wie folgt.
Im Referenznotizbuch ist der Code zum Ändern der StatsBomb-Daten in das obige SPADL-Format geschrieben, und Sie können ihn einfach in SPADL konvertieren, indem Sie darauf verweisen. Hier ist die Vorgehensweise wie folgt.
cceraction.spadl.api.statsbombjson_to_statsbombh5 (statsbomb_json, statsbomb_h5)
statsbombh5_to_spadlh5 (statsbomb_h5, spadl_h5)
in das SPADL-FormatSie können die Daten im SPADL-Format auch wie folgt zeichnen, indem Sie matplotsoccer.actions
im Python-Paket ** matplotsoccer ** verwenden.
Hier habe ich eine Szene [^ 9] des Spiels Japan-Belgien aufgezeichnet, die für japanische Fußballfans sehr beeindruckend wäre. Sie können sehen, wer wann spielt und welche Art von Spiel mit Figuren und Tischen.
[^ 9]: Szene mit dem dritten Punkt der belgischen Nationalmannschaft
--Referenz
Erstellen Sie als Nächstes einen Feature-Betrag basierend auf SPADL und ermitteln Sie die Punktzahl / Torwahrscheinlichkeit in Angriff / Verteidigung. Dieses Mal habe ich versucht, ein Vorhersagemodell zu erstellen, indem ich das vorherige Spiel in die Feature-Menge aufgenommen habe. Die verwendeten Merkmalsmengen sind wie folgt. Es gibt zwei Arten davon, das neueste und das vorherige Spiel.
Diese Funktion und die Zielvariable können mit "cceraction.classification.features "und "cceraction.classification.labels" abgeleitet werden.
Mit diesen Funktionen haben wir ein Vorhersagemodell mit xgboost erstellt und die Vorhersagegenauigkeit bestätigt. Dann ist die Vorhersagegenauigkeit des diesmal erstellten Vorhersagemodells wie folgt.
Scores | Concedes | |
---|---|---|
brier_score_loss | 0.0092 | 0.0025 |
AUC | 0.8512 | 0.8865 |
Wir haben auch SHAP [^ 5] [^ 6] verwendet, um zu sehen, wie Features zum Vorhersagemodell beitragen. Schauen wir uns die Feature-Menge an, die zur Bewertungswahrscheinlichkeit mit summary_plot beiträgt.
[^5 ]: Lundberg, Scott M., and Su-In Lee. "A unified approach to interpreting model predictions." Advances in Neural Information Processing Systems. 2017. [^6 ]: Lundberg, Scott M., et al. "Explainable AI for Trees: From Local Explanations to Global Understanding." arXiv preprint arXiv:1905.04610 (2019).
Mit SHAP können Sie visuell überprüfen, wie sich die Feature-Menge auf die Zielvariable auswirkt.
Sie können sich auch jede Variable genauer ansehen, wenn Sie eine finden, die Sie interessiert. Im folgenden Dependency_plot sehen wir, wie die Entfernung zum Ziel während der Aktion zur Bewertungswahrscheinlichkeit beiträgt. Da die horizontale Achse der Abstand zum Ziel ist, wenn die Aktion endet, und die vertikale Achse der SHAP-Wert ist, können Sie hier sehen, dass die Bewertungswahrscheinlichkeit umso höher ist, je kürzer der Abstand nach der Aktion ist.
VAEP (Bewertung von Aktionen durch Schätzen von Wahrscheinlichkeiten) wird basierend auf der Bewertungswahrscheinlichkeit / Zugeständniswahrscheinlichkeit des in 3 berechneten Vorhersagemodells berechnet. Der VAEP für die Aktion $ a_i $ von Team $ x $ wird wie folgt berechnet:
V(a_i,x) = \Delta P_{scores}(a_i,x) + (- \Delta P_{concedes}(a_i,x))
In diesem Moment, $ \ Delta P_ {Scores} (a_i, x) $ bedeutet die Erhöhung der Score-Wahrscheinlichkeit aufgrund der Aktion, und $ \ Delta P_ {Zugeständnisse} (a_i, x) $ bedeutet die Erhöhung der Zielwahrscheinlichkeit aufgrund der Aktion. Ich werde.
Mit anderen Worten, der VAEP ist höher für Aktionen, die (1) die Bewertungswahrscheinlichkeit erhöhen und (2) die Zugeständniswahrscheinlichkeit verringern.
Berechnen Sie den VAEP tatsächlich mithilfe von Fußballaktionen.
Hier kann es mit cceraction.vaep.value ()
berechnet werden.
Als Ergebnis der Anordnung in absteigender Reihenfolge des gesamten VAEP wurden die folgenden Ergebnisse erhalten.
Das Ergebnis war, dass die siegreiche französische Nationalmannschaft Embape die höchste VAEP-Gesamtzahl aufwies.
Oben habe ich versucht, die Gesamtzahl der VAEP zu löschen, aber dieses Ergebnis allein berücksichtigt nicht die Spielzeit. Daher wird der VAEP pro 90 Minuten berechnet, indem die in der Arbeit praktizierte Spielzeit gemittelt wird. Außerdem beschränken wir uns als Bedingung auf nur die Spieler, die 180 Minuten oder länger teilgenommen haben.
Mit Blick auf die VAEP pro 90 Minuten kam Russlands Vertreter Dennis Chelishev als Erster ins Spiel. Chelishev erzielte 4 Tore in 5 Spielen, aber aufgrund der Tatsache, dass er in der Mitte teilnahm und in der Mitte ersetzt wurde. Betrachtet man den VAEP pro 90 Minuten, so scheint das Ranking auf den 1. Platz gestiegen zu sein. Interessant war auch, dass Toni Claus, die deutsche Nationalmannschaft, die in diesem Turnier aus der Gruppenliga ausgeschieden war, einen hohen Rang erhielt.
Darüber hinaus kann es durch die Ausgabe eines durchschnittlichen VAEP pro Spiel möglich sein, Spieler zu extrahieren, die gute Arbeit leisten, obwohl die Anzahl der Spiele gering ist.
Fügen wir den berechneten VAEP zu dem zuvor eingeführten Plot von matplotsoccer hinzu. Dies ermöglicht es, das Verhalten jedes Spielers in der Zielszene zu quantifizieren und zu bewerten. Wenn man sich diese Zahl ansieht, ist Debruines Pass mit Ausnahme des Schießens und der Unterstützung am besten bewertet.
Dieses Mal haben wir die Fußballaktion anhand der tatsächlichen Daten des Fußball-Weltmeisterschaftsturniers Russland 2018 eingeführt. Ehrlich gesagt fand ich es sehr praktisch, mehrere Datenquellen wie StatsBomb und Wyscout in SPADL konvertieren zu können. Außerdem sind die StatsBomb-Daten sehr detailliert, und ich hatte das Gefühl, dass sie für verschiedene Analysen verwendet werden könnten. (Danke, dass du es kostenlos nutzen kannst ...) Das öffentliche Notizbuch auf dem Fußball-Action-Github wird ebenfalls im HDF5-Format verarbeitet, und ich benutze es normalerweise nicht so oft, also habe ich es gelernt. Und vor allem fand ich es sehr interessant, aktuelle Spieldaten auf diese Weise analysieren zu können! Wenn Sie wie ich an Sport- und Fußballanalysen interessiert sind, versuchen Sie es bitte mit Fußball.
# ----
#Referenzierte Öffentlichkeit-Notebook MIT Lizenz
# (c) 2019 KU Leuven Machine Learning Research Group
# Released under the MIT license.
# see https://github.com/ML-KULeuven/socceraction/blob/master/LICENSE
# ----
# package
%load_ext autoreload
%autoreload 2
import os; import sys;
import tqdm
import requests
import math
import zipfile
import warnings
import pandas as pd
warnings.simplefilter(action='ignore', category=pd.errors.PerformanceWarning)
import socceraction.spadl.api as spadl
import matplotsoccer
import matplotlib
#Ordnernamen/Geben Sie den Dateinamen an
datafolder = "hogehoge" #Geben Sie den Ordnernamen an
statsbombzip = os.path.join(datafolder, "open-data-master.zip")
statsbombroot = os.path.join(datafolder, "statsbomb-root")
statsbombdata = os.path.join(datafolder, "statsbomb-root", "open-data-master", "data")
#Zip-Datei extrahieren
with zipfile.ZipFile(statsbombzip, 'r') as zipObj:
zipObj.extractall(statsbombroot)
# StatsBomb(json)Daten von SPADL(HDF5)Konvertieren zu
## StatsBomb(Raw Data) : json -> StatsBomb(Raw Data) : h5
statsbomb_json = os.path.join(datafolder,"statsbomb-root","open-data-master","data")
statsbomb_h5 = os.path.join(datafolder,"statsbomb.h5")
spadl_h5 = os.path.join(datafolder,"spadl-statsbomb.h5")
spadl.statsbombjson_to_statsbombh5(statsbomb_json,statsbomb_h5)
tablenames = ["matches","players","teams","competitions"]
tables = {name : pd.read_hdf(statsbomb_h5,key=name) for name in tablenames}
match_id = tables["matches"].match_id[0]
tables["events"] = pd.read_hdf(statsbomb_h5,f"events/match_{match_id}")
for k,df in tables.items():
print("#",k)
print(df.columns,"\n")
## StatsBomb(Raw Data) : h5 -> SPADL : h5
spadl.statsbombh5_to_spadlh5(statsbomb_h5,spadl_h5)
tablenames = ["games","players","teams","competitions","actiontypes","bodyparts","results"]
tables = {name : pd.read_hdf(spadl_h5,key=name) for name in tablenames}
game_id = tables["games"].game_id[0]
tables["actions"] = pd.read_hdf(spadl_h5,f"actions/game_{game_id}")
for k,df in tables.items():
print("#",k)
print(df.columns,"\n")
#FIFA Weltmeisterschaft:Visualisieren Sie das Spiel zwischen Japan und Belgien
## game_Extraktion von id
tablenames = ["games","players","teams","competitions","actiontypes","bodyparts","results"]
tables = {name: pd.read_hdf(spadl_h5, key=name) for name in tablenames}
games = tables["games"].merge(tables["competitions"])
game_id = games[(games.competition_name == "FIFA World Cup")
& (games.away_team_name == "Japan")
& (games.home_team_name == "Belgium")].game_id.values[0]
game_id # 7584
##Aktion im Zusammenhang mit der Wertung_Extraktion von id
actions = pd.read_hdf(spadl_h5, f"actions/game_{game_id}")
actions = (
actions.merge(tables["actiontypes"])
.merge(tables["results"])
.merge(tables["bodyparts"])
.merge(tables["players"],"left",on="player_id")
.merge(tables["teams"],"left",on="team_id")
.sort_values(["period_id", "time_seconds", "timestamp"])
.reset_index(drop=True))
actions["player"] = actions[["player_nickname",
"player_name"]].apply(lambda x: x[0] if x[0] else x[1],axis=1)
list(actions[(actions.type_name=='shot')&(actions.result_name=='success')].index)
# [1215, 1334, 1658, 1742, 2153]
##Belgien 3. Punkt
shot = 2153
a = actions[shot-8:shot+1]
games = tables["games"]
g = list(games[games.game_id == a.game_id.values[0]].itertuples())[0]
minute = int((a.period_id.values[0]-1)*45 +a.time_seconds.values[0] // 60) + 1
game_info = f"{g.match_date} {g.home_team_name} {g.home_score}-{g.away_score} {g.away_team_name} {minute}'"
print(game_info)
labels = a[["time_seconds", "type_name", "player", "team_name"]]
matplotsoccer.actions(
location=a[["start_x", "start_y", "end_x", "end_y"]],
action_type=a.type_name,
team= a.team_name,
result= a.result_name == "success",
label=labels,
labeltitle=["time","actiontype","player","team"],
zoom=False,
figsize=6)
# ----
#Referenzierte Öffentlichkeit-Notebook MIT Lizenz
# (c) 2019 KU Leuven Machine Learning Research Group
# Released under the MIT license.
# see https://github.com/ML-KULeuven/socceraction/blob/master/LICENSE
# ----
# package
%load_ext autoreload
%autoreload 2
import os; import sys; sys.path.insert(0,'hogehoge')#Ordnernamen
import pandas as pd
import tqdm
import warnings
warnings.simplefilter(action='ignore', category=pd.errors.PerformanceWarning)
import socceraction.classification.features as fs
import socceraction.classification.labels as lab
import xgboost
from sklearn.metrics import roc_auc_score,brier_score_loss
import shap
shap.initjs()
#Definition von Dateiname und Ordnername
datafolder = "hogehoge" #Geben Sie den Ordnernamen an
spadl_h5 = os.path.join(datafolder,"spadl-statsbomb.h5")
features_h5 = os.path.join(datafolder,"features.h5")
labels_h5 = os.path.join(datafolder,"labels.h5")
predictions_h5 = os.path.join(datafolder,"predictions.h5")
#Daten lesen
games = pd.read_hdf(spadl_h5,"games")
games = games[games.competition_name == "FIFA World Cup"]
print("nb of games:", len(games))
actiontypes = pd.read_hdf(spadl_h5, "actiontypes")
bodyparts = pd.read_hdf(spadl_h5, "bodyparts")
results = pd.read_hdf(spadl_h5, "results")
#Etikett erstellen
yfns = [lab.scores,lab.concedes,lab.goal_from_shot]
for game in tqdm.tqdm(list(games.itertuples()),
desc=f"Computing and storing labels in {labels_h5}"):
actions = pd.read_hdf(spadl_h5,f"actions/game_{game.game_id}")
actions = (
actions.merge(actiontypes,how="left")
.merge(results,how="left")
.merge(bodyparts,how="left")
.sort_values(["period_id", "time_seconds", "timestamp",'action_id'])
.reset_index(drop=True))
Y = pd.concat([fn(actions) for fn in yfns],axis=1)
Y.to_hdf(labels_h5,f"game_{game.game_id}")
#Erstellung der Merkmalsmenge
xfns = [fs.actiontype,
fs.actiontype_onehot,
fs.bodypart,
fs.bodypart_onehot,
fs.result,
fs.result_onehot,
fs.goalscore,
fs.startlocation,
fs.endlocation,
fs.movement,
fs.space_delta,
fs.startpolar,
fs.endpolar,
fs.team,
fs.time,
fs.time_delta]
for game in tqdm.tqdm(list(games.itertuples()),
desc=f"Generating and storing features in {features_h5}"):
actions = pd.read_hdf(spadl_h5,f"actions/game_{game.game_id}")
actions = (
actions.merge(actiontypes,how="left")
.merge(results,how="left")
.merge(bodyparts,how="left")
.sort_values(["period_id", "time_seconds", "timestamp",'action_id'])
.reset_index(drop=True))
gamestates = fs.gamestates(actions,2)
gamestates = fs.play_left_to_right(gamestates,game.home_team_id)
X = pd.concat([fn(gamestates) for fn in xfns],axis=1)
X.to_hdf(features_h5,f"game_{game.game_id}")
xfns = [fs.actiontype_onehot,
fs.bodypart_onehot,
fs.result,
fs.goalscore,
fs.startlocation,
fs.endlocation,
fs.movement,
fs.space_delta,
fs.startpolar,
fs.endpolar,
fs.team,
fs.time_delta]
nb_prev_actions = 2
Xcols = fs.feature_column_names(xfns,nb_prev_actions)
X = []
for game_id in tqdm.tqdm(games.game_id,desc="selecting features"):
Xi = pd.read_hdf(features_h5,f"game_{game_id}")
X.append(Xi[Xcols])
X = pd.concat(X)
Ycols = ["scores","concedes"]
Y = []
for game_id in tqdm.tqdm(games.game_id,desc="selecting label"):
Yi = pd.read_hdf(labels_h5,f"game_{game_id}")
Y.append(Yi[Ycols])
Y = pd.concat(Y)
print("X:", list(X.columns))
print("Y:", list(Y.columns))
#Vorausschauende Modellkonstruktion von xgboost
%%time
# scores
model_scores = xgboost.XGBClassifier()
model_scores.fit(X,Y['scores'])
# concedes
model_concedes = xgboost.XGBClassifier()
model_concedes.fit(X,Y['concedes'])
Y_hat = pd.DataFrame()
Y_hat['scores'] = model_scores.predict_proba(X)[:,1]
Y_hat['concedes'] = model_concedes.predict_proba(X)[:,1]
#Vorhersagegenauigkeit
print(f"scores_brier : \t\t{brier_score_loss(Y['scores'],Y_hat['scores']).round(4)}")
print(f"concedes_brier : \t{brier_score_loss(Y['concedes'],Y_hat['concedes']).round(4)}")
print(f"scores_auc : \t\t{roc_auc_score(Y['scores'],Y_hat['scores']).round(4)}")
print(f"concedes_auc : \t{roc_auc_score(Y['concedes'],Y_hat['concedes']).round(4)}")
#Identifizierung von Vorhersagefaktoren mit SHAP(scores)
explainer_scores = shap.TreeExplainer(model_scores)
shap_scores = explainer_scores.shap_values(X)
## summary_plot
shap.summary_plot(shap_scores,features=X,feature_names=X.columns)
## dependence_plot
shap.dependence_plot('end_dist_to_goal_a0',
shap_scores,
features=X,
feature_names=X.columns,
interaction_index='end_dist_to_goal_a0')
#Vorhersageergebnisse speichern
A = []
for game_id in tqdm.tqdm(games.game_id,"loading game ids"):
Ai = pd.read_hdf(spadl_h5,f"actions/game_{game_id}")
A.append(Ai[["game_id"]])
A = pd.concat(A)
A = A.reset_index(drop=True)
grouped_predictions = pd.concat([A,Y_hat],axis=1).groupby("game_id")
for k,df in tqdm.tqdm(grouped_predictions,desc="saving predictions per game"):
df = df.reset_index(drop=True)
df[Y_hat.columns].to_hdf(predictions_h5,f"game_{int(k)}")
# ----
#Referenzierte Öffentlichkeit-Notebook MIT Lizenz
# (c) 2019 KU Leuven Machine Learning Research Group
# Released under the MIT license.
# see https://github.com/ML-KULeuven/socceraction/blob/master/LICENSE
# ----
# package
%load_ext autoreload
%autoreload 2
import os; import sys; sys.path.insert(0,'hogehoge') #Ordnernamen
import pandas as pd
import tqdm
import warnings
warnings.simplefilter(action='ignore', category=pd.errors.PerformanceWarning)
import socceraction.vaep as vaep
import matplotsoccer
import matplotlib
#Definition von Dateiname und Ordnername
datafolder = "hogehoge" #Ordnernamen
spadl_h5 = os.path.join(datafolder,"spadl-statsbomb.h5")
predictions_h5 = os.path.join(datafolder,"predictions.h5")
#Daten bekommen
games = pd.read_hdf(spadl_h5,"games")
games = games[games.competition_name == "FIFA World Cup"]
print("nb of games:", len(games))
players = pd.read_hdf(spadl_h5,"players")
teams = pd.read_hdf(spadl_h5,"teams")
actiontypes = pd.read_hdf(spadl_h5, "actiontypes")
bodyparts = pd.read_hdf(spadl_h5, "bodyparts")
results = pd.read_hdf(spadl_h5, "results")
#Berechnung des VAEP
A = []
for game in tqdm.tqdm(list(games.itertuples())):
actions = pd.read_hdf(spadl_h5,f"actions/game_{game.game_id}")
actions = (
actions.merge(actiontypes)
.merge(results)
.merge(bodyparts)
.merge(players,"left",on="player_id")
.merge(teams,"left",on="team_id")
.sort_values(["period_id", "time_seconds", "timestamp"])
.reset_index(drop=True)
)
preds = pd.read_hdf(predictions_h5,f"game_{game.game_id}")
values = vaep.value(actions,preds.scores,preds.concedes)
A.append(pd.concat([actions,preds,values],axis=1))
A = pd.concat(A).sort_values(["game_id","period_id", "time_seconds", "timestamp"]).reset_index(drop=True)
A.columns
A["player"] = A[["player_nickname",
"player_name"]].apply(lambda x: x[0] if x[0] else x[1],axis=1)
#Berechnen Sie den Gesamt-VAEP jedes Spielers und überprüfen Sie ihn in absteigender Reihenfolge
summary = A.groupby(['player',
'team_name',
'player'])[['offensive_value',
'defensive_value',
'vaep_value']].sum().reset_index()
summary.sort_values('vaep_value',ascending = False).head(10)
#Berechnen Sie den durchschnittlichen VAEP pro 90 Minuten und überprüfen Sie ihn in absteigender Reihenfolge
players = A_[["player_id",
"team_name",
"player",
"vaep_value",
"count"]].groupby(["player_id",
"team_name",
"player"]).sum().reset_index()
players = players.sort_values("vaep_value",ascending=False)
pg = pd.read_hdf(spadl_h5,"player_games")
pg = pg[pg.game_id.isin(games.game_id)]
mp = pg[["player_id","minutes_played"]].groupby("player_id").sum().reset_index()
stats = players.merge(mp)
stats = stats[stats.minutes_played > 180]
stats["vaep_rating"] = stats.vaep_value * 90 / stats.minutes_played
stats.sort_values("vaep_rating",ascending=False).head(10)
#Visualisierung durch matplotsoccer
##Extraktion von Szenen mit Zielen
shot_goal_index = A[(A.game_id == 7584)&A.type_name.str.contains("shot")&(A.result_name=='success')]
##Belgiens dritte Visualisierung
def get_time(period_id,time_seconds):
m = int((period_id-1)*45 + time_seconds // 60)
s = time_seconds % 60
if s == int(s):
s = int(s)
return f"{m}m{s}s"
###Extraktion von Szenen
a = A.iloc[shot_goal_index.index[4]-6:shot_goal_index.index[4]+1,:].sort_values('action_id')
a["player"] = a[["player_nickname",
"player_name"]].apply(lambda x: x[0] if x[0] else x[1],axis=1)
###Spielinformationen
g = list(games[games.game_id == a.game_id.values[0]].itertuples())[0]
game_info = f"{g.match_date} {g.home_team_name} {g.home_score}-{g.away_score} {g.away_team_name}"
minute = get_time(int(a[a.index == a.index[-1]].period_id),int(a[a.index == a.index[-1]].time_seconds))
print(f"{game_info} {minute}' {a[a.index == a.index[-1]].type_name.values[0]} {a[a.index == a.index[-1]].player_name.values[0]}")
###Datenformung
a["scores"] = a.scores.apply(lambda x : "%.3f" % x )
a["vaep_value"] = a.vaep_value.apply(lambda x : "%.3f" % x )
a["time"] = a[["period_id","time_seconds"]].apply(lambda x: get_time(*x),axis=1)
cols = ["time","type_name","player","team_name","scores","vaep_value"]
###Handlung
matplotsoccer.actions(a[["start_x","start_y","end_x","end_y"]],
a.type_name,
team=a.team_name,
result = a.result_name == "success",
label=a[cols],
labeltitle = cols,
zoom=False)
Recommended Posts