Сохранение, структуры и мост к pandas: что дальше
Финальный урок: как сохранять и загружать массивы, что такое структурированные массивы, как NumPy связан с pandas, и итоговый чек-лист эффективного кода.
Формат .npy — бинарный формат NumPy для сохранения одного массива со всеми метаданными (форма, dtype); читается мгновенно и без потерь, в отличие от текстовых форматов.
Сохранение и загрузка: save, load, savez
Сохранять массивы в текст (CSV) — расточительно: теряется точность, dtype, форма, файл занимает много места и медленно парсится. NumPy предлагает бинарные форматы. np.save пишет один массив в файл .npy, np.load читает его обратно — быстро и без потерь. Для нескольких массивов есть np.savez (несжатый) и np.savez_compressed (сжатый), создающие архив .npz.
import numpy as np
a = np.arange(12).reshape(3, 4)
np.save('data.npy', a) # один массив
loaded = np.load('data.npy') # читаем обратно
print(np.array_equal(a, loaded)) # True — без потерь
# Несколько массивов в один архив
np.savez('bundle.npz', train=a, labels=np.array([0, 1, 0]))
bundle = np.load('bundle.npz')
print(bundle['train'].shape, bundle['labels'])
Вывод:
True (3, 4) [0 1 0]
Правило: для промежуточных результатов и быстрого обмена между скриптами используйте .npy/.npz. Текстовые np.savetxt/np.loadtxt уместны лишь когда файл должен читаться человеком или другой программой, не знающей NumPy.
Бинарный формат против текстового: что выбрать
Выбор формата хранения важнее, чем кажется. Текстовые форматы (CSV, обычный txt) хороши одним — их читает человек и любая программа. Но за это вы платите дорого: число вроде 0.1 при записи в текст и обратном чтении может потерять точность в последних знаках; dtype и форма не сохраняются (всё парсится как строки и переводится в float); файл занимает в разы больше места; чтение медленное, потому что каждое число нужно разобрать из текста. Бинарные форматы NumPy (.npy, .npz) лишены этих недостатков: они сохраняют точные байты чисел, всю форму и тип, читаются почти мгновенно (это просто загрузка блока в память) и компактны. Правило выбора простое: если файл предназначен для вашего же кода или обмена между Python-скриптами — берите бинарный .npy/.npz. Текстовый формат оставьте для случаев, когда данные должен прочитать человек или внешний инструмент, не знающий NumPy. Отдельно стоит savez_compressed для архивов: он сжимает данные, экономя место на диске ценой времени на распаковку, — полезно для редко читаемых, но объёмных наборов.
Структурированные массивы: разные типы в одной строке
Обычный ndarray однороден — один dtype на всё. Но иногда нужны «записи» с полями разных типов, как строки таблицы: имя (строка), возраст (целое), рост (вещественное). Для этого есть структурированные массивы — с составным dtype, описывающим именованные поля. К полям обращаются по имени.
import numpy as np
dt = np.dtype([('name', 'U10'), ('age', 'i4'), ('height', 'f4')])
people = np.array([('Аня', 25, 1.65),
('Боря', 30, 1.80)], dtype=dt)
print(people['name']) # доступ к полю по имени
print(people['age'].mean()) # агрегации по полю
print(people[0]) # одна запись целиком
Вывод:
['Аня' 'Боря']
27.5
('Аня', 25, 1.65)
Структурированные массивы полезны для чтения бинарных форматов с фиксированной схемой. Но для повседневной работы с табличными данными смешанных типов есть инструмент удобнее — pandas.
Когда нужны структурированные массивы, а когда pandas
Структурированные массивы — мощный, но нишевый инструмент. Их главная область — чтение и запись бинарных форматов с фиксированной схемой записи: файлы научных приборов, сетевые пакеты, бинарные форматы данных, где каждая «запись» имеет жёстко заданную структуру полей разных типов. Здесь структурированный dtype точно описывает раскладку байтов, и NumPy читает такие данные эффективно и без копирования. Но для анализа разнородных табличных данных — фильтрации, группировки, соединения таблиц, работы с пропусками и датами — структурированные массивы неудобны: у них нет высокоуровневых операций, которые есть в pandas. Поэтому правило простое: структурированные массивы — для низкоуровневого ввода-вывода бинарных форматов; pandas — для анализа таблиц. Не пытайтесь строить аналитику на структурированных массивах, повторяя то, что pandas делает из коробки. И наоборот, не тяните pandas туда, где нужно лишь быстро прочитать бинарный буфер фиксированной структуры. Каждый инструмент хорош в своей нише, и понимание границы между ними экономит силы.
Мост к pandas: где заканчивается NumPy
NumPy — это про однородные числовые массивы и скорость. Как только данные становятся табличными и разнородными (колонки разных типов, имена столбцов, метки строк, пропуски, группировки, работа с датами и категориями) — это территория pandas. И связь между ними прямая: pandas построен на NumPy. Каждая колонка DataFrame — это, по сути, NumPy-массив, а у DataFrame и Series есть атрибут .values (или .to_numpy()), отдающий данные как ndarray.
Все навыки этого курса переносятся в pandas: векторизация, broadcasting, маски, агрегации с axis — там работают так же, потому что под капотом тот же NumPy. Поэтому изучение NumPy — это фундамент, на котором стоит весь остальной анализ данных. Типичный поток: загрузить и подготовить таблицу в pandas, при необходимости вынуть числовой массив через .to_numpy() и скормить его в scikit-learn или собственные вычисления на NumPy.
| Берите NumPy, когда | Берите pandas, когда |
| однородные числовые массивы | таблицы со столбцами разных типов |
| матричные/тензорные вычисления | нужны метки строк/столбцов |
| максимальная скорость и контроль | группировки, джойны, временные ряды |
| основа для ML-библиотек | очистка и разведка данных |
NumPy как фундамент: куда идти дальше
Завершая курс, полезно увидеть NumPy в контексте всей экосистемы. Вы освоили не изолированную библиотеку, а общий язык числовых вычислений Python, на котором построено почти всё остальное. pandas добавляет поверх NumPy метки, разнородные колонки, группировки и работу с пропусками — но под капотом это те же массивы, и ваши навыки векторизации и масок там работают без изменений. matplotlib рисует графики из NumPy-массивов. scikit-learn принимает массивы признаков и возвращает массивы предсказаний; все его алгоритмы говорят на языке NumPy. SciPy расширяет NumPy продвинутой математикой — оптимизацией, интегрированием, обработкой сигналов, разреженными матрицами. Фреймворки глубокого обучения копируют интерфейс NumPy для своих тензоров, добавляя автоматическое дифференцирование и работу на GPU. Иными словами, NumPy — это корень дерева, из которого растёт весь научный и аналитический Python. Каждая концепция, которую вы здесь усвоили — ndarray и его память, views и copies, broadcasting, векторизация, оси и агрегации — переносится дальше почти буквально. Поэтому время, вложенное в глубокое понимание NumPy, окупается во всём, что вы будете делать с данными на Python. Это лучшая инвестиция в фундамент.
Итоговый чек-лист производительности
Соберём принципы всего курса в один список. Если код на NumPy медленный или прожорливый по памяти, пройдитесь по нему:
checklist = [
"Нет ли явных Python-циклов по элементам массива?",
"Заменены ли if/else на np.where и маски?",
"Используется ли подходящий dtype (не шире нужного)?",
"Нет ли лишних копий: astype, flatten, fancy-индексация в цикле?",
"Предвыделены ли массивы вместо роста через append?",
"Применяются ли out= и += в горячих местах?",
"Идёт ли обход вдоль непрерывной (последней для C) оси?",
"Правильно ли указан axis в агрегациях?",
]
for i, item in enumerate(checklist, 1):
print("%d. %s" % (i, item))
Вывод:
1. Нет ли явных Python-циклов по элементам массива? 2. Заменены ли if/else на np.where и маски? 3. Используется ли подходящий dtype (не шире нужного)? 4. Нет ли лишних копий: astype, flatten, fancy-индексация в цикле? 5. Предвыделены ли массивы вместо роста через append? 6. Применяются ли out= и += в горячих местах? 7. Идёт ли обход вдоль непрерывной (последней для C) оси? 8. Правильно ли указан axis в агрегациях?
Типичные ошибки новичков: сводка
- Циклы вместо векторизации — теряется вся скорость NumPy.
- Правка view в уверенности, что это копия (и наоборот) — порча данных.
- Переполнение узких целых и сравнение float через
==. - Ошибки broadcasting из-за невнимания к формам (выравнивание справа).
- Путаница
*и@, неверныйaxisв агрегациях. - Использование устаревшего
np.random.seedвместоdefault_rng.
Связь навыков: всё переносится в pandas
Стоит ещё раз подчеркнуть главное практическое следствие того, что pandas построен на NumPy: почти всё, что вы здесь изучили, работает в pandas без переучивания. Векторные арифметические операции над колонками — это NumPy под капотом. Булевы маски для фильтрации строк DataFrame — те же маски, что мы строили над массивами. Агрегации с осями, сравнения, where, обработка пропусков через специальные функции — всё это знакомые концепции в новой обёртке. Когда вы пишете в pandas df[df['age'] > 18], вы применяете ровно тот приём булевой индексации, что разбирали в этом курсе. Поэтому переход от NumPy к pandas — это не изучение новой парадигмы, а добавление удобств (метки, разнородные колонки, группировки) поверх уже освоенной модели. И в обратную сторону: когда в pandas вам нужна максимальная скорость или операция, которой нет в высокоуровневом API, вы достаёте массив через .to_numpy() и работаете напрямую с NumPy. Эта бесшовная связь — причина, по которой освоение NumPy окупается мгновенно: вы получаете не одну библиотеку, а ключ ко всему стеку анализа данных на Python.
Что дальше
Вы освоили ядро NumPy: от устройства ndarray и памяти до broadcasting, линейной алгебры и производительности. Дальнейшие шаги: pandas для табличных данных, matplotlib для визуализации, scikit-learn для машинного обучения, SciPy для научных вычислений — все они стоят на NumPy и говорят на его языке. Понимание массивов, которое вы получили, — это пропуск во весь экосистему научного Python.
Подводные камни
- Хранить числовые массивы в CSV. Медленно, теряется точность и dtype. Берите
.npy/.npz. - Тянуть разнородные таблицы в NumPy. Структурированные массивы неудобны для анализа; это работа pandas.
- Забывать, что pandas — это NumPy. Навыки переносятся;
.to_numpy()даёт прямой мост.
Лучшие практики
- Сохраняйте промежуточные массивы в бинарном
.npy/.npz, а не в текст. - Для табличных разнородных данных переходите на pandas, оставляя NumPy для числового ядра.
- Регулярно прогоняйте код по чек-листу производительности.
- Рассматривайте NumPy как фундамент: освоив его, вы быстро войдёте в pandas, scikit-learn и SciPy.
Итог
- Сохраняйте массивы в бинарном формате (
save/load,savez) — быстро и без потерь. - Структурированные массивы дают поля разных типов, но для таблиц удобнее pandas.
- pandas построен на NumPy; навыки векторизации и масок переносятся напрямую.
- Чек-лист производительности и знание типичных ошибок — ваш итоговый инструмент.