Xg предсказывает результаты матчей?

Для начала определим для кого эта статья? Моя цель заинтересовать не только обыкновенных зрителей, но и тех, кто уже занимается футбольной аналитикой. В статье я постараюсь показать интересные исследования об Xg.

Многие из тех, кто смотрит футбол и читает новости когда-нибудь видел метрику «xg». Что она вообще означает? Простыми словами Xg это количество ожидаемых голов. Т.е. каждый нанесённый удар по воротам имеет вероятность конвертироваться в забитый мяч, но с каждой позиции эта вероятность разная (если углубляться, то станет очевидным, что xg зависит от нескольких параметров, а не от одной позиции). К примеру, самая высокая вероятность забить мяч при исполнении пенальти. Чаще всего с пенальти дают 0.79 xg. Необходимо учитывать, что единой формулы расчёта xg нет, каждый провайдер рассчитывает её по-своему. Так например, для написания этой статьи я использовал данные с сайта https://understat.com/, но, если мы посмотрим другие источники, цифры будут отличаться.

Моя задача узнать, насколько точно Xg предсказывает количество голов в матче. Исследование будем проводить для АПЛ сезона 2022/2023. В данном исследовании мы ограничимся простыми методами анализа. Я составил таблицу из 380 матчей АПЛ. Пример таблицы с первыми 10 матчами АПЛ.

Table_EPL <- read.csv("F:\\EPL.csv")# Загружаем наш csv файл

3a90612a1c8334e3ac027ff948a24c4f.png

Order — отвечает в таблице за количество матчей от 1 до 380

Week — в каком туре был сыгран матч, в Англии туры называют неделями. Предварительно для удобства все матчи объединены по турам, вне зависимости от даты, например матч 28 тура Брайтон — МЮ был сыгран 4 мая, хотя 28 тур игрался в середине марта.

Team1 — команда хозяин

Xg1 — показатель xg домашней команды

Goal1 — сколько голов забила домашняя команда

Goal2 — сколько голов забила гостевая команда

Xg2 — показатель xg гостевой команды

Team2 — команда гость

Изначальная таблица построена, далее будем считать разницу между забитыми мячами и xg у каждой из команд (diff1 и diff2), а потом напишем «yes» если разница меньше или равна 0.5, и, если разница строго больше 0.5 пишем «no» (Res1 и Res2).

Table_EPL$diff1 <- (Table_EPL$Xg1 - Table_EPL$Goal1)# Считаем разность Xg и забитых мячей для команд хозяев
Table_EPL$diff2 <- (Table_EPL$Xg2 - Table_EPL$Goal2)# Считаем разность Xg и забитых мячей для команд гостей
Table_EPL$Res1 <- ifelse(abs(Table_EPL$diff1) > 0.5, 'no', 'yes')# Условие "успешности" прдесказанных забитых голов для команд хозяев
Table_EPL$Res2 <- ifelse(abs(Table_EPL$diff2) > 0.5, 'no', 'yes')# Условие "успешности" прдесказанных забитых голов для команд гостей

Получится данная таблица:

ccbee12f04feafbb6502e1674b4c56e4.png

Далее проведём два анализа строгий и нестрогий. В строгом анализе будем выводить «yes» если в Res1 и Res2 указано «yes», в нестрогом анализе если хотя бы в одном из столбцов имеется значение «yes».

Проведём строгий анализ

Table_EPL$success <- ifelse(Table_EPL$Res1 == 'yes' & Table_EPL$Res2 == 'yes', 'yes', 'no')# Условие "успешного" предсказания результата матча

Всего успешно предсказанных матчей получается 65, неуспешных соответственно 315.

Всего успешно предсказанных матчей получается 65, неуспешных соответственно 315.

length(which(Table_EPL$success == 'no' ))# Подсчёт "неуспешных" результатов

Теперь рассмотрим нестрогий анализ

Table_EPL$success <- ifelse(Table_EPL$Res1 == 'yes' | Table_EPL$Res2 == 'yes', 'yes', 'no')# Условие "успешного" предсказания результата матча

Получится таблица:

Всего успешно предсказанных матчей получается 241, неуспешных соответственно 139.

Всего успешно предсказанных матчей получается 241, неуспешных соответственно 139.

length(which(Table_EPL$success == 'no' ))# Подсчёт "неуспешных" результатов

Суммарные значения

sum(Table_EPL$Xg1,Table_EPL$Xg2)# Суммарный Xg
sum(Table_EPL$Goal1,Table_EPL$Goal2)# Суммарное количество голов

Суммарный xg равен 1136.54, мячей забито 1084, разница равна 52.54

Столь незначительное отклонение от забитых мячей говорит, что Xg может не быть точным в каждом конкретном матче, но на дистанции сезона, данная метрика покажет более чем хорошие результаты. Незначительное оно т.к. я рассматриваю ошибку предсказания в матче больше 0,5. В нашем случае разница значительно меньше 190(380 матчей * 0,5).

Далее приведу статистику средних значений.

Весь чемпионат:

summary(c(Table_EPL$Xg1,Table_EPL$Xg2))# Вычисляем средний Xg

Средний Xg — 1,48

summary(c(Table_EPL$Goal1,Table_EPL$Goal2))# Вычисляем среднее количество голов

Среднее кол-во голов — 1,43

Для команд хозяев:

summary(Table_EPL$Xg1)# Вычисляем средний Xg

Средний Xg — 1,67

summary(Table_EPL$Goal1)# Вычисляем среднее количество голов

Среднее кол-во голов — 1,63

Для команд гостей:

summary(Table_EPL$Xg2)# Вычисляем средний Xg

Средний Xg — 1,3

summary(Table_EPL$Goal2)# Вычисляем среднее количество голов

Среднее кол-во голов — 1,2

Ну и в конце проведём некую оценку точности показателей Xg. Я здесь имею ввиду, что чем больше забито мячей, тем большую неточность показывает Xg. Пример матч Ливерпуль 9:0 Борнмут, Xg в этом матче Ливерпуль 4,86 Борнмут 0,18.

Попробуем оценить в какой момент Xg не даёт удовлетворительную точность. Замечу, что здесь поменяем способ оценки и будем рассчитывать не интервал ± 0,5 xg, а значение xg большее или равное минимально допустимой границе для количества забитых мячей.

Для домашних игр:

length(which(Table_EPL$Goal1 == '4'))# Количество матчей с 4 голами
length(which(Table_EPL$Goal1 == '4' & Table_EPL$Xg1 >= '3.5'))# Количество матчей с 4 голами и Xg более 3.5

Матчей с 4 забитыми мячами — 28, xg ≥ 3,5 — 4 матча, точность ~ 14,3%

length(which(Table_EPL$Goal1 == '3'))# Количество матчей с 3 голами
length(which(Table_EPL$Goal1 == '3' & Table_EPL$Xg1 >= '2.5'))# Количество матчей с 3 голами и Xg более 2.5

Матчей с 3 забитыми мячами — 43, xg ≥ 2,5 — 19 матчей, точность ~ 44,2%

length(which(Table_EPL$Goal1 == '2'))# Количество матчей с 2 голами
length(which(Table_EPL$Goal1 == '2' & Table_EPL$Xg1 >= '1.5'))# Количество матчей с 2 голами и Xg более 1.5

Матчей с 2 забитыми мячами — 90, xg ≥ 1,5 — 53 матча, точность ~ 58,9% 

length(which(Table_EPL$Goal1 == '1'))# Количество матчей с 1 голом
length(which(Table_EPL$Goal1 == '1' & Table_EPL$Xg1 >= '0.5'))# Количество матчей с 1 голом и Xg более 0.5

Матчей с 1 забитым мячом — 124, xg ≥ 0,5 — 112 матчей, точность ~ 90,3% 

Построим простой график для иллюстрации

library(ggplot2)# Подключаем ggplot2 для построения графика
plot(Table_XG$week, Table_XG$Goal1, type =  "o", pch = 16,# Ось Х, Ось У, Тип линии графика, Тип точки на графике
     main = 'Xg in match',# Название графика
     xlab = 'week',# Подпись оси Х
     ylab = 'xg and goal',# Подпись оси У
     col = 'green3',# Цвет линии
     lwd = 2)# Толщина линии
xlines = seq(min(Table_XG$week), max(Table_XG$week), 1)# Создаём последовательность с указанием минимального и максимального значения
ylines = seq(min(Table_XG$Goal1), max(Table_XG$Goal1), 1)# Создаём последовательность с указанием минимального и максимального значения
abline(h = ylines, v = xlines, col = "lightgray")# Рисуем сетку по нашим последовательностям
lines(Table_XG$week, Table_XG$Xg1, type = "o", pch = 19, col = 'red', lwd = 2)# Добавляем вторую линию на график, аналогично первой
legend("topleft",# Создаём легенду и указываем её положение                                    
       legend = c("Goals", "Xg"),# Что будет указано в легенде
       col = c("green3", "red"),# указываем цвета в легенде
       lty = 7,# Тип линии в легенде
       pch = 19)# Тип точки в легенде

99a5d53545a93bdd919ff9152a7d5e34.png

Для гостевых игр:

length(which(Table_EPL$Goal2 == '4'))# Количество матчей с 4 голами
length(which(Table_EPL$Goal2 == '4' & Table_EPL$Xg2 >= '3.5'))# Количество матчей с 4 голами и Xg более 3.5

Матчей с 4 забитыми мячами — 15, xg ≥ 3,5 — 2 матча, точность ~ 13,3% 

length(which(Table_EPL$Goal2 == '3'))# Количество матчей с 3 голами
length(which(Table_EPL$Goal2 == '3' & Table_EPL$Xg2 >= '2.5'))# Количество матчей с 3 голами и Xg более 2.5

Матчей с 3 забитыми мячами — 35, xg ≥ 2,5 — 7 матчей, точность ~ 20% 

length(which(Table_EPL$Goal2 == '2'))# Количество матчей с 2 голами
length(which(Table_EPL$Goal2 == '2' & Table_EPL$Xg2 >= '1.5'))# Количество матчей с 2 голами и Xg более 1.5

Матчей с 2 забитыми мячами — 76, xg ≥ 1,5 — 44 матча, точность ~ 57,9% 

length(which(Table_EPL$Goal2 == '1'))# Количество матчей с 1 голом
length(which(Table_EPL$Goal2 == '1' & Table_EPL$Xg2 >= '0.5'))# Количество матчей с 1 голом и Xg более 0.5

Матчей с 1 забитым мячом — 125, xg ≥ 0,5 — 112 матчей, точность ~ 89,6%

Построим простой график для иллюстрации

library(ggplot2)# Подключаем ggplot2 для построения графика
plot(Table_XG$week, Table_XG$Goal2, type =  "o", pch = 16,# Ось Х, Ось У, Тип линии графика, Тип точки на графике
     main = 'Xg in match',# Название графика
     xlab = 'week',# Подпись оси Х
     ylab = 'xg and goal',# Подпись оси У
     col = 'green3',# Цвет линии
     lwd = 2)# Толщина линии
xlines = seq(min(Table_XG$week), max(Table_XG$week), 1)# Создаём последовательность с указанием минимального и максимального значения
ylines = seq(min(Table_XG$Goal2), max(Table_XG$Goal2), 1)# Создаём последовательность с указанием минимального и максимального значения
abline(h = ylines, v = xlines, col = "lightgray")# Рисуем сетку по нашим последовательностям
lines(Table_XG$week, Table_XG$Xg2, type = "o", pch = 19, col = 'red', lwd = 2)# Добавляем вторую линию на график, аналогично первой
legend("topleft",# Создаём легенду и указываем её положение                                    
       legend = c("Goals", "Xg"),# Что будет указано в легенде
       col = c("green3", "red"),# указываем цвета в легенде
       lty = 7,# Тип линии в легенде
       pch = 19)# Тип точки в легенде

95f17fdfd217c3d94c8144d645f83dd2.png

Выводы

Исходя из проведённого анализа можно сделать вывод, что xg показывает высокую точность предсказания результатов матчей на дистанции, а не в одном отдельном взятом матче. Это можно понять увидев, что при строгом анализе предсказано ~ 17,1% матчей, а при нестрогом ~ 63,4% матчей, что конечно хорошо, но как по мне недостаточно, учитывая, что мы считали матч успешным, если хотя бы у одной из команд предсказано значение. Также у Xg есть такой недостаток, как потеря точности при забитых мячах больше 2. В итоге можно сказать, что xg действительно хорошая и нужная метрика, однако она не является единственной главной.

Для опытных аналитиков статья будет просто интересной информацией, а для обыкновенных зрителей, я надеюсь, она станет толчком к началу углубленного изучения футбольной статистики.

© Habrahabr.ru