numpy数组切片:显式/隐式副本和内存管理

时间:2015-06-16 14:46:20

标签: arrays numpy

这是一个初学的python问题,最终与内存管理有关。

我正在将一个uint32 numpy数组切成两部分,然后尝试创建一个子数组的uint8视图。请注意,通过创建视图,我的意思是在uint8中重新解释内存中的基础数据,而不是在uint8中转换变量:因此大小会在过程中发生变化。

这是初始数组和视图的一个例子,工作正常:

a=np.array([(1,2,3,4),(5,6,7,8),(9,10,11,12)],np.int32)
a.view(np.int8) # everything is fine

崩溃(c不是硬拷贝,仍然与原始数组绑定):

a=np.array([(1,2,3,4),(5,6,7,8),(9,10,11,12)],np.int32)
c, a= np.split (a,[1],1);
c.view(np.int8) #oups

在创建视图之前抛弃原始数组并没有帮助:

a=np.array([(1,2,3,4),(5,6,7,8),(9,10,11,12)],np.int32)
c, b= np.split (a,[1],1);
del a
c.view(np.int8) #oups

这是我提出的最好的:

a=np.array([(1,2,3,4),(5,6,7,8),(9,10,11,12)],np.int32)
c, a= np.split (a,[1],1);
c=np.copy(c).view(np.uint8) #ok, but really ?!?

有没有更好的方法将数组拆分为2个子数组,以便numpy考虑它们" native",而不复制它们? (当然原始数组会被丢弃)

2 个答案:

答案 0 :(得分:1)

在分割或切片之前,将a视为dtype np.int8 。然后你可以使用

In [219]: c, _ = np.split(a.view(np.int8), [4], 1)

In [220]: c
Out[220]: 
array([[1, 0, 0, 0],
       [5, 0, 0, 0],
       [9, 0, 0, 0]], dtype=int8)

甚至更简单,

In [286]: c = a.view(np.int8)[:, :4]
In [287]: c
Out[287]: 
array([[1, 0, 0, 0],
       [5, 0, 0, 0],
       [9, 0, 0, 0]], dtype=int8)

代替。

答案 1 :(得分:1)

崩溃不是正确的术语。它只是给出了一条错误消息:

ValueError: new type not compatible with array.

忘记'丢弃'原件;拆分产品仍然存在,并使用原始数据缓冲区。

如果你沿着轴0分割了数组,那么视图就可以了。

In [368]: c0.view(np.int8)
Out[368]: array([[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]], dtype=int8)

或者原件是order='F'

In [369]: a=np.array([(1,2,3,4),(5,6,7,8),(9,10,11,12)],np.int32,order='F')

In [370]: c,b=np.split(a,[1],1)

In [371]: c.view(np.int8)
Out[371]: 
array([[1],
       [0],
       ...
       [9],
       [0],
       [0],
       [0]], dtype=int8)

如果需要,可以将最后一个重新改为(3,4)。

可视化原始数据缓冲区中数字的布局

[ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]

您要求的观点是:

[ 1,0,0,0,  2,  3,  4,  5,0,0,0,  6,  7,  8,  9,0,0,0, 10, 11, 12]

很高兴将整个事物视为int8,但不仅仅是点点滴滴。

使用替代方法,您要求将连续块视为字节

[ 1,0,0,0,  2,0,0,0,  3,0,0,0,  4,  5,  6,  7,  8,  9, 10, 11, 12]