结构化数组#
引言#
结构化数组是 ndarray,其数据类型是简单的、按名称组织的 字段 序列的组合。例如,
>>> x = np.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)],
... dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])
>>> x
array([('Rex', 9, 81.), ('Fido', 3, 27.)],
dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')])
这里的 x 是一个长度为 2 的一维数组,其数据类型是一个结构,包含三个字段:1. 一个长度最多为 10 的字符串,名为 ‘name’;2. 一个 32 位整数,名为 ‘age’;3. 一个 32 位浮点数,名为 ‘weight’。
如果你在位置 1 索引 x,你会得到一个结构
>>> x[1]
np.void(('Fido', 3, 27.0), dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')])
你可以通过使用字段名进行索引来访问和修改结构化数组的单个字段
>>> x['age']
array([9, 3], dtype=int32)
>>> x['age'] = 5
>>> x
array([('Rex', 5, 81.), ('Fido', 5, 27.)],
dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')])
结构化数据类型被设计用来模仿 C 语言中的 ‘struct’,并且具有相似的内存布局。它们旨在与 C 代码进行接口以及对结构化缓冲区进行底层操作,例如用于解释二进制数据块。为此,它们支持诸如子数组、嵌套数据类型和联合(union)等特殊功能,并允许控制结构的内存布局。
希望处理表格数据(例如 CSV 文件中存储的数据)的用户可能会发现 xarray、pandas 或 DataArray 等 PyData 项目更适合。这些项目提供了表格数据分析的高级接口,并且针对此类用途进行了更好的优化。例如,NumPy 中结构化数组的类 C 结构内存布局可能导致缓存性能较差。
结构化数据类型#
结构化数据类型可以被看作是一个固定长度(结构的 itemsize)的字节序列,该序列被解释为一组字段。每个字段都有一个名称、一个数据类型以及其在结构中的字节偏移量。字段的数据类型可以是任何 NumPy 数据类型,包括其他结构化数据类型,也可以是 子数组数据类型,其行为类似于具有指定形状的 ndarray。字段的偏移量是任意的,字段甚至可能重叠。这些偏移量通常由 NumPy 自动确定,但也可以指定。
结构化数据类型创建#
可以使用 numpy.dtype 函数创建结构化数据类型。有 4 种替代的规范形式,在灵活性和简洁性上有所不同。这些在 数据类型对象 参考页面中有进一步的文档,总结如下:
一个由元组组成的列表,每个字段一个元组
每个元组的形式是
(fieldname, datatype, shape),其中 shape 是可选的。fieldname是一个字符串(如果使用标题,则为元组,请参见下面的 字段标题),datatype可以是任何可转换为数据类型的对象,而shape是一个整数元组,指定子数组的形状。>>> np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2, 2))]) dtype([('x', '<f4'), ('y', '<f4'), ('z', '<f4', (2, 2))])
如果
fieldname是空字符串'',则该字段将获得一个默认名称,形式为f#,其中#是字段的整数索引,从左侧开始计数为 0。>>> np.dtype([('x', 'f4'), ('', 'i4'), ('z', 'i8')]) dtype([('x', '<f4'), ('f1', '<i4'), ('z', '<i8')])
字段在结构内的字节偏移量以及整个结构的 itemsize 是自动确定的。
一个由逗号分隔的数据类型规范组成的字符串
在这种简写符号中,任何 字符串数据类型规范 都可以在字符串中使用并用逗号分隔。itemsize 和字段的字节偏移量是自动确定的,字段名称被赋予默认名称
f0、f1等。>>> np.dtype('i8, f4, S3') dtype([('f0', '<i8'), ('f1', '<f4'), ('f2', 'S3')]) >>> np.dtype('3int8, float32, (2, 3)float64') dtype([('f0', 'i1', (3,)), ('f1', '<f4'), ('f2', '<f8', (2, 3))])
一个由字段参数数组组成的字典
这是最灵活的规范形式,因为它允许控制字段的字节偏移量以及结构的 itemsize。
该字典有两个必需的键 ‘names’ 和 ‘formats’,以及四个可选键 ‘offsets’、‘itemsize’、‘aligned’ 和 ‘titles’。‘names’ 和 ‘formats’ 的值应分别为字段名称列表和数据类型规范列表,长度相同。可选的 ‘offsets’ 值应为整数字节偏移量列表,每个字段在结构中有一个。如果未给出 ‘offsets’,则自动确定偏移量。可选的 ‘itemsize’ 值应为描述数据类型总大小(以字节为单位)的整数,该大小必须足以容纳所有字段。
>>> np.dtype({'names': ['col1', 'col2'], 'formats': ['i4', 'f4']}) dtype([('col1', '<i4'), ('col2', '<f4')]) >>> np.dtype({'names': ['col1', 'col2'], ... 'formats': ['i4', 'f4'], ... 'offsets': [0, 4], ... 'itemsize': 12}) dtype({'names': ['col1', 'col2'], 'formats': ['<i4', '<f4'], 'offsets': [0, 4], 'itemsize': 12})
偏移量可以选择使字段重叠,但这将意味着对一个字段的赋值可能会覆盖任何重叠字段的数据。作为例外,
numpy.object_类型的字段不能与其他字段重叠,因为有覆盖内部对象指针然后解引用它的风险。可选的 ‘aligned’ 值可以设置为
True,以便自动偏移量计算使用对齐的偏移量(参见 自动字节偏移量和对齐),就像numpy.dtype的 ‘align’ 关键字参数设置为 True 一样。可选的 ‘titles’ 值应为一个与 ‘names’ 长度相同的标题列表,请参见下面的 字段标题。
一个由字段名称组成的字典
字典的键是字段名称,值是指定类型和偏移量的元组
>>> np.dtype({'col1': ('i1', 0), 'col2': ('f4', 1)}) dtype([('col1', 'i1'), ('col2', '<f4')])
此形式已被弃用,因为在 Python 3.6 之前的 Python 版本中,Python 字典不保留顺序。字段标题 可以通过使用 3 元组来指定,如下所示。
操作和显示结构化数据类型#
结构化数据类型的字段名称列表可以在 dtype 对象的 names 属性中找到
>>> d = np.dtype([('x', 'i8'), ('y', 'f4')])
>>> d.names
('x', 'y')
每个单独字段的 dtype 可以按名称查找
>>> d['x']
dtype('int64')
通过将一个字符串序列赋值给 names 属性(长度必须相同),可以修改字段名称。
dtype 对象还有一个类似字典的属性 fields,其键是字段名称(以及 字段标题,见下文),其值是包含每个字段的 dtype 和字节偏移量的元组。
>>> d.fields
mappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)})
对于非结构化数组,names 和 fields 属性都将等于 None。测试 dtype 是否为结构化的推荐方法是使用 if dt.names is not None 而不是 if dt.names,以考虑包含 0 个字段的 dtypes。
结构化数据类型的字符串表示形式如果可能,将显示为“元组列表”形式;否则,NumPy 将回退到使用更通用的字典形式。
自动字节偏移量和对齐#
NumPy 使用两种方法之一来自动确定结构化数据类型的字段字节偏移量和整体 itemsize,具体取决于 numpy.dtype 的关键字参数是否指定了 align=True。
默认情况下(align=False),NumPy 将字段紧密打包在一起,使每个字段从前一个字段结束的字节偏移量开始,并且字段在内存中是连续的。
>>> def print_offsets(d):
... print("offsets:", [d.fields[name][1] for name in d.names])
... print("itemsize:", d.itemsize)
>>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2'))
offsets: [0, 1, 2, 6, 7, 15]
itemsize: 17
如果设置了 align=True,NumPy 将以许多 C 编译器填充 C 结构的方式来填充结构。对齐的结构在某些情况下可以提高性能,但代价是增加了数据类型的尺寸。填充字节会插入到字段之间,使得每个字段的字节偏移量成为该字段对齐值的倍数,对于简单数据类型,这通常等于字段的字节大小,请参见 PyArray_Descr.alignment。结构还将添加尾部填充,使其 itemsize 成为最大字段对齐值的倍数。
>>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2', align=True))
offsets: [0, 1, 4, 8, 16, 24]
itemsize: 32
请注意,尽管几乎所有现代 C 编译器默认都以这种方式填充,但 C 结构中的填充是 C 实现定义的,因此此内存布局不保证与 C 程序中相应结构的确切匹配。可能需要进行一些工作,无论是 NumPy 端还是 C 端,才能获得精确的对应关系。
如果使用字典式 dtype 规范中的可选 offsets 键指定了字段的偏移量,那么设置 align=True 将检查每个字段的偏移量是否为其大小的倍数,并且 itemsize 是否为最大字段大小的倍数,如果不是则引发异常。
如果结构化数组的字段偏移量和 itemsize 满足对齐条件,则数组将设置 ALIGNED 标志。
便利函数 numpy.lib.recfunctions.repack_fields 可将对齐的 dtype 或数组转换为打包的,反之亦然。它以 dtype 或结构化 ndarray 作为参数,并返回一个具有重新打包字段的副本,无论是否包含填充字节。
字段标题#
除了字段名称之外,字段还可以拥有一个关联的 标题,这是一个备用名称,有时用作字段的附加描述或别名。标题可以像字段名称一样用于索引数组。
要在使用列表-元组形式的 dtype 规范时添加标题,可以将字段名称指定为由两个字符串组成的元组,而不是单个字符串,第一个字符串是字段的标题,第二个字符串是字段名称。例如
>>> np.dtype([(('my title', 'name'), 'f4')])
dtype([(('my title', 'name'), '<f4')])
使用第一种字典式规范形式时,可以按照上述描述,将标题作为额外的 'titles' 键提供。使用第二种(已弃用的)字典式规范形式时,可以通过提供一个 3 元素元组 (datatype, offset, title) 来代替普通的 2 元素元组来提供标题。
>>> np.dtype({'name': ('i4', 0, 'my title')})
dtype([(('my title', 'name'), '<i4')])
dtype.fields 字典将包含标题作为键(如果使用了任何标题)。这意味着一个带有标题的字段将在 fields 字典中被表示两次。这些字段的元组值还将包含第三个元素,即字段标题。因此,并且因为 names 属性保留了字段顺序而 fields 属性可能不会,建议使用 dtype 的 names 属性来遍历 dtype 的字段,它不会列出标题,如下所示:
>>> for name in d.names:
... print(d.fields[name][:2])
(dtype('int64'), 0)
(dtype('float32'), 8)
联合类型#
结构化数据类型在 NumPy 中默认实现为基础类型 numpy.void,但可以使用 数据类型对象 中描述的 (base_dtype, dtype) 形式将其他 NumPy 类型解释为结构化类型。这里,base_dtype 是所需的底层 dtype,字段和标志将从 dtype 复制。此 dtype 类似于 C 中的 ‘union’。
结构化数组的索引和赋值#
向结构化数组赋值#
有多种方法可以为结构化数组赋值:使用 Python 元组、使用标量值或使用其他结构化数组。
从 Python 原生类型(元组)赋值#
为结构化数组赋值的最简单方法是使用 Python 元组。每个赋值值都应是一个长度等于数组字段数的元组,而不是列表或数组,因为这些会触发 NumPy 的广播规则。元组的元素按从左到右的顺序赋给数组的连续字段。
>>> x = np.array([(1, 2, 3), (4, 5, 6)], dtype='i8, f4, f8')
>>> x[1] = (7, 8, 9)
>>> x
array([(1, 2., 3.), (7, 8., 9.)],
dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '<f8')])
从标量赋值#
赋给结构化元素的标量将赋给所有字段。当标量被赋给结构化数组,或者非结构化数组被赋给结构化数组时,就会发生这种情况。
>>> x = np.zeros(2, dtype='i8, f4, ?, S1')
>>> x[:] = 3
>>> x
array([(3, 3., True, b'3'), (3, 3., True, b'3')],
dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
>>> x[:] = np.arange(2)
>>> x
array([(0, 0., False, b'0'), (1, 1., True, b'1')],
dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
结构化数组也可以赋给非结构化数组,但前提是结构化数据类型只有一个字段。
>>> twofield = np.zeros(2, dtype=[('A', 'i4'), ('B', 'i4')])
>>> onefield = np.zeros(2, dtype=[('A', 'i4')])
>>> nostruct = np.zeros(2, dtype='i4')
>>> nostruct[:] = twofield
Traceback (most recent call last):
...
TypeError: Cannot cast array data from dtype([('A', '<i4'), ('B', '<i4')]) to dtype('int32') according to the rule 'unsafe'
从其他结构化数组赋值#
两个结构化数组之间的赋值就像源元素被转换为元组然后赋给目标元素一样。也就是说,源数组的第一个字段被赋给目标数组的第一个字段,依此类推,忽略字段名称。字段数量不同的结构化数组不能相互赋值。目标结构中未包含在任何字段中的字节不受影响。
>>> a = np.zeros(3, dtype=[('a', 'i8'), ('b', 'f4'), ('c', 'S3')])
>>> b = np.ones(3, dtype=[('x', 'f4'), ('y', 'S3'), ('z', 'O')])
>>> b[:] = a
>>> b
array([(0., b'0.0', b''), (0., b'0.0', b''), (0., b'0.0', b'')],
dtype=[('x', '<f4'), ('y', 'S3'), ('z', 'O')])
涉及子数组的赋值#
当为是子数组的字段赋值时,将首先将赋值值广播到子数组的形状。
结构化数组的索引#
访问单个字段#
可以通过使用字段名称索引数组来访问和修改结构化数组的单个字段。
>>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
>>> x['foo']
array([1, 3])
>>> x['foo'] = 10
>>> x
array([(10, 2.), (10, 4.)],
dtype=[('foo', '<i8'), ('bar', '<f4')])
结果数组是原始数组的一个视图。它共享相同的内存位置,对视图的写入将修改原始数组。
>>> y = x['bar']
>>> y[:] = 11
>>> x
array([(10, 11.), (10, 11.)],
dtype=[('foo', '<i8'), ('bar', '<f4')])
此视图具有与被索引字段相同的 dtype 和 itemsize,因此它通常是一个非结构化数组,除非是嵌套结构。
>>> y.dtype, y.shape, y.strides
(dtype('float32'), (2,), (12,))
如果访问的字段是子数组,则子数组的维度将附加到结果的形状之后。
>>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))])
>>> x['a'].shape
(2, 2)
>>> x['b'].shape
(2, 2, 3, 3)
访问多个字段#
可以使用多字段索引来索引和赋值结构化数组,其中索引是字段名称列表。
警告
多字段索引的行为在 NumPy 1.15 和 NumPy 1.16 之间发生了变化。
使用多字段索引的结果是原始数组的一个视图,如下所示:
>>> a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'f4')])
>>> a[['a', 'c']]
array([(0, 0.), (0, 0.), (0, 0.)],
dtype={'names': ['a', 'c'], 'formats': ['<i4', '<f4'], 'offsets': [0, 8], 'itemsize': 12})
对视图的赋值会修改原始数组。视图的字段将按索引的顺序排列。请注意,与单字段索引不同,视图的 dtype 与原始数组的 itemsize 相同,并且字段偏移量与原始数组中的相同,未索引的字段仅被省略。
警告
在 NumPy 1.15 中,使用多字段索引数组会返回上述结果的副本,但字段会像通过 numpy.lib.recfunctions.repack_fields 传递一样在内存中被打包在一起。
从 NumPy 1.16 开始的新行为导致未索引字段的位置存在额外的“填充”字节,与 1.15 相比。您需要更新任何依赖于数据具有“打包”布局的代码。例如,这样的代码:
>>> a[['a', 'c']].view('i8') # Fails in Numpy 1.16
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: When changing to a smaller dtype, its size must be a divisor of the size of original dtype
将需要更改。此代码自 NumPy 1.12 起已引发 FutureWarning,自 1.7 起类似的代码已引发 FutureWarning。
在 1.16 版本中,numpy.lib.recfunctions 模块中引入了许多函数,以帮助用户适应此更改。这些函数包括 numpy.lib.recfunctions.repack_fields,numpy.lib.recfunctions.structured_to_unstructured,numpy.lib.recfunctions.unstructured_to_structured,numpy.lib.recfunctions.apply_along_fields,numpy.lib.recfunctions.assign_fields_by_name,以及 numpy.lib.recfunctions.require_fields。
函数 numpy.lib.recfunctions.repack_fields 始终可用于重现旧行为,因为它将返回结构化数组的打包副本。例如,上面的代码可以替换为:
>>> from numpy.lib.recfunctions import repack_fields
>>> repack_fields(a[['a', 'c']]).view('i8') # supported in 1.16
array([0, 0, 0])
此外,NumPy 现在提供了一个新函数 numpy.lib.recfunctions.structured_to_unstructured,它是一个更安全、更高效的替代方案,适用于希望将结构化数组转换为非结构化数组的用户,因为上述视图通常就是为此目的而设计的。此函数在考虑填充的情况下安全地转换为非结构化类型,通常避免复制,并且还能根据需要转换数据类型,不像视图那样。像这样的代码:
>>> b = np.zeros(3, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])
>>> b[['x', 'z']].view('f4')
array([0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)
可以通过替换为以下内容来使其更安全:
>>> from numpy.lib.recfunctions import structured_to_unstructured
>>> structured_to_unstructured(b[['x', 'z']])
array([[0., 0.],
[0., 0.],
[0., 0.]], dtype=float32)
对具有多字段索引的数组的赋值会修改原始数组
>>> a[['a', 'c']] = (2, 3)
>>> a
array([(2, 0, 3.), (2, 0, 3.), (2, 0, 3.)],
dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<f4')])
这遵循上面描述的结构化数组赋值规则。例如,这意味着可以使用适当的多字段索引来交换两个字段的值。
>>> a[['a', 'c']] = a[['c', 'a']]
使用整数索引获取结构化标量#
索引结构化数组的单个元素(使用整数索引)会返回一个结构化标量。
>>> x = np.array([(1, 2., 3.)], dtype='i, f, f')
>>> scalar = x[0]
>>> scalar
np.void((1, 2.0, 3.0), dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<f4')])
>>> type(scalar)
<class 'numpy.void'>
与其他 NumPy 标量不同,结构化标量是可变的,并且表现得像原始数组的视图,因此修改标量会修改原始数组。结构化标量还支持按字段名进行访问和赋值。
>>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
>>> s = x[0]
>>> s['bar'] = 100
>>> x
array([(1, 100.), (3, 4.)],
dtype=[('foo', '<i8'), ('bar', '<f4')])
与元组类似,结构化标量也可以使用整数进行索引。
>>> scalar = np.array([(1, 2., 3.)], dtype='i, f, f')[0]
>>> scalar[0]
np.int32(1)
>>> scalar[1] = 4
因此,元组可能被视为 NumPy 结构化类型的原生 Python 等价物,就像原生 Python 整数是 NumPy 整数类型的等价物一样。可以通过调用 numpy.ndarray.item 将结构化标量转换为元组。
>>> scalar.item(), type(scalar.item())
((1, 4.0, 3.0), <class 'tuple'>)
查看包含对象的结构化数组#
为了防止覆盖 object 类型字段中的对象指针,NumPy 目前不允许查看包含对象的结构化数组。
结构比较和提升#
如果两个 void 结构化数组的数据类型相等,则测试数组的相等性将产生一个布尔数组,其维度与原始数组相同,其中对应结构的全部字段相等的元素将设置为 True。
>>> a = np.array([(1, 1), (2, 2)], dtype=[('a', 'i4'), ('b', 'i4')])
>>> b = np.array([(1, 1), (2, 3)], dtype=[('a', 'i4'), ('b', 'i4')])
>>> a == b
array([True, False])
NumPy 将提升单个字段的数据类型以执行比较。因此,以下也是有效的(注意字段 ‘a’ 的 'f4' dtype)。
>>> b = np.array([(1.0, 1), (2.5, 2)], dtype=[("a", "f4"), ("b", "i4")])
>>> a == b
array([True, False])
要比较两个结构化数组,它们必须能够提升为 numpy.result_type 和 numpy.promote_types 返回的公共 dtype。这强制要求字段的数量、字段名称和字段标题必须完全匹配。当无法进行提升时(例如,由于字段名称不匹配),NumPy 将引发错误。两个结构化 dtypes 之间的提升将产生一个规范的 dtype,该 dtype 确保所有字段都是本机字节序。
>>> np.result_type(np.dtype("i,>i"))
dtype([('f0', '<i4'), ('f1', '<i4')])
>>> np.result_type(np.dtype("i,>i"), np.dtype("i,i"))
dtype([('f0', '<i4'), ('f1', '<i4')])
提升产生的 dtype 也保证是打包的,这意味着所有字段都是连续排序的,并且移除了任何不必要的填充。
>>> dt = np.dtype("i1,V3,i4,V1")[["f0", "f2"]]
>>> dt
dtype({'names': ['f0', 'f2'], 'formats': ['i1', '<i4'], 'offsets': [0, 4], 'itemsize': 9})
>>> np.result_type(dt)
dtype([('f0', 'i1'), ('f2', '<i4')])
请注意,结果打印时没有 offsets 或 itemsize,表示没有额外的填充。如果使用 align=True 创建了结构化 dtype,确保 dtype.isalignedstruct 为 true,则此属性会得到保留。
>>> dt = np.dtype("i1,V3,i4,V1", align=True)[["f0", "f2"]]
>>> dt
dtype({'names': ['f0', 'f2'], 'formats': ['i1', '<i4'], 'offsets': [0, 4], 'itemsize': 12}, align=True)
>>> np.result_type(dt)
dtype([('f0', 'i1'), ('f2', '<i4')], align=True)
>>> np.result_type(dt).isalignedstruct
True
当提升多个 dtypes 时,如果任何输入是已对齐的,则结果就是对齐的。
>>> np.result_type(np.dtype("i,i"), np.dtype("i,i", align=True))
dtype([('f0', '<i4'), ('f1', '<i4')], align=True)
< 和 > 运算符在比较 void 结构化数组时始终返回 False,并且不支持算术和位运算。
已在版本 1.23 中更改: 在 NumPy 1.23 之前,当提升到公共 dtype 失败时会发出警告并返回 False。此外,提升更加严格:它会拒绝上面混合浮点数/整数的比较示例。
记录数组#
作为可选的便利功能,NumPy 提供了一个 ndarray 子类 numpy.recarray,它允许通过属性而不是仅通过索引来访问结构化数组的字段。记录数组使用一种特殊的数据类型 numpy.record,它允许通过属性在从数组获得的结构化标量上进行字段访问。numpy.rec 模块提供了从各种对象创建 recarray 的函数。用于创建和操作结构化数组的附加辅助函数可以在 numpy.lib.recfunctions 中找到。
创建记录数组的最简单方法是使用 numpy.rec.array。
>>> recordarr = np.rec.array([(1, 2., 'Hello'), (2, 3., "World")],
... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')])
>>> recordarr.bar
array([2., 3.], dtype=float32)
>>> recordarr[1:2]
rec.array([(2, 3., b'World')],
dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])
>>> recordarr[1:2].foo
array([2], dtype=int32)
>>> recordarr.foo[1:2]
array([2], dtype=int32)
>>> recordarr[1].baz
b'World'
numpy.rec.array 可以将多种参数转换为记录数组,包括结构化数组。
>>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
... dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'S10')])
>>> recordarr = np.rec.array(arr)
numpy.rec 模块提供了许多其他创建记录数组的便利函数,请参见 记录数组创建例程。
可以使用适当的 view 来获得结构化数组的记录数组表示。
>>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')])
>>> recordarr = arr.view(dtype=np.dtype((np.record, arr.dtype)),
... type=np.recarray)
为了方便起见,将 ndarray 视为 numpy.recarray 类型会自动转换为 numpy.record 数据类型,因此可以省略 dtype。
>>> recordarr = arr.view(np.recarray)
>>> recordarr.dtype
dtype((numpy.record, [('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')]))
要回到普通的 ndarray,必须重置 dtype 和类型。以下视图执行此操作,并考虑了 recordarr 不是结构化类型的异常情况。
>>> arr2 = recordarr.view(recordarr.dtype.fields or recordarr.dtype, np.ndarray)
按索引或按属性访问的记录数组字段将返回为记录数组,如果该字段具有结构化类型,否则返回为普通 ndarray。
>>> recordarr = np.rec.array([('Hello', (1, 2)), ("World", (3, 4))],
... dtype=[('foo', 'S6'),('bar', [('A', int), ('B', int)])])
>>> type(recordarr.foo)
<class 'numpy.ndarray'>
>>> type(recordarr.bar)
<class 'numpy.rec.recarray'>
请注意,如果一个字段的名称与 ndarray 属性的名称相同,则 ndarray 属性具有优先权。此类字段将无法通过属性访问,但仍可以通过索引访问。
Recarray 辅助函数#
用于操作结构化数组的实用程序集合。
这些函数最初由 John Hunter 为 matplotlib 实现。它们已被重写和扩展,以便于使用。
- numpy.lib.recfunctions.append_fields(base, names, data, dtypes=None, fill_value=-1, usemask=True, asrecarray=False)[source]#
向现有数组添加新字段。
字段的名称由 names 参数给出,相应的值由 data 参数给出。如果附加了单个字段,names、data 和 dtypes 不需要是列表,只需是值即可。
- 参数:
- basearray
要扩展的输入数组。
- namesstring, sequence
与新字段名称对应的字符串或字符串序列。
- dataarray or sequence of arrays
存储要添加到 base 的字段的数组或数组序列。
- dtypessequence of datatypes, optional
数据类型或数据类型序列。如果为 None,则从 data 中估算数据类型。
- fill_value{float}, optional
用于填充较短数组上缺失数据的填充值。
- usemask{False, True}, optional
是否返回掩码数组。
- asrecarray{False, True}, optional
是否返回 recarray (MaskedRecords)。
- numpy.lib.recfunctions.apply_along_fields(func, arr)[source]#
将函数“func”作为归约操作应用于结构化数组的字段。
这类似于
numpy.apply_along_axis,但将结构化数组的字段视为一个额外的轴。所有字段都首先根据numpy.result_type的类型提升规则强制转换为公共类型。- 参数:
- funcfunction
应用于“字段”维度的函数。此函数必须支持 axis 参数,例如
numpy.mean、numpy.sum等。- arrndarray
要为其应用 func 的结构化数组。
- 返回:
- outndarray
归约操作的结果。
示例
>>> import numpy as np
>>> from numpy.lib import recfunctions as rfn >>> b = np.array([(1, 2, 5), (4, 5, 7), (7, 8 ,11), (10, 11, 12)], ... dtype=[('x', 'i4'), ('y', 'f4'), ('z', 'f8')]) >>> rfn.apply_along_fields(np.mean, b) array([ 2.66666667, 5.33333333, 8.66666667, 11. ]) >>> rfn.apply_along_fields(np.mean, b[['x', 'z']]) array([ 3. , 5.5, 9. , 11. ])
- numpy.lib.recfunctions.assign_fields_by_name(dst, src, zero_unassigned=True)[source]#
通过字段名称将一个结构化数组的值分配给另一个。
通常在 numpy >= 1.14 中,一个结构化数组到另一个的赋值是“按位置”复制字段,这意味着 src 的第一个字段复制到 dst 的第一个字段,依此类推,而不管字段名称。
此函数改为“按字段名称”复制,这样 dst 中的字段将从 src 中具有相同名称的字段分配。这适用于嵌套结构。这就是结构赋值在 numpy >= 1.6 到 <= 1.13 中的工作方式。
- 参数:
- dstndarray
- srcndarray
赋值期间的源和目标数组。
- zero_unassignedbool, optional
如果为 True,则目标数组中没有在源数组中找到匹配字段的字段将用值 0(零)填充。这是 numpy <= 1.13 的行为。如果为 False,则这些字段不会被修改。
- numpy.lib.recfunctions.drop_fields(base, drop_names, usemask=True, asrecarray=False)[source]#
返回一个新数组,其中删除了 drop_names 中的字段。
支持嵌套字段。
- 参数:
- basearray
输入数组。
- drop_namesstring or sequence
与要删除的字段名称对应的字符串或字符串序列。
- usemask{False, True}, optional
是否返回掩码数组。
- asrecarraystring or sequence, optional
是否返回 recarray 或 mrecarray(asrecarray=True),或者返回具有灵活 dtype 的普通 ndarray 或掩码数组。默认为 False。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> a = np.array([(1, (2, 3.0)), (4, (5, 6.0))], ... dtype=[('a', np.int64), ('b', [('ba', np.double), ('bb', np.int64)])]) >>> rfn.drop_fields(a, 'a') array([((2., 3),), ((5., 6),)], dtype=[('b', [('ba', '<f8'), ('bb', '<i8')])]) >>> rfn.drop_fields(a, 'ba') array([(1, (3,)), (4, (6,))], dtype=[('a', '<i8'), ('b', [('bb', '<i8')])]) >>> rfn.drop_fields(a, ['ba', 'bb']) array([(1,), (4,)], dtype=[('a', '<i8')])
- numpy.lib.recfunctions.find_duplicates(a, key=None, ignoremask=True, return_index=False)[source]#
查找结构化数组在给定键上的重复项。
- 参数:
- aarray-like
输入数组。
- key{string, None}, optional
用于检查重复项的字段名称。如果为 None,则按记录执行搜索。
- ignoremask{True, False}, optional
是否应忽略掩码数据或将其视为重复项。
- return_index{False, True}, optional
是否返回重复值的索引。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> ndtype = [('a', int)] >>> a = np.ma.array([1, 1, 1, 2, 2, 3, 3], ... mask=[0, 0, 1, 0, 0, 0, 1]).view(ndtype) >>> rfn.find_duplicates(a, ignoremask=True, return_index=True) (masked_array(data=[(1,), (1,), (2,), (2,)], mask=[(False,), (False,), (False,), (False,)], fill_value=(999999,), dtype=[('a', '<i8')]), array([0, 1, 3, 4]))
- numpy.lib.recfunctions.flatten_descr(ndtype)[source]#
展平结构化数据类型描述。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> ndtype = np.dtype([('a', '<i4'), ('b', [('ba', '<f8'), ('bb', '<i4')])]) >>> rfn.flatten_descr(ndtype) (('a', dtype('int32')), ('ba', dtype('float64')), ('bb', dtype('int32')))
- numpy.lib.recfunctions.get_fieldstructure(adtype, lastname=None, parents=None)[source]#
返回一个字典,其中字段索引是其父字段的列表。
此函数用于简化对嵌套在其他字段中的字段的访问。
- 参数:
- adtypenp.dtype
输入数据类型。
- lastnameoptional
最后处理的字段名称(在递归中内部使用)。
- parentsdictionary
父字段字典(在递归中内部使用)。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> ndtype = np.dtype([('A', int), ... ('B', [('BA', int), ... ('BB', [('BBA', int), ('BBB', int)])])]) >>> rfn.get_fieldstructure(ndtype) ... # XXX: possible regression, order of BBA and BBB is swapped {'A': [], 'B': [], 'BA': ['B'], 'BB': ['B'], 'BBA': ['B', 'BB'], 'BBB': ['B', 'BB']}
- numpy.lib.recfunctions.get_names(adtype)[source]#
将输入数据类型的字段名称作为元组返回。输入数据类型必须有字段,否则会引发错误。
- 参数:
- adtypedtype
输入数据类型。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> rfn.get_names(np.empty((1,), dtype=[('A', int)]).dtype) ('A',) >>> rfn.get_names(np.empty((1,), dtype=[('A',int), ('B', float)]).dtype) ('A', 'B') >>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])]) >>> rfn.get_names(adtype) ('a', ('b', ('ba', 'bb')))
- numpy.lib.recfunctions.get_names_flat(adtype)[source]#
将输入数据类型的字段名称作为元组返回。输入数据类型必须有字段,否则会引发错误。嵌套结构会事先展平。
- 参数:
- adtypedtype
输入数据类型。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> rfn.get_names_flat(np.empty((1,), dtype=[('A', int)]).dtype) is None False >>> rfn.get_names_flat(np.empty((1,), dtype=[('A',int), ('B', str)]).dtype) ('A', 'B') >>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])]) >>> rfn.get_names_flat(adtype) ('a', 'b', 'ba', 'bb')
- numpy.lib.recfunctions.join_by(key, r1, r2, jointype='inner', r1postfix='1', r2postfix='2', defaults=None, usemask=True, asrecarray=False)[source]#
根据键 key 连接数组 r1 和 r2。
键应该是字符串或字符串序列,对应于用于连接数组的字段。如果在两个输入数组中找不到 key 字段,则会引发异常。Neither r1 nor r2 应该有任何重复项:重复项的存在会使输出非常不可靠。请注意,算法不会查找重复项。
- 参数:
- key{string, sequence}
用于比较的字段的字符串或字符串序列。
- r1, r2arrays
结构化数组。
- jointype{‘inner’, ‘outer’, ‘leftouter’}, optional
如果为“inner”,则返回 r1 和 r2 共有的元素。如果为“outer”,则返回共有元素以及 r1 中不在 r2 中的元素以及 r2 中不在 r1 中的元素。如果为“leftouter”,则返回共有元素以及 r1 中不在 r2 中的元素。
- r1postfixstring, optional
附加到 r1 中存在于 r2 但不在键中的字段名称的字符串。
- r2postfixstring, optional
附加到 r2 中存在于 r1 但不在键中的字段名称的字符串。
- defaults{dictionary}, optional
映射字段名称到相应默认值的字典。
- usemask{True, False}, optional
是否返回 MaskedArray(如果 asrecarray==True 则为 MaskedRecords)或 ndarray。
- asrecarray{False, True}, optional
是否返回 recarray(如果 usemask==True 则为 MaskedRecords)或仅返回一个灵活类型的 ndarray。
备注
输出将沿键排序。
通过删除两个数组中不包含在键中的字段来形成一个临时数组,并连接结果。然后对该数组进行排序,并选择公共条目。通过用选定的条目填充字段来构造输出。如果存在一些重复项,则不保留匹配...
- numpy.lib.recfunctions.merge_arrays(seqarrays, fill_value=-1, flatten=False, usemask=False, asrecarray=False)[source]#
逐字段合并数组。
- 参数:
- seqarrayssequence of ndarrays
数组序列。
- fill_value{float}, optional
用于填充较短数组上缺失数据的填充值。
- flatten{False, True}, optional
是否折叠嵌套字段。
- usemask{False, True}, optional
是否返回掩码数组。
- asrecarray{False, True}, optional
是否返回 recarray (MaskedRecords)。
备注
如果没有掩码,缺失值将用某个值填充,具体取决于其对应类型。
-1用于整数-1.0用于浮点数'-'用于字符'-1'用于字符串True用于布尔值
XXX:我仅通过经验获得了这些值。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> rfn.merge_arrays((np.array([1, 2]), np.array([10., 20., 30.]))) array([( 1, 10.), ( 2, 20.), (-1, 30.)], dtype=[('f0', '<i8'), ('f1', '<f8')])
>>> rfn.merge_arrays((np.array([1, 2], dtype=np.int64), ... np.array([10., 20., 30.])), usemask=False) array([(1, 10.0), (2, 20.0), (-1, 30.0)], dtype=[('f0', '<i8'), ('f1', '<f8')]) >>> rfn.merge_arrays((np.array([1, 2]).view([('a', np.int64)]), ... np.array([10., 20., 30.])), ... usemask=False, asrecarray=True) rec.array([( 1, 10.), ( 2, 20.), (-1, 30.)], dtype=[('a', '<i8'), ('f1', '<f8')])
- numpy.lib.recfunctions.rec_append_fields(base, names, data, dtypes=None)[source]#
向现有数组添加新字段。
字段的名称由 names 参数给出,相应的值由 data 参数给出。如果附加了单个字段,names、data 和 dtypes 不需要是列表,只需是值即可。
- 参数:
- basearray
要扩展的输入数组。
- namesstring, sequence
与新字段名称对应的字符串或字符串序列。
- dataarray or sequence of arrays
存储要添加到 base 的字段的数组或数组序列。
- dtypessequence of datatypes, optional
数据类型或数据类型序列。如果为 None,则从 data 中估算数据类型。
- 返回:
- appended_arraynp.recarray
另请参阅
- numpy.lib.recfunctions.rec_drop_fields(base, drop_names)[source]#
返回一个新 numpy.recarray,其中删除了 drop_names 中的字段。
- numpy.lib.recfunctions.rec_join(key, r1, r2, jointype='inner', r1postfix='1', r2postfix='2', defaults=None)[source]#
根据键连接数组 r1 和 r2。join_by 的替代方法,它始终返回 np.recarray。
另请参阅
join_by等效函数
- numpy.lib.recfunctions.recursive_fill_fields(input, output)[source]#
从 output 填充字段,并从 input 填充字段,支持嵌套结构。
- 参数:
- inputndarray
输入数组。
- outputndarray
输出数组。
备注
output 的大小应至少与 input 一样大。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> a = np.array([(1, 10.), (2, 20.)], dtype=[('A', np.int64), ('B', np.float64)]) >>> b = np.zeros((3,), dtype=a.dtype) >>> rfn.recursive_fill_fields(a, b) array([(1, 10.), (2, 20.), (0, 0.)], dtype=[('A', '<i8'), ('B', '<f8')])
- numpy.lib.recfunctions.rename_fields(base, namemapper)[source]#
重命名灵活数据类型 ndarray 或 recarray 的字段。
支持嵌套字段。
- 参数:
- basendarray
必须修改其字段的输入数组。
- namemapperdictionary
将旧字段名称映射到其新版本。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> a = np.array([(1, (2, [3.0, 30.])), (4, (5, [6.0, 60.]))], ... dtype=[('a', int),('b', [('ba', float), ('bb', (float, 2))])]) >>> rfn.rename_fields(a, {'a':'A', 'bb':'BB'}) array([(1, (2., [ 3., 30.])), (4, (5., [ 6., 60.]))], dtype=[('A', '<i8'), ('b', [('ba', '<f8'), ('BB', '<f8', (2,))])])
- numpy.lib.recfunctions.repack_fields(a, align=False, recurse=False)[source]#
重新打包结构化数组或 dtype 的内存中的字段。
结构化数据类型的内存布局允许字段位于任意字节偏移处。这意味着字段之间可以插入填充字节,它们的偏移量可能不是单调递增的,并且它们可能重叠。
此方法删除任何重叠,并在内存中重新排序字段,使其具有单调递增的字节偏移量,并根据 align 选项添加或删除填充字节,该选项的行为类似于
numpy.dtype的 align 选项。如果 align=False,此方法生成“打包”内存布局,其中每个字段从前一个字段结束的字节开始,并删除任何填充字节。
如果 align=True,此方法生成“对齐”内存布局,其中每个字段的偏移量是其对齐方式的倍数,并且总项大小是最大对齐方式的倍数(通过添加填充字节)。
- 参数:
- andarray or dtype
要重新打包字段的数组或 dtype。
- alignboolean
如果为 true,则使用“对齐”内存布局,否则使用“打包”布局。
- recurseboolean
如果为 True,则也重新打包嵌套结构。
- 返回:
- repackedndarray or dtype
a 的副本,其中字段已重新打包,如果不需要重新打包,则为 a 本身。
示例
>>> import numpy as np
>>> from numpy.lib import recfunctions as rfn >>> def print_offsets(d): ... print("offsets:", [d.fields[name][1] for name in d.names]) ... print("itemsize:", d.itemsize) ... >>> dt = np.dtype('u1, <i8, <f8', align=True) >>> dt dtype({'names': ['f0', 'f1', 'f2'], 'formats': ['u1', '<i8', '<f8'], 'offsets': [0, 8, 16], 'itemsize': 24}, align=True) >>> print_offsets(dt) offsets: [0, 8, 16] itemsize: 24 >>> packed_dt = rfn.repack_fields(dt) >>> packed_dt dtype([('f0', 'u1'), ('f1', '<i8'), ('f2', '<f8')]) >>> print_offsets(packed_dt) offsets: [0, 1, 9] itemsize: 17
- numpy.lib.recfunctions.require_fields(array, required_dtype)[source]#
使用按字段名称的赋值将结构化数组强制转换为新的 dtype。
此函数通过名称将值从旧数组分配到新数组,因此输出数组中字段的值是源数组中具有相同名称的字段的值。这会创建一个仅包含 required_dtype “必需”字段的新 ndarray。
如果 required_dtype 中的字段名称在输入数组中不存在,则该字段将在输出数组中创建并设置为 0。
- 参数:
- andarray
要强制转换的数组。
- required_dtypedtype
输出数组的数据类型。
- 返回:
- outndarray
具有新 dtype 的数组,其字段值从输入数组中具有相同名称的字段复制。
示例
>>> import numpy as np
>>> from numpy.lib import recfunctions as rfn >>> a = np.ones(4, dtype=[('a', 'i4'), ('b', 'f8'), ('c', 'u1')]) >>> rfn.require_fields(a, [('b', 'f4'), ('c', 'u1')]) array([(1., 1), (1., 1), (1., 1), (1., 1)], dtype=[('b', '<f4'), ('c', 'u1')]) >>> rfn.require_fields(a, [('b', 'f4'), ('newf', 'u1')]) array([(1., 0), (1., 0), (1., 0), (1., 0)], dtype=[('b', '<f4'), ('newf', 'u1')])
- numpy.lib.recfunctions.stack_arrays(arrays, defaults=None, usemask=True, asrecarray=False, autoconvert=False)[source]#
逐字段叠加数组。
- 参数:
- arraysarray or sequence
输入数组序列。
- defaultsdictionary, optional
映射字段名称到相应默认值的字典。
- usemask{True, False}, optional
是否返回 MaskedArray(如果 asrecarray==True 则为 MaskedRecords)或 ndarray。
- asrecarray{False, True}, optional
是否返回 recarray(如果 usemask==True 则为 MaskedRecords)或仅返回一个灵活类型的 ndarray。
- autoconvert{False, True}, optional
是否自动将字段的类型转换为最大类型。
示例
>>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> x = np.array([1, 2,]) >>> rfn.stack_arrays(x) is x True >>> z = np.array([('A', 1), ('B', 2)], dtype=[('A', '|S3'), ('B', float)]) >>> zz = np.array([('a', 10., 100.), ('b', 20., 200.), ('c', 30., 300.)], ... dtype=[('A', '|S3'), ('B', np.double), ('C', np.double)]) >>> test = rfn.stack_arrays((z,zz)) >>> test masked_array(data=[(b'A', 1.0, --), (b'B', 2.0, --), (b'a', 10.0, 100.0), (b'b', 20.0, 200.0), (b'c', 30.0, 300.0)], mask=[(False, False, True), (False, False, True), (False, False, False), (False, False, False), (False, False, False)], fill_value=(b'N/A', 1e+20, 1e+20), dtype=[('A', 'S3'), ('B', '<f8'), ('C', '<f8')])
- numpy.lib.recfunctions.structured_to_unstructured(arr, dtype=None, copy=False, casting='unsafe')[source]#
将 n 维结构化数组转换为 (n+1) 维非结构化数组。
新数组将有一个新的最后一个维度,其大小等于输入数组的字段元素数量。如果未提供,则输出数据类型由应用于所有字段数据类型的 numpy 类型提升规则确定。
嵌套字段以及任何子数组字段的每个元素都计为一个字段元素。
- 参数:
- arrndarray
要转换的结构化数组或 dtype。不能包含对象数据类型。
- dtypedtype, optional
输出非结构化数组的数据类型。
- copybool, optional
如果为 true,则始终返回副本。如果为 false,则在可能的情况下返回视图,例如当 dtype 和字段的步幅合适且数组子类型是
numpy.ndarray、numpy.recarray或numpy.memmap之一时。版本 1.25.0 中已更改:如果字段由均匀步幅分隔,现在可以返回视图。
- casting{‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optional
请参阅
numpy.ndarray.astype的 casting 参数。控制可以发生什么类型的数据转换。
- 返回:
- unstructuredndarray
具有一个附加维度的非结构化数组。
示例
>>> import numpy as np
>>> from numpy.lib import recfunctions as rfn >>> a = np.zeros(4, dtype=[('a', 'i4'), ('b', 'f4,u2'), ('c', 'f4', 2)]) >>> a array([(0, (0., 0), [0., 0.]), (0, (0., 0), [0., 0.]), (0, (0., 0), [0., 0.]), (0, (0., 0), [0., 0.])], dtype=[('a', '<i4'), ('b', [('f0', '<f4'), ('f1', '<u2')]), ('c', '<f4', (2,))]) >>> rfn.structured_to_unstructured(a) array([[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]])
>>> b = np.array([(1, 2, 5), (4, 5, 7), (7, 8 ,11), (10, 11, 12)], ... dtype=[('x', 'i4'), ('y', 'f4'), ('z', 'f8')]) >>> np.mean(rfn.structured_to_unstructured(b[['x', 'z']]), axis=-1) array([ 3. , 5.5, 9. , 11. ])
- numpy.lib.recfunctions.unstructured_to_structured(arr, dtype=None, names=None, align=False, copy=False, casting='unsafe')[source]#
将 n 维非结构化数组转换为 (n-1) 维结构化数组。
输入数组的最后一个维度被转换为一个结构,其字段元素数量等于输入数组最后一个维度的尺寸。默认情况下,所有输出字段都具有输入数组的 dtype,但也可以提供具有相同数量字段元素的输出结构化 dtype。
嵌套字段以及任何子数组字段的每个元素都计入字段元素的数量。
- 参数:
- arrndarray
要转换的非结构化数组或 dtype。
- dtypedtype, optional
输出数组的结构化 dtype。
- nameslist of strings, optional
如果未提供 dtype,则此参数指定输出 dtype 的字段名称(按顺序)。字段 dtype 将与输入数组的相同。
- alignboolean, optional
是否创建对齐的内存布局。
- copybool, optional
请参阅
numpy.ndarray.astype的 copy 参数。如果为 true,则始终返回副本。如果为 false,并且满足 dtype 要求,则返回视图。- casting{‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optional
请参阅
numpy.ndarray.astype的 casting 参数。控制可以发生什么类型的数据转换。
- 返回:
- structuredndarray
维度较少的结构化数组。
示例
>>> import numpy as np
>>> from numpy.lib import recfunctions as rfn >>> dt = np.dtype([('a', 'i4'), ('b', 'f4,u2'), ('c', 'f4', 2)]) >>> a = np.arange(20).reshape((4,5)) >>> a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) >>> rfn.unstructured_to_structured(a, dt) array([( 0, ( 1., 2), [ 3., 4.]), ( 5, ( 6., 7), [ 8., 9.]), (10, (11., 12), [13., 14.]), (15, (16., 17), [18., 19.])], dtype=[('a', '<i4'), ('b', [('f0', '<f4'), ('f1', '<u2')]), ('c', '<f4', (2,))])