[PYTHON] Ich habe versucht, die Daten des Fußballturniers der FIFA Fussball-Weltmeisterschaft Russland mit Fußball zu analysieren

** 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.

Einführung

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.

  1. ** Übereinstimmungsdaten in SPADL konvertieren **
  2. ** Berechnung der Erfolgswahrscheinlichkeit beim Angriff / bei der Verteidigung jeder Aktion **
  3. ** Berechnung des VAEP unter Verwendung der Erfolgswahrscheinlichkeit in jeder Aktion **

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.

Eigentlich mit Fußball-Action analysieren

Sie können Fußballaktion mit pip wie folgt installieren.

pip install socceraction

1. Laden Sie die Daten herunter

--Referenz

1.1 Über die diesmal verwendeten Daten

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.

StatsBomb Logo [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.

1.2 So erhalten Sie Daten

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

2. Konvertieren Sie Daten in SPADL

--Referenz

2.1 Über das Format von SPADL

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.

  1. Konvertieren Sie StatsBomb JSON in eine Datei im HDF5-Format mit cceraction.spadl.api.statsbombjson_to_statsbombh5 (statsbomb_json, statsbomb_h5)
  2. Konvertieren Sie StatsBomb-Dateien mit statsbombh5_to_spadlh5 (statsbomb_h5, spadl_h5) in das SPADL-Format

Sie können die Daten im SPADL-Format auch wie folgt zeichnen, indem Sie matplotsoccer.actions im Python-Paket ** matplotsoccer ** verwenden.

image.png

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

3. Vorhersage der Wahrscheinlichkeit nach Modell

--Referenz

3.1 Erstellen eines Vorhersagemodells

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

3.2 Bestätigung wichtiger Funktionen durch SHAP

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).

image.png

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. image.png 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.

4. Berechnung des VAEP

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.

image.png

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.

image.png

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.

5. Visualisierung der Ergebnisse für jede Szene

Fügen wir den berechneten VAEP zu dem zuvor eingeführten Plot von matplotsoccer hinzu. image.png 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.

Zusammenfassung

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.

Referenz: Diesmal verwendeter Code

1. Datenerfassung und Visualisierung von Scoring-Szenen

# ----
#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)

2. Feature-Erstellung, Erstellung von Vorhersagemodellen, SHAP-Berechnung

# ----
#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)}")

3. Berechnung des VAEP

# ----
#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

Ich habe versucht, die Daten des Fußballturniers der FIFA Fussball-Weltmeisterschaft Russland mit Fußball zu analysieren
Ich habe versucht, die Daten mit Zwietracht zu speichern
Ich habe versucht, die Negativität von Nono Morikubo zu analysieren. [Vergleiche mit Posipa]
Ich habe versucht, die statistischen Daten der neuen Corona mit Python abzurufen und zu analysieren: Daten der Johns Hopkins University
Ich habe versucht, die Laufdaten des Rennspiels (Assetto Corsa) mit Plotly zu visualisieren
Ich habe versucht, die Entropie des Bildes mit Python zu finden
Ich habe versucht, die Emotionen des gesamten Romans "Wetterkind" zu analysieren
Ich habe versucht, mit TensorFlow den Durchschnitt mehrerer Spalten zu ermitteln
Ich habe Python satt, also habe ich versucht, die Daten mit nehan zu analysieren (ich möchte sogar mit Corona live gehen) - Teil 2)
Ich habe Python satt, also habe ich versucht, die Daten mit nehan zu analysieren (ich möchte sogar mit Corona live gehen) - Teil 1)
Ich habe versucht, die Punktgruppendaten-DB der Präfektur Shizuoka mit Vue + Leaflet anzuzeigen
Ich habe versucht, die Bewässerung des Pflanzgefäßes mit Raspberry Pi zu automatisieren
[Pandas] Ich habe versucht, Verkaufsdaten mit Python zu analysieren. [Für Anfänger]
Ich habe versucht, die Größe des logischen Volumes mit LVM zu erweitern
Ich habe den Befehl worldcup verwendet, um das Ergebnis der Weltmeisterschaft zu überprüfen.
Ich habe versucht, die Effizienz der täglichen Arbeit mit Python zu verbessern
Ich habe versucht, den Authentifizierungscode der Qiita-API mit Python abzurufen.
Ich habe versucht, die Bewegungen von Wiire-Playern automatisch mit Software zu extrahieren
(Python) Ich habe versucht, 1 Million Hände zu analysieren ~ Ich habe versucht, die Anzahl der AA ~ zu schätzen
Ich habe versucht, die Beschleunigung von Python durch Cython zu verifizieren und zu analysieren
Ich habe versucht, die Standardrolle neuer Mitarbeiter mit Python zu optimieren
Ich habe versucht, den Text des Romans "Wetterkind" mit Word Cloud zu visualisieren
Ich habe versucht, die Filminformationen der TMDb-API mit Python abzurufen
Ich habe versucht, das Verhalten des neuen Koronavirus mit dem SEIR-Modell vorherzusagen.
Ich habe Web Scraping versucht, um die Texte zu analysieren.
Ich habe versucht, CloudWatch-Daten mit Python abzurufen
Ich habe versucht, die Trapezform des Bildes zu korrigieren
Qiita Job Ich habe versucht, den Job zu analysieren
Ich habe versucht, die Texte von Hinatazaka 46 zu vektorisieren!
Ich habe versucht, die Tweets von JAWS DAYS 2017 mit Python + ELK einfach zu visualisieren
Ich habe versucht, die Daten des Laptops durch Booten unter Ubuntu zu retten
Die Geschichte von soracom_exporter (Ich habe versucht, SORACOM Air mit Prometheus zu überwachen)
Ich habe versucht, ein Modell mit dem Beispiel von Amazon SageMaker Autopilot zu erstellen
Ich habe versucht, die Literatur des neuen Corona-Virus mit Python automatisch an LINE zu senden
Ich habe versucht, Funktionen mit SIFT von OpenCV zu extrahieren
Ich habe versucht, die Grundform von GPLVM zusammenzufassen
Ich habe versucht, eine CSV-Datei mit Python zu berühren
Ich habe versucht, Soma Cube mit Python zu lösen
Ich habe versucht, die API von Sakenowa Data Project zu verwenden
Ich habe versucht, die Spacha-Informationen von VTuber zu visualisieren
Ich habe versucht, den negativen Teil von Meros zu löschen
Ich habe versucht, das Problem mit Python Vol.1 zu lösen
Ich habe versucht, die Stimmen der Sprecher zu klassifizieren
Ich habe versucht, die String-Operationen von Python zusammenzufassen
Ich habe versucht, das Artikel-Update des Livedoor-Blogs mit Python und Selen zu automatisieren.
Ich habe versucht, die Eigenschaften der neuen Informationen über mit dem Corona-Virus infizierte Personen mit Wordcloud zu visualisieren
[Erste Datenwissenschaft ⑥] Ich habe versucht, den Marktpreis von Restaurants in Tokio zu visualisieren
Ich wollte nur die Daten des gewünschten Datums und der gewünschten Uhrzeit mit Django extrahieren
Ich habe versucht, die Verarbeitungsgeschwindigkeit mit dplyr von R und pandas von Python zu vergleichen
Beim 15. Offline-Echtzeitversuch habe ich versucht, das Problem des Schreibens mit Python zu lösen
[Pferderennen] Ich habe versucht, die Stärke des Rennpferdes zu quantifizieren
Ich habe versucht, das Bild mit Python + OpenCV "gammakorrektur" zu machen
Ich habe versucht zu simulieren, wie sich die Infektion mit Python ausbreitet
Ich habe versucht, die Standortinformationen des Odakyu-Busses zu erhalten
Ich habe versucht, zum Zeitpunkt der Bereitstellung mit Fabric und ChatWork Api automatisch in ChatWork zu posten
Ich habe versucht, den WEB-Server der normalen Linux-Programmierung 1st Edition mit C ++ 14 neu zu schreiben
Ich habe versucht, das Problem von F02 zu lösen, wie man mit Python offline in Echtzeit schreibt