Python NumPy 教程:矩阵与向量运算
NumPy (Numerical Python) 是 Python 中用于科学计算的核心库。它提供了一个高性能的多维数组对象,以及用于处理这些数组的工具。NumPy 的强大之处在于其能够高效地处理大型数据集,尤其是在矩阵和向量运算方面,这对于机器学习、数据分析和科学研究至关重要。
本文将深入探讨如何使用 NumPy 进行矩阵和向量运算,涵盖从基础概念到高级应用。
1. NumPy 数组基础 (ndarrays)
NumPy 的核心是 ndarray 对象,它是一个同构的、多维的数组。
1.1 创建 NumPy 数组
你可以通过多种方式创建 NumPy 数组,例如从 Python 列表或元组创建。
导入 NumPy:
python
import numpy as np
创建一维数组 (向量):
“`python
从列表创建一维数组
vector = np.array([1, 2, 3, 4, 5])
print(“一维数组 (向量):\n”, vector)
print(“维度:”, vector.shape) # (5,) 表示一个包含5个元素的一维数组
print(“数据类型:”, vector.dtype)
“`
创建二维数组 (矩阵):
“`python
从嵌套列表创建二维数组
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(“\n二维数组 (矩阵):\n”, matrix)
print(“维度:”, matrix.shape) # (3, 3) 表示3行3列的矩阵
print(“数据类型:”, matrix.dtype)
“`
其他创建数组的方法:
np.zeros(shape): 创建全为零的数组。np.ones(shape): 创建全为一的数组。np.full(shape, fill_value): 创建指定值的数组。np.arange(start, stop, step): 创建等差数列。np.linspace(start, stop, num): 创建等间距数列。np.random.rand(d0, d1, ...): 创建在 [0, 1) 之间均匀分布的随机数。np.identity(n)或np.eye(n): 创建单位矩阵。
“`python
zeros_matrix = np.zeros((2, 3))
print(“\n全零矩阵:\n”, zeros_matrix)
ones_vector = np.ones(4)
print(“\n全一向量:\n”, ones_vector)
identity_matrix = np.identity(3)
print(“\n单位矩阵:\n”, identity_matrix)
random_matrix = np.random.rand(2, 2)
print(“\n随机矩阵:\n”, random_matrix)
“`
1.2 数组属性
.shape: 数组的维度 (元组)。.ndim: 数组的维数 (整数)。.size: 数组中元素的总数 (整数)。.dtype: 数组中元素的数据类型。
python
print("\nmatrix 的维度:", matrix.ndim)
print("matrix 的元素总数:", matrix.size)
2. 基本算术运算 (Element-wise Operations)
NumPy 数组之间的加、减、乘、除等算术运算默认是按元素进行的 (element-wise)。
“`python
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(“a:”, a)
print(“b:”, b)
print(“\na + b:”, a + b) # [5 7 9]
print(“a – b:”, a – b) # [-3 -3 -3]
print(“a * b:”, a * b) # [4 10 18] (元素级乘法)
print(“a / b:”, a / b) # [0.25 0.4 0.5 ]
与标量进行运算
print(“\na + 10:”, a + 10) # [11 12 13]
print(“a * 2:”, a * 2) # [2 4 6]
“`
对于矩阵也一样:
“`python
matrix1 = np.array([[1, 2], [3, 4]])
matrix2 = np.array([[5, 6], [7, 8]])
print(“\nmatrix1:\n”, matrix1)
print(“matrix2:\n”, matrix2)
print(“\nmatrix1 + matrix2:\n”, matrix1 + matrix2)
print(“matrix1 * matrix2:\n”, matrix1 * matrix2) # 元素级乘法
“`
3. 矩阵乘法 (Dot Product)
矩阵乘法是线性代数中的一个核心操作。在 NumPy 中,可以使用 @ 运算符或 np.dot() 函数执行矩阵乘法。
重要规则: 两个矩阵 A 和 B 可以相乘,当且仅当矩阵 A 的列数等于矩阵 B 的行数。结果矩阵的行数与 A 的行数相同,列数与 B 的列数相同。
“`python
A = np.array([[1, 2],
[3, 4]])
B = np.array([[5, 6],
[7, 8]])
print(“矩阵 A:\n”, A)
print(“矩阵 B:\n”, B)
使用 @ 运算符进行矩阵乘法
C = A @ B
print(“\nA @ B (矩阵乘法):\n”, C)
使用 np.dot() 函数进行矩阵乘法
D = np.dot(A, B)
print(“\nnp.dot(A, B) (矩阵乘法):\n”, D)
结果应为:
[[ 15 + 27, 16 + 28],
[ 35 + 47, 36 + 48]]
= [[5+14, 6+16],
[15+28, 18+32]]
= [[19, 22],
[43, 50]]
“`
3.1 向量的内积 (Dot Product)
当对一维数组 (向量) 使用 np.dot() 或 @ 时,它们计算的是向量的内积 (点积)。
“`python
v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])
print(“\n向量 v1:”, v1)
print(“向量 v2:”, v2)
向量内积:14 + 25 + 3*6 = 4 + 10 + 18 = 32
dot_product_vec = np.dot(v1, v2)
print(“\nv1 和 v2 的内积 (np.dot):”, dot_product_vec)
对于一维数组,@ 运算符的行为与 np.dot 相同
dot_product_vec_at = v1 @ v2
print(“v1 和 v2 的内积 (@ 运算符):”, dot_product_vec_at)
“`
4. 向量的叉积 (Cross Product)
叉积 (或向量积) 是只在三维空间中定义的二元运算。结果是一个向量,它垂直于两个输入向量。
“`python
vec_a = np.array([1, 0, 0]) # x 轴单位向量
vec_b = np.array([0, 1, 0]) # y 轴单位向量
print(“\n向量 vec_a:”, vec_a)
print(“向量 vec_b:”, vec_b)
x 轴和 y 轴的叉积是 z 轴
cross_product_result = np.cross(vec_a, vec_b)
print(“vec_a 和 vec_b 的叉积:”, cross_product_result) # [0, 0, 1]
“`
5. 广播 (Broadcasting)
广播是 NumPy 的一个强大功能,它允许 NumPy 在执行算术运算时,对形状不同的数组进行处理。
当两个数组的形状不兼容时,NumPy 会尝试“广播”其中一个或两个数组,使其形状兼容。广播遵循一套严格的规则:
- 维数相同: 比较两个数组的维度,从尾部维度开始向前比较。
- 维度不同: 如果一个数组的维数少于另一个,那么较小维数的数组会从其左侧被“填充”为 1。
- 兼容规则:
- 如果两个维度相等,则兼容。
- 如果其中一个维度为 1,则兼容(该维度会被拉伸以匹配另一个维度)。
- 否则,不兼容,会引发
ValueError。
示例:
“`python
matrix_3x3 = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
vector_row = np.array([10, 20, 30]) # 形状 (3,)
vector_col = np.array([[10],
[20],
[30]]) # 形状 (3, 1)
print(“matrix_3x3:\n”, matrix_3x3)
print(“\nvector_row:”, vector_row)
print(“vector_row.shape:”, vector_row.shape)
print(“\nvector_col:\n”, vector_col)
print(“vector_col.shape:”, vector_col.shape)
广播示例 1: 矩阵 + 行向量
vector_row (3,) 会被广播成 (1, 3),然后被拉伸成 (3, 3)
result1 = matrix_3x3 + vector_row
print(“\nmatrix_3x3 + vector_row (广播):\n”, result1)
广播示例 2: 矩阵 + 列向量
vector_col (3, 1) 会被拉伸成 (3, 3)
result2 = matrix_3x3 + vector_col
print(“\nmatrix_3x3 + vector_col (广播):\n”, result2)
不兼容的广播示例
vector_row 的形状是 (3,)
np.array([1, 2]) 的形状是 (2,)
尾部维度不匹配 (3 != 2),且都不是 1
try:
np.array([1, 2, 3]) + np.array([1, 2])
except ValueError as e:
print(f”\n广播错误示例: {e}”)
“`
6. 索引、切片和重塑
6.1 索引和切片
NumPy 数组的索引和切片与 Python 列表类似,但支持多维。
“`python
data = np.array([[10, 20, 30, 40],
[50, 60, 70, 80],
[90, 100, 110, 120]])
print(“原始数据:\n”, data)
访问单个元素 (行, 列)
print(“\ndata[0, 1]:”, data[0, 1]) # 20
访问第一行
print(“data[0, :]:”, data[0, :]) # [10 20 30 40]
print(“data[0]:”, data[0]) # 等价于 data[0, :]
访问第一列
print(“data[:, 0]:”, data[:, 0]) # [10 50 90]
访问子矩阵
print(“data[0:2, 1:3]:\n”, data[0:2, 1:3])
[[20 30]
[60 70]]
使用步长
print(“data[::2, ::-1]:\n”, data[::2, ::-1]) # 每两行取一次,列反向
“`
6.2 布尔索引
使用布尔数组进行索引,可以方便地筛选满足条件的元素。
“`python
matrix_vals = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
找到所有大于 5 的元素
greater_than_5 = (matrix_vals > 5)
print(“\n大于 5 的布尔掩码:\n”, greater_than_5)
使用布尔掩码进行筛选
filtered_elements = matrix_vals[greater_than_5]
print(“筛选出的元素 (大于 5):”, filtered_elements) # [6 7 8 9]
“`
6.3 花式索引 (Fancy Indexing)
使用整数数组进行索引。
“`python
arr = np.array([10, 20, 30, 40, 50, 60])
访问指定位置的元素
indices = np.array([0, 2, 5])
print(“\n花式索引结果:”, arr[indices]) # [10 30 60]
也可以用于二维数组
matrix_fancy = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
rows = np.array([0, 2, 1]) # 选取第0, 2, 1行
cols = np.array([1, 0, 2]) # 选取第1, 0, 2列 (与行索引对应)
结果是 (matrix_fancy[0,1], matrix_fancy[2,0], matrix_fancy[1,2])
print(“\n花式索引二维数组 (对应元素):\n”, matrix_fancy[rows, cols]) # [2 7 6]
选取多行多列构成子矩阵
print(“\n选取多行多列 (子矩阵):\n”, matrix_fancy[rows[:, np.newaxis], cols])
[[2 1 3]
[8 7 9]
[5 4 6]]
“`
6.4 重塑 (Reshaping)
reshape() 函数可以改变数组的形状,但不会改变其数据。
“`python
original_array = np.arange(12) # [0, 1, …, 11]
print(“\n原始数组:”, original_array)
重塑为 3 行 4 列的矩阵
reshaped_matrix = original_array.reshape(3, 4)
print(“\n重塑为 3×4 矩阵:\n”, reshaped_matrix)
重塑为 2 行 6 列的矩阵
reshaped_2x6 = original_array.reshape(2, 6)
print(“\n重塑为 2×6 矩阵:\n”, reshaped_2x6)
使用 -1 让 NumPy 自动计算维度
reshaped_auto = original_array.reshape(4, -1) # 4 行,列数自动计算为 3
print(“\n重塑为 4x? 矩阵:\n”, reshaped_auto)
将矩阵展平为一维数组
flattened_array = reshaped_matrix.flatten()
print(“\n展平为一维数组 (flatten):\n”, flattened_array)
使用 .ravel() 也能展平,但它返回的是视图 (可能共享内存),flatten 返回副本
raveled_array = reshaped_matrix.ravel()
print(“展平为一维数组 (ravel):\n”, raveled_array)
“`
7. 常用线性代数函数
NumPy 的 linalg 模块提供了许多有用的线性代数函数。
“`python
matrix_la = np.array([[1, 2],
[3, 4]])
print(“矩阵 matrix_la:\n”, matrix_la)
转置 (Transpose)
transpose_matrix = matrix_la.T
print(“\n转置矩阵 (matrix_la.T):\n”, transpose_matrix)
也可以使用 np.transpose(matrix_la)
逆矩阵 (Inverse)
try:
inverse_matrix = np.linalg.inv(matrix_la)
print(“\n逆矩阵 (np.linalg.inv):\n”, inverse_matrix)
# 验证:矩阵 * 逆矩阵 约等于 单位矩阵
print(“matrix_la @ inverse_matrix:\n”, matrix_la @ inverse_matrix)
except np.linalg.LinAlgError:
print(“\n矩阵不可逆”)
行列式 (Determinant)
determinant = np.linalg.det(matrix_la)
print(“\n行列式 (np.linalg.det):”, determinant)
特征值和特征向量 (Eigenvalues and Eigenvectors)
返回两个数组:第一个是特征值,第二个是特征向量 (每列是一个特征向量)
eigenvalues, eigenvectors = np.linalg.eig(matrix_la)
print(“\n特征值 (np.linalg.eig):\n”, eigenvalues)
print(“特征向量 (np.linalg.eig):\n”, eigenvectors)
求解线性方程组 Ax = b
A_eq = np.array([[2, 1],
[1, 1]])
b_eq = np.array([5, 3])
求解 x
x_solution = np.linalg.solve(A_eq, b_eq)
print(“\n线性方程组 Ax=b 的解 (np.linalg.solve):”, x_solution)
验证:A @ x_solution 应该等于 b_eq
print(“验证 A @ x_solution:”, A_eq @ x_solution)
“`
8. 聚合函数
NumPy 提供了许多用于聚合数组的函数,例如求和、平均值、最大值、最小值等。
“`python
agg_matrix = np.array([[1, 2, 3],
[4, 5, 6]])
print(“聚合矩阵:\n”, agg_matrix)
数组所有元素的和
print(“\n所有元素的和 (np.sum):”, np.sum(agg_matrix))
沿着指定轴求和 (axis=0 按列,axis=1 按行)
print(“按列求和 (axis=0):”, np.sum(agg_matrix, axis=0)) # [5 7 9]
print(“按行求和 (axis=1):”, np.sum(agg_matrix, axis=1)) # [ 6 15]
平均值
print(“\n所有元素的平均值 (np.mean):”, np.mean(agg_matrix))
print(“按列平均值 (axis=0):”, np.mean(agg_matrix, axis=0))
最大值和最小值
print(“\n所有元素的最大值 (np.max):”, np.max(agg_matrix))
print(“按行最小值 (axis=1):”, np.min(agg_matrix, axis=1))
其他聚合函数:np.std (标准差), np.var (方差), np.median (中位数) 等
“`
总结
NumPy 是 Python 中进行矩阵和向量运算的基石。通过本文,你应该对以下概念有了深入的理解:
ndarray对象: NumPy 的核心,用于表示多维数组。- 数组创建: 使用
np.array(),np.zeros(),np.ones()等方法。 - 元素级运算: 数组之间的加减乘除默认按元素进行。
- 矩阵乘法: 使用
@运算符或np.dot()函数进行,是线性代数的核心。 - 向量内积与叉积:
np.dot()和np.cross()。 - 广播 (Broadcasting): NumPy 处理不同形状数组运算的强大机制。
- 索引、切片和重塑: 灵活地访问和改变数组结构。
- 线性代数函数:
np.linalg模块提供了转置、逆矩阵、行列式、特征值等高级功能。 - 聚合函数:
np.sum(),np.mean(),np.max()等用于统计分析。
掌握这些 NumPy 基础知识,将为你在数据科学、机器学习和科学计算领域的进一步学习和实践打下坚实的基础。