6.13. Lineaarialgebra¶
Lineaarialgebra kameralla on pienten matriisien työtä: 3x3-rotaatio, joka yhdistää IMU-näytteen maailmankehykseen, kalibrointimatriisi, joka oikaisee linssin, Kalman-suotimen tila-kovarianssipäivitys, polynomisovitus, jonka normaaliyhtälöt tulevat ulos pikkuruisena lineaarisena ratkaisuna. numpy.linalg- ja scipy.linalg-alimoduulit kattavat juuri tuon mittakaavan.
Funktiot sijaitsevat kahdessa moduulissa. Matriisitulo-operaatiot ovat numpy:n ylätasolla; hajotelmat ja matriisin käänteismatriisi ovat numpy.linalg:n alla; varsinaiset lineaaristen järjestelmien ratkaisijat ovat scipy.linalg:n alla. Esimerkiksi 2x2-matriisikertolasku:
from ulab import numpy as np
A = np.array([[1, 2], [3, 4]], dtype=np.float)
B = np.array([[5, 6], [7, 8]], dtype=np.float)
np.dot(A, B)
# array([[19.0, 22.0],
# [43.0, 50.0]])
6.13.1. Mitä on saatavilla¶
dot()– matriisi- tai vektoritulo.cross()– 3-ulotteisten vektorien ristitulo.trace()– lävistäjän summa.inv()– matriisin käänteismatriisi.det()– determinantti.cholesky()– Choleskyn hajotelma (symmetrinen positiivisesti definiitti syöte).eig()– reaalisen symmetrisen matriisin ominaisarvot ja ominaisvektorit.norm()– vektorin tai matriisin 2-normi.qr()– QR-hajotelma vaihtoehdollamode='reduced'(oletus) taimode='complete'.solve_triangular()– ratkaiseA @ x = b, kunAon kolmiomatriisi.cho_solve()– ratkaiseA @ x = b, kun annetaanA:n Cholesky-tekijä.
6.13.2. dot, cross, trace¶
dot() on tapa, jolla matriisikertolasku kirjoitetaan kameralla. Operaattoria @, jonka työpöytä-numpy tarjoaa samaan tarkoitukseen, ei ole toteutettu ndarray-oliolle, joten jokainen matriisi-vektori-, matriisi-matriisi- ja vektoripistetulo kulkee dot()-kutsun kautta:
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
np.dot(a, b) # 32.0 (scalar product)
np.cross(a, b) # array([-3.0, 6.0, -3.0])
m = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
np.dot(m, a) # matrix-vector product
np.dot(m, m) # matrix-matrix product
np.trace(m) # 1 + 5 + 9 = 15.0
dot():n tulos on aina dtypeltään float. cross() on kahden 3-vektorin ristitulo, trace() neliömatriisin päälävistäjän summa.
6.13.3. inv ja det¶
m = np.array([[1, 2, 3, 4],
[4, 5, 6, 4],
[7, 9, 9, 4],
[3, 4, 5, 6]])
print(np.linalg.inv(m))
print(np.linalg.det(m))
Käänteismatriisi lasketaan Gauss-Jordan-eliminoinnilla, joten inv() nostaa poikkeuksen ValueError, kun matriisi on singulaarinen (jokin lävistäjän alkio menee nollaksi eliminoinnin aikana). RAM-kustannus on suunnilleen kaksi kertaa syötteen koko.
Determinantti käyttää uudelleen samaa eliminointia – ajoaika on käytännössä sama kuin käänteismatriisilla.
Kun sovelluksen tavoitteena on ratkaista lineaarinen järjestelmä, älä käännä ja kerro – suosi alla olevia varsinaisia ratkaisijoita. Molemmat ovat nopeampia ja numeerisesti paremmin käyttäytyviä.
6.13.4. cholesky¶
Symmetriselle positiivisesti definiitille matriisille A cholesky() palauttaa alakolmiomatriisin L siten, että A = L @ L.T
a = np.array([[25, 15, -5],
[15, 18, 0],
[-5, 0, 11]])
L = np.linalg.cholesky(a)
Jos syöte ei ole positiivisesti definiitti tai ei ole symmetrinen, nostetaan poikkeus ValueError.
Cholesky-tekijä on puolet LU-tekijöinnin työstä ja on oikea lähtökohta mihin tahansa ongelmaan, jonka matriisi tiedetään symmetriseksi positiivisesti definiitiksi (kovarianssipäivitykset, pienimmän neliösumman sovituksen normaaliyhtälöt).
6.13.5. eig¶
eig() toimii vain reaalisilla symmetrisillä matriiseilla. Epäsymmetriset matriisit nostavat poikkeuksen ValueError. Se palauttaa 2-monikon (eigenvalues, eigenvectors)
a = np.array([[1, 2, 1, 4],
[2, 5, 3, 5],
[1, 3, 6, 1],
[4, 5, 1, 7]], dtype=np.uint8)
x, y = np.linalg.eig(a)
Huomioita:
Ominaisarvot palautuvat ilman erityistä järjestystä. Käytä funktiota
sort()(ja samaa permutaatiota ominaisvektoreihin funktionargsort()kautta), kun lajiteltu järjestys on tärkeä.Ominaisvektori on yksikäsitteinen vain nollasta poikkeavaa skalaaria vaille, joten yksittäisten ominaisvektorien etumerkki ei ole yksikäsitteisesti määritelty. Kaksi oikeaa ajoa voivat tuottaa vastakkaismerkkisiä vektoreita; tämä on harmitonta.
6.13.6. norm¶
Vektorin tai matriisin euklidinen (Frobeniuksen) normi:
v = np.array([1, 2, 3, 4, 5])
m = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
np.linalg.norm(v) # 7.416...
np.linalg.norm(m) # 16.881...
Valinnainen avainsana axis= ottaa normin yksittäisen akselin suunnassa koko taulukon sijaan.
6.13.7. qr¶
qr() jakaa suorakulmaisen matriisin A (muoto (M, N)) ortonormaaliksi matriisiksi Q ja yläkolmiomatriisiksi R siten, että A == Q @ R
A = np.arange(6).reshape((3, 2))
q, r = np.linalg.qr(A)
# mode='reduced' (default): q is (3, 2), r is (2, 2)
q, r = np.linalg.qr(A, mode='complete')
# q is (3, 3), r is (3, 2)
Hajotelma on toteutettu peräkkäisillä Givensin rotaatioilla. Oikea valinta pienimmän neliösumman ongelmiin, joissa matriisi ei ole symmetrinen.
6.13.8. Järjestelmien ratkaiseminen¶
Kaksi varsinaista ratkaisijaa ulab.scipy.linalg:n alla ovat molemmat nopeampia ja tarkempia kuin np.dot(np.linalg.inv(A), b):
solve_triangular(a, b, lower=False)()– ratkaisea @ x = bolettaen, ettäaon kolmiomatriisi:A = np.array([[3, 0, 0, 0], [2, 1, 0, 0], [1, 0, 1, 0], [1, 2, 1, 8]]) b = np.array([4, 2, 4, 2]) x = sp.linalg.solve_triangular(A, b, lower=True)
cho_solve(L, b)()– annettuna Cholesky-tekijäL, ratkaiseA @ x = b, missäA = L @ L.TL = np.linalg.cholesky(A) x = sp.linalg.cho_solve(L, b)
Käytä näitä kääntämisen sijaan aina, kun A:n rakenne sen sallii – ne säästävät eliminointityön ja eksplisiittisen käänteismatriisin.
6.13.9. Pienen lineaarisen järjestelmän ratkaiseminen¶
A = np.array([[3, 0, 1, 1],
[0, 1, 0, 2],
[1, 0, 1, 1],
[1, 2, 1, 8]])
b = np.array([4, 2, 4, 2])
x = np.dot(np.linalg.inv(A), b)
print(x)
print(np.dot(A, x)) # should equal b
Sama ongelma voidaan ilmaista jakamalla A tekijöihin ja kutsumalla sopivaa ratkaisijaa – nopeampaa ja tarkempaa, kun A:lla on oikea rakenne.
Täydellisen argumenttitason viitteen löydät kohdista numpy.linalg — Lineaarialgebran rutiinit ja scipy.linalg — Lineaarialgebran rutiinit.