"Der Sieg der künstlichen Intelligenz über Fußball-Experten" - das könnte der Titel dieses Artikels über die Ergebnisse eines Fußballwettbewerbs sein. Konnte, aber leider nicht.
Während der Weltmeisterschaft veranstaltete "
NORBIT " in unserer Firma einen Wettbewerb um die besten prognostizierten Spiele für den Fußball. Ich bin zu oberflächlich im Fußball versiert, um etwas zu behaupten, aber der Wunsch, an dem Wettbewerb teilzunehmen, hat meine Faulheit immer noch überzeugt. Under the Cut - eine Geschichte darüber, wie ich dank maschinellem Lernen unter Experten von Fußballmannschaften gute Ergebnisse erzielen konnte. Ich habe zwar den Jackpot nicht geknackt, aber eine neue faszinierende Welt der Datenwissenschaft entdeckt.
Ich begann mit der Hypothese, dass es neben den individuellen Fähigkeiten der Nationalmannschaftsspieler immer noch unermessliche, aber wichtige Faktoren gibt - Teamgeist + Teamwork (zum Beispiel ein Team in einem Spiel mit einem stärkeren Gegner, aber im Testspiel und auf seinem Feld gewinnt häufiger). Die Aufgabe ist für eine Person nicht so einfach, aber für maschinelles Lernen durchaus verständlich.
Ich hatte einmal ein wenig Erfahrung mit ML (mit der BrainJS-Bibliothek), aber dieses Mal habe ich beschlossen, die Aussage zu überprüfen, dass Python für solche Aufgaben viel besser geeignet ist.
Ich begann meine Einführung in Python mit einem ausgezeichneten Kurs über
Coursera und lernte die Grundlagen des maschinellen Lernens aus einer Reihe von Artikeln von Open Data Science über
Habré .
Ziemlich schnell fand ein großer
Datensatz mit der Geschichte aller Spiele internationaler Mannschaften vom Beginn des 20. Jahrhunderts. Nach dem Import in Pandas Dataframe:
Insgesamt enthält die Datenbank Informationen zu 39.000 Spielen internationaler Mannschaften.
Pandas macht es sehr bequem, die Daten zu analysieren. Das produktivste Spiel war beispielsweise zwischen Australien und Amerikanisch-Samoa im Jahr 2001, das mit einem Ergebnis von
31: 0 endete.
Jetzt müssen Sie eine objektive Bewertung der Mannschaftsstufe im Jahr des Spiels hinzufügen. Diese Bewertungen werden von der FIFA durchgeführt.
Leider wird das FIFA-Rating erst seit 1992 durchgeführt. Und nach dem Zeitplan zu urteilen, sind die Teambewertungen sehr anfällig für Änderungen, und ich möchte die Positionen der Teams in der Weltrangliste erst in diesem Jahr mitteln.
Die UEFA behält ihre Statistiken aus früheren Zeiten bei, aber ich konnte keinen fertigen Datensatz finden, daher kam diese
Seite zur Rettung. Unter Node.js gibt es ein leistungsfähiges und praktisches
Cheerio für solche Aufgaben, aber unter Python stellte sich heraus, dass alles nicht weniger einfach war (verzeihen Sie mir, dem Administrator dieser Site).
Web Scraping Rankingfrom requests import get from requests.exceptions import RequestException from contextlib import closing from bs4 import BeautifulSoup def query_url(url): try: with closing(get(url, stream=True)) as resp: if is_good_response(resp): return resp.content else: return None except RequestException as e: log_error('Error during requests to {0} : {1}'.format(url, str(e))) return None def is_good_response(resp): content_type = resp.headers['Content-Type'].lower() return (resp.status_code == 200 and content_type is not None and content_type.find('html') > -1) def log_error(e): print(e) def parse_ranks(raw_html, year): html = BeautifulSoup(raw_html, 'html.parser') ranks = [] for tr in html.select('tr'): tds = tr.select("td") if len(tds) == 10: rank = (year, tds[2].text, tds[7].text) ranks.append(rank) return ranks def get_url(year): if year in range(1960, 1999): method = 1 if year in range(1999, 2004): method = 2 if year in range(2004, 2009): method = 3 if year in range(2009, 2018): method = 4 if year in range(2018, 2019): method = 5 return f"https://kassiesa.home.xs4all.nl/bert/uefa/data/method{method}/crank{year}.html" ranks = [] for year in range(1960, 2019): url = get_url(year) print(url) raw_html = query_url(url) rank = parse_ranks(raw_html, year) ranks += rank with open('team_ranks.csv', 'w') as f: writer = csv.writer(f , lineterminator='\n') writer.writerow(['year', 'country', 'rank']) for rank in ranks: writer.writerow(rank)
Schwankungen des Ratings nach dem Hinzufügen des UEFA-Ratings (und einer kleinen Überarbeitung der Namen der Länder gemäß den Ergebnissen der geopolitischen Rochade):
Aber auch dies war nicht ohne ein Fass Teer - die UEFA zählt nur europäische Teams (manchmal muss man sich überlegen, was unter den üblichen Abkürzungen verborgen ist, bevor man sie einsetzt). Glücklicherweise haben sich die Playoffs fast "europäisch" entwickelt.
Es bleibt etwas bequemer, die Ergebnisse in separate Spiele aufzuteilen und der Tabelle Bewertungen hinzuzufügen.
Der interessanteste Teil ist das Modelltraining. Google schlug sofort die einfachste und schnellste Option vor - dies ist der MLPClassifier aus der Python-Bibliothek - Sklearn. Versuchen wir, ein Modell am Beispiel Schwedens zu trainieren.
from sklearn.neural_network import MLPClassifier games = pd.read_csv('games.csv')
Genauigkeit: 0,62Nicht viel genauer als das Werfen von Münzen, aber wahrscheinlich schon besser als meine potenziellen "Experten" -Prognosen. Es wäre vernünftig zu versuchen, die Daten anzureichern, mit Hyperparametern zu spielen, aber ich entschied mich, den anderen Weg zu gehen und die Yandex-Gradienten-
Catboost- Bibliothek zum Boosten auszuprobieren. Dies ist einerseits patriotischer, andererseits versprechen sie Qualitätsarbeit mit kategorialen Attributen, was durch zahlreiche
Vergleiche bestätigt wird.
Übernahm die Einstellungen aus dem
Beispiel :
Genauigkeit: 0,73Schon besser, versuchen Sie es in der Praxis.
def get_prediction(country, against): y = SwdenGames['score'] y = y.astype('int') X = SwdenGames.drop(['score', 'againstTitle'], axis=1) train_pool = Pool(X, y, cat_features=[1, 2, 4]) query = [ get_team_rank(country, 2018), 0, 1 if country == 'Russia' else 0, get_team_rank(against, 2018), against] return cb_model.predict_proba([query])[0] team_1 = 'Belgium' team_2 = 'France' result = get_prediction(team_1, team_2) if result[0] > result[1]: print(f" {team_1} {team_2} {result[0]*100:.1f}%") else: print(f" {team_1} {team_2} {result[1]*100:.1f}%")
Vorhersageergebnisse für das Finale „Crotia-Team verliert mit 93,7% Wahrscheinlichkeit gegen Frankreich-Team“
Obwohl ich dieses Mal den
NORBIT- Wettbewerb nicht gewonnen
habe , hoffe ich wirklich, dass dieser Artikel das Maß an Magie für jemanden im praktischen Einsatz des maschinellen Lernens verringert oder mich vielleicht sogar dazu motiviert, meine eigenen Experimente durchzuführen.