python построение собственных векторов

Я думал, что собственные векторы должны быть ортогональны друг другу. Следующее, кажется, нарушает это. Я хотел проверить, не делаю ли я что-то не так. Спасибо за любое понимание!!!

Вот код для PCA (данные внизу поста)

from numpy import array
from numpy import mean
from numpy import cov
from numpy.linalg import eig


#calculate the mean of each column
M = mean(df.T, axis=1)

# center columns by subtracting column means
C = df - M

# calculate covariance matrix of centered matrix
V = cov(df.T)

# eigendecomposition of covariance matrix
values, vectors = eig(V)

# project data
P = vectors.T.dot(C.T)

#Make a list of (eigenvalue, eigenvector) tuples
eig_pairs = [(np.abs(values[i]), vectors[:,i]) for i in range(len(values))]

# Sort the (eigenvalue, eigenvector) tuples from high to low
eig_pairs.sort(key=lambda x: x[0], reverse=True)


matrix_w = np.hstack((eig_pairs[0][1].reshape(20,1), eig_pairs[1][1].reshape(20,1)))
#print('Matrix W:\n', matrix_w)

Все, что я сделал здесь, чтобы построить собственные векторы, это взял первые две строки matrix_w. Это правильно? Я просто вручную ввел их в массив M. Моя матрица_w неверна или это неправильный выбор вектора для первых двух главных компонент?

M =  np.array([[0.00747255,  0.16222854],[-0.18394907,  0.12426324]])
rows,cols = M.T.shape

#Get absolute maxes for axis ranges to center origin
maxes = 1.1*np.amax(abs(M), axis = 0)

for i,l in enumerate(range(0,cols)):
    xs = [0,M[i,0]]
    ys = [0,M[i,1]]
    plt.plot(xs,ys)

plt.plot(0,0,'ok') #<-- plot a black point at the origin
plt.axis('equal')  #<-- set the axes to the same scale

plt.legend(['V'+str(i+1) for i in range(cols)]) #<-- give a legend
plt.grid(b=True, which='major') #<-- plot grid lines
plt.show()```

Вот как выглядят нанесенные векторы, но они не ортогональны.

введите здесь описание изображения

Вот данные (уже нормализованные np.log):

[[1.954242509439325,
  1.6901960800285136,
  1.9444826721501687,
  1.2787536009528289,
  1.7558748556724915,
  1.7075701760979363,
  1.2787536009528289,
  1.3222192947339193,
  1.4313637641589874,
  1.3222192947339193,
  1.9084850188786497,
  1.8750612633917,
  1.6434526764861874,
  1.8512583487190752,
  1.3424226808222062,
  1.9590413923210936,
  1.9294189257142926,
  1.8692317197309762,
  1.4771212547196624,
  1.414973347970818],
 [1.9138138523837167,
  1.0,
  1.7781512503836436,
  0.3010299956639812,
  1.7403626894942439,
  1.6127838567197355,
  0.47712125471966244,
  0.3010299956639812,
  0.6020599913279624,
  0.3010299956639812,
  1.8260748027008264,
  1.8512583487190752,
  0.9542425094393249,
  1.662757831681574,
  1.9030899869919435,
  1.8195439355418688,
  1.380211241711606,
  1.9731278535996986,
  0.6989700043360189,
  1.255272505103306],
 [1.9444826721501687,
  1.6232492903979006,
  1.7993405494535817,
  0.6020599913279624,
  1.8808135922807914,
  1.724275869600789,
  1.0413926851582251,
  1.3617278360175928,
  1.0413926851582251,
  0.6989700043360189,
  1.9395192526186185,
  1.9242792860618816,
  1.6020599913279623,
  1.6532125137753437,
  1.9444826721501687,
  1.9731278535996986,
  1.6720978579357175,
  1.5563025007672873,
  1.7558748556724915,
  0.47712125471966244],
 [1.9822712330395684,
  1.792391689498254,
  1.9912260756924949,
  1.505149978319906,
  1.792391689498254,
  1.8260748027008264,
  1.6334684555795864,
  0.8450980400142568,
  1.146128035678238,
  1.146128035678238,
  1.919078092376074,
  1.9493900066449128,
  1.7853298350107671,
  1.9084850188786497,
  1.1760912590556813,
  1.4913616938342726,
  1.9867717342662448,
  1.1139433523068367,
  1.724275869600789,
  1.1760912590556813],
 [1.9731278535996986,
  1.5797835966168101,
  1.6812412373755872,
  1.0413926851582251,
  1.8692317197309762,
  1.568201724066995,
  1.3617278360175928,
  0.9542425094393249,
  1.1139433523068367,
  1.0791812460476249,
  1.8808135922807914,
  1.8808135922807914,
  1.6232492903979006,
  1.7558748556724915,
  1.462397997898956,
  1.9242792860618816,
  1.9030899869919435,
  1.919078092376074,
  1.3010299956639813,
  0.6989700043360189],
 [1.9867717342662448,
  1.7853298350107671,
  1.9344984512435677,
  1.4471580313422192,
  1.8976270912904414,
  1.863322860120456,
  1.0791812460476249,
  0.8450980400142568,
  1.414973347970818,
  1.3617278360175928,
  1.9294189257142926,
  1.9731278535996986,
  1.919078092376074,
  1.3010299956639813,
  1.9590413923210936,
  1.9731278535996986,
  1.9731278535996986,
  1.9242792860618816,
  1.4913616938342726,
  1.380211241711606],
 [1.4313637641589874,
  1.9344984512435677,
  1.99563519459755,
  1.3424226808222062,
  1.9590413923210936,
  1.7403626894942439,
  1.8808135922807914,
  1.2304489213782739,
  1.3010299956639813,
  1.380211241711606,
  1.8808135922807914,
  1.8325089127062364,
  1.9493900066449128,
  1.9590413923210936,
  1.0413926851582251,
  1.9777236052888478,
  1.9731278535996986,
  1.7558748556724915,
  1.0413926851582251,
  1.4471580313422192],
 [1.8573324964312685,
  1.414973347970818,
  1.8864907251724818,
  0.3010299956639812,
  1.3424226808222062,
  1.5314789170422551,
  0.0,
  0.6989700043360189,
  1.3010299956639813,
  0.47712125471966244,
  1.3424226808222062,
  1.7075701760979363,
  0.9030899869919435,
  1.2041199826559248,
  1.9493900066449128,
  1.8129133566428555,
  1.8920946026904804,
  1.9637878273455553,
  0.7781512503836436,
  0.9542425094393249],
 [1.7403626894942439,
  1.4913616938342726,
  1.7853298350107671,
  1.1760912590556813,
  1.462397997898956,
  1.5185139398778875,
  0.0,
  0.6989700043360189,
  1.1760912590556813,
  1.0413926851582251,
  1.6901960800285136,
  1.6232492903979006,
  1.146128035678238,
  1.6127838567197355,
  1.7075701760979363,
  1.7075701760979363,
  1.8573324964312685,
  1.4471580313422192,
  1.1139433523068367,
  1.0413926851582251],
 [1.863322860120456,
  1.8573324964312685,
  1.9294189257142926,
  1.3979400086720377,
  1.4913616938342726,
  1.8388490907372552,
  1.0,
  1.2304489213782739,
  1.2787536009528289,
  1.1760912590556813,
  1.8976270912904414,
  1.845098040014257,
  1.662757831681574,
  1.7853298350107671,
  1.806179973983887,
  1.9138138523837167,
  1.6812412373755872,
  1.7853298350107671,
  1.6812412373755872,
  1.4771212547196624],
 [1.9822712330395684,
  1.2304489213782739,
  1.9637878273455553,
  1.5440680443502757,
  1.8195439355418688,
  1.505149978319906,
  1.2304489213782739,
  1.0413926851582251,
  1.7075701760979363,
  1.6232492903979006,
  1.9084850188786497,
  1.8573324964312685,
  1.6989700043360187,
  1.806179973983887,
  1.0413926851582251,
  1.9637878273455553,
  1.9590413923210936,
  1.4771212547196624,
  1.0413926851582251,
  1.5314789170422551],
 [1.9637878273455553,
  1.2304489213782739,
  1.919078092376074,
  1.1139433523068367,
  1.792391689498254,
  1.7075701760979363,
  0.6020599913279624,
  1.2304489213782739,
  1.4771212547196624,
  1.1760912590556813,
  1.7853298350107671,
  1.8573324964312685,
  1.5314789170422551,
  1.7075701760979363,
  1.0413926851582251,
  1.7993405494535817,
  1.9731278535996986,
  1.4471580313422192,
  0.3010299956639812,
  1.792391689498254],
 [1.4771212547196624,
  1.7160033436347992,
  1.99563519459755,
  1.0413926851582251,
  1.9030899869919435,
  1.8750612633917,
  1.255272505103306,
  0.3010299956639812,
  0.6989700043360189,
  0.47712125471966244,
  1.7558748556724915,
  1.7160033436347992,
  1.662757831681574,
  1.9493900066449128,
  0.6989700043360189,
  1.9867717342662448,
  1.3979400086720377,
  1.4913616938342726,
  0.47712125471966244,
  0.9542425094393249]]

df = pd.DataFrame(data, columns=['Real coffee', 'Instant coffee', 'Tea', 'Sweetener', 'Biscuits',
       'Powder soup', 'Tin soup', 'Potatoes', 'Frozen fish', 'Frozen veggies',
       'Apples', 'Oranges', 'Tinned fruit', 'Jam', 'Garlic', 'Butter',
       'Margarine', 'Olive oil', 'Yoghurt', 'Crisp bread'])


person zelda1234    schedule 23.01.2020    source источник
comment
На собственные векторы не накладывается ограничение, говорящее, что они должны быть ортогональны. Собственные векторы корреляционной матрицы должны быть ортогональны. Трудно следить за вашей сортировкой, почему бы вам просто не проверить ортогональность всех пар vectors с помощью np.dot(vectors[:, col_i], vectors[:, col_j]). Если они ортогональны, то скалярное произведение должно быть равно 0 для всех i и j (кроме i==j).   -  person Dan    schedule 23.01.2020
comment
Попробуйте отсортировать что-то вроде этого: order = np.argsort(values), matrix_w = vectors[:, order]   -  person Dan    schedule 23.01.2020
comment
И какой формы был vectors? Если это не было 2 на 2, похоже, что вы обрезали векторы, поэтому, конечно, они больше не ортогональны, вы просто спроецировали их в 2D из (я полагаю) 20D   -  person Dan    schedule 23.01.2020
comment
@Dan форма векторов (20,20). я не понимаю, как проверить ортогональность с помощью np.dot - мне нужно сделать цикл? могу ли я сделать что-то вроде matrix_w.dot(matrix_w.T)   -  person zelda1234    schedule 23.01.2020
comment
Вы можете использовать петлю. В противном случае, я думаю, возможно, vectors @ vectors.T эффективно выполняет попарное скалярное произведение каждой пары (просто посмотрите на нижний треугольник). Ваша ортогональность находится в 20D, когда вы проецируете в 2D, нет причин оставаться ортогональными. Подумайте о том, что происходит, когда вы проецируете 3D-оси в 2D (как на каждой трехмерной диаграмме, которую вы когда-либо видели), ось z больше не ортогональна x или y. Это, по сути, то, что вы делаете.   -  person Dan    schedule 24.01.2020


Ответы (1)


Простая проверка ортогональности двух векторов состоит в том, чтобы увидеть, равно ли скалярное произведение нулю. В вашем случае ортогональные векторы должны быть столбцами vectors (т.е. собственными векторами ковариационной матрицы). Например, следующее должно выполняться без возникновения ошибки

n, m = vectors.shape
for col_i in range(m):
    for col_j in range(m):
        if col_i < col_j:  # use strictly less than because we don't want to consider a column with itself, and the dot product is commutable so order doesn't matter
            is_orthogonal = np.dot(vectors[:, col_i], vectors[:, col_j])
            if not np.isclose(is_orthogonal, 0):
                raise ValueError(f"Eigenvector {col_i} and Eigenvector {col_j} are not orthogonal.")

Более быстрый способ — помнить, что матричное произведение — это просто скалярное произведение строк первой матрицы со столбцами второй, т. е. vectors.T @ vectors. Затем мы хотим проверить, что нижний треугольник этого результата, за исключением диагонали (по тем же причинам, что и if col_i < col_j в цикле), равен нулю:

np.all(np.isclose(np.tril(vec.T @ vec, -1), 0))

Это должно вернуть True

Причина, по которой ваш график не выглядит ортогональным, заключается в том, что вы взяли два 20D-вектора и произвольно проецировали их на 2D. При этом нет гарантии, что они останутся ортогональными. В качестве примера рассмотрим распространенную диаграмму оси xyz:

введите здесь описание изображения

Вы знаете, что ось z ортогональна оси x, но если вы проецируете ее на 2D, то угол, который вы видите, зависит от угла проекции и больше не является ортогональным.

person Dan    schedule 24.01.2020