NumPy: 结构化数组
1. 你将学到
- ❶ 结构化 dtype — 定义多字段复合类型
- ❷ 字段访问 — 字典式与属性式读取修改
- ❸ 嵌套结构 — 多层字段定义与访问
- ❹ recarray — 记录数组的属性访问
- ❺ vs Pandas — 结构化数组与 DataFrame 对比互转
2. 故事
Alice 需要存储员工数据:姓名、年龄、工资、部门。普通 ndarray 只能存同类型——要么全是数字,要么全是字符串。她试过用 4 个独立数组,但维护起来一片混乱。直到她发现结构化数组:
PYTHON
dt = np.dtype([('name','U20'),('age','i4'),('salary','f8'),('dept','U10')])
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。
"一个数组,多个字段,NumPy 原生的轻量表格。"
Bob 惊叹:不用 Pandas 也能存表格数据,而且内存更省、速度更快。
3. 知识点
(1) 结构化 dtype 定义
结构化 dtype 允许每个元素包含多个命名字段,类似 C 结构体或数据库行。
PYTHON
import numpy as np
dt = np.dtype([
('name', 'U20'),
('age', 'i4'),
('salary', 'f8'),
('dept', 'U10'),
])
employees = np.array([
('Alice', 30, 85000.0, 'Engineering'),
('Bob', 25, 62000.0, 'Marketing'),
('Charlie', 35, 95000.0, 'Engineering'),
('Carol', 28, 72000.0, 'Sales'),
], dtype=dt)
print(employees)
TEXT
📖 仅展示
[('Alice', 30, 85000., 'Engineering') ('Bob', 25, 62000., 'Marketing')
('Charlie', 35, 95000., 'Engineering') ('Carol', 28, 72000., 'Sales')]
dtype 语法说明:
| 语法 | 等价 | 说明 |
|---|---|---|
'i4' |
np.int32 |
4 字节有符号整数 |
'f8' |
np.float64 |
8 字节浮点数 |
'U20' |
np.str_ |
Unicode 字符串,最长 20 字符 |
'b1' |
np.bool_ |
布尔值 |
'O' |
np.object_ |
Python 对象 |
(2) 字段访问与修改
PYTHON
import numpy as np
dt = np.dtype([('name','U20'),('age','i4'),('salary','f8')])
data = np.array([
('Alice', 30, 85000.0),
('Bob', 25, 62000.0),
('Charlie', 35, 95000.0),
], dtype=dt)
print(data['name'])
print(data['salary'])
data['salary'] = data['salary'] * 1.1
print(data['salary'])
data[0]['age'] = 31
print(data[0])
TEXT
📖 仅展示
['Alice' 'Bob' 'Charlie']
[85000. 62000. 95000.]
[93500. 68200. 104500.]
('Alice', 31, 93500.)
字段访问方式:
| 方式 | 语法 | 说明 |
|---|---|---|
| 字典式 | data['name'] |
访问整个字段列 |
| 索引+字段 | data[0]['age'] |
访问某行某字段 |
| 字段+索引 | data['age'][0] |
同上,等价 |
| 批量修改 | data['salary'] *= 1.1 |
整列修改 |
(3) 排序与筛选
PYTHON
import numpy as np
dt = np.dtype([('name','U20'),('age','i4'),('score','f4')])
students = np.array([
('Alice', 20, 92.5),
('Bob', 22, 88.0),
('Charlie', 19, 95.3),
('Carol', 21, 78.8),
('David', 20, 88.5),
], dtype=dt)
sorted_by_score = np.sort(students, order='score')
print("By score asc:", sorted_by_score['name'])
sorted_by_age = np.sort(students, order=['age', 'score'])
print("By age then score:", sorted_by_age['name'])
mask = students['score'] >= 90
print("Score >= 90:", students[mask]['name'])
rank = np.argsort(students, order='score')
print("Rank indices:", rank)
TEXT
📖 仅展示
By score asc: ['Carol' 'Bob' 'David' 'Alice' 'Charlie']
By age then score: ['Charlie' 'David' 'Alice' 'Carol' 'Bob']
Score >= 90: ['Alice' 'Charlie']
Rank indices: [3 1 4 0 2]
(4) 嵌套结构
结构化 dtype 支持嵌套——一个字段本身可以是结构化类型:
PYTHON
import numpy as np
address_dt = np.dtype([
('city', 'U20'),
('zip', 'U10'),
])
person_dt = np.dtype([
('name', 'U20'),
('age', 'i4'),
('address', address_dt),
])
people = np.array([
('Alice', 30, ('Beijing', '100000')),
('Bob', 25, ('Shanghai', '200000')),
], dtype=person_dt)
print(people['name'])
print(people['address']['city'])
print(people[0]['address']['city'])
TEXT
📖 仅展示
['Alice' 'Bob']
['Beijing' 'Shanghai']
Beijing
(5) 记录数组 recarray
np.recarray 允许用属性方式访问字段,更直观但略慢:
PYTHON
import numpy as np
dt = np.dtype([('name','U20'),('age','i4'),('score','f4')])
data = np.array([
('Alice', 20, 92.5),
('Bob', 22, 88.0),
], dtype=dt)
# NumPy 2.x:view(np.recarray) 已弃用;改用 np.rec.fromarrays
rec = np.rec.fromarrays([data['name'], data['age'], data['score']], dtype=dt)
print(rec.name)
print(rec.age)
print(rec.score)
rec.age += 1
print(rec.age)
TEXT
📖 仅展示
['Alice' 'Bob']
[20 22]
[92.5 88. ]
[21 23]
(6) 与 Pandas 互转
PYTHON
import numpy as np
import pandas as pd
dt = np.dtype([('name','U20'),('age','i4'),('salary','f8')])
employees = np.array([
('Alice', 30, 85000.0),
('Bob', 25, 62000.0),
('Charlie', 35, 95000.0),
], dtype=dt)
df = pd.DataFrame(employees)
print(df)
print(type(df))
back = df.to_records(index=False)
print(back)
print(back.dtype)
values_only = np.array(df.to_numpy(), dtype=dt)
print(values_only)
TEXT
📖 仅展示
name age salary
0 Alice 30 85000.0
1 Bob 25 62000.0
2 Charlie 35 95000.0
<class 'pandas.core.frame.DataFrame'>
[('Alice', 30, 85000.) ('Bob', 25, 62000.) ('Charlie', 35, 95000.)]
[('name', '<U20'), ('age', '<i4'), ('salary', '<f8')]
[('Alice', 30, 85000.) ('Bob', 25, 62000.) ('Charlie', 35, 95000.)]
4. 对比表格
(1) 结构化数组 vs dict 列表 vs DataFrame
| 维度 | 结构化数组 | dict 列表 | DataFrame |
|---|---|---|---|
| 内存 | 最省(连续内存) | 最高(对象开销) | 中等 |
| 速度 | 最快(C 层遍历) | 最慢(Python 循环) | 快(列式优化) |
| 字段访问 | arr['name'] |
d['name'] |
df['name'] |
| 类型约束 | 严格 dtype | 无 | 灵活 |
| 适用规模 | 小中型表格 | 少量记录 | 大中型数据 |
| 功能丰富度 | 基础 | 基础 | 最丰富 |
(2) 字段访问方式对比
| 方式 | 语法 | 返回类型 | 适用对象 |
|---|---|---|---|
| 字典式 | arr['name'] |
ndarray | 结构化数组 |
| 属性式 | rec.name |
ndarray | recarray |
| 索引+字段 | arr[0]['name'] |
标量 | 两者均可 |
| 字段+索引 | arr['name'][0] |
标量 | 两者均可 |
(3) dtype 字符串语法
| 简写 | 类型 | 字节数 | 范围/精度 |
|---|---|---|---|
'i1' |
int8 | 1 | -128 ~ 127 |
'i4' |
int32 | 4 | ±2.1×10⁹ |
'i8' |
int64 | 8 | ±9.2×10¹⁸ |
'f4' |
float32 | 4 | ~7 位有效 |
'f8' |
float64 | 8 | ~15 位有效 |
'U10' |
str | 40 | 10 字符 Unicode |
'b1' |
bool | 1 | True/False |
(4) 结构化数组 vs 记录数组
| 维度 | 结构化数组 | 记录数组 (recarray) |
|---|---|---|
| 创建 | np.array(data, dtype=dt) |
arr.view(np.recarray) |
| 访问字段 | arr['name'] |
rec.name |
| 性能 | 略快 | 略慢(属性查找开销) |
| 可读性 | 中等 | 更直观 |
| 修改字段 | arr['age'] = ... |
rec.age = ... |
| 本质 | 基础形式 | view,底层同一块内存 |
5. 原理图解
graph LR
A["结构化数组"] --> B["dtype 定义<br>[('name','U20'),<br>('age','i4'),<br>('salary','f8')]"]
A --> C["字段访问<br>arr['name']<br>arr['salary']"]
A --> D["排序筛选<br>np.sort(order=)<br>布尔掩码"]
A --> E["嵌套结构<br>address = dtype(<br>[('city','U20')])"]
A --> F["recarray<br>rec.name<br>rec.age"]
A --> G["Pandas 互转<br>pd.DataFrame(arr)<br>df.to_records()"]
B --> H["内存布局<br>name|age|salary<br>连续按行存储"]
C --> I["修改<br>arr['salary'] *= 1.1"]
D --> J["多字段排序<br>order=['age','score']"]
E --> K["访问<br>arr['address']['city']"]
F --> L["view 模式<br>不复制数据"]
style A fill:#e1f5fe
style B fill:#fff9c4
style C fill:#c8e6c9
style D fill:#ffccbc
style E fill:#e1bee7
style F fill:#b2dfdb
style G fill:#ffe0b2
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。
6. 示例
▶ 示例: 1:定义 dtype 并创建结构化数组(难度⭐)
PYTHON
import numpy as np
dt = np.dtype([
('id', 'i4'),
('product', 'U20'),
('price', 'f4'),
('stock', 'i4'),
])
products = np.array([
(1, 'Laptop', 5999.0, 50),
(2, 'Mouse', 129.0, 200),
(3, 'Keyboard', 349.0, 150),
(4, 'Monitor', 2499.0, 30),
], dtype=dt)
print("dtype:", dt)
print("nbytes:", products.nbytes)
print("字段:", dt.names)
print("产品名:", products['product'])
print("库存:", products['stock'])
输出:
TEXT 📖 仅展示# 输出结果
TEXT
📖 仅展示
dtype: [('id', '<i4'), ('product', '<U20'), ('price', '<f4'), ('stock', '<i4')]
nbytes: 432
字段: ('id', 'product', 'price', 'stock')
产品名: ['Laptop' 'Mouse' 'Keyboard' 'Monitor']
库存: [ 50 200 150 30]
⚠️ 注意: 以上代码需在本地 Python 环境中运行。
▶ 示例: 2:字段访问与修改(难度⭐)
PYTHON
import numpy as np
dt = np.dtype([('name','U20'),('age','i4'),('salary','f8')])
staff = np.array([
('Alice', 30, 85000.0),
('Bob', 25, 62000.0),
('Charlie', 35, 95000.0),
], dtype=dt)
print("工资列:", staff['salary'])
staff['salary'] *= 1.05
print("涨薪5%:", staff['salary'])
staff[1]['age'] = 26
print("Bob age:", staff[1]['age'])
high_salary = staff['salary'] > 70000
print("高薪:", staff[high_salary]['name'])
输出:
TEXT 📖 仅展示# 输出结果
TEXT
📖 仅展示
工资列: [85000. 62000. 95000.]
涨薪5%: [89250. 65100. 99750.]
Bob age: 26
高薪: ['Alice' 'Charlie']
⚠️ 注意: 以上代码需在本地 Python 环境中运行。
▶ 示例: 3:排序与排名(难度⭐⭐)
PYTHON
import numpy as np
dt = np.dtype([('name','U20'),('dept','U10'),('salary','f8')])
employees = np.array([
('Alice', 'Eng', 95000.0),
('Bob', 'Mkt', 62000.0),
('Charlie', 'Eng', 88000.0),
('Carol', 'Mkt', 71000.0),
('David', 'Eng', 76000.0),
], dtype=dt)
by_salary = np.sort(employees, order='salary')
print("工资升序:", by_salary['name'])
by_dept_salary = np.sort(employees, order=['dept', 'salary'])
print("部门+工资:", by_dept_salary['name'])
ranks = np.argsort(employees, order='salary')
print("排名索引:", ranks)
print("排名:", employees[ranks]['name'])
top3 = by_salary[-3:]
print("Top3:", top3['name'], top3['salary'])
输出:
TEXT 📖 仅展示# 输出结果
TEXT
📖 仅展示
工资升序: ['Bob' 'Carol' 'David' 'Charlie' 'Alice']
部门+工资: ['David' 'Charlie' 'Alice' 'Bob' 'Carol']
排名索引: [1 3 4 2 0]
排名: ['Bob' 'Carol' 'David' 'Charlie' 'Alice']
Top3: ['David' 'Charlie' 'Alice'] [76000. 88000. 95000.]
⚠️ 注意: 以上代码需在本地 Python 环境中运行。
▶ 示例: 4:嵌套结构(难度⭐⭐)
PYTHON
import numpy as np
contact_dt = np.dtype([
('email', 'U30'),
('phone', 'U15'),
])
employee_dt = np.dtype([
('name', 'U20'),
('age', 'i4'),
('salary', 'f8'),
('contact', contact_dt),
])
team = np.array([
('Alice', 30, 85000.0, ('alice@test.com', '138-0001')),
('Bob', 25, 62000.0, ('bob@test.com', '139-0002')),
('Charlie', 35, 95000.0, ('charlie@test.com', '137-0003')),
], dtype=employee_dt)
print("姓名:", team['name'])
print("邮箱:", team['contact']['email'])
print("Alice phone:", team[0]['contact']['phone'])
print("dtype 结构:", employee_dt)
输出:
TEXT 📖 仅展示# 输出结果
TEXT
📖 仅展示
姓名: ['Alice' 'Bob' 'Charlie']
邮箱: ['alice@test.com' 'bob@test.com' 'charlie@test.com']
Alice phone: 138-0001
dtype 结构: [('name', '<U20'), ('age', '<i4'), ('salary', '<f8'), ('contact', [('email', '<U30'), ('phone', '<U15')])]
⚠️ 注意: 以上代码需在本地 Python 环境中运行。
▶ 示例: 5:与 Pandas 互转(难度⭐⭐)
PYTHON
import numpy as np
import pandas as pd
dt = np.dtype([('name','U20'),('age','i4'),('salary','f8'),('dept','U10')])
arr = np.array([
('Alice', 30, 85000.0, 'Eng'),
('Bob', 25, 62000.0, 'Mkt'),
('Charlie', 35, 95000.0, 'Eng'),
], dtype=dt)
df = pd.DataFrame(arr)
print("DataFrame:")
print(df)
print("dtypes:", df.dtypes.tolist())
back = df.to_records(index=False)
print("\nBack to structured:")
print(back)
print("dtype match:", back.dtype == arr.dtype)
arr2 = np.array(df.to_records(index=False), dtype=dt)
print("Data match:", np.array_equal(arr, arr2))
输出:
TEXT 📖 仅展示# 输出结果
TEXT
📖 仅展示
DataFrame:
name age salary dept
0 Alice 30 85000.0 Eng
1 Bob 25 62000.0 Mkt
2 Charlie 35 95000.0 Eng
dtypes: [dtype('<U20'), dtype('<i4'), dtype('<f8'), dtype('<U10')]
Back to structured:
[('Alice', 30, 85000., 'Eng') ('Bob', 25, 62000., 'Mkt')
('Charlie', 35, 95000., 'Eng')]
dtype match: True
Data match: True
⚠️ 注意: 以上代码需在本地 Python 环境中运行。
7. 综合示例:员工管理系统
Alice 用结构化数组实现员工管理:存储 → 按部门筛选 → 按工资排序 → 统计 → 转 Pandas,一条流水线完成。
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。
:员工数据存储与统计分析(难度⭐⭐⭐)
PYTHON
import numpy as np
import pandas as pd
# ========================================
# Part 1: 定义 dtype 并创建员工数据
# ========================================
print("=== Part 1: 创建员工数据 ===\n")
dt = np.dtype([
('name', 'U20'),
('age', 'i4'),
('salary', 'f8'),
('dept', 'U10'),
])
employees = np.array([
('Alice', 30, 85000.0, 'Engineering'),
('Bob', 25, 62000.0, 'Marketing'),
('Charlie', 35, 95000.0, 'Engineering'),
('Carol', 28, 72000.0, 'Sales'),
('David', 32, 88000.0, 'Engineering'),
('Eve', 27, 68000.0, 'Marketing'),
('Frank', 40, 110000.0, 'Sales'),
('Grace', 29, 76000.0, 'Engineering'),
], dtype=dt)
print("员工总数:", len(employees))
print("总内存:", employees.nbytes, "bytes")
print("字段:", dt.names)
# ========================================
# Part 2: 按部门筛选
# ========================================
print("\n=== Part 2: 按部门筛选 ===\n")
for dept in np.unique(employees['dept']):
mask = employees['dept'] == dept
group = employees[mask]
print("[{}] {} 人: {}".format(
dept, len(group), ', '.join(group['name'])))
eng_mask = employees['dept'] == 'Engineering'
eng = employees[eng_mask]
print("\nEngineering 平均工资: {:.0f}".format(eng['salary'].mean()))
# ========================================
# Part 3: 按工资排序
# ========================================
print("\n=== Part 3: 按工资排序 ===\n")
by_salary = np.sort(employees, order='salary')
print("工资升序:")
for e in by_salary:
print(" {:10s} age={:2d} salary={:>10.0f} dept={}".format(
e['name'], e['age'], e['salary'], e['dept']))
by_dept_salary = np.sort(employees, order=['dept', 'salary'])
print("\n部门+工资排序:")
for e in by_dept_salary:
print(" [{:>12s}] {:10s} salary={:>10.0f}".format(
e['dept'], e['name'], e['salary']))
# ========================================
# Part 4: 统计分析
# ========================================
print("\n=== Part 4: 统计分析 ===\n")
print("全员统计:")
print(" 平均年龄: {:.1f}".format(employees['age'].mean()))
print(" 平均工资: {:.0f}".format(employees['salary'].mean()))
print(" 工资中位: {:.0f}".format(np.median(employees['salary'])))
print(" 工资范围: {:.0f} ~ {:.0f}".format(
employees['salary'].min(), employees['salary'].max()))
print("\n按部门统计:")
for dept in np.unique(employees['dept']):
mask = employees['dept'] == dept
g = employees[mask]
print(" [{:>12s}] 人数={:d} 平均工资={:>10.0f} 最高={:>10.0f}".format(
dept, len(g), g['salary'].mean(), g['salary'].max()))
senior_mask = (employees['age'] >= 30) & (employees['salary'] >= 80000)
print("\n资深高薪 (age>=30, salary>=80000):")
for e in employees[senior_mask]:
print(" {} age={} salary={:.0f}".format(
e['name'], e['age'], e['salary']))
# ========================================
# Part 5: 转 Pandas 深度分析
# ========================================
print("\n=== Part 5: 转 Pandas 分析 ===\n")
df = pd.DataFrame(employees)
print(df.to_string(index=False))
print("\n部门工资统计:")
print(df.groupby('dept')['salary'].agg(['mean','max','min','count']))
top3 = df.nlargest(3, 'salary')[['name','salary','dept']]
print("\nTop3 工资:")
print(top3.to_string(index=False))
back = df.to_records(index=False)
print("\n回转验证: 通过 np.sort + np.array_equal 比对双方排序后是否相等")
emp_sorted = np.sort(employees, order='name')
back_sorted = np.sort(back, order='name')
print("对等结果:", np.array_equal(emp_sorted, back_sorted))
输出:
TEXT 📖 仅展示# 输出结果
TEXT
📖 仅展示
=== Part 1: 创建员工数据 ===
员工总数: 8
总内存: 544 bytes
字段: ('name', 'age', 'salary', 'dept')
=== Part 2: 按部门筛选 ===
[Engineering] 4 人: Alice, Charlie, David, Grace
[Marketing] 2 人: Bob, Eve
[Sales] 2 人: Carol, Frank
Engineering 平均工资: 86000
=== Part 3: 按工资排序 ===
工资升序:
Bob age=25 salary= 62000 dept=Marketing
Eve age=27 salary= 68000 dept=Marketing
Carol age=28 salary= 72000 dept=Sales
Grace age=29 salary= 76000 dept=Engineering
Alice age=30 salary= 85000 dept=Engineering
David age=32 salary= 88000 dept=Engineering
Charlie age=35 salary= 95000 dept=Engineering
Frank age=40 salary= 110000 dept=Sales
部门+工资排序:
[ Engineering] Alice salary= 85000
[ Engineering] Grace salary= 76000
[ Engineering] David salary= 88000
[ Engineering] Charlie salary= 95000
[ Marketing] Bob salary= 62000
[ Marketing] Eve salary= 68000
[ Sales] Carol salary= 72000
[ Sales] Frank salary= 110000
=== Part 4: 统计分析 ===
全员统计:
平均年龄: 30.8
平均工资: 82000
工资中位: 80500
工资范围: 62000 ~ 110000
按部门统计:
[ Engineering] 人数=4 平均工资= 86000 最高= 95000
[ Marketing] 人数=2 平均工资= 65000 最高= 68000
[ Sales] 人数=2 平均工资= 91000 最高= 110000
资深高薪 (age>=30, salary>=80000):
Alice age=30 salary=85000
Charlie age=35 salary=95000
David age=32 salary=88000
Frank age=40 salary=110000
=== Part 5: 转 Pandas 分析 ===
name age salary dept
Alice 30 85000.0 Engineering
Bob 25 62000.0 Marketing
Charlie 35 95000.0 Engineering
Carol 28 72000.0 Sales
David 32 88000.0 Engineering
Eve 27 68000.0 Marketing
Frank 40 110000.0 Sales
Grace 29 76000.0 Engineering
部门工资统计:
mean max min count
dept
Engineering 86000 95000.0 76000.0 4
Marketing 65000 68000.0 62000.0 2
Sales 91000 110000.0 72000.0 2
Top3 工资:
Charlie 95000.0 Engineering
Frank 110000.0 Sales
David 88000.0 Engineering
回转验证: True
⚠️ 注意: 以上代码需在本地 Python 环境中运行。
❓ 常见问题
Q 结构化数组和 DataFrame 用哪个?
A 数据量小(千级以内)且只需基础排序筛选,用结构化数组更省内存更快;数据量大或需要 groupby/merge/透视表等复杂操作,用 DataFrame。结构化数组适合嵌入式/无 Pandas 环境或纯数值管道中的表格数据。
Q 字段名可以用中文吗?
A 技术上可以,
np.dtype([('姓名','U20'),('年龄','i4')]) 能正常工作,但不推荐——部分工具(如 Pandas to_records)对中文字段名支持不一致,且代码可读性差。建议用英文字段名,另建映射字典做显示转换。Q 结构化数组能做 join 吗?
A NumPy 没有内置 join 操作。简单匹配可用
np.isin + 布尔索引,复杂关联需转 Pandas 用 pd.merge。结构化数组的强项是单表操作(筛选/排序/统计),多表关联不是它的设计目标。Q recarray 和结构化数组有什么区别?
A recarray 是结构化数组的 view,底层同一块内存。区别仅在访问方式:
arr['name'] vs rec.name。recarray 的属性访问略慢(多了属性查找开销),但代码更可读。两者互转零拷贝:rec = arr.view(np.recarray) 和 arr = rec.view(np.void)。Q 如何给结构化数组添加新字段?
A NumPy 结构化数组的 dtype 创建后不可变,无法直接添加字段。需用
np.empty 创建新 dtype 数组,逐字段拷贝旧数据,再填充新字段。或用 np.lib.recfunctions.append_fields(需额外导入)。频繁增删字段应改用 DataFrame。📖 小节
- 结构化 dtype:
np.dtype([('name','U20'),('age','i4'),('salary','f8')])定义多字段复合类型 - 字段访问:
arr['name']取整列,arr[0]['name']取单值,支持批量修改 - 嵌套结构:字段本身可以是结构化 dtype,通过
arr['address']['city']访问 - recarray:
.view(np.recarray)转为属性访问模式,rec.name代替arr['name'] - 排序筛选:
np.sort(order='salary')单字段排序,order=['dept','salary']多字段排序 - 与 Pandas 互转:
pd.DataFrame(arr)转 DataFrame,df.to_records(index=False)转回
📝 作业
(1) 学生成绩结构化排序
- 定义结构化 dtype 包含
name(U20)、math(f4)、english(f4)、science(f4) - 创建 6 名学生记录
- 添加
total字段(f4),值为三科总分 - 按 total 降序排列,输出排名、姓名、总分
(2) 数据筛选查询
- 用作业(1)的结构化数组
- 筛选 math >= 85 的学生
- 筛选 total >= 250 的学生
- 找出 english 最高分的学生姓名
- 统计各科平均分、最高分、最低分
(3) Pandas 互转对比
- 将作业(1)的结构化数组转为 DataFrame
- 在 DataFrame 上做相同的筛选和排序,对比代码差异
- 比较
arr['math'].mean()和df['math'].mean()的结果是否一致 - 将 DataFrame 转回结构化数组,验证数据完整性
- 对比两种方式代码量和可读性