❀ 1 数据科学/机器学习工作流程
❀ 1.1 获取(Acquisition)
❀ 1.2 检查和研究(Inspection and exploration)
❀ 1.3 清理和准备(Cleaning and preparation)
❀ 1.4 建模(Modeling)
❀ 1.5 评估(Evaluation)
❀ 1.6 部署(Deployment)
❀ 2 Python库和函数
❀ 2.1 获取(Acquisition)
❀ 2.2 检查(Inspection)
❀ 2.2.1 Jupyter笔记本(The Jupyter notebook)
❀ 2.2.2 Pandas
❀ 2.2.3 可视化(Visualization)
❀ 2.2.3.1 matplotlib库
❀ 2.2.3.2 seaborn库
❀ 2.3 准备(preparation)
❀ 2.3.1 Map
❀ 2.3.2 Apply
❀ 2.3.3 Applymap
❀ 2.3.4 Groupby
❀ 2.4 建模和评估(Modeling and evaluation)
❀ 2.4.1 Statsmodels
❀ 2.4.2 Scikit-learn
❀ 2.5 部署(Deployment)
❀ 3 设置你的机器学习环境
❀ 4 总结
机器学习正在迅速改变我们的世界。 作为人工智能的核心,度过一天是困难的如果没有弄懂它将如何改变我们的生活。 有人认为它会把我们带入奇异的技术乌托邦。 另外一些人则认为,我们正在朝着一个技术发展的方向前进,这个技术发展的标志是不断与作业机器人和无人驾驶飞行器作战。 但是,尽管专家们可能会喜欢讨论这些夸张的未来,但更现实的是,机器学习正在迅速成为我们日常生活的一部分。 机器学习通过对计算机和我们周围世界的交互方式进行微妙而渐进的改进,正在悄然改善我们的生活。
如果您在Amazon.com等在线零售平台购物,使用流媒体音乐或电影服务(如Spotify或Netflix),甚至只是执行Google搜索,就会遇到机器学习应用程序。 使用这些服务的用户生成的数据被收集、汇总和反馈到模型中, 通过为每个用户创建量身定制的体验来改进服务。
现在是开发机器学习应用程序的理想时机,正如您将发现的那样,Python是开发这些应用程序的理想选择。 Python有一个深入而活跃的开发者社区,其中许多开发者也来自科学界。 这为Python提供了丰富的科学计算库。 在本书中,我们将讨论并使用这个Python科学堆栈中的一些库。
在接下来的章节中,我们将逐步学习如何构建各种机器学习应用程序。 但在我们认真开始之前,我们将在本章的剩余部分中讨论这些关键库的功能,以及如何准备好您的环境以最好地利用它们。
我们将在本章中介绍以下主题:
❀数据科学/机器学习工作流程
❀工作流程的每个阶段的库
❀设置您的环境
构建机器学习应用程序虽然在很多方面与标准工程范例相似,但是在一个关键方面有所不同:需要将数据作为原材料。 数据项目的成功在很大程度上取决于您获得的数据的质量以及如何处理。 而且,由于使用数据属于数据科学领域,因此了解数据科学工作流程会很有帮助:
机器学习应用程序的数据拥有大量的来源; 它可能被作为一个CSV文件的电子邮件附件,它可能来自下载的服务器日志,或者可能需要建立一个自定义网页。 数据也可以有多种格式。 在大多数情况下,它将是基于文本的数据,但正如我们将要看到的,机器学习应用程序可以使用图像甚至视频文件轻松构建。 不管格式如何,一旦获得数据,理解数据中的内容至关重要。
一旦数据被获取,下一步就是检查和研究它。 在这个阶段,主要目标是对数据进行完整性检查,而完成这一工作的最好方法是寻找不可能或极不可能的事情。 例如,如果数据具有唯一标识符,请检查确实只有一个; 如果数据是基于价格的,检查是否总是正的; 无论数据类型如何,检查最极端的情况。 他们合理吗? 一个好的做法是对数据进行一些简单的统计测试并将其可视化。 此外,有可能某些数据丢失或不完整。 在这个阶段注意到这一点是非常重要的,因为需要在清理和准备阶段对数据进行处理。 模型只与进入它们的数据一样好,所以正确使用这个步骤是至关重要的。
当所有的数据都是有序的时候,下一步就是把它放在一个适合建模的格式中。 这个阶段包含了一些过程,如过滤,聚合,输入和转换。 需要的操作类型将高度依赖于数据的类型以及所使用的库和算法的类型。 例如,对于基于自然语言的文本,所需的转换将与时间序列数据所需的转换大不相同。 在本书中,我们将看到许多这类转换的例子。
一旦数据准备完成,下一个阶段就是建模。 在这个阶段,选择一个合适的算法,并对数据进行建模。 在这个阶段有许多最佳实践,我们将会详细讨论它们,但是基本的步骤是把数据分成训练(training:不知道怎么翻译),测试和验证集。 这种分割数据的方式可能看起来很不合理 - 特别是当更多的数据通常会产生更好的模型时 - 但是我们将会看到,这样做可以让我们得到更好的反馈,了解模型在现实世界中的表现,并从建模的基本错误中阻止我们:过度拟合(overfitting)。
一旦建立模型并进行预测,下一步就是了解模型如何实现这一点。 这是评估试图回答的问题。 有很多方法可以衡量一个模型的性能,而且它很大程度上依赖于数据类型和使用的模型,但是总的来说,我们试图回答模型的预测有多接近实际值。 有一些令人困惑的词汇,例如均方根误差,欧几里得距离和F1分数,但最终它们只是实际值与估计预测之间的距离的度量。
一旦模型的性能令人满意,下一步就是部署。 这可能需要多种形式,具体取决于用例,但是常见的情形是作为另一个更大的应用程序、定制的Web应用程序的一个功能,甚至只是一个简单的cron作业。
现在我们已经了解了数据科学工作流程中的每一个步骤,我们将在每个步骤中查看这些库中的一些有用的Python库和函数。
因为访问数据的最常用方法之一是通过RESTful API,所以需要注意的一个库是Python请求库(Requests库)(http://www.python-requests.org/en/latest/)。 为人们提供HTTP,它提供了一个干净和简单的方式来与API交互。
让我们来看看使用请求( Requests)从GitHub的API下拉数据的示例交互。 在这里,我们将调用API并请求一个主角存储库列表:
import requests
r = requests.get(r"https://api.github.com/users/acombs/starred")
r.json()
这将返回主角的所有存储库列表及其属性的JSON文档。 这是前面调用的输出的一个片段:
requests库有很多功能,但是我建议你在上面提供的链接中查看文档。
由于检查数据是机器学习应用程序开发的关键步骤,现在我们将深入了解几个库,这些库将为我们完成这项任务。
有一些库将有助于简化数据检查过程。 第一个是带有IPython的Jupyter笔记本(http://ipython.org/)。 这是一个完善的交互式计算环境,非常适合数据挖掘。 与大多数开发环境不同,Jupyter笔记本是一个基于Web的前端(IPython内核),分为单独的代码块或单元格。 根据需要,单元格可以单独或同时运行。 这允许开发人员运行场景,查看输出结果,然后逐步浏览代码,进行调整并查看结果更改,而不用离开笔记本。 以下是Jupyter笔记本中的示例交互:
Pandas是一个非常好的数据分析工具。参照Pandas文件(http://pandas.pydata.org/pandas-docs/version/0.17.1/):
它有更广泛的目标,即成为任何语言中最强大、最灵活的开源数据分析/操作工具。
如果它还没有达到这个要求,离目标也不会太远了。 现在我们来看看:
import os
import pandas as pd
import requests
PATH = r'/Users/alexcombs/Desktop/iris/'
r =requests.get('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data')
with open(PATH + 'iris.data', 'w') as f:
f.write(r.text)
os.chdir(PATH)
df = pd.read_csv(PATH + 'iris.data', names=['sepal length', 'sepal width','petal length', 'petal width', 'class'])
df.head()
备注:自己学习时翻译成了中文,方便理解,’sepal length’=’萼片长度’, ‘sepal width’=’萼片宽度’,’petal length’=’花瓣长度’, ‘petal width’=’花瓣宽度’, ‘class’=’分类’
df['sepal length']
df.ix[:3,:2]
上面的代码生成以下输出:
df.ix[:3, [x for x in df.columns if 'width' in x]]
上面的代码生成以下输出:
df['class'].unique()
上面的代码生成以下输出:
df[df['class']=='Iris-virginica']
上面的代码生成以下输出:
df.count()
df[df['class']=='Iris-virginica'].count()
virginica = df[df['class']=='Iris-virginica'].reset_index(drop=True)
virginica
df[(df['class']=='Iris-virginica')&(df['petal width']>2.2)]
df.describe()
df.describe(percentiles=[.20,.40,.80,.90,.95])
df.corr()
到目前为止,我们已经看到如何选择DataFrame表的一部分,并从我们的数据中获得汇总统计信息,但现在让我们继续学习如何直观地检查数据。 但是,为什么还要用肉眼检查呢? 让我们看一个例子来理解为什么。
下表说明了四个不同系列的x和y值的汇总统计信息:
x和y系列 | 值 |
---|---|
x的均值 | 9 |
y的均值 | 7.5 |
x的样本方差 | 11 |
y的样本方差 | 4.1 |
x和y之间的相关性 | 0.816 |
回归线 | y=3.00+0.500x |
基于具有相同汇总统计数据的系列,我们可以假设这些系列将会在视觉上类似。 当然,我们是错的,非常错误。 这四个系列是Anscombe( 安斯科姆)四重奏的一部分,它们是为了说明视觉数据检查的重要性而刻意创建的。 每个系列都绘制在下图中:
我们要看的第一个库是matplotlib。 它是Python绘图库之祖。 最初是为了模拟MATLAB的绘图功能而创建的,它随着自身功能的不断变化而成为一个功能齐全的库。 对于那些没有使用MATLAB背景的人来说,很难理解所有这些部分是如何协同工作一起来创建图形的。
我们将把这些部分分解为逻辑组件,以便了解发生了什么事情。 在深入研究matplotlib之前,让我们设置我们的Jupyter笔记本,让我们看到我们的图形。 要做到这一点,我们需要将以下几行添加到我们的import语句中:
import matplotlib.pyplot as plt
plt.style.use('ggplot')
%matplotlib inline
import numpy as np
第一行导入matplotlib,第二行将样式设置为近似R的ggplot库(这需要matplotlib 1.41),第三行设置绘图,使它们在笔记本中可见,最后一行导入numpy。 本章后面我们将使用numpy进行一些操作。
现在,让我们使用以下代码在Iris数据集上生成第一个图形:
fig, ax = plt.subplots(figsize=(6,4))
ax.hist(df['petal width'], color='black');
ax.set_ylabel('Count', fontsize=12)
ax.set_xlabel('Width', fontsize=12)
plt.title('Iris Petal Width', fontsize=14, y=1.01)
上面的代码生成以下输出:
fig, ax = plt.subplots(2,2, figsize=(6,4))
ax[0][0].hist(df['petal width'], color='black');
ax[0][0].set_ylabel('Count', fontsize=12)
ax[0][0].set_xlabel('Width', fontsize=12)
ax[0][0].set_title('Iris Petal Width', fontsize=14, y=1.01)
ax[0][1].hist(df['petal length'], color='black');
ax[0][1].set_ylabel('Count', fontsize=12)
ax[0][1].set_xlabel('Lenth', fontsize=12)
ax[0][1].set_title('Iris Petal Lenth', fontsize=14, y=1.01)
ax[1][0].hist(df['sepal width'], color='black');
ax[1][0].set_ylabel('Count', fontsize=12)
ax[1][0].set_xlabel('Width', fontsize=12)
ax[1][0].set_title('Iris Sepal Width', fontsize=14, y=1.01)
ax[1][1].hist(df['sepal length'], color='black');
ax[1][1].set_ylabel('Count', fontsize=12)
ax[1][1].set_xlabel('Length', fontsize=12)
ax[1][1].set_title('Iris Sepal Length', fontsize=14, y=1.01)
plt.tight_layout()
前面代码的输出显示在以下屏幕截图中:
fig, ax = plt.subplots(figsize=(6,6))
ax.scatter(df['petal width'],df['petal length'], color='green')
ax.set_xlabel('Petal Width')
ax.set_ylabel('Petal Length')
ax.set_title('Petal Scatterplot')
上面的代码生成以下输出:
fig, ax = plt.subplots(figsize=(6,6))
ax.plot(df['petal length'], color='blue')
ax.set_xlabel('Specimen Number')
ax.set_ylabel('Petal Length')
ax.set_title('Petal Length Plot')
上面的代码生成以下输出:
fig,ax=plt.subplots(figsize=(6,6))
bar_width=.8
labels=[x for x in df.columns if 'length' in x or 'width' in x]
ver_y=[df[df['class']=='Iris-versicolor'][x].mean() for x in labels]
vir_y=[df[df['class']=='Iris-virginica'][x].mean() for x in labels]
set_y=[df[df['class']=='Iris-setosa'][x].mean() for x in labels]
x=np.arange(len(labels))
ax.bar(x,vir_y,bar_width,bottom=set_y,color='darkgrey')
ax.bar(x,set_y,bar_width,bottom=ver_y,color='white')
ax.bar(x,ver_y,bar_width,color='black')
ax.set_xticks(x+(bar_width/2))
ax.set_xticklabels(labels,rotation=-70,fontsize=12);
ax.set_title('Mean Feature Measurement By Class',y=1.01)
ax.legend(['Virginica','Setosa','Versicolor'])
上面的代码生成以下输出:
我们将看到的下一个可视化库称为seaborn(http://stanford.edu/mwaskom/software/seaborn/index.html)。 这是一个专为统计可视化而创建的库。 实际上,它是使用pandas数据框的最佳选择,其中列是特征,行是观察值。 这种DataFrame表的风格称为整洁数据,它是机器学习应用程序最常见的形式。
现在我们来看看seaborn的力量:
import seaborn as sns
sns.pairplot(df, hue="class")
用这两行代码,我们得到以下输出:
fig, ax = plt.subplots(2, 2, figsize=(7, 7))
sns.set(style='white', palette='muted')
sns.violinplot(x=df['class'], y=df['sepal length'], ax=ax[0,0])
sns.violinplot(x=df['class'], y=df['sepal width'], ax=ax[0,1])
sns.violinplot(x=df['class'], y=df['petal length'], ax=ax[1,0])
sns.violinplot(x=df['class'], y=df['petal width'], ax=ax[1,1])
fig.suptitle('Violin Plots', fontsize=16, y=1.03)
for i in ax.flat:
plt.setp(i.get_xticklabels(), rotation=-90)
fig.tight_layout()
上面的代码生成以下输出:
我们已经学习了很多关于检查数据的知识,但现在让我们继续学习如何处理和操作数据。 在这里,我们将学习pandas的
Series.map(),Series.apply(),DataFrame.apply(),DataFrame.applymap()和DataFrame.groupby()方法。 这对于处理数据非常有用,在特性工程的机器学习方面尤其有用,这个概念我们将在后面的章节中详细讨论。
在我们的例子中用到了一系列的map方法,所以,我们将使用它来转换我们的DataFrame表的一列,记住它只是一个pandas系列。 假设我们类的名稍微长一点,我们想用我们的特殊的‘三字’编码系统对它们进行编码。 我们将使用带有Python字典的map方法来实现这一点。 我们将替换每一个iris数据类型:
df['class'] = df['class'].map({
'Iris-setosa': 'SET', 'Iris-virginica':'VIR', 'Iris-versicolor': 'VER'})
df
apply方法允许我们使用DataFrame和列。 我们将从一个同样适用于map的例子开始,然后我们将继续讨论仅适用于apply的例子。
使用irsi的DataFrame,我们来创建一个基于‘petal width’的新列。 我们以前看到‘petal width’的平均值是1.3。 现在让我们在我们的DataFrame中创建一个新的列,它包含基于‘petal width’列中的值的二进制值。 如果花瓣宽度等于或大于中值,我们将其编码为1,如果小于中值,则将其编码为0。我们将使用‘petal width’列上的apply方法:
df['wide petal'] = df['petal width'].apply(lambda v: 1 if v >= 1.3 else 0)
df
上面的代码生成以下输出:
df['petal area'] = df.apply(lambda r: r['petal length'] * r['petal width'],axis=1)
df
我们已经了解了如何处理列和行,但是假设您想要在DataFrame中的所有数据单元上执行一个函数; 使用applymap是正确的选择。 我们来看一个例子:
df.applymap(lambda v: np.log(v) if isinstance(v, float) else v)
现在让我们来看一个非常有用的操作,但是对于新的pandas用户来说,他们往往很难掌握DataFrame .groupby()方法。 为了说明最重要的功能,我们将逐步介绍一些示例。
groupby操作完全按照它所说的, 它根据您选择的一些类来分组数据。 让我们来看看使用我们的iris数据集的一个简单的例子。 我们将返回并重新导入我们的原始iris数据集并运行我们的第一个groupby操作:
df.groupby('class').mean()
df.groupby('class').describe()
df.groupby('petal width')['class'].unique().to_frame()
df.groupby('class')['petal width']\
.agg({
'delta': lambda x: x.max() - x.min(), 'max': np.max, 'min': np.min})
我们只谈到了groupby方法的功能, 还有很多东西需要学习,所以我建议你阅读下面的文档:http://pandas.pydata.org/pandas-docs/stable/。
我们了解了如何操作和准备数据以作为下一步建模的基础。 现在我们将继续讨论Python机器学习生态系统中的主要库。
Python拥有用于统计建模和机器学习的优秀的文档库。 我们将只介绍下面几个最流行的库。
我们将要介绍的第一个库是statsmodels库()。 Statsmodels是一个Python包,用于开发数据、评估模型和运行统计测试。 我们在这里使用它来建立setosa类的’sepal length’和’sepal width’之间关系的简单线性回归模型。
首先,让我们用散点图来直观地检查一下关系:
fig, ax = plt.subplots(figsize=(7,7))
ax.scatter(df['sepal width'][:50], df['sepal length'][:50])
ax.set_ylabel('Sepal Length')
ax.set_xlabel('Sepal Width')
ax.set_title('Setosa Sepal Width vs. Sepal Length', fontsize=14,y=1.02)
上面的代码生成以下输出:
import statsmodels.api as sm
y = df['sepal length'][:50]
x = df['sepal width'][:50]
X = sm.add_constant(x)
results = sm.OLS(y, X).fit()
print(results.summary())
上面的代码生成以下输出:
fig, ax = plt.subplots(figsize=(7,7))
ax.plot(x, results.fittedvalues, label='regression line')
ax.scatter(x, y, label='data point', color='r')
ax.set_ylabel('Sepal Length')
ax.set_xlabel('Sepal Width')
ax.set_title('Setosa Sepal Width vs. Sepal Length', fontsize=14,y=1.02)
ax.legend(loc=2)
上面的代码生成以下输出:
Scikit-learn是一个了不起的Python库,它提供了无与伦比的文档,旨在为数十种算法提供一致的API。 它建立在Python本身的核心组件之上,它本身就是建立在NumPy,SciPy,pandas和matplotlib的核心组件基础之上的。 以下是scikit-learn涵盖的一些领域:分类,回归,聚类,降维,模型选择和预处理。
我们将看几个例子。 首先,我们将使用我们的iris数据建立一个分类器,然后我们将看看如何使用scikit-learn的工具来评估我们的模型。
from sklearn.ensemble import RandomForestClassifier
from sklearn.cross_validation import train_test_split
clf = RandomForestClassifier(max_depth=5, n_estimators=10)
X = df.ix[:,:4]
y = df.ix[:,4]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.3)
clf.fit(X_train,y_train)
y_pred = clf.predict(X_test)
rf = pd.DataFrame(list(zip(y_pred, y_test)), columns=['predicted','actual'])
rf['correct'] = rf.apply(lambda r: 1 if r['predicted'] ==r['actual'] else 0, axis=1)
rf
上面的代码生成以下输出:
rf['correct'].sum()/rf['correct'].count()
这将生成以下输出:
在本书中,我们将使用最新的Python版本,截至编写时,这是3.5版本。 如果您使用的是Python 2.X版本,那么您将需要添加一个额外的导入语句来完成整数除法,就像在Python 3.X中一样。 如果没有这一行,你的准确性将被报告为0,而不是95%。 该行如下:
from future import division
这一奇怪的行是在导入实例化我们的分类器,在本例中,是一个随机森林分类器。 我们选择一个使用10个决策树的森林,每棵树的最大分裂深度为5。 这是为了避免过度配合,我们将在后面的章节中深入讨论。
接下来的两行创建我们的X矩阵和y向量。 我们原来的iris DataFrame包含四个特征:花瓣的宽度和长度以及萼片的宽度和长度。 这些特征被选中并成为我们独立的特征矩阵X.最后一列,iris类的名称,就成为我们的依赖y向量。
然后将这些传递给train_test_split方法,该方法将我们的数据转换为四个子集,X_train,X_test,y_train和y_test。 test_size参数设置为.3,这意味着我们的数据集的30%将被分配给X_test和y_test分区,其余的将被分配给训练分区X_train和y_train。
接下来,我们的模型是符合训练数据的。 在对模型进行处理之后,我们使用我们的测试数据在分类器上调用预测方法。 请记住,测试数据是分类器没有看到的数据。 这个预测的返回是一个预测标签的列表。 然后我们创建一个实际标签的DataFrame与预测的标签。 我们最后总结正确的预测,并除以实例总数,我们可以看到这给了我们一个非常准确的预测。 现在让我们来看看哪些特征给了我们最具辨别力或预测能力:
f_importances = clf.feature_importances_f_names = df.columns[:4]
f_std = np.std([tree.feature_importances_ for tree in clf.estimators_], axis=0)
zz = zip(f_importances, f_names, f_std)
zzs = sorted(zz, key=lambda x: x[0], reverse=True)
imps = [x[0] for x in zzs]
labels = [x[1] for x in zzs]
errs = [x[2] for x in zzs]
plt.bar(range(len(f_importances)), imps, color="r", yerr=errs,align="center")
plt.xticks(range(len(f_importances)), labels);
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
from sklearn.cross_validation import train_test_split
clf = OneVsRestClassifier(SVC(kernel='linear'))
X = df.ix[:,:4]
y = np.array(df.ix[:,4]).astype(str)
X_train, X_test, y_train, y_test = train_test_split(X, y,test_size=.3)
clf.fit(X_train,y_train)
y_pred = clf.predict(X_test)
rf = pd.DataFrame(list(zip(y_pred, y_test)), columns=['predicted','actual'])
rf['correct'] = rf.apply(lambda r: 1 if r['predicted'] ==r['actual'] else 0, axis=1)
rf
上面的代码生成以下输出:
rf['correct'].sum()/rf['correct'].count()
上面的代码生成以下输出:
将机器学习模型投入生产时有多种选择。 这在很大程度上取决于应用程序的性质。 部署可以包括从本地计算机上运行的cron作业到部署在Amazon EC2实例上的任何内容。
我们在这里不会详细介绍具体的实现,但我们将有机会在本书中深入探讨不同的部署示例。
在本章中,我们已经介绍了许多库,可以使用Python的包管理器来单独安装。 然而,我强烈建议你使用Continuum的Anaconda Python发行版的预装解决方案。 这是一个包含几乎所有需要的包和依赖项的可执行文件。 而且由于这个发行版是针对Python科学堆栈用户的,所以它本质上是一个完成的解决方案。
Anaconda还包括一个软件包管理器,使更新软件包成为一项简单的任务。 只需输入conda update ,库就会更新到最新的稳定版本。
在这一章中,我们介绍了数据科学/机器学习的工作流程。 我们看到了如何将数据逐步从数据采集一直贯穿到部署的各个阶段。 我们还介绍了Python科学堆栈中每个最重要的库的关键特性。
我们现在将学习这些知识和这些经验,并开始应用它们来创建独特和有用的机器学习应用程序。 在下一章中,我们将看到如何应用回归建模来找到一个便宜的公寓。 让我们开始吧!
备注:这是我在学习的时候对英文版的翻译,主要作为自己学习的参考,也避免下次再看的时候还需要重新翻译,翻译以机器翻译为主,会存在一些错误,先翻译出来了,后边的好多代码都没有亲自敲