【数学】线性代数(Python)

发布于:2025-04-09 ⋅ 阅读:(31) ⋅ 点赞:(0)

参考:https://aibydoing.com/notebooks/appendix01-01-linear-algebra-with-python

矩阵的定义

通过数组的维度来区分向量(1 维数组)、矩阵(2 维数组)和张量(高维数组)

# 使用import numpy as np导入NumPy库,并约定别名为np,方便后续调用。
import numpy as np

# 【创建多维数组】     将输入数据(如列表、元组等)转换为 NumPy 多维数组(ndarray)
# 【统一数据类型】     自动推断或强制统一数组元素的数据类型(dtype)。
# 【提升性能】        NumPy 数组在内存中是连续存储的,支持向量化操作,比 Python 原生列表运算快数十到数百倍。
# 【支持科学计算】     提供丰富的数学函数(如 sin, exp, dot)和线性代数操作(如矩阵乘法、求逆)
# 【内存优化】        通过指定 dtype 控制内存占用(如 int32、float16)。

a = np.array([1, 2])
b = np.array([[1, 2, 3], [4, 5, 6]])
c = np.array([b, b])

print("向量 a 的大小:", a.shape)
print("矩阵 b 的大小:", b.shape)
print("张量 c 的大小:", c.shape)

# 输出:
# 向量 a 的大小: (2,)
# 矩阵 b 的大小: (2, 3)
# 张量 c 的大小: (2, 2, 3)

矩阵的运算

# 矩阵的运算法则

# 使用import numpy as np导入NumPy库,并约定别名为np,方便后续调用。
import numpy as np

# 标量和矩阵之间的运算都可以表示为:该标量和矩阵中的每个元素都进行了一次运算。
a = np.array([[1, 2, 3], [4, 5, 6]])
print("a:\n", a)
print("a+2:\n", a+2)
print("a-2:\n", a-2)
print("a*2:\n", a*2)
print("a/2:\n", a/2)
print("==============")


# 条件:只有两个大小相等的矩阵才能加减,即当一个矩阵大小为 M*N 时,另一个矩阵的大小也必须为  M*N 。
# 运算方式:每个矩阵中对应位置的元素发生运算。
a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[1, 2, 3], [4, 5, 6]])
print("{}\n+\n{}\n=\n{}".format(a, b, a+b))
print("==============")
print("{}\n ÷ \n{}\n=\n{}".format(a, b, a/b))
print("==============")


# 【矩阵乘法】 A的列数等于B的行数
a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[1, 4], [2, 5], [3, 6]])
# a 乘以 b
c= a.dot(b)
# b 乘以 a
d = b.dot(a)
print("ab的大小为:", c.shape)
print("值为:\n", c)
print("===========")
print("ba的大小为:", d.shape)
print("值为:\n", d)
print("===========")


# 【Hadamard 的乘积】 表示对应元素之间的乘积
a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[1, 2, 1], [2, 2, 1]])
e = np.multiply(a, b)
print("ab Hadamard乘积的大小为:", e.shape)
print("值为:\n", e)
print("===========")


# 【广播机制】在两个大小不同的数组进行运算之前,将较小的数组的形状扩展成较大的数组形状,然后再进行运算。
a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[1, 2, 3]])
print("值为:\n", a+b)
print("===========")


# 【无法广播】 两个数组的尺寸在任何维度都不相同,且都不等于 1
# a_ = np.array([[1, 2, 3], [4, 5, 6]])
# b_ = np.array([[1, 2]])
# a_+b_

矩阵的属性

# 矩阵的性质

# 使用import numpy as np导入NumPy库,并约定别名为np,方便后续调用。
import numpy as np


# 将矩阵的行列互换得到的新矩阵称为转置矩阵
a= np.array([[1,2,3],[4,5,6]])
print("a:")
print(a)
print("a 的转置矩阵:")
print(a.T)
print("===========")


# 其主对角线元素为 1,其余元素为 0。
# 传入大小 n
b = np.identity(4)
print (b)
print("===========")


# 如果一个矩阵和 A 的乘积(传统乘积)为一个单位矩阵,那么这个矩阵就是 A 的逆矩阵
a = np.array([[1, 2], [3, 4]])
# 通过 np.linalg.inv() 求取逆矩阵
print(np.linalg.inv(a))
print("=================")
# 矩阵对象可以通过 ‘.I’ 属性,更方便的求逆
A = np.matrix(a)
print(A.I)
print("=================")


# 这种可逆的矩阵称之为非奇异矩阵,把那些不可逆的矩阵称之为奇异矩阵。
# 如果该矩阵为一个方阵且方阵的行列式不等于 0 ,则表示该矩阵可逆


# 行列式是方阵(即行数和列数相等的矩阵)才有的一种特征
a = np.array([[1, 2], [3, 4]])
b = np.array([[1, 2], [2, 4]])
print("a的行列式为", np.linalg.det(a))
print("b的行列式为", np.linalg.det(b))
print("=================")


# L2 范数,又称做欧几里得范数
print("按列向量计算 a 的范数", np.linalg.norm(a, axis=0))  # 按列向量计算范数
print("按行向量计算 a 的范数", np.linalg.norm(a, axis=1))  # 按行向量计算范数
print("计算矩阵 a 的范数", np.linalg.norm(a))  # 按列向量计算范数
print("=================")


# 矩阵的迹即为矩阵的对角元素(即对角线上的所有元素)之和
a = np.array([[1, 2], [3, 4]])
print("a_00:", a[0][0])
print("a_11:", a[1][1])
print("Tr(a):", np.trace(a))
print("=================")


# 对角矩阵:只在主对角线上含有非零元素,其他位置都为零的矩阵
# 函数传入的是对角线上的值
x = np.diag((1, 2, 3, 4))
print("x:", x)
print("np.diag(x):", np.diag(x))
print("=================")


# 对称矩阵: 如果矩阵 A 的转置和矩阵 A 相同,则矩阵 A 就是对称矩阵
# 随机初始化 25 个数,然后将这一组数转换为 5*5 的矩阵
x = np.random.randn(25).reshape(5, 5)
print("x:", x)
cov_up = np.triu(x)
print("cov_up:", cov_up)
cov_down = cov_up.T
print("cov_down:", cov_down)
cov_up_down = cov_up+cov_down
print("cov_up_down:", cov_up_down)
print("=================")


# 正交矩阵:正交矩阵的逆等于其转置

矩阵的分解

# 矩阵的分解

# 使用import numpy as np导入NumPy库,并约定别名为np,方便后续调用。
import numpy as np


# 【方阵】 特征分解:如果存在一个非零向量 v(称为特征向量)和一个标量 λ(称为特征值),使得以下等式成立:Av=λv
a = np.array([[1, 2, 3], [5, 8, 7], [1, 1, 1]])
e_vals, e_vecs = np.linalg.eig(a)
print("特征值为:", e_vals)
print("特征向量为:\n", e_vecs)
print("===========")


# 【任一矩阵】 奇异值分解 (SVD) 也是一种矩阵分解方法 A = UΣV^T
a = np.array([[1, 2, 3, 4], [5, 8, 6, 7], [1, 1, 1, 2]])
u, s, vh = np.linalg.svd(a)  # vh 表示 v 的转置
print(u.shape, s.shape, vh.shape)
print("===========")

矩阵的本质

乘法:是一种变换,是把一个向量,通过旋转,拉伸,变成另一个向量的过程
特征分解:向量在经过线性变换后的方向不变性(伸缩变换),找出那些方向(特征向量)在线性变换下只发生缩放变化(特征值)
奇异值分解(SVD):

遗留问题

特征分解与奇异值分解的区别
右奇异向量矩阵为什么要转置