Введение в спортивную аналитику с помощью Pandas
Спортивная аналитика - одно из важнейших направлений науки о данных. Прогресс в методах сбора и анализа данных сделал команды более привлекательными для адаптации стратегий, основанных на аналитике данных.
Аналитика данных дает ценную информацию как об эффективности команды, так и о производительности игроков. При разумном и систематическом использовании аналитика данных, скорее всего, выведет команды впереди конкурентов.
В некоторых клубах есть целая команда, занимающаяся аналитикой данных. Ливерпуль - пионер в использовании аналитики данных, что, на мой взгляд, является важной частью их успеха. Они последний чемпион Премьер-лиги и победитель Лиги чемпионов 2019 года.
В этом посте мы будем использовать Pandas, чтобы получить значимые результаты матчей немецкой Бундеслиги в сезоне 2017–18. Наборы данных можно скачать по ссылке. Мы будем использовать часть наборов данных, представленных в документе «Открытый набор данных пространственно-временных событий матчей в футбольных соревнованиях».
Наборы данных сохраняются в формате JSON, который можно легко прочитать в фреймах данных pandas.
import numpy as np
import pandas as pd
events = pd.read_json("/content/events_Germany.json")
matches = pd.read_json("/content/matches_Germany.json")
teams = pd.read_json("/content/teams.json")
players = pd.read_json("/content/players.json")
events.head()
Фрейм данных событий содержит подробную информацию о событиях, произошедших в матчах. Например, первая строка сообщает нам, что игрок 15231 сделал «простой пас» из позиции (50,50) в (50,48) в третью секунду матча 2516739.
Фрейм данных событий включает идентификаторы игроков и команд, но не имена игроков и команд. Мы добавим их из фреймов данных команд и игроков, используя функцию слияния.
Идентификаторы хранятся в столбце «wyId» в фреймах данных команд и игроков.
#merge with teams
events = pd.merge(
events, teams[['name','wyId']],
left_on='teamId', right_on='wyId'
)
events.rename(columns={'name':'teamName'}, inplace=True)
events.drop('wyId', axis=1, inplace=True)
#merge with players
events = pd.merge(
events, players[['wyId','shortName','firstName']],
left_on='playerId', right_on='wyId'
)
events.rename(
columns={'shortName':'playerName', 'firstName':'playerFName'},
inplace=True
)
events.drop('wyId', axis=1, inplace=True)
Мы объединили фреймы данных на основе столбцов, содержащих идентификаторы, а затем переименовали новые столбцы. Наконец, столбец «wyId» удаляется, потому что идентификаторы уже хранятся в кадре данных событий.
Среднее количество передач за матч
Команды, которые доминируют в игре, обычно делают больше передач. В целом у них больше шансов выиграть матч. Конечно, есть исключения.
Давайте проверим среднее количество передач за матч для каждой команды. Сначала мы создадим фрейм данных, содержащий название команды, идентификатор матча и количество проходов, выполненных в этом матче.
pass_per_match = events[events.eventName == 'Pass']\[['teamName','matchId','eventName']]\
.groupby(['teamName','matchId']).count()\
.reset_index().rename(columns={'eventName':'numberofPasses'})
Аугсбург сделал 471 передачу в матче 2516745. Вот список 5 лучших команд по количеству передач за матч.
pass_per_match[['teamName','numberofPasses']]\
.groupby('teamName').mean()\
.sort_values(by='numberofPasses', ascending=False).round(1)[:5]
Неудивительно, что у «Баварии» больше всего передач. В последние годы они доминируют в Бундеслиге.
Средняя длина передачи игроков
Успешный результат можно оценить по многим параметрам. Некоторые передачи настолько успешны, что очень легко забить.
Мы сосредоточимся на количественной оценке проходов, то есть на длине. Некоторые игроки очень хороши в длинных передачах.
Столбец позиций содержит начальное и конечное положение мяча в координатах x и y. Мы можем рассчитать длину на основе этих координат. Давайте сначала создадим фрейм данных, который содержит только проходы.
passes = events[events.eventName=='Pass'].reset_index(drop=True)
Теперь мы можем рассчитать длину.
pass_length = []
for i in range(len(passes)):
length = np.sqrt(((passes.positions[i][0]['x'] -
passes.positions[i][1]['x'])**2)\ +
((passes.positions[i][0]['y'] -
passes.positions[i][1]['y'])**2))
pass_length.append(length)
passes['pass_length'] = pass_length
Функцию groupby можно использовать для расчета средней длины передачи для каждого игрока.
passes[['playerName','pass_length']].groupby('playerName')\
.agg(['mean','count']).\
sort_values(by=('pass_length','mean'), ascending=False).round(1)[:5]
Мы перечислили 5 лучших игроков по средней длине передач, а также по количеству выполненных передач. Количество проходов важно, потому что выполнение всего 3 проходов не имеет большого значения по отношению к среднему значению. Таким образом, мы можем фильтровать те, которые меньше определенного количества проходов.
Среднее количество передач для выигрыша и не-выигрыша
Давайте сравним среднее количество передач между выигранными и невыигрышными матчами. Я буду использовать в качестве примера сопоставление Б. Леверкузена.
events = pd.merge(events, matches[['wyId','winner']], left_on='matchId', right_on='wyId')
events.drop('wyId', axis=1, inplace=True)
Теперь мы можем создать фрейм данных, который содержит только события, идентификатор команды которых равен 2446 (идентификатор Б. Леверкузена).
leverkusen = events[events.teamId == 2446]
Победителем становится Б. Леверкузен, если значение в столбце «победитель» равно 2446. Чтобы вычислить среднее количество передач в матчах, в которых выиграл Б. Леверкузен, нам необходимо отфильтровать фрейм данных на основе победителя и имени события. Затем мы применим группировку и подсчет, чтобы увидеть количество передач за матч.
passes_in_win = leverkusen[(leverkusen.winner == 2446) & (leverkusen.eventName == 'Pass')][['matchId','eventName']].groupby('matchId').count()
passes_in_notwin = leverkusen[(leverkusen.winner != 2446) & (leverkusen.eventName == 'Pass')][['matchId','eventName']].groupby('matchId').count()
Мы можем легко получить среднее количество проходов, применив функцию среднего.
Хотя выполнение большего количества передач не означает определенной победы, это поможет вам доминировать в игре и повысить ваши шансы на выигрыш.
Возможности спортивной аналитики выходят далеко за рамки того, что мы сделали в этом посте. Однако без ознакомления с основами будет труднее усвоить знания о более сложных методах.