第一章 Python机器学习生态系统

来源:互联网 发布:md3600f软件登录 编辑:程序博客网 时间:2024/05/06 16:23

第一章 Python机器学习生态系统

❀ 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科学堆栈中的一些库。
  在接下来的章节中,我们将逐步学习如何构建各种机器学习应用程序。 但在我们认真开始之前,我们将在本章的剩余部分中讨论这些关键库的功能,以及如何准备好您的环境以最好地利用它们。
  我们将在本章中介绍以下主题:
    ❀数据科学/机器学习工作流程
    ❀工作流程的每个阶段的库
    ❀设置您的环境

数据科学/机器学习工作流程

  构建机器学习应用程序虽然在很多方面与标准工程范例相似,但是在一个关键方面有所不同:需要将数据作为原材料。 数据项目的成功在很大程度上取决于您获得的数据的质量以及如何处理。 而且,由于使用数据属于数据科学领域,因此了解数据科学工作流程会很有帮助:
  

这里写图片描述

  这个过程按以下顺序进行:获取,检查和研究,清理和准备,建模,评估和最终部署。 往往需要循环回到先前的步骤,例如在检查和准备数据时,或在评估和建模时,但较高级别的过程可以被描述为上边的图所示。
  现在我们来详细讨论每一步。

获取(Acquisition)

  机器学习应用程序的数据拥有大量的来源; 它可能被作为一个CSV文件的电子邮件附件,它可能来自下载的服务器日志,或者可能需要建立一个自定义网页。 数据也可以有多种格式。 在大多数情况下,它将是基于文本的数据,但正如我们将要看到的,机器学习应用程序可以使用图像甚至视频文件轻松构建。 不管格式如何,一旦获得数据,理解数据中的内容至关重要。

检查和研究(Inspection and exploration)

  一旦数据被获取,下一步就是检查和研究它。 在这个阶段,主要目标是对数据进行完整性检查,而完成这一工作的最好方法是寻找不可能或极不可能的事情。 例如,如果数据具有唯一标识符,请检查确实只有一个; 如果数据是基于价格的,检查是否总是正的; 无论数据类型如何,检查最极端的情况。 他们合理吗? 一个好的做法是对数据进行一些简单的统计测试并将其可视化。 此外,有可能某些数据丢失或不完整。 在这个阶段注意到这一点是非常重要的,因为需要在清理和准备阶段对数据进行处理。 模型只与进入它们的数据一样好,所以正确使用这个步骤是至关重要的。

清理和准备(Cleaning and preparation)

  当所有的数据都是有序的时候,下一步就是把它放在一个适合建模的格式中。 这个阶段包含了一些过程,如过滤,聚合,输入和转换。 需要的操作类型将高度依赖于数据的类型以及所使用的库和算法的类型。 例如,对于基于自然语言的文本,所需的转换将与时间序列数据所需的转换大不相同。 在本书中,我们将看到许多这类转换的例子。

建模(Modeling)

  一旦数据准备完成,下一个阶段就是建模。 在这个阶段,选择一个合适的算法,并对数据进行建模。 在这个阶段有许多最佳实践,我们将会详细讨论它们,但是基本的步骤是把数据分成训练(training:不知道怎么翻译),测试和验证集。 这种分割数据的方式可能看起来很不合理 - 特别是当更多的数据通常会产生更好的模型时 - 但是我们将会看到,这样做可以让我们得到更好的反馈,了解模型在现实世界中的表现,并从建模的基本错误中阻止我们:过度拟合(overfitting)。

评估(Evaluation)

  一旦建立模型并进行预测,下一步就是了解模型如何实现这一点。 这是评估试图回答的问题。 有很多方法可以衡量一个模型的性能,而且它很大程度上依赖于数据类型和使用的模型,但是总的来说,我们试图回答模型的预测有多接近实际值。 有一些令人困惑的词汇,例如均方根误差,欧几里得距离和F1分数,但最终它们只是实际值与估计预测之间的距离的度量。

部署(Deployment)

  一旦模型的性能令人满意,下一步就是部署。 这可能需要多种形式,具体取决于用例,但是常见的情形是作为另一个更大的应用程序、定制的Web应用程序的一个功能,甚至只是一个简单的cron作业。

Python库和函数

  现在我们已经了解了数据科学工作流程中的每一个步骤,我们将在每个步骤中查看这些库中的一些有用的Python库和函数。

获取(Acquisition)

  因为访问数据的最常用方法之一是通过RESTful API,所以需要注意的一个库是Python请求库(Requests库)(http://www.python-requests.org/en/latest/)。 为人们提供HTTP,它提供了一个干净和简单的方式来与API交互。
  让我们来看看使用请求( Requests)从GitHub的API下拉数据的示例交互。 在这里,我们将调用API并请求一个主角存储库列表:

import requestsr = requests.get(r"https://api.github.com/users/acombs/starred")r.json()

  这将返回主角的所有存储库列表及其属性的JSON文档。 这是前面调用的输出的一个片段:

这里写图片描述

  requests库有很多功能,但是我建议你在上面提供的链接中查看文档。

检查(Inspection)

  由于检查数据是机器学习应用程序开发的关键步骤,现在我们将深入了解几个库,这些库将为我们完成这项任务。

Jupyter笔记本(The Jupyter notebook)

  有一些库将有助于简化数据检查过程。 第一个是带有IPython的Jupyter笔记本(http://ipython.org/)。 这是一个完善的交互式计算环境,非常适合数据挖掘。 与大多数开发环境不同,Jupyter笔记本是一个基于Web的前端(IPython内核),分为单独的代码块或单元格。 根据需要,单元格可以单独或同时运行。 这允许开发人员运行场景,查看输出结果,然后逐步浏览代码,进行调整并查看结果更改,而不用离开笔记本。 以下是Jupyter笔记本中的示例交互:
  

这里写图片描述 


  请注意,我们在这里做了很多事情,不仅与IPython后端交互,还与终端外壳交互。 这个特定的实例运行一个Python 3.5内核,但是如果你喜欢的话,你可以轻松地运行一个Python 2.X内核。 在这里,我们已经导入了Python os库并且调用了一个查找当前工作目录(cell#2),你可以看到它是输入代码单元下面的输出。 然后,我们使用单元格#3中的os库更改目录,但之后停止使用os库,并开始在单元格#4中使用基于Linux的命令。 这是通过添加! 在单元格前面。 在单元格#6中,您可以看到我们甚至能够将shell输出保存到Python变量(file_two)。 这是一个很好的功能,使文件操作一个简单的任务。
  现在让我们来看看使用笔记本的一些简单的数据操作。 这也是我们第一次介绍另外一个不可或缺的库,pandas。  

Pandas

  Pandas是一个非常好的数据分析工具。参照Pandas文件(http://pandas.pydata.org/pandas-docs/version/0.17.1/):

它有更广泛的目标,即成为任何语言中最强大、最灵活的开源数据分析/操作工具。

  如果它还没有达到这个要求,离目标也不会太远了。 现在我们来看看:

import osimport pandas as pdimport requestsPATH = 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’=’分类’

'萼片长度','萼片宽度','花瓣长度','花瓣宽度','分类'

  正如前面的代码和屏幕截图所看到的,我们已经从https://archive.ics.uci.edu/ml/datasets/Iris下载了一个经典的机器学习数据集iris.data,并写入到iris目录。 这实际上是一个CSV文件,使用pandas,我们打开并读取文件。 因为这个特定的文件没有标题行,我们还添加了列名。 如果文件包含一个标题行,pandas会自动解析并反映这个。 与其他CSV库相比,pandas使这个操作变的简单。
  解析文件只是这个库的一个小功能。 要使用适合单个机器的数据集,pandas是最好的工具。 它有点像Excel。 像流行的电子表格程序一样,操作的基本单位是表格形式的列和行数据。 在pandas的术语中,数据列是Series,表是DataFrame。
  使用前面截图所示的相同的iris DataFrame表,让我们来看看几个常见的操作:  

df['sepal length']

这里写图片描述

  第一个操作就是通过引用它的列名来从DataFrame中选择一个列。 另一种我们可以执行这种数据分割的方法是使用.ix [行,列]符号。 我们用这个表示法来选择前两列和前四行:

df.ix[:3,:2]

  上面的代码生成以下输出:
  

这里写图片描述

  使用.ix标记和Python列表切片语法,我们可以选择这个DataFrame表的一个切片。 现在让我们把它放在一个缺口,并使用列表迭代器来选择宽度列:

df.ix[:3, [x for x in df.columns if 'width' in x]]

  上面的代码生成以下输出:
  

这里写图片描述

  我们在这里所做的是创建一个列表,它是所有列的子集。 前面的df.columns返回所有列的列表,我们的迭代使用条件语句来只选择标题中具有width的列。 显然,在这种情况下,我们可以轻松地在列表中输入我们想要的列,这显示了处理更大的数据集时的能力。
  我们已经看到了如何根据DataFrame表中的位置来选择切片,但现在让我们看看另一种选择数据的方法。 这次我们将根据一些特定的条件选择数据的一个子集。 我们首先列出所有可用的唯一的class,然后选择其中一个(简单的说就是去除一列的重复值):

df['class'].unique()

  上面的代码生成以下输出:
  

这里写图片描述

df[df['class']=='Iris-virginica']

  上面的代码生成以下输出:
 

 这里写图片描述
 
  在最右边的列中,我们可以看到我们的DataFrame表只包含Iris-virginica类的数据。 实际上,DataFrame表的大小现在是50行,文件原始数据有150行:

df.count()

  

这里写图片描述

df[df['class']=='Iris-virginica'].count()

  

这里写图片描述

  我们也可以看到左边的索引保留了原始的行号。 我们现在可以将这些数据保存为一个新的DataFrame并重置索引,如下面的代码和屏幕截图所示:

virginica = df[df['class']=='Iris-virginica'].reset_index(drop=True)virginica

  

这里写图片描述

  我们通过在一列上添加条件来选择数据; 让我们现在添加更多的条件。 我们将回到我们原来的DataFrame表并使用两个条件选择数据:

df[(df['class']=='Iris-virginica')&(df['petal width']>2.2)]

  

这里写图片描述

  DataFrame表,现在只包含来自花瓣宽度大于2.2的Iris-virginica类的数据。
  现在让我们使用pandas从我们的Iris数据集中快速获得一些描述性统计数据:

df.describe()

  

这里写图片描述

  通过调用DataFrame 表的.describe()方法,我们收到了每个相关列的描述性统计信息的细目。 (请注意,class 被自动删除,因为它与此无关。)
  如果我们想要更细化的信息,我们也可以传递自定义百分比:

df.describe(percentiles=[.20,.40,.80,.90,.95])

  

这里写图片描述

  接下来,我们来检查这些功能之间是否有任何关联。 这可以通过在DataFrame上调用.corr()来完成:

df.corr()

  

这里写图片描述

  默认返回每个行 - 列对的Pearson相关系数。 这可以通过传递方法参数来切换到肯德尔或者斯皮尔曼的等级相关系数(例如, .corr(method=”spearman”) or .corr(method=”kendall”))

可视化(Visualization)

  到目前为止,我们已经看到如何选择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( 安斯科姆)四重奏的一部分,它们是为了说明视觉数据检查的重要性而刻意创建的。 每个系列都绘制在下图中:
  

这里写图片描述

  安斯库姆(Anscombe)四重奏取自:https://en.wikipedia.org/wiki/Anscombe%27s_quartet
  显然,我们不会把这些数据集看作是完全相同的。 所以,现在我们理解了可视化的重要性,让我们来看看一对有用的Python库。

matplotlib库

  我们要看的第一个库是matplotlib。 它是Python绘图库之祖。 最初是为了模拟MATLAB的绘图功能而创建的,它随着自身功能的不断变化而成为一个功能齐全的库。 对于那些没有使用MATLAB背景的人来说,很难理解所有这些部分是如何协同工作一起来创建图形的。
  我们将把这些部分分解为逻辑组件,以便了解发生了什么事情。 在深入研究matplotlib之前,让我们设置我们的Jupyter笔记本,让我们看到我们的图形。 要做到这一点,我们需要将以下几行添加到我们的import语句中:

import matplotlib.pyplot as pltplt.style.use('ggplot')%matplotlib inlineimport 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)

  上面的代码生成以下输出:
  

这里写图片描述

  即使在这个简单的例子中也有很多需要学习,但我们将逐行分解。 第一行创建宽度为6“,高度为4”的单个子图。 然后我们通过调用.hist()并传入我们的数据,从我们的iris数据DataFrame表绘制花瓣宽度的直方图。 我们也在这里设置图的颜色为黑色。 接下来的两行分别在我们的y轴和x轴上放置标签,最后一行为我们的图形设置标题。 我们使用y参数调整标题的相对于图表顶部y的位置,并在默认情况下稍微增加字体大小。 这给我们一个花瓣宽度数据的很好的直方图。 现在我们来扩展这个,并为我们的iris数据集的每一列生成直方图:

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()

  前面代码的输出显示在以下屏幕截图中:
  

这里写图片描述

  显然,这并不是最有效的代码方式,但是演示matplotlib是如何工作是非常有用的。 请注意,我们现在有四个子图,而不是我们在第一个示例中使用的单个子图对象ax,它们是通过现在的ax数组访问的。 代码的新增内容是调用plt.tight_layout(); 这种方法会很好地调整子图自动避免拥挤。
  现在我们来看看matplotlib中的其他一些类型的图。 一个有用的是散点图。 在这里,我们将绘制花瓣宽度与花瓣长度的散点图:

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')

  上面的代码生成以下输出:
  

这里写图片描述

  基于这个简单的线图,我们已经可以看到每个类都有不同的长度集合,记住我们的样本数据集有50个有序的例子。 这告诉我们,花瓣长度可能是区分类之间的一个有用的特征。
  让我们看一下matplotlib库中的最后一种图表,即条形图。 这也许是你们会看到的最常见的图表之一。 在这里,我们将为三类irises类的每个特性绘制一个条形图,并使其更加有趣,我们将使它成为一个堆叠的条形图,其中有一些附加的matplotlib特性:

fig,ax=plt.subplots(figsize=(6,6))bar_width=.8labels=[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'])

  上面的代码生成以下输出:

这里写图片描述

  要生成条形图,我们需要将x和y值传递给.bar()方法。在这种情况下,x值将只是我们感兴趣的特征长度的一个数组,在这里是四个,或者DataFrame表中的每一列都有一个。 np.arange()函数函数是生成此函数的一种简单方法,但我们可以手动输入这个数组。因为我们不想让x轴显示这个1到4,我们调用.set_xticklabels()方法并传入我们要显示的列名。要正确排列x标签,我们还需要调整标签的间距;这就是为什么我们将xticks设置为x加上bar_width的一半大小,我们之前也设置了0.8。 y值来自每个类的每个特性的均值。然后我们通过调用.bar()来绘制每个图。重要的是要注意,我们传递每个系列的底部参数,将其最小y点设置为等于其下面系列的最大y点。这创建了堆叠的效果。最后,我们添加一个描述每个系列的图例。这些名称按照从上到下排列的顺序插入到图例列表中。

seaborn库 

  我们将看到的下一个可视化库称为seaborn(http://stanford.edu/mwaskom/software/seaborn/index.html)。 这是一个专为统计可视化而创建的库。 实际上,它是使用pandas数据框的最佳选择,其中列是特征,行是观察值。 这种DataFrame表的风格称为整洁数据,它是机器学习应用程序最常见的形式。
  现在我们来看看seaborn的力量:

import seaborn as snssns.pairplot(df, hue="class")

  用这两行代码,我们得到以下输出:
  

这里写图片描述

  刚刚详细介绍了matplotlib的复杂细节,我们很简单的就生成了这个图。 我们所有的功能都是相互对立的,只用两行代码进行正确的标记。 当seaborn使得这些类型的可视化如此简单的时候,学习matplotlib是一种浪费吗? 幸运的是,seaborn是建立在matplotlib之上的。 实际上,我们可以使用我们所学的关于matplotlib的所有东西来修改和使用seaborn。 我们来看看另一个可视化:

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()

  上面的代码生成以下输出:
  

这里写图片描述

  在这里,我们为四个特征中的每一个生成了小提琴图。小提琴的曲线图显示了这些特征的分布。 例如,我们可以很容易地看到,iris的花瓣长度高度聚集在1和2厘米之间,而iris - 弗吉尼亚从4到7厘米更为分散。 我们也可以注意到,我们已经使用了构建matplotlib图形时使用的很多相同的代码。 主要区别在于之前添加了sns.plot()调用代替ax.plot()调用。 我们还在所有子图上添加了一个标题,而不是用fig.suptitle()方法分别添加。另一个值得注意的添加是在每个子块上的迭代,以改变xticklabel的旋转。 我们调用ax.flat(),然后遍历每个子图轴,使用.setp()来设置一个特定的属性。 这可以防止我们必须单独输入ax [0] [0] … ax [1] [1],并像在之前的matplotlib子图代码中那样设置属性。
  我们在这里使用的图形是一个很好的开始,但是可以使用matplotlib和seaborn生成数百种图形样式。 我强烈建议您花些时间深入研究这两个库的文档。

准备(preparation)

  我们已经学习了很多关于检查数据的知识,但现在让我们继续学习如何处理和操作数据。 在这里,我们将学习pandas的
Series.map(),Series.apply(),DataFrame.apply(),DataFrame.applymap()和DataFrame.groupby()方法。 这对于处理数据非常有用,在特性工程的机器学习方面尤其有用,这个概念我们将在后面的章节中详细讨论。

Map

  在我们的例子中用到了一系列的map方法,所以,我们将使用它来转换我们的DataFrame表的一列,记住它只是一个pandas系列。 假设我们类的名稍微长一点,我们想用我们的特殊的‘三字’编码系统对它们进行编码。 我们将使用带有Python字典的map方法来实现这一点。 我们将替换每一个iris数据类型:

df['class'] = df['class'].map({'Iris-setosa': 'SET', 'Iris-virginica':'VIR', 'Iris-versicolor': 'VER'})df

  

这里写图片描述

  让我们看看我们在这里做了什么。 我们在现有类列的每个值上运行map方法。当在Python字典中找到每个值时,它被添加到return系列中。 我们将这个return序列分配给相同的类名,所以它取代了我们原来的’class’列。 如果我们选择了一个不同的名称,比如简短的类名,那么这个列就会被添加到DataFrame表中,然后我们将会得到原始的类列和新的短列类。(简单说就是将长的类名替换成了短的类名)
  我们可以将另一个系列或函数传递给map方法,以在一个列上执行这个转换,但是这也可以通过apply方法实现,我们将在下一篇文章中介绍它。字典功能是map方法特有的,选择map最常见的原因是用于单列转换。 现在我们来看看apply方法。

Apply

  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

  上面的代码生成以下输出:
  

这里写图片描述

  这里发生了一些事情。 让我们逐步分析。 首先,我们能够使用列选择将我们要创建的列名添加到DataFrame的一个新的列,在本例中是‘petal width’。 我们设置这个新列设置为apply方法的输出。 在这里,我们使用‘petal width’列,它在‘petal width’列中返回相应的值。 apply方法通过遍历‘petal width’列的每个值来运行。 如果该值大于或等于1.3,则函数返回1; 否则,它返回0。 这种类型的转换是机器学习中一个相当常见的特征工程转换,所以应该熟悉如何运用它。

df['petal area'] = df.apply(lambda r: r['petal length'] * r['petal width'],axis=1)df

  

这里写图片描述

  请注意,我们在整个DataFrame上调用调用了apply,而不是在列上,因为在整个DataFrame上调用了apply,所以我们传递了axis = 1来告诉pandas我们想要按行应用这个函数。 如果我们通过axis = 0,那么函数将按列操作。 在这里,每列都按顺序处理,我们选择将’petal length’和’petal width’列的值相乘。 由此产生的列成为DataFrame中的’petal area’列。 这种功能和灵活性使pandas成为数据操作不可或缺的工具。

applymap

  我们已经了解了如何处理列和行,但是假设您想要在DataFrame中的所有数据单元上执行一个函数; 使用applymap是正确的选择。 我们来看一个例子:

df.applymap(lambda v: np.log(v) if isinstance(v, float) else v)

  

这里写图片描述

  在这里,我们调用DataFrame上的applymap以获取每个值的日志(np.log(),如果该值是浮点类型的实例,则使用numpy库来返回此值)。当值分别是字符串和整数值时,这种类型检查防止返回一个错误或一个浮点类型的‘class’或‘wide petal’列 。 applymap的常见用法是基于满足某些条件标准来转换或格式化每个单元格。

Groupby

  现在让我们来看一个非常有用的操作,但是对于新的pandas用户来说,他们往往很难掌握DataFrame .groupby()方法。 为了说明最重要的功能,我们将逐步介绍一些示例。
  groupby操作完全按照它所说的, 它根据您选择的一些类来分组数据。 让我们来看看使用我们的iris数据集的一个简单的例子。 我们将返回并重新导入我们的原始iris数据集并运行我们的第一个groupby操作:

df.groupby('class').mean()

  

这里写图片描述

  每个类的数据被分区,并提供每个功能的平均值。 现在让我们更进一步,对每个类都进行全面的描述性统计:

df.groupby('class').describe()

  

这里写图片描述

  现在我们可以看到按类进行的分类。 现在让我们来看看我们可以执行的其他一些groupby操作。 我们之前看到,‘petal length and width’在类别之间有一些比较清晰的界限, 让我们看看我们如何使用groupby来查看这个:

df.groupby('petal width')['class'].unique().to_frame()

  

这里写图片描述

  在这种情况下,我们根据与之关联的’petal width’对每个不同的类分组。 这是一个可以管理的度量值,但是如果它变得更大,我们可能需要将度量放进方括号。 正如我们以前所见,这可以用apply方法来完成。
  现在让我们来看看一个自定义的聚合函数:

df.groupby('class')['petal width']\.agg({'delta': lambda x: x.max() - x.min(), 'max': np.max, 'min': np.min})

  

这里写图片描述

  在这段代码中,我们使用函数np.max和np.min以及一个返回最大’petal width’减去最小’petal width’的lambda函数按类别对’petal width’进行分组。 (这两个np函数来自numpy库)。这些函数以字典的形式传递给.agg()方法,以便返回一个DataFrame,其中键为列名。 可以运行单个函数,也可以将函数作为列表传递,但列名称的信息量较少。

  我们只谈到了groupby方法的功能, 还有很多东西需要学习,所以我建议你阅读下面的文档:http://pandas.pydata.org/pandas-docs/stable/。

  我们了解了如何操作和准备数据以作为下一步建模的基础。 现在我们将继续讨论Python机器学习生态系统中的主要库。

建模和评估(Modeling and evaluation)

  Python拥有用于统计建模和机器学习的优秀的文档库。 我们将只介绍下面几个最流行的库。

Statsmodels

  我们将要介绍的第一个库是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)

  上面的代码生成以下输出:
  

这里写图片描述

  我们可以看到,似乎有一个正线性关系,就是说,随着萼片宽度(Sepal Width)的增加,萼片长度(‘Sepal Length’)也是如此。 我们接下来使用statsmodels对数据建立线性回归模型来评估这种关系的强度:

import statsmodels.api as smy = df['sepal length'][:50]x = df['sepal width'][:50]X = sm.add_constant(x)results = sm.OLS(y, X).fit()print(results.summary())

  上面的代码生成以下输出:
  

这里写图片描述

  前面的屏幕截图显示了我们的简单回归模型的结果。 由于这是一个线性回归,因此模型采用Y = B0 + B1X的格式,其中B0是截距,B1是回归系数。 在这里,公式将是:‘Sepal Length’= 2.6447 + 0.6909 *‘Sepal Width’。 我们还可以看到模型的R2是一个相当可观的0.558,而p值(Prob)非常重要——至少对于这个类来说是如此。
  现在我们使用结果对象来绘制我们的回归线:

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)

  上面的代码生成以下输出:
  

这里写图片描述

  通过绘制results.fittedvalues,我们可以从我们的模型得到相应的回归直线。
  还有一些其他的统计函数和测试在statsmodels包中,我建议你去探索它们。 这是Python中标准统计建模的一个非常有用的软件包。 现在让我们来看看Python机器学习包,scikit-learn。

Scikit-learn

  Scikit-learn是一个了不起的Python库,它提供了无与伦比的文档,旨在为数十种算法提供一致的API。 它建立在Python本身的核心组件之上,它本身就是建立在NumPy,SciPy,pandas和matplotlib的核心组件基础之上的。 以下是scikit-learn涵盖的一些领域:分类,回归,聚类,降维,模型选择和预处理。
  我们将看几个例子。 首先,我们将使用我们的iris数据建立一个分类器,然后我们将看看如何使用scikit-learn的工具来评估我们的模型。

from sklearn.ensemble import RandomForestClassifierfrom sklearn.cross_validation import train_test_splitclf = 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()

  这将生成以下输出:
  

这里写图片描述

  在前面的几行代码中,我们构建、训练并测试了一个分类器,它在我们的虹膜数据集上有95%的准确率。 让我们查看每个步骤。 在前两行代码中,我们做了一些导入;前两个来自scikit- learn,谢天谢地,它被缩短为import语句的sklearn。 第一个导入是一个随机森林分类器,第二个是将数据分成训练和测试队列的模块。 由于多种原因,这种数据划分对于构建机器学习应用程序至关重要。 我们将在后面的章节中介绍这一点,但现在已经足够说明这是必须的了。 这个train_test_split模块也会打乱我们的数据,这也是很重要的,因为订单中包含的信息可能会影响您的实际预测

  在本书中,我们将使用最新的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);

这里写图片描述

  正如我们所预期的那样,基于我们早期的视觉分析,花瓣的长度和宽度在区分iris类别时有更多的区分能力。这些数字究竟从何而来? 随机森林有一个名为.feature_importances_的方法,它返回要在树叶处分割的特征的相对强度。如果一个特性能够持续且清晰地将一个组划分为不同的类,那么它将具有很高的特性。 这个数字总是1。 正如你会注意到的那样,我们已经包含了标准偏差,这有助于说明每个特征的一致性。 这是通过对每10棵树的每一个特征进行特征重要性和计算标准偏差来生成的。
  现在让我们看看使用scikit-learn的另一个例子。 我们现在将切换分类器并使用支持向量机(SVM):

from sklearn.multiclass import OneVsRestClassifierfrom sklearn.svm import SVCfrom sklearn.cross_validation import train_test_splitclf = 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()

  上面的代码生成以下输出:
  

这里写图片描述

  在这里,我们交换了一个支持向量机而不改变我们的任何代码。 唯一的变化是与SVM的导入相关的变化,而不是随机森林,以及实例化分类器的那一行。 (需要对y标签格式进行一个小改动,因为SVM不能像随机森林分类器那样将其解释为NumPy字符串)。
  这只是 scikit-learn能力的一小部分,但它应该能够说明这个强大的工具对于机器学习应用程序的功能和作用。 还有一些额外的机器学习库,我们在这里没有机会讨论,但会在后面的章节中讨论,但是我强烈建议如果这是您第一次使用机器学习库,并且您想要一个强大的通用工具,scikit-learn是你的选择。

部署(Deployment)

  将机器学习模型投入生产时有多种选择。 这在很大程度上取决于应用程序的性质。 部署可以包括从本地计算机上运行的cron作业到部署在Amazon EC2实例上的任何内容。
  我们在这里不会详细介绍具体的实现,但我们将有机会在本书中深入探讨不同的部署示例。

设置你的机器学习环境

  在本章中,我们已经介绍了许多库,可以使用Python的包管理器来单独安装。 然而,我强烈建议你使用Continuum的Anaconda Python发行版的预装解决方案。 这是一个包含几乎所有需要的包和依赖项的可执行文件。 而且由于这个发行版是针对Python科学堆栈用户的,所以它本质上是一个完成的解决方案。
  Anaconda还包括一个软件包管理器,使更新软件包成为一项简单的任务。 只需输入conda update ,库就会更新到最新的稳定版本。

总结

  在这一章中,我们介绍了数据科学/机器学习的工作流程。 我们看到了如何将数据逐步从数据采集一直贯穿到部署的各个阶段。 我们还介绍了Python科学堆栈中每个最重要的库的关键特性。
  我们现在将学习这些知识和这些经验,并开始应用它们来创建独特和有用的机器学习应用程序。 在下一章中,我们将看到如何应用回归建模来找到一个便宜的公寓。 让我们开始吧!

备注:这是我在学习的时候对英文版的翻译,主要作为自己学习的参考,也避免下次再看的时候还需要重新翻译,翻译以机器翻译为主,会存在一些错误,先翻译出来了,后边的好多代码都没有亲自敲

原创粉丝点击