Многие люди (включая меня) называют футбол «непредсказуемой игрой», потому что в футбольном матче есть множество факторов, влияющих на окончательный счёт. И это верно… в определённой степени.
Сложно спрогнозировать окончательный счёт или победителя матча, однако при прогнозировании победителя в соревнованиях всё не так. За последние пять лет «Бавария» выиграла все Бундеслиги, а «Манчестер Сити» выиграл 4 Премьер-лиги.
Совпадение? Не думаю.
На самом деле, в середине сезона 20-21 годов я создал модель для прогнозирования победителя Премьер-лиги, Чемпионата Испании, Чемпионата Италии и Бундеслиги, и она успешно спрогнозировала всех победителей.
Прогноз сделать было не так сложно, потому что на тот момент было сыграно уже 19 матчей. Теперь я запущу ту же модель для прогнозирования результатов Чемпионата мира 2022.
В статье я расскажу, как спрогнозировал победителя Чемпионата мира при помощи Python (подробнее о коде можно узнать из моего часового видеотуториала).
Прим. переводчика: результаты ЧМ показали, что приведённая в этой статье модель допустила довольно много промахов. Однако мы считаем, что она имеет ценность, поэтому публикуем её здесь.
▍ Как мы будем прогнозировать матчи?
Существуют разные способы создания прогнозов. Я могу изготовить сложную модель машинного обучения и передать ей множество переменных, однако прочитав несколько научных статей, я решил дать шанс распределению Пуассона.
Почему? Давайте рассмотрим определение этого распределения.
Распределение Пуассона — это дискретное распределение вероятностей, описывающее количество событий, происходящих в фиксированном временном интервале или области возможностей.
Если мы будем воспринимать гол как событие, которое может произойти за 90 минут футбольного матча, то сможем вычислить вероятность количества голов, которые будут забиты в матче команды А и команды Б.
Но этого недостаточно. Нам ещё нужно соответствовать допущениям распределения Пуассона.
- Количество событий можно подсчитать (в матче может быть 1, 2, 3 или больше голов).
- События происходят независимо друг от друга (событие одного гола не должно влиять на вероятность другого).
- Частота событий постоянна (вероятность того, что гол будет забит в определённый интервал времени, должна быть совершенно одинаковой для любого другого интервала времени той же длины).
- Два события не могут произойти точно в один момент времени (два гола не могут произойти одновременно).
Когда я прогнозировал победителей европейских чемпионатов, я создал гистограмму количества голов в каждом матче на протяжении последних пяти лет для четырёх чемпионатов.
Гистограммы количества голов в четырёх чемпионатах
Аппроксимирующая кривая всех чемпионатов похожа на распределение Пуассона.
Мы можем прийти к выводу, что распределение Пуассона подходит для вычисления количества голов, которые могут быть забиты в матче.
Вот формула распределения Пуассона:
Для создания прогнозов я учёл следующие аспекты:
- lambda: медианное значение голов за 90 минут (команда А и команда Б),
- x: количество голов в матче, которые могли забить команда А и команда Б.
lambda
нам нужно среднее количество голов, забитых/пропущенных каждой командой. Это приводит нас к следующему пункту.▍ Голы забитые/пропущенные каждой командой
Собрав данные со всех матчей Чемпионата мира, сыгранных с 1930 по 2018 год, я смог вычислить среднее количество голов, забитых и пропущенных командой каждой страны.
В прогнозе, сделанном для четырёх европейских чемпионатов, я учёл фактор игры дома/в гостях, но поскольку на Чемпионате мира почти все команды играют на нейтральном стадионе, в этом анализе данный фактор не учитывался.
Получив количество голов, забитых/пропущенных командой каждой страны, я создал функцию, предсказывающую количество очков, которые получит каждая команда в групповом этапе.
▍ Прогнозирование группового этапа
Ниже показан код, использованный мной для прогнозирования количества очков, которые получит команда каждой страны в групповом этапе. Выглядит пугающе, однако в этом коде присутствует многое из того, что описано выше.
def predict_points(home, away):
if home in df_team_strength.index and away in df_team_strength.index:
lamb_home = df_team_strength.at[home,'GoalsScored'] * df_team_strength.at[away,'GoalsConceded']
lamb_away = df_team_strength.at[away,'GoalsScored'] * df_team_strength.at[home,'GoalsConceded']
prob_home, prob_away, prob_draw = 0, 0, 0
for x in range(0,11): #количество голов команды хозяев
for y in range(0, 11): #количество голов команды гостей
p = poisson.pmf(x, lamb_home) * poisson.pmf(y, lamb_away)
if x == y:
prob_draw += p
elif x > y:
prob_home += p
else:
prob_away += p
points_home = 3 * prob_home + prob_draw
points_away = 3 * prob_away + prob_draw
return (points_home, points_away)
else:
return (0, 0)
Если объяснять простым языком,
predict_points
вычисляет количество очков, которые получат команды, играющие дома и в гостях. Чтобы получить их, я вычисляю lambda
для каждой команды по формуле average_goals_scored * average_goals_conceded
.Затем я симулирую все возможные результаты матча от 0-0 до 10-10 (этот последний счёт является просто пределом моего интервала голов). Получив
lambda
и x
, я использую формулу распределения Пуассона для вычисления p
.prob_home
, prob_draw
и prob_away
накапливают значение p
, если, допустим, матч заканчивается со счётом 1-0 (выиграла команда хозяев), 1-1 (ничья) или 0-1 (выиграла команда гостей). Затем по показанной ниже формуле вычисляется результат.points_home = 3 * prob_home + prob_draw
points_away = 3 * prob_away + prob_draw
Если мы используем
predict_points
для прогнозирования матча Англии против США, то получим следующее.>>> predict_points('England', 'United States')
(2.2356147635326007, 0.5922397535606193)
Это значит, что Англия получит 2,23 очка, а США — 0,59. Я получаю десятичные дроби, потому что использую вероятности.
Если мы применим функцию
predict_points
ко всем матчам в групповом этапе, то получим первое и второе место в каждой группе, а значит, следующие матчи плей-офф.▍ Прогнозирование плей-оффов
В плей-оффах мне нужно было прогнозировать не очки, а победителя в каждом из матчей. Поэтому я создал новую функцию
get_winner
на основе функции predict_points
.def get_winner(df_fixture_updated):
for index, row in df_fixture_updated.iterrows():
home, away = row['home'], row['away']
points_home, points_away = predict_points(home, away)
if points_home > points_away:
winner = home
else:
winner = away
df_fixture_updated.loc[index, 'winner'] = winner
return df_fixture_updated
Если
points_home
больше points_away
, то победителем стала команда хозяев, в противном случае — команда гостей.Благодаря функции
get_winner
я могу получить результаты предыдущих турнирных таблиц.▍ Прогнозирование четвертьфинала, полуфинала и финала
Если я снова использую
get_winner
, то смогу спрогнозировать победителя Чемпионата мира. И вот окончательный результат!Запустив функцию ещё раз, я выяснил, что победителем будет…
Бразилия!
Вот и всё! Вот так я спрогнозировал результаты Чемпионата мира 2022 года при помощи Python и распределения Пуассона. Полный код выложен на GitHub. Также вы можете изучить мой список на Medium со всеми статьями, относящимися к этому проекту на Python.
Комментарии (13)
thevlad
12.12.2022 17:36+4Если объяснить в двух словах, то вы посчитали среднюю по всей истории стационарную интенсивность голов для каждой команды, и потом на основе этого единственного фактора пытаетесь сделать предсказание. Не удивлюсь что если банальное max(lambda_i) будет давать тот же результат (по крайней мере это логично с точки зрения пуассоновского распределения). И то что получилась Бразилия, тоже вполне очевидно.
PS: да, увидел что перевод, но все равно думаю кому-то будет интересно
AlexCzech01
12.12.2022 23:33+4Сборная Уэльса вышла в финал чемпионата мира во второй раз в истории, а первый был в 1958. Получается, что её выход в плэй-офф предсказан на основании того, что 64 года назад они сыграли довольно хорошо. Если бы они тогда проиграли все 3 матча - они бы и по этой модели должны были бы сыграть плохо. Очевидно, что это не имеет никакого отношения к реальной их силе
Уже из этого примера понятно, что эта модель никуда не годится
И действительно неудивительно, что чемпионом по ней стала Бразилия - это единственная сборная, которая участвовала абсолютно во всех финальных турнирах ЧМ в истории
Это скорее яркий антипаттерн - когда берется модель, неплохо подошедшая к одной задаче, и механически применяется к другой похожей, но на самом деле по сути абсолютно другой
Vsevo10d
13.12.2022 01:57Бессмысленно, как по мне.
Во-первых, национальные сборные весьма нестабильная вещь, даже если какой-то гениальный футболист будет 10 лет подряд выдавать одинаково качественную игру, это только 2 чемпионата мира подряд.
Во-вторых, футбол - наименее подходящая для таких моделей игра, поскольку выигрыш там основан на очень сложном и маловероятном событии - голе. В футболе стандартный счет - от 1:0 до 2:1, счет 3:0 – это закатывание соперника в асфальт практически. С матчевым счетом такой дискретности считать выигрыши команд по эффективности голов - ну лиги вы еще оцените, но турниры с плей-офф будут полны внезапных андердогов. А еще существует такая убогая вещь, как пенальти после дополнительного времени.
Лучше уж хоккей предсказывать, там счет голов за матч в целом побольше, меньше шансов случайно забить.
И кстати, финал "Бразилия - Франция" уже, помнится, был, и с немного другим результатом ))
Laurens
13.12.2022 11:31Я помню, когда лучше всяких Python'ов предсказывал игры чемпионата осьминог Пауль. Последние чемпионаты показывают, что в футболе может многое поменяться. какой тренер, как сборная смогла "сыграться".. те же хорваты- какой им там раньше четвертьфинал даже? Испанцы - был СОСТАВ, так взяли 3 международных кубка..
svetloffs
13.12.2022 15:42Как показала практика, лучшие предсказатели исхода - мнения зрителей (это акк-ты==люди на сайте любой из контор (или аггрегатора событий) - там часто ставят голосование перед матчем). я в своих моделях коэфф от этого рейтинга стал добавлять... а модели - да, кул, но не точно.
Starina_js
15.12.2022 06:50Хех, какой шанс предсказать, что Аргентина в группе проиграет Саудовской Аравии, Франция проиграет Тунису, а Марокко в плейофф пройдет Испанию и Португалию , дойдет до полуфинала ?)
nekit-0123
Флаги напутаны на картинке, и если даже поменять их местами то прогноз и на 50% не верен, значит вся работа проделана грубо говоря зря
4500zenja
Отчего же они напутаны?
Матчи 1/8-финала плейофф составляется следующим образом: 1-ое место группы A играет со 2-ым местом группы B, 2-ое место группы A – с 1-мы местом группы B, а дальше повторяем процесс, меняем при этим названия групп с A/B на C/D, E/F и G/H соответственно
UPD: и ещё автор перевода отдельно подчеркнул, что, хоть система и показала много промахов, выложить результаты всё равно стоит, ибо она имеет ценность :)
nekit-0123
Прошу прощения только после объяснения понял где какая группа.
А на счет ценности неуверен
lexasss
Про ценность конретно этого исследования - согласен. Автор использует, например, статистику 1930 года чтобы делать предсказания в 2022. Марокко в полуфинале у такого способа не окажется никогда. Его лучше спользовать так же как и раньше - прогнозировать победителя лиги в середине сезона, где 17-19 игр уже сыграно, и столько же осталось, т.к. статистика уже кое-какая есть, и она адекватна текущему состоянию команд.