Skip to main content
 首页 » 编程设计

python之如果切片不能解决内存错误,如何合并两个大的 numpy 数组

2025年05月04日33JustinYoung

我有两个 numpy 数组 container1 和 container2 其中 container1.shape = (900,4000) 和 container2.shape = (5000,4000)。使用 vstack 合并它们会导致 MemoryError。搜索这里发布的旧问题后,我尝试使用 slicing 像这样合并它们:

mergedContainer = numpy.vstack((container1, container2[:1000])) 
mergedContainer = numpy.vstack((mergedContainer, container[1000:2500])) 
mergedContainer = numpy.vstack((mergedContainer, container[2500:3000])) 

但在此之后即使我这样做了:

mergedContainer = numpy.vstack((mergedContainer, container[3000:3100])) 

它会导致 MemoryError。

我正在使用 Python 3.4.3(32 位) 并希望在不切换到 64 位 的情况下解决问题。

请您参考如下方法:

每次调用 np.vstack 时,NumPy 都必须为全新的数组分配空间。 所以如果我们说 1 行需要 1 个内存单元

np.vstack([container, container2]) 

需要额外的 900+5000 内存单元。此外,在分配发生之前, Python 也需要为旧的 mergedContainer(如果它存在)保留空间 作为新 mergedContainer 的空间。所以构建 mergedContainer 与切片迭代实际上需要比尝试构建它更多的内存 只需调用一次 np.vstack。

迭代构建它:

| total | mergedContainer | container1 | container2 | temp |                                                                      | 
|-------+-----------------+------------+------------+------+----------------------------------------------------------------------| 
|  7800 |            1900 |        900 |       5000 |    0 | mergedContainer = np.vstack((container1, container2[:1000]))         | 
| 11200 |            3400 |        900 |       5000 | 1900 | mergedContainer = np.vstack((mergedContainer, container[1000:2500])) | 
| 13200 |            3900 |        900 |       5000 | 3400 | mergedContainer = np.vstack((mergedContainer, container[2500:3000])) | 

通过一次调用 np.vstack 构建它:

| total | mergedContainer | container1 | container2 | temp |                                                       | 
|-------+-----------------+------------+------------+------+-------------------------------------------------------| 
| 11800 |            5900 |        900 |       5000 |    0 | mergedContainer = np.vstack((container1, container2)) | 

但是,我们可以做得更好。而不是调用 np.vstack 重复,分配所有需要的空间一次 最开始并写入container1和 container2 放入其中。换句话说,避免分配两个不同的数组 container1 和 container2 如果您知道最终要合并它们。

container = np.empty((5900, 4000)) 

请注意 basic slices such as container[:900] always return views ,并且 View 需要 基本上没有额外的内存。所以你可以定义 container1 和 container2 像这样:

container1 = container[:900]    
container2 = container[900:]    

然后就地赋值。这会修改 container:

container1[:] = ...               
container2[:] = ... 

因此您的内存需求将保持在 5900 单位左右。


例如,

import numpy as np 
np.random.seed(2015) 
 
container = np.empty((5, 4), dtype='int') 
container1 = container[:2]    
container2 = container[2:]    
container1[:] = np.random.randint(10, size=(2,4)) 
container2[:] = np.random.randint(1000, size=(3,4)) 
print(container) 

产量

[[  2   2   9   6] 
 [  8   5   7   8] 
 [112  70 487 124] 
 [859   8 275 936] 
 [317 134 393 909]] 

同时只需要一个形状数组 (5, 4) 的空间,以及随机数组的临时使用空间。

因此,您不必为节省内存而对代码进行太多更改。只需设置它

container = np.empty((5900, 4000)) 
container1 = container[:900]    
container2 = container[900:]    

然后使用

container1[:] = ... 

代替

container1 = ... 

就地赋值。 (或者,当然,您可以直接写入 container。)