以下程序从嵌套的数组列表中创建一个大型数组:
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]])
答案 0 :(得分:1)
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
生成与嵌套堆栈相同的2d数组:
np.vstack([np.hstack([a, a + 1]), np.hstack([a + 2, a + 3])])
np.array
和np.stack
生成一个4d数组。它可以重新变形为2d,但元素的顺序是不同的。为了匹配我们需要在重塑之前进行一些转置。 e.g。
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]])