在有关reshape()函数的numpy手册中,它说
>>> a = np.zeros((10, 2)) # A transpose make the array non-contiguous >>> b = a.T # Taking a view makes it possible to modify the shape without modifying the # initial object. >>> c = b.view() >>> c.shape = (20) AttributeError: incompatible shape for a non-contiguous array
我的问题是:
连续数组只是存储在不间断内存块中的数组:要访问数组中的下一个值,我们只需移至下一个内存地址。
这意味着arr是C连续数组,因为行被存储为连续的内存块。下一个内存地址保存该行的下一行值。如果要向下移动一列,我们只需要跳过三个块(例如,从0跳到4意味着我们跳过1,2和3)。
用换位数组arr.T意味着C连续性丢失,因为相邻的行条目不再位于相邻的存储器地址中。但是,Fortranarr.T是连续的,因为列在内存的连续块中
从性能角度来看,访问彼此相邻的内存地址通常比访问更“扩展”的地址更快(从RAM中获取值可能需要为CPU提取并缓存许多相邻地址)。意味着对连续阵列的操作通常会更快。
由于C连续的内存布局,因此按行操作通常比按列操作快。例如,您通常会发现
np.sum(arr, axis=1) # sum the rows
快于:
np.sum(arr, axis=0) # sum the columns
同样,对于Fortran连续数组,对列的操作将稍快一些。
最后,为什么不能通过分配新形状来展平Fortran连续数组?
>>> arr2 = arr.T >>> arr2.shape = 12 AttributeError: incompatible shape for a non-contiguous array
为了使这成为可能,NumPy必须arr.T像这样将各行放在一起:
在此处输入图片说明
(shape直接设置属性将假定C顺序-即NumPy尝试按行执行该操作。)
shape
这是不可能的。对于任何轴,NumPy需要具有恒定的步幅长度(要移动的字节数)才能到达数组的下一个元素。arr.T以这种方式展平将需要在内存中向前和向后跳过以检索数组的连续值。
如果我们arr2.reshape(12)改为写,NumPy会将arr2的值复制到新的内存块中(因为它无法将视图返回到该形状的原始数据)。
arr2.reshape(12)
arr2