Python 如何将两个二维numpy数组复制到预先分配的数组

Python 如何将两个二维numpy数组复制到预先分配的数组,python,numpy,Python,Numpy,我有两个大的2d numpy数组,行数相同,列数不同。假设arr1有形状(num_rows1,num_cols1),arr2有形状(num_rows1,num_cols2) 我预先分配了大小为(num_rows1、num_cols1+num_cols2)的numpy数组arr12 将arr1和arr2复制到arr12以使arr1与arr2连接的最有效方法是什么 使用此预分配方法是否比numpy的串联方法更有效?numpy编译代码(如concatenate)通常确定返回数组的大小,创建该数组,并将

我有两个大的2d numpy数组,行数相同,列数不同。假设arr1有形状(num_rows1,num_cols1),arr2有形状(num_rows1,num_cols2)

我预先分配了大小为(num_rows1、num_cols1+num_cols2)的numpy数组arr12

将arr1和arr2复制到arr12以使arr1与arr2连接的最有效方法是什么


使用此预分配方法是否比numpy的串联方法更有效?

numpy
编译代码(如
concatenate
)通常确定返回数组的大小,创建该数组,并将值复制到该数组中。事实上,它通过C-API调用做到这一点并不会对内存使用产生任何影响<代码>串联不会覆盖或重用参数使用的任何内存

In [465]: A, B = np.ones((1000,1000)), np.zeros((1000,500))
一些时间比较:

In [466]: timeit np.concatenate((A,B), axis=1)                                                         
6.73 ms ± 338 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [467]: C = np.zeros((1000,1500))                                                                    
In [468]: timeit np.concatenate((A,B), axis=1, out=C)                                                  
6.44 ms ± 174 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [469]: %%timeit 
     ...: C = np.zeros((1000,1500)) 
     ...: np.concatenate((A,B), axis=1, out=C)                                                                                               
11.5 ms ± 358 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [470]: %%timeit 
     ...: C = np.zeros((1000,1500)) 
     ...: C[:,:1000]=A; C[:,1000:]=B                                                                                             
11.5 ms ± 282 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [471]: %%timeit 
     ...: C[:,:1000]=A; C[:,1000:]=B                                                                                              
6.29 ms ± 160 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
因此,如果目标阵列已经存在,请使用它。但是仅仅为了这个目的而创建一个,似乎没有什么好处。

基准测试 我们将对各种数据集进行基准测试,并从中得出结论

时间安排 使用包(打包在一起的一些基准测试工具;免责声明:我是它的作者)对建议的解决方案进行基准测试

基准代码:

import numpy as np
import benchit

def numpy_concatenate(a, b):
    return np.concatenate((a,b),axis=1)

def numpy_hstack(a, b):
    return np.hstack((a,b))

def preallocate(a, b):
    m,n = a.shape[1], b.shape[1]
    out = np.empty((a.shape[0],m+n), dtype=np.result_type((a.dtype, b.dtype)))
    out[:,:m] = a
    out[:,m:] = b
    return out
    
funcs = [numpy_concatenate, numpy_hstack, preallocate]
R = np.random.rand 

inputs = {n: (R(1000,1000), R(1000,n)) for n in [100, 200, 500, 1000, 200, 5000]}
t = benchit.timings(funcs, inputs, multivar=True,   input_name='Col length of b')
t.plot(logy=False, logx=True, savepath='plot_1000rows.png')

结论:它们在时间上具有可比性

内存分析 在内存端,
np.hstack
应该类似于
np.concatenate
。因此,我们将使用其中一个

让我们用大型2D数组设置一个输入数据集。我们将进行一些内存基准测试

设置代码:

# Filename : memprof_npconcat_preallocate.py
import numpy as np
from memory_profiler import profile

@profile(precision=10)
def numpy_concatenate(a, b):
    return np.concatenate((a,b),axis=1)

@profile(precision=10)
def preallocate(a, b):
    m,n = a.shape[1], b.shape[1]
    out = np.empty((a.shape[0],m+n), dtype=np.result_type((a.dtype, b.dtype)))
    out[:,:m] = a
    out[:,m:] = b
    return out

R = np.random.rand
a,b = R(1000,1000), R(1000,1000)

if __name__ == '__main__':
    numpy_concatenate(a, b)

if __name__ == '__main__':
    preallocate(a, b)  
因此,
a
是1000x1000,而
b
也是如此

运行:

因此,对于
preallocate
方法,总mem消耗量为
14.2929687500
+
0.7734375000
,略小于
15.2265625000

a
b
-

$ python3 -m memory_profiler memprof_npconcat_preallocate.py
Filename: memprof_npconcat_preallocate.py

Line #    Mem usage    Increment   Line Contents
================================================
     9 435.4101562500 MiB 435.4101562500 MiB   @profile(precision=10)
    10                             def numpy_concatenate(a, b):
    11 816.8515625000 MiB 381.4414062500 MiB       return np.concatenate((a,b),axis=1)


Filename: memprof_npconcat_preallocate.py

Line #    Mem usage    Increment   Line Contents
================================================
    13 435.5351562500 MiB 435.5351562500 MiB   @profile(precision=10)
    14                             def preallocate(a, b):
    15 435.5351562500 MiB   0.0000000000 MiB       m,n = a.shape[1], b.shape[1]
    16 435.5351562500 MiB   0.0000000000 MiB       out = np.empty((a.shape[0],m+n), dtype=np.result_type((a.dtype, b.dtype)))
    17 780.3203125000 MiB 344.7851562500 MiB       out[:,:m] = a
    18 816.9296875000 MiB  36.6093750000 MiB       out[:,m:] = b
    19 816.9296875000 MiB   0.0000000000 MiB       return out
同样,来自预分配的总数较小


结论:预分配方法对记忆的益处稍好一些,这在某种程度上是有道理的。使用concatenate时,我们有三个数组涉及src1+src2->dst,而使用preallocation时,只有src和dst两个步骤的内存拥塞较小。

您可以执行
np.stack((a,b),1,out=arr3)
检查这里:np.stack()不是在引擎盖下使用np.concatenate()吗?我在寻找比np.concatenate()更高效的东西。嗯,对不起,我没看到!你看到这个了吗?没问题。我见过那根线。这些示例主要针对一维阵列。我想知道如何有效地处理2d数组。我相信它将使用与np.concatenate相同的数量。不同之处在于,预分配允许您预先保留内存,而np.concatenate在内存中分配一个新位置。所以我认为如果只需要一次,np.concatenate将比preallocation更有用。
$ python3 -m memory_profiler memprof_npconcat_preallocate.py
Filename: memprof_npconcat_preallocate.py

Line #    Mem usage    Increment   Line Contents
================================================
     9 435.4101562500 MiB 435.4101562500 MiB   @profile(precision=10)
    10                             def numpy_concatenate(a, b):
    11 816.8515625000 MiB 381.4414062500 MiB       return np.concatenate((a,b),axis=1)


Filename: memprof_npconcat_preallocate.py

Line #    Mem usage    Increment   Line Contents
================================================
    13 435.5351562500 MiB 435.5351562500 MiB   @profile(precision=10)
    14                             def preallocate(a, b):
    15 435.5351562500 MiB   0.0000000000 MiB       m,n = a.shape[1], b.shape[1]
    16 435.5351562500 MiB   0.0000000000 MiB       out = np.empty((a.shape[0],m+n), dtype=np.result_type((a.dtype, b.dtype)))
    17 780.3203125000 MiB 344.7851562500 MiB       out[:,:m] = a
    18 816.9296875000 MiB  36.6093750000 MiB       out[:,m:] = b
    19 816.9296875000 MiB   0.0000000000 MiB       return out