"La victoria de la inteligencia artificial sobre los expertos en fútbol": este podría ser el título de este artículo sobre los resultados de una competición de fútbol. Podría, pero, por desgracia, no lo hizo.
Durante la Copa del Mundo, en nuestra empresa "
NORBIT " celebró una competencia por los mejores partidos pronosticados para el fútbol. Estoy demasiado versado en el fútbol como para reclamar algo, pero el deseo de participar en la competencia aún se ganó mi pereza. Under the cut: una historia sobre cómo, gracias al aprendizaje automático, logré buenos resultados entre los expertos en equipos de fútbol. Es cierto que no pude ganar el premio gordo, pero descubrí un nuevo mundo fascinante de Data Science.
Comencé con la hipótesis de que, además de las habilidades individuales de los jugadores del equipo nacional, todavía hay factores inconmensurables, pero importantes: espíritu de equipo + trabajo en equipo (por ejemplo, un equipo en un juego con un oponente más fuerte, pero en el partido de prueba y en su campo con más frecuencia gana). La tarea no es tan simple para una persona, pero es bastante comprensible para el aprendizaje automático.
Una vez tuve un poco de experiencia con ML (con la biblioteca BrainJS), pero esta vez decidí verificar la afirmación de que Python es mucho más adecuado para tales tareas.
Comencé mi introducción a Python con un excelente curso sobre
Coursera , y aprendí los conceptos básicos del aprendizaje automático de una serie de artículos de Open Data Science sobre
Habré .
Rápidamente encontró un gran
conjunto de datos con la historia de todos los juegos de equipos internacionales de principios del siglo XX. Después de importar en el marco de datos de Pandas:
En total, la base de datos contiene información sobre 39 mil juegos de equipos internacionales.
Pandas hace que sea muy conveniente analizar los datos, por ejemplo, la coincidencia más productiva fue entre Australia y Samoa Americana en 2001, que terminó con un puntaje de
31: 0 .
Ahora necesitas agregar una evaluación objetiva del nivel del equipo en el año del partido. Estas evaluaciones son manejadas por la FIFA.
Pero, desafortunadamente, la calificación de FIFA se ha llevado a cabo solo desde 1992. Y, a juzgar por el calendario, las clasificaciones de los equipos son muy susceptibles a los cambios, y realmente no quisiera promediar las posiciones de los equipos en el ranking mundial hasta este año.
La UEFA mantiene sus estadísticas de los tiempos más antiguos, pero no pude encontrar un conjunto de datos listo, por lo que este
sitio vino al rescate. Bajo Node.js hay un
Cheerio potente y conveniente para tales tareas, pero bajo Python todo resultó no menos simple (perdóname el administrador de este sitio).
Ranking de raspado webfrom 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)
Fluctuaciones en la calificación después de agregar la calificación de la UEFA (y una pequeña revisión de los nombres de los países según los resultados del enroque geopolítico):
Pero incluso esto no fue sin un barril de alquitrán: la UEFA clasifica solo a los equipos europeos (a veces hay que pensar en lo que se esconde bajo las abreviaturas comunes antes de usarlos). Afortunadamente, los playoffs se han desarrollado casi "europeos".
Sigue siendo un poco más conveniente dividir los resultados en juegos separados y agregar calificaciones a la tabla.
La parte más interesante es el entrenamiento modelo. Google sugirió de inmediato la opción más simple y rápida: este es el MLPClassifier de la biblioteca de Python: Sklearn. Intentemos entrenar un modelo usando el ejemplo de Suecia.
from sklearn.neural_network import MLPClassifier games = pd.read_csv('games.csv')
Exactitud: 0.62No es mucho más preciso que lanzar monedas, pero probablemente ya sea mejor que mis posibles pronósticos "expertos". Sería razonable tratar de enriquecer los datos, jugar con hiperparámetros, pero decidí ir a otro lado y probar la biblioteca de
refuerzo Yanbo Gradient
Catboost . Por un lado, esto es más patriótico, por otro lado, prometen un trabajo de calidad con atributos categóricos, lo que se confirma mediante numerosas
comparaciones .
Tomó la configuración del
ejemplo :
Precisión: 0,73Ya mejor, inténtalo en la práctica.
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}%")
Resultados de predicción para el final "El equipo de Crotia pierde ante el equipo de Francia con una probabilidad del 93.7%"
Aunque esta vez no
gané el concurso
NORBIT , realmente espero que este artículo reduzca el nivel de magia para alguien en el uso práctico del aprendizaje automático, o tal vez incluso me motive a hacer mis propios experimentos.