「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」
前言
numpy 库中核心对象是可以表示N维数组ndarray。ndarray 拥有同类型的数据块,并且每个数据块内存大小相同且存储在一段连续的物理地址,使其在科学计算领域内占据主导地位。
但是,面对不同类型的数据块存放需求,numpy 参考C语言的结构概念,提供“结构化数组”。我们在上一篇 numpy之结构化数据类型中,知晓了 numpy 结构化数组是由一系列的数据类型组成的命名字段的ndarray,并且同样可以共享内存空间。
numpy 结构化数组与普通数组区别在于,结构化数组的数据类型。在上一篇文章中,我们知道结构化数据类型是一段长度的字节序列(itemsize),是有一系列的字段的集合。
结构化数据类型的每一个字段有字段名(name),数据类型(datatype)和字节偏移量(offset)组成。并且可以使用numpy.dtype()方法创建结构化数据类型,一共有四种方法可以选择使用。
既然我们都已学习了结构化数据类型的创建,本期,我们将继续学习如何查询结构化数据类型相关信息及相关注意事项,Let's go~~
1. 结构化数据类型字段名
结构化数据类型是由一系列的字段组成的。字段是主要由name、datatype和offset
- 在结构化数据类型字段名中,我们可以通过 names 这个属性显示。
- names 属性在 dtype 对象的属性中
- names 属性查询到的是长度相同的字符串的序列
- 结构化数据类型字段名称可以通过names赋值的字符串序列进行修改
>>> stu_type = np.dtype({"names":["name","age"],"formats":["S6","i4"],"offsets":[2,3],"itemsize":12})
>>> stu_type.names
('name', 'age')
>>> stu_type.names = ("name1","age1")
>>> stu_type
dtype({'names':['name1','age1'], 'formats':['S6','<i4'], 'offsets':[2,3], 'itemsize':12})
>>>
我们可以查看numpy 官方文档中,对dtype 对象进行相关的说明,dtype是创建描述数据类型对象。
dtype对象包含常见的属性如下:
| 属性 | 说明 |
|---|---|
| dtype.name | 描述字段名称 |
| dtype.names | 字段名称列表 |
| dtype.ndim | 子数组的维数,否则 |
| dtype.shape | 描述数组的形状 |
| dtype.flags | 描述解释数据类型的位标志 |
| dtype.fields | 数组命字段字典 |
| dtype.base | 数组数据来源 |
| dtype.alignment | 数组的字节偏移量 |
在 dtype 对象中有一个 fields 属性是类似字典的属性,fields key 值是字段名称,value 值是每个字段的datatype和字节偏移量的元组
>>> stu_type
dtype({'names':['name1','age1'], 'formats':['S6','<i4'], 'offsets':[2,3], 'itemsize':12})
>>> stu_type.fields
mappingproxy({'name1': (dtype('S6'), 2), 'age1': (dtype('int32'), 3)})
>>>
对于普通数组,names和fields属性内容是相同的,如我们查询一维数组names和fields都是None:
>>> y = np.array([1,2,3,4])
>>> y.dtype.names
>>> print(y.dtype.names)
None
>>> print(y.dtype.fields)
None
>>>
所以,判断一个数组是否是结构化,我们可以通过 dtype.names来查询
如果是结构化数组类型的字符串结果会返回以元组形式显示。
2. 字节自动偏移和对齐
numpy 结构化数组依赖numpy.dtype 的align=True的信息来进行字段自动偏移量和对齐功能。
numpy.dtype中align 属性值默认是False时
- numpy 会将字段打包在一起
- 字段在内存中是连续存储的
- 每个字段按照从前一个字段的字节偏移量开始
>>> d = np.dtype("S1,S1,U1,i4,S1,i8")
>>> [d.fields[name][1] for name in d.names]
[0, 1, 2, 6, 10, 11]
>>> d.itemsize
19
>>>
当 align 为True时,可以将字段进行自动对齐
- numpy 将采用C编译器C-strue方法进行填充结构
- 填充策略采用字节间插入填充,以便每个字节的偏移量将是该字段对齐的倍数
- 对于简单数据类型来说,将等于字段的字节大小
- 如果项目中大小不是最大字段对齐的倍数,则还需要进行字段尾部填充
- 填充可以使字段进行对齐提高性能,但是会整机数据类型大小
>>> d = np.dtype("S1,S1,U1,i4,S1,i8",align=True)
>>> [d.fields[name][1] for name in d.names]
[0, 1, 4, 8, 12, 16]
>>> d.itemsize
24
>>>
numpy 结构化数组的 offsets 如果使用是基于 dtype 中可选键指定偏移量,则需要设置align = True。则系统内部需要检查每个字段的偏移量是否是其大小的倍数。项目大小是最大字段的大小的倍数,否则就会触发异常。
3. 字段标题
字段除字段名称外,还包含关联的字段标题。
- 字段标题,作为字段名称的附加描述
- 字段标题可以用于索引,与字段名称一样使用
如果在dtype里需要添加字段标题时,需要分情况:
-
当使dtype 使用元组形式时,需要再添加一个元组形式如(字段名称,字段标题)包含起来
>>> stu_type = np.dtype([(("name","nickname"),"S1")]) >>> stu_type dtype([(('name', 'nickname'), 'S1')]) >>> -
当使用字段参数字典形式时,可以添加titles键来定义
>>> stu_type = np.dtype({"names":["name","age"],"titles":["nickname","age1"],"formats":["S6","i4"],"offsets":[2,3],"itemsize":12}) >>> stu_type dtype({'names':['name','age'], 'formats':['S6','<i4'], 'offsets':[2,3], 'titles':['nickname','age1'], 'itemsize':12}) >>> -
当使用字段名字典形式时,则需要采用(datatype,offset,title)这样的形式来添加标题
>>> stu_type = np.dtype({"name":("S6",0,"nickname"),"age":("i8",1)}) >>> stu_type dtype({'names':['name','age'], 'formats':['S6','<i8'], 'offsets':[0,1], 'titles':['nickname',None], 'itemsize':9}) >>>
结构化数组中如果包含了标题字段,则fields属性查询可以看到在内部存储两次。
我们使用遍历names属性,查询到fields列表中可以查看到带有标题的字段名。
>>> [stu_type.fields[name][:2] for name in stu_type.names]
[(dtype('S6'), 0), (dtype('int64'), 1)]
>>>
总结
本期,继续学习numpy 结构化数据类型字段相关信息,我们可以使用dtype.names 查询到结构化数组字段序列,dtype align=True 可以将结构化数组字段进行自动对齐。
同时,字段名还包含一个备选字段,字段标题。当字段设置有标题时,fields 字典中会表示两次。
以上是本期内容,欢迎大佬们点赞评论,下期见~