Методы очистки данных в Pandas

от автора

Привет, Хабр!

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

Очищать грязные данные можно c Pandas. Рассмотрим основные методы.

Пропущенные значения

Пропущенные значения могут возникать по разным причинам. Вне зависимости от причины, сначала их нужно обнаружить.

isnull() в Pandas возвращает DataFrame или Series с булевыми значениями, где True указывает на пропущенное значение. Аналогично, notnull() возвращает True для элементов, где значение присутствует:

# удаляем строки, где есть хотя бы одно пропущенное значение cleaned_df = df.dropna()  # заполняем все пропущенные значения нулями filled_df = df.fillna(0)  print("Очищенный DataFrame:\n", cleaned_df) prit("DataFrame с заполненными пропусками:\n", filled_df)

Код выведет таблицу, где True обозначает пропущенные значения.

— Что с ними делать дальше? Один из подходов – удаление строк или столбцов с пропусками, но это может привести к потере какой-то информации. Другой подход – заполнение пропусков.

Для заполнения пропусков используем метод fillna():

# заполняем пропуски средним значением по столбцам df.fillna(df.mean(), inplace=True)  print("df с заполненными пропусками средним:\n", df)

Для категориальных данных может быть разумно заполнить пропуски наиболее часто встречающимся значением:

# заполнение пропусков в зависимости от условий df['A'].fillna(value=df['A'].mean(), inplace=True) df['B'].fillna(value=df['B'].median(), inplace=True)  # кастомная функция для заполнения def custom_fill(series):     return series.fillna(series.mean())  df.apply(custom_fill)

Удаление с помощью dropna()

По умолчанию dropna() удаляет строки, которые содержат хотя бы одно пропущенное значение:

import pandas as pd import numpy as np  df = pd.DataFrame({     'Name': ['ivan', 'artem', np.nan, 'diana', 'eva'],     'Age': [25, np.nan, np.nan, 27, 28],     'City': ['New York', 'Los Angeles', 'Chicago', np.nan, 'Miami'] })  # удаляем строки с пропущенными значениями df_cleaned = df.dropna() print(df_cleaned)

dropna() удаляет все строки, где есть хотя бы одно NaN.

Чтобы удалить столбцы, содержащие пропущенные значения можно юзать параметр axis=1:

df_cleaned_columns = df.dropna(axis=1) print(df_cleaned_columns)

Можно удалить строки, где все значения пропущены с помощью параметра how='all':

# добавляем строку, полностью состоящую из NaN df.loc[5] = [np.nan, np.nan, np.nan]  # удаляем строки, где все значения являются NaN df_cleaned_all = df.dropna(how='all') print(df_cleaned_all)

Можно указать столбцы, для которых должна быть применена проверка на NaN, используя параметр subset.

# удаляем строки, где пропущены значения в определенных столбцах df_cleaned_subset = df.dropna(subset=['Name', 'City']) print(df_cleaned_subset)

В этом случае будут удалены только те строки, в которых отсутствуют значения в столбцах Name или City

thresh позволяет указать минимальное количество непропущенных значений, при котором строка или столбец сохраняется:

# удаляем строки, где менее двух непропущенных значений df_cleaned_thresh = df.dropna(thresh=2) print(df_cleaned_thresh)

Кастомные варианты

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

Ср. значение:

import pandas as pd import numpy as np  df = pd.DataFrame({     'A': [1, 2, np.nan, 4, 5],     'B': [np.nan, 2, 3, np.nan, 5],     'C': [1, 2, 3, 4, np.nan] })  # заполняем пропущенные значения в столбце A средним значением по этому столбцу df['A'].fillna(df['A'].mean(), inplace=True)

Медиана

Медиана может быть предпочтительнее среднего значения в случаях, когда данные содержат выбросы, которые могут исказить среднее:

# фулим пропущенные значения в столбце B медианой df['B'].fillna(df['B'].median(), inplace=True)

Мода

Для категориальных данных или данных с дискретными значениями можно использовать моду:

# C - категориальный столбец, заполняем пропущенные значения модой df['C'].fillna(df['C'].mode()[0], inplace=True)

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

# Заполняем пропущенные значения в столбце A, используя кастомную логику df['A'].fillna(df.apply(lambda row: row['B'] if pd.isnull(row['A']) else row['A'], axis=1), inplace=True)

Когда заполнение должно учитывать группировку по какому-либо признаку, можно использовать apply() или transform() совместно с groupby():

# допустим, есть столбец группы, и мы хотим заполнить пропуски средним значением внутри каждой группы df['group'] = ['X', 'X', 'Y', 'Y', 'Z'] df['A'] = df.groupby('group')['A'].transform(lambda x: x.fillna(x.mean()))

А что насчет дупликатов?

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

drop_duplicates() позволяет не только удалять полные дубликаты строк, но и предоставляет настройки для работы с частичными дубликатами, удалим полные дупликаты:

import pandas as pd  df = pd.DataFrame({     'A': [1, 2, 2, 3, 3, 3],     'B': ['a', 'b', 'b', 'c', 'c', 'c'],     'C': [100, 200, 200, 300, 300, 300] })  # удаляем дубликаты df_unique = df.drop_duplicates()  print(df_unique)

Код удалит все полные дубликаты строк, оставив уникальные комбинации значений по всем столбцам.

Часто нужно удалять дубликаты, основываясь не на всех столбцах, а только на некоторых. Для этого в drop_duplicates() есть параметр subset:

# удаляем дубликаты, основываясь только на столбцах 'A' и 'B' df_unique_subset = df.drop_duplicates(subset=['A', 'B'])  print(df_unique_subset)

keep позволяет контролировать, какие дубликаты будут удалены: первый, последний или все:

# Удаляем все дубликаты, кроме последнего вхождения df_keep_last = df.drop_duplicates(keep='last')  print(df_keep_last)

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

# преобразуем все строки в нижний регистр и удаляем пробелы df['B'] = df['B'].str.lower().str.replace(' ', '')  # теперь удаляем дубликаты df_preprocessed = df.drop_duplicates()  print(df_preprocessed)

Категориальные данные

get_dummies() используется для преобразования категориальных переменных в фиктивные/индикаторные переменные, кстати в ml юзается довольно часто:

import pandas as pd  df = pd.DataFrame({     'Color': ['Red', 'Green', 'Blue', 'Green'] })  # преобразуем категориальные данные в индикаторные переменные dummies = pd.get_dummies(df['Color']) print(dummies)

В результате каждое уникальное значение в столбце Color превращается в отдельный столбец с индикаторными переменными (0 или 1), указывающими на присутствие или отсутствие данной категории в каждой строке.

factorize() используется для получения числового представления категориальных данных, присваивая каждой уникальной категории целочисленный идентификатор:

# получаем числовое представление категориальных данных codes, uniques = pd.factorize(df['Color'])  print(codes)  # массив кодов print(uniques)  # массив уникальных значений

str-методы позволяют выполнять такие операции, как преобразование регистра, поиск и замена подстрок, разбиение строк и т.п:

df_text = pd.DataFrame({     'Text': ['This is a test.', 'Hello, World!', 'Otus!'] })  # преобразуем все тексты в нижний регистр df_text['Text_lower'] = df_text['Text'].str.lower()  # удаляем знаки пунктуации df_text['Text_clean'] = df_text['Text'].str.replace('[^\w\s]', '', regex=True)  print(df_text)

Иногда можно использовать str.replace(), str.findall().

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

# преобразование кодов обратно в текстовые категории df['Color_restored'] = codes df['Color_restored'] = df['Color_restored'].map(lambda x: uniques[x])  print(df)

Какие методы очистки знаете вы?

В преддверии старта курса Аналитик данных хочу пригласить вас на бесплатные вебинары про подготовку данных в Pandas, а также про SQL в реалиях начинающего дата-аналитика.


ссылка на оригинал статьи https://habr.com/ru/articles/797283/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *