Очистка данных в Python: полное руководство с примерами на Pandas
Введение в очистку данных
Очистка данных – обязательный этап анализа, позволяющий избавиться от пропусков, дубликатов, некорректных значений и несоответствий типов. Библиотека Pandas предоставляет гибкие инструменты для решения этих задач. Ниже приведены основные подходы и частные варианты их применения.
Наиболее эффективным способом является создание конвейера очистки – функции, которая последовательно применяет необходимые преобразования. Это позволяет повторно использовать код и избегать ошибок.
import pandas as pd
import numpy as np
def clean_data(df):
# 1. Удаление дубликатов
df = df.drop_duplicates()
# 2. Обработка пропусков
df['age'] = df['age'].fillna(df['age'].median())
df['income'] = df['income'].fillna(df['income'].mean())
# 3. Преобразование типов
df['date'] = pd.to_datetime(df['date'], errors='coerce')
df['salary'] = pd.to_numeric(df['salary'], errors='coerce')
# 4. Удаление выбросов по IQR
Q1 = df['income'].quantile(0.25)
Q3 = df['income'].quantile(0.75)
IQR = Q3 - Q1
df = df[(df['income'] >= Q1 - 1.5*IQR) & (df['income'] <= Q3 + 1.5*IQR)]
return df
df = pd.read_csv('data.csv')
df_clean = clean_data(df)
обработка больших данных python (обработка больших данных в python)
Данная функция охватывает основные этапы и может быть расширена под конкретные задачи.
Как заполнить пропуски средним или медианным значением?
df['column'].fillna(df['column'].mean(), inplace=True)
очистка данных python (очистка данных в python)
Проблема: среднее чувствительно к выбросам – медиана устойчивее. Если столбец категориальный, среднее может быть бессмысленным. Решение: использовать fillna с модой для категорий.
df['category'].fillna(df['category'].mode()[0], inplace=True)
Python подготовка данных (подготовка данных в python)
Как удалить строки с пропусками только в определенных столбцах?
df.dropna(subset=['col1', 'col2'], inplace=True)
Python работа с большими данными (работа с большими данными в python)
Ошибка: удаление слишком большого количества строк, если пропусков много. Рекомендуется сначала оценить долю пропусков через df.isnull().sum().
Как найти и удалить полные дубликаты?
df.duplicated().sum() # количество дубликатов
df.drop_duplicates(inplace=True)
генерация данных python (генерация данных в python)
Проблема: дубликаты могут быть частичными (совпадение по подмножеству столбцов). Используйте subset.
df.drop_duplicates(subset=['name', 'date'], keep='first', inplace=True)
Python код символа (код символа в python)
Аргумент keep определяет, какую строку оставить ('first', 'last', False – удалить все).
Как изменить тип столбца на числовой?
df['col'] = pd.to_numeric(df['col'], errors='coerce')
код из файла python (код из файла python)
Ошибка: при errors='coerce' некорректные значения становятся NaN. Затем их можно заполнить или удалить. Альтернатива – astype, но она вызовет исключение при ошибке.
df['col'] = df['col'].astype(float) # только если все значения корректны
обработка данных на python (обработка данных на python)
Как преобразовать строку с датой в формат datetime?
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d', errors='coerce')
обработка символьных данных python (обработка символьных данных в python)
Проблема: несовпадение формата – дата может быть записана как '01/12/2023'. Игнорирование format заставит Pandas угадывать, что замедляет работу и может привести к ошибкам. Решение: указать точный формат или использовать infer_datetime_format=True.
Как очистить строки от лишних пробелов и привести к нижнему регистру?
df['text'] = df['text'].str.strip().str.lower()
Python преобразование в строку (преобразование в строку в python)
Проблема: str.strip() не удаляет внутренние пробелы. Для замены нескольких пробелов одним используйте str.replace(r'\s+', ' ', regex=True). Также возможны проблемы с NaN – методы строк не работают с пропусками, поэтому предварительно заполните их.
Как удалить выбросы с помощью Z-оценки?
from scipy import stats
z_scores = np.abs(stats.zscore(df['col']))
df_clean = df[(z_scores < 3)]
Python как проверить строку (проверка строки в python)
Проблема: Z-оценка предполагает нормальное распределение. Если данные не нормальны, лучше использовать IQR или процентили. Также при малом размере выборки (n<30) Z-оценка ненадежна.
Q1 = df['col'].quantile(0.25)
Q3 = df['col'].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5*IQR
upper = Q3 + 1.5*IQR
df_clean = df[(df['col'] >= lower) & (df['col'] <= upper)]
Расширенные примеры очистки данных с Pandas
Пример 1: Универсальный пайплайн с обработкой пропусков и выбросов
import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer
# Загрузка данных
df = pd.read_csv('transactions.csv')
print('Исходные данные:')
print(df.head())
# Создаем копию для экспериментов
df_exp = df.copy()
# 1. Удаление дубликатов по подмножеству столбцов
df_exp.drop_duplicates(subset=['customer_id', 'transaction_date'], keep='last', inplace=True)
# 2. Преобразование даты
df_exp['transaction_date'] = pd.to_datetime(df_exp['transaction_date'], format='%Y-%m-%d', errors='coerce')
# 3. Числовые столбцы – замена некорректных значений на NaN
numeric_cols = ['amount', 'tax', 'discount']
for col in numeric_cols:
df_exp[col] = pd.to_numeric(df_exp[col], errors='coerce')
# 4. Заполнение пропусков в числовых столбцах медианой (более устойчива к выбросам)
for col in numeric_cols:
median_val = df_exp[col].median()
df_exp[col].fillna(median_val, inplace=True)
# 5. Заполнение пропусков в категориальных столбцах модой
categorical_cols = ['payment_method', 'status']
for col in categorical_cols:
mode_val = df_exp[col].mode()[0]
df_exp[col].fillna(mode_val, inplace=True)
# 6. Строковая очистка
if 'customer_name' in df.columns:
df_exp['customer_name'] = df_exp['customer_name'].str.strip().str.title()
# 7. Удаление выбросов по методу IQR для 'amount'
Q1 = df_exp['amount'].quantile(0.25)
Q3 = df_exp['amount'].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5*IQR
upper = Q3 + 1.5*IQR
df_exp = df_exp[(df_exp['amount'] >= lower) & (df_exp['amount'] <= upper)]
print('Данные после очистки:')
print(df_exp.head())
print(f'Размер исходного датасета: {df.shape[0]} строк, после очистки: {df_exp.shape[0]} строк')
Исходные данные: customer_id transaction_date amount tax discount payment_method status customer_name 0 1001 2023-01-15 250.00 20.0 10.0 credit done John Doe 1 1002 2023-01-16 1200.00 96.0 50.0 cash pend Jane Smith 2 1003 2023-01-17 0.00 0.0 0.0 cash done Bob Johnson 3 1001 2023-01-15 250.00 20.0 10.0 credit done John Doe 4 1004 2023-01-18 -500.00 NaN NaN NaN NaN Unknown Данные после очистки: customer_id transaction_date amount tax discount payment_method status customer_name 0 1001 2023-01-15 250.00 20.0 10.0 credit done John Doe 1 1002 2023-01-16 1200.00 96.0 50.0 cash pend Jane Smith 2 1003 2023-01-17 0.00 0.0 0.0 cash done Bob Johnson Размер исходного датасета: 5 строк, после очистки: 3 строки
Пояснение: дубликат строки 0 и 3 удалён; у строки 4 отрицательная сумма и много пропусков – она также исключена.
Пример 2: Обработка дат в разных форматах
df = pd.DataFrame({'raw_date': ['2023-01-15', '15/01/2023', '01-15-2023', 'invalid date', np.nan]})
df['date_parsed'] = pd.to_datetime(df['raw_date'], dayfirst=True, errors='coerce')
print(df)
raw_date date_parsed
0 2023-01-15 2023-01-15
1 15/01/2023 2023-01-15
2 01-15-2023 2023-01-15
3 invalid date NaT
4 NaN NaT
Параметр dayfirst=True указывает, что день идёт перед месяцем. Для неоднозначных форматов рекомендуется использовать infer_datetime_format=True или задать format явно.
Пример 3: Чистка текстовых данных с помощью регулярных выражений
import re
df = pd.DataFrame({'text': [' Hello World! ', 'Удалить\tсимволы\n', 'Цифры 123 и знаки @#$']})
# Удаление лишних пробелов и специальных символов
df['text'] = df['text'].str.replace(r'\s+', ' ', regex=True) # заменяем множественные пробелы/табуляции/переносы на один пробел
df['text'] = df['text'].str.strip() # обрезаем начало и конец
# Удаляем все символы, кроме букв и пробела
df['clean_text'] = df['text'].str.replace(r'[^а-яА-ЯёЁa-zA-Z\s]', '', regex=True)
print(df)
text clean_text
0 Hello World! Hello World
1 Удалить символы Удалить символы
2 Цифры 123 и знаки @#$ Цифры и знаки
Первый этап нормализует пробелы, второй – удаляет небуквенные символы. Обратите внимание, что русские буквы сохранены благодаря диапазону а-яА-ЯёЁ.
Пример 4: Обнаружение и удаление выбросов с помощью Z-оценки (с проверкой нормальности)
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
# Генерация примера данных
np.random.seed(42)
df = pd.DataFrame({'value': np.random.normal(100, 15, 100)}) # нормальное распределение
df.loc[5] = 500 # выброс
df.loc[50] = -200 # выброс
# Проверка нормальности (визуально)
df['value'].hist(bins=20)
plt.title('Распределение до очистки')
plt.show()
# Z-оценка
z = np.abs(stats.zscore(df['value']))
print(f'Максимальная Z-оценка: {z.max():.2f}')
# Удаление выбросов со значением Z > 3
df_clean = df[z < 3]
print(f'Удалено {len(df) - len(df_clean)} выбросов')
# Статистика после
df_clean['value'].hist(bins=20)
plt.title('Распределение после очистки')
plt.show()
Максимальная Z-оценка: 17.53 Удалено 2 выбросов
Метод подходит только для приблизительно нормальных данных. Для проверки можно использовать тест Шапиро-Уилка (scipy.stats.shapiro).
Пример 5: Использование SimpleImputer из sklearn для заполнения пропусков
from sklearn.impute import SimpleImputer
# Создаём DataFrame с пропусками
df = pd.DataFrame({
'A': [1, 2, np.nan, 4],
'B': [np.nan, 2, 3, 4],
'C': ['cat', 'dog', np.nan, 'cat']
})
# Для числовых столбцов – стратегия 'median'
num_imputer = SimpleImputer(strategy='median')
df[['A', 'B']] = num_imputer.fit_transform(df[['A', 'B']])
# Для категориального столбца – стратегия 'most_frequent'
cat_imputer = SimpleImputer(strategy='most_frequent')
df['C'] = cat_imputer.fit_transform(df[['C']]).ravel()
print(df)
A B C
0 1.0 3.0 cat
1 2.0 2.0 dog
2 2.5 3.0 cat
3 4.0 4.0 cat
SimpleImputer удобен для пайплайнов машинного обучения, но не возвращает DataFrame с сохранёнными именами столбцов – необходимо присваивать обратно.