18

我用 np.save() 保存了几个 numpy 数组,它们放在一起非常大。

是否可以将它们全部加载为内存映射文件,然后在不将任何内容加载到内存的情况下将它们连接起来并切片?

4

3 回答 3

22

显然使用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

保存在磁盘上的数组实际上是展平的,因此,如果您在更改数组顺序和不更改数组顺序的情况下创建,则 in 中第二行的c第一个元素将转到in 中的第一个元素。但是您可以轻松避免这种传递(主要列)到:mode=r+shape=(5000,4000)1000acorder='F'memmap

c = np.memmap('a.array', dtype='float64', mode='r+',shape=(5000,4000), order='F')
c[:, 3000:] = b

在这里,您有一个带有连接结果的更新文件“a.array”。您可以重复此过程以成对连接两个。

相关问题:

于 2013-05-31T23:38:20.487 回答
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)

这样可以避免 hacky 的附加文件句柄。然后可以像任何 numpy 数组一样对 dask 数组进行切片和处理,并且在计算结果时调用compute.

请注意,有两个警告:

  1. 不可能进行就地重新分配,例如c[::2] = 0不可能,因此在这些情况下需要创造性的解决方案。
  2. 这也意味着无法再更新原始文件。要保存结果,store应使用 dask 方法。此方法可以再次接受一个memmapped数组。
于 2021-06-26T00:59:24.980 回答
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()
于 2018-11-28T11:49:45.070 回答