一、结构化数组
1、结构化数组创建的意义
- ndarray是一种同构数据容器,想要用数组存储不同数据类型的时候会有很不方便,因此诞生了结构化数组
- 结构化数组提供将数组内单个数据解释为带有任意类型列的表格型结构
- 主要特点:
- 可以存储不同类型的数据(整数、浮点数、字符串等)
- 每个字段有名称和数据类型
- 支持类似数据库表格的操作
- 内存布局紧凑,访问高效
2、创建结构化数组
python
复制代码
import numpy as np
# 定义数据类型
dt = np.dtype([('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])
# 创建结构化数组
data = np.array([('Alice', 25, 55.5), ('Bob', 32, 75.2)], dtype=dt)
print(data)
"""
输出:
[('Alice', 25, 55.5) ('Bob', 32, 75.2)]
"""
python
复制代码
# 从字典创建结构化数组
data_dict = {
'names': ['Alice', 'Bob', 'Charlie'],
'ages': [25, 32, 37],
'weights': [55.5, 75.2, 80.1]
}
# 先定义 dtype
dt = np.dtype([('names', 'U10'), ('ages', 'i4'), ('weights', 'f4')])
# 创建结构化数组
# 创建空/全是0的结构化数组
data = np.zeros(len(data_dict['names']), dtype=dt)
# 此时data的为[('',0,0),('',0,0),('',0,0)]
data['names'] = data_dict['names']# 将字典的name对应的内容添加到结构化数组中name对应的类型
data['ages'] = data_dict['ages'] # 同上
data['weights'] = data_dict['weights']# 同上
print(data)
persontype = np.dtype({
'names':['name', 'age', 'chinese', 'math', 'english'],
'formats':['S32','i', 'i', 'i', 'f']}
)# 每一行有五列,每列通过属性名的方式去获取对应的值
# 等价于persontype = [('name','S32'),('age','i'),('chinese','i'),('math','i'),('english','f')]
# 指定ndarray时,dtype(data type)指定为dtype
peoples = np.array([("ZhangFei",32,75,100,90),
("GuanYu",24,85,96,88.5),
("ZhaoYun",28,85,92,96.5),
("HuangZhong",29,65,85,100)],
dtype=persontype)
# peoples也像个二维列表,但是第二个维度可以用字段名去指定元素
# 而不是用数字了,而是像字典一样通过属性名取获取对应的值
ages = peoples[:]['age'] # 等价于 peoples['age']
chineses = peoples[:]['chinese'] # peoples['chinese']
maths = peoples[:]['math'] # peoples['math']
englishs = peoples[:]['english'] # peoples['english']
print(peoples)
python
复制代码
# 从元组列表创建
data = np.array([('Alice', 25, 55.5), ('Bob', 32, 75.2)],
dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])
3、访问结构化数组数据
python
复制代码
# 访问所有名字
print(data['name']) # 输出: ['Alice' 'Bob']
# 访问所有年龄
print(data['age']) # 输出: [25 32]
# 访问第一个元素的所有字段
print(data[0]) # 输出: ('Alice', 25, 55.5)
python
复制代码
# 访问名字和年龄
print(data[['name', 'age']])
"""
输出:
[('Alice', 25) ('Bob', 32)]
"""
4、字段操作
python
复制代码
# 修改年龄
data['age'] = [26, 33]
# 修改单个元素的字段
data[1]['weight'] = 76.0
- 条件筛选(使用方法类似np.where的使用方法)
python
复制代码
# 筛选年龄大于30的记录
print(data[data['age'] > 30])
python
复制代码
# 按年龄排序
print(np.sort(data, order='age'))
# 按多个字段排序(先按年龄,再按体重)
print(np.sort(data, order=['age', 'weight']))
python
复制代码
# 计算平均年龄
print(np.mean(data['age']))
# 添加新字段
new_dt = np.dtype(data.dtype.descr + [('height', 'f4')])
new_data = np.zeros(data.shape, dtype=new_dt)
for field in data.dtype.fields:
new_data[field] = data[field]
new_data['height'] = [165.5, 180.2]
5、 结构化数组与普通数组的转换
- 结构化数组转普通数组(直接使用np.array进行转化)
python
复制代码
# 提取所有数值字段
numeric_data = np.array([data['age'], data['weight']]).T
- 普通数组转结构化数组(相当于创建结构化数组的方三)
python
复制代码
# 假设有一个普通数组
arr = np.array([[1, 2.5, 'Alice'], [2, 3.7, 'Bob']])
# 转换为结构化数组
dt = np.dtype([('id', 'i4'), ('value', 'f4'), ('name', 'U10')])
struct_arr = np.array([tuple(row) for row in arr], dtype=dt)
6、结构化数组的局限性
- 灵活性:不如 Pandas DataFrame 灵活
- 功能:缺乏高级数据操作功能(如分组、透视等)
- 性能:对于某些操作可能不如专门的数据结构高效
- 内存:字符串字段会占用固定长度的内存
二、Numpy 文件
1、保存到文件
- save(文件名,数组):保存数组到文件中,若未指定文件的后缀名自动保存为npy文件。
- savetxt(文件名,数组,其他限制条件):将文件保存到以txt为后缀的文件中
- savez(文件名,数组,数组):将多个文件保存到一个未压缩的文件中,数组以关键字的形式传入(关键字自定)
- savez_compressed(文件名,数组):将文件保存到一个已经压缩的文件中
python
复制代码
# 保存为文本文件
import numpy as np
names = [ ('Tom', 18, 175), ('Jerry', 22, 180), ('Ben', 21, 170)]
dtype = [('name', 'S10'), ('age', int), ('height', float)]
data = np.array(names, dtype=dtype) # 创建结构化数组,数据类型为自定义的dtype类型
np.savetxt('data.csv', data, fmt='%s,%d,%.2f', header='name,age,height', comments='')
# data.csv文件内容:
# name,age,height
# b'Tom',18,175.00
# b'Jerry',22,180.00
# b'Ben',21,170.00
# 其中的分隔符是,是因为fmt格式将comments冲掉了
np.save('structured_data', data) # 使用save进行保存,不用指定后缀,自动添加npy后缀
np.savez("array_archive.npz", a=data, b=data) # 同时存多个数组到未压缩的文件,可以使用任意关键字
np.savez_compressed("array_archive.npz", a=data, b=data) # 同时存多个数组到已经压缩的文件,可以使用任意关键字
2、从文件加载
- loadtxt(文件名,使用savetxt时添加的限制条件):读取txt结尾的文件
- getfromtxt(文件名,限制条件):假如数组文件中有缺失的内容,该方法会将缺失的内容读成nan(nan代表浮点数据类型的数字)
- load(文件名):读文件的时候必须加上后缀
python
复制代码
# 加载二进制文件
data = np.load('structured_data.npy')
print(data) # 输出: NpzFile 'array_archive.npz' with keys: a, b
# 可以看到压缩文件中有a,b
print(data["a"]) # 查看压缩文件中a文件的内容
# 从文本文件加载
data = np.genfromtxt('data.csv', delimiter=',',
dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')],
skip_header=1)
print(data)
# 输出:[("b'Tom'", 18, 175.) ("b'Jerry'", 22, 180.) ("b'Ben'", 21, 170.)]
3、操作字节文件
- 操纵字节文件(多半和其余语言进行交互,这种文件可以是音频、视频等任何格式的文件)
- 此处的字节文件是一个二进制的字节流文件。
python
复制代码
import wave # 导入wave模块(音频模块)
import numpy as np
wf = wave.open('alert.wav') # 本地目录下的文件
data = wf.readframes(wf.getnframes()) # 二进制数据 固定用法
data1 = np.frombuffer(data) # 二进制解析成ndarray ,输出:array([], dtype=float64)
# frombuffer函数:将字节流 读成 numpy数组
data1 = np.frombuffer(data, dtype='int64') # array([], dtype=int64)