大数据的增量 PCA
Posted
技术标签:
【中文标题】大数据的增量 PCA【英文标题】:Incremental PCA on big data 【发布时间】:2015-10-04 09:16:11 【问题描述】:我刚刚尝试使用 sklearn.decomposition 中的 IncrementalPCA,但它像之前的 PCA 和 RandomizedPCA 一样抛出了 MemoryError。我的问题是,我要加载的矩阵太大而无法放入 RAM。现在它作为形状数据集存储在 hdf5 数据库中 ~(1000000, 1000),所以我有 1.000.000.000 个 float32 值。我认为 IncrementalPCA 分批加载数据,但显然它试图加载整个数据集,这没有帮助。这个库是如何使用的? hdf5格式有问题吗?
from sklearn.decomposition import IncrementalPCA
import h5py
db = h5py.File("db.h5","r")
data = db["data"]
IncrementalPCA(n_components=10, batch_size=1).fit(data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/software/anaconda/2.3.0/lib/python2.7/site-packages/sklearn/decomposition/incremental_pca.py", line 165, in fit
X = check_array(X, dtype=np.float)
File "/software/anaconda/2.3.0/lib/python2.7/site-packages/sklearn/utils/validation.py", line 337, in check_array
array = np.atleast_2d(array)
File "/software/anaconda/2.3.0/lib/python2.7/site-packages/numpy/core/shape_base.py", line 99, in atleast_2d
ary = asanyarray(ary)
File "/software/anaconda/2.3.0/lib/python2.7/site-packages/numpy/core/numeric.py", line 514, in asanyarray
return array(a, dtype, copy=False, order=order, subok=True)
File "h5py/_objects.pyx", line 54, in h5py._objects.with_phil.wrapper (-------src-dir-------/h5py/_objects.c:2458)
File "h5py/_objects.pyx", line 55, in h5py._objects.with_phil.wrapper (-------src-dir-------/h5py/_objects.c:2415)
File "/software/anaconda/2.3.0/lib/python2.7/site-packages/h5py/_hl/dataset.py", line 640, in __array__
arr = numpy.empty(self.shape, dtype=self.dtype if dtype is None else dtype)
MemoryError
感谢您的帮助
【问题讨论】:
【参考方案1】:您的程序可能无法将整个数据集加载到 RAM 中。每个 float32 × 1,000,000 × 1000 的 32 位是 3.7 GiB。这在只有 4 GiB RAM 的机器上可能是个问题。要检查它是否确实是问题所在,请尝试单独创建一个此大小的数组:
>>> import numpy as np
>>> np.zeros((1000000, 1000), dtype=np.float32)
如果您看到MemoryError
,您要么需要更多 RAM,要么需要一次处理一个数据集。
对于 h5py 数据集,我们应该避免将整个数据集传递给我们的方法,而是传递数据集的切片。一次一个。
由于我没有你的数据,让我从创建一个相同大小的随机数据集开始:
import h5py
import numpy as np
h5 = h5py.File('rand-1Mx1K.h5', 'w')
h5.create_dataset('data', shape=(1000000,1000), dtype=np.float32)
for i in range(1000):
h5['data'][i*1000:(i+1)*1000] = np.random.rand(1000, 1000)
h5.close()
它创建了一个不错的 3.8 GiB 文件。
现在,如果我们在 Linux 中,我们可以限制程序可用的内存量:
$ bash
$ ulimit -m $((1024*1024*2))
$ ulimit -m
2097152
现在,如果我们尝试运行您的代码,我们将收到 MemoryError。 (按 Ctrl-D 退出新的 bash 会话并稍后重置限制)
让我们试着解决这个问题。我们将创建一个 IncrementalPCA 对象,并多次调用其.partial_fit()
方法,每次都提供不同的数据集切片。
import h5py
import numpy as np
from sklearn.decomposition import IncrementalPCA
h5 = h5py.File('rand-1Mx1K.h5', 'r')
data = h5['data'] # it's ok, the dataset is not fetched to memory yet
n = data.shape[0] # how many rows we have in the dataset
chunk_size = 1000 # how many rows we feed to IPCA at a time, the divisor of n
ipca = IncrementalPCA(n_components=10, batch_size=16)
for i in range(0, n//chunk_size):
ipca.partial_fit(data[i*chunk_size : (i+1)*chunk_size])
它似乎对我有用,如果我查看 top
报告的内容,内存分配保持在 200M 以下。
【讨论】:
好的,所以基本上我不应该调用 fit 而是调用 partial_fit 几次。我没有看到那个方法,因为本教程使用了 fit。如果 fit 一次加载整个数据集,你知道为什么 fit 有参数 batch_size 吗? h5py 库可能会处理不将所有数据加载到内存中的技巧。它的数据集对象 (h5['data']
) 似乎表现得像一个常规的 numpy 数组,但事实并非如此。 IncrementalPCA
不知道它是一个磁盘数据结构,并且在某些时候会读取所有行 (MemoryError
!)。计算依然在batch_size
分批执行。
这发生在fit()
中,calls check_array() 应该将数据转换为常规的 numpy 数组 (github.com/scikit-learn/scikit-learn/blob/0.16.1/sklearn/utils/…) 调用 partial_fit()
会绕过此转换。
@sastinin 我注意到解释的方差似乎在每次迭代中都会减少。这正常吗?我希望它遵循一条凸曲线并在某一点接近 100%。但我也不确定部分拟合是否需要批量大小和特征数量之间的某种关系。
@MehmedB 这个例子的重点不是找到解决方案,而是展示如何处理更小的数据块。根据您的数据集,您可能需要进行随机样本或进行更多迭代。在这种情况下,我们正在对白噪声数据进行 PCA。在足够大的数据集上,所有组件都应该相等。该 IPCA 不应该收敛(因此,解释方差会减少)。【参考方案2】:
可以使用 NumPy 的 memmap
类,它允许操作
存储在磁盘上的二进制文件中的大型数组,就好像它完全在内存中一样;该类仅在需要时将其需要的数据加载到内存中。由于incrementalPCA 在任何给定时间使用批处理,因此内存使用仍处于控制之中。这是一个示例代码
from sklearn.decomposition import IncrementalPCA
import numpy as np
X_mm = np.memmap(filename, dtype="float32", mode="readonly", shape=(m, n))
batch_size = m // n_batches
inc_pca = IncrementalPCA(n_components=10, batch_size=batch_size)
inc_pca.fit(X_mm)
【讨论】:
以上是关于大数据的增量 PCA的主要内容,如果未能解决你的问题,请参考以下文章