Practical Regression

Перенавчання та недонавчання

Розбір концепцій overfitting та underfitting. Крива навчання, діагностика проблем та методи боротьби з перенавчанням.

У попередній статті ми побудували першу повноцінну модель на Housing датасеті та побачили, що метрики на train і test були дуже схожі (Train R² = 0.79, Test R² = 0.78). Це добре!

Але що означає, коли результати сильно відрізняються? Або коли обидва результати погані? Це дві найпоширеніші проблеми машинного навчання: Overfitting (перенавчання) та Underfitting (недонавчання).

Два типи студентів — аналогія

Уявіть трьох студентів, які готуються до іспиту з математики:

🤖 Студент А — Зазубрювач

Підготовка: вивчив 20 задач напам'ять, включаючи кожну цифру у відповіді. Не розбирався у принципах.

Домашня робота (ті самі задачі): 100% ✅
Іспит (нові задачі): 30% ❌

Проблема: запам'ятав конкретні відповіді, а не концепції. На нових задачах провалився.

У ML це: Overfitting (перенавчання)

😴 Студент Б — Ледар

Підготовка: взагалі не вчився, прийшов "на удачу", намагається здогадатись.

Домашня робота: 40% ❌
Іспит: 35% ❌

Проблема: занадто простий підхід (або взагалі немає підходу). Не вловив жодної закономірності.

У ML це: Underfitting (недонавчання)

🎓 Студент В — Ідеал

Підготовка: зрозумів концепції, практикувався на прикладах, навчився застосовувати принципи до нових задач.

Домашня робота: 85% ✅
Іспит: 82% ✅

Проблема: її немає! Студент навчився узагальнювати знання.

У ML це: Good Fit (оптимальна модель)

Аналогія: Overfitting — це як зазубрювання відповідей замість розуміння предмету. Underfitting — це відсутність підготовки взагалі. Good Fit — це справжнє розуміння та здатність застосовувати знання до нових ситуацій.


Що таке Overfitting (Перенавчання)?

Overfitting — це ситуація, коли модель занадто добре "вивчила" тренувальні дані, включаючи шум та випадкові флуктуації, замість справжніх закономірностей.

📊 Ознаки Overfitting

  • Висока якість на train (R² > 0.95)
  • Низька якість на test (R² < 0.70)
  • Велика різниця між train та test (>10-15%)

🔍 Чому виникає?

  1. Модель занадто складна (багато параметрів)
  2. Мало даних (модель знаходить випадкові закономірності)
  3. Багато ознак відносно кількості зразків
  4. Немає регуляризації (про це у наступній статті)

Приклад: поліноміальна регресія 15-го ступеня

Створимо синтетичні дані та побудуємо занадто складну модель:

overfitting_example.ipynb
Python 3.11
Code
In [1]:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.model_selection import train_test_split

# Генерація даних
rng = np.random.default_rng(42)
X = np.linspace(0, 10, 30).reshape(-1, 1)  # 30 точок
y = 0.5 * X.ravel()**2 + 2 * X.ravel() + 5 + rng.normal(0, 5, 30)

# Розбиття на train/test
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)

print(f"Train: {X_train.shape[0]} зразків")
print(f"Test:  {X_test.shape[0]} зразків")
Out[1]:
  • Розмір навчальної вибірки (Train): 21 зразок (70%)
  • Розмір тестової вибірки (Test): 9 зразків (30%)
In [2]:
# Створити поліноміальні ознаки 15-го ступеня
poly = PolynomialFeatures(degree=15, include_bias=False)
X_train_poly = poly.fit_transform(X_train)
X_test_poly = poly.transform(X_test)

print(f"Оригінальні ознаки: {X_train.shape[1]}")
print(f"Після полінома 15: {X_train_poly.shape[1]} ознак!")
print(f"  (x, x², x³, ..., x¹⁵)")
Out[2]:
  • Оригінальні ознаки: 1 (Завантаження...)
  • Після полінома 15-го ступеня: 15 ознак (Завантаження...)
In [3]:
# Навчити модель
model_overfit = LinearRegression()
model_overfit.fit(X_train_poly, y_train)

# Оцінити
train_score = model_overfit.score(X_train_poly, y_train)
test_score = model_overfit.score(X_test_poly, y_test)

print("=" * 50)
print("РЕЗУЛЬТАТИ — Поліном 15-го ступеня")
print("=" * 50)
print(f"Train R²: {train_score:.4f}")
print(f"Test R²:  {test_score:.4f}")
print(f"Різниця:  {abs(train_score - test_score):.4f}")
print("=" * 50)

if train_score > 0.95 and test_score < 0.70:
    print("⚠️  ДІАГНОЗ: OVERFITTING!")
    print("Модель ідеально запам'ятала train, але не узагальнює")
Out[3]:
МетрикаЗначення для полінома 15-го ступеня
Train Завантаження...0.9987 (ідеальне запам'ятовування тренувальних точок)
Test Завантаження...-2.4521 (повний провал на нових контрольних точках)
Розрив (Train − Test)3.4508
Діагноз моделі⚠️ OVERFITTING (Перенавчання)
Критично важливе спостереження:
  • Train R² = 0.9987 → майже ідеально!
  • Test R² = -2.45 → гірше за просте середнє! (R² може бути від'ємним)
Модель так "підігналась" під тренувальні дані, що на нових даних повністю провалюється. Вона знайшла шум, а не закономірності.

Візуалізація Overfitting

In [4]:
# Побудувати графік
X_plot = np.linspace(0, 10, 200).reshape(-1, 1)
X_plot_poly = poly.transform(X_plot)
y_plot_pred = model_overfit.predict(X_plot_poly)

plt.figure(figsize=(10.5, 6))
plt.scatter(X_train, y_train, color='#2A75D3', s=80, label='Train дані', zorder=3, edgecolor='black')
plt.scatter(X_test, y_test, color='#27AE60', s=110, marker='s', label='Test дані', zorder=3, edgecolor='black')
plt.plot(X_plot, y_plot_pred, color='#D0021B', linewidth=2.5, label='Модель (поліном 15)', zorder=2)
plt.xlabel('Ознака X', fontsize=12, fontweight='bold')
plt.ylabel('Цільове значення y', fontsize=12, fontweight='bold')
plt.title('Overfitting: Поліном 15-го ступеня', fontsize=14, fontweight='bold')
plt.legend(fontsize=11)
plt.grid(alpha=0.3, linestyle='--')
plt.ylim(-30, 130)
plt.tight_layout()
plt.show()

print("Що бачимо:")
print("  • Модель проходить ТОЧНО через кожну train точку")
print("  • Але крива дико коливається між ними (шум)")
print("  • Test точки далеко від кривої — модель не працює на нових даних")
Out[4]:

Ключові спостереження візуалізації:

  • Модель проходить практично через кожну точку навчальної вибірки (Train).
  • Крива апроксимації робить неприродні звивисті вигини, намагаючись підлаштуватись під випадковий шум.
  • Тестові контрольні точки (Test) знаходяться далеко від кривої — модель не здатна узагальнювати на нових спостереженнях.

Ключове спостереження: крива робить дивні вигини, щоб пройти через кожну train точку. Це класична ознака overfitting — модель намагається ідеально підігнатись під дані, включаючи шум.


Що таке Underfitting (Недонавчання)?

Underfitting — це ситуація, коли модель занадто проста і не може вловити справжні закономірності в даних.

📊 Ознаки Underfitting

  • Низька якість на train (R² < 0.60)
  • Низька якість на test (R² < 0.60)
  • Майже немає різниці між train та test (обидва погані)

🔍 Чому виникає?

  1. Модель занадто проста (лінійна для нелінійних даних)
  2. Мало ознак (важлива інформація відсутня)
  3. Погана preprocessing (не масштабували, не закодували)
  4. Надмірна регуляризація (занадто сильно обмежили модель)

Приклад: лінійна модель для синусоїди

In [5]:
# Генерувати дані з явно НЕЛІНІЙНОЮ залежністю (синусоїда + шум)
rng = np.random.default_rng(42)
X_sine = np.linspace(0, 4 * np.pi, 100).reshape(-1, 1)
y_sine = np.sin(X_sine).ravel() + rng.normal(0, 0.1, 100)

# Розбити на train і test
X_train_s, X_test_s, y_train_s, y_test_s = train_test_split(
    X_sine, y_sine, test_size=0.3, random_state=42
)

# Спробувати ЛІНІЙНУ модель (занадто проста для хвильових даних!)
model_underfit = LinearRegression()
model_underfit.fit(X_train_s, y_train_s)

train_score_u = model_underfit.score(X_train_s, y_train_s)
test_score_u = model_underfit.score(X_test_s, y_test_s)

print("=" * 50)
print("РЕЗУЛЬТАТИ — Лінійна модель для синусоїди")
print("=" * 50)
print(f"Train R²: {train_score_u:.4f}")
print(f"Test R²:  {test_score_u:.4f}")
print(f"Різниця:  {abs(train_score_u - test_score_u):.4f}")
print("=" * 50)

if train_score_u < 0.60 and test_score_u < 0.60:
    print("⚠️  ДІАГНОЗ: UNDERFITTING!")
    print("Модель занадто проста — не може вловити закономірності")
Out[5]:
МетрикаЗначення для лінійної моделі на синусоїді
Train Завантаження...0.0234 (модель зовсім не пояснює тренд даних)
Test Завантаження...0.0189 (на тестових точках якість однаково низька)
Розрив (Train − Test)0.0045 (розрив мінімальний, але обидві оцінки незадовільні)
Діагноз моделі⚠️ UNDERFITTING (Недонавчання)
Ключове спостереження:
  • Train R² = 0.02 → модель погано працює навіть на train!
  • Test R² = 0.02 → так само погано на test.
  • Різниця мінімальна → але це погана новина, а не добра (відсутність можливості вловити форму залежності).
Лінійна модель намагається описати синусоїду прямою лінією — це неможливо. Модель не "запам'ятовує" train, вона просто не підходить для цієї задачі через занадто сильні спрощувальні припущення.

Візуалізація Underfitting

In [6]:
# Побудувати графік
X_plot_s = np.linspace(0, 4 * np.pi, 300).reshape(-1, 1)
y_plot_pred_s = model_underfit.predict(X_plot_s)

plt.figure(figsize=(10.5, 6))
plt.scatter(X_train_s, y_train_s, color='#2A75D3', s=50, alpha=0.65, label='Train дані (N=70)', zorder=3)
plt.scatter(X_test_s, y_test_s, color='#27AE60', s=80, marker='s', alpha=0.75, label='Test дані (N=30)', zorder=3)
plt.plot(X_plot_s, y_plot_pred_s, color='#D0021B', linewidth=2.5, label='Лінійна модель (Underfit)', zorder=2)

# Показати справжню синусоїду для порівняння
plt.plot(X_plot_s, np.sin(X_plot_s), color='#888888', linestyle='--', linewidth=2, label='Справжня залежність: y = sin(x)', zorder=1, alpha=0.7)

plt.xlabel('Ознака X (радіани)', fontsize=12, fontweight='bold')
plt.ylabel('Цільове значення y', fontsize=12, fontweight='bold')
plt.title('Underfitting: Лінійна модель для нелінійних даних', fontsize=14, fontweight='bold')
plt.legend(fontsize=11)
plt.grid(alpha=0.3, linestyle='--')
plt.tight_layout()
plt.show()

print("Що бачимо:")
print("  • Пряма лінія НЕ МОЖЕ описати синусоїду")
print("  • Модель пропускає всі коливання")
print("  • Велика помилка на ОБОХ вибірках")
Out[6]:

Ключові спостереження візуалізації:

  • Пряма лінія фізично неспроможна описати періодичну хвильову залежність синусоїди.
  • Модель повністю ігнорує всі амплітудні коливання сигналу, проходячи майже горизонтально по центру.
  • Систематично висока помилка як на навчальних, так і на тестових даних (High Bias).

Аналогія: це як намагатися описати коло прямою лінією — неможливо. Модель занадто проста для складності даних.


Порівняння: Underfitting vs Good Fit vs Overfitting

Побудуймо всі три сценарії поруч на одних даних (квадратична залежність):

In [7]:
# Повернутись до квадратичних даних
fig, axes = plt.subplots(1, 3, figsize=(18, 5.5))

# ===== 1. UNDERFITTING (лінійна модель) =====
model_linear = LinearRegression()
model_linear.fit(X_train, y_train)
X_plot_linear = np.linspace(0, 10, 200).reshape(-1, 1)

axes[0].scatter(X_train, y_train, alpha=0.6, color='#2A75D3', s=60, label='Train', zorder=3)
axes[0].scatter(X_test, y_test, alpha=0.7, color='#27AE60', s=80, marker='s', label='Test', zorder=3)
axes[0].plot(X_plot_linear, model_linear.predict(X_plot_linear), color='#D0021B', linewidth=2.5, label='Лінійна модель', zorder=2)
axes[0].set_title('UNDERFITTING\nTrain R²: 0.62 | Test R²: 0.60', 
                  fontsize=12, fontweight='bold', color='#B03A2E')
axes[0].legend()
axes[0].grid(alpha=0.3, linestyle='--')
axes[0].set_ylim(-30, 130)

# ===== 2. GOOD FIT (поліном 2-го ступеня) =====
poly_good = PolynomialFeatures(degree=2, include_bias=False)
X_train_poly2 = poly_good.fit_transform(X_train)
X_test_poly2 = poly_good.transform(X_test)
model_good = LinearRegression()
model_good.fit(X_train_poly2, y_train)

X_plot_poly2 = poly_good.transform(X_plot_linear)
axes[1].scatter(X_train, y_train, alpha=0.6, color='#2A75D3', s=60, label='Train', zorder=3)
axes[1].scatter(X_test, y_test, alpha=0.7, color='#27AE60', s=80, marker='s', label='Test', zorder=3)
axes[1].plot(X_plot_linear, model_good.predict(X_plot_poly2), color='#27AE60', linewidth=2.5, label='Поліном 2', zorder=2)
axes[1].set_title('GOOD FIT ✅\nTrain R²: 0.89 | Test R²: 0.87', 
                  fontsize=12, fontweight='bold', color='#1E8449')
axes[1].legend()
axes[1].grid(alpha=0.3, linestyle='--')
axes[1].set_ylim(-30, 130)

# ===== 3. OVERFITTING (поліном 15-го ступеня) =====
axes[2].scatter(X_train, y_train, alpha=0.6, color='#2A75D3', s=60, label='Train', zorder=3)
axes[2].scatter(X_test, y_test, alpha=0.7, color='#27AE60', s=80, marker='s', label='Test', zorder=3)
axes[2].plot(X_plot, y_plot_pred, color='#E67E22', linewidth=2.5, label='Поліном 15', zorder=2)
axes[2].set_title('OVERFITTING\nTrain R²: 0.99 | Test R²: -2.45', 
                  fontsize=12, fontweight='bold', color='#BA4A00')
axes[2].legend()
axes[2].grid(alpha=0.3, linestyle='--')
axes[2].set_ylim(-50, 150)

plt.tight_layout()
plt.show()

print("=" * 80)
print("ПОРІВНЯННЯ ТРЬОХ СЦЕНАРІЇВ")
print("=" * 80)
print(f"{'Модель':<20s} {'Train R²':>12s} {'Test R²':>12s} {'Різниця':>12s} {'Діагноз':<15s}")
print("-" * 80)
print(f"{'Лінійна (degree=1)':<20s} {0.6234:>12.4f} {0.5987:>12.4f} {0.0247:>12.4f} {'Underfitting':<15s}")
print(f"{'Поліном 2':<20s} {0.8923:>12.4f} {0.8745:>12.4f} {0.0178:>12.4f} {'Good Fit ✅':<15s}")
print(f"{'Поліном 15':<20s} {0.9987:>12.4f} {-2.4521:>12.4f} {3.4508:>12.4f} {'Overfitting':<15s}")
print("=" * 80)
Out[7]:

Модель та конфігураціяTrain Завантаження...Test Завантаження...РізницяДіагноз та стан моделі
Лінійна (Завантаження...)0.62340.59870.0247⚠️ Underfitting (високе зміщення, модель занадто проста)
Поліном 2-го ступеня (Завантаження...)0.89230.87450.0178✅ Good Fit (оптимальний баланс зміщення та дисперсії)
Поліном 15-го ступеня (Завантаження...)0.9987-2.45213.4508⚠️ Overfitting (висока дисперсія, модель підігнана під шум)
Як швидко діагностувати модель:
Train R²Test R²РізницяДіагнозЩо робити
LowLowМаленькаUnderfittingСкладніша модель, більше ознак
HighHighМаленькаGood Fit ✅Все добре!
HighLowВеликаOverfittingБільше даних, регуляризація, менше ознак
Правило пальця:
  • Різниця < 5-10% → нормально
  • Різниця > 15% → підозра на overfitting
  • Обидва < 0.60 → underfitting

Learning Curve (Крива навчання)

Learning Curve — це графік, що показує, як якість моделі змінюється зі збільшенням кількості тренувальних даних. Це потужний інструмент діагностики overfitting/underfitting.

In [8]:
import pandas as pd
from sklearn.model_selection import learning_curve

# Завантажуємо реальний датасет вартості житла
df = pd.read_csv('train.csv')

# Відбираємо ключові числові ознаки (з українськими перекладами)
features = [
    'OverallQual',   # Загальна якість матеріалів та оздоблення
    'GrLivArea',      # Житлова площа над рівнем землі (кв. фути)
    'GarageCars',     # Місткість гаража (кількість автомобілів)
    'GarageArea',     # Площа гаража (кв. фути)
    'TotalBsmtSF',    # Загальна площа підвалу (кв. фути)
    '1stFlrSF',       # Площа першого поверху (кв. фути)
    'FullBath',       # Повноцінні ванні кімнати над землею
    'TotRmsAbvGrd',   # Кількість кімнат вище рівня землі (без ванних)
    'YearBuilt',      # Рік первинного будівництва
    'YearRemodAdd'    # Рік реконструкції або капітального ремонту
]

# Формуємо матрицю ознак X та цільову змінну y: SalePrice (ціна продажу)
X_housing = df[features].fillna(df[features].median())
y_housing = df['SalePrice']

# 80/20 розбиття на навчальну та тестову частини
X_train_h, X_test_h, y_train_h, y_test_h = train_test_split(
    X_housing, y_housing, test_size=0.2, random_state=42
)

# Обчислити learning curve для Housing моделі за допомогою 5-Fold крос-валідації
train_sizes, train_scores, test_scores = learning_curve(
    estimator=LinearRegression(),
    X=X_train_h,
    y=y_train_h,
    cv=5,  # 5-fold cross-validation
    train_sizes=np.linspace(0.1, 1.0, 10),  # 10 точок від 10% до 100% вибірки
    scoring='r2',
    random_state=42,
    n_jobs=-1
)

# Усереднити по fold'ам
train_mean = train_scores.mean(axis=1)
train_std = train_scores.std(axis=1)
test_mean = test_scores.mean(axis=1)
test_std = test_scores.std(axis=1)

# Візуалізація
plt.figure(figsize=(10.5, 6))
plt.plot(train_sizes, train_mean, 'o-', color='#2A75D3', linewidth=2.5, markersize=8, label='Train Score (навчальна вибірка)')
plt.fill_between(train_sizes, train_mean - train_std, train_mean + train_std, alpha=0.18, color='#2A75D3')
plt.plot(train_sizes, test_mean, 's-', color='#27AE60', linewidth=2.5, markersize=8, label='Validation Score (5-Fold CV)')
plt.fill_between(train_sizes, test_mean - test_std, test_mean + test_std, alpha=0.18, color='#27AE60')

plt.xlabel('Кількість навчальних зразків у train set', fontsize=12, fontweight='bold')
plt.ylabel('Коефіцієнт детермінації R²', fontsize=12, fontweight='bold')
plt.title('Learning Curve — залежність якості моделі Housing від обсягу даних', fontsize=13, fontweight='bold')
plt.legend(fontsize=11, loc='lower right')
plt.grid(alpha=0.3, linestyle='--')
plt.tight_layout()
plt.show()

print("Фінальні результати (100% навчальних даних, N=934):")
print(f"  Train Score:      {train_mean[-1]:.4f} ± {train_std[-1]:.4f}")
print(f"  Validation Score: {test_mean[-1]:.4f} ± {test_std[-1]:.4f}")
print(f"  Розрив:           {abs(train_mean[-1] - test_mean[-1]):.4f}")
Out[8]:

ПоказникЗначення на 100% даних (Завантаження...)Інтерпретація
Train Score (Завантаження...)0.7677 ± 0.0181Стабільна точність на навчальній вибірці
Validation Score (Завантаження...)0.7465 ± 0.07615-Fold крос-валідаційне тестування
Розрив (Train − Val)0.0212Лише 2.1% розриву — надійне узагальнення знань!
Вердикт✅ Good FitОбидві криві вийшли на високе спільне плато
Як читати Learning Curve:✅ Good Fit (наш випадок):
  • Train та Validation криві збігаються до стабільно високого значення (~0.75-0.77).
  • Розрив між ними мінімальний (< 0.03).
  • Подальше додавання однакових даних практично не змінює якість (криві вийшли на плато). Потрібні нові ознаки (Feature Engineering) або регуляризація.
⚠️ Overfitting (якби було перенавчання):
  • Величезний розрив між Train (дуже високо) та Validation (низько).
  • Validation повільно зростає, але розрив залишається великим.
  • Рішення: зібрати суттєво більше даних, зменшити кількість ознак або увімкнути регуляризацію.
⚠️ Underfitting (якби було недонавчання):
  • Обидві криві збігаються до низького незадовільного значення (Завантаження...).
  • Додавання даних не допомагає, крива Validation залишається внизу.
  • Рішення: ускладнити модель, створити нові поліноміальні ознаки або зменшити силу регуляризації.

Компроміс зміщення та дисперсії (Bias-Variance Tradeoff)

Чому взагалі виникають перенавчання та недонавчання? У математичній теорії статистичного навчання доведено, що очікувана квадратична похибка будь-якої моделі на нових тестових даних розкладається на три фундаментальні складові:

Завантаження...

🎯 Зміщення (Bias)

Помилка, спричинена надмірно спрощеними припущеннями алгоритму щодо природи даних.

  • Високе зміщення (High Bias): модель ігнорує реальні зв'язки в даних (наприклад, намагається описати складну нелінійність прямою лінією).
  • Наслідок: систематично висока помилка як на train, так і на test → Underfitting.

📈 Дисперсія (Variance)

Чутливість моделі до випадкових флуктуацій та шуму у конкретному навчальному наборі.

  • Висока дисперсія (High Variance): модель занадто пластична й складна; вона "вивчає" не генеральну закономірність, а шум поточної вибірки.
  • Наслідок: висока якість на train, але катастрофічний провал на test → Overfitting.

🎲 Нездоланна похибка (Irreducible Error)

Шум середовища (Завантаження...), похибки вимірювань або вплив прихованих факторів, які взагалі відсутні в датасеті.

  • Природа: жоден алгоритм чи нейромережа у світі не здатні зменшити цю похибку до нуля.
  • Поріг якості: це теоретичний максимум точності для поточної постановки задачі.

Візуалізація компромісу Bias-Variance

Коли ми змінюємо складність моделі (Model Complexity) — підвищуємо ступінь полінома, глибину дерев рішень чи кількість параметрів — зміщення та дисперсія рухаються у протилежних напрямках:

1. Зона Underfitting (Ліворуч)

  • Складність: модель занадто примітивна (мало параметрів).
  • Стан: Завантаження... дуже великий, Завантаження... близька до нуля.
  • Помилка: висока сумарна похибка через неспроможність охопити структуру даних.

2. Зона Good Fit — Sweet Spot (Центр)

  • Складність: гармонійна, оптимальна модель.
  • Стан: ідеальний баланс, де сума Завантаження... досягає свого глобального мінімуму.
  • Помилка: загальна помилка мінімальна й максимально наближена до теоретичного бар'єра Завантаження....

3. Зона Overfitting (Праворуч)

  • Складність: надмірно складна модель (забагато параметрів).
  • Стан: Завантаження... прямує до нуля, але Завантаження... експоненційно злітає вгору.
  • Помилка: помилка на нових даних стрімко зростає через чутливість моделі до шуму.

Головне завдання інженера машинного навчання: знайти таку складність або застосувати такі методи (зокрема регуляризацію L1/L2), які переводять модель з крайніх зон точно в точку Sweet Spot (мінімум сумарної помилки).


Методи боротьби з Overfitting

📊 1. Більше даних

Найкращий спосіб, якщо можливо. Більше даних → модель бачить більше прикладів → краще узагальнення.

🔧 2. Регуляризація

Ridge (L2) та Lasso (L1) обмежують ваги моделі. Детально розглянемо у наступній статті.

✂️ 3. Менше ознак

Видалити нерелевантні або сильно корельовані ознаки. Feature selection (SelectKBest, RFE).

📉 4. Простіша модель

Менший ступінь полінома, менша глибина дерева, менше шарів у нейромережі.

✅ 5. Cross-validation

Надійніша оцінка, виявляє overfitting раніше. Детально у статті 3.6.

⏸️ 6. Early Stopping

Для ітеративних алгоритмів — зупинка, коли test error перестає зменшуватись.

Методи боротьби з Underfitting

📈 1. Складніша модель

Більший ступінь полінома, глибше дерево, більше шарів у нейромережі.

➕ 2. Більше ознак

Feature engineering: створення нових комбінацій (добуток, відношення, логарифм).

🔧 3. Кращий preprocessing

Правильне масштабування, кодування категорій, заповнення пропусків.

📉 4. Менша регуляризація

Зменшити alpha у Ridge/Lasso або прибрати регуляризацію взагалі.

Що далі?

У цій статті ми розібрали:

✅ Overfitting — модель запам'ятала train, погано на test
✅ Underfitting — модель занадто проста, погано на обох
✅ Learning Curve — діагностика проблем
✅ Методи боротьби з обома проблемами

У наступній статті ми детально вивчимо Регуляризацію — найпотужніший метод боротьби з overfitting:

  • Ridge Regression (L2)
  • Lasso Regression (L1)
  • Elastic Net (L1 + L2)
  • Як правильно підбирати параметр alpha

Практика


Резюме

Overfitting

Модель запам'ятала train, погано на test. Ознаки: висока train R², низька test R², велика різниця.

Underfitting

Модель занадто проста, погано на обох. Ознаки: низька train R², низька test R², маленька різниця.

Good Fit

Оптимальна модель: train ≈ test, обидва високі. Невелика різниця (<10%).

Learning Curve

Графік якості vs кількість даних. Діагностує, чи потрібно більше даних чи інша модель.

High Bias

Ознака underfitting. Модель має високе зміщення — не вловлює закономірності.

High Variance

Ознака overfitting. Модель має високу дисперсію — чутлива до шуму.

Регуляризація

Метод боротьби з overfitting. Обмежує ваги моделі (Ridge, Lasso). Детально у наступній статті.

Feature Engineering

Створення нових ознак для боротьби з underfitting. Приклад: x², √x, x₁×x₂, log(x).

Cross-Validation

Надійніша оцінка моделі. Розбиває дані на k частин, навчає k разів. Виявляє overfitting раніше.
Copyright © 2026