使用Scikit-learn时的Python MemoryError

Nyx*_*nyx 13 python numpy scipy python-2.7 scikit-learn

我在具有24GB内存的Windows 8 64位系统上运行Python 2.7(64位).在进行通常的拟合时Sklearn.linear_models.Ridge,代码运行正常.

问题:然而,当Sklearn.linear_models.RidgeCV(alphas=alphas)用于拟合时,我MemoryError在rr.fit(X_train, y_train)执行拟合程序的行上遇到下面显示的错误.

我该如何防止此错误?

代码段

def fit(X_train, y_train):
    alphas = [1e-3, 1e-2, 1e-1, 1e0, 1e1]

    rr = RidgeCV(alphas=alphas)
    rr.fit(X_train, y_train)

    return rr


rr = fit(X_train, y_train)
Run Code Online (Sandbox Code Playgroud)

错误

MemoryError                               Traceback (most recent call last)
<ipython-input-41-a433716e7179> in <module>()
      1 # Fit Training set
----> 2 rr = fit(X_train, y_train)

<ipython-input-35-9650bd58e76c> in fit(X_train, y_train)
      3 
      4     rr = RidgeCV(alphas=alphas)
----> 5     rr.fit(X_train, y_train)
      6 
      7     return rr

C:\Python27\lib\site-packages\sklearn\linear_model\ridge.pyc in fit(self, X, y, sample_weight)
    696                                   gcv_mode=self.gcv_mode,
    697                                   store_cv_values=self.store_cv_values)
--> 698             estimator.fit(X, y, sample_weight=sample_weight)
    699             self.alpha_ = estimator.alpha_
    700             if self.store_cv_values:

C:\Python27\lib\site-packages\sklearn\linear_model\ridge.pyc in fit(self, X, y, sample_weight)
    608             raise ValueError('bad gcv_mode "%s"' % gcv_mode)
    609 
--> 610         v, Q, QT_y = _pre_compute(X, y)
    611         n_y = 1 if len(y.shape) == 1 else y.shape[1]
    612         cv_values = np.zeros((n_samples * n_y, len(self.alphas)))

C:\Python27\lib\site-packages\sklearn\linear_model\ridge.pyc in _pre_compute_svd(self, X, y)
    531     def _pre_compute_svd(self, X, y):
    532         if sparse.issparse(X) and hasattr(X, 'toarray'):
--> 533             X = X.toarray()
    534         U, s, _ = np.linalg.svd(X, full_matrices=0)
    535         v = s ** 2

C:\Python27\lib\site-packages\scipy\sparse\compressed.pyc in toarray(self, order, out)
    559     def toarray(self, order=None, out=None):
    560         """See the docstring for `spmatrix.toarray`."""
--> 561         return self.tocoo(copy=False).toarray(order=order, out=out)
    562 
    563     ##############################################################

C:\Python27\lib\site-packages\scipy\sparse\coo.pyc in toarray(self, order, out)
    236     def toarray(self, order=None, out=None):
    237         """See the docstring for `spmatrix.toarray`."""
--> 238         B = self._process_toarray_args(order, out)
    239         fortran = int(B.flags.f_contiguous)
    240         if not fortran and not B.flags.c_contiguous:

C:\Python27\lib\site-packages\scipy\sparse\base.pyc in _process_toarray_args(self, order, out)
    633             return out
    634         else:
--> 635             return np.zeros(self.shape, dtype=self.dtype, order=order)
    636 
    637 

MemoryError: 
Run Code Online (Sandbox Code Playgroud)

码

print type(X_train)
print X_train.shape
Run Code Online (Sandbox Code Playgroud)

结果

<class 'scipy.sparse.csr.csr_matrix'>
(183576, 101507)
Run Code Online (Sandbox Code Playgroud)

kwa*_*ord 19

看一下堆栈跟踪的这一部分:

    531     def _pre_compute_svd(self, X, y):
    532         if sparse.issparse(X) and hasattr(X, 'toarray'):
--> 533             X = X.toarray()
    534         U, s, _ = np.linalg.svd(X, full_matrices=0)
    535         v = s ** 2
Run Code Online (Sandbox Code Playgroud)

您正在使用的算法依赖于numpy的线性代数例程来执行SVD.但那些无法处理稀疏矩阵,因此作者只需将它们转换为常规的非稀疏数组.为此必须要做的第一件事是分配一个全零数组,然后用稀疏矩阵中稀疏存储的值填充适当的点.听起来很容易,但让我们算一算.float64(默认dtype,如果你不知道你正在使用的那个,你可能正在使用)元素需要8个字节.因此,根据您提供的数组形状,新的零填充数组将是:

183576 * 101507 * 8 = 149,073,992,256 ~= 150 gigabytes
Run Code Online (Sandbox Code Playgroud)

您系统的内存管理器可能只看了一眼分配请求并自杀了.但你能做些什么呢?

首先,这看起来像一个相当荒谬的功能.我对你的问题领域或你的功能都不了解,但我的直觉反应是你需要在这里做一些降维.

其次,您可以尝试修复算法对稀疏矩阵的错误处理.它在numpy.linalg.svd这里窒息,所以你可能可以使用它scipy.sparse.linalg.svds.我不知道有问题的算法,但它可能不适合稀疏矩阵.即使您使用适当的稀疏线性代数例程,它也可能产生(或内部使用)一些大小与您的数据相似的非稀疏矩阵.使用稀疏矩阵表示来表示非稀疏数据只会导致使用比原来更多的空间,因此这种方法可能不起作用.谨慎行事.

  • +1,虽然我不同意100k是一个"荒谬"的功能.对于OP似乎正在处理的文档处理任务(给出其他帖子),它实际上相当低. (3认同)

Mat*_*ieu 6

这里的相关选项是gcv_mode.它可以采用3个值:"auto","svd"和"eigen".默认情况下,它设置为"auto",具有以下行为:如果n_samples> n_features,则使用svd模式,否则使用本征模式.

因为在您的情况下n_samples> n_features,所以选择了svd模式.但是,svd模式当前不能正确处理稀疏数据.应该修复scikit-learn以使用适当的稀疏SVD而不是密集的SVD.

作为一种解决方法,我会通过gcv_mode ="eigen"强制本征模式,因为这种模式应该正确处理稀疏数据.但是,在您的情况下,n_samples非常大.由于本征模式构建了核矩阵(因此具有n_samples**2内存复杂度),因此内核矩阵可能不适合存储器.在这种情况下,我只会减少样本数量(特征模式可以毫无问题地处理非常多的特征).

在任何情况下,由于N_SAMPLES次和n_features是相当大的,你是推这个实现其限制(即使有合适的稀疏SVD).

另请参阅https://github.com/scikit-learn/scikit-learn/issues/1921