3、数据质量与清洗基础:数据质量维度与清洗策略
数据质量这事儿,我做了十几年ETL,感触特别深。
很多人觉得ETL就是写写SQL、跑跑任务。其实不然。你数据质量搞不好,后面报表全是错的,业务部门追着你骂。我见过太多项目,上线第一天就崩,原因就是数据质量没把住。
说白了,数据质量是ETL的命根子。今天咱们就把这块掰开揉碎了讲清楚。
3.1 数据质量的四个核心维度
数据质量不是玄学,它有具体的衡量标准。我个人习惯用四个维度来卡:完整性、准确性、一致性、时效性。
3.1.1 完整性
完整性,就是数据有没有缺胳膊少腿。
举个例子。用户表里,手机号字段是必填的。结果你发现10%的用户手机号是空的。这就是完整性有问题。
我在项目中遇到过最夸张的一次:某电商订单表,订单金额字段居然有30%是NULL。后来一查,是上游系统某个版本升级后,字段映射丢了。嗯,这种坑,你光靠肉眼根本看不出来。
- 必填字段是否为NULL或空字符串
- 主键是否唯一、是否有重复
- 外键关联是否存在(比如订单表引用了不存在的用户ID)
- 时间戳是否缺失
3.1.2 准确性
准确性,就是数据对不对。
数据是填了,但填错了,比没填更可怕。你想想看,用户年龄填的是200岁,这明显不对。或者订单金额明明是100块,结果存成了10000块。
我曾经接手过一个金融项目。交易流水里,有一批数据的时间戳全部是1970-01-01。为什么?因为上游系统时间戳字段用了默认值0。这种数据要是直接进数仓,那风控模型直接废了。
- 值域检查:年龄0-150,金额大于0
- 格式校验:手机号11位,邮箱包含@
- 业务规则:下单时间不能晚于发货时间
- 统计异常:平均值、标准差超出合理范围
3.1.3 一致性
一致性,说白了就是同一个东西,在不同地方得长一个样。
比如用户性别,A系统存的是"男/女",B系统存的是"1/0",C系统存的是"M/F"。你把这些数据合并到一起,就乱套了。
我记得有一次做数据仓库整合,客户信息来自三个不同系统。同一个客户,在CRM系统里叫"张三",在订单系统里叫"张先生",在客服系统里叫"zhangsan"。你说这怎么关联?
- 同一实体在不同系统中的编码规则不同
- 度量单位不统一(斤 vs 公斤,元 vs 分)
- 时间格式不一致(YYYY-MM-DD vs YYYY/MM/DD)
- 枚举值定义冲突
3.1.4 时效性
时效性,就是数据得及时。
你做个实时大屏,结果数据延迟了2小时。业务领导看着昨天的数据做今天的决策,这不扯淡吗?
我做过一个物流项目,要求每5分钟更新一次包裹位置。结果ETL任务跑一次要15分钟。数据还没跑完,快递都送到下一站了。后来我们优化了增量抽取策略,才把延迟压到2分钟以内。
- 数据产生到可用的时间差(延迟)
- 批处理任务的完成时间窗口
- 实时数据的最大容忍延迟
- 数据过期后的处理策略(比如超过1小时的数据直接丢弃)
3.2 常见数据质量问题
上面讲了四个维度,下面咱们看看实际工作中最常见的坑。我列了个表,都是血泪教训。
| 问题类型 | 具体表现 | 影响 |
|---|---|---|
| 缺失值 | 字段为NULL、空字符串、占位符(如"未知") | 统计结果偏差,模型训练失败 |
| 重复数据 | 同一记录出现多次,主键冲突 | 聚合计算翻倍,报表失真 |
| 异常值 | 超出合理范围的数据(如负数年龄) | 拉偏平均值,影响分析结论 |
| 格式错误 | 日期格式不统一,电话号码含字母 | 解析失败,ETL任务报错 |
| 业务逻辑冲突 | 订单金额与明细合计不符 | 财务对账不平,审计通不过 |
| 数据漂移 | 同一指标在不同时间查询结果不同 | 业务决策失去依据 |
为什么会这样?我总结下来,根源无非三个:
- 上游系统不规范:业务系统设计时就没考虑数据质量
- 人为操作失误:手工录入、批量导入时出错
- 系统间集成问题:接口变更、字段映射错误
3.3 数据清洗策略
发现问题只是第一步,怎么清洗才是真功夫。下面是我常用的几种策略。
3.3.1 缺失值处理
遇到NULL值,不能一刀切。得看场景。
- 删除:缺失比例很低(<5%),且该字段对分析不重要
- 填充:用均值、中位数、众数填充。比如用户年龄缺失,可以用整体平均年龄
- 预测填充:用机器学习模型预测缺失值。适合关键字段
- 标记:保留NULL,但加一个"是否缺失"的标记字段
3.3.2 重复数据去重
去重不是简单的DISTINCT。你得先定义"重复"的标准。
-- 精确去重:所有字段完全一致
SELECT DISTINCT * FROM orders;
-- 业务去重:基于业务主键去重
WITH dedup AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY order_id
ORDER BY update_time DESC
) AS rn
FROM orders
)
SELECT * FROM dedup WHERE rn = 1;
我建议用业务主键去重,保留最新的一条。比如订单号相同,取最后更新的那条记录。
3.3.3 异常值处理
异常值有两种:一种是明显错误(比如年龄200),一种是统计异常(比如交易金额突然放大100倍)。
- 阈值截断:设定上下限,超出则截断或置为NULL
- 分箱处理:将连续值离散化,比如年龄分为0-18、18-30、30-50、50+
- IQR方法:用四分位距识别离群点
3.3.4 格式标准化
格式问题,说白了就是统一规范。
-- 日期格式统一
SELECT
CASE
WHEN date_str LIKE '%/%' THEN TO_DATE(date_str, 'YYYY/MM/DD')
WHEN date_str LIKE '%-%' THEN TO_DATE(date_str, 'YYYY-MM-DD')
ELSE NULL
END AS standardized_date
FROM raw_data;
-- 手机号清洗(去除非数字字符)
SELECT
REGEXP_REPLACE(phone, '[^0-9]', '') AS clean_phone
FROM users;
我习惯在ETL入口层就做格式标准化。越早做,后面越省心。
3.3.5 业务规则校验
这个最复杂,也最重要。你得懂业务才能做。
举个例子:订单金额 = 商品单价 × 数量 + 运费 - 优惠。如果这个等式不成立,数据就有问题。
-- 业务规则校验示例
SELECT order_id,
CASE
WHEN ABS(total_amount - (unit_price * quantity + freight - discount)) > 0.01
THEN '金额不一致'
ELSE '正常'
END AS check_result
FROM orders;
我曾经遇到过一个案例:某电商的优惠券金额居然大于订单金额,导致退款时出现负数。这种问题,光靠数据清洗解决不了,得推动业务系统改逻辑。
3.4 数据质量的知识体系
下面这张图,是我自己总结的数据质量与清洗的知识框架。你照着这个思路走,基本不会跑偏。
3.5 我的几点建议
最后,分享几个实战中的心得。
- 数据质量要前置:别等到数据进数仓了再洗。在源系统、在抽取阶段就做校验,成本最低。
- 建立质量监控看板:每天自动跑质量检查,异常数据自动告警。我习惯用邮件+钉钉双通道通知。
- 保留原始数据:清洗前一定要备份原始数据。万一洗错了,还能回滚。这个坑我踩过,不说了都是泪。
- 清洗规则要文档化:每条清洗规则,谁定的、为什么这么定、什么时候改的,都得记清楚。不然半年后你自己都看不懂。
数据质量这事儿,没有一劳永逸的解法。它是个持续改进的过程。你做得越久,遇到的坑越多,经验也就越丰富。嗯,今天就聊到这儿,希望对你有帮助。