Аналитика данных и наука о данных - большая часть современного профессионального спорта. Вот некоторые из способов его использования:

  • выигрышные игры
  • выбор игроков в командных играх
  • помогая командам лучше понять своих фанатов
  • улучшить производительность игрока
  • снизить риск травм

В фильме «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 или наш веб-сайт (указанный ниже). Спасибо за уделенное время и удачи!

Использованная литература:

  1. Гамильтон, Х., Расширение пифагорейских ожиданий в отношении футбольных ассоциаций, 21.06.2021, ссылка

Свяжитесь с г-ном Data Science:

MrDataScience.com, GitHub, Средний,