Sklearn-机器学习快速启动指南-全-
Sklearn 机器学习快速启动指南(全)
原文:
annas-archive.org/md5/88cc1599da7fc47c30a7a809cfd13bb1译者:飞龙
前言
本书的基本目标是帮助读者快速部署、优化和评估 scikit-learn 提供的各种机器学习算法,以灵活的方式进行操作。
读者将学习如何部署有监督的机器学习算法,如逻辑回归、k 近邻、线性回归、支持向量机、朴素贝叶斯以及基于树的算法,来解决分类和回归机器学习问题。
读者还将学习如何部署无监督机器学习算法,如 k 均值算法,来将未标记的数据聚类成不同的组。
最后,读者将会学习不同的技术,用于直观地解释和评估他们所构建的算法的性能。
本书的适用对象
本书适合数据科学家、软件工程师以及对机器学习感兴趣并且有 Python 基础的人,他们希望通过使用 scikit-learn 框架理解、实现和评估各种机器学习算法。
本书的内容
第一章,引入 scikit-learn 机器学习,简要介绍了不同类型的机器学习及其应用。
第二章,使用 K 近邻预测类别,介绍了如何使用 k 近邻算法,并在 scikit-learn 中实现它来解决分类问题。
第三章,使用逻辑回归预测类别,解释了在 scikit-learn 中使用逻辑回归算法解决分类问题时的原理与实现。
第四章,使用朴素贝叶斯和支持向量机预测类别,解释了朴素贝叶斯和线性支持向量机算法在解决 scikit-learn 中的分类问题时的原理与实现。
第五章,使用线性回归预测数值结果,解释了在 scikit-learn 中使用线性回归算法解决回归问题时的原理与实现。
第六章,使用树模型进行分类和回归,解释了决策树、随机森林以及提升和集成算法在解决 scikit-learn 中的分类和回归问题时的原理与实现。
第七章,使用无监督机器学习进行数据聚类,解释了在 scikit-learn 中使用 k 均值算法解决无监督问题时的原理与实现。
第八章,性能评估方法,包含了有监督和无监督机器学习算法的可视化性能评估技术。
要充分利用本书
要充分利用本书:
-
假设您具备基础的 Python 知识。
-
Jupyter Notebook 是首选的开发环境,但不是必需的。
下载示例代码文件
您可以从您的账户下载本书的示例代码文件,网址是www.packt.com。如果您在其他地方购买了本书,您可以访问www.packt.com/support并注册,让我们将文件直接发送到您的邮箱。
您可以通过以下步骤下载代码文件:
-
请登录或注册www.packt.com。
-
选择“支持”标签。
-
点击“代码下载与勘误”。
-
在搜索框中输入书名并按照屏幕上的指示操作。
下载文件后,请确保使用最新版本的软件解压或提取文件夹:
-
WinRAR/7-Zip for Windows
-
Zipeg/iZip/UnRarX for Mac
-
7-Zip/PeaZip for Linux
本书的代码包也托管在 GitHub 上,地址是github.com/PacktPublishing/Machine-Learning-with-scikit-learn-Quick-Start-Guide。如果代码有更新,将在现有的 GitHub 仓库中进行更新。
我们的其他代码包也可以在github.com/PacktPublishing/找到。快去看看吧!
代码实战
访问以下链接查看代码运行的视频:
使用的约定
本书中使用了多种文本约定。
CodeInText:表示文本中的代码字、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 账户名。举个例子:“将下载的WebStorm-10*.dmg磁盘镜像文件作为另一磁盘挂载到系统中。”
一段代码如下设置:
from sklearn.naive_bayes import GaussianNB
#Initializing an NB classifier
nb_classifier = GaussianNB()
#Fitting the classifier into the training data
nb_classifier.fit(X_train, y_train)
#Extracting the accuracy score from the NB classifier
nb_classifier.score(X_test, y_test)
警告或重要说明会以此形式出现。
小贴士和技巧以这种形式出现。
与我们联系
我们欢迎读者的反馈。
一般反馈:如果您对本书的任何部分有疑问,请在邮件主题中注明书名,并通过customercare@packtpub.com联系我们。
勘误:尽管我们已尽一切努力确保内容的准确性,但错误难免发生。如果您在本书中发现错误,我们将感激您向我们报告。请访问www.packt.com/submit-errata,选择您的书籍,点击“勘误提交表格”链接并填写相关信息。
盗版:如果您在互联网上发现我们作品的任何非法副本,无论形式如何,我们将感激您提供相关的地址或网站名称。请通过copyright@packt.com与我们联系,并附上相关资料的链接。
如果您有兴趣成为作者:如果您在某个领域具有专业知识,并且有兴趣撰写或贡献书籍,请访问authors.packtpub.com。
评论
请留下评论。阅读并使用本书后,为什么不在您购买书籍的网站上留下评论呢?潜在读者可以看到并参考您客观的意见来做出购买决策,我们在 Packt 也能了解您对我们产品的看法,而我们的作者也可以看到您对他们书籍的反馈。谢谢!
如需了解更多关于 Packt 的信息,请访问packt.com。
第一章:使用 scikit-learn 介绍机器学习
欢迎来到使用 scikit-learn 的机器学习世界。我很高兴你选择了这本书来开始或进一步提升你在广阔的机器学习领域的知识。机器学习有时可能会让人感到不知所措,这部分原因是市场上有大量可用的工具。这本书将把工具选择的过程简化为一个——scikit-learn。
如果要用一句话告诉你这本书能为你做什么,那就是——本书提供了可以实施的管道,以解决广泛的机器学习问题。
正如这句话所暗示的,你将学习如何使用一些在行业和专业竞赛中广泛使用的最流行的算法构建端到端的机器学习管道,例如 Kaggle。
然而,在本介绍性章节中,我们将讨论以下主题:
-
机器学习简要介绍
-
什么是 scikit-learn?
-
安装 scikit-learn
-
你将在本书中学习实现的 scikit-learn 算法
现在,让我们开始这段有趣的机器学习之旅,使用 scikit-learn!
机器学习简要介绍
机器学习已经引起了广泛关注——从埃隆·马斯克担心无监管人工智能在社会中的角色,到马克·扎克伯格持有与马斯克相反的看法。
那么,机器学习究竟是什么呢?简单来说,机器学习是一组方法,可以在数据中发现模式,并利用这些模式进行未来预测。机器学习在多个行业中找到了巨大的价值,从金融到医疗保健。这意味着对具备机器学习领域技能的人才有了更高的需求。
广义上讲,机器学习可以分为三种主要类型:
-
监督学习
-
无监督学习
-
强化学习
Scikit-learn 旨在解决与监督学习和无监督学习相关的问题,目前不支持强化学习。
监督学习
监督学习是一种机器学习形式,其中我们的数据附带一组标签或一个数字化的目标变量。这些标签/类别通常属于一个特征/属性,通常称为 目标变量。例如,你的数据中的每一行可能属于 健康 或 不健康 的类别。
给定一组特征,例如体重、血糖水平和年龄,我们可以使用监督机器学习算法来预测这个人是否健康。
在下面的简单数学表达式中,S 是监督学习算法,X 是输入特征集,例如体重和年龄,Y 是目标变量,标签为 健康 或 不健康:

虽然有监督机器学习是最常用的机器学习类型,在 scikit-learn 和行业中也有广泛应用,但大多数数据集通常没有预定义的标签。无监督学习算法首先用于将没有标签的数据聚类成不同的组,然后我们可以为这些组分配标签。此内容将在下一个章节中详细讨论。
无监督学习
无监督学习是一种机器学习形式,算法试图在没有结果/目标变量的数据中检测/发现模式。换句话说,我们没有带有预先存在标签的数据。因此,算法通常会使用诸如距离等度量标准,根据数据之间的接近程度将它们分组。
如前一节所讨论的,您在现实世界中遇到的大多数数据将不会带有一组预定义的标签,因此,只会有一组输入特征而没有目标属性。
在以下简单的数学表达式中,U 是无监督学习算法,而 X 是一组输入特征,如体重和年龄:

给定这些数据,我们的目标是创建可以标记为 健康 或 不健康 的组。无监督学习算法将使用诸如距离之类的度量标准来识别一组点之间的接近程度以及两个这样的组之间的距离。然后,算法将继续将这些组聚类成两个不同的组,如下图所示:

将两个组聚类在一起
什么是 scikit-learn?
Scikit-learn 是一个免费且开源的软件,帮助你解决有监督和无监督的机器学习问题。该软件完全用 Python 编写,并利用 Python 提供的最流行的库,主要包括 NumPy 和 SciPy。
scikit-learn 非常受欢迎的主要原因在于,世界上大多数最流行的机器学习算法,一旦你了解核心流程,就能非常快速地以即插即用的方式实现。另一个原因是,像 逻辑回归 和 支持向量机 这样的流行分类算法是用 Cython 编写的。Cython 用来提供这些算法 类似 C 语言 的性能,从而使得在这个过程中使用 scikit-learn 非常高效。
安装 scikit-learn
您可以通过两种方式在个人设备上安装 scikit-learn:
-
使用 pip 方法
-
使用 Anaconda 方法
pip 方法可以在 macOS/Linux 终端或 Windows PowerShell 中实现,而 Anaconda 方法则可以在 Anaconda 提示符中使用。
在这两种安装方法之间进行选择非常简单:
-
如果您希望所有常见的 Python 数据科学包都安装在同一个环境中,Anaconda 方法是最佳选择
-
如果您希望从头开始为 scikit-learn 构建自己的环境,pip 方法是最佳选择(适用于 Python 高级用户)
本书将使用 Python 3.6 版本展示所有代码,除非另有说明。
Pip 方法
在安装 scikit-learn 之前,您的设备需要安装一些包。具体如下:
-
NumPy:版本 1.8.2 或更高
-
SciPy:版本 0.13.3 或更高
可以使用以下命令通过 pip 方法安装:
pip3 install NumPy
pip3 install SciPy
接下来,我们可以使用以下代码安装 scikit-learn:
pip3 install scikit-learn
此外,如果您已经在设备上安装了 scikit-learn 并且只想将其升级到最新版本,可以使用以下代码:
pip3 install -U scikit-learn
本书中实现的 scikit-learn 版本是 0.19.1。
Anaconda 方法
如果您是通过 Anaconda 分发版安装了 Python,可以通过在 Anaconda 提示符中使用以下代码安装 scikit-learn:
第一步是安装依赖项:
conda install NumPy
conda install SciPy
接下来,我们可以使用以下代码安装 scikit-learn:
conda install scikit-learn
此外,如果您已经使用 Anaconda 分发版安装了 scikit-learn,您可以通过在 Anaconda 提示符中使用以下代码将其升级到最新版本:
conda update scikit-learn
在升级或卸载已通过 Anaconda 安装的 scikit-learn 时,切勿使用 pip 方法,因为这样做很可能导致升级失败或无法删除所有所需文件。请始终使用 pip 方法或 Anaconda 方法,以保持一致性。
额外的包
在本节中,我们将讨论我们将在本书中安装的、与 scikit-learn 无关的包。
Pandas
要安装 Pandas,您可以使用 pip 方法或 Anaconda 方法,如下所示:
Pip 方法:
pip3 install pandas
Anaconda 方法:
conda install pandas
Matplotlib
要安装 matplotlib,您可以使用 pip 方法或 Anaconda 方法,如下所示:
Pip 方法:
pip3 install matplotlib
Anaconda 方法:
conda install matplotlib
树
要安装 tree,您可以使用 pip 方法或 Anaconda 方法,如下所示:
Pip 方法:
pip3 install tree
Anaconda 方法:
conda install tree
Pydotplus
要安装 pydotplus,您可以使用 pip 方法或 Anaconda 方法,如下所示:
Pip 方法:
pip3 install pydotplus
Anaconda 方法:
conda install pydotplus
图像
要安装图像,您可以使用 pip 方法或 Anaconda 方法,如下所示:
Pip 方法:
pip3 install Image
Anaconda 方法:
conda install Image
您将使用 scikit-learn 实现的算法
本书中您将学习的算法大致分为以下两类:
-
有监督学习算法
-
无监督学习算法
有监督学习算法
有监督学习算法可用于解决分类和回归问题。本书中,你将学习如何实现一些最受欢迎的有监督机器学习算法。受欢迎的有监督机器学习算法在工业和研究中得到了广泛应用,帮助我们解决了各个领域的广泛问题。以下是这些有监督学习算法:
-
线性回归:这种有监督学习算法用于预测连续的数值结果,如房价、股票价格和温度等。
-
逻辑回归:逻辑回归学习算法是一种流行的分类算法,尤其用于信用行业预测贷款违约。
-
k-最近邻:k-NN 算法是一种分类算法,用于将数据分类为两个或多个类别,广泛应用于根据价格、面积、卧室数量及其他多种特征将房屋分类为昂贵和可负担的类别。
-
支持向量机:SVM 算法是一种流行的分类算法,广泛用于图像和人脸识别,以及手写识别等应用。
-
基于树的算法:基于树的算法,如决策树、随机森林和提升树,通常用于解决分类和回归问题。
-
朴素贝叶斯:朴素贝叶斯分类器是一种使用概率数学模型来解决分类问题的机器学习算法。
无监督学习算法
无监督机器学习算法通常用于根据距离对数据点进行聚类。你将在本书中学习到的无监督学习算法如下:
- k-均值:k-均值算法是一种流行的算法,通常用于根据多种特征(如消费习惯)将顾客划分为不同类别。该算法也用于根据房屋的特征(如价格和面积)将房屋进行分类。
总结
本章简要介绍了机器学习的基础,适合那些刚刚开始进入机器学习领域的读者。你已经了解了 scikit-learn 在机器学习中的应用,并学会了如何安装所需的软件。
最后,你简要了解了在本书学习过程中将实现的所有算法,以及它们在现实世界中的相关应用。
在下一章,你将学习如何实现第一个算法——k-最近邻算法!
第二章:使用 K-近邻预测类别
k-近邻(k-Nearest Neighbors)(k-NN)算法是一种监督学习算法,用于预测类别。在本章中,你将学习以下内容:
-
为使用 scikit-learn 进行机器学习准备数据集
-
k-NN 算法的工作原理 在幕后
-
实现你的第一个 k-NN 算法来预测欺诈交易
-
微调 k-NN 算法的参数
-
为优化性能而对数据进行缩放
k-NN 算法在分类和监督学习领域有广泛的应用。该算法的一些实际应用包括预测金融行业的贷款违约和信用欺诈,以及预测医疗行业中患者是否患有癌症。
本书的设计旨在实现一个稳健的机器学习管道,适用于书中提到的每个算法,并且需要使用 Jupyter Notebook。
Jupyter Notebook 可以通过以下链接提供的安装说明安装到你的本地机器上:jupyter.org/install.html。
或者,你也可以通过使用以下链接在浏览器中使用 Jupyter Notebook:jupyter.org/try。
本书中的每一章都配有一个在 Jupyter Notebook 中实现的管道,存放在本书的官方 GitHub 仓库中,因此,强烈推荐你在本地机器上安装 Jupyter Notebook。
技术要求
你需要在系统中安装 Python 3.6 或更高版本、Pandas ≥ 0.23.4、Scikit-learn ≥ 0.20.0、NumPy ≥ 1.15.1 和 Matplotlib ≥ 3.0.0。
本章的代码文件可以在 GitHub 上找到:
查看以下视频,看看代码的实际应用:
为使用 scikit-learn 进行机器学习准备数据集
使用 scikit-learn 实现任何机器学习算法的第一步是数据准备。scikit-learn 提供了一些实现的限制,这些限制将在本节稍后讨论。我们将使用的数据集基于移动支付,来自全球最受欢迎的竞争性机器学习网站——Kaggle。
你可以从以下网址下载数据集:www.kaggle.com/ntnu-testimon/paysim1。
下载后,通过在终端(macOS/Linux)或 Anaconda Prompt/PowerShell(Windows)中使用以下代码来打开一个新的 Jupyter Notebook:
Jupyter Notebook
这个数据集的基本目标是预测一个移动交易是否为欺诈交易。为了实现这一目标,我们首先需要对数据的内容有一个简要了解。为了探索数据集,我们将使用 Python 中的pandas包。你可以通过在终端(macOS/Linux)或 PowerShell(Windows)中使用以下代码来安装 pandas:
pip3 install pandas
可以通过在 Anaconda 命令提示符下使用以下代码,在 Windows 机器上安装 Pandas:
conda install pandas
我们现在可以通过使用以下代码将数据集读取到 Jupyter Notebook 中:
#Package Imports
import pandas as pd
#Reading in the dataset
df = pd.read_csv('PS_20174392719_1491204439457_log.csv')
#Viewing the first 5 rows of the dataset
df.head()
这会生成如下截图所示的输出:

删除冗余特征
从之前看到的数据集中,有一些列对于机器学习过程来说是冗余的:
-
nameOrig:这一列是属于每个客户的唯一标识符。由于每个标识符在数据集的每一行都是唯一的,机器学习算法将无法从该特征中辨别出任何模式。 -
nameDest:这一列也是每个客户的唯一标识符,因此对机器学习算法没有价值。 -
isFlaggedFraud:如果一个人尝试在单笔交易中转账超过 200,000,该列会标记该交易为欺诈交易。由于我们已经有一个名为isFraud的功能,它会将交易标记为欺诈,因此这个功能变得多余。
我们可以使用以下代码从数据集中删除这些特征:
#Dropping the redundant features
df = df.drop(['nameOrig', 'nameDest', 'isFlaggedFraud'], axis = 1)
减少数据的大小
我们正在处理的数据集包含超过 600 万行数据。大多数机器学习算法在处理这么大规模的数据集时会需要很长时间。为了加快执行速度,我们将数据集的大小缩减至 20,000 行。我们可以使用以下代码来做到这一点:
#Storing the fraudulent data into a dataframe
df_fraud = df[df['isFraud'] == 1]
#Storing the non-fraudulent data into a dataframe
df_nofraud = df[df['isFraud'] == 0]
#Storing 12,000 rows of non-fraudulent data
df_nofraud = df_nofraud.head(12000)
#Joining both datasets together
df = pd.concat([df_fraud, df_nofraud], axis = 0)
在前面的代码中,欺诈交易的行被存储在一个数据框中。这个数据框包含稍微超过 8,000 行数据。12,000 行非欺诈交易存储在另一个数据框中,两个数据框通过 pandas 的concat方法连接在一起。
这将产生一个稍微超过 20,000 行的数据框,现在我们可以相对快速地在其上执行算法。
编码类别变量
scikit-learn 的一个主要限制是,你不能在具有类别性质的列上实施机器学习算法。例如,我们数据集中的type列有五个类别:
-
CASH-IN -
CASH-OUT -
DEBIT -
PAYMENT -
TRANSFER
这些类别将需要被编码成 scikit-learn 可以理解的数字。为了做到这一点,我们必须实施一个两步的过程。
第一步是将每个类别转换为数字:CASH-IN = 0,CASH-OUT = 1,DEBIT = 2,PAYMENT = 3,TRANSFER = 4。我们可以使用以下代码来完成此操作:
#Package Imports
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
#Converting the type column to categorical
df['type'] = df['type'].astype('category')
#Integer Encoding the 'type' column
type_encode = LabelEncoder()
#Integer encoding the 'type' column
df['type'] = type_encode.fit_transform(df.type)
代码首先将type列转换为分类特征。然后,我们使用LabelEncoder()来初始化一个称为type_encode的整数编码器对象。最后,我们在type列上应用fit_transform方法,以将每个类别转换为一个数字。
大体上讲,有两种类型的分类变量:
-
名义
-
有序
名义分类变量没有固有的顺序。名义分类变量的一个例子是type列。
有序分类变量具有固有的顺序。有序分类变量的一个例子是教育水平,其中拥有硕士学位的人将比仅有本科学位的人具有更高的顺序/值。
对于有序分类变量,仅需整数编码即足够,无需进行独热编码,如前所示。由于type列是名义分类变量,因此我们在整数编码后必须进行独热编码。通过以下代码实现:
#One hot encoding the 'type' column
type_one_hot = OneHotEncoder()
type_one_hot_encode = type_one_hot.fit_transform(df.type.values.reshape(-1,1)).toarray()
#Adding the one hot encoded variables to the dataset
ohe_variable = pd.DataFrame(type_one_hot_encode, columns = ["type_"+str(int(i)) for i in range(type_one_hot_encode.shape[1])])
df = pd.concat([df, ohe_variable], axis=1)
#Dropping the original type variable
df = df.drop('type', axis = 1)
#Viewing the new dataframe after one-hot-encoding
df.head()
在代码中,我们首先创建一个名为type_one_hot的独热编码对象。然后,我们通过使用fit_transform方法将type列转换为独热编码列。
fit_transform方法。
我们有五个由整数 0 到 4 表示的类别。现在,每个这五个类别都将有自己的列。因此,我们创建了五列,分别称为type_0、type_1、type_2、type_3和type_4。这五列中的每一列都由两个值表示:1表示该类别存在,0表示该类别不存在。
此信息存储在ohe_variable中。由于此变量包含五列,我们将使用pandas的concat方法将其与原始数据框连接起来。
在进行独热编码后,顺序type列会从数据框中删除,因为此列在独热编码后已经变得多余。最终的数据框现在如下所示:

缺失值
另一个与 scikit-learn 的限制是它不能处理带有缺失值的数据。因此,我们必须首先检查数据集中是否有任何列中的缺失值。我们可以通过使用以下代码来实现这一点:
#Checking every column for missing values
df.isnull().any()
这将产生以下输出:

在此我们注意到每列都有一些缺失值。
可以通过多种方式处理缺失值,例如以下方式:
-
中位数插补
-
均值插补
-
用大多数值填充它们
技术的数量非常多,具体取决于数据集的性质。处理具有缺失值特征的过程称为特征工程。
特征工程可以用于分类和数值列,需要一本完整的书来解释组成该主题的各种方法。
由于本书将重点介绍如何应用 scikit-learn 提供的各种机器学习算法,因此不会涉及特征工程。
因此,为了与本书的目标保持一致,我们将用零来填补所有缺失的值。
我们可以使用以下代码来实现:
#Imputing the missing values with a 0
df = df.fillna(0)
我们现在有一个适用于 scikit-learn 机器学习的数据集。我们将使用这个数据集来进行未来章节的学习。为了方便起见,我们将把这个数据集导出为.csv文件,并存储在你正在使用 Jupyter 笔记本的同一目录中。
我们可以使用以下代码来实现:
df.to_csv('fraud_prediction.csv')
这将创建一个.csv文件,存储在你工作的目录中,你可以使用 pandas 将其再次加载到笔记本中。
k-NN 算法
从数学角度来看,k-NN 算法是最简单的机器学习算法之一。请参考以下图表,了解它如何工作的概览:

k-NN 算法的工作原理
前面图中的星号代表新的数据点。如果我们构建一个带有三个邻居的 k-NN 算法,那么这些星号将寻找与其最接近的三个数据点。
在左下方的情况下,星号看到了两个三角形和一个圆形。因此,算法会将星号分类为三角形,因为三角形的数量大于圆形的数量。
在右上方的情况下,星号看到了两个圆形和一个三角形。因此,算法将把星号分类为圆形,因为圆形的数量大于三角形的数量。
真实的算法以一种非常概率的方式进行,并选择具有最高概率的类别/形状。
使用 scikit-learn 实现 k-NN 算法
在接下来的章节中,我们将实现 k-NN 算法的第一个版本并评估其初始准确性。在使用 scikit-learn 实现机器学习算法时,通常的做法是首先实现算法而不对任何相关参数进行微调或优化,以便评估其性能。
在接下来的章节中,你将学习如何完成以下任务:
-
将数据分割为训练集和测试集
-
在数据上实现算法的第一个版本
-
使用 k-NN 分数评估模型的准确性
将数据分割为训练集和测试集
训练集和测试集的概念对于每个机器学习问题来说都是基础。当我们思考这个概念时,很容易理解为什么引入了这一概念。将机器学习看作是人类学习过程的直接对应;当我们学习数学概念时,我们首先学习如何解决一组附带解答的题目,以便理解解决这些问题的具体方法。然后,我们会参加学校或大学的考试,尝试解决一些我们之前未曾接触或见过的问题,以测试我们对概念的理解。
训练集是机器学习算法用来学习的数据集的一部分。测试集是机器学习算法未见过的数据集的一部分,用来评估算法的性能。
这个过程的第一步是将所有特征保存到一个变量中,将包含标签的目标变量保存到另一个变量中。
在我们的数据集中,目标变量被称为isFraud,包含两个标签:0 表示交易不是欺诈,1 表示交易是欺诈。特征是剩余的变量。我们可以通过以下代码将其存储到两个单独的变量中:
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
在前面的代码中,.*values*用于将特征和目标变量中的值转换为 NumPy 数组。
接下来,我们将使用以下代码将特征和目标拆分为训练集和测试集:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
我们使用sklearn.model_selection中的train_test_split来执行此任务。在前面的代码中,我们有四个变量。X_train和X_test对应特征的训练集和测试集,而y_train和y_test对应目标变量的训练集和测试集。
train_test_split()函数接受四个参数。第一个参数是包含特征的数组,第二个参数是包含目标变量的数组。test_size参数用于指定将拆分并存储到测试集的数据量。由于我们指定了0.3,原始数据的 30%将被存储到测试集中,而 70%的原始数据将用于训练。
train_test_split()函数有两种主要方式将数据打乱并划分为训练集和测试集:
-
随机抽样:将目标标签随机分配到训练集和测试集中(在前面的例子中为
y_train和y_test)。 -
分层抽样:确保目标标签在训练集和测试集中得到充分表示。在前面的代码中,stratify参数已设置为目标标签,以确保这一点。
模型的实现和评估
现在我们已经获得了训练集和测试集的划分,我们可以在训练集上实施 k-NN 算法,并在测试集上评估其得分。我们可以通过以下代码实现这一点:
from sklearn.neighbors import KNeighborsClassifier
#Initializing the kNN classifier with 3 neighbors
knn_classifier = KNeighborsClassifier(n_neighbors=3)
#Fitting the classifier on the training data
knn_classifier.fit(X_train, y_train)
#Extracting the accuracy score from the test sets
knn_classifier.score(X_test, y_test)
在前面的代码中,我们首先用三个邻居初始化一个 k-NN 分类器。邻居数量是任意选择的,三个是一个不错的起始数。接下来,我们使用.fit()方法将该分类器拟合到我们的训练数据上。最后,通过在测试数据上使用.score()方法,我们获得一个介于 0 和 1 之间的值,表示分类器的准确性。
在我们的例子中,我们获得了0.98的准确率,这非常好!
有很多评估和评价分类器性能的方法,准确率不应该是唯一评估分类器性能的标准。更多的评估方法将在本章后续部分讨论。
微调 k-NN 算法的参数
在前一节中,我们在初始化 k-NN 分类器时任意设置了邻居数为三。然而,这真的是最优值吗?嗯,这可能是,因为我们在测试集上得到了相对较高的准确率。
我们的目标是创建一个既不对数据过拟合也不欠拟合的机器学习模型。过拟合数据意味着模型被非常具体地训练在提供的训练样本上,并且在遇到之前没有见过的数据时,无法很好地泛化。例如,我们可能已经非常具体地将模型拟合到训练数据上,而测试案例也与训练数据非常相似。因此,模型能够表现得非常好,并且产生非常高的准确率。
欠拟合是另一种极端情况,在这种情况下,模型以非常通用的方式拟合数据,在测试集中预测正确类别标签的表现不佳。这与过拟合恰好相反。
通过可视化模型在训练集和测试集中的表现,使用不同数量的邻居,可以避免这两种情况。为此,我们首先使用GridSearchCV算法来找到最优的邻居数量。
GridSearchCV创建一个空的网格,并将其填充为我们希望优化的邻居数量或任何其他机器学习参数的可能值。然后,它使用网格中的每个值测试其性能,并确定该参数的最优值。我们可以通过以下代码实现GridSearchCV算法来找到最优的邻居数量:
import numpy as np
from sklearn.model_selection import GridSearchCV
#Initializing a grid with possible number of neighbors from 1 to 24
grid = {'n_neighbors' : np.arange(1, 25)}
#Initializing a k-NN classifier
knn_classifier = KNeighborsClassifier()
#Using cross validation to find optimal number of neighbors
knn = GridSearchCV(knn_classifier, grid, cv = 10)
knn.fit(X_train, y_train)
#Extracting the optimal number of neighbors
knn.best_*params_
#Extracting the accuracy score for optimal number of neighbors
knn.best_score_*
在这段代码中,我们首先初始化一个包含 1 到 24 之间值的数字数组。这个范围是任意选择的,你可以增加或减少范围。然而,增加范围意味着计算时需要更多的时间,特别是当你的数据集较大时,找到最优邻居数的过程将更加耗时。
接下来,我们初始化一个 k-NN 分类器,并使用GridSearchCV()函数与网格一起对分类器进行操作。我们将cv参数设置为 10,表示在执行时我们希望使用 10 折交叉验证。交叉验证是一种技术,其中分类器首先将数据划分为 10 个部分。前九个部分作为训练集,第十部分作为测试集。在第二次迭代中,我们使用前八个部分和第十部分作为训练集,第九部分作为测试集。这个过程会重复,直到每一部分数据都被用于测试。这种方法可以创建一个非常强大的分类器,因为我们使用了整个数据集进行训练和测试,确保没有遗漏任何数据。
交叉验证在下面的图示中进行了说明:

交叉验证实战
在前面的图示中,黑色框表示训练数据,而白色框表示测试数据。
最后,我们使用.best_params_来提取最佳的邻居数量。在我们的例子中,最佳邻居数量是 1,导致了0.985的准确率分数。这比我们最初构建的分类器有所改进,后者使用三个邻居的准确率为0.983。
使用交叉验证可以确保我们不会对数据进行过拟合或欠拟合,因为我们已使用整个数据集进行训练和测试。
为了优化性能进行缩放
k-NN 算法是一种基于距离的算法。当一个新的数据点被引入数据集,并且算法需要对该新数据点进行分类时,它会使用距离来检查与之最接近的点。
如果我们有不同范围值的特征——例如,特征一的范围是 0 到 800,而特征二的范围是 1 到 5——那么这个距离度量就不再有意义了。我们希望所有特征的值范围相同,以便距离度量在所有特征上都具有相同的标准。
其中一种方法是将每个特征的每个值减去该特征的均值,并除以该特征的方差。这称为标准化:

我们可以通过以下代码对数据集进行操作:
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
#Setting up the scaling pipeline
pipeline_order = [('scaler', StandardScaler()), ('knn', KNeighborsClassifier(n_neighbors = 1))]
pipeline = Pipeline(pipeline_order)
#Fitting the classfier to the scaled dataset
knn_classifier_scaled = pipeline.fit(X_train, y_train)
#Extracting the score
knn_classifier_scaled.score(X_test, y_test)
在这段代码中,我们指定了管道执行的顺序。我们将这个顺序存储在一个名为pipeline_order的变量中,指定首先使用StandardScaler()函数对数据进行缩放,然后构建一个具有一个邻居的 k-NN 分类器。
接下来,我们使用Pipeline()函数并将管道的顺序作为唯一参数传入。然后,我们将该管道拟合到训练集,并从测试集中提取准确率分数。
Pipeline 函数,顾名思义,用于将多个函数组合成一个管道,并按我们认为适合的顺序执行它们。这个函数帮助我们简化和自动化常见的机器学习任务。
这导致了 0.997 的准确率,这比 0.985 的得分有了显著的提高。因此,我们看到数据缩放有助于提升性能。
总结
本章帮助你为使用 scikit-learn 进行机器学习准备了一个数据集。你了解了在使用 scikit-learn 进行机器学习时所施加的约束,以及如何创建一个适合 scikit-learn 的完美数据集。
你还学习了 k-NN 算法的工作原理,并使用 scikit-learn 实现了该算法的一个版本,用于预测交易是否欺诈。然后,你学习了如何使用流行的 GridSearchCV 算法优化算法的参数。最后,你了解了如何标准化和缩放数据,以优化模型的性能。
在下一章中,你将再次学习如何使用一种新算法——逻辑回归算法,来分类欺诈交易!
第三章:使用逻辑回归进行分类预测
逻辑回归算法是机器学习领域中最具可解释性的算法之一,尽管“回归”一词通常用于预测数值结果,但逻辑回归算法用于预测类别并解决分类机器学习问题。
在本章中,你将学习以下内容:
-
逻辑回归算法在数学上的工作原理
-
使用 scikit-learn 实现并评估你的第一个逻辑回归算法
-
使用
GridSearchCV微调超参数 -
为了潜在提高准确性,对数据进行缩放
-
解读模型的结果
逻辑回归有广泛的应用,尤其在金融领域,在那里构建可解释的机器学习模型是说服投资者和监管者你的模型在直观和逻辑上都合理的关键。
技术要求
你需要在系统上安装 Python 3.6 或更高版本、Pandas ≥ 0.23.4、Scikit-learn ≥ 0.20.0 和 Matplotlib ≥ 3.0.0。
本章的代码文件可以在 GitHub 上找到:
查看以下视频,看看代码的实际操作:
从数学角度理解逻辑回归
顾名思义,逻辑回归本质上源自线性回归算法。线性回归算法将在后续章节中深入讨论。现在,让我们考虑一个假设情况:我们希望根据贷款的利率预测某一贷款是否会违约。使用线性回归,可以构建以下方程:
违约 = (利率 × x) + c
在上述方程中,c 是截距,x 是系数,将作为逻辑回归模型的输出。截距和系数将具有数值。为了此示例,我们假设 c 为 5,x 为 -0.2。方程现在变为:
违约 = (利率 × -0.2) + 5
该方程可以通过以下图示表示为二维图:

假设利率为 10%,该方程产生的违约值如下:
违约 = (10 × -0.2) + 5
违约 = 3
现在,逻辑回归模型使用logit函数将这个值 3 转换为一个介于 0 和 1 之间的概率:

评估前面的方程式后,我们得到答案 0.95。换句话说,使用我们刚刚构建的逻辑回归模型,我们获得了 95% 的概率,表示在利率为 10% 时,贷款违约的可能性。
在对线性方程应用 logit 函数后,之前的二维图表变为下图所示:
在前面的图表中,发生了以下情况:
-
当利率沿着 x 轴接近无穷大时,函数趋近于 1。
-
当利率沿 x 轴接近 0 时,函数趋近于 0。
使用 scikit-learn 实现逻辑回归
在本节中,您将学习如何为您的数据集实现并快速评估逻辑回归模型。我们将使用之前已经清理和准备好的数据集,目的是预测某笔交易是否为欺诈。在上一章中,我们将此数据集保存为 fraud_detection.csv。第一步是将该数据集加载到 Jupyter Notebook 中。这可以通过以下代码完成:
import pandas as pd
# Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
将数据分为训练集和测试集
使用 scikit-learn 构建任何机器学习模型的第一步是将数据分为训练集和测试集。这可以通过以下代码完成:
from sklearn.model_selection import train_test_split
#Creating the features and target
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
#Creating the training and testing data
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
下一步是实现一个基本的逻辑回归分类器并评估其准确率。这可以通过以下代码完成:
from sklearn import linear_model
#Initializing an logistic regression object
logistic_regression = linear_model.LogisticRegression()
#Fitting the model to the training and test sets
logistic_regression.fit(X_train, y_train)
在前面的代码中,linear_model 包从 sklearn 导入,并通过调用 LogisticRegression() 方法来初始化逻辑回归算法。然后将该逻辑回归算法拟合到训练数据中。
为了提取准确率评分,我们对测试数据使用以下代码:
#Accuracy score of the logistic regression model
logistic_regression.score(X_test, y_test)
该模型在测试数据上的准确率为 58.9%。这意味着基本的逻辑回归模型的表现仅略优于一个随机猜测输出的算法。
微调超参数
从前一部分中实现的逻辑回归模型的输出可以看出,该模型的表现略优于随机猜测。这样的模型无法为我们提供价值。为了优化模型,我们将使用上一章中介绍的 GridSearchCV 算法来优化逻辑回归模型的超参数。
逻辑回归模型使用的超参数被称为反向正则化强度。这是因为我们正在实现一种被称为 l1 回归的线性回归。关于这种线性回归的详细解释,请参考 第五章,使用线性回归预测数值结果。
为了优化反向正则化强度,简称 C,我们使用以下代码:
#Building the model with L1 penality
logistic_regression = linear_model.LogisticRegression(penalty='l1')
#Using GridSearchCV to search for the best parameter
grid = GridSearchCV(logistic_regression, {'C':[0.0001, 0.001, 0.01, 0.1, 10]})
grid.fit(X_train, y_train)
# Print out the best parameter
print("The most optimal inverse regularization strength is:", grid.best_params_)
这将生成如下所示的输出:

在前面的代码中,我们首先初始化了一个逻辑回归模型,并将惩罚参数设置为l1,这表示我们使用的是l1回归。然后我们初始化了一个网格,其中包含从 0.0001 到 10\的逆正则化强度的可能值。
在网格对象中初始化模型的超参数的值的个数是任意的。然而,值越多,GridSearchCV找到最佳超参数值的时间就越长,从而使得这一过程在计算上变得更加昂贵。
然后,将包含逆正则化强度可能值的网格对象拟合到训练数据中,并打印出最佳值,在本例中是 10\。我们现在可以通过以下代码构建一个新的逻辑回归模型,使用这个新获得的最佳超参数值:
#Initializing an logistic regression object
logistic_regression = linear_model.LogisticRegression(C = 10, penalty = 'l1')
#Fitting the model to the training and test sets
logistic_regression.fit(X_train, y_train)
使用以下代码评估测试数据上的模型时,我们得到了 99.6%的准确率!这可算是一个相当大的提升。
#Accuracy score of the logistic regression model
logistic_regression.score(X_test, y_test)
检查GridSearchCV是否给出准确结果的一种方法是绘制逆正则化强度不同值在 x 轴上的变化,并将准确率得分绘制在y轴上。这可以通过以下代码完成:
train_errors = []
test_errors = []
C_list = [0.0001, 0.001, 0.01, 0.1, 10, 100, 1000]
# Evaluate the training and test classification errors for each value of C
for value in C_list:
# Create LogisticRegression object and fit
logistic_regression = linear_model.LogisticRegression(C= value, penalty = 'l1')
logistic_regression.fit(X_train, y_train)
# Evaluate error rates and append to lists
train_errors.append(logistic_regression.score(X_train, y_train) )
test_errors.append(logistic_regression.score(X_test, y_test))
# Plot results
plt.semilogx(C_list, train_errors, C_list, test_errors)
plt.legend(("train", "test"))
plt.ylabel('Accuracy Score')
plt.xlabel('C (Inverse regularization strength)')
plt.show()
这将产生如下面所示的图:

从前面的图中可以清楚地看到,逆正则化强度为 10 时,训练集和测试集的准确率都很高。此类图表还用于判断某个超参数值是否出现过拟合情况,即在训练集上得到较高的准确率,但在测试集上得到较低的准确率。相反,它们也可以用来检查模型是否低估了数据,通过在训练集上获得较低的准确率。
数据缩放
尽管模型表现极为出色,缩放数据仍然是构建逻辑回归机器学习模型中的一个有用步骤,因为它标准化了数据,使其在相同范围的值内。在缩放数据时,我们将使用上一章中用过的StandardScaler()函数。具体代码如下:
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
#Setting up the scaling pipeline
pipeline_order = [('scaler', StandardScaler()), ('logistic_reg', linear_model.LogisticRegression(C = 10, penalty = 'l1'))]
pipeline = Pipeline(pipeline_order)
#Fitting the classfier to the scaled dataset
logistic_regression_scaled = pipeline.fit(X_train, y_train)
#Extracting the score
logistic_regression_scaled.score(X_test, y_test)
前面的代码使得模型的准确率得分提高了 0.1%,考虑到模型原本已经有非常高的准确率,这已经是一个不错的提升。该代码与上一章为 k-NN 算法构建的缩放管道类似,唯一的区别是我们使用了逻辑回归模型,而不是 k-NN 模型。
解释逻辑回归模型
逻辑回归算法的一个关键优势是其高度可解释性。这意味着模型的结果可以解释为输入变量的函数。这使我们能够理解每个变量如何影响模型最终结果。
在第一部分中,我们了解到逻辑回归模型由每个变量的系数和一个截距组成,可以用来解释模型的工作原理。为了提取模型中每个变量的系数,我们使用以下代码:
#Printing out the coefficients of each variable
print(logistic_regression.coef_)
这导致了如下截图所示的输出:

系数的顺序与输入模型的数据集中变量的顺序相同。为了从模型中提取截距,我们使用以下代码:
#Printing out the intercept of the model
print(logistic_regression.intercept_)
这导致了如下截图所示的输出:

现在我们已经获得了每个变量的系数以及截距,我们可以构建以下形式的方程:

摘要
在本章中,您已经了解了逻辑回归模型在数学层面上的工作原理。尽管简单,但该模型在可解释性方面表现出色,这在金融行业中非常有益。
您还学会了如何使用 scikit-learn 构建和评估逻辑回归算法,并使用GridSearchCV算法进行超参数优化。此外,您还学会了通过绘制不同超参数数值的准确度得分来验证GridSearchCV算法提供给您的结果是否准确。
最后,您对数据进行了缩放以使其标准化,并学会了如何在数学层面解释您的模型。
在下一章中,您将学习如何使用 scikit-learn 实现基于树的算法,如决策树、随机森林和梯度提升树。
第四章:使用朴素贝叶斯和支持向量机预测类别
在本章中,你将学习两种流行的分类机器学习算法:朴素贝叶斯算法和线性支持向量机。朴素贝叶斯算法是一个概率模型,用于预测类别和分类,而线性支持向量机则使用线性决策边界来预测类别和分类。
在本章中,你将学习以下内容:
-
解释朴素贝叶斯算法背后的理论概念,使用数学术语
-
使用 scikit-learn 实现朴素贝叶斯算法
-
线性支持向量机算法的工作原理
-
图形化优化线性支持向量机的超参数
技术要求
你需要在系统上安装 Python 3.6 或更高版本、Pandas ≥ 0.23.4、Scikit-learn ≥ 0.20.0 和 Matplotlib ≥ 3.0.0。
本章的代码文件可以在 GitHub 上找到:
查看以下视频,看看代码如何运行:
朴素贝叶斯算法
朴素贝叶斯算法利用贝叶斯定理来进行分类。算法之所以被称为朴素,是因为它假设所有特征之间是相互独立的。但实际上这是不可能的,因为数据集中的每个属性/特征在某种程度上与其他属性相关。
尽管朴素贝叶斯算法是“朴素”的,但它在实际应用中表现良好。贝叶斯定理的公式如下:

贝叶斯定理公式
我们可以将前述算法分解为以下几个组成部分:
-
p(h|D):这是在给定数据集的前提下,假设发生的概率。举个例子,这可以是一个欺诈交易发生的概率,前提是我们有一个包含欺诈和非欺诈交易的数据集。
-
p(D|h):这是在假设的前提下,数据存在的概率。举个例子,这可以是拥有一个包含欺诈交易的数据集的概率。
-
p(h):这是假设发生的概率。举个例子,这可以是一个声明,表示在移动行业中,欺诈交易发生的平均概率为 2%。
-
p(D):这是在不知道任何假设的情况下,数据存在的概率。举个例子,这可以是一个数据集存在的概率,而我们并不知道具体要做什么(例如,预测欺诈性移动交易)。
在上述公式中,p(D)可以用p(h)和p(D|h)来重新写为如下形式:

让我们来看看如何在移动交易示例中使用预测类别的方法来实现这一点:
| p(D|h) | p(h) | p(D|-h) | (1 - p(h)) |
|---|---|---|---|
| 0.8 | 0.08 | 0.02 | 0.92 |
将上述表格中的值代入贝叶斯定理公式,得到结果为 0.77。这意味着,使用之前给定的数据,分类器预测交易为欺诈的概率为 77%。
在 scikit-learn 中实现朴素贝叶斯算法
现在你已经了解了朴素贝叶斯算法如何生成预测,我们将使用 scikit-learn 实现相同的分类器,以预测某一交易是否为欺诈。
第一步骤是导入数据,创建特征数组和目标数组,并将数据划分为训练集和测试集。
我们可以使用以下代码来实现:
import pandas as pd
from sklearn.model_selection import train_test_split
df = pd.read_csv('fraud_prediction.csv')
df = df.drop(['Unnamed: 0'], axis = 1)
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
下一步是构建朴素贝叶斯分类器。我们可以使用以下代码来实现:
from sklearn.naive_bayes import GaussianNB
#Initializing an NB classifier
nb_classifier = GaussianNB()
#Fitting the classifier into the training data
nb_classifier.fit(X_train, y_train)
#Extracting the accuracy score from the NB classifier
nb_classifier.score(X_test, y_test)
在上述代码中,以下内容适用:
-
首先,我们从 scikit-learn 导入
GaussianNB模块 -
接下来,我们初始化一个朴素贝叶斯分类器,并将其存储在变量
nb_classifier中 -
然后,我们将分类器拟合到训练数据,并在测试数据上评估其准确性。
朴素贝叶斯分类器只有一个超参数,即假设的先验概率,p(h)。**然而,请牢记以下几点:
-
在大多数问题中,先验概率是不可用的。
-
即使如此,通常会将值固定为一个统计事实,因此不会进行超参数优化。
支持向量机
在本节中,您将学习支持向量机(SVMs),或者更具体地说,线性支持向量机。为了理解支持向量机,您需要知道什么是支持向量。它们在下图中得到了说明:

支持向量的概念
在上述图表中,以下内容适用:
-
线性支持向量机是一种线性分类器。构建一个线性决策边界,边界一侧的观测点(圆形)属于一个类别,而另一侧的观测点(方形)属于另一个类别。
-
支持向量是那些上面有三角形标记的观测点。
-
这些是非常接近线性决策边界的观测点,或者被错误分类的观测点。
-
我们可以通过定义观测点距离决策边界的接近程度,来确定哪些观测点将成为支持向量。
-
这一点由名为逆正则化强度的超参数控制。**
为了理解线性支持向量机的工作原理,请考虑以下图示:

最大边距的概念
在前面的图示中,适用以下内容:
-
支持向量和线性决策边界之间的线称为边距。
-
支持向量机的目标是最大化这个边界,以便正确地分类一个新的数据点。
-
逆正则化强度的低值确保该边界尽可能大。
在 scikit-learn 中实现线性支持向量机算法
在本节中,您将学习如何在 scikit-learn 中实现线性支持向量机。第一步是导入数据并将其拆分为训练集和测试集。我们可以通过以下代码实现:
import pandas as pd
from sklearn.model_selection import train_test_split
df = pd.read_csv('fraud_prediction.csv')
df = df.drop(['Unnamed: 0'], axis = 1)
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
下一步是构建线性支持向量机分类器。我们可以通过以下代码实现:
from sklearn.svm import LinearSVC
#Initializing a SVM model
svm = LinearSVC(random_state = 50)
#Fitting the model to the training data
svm.fit(X_train, y_train)
#Extracting the accuracy score from the training data
svm.score(X_test, y_test)
在前面的代码中,适用以下内容:
-
首先,我们从 scikit-learn 导入
LinearSVC模块。 -
接下来,我们初始化一个线性支持向量机对象,设置随机状态为 50,这样模型每次都会生成相同的结果。
-
最后,我们将模型拟合到训练数据,并评估其在测试数据上的准确度。
现在我们已经构建了模型,可以找到并优化超参数的最理想值。
线性支持向量机的超参数优化
在本节中,您将学习如何优化线性支持向量机的超参数。特别地,有一个超参数值得关注:逆正则化强度。
我们将探索如何通过图形化和算法两种方式来优化这个超参数。
图形化超参数优化
为了优化逆正则化强度,我们将绘制训练集和测试集的准确度得分,使用以下代码:
import matplotlib.pyplot as plt
from sklearn.svm import LinearSVC
training_scores = []
testing_scores = []
param_list = [0.0001, 0.001, 0.01, 0.1, 10, 100, 1000]
# Evaluate the training and test classification errors for each value of the parameter
for param in param_list:
# Create SVM object and fit
svm = LinearSVC(C = param, random_state = 42)
svm.fit(X_train, y_train)
# Evaluate the accuracy scores and append to lists
training_scores.append(svm.score(X_train, y_train) )
testing_scores.append(svm.score(X_test, y_test) )
# Plot results
plt.semilogx(param_list, training_scores, param_list, testing_scores)
plt.legend(("train", "test"))
plt.ylabel('Accuracy scores')
plt.xlabel('C (Inverse regularization strength)')
plt.show()
在前面的代码中,适用以下内容:
-
首先,我们初始化两个空列表,用于存储训练集和测试集的准确度得分。
-
下一步是创建超参数的值列表,在本例中,超参数是逆正则化强度。
-
然后,我们遍历超参数列表中的每个值,使用每个逆正则化强度值构建线性支持向量机分类器。
-
然后,训练集和测试集的准确度得分将被追加到空列表中。
-
使用
matplotlib,我们将逆正则化强度(沿X轴)与训练集和测试集的准确度得分(沿Y轴)绘制成图。
这将生成如下图所示的图表:

图形化超参数优化
在前面的图示中,适用以下内容:
-
我们可以观察到,对于逆正则化强度为 10^(-2)时,训练集和测试集的准确度得分最高。
-
重要的是选择一个在训练集和测试集上都具有较高准确度的值,而不仅仅是其中一个数据集
-
这将帮助你避免过拟合和欠拟合
使用 GridSearchCV 进行超参数优化
在本节中,你将学习如何使用 GridSearchCV 算法优化反正则化强度。我们可以使用以下代码来完成这一操作:
from sklearn.model_selection import GridSearchCV
#Building the model
svm = LinearSVC(random_state = 50)
#Using GridSearchCV to search for the best parameter
grid = GridSearchCV(svm, {'C':[0.00001, 0.0001, 0.001, 0.01, 0.1, 10]})
grid.fit(X_train, y_train)
# Print out the best parameter
print("The best value of the inverse regularization strength is:", grid.best_params_)
在前面的代码中,以下内容适用:
-
首先,我们从 scikit-learn 导入
GridSearchCV模块 -
下一步是初始化一个线性支持向量机模型,随机状态设为 50,以确保每次构建模型时得到相同的结果
-
我们接着初始化一个可能的超参数值网格,用于反正则化强度
-
最后,我们将超参数值网格拟合到训练集上,从而构建多个线性 SVM 模型,使用不同的反正则化强度值
-
GridSearchCV算法接着评估模型,选择产生最少泛化误差的模型,并返回超参数的最优值
将超参数优化的图形方法结果与 GridSearchCV 的结果进行比较是一个好习惯,这样可以验证你的结果。
缩放数据以提高性能
在本节中,你将学习如何通过缩放和标准化数据来提高线性支持向量机的整体性能。缩放的概念与前几章相同,这里不会再讨论。为了缩放数据,我们使用以下代码:
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
#Setting up the scaling pipeline
order = [('scaler', StandardScaler()), ('SVM', LinearSVC(C = 0.1, random_state = 50))]
pipeline = Pipeline(order)
#Fitting the classfier to the scaled dataset
svm_scaled = pipeline.fit(X_train, y_train)
#Extracting the score
svm_scaled.score(X_test, y_test)
在前面的代码中,以下内容适用:
-
首先,我们从 scikit-learn 导入
StandardScaler和Pipeline模块,以便构建一个缩放管道 -
我们接着设置管道的顺序,指定首先使用
StandardScaler()函数来缩放数据,并在该缩放数据上构建线性支持向量机 -
Pipeline()函数用于设置管道的顺序,建立管道 -
然后我们将这个管道拟合到训练数据上,并从测试数据中提取缩放后的准确度得分
总结
本章向你介绍了两种基本的监督式机器学习算法:朴素贝叶斯算法和线性支持向量机。更具体地说,你学习了以下内容:
-
贝叶斯定理如何用于生成概率,以指示数据点是否属于某个特定类别或类别
-
在 scikit-learn 中实现朴素贝叶斯分类器
-
线性支持向量机的工作原理
-
在 scikit-learn 中实现线性支持向量机
-
使用图形方法和
GridSearchCV算法优化反正则化强度 -
如何缩放数据以潜在地提高性能
在下一章中,你将学习另一种有监督的机器学习算法,它用于预测数值,而不是类别和分类:线性回归!
第五章:使用线性回归预测数值结果
在进行线性回归时,graph_from_dot_data()函数用于根据一组输入特征预测一个连续的数值。这一机器学习算法对于统计学家来说至关重要,尤其是在预测数值结果时。尽管像神经网络和深度学习这样的高级算法在现代已取代了线性回归,但这一算法依然是神经网络和深度学习的基础。
使用线性回归算法构建机器学习模型的关键好处,与神经网络和深度学习相比,它具有高度的可解释性。可解释性帮助您作为机器学习从业者理解不同的输入变量在预测输出时的行为。
线性回归算法被应用于金融行业(用于预测股票价格)和房地产行业(用于预测房价)。事实上,线性回归算法可以应用于任何需要根据一组输入特征预测数值的领域。
本章将涵盖以下主题:
-
线性回归算法的内部机制
-
使用 scikit-learn 构建并评估您的第一个线性回归算法
-
对数据进行缩放,以期提高性能
-
优化您的线性回归模型
技术要求
您需要在系统上安装 Python 3.6 或更高版本,Pandas ≥ 0.23.4,Scikit-learn ≥ 0.20.0 和 Matplotlib ≥ 3.0.0。
本章的代码文件可以在 GitHub 上找到:
查看以下视频,查看代码的实际运行情况:
线性回归算法的内部机制
在线性回归算法的最基本形式中,其表达式可以写成如下:

在前述方程中,模型的输出是一个数值结果。为了得到这个数值结果,我们要求每个输入特征与一个名为参数 1的参数相乘,并在此结果上加上第二个参数参数 2。
换句话说,我们的任务是找到能够尽可能准确预测数值结果的两个参数值。用图形化的方式来表示,考虑以下图示:

目标与输入特征之间的二维图
上述图示展示了一个二维图,其中目标变量(我们希望预测的内容)位于y轴上(数值型输出),输入特征位于x轴上。线性回归的目标是找到上述方程中提到的两个参数的最优值,从而将一条线拟合到给定的点集。
这条线被称为最佳拟合线。最佳拟合线是指能够非常好地拟合给定数据点集的直线,以便可以为我们做出准确的预测。因此,为了找到能够生成最佳拟合线的参数的最优值,我们需要定义一个能够为我们完成此任务的函数。
这个函数被称为损失函数。顾名思义,损失函数的目标是尽可能地最小化损失/误差,以便我们能够获得最佳拟合线。为了理解这个过程,请参考以下图示:

最佳拟合线
在上述图示中,线条被拟合到数据点集,特征可以定义如下:
-
每个数据点到拟合线的距离被称为残差。
-
损失/误差函数是这些残差的平方和。
-
线性回归算法的目标是最小化这个值。残差的平方和被称为普通最小二乘法(OLS)。
在 scikit-learn 中实现线性回归
在本节中,你将实现第一个线性回归算法,使用 scikit-learn。为了方便理解,本节将分为三个子节,分别讲解以下主题:
-
实现并可视化一个简单的二维线性回归模型
-
实现线性回归以预测手机交易金额
-
对数据进行缩放,以提高可能的性能
二维线性回归
在这一子节中,你将学习如何实现第一个线性回归算法,通过使用一个输入特征——账户持有者的旧余额,来预测手机交易的金额。我们将使用在本书的第二章《使用 K 最近邻预测类别》中使用的相同欺诈性手机交易数据集。
第一步是读取数据集并定义特征和目标变量。这可以通过以下代码来完成:
import pandas as pd
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Define the feature and target arrays
feature = df['oldbalanceOrg'].values
target = df['amount'].values
接下来,我们将创建一个简单的散点图,展示手机交易金额在y轴上的数据(即线性回归模型的输出),以及账户持有者的旧余额沿x轴的数据(即输入特征)。这可以通过以下代码实现:
import matplotlib.pyplot as plt
#Creating a scatter plot
plt.scatter(feature, target)
plt.xlabel('Old Balance of Account Holder')
plt.ylabel('Amount of Transaction')
plt.title('Amount Vs. Old Balance')
plt.show()
在前述代码中,我们使用plt.scatter()函数创建了特征在* x * 轴上与目标在* y * 轴上之间的散点图。这样得到了以下图示中的散点图:

线性回归模型的二维空间
现在,我们将线性回归模型拟合到前述图表中所示的二维空间中。请注意,在前述图表中,数据并非完全线性。为了实现这一点,我们使用以下代码:
#Initializing a linear regression model
linear_reg = linear_model.LinearRegression()
#Reshaping the array since we only have a single feature
feature = feature.reshape(-1, 1)
target = target.reshape(-1, 1)
#Fitting the model on the data
linear_reg.fit(feature, target)
#Define the limits of the x axis
x_lim = np.linspace(min(feature), max(feature)).reshape(-1, 1)
#Creating the scatter plot
plt.scatter(feature, target)
plt.xlabel('Old Balance of Account Holder')
plt.ylabel('Amount of Transaction')
plt.title('Amount Vs. Old Balance')
#Creating the prediction line
plt.plot(x_lim, linear_reg.predict(x_lim), color = 'red')
#Show the plot
plt.show()
这会得到一条最佳拟合线,如下图所示:

最佳拟合线
在前述代码中,首先我们初始化一个线性回归模型,并将训练数据拟合到该模型中。由于我们只有一个特征,我们需要为 scikit-learn 调整特征和目标。接着,我们定义了包含特征变量的* x * 轴的上下限。
最后,我们创建了特征与目标变量之间的散点图,并在前述图表中加入了红色的最佳拟合线。
使用线性回归预测移动交易金额
现在我们已经可视化了一个简单的线性回归模型在二维空间中的工作原理,我们可以利用线性回归算法,通过我们移动交易数据集中的所有其他特征来预测移动交易的总金额。
第一步是将我们的欺诈预测数据集导入工作区,并将其分为训练集和测试集。这可以通过以下代码完成:
import pandas as pd
from sklearn.model_selection import train_test_split
# Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
现在,我们可以拟合线性回归模型,并通过以下代码评估模型的初始准确性分数:
from sklearn import linear_model
#Initializing a linear regression model
linear_reg = linear_model.LinearRegression()
#Fitting the model on the data
linear_reg.fit(X_train, y_train)
#Accuracy of the model
linear_reg.score(X_test, y_test)
在前述代码中,首先我们初始化一个线性回归模型,然后通过.fit()函数将其拟合到训练数据中。接着,我们通过.score()函数评估在测试数据上的准确性分数。最终,我们得到一个 98%的准确性分数,这非常棒!
数据标准化
对数据进行标准化处理并提供一定的标准化水平是任何线性回归管道中的关键步骤,因为它可以提高模型的表现。为了缩放数据,我们使用以下代码:
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
#Setting up the scaling pipeline
pipeline_order = [('scaler', StandardScaler()), ('linear_reg', linear_model.LinearRegression())]
pipeline = Pipeline(pipeline_order)
#Fitting the classfier to the scaled dataset
linear_reg_scaled = pipeline.fit(X_train, y_train)
#Extracting the score
linear_reg_scaled.score(X_test, y_test)
我们使用与之前章节相同的标准化管道。在前述代码中,我们将模型名称替换为线性回归模型,并评估在测试数据上的标准化准确性分数。
在这种情况下,数据标准化并未带来准确性分数的提升,但将标准化引入线性回归管道中仍然至关重要,因为在大多数情况下,它会提升准确性分数。
模型优化
线性回归算法的基本目标是最小化损失/代价函数。为了实现这一目标,算法尝试优化每个特征的系数值(Parameter1),使得损失函数最小化。
有时,这会导致过拟合,因为每个变量的系数是针对其训练数据进行优化的。这意味着你的线性回归模型在训练数据之外的泛化能力较差。
我们通过对超优化的系数进行惩罚,以防止过拟合的过程被称为正则化。
正则化方法大致可以分为两类,如下所示:
-
岭回归
-
Lasso 回归
在接下来的小节中,将详细讨论这两种正则化技术,并介绍如何将它们应用到你的模型中。
岭回归
岭回归的公式如下:

在前面的公式中,岭回归的损失函数等于普通最小二乘法损失函数,加上每个特征的Parameter1的平方与alpha的乘积。
alpha是一个可以优化的参数,用于控制岭回归损失函数惩罚系数的程度,从而防止过拟合。显然,如果alpha等于0,则岭回归损失函数等同于普通最小二乘法损失函数,从而对最初的过拟合模型没有任何影响。
因此,优化这个alpha值可以提供一个最佳模型,使其能够在训练数据之外进行泛化。
为了将岭回归应用于欺诈预测数据集,我们使用以下代码:
from sklearn.linear_model import Ridge
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge
# Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
#Initialize a ridge regression model
ridge_reg = Ridge(alpha = 0, normalize = True)
#Fit the model to the training data
ridge_reg.fit(X_train, y_train)
#Extract the score from the test data
ridge_reg.score(X_test, y_test)
在前面的代码中,首先我们读取数据集并将其分为训练集和测试集(如往常一样)。接下来,我们使用Ridge()函数初始化一个岭回归模型,并将alpha参数设置为0,normalize参数设置为True,以便对数据进行标准化。
接下来,将岭回归模型拟合到训练数据中,并从测试数据中提取准确率分数。这个模型的准确率与我们在没有使用岭回归作为优化模型的参数时构建的模型的准确率完全相同;alpha被设置为0。
为了使用GridSearchCV算法获得最佳的alpha值,我们使用以下代码:
from sklearn.model_selection import GridSearchCV
#Building the model
ridge_regression = Ridge()
#Using GridSearchCV to search for the best parameter
grid = GridSearchCV(ridge_regression, {'alpha':[0.0001, 0.001, 0.01, 0.1, 10]})
grid.fit(X_train, y_train)
# Print out the best parameter
print("The most optimal value of alpha is:", grid.best_params_)
#Initializing an ridge regression object
ridge_regression = Ridge(alpha = 0.01)
#Fitting the model to the training and test sets
ridge_regression.fit(X_train, y_train)
#Accuracy score of the ridge regression model
ridge_regression.score(X_test, y_test)
在前面的代码中,以下内容适用:
-
首先,我们初始化一个岭回归模型,然后使用
GridSearchCV算法从一系列值中搜索最佳的alpha值。 -
在获得最佳的
alpha值后,我们使用这个最佳值构建一个新的岭回归模型,并在训练数据中进行训练,然后评估测试数据上的准确率。
由于我们的初始模型已经得到了很好的优化,因此准确率分数没有明显增加。然而,在具有更大维度/特征的数据集上,岭回归对于提供一个不会过拟合且泛化良好的模型具有巨大的价值。
为了验证GridSearchCV算法为我们提供的结果,我们将构建一个图表,y 轴为准确率分数,x 轴为不同的alpha值,分别针对训练数据和测试数据。为此,我们使用以下代码:
import matplotlib.pyplot as plt
train_errors = []
test_errors = []
alpha_list = [0.0001, 0.001, 0.01, 0.1, 10]
# Evaluate the training and test classification errors for each value of alpha
for value in alpha_list:
# Create Ridge object and fit
ridge_regression = Ridge(alpha= value)
ridge_regression.fit(X_train, y_train)
# Evaluate error rates and append to lists
train_errors.append(ridge_regression.score(X_train, y_train) )
test_errors.append(ridge_regression.score(X_test, y_test))
# Plot results
plt.semilogx(alpha_list, train_errors, alpha_list, test_errors)
plt.legend(("train", "test"))
plt.ylabel('Accuracy Score')
plt.xlabel('Alpha')
plt.show()
这将产生以下输出:

准确率与alpha的关系
在前面的图中,可以明显看出,0.01 或更低的值为训练数据和测试数据提供了最高的准确率,因此,GridSearchCV算法的结果是合乎逻辑的。
在上述代码中,首先我们初始化两个空列表,用来存储训练数据和测试数据的准确率分数。然后,我们评估不同alpha值下的训练集和测试集准确率分数,并创建前面的图表。
套索回归
套索回归的方程如下:

在上述方程中,套索损失函数等于普通最小二乘损失函数加上每个特征系数的绝对值与alpha的乘积。
alpha是一个我们可以优化的参数,用来控制套索损失函数对系数的惩罚程度,从而防止过拟合。再次说明,如果alpha等于0,套索损失函数就等于普通最小二乘损失函数,从而与最初的过拟合模型没有任何区别。
因此,优化alpha值提供了一个最佳模型,使其能够很好地泛化到训练数据之外的数据。
为了将套索回归应用于欺诈预测数据集,我们使用以下代码:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Lasso
import warnings
# Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
#Initialize a lasso regression model
lasso_reg = Lasso(alpha = 0, normalize = True)
#Fit the model to the training data
lasso_reg.fit(X_train, y_train)
warnings.filterwarnings('ignore')
#Extract the score from the test data
lasso_reg.score(X_test, y_test)
上述代码与我们用来构建岭回归模型的代码非常相似,唯一的不同是我们使用Lasso()函数来初始化套索回归模型。此外,使用了warnings包,以便在我们将alpha值设为0时抑制生成的警告。
为了优化alpha值,我们使用GridSearchCV算法。这是通过使用以下代码实现的:
from sklearn.model_selection import GridSearchCV
#Building the model
lasso_regression = Lasso()
#Using GridSearchCV to search for the best parameter
grid = GridSearchCV(lasso_regression, {'alpha':[0.0001, 0.001, 0.01, 0.1, 10]})
grid.fit(X_train, y_train)
# Print out the best parameter
print("The most optimal value of alpha is:", grid.best_params_)
#Initializing an lasso regression object
lasso_regression = Lasso(alpha = 0.0001)
#Fitting the model to the training and test sets
lasso_regression.fit(X_train, y_train)
#Accuracy score of the lasso regression model
lasso_regression.score(X_test, y_test)
上述代码与我们为岭回归实现的alpha优化类似。在这里,我们使用套索回归模型,而不是岭回归模型。
为了验证GridSearchCV算法的结果,我们构建了一个图表,其中显示了训练集和测试集的准确率分数与alpha值的关系。具体代码如下:
train_errors = []
test_errors = []
alpha_list = [0.0001, 0.001, 0.01, 0.1, 10]
# Evaluate the training and test classification errors for each value of alpha
for value in alpha_list:
# Create Lasso object and fit
lasso_regression = Lasso(alpha= value)
lasso_regression.fit(X_train, y_train)
# Evaluate error rates and append to lists
train_errors.append(ridge_regression.score(X_train, y_train) )
test_errors.append(ridge_regression.score(X_test, y_test))
# Plot results
plt.semilogx(alpha_list, train_errors, alpha_list, test_errors)
plt.legend(("train", "test"))
plt.ylabel('Accuracy Score')
plt.xlabel('Alpha')
plt.show()
这将产生以下输出:

准确性与 alpha 的关系
所有的alpha值都提供相同的准确度分数,因此我们可以选择由GridSearchCV算法提供的值。
总结
在本章中,你了解了线性回归算法的内部工作原理,通过残差和普通最小二乘等关键概念。你还学会了如何在二维空间中可视化简单的线性回归模型。
我们还介绍了如何实现线性回归模型来预测移动交易的金额,并在有效的管道中对数据进行缩放,以带来潜在的性能提升。
最后,你学会了如何通过使用正则化概念来优化你的模型,正则化形式为岭回归和套索回归。
第六章:基于树的分类与回归
基于树的算法因其可解释性和声音预测而非常流行,在在线平台如 Kaggle 上赢得了许多机器学习竞赛。此外,它们在解决问题的简单和复杂用例中也有许多应用。
构建树是几乎所有行业中用于决策制定的方法。树可用于解决基于分类和回归的问题,并有几个用例使其成为首选解决方案!
本章节主要分为以下两个部分:
-
分类树
-
回归树
每个部分将涵盖不同类型基于树的算法的基本理论,以及它们在 scikit-learn 中的实现。通过本章结束时,您将学会如何将多个算法聚合到一个集成中,并让它们投票决定最佳预测结果。
技术要求
您需要在系统上安装 Python 3.6 或更高版本,Pandas ≥ 0.23.4,Scikit-learn ≥ 0.20.0 和 Matplotlib ≥ 3.0.0。
本章的代码文件可在 GitHub 上找到:
github.com/PacktPublishing/Machine-Learning-with-scikit-learn-Quick-Start-Guide/blob/master/Chapter_06.ipynb.
观看以下视频,了解代码的实际操作:
分类树
分类树用于预测类别或类别。这类似于您在本书中之前学习过的分类算法,如 k 最近邻算法或逻辑回归。
广义上讲,有三种基于树的算法用于解决分类问题:
-
决策树分类器
-
随机森林分类器
-
AdaBoost 分类器
在本节中,您将学习每种基于树的算法如何工作,以便将数据行分类为特定的类别或类别。
决策树分类器
决策树是最简单的基于树的算法,也是其他两种算法的基础。让我们考虑以下简单的决策树:

简单的决策树
简而言之,决策树是一组帮助我们将观察结果分类为不同组的规则。在前面的图表中,规则可以写成如下形式:
If (value of feature is less than 50); then (put the triangles in the left-hand box and put the circles in the right-hand box).
先前的决策树完美地将观察结果划分为两个不同的组。这是理想决策树的特征。顶部的第一个框被称为根,在决定如何分组观察结果时是树的最重要特征。
根节点下的框被称为子节点。在前面的树中,子节点也是叶节点。叶节点是最后一组框,通常位于树的最底部。如你所料,决策树实际上是一个常规的树形结构,只不过是倒置的。
选择最佳特征
决策树如何决定哪个特征最好?最佳特征是提供最佳划分的特征,它将树划分为两个或更多不同的组,具体取决于数据中包含的类别或类的数量。让我们看以下图示:

展示良好划分的决策树
在前面的图示中,发生了以下情况:
-
该树将根节点中的数据划分为两个不同的组。
-
在左侧组中,我们看到有两个三角形和一个圆形。
-
在右侧组中,我们看到有两个圆形和一个三角形。
-
由于树将每个类的大多数元素分配到一个组中,我们可以说,在将数据划分成不同组方面,树做得很好。
让我们看另一个例子——这次是一个划分不好的例子。考虑下面的图示:

展示坏划分的决策树
在前面的图示中,发生了以下情况:
-
该树将根节点中的数据划分成四个不同的组。从本身来看,这是不好的,因为显然只有两种类别(三角形和圆形)。
-
此外,每个组都有一个三角形和一个圆形。
-
在这四个组中没有任何一个组有明显的主要类别或类别。每个组中有 50%的某个类别;因此,除非树依赖于更多特征,否则无法得出最终决策,这样会增加树的复杂性。
基尼系数
决策树用来判断根节点的度量被称为基尼系数。基尼系数的值越高,说明这个特征在将数据划分为不同组方面的效果越好。为了学习如何计算特征的基尼系数,我们来看一下以下图示:

计算基尼系数
在前面的图示中,发生了以下情况:
-
该特征将数据划分成两个组。
-
在左侧组中,我们有两个三角形和一个圆形。
-
因此,左侧组的基尼系数为(2 个三角形/3 个总数据点)² + (1 个圆形/3 个总数据点)²。
-
计算此值的方法如下:
0.55。 -
基尼系数为 0.55 表示该树的根节点以这样的方式划分数据:每个组都有一个主要类别。
-
一个完美的根特征的基尼系数为 1。这意味着每个组只有一个类/类别。
-
一个不好的根特征的基尼系数为 0.5,这意味着组内没有明显的类或类别。
实际上,决策树是以递归方式构建的,树会选择一个随机属性作为根节点,然后计算该属性的基尼系数。它会一直这样做,直到找到能够最好地将数据在节点中划分为具有不同类别和类别的属性。
在 scikit-learn 中实现决策树分类器
在本节中,您将学习如何在 scikit-learn 中实现决策树分类器。我们将使用相同的欺诈检测数据集。第一步是将数据集加载到 Jupyter Notebook 中。我们可以使用以下代码来实现:
import pandas as pd
df = pd.read_csv('fraud_prediction.csv')
下一步是将数据拆分为训练集和测试集。我们可以使用以下代码实现:
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
我们现在可以通过以下代码,在训练数据上构建初始决策树分类器,并在测试数据上测试其准确性:
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(criterion = 'gini', random_state = 50)
#Fitting on the training data
dt.fit(X_train, y_train)
#Testing accuracy on the test data
dt.score(X_test, y_test)
在前面的代码中,我们执行以下操作:
-
首先,我们从 scikit-learn 导入
DecisionTreeClassifier。 -
然后,我们用两个参数初始化
DecisionTreeClassifier对象。第一个是criterion,它是树递归选择最重要特征的度量方式,在本例中是基尼系数。第二个是random_state,设置为 50,以便每次运行时,模型都会产生相同的结果。 -
最后,我们在训练数据上拟合模型,并在测试数据上评估其准确性。
决策树的超参数调优
决策树有大量的超参数,需要微调才能得到最优模型,从而尽可能减少泛化误差。在本节中,我们将重点讨论两个特定的超参数:
-
最大深度: 这是决策树可以生长的最大子节点数,直到树被截断。例如,如果将其设置为 3,则树将使用三个子节点,并在无法再生长时截断树。
-
最小叶子样本数: 这是在叶节点中需要存在的最小样本数或数据点。叶节点是树的最后一个节点。如果这个参数设置为 0.04,它告诉树必须生长到最后一个节点,其中包含数据总样本的 4%。
为了优化理想的超参数并提取最佳的决策树,我们使用 scikit-learn 中的GridSearchCV模块。我们可以使用以下代码进行设置:
from sklearn.model_selection import GridSearchCV
#Creating a grid of different hyperparameters
grid_params = {
'max_depth': [1,2,3,4,5,6],
'min_samples_leaf': [0.02,0.04, 0.06, 0.08]
}
#Building a 10 fold Cross Validated GridSearchCV object
grid_object = GridSearchCV(estimator = dt, param_grid = grid_params, scoring = 'accuracy', cv = 10, n_jobs = -1)
在前面的代码中,我们执行以下操作:
-
我们首先从 scikit-learn 导入
GridSearchCV模块。 -
接下来,我们创建一个包含超参数可能值的字典,并将其存储为
grid_params。 -
最后,我们创建一个
GridSearchCV对象,使用决策树分类器作为估算器;即包含超参数值的字典。 -
我们将
scoring参数设置为accuracy,因为我们希望提取GridSearchCV找到的最佳模型的准确度。
然后,我们使用以下代码将此网格对象拟合到训练数据上:
#Fitting the grid to the training data
grid_object.fit(X_train, y_train)
然后,我们可以使用以下代码提取最佳参数集:
#Extracting the best parameters
grid_object.best_params_
上述代码的输出表明,最大深度为 1,叶节点的最小样本数为 0.02 是此数据的最佳参数。我们可以使用这些最优参数,并使用以下代码构建一个新的决策树:
#Extracting the best parameters
grid_object.best_params_
可视化决策树
构建并实现决策树来解决问题的一个最佳方面是,它可以通过决策树图进行轻松解释,展示你构建的算法如何工作。为了可视化一个简单的决策树,应用于欺诈检测数据集,我们使用以下代码:
#Package requirements
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.externals.six import StringIO
from IPython.display import Image
from sklearn.tree import export_graphviz
import pydotplus
from sklearn import tree
我们首先导入所需的包。这里的新包如下:
-
StringIO -
Image -
export_graphviz -
pydotplus -
tree
包的安装在第一章中进行了说明,《引入机器学习与 scikit-learn》。
接着,我们读取数据集并初始化一个决策树分类器,如下代码所示:
#Reading in the data
df = pd.read_csv('fraud_prediction.csv')
df = df.drop(['Unnamed: 0'], axis = 1)
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
#Initializing the DT classifier
dt = DecisionTreeClassifier(criterion = 'gini', random_state = 50, max_depth= 5)
接下来,我们将树拟合到特征和目标上,然后分别提取特征名称:
#Fitting the classifier on the data
dt.fit(features, target)
#Extracting the feature names
feature_names = df.drop('isFraud', axis = 1)
然后,我们可以使用以下代码可视化决策树:
#Creating the tree visualization
data = tree.export_graphviz(dt, out_file=None, feature_names= feature_names.columns.values, proportion= True)
graph = pydotplus.graph_from_dot_data(data)
# Show graph
Image(graph.create_png())
在上面的代码中,我们执行了以下操作:
-
我们使用
tree.export_graphviz()函数构建决策树对象,并将其存储在一个名为data的变量中。 -
该函数使用了几个参数:
dt是你构建的决策树;out_file设置为None,因为我们不想将树的可视化结果保存到 Jupyter Notebook 以外的任何文件中;feature_names是我们之前定义的特征名称;proportion设置为True(稍后会详细解释)。 -
接下来,我们构建包含树中数据的图形,以便通过使用
pydotplus.graph_from_dot_data()函数将决策树图可视化,这个函数作用于包含决策树数据的data变量。 -
最后,我们通过
Image()函数可视化决策树,将决策树图传递给它。
这将得到一个类似于下图所示的决策树:

结果决策树
这棵树一开始可能看起来比较复杂,但其实并不是!为了理解这棵树,我们先考虑根节点和前两个子节点。这在下面的图示中进行了说明:

决策树的片段
在上面的图示中,请注意以下几点:
-
在根节点中,树已识别出“step”特征为具有最高 Gini 值的特征。
-
根节点通过这样的方式进行分裂:71%的数据(即 0.71)进入非欺诈交易类别,而 29%的数据(即 0.29)进入欺诈交易类别。
-
如果步骤大于或等于 7.5(右侧),则所有交易都被分类为欺诈交易。
-
如果步骤小于或等于 7.5(左侧),则 99.6%的交易(即 0.996)被分类为非欺诈交易,而 0.4%的交易(即 0.004)被分类为欺诈交易。
-
如果金额大于或等于 4,618,196.0,则所有交易都被分类为欺诈交易。
-
如果金额小于或等于 4,618,196.0,则 99.6%的交易(即 0.996)被分类为非欺诈交易,而 0.4%的交易(即 0.004)被分类为欺诈交易。
请注意,决策树实际上仅仅是一组“如果-那么”规则,这些规则是以嵌套的方式构建的。
随机森林分类器
现在你已经从最基础的层面理解了决策树的核心原理,接下来我们将探索什么是随机森林。随机森林是一种集成学习方法。集成学习方法是通过多个机器学习模型共同做出决策的方式。
让我们考虑以下图示:

集成学习的概念
随机森林算法的操作流程如下:
-
假设你最初有一个包含 100 个特征的数据集。
-
从这里开始,我们将首先构建一个包含 10 个特征的决策树。这些特征是随机选择的。
-
现在,使用剩余的 90 个特征中的随机选择,我们构建下一个决策树,同样使用 10 个特征。
-
这个过程会继续,直到没有更多特征可以用来构建决策树。
-
到目前为止,我们已经有了 10 棵决策树,每棵树有 10 个特征。
-
每棵决策树被称为随机森林的基础估计器。
-
因此,我们有一片树林,每棵树都是使用一组随机选择的 10 个特征构建的。
算法的下一步是做出预测。为了更好地理解随机森林算法如何进行预测,考虑以下图示:

在随机森林中进行预测的过程
在前面的图示中,发生了以下情况:
-
假设随机森林中有 10 棵决策树。
-
每棵决策树对进入的数据做出单一的预测。
-
如果六棵树预测类别 A,四棵树预测类别 B,那么随机森林算法的最终预测结果是类别 A,因为它获得了多数票。
-
基于多个模型的输出进行投票预测的过程被称为集成学习。
现在你已经了解了算法的内部工作原理,我们可以使用 scikit-learn 来实现它!
在 scikit-learn 中实现随机森林分类器
在这一部分中,我们将在 scikit-learn 中实现随机森林分类器。第一步是读取数据,并将其拆分为训练集和测试集。我们可以使用以下代码来完成:
import pandas as pd
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the index
df = df.drop(['Unnamed: 0'], axis = 1)
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
下一步是构建随机森林分类器。我们可以使用以下代码来实现:
from sklearn.ensemble import RandomForestClassifier
#Initiliazing an Random Forest Classifier with default parameters
rf_classifier = RandomForestClassifier(random_state = 50)
#Fitting the classifier on the training data
rf_classifier.fit(X_train, y_train)
#Extracting the scores
rf_classifier.score(X_test, y_test)
在上面的代码块中,我们执行以下操作:
-
我们首先从 scikit-learn 导入
RandomForestClassifier。 -
接下来,我们初始化一个随机森林分类器模型。
-
然后,我们将该模型拟合到训练数据,并在测试数据上评估其准确性。
随机森林算法的超参数调优
在这一部分中,我们将学习如何优化随机森林算法的超参数。由于随机森林本质上是基于多个决策树,因此它的超参数与决策树非常相似。为了优化超参数,我们使用以下代码:
from sklearn.model_selection import GridSearchCV
#Creating a grid of different hyperparameters
grid_params = {
'n_estimators': [100,200, 300,400,5000],
'max_depth': [1,2,4,6,8],
'min_samples_leaf': [0.05, 0.1, 0.2]
}
#Building a 3 fold Cross-Validated GridSearchCV object
grid_object = GridSearchCV(estimator = rf_classifier, param_grid = grid_params, scoring = 'accuracy', cv = 3, n_jobs = -1)
#Fitting the grid to the training data
grid_object.fit(X_train, y_train)
#Extracting the best parameters
grid_object.best*params* #Extracting the best model
rf_best = grid_object.best*estimator_*
在上面的代码块中,我们执行以下操作:
-
我们首先导入
GridSearchCV包。 -
我们初始化一个包含超参数值的字典。
max_depth和min_samples_leaf的值类似于决策树的超参数。 -
然而,
n_estimators是一个新参数,表示在做最终预测时,随机森林算法考虑的树的总数。 -
然后,我们构建并拟合
gridsearch对象到训练数据,并提取出最佳参数。 -
然后,使用这些最佳超参数提取出最优模型。
AdaBoost 分类器
在这一部分中,你将了解 AdaBoost 分类器的内部工作原理,以及提升(boosting)概念如何帮助你获得更好的结果。提升是一种集成机器学习方法,其中一个机器学习模型通过学习之前构建的模型的错误,从而提高最终预测的准确性。
AdaBoost 代表自适应提升,它是一种提升算法,重点关注初始预测模型出错的数据行。这样,下一模型就不会犯同样的错误。
AdaBoost 算法工作的过程在下图中进行了说明:

AdaBoost 算法概述
在上述 AdaBoost 算法的示意图中,发生了以下情况:
-
第一个决策树被构建,并输出一组预测结果。
-
第一个决策树预测错误的样本会被赋予一个权重
w。这意味着,如果权重设置为 2,那么该样本的两个实例会被加入数据集中。 -
这使得决策树 2 能够以更快的速度学习,因为我们有更多的样本数据,这些样本在之前的预测中出现了错误。
-
这个过程会一直重复,直到所有树都构建完成。
-
最后,收集所有树的预测结果,并启动加权投票以确定最终预测。
在 scikit-learn 中实现 AdaBoost 分类器
在本节中,我们将学习如何在 scikit-learn 中实现 AdaBoost 分类器,以预测一个交易是否为欺诈交易。像往常一样,第一步是导入数据并将其拆分为训练集和测试集。
这可以通过以下代码完成:
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the index
df = df.drop(['Unnamed: 0'], axis = 1)
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
下一步是构建 AdaBoost 分类器。我们可以使用以下代码实现:
from sklearn.ensemble import AdaBoostClassifier
#Initialize a tree (Decision Tree with max depth = 1)
tree = DecisionTreeClassifier(max_depth=1, random_state = 42)
#Initialize an AdaBoost classifier with the tree as the base estimator
ada_boost = AdaBoostClassifier(base_estimator = tree, n_estimators=100)
#Fitting the AdaBoost classifier to the training set
ada_boost.fit(X_train, y_train)
#Extracting the accuracy scores from the classifier
ada_boost.score(X_test, y_test)
在前面的代码块中,我们执行了以下操作:
-
我们首先从 scikit-learn 导入
AdaBoostClassifier包。 -
接下来,我们初始化一个决策树,作为我们 AdaBoost 分类器的基础。
-
然后我们构建 AdaBoost 分类器,基学习器为决策树,并指定总共需要 100 棵决策树。
-
最后,我们将分类器拟合到训练数据中,并从测试数据中提取准确率评分。
AdaBoost 分类器的超参数调优
在本节中,我们将学习如何调整 AdaBoost 分类器的超参数。AdaBoost 分类器只有一个需要关注的参数——基学习器的数量,或决策树的数量。
我们可以使用以下代码优化 AdaBoost 分类器的超参数:
from sklearn.model_selection import GridSearchCV
#Creating a grid of hyperparameters
grid_params = {
'n_estimators': [100,200,300]
}
#Building a 3 fold CV GridSearchCV object
grid_object = GridSearchCV(estimator = ada_boost, param_grid = grid_params, scoring = 'accuracy', cv = 3, n_jobs = -1)
#Fitting the grid to the training data
grid_object.fit(X_train, y_train)
#Extracting the best parameters
grid_object.best*params*
#Extracting the best model
ada_best = grid_object.best_estimator_
在前面的代码中,我们执行了以下操作:
-
我们首先导入
GridSearchCV包。 -
我们初始化了一个超参数值字典。在这种情况下,
n_estimators是决策树的数量。 -
然后我们构建并拟合
gridsearch对象到训练数据,并提取最佳参数。 -
然后使用这些最优超参数提取最佳模型。
回归树
你已经学习了如何使用决策树将预测分类为属于特定的类别或类别。然而,决策树也可以用于解决与预测数值结果相关的问题。在本节中,你将学习三种基于树的算法,这些算法可以在 scikit-learn 中实现,以预测数值结果,而不是类别:
-
决策树回归器
-
随机森林回归器
-
梯度提升树
决策树回归器
当我们有非线性数据时,线性回归模型可能不是最佳选择。在这种情况下,选择一个能够完全捕捉数据非线性的模型是有意义的。决策树回归器可以像线性回归模型一样用于预测数值结果。
对于决策树回归器,我们使用均方误差,而不是基尼指数,来决定树的构建方式。你将在第八章中详细了解均方误差,性能评估方法。简而言之,均方误差用于告诉我们预测误差率。
请考虑下图所示的树:

一个用于回归的决策树示例
在考虑前面的决策树图示时,请注意以下几点:
-
我们试图预测通过树来进行的移动交易金额。
-
当树试图决定如何分割时,它会选择一个节点,使得该节点中的目标值最接近目标变量的均值。
-
你会注意到,当你沿着树的左侧,沿着
True的分支向下走时,节点的均方误差会逐渐减小。 -
因此,节点是以递归的方式构建的,从而减少了整体的均方误差,进而获得了
True值。 -
在前面的树中,如果原始余额小于 600,281,则金额(这里用
value表示)为 80,442;如果大于 600,281,则金额为 1,988,971。
在 scikit-learn 中实现决策树回归器
在这一节中,你将学习如何在 scikit-learn 中实现决策树回归器。第一步是导入数据,并创建特征和目标变量。我们可以使用以下代码来完成:
import pandas as pd
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the index
df = df.drop(['Unnamed: 0'], axis = 1)
#Creating the features
features = df.drop('amount', axis = 1).values
target = df['amount'].values
注意,在回归的情况下,目标变量是金额,而不是isFraud列。
接下来,我们将数据分成训练集和测试集,并构建决策树回归器,如以下代码所示:
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
#Splitting the data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42)
#Building the decision tree regressor
dt_reg = DecisionTreeRegressor(max_depth = 10, min_samples_leaf = 0.2, random_state= 50)
#Fitting the tree to the training data
dt_reg.fit(X_train, y_train)
在前面的代码中,我们做了以下操作:
-
我们首先导入所需的包,并将数据分成训练集和测试集。
-
接下来,我们使用
DecisionTreeRegressor()函数构建决策树回归器。 -
我们指定了两个超参数:
max_depth,它告诉算法树必须有多少个分支,和min_sample_leaf,它告诉树每个节点必须包含的最小样本数。在这种情况下,后者被设置为 20%,即总数据的 0.2。 -
random_state设置为 50,确保每次运行代码时构建相同的树。 -
然后我们将树拟合到训练数据上。
可视化决策树回归器
就像我们可视化决策树分类器一样,我们也可以可视化决策树回归器。不同的是,显示的将是目标变量的值,而不是树节点所属的类别或类别。
我们可以使用以下代码来可视化决策树回归器:
#Package requirements
from sklearn.tree import DecisionTreeClassifier
from sklearn.externals.six import StringIO
from IPython.display import Image
from sklearn.tree import export_graphviz
import pydotplus
from sklearn import tree
#Extracting the feature names
feature_names = df.drop('amount', axis = 1)
#Creating the tree visualization
data = tree.export_graphviz(dt_reg, out_file=None, feature_names= feature_names.columns.values, proportion= True)
graph = pydotplus.graph_from_dot_data(data)
# Show graph
Image(graph.create_png())
代码与决策树分类器的实现方法完全相同,这里不会详细讨论。这样就得到了如下图所示的决策树回归器:

决策树回归器的可视化
随机森林回归器
随机森林回归器以决策树回归器为基本估计器,使用类似于随机森林分类器的方法进行预测,如下图所示:

在随机森林回归器中做最终预测
随机森林分类器和随机森林回归器之间唯一的区别在于,后者的基估计器是决策树回归器。
在 scikit-learn 中实现随机森林回归器
在本节中,您将学习如何在 scikit-learn 中实现随机森林回归器。第一步是导入数据并将其划分为训练集和测试集。可以使用以下代码来完成此操作:
import pandas as pd
from sklearn.model_selection import train_test_split
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the index
df = df.drop(['Unnamed: 0'], axis = 1)
#Creating the features and target arrays
features = df.drop('amount', axis = 1).values
target = df['amount'].values
#Splitting the data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42)
下一步是构建随机森林回归器。我们可以使用以下代码来完成此操作:
from sklearn.ensemble import RandomForestRegressor
#Initiliazing an Random Forest Regressor with default parameters
rf_reg = RandomForestRegressor(max_depth = 10, min_samples_leaf = 0.2, random_state = 50)
#Fitting the regressor on the training data
rf_reg.fit(X_train, y_train)
在前面的代码中,我们做了以下操作:
-
我们首先从 scikit-learn 中导入
RandomForestRegressor模块。 -
然后,我们初始化一个随机森林回归器对象,命名为
rf_reg,为每棵决策树设置最大深度为 10,并将每棵树的数据和样本数最小值设置为总数据量的 20%。 -
然后,我们将树拟合到训练集上。
梯度提升树
在本节中,您将学习如何将梯度提升树用于回归,并了解如何在 scikit-learn 中实现这一过程。
在本章前面学习的 AdaBoost 分类器中,错误分类的样本会被赋予权重。而在梯度提升树中,不使用权重,而是将残差误差作为每棵树的标签,以便进行未来的预测。以下图示展示了这一概念:

以下是前面图示中发生的过程:
-
第一棵决策树使用您提供的数据和目标变量 Y 进行训练。
-
然后,我们计算该树的残差误差。
-
残差误差是通过预测值和实际值之间的差异来计算的。
-
第二棵树现在已开始训练,使用残差作为目标。
-
构建多个树的过程是迭代的,并且会持续进行,直到达到我们指定的基估计器数量。
-
最终预测是通过将第一个树预测的目标值加上所有其他树的残差与收缩因子的乘积来完成的。
-
收缩因子是我们控制梯度提升过程速率的一个因子。
-
较小的收缩因子(学习率)意味着算法会学习得更快,因此需要通过更多的基估计器(即决策树)来防止过拟合。
-
较大的收缩因子(学习率)意味着算法会学习得更慢,因此需要较少的树来减少计算时间。
在 scikit-learn 中实现梯度提升树
在本节中,我们将学习如何在 scikit-learn 中实现梯度提升回归器。首先,像往常一样,我们需要导入数据集,定义特征和目标数组,并将数据划分为训练集和测试集。可以使用以下代码完成此操作:
import pandas as pd
from sklearn.model_selection import train_test_split
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the index
df = df.drop(['Unnamed: 0'], axis = 1)
#Creating the features
features = df.drop('amount', axis = 1).values
target = df['amount'].values
#Splitting the data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42)
下一步是构建梯度提升回归器。这可以通过以下代码实现:
from sklearn.ensemble import GradientBoostingRegressor
#Initializing an Gradient Boosted Regressor with default parameters
gb_reg = GradientBoostingRegressor(max_depth = 5, n_estimators = 100, learning_rate = 0.1, random_state = 50)
#Fitting the regressor on the training data
gb_reg.fit(X_train, y_train)
在前面的代码中,我们做了以下操作:
-
我们首先从 scikit-learn 导入
GradientBoostingRegressor。 -
然后,我们构建一个梯度提升回归器对象,包含三个主要参数:每棵树的最大深度、树的总数和学习率。
-
然后,我们将回归器拟合到训练数据上。
集成分类器
本章探讨了集成学习的概念,介绍了随机森林、AdaBoost 和梯度提升树。然而,这一概念可以扩展到树以外的分类器。
如果我们建立了逻辑回归、随机森林和 k-近邻分类器,并希望将它们组合在一起,通过多数投票提取最终预测结果,那么我们可以使用集成分类器来实现。
通过以下图表可以更好地理解这个概念:

使用投票分类器进行集成学习来预测欺诈交易
在查看前面的图表时,请注意以下几点:
-
随机森林分类器预测某一交易为欺诈交易,而其他两个分类器预测该交易不是欺诈交易。
-
投票分类器看到三者中有两项预测为非欺诈,因此,输出最终预测为非欺诈。
在 scikit-learn 中实现投票分类器
在本节中,您将学习如何在 scikit-learn 中实现投票分类器。第一步是导入数据,创建特征和目标数组,并创建训练集和测试集划分。可以使用以下代码来完成:
import pandas as pd
from sklearn.model_selection import train_test_split
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the index
df = df.drop(['Unnamed: 0'], axis = 1)
#Splitting the data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42)
接下来,我们将构建两个包括投票分类器的分类器:决策树分类器和随机森林分类器。这可以通过以下代码实现:
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
#Initializing the DT classifier
dt = DecisionTreeClassifier(criterion = 'gini', random_state = 50)
#Fitting on the training data
dt.fit(X_train, y_train)
#Initiliazing an Random Forest Classifier with default parameters
rf_classifier = RandomForestClassifier(random_state = 50)
#Fitting the classifier on the training data
rf_classifier.fit(X_train, y_train)
接下来,我们将使用以下代码构建投票分类器:
from sklearn.ensemble import VotingClassifier
#Creating a list of models
models = [('Decision Tree', dt), ('Random Forest', rf_classifier)]
#Initialize a voting classifier
voting_model = VotingClassifier(estimators = models)
#Fitting the model to the training data
voting_model.fit(X_train, y_train)
#Evaluating the accuracy on the test data
voting_model.score(X_test, y_test)
在前面的代码中,我们做了以下操作:
-
我们首先从 scikit-learn 导入
VotingClassifier模块。 -
接下来,我们创建一个包含所有要在投票分类器中使用的模型的列表。
-
在分类器列表中,每个模型都以元组的形式存储,其中包括模型的名称(字符串)和模型本身。
-
然后,我们初始化一个投票分类器,使用第二步中构建的模型列表。
-
最后,将模型拟合到训练数据上,并从测试数据中提取准确度。
总结
尽管本章较长,但您已经进入了基于树的算法世界,并带着一套可以解决小规模和大规模问题的工具离开。总结一下,您已经学习了以下内容:
-
如何使用决策树进行分类和回归
-
如何使用随机森林进行分类和回归
-
如何使用 AdaBoost 进行分类
-
如何使用梯度提升树进行回归
-
投票分类器如何用于将不同的模型组合成一个单一模型
在接下来的章节中,你将学习如何处理没有目标变量或标签的数据,以及如何进行无监督机器学习来解决此类问题!
第七章:使用无监督机器学习进行数据聚类
您在实际应用中遇到的大部分数据都不会带有标签。如果数据没有标签,您无法应用有监督的机器学习技术。无监督机器学习通过将数据分组为聚类来解决此问题;然后我们可以基于这些聚类分配标签。
一旦数据被聚类成特定数量的组,我们就可以继续为这些组分配标签。无监督学习是您作为数据科学家需要实施的第一步,之后才能应用有监督的机器学习技术(如分类)进行有意义的预测。
无监督机器学习算法的一个常见应用是客户数据,这些数据可以在各行各业中找到。作为数据科学家,您的工作是找到可以细分的客户群体,并向其推送有针对性的产品和广告。
在本章中,您将学习以下主题:
-
k-means 算法及其内部工作原理,用于对无标签数据进行聚类
-
在 scikit-learn 中实现 k-means 算法
-
使用特征工程优化无监督机器学习
-
聚类可视化
-
从无监督学习到有监督学习
技术要求
您需要在系统中安装 Python 3.6 或更高版本,Pandas ≥ 0.23.4,Scikit-learn ≥ 0.20.0,NumPy ≥ 1.15.1,Matplotlib ≥ 3.0.0,Pydotplus ≥ 2.0.2,Image ≥ 3.1.2,Seaborn ≥ 0.9.0 和 SciPy ≥ 1.1.0。
本章的代码文件可以在 GitHub 上找到:
github.com/PacktPublishing/Machine-Learning-with-scikit-learn-Quick-Start-Guide/blob/master/Chapter_07.ipynb.
请观看以下视频,查看代码的实际应用:
k-means 算法
在本节中,您将学习 k-means 算法的工作原理,以便将数据聚类成有逻辑意义的组。
让我们考虑一组点,如下图所示:

一组随机点
质心分配
算法的第一步是分配一组随机质心。假设我们要找到两个不同的聚类或组,算法可以分配两个质心,如下图所示:

由星号表示的质心
在前面的图示中,星号代表算法的质心。请注意,在这种情况下,聚类的中心完美地符合两个不同的组。这是最理想的情况。实际上,均值(或质心)是随机分配的,并且在每次迭代中,聚类的质心都会向两个组的中心靠近。
这个算法被称为 k-means 算法,因为我们试图找到一组点的均值作为质心。由于均值只能针对一组数值点计算,因此这种聚类算法只能处理数值数据。
实际上,将这些点分组为两个不同的聚类并不像看起来那么简单。该过程的可视化表示可以如下所示:

k-means 算法中分配质心的过程
在前面的图示中,随机分配质心的过程从左上角开始。随着我们向下并朝右上角移动,请注意质心如何逐渐靠近两个不同组的中心。实际上,算法没有一个最佳的终止点来停止迭代。
算法什么时候停止迭代?
通常,算法会寻找两个度量标准,以停止迭代过程:
-
形成的不同组(或聚类)之间的距离
-
每个点与聚类质心之间的距离
聚类形成的最佳情况是,当不同组或聚类之间的距离尽可能大,而每个点与聚类质心之间的距离尽可能小。
在 scikit-learn 中实现 k-means 算法
现在你已经理解了 k-means 算法的内部工作原理,我们可以继续在 scikit-learn 中实现它。我们将使用在之前章节中使用的相同的欺诈检测数据集。关键的区别是,我们将丢弃包含标签的目标特征,并识别用于检测欺诈的两个聚类。
创建基础 k-means 模型
为了将数据集加载到工作空间并丢弃包含标签的目标特征,我们使用以下代码:
import pandas as pd
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the target feature & the index
df = df.drop(['Unnamed: 0', 'isFraud'], axis = 1)
接下来,我们可以实现具有两个聚类均值的 k-means 算法。选择使用两个聚类均值是任意的,因为我们知道应该有两个不同的聚类,分别对应两个标签:欺诈和非欺诈交易。我们可以通过以下代码来实现:
from sklearn.cluster import KMeans
#Initializing K-means with 2 clusters
k_means = KMeans(n_clusters = 2)
#Fitting the model on the data
k_means.fit(df)
在之前的代码中,首先,我们从 scikit-learn 中导入KMeans包并初始化一个具有两个聚类的模型。然后,我们使用.fit()函数将该模型拟合到数据上。这将产生一组标签作为输出。我们可以使用以下代码提取这些标签:
#Extracting labels
target_labels = k_means.predict(df)
#Printing the labels
target_labels
上述代码生成的输出是每个移动交易的标签数组,如下所示:

标签数组
现在我们有了一组标签,我们知道每个交易属于哪个聚类。标签为 0 的移动交易属于一组,而标签为 1 的交易属于第二组。
最佳的聚类数量
在解释 k-means 算法如何工作的过程中,我们提到过,当算法找到最佳的聚类数量时,它会终止。然而,当使用 scikit-learn 随机选择聚类时,这种情况并不总是成立。在这种情况下,我们需要找到最佳的聚类数量。
我们可以通过一种被称为惯性的度量来实现这一点。惯性度量的是聚类中数据点与其质心的接近程度。显然,较低的惯性意味着组或聚类紧密地聚集在一起,这样是比较好的。
为了计算模型的惯性值,我们使用以下代码:
# Inertia of present model
k_means.inertia_
上述代码产生了一个惯性值为 4.99 × 10 ^ 17,这个值相对于其他不同聚类数所产生的惯性值来说极大(后面会解释),因此不是一个好的惯性值。这表明个别数据点分布较广,并没有紧密地聚集在一起。
在大多数情况下,我们并不确切知道最佳的聚类数量,因此我们需要为不同的聚类数绘制惯性得分。我们可以通过以下代码来实现:
import matplotlib.pyplot as plt
import seaborn as sns
#Initialize a list of clusters from 1 to 10 clusters
clusters = [1,2,3,4,5,6,7,8,9,10]
#Create an empty list in order to store the inertia values
inertia_values = []
for cluster in clusters:
#Build a k-means model for each cluster value
k_means = KMeans(n_clusters = cluster)
#Fit the model to the data
k_means.fit(df)
# Store inertia value of each model into the empty list
inertia_values.append(k_means.inertia_)
# Plot the result
plt.lineplot(x = clusters, y = inertia_values)
plt.xlabel('Number of Clusters')
plt.ylabel('Inertia Value')
plt.title('Number of Clusters Vs. Inertia Values')
plt.show()
这将产生以下图表:

惯性作为聚类数的函数
在上面的代码中,首先,我们创建了一个包含 1 到 10 值的聚类列表。每个值表示将用于机器学习模型中的聚类数量。接着,我们创建了一个空列表,用来存储每个模型所产生的惯性值。
接下来,我们遍历聚类列表,并为列表中每个聚类值构建并评估一个 k-means 模型。每个模型现在会产生一个惯性值,该值会存储在我们在代码块开始时初始化的列表中。然后,使用 matplotlib 绘制一个简单的折线图,x 轴为聚类数,y 轴为相应的惯性值。
该图表告诉我们,当聚类数为 10 时,惯性值最低。然而,拥有过多的聚类也是我们需要避免的事情,因为过多的组别并不能帮助我们很好地进行泛化,而且每个组别的特征会变得非常具体。
因此,选择问题的最佳聚类数量的理想方式是,假设我们事先没有关于我们想要的组数的先验信息,找到图中的肘部点。
肘部点是惯性值减少速率减缓的那个点。肘部点在下图中得到了说明:

图表的肘部点
在前面的图表中,很明显肘部点对应于四个聚类。这可能意味着除了标准的“欺诈”和“非欺诈”分类外,存在四种不同类型的欺诈交易。然而,由于我们事先知道数据集有一个二元目标特征,包含两个类别,我们不会深入探讨为什么四个聚类是该数据集的理想聚类数。
优化的特征工程
数据集中的特征工程是一个基本概念,用于提高模型的性能。将特征调整到算法设计的最佳状态是有益的,因为它可以提高准确性,同时减少泛化误差。你将学习到的几种用于优化数据集的特征工程技术如下:
-
缩放
-
主成分分析
缩放
缩放是标准化数据的过程,使每个特征下的值落在某个特定范围内,如-1 到+1. 为了缩放数据,我们用某一特征的每个值减去该特征的均值,再除以该特征的方差。为了缩放我们欺诈检测数据集中的特征,我们使用以下代码:
from sklearn.preprocessing import StandardScaler
#Setting up the standard scaler
scale_data = StandardScaler()
#Scaling the data
scale_data.fit(df)
df_scaled = scale_data.transform(df)
#Applying the K-Means algorithm on the scaled data
#Initializing K-means with 2 clusters
k_means = KMeans(n_clusters = 2)
#Fitting the model on the data
k_means.fit(df_scaled)
# Inertia of present model
k_means.inertia_
在前面的代码中,我们使用StandardScalar()函数来缩放我们的数据框,然后我们在缩放后的数据上构建了一个包含两个聚类的 k-means 模型。评估模型的惯性后,输出的值为 295,000,明显优于没有缩放时模型输出的4.99 × 10¹⁷。
然后,我们可以使用与之前相同的代码绘制聚类数与惯性值的图表,唯一的不同是将原始数据框替换为缩放后的数据框:
#Initialize a list of clusters from 1 to 10 clusters
clusters = [1,2,3,4,5,6,7,8,9,10]
#Create an empty list in order to store the inertia values
inertia_values = []
for cluster in clusters:
#Build a k-means model for each cluster value
k_means = KMeans(n_clusters = cluster)
#Fit the model to the data
k_means.fit(df_scaled)
# Store inertia value of each model into the empty list
inertia_values.append(k_means.inertia_)
# Plot the result
sns.lineplot(x = clusters, y = inertia_values)
plt.xlabel('Number of Clusters')
plt.ylabel('Inertia Value')
plt.title('Number of Clusters Vs. Inertia Values')
plt.show()
这将产生以下输出:

缩放后的聚类最佳数量
我们注意到,前面的图表并没有一个非常明显的肘部点,在这个点上惯性值的下降速率较低。然而,如果我们仔细观察,可以在 8 个聚类处找到这个点。
主成分分析
主成分分析(PCA)是降维的一个子集。降维是指减少对预测模型没有预测价值的特征的过程。我们还优化并提高了算法处理的计算效率。这是因为一个特征较少的数据集会让算法更容易更快地检测到模式。
PCA 的第一步叫做去相关化。相互高度相关的特征对预测模型没有价值。因此,在去相关化步骤中,PCA 将两个高度相关的特征的数据点展开,使其在轴上对齐,并且不再相关。这个过程可以如下图所示:

去相关化过程
一旦特征被去相关化,主成分(或特征)就会从数据中提取出来。这些特征具有较高的方差,并且提供了对预测模型最有价值的信息。方差较低的特征会被丢弃,因此数据集的维度数量减少。
为了使用 PCA 进行降维,我们使用以下代码:
from sklearn.decomposition import PCA
#Initialize a PCA model with 5 features
pca_model = PCA(n_components = 5)
#Fit the model to the scaled dataframe
pca_model.fit(df_scaled)
#Transform the features so that it is de-correlated
pca_transform = pca_model.transform(df_scaled)
#Check to see if there are only 5 features
pca_transform.shape
在前面的代码中,首先,我们从 scikit-learn 导入PCA方法。接下来,我们初始化一个具有五个主成分的 PCA 模型。在这里,我们指定要将数据集减少到仅包含五个最重要的特征。
然后,我们将 PCA 模型拟合到数据框并进行转换,以获得去相关的特征。检查最终特征数组的形状,我们可以看到它只有五个特征。最后,我们使用仅包含主成分特征的 k-means 模型,如下所示的代码所示:
#Applying the K-Means algorithm on the scaled data
#Initializing K-means with 2 clusters
k_means = KMeans(n_clusters = 2)#Fitting the model on the data
k_means.fit(pca_transform)
# Inertia of present model
k_means.inertia_
评估新模型的惯性改善了其性能。我们得到了比缩放模型更低的惯性值。现在,让我们评估不同主成分或特征数量的惯性分数。为此,我们使用以下代码:
#Initialize a list of principal components
components = [1,2,3,4,5,6,7,8,9,10]
#Create an empty list in order to store the inertia values
inertia_values = []
for comp in components:
#Initialize a PCA model
pca_model = PCA(n_components = comp)
#Fit the model to the dataframe
pca_model.fit(df_scaled)
#Transform the features so that it is de-correlated
pca_transform = pca_model.transform(df_scaled)
#Build a k-means model
k_means = KMeans(n_clusters = 2)
#Fit the model to the data
k_means.fit(pca_transform)
# Store inertia value of each model into the empty list
inertia_values.append(k_means.inertia_)
# Plot the result
sns.lineplot(x = components, y = inertia_values)
plt.xlabel('Number of Principal Components')
plt.ylabel('Inertia Value')
plt.title('Number of Components Vs. Inertia Values')
plt.show()
在前面的代码中,适用以下内容:
-
首先,我们初始化一个列表,用于存储我们想用来构建模型的不同主成分值。这些值从 1 到 10。
-
接下来,我们初始化一个空的列表,用于存储每个模型的惯性值。
-
使用每个主成分值,我们构建一个新的 k-means 模型,并将该模型的惯性值附加到空列表中。
-
最后,绘制惯性值与不同主成分值之间的关系图。
该图像如下所示:

惯性值与主成分数量的关系
在前面的图中,可以清楚地看到,惯性值在一个主成分时最小。
聚类可视化
当数据集中的变量/维度非常多时,直观展示你的聚类是一个不容易的任务。有两种主要方法可以用来可视化聚类的分布,如下所示:
-
t-SNE:在二维空间中创建数据集的地图
-
层次聚类:使用基于树的可视化方式,称为树状图,来创建层次结构
在本节中,您将学习如何实现这些可视化技术,以创建引人注目的集群可视化效果。
t-SNE
t-SNE 是 t-分布随机邻域嵌入 的缩写。t-SNE 的基本概念是将高维度映射到二维空间。简单来说,如果您的数据集具有超过两个特征,t-SNE 将非常适合显示您的整个数据集如何在计算机屏幕上可视化!
第一步是实现 k-means 算法,并创建一组我们可以合并到未标记数据集中的预测标签。我们可以通过使用以下代码来实现这一点:
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the target feature & the index
df = df.drop(['Unnamed: 0', 'isFraud'], axis = 1)
#Initializing K-means with 2 clusters
k_means = KMeans(n_clusters = 2)
#Fitting the model on the data
k_means.fit(df)
#Extracting labels
target_labels = k_means.predict(df)
#Converting the labels to a series
target_labels = pd.Series(target_labels)
#Merging the labels to the dataset
df = pd.merge(df, pd.DataFrame(target_labels), left_index=True, right_index=True)
#Renaming the target
df['fraud'] = df[0]
df = df.drop([0], axis = 1)
暂时不要担心前面代码段的工作原理,因为在本章的后续部分中,我们将详细解释如何将无监督机器学习问题转换为监督学习问题。
接下来,我们将创建一个 t-SNE 对象,并将其拟合到我们仅包含特征的数据点数组中。然后,我们同时转换这些特征,以便可以在二维空间中查看所有特征。这在以下代码段中完成:
from sklearn.manifold import TSNE
#Creating the features
features = df.drop('fraud', axis = 1).values
target = df['fraud'].values
#Initialize a TSNE object
tsne_object = TSNE()
#Fit and transform the features using the TSNE object
transformed = tsne_object.fit_transform(features)
在前述代码中,以下内容适用:
-
首先,我们通过使用
TSNE()函数初始化 t-SNE 对象。 -
使用 t-SNE 对象,我们使用
fit_transform()方法对我们的特征数据进行拟合和转换。
接下来,我们使用以下代码创建 t-SNE 可视化:
#Creating a t-SNE visualization
x_axis = transformed[:,0]
y_axis = transformed[:,1]
plt.scatter(x_axis, y_axis, c = target)
plt.show()
在前述代码中,以下内容适用:
-
我们从转换特征集中提取第一和第二个特征,分别作为 x 轴和 y 轴。
-
然后,我们绘制散点图,并根据先前使用 k-means 算法生成的目标标签对其进行着色。这生成以下图表:

t-SNE 可视化
在前述图中,黄色表示被分配欺诈标签的交易,而紫色表示被分配非欺诈标签的交易。(请参考图像的彩色版本。)
层次聚类
如最初讨论的那样,层次聚类技术使用树状图来可视化集群或群组。为了解释树状图的工作原理,我们将考虑一个具有四个特征的数据集。
第一步 – 将每个特征作为单独的集群
在第一步中,数据集中的每个特征被认为是其自己的集群。这在以下图表中有所说明:

每个特征作为树状图中的单个集群
每个前面图表中的特征都是一个单独的集群,现阶段如此。此算法现在搜索找到彼此最接近的两个特征,并将它们合并成一个单独的集群。
第二步 – 合并
在这一步骤中,算法将两个最接近的特征中的数据点合并到一个聚类中。这个过程在下面的图示中有所体现:

特征合并为单一聚类的过程
在前面的图示中,很明显算法已经选择了特征 2和特征 3,并决定这两个特征下的数据是彼此最接近的。
第 3 步 – 迭代
现在,算法继续迭代合并特征,直到无法再形成任何聚类。最终形成的树状图如下所示:
在前面的图示中,特征 2和特征 3被归为一个单一的聚类。然后,算法决定特征 1和特征 2与特征 3的聚类是最接近的。因此,这三个特征被归为一个组。最后,特征 4与特征 3聚为一组。
实现层次聚类
现在你已经学习了层次聚类是如何工作的,我们可以实现这个概念。为了创建一个层次聚类,我们使用以下代码:
from scipy.cluster.hierarchy import linkage
from scipy.cluster.hierarchy import dendrogram
import numpy as np
import matplotlib.pyplot as plt
#Creating an array of 4 features
array = np.array([[1,2,3,4], [5,6,7,8], [2,3,4,5], [5,6,4,3]])
feature_names = ['a', 'b', 'c', 'd']
#Creating clusters
clusters = linkage(array, method = 'complete')
#Creating a dendrogram
dendrogram(clusters, labels = feature_names, leaf_rotation = 90)
plt.show()
前面的代码将生成一个树状图,如下面的图示所示:

树状图
在前面的代码中,以下内容适用:
-
首先,我们创建一个包含四列的数组。
-
然后,我们使用
linkage函数创建聚类。在函数中,我们将method参数设置为 complete,以表示我们想要整个树状图。 -
最后,我们使用
dendrogram函数创建带有聚类的树状图。我们将标签名称设置为之前在代码中创建的特征名称列表。
从无监督学习到监督学习
无监督学习的最终目标是获取一个没有标签的数据集,并为数据集的每一行分配标签,以便我们可以通过它运行监督学习算法。这使我们能够创建利用这些标签的预测。
在本节中,你将学习如何将无监督机器学习算法生成的标签转换为一个使用这些标签的决策树。
创建标注数据集
第一步是将无监督机器学习算法(如 k-means 算法)生成的标签转换,并将其附加到数据集中。我们可以使用以下代码来实现:
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the target feature & the index
df = df.drop(['Unnamed: 0', 'isFraud'], axis = 1)
在前面的代码中,我们读取了欺诈检测数据集,并删除了目标列和索引列:
#Initializing K-means with 2 clusters
k_means = KMeans(n_clusters = 2)
#Fitting the model on the data
k_means.fit(df)
接下来,在前面的代码中,我们初始化并拟合了一个具有两个聚类的 k-means 模型:
#Extracting labels
target_labels = k_means.predict(df)
#Converting the labels to a series
target_labels = pd.Series(target_labels)
#Merging the labels to the dataset
df = pd.merge(df, pd.DataFrame(target_labels), left_index=True, right_index=True)
最终,我们通过使用predict()方法创建目标标签,并将其转换为pandas系列。然后我们将这个系列合并到数据框中,以便创建我们的标注数据集。
构建决策树
既然我们已经有了标注的数据集,我们可以创建一个决策树,将无监督学习问题转化为有监督学习问题。
为了做到这一点,我们从所有必要的包导入开始,如下所示的代码所示:
from sklearn.tree import DecisionTreeClassifier
from sklearn.externals.six import StringIO
from IPython.display import Image
from sklearn.tree import export_graphviz
import pydotplus
from sklearn import tree
接下来,我们将目标列重命名为适当的名称(当我们合并由 k-means 算法创建的目标标签时,默认生成了 0 作为名称)。我们可以通过以下代码来实现:
#Renaming the target
df['fraud'] = df[0]
df = df.drop([0], axis = 1)
接下来,我们使用以下代码构建决策树分类算法:
#Creating the features
features = df.drop('fraud', axis = 1).values
target = df['fraud'].values
#Initializing an empty DT classifier with a random state value of 42
dt_classifier = DecisionTreeClassifier(criterion = 'gini', random_state = 42)
#Fitting the classifier on the training data
dt_classifier.fit(features, target)
在前面的代码中,首先,我们创建了特征和目标变量,并初始化了一个决策树分类器。然后,我们将分类器拟合到特征和目标上。
最后,我们希望可视化决策树。我们可以通过以下代码来实现:
#Creating a data frame with the features only
features = df.drop('fraud', axis = 1)
dot_data = tree.export_graphviz(dt_classifier, out_file=None, feature_names= features.columns)
# Draw graph
graph = pydotplus.graph_from_dot_data(dot_data)
#Show graph
Image(graph.create_png())
这导致了下图所示的决策树:

创建的决策树的一部分
总结
在本章中,你了解了 k-means 算法的工作原理,以便将未标记的数据点聚类到不同的群组中。接着,你学会了如何使用 scikit-learn 实现这一点,并扩展了实现中的特征工程部分。
在学习如何使用层次聚类和 t-SNE 可视化聚类之后,你又学会了如何将多维数据集映射到二维空间。最后,你学习了如何使用决策树将无监督学习问题转化为有监督学习问题。
在接下来的(也是最后一章),你将学习如何正式评估到目前为止你所构建的所有机器学习算法的性能!
第八章:性能评估方法
性能评估的方法会根据你选择实现的机器学习算法类型有所不同。一般来说,针对分类、回归和无监督机器学习算法,会有不同的评估指标来衡量你的模型在特定任务上的表现。
在本章中,我们将探索不同的性能评估方法,帮助你更好地理解模型。章节将分为以下三个部分:
-
分类算法的性能评估
-
回归算法的性能评估
-
无监督算法的性能评估
技术要求
你需要在系统中安装 Python 3.6 或更高版本、Pandas ≥ 0.23.4、Scikit-learn ≥ 0.20.0、NumPy ≥ 1.15.1、Matplotlib ≥ 3.0.0,以及 Scikit-plot ≥ 0.3.7。
本章的代码文件可以在 GitHub 上找到:
查看以下视频,看看代码的实际效果:
为什么性能评估至关重要?
理解为什么我们首先需要评估模型的性能是非常关键的。以下是一些可能的原因,说明为什么性能评估至关重要:
-
它防止过拟合:过拟合发生在算法过度拟合数据,并做出仅针对一个数据集的特定预测。换句话说,模型无法将预测推广到它未接触过的数据。
-
它防止欠拟合:这恰恰与过拟合相反。在这种情况下,模型的性质非常通用。
-
理解预测:性能评估方法将帮助你更详细地了解模型是如何做出预测的,以及这些预测的性质和其他有用信息,例如模型的准确性。
分类算法的性能评估
为了评估分类算法的性能,我们可以考虑在本书中构建的两种分类算法:k 最近邻和逻辑回归。
第一步是将这两种算法实现到欺诈检测数据集中。我们可以通过以下代码来实现:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn import linear_model
#Reading in the fraud detection dataset
df = pd.read_csv('fraud_prediction.csv')
#Creating the features
features = df.drop('isFraud', axis = 1).values
target = df['isFraud'].values
#Splitting the data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.3, random_state = 42, stratify = target)
# Building the K-NN Classifier
knn_classifier = KNeighborsClassifier(n_neighbors=3)
knn_classifier.fit(X_train, y_train)
#Initializing an logistic regression object
logistic_regression = linear_model.LogisticRegression()
#Fitting the model to the training and test sets
logistic_regression.fit(X_train, y_train)
在前面的代码中,我们将欺诈检测数据集读取到笔记本中,并将数据分成特征和目标变量,和往常一样。然后,我们将数据分为训练集和测试集,并在训练数据中构建 k 最近邻和逻辑回归模型。
在本节中,您将学习如何评估单一模型的性能:k-最近邻。您还将学习如何比较和对比多个模型。因此,您将学习以下内容:
-
混淆矩阵
-
规范化混淆矩阵
-
曲线下面积(
auc分数) -
累积增益曲线
-
提升曲线
-
K-S 统计量图
-
校准图
-
学习曲线
-
交叉验证箱线图
本节中的一些可视化图表将需要一个名为 scikit-plot 的包。scikit-plot 包非常有效,专门用于可视化机器学习模型的各种性能指标。它特别为使用 scikit-learn 构建的模型而设计。
为了在本地机器上安装 scikit-plot,可以在终端使用 pip 安装,命令如下:
pip3 install scikit-plot
如果您使用的是 Anaconda 发行版来管理您的 Python 包,可以通过以下代码安装 scikit-plot:
conda install -c conda-forge scikit-plot
混淆矩阵
直到现在,我们一直使用准确率作为唯一的模型性能衡量标准。这是可以的,因为我们有一个平衡的数据集。平衡数据集是指每个类别的标签数量几乎相等。在我们正在处理的数据集中,8,000 个标签属于欺诈交易,12,000 个标签属于非欺诈交易。
假设有这样一种情况:90%的数据是非欺诈交易,只有 10%的交易是欺诈案件。如果分类器报告的准确率为 90%,这就没有意义,因为它所看到的大部分数据是非欺诈案件,而它看到的欺诈案件非常少。所以,即使它准确地分类了 90%的案件,也意味着它所分类的大多数案件将属于非欺诈案件。这对我们没有任何价值。
混淆矩阵是一种性能评估技术,可以用于处理数据集不平衡的情况。我们数据集的混淆矩阵如下所示:

欺诈交易的混淆矩阵
混淆矩阵的目标是最大化真正例和真负例的数量,因为这能给出正确的预测;它还最小化假阴性和假阳性的数量,因为它们给出的是错误的预测。
根据您的问题,假阳性可能比假阴性更为问题(反之亦然),因此,构建正确分类器的目标应该是以最佳的方式解决您的问题。
为了在 scikit-learn 中实现混淆矩阵,我们使用以下代码:
from sklearn.metrics import confusion_matrix
#Creating predictions on the test set
prediction = knn_classifier.predict(X_test)
#Creating the confusion matrix
print(confusion_matrix(y_test, prediction))
这将产生如下输出:

我们分类器输出的欺诈交易混淆矩阵
在前面的代码中,我们使用 .predict() 方法对测试训练数据生成一组预测结果,然后对目标变量的测试集和之前创建的预测结果使用 confusion_matrix() 函数。
前面的混淆矩阵看起来几乎完美,因为大多数情况都被分类为真正例和真反例,沿着主对角线排列。只有 46 个案例被错误分类,而且这个数字几乎相等。这意味着假阳性和假阴性的数量最小且平衡,两者之间没有明显的偏向。这是理想分类器的一个例子。
从混淆矩阵中可以推导出的另外三个度量标准是精准率、召回率和F1 分数。较高的精准率表示较少的非欺诈交易被误分类为欺诈交易,而较高的召回率则表示大部分欺诈交易被正确预测。
F1 分数是精准率和召回率的加权平均值。
我们可以使用以下代码计算精准率和召回率:
from sklearn.metrics import classification_report
#Creating the classification report
print(classification_report(y_test, prediction))
这将产生以下输出:

分类报告
在前面的代码中,我们使用 classification_report() 函数,传入两个参数:目标变量的测试集和我们之前为混淆矩阵创建的预测变量。
在输出中,精准率、召回率和 F1 分数都很高,因为我们已经构建了理想的机器学习模型。这些值的范围从 0 到 1,1 为最高。
标准化混淆矩阵
标准化混淆矩阵使数据科学家更容易直观地理解标签是如何被预测的。为了构建标准化混淆矩阵,我们使用以下代码:
import matplotlib.pyplot as plt
import scikitplot as skplt
#Normalized confusion matrix for the K-NN model
prediction_labels = knn_classifier.predict(X_test)
skplt.metrics.plot_confusion_matrix(y_test, prediction_labels, normalize=True)
plt.show()
这将产生以下标准化混淆矩阵:

K-NN 模型的标准化混淆矩阵
在前面的图中,预测标签位于 x 轴,而真实(或实际)标签位于 y 轴。我们可以看到,该模型对欺诈交易的预测错误率为 0.01,即 1%,而 99%的欺诈交易预测正确。我们还可以看到,K-NN 模型对所有非欺诈交易的预测准确率达到了 100%。
现在,我们可以通过使用标准化混淆矩阵来比较逻辑回归模型的表现,如下所示:
#Normalized confusion matrix for the logistic regression model
prediction_labels = logistic_regression.predict(X_test)
skplt.metrics.plot_confusion_matrix(y_test, prediction_labels, normalize=True)
plt.show()
这将产生以下标准化混淆矩阵:

逻辑回归模型的标准化混淆矩阵
在前面的混淆矩阵中,可以明显看出,逻辑回归模型仅正确预测了 42%的非欺诈交易。这几乎立刻表明,K-NN 模型的表现更好。
曲线下的面积
这个曲线在本例中是接收者操作特征(ROC)曲线。这是一个表示真实正例率与假正例率之间关系的图。我们可以通过以下方式绘制该曲线:
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score
import matplotlib.pyplot as plt
#Probabilities for each prediction output
target_prob = knn_classifier.predict_proba(X_test)[:,1]
#Plotting the ROC curve
fpr, tpr, thresholds = roc_curve(y_test, target_prob)
plt.plot([0,1], [0,1], 'k--')
plt.plot(fpr, tpr)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.show()
这会生成如下曲线:

ROC 曲线
在前面的代码中,首先,我们为每个预测标签创建一组概率。例如,预测标签 1 会有一组与之相关的概率,而标签 0 则有另一组概率。利用这些概率,我们使用roc_curve()函数,并结合目标测试集,来生成 ROC 曲线。
上面的曲线是一个完美的 ROC 曲线示例。该曲线的真实正例率为 1.0,表示预测准确,而假正例率为 0,表示没有错误预测。
这样的曲线通常具有最大的曲线下方区域,与准确度较低的模型曲线相比。为了计算曲线下面积得分,我们使用以下代码:
#Computing the auc score
roc_auc_score(y_test, target_prob)
这会产生 0.99 的得分。较高的auc得分表示模型表现更好。
累积增益曲线
在构建多个机器学习模型时,了解哪个模型产生了你期望的预测类型非常重要。累积增益曲线可以帮助你进行模型比较,通过告诉你某个类别/类在特定模型的样本数据中占据的百分比。
简单来说,在欺诈检测数据集中,我们可能希望选择一个能够预测更多欺诈交易的模型,而不是一个无法做到这一点的模型。为了构建 k 最近邻模型的累积增益图,我们使用以下代码:
import scikitplot as skplt
target_prob = knn_classifier.predict_proba(X_test)
skplt.metrics.plot_cumulative_gain(y_test, target_prob)
plt.show()
这会生成以下图形:

k 最近邻模型的累积增益图
在前面的代码中,以下内容适用:
-
首先,我们导入
scikit-plot包,它用于生成前面的图。然后,我们计算目标变量的概率,在本例中,这些概率表示某个特定移动交易是否为欺诈交易的可能性,基于测试数据。 -
最后,我们在这些概率和测试数据的目标标签上使用
plot_cumulative_gain()函数,以生成前面的图。
我们如何解读前面的图形?我们只需寻找一个点,在该点上,数据中的某个百分比包含了 100%的目标类别。下图为此示意:

100%目标类别存在的点
前图中的点对应于x轴上的 0.3 和y轴上的 1.0。这意味着 30%到 100%的数据将包含目标类 1,即欺诈交易。
这也可以这样解释:如果你使用 K 最近邻模型,70%的数据将包含 100%的欺诈交易预测。
现在,让我们计算逻辑回归模型的累积增益曲线,看看它是否有所不同。为此,我们使用以下代码:
#Cumulative gains plot for the logistic regression model
target_prob = logistic_regression.predict_proba(X_test)
skplt.metrics.plot_cumulative_gain(y_test, target_prob)
plt.show()
这产生了以下图形:

逻辑回归模型的累积增益图
前面的图与 K-NN 模型先前生成的累积增益图相似,都是 70%的数据包含 100%的目标类。因此,使用 K-NN 模型或逻辑回归模型都会得到类似的结果。
然而,使用累积增益图来比较不同模型的表现是一个好的实践,这样可以从根本上理解模型如何进行预测。
提升曲线
提升曲线可以告诉你,通过使用机器学习模型进行预测的效果如何,相较于不使用模型的情况。为了构建 K 最近邻模型的提升曲线,我们使用以下代码:
# Lift curve for the K-NN model
target_prob = knn_classifier.predict_proba(X_test)
skplt.metrics.plot_lift_curve(y_test, target_prob)
plt.show()
这产生了以下图形:

K-NN 模型的提升曲线
我们如何解读前面的提升曲线呢?我们需要找到曲线下滑的点。以下图为您展示了这个点:

提升曲线中的兴趣点
在前面的图中,突出显示的点是我们在任何提升曲线中都要寻找的点。这个点告诉我们,当使用 K-NN 预测模型时,0.3 或 30%的数据比完全不使用任何模型预测欺诈交易时,表现要好 3.5 倍。
现在,我们可以构建逻辑回归模型的提升曲线,以便比较两种模型的表现。我们可以通过使用以下代码来实现:
#Cumulative gains plot for the logistic regression model
target_prob = logistic_regression.predict_proba(X_test)
skplt.metrics.plot_lift_curve(y_test, target_prob)
plt.show()
这产生了以下图形:

逻辑回归模型的提升曲线
尽管该图告诉我们 30%的数据会看到性能改善(类似于我们之前构建的 K-NN 模型来预测欺诈交易),但在预测非欺诈交易时(蓝线)存在差异。
对于少部分数据,非欺诈交易的提升曲线实际上低于基线(虚线)。这意味着在预测非欺诈交易时,逻辑回归模型在少数数据上的表现甚至不如不使用预测模型。
K-S 统计图
K-S 统计图,或称科尔莫哥洛夫-斯米尔诺夫统计图,是一种能够告诉你模型是否在预测数据集中不同标签时产生混淆的图。为了说明在这种情况下“混淆”是什么意思,我们将通过以下代码为 K-NN 模型构建 K-S 统计图:
#KS plot for the K-NN model
target_proba = knn_classifier.predict_proba(X_test)
skplt.metrics.plot_ks_statistic(y_test, target_proba)
plt.show()
这将产生以下图:

K-NN 模型的 K-S 统计图
在前面的图中,以下内容适用:
-
虚线表示欺诈交易(底部的黄色线)和非欺诈交易(顶部的蓝色线)预测之间的距离。这一距离为 0.985,如图所示。
-
K-S 统计得分接近 1 通常是一个很好的指标,表明模型在预测这两种不同的目标标签时没有混淆,并且在预测标签时可以清楚地区分它们。
-
在前面的图中,可以观察到 0.985 的得分为两类预测之间的差异,最大可达 70%(0.7)的数据。这个差异可以在X轴上看到,因为 0.7 的阈值仍然具有最大分离距离。
现在我们可以计算逻辑回归模型的 K-S 统计图,以便比较这两个模型在预测两个类别标签之间的区分能力。我们可以通过以下代码来实现:
#KS plot for the logistic regression model
target_proba = logistic_regression.predict_proba(X_test)
skplt.metrics.plot_ks_statistic(y_test, target_proba)
plt.show()
这将产生以下图:

逻辑回归模型的 K-S 统计图
尽管两个模型的分离分数相同,都是 0.985,但分离发生的阈值却有所不同。在逻辑回归模型中,这一距离仅出现在数据的下 43%部分,因为最大分离开始的阈值为 0.57,沿着X轴。
这意味着 K 近邻模型对于大约 70%的总数据,其距离较大,在预测欺诈交易时要比其他模型更为准确。
校准图
校准图,顾名思义,是用来告诉你模型的校准情况。一个校准良好的模型,其预测得分应该等于正类的比例(在此例中为欺诈交易)。为了绘制校准图,我们使用以下代码:
#Extracting the probabilites that the positive class will be predicted
knn_proba = knn_classifier.predict_proba(X_test)
log_proba = logistic_regression.predict_proba(X_test)
#Storing probabilities in a list
probas = [knn_proba, log_proba]
# Storing the model names in a list
model_names = ["k_nn", "Logistic Regression"]
#Creating the calibration plot
skplt.metrics.plot_calibration_curve(y_test, probas, model_names)
plt.show()
这将产生以下校准图:

两个模型的校准图
在前面的代码中,以下内容适用:
-
首先,我们计算每个模型预测正类(欺诈交易)的概率。
-
然后,我们将这些概率和模型名称存储在一个列表中。
-
最后,我们使用
scikit-plot包中的plot_calibration_curve()函数,结合这些概率、测试标签和模型名称,来创建校准图。
这将生成前面的校准图,解释如下:
-
虚线代表完美的校准图。这是因为在每个点,平均预测值的准确度与正类的比例完全一致。
-
从图中可以看出,k 近邻模型的校准效果明显优于逻辑回归模型的校准图。
-
这是因为 k 近邻模型的校准图比逻辑回归模型的校准图更接近理想的校准图。
学习曲线
学习曲线是一个图表,用于比较随着样本/行数的增加,训练准确率和测试准确率的变化。为了构建 K 近邻模型的学习曲线,我们使用以下代码:
skplt.estimators.plot_learning_curve(knn_classifier, features, target)
plt.show()
这将生成以下图表:

K-NN 模型的学习曲线
在前面的曲线中,以下内容适用:
-
当样本数为 15,000 时,训练得分和测试得分才是最高的。这表明即使我们只有 15,000 个样本(而不是 17,500 个),我们仍然能够得到最好的结果。
-
任何少于 15,000 个样本的情况都会导致测试的交叉验证得分远低于训练得分,表明模型出现过拟合。
交叉验证箱形图
在这张图中,我们通过使用箱形图比较多个模型的交叉验证准确率得分。为此,我们使用以下代码:
from sklearn import model_selection
#List of models
models = [('k-NN', knn_classifier), ('LR', logistic_regression)]
#Initializing empty lists in order to store the results
cv_scores = []
model_name_list = []
for name, model in models:
#5-fold cross validation
cv_5 = model_selection.KFold(n_splits= 5, random_state= 50)
# Evaluating the accuracy scores
cv_score = model_selection.cross_val_score(model, X_test, y_test, cv = cv_5, scoring= 'accuracy')
cv_scores.append(cv_score)
model_name_list.append(name)
# Plotting the cross-validated box plot
fig = plt.figure()
fig.suptitle('Boxplot of 5-fold cross validated scores for all the models')
ax = fig.add_subplot(111)
plt.boxplot(cv_scores)
ax.set_xticklabels(model_name_list)
plt.show()
这将生成以下图表:

交叉验证箱形图
在前面的代码中,以下内容适用:
-
首先,我们将要比较的模型存储在一个列表中。
-
然后,我们初始化两个空列表,用于存储交叉验证准确率得分和模型名称的结果,以便后续使用,以便生成箱形图。
-
然后,我们遍历模型列表中的每个模型,使用
model_selection.KFold()函数将数据划分为五折交叉验证集。 -
接下来,我们通过使用
model_selection.cross_val_scores()函数提取五折交叉验证得分,并将得分和模型名称添加到我们在代码开头初始化的列表中。使用
model_selection.cross_val_scores()函数,并将得分与模型名称一起追加到我们在代码开头初始化的列表中。 -
最后,创建了一个箱形图,展示了交叉验证得分的箱形图。
我们创建的列表由五个交叉验证得分和模型名称组成。箱线图将这五个得分应用于每个模型,计算最小值、最大值、中位数、第一个四分位数和第三个四分位数,并以箱线图的形式展示。
在前面的图中,以下内容适用:
-
很明显,K-NN 模型的准确度最高,并且最小值与最大值之间的差异最小。
-
另一方面,逻辑回归模型在最小值和最大值之间的差异最大,并且在其准确度得分中也存在异常值。
回归算法的性能评估
有三个主要指标可以用来评估你构建的回归算法的性能,具体如下:
-
均方绝对误差 (MAE)
-
均方误差 (MSE)
-
均方根误差 (RMSE)
在本节中,您将了解这三种指标是什么,它们是如何工作的,以及如何使用 scikit-learn 实现它们。第一步是构建线性回归算法。我们可以通过使用以下代码来实现:
## Building a simple linear regression model
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Define the feature and target arrays
feature = df['oldbalanceOrg'].values
target = df['amount'].values
#Initializing a linear regression model
linear_reg = linear_model.LinearRegression()
#Reshaping the array since we only have a single feature
feature = feature.reshape(-1, 1)
target = target.reshape(-1, 1)
#Fitting the model on the data
linear_reg.fit(feature, target)
predictions = linear_reg.predict(feature)
均方绝对误差
均方绝对误差的公式如下:

MAE 公式
在前面的公式中,
代表输出的真实值(或实际值),而
代表预测的输出值。因此,通过计算每一行数据中真实值和预测值之间的差异总和,然后将其除以观测数据的总数,得到绝对误差的均值。
为了在 scikit-learn 中实现 MAE,我们使用以下代码:
from sklearn import metrics
metrics.mean_absolute_error(target, predictions)
在前面的代码中,scikit-learn 中 metrics 模块的 mean_absolute_error() 函数用于计算 MAE。它接受两个参数:真实输出(目标值)和预测输出(预测值)。
均方误差
均方误差的公式如下:

MSE 公式
前面的公式与我们看到的均方绝对误差公式相似,不同之处在于,我们不是计算真实值和预测值之间的绝对差异,而是计算它们差异的平方。
为了在 scikit-learn 中实现 MSE,我们使用以下代码:
metrics.mean_squared_error(target, predictions)
我们使用 metrics 模块中的 mean_squared_error() 函数,传入真实输出值和预测值作为参数。均方误差对于检测较大的误差更有效,因为我们对误差进行了平方,而不仅仅依赖于差异。
均方根误差
均方根误差的公式如下:

前面的公式与均方误差(MSE)非常相似,唯一不同的是我们对 MSE 公式进行了平方根处理。
为了在 scikit-learn 中计算 RMSE,我们使用以下代码:
import numpy as np
np.sqrt(metrics.mean_squared_error(target, predictions))
在前面的代码中,我们使用了mean_squared_error()函数来计算真实输出与预测结果之间的误差,然后通过使用numpy包中的np.sqrt()函数计算该值的平方根。
相较于 MAE 和 MSE,RMSE 是评估线性回归模型时最合适的指标,因为它能够检测到较大的误差,并且以输出单位表示该值。使用这三种指标中的任何一个时,关键的结论是,这些metrics给出的值应该尽可能低,表明模型的误差较小。
无监督算法的性能评估
在本节中,你将学习如何评估无监督机器学习算法的性能,例如 k-means 算法。第一步是构建一个简单的 k-means 模型。我们可以通过使用以下代码来完成:
#Reading in the dataset
df = pd.read_csv('fraud_prediction.csv')
#Dropping the target feature & the index
df = df.drop(['Unnamed: 0', 'isFraud'], axis = 1)
#Initializing K-means with 2 clusters
k_means = KMeans(n_clusters = 2)
现在我们已经有了一个简单的 k-means 模型,其中包含两个聚类,我们可以继续评估该模型的性能。可以使用的不同可视化性能图表如下:
-
肘部图
-
轮廓分析图
在本节中,你将学习如何创建和解释上述每一个图表。
肘部图
为了构建肘部图,我们使用以下代码:
skplt.cluster.plot_elbow_curve(k_means, df, cluster_ranges=range(1, 20))
plt.show()
这会生成如下图所示的图表:

肘部图
肘部图是一个图表,表示模型考虑的聚类数在x轴上,而平方误差总和则在y轴上。
在前面的代码中,以下内容适用:
-
我们使用
plot_elbow_curve()函数,输入 k-means 模型、数据和我们想要评估的聚类数。 -
在这种情况下,我们定义了 1 到 19 个聚类的范围。
在前面的图表中,以下内容适用:
-
很明显,肘部点,或者说平方误差总和(y轴)开始非常缓慢下降的点,出现在聚类数为 4 时。
-
该图表还在y轴(右侧)提供了一个有趣的指标,即聚类时长(以秒为单位)。这表示算法创建聚类所花费的时间,单位为秒。
总结
在本章中,你学会了如何评估三种不同类型的机器学习算法的性能:分类、回归和无监督学习。
对于分类算法,你学会了如何通过一系列可视化技术评估模型的性能,例如混淆矩阵、归一化混淆矩阵、曲线下面积、K-S 统计图、累计增益图、提升曲线、校准图、学习曲线和交叉验证箱线图。
对于回归算法,你学习了如何通过三种度量标准来评估模型的性能:均方误差、平均绝对误差和均方根误差。
最后,对于无监督学习算法,你学习了如何通过使用肘部法则图来评估模型的性能。
恭喜你!你已经顺利完成了使用 scikit-learn 的机器学习之旅。你已经通过了八章内容,这些内容为你提供了快速入门的途径,帮助你进入了机器学习的奇妙世界,并使用了全球最受欢迎的机器学习框架之一:scikit-learn。
在本书中,你学习了以下主题:
-
什么是机器学习(简而言之),以及机器学习的不同类型和应用
-
监督学习算法,如 K-NN、逻辑回归、朴素贝叶斯、支持向量机和线性回归
-
无监督学习算法,如 k-means 算法
-
既能执行分类任务又能进行回归的算法,如决策树、随机森林和梯度提升树
我希望你能充分利用本书所提供的知识,应用这些知识,通过机器学习作为工具,解决许多现实世界中的问题!


0.55。
浙公网安备 33010602011771号