做数据分析的人最烦的不是跑模型而是拿到手的数据一团乱麻。一个几百上千行的 CSV光缺失值、重复行、日期格式不统一就能耗掉大半天时间更别提那种“看着是数字实际上是文本”的阴间列。我用过的办法不少纯写 pandas 脚本撸一遍太机械带业务判断的清洗又没法标准化。这个>name: data_cleaning_skill description: 自动诊断并清洗结构化表格数据输出清洗前后的对比报告 input: 文件: 支持 csv、xlsx、tsv 格式 参数: 缺失率阈值: 0.2 异常值倍数: 1.5 是否保留原文备份: true output: 清洗后文件: 同输入格式 质量报告: markdown 格式包含清洗前后质量对比触发条件也很关键。你肯定不想在一个只有三行干净数据的小文件上也跑一遍完整链条那样纯属浪费。我的触发规则是数据行数少于 50 行或缺失率总量小于 1% 时只输出诊断报告不执行清洗只有超过阈值才进入完整流程。这条规则帮我挡掉了很多无效计算。4.2 核心工具函数实现这里给出一段核心函数的简化实现用 pandas 编写。实际使用的时候可以把这些函数组装成一个工具库供上层调度调用。import pandas as pd import numpy as np from unicodedata import normalize def profile_data(df: pd.DataFrame) - dict: 生成数据体检报告的核心指标 report {} for col in df.columns: non_null df[col].count() total len(df) missing_rate 1 - non_null / total unique_rate df[col].nunique() / non_null report[col] { missing_rate: round(missing_rate, 4), unique_rate: round(unique_rate, 4), dtype: str(df[col].dtype), } return report def normalize_text(s: pd.Series) - pd.Series: 统一文本格式全角转半角、去首尾空格、大写转小写 def _normalize(x): if pd.isna(x): return x x normalize(NFKC, str(x)).strip().lower() return x return s.map(_normalize) def remove_duplicates(df: pd.DataFrame, subsetNone) - pd.DataFrame: 去重并记录影响行数 before len(df) df df.drop_duplicates(subsetsubset) after len(df) print(f去重影响行数{before - after}) return df def detect_outliers_iqr(df: pd.DataFrame, colsNone, multiplier1.5) - pd.DataFrame: IQR 异常值检测返回带标记列的副本 out df.copy() cols cols or df.select_dtypes(include[np.number]).columns for col in cols: q1 df[col].quantile(0.25) q3 df[col].quantile(0.75) iqr q3 - q1 lower q1 - multiplier * iqr upper q3 multiplier * iqr out[f{col}_outlier] (df[col] lower) | (df[col] upper) return out这几个函数分别对应三个核心模块诊断、文本标准化、异常值标记。真实技能包里的函数会比这些更细但骨架思路就是如此每一个函数只做一件事并且必须能输出影响行数。这样上层模型才能把每一步的结果汇总成一份清晰的报告。4.3 参数选择与调优心得默认参数怎么定我说说我的经验。缺失率阈值我一般设 0.2低于 20% 的缺失直接用中位数填充超过就考虑删除行或整列。这个值不是拍脑袋定的而是参考了数据质量领域的常见分界线缺失率超过 20% 的字段代表这个数据项的采集流程本身有问题填充的意义已经不大了。异常值倍数是另一个需要根据业务调整的参数。1.5 倍是标准配置我实际用下来发现对客单价、收入这类偏态分布很强的指标1.5 倍会把大量高价值用户标成异常误杀明显。这时候我会把倍数放宽到 3并且把标记出来的异常值单独生成一个文件而不是直接删除。在真实项目里我都是这样操作的第一次跑全部用默认参数重点看诊断报告看完报告后对业务的核心指标列单独调整参数最后把人工确认过的列配置固化到 skill 的配置文件里。这样一来同一个 skill 在不同数据集上跑出来的行为是稳定的不用每次重新口头叮嘱模型“这个列别删”。4.4 让输出可解释、可追溯自动清洗最怕的不是出错而是错了你不知道。所以在技能设计里“可解释”不是加分项是硬性要求。我固定输出三样东西清洗后的数据文件。一份 Markdown 格式的清洗报告里面包含每一步操作的影响行数、前后样例对比。一份原始数据备份保留所有清洗前的记录。这里说说清洗报告的格式。每一列我都会注明“原缺失率 → 新缺失率”的变化每个删除操作都会列出删除行的部分特征值。比如“删除了 12 行重复记录删除样本中有 10 行手机号相同2 行邮箱相同”。这种细节能让你快速判断当时删除逻辑是不是合理。我自己踩过一次坑某次清洗自动把 200 行“下单时间为空”的记录删了当时看报告觉得没问题后来线上订单对账怎么都对不上。最后发现那批记录是线下订单时间填在另一个字段里。从那以后我的技能里永远保留了原文备份并且所有删行操作必须带原因标签这个习惯救了我很多次。5. 常见问题与排查技巧实录5.1 清洗结果把业务数据改坏了怎么办改坏数据是早晚会发生的事关键是怎么及时发现。我的排查套路是先看“清洗前后对照表”里的差异行重点盯两类列唯一标识列比如 ID和时间列。这两类列一旦发生变化一定是清洗逻辑出了问题直接回滚到备份数据重来。一个比较隐蔽的坑是类型转换导致的数据精度丢失。比如把 float 的订单金额转成 int表面看只是去掉了小数点实际上可能把 999999.99 变成了 999999一条差 0.99 元。几百条下来对账就差了 300 多块。这种问题靠肉眼很难发现所以我后来加了一条硬性规则凡是数值列清洗前后必须对比 sum 和 count数值对不上就自动终止流程。5.2 模型判断和规则打架时怎么处理模型说“这列该删”规则说“这列缺失率还行”听谁的我的原则是确定性规则优先模型建议只作为补充。模型判断的优势在于理解语义劣势在于不一定理解数据的采集背景。当两者冲突时规则负责“能不能删”模型负责“该不该删”。规则判断结果为“不能删”的时候模型给出建议也只能进入人工确认队列不能直接执行。举个实际例子某个字段缺失率 70%规则层判定建议整列丢弃但模型识别出这是“首次访问来源渠道”是业务方核心指标两者冲突。最终处理是保留列并改为填充“未知”同时标记人工复核。这种妥协方案比直接听任一方都稳妥。5.3 大文件跑不动、超时怎么办数据清洗遇到大文件是常态。几十万行、上百列的数据跑一次诊断报告就要半天那肯定不行。我的处理办法是分三步先抽样诊断、再全量执行、最后对比验证。抽样诊断是从全量数据里随机抽 1 万行跑一遍体检报告确定清洗策略全量执行时只跑已经定好的规则逻辑不重复计算诊断指标最后用清洗前后的整体统计量做对比比如行数差、缺失率变化、数值列的求和差异确保抽样得到的策略在全量数据上没跑偏。这套流程把原本几十亿次的计算量降了几个数量级实际效果非常明显。5.4 常见脏数据速查表最后整理一个速查表基本覆盖了我在真实场景里遇到的大部分脏数据形态问题类型表现形态推荐处理策略隐式缺失-、/、无、NULL、空字符串统一映射为 NaN再走缺失值处理哨兵值1900-01-01、999999、-1单独识别并标记不当作普通值格式混用日期多种写法、全角半角混用统一解析 NFKC 标准化近似重复除主键外字段完全一致按业务字段组合分组后去重非法语义地址列混入手机号、数值列含文本模型语义校验 人工确认数值含单位1万、1.5k、10%正则抽取后按业务单位换算错位数据列内容整体偏移一列先识别高置信度列名对齐再回填编码乱码中文变锟斤拷统一转 UTF-8必要时重新解码这张表我贴在工作台旁边。处理数据的时候先对号入座再决定用哪个工具函数思路会清晰很多。6. 把>
阅读完成 · 觉得有帮助?