Давайте рассмотрим распространенную проблему с пропущенными данными и способы ее решения.

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

Кстати, подписывайтесь на наши социальные сети, мы туда еженедельно публикуем топовый контент! Вот наш канал в телеграм и группа ВК.

Таблица 1: Пример набора данных о машинах

Марка

Модель

Год выпуска

Цена

Нормализованные потери

Тип топлива

Toyota

Corolla

2019

15000

134

Бензин

Honda

Civic

2020

17000

NaN

Дизель

Ford

Mustang

2018

25000

235

NaN

Subaru

Outback

2017

NaN

178

Бензин

Hyundai

Elantra

2021

18000

156

Гибрид

Nissan

Sentra

2019

15500

170

Бензин

Давайте сначала создадим датафрейм для примера:

import pandas as pd
# Создание DataFrame
data = {
    'Марка': ['Toyota', 'Honda', 'Ford', 'Subaru', 'Hyundai', 'Nissan'],
    'Модель': ['Corolla', 'Civic', 'Mustang', 'Outback', 'Elantra', 'Sentra'],
    'Год выпуска': [2019, 2020, 2018, 2017, 2021, 2019],
    'Цена': [15000, 17000, 25000, None, 18000, 15500],
    'Нормализованные потери': [134, None, 235, 178, 156, 170],
    'Тип топлива': ['Бензин', 'Дизель', None, 'Бензин', 'Гибрид', 'Бензин']
}
df = pd.DataFrame(data)

Как обработать пропущенные данные? 

Каждая ситуация уникальна, и подход к ней должен быть индивидуальным. Давайте начнем с восстановления данных.

1 Способ: Восстановление данных

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

Например, если вам известно, что пропущенное значение нормализованных потерь для Honda Civic составляет 150, то вы можете его восстановить.

Сделать это можно так:

#Заполнение пропущенных значений на основе дополнительной информации
df.loc[df['Модель'] == 'Outback', 'Цена'] = 17625
df.loc[df['Модель'] == 'Civic', 'Потери'] = 150
df.loc[df['Модель'] == 'Mustang', 'Тип топлива'] = 'Дизель'

Таблица 2: Набор данных с заполненными пропущенными значениями

Марка

Модель

Год выпуска

Цена

Нормализованные потери

Тип топлива

Toyota

Corolla

2019

15000

134

Бензин

Honda

Civic

2020

17000

150

Дизель

Ford

Mustang

2018

25000

235

Дизель

Subaru

Outback

2017

17625

178

Бензин

Hyundai

Elantra

2021

18000

156

Гибрид

Nissan

Sentra

2019

15500

170

Бензин

2 Способ: Удаление данных

Но, к сожалению, не всегда данные можно восстановить из источника.

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

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

# Удаление строк с пропущенными значениями в столбце "Цена"
df = df.dropna(subset=['Цена'])

Таблица 3: Набор данных с удаленными строками, содержащими пропущенные значения

Марка

Модель

Год выпуска

Цена

Нормализованные потери

Тип топлива

Toyota

Corolla

2019

15000

134

Бензин

Honda

Civic

2020

17000

NAN

Дизель

Ford

Mustang

2018

25000

235

NAN

Hyundai

Elantra

2021

18000

156

Гибрид

Nissan

Sentra

2019

15500

170

Бензин

3 Способ: замена пропущенных значений средним

Еще один из стандартных методов - замена пропущенных значений средним значением по переменной.

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

# Замена пропущенных значений средними значениями
df['Цена'].fillna(df['Цена'].mean(), inplace=True)
df['Нормализованные потери'].fillna(df['Нормализованные потери'].mean(), inplace=True)

Таблица 4: Набор данных с замененными пропущенными значениями средними значениями

Марка

Модель

Год выпуска

Цена

Нормализованные потери

Тип топлива

Toyota

Corolla

2019

15000

134

Бензин

Honda

Civic

2020

17000

174.6

Дизель

Ford

Mustang

2018

25000

235

NAN

Subaru

Outback

2017

18100

178

Бензин

Hyundai

Elantra

2021

18000

156

Гибрид

Nissan

Sentra

2019

15500

170

Бензин

На самом деле, хитростей много. И это не единственный практический пример. Например, в Симуляторе «Аналитик данных» от Simulative мы разбираем просто кучу реальных кейсов.

4 Способ: Оставить все, как есть

Но что, если эти значения нельзя усреднить, как в случае с категориальными переменными? 

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

# Замена пропущенных значений в столбце "Тип топлива" на наиболее часто встречающееся значение
mode_fuel_type = df['Тип топлива'].mode()[0]  # Вычисление моды (наиболее часто встречающегося значения)
df['Тип топлива'].fillna(mode_fuel_type, inplace=True)

Таблица 5: Набор данных с заменой пропущенных значений в столбце "Тип топлива"

Марка

Модель

Год выпуска

Цена

Нормализованные потери

Тип топлива

Toyota

Corolla

2019

15000

134

Бензин

Honda

Civic

2020

17000

174.6

Дизель

Ford

Mustang

2018

25000

235

Бензин

Subaru

Outback

2017

18100

178

Бензин

Hyundai

Elantra

2021

18000

156

Гибрид

Nissan

Sentra

2019

15500

170

Бензин

В этом примере мы заменили пропущенные значения в столбце "Тип топлива" на наиболее часто встречающееся значение, которое в данном случае является "Бензин".

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

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

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

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

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

  • Замена пропущенных значений может исказить структуру данных. Например, замена средним значением может создать ложное представление о распределении.

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

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

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

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

Комментарии (2)


  1. sunsexsurf
    12.11.2023 16:00
    +1

    Вы почти не раскрыли (может, опосредованно об этом было сказано в п.5) идею того, что пропуски можно заполнять усредненным значением по кластеру: т.е. сперва вы разбиваете датасет на кластеры, потом выбираете, каким средним пользоваться (обычное, усеченное, медиана или даже мода) и им заполняете. Тогда вы сможете немного побороться с тем, что посчитаете это усреднение не по всему датасету, а только по тем соседям, которые к этому кластеру относятся. И вот эта идея - часто гораздо более аккаратная по отношению к пропускам, нежели бездумное .fillna() по всем данным.


  1. AlexMegunovv
    12.11.2023 16:00

    киньте ссылочку на гит плиз