← Назад к вопросам
Какие знаешь методы очистки данных?
1.0 Junior🔥 181 комментариев
#Pandas и обработка данных#Python и программирование#Опыт работы и проекты
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Методы очистки данных (Data Cleaning) для Data Analyst
Очистка данных — это один из самых критичных процессов в аналитике. Грязные данные приводят к неверным выводам. По статистике, Data Analyst тратит 60-80% времени на очистку и подготовку данных.
1. Обработка пропущенных значений (Missing Values)
Типы пропусков
import pandas as pd
import numpy as np
# Создадим DataFrame с пропусками
df = pd.DataFrame({
'name': ['Alice', 'Bob', np.nan, 'David'],
'age': [25, None, 30, np.nan],
'salary': [50000, 60000, np.nan, 70000]
})
print(df.isnull())
print(df.isnull().sum()) # Подсчет пропусков
Методы обработки
# 1. Удаление строк с пропусками
df_dropped = df.dropna() # удалить все строки с хотя бы одним пропуском
df_dropped = df.dropna(subset=['name']) # удалить если пропуск в 'name'
# 2. Удаление столбца, если много пропусков
df_cleaned = df.dropna(axis=1, thresh=len(df)*0.7) # оставить столбцы с 70%+ данных
# 3. Заполнение констаными значениями
df_filled = df.fillna(0) # заполнить нули
df_filled = df.fillna(df.mean()) # заполнить средним значением
df_filled = df.fillna(method='ffill') # заполнить предыдущим значением (forward fill)
# 4. Интерполяция (для временных рядов)
df_interpolated = df.interpolate(method='linear')
# 5. Заполнение с условием
df['salary'] = df['salary'].fillna(df['salary'].median())
SQL подход
-- Выявить пропуски
SELECT COUNT(*) - COUNT(age) as missing_age
FROM users;
-- Удалить строки с пропусками
DELETE FROM users WHERE age IS NULL OR email IS NULL;
-- Заполнить значением
UPDATE users SET phone = '+7-000-0000' WHERE phone IS NULL;
-- Заменить на среднее
UPDATE products
SET price = (SELECT AVG(price) FROM products WHERE price IS NOT NULL)
WHERE price IS NULL;
2. Выявление и обработка выбросов (Outliers)
Метод межквартильного размаха (IQR)
# Выявление выбросов
Q1 = df['salary'].quantile(0.25)
Q3 = df['salary'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df['salary'] < lower_bound) | (df['salary'] > upper_bound)]
print(f"Найденные выбросы: {len(outliers)}")
# Удаление выбросов
df_no_outliers = df[(df['salary'] >= lower_bound) & (df['salary'] <= upper_bound)]
# Или обрезание (capping)
df['salary'] = df['salary'].clip(lower=lower_bound, upper=upper_bound)
Метод Z-score
from scipy import stats
# Z-score: стандартное отклонение от среднего
z_scores = np.abs(stats.zscore(df['salary']))
# Выбросы > 3 стандартных отклонений
outliers = df[z_scores > 3]
df_clean = df[z_scores <= 3]
SQL для выявления выбросов
-- Выявить аномально высокие зарплаты
WITH salary_stats AS (
SELECT
AVG(salary) as mean,
STDDEV(salary) as stddev
FROM employees
)
SELECT e.name, e.salary
FROM employees e, salary_stats s
WHERE ABS((e.salary - s.mean) / s.stddev) > 3;
3. Дублирование (Duplicates)
# Выявление дубликатов
duplicates = df[df.duplicated(keep=False)]
print(f"Дубликаты: {len(duplicates)}")
# Удаление дубликатов
df_unique = df.drop_duplicates()
# Удаление дубликатов по конкретным столбцам
df_unique = df.drop_duplicates(subset=['email'])
# Оставить первое/последнее вхождение
df_unique = df.drop_duplicates(subset=['email'], keep='first')
df_unique = df.drop_duplicates(subset=['email'], keep='last')
SQL
-- Выявить дубликаты
SELECT email, COUNT(*) as count
FROM users
GROUP BY email
HAVING COUNT(*) > 1;
-- Удалить дубликаты (оставить первый ID)
DELETE FROM users
WHERE id NOT IN (
SELECT MIN(id)
FROM users
GROUP BY email
);
4. Нормализация и форматирование данных
Приведение к нижнему/верхнему регистру
df['email'] = df['email'].str.lower()
df['name'] = df['name'].str.upper()
df['status'] = df['status'].str.strip() # удалить пробелы
Нормализация в диапазон [0, 1]
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
df['salary_normalized'] = scaler.fit_transform(df[['salary']])
# Или вручную
df['salary_norm'] = (df['salary'] - df['salary'].min()) / (df['salary'].max() - df['salary'].min())
Стандартизация (Z-score normalization)
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df['salary_standard'] = scaler.fit_transform(df[['salary']])
# Или вручную
df['salary_std'] = (df['salary'] - df['salary'].mean()) / df['salary'].std()
Форматирование дат
# Парсинг дат
df['order_date'] = pd.to_datetime(df['order_date'], format='%d/%m/%Y')
# Извлечение компонентов
df['year'] = df['order_date'].dt.year
df['month'] = df['order_date'].dt.month
df['day_of_week'] = df['order_date'].dt.day_name()
# Форматирование вывода
df['date_formatted'] = df['order_date'].dt.strftime('%Y-%m-%d')
5. Обработка категориальных данных
Исправление опечаток
# Заменить значения
df['status'] = df['status'].replace({
'complited': 'completed',
'panding': 'pending',
'canelled': 'cancelled'
})
# Использовать FuzzyWuzzy для похожих строк
from fuzzywuzzy import fuzz
from fuzzywuzzy import process
# Найти близкие варианты
choices = ['completed', 'pending', 'cancelled']
df['status_corrected'] = df['status'].apply(
lambda x: process.extractOne(x, choices)[0] if pd.notna(x) else None
)
One-Hot Encoding
# Преобразовать категории в бинарные столбцы
df_encoded = pd.get_dummies(df, columns=['status'])
print(df_encoded)
# Результат будет status_completed, status_pending, status_cancelled
Label Encoding
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
df['status_encoded'] = le.fit_transform(df['status'])
print(dict(zip(le.classes_, le.transform(le.classes_))))
6. Валидация данных
# Проверка типов
assert df['age'].dtype == 'int64', "Age должен быть целым числом"
# Проверка диапазонов
assert (df['age'] >= 0).all() and (df['age'] <= 120).all(), "Возраст вне диапазона"
# Проверка уникальности
assert df['email'].nunique() == len(df), "Есть дубликаты email"
# Проверка обязательных полей
assert df['email'].notna().all(), "Есть пропуски в email"
# Валидация email
import re
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
df['email_valid'] = df['email'].str.match(pattern)
SQL валидация
-- Проверить ограничения
ALTER TABLE users ADD CONSTRAINT check_age
CHECK (age >= 0 AND age <= 120);
-- Выявить невалидные данные
SELECT * FROM users WHERE age < 0 OR age > 120;
-- Удалить невалидные
DELETE FROM users WHERE email NOT LIKE '%@%';
7. Консолидация и трансформация данных
Объединение данных из разных источников
# Слияние DataFrame
df_result = pd.merge(df_users, df_orders, on='user_id', how='left')
# Конкатенация
df_combined = pd.concat([df_sales_2023, df_sales_2024])
# Объединение с удалением дубликатов
df_unique = pd.concat([df1, df2]).drop_duplicates()
Расстаянные операции
# Melt: преобразить столбцы в строки
df_melted = df.melt(id_vars=['name'], var_name='month', value_name='sales')
# Pivot: преобразить строки в столбцы
df_pivot = df.pivot_table(
index='name',
columns='month',
values='sales',
aggfunc='sum'
)
8. Автоматизация очистки
class DataCleaner:
def __init__(self, df):
self.df = df
def remove_nulls(self, subset=None):
self.df = self.df.dropna(subset=subset)
return self
def remove_duplicates(self, subset=None):
self.df = self.df.drop_duplicates(subset=subset)
return self
def remove_outliers(self, column, method='iqr'):
if method == 'iqr':
Q1 = self.df[column].quantile(0.25)
Q3 = self.df[column].quantile(0.75)
IQR = Q3 - Q1
self.df = self.df[
(self.df[column] >= Q1 - 1.5 * IQR) &
(self.df[column] <= Q3 + 1.5 * IQR)
]
return self
def get_result(self):
return self.df
# Использование
cleaner = DataCleaner(df)
df_clean = (cleaner
.remove_nulls()
.remove_duplicates()
.remove_outliers('salary')
.get_result())
Чеклист очистки данных
- ✓ Проверить пропуски (NULL, NaN)
- ✓ Выявить выбросы (outliers)
- ✓ Удалить/обработать дубликаты
- ✓ Нормализовать текст (case, пробелы)
- ✓ Привести даты к единому формату
- ✓ Исправить опечатки в категориях
- ✓ Валидировать типы данных
- ✓ Проверить диапазоны значений
- ✓ Удалить ненужные столбцы
- ✓ Документировать все изменения
Для Data Analyst качество данных определяет качество выводов. Никогда не пренебрегайте этапом очистки — это основа надежной аналитики.