Учебник NumPy для начинающих
NumPy — фундамент всего научного и аналитического Python: на нём стоят pandas, scikit-learn, SciPy, matplotlib и почти весь современный data science и машинное обучение. В основе библиотеки лежит один объект — ndarray, N-мерный массив фиксированного типа, который хранит данные в непрерывном блоке памяти и позволяет выполнять операции над миллионами чисел в десятки и сотни раз быстрее обычных списков Python.
Этот курс — не справочник «какую функцию вызвать», а глубокий разбор того, как и почему NumPy работает именно так. Вы поймёте, что такое dtype, shape и strides, чем view отличается от copy и как это ловит коварные баги, как на самом деле устроен broadcasting, почему векторизация быстрее цикла и где она вас подведёт. Мы разберём индексацию, изменение формы, линейную алгебру, новый генератор случайных чисел и приёмы оптимизации.
Код с import numpy в браузерной песочнице не запускается, поэтому такие примеры даны для чтения с разбором вывода. Но рядом вы найдёте запускаемые примеры на чистом Python, которые показывают, что именно NumPy делает под капотом — цикл против векторизации, ручной broadcasting, скалярное произведение «руками». Это лучший способ прочувствовать, за что мы платим библиотеке и что получаем взамен.
Курс «NumPy» состоит из 6 разделов и 23 уроков: Введение и ndarray, Индексация, срезы и views vs copies, Broadcasting и поэлементные операции, Форма, оси и комбинирование, Линейная алгебра и случайность и Производительность и практика. Уроки идут по порядку — от основ к более сложным темам, в каждом есть объяснение с примерами, а в конце — вопросы для самопроверки. К урокам привязаны задачи с автоматической проверкой: прочитали тему — сразу закрепили её кодом.
Программа курса
1 Введение и ndarray
- Зачем нужен NumPy: векторизация против циклов
Почему NumPy в десятки раз быстрее списков Python: векторизация, непрерывная память, типизация. Разбираем цикл против векторного кода на живом примере.
- ndarray изнутри: shape, dtype, strides и порядок памяти
Как устроен ndarray: один блок памяти плюс метаданные shape, dtype, strides. Разбираем C- и Fortran-порядок и почему strides объясняют скорость операций.
- Создание массивов: array, zeros, arange, linspace и другие
Все способы создать ndarray: из списков, заполненные нулями и единицами, диапазоны arange и linspace, eye, full, fromfunction. Когда какой выбирать.
- Типы данных (dtype): точность, переполнение и приведение
dtype в NumPy: целые и вещественные, bool и complex, разрядность и itemsize. Разбираем переполнение целых, потерю точности float и правила приведения типов.
- Зачем нужен NumPy: векторизация против циклов
2 Индексация, срезы и views vs copies
- Базовая индексация и срезы N-мерных массивов
Индексация и срезы в NumPy: один кортеж индексов для всех осей, start:stop:step по каждой оси, отрицательные индексы, многоточие и присваивание срезу.
- Views и copies: главный источник коварных багов
Когда срез NumPy даёт view, а когда copy. Как view разделяет память с оригиналом, чем это опасно, и как проверять через .base и np.shares_memory.
- Продвинутая индексация: булевы маски и fancy-индексы
Булева индексация и fancy-индексация в NumPy: фильтрация по условию, выбор элементов по списку индексов, комбинации, np.where. Почему это всегда копия.
- np.newaxis, изменение размерности и модификация на месте
Как добавлять оси через np.newaxis и None, превращать вектор в строку или столбец, и почему операции на месте (+=) экономят память, но связаны с views.
- Базовая индексация и срезы N-мерных массивов
3 Broadcasting и поэлементные операции
- Универсальные функции (ufunc): поэлементная математика
ufunc в NumPy: поэлементные функции add, sqrt, exp, sin и сотни других. Параметры out= для записи без копий и where= для условного применения.
- Broadcasting: как NumPy сопоставляет массивы разных форм
Полный разбор broadcasting в NumPy: правило выравнивания осей справа налево, совместимость (равны или одна равна 1), растяжение оси-1, частые ошибки ValueError.
- Агрегации: sum, mean, std с axis и keepdims
Агрегирующие функции NumPy: sum, mean, std, min, argmin. Главное — параметр axis (вдоль какой оси сворачивать) и keepdims для сохранения размерности.
- Сравнения и логика: маски, any, all и логические функции
Поэлементные сравнения дают булевы массивы. Как сводить их через any и all, комбинировать через np.logical_and/or/not и считать совпадения.
- Универсальные функции (ufunc): поэлементная математика
4 Форма, оси и комбинирование
- reshape, ravel и flatten: меняем форму без потери данных
Как менять форму массива через reshape, разворачивать в 1D через ravel и flatten. Когда это view, а когда copy, и зачем нужен -1 в reshape.
- Транспонирование, swapaxes и смысл осей в N измерениях
Транспонирование .T, swapaxes и moveaxis: как менять порядок осей и что это значит для трёхмерных и более данных. Почему транспонирование бесплатно.
- Объединение и разбиение: concatenate, stack, split
Как собирать массивы вместе: concatenate вдоль оси, vstack/hstack/dstack, stack с новой осью. И как разрезать массив через split. Разница между concatenate и stack.
- reshape, ravel и flatten: меняем форму без потери данных
5 Линейная алгебра и случайность
- Умножение массивов: поэлементное против матричного
Разница между * (поэлементное умножение) и @ (матричное произведение) в NumPy. Как работают dot и matmul, скалярное произведение векторов и правило размеров.
- np.linalg: решение систем, обратная матрица, разложения
Подмодуль np.linalg: solve для систем уравнений, inv и det, собственные значения eig, разложение svd, нормы norm. С практическим смыслом каждой операции.
- Случайные числа: современный Generator вместо legacy
Новый API случайных чисел NumPy: np.random.default_rng() вместо устаревшего seed. Распределения, воспроизводимость и почему Generator лучше старого RandomState.
- Сортировка и поиск: sort, argsort, searchsorted, unique
Сортировка массивов через sort и argsort, бинарный поиск через searchsorted, уникальные значения и их подсчёт через unique. С практическими приёмами.
- Умножение массивов: поэлементное против матричного
6 Производительность и практика
- Векторизация на практике: переписываем циклы
Пошаговый разбор, как заменить Python-цикл на векторизованный код NumPy: арифметика, условия через маски, накопление. Типичные шаблоны и мышление.
- Память и копии: когда вычисление становится дорогим
Где NumPy втихую копирует данные и тратит память: временные массивы в выражениях, дорогие копии больших массивов, операции на месте и переиспользование буферов.
- Выбор и фильтрация: where, select, clip и маски
Практические инструменты выбора значений: np.where для условий, np.select для нескольких ветвей, np.clip для ограничения диапазона и фильтрация масками.
- Сохранение, структуры и мост к pandas: что дальше
Сохранение и загрузка массивов (save/load/savez), структурированные массивы кратко, связь NumPy с pandas и итоговый чек-лист производительности.
- Векторизация на практике: переписываем циклы