Um modelo de aprendizado de máquina em Python usando a biblioteca Scikit-learn para prever os resultados de partidas de futebol na Russian Premier League (RPL).
Entrada
Eu fui inspirado a escrever este artigo pelo artigo
Aprendizado de máquina: prever a matemática do EPL de 2018 . Nosso modelo de aprendizado de máquina será treinado nas estatísticas das partidas da Liga Russa (RPL) a partir da temporada 2015/2016 para prever os resultados dos próximos jogos. Dados extraídos do site de estatísticas de futebol do wyscout.com.
Código e dados estão disponíveis no
github .
Dados
Conectamos as bibliotecas necessárias:
import pandas as pd import numpy as np import collections
Os dados da correspondência estão no
github .
data = pd.read_csv("RPL.csv", encoding = 'cp1251', delimiter=';') data.head()

O que significa xG e PPDA?xG (objetivos esperados) é um modelo de objetivos esperados. É baseado no indicador de chutes no gol, com base nos quais podemos estimar quantos gols a equipe realmente teve que marcar se levarmos em conta todos os chutes que ele realizou.
Saiba mais sobre o xG.PPDA (passes permitidos por ação defensiva) é um indicador de estatística de futebol que permite determinar a intensidade da pressão em uma partida. Quanto menor o valor do PPDA, maior a intensidade do jogo na defesa.
Saiba mais sobre o PPDAPPDA = número de passes feitos pela equipe atacante / número de ações em defesa
Vamos prever os resultados das partidas para a segunda parte da temporada 2018/2019 (ou seja, partidas disputadas em 2019). A lista de times que jogam nesta temporada (sem levar em consideração Arsenal, Orenburg, Dínamo, Krylia Sovetov e Yenisei, porque eles não têm estatísticas para as temporadas anteriores ou existem poucas estatísticas sobre eles):
RPL_2018_2019 = pd.read_csv('Team Name 2018 2019.csv', encoding = 'cp1251') teamList = RPL_2018_2019['Team Name'].tolist() teamList

Removemos partidas com equipes que não participam da temporada 2018/2019:
deleteTeam = [x for x in pd.unique(data['']) if x not in teamList] for name in deleteTeam: data = data[data[''] != name] data = data[data[''] != name] data = data.reset_index(drop=True)
Função que retorna estatísticas da equipe para uma temporada:
def GetSeasonTeamStat(team, season): goalScored = 0
Exemplo de uso de função:
GetSeasonTeamStat("", 2018)

Por conveniência, podemos adicionar o código:
returnNames = ["", "", "", "\n ", " ", "\n ", "\nxG ( )", "PPDA ( )", "\n", " ", "\n", " ", "\n", " ", "\n ( )"] for i, n in zip(returnNames, GetSeasonTeamStat("", 2018)): print(i, n)

Por que nossas estatísticas são diferentes das estatísticas reaisEstatísticas reais de Spartak na temporada 2017/2018:

As estatísticas são diferentes porque Levamos em consideração os jogos das equipes que não jogam no RPL na temporada 2018/2019. Ou seja, não levamos em consideração as partidas de Spartak - SKA, Spartak - Tosno, etc.
Função que retornará estatísticas de todas as equipes para a temporada:
def GetSeasonAllTeamStat(season): annual = collections.defaultdict(list) for team in teamList: team_vector = GetSeasonTeamStat(team, season) annual[team] = team_vector return annual
Modelo de treinamento
Escreveremos uma função que retornará dados de treinamento. Ela cria um dicionário com vetores de equipe para todas as estações. Para cada jogo, a função calcula a diferença entre os vetores das equipes para uma determinada temporada e a grava no xTrain. A função define yTrain como 1 se a equipe da casa vencer e 0 caso contrário.
def GetTrainingData(seasons): totalNumGames = 0 for season in seasons: annual = data[data[''] == season] totalNumGames += len(annual.index) numFeatures = len(GetSeasonTeamStat('', 2016))
Aprendemos dados de treinamento para todas as estações de 2015/2016 a 2018/2019.
years = range(2016,2019) xTrain, yTrain = GetTrainingData(years)
Para prever a probabilidade de vitória, usaremos o algoritmo de aprendizado de máquina LinearRegression da biblioteca Scikit-Learn.
from sklearn.linear_model import LinearRegression model = LinearRegression() model.fit(xTrain, yTrain)
Escreveremos uma função que retornará previsões. Ele retornará um valor entre 0 e 1, onde 0 é a perda e 1 é o ganho.
def createGamePrediction(team1_vector, team2_vector): diff = [[a - b for a, b in zip(team1_vector, team2_vector)]] predictions = model.predict(diff) return predictions
Resultados
Por exemplo, vejamos as previsões do algoritmo para a partida Zenit - Spartak
team1_name = "" team2_name = "" team1_vector = GetSeasonTeamStat(team1_name, 2019) team2_vector = GetSeasonTeamStat(team2_name, 2019) print (', ' + team1_name + ':', createGamePrediction(team1_vector, team2_vector)) print (', ' + team2_name + ':', createGamePrediction(team2_vector, team1_vector))

No jogo Zenit - Spartak, a probabilidade de vitória para Zenit é de 47% (17/03/2019 Spartak 1-1 Zenit).
Proponho fazer uma previsão considerando o seguinte:
Até 40% - o time não ganha (perda ou empate)
De 40% a 60% - alta probabilidade de empate
De 60% - a equipe definitivamente não perderá (vencerá ou empatará)
Obter previsões para o CSKA contra todos os outros clubes
for team_name in teamList: team1_name = "" team2_name = team_name if(team1_name != team2_name): team1_vector = GetSeasonTeamStat(team1_name, 2019) team2_vector = GetSeasonTeamStat(team2_name, 2019) print(team1_name, createGamePrediction(team1_vector, team2_vector), " - ", team2_name, createGamePrediction(team2_vector, team1_vector,))

O algoritmo forneceu uma previsão correta para quase todas as correspondências que não terminaram em empate. A única previsão imprecisa: CSKA Moscou - Zenit. A probabilidade de vitória do CSKA é maior em 0,001; pode-se supor que as equipes tenham força igual e disputarão um empate, mas no final o Zenit venceu (3-1).
Conclusão
Nosso algoritmo é muito primitivo. Ele leva em conta apenas as estatísticas dos jogos (e depois apenas 15 parâmetros básicos), e o resultado no futebol depende de muitos fatores. Até a condição do campo ou o clima podem afetar o resultado do jogo.
Em seguida, gostaria de aumentar o número de sinais, criar uma amostra de teste, experimentar vários algoritmos, configurar o modelo e obter previsões mais precisas.
Ficaria muito grato se você deixar suas idéias e comentários.