我用np.save()保存了几个numpy数组,并且放在一起它们非常庞大。
是否可以将它们全部作为内存映射文件加载,然后连接并切换所有这些文件而不将任何内容加载到内存中?
答案 0 :(得分:12)
使用numpy.concatenate
显然将数组加载到内存中。为避免这种情况,您可以在新文件中轻松创建第三个memmap
数组,并从要连接的数组中读取值。以更有效的方式,您还可以将新数组附加到磁盘上现有的文件中。
对于任何情况,您必须为数组选择正确的顺序(行主要或列主要)。
以下示例说明了如何沿轴0和轴1连接。
1)沿axis=0
a = np.memmap('a.array', dtype='float64', mode='w+', shape=( 5000,1000)) # 38.1MB
a[:,:] = 111
b = np.memmap('b.array', dtype='float64', mode='w+', shape=(15000,1000)) # 114 MB
b[:,:] = 222
您可以在模式a
(读取和追加)中定义与要连接的第一个数组(此处为r+
)读取相同文件的第三个数组,但是使用最终数组的形状想要在连接之后实现,比如:
c = np.memmap('a.array', dtype='float64', mode='r+', shape=(20000,1000), order='C')
c[5000:,:] = b
axis=0
连接不需要传递order='C'
,因为这已经是默认顺序。
2)沿axis=1
a = np.memmap('a.array', dtype='float64', mode='w+', shape=(5000,3000)) # 114 MB
a[:,:] = 111
b = np.memmap('b.array', dtype='float64', mode='w+', shape=(5000,1000)) # 38.1MB
b[:,:] = 222
保存在磁盘上的阵列实际上是扁平的,因此如果您使用c
和mode=r+
创建shape=(5000,4000)
而不更改数组顺序,则第二个1000
第一个元素a
中的行将转到c
中的第一行。但是,您可以轻松避免将order='F'
(列专业)传递给memmap
:
c = np.memmap('a.array', dtype='float64', mode='r+',shape=(5000,4000), order='F')
c[:, 3000:] = b
这里有一个带有连接结果的更新文件'a.array'。您可以重复此过程以成对的方式连接。
相关问题:
答案 1 :(得分:1)
也许是另一种解决方案,但我还有一个多维数组,分布在多个文件中,我只想读取。我用 dask concatenation 解决了这个问题。
import numpy as np
import dask.array as da
a = np.memmap('a.array', dtype='float64', mode='r', shape=( 5000,1000))
b = np.memmap('b.array', dtype='float64', mode='r', shape=(15000,1000))
c = da.concatenate([a, b], axis=0)
这种方式可以避免额外的文件句柄。然后可以像任何 numpy 数组一样对 dask 数组进行切片和处理,并且在需要计算结果时调用 compute
。
请注意,有两个警告:
c[::2] = 0
是不可能的,因此在这些情况下需要创造性的解决方案。store
方法。此方法可以再次接受 memmapped
数组。答案 2 :(得分:0)
如果您使用order='F'
,将导致另一个问题,当您下次加载文件时,即使通过order='F
,也将一团糟。所以我的解决方案在下面,我做了很多测试,一切正常。
fp = your old memmap...
shape = fp.shape
data = your ndarray...
data_shape = data.shape
concat_shape = data_shape[:-1] + (data_shape[-1] + shape[-1],)
print('cancat shape:{}'.format(concat_shape))
new_fp = np.memmap(new_file_name, dtype='float32', mode='r+', shape=concat_shape)
if len(concat_shape) == 1:
new_fp[:shape[0]] = fp[:]
new_fp[shape[0]:] = data[:]
if len(concat_shape) == 2:
new_fp[:, :shape[-1]] = fp[:]
new_fp[:, shape[-1]:] = data[:]
elif len(concat_shape) == 3:
new_fp[:, :, :shape[-1]] = fp[:]
new_fp[:, :, shape[-1]:] = data[:]
fp = new_fp
fp.flush()