Silent Heros of Analytics: предварительная обработка данных 101 – очистка данных

Мы все слышали старую поговорку: «Мусор на входе, мусор на выходе». Он открывает истину в области анализа данных: качество ваших идей неразрывно связано с качеством ваших данных. Независимо от того, насколько сложной является ваша модель или насколько оптимизированным может показаться ваш отчет, если основа — ваши данные — ошибочны, ваши идеи тоже будут ошибочными. Возможно, это звучит не так уж и плохо, если вы сначала об этом подумаете. Затраты на внесение изменений в данные, находящиеся еще на этапе разработки, возможно, не вызовут у вас сердечного приступа. А теперь представьте, как они будут обостряться, когда отчеты, основанные на ошибочных данных, уже используются во всей организации, и сколько усилий потребуется, чтобы внести какие-либо поправки в данные. Решение? Тщательная очистка данных.

Ниже вы найдете мой контрольный список с простыми шаблонами сценариев Python, который поможет мне и, надеюсь, поможет вам беспрепятственно предварительно обработать данные и подготовить их к моделированию.

  1. Пошаговый процесс

1.1. Понимание ваших данных

Прежде чем приступить к какой-либо аналитической задаче, найдите время, чтобы ознакомиться со своими данными. Тщательная первоначальная оценка может пролить свет на дальнейший путь. Знание предметной области или консультация профильного эксперта помогут вам выбрать наиболее точные инструменты предварительной обработки, чтобы избавиться от ненужных деталей, сохранив при этом все важные нюансы.

Мне всегда помогают вопросы ниже:

  • Как, когда, где собирались данные? (Есть ли потенциальная предвзятость при сборе данных?)
  • Что он представляет (строки, имена столбцов и т. д.)?
  • Чего может не хватать?
  • Насколько на самом деле необработанные данные? Прошли ли уже данные предварительную обработку?

Ответы на эти вопросы, ваши знания предметной области и обращение к профильному эксперту в случае сомнений помогут вам выбрать наиболее точные инструменты предварительной обработки.

1.2. Удаление ненужного

Беспорядок — враг ясности и отвлекает вас от самых важных данных. Избавьтесь от дубликатов и избыточности — это поможет вам сохранить актуальность и неэффективность вашего набора данных.

import pandas as pd
df = pd.read_csv(‘dataset.csv’)

#To remove all the duplicated rows
df_nd = df.drop_duplicates()

#You might want to apply it on the specific columns
df_nd = df.drop_duplicates(subset=['column1', 'column2'])

#Or enhance by adding additional conditioning
df_nd = df[~df.duplicated(subset=['column1', 'column2']) | (df['column3'] != specific_value)]

1.3. Обработка недостающих данных

Обычно это сбой в моих наборах данных. Существует несколько методов, с помощью которых можно эффективно устранить эти пробелы. Однако имейте в виду, что в зависимости от причины отсутствия данных подход может быть разным:

MCAR: данные отсутствуют совершенно случайно.

  • Вероятность пропуска одинакова для всех наблюдений.
  • Представьте себе опрос, в котором некоторые респонденты случайно пропустили вопросы, совершенно случайно, без привязки к какой-либо характеристике респондентов, — это пример MCAR.
  • Удаление случаев MCAR не искажает результаты, однако, поскольку размер выборки меньше, это может снизить эффективность статистических тестов.
  • Решением может быть удаление недостающих строк данных.
#To remove all rows containing any NaN values
df.dropna()

#Instead you can remove columns that contain any NaN values
df.dropna(axis=1)

#Similarly to how we removed duplicates, you might want to specify columns
df.dropna(subset=['column1', 'column2'])
  • Простые вменения, такие как среднее
#To replace all NaN values with mean non-NaN values from column1 
df['column1'].fillna(df['column1'].mean())

#To replace with a constant value x + let us add a parameter to define number of NaN we want to fill
df['column1'].fillna(value=0, limit=3)

#Instead you can fill NaN with value from the previous row (change the method to 'bfill' to fill NaN with value from the next row)
df['column1'].fillna(method='ffill')
  • Линейная интерполяция:Линейная интерполяция позволяет оценить недостающие значения, находя точку (x, y) между двумя уже заданными точками (x₁, y₁), (x₂, y₂). . Однако предполагается, что изменение линейное (есть и другие методы интерполяции: полиномиальная, сплайновая, временная).
#For linear interpolation
df_interpolated = df.interpolate(method=’linear’)

#You can apply linear interpolation on the part of the dataset and apply additional method on the rest of the dataset
#Assuming 'column_name' is the column you're interested in
df.sort_values('column1', ascending=False)

# Apply interpolation to the top 40 rows
df.iloc[:40] = df.iloc[:40].interpolate(method='linear')

# Fill the rest with the minimum value of the column
min_value = df['column1'].min()
df.iloc[40:] = df.iloc[40:].fillna(value=min_value)
  • Вменение KNN:Метод KNN основан на принципе, согласно которому точка с пропущенными значениями может быть вменена с использованием информации от ее ближайших соседей «k» в пространстве данных.
from sklearn.impute import KNNImputer
imputer = KNNImputer(n_neighbors=3)

# You can apply the imputer only on the selected column and then update your original DataFrame with the imputed values
imputed_data = imputer.fit_transform(df[['column1']])
df['column1'] = imputed_data

— МАР: данные отсутствуют случайно.

  • Вероятность пропуска зависит от наблюдаемых данных, а не от ненаблюдаемых. Если вы можете предсказать отсутствие на основе других наблюдаемых переменных, данные, скорее всего, соответствуют MAR.
  • Например, представьте, что пожилые респонденты опроса с меньшей вероятностью раскрывают свой доход, но с большей вероятностью раскрывают свой возраст. Если вы знаете их возраст, вы можете смоделировать вероятность того, что они раскроют свой доход. В этом случае возраст отслеживается, но доход может отсутствовать. Отсутствие данных о доходах связано с наблюдаемыми данными о возрасте, но не связано с фактическими (ненаблюдаемыми) значениями доходов.
  • Удаление случаев MAR может привести к необъективным результатам, если модель не учитывает переменные, вызывающие пропуски.
  • Здесь вам, возможно, придется поискать более продвинутые решения, которые будут фиксировать взаимосвязи данных: уравнения взвешенной оценки или вменения на основе моделей, например, модель регрессии.

— MNAR: пропало не случайно.

  • Отсутствие зависит от самих ненаблюдаемых данных. Это самый сложный механизм, поскольку он подразумевает наличие систематической причины отсутствия значений, напрямую связанной с самими значениями.
  • Например, рассмотрим опрос, в котором респонденты с более высокими доходами с меньшей вероятностью раскрывают свои доходы. Здесь отсутствие данных о доходах напрямую связано с несоблюдением значений доходов.
  • Обработка MNAR является сложной задачей, поскольку невозможно определить механизм отсутствия, используя только наблюдаемые данные. Может потребоваться дополнительное моделирование или расширенные знания предметной области, независимо от метода, он все равно оставляет много места для предположений.

Даже если это не решается реализацией любого из вышеперечисленных решений, хорошей практикой может быть пометка любых отсутствующих данных в наборе данных и введение категории отсутствующие.

1.4. Исправление выбросов

Это может быть либо результатом человеческого вклада, либо экспериментальных ошибок.

  • Ограничение. Обработка выбросов путем установки порогового значения: любые значения данных ниже или выше этого значения считаются выбросами и заменяются определенными минимальным и максимальным значением. Чтобы определить пороговое значение, вы можете либо положиться на знания предметной области (диапазон допустимых значений данных может быть уже известен), либо использовать статистический метод, например IQR.

Метод межквартильного диапазона – это метод обнаружения выбросов, особенно для наборов данных, которые обычно не распределяются. IQR — это диапазон между первым квартилем (25-й процентиль) и третьим квартилем (75-й процентиль) данных. Короче говоря, используя статистическую дисперсию, метод IQR учитывает 50% средних данных (согласно эмпирическому правилу) и рассматривает точки за пределами границ как выбросы.

q1 = df['values'].quantile(0.25)
q3 = df['values'].quantile(0.75)
iqr = q3 - q1

lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr

df['values'] = df['values'].apply(lambda x: upper_bound if x > upper_bound else lower_bound if x < lower_bound else x)

1,5. Согласованность данных

Это не подлежит обсуждению. Наличие столбца test_test_test в данный момент может показаться заманчивым, но если перенесемся на несколько недель вперед, его значение может быть потеряно. Последовательные соглашения об именах имеют решающее значение. Они расширяют возможности не только вас, но и всей организации, облегчая плавную навигацию по данным. Проверьте, нет ли общеорганизационных стандартов, которые следует применять к вашим данным, подробнее читайте в этой статье.

1.8. Исправление ошибок и очистка текстовых данных

Как аналитик данных, вы часто будете сталкиваться с текстовыми неточностями — специальными символами, которые необходимо удалить, словами, требующими определения корней, и т. д. Кодирование текстовых данных также имеет решающее значение для некоторых аналитических операций.

На следующей неделе я поделюсь с вами некоторыми лингвистическими нюансами, которые я учитываю до и во время анализа текстовых данных (будь то исследовательский анализ данных или случай НЛП), а пока вот несколько универсальных приемов и советов, которым стоит следовать. :

  • Преобразовать в нижний регистр
#To convert text from specific column
df['column1'] = df['column1'].str.lower()

#To capitalize the first letter
df['column1'] = df['column1'].str.title()
  • Удалите начальные и конечные пробелы. Обычно они возникают в результате вмешательства человека, но, как всегда, просмотрите свой набор данных. Будьте особенно осторожны при изменении набора данных.
#To remove leading whitespaces
df['column_name'] = df['column_name'].str.lstrip()

#To remove trailing whitespaces
df['column_name'] = df['column_name'].str.rstrip()
  • Отфильтровать нежелательные символы.Список сильно зависит от данных. Некоторые символы могут быть нерелевантны для одного набора данных, но иметь решающее значение для другого.
# To replace any character with is not a number or a letter with a space
df['column_name'] = df['column_name'].str.replace('[^a-zA-Z0–9]', ' ')

#Or to completely remove these characters
df['column_name'] = df['column_name'].str.replace('[^a-zA-Z0–9]', '')
  • Удалите символы, отличные от ASCII. Чтобы избежать проблем с кодировкой или совместимостью, рассмотрите возможность удаления символов NO-ASCII.
#To remove non-ASCII characters
text = text.encode(“ascii”, errors=”ignore”).decode()

#To remove non-ASCII chracters from a specific column in a DataFrame
df['column1'] = df['column1'].apply(lambda x: x.encode('ascii', errors='ignore').decode() if isinstance(x, str) else x)

#You can also use unidecode module to turn non-ASCII characters into the closest representation in ASCII
from unidecode import unidecode
df['column1'] = df['column1'].apply(lambda x: unidecode(x) if isinstance(x, str) else x)
  • Основное определение. Возможно, вам придется сократить слова до их корневой формы, например, работа ->работа. Имейте в виду, что пропаривание — это процесс, основанный на правилах, и он не учитывает морфологический анализ (своими мыслями о лемматизации в практическом контексте я поделюсь в другой раз).
import pandas as pd
import nltk
nltk.download('punkt')
from nltk.tokenize import word_tokenize
from nltk.stem import PorterStemmer

stemmer = PorterStemmer()

def tokenize_and_stem(text):
    tokens = word_tokenize(text)
    stemmed = [stemmer.stem(token) for token in tokens]
    return ' '.join(stemmed)

df['stemmed_text '] = df['column1'].apply(tokenize_and_stem)

1.7. Проверка. Всегда проверяйте, что ваши данные соответствуют указанным форматам или ограничениям. Есть несколько шагов, которым я следую, чтобы не упустить ни одного нюанса:

  • Описательная статистика: я генерирую сводную статистику высокого уровня (среднее значение, медиана, мода, стандартное отклонение) и сравниваю ее с исходными данными.
  • Анализ распределения: мне нравится, чтобы все было наглядно, и я склонен быстрее выявлять аномалии при визуализации, поэтому я обычно создаю дополнительную гистограмму или коробчатую диаграмму, используя matplotlib или seaborn.
  • Повторная проверка на наличие пропущенных значений. Я еще раз гарантирую, что весь набор данных проверен и все несоответствия устранены.
  • Проверка для конкретного домена. Я консультируюсь по всем последним проблемам с МСП или, если возможно, передаю данные для проверок в конкретном домене.

2. Примечания

Дело не в том, что любой метод предварительной обработки является безотказным. Некоторые дополнительные шаги по пути позволяют мне предварительно обрабатывать данные, не опасаясь, что я их испорчу (и этот страх всегда меня убивает).

2.1. Выбор правильных методов

Не все методы очистки данных подходят для каждой ситуации. Всегда помните о цели вашего анализа и контексте.

2.2. Резервные копии — ваши лучшие друзья

Хранение предыдущих версий данных экономит мне много энергии (и здравомыслия). Особенно, если процесс очистки данных оказывается утомительным и трудоемким, обязательно отслеживайте старые версии и изменения документов, которые вы вносите в данные.

2.3.Хранение необработанных данных

Не забывайте никогда не отбрасывать исходный нефильтрованный набор данных. Часто он служит капсулой времени, предоставляя контекст, который может пригодиться в будущем для справки.

2.4. Переоценка с течением времени

Динамичный характер данных требует регулярной проверки и обновления процесса очистки. То, что хорошо работает для ваших данных сейчас, может не подойти в будущем.

2.5. Автоматизация, но с осторожностью

Хотя автоматизация может сэкономить время, ключевым моментом является соблюдение осторожности. Регулярная проверка на наличие аномалий после автоматизации является обязательной. Это помогает не только улучшить процесс очистки конвейера, но и выявить нюансы, которые впоследствии могут привести к неожиданным наблюдениям.

В великом гобелене анализа данных очистка данных может показаться скромной темой. Но именно эти отдельные нити скрепляют шедевр. Более чистые данные означают более четкое понимание.

Оставайтесь с нами, чтобы прочитать следующую главу, посвященную преобразованию данных.

— — — —

Если вы хотите продолжить обсуждение, напишите мне:

Так весело общаться с другими фанатами данных!