# 数据预处理步骤:如何清洗企业业务数据

> 了解如何通过数据预处理步骤,把杂乱的业务记录变成可靠的洞察,并附中小企业示例。看看 ELECTE 如何实现这些步骤的自动化。

Source: https://www.electe.net/zh/%E9%82%AE%E5%AF%84/data-preprocessing-steps

Site guide: https://www.electe.net/zh/llms.txt

你导出了一份看起来已经完工的销售数据:订单、成本和日期填满了整张表。随后,一份预测报告送到财务负责人桌上,平均订单价值却突然上升,而产品目录并没有任何变化。

这种跳升往往是预处理错误造成的,而不是购买行为发生了变化。比如,文件里还有重复发票时就去填补空白价格,或者在留出任何数据行之前就对整份导出数据做缩放,都会让模型提前学到本不该看到的信息。大多数文章把**数据预处理步骤**列成一组彼此独立、可以任意顺序应用的技术。但恰恰是顺序,让结果被夸大。

下面是我建议的做法:当分析师负责一份正在使用的业务文件时,就按这个顺序来处理。你将看到完整的执行顺序、我只当作起点而非铁律的阈值,以及一种锁定每个拟合设置的方法,让下一次数据加载沿用同样的处理路径。

## 按正确顺序执行的七个数据预处理步骤

一份销售导出数据看起来可能很完整,却仍然藏着重复的发票行、空白的单位成本,以及两种格式并存的日期。如果清理顺序不对,之后的每一个平均值都会继承这些问题。

**任何需要从数据中学习数值的步骤,都必须在拆分之后运行。**如果在整份文件上计算均值、中位数或缩放范围,验证集的数据就会影响训练。这样得出的分数看起来会比模型在下个月订单上的实际表现更好。

步骤具体操作完成标准1. 数据探查与清洗检查行数、数据类型和空值率;删除完全重复的记录;统一日期和标签格式得到干净的基础表,每个类别只有一个标签2. 拆分数据打乱行顺序,再划分为训练集和验证集两个数据集已生成,且尚未计算任何需从数据中学习的参数3. 处理缺失值删除行、删除特征,或仅使用训练数据进行填补每个字段都已完整,或已标记缺失部分4. 编码与特征工程将类别转换为数值;构建比率、时间部分和滚动平均值得到可直接用于建模的特征表,各列均有文档说明5. 处理异常值先核实极端值,再进行截断、转换或标记极端值有据可查,而不是凭猜测处理6. 数值特征缩放在训练数据上拟合缩放器,并将其应用于验证数据各数值列处于可比较的范围内7. 固化流水线保存每个已拟合的转换步骤,使新数据遵循相同的处理路径流程可重复运行,适用于每次新数据加载

假设一家零售商有 12,000 条订单行,其中包含 900 条重复的发票行。如果在删除这些重复行之前先填补缺失的价格,同一张发票就会被计算两次,平均值也会偏离价目表。

> **实用规则:**在计算下一行所需的任何数据之前,先把当前这一行处理完。

把你手头打开的文件对照这七行。第一个还没有完成的行,就是今天唯一值得动手处理的一行。

## 分析并清洗原始业务数据

数据剖析只需一小时,经理在任何人打开模型之前就能完成。请保持原始文件不动,并把每一处改动都写入清洗日志,这样财务负责人就能看到合计数为什么发生了变化。

1. **统计行数和列数,然后逐列确认数据类型。**以文本形式存储的成本无法求和,而且不会明显报错。在信任任何合计数之前,先转换类型。
2. **计算每一列的空值率。**空白超过 30% 的列应按缺失值规则处理,而不是快速填充。只有当空白超过 50% 且该字段对决策不是必需时,我才会直接删除整列。
3. **只删除完全重复的记录,不删除相似记录。**同时按发票号、日期和金额进行匹配。行 ID 不同的第二笔订单是一笔真实的销售。仅仅因为客户和日期相同就把它删掉,会造成收入被低估。
4. **一次性统一格式。**统一日期格式,每列只用一种货币,代码中不留多余空格。格式混杂会把一个产品拆成两个序列,并导致之后的关联出错。
5. **统一类别标签。**`UK`、`U.K.` 和 `United Kingdom` 是同一个市场。在一份为期三年的电商导出数据中,同一条产品线若有四种写法,造成的危害也是一样的。选定一个标签,并把其余的映射过去。

假设这份导出数据中,某一年的订单日期存为 `2024-03-01`,另一年则存为 `01/03/2024`。在两者统一为同一种格式之前,月度图表要么重复计算三月,要么漏掉三月。

### 日志与隐私剔除能起到什么保护作用

清洗日志是一张简短的表格:列、规则、改动行数、负责人、日期。当财务问起去年三月为什么变小了,你可以直接指向去重规则,而不必凭记忆重建文件。

在文件进入任何分析平台之前,先去掉客户姓名、电子邮箱和支付信息。预测需求并不需要这些信息,把它们留在提取的数据中会带来隐私问题,而这是模型无法挽回的。

如果你想了解商业数据提取“合格”的标准,可以参考 [Pipecorn 的销售数据质量洞察](https://pipecorn.com/blog/data-quality-standards),它是一份很实用的检查清单,涵盖标识符、完整性和一致性。用它来决定哪些列值得保留,然后再回到上面的空值率筛选。

## 在任何学习开始之前先拆分数据

拆分就像一道围栏。任何需要估计统计量的操作,都不应该在完整文件上进行。

对于有监督的文本分类，[Google 的文本分类指南](https://developers.google.com/machine-learning/guides/text-classification/step-3)建议在拆分前先打乱数据，因为保留原始顺序可能会使两个数据集都产生偏差。打乱之后，常见的拆分方式是将 **80%** 的样本用于训练，**20%** 用于验证。随后，两个数据集应用相同的转换，但这些转换必须先在训练数据行上学习得到。

### 为什么按顺序排列的销售文件会“说谎”

导出的数据常常已按日期、地区或客户排序。如果把这样的文件从上到下直接拆分，你会用 2023 年的数据训练，却用 2024 年末的数据验证。这样得到的分数反映的是日历、促销日程，或者某一个地区的构成，而不能说明模型是否真正理解了订单。

当每一行都是独立个案时，应当打乱数据，例如已成交的订单、已流失的账户、已分类的工单。当问题是预测未来时，则不要打乱。

> 做预测时要保持时间顺序：用较早月份的数据训练，用较晚月份的数据测试。打乱数据会让模型“看到未来”，还把这当成能力。

### 文本字段需要按频次截断

客服工单和产品描述会拆分出成千上万个词元。在同一套 Google 工作流程中，需要丢弃出现次数少于**两次**的词元，保留排名前 **20,000** 的词元特征，并用基于 F 检验的重要性得分对剩余词元排序。只出现一次的词元通常是拼写错误或一次性的 SKU，不是值得单独设一列的规律。

拆分之后，所有映射都只能基于训练数据拟合，然后将这个固定下来的映射应用到验证数据上。若在留出的数据行上重新计算词表或类别列表，就是另一种把答案泄露到数据准备环节的做法。

## 填补缺失值，同时避免结果失真

某个字段的空白频率，以及决策是否需要该字段，决定了采取哪种做法。下面的区间只是经验法则，并非定律。受监管的风险模型可能不允许删除某些数据行，而零售预测则可以舍弃这些行。

缺失比例特征重要性处理方式低于 5%任意如果剩余数据足够，删除这些行5% 至 30%低删除该特征5% 至 30%高仅根据训练集数据进行填补超过 30%高进行填补，新增缺失标记列，并调查该字段为何为空超过 30%低删除该特征

在一份本来完整的订单文件中,出现少量成本空白,这是第一类情形。删除这些行,比编造一个价格的代价更小。中间区间里一个很少使用的调查字段,不值得硬填一个猜测值,所以直接删掉这一列。用于流失分析的在网时长则要保留,并对其进行估算。

[Google 关于聚类数据准备的指南](https://developers.google.com/machine-learning/clustering/prepare-data)给出了三种实用做法:删除含缺失值的样本、删除该特征,或根据其他数据预测缺失值。缺失很少时,可以考虑删除行。缺失频繁时,通常要么删除该特征,要么进行填补。

### 预测缺失值,而不是粘贴一个常数

对于数值字段,可以用有值的行训练一个回归模型,再估算空白处。例如,缺失的客户年龄可以根据收入和在网时长来估算,而不是全部替换成公司范围内的同一个平均值。这样用到的是你已经信任的变量关系。

订单金额的分布是偏斜的。少数大额批发订单会拉高**均值**,所以用均值填补会让普通购物篮看起来比实际更“富”。**中位数**贴近典型订单,在出现一张大宗发票时变化也更小。填补前后都要对比汇总统计。如果变化很大,说明这种方法是在改写业务,而不是修补缺口。

对于类别字段,可以把空白标记为 `Unknown`。缺失本身往往就是信号:比如结账时没有采集地区,或者产品没有供应商编码。把它变成一个真实的类别水平,既保留了这一行,也让模型知道该字段是有意留空的。

在运营数据中,频繁出现空白并不罕见。2025 年一项关于用水数据不完整的研究描述了一个建筑数据集:从 2019 年 2 月到 2023 年 12 月共有 **33,888** 条小时记录,其中 **20%** 的小时存在缺失值。在这个比例下,一刀切地删除行会丢掉太多历史数据([该研究](https://arxiv.org/html/2506.08882v1))。

填补器只能用训练集的行来拟合。如果你想在方法层面(而不是订单层面)再做一轮梳理,[ELECTE 的缺失数据指南](https://www.electe.net/post/missing-data-imputation)对填补方法的选择有更详细的说明。

## 编码类别并构造有用的特征

这里有两项工作:把标签转换成模型可用的数字,以及构造能回答业务问题、而原始字段无法回答的列。

### 编码时不要制造虚假的排序

**独热编码**适用于取值较少的类别,例如五个销售区域。每个区域都变成各自的“是/否”列,没有哪个区域比另一个“更大”。

**序数编码**适用于确实有顺序的字段,例如尺码 S、M、L。这些数字对应的是业务中已经在使用的排序。

不要给渠道或城市这类无序名称赋值 1、2、3。模型会把更大的编码当作“更多”的某种程度。这种虚假的排序,之后会表现为一个很自信但错误的系数。当某个字段有数百个水平时,独热编码会生成非常宽的表。编码之前,先把稀少的水平归并为 `Other`,并且只用训练集的行来确定这种归并。

### 能回答业务问题的列

围绕一个决策列出一份简短清单,而不是把能想到的每个比率都堆进去。

- **利润率：** `(price − cost) / price` 能告诉你促销价是否仍高于成本，这是单看收入做不到的。
- **距上次购买的天数：**流失分析需要的是最近一次购买的时间，而不是客户 ID 的又一份副本。
- **星期几和月份：**需求规划关注的是周五的销量高峰和季节性月份，而这些信息都藏在完整的时间戳里。
- **滚动 7 日平均值：**每日销量起伏不定，而周平均值能显示需求是否在上升。
- **库销比：**库存经理能比只看原始在库数量更早发现缺货的苗头。

我会先从与这一项决策相关的十到十五个特征入手。当两列的相关系数超过 0.95 时，删掉其中一列，因为第二列只是重复第一列。在数据字典中，把业务含义写在列名旁边。如果编码映射或滚动平均值是在整个文件上学到的，包括你原本打算留作验证的行，就会重现你在数据拆分时已经堵住的数据泄漏。

## 缩放数值并处理异常值

极端值不一定是错误。B2B 客户下的 40 件订单是一笔真实的销售。给它加上标记，避免它主导均值，同时把它保留在历史数据中。而把 1,000 误输成 100,000 的单价则是录入错误。应当修正那个数字，而不是把它当作需求来“处理”。

### 删除极端值之前先核实

有两种检查方法搭配使用效果很好。**1.5 × 四分位距**规则可以标出远离列中间位置的数据点。领域检查则判断该值是否可能存在：负库存、十年后的日期、高于售价的折扣。先核实，然后再将数值限制在第 1 和第 99 百分位，对偏态的收入做对数变换，或者添加标记并保留原始数值用于报表。

> 你删掉的大宗订单，就是你再也无法预测的收入。你保留下来的录入错误，会变成模型以为客户愿意支付的价格。

限幅之后重新运行汇总。该列的中心位置几乎不应发生变化。如果中位数出现跳变，说明限幅的作用过大，你应该重新检查源数据行。

### 哪种缩放器适合当前的数据特征

缩放可以避免像年收入这样单位很大的列，淹没像每单件数这样单位很小的列。[Scikit-learn 的预处理文档](https://scikit-learn.org/stable/modules/preprocessing.html)指出，**StandardScaler** 以训练集均值为中心并按方差缩放各个特征，而当存在大量异常值时，它的表现可能较差。**RobustScaler** 是可直接替换的方案，它使用对异常值更不敏感的中心和范围估计。

数据特征缩放器适用原因分布大致对称，极端值很少StandardScaler以均值为中心，并按方差进行缩放存在大量离群值，例如偶尔出现的大宗订单RobustScaler使用中位数和四分位距，不易受极端值影响数值需要固定范围，例如 1 到 5 的评分MinMaxScaler将数值映射到 0-1 区间，且不改变其分布形状

只在训练数据上拟合缩放器，然后将该拟合结果应用于验证集。如果在留出集上重新拟合，验证集中的极端行就会左右缩放比例。如需在选择处理方法之前更深入地了解如何识别极端值，请参阅[ELECTE 异常值指南](https://www.electe.net/post/outlier-statistica)。

## 自动化流水线并检查输出

存放在某个笔记本中的清洗后文件，可能在不同次运行之间出现偏差。新文件可能得到不同的填充值、类别编码或缩放比例，导致仪表盘发生变化，即使底层业务并没有变化。

流水线会把已拟合的填充器、编码器和缩放器放在一起，并将相同的转换应用于新文件。这些步骤只使用训练分区进行拟合，然后将拟合得到的设置应用于验证数据和测试数据，不再重新计算。[IBM 关于数据泄漏的说明](https://www.ibm.com/think/topics/data-leakage-machine-learning)解释了为什么在训练数据和测试数据上一起拟合预处理步骤，会把信息泄漏到评估中。

### 每次运行后的检查

任务运行成功,只能说明流程执行完毕。还需要检查输出是否仍与源数据以及你设定的规则一致:

- **行数:**将加载的文件与导出数据核对,并计入已记录的重复项。
- **各列空值率:**如果空值率突然上升,请及时排查,这可能意味着某个源字段不再传入。
- **数值范围:**检查价格、数量和日期是否仍在可接受的范围内。
- **新类别:**遇到未见过的地区或 SKU 时,将其归入已定义的类别,而不是不加提示地丢弃。

想了解[数据验证的实用示例](https://www.electe.net/post/data-validation-techniques)，请查看这些检查如何应用于业务文件。请将自动生成的结果视为估计值，并在用其触发警报之前，先人工审核最初的几个周期。

**ELECTE** 是面向成长型企业的 AI 数据分析平台,可连接会计软件或上传的文件,无需分析师即可完成数据分析和预测。通过自动化财务分析,客户每周可节省 10 多个小时。但这一帮助的前提是:使用经过拟合、能够在评审中站得住脚的处理步骤,而不是在每次上传时都重新计算。

本周,请选取一个数据集,按照七行表格逐项检查,并标出哪些步骤仍需手动完成。可以将重复执行的步骤自动化,但那些需要判断的情况,例如重复记录还是真实的补货订单、录入错误还是大宗订单,在规则稳定之前仍应保留人工审核。

---

ELECTE 可连接你的会计数据或上传的文件,完成数据准备,并生成可与团队一起审阅的预测和报告。如果你希望每次加载数据时都以同样的方式执行这些数据预处理步骤,请访问 [ELECTE](https://www.electe.net),看看平台如何在你自己的数据上运行整个流程。
