为什么 PCA 结果会随着输入的微小变化而发生巨大变化?
Why does PCA result change drastically with a small change in the input?
我正在使用 PCA 将 Nx3 数组缩减为 Nx2 数组。这主要是因为 PCA 变换(Nx2 矩阵)对于在原始 Nx3 数组上执行的旋转或平移是不变的。下面以下面为例
import numpy as np
from sklearn.decomposition import PCA
a = np.array([[0.5 , 0.5 , 0.5 ],
[0.332, 0.456, 0.751],
[0.224, 0.349, 0.349],
[0.112, 0.314, 0.427]])
pca = PCA(n_components=2, svd_solver='full', random_state=10)
print(pca.fit_transform(a))
输出如下。请注意,由于平移不变性,我们得到相同的输出 print(pca.fit_transform(a-L))
,L
是任何数字。与旋转相同。
[[ 0.16752654 0.15593431]
[ 0.20568992 -0.14688601]
[-0.16899598 0.06364857]
[-0.20422047 -0.07269687]]
现在,我对数组 a
进行非常小的扰动 (~1%) 并执行 PCA。
a_p = np.array([[0.51 , 0.53 , 0.52 ],
[0.322, 0.452, 0.741],
[0.217, 0.342, 0.339],
[0.116, 0.31 , 0.417]])
pca = PCA(n_components=2, svd_solver='full', random_state=10)
print(pca.fit_transform(a_p))
结果如下。这和原来数组的PCA有很大的不同。
[[-0.2056024 , -0.14346977]
[-0.18563578 0.15627932]
[ 0.17974942 -0.07001969]
[ 0.21148876 0.05721014]]
我预计扰动数组的PCA变换与原始数组非常相似,但百分比变化很大。为什么是这样?有什么方法可以为稍微 perturbed/shaked 的数组获得非常相似的 PCA 转换?
我知道在第二种情况下(例如 pca.transform(a_p)
),我可以通过仅执行变换操作来获得类似的 PCA,但是,在这种情况下,我失去了旋转和平移不变性 w.r.t。 a_p
.
这个问题最初与晶体学有关,我的要求是 PCA(或其他)变换不应显着改变输入的微小变化,并且它应该对输入的旋转和变换保持不变.任何人都可以解释以上内容或建议我使用符合我目的的替代方法吗?
您得到的是符号偏移的向量作为主成分。
看下面的代码。我刚刚抓取了 2 个 PCA 实例作为 pca1
和 pca2
来访问它们的 components_
属性:
import numpy as np
from sklearn.decomposition import PCA
a = np.array([[0.5 , 0.5 , 0.5 ],
[0.332, 0.456, 0.751],
[0.224, 0.349, 0.349],
[0.112, 0.314, 0.427]])
pca1 = PCA(n_components=2, svd_solver='full', random_state=10)
print(pca1.fit_transform(a))
a_p = np.array([[0.51 , 0.53 , 0.52 ],
[0.322, 0.452, 0.741],
[0.217, 0.342, 0.339],
[0.116, 0.31 , 0.417]])
pca2 = PCA(n_components=2, svd_solver='full', random_state=10)
print(pca2.fit_transform(a_p))
pca1.components_
array([[ 0.64935364, 0.38718276, 0.65454515],
[ 0.63947417, 0.18783695, -0.74551329]])
pca2.components_
array([[-0.65743254, -0.42817638, -0.62003826],
[-0.59052329, -0.21834821, 0.77692104]])
如您所见,PC 指向相似的方向,但您的符号相反。
例如,pca1
的 PC1 是 [ 0.64935364, 0.38718276, 0.65454515]
而 pca2
的 PC1 是 [-0.65743254, -0.42817638, -0.62003826]
。忽略符号,每个坐标之间的差异都比较小……根据我的计算大约在2%、10%和5%。
这符合你“他们应该比较近”的直觉。
这里的关键见解是矢量 [-0.65743254, -0.42817638, -0.62003826]
和矢量 [0.65743254, 0.42817638, 0.62003826]
在 space 中位于同一条线上,但只是“指向”不同的方向。因此,对于 PCA 来说,两者都是同样有效的主成分。
我不知道有什么方法可以强制 sklearn
生成指向同一象限的向量。
这解释了点之间的大部分距离,这是一个“符号”距离。其余部分因您引入的差异而得到解释。
一个快速的解决方案可能是切换 a_p
.
的 PCA 转换结果的符号
“符号问题”的一个积极方面是实际上您可以切换嵌入值的符号而不会丢失信息。
所以你会做这样的事情:
t1 = pca1.fit_transform(a)
t2 = pca2.fit_transform(a_p)
t2 = -t2 # Change signs
t1
array([[ 0.16752654, 0.15593431],
[ 0.20568992, -0.14688601],
[-0.16899598, 0.06364857],
[-0.20422047, -0.07269687]])
t2
array([[ 0.2056024 , 0.14346977],
[ 0.18563578, -0.15627932],
[-0.17974942, 0.07001969],
[-0.21148876, -0.05721014]])
其中 t1
和 t2
与您最初的直觉大致相似 - 并且是正确的 - 建议。
我正在使用 PCA 将 Nx3 数组缩减为 Nx2 数组。这主要是因为 PCA 变换(Nx2 矩阵)对于在原始 Nx3 数组上执行的旋转或平移是不变的。下面以下面为例
import numpy as np
from sklearn.decomposition import PCA
a = np.array([[0.5 , 0.5 , 0.5 ],
[0.332, 0.456, 0.751],
[0.224, 0.349, 0.349],
[0.112, 0.314, 0.427]])
pca = PCA(n_components=2, svd_solver='full', random_state=10)
print(pca.fit_transform(a))
输出如下。请注意,由于平移不变性,我们得到相同的输出 print(pca.fit_transform(a-L))
,L
是任何数字。与旋转相同。
[[ 0.16752654 0.15593431]
[ 0.20568992 -0.14688601]
[-0.16899598 0.06364857]
[-0.20422047 -0.07269687]]
现在,我对数组 a
进行非常小的扰动 (~1%) 并执行 PCA。
a_p = np.array([[0.51 , 0.53 , 0.52 ],
[0.322, 0.452, 0.741],
[0.217, 0.342, 0.339],
[0.116, 0.31 , 0.417]])
pca = PCA(n_components=2, svd_solver='full', random_state=10)
print(pca.fit_transform(a_p))
结果如下。这和原来数组的PCA有很大的不同。
[[-0.2056024 , -0.14346977]
[-0.18563578 0.15627932]
[ 0.17974942 -0.07001969]
[ 0.21148876 0.05721014]]
我预计扰动数组的PCA变换与原始数组非常相似,但百分比变化很大。为什么是这样?有什么方法可以为稍微 perturbed/shaked 的数组获得非常相似的 PCA 转换?
我知道在第二种情况下(例如 pca.transform(a_p)
),我可以通过仅执行变换操作来获得类似的 PCA,但是,在这种情况下,我失去了旋转和平移不变性 w.r.t。 a_p
.
这个问题最初与晶体学有关,我的要求是 PCA(或其他)变换不应显着改变输入的微小变化,并且它应该对输入的旋转和变换保持不变.任何人都可以解释以上内容或建议我使用符合我目的的替代方法吗?
您得到的是符号偏移的向量作为主成分。
看下面的代码。我刚刚抓取了 2 个 PCA 实例作为 pca1
和 pca2
来访问它们的 components_
属性:
import numpy as np
from sklearn.decomposition import PCA
a = np.array([[0.5 , 0.5 , 0.5 ],
[0.332, 0.456, 0.751],
[0.224, 0.349, 0.349],
[0.112, 0.314, 0.427]])
pca1 = PCA(n_components=2, svd_solver='full', random_state=10)
print(pca1.fit_transform(a))
a_p = np.array([[0.51 , 0.53 , 0.52 ],
[0.322, 0.452, 0.741],
[0.217, 0.342, 0.339],
[0.116, 0.31 , 0.417]])
pca2 = PCA(n_components=2, svd_solver='full', random_state=10)
print(pca2.fit_transform(a_p))
pca1.components_
array([[ 0.64935364, 0.38718276, 0.65454515],
[ 0.63947417, 0.18783695, -0.74551329]])
pca2.components_
array([[-0.65743254, -0.42817638, -0.62003826],
[-0.59052329, -0.21834821, 0.77692104]])
如您所见,PC 指向相似的方向,但您的符号相反。
例如,pca1
的 PC1 是 [ 0.64935364, 0.38718276, 0.65454515]
而 pca2
的 PC1 是 [-0.65743254, -0.42817638, -0.62003826]
。忽略符号,每个坐标之间的差异都比较小……根据我的计算大约在2%、10%和5%。
这符合你“他们应该比较近”的直觉。
这里的关键见解是矢量 [-0.65743254, -0.42817638, -0.62003826]
和矢量 [0.65743254, 0.42817638, 0.62003826]
在 space 中位于同一条线上,但只是“指向”不同的方向。因此,对于 PCA 来说,两者都是同样有效的主成分。
我不知道有什么方法可以强制 sklearn
生成指向同一象限的向量。
这解释了点之间的大部分距离,这是一个“符号”距离。其余部分因您引入的差异而得到解释。
一个快速的解决方案可能是切换 a_p
.
“符号问题”的一个积极方面是实际上您可以切换嵌入值的符号而不会丢失信息。
所以你会做这样的事情:
t1 = pca1.fit_transform(a)
t2 = pca2.fit_transform(a_p)
t2 = -t2 # Change signs
t1
array([[ 0.16752654, 0.15593431],
[ 0.20568992, -0.14688601],
[-0.16899598, 0.06364857],
[-0.20422047, -0.07269687]])
t2
array([[ 0.2056024 , 0.14346977],
[ 0.18563578, -0.15627932],
[-0.17974942, 0.07001969],
[-0.21148876, -0.05721014]])
其中 t1
和 t2
与您最初的直觉大致相似 - 并且是正确的 - 建议。