处理数据
相比于构建模型,机器学习从业者需要花更多的时间来评估、清理和转换数据。
数值数据表示整数或浮点值 其行为方式与数字类似的函数。也就是说,它们是可累加的、可数的、有序的, 依此类推。
尽管有些数据是是以数字方式存在,但却并不是数值数据。
邮政编码 40004(位于肯塔基州纳尔逊县)不能视为华盛顿特区邮政编码 20002 数量的两倍。这些数字代表类别(具体而言是地理区域),并被视为 分类数据。
手机号码也类似,这些数据表现为数字形式,但在数据库中,应以字符串类型存储;在机器学习中,它们被视为分类数据。
处理数值数据 Numerical Data
模型如何利用数据
假设某个数据集提供了五个列,但其中只有两个列(b 和 d)是模型中的特征。在处理第 3 行中的示例时,模型是否会像下面这样简单地抓取突出显示的两个单元格(3b 和 3d)的内容?
这并不是模型获取示例的确切方式。
事实上,该模型实际上会提取一个浮点值数组,称为特征向量(Feature Vector)
。一个样本的浮点值构成一个特征向量。
更接近真实情况,但不切合实际。
不过,特征向量很少使用数据集的原始值。相反,通常必须将数据集的值处理成模型可以更好地学习的表示形式。因此,更现实的特征向量可能如下所示:
更逼真的特征向量。
使用数据集中的实际值进行训练,而不是使用经过更改的值,模型的预测结果会更好吗?令人惊讶的是,答案是否定的。
必须确定将原始数据集值表示为特征向量中可训练值的最佳方法,此过程称为特征工程(Feature Engineering)
。
最常见的特征工程技术包括:
归一化(Normalizaiton)
:将数值转换为标准范围。分桶(Binning/Bucketing)
:将数值转换为范围分桶。
特征向量中的每个值都必须是浮点值。不过,许多特征本质上是字符串或其他非数字值。因此,特征工程的很大一部分是将非数值表示为数值。
认识数值数据
可视化数据
图形可以帮助你发现隐藏在数据中的异常或模式。因此,在深入分析之前,应通过图形方式查看数据,比如散点图或直方图。不要只在数据管道的起点查看图形,而应在整个数据转换过程中持续观察。可视化有助于你不断验证自己的假设。
推荐使用 pandas 进行可视化操作:
注意,某些可视化工具针对特定的数据格式进行了优化。例如,一个用于分析 protocol buffers 的可视化工具可能不适用于 CSV 数据。
统计评估数据
除了可视化分析,建议通过数学方式评估潜在的特征与标签,获取一些基本统计量,例如:
- 均值、中位数、标准差
- 四分位分布点的值:第 0、25、50、75、100 百分位数(第 0 百分位为该列最小值,100 百分位为最大值,50 百分位即中位数)
查找异常值
异常值指的是在某个特征或标签中明显偏离其他数据点的值。异常值常常会影响模型训练,因此识别异常值非常重要。
当第 0 和第 25 百分位之间的差值与第 75 和第 100 百分位之间的差值相差显著时,说明数据集中很可能存在异常值。
注意:不要过度依赖基础统计量。有些异常可能隐藏在看似平衡的数据中。
异常值一般可以分为以下几类:
- 错误导致的异常值:例如,实验人员误多输了一个零,或数据采集设备发生了故障。通常应删除这类包含错误异常值的样本。
- 合法但偏离的异常值:如果这些异常值不是错误,而你的模型在未来需要对这类情况做出合理预测——
- 如果答案是“需要”,那么应将这些异常值保留在训练集中。有时候,特征中的异常也对应着标签中的异常,保留它们反而可能帮助模型提升预测效果。当然,仍需注意:极端异常值可能对模型产生负面影响。
- 如果答案是“不需要”,那么可以考虑删除这些异常值,或者采用更深入的特征工程方法处理它们,比如裁剪(Clipping)等技术。
处理数据
归一化
在通过统计分析和可视化手段检查数据之后,应对数据进行适当转换,以帮助模型更有效地训练。归一化的目标是将各个特征转换到相似的数值范围。
例如,考虑以下两个特征:
- 特征 X 的取值范围是 154 到 24,917,482;
- 特征 Y 的取值范围是 5 到 22。
这两个特征的数值跨度差异极大。归一化可以将 X 和 Y 映射到一个相似的范围,例如 0 到 1。
归一化的好处包括:
- 加快模型训练收敛速度:当特征的取值范围差异较大时,梯度下降过程可能会“震荡”,从而降低收敛速度。不过,一些高级优化器(如 Adagrad 和 Adam)通过动态调整学习率,在一定程度上缓解了这个问题。
- 提升模型的预测能力:如果特征的数值尺度差异较大,训练出的模型可能对某些特征的关注不够,进而影响预测效果。
- 避免“NaN 陷阱”:当某些特征的取值非常大时,模型中的某些值可能会超出浮点数表示范围,从而被系统标记为 NaN(Not a Number)。一旦出现 NaN,模型中的其他数值也可能逐步被污染,最终导致整个模型失效。
- 帮助模型学习更合理的特征权重:如果未对特征进行缩放,模型往往会对范围更大的特征赋予更大的权重,而忽视那些数值范围较小但同样重要的特征。
因此,建议对数值范围相差较大的数值特征(如年龄与收入)进行归一化。即便是单个取值范围很大的特征(例如城市人口),也建议归一化处理。
⚠️ 注意:如果在训练时对某个特征进行了归一化,那么在进行预测时,也必须以相同方式对该特征进行归一化。
举个例子,考虑以下两个特征:
- 特征 A 的最小值为 -0.5,最大值为 +0.5;
- 特征 B 的最小值为 -5.0,最大值为 +5.0。
这两个特征的跨度都不算大,但特征 B 的范围是特征 A 的 10 倍:
在训练开始阶段,模型会默认认为特征 B 的“重要性”是特征 A 的 10 倍,这会导致训练过程比预期慢,最终模型的表现可能也会欠佳,尽管在这种情况下不归一化造成的损失相对较小,但依然建议将特征 A 和 B 统一归一化到相同的范围,例如 -1.0 到 +1.0。
本节介绍三种常见的归一化方法:
- 线性缩放(Linear Scaling)
- Z-score 标准化(Z-score Scaling)
- 对数缩放(Log Scaling)
- 此外还介绍了“裁剪(Clipping)”技术。虽然裁剪不是严格意义上的归一化方法,但它能将异常数值限制在一定范围内,从而帮助训练出更稳定有效的模型。
线性缩放(Linear Scaling)归一化
线性缩放(通常简称为缩放)是指将浮点值从其自然范围转换为标准范围(通常为 0 到 1 或 -1 到 +1)。
线性缩放标准化在以下数据集中适用::
- 数据的下限和上限随时间的推移变化不大。
- 特征中包含的离群值很少或没有,并且这些离群值不极端。
- 特征在其范围内大致均匀分布。 也就是说,直方图会显示大多数值大致均等的条形。
假设人 age 是特征。线性缩放对 age 来说是一种很好的归一化方法,因为:
- 大致下限和上限为 0 到 100。
- age 中极值数据的百分比相对较小。只有大约 0.3% 的人口年龄超过 100 周岁。
- 虽然某些年龄段的代表性略高于其他年龄段,但大型数据集应包含所有年龄段的足够样本。
Z-Score 归一化
Z-score 表示一个数值距离平均值的标准差数量。例如,一个比平均值高出 2 个标准差的数值,其 Z-score 为 +2.0;一个比平均值低 1.5 个标准差的数值,其 Z-score 为 –1.5。
Z-Score 标准化在以下数据集中适用:
- 数据呈正态分布(或近似正态分布)
- 没有极端离群值
将特征使用 Z-score 标准化,意味着用该特征的 Z-score 值来表示它在特征向量中的值。例如,下图展示了两个直方图:
两个直方图显示了完全相同的分布。第一个直方图为原始数据,均值为 200,标准差为 30;第二个直方图是 Z-score 转换后的版本,均值为 0,标准差为 1。
即使是一些近似正态分布的数据,Z-score 标准化也是一种不错的选择。
近似正态分布下,原始数据(左)与 Z-score 标准化数据(右)对比。
对数缩放(Log Scaling)标准化
对数缩放是指对原始数值取对数。在理论上,可以使用任何底数;但在实际中,通常使用自然对数(ln)。
对数缩放标准化在以下数据集中适用:
- 数据符合幂律分布(power law distribution)。
简单来说,幂律分布具有以下特征:
- X 值较小时,Y 值非常大;
- 随着 X 值增大,Y 值迅速下降;
- 因此,X 值很大时,Y 值趋于很小。
一个典型的例子是电影评分数量。如下图所示:
- 少数电影拥有大量用户评分(X 小、Y 大);
- 但大多数电影只有极少的评分(X 大、Y 小)。
对数缩放会改变分布形态,使其更适合模型训练,从而提高预测效果。
原始分布 vs 对数变换后的分布:原始图(左)呈现“头部密集、长尾稀疏”的结构;对数图(右)分布更均匀。
另一个例子是图书销量,也符合幂律分布:
- 大多数出版书籍销量极低,可能只有一两百本;
- 少数图书销量适中,达到几千本;
- 极少数畅销书能卖出超过一百万本。
假设正在训练一个线性模型,用来预测“书籍封面与销量之间的关系”。如果你直接用原始销量数据,模型将被迫找出某些封面让图书销量从 100 本暴涨到 1,000,000 本的“1 万倍”差异,这几乎不现实。
但如果对销量数据进行对数变换,情况会变得更合理:
ln(100) ≈ 4.6;ln(1,000,000) ≈ 13.8
这样,最畅销书与最不畅销书的对数差距仅为约 3 倍,这在人类直觉上更合理(一本畅销书的封面可能在某种意义上确实比冷门书吸引力大几倍)。
裁剪(Clipping)
裁剪是一种减少极端异常值影响的技术。简单来说,裁剪会将异常值“限制”在一个指定的最大值之内。
这听起来也许有点“粗暴”,但实践中它经常非常有效。
举例来说,假设有一个名为 roomsPerPerson 的特征,表示每位住户平均拥有的房间数(总房间数 / 居住人数)。下图显示:
超过 99% 的取值符合正态分布,均值约为 1.8,标准差为 0.7;
但也存在一些极端异常值,例如某些数据点达到 每人 17 个房间。
该如何减少这些极端值的影响呢?由于该数据分布既非均匀分布、也非正态分布、也非幂律分布,考虑采取一种简单的做法:
把 roomsPerPerson 的最大值裁剪为 4.0(即所有 >4.0 的值都设置为 4.0)。
注意:裁剪并不意味着模型忽略这些值,而是将所有超过 4.0 的值统一设置为 4.0,这就是为什么图中在 4.0 出现了一个“人为堆积的小峰”。
即便存在这个不自然的峰值,整体分布变得更可控,也更有利于模型训练。
但也要注意,有些异常值可能是真正重要的信息。
因此,裁剪要谨慎使用,避免误伤有价值的数据。
数据分箱 Binning/Bucketing
分箱是一种特征工程技术,用于将连续的数值特征划分为不同的区间(即 bin 或 bucket)。在许多情况下,分箱操作会将数值型数据转化为类别型数据。
例如,考虑一个名为 X 的特征,其最小值为 15,最大值为 425。你可以将其划分为以下 5 个 bin:
- Bin 1:15 到 34
- Bin 2:35 到 117
- Bin 3:118 到 279
- Bin 4:280 到 392
- Bin 5:393 到 425
在这个例子中,X 落在 15 到 34 区间的所有值都归入 Bin 1。虽然 X 在数据集中只是一列,但分箱后,模型会把它当作 5 个独立特征来处理(即 5 个特征向量),因此会分别为每个 bin 学习权重。
特征向量表示 这五个分箱如下:
何时使用分箱?
当以下任一条件成立时,分箱是比缩放或裁剪更合适的选择:
- 该特征与标签之间整体上没有明显的线性关系;
- 该特征的数值呈集中簇状分布(clustering)。
分箱有时看起来不直观——例如模型会将数值 37 和 115 等同看待(如果它们落入同一个 bin)。但当特征在分布上**比起线性更倾向于“分组”或“成团”**时,分箱反而能更好地表现数据结构。
分箱示例:温度与购物者人数
假设你正在训练一个模型,预测每天根据户外温度来估算购物者人数。下图是温度与购物人数之间的散点图:
一个由 45 个点构成的散点图。点自然分成了 3 个聚集区域。
在线性回归中,模型对每个特征只学习一个权重。如果温度作为一个连续特征,那么温度 35.0 会在预测中产生的影响,是温度 7.0 的 五倍或五分之一。但从图中来看,温度与购物人数之间并没有呈现线性关系。
相反,图中的点明显聚集在以下三个温度区间:
- Bin 1:4–11°C
- Bin 2:12–26°C
- Bin 3:27–36°C
分位数分箱(Quantile Bucketing)
分位数分箱是一种将数据划分为若干区间(bucket)的方法,其目标是让每个分箱中的样本数量尽可能相等。这种方法在很大程度上可以弱化异常值的影响。
为了说明分位数分箱要解决的问题,来看下图中的一个示例:
在该例中,所有分箱的区间跨度是固定的,每个 bucket 覆盖 正好 10,000 美元的价格范围。注意,0 到 10,000 美元的分箱中有几十个样本,而 50,000 到 60,000 美元的分箱中却只有 5 个样本。因此,模型在训练时能从前者学到足够的信息,而后者则样本太少,难以学出有效规律。
相比之下,下图采用的是分位数分箱方法,将汽车价格划分成若干个 bin,每个 bin 中的样本数量大致相同。可以看到:
- 有些分箱对应的价格范围很窄;
- 有些分箱则跨越了非常宽的价格区间。
这正是分位数分箱的核心优势:根据样本分布动态调整分箱宽度,从而让模型在每个区间都能获得足够训练样本,避免因数据分布不均造成模型偏倚或过拟合。
对于许多数据分布,等间距分箱(equal interval bucketing) 是有效的。但对于偏态分布(skewed data),更推荐使用分位数分箱(quantile bucketing)。
等间距分箱会为长尾部分分配较多的信息空间,而将数据集中分布的“主干部分(torso)”压缩到少数几个分箱中。
相反,分位数分箱则为主干部分分配更多的信息空间,而将长尾部分压缩到一个分箱中。
擦除数据
苹果树结出的果实中,有些甜美可口,也有些虫蛀腐烂。但在高端超市里,我们看到的苹果几乎都是 100% 完美的果实。在果园与超市之间,有人花了大量时间将坏苹果挑出,或者在尚可挽救的果子上打蜡处理。
作为一名机器学习工程师,你也会花大量时间清理数据:剔除坏样本、清洗可用样本。哪怕是少量“坏苹果”,也可能毁掉整个训练数据集。
数据集中许多样本之所以不可靠,通常是由于以下某些问题所致:
此外,当当标签由多人标注时,应采用统计方法评估各标注者是否一致。也许某位标注者比其他人更严格,或者他采用了不同的评分标准?
一旦发现有问题的样本(无论是特征错误还是标签错误),通常的处理方法包括:
- 从数据集中删除它们;
- 对其值进行填补(插补)。
多项式转换(Polynomial transforms)
来看下面的数据点分布图,其中粉色圆点代表一个类别(例如某种树),绿色三角形代表另一个类别:
我们无法绘制一条能清晰区分这两个类的直线,但可以绘制一条能做到这一点的曲线:
使用 y = x^2 分隔类。
处理分类数据
分类数据具有一组明确的取值集合。例如:
- 国家公园中各种动物的物种名称
- 某个城市中的街道名称
- 已经分箱的数值(参见《数值数据处理》模块)
数字也可能是分类数据
真正的数值型数据是可以进行有意义的运算的,尤其是乘法。比如,在预测房价的模型中,如果使用房屋面积作为一个特征,那么可以合理地认为,在其他条件相同的情况下,面积为 200 平方米的房子,大致应当是面积为 100 平方米的房子的两倍价值。
但很多时候,如果某个特征是整数值,并不意味着它适合用作数值特征。比如,邮政编码,虽然它通常用整数表示,但它的数值并没有大小意义。如果你将其当作数值型特征输入模型,那么你就等于告诉模型,邮编 20004 比邮编 10002“大一倍”或“影响大一倍”,这显然是错误的。
相反,应当将邮政编码视为分类数据,这样模型就能为每一个邮编单独学习一个权重。
编码(Encoding)
编码是指将分类数据或其他非数值型数据转换为数值向量,从而供模型训练使用。因为机器学习模型只能处理浮点数,无法直接理解像 “dog” 或 “maple” 这样的字符串。
词汇表
“维度(dimension)” 是 特征向量中元素数量的同义词。当一个分类特征的可能取值数量较少时,称其为是低维的(low-dimensional)
。可以将低维特征其编码为一个词表(vocabulary)。使用词表编码时,模型会将每个可能的分类值视为一个单独的特征,在训练过程中为每个类别学习一个独立的权重。
假设你正在构建一个模型,用来预测汽车价格,其中包含一个名为 car_color
的分类特征。由于厂商提供的车身颜色种类有限,car_color 是一个低维分类特征。它的词表可能包括:
["Red", "Orange", "Yellow", "Green", "Blue", "Black", "White", "Purple"]
独热编码
索引编号
机器学习模型只能处理浮点数,不能直接使用字符串(如 “Red” 或 “Green”)。因此,必须先将每个字符串映射为唯一的索引编号,如:
Red → 0
Orange → 1
Yellow → 2
...
Purple → 7
但仅用索引编号是不够的。如果直接将这些整数输入模型,模型会错误地认为这些值之间有连续的数值关系。例如,它可能会以为 “Purple”(7)比 “Orange”(1)大七倍,从而得出错误的结论。
为了解决这个问题,可以将索引编号转化为 one-hot 向量。在 one-hot 编码中:
- 每个类别由一个长度为 N 的向量表示(N 是类别总数);
- 向量中只有一个元素为 1,其余均为 0。
例如,假设 car_color 有 8 个类别,那么:
Blue → [0, 0, 1, 0, 0, 0, 0, 0]
最终,作为特征向量传入模型的是 one-hot 向量,而非原始字符串或编号。模型会为向量中每个元素学习一个独立的权重。
稀疏表示(Sparse Representation)
如果一个特征的大多数值都是 0,我们称它为稀疏特征(sparse feature)
。很多分类特征(如 car_color)都属于稀疏特征。
稀疏表示不存储整个 one-hot 向量,而是只存储其中值为 1.0 的位置。
比如:
[0, 0, 1, 0, 0, 0, 0, 0] → 稀疏表示为:2
这比存储完整向量节省了大量内存。但注意,模型训练时仍需使用完整的 one-hot 向量,而非稀疏表示。
分类数据中的离群值(Outliers)
像数值特征一样,分类特征中也可能存在异常值。例如,car_color 中除了常见颜色外,可能还有罕见颜色如 “Mauve” 或 “Avocado”。与其为这些稀有颜色分配独立类别,不如将它们统一归入一个**“词表外类别(OOV, out-of-vocabulary)”**。
也就是说,所有异常颜色都放入一个统一的分箱中。系统只需为这个“异常桶”学习一个权重即可。
类别数较多时的处理方式
当分类特征的类别数量非常多时,one-hot 编码就不再适用了。此时,更推荐使用嵌入(Embeddings)。嵌入的优势包括:
- 显著减少特征维度;
- 通常训练速度更快;
- 构建出的模型推理速度更快(即更低延迟)。
还有一种不太常见的降维方法是哈希编码(hashing trick),也能减少维度,但使用上需谨慎。
特征交叉(Feature crosses)
特征交叉是通过对两个或多个分类特征或分桶特征进行笛卡尔积(Cartesian product)
运算而生成的。与多项式变换(polynomial transforms)
类似,特征交叉可以让线性模型处理非线性关系,并且能够编码特征之间的交互作用。
—特征交叉后的独热编码:
- 穷举所有交叉的特征,数量即为独热编码的维数
例如,考虑一个关于树叶的数据集,其中包含以下两个分类特征:
- edges(叶缘):可能取值为 smooth(平滑)、toothed(锯齿状)、lobed(裂片状)
- arrangement(叶序):可能取值为 opposite(对生)、alternate(互生)
这两个特征的特征交叉(即笛卡尔积)结果如下,维数为 6
{Smooth_Opposite, Smooth_Alternate, Toothed_Opposite, Toothed_Alternate, Lobed_Opposite, Lobed_Alternate}
假设上述顺序就是 one-hot 编码中各特征的列顺序,则一个具有 smooth 叶缘 且 opposite 叶序 的叶子,可以用以下 one-hot 向量表示:
{(1, 0, 0), (1, 0)}
每一个交叉项的值,都是其对应基础特征值的乘积。例如:
Smooth_Opposite = edges[0] * arrangement[0]Smooth_Alternate = edges[0] * arrangement[1]Toothed_Opposite = edges[1] * arrangement[0]Toothed_Alternate = edges[1] * arrangement[1]Lobed_Opposite = edges[2] * arrangement[0]Lobed_Alternate = edges[2] * arrangement[1]
则 smooth_opposite 应为 1,则具有 smooth 叶缘 且 opposite 叶序 的叶子的独热编码为:
{(1, 0, 0, 0, 0, 0)}
⚠️ 注意事项:
对两个稀疏特征做交叉,会生成一个更稀疏的新特征。
例如:
若特征 A 是一个包含 100 个可能值的稀疏特征,特征 B 是一个包含 200 个可能值的稀疏特征,
那么它们的特征交叉将产生一个包含 20,000 个可能取值的稀疏特征。
数据集
数据集(Dataset)是由多个样本(example)组成的集合。
许多数据集以表格(网格)的形式存储数据,例如 CSV(逗号分隔值)
、电子表格或数据库表格。表格格式对于机器学习模型来说是一种直观的输入方式。你可以将表格中的每一行想象为一个样本,每一列则是一个潜在的特征或标签。当然,数据集也可能来源于其他格式,比如日志文件或 protocol buffer 等。
无论数据格式如何,机器学习模型的好坏最终取决于它所训练的数据质量。
一个数据集可能包含多种数据类型,包括但不限于:
- 数值数据(numerical data):前述提及
- 类别数据(categorical data):前述提及
- 人类语言:包括单词、句子,甚至完整的文本文档
- 多媒体:如图片、视频、音频文件
- 其他机器学习系统的输出
- 嵌入向量(embedding vectors):后续将提及
数据的数量越多越好
粗略经验法则:训练样本的数量应至少是模型中可训练参数数量的 10 倍甚至 100 倍。但实际上,优秀的模型往往训练于远超这个比例的大数据集上。
例如,你设计了一个神经网络模型,其中包含了 10,000 个可训练参数(即 10,000 个权重和偏置),那么至少应该有:
- 10 倍的训练样本:即 100,000 个样本
- 更理想的情况是 100 倍:即 1,000,000 个样本
在特征较少的大型数据集上训练出的模型,通常优于在特征较多的小数据集上训练的模型。Google 长期以来在这一点上取得了良好成效:用简单模型训练大数据集。
巨量的数据可以防止过拟合(overfitting)
和提升泛化能力(generalization)
。
- 如果样本太少,而参数太多,模型虽然有“记住”训练数据的能力,却无法学到有普遍规律性的模式,换句话说,它在训练集上可能表现很好,但在新数据(测试集)上表现很差。
不完整的样本
在理想情况下,每个样本都是完整的;也就是说,每个示例都包含每个特征的值。
遗憾的是,现实世界的样本通常不完整,也就是说,至少缺少一个特征值。
请勿使用不完整的样本训练模型。请改为执行以下操作之一:
- 删除不完整的样本。
- 如果数据集包含足够的完整样本来训练实用的模型,请考虑删除不完整的样本。
- 如果只有一个特征缺少大量数据,并且该特征可能对模型帮助不大,那么不妨考虑从模型输入中删除该特征,看看移除该特征会导致质量下降多少。如果模型在没有该特征的情况下也能正常运行或几乎能正常运行,那就太棒了。
- 猜测并填补缺失值:通过为缺失值提供合理的猜测,将不完整的样本转换为完整的样本。
- 反之,如果没有足够的完整样本来训练有用的模型,则可以考虑对缺失值进行插值。
- 巧妙的算法可以推断出一些相当不错的缺失值;不过,推断出的值很少能与实际值一样好。因此,良好的数据集可告知模型哪些值是经过插值的,哪些值是实际值。实现此目的的一种方法是向数据集中添加一个额外的布尔值列,用于指示是否对特定地图项的值进行了插值。例如,如果有一个名为 temperature 的特征,您可以添加一个名为 temperature_is_imputed 的额外布尔特征。然后,在训练过程中,模型可能会逐渐学习,对包含特征 temperature 的插值值的示例的信任度低于对包含实际(非插值)值的示例的信任度。
处理不平衡数据集
处理数据不平衡的一种方法是:对多数类进行下采样(downsampling)
,并对下采样后的样本进行加权(upweighting)
:
- 下采样:在训练过程中,只从多数类中取一个较小的子集参与训练。
- 加权:给被下采样的样本增加一个样本权重,该权重值等于下采样的比例因子。
第一步:对多数类进行下采样
以图所示的病毒数据集为例,其中每 200 个负样本才有 1 个正样本。
我们以 10 倍的因子对负样本下采样之后,比例改善为 1:20(即 5%),虽然仍有些不平衡,但相比原始 0.5% 的极端比例,已有明显改善。
第二步:对下采样样本进行加权
下采样之后,我们为这些被选中的负样本添加样本权重。
若下采样因子是 10,那么每个被选中的负样本应被赋予权重 10。(这看起来可能有些反直觉,但稍后会解释原因。)
下图展示了两步流程:
- 随机抽取一部分多数类样本(下采样);
- 给这部分样本添加更高权重(加权)。
📌 关于“权重”的说明
- 此处的“权重”并非模型参数(如 w₁、w₂),而是样本权重,用来表示某个训练样本在计算损失时的重要程度。
- 样本权重 = 10 表示该样本在训练中被认为比权重为 1 的样本“重要 10 倍”。
- 加权的目的:这样做能减少模型的预测偏差。下采样 + 加权的组合有助于让模型的预测值整体上更接近数据集中标签的真实分布。
⚖️ 比例重平衡(Rebalance Ratios)
那么应该下采样多少?加多少权重?
这种下采样 + 加权的方法,尤其适用于大规模、极度不平衡的数据集,如疾病预测、欺诈检测等场景。
拆分原始数据集
推荐的做法是将数据集划分为三部分:
- 训练集(training set):用于训练模型。
- 测试集(test set):用于评估已训练好的模型。
- 验证集(validation set):在训练过程中,用于对模型进行初步评估与调整。
一个模型开发的工作流程,包含以下步骤:
- 在训练集上训练模型;
- 在验证集上评估模型性能;
- 根据验证集上的表现调整模型(如学习率、特征选择,甚至重设计模型结构);
- 重复步骤 1~3,直到选择出在验证集上表现最好的模型;
- 最后,用测试集确认模型效果。
📌 注意:训练集上的任何特征变换(如归一化、缩放等),必须同样应用于验证集、测试集,以及未来真实使用的数据中。
评价模型
拟合 Fitting 相关问题
- 过拟合是指在训练集上可以做出出色的预测,但在新数据上做出的预测却不准确。
- 欠拟合是指模型对训练数据的学习不足,既无法在训练集上取得良好效果,也无法在测试集上取得好效果。
泛化与过拟合相反。也就是说,泛化能力强的模型可以对新数据做出良好的预测。您的目标是创建一个能够很好地泛化到新数据的模型。
过拟合产生的原因主要有三个:
- 模型记住了数据中的噪音。意味着模型受到噪音的干扰,导致拟合的函数形状与实际总体的数据分布相差甚远。这里的噪音可以是标记错误的样本,也可以是少量明显偏离总体分布的样本(异常点)。通过清洗样本或异常值处理可以帮助缓解这个问题。
- 训练数据过少 导致训练的数据集根本无法代表整体的数据情况,做什么也是徒劳的。需要想方设法增加数据,包括人工合成假样本。
- 模型复杂度过高 导致模型对训练数据学习过度,记住了过于细节的特征,如下图(来源Coursera的机器学习课程)。
检测过拟合
以下曲线可帮助检测过拟合:
- 损失曲线
- 泛化曲线:显示两个或更多损失曲线的图表称为泛化曲线
- 初始阶段(左侧):两条曲线都在下降,说明模型在训练集和验证集上都在变好。此时模型尚未过拟合,泛化能力良好。
- 中后期阶段:蓝线(训练损失)继续下降,说明模型在训练集上表现越来越好;红线(验证损失)却开始上升,说明模型在验证集上表现变差。
✅ 这说明:模型开始记住训练数据中的细节甚至噪声,失去了对新数据的泛化能力,也就是发生了过拟合。
相比之下,适合度较高的模型的泛化曲线会显示两个形状相似的损失曲线。
过拟合是什么时候发生的
- 在训练不足时模型的拟合能力不够强,训练数据的扰动不足以使模型产生显著变化,此时偏差主导了泛化误差。
- 随着训练程度的加深,模型的拟合能力逐渐增强,训练数据发生的扰动逐渐被模型学习到,方差逐渐主导了泛化误差。
- 在训练充分后模型的拟合能力非常强,训练数据发生的轻微扰动都会导致模型发生显著变化。
- 若训练数据自身的、非全局的特性被模型学到了,则将发生过拟合。
通过误差分析拟合问题
偏差和方差 Bias-Variance
- 偏差:衡量了模型期望输出与真实值之间的差别,刻画了模型本身的拟合能力。
- 方差:度量了训练集的变动所导致的学习性能的变化,刻画了模型输出结果由于训练集的不同造成的波动。
偏差、方差与模型容量有关。用 MSE 衡量泛化误差时,增加容量会增加方差、降低偏差。
- 偏差降低,是因为随着容量的增大,模型的拟合能力越强:对给定的训练数据,它拟合的越准确。
- 方差增加,是因为随着容量的增大,模型的随机性越强:对不同的训练集,它学得的模型可能差距较大。
一般来说,偏差和方差是由冲突的,这称作偏差-方差窘境 bias-variance dilemma
。
从误差到拟合
通过训练误差和测试误差 --> 分析模型是否存在高方差、高偏差 --> 偏差-方差可以反映模型的过拟合与欠拟合。
- 高偏差对应于模型的欠拟合:模型过于简单,以至于未能很好的学习训练集,从而使得训练误差过高。例如,用 linear regression 去拟合非线性的数据集。此时模型预测的方差较小,表示预测较稳定。但是模型预测的偏差会较大,表示预测不准确。
- 高方差对应于模型的过拟合:模型过于复杂,以至于将训练集的细节都学到,将训练集的一些细节当做普遍的规律,从而使得测试集误差与训练集误差相距甚远。例如,不做任何剪枝的决策树,可以在任何训练集上做到极高的准确率。此时模型预测的偏差较小,表示预测较准确。但是模型预测的方差较大,表示预测较不稳定。
通过训练误差和测试误差来分析模型是否存在高方差、高偏差。
- 如果训练误差较高:说明模型的方差较大,模型出现了欠拟合。
- 如果训练误差较低,而测试误差较高:说明模型的偏差较大,出现了过拟合。
- 如果训练误差较低,测试误差也较低:说明模型的方差和偏差都适中,是一个比较理想的模型。
- 如果训练误差较高,且测试误差更高:说明模型的方差和偏差都较大。
- 上述分析的前提是:训练集、测试集的数据来自于同一个分布,且噪音较小。
缓解拟合问题
模型复杂性
❗复杂模型在训练集中的表现通常优于简单模型。不过,简单的模型在测试集上的表现通常优于复杂的模型。
L2 正则化 Regularization
机器学习模型必须同时满足两个相互冲突的目标:
- 能很好地拟合数据。
- 尽可能简单地拟合数据。
为了让模型保持简单,一种方法是惩罚复杂的模型;也就是说,在训练过程中强制模型变得更简单。对复杂模型进行惩罚是一种正则化。
L2 正则化是一种常用的正则化指标,其使用以下公式:
标注(Annotation)
标注就是给数据打标签的过程。在机器学习中,标注数据是为了让模型能够学习如何将输入数据映射到正确的输出。标注的过程通常包括以下几个步骤:
- 选择数据:选择需要标注的数据,例如图片、文本或视频。
- 添加标签:为每个数据样本添加标签。例如,我们有一组图片,我们会给每张图片加上标签,标明这张图片是“狗”还是“猫”。
- 检查和验证:确保标注的准确性,以便模型可以学习到正确的信息。