我有50000+个npz文件(文件大小为15MB),每个文件包含三个numpy数组A,B,C。
A是一个形状为numpy的数组(33000,); B是uint8
类型的小数形状(33000,),C是小数形状(33000,224,224)。
npz_file_dict = np.load(npz_file_path)
num_records = len(npz_file_dict['A'])
A = npz_file_dict['A']
B = npz_file_dict['B']
C = npz_file_dict['C']
def get_items(num_records):
for i in range(num_records)
yield A[i], B[i], C[i]
for a,b,c in get_items(num_records):
# do some work with (a,b,c)
# store the result in a json format with {'a' : a, 'b' : b, 'c' : c}
for循环需要很长时间才能完成(有时350,000条记录需要花费超过35分钟的时间)。有没有一种有效的方法来解析记录?
编辑:我尝试做内存映射的numpy数组,但是由于它们仅对npy文件有效,因此它似乎无法提高性能。
编辑:需要对我提出的方法进行批评。
我一直使用内存映射来加快迭代速度,对于读取的每个文件,我都会花费一些时间(在我称为设置阶段)将这个庞大的numpy数组映射到文件指针。
num_records = len(npz_file_dict['np_cids'])
print(num_records)
start_memmap = time()
data = npz_file_dict['C']
print('Time to read data {}'.format(time() - start_memmap))
filename = path.join(mkdtemp(), 'newfile.dat')
print('Path to file', filename)
fp = np.memmap(filename, dtype='float32', mode='w+', shape=(num_records, 224,224))
fp[:] = data[:]
finish_memmap = time()
print('Time to create memmap {}'.format(finish_memmap - start_memmap))
完成此设置后,我只需在for循环中遍历A和B数组,然后使用fp
来获取相应的i^th
记录。这种方法的优点是迭代速度非常快。缺点是建立时间介于单处理模式下的50秒和多处理模式下的100秒之间。
如果在30000条记录中摊销建立时间,则约为3.3毫秒。在迭代过程中,读取速度非常快-几百微秒。这样一来,每条记录所花费的总时间约为5毫秒。与我以前的方法(每条记录花费150ms)相比,这是96%的速度。
答案 0 :(得分:1)
我认为您可以使用以下代码清理代码:
npz_file_dict = np.load(npz_file_path)
A = npz_file_dict['A'] # (33000,) shape array
B = npz_file_dict['B']
C = npz_file_dict['C']
for a,b,c in zip(A,B,C):
# do some work with (a,b,c)
# store the result in a json format with {'a' : a, 'b' : b, 'c' : c}
这清楚表明您正在使用从文件加载的阵列。我不知道它是否会加快速度;这取决于npz
加载程序是否使用某种具有重复npz_file_dict['A]
访问权限的缓存。
但是,无论如何创建或加载它们,通过numpy数组进行迭代的速度都很慢-比在其上使用编译的“整个数组”操作要慢得多。列表上的迭代速度更快。实际上,这样做可能会有所帮助
for a,b,c in zip(A.tolist(), B.tolist(), list(C):
...
A.tolist()
是将数组转换为列表的快速方法。我不会在C
上使用它,因为它是3d,并且我假设您想将C[i,:,:]
用作数组,而不是嵌套列表。尽管由于您正在将c
写到json
,但您可能还是希望它是列表的列表。
===
在memmap
数组上进行迭代比在内存中数组上进行迭代要慢得多:
In [1]: C=np.ones((3000,224,224))
In [2]: np.savez('bigC.npz',C=C)
In [3]: fp = np.memmap('bigC.dat', dtype=C.dtype, mode='w+', shape=C.shape)
In [4]: fp[:] = C[:]
In [5]: %%timeit
...: for i in range(3000):
...: c = C[i]
...:
566 µs ± 2.55 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [7]: %%timeit
...: for i in range(3000):
...: c = fp[i]
...:
...:
9.74 ms ± 94.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
遍历npz
负载确实很慢-我的测试仍在运行:
In [8]: %%timeit d = np.load('bigC.npz')
...: for i in range(3000):
...: c = d['C'][i]
以一个初始负载进行测试:
In [243]: d = np.load('bigC.npz')
In [244]: %%timeit
...: D = d['C']
...: for i in range(3000):
...: c = D[i]
...:
2.17 s ± 27.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [245]: %%timeit
...: D = d['C']
...:
...:
2.14 s ± 6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
因此可以避免从npz
一次加载大型数组,但是您当然不希望为每一行重复加载它。如果数组太大而不能容纳在内存中,则将其转储到内存映射中可能会有所帮助,这并不是对内存数组的改进。