Привет! Одно из главных преимуществ NumPy — это векторизованные операции. Вместо того чтобы писать циклы для обработки каждого элемента, вы можете применять операции ко всему массиву целиком. Это не только короче, но и значительно быстрее.
В этой статье мы разберём:
- Что такое векторизованные операции
- Арифметические операции с массивами
- Универсальные функции (ufunc)
- Broadcasting
- Сравнение производительности
- Основная часть
- Что такое векторизованные операции
- Арифметические операции с массивами
- Операции между массивами
- Универсальные функции (ufunc)
- Статистические функции
- Broadcasting
- Сравнение производительности
- Булевы операции
- Полный пример
- Задачи для закрепления
- Нюансы и подводные камни
- Broadcasting требует совместимых форм
- Ufunc создают новые массивы
- Векторизованные операции используют больше памяти
- Частые ошибки и как их избежать
- Ошибка 1: Неправильная размерность
- Ошибка 2: Ожидание изменения исходного массива
- Ошибка 3: Сравнение с and/or
- Шпаргалка
- Заключение
- КВИЗ
- Что дальше?
Основная часть
Что такое векторизованные операции
Векторизованные операции — это операции, которые применяются ко всем элементам массива одновременно, без явных циклов.
import numpy as np
# Python-цикл (медленно)
arr = np.array([1, 2, 3, 4, 5])
result = []
for x in arr:
result.append(x * 2)
print(result) # [2, 4, 6, 8, 10]
# Векторизованная операция (быстро)
result = arr * 2
print(result) # [2 4 6 8 10]Совет: Векторизованные операции не требуют циклов и работают значительно быстрее.
Арифметические операции с массивами
arr = np.array([1, 2, 3, 4, 5])
# Сложение
print(arr + 10) # [11 12 13 14 15]
# Вычитание
print(arr - 1) # [0 1 2 3 4]
# Умножение
print(arr * 3) # [3 6 9 12 15]
# Деление
print(arr / 2) # [0.5 1. 1.5 2. 2.5]
# Степень
print(arr ** 2) # [1 4 9 16 25]Совет: Все арифметические операции применяются поэлементно.
Операции между массивами
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# Сложение массивов
print(a + b) # [5 7 9]
# Вычитание
print(a - b) # [-3 -3 -3]
# Умножение (поэлементное)
print(a * b) # [4 10 18]
# Деление
print(a / b) # [0.25 0.4 0.5 ]Важно: Массивы должны быть одинаковой формы (или совместимы через broadcasting).
Универсальные функции (ufunc)
Ufunc — это функции, которые работают с массивами поэлементно.
arr = np.array([0, np.pi/2, np.pi])
# Тригонометрические функции
print(np.sin(arr)) # [0.0000000e+00 1.0000000e+00 1.2246468e-16]
print(np.cos(arr)) # [ 1.000000e+00 6.123234e-17 -1.000000e+00]
# Экспонента и логарифм
print(np.exp(arr)) # [ 1. 4.81047738 23.14069263]
print(np.log(np.exp(1))) # 1.0
# Квадратный корень
print(np.sqrt(arr + 1)) # [1. 1.25331414 1.41421356]
# Округление
arr2 = np.array([1.2, 2.7, 3.5])
print(np.floor(arr2)) # [1. 2. 3.]
print(np.ceil(arr2)) # [2. 3. 4.]
print(np.round(arr2)) # [1. 3. 4.]Совет: Ufunc работают быстрее, чем поэлементные операции в Python.
Статистические функции
arr = np.array([1, 2, 3, 4, 5])
# Сумма
print(np.sum(arr)) # 15
# Среднее
print(np.mean(arr)) # 3.0
# Медиана
print(np.median(arr)) # 3.0
# Минимум и максимум
print(np.min(arr)) # 1
print(np.max(arr)) # 5
# Стандартное отклонение
print(np.std(arr)) # 1.4142135623730951
# Сумма по оси
matrix = np.array([[1, 2], [3, 4]])
print(np.sum(matrix, axis=0)) # [4 6] # по столбцам
print(np.sum(matrix, axis=1)) # [3 7] # по строкамСовет: Используй параметр
axisдля вычислений по строкам или столбцам.
Broadcasting
Broadcasting — это механизм, который позволяет выполнять операции с массивами разных форм.
# Скаляр + массив
arr = np.array([1, 2, 3])
print(arr + 10) # [11 12 13]
# Вектор + матрица (строки)
matrix = np.array([[1, 2, 3], [4, 5, 6]])
vector = np.array([10, 20, 30])
print(matrix + vector)
# [[11 22 33]
# [14 25 36]]
# Вектор-столбец + матрица
matrix = np.array([[1, 2, 3], [4, 5, 6]])
vector = np.array([[10], [20]])
print(matrix + vector)
# [[11 12 13]
# [24 25 26]]Совет: Broadcasting автоматически расширяет меньший массив до размера большего.
Сравнение производительности
import time
# Создаём большой массив
size = 10000000
arr = np.random.rand(size)
# Python-цикл
start = time.time()
result = []
for x in arr:
result.append(x * 2)
print(f"Python цикл: {time.time() - start:.4f} сек")
# Векторизованная операция
start = time.time()
result = arr * 2
print(f"Векторизовано: {time.time() - start:.4f} сек")Результат (примерный):
Python цикл: 0.85 сек
Векторизовано: 0.02 секСовет: Векторизованные операции в десятки раз быстрее!
Булевы операции
arr = np.array([1, 2, 3, 4, 5])
# Сравнение
print(arr > 3) # [False False False True True]
print(arr == 3) # [False False True False False]
# Логические операции
mask = (arr > 2) & (arr < 5)
print(mask) # [False False True True False]
# Сумма True
print(np.sum(arr > 3)) # 2 (количество элементов > 3)
# Все элементы > 0
print(np.all(arr > 0)) # True
# Любой элемент > 4
print(np.any(arr > 4)) # TrueПолный пример
import numpy as np
# Создаём массив
arr = np.arange(1, 13).reshape(3, 4)
print("Исходный массив:\n", arr)
# Векторизованные операции
print("\nУмножение на 2:\n", arr * 2)
print("Квадрат:\n", arr ** 2)
print("Синус:\n", np.sin(arr))
# Статистика
print("\nСумма:", np.sum(arr))
print("Среднее:", np.mean(arr))
print("Максимум:", np.max(arr))
# Операции по осям
print("\nСумма по строкам:", np.sum(arr, axis=1))
print("Сумма по столбцам:", np.sum(arr, axis=0))
# Broadcasting
vector = np.array([10, 20, 30, 40])
print("\nПрибавление вектора:\n", arr + vector)
# Булевы операции
print("\nЭлементы > 5:", arr[arr > 5])
print("Количество элементов > 5:", np.sum(arr > 5))Результат:
Исходный массив:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
Умножение на 2:
[[ 2 4 6 8]
[10 12 14 16]
[18 20 22 24]]
Сумма: 78
Среднее: 6.5
Максимум: 12
Сумма по строкам: [10 26 42]
Сумма по столбцам: [15 18 21 24]
Прибавление вектора:
[[11 22 33 44]
[15 26 37 48]
[19 30 41 52]]
Элементы > 5: [ 6 7 8 9 10 11 12]
Количество элементов > 5: 7Задачи для закрепления
Задача 1. Умножь массив [1, 2, 3, 4, 5] на 3.
Задача 2. Вычисли сумму двух массивов [1, 2, 3] и [4, 5, 6].
Задача 3. Найди среднее значение массива [10, 20, 30, 40, 50].
Задача 4. Найди элементы массива, которые больше 5.
Задача 5. Вычисли сумму элементов по строкам матрицы 2×3.
Ответы:
Задача 1.
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
result = arr * 3
print(result) # [3 6 9 12 15]Задача 2.
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
result = a + b
print(result) # [5 7 9]Задача 3.
arr = np.array([10, 20, 30, 40, 50])
mean = np.mean(arr)
print(mean) # 30.0Задача 4.
arr = np.array([1, 2, 3, 4, 5, 6, 7])
result = arr[arr > 5]
print(result) # [6 7]Задача 5.
matrix = np.array([[1, 2, 3], [4, 5, 6]])
row_sums = np.sum(matrix, axis=1)
print(row_sums) # [6 15]Нюансы и подводные камни
Broadcasting требует совместимых форм
Массивы должны быть совместимы по размерности. Если нет — ошибка.
Ufunc создают новые массивы
Ufunc не изменяют исходный массив, а возвращают новый.
Векторизованные операции используют больше памяти
При больших массивах результат занимает столько же памяти, сколько и исходный.
Частые ошибки и как их избежать
Ошибка 1: Неправильная размерность
Проверяй shape массивов перед операциями.
Ошибка 2: Ожидание изменения исходного массива
Ufunc возвращают новый массив. Используй arr += 1 для изменения на месте.
Ошибка 3: Сравнение с and/or
Используй & и | для булевых массивов.
Шпаргалка
| Операция | Python | NumPy |
|---|---|---|
| Умножение на скаляр | [x*2 for x in arr] | arr * 2 |
| Сложение массивов | [a+b for a,b in zip(x,y)] | x + y |
| Сумма | sum(arr) | np.sum(arr) |
| Среднее | — | np.mean(arr) |
| Синус | [math.sin(x) for x in arr] | np.sin(arr) |
Заключение
Сегодня мы:
- Узнали, что такое векторизованные операции
- Изучили арифметические операции и ufunc
- Разобрали broadcasting
- Сравнили производительность





