2D PCA线条配合numpy

时间:2016-06-09 13:05:49

标签: python numpy math regression pca

我试图用numpy实现2D PCA。 代码很简单:

import numpy as np

n=10
d=10
x=np.linspace(0,10,n)
y=x*d

covmat = np.cov([x,y])
print(covmat)

eig_values, eig_vecs = np.linalg.eig(covmat)
largest_index = np.argmax(eig_values)
largest_eig_vec = eig_vecs[largest_index]

协方差矩阵是:

[[   11.31687243   113.16872428]
 [  113.16872428  1131.6872428 ]]

然后,我得到了一个简单的辅助方法,可以在给定方向上围绕给定中心绘制一条线(作为一系列点)。 这是由pyplot使用的,因此我正在为x和y坐标准备单独的列表。

def plot_line(center, dir, num_steps, step_size):
    line_x = []
    line_y = []
    for i in range(num_steps):
        dist_from_center = step_size * (i - num_steps / 2)
        point_on_line = center + dist_from_center * dir
        line_x.append(point_on_line[0])
        line_y.append(point_on_line[1])
    return (line_x, line_y)

最后是情节设置:

lines = []
mean_point=np.array([np.mean(x),np.mean(y)])
lines.append(plot_line(mean_point, largest_eig_vec, 200, 0.5))

import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

ax.scatter(x,y, c="b", marker=".", s=10
           )
for line in lines:
    ax.plot(line[0], line[1], c="r")

ax.scatter(mean_point[0], mean_point[1], c="y", marker="o", s=20)

plt.axes().set_aspect('equal', 'datalim')
plt.show()

不幸的是,PCA似乎不起作用。 这是情节:

pca line fitting

我害怕我不知道出了什么问题。

  • 我手动计算了协方差 - >同样的结果。
  • 我检查了另一个特征值 - >垂直于红线。
  • 我用方向(1,10)测试了plot_line。它与我的观点完全一致: perfectly aligned

最终的图显示pca拟合的线是正确的结果,只有它在y轴上镜像。

事实上,如果我改变了特征向量的x坐标,那么该线就完美拟合了:

perfect fit

显然这是一个根本问题。不知怎的,我误解了如何使用pca。

我的错误在哪里? 在线资源似乎完全像我实现它一样描述PCA。 我不相信我必须在y轴上明确地反映我的线条。它必须成为别的东西。

1 个答案:

答案 0 :(得分:5)

您的错误在于您正在提取特征向量数组的最后一个。但是,特征向量形成np.linalg.eig返回的特征向量数组的,而不是行。来自documentation

  

[...]数组a,w和v满足方程dot(a[:,:], v[:,i]) = w[i] * v[:,i] [对于每个i]

其中a是应用np.linalg.eig的数组,w是1d特征值数组,v是特征向量的2d数组。所以列v[:, i]是特征向量。

在这个简单的二维情况下,由于两个特征向量是相互正交的(因为我们以对称矩阵开始)和单位长度(因为np.linalg.eig将它们标准化),特征向量数组有两种形式之一

[[ cos(t)  sin(t)]
 [-sin(t)  cos(t)]]

[[ cos(t)  sin(t)]
 [ sin(t) -cos(t)]]

对于某个实数t,在第一种情况下,读取第一行(例如)而不是第一列会给[cos(t), sin(t)]代替[cos(t), -sin(t)]。这解释了您所看到的明显反映。

替换

largest_eig_vec = eig_vecs[largest_index]

largest_eig_vec = eig_vecs[:, largest_index]

你应该得到预期的结果。