首页 > 解决方案 > 高级索引和基本切片的组合

问题描述

我试图从 Numpy 文档中了解基本切片和高级索引部分的组合。它说高级索引操作可能有不同的内存布局,我在下面的代码片段中观察到一些不同的行为:

a = np.random.randn(3,3)
# case1
a[:, :][a > 0] = 0
output:
array([[ 0.        , -1.07474179, -0.06313855],
       [ 0.        , -0.74049837, -1.7376245 ],
       [-0.93616586,  0.        , -2.2520479 ]])
# case2
a[:, (0, 1, 2)][a > 0] = 0
output:
array([[ 0.67667783, -1.07474179, -0.06313855],
       [ 0.74418166, -0.74049837, -1.7376245 ],
       [-0.93616586,  0.96351976, -2.2520479 ]])

在我看来,第二种情况是高级索引,所以不会对原来的a. (如果我理解错了,请纠正我。)

但是,以下情况似乎关键不是高级索引。

a[:, (0, 1, 2)] = 0
output:
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])

让我很困惑,你能给我一些想法吗?提前致谢!

标签: pythonnumpy

解决方案


在您的情况 #2 中a[:, (0, 1, 2)][a > 0] = 0,高级索引正在创建数组的副本,如NumPy 手册中所述:

高级索引始终返回数据的副本

然后赋值操作会改变这个副本,这意味着原始数组a保持不变。副本由 触发[a<0],这会导致解释器调用a.__getitem__((slice(None,None), (0, 1, 2)))导致副本。

在第三种情况下,a[:, (0, 1, 2)] = 0解释器不需要创建副本。相反,它调用a.__setitem__((slice(None,None), (0, 1, 2)), 0)which 直接修改原始数组。

这种行为在 The NumPy Cookbook 中的条目“但是花哨的索引有时确实会返回视图,不是吗?


推荐阅读