我需要为很多不同的N (1到10000之间)的值计算Q ^ N,而Numpy有点太慢了。
我已经math.stackexchange.com问我是否可以避免为我的特定需求计算Q ^ N而且有人回答我使用P D^N P^-1
方法计算Q ^ N应该非常快。
基本上,而不是做:
import numpy as np
from numpy import linalg as LA
...
LA.matrix_power(m, N)
我试过了:
diag, P = LA.eig(m)
DN = np.diag(diag**N)
P1 = LA.inv(P)
P*DN*P1
我获得与结果相同的矩阵(试过一个例子)
在更复杂的矩阵上,问:
% timeit.Timer('Q**10000', setup=setup).repeat(2, 100)
[5.87254786491394, 5.863131046295166]
% timeit.Timer('diag, P = linalg.eig(Q); DN=np.diag(diag**10000);P1=linalg.inv(P); P*DN*P1', setup=setup).repeat(2, 100)
[2.0032401084899902, 2.018735885620117]
关于我最初的问题,第二种方法允许我只计算一次P, diag and P1
并使用数千次。使用这种方法的速度提高了8倍。
我的问题是:
修改
答案 0 :(得分:3)
您已经发现您的特征值为(0, a, b, c, ..., 1)
。让我重命名您的参数,以便特征值为(0, e1, e2, e3, ..., 1)
。要找出与特征值(v0, v1, v2, ..., v(n-1))
对应的特征向量ej
,您必须求解方程组:
v1 = v0*ej
v1*e1 + v2*(1-e1) = v1*ej
v2*e2 + v3*(1-e2) = v2*ej
...
vj*ej + v(j+1)*(1-ej) = vj*ej
...
v(n-1) = v(n-1)*ej
或许不太清楚,如果您的所有ei
都是不同的,并且没有一个等于0
或1
,那么解决方案总是很明确,并且在处理时ej
,得到的特征向量的第一个j
分量非零,其余的等于零。这保证了没有特征向量是其他特征向量的线性组合,因此特征向量矩阵是可逆的。
当您的ei
部分0
或1
或重复时,问题就出现了。我无法提供相关证据,但尝试使用以下代码时,您应该只担心ei
中的任何两个是否与1
相同且不同:< / p>
>>> def make_mat(values):
... n = len(values) + 2
... main_diag = np.concatenate(([0], values, [1]))
... up_diag = 1 - np.concatenate(([0], values))
... return np.diag(main_diag) + np.diag(up_diag, k=1)
>>> make_mat([4,5,6])
array([[ 0, 1, 0, 0, 0],
[ 0, 4, -3, 0, 0],
[ 0, 0, 5, -4, 0],
[ 0, 0, 0, 6, -5],
[ 0, 0, 0, 0, 1]])
>>> a, b = np.linalg.eig(make_mat([4,5,6]))
>>> a
array([ 0., 4., 5., 6., 1.])
>>> b
array([[ 1. , 0.24253563, -0.18641093, 0.13608276, 0.4472136 ],
[ 0. , 0.9701425 , -0.93205465, 0.81649658, 0.4472136 ],
[ 0. , 0. , 0.31068488, -0.54433105, 0.4472136 ],
[ 0. , 0. , 0. , 0.13608276, 0.4472136 ],
[ 0. , 0. , 0. , 0. , 0.4472136 ]])
现在有些测试用例:
>>> a, b = np.linalg.eig(make_mat([1,0,3])) # having a 0 or 1 is OK
>>> b
array([[ 1. , 0.70710678, 0. , 0. , 0. ],
[ 0. , 0.70710678, 0. , 0. , 0. ],
[ 0. , 0. , 1. , 0.31622777, 0.57735027],
[ 0. , 0. , 0. , 0.9486833 , 0.57735027],
[ 0. , 0. , 0. , 0. , 0.57735027]])
>>> a, b = np.linalg.eig(make_mat([1,1,3])) # repeating 1 is OK
>>> b
array([[ 1. , 0.70710678, 0. , 0. , 0. ],
[ 0. , 0.70710678, 0. , 0. , 0. ],
[ 0. , 0. , 1. , 0. , 0. ],
[ 0. , 0. , 0. , 1. , 0.70710678],
[ 0. , 0. , 0. , 0. , 0.70710678]])
>>> a, b = np.linalg.eig(make_mat([0,0,3])) # repeating 0 is not OK
>>> np.round(b, 3)
array([[ 1. , -1. , 1. , 0.035, 0.447],
[ 0. , 0. , 0. , 0.105, 0.447],
[ 0. , 0. , 0. , 0.314, 0.447],
[ 0. , 0. , 0. , 0.943, 0.447],
[ 0. , 0. , 0. , 0. , 0.447]])
>>> a, b = np.linalg.eig(make_mat([2,3,3])) # repeating other values are not OK
>>> np.round(b, 3)
array([[ 1. , 0.447, -0.229, -0.229, 0.447],
[ 0. , 0.894, -0.688, -0.688, 0.447],
[ 0. , 0. , 0.688, 0.688, 0.447],
[ 0. , 0. , 0. , 0. , 0.447],
[ 0. , 0. , 0. , 0. , 0.447]])
答案 1 :(得分:3)
我正在回答我的问题:
根据source code,我认为Numpy正在使用Squaring的Exponentiation:
# binary decomposition to reduce the number of Matrix
# multiplications for n > 3.
beta = binary_repr(n)
Z, q, t = M, 0, len(beta)
while beta[t-q-1] == '0':
Z = N.dot(Z, Z)
q += 1
result = Z
for k in range(q+1, t):
Z = N.dot(Z, Z)
if beta[t-k-1] == '1':
result = N.dot(result, Z)
return result
在我的情况下,当n
很大时,比计算特征值和特征向量并计算M ^ N等于P D ^ N P ^ -1更慢。
现在,关于我的问题:
在这种情况下,不可能使用最后一种方法来计算Q ^ N?
当某些特征值相等时,将无法反转P.有人建议在issue tracker的Numpy中进行。答案是:“您的方法仅适用于无缺陷的密集矩阵。”
在我的情况下使用它是否正常(这里给出的矩阵Q)?
并非总是如此,我可能有几个相等的特征值。
numpy中是否有一个已经完成的功能?
我认为它出现在SciPy中:https://github.com/scipy/scipy/blob/v0.12.0/scipy/linalg/matfuncs.py#L57
所以我们也可以这样做:
LA.expm(n*LA.logm(m))
计算m ^ n。
如何更改矩阵P使其变为可逆但是得到的矩阵不会改变?我的意思是,如果值接近真实结果就可以了,接近我的意思是〜0.0001。
我不能简单地添加epsilon值,因为当值太接近时,分解方法是合理的。我很确定这可能导致不可预测的错误。