2. 科学计算数据基础

自动报告的质量,几乎在数据进入模板之前就已经被决定了。报告生成环节真正需要的不是“一堆数字”,而是一份结构清晰、类型正确、缺失可控、口径统一的数据源。本节围绕 NumPy 数组操作、Pandas 数据框处理、数据清洗与特征工程三条主线,说明如何把原始计算结果整理成可直接供报告模板消费的结构化数据。

一、NumPy:把计算结果组织成可索引的数组

科学计算中大量中间结果天然是数组形态,例如一组时间步上的温度序列、二维网格上的应力分布、多组参数下的误差曲线。NumPy 的价值不只是算得快,更在于它提供了稳定的形状(shape)、维度(ndim)、数据类型(dtype)三元描述,使后续代码可以按统一约定访问数据。

报告场景中最常见的操作有三类。第一类是形状变换:把一维序列 reshape 成二维表结构,或用 np.newaxis 增加维度以便广播。第二类是聚合:用 mean、std、min、max 配合 axis 参数沿指定方向压缩,得到报告需要的统计量。第三类是索引与掩码:用布尔数组筛选满足条件的样本,例如只保留误差小于阈值的工况。

import numpy as np

# 假设 4 个工况 × 5 个时间步的实测温度(示例数据)
temp = np.array([
    [20.1, 21.3, 23.0, 24.2, 24.8],
    [19.8, 20.9, 22.4, 23.9, 24.5],
    [21.0, 22.6, 24.1, 25.3, 26.0],
    [20.4, 21.1, 22.0, 22.8, 23.1],
])

mean_by_case = temp.mean(axis=1)      # 每个工况的均值,形状 (4,)
peak_by_step = temp.max(axis=0)       # 每个时间步的峰值,形状 (5,)
stable = temp[temp.std(axis=1) < 1.5] # 波动较小的工况
print(mean_by_case.round(2), peak_by_step.round(2))

需要特别提醒的是 axis 的语义:axis=0 表示沿行方向压缩、结果为每列一个值;axis=1 表示沿列方向压缩、结果为每行一个值。报告中的“按工况统计”和“按时间步统计”正是这两种方向,写反了不会报错,但结论会整体错位,这是实际项目中最隐蔽的错误之一。

二、Pandas:把异构结果拼成一张可追溯的表

当报告需要同时呈现工况编号、参数、统计量、判定结论时,纯数组就不够用了,因为列的类型不同、含义不同。Pandas 的 DataFrame 以“列名 + 索引”的方式承载异构数据,是报告数据源最自然的容器。

构建时建议遵循“先列后行”的思路:每一列对应报告中的一个字段,行对应一个观测单元(一个工况、一个样本、一个时间点)。字段命名应直接对应报告中的表述,避免出现 col1、tmp 这类无法追溯的缩写。

import pandas as pd

df = pd.DataFrame({
    "case_id": ["C01", "C02", "C03", "C04"],
    "inlet_temp": [20.0, 19.5, 21.2, 20.3],
    "mean_temp": mean_by_case.round(2),
    "peak_temp": temp.max(axis=1).round(2),
    "std_temp": temp.std(axis=1).round(3),
})
df["delta"] = (df["mean_temp"] - df["inlet_temp"]).round(2)
print(df)

除构建外,报告流程中高频使用的还有 groupby 分组聚合、merge 关联多来源结果、pivot_table 生成交叉汇总。例如把仿真结果表与实验结果表按 case_id 合并,再计算偏差列,就能直接支撑“仿真与实验对比”这一报告章节。

三、数据清洗:让缺失与异常变得可解释

清洗不是“把脏数据删掉”,而是让每一处修改都有记录、有依据。报告数据源的清洗通常包含四步:识别缺失、判断缺失机制、选择处理策略、保留处理痕迹。

缺失识别可用 df.isna().sum() 快速定位;缺失机制要区分完全随机缺失、与某变量相关缺失、以及“计算未收敛导致的系统性缺失”。前者可插值或删除,后者必须回到计算环节排查,否则报告结论会被系统性偏差污染。处理策略上,数值列常用中位数填充或前向填充,分类列用众数或单独标记为“未知”,并新增一列 xxx_filled 记录是否被填充。

异常值处理同样需要口径。以温度为例,可先用四分位距法给出候选异常:低于 Q1 - 1.5·IQR 或高于 Q3 + 1.5·IQR 的点标记为可疑,再结合物理量程判断是测量错误还是真实极端工况。物理上不可能的值(如负绝对温度)应直接置为缺失并记录原因;物理上可能但偏离较大的值应保留,但在报告中单独说明。

清洗阶段务必保留原始数据副本与清洗日志(哪一列、哪一行、原值、新值、原因)。报告一旦被质疑,能否复现清洗过程往往比结论本身更重要。

四、特征工程:把原始量转成报告能直接讲的指标

报告读者关心的往往不是原始序列,而是派生指标。特征工程就是把“数组”翻译成“结论语言”的环节。常见构造包括:变化率(末值减初值除以初值)、波动性(标准差或极差)、达标率(满足阈值的样本占比)、归一化偏差(相对基准的百分比差异)。

构造特征时应遵守两条原则:一是可解释,每个派生列都能用一句话说明其业务或物理含义;二是可复算,公式中出现的每个输入列都保留在数据源中,便于复核。下面的 SVG 展示了从原始数组到报告数据源的完整加工链路,以及各环节的关键动作与产物形态。

报告数据源加工链路 原始计算结果 NumPy 数组 shape / dtype 多工况 × 时间步 聚合与变换 axis 方向聚合 reshape / 掩码筛选 均值·峰值·标准差 清洗与校验 缺失识别与填充 IQR 异常标记 清洗日志留痕 报告数据源 DataFrame 宽表 字段名对应报告 一行一工况 特征工程:派生报告指标 变化率 =(末值 − 初值)/ 初值 达标率 = 满足阈值样本数 / 总样本数 归一化偏差 =(实测 − 基准)/ 基准 × 100% 可追溯要求 保留原始副本 记录清洗日志 派生列可复算

五、一个可直接套用的数据源字段示例

下面给出一个面向“工况对比报告”的数据源字段设计示例,字段与报告中的表述一一对应,可直接作为模板调整使用。表中数值为示例数据,仅用于说明结构。

字段名 含义 类型 示例值 来源
case_id工况编号字符串C03原始记录
inlet_temp入口温度浮点21.2原始记录
mean_temp平均温度浮点24.6axis=1 聚合
peak_temp峰值温度浮点26.0axis=1 聚合
std_temp温度标准差浮点1.42axis=1 聚合
delta温升浮点3.4派生特征
is_filled是否经过填充布尔False清洗日志
is_outlier是否标记异常布尔FalseIQR 判定

完成上述整理后,建议做一次交付前自检:每列类型是否符合预期、关键列是否存在缺失、派生列能否用原始列复算一致、行数是否与工况数吻合、字段名是否与报告模板占位符一致。这五项检查通过,数据源就可以交给报告生成环节,后续的模板渲染、图表绘制和结论表述才有可靠基础。