结构化数组

【Numpy基础知识】结构化数组-LMLPHP

导包

import numpy as np

【1】介绍

结构化数组是 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. 名为“age”的 32 位整数,以及 3. 名为“weight”的 32 位浮点数。

如果你在位置 1 索引 x,你会得到一个结构:

x[1]
('Fido', 3, 27.)

可以通过使用字段名称编制索引来访问和修改结构化数组的各个字段:

x['age']
array([9, 3])
x['age'] = 5
x
array([('Rex', 5, 81.), ('Fido', 5, 27.)],
      dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')])

【2】结构化数据类型

结构化数据类型可以被认为是特定长度(结构的 itemsize)的字节序列,它被解释为字段集合。每个字段在结构中都有一个名称、一个数据类型和一个字节偏移量。字段的数据类型可以是任何 numpy 数据类型,包括其他结构化数据类型,也可以是行为类似于指定形状的 ndarray 的子数组数据类型。字段的偏移量是任意的,字段甚至可能重叠。这些偏移量通常由 numpy 自动确定,但也可以指定。

① 结构化数据类型创建

可以使用函数numpy.dtype创建结构化数据类型。有 4 种替代形式的规范,其灵活性和简洁性各不相同。

(1)元组列表,每个字段一个元组

每个元组都有形式(fieldname, datatype, 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')])

这会自动确定结构中字段的字节偏移量和总结构项大小。

(2)一串逗号分隔的 dtype 规范

在此速记表示法中,任何字符串 dtype 规范都可以在字符串中使用并用逗号分隔。字段的项大小和字节偏移量是自动确定的,字段名称被赋予默认名称 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))])

(3)字段参数数组字典

这是最灵活的规范形式,因为它允许控制字段的字节偏移量和结构的 itemsize。

字典有两个必需的键,“名称”和“格式”,以及四个可选键,“偏移”,“itemsize”,“对齐”和“标题”。“名称”和“格式”的值应分别是相同长度的字段名称列表和 dtype 规范列表。可选的“偏移量”值应该是整数字节偏移量的列表,结构中的每个字段对应一个。如果未给出“偏移量”,则自动确定偏移量。可选的“itemsize”值应是一个整数,用于描述 dtype 的总大小(以字节为单位),该大小必须足够大以包含所有字段。

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_类型的字段不能与其他字段重叠,因为存在破坏内部对象指针然后取消引用它的风险。

(4)字段名称字典

字典的键是字段名称,值是指定类型和偏移量的元组:

np.dtype({'col1': ('i1', 0), 'col2': ('f4', 1)})
dtype([('col1', 'i1'), ('col2', '<f4')])

不鼓励这种形式,因为 Python 字典在 Python 3.6 之前没有保留 Python 版本中的顺序。

② 操作和显示结构化数据类型

结构化数据类型的字段名称列表可以在 dtype 对象的 names 属性中找到:

d = np.dtype([('x', 'i8'), ('y', 'f4')])
d.names
('x', 'y')

可以通过使用相同长度的字符串序列分配给 names 属性来修改字段名称。

dtype 对象还具有类似字典的属性 fields,其键是字段名称(和字段标题),其值是包含每个字段的 dtype 和字节偏移量的元组。

d.fields
mappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)})

对于非结构化数组,namesfields属性都将等于 None。测试dtype是否结构化的推荐方法是使用如果dt.names不是None,而不是如果dt.names,以考虑具有0个字段的dtype。

如果可能的话,结构化数据类型的字符串表示形式显示在“元组列表”形式中,否则 numpy 会回退到使用更通用的字典形式。

③ 自动字节偏移和对齐

Numpy 使用两种方法之一自动确定结构化数据类型的字段字节偏移量和整体项大小,具体取决于 align=True 是否指定为 numpy.dtype 的关键字参数.

默认情况下 (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结构相同的方式填充结构。在某些情况下,对齐的结构可以提高性能,但代价是数据类型大小增加。在字段之间插入填充字节,以便每个字段的字节偏移量将是该字段对齐方式的倍数,

print_offsets(np.dtype('u1,u1,i4,u1,i8,u2', align=True))
offsets: [0, 1, 4, 8, 16, 24]
itemsize: 32

④ 字段标题

除了字段名称之外,字段还可能具有关联的标题,即备用名称,有时用作字段的附加描述或别名。标题可用于为数组编制索引,就像字段名称一样。

要在使用 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 字典将包含标题作为键(如果使用任何标题)。这实际上意味着带有标题的字段将在字段字典中表示两次。这些字段的元组值还将具有第三个元素,即字段标题。因此,并且由于 names 属性保留字段顺序,而字段属性可能不会,因此建议使用 dtype 的 names 属性遍历 dtype 的fields,该属性不会列出标题,names如下所示:

for name in d.fields:
    print(d.fields[name][:2])
(dtype('int64'), 0)
(dtype('float32'), 8)

⑤ 联合类型

默认情况下,结构化数据类型在 numpy 中实现为基本类型 numpy.void,但可以使用数据类型对象中描述的 (base_dtype, dtype) 形式将其他 numpy 类型解释为结构化类型。在这里,base_dtype是所需的底层 dtype,字段和标志将从 dtype 复制。这个 dtype 类似于 C 中的“联合”。

【3】结构化数组的索引和赋值

有多种方法可以为结构化数组赋值:使用 python 元组、使用标量值或使用其他结构化数组。

- 将数据分配给结构化数组

① 来自Python本机类型(元组)的赋值

为结构化数组赋值的最简单方法是使用 python 元组。每个分配的值都应该是一个长度等于数组中字段数的元组,而不是列表或数组,因为这些将触发 numpy 的广播规则。元组的元素从左到右分配给数组的连续字段:

x = np.array([(1, 2, 3), (4, 5, 6)], dtype='i8,f4,f8')
print(x)
[(1, 2., 3.) (4, 5., 6.)]
x[1] = (7, 8, 9)
print(x)
[(1, 2., 3.) (7, 8., 9.)]

② 标量赋值

分配给结构化元素的标量将分配给所有字段。当标量分配给结构化数组或将非结构化数组分配给结构化数组时,会发生这种情况:

x = np.zeros(2, dtype='i8,f4,?,S1')
print(x)
[(0, 0., False, b'') (0, 0., False, b'')]
x[:] = 3
print(x)
[(3, 3.,  True, b'3') (3, 3.,  True, b'3')]
x[:] = np.arange(2)
print(x)
[(0, 0., False, b'0') (1, 1.,  True, b'1')]

结构化数组也可以分配给非结构化数组,但前提是结构化数据类型只有一个字段:

onefield = np.zeros(2, dtype=[('A', 'i4')])
nostruct = np.zeros(2, dtype='i4')
print(nostruct)
[0 0]

③ 来自其他结构化数组的赋值

两个结构化数组之间的赋值就像源元素已转换为元组,然后分配给目标元素一样。也就是说,源数组的第一个字段分配给目标数组的第一个字段,第二个字段同样分配给目标数组的第一个字段,依此类推,而不考虑字段名称。具有不同字段数的结构化数组不能相互分配。目标结构中未包含在任何字段中的字节不受影响。

a = np.zeros(3, dtype=[('a', 'i8'), ('b', 'f4'), ('c', 'S3')])
a
array([(0, 0., b''), (0, 0., b''), (0, 0., b'')],
      dtype=[('a', '<i8'), ('b', '<f4'), ('c', 'S3')])
b = np.ones(3, dtype=[('x', 'f4'), ('y', 'S3'), ('z', 'O')])
b
array([(1., b'1', 1), (1., b'1', 1), (1., b'1', 1)],
      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
array([(1, 2.), (3, 4.)], dtype=[('foo', '<i8'), ('bar', '<f4')])
x['foo']
array([1, 3], dtype=int64)
x['foo'] = 10
x
array([(10, 2.), (10, 4.)], dtype=[('foo', '<i8'), ('bar', '<f4')])

生成的数组是原始数组的视图。它共享相同的内存位置,写入视图将修改原始数组。

y = x['bar']
y
array([2., 4.], dtype=float32)
y[:] = 11
y
array([11., 11.], dtype=float32)
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
array([[(0, [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]),
        (0, [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]])],
       [(0, [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]),
        (0, [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]])]],
      dtype=[('a', '<i4'), ('b', '<f8', (3, 3))])
x['a'].shape
(2, 2)
x['b'].shape
(2, 2, 3, 3)

② 访问多个字段

可以索引并分配给具有多字段索引的结构化数组,其中索引是字段名称的列表。

使用多字段索引进行索引的结果是原始数组的视图,如下所示:

a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'f4')])
a
array([(0, 0, 0.), (0, 0, 0.), (0, 0, 0.)],
      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,并且具有与原始数组中相同的偏移量,并且仅缺少未编制索引的字段。

分配给具有多字段索引的数组会修改原始数组:

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']]
a
array([(3, 0, 2.), (3, 0, 2.), (3, 0, 2.)],
      dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<f4')])

③ 使用整数进行索引以获取结构化标量

索引结构化数组的单个元素(使用整数索引)将返回结构化标量:

x = np.array([(1, 2., 3.)], dtype='i,f,f')
x
array([(1, 2., 3.)], dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<f4')])
scalar = x[0]
scalar
(1, 2., 3.)
type(scalar)
numpy.void

与其他 numpy 标量不同,结构化标量是可变的,其作用类似于原始数组的视图,因此修改标量将修改原始数组。结构化标量还支持按字段名称进行访问和分配:

x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
x
array([(1, 2.), (3, 4.)], dtype=[('foo', '<i8'), ('bar', '<f4')])
s = x[0]
s
(1, 2.)
s['bar'] = 100
s
(1, 100.)
x
array([(1, 100.), (3,   4.)], dtype=[('foo', '<i8'), ('bar', '<f4')])

与元组类似,结构化标量也可以使用整数进行索引:

scalar = np.array([1, 2., 3.], dtype='i,f,f')[0]
scalar
(1, 1., 1.)
scalar[0]
1
scalar[1] = 4
scalar
(1, 4., 1.)

因此,元组可能被认为是与numpy的结构化类型等效的本机Python,就像本机python整数等效于numpy的整数类型一样。结构化标量可以通过调用numpy.ndarray.item转换为元组:

scalar.item(), type(scalar.item())
((1, 4.0, 1.0), tuple)
- 查看包含对象的结构化数组

为了防止在对象类型的字段中破坏object指针,numpy 目前不允许包含对象的结构化数组的视图。

- 结构比较与推广

如果两个 void 结构化数组的 dtype 相等,则测试数组的相等性将导致具有原始数组维度的布尔数组,其中元素设置为 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 和 np.promote_types 返回的通用 dtype。这将强制字段数、字段名称和字段标题必须精确匹配。当无法升级时,例如由于字段名称不匹配,NumPy 将引发错误。两个结构化 dtype 之间的提升会产生一个规范的 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

升级多个 dtype 时,如果任何输入为:

np.result_type(np.dtype("i,i"), np.dtype("i,i", align=True))
dtype([('f0', '<i4'), ('f1', '<i4')], align=True)

<比较空结构化数组时,<运算符和>运算符始终返回 False,并且不支持算术和按位运算。

【4】记录数组

作为可选的便利,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
rec.array([(1, 2., b'Hello'), (2, 3., b'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])
recordarr.foo[1:2]
array([2])
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)
recordarr
rec.array([(1, 2., b'Hello'), (2, 3., b'World')],
          dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])

可以使用适当的视图获得结构化数组的记录数组表示形式:

arr = np.array([(1, 2., 'Hello'), (2, 3., "World")], dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'a10')])
recordarr = arr.view(dtype=np.dtype((np.record, arr.dtype)), type=np.recarray)
recordarr
rec.array([(1, 2., b'Hello'), (2, 3., b'World')],
          dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])

为方便起见,将 ndarray 视为 numpy.recarray 类型将自动转换为 numpy.recarray 数据类型,因此可以将 dtype 排除在视图之外:numpy.record

recordarr = arr.view(np.recarray)
recordarr.dtype
dtype((numpy.record, [('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')]))

要返回到普通的 ndarray,必须重置 dtype 和 type。以下视图这样做,考虑到记录者不是结构化类型的异常情况:

arr2 = recordarr.view(recordarr.dtype.fields or recordarr.dtype, np.ndarray)
arr2
array([(1, 2., b'Hello'), (2, 3., b'World')],
      dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])

如果按索引或按属性访问的记录数组字段具有结构化类型,则作为记录数组返回,否则作为纯 ndarray 返回。

recordarr = np.rec.array([('Hello', (1, 2)), ("World", (3, 4))],
                         dtype=[('foo', 'S6'), ('bar', [('A', int), ('B', int)])])
type(recordarr.foo)
numpy.ndarray
type(recordarr.bar)
numpy.recarray

注意,如果字段与 ndarray 属性同名,则 ndarray 属性优先。此类字段将无法按属性访问,但仍可通过索引访问。

① Recarray Helper 函数

用于操作结构化数组的实用程序集合。

这些函数中的大多数最初是由 John Hunter 为 matplotlib 实现的。为方便起见,它们已被重写和扩展。

(1) numpy.lib.recfunctions.append_fields(base, names, data, dtypes=None, fill_value=-1, usemask=True, asrecarray=False)[来源]

向现有数组添加新字段。

字段的名称与名称参数一起给出,相应的值与数据参数一起给出。如果附加单个字段,则名称、数据和 dtype 不必是列表,而只需是值。

(2)numpy.lib.recfunctions.apply_along_fields(func, arr)

应用函数“func”作为结构化数组字段的缩减。

这类似于apply_along_axis,但将结构化数组的字段视为额外的轴。这些字段首先按照应用于字段 dtype 的类型提升规则numpy.result_type强制转换为通用类型。

举个栗子

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. ])

(3)numpy.lib.recfunctions.assign_fields_by_name(dst, src, zero_unassigned=True)
按字段名称将值从一个结构化数组分配给另一个结构化数组。

通常在numpy >= 1.14中,将一个结构化数组分配给另一个结构化数组会“按位置”复制字段,这意味着src中的第一个字段被复制到dst的第一个字段,依此类推,无论字段名称如何。

此函数改为复制“按字段名称”,以便从 src 中同名的字段分配 dst 中的字段。这以递归方式应用于嵌套结构。这就是结构赋值在 numpy >= 1.6 到 <= 1.13 中的工作方式。

举个栗子

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)])])
a
array([(1, (2., 3)), (4, (5., 6))],
      dtype=[('a', '<i8'), ('b', [('ba', '<f8'), ('bb', '<i8')])])
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')])

(4)numpy.lib.recfunctions.find_duplicates(a, key=None, ignoremask=True, return_index=False)

沿着给定键查找结构化数组中的重复项

举个栗子

from numpy.lib import recfunctions as rfn
ndtype = [('a', int)]
ndtype
[('a', int)]
a = np.ma.array([1, 1, 1, 2, 2, 3, 3], mask=[0, 0, 1, 0, 0, 0, 1]).view(ndtype)
a
masked_array(data=[(1,), (1,), (--,), (2,), (2,), (3,), (--,)],
             mask=[(False,), (False,), ( True,), (False,), (False,),
                   (False,), ( True,)],
       fill_value=(999999,),
            dtype=[('a', '<i4')])
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', '<i4')]),
 array([0, 1, 3, 4], dtype=int64))

(5)numpy.lib.recfunctions.flatten_descr(NDTYPE)

平展结构化数据类型说明。

举个栗子

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')))

(6)numpy.lib.recfunctions.get_fieldstructure(广告类型,姓氏=无,父==无)

返回一个字典,其中包含为其父字段列表编制索引的字段。

此函数用于简化对嵌套在其他字段中的字段的访问。

举个栗子

from numpy.lib import recfunctions as rfn
ndtype = np.dtype([('A', int),
                   ('B', [('BA', int),
                          ('BB', [('BBA', int), ('BBB', int)])])])
rfn.get_fieldstructure(ndtype)
{'A': [],
 'B': [],
 'BA': ['B'],
 'BB': ['B'],
 'BBA': ['B', 'BB'],
 'BBB': ['B', 'BB']}

(7)numpy.lib.recfunctions.get_names(广告类型)

以元组形式返回输入数据类型的字段名称。输入数据类型必须具有字段,否则将引发错误。

举个栗子

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')))

(8)numpy.lib.recfunctions.get_names_flat(广告类型)

以元组形式返回输入数据类型的字段名称。输入数据类型必须具有字段,否则将引发错误。嵌套结构事先被展平。

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')

(9)numpy.lib.recfunctions.join_by(key, r1, r2, jointype=‘inner=’, r1postfix=‘1’, =r2postfix=‘2’, defaults=无=,使用掩码=真,asrecarray=假)

在键上联接数组 r1 和 r2.

键应为字符串或与用于连接数组的字段对应的字符串序列。如果在两个输入数组中找不到键字段,则会引发异常。r1 和 r2 都不应该有任何重复键:重复项的存在会使输出非常不可靠。请注意,算法不会查找重复项。

(10)numpy.lib.recfunctions.merge_arrays(seqarrays, fill_value=-1, flattenFalse, asrecarray=False)

逐个字段合并数组。

举个栗子

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', '<i4'), ('f1', '<f8')])
rfn.merge_arrays((np.array([1, 2], dtype=np.int64),
                  np.array([10., 20., 30.])), usemask=False)
array([( 1, 10.), ( 2, 20.), (-1, 30.)],
      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([(8589934593, 10.), (        -1, 20.), (        -1, 30.)],
          dtype=[('a', '<i8'), ('f1', '<f8')])

(11)numpy.lib.recfunctions.rec_append_fields(基数、名称、数据、dtypes=None)

向现有数组添加新字段。

字段的名称与名称参数一起给出,相应的值与数据参数一起给出。如果附加单个字段,则名称、数据和 dtype 不必是列表,而只需是值。

(12)numpy.lib.recfunctions.rec_drop_fields(底座,drop_names)

返回一个新的 numpy.recarray drop_names删除了字段。

(13)numpy.lib.recfunctions.rec_join(key, r1, r2, jointype=‘inner=’, r1postfix=‘1’, =r2postfix=‘2’, defaults=无)

在键上联接数组 r1 和 r2。join_by的替代方法,它总是返回一个 np.recarray。

(14)numpy.lib.recfunctions.recursive_fill_fields(输入、输出))

使用输入中的字段填充输出中的字段,并支持嵌套结构。

举个栗子

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')])

(15)numpy.lib.recfunctions.rename_fields(base, namemapper)

重命名灵活数据类型 ndarray 或 recarray 中的字段。

支持嵌套字段。

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', '<i4'), ('b', [('ba', '<f8'), ('BB', '<f8', (2,))])])

(16)numpy.lib.recfunctions.repack_fields(a, align==False, recurse=False)
将结构化数组或 dtype 的字段重新打包到内存中。

结构化数据类型的内存布局允许任意字节偏移的字段。这意味着字段可以通过填充字节分隔,它们的偏移量可以非单调增加,并且可以重叠。

此方法删除任何重叠并重新排序内存中的字段,以便它们具有增加的字节偏移量,并根据对齐选项添加或删除填充字节,其行为类似于 numpy.dtype 的对齐选项.

如果 align=False,此方法将生成一个“打包”内存布局,其中每个字段从前一个字段结束的字节开始,并删除任何填充字节。

如果 align=True,则此方法通过根据需要添加填充字节来生成“对齐”内存布局,其中每个字段的偏移量是其对齐方式的倍数,而总 itemsize 是最大对齐方式的倍数。

举个栗子

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([('f0', 'u1'), ('f1', '<i8'), ('f2', '<f8')], 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

(17)numpy.lib.recfunctions.require_fields(数组,required_dtype)
使用字段名称赋值将结构化数组强制转换为新的 dtype。

此函数按名称从旧数组分配给新数组,因此输出数组中字段的值是源数组中同名字段的值。这具有创建一个新的 ndarray 的效果,该数组仅包含required_dtype“必需”的字段。

如果输入数组中不存在required_dtype中的字段名称,则会创建该字段并在输出数组中设置为 0。

举个栗子

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')])

(18)numpy.lib.recfunctions.stack_arrays(arrays, defaults=None, usemask=True=, asrecarray==False, autoconvert=False)
按字段叠加数组字段

举个栗子

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', 1.e+20, 1.e+20),
            dtype=[('A', 'S3'), ('B', '<f8'), ('C', '<f8')])

(19)numpy.lib.recfunctions.structured_to_unstructured(arr, dtype=None, copy=False=, casting=‘unsafe’)
将 n-D 结构化数组转换为 (n+1)-D 非结构化数组。

新数组将具有一个新的最后一个维度,其大小等于输入数组的字段元素数。如果未提供,则输出数据类型由应用于所有字段数据类型的 numpy 类型升级规则确定。

嵌套字段以及任何子数组字段的每个元素都算作单个字段元素。

举个栗子

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. ])

(20)numpy.lib.recfunctions.unstructured_to_structured(arr, dtypeFalse, copy=False,铸造=“不安全”)
将 n-D 非结构化数组转换为 (n-1)-D 结构化数组。

输入数组的最后一个维度被转换为一个结构,其字段元素的数量等于输入数组最后一个维度的大小。默认情况下,所有输出字段都具有输入数组的 dtype,但可以提供具有相同数量的字段元素的输出结构化 dtype。

嵌套字段以及任何子数组字段的每个元素都计入字段元素的数量。

举个栗子

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,))])
12-23 07:15