Перед concat: ловим несовпадение схем выгрузок
Октябрьская выгрузка использует amount, ноябрьская — total. concat успешно объединяет их, создавая две колонки с пропусками. Ошибка проявляется позже: отчёт считает только половину денежных строк.
Успешное объединение не проверяет договор
concat по строкам по умолчанию объединяет набор колонок. Это удобно для разнородных таблиц, но опасно для одинаковых регулярных поставок. join="inner" тоже не является исправлением: он способен молча удалить непохожие колонки.
Сначала опишите обязательную схему. Если старое и новое имя действительно означают один показатель, выполните явное переименование в адаптере конкретного источника. Если смысл поменялся, простого rename недостаточно: нужна отдельная версия расчёта.
Остановить несовместимую поставку
Пример содержит правильный файл и файл с переименованным полем. Функция сравнивает точный набор колонок и приводит типы по договору. Несовместимый файл отвергается до concat. Для демонстрации затем исправляем известное переименование и повторяем приёмку.
Добавляем source, чтобы каждая строка сохраняла происхождение. После объединения проверяем глобальный ключ: два по отдельности корректных файла могут содержать один заказ дважды.
import pandas as pd
schema = {"order_id": "int64", "amount": "int64"}
def accept(frame, source):
if set(frame.columns) != set(schema):
raise ValueError("schema mismatch: " + source)
result = frame.astype(schema).copy()
result["source"] = source
return result
old = pd.DataFrame({"order_id": [1], "amount": [100]})
new = pd.DataFrame({"order_id": [2], "total": [200]})
try:
accept(new, "november")
except ValueError:
rejected = True
else:
rejected = False
assert rejected
combined = pd.concat([accept(old, "october"),
accept(new.rename(columns={"total": "amount"}), "november")], ignore_index=True)
assert combined["order_id"].is_unique
assert combined["amount"].sum() == 300
print(combined.to_string(index=False))Несовместимость обнаружена до появления двух денежных колонок. Переименование является явным решением, а источник сохранён в результате. В реальном процессе адаптер не должен автоматически считать любое поле total эквивалентом amount.
Отделить схему от качества значений
Правильные имена и dtypes ещё допускают отрицательные суммы, неверный период и пропущенные дни. После приёмки схемы выполните предметные проверки. Приведение к целому типу тоже требует осторожности: дробное число может потерять часть при преобразовании, поэтому проверяйте допустимость дробей до astype, когда они приходят из непроверенного источника.
Набор разрешённых дополнительных столбцов зависит от договора. Для строгой таблицы любое новое поле требует разбора. Для расширяемой схемы можно разрешить лишние поля, но фиксировать их появление и выбирать нужные колонки явно.
Проверьте повторную доставку файла и перекрывающиеся периоды. ignore_index сбрасывает только технический индекс, а не удаляет повторные сущности. Ключ заказа или операции остаётся отдельным контролем. Тогда смена формата и повтор доставки не превратятся в незаметное изменение выручки.
Закрепить на практике
В бесплатном уроке merge и concat вы отработаете объединение таблиц. Пример статьи добавляет приёмку схемы и происхождение строк, чтобы знакомая операция оставалась проверяемой на новых поставках. Откройте бесплатный урок и задачи. Полная последовательность тем — в бесплатном курсе.
Продолжить на практике
- NumPy и pandas: практический тренажёр ↗
Бесплатный тренажёр NumPy и pandas для тех, кто знает основы Python. Научитесь очищать таблицы, объединять данные и собирать отчёты: 31 урок и 124 задачи с кодом и автоматической проверкой.
