微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

numpy - 为什么 Z[(0,2)] 可以在某些情况下查看而在其他情况下可以复制?

如何解决numpy - 为什么 Z[(0,2)] 可以在某些情况下查看而在其他情况下可以复制?

继续问题numpy - why Z[(0,2)] is view but Z[(0,2),(0)] is copy?。我得到了答案并了解到 逗号 触发高级索引会产生完全不同的索引。答案还提供了一种使用 __array_interface__ 来理解复制/查看行为的方法

但是显然我还没有深入到答案的这一部分。

如果新数组可以用形状、步幅和原始数据缓冲区的全部或部分来描述,则返回一个视图

因为我仍然无法解释为什么下面的行为不同。因此,提出一个新问题以深入了解此 (shape,stride) 机制,以了解查看/复制的工作原理。

请详细说明 numpy 如何使用 shhapestride 来确定是否返回副本。

一个索引X[0,1]返回一个视图。

X = np.arange(36).reshape(3,3,4)
print("X is \n{}\n".format(X))
print("X.__array_interface__ \n{}\n".format(X.__array_interface__))

_x =  X[
    0,2
]
print("X[0,1] is \n{}\nIs view? {}\n".format(
    _x,_x.base is not None
))
print("_x.__array_interface__ is \n{}\n".format(_x.__array_interface__))
---
X is 
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]
  [32 33 34 35]]]

X.__array_interface__ 
{'data': (94194168544480,False),'strides': None,'descr': [('','<i8')],'typestr': '<i8','shape': (3,4),'version': 3}

X[0,1] is 
[ 8  9 10 11]
Is view? True

_x.__array_interface__ is 
{'data': (94194168544544,'shape': (4,),'version': 3}

但是,具有相同 [0,1] 的下一个索引返回一个副本。

Y = np.arange(12).reshape(3,4)
print("Y is \n{}\n".format(Y))
print("Y.__array_interface__ is \n{}\n".format(Y.__array_interface__))

_y = Y[
    0,1
]
print("Y[0,1] is \n{}\nIs view {}\n".format(
    _y,_y.base is not None
))
print(".Y[0,1].__array_interface__ is \n{}\n".format(_y.__array_interface__))
---
Y is 
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

Y.__array_interface__ is 
{'data': (94194175499568,'version': 3}

Y[0,1] is 
1
Is view False

.Y[0,1].__array_interface__ is 
{'data': (94194177613184,'shape': (),'version': 3,'__ref': array(1)}

解决方法

In [195]: Y = np.arange(12).reshape(3,4)
In [196]: Y
Out[196]: 
array([[ 0,1,2,3],[ 4,5,6,7],[ 8,9,10,11]])

在二维数组上使用 2 个标量索引会从数组中返回一个元素,即 numpy 标量。

In [197]: Y[0,1]
Out[197]: 1
In [198]: type(_)
Out[198]: numpy.int64

在大多数情况下,我们可以将此类对象视为 Python 整数。它确实具有 ndarray 之类的属性,例如 shape 甚至 __array_interface__,但它不是 ndarray

相比之下,数组的“切片”本身就是一个数组:

In [199]: Y[0,:]
Out[199]: array([0,3])
In [200]: type(_)
Out[200]: numpy.ndarray

https://numpy.org/doc/stable/reference/arrays.scalars.html

该文档有一小部分展示了如何将数组标量视为 0d 数组。

In [209]: Y.__array_interface__['data']
Out[209]: (38135024,False)
In [210]: Y[0,0].__array_interface__['data']
Out[210]: (35130688,False)
In [211]: Y[0,...].__array_interface__['data']
Out[211]: (38135024,False)
In [212]: Y[0,0]             # array scalar
Out[212]: 0
In [213]: Y[0,...]         # 0d array
Out[213]: array(0)

要获取数组的元素,作为“普通”Python 类型:

In [215]: Y.item(0,0)
Out[215]: 0
In [216]: type(_)
Out[216]: int

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。