2015-01-05 9 views
15

Betrachten Sie die Singulärwertzerlegung M = USV *. Dann ergibt die Eigenwertzerlegung von M * M M * M = V (S * S) V * = VS * U * USV *. Ich möchte diese Gleichheit mit numpy überprüfen, indem Sie zeigen, dass die Eigenvektoren von eigh Funktion sind die gleichen wie die von svd Funktion zurückgegeben zurückgegeben:Eigenvektoren, die mit nepy's eigh und svd berechnet wurden, stimmen nicht überein

import numpy as np 
np.random.seed(42) 
# create mean centered data 
A=np.random.randn(50,20) 
M= A-np.array(A.mean(0),ndmin=2) 

# svd 
U1,S1,V1=np.linalg.svd(M) 
S1=np.square(S1) 
V1=V1.T 

# eig 
S2,V2=np.linalg.eigh(np.dot(M.T,M)) 
indx=np.argsort(S2)[::-1] 
S2=S2[indx] 
V2=V2[:,indx] 

# both Vs are in orthonormal form 
assert np.all(np.isclose(np.linalg.norm(V1,axis=1), np.ones(V1.shape[0]))) 
assert np.all(np.isclose(np.linalg.norm(V1,axis=0), np.ones(V1.shape[1]))) 
assert np.all(np.isclose(np.linalg.norm(V2,axis=1), np.ones(V2.shape[0]))) 
assert np.all(np.isclose(np.linalg.norm(V2,axis=0), np.ones(V2.shape[1]))) 

assert np.all(np.isclose(S1,S2)) 
assert np.all(np.isclose(V1,V2)) 

Die letzte Behauptung fehlschlägt. Warum?

+0

Sie können hinzufügen eine positive Zahl für alle diagonalen Elemente, dh M2 = M + a * I, wobei a groß genug ist, um M2 positiv semidefnit zu machen. Dann sollten SVD und Eigh besser zustimmen. –

Antwort

14

Spielen Sie einfach mit kleinen Zahlen, um Ihr Problem zu debuggen.

beginnen mit A=np.random.randn(3,2) statt Ihrer viel größere Matrix mit der Größe (50,20)

In meinem zufälligen Fall finde ich, dass

v1 = array([[-0.33872745, 0.94088454], 
    [-0.94088454, -0.33872745]]) 

und für v2:

v2 = array([[ 0.33872745, -0.94088454], 
    [ 0.94088454, 0.33872745]]) 

sie nur für sich unterscheiden ein Zeichen, und offensichtlich, selbst wenn normalisiert, um Einheitsmodul zu haben, kann sich der Vektor für ein Zeichen unterscheiden.

Nun, wenn Sie versuchen, den Trick

assert np.all(np.isclose(V1,-1*V2)) 

für Ihre ursprüngliche große Matrix, es nicht ... wieder, das ist OK. Was passiert ist, dass einige Vektoren mit -1 multipliziert wurden, andere nicht.

Eine korrekte Art und Weise für die Gleichstellung zwischen den Vektoren zu überprüfen ist:

assert allclose(abs((V1*V2).sum(0)),1.) 

und in der Tat, ein Gefühl dafür zu bekommen, wie das funktioniert Sie diese Menge drucken:

(V1*V2).sum(0) 

, dass ist in der Tat entweder +1-1 oder in Abhängigkeit von dem Vektor:

array([ 1., -1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 
    1., -1., 1., 1., 1., -1., -1.]) 

EDIT: Dies wird in den meisten Fällen passieren, besonders wenn von einer zufälligen Matrix ausgehend. Beachten Sie jedoch, dass dieser Test wird wahrscheinlich fehlschlagen, wenn ein oder mehrere Eigenwerte einen Eigenraum der Dimension größer als 1, wie unten durch @Sven Marnach in seinem Kommentar darauf hingewiesen:

Es könnte auch andere Unterschiede als nur multipliziert Vektoren -1. Wenn eine der Eigenwerte ein multidimensionales Eigenraum hat, Sie könnte eine beliebige Orthonormalbasis dieser Eigenraum erhalten und zu solche Basen könnten gegeneinander durch eine arbitraty unitarisch

Matrix gedreht werden
+0

@matus OK, ich bin verloren :) Aber ich vertraue auf Ihr Urteil, und so werde ich meine Kommentare entfernen, um zukünftige Leser nicht zu verwirren. Prost! – BartoszKP

+0

Es kann andere Unterschiede geben als nur Vektoren multipliziert mit -1.Wenn einer der Eigenwerte einen mehrdimensionalen Eigenraum hat, könnten Sie eine willkürliche orthonormale Basis dieses Eigenraums erhalten, und solche Basen könnten gegeneinander durch eine arbitraty unitäre Matrix gedreht werden. –

+0

@SvenMarnach, das ist ein sehr gültiger Punkt. Ich werde den Beitrag bearbeiten, um auf diesen Vorbehalt hinzuweisen – gg349

Verwandte Themen