【问题标题】:Memory efficient way to split large numpy array into train and test将大型 numpy 数组拆分为训练和测试的内存有效方法
【发布时间】:2015-10-06 16:23:12
【问题描述】:

我有一个大型 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)

【问题讨论】:

  • 在 64G 机器上为我工作,在 8G 笔记本电脑上出现大问题(如果我没有杀死它可能会导致内存错误)。问题很可能是训练/测试拆分不可避免地会产生数据副本,因为它使用花哨的索引,而在没有随机化的情况下,例如KFold,这可以避免(但您必须自己编写拆分代码,因为 sklearn 的 KFold 也会复制)。如果您需要随机化,您可以考虑先对数据进行就地改组。

标签: python arrays scikit-learn


【解决方案1】:

另一种使用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()

【讨论】:

  • 如果您的模型可以从生成器中批量学习,则此方法也非常适合从 sklearn 中获取拆分(这也适用于分层)。除了索引列表,您还可以创建指向文件的路径列表。在这种情况下,你不需要写作和阅读。
  • 这应该是公认的答案!不需要 numpy 死灵术
【解决方案2】:

我尝试过的一种有效方法是将 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 数据帧进行洗牌。虽然现在这已经足够了,但为什么 numpy 和 sci-kit learn 的 shuffle 和 train_test_split 实现会导致大数组的内存错误?

【讨论】:

    【解决方案3】:

    我遇到了类似的问题。

    正如@user1879926 所述,我认为随机播放是内存耗尽的主要原因。

    并且,正如'Shuffle' is claimed to be an invalid parameter for model_selection.train_test_split 所引用的, train_test_split in sklearn 0.19 有禁用随机播放的选项。

    所以,我认为您可以通过添加 shuffle=False 选项来避免内存错误。

    【讨论】:

      【解决方案4】:

      我的代码也遇到了同样的问题。我正在使用像你这样的密集数组并且内存不足。我将我的训练数据转换为稀疏(我正在做文档分类)并解决了我的问题。

      【讨论】:

        【解决方案5】:

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

        您可以做的是遍历数组,并为每个实例“抛硬币”(使用 random 包)来确定您是将该实例用作训练还是测试,并根据哪个实例将实例存储在适当的 numpy 数组。

        这种迭代方法应该只适用于 10000 个实例。奇怪的是,10000 X 70000 并没有那么大。你在运行什么类型的机器?让我想知道这是 Python/numpy/scikit 问题还是机器问题...

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

        【讨论】:

        • 一个 10,000 x 70,000 NumPy 浮点数的数组有 700 MB 元素,其中每个元素占用 8 个字节,因此该数组使用大约 6 GB 内存。这实际上是相当大的。
        • 我认为大小都是相对的——在个人计算机方面,绝对是相当大的。 HPC 术语,没那么多。
        • 我的问题中的代码 sn-p 对你们中的任何人都有效吗?
        • @user1879926 是的。在具有 48Gb 内存的机器上。这就是为什么我要问你在运行什么机器。
        • 我的 Macbook 有 16gb 的 RAM 和大约 500gb 的可用磁盘空间。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-18
        • 2021-03-02
        • 2020-06-08
        • 2023-03-11
        • 1970-01-01
        相关资源
        最近更新 更多