NumPy的核心优势之一是其强大的矢量化运算能力。你可以对整个数组执行数学运算,而无需编写显式循环,代码简洁且运行效率极高。本节将介绍NumPy中最常用的数学运算。
数组与标量(单个数值)进行运算时,标量会与数组的每个元素逐一操作(广播机制)。这是最直观的矢量化操作。
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
print("原数组:", arr)
# 加法
print("arr + 10 =", arr + 10)
# 减法
print("arr - 2 =", arr - 2)
# 乘法
print("arr * 3 =", arr * 3)
# 除法
print("arr / 2 =", arr / 2)
# 幂运算
print("arr ** 2 =", arr ** 2)
# 比较运算(返回布尔数组)
print("arr > 3 =", arr > 3)
输出:
原数组: [1 2 3 4 5]
arr + 10 = [11 12 13 14 15]
arr - 2 = [-1 0 1 2 3]
arr * 3 = [ 3 6 9 12 15]
arr / 2 = [0.5 1. 1.5 2. 2.5]
arr ** 2 = [ 1 4 9 16 25]
arr > 3 = [False False False True True]
两个形状相同的数组进行运算时,对应位置的元素进行运算。结果是一个新数组,形状与原数组相同。
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
print("a + b =", a + b)
print("a * b =", a * b)
print("a / b =", a / b)
print("a ** b =", a ** b) # 注意:幂运算可能产生大数
# 二维数组示例
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print("A + B:\n", A + B)
print("A * B(元素乘):\n", A * B) # 不是矩阵乘法
输出:
a + b = [11 22 33 44]
a * b = [ 10 40 90 160]
a / b = [0.1 0.1 0.1 0.1]
a ** b = [1 1048576 3486784401 ...] # 部分结果省略
A + B:
[[ 6 8]
[10 12]]
A * B(元素乘):
[[ 5 12]
[21 32]]
NumPy提供了许多通用函数,它们对数组中的每个元素执行快速操作。可以分为一元ufunc(作用于一个数组)和二元ufunc(作用于两个数组)。
arr = np.array([1, 4, 9, 16, 25])
print("np.sqrt:", np.sqrt(arr)) # 平方根
print("np.exp:", np.exp(arr)) # 指数 e^x
print("np.log:", np.log(arr)) # 自然对数
print("np.sin:", np.sin(arr)) # 正弦
print("np.cos:", np.cos(arr)) # 余弦
print("np.abs:", np.abs([-1, -2, 3])) # 绝对值
print("np.ceil:", np.ceil([1.2, 2.7]))# 向上取整
print("np.floor:", np.floor([1.2, 2.7])) # 向下取整
输出:
np.sqrt: [1. 2. 3. 4. 5.]
np.exp: [2.71828183e+00 5.45981500e+01 8.10308393e+03 8.88611052e+06 7.20048993e+10]
np.log: [0. 1.38629436 2.19722458 2.77258872 3.21887582]
np.sin: [ 0.84147098 -0.7568025 0.41211849 -0.28790332 -0.13235175]
np.cos: [ 0.54030231 -0.65364362 -0.91113026 -0.95765948 -0.99120281]
np.abs: [1 2 3]
np.ceil: [2. 3.]
np.floor: [1. 2.]
a = np.array([10, 20, 30])
b = np.array([3, 4, 5])
print("np.add:", np.add(a, b)) # 加法
print("np.subtract:", np.subtract(a, b)) # 减法
print("np.multiply:", np.multiply(a, b)) # 乘法
print("np.divide:", np.divide(a, b)) # 除法
print("np.power:", np.power(a, b)) # 幂
print("np.mod:", np.mod(a, b)) # 取余
print("np.maximum:", np.maximum(a, b)) # 逐元素最大值
print("np.minimum:", np.minimum(a, b)) # 逐元素最小值
输出:
np.add: [13 24 35]
np.subtract: [7 16 25]
np.multiply: [ 30 80 150]
np.divide: [3.33333333 5. 6. ]
np.power: [ 100 160000 24300000]
np.mod: [1 0 0]
np.maximum: [10 20 30]
np.minimum: [3 4 5]
注意:np.maximum 与 np.max 不同,前者是逐元素比较,后者是聚合求最大值。
聚合函数对整个数组或沿着某个轴进行统计计算,返回一个或一组数值。
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("数组:\n", arr)
# 全局统计
print("总和:", np.sum(arr))
print("平均值:", np.mean(arr))
print("最大值:", np.max(arr))
print("最小值:", np.min(arr))
print("标准差:", np.std(arr))
print("方差:", np.var(arr))
# 沿轴统计 (axis=0 表示列,axis=1 表示行)
print("按列求和 (axis=0):", np.sum(arr, axis=0))
print("按行求和 (axis=1):", np.sum(arr, axis=1))
print("按列平均值:", np.mean(arr, axis=0))
print("按行最大值:", np.max(arr, axis=1))
输出:
数组:
[[1 2 3]
[4 5 6]
[7 8 9]]
总和: 45
平均值: 5.0
最大值: 9
最小值: 1
标准差: 2.581988897471611
方差: 6.666666666666667
按列求和 (axis=0): [12 15 18]
按行求和 (axis=1): [ 6 15 24]
按列平均值: [4. 5. 6.]
按行最大值: [3 6 9]
使用 np.dot()、@ 运算符或 np.matmul() 进行矩阵乘法。
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print("矩阵点积 (np.dot):\n", np.dot(A, B))
print("矩阵点积 (A @ B):\n", A @ B) # Python 3.5+
print("元素乘法 (A * B):\n", A * B) # 区别:元素乘
输出:
矩阵点积 (np.dot):
[[19 22]
[43 50]]
矩阵点积 (A @ B):
[[19 22]
[43 50]]
元素乘法 (A * B):
[[ 5 12]
[21 32]]
当两个数组形状不同时,NumPy会尝试通过广播规则使它们兼容。例如,二维数组加一维数组:
a = np.array([[1, 2, 3], [4, 5, 6]]) # shape (2,3)
b = np.array([10, 20, 30]) # shape (3,)
print("a + b:\n", a + b) # b 被广播到每一行
输出:
a + b:
[[11 22 33]
[14 25 36]]
广播机制将在后续章节详细讲解。
某些运算符支持就地操作(如 +=、*=),它们会直接修改原数组,不会创建新数组,从而节省内存。
arr = np.array([1, 2, 3])
print("原数组:", arr)
arr += 10
print("arr += 10 后:", arr)
arr *= 2
print("arr *= 2 后:", arr)
输出:
原数组: [1 2 3]
arr += 10 后: [11 12 13]
arr *= 2 后: [22 24 26]
np.add、np.multiply 等,它们支持 out 参数指定输出数组,可以实现就地操作。
本节介绍了NumPy的基本数学运算,包括数组与标量的运算、数组之间的元素级运算、丰富的通用函数(ufunc)以及聚合统计函数。这些矢量化操作使NumPy代码简洁高效。下一章我们将深入探讨广播机制,理解不同形状数组间运算的规则。