← Все курсы · Курс Python · Все руководства

Обработка пропущенных значений в pandas: водянка, чувствовать и что утверждает каждый

Каждый вариант представляет собой заявление о том, какое значение было отсутствующим. · Часть Analyst Prep Kit

К , аналитик данных · Опубликовано

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

Вот что нужно сделать сегодня, прежде чем что-либо решать. Бегать df.isna().sum() и запишите цифры. Затем запустите len(df.dropna()) и сравните его с len(df). Эти две строки сообщают вам, чего не хватает и сколько будет стоить самое ленивое исправление, и большинство людей стремятся к исправлению, даже не зная ни одной цифры.

Краткая версия: pandas с радостью пропустит пропущенные значения в сводке, удалит содержащие их строки или заменит их чем-то по вашему выбору. Все три — решения, и только одно из них честно по умолчанию.

То, что заполнение средним значением влияет на разброс, — это идея, поэтому она получает картину.

Filled values are not observations A horizontal value axis runs across the picture with a tall dashed vertical line standing at the average. Fourteen small solid blue dots are scattered along the axis at their own positions, some well to the left of the dashed line and some well to the right, so the real measurements are spread out. Above the axis sit two hollow circles drawn with dashed outlines, standing for the two values that were never recorded. A short arrow drops from each hollow circle straight down onto the dashed average line, where two solid amber dots now sit, one on top of the other, exactly on the line. Every other dot is somewhere of its own; these two are on the average and nowhere else, so the picture shows that the filled points contribute no spread at all.
Четырнадцать реальных значений распределены по оси. Те два, которые никогда не записывались, помещаются точно в среднее значение, поэтому они добавляются к подсчету, не добавляя никаких отклонений, и данные выглядят более согласованными, чем они были измерены.
Что вы узнаете
  1. Сначала найди их и посчитай.
  2. дропна и что для этого нужно
  3. Резюме уже пропускают их
  4. Заполнение нулями
  5. Заполнение средним значением
  6. Прямое заполнение и значение, которое оно создает
  7. Отсутствующее значение, которое не сохраняется как отсутствующее.
  8. группировка тихо роняет недостающий ключ
  9. Полное до и после
  10. Пограничные случаи, которые стоит знать
  11. Почему это работает
  12. Использование этого в вашем собственном проекте
  13. Все на одном экране
Каждое число на этой странице является реальным. Таблица заказов из шестнадцати строк, используемая во всем этом наборе руководств, с семью ячейками, намеренно удаленными, работает в pandas 3.0.2. Шестнадцать строк достаточно малы, чтобы проверить любую из них вручную.

1. Сначала найдите их и посчитайте.

Одна строка, и это единственное место, где появляется вся картина.

df.isna().sum()

order_id      0
order_date    0
rep           0
region        1
product       0
units         2
unit_price    1
revenue       3

128 cells in the frame, 7 of them missing

Семь ячеек из ста двадцати восьми. Обратите внимание, что revenue не хватает троих, где units имеет два и unit_price имеет один: доход рассчитывается на основе обоих, поэтому дыра в любом из них приводит к дыре в результате. Отсутствие распространяется через арифметику, а производный столбец отсутствует везде, где есть какие-либо его входные данные.

Еще две линии стоит запустить одновременно. df.isna().mean() дает пропорцию, а не количество, которое вы и будете цитировать. И df.isna().sum(axis=1) дает счетчик на строку, который показывает, сосредоточены ли дыры в нескольких плохих строках или разбросаны по многим, и эти две ситуации требуют разного подхода.

2. дропна и что для этого нужно

Перед пояснением: из шестнадцати строк пропущено семь ячеек. Скажите, сколько строк сохранилось dropna().

len(df)                          16
len(df.dropna())                 12
len(df.dropna(subset=["units"])) 14
len(df.dropna(how="all"))        16
df.dropna(axis=1).shape[1]        4 of 8 columns

Простой dropna() удалил четыре строки, четверть таблицы, чтобы разобраться с семью ячейками. По умолчанию это how="any": строка идет, если любой столбец в нем отсутствует, включая столбцы, которые вы не собирались использовать. Это наиболее распространенный способ случайно выбросить данные.

Три аргумента, которые делают это намеренным:

ВызовУдаляет строку, когдаИспользуйте, когда
dropna()Отсутствует какой-либо столбецРедко. Вы собираетесь использовать каждый столбец.
dropna(subset=["units"])Столбцы, которые вы называете, отсутствуют.Обычно. Укажите, что необходимо для анализа.
dropna(how="all")Каждый столбец отсутствуетОчистка действительно пустых строк из импорта.
dropna(thresh=8)Менее 8 столбцов имеют значениеУдаление строк слишком редко, чтобы быть полезным.

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

Что бы вы ни использовали, напечатайте количество строк до и после. Потеря четверти стола – это находка; потерять его, не заметив, — вот проблема.

3. В аннотациях их уже нет

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

units, with two values missing
  count 14   sum 74.0   mean 5.2857   std 2.5246

the same column with nothing missing
  count 16   sum 101    mean 6.3125   std 3.7008

В каждой сводке пропущены пропущенные значения, вместо того, чтобы выдавать ошибки или ничего не возвращать. sum добавил четырнадцать, которые у него были. mean разделить на четырнадцать, а не на шестнадцать. И count сообщает четырнадцать, вот в чем суть: count сообщает вам, из скольких значений была вычислена сводка, и сравнение ее с количеством строк — самая дешевая проверка на недостающие данные.

Такое поведение полезно, и это также тихая часть. Среднее значение по столбцу, в котором отсутствует одна восьмая, представляет собой утверждение о семи восьмых, которые ответили, и оно будет представлено как утверждение обо всех, если кто-то не скажет иное. Здесь честное предложение таково: средние единицы составляют 5,29. среди четырнадцати заказов, количество которых нам известно.

Также стоит посмотреть аналог производных столбцов. Для дохода нужны и единицы, и цена, поэтому он существует в тринадцати из шестнадцати строк, и его общее количество составляет 8150 против истинного 9890. Этот разрыв в 1740 не является арифметической ошибкой; это три строки, которые невозможно вычислить.

4. Заполнение нулями

fillna(0) Это рефлекс, и это конкретное утверждение: недостающего количества не было.

leave as NaN   count 14   sum 74.0   mean 5.2857   std 2.5246
fillna(0)      count 16   sum 74.0   mean 4.6250   std 2.9637

Сумма не переместилась, поскольку добавление нуля ничего не добавляет. Среднее значение упало с 5,29 до 4,63, поскольку знаменатель увеличился с четырнадцати до шестнадцати. И распространение пошло вверхс 2,52 до 2,96, поскольку два значения были помещены в нижнюю часть диапазона.

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

Когда значение неизвестно, а не отсутствует, ноль — это ложное измерение, которое будет усреднено, отображено на графике и суммировано точно так же, как реальное. Это та же торговля, что и скрыть ошибку за нулем в электронной таблице, и это идет не так по той же причине.

5. Заполнение средним значением

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

leave as NaN     count 14   mean 5.2857   std 2.5246
fillna(mean)     count 16   mean 5.2857   std 2.3503

Среднее значение идентично четырем десятичным знакам, и именно поэтому метод кажется безопасным. Стандартное отклонение упало с 2,52 до 2,35, и это пришлось: два значения были помещены точно в среднее значение, поэтому они не вносят никакого вклада в разброс, но продолжают отсчитываться в сторону делителя.

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

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

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

6. Прямое заполнение и создаваемое им значение

ffill переносит предыдущее значение вперед. В реальном временном ряду чего-то, что сохраняется, — цены, статуса, показаний счетчика — это часто совершенно верно: значение не изменилось, оно просто не было перезаписано.

Обо всем остальном он изобретает данные. Отсортировано по дате, без одного региона:

order_date   region   region_ffill
2026-05-04   East     East
2026-05-11   NaN      East      <- the real answer was North
2026-05-18   South    South
2026-05-25   West     West

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

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

bfill это то же самое в обратном направлении и содержит более строгое предупреждение: оно заполняет значение из будущего, которое во всем, что вы моделируете или прогнозируете, является утечкой.

7. Отсутствующее значение, которое не сохраняется как отсутствующее.

Перед пояснением: исходная система пишет -1 где количество неизвестно. Чего-чего isna() отчеты.

Ноль. Это число, поэтому с точки зрения pandas ничего не пропущено.

with -1 as the marker   mean 4.5000   count 16   min -1
stored as missing       mean 5.2857   count 14

Среднее значение неверно почти на целую единицу, счетчик говорит, что каждая строка имеет значение, и единственная видимая подсказка — это то, что минимум отрицательный. Измените маркер на 0 или 999 и даже эта подсказка исчезает.

Это худший случай на странице именно потому, что ни один из инструментов на странице не подходит: isna ничего не находит, dropna ничего не роняет и fillna нечем заполнить. Единственная защита — взглянуть хотя бы раз на сами ценности.

df["units"].min(), df["units"].max()      absurd extremes
df["units"].value_counts().head()         one value appearing far too often
df.describe()                             a min or max that cannot be real

Привычка, которая его цепляет: в любом новом числовом столбце смотреть на минимум и максимум и спрашивать, возможны ли оба. Количество -1, возраст 999, дата 01.01.1900 и цена 0,01 — все это одно и то же, и все их лучше всего преобразовать в реальное недостающее значение во время загрузки с помощью na_values, что аргумент read_csv именно для этого.

8. группировка тихонько роняет недостающий ключ

Одна строка не имеет региона. Группировка по регионам:

East   4
North  4
South  4
West   3
        rows accounted for: 15 of 16

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

df.groupby("region", dropna=False)

East   4
North  4
South  4
West   3
NaN    1
        rows accounted for: 16 of 16

Один аргумент, и появляется недостающая группа. Запустите его таким образом один раз для каждого ключа, по которому вы группируете, прочитайте NaN Строка, а затем решить, что с этим делать, вместо того, чтобы позволять решать по умолчанию. Это та же привычка и тот же аргумент, что и в групповое руководство, и проверка является арифметической: размеры групп должны прибавляться к количеству строк, с которого вы начали.

Полное до и после

Те же шестнадцать заказов, тот же вопрос: каков средний объем заказа?

До

df["units"] = df["units"].fillna(0)
df.groupby("region")["units"].mean()

mean units 4.63, spread 2.96, sixteen values, no missing data anywhere

Полноценный столбец, среднее значение слишком низкое на 0,66, слишком большой разброс, один регион молчаливо отсутствует в группировке, и на странице нет ничего, что указывало бы на то, что что-то когда-либо отсутствовало.

после

# 1. count first
df.isna().sum()                      units 2, unit_price 1, region 1
len(df), len(df.dropna())            16, 12

# 2. leave the holes, and say what the summary is over
df["units"].count()                  14 of 16
df["units"].mean()                   5.2857

# 3. group without losing the missing key
df.groupby("region", dropna=False)["units"].count().sum()    16 of 16

# 4. the sentence that goes with the number
"Average order quantity is 5.29 units, over the 14 of 16 orders
 where the quantity was recorded. Two orders have no quantity."

Утверждение, и именно поэтому выбор заслуживает абзаца, а не рефлекса: одни и те же две недостающие величины дают в среднем 5,29, 4,63 или 5,29 с меньшим разбросом в зависимости от того, к какому однострочному исправлению вы стремитесь, и только одно из трех говорит читателю, что чего-то вообще не хватает.

Пограничные случаи, которые стоит знать

Шесть, которые появятся.

НЭН не равен самому себе. np.nan == np.nan является False, так df[df["region"] == np.nan] ничего не возвращает, пока df["region"].isna().sum() возвращает один. Всегда используйте isna и notna, никогда не тест на равенство.

Целочисленный столбец становится числом с плавающей запятой. Целые числа плюс пропущенное значение не могут быть целыми числами, поэтому pandas расширяет столбец, и ваши количества становятся 4,0 и 10,0. Это сигнал, а не ошибка, и целочисленный тип, допускающий значение NULL. "Int64", с большой буквы, сохраняет их целыми, если это имеет значение.

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

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

Отсутствующие значения в ключе слияния. Они совпадают друг с другом, что приводит к умножению строк. Удалите или заполните их до присоединения, а не после.

Почему его нет, имеет значение. Случайное отсутствие количества — это другая проблема, чем отсутствие количества из-за отмены заказа. Второй — это информация, и удаление этих строк удаляет скорее закономерность, чем неудобство.

Почему это работает

Причина, по которой не существует правильного ответа по умолчанию, заключается в том, что правильное лечение зависит от Почему значение отсутствует, и данные не могут вам об этом сказать. Стандартная структура отличает значения, отсутствующие совершенно случайно, от значений, отсутствие которых связано с чем-то другим, и суть этого различия практична: анализ только полных случаев безопасен в первой ситуации и предвзят во второй, и вы не можете определить, в каком из них вы находитесь, только по файлу (Рубин, 1976, Биометрия, 63(3), 581–592). Количество, отсутствующее из-за того, что поле было пропущено, — это одно; количество отсутствует, поскольку эти заказы были отменены, — это другое, и dropna() относится к ним одинаково.

Конкретный вред, указанный в пятом разделе, хорошо документирован и не является делом вкуса. Замена отсутствующих значений средним из наблюдаемых подвергается критике именно потому, что она сохраняет среднее значение, одновременно искусственно уменьшая изменчивость, поэтому стандартные отклонения, стандартные ошибки и любой интервал, построенный на их основе, оказываются слишком маленькими, и анализ выглядит более точным, чем подтверждают данные (Шафер & Грэм, 2002, Психологические методы, 7(2), 147–177). Падение с 2,52 до 2,35 для двух значений из шестнадцати — это маленькая версия этого; на столбце, которому не хватает пятой части, это не мало.

Одно замечание в шпаргалке ниже. Он создан для того, чтобы его просматривали и вспоминали, а не перечитывали, потому что в обзорах методов обучения практическое тестирование и интервалы ставятся в верхней части того, что работает, а перечитывание и выделение — в нижней части, несмотря на то, что перечитывание кажется гораздо более продуктивным (Данлоски, Роусон, Марш, Натан & Уиллингем, 2013, Психологическая наука в общественных интересах, 14(1), 4–58).

Использование этого в вашем собственном проекте

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

  1. Прежде чем принять решение, посчитайте. isna().sum(), и isna().mean() для пропорции, которую вы укажете.
  2. Проверьте часовых. Посмотрите на минимальное и максимальное значения каждого числового столбца и спросите, возможны ли оба значения.
  3. Спросите, почему отсутствует каждый столбец, однажды, того, кто владеет данными. Этот ответ решает все дальнейшее.
  4. Предпочитаю покинуть дыру и сообщать о подсчете, по которому он был вычислен. Это единственный вариант, который по умолчанию честен.
  5. Укажите подмножество, которое вы действительно используете., никогда с голым dropna()и напечатайте количество строк с обеих сторон.
  6. Группа с dropna=False хотя бы один раз для каждого ключа, и проверьте, что размеры групп возвращаются к числу строк.

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

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

Все на одном экране

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

вещьЧто он делает
Найдите ихdf.isna().sum(), и .mean() для пропорции.
За строкуdf.isna().sum(axis=1). Сосредоточенно или рассеянно?
Производные столбцыОтсутствует везде, где есть какие-либо данные. Дыры распространяются через арифметику.
dropna()Удаляет строку, если любой столбец отсутствует. Ушло 16 рядов по 12.
dropna(subset=[...])Только по тем столбцам, которые вы называете. Обычно то, что вы имели в виду.
dropna(axis=1)Удаляет столбцы. Здесь осталось 4 из 8.
РезюмеПо умолчанию пропускать пропущенные значения. Ни ошибки, ни предупреждения.
count()Сколько значений используется в сводке. Сравните с количеством строк.
fillna(0)Утверждает, что ценность отсутствует. Среднее значение упало с 5,29 до 4,63.
Когда ноль правильныйНикаких продаж, никаких возвратов, никаких кликов. Настоящее измерение ничего.
fillna(mean)Среднее значение не изменилось, спред сократился с 2,52 до 2,35.
Почему это важноЗаполненные точки находятся в среднем и не добавляют изменений.
ffillСохраняет предыдущее значение. Правильно для государств, неправильно для событий.
ffill(limit=1)Останавливает перенос одного значения через длинный промежуток.
bfillНаполняется из будущего. Утечка во всем, что вы моделируете.
Стражи-1, 999, 1900-01-01. isna ничего не находит. Проверьте мин и макс.
NaN == NaNЛОЖЬ. Использовать isna, никогда не тест на равенство.
groupbyТихо роняет недостающий ключ. Использовать dropna=False.
Единственная привычка, которую следует сохранить. Сообщите о количестве, по которому была вычислена сводка, рядом со сводкой. «В среднем 5,29 по 14 из 16 заказов» — это предложение, которое никто не сможет неправильно прочитать; «Среднее 5,29» — это то же число с удаленной важной частью, и каждый вариант на этой странице, за исключением того, что оставлено только отверстие, делает это удаление постоянным. Если отсутствующие данные ведут себя не так, как описано на этой странице, существует общая шлейф диагностики на предмет застревания.

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

Ссылки

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

Python для аналитиков составляет 203 страницы, недостающие данные обрабатываются намеренно, поэтому пробел никогда не превращается в значение, которое вы не имели в виду.

Python для аналитиков, 19 $ →
Специально тренируйтесь на данных с дырками.

тот Курс Python дает вам повторения: столбцы с разбросанными и концентрированными пропусками, контрольные значения, которые нужно найти, и одно и то же резюме, рассчитанное четырьмя способами, а также карточки с информацией о том, что утверждает каждое заполнение. Теперь вы владеете методом; комплект - это практика. Ничего устанавливать, учетная запись не требуется.

Откройте комплект Python →