如何实现scipy.linalg.eigvals对单矩阵与批量矩阵的广播调用?
问题解决:scipy.linalg.eigvals批量处理广义特征值计算
错误原因
scipy.linalg.eigvals不支持自动识别批量矩阵(带前导额外维度的数组)。当传入形状为(3,2,2)的b时,函数无法将其解析为3个独立的2x2矩阵,而是将其视为非方阵的3D数组,因此抛出ValueError: expected square matrix错误。
可行方案
方案1:手动循环遍历批量矩阵
直接遍历b中的每个子矩阵,逐个计算与a的广义特征值,逻辑直观且性能稳定:
import scipy.linalg as la import numpy as np # 转换为numpy数组方便维度操作 a = np.array([[1, 2], [3, 4]]) b = np.array([[[5, 6], [7, 8]], [[9, 10], [11, 12]], [[13, 14], [15, 16]]]) eigvals = [] for b_i in b: vals = la.eigvals(a, b_i) eigvals.append(vals) # 转换为形状为(3,2)的numpy数组 eigvals = np.array(eigvals) print(eigvals)
方案2:使用numpy.apply_along_axis批量处理
利用numpy.apply_along_axis简化循环代码,沿着批量维度(axis=0)对每个子矩阵执行计算:
import scipy.linalg as la import numpy as np a = np.array([[1, 2], [3, 4]]) b = np.array([[[5, 6], [7, 8]], [[9, 10], [11, 12]], [[13, 14], [15, 16]]]) # 定义单个矩阵对的特征值计算函数 def calc_single_eig(b_i): return la.eigvals(a, b_i) # 沿着批量维度处理所有子矩阵,转置调整输出形状为(3,2) eigvals = np.apply_along_axis(calc_single_eig, axis=0, arr=b).T print(eigvals)
方案3:向量化包装(可选)
通过np.vectorize结合维度广播,实现更简洁的批量调用:
import scipy.linalg as la import numpy as np a = np.array([[1, 2], [3, 4]]) b = np.array([[[5, 6], [7, 8]], [[9, 10], [11, 12]], [[13, 14], [15, 16]]]) # 将a扩展为与b匹配的批量形状(3,2,2) a_broadcast = np.broadcast_to(a, b.shape) # 向量化eigvals函数,指定输入输出的矩阵/数组形状 vec_eig = np.vectorize(la.eigvals, signature='(n,n),(n,n)->(n)') eigvals = vec_eig(a_broadcast, b) print(eigvals)
补充说明
- 所有方案均需先将列表转换为numpy数组,便于维度操作和计算。
- 若处理超大规模批量数据(如上万矩阵),可考虑使用
jax.scipy.linalg.eigvals,它原生支持广播和GPU加速,但需额外安装JAX库。对于100个20x20矩阵的场景,上述前两种方案完全能满足需求。
内容的提问来源于stack exchange,提问作者Duckduckcode
相关产品推荐
相关产品推荐

