Python Scipy轴QR置换

Python Scipy轴QR置换,python,performance,scipy,Python,Performance,Scipy,我必须使用Scipy枢轴QR分解来解很多线性系统 Q、 R,perm=scipy.linalg.qrPW,pivoting=True,mode='full' 在求解系统时,我使用 使用下面的函数排列矩阵 def pvec2pmatvec: n=lenvec P=np.zerosn,n 计数器=0 对于0,n范围内的i: 对于0,n范围内的j: 如果j==vec[计数器]: P[i,j]=1.0 计数器=计数器+1 打破 返回P.T 不幸的是,这非常缓慢,代码花费大量时间生成这些矩阵。 是否可以加

我必须使用Scipy枢轴QR分解来解很多线性系统

Q、 R,perm=scipy.linalg.qrPW,pivoting=True,mode='full' 在求解系统时,我使用 使用下面的函数排列矩阵

def pvec2pmatvec: n=lenvec P=np.zerosn,n 计数器=0 对于0,n范围内的i: 对于0,n范围内的j: 如果j==vec[计数器]: P[i,j]=1.0 计数器=计数器+1 打破 返回P.T 不幸的是,这非常缓慢,代码花费大量时间生成这些矩阵。
是否可以加速此功能?

很难回答您的问题,因为我不知道您的代码应该做什么。此外,似乎与标题没有任何联系。如果你理解正确,你要求我优化给定的函数,甚至不知道输入是什么

我假设vec应该是一个一维整数数组。在这种情况下,第二个循环是完全不必要的。有两种情况:

vec[计数器]在0,n范围内 在本例中,您将P[i,vec[counter]]设置为1,并根据break语句增加计数器 vec[计数器]不在范围0,n中 计数器永远不会增加,因为if语句永远不会为真。因此,我们忽略vec的其余部分并返回矩阵。 因此,第一个简化是:

def pvec2pmat(vec):

   n = len(vec)
   P = np.zeros((n, n))
   counter = 0
   for i in range(0, n):
       if vec[counter] in range(0, n):
           P[i, vec[counter]] = 1.0
           counter += 1
       else:
           return P.T
   return P.T
因此,vec的相关部分直到第一次达到不在0,n范围内的值为止。我们可以在一开始就检查这一点,然后丢弃其余的

我们可以使用

invalid = (vec < 0) & (vec > 0)
try:
   first_invalid = np.flatnonzero(invalid)[0]
except IndexError:  # no invalid values
   pass
else:
   vec[:first_invalid]  # keep only till first invalid encounter
但是,也可以使用indixing:

P[np.arange(vec.size), vec] = 1
最后我们意识到,我们不需要转置,只需按相反的顺序分配它,就可以得到

def pvec2pmat(vec): 
    n = len(vec) 
    P = np.zeros((n, n))
    invalid = (vec < 0) & (vec > 0)
    try:
       first_invalid = np.flatnonzero(invalid)[0]
    except IndexError:  # no invalid values
       pass
    else:
       vec[:first_invalid]  # keep only till first invalid encounter
    P[vec, np.arange(vec.size)] = 1 
    return P
对于这个特定的示例,我的代码占用您版本的1/300时间。根据您的需要,如果选择P作为布尔矩阵,并且我们指定True,则可以实现另一个较大的加速比

def pvec2pmat(vec): 
    n = len(vec) 
    P = np.zeros((n, n))
    invalid = (vec < 0) & (vec > 0)
    try:
       first_invalid = np.flatnonzero(invalid)[0]
    except IndexError:  # no invalid values
       pass
    else:
       vec[:first_invalid]  # keep only till first invalid encounter
    P[vec, np.arange(vec.size)] = 1 
    return P
vec = np.arange(1000)
np.random.shuffle(vec)

# your version
128 ms ± 2.66 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

# my version
%timeit pvec2pmat(vec)
379 µs ± 22.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# for this simple example of a permutation, we can of course resort to
# siple indexing
%timeit np.eye(vec.size)[:, vec]
8.89 ms ± 13.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)