web-dev-qa-db-fra.com

Vérification efficace et pythonique de la matrice singulière

Travailler sur une algèbre matricielle ici. Parfois, j'ai besoin d'inverser une matrice qui peut être singulière ou mal conditionnée. Je comprends que c'est pythonique de simplement faire ceci:

try:
    i = linalg.inv(x)
except LinAlgErr as err:
    #handle it

mais je ne suis pas sûr à quel point c'est efficace. Cela ne serait-il pas mieux?

if linalg.cond(x) < 1/sys.float_info.epsilon:
    i = linalg.inv(x)
else:
    #handle it

Numpy.Linalg est-il simplement effectué avant le test que je proscrit?

27
Dr. Drew

Donc basé sur les entrées ici, je marque mon bloc de code d'origine avec le test explicite comme solution:

if linalg.cond(x) < 1/sys.float_info.epsilon:
    i = linalg.inv(x)
else:
    #handle it

Étonnamment, la fonction numpy.linalg.inv n'effectue pas ce test. J'ai vérifié le code et je l'ai trouvé sur toutes ses machinations, puis appelle simplement la routine de lapack - semble assez inefficace. De plus, j'aurais 2ème point fait par Davep: que l'inverse d'une matrice ne doit pas être calculée à moins que cela ne soit explicitement nécessaire.

12
Dr. Drew

Votre première solution attrape le cas où votre matrice est si singulière que NUMPY ne peut pas faire face à tout - potentiellement un cas extrême. Votre deuxième solution est meilleure, car elle attrape le cas où NUMPY donne une réponse, mais cette réponse est potentiellement corrompue par une erreur d'arrondi - cela semble beaucoup plus raisonnable.

Si vous essayez d'inverser des matrices mal conditionnées, vous devriez envisager d'utiliser décomposition de valeur singulière . Si utilisé soigneusement, il peut vous donner une réponse raisonnable dans laquelle les autres routines échouent.

Si vous ne voulez pas SVD, voyez également mon commentaire sur l'utilisation de Lu_Factor au lieu d'INV.

15
DaveP

Vous devez calculer le numéro de condition de la matrice pour voir s'il est inversible.

import numpy.linalg

if numpy.isfinite(numpy.linalg.cond(A)):
    B = numpy.linalg.inv(A)
else:
    # handle it
4
Nicolas Barbey

Pourquoi ne pas simplement vérifier si le déterminant est non nul?

det = numpy.linalg.det(A)
if det != 0:
   #proceed
1