Practical Regression

Exploratory Data Analysis датасету Housing Prices

Розвідувальний аналіз даних реального датасету про ціни на житло. Виявлення пропусків, кореляцій та проблем перед побудовою моделі.

У попередній статті ми навчились працювати з scikit-learn на простих синтетичних даних. Тепер настав час зануритись у реальну задачу машинного навчання — передбачення цін на житло на основі датасету з Kaggle.

Але перш ніж будувати модель, потрібно зрозуміти дані. Саме цьому присвячена практика Exploratory Data Analysis (EDA) — розвідувальний аналіз даних.

Kaggle Competition — реальна задача ML

Housing Prices: Advanced Regression Techniques — одне з найпопулярніших навчальних змагань на платформі Kaggle. У ньому взяли участь понад 5000 команд Data Scientists з усього світу.

🎯 Мета змагання

Передбачити ціну будинку (SalePrice — ціна продажу) на основі 79 ознак: площа, кількість кімнат, рік будівництва, район, якість ремонту, тощо.

📊 Датасет

  • 1460 будинків у тренувальному наборі
  • 80 стовпців (79 ознак + ціна)
  • Реальні дані з міста Ames, Iowa (США)
  • Різноманітні типи ознак: числові, категоріальні

🏆 Метрика оцінки

RMSE (Root Mean Squared Error) між логарифмами передбаченої та реальної ціни. Чим менше — тим краще.

Аналогія: це як "олімпіада з ML" — реальні дані, реальна конкуренція, реальні виклики. Те, що ви навчитесь тут, застосовується в production-моделях.


Що таке EDA (Exploratory Data Analysis)?

Exploratory Data Analysis (EDA) — це перший обов'язковий крок перед побудовою будь-якої ML-моделі. Це процес детального вивчення даних для розуміння їхньої структури, виявлення проблем та пошуку закономірностей.

Ключові питання EDA:

📋 Структура

  • Які ознаки є в датасеті?
  • Скільки рядків та стовпців?
  • Які типи даних (числові, текстові)?

❓ Проблеми

  • Чи є пропуски (NaN)?
  • Чи є викиди (outliers)?
  • Чи є дублікати рядків?

🔗 Зв'язки

  • Які ознаки корелюють з ціною?
  • Які ознаки корелюють між собою?
  • Чи є нелінійні залежності?

Аналогія: EDA — це як медичний огляд перед операцією. Лікар має знати стан "пацієнта" (датасету): чи є "хвороби" (пропуски), чи все "на місці" (ознаки правильного типу), як працюють "органи" (взаємодія ознак).

Типова помилка початківців: відразу почати будувати модель, не проаналізувавши дані. Результат — погана якість, непередбачувані помилки, годинні втрати на налагодження.Правило: витратьте 30-40% часу на EDA — це окупиться швидким та якісним моделюванням.

Завантаження датасету

Датасет Housing Prices можна завантажити кількома способами:

# Встановіть kaggle CLI
pip install kaggle

# Завантажте датасет
kaggle competitions download -c house-prices-advanced-regression-techniques

# Розпакуйте
unzip house-prices-advanced-regression-techniques.zip

Для цієї статті будемо вважати, що файл train.csv вже завантажений у вашу робочу папку.

housing_eda.ipynb
Python 3.11
Code
In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Налаштування відображення
pd.set_option('display.max_columns', None)  # Показувати всі стовпці
pd.set_option('display.width', None)
sns.set_style('whitegrid')  # Стиль графіків

# Завантаження даних
df = pd.read_csv('train.csv')

print(f"Датасет завантажено!")
print(f"Розмір: {df.shape[0]} рядків × {df.shape[1]} стовпців")
Out[1]:
Датасет завантажено!
Розмір: 1460 рядків × 81 стовпців
Пояснення розміру:
  • 1460 рядків — 1460 будинків у датасеті
  • 81 стовпець — 1 ідентифікатор (Id) + 79 ознак + 1 цільова змінна (SalePrice — ціна продажу)

Перший погляд — базові методи pandas

Почнемо з швидкого огляду структури даних.

Перші рядки датасету

In [2]:
# Перші 5 рядків
df.head()
Out[2]:
IdMSSubClassMSZoningLotFrontageLotAreaStreetAlleyLotShape...SalePrice
0160RL65.08450PaveNaNReg...208500
1220RL80.09600PaveNaNReg...181500
2360RL68.011250PaveNaNIR1...223500
3470RL60.09550PaveNaNIR1...140000
4560RL84.014260PaveNaNIR1...250000

5 rows × 81 columns

Що бачимо:

  • Багато стовпців (показано лише частину)
  • Різні типи даних: числа (LotArea — площа ділянки), текст (MSZoning — зона забудови), пропуски (NaN в Alley — тип під'їзного провулка)
  • Цільова змінна SalePrice (ціна продажу) — ціна в доларах США

Інформація про стовпці

In [3]:
# Детальна інформація про датасет
df.info()
Out[3]:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1460 entries, 0 to 1459
Data columns (total 81 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Id 1460 non-null int64
1 MSSubClass 1460 non-null int64
2 MSZoning 1460 non-null object
3 LotFrontage 1201 non-null float64
4 LotArea 1460 non-null int64
5 Street 1460 non-null object
6 Alley 91 non-null object
...
79 SaleType 1460 non-null object
80 SalePrice 1460 non-null int64
dtypes: float64(3), int64(35), object(43)
memory usage: 923.9+ KB
Ключові спостереження:
  • Типи даних:
    • int64 — цілі числа (35 стовпців)
    • float64 — дробові числа (3 стовпці)
    • object — текст/категорії (43 стовпці)
  • Пропуски:
    • LotFrontage (довжина фасаду ділянки): 1201 non-null → 259 пропусків (1460 - 1201)
    • Alley (тип під'їзного провулка): 91 non-null → 1369 пропусків! (майже 94%)

Статистичний опис числових ознак

In [4]:
# Статистика для числових стовпців
df.describe()
Out[4]:
IdMSSubClassLotFrontageLotArea...SalePrice
count1460.0000001460.0000001201.0000001460.000000...1460.000000
mean730.50000056.89726070.04995810516.828082...180921.195890
std421.61000942.30057124.2847529981.264932...79442.502883
min1.00000020.00000021.0000001300.000000...34900.000000
25%365.75000020.00000059.0000007553.500000...129975.000000
50%730.50000050.00000069.0000009478.500000...163000.000000
75%1095.25000070.00000080.00000011601.500000...214000.000000
max1460.000000190.000000313.000000215245.000000...755000.000000

8 rows × 38 columns

Інтерпретація статистики для цільової змінної SalePrice (ціна продажу):
  • Середня ціна: $180,921
  • Медіана (50%): $163,000 (нижча за середню → розподіл скошений вправо)
  • Мінімум: $34,900 (дуже дешевий будинок)
  • Максимум: $755,000 (дорогий будинок-викид)
  • Стандартне відхилення: $79,443 (велика варіація цін)

Аналіз пропусків (Missing Values)

Пропуски — одна з найбільших проблем реальних датасетів. Давайте виявимо всі стовпці з пропусками та оцінимо їх масштаб.

In [5]:
# Підрахунок пропусків для кожного стовпця
missing = df.isnull().sum()
missing = missing[missing > 0].sort_values(ascending=False)

# Відсоток пропусків
missing_percent = (missing / len(df)) * 100

# Об'єднати в DataFrame
missing_df = pd.DataFrame({
    'Стовпець': missing.index,
    'Пропусків': missing.values,
    'Відсоток': missing_percent.values
})

print(f"Стовпців з пропусками: {len(missing_df)}\n")
print(missing_df.head(10))
Out[5]:
Стовпців з пропусками: 19
Стовпець Пропусків Відсоток
0 PoolQC 1453 99.52
1 MiscFeature 1406 96.30
2 Alley 1369 93.77
3 Fence 1179 80.75
4 FireplaceQu 690 47.26
5 LotFrontage 259 17.74
6 GarageType 81 5.55
7 GarageYrBlt 81 5.55
8 GarageFinish 81 5.55
9 GarageQual 81 5.55
Критичні спостереження:
  • PoolQC (якість басейну): 99.5% пропусків → майже ніхто не має басейну
  • MiscFeature (додаткові зручності): 96.3% пропусків → сараї, тенісні корти тощо
  • Alley (тип під'їзного провулка): 93.8% пропусків → більшість будинків без провулка
  • Fence (наявність та якість огорожі): 80.8% пропусків
  • FireplaceQu (якість каміна): 47.3% пропусків → у багатьох будинках взагалі немає каміна
  • LotFrontage (лінійна довжина фасаду ділянки): 17.7% пропусків
  • Характеристики гаража (GarageType — тип гаража, GarageYrBlt — рік побудови гаража, GarageFinish — стан внутрішнього оздоблення, GarageQual — якість гаража): по 5.5% (81 будинок взагалі не має гаража)
Ці пропуски — не помилки, а реальність: якщо у будинку немає басейну/огорожі/провулка/гаража, значення не заповнене. Але для ML-моделі NaN — це проблема.Стратегія:
  • Стовпці з >50% пропусків → видалити або заповнити спеціальним значенням "None"
  • Стовпці з <20% пропусків → заповнити (imputation)

Візуалізація пропусків

In [6]:
# Графік пропусків
plt.figure(figsize=(12, 6))
plt.barh(range(len(missing_df)), missing_df['Відсоток'], color='coral', edgecolor='black')
plt.yticks(range(len(missing_df)), missing_df['Стовпець'])
plt.xlabel('Відсоток пропусків (%)', fontsize=12)
plt.title('Топ-19 стовпців з пропусками', fontsize=14, fontweight='bold')
plt.axvline(50, color='red', linestyle='--', linewidth=2, label='50% поріг')
plt.legend()
plt.gca().invert_yaxis()
plt.grid(axis='x', alpha=0.3)
plt.tight_layout()
plt.show()
Out[6]:

Аналіз цільової змінної — SalePrice (ціна продажу)

Це те, що ми хочемо передбачити. Важливо зрозуміти розподіл цін перед побудовою моделі.

Статистика та розподіл

In [7]:
# Базова статистика
print("Статистика SalePrice:")
print(f"  Середня:  ${df['SalePrice'].mean():,.0f}")
print(f"  Медіана:  ${df['SalePrice'].median():,.0f}")
print(f"  Мінімум:  ${df['SalePrice'].min():,.0f}")
print(f"  Максимум: ${df['SalePrice'].max():,.0f}")
print(f"  Std:      ${df['SalePrice'].std():,.0f}")

# Skewness (асиметрія)
skewness = df['SalePrice'].skew()
print(f"\nSkewness: {skewness:.4f}")
if skewness > 0.5:
    print("  → Розподіл скошений вправо (right-skewed)")
    print("  → Більшість будинків дешевші, є кілька дорогих")
Out[7]:
Статистика SalePrice:
Середня: $180,921
Медіана: $163,000
Мінімум: $34,900
Максимум: $755,000
Std: $79,443
Skewness: 1.8829
→ Розподіл скошений вправо (right-skewed)
→ Більшість будинків дешевші, є кілька дорогих

Гістограма розподілу цін

In [8]:
# Гістограма
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.hist(df['SalePrice'], bins=50, color='skyblue', edgecolor='black', alpha=0.7)
plt.axvline(df['SalePrice'].mean(), color='red', linestyle='--', linewidth=2, 
            label=f'Середня: ${df["SalePrice"].mean():,.0f}')
plt.axvline(df['SalePrice'].median(), color='green', linestyle='--', linewidth=2,
            label=f'Медіана: ${df["SalePrice"].median():,.0f}')
plt.xlabel('Ціна ($)', fontsize=11)
plt.ylabel('Кількість будинків', fontsize=11)
plt.title('Розподіл цін на будинки', fontsize=13, fontweight='bold')
plt.legend()
plt.grid(alpha=0.3)

# Box plot для виявлення викидів
plt.subplot(1, 2, 2)
plt.boxplot(df['SalePrice'], vert=False, patch_artist=True,
            boxprops=dict(facecolor='lightgreen', alpha=0.7),
            medianprops=dict(color='red', linewidth=2))
plt.xlabel('Ціна ($)', fontsize=11)
plt.title('Box Plot — виявлення викидів', fontsize=13, fontweight='bold')
plt.grid(alpha=0.3)

plt.tight_layout()
plt.show()
Out[8]:
Висновки з розподілу:
  1. Right-skewed — більшість будинків у діапазоні $100k-$200k
  2. Викиди — є будинки дорожче $500k (видно на box plot справа)
  3. Медіана < Середня — підтверджує скошеність розподілу
  4. Для ML: можливо, варто застосувати log-transformation для нормалізації (детально в статті 3.3)

Кореляційний аналіз — зв'язок з ціною

Найважливіше питання EDA: які ознаки найбільше впливають на ціну? Для цього обчислимо кореляцію між усіма числовими ознаками та цільовою змінною SalePrice (ціна продажу).

In [9]:
# Обчислення кореляції з ціною
numeric_cols = df.select_dtypes(include=['int64', 'float64']).columns
correlations = df[numeric_cols].corr()['SalePrice'].sort_values(ascending=False)

print("Топ-10 ознак з найбільшою позитивною кореляцією:\n")
print(correlations.head(11))  # 11, бо перший — сама ціна (1.0)

print("\n\nТоп-5 ознак з найбільшою негативною кореляцією:\n")
print(correlations.tail(5))
Out[9]:
Топ-10 ознак з найбільшою позитивною кореляцією:
SalePrice 1.000000
OverallQual 0.790982
GrLivArea 0.708624
GarageCars 0.640409
GarageArea 0.623431
TotalBsmtSF 0.613581
1stFlrSF 0.605852
FullBath 0.560664
TotRmsAbvGrd 0.533723
YearBuilt 0.522897
YearRemodAdd 0.507101
Name: SalePrice, dtype: float64
Топ-5 ознак з найбільшою негативною кореляцією:
KitchenAbvGr -0.135907
EnclosedPorch -0.128578
MSSubClass -0.084284
OverallCond -0.077856
YrSold -0.028923
Name: SalePrice, dtype: float64
Інтерпретація кореляції:
  • OverallQual (загальна якість матеріалів та оздоблення, 0.79) — має найсильніший позитивний зв'язок з ціною
  • GrLivArea (житлова площа над землею, 0.71) — на другому місці за силою впливу
  • GarageCars (місткість гаража, 0.64) та GarageArea (площа гаража, 0.62) — суттєво підвищують вартість
  • TotalBsmtSF (площа підвалу, 0.61) та 1stFlrSF (площа 1-го поверху, 0.61) — просторові метрики з високою кореляцією
  • FullBath (повноцінні ванні кімнати, 0.56) та TotRmsAbvGrd (кількість кімнат над землею, 0.53) — показники просторості
  • YearBuilt (рік побудови, 0.52) та YearRemodAdd (рік реконструкції, 0.51) — новіші та оновлені будинки коштують дорожче
  • Негативні кореляції слабкі (< -0.14, наприклад KitchenAbvGr (кількість кухонь вище рівня землі), EnclosedPorch (площа закритої веранди), MSSubClass (підклас типу будівлі)) — майже не мають лінійного зв'язку з ціною
Висновок: при побудові моделі варто зосередитись на топ-10 ознак з позитивною кореляцією (> 0.5).

Візуалізація кореляції (Bar Plot)

In [10]:
# Візуалізація топ-10 кореляцій
top_corr = correlations[1:11]  # без SalePrice (1.0)

plt.figure(figsize=(10, 6))
colors = ['forestgreen' if x > 0.6 else 'orange' for x in top_corr.values]
plt.barh(range(len(top_corr)), top_corr.values, color=colors, edgecolor='black')
plt.yticks(range(len(top_corr)), top_corr.index)
plt.xlabel('Кореляція з SalePrice', fontsize=12)
plt.title('Топ-10 ознак за кореляцією з ціною', fontsize=14, fontweight='bold')
plt.axvline(0.5, color='red', linestyle='--', linewidth=1.5, alpha=0.7, label='Поріг 0.5')
plt.gca().invert_yaxis()
plt.legend()
plt.grid(axis='x', alpha=0.3)
plt.tight_layout()
plt.show()
Out[10]:

Кореляційна матриця (Heatmap)

Для розуміння взаємозв'язків між усіма ознаками побудуємо heatmap топ-15 ознак.

In [11]:
# Топ-15 ознак за кореляцією з ціною + сама ціна
top_features = correlations[1:16].index.tolist() + ['SalePrice']
corr_matrix = df[top_features].corr()

# Побудова heatmap
plt.figure(figsize=(14, 12))
sns.heatmap(
    corr_matrix,
    annot=True,          # показувати числа
    fmt='.2f',           # формат: 2 знаки після коми
    cmap='coolwarm',     # колірна схема
    square=True,         # квадратні клітинки
    linewidths=0.5,      # лінії між клітинками
    cbar_kws={"shrink": 0.8},  # розмір колірної шкали
    vmin=-1, vmax=1      # діапазон від -1 до 1
)
plt.title('Кореляційна матриця топ-15 ознак', fontsize=15, fontweight='bold', pad=20)
plt.tight_layout()
plt.show()
Out[11]:
Виявлена мультиколінеарність (multicollinearity):
  • GarageCars (місткість гаража в авто) ↔ GarageArea (площа гаража): кореляція 0.88 (дуже сильна!)
  • TotalBsmtSF (загальна площа підвалу) ↔ 1stFlrSF (площа 1-го поверху): кореляція 0.82
  • GrLivArea (житлова площа над землею) ↔ TotRmsAbvGrd (загальна кількість кімнат над землею): кореляція 0.83
Що це означає? Ці ознаки дублюють одна одну (вимірюють майже те саме). Для лінійної регресії це може бути проблемою — модель стане нестабільною.Рішення: у наступних статтях або видалимо одну з корельованих ознак, або використаємо регуляризацію (Ridge/Lasso).

Scatter Plots — візуалізація зв'язків

Побудуємо точкові діаграми для топ-4 ознак vs ціна (SalePrice — ціна продажу), щоб побачити характер залежності.

In [12]:
# Топ-4 ознаки
top_4 = ['OverallQual', 'GrLivArea', 'GarageCars', 'TotalBsmtSF']

fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()

for i, col in enumerate(top_4):
    axes[i].scatter(df[col], df['SalePrice'], alpha=0.5, color='dodgerblue', edgecolor='black', s=30)
    axes[i].set_xlabel(col, fontsize=11)
    axes[i].set_ylabel('SalePrice ($)', fontsize=11)
    axes[i].set_title(f'{col} vs SalePrice (corr={correlations[col]:.3f})', 
                      fontsize=12, fontweight='bold')
    axes[i].grid(alpha=0.3, linestyle='--')

plt.suptitle('Scatter Plots: Топ-4 ознаки vs Ціна', fontsize=14, fontweight='bold', y=1.00)
plt.tight_layout()
plt.show()
Out[12]:
Що бачимо на графіках:
  1. OverallQual (загальна якість) vs SalePrice (ціна продажу) — чіткий позитивний лінійний зв'язок (якість ↑ → ціна ↑)
  2. GrLivArea (житлова площа) vs SalePrice (ціна продажу) — лінійна залежність, але є 2 викиди (дуже великі будинки з низькою ціною справа внизу)
  3. GarageCars (місткість гаража в авто) vs SalePrice (ціна продажу) — дискретні значення (0, 1, 2, 3, 4 машиномісця), позитивний зв'язок
  4. TotalBsmtSF (площа підвалу) vs SalePrice (ціна продажу) — лінійна залежність, багато будинків з площею підвалу = 0
Ці графіки підтверджують: лінійна регресія підійде для цієї задачі!

Виявлення викидів (Outliers)

Викиди — це екстремальні значення, що можуть спотворити модель. Використаємо box plot для їх виявлення в ключових ознаках: GrLivArea (житлова площа над землею), TotalBsmtSF (площа підвалу), LotArea (площа ділянки) та SalePrice (ціна продажу).

In [13]:
# Box plots для ключових ознак + ціна
outlier_features = ['GrLivArea', 'TotalBsmtSF', 'LotArea', 'SalePrice']

fig, axes = plt.subplots(1, 4, figsize=(16, 4))

for i, col in enumerate(outlier_features):
    bp = axes[i].boxplot(df[col].dropna(), patch_artist=True,
                          boxprops=dict(facecolor='lightyellow', alpha=0.7),
                          medianprops=dict(color='red', linewidth=2),
                          whiskerprops=dict(linewidth=1.5),
                          capprops=dict(linewidth=1.5))
    axes[i].set_ylabel(col, fontsize=11)
    axes[i].set_title(f'{col}', fontsize=12, fontweight='bold')
    axes[i].grid(axis='y', alpha=0.3)

plt.suptitle('Box Plots — виявлення викидів', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()
Out[13]:

Детальний аналіз викидів GrLivArea (житлова площа над землею)

In [14]:
# Будинки з площею > 4000 кв. футів
outliers = df[df['GrLivArea'] > 4000][['GrLivArea', 'SalePrice', 'OverallQual', 'Neighborhood']]

print(f"Виявлено {len(outliers)} будинків-викидів (GrLivArea > 4000):\n")
print(outliers)

print("\nСередня ціна всіх будинків: $", df['SalePrice'].mean())
print("Ціна викидів: ", outliers['SalePrice'].values)
Out[14]:
Виявлено 4 будинків-викидів (GrLivArea > 4000):
GrLivArea SalePrice OverallQual Neighborhood
523 4476 184750 5 Edwards
691 4676 755000 10 NridgHt
1182 5642 160000 4 Edwards
1298 4316 183850 5 Edwards
Середня ціна всіх будинків: $ 180921.19589041095
Ціна викидів: [184750 755000 160000 183850]
Спостереження:
  • Будинок #691: площа 4676 кв.фт, ціна $755k → нормальний дорогий будинок (OverallQual=10 — найвища якість матеріалів та оздоблення)
  • Будинки #1182 та #1298: площа >4000 кв.фт, але ціна $160k-$184k → аномалії!
    • Можливо, помилки в даних
    • Або особливі умови (наприклад, будинок потребує ремонту)
Рішення: при побудові моделі ці два будинки краще видалити, щоб вони не спотворювали результат.

Висновки з EDA — що ми дізналися?

Після повного розвідувального аналізу даних ми маємо чітку картину датасету Housing Prices:

📊 Структура даних

  • 1460 будинків, 80 ознак
  • 38 числових + 43 категоріальні
  • Цільова змінна: SalePrice (ціна продажу, від $35k до $755k)

❌ Проблеми виявлені

  1. Пропуски: 19 стовпців мають NaN (від 5% до 99%)
  2. Категорії: 43 текстові стовпці → потрібно кодувати
  3. Різні масштаби: GrLivArea (житлова площа, сотні/тисячі) vs YearBuilt (рік будівництва, тисячі) → потрібне масштабування
  4. Мультиколінеарність: GarageCars (місткість гаража) ↔ GarageArea (площа гаража) (0.88)
  5. Викиди: 2-4 аномальні будинки (великі, але дешеві)

🎯 Ключові ознаки

Топ-10 за кореляцією з ціною SalePrice:

  • OverallQual (загальна якість матеріалів): 0.79
  • GrLivArea (житлова площа над землею): 0.71
  • GarageCars (місткість гаража в авто): 0.64
  • GarageArea (площа гаража): 0.62
  • TotalBsmtSF (загальна площа підвалу): 0.61
  • 1stFlrSF (площа першого поверху): 0.61
  • FullBath (повноцінні ванні кімнати): 0.56
  • TotRmsAbvGrd (кількість кімнат над землею): 0.53
  • YearBuilt (рік будівництва): 0.52
  • YearRemodAdd (рік реконструкції): 0.51
План дій для наступних статей:
  1. Preprocessing (стаття 3):
    • Обробка пропусків (SimpleImputer)
    • Кодування категорій (one-hot encoding)
    • Масштабування ознак (StandardScaler)
    • Видалення викидів
  2. Feature Selection (стаття 4):
    • Відбір топ-15 ознак для моделі
    • Вирішення мультиколінеарності
  3. Modeling (статті 4-7):
    • Train/test split
    • Навчання моделі
    • Оцінка та покращення

Що далі?

У цій статті ми провели повний Exploratory Data Analysis реального датасету:

✅ Завантажили датасет Housing Prices (1460 будинків, 80 ознак)
✅ Виявили пропуски (19 стовпців з NaN, до 99%)
✅ Проаналізували розподіл цільової змінної (right-skewed)
✅ Обчислили кореляції (топ-10 ознак)
✅ Побудували візуалізації (heatmap, scatter, box plots)
✅ Виявили викиди та мультиколінеарність
✅ Сформулювали план preprocessing

У наступній статті ми перейдемо до Preprocessing (попередня обробка даних). Ми навчимося:

  • Заповнювати пропуски за допомогою SimpleImputer
  • Кодувати категоріальні ознаки (OneHotEncoder, pd.factorize)
  • Масштабувати числові ознаки (StandardScaler, MinMaxScaler)
  • Будувати preprocessing pipeline для автоматизації

Після цього дані будуть готові для навчання ML-моделі!


Практика


Резюме

EDA (Exploratory Data Analysis)

Розвідувальний аналіз даних — перший обов'язковий крок ML. Мета: зрозуміти структуру, виявити проблеми, знайти закономірності.

.info()

Показує типи даних, кількість non-null значень, використану пам'ять. Перше, що треба викликати після завантаження.

.describe()

Статистичний опис числових ознак: count, mean, std, min, quartiles, max. Швидкий огляд розподілу.

.isnull().sum()

Підрахунок пропусків для кожного стовпця. Критично для планування preprocessing.

.corr()

Кореляційна матриця — показує лінійні зв'язки між ознаками. Значення від -1 (негативна) до +1 (позитивна).

Heatmap

Візуалізація кореляційної матриці у вигляді кольорової карти. Червоний = позитивна, синій = негативна.

Scatter Plot

Точкова діаграма для візуалізації зв'язку між двома змінними. Дозволяє побачити лінійність, викиди.

Box Plot

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

Outliers

Викиди — аномальні значення, що сильно відрізняються від інших. Можуть спотворити модель.

Multicollinearity

Мультиколінеарність — сильна кореляція між ознаками (>0.8). Означає, що ознаки дублюють одна одну.
Copyright © 2026