Python NumPy 教程:矩阵与向量运算 – wiki基地

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() 函数执行矩阵乘法。

重要规则: 两个矩阵 AB 可以相乘,当且仅当矩阵 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. 维数相同: 比较两个数组的维度,从尾部维度开始向前比较。
  2. 维度不同: 如果一个数组的维数少于另一个,那么较小维数的数组会从其左侧被“填充”为 1。
  3. 兼容规则:
    • 如果两个维度相等,则兼容。
    • 如果其中一个维度为 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 基础知识,将为你在数据科学、机器学习和科学计算领域的进一步学习和实践打下坚实的基础。

滚动至顶部