| khl_3 | ||
| khl_3_win | ||
| .gitignore | ||
| 3.py | ||
| individual_1.py | ||
| individual_4.py | ||
| individual_5.py | ||
| main.py | ||
| new_main.py | ||
| README.md | ||
| РАЗБОР_КОДА.md | ||
Летняя практика — Турнирные таблицы КХЛ
Проект анализирует результаты матчей регулярного чемпионата КХЛ за сезоны 2018/19 – 2021/22 и строит по ним турнирные таблицы и график. Основные инструменты — библиотека pandas (работа с таблицами) и matplotlib (график).
1. Структура проекта
| Файл / папка | Назначение |
|---|---|
main.py |
Основная программа: строит полную турнирную таблицу чемпионата и таблицы по конференциям (Запад / Восток). |
divisions.py |
Отдельный модуль: добавляет деление на дивизионы и правило посева победителей дивизионов. Логику расчёта берёт из main.py, сам main.py не меняет. |
3.py |
Задание №3: график разницы заброшенных и пропущенных шайб одной команды по ходу сезона. |
khl_3/ |
Исходные данные — CSV-файлы матчей (4 сезона, кодировка UTF-8). |
Формат исходных данных (CSV)
,Номер,Дата,Команда_1,Команда_2,Период_1,Период_2,Период_3,Овертайм,Буллиты
0,1,2018-09-01,Ак Барс,СКА,0:1,1:2,0:3,:,:
Команда_1— хозяева,Команда_2— гости.Период_1..3,Овертайм,Буллиты— счёт в форматехозяева:гости.- Пустой
:означает, что период не игрался (нет овертайма/буллитов). - Технические результаты записаны знаками:
+ — -(техпобеда хозяев) и- — +(техпобеда гостей). Встречаются в сезоне 2020/21.
2. Установка и запуск
pip install pandas numpy matplotlib
# Полная турнирная таблица + таблицы по конференциям
python3 main.py khl_3/khl_2018_19.csv
# Таблицы по конференциям с дивизионами и посевом победителей дивизионов
python3 divisions.py khl_3/khl_2020_21.csv
# График разницы шайб одной команды по датам (сохраняется в diff_<команда>.png)
python3 3.py khl_3/khl_2018_19.csv "ЦСКА"
Имя файла важно: программы достают код сезона (
2018_19) из имениkhl_2018_19.csv, чтобы понять, какие команды в какой конференции (и дивизионе) играли.
3. Как работает main.py (ядро проекта)
Логика построена на векторных операциях pandas: вычисления делаются сразу над целым столбцом, без циклов по строкам.
Шаг 1. parse_score(df, col) — разбирает строку счёта "3:1" на два числа.
str.split(':', expand=True) раскладывает столбец в два, to_numeric(..., errors='coerce')
превращает текст в числа, а пустой период (:) или знаки техрезультата через
fillna(0) считаются как 0.
Шаг 2. build_standings(df, conf_map) — превращает список матчей в таблицу команд:
- Считает голы в основное время (сумма трёх периодов).
- Определяет тип исхода каждого матча сравнением столбцов: победа в основное время / в овертайме / по буллитам — и аналогично поражения. Победителю по буллитам добавляется ровно 1 решающая шайба.
- Отдельно обрабатывает технические результаты (
+ — -/- — +): засчитывает их как победу/поражение в основное время, но шайбы не начисляет (0:0). - «Разворачивает» матч в две строки — взгляд хозяев и взгляд гостей —
и склеивает их (
pd.concat). Теперь у каждой команды по строке на матч. groupby('Команда').sum()суммирует все показатели по командам.- Считает производные показатели:
- И — игры, О — очки (победа = 2, поражение в ОТ/буллитах = 1),
- Р — разница шайб, %О — процент набранных очков.
%Осчитается в целых числах (* 10000 // (2*И) / 100) с отбрасыванием знаков, как на сайте КХЛ, — без округления и без ошибок float (57.00 не съезжает в 56.99).
- Сортирует по регламенту КХЛ:
%О → В → ВО → ВБ → Р → ГЗ.
Шаг 3. show_table и main — печатают полную таблицу, затем отдельно
конференции Запад и Восток (фильтр по столбцу Конф).
Обозначения столбцов
И — игры · В — победы в основное время · ВО — победы в овертайме ·
ВБ — победы по буллитам · ПБ — поражения по буллитам · ПО — поражения в овертайме ·
П — поражения в основное время · ГЗ — голы забитые · ГП — голы пропущенные ·
Р — разница · О — очки · %О — процент очков.
4. Дополнительные файлы
divisions.py — дивизионы и посев
В части сезонов КХЛ (2018/19–2020/21) действовало правило: победители двух дивизионов получают места 1 и 2 в конференции, даже если по очкам они не в топ-2. Например, в 2020/21 на Западе СКА (82 очка) стоит выше Динамо М (84) и Локомотива (83) — СКА выиграл дивизион Боброва. В сезоне 2021/22 это правило отменили (чистый порядок по %О).
divisions.py:
- переиспользует
build_standingsиCONFERENCESизmain.py(не дублируя логику и не изменяяmain.py); - словарь
DIVISIONSзадаёт состав четырёх дивизионов (Боброва, Тарасова — Запад; Харламова, Чернышёва — Восток) по каждому сезону; SEED_BY_DIVISIONвключает посев только там, где он применялся;seed_conferenceподнимает победителей дивизионов на места 1–2;- выводит таблицы конференций с дополнительным столбцом
Див.
3.py — график разницы шайб
Задание №3: строит график разницы заброшенных и пропущенных шайб одной команды
по датам матчей. Считает голы в каждом матче (match_goals, та же логика подсчёта,
что в main.py, включая зануление технических результатов), разносит матч на взгляд
хозяев и гостей, оставляет нужную команду, рисует линию «забито − пропущено» по дате
и сохраняет картинку diff_<команда>.png.
5. Материал к защите
О чём проект. По «сырым» результатам матчей КХЛ автоматически строится официальная турнирная таблица, таблицы с дивизионами и график. Цель — освоить обработку табличных данных в pandas и визуализацию в matplotlib.
Ключевые идеи, которые стоит назвать на защите:
- Векторизация вместо циклов. Все расчёты — операции над столбцами целиком
(сложение, сравнение, маски
True/False). Это и быстрее, и короче, чемforпо строкам. - Приём «одна строка матча → две строки команд». Чтобы посчитать статистику
команды, каждый матч дублируется: одна запись со стороны хозяев, другая — гостей.
После этого
groupbyсводит всё в таблицу команд. - Булевы маски. Тип исхода (победа/поражение и как именно) — это столбцы
True/False, которые переводятся в1/0через.astype(int)и суммируются. - Точное соответствие регламенту КХЛ. Система очков (2/1/0), добавление шайбы за буллиты, технические результаты, целочисленный (без округления) процент очков, порядок критериев сортировки, посев победителей дивизионов.
- Переиспользование кода.
divisions.pyи3.pyопираются на логику изmain.py, чтобы не дублировать разбор счёта и расчёт таблицы.
Возможные вопросы и ответы:
- Почему пустой период = 0:0? — Овертайм/буллиты есть не во всех матчах;
fillna(0)делает расчёт единообразным. - Почему %О считается в целых числах, а не через
round? — Сайт КХЛ отбрасывает знаки после второго (а не округляет), и целочисленная арифметика не даёт ошибок float (57.00 вместо 56.99...). - Как обрабатываются технические результаты? —
+ — -/- — +засчитываются как победа/поражение в основное время, но без шайб (0:0), как в КХЛ. - Почему дивизионы в отдельном файле? — чтобы не усложнять
main.py;divisions.pyпереиспользует его функции, ничего в нём не меняя. - Как добавить новый сезон? — добавить CSV в
khl_3/, описать конференции вCONFERENCES(вmain.py) и при необходимости дивизионы вDIVISIONS(вdivisions.py).