基于实例 vs 基于模型学习
另一种分类机器学习的方法是判断它们是如何进行归纳推广的。大多机器学习任务是关于预测的。这意味着给定一定数量的训练样本,系统需要能推广到之前没见到过的样本。对训练数据集有很好的性能还不够,真正的目标是对新实例预测的性能。
有两种主要的归纳方法:基于实例学习和基于模型学习。
基于实例学习
也许最简单的学习形式就是用记忆学习。如果用这种方法做一个垃圾邮件检测器,只需标记所有和用户标记的垃圾邮件相同的邮件 —— 这个方法不差,但肯定不是最好的。
不仅能标记和已知的垃圾邮件相同的邮件,你的垃圾邮件过滤器也要能标记类似垃圾邮件的邮件。这就需要测量两封邮件的相似性。一个(简单的)相似度测量方法是统计两封邮件包含的相同单词的数量。如果一封邮件含有许多垃圾邮件中的词,就会被标记为垃圾邮件。
这被称作基于实例学习:系统先用记忆学习案例,然后使用相似度测量推广到新的例子(图 1-15)。
图 1-15 基于实例学习
基于模型学习
另一种从样本集进行归纳的方法是建立这些样本的模型,然后使用这个模型进行预测。这称作基于模型学习(图 1-16)。
图 1-16 基于模型学习
例如,你想知道钱是否能让人快乐,你从 OECD 网站(http://stats.oecd.org/index.aspx?DataSetCode=BLI)下载了 Better Life Index 指数数据,还从 IMF (点击阅读原文可跳转)下载了人均 GDP 数据。表 1-1 展示了摘要。
表 1-1 钱会使人幸福吗?
用一些国家的数据画图(图 1-17)。
图 1-17 你看到趋势了吗?
确实能看到趋势!尽管数据有噪声(即,部分随机),看起来生活满意度是随着人均 GDP 的增长线性提高的。所以,你决定生活满意度建模为人均 GDP 的线性函数。这一步称作模型选择:你选一个生活满意度的线性模型,只有一个属性,人均 GDP(公式 1-1)。
公式 1-1 一个简单的线性模型
这个模型有两个参数θ0
和θ1
。通过调整这两个参数,你可以使你的模型表示任何线性函数,见图 1-18。
图 1-18 几个可能的线性模型
在使用模型之前,你需要确定θ0
和θ1
。如何能知道哪个值可以使模型的性能最佳呢?要回答这个问题,你需要指定性能的量度。你可以定义一个实用函数(或拟合函数)用来测量模型是否够好,或者你可以定义一个代价函数来测量模型有多差。对于线性回归问题,人们一般是用代价函数测量线性模型的预测值和训练样本的距离差,目标是使距离差最小。
接下来就是线性回归算法,你用训练样本训练算法,算法找到使线性模型最拟合数据的参数。这称作模型训练。在我们的例子中,算法得到的参数值是θ0=4.85
和θ1=4.91×10–5
。
现在模型已经最紧密地拟合到训练数据了,见图 1-19。
图 1-19 最佳拟合训练数据的线性模型
最后,可以准备运行模型进行预测了。例如,假如你想知道塞浦路斯人有多幸福,但 OECD 没有它的数据。幸运的是,你可以用模型进行预测:查询塞浦路斯的人均 GDP,为 22587 美元,然后应用模型得到生活满意度,后者的值在4.85 + 22,587 × 4.91 × 10-5 = 5.96
左右。
为了激起你的兴趣,案例 1-1 展示了加载数据、准备、创建散点图的 Python 代码,然后训练线性模型并进行预测。
案例 1-1,使用 Scikit-Learn 训练并运行线性模型。
import matplotlib import matplotlib.pyplot as plt import numpy as np import pandas as pd import sklearn # 加载数据 oecd_bli = pd.read_csv("oecd_bli_2015.csv", thousands=',') gdp_per_capita = pd.read_csv("gdp_per_capita.csv",thousands=',',delimiter='\t', encoding='latin1', na_values="n/a") # 准备数据 country_stats = prepare_country_stats(oecd_bli, gdp_per_capita) X = np.c_[country_stats["GDP per capita"]] y = np.c_[country_stats["Life satisfaction"]] # 可视化数据 country_stats.plot(kind='scatter', x="GDP per capita", y='Life satisfaction') plt.show() # 选择线性模型 lin_reg_model = sklearn.linear_model.LinearRegression() # 训练模型 lin_reg_model.fit(X, y) # 对塞浦路斯进行预测 X_new = [[22587]] # 塞浦路斯的人均GDP print(lin_reg_model.predict(X_new)) # outputs [[ 5.96242338]]
注解:如果你之前接触过基于实例学习算法,你会发现斯洛文尼亚的人均 GDP(20732 美元)和塞浦路斯差距很小,OECD 数据上斯洛文尼亚的生活满意度是 5.7,就可以预测塞浦路斯的生活满意度也是 5.7。如果放大一下范围,看一下接下来两个临近的国家,你会发现葡萄牙和西班牙的生活满意度分别是 5.1 和 6.5。对这三个值进行平均得到 5.77,就和基于模型的预测值很接近。这个简单的算法叫做k近邻回归(这个例子中,
k=3
)。
在前面的代码中替换线性回归模型为 K 近邻模型,只需更换下面一行:
clf = sklearn.linear_model.LinearRegression()
为:
clf = sklearn.neighbors.KNeighborsRegressor(n_neighbors=3)
如果一切顺利,你的模型就可以作出好的预测。如果不能,你可能需要使用更多的属性(就业率、健康、空气污染等等),获取更多更好的训练数据,或选择一个更好的模型(比如,多项式回归模型)。
总结一下:
研究数据
选择模型
用训练数据进行训练(即,学习算法搜寻模型参数值,使代价函数最小)
最后,使用模型对新案例进行预测(这称作推断),但愿这个模型推广效果不差
这就是一个典型的机器学习项目。在第 2 章中,你会第一手地接触一个完整的项目。
我们已经学习了许多关于基础的内容:你现在知道了机器学习是关于什么的,为什么它这么有用,最常见的机器学习的分类,典型的项目工作流程。现在,让我们看一看学习中会发生什么错误,导致不能做出准确的预测。
机器学习的主要挑战
简而言之,因为你的主要任务是选择一个学习算法并用一些数据进行训练,会导致错误的两件事就是“错误的算法”和“错误的数据”。我们从错误的数据开始。
训练数据量不足
要让一个蹒跚学步的孩子知道什么是苹果,需要做的就是指着一个苹果说“苹果”(可能需要重复这个过程几次)。现在这个孩子就能认识所有形状和颜色的苹果。真是个天才!
机器学习还达不到这个程度;需要大量数据,才能让多数机器学习算法正常工作。即便对于非常简单的问题,一般也需要数千的样本,对于复杂的问题,比如图像或语音识别,你可能需要数百万的样本(除非你能重复使用部分存在的模型)。
数据不合理的有效性
在一篇 2001 年发表的著名论文中,微软研究员 Michele Banko 和 Eric Brill 展示了不同的机器学习算法,包括非常简单的算法,一旦有了大量数据进行训练,在进行去除语言歧义的测试中几乎有相同的性能(见图 1-20)。
图 1-20 数据和算法的重要性对比
论文作者说:“结果说明,我们可能需要重新考虑在算法开发 vs 语料库发展上花费时间和金钱的取舍。”
对于复杂问题,数据比算法更重要的主张在 2009 年由 Norvig 发表的论文《The Unreasonable Effectiveness of Data》得到了进一步的推广。但是,应该注意到,小型和中型的数据集仍然是非常常见的,获得额外的训练数据并不总是轻易和廉价的,所以不要抛弃算法。
没有代表性的训练数据
为了更好地进行归纳推广,让训练数据对新数据具有代表性是非常重要的。无论你用的是基于实例学习或基于模型学习,这点都很重要。
例如,我们之前用来训练线性模型的国家集合不够具有代表性:缺少了一些国家。图 1-21 展示了添加这些缺失国家之后的数据。
图 1-21 一个更具代表性的训练样本
如果你用这份数据训练线性模型,得到的是实线,旧模型用虚线表示。可以看到,添加几个国家不仅可以显著地改变模型,它还说明如此简单的线性模型可能永远不会达到很好的性能。貌似非常富裕的国家没有中等富裕的国家快乐(事实上,非常富裕的国家看起来更不快乐),相反的,一些贫穷的国家看上去比富裕的国家还幸福。
使用了没有代表性的数据集,我们训练了一个不可能得到准确预测的模型,特别是对于非常贫穷和非常富裕的国家。
使用具有代表性的训练集对于推广到新案例是非常重要的。但是做起来比说起来要难:如果样本太小,就会有样本噪声(即,会有一定概率包含没有代表性的数据),但是即使是非常大的样本也可能没有代表性,如果取样方法错误的话。这叫做样本偏差。
一个样本偏差的著名案例
也许关于样本偏差最有名的案例发生在 1936 年兰登和罗斯福的美国大选:《文学文摘》做了一个非常大的民调,给 1000 万人邮寄了调查信。得到了 240 万回信,非常有信心地预测兰登会以 57% 赢得大选。然而,罗斯福赢得了 62% 的选票。错误发生在《文学文摘》的取样方法:
首先,为了获取发信地址,《文学文摘》使用了电话黄页、杂志订阅用户、俱乐部会员等相似的列表。所有这些列表都偏向于富裕人群,他们都倾向于投票给共和党(即兰登)。
第二,只有 25% 的回答了调研。这就又一次引入了样本偏差,它排除了不关心**的人、不喜欢《文学文摘》的人,和其它关键人群。这种特殊的样本偏差称作无应答偏差。
下面是另一个例子:假如你想创建一个能识别放克音乐(Funk Music, 别名骚乐)视频的系统。建立训练集的方法之一是在 YouTube 上搜索“放克音乐”,使用搜索到的视频。但是这样就假定了 YouTube 的搜索引擎返回的视频集,是对 YouTube 上的所有放克音乐有代表性的。事实上,搜索结果会偏向于人们歌手(如果你居住在巴西,你会得到许多“funk carioca”视频,它们和 James Brown 的截然不同)。从另一方面来讲,你怎么得到一个大的训练集呢?
低质量数据
很明显,如果训练集中的错误、异常值和噪声(错误测量引入的)太多,系统检测出潜在规律的难度就会变大,性能就会降低。花费时间对训练数据进行清理是十分重要的。事实上,大多数据科学家的一大部分时间是做清洗工作的。例如:
如果一些实例是明显的异常值,最好删掉它们或尝试手工修改错误;
如果一些实例缺少特征(比如,你的 5% 的顾客没有说明年龄),你必须决定是否忽略这个属性、忽略这些实例、填入缺失值(比如,年龄中位数),或者训练一个含有这个特征的模型和一个不含有这个特征的模型,等等。
不相关的特征
俗语说:进来的是垃圾,出去的也是垃圾。你的系统只有在训练数据包含足够相关特征、非相关特征不多的情况下,才能进行学习。机器学习项目成功的关键之一是用好的特征进行训练。这个过程称作特征工程,包括:
特征选择:在所有存在的特征中选取最有用的特征进行训练。
特征提取:组合存在的特征,生成一个更有用的特征(如前面看到的,可以使用降维算法)。
收集新数据创建新特征。
现在,我们已经看过了许多坏数据的例子,接下来看几个坏算法的例子。
过拟合训练数据
如果你在外国游玩,当地的出租车司机多收了你的钱。你可能会说这个国家所有的出租车司机都是小偷。过度归纳是我们人类经常做的,如果我们不小心,机器也会犯同样的错误。在机器学习中,这称作过拟合:意思是说,模型在训练数据上表现很好,但是推广效果不好。
图 1-22 展示了一个高阶多项式生活满意度模型,它大大过拟合了训练数据。即使它比简单线性模型在训练数据上表现更好,你会相信它的预测吗?
图 1-22 过拟合训练数据
复杂的模型,比如深度神经网络,可以检测数据中的细微规律,但是如果训练集有噪声,或者训练集太小(太小会引入样本噪声),模型就会去检测噪声本身的规律。很明显,这些规律不能推广到新实例。例如,假如你用更多的属性训练生活满意度模型,包括不包含信息的属性,比如国家的名字。如此一来,负责的模型可能会检测出训练集中名字有 w 字母的国家的生活满意度大于 7:新西兰(7.3),挪威(7.4),瑞典(7.2)和瑞士(7.5)。你能相信这个 W-满意度法则推广到卢旺达和津巴布韦吗?很明显,这个规律只是训练集数据中偶然出现的,但是模型不能判断这个规律是真实的、还是噪声的结果。
警告:过拟合发生在相对于训练数据的量和噪声,模型过于复杂的情况。可能的解决方案有:
简化模型,可以通过选择一个参数更少的模型(比如使用线性模型,而不是高阶多项式模型)、减少训练数据的属性数、或限制一下模型
收集更多的训练数据
减小训练数据的噪声(比如,修改数据错误和去除异常值)
限定一个模型以让它更简单,降低过拟合的风险被称作正则化(regularization)。例如,我们之前定义的线性模型有两个参数,θ0
和θ1
。它给了学习算法两个自由度以让模型适应训练数据:可以调整截距θ0
和斜率θ1
。如果强制θ1=0
,算法就只剩一个自由度,拟合数据就会更为困难:能做的只是将在线下移动,尽可能地靠近训练实例,结果会在平均值附近。这就是一个非常简单的模型!如果我们允许算法可以修改θ1
,但是只能在一个很小的范围内修改,算法的自由度就会介于 1 和 2 之间。它要比两个自由度的模型简单,比 1 个自由度的模型要复杂。你的目标是在完美拟合数据和保持模型简单性上找到平衡,确保算法的推广效果。
图 1-23 展示了三个模型:虚线表示用缺失部分国家的数据训练的原始模型,短划线是我们的第二个用所有国家训练的模型,实线模型的训练数据和第一个相同,但进行了正则化限制。你可以看到正则化强制模型有一个小的斜率,它对训练数据的拟合不是那么好,但是对新样本的推广效果好。
图 1-23 正则化降低了过度拟合的风险
正则化的度可以用一个超参数(hyperparameter)控制。超参数是一个学习算法的参数(而不是模型的)。这样,它是不会被学习算法本身影响的,它优于训练,在训练中是保持不变的。如果你设定的超参数非常大,就会得到一个几乎是平的模型(斜率接近于 0);这种学习算法几乎肯定不会过拟合训练数据,但是也很难得到一个好的解。调节超参数是创建机器学习算法非常重要的一部分(下一章你会看到一个详细的例子)。
欠拟合训练数据
你可能猜到了,欠拟合是和过拟合相对的:当你的模型过于简单时就会发生。例如,生活满意度的线性模型倾向于欠拟合;现实要比这个模型复杂的多,所以预测很难准确,即使在训练样本上也很难准确。
解决这个问题的选项包括:
选择一个更强大的模型,带有更多参数
用更好的特征训练学习算法(特征工程)
减小对模型的限制(比如,减小正则化超参数)
回顾
现在,你已经知道了很多关于机器学习的知识。然而,学过了这么多概念,你可能会感到有些迷失,所以让我们退回去,回顾一下重要的:
机器学习是让机器通过学习数据对某些任务做得更好,而不使用确定的代码规则。
有许多不同类型的机器学习系统:监督或非监督,批量或在线,基于实例或基于模型,等等。
在机器学习项目中,我们从训练集中收集数据,然后对学习算法进行训练。如果算法是基于模型的,就调节一些参数,让模型拟合到训练集(即,对训练集本身作出好的预测),然后希望它对新样本也能有好预测。如果算法是基于实例的,就是用记忆学习样本,然后用相似度推广到新实例。
如果训练集太小、数据没有代表性、含有噪声、或掺有不相关的特征(垃圾进,垃圾出),系统的性能不会好。最后,模型不能太简单(会发生欠拟合)或太复杂(会发生过拟合)。
还差最后一个主题要学习:训练完了一个模型,你不只希望将它推广到新样本。如果你想评估它,那么还需要作出必要的微调。一起来看一看。
测试和确认
要知道一个模型推广到新样本的效果,唯一的办法就是真正的进行试验。一种方法是将模型部署到生产环境,观察它的性能。这么做可以,但是如果模型的性能很差,就会引起用户抱怨 —— 这不是最好的方法。
更好的选项是将你的数据分成两个集合:训练集和测试集。正如它们的名字,用训练集进行训练,用测试集进行测试。对新样本的错误率称作推广错误(或样本外错误),通过模型对测试集的评估,你可以预估这个错误。这个值可以告诉你,你的模型对新样本的性能。
如果训练错误率低(即,你的模型在训练集上错误不多),但是推广错误率高,意味着模型对训练数据过拟合。
提示:一般使用 80% 的数据进行训练,保留20%用于测试。
因此,评估一个模型很简单:只要使用测试集。现在假设你在两个模型之间犹豫不决(比如一个线性模型和一个多项式模型):如何做决定呢?一种方法是两个都训练,,然后比较在测试集上的效果。
现在假设线性模型的效果更好,但是你想做一些正则化以避免过拟合。问题是:如何选择正则化超参数的值?一种选项是用 100 个不同的超参数训练100个不同的模型。假设你发现最佳的超参数的推广错误率最低,比如只有 5%。然后就选用这个模型作为生产环境,但是实际中性能不佳,误差率达到了 15%。发生了什么呢?
答案在于,你在测试集上多次测量了推广误差率,调整了模型和超参数,以使模型最适合这个集合。这意味着模型对新数据的性能不会高。
这个问题通常的解决方案是,再保留一个集合,称作验证集合。用测试集和多个超参数训练多个模型,选择在验证集上有最佳性能的模型和超参数。当你对模型满意时,用测试集再做最后一次测试,以得到推广误差率的预估。
为了避免“浪费”过多训练数据在验证集上,通常的办法是使用交叉验证:训练集分成互补的子集,每个模型用不同的子集训练,再用剩下的子集验证。一旦确定模型类型和超参数,最终的模型使用这些超参数和全部的训练集进行训练,用测试集得到推广误差率。
没有免费午餐公理
模型是观察的简化版本。简化意味着舍弃无法进行推广的表面细节。但是,要确定舍弃什么数据、保留什么数据,必须要做假设。例如,线性模型的假设是数据基本上是线性的,实例和模型直线间的距离只是噪音,可以放心忽略。
在一篇 1996 年的著名论文中,David Wolpert 证明,如果完全不对数据做假设,就没有理由选择一个模型而不选另一个。这称作没有免费午餐(NFL)公理。对于一些数据集,最佳模型是线性模型,而对其它数据集是神经网络。没有一个模型可以保证效果更好(如这个公理的名字所示)。确信的唯一方法就是测试所有的模型。因为这是不可能的,实际中就必须要做一些对数据合理的假设,只评估几个合理的模型。例如,对于简单任务,你可能是用不同程度的正则化评估线性模型,对于复杂问题,你可能要评估几个神经网络模型。