【问题标题】:How to split large data and rejoin later如何拆分大数据并稍后重新加入
【发布时间】:2023-03-25 03:55:01
【问题描述】:

我的代码生成一个大小为 (1, 1, n, n, m, m) 的 numpy 数组列表,其中 n 可能在 50-100 之间变化,m 在 5-10 之间变化,具体取决于手头的情况。列表本身的长度可能高达 10,000,并且正在代码末尾使用 pickle 写入/转储。对于这些数字较高端的情况或文件大小超过 5-6 GB 的情况,我会收到 Out of Memory 错误。下面是一个虚构的例子,

import numpy as np
list, list_length = [], 1000
n = 100
m = 3
for i in range(0, list_length):
   list.append(np.random.random((1, 1, n, n, m, m)))

file_path = 'C:/Users/Desktop/Temp/'
with open(file_path, 'wb') as file:
    pickle.dump(list, file)

我正在寻找一种可以帮助我的方法

  • 拆分数据,这样我就可以摆脱内存错误,并且
  • 以后需要时以原始形式重新加入数据

我能想到的是:

for i in range(0, list_length):
   data = np.random.random((1, 1, n, n, m, m))
   file_path = 'C:/Users/Desktop/Temp/'+str(i)
   with open(file_path, 'wb') as file:
      pickle.dump(data, file)

然后结合使用:

combined_list = []
for i in range(0, list_length):
    file_path = 'C:/Users/Desktop/Temp/single' + str(i)
    with open(file_path, 'rb') as file:
        data = pickle.load(file)
    combined_list.append(data)

使用这种方式,文件大小肯定会因多个文件而减小,但也会因多个文件 I/O 操作而增加处理时间。

有没有更优雅更好的方法来做到这一点?

【问题讨论】:

    标签: python python-3.x numpy file-io split


    【解决方案1】:

    使用savezsavez_compressed,甚至h5py 之类的东西可能会像@tel 提到的那样有用,但是尝试“重新发明”缓存机制需要付出额外的努力。如果适用,有两种更简单的方法来处理大于内存的ndarray

    • 最简单的方法当然是在 Windows 上启用 pagefile(或其他名称)或在 Linux 上启用 swap(不确定 OS X 对应部分)。这会创建一个几乎足够大的内存,因此您根本不需要担心内存。它将相应地保存到磁盘/从磁盘加载

    • 如果第一种方式由于没有管理员权限等原因不适用,numpy提供另一种方式:np.memmap。此函数将ndarray 映射到磁盘,以便您可以像在内存中一样索引它。从技术上讲,IO 是直接对硬盘进行的,但操作系统会相应地缓存

    对于第二种方式,您可以使用以下命令创建硬盘端ndarray

    np.memmap('yourFileName', 'float32', 'w+', 0, 2**32)
    

    这会立即创建一个 16GB float32 数组(包含 4G 号码)。然后,您可以对其进行 IO。很多函数都有一个out 参数。您可以相应地设置out 参数,以便输出不会从内存“复制”到磁盘

    如果您想使用第二种方法保存ndarrays 的列表,请创建大量memmaps,或者将它们连接到单个数组中

    【讨论】:

    • 这对我来说是新事物。会尝试并回来。
    【解决方案2】:

    不要使用 pickle 来存储大数据,这不是序列化任何东西的有效方法。相反,请通过 numpy.savez_compressednumpy.load 函数使用内置的 numpy 序列化格式/函数。

    系统内存不是无限的,因此在某些时候您仍需要拆分文件(或使用更重的解决方案,例如 h5py 包提供的解决方案)。但是,如果您能够将原始列表放入内存中,那么 savez_compressedload 应该可以满足您的需求。

    【讨论】:

    • 我会试试这个解决方案。但是我可以用这种方法保存数组列表吗?文档提到它必须是数组。
    • 我刚刚尝试使用 np.savez_compressed。对于 n=50,m=3,list_length = 1000,计算需要多 7 倍的时间,这是一个低端情况。
    • 只需执行np.savez_compressed('filename', *l) 即可保存数组列表l。如果花费的时间太长,您可以使用 np.savez 函数在某种程度上权衡速度与磁盘大小。
    猜你喜欢
    • 2019-01-02
    • 2015-03-07
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多