Исследование и подготовка данных — это фундамент, на котором строятся любые проекты в Data Science. Новички часто привыкают к "стерильным" учебным датасетам, где все гладко и чисто. Реальность же больше похожа на археологические раскопки: данные почти всегда неполные, с ошибками, неточностями и, конечно, пропусками.
Пропуски появляются по тысяче причин: сломался датчик, оператор поленился внести данные, произошел сбой при передаче, или в старой базе просто не было такого поля. Игнорировать их нельзя: большинство алгоритмов машинного обучения с пропусками не работают.
В зависимости от источника данных пропуски могут иметь разные обозначения. Наиболее часто используется NaN (Not a Number), но также можно встретить «NA», «None», «-999», «0», « », «-», «?» и другие варианты.
Если в датафрейме отсутствуют данные и они обозначены не как NaN, то их необходимо преобразовать в NaN. Например, можно использовать следующий код:
df = df.replace('', np.nan)
Первая реакция любого, кто работает с Pandas, — вызвать df.isna().sum()
. Мы получаем аккуратную табличку с количеством пропусков по каждому столбцу и чувствуем, что контролируем ситуацию. Но это иллюзия. Знать сколько данных пропущено — это лишь первый шаг. Гораздо важнее понять, как они пропущены. Есть ли в этих пропусках система? Связаны ли они между собой? Являются ли они случайным шумом или сигналом о серьезных проблемах в данных?
Простой подсчет NaN
не ответит на эти вопросы. Чтобы перейти от поверхностного взгляда к глубокому пониманию, нам нужен специализированный инструмент. И здесь на сцену выходит missingno.
Pandas — очень хороший инструмент. И для первичной оценки пропусков у него есть всё необходимое. Прежде чем мы погрузимся в missingno
, быстро вспомним арсенал Pandas, чтобы понять его границы.
Возьмем для примера датасет с данными каротажа по скважинам в Норвежском море. Они содержат серию электрических измерений, которые были получены с помощью инструментов для каротажа скважин. Измерения используются для характеристики геологии недр и определения подходящих залежей углеводородов. Это реальные данные, а значит, они неидеальны.
import pandas as pd
import numpy as np
# Загружаем данные
df = pd.read_csv('https://github.com/obulygin/content/raw/refs/heads/main/xeek_data/xeek_train_subset.csv')
df
1. Метод .info()
Это наш первый взгляд на здоровье датафрейма.
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 133198 entries, 0 to 133197
Data columns (total 22 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 WELL 133198 non-null object
1 DEPTH_MD 133198 non-null float64
2 X_LOC 125805 non-null float64
3 Y_LOC 125805 non-null float64
4 Z_LOC 125805 non-null float64
5 GROUP 133198 non-null object
6 FORMATION 111632 non-null object
7 CALI 133006 non-null float64
8 RSHA 62039 non-null float64
9 RMED 125556 non-null float64
10 RDEP 125805 non-null float64
11 RHOB 108053 non-null float64
12 GR 133198 non-null float64
13 NPHI 91725 non-null float64
14 PEF 100840 non-null float64
15 DTC 132635 non-null float64
16 SP 93680 non-null float64
17 ROP 130454 non-null float64
18 DTS 12184 non-null float64
19 DCAL 56200 non-null float64
20 DRHO 105539 non-null float64
21 LITHOFACIES 133198 non-null int64
dtypes: float64(18), int64(1), object(3)
memory usage: 22.4+ MB
Вывод .info()
уже дает нам важную подсказку. Общее число записей (RangeIndex
) — 133,198. Но Non-Null Count
у многих столбцов (X_LOC
, FORMATION
, CALI
и т.д.) заметно меньше. Это прямое указание на наличие пропусков.
2. Метод .isna().sum()
Самый прямой способ подсчитать пропуски:
df.isna().sum()
WELL 0
DEPTH_MD 0
X_LOC 7393
Y_LOC 7393
Z_LOC 7393
GROUP 0
FORMATION 21566
CALI 192
RSHA 71159
RMED 7642
RDEP 7393
RHOB 25145
GR 0
NPHI 41473
PEF 32358
DTC 563
SP 39518
ROP 2744
DTS 121014
DCAL 76998
DRHO 27659
LITHOFACIES 0
dtype: int64
Метод isna()
возвращает логический массив с True
(если значение является пропуском) и False
- если нет. А sum()
суммирует элементы в этом массиве (где True будут единицами, а False — нулями), так мы и получим количество пропусков. Теперь у нас есть точные цифры. Мы видим, что в некоторых столбцах (X_LOC
, Y_LOC
, Z_LOC
, RDEP
) одинаковое количество пропусков — 7393. Это уже наводит на мысль о неслучайности. Столбец DTS
пропущен более чем в ста тысячх строк — он почти пустой. DCAL
, RSHA
тоже выглядят плохо.
В чем же проблема?
Мы знаем что и сколько. Но мы не видим картину целиком.
X_LOC
, пропущено ли там и Y_LOC
? (Судя по одинаковому числу — да, но это лишь гипотеза).RHOB
с пропусками в CALI
?DTS
свойством определенных скважин или они случайны?Ответы на эти и другие вопросы определяют стратегию работы с данными. Простое удаление строк (dropna()
) может уничтожить ценную информацию, а наивная замена средним — исказить распределение и связи между признаками.
Нам нужен инструмент, который превратит эту сухую таблицу чисел в наглядную карту. И этот инструмент — missingno
.
missingno
— это не просто библиотека для красивых графиков. Это философия визуального аудита данных. Она предоставляет четыре мощных инструмента, каждый из которых отвечает на свой класс вопросов о структуре пропусков.
Установка стандартная:
pip install missingno
А теперь давайте проведем настоящее расследование, используя наш датасет.
msno.bar()
: Быстрая оценка полнотыСтолбчатая диаграмма — это аналог isna().sum()
, но в графическом виде. Она показывает, какая доля данных присутствует в каждом столбце.
import missingno as msno
import matplotlib.pyplot as plt
msno.bar(df)
plt.show()
Как читать этот график:
[!TIP] Когда использовать
msno.bar()
? Это ваш первый шаг. Используйте его сразу после загрузки данных, чтобы получить "общую температуру по больнице" и мгновенно выявить самые проблемные столбцы, которые потребуют пристального внимания.
Этот график полезен, но он все еще не показывает расположение пропусков. Чтобы заглянуть внутрь структуры датафрейма, нам нужен следующий инструмент.
msno.matrix()
: рентген вашего датафреймаМатричный график — это, пожалуй, самый информативный инструмент в арсенале missingno
. Он позволяет буквально заглянуть внутрь датафрейма и увидеть точное расположение каждого пропущенного значения.
msno.matrix(df)
plt.show()
Как читать этот график:
NaN
).Какие выводы можно сделать:
X_LOC
, Y_LOC
, Z_LOC
и RDEP
. Белые горизонтальные черточки в них появляются и исчезают синхронно. Это визуальное подтверждение нашей гипотезы, сделанной на основе isna().sum()
: если пропущено одно из этих значений, скорее всего, пропущены и остальные.[!INFO] Почему матрица так важна? Матричный график переводит наш анализ с уровня "сколько" на уровень "где и как". Он незаменим для временных рядов и любых упорядоченных данных (например, геологических разрезов по глубине), так как позволяет увидеть, являются ли пропуски изолированными событиями или системными сбоями на протяжении определенных периодов/участков.
msno.heatmap()
: Поиск скрытых связейМы уже подозреваем, что пропуски в некоторых столбцах связаны. Тепловая карта создана, чтобы измерить эту связь количественно. Она вычисляет корреляцию отсутствия данных (nullity correlation) между столбцами.
msno.heatmap(df)
plt.show()
Как читать этот график:
<1
: Если вы видите ячейку со значением, которое не равно 1, но меньше него (например, 0.8), это означает, что не все, но многие пропуски совпадают.Какие выводы можно сделать:
RDEP
, RMED
, X_LOC
, Y_LOC
, Z_LOC
. Корреляция между ними очень высока. Это означает, что данные в этих столбцах почти всегда пропадают вместе. Вероятно, они собирались в рамках одного процесса или одним набором инструментов.DTS
и RSHA
. Они не показывают сильной корреляции с другими кластерами. Их пропуски — это отдельная история. При этом между собой они тоже не коррелируют, что интересно.FORMATION
и RHOB
, например, скорее всего, никак не связаны.msno.dendrogram()
: Карта родства пропусковДендрограмма предлагает еще один взгляд на корреляцию отсутствия данных, группируя столбцы с похожими паттернами пропусков с помощью иерархической кластеризации. Это как генеалогическое древо для ваших столбцов, где близкие родственники — это столбцы, чьи пропуски ведут себя похоже.
msno.dendrogram(df)
plt.show()
Как читать этот график:
Какие выводы можно сделать:
LITHOFACIES
, GR
, GROUP
, WELL
, DEPTH_MD
), объединенную на уровне 0. Это наши полностью заполненные столбцы. Их паттерн пропусков идентичен — пропусков нет.X_LOC
, Y_LOC
, Z_LOC
и RDEP
на очень низком уровне, подтверждая их тесную связь. RMED
присоединяется к этой группе чуть выше, что говорит о сильной, но не идеальной связи — именно то, что мы видели на тепловой карте.DTS
, RSHA
и CALI
присоединяются к общему дереву очень высоко. Это значит, что их паттерны пропусков уникальны и не похожи ни друг на друга, ни на другие столбцы. Они — "дальние родственники" для остального набора данных.Ваша поддержка — это энергия для новых статей и проектов. Спасибо, что читаете!
Мы прошли путь от простого подсчета NaN
до глубокого структурного анализа. Библиотека missingno
не заполняет пропуски за вас. Она делает нечто более важное — дает вам исчерпывающую информацию для принятия осознанного решения.
На основе нашего анализа можно наметить конкретный план действий:
DTS
: Пропущено более 85% данных. Пытаться восстановить его — крайне рискованная затея, которая может привнести больше шума, чем сигнала. Наиболее разумная стратегия — удалить этот столбец.RSHA
: Пропущено почти 50% данных. Ситуация пограничная. Можно рассмотреть его удаление или попытаться восстановить значения, но только для тех моделей, которые устойчивы к подобным манипуляциям.X_LOC
, Y_LOC
, Z_LOC
, RDEP
, RMED
: Эти столбцы теряют данные синхронно. Это значит, что если мы решим удалить строки с пропусками (dropna
), мы должны делать это с учетом всего кластера. Удаление строк, где пропущен X_LOC
, почти наверняка приведет к удалению тех же строк, где пропущены Y_LOC
и Z_LOC
.FORMATION
, CALI
, RHOB
): Их пропуски не сильно коррелируют друг с другом. Здесь можно применять более тонкие методы импутации (заполнения): для каждого столбца подбирать свою стратегию (например, заполнение модой для категориального FORMATION
и медианой/средним или даже модельным предсказанием для числовых CALI
и RHOB
).Простой вызов df.isna().sum()
никогда не дал бы нам такой глубины понимания. Визуальный анализ с missingno
превращает проблему пропусков из технической неприятности в интересный исследовательский квест, по итогам которого вы знаете о своих данных гораздо больше. А хорошее знание данных — это и есть ключ к построению качественных моделей.