Why does sklearn's PCA not return reproducible results?

时间:2018-10-30 15:07:12

标签: python scikit-learn pca

I am using scikit's PCA分配随机值,已经注意到一些非常奇怪的行为。本质上,当使用500个以上的样本时,结果是不可重现的。此示例显示了正在发生的事情:

import numpy as np
from sklearn.decomposition import PCA

Ncomp = 15
Nsamp = 501
Nfeat = 30

PCAnalyzer = PCA(n_components = Ncomp)
ManySamples = np.random.rand(Nsamp, Nfeat)
TestSample = np.ones((1, Nfeat))

print(PCAnalyzer.fit(ManySamples).transform(TestSample))
print(PCAnalyzer.fit(ManySamples).transform(TestSample))
print(PCAnalyzer.fit(ManySamples).transform(TestSample))
print(PCAnalyzer.fit(ManySamples).transform(TestSample))

它输出:

>>> print(PCAnalyzer.fit(ManySamples).transform(TestSample))
[[-0.25641111  0.42327221  0.4616427  -0.72047479 -0.12386481  0.10608497
   0.28739712 -0.26003239  1.27305465  1.05307604 -0.53915119 -0.07127874
   0.25312454 -0.12052255 -0.06738885]]
>>> print(PCAnalyzer.fit(ManySamples).transform(TestSample))
[[-0.26656397  0.42293446  0.45487161 -0.7339531  -0.16134778  0.15389179
   0.27052166 -0.33565591  1.26289845  0.96118269  0.5362569  -0.54688338
   0.08329318 -0.08423136 -0.00253318]]
>>> print(PCAnalyzer.fit(ManySamples).transform(TestSample))
[[-0.21899525  0.38527988  0.45101669 -0.73443888 -0.20501978  0.09640448
   0.17826649 -0.37653009  1.04856884  1.10948052  0.60700417 -0.39864793
   0.18020651  0.08061955  0.05383696]]
>>> print(PCAnalyzer.fit(ManySamples).transform(TestSample))
[[-0.27070256  0.41532602  0.45936926 -0.73820121 -0.18160026 -0.13139435
   0.28015907 -0.28144421  1.16554587  1.00472104  0.16983399 -0.67157762
  -0.3005816   0.54645421  0.09807374]]

将样本(Nsamp)的数量减少到500或更少,或将组件(Ncomp)的数量增加到20或更多,可以解决此问题-但这对我来说不切实际。

2 个答案:

答案 0 :(得分:2)

这是由于sklearn使用的默认求解器。来自docs

  

通过基于X.shape和n_components的默认策略选择求解器:如果输入数据大于500x500,并且要提取的组件数小于数据最小维度的80%,则该数量更多启用了有效的“随机化”方法。否则,将计算出精确的完整SVD,然后选择截断。

如果需要可重复的结果,请使用其他求解器,或设置random_state

答案 1 :(得分:0)

有时候,阅读文档会有所帮助:

  

它通过Halko等人的方法使用完整SVD或随机截短SVD的LAPACK实现。 2009,具体取决于输入数据的形状和要提取的组件数。

这解决了这个问题:

PCAnalyzer = PCA(n_components = Ncomp, svd_solver = 'full')