简体   繁体   English

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

[英]How does numpy allocate memory for nested array?

The following program creates a large array from a nested list of arrays: 以下程序从数组的嵌套列表创建一个大数组:

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)

Does np.array pre-allocate memory for only once for the result before copying data into the memory in this case? 在这种情况下,np.array是否只为结果预分配一次内存,然后再将数据复制到内存中?

Or, this is similar to: 或者,这类似于:

c = np.vstack([np.hstack([a, a + 1]), np.hstack([a + 2, a + 3])])

which would pre-allocate memory for 3 times? 哪个会预分配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]] produces 3 new arrays (the sums) plus a list of pointers to those arrays. nested_list = [[a, a + 1], [a + 2, a + 3]]产生3个新数组(总和)以及指向这些数组的指针列表。 That's just basic Python interpreter action. 那只是基本的Python解释器动作。

b = np.array(nested_list) : np.array is a complex compiled function, so without some serious digging it is hard to tell exactly what it does. b = np.array(nested_list)np.array是一个复杂的编译函数,因此,如果不进行深入研究,就很难确切地知道它的作用。 My impression from previous use, and especially errors when components don't exactly match in size, is that it scans the input to determine the highest-dimensional array that it can create, and then plugs the pieces in, with type conversions if needed. 我对以前使用的印象,尤其是当组件的大小不完全匹配时出现的错误,给我的印象是,它扫描输入以确定它可以创建的最大维数组,然后将其插入,并在需要时进行类型转换。

It's easy to do time comparisons; 比较时间很容易; harder to track memory use. 很难跟踪内存使用情况。 But assuming that data copying is the biggest time consumer, time tests are probably a good proxy for memory use. 但是假设数据复制是最大的时间消耗者,则时间测试可能是内存使用的良好代理。 And unless we are hitting memory errors, we are usually more concerned with time than memory use. 而且,除非遇到内存错误,否则我们通常更关注时间而不是内存使用。

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)

Working from the nested list of arrays is a bit faster than working from the pure list equivalent. 从数组的嵌套列表中进行操作比从纯列表中进行处理要快一些。 It may be copying those arrays to the target as blocks. 它可能会将这些数组作为块复制到目标。

Individual stacks is noticeably slower, though it also creates the a+n arrays as well: 单个堆栈明显较慢,尽管它也会创建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 acts the same as np.array (with the default axis). np.stack行为与np.array相同(具有默认轴)。 It too uses concatenate : 它也使用concatenate

In [570]: timeit np.stack(alist)
28.7 µs ± 262 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Including the a+n calculations into the timing may be fairer: 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)

The new np.block was mentioned - it produces something different and is quite a bit slower 提到了新的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 produces the same 2d array as the nested stacks: block产生与嵌套堆栈相同的二维数组:

np.vstack([np.hstack([a, a + 1]), np.hstack([a + 2, a + 3])])

np.array and np.stack produce a 4d array. np.arraynp.stack产生一个4d数组。 It can be reshaped to 2d, but the order of elements is different. 可以将其重塑为2d,但是元素的顺序不同。 To match we'd need to do some transposing before reshaping. 为了匹配,我们需要在重塑之前进行一些移调。 eg 例如

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