在Python中,numpy提供了强大的矩阵运算功能。使用numpy,你可以轻松执行矩阵加法、矩阵乘法、转置、逆矩阵、行列式等多种矩阵运算。而在机器学习、深度学习和自动驾驶算法开发中,矩阵运算是最基础的运算,本文详细介绍numpy的矩阵操作和运算方法,同时通过实例展示其在具体工程开发中的应用。
1. 矩阵创建
1.1 普通矩阵
通过 numpy.array() 将 Python 的二维列表转换为 NumPy 矩阵。
import numpy as np
# 使用二维列表创建一个 2x3 的矩阵
matrix = np.array([[1, 2, 3], [4, 5, 6]])
print(matrix)
[[1 2 3]
[4 5 6]]
1.2 特殊矩阵
1.2.1 全零矩阵
使用 numpy.zeros()
创建一个全零矩阵,指定矩阵的形状即可。
# 创建一个 3x3 的全零矩阵
zero_matrix = np.zeros((3, 3))
1.2.2 全1矩阵
使用 numpy.ones()
创建一个所有元素为1的矩阵。
# 创建一个 2x2 的全1矩阵
ones_matrix = np.ones((2, 2))
1.2.3 单位矩阵
使用 numpy.eye()
或 numpy.identity()
创建单位矩阵。单位矩阵是对角线为1,其余元素为0的方阵。
# 创建一个 3x3 的单位矩阵
identity_matrix = np.eye(3)
1.2.4 随机矩阵
使用 numpy.random.rand()
创建一个指定形状的随机矩阵,元素的取值范围在 [0, 1) 之间。
# 创建一个 2x3 的随机矩阵
random_matrix = np.random.rand(2, 3)
1.2.5 随机整数矩阵
使用 numpy.random.randint()
创建一个由随机整数组成的矩阵,指定取值范围和矩阵形状。
# 创建一个 2x3 的随机整数矩阵,元素在 [0, 10) 之间
random_int_matrix = np.random.randint(0, 10, size=(2, 3))
1.2.6 特定范围的矩阵
使用 numpy.arange()
和 reshape()
创建一个包含特定范围数值的矩阵,
# 创建一个包含 1 到 9 的矩阵,并 reshape 为 3x3 的矩阵
# numpy.arange(start, stop, step, dtype=None)默认不包括终点
range_matrix = np.arange(1, 10, 1).reshape((3, 3))
1.2.7 等间隔数值矩阵
使用 numpy.linspace()
创建一个包含等间隔数值的矩阵。
# 创建包含从 0 到 1 的 9 个等间隔数值的数组
# numpy.linspace(start, stop, num=50)默认包括终点
linspace_matrix = np.linspace(1, 9, 9).reshape((3, 3))
1.2.8 对角矩阵
使用 numpy.diag()
可以从一个数组生成对角矩阵,或者提取矩阵的对角线元素。
# 创建一个对角矩阵
diag_matrix = np.diag([1, 2, 3])
2. 矩阵array参数
ndim
:返回数组的维数
shape
:返回数组的形状
size
:返回数组中所有元素的总个数
dtype
:返回数组中元素的数据类型
itemsize
:返回数组中每个元素的字节大小
nbytes
:返回数组占用的总字节数
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("维度 (ndim):", arr.ndim)
print("形状 (shape):", arr.shape)
print("元素总数 (size):", arr.size)
print("数据类型 (dtype):", arr.dtype)
print("每个元素的字节大小 (itemsize):", arr.itemsize)
print("数组占用的总字节大小 (nbytes):", arr.nbytes)
3. 矩阵索引
在 NumPy
中,矩阵(多维数组)的索引和切片非常灵活,可以通过多种方式访问或修改矩阵中的元素。以下是一些常见的 NumPy
矩阵索引操作。
3.1 基本索引
与 Python 的列表类似,NumPy
矩阵的索引从 0 开始,可以使用行、列的索引来访问特定元素。
import numpy as np
# 创建一个 3x3 矩阵
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 访问第一行第二列的元素
element = A[0, 1]
print("第一行第二列的元素:", element)
3.2 矩阵切片
切片操作可以用于选择矩阵中的一部分。语法为 [起始:结束:步长]
。
# 选择前两行的所有列
row_slice = A[:2, :]
print("前两行的子矩阵:\n", row_slice)
# 选择所有行的第二列
col_slice = A[:, 1]
print("所有行的第二列:\n", col_slice)
# 选择前两行和前两列
sub_matrix = A[:2, :2]
print("子矩阵:\n", sub_matrix)
# 选择所有行,每隔一列取一个元素
step_slice = A[:, ::2]
print("步长为2的子矩阵:\n", step_slice)
3.3 布尔索引
布尔索引允许通过条件筛选矩阵中的元素,返回满足条件的元素。
# 选择矩阵中所有大于5的元素
bool_index = A[A > 5]
print("大于5的元素:", bool_index)
3.4 花式索引
花式索引允许通过指定多个索引来访问矩阵中的特定元素。
# 访问矩阵中指定的行和列的元素
fancy_index = A[[0, 2], [1, 2]] # 访问 (0,1) 和 (2,2) 位置的元素
print("花式索引结果:", fancy_index)
3.5 子矩阵索引
可以通过使用多个索引列表选择特定的行和列组成子矩阵。
# 选择第 0 和 2 行,第 1 和 2 列,生成子矩阵
sub_matrix = A[[0, 2], :][:, [1, 2]]
print("子矩阵:\n", sub_matrix)
4. 矩阵拼接
在 NumPy
中,矩阵拼接(合并)操作主要通过 numpy.concatenate()
、numpy.hstack()
、numpy.vstack()
和 numpy.stack()
等函数来实现。可以通过这些函数将多个矩阵沿不同的轴进行拼接。
4.1 numpy.concatenate
numpy.concatenate()
可以将多个数组沿指定的轴进行拼接。默认情况下,它沿着第一个轴(axis=0
)拼接。numpy.vstack()
是 numpy.concatenate()
的简化版,用于垂直方向(沿 axis=0
,行)的拼接,相当于 axis=0
的拼接。
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 沿着 axis=0 拼接(即行拼接)
C = np.concatenate((A, B), axis=0)
print("行拼接结果:\n", C)
D = np.concatenate((A, B), axis=1)
print("列拼接结果:\n", D)
E = np.vstack((A, B))
print("垂直拼接结果:\n", E)
F = np.hstack((A, B))
print("水平拼接结果:\n", F)
4.2 numpy.stack
numpy.stack()
是用于沿着新轴拼接数组,它可以在现有的数组中插入一个新的维度进行拼接。你可以指定 axis
参数来选择在哪个轴上插入新的维度。
G = np.stack((A, B), axis=0)
print("沿新轴拼接结果(axis=0):\n", G)
沿新轴拼接结果(axis=0):
[[[1 2]
[3 4]][[5 6]
[7 8]]]
4.3 numpy.block
numpy.block()
函数可以用于更复杂的矩阵拼接,通过提供嵌套列表的方式将多个矩阵块组合成一个大的矩阵。
K = np.block([[A, B], [B, A]])
print("块拼接结果:\n", K)
5. 矩阵初级运算
5.1 矩阵逐元素加减乘除
矩阵逐元素加减乘除是逐元素操作,要求两个矩阵的形状相同。
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 矩阵加法
C = A + B
print("矩阵加法:\n", C)
# 矩阵减法
D = A - B
print("矩阵减法:\n", D)
# 矩阵逐元素乘法
element_wise_product = A * B
print("逐元素乘法:\n", element_wise_product)
# 矩阵逐元素除法
element_wise_divide = A / B
print("逐元素除法结果:\n", element_wise_divide)
5.2 矩阵乘法
矩阵点乘:矩阵对应元素相乘(形状相同)np.multiply(a,b) 或a*b
矩阵叉乘(矩阵相乘):np.dot(a,b)或a@b
向量点乘(向量内积):np.dot(a,b)或a@b,为标量
向量逐元素相乘:np.multiply(a,b)等价于a*b
向量外积(向量积或叉积):np.cross(a,b)两个向量的法向量
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
C = np.array([1, 2, 3])
D = np.array([5, 6, 7])
# 矩阵点乘/矩阵逐元素相乘
E = A * B
F = np.multiply(A, B)
# 矩阵相乘/矩阵叉乘
G = A @ B
H = np.dot(A, B)
# 向量点乘/向量内积
J = C @ D
K = np.dot(C, D)
# 向量逐元素相乘
L = C * D
M = np.multiply(C, D)
# 向量外积、向量积或叉积,向量的法向量
N = np.cross(C, D)
print("向量外积:\n", N)
6. 矩阵的高级操作
6.1 矩阵属性
矩阵转置:矩阵的转置是将矩阵的行和列互换,使用 .T
属性。
矩阵的逆:矩阵的逆对方阵(行数与列数相同的矩阵)定义,使用 numpy.linalg.inv()
可以计算矩阵的逆。
矩阵的行列式:行列式是标量值,表示矩阵的某些属性(如是否可逆)。使用 numpy.linalg.det()
可以计算矩阵的行列式。
矩阵的迹:矩阵的迹是矩阵主对角线上元素的和,使用 numpy.trace()
可以计算。
矩阵的特征值和特征向量:特征值和特征向量是矩阵的重要属性。你可以使用 numpy.linalg.eig()
函数来计算特征值和特征向量。
矩阵的广义逆:广义逆矩阵(Moore-Penrose伪逆)用于非方阵或不可逆的矩阵。使用 numpy.linalg.pinv()
计算矩阵的广义逆。
矩阵的范数:矩阵的范数用于度量矩阵的大小。可以使用 numpy.linalg.norm()
计算不同类型的范数。
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 矩阵转置
A_T = A.T
print("矩阵转置:\n", A_T)
# 矩阵的逆
A_inv = np.linalg.inv(A)
print("矩阵的逆:\n", A_inv)
# 矩阵的行列式
det_A = np.linalg.det(A)
print("矩阵行列式:\n", det_A)
# 矩阵的迹
trace_A = np.trace(A)
print("矩阵的迹:\n", trace_A)
# 计算特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(A)
print("特征值:\n", eigenvalues)
print("特征向量:\n", eigenvectors)
# 计算广义逆矩阵
pseudo_inv = np.linalg.pinv(A)
print("广义逆矩阵:\n", pseudo_inv)
# 计算矩阵的二范数(默认)
norm_A = np.linalg.norm(A)
print("矩阵的二范数:\n", norm_A)
# 计算矩阵的 1 范数(列和的最大值)
norm_A_1 = np.linalg.norm(A, ord=1)
print("矩阵的 1 范数:\n", norm_A_1)
# 计算矩阵的无穷范数(行和的最大值)
norm_A_inf = np.linalg.norm(A, ord=np.inf)
print("矩阵的无穷范数:\n", norm_A_inf)
6.2 广播机制
广播机制允许对不同形状的数组执行逐元素操作,NumPy
会自动扩展较小的数组以匹配较大的数组进行计算。广播使得矩阵运算更加高效和简洁。
import numpy as np
# 2x3 的矩阵
A = np.array([[1, 2, 3], [4, 5, 6]])
# 1x3 的数组,广播到 2x3 的形状
B = np.array([10, 20, 30])
# 逐元素相加
C = A + B
print("广播后的矩阵相加结果:\n", C)
6.3 矩阵分解
矩阵分解是线性代数中的重要工具,常用于求解线性方程组、特征值问题、最小二乘法等。NumPy
提供了多种矩阵分解方法,如 LU 分解、QR 分解和奇异值分解(SVD)。
6.3.1 LU 分解
LU 分解将矩阵分解为一个下三角矩阵和一个上三角矩阵。
import scipy.linalg as la
A = np.array([[4, 3], [6, 3]])
P, L, U = la.lu(A)
print("P 矩阵:\n", P)
print("L 矩阵:\n", L)
print("U 矩阵:\n", U)
6.3.2 QR 分解
QR 分解将矩阵分解为正交矩阵和上三角矩阵。
Q, R = np.linalg.qr(A)
print("Q 矩阵:\n", Q)
print("R 矩阵:\n", R)
6.3.3 SVD分解
SVD 是将矩阵分解为三个矩阵:左奇异矩阵、对角矩阵(奇异值)、右奇异矩阵。
U, S, V = np.linalg.svd(A)
print("U 矩阵:\n", U)
print("奇异值:\n", S)
print("V 矩阵:\n", V)
6.4 最小二乘法
使用 numpy.linalg.lstsq()
解决超定方程(方程个数多于未知数)的最小二乘问题。
import numpy as np
A = np.array([[1, 1], [1, 2], [1, 3]])
B = np.array([1, 2, 2])
# 使用最小二乘法求解 AX = B
X, residuals, rank, s = np.linalg.lstsq(A, B, rcond=None)
print("最小二乘法求解结果:\n", X)
7. 张量计算
7.1 张量定义
在 NumPy
中,张量是指具有多维数据结构的数组,通常扩展自二维矩阵。张量可以是 1D(向量)、2D(矩阵)、3D(例如彩色图像的表示)甚至是更高维度的数组。NumPy
提供了多种方法来操作和计算张量,广泛应用于机器学习、深度学习、科学计算等领域。在 NumPy
中,张量本质上就是多维数组,使用 np.array()
函数可以创建不同维度的张量。
7.2 张量运算
7.2.1 numpy.tensordot
numpy.tensordot()
是用于计算两个张量的 张量积。它可以沿指定的轴对两个张量进行求和操作。这种方法常用于执行类似矩阵乘法或高维张量的积操作。你可以指定沿哪些轴进行运算。
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
C = np.tensordot(A, B, axes=1)
print("矩阵乘法结果(tensordot):\n", C)
7.2.2 numpy.einsum
numpy.einsum()
实现了基于 爱因斯坦求和约定(Einstein Summation Convention) 的张量运算。它允许通过字符来表示张量的维度,并定义如何操作张量(求和、外积、内积、转置、矩阵乘法等)。这种方式提供了更灵活和简洁的表达方式,适用于各种张量运算。
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 使用 einsum 进行矩阵乘法
C = np.einsum('ik,kj->ij', A, B)
print("矩阵乘法结果:\n", C)
diagonal = np.einsum('ii->i', A)
print("矩阵的对角线元素:", diagonal)
trace = np.einsum('ii->', A)
print("矩阵的迹:", trace)
8. 应用示例
8.1 解3x3线性方程组
考虑线性方程组:
对应的矩阵形式为:
使用 numpy.linalg.solve()
来求解:
import numpy as np
# 系数矩阵 A
A = np.array([[1, 2, 3], [4, 5, 6], [7, 4, 3]])
# 结果向量 B
B = np.array([1, 2, 3])
# 求解线性方程组
X = np.linalg.solve(A, B)
print("解:\n", X)
解:
[ 1. -2. 1.33333333]
8.2 二次多项式拟合
假设我们有一组数据点,拟合一条二次曲线。
import numpy as np
import matplotlib.pyplot as plt
# 给定的 x 和 y 数据
x = np.array([0, 1, 2, 3, 4, 5])
y = np.array([1, 1.8, 3.2, 4.5, 6.1, 8])
# 使用 numpy.polyfit 拟合二次多项式
coefficients = np.polyfit(x, y, 2)
# 打印拟合的多项式系数
print("二次多项式系数:", coefficients)
# 根据拟合结果创建多项式函数
p = np.poly1d(coefficients)
# 生成拟合曲线的 x 和 y 值
x_fit = np.linspace(0, 5, 100)
y_fit = p(x_fit)
# 绘制原始数据点和拟合曲线
plt.scatter(x, y, color='red', label='数据点')
plt.plot(x_fit, y_fit, label='拟合曲线', color='blue')
plt.xlabel('x')
plt.ylabel('y')
plt.title('二次多项式拟合')
plt.legend()
plt.show()
二次多项式系数: [0.1125 0.84321429 0.96071429]