Очистка и подготовка данных в Pandas и Python

В этом руководстве вы научитесь очищать и подготавливать данные в Pandas DataFrame. Вы узнаете, как работать с пропущенными данными, дубликатами данных и неаккуратными строковыми данными. Умение эффективно очищать и готовить набор данных — важный навык. Многие специалисты по данным считают, что они тратят 80% своего времени на очистку и подготовку своих наборов данных.

Pandas предоставляет вам несколько быстрых, гибких и интуитивно понятных способов очистки и подготовки данных. К концу этого руководства вы узнаете всё, что нужно для начала работы с:

  • Работа с отсутствующими данными с использованием методов, таких как .fillna()

  • Работа с повторяющимися данными с использованием методов, таких как метод .remove_duplicates()

  • Очистка строковых данных с использованием аксессора .str

Обработка отсутствующих данных в Pandas

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

# Загрузка образца DataFrame с использованием библиотеки Pandas
import pandas as pd
import numpy as np

df = pd.DataFrame.from_dict({
    'Name': ['Nik', 'Kate', 'Evan', 'Kyra', np.NaN],
    'Age': [33, 32, 40, 57, np.NaN],
    'Location': ['Toronto', 'London', 'New York', np.NaN, np.NaN]
})
print(df)

# Вывод:
#   Name   Age Location
# 0   Nik  33.0  Toronto
# 1  Kate  32.0   London
# 2  Evan  40.0  New York
# 3  Kyra  57.0     NaN
# 4   NaN   NaN     NaN

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

Понимание метода isnull в Pandas

Pandas предоставляет чрезвычайно полезный метод .isnull(), который определяет, отсутствует ли значение. Метод возвращает логическое значение: True или False. Мы можем применить метод как ко всему DataFrame, так и к одному столбцу. Метод корректно распространяется на Series или DataFrame в зависимости от того, к чему он применяется. Давайте быстро рассмотрим:

# Исследуем метод .isnull()
print(df.isnull())

# Вывод:
#    Name    Age  Location
# 0  False  False     False
# 1  False  False     False
# 2  False  False     False
# 3  False  False      True
# 4   True   True      True

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

Подсчет пропущенных значений в Pandas DataFrame

Первым шагом, который вы захотите предпринять, будет определить, сколько значений отсутствуют в вашем DataFrame. Один из способов сделать это — использовать цепочку методов .isnull() и .sum()

# Выводим количество пропущенных значений в каждом столбце с помощью метода .isnull().sum()
print(df.isnull().sum())

# Вывод:
# Name        1
# Age         1
# Location    2
# dtype: int64

Причина, по которой это работает, заключается в том, что значение True фактически представлено значением 1, а False - значением 0. Благодаря этому мы можем применить метод .sum() к DataFrame. Это возвращает Series, содержащий количество отсутствующих элементов в каждом столбце.

Как подсчитать непропущенные данные в Pandas DataFrame?

В Pandas есть функция отрицания .isnull(). Чтобы посчитать данные, которые не отсутствуют в каждом столбце, можно объединить методы .notnull() и .sum(). Это возвращает Series с количеством ненулевых данных в каждом столбце.

Удаление отсутствующих данных в Pandas DataFrame

При работе с отсутствующими данными часто рекомендуется сделать одно из двух: либо удалить записи, либо найти способы заполнить данные. В этом разделе вы узнаете, как выполнить первое из двух действий. Pandas предоставляет метод .dropna(), который используется для удаления отсутствующих данных. Давайте рассмотрим этот метод:

# Исследуем метод Pandas .dropna()
df.dropna(
    axis=0,         # Указываем, удалять ли строки или столбцы (0 - строки, 1 - столбцы)
    how='any',      # Указываем, удалять ли записи, если 'all' или 'any' из них пропущены
    thresh=None,    # Указывает минимальное количество необходимых заполненных значений для сохранения строки/столбца
    subset=None,    # Указываем, какие строки/столбцы учитывать при удалении
    inplace=False   # Указывает, удалять ли данные в месте (то есть без необходимости заново присваивать)
)

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

# Удаление пропущенных значений с использованием параметров по умолчанию 
df = df.dropna()
print(df)

# Вывод результата после удаления пропущенных значений:
#    Name   Age  Location
# 0   Nik  33.0   Toronto
# 1  Kate  32.0    London
# 2  Evan  40.0  New York

По умолчанию, Pandas удаляет записи, где отсутствует любое значение. Из-за этого также была удалена четвертая строка, в которой отсутствовало только одно значение.

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

# Удаляем строки, если все значения в строке отсутствуют (равны NaN)
df = df.dropna(how='all')
print(df)

# Вывод:
#    Name   Age  Location
# 0   Nik  33.0   Toronto
# 1  Kate  32.0    London
# 2  Evan  40.0  New York
# 3  Kyra  57.0       NaN

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

  • thresh=: количество элементов, которые должны быть пустыми

  • subset=: названия столбцов, которые нужно учитывать при рассмотрении отсутствующих значений.

Заполнение отсутствующих данных в Pandas DataFrame

Удаление пропущенных данных также удаляет любые связанные данные из этих записей. Поэтому может быть полезно заполнить пропущенные значения. Вы можете сделать это, используя метод .fillna(). Метод может быть применен как ко всему DataFrame, так и к одному столбцу. Заполнение константой в качестве параметра заменяет все пропущенные значения на это значение:

# Используем .fillna() для заполнения пропущенных значений нулями
df = df.fillna(0)
print(df)

# Вывод:
#    Name   Age  Location
# 0   Nik  33.0   Toronto
# 1  Kate  32.0    London
# 2  Evan  40.0  New York
# 3  Kyra  57.0       0.0
# 4     0   0.0       0.0

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

# Заполнение столбцов различными значениями
df = df.fillna({'Name': 'Someone', 'Age': 25, 'Location': 'USA'})
print(df)

# Вывод:
#       Name   Age  Location
# 0      Nik  33.0   Toronto
# 1     Kate  32.0    London
# 2     Evan  40.0  New York
# 3     Kyra  57.0     USA
# 4  Someone  25.0     USA

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

# Замена пропущенных значений в столбце 'Age' средним значением этого столбца
df['Age'] = df['Age'].fillna(df['Age'].mean())
print(df)

# Вывод:
#    Name   Age  Location
# 0   Nik  33.0   Toronto
# 1  Kate  32.0    London
# 2  Evan  40.0  New York
# 3  Kyra  57.0     40.5
# 4  NaN  40.5     NaN

В следующем разделе вы узнаете, как справляться с дублированными данными в DataFrame Pandas.

Работа с дублирующимися данными в Pandas

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

# Загрузка образцового DataFrame из библиотеки Pandas
import pandas as pd

df = pd.DataFrame.from_dict({
    'Name': ['Nik', 'Kate', 'Evan', 'Kyra', 'Nik', 'Kate'],
    'Age': [33, 32, 40, 57, 33, 32],
    'Location': ['Toronto', 'London', 'New York', 'Atlanta', 'Toronto', 'Paris'],
    'Date Modified': ['2022-01-01', '2022-02-24', '2022-08-12', '2022-09-12', '2022-01-01', '2022-12-09']
})

print(df)

# Вывод:
#    Name  Age  Location Date Modified
# 0   Nik   33   Toronto    2022-01-01
# 1  Kate   32    London    2022-02-24
# 2  Evan   40  New York    2022-08-12
# 3  Kyra   57   Atlanta    2022-09-12
# 4   Nik   33   Toronto    2022-01-01
# 5  Kate   32     Paris    2022-12-09

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

Выявление дубликатов записей в Pandas DataFrame

Pandas предоставляет полезный метод .duplicated(), который позволяет выявлять дублирующиеся записи в наборе данных. Этот метод, аналогичный методу .isnull(), возвращает булевые значения, когда существуют дубликаты записей. Метод возвращает единственную серию, если записи дублируются.

# Определение дублирующихся записей в DataFrame Pandas
print(df.duplicated())

# Вывод:
# 0    False
# 1    False
# 2    False
# 3    False
# 4     True
# 5    False
# dtype: bool

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

# Подсчет количества дублирующихся записей в DataFrame
print(df.duplicated().sum())

# Вывод:
# 1

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

Удаление дубликатов данных в Pandas DataFrame

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

# Метод Pandas .drop_duplicates() для удаления дублирующихся записей
df.drop_duplicates(
    subset=None,            # Какие столбцы учитывать при определении дубликатов
    keep='first',           # Оставлять ли первую встречу дубликата
    inplace=False,          # Удалять дублирующиеся записи непосредственно в исходном DataFrame
    ignore_index=False      # Пренебрегать индексацией после удаления дубликатов
)

Посмотрим, что произойдет, если применить метод со всеми параметрами по умолчанию:

# Удаление дублирующихся записей с использованием по умолчанию аргументов
df = df.drop_duplicates()
print(df)

# Вывод:
#    Name  Age  Location Date Modified
# 0   Nik   33   Toronto    2022-01-01
# 1  Kate   32    London    2022-02-24
# 2  Evan   40  New York    2022-08-12
# 3  Kyra   57   Atlanta    2022-09-12
# 5  Kate   32     Paris    2022-12-09

Мы видим, что это вернуло DataFrame, где совпали только все элементы. Он сохранил первую запись нашего дубликата (индекс 0).

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

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

# Удаление дублирующихся записей на основе подмножества столбцов
df = df.sort_values(by='Date Modified', ascending=False)
df = df.drop_duplicates(subset=['Name', 'Age'], keep='first')
print(df)

# Вывод:
#    Name  Age  Location Date Modified
# 5  Kate   32     Paris    2022-12-09
# 3  Kyra   57   Atlanta    2022-09-12
# 2  Evan   40  New York    2022-08-12
# 0   Nik   33   Toronto    2022-01-01

Давайте разберем, что мы здесь сделали:

  1. Мы отсортировали данные по 'Date Modified' в порядке убывания. Это размещает более новые записи первыми.

  2. Затем мы удаляем дубликаты на основе 'Name' и 'Age', оставляя первый экземпляр.

В следующем разделе вы узнаете, как очищать строки в Pandas.

Очистка строк в Pandas

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

Давайте загрузим DataFrame Pandas, который содержит строковые данные для работы.

# Загрузка образцового DataFrame из библиотеки Pandas
import pandas as pd

df = pd.DataFrame.from_dict({
    'Name': ['Tranter, Melvyn', 'Lana, Courtney', 'Abel, Shakti', 'Vasu, Imogene', 'Aravind, Shelly'],
    'Region': ['Region A', 'Region A', 'Region B', 'Region C', 'Region D'],
    'Location': ['TORONTO', 'LONDON', 'New york', 'ATLANTA', 'toronto'],
    'Favorite Color': ['   green  ', 'red', '  yellow', 'blue', 'purple  ']
})

print(df)

# Вывод:
#               Name    Region  Location Favorite Color
# 0  Tranter, Melvyn  Region A   TORONTO        green   
# 1   Lana, Courtney  Region A    LONDON            red  
# 2     Abel, Shakti  Region B  New york         yellow  
# 3    Vasu, Imogene  Region C   ATLANTA           blue  
# 4  Aravind, Shelly  Region D   toronto       purple   

Мы видим, что наша DataFrame содержит неупорядоченные строковые данные! Например, некоторые столбцы содержат несколько данных (имя и фамилия), другие имеют избыточные данные (слово «Region»), имеют неаккуратную капитализацию (местоположение) и добавленные пробелы (любимые цвета).

Чтобы применить строковые методы ко всему объекту Series в Pandas, нужно использовать атрибут .str, который предоставляет доступ к векторизованным строковым методам.

Обрезка пробелов в строках Pandas

# Удаление пробельных символов с обеих сторон из столбца DataFrame Pandas
df['Favorite Color'] = df['Favorite Color'].str.strip()
print(df)

# Вывод:
#               Name    Region  Location Favorite Color
# 0  Tranter, Melvyn  Region A   TORONTO          green
# 1   Lana, Courtney  Region A    LONDON            red
# 2     Abel, Shakti  Region B  New york         yellow
# 3    Vasu, Imogene  Region C   ATLANTA           blue
# 4  Aravind, Shelly  Region D   toronto         purple

Здесь мы смогли успешно удалить пробелы из столбца, повторно присвоив его самому себе.

Разделение строк на столбцы в Pandas

Столбец 'Имя' содержит как фамилию, так и имя человека. Во многих случаях вам может понадобиться разделить этот столбец на два – отдельно для имени и фамилии. Этот подход будет работать немного иначе, так как нам нужно будет назначить два столбца, а не один.

Посмотрим, что произойдет, когда мы применим метод .str.split() к столбцу:

# Применение метода .split на столбце DataFrame Pandas
print(df['Name'].str.split(','))

# Вывод:
# 0    [Tranter,  Melvyn]
# 1     [Lana,  Courtney]
# 2       [Abel,  Shakti]
# 3      [Vasu,  Imogene]
# 4    [Aravind,  Shelly]
# Name: Name, dtype: object

Мы видим, что это вернуло список строк. Однако, чтобы назначить это нескольким столбцам, нам нужно передать аргумент expand=True, чтобы указать Pandas разделить значения на отдельные элементы. После этого мы можем присвоить значения двум столбцам.

# Разделение столбца 'Name' на два новых столбца: 'Last Name' и 'First Name'
df[['Last Name', 'First Name']] = df['Name'].str.split(',', expand=True)

print(df)

# Вывод:
#               Name    Region  Location Favorite Color Last Name First Name
# 0  Tranter, Melvyn  Region A   TORONTO        green     Tranter     Melvyn
# 1   Lana, Courtney  Region A    LONDON            red      Lana   Courtney
# 2     Abel, Shakti  Region B  New york         yellow      Abel     Shakti
# 3    Vasu, Imogene  Region C   ATLANTA           blue      Vasu    Imogene
# 4  Aravind, Shelly  Region D   toronto       purple     Aravind     Shelly

Обратите внимание на использование двойных квадратных скобок. Это необходимо, так как мы передаем список колонок, которые хотим создать!

Замена текста в строках в Pandas

В столбце 'Region' слово «Region» избыточно. В этом примере вы научитесь заменять текст в столбце. В частности, вы научитесь удалять заданную подстроку в более длинной строке. Для этого мы можем использовать метод .replace(), который как раз подходит для такой задачи. Метод принимает строку, которую мы хотим заменить, и строку, на которую хотим заменить. Поскольку мы хотим удалить подстроку, мы просто передадим пустую строку в качестве замены.

# Замена подстроки в столбце DataFrame Pandas
df['Region'] = df['Region'].str.replace('Region ', '')

print(df)

# Вывод:
#               Name Region  Location Favorite Color
# 0  Tranter, Melvyn      A   TORONTO        green  
# 1   Lana, Courtney      A    LONDON            red
# 2     Abel, Shakti      B  New york         yellow
# 3    Vasu, Imogene      C   ATLANTA           blue
# 4  Aravind, Shelly      D   toronto       purple  

Изменение регистра строк в Pandas

В этом разделе мы узнаем, как исправить странные и несоответствующие регистры, которые существуют в столбце 'Location'. Pandas предоставляет доступ к ряду методов, позволяющих изменять регистр строк:

  • .upper() преобразует строку в верхний регистр.

  • .lower() преобразует строку в нижний регистр

  • .title() преобразует строку в формат заглавных букв

В этом случае мы хотим, чтобы наши местоположения были в виде заголовков, поэтому мы можем применить метод .str.title() к строке:

# Преобразование текста в столбце DataFrame Pandas к формату заголовков (title case)
df['Location'] = df['Location'].str.title()
print(df)

# Вывод:
#               Name    Region  Location Favorite Color
# 0  Tranter, Melvyn  Region A   Toronto        green  
# 1   Lana, Courtney  Region A    London            red  
# 2     Abel, Shakti  Region B  New York         yellow  
# 3    Vasu, Imogene  Region C   Atlanta           blue  
# 4  Aravind, Shelly  Region D   Toronto       purple   

Мы видим, что применяя метод .str.title(), каждое слово было написано с заглавной буквы.

Упражнения

Пришло время проверить свои знания! Попробуйте решить упражнения ниже. Если вы хотите проверить свое решение, просто переключите поле, чтобы увидеть пример решения. Загрузите приведенный ниже DataFrame, чтобы ответить на вопросы:

# Загрузка DataFrame из библиотеки Pandas с использованием словаря данных
import pandas as pd
import numpy as np

df = pd.DataFrame.from_dict({
    'Name': ['Tranter; Melvyn', 'Lana; Courtney', 'Abel; Shakti', 'Vasu; Imogene', 'Aravind; Shelly', 'Tranter; Melvyn'],
    'Location': ['TORONTO', 'LONDON', 'New york', np.NaN, 'toronto', 'Madrid'],
    'Sales': [123, 243, 654, np.NaN, 345, np.NaN]
})

print(df)

# Вывод:
#               Name   Location  Sales
# 0     Tranter; Melvyn    TORONTO   123.0
# 1      Lana; Courtney    LONDON   243.0
# 2        Abel; Shakti  New york   654.0
# 3      Vasu; Imogene       NaN     NaN
# 4      Aravind; Shelly   toronto   345.0
# 5     Tranter; Melvyn    Madrid     NaN
  • Question 1

  • Question 2

  • Question 3

Создайте столбцы Имя и Фамилия. Обратите внимание, что имена разделены точкой с запятой.

df[['Last Name', 'First Name']] = df['Name'].str.split(';', expand=True)

Удалите все дублирующиеся записи, основываясь только на столбце "Name", сохраняя последнюю запись.

df = df.drop_duplicates(subset='Name', keep='last')

Рассчитать процент отсутствующих записей в каждом столбце.

Разделите результат df.isnull().sum() на длину датафрей

print(df.isnull().sum() / len(df))

# Вывод:
# Name        0.000000
# Location    0.166667
# Sales       0.333333
# dtype: float64

Заключение и резюме

В этом руководстве вы узнали, как использовать Pandas для очистки данных! В следующем разделе приведен краткий обзор того, что вы узнали в этом руководстве:

  • Pandas предоставляет множество методов для манипуляции и очистки данных.

  • Пропущенные данные можно определить с помощью метода .isnull(). Количество пропущенных данных по каждому столбцу можно подсчитать, добавив метод .sum(), который возвращает Series с количеством по каждому столбцу.

  • Пропущенные данные можно удалить с помощью метода .dropna(), который можно настроить с использованием различных параметров.

  • Повторяющиеся данные можно найти с помощью метода .isduplicate()

  • Метод .drop_duplicates() может быть использован для удаления дублирующих записей, предлагая значительные возможности для настройки того, какие записи считать дубликатами

  • Pandas может использовать строковые методы Python через атрибут .str. Это может быть полезно для применения векторизированных методов очистки к неструктурированным текстовым данным.

Дополнительные ресурсы

To learn more about related topics, check out the following tutorials:

  • Pandas Fillna – Работа с пропущенными значениями

  • Установить условный столбец Pandas на основе значений другого столбца

Last updated