2. NumPy数组创建与工程数据载入
在工程数据处理中,我们面对的原始数据往往来自不同渠道:手工录入的测量值、按固定步长生成的仿真坐标、传感器导出的CSV表格、仪器软件保存的TXT文本。NumPy的第一项任务,就是把这些形态各异的数据统一转换成ndarray,并保证数值类型(dtype)与精度符合后续计算要求。本节围绕“如何创建”和“如何载入”两条主线展开,重点说明不同创建方式的适用场景,以及dtype在工程精度中的实际影响。
一、从列表与元组创建数组
最直接的方式是使用 np.array(),把Python的列表或元组转换为数组。列表和元组本身是Python对象,元素可以是任意类型;而ndarray要求所有元素类型一致,NumPy会根据输入自动推断dtype。
import numpy as np
# 从列表创建:一维数组
strain = np.array([120, 135, 128, 142, 150]) # dtype 推断为 int64
# 从元组创建:二维数组(每行一个测点,两列分别为温度、压力)
sensors = np.array(((25.3, 101.2), (26.1, 100.8), (24.9, 101.5)))
# 显式指定dtype,避免自动推断带来的精度问题
force = np.array([12.5, 13.0, 12.8], dtype=np.float32)
这里有一个工程上常见的细节:整数列表会被推断为整型,一旦后续做除法或叠加小数,就可能出现意外的截断或类型提升。因此,当数据本身代表物理量(温度、压力、电压)时,建议在创建时就显式写出 dtype=np.float64,让精度意图清晰可见。另外,np.array() 默认会复制数据;如果只是想把已有数组换个形状而不复制,应使用 np.asarray() 或 reshape。
二、用arange与linspace生成序列
工程计算中经常需要构造等间隔的自变量序列,例如时间轴、频率扫描点、空间网格坐标。NumPy提供两个互补的函数:
np.arange(start, stop, step):按步长生成,区间为左闭右开,结果个数由步长决定,可能出现浮点累积误差导致末点偏移。np.linspace(start, stop, num):按点数生成,区间为闭区间,首末点精确包含,适合需要严格控制采样点数的场景。
t = np.arange(0, 1.0, 0.1) # 可能得到 10 或 11 个点,末点受浮点误差影响
t2 = np.linspace(0, 1.0, 11) # 精确 11 个点,0 和 1.0 都包含
freq = np.linspace(50, 1000, 20) # 频率扫描:50Hz 到 1000Hz 共 20 个点
选择原则很明确:如果关心的是“每隔多少取一个”,用 arange;如果关心的是“总共取多少个点、首末必须准确”,用 linspace。做频谱分析或绘制曲线时,后者更稳妥,因为采样点数直接决定频率分辨率,末点缺失会让结果产生系统性偏差。
三、从CSV与TXT文件载入工程数据
真实工程数据多以文本表格形式保存。NumPy提供 np.loadtxt() 和 np.genfromtxt() 两个主力函数。前者速度快、要求数据规整;后者能处理缺失值和表头,容错性更强。
# 纯数值、逗号分隔的CSV
data = np.loadtxt("sensor_log.csv", delimiter=",", skiprows=1)
# 含缺失值或混合列的文本,用genfromtxt
data2 = np.genfromtxt("test_run.txt", delimiter="\t",
skip_header=2, filling_values=np.nan)
# 只读取指定列(例如第2、4列)
cols = np.loadtxt("sensor_log.csv", delimiter=",", skiprows=1, usecols=(1, 3))
载入时几个参数直接决定结果是否正确:delimiter 必须与文件实际分隔符一致(逗号、制表符或空格);skiprows/skip_header 用于跳过表头或说明行;usecols 可只提取需要的列,减少内存占用;dtype 可指定整张表的类型。若文件中混有单位符号或空单元格,loadtxt 会直接报错,此时应改用 genfromtxt 并配合 filling_values 把缺失位置填为 np.nan,再在后续清洗中处理。
data.shape、data.dtype 和 np.isnan(data).sum(),确认行列数、类型和缺失情况与预期一致,这是工程数据处理的常规自检。四、理解dtype与数据精度
dtype决定每个元素占多少字节、能表示多大范围和多少位有效数字。工程上常用的有 int32/int64、float32/float64、bool。关键认识有两点:其一,float32 只有约7位十进制有效数字,float64 约15~16位;其二,类型转换遵循“安全提升”规则,混合运算时低精度会向高精度看齐,但显式 astype 可能发生截断。
a = np.array([1.23456789], dtype=np.float32)
print(a) # 约 1.2345679,末位已损失
b = a.astype(np.float64) # 提升后仍是 1.2345679,丢失的精度补不回来
c = np.array([1, 2, 3], dtype=np.int32)
print(c / 2) # 结果为 float64,除法自动提升
因此,涉及累加、积分、坐标变换等对误差敏感的计算,应默认使用 float64;只有在内存或带宽受限、且精度要求不高的场景(如大批量图像像素、嵌入式采集缓存)才考虑 float32。载入文件时若未指定dtype,NumPy通常推断为 float64,这符合多数工程计算的安全默认。
五、一个完整的载入与检查流程
假设有一份电机测试数据 motor_test.csv,首行为表头,三列分别为时间(s)、转速(rpm)、电流(A),共500行。合理的处理顺序是:先用 loadtxt 跳过表头载入,再检查形状是否为 (500, 3),确认dtype为float64,然后按列切片取出时间轴与电流,最后做量纲换算或绘图。若发现某行缺失导致报错,则切换到 genfromtxt 并把缺失填为 np.nan,用 np.nanmean 等函数在统计时自动忽略缺失点。这个流程把“创建—载入—类型确认—清洗”串成闭环,也是后续数组运算、切片索引和统计分析能够可靠进行的前提。
np.array(文件内容) 的方式手工解析文本,也不要在载入后忽略dtype直接做高精度累加。前者容易因分隔符和换行处理出错,后者会让float32的舍入误差在长序列积分中逐步放大。小结本节要点:列表与元组创建适合小规模、结构已知的数据;arange 与 linspace 分别按步长和点数生成序列,后者在采样点数敏感的场景更可靠;CSV/TXT载入要匹配分隔符、跳过表头、按需选列,并对缺失值有预案;dtype不是可有可无的细节,它直接决定数值范围和有效精度,工程计算默认优先 float64。掌握这四类入口,就具备了把工程原始数据安全送入NumPy计算体系的基本能力。