结构化数组的 dtype 必须显式指定字段名和类型;它按字段组织数据,非普通二维数组,需先定义 dtype 再构造数组,字段顺序、类型、命名均需严格匹配,访问应通过字段名而非位置索引。

结构化数组的 dtype 定义必须显式指定字段名和类型
NumPy 的 structured array 不是普通二维数组,它像数据库表一样按字段组织数据。如果只用 np.array([...]) 直接传入字典或元组列表,NumPy 会默认转成 object 类型,后续无法做向量化运算。
正确做法是先定义 dtype,再构造数组:
import numpy as np
dt = np.dtype([('name', 'U10'), ('age', 'i4'), ('score', 'f4')])
data = np.array([('Alice', 25, 89.5), ('Bob', 30, 92.0)], dtype=dt)
注意:'U10' 表示最多 10 个 Unicode 字符;'i4' 是 32 位整数;字段顺序和类型必须与数据严格匹配,否则会静默截断或填充零。
- 字段名不能是 Python 关键字(如
class、def),否则访问时语法报错 - 字符串字段推荐用
U(Unicode)而非S(bytes),避免编码问题 - 嵌套结构可用
dtype嵌套定义,但索引变复杂,日常少用
访问字段要用点号或方括号,不能用二维索引
结构化数组不是矩阵,arr[0][1] 这种写法会返回第一个记录的第二个字段值(依赖字段顺序),但语义模糊且易出错。应始终通过字段名访问:
print(data['name']) # ['Alice' 'Bob'] print(data['score'][0]) # 89.5
点号访问(data.name)更简洁,但字段名含空格或特殊字符时只能用方括号。
- 对字段切片(如
data['score'] > 90)返回布尔数组,可直接用于布尔索引 -
data[['name', 'score']]返回新结构化数组,仅含指定字段 - 不能对整个结构化数组调用
.reshape(),必须先提取字段再 reshape
多维结构化数组需在 dtype 外再指定 shape
结构化数组本身可以有多个维度(如 (3, 4)),但每个元素仍是单条记录。常见误区是以为“多维”意味着字段内部是数组——其实不是,那是“结构化数组的字段为数组类型”。
例如,表示 2×3 个学生的数据:
dt = np.dtype([('id', 'i4'), ('grades', 'f4', (5,))]) # grades 是长度为 5 的 float 数组
arr = np.zeros((2, 3), dtype=dt)
arr[0, 1]['id'] = 101
arr[0, 1]['grades'] = [85, 90, 78, 92, 88]
这里 (5,) 是字段 grades 的 shape,而 (2, 3) 是整个结构化数组的 shape。
- 字段内数组维度写在 dtype 元组第三项(如
('grades', 'f4', (5,))),缺省即标量 - 多维结构化数组的广播规则与普通数组一致,但字段操作仍需显式指定
- 内存布局是结构体数组(AoS),不是数组结构体(SoA),所以跨字段向量化效率较低
结构化数组与 pandas DataFrame 的互转要注意缺失值处理
用 pd.DataFrame(arr) 转换时,NumPy 的 None 或 np.nan 在结构化数组中可能被转成 object 类型列,丢失数值属性。反过来,df.to_records() 默认生成 object dtype,需手动指定:
df = pd.DataFrame({'x': [1, 2], 'y': [3.5, np.nan]})
rec = df.to_records(index=False, column_dtypes={'x': 'i4', 'y': 'f4'})
更稳妥的方式是先构造明确 dtype 再赋值:
dt = np.dtype([('x', 'i4'), ('y', 'f4')])
rec = np.empty(len(df), dtype=dt)
rec['x'] = df['x'].values.astype('i4')
rec['y'] = df['y'].values.astype('f4') # 自动将 NaN 转为 np.nan
- 结构化数组不支持
np.nan在整数字段中,会转成0或引发警告 - pandas 的
to_records()默认把索引也写入,加index=False避免多余字段 - 字段名含下划线或数字开头时,DataFrame 转结构化数组后点号访问会失败,必须用方括号
字段嵌套、跨维度广播、dtype 对齐这些细节不显眼,但一旦出错很难定位到根源。尤其当数据来自 CSV 或 HDF5 并带混合类型时,先打印 arr.dtype 和 arr.shape 比直接计算更省时间。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











