Аналитика данных и наука о данных - большая часть современного профессионального спорта. Вот некоторые из способов его использования:
- выигрышные игры
- выбор игроков в командных играх
- помогая командам лучше понять своих фанатов
- улучшить производительность игрока
- снизить риск травм
В фильме «Moneyball» 2011 года (небольшое предупреждение о спойлере) Брэд Питт играет генерального менеджера бейсбольной команды Oakland Athletics Билли Бина, уделяя особое внимание сезону команды 2002 года. Фильм основан на одноименной научно-популярной книге Майкла Льюиса 2003 года.
В 2002 году «Окленд Атлетикс» установила бейсбольный рекорд, выиграв двадцать игр подряд, что само по себе является значительным достижением, но еще более запоминающимся, учитывая, что Окленд не был богатой командой и не мог позволить себе дорогих игроков. Так что их генеральный менеджер Билли Бин и его помощник Пол ДеПодеста (персонажа в фильме звали Питер Брэнд) использовали саберметрию, чтобы создать команду-победительницу. Sabermetrics (иногда называемые SABRmetrics) - это использование статистики для лучшего понимания таких аспектов, как сильные и слабые стороны игроков.
Если не первым, то бейсбол был одним из первых видов спорта, в котором аналитика данных использовалась для принятия тренерских и управленческих решений. В наши дни большинство профессиональных спортсменов используют данные для принятия решений.
Sabermetrics - это пример анализа полевых данных. Другой ключевой областью является анализ данных вне поля, который фокусируется на физических данных, таких как положение, движение и частота пульса. Сбор данных вне поля стал возможен с развитием носимых устройств сбора данных. Технология может собирать данные о таких вещах, как GPS (движение, положение, скорость, ускорение ...), мониторинг сердечного ритма, дыхания и так далее.
В фильме «Манибол» было сосредоточено внимание на противостоянии между персонажами, пытающимися использовать саберметрию, и персонажами, которые выступали против использования статистики при выборе команды и решениях тренера. На самом деле наука о данных не заменит коучей, инструкторов или скаутов, но может улучшить процесс принятия решений, сделав его менее зависимым от традиций и интуиции.
Теперь, когда вы больше разбираетесь в истории и использовании науки о данных в спорте, давайте приступим к написанию кода. В следующих примерах мы рассмотрим, как добавлять столбцы для применения функций к фреймам данных, создавать тепловые карты и графики скрипки и комбинировать фреймы данных с использованием общего ключа. Чтобы следовать примерам, вам необходимо установить следующие библиотеки python:
Давайте посмотрим на несколько примеров:
Пример 1 - Исследовательский анализ данных набора спортивных данных
Первый набор данных - это менее известный вид спорта, по крайней мере, за пределами Австралии. Это некоторая статистика австралийских правил футбола. Есть объяснение Австралийских правил футбола в Википедии. В мире существует множество разновидностей футбола; австралийский сорт, пожалуй, уникален тем, что играет на овальном поле, а не на обычном прямоугольном поле. Мы проведем некоторый исследовательский анализ данных (EDA) по данным.
Данные доступны на Kaggle.
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt
df_afl = pd.read_csv('sport/afl_stats.csv')
df_afl.head(2)
так что у нас смешаны игровые данные и данные игрока, мы можем извлечь игровые данные в меньший фрейм данных:
keep_columns = ['Year', 'Round', 'Team', 'Score', 'Margin', 'WinLoss', 'Opposition', 'Day', 'Date', 'Start Time', 'Venue', 'Attendance', 'Rainfall(mm)']
df_afl_games = df_afl[keep_columns]
df_afl_games.head(2)
В этом новом фрейме данных будет много дубликатов; мы можем удалить дубликаты, используя:
df_afl_games = df_afl_games.drop_duplicates()
df_afl_games.head(2)
При желании мы могли бы проанализировать эти данные, например:
df_afl_games['Day'].value_counts(normalize=True)
Sat 0.510732 Sun 0.297744 Fri 0.126032 Thu 0.038525 Mon 0.017611 Wed 0.004953 Tue 0.004403 Name: Day, dtype: float64
Таким образом, более 80% игр проводится в выходные дни и более 50% - в субботу. По вторникам в игры не играли. Мы также можем создавать меньшие фреймы данных, на этот раз используя условия для выбора строк. Мы можем сравнить распределение очков между разными командами, когда они играют дома:
df_afl_games_adelaide = df_afl_games[df_afl_games['Team']=='Adelaide']
df_afl_games_Sydney = df_afl_games[df_afl_games['Team']=='Sydney']
sns.violinplot(x='Score',data=df_afl_games_adelaide);
sns.violinplot(x='Score',data=df_afl_games_Sydney,color='green');
Эти скрипичные сюжеты иллюстрируют распределение очков в домашних матчах между двумя командами.
Другой способ исследования данных - поиск корреляций. Мы можем посмотреть на корреляцию между столбцами в полном фрейме данных. Сначала получите список всех числовых столбцов:
columns = ['Rainfall(mm)','Height', 'Weight', 'Disposals', 'Kicks', 'Marks', 'Handballs', 'Goals', 'Behinds', 'Hit Outs', 'Tackles', 'Rebounds', 'Inside 50s', 'Clearances', 'Clangers', 'Frees', 'Frees Against', 'Brownlow Votes', 'Contested Possessions', 'Uncontested Possessions', 'Contested Marks', 'Marks Inside 50', 'One Percenters', 'Bounces', 'Goal Assists', '% Played', 'Subs']
Затем используйте Seaborn для построения корреляционной матрицы:
plt.figure(figsize = (16,10))
sns.heatmap(df_afl[columns].corr().round(2),annot=True);
Некоторые из этих данных легко понять; Например
- нет корреляции между количеством осадков и количеством забитых голов
Но для понимания других взаимосвязей требуются некоторые специальные знания, например:
- существует корреляция между «Неоспоримым имуществом» и «Распоряжением», но меньше корреляции между «Оспариваемым имуществом» и «Распоряжением».
Для людей, знакомых с AFL, это можно легко объяснить; для всех нас это загадка. Подобные примеры иллюстрируют необходимость знания предметной области или сотрудничества экспертов по данным и экспертов в предметной области. Но он также показывает, как несколько строк кода могут раскрыть потенциально полезную информацию из необработанных данных. В следующем примере мы рассмотрим математическое ожидание Пифагора; способ измерения производительности команды.
Пример 2 - Использование пифагоровых ожиданий для оценки производительности
В этом примере рассматривается математическое ожидание; полное объяснение есть в Википедии. Первоначально он был разработан для бейсбола. Цель пифагорейского ожидания - определить, было ли хорошее выступление команды в сезоне результатом ее силы или удачи. Команда, которая выступила лучше, чем их пифагорейские ожидания, вероятно, имела несколько удачных побед. Математическая формула, используемая в расчетах, использует константу k, которая варьируется от вида спорта к виду спорта. Данные, на которые мы будем смотреть, - это футбол. Пифагорейские ожидания основаны на эмпирических наблюдениях, а не на научной теории выступлений спортивных команд. Более надежная формула представлена в справочной статье [1]. Формула, использованная в этом примере, взята из этой статьи.
В этом примере также показано, как сгенерировать новый столбец в кадре данных путем применения функции с использованием нескольких столбцов в качестве параметров функции.
Данные доступны на Kaggle.
results = pd.read_csv('sport/results.csv', encoding= 'unicode_escape')
results.head(1)
Посмотрим на одну команду на один сезон:
results_9394 = results[(results['Season']=='1993-94') & ((results['HomeTeam']=='Arsenal') | (results['AwayTeam']=='Arsenal'))]
results_9394.head(2)
Есть много столбцов, которые нам не нужны, поэтому давайте их отбросим:
keep_cols = ['Season', 'HomeTeam', 'AwayTeam', 'FTHG', 'FTAG', 'FTR'] results_9394 = results_9394[keep_cols]
results_9394.head(2)
Одна из версий формулы футбола:
процент взятых очков = GF¹.2 / (GF¹.2 + GA¹.2)
где GF = забитые голы, GA = голы, забитые другой командой. Эта формула предполагает, что, если команда не пропустит ни одного гола, она выиграет все свои игры, так как GA стремится к нулю, а процент процент баллов стремится к 1,0, поэтому набирается максимальное количество очков. Показатель степени - это эмпирическое значение, которое варьируется в зависимости от вида спорта.
Чтобы рассчитать это, используя приведенные выше данные, мы могли бы использовать:
def get_gf(HomeTeam,AwayTeam,FTHG,FTAG,FTR): gf = 0 if HomeTeam == 'Arsenal': gf = FTHG elif AwayTeam == 'Arsenal': gf = FTAG return gf
def get_ga(HomeTeam,AwayTeam,FTHG,FTAG,FTR): ga = 0 if HomeTeam == 'Arsenal': ga = FTAG elif AwayTeam == 'Arsenal': ga = FTHG return ga
results_9394['gf'] = results_9394.apply(lambda x: get_gf(x['HomeTeam'],x['AwayTeam'],x['FTHG'],x['FTAG'],x['FTR']),axis=1)
results_9394['ga'] = results_9394.apply(lambda x: get_ga(x['HomeTeam'],x['AwayTeam'],x['FTHG'],x['FTAG'],x['FTR']),axis=1)
Это добавляет два новых столбца, gf и ga.
results_9394.head()
Теперь мы можем подсчитать очки, команда получает 2 очка за победу, 1 за ничью и ноль за поражение.
def get_points(HomeTeam,AwayTeam,FTR): points = 0 if FTR == 'D': points = 1 elif HomeTeam == 'Arsenal' and FTR == 'H': points = 2 elif HomeTeam == 'Arsenal' and FTR == 'A': points = 0 elif AwayTeam == 'Arsenal' and FTR == 'H': points = 0 else: points = 2 return points
results_9394['points'] = results_9394.apply(lambda x: get_points(x['HomeTeam'],x['AwayTeam'],x['FTR']),axis=1)
results_9394.head()
общее количество доступных очков - это общее количество игр, умноженное на два
results_9394.shape
(42, 9)
итого доступное количество баллов = 42 * 2 = 84
общее количество набранных баллов = сумма в столбце баллов:
results_9394['points'].sum()
53
посмотрим, насколько хорошо формула это предсказывает:
GF = results_9394['gf'].sum() print(GF)
53
GA = results_9394['ga'].sum() print(GA)
28
percentagePointsTaken = 53**1.2/(53**1.2 + 28**1.2) print(percentagePointsTaken)
0.6825910423843826
0.6825910423843826 * 84
57.33764756028814
Таким образом, прогнозируемый счет - 57, фактический - 53, что говорит о том, что команда "Арсенала" недостаточно хорошо выступила в сезоне 1993/94.
Пример 3 - Расследование травм НФЛ
В этом примере исследуются спортивные травмы. Способность тренерской команды лучше понимать, как и когда возникают травмы, может помочь снизить количество травм.
Данные доступны на Kaggle. Данные разделены на три разных файла.
df_i = pd.read_csv('sport/InjuryRecord.csv')
df_i.head(1)
df_i['Surface'].value_counts()
Synthetic 57 Natural 48 Name: Surface, dtype: int64
df_syn = df_i[df_i['Surface']=='Synthetic']
df_nat = df_i[df_i['Surface']=='Natural']
df_syn['BodyPart'].value_counts(normalize=True)
Ankle 0.438596 Knee 0.421053 Toes 0.105263 Foot 0.035088 Name: BodyPart, dtype: float64
df_nat['BodyPart'].value_counts(normalize=True)
Knee 0.500000 Ankle 0.354167 Foot 0.104167 Heel 0.020833 Toes 0.020833 Name: BodyPart, dtype: float64
Исходя из этого, возможно, мы можем сказать, что травмы колена более вероятны на натуральных поверхностях, в то время как травмы лодыжек более распространены на синтетических поверхностях.
Мы можем продолжить расследование, посмотрев на PlayKey. Это требует объединения наборов данных:
plays = pd.read_csv('sport/PlayList.csv')
plays.head(1)
Давайте посмотрим на травмы колена на натуральных поверхностях:
df_nat_knee = df_nat[df_nat['BodyPart']=='Knee']
#result = pd.concat([df_nat_knee, plays], axis=1, join='inner', keys=['PlayKey']) result = pd.merge(df_nat_knee, plays, on="PlayKey")
result.head()
Теперь мы можем посмотреть на такие вещи, как тип стадиона, погоду и температуру - например, распределение температуры при травмах колена.
sns.violinplot(x='Temperature',data=result,color='red');
и тип погоды, наиболее связанный с травмами колена:
result['Weather'].value_counts()
Sunny 5 Partly Cloudy 4 Rain 3 Clear 2 Cloudy 2 Cold 1 Cloudy with periods of rain, thunder possible. Winds shifting to WNW, 10-20 mph. 1 Name: Weather, dtype: int64
Таким образом, травмы колена чаще возникают на сухом поле (солнечная или частично пасмурная погода). Возможно, травмы колена вызваны скручиванием, а не скольжением.
Завершение
Анализ спортивных данных может дать важную информацию об эффективности команды и игроков и лучше понять, как, когда и почему происходят травмы и каких игроков следует включить в команду.
Подводя итог, после прочтения этой статьи вы должны были узнать:
- Как создавать сюжеты для скрипки и корреляционные сюжеты.
- Как создавать новые столбцы с помощью функций.
- Как объединить наборы данных по ключу.
Если у вас есть отзывы или предложения по улучшению этой статьи, мы будем рады их услышать. Свяжитесь с нами через Medium, GitHub или наш веб-сайт (указанный ниже). Спасибо за уделенное время и удачи!
Использованная литература:
- Гамильтон, Х., Расширение пифагорейских ожиданий в отношении футбольных ассоциаций, 21.06.2021, ссылка