数据集:数据的特征#
一个数据集,本质上就是一批样本的集合。
很多数据集会把数据存成表格(网格),即 $m$ 行样本 $n$ 列特征,比如逗号分隔的 CSV 文件,或者直接来自电子表格与数据库表。表格对机器学习模型来说是一种相当直观的输入格式:你可以把表格的每一行想成一个样本,每一列想成一个候选特征或标签。当然,数据集也可能来自其他形式,比如日志文件和 protocol buffer。
不管格式如何,模型的能力上限都不会超过它所训练的那份数据。这一节就来看看数据有哪几个关键特征。
数据的类型#
一个数据集里可能装着各种各样的数据类型,包括但不限于:
数值型数据,课程中有一个 单独的小节专门讲它
类别型数据,同样在 单独的小节里展开
人类语言,从单个词语、单句话,一直到整篇文本
多媒体,比如图像、视频和音频文件
其他 ML 系统的输出
嵌入向量,课程后面会有专门的小节介绍
数据的数量#
作为一条粗略的经验法则:模型可训练的参数有多少,样本数就至少要比它多一个数量级(最好两个)。不过实际情况是,好的模型往往用的样本远不止这个数。
在特征很少的大数据集上训练出来的模型,通常要优于在特征很多的小数据集上训练出来的模型。Google 长期以来就深谙此道——用简单的模型去喂海量的数据,往往能取得很好的效果。
不同的机器学习项目,需要的样本量可能相差得极其悬殊。有些相对简单的问题,几十个样本或许就够了;而另一些问题,一万亿个样本都可能不够用。
不过,如果你是在一个现成的模型上做微调,而且这个模型此前已经用同一套结构的海量数据训练过,那么小数据集也可能训出好结果。
数据的质量与可靠性#
人人都更喜欢高质量的数据,但「质量」这个概念实在太模糊了,可以被定义出无数种版本。课程在这里采用了一个务实的定义:
高质量的数据集,能帮助模型达成它的目标。
低质量的数据集,会妨碍模型达成它的目标。
高质量的数据集通常也是可靠的。可靠性指的是你能在多大程度上信任这份数据。用可靠数据训练出来的模型,比用不可靠数据训练出来的模型更有可能给出有用的预测。
要衡量可靠性,你需要弄清楚三件事:
标签错误的普遍程度有多大?比如,如果你的数据是人工标注的,人工标注者犯错的比例有多高?
你的特征是否有噪声?也就是说,特征里的数值本身是否含有错误?要现实一点——你不可能把数据集里的噪声全部清除干净。有些噪声是正常的;比如,任何位置的 GPS 测量值都会随时间有微小的波动。
数据是否针对你的问题做了恰当的筛选?比如,你的数据集里该不该包含来自爬虫的搜索查询?如果你在做垃圾邮件检测系统,那答案很可能是「该包含」;但如果你想改进的是面向真人的搜索结果,那就「不该包含」。
以下几种情况,是数据不可靠的常见成因:
值缺失。比如,某个人忘了填写房屋的年龄。
样本重复。比如,服务器误把同一批日志上传了两次。
特征值有误。比如,有人多敲了一个数字,或者温度计被落在了太阳底下。
标签有误。比如,有人把一张橡树的照片错标成了枫树。
数据中某一段整体有问题。比如,某个特征一向都很可靠,唯独网络持续崩溃的那一天出了岔子。
我们建议用自动化手段来标记不可靠的数据。例如,依赖外部正式数据结构信息的单元测试,就能把落在定义范围之外的值标出来。
注意: 任何足够大、足够多样的数据集,几乎必然包含落在你的数据结构信息或单元测试区间之外的异常值。如何处理这些异常值,本身就是机器学习的一道重要课题。数值型数据小节里详细讲了该怎么对付数值型异常值。
完整样本与不完整样本#
理想情况下,每个样本都是完整的,也就是说每个样本的每个特征都有值。
遗憾的是,现实中的样本经常是不完整的,也就是至少有一个特征值缺失。
不要拿不完整的样本去训练模型。相反,应该用下面两种方式之一把它们修复或者剔除掉:
删除不完整的样本。
插补缺失值,也就是为那些缺失的值提供有依据的猜测,把不完整样本补成一个完整样本。
MLWM: 最简单的插值策略可以说最值、最大值、最小值等方法。
如果数据集里的完整样本已经足够训练出一个有用的模型,那就考虑删掉那些不完整样本。同理,如果只有一个特征缺失的数据量很大,而这一个特征大概也帮不上模型多少忙,那就考虑把这个特征从模型输入里去掉,看看去掉之后质量掉了多少;模型照样好用或者几乎一样好用,那就是个皆大欢喜的结果。反过来,如果你的完整样本不够训出一个有用的模型,那或许可以考虑插补缺失值。
删掉无用或者冗余的样本当然没问题,删掉重要样本则是糟糕的做法。 不过不幸的是,要区分「无用样本」和「有用样本」并不容易。如果你实在拿不定主意该删还是该插,不妨构建两份数据集:一份由删除不完整样本得到,另一份由插补得到。然后比较一下,看哪一份能训出更好的模型。
精明的算法确实能插补出相当不错的缺失值;但插补出来的值,几乎总是比不上真实值。所以,一份好数据集应该让模型分得清哪些值是插补来的、哪些是真实的。一种做法是在数据集里额外加一个布尔列,用它标明某个特征的值是否为插补而来。
比如,对于一个叫 temperature 的特征,你可以再加一个类似 temperature_is_imputed 的布尔特征。这样在训练时,模型多半会逐渐学会:对 temperature 这个特征,含有插补值的样本可信度要低于含有真实值的样本。
插补是生成有依据的数据,而不是编造随机或有欺骗性的数据。要当心:好的插补能改善模型,坏的插补则可能伤害模型。
一种常见的插补算法,是用均值或中位数作为插补值。因此,当你用 Z-score 来表示一个数值特征时,插补出来的值通常就是 0(因为 0 一般就是平均 Z-score)。
练习:检验你的理解#
像下面这个练习里按
Timestamp排好序的数据集,有时确实能让插补变简单。但拿一个排好序的数据集去训练模型是个坏主意。所以,插补完之后,记得把训练集中样本的顺序打乱。
下面是某个数据集的两列数据,已按 Timestamp 排好序:
| Timestamp | Temperature |
|---|---|
| June 8, 2023 09:00 | 12 |
| June 8, 2023 10:00 | 18 |
| June 8, 2023 11:00 | missing |
| June 8, 2023 12:00 | 24 |
| June 8, 2023 13:00 | 38 |
下面哪个取值,是那个缺失的 Temperature 比较合理的插补值?
23
31
51
点击查看答案
23 比较合理。 23 是相邻几个值(12、18、24 和 38)的均值。不过我们只看到了数据集的一小部分,所以也有可能 23 在别的日子对应 11:00 时会是个异常值。
31 不太可能。 从我们能看到的这部分数据集来看,31 对于 11:00 的温度来说高得多了。但除非把插补建立在大得多的样本量之上,否则我们无法确定。
51 非常不可能。 51 比这里显示的任何一个取值都高得多(因此也比均值高得多)。
关键术语:
数据集
嵌入向量
样本
特征
模型
值插补
Z-score 标准化