2025, Dec 18 06:02

Как избежать ModuleNotFoundError: numpy._core.numeric при сериализации pandas DataFrame через pickle

Разбираем ModuleNotFoundError: numpy._core.numeric при загрузке pandas DataFrame из pickle и даем решение: используйте pickle.dump с протоколом по умолчанию.

Обмениваться объектом pandas DataFrame между машинами через pickle кажется простой задачей, пока неожиданная ошибка импорта не прервёт работу. DataFrame, сохранённый в pickle на одной системе, локально читается без проблем, но на другой машине загрузка может упасть с ModuleNotFoundError, указывающей на numpy._core.numeric, даже если версии pandas и numpy совпадают. Причина кроется не в способе загрузки, а в том, как объект изначально сериализовали.

Воспроизведение сбоя

DataFrame сериализовали на машине A с помощью встроенного метода, а на машине B пытались десериализовать как обычным загрузчиком pickle, так и обёрткой pandas. В обоих случаях ошибка стабильно повторялась.

frame.to_pickle('bundle.pkl')
with open('path/to/bundle.pkl','rb') as fh:
restored_obj = pickle.load(fh)
restored_obj = pd.read_pickle('path/to/bundle.pkl')
ModuleNotFoundError: No module named 'numpy._core.numeric'

В обоих окружениях использовались pandas 2.2.2 и numpy 1.26.4. Синхронизация версий помогала некоторым пользователям, но в этом случае — нет.

Что на самом деле происходит

Поведение зависит от способа сериализации и выбранного протокола pickle. Объекты, сохранённые встроенным путём сериализации pandas или выгруженные с использованием максимально доступного протокола pickle, при чтении обратно давали ту же ошибку импорта — независимо от того, загружались ли они через pickle.load или pd.read_pickle. Напротив, простой pickle.dump с протоколом по умолчанию проблему обходил.

Рабочий подход

Сериализация DataFrame через pickle.dump с протоколом по умолчанию делает артефакт переносимым между машинами. Затем его можно успешно загрузить как стандартным загрузчиком pickle, так и через pandas.read_pickle.

with open('safe_dump.pkl','wb') as fh:
pickle.dump(frame, fh)
with open('path/to/safe_dump.pkl','rb') as fh:
revived = pickle.load(fh)
revived = pd.read_pickle('path/to/safe_dump.pkl')

Однако, если принудительно указать максимальный протокол при сохранении, при загрузке сбой повторяется — ровно как и раньше.

with open('safe_dump.pkl','wb') as fh:
pickle.dump(frame, fh, protocol=pickle.HIGHEST_PROTOCOL)

Почему этот нюанс важен

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

Практические выводы

Если при распаковке pandas DataFrame на другой машине вы видите ModuleNotFoundError: No module named 'numpy._core.numeric', создавайте артефакт через pickle.dump с протоколом по умолчанию. Для этого сценария не следует принудительно использовать pickle.HIGHEST_PROTOCOL. Если объект ранее сериализовали методом DataFrame.to_pickle и возникает сбой, пересохраните его через pickle.dump и проверьте снова. Одного совпадения версий может быть недостаточно — здесь важен именно путь сериализации. Быстрый тест сериализации и обратной загрузки на второй машине перед включением артефакта в рабочий процесс сэкономит время и убережёт от путаницы.