В реальной жизни данные, к сожалению, не идеальны и требуют тщательной предобработки. Проблемы с данными могут возникать по разным причинам: из-за их природы, способа сбора или ошибок при вводе.
Очистка данных позволит сделать анализ более точным, а в случае машинного обучения — улучшить качество моделей.
Давайте рассмотрим пять задач, с которыми можно столкнуться в рамках очистки данных. Это не исчерпывающий список, но он послужит хорошим ориентиром при работе с реальными датасетами.
Все примеры мы будем рассматривать на Ames Housing Dataset, который содержит информацию о продажах жилой недвижимости в городе Эймс, штат Айова, США.
Примечание: когда мы говорим о дубликатах в наборах данных, мы имеем в виду дублирование целых строк, каждая из которых представляет собой отдельное наблюдение. А в столбце могут быть повторяющиеся значения, это нормально. Мы говорим именно о полном дублировании наблюдений, которое является ошибкой.
duplicate_rows = df[df.duplicated()]
duplicate_rows
df_cleaned = df.drop_duplicates()
df_cleaned.reset_index(drop=True, inplace=True)
df_cleaned
df_cleaned = df_cleaned.drop(index=214)
df_cleaned.reset_index(drop=True, inplace=True)
df_cleaned
df_cleaned['SalePrice'] = df_cleaned['SalePrice'].round(2)
df_cleaned.head()
df_cleaned['HouseStyle'] = df_cleaned['HouseStyle'].replace('OneStory', '1Story')
import seaborn as sns
import matplotlib.pyplot as plt
# Создаем диаграмму "ящик с усами" для SalePrice
plt.figure(figsize=(10, 6))
sns.boxplot(x=df_cleaned['SalePrice'])
plt.title('Box Plot of SalePrice')
plt.xlabel('SalePrice')
plt.show()
Z-score = (конкретное значение – среднее арифметическое признака) / стандартное отклонение признака
Модифицированный Z-score = (конкретное значение – медиана признака) / медианное абсолютное отклонение (MAD) признака
1, 2, 2, 2, 3, 3, 3, 5, 9
2, 1, 1, 1, 0, 0, 0, 2, 5
0, 0, 0, 1, 1, 1, 2, 2, 5
import pandas as pd
from scipy.stats import median_abs_deviatio
# Предполагаем, что 'data' — это наш дашатфрейм, и он содержит столбец 'SalePrice'
# Вычисляем медиану для столбца SalePrice
median_sale_price = data['SalePrice'].median()
# Вычисляем медианное абсолютное отклонение (MAD) для столбца SalePrice
mad_sale_price = median_abs_deviation(data['SalePrice'], scale='normal')
# Вычисляем модифицированный Z-score для столбца SalePrice
data['Modified_Z_Score'] = (data['SalePrice'] - median_sale_price) / mad_sale_price
# Выводим первые несколько строк с модифицированным Z-score
print(data[['SalePrice', 'Modified_Z_Score']].head())
# Фильтруем строки, где модифицированный Z-score >= 3 или <= -3
outliers = data[(data['Modified_Z_Score'] >= 3) | (data['Modified_Z_Score'] <= -3)]
# Выводим отфильтрованные строки
outliers = outliers[['SalePrice', 'Modified_Z_Score']]
outliers
data_without_outliers = data.drop(index=outliers.index)
# Выводим новый датафрейм без выбросов
print(data_without_outliers)
import seaborn as sns
import matplotlib.pyplot as plt
# Строим ящик с усами для SalePrice
plt.figure(figsize=(10, 6))
sns.boxplot(x=data_without_outliers['SalePrice'])
plt.title('Box Plot of SalePrice')
plt.xlabel('SalePrice')
plt.show()
# Вычисляем количество наблюдений в исходном и отфильтрованном датафреймах
original_count = len(data)
filtered_count = len(data_without_outliers)
# Вычисляем количество удаленных строк
removed_count = original_count - filtered_count
# Вычисляем процент удаленных строк
percentage_removed = (removed_count / original_count) * 100
# Выводим процент
print(f"Процент удаленных наблюдений: {percentage_removed:.2f}%")
# Определяем столбцы с пропусками
columns_with_missing = data.columns[data.isnull().any()]
# Создаем новый датафрейм только с теми столбцами, где есть пропускики
data_with_missingness = data[columns_with_missing]
# Выводим новый датафрейм
data_with_missingness
import seaborn as sns
import matplotlib.pyplot as plt
# Транспонируем датафрейм
transposed_data = data_with_missingness.T
# Создаем тепловую карту для визуализации пропусков
plt.figure(figsize=(12, 8))
sns.heatmap(transposed_data.isnull(), cbar=False, yticklabels=True)
plt.title('Тепловая карта пропущенных данных (транспонированная)')
plt.xlabel('Наблюдения')
plt.ylabel('Признаки')
plt.tight_layout()
plt.show()
Также можно использовать библиотеку missingno, которая специально предназначена для удобных визуализаций пропусков.
Источник: JetBrains Blog