如何获取嵌套的NumPy结构化数组字段(高级索引)

3

我有一个复杂的嵌套结构数组(通常用作记录数组)。 这个例子中是简化过的,但在实际情况下有多个层级。

c = [('x','f8'),('y','f8')]
A = [('data_string','|S20'),('data_val', c, 2)]
zeros = np.zeros(1, dtype=A)
print(zeros["data_val"]["x"])

我正在尝试对嵌套数组的"x"数据类型进行索引,而不定义前面的命名字段。 我希望像print(zeros [:,“x”])这样的语句可以让我切片所有顶级数据,但它不起作用。

是否有一些方法可以使用访问其字段名称的嵌套结构化数组进行高级索引?


每个字段级别必须单独索引。您不能将它们合并为一个。 - hpaulj
@hpaulj 所以无法将其视为多维的,并将顶层索引为“all”或[:]以便访问最低级别?这意味着我需要知道前一级字段名称是什么? - 001001
如果有的话,它将会在 https://numpy.org/doc/stable/user/basics.rec.html 页面进行记录。索引字段更像是 dict 的索引而不是多维数组的索引。您定义了一个嵌套的 dtype,而不是多维的 dtype。 - hpaulj
看起来你想要一个类似于 Pandas 提供的 dataframe 数据结构(但不是 Numpy)。 - Jérôme Richard
2个回答

2
我不知道展示结果数组是否有助于您直观地理解嵌套。
In [279]: c = [('x','f8'),('y','f8')]
     ...: A = [('data_string','|S20'),('data_val', c, 2)]
     ...: arr = np.zeros(2, dtype=A)
In [280]: arr
Out[280]: 
array([(b'', [(0., 0.), (0., 0.)]), (b'', [(0., 0.), (0., 0.)])],
      dtype=[('data_string', 'S20'), ('data_val', [('x', '<f8'), ('y', '<f8')], (2,))])

请注意,()[] 的嵌套反映了字段的嵌套关系。 arr.dtype只能直接访问顶级字段名称:
In [281]: arr.dtype.names
Out[281]: ('data_string', 'data_val')
In [282]: arr['data_val']
Out[282]: 
array([[(0., 0.), (0., 0.)],
       [(0., 0.), (0., 0.)]], dtype=[('x', '<f8'), ('y', '<f8')])

但是,通过访问一个字段,我们可以查看它的字段:

In [283]: arr['data_val'].dtype.names
Out[283]: ('x', 'y')
In [284]: arr['data_val']['x']
Out[284]: 
array([[0., 0.],
       [0., 0.]])

记录编号索引是独立的,通常可以是多维的:

In [285]: arr[1]['data_val']['x'] = [1,2]
In [286]: arr[0]['data_val']['y'] = [3,4]
In [287]: arr
Out[287]: 
array([(b'', [(0., 3.), (0., 4.)]), (b'', [(1., 0.), (2., 0.)])],
      dtype=[('data_string', 'S20'), ('data_val', [('x', '<f8'), ('y', '<f8')], (2,))])

由于data_val字段具有(2,)形状,因此我们可以将该索引与arr的(2,)形状混合/匹配:

In [289]: arr['data_val']['x']
Out[289]: 
array([[0., 0.],
       [1., 2.]])
In [290]: arr['data_val']['x'][[0,1],[0,1]]
Out[290]: array([0., 2.])
In [291]: arr['data_val'][[0,1],[0,1]]
Out[291]: array([(0., 3.), (2., 0.)], dtype=[('x', '<f8'), ('y', '<f8')])

我提到过字段索引就像字典索引一样。注意这些字段的显示内容:
In [294]: arr.dtype.fields
Out[294]: 
mappingproxy({'data_string': (dtype('S20'), 0),
              'data_val': (dtype(([('x', '<f8'), ('y', '<f8')], (2,))), 20)})

每个记录都存储为52字节的块:
In [299]: arr.itemsize
Out[299]: 52
In [300]: arr.dtype.str
Out[300]: '|V52'

其中有20个是data_string,另外32个是2个c字段

In [303]: arr['data_val'].dtype.str
Out[303]: '|V16'

您可以请求字段列表,并获得一种特殊类型的视图。它的数据类型显示略有不同。
In [306]: arr[['data_val']]
Out[306]: 
array([([(0., 3.), (0., 4.)],), ([(1., 0.), (2., 0.)],)],
      dtype={'names': ['data_val'], 'formats': [([('x', '<f8'), ('y', '<f8')], (2,))], 'offsets': [20], 'itemsize': 52})

In [311]: arr['data_val'][['y']]
Out[311]: 
array([[(3.,), (4.,)],
       [(0.,), (0.,)]],
      dtype={'names': ['y'], 'formats': ['<f8'], 'offsets': [8], 'itemsize': 16})

每个"data_val"都从52字节记录的第20个字节开始。而每个"y"都从其16字节记录的第8个字节开始。


这真的很有帮助,尽管它也引发了我原问题范围之外更多的问题。 - 001001

1
语句zeros['data_val']创建了一个数组的视图,此时该数组可能已经不连续。由于c是数组类型,因此可以提取多个x的值,这意味着x具有明确定义的步幅和形状。语句zeros[:, 'x']的语义非常不清楚。例如,对于没有xdata_string会发生什么?我希望会出现错误;您可能期望其他结果。
我唯一能想到简化索引的方法是将c直接扩展为A,类似于C中的匿名结构,但是用数组很难做到这一点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接