【问题标题】:Different behaviour of indexing and slicing in numpy structured arraysnumpy 结构化数组中索引和切片的不同行为
【发布时间】:2020-04-24 16:58:04
【问题描述】:

假设你有一个结构化数组a:

import numpy as np

a = np.array([1, 2, 3, 4, 5, 6], dtype=[('val', 'i4')])
print(a)
[(1,) (2,) (3,) (4,) (5,) (6,)]

现在,如果我想将其中一个条目更改为不同的值,以下两种方式似乎是等效的(案例 I):

# both of these work
"""version a)"""
a['val'][1] = 10
print(a)
[( 1,) (10,) ( 3,) ( 4,) ( 5,) ( 6,)]

"""version b)"""
a[1]['val'] = 2
print(a)
[(1,) (2,) (3,) (4,) (5,) (6,)]

但是,如果我们尝试更改多个条目(案例 II),这种歧义(不确定这是否是适当的术语)就会失效:

"""version a)"""
a['val'][[0, 1]] = 15
print(a)
[(15,) (15,) ( 3,) ( 4,) ( 5,) ( 6,)]
# this works

"""version b)"""
a[[0, 1]]['val'] = 5
print(a)
[(15,) (15,) ( 3,) ( 4,) ( 5,) ( 6,)]
# this has no effect

我想也许在第二种情况下,版本 b),创建了一个新对象,因此为这些条目分配一个新值只会影响新对象,但不会影响原始对象。但同样在第一种情况下,版本 b),似乎创建了一个新对象,因为以下两个语句都返回 False:

print(a[1]['val'] is a['val'][1])
print(a['val'][[0, 1]] is a[[0, 1]]['val'])

这种歧义只在第一种情况下给出,而在第二种情况下没有给出,这对我来说似乎是不一致的,如果至少令人困惑的话。我错过了什么?

【问题讨论】:

  • 所有索引都会产生一个新的数组对象,所以is 不是一个好的测试。重要的是第一个索引是生成copy 还是view。 a[...][...] = value 对这种区别特别敏感。
  • 即使是简单的 dtype 数组,arr[[0,1]][1:] = 1 也不会修改 arr。 arr[[0,1]] 是高级索引; arr[0] 和 arr[3:] 是基本的,与 dtype 无关。
  • 单独查看a['val']、a[1] 和a[[0,1]]。注意形状和dtype。字段和记录索引不可互换。并且字段索引不是“列”索引。
  • 谢谢!那么有什么方法可以检查两个数组是否来自同一个源数组(并且还保存相同的值)?我不确定是否真的有一个用例,只是好奇。

标签: python arrays numpy structured-array


【解决方案1】:

很好的观察。根据numpy doc:对于索引数组的所有情况,返回的是原始数据的副本,而不是切片的视图。虽然单元素索引返回一个视图。

还请注意,根据 scipy 文档,在结构化数组上调用字段会创建一个视图,并且使用整数索引会创建一个结构化标量,与其他 numpy 标量不同,结构化标量是可变的,并且像视图一样进入原始数组,这样修改标量将修改原始数组。结构化标量还支持按字段名称访问和分配

虽然它可能不共享内存(我不确定它的内部实现),但它就像一个视图并更改了原始数组。因此,当您使用单个整数调用数组时,它就像一个视图并更改原始数组,而当您通过整数索引上的数组调用它时,它会创建一个副本并且不会更改原始数组。

【讨论】:

  • 谢谢!这解释了这种行为,尽管我认为它仍然非常不直观且容易出错。
猜你喜欢
  • 2018-10-17
  • 1970-01-01
  • 2015-02-02
  • 1970-01-01
  • 2023-03-26
  • 2014-05-07
  • 2023-03-18
  • 2017-06-24
  • 1970-01-01
相关资源
最近更新 更多