Кафедра ШІзики

Якість даних - Фундамент хорошого ML

Кафедра ШІзики

Автор

25 хвилин

Час читання

28.10.2025

Дата публікації

Рівень:
Початківець
Теги: #якість-даних #очищення-даних #підготовка-даних #машинне-навчання #практика

📌 Новачок у Python? Ця стаття використовує приклади коду на Python. Якщо ви ще не працювали з Python, спочатку перегляньте наш посібник Налаштування Python для ML! Це займе 35 хвилин, і ви будете готові виконати весь код тут.

Якість даних - Фундамент хорошого ML 🧹

Є таке прислів’я в машинному навчанні: “Сміття на вході - сміття на виході” (Garbage in, garbage out).

Нагодуйте свою модель брудними даними з опечатками, відсутніми значеннями та дивними викидами - і ви отримаєте прогнози, які будуть такими ж брудними. Це як намагатися спекти торт з зіпсованих інгредієнтів. Неважливо, наскільки дорога ваша піч (алгоритм) - торт буде смаковитий жахливо.

Ось неприємна правда: дата-саєнтисти витрачають 80% свого часу на очищення та підготовку даних, а не на побудову вишуканих моделей. Так, ви правильно прочитали. Більшість роботи з ML - це не нейронні мережі або градієнтний бустинг - це виправлення опечаток, заповнення відсутніх значень та розбір хаосу.

Але ось хороша новина: чисті дані з простою моделлю завжди перемагають брудні дані зі складною моделлю. Опануйте якість даних, і ви вже на півдорозі до успіху в ML!

Сувора реальність: Ваші дані брудні 🤯

Історія: Катастрофа застосунку для знайомств

Уявіть застосунок для знайомств, який намагається побудувати систему рекомендацій. Вони зібрали дані з профілів користувачів:

Користувач #1:
Вік: 25
Зріст: 170 см
Місто: Київ
Інтереси: "походи, читання, кава"

Користувач #2:
Вік: 999
Зріст: -5 см
Місто: "у твоєї мами вдома лол"
Інтереси: [порожньо]

Користувач #3:
Вік: 18
Зріст: 6'2"
Місто: Kyiv
Інтереси: "походи кава КАВА походи читання походи"

Користувач #4:
Вік: 0
Зріст: null
Місто: "Київ, Україна, Земля"
Інтереси: "😎🏖️💪🎮"

Що пішло не так?

  • Користувач #2: Очевидно фейкові дані (жартівник або бот)
  • Користувач #3: Різні одиниці виміру (фути vs см), дублікати інтересів
  • Користувач #4: Невірний вік, відсутній зріст, надто детальне місто, емодзі замість тексту

І це після того, як користувачі заповнили форми! Уявіть, якщо ви парсите дані з дикого інтернету. 😱

Правило 80/20 машинного навчання

У кожному ML проєкті час зазвичай розподіляється так:

📊 Розподіл часу проєкту:

80% Робота з даними:
├─ 30% Пошук та збір даних
├─ 25% Очищення та виправлення проблем
├─ 15% Feature engineering
└─ 10% Розуміння того, що у вас є

20% Все інше:
├─ 10% Навчання моделей
├─ 5% Налаштування гіперпараметрів
└─ 5% Деплой та моніторинг

Більшість початківців думає, що ML - це про алгоритми. Помилка! ML - це про дані. Алгоритми - це легка частина - sklearn робить це за 3 рядки коду. Складна частина - це зробити ваші дані придатними до використання.

Типи проблем якості даних 🚨

Давайте дослідимо найпоширеніші проблеми, з якими ви зіткнетеся (спойлер: ви зіткнетеся з УСІМА ними).

1. Відсутні значення - Тихий вбивця 🕳️

Визначення: Дані, які повинні бути там… але їх немає.

Реальний приклад: Дані клієнтів електронної комерції

customer_idageincomeprevious_purchaseschurn
100132750005No
1002NaN12000012No
100345NaN3Yes
10042865000NaNNo
1005NaNNaN0Yes

Чому це відбувається?

  • Користувачі пропускають необов’язкові поля форми
  • Система збору даних зламалася
  • Обмеження конфіденційності (користувачі не хочуть ділитися доходом)
  • Нову функцію додали нещодавно (старі записи її не мають)
  • Інтеграція між системами зазнала невдачі

Проблема для ML:

Більшість алгоритмів не можуть працювати з NaN/null значеннями. Вони вилетять з помилками типу:

ValueError: Input contains NaN, infinity or a value too large

Ви повинні вирішити: видалити ці рядки? Заповнити чимось? Використати спеціальний алгоритм, який працює з відсутніми даними?

Стратегії обробки

Стратегія 1: Видалити рядок (Listwise Deletion)

# Видалити рядки з БУДЬ-ЯКИМ відсутнім значенням
clean_data = data.dropna()

✅ Плюси: Просто, чистий датасет
❌ Мінуси: Можете втратити 50%+ своїх даних!

Коли використовувати: Якщо відсутні дані рідкісні (<5%) і випадкові

Стратегія 2: Видалити колонку

# Видалити колонку, якщо >30% значень відсутні
clean_data = data.drop('income', axis=1)

✅ Плюси: Зберегти всі рядки
❌ Мінуси: Втратити потенційно цінну ознаку

Коли використовувати: Коли одна колонка має переважно відсутні дані

Стратегія 3: Заповнити статистикою

# Заповнити середнім (для числових даних)
data['age'].fillna(data['age'].mean(), inplace=True)

# Заповнити медіаною (краще для викидів)
data['income'].fillna(data['income'].median(), inplace=True)

# Заповнити модою (для категоріальних даних)
data['city'].fillna(data['city'].mode()[0], inplace=True)

✅ Плюси: Зберегти всі дані
❌ Мінуси: Може приховати патерни ("чому це відсутнє?")

Коли використовувати: Для числових ознак з <20% відсутніх

Стратегія 4: Створити категорію “Відсутнє”

# Для категоріальних даних зробити "відсутнє" валідною категорією
data['city'].fillna('Unknown', inplace=True)

✅ Плюси: Зберігає сигнал "відсутності"
❌ Мінуси: Створює штучну категорію

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

Стратегія 5: Передбачуюча імпутація

# Використовувати інші ознаки для передбачення відсутніх значень
from sklearn.impute import KNNImputer

imputer = KNNImputer(n_neighbors=5)
data_imputed = imputer.fit_transform(data)

✅ Плюси: Розумний, використовує патерни в даних
❌ Мінуси: Обчислювально затратний, може бути надто впевненим

Коли використовувати: Коли у вас є час і відсутність корелює з іншими ознаками


2. Дублікати - Монстр копі-паст 📋

Визначення: Одні й ті самі дані з’являються кілька разів (навмисно чи ні).

Реальний приклад: База даних реєстрації користувачів

emailnamesignup_dateпримітки
john@email.comJohn Smith2024-01-15
john@email.comJohn Smith2024-01-15Точний дублікат
john@email.comJohnny Smith2024-02-20Та сама людина, інше ім’я?
JOHN@EMAIL.COMJohn Smith2024-01-15Різниця в регістрі
john@email.comJohn Smth2024-01-15Опечатка в імені

Чому це відбувається?

  • Користувач клікнув “Відправити” кілька разів (нетерплячий!)
  • Баг системи під час імпорту даних
  • Злиття даних з кількох джерел
  • Немає обмеження унікальності в базі даних
  • Атаки ботів

Проблема для ML:

  • Надмірно представляє певні точки даних
  • Зміщує модель до дубльованих прикладів
  • Штучно збільшує розмір датасету
  • Псує розбиття train/test (одні дані в обох!)

Стратегії обробки

Стратегія 1: Точні дублікати

# Видалити точні дублікати
data_clean = data.drop_duplicates()

# Або тільки в конкретних колонках
data_clean = data.drop_duplicates(subset=['email'])

✅ Просто і безпечно

Стратегія 2: Нечіткі дублікати (Приблизне співпадіння)

# Для схожості тексту
from difflib import SequenceMatcher

def similar(a, b):
    return SequenceMatcher(None, a, b).ratio() > 0.9

# Знайти схожі імена
for i in range(len(data)):
    for j in range(i+1, len(data)):
        if similar(data['name'][i], data['name'][j]):
            print(f"Можливий дублікат: {data['name'][i]}{data['name'][j]}")

⚠️ Потребує ручного перегляду

Коли використовувати: Текстові дані з опечатками, різними форматами

Краща практика:

# Перед видаленням дублікатів
print(f"Оригінальний розмір: {len(data)}")
print(f"Унікальні email: {data['email'].nunique()}")

# Видалити
data_clean = data.drop_duplicates(subset=['email'], keep='first')

print(f"Після дедуплікації: {len(data_clean)}")
print(f"Видалено: {len(data) - len(data_clean)} дублікатів ({100*(len(data)-len(data_clean))/len(data):.1f}%)")

Завжди логуйте що ви видалили для аудиту!


3. Неузгоджене форматування - Король хаосу 👑

Визначення: Одна і та ж інформація зберігається різними способами.

Реальний приклад: Категорії товарів

product          | category
Ноутбук Pro 15"  | Електроніка
iPhone 14        | електроніка  # малі літери
Samsung TV       | ЕЛЕКТРОНІКА  # великі літери
iPad Air         | Електроніка > Планшети  # ієрархія
AirPods Pro      | Побутова електроніка  # детальніше
MacBook          | Техніка / Електроніка  # альтернативний роздільник
Smart Watch      | Носимі пристрої, Електроніка  # кілька категорій

Сім різних способів сказати “Електроніка”! 🤦‍♂️

Більше прикладів

Дати:

2024-01-15      # ISO формат
01/15/2024      # Американський формат
15/01/2024      # Європейський формат
15-Jan-2024     # Текстовий місяць
Jan 15, 2024    # Повний текст
1705276800      # Unix timestamp

Номери телефонів:

+38 (050) 123-45-67
+380501234567
050-123-45-67
0501234567
(050) 123-45-67

Адреси:

вул. Хрещатик 1, Київ, 01001
вулиця Хрещатик, буд. 1, м. Київ, 01001
хрещатик 1, київ, 01001

Проблема для ML:

Модель бачить це як абсолютно різні значення, хоча вони означають одне й те саме!

Стратегії обробки

Стратегія 1: Стандартизація

# Перетворити в малі літери
data['category'] = data['category'].str.lower()

# Видалити зайві пробіли
data['category'] = data['category'].str.strip()

# Замінити синоніми
category_map = {
    'електроніка': 'електроніка',
    'техніка': 'електроніка',
    'побутова електроніка': 'електроніка',
    'електронний': 'електроніка'
}
data['category'] = data['category'].map(category_map).fillna(data['category'])

✅ Створює узгоджений формат

Стратегія 2: Парсинг та переформатування

import pandas as pd

# Дати: конвертувати все в datetime
data['date'] = pd.to_datetime(data['date'], infer_datetime_format=True)

# Потім форматувати однаково
data['date_str'] = data['date'].dt.strftime('%Y-%m-%d')

# Номери телефонів: видалити всі нецифри
data['phone'] = data['phone'].str.replace(r'[^0-9]', '', regex=True)

✅ Обробляє кілька вхідних форматів

Стратегія 3: Валідація та відхилення

# Визначити валідні категорії
VALID_CATEGORIES = ['електроніка', 'одяг', 'їжа', 'книги']

# Позначити невалідні записи
data['category_valid'] = data['category'].isin(VALID_CATEGORIES)

# Обробити невалідні
data.loc[~data['category_valid'], 'category'] = 'інше'

✅ Забезпечує якість даних на вході

4. Викиди та помилки - Бешкетники 🎭

Визначення: Значення, які технічно можливі, але практично безглузді.

Реальний приклад: Застосунок для викликання авто

trip_iddistance_kmduration_minfare_usdspeed_kmhпримітки
15.21812.5017.3Нормальна поїздка
20.1458.000.13Застрягли в пробці?
385012015.00425Надзвуковий автомобіль?!
4-3.2105.00-19.2Негативна відстань?
512.5022.00Телепортація?

Чому це відбувається?

  • Помилки GPS: Тунелі, втрата сигналу, міські каньйони
  • Баги системи: Ділення на нуль, переповнення типу даних
  • Людська помилка: Помилки ручного введення
  • Тестові дані: Інженери забули видалити тестові записи
  • Шахрайство: Водії/користувачі грають з системою

Проблема для ML:

  • Викривляє статистику (середнє, стандартне відхилення)
  • Спотворює навчання моделі (сприймає помилки як патерни)
  • Ламає алгоритми (нескінченність, негативні значення де неможливо)

Стратегії обробки

Стратегія 1: Статистичне виявлення

import numpy as np

# Метод 1: Z-score (скільки стандартних відхилень)
from scipy import stats

z_scores = np.abs(stats.zscore(data['fare_usd']))
outliers = z_scores > 3  # Далі 3 стандартних відхилень

print(f"Знайдено {outliers.sum()} викидів")

# Метод 2: IQR (Міжквартильний розмах)
Q1 = data['fare_usd'].quantile(0.25)
Q3 = data['fare_usd'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

outliers = (data['fare_usd'] < lower_bound) | (data['fare_usd'] > upper_bound)

✅ Працює для нормально розподілених даних
❌ Може позначити валідні екстремальні значення

Стратегія 2: Правила на основі доменних знань

# На основі бізнес-логіки
invalid_trips = (
    (data['distance_km'] < 0) |           # Негативна відстань неможлива
    (data['distance_km'] > 500) |         # 500км надто далеко для міської поїздки
    (data['duration_min'] <= 0) |         # Нульовий час неможливий
    (data['fare_usd'] < 2.50) |           # Мінімальний тариф
    (data['fare_usd'] > 1000) |           # Підозріло дорого
    (data['speed_kmh'] > 120)             # Обмеження швидкості 100
)

print(f"Знайдено {invalid_trips.sum()} невалідних поїздок")

# Позначити їх
data['is_valid'] = ~invalid_trips

✅ Використовує бізнес-логіку
✅ Пояснюване

Стратегія 3: Візуалізація

import matplotlib.pyplot as plt

# Box plot для виявлення викидів
data['fare_usd'].plot(kind='box')
plt.title('Розподіл тарифів')
plt.show()

# Scatter plot для відношень
plt.scatter(data['distance_km'], data['fare_usd'])
plt.xlabel('Відстань (км)')
plt.ylabel('Тариф (USD)')
plt.title('Відстань vs Тариф')
plt.show()

✅ Візуальна перевірка ловить дивні патерни

Що робити з викидами:

  1. Видалити їх - Якщо явно помилки
  2. Обмежити їх - Замінити максимальним розумним значенням
  3. Залишити їх - Якщо справді цікаві (як сплеск продажів на Чорну п’ятницю)
  4. Дослідити - Може виявити баги або шахрайство
# Обмеження (Winsorization)
upper_limit = data['fare_usd'].quantile(0.99)
data['fare_usd_capped'] = data['fare_usd'].clip(upper=upper_limit)

5. Проблеми з типами даних - Плутанина типів 🔢

Визначення: Дані зберігаються у неправильному форматі або типі.

Реальний приклад: Поле віку

age
25
"32"        # Рядок замість числа
"сорок два" # Текст
None        # Відсутнє
25.5        # Десяткове (віки зазвичай цілі числа)
"25 років"  # З одиницями
-5          # Негативний (помилка)
999         # Значення за замовчуванням для відсутніх?

Проблема:

  • Не можна виконувати математику з рядками
  • Не можна категоризувати числа
  • Алгоритми очікують специфічні типи

Стратегії обробки

# Конвертувати типи
data['age'] = pd.to_numeric(data['age'], errors='coerce')  # Нечислові → NaN

# Потім очистити
data = data[data['age'] > 0]          # Видалити негативні
data = data[data['age'] < 120]        # Видалити неможливі
data['age'] = data['age'].astype(int) # Конвертувати в ціле

# Для категоріальних
data['category'] = data['category'].astype('category')

✅ Забезпечує узгодженість типів

Чек-лист якості даних ✅

Перед навчанням БУДЬ-ЯКОЇ моделі пройдіться по цьому чек-листу:

1. Повнота

# Перевірити відсутні значення
print(data.isnull().sum())
print(f"Відсоток відсутніх:\n{data.isnull().mean() * 100}")

# Перевірити порожні рядки
print((data == '').sum())

Пункти дій:

  • Жодна колонка не має >30% відсутніх значень
  • Відсутні значення оброблені (видалені/заповнені)
  • Задокументовано чому значення відсутні

2. Унікальність

# Перевірити дублікати
print(f"Всього рядків: {len(data)}")
print(f"Унікальні рядки: {len(data.drop_duplicates())}")
print(f"Дублікати: {len(data) - len(data.drop_duplicates())}")

# Перевірити унікальність ID
print(f"Унікальні ID: {data['id'].nunique()} з {len(data)}")

Пункти дій:

  • Дублікати видалені або обґрунтовані
  • ID колонки дійсно унікальні
  • Тестові дані не змішані з реальними

3. Узгодженість

# Перевірити типи даних
print(data.dtypes)

# Перевірити формати значень
print(data['phone'].value_counts()[:10])  # Побачити варіації формату
print(data['date'].value_counts()[:10])

Пункти дій:

  • Всі дати в одному форматі
  • Весь текст в одному регістрі (зазвичай малі літери)
  • Категоріальні значення стандартизовані
  • Одиниці узгоджені (всі км, не мікс км/милі)

4. Валідність

# Перевірити діапазони
print(data.describe())

# Перевірити неможливі значення
print(f"Негативні віки: {(data['age'] < 0).sum()}")
print(f"Майбутні дати: {(data['date'] > pd.Timestamp.now()).sum()}")

Пункти дій:

  • Немає неможливих значень (негативні віки, майбутні дати)
  • Значення в очікуваних діапазонах
  • Немає значень-заповнювачів (999, -1, “N/A”)

5. Точність

# Вибірка випадкових рядків та ручна перевірка
print(data.sample(10))

# Перевірка з відомою правдою
# (наприклад, загальні продажі повинні збігатися з обліковими записами)

Пункти дій:

  • Точкова перевірка випадкових зразків
  • Агрегати збігаються з відомими сумами
  • Перехресна перевірка з іншими джерелами даних

Реальний кейс: Очищення брудних даних клієнтів 📊

Ситуація

Компанія з підпискових коробок має дані клієнтів за 3 роки. Вони хочуть передбачити відтік (скасування). Давайте очистимо їхні дані!

Сирі дані (Перші 5 рядків)

customer_idsignup_dateagecityplanmonthly_feestatusпримітки
10012021-15-0332київpremium29.99active
10012021-15-0332київpremium29.99activeдублікат
100215/03/2021NaNКИЇВbasic$14.99active
10032021-03-15150львівPremium29.99canceled
1004null28lvivbasicnullactive

Покрокове очищення

Крок 1: Завантажити та перевірити

import pandas as pd

# Завантажити дані
data = pd.read_csv('customers.csv')

print(f"Розмір: {data.shape}")
print(f"\nІнфо:")
print(data.info())
print(f"\nВідсутні значення:")
print(data.isnull().sum())
print(f"\nДублікати: {data.duplicated().sum()}")

Крок 2: Видалити точні дублікати

before = len(data)
data = data.drop_duplicates()
after = len(data)

print(f"Видалено {before - after} дублікатів ({100*(before-after)/before:.1f}%)")

Крок 3: Виправити дати

# Конвертувати всі формати дат в datetime
data['signup_date'] = pd.to_datetime(data['signup_date'], errors='coerce')

# Видалити невалідні дати
data = data[data['signup_date'].notnull()]

print(f"Залишилось {len(data)} рядків з валідними датами")

Крок 4: Очистити вік

# Заповнити відсутні віки медіаною
median_age = data['age'].median()
data['age'].fillna(median_age, inplace=True)

# Виправити викиди (обмежити розумним діапазоном)
data.loc[data['age'] < 18, 'age'] = 18
data.loc[data['age'] > 100, 'age'] = 100

print(f"Діапазон віку: {data['age'].min()} - {data['age'].max()}")

Крок 5: Стандартизувати текст

# Місто: малі літери та мапити загальні варіації
data['city'] = data['city'].str.lower().str.strip()

city_map = {
    'lviv': 'львів',
    'kyiv': 'київ'
}
data['city'] = data['city'].replace(city_map)

# План: стандартизувати регістр
data['plan'] = data['plan'].str.lower()

# Статус: стандартизувати
data['status'] = data['status'].str.lower()

print(f"\nУнікальні міста: {data['city'].unique()}")
print(f"Унікальні плани: {data['plan'].unique()}")

Крок 6: Виправити грошові значення

# Видалити $ та конвертувати у float
data['monthly_fee'] = data['monthly_fee'].replace('[\$,]', '', regex=True)
data['monthly_fee'] = pd.to_numeric(data['monthly_fee'], errors='coerce')

# Заповнити відсутні тарифи на основі плану
plan_fees = data.groupby('plan')['monthly_fee'].median()
data['monthly_fee'] = data.groupby('plan')['monthly_fee'].transform(
    lambda x: x.fillna(x.median())
)

print(f"\nТарифи по планах:\n{plan_fees}")

Крок 7: Фінальна валідація

# Створити звіт якості даних
print("\n=== ЗВІТ ЯКОСТІ ДАНИХ ===")
print(f"Всього рядків: {len(data)}")
print(f"Діапазон дат: {data['signup_date'].min()} до {data['signup_date'].max()}")
print(f"Діапазон віку: {data['age'].min()} до {data['age'].max()}")
print(f"Відсутні значення:\n{data.isnull().sum()}")
print(f"\nРозподіл значень:")
print(f"Міста:\n{data['city'].value_counts()}")
print(f"\nПлани:\n{data['plan'].value_counts()}")
print(f"\nСтатус:\n{data['status'].value_counts()}")

Крок 8: Зберегти чисті дані

# Зберегти очищену версію
data.to_csv('customers_clean.csv', index=False)

print("\n✅ Очищення даних завершено!")
print(f"Чисті дані збережені в customers_clean.csv")

Поширені помилки, яких слід уникати ⚠️

1. Очищення перед розбиттям

# ❌ НЕПРАВИЛЬНО: Спочатку очистити весь датасет
data_clean = clean_data(data)
train, test = split(data_clean)

# ✅ ПРАВИЛЬНО: Спочатку розбити, потім очистити train і test окремо
train, test = split(data)
train_clean = clean_data(train)
test_clean = clean_data(test)

Чому? Рішення про очищення (як імпутація середнім) повинні використовувати тільки тренувальні дані, щоб уникнути витоку даних!

2. Видалення занадто багато даних

# ❌ Видалення будь-якого рядка з БУДЬ-ЯКИМ відсутнім значенням
data_clean = data.dropna()  # Втратили 80% даних!

# ✅ Розумніший підхід
# Видалити колонки з >50% відсутніх
cols_to_keep = data.columns[data.isnull().mean() < 0.5]
data = data[cols_to_keep]

# Потім заповнити решту відсутніх значень
data = impute(data)

3. Недокументування змін

# ❌ Просто тихо очищаємо
data['age'].fillna(30, inplace=True)

# ✅ Документуємо все
log_cleaning_step("age", "заповнено відсутні", f"використано медіану: {data['age'].median()}")
data['age'].fillna(data['age'].median(), inplace=True)

4. Ігнорування доменних знань

# ❌ Сліпе використання статистичних методів
data = data[data['income'] < data['income'].quantile(0.99)]  # Обмежити 99-м персентилем

# ✅ Використовувати бізнес-логіку
data = data[data['income'] < 500000]  # Жоден клієнт не заробляє >500k (ми продаємо піцу, не яхти!)

Золоті правила якості даних 🏆

  1. Починайте з якості даних, не з алгоритмів

    • Проста модель на чистих даних перемагає складну модель на брудних даних
  2. Візуалізуйте до і після

    • Завжди будуйте графіки ваших даних до та після очищення
    • Допомагає знайти помилки
  3. Документуйте все

    • Кожне рішення про очищення має бути залоговане
    • Майбутній ви подякує теперішньому вам
  4. Ніколи не видаляйте оригінальні дані

    • Зберігайте сирі дані незмінними
    • Створюйте очищену версію окремо
  5. Автоматизуйте конвеєр

    • Перетворіть кроки очищення на багаторазові функції
    • Ви запускатимете це багато разів
  6. Валідуйте постійно

    • Перевіряйте якість даних на кожному етапі
    • Налаштуйте автоматичні сповіщення про погані дані в продакшені

Інструменти та бібліотеки 🛠️

Бібліотеки Python

# Основні
import pandas as pd
import numpy as np

# Візуалізація
import matplotlib.pyplot as plt
import seaborn as sns

# Поглиблене очищення
from sklearn.impute import SimpleImputer, KNNImputer
from sklearn.preprocessing import StandardScaler

# Спеціалізовані
import missingno as msno  # Візуалізувати відсутні дані
import pandas_profiling  # Автоматичний звіт якості даних

Швидкий звіт якості даних

# Встановити: pip install pandas-profiling
from pandas_profiling import ProfileReport

profile = ProfileReport(data, title='Звіт якості даних')
profile.to_file("data_quality_report.html")

# Відкриває інтерактивний HTML звіт з:
# - Візуалізація відсутніх значень
# - Матриця кореляції
# - Графіки розподілу
# - Виявлення дублікатів
# - і багато іншого!

Підсумок: Ваш процес очищення даних 🎯

1. Завантажити та перевірити
   ├─ Перевірити форму та типи
   ├─ Подивитись перші/останні рядки
   ├─ Отримати підсумкову статистику
   └─ Порахувати відсутні значення

2. Обробити дублікати
   ├─ Видалити точні дублікати
   ├─ Ідентифікувати нечіткі дублікати
   └─ Задокументувати видалення

3. Виправити відсутні значення
   ├─ Зрозуміти чому відсутні
   ├─ Вирішити стратегію для кожної колонки
   └─ Заповнити або видалити

4. Стандартизувати формати
   ├─ Дати → datetime
   ├─ Текст → малі літери
   ├─ Категорії → стандартні назви
   └─ Числа → правильні типи

5. Обробити викиди
   ├─ Виявити за допомогою статистики/візуалізації
   ├─ Дослідити причину
   └─ Обмежити, видалити або залишити

6. Валідувати
   ├─ Перевірити діапазони
   ├─ Перевірити узгодженість
   ├─ Зразковий ручний огляд
   └─ Створити звіт якості

7. Документувати та зберегти
   ├─ Залогувати всі трансформації
   ├─ Зберегти конвеєр очищення
   └─ Експортувати чисті дані

Що далі? 🚀

Тепер, коли ваші дані чисті, ви готові зрозуміти їх глибоко! У наступній статті ми дослідимо Дослідницький аналіз даних (EDA) - мистецтво виявлення патернів, зв’язків та інсайтів, прихованих у ваших даних через візуалізацію та статистику.

Пам’ятайте: Чисті дані - це фундамент. Все інше будується поверх нього. Витратьте час тут, і ваші моделі подякують вам пізніше!

Удачі в очищенні! 🧹✨