Фильтр с неизвестным результатом: nullable boolean в pandas

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

Неизвестное условие требует решения

Nullable boolean хранит True, False и pd.NA. При сравнении nullable числа с порогом пропуск сохраняется как неизвестное решение. В булевой индексации pandas такие элементы не включаются в выборку. Это удобно для отбора подтверждённых случаев, но ничего не говорит о размере неизвестной части.

Для нашей задачи True означает подтверждённый крупный чек, False — подтверждённый некрупный, NA — сумма не получена. Сначала считаем эти три состояния. Лишь затем решаем, какой знаменатель соответствует вопросу бизнеса.

Сохранить неизвестные строки отдельно

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

fillna(False) здесь используется только для выбора подтверждённых строк. Исходная маска сохраняется, поэтому неизвестность не исчезает из диагностики.

import pandas as pd
x = pd.DataFrame({"order_id": [1, 2, 3], "amount": pd.array([1500, 500, None], dtype="Int64")})
mask = x["amount"].gt(1000)
confirmed = x.loc[mask.fillna(False)]
unknown = x.loc[mask.isna()]
known_share = mask.dropna().mean()
confirmed_share = mask.fillna(False).mean()
print({"confirmed_ids": confirmed["order_id"].tolist(),
       "unknown_ids": unknown["order_id"].tolist(),
       "among_known": float(known_share), "among_all": float(confirmed_share)})
assert confirmed["order_id"].tolist() == [1]
assert unknown["order_id"].tolist() == [3]
assert known_share == 0.5 and abs(confirmed_share - 1/3) < 1e-12

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

Проверить составные условия

В трёхзначной логике сочетание условий тоже может оставлять NA. Например, для условия «крупный чек и оплачено» подтверждённое False по оплате уже исключает заказ независимо от неизвестной суммы. Для True по оплате неизвестная сумма сохраняет неопределённость. Проверьте эти комбинации на маленькой таблице до сложного фильтра.

Не сравнивайте пропуски обычным равенством. Используйте isna и notna. Смешение object, float и nullable типов может менять представление неизвестности, поэтому проверьте dtypes после загрузки и явно выберите тип поля.

В отчёте полезно хранить число известных решений и число неизвестных. Если покрытие падает между месяцами, прежняя доля среди известных может перестать описывать сопоставимый состав заказов. Очередь unknown даёт конкретные id для восстановления данных, а не только тревожный процент.

Закрепить на практике

В бесплатном уроке о пропусках и nullable dtype вы получите основу для различения отсутствующего значения и нуля. После него проверьте, как неизвестное значение проходит через условие и влияет на знаменатель. Откройте бесплатный урок и задачи. Полная последовательность тем — в бесплатном курсе.

Продолжить на практике

  • NumPy и pandas: практический тренажёр ↗

    Бесплатный тренажёр NumPy и pandas для тех, кто знает основы Python. Научитесь очищать таблицы, объединять данные и собирать отчёты: 31 урок и 124 задачи с кодом и автоматической проверкой.