为什么数据预处理如此重要?
想象你要做一顿美味的饭菜。你去菜市场买了新鲜的蔬菜、肉和调料。但回到家发现:有些蔬菜烂了,肉有异味,调料混在一个袋子里分不清。你会直接把所有东西倒进锅里煮吗?当然不会!你会先清洗蔬菜、切掉烂的部分、把调料分开、称好正确的用量。只有完成了这些准备工作,你才会开始烹饪。
数据预处理在机器学习中扮演的角色,就是做饭前的准备工作。数据就像原始食材——它天生就是脏的、不完整的、格式混乱的。如果你把脏数据直接喂给模型,模型会学到垃圾规律,输出垃圾预测。这就是著名的原则:Garbage in, garbage out(垃圾进,垃圾出)。
让我们看看真实世界的数据长什么样。假设你在医院工作,想建一个模型预测病人是否患有糖尿病。你收集了成千上万病人的数据:年龄、体重、血压、血糖等。但数据非常凌乱:
- 有些病人忘了报告体重——缺失值
- 两个护士不小心录入同一个病人两次——重复数据
- 一个病人被录成250岁——异常值
- 性别列里有"M"、"Male"、"m"、"F"、"Female"、"f"——格式不统一
- 有些体重用公斤、有些用磅——量纲不同
你的神经网络无法理解这些人类错误。它看到"250"岁会认为这是合法年龄,尝试从中学习。它看到"M"和"m"会认为是两个不同的性别。遇到缺失值就不知所措了。结果呢?一个表现比抛硬币还差的模型。
数据预处理是原始现实和数学模型之间的桥梁。它把混乱的人类数据转化为干净的数值矩阵,让模型能够理解。你可以把它想象成翻译:从现实世界混乱的语言翻译到数学精确的语言。
标准的预处理流程如下:
- 清洗(Cleaning):删除或修复坏数据——缺失值、重复值、异常值
- 标准化(Standardization):让所有特征具有相同的尺度——防止一个特征主导其他特征
- 编码(Encoding):将文本类别转换为数字——因为数学只认识数字
- 增强(Augmentation):创造合成数据,帮助模型学得更好
- 划分(Splitting):把数据分成训练/验证/测试集——让你能诚实地评估性能
再打个比方。想象你在教孩子认苹果。你给他们看苹果的图片。但有些图片是模糊的,有些其实是贴了红贴纸的橙子,有些小到看不到细节。孩子会搞混。你需要先清理图片,把它们调整到统一大小,最好从不同的角度展示。这就是预处理。
数据质量决定了模型的天花板。世界上最好的算法也无法从坏数据中做出好模型。反过来,即使简单的算法+高质量数据也能产生优秀的结果。这就是为什么数据科学家把60-80%的时间花在数据预处理上,而不是构建花哨的模型。
数据清洗:缺失值、重复值、异常值
数据清洗是预处理中第一步也是最重要的一步。就像做饭前要洗菜一样——你不会吃不洗的蔬菜,你的模型也不应该学脏数据。
1. 缺失值(Missing Values)
什么是缺失值?简单说就是数据表格中的空白格——数据应该在但实际不存在的地方。在Excel里看起来是空单元格。在数据库中可能是NULL、NaN(Not a Number,非数字)或单纯的空白。
为什么会出现缺失值?很多原因:
- 问卷调查中有人忘记填某个字段
- 传感器故障,没有记录温度读数
- 病人拒绝回答收入问题
- 系统间数据传输时丢失
- 数据库后来新增了列,旧记录没有值
为什么缺失值很重要?因为神经网络无法处理空白。它期望每个单元格都有数字。如果你留空,数学运算就会出问题。计算机会尝试和"空"做运算,然后崩溃或产生错误结果。
如何处理缺失值?有几种策略,各有优缺点:
策略1:删除整行
如果某行缺失太多,直接删除。最简单粗暴的方法。
例:1000条病人记录,50条没有血压数据。删除这50行,剩下950条干净数据。
优点:简单,不扭曲数据
缺点:丢失数据。如果30%的行都有缺失值,你就丢失了30%的数据。数据稀少时这是很大的浪费。
策略2:用均值填充
计算该列中所有非缺失值的平均值,用这个平均值填充空白。
例:血压列 [120, 130, NaN, 125, NaN, 140]
步骤1:计算非缺失值的均值:(120+130+125+140)/4 = 515/4 = 128.75
步骤2:用128.75填充NaN:[120, 130, 128.75, 125, 128.75, 140]
优点:保持整体均值不变,计算简单
缺点:减少了数据的方差(分散程度)。如果很多值都缺失了,所有人都得到同一个值,这让数据看起来比实际情况集中。
策略3:用中位数填充
把非缺失值排序,取中间那个值。
例:血压列 [120, 130, NaN, 125, NaN, 140]
排序非缺失值:[120, 125, 130, 140],中间两个是125和130,中位数=(125+130)/2=127.5
填充:[120, 130, 127.5, 125, 127.5, 140]
优点:比均值更抗异常值。如果某个病人血压是300(异常值),均值会被拉高,但中位数仍然合理。
策略4:用常数填充
用特殊数字如-1或0填充,或用"未知"这样的占位类别填充文本。
例:用-1填充。[120, 130, -1, 125, -1, 140]
优点:模型可以学到-1=缺失,区别对待
缺点:如果用0而有些真实值也是0,模型会混淆
2. 重复数据(Duplicate Rows)
重复数据是指完全相同的行出现了不止一次。可能的原因:
- 两个不同系统记录了同一笔交易
- 用户在表单上点击了两次"提交"
- 从多个来源合并数据时发生重叠
为什么重复数据很重要?因为它们让你的模型高估那些记录的重要性。如果你有1000个独立的病人,但有50个是重复的,模型以为那50个病人是100个。模型会两倍强度地学习他们的模式,这会导致偏差。
处理方法:删除重复行。代码:df.drop_duplicates()
3. 异常值(Outliers)
异常值是指同一个列中与其他值差异极大的数值。就像一群普通身高的人中站着一个3米高的巨人。
为什么会出现异常值?
- 数据录入错误:年龄误输入250而非25
- 测量错误:体重秤故障记录了999公斤
- 真实但罕见的事件:正常收入数据中的亿万富翁
IQR(四分位距)方法检测异常值:
例:数据 [10, 15, 20, 22, 25, 30, 35, 100]
步骤1:排序后已排好
步骤2:中位数Q2 = (22+25)/2 = 23.5
步骤3:Q1(下半部分中位数)= (15+20)/2 = 17.5
步骤4:Q3(上半部分中位数)= (30+35)/2 = 32.5
步骤5:IQR = 32.5 - 17.5 = 15
步骤6:下限 = 17.5 - 1.5×15 = -5
步骤7:上限 = 32.5 + 1.5×15 = 55
步骤8:100 > 55,所以100是异常值
Min-Max归一化
<p>想象你在比较汽车的速度和卡车的重量。汽车速度约60-120km/h,卡车重量约5000-50000kg。如果你直接把这些数字输入神经网络,重量数值比速度大1000倍!模型会认为重量比速度重要1000倍!但事实并非如此——两个特征同等重要。我们需要让它们可比较。</p> <p><b>Min-Max归一化</b>是一种把所有数值缩放到固定范围(通常[0,1])的技术。就像把不同货币换算成统一货币,让你能公平比较。</p> <p>公式:<b>x' = (x - min) / (max - min)</b></p> <p>参数详解:</p> <table border="1"> <tr><th>符号</th><th>名称</th><th>含义</th><th>典型值</th><th>太大/太小的影响</th></tr> <tr><td>x</td><td>原始值</td><td>数据中的原始数值</td><td>任意实数</td><td>无——这是输入数据</td></tr> <tr><td>min</td><td>最小值</td><td>该列数据中的最小值</td><td>由数据决定</td><td>无——由数据计算得出</td></tr> <tr><td>max</td><td>最大值</td><td>该列数据中的最大值</td><td>由数据决定</td><td>无——由数据计算得出</td></tr> <tr><td>x'</td><td>归一化值</td><td>缩放后的新值</td><td>0到1之间</td><td>无——这是输出结果</td></tr> </table> <p><b>为什么这个公式有效?</b>分子 (x-min) 告诉我们x离最小值有多远。分母 (max-min) 告诉我们所有数据的总范围。相除得到的是比例:"离底部有多远,占整个高度的百分比"。就像说"这个水瓶装了70%的水"——是相对量而非绝对量。</p> <p><b>数值示例:</b>学生身高 [150, 160, 170, 180, 190] cm</p> <p>步骤1:min=150, max=190, range=40</p> <p>步骤2:</p> <p>150 → (150-150)/40 = 0.0</p> <p>160 → (160-150)/40 = 0.25</p> <p>170 → (170-150)/40 = 0.5</p> <p>180 → (180-150)/40 = 0.75</p> <p>190 → (190-150)/40 = 1.0</p> <p>结果:[0.0, 0.25, 0.5, 0.75, 1.0]</p> <p><b>什么时候用Min-Max?</b>数据有明确边界时,比如图像像素值0-255、年龄0-150。</p> <p><b>什么时候不用?</b>数据有异常值时。如果有一个学生身高300cm,max=300,正常数据都被压缩到[0,0.67]。用Z-Score替代。</p>
Z-Score标准化
<p><b>Z-Score标准化</b>是深度学习中默认使用的预处理技术。不同于Min-Max把数据压到[0,1],Z-Score把数据变换为均值为0、标准差为1。就像把秤的零点调到平均值的位置。</p> <p>公式:<b>x' = (x - μ) / σ</b></p> <p>参数详解:</p> <table border="1"> <tr><th>符号</th><th>名称</th><th>含义</th><th>典型值</th><th>太大/太小的影响</th></tr> <tr><td>x</td><td>原始值</td><td>数据中的原始数值</td><td>任意实数</td><td>无——这是输入</td></tr> <tr><td>μ (mu)</td><td>均值</td><td>所有数据的平均值——数据的"重心"</td><td>由数据计算</td><td>μ大说明数据整体偏大</td></tr> <tr><td>σ (sigma)</td><td>标准差</td><td>数据分散程度的度量——数据的"宽度"</td><td>由数据计算</td><td>σ大说明数据分散,σ小说明集中</td></tr> <tr><td>x'</td><td>Z-Score值</td><td>偏离均值多少倍的标准差</td><td>通常-3到+3</td><td>x'>2或<-2表示该值比较罕见</td></tr> </table> <p><b>数值示例:</b>数据 [2, 4, 4, 4, 5, 5, 7, 9]</p> <p>μ = (2+4+4+4+5+5+7+9)/8 = 40/8 = 5.0</p> <p>方差 = [(2-5)²+(4-5)²+(4-5)²+(4-5)²+(5-5)²+(5-5)²+(7-5)²+(9-5)²]/8 = 32/8 = 4</p> <p>σ = √4 = 2.0</p> <p>标准化:2→(2-5)/2=-1.5, 4→-0.5, 4→-0.5, 4→-0.5, 5→0.0, 5→0.0, 7→1.0, 9→2.0</p> <p>结果:[-1.5, -0.5, -0.5, -0.5, 0.0, 0.0, 1.0, 2.0]</p> <p><b>为什么Z-Score是深度学习默认选择?</b>因为:更抗异常值;神经网络在输入中心化时学习更好;不同特征可以直接比较。</p>
类别编码:把文字变成数字
<p>神经网络只认识数字。它看不懂"男"、"女"、"红"、"蓝"、"北京"、"东京"这些文字。需要把所有类别转换成数字。<b>类别编码</b>就是这个转换过程。</p> <p><b>1. 标签编码(Label Encoding)</b></p> <p>最简单的编码方式:给每个类别分配一个唯一的整数。</p> <p>例:城市列 ["北京", "上海", "广州", "北京", "上海"]</p> <p>独特类别:北京、上海、广州 → 分别编码为0、1、2</p> <p>结果:[0, 1, 2, 0, 1]</p> <p>优点:简单,省内存,只占用一列</p> <p>缺点:模型可能认为数字有大小含义——以为上海(1)比北京(0)大、比广州(2)小。但城市没有自然顺序!</p> <p>什么时候用:类别本身有自然顺序时。例如["小","中","大"]→[0,1,2]是合理的。</p> <p><b>2. 独热编码(One-Hot Encoding)</b></p> <p>为每个类别创建一个新列。若某个样本属于某类别则该列=1,其他列=0。</p> <p>例:"北京","上海","广州","北京","上海"→创建3列:is_北京, is_上海, is_广州</p> <p>北京→[1,0,0],上海→[0,1,0],广州→[0,0,1]</p> <p>优点:没有虚假的顺序关系,每个类别平等对待</p> <p>缺点:类别多时列数膨胀——1000个城市就有1000列</p>
数据增强与数据集划分
数据增强:在现有数据基础上创造合成训练数据。就像复印笔记并加入些许变化。
图像增强:水平翻转、旋转5-15度、裁剪、调亮度。猫朝左变猫朝右,仍然是猫。
文本增强:同义词替换("今天天气很好"→"今日天气很棒")、回译(翻译到英语再翻译回中文)。
什么时候用增强?数据有限时。百万级数据时增强不太必要,数百条时增强能让有效训练集翻倍。
数据集划分:把数据分成三份——训练集(训练模型)、验证集(调参数)、测试集(最终评估)。
为什么需要三份?如果只有训练和测试,你会不断根据测试结果调模型,最终模型被"优化"到测试集上不真实。验证集充当"模拟考"。
典型比例:80/10/10 或 70/15/15。分层划分保证每个集合的类别比例一致。
例:1000条,700通过/300不通过。训练(80%)=560通过/240不通过,验证(10%)=70/30,测试(10%)=70/30。
练习题
Q1:Min-Max归一化
数据集 [10, 20, 30, 40, 50],应用Min-Max归一化。
Q2:Z-Score标准化
数据集 [4, 8, 6, 10, 12],计算均值和标准差后标准化。
Q3:异常值检测
数据集 [5, 7, 8, 9, 10, 12, 15, 100],用IQR方法检测。
Q4:独热编码
颜色列 ["红","蓝","绿","红","蓝"],做独热编码。
Q5:分层划分
500条记录,400条A类100条B类,80/10/10分层划分各多少?
查看答案
A1:min=10, max=50, range=40。10→0, 20→0.25, 30→0.5, 40→0.75, 50→1.0
A2:μ=8, 方差=8, σ≈2.828。4→-1.414, 8→0, 6→-0.707, 10→0.707, 12→1.414
A3:Q1=7.5, Q3=13.5, IQR=6, 上限=13.5+9=22.5, 100>22.5是异常值
A4:红[1,0,0], 蓝[0,1,0], 绿[0,0,1], 红[1,0,0], 蓝[0,1,0]
A5:训练:320A+80B=400。验证:40A+10B=50。测试:40A+10B=50