4. 数据接收与原始数据层构建

临床研究的数据流水线从“接收”开始。无论上游是EDC系统导出的CSV、统计软件生成的SAS数据集、CDISC标准下的XPT传输文件,还是实验室信息系统推送的XML,进入流水线的第一站都应当是原始数据层(Raw Data Layer)。这一层的核心原则是:原样保留、不可变、可追溯。任何解析、清洗、类型转换都发生在原始层之后,原始层本身只负责“接住”数据并证明它没有被篡改。

原始数据导入与文件格式解析

导入的第一步不是写代码,而是建立接收清单。每批数据到达时,应记录:来源系统、传输方式(SFTP/API/人工上传)、到达时间、文件清单、文件大小、校验值(MD5或SHA-256)、对应的传输批次号。这些元数据本身也是原始层的一部分,通常写入一张ingest_manifest表或同目录下的manifest.json。

不同格式的解析策略差异很大,需要分别处理:

  • CSV:看似简单,实则陷阱最多。必须显式指定分隔符、引号规则、编码(UTF-8/GBK)、是否含表头、缺失值表示(空串、NA、.、-9)。建议解析时全部按字符串读入,不做自动类型推断,避免00123被吞掉前导零、日期被误判。
  • SAS7BDAT:需借助pyreadstat或pandas.read_sas读取,注意SAS的缺失值有.、.A~.Z、._等多种特殊缺失码,不能简单当作NaN。
  • XPT(SAS Transport):CDISC SDTM/ADaM的标准传输格式,固定80字节记录结构,变量名大写且不超过8字符,需用pyreadstat.read_xport解析,并保留其变量标签与格式信息。
  • XML:常见于CDISC ODM和Lab数据。应使用lxml按XPath提取,同时保留原始XML文件本身,因为ODM中的ItemGroupDef、CodeList等元数据对后续校验至关重要。

解析后的数据应写入原始层的落地表,字段全部为字符串类型,并附加_ingest_batch_id、_source_file、_row_num三列溯源信息。这样即使后续发现解析错误,也能定位到具体文件的具体行。

数据校验与接收报告

接收校验分三个层次,由浅入深:

  1. 文件级校验:文件是否存在、大小是否非零、MD5是否与发送方一致、文件数量是否与清单匹配。
  2. 结构级校验:列名是否与预期Schema一致、列数是否正确、编码是否可解析、行数是否在合理范围(如与上一批次偏差不超过20%)。
  3. 内容级校验:关键字段非空率、受试者ID格式、日期格式、枚举值是否在允许集合内、重复主键检测。

校验结果应生成一份接收报告(Ingest Report),包含:批次号、文件清单及校验值、各文件行数与列数、结构校验通过/失败项、内容校验的异常计数与示例行、总体状态(PASS/WARN/FAIL)。WARN表示可继续但需人工确认,FAIL表示阻断,数据不得进入下游。

建议将接收报告同时输出为JSON(供程序消费)和HTML(供人工审阅),并归档到原始层同一批次目录下,形成“数据+元数据+报告”三位一体的接收包。

原始数据存储策略

原始层推荐采用不可变分区存储:按来源系统/数据集/接收日期/批次号组织目录,文件写入后设为只读,任何修正都以新批次追加,不覆盖旧文件。这样天然满足ALCOA+中的“原始性、准确性、完整性、一致性、持久性”。

存储介质上,小规模研究可直接用文件系统加Parquet落地;中大型研究建议对象存储(如S3/MinIO)加元数据库(如PostgreSQL记录manifest和报告)。无论哪种,都应保证:原始文件与解析后的落地表同时保留,前者是法律意义上的原始记录,后者是工程意义上的可查询副本。

原始数据层接收与构建流程 EDC / CSV SAS7BDAT XPT (CDISC) XML (ODM/Lab) 接收清单 来源/时间/大小 MD5 / 批次号 格式解析 CSV: 显式分隔/编码 SAS: 特殊缺失码 XPT: 80字节记录 XML: XPath提取 全部按字符串落地 三层校验 ① 文件级 ② 结构级 ③ 内容级 接收报告 Ingest Report PASS / WARN / FAIL · 异常计数 · 示例行 · JSON + HTML 原始数据层(不可变分区存储) 原始文件(只读) CSV / SAS / XPT / XML 落地表(全字符串) + _batch_id / _source / _row 元数据与报告 manifest + ingest_report ↓ 仅当状态为 PASS 或 WARN 时,数据方可进入下游清洗与转换层

一个常见的误区是把“解析成功”等同于“接收成功”。解析成功只说明文件能被程序读取,不代表数据符合研究预期。例如某批次CSV中SEX列出现了M、F、1、2四种写法,解析完全正常,但内容校验必须将其标记为WARN并输出示例行,由数据管理员确认映射规则后再进入下游。原始层不做修正,只做记录和报告。