MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python NumPy中的矩阵与线性代数运算

2021-10-287.8k 阅读

Python NumPy中的矩阵与线性代数运算

NumPy基础介绍

NumPy(Numerical Python)是Python中一个极为重要的库,专门用于处理多维数组和矩阵运算。它提供了高效的数组操作,大大提升了数值计算的效率。在NumPy中,核心的数据结构是ndarray(N-dimensional array),即多维数组。

创建NumPy数组

可以通过多种方式创建NumPy数组。例如,从Python列表创建:

import numpy as np

# 从一维列表创建一维数组
list1 = [1, 2, 3]
arr1 = np.array(list1)
print(arr1)

# 从二维列表创建二维数组
list2d = [[1, 2, 3], [4, 5, 6]]
arr2d = np.array(list2d)
print(arr2d)

上述代码中,np.array()函数将Python列表转换为NumPy数组。一维列表转换为一维数组,二维列表转换为二维数组,以此类推。

数组属性

NumPy数组具有一些重要的属性,比如shape表示数组的维度形状,dtype表示数组元素的数据类型。

import numpy as np

arr = np.array([[1, 2, 3], [4, 5, 6]])
print("数组形状:", arr.shape)
print("数据类型:", arr.dtype)

arr.shape返回一个元组,对于二维数组,第一个元素是行数,第二个元素是列数。arr.dtype显示数组中元素的数据类型,常见的有int64float64等。

矩阵相关操作

在NumPy中,矩阵是二维数组的一种特殊形式。虽然NumPy本身没有专门的矩阵类(在早期版本有matrix类,但现在推荐使用二维数组代替),但可以使用二维数组来进行矩阵相关的操作。

创建矩阵(二维数组表示)

import numpy as np

# 创建一个2x3的矩阵(二维数组)
matrix = np.array([[1, 2, 3], [4, 5, 6]])
print(matrix)

这里创建的matrix本质是一个二维数组,但在运算时可以按照矩阵的规则进行操作。

矩阵索引与切片

矩阵的索引和切片与二维数组类似。可以通过索引获取特定位置的元素,通过切片获取子矩阵。

import numpy as np

matrix = np.array([[1, 2, 3], [4, 5, 6]])

# 获取第一行第二列的元素
element = matrix[0, 1]
print("第一行第二列的元素:", element)

# 获取第一行
row = matrix[0, :]
print("第一行:", row)

# 获取前两行,前两列组成的子矩阵
sub_matrix = matrix[:2, :2]
print("子矩阵:", sub_matrix)

通过matrix[row_index, col_index]获取单个元素,matrix[row_slice, col_slice]获取子矩阵。其中:表示取所有元素。

矩阵转置

矩阵的转置是将矩阵的行和列互换。在NumPy中,可以使用transpose()方法或T属性来实现矩阵转置。

import numpy as np

matrix = np.array([[1, 2, 3], [4, 5, 6]])

# 使用transpose方法
transposed1 = matrix.transpose()
print("使用transpose方法转置后的矩阵:\n", transposed1)

# 使用T属性
transposed2 = matrix.T
print("使用T属性转置后的矩阵:\n", transposed2)

这两种方式都能实现矩阵转置,T属性更为简洁。

线性代数运算

NumPy提供了丰富的线性代数运算函数,涵盖矩阵乘法、求逆、行列式计算、特征值和特征向量计算等。

矩阵乘法

矩阵乘法是线性代数中的基本运算。在NumPy中,可以使用dot()函数或@运算符进行矩阵乘法。

import numpy as np

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 使用dot函数
product1 = np.dot(A, B)
print("使用dot函数的矩阵乘积:\n", product1)

# 使用@运算符
product2 = A @ B
print("使用@运算符的矩阵乘积:\n", product2)

需要注意的是,矩阵乘法要求前一个矩阵的列数等于后一个矩阵的行数。这里A是2x2矩阵,B也是2x2矩阵,满足乘法条件。

矩阵求逆

对于方阵,如果存在逆矩阵,求逆操作可以通过linalg.inv()函数实现。

import numpy as np

A = np.array([[1, 2], [3, 4]])

try:
    inverse = np.linalg.inv(A)
    print("矩阵的逆:\n", inverse)
except np.linalg.LinAlgError:
    print("该矩阵不可逆")

并非所有方阵都可逆,若矩阵不可逆,linalg.inv()函数会抛出LinAlgError异常。

行列式计算

矩阵的行列式是一个标量值,可以通过linalg.det()函数计算。

import numpy as np

A = np.array([[1, 2], [3, 4]])
det = np.linalg.det(A)
print("矩阵的行列式:", det)

对于2x2矩阵[[a, b], [c, d]],其行列式为ad - bc。上述代码中,A的行列式为1*4 - 2*3 = -2

特征值和特征向量计算

特征值和特征向量在许多领域如物理学、工程学中都有重要应用。在NumPy中,可以使用linalg.eig()函数计算方阵的特征值和特征向量。

import numpy as np

A = np.array([[1, 2], [2, 1]])
eigenvalues, eigenvectors = np.linalg.eig(A)
print("特征值:", eigenvalues)
print("特征向量:\n", eigenvectors)

eig()函数返回两个值,第一个是特征值组成的一维数组,第二个是特征向量组成的二维数组,每一列是一个特征向量。

矩阵的分解

矩阵分解是将矩阵分解为多个矩阵的乘积,这在数值计算和数据分析中有广泛应用。NumPy提供了一些常用的矩阵分解函数。

LU分解

LU分解将一个矩阵分解为一个下三角矩阵(L)和一个上三角矩阵(U)的乘积。在NumPy中,可以使用scipy.linalg.lu()函数(scipy库基于numpy,这里需要导入scipy.linalg)。

import numpy as np
from scipy.linalg import lu

A = np.array([[2, -1, 1], [3, 3, 9], [3, 3, 5]])
P, L, U = lu(A)
print("置换矩阵P:\n", P)
print("下三角矩阵L:\n", L)
print("上三角矩阵U:\n", U)

这里lu()函数返回三个矩阵,P是置换矩阵,L是下三角矩阵,U是上三角矩阵,满足A = P @ L @ U

QR分解

QR分解将矩阵分解为一个正交矩阵(Q)和一个上三角矩阵(R)的乘积。同样在scipy.linalg中,使用qr()函数。

import numpy as np
from scipy.linalg import qr

A = np.array([[1, 1], [2, 1], [3, 1]])
Q, R = qr(A)
print("正交矩阵Q:\n", Q)
print("上三角矩阵R:\n", R)

QR分解在求解线性方程组、最小二乘法等问题中有重要应用。

SVD分解(奇异值分解)

奇异值分解(SVD)将矩阵分解为三个矩阵的乘积:A = U @ S @ V.T,其中UV是正交矩阵,S是对角矩阵,对角线上的元素为奇异值。在NumPy中,使用linalg.svd()函数。

import numpy as np

A = np.array([[1, 2], [3, 4], [5, 6]])
U, s, V = np.linalg.svd(A)
S = np.diag(s)
print("U矩阵:\n", U)
print("奇异值矩阵S:\n", S)
print("V矩阵:\n", V)

SVD在数据降维、图像压缩等领域有广泛应用,通过保留较大的奇异值,可以实现对矩阵的近似表示。

求解线性方程组

线性方程组在科学计算和工程问题中经常出现。例如,对于线性方程组Ax = b,其中A是系数矩阵,x是未知数向量,b是常数向量。在NumPy中,可以使用linalg.solve()函数求解。

import numpy as np

A = np.array([[2, 1], [1, -1]])
b = np.array([4, -1])

x = np.linalg.solve(A, b)
print("线性方程组的解:", x)

上述代码中,np.linalg.solve(A, b)函数求解了线性方程组Ax = b,返回的x是方程组的解向量。需要注意的是,A必须是方阵且可逆,否则会抛出异常。

矩阵范数

矩阵范数是衡量矩阵“大小”的一种方式,在数值分析中用于评估矩阵运算的误差和稳定性。NumPy的linalg模块提供了计算矩阵范数的函数。

常用矩阵范数

  1. 1 - 范数:列元素绝对值之和的最大值。可以使用linalg.norm(A, ord = 1)计算。
  2. 2 - 范数:最大奇异值。使用linalg.norm(A, ord = 2),在默认情况下ord参数省略时,计算的也是2 - 范数。
  3. 无穷范数:行元素绝对值之和的最大值。通过linalg.norm(A, ord = np.inf)计算。
import numpy as np

A = np.array([[1, 2], [3, 4]])

norm_1 = np.linalg.norm(A, ord = 1)
norm_2 = np.linalg.norm(A, ord = 2)
norm_inf = np.linalg.norm(A, ord = np.inf)

print("1 - 范数:", norm_1)
print("2 - 范数:", norm_2)
print("无穷范数:", norm_inf)

这些范数在不同的应用场景中有不同的用途,比如在误差分析、迭代算法收敛性判断等方面。

案例应用

图像压缩

图像可以表示为矩阵,利用SVD分解可以实现图像的压缩。以灰度图像为例,假设我们有一个图像矩阵image_matrix

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

# 读取图像并转换为灰度图
image = Image.open('example.jpg').convert('L')
image_matrix = np.array(image)

# 进行SVD分解
U, s, V = np.linalg.svd(image_matrix)

# 保留前k个奇异值进行近似
k = 50
S_k = np.diag(s[:k])
U_k = U[:, :k]
V_k = V[:k, :]
approx_matrix = U_k @ S_k @ V_k

# 显示原始图像和压缩后的图像
plt.subplot(1, 2, 1)
plt.imshow(image_matrix, cmap='gray')
plt.title('原始图像')

plt.subplot(1, 2, 2)
plt.imshow(approx_matrix, cmap='gray')
plt.title('压缩后的图像 (k = 50)')

plt.show()

在上述代码中,通过SVD分解得到图像矩阵的三个分解矩阵,然后只保留前k个奇异值及其对应的左右奇异向量,重构近似矩阵,从而实现图像压缩。k值越小,压缩比越高,但图像质量也会相应下降。

数据分析中的主成分分析(PCA)

主成分分析(PCA)是一种常用的数据降维技术,其核心步骤涉及矩阵运算。假设我们有一个数据矩阵data_matrix,每一行是一个样本,每一列是一个特征。

import numpy as np

# 生成示例数据矩阵
data_matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 数据标准化
mean = np.mean(data_matrix, axis = 0)
std = np.std(data_matrix, axis = 0)
normalized_data = (data_matrix - mean) / std

# 计算协方差矩阵
cov_matrix = np.cov(normalized_data, rowvar = False)

# 计算协方差矩阵的特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)

# 按特征值降序排序
sorted_indices = np.argsort(eigenvalues)[::-1]
eigenvalues = eigenvalues[sorted_indices]
eigenvectors = eigenvectors[:, sorted_indices]

# 选择前k个主成分
k = 2
principal_components = eigenvectors[:, :k]

# 降维后的数据
reduced_data = normalized_data @ principal_components

print("降维后的数据:\n", reduced_data)

在PCA中,首先对数据进行标准化处理,然后计算协方差矩阵,通过求解协方差矩阵的特征值和特征向量,选择前k个最大特征值对应的特征向量作为主成分,将原始数据投影到这些主成分上,实现数据降维。

通过以上内容,我们详细介绍了NumPy中矩阵与线性代数运算的各个方面,从基础的矩阵操作到复杂的矩阵分解、线性方程组求解以及实际应用案例,展示了NumPy在数值计算中的强大功能。掌握这些知识,将有助于在科学计算、数据分析、机器学习等多个领域的开发和研究工作。