Task1_of_summer_practice/README.md
2026-06-30 09:54:59 +03:00

157 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Летняя практика — Турнирные таблицы КХЛ
Проект анализирует результаты матчей регулярного чемпионата КХЛ за сезоны
**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. Установка и запуск
```bash
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. Считает голы в основное время (сумма трёх периодов).
2. Определяет **тип исхода** каждого матча сравнением столбцов:
победа в основное время / в овертайме / по буллитам — и аналогично поражения.
Победителю по буллитам добавляется ровно 1 решающая шайба.
3. Отдельно обрабатывает **технические результаты** (`+ — -` / `- — +`):
засчитывает их как победу/поражение в основное время, но шайбы не начисляет (0:0).
4. **«Разворачивает» матч в две строки** — взгляд хозяев и взгляд гостей —
и склеивает их (`pd.concat`). Теперь у каждой команды по строке на матч.
5. `groupby('Команда').sum()` суммирует все показатели по командам.
6. Считает производные показатели:
* **И** — игры, **О** — очки (победа = 2, поражение в ОТ/буллитах = 1),
* **Р** — разница шайб, **%О** — процент набранных очков.
* `%О` считается **в целых числах** (`* 10000 // (2*И) / 100`) с отбрасыванием
знаков, как на сайте КХЛ, — без округления и без ошибок float (57.00 не съезжает в 56.99).
7. Сортирует по регламенту КХЛ: `%ОВВО → ВБ → Р → ГЗ`.
**Шаг 3. `show_table` и `main`** — печатают полную таблицу, затем отдельно
конференции Запад и Восток (фильтр по столбцу `Конф`).
### Обозначения столбцов
`И` — игры · `В` — победы в основное время · `ВО` — победы в овертайме ·
`ВБ` — победы по буллитам · `ПБ` — поражения по буллитам · `ПО` — поражения в овертайме ·
`П` — поражения в основное время · `ГЗ` — голы забитые · `ГП` — голы пропущенные ·
`Р` — разница · `О` — очки · `%О` — процент очков.
---
## 4. Дополнительные файлы
### `divisions.py` — дивизионы и посев
В части сезонов КХЛ (2018/192020/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` поднимает победителей дивизионов на места 12;
* выводит таблицы конференций с дополнительным столбцом `Див`.
### `3.py` — график разницы шайб
Задание №3: строит **график** разницы заброшенных и пропущенных шайб одной команды
по датам матчей. Считает голы в каждом матче (`match_goals`, та же логика подсчёта,
что в `main.py`, включая зануление технических результатов), разносит матч на взгляд
хозяев и гостей, оставляет нужную команду, рисует линию «забито пропущено» по дате
и сохраняет картинку `diff_<команда>.png`.
---
## 5. Материал к защите
**О чём проект.** По «сырым» результатам матчей КХЛ автоматически строится
официальная турнирная таблица, таблицы с дивизионами и график. Цель — освоить
обработку табличных данных в pandas и визуализацию в matplotlib.
**Ключевые идеи, которые стоит назвать на защите:**
1. **Векторизация вместо циклов.** Все расчёты — операции над столбцами целиком
(сложение, сравнение, маски `True/False`). Это и быстрее, и короче, чем `for` по строкам.
2. **Приём «одна строка матча → две строки команд».** Чтобы посчитать статистику
команды, каждый матч дублируется: одна запись со стороны хозяев, другая — гостей.
После этого `groupby` сводит всё в таблицу команд.
3. **Булевы маски.** Тип исхода (победа/поражение и как именно) — это столбцы `True/False`,
которые переводятся в `1/0` через `.astype(int)` и суммируются.
4. **Точное соответствие регламенту КХЛ.** Система очков (2/1/0), добавление шайбы
за буллиты, технические результаты, целочисленный (без округления) процент очков,
порядок критериев сортировки, посев победителей дивизионов.
5. **Переиспользование кода.** `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`).