[英]How does numpy allocate memory for nested array?
以下程序从数组的嵌套列表创建一个大数组:
import numpy as np
a = np.arange(6).reshape(2, 3)
nested_list = [[a, a + 1], [a + 2, a + 3]]
b = np.array(nested_list)
在这种情况下,np.array是否只为结果预分配一次内存,然后再将数据复制到内存中?
或者,这类似于:
c = np.vstack([np.hstack([a, a + 1]), np.hstack([a + 2, a + 3])])
哪个会预分配3次内存?
>>> b
array([[[[0, 1, 2],
[3, 4, 5]],
[[1, 2, 3],
[4, 5, 6]]],
[[[2, 3, 4],
[5, 6, 7]],
[[3, 4, 5],
[6, 7, 8]]]])
>>> c
array([[0, 1, 2, 1, 2, 3],
[3, 4, 5, 4, 5, 6],
[2, 3, 4, 3, 4, 5],
[5, 6, 7, 6, 7, 8]])
>>> b.shape
(2, 2, 2, 3)
>>> b.reshape(2*2, 2*3)
array([[0, 1, 2, 3, 4, 5],
[1, 2, 3, 4, 5, 6],
[2, 3, 4, 5, 6, 7],
[3, 4, 5, 6, 7, 8]])
nested_list = [[a, a + 1], [a + 2, a + 3]]
产生3个新数组(总和)以及指向这些数组的指针列表。 那只是基本的Python解释器动作。
b = np.array(nested_list)
: np.array
是一个复杂的编译函数,因此,如果不进行深入研究,就很难确切地知道它的作用。 我对以前使用的印象,尤其是当组件的大小不完全匹配时出现的错误,给我的印象是,它扫描输入以确定它可以创建的最大维数组,然后将其插入,并在需要时进行类型转换。
比较时间很容易; 很难跟踪内存使用情况。 但是假设数据复制是最大的时间消耗者,则时间测试可能是内存使用的良好代理。 而且,除非遇到内存错误,否则我们通常更关注时间而不是内存使用。
In [565]: alist = [[a,a+1],[a+2,a+3]]
In [566]: allist = [[a.tolist(), (a+1).tolist()],[(a+2).tolist(), (a+3).tolist()]]
In [567]: timeit np.array(alist)
6.74 µs ± 63.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [568]: timeit np.array(allist)
9.92 µs ± 286 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
从数组的嵌套列表中进行操作比从纯列表中进行处理要快一些。 它可能会将这些数组作为块复制到目标。
单个堆栈明显较慢,尽管它也会创建a+n
数组:
In [569]: timeit c = np.vstack([np.hstack([a, a + 1]), np.hstack([a + 2, a + 3])])
37.8 µs ± 39 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
np.stack
行为与np.array
相同(具有默认轴)。 它也使用concatenate
:
In [570]: timeit np.stack(alist)
28.7 µs ± 262 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
将a+n
计算包括在时间中可能更公平:
In [571]: %%timeit
...: alist = [[a,a+1],[a+2,a+3]]
...: np.stack(alist)
...:
38.6 µs ± 509 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [572]: %%timeit
...: alist = [[a,a+1],[a+2,a+3]]
...: np.array(alist)
...:
15.7 µs ± 177 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
提到了新的np.block
它产生了一些不同的东西,并且速度慢了很多
In [573]: np.block(alist)
Out[573]:
array([[0, 1, 2, 1, 2, 3],
[3, 4, 5, 4, 5, 6],
[2, 3, 4, 3, 4, 5],
[5, 6, 7, 6, 7, 8]])
In [574]: timeit np.block(alist)
126 µs ± 2.39 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
block
产生与嵌套堆栈相同的二维数组:
np.vstack([np.hstack([a, a + 1]), np.hstack([a + 2, a + 3])])
np.array
和np.stack
产生一个4d数组。 可以将其重塑为2d,但是元素的顺序不同。 为了匹配,我们需要在重塑之前进行一些移调。 例如
In [590]: np.array(alist).transpose(0,2,1,3).reshape(4,6)
Out[590]:
array([[0, 1, 2, 1, 2, 3],
[3, 4, 5, 4, 5, 6],
[2, 3, 4, 3, 4, 5],
[5, 6, 7, 6, 7, 8]])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.