ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

数据清洗在大数据项目中的关键作用:原理、方法与实战指南

数据清洗在大数据项目中的关键作用:原理、方法与实战指南 1. 数据清洗到底是什么为什么所有大数据项目都绕不开它做了这么多年数据相关的工作我越来越觉得“数据清洗”是个被严重低估的环节。很多人一听“清洗”两个字觉得就是删删空值、去去重简单得很。真到了实际项目里你才会发现数据清洗往往占整个数据分析流程 60% 以上的工作量而且决定了一个项目到底是能落地出洞察还是做个寂寞。先给个定义。数据清洗英文叫 Data Cleaning 或者 Data Cleansing指的是对原始数据进行检测、纠错、去重、格式统一、缺失值处理、异常值识别等一系列操作把“脏数据”变成“干净数据”的过程。所谓脏数据就是不符合质量要求的数据——比如字段缺失、格式混乱、重复记录、取值越界、逻辑矛盾等等。我习惯把数据清洗理解为“搬家前的打包整理”。你从旧房子搬进新房子如果只是一股脑把东西塞进箱子到新家之后你会发现东西找不到、易碎品碎了、过期食品和新鲜食品混在一起。数据处理也是一样原始数据就是那一堆混乱的东西数据清洗就是分门别类地打包、扔掉垃圾、把易碎品单独保护起来。不做这一步后面住得越久越难受。这里要重点提一个概念GIGO即 Garbage In, Garbage Out垃圾进垃圾出。如果你的模型输入的是垃圾数据那么无论算法多先进、计算资源多充足输出的结果也一定是垃圾。这个原则在大数据时代尤其致命因为数据量大并不等于数据质量高量大只会让错误被放大得更快。那数据清洗到底能解决什么问题我总结下来主要是四类数据不完整比如用户注册信息只有手机号没有年龄和性别。这在统计用户画像时会直接导致样本偏差。数据不一致同一个字段在不同记录里格式完全不同。比如日期有的写 2024-01-01有的写 2024/1/1还有的写 20240101非常让人崩溃。数据重复同一条记录因为采集渠道不同或系统bug被存了多份。这会导致计数类指标虚高、去重统计失真。数据错误明显不合逻辑的值。比如年龄填了 289、销售额是负数、商品单价超过 999999 这类越界数据。适合谁来学这篇文章我建议以下三类人认真读一是刚接触数据分析、大数据开发的学生这类人经常在课程设计或毕业设计中要做数据清洗网上教程零碎看完还是不会二是已经入行但主要写业务代码、很少碰数据质量问题的开发人员需要了解数据清洗的完整方法论三是做数据治理、数据中台建设的从业者需要系统梳理清洗流程并建立质量规范。无论你是哪个阶段这篇文章都会给你一套可以照着用的思路和工具方案。2. 数据清洗在大数据项目中的角色和位置2.1 大数据流程中的“咽喉要道”一条标准的大数据流水线通常长这样数据采集来自业务库、日志、埋点、爬虫、传感器→ 数据清洗与预处理 → 数据存储数仓、数据湖→ 数据计算与分析 → 数据可视化或模型训练。看一下“数据清洗与预处理”这步的位置上下游都依赖它。上游采集的数据是完全没有约束的来源越多样、格式越混乱下游的分析、建模、报表全部建立在清洗后的数据上。这个环节要是松了就等于整条流水线里埋了一颗雷它不会立刻爆炸但会在某个分析结果出来时让你被业务方质疑劳动成果。在实际项目中我见过一个典型的案例。某电商平台做转化率分析原始埋点数据里同一个用户把商品加入购物车再删除又加回来再删除记录了 8 条会话。不做清洗直接统计购物车转化率比真实值高了 300%。这种错误看起来很低级但如果不按会话去重、不结合时间窗口做状态机判断你根本发现不了。这就是数据清洗在大数据链路里的价值——它不是锦上添花而是决定数据能不能用的关键关卡。2.2 数据清洗与数据治理的关系数据清洗不是孤立动作它其实是“数据治理”这个大体系里的核心执行环节。数据治理讲的是全生命周期管理包括数据标准制定、元数据管理、数据质量度量、数据安全与权限、数据生命周期策略等。而数据清洗就是数据质量这条线上最落地的动作。打个比方。数据治理是交通法规体系数据清洗就是路口的红绿灯和交警——法律法规立了再多真到具体路口还是要有人指挥车辆按顺序通行把违章车拦下来。没有清洗治理就是空头文件没有治理框架清洗也只是打游击今天洗这一块明天那一块永远洗不干净。实际做治理时我建议建立一套数据质量规则库。把清洗规则沉淀成可配置的校验条件。比如完整性规则核心字段非空率必须达到 99% 以上唯一性规则业务主键去重率 100%合法性规则年龄范围 0–120金额非负且小于 100 万一致性规则省份字段必须匹配国家行政区划代码表有了这套规则库数据清洗就从“每次临时写脚本”升级成“可重复执行的质量保障流程”这也是很多大厂数据平台团队在做的方向。3. 核心清洗工作全拆解缺失、重复、异常、格式3.1 缺失值处理不要一味“删”缺失值是最常见的脏数据形态。但“有缺失”不代表“有问题”关键是缺失的比例、缺失的字段重要程度、缺失产生的机制。处理缺失值有几种策略删除缺失记录适用于缺失比例很低比如 1% 以下且删除后不影响样本代表性的时候。填充缺失值用均值、中位数、众数、前后值、模型预测值来补。数值型字段一般用中位数填充比均值更稳因为均值容易被极端值拉偏类别型字段用众数填充。单独分组把缺失本身作为一个取值比如“未知”“未填写”在建模时让模型自己学习这个分组的模式。不处理某些算法天然能容忍缺失值比如 XGBoost、LightGBM 这类树模型分裂时能自动处理缺失方向的划分。举个例子。用户画像项目里用户的“年龄”字段缺失率达到 40%这个时候如果你直接把缺失记录删掉剩下 60% 的样本可能就不是总体用户了——年纪大的人不爱填年龄这是有偏的。正确的做法是用其他字段比如注册时长、消费类目去建模预测年龄或者把年龄切成“已知”和“未知”两个群体单独分析。3.2 去重定义好“唯一粒度”比用什么工具更重要很多人以为去重不就是一行的所有字段都相同就删掉一个吗其实远没那么简单。真实场景里重复记录可能只是部分字段相同而且可能由于采集时间不同、来源渠道不同几条记录之间存在细微差异。去重的关键在于明确业务粒度。比如订单数据业务粒度是“订单号”那只要订单号重复就认为是重复数据再比如用户行为日志粒度是“用户 ID 会话 ID 事件类型 事件时间”这四个维度都相同的才算重复。技术实现上如果去重字段就一个或两个用 SQL 里的ROW_NUMBER() OVER(PARTITION BY ... ORDER BY ...)窗口函数就能轻松搞定。比如保留每个订单号里最新一条记录SELECT * FROM ( SELECT *, ROW_NUMBER() OVER(PARTITION BY order_id ORDER BY update_time DESC) AS rn FROM raw_orders ) t WHERE t.rn 1;如果是多维度的近似去重比如文本相似内容去重、图片相似去重那就得上 SimHash、MinHash 这类局部敏感哈希算法了。我做过一个舆情数据清洗同一个新闻被不同站点转载改写标题 80% 相似普通的字段精确去重根本不管用最后是跑 MinHash 做 Jaccard 相似度聚类效果才过得去。3.3 异常值检测先判断“真异常”还是“业务真相”异常值不等于错误值。比如一个美妆电商的订单里突然有笔金额 20 万的大单可能是团体采购也可能是一场数据错误。直接删掉很可能把真实业务现象抹掉不处理又会影响统计分布。处理思路分三步描述性统计摸底用describe()看 min、max、均值、分位数快速发现越界值。规则统计双重判断越界的用业务规则剔除比如年龄 120 直接判错不越界但偏离分布的用 3σ标准差原则或者 IQR四分位距方法标记出来人工判断。异常值记录台账把每个被标记的异常值、判断依据、处理方式记录下来方便后续追溯。IQR 方法是这样的计算 Q125 分位和 Q375 分位IQR Q3 - Q1任何小于 Q1 - 1.5 * IQR 或大于 Q3 1.5 * IQR 的值都被认为是离群点。这个标准在工程实践里用得最多因为它不依赖数据分布假设比 3σ 更稳健。不过要注意正态数据用 3σ 更合理偏态数据用 IQR 更合理没有绝对最好的方法只有适不适合当前数据。3.4 格式统一和数据标准化这一块看似技术含量不高却是最磨人的。日期格式、手机号格式、金额单位、是否带空格、全角半角、大小写……每一个都能让数据爆炸。我做过一个旅游网站的分析项目数据来自三个渠道APP 埋点、小程序埋点、第三方广告投放回传。三个渠道的日期格式分别是 20240101、2024-01-01、2024/01/01 00:00:00平台字段一个叫 ios、一个叫 iOS、一个叫 iPhone国家字段有“中国”、“China”、“CN”、“中国大陆”。你看数据量不大吧但处理起来没有一个统一的清洗逻辑分析代码里就得写一堆 CASE WHEN 做兼容代码极其丑陋且难维护。正确的做法是接入时统一规范日期统一成yyyy-MM-dd HH:mm:ss枚举值统一成规范编码比如性别 0/1/2平台 ios/android/h5字符串 trim 掉首尾空格全角转半角金额统一成浮点数单位默认元用 Python 里的 pandas 做这类规则性清洗非常顺手。全角半角转换可以用一个字典映射实现。日期统一可以用pd.to_datetime()加format参数。4. 主流清洗工具和框架选型按场景对号入座4.1 数据量不大、灵活调试Pandas 是王者Pandas 适合单机处理的数据量一般百万级以下开发效率极高写清洗代码像写业务逻辑一样自然而且能看到中间结果适合做探索式清洗。常用操作import pandas as pd df pd.read_csv(raw_data.csv) # 查看缺失值 df.isnull().sum() # 填充缺失值 df[age].fillna(df[age].median(), inplaceTrue) # 删除全部为空的行 df.dropna(howall, inplaceTrue) # 去重 df.drop_duplicates(subset[user_id, event_time], keeplast, inplaceTrue) # 类型转换 df[create_time] pd.to_datetime(df[create_time], format%Y-%m-%d %H:%M:%S) df[amount] df[amount].astype(float)Pandas 的优势在于生态丰富。处理完清洗还能直接做分析画图数据科学家最喜欢。缺点也明显——数据量超过内存就干瞪眼而且清洗代码的复用性一般改一次源表结构就要改一堆代码。4.2 海量数据分布式清洗Spark 是主力当单日数据量到亿级、TB 级就只能上 Spark。Spark 的核心思路是把数据切分到多个节点并行计算清洗逻辑通过 DataFrame API 或 SQL 表达提交到集群上跑。Spark 清洗的典型写法val df spark.read.option(header, true).csv(/data/raw/orders) // 去重 df.dropDuplicates(order_id, event_time) // 空值处理 df.na.fill(Map(age - 0, city - 未知)) // 过滤异常 df.filter($amount 0 $amount 1000000) // 自定义 UDF 清洗复杂字段 val cleanPhoneUDF udf((phone: String) { phone.replaceAll(\\s, ).replaceAll(-, ) })用 Spark 做清洗的好处是同一个逻辑从几百万行搬到几亿行不需要改算法只要调集群资源就行。但代价是开发和调试成本高不能像 pandas 一样随手查看中间结果当然现在有 Spark 的交互式 notebook 可以缓解这个问题。这里需要特别强调一下MapReduce 综合应用案例。很多人觉得 MapReduce 过时了但做网约车数据分析、招聘数据清洗这类经典综合项目时MapReduce 反而是最能理清分布式计算逻辑的框架。它把清洗任务拆成 Map 和 Reduce 两个阶段Map 阶段逐条处理原始数据完成格式转换、字段提取、无效数据过滤Reduce 阶段按 key 聚合完成去重、统计类清洗。这个过程虽然写起来比 Spark 繁琐但它把分布式计算的本质讲得很清楚。大数据专业的学生如果只是调 Spark API很难真正理解 shuffle 和数据分区带来的问题跑一次 MapReduce 手动实现清洗逻辑很多概念一下就通了。4.3 企业级数据质量平台脚本之外的工程化方案如果公司数据规模大、部门多靠各业务线自己写 Python 清洗脚本最终一定失控。每人都按自己的理解定义“干净数据”口径必然打架。这时候需要的是数据质量平台比如 Apache Griffin、Great Expectations、Deequ 这类工具以及企业自研的数据质量中心。这类平台的思路是把数据质量规则非空、唯一、枚举合法、值域范围、表行数波动配置化、可视化然后定时调度执行产出质量报告。当某张表的空值率超过阈值、主键出现重复时会自动告警甚至阻断下游任务执行。我参与建设过一个数据质量中心整体架构是这样的规则配置层Web 界面配置表级别和字段级别的质量规则定时调度层用 Airflow/DolphinScheduler 每天跑质量校验任务执行引擎层SQL 模板自动生成校验 SQL跑在 Hive/Spark 上质量报告层输出质量分、问题明细、责任归属推送给对应数据负责人这个体系的好处是数据质量问题从“事后分析”“临时救火”变成“事前预防”“事中监控”。规则库一次建立长期受益。数据团队终于不用每天被业务问“这个数为什么不对”了。5. 网约车大数据综合项目实战一个完整的数据清洗实例5.1 项目背景和原始数据结构网约车项目是大数据学习的经典综合案例因为它天然包含多种数据形态订单数据、轨迹 GPS 数据、司机数据、乘客数据、天气数据、城市区域数据。我对基于 Spark 的数据清洗流程做一次完整拆解这个流程也适用于绝大多数位置相关项目。假设原始订单表order_info长这样字段名类型说明order_idstring订单号driver_idstring司机 IDpassenger_idstring乘客 IDstart_timestring出发时间原始格式混乱end_timestring到达时间start_lngdouble起点经度start_latdouble起点纬度end_lngdouble终点经度end_latdouble终点纬度distancedouble里程公里amountdouble订单金额元statusstring订单状态数据是从日志文件抽取出来的常见问题有订单重复上报、经纬度为 0代表定位失败、金额为负、起止时间格式不一致、状态字段有“已完成”“complete”“COMPLETED”三种写法。5.2 清洗规则设计在设计清洗规则之前先要回答一个问题这个数据要用来做什么分析如果只做订单量趋势分析经纬度缺失可以不处理如果要做区域热力图经纬度必须清洗。所以清洗规则的制定必须跟着下游需求走不是一个通用模板套所有项目。这个网约车项目要做三件事各城市订单量分布、出行高峰时段分析、平均客单价分析。据此设计规则如下订单号非空且唯一重复数据只保留最新状态的那条状态字段统一映射完成/complete/COMPLETED → 1取消/cancel/CANCELLED → 0时间字段统一为yyyy-MM-dd HH:mm:ss同时过滤开始时间晚于结束时间的逻辑矛盾记录经纬度范围校验经度 73–135纬度 3–53超出或者为 0 的标记为无效定位这个项目里不删除因为订单仍可能有效金额非负且小于 1000 元超出视为异常订单里程与金额做交叉校验平均每公里价格 amount / distance合理范围应在 1–5 元之间超出则标记异常5.3 Spark 清洗代码核心实现import org.apache.spark.sql.SparkSession import org.apache.spark.sql.functions._ val spark SparkSession.builder() .appName(ride_data_cleaning) .enableHiveSupport() .getOrCreate() // 读取原始数据 val rawDF spark.read.option(header, true) .csv(/data/ride/raw/order_info) // 1. 去重保留每个订单最新记录 val dedupDF rawDF.dropDuplicates(order_id) // 2. 状态字段统一映射 val statusMap Map( 已完成 - 1, complete - 1, COMPLETED - 1, 取消 - 0, cancel - 0, CANCELLED - 0 ) val statusExpr statusMap.map { case (k, v) when(lower(trim(col(status))) k.toLowerCase, v) }.reduce(_ otherwise _) // 3. 时间格式统一 val timeDF dedupDF.withColumn(start_time_clean, when(col(start_time).rlike(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}), col(start_time)) .otherwise(unix_timestamp(col(start_time), yyyy/MM/dd HH:mm:ss).cast(timestamp)) ) // 4. 过滤逻辑矛盾数据 val logicDF timeDF.filter(col(start_time_clean) col(end_time_clean)) // 5. 异常标记而非删除 val markedDF logicDF.withColumn(is_invalid_location, when(col(start_lng) 73 || col(start_lng) 135 || col(start_lng) 0, 1).otherwise(0) ).withColumn(is_abnormal_amount, when(col(amount) 0 || col(amount) 1000, 1).otherwise(0) ) markedDF.write.mode(overwrite) .partitionBy(dt) .saveAsTable(ods.order_info_clean)注意这里我用的是“异常标记”而不是直接删除。为什么因为异常数据可能仍然带有分析价值直接删掉就丢了信息。比如金额为负的订单可能是退款单在分析日均营收时应该排除但在分析取消率时反而要计入。做成标记字段下游各取所需。5.4 清洗结果评估效果要用数据说话洗完之后怎么确认洗得有效建议从三个维度做前后对比数据量变化记录数从原始 1200 万降到去重后的 986 万重复率约 17.8%说明上游存在严重重复上报。字段完整率经纬度合法率从清洗前的 78% 提升到 96%这部分提升主要靠地理位置范围过滤。逻辑一致性验证时间倒挂的记录数从 3.2 万降到 0状态字段唯一枚举值从 17 种归一到 2 种。这个效果汇报出来基本所有人都能直观感受到清洗的价值——没有人愿意用 1200 万里包含 214 万条重复数据的基础表去做业务报表。6. 校园大数据项目里的数据清洗小白也必须会的基本功6.1 校园场景数据的独特性校园大数据项目这几年很火——校园卡消费数据、图书馆入馆数据、选课数据、宿舍门禁记录、体测数据。这类项目和工业界项目相比数据量不大几百 MB 到几个 GB但脏的情况一点也不少。我在带学生做校园大数据项目时最常见的脏数据有这些同一个学生在不同表里的学号格式不同有的带学院前缀有的不带校园卡消费记录里有退款记录和系统测试记录混在其中一卡通数据中同一笔消费被重复上传POS 机断网重传导致门禁记录的时间居然是“2024-02-30”这种不存在的日期提示校园数据虽然量小但它涉及的人员隐私和敏感性很高。做项目时务必进行脱敏处理——学号要打码、姓名要做映射替换、精确消费金额可以按区间化处理。这和工业界的 PII个人身份信息保护思路是一致的。数据清洗不只是技术活还涉及合规意识。6.2 Excel 也能做的“轻量级清洗”很多学生一上来就学 pandas反而忽略了 Excel 本身就是一款不错的数据清洗工具。我建议在没学编程之前先用 Excel 建立对数据质量的直觉。Excel 里常用的清洗功能删除重复项数据选项卡 → 删除重复值可以选择判断列分列文本分列功能按分隔符或者固定宽度拆分字段清洗“20240101张三88”这种混乱文本特别好用查找替换支持通配符? 匹配单字符* 匹配多字符清理乱码字符和统一格式的利器条件格式把空值、重复值高亮出来肉眼快速定位问题Power Query这才是 Excel 清洗的大招——支持合并查询、逆透视、自定义列、清洗规则复用而且可以记录每一步操作形成查询流程下次数据更新后一键刷新基本相当于一个可视化 ETL 工具这里特别想聊一下热词里提到的“替换多个怎么写函数”这个问题。Excel 里如果要替换多个不同内容很多人第一反应是连续写多个 SUBSTITUTE 嵌套比如SUBSTITUTE(SUBSTITUTE(A1,北京,北京市),上海,上海市)这在替换数量少的时候没问题但如果要替换几十种方言叫法比如“俺”“咱”“阿拉”全统一成“我”嵌套就会非常痛苦。我的建议是用文本替换的超级公式组合用 SUBSTITUTE 嵌套、TRIM 去空格、CLEAN 去非打印字符再加上数组公式或 VBA 批量处理。pandas 里也有replace()配合字典实现多对一映射df[city] df[city].replace({北京: 北京市, 上海: 上海市, BJ: 北京市})这个我觉得才是“替换多个怎么写函数”的最佳答案。处理批量映射类清洗优雅程度从高到低排序pandas 字典映射 Excel Power Query 的替换功能 嵌套 SUBSTITUTE。选择哪个取决于你手里的工具我个人的经验是超过 5 种映射就建议不要用 SUBSTITUTE 嵌套了代码会变得完全不可读。6.3 Python pandas 在校园项目里的实操模板如果校园项目有一点数据量几十万行并且要做相对系统的分析我推荐用下面的 pandas 清洗模板。这个模板可以做很多项目的通用底座import pandas as pd import numpy as np # 读取原始数据 df pd.read_excel(campus_card_raw.xlsx) # 第一步概览 print(df.shape) print(df.dtypes) print(df.isnull().sum()) # 第二步类型修正 df[trade_time] pd.to_datetime(df[trade_time], errorscoerce) df[amount] pd.to_numeric(df[amount], errorscoerce) # 第三步非法值替换为 NaN df.replace([np.inf, -np.inf], np.nan, inplaceTrue) # 第四步缺失值处理 # 金额缺失的删除因为这些记录没有分析价值 df df.dropna(subset[amount]) # 商户名称缺失的填充为“未知商户” df[merchant_name] df[merchant_name].fillna(未知商户) # 第五步去重 df df.drop_duplicates(subset[student_id, trade_time, amount]) # 第六步异常值处理IQR方法 Q1 df[amount].quantile(0.25) Q3 df[amount].quantile(0.75) IQR Q3 - Q1 lower_bound Q1 - 1.5 * IQR upper_bound Q3 1.5 * IQR df[is_outlier] ((df[amount] lower_bound) | (df[amount] upper_bound)).astype(int) # 保留异常标记不在清洗阶段删除 df.to_csv(campus_card_clean.csv, indexFalse, encodingutf-8-sig)注意最后一行我用了encodingutf-8-sig这是给 Excel 读取用的不加 BOM 的话用 Excel 打开中文会乱码。这个细节是学生最容易踩的坑每次看到都提醒一次但总是有人再踩。7. 招聘数据清洗实战MapReduce 思路与 SQL 笔试高频考点7.1 招聘数据的典型“脏”法招聘数据清洗是很多实验课和比赛的选题比如头歌平台上就有“实验4 MapReduce 综合应用案例——招聘数据清洗”说明这个场景被认为是分布式数据处理的不错入门案例。招聘数据常见的脏问题非常典型职位名称不统一“Java开发工程师”和“java开发”其实是同一个意思、薪资字段格式混乱“15k-25k”“1.5万-2万/月”“面议”、学历字段枚举值繁多“本科及以上”“本科”“硕士/MBA”“大专”、公司规模数值和文字混排“100-499人”“少于50人”、发布时间格式多样。清洗这类数据的关键是“字段标准化映射”。以薪资为例最合理的方式是解析成最低月薪和最高月薪两个数值字段以“千元/月”为单位。解析思路统一把“万/月”转成“k/月”比如 1.5万-2万/月 → 15k-20k/月去掉“面议”“薪资面议”等无数值记录单独归为“面议”类别按分隔符-、—、~拆出上下限转成浮点数7.2 MapReduce 清洗实现逻辑拆解用 MapReduce 来做招聘数据清洗实际写起来比 Spark 繁琐但它能帮你深入理解分布式计算的基本模型。整体思路可以拆成 Map 和 Reduce 两个阶段Map 阶段做的事情逐行读取 CSV 文本按分隔符切分字段对每一行数据独立做格式标准化、非法值过滤、字段映射输出行号, 清洗后的记录键值对。其实大部分清洗逻辑都在 Map 阶段完成Reduce 阶段做的事情按某个 key比如职位类别做聚合把同一类别的数据合并输出同时可以附带统计信息用 MapReduce 做清洗的实际体验是把逻辑想清楚比写代码更花时间。每一条规则都要想清楚“这一步是 map 还是 reduce”答案是除了需要跨记录比较的操作去重需要看全局、聚合需要先分组绝大多数清洗逻辑都是 map 阶段逐条处理的。这也是为什么 Spark 里用 DataFrame API 写清洗感觉和写 SQL 差不多因为 Spark 已经把 MapReduce 的细节封装掉了。7.3 大数据 SQL 面试题里的清洗陷阱面试大数据岗位时SQL 数据清洗是高频考点基本每轮必问。面试官考察的无非这几个能力窗口函数、空值处理、字符串处理、CASE WHEN 逻辑。常见面试题整理Q1用户登录表里有重复登录记录如何统计真实用户数SELECT COUNT(DISTINCT user_id) FROM login_log;如果是统计每日活跃用户数去重口径则是SELECT dt, COUNT(DISTINCT user_id) AS dau FROM login_log GROUP BY dt;Q2订单表中无下单时间的订单如何按天统计思路先把时间字段做 coalesce 兜底比如COALESCE(order_time, create_time)如果都没有就归到“未知时间”分组。这一题考察的是对脏数据场景的处理意识不是纯函数记忆。Q3如何把15k-25k的薪资字符串解析出最低值和最高值MySQL 或 Hive 里可以用 split 和正则SELECT CAST(SPLIT(REPLACE(salary, k, ), -)[0] AS INT) AS min_salary_k, CAST(SPLIT(REPLACE(salary, k, ), -)[1] AS INT) AS max_salary_k FROM job_info WHERE salary LIKE %-%;无论如何SQL 面试的核心是用最简洁的方式表达清洗逻辑。平时要刻意训练自己“拿到一张脏表第一时间就想清楚去重键、过滤条件、映射规则”的思维习惯。8. 清洗过程中的典型问题与排查套路8.1 内存爆炸pandas 处理几百万行数据时经常卡死常见原因读入了不需要的列、字段类型对象占用内存过大、反复 copy 数据框。优化手段pd.read_csv(usecols[col1, col2])只读需要的列用dtype参数预先指定列类型比如把城市名指定为 category 类型尽量使用inplaceTrue或链式操作避免反复创建新 DataFrame如果数据实在大到单机内存扛不住赶紧切换到 Spark 或者用 Dask 做分块处理不要硬扛。8.2 清洗后的数据反而“变少”太多有些同学洗完数据发现 1000 万行了剩下 100 万直接慌了以为是代码写错了。其实第一步不是检查代码而是回头看你到底过滤了什么规则。最常见的流失原因是多个过滤条件叠加后总过滤比例远超预期——每条规则单独看只过滤 10%但五条规则叠加后数据量只剩 50% 甚至更少。这算是清洗逻辑的累计效应本身不算错误但每个过滤动作都要刻意确认一下合理性。如果某条规则过滤比例超过 30%需要停下来单独审视这条规则是否过严。我通常的做法是为过滤动作打点计数给每类规则做一条单独的“清洗日志”标明规则名、命中数量、原因示例。这样下来每个过滤规则的影响都透明可查不会出现数据量骤降时像无头苍蝇一样排查的情况。8.3 字符编码问题读取 CSV 出现乱码大概率是指定编码不对。中文数据常见的编码是 utf-8 和 gbkPython 读取时如果默认 utf-8 报错可以尝试encodinggbk或者更健壮的encodingutf-8errorsignore。写文件时注意 Excel 需要 utf-8-sig 才能正常显示中文这个点之前提过值得再强调一次。8.4 时间字段解析失败pd.to_datetime()报错一般有两种情况日期格式不统一比如有 2024-01-01 也有 2024/01/01或者存在非法日期比如 2月30日。解决方式df[dt] pd.to_datetime(df[dt], format%Y-%m-%d, errorscoerce)errorscoerce的意思是解析失败的置为 NaT不会中断。之后再对 NaT 的数据单独处理。我建议任何生产级的清洗代码都要带上这个参数否则一条脏数据就能让整个任务崩溃。8.5 清洗规则变更后的重复执行问题数据清洗不是一次性的它是周期性任务。比如每天跑当天新增数据的清洗那么每次跑的时候要保证清洗逻辑可重复执行。最稳妥的做法是每次清洗前先清理目标表再写入完整数据不能搞增量追加和全量覆盖混用的逻辑。另一个问题是历史清洗过的数据如果规则变了怎么办建议在目标表增加data_version字段记录清洗规则版本这样规则变更后可以按版本重新清洗。9. 常见问题速查表问题现象可能原因解决方案数据量清洗后下降太多多个过滤规则叠加累计过滤率过高分规则打点统计过滤量审查单条规则的合理性中文字段读取乱码源文件编码与读取编码不一致尝试 gbk / utf-8 / utf-8-sig 编码pd.to_datetime报错日期格式不统一或存在非法日期加errorscoerce解析失败的后置处理去重后结果仍不干净去重键粒度设置不合理结合业务语义重新定义业务粒度字段清洗代码跑得极慢单机 pandas 处理超出内存换 Spark或只读取必要字段、指定 dtype每日清洗任务结果波动上游数据源结构变化建数据质量监控表结构变化自动告警Excel 打开清洗结果乱码文件无 BOM 头保存时用encodingutf-8-sig过滤掉的值其实有业务含义规则太硬未区分标记和删除用标记字段替换删除保留数据可选性这条速查表其实是我做每个清洗项目时都会维护的“排雷手册”。建议你也建一个自己的每踩一次新坑就往里加一条这个表的价值会随着年深日久而显现它是你个人经验的最好承载。10. 关于工具选型和架构层的一点思考10.1 不同规模下的清洗技术选型这些年我经历过的不同数据规模阶段对应的技术栈选择完全不同可以给一个比较通用的参考数据规模推荐方案理由单表百万行以下pandas / Excel Power Query开发效率高、可视化好、不需要集群单表百万到千万行pandas 分块读取或单机 DuckDBDuckDB 能跑 SQL内存友好单表亿级Spark / Hive分布式并行清洗吞吐高企业级多源数据数据质量平台 Spark 定时调度规则配置化、可监控、可追溯选型的一条原则能简单就不复杂。单机 pandas 能解决的事没必要上 Spark 集群Spark 再牛也不能解决你代码逻辑本身就是错的问题。反过来数据真到了亿级还硬用 pandas那就是给自己找罪受。10.2 清洗代码的工程化规范把清洗脚本从“一个人自己用”变成“团队可维护的资产”我建议遵循以下规范清洗脚本与业务逻辑分离清洗规则配置化做成 YAML/JSON 文件不要写死在代码里每个清洗规则有唯一 ID方便定位问题和追踪口径保存清洗日志每个步骤的输入行数、输出行数、规则命中行数全部记录清洗结果输出数据质量报告每次清洗结束自动生成质量报告发给下游消费者用 YAML 管理清洗规则的一个简单例子rules: - rule_id: R001 name: order_id_non_null type: completeness field: order_id condition: is not null action: drop - rule_id: R002 name: status_normalize type: consistency field: status mapping: 已完成: 1 complete: 1 COMPLETED: 1 取消: 0这样做的好处你以为是在管理清洗逻辑实际上是在管理公司的数据口径资产。数据口径无论在哪里都是业务争抢点能把口径固化成规则文件绝对是数据团队的重要沉淀。11. 数据处理思维进阶从清洗到数据质量的全局视野做多了数据清洗你会慢慢发现一个道理清洗的尽头是数据质量体系的建设。单次项目的清洗解决的是“这一批数据能不能用”的问题而数据质量体系解决的是“以后的数据怎么一直都是可用的”的问题。从个人角度讲培养数据质量意识有几个习惯值得刻意练习一是每拿到一份数据先问自己三个问题这份数据是谁产生的它的业务含义是什么它被采上来之后经历了多少加工环节这三个问题能帮你快速定位脏数据的来源。比如日志数据因为网络波动产生断档业务库数据因为状态机迁移产生冗余历史值如果是系统 bug 导致的脏光靠清洗脚本是不够的要推动技术团队去修源头。数据清洗做了几年后你会非常认同一个观点最好的数据清洗是根本不产生脏数据。源头治理比下游清洗的效率高十倍。二是养成“清洗留痕”的习惯。每做一步操作都要能说清楚为什么做、影响了多少数据。很多数据的“不可信”往往就是说不清数据经历了什么加工。分析师的报表被人挑战时如果拿不出清洗过程的说明就很难让人信服你的结果是可靠的。三是把数据质量当做长期指标来经营。不要只盯着项目交付那一刻的数据情况要为每一张核心表建立质量基线持续监控波动。大数据时代的数据清洗早已不是当年“临时写个脚本跑一把”的野路子它在数据治理体系里找到了自己的位置从一套散落的处理技巧沉淀成标准、规则、自动化平台和监控告警四位一体的工程质量保障。这也是我在标题里强调“关键作用”的原因——在整个大数据链路中数据清洗可能是最不性感但最不能出错的环节它的价值不在于用了多牛的算法而在于托住了整条数据链路的地基让下游的一切分析、挖掘、建模都站在一个可靠的基础上。最后分享一个我个人的体会。在我做过的所有数据项目里唯一一次让业务方当场认可数据团队价值的时刻不是模型上线时精确度狂飙的瞬间而是一张几百亿行的核心报表做完彻底清洗、口径核对无误、连续一周零告警的某天早会上。那种踏实的信任感是做数据的人能收获的最好的正反馈。希望这篇文章能帮你在数据清洗这条路上少踩几个坑早一点建立起自己的数据质量方法论。
返回列表