Python numpy 记录数组辅助方法二

895 阅读7分钟

image.png

「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战

前言

继上一节numpy 记录数组辅助方法,我们已经对 recarray 辅助方法学习了一些。我们都知道recarray 辅助方法是由 numpy.lib 中 recfunctions 模块提供一系列对创建和操作结构化的函数方法。

  • apply_along_fields() 方法可以使用应用函数缩减结构化数组中字段
  • append_fields() 方法将新字段添加到结构化数组
  • drop_fields() 方法在结构化数组中删除指定字段,并返回新数组
  • join_by() 方法通过key连接两个数组
  • merge_arrays()方法将数组列表进行合并

在使用合并数组列表中,数组的长度不一致时,系统合并过程中,系统会对较短的数组将缺失的值进行自动填充,填充的内容取决与它对应的类型。

填充值说明
-1整数类型
-1.0浮点数类型
"-"字符
'-1'字符串
True布尔值

本期,我们将继续学习 recfunctions 模块对结构化数组操作的相关方法,Let's go~

1. 获取结构化数组字段名称相关操作

recfunctions 模块还提供对结构化数据类型字段名称获取。

1.1 以字典形式返回字段名称

recfunctions 模块提供 get_fieldstructure() 方法对结构化数据类型字段以字典形式返回。

get_fieldstructure()方法对嵌入的结构化数据类似可以简化。

get_fieldstructure(adtype, lastname=None, parents=None,)

参数说明:

参数说明
adtype结构化数据类似np.dtype()
lastname最后处理字段名称,可选
parents父字段字典
>>> import numpy as np
>>> from numpy.lib import recfunctions as rfn
>>> arr_dtype = np.dtype([("A","i8"),("B","i8")])
>>> rfn.get_fieldstructure(arr_dtype)
{'A': [], 'B': []}
>>>

get_fieldstructure()方法对嵌入的结构化数据类似可以简化尤为明显。

>>> import numpy as np
>>> from numpy.lib import recfunctions as rfn
>>> stu_dtype = np.dtype([("school","S16"),("class",[("classA","S6"),("classB","S6")])])
>>> rfn.get_fieldstructure(stu_dtype)
{'school': [], 'class': [], 'classA': ['class'], 'classB': ['class']}
>>>

1.2 以元组形式返回字段名称

recfunctions 模块提供 get_names()方法,以元组形式返回结构化数据类型字段

get_names(adtype)

参数说明:

参数说明
adtype输入数据类型
>>> arr_dtype = np.dtype([("A","i8"),("B","i8"),("C",[("C1","i8"),("C2","i4")])])
>>> rfn.get_names(arr_dtype)
('A', 'B', ('C', ('C1', 'C2')))
>>>

1.3 以元组展平形式返回字段名称

recfunctions 模块提供 get_name_flat() 对于嵌入结构的结构化数据类型字段名称为元组返回.

get_names_flat(adtype)

参数说明:

参数说明
adtype结构化数据类型

对比 get_names() 方法,对于嵌入字段名称,get_names_flat()方法返回时会取消嵌入结构,返回单元组。

>>> arr_dtype = np.dtype([("A","i8"),("B","i8"),("C",[("C1","i8"),("C2","i4")])])
>>> rfn.get_names(arr_dtype)
('A', 'B', ('C', ('C1', 'C2')))
>>> rfn.get_names_flat(arr_dtype)
('A', 'B', 'C', 'C1', 'C2')
>>>

2. 查找结构化数组重复项

recfunctions 模块提供 find_duplicates() 可以根据特定key结构化数组的重复项

find_duplicates(a, key=None, ignoremask=True, return_index=False)

参数说明:

参数说明
a输入数组
key用于检查重复性的字段的名称。默认为None
ignoremask是否舍弃数据
return_index是否返回重复值的索引

使用 find_duplicates() 方法时,数组需要使用np.ma.array()类型

>>> arr =np.ma.array([1,1,2,3,1,3,1],dtype = [("A","i8")])
>>> rfn.find_duplicates(arr)
masked_array(data=[(1,), (1,), (1,), (1,), (3,), (3,)],
             mask=[(False,), (False,), (False,), (False,), (False,),
                   (False,)],
       fill_value=(999999,),
            dtype=[('A', '<i8')])
>>>

如果使用np.array()创建的数据,进行查找重复项式时,系统会报AttributeError

>>> arr =np.array([1,1,2,3,1,3,1],dtype = [("A","i8")])
>>> rfn.find_duplicates(arr)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 6, in find_duplicates
  File "C:\Users\user\AppData\Roaming\Python\Python37\site-packages\numpy\lib\recfunctions.py", line 1388, in find_duplicates
    sorteddata = sortedbase.filled()
AttributeError: 'numpy.ndarray' object has no attribute 'filled'

3. 字段名称赋值

recfunctions 模块还提供 assign_fields_by_name()方法,可以将数组A的字段值赋值给数组B。

  • assign_fields_by_name()方法是按字段名复制的,从源数组中字段复制给目标字段分配。
  • 该方法使用递归,非常适合嵌套结构的结构化数组
assign_fields_by_name(dst, src, zero_unassigned=True)

参数说明:

参数说明
dst源数组
src目标数组
zero_unassigned可选,如果为True。dst中src中没有匹配的字段将填充为0
>>> arr =np.array([1,1,2,3,1,3,1],dtype = [("A","i8")])
>>> arr2 =np.array([10,10,20,30,1,3,1],dtype = [("A","i8")])
>>> rfn.assign_fields_by_name(arr,arr2)
>>> arr
array([(10,), (10,), (20,), (30,), ( 1,), ( 3,), ( 1,)],
      dtype=[('A', '<i8')])
>>>

注意 dst 和 src 数组必须要保持同shape的,否则系统会报ValueError

>>> arr =np.array([1,1,2,3,1,3,1],dtype = [("A","i8")])
>>> arr2 = np.array([(1,2),(3,3),(1,2)],dtype=[("A","i8"),("B","i8")])
>>> rfn.assign_fields_by_name(arr2,arr)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 6, in assign_fields_by_name
  File "C:\Users\user\AppData\Roaming\Python\Python37\site-packages\numpy\lib\recfunctions.py", line 1200, in assign_fields_by_name

    zero_unassigned)
  File "<__array_function__ internals>", line 6, in assign_fields_by_name
  File "C:\Users\user\AppData\Roaming\Python\Python37\site-packages\numpy\lib\recfunctions.py", line 1191, in assign_fields_by_name

    dst[...] = src
ValueError: could not broadcast input array from shape (7) into shape (3)
>>>

4. 字段折叠

recfunctions 模块将数组列表字段进行叠加,返回一个新数组。

stack_arrays(arrays, defaults=None, usemask=True, asrecarray=False,
                 autoconvert=False)

参数说明:

参数说明
arrays数组或者数组序列
defaults字典类型,将字段名映射到相应的默认值
usemask是否返回掩码数组
asrecarray是否返回记录数组
autoconvert是否自动将字段的类型转换为最大值
>>> arr =np.array([1,1,2,3,1,3,1],dtype = [("A","i8")])
>>> arr2 = np.array([(1,2),(3,3),(1,2)],dtype=[("A","i8"),("B","i8")])
>>> new_arr = rfn.stack_arrays((arr,arr2))
>>> new_arr
masked_array(data=[(1, --), (1, --), (2, --), (3, --), (1, --), (3, --),
                   (1, --), (1, 2), (3, 3), (1, 2)],
             mask=[(False,  True), (False,  True), (False,  True),
                   (False,  True), (False,  True), (False,  True),
                   (False,  True), (False, False), (False, False),
                   (False, False)],
       fill_value=(999999, 999999),
            dtype=[('A', '<i8'), ('B', '<i8')])
>>>

注意:在数组序列字段叠加过程中,字段名称缺少的值,系统会默认填充"--"

5. 结构化与非结构化转换

recfunctions 模块中还支持对结构化数组与非结构化数组相互转换的方法。

5.1 结构化转换成非结构化

recfunctions 模块提供 structured_to_unstructured()方法将结构化数组转换成非结构化数组。

  • structured_to_unstructured()方法将n结构化数组转换(n+1)D非结构化数组
  • 新数组将一个新的最后一维,其大小等于输入数组的字段元素数
  • 如果未提供输出数据类型,则系统会按照numpy 数据类型规则确定
structured_to_unstructured(arr, dtype=None, copy=False, casting='unsafe')

参数说明:

参数说明
arr结构化数组
dtype指定输出非结构化数组的dtype
copy默认为false,如果为True,则会返回一个副本,否则返回视图
casting可选项,可选值有"no","equiv","safe","some_kind","unsafe",控制数据类型转换情况
>>> arr =np.array([1,1,2,3,1,3,1],dtype = [("A","i8")])
>>> arr
array([(1,), (1,), (2,), (3,), (1,), (3,), (1,)], dtype=[('A', '<i8')])
>>> rfn.structured_to_unstructured(arr)
array([[1],
       [1],
       [2],
       [3],
       [1],
       [3],
       [1]], dtype=int64)
>>> arr2 = np.array([(1,2),(3,3),(1,2)],dtype=[("A","i8"),("B","i8")])
>>> rfn.structured_to_unstructured(arr2)
array([[1, 2],
       [3, 3],
       [1, 2]], dtype=int64)
>>>

5.2 非结构化转换成结构化

recfunctions 模块也提供支持将非结构化数组转换成结构化数组的unstructured_to_structured()方法。

  • 该方法将n维非结构化数组转换成(n-1)维结构化数组
  • 输入的数组的最后一维被转换成一个结构,字段元素的数量等于输入数组最后一维的大小
  • 默认情况,输出的字段都具有输入数组的dtype 。
  • 可以提供输出结构化的dtype字段
unstructured_to_structured(arr, dtype=None, names=None, align=False,
                               copy=False, casting='unsafe')

参数说明:

参数说明
arr非结构化数组
dtype要输出的结构化数组dtype
names字符串列表
align是否创建对齐内存布局
copy是否要返回一个副本
casting控制发生的数据类型转换
>>> arr = np.array([(1,2),(3,3),(1,2)])
>>> arr_dtype = np.dtype([("A","i8"),("B","i8")])
>>> rfn.unstructured_to_structured(arr)
array([(1, 2), (3, 3), (1, 2)], dtype=[('f0', '<i4'), ('f1', '<i4')])
>>> rfn.unstructured_to_structured(arr,arr_dtype)
array([(1, 2), (3, 3), (1, 2)], dtype=[('A', '<i8'), ('B', '<i8')])
>>>

总结

本期,我们已经对recfunctions 模块提供对结构化数组操作如可使用stack_arrays()方法将数组序列字段进行叠加,返回新数组。并且我们可以使用unstructured_to_structured()将非结构化数组转换成结构化数组,structured_to_unstructured将结构化数组转换成非结构化数组。

recarray 辅助方法可以帮助我们更好使用结构化数组,在实际工作中大家多多使用。

以上是本期内容,欢迎大佬们点赞评论,下期见~