R 应用监督学习(四)
原文:
annas-archive.org/md5/a69bdbe06296bcd4cedce10b02fa8fe7译者:飞龙
第九章:基于研究论文的毕业设计
学习目标
到本章结束时,你将能够:
-
使用 mlr 和 OpenML 在问题上应用端到端的机器学习工作流程,这包括识别研究文章。
-
训练机器学习模型,并随后在测试数据集上使用该模型进行预测和评估。
-
对数据集进行重采样。
-
设计用于构建各种模型的实验。
-
为选择最佳模型建立基准。
在本章中,我们将基于一个现实世界问题选取最新的研究论文,并重现其结果。
简介
在本章的最后,我们将专注于一个基于研究的项目。所有前几章中的想法,例如使用 SCQ 框架设计问题、识别数据来源、预处理数据集、训练机器学习模型、评估模型、应用重采样技术以及许多其他概念都将被使用。此外,本章还将关注基准测试模型、设计机器学习实验、在开源平台上协作以及使研究工作可重复,以造福更大的社区。
在线资源的丰富、计算能力的提升以及现成的工具包解决方案的广泛应用,使得成为机器学习专业人员的门槛降至最低。如今,我们有很多快速入门算法,它们作为 R 和 Python 等编程语言中的函数提供,甚至在 Google Cloud AutoML 或 Microsoft Azure Machine Learning Studio 等平台上的拖放操作中提供。然而,在许多这样的快速入门 Hello World 模型中,通常缺少的是对问题解决的敏锐关注以及超越现有工具的能力。
除了豪华的工具集之外,还存在着由许多学术界和工业界的领先实践者产生的以研究为导向的工作世界。当涉及到产生突破和高品质成果时,这种研究工作的重要性是巨大的。然而,这种研究工作的可访问性有限,因此阻碍了机器学习实践者中的广泛应用。不追求基于研究的工作的另一个原因是由于缺乏可重复性(大多是因为代码未在公共领域提供,研究发现不明确,或研究工作质量差)以及在研究文章或论文中发现的充满术语的理论(许多是用数学语言编写的)。
本章致力于此类研究工作,这些工作往往被许多努力进入机器学习但仅限于使用博客或在线书籍中提倡的特定工具和包的许多学习者忽视。我们将关注两个重要的研究工作,幸运的是,它们也找到了在 R 包中的位置。下一节将介绍这项工作,并设定本章其余部分的流程。
探索研究工作
在本章中,我们将探讨两项最终也成为开源项目的最显著研究成果。本章的重点在于自上而下的方法,我们将从优秀研究成果的起源开始,看看它是如何成为每个人都可以使用的主流工具包的。在强调研究成果的同时,我们还想强调,许多研究成果在市场上可用的标准工具包中找不到位置,但如果稍微努力一些,就能发现一些珍宝。
我们推荐参考 paperswithcode.com 创作者所付出的出色努力。Papers With Code 团队借助社区的帮助和自动化的力量,创建了一个免费且开放的资源平台,包含机器学习论文、代码和评估表格。他们已经自动化了代码与论文的链接,现在正在努力自动化从论文中提取评估指标。这项工作值得称赞,因为它将把最佳研究成果从噪音和繁杂中凸显出来。
下表将突出五个研究成果案例,这些案例是通过 Papers With Code 网站找到的。在整个书中,你已经看到了很多用于机器学习工作流程各个阶段的 R 代码和不同包。mlr 和 OpenML 研究人员的工作现在已打包在 R 中,特别是 OpenML 是一个完整的平台。我们将学习如何利用 mlr 和 OpenML 平台来制作最佳的机器学习模型,而不仅仅是快速入门的 Hello World 示例。为了参考,请查看以下表格:
![图 9.1:本课程演示中使用的论文(第一部分)]
图 9.1:本章演示中使用的论文(第一部分)
![图 9.2:本课程演示中使用的论文(第二部分)]
图 9.2:本章演示中使用的论文(第二部分)
mlr 包
现在,我们将学习 mlr 包如何提供一个完整的框架来处理许多机器学习模型和问题。在许多机器学习项目中,人们往往需要管理大量围绕众多实验的细节(也称为试错迭代)。每个实验都包含使用不同机器学习算法、性能指标、超参数、重采样技术和预测的大量训练。除非我们系统地分析每个实验中获得的信息,否则我们无法得出最佳参数值组合。
使用 mlr 包的另一个优点来自于其丰富的机器学习算法集合,来自各种包。我们不再需要为机器学习算法的不同实现安装多个包。相反,mlr 在一个地方提供了一切。为了更好地理解这一点,请参考以下表格:
图 9.3:mlr 包(第一部分)
图 9.3:mlr 包(第一部分)
多标签分类算法
mlr 包中提供了以下多标签分类模型,其中单个观测值可以分配给多个类别。这些模型在解决许多有用的问题中很有用,例如,在 Netflix 上,你会看到每部电影都可以被标记为动作、冒险和奇幻。或者,在 YouTube 上,每天都有数百万个视频被发布,一个自动算法可以将视频标记为多个类别,从而帮助内容过滤和更好的搜索。
我们将使用这些算法以及前表中定义的分类器:
![图 9.4:使用 mlr 包进行多标签分类]
图 9.4:使用 mlr 包进行多标签分类
OpenML 包
OpenML,一个学术和工业研究人员可以通过它自动共享、组织和审议机器学习实验、数据、算法和流程的合作平台。该平台带来了高效的协作,并实现了可重复性。
R 中的 OpenML 包包含各种功能,允许用户搜索、上传和下载数据集,并执行与机器学习相关的操作。用户可以上传机器学习实验的输出,与其他用户分享,并下载输出结果。这增强了工作的可重复性,加快了研究工作,并将来自不同领域的人们聚集在一起。
研究论文中的问题设计
在本章中,我们将理解、分析和重现《学习多标签场景分类》论文的结果。我们将有效地使用 mlr 和 OpenML 包来重现结果。在此之前,让我们使用SCQ 框架来编写论文中的情况-复杂性-问题:
![图 9.5:来自论文《学习多标签场景分类》的 SCQ]
图 9.5:来自论文《学习多标签场景分类》的 SCQ
场景数据集功能
论文使用了scene数据集进行语义场景分类任务。该数据集是自然场景图像的集合,其中自然场景可能包含多个对象,因此多个类别标签可以描述场景。例如,背景有山的田野场景。从论文中,我们选取了第一张图,它显示了两个图像,这两个图像是多标签图像,描述了单个图像中的两个不同场景。图 9.6是海滩和城市场景,而图 9.7展示了山脉:
![图 9.6:海滩和城市场景。
![img/C12624_09_06.jpg]
图 9.6:海滩和城市场景。
![图 9.7:山脉场景。
![img/C12624_09_07.jpg]
图 9.7:山脉场景。
从给定的图像中,我们可以使用以下内容:
-
颜色信息:当区分某些类型的户外场景时,这种信息很有用。
-
空间信息:这种信息在许多情况下都很有用。例如,图像顶部的光、暖色调可能对应日出。
论文使用CIE LUV,如空间,表示为 Luv。Luv 空间提出了预期的感知均匀性。在将 XYZ 空间适应到 Luv 空间(一种从 XYZ 空间到LUV空间的数学转换)之后,图像被一个 7 x 7 网格分成 49 个块。然后,作者计算每个波段(RGB)的第一和第二矩(均值和方差),这分别对应于低分辨率图像和计算成本较低的质量特征。总共,我们为每张图像获得49 x 2 x 3 = 294个特征向量。
数据集中的剩余六列对应于用真/假编码值表示的六个标签。如果一个图像属于两个类别,相应的列将具有真值。
注意
在比色法中,国际照明委员会(CIE)于 1976 年采用了 CIE 1976 L*、u*、v*颜色空间,作为 1931 CIE XYZ 颜色空间的一个简单计算转换,但试图实现感知均匀性,即两种颜色之间的差异或距离。
使用 mlr 和 OpenML 包实现多标签分类器
现在我们将了解如何使用 mlr 和 OpenML 包训练多标签分类器。首先,我们将从 OpenML 下载场景数据集。
练习 102:从 OpenML 下载场景数据集
在这个练习中,我们将下载场景数据集并为其进一步分析做准备。
完成练习的以下步骤:
-
为了通过 OpenML API 下载场景数据集,首先在
www.openml.org/register网站上创建一个账户。注册过程涉及验证您的电子邮件地址,之后您将获得访问 API 密钥的权限。![图 9.8:OpenML 注册页面。![img/C12624_09_08.jpg]
图 9.8:OpenML 注册页面。
-
登录您的账户后,转到您的账户并选择 API 认证选项。
-
在 API 认证页面,从 API 密钥部分选择并复制粘贴 API 密钥。Multilabel Classification with R Package mlr 论文的作者上传了一组带有 2016_multilabel_r_benchmark_paper 标签的数据集,我们现在可以从 OpenML 下载并开始重现他们的结果。我们将特别使用场景数据集(ID 为 40595)。
-
在继续之前,打开 RStudio 并安装所有必需的包。
-
导入所需的包和库:
library(mlr) library(BBmisc) library(OpenML) library(batchtools) library(parallelMap) -
使用来自 OpenML 的 API 密钥,并使用以下命令注册 API 密钥:
setOMLConfig(apikey = “627394a14f562f0fa8bcc9ec443d879f”)输出如下:
## OpenML configuration: ## server : http://www.openml.org/api/v1 ## cachedir : C:\Users\Karthik\AppData\Local\Temp\Rtmp6bSgE4/cache ## verbosity : 1 ## arff.reader : farff ## confirm.upload : TRUE ## apikey : ***************************d879f -
使用以下命令从源下载数据集:
ds.list = listOMLDataSets(tag = “2016_multilabel_r_benchmark_paper”)输出如下:
## Downloading from ‘http://www.openml.org/api/v1/json/data/list/tag/2016_multilabel_r_benchmark_paper/limit/5000/status/active’ to ‘<mem>’. -
接下来,我们将使用 ID 40595 获取场景数据集:
oml.data = lapply(40595, getOMLDataSet) df.oml.data.scene <- data.frame(oml.data)注意
在执行前两个命令之前,请确保您已安装 farff 包。
-
使用以下命令创建 DataFrame:
df_scene = df.oml.data.scene labels = colnames(df_scene)[295:300] scene.task = makeMultilabelTask(id = “multi”, data = df_scene, target = labels)输出如下:
图 9.9:场景.task 变量的环境设置
在这个练习中,我们在 OpenML 上注册了一个账户并获取了一个 API 密钥。使用该 API 密钥,我们能够下载具有 OpenML 中 2016_multilabel_r_benchmark_paper 标签的场景数据集。最后,我们将数据集转换为数据框。OpenML 提供了许多这样的功能以促进协作。通过分配标签,人们可以与更大的社区分享他们的代码、实验和流程。
构建学习器
学习器是 mlr 包中机器学习算法的实现。如前文所述的 mlr 包部分所强调,mlr 中有一个丰富的学习器函数集合。
对于我们的场景分类问题,mlr 包提供了两种可能的方式来构建多标签分类模型:
-
适应方法:在这种情况下,我们在整个问题上适应一个显式算法。
-
转换方法:我们将问题转换为一个简单的二元分类问题,然后应用可用的二元分类算法。
适应方法
R 中的 mlr 包提供了两种算法适应方法。首先,来自randomForestSRC包的多变量随机森林算法,其次,内置在rFerns包中的随机森林多标签算法。
mlr 中的makeLearner()函数创建了rFerns和randomForestSRC算法的模型对象,如下面的代码所示:
multilabel.lrn3 = makeLearner(“multilabel.rFerns”)
multilabel.lrn4 = makeLearner(“multilabel.randomForestSRC”)
multilabel.lrn3
输出如下,显示了关于多标签.rFerns 模型的信息,如名称和预测类型:
## Learner multilabel.rFerns from package rFernsd
## Type: multilabel
## Name: Random ferns; Short name: rFerns
## Class: multilabel.rFerns
## Properties: numerics,factors,ordered
## Predict-Type: response
## Hyperparameters:
注意
在执行前两个命令之前,请确保您已安装rFerns和randomForestSRC包。
转换方法
构建学习器的第二种方法是使用makeLearner()函数,然后可以使用以下章节中描述的五个包装函数中的任何一个来进行问题转换。
二元相关方法
在多标签分类问题中,每个标签都可以被转换为一个二元分类问题。在这个过程中,任何一个观测值都可能被分配多个标签。在 mlr 包中,makeMultilabelBinaryRelevanceWrapper()方法将二元学习器方法转换为包装的二元相关多标签学习器。
分类链方法
分类链包装器方法实现了一个多标签模型,其中二元分类器被排列成链。每个模型按照链中指定的顺序输出预测。该模型使用给定数据集中的所有特征,以及链中之前模型的全部预测。mlr 中的makeMultilabelClassifierChainsWrapper()方法用于创建分类链包装器。
嵌套堆叠
然而,与分类链类似,观察到的类别(或标签)不是实际类别,而是基于从链中前一个模型(学习器)获得的类别估计。mlr 包中的makeMultilabelNestedStackingWrapper()方法用于创建嵌套堆叠包装器。
依赖二分类相关性方法
mlr 包中的makeMultilabelDBRWrapper方法用于创建依赖二分类相关性包装器。
堆叠
然而,与依赖二分类相关性方法类似,在训练阶段,用作每个标签输入的标签是通过二分类方法获得的,而不是使用实际标签。mlr 包中的makeMultilabelStackingWrapper方法用于创建堆叠包装器。
在以下练习中,我们将看到如何使用classif.rpart方法生成决策树模型。
练习 103:使用 classif.rpart 方法生成决策树模型
在这个练习中,我们将使用classif.rpart方法生成决策树模型,然后使用二分类和嵌套堆叠包装器进行转换。
执行以下步骤以完成练习:
-
首先,使用
makeLearner方法创建classif.rpart的对象:lrn = makeLearner(“classif.rpart”, predict.type = “prob”) -
接下来,使用
makeMultilabelBinaryRelevanceWrapper方法创建堆叠包装器:multilabel.lrn1 = makeMultilabelBinaryRelevanceWrapper(lrn) multilabel.lrn2 = makeMultilabelNestedStackingWrapper(lrn) -
接下来,打印模型:
lrn输出如下:
Learner classif.rpart from package rpart Type: classif Name: Decision Tree; Short name: rpart Class: classif.rpart Properties: twoclass,multiclass,missings,numerics,factors,ordered,prob,weights,featimp Predict-Type: prob Hyperparameters: xval=0 -
打印堆叠包装器,如图所示:
multilabel.lrn1以下命令的输出如下,显示了模型类型、作为模型输出一部分的属性以及预测类型:
Learner multilabel.binaryRelevance.classif.rpart from package rpart Type: multilabel Name: ; Short name: Class: MultilabelBinaryRelevanceWrapper Properties: numerics,factors,ordered,missings,weights,prob,twoclass,multiclass Predict-Type: prob Hyperparameters: xval=0
训练模型
我们可以使用多标签学习者和多标签任务作为输入,像通常一样训练模型;使用multilabel.lrn1对象。
练习 104:训练模型
在这个练习中,我们首先将数据随机分为训练集和测试集,然后使用 mlr 包中的train()函数和前一小节中定义的multilabel.lrn1对象来训练模型。
执行以下步骤以完成练习:
-
使用以下命令进行训练、预测和评估数据集:
df_nrow <- nrow(df_scene) df_all_index <- c(1:df_nrow) -
使用以下命令创建
test_index 变量:train_index <- sample(1:df_nrow, 0.7*df_nrow) test_index <- setdiff(df_all_index,train_index) -
使用
train函数,该函数接受模型对象multilabel.lrn1(仅包含随机选择的train_index的scene.task)来训练模型:scene_classi_mod = train(multilabel.lrn1, scene.task, subset = train_index) scene_classi_mod输出如下:
Model for learner.id=multilabel.binaryRelevance.classif.rpart; learner.class=MultilabelBinaryRelevanceWrapper Trained on: task.id = multi; obs = 1684; features = 294 Hyperparameters: xval=0
使用 R 中的rpart包训练的scene_classi_mod模型,使用了从scene数据集中随机选择的1684个观测值,它是机器学习中分类和回归树(CART)算法的实现,并包装了二值相关方法进行多标签分类。
预测输出
在 mlr 中,可以使用predict函数进行预测。输入参数是训练模型;将scene.task数据集分配给task和test_index参数,它们对应于分配给subset参数的测试数据集:
pred = predict(scene_classi_mod, task = scene.task, subset = test_index)
names(as.data.frame(pred))
[1] “id” “truth.Beach” “truth.Sunset” “truth.FallFoliage”
[5] “truth.Field” “truth.Mountain” “truth.Urban” “prob.Beach”
[9] “prob.Sunset” “prob.FallFoliage” “prob.Field” “prob.Mountain”
[13] “prob.Urban” “response.Beach” “response.Sunset” “response.FallFoliage”
[17] “response.Field” “response.Mountain” “response.Urban”
模型性能
为了评估预测的性能,mlr 包提供了performance()函数,该函数接受模型的预测作为输入,以及我们想要计算的所有度量。所有可用的多标签分类度量可以通过listMeasures()列出。根据论文,我们在预测上使用了hamloss、f1、subset01、acc、tpr和ppv等度量:
MEASURES = list(multilabel.hamloss, multilabel.f1, multilabel.subset01, multilabel.acc, multilabel.tpr, multilabel.ppv)
performance(pred, measures = MEASURES)
上一条命令的输出如下:
multilabel.hamloss multilabel.f1 multilabel.subset01 multilabel.acc multilabel.tpr
0.1260950 0.5135085 0.5878285 0.4880129 0.5477178
multilabel.ppv
0.7216733
以下命令将列出所有可用的多标签分类问题度量:
listMeasures(“multilabel”)
输出如下:
[1] “featperc” “multilabel.tpr” “multilabel.hamloss” “multilabel.subset01” “timeboth”
[6] “timetrain” “timepredict” “multilabel.ppv” “multilabel.f1” “multilabel.acc”
数据重采样
为了评估学习算法的完整性能,我们可以进行一些重采样。为了定义重采样策略,可以使用makeResampleDesc()或makeResampleInstance()。之后,运行resample()函数。使用以下默认度量来计算汉明损失:
rdesc = makeResampleDesc(method = “CV”, stratify = FALSE, iters = 3)
r = resample(learner = multilabel.lrn1, task = scene.task, resampling = rdesc,measures = list(multilabel.hamloss), show.info = FALSE)
r
输出如下:
Resample Result
Task: multi
Learner: multilabel.binaryRelevance.classif.rpart
Aggr perf: multilabel.hamloss.test.mean=0.1244979
Runtime: 4.28345
每个标签的二进制性能
我们可以计算每个标签的二进制性能度量,例如准确度或auc,getMultilabelBinaryPerformances()函数很有用。我们可以将此函数应用于任何多标签预测,例如,也可以应用于重采样的多标签预测。为了计算auc,我们需要预测概率:
getMultilabelBinaryPerformances(r$pred, measures = list(acc, mmce, auc))
输出如下:
## acc.test.mean mmce.test.mean auc.test.mean
## Beach 0.8728708 0.12712921 0.7763484
## Sunset 0.9335272 0.06647279 0.9066371
## FallFoliage 0.9148317 0.08516826 0.8699105
## Field 0.9077690 0.09223099 0.8895795
## Mountain 0.7922725 0.20772746 0.7670873
## Urban 0.8213544 0.17864562 0.7336219
基准测试模型
在基准实验中,不同的学习方法被应用于一个或多个数据集,目的是比较和排名算法,根据一个或多个性能度量。mlr()方法提供了一个非常稳健的框架来执行此类实验,并有助于跟踪实验的所有结果以进行比较。
进行基准实验
在我们的第一个实验中,我们使用mlr()包中的多标签randomForestSRC和rFerns学习者和各种度量来获得我们的第一个基准。
在以下练习中,我们将探索如何对各种学习器进行基准测试。
练习 105:探索如何在各种学习器上进行基准测试
在这个练习中,我们将看到如何对迄今为止创建的各种学习者进行基准测试,并将结果进行比较,以选择多标签场景分类问题的最佳学习者(模型)。这有助于我们将所有结果组织成结构化格式,以选择表现最佳的模式。
执行以下步骤以完成练习:
-
首先,使用以下命令列出所有学习者:
lrns = list(makeLearner(“multilabel.randomForestSRC”), makeLearner(“multilabel.rFerns”) ) MEASURES = list(multilabel.hamloss, multilabel.f1, multilabel.subset01, multilabel.acc, multilabel.tpr, multilabel.ppv) -
进行基准实验:
bmr = benchmark(lrns, scene.task, measures = MEASURES)输出如下:
## Exporting objects to slaves for mode socket: .mlr.slave.options ## Mapping in parallel: mode = socket; cpus = 2; elements = 2. -
现在,执行
bmr对象:bmr模型的训练迭代将类似于以下每个学习者:
Task: multi, Learner: multilabel.rFerns [Resample] cross-validation iter 9: multilabel.hamloss.test.mean=0.183,multilabel.f1.test.mean=0.653,multilabel.subset01.test.mean=0.768,multilabel.acc.test.mean=0.54,multilabel.tpr.test.mean= 0.9,multilabel.ppv.test.mean=0.564 ... [Resample] Aggr. Result: multilabel.hamloss.test.mean=0.183,multilabel.f1.test.mean=0.663,multilabel.subset01.test.mean=0.756,multilabel.acc.test.mean=0.549,multilabel.tpr.test.mean=0.916,multilabel.ppv.test.mean=0.566下表展示了测试数据上各种度量的平均值:
图 9.10:测试数据上各种度量的平均值。
此表显示,randomForestSRC模型在所有度量上比rFerns做得稍好,主要在hamloss 平均值度量上。
访问基准结果
mlr()方法提供了许多getBMR函数,可以从基准实验对象中提取有用的信息,如性能、预测、学习者等。
学习者表现
getBMRPerformances函数给出了训练过程中每个迭代中基准中定义的所有度量的所有值。下表列出了使用randomForestSRC和rFerns学习者每个度量的值。
getBMRPerformances(bmr, as.df = TRUE)
图 9.11:学习者的 randomForestSRC 表现
图 9.12:学习者的 rFerns 表现
预测
我们还可以使用getBMRPredictions函数在测试数据集上获取预测。本节中的两个表格显示了 ID 列表示的几个图像的实际和预测标签。观察发现,预测并不完美,正如我们预期的那样,整体准确率相对较低。
使用 randomForestSRC 进行预测:
head(getBMRPredictions(bmr, as.df = TRUE))
图 9.13:实际标签。
图 9.14:预测标签。
学习者和度量
getBMRLearners函数提供了关于基准中使用的学习者的详细信息。可以使用此函数获取有关超参数和预测类型等信息。同样,getBMRMeasures函数提供了有关性能度量的详细信息。下表显示了我们在基准实验中使用的度量的详细信息:
getBMRLearners(bmr)
输出如下:
## $multilabel.randomForestSRC
## Learner multilabel.randomForestSRC from package randomForestSRC
## Type: multilabel
## Name: Random Forest; Short name: rfsrc
## Class: multilabel.randomForestSRC
## Properties: missings,numerics,factors,prob,weights
## Predict-Type: response
## Hyperparameters: na.action=na.impute
##
##
## $multilabel.rFerns
## Learner multilabel.rFerns from package rFerns
## Type: multilabel
## Name: Random ferns; Short name: rFerns
## Class: multilabel.rFerns
## Properties: numerics,factors,ordered
## Predict-Type: response
## Hyperparameters:
运行getBMRMeasures(bmr)函数:
getBMRMeasures(bmr)
图 9.15:学习者和度量(第一部分)。
图 15 和 16 总结了getBMRMeasures(bmr)命令的结果:
图 9.16:学习者和度量(第二部分)。
合并基准结果
通常,我们会运行多个实验,并希望将所有实验的基准结果汇总到一个列表中,以便比较结果。mergeBenchmarkResults 函数有助于合并结果。
这里是基准:
lrns = list(makeLearner(“multilabel.randomForestSRC”),
makeLearner(“multilabel.rFerns”)
)
bmr = benchmark(lrns, scene.task, measures = MEASURES)
lrn.classif.randomForest = makeLearner(“classif.randomForest”)
bmr.BR.rf = benchmark(lrn.classif.randomForest, scene.task, measures = MEASURES)
mergeBenchmarkResults(list(bmr, bmr.BR.rf))
图 9.17:合并基准结果。
显然,使用 classif.randomForest 与分类器链包装器产生最高的准确率,并在其他所有指标上也表现良好。
活动十四:使用 classif.C50 学习者而不是 classif.rpart 获取二进制性能步骤
在这个活动中,我们将回顾构建模型的整个流程,我们将使用 makeLearner 函数指定 rpart 模型,替换 C50。具体来说,我们将重新运行整个机器学习流程,从问题转换步骤到使用 classif.C50 学习者而不是 classif.rpart 的二进制性能步骤。
按照以下步骤完成活动:
-
定义算法自适应方法。
-
使用问题转换方法,并将
classif.rpart学习者更改为classif.C50。注意
为了使此代码正常工作,你需要安装
C50包。 -
打印学习者的详细信息。
-
打印多标签学习者的详细信息。
-
使用训练数据集训练模型。
-
打印模型详细信息。
-
使用我们之前创建的 C50 模型在测试数据集上预测输出。
-
打印性能指标。
-
打印
listMeasures变量的性能指标。 -
使用交叉验证方法进行重采样。
-
打印二进制性能。
一旦你完成活动,你应该看到以下输出:
## acc.test.mean mmce.test.mean auc.test.mean
## Beach 0.8608226 0.13917740 0.8372448
## Sunset 0.9401745 0.05982551 0.9420085
## FallFoliage 0.9081845 0.09181554 0.9008202
## Field 0.8998754 0.10012464 0.9134458
## Mountain 0.7710843 0.22891566 0.7622767
## Urban 0.8184462 0.18155380 0.7837401
注意
此活动的解决方案可以在第 466 页找到。
使用 OpenML 上传函数工作
为了提高实验的协作和版本控制,我们可以使用 uploadOMLFlow 函数将我们创建的流程上传到 OpenML:
flow.id = uploadOMLFlow(makeLearner(“multilabel.randomForestSRC”))
输出如下:
Downloading from ‘http://www.openml.org/api/v1/flow/exists/mlr.multilabel.randomForestSRC/R_3.2.2-v2.b955a5ec’ to ‘<mem>’.
Do you want to upload the flow? (yes|no)
Uploading flow to the server.
Downloading response to: C:\Users\Karthik\AppData\Local\Temp\Rtmpe4W4BW\file3f044abf30f2.xml
Uploading to ‘http://www.openml.org/api/v1/flow’.
Flow successfully uploaded. Flow ID: 9708
我们鼓励学生探索 OpenML 平台,以找到更多此类功能,因为这个平台帮助全球的研究人员协作和分享他们的工作,使优秀的工作快速传播,并帮助利用研究人员的集体智慧构建最佳模型。
摘要
在本章中,我们使用了 R 语言的 mlr 和 OpenML 包来构建一个完整的机器学习工作流程,用于解决多标签语义场景分类问题。mlr 包提供了一系列丰富的机器学习算法和评估度量,这有助于我们快速实施,并加速了实验过程,以便为问题找到最佳模型。该包还提供了许多包装函数来处理多标签问题。使用像 mlr 这样的强大框架构建现实世界的机器学习模型有助于加快实施速度,并为整个项目提供结构。此外,使用 OpenML,我们可以使用现有的数据集和代码重现研究工作,并根据我们的需求进行修改。这样的平台能够与世界各地的研究人员进行大规模合作。最后,我们还可以上传自己的机器学习流程供他人使用,以便他们从我们停止的地方继续。
在本书中,我们的重点是教授使用 R 编程语言进行监督学习。监督学习是一类算法,其中我们提供了数据的有标签观测。探索性数据分析(EDA)方法有助于深入了解数据集,而 SCQ 框架用于精确设计问题。特征的选择基于问题设计,并在多次实验和评估后选择合适的监督学习模型。然后我们学习了如何在生产环境中部署机器学习模型,这些模型可以被业务中的应用团队使用。此外,在数据集有数百个特征的情况下,我们使用了特征降维和选择技术。
我们想强调的是,在任何机器学习项目中,超过一定阶段(可能是从项目开始算起 3 个月的努力或 100 次不同组合的尝试),我们应该停下来思考我们到目前为止所做的工作是否可以部署到生产环境中。如果答案是肯定的,那么部署它并持续监控任何异常和改进。如果答案是否定的,那么就回到起点重新开始(显然,如果这种奢侈是允许的)。在超参数微调和模型选择等阶段进行机器学习是一种艺术。需要大量的试错实验才能得出最佳模型。
附录
关于
本节包含的内容旨在帮助学生执行书中的活动。它包括学生为完成和实现书中的目标而需要执行的详细步骤。
R 高级分析
活动一:创建 R Markdown 文件以读取 CSV 文件并编写数据摘要
-
启动 RStudio 并导航到 文件 | 新建文件 | R Markdown。
-
在新的 R Markdown 窗口中,提供 标题 和 作者 名称,如图所示。确保在 默认输出格式 部分下选择 Word 选项:![图 1.13:在 RStudio 中创建新的 R Markdown 文件]
![图片 C12624_01_121.jpg]
图 1.13:在 RStudio 中创建新的 R Markdown 文件
-
现在,使用
read.csv()方法读取bank-full.csv文件:![图 1.14:使用 read.csv 方法读取数据]![图片 C12624_01_13.jpg]
图 1.14:使用 read.csv 方法读取数据
-
最后,使用
summary方法将摘要打印到 word 文件中:
![图 1.15:使用 summary 方法后的最终输出]
![图片 C12624_01_14.jpg]
图 1.15:使用 summary 方法后的最终输出
活动二:创建两个矩阵的列表并访问值
-
通过从二项分布中随机生成数字创建两个大小为
10 x 4和4 x 5的矩阵。分别命名为mat_A和mat_B:mat_A <- matrix(rbinom(n = 40, size = 100, prob = 0.4),nrow = 10, ncol=4) mat_B <- matrix(rbinom(n = 20, size = 100, prob = 0.4),nrow = 4, ncol=5) -
现在,将两个矩阵存储在一个列表中:
list_of_matrices <- list(mat_A = mat_A, mat_B =mat_B) -
使用列表访问
mat_A的第 4 行和第 2 列,并将其存储在变量A中,并访问mat_B的第 2 行和第 1 列,并将其存储在变量B中:A <- list_of_matrices[["mat_A"]][4,2] B <- list_of_matrices[["mat_B"]][2,1] -
将
A和B矩阵相乘,并从mat_A的第 2 行和第 1 列中减去:list_of_matrices[["mat_A"]][2,1] - (A*B)输出如下:
## [1] -1554
活动三:使用 dplyr 和 tidyr 从银行数据创建包含所有数值变量的五个汇总统计量的 DataFrame
-
在系统中导入
dplyr和tidyr包:library(dplyr) library(tidyr) Warning: package 'tidyr' was built under R version 3.2.5 -
创建
dfDataFrame 并将其文件导入其中:df <- tbl_df(df_bank_detail) -
使用
select()从银行数据中提取所有数值变量,并使用summarise_all()方法计算最小值、1st 四分位数、3rd 四分位数、中位数、均值、最大值和标准差:df_wide <- df %>% select(age, balance, duration, pdays) %>% summarise_all(funs(min = min, q25 = quantile(., 0.25), median = median, q75 = quantile(., 0.75), max = max, mean = mean, sd = sd)) -
结果是一个宽数据框。4 个变量,7 个度量:
dim(df_wide) ## [1] 1 28 -
将结果存储在名为
df_wide的宽格式 DataFrame 中,使用tidyr函数对其进行重塑,最后将宽格式转换为深度格式,使用tidyr包的 gather、separate 和 spread 函数:df_stats_tidy <- df_wide %>% gather(stat, val) %>% separate(stat, into = c("var", "stat"), sep = "_") %>% spread(stat, val) %>% select(var,min, q25, median, q75, max, mean, sd) # reorder columns print(df_stats_tidy)输出如下:
## # A tibble: 4 x 8 ## var min q25 median q75 max mean sd ## * <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 age 18 33 39 48 95 40.93621 10.61876 ## 2 balance -8019 72 448 1428 102127 1362.27206 3044.76583 ## 3 duration 0 103 180 319 4918 258.16308 257.52781 ## 4 pdays -1 -1 -1 -1 871 40.19783 100.12875
数据探索分析
活动四:绘制多个密度图和箱线图
-
首先,在 RStudio 中加载必要的库和包:
library(ggplot2) library(cowplot) -
将
bank-additional-full.csv数据集读取到名为df的 DataFrame 中:df <- read.csv("bank-additional-full.csv",sep=';') -
定义
plot_grid_numeric函数用于密度图:plot_grid_numeric <- function(df,list_of_variables,ncols=2){ plt_matrix<-list() i<-1 for(column in list_of_variables){ plt_matrix[[i]]<-ggplot(data=df,aes_string(x=column)) + geom_density(fill="red",alpha =0.5) + ggtitle(paste("Density Plot for variable:",column)) + theme_bw() i<-i+1 } plot_grid(plotlist=plt_matrix,ncol=2) } -
绘制
campaign、pdays、previous和emp.var.rate变量的密度图:plot_grid_numeric(df,c("campaign","pdays","previous","emp.var.rate"),2)输出如下:
![图 2.27:
campaign、pdays、previous和emp.var.rate变量的密度图]![图片 C12624_02_25.jpg]
图 2.27:展示 pdays、previous、emp.var.rate 变量的密度图
观察到我们使用直方图获得的解释在密度图中也明显为真。因此,这可以作为查看相同趋势的另一种替代图表。
-
对步骤 4 进行重复以生成箱线图:
plot_grid_numeric <- function(df,list_of_variables,ncols=2){ plt_matrix<-list() i<-1 for(column in list_of_variables){ plt_matrix[[i]]<-ggplot(data=df,aes_string(y=column)) + geom_boxplot(outlier.colour="black") + ggtitle(paste("Boxplot for variable:",column)) + theme_bw() i<-i+1 } plot_grid(plotlist=plt_matrix,ncol=2) } plot_grid_numeric(df,c("campaign","pdays","previous","emp.var.rate"),2)输出如下:
![图 2.28:展示 pdays、previous、emp.var.rate 变量的箱线图
图 2.28:展示 pdays、previous、emp.var.rate 变量的箱线图
现在,让我们探索数据集的最后四个数值变量,即 nr.employed、euribor3m、cons.conf.index 和 duration,看看我们是否能得出一些有意义的见解。
监督学习简介
活动五:按月份在 PRES 和 PM2.5 之间绘制散点图
-
将
ggplot2包导入系统:library(ggplot2) -
在
ggplot中,将a()方法的组件分配给变量PRES。ggplot(data = PM25, aes(x = PRES, y = pm2.5, color = hour)) + geom_point() -
在
geom_smooth()方法的下一层中,通过传递colour = "blue"来区分。geom_smooth(method='auto',formula=y~x, colour = "blue", size =1) -
最后,在
facet_wrap()层中,使用month变量为每个月绘制单独的隔离图。facet_wrap(~ month, nrow = 4)最终代码将如下所示:
ggplot(data = PM25, aes(x = PRES, y = pm2.5, color = hour)) + geom_point() + geom_smooth(method='auto',formula=y~x, colour = "blue", size =1) + facet_wrap(~ month, nrow = 4)图形如下:
![图 3.19:展示 PRES 和 PM2.5 之间关系的散点图
图 3.19:显示 PRES 和 PM2.5 之间关系的散点图
活动六:转换变量并推导新变量以构建模型
构建模型时请执行以下步骤:
-
将所需的库和包导入系统:
library(dplyr) library(lubridate) library(tidyr) library(ggplot2) library(grid) library(zoo) -
将年、月、日和小时合并为一个
datetime变量:PM25$datetime <- with(PM25, ymd_h(sprintf('%04d%02d%02d%02d', year, month, day,hour))) -
删除任何列中存在缺失值的行:
PM25_subset <- na.omit(PM25[,c("datetime","pm2.5")]) -
使用
zoo包中的rollapply()方法计算 PM2.5 的移动平均值;这是为了平滑 PM2.5 读取中的任何噪声:PM25_three_hour_pm25_avg <- rollapply(zoo(PM25_subset$pm2.5,PM25_subset$datetime), 3, mean) -
创建 PM25 污染的两个级别,
0–正常,1-高于正常。我们也可以创建超过两个级别;然而,对于最佳适用于二元分类的逻辑回归,我们使用了两个级别:PM25_three_hour_pm25_avg <- as.data.frame(PM25_three_hour_pm25_avg) PM25_three_hour_pm25_avg$timestamp <- row.names(PM25_three_hour_pm25_avg) row.names(PM25_three_hour_pm25_avg) <- NULL colnames(PM25_three_hour_pm25_avg) <- c("avg_pm25","timestamp") PM25_three_hour_pm25_avg$pollution_level <- ifelse(PM25_three_hour_pm25_avg$avg_pm25 <= 35, 0,1) PM25_three_hour_pm25_avg$timestamp <- as.POSIXct(PM25_three_hour_pm25_avg$timestamp, format= "%Y-%m-%d %H:%M:%S",tz="GMT") -
将结果数据框(PM25_three_hour_pm25_avg)与其他环境变量的值合并,例如我们在线性回归模型中使用的
TEMP、DEWP和Iws:PM25_for_class <- merge(PM25_three_hour_pm25_avg, PM25[,c("datetime","TEMP","DEWP","PRES","Iws","cbwd","Is","Ir")], by.x = "timestamp",by.y = "datetime") -
使用 TEMP、DEWP 和 Iws 变量在
pollution_level上拟合广义线性模型 (glm):PM25_logit_model <- glm(pollution_level ~ DEWP + TEMP + Iws, data = PM25_for_class,family=binomial(link='logit')) -
总结模型:
summary(PM25_logit_model)输出如下:
Call: glm(formula = pollution_level ~ DEWP + TEMP + Iws, family = binomial(link = "logit"), data = PM25_for_class) Deviance Residuals: Min 1Q Median 3Q Max -2.4699 -0.5212 0.4569 0.6508 3.5824 Coefficients: Estimate Std. Error z value Pr(>|z|) (Intercept) 2.5240276 0.0273353 92.34 <2e-16 *** DEWP 0.1231959 0.0016856 73.09 <2e-16 *** TEMP -0.1028211 0.0018447 -55.74 <2e-16 *** Iws -0.0127037 0.0003535 -35.94 <2e-16 *** --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 (Dispersion parameter for binomial family taken to be 1) Null deviance: 49475 on 41754 degrees of freedom Residual deviance: 37821 on 41751 degrees of freedom AIC: 37829 Number of Fisher Scoring iterations: 5
回归
活动七:不使用 summary 函数使用模型对象打印各种属性
-
首先,使用以下命令打印系数值。确保输出类似于使用
coefficients选项的summary函数的输出。系数是从使用 OLS 算法的模型中得到的拟合值:multiple_PM25_linear_model$coefficients输出如下:
(Intercept) DEWP TEMP Iws 161.1512066 4.3841960 -5.1335111 -0.2743375 -
查找预测值和实际 PM2.5 值之间的残差值(差异),应尽可能小。残差反映了使用系数得到的拟合值与实际值之间的距离。
multiple_PM25_linear_model$residuals输出如下:
25 26 27 28 17.95294914 32.81291348 21.38677872 26.34105878 29 30 31 32 -
接下来,找到最适合模型的最佳 PM2.5 实际值的拟合值。使用系数,我们可以计算拟合值:
multiple_PM25_linear_model$fitted.values输出如下:
25 26 27 28 29 111.047051 115.187087 137.613221 154.658941 154.414781 30 31 32 33 34 -
查找 R-Squared 值。它们应该与你在
summary函数输出中“Multiple R-squared”旁边的值相同。R-Square 有助于评估模型性能。如果值接近 1,则模型越好:summary(multiple_PM25_linear_model)$r.squared输出如下:
[1] 0.2159579 -
查找 F-Statistic 值。确保输出应与你在
summary函数输出中“F-Statistics”旁边的输出相同。这将告诉你模型是否比仅使用目标变量的均值拟合得更好。在许多实际应用中,F-Statistic 与 p-values 一起使用:summary(multiple_PM25_linear_model)$fstatistic输出如下:
value numdf dendf 3833.506 3.000 41753.000 -
最后,找到系数 p-values,并确保值应与你在
summary函数中每个变量的“Coefficients”部分下获得的值相同。它将出现在标题为“Pr(>|t|)”的列下。如果值小于 0.05,则变量在预测目标变量时具有统计学意义:summary(multiple_PM25_linear_model)$coefficients[,4]输出如下:
(Intercept) DEWP TEMP Iws 0.000000e+00 0.000000e+00 0.000000e+00 4.279601e-224
模型的属性对于理解同样重要,尤其是在线性回归中,以便获得预测。它们有助于很好地解释模型并将问题与其实际用例联系起来。
分类
活动 8:使用附加特征构建逻辑回归模型
-
创建
df_new数据框的副本到df_copy以进行活动:df_copy <- df_new -
为每个选定的三个数值特征创建新的特征,包括平方根、平方幂和立方幂转换:
df_copy$MaxTemp2 <- df_copy$MaxTemp ² df_copy$MaxTemp3 <- df_copy$MaxTemp ³ df_copy$MaxTemp_root <- sqrt(df_copy$MaxTemp) df_copy$Rainfall2 <- df_copy$Rainfall ² df_copy$Rainfall3 <- df_copy$Rainfall ³ df_copy$Rainfall_root <- sqrt(df_copy$Rainfall) df_copy$Humidity3pm2 <- df_copy$Humidity3pm ² df_copy$Humidity3pm3 <- df_copy$Humidity3pm ³ df_copy$Humidity3pm_root <- sqrt(df_copy$Humidity3pm) -
将
df_copy数据集分为 70:30 的训练和测试比例:#Setting seed for reproducibility set.seed(2019) #Creating a list of indexes for the training dataset (70%) train_index <- sample(seq_len(nrow(df_copy)),floor(0.7 * nrow(df_copy))) #Split the data into test and train train_new <- df_copy[train_index,] test_new <- df_copy[-train_index,] -
使用新的训练数据拟合逻辑回归模型:
model <- glm(RainTomorrow~., data=train_new ,family=binomial(link='logit')) -
使用训练数据上的拟合模型预测响应并创建混淆矩阵:
print("Training data results -") pred_train <-factor(ifelse(predict(model,newdata=train_new, type = "response") > 0.5,"Yes","No")) #Create the Confusion Matrix train_metrics <- confusionMatrix(pred_train, train_new$RainTomorrow,positive="Yes") print(train_metrics)输出如下:
"Training data results -" Confusion Matrix and Statistics Reference Prediction No Yes No 58330 8650 Yes 3161 8906 Accuracy : 0.8506 95% CI : (0.8481, 0.8531) No Information Rate : 0.7779 P-Value [Acc > NIR] : < 2.2e-16 Kappa : 0.5132 Mcnemar's Test P-Value : < 2.2e-16 Sensitivity : 0.5073 Specificity : 0.9486 Pos Pred Value : 0.7380 Neg Pred Value : 0.8709 Prevalence : 0.2221 Detection Rate : 0.1127 Detection Prevalence : 0.1527 Balanced Accuracy : 0.7279 'Positive' Class : Yes -
使用拟合模型在测试数据上预测响应并创建混淆矩阵:
print("Test data results -") pred_test <-factor(ifelse(predict(model,newdata=test_new, type = "response") > 0.5,"Yes","No")) #Create the Confusion Matrix test_metrics <- confusionMatrix(pred_test, test_new$RainTomorrow,positive="Yes") print(test_metrics)输出如下:
"Test data results -" Confusion Matrix and Statistics Reference Prediction No Yes No 25057 3640 Yes 1358 3823 Accuracy : 0.8525 95% CI : (0.8486, 0.8562) No Information Rate : 0.7797 P-Value [Acc > NIR] : < 2.2e-16 Kappa : 0.5176 Mcnemar's Test P-Value : < 2.2e-16 Sensitivity : 0.5123 Specificity : 0.9486 Pos Pred Value : 0.7379 Neg Pred Value : 0.8732 Prevalence : 0.2203 Detection Rate : 0.1128 Detection Prevalence : 0.1529 Balanced Accuracy : 0.7304 'Positive' Class : Yes
活动 9:创建具有附加控制参数的决策树模型
-
加载
rpart库。library(rpart) -
创建具有新值
minsplit =15和cp = 0.00的决策树控制对象:control = rpart.control( minsplit = 15, cp = 0.001) -
使用训练数据拟合树模型并将控制对象传递给
rpart函数:tree_model <- rpart(RainTomorrow~.,data=train, control = control) -
绘制复杂度参数图以查看树在不同
CP值下的表现:plotcp(tree_model)输出如下:
![图 5.10:决策树输出
图 5.10:决策树输出
-
使用拟合模型在训练数据上做出预测并创建混淆矩阵:
print("Training data results -") pred_train <- predict(tree_model,newdata = train,type = "class") confusionMatrix(pred_train, train$RainTomorrow,positive="Yes")输出如下:
"Training data results -" Confusion Matrix and Statistics Reference Prediction No Yes No 58494 9032 Yes 2997 8524 Accuracy : 0.8478 95% CI : (0.8453, 0.8503) No Information Rate : 0.7779 P-Value [Acc > NIR] : < 2.2e-16 Kappa : 0.4979 Mcnemar's Test P-Value : < 2.2e-16 Sensitivity : 0.4855 Specificity : 0.9513 Pos Pred Value : 0.7399 Neg Pred Value : 0.8662 Prevalence : 0.2221 Detection Rate : 0.1078 Detection Prevalence : 0.1457 Balanced Accuracy : 0.7184 'Positive' Class : Yes -
使用拟合的模型对测试数据进行预测并创建混淆矩阵:
print("Test data results -") pred_test <- predict(tree_model,newdata = test,type = "class") confusionMatrix(pred_test, test$RainTomorrow,positive="Yes")输出如下:
"Test data results -" Confusion Matrix and Statistics Reference Prediction No Yes No 25068 3926 Yes 1347 3537 Accuracy : 0.8444 95% CI : (0.8404, 0.8482) No Information Rate : 0.7797 P-Value [Acc > NIR] : < 2.2e-16 Kappa : 0.4828 Mcnemar's Test P-Value : < 2.2e-16 Sensitivity : 0.4739 Specificity : 0.9490 Pos Pred Value : 0.7242 Neg Pred Value : 0.8646 Prevalence : 0.2203 Detection Rate : 0.1044 Detection Prevalence : 0.1442 Balanced Accuracy : 0.7115 'Positive' Class : Yes
活动 10:构建具有更多树的随机森林模型
-
首先,使用以下命令导入
randomForest库:library(randomForest) -
使用所有可用独立特征构建随机森林模型。将模型中的树的数量定义为 500。
rf_model <- randomForest(RainTomorrow ~ . , data = train, ntree = 500, importance = TRUE, maxnodes=60) -
在训练数据上评估:
print("Training data results -") pred_train <- predict(rf_model,newdata = train,type = "class") confusionMatrix(pred_train, train$RainTomorrow,positive="Yes")以下为输出:
"Training data results -" Confusion Matrix and Statistics Reference Prediction No Yes No 59638 10169 Yes 1853 7387 Accuracy : 0.8479 95% CI : (0.8454, 0.8504) No Information Rate : 0.7779 P-Value [Acc > NIR] : < 2.2e-16 Kappa : 0.4702 Mcnemar's Test P-Value : < 2.2e-16 Sensitivity : 0.42077 Specificity : 0.96987 Pos Pred Value : 0.79946 Neg Pred Value : 0.85433 Prevalence : 0.22210 Detection Rate : 0.09345 Detection Prevalence : 0.11689 Balanced Accuracy : 0.69532 'Positive' Class : Yes -
在测试数据上评估:
print("Test data results -") pred_test <- predict(rf_model,newdata = test,type = "class") confusionMatrix(pred_test, test$RainTomorrow,positive="Yes")输出如下:
"Test data results -" Confusion Matrix and Statistics Reference Prediction No Yes No 25604 4398 Yes 811 3065 Accuracy : 0.8462 95% CI : (0.8424, 0.8501) No Information Rate : 0.7797 P-Value [Acc > NIR] : < 2.2e-16 Kappa : 0.4592 Mcnemar's Test P-Value : < 2.2e-16 Sensitivity : 0.41069 Specificity : 0.96930 Pos Pred Value : 0.79076 Neg Pred Value : 0.85341 Prevalence : 0.22029 Detection Rate : 0.09047 Detection Prevalence : 0.11441 Balanced Accuracy : 0.69000 'Positive' Class : Yes
特征选择和降维
活动 11:将北京 PM2.5 数据集的 CBWD 特征转换为单热编码列
-
将北京 PM2.5 数据集读取到 DataFrame
PM25中:PM25 <- read.csv("PRSA_data_2010.1.1-2014.12.31.csv") -
创建一个变量
cbwd_one_hot来存储dummyVars函数的结果,其第一个参数为~ cbwd:library(caret) cbwd_one_hot <- dummyVars(" ~ cbwd", data = PM25) -
使用
predict()函数在cbwd_one_hot上的输出,并将其转换为 DataFrame:cbwd_one_hot <- data.frame(predict(cbwd_one_hot, newdata = PM25)) -
从
PM25DataFrame 中删除原始的cbwd变量:PM25$cbwd <- NULL -
使用
cbind()函数,将cbwd_one_hot添加到PM25DataFrame 中:PM25 <- cbind(PM25, cbwd_one_hot) -
打印
PM25的前 6 行:head(PM25)上一条命令的输出如下:
## No year month day hour pm2.5 DEWP TEMP PRES Iws Is Ir cbwd.cv cbwd.NE ## 1 1 2010 1 1 0 NA -21 -11 1021 1.79 0 0 0 0 ## 2 2 2010 1 1 1 NA -21 -12 1020 4.92 0 0 0 0 ## 3 3 2010 1 1 2 NA -21 -11 1019 6.71 0 0 0 0 ## 4 4 2010 1 1 3 NA -21 -14 1019 9.84 0 0 0 0 ## 5 5 2010 1 1 4 NA -20 -12 1018 12.97 0 0 0 0 ## 6 6 2010 1 1 5 NA -19 -10 1017 16.10 0 0 0 0 ## cbwd.NW cbwd.SE ## 1 1 0 ## 2 1 0 ## 3 1 0 ## 4 1 0 ## 5 1 0 ## 6 1 0
观察head(PM25)命令的输出中的变量cbwd:它现在已转换为带有NE、NW和SE后缀的单热编码列。
模型改进
活动 12:执行重复 K 折交叉验证和网格搜索优化
-
加载用于练习所需的包
mlbench、caret和dplyr:library(mlbench) library(dplyr) library(caret) -
从
mlbench包中将PimaIndianDiabetes数据集加载到内存中:data(PimaIndiansDiabetes) df<-PimaIndiansDiabetes -
设置一个
seed值为2019以确保可重复性:set.seed(2019) -
使用
caret包中的trainControl函数定义 K 折验证对象,并将method定义为repeatedcv而不是cv。在trainControl函数中定义一个额外的结构来指定验证的重复次数repeats = 10:train_control = trainControl(method = "repeatedcv", number=5, repeats = 10, savePredictions = TRUE,verboseIter = TRUE) -
将随机森林模型的超参数
mtry的网格定义为(3,4,5):parameter_values = expand.grid(mtry=c(3,4,5)) -
使用网格值、交叉验证对象和随机森林分类器拟合模型:
model_rf_kfold<- train(diabetes~., data=df, trControl=train_control, method="rf", metric= "Accuracy", tuneGrid = parameter_values) -
通过打印平均准确率和准确率标准差来研究模型性能:
print(paste("Average Accuracy :",mean(model_rf_kfold$resample$Accuracy))) print(paste("Std. Dev Accuracy :",sd(model_rf_kfold$resample$Accuracy))) -
通过绘制不同超参数值下的准确率来研究模型性能:
plot(model_rf_kfold)最终输出如下:
图 7.17:不同超参数值下的模型性能准确率
在此图中,我们可以看到我们对同一模型执行了重复的 k 折交叉验证和网格搜索优化。
模型部署
活动 13:使用 Plumber 部署 R 模型
-
创建一个
model.r脚本,该脚本将加载所需的库、数据、拟合回归模型以及必要的函数来对未见数据进行预测: -
加载包含此活动数据的
mlbench库:library(mlbench) -
将
BostonHousing数据加载到 DataFramedf中:data(BostonHousing) df<-BostonHousing -
使用 df 的前
400行创建训练数据集,并使用剩余的数据进行测试:train <- df[1:400,] test <- df[401:dim(df)[1],] -
使用
lm函数拟合逻辑回归模型,以medv(中位数)作为因变量和 10 个自变量,例如crim、zn、indus、chas、nox、rm、age、dis、rad和tax。model <- lm(medv~crim+zn+indus+chas+ nox+rm+age+dis+rad+tax,data=train) -
定义一个模型端点为
predict_data;这将被用作 Plumber 的 API 端点:#' @get /predict_data function(crim,zn,indus,chas,nox,rm,age,dis,rad,tax){ -
在函数内部,将参数转换为数值和因子(因为 API 调用将只传递字符串):
crim <- as.numeric(crim) zn <- as.numeric(zn) indus <- as.numeric(indus) chas <- as.factor(chas) nox <- as.numeric(nox) rm <- as.numeric(rm) age <- as.numeric(age) dis <- as.numeric(dis) rad <- as.numeric(rad) tax <- as.numeric(tax) -
将模型的 10 个独立特征作为名为
sample的 DataFrame 进行包装,列名保持一致:sample <- data.frame(crim = crim, zn = zn, indus = indus, chas = chas, nox = nox, rm = rm, age = age, dis = dis, rad = rad, tax = tax ) -
将
sampleDataFrame 传递给预测函数,并使用在第 4 步中创建的模型,返回预测结果:y_pred<-predict(model,newdata=sample) list(Answer=y_pred) }整个
model.r文件将看起来像这样:library(mlbench) data(BostonHousing) df<-BostonHousing train <- df[1:400,] test <- df[401:dim(df)[1],] model <- lm(medv~crim+zn+indus+chas+nox+rm+age+dis+rad+tax,data=train) #' @get /predict_data function(crim,zn,indus,chas,nox,rm,age,dis,rad,tax){ crim <- as.numeric(crim) zn <- as.numeric(zn) indus <- as.numeric(indus) chas <- as.factor(chas) nox <- as.numeric(nox) rm <- as.numeric(rm) age <- as.numeric(age) dis <- as.numeric(dis) rad <- as.numeric(rad) tax <- as.numeric(tax) sample <- data.frame(crim = crim, zn = zn, indus = indus, chas = chas, nox = nox, rm = rm, age = age, dis = dis, rad = rad, tax = tax ) y_pred<-predict(model,newdata=sample) list(Answer=y_pred) } -
加载
plumber库。library(plumber) -
使用
plumb函数创建一个 plumber 对象,并传递第一部分中创建的model.r文件。r <- plumb(model.r) -
通过传递主机名
localhost或127.0.0.1和一个端口号,例如8080,运行 plumber 对象。http://127.0.0.1:8080/ -
使用浏览器或 Postman 测试部署的模型并调用 API。
API 调用:
http://127.0.0.1:8080/predict_
ata?crim=0.01&zn=18&indus=2.3&chas=0&nox=0.5&rm=6&
age=65&dis=4&rad=1&tax=242
{"Answer":[22.5813]}
基于研究论文的综合项目
活动 14:使用 classif.C50 学习器而不是 classif.rpart 获取二进制性能步骤
-
定义算法自适应方法:
multilabel.lrn3 = makeLearner("multilabel.rFerns") multilabel.lrn4 = makeLearner("multilabel.randomForestSRC") multilabel.lrn3输出如下:
## Learner multilabel.rFerns from package rFerns ## Type: multilabel ## Name: Random ferns; Short name: rFerns ## Class: multilabel.rFerns ## Properties: numerics,factors,ordered ## Predict-Type: response ## Hyperparameters: -
使用问题转换方法,并将
classif.rpart学习器更改为classif.C50:lrn = makeLearner("classif.C50", predict.type = "prob") multilabel.lrn1 = makeMultilabelBinaryRelevanceWrapper(lrn) multilabel.lrn2 = makeMultilabelNestedStackingWrapper(lrn)注意
您需要安装
C50包以确保此代码能够运行。 -
打印学习器详细信息:
lrn输出如下:
## Learner classif.C50 from package C50 ## Type: classif ## Name: C50; Short name: C50 ## Class: classif.C50 ## Properties: twoclass,multiclass,numerics,factors,prob,missings,weights ## Predict-Type: prob ## Hyperparameters: -
打印多标签学习器详细信息:
multilabel.lrn1输出如下:
## Learner multilabel.binaryRelevance.classif.C50 from package C50 ## Type: multilabel ## Name: ; Short name: ## Class: MultilabelBinaryRelevanceWrapper ## Properties: numerics,factors,missings,weights,prob,twoclass,multiclass ## Predict-Type: prob ## Hyperparameters: -
使用与训练数据集相同的数据集来训练模型:
df_nrow <- nrow(df_scene) df_all_index <- c(1:df_nrow) train_index <- sample(1:df_nrow, 0.7*df_nrow) test_index <- setdiff(df_all_index,train_index) scene_classi_mod = train(multilabel.lrn1, scene.task, subset = train_index) -
打印模型详细信息:
scene_classi_mod输出如下:
## Model for learner.id=multilabel.binaryRelevance.classif.C50; learner.class=MultilabelBinaryRelevanceWrapper ## Trained on: task.id = multi; obs = 1684; features = 294 ## Hyperparameters: -
使用我们为测试数据集创建的
C50模型进行预测输出:pred = predict(scene_classi_mod, task = scene.task, subset = test_index) names(as.data.frame(pred))输出如下:
## [1] "id" "truth.Beach" "truth.Sunset" ## [4] "truth.FallFoliage" "truth.Field" "truth.Mountain" ## [7] "truth.Urban" "prob.Beach" "prob.Sunset" ## [10] "prob.FallFoliage" "prob.Field" "prob.Mountain" ## [13] "prob.Urban" "response.Beach" "response.Sunset" ## [16] "response.FallFoliage" "response.Field" "response.Mountain" ## [19] "response.Urban" -
打印性能度量:
MEASURES = list(multilabel.hamloss, multilabel.f1, multilabel.subset01, multilabel.acc, multilabel.tpr, multilabel.ppv) performance(pred, measures = MEASURES)输出如下:
## multilabel.hamloss multilabel.f1 multilabel.subset01 ## 0.1258645 0.5734901 0.5532503 ## multilabel.acc multilabel.tpr multilabel.ppv ## 0.5412633 0.6207930 0.7249104 -
打印
listMeasures变量的性能度量:listMeasures("multilabel")输出如下:
## [1] "featperc" "multilabel.tpr" "multilabel.hamloss" ## [4] "multilabel.subset01" "timeboth" "timetrain" ## [7] "timepredict" "multilabel.ppv" "multilabel.f1" ## [10] "multilabel.acc" -
使用交叉验证方法进行重采样:
rdesc = makeResampleDesc(method = "CV", stratify = FALSE, iters = 3) r = resample(learner = multilabel.lrn1, task = scene.task, resampling = rdesc,measures = list(multilabel.hamloss), show.info = FALSE) r输出如下:
## Resample Result ## Task: multi ## Learner: multilabel.binaryRelevance.classif.C50 ## Aggr perf: multilabel.hamloss.test.mean=0.1335695 ## Runtime: 72.353 -
打印二进制性能:
getMultilabelBinaryPerformances(r$pred, measures = list(acc, mmce, auc))输出如下:
## acc.test.mean mmce.test.mean auc.test.mean ## Beach 0.8608226 0.13917740 0.8372448 ## Sunset 0.9401745 0.05982551 0.9420085 ## FallFoliage 0.9081845 0.09181554 0.9008202 ## Field 0.8998754 0.10012464 0.9134458 ## Mountain 0.7710843 0.22891566 0.7622767 ## Urban 0.8184462 0.18155380 0.7837401