Чтобы просто посмотреть результаты прогноза, смотрите усеченную историю здесь.

Это первая статья из серии статей о машинном обучении для анализа НФЛ. В течение сезона я буду пересматривать модели, тестировать новые параметры и пытаться предсказать различные переменные. Это личный проект, который я делаю с помощью и при поддержке K2 Data Science, и все методы можно найти на моем GitHub. Сегодня мы рассмотрим несколько более сложные взаимосвязи переменных и попытаемся различить многомерные отношения более высокой размерности (отношения между несколькими входными переменными и выходной переменной).

Поскольку с этими данными можно многое сделать, я хотел бы коснуться применения. На данный момент я все еще пытаюсь найти лучший анализ, который можно сделать с этим типом ввода. Анализ потенциально может варьироваться от статистики, которая способствует сотрясениям мозга, сколько рашей за сезон приводит к существенному снижению усилий в последующем сезоне, какая статистика больше всего способствует победе и поражению, выпадающих игроков на их позиции или попытки определить ставки, чтобы сделать на игры. Лично меня интересуют все эти вещи, и я надеюсь, что со временем все это будет реализовано. Однако для усложнения мы начнем с простого:

Можем ли мы предсказать, что команда выиграет игру на этой неделе, и с какой степенью точности?

Для этого нам потребуется:

  1. Соберите всю позиционную статистику, полученную в одной игре. (Примечание: в настоящее время у меня есть таблицы только для QB, WR и RB. Я предполагаю, что точность будет увеличена с увеличением количества данных, и это произойдет в свое время). Я сохранил эти результаты в локальной базе данных sqlite для простоты доступа. Сейчас я использую только данные QB за последние 10 лет, так как эта позиция, возможно, оказывает наибольшее влияние на исход игры. Очевидно, что есть много других факторов, и набор данных будет расширен для включения других позиций, но для проверки концепции данных QB должно быть достаточно.
  2. Манипулировать данными, чтобы сделать их удобными для ML — это включало сопоставление игроков, команд, противников, удаление полей со странным форматированием, удаление пустых значений, преобразование строк даты в даты и время.
  3. Я решил, что лучшим способом отразить сценарии из реальной жизни будет разделение данных на свойства игрового дня и прошлые данные, так что свойствами игрового дня будут команда, соперники, время года и стартовый QB. Для прошлых данных я решил агрегировать статистику для каждой игры, в которую этот стартовый QB играл в прошлом.
  4. Чтобы оптимизировать модели обучения, я использовал GridSearchCV sklearn для тестирования различных комбинаций параметров для каждой модели классификации. Это также позволило немного контролировать параметры тестирования, чтобы сократить время итерации.
  5. В классе оптимизации я встроил уменьшение размерности, так что вы можете включать и выключать анализ основных компонентов (PCA) для этой цели (однако он не работает на всех моделях, поскольку он переназначает некоторые значения как отрицательные).
  6. Тогда просто ранжируйте модели! Я использовал чисто тестовую оценку для своего рейтинга (точность модели в классификации данных, которые не были включены в обучающий набор), которая оказалась очень последовательной для всех моделей, что утешительно.
  7. Наконец, я создал фрейм данных, который показывает прогнозы игр на неделю и агрегированный прогноз по всем моделям. Посмотрим, как он поведет себя в течение первой недели, и оптимизируем оттуда.

Без дальнейших церемоний:

1. Соберите позиционную статистику

Здесь мы создаем подключение к базе данных sqlite, в которой хранятся данные QB. Здесь показаны первые 5 строк кадра данных из 3784 строк со всей необработанной статистикой.

2. Очистите данные

Как видно из приведенных выше необработанных данных, многие из этих столбцов необходимо проанализировать перед подачей в модель ML. Например, мешки представлены в формате (количество мешков)/(общий метраж мешков), поэтому их можно разделить на два числовых столбца. Кроме того, все чисто строковые столбцы, такие как player_name, могут быть сопоставлены с уникальным числовым значением.

Есть несколько способов сделать это — у sklearn есть объект sklearn.preprocessing.OneHotEncoder, который создает двоичный столбец для каждой уникальной строки, или sklearn.preprocessing.LabelEncoder, который создает словарную карту значений string:encoding. Однако оба они являются временными объектами. Я предпочитаю, чтобы мои карты были постоянно доступны, поэтому для этой цели я создал таблицу карт команд и игроков в своей БД, чтобы вызывать ее, когда необходимы переводы. dataInitializer.cleanData() — это функция, которую я создал для преобразования всех столбцов в удобный для ML формат.

3. Агрегация статистики

Затем мы агрегируем статистику по столбцам, которые имеет смысл агрегировать. Это определение было довольно ручным — очевидно, нет смысла агрегировать сезоны или недели, но в будущем может иметь смысл иметь столбец общего сезона.

4. Множество оптимизаций модели и 5. Уменьшение размерности

Для оптимизации модели я предварительно загрузил параметры со страницы модели в документации sklearn и урезал их до такой степени, что разница в точности была незначительной, но потребовалось значительно меньше вычислительных усилий. Некоторые модели по-прежнему требуют некоторого времени, особенно SVC с ядром rbf и (по понятным причинам) все ансамблевые модели. При оптимизации оптимизатора я включил подробный параметр в функцию GridSearchCV, чтобы получить представление о времени, которое потребовалось каждой модели для перебора всех предоставленных параметров, чтобы упростить выявление зависаний. В финальной версии я просто добавил ручной таймер, так как verbose=1 все же больше, чем нужно для такого количества подгонок. Для параметра PCA было задано значение True для моделей, которые допускали его использование в своих конвейерах.

Наконец, функция mlOptimizer.optimizeModel() сохраняет модель с наилучшей точностью теста в словарь, который будет вызываться позже для построения графиков и прогнозов.

Примечание. Для этих целей я использовал MacBook Pro i7 с тактовой частотой 3,1 ГГц и 16 ГБ ОЗУ на MacOS Sierra. Общее время подгонки составило около 35 минут.

6. Ранжирование моделей

mlOptimizer.view() возвращает результаты «лучшего классификатора» из приведенной выше оптимизации. Эти результаты сортируются по тестовому баллу, который является мерой точности классификации. В данном контексте это означает: для модели с тестовой оценкой 0,55 модель правильно предсказала, выиграет ли команда игру с точностью 55%.

7. Прогнозирование игр

Я разделил это на получение игр для любой конкретной недели/сезона, а затем использовал 5 лучших моделей классификации результатов для прогнозирования игр на эту неделю и возвращал фрейм данных с этими данными. Я также включил столбец агрегированных данных, чтобы увидеть, служит ли он лучшим предсказателем. Мне еще предстоит написать функцию для сохранения результатов в БД и оценки точности предсказания после того, как игры сыграны, но это в моем списке дел.

Я открыт для предложений о том, как лучше отобразить это, в данный момент я просто использую модифицированную тепловую карту Seaborn. Команды перечислены в порядке игры. Интересно, что поскольку прогнозы вычисляются независимо для каждой команды, во многих случаях модели предсказывают, что обе команды, играющие друг с другом, выиграют, что, очевидно, невозможно. Что-то думать о.

Далее будет анализ результатов после завершения всех игр первой недели.