Analiza ważonych głównych składników

17

Po krótkich poszukiwaniach niewiele znajduję informacji na temat włączania wag obserwacyjnych / błędów pomiarowych do analizy głównych składników. To, co uważam, polega na iteracyjnych podejściach obejmujących wagi (np. Tutaj ). Moje pytanie brzmi: dlaczego to podejście jest konieczne? Dlaczego nie możemy użyć wektorów własnych ważonej macierzy kowariancji?

bez nazwy
źródło
1
Oprócz odpowiedzi poniżej, zobacz wątek stats.stackexchange.com/q/141754/3277 , w którym ważony PCA (z wagami na kolumnach i / lub wierszach) jest wyjaśniony jako przede wszystkim równoważny ważonemu (uogólnionemu) svd / dwupłat.
ttnphns

Odpowiedzi:

33

To zależy od tego, do czego dokładnie odnoszą się twoje wagi.

Ciężary rzędów

Niech będzie macierzą danych ze zmiennymi w kolumnach i n obserwacjami x i w rzędach. Jeśli każda obserwacja ma powiązaną masę wagowo I , to jest rzeczywiście prosta włączyć te ciężary do PCA.Xnxjawja

Najpierw należy obliczyć średnią ważoną odejmij je od danych, abyjewyśrodkować.μ=1wjawjaxja

Następnie obliczamy macierz ważonej kowariancji , gdzieW=diag(wi)to diagonalna macierz wag, i zastosuj standardowy PCA do jej analizy.1wjaXW.XW=diag(wi)

Masy komórek

W opracowaniu Tamuz i in., 2013 , które znalazłeś, rozważany jest bardziej skomplikowany przypadek, gdy do każdego elementu macierzy danych stosowane są różne wagi . Wtedy rzeczywiście nie ma rozwiązania analitycznego i trzeba zastosować metodę iteracyjną. Należy zauważyć, że, jak potwierdzili autorzy, wymyślili na nowo koło, ponieważ takie ogólne ciężary były z pewnością rozważane wcześniej, np. W Gabriel i Zamir, 1979, Przybliżenie macierzy niższego rzędu przez najmniejsze kwadraty z dowolnym wyborem wag . Zostało to również omówione tutaj .wij

Jako dodatkowa uwaga: jeśli wagi różnią się zarówno zmiennymi, jak i obserwacjami, ale są symetryczne, tak że w i j = w j i , wówczas możliwe jest rozwiązanie analityczne, patrz Koren i Carmel, 2004, Solidna liniowa redukcja wymiarów .wijwij=wji

ameba mówi Przywróć Monikę
źródło
Dziękuję za wyjaśnienie. Czy możesz wyjaśnić, dlaczego żadne rozwiązanie analityczne nie jest możliwe przy odważnikach o przekątnej? I tego mi brakuje zarówno w Tamuz et al 2013, jak i Gabriel i Zamir 1979.
noname
@noname: Nie znam takiego dowodu, a ponadto nie byłbym zaskoczony, gdyby nie był znany. Na ogół dość trudne jest udowodnienie, że coś jest niemożliwe , w szczególności, że coś nie jest możliwe analitycznie. Niemożliwość rozłamu kątów czekał na swój dowód ponad 2000 lat ... (cd.)
Amoeba mówi Przywróć Monikę
3
i,jwij(XijAij)2 with respect to A constrained to have low rank q. is not reducible to an eigenvector problem. I am afraid you would need another forum for that (maybe mathoverflow?). But note that finding eigenvectors is also not exactly an analytical solution: it's just that the iterations are usually silently performed by a standard library function.
amoeba says Reinstate Monica
2
+1. The first section of the answer can be conceptualized also in terms of Weighted (Generalized) Biplot as described here. Keeping in mind how PCA is a "specific case of" Biplot (also concerned in the lined answer).
ttnphns
@ttnphns: After your comment and another thread being closed as a duplicate, I re-read my answer and expanded the explanation of how to deal with row weights. I think previously it was not completely correct or at least was not complete because I did not mention the centering with a weighted mean. I hope it makes more sense now!
amoeba says Reinstate Monica
5

Dziękuję bardzo ameba za wgląd w wagi rzędów. Wiem, że to nie jest przepełnienie stosu, ale miałem pewne trudności ze znalezieniem implementacji PCA ważonego wierszem z wyjaśnieniem, a ponieważ jest to jeden z pierwszych wyników, kiedy korzystam z Google ważonego PCA, pomyślałem, że dobrze byłoby dołączyć moje rozwiązanie , może może pomóc innym w tej samej sytuacji. W tym fragmencie kodu Python2 do obliczenia stycznych zestawu danych 2D używana jest PCA ważona jądrem RBF takim jak ten opisany powyżej. Będę bardzo szczęśliwy, słysząc opinie!

def weighted_pca_regression(x_vec, y_vec, weights):
    """
    Given three real-valued vectors of same length, corresponding to the coordinates
    and weight of a 2-dimensional dataset, this function outputs the angle in radians
    of the line that aligns with the (weighted) average and main linear component of
    the data. For that, first a weighted mean and covariance matrix are computed.
    Then u,e,v=svd(cov) is performed, and u * f(x)=0 is solved.
    """
    input_mat = np.stack([x_vec, y_vec])
    weights_sum = weights.sum()
    # Subtract (weighted) mean and compute (weighted) covariance matrix:
    mean_x, mean_y =  weights.dot(x_vec)/weights_sum, weights.dot(y_vec)/weights_sum
    centered_x, centered_y = x_vec-mean_x, y_vec-mean_y
    matrix_centered = np.stack([centered_x, centered_y])
    weighted_cov = matrix_centered.dot(np.diag(weights).dot(matrix_centered.T)) / weights_sum
    # We know that v rotates the data's main component onto the y=0 axis, and
    # that u rotates it back. Solving u.dot([x,0])=[x*u[0,0], x*u[1,0]] gives
    # f(x)=(u[1,0]/u[0,0])x as the reconstructed function.
    u,e,v = np.linalg.svd(weighted_cov)
    return np.arctan2(u[1,0], u[0,0]) # arctan more stable than dividing


# USAGE EXAMPLE:
# Define the kernel and make an ellipse to perform regression on:
rbf = lambda vec, stddev: np.exp(-0.5*np.power(vec/stddev, 2))
x_span = np.linspace(0, 2*np.pi, 31)+0.1
data_x = np.cos(x_span)[:-1]*20-1000
data_y = np.sin(x_span)[:-1]*10+5000
data_xy = np.stack([data_x, data_y])
stddev = 1 # a stddev of 1 in this context is highly local
for center in data_xy.T:
    # weight the  points based on their euclidean distance to the current center
    euclidean_distances = np.linalg.norm(data_xy.T-center, axis=1)
    weights = rbf(euclidean_distances, stddev)
    # get the angle for the regression in radians
    p_grad = weighted_pca_regression(data_x, data_y, weights)
    # plot for illustration purposes
    line_x = np.linspace(-5,5,10)
    line_y = np.tan(p_grad)*line_x
    plt.plot(line_x+center[0], line_y+center[1], c="r")
    plt.scatter(*data_xy)
    plt.show()

I przykładowy wynik (robi to samo dla każdej kropki): enter image description here

Pozdrawiam,
Andres

fr_andres SupportsMonicaCellio
źródło