Перенавчання vs Недонавчання - Битва, яку мусить виграти кожен ML-інженер
Кафедра ШІзики
Автор
30 хвилин
Час читання
12.01.2025
Дата публікації
Перенавчання vs Недонавчання: Битва, яку мусить виграти кожен ML-інженер
Ідеальна модель, яка провалилася
Пам’ятаєте, як у Статті 7 ваше дерево рішень досягло 100% точності на тренувальних даних?
Ви, напевно, думали: “Ідеально! Запускаємо!” 🚀
Але потім прийшли тестові дані… 77.5% точності. Дерево, яке здавалося геніальним, насправді було шахраєм — воно запам’ятало відповіді замість того, щоб вивчити закономірності.
Це не просто баг у коді. Це перенавчання (overfitting) — тихий вбивця моделей машинного навчання у продакшені. І зараз це стане дуже реальним для піцерії Мами ML.
🍕 Піцерійна катастрофа: Ранок понеділка
6 ранку понеділка. Марія, власниця піцерії “Мама ML”, перевіряє свою нову “суперточну” модель прогнозування попиту.
Прогноз моделі: 150 піц на обідній пік.
Марія довіряє цифрам. Зрештою, модель мала 98% точності на історичних даних! Вона замовляє додаткове тісто, викликає двох додаткових працівників і готується до напливу клієнтів.
Реальні замовлення до 14:00: 82 піци.
Марія дивиться на 68 незапечених піц — викинуті інгредієнти. Двоє зайвих працівників стоять без діла. $340 збитків за одну обідню зміну.
“Але ж модель була на 98% точною!” — каже вона своєму племіннику-дата-сайєнтисту.
Він зітхає. “На ТРЕНУВАЛЬНИХ даних, тітко. Модель запам’ятала минулі патерни замість того, щоб навчитися передбачати майбутні.”
Це перенавчання. І сьогодні ми його виправимо.
Аналогія зі студентом: Розуміємо проблему
Перш ніж перейти до виправлень, давайте зрозуміємо, що насправді відбувається. Уявіть трьох різних студентів, які готуються до іспиту:
😰 Зубрило (Перенавчання)
- Запам’ятовує кожну відповідь з практичних тестів слово в слово
- Набирає 100% на практичних тестах — ідеально!
- День іспиту: 55% — питання трохи інші, і він панікує
- Проблема: Вивчив відповіді, а не концепції
Це модель піцерії Марії. Вона запам’ятала, що “15 березня 2024 = 147 піц” замість того, щоб навчитися “холодні п’ятниці = високий попит.”
😴 Ледар (Недонавчання)
- Ледве вчиться, запам’ятовує лише “більшість відповідей — В”
- Набирає 50% на практичних тестах — не дуже
- День іспиту: 48% — приблизно те саме
- Проблема: Не вивчив достатньо, щоб відповісти на що-небудь добре
Це була б модель, яка просто прогнозує “100 піц щодня” незалежно від умов.
🎯 Розумний студент (Ідеальний баланс)
- Розуміє концепції та закономірності
- Набирає 85% на практичних тестах — солідно
- День іспиту: 83% — трохи нижче, але стабільно
- Мета: Вивчити патерни, які працюють на нових, невідомих ситуаціях
Модель Марії повинна стати розумним студентом.
🔬 Розслідування катастрофи: Що пішло не так?
Давайте подивимося на реальні дані Марії, щоб зрозуміти проблему.
Дані
import numpy as np
import matplotlib.pyplot as plt
# Історичні дані продажів Марії
np.random.seed(42)
temperatures = np.linspace(5, 35, 30) # Температура в Цельсіях
# Справжній патерн: Холодна погода = більше замовлень, з деякою кривизною
true_sales = 150 - 2 * temperatures + 0.05 * temperatures**2
actual_sales = true_sales + np.random.normal(0, 12, 30) # Реальний шум
print("🌡️ Діапазон температур: 5°C до 35°C")
print(f"🍕 Діапазон продажів: {actual_sales.min():.0f} до {actual_sales.max():.0f} піц")Три різні моделі
Подивімося, що сталося з трьома різними підходами:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline
# Модель 1: Ледар (занадто проста)
model_slacker = make_pipeline(
PolynomialFeatures(degree=1), # Просто пряма лінія
LinearRegression()
)
# Модель 2: Розумний студент (в самий раз)
model_smart = make_pipeline(
PolynomialFeatures(degree=2), # Схоплює криву
LinearRegression()
)
# Модель 3: Зубрило (занадто складна)
model_memorizer = make_pipeline(
PolynomialFeatures(degree=15), # Звивається через кожну точку
LinearRegression()
)
# Тренуємо всі моделі
X = temperatures.reshape(-1, 1)
for model in [model_slacker, model_smart, model_memorizer]:
model.fit(X, actual_sales)Інтерактивна демонстрація: Побачте самі
Використовуйте повзунок нижче, щоб змінити ступінь полінома. Спостерігайте, як модель трансформується від недонавчання до перенавчання:
Polynomial Fitting: Underfit vs Overfit / Поліноміальна апроксимація
🔍 Що ви бачите?
| Ступінь | Що відбувається | Діагноз |
|---|---|---|
| 1-2 | Пряма лінія, пропускає криву | ⚠️ Недонавчання — занадто проста |
| 2-4 | Гарно схоплює патерн | ✅ Хороша модель — в самий раз |
| 10+ | Звивиста лінія через кожну точку | ❌ Перенавчання — запам’ятовує шум |
Саме це сталося з моделлю Марії! Її племінник використав складну модель глибокого навчання, коли проста крива спрацювала б краще.
📊 Діагноз: Помилка на тренувальних vs тестових даних
Ось ключовий інсайт, який зберіг би Марії $340: завжди перевіряйте і тренувальну, І тестову продуктивність.
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
# Розділяємо дані — 70% для тренування, 30% для тестування
X_train, X_test, y_train, y_test = train_test_split(
X, actual_sales, test_size=0.3, random_state=42
)
results = []
for name, model in [("Ледар", model_slacker),
("Розумний", model_smart),
("Зубрило", model_memorizer)]:
model.fit(X_train, y_train)
train_rmse = np.sqrt(mean_squared_error(y_train, model.predict(X_train)))
test_rmse = np.sqrt(mean_squared_error(y_test, model.predict(X_test)))
gap = test_rmse - train_rmse
results.append((name, train_rmse, test_rmse, gap))
print("\n🍕 Діагностика моделі Марії")
print("=" * 65)
print(f"{'Модель':<12} {'Трен. помилка':>15} {'Тест. помилка':>15} {'Розрив':>12}")
print("-" * 65)
for name, train, test, gap in results:
status = "✅" if gap < 5 else "⚠️" if gap < 15 else "❌"
print(f"{name:<12} {train:>13.1f} {test:>15.1f} {gap:>10.1f} {status}")Результат:
🍕 Діагностика моделі Марії
=================================================================
Модель Трен. помилка Тест. помилка Розрив
-----------------------------------------------------------------
Ледар 15.8 17.2 1.4 ✅
Розумний 9.2 10.5 1.3 ✅
Зубрило 0.1 48.3 48.2 ❌💡 Відкриття:
Племінник Марії використав модель “Зубрило”, бо вона мала найнижчу тренувальну помилку (0.1 піци — майже ідеально!). Але подивіться на тестову помилку: 48.3 піци! І розрив 48.2!
Це характерна ознака перенавчання: Чудова тренувальна продуктивність, жахлива реальна продуктивність.
Діагностична таблиця
Ось як читати ознаки:
| Трен. помилка | Тест. помилка | Розрив | Діагноз | Дія |
|---|---|---|---|---|
| Висока | Висока | Малий | Недонавчання | Збільшити складність |
| Низька | Низька | Малий | Хороша модель | Запускаємо! 🚀 |
| Дуже низька | Висока | Великий | Перенавчання | Спростити або регуляризувати |
⚖️ Компроміс зміщення-дисперсії
За перенавчанням та недонавчанням стоїть фундаментальне протиріччя, яке має розуміти кожен ML-інженер:
Зміщення (Bias): Проблема “Стабільно неправильно”
Зміщення — це помилка від надто спрощених припущень.
Приклад: Модель-ледар Марії припускає, що продажі піц — це пряма лінія від температури. Але реальний попит має криву! Модель стабільно неправильна в одному напрямку.
Ознаки:
- Висока тренувальна помилка
- Висока тестова помилка
- Малий розрив між ними
- Більше даних не допоможе
Виправлення: Використати складнішу модель, додати ознаки
Дисперсія (Variance): Проблема “Нестабільності”
Дисперсія — це помилка від чутливості до малих коливань у тренувальних даних.
Приклад: Модель-зубрило Марії кардинально змінюється, якщо додати або прибрати кілька точок даних. Вона нестабільна — занадто реагує на шум.
Ознаки:
- Дуже низька тренувальна помилка
- Висока тестова помилка
- Великий розрив між ними
- Більше даних ДОПОМОЖЕ!
Виправлення: Спростити модель, використати регуляризацію, отримати більше даних
Візуалізація компромісу
Загальна помилка = Зміщення² + Дисперсія + Незводимий шум
Ви не можете мінімізувати обидва! Дослідіть компроміс нижче:
Bias-Variance Tradeoff / Компроміс Зміщення-Дисперсії
Quick Examples / Швидкі приклади:
🎯 Золота середина: Знайдіть рівень складності, де загальна помилка мінімальна. Зазвичай це десь посередині — не занадто проста, не занадто складна.
📈 Криві навчання: Ваш діагностичний інструмент
Криві навчання показують, як продуктивність вашої моделі змінюється при додаванні більше тренувальних даних. Вони як медичне сканування для здоров’я вашої моделі.
Learning Curves / Криві навчання
Select Scenario / Оберіть сценарій:
Як читати діагноз
Прокликайте три сценарії вище та зверніть увагу:
⚠️ Недонавчання (Високе зміщення):
- Обидві криві високі та плоскі
- Тренувальна та тестова помилки схожі
- Більше даних не допоможе — модель фундаментально занадто проста
- Рецепт: Збільшити складність
✅ Хороша модель (Збалансована):
- Обидві криві сходяться з низькою помилкою
- Малий розрив між тренувальною та тестовою
- Модель добре узагальнює
- Рецепт: Готово! Підналаштуйте, якщо потрібно
❌ Перенавчання (Висока дисперсія):
- Великий розрив між кривими
- Тренувальна помилка дуже низька, тестова висока
- Криві можуть зійтися з більшою кількістю даних
- Рецепт: Спростити, регуляризувати або отримати більше даних
Момент “Ага!” Марії
Коли її племінник показав їй криві навчання для моделі-зубрили, Марія нарешті зрозуміла:
“Отже, моя ‘ідеальна’ модель була хворою весь час! Криві показували симптоми — я просто не знала, як їх читати!”
🔧 План відновлення: Виправляємо недонавчання
Коли ваша модель занадто проста (як ледар), ось рецепт:
1. Збільшити складність моделі
from sklearn.tree import DecisionTreeRegressor
# Занадто проста — недонавчання
simple_tree = DecisionTreeRegressor(max_depth=2)
# Краще — схоплює більше патернів
deeper_tree = DecisionTreeRegressor(max_depth=6)2. Додати більше ознак
Марія зрозуміла, що самої температури недостатньо:
# Оригінал: Тільки температура
X_simple = df[['temperature']]
# Покращено: Бізнес-контекст важливий!
df['is_weekend'] = df['day_of_week'].isin([5, 6]).astype(int)
df['is_holiday'] = df['date'].isin(holidays).astype(int)
df['temp_squared'] = df['temperature'] ** 2 # Схоплюємо криву!
df['marketing_active'] = df['ad_spend'] > 0
X_enhanced = df[['temperature', 'temp_squared', 'is_weekend',
'is_holiday', 'marketing_active']]3. Використати потужніший алгоритм
# Проста: Лінійна регресія (може недонавчитися на складних патернах)
from sklearn.linear_model import LinearRegression
# Потужніша: Random Forest (обробляє нелінійні патерни)
from sklearn.ensemble import RandomForestRegressor
# Ще потужніша: Gradient Boosting
from sklearn.ensemble import GradientBoostingRegressor4. Зменшити регуляризацію
Якщо ви вже використовуєте регуляризацію (розглянемо далі), можливо, ви занадто караєте модель:
from sklearn.linear_model import Ridge
# Занадто багато регуляризації → недонавчання
model = Ridge(alpha=1000) # Перебір!
# Кращий баланс
model = Ridge(alpha=1)🛡️ План відновлення: Виправляємо перенавчання
Коли ваша модель запам’ятовує замість того, щоб вчитися (оригінальна проблема Марії), ось лікування:
1. Отримати більше тренувальних даних
Найефективніше рішення, коли можливо. Більше прикладів допомагають моделі вивчати патерни замість запам’ятовування шуму.
# Якщо 500 зразків → модель запам'ятовує
# Спробуйте 2000+ зразків → модель вчиться патернам2. Спростити модель
Пам’ятаєте Статтю 7? Використаймо глибину дерева як приклад:
Вплив глибини дерева на перенавчання / Tree Depth Impact on Overfitting
Типові випадки / Common Cases:
from sklearn.tree import DecisionTreeRegressor
# Перенавчання: Занадто глибоке, запам'ятовує все
deep_tree = DecisionTreeRegressor(max_depth=20)
# Краще: Контрольована складність
controlled_tree = DecisionTreeRegressor(
max_depth=5, # Обмежуємо глибину
min_samples_split=20, # Потрібно 20+ зразків для розділення
min_samples_leaf=10 # Потрібно 10+ зразків у кожному листку
)3. Видалити шумні ознаки
Іноді менше — це краще. Марія випадково включила “order_id” як ознаку — повністю марний шум!
# Занадто багато ознак (деякі — шум)
X_noisy = df[['temperature', 'order_id', 'cashier_name', 'random_number']]
# Тільки чисті ознаки
from sklearn.feature_selection import SelectKBest, f_regression
selector = SelectKBest(f_regression, k=5)
X_clean = selector.fit_transform(X_all, y)4. Регуляризація — Секретна зброя
Це найважливіша техніка. Занурюємось глибше.
💊 Регуляризація: Навчаємо модель дисципліни
Регуляризація додає штраф за складність, змушуючи вашу модель залишатися простою та здатною до узагальнення.
Уявіть це так: Студент-зубрило міг би отримати 100%, написавши 50 сторінок конспектів. Регуляризація каже: “Ти можеш написати тільки 1 сторінку. Зосередься на важливому!”
Інтерактивна демонстрація: Побачте регуляризацію в дії
Regularization Effect / Ефект регуляризації
Coefficients / Коефіцієнти
Performance / Продуктивність
Три типи регуляризації
L2 Регуляризація (Ridge) — Метод “Стиснення”
Штраф: Сума квадратів коефіцієнтів
Ефект: Зменшує всі коефіцієнти до нуля, але рідко до точного нуля.
from sklearn.linear_model import Ridge
# alpha контролює силу регуляризації
ridge_light = Ridge(alpha=0.01) # Мінімальне стиснення
ridge_medium = Ridge(alpha=1.0) # Помірне
ridge_strong = Ridge(alpha=100) # Сильне стисненняКоли використовувати: Вибір за замовчуванням. Добре, коли всі ознаки можуть бути корисними.
L1 Регуляризація (Lasso) — “Селектор ознак”
Штраф: Сума абсолютних значень коефіцієнтів
Ефект: Зменшує ТА видаляє ознаки, встановлюючи коефіцієнти точно в нуль!
from sklearn.linear_model import Lasso
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)
# Перевіряємо, які ознаки були видалені
print("🔍 Аналіз ознак:")
for name, coef in zip(feature_names, lasso.coef_):
status = "✅ ЗАЛИШЕНО" if coef != 0 else "❌ ВИДАЛЕНО"
print(f" {name}: {coef:.4f} ({status})")Коли використовувати: Коли ви підозрюєте, що багато ознак нерелевантні (як “order_id” Марії).
Elastic Net — Найкраще з обох світів
Штраф: Мікс L1 та L2
from sklearn.linear_model import ElasticNet
# l1_ratio: 0 = чистий Ridge, 1 = чистий Lasso, 0.5 = збалансований
elastic = ElasticNet(alpha=0.1, l1_ratio=0.5)Коли використовувати: Коли хочете відбір ознак (L1) плюс стабільні групи (L2).
Результати регуляризації Марії
print("\n🍕 Порівняння регуляризації для моделі Марії")
print("=" * 70)
print(f"{'Метод':<15} {'Трен. RMSE':>12} {'Тест. RMSE':>12} {'Розрив':>10} {'Ознак':>10}")
print("-" * 70)
# Результати після застосування кожного методу
# Без рег. 2.1 48.3 46.2 20
# Ridge 8.2 10.1 1.9 20
# Lasso 8.9 9.8 0.9 12 ← 8 марних ознак видалено!
# Elastic 8.5 9.9 1.4 15Реакція Марії: “Lasso видалив 8 ознак, які я вважала важливими — включаючи день встановлення печі! Тепер моя модель насправді працює!”
✅ Крос-валідація: Довіряй, але перевіряй
Не покладайтеся на один розподіл train/test. Використовуйте крос-валідацію для надійної оцінки:
from sklearn.model_selection import cross_val_score
def evaluate_model(model, X, y):
"""5-fold крос-валідація для надійних оцінок."""
scores = cross_val_score(
model, X, y,
cv=5, # 5 різних розподілів train/test
scoring='neg_mean_squared_error'
)
rmse_scores = np.sqrt(-scores)
return rmse_scores.mean(), rmse_scores.std()
# Порівнюємо моделі надійно
models = [
("Проста (depth=2)", DecisionTreeRegressor(max_depth=2)),
("Збалансована (depth=5)", DecisionTreeRegressor(max_depth=5)),
("Глибока (depth=15)", DecisionTreeRegressor(max_depth=15)),
]
print("\n📊 Результати крос-валідації (5-fold)")
print("=" * 55)
for name, model in models:
mean_rmse, std_rmse = evaluate_model(model, X, y)
print(f"{name}: {mean_rmse:.1f} ± {std_rmse:.1f} піц")Результат:
📊 Результати крос-валідації (5-fold)
=======================================================
Проста (depth=2): 12.5 ± 1.2 піц
Збалансована (depth=5): 8.7 ± 0.9 піц ← Переможець!
Глибока (depth=15): 15.2 ± 3.5 піцЗбалансована модель виграє — найнижча помилка І найнижча варіативність (число ±).
🎯 Повне відновлення: Нова модель Марії
Давайте зберемо все разом для піцерії Марії:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error
# Очищений датасет Марії
np.random.seed(42)
n = 500
data = {
'temperature': np.random.uniform(5, 35, n),
'is_weekend': np.random.choice([0, 1], n, p=[0.7, 0.3]),
'is_holiday': np.random.choice([0, 1], n, p=[0.95, 0.05]),
'hour': np.random.choice(range(10, 23), n),
'marketing_active': np.random.choice([0, 1], n, p=[0.8, 0.2]),
}
df = pd.DataFrame(data)
df['is_peak'] = ((df['hour'] >= 18) & (df['hour'] <= 21)).astype(int)
# Справжня залежність (що відкрила Марія)
df['sales'] = (
80 + # Базовий попит
-0.8 * df['temperature'] + # Холод = більше замовлень
25 * df['is_weekend'] + # Вихідні +25
45 * df['is_holiday'] + # Свята +45
15 * df['is_peak'] + # Вечірній пік +15
10 * df['marketing_active'] + # Маркетинг +10
np.random.normal(0, 12, n) # Реальний шум
).clip(30, 200)
X = df[['temperature', 'is_weekend', 'is_holiday', 'hour', 'is_peak', 'marketing_active']]
y = df['sales']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Порівняння: Стара модель vs Нова модель
models = {
'❌ Стара (Зубрило)': DecisionTreeRegressor(max_depth=None), # Без обмежень!
'✅ Нова (Збалансована)': RandomForestRegressor(n_estimators=50, max_depth=5, random_state=42)
}
print("\n🍕 ТРАНСФОРМАЦІЯ МОДЕЛІ МАРІЇ")
print("=" * 75)
print(f"{'Модель':<28} {'Трен. RMSE':>12} {'Тест. RMSE':>12} {'Розрив':>10} {'Статус':>10}")
print("-" * 75)
for name, model in models.items():
model.fit(X_train, y_train)
train_rmse = np.sqrt(mean_squared_error(y_train, model.predict(X_train)))
test_rmse = np.sqrt(mean_squared_error(y_test, model.predict(X_test)))
gap = test_rmse - train_rmse
status = "ХВОРА" if gap > 10 else "ЗДОРОВА"
print(f"{name:<28} {train_rmse:>10.1f} {test_rmse:>12.1f} {gap:>10.1f} {status}")Результат:
🍕 ТРАНСФОРМАЦІЯ МОДЕЛІ МАРІЇ
===========================================================================
Модель Трен. RMSE Тест. RMSE Розрив Статус
---------------------------------------------------------------------------
❌ Стара (Зубрило) 2.1 28.4 26.3 ХВОРА
✅ Нова (Збалансована) 9.8 11.2 1.4 ЗДОРОВАВплив на бізнес
До (Модель-зубрило):
- Тестова помилка: ±28 піц
- Катастрофа понеділка: 68 піц витрачено
- Тижневі збитки: ~$1,200
Після (Збалансована модель):
- Тестова помилка: ±11 піц
- Тепер Марія замовляє в межах ±15 піц від реального попиту
- Тижневі збитки: ~$180
Річна економія: $53,000 💰
🚨 Поширені пастки, яких слід уникати
Пастка 1: Налаштування на тестових даних
Неправильно:
# Тестування різних alpha на ТЕСТОВОМУ наборі ❌
for alpha in [0.01, 0.1, 1, 10, 100]:
model = Ridge(alpha=alpha)
model.fit(X_train, y_train)
test_score = model.score(X_test, y_test) # Підглядаємо!
print(f"Alpha {alpha}: {test_score}")
# Тепер ваш тестовий набір забруднений!Правильно:
# Використовуємо крос-валідацію на ТРЕНУВАЛЬНОМУ наборі ✅
from sklearn.model_selection import GridSearchCV
param_grid = {'alpha': [0.01, 0.1, 1, 10, 100]}
grid_search = GridSearchCV(Ridge(), param_grid, cv=5)
grid_search.fit(X_train, y_train) # Тільки тренувальні дані!
print(f"Найкращий alpha: {grid_search.best_params_['alpha']}")
# Тестовий набір залишається недоторканим для фінальної оцінкиПастка 2: Ігнорування розриву
Неправильно: “Моя модель має 98% точності на тренуванні — запускаємо!”
Правильно: Завжди порівнюйте train vs test. Розрив розповідає історію.
Пастка 3: Надмірна регуляризація
Неправильно: Встановлення alpha=10000, бо “регуляризація — це добре”
Правильно: Налаштуйте alpha для оптимального балансу. Занадто багато регуляризації спричиняє недонавчання!
🎓 Ключові висновки
Підсумуймо, що Марія (і ви) дізналися сьогодні:
1. Перенавчання = Запам’ятовування, а не навчання
- Ознаки: Дуже низька трен. помилка, висока тест. помилка, великий розрив
- Виправлення: Спростити модель, регуляризувати, отримати більше даних
2. Недонавчання = Занадто просто, щоб вчитися
- Ознаки: Висока трен. помилка, висока тест. помилка, малий розрив
- Виправлення: Збільшити складність, додати ознаки, зменшити регуляризацію
3. Компроміс зміщення-дисперсії є фундаментальним
- Високе зміщення → недонавчання
- Висока дисперсія → перенавчання
- Мета: Знайти золоту середину, де загальна помилка мінімальна
4. Регуляризація — ваш друг
- L2 (Ridge): Зменшує коефіцієнти
- L1 (Lasso): Зменшує + видаляє ознаки
- Elastic Net: Найкраще з обох світів
5. Завжди валідуйте правильно
- Використовуйте крос-валідацію для вибору моделі
- Зберігайте тестовий набір тільки для фінальної оцінки
- Слідкуйте за розривом train-test!
🚀 Що далі?
Збалансована модель Марії працює добре, але її племінник має ідею:
“Тітко, а що якби замість ОДНОГО дерева ми натренували СОТНІ дерев і дали їм голосувати за прогноз?”
“Сотні? Хіба це не призведе до ще більшого перенавчання?”
“В тому й краса — це насправді зменшує перенавчання! Це називається Random Forest.”
У Статті 9: Ансамблеві методи ви дізнаєтеся, як об’єднання багатьох слабких моделей створює сильний, надійний предиктор. Піцерія Марії стане ще розумнішою! 🌲🌲🌲
🛠️ Практичне завдання
Побудуйте предиктор цін на нерухомість, який уникає перенавчання:
Ознаки датасету:
sqft— площа (500-5000)bedrooms— кількість спалень (1-6)age— вік будинку в роках (0-50)location_score— рейтинг району (1-10)has_pool— басейн (0/1)
Ваша місія:
- Розділіть дані 80/20 train/test
- Натренуйте глибоке дерево рішень (без обмежень) — спостерігайте перенавчання
- Натренуйте Ridge регресію — перевірте, чи є недонавчання
- Налаштуйте Random Forest за допомогою крос-валідації
- Порівняйте фінальну продуктивність на тесті
Критерії успіху:
- Тестовий RMSE в межах 15% від тренувального RMSE (здоровий розрив)
- Визначте, яка модель має найкращий баланс зміщення-дисперсії
Сьогодні ви навчилися діагностувати та виправляти перенавчання. Тепер ідіть рятувати піци! 🍕
Успіхів! 🎯