完全嵌套NumPy结构化标量

时间:2018-05-12 09:52:52

标签: python numpy structured-array

在NumPy文档和其他StackOverflow问题中,提到了嵌套的NumPy结构化标量。在我看过的每个地方,他们似乎都将嵌套的结构化标量描述为包含另一个标量(显然)的标量,但内部标量总是另一个dtype。我想做的是能够有一个NumPy dtype,它有一个字段,它是自己的dtype。

一个简单的例子是表示树节点的dtype,它存储一些值(如整数),另一个树节点表示它的父节点。

这似乎应该使用numpy.void完成,但我无法使用类似以下的dtype来完成:

node_dtype = np.dtype([("parent", np.void), ("info", np.uint8)])

3 个答案:

答案 0 :(得分:2)

np.void

我认为您认为np.void可行,因为结构化数组记录的typevoid

In [32]: node_dtype = np.dtype([("parent", np.void), ("info", np.uint8)])
In [33]: np.zeros(3, node_dtype)
Out[33]: 
array([(b'', 0), (b'', 0), (b'', 0)],
      dtype=[('parent', 'V'), ('info', 'u1')])
In [34]: type(_[0])
Out[34]: numpy.void

但请注意

In [35]: __['parent']
Out[35]: array([b'', b'', b''], dtype='|V0')

该字段占用0个字节。

In [36]: np.zeros(3, np.void)
Out[36]: array([b'', b'', b''], dtype='|V0')
In [37]: np.zeros(3, np.void(0))
Out[37]: array([b'', b'', b''], dtype='|V0')
In [38]: np.zeros(3, np.void(5))
Out[38]: 
array([b'\x00\x00\x00\x00\x00', b'\x00\x00\x00\x00\x00',
       b'\x00\x00\x00\x00\x00'], dtype='|V5')
In [39]: _[0] = b'12345'

np.void通常采用一个参数,一个指定长度的整数。

虽然可以嵌套dtypes,但结果必须仍然是已知的itemsize

In [57]: dt0 = np.dtype('i,f')
In [58]: dt1 = np.dtype([('f0','U3'), ('nested',dt0)])
In [59]: dt1
Out[59]: dtype([('f0', '<U3'), ('nested', [('f0', '<i4'), ('f1', '<f4')])])
In [60]: dt1.itemsize
Out[60]: 20

生成的数组将具有已知大小的数据缓冲区,足以容纳arr.sizearr.itemsize字节的项。

object dtype

您可以使用object dtype字段构建结构化数组

In [61]: arr = np.empty(3, 'O,i')
In [62]: arr
Out[62]: 
array([(None, 0), (None, 0), (None, 0)],
      dtype=[('f0', 'O'), ('f1', '<i4')])
In [63]: arr[1]['f0']=arr[0]
In [64]: arr[2]['f0']=arr[1]
In [65]: arr
Out[65]: 
array([(None, 0), ((None, 0), 0), (((None, 0), 0), 0)],
      dtype=[('f0', 'O'), ('f1', '<i4')])
In [66]: arr[0]['f1']=100
In [67]: arr
Out[67]: 
array([(None, 100), ((None, 100),   0), (((None, 100), 0),   0)],
      dtype=[('f0', 'O'), ('f1', '<i4')])
In [68]: arr[1]['f1']=200
In [69]: arr[2]['f1']=300
In [70]: arr
Out[70]: 
array([(None, 100), ((None, 100), 200), (((None, 100), 200), 300)],
      dtype=[('f0', 'O'), ('f1', '<i4')])

我不知道这是否是一个特别有用的结构。列表可能同样好

In [71]: arr.tolist()
Out[71]: [(None, 100), ((None, 100), 200), (((None, 100), 200), 300)]

答案 1 :(得分:1)

为我尝试这个崩溃的numpy:

>>> import numpy as np
>>>
# normal compound dtype, no prob
>>> L = [('f1', int), ('f2', float), ('f3', 'U4')]
>>> np.dtype(L)
dtype([('f1', '<i8'), ('f2', '<f8'), ('f3', '<U4')])
>>> 
# dtype containing itself
>>> L.append(('f4', L))
>>> L
[('f1', <class 'int'>), ('f2', <class 'float'>), ('f3', 'U4'), ('f4', [...])]
>>> np.dtype(L)
Speicherzugriffsfehler (Speicherabzug geschrieben)
# and that is German for segfault (core dumped)

考虑到解释这种结构时的概念问题,更不用说为它自动提出内存布局了,我并不感到惊讶它不起作用,但显然它不应该崩溃

答案 2 :(得分:1)

我无法帮助玩@hpaulj非常简洁的解决方案。

有一点让我觉得有用的东西让我知道。

它不起作用 - 或者至少不起作用 - 散装:

>>> import numpy as np
>>> 
>>> arr = np.empty(4, 'O,i')
>>> arr['f1'] = np.arange(4)
>>> 
# assign one by one:
# ------------------
>>> for i in range(4): arr[i]['f0'] = arr[(i+1) % 4]
... 
# inddividual elements link up nicely:
>>> arr[0]['f0']['f0'] is arr[1]['f0']
True
>>> print([(a['f1'], a['f0']['f1'], a['f0']['f0']['f1']) for a in arr])
[(0, 1, 2), (1, 2, 3), (2, 3, 0), (3, 0, 1)]
# but don't try it in bulk:
>>> print(arr['f1'], arr['f0']['f1'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices
>>> 
>>> arr = np.empty(4, 'O,i')
>>> arr['f1'] = np.arange(4)
>>> 
# assign in bulk:
# ---------------
>>> arr['f0'][[3,0,1,2]] = arr
>>> 
# no linking up:
>>> arr[0]['f0']['f0'] is arr[1]['f0']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: tuple indices must be integers or slices, not str
>>> print([(a['f1'], a['f0']['f1'], a['f0']['f0']['f1']) for a in arr])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
TypeError: tuple indices must be integers or slices, not str