Я не любитель читать статьи, где много рассуждают о том почему эта статья существует и как она появилась на свет. Поэтому просто перейду к делу.
У нас есть проблема: Пропуски (пустоты) в данных. Нам надо понять, что с ними делать и как справляться. Я разложил эту статью на 4 раздела:
- Разбираем тип возникновения пропусков.
- Научитесь анализировать пустоты.
- Покажу как их обрабатывать.
- В заключении покажу, что я сделал со своими пропусками в датасете.
Тип возникновения пропусков.
У кого не спроси, все специалисты знают, что пропуски делятся на 3 типа, надо выяснить, к какому именно типу относиться пропуск, если сделали, то это уже пол дела:
1. MCAR (Missing Completely At Random) - в рандомный момент появился пропуск, он ни от чего не зависит. Вот несколько примеров:
- стоит у вас датчик, который фиксирует температуру, его работа зависит от питания с розетки на сетевом фильтре, а новый работник выключал этот сетевой фильтр, в разные дни, в итоге данных по температуре в определенные дни не наблюдалось.
- вы загрузили файл с интернета, когда у вас сбоила связь, и файл скачался с отсутствием некоторых данных.
- или Самый простой: допустим у тебя список людей на листочке с обозначением их роста и веса. Пошел дождь и капнул на листок, некоторые значения размыло. Вот и образовались пропуски
2. MAR (Missing At Random) - пропуск, который зависит от других показателей в наборе данных, но не от пропущенных. Пропущенные на него не влияют! Примеры:
- Мужчины реже указывают возраст, чем женщины. В 60% случаев мужчины не пишет свой возраст, когда женщины только в 95% случаев. Почему MCAR? Данные зависят от Пола.
- Люди с средним уровнем дохода и выше, возьмем порог примерно в 100 тыс. в месяц, не пишут в графе зарплата свои данные. Снова отсутствуют данные из-за того, что человек просто зарабатывает выше среднего.
- Даже в школе могли случайно поставить Н (отсутствовал на уроке), по причине, что, если у ученика много прошлых «Н» (невыполненных заданий), учитель чаще пропускает оценку. Пропуск зависит от предыдущих оценок, а не от текущего уровня знаний.
3. MNAR (Missing Not At Random) - пропуски зависят от ненаблюдаемых факторов или от самих пропущенных значений.
- стоит задача: собрать данные по температуре на Солнце, но вы прилетели туда с термометром, которым измеряли собственную температуру. У вас не получилось собрать данные потому, что данные экстремально высокие.
- самый простой пример: Мама спрашивает детей: "Кто съел конфеты?" Что происходит: Кто не брал конфеты — спокойно говорят "Не я", Кто съел немного — говорят "Я взял одну", Кто съел много — просто молчат (пропуск в данных!) Почему это MNAR: Пустые ответы — это именно те, кто наелся конфет, чем больше провинность, тем вероятнее пропуск, если считать только ответивших, получится, что конфет съели меньше, чем на самом деле.
Если и теперь не понятно, то Напишите в комментах, попробуем разобраться.
Анализирование пропусков
Перед тем как заполнять или удалять пропуски, нужно их тщательно изучить. Давайте возьмем тот же Датафрейм, который мы использовали в уроке по подготовки таблицы.
1. Визуализация пропусков
1.1. Матрица пропусков (missingno.matrix)
- Белые полосы - это пропущенные значения
- Позволяет увидеть:
Общий паттерн пропусков
Связаны ли пропуски между столбцами
Случайное или систематическое распределение
1.2. Тепловая карта корреляции пропусков
- Показывает, как связаны пропуски между разными столбцами
- Чаще использую, когда столбцов с пропусками больше
- Значения от -1 до 1:
1 = если пропуск в одном столбце, то обязательно в другом
-1 = если в одном есть, в другом нет
0 = нет связи
2. Статистический анализ
a) Базовая статистика:
df.isna().sum() # cчитаем количество пропущенных значений.
df.isna().mean() * 100 # cчитаем процент пропущенных значений
b) Анализ распределения:
# Для числовых данных
df[df['column'].isna()]['other_column'].describe()
# Для категориальных
df[df['column'].isna()]['other_column'].value_counts()
3. Анализ зависимостей
a) Сравнение групп:
# Создаем метку пропусков
df['missing_flag'] = df['column'].isna()
# Сравниваем статистики
df.groupby('missing_flag')['other_column'].describe()
b) Визуальное сравнение:
import seaborn as sns
sns.boxplot(x='missing_flag', y='other_column', data=df)
4. Практические рекомендации
- Очень важно! Разберитесь в теме, в которой прийдется работать с данными, изучите "вдоль и поперек" зависимости данных, узнайте как формировалась таблица и т.д. Понимание того с какими данными вы работает, решит большинство ваших проблем связанных с пропусками. Например, зная, что У автомобилей может быть разное поколение, вы можете понимать примерные года выпуска автомобиля.
- Критические пороги (по началу можно использовать, когда станете более опытными, будете понимать, что это условные цифры и многие данные важны):
<5% пропусков → можно заполнять
5-30% → требуется осторожное заполнение
30% → рассмотреть удаление столбца - Документирование:
Фиксировать долю пропусков
Записывать обнаруженные зависимости
Сохранять визуализации
Обработка пропусков
Рассмотри два основных метода заполнения пропусков - Удаление и Заполнение.
1. Удаление
Complete-Case Analysis (Listwise Deletion Method). Метод для удаления строк и столбцов - dropna(). Этот метод подходит, если пропусков в строках мало (<5%) и они MCAR, если признак содержит >30-50% пропусков и не критичен для модели. Эти 2 условия должны ОБЯЗАТЕЛЬНО выполняться, иначе вы можете потерять большое количество данных, возрастают стандартные отклонения, сильно меняются средние и медианы, репрезентативность данных падает.
Если вы все-таки решили, что "мне нужно удалить данные, даже если это MAR (тем более MNAR)", то запомните, статистические свойства выборки, изменение параметров построенных моделей, увеличение стандартных отклонений становятся еще сильнее.
Удалить вы всегда успеете, лучше сначала рассмотрите, как можно их заменить.
2. Заполнение
Рассмотрим метод Mean Substitution - заполнение пустот средним значением. Альтернативные варианты (заполнение медианой, нулем и т.п.). Это, конечно, все хорошо, просто взял и заполнил. "Можно не париться!" - подумаете вы, но этого тоже есть свои недостатки:
Представим, что у нас есть данные, где 200 тыс. наблюдений, из них в одном столбце 50 тыс. пропусков, проанализировав мы определились, что тип пропуска MCAR. Разброс значений от -83 до 1577. при это среднее у них 688, а медиана равна 42. Значит в данных присутствуют выбросы, среднее значение очень чувствительно к ним. Если мы заменим все средним значением, то это данные становятся не репрезентативными. Тоже самое относиться и к медианым значениям.
В случае с категориальными переменными, то тут тоже не все так однозначно, можно заполнить словом None или Модой (часто встречающиеся значение), но это тоже исказит данные.
Мы можем заменить пропусками медианой, средним значением, константой, но важно понимать:
- Разброс значений не велик, выбросы есть, но они не критичны, если данные распределены нормально, только вот это идеальная картина мира, которая бывает очень редко
- Прежде чем заполнять данные лучше несколько раз убедиться на графиках и зависимостях, что они не повредят обучению модели, ведь мы же для этого всё делаем.
Перейдем к работе с пропусками на моем датасете
Я всегда начинаю с того, что анализирую пропуски и потом делаю выводы. Напомню небольшие числа:
Количество пропусков столбца "production_year" - 27 из 200
Процент пропусков столбца "production_year" - 13.5%
1. Визуализация на показала следующее:
На гистограмме мы увидели двух пиковый тип. Это значит, что большинство значений в двух местах, в нашем случае это 1995 год и 2025 год.
При этом на диаграмме "Ящик с усами" мы не видим четких выбросов.
Если бы таблица была больше и значения были бы чуть шире, то мы бы увидели выбросы. По этой диаграмме, я бы не делал однозначных выводов, т.к. гистограмма в нашем случае более информативна.
Возвращаясь к матрице пропусков и тепловой карте пропусков. Здесь мы видим, что на матрице есть строки, где пропущены значения сразу в двух столбцах, но при этом корреляция показывает, что пропуски между собой слабо зависимы. Поэтому целые строки я удалять не буду.
Теперь рассмотрим корреляцию пропущенных значением с годом выпуска и и ключевым признаком ("Цена"):
Корреляция слабая положительная. Год не сильно влияет на цену, в целом на этом бы я и закончил и удалил строки, но есть и другие признаки, которые могут повлиять на цену, поэтому всегда анализируйте их, сейчас мы этим заниматься не будем, потому что в удалении нет смысла и я вам покажу почему. Чтобы у вас было понимание как анализировать корреляцию, оставлю здесь небольшую таблицу:
Интересно было то, что у всех брендов автомобилей, кроме Mercedes, были пропуски. Они распределялись следующим образом:
Поэтому я взялся за эту мысль и решил посмотреть какого года автомобиль по бреду и пробегу. Пробег я разделил на группы в разницу пробега 20 тыс. км. То есть мы берем Audi и смотрим средний год на каждый 20 тыс. км пробега.
После этого я решил, что я буду выводить среднюю между медианой и средним значением года выпуска автомобилей исходя из бренда и количества пробега этого автомобиля. Таким способом я заполню пропуски.