内存高效的方法将大型numpy数组分割为训练集和测试集。

16

我有一个很大的numpy数组,当我运行scikit-learn的train_test_split将数组拆分为训练和测试数据时,总是遇到内存错误。有什么更节省内存的方法来拆分训练和测试数据集,并且为什么train_test_split会导致这种情况?

以下代码会导致内存错误并崩溃。

import numpy as np
from sklearn.cross_validation import train_test_split

X = np.random.random((10000,70000))
Y = np.random.random((10000,))
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.33, random_state=42)

1
这可能会引起兴趣 - http://numpy-discussion.10968.n7.nabble.com/Huge-arrays-td25254.html - wwii
2
在我的64G机器上运行良好,在8G笔记本电脑上遇到了大问题(如果我没有终止它,可能会导致内存错误)。问题很可能是由于训练/测试拆分不可避免地会复制数据,因为它使用了高级索引,而在没有随机化的情况下,例如KFold,这可以避免(但您必须自己编写拆分代码,因为sklearn的KFold也会复制)。如果您需要随机化,可以考虑首先对数据进行就地洗牌。 - eickenberg
5个回答

10

我尝试过的一种方法是将X存储在Pandas数据帧中并进行混洗。

X = X.reindex(np.random.permutation(X.index))

当我尝试时,我遇到了相同的内存错误

np.random.shuffle(X)

然后,我将Pandas数据帧转换回NumPy数组,并使用此函数,可以获得训练测试拆分。

#test_proportion of 3 means 1/3 so 33% test and 67% train
def shuffle(matrix, target, test_proportion):
    ratio = int(matrix.shape[0]/test_proportion) #should be int
    X_train = matrix[ratio:,:]
    X_test =  matrix[:ratio,:]
    Y_train = target[ratio:,:]
    Y_test =  target[:ratio,:]
    return X_train, X_test, Y_train, Y_test

X_train, X_test, Y_train, Y_test = shuffle(X, Y, 3)

目前这个方法可以使用,当我想进行k折交叉验证时,我可以循环k次并打乱pandas dataframe的顺序。虽然目前这足够了,但为什么numpy和sci-kit learn的shuffle和train_test_split实现在处理大型数组时会导致内存错误?


6

使用sklearn的split方法减少内存使用的另一种方法是生成X的索引向量并在此向量上进行分割。之后,您可以选择条目并将训练和测试拆分写入磁盘。

import h5py
import numpy as np
from sklearn.cross_validation import train_test_split

X = np.random.random((10000,70000))
Y = np.random.random((10000,))

x_ids = list(range(len(X)))
x_train_ids, x_test_ids, Y_train, Y_test = train_test_split(x_ids, Y, test_size = 0.33, random_state=42)

# Write

f = h5py.File('dataset/train.h5py', 'w')
f.create_dataset(f"inputs", data=X[x_train_ids], dtype=np.int)
f.create_dataset(f"labels", data=Y_train, dtype=np.int)
f.close()

f = h5py.File('dataset/test.h5py', 'w')
f.create_dataset(f"inputs", data=X[x_test_ids], dtype=np.int)
f.create_dataset(f"labels", data=Y_test, dtype=np.int)
f.close()

# Read

f = h5py.File('dataset/train.h5py', 'r')
X_train = np.array(f.get('inputs'), dtype=np.int)
Y_train = np.array(f.get('labels'), dtype=np.int)
f.close()

f = h5py.File('dataset/test.h5py', 'r')
X_test = np.array(f.get('inputs'), dtype=np.int)
Y_test = np.array(f.get('labels'), dtype=np.int)
f.close()

1
如果您的模型可以从生成器中批量学习,那么这种方法也非常适合从sklearn获取拆分(这也适用于分层)。您可以创建一个指向文件的路径列表,而不是索引列表。在这种情况下,您就不需要进行写入和读取了。 - Austin
这个回答值得被采纳!不需要使用numpy的黑魔法。 - madprogramer

5

1

我在代码中遇到了同样的问题。我像你一样使用了密集数组,结果内存不足。我把我的训练数据转换成了稀疏数据(我正在进行文档分类),并解决了这个问题。


-1

我认为一种更“内存高效”的方法是迭代地选择用于训练和测试的实例(尽管,如计算机科学中通常的那样,您会牺牲使用矩阵固有的效率)。

您可以遍历数组,并针对每个实例,“掷硬币”(使用随机包)来确定是否将实例用作训练或测试,并根据情况将实例存储在适当的numpy数组中。

这种迭代方法对于仅有10000个实例并不会很差。但是,有趣的是,10000 X 70000并不算太大;您正在运行什么类型的机器?这让我想知道它是Python/numpy/scikit问题还是机器问题...

无论如何,希望这有所帮助!


1
一个由10,000 x 70,000个NumPy浮点数组成的数组,有700 MB的元素,每个元素占用8字节,因此这个数组使用了大约6 GB的内存。实际上,这是相当可观的。 - Eric O. Lebigot
我认为大小都是相对的 -- 在个人电脑的术语中,绝对是相当大的。在高性能计算的术语中,则不是那么重要。 - DMML
你们其中有人的问题中的代码片段有效吗? - user1879926
@user1879926 是的。在一台有48GB内存的机器上。这就是为什么我问你在运行什么样的机器。 - DMML
我的Macbook有16GB的内存和大约500GB的可用磁盘空间。 - user1879926

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接