如何使用sklearn的IncrementalPCA partial_fit

时间:2017-06-02 18:03:50

标签: python machine-learning scikit-learn pca

我有一个相当大的数据集,我想分解但是太大而无法加载到内存中。研究我的选择,似乎sklearn's IncrementalPCA是一个不错的选择,但我无法弄清楚如何使其发挥作用。

我可以很好地加载数据:

f = h5py.File('my_big_data.h5')
features = f['data']

this example开始,似乎我需要决定我想从中读取的块大小:

num_rows = data.shape[0]     # total number of rows in data
chunk_size = 10              # how many rows at a time to feed ipca

然后我可以创建我的IncrementalPCA,逐块地传输数据,并部分适合它(也来自上面的例子):

ipca = IncrementalPCA(n_components=2)
for i in range(0, num_rows//chunk_size):
    ipca.partial_fit(features[i*chunk_size : (i+1)*chunk_size])

这一切都没有错误,但我不知道下一步该做什么。我如何实际降低尺寸并获得一个新的numpy数组,我可以进一步操作并保存?

修改
上面的代码用于测试我的数据的一个较小的子集 - 正如@ImanolLuengo正确指出的那样,在最终代码中使用更大数量的维度和块大小会更好。

1 个答案:

答案 0 :(得分:2)

正如您所猜测的那样,拟合已正确完成,但我建议将chunk_size增加到100或1000(甚至更高,具体取决于数据的形状)。

现在要做的就是改变它,实际上是transform它:

out = my_new_features_dataset # shape N x 2
for i in range(0, num_rows//chunk_size):
    out[i*chunk_size:(i+1) * chunk_size] = ipca.transform(features[i*chunk_size : (i+1)*chunk_size])

那应该会给你新的转换功能。如果您仍有太多样本要适合内存,我建议您使用out作为另一个hdf5数据集。

另外,我认为将大型数据集减少为2个组件可能不是一个好主意。但如果不了解features的形状,很难说。我建议将它们缩减为sqrt(features.shape[1]),因为它是一个不错的启发式或专业提示:使用ipca.explained_variance_ratio_来确定最低的功能,以确保您负担得起的信息丢失阈值。

修改:对于explained_variance_ratio_,它会返回维度n_components的向量(您作为参数传递给IPCA的n_components),其中每个值 i 通过 i -th新组件解释原始数据的方差百分比。

您可以按照this answer中的步骤提取第一个 n 组件保留的信息量:

>>> print(ipca.explained_variance_ratio_.cumsum())
[ 0.32047581  0.59549787  0.80178824  0.932976    1.        ]

注意:假设您已将IPCA减少到5个组件,数字从上面的答案中获取。 i -th数表示第一个[0,i]分量解释了多少原始数据,因为它是解释的方差比的累积和。

因此,通常所做的是使您的PCA适合与原始数据相同数量的组件:

ipca = IncrementalPCA(n_components=features.shape[1])

然后,在对整个数据进行培训(迭代+ partial_fit)后,您可以绘制explaine_variance_ratio_.cumsum()并选择要丢失的数据量。或者自动执行:

k = np.argmax(ipca.explained_variance_ratio_.cumsum() > 0.9)

上面将返回cumcum数组中第一个索引值为> 0.9的索引,这表示保留至少90%原始数据的PCA组件数。

然后你可以调整转换以反映它:

cs = chunk_size
out = my_new_features_dataset # shape N x k
for i in range(0, num_rows//chunk_size):
    out[i*cs:(i+1)*cs] = ipca.transform(features[i*cs:(i+1)*cs])[:, :k]

注意切片到:k只选择第一个k组件而忽略其余组件。