Compare commits

..

7 Commits

Author SHA1 Message Date
Dmitry Belan e00320edb1 update: update task 7
CI Check / lint-and-check (push) Failing after 9s
2026-07-14 17:28:57 +03:00
Dmitry Belan 9b003b95d4 feat: add REAMDE.md
CI Check / lint-and-check (push) Successful in 9s
2026-07-14 16:55:44 +03:00
Dmitry Belan 9738df1cd0 fix: cz
CI Check / lint-and-check (push) Successful in 10s
2026-07-14 16:45:25 +03:00
Dmitry Belan 8b3580f04b fix: rename workflow folder
CI Check / lint-and-check (push) Failing after 4m33s
2026-07-14 16:37:01 +03:00
Dmitry Belan 4cdd002829 trigger CI 2026-07-14 16:36:09 +03:00
Dmitry Belan 9619f92a1b feat: add .pre-commit-config.yaml 2026-07-14 13:05:21 +03:00
Dmitry Belan 658adce5c6 feat: add pre_commit pip 2026-07-14 13:04:13 +03:00
5 changed files with 91 additions and 32 deletions
@@ -31,4 +31,4 @@ jobs:
- name: Check Commit Convention
# Проверка всех новых коммитов в PR или последней пуш-сессии
run: cz check --rev-range origin/main..HEAD
run: cz check --rev-range HEAD~1..HEAD
+7
View File
@@ -0,0 +1,7 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.0
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
+34 -23
View File
@@ -1,5 +1,7 @@
Ограничение по времени: 3.0 с
Ограничение по памяти: 512 МБ
### Последняя Надежда Эпсилон-9: Протокол «К-Резонанс»
**Ограничение по времени:** 3.0 с
**Ограничение по памяти:** 512 МБ
Год 2142. Межзвездная колония на планете Эпсилон-9 столкнулась с невидимой смертью. Внешне безобидная флора планеты скрывает фатальную угрозу: питательный, спасающий от голода «Звездный Корень» и парализующая нервную систему «Теневая Лоза» визуально абсолютно неразличимы. Их выдают только биоэлектрические поля, которые сканируют наши харвестеры.
@@ -7,46 +9,55 @@
Командор колонии Лира врывается в ваш инженерный отсек. В её руках дымящийся кристалл памяти.
— Инженер! — кричит она, смахивая пепел с терминала. — Я знаю, ты привык поднимать надежный бэкенд и обучать сложные модели, но сейчас от твоих навыков зависят наши жизни! Я вытащила из мертвых архивов концепты древнего алгоритма K-Ближайших Соседей. Мы должны воссоздать его с нуля, и нам нужна строгая архитектура, чтобы система не рухнула. Будем писать объектно-ориентированно. Слушай меня внимательно, я зачитаю спецификацию протокола прямо с поврежденных секторов, а ты переноси это в код!
— Инженер! — кричит она, смахивая пепел с терминала. — Я вытащила из мертвых архивов чертежи древнего алгоритма K-Ближайших Соседей. Мы должны воссоздать его с нуля, иначе завтра колония вымрет. И нам нужна строгая архитектура, чтобы система не рухнула. Будем писать объектно-ориентированно. Слушай меня внимательно, я зачитаю спецификацию протокола прямо с поврежденных секторов, а ты пиши код!
Лира подключает кристалл к вашему монитору, и аварийное освещение окрашивает отсек в красный цвет.
— Разделим логику выживания на модули, — диктует Командор, глядя на бегущие строки. — Сначала создай класс `DataProcessor`. Харвестеры присылают нам сплошной текстовый мусор. Напиши в нем метод `parse_sensor_data(self, record)`. Он должен принимать сырую строку, где числа и класс разделены запятыми, и возвращать кортеж. Первым элементом в нем пойдет список чисел с плавающей точкой — сырые признаки. Вторым — строка класса растения.
— Разделим логику выживания на модули, — диктует Командор, глядя на бегущие строки. — Для начала создай класс `DataProcessor`, он будет отвечать за очистку. Харвестеры присылают нам сплошной текстовый мусор. В этом классе тебе нужно написать первый метод `parse_sensor_data(self, record)`. Он должен принимать сырую строку, где числа и класс разделены запятыми, и возвращать кортеж. Первым элементом в нем пойдет список чисел с плавающей точкой — это наши сырые признаки. Вторым — строка класса растения.
Она нервно стучит по экрану:
— Данные с сенсоров скачут! Чтобы алгоритм не сошел с ума от разницы в масштабах измерений, нужна калибровка. Добавь метод `calculate_statistics(self, dataset)`. Прогони через него размеченные данные и вычисли для каждого признака среднее арифметическое и стандартное отклонение. Верни это как список словарей с ключами `"mean"` и `"std"`. И помни, корень придется извлекать возведением в степень `0.5`, математических модулей у нас нет!
— Данные с сенсоров скачут! Чтобы алгоритм не сошел с ума от разницы в масштабах измерений, нам нужна калибровка. В этот же класс добавь метод `calculate_statistics(self, dataset)`. Прогони через него размеченные данные и вычисли для каждого признака среднее арифметическое и стандартное отклонение. Верни это как список словарей с ключами `"mean"` и `"std"`. И помни, корень придется извлекать возведением в степень `0.5`, у нас нет математических модулей!
— Как только получим статистическую базу, — продолжает Лира, — пиши метод `normalize_features(self, features, stats)`. Каждый сырой признак растения нужно очистить от шума, вычтя среднее и разделив на стандартное отклонение. Верни новый список идеальных, нормализованных чисел.
— Как только получим статистическую базу, — продолжает Лира, — пиши там же метод `normalize_features(self, features, stats)`. Каждый сырой признак растения нужно очистить от шума, вычтя среднее и разделив на стандартное отклонение. Этот метод должен брать список признаков и словарь статистики, а возвращать новый список идеальных, нормализованных чисел.
Свет в отсеке мигает. Система охлаждения воет на пределе возможностей.
— Теперь архитектура самого предсказателя! Создай класс `KNNClassifier`. При инициализации через `__init__(self, k)` он должен принимать и сохранять внутри себя количество соседей `k`.
Затем заложи в него геометрию выживания — метод `euclidean_distance(self, vector_a, vector_b)`. Он берет два нормализованных списка чисел и вычисляет дистанцию между ними в многомерном пространстве, возвращая одно число с плавающей точкой.
— Теперь самое главное — архитектура ядра! Создай класс `KNNClassifier`. При инициализации через `__init__(self, k)` он должен принимать и сохранять внутри себя количество соседей `k`. Затем заложи в него геометрию выживания — метод `euclidean_distance(self, vector_a, vector_b)`. Он должен брать два нормализованных списка чисел и вычислять дистанцию между ними в многомерном пространстве. Просто верни одно число с плавающей точкой.
Лира выводит на экран голограмму базы данных:
— Систему нужно обучить. Напиши метод `fit(self, train_features, train_labels)`, который просто сохранит нормализованную обучающую выборку и её классы внутри объекта. А чтобы найти сородичей, добавь метод `find_k_nearest(self, test_point)`. Он должен прочесать сохраненную базу `train_features` и найти `k` самых близких соседей для неизвестного растения, вернув список их классов-строк.
— Систему нужно обучить. Напиши метод `fit(self, train_features, train_labels)`, который просто сохранит нормализованную обучающую выборку и её классы внутри объекта классификатора. А чтобы найти сородичей, добавь метод `find_k_nearest(self, test_point)`. Он должен прочесать сохраненную базу и найти `k` самых близких соседей для неизвестного растения `test_point`. От тебя требуется вернуть только список их классов-строк.
— Но соседи могут расходиться во мнениях, — Лира хмурится. — Нам нужна логика большинства. Метод `majority_vote(self, neighbors)` примет этот список классов и вернет тот, который встречается чаще всего. Если будет ничья — возвращай любой из лидирующих классов.
— Но соседи могут расходиться во мнениях, — Лира хмурится. — Нам нужна логика большинства. Метод `majority_vote(self, neighbors)` в этом же классе примет этот список и вернет тот класс, который встречается чаще всего. Если будет ничья — система должна выжить, просто возвращай любой из лидирующих классов. Это и будет наш приговор.
Она тяжело вздыхает, опираясь на стол:
— Оберни этот поиск и голосование в единый боевой интерфейс `predict_class(self, test_point)`. Этот метод примет одно неизвестное нормализованное растение и прогонит его через поиск соседей и голосование, чтобы сразу выдать итоговый класс-строку.
А для массовой проверки на архивах добавь метод `calculate_accuracy(self, predictions, true_labels)`. Сравни списки наших предсказаний с истинными классами и верни долю правильных ответов от `0.0` до `1.0`. Цена каждой ошибки — чья-то жизнь.
— Оберни этот поиск и голосование в единый боевой интерфейс `predict_class(self, test_point)`. Ему мы будем скармливать одно неизвестное нормализованное растение, чтобы он сам вызвал поиск соседей, провел голосование и сразу выдал итоговый класс-строку.
— Но прежде чем отправить харвестеры в поля и кормить людей, — голос Лиры дрожит, — мы обязаны проверить алгоритм на архивах. Создай отдельный класс `AccuracyCalculator`. В нем будет всего один метод `calculate(self, predictions, true_labels)`. Сравни списки наших предсказаний с истинными классами на тестовом полигоне и верни долю правильных ответов от `0.0` до `1.0`. Цена каждой ошибки — чья-то жизнь.
Лира кладет руку вам на плечо. В её глазах отражается код аварийного терминала:
— И наконец, Инженер... Великий Синтез. Снаружи классов напиши финальную функцию `run_protocol(train_raw_lines, test_raw_lines, k)`. Она объединит весь пайплайн. Создай экземпляры `DataProcessor` и `KNNClassifier`. Распарси обе выборки. Затем вычисли статистику строго и только по обучающей базе, чтобы не было утечки данных из будущего. Нормализуй обе выборки. Скорми обучающие данные в метод `fit`. Пройдись циклом по тестовым растениям, собирая предсказания через `predict_class`, и рассчитай точность. В самом конце функция должна вернуть словарь с двумя ключами: `"accuracy"` с итоговой точностью и `"predictions"` со списком всех предсказанных классов.
— И наконец, Инженер... Великий Синтез. Вне классов напиши финальную функцию `run_protocol(train_raw_lines, test_raw_lines, k)`. Она должна объединить весь пайплайн воедино. Создай экземпляры `DataProcessor`, `KNNClassifier` и `AccuracyCalculator`. Сначала распарси обе выборки. Затем вычисли статистику строго и только по обучающей базе, чтобы не было утечки данных из будущего. Потом нормализуй обе выборки. Скорми обучающие данные в метод `fit`. Пройдись циклом и сделай предсказания для каждого растения в тесте. В самом конце функция должна рассчитать точность и вернуть словарь с двумя ключами: `"accuracy"` с итоговой точностью и `"predictions"` со списком всех предсказанных классов.
Терминал призывно мигает пустым курсором. Система охлаждения реактора издает последний предупреждающий гудок. Жизнь Эпсилон-9 зависит от чистоты твоей архитектуры. Приступайте.
Терминал призывно мигает пустым курсором. Система охлаждения реактора издает последний предупреждающий гудок. Жизнь Эпсилон-9 зависит от чистоты твоей архитектуры. Приступай.
---
### Блок тестирования протокола (Чек-лист от Командора)
### Блок тестирования: Симуляция запуска на архивных данных
Лира выводит на соседний экран строгую последовательность проверки модулей.
Как только напишешь классы, прогони систему через этот алгоритм запуска. Никаких отклонений!
Лира выводит на соседний голографический экран небольшую выборку исторических данных.
Инженер, мы не можем рисковать. Прежде чем подключать твой код напрямую к харвестерам, запусти симуляцию на этом крошечном наборе. Если твой «Синтез» работает верно, мы спасены.
1. **Запросите справку из архивов:** Вызовите документацию (`help()`) по классам `DataProcessor` или `KNNClassifier`, чтобы убедиться, что сектора памяти целы и спецификация ясна.
2. **Создайте объекты спасения:** Инициализируйте экземпляры классов `DataProcessor` и `KNNClassifier` (задайте нужное число соседей `k`).
3. **Откалибруйте систему:** Используя объект класса `DataProcessor`, обработайте сырые данные (рассчитайте статистику и нормализуйте базу).
4. **Попробуйте классифицировать:** Попробуйте прогнать через систему неизвестное растение (`predict_class`), чтобы проверить отклик пустой базы.
5. **Завершите обучение:** Если алгоритм еще не готов к бою (выдает ошибку или пустой ответ из-за отсутствия базы), загрузите в него нормализованную обучающую выборку (вызовите метод `fit`).
6. **Соберите "урожай":** Как только модель обучена, запустите финальное сканирование тестовой базы, классифицируйте все растения и выведите результат предсказаний.
**Требования к проверке:**
1. Запишите в код следующие архивные данные:
```python
train_raw = [
"0.5, 1.2, Звездный Корень",
"0.6, 1.3, Звездный Корень",
"5.1, 8.2, Теневая Лоза",
"4.9, 8.1, Теневая Лоза"
]
test_raw = [
"0.55, 1.25, Звездный Корень",
"5.0, 8.15, Теневая Лоза"
]
+47
View File
@@ -0,0 +1,47 @@
# Контрольные работы: Миха
Добро пожаловать в рабочее пространство для выполнения контрольных работ. В этом репозитории мы учимся писать чистый, качественный и работающий код, используя современные инструменты разработки.
## 🛠 Технологический стек
* **Язык**: Python
* **Автоматизация (CI)**: Gitea Actions
* **Контроль качества**: Ruff (линтер)
* **Стандарты коммитов**: Commitizen
## 📋 Статус проверок
[![Gitea Actions Status](https://gitea.dimong.ru/Dimong4/miha-kr/actions/workflows/ci.yaml/badge.svg)](https://gitea.dimong.ru/Dimong4/miha-kr/actions)
---
## 🚀 Как работать с этим репозиторием
### 1. Подготовка окружения
Перед началом работы убедись, что у тебя установлены:
* **Git** — для управления версиями.
* **Python 3.x** — для написания кода.
* **pip** — для установки зависимостей.
### 2. Установка зависимостей
Если твое решение требует дополнительных библиотек:
1. Создай файл `requirements.txt` в корне проекта.
2. Установи зависимости командой: `pip install -r requirements.txt`.
3. Обязательно добавь все используемые библиотеки в `requirements.txt`, чтобы они корректно работали в среде автоматической проверки.
### 3. Рабочий процесс (Workflow)
1. **Создай новую ветку** для своей работы: `git checkout -b task-name`.
2. **Пиши код** и проверяй его локально.
3. **Сделай коммит**, соблюдая правила (Commitizen): `git commit -m "feat: добавил решение задачи №1"`.
4. **Отправь изменения** в репозиторий: `git push origin task-name`.
### 4. Проверка и сдача
* После `push` перейди на страницу репозитория во вкладку **Actions**.
* Если горит **зеленая галочка ✅** — работа прошла автоматический контроль качества.
* Если **красный крестик ❌** — открой логи задачи, исправь замечания линтера и запушь исправления.
* После успеха создай **Pull Request** из своей ветки в `main` для финальной проверки.
---
## 🎓 Правила
* **Чистота кода**: Игнорирование предупреждений линтера `Ruff` недопустимо.
* **Ветка main**: Прямые пуши в `main` запрещены. Ветка защищена правилами CI/CD.
* **Ответственность**: Ты несешь ответственность за свой код и его работоспособность в CI-среде.
+2 -8
View File
@@ -1,10 +1,4 @@
ruff
commitizen
flake8==7.1.1
flake8-absolute-import==1.0.0.2
flake8-commas==4.0.0
flake8-import-order==0.18.2
flake8-print==5.0.0
flake8-quotes==3.4.0
parameterized==0.9.0
pep8-naming==0.14.1
parameterized
pre_commit