结构化数组是数据类型由简单数据类型组成的ndarrays,这些数据类型组织为一个名为 fields . 例如:
>>> 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”和3的32位整数。名为“weight”的32位浮点。
x
如果你索引 x 在位置1,你得到一个结构:
>>> x[1] ('Fido', 3, 27.0)
通过使用字段名进行索引,可以访问和修改结构化数组的各个字段:
>>> 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语言中的“结构”,并共享类似的内存布局。它们用于与C代码接口,以及对结构化缓冲区的低级操作,例如解释二进制blob。为了实现这些目的,它们支持诸如子数组、嵌套数据类型和联合等特殊功能,并允许控制结构的内存布局。
希望处理表格数据(如存储在csv文件中)的用户可能会发现其他pydata项目更适合,如xarray、pandas或dataarray。这些为表格数据分析提供了一个高级接口,并针对该用途进行了更好的优化。例如,在numpy中,结构化数组的类C结构内存布局相比之下,可能会导致较差的缓存行为。
结构化数据类型可以看作是一个特定长度的字节序列(结构的 itemsize )它被解释为字段的集合。每个字段在结构中都有一个名称、一个数据类型和一个字节偏移量。字段的数据类型可以是任何numpy数据类型,包括其他结构化数据类型,也可以是 subarray data type 其行为类似于指定形状的ndarray。场的偏移量是任意的,甚至可能重叠。这些偏移通常由numpy自动确定,但也可以指定。
可以使用函数创建结构化数据类型 numpy.dtype . 规范有4种可选形式,在灵活性和简洁性上各不相同。这些进一步记录在 Data Type Objects 参考页,总结如下:
numpy.dtype
元组列表,每个字段一个元组
每个元组都有这样的形式 (fieldname, datatype, shape) 其中形状是可选的。 fieldname 是字符串(或元组,如果使用了标题,请参见 Field Titles 下面) datatype 可以是任何可转换为数据类型的对象,并且 shape 是指定子数组形状的整数元组。
(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开始计算::
''
f#
#
>>> np.dtype([('x', 'f4'), ('', 'i4'), ('z', 'i8')]) dtype([('x', '<f4'), ('f1', '<i4'), ('z', '<i8')])
结构中字段的字节偏移量和总结构项大小是自动确定的。
逗号分隔的数据类型规范字符串
在这个速记法中 string dtype specifications 可以用在字符串中,并用逗号分隔。字段的itemsize和byte偏移量将自动确定,字段名将被赋予默认名称。 f0 , f1 等::
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))])
字段参数数组的字典
这是最灵活的规范形式,因为它允许控制字段的字节偏移量和结构的项大小。
字典有两个必需的键:“名称”和“格式”,以及四个可选键:“偏移量”、“项大小”、“对齐”和“标题”。“name”和“formats”的值应分别是字段名列表和相同长度的数据类型规范列表。可选的“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_ 类型不能与其他字段重叠,因为可能会破坏内部对象指针,然后取消对其的引用。
numpy.object_
可选的“对齐”值可以设置为 True 要使自动偏移计算使用对齐偏移(请参见 自动字节偏移和对齐 ,就好像 numpy.dtype 已设为真。
True
可选的“标题”值应该是与“名称”长度相同的标题列表,请参见 Field Titles 下面。
字段名词典
不鼓励使用这种形式的规范,但这里记录了这些规范,因为旧的numpy代码可能会使用它。字典的键是字段名,值是指定类型和偏移量的元组::
>>> np.dtype({'col1': ('i1', 0), 'col2': ('f4', 1)}) dtype([('col1', 'i1'), ('col2', '<f4')])
不鼓励使用此表单,因为python字典在python 3.6之前的版本中不保留顺序,并且结构化数据类型中字段的顺序具有意义。 Field Titles 可以通过使用3元组来指定,请参见下文。
结构化数据类型的字段名列表可以在 names dtype对象的属性:
names
>>> d = np.dtype([('x', 'i8'), ('y', 'f4')]) >>> d.names ('x', 'y')
可以通过将分配给 names 属性使用相同长度的字符串序列。
dtype对象还具有类似字典的属性, fields ,其键是字段名(和 Field Titles ,请参见下文),其值是包含每个字段的数据类型和字节偏移量的元组。::
fields
>>> d.fields mappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)})
两个 names 和 fields 属性将等于 None 对于非结构化数组。测试数据类型是否结构化的建议方法是 if dt.names is not None 而不是 if dt.names ,以说明具有0个字段的数据类型。
None
如果可能,结构化数据类型的字符串表示形式将显示在“元组列表”窗体中,否则numpy将返回到使用更通用的字典窗体。
numpy使用两种方法之一自动确定字段字节偏移量和结构化数据类型的总体项大小,具体取决于 align=True 被指定为的关键字参数 numpy.dtype .
align=True
默认情况下 (align=False ,numpy将把这些字段打包在一起,以便每个字段从上一个字段结束时的字节偏移量开始,并且这些字段在内存中是连续的。::
align=False
>>> 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是最大字段对齐方式的倍数。::
PyArray_Descr.alignment
>>> 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方面,以获得精确的对应关系。
如果使用可选的 offsets 输入基于字典的数据类型规范,设置 align=True 将检查每个字段的偏移量是否为其大小的倍数,以及项大小是否为最大字段大小的倍数,如果不是,则引发异常。
offsets
如果字段的偏移量和结构化数组的itemsize满足对齐条件,则数组将具有 ALIGNED flag 集合。
ALIGNED
flag
便利功能 numpy.lib.recfunctions.repack_fields 将对齐的数据类型或数组转换为压缩的数据类型或数组,反之亦然。它接受一个数据类型或结构化的ndarray作为参数,并返回一个带有重新打包的字段(有填充字节或没有填充字节)的副本。
numpy.lib.recfunctions.repack_fields
除了字段名之外,字段还可以有一个关联的 title ,备用名称,有时用作字段的附加说明或别名。标题可以用于索引数组,就像字段名一样。
要在使用数据类型规范的元组列表形式时添加标题,可以将字段名指定为两个字符串的元组,而不是单个字符串,后者分别是字段的标题和字段名。例如::
>>> np.dtype([(('my title', 'name'), 'f4')]) dtype([(('my title', 'name'), '<f4')])
当使用基于词典的规范的第一种形式时,标题可以作为额外的标题提供。 'titles' 键如上所述。当使用第二个(不鼓励使用的)基于字典的规范时,可以通过提供3元素元组来提供标题。 (datatype, offset, title) 而不是通常的2元素元组:
'titles'
(datatype, offset, title)
>>> np.dtype({'name': ('i4', 0, 'my title')}) dtype([(('my title', 'name'), '<i4')])
这个 dtype.fields 如果使用任何标题,字典将包含标题作为键。用一个字典表示一个字段将被有效地表示两次。这些字段的元组值还有第三个元素,字段标题。因为这个,因为 names 属性保留字段顺序,而 fields 属性不能,建议使用 names 不列出标题的数据类型的属性,如:
dtype.fields
>>> for name in d.names: ... print(d.fields[name][:2]) (dtype('int64'), 0) (dtype('float32'), 8)
结构化数据类型在numpy中实现为具有基类型 numpy.void 默认情况下,但可以使用 (base_dtype, dtype) 数据类型规范格式 Data Type Objects . 在这里, base_dtype 是所需的基础数据类型,字段和标志将从 dtype . 此数据类型类似于C中的“union”。
numpy.void
(base_dtype, dtype)
base_dtype
dtype
有许多方法可以为结构化数组赋值:使用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})
指定给视图将修改原始数组。视图的字段将按索引顺序排列。请注意,与单字段索引不同,视图的数据类型与原始数组具有相同的itemsize,并且具有与原始数组中相同偏移量的字段,未编制索引的字段只是丢失了。
在numpy 1.15中,使用多字段索引对数组进行索引时,返回了上面结果的副本,但将字段打包在内存中,就像通过 numpy.lib.recfunctions.repack_fields .
与1.15相比,numpy 1.16的新行为会在未索引字段的位置导致额外的“填充”字节。您将需要更新任何依赖于具有“打包”布局的数据的代码。例如,代码如下:
>>> 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
需要更改。此代码引发了 FutureWarning 自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
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])
对具有多字段索引的数组的赋值将修改原始数组::
>>> 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 (1, 2., 3.) >>> type(scalar) <class 'numpy.void'>
与其他numpy scalar不同,结构化scalar是可变的,在原始数组中的作用类似于视图,因此修改标量将修改原始数组。结构化标量还支持按字段名访问和分配:
>>> 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] 1 >>> scalar[1] = 4
因此,tuples可以被认为是与numpy的结构化类型等价的本机python,很像本机python整数与numpy的整数类型等价。结构化标量可以通过调用 numpy.ndarray.item ::
numpy.ndarray.item
>>> scalar.item(), type(scalar.item()) ((1, 4.0, 3.0), <class 'tuple'>)
为了防止在 object 类型,numpy当前不允许查看包含对象的结构化数组。
object
如果两个void结构化数组的数据类型相等,则测试数组的相等性将生成一个布尔数组,该数组的维数为原始数组的维数,元素设置为 True 相应结构的所有字段都相等。如果字段名、数据类型和标题相同,则结构化数据类型是相等的,而忽略了顺序,并且字段的顺序相同::
>>> a = np.zeros(2, dtype=[('a', 'i4'), ('b', 'i4')]) >>> b = np.ones(2, dtype=[('a', 'i4'), ('b', 'i4')]) >>> a == b array([False, False])
当前,如果两个void结构化数组的数据类型不相等,则比较失败,返回标量值 False . 此行为自numpy 1.10起已被弃用,将来将引发错误或执行元素比较。
False
这个 < 和 > 操作员总是返回 False 比较void结构化数组时,不支持算术和位运算。
<
>
作为可选的便利,numpy提供了一个ndarray子类, numpy.recarray 它允许按属性而不是仅按索引访问结构化数组的字段。记录数组使用特殊的数据类型, numpy.record ,允许对从数组中获得的结构化标量按属性进行字段访问。这个 numpy.rec 模块提供从各种对象创建重新排列的函数。可以在中找到用于创建和操作结构化数组的其他辅助函数 numpy.lib.recfunctions .
numpy.recarray
numpy.record
numpy.rec
创建记录数组的最简单方法是 numpy.rec.array ::
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 模块为创建记录数组提供了许多其他方便的函数,请参见 record array creation routines .
可以使用适当的 view ::
>>> 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)
为方便起见,将ndarray作为类型查看 numpy.recarray 将自动转换为 numpy.record 数据类型,因此可以将该数据类型从视图中删除::
>>> recordarr = arr.view(np.recarray) >>> recordarr.dtype dtype((numpy.record, [('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')]))
要返回普通的ndarray,必须重置dtype和type。考虑到recorderr不是结构化类型的异常情况,以下视图会执行此操作:
>>> 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.recarray'>
请注意,如果字段与ndarray属性同名,则以ndarray属性为准。这些字段将无法被属性访问,但仍可以被索引访问。
用于操作结构化数组的实用程序集合。
这些功能中的大部分最初是由JohnHunter为Matplotlib实现的。为了方便起见,它们被重写和扩展。
numpy.lib.recfunctions.
append_fields
将新字段添加到现有数组。
字段的名称与 names 参数,对应的值与 data 参数。如果附加了一个字段, names , data 和 dtypes 不必是列表,只需要值。
要扩展的输入数组。
与新字段名称对应的字符串或字符串序列。
存储要添加到基中的字段的数组或数组序列。
数据类型或数据类型序列。如果没有,数据类型将从 data .
填充值,用于填充较短数组上丢失的数据。
是否返回屏蔽数组。
是否返回recarray(maskedrecords)。
apply_along_fields
将函数“func”作为结构化数组字段间的归约。
这和 apply_along_axis ,但将结构化数组的字段视为一个额外的轴。所有字段都首先按照中的类型提升规则强制转换为公共类型 numpy.result_type 应用于字段的数据类型。
numpy.result_type
应用于“字段”维度的函数。此函数必须支持 axis 争论,就像np.平均值, np.总和等等。
要应用func的结构化数组。
手术结果
实例
>>> 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. ])
assign_fields_by_name
按字段名将值从一个结构化数组分配给另一个结构化数组。
通常在numpy>=1.14中,将一个结构化数组赋值给另一个数组会“按位置”复制字段,这意味着src的第一个字段会复制到dst的第一个字段,依此类推,而不考虑字段名。
相反,这个函数复制“按字段名”,这样dst中的字段就从src中同名的字段赋值。这将递归地应用于嵌套结构。这就是结构分配在numpy>=1.6到<1.13时的工作原理。
分配期间的源和目标数组。
如果为True,则dst中src中没有匹配字段的字段将用值0(零)填充。这是numpy<=1.13的行为。如果为False,则不会修改这些字段。
drop_fields
返回包含字段的新数组 drop_names 下降。
支持嵌套字段。
在 1.18.0 版更改: drop_fields 如果删除所有字段,则返回包含0个字段的数组,而不是返回 None 就像以前一样。
输入数组
与要删除的字段的名称相对应的字符串或字符串序列。
返回recarray还是mrecarray (asrecarray=True )或者是一个普通的、数据类型灵活的ndarray或masked数组。默认值为假。
>>> 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')])
find_duplicates
沿给定键查找结构化数组中的重复项
要检查重复项的字段的名称。如果没有,则按记录执行搜索
是否应丢弃屏蔽数据或将其视为重复数据。
是否返回重复值的索引。
>>> 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]))
flatten_descr
展平结构化数据类型描述。
>>> 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')))
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) ... # XXX: possible regression, order of BBA and BBB is swapped {'A': [], 'B': [], 'BA': ['B'], 'BB': ['B'], 'BBA': ['B', 'BB'], 'BBB': ['B', 'BB']}
get_names
以元组形式返回输入数据类型的字段名。
>>> from numpy.lib import recfunctions as rfn >>> rfn.get_names(np.empty((1,), dtype=int)) Traceback (most recent call last): ... AttributeError: 'numpy.ndarray' object has no attribute 'names'
>>> rfn.get_names(np.empty((1,), dtype=[('A',int), ('B', float)])) Traceback (most recent call last): ... AttributeError: 'numpy.ndarray' object has no attribute 'names' >>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])]) >>> rfn.get_names(adtype) ('a', ('b', ('ba', 'bb')))
get_names_flat
以元组形式返回输入数据类型的字段名。嵌套结构预先展平。
>>> from numpy.lib import recfunctions as rfn >>> rfn.get_names_flat(np.empty((1,), dtype=int)) is None Traceback (most recent call last): ... AttributeError: 'numpy.ndarray' object has no attribute 'names' >>> rfn.get_names_flat(np.empty((1,), dtype=[('A',int), ('B', float)])) Traceback (most recent call last): ... AttributeError: 'numpy.ndarray' object has no attribute 'names' >>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])]) >>> rfn.get_names_flat(adtype) ('a', 'b', 'ba', 'bb')
join_by
连接数组 r1 和 r2 在密钥上 key .
键应该是与用于联接数组的字段相对应的字符串或字符串序列。如果 key 在两个输入数组中找不到字段。既不 r1 也不 r2 应该有副本 key :存在重复项将使输出非常不可靠。请注意,算法不会查找重复项。
与用于比较的字段相对应的字符串或字符串序列。
结构化数组。
如果为“inner”,则返回R1和R2共用的元素。如果为“outer”,则返回公共元素以及不在r2中的r1元素和不在r2中的元素。如果“leftouter”,则返回公共元素和不在r2中的r1元素。
附加到R1字段名称后的字符串,这些字段存在于R2中,但缺少键。
附加到r2字段名称的字符串,这些字段存在于r1中,但不存在键。
字典将字段名映射到相应的默认值。
是否返回maskedArray(或maskedRecords是 asrecarray==True 或者一个nDAREL。
是否返回recarray(或maskedrecords if usemask==True )或者只是一个灵活的类型。
笔记
输出按键排序。
临时数组是通过删除两个数组键以外的字段并连接结果形成的。然后对该数组进行排序,并选择公共条目。通过用所选条目填充字段来构造输出。如果存在某些重复项,则不保留匹配…
merge_arrays
逐字段合并数组。
阵列序列
是否折叠嵌套字段。
如果没有遮罩,丢失的值将填充一些内容,具体取决于其对应的类型:
-1 整数
-1
-1.0 对于浮点数
-1.0
'-' 为人物
'-'
'-1' 弦乐
'-1'
True 对于布尔值
我刚从经验上得到这些值
>>> 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')])
rec_append_fields
参见
rec_drop_fields
返回一个新的numpy.recarray,其中字段位于 drop_names 下降。
rec_join
连接数组 r1 和 r2 在钥匙上。除了join_by之外,它始终返回np.recarray。
等效函数
recursive_fill_fields
用输入的字段填充输出的字段,并支持嵌套结构。
输入数组。
输出数组。
output should be at least the same size as input
>>> 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')])
rename_fields
从灵活的数据类型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', '<i8'), ('b', [('ba', '<f8'), ('BB', '<f8', (2,))])])
repack_fields
在内存中重新打包结构化数组或数据类型的字段。
结构化数据类型的内存布局允许字段具有任意字节偏移量。这意味着字段可以通过填充字节来分隔,它们的偏移量可以是非单调递增的,并且可以重叠。
此方法删除所有重叠,并对内存中的字段重新排序,使其具有不断增加的字节偏移量,并根据不同的类型添加或删除填充字节 align 选项,其行为类似于 align 选择权 np.dtype .
np.dtype
如果 align=False ,此方法生成一个“压缩”内存布局,其中每个字段从上一个字段结束的字节开始,并且删除所有填充字节。
如果 align=True ,此方法通过根据需要添加填充字节,生成一个“对齐”内存布局,其中每个字段的偏移量是其对齐方式的倍数,总itemsize是最大对齐方式的倍数。
要为其重新打包字段的数组或数据类型。
如果为true,则使用“对齐”内存布局,否则使用“打包”布局。
如果为True,请重新打包嵌套结构。
副本 a 重新打包字段,或 a 如果不需要重新包装的话。
>>> 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
require_fields
使用按字段名赋值将结构化数组强制转换为新的数据类型。
此函数按名称从旧数组分配给新数组,因此输出数组中字段的值就是源数组中同名字段的值。这样做的效果是创建一个新的ndarray,其中只包含所需数据类型的字段“required”。
如果输入数组中不存在所需数据类型中的字段名,则会创建该字段并在输出数组中将其设置为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')])
stack_arrays
按字段叠加数组字段
输入数组的序列。
是否自动将字段类型强制转换为最大值。
>>> 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')])
structured_to_unstructured
将n-D结构化数组转换为(n+1)-D非结构化数组。
新数组的最后一个维度的大小将与输入数组的字段元素数相等。如果未提供,则输出数据类型由应用于所有字段数据类型的numpy类型提升规则确定。
嵌套字段以及任何子数组字段的每个元素都算作单个字段元素。
要转换的结构化数组或数据类型。不能包含对象数据类型。
输出非结构化数组的数据类型。
请参见将参数复制到 ndarray.astype . 如果为true,请始终返回副本。如果为假,以及 dtype 满足需求时,将返回一个视图。
ndarray.astype
参见铸造参数 ndarray.astype . 控制可能发生的数据转换类型。
具有一个以上维度的非结构化数组。
>>> 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. ])
unstructured_to_structured
将n-D非结构化数组转换为(n-1)-D结构化数组。
将输入数组的最后一个维度转换为结构,字段元素的数量等于输入数组最后一个维度的大小。默认情况下,所有输出字段都具有输入数组的数据类型,但可以提供具有相同字段元素数的输出结构化数据类型。
嵌套字段以及任何子数组字段的每个元素都计入字段元素的数量。
要转换的非结构化数组或数据类型。
输出数组的结构化数据类型
如果未提供数据类型,则按顺序指定输出数据类型的字段名。字段数据类型将与输入数组相同。
是否创建对齐的内存布局。
维数较少的结构化数组。
>>> 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,))])