二维 PCA 线拟合与 numpy
2D PCA line fitting with numpy
我正在尝试使用 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 似乎不起作用。
情节如下:
恐怕我不知道出了什么问题。
- 我手动计算了协方差 -> 相同的结果。
- 我检查了另一个特征值 -> 垂直于红线。
- 我用方向 (1,10) 测试了 plot_line。它完全符合我的观点:
最后的图表明,pca 拟合的线是正确的结果,只是它在 y 轴上镜像。
事实上,如果我改变特征向量的 x 坐标,直线就完美拟合了:
显然这是一个基本问题。不知何故,我误解了如何使用 pca。
我的错误在哪里?
在线资源似乎完全按照我实施的方式描述了 PCA。
我不相信我必须在 y 轴上明确地反映我的线拟合。它必须是别的东西。
你的错误在于你提取了特征向量数组的最后 行。但是特征向量构成 np.linalg.eig
返回的特征向量数组的 列 ,而不是行。来自 documentation:
[...] the arrays a, w, and v satisfy the equations dot(a[:,:], v[:,i]) = w[i] * v[:,i]
[for each i
]
其中 a
是应用了 np.linalg.eig
的数组,w
是特征值的一维数组,而 v
是特征向量的二维数组。所以列 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]
你应该会得到预期的结果。
我正在尝试使用 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 似乎不起作用。 情节如下:
恐怕我不知道出了什么问题。
- 我手动计算了协方差 -> 相同的结果。
- 我检查了另一个特征值 -> 垂直于红线。
- 我用方向 (1,10) 测试了 plot_line。它完全符合我的观点:
最后的图表明,pca 拟合的线是正确的结果,只是它在 y 轴上镜像。
事实上,如果我改变特征向量的 x 坐标,直线就完美拟合了:
显然这是一个基本问题。不知何故,我误解了如何使用 pca。
我的错误在哪里? 在线资源似乎完全按照我实施的方式描述了 PCA。 我不相信我必须在 y 轴上明确地反映我的线拟合。它必须是别的东西。
你的错误在于你提取了特征向量数组的最后 行。但是特征向量构成 np.linalg.eig
返回的特征向量数组的 列 ,而不是行。来自 documentation:
[...] the arrays a, w, and v satisfy the equations
dot(a[:,:], v[:,i]) = w[i] * v[:,i]
[for eachi
]
其中 a
是应用了 np.linalg.eig
的数组,w
是特征值的一维数组,而 v
是特征向量的二维数组。所以列 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]
你应该会得到预期的结果。