如何让scipy.linalg.eig采用加权内积对特征向量进行归一化?
好问题!scipy.linalg.eig确实没有内置支持自定义加权内积归一化的选项,但我们有两种实用的方法来实现你想要的效果——让特征向量满足$\sum_i v_i^2 w_i = 1$(其中$w$是你的权重向量)。下面分别介绍:
方法1:手动重新归一化特征向量
这是最直接的思路:先用scipy.linalg.eig得到标准内积归一的特征向量,再根据你的权重向量重新调整每个向量的尺度。
原理
假设scipy.linalg.eig返回的特征向量矩阵为vecs(每一列对应一个特征向量),对于任意一列特征向量v,它当前满足$\sum_i v_i^2 = 1$。我们需要计算它的加权范数平方:
$$\text{weighted_norm_sq} = \sum_i v_i^2 w_i$$
然后用归一化因子$\frac{1}{\sqrt{\text{weighted_norm_sq}}}$乘以原向量,就能得到满足加权内积归一化的新向量。
代码示例
import numpy as np from scipy.linalg import eig # 示例矩阵和权重向量 A = np.array([[1, 2], [3, 4]]) w = np.array([0.5, 2.0]) # 自定义权重 # 求解标准特征值问题 vals, vecs = eig(A) # 对每个特征向量进行加权归一化 weighted_vecs = np.zeros_like(vecs) for i in range(vecs.shape[1]): v = vecs[:, i] weighted_norm = np.sqrt(np.sum(v**2 * w)) weighted_vecs[:, i] = v / weighted_norm # 验证:检查每个特征向量的加权范数是否为1 for i in range(weighted_vecs.shape[1]): print(f"特征向量{i}的加权范数平方:{np.sum(weighted_vecs[:,i]**2 * w):.6f}")
方法2:通过矩阵相似变换求解
如果不想事后调整特征向量,我们可以先对原矩阵做相似变换,将加权内积归一化的需求转化为标准特征值问题,直接求解得到符合要求的特征向量。
原理
我们的目标是求解$A\mathbf{v} = \lambda\mathbf{v}$,同时满足$\mathbf{v}^T W \mathbf{v} = 1$(其中$W$是对角矩阵,对角元素为权重$w_i$)。
令$\mathbf{v} = W{-1/2}\mathbf{u}$($W{-1/2}$是$W$的逆平方根矩阵,即对角元素为$1/\sqrt{w_i}$的对角矩阵),代入原方程可得:
$$A W^{-1/2}\mathbf{u} = \lambda W^{-1/2}\mathbf{u}$$
两边左乘$W^{1/2}$,得到:
$$W^{1/2} A W^{-1/2}\mathbf{u} = \lambda\mathbf{u}$$
此时求解这个变换后矩阵的特征值问题,得到的$\mathbf{u}$是标准内积归一的($\mathbf{u}T\mathbf{u}=1$),对应的$\mathbf{v}=W{-1/2}\mathbf{u}$自然满足$\mathbf{v}^T W \mathbf{v} = 1$,完全符合你的需求。而且相似变换不会改变特征值,所以得到的特征值和原问题一致。
代码示例
import numpy as np from scipy.linalg import eig # 示例矩阵和权重向量 A = np.array([[1, 2], [3, 4]]) w = np.array([0.5, 2.0]) # 构造权重的平方根和逆平方根对角矩阵 sqrt_W = np.diag(np.sqrt(w)) inv_sqrt_W = np.diag(1 / np.sqrt(w)) # 构造变换后的矩阵 A_transformed = sqrt_W @ A @ inv_sqrt_W # 求解变换后的特征值问题 vals, us = eig(A_transformed) # 转换为加权归一的特征向量 weighted_vecs = inv_sqrt_W @ us # 验证 for i in range(weighted_vecs.shape[1]): print(f"特征向量{i}的加权范数平方:{np.sum(weighted_vecs[:,i]**2 * w):.6f}")
两种方法的对比
- 方法1更简单直观,适合小矩阵或者只需要快速调整的场景;
- 方法2适合需要直接从求解过程得到目标向量的场景,避免事后循环处理,但需要额外的矩阵运算。
内容的提问来源于stack exchange,提问作者Rachel Garrick

