Перевод статьи «A Beginner’s Guide to Data Cleaning in Python».
Когда вы начинаете новый проект, связанный с данными, вы редко получаете данные в идеальном для анализа состоянии. Поэтому в начале каждого нового проекта необходимо произвести очистку данных.
Очистка данных — это процесс удаления ошибок, выбросов и несоответствий, а также обеспечение того, чтобы все данные были представлены в формате, подходящем для анализа. Данные, содержащие множество ошибок или не прошедшие процесс очистки, называются грязными данными.
Этот шаг может показаться необязательным для многих начинающих специалистов по данным, но будьте уверены, он крайне важен! Без надлежащей очистки данных ваша модель может прийти к неверному выводу, ваш график может показать фальшивую тенденцию, а ваши статистические данные могут быть дико неточными.
Рассмотрим чрезвычайно маленький набор данных. Вы с друзьями делите конфеты между собой поровну, и вам нужно определить, сколько конфет достанется каждому. Вы вводите свои данные в таблицу:
Люди | Количество конфет |
---|---|
Peter | 5 |
Sandy | 20 |
Sandy | 20 |
Joseph | 3 |
Amed | 12 |
Если взять среднее значение столбца «Количество конфет», то можно прийти к выводу, что каждый человек должен получить 12 конфет.
Однако если вы попытаетесь раздать всем по 12 конфет, то конфеты закончатся раньше, чем каждый получит свою долю, потому что в таблице продублирована строка Sandy. Всего у вас будет 40 конфет, а не 60, и только 4 человека, а не 5!
Не уделив время очистке набора данных, вы рискуете прийти к неверному выводу.
В случае с делением конфет между друзьями самым большим последствием может стать ссора. Но в мире бизнеса пренебрежение очисткой набора данных может привести к анализу, на основе которого будет предложено запустить неправильный продукт, нанять неправильное количество сотрудников, инвестировать в неправильные акции или даже назначить клиенту неправильную цену!
Очистка данных еще более важна, если анализ данных будет сложным. В такой ситуации у вас может не быть столь четких представлений о том, какими должны быть результаты, а значит, вы можете не заметить неверные результаты.
Тщательная очистка данных, а также тщательное тестирование помогут снять эти проблемы. В этом руководстве мы расскажем о том, что нужно знать о процессе очистки данных в Python.
Существует множество типов ошибок и несоответствий, которые могут привести к загрязнению данных. Давайте рассмотрим несколько наиболее распространенных.
Неполные наборы данных встречаются очень часто. В вашем наборе данных может не оказаться информации за несколько лет, каких-то данных о клиенте или части ассортимента продукции вашей компании.
Пропущенные значения могут сказаться на вашем анализе. Отсутствие значительной части важных данных может привести к искажению результатов. Кроме того, значения NaN или отсутствующие ячейки в DataFrame могут привести к поломке кода Python, что вызовет массу неудобств при построении модели.
Выбросы (outliers) — это значения, которые находятся далеко за пределами нормы и не являются репрезентативными для данных. Такие значения могут быть результатом опечатки или исключительных обстоятельств. Важно отличать истинные выбросы от информативных экстремальных ситуаций. Выбросы могут исказить результаты, что в конечном итоге приведет к неправильному ответу.
Как мы видели выше, дублирование данных может привести к неправильному выводу. Будьте внимательны к дубликатам, которые встречаются более одного раза, а также к тем, которые содержат противоречивую или обновленную информацию.
Иногда значения в нашем наборе данных просто неверны. Это может быть неправильно написанное имя клиента, неверно указанный номер продукта, устаревшая информация или неправильно обозначенные данные.
Иногда бывает сложно определить, являются ли ваши данные ошибочными, поэтому проверка источника очень важна! Помните, что ваш анализ хорош лишь настолько, насколько хороши ваши данные.
Непоследовательность проявляется в разных формах. Явно непоследовательные данные могут указывать на опечатку или ошибку. Если вы видите, что возраст покупателя указан задом наперед, ингредиент меняет идентификационный номер или продукт имеет сразу две цены, стоит присмотреться и убедиться, что все правильно.
Еще один проблемный тип непоследовательности — несоответствие формата данных. Разные значения могут быть представлены в разных единицах измерения (километры, мили и дюймы), в разных стилях (mm-dd-yyyy и dd-mm-yyyy), в разных типах данных (float и int) или даже в разных типах файлов (.jpg и .png).
Из-за этих несоответствий вашему коду будет сложно или даже невозможно правильно интерпретировать значения. Это может привести к неправильному анализу или к тому, что ваш код вообще не будет работать.
Прежде чем использовать набор данных в сложном анализе, важно разобраться в самих данных. Для этого необходимо провести исследование данных. Этот шаг можно рассматривать как предварительный анализ.
Давайте рассмотрим несколько типичных шагов по исследованию данных в табличном формате:
Все это может показаться излишним для предполагаемого анализа, но есть несколько важных причин, по которым вы всегда должны выполнять эти шаги.
Во-первых, это позволит вам лучше понять границы вашего набора данных, что очень важно, если вы хотите доверять результатам вашего окончательного анализа.
Во-вторых, изучение данных может указать вам на важные тенденции и направления для анализа, о которых вы раньше не задумывались. Они могут дополнить ваши предполагаемые анализы или стать осложняющими факторами, которые вам необходимо учесть.
В-третьих, предварительный анализ может стать первой подсказкой о том, где у вас могут быть грязные данные. Благодаря предварительному анализу вы можете увидеть выброс, осознать, что категорий в два раза больше, чем должно быть, или обнаружить, что метод сбора данных в прошлом году был иным, чем в позапрошлом. Все это критически важная информация, которая должна побудить вас проявить любопытство к своему набору данных.
Давайте разберемся с некоторыми методами очистки данных в Python. Для этого рассмотрим, как справиться с некоторыми распространенными проблемами, связанными с грязными данными.
Когда у вас большой набор данных, некоторые поля наверняка будут отсутствовать в одной или нескольких записях. Из-за этого не только можно упустить ценные данные: NaN-записи могут сбивать некоторые функции Python, делая вашу модель неточной.
Обнаружив пропущенное значение, вы можете либо исключить эту запись из анализа, либо попытаться вставить что-то вместо пропущенного значения. Если ваш набор данных достаточно мал, я бы предложила просмотреть строки, содержащие пропущенные значения, чтобы определить наилучший вариант действий.
import pandas as pd # Identify rows with NaN values rows_with_nan = df[df.isnull().any(axis=1)] #View the rows with NaN values print(rows_with_nan)
Удаление записи, как правило, не является первым выбором, поскольку это означает изъятие потенциально ценной информации из анализа.
Но иногда удаление — наилучший вариант, например, если запись не содержит какой-то другой ценной информации, чтобы был смысл ее сохранять. Например, если запись — это только дата.
Удаление — это также самый простой способ справиться с записями, имеющими недостающие значения. Поэтому, если у вас мало времени, а оставшаяся часть записи не важна для анализа, удаление записей с NaN — один из вариантов.
Чтобы удалить из DataFrame строки, содержащие NaN, можно использовать метод .dropna()
из библиотеки Pandas.
import pandas as pd # Assuming df is your DataFrame df.dropna(inplace=True)
От редакции Pythonist: читайте также статью «Как очистить данные при помощи Pandas».
Обычно предпочтительным методом обработки отсутствующих значений является вставка разумного значения. Поиск разумного значения для вставки это своего рода искусство, но есть несколько устоявшихся методов, которые могут стать хорошей отправной точкой.
Метод .fillna()
из Pandas заполняет пропущенные значения, используя среднее значение, чтобы не менять распределение.
import pandas as pd # Assuming df is your DataFrame # Replace NaN values with the mean of the column df.fillna(df.mean(), inplace=True)
В библиотеке sci-kit learn есть простая функция расчета данных, которая тоже хорошо работает.
from sklearn.impute import SimpleImputer import pandas as pd # Assuming df is your DataFrame imputer = SimpleImputer(strategy='mean') df_imputed = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)
Если вам нужен более сложный метод поиска хорошего значения, вы можете рассмотреть возможность использования KNN или регрессионной импутации. В конечном итоге выбор метода зависит от ваших данных, потребностей и имеющихся ресурсов.
Выбросы — сложная проблема. Некоторые кажущиеся выбросы на самом деле являются важными данными, например, реакция фондового рынка на кризисы, такие как COVID-19 и глобальная рецессия. Однако другие могут оказаться опечатками или быть вызваны несущественными и редкими обстоятельствами — их следует удалить.
Поймете ли вы разницу между значимыми и ненужными выбросами, часто зависит от понимания контекста данных. Контекст вы можете понять, проведя исследование данных, о котором мы уже говорили. Также имеет значение четкое представление о цели анализа.
Многие выбросы видны при отображении данных на графике, но вы также можете использовать статистические методы для выявления выбросов.
Один из распространенных методов — вычисление Z-оценки для каждой точки данных и исключение значений с экстремальными Z-оценками.
import numpy as np import pandas as pd # Generate some sample data np.random.seed(0) data = np.random.randint(low=0, high=11, size=1000) # Add some outliers data[0] = 100 data[1] = -100 # Calculate Z-scores z_scores = (data - np.mean(data)) / np.std(data) # Identify outliers based on Z-score threshold (e.g., 3) threshold = 3 outliers = np.where(np.abs(z_scores) > threshold)[0] print("Outliers identified using Z-score method:") print(data[outliers])
Другой метод — вычисление межквартильного размаха (IQR) распределения и классификация любых значений, которые находятся на уровне Q1-(1,5 x IQR) или Q3 + (1,5 x IQR), как потенциальных выбросов.
import numpy as np import pandas as pd # Generate some sample data np.random.seed(0) data = np.random.randint(low=0, high=11, size=1000) # Add some outliers data[0] = 100 data[1] = -100 # Calculate quartiles and IQR q1 = np.percentile(data, 25) q3 = np.percentile(data, 75) iqr = q3 - q1 # Identify outliers based on IQR lower_bound = q1 - (1.5 * iqr) upper_bound = q3 + (1.5 * iqr) outliers = np.where((data < lower_bound) | (data > upper_bound))[0] print("Outliers identified using IQR method:") print(data[outliers])
После того как вы выявили выбросы и определили, что они являются проблемными, с ними нужно что-то сделать. Существует несколько методов борьбы с выбросами. Если вы определили, что выброс вызван ошибкой, можно просто исправить ошибку, чтобы устранить выброс.
В других случаях можно удалить выброс из набора данных или заменить его менее экстремальным значением, сохраняющим общую форму распределения.
Ограничение (англ. capping) — это метод, при котором вы устанавливаете предел, или порог, распределения данных и заменяете любые значения, выходящие за эти пределы, заданным значением.
import pandas as pd import numpy as np # Create a sample DataFrame with outliers data = { 'A': [100, 90, 85, 88, 110, 115, 120, 130, 140], 'B': [1, 2, 3, 4, 5, 6, 7, 8, 9] } df = pd.DataFrame(data) # Define the lower and upper thresholds for capping (Here I used the 5th and 95th percentiles) lower_threshold = df.quantile(0.05) upper_threshold = df.quantile(0.95) # Cap outliers capped_df = df.clip(lower=lower_threshold, upper=upper_threshold, axis=1) print("Original DataFrame:") print(df) print("\nCapped DataFrame:") print(capped_df)
В некоторых случаях можно преобразовать данные таким образом, чтобы уменьшить влияние выбросов. Например, извлечь квадратный корень или применить логарифмическую формулу.
Будьте осторожны при преобразовании данных, так как в конечном итоге вы можете создать еще больше проблем. Прежде чем принять решение о преобразовании данных, необходимо учесть несколько моментов.
Мы уже видели, как дубликаты могут нанести вред нашему анализу. К счастью, Python позволяет легко их выявлять и обрабатывать.
Используя метод duplicated()
в библиотеке Python pandas, вы можете легко определить дубликаты строк в DataFrame и проанализировать их.
import pandas as pd # Assuming 'df' is your DataFrame duplicate_rows = df[df.duplicated()]
Это вернет DataFrame, содержащий строки, которые являются дубликатами. Как только вы получите этот DataFrame с дублирующимися строками, я рекомендую вам просмотреть дубликаты, если их не слишком много.
Большинство дубликатов могут быть точными копиями. Их можно просто отбросить с помощью метода drop_duplicates()
в Pandas:
# Removing duplicates cleaned_df = df.drop_duplicates()
В некоторых случаях целесообразнее объединить дубликаты, агрегируя информацию. Например, если дубликаты представляют собой несколько записей об одной и той же сущности, мы можем объединить их с помощью функций агрегирования:
# Merging duplicates by aggregating values merged_df = df.groupby(list_of_columns).agg({'column_to_merge': 'sum'})
Это позволит объединить дублирующиеся строки в одну, агрегируя значения на основе заданных функций, таких как сумма, среднее и т. д.
import pandas as pd #Sample DataFrame data = { 'customer_id' : [102, 102, 101, 103, 102] 'product_id' : ['A', 'B', 'A', 'C', 'B'] 'quantity_sold : [5, 3, 2, 1, 4] } df = pd.DataFrame(data) df }
customer_id | product_id | quantity_sold | |
---|---|---|---|
0 | 101 | A | 5 |
1 | 102 | B | 3 |
2 | 101 | A | 2 |
3 | 103 | C | 1 |
4 | 102 | B | 4 |
# Merging duplicates by aggregating values merged_df = df.groupby(['cutomer_id', 'product_id']).agg({'quantity_sold': 'sum'}).reset_index() merged_df
customer_id | product_id | quantity_sold | |
---|---|---|---|
0 | 101 | A | 7 |
1 | 102 | B | 7 |
2 | 103 | C | 1 |
Различные типы непоследовательности требуют различных решений. Несоответствия, возникшие в результате неправильного ввода данных или опечаток, могут потребовать исправления со стороны компетентного источника. В зависимости от обстоятельств, неправильные данные можно заменить с помощью импутации, как если бы это было отсутствующее значение, или полностью удалить из набора данных.
Непоследовательность в форматировании данных можно исправить с помощью некоторых методов стандартизации. Чтобы удалить из строки начальные и завершающие пробелы, можно использовать метод .strip()
. Методы .upper()
и .lower()
стандартизируют регистр в строках. А преобразование дат в datatime
с помощью pd.to_datetime
стандартизирует форматирование дат.
Вы также можете гарантировать одинаковый тип данных у всех значений в столбце DataFrame, используя метод .astype()
.
Для исправления непоследовательности форматирования вам также могут понадобиться:
value_mapping = {'M': 'Male', 'F': 'Female'} standardized_value = value_mapping.get('M', 'Unknown')
Преобразование данных и инжиниринг признаков (англ. feature engineering) — это методы предварительной обработки, позволяющие преобразовать необработанные данные в формат, более подходящий для алгоритмов машинного обучения и статистического анализа.
В этом разделе мы кратко рассмотрим некоторые распространенные методы преобразования данных и инжиниринга признаков на Python.
Нормализация и стандартизация — это две техники, используемые для приведения признаков к одинаковому масштабу. Это важно для многих алгоритмов машинного обучения.
Нормализация приводит данные к фиксированному диапазону, обычно от 0 до 1. Это гарантирует, что все признаки находятся на одной шкале, и не позволяет одним признакам доминировать над другими из-за их большей величины.
from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() scaled_data = scaler.fit_transform(data)
Стандартизация преобразует данные так, чтобы среднее значение было равно 0, а стандартное отклонение — 1. Эта техника полезна, когда данные имеют разные масштабы и диапазоны, и гарантирует, что каждый признак оказывает сопоставимое влияние на модель.
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() standardized_data = scaler.fit_transform(data)
Способ масштабирования данных определяется специфическими характеристиками ваших данных и требованиями предполагаемой модели.
Кодирование категориальных переменных — важный этап предварительной обработки в машинном обучении, когда речь идет о признаках, не являющихся числовыми. Категориальные переменные представляют собой качественные данные, такие как типы, классы или метки. Чтобы использовать эти переменные в алгоритмах машинного обучения, их необходимо преобразовать в числовой формат.
Одним из распространенных методов кодирования категориальных переменных является прямое кодирование (англ. one-hot encoding), которое преобразует каждую категорию в двоичный вектор. Этот метод особенно полезен при работе с номинальными категориальными переменными, в которых отсутствует присущий категориям порядок или иерархия.
import pandas as pd encoded_data = pd.get_dummies(data, columns=['categorical_column'])
import pandas as pd #Create a sample DataFrame with categorical column data = { 'ID' : [1, 2, 3, 4, 5] } df = pd.DataFrame(data) #Performe one-hot encoding encoded_data = pd.get_dummies(df, columns==['Color']) print("Original DataFrame") print(df) print("\nEncoded DataFrame:") print(encoded_data)
Другой подход — кодирование метки, при котором каждой категории присваивается уникальное целое число. Каждая категория сопоставляется с числовым значением, эффективно преобразуя категориальные метки в порядковые номера. Этот метод подходит для порядковых категориальных переменных, где существует естественный порядок или ранжирование между категориями.
from sklearn.preprocessing import LabelEncoder encoder = LabelEncoder() encoded_data['categorical_column'] = encoder.fit_transform(data['categorical_column'])
from sklearn.preprocessing import LabelEncoder import pandas as pd #Create a sample DataFrame with categorical column data = { 'ID' : [1, 2, 3, 4, 5] 'Color' : [ 'Red', 'Blue', 'Green', 'Red', 'Green' ] } df = pd.DataFrame(data) #Perform label encoding encoder = LabelEncoder() df ['Color_LabelEncoded'] = encoder.fit_transform(df['Color']) print("Original DataFrame:") print(df[['ID', 'Color']]) print("\nDataFrame with Label Encoded Column:") print(df[['ID', 'Color_LabelEncoded']])
Важно выбрать подходящий метод кодирования в зависимости от характера категориальной переменной и требований алгоритма машинного обучения. One-hot encoding обычно предпочтителен для номинальных переменных, а кодирование с помощью меток подходит для порядковых переменных.
Инжиниринг признаков — это этап разработки модели машинного обучения, включающий создание новых признаков или модификацию существующих. Этот процесс распространен в тех случаях, когда в исходных данных отсутствуют признаки, непосредственно способствующие решению задачи обучения, или когда существующие признаки не имеют той формы, которую может эффективно использовать алгоритм обучения.
Рассмотрим сценарий, в котором вы работаете с набором данных о ценах на жилье и хотите предсказать цену продажи домов на основе различных характеристик, таких как количество комнат, жилая площадь и состояние недвижимости. Однако в наборе данных нет характеристики, которая напрямую отражала бы общее состояние дома.
В этом случае можно создать новый признак, объединив существующие признаки или извлекая соответствующую информацию.
Например, можно создать характеристику «Общее состояние», объединив оценки состояния отдельных компонентов дома, таких как состояние кухни, качество подвала, возраст объекта, недавние ремонтные работы и т. д.
В случаях, когда связь между признаками и целевой переменной нелинейна, можно генерировать полиномиальные признаки, возводя существующие признаки в различные степени. Такой подход помогает отразить сложные взаимосвязи между переменными, которые не могут быть разделимы линейно.
from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures(degree=2) polynomial_features = poly.fit_transform(data)
В других случаях вы можете иметь дело с высокоразмерными наборами данных или мультиколлинеарностью признаков. Такие методы, как анализ главных компонент (Principal Component Analysis, PCA), могут быть использованы для снижения размерности набора данных, сохраняя при этом большую часть необходимой информации.
from sklearn.decomposition import PCA pca = PCA(n_components=2) transformed_features = pca.fit_transform(data)
Инжиниринг признаков гарантирует, что у вас есть правильные данные в правильном формате для использования моделью. Существует множество техник построения признаков, и выбор будет зависеть от того, чего вы хотите добиться.
Очистка данных — важный шаг в любом проекте по анализу данных или машинному обучению. Вот несколько наилучших практик, которые следует иметь в виду, чтобы оптимизировать процесс очистки данных:
Всегда сохраняйте оригинал!
Это самый важный совет при очистке данных. Храните копии файлов исходных данных отдельно от очищенных и обработанных версий. Это гарантирует, что у вас всегда будет точка отсчета и вы сможете легко вернуться к исходным данным в случае необходимости.
Лично я всегда делаю копию файла необработанных данных до внесения изменений и добавляю к имени файла суффикс «-RAW», чтобы знать, что это оригинал.
Добавьте в код комментарии, чтобы объяснить цель каждого шага очистки и все сделанные предположения.
Вы должны быть уверены, что ваши усилия по очистке данных не приведут к существенному изменению распределения или появлению непредвиденных ошибок. Повторное исследование данных после очистки поможет убедиться, что вы на правильном пути.
Если процесс очистки длительный или автоматизированный, возможно, вам захочется вести отдельный документ, в котором вы будете фиксировать подробности каждого этапа очистки.
Такие детали, как дата, конкретные действия и возникшие проблемы, могут оказаться полезными в дальнейшем.
Не забудьте сохранить этот документ в легкодоступном месте, например, в той же папке проекта, где хранятся данные или код. Если речь идет об автоматизированном, регулярно обновляемом конвейере, подумайте о том, чтобы это логирование было автоматической частью процесса очистки данных. Это позволит вам проверять, все ли работает без сбоев.
Определите общие задачи по очистке данных и заключите их в функции многократного использования. Это позволит вам применять одни и те же действия по очистке к нескольким наборам данных. Это особенно полезно, если у вас есть специфические для компании аббревиатуры, которые вы хотите отобразить (англ. map).
Очистка данных — это не просто рутинная задача. Это важнейший шаг, который является основой любого успешного проекта по анализу данных и машинному обучению. Обеспечивая точность, согласованность и надежность данных, вы закладываете основу для принятия обоснованных решений и получения значимых выводов.
Грязные данные могут привести к ошибочным выводам и некачественному анализу, что чревато серьезными последствиями, независимо от того, делите ли вы конфеты между друзьями или принимаете бизнес-решения. Вложение времени и усилий в очистку данных окупается в долгосрочной перспективе, обеспечивая достоверность анализа и практичность результатов.
Управление памятью - важный, но часто упускаемый из виду аспект программирования. При неправильном подходе оно…
Как возникает круговой импорт? Эта ошибка импорта обычно возникает, когда два или более модуля, зависящих…
Вы когда-нибудь оказывались в ситуации, когда скрипт на Python выполняется очень долго и вы задаетесь…
В этом руководстве мы разберем все, что нужно знать о символах перехода на новую строку…
Блок if __name__ == "__main__" в Python позволяет определить код, который будет выполняться только при…
Давайте разберем, как настроить модульные тесты для экземпляров классов. Мы напишем тесты для проверки функциональности…