繁体   English   中英

numpy如何为嵌套数组分配内存?

[英]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.arraynp.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM