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

В этой статье я хочу рассказать про то как можно увидеть определенные паттерны в событиях, на первый взгляд кажущимися хаотичными. Собрав небольшое количество данных, после и подготовки и визуализации можно не найти каких-либо интересных результатов поведения исследуемых систем. Но чем шире становится выборка, по мере увеличения набора данных, визуализация может приобретать заметные поведенческие особенности системы, которые можно описать словами, и которые дадут вам некоторое понимание работы системы. C другой стороны, когда у вам очень много данных, отображение всех событий сразу тоже может не дать понимания, поэтому данные придется агрегировать. Для иллюстрации такого примера в этой статье рассмотрим футбольные пасы.

Футбол, наверное, самый популярный спорт в мире. Я не увлекаюсь футболом, но мне всегда было интересно посмотреть базовые паттерны этой игры, исследуя большое количество данных в разных матчах. То есть, интересно было построить некую усредненную картину футбола. Надо отметить, что для футбола есть свои правила игры, поэтому паттерны игры должны существовать.

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

Один раз я случайно наткнулся на 2 статьи:

Football Winds Map
Advanced sports visualization with Python, Matplotlib and Seaborn

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

Вообще, описание хаотичных, на первых взгляд, систем известными физическими уравнениями для газа или жидкости практикуется, например, в анализе транспортных потоков, где транспортные потоки описываются уравнениями Навье-Стокса для Ньютоновской жидкости (Статья Traffic Management Model). Поэтому визуализация футбольных пасов в виде карты ветров тоже достаточно интересна, и мне интересно стало сделать что-то подобное в Tableau.

1. Сбор и преобразование данных

Данные о действиях на поле во время матчей собраны StatsBomb – часть из них есть в открытом доступе на GitHub. Данные представлены в виде 890 JSON файлов, каждый файл содержит данные одного матча. Данные содержат информацию о следующих лигах/кубках:

— Champion League 1999
— 2019 — FA Women’s Super League 2018
— 2020 — FIFA World Cup 2018
— La Liga 2004 — 2020
— NWSL 2018
— Premier League 2003 — 2004
— Women’s World Cup 2019

 

Tableau может читать JSON, но не 890 файлов сразу, поэтому далее преобразуем все 890 JSON файлов в 1 CSV файл. Предварительно нужно скачать zip архив с GitHub и распаковать все 890 файлов в локальную директорию. Скрипт ниже читает все JSON файлы в указанной папке на локальном компьютере и преобразует каждый файл в CSV файл.

import json
import pandas as pd
from pandas.io.json import json_normalize
import os

#set working directory
path="C:\Docs\Tableau\SportsVizSunday\Foolball 2018\open-data-master\data\matches"

for filename in os.listdir(path):
    if filename.endswith(".json"):
        bb=os.path.join(path, filename)
        print(bb)
        with open(bb, encoding="utf8") as data_file:
            data = json.load(data_file)
        df = json_normalize(data, sep="_")

        a = df.to_csv(path + filename + '.csv', encoding="utf8", index=None)

        df1 = pd.read_csv(path + filename + '.csv')
        df1.to_csv(path + filename + '.csv', index=False)

        continue
    else:
        continue

После завершения работы этого скрипта вы получите 890 .csv файлов в указанной в скрипте директории. Далее склеим все файлы в 1 .csv. Следующий скрипт делает UNION всех файлов в указанной папке и сохраняет их как один CSV файл:

import os
import glob
import pandas as pd
#set working directory
os.chdir('C:/Docs/Tableau/SportsVizSunday/Foolball 2018/open-data-master/data')

#find all csv files in the folder
#use glob pattern matching -> extension = 'csv'
#save result in list -> all_filenames
extension = 'csv'
all_filenames = [i for i in glob.glob('*.{}'.format(extension))]
#print(all_filenames)

#combine all files in the list
combined_csv = pd.concat([pd.read_csv(f) for f in all_filenames ])
#export to csv
combined_csv.to_csv( "combined_ccs.csv", index=False, encoding='utf-8-sig')

Теперь у нас есть один общий CSV файл, содержащий информацию о событиях в каждом из 890 матчей. Дальнейшую очистку данных и удаление ненужных полей я сделал в Tableau Prep. В данных осталась только информация о пасах. Координаты точек пасов в конечном датасете определяются точками начала и конца паса на декартовой системе координат, и их можно отобразить на футбольном поле. Для различных футбольных матчей размеры поля могут отличаться; в исходных данных такие отклонения были компенсированы так, чтобы каждый матч можно было отобразить на поле со следующими координатами:

В самом датасете данные всех координат игровых событий подготовлены так, как будто для любой команды правая сторона поля — это сторона противника.

2. Оценка данных при помощи Tableau

Tableau идеально подходит для быстрого анализа, поэтому попробуем просто отобразить все пасы при помощи линий и оценить их количество, Подключим полученный CSV файл к Tableau и отобразим точки начал и концов пасов. Точки начала:

Точки конца:

Получились картинки из которых ничего непонятно, поскольку количество точек на каждой немногим меньше 900 000 штук, а это почти миллион. Для построения линий пасов сделаем UNION в Tableau:

Таблица Output_football_all.csv будет отвечать за координаты начала пасов, а Output_football_all.csv1 будет отрисовывать координаты концов пасов. Если соединить все точки, то есть, каждый пас представить линией, получим на уровне прозрачности 1% следующее:

Id в грануляции здесь – это идентификатор паса. То есть Tableau на минимальном уровне прозрачности рисует около 890 000 линий, и все они сливаются в один синий прямоугольник — это нам тоже ничего не дает. Но мы можем понять что в одном матче, в среднем, проводится примерно 1000 пасов, то есть, каждая команда выполняет около 500 пасов. Это примерно соответствует официальной футбольной статистике.

Вычисления XXX и YYY выглядят следующим образом:

XXX

CASE RIGHT([Table Name],1)
WHEN ‘1’ THEN [X0] ELSE [X1]
END

YYY

CASE RIGHT([Table Name],1)
WHEN ‘1’ THEN [Y0]
ELSE [Y1]
END

3. Агрегация данных

Эта картина нам ни о чем не говорит, потому что здесь около 890 000 линий, и все они накладываются друг на друга. Поэтому следующим шагом я решил сгруппировать линии по началу старта, округлив X0 и Y0:

X0

ROUND(FLOAT(MID(SPLIT([Location],’,’,1),2,10)))

Y0

ROUND(FLOAT(SPLIT(SPLIT([Location],’,’,2),’]’,1)))

Если расположить округленные координаты на футбольном поле, получим следующее:

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

COUNT { FIXED [X0],[Y0]: SUM(1)} / 2

То есть, вычислениями с округлениями мы разбили футбольное поле на квадраты со стороной 1 метр (примерно), и далее будем визуализировать пасы из каждого квадрата. 2 в знаменателе нам нужно для того, чтобы вернуть верное кол-во пасов, поскольку данные были увеличены в 2 раза операцией UNION. Для каждого такого квадрата усредним координаты конца паса:

XXX

CASE RIGHT([Table Name],1)
WHEN ‘1’ THEN [X0]
ELSE { FIXED [X0], [Y0], [Table Name]: AVG([X1])}
END

YYY
CASE RIGHT([Table Name],1)
WHEN ‘1’ THEN [Y0]
ELSE { FIXED [X0], [Y0], [Table Name]: AVG([Y1])}
END

То есть, усредняя координаты конца паса, мы все пасы с одного квадратного метра заменяем только одной линией — это сильно уменьшает общее количество линий на визуализации. Так мы избавляемся от проблемы перекрытия большим количеством линий друг друга. Получается такая картина:

Направления пасов показываем добавлением Table Name в Size, получая утолщение линии в конце паса. Так создается ощущение летящего мяча.

И конечный виз в Tableau:

Клик для перехода

В этом визе специально низкое количество пасов отмечается черным цветом, чтобы на темном фоне такие линии, как несущественные, были практически не видны. Если поменять палитру, усилив линии с низким количеством пасов, то получим:

Интересно построить динамическую картину пасов, начиная с одного матча, и на каждом следующем шаге добавляя пасы другого матча. Такая динамическая картина как раз показывает переход от кажущегося хаоса на малом количестве данных к упорядочению линий на большом количестве данных:

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

Для пасов одного матча вообще непонятно что происходит на поле, практически невозможно выделить приоритетные направления пасов:

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

Для 889 матчей можно видеть приоритетные направления пасов на каждом участке поля:

Надо отметить что после 300 матчей картина сильно не меняется.

Заключение

Данные, которые мы визуализировали, включают информацию о пасах в различных видах соревнований, игры различных лиг, женский и мужской футбол. Мы получили общую усредненную картину, которая может дать понимание того, как в футболе проходит атака. На сайте Reddit в сообществе r/dataisbeautiful этот виз прокомментировали 600 раз, виз собрал более 35000 upvotes, каждый нашел свои инсайты в этой визуализации. 

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

Также выше мы могли убедиться, что небольшое количество данных и слишком большое количество точек не работают на визуализации, а работает некоторое среднее количество.