2015-01-05 8 views
15

Należy rozważyć dekompozycję osobliwą M = USV *. Następnie rozpad wartości własnej M * M daje M * M = V (S * S) V * = VS * U * USV *. Chciałbym zweryfikować tę równość z numpy pokazując, że wektory własne zwracane przez eigh funkcji są takie same jak te zwracane przez svd funkcji:Wektory własne obliczone za pomocą numpy's eigh i svd nie pasują do

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)) 

Ostatnie twierdzenie nie powiedzie się. Czemu?

+0

Możesz dodać liczba dodatnia do wszystkich elementów diagonalnych, tj. spraw, aby M2 = M + a * I, gdzie a jest wystarczająco duże, aby uzyskać dodatni semisfnit M2. Następnie SVD i eigh powinni się lepiej zgodzić. –

Odpowiedz

14

Po prostu graj małymi numerami, aby usunąć problem.

Zacznij A=np.random.randn(3,2) zamiast swojego znacznie większej matrycy o rozmiarze (50,20)

W moim losowego przypadku, uważam, że

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

i v2:

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

różnią się one jedynie do znak, i oczywiście, nawet jeśli znormalizowany by mieć moduł jednostki, wektor może się różnić dla znaku.

Teraz jeśli spróbujesz Sztuką

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

do oryginalnego wielkiej matrycy, to nie ... znowu, to jest OK. Co się dzieje, to, że niektóre wektory zostały pomnożone przez -1, inne nie.

Prawidłowe sposobem na sprawdzenie równości wektorów jest:

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

i rzeczywiście, aby uzyskać poczucie jak to was pracuje może wydrukować tę ilość:

(V1*V2).sum(0) 

że rzeczywiście jest albo +1 lub -1 zależności od wektora:

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

EDYCJA: Będzie to miało miejsce w większości przypadków, szczególnie jeśli rozpoczyna się od losowej macierzy. Zauważ jednak, że test ten będzie prawdopodobnie nie uda, jeśli jeden lub więcej wartości własnych ma eigenspace wymiaru większego niż 1, jak podkreślił @Sven Marnach w swoim komentarzu poniżej:

Mogą istnieć inne różnice nie tylko wektory pomnożone przez -1. Jeśli którakolwiek z wartości własnych ma wielowymiarowy eigenspace, można uzyskać dowolną podstawę ortonormalną tego eigenspace oraz Takie zasady mogą być obrócone względem siebie przez arbitraty unitarnego matrycy

+0

@matus OK, jestem zagubiony :) Ale ufam twojemu osądowi, więc usunę moje komentarze, aby nie mylić przyszłych czytelników. Twoje zdrowie! – BartoszKP

+0

Mogą istnieć inne różnice niż tylko wektory pomnożone przez -1.Jeśli którakolwiek z wartości własnych ma wielowymiarową przestrzeń własną, można uzyskać arbitralne ortonormalne podstawy tej przestrzeni własnej, a do takich baz można obrócić względem siebie o arbitralną unitarną matrycę. –

+0

@SvenMarnach, jest to bardzo ważny punkt. Będę edytować post, aby wskazać to zastrzeżenie – gg349

Powiązane problemy