# Домашнє завдання · NumPy для ML

> Лекція: [lecture.html](lecture.html) · Практика: [practice.ipynb](practice.ipynb) · Тест: [quiz.html](quiz.html)

Усе робиться на своїх даних — не на дошці оголошень із лекції. Візьми будь-яку числову
таблицю, яка тобі цікава: витрати за місяць, результати матчів, характеристики ноутбуків
із маркетплейсу, показники погоди. Головне, щоб у ній було **щонайменше три числові
колонки й одна, яку хочеться передбачити**. Якщо таблиці немає — згенеруй її самостійно
через `np.random.default_rng(42)`, як ми робили в практиці.

---

## 🟢 Рівень 1 — База

Зведи свою таблицю до форми, у якій дані приймає будь-яка бібліотека машинного навчання.

1. Склади матрицю ознак `X` через `np.column_stack` і вектор таргета `y`.
   Приведи `X` до `float64`.
2. Виведи `X.shape`, `y.shape`, `X.dtype`, `X.nbytes` і поясни коментарем, що означає
   кожне число у формі.
3. Порахуй `X.mean(axis=0)`, `X.std(axis=0)`, `X.min(axis=0)`, `X.max(axis=0)`
   і виведи їх таблицею: рядок на ознаку.
4. Порахуй `розмах = X.max(axis=0) - X.min(axis=0)` і скажи словами, у скільки разів
   найбільший розмах більший за найменший.

**Зроблено, якщо:** виконується `assert X.ndim == 2 and y.ndim == 1 and X.shape[0] == y.shape[0]`,
таблиця статистик надрукована, а відношення найбільшого розмаху до найменшого виведено числом.

---

## 🟡 Рівень 2 — Плюс

Масштабування й маски на своїх даних.

1. Відмасштабуй `X` двома способами: «мінімум-розмах» (у проміжок 0…1) і стандартизацію
   (середнє 0, розкид 1). Обидва — **одним рядком через транслювання**, без циклів.
2. Доведи `assert np.allclose(...)`, що після першого способу мінімуми стовпців дорівнюють
   нулю, а максимуми — одиниці; після другого — середні нулю, а розкид одиниці.
3. Спробуй навмисно зробити помилку: відніми від `X` результат `X.mean(axis=1)` без
   `keepdims`. Спіймай виняток через `try/except ValueError` і надрукуй текст помилки.
   Потім покажи виправлений варіант і його форму.
4. Побудуй маску, яка ділить рядки на дві групи за якоюсь ознакою (наприклад, «дорожчі
   за медіану»), і порівняй **середні всіх ознак** у двох групах: `X[маска].mean(axis=0)`
   проти `X[~маска].mean(axis=0)`. Знайди ознаку, яка відрізняється найсильніше.

**Зроблено, якщо:** усі `assert` проходять, текст `ValueError` надрукований разом із
виправленням, а найконтрастніша ознака названа й різниця по ній виведена числом.

---

## 🔴 Рівень 3 — Виклик

Поміряй усе сам і зроби висновок про межу застосовності.

1. Напиши функцію `порівняти(розмір)`, яка на масиві з `розмір` елементів міряє
   `time.perf_counter`-ом дві реалізації однієї дії — циклом і векторно — і повертає
   обидва часи. Візьми найкращий час із кількох прогонів.
2. Прогони її на розмірах `1_000, 10_000, 100_000, 1_000_000` і побудуй таблицю:
   розмір, час циклу, час вектора, у скільки разів швидше, скільки памʼяті займає
   список і скільки масив.
3. Дай відповідь на два питання **словами, спираючись на свої числа**:
   * чи росте прискорення нескінченно, чи десь виходить на межу — і чому;
   * з якого приблизно розміру різниця перестає бути «академічною» й починає впливати
     на те, скільки ти чекаєш перед екраном.
4. Додатково: заміряй той самий цикл, але **по масиву**, а не по списку
   (`for значення in масив`). Поясни, чому він виявився повільнішим за цикл по списку.

**Зроблено, якщо:** таблиця з чотирьох рядків надрукована, обидві відповіді написані
своїми словами з посиланням на конкретні заміряні числа, а третій замір (цикл по масиву)
зроблений і пояснений.

---

## Підказки

* Форма — головний діагностичний інструмент теми. Якщо щось поводиться дивно, друкуй
  `.shape` після кожного перетворення: у девʼяти випадках із десяти помилку видно одразу.
* Якщо `assert np.allclose(...)` падає на стандартизації — подивись, чи не має котрась
  ознака нульового розкиду. Ділення на нуль дає `nan`, а `nan` не дорівнює нічому,
  включно із самим собою.
* Заміри часу нестабільні, особливо якщо в цю мить система чимось зайнята. Бери
  найкращий час із кількох прогонів, а не середній, і не роби висновків із різниці
  в кілька відсотків.
