Якість даних - Фундамент хорошого 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_id | age | income | previous_purchases | churn |
|---|---|---|---|---|
| 1001 | 32 | 75000 | 5 | No |
| 1002 | NaN | 120000 | 12 | No |
| 1003 | 45 | NaN | 3 | Yes |
| 1004 | 28 | 65000 | NaN | No |
| 1005 | NaN | NaN | 0 | Yes |
Чому це відбувається?
- Користувачі пропускають необов’язкові поля форми
- Система збору даних зламалася
- Обмеження конфіденційності (користувачі не хочуть ділитися доходом)
- Нову функцію додали нещодавно (старі записи її не мають)
- Інтеграція між системами зазнала невдачі
Проблема для 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. Дублікати - Монстр копі-паст 📋
Визначення: Одні й ті самі дані з’являються кілька разів (навмисно чи ні).
Реальний приклад: База даних реєстрації користувачів
| name | signup_date | примітки | |
|---|---|---|---|
| john@email.com | John Smith | 2024-01-15 | |
| john@email.com | John Smith | 2024-01-15 | Точний дублікат |
| john@email.com | Johnny Smith | 2024-02-20 | Та сама людина, інше ім’я? |
| JOHN@EMAIL.COM | John Smith | 2024-01-15 | Різниця в регістрі |
| john@email.com | John Smth | 2024-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_id | distance_km | duration_min | fare_usd | speed_kmh | примітки |
|---|---|---|---|---|---|
| 1 | 5.2 | 18 | 12.50 | 17.3 | Нормальна поїздка |
| 2 | 0.1 | 45 | 8.00 | 0.13 | Застрягли в пробці? |
| 3 | 850 | 120 | 15.00 | 425 | Надзвуковий автомобіль?! |
| 4 | -3.2 | 10 | 5.00 | -19.2 | Негативна відстань? |
| 5 | 12.5 | 0 | 22.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()
✅ Візуальна перевірка ловить дивні патерниЩо робити з викидами:
- Видалити їх - Якщо явно помилки
- Обмежити їх - Замінити максимальним розумним значенням
- Залишити їх - Якщо справді цікаві (як сплеск продажів на Чорну п’ятницю)
- Дослідити - Може виявити баги або шахрайство
# Обмеження (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_id | signup_date | age | city | plan | monthly_fee | status | примітки |
|---|---|---|---|---|---|---|---|
| 1001 | 2021-15-03 | 32 | київ | premium | 29.99 | active | |
| 1001 | 2021-15-03 | 32 | київ | premium | 29.99 | active | дублікат |
| 1002 | 15/03/2021 | NaN | КИЇВ | basic | $14.99 | active | |
| 1003 | 2021-03-15 | 150 | львів | Premium | 29.99 | canceled | |
| 1004 | null | 28 | lviv | basic | null | active |
Покрокове очищення
Крок 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 (ми продаємо піцу, не яхти!)Золоті правила якості даних 🏆
-
Починайте з якості даних, не з алгоритмів
- Проста модель на чистих даних перемагає складну модель на брудних даних
-
Візуалізуйте до і після
- Завжди будуйте графіки ваших даних до та після очищення
- Допомагає знайти помилки
-
Документуйте все
- Кожне рішення про очищення має бути залоговане
- Майбутній ви подякує теперішньому вам
-
Ніколи не видаляйте оригінальні дані
- Зберігайте сирі дані незмінними
- Створюйте очищену версію окремо
-
Автоматизуйте конвеєр
- Перетворіть кроки очищення на багаторазові функції
- Ви запускатимете це багато разів
-
Валідуйте постійно
- Перевіряйте якість даних на кожному етапі
- Налаштуйте автоматичні сповіщення про погані дані в продакшені
Інструменти та бібліотеки 🛠️
Бібліотеки 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) - мистецтво виявлення патернів, зв’язків та інсайтів, прихованих у ваших даних через візуалізацію та статистику.
Пам’ятайте: Чисті дані - це фундамент. Все інше будується поверх нього. Витратьте час тут, і ваші моделі подякують вам пізніше!
Удачі в очищенні! 🧹✨