В случае, если ваша линейная система хорошо определена, я сохраню M
LU-разложение и буду использовать его для всех b
по отдельности или просто сделаю один вызов решения для 2d-массива B
, представляющего горизонтально расположенные b
, это действительно зависит от вашей проблемы, но это глобально та же идея. Предположим, у вас есть каждый b
по одному, затем:
import numpy as np
from scipy.linalg import lstsq, lu_factor, lu_solve, svd, pinv
# as you didn't specified any practical dimensions
n = 100
# number of b's
nb_b = 10
# generate random n-square matrix M
M = np.random.rand(n**2).reshape(n,n)
# Set of nb_b of right hand side vector b as columns
B = np.random.rand(n*nb_b).reshape(n,nb_b)
# compute pivoted LU decomposition of M
M_LU = lu_factor(M)
# then solve for each b
X_LU = np.asarray([lu_solve(M_LU,B[:,i]) for i in range(nb_b)])
, но если он недооценен или переопределен, вам нужно использовать lstsq , как вы это сделали :
X_lstsq = np.asarray([lstsq(M,B[:,i])[0] for i in range(nb_b)])
или просто сохранить псевдообратную M_pinv
с pinv (построена на lstsq) или pinv2 (построена на SVD):
# compute the pseudo-inverse of M
M_pinv = pinv(M)
X_pinv = np.asarray([np.dot(M_pinv,B[:,i]) for i in range(nb_b)])
или вы также можете выполнить работу самостоятельно, как, например, в pinv2
, просто сохраните SVD в M
и решите это вручную:
# compute svd of M
U,s,Vh = svd(M)
def solve_svd(U,s,Vh,b):
# U diag(s) Vh x = b <=> diag(s) Vh x = U.T b = c
c = np.dot(U.T,b)
# diag(s) Vh x = c <=> Vh x = diag(1/s) c = w (trivial inversion of a diagonal matrix)
w = np.dot(np.diag(1/s),c)
# Vh x = w <=> x = Vh.H w (where .H stands for hermitian = conjugate transpose)
x = np.dot(Vh.conj().T,w)
return x
X_svd = np.asarray([solve_svd(U,s,Vh,B[:,i]) for i in range(nb_b)])
, которые все дают тот же результат, если проверено с помощью np.allclose
(если система не является точно определенной, что приводит к отказу прямого подхода LU). Наконец, с точки зрения производительности:
%timeit M_LU = lu_factor(M); X_LU = np.asarray([lu_solve(M_LU,B[:,i]) for i in range(nb_b)])
1000 loops, best of 3: 1.01 ms per loop
%timeit X_lstsq = np.asarray([lstsq(M,B[:,i])[0] for i in range(nb_b)])
10 loops, best of 3: 47.8 ms per loop
%timeit M_pinv = pinv(M); X_pinv = np.asarray([np.dot(M_pinv,B[:,i]) for i in range(nb_b)])
100 loops, best of 3: 8.64 ms per loop
%timeit U,s,Vh = svd(M); X_svd = np.asarray([solve_svd(U,s,Vh,B[:,i]) for i in range(nb_b)])
100 loops, best of 3: 5.68 ms per loop
Тем не менее, вы должны проверить их с соответствующими размерами.
Надеюсь, это поможет.