教你的电脑
正如我在之前的两篇文章(机器学习无处不在 和 为机器学习准备数据)中所写的那样,机器学习正在以多种方式影响着我们的生活。作为消费者,您无疑已经体验过机器学习,无论您是否意识到——从各种在线商店为您推荐您应该购买的产品,到 Facebook 上出现(和不出现)的帖子选择,到航空公司使用的令人恼火的语音识别系统,再到越来越多的公司根据您的个人偏好为您选择服装、食物和葡萄酒。
机器学习无处不在,虽然理论和实践都需要一些时间来学习和内化,但对于人们来说,基础知识还是相当简单的。
机器学习背后的基本思想是,您构建一个模型——描述输入和输出之间关系的方式。然后,这个模型允许您要求计算机分析新数据,并预测新输入集的输出。这基本上就是机器学习的全部内容。在“监督学习”中,计算机被训练来根据人类先前分类的输入对数据进行分类。在“无监督学习”中,您要求计算机代表您对数据进行分类。
在我的上一篇文章中,我开始探索由数据科学家(和神经科学博士生)斯科特·科尔创建的数据集,他测量了加利福尼亚州各种餐厅的墨西哥卷饼。我研究了科尔和他的研究员食客收集的不同数据类别,并考虑了一些方法,可以将数据集精简为更易于管理且合理的数据集。
在这里,我描述了如何使用这个较小的数据集,它仅包含被认为是必要的特征,并使用它通过创建机器学习模型来训练计算机。
机器学习模型假设墨西哥卷饼的质量仅由其大小决定。因此,墨西哥卷饼越大,质量越好;墨西哥卷饼越小,质量越差。如果您将大小描述为矩阵 X,并将结果质量评分描述为 y,则可以用数学方式将其描述为
y = qX
其中 q 是描述 X 和 y 之间关系的因子。
当然,您知道墨西哥卷饼的质量不仅仅与大小有关。实际上,在科尔的研究中,大小已从特征列表中删除,部分原因是并非每个数据点都包含大小信息。
此外,这个示例模型需要考虑多个因素——而不仅仅是一个——并且可能需要以复杂的方式组合它们,才能准确预测输出值。实际上,有许多算法可以用来创建模型;确定哪一个合适,然后在正确的方式中对其进行调整,是游戏的一部分。
那么,这里的目标是将墨西哥卷饼数据和算法结合起来,创建一个墨西哥卷饼美味程度的模型。下一步将是查看该模型是否可以根据其输入预测墨西哥卷饼的美味程度。
但是,您如何创建这样的模型呢?
理论上,您可以从头开始创建它,阅读适当的统计文献并在代码中实现所有内容。但是因为我正在使用 Python,并且因为 Python 的 scikit-learn 经过多年的调整和改进,所以有多种模型类型可供选择,而其他人已经创建了这些模型。
但是,在开始模型构建之前,让我们先将数据转换为必要的格式。正如我在上一篇文章中提到的以及上面暗示的那样,Python 的机器学习包(scikit-learn)期望,在训练监督学习模型时,您需要一组样本输入,传统上放在一个名为 X(是的,大写 X)的二维矩阵中,以及一组样本输出,传统上放在一个名为 y(小写)的向量中。您可以在 Jupyter 笔记本中按如下方式获得它们
%pylab inline
import pandas as pd # load pandas with an alias
from pandas import Series, DataFrame # load useful Pandas classes
df = pd.read_csv('burrito.csv') # read into a data frame
加载包含墨西哥卷饼数据的 CSV 文件后,您将仅保留包含感兴趣的特征以及输出分数的列
burrito_data = df[range(11,24)]
然后,您将删除彼此高度相关和/或大量数据缺失的列。在这种情况下,这意味着删除所有与墨西哥卷饼大小相关的特征
burrito_data.drop(['Circum', 'Volume', 'Length'], axis=1,
↪inplace=True)
让我们也删除任何一个或多个值为 NaN(“非数字”)的样本(即行),这将抛出值
burrito_data.dropna(inplace=True, axis=0)
完成此操作后,数据帧即可在模型中使用。分离出 X 和 y 值
y = burrito_data['overall']
X = burrito_data.drop(['overall'], axis=1)
现在的目标是创建一个模型,尽可能好地描述 X 中的值如何导致 y 中的值。换句话说,如果您查看 X.iloc[0]
(即,第一个墨西哥卷饼样本的输入值)和 y.iloc[0]
(即,第一个墨西哥卷饼样本的输出值),应该可以理解这些输入如何映射到这些输出。此外,在用数据训练计算机后,计算机应该能够根据相同的输入预测墨西哥卷饼的总体评分。
现在数据已就绪,您可以构建模型了。但是,您应该为模型使用哪种算法(有时称为“分类器”)?在许多方面,这是机器学习中的一个大问题,通常只能通过经验和反复试验来解答。您解决的机器学习问题越多,您就越能感受到您可以尝试的模型类型。但是,总是有可能出错,这就是为什么通常值得创建几种不同类型的模型,并将它们相互比较以验证有效性。我计划在下一篇文章中更多地谈论有效性测试;现在,重要的是了解如何构建模型。
不同的算法适用于不同类型的机器学习问题。在这种情况下,输入数据已经被排名,这意味着您可以使用监督学习模型。模型的输出是一个介于 0 到 5 之间的数字评分,这意味着您必须使用数字模型,而不是分类模型。
区别在于,分类模型的输出将(顾名思义)指示输入应放入的几个类别中的哪一个,这些类别由整数标识。例如,现代政党聘请数据科学家,试图根据输入数据确定某人将如何投票。结果,即政党,是分类的。
但是,在这种情况下,您有数字数据。在这种模型中,您期望输出在数字范围内变化。定价模型,确定某人可能愿意为特定商品支付多少钱或为广告收取多少费用,将使用这种模型。
我应该注意到,如果您愿意,您可以简单地通过舍入或截断浮点 y 值,将数字数据转换为分类数据,这样您就可以获得整数值。正是这种转换可能是您需要考虑——并尝试和测试——在机器学习项目中进行的。而且,正是这无数的选择和选项可能导致数据科学项目变得复杂,并结合您的经验和见解,以及对各种可能模型的蛮力测试。
假设您将保持数据不变。您不能使用纯粹的分类模型,而需要使用一种结合了“回归”统计概念的模型,在回归中,您尝试确定哪些输入因素导致输出与输出线性相关——也就是说,假设理想情况类似于您在上面看到的“y = qX”;鉴于情况并非如此,肉类质量、均匀性与温度相比有多大的影响?这些因素中的每一个都以某种方式影响了整体质量,但其中一些因素比其他因素的影响更大。
最容易理解和最流行的模型类型之一是使用 K 近邻 (KNN) 算法。KNN 基本上说,您将获取一条新的数据,并将其特征与现有的、已知的、分类的数据的特征进行比较。然后,新数据被分类到与其 K 个最近邻居相同的类别中,其中 K 是您必须确定的数字,通常通过反复试验确定。
但是,KNN 仅适用于类别;此示例处理的是回归问题,不能使用 KNN。除了,Python 的 scikit-learn 恰好带有一个版本的 KNN,该版本旨在用于回归问题——KNeighborsRegressor
分类器。
那么,您如何使用它呢?以下是 scikit-learn 中所有监督学习发生的基本方式
-
导入实现分类器的 Python 类。
-
创建一个模型——即分类器的实例。
-
使用“fit”方法训练模型。
-
将数据馈送到模型并获得预测。
让我们用数据试一下。您已经有了 X 和 y,您可以将它们插入到标准的 sklearn
模式中
from sklearn.neighbors import KNeighborsRegressor # import classifier
KNR = KNeighborsRegressor() # create a model
KNR.fit(X, y) # train the model
如果没有上面的 dropna
(我在其中删除了包含一个或多个 NaN 值的任何行),您仍然会有“脏”数据,并且 sklearn 将无法继续。一些分类器可以处理 NaN 数据,但作为一般规则,您需要摆脱 NaN 值——要么是为了满足分类器的规则,要么是为了确保您的结果质量高,甚至(在某些情况下)有效。
有了训练好的模型,您现在可以问它:“如果您有一个配料非常好的墨西哥卷饼,它的排名会有多高?”
您要做的就是创建一个新的、假的样本墨西哥卷饼,其中包含所有高质量的配料
great_ingredients = np.ones(X.iloc[0].count()) * 5
在上面的代码行中,我从 X 中获取了第一个样本(即,X.iloc[0]
),然后计算了它包含多少项。然后,我将结果 NumPy 数组乘以 5,使其包含所有 5。我现在可以要求模型预测这样一个墨西哥卷饼的总体质量
KNR.predict([great_ingredients])
我得到的结果是
array([ 4.86])
这意味着墨西哥卷饼确实会得分很高——不是 5 分,但仍然很高。如果您创建一个配料绝对糟糕的墨西哥卷饼会怎样?让我们找到预测的质量
terrible_ingredients = np.zeros(X.iloc[0].count())
在上面的代码行中,我创建了一个包含零的 NumPy 数组,其长度与 X 的特征列表相同。如果您现在要求模型预测这个墨西哥卷饼的分数,您会得到
array([ 1.96])
好消息是,您现在已经训练计算机根据一组评级的配料预测墨西哥卷饼的质量。另一个好消息是,您可以确定哪些配料更有影响力,哪些配料影响力较小。
与此同时,存在一个问题:您如何知道 KNN 回归是您可以使用的最佳模型?当我说“最佳”时,我问它是否最准确地预测墨西哥卷饼的质量。例如,也许不同的分类器会具有更高的分散性,或者会更准确地描述墨西哥卷饼。
分类器也可能是一个好的分类器,但它的一个参数——您可以用来“调整”模型的参数——设置不正确。我怀疑您确实可以做得更好,因为实际采样的最佳墨西哥卷饼获得了 5 分,而最差的墨西哥卷饼获得了 1.5 分。这意味着该模型不是一个糟糕的开始,但它并没有完全处理人们期望的整个范围。
解决此问题的一种可能方法是调整您在创建模型时传递给分类器的参数。在任何与 KNN 相关的模型的情况下,您可以尝试调整的第一个参数之一是 n_neighbors
。默认情况下,它设置为 5,但是如果您将其设置为更高或更低会怎样?
一段 Python 代码可以为您建立这一点
for k in range(1,10):
print(k)
KNR = KNeighborsRegressor(n_neighbors=k)
KNR.fit(X, y)
print("\tTerrible: {0}".format(KNR.predict([terrible_ingredients])))
print("\tBest: {0}".format(KNR.predict([great_ingredients])))
运行上面的代码后,似乎具有最高高和最低低的模型是 n_neighbors
等于 1 的模型。这与我预期的不太一样,但这就是为什么尝试不同模型很重要的原因。
然而,这种检查 n_neighbors
的哪个值是最佳值的方法相当原始,并且存在许多问题。在我的下一篇文章中,我计划研究检查模型,使用比我在这里使用的更复杂的技术。
到目前为止,我已经描述了如何从单个分类器创建多个模型,但是 scikit-learn 带有许多分类器,并且通常尝试几个是一个好主意。
因此,在这种情况下,让我们也尝试一个简单的回归模型。KNN 使用现有的、已知的数据点来决定根据新输入预测哪些输出,而回归使用良好的旧统计技术。因此,您可以按如下方式使用它
from sklearn.linear_model import LinearRegression
LR = LinearRegression()
LR.fit(X, y)
print("\tTerrible: {0}".format(KNR.predict([terrible_ingredients])))
print("\tBest: {0}".format(KNR.predict([great_ingredients])))
再次,我想强调的是,仅仅因为您没有涵盖从最好到最坏的整个输出值范围,您就不能否定此模型。而且,适用于某些数据集的模型通常不适用于其他数据集。
但是正如您所看到的,scikit-learn 使创建和试验不同的模型变得容易——实际上几乎微不足道。因此,您可以尝试不同的分类器和分类器类型,以创建描述您的数据的模型。
既然您已经创建了几个模型,那么最大的问题是哪个模型是最好的?哪个模型不仅描述了数据,而且做得很好?当您遇到越来越多的墨西哥卷饼时,哪个模型将提供最强的预测能力?墨西哥卷饼制造商应该强调哪些配料才能最大程度地提高食客满意度,同时最大程度地降低成本?
为了回答这些问题,您需要有一种测试模型的方法。在我的下一篇文章中,我将研究如何测试您的模型,使用各种技术来检查模型的有效性,甚至将多种分类器类型相互比较。
资源我在本文中使用了 Python 和 SciPy 堆栈的许多部分(NumPy、SciPy、Pandas、matplotlib 和 scikit-learn)。所有这些都可以从 PyPI 或 SciPy.org 获得。
我为对数据科学和机器学习感兴趣的人推荐了一些资源。一个长期存在的每周电子邮件列表是 “KDNuggets”。您还应该考虑 “Data Science Weekly” 新闻通讯和 “This Week in Data”,其中描述了公众可用的最新数据集。
我是播客的忠实粉丝,特别喜欢“Partially Derivative”。其他好的播客包括“Data Stories”和“Linear Digressions”。我定期收听所有这三个播客,并从中学习。
如果您想进入数据科学和机器学习领域,我推荐 Kevin Markham 的 “Data School” 和 Jason Brownlie 的 “Machine Learning Mastery”,他在那里销售许多关于这些主题的简短、密集但高质量的电子书。