TowardsDataScience 博客中文翻译 2019(三百三十一)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

机器学习营销——发展业务的 10 个应用

原文:https://towardsdatascience.com/machine-learning-marketing-10-applications-for-growing-your-business-dfa14305a7cb?source=collection_archive---------21-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Franki Chamaki on Unsplash

机器学习和营销之间的关系在过去几年里蓬勃发展,催生了一系列优化这一过程的新策略和工具。现代营销人员别无选择,只能紧跟潮流,以保持竞争力,并在行业中保持理想的技能组合。

另一方面,我们都一直在寻求这种革命性的营销方式。“客户是业务的核心”是如此熟悉的一句话,现在我们终于可以通过利用机器学习来实现它。正如 Altimeter 首席分析师兼未来学家 Brian Solis 所说:

“人工智能和机器学习将对 2018 年的营销产生最深远的影响,因为它将从根本上让‘营销’更加人性化……这本身就很讽刺”。

通过跟踪和分析数据以推动客户参与,机器学习在市场营销中有许多应用。

1.预测客户终身价值

获得一个新客户的成本远远高于保持现有客户的满意度。如果营销人员想要在成本和结果之间取得平衡,明智的预算和努力分配是他们必须的。

使用 RFM(近期、频率和货币)分析,我们可以预测客户的终身价值,并关注那些将在未来带来最多收入的客户。

2.预测客户流失

客户流失预测与客户终身价值相关。预测分析使用关于客户行为的数据来预测客户是否会离开企业。这些信息对营销人员非常有用,因为他们可以在早期发现风险,并及时采取行动防止风险发生。

假设一个客户连续 6 个月每周访问你的网站,但是下个月他只访问一次,这可能导致他不再回来。如果你预料到了这一点,你可以向前迈出一步,提出一项新的交易,或者给他提供一些有价值的东西,如折扣或免费送货。

这为营销人员建立了一种积极的心态,帮助双方建立一种忠诚、值得信赖的关系。

3.改善客户旅程

过去,顾客体验是留给销售公司产品的人的。互动是一对一进行的。在数字时代,这种情况不再存在,也不可能满足每个对你的产品感兴趣的人的独特体验。

但是技术进步已经开始解决这个问题。我敢说,在理解客户需求并轻松引导他们完成购买之旅方面,机器学习算法甚至比人类做得更好。

由于自然语言处理,客户支持也有所改善。客户可以陈述他们的问题,机器学习技术将破译其含义,进一步向客户支持团队提供标准化的消息内容。快速有效地解决投诉是满足行业和客户需求的关键。

从所有接触点的无缝个性化导航到快速高效的客户支持,我们可以提高客户保留率并建立持久的忠诚度

4.线索评分

机器学习可以生成倾向模型,使用数据根据潜在客户的购买概率对其进行评分。这在处理许多销售线索时很方便,因为它节省了时间并提高了效率,使销售团队能够执行其他重要任务。

销售线索评分还有助于定义理想的买家角色。通过查看购买量最大的客户的个人资料,营销人员可以识别出未来需要关注的共同特征。

5.个性化

机器学习营销的主要目的是提供一个个性化的客户旅程,这是专门定制的,以在正确的时间满足个人需求。现场个性化,以及电子邮件和广告个性化,可以帮助你实现目标。

“没有个性化,我们就失去了相关性和速度”Marvin Chow——谷歌营销副总裁

通过机器学习支持的个性化,您可以预见客户在购买过程中的位置,并为他提供合适的内容。如果客户是你网站的常客,当你可以向他提供折扣或免费送货来建立忠诚度时,发送多余的内容是没有意义的。

6.产品推荐

向上销售和交叉销售可以通过使用机器学习来加速和优化产品推荐流程,从而提高参与度。通过预测需求和分析过去的客户行为,营销人员可以有针对性地提供更好的转换机会。

适当的产品推荐也有助于保持新鲜感,避免冗余。如果客户已经有一张信用卡,你为什么还要给他提供信用卡交易呢?因为他刚刚买了梦想中的房子,你可以为他提供房屋保险。

7.动态定价

打折还是不打折?这是许多营销人员迫切需要解决的问题。销售有时可能是王牌,但不断降价比完全不打折对公司利润的损害更大。

机器学习算法可以识别不需要打折就可以购买产品的人,以及那些可以利用这种推动最终进行购买的人。

使用动态定价可以最大限度地提高销售额,保持企业盈利。但是这种策略应该根据你的行业和客户来谨慎使用。

8.广告定位

对于营销人员来说,寻求广告优化是永无止境的。A/B 测试是顺利开展活动的基础,但它永远无法超越机器学习。通过不断学习和调整融合的数据分析是在购买生命周期中的正确时间接触正确受众的防弹策略。

9.营销自动化

自动化使营销人员能够建立工作流程并进行频繁的实验来优化流程。然而,这个过程需要大量的试验和错误,而没有真正解释形成结果的模式。

有了机器学习,你可以抛弃那个乏味的过程,让它基于对客户习惯的深刻洞察来运行测试。营销自动化通过这种方式变得更加强大。

10.理解和预测投资回报率

当客户体验和数据驱动的销售技巧成为你战略的一部分时,难怪营销投资回报率会增加。我们有许多公司以机器学习作为他们的强项来领导他们的行业的例子。

理解和预测投资回报率有助于你在公司内部建立一种数据驱动的文化,这从长远来看更有价值。

现在怎么办?

我们不能对机器学习在市场营销中的所有应用和好处视而不见。更高的准确性,更多的时间专注于创造性任务,更多的数据需要利用。

统计数据摆在那里,人们对此深信不疑,世界各地的公司都在为一流的客户体验和飞速增长的销售额做准备。

机器学习是拼图中缺失的一块。现在是时候退一步,放眼全局,开始为成功制定战略了。

利用机器学习识别陨石中的矿物

原文:https://towardsdatascience.com/machine-learning-meteorites-fcd8f6859ed7?source=collection_archive---------16-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上周末,美国自然历史博物馆(AMNH)举办了第五届年度黑客马拉松。今年的主题是“黑掉太阳系”我的团队致力于一个项目,以确定和绘制陨石的矿物成分。

了解陨石的矿物成分可以让我们了解太阳系。当它们来自行星际天体(如小行星)时,我们可以了解 45 亿年前太阳系是如何形成的。陨石甚至可以来自其他星球,这给了我们一种从几百万公里外研究它们的方法。

化学 101

原子是构成物质的微小物体。原子由中心的质子和中子组成,周围是电子。原子核中质子的数量决定了那个原子是什么 T2 元素。比如最轻的元素氢,有 1 个质子;氧有 8 个,铁有 26 个。

分子由多个原子结合在一起组成。例如,一个水分子由两个氢原子和一个氧原子组成。这可以写成 H₂O.的化学式

矿物是一组固体分子,如钻石、石英或黄玉。原子可以以无数种方式聚集在一起,形成非常不同的矿物。已知的元素只有 118 种,但它们合在一起构成了 3800 种矿物

有些矿物配方可能相当复杂,例如黄玉:al₂sio₄(oh,f)₂——2 个铝、1 个硅、4 个氧和 2 个氧+氢或 2 个氟。而其他人的公式可能非常简单。钻石的分子式是 C——仅仅是碳。但是,原子的结构也很重要。钻石和石墨(你铅笔里的东西)都是由碳组成的,但它们如此不同是因为碳原子以不同的方式结合。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The chemical structure of diamonds vs graphite. (http://www.jidonline.com/viewimage.asp?img=JInterdiscipDentistry_2011_1_2_93_85026_f3.jpg)

陨石是如何被研究的

科学家使用电子微探针(EMP)扫描陨石。电磁脉冲向陨石发射一束电子。当电子束与陨石中的原子碰撞时,原子会发出 x 射线。每个元件具有不同的特征频率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A graph of characteristic frequencies of different elements. (https://commons.wikimedia.org/wiki/File:XRFScan.jpg)

在开始扫描之前,科学家们设置电磁脉冲来检测一组特定的元素。当所需元素的特征 x 射线发射时,探测器记录强度。EMP 产生一系列灰度图像,每个元素一个,其中每个像素代表该元素在该位置的比例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The 10 images produced by the EMP when scanning a meteorite for 10 different elements. Brighter means that more of that element is present at that location. The 10 elements are: Aluminum (Al), Calcium (Ca), Chromium (Cr), Iron (Fe), Magnesium (Mg), Nickel (Ni), Phosphorus §, Silicon (Si), Sulfur (S) and Titanium (Ti).

这可以告诉我们存在什么元素。但是我们如何确定矿物质呢?

来自不同元素的 x 射线的相对强度对应于该元素在不同矿物中的相对比例。一种元素存在的越多,撞击该元素原子的电子就越多,从而发射出特有的 x 射线。例如,矿物硫铁矿大约 2/3 是铁,1/3 是硫,这意味着我们预计发射的 x 射线的 2/3 是铁的 x 射线特征,1/3 是硫的特征。

但是有几个问题使这变得困难。首先,结果可能非常嘈杂,这意味着 EMP 很少会给出与矿物中理论元素比例相匹配的结果。第二,每个元件的传感器的比例不同。例如,铁读数 400 可能意味着 50%的铁,而硫读数 200 可能意味着 100%的硫。

为了控制这些,陨石和“标准”一起被扫描。标准是已知的矿物,被扫描以了解电磁脉冲的行为。我们有 8 种标准矿物,排列成 4x2 网格,如下图所示。每个方块都标有放在那里的已知矿物。顶部是铁(Fe)扫描的图像,中间是硫(S)扫描的图像,底部是镍(Ni)扫描的图像。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Scans from 3 of the 10 elements for the known standard minerals. Each square is the labeled with the known mineral that was placed there. The top is the image from the iron (Fe) scan, the middle is from the sulfur (S) scan and the bottom from the nickle (Ni) scan. *SCOlv stands for San Carlos Olivine, which doesn’t have one distinct chemical formula.

这应该给你一种感觉,我们如何从矿物的组成元素中找出矿物。例如,只有铁的正方形在铁扫描中是亮的,而在其余时间是暗的,这表明那里只存在铁。Fe₃O4 和 FeS 在 Fe 扫描中看起来都很相似,但是 FeS 在 s 扫描中也会变亮。同样,FeS 和 NiS 在 S 扫描中看起来相似,但是 Ni 扫描可以帮助区分它们。还要注意图像中的所有斑点。即使我们正在扫描已知的矿物,他们也不会给出完全一致的读数。当我们试图识别陨石中的未知矿物时,我们必须记住这一点。

机器学习

现在我们有了尝试解决这个问题所需的所有要素。概括地说,我们的最终目标是识别陨石内部的矿物。为了做到这一点,我们在电子探针中扫描陨石,这可以告诉我们陨石中每个位置的元素的相对比例。与此同时,我们扫描了一组称为标准的已知矿物,这样我们就可以正确地解释电磁脉冲的结果。

我的目标是为我们的陨石中的不明矿物创建一个分类器,但是到目前为止,我们只有标记为数据作为标准。我们不能直接从标准中建立一个分类器,因为如果陨石含有标准中没有的矿物,我们就不能对它进行正确的分类。但是,如果我们猜测陨石中可能有什么矿物,我们可以模拟这些矿物(目标矿物),并在此基础上建立一个分类器。这些标准可以帮助我们进行模拟。

第一步是使用标准来找到将元素的重量比例转换成 EMP 强度的系数。我们期望重量比例和强度之间的线性关系。例如,如果一种矿物含有 50%的铁,我们预计其强度是含有 25%铁的矿物的两倍。这意味着我们可以使用线性回归来找到系数。

下面显示了每个元素的回归结果。每个蓝色斑点来自不同的标准。理论上,每个蓝色斑点应该是一个点,但由于读数中的噪声,它们被拉长了。即使有噪声,你也可以看到一个相当清晰的线性关系。但是,在预期比例接近的情况下,例如在 Fe 图中,事情可能是不明确的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The linear regression results for each element. The x-axis is the intensity from the EMP results and the y-axis is the theoretical weight-proportion of that element in the mineral.

我可以用这些结果来模拟我们要找的目标矿物。为了模拟一种矿物,我们计算每种矿物元素的理论重量比例,使用回归结果将它们转换为预期强度,并根据我们在标准中发现的噪声添加随机噪声。

我对每种目标矿物模拟了 10,000 次,并将样本分成 80%的训练集/20%的测试集。我在训练集上训练了一个随机森林分类器,得到的模型在测试集上达到了 96.8%的准确率。

结果

将该模型应用于陨石扫描,结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The predicted mineral composition of a meteorite. Each color represents a different mineral.

在第二颗陨石中:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The predicted mineral composition of a meteorite. Each color represents a different mineral.

我们没有这些陨石的地面真相,所以我们不知道它有多准确。但是和我们一起工作的科学家说最初的结果是有希望的!

结论和后续步骤

这种方法的一个大问题是,它要求科学家提前知道他们在寻找什么矿物。因此,它在识别已知-未知方面似乎很有前途,但会对未知-未知给出错误的分类。

我的团队采用的另一种识别矿物的方法是用 DBSCAN 进行无监督聚类。它不会告诉你具体是什么矿物,但它可以告诉你陨石中有类似元素成分的矿物,可能代表一种独特的矿物。我们认为可能有一种方法可以将这些方法结合起来,两全其美。

我们正在继续这项工作,并希望它不仅仅是一个有趣的黑客马拉松项目,并且成为科学家工具箱中有用的一部分。

我们所有的代码都可以在github上找到。我们仍在努力,所以事情可能会有所改变。

本页更详细的描述了原挑战:https://github . com/amnh/HackTheSolarSystem/wiki/陨石-矿物-测绘

团队的其他成员包括:凯蒂·艾伯特、梅雷特·戈特舍、彼得·康、、塞西娜·巴比奇·莫罗和约翰·安德伍德。塞缪尔·阿尔珀特和玛丽娜·杰玛给了我们建议。感谢 Abigail Pope-Brooks 编辑这篇文章。

Cecina 还写了一篇关于周末的 博文

用 C++部署机器学习模型

原文:https://towardsdatascience.com/machine-learning-model-deployment-with-c-fad31d5fe04?source=collection_archive---------6-----------------------

最近,我着迷于构建一个数学化的应用程序,并在没有任何模型大小、平台或 api 调用需求限制的情况下大规模部署它,这将是多么有趣。我知道 Python 有足够的库来处理机器学习项目的原型,但是没有多少人在谈论扩展这个项目,尤其是当你不想通过 web api 来做这件事的时候。

我相信真正的智能不应该仅仅依赖于对 api 的调用来实现模型的规模化。这种魅力让我开始研究如何将 C++用于机器学习和一般智能。

我坚信 Matlab 和 Python 的数学优势都是基于底层的 c/c++代码。因此,从根本上扩展技术以处理机器学习中涉及的数学计算,并考虑一个极快的场景,可能需要您能够深入研究低级编程,尤其是 c/c++。

此外,我想知道为什么大多数计算机科学学校确保他们的课程中有 c/c++课程。这强调了将 c/c++用于可伸缩技术的理由。

在使用 Udemy 动手课程学习 c++之后,现在的挑战是在 android 中集成一个简单的人脸识别应用程序。

这篇文章将包括构建 c++项目和在 android 或任何其他操作系统环境中部署所需的一些初步方法。

组件:

  1. 用 opencv 建立一个机器学习的 c++项目。
  2. 学习主成分分析生成特征脸
  3. 为多平台部署设置. so 推理库
  4. 为推理库开发 jni 包装器。
  5. 使用 Android 或任何 java 代码中的库。

第一部分将是用 OpenCV 学习一个机器学习算法。在这种情况下,我们将探索最基本的人脸识别算法,使用主成分分析的特征脸。机器学习社区非常熟悉 python 中的这一点,特别是使用 sci-kit learn 等工具,但是当生产,尤其是离线/设备上生产出现在脑海中时,从不同的维度进行这一工作的需求是有利的。

OpenCV 提供了一个非常好的学习主成分分析的 api,一旦设置好数据,学习起来非常简单。

以下是步骤:

使用 OpenCV 建立一个 cmake 项目 c++。

您的 CMakeFile.txt 的关键部分是确保 0 项目中有一个 OpenCV 库,并且可供您的库编译。理想情况下,在请求 Cmake 为您查找 OpenCV 之前,在您的机器上安装 OpenCV 库是很重要的。

find_package(OpenCV REQUIRED)include_directories(${OpenCV_INCLUDE_DIRS})set(LIBS ${OpenCV_LIBS})target_link_libraries(featureCalculation ${LIBS})

PS:为了训练和推断,我不得不设置不同的 cmake。我将分享这两个

学习主成分分析。

既然 OpenCV 已经可用,学习 PCA 就相当简单了。逻辑是这样的:

读取所有图像数据作为数组。 使用 OpenCV 中的 cv::glob ,所有文件名都以 结尾。jpg,。png 或/和。用 cv::imread 可以读取 jpeg ,可以进行图像数据的数据预处理。

农作物面孔。 这很重要,因为PCA 对人脸图像比对整幅图像做得好得多。我发现多任务级联卷积网络(MTCNN) 是最可靠、最简单、最小的人脸检测和裁剪模型。在 C++中有一个使用 OpenCV 中的 Caffe 网络的原始模型的实现。

将裁剪后的面转换成灰度。 这部分挺直截了当的。使用cv::CVT COLOR(originalimagemat,grayscaleimagematcontainer,cv::COLOR_BGR2GRAY) 我们可以在 OpenCV 中将原始的 BGR 图像转换成灰度。

其他预处理 —另一个预处理是确保数据类型正确。这非常重要,因为 C++非常注重数据类型的精度。在这一点上很容易引入错误,因此要小心确保数据类型是正确的。除此之外,这是一个好主意,规范化您的图像数据和调整所有图像到一个一致的形状。只有当数据在同一维度时,PCA 才起作用。在 OpenCV 中,我们可以使用以下函数来处理预处理:

CV::resize(original image,containermatofnewimage,size) 用于调整图像大小original mat::convertTo(newmatnormalize,CV_32FC3,1/255.0) 用于归一化图像的像素值。

将所有图像转换成数据表 —数据表有点像单个数据表,其中每个元素都表示为一行,有趣的是,我们可以将数据表中的每一行都视为扁平格式的独立图像。PCA 的本质是将图像值投影到具有该图像的独特表示的几列。因此,数据表将具有等于训练数据集中图像数量的行,而列将是每个图像的归一化灰度值。

为了创建数据表, std::vector 可用于保存所有图像(希望它们适合内存),然后将其复制到数据矩阵的每一行。这是一个帮助器函数,它从一个矢量图像 mat 中完成这个任务。

**cv::Mat** **createdatamatrix**(std::vector<cv::Mat> imageArray) {
cv::Mat datamatrix(static_cast<int>(imageArray.size()), imageArray[0].rows * imageArray[0].cols, CV_32F);
unsigned int i;
*for*(i=0; i < imageArray.size(); i++) {
   cv::Mat imageRow = imageArray[i].clone().reshape(1, 1);
   cv::Mat rowIData = datamatrix.row(i);
   imageRow.copyTo(rowIData);
  }
  ***return*** datamatrix;
}

cv::reshape() 帮助将 mat 数组变换成不同的形状,用 (1,1) 字面意思是我们希望数据存在一行中。

学习实际主成分分析算法。 现在我们已经用预处理的人脸图像创建了数据表,学习 PCA 模型通常是顺利的。就像把数据表传递给一个 OpenCV pca 实例一样流畅,带有你期望的最大组件像这样cv::PCA PCA PCA(datatable,cv::Mat(),cv::PCA::DATA_AS_ROW,number_of_components) 。这样,我们就有了一个用 C++编写的学习过的 PCA,可以用于生产了。

为了将该模型转移到任何环境中使用,open cv 有一个 文件存储 对象,允许您按原样保存垫子。因此,我可以保存这个文件,并通过 jni for OpenCV 传递其文件名,以重新创建用于推理的模型实例。为模特服务就是这么简单。

为了结束本文的推理部分,我将简单地展示如何使用 OpenCV 编写 mat 对象。最终,保存的模型中的值会以 YAML 文件或 XML 的形式输出,这取决于用户最喜欢的选择。

保存 pca 模型对象,用于生产环境上的推理。 pca 对象中确切需要保存的是经过训练的 PCA 的均值特征向量,有时也保存特征值可能是个好主意,以防您想要构造自己的特征脸投影,但是 OpenCV 已经实现了一个 pca- >项目 实例,它有助于推理和特征脸生成。在任何情况下,以下是如何保存您的模型:

**void Facepca::savemodel**(cv::PCA pcaModel, const std::stringfilename)
{
  cv::FileStorage fs(filename,cv::FileStorage::WRITE);
  fs << “mean” << pcaModel.mean;
  fs << “e_vectors” << pcaModel.eigenvectors;
  fs << “e_values” << pcaModel.eigenvalues;
  fs.release();
}

推理层

保存模型后,推理层将包括加载保存的模型,该模型的值也通过 OpenCV 存储在 yml 文件中,并被开发以形成具有必要数据预处理模块的推理引擎,该推理引擎最终被捆绑为用于在基于 linux 的环境上部署的. so 文件。对于其他平台,cpp 代码可以被编译为分别用于 windows 和 mac 的 dlldylib

因为我们更关心在 android 应用程序上部署模型,所以重点将是构建 。所以 文件推理机从我们保存的模型中。

建筑。so 推理库

加载 PCA 模型 为了推理,我们让 OpenCV 从保存的 中加载已有的模型文件。yml 文件,之后我们将特征值、特征向量和均值输入到一个新的 PCA 对象中,然后我们可以调用一个 pca- >项目 来创建一个新图像的投影。

下面是加载保存的 OpenCV 文件存储模型的示例代码。

cv::PCA **newPcaModel**;
cv::PCA **loadmodel**(cv::PCA newPcaModel, const std::string filename){
   cv::FileStorage fs(filename,cv::FileStorage::READ);
   fs[“mean”] >> newPcaModel.mean ;
   fs[“e_vectors”] >> newPcaModel.eigenvectors ;
   fs[“e_values”] >> newPcaModel.eigenvalues ;
   fs.release();
   ***return*** newPcaModel;
}
**loadmodel**(newPcaModel, “path-to-saved-yml-file”);

一旦模型被加载, newPcaModel 对象现在包含从现有训练参数保存的模型,即 pca 特征值、特征向量和均值。因此,当完成面部投影时,可以保证返回的数据与训练数据集相关。

创建新的图像预处理和预测阶段。 在机器学习模型的推断过程中,重要的是输入图像也要经过与训练数据集相同的预处理。

可以使用几种方法将图像传递给推理引擎,可能是从磁盘加载图像,也可能是将图像作为 base64 字符串传递。

在我们的例子中,可能的方法是使用 base64 字符串,因为我们也考虑了两个因素,一个是 jni 将被暴露,另一个是我们的最终库是用于 android 应用程序的。

记住这一点,然后我们需要确保库能够从 base64 字符串中检索图像并将其发送到 OpenCV。

在 c++中解码一个 base64 字符串是非常重要的,然而,读者可以参考这个链接中的代码片段。

一旦 base64 图像字符串被解码,我们就将该字符串转换成一个由 无符号字符(uchar) 组成的向量,它可以被认为是图像值。

OpenCV 可以使用函数调用cv::im decode(vectorUchar,flag) 将 uchar 的矢量解码成图像。这个过程返回一个 Mat 图像,用它可以做进一步的预处理。

然后,图像可以通过以下预处理阶段:

  • 人脸提取
  • 将裁剪面转换为灰度。
  • 图像大小调整
  • 图像标准化
  • 创建数据矩阵

正如本文上面的培训部分所述。

对新图像进行推理的最后一步是使用加载的 pca 对象在新图像中创建人脸的投影。

这样做的代码片段将如下所示:

newPcaModel->project(datamatrix.row(0));

当你用一个加载的 pca 对象在两个面上投影,并使用距离度量(如欧几里德距离或余弦相似度)比较投影(特征面)时,识别或验证部分发生。

为推理库开发 jni 包装器

用一个暴露的 jni 打包这个库。 这一部分非常简单,一旦推理代码被适当地结构化,很可能是在一个类中,那么 jni 主体就可以直接调用暴露的函数来进行模型加载、预处理和预测。

然而,要创建一个 jni,理解 java 中的链接是如何发生的是很重要的。

第一种方法是创建一个 java 类和您希望在 Java 类中使用的带有输入参数的函数。

这将是 jni 在创建 cpp 代码时使用的函数名。Java 中方法的类路径名与 cpp 中的类路径名之间的一致性非常重要。

让我们假设我们将用于 pca 特征匹配的方法被命名为matchpcafeatures(),然后我们的 java 类可以看起来像这样。

package org.example.codeclass MatchFeatures {static float matchpcafeatures(modelfilename: String, image: String, projectionToCompare: Array[Float])}

有了上面的 java 类和方法,我们的 jni 头文件看起来会像这样。

*#include* <jni.h>*/* Header for class com_example_code_MatchFeatures */
#ifndef* _Included_com_example_code_MatchFeatures
*#define* _Included_com_example_code_MatchFeatures*#ifdef* __cplusplus
extern “C” {
*#endif*JNIEXPORT jfloat JNICALL Java_com_example_code_MatchFeatures_matchpcafeatures
(JNIEnv *, jobject, jstring, jstring, jfloatArray);*#ifdef* __cplusplus
}
*#endif
#endif*

你还不需要担心 extern C 的细节,重点是 jni 头文件中方法的名称。

接下来,我们将看看如何使用上面的 java 代码进行推理。让我们首先为这个方法开发 jni 桥。

jni 头的最后 3 个参数与 java 方法中的参数完全相同,位置也完全相同。

因此,我们将对这些参数进行处理,因为它们是客户对我们的 c++推理引擎的关键要求。

下面展示了如何连接这些输入参数并返回一个值,java 代码可以接受这个值并继续它的其他进程。

*/**
* Match features of pca
* */*JNIEXPORT jfloat JNICALL Java_com_seamfix_qrcode_FaceFeatures_matchpcafeatures
(JNIEnv * env, jobject obj, jstring pcafilename, jstring imagestring, jfloatArray projectionToCompare){ const char *pcastring_char;
  pcastring_char = env->GetStringUTFChars(pcafilename, 0);
  *if*(pcastring_char == NULL) {
    *return* 0.0f;
  } const char *imagestring_char;
  imagestring_char = env->GetStringUTFChars(imagestring, 0);
  *if*(imagestring_char == NULL) {
     *return* 0.0f;
  } *//Get file name string as a string for cpp* std::string stdfilename(pcastring_char);
  cv::PCA pca; *//Class InferencPca holds the preprocesing and inference methods* InferencePca ef;
  std::vector<cv::Mat> imagevec; *//Get image as base64* cv::Mat image = ef.readBase64Image(imagestring_char);
  ef.loadmodel(pca, stdfilename);
  imagevec.push_back(image); cv::Mat datamatrix = ef.createdatamatrix(imagevec);
  cv::Mat projection = ef.project(datamatrix.row(0)); *//Load the existing vector.* std::vector<float> initialProjectionPoints; *//Load existing features -- needed to do comparison of faces* jsize intArrayLen = env->GetArrayLength(existingfeatures);
  jfloat *pointvecBody = 
      env->GetFloatArrayElements(existingfeatures, 0); *for* (int i =0; i < intArrayLen; i++) {
     initialProjectionPoints.push_back(pointvecBody[i]);
  } std::vector<float> newProjectionpoints =     
                ef.matToVector(projection);
  float comparisonScores = 
     ef.compareProjections(newProjectionpoints, 
                            initialProjectionPoints); env->ReleaseFloatArrayElements(existingfeatures, pointvecBody, 0);
  env->ReleaseStringUTFChars(pcafilename, pcastring_char);***return*** comparisonScores;}

有了这个,我们就着手打造我们的 。于是库和库成功地释放给 java 代码使用。cmakelists . txt中说明了构建库的协议。

它看起来像下面这样:

find_package(JNI REQUIRED)*#Include jni directories* include_directories(${JNI_INCLUDE_DIRS})
file (GLOB_RECURSE SOURCE_FILE src/*.h src/*.cpp)set(LIBS ${JNI_LIBRARIES})
add_library(matchprojection SHARED ${SOURCE_FILE})target_link_libraries(matchprojection ${LIBS})

构建项目应该生成一个lib-match projection . so文件,该文件可以添加到您的 java 项目中。

然而,对于 android 来说,这有点棘手,因为构建工具不同于官方的 cmake 构建工具链,Android 有自己的本地 cpp 代码构建工具。这叫做***【NDK】***【原生开发套件】。这将用于为生成的 构建 c++原生代码。所以 要兼容安卓。

建筑。所以使用 NDK 的安卓系统的** 将会是一个完整的教程,所以我现在跳过它。

但是一般来说,一旦使用 NDK 完成构建,您将拥有相同的lib-match projection . so可以在您的 android 应用程序中使用。

使用。Android 应用程序中的库。

在 Android 应用程序中使用生成的库就像在任何 java 应用程序中使用它一样。

其思想是加载本地库,然后用所需的参数调用最初创建的类中对应于本地 jni 方法的方法。

要在包括 android 在内的任何 java 程序中加载该库,请确保 。所以 库是在你的程序的类路径中,有的会把它放在一个名为 lib 或者 jniLibs 的文件夹下。这样我就可以使用函数调用来加载库,如下所示:

System.loads(“native-lib”)

最后,我可以用必要的参数调用前面创建的方法,然后本机代码可以为我执行。

MatchFeatures mf = *new* MatchFeatures();float matchscores = mf.matchpcafeatures(storedpacfilepath, imagebase64string, anotherimageprojectionarray);

如果您仔细观察,就会发现该方法被声明为 native,并且该方法没有主体,这是因为程序知道有一个用该类路径名定义的 native cpp 方法。

结论:

这种方法是在 java 环境中构建和部署包含本机代码的项目的基本方法。此外,最复杂的算法问题,包括机器学习和核心计算机视觉项目,可以很容易地在 cpp most 中推理,因为它很快,而且有现成的库。

甚至 TensorFlow 也有一个在 c++中加载深度学习模型以及在 c++中使用其 tflite 模型的 api。

因此,我认为这种使用本机代码构建推理引擎的方法是一种构建强大的生产就绪型引擎的方法,这种引擎将利用高精度数学,尤其是将机器学习模型部署到各种环境,尤其是离线环境中的 android 环境。

我在 Seamfix Nigeria Ltd .担任数据科学家和机器学习工程师,我的工作重点是确保数据科学功能最终应用于生产。

Docker 中作为微服务的机器学习模型

原文:https://towardsdatascience.com/machine-learning-models-as-micro-services-in-docker-a798e1f068a5?source=collection_archive---------5-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

机器学习开发中最大的被低估的挑战之一是在生产中以可扩展的方式部署训练好的模型。我读过的一个关于它的笑话是“如今机器学习最常见的部署方式是 powerpoint 幻灯片:)”。

为什么是 Docker?

Docker 是一个容器化平台,它将一个应用程序&及其所有依赖项打包到一个容器中。

激活该容器导致应用程序被激活

当你有一大堆以隔离方式工作的服务,并作为 web 应用程序的数据提供者时,就使用 Docker。根据负载情况,可以根据设置的规则按需剥离实例。

为什么要用 Docker 做机器学习模型?

常规软件应用程序的生产部署非常困难。如果那个软件是机器学习管道,那就更糟糕了!在今天的情况下,你无法摆脱机器学习,因为这是你在业务中可以获得的最大竞争优势。在生产中,一个机器学习驱动的应用程序可能会出于多种目的使用多个模型。可以通过 docker 处理的机器学习模型部署中的一些主要实际挑战有:

  1. 不同型号的环境不一致。

有些情况下,对于一个模型,您需要将 LANG_LEVEL 设置为“c ”,而对于另一个模型,LANG_LEVEL 应该为“en_us”。UTF 8 英尺高。将不同的模型放入不同的容器中,以便获得不同模型的隔离环境

2。模型间不一致的库需求。

您已经使用 tensorflow 1.10 开发了一个文本摘要器。现在我们想用 tensorflow2.0 支持的迁移学习进行情感分析(假设)。将它们放在不同的容器中不会破坏应用程序。

另一个主要的用例是,你用 python 开发 ML 模型。但是你想用 Go 语言做的应用(为了一些技术优势),那么通过 docker 把 ml 模型暴露给 app 就解决了。

3。不同型号的资源需求不一致。

你有一个非常复杂的对象检测模型,需要 GPU,你有 5 个不同的神经网络,用于其他目的,适合在 CPU 上运行。然后在容器中部署模型时,您可以根据需求灵活地分配资源。

4。跨模型的不一致流量。

假设您有一个问题标识符模型和答案生成模式,前者调用频繁,而后者调用不频繁。那么你需要比答案生成器更多的问题标识符实例。这可以由 docker 轻松处理。

另一个场景是,上午 10 点你的模型有 10000 个请求,而晚上 8 点只有 100 个。因此,您需要根据您的需求剥离更多的服务实例,这在 docker 中更容易。

5。模型级缩放

假设你有一个每秒处理 100000 个请求的统计模型,而一个每秒能够处理 100 个请求的深度学习模型。那么对于 10000 个请求,你只需要纵向扩展深度学习模型。这可以由 docker 来完成。

现在让我们看看如何创建深度学习模型的容器。在这里,我建立的模型是在 http://cogcomp.org/Data/QA/QC/的可用的问题分类器数据集上的问题主题标识符。Google 的通用句子编码器用于单词嵌入。

为模型创建容器时,通常必须遵循的工作流程是:

  1. 建立和训练模型。
  2. 创建模型的 API。(这里我们把它放在一个 flask API 中)。
  3. 创建包含所有必需库的需求文件。
  4. 使用必要的环境设置和启动操作创建 docker 文件。
  5. 建立 docker 形象。
  6. 现在运行容器,并在完成后跳舞:)

[## sambit 9238/QuestionTopicAnalysis

发现问题主题在各种用例中起着重要的作用,从问答系统到回答…

github.com](https://github.com/sambit9238/QuestionTopicAnalysis)

建立并训练模型。

为了建立和训练模型,基本的工作流程是获取数据,对数据进行清理和处理,然后将数据提供给模型架构,以获得训练好的模型。

例如,我在 http://cogcomp.org/Data/QA/QC/的 TREC 数据集上建立了一个问题意图分类器模型。训练数据有 6 个意图,每个意图的实例数如下:

Counter({'DESC': 1162,
         'ENTY': 1250,
         'ABBR': 86,
         'HUM': 1223,
         'NUM': 896,
         'LOC': 835})

可以在https://github . com/sambit 9238/QuestionTopicAnalysis/blob/master/question _ topic . ipynb查看模型创建

这里遵循的处理步骤是:

  1. 处理宫缩就像我会,我已经等。
  2. 处理超链接、邮件地址等。
  3. 处理数字和身份证。
  4. 处理标点符号。

对于嵌入,使用了来自 tensorflow-hub 的 Google 通用句子编码器。

遵循的模型结构是具有两个隐藏层的神经网络,每个隐藏层具有 256 个神经元。为了避免过度拟合,使用 L2 正则化。

Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 1)                 0         
_________________________________________________________________
lambda_1 (Lambda)            (None, 512)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 256)               131328    
_________________________________________________________________
dense_2 (Dense)              (None, 256)               65792     
_________________________________________________________________
dense_3 (Dense)              (None, 6)                 1542      
=================================================================
Total params: 198,662
Trainable params: 198,662
Non-trainable params: 0
_________________________________

该模型存储在. h5 文件中以供重用。标签编码器存储在 pickle 文件中以供重用。

创建模型的 API。(这里我们把它放在一个 flask API 中)。

存储的模型放在 Flask api 中,以便可以在生产中使用(https://github . com/sambit 9238/QuestionTopicAnalysis/blob/master/docker _ question _ topic/app . py)。)

API 需要一个文本列表,因为在实时使用时会出现多个句子。它经过清洗和处理后被送入预测系统。预测结果被缩放以表示每个意图的置信度百分比。然后,缩放后的结果以 JSON 格式发送。

举个例子,

输入:【“你工资多少?”]

输出:{‘ABBR’: 0.0012655753,’ DESC’: 0.0079659065,’ ENTY’: 0.011016952,‘哼’:0.028764706,’ LOC’: 0.013653239,’ NUM’: 0.93733364}

这意味着模型有 93%的把握认为这个问题的答案应该是一个数字

创建包含所有所需库的需求文件。

为了创建 Docker 映像来服务我们的 API,我们需要创建一个需求文件,其中包含所有使用过的库及其版本。

创建具有必要环境设置和启动操作的 Dockerfile 文件。

一个 Dockerfile 是一个文本文档,它包含用户可以在命令行上调用的所有命令来组合一个图像。

对于我们的示例,预构建的 python-3.6 映像被用作基础映像。然后,已经下载了预先训练的通用语句编码器模型文件,随后安装了所需的库。docker 的 5000 端口是公开的,这是 flask app 在默认配置下运行的端口。

打造 docker 形象。并运行容器

现在我们在一个目录中有了 Dockerfile、flask API 和经过训练的模型文件。因此,我们需要从中创建 docker 图像。该命令可以是:

docker build -t question_topic .
#the last option is location of the directory. Since I am in the directory so '.' is put, which represents current directory in unix.

现在 docker 映像已经创建,我们需要在容器docker run -p 8888:5000 --name question_topic question_topic中运行该映像

它将使创建的 docker 映像运行。docker 中的端口 5000 映射到主机的 8888 端口。因此,API 将在端口 8888 接收和响应请求。如果您想在后台运行 docker 并将其从命令提示符中分离出来(这将是实时的情况),请使用’-d '选项运行它。

为了检查 docker 的输出,让我们使用 curl 发送一个 post 请求。

输入:

为了提供输入,curl—request POST
—URLhttp://0 . 0 . 0 . 0:8888/predict _ topic
—header ’ content-type:application/JSON ’
—data ’ { " raw text _ list ":[“您现在在哪里工作?”,“你的工资是多少?”]}’

输出:

{

" input": “[‘你现在在哪里工作?’,‘你的工资是多少?’]”,

“output”:“[{ ’ ABBR ‘:0.0033528977,’ DESC’: 0.0013749895,’ ENTY’: 0.0068545835,‘哼’:0.7283039,’ LOC’: 0.25804028,’ NUM’: 0.0020733867},

{‘ABBR’: 0.0012655753,’ DESC’: 0.0079659065,’ ENTY’: 0.011016952,‘哼’:0.028764706,’ LOC’: 0.013653239,’ NUM’: 0.93733364} ]"

}

看来 docker 运行良好:)

备注:

提到的例子还没有准备好投入生产。但是,通过以下几个步骤,它就可以投入生产了:

  1. 在模型级别,可以进行更多的处理和模型超参数调整,以使模型更好。
  2. 在 API 级别,不需要在每次请求时初始化会话和变量。通过大幅缩短 API 的响应时间,可以在应用启动时完成一次。
  3. 在 docker 级别,Docker 文件没有优化,因此 Docker 映像在大小上可能比要求的要大。

深度学习—模型优化和压缩:简化

原文:https://towardsdatascience.com/machine-learning-models-compression-and-quantization-simplified-a302ddf326f2?source=collection_archive---------10-----------------------

看看最先进的机器学习模型的压缩、修剪和量化领域

这是什么?

我们周围的世界充满了神经网络和深度学习模型,它们在创造奇迹!!但是这些模型既计算量大又耗能。如此昂贵,以至于人们已经开始要求 AI/ML 对他们的碳排放负责,数字 不好看!!

[## 训练一个人工智能模型在它们的一生中可以排放相当于五辆汽车的碳

人工智能行业经常被比作石油行业:一旦被开采和提炼,数据就像石油一样,可以…

www.technologyreview.com](https://www.technologyreview.com/s/613630/training-a-single-ai-model-can-emit-as-much-carbon-as-five-cars-in-their-lifetimes/?utm_medium=tr_social&utm_source=facebook&utm_campaign=site_visitor.unpaid.engagement&fbclid=IwAR04gQbmXY7OxR3vx8BRb52-pYhlqhXhxorXGSkgGkygu8jUVgbF_CJxYwI)

更多研究人员转向模型压缩的另一个主要原因是在硬件资源有限的系统上部署这些模型的困难。虽然这些模型已经成功地成为头条新闻并实现了非凡的性能,但它们需要昂贵的高速 GPU 的支持才能工作,这限制了它们的应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

能够压缩这些高度复杂的模型,将它们传输到硬件设备,并结束它们对巨大计算资源的依赖,是该领域的主要目标之一。这些进步可以帮助我们将人工智能融入到我们周围的每个小型嵌入式系统中。

为什么不直接用 GPU 服务器?

是的当然!!随着像谷歌和亚马逊这样的互联网巨头提供在线计算服务,人们确实想知道进行远程计算是否是一条出路。虽然人们已经开始像使用拐杖一样使用这些云服务进行繁重的计算,但它也带来了自己的一系列问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

云计算的一个主要问题是网络连接。该系统需要一直在线才能顺利工作。但是这并不总是能够保证的,因此在本地进行计算对于不能承受任何网络延迟的系统来说是极其重要的。

使用这些云服务的另一个问题是牺牲“空气间隙”。“空气间隙”是一个技术术语,用来表示没有连接到互联网的系统,因此无法被远程攻破。访问这些配置中的数据需要通过物理方式完成,不可能完成的任务风格!!😛

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于极度保护隐私和安全的系统来说,放弃这种“空气间隙”是不理想的,因此他们更喜欢本地计算而不是云服务。

但这些都不会影响到我!!

*这是大多数 ML 社区相信的,但不是真的!!*如果您是 ML 的初学者,希望开发最先进的模型,并且不受处理能力的限制,那么您可能会认为高度复杂和深度的模型总是最佳选择。

但这是一个巨大的误解。高度复杂和深度的模型不能保证性能。更不用说,这些模型可能需要几个小时甚至几天的训练时间(即使是在 GPU 上)。对修剪和量化的研究表明,模型中真正重要的连接只占整个蜘蛛网的一小部分!!

例如,像 AlexNet 和 VGG-16 这样的著名 ImageNet 模型已经被压缩到其原始大小的 40-50 倍,而准确性没有任何损失(实际上略有增加)。这极大地提高了他们的推理速度,以及他们适应各种设备的便利性。

有足够的说服力,让我们谈谈所涉及的技术!!

模型压缩可以分为两大类,

修剪:移除架构中存在的冗余连接。剪枝包括切除不重要的权重(通常定义为绝对值小的权重)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显然,所形成的新模型将具有较低的准确性,因为该模型实际上是为原始连接而训练的。这就是为什么模型在修剪后被微调以重新获得准确性。值得注意的是,全连接层和 CNN 通常可以达到 90%的稀疏度,而不会损失任何精度。

量化:量化包括通过聚类或四舍五入将权重捆绑在一起,这样相同数量的连接可以用更少的内存来表示。

通过聚类/捆绑进行量化,从而使用较少数量的不同浮点值来表示更多数量的特征,这是最常用的技术之一。形成许多量化方法框架的另一种常见技术是通过舍入将浮点权重转换为定点表示。

同样,正如修剪一样,我们需要在量化后对模型进行微调。这里重要的一点是,量化时赋予权重的属性也应该通过微调来保持。这就是为什么要使用特定的微调方式来匹配量化方法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请看上图,这是一个通过聚类进行量化的例子。相同颜色的权重聚集在一起,用它们的质心来表示。这减少了表示这些权重所需的数据量。早期需要 32 位16 = 512 位来表示它们。现在只需要 32 位 4+2 位*16 = 160 位来表示它们。在微调期间,属于同一颜色的所有权重的梯度被相加,然后从质心中减去。这确保了在量化期间进行的聚类通过微调得以保持。

下一步是什么?

深度学习模型剪枝和量化是相对较新的领域。虽然在这一领域取得了重大成功,但仍有很长的路要走。该领域的下一个重点应该是创建开源和易于访问的管道,用于将常见的深度学习模型转移到 FPGAs 等嵌入式系统。

这个博客是为机器学习领域创建简化介绍的努力的一部分。点击此处的完整系列

[## 机器学习:简化

在你一头扎进去之前就知道了

towardsdatascience.com](/machine-learning-simplified-1fe22fec0fac)

或者干脆阅读系列的下一篇博客

[## 带人工智能的高频交易(HFT):简化

让我们来看看高频交易这个竞争激烈的世界,以及人工智能是如何成为其中一部分的。

towardsdatascience.com](/high-frequency-trading-hft-with-ai-simplified-a24c00da72e0)

参考

[1]韩、宋、、毛和威廉·j·戴利。"深度压缩:压缩深度神经网络与剪枝,训练量化和霍夫曼编码."arXiv 预印本 arXiv:1510.00149 (2015)。
[2]贾,海鹏,等.“模型压缩中的丢弃问题”arXiv 预印本 arXiv:1812.02035 (2018)。
[3]王、硕等,“C-lstm:在 fpgas 上使用结构化压缩技术实现高效 lstm。”2018 年 ACM/SIGDA 现场可编程门阵列国际研讨会论文集。ACM,2018。

分类变量上的机器学习

原文:https://towardsdatascience.com/machine-learning-on-categorical-variables-3b76ffe4a7cb?source=collection_archive---------4-----------------------

如何正确运行和评估模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by v2osk on Unsplash

乍一看,分类变量和数字变量没什么不同。但是,一旦你开始深入挖掘,并在代码中实现你的机器学习(和预处理)思想,你就会每分钟都停下来问一些问题,比如“我在训练集和测试集上都做特征工程吗?”或者“我听说了一些关于基数的事情——那是什么,我应该用谷歌搜索更多相关信息吗?”

让我们看看我们是否可以通过一个行动计划来澄清这一点,即如何处理具有许多分类变量的数据集并训练几个模型。

Kaggle 将作为我们的数据源:它有一个优秀的房价数据集。准备花些时间浏览提供的数据字典。您可以在单独的浏览器窗口中打开它。我们还会将其加载到 Jupyter 笔记本中。在本练习中,我们将根据房屋的各种参数预测列 SalePrice 中的值。

和往常一样,所有代码都可以在 GitHub 上获得(你需要工作簿Features _ for _ mlops . ipynb)。它还有一些额外的图表,我们在这里没有涉及,但对于更好地理解这个过程是有用的。

让我们加载依赖项和数据:

# Loading necessary packages
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as st
import seaborn as sns
import pandas_profiling
import requests 
%matplotlib inlinetrain = pd.read_csv(r'train.csv')
test = pd.read_csv(r'test.csv')

如果您想在 GUI 中有一个数据字典:

response = requests.get('[https://storage.googleapis.com/kaggle-competitions-data/kaggle/5407/205873/data_description.txt?GoogleAccessId=web-data@kaggle-161607.iam.gserviceaccount.com&Expires=1564407075&Signature=Iduf4UDvx2Cei5S9B7A%2B%2Fz3u%2Ff8GG0RxvpfMu5IHRtJOFBsjq806B2sSr6zucZBwJeBNSOuIpOssfa4i%2BYS8ybrJgaHnA%2Fqkcox6ZsD8BLIl3yTHjwmfkie2ohGSI0bdZLiXblBWps8xJ8sGZPnmTegLYLhFgrA7O0BEF5dIXrFVYufTcndkOeOyYm3fopGjTablaxWOUyhmd43WfOxADJInaMqUk37SBzVD4jD1bj%2F%2B%2FJkK7OeTvUIBJOR3EXij97rhVqcZNdxTttF91t0W3HFcqJrRhrw5%2BKvZmHNzsT5AO164QSjlFqT5kU3dZWoZqxdDOxImVvr%2Fw2m4IRZGCw%3D%3D'](https://storage.googleapis.com/kaggle-competitions-data/kaggle/5407/205873/data_description.txt?GoogleAccessId=web-data@kaggle-161607.iam.gserviceaccount.com&Expires=1564407075&Signature=Iduf4UDvx2Cei5S9B7A%2B%2Fz3u%2Ff8GG0RxvpfMu5IHRtJOFBsjq806B2sSr6zucZBwJeBNSOuIpOssfa4i%2BYS8ybrJgaHnA%2Fqkcox6ZsD8BLIl3yTHjwmfkie2ohGSI0bdZLiXblBWps8xJ8sGZPnmTegLYLhFgrA7O0BEF5dIXrFVYufTcndkOeOyYm3fopGjTablaxWOUyhmd43WfOxADJInaMqUk37SBzVD4jD1bj%2F%2B%2FJkK7OeTvUIBJOR3EXij97rhVqcZNdxTttF91t0W3HFcqJrRhrw5%2BKvZmHNzsT5AO164QSjlFqT5kU3dZWoZqxdDOxImVvr%2Fw2m4IRZGCw%3D%3D'))
dict = response.text
print(dict)

我们现在可以进行快速数据分析:

train.describe().T
test.describe().T

和往常一样,我推荐熊猫简介包

pandas_profiling.ProfileReport(train)

有很多缺失的值。除了逐一检查每个特性并决定如何处理它们之外,没有什么灵丹妙药可以解决这个问题。我们用以下方式清洁它们:

dr = ['Alley','Fence','FireplaceQu','MiscFeature','PoolQC']
train.drop(labels = dr, axis = 1, inplace = True)
test.drop(labels = dr, axis = 1, inplace = True)train['LotFrontage'].fillna(train['LotFrontage'].mean(), inplace = True)
train['GarageQual'].fillna('NA', inplace = True)
train['GarageFinish'].fillna('NA', inplace = True)
train['GarageCond'].fillna('NA', inplace = True)
train['GarageYrBlt'].fillna(train['GarageYrBlt'].mean(), inplace = True)
train['GarageType'].fillna('NA', inplace = True)
train['MasVnrType'].fillna('None', inplace = True)
train['MasVnrArea'].fillna(train['MasVnrArea'].mean(), inplace = True)
train['BsmtQual'].fillna('NA', inplace = True)
train['BsmtCond'].fillna('NA', inplace = True)
train['BsmtExposure'].fillna('NA', inplace = True)
train['BsmtFinType1'].fillna('NA', inplace = True)
train['BsmtFinType2'].fillna('NA', inplace = True)
train['Electrical'].fillna('SBrkr', inplace = True) # substituting with the majority class# and for the test settest['LotFrontage'].fillna(train['LotFrontage'].mean(), inplace = True)
test['GarageQual'].fillna('NA', inplace = True)
test['GarageFinish'].fillna('NA', inplace = True)
test['GarageCond'].fillna('NA', inplace = True)
test['GarageYrBlt'].fillna(train['GarageYrBlt'].mean(), inplace = True)
test['GarageType'].fillna('NA', inplace = True)
test['MasVnrType'].fillna('None', inplace = True)
test['MasVnrArea'].fillna(train['MasVnrArea'].mean(), inplace = True)
test['BsmtQual'].fillna('NA', inplace = True)
test['BsmtCond'].fillna('NA', inplace = True)
test['BsmtExposure'].fillna('NA', inplace = True)
test['BsmtFinType1'].fillna('NA', inplace = True)
test['BsmtFinType2'].fillna('NA', inplace = True)
test['Electrical'].fillna('SBrkr', inplace = True) # substituting with the majority class

有趣的是,测试集有缺失值,而训练集没有。这意味着我们需要做额外的清洁工作:

test['MSZoning'].fillna('RL', inplace = True)
test['Utilities'].dropna(inplace = True)
test['Exterior1st'].dropna(inplace = True)
test['Exterior2nd'].dropna(inplace = True)
test['BsmtFinSF1'].fillna(test['BsmtFinSF1'].mean(), inplace = True)
test['BsmtFinSF2'].fillna(test['BsmtFinSF2'].mean(), inplace = True)
test['BsmtUnfSF'].fillna(test['BsmtUnfSF'].mean(), inplace = True)
test['TotalBsmtSF'].fillna(test['TotalBsmtSF'].mean(), inplace = True)
test['BsmtFullBath'].fillna(test['BsmtFullBath'].mean(), inplace = True)
test['BsmtHalfBath'].fillna(test['BsmtHalfBath'].mean(), inplace = True)
test['KitchenQual'].dropna(inplace = True)
test['Functional'].dropna(inplace = True)
test['GarageCars'].fillna(round(float(test['GarageCars'].mean()),1), inplace = True)
test['GarageArea'].fillna(test['GarageArea'].mean(), inplace = True)
test['SaleType'].dropna(inplace = True)test.drop(test.index[[95,45,485,756,1013,1029]], inplace = True)
test.drop(test.index[[455,691]], inplace = True)
test.drop(test.loc[test['Id']==1916].index, inplace = True)
test.drop(test.loc[test['Id']==2152].index, inplace = True)

在这个过程之后,没有 nan 留下:

train.columns[train.isna().any()].tolist()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

It’s an empty list that would have had columns with NaNs if there were any

test[test.isna().any(axis=1)]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The Test set is also good to go

分类变量的未来工程

这就是你在这里的原因。这是我们将遵循的清单:

  • 确保分类变量被如此对待。这同样适用于数字变量
  • 检查分类要素的基数
  • 查看“可疑”列如何与目标变量交互
  • 查看是否有任何高度相关的要素可以删除
  • 看看有没有可以组合的功能
  • 考虑基数,对分类变量进行一次性编码或频率编码

分类变量的类型为“类别”

如果您查看一些列,如 MSSubClass ,您会意识到,虽然它们包含数值(在本例中为 20、30 等。),它们实际上是分类变量。从数据字典中可以清楚地看出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Numbers don’t always mean numbers

我们怀疑这样的柱子不止一根。我们来确认一下:

[col for col in train.columns.tolist() if train[col].dtype not in ['object']]

它返回非对象列的列表。在阅读了对它们每一个的描述后,我们决定进行以下转换:

train['Id'] = train['Id'].astype('category') 
train['MSSubClass'] = train['MSSubClass'].astype('category')
# train['YearBuilt'] = train['YearBuilt'].astype('category')
# train['YrSold'] = train['YrSold'].astype('category')
# train['YearRemodAdd'] = train['YearRemodAdd'].astype('category')
train['GarageYrBlt'] = train['GarageYrBlt'].astype('category')
train['Fence'] = train['Fence'].astype('category')
train['MiscFeature'] = train['MiscFeature'].astype('category')
train['MiscVal'] = train['MiscVal'].astype('category')

您将很快看到为什么三个与年份相关的列还没有被转换。

基数

如果您有显示高基数的分类要素,您可能会面临某些问题。最有可能的情况是,您将使用一键编码器,您的数据集可能会突然变得非常宽和稀疏。这不利于计算(尤其是当列数接近观察数时),不利于任何基于树的方法(很可能,树会向一个方向生长),并且可能导致过度拟合和数据泄漏。

你可以从概念上或者技术上来解决这个问题。****

概念方法:检查每一个变量,对它们进行 value_counts() 运算,决定是否可以牺牲一些不常用的值,将它们放在“其他”项下。

top = test['GarageType'].isin(test['GarageType'].value_counts().index[:5])
test.loc[~top, 'GarageType'] = "other"

我们刚刚在这里做的: index() 返回给定元素在列表中的位置。在我们的例子中,该列中所有不在频率前五位的值现在都在“其他”中。理想情况下,您希望对每一列都这样做。之后,你做一个热编码。然而,如果你对自己的时间很吝啬,你可能会用一种纯粹的技术方法。最有可能的是,你的计算机将能够处理一个非常广泛的数据集,并相对快速地处理它。所以只要调用 get_dummies()就可以了,希望一切顺利。你可能需要忘记基于森林的或者降维方法,但是,在大多数情况下,你可以忍受它。Sklearn 的 OneHotEncoder() 在这里提供了一些额外的功能可能会有用。它有一个参数 n_values() ,您可以用它来指定每一列可以保留的值的最大数量。

在这个特定的数据集中,我们首先调查了训练列和测试列是否具有不同的基数:

for col in train.columns:
    if train[col].dtype == "object":
        print("For column {} cardinality in Train minus cardinality in Test equals: {}".format(col, train[col].nunique()-test[col].nunique())) 

然后决定通过研究条形图来研究这些信息:

# Gathering columns for which cardinality isn't the same into a list in order to make charts
cols_list = []
for col in train.columns:
     if train[col].dtype == "object" and (train[col].nunique()-test[col].nunique()) != 0:
        cols_list.append(col)

# looking at values in these columns
for l in cols_list:
    sns.catplot(x=l, hue='Status', kind='count', data=combo)
    plt.xticks(rotation=45)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Example of a variable’s values in the train and test datasets

幸运的是,一般来说,没有一个列有很多不同的分类值,测试集和训练集也没有表现出很高的基数。正因为如此,我们能够继续进行一个普通的独热编码。

“可疑”栏

正如我们上面所说的,高基数的情况没有那么糟糕,只适用于相应列中的较小值。因此,我们将保持原样。不过,我们仍然可以检查它们是如何影响销售价格的。

我们将构建盒子图*(可能需要一些时间来渲染)*:

# list w/ categorical variables
cater_cols = train.select_dtypes(include='category').columns.to_list()for cols in cater_cols:
    plt.figure()
    sns.boxplot(x = cols, y = 'SalePrice', data = train)

一个好主意是在以下情况后关闭图表:

plt.clf()
plt.close()

无法检测到任何可见的异常值。

相关

我们将把数字特征与销售价格联系起来,希望了解哪些可以删除,哪些可以合并。查看每个特性可能不是一个好主意,所以让我们关注前 15 个(但是您可以在下面的代码中将这个数字更改为任何其他值)最相关的变量:

corrmat = train.corr()
plt.figure(figsize=(20,10))
k = 15 #number of variables for heatmap
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(train[cols].values.T)
sns.set(font_scale=1.25)
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.values)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Top categories affecting SalePrice

同样,你需要运用一些常识。例如, GarageCarsGarageArea 都在讲述一个关于你停放车辆的地方有多大的故事。关于平方英尺的信息分布在不同的列中,并且可能被汇总。平方英尺的浴池可以跟随诉讼。一个时代的房子和他们何时被改造也应该齐头并进。让我们来实现它:

train['Remodeled Y/N'] = np.where(train['YearRemodAdd'] ==train['YearBuilt'], 'No', 'Yes')
train['Age when Sold'] = train['YrSold'] - train['YearRemodAdd']
train['Remodeled Y/N'] = train['Remodeled Y/N'].astype('category')train['totSqFt'] = train['TotalBsmtSF'] + train['GrLivArea'] + train['1stFlrSF'] + train['2ndFlrSF']train['totBath'] = train['FullBath'] + 0.5*train['HalfBath'] + train['BsmtFullBath'] + 0.5*train['BsmtHalfBath']

我们刚刚创建了一个新列, totSqFt ,它合并了三个现有的值。我们可以检查它是否可以作为一个正确的近似:

fig = plt.figure(figsize=(20,10))
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)ax1.scatter(train['totSqFt'],train['SalePrice'], color = 'crimson', label = 'totSqFt')ax2.scatter(train['GrLivArea'],train['SalePrice'], color = 'teal', alpha = 0.3, label ='GrLivArea')
ax2.scatter(train['TotalBsmtSF'],train['SalePrice'], color = 'midnightblue', label = 'TotalBsmtSF')
ax2.scatter(train['1stFlrSF'],train['SalePrice'], color = 'coral', alpha = 0.4, label = '1stFlrSF')ax1.legend()
ax2.legend()
plt.show()

看起来很准确:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sum of three columns on the left; original features on the right

完成后,我们可以删除进入新变量的列:

# Remove variables that were used to create new features
cols_2_remove = ['GrLivArea','TotalBsmtSF','1stFlrSF','YearRemodAdd','YearBuilt','YrSold','Id','2ndFlrSF',
                'FullBath','HalfBath','BsmtFullBath','BsmtHalfBath','GarageYrBlt']
train_rem = train.copy()
train_rem.drop(cols_2_remove, axis = 1, inplace = True)

我们有独立变量,情况很好,但是让我们再看看销售价格

# Building normality plots
from statsmodels.graphics.gofplots import qqplot
from matplotlib import pyplot

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Normality plot for SalePrice

这张 q-q 图显示,非常便宜和非常昂贵的房子并不真正遵循正态分布。对 totSqFt 的额外检查证实了这一点:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

q-q plot for totSqFt

你可以探索这些又大又贵(或者又小又便宜)的房子:

train_rem[train_rem['totSqFt']>10000]
train_rem[train_rem['SalePrice']>700000]

它们没有什么特别的,所以我们应该对从集合中移除它们感到相对安全:

train_rem.drop(train_rem[train_rem.totSqFt>10000].index, inplace = True)
train_rem.drop(train_rem[train_rem.SalePrice>700000].index, inplace = True)

之后,q-q 图看起来更正常。

这是有效处理具有大量分类特征的数据集的方法。我们已经做了大量的数据探索和预处理,这将在 ML 阶段有所帮助。

现在这里最重要的部分:**你必须对合并的数据集进行任何编码!**为什么?假设您有一个列“颜色”,它在训练集中的值为“蓝色”、“绿色”和“黑色”。同时测试也有“黄色”和“红色”您的编码器必须看到所有可能的值,才能充分利用它们。

操作的顺序是:

  • 在新列状态中分别标记训练集和测试集
  • 组合列车和测试装置,从列车部分移除销售价格
  • 对分类特征进行一次性编码(但不包括状态
  • 使用状态将接头组拆分回列车并测试

没有理由保留分类列的对象类型。让我们把它们变成 类别

# turning object columns into category columns
for i in train.select_dtypes(include='object').columns.to_list():
    train[i] = train[i].astype('category')

和主要部分:

# list w/ categorical variables
cater_cols = train.select_dtypes(include='category').columns.to_list()#Add new column Status to both sets to differentiate between the two
train_1 = train_rem.copy()
train_1.drop(labels = 'SalePrice', axis = 1, inplace = True)
train_1['Status'] = 'Train Set' # adding a column Status to differentiate between Train and Test in the combined set
test_1 = test_rem.copy()
test_1['Status'] = 'Test Set'
combo = train_1.copy()
combo = combo.append(test_1)

确保每件事都做对的一个好方法是不断检查你的数据帧的形状:

train_1.shape
test_1.shape
combo.shape

这里我们单独保存了状态并从 X:

X = combo.copy()
St = X['Status']
X.drop('Status', axis = 1, inplace = True)

以及编码:

X_cat = X.select_dtypes(include=['category'])
X_num = X.select_dtypes(exclude=['category'])
X_encoded = pd.get_dummies(X_cat)

现在我们有三块: X_encoded (编码后的分类变量) X_num (没变的数值变量) St (就一列,状态)。

检查它们的大小是否匹配:

print("X_encoded = {}\nX_num = {}\nSt = {}".format(X_encoded.shape,X_num.shape, St.shape))

将它们组合在一起(并进行最终尺寸检查):

frames = [X_encoded, X_num, St]
combo_enc = pd.concat(frames, axis = 1)print('Combined set is {}'.format(combo_enc.shape))

现在,我们可以将组合集分为训练集和测试集,并继续机器学习:

train_enc = combo_enc.loc[combo_enc['Status']=='Train Set']
test_enc = combo_enc.loc[combo_enc['Status']=='Test Set']print('Encoded Train set is {}\nEncoded Test set is {}'.format(train_enc.shape,test_enc.shape))

这种事实上的方法是透明的,在各种文章和书籍中都有描述。然而,让我们避免使我们的数据集太宽。怎么会?通过频率编码。

频率编码

X_cat_freq = X_cat.copy()for c in X_cat_freq.columns.to_list():
    X_cat_freq[c] = X_cat_freq.groupby(c).transform('count')/len(X_cat_freq[c])

频率编码并不难理解或实现。我们计算一列中不同值的数量,然后除以该列的总长度。结果,我们得到了每一个值的“份额”,这些值在任何 ML 算法中都能很好地发挥作用。

下面的代码看起来应该很熟悉:我们需要区分训练集和测试集,然后将它们合并在一起,

frames_freq = [X_cat_freq, X_num, St]
combo_enc_freq = pd.concat(frames_freq, axis = 1)combo_enc_freq.shape
# All features and Status are together#cut combo_enc_freq by Train and Test. Add SalePrice back to the Train portion
train_freq = combo_enc_freq.loc[combo_enc_freq['Status']=='Train Set']
test_freq = combo_enc_freq.loc[combo_enc_freq['Status']=='Test Set']# adding SalePrice to Encoded Train set
fr = [train_freq, sp]
train_freq = pd.concat(fr, axis = 1)# Checking sizes 
print("Respective sizes of the train set: {}\nOf the test set: {}\nOf the prices array:{}".format(train_freq.shape,
                                                                                                 test_freq.shape,
                                                                                                 sp.shape))

为了便于您比较哪种编码类型会产生更好的结果,我们创建了使用频率和一键编码方法编码的数据帧:

features_freq = train_freq.drop(['SalePrice','Status'], axis = 1)
result_freq = np.exp(train_freq['SalePrice'])X_train_freq, X_test_freq, y_train_freq, y_test_freq = train_test_split(features_freq, result_freq, test_size = 0.2, random_state = 12)features = train_enc.drop(['SalePrice','Status'], axis = 1)
result = train_enc['SalePrice']X_train, X_test, y_train, y_test = train_test_split(features, result, test_size = 0.2, random_state = 12)

机器学习

这一部分在其他资料中有详细解释;此外,GitHub 上的工作簿包含了几个不同模型的实现:从使用 one-hot 编码数据集的回归到 Lasso 和 XGBoost。下面我们将探讨线性回归和 XGBoost,我们在经过频率编码的集合上运行。

import xgboost as xgb
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import StratifiedKFold
import math

加载完依赖项后,我们可以开始建模了。

regr_freq = LinearRegression()
regr_freq.fit(X_train_freq, y_train_freq)print("RMSE is: {:.2f}\nR_squared is {:.2f}%".format(math.sqrt(np.mean((regr_freq.predict(X_test_freq) - y_test_freq) ** 2)),
                                                   regr_freq.score(X_test_freq,y_test_freq)*100))

回归给了我们:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Not bad for the simplest method possible

和 XGBoost:

xgb_freq = xgb.XGBRegressor(n_estimators=100, learning_rate=0.08, gamma=0, subsample=0.75,
                           colsample_bytree=1, max_depth=7)xgb_freq.fit(X_train_freq,y_train_freq)
predictions_xgb_freq = xgb_freq.predict(X_test_freq)
print(explained_variance_score(predictions_xgb_freq,y_test_freq))

现成的结果几乎与回归结果一致:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果我们优化参数,会有帮助吗?运行以下代码需要几分钟时间:

# TAKES TIME
n_estimators = [80, 100, 120, 140, 160]
max_depth = [4, 5, 6, 7, 8, 9, 10]
learning_rate = [0.0001, 0.001, 0.005, 0.01, 0.1, 0.2, 0.3, 0.04]
param_grid = dict(max_depth = max_depth, n_estimators = n_estimators, learning_rate=learning_rate)
kfold = StratifiedKFold(n_splits = 10, shuffle = True, random_state = 10)
grid_search_xg_freq = GridSearchCV(xgb_freq, param_grid, scoring = 'r2', n_jobs = -1, cv=kfold, verbose = 1)
result_gcv_xgb_freq = grid_search_xg_freq.fit(X_train_freq, y_train_freq.astype(int))print("Best score: %f using %s" % (result_gcv_xgb_freq.best_score_, result_gcv_xgb_freq.best_params_))
means = result_gcv_xgb_freq.cv_results_['mean_test_score']
stds = result_gcv_xgb_freq.cv_results_['std_test_score']
params = result_gcv_xgb_freq.cv_results_['params']

让我们使用最佳参数:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Results of GridSearchCV

# Rebuilding using the best parameters:
xgb_freq = xgb.XGBRegressor(n_estimators=110, learning_rate=0.1, gamma=0, subsample=0.75,
                           colsample_bytree=1, max_depth=5)xgb_freq.fit(X_train_freq,y_train_freq)
predictions_xgb_freq = xgb_freq.predict(X_test_freq)
print("R squared is {}".format(explained_variance_score(predictions_xgb_freq,y_test_freq)))

我们可以进一步调整模型,但这不是主要的学习成果。主要的一点是,通过以明智和准确的方式对待分类特征,我们可以在没有非常花哨的机器学习方法或过度计算能力的情况下获得体面的结果。

机器学习,第 1 部分:基本概念

原文:https://towardsdatascience.com/machine-learning-part-1-essential-concepts-c2556fb2f3e1?source=collection_archive---------22-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image by the author

机器学习基础

  1. 基本概念(你在这里)
  2. 监督学习
  3. 无监督学习
  4. 强化学习

系列介绍

当我第一次学习机器学习的时候,我发现了很多对孤立概念的很好的解释:一个算法,一个子领域,一个概念,等等。随着时间的推移,这些孤立的解释开始汇集成一个更大的、相互关联的视野。作为一个倾向于系统思考的人,我希望我能早点接触到提供这种更大视角的东西。

这一系列的文章就是一个尝试。这些帖子应该都适合没有机器学习经验的人,每个部分都提供足够的信息来真正理解特定问题的要点。也就是说,我不会像课程或教科书那样,对每个问题的数学或算法进行详细的描述。相反,重点是提供上下文和机器学习最常见的子问题之间的联系。对于那些喜欢系统思考的人来说,这应该为更深入地研究特定算法和问题提供了一个极好的切入点。

这篇文章的第一部分涵盖了所有机器学习形式的基本概念。它主要谈论数据、数据集以及我们如何使用它们。第 2 部分涵盖监督学习,第 3 部分涵盖非监督学习,第 4 部分涵盖强化学习。如果你甚至不确定什么是机器学习,或者为什么需要它,那么它可能值得一读我的广泛介绍文章。如果你对机器学习/数据科学领域的各种术语感到困惑,我也有一篇关于这个的文章。

有人监督与无人监督

机器学习的一般定义是,我们使用数据来训练一个试图学习复杂决策逻辑的模型。通常,决策是如此复杂,以至于程序员要么自己不知道正确的逻辑,要么不知道如何将该逻辑翻译成计算机友好的格式,或者两者兼而有之。如果逻辑简单,程序员知道,他们可以直接编程。学习复杂决策的逻辑通常是通过使用数据集来完成的。根据我们收到的数据类型,我们有两种不同的方法来学习我们的决策逻辑。

监督学习中,我们有一个训练观察数据集,它被**标记。**带标签的数据意味着“正确”的答案提供给了我们。用更专业的术语来说,我们知道特定输入的预期输出。有标签很重要,原因有二:首先,假设我们生成一个逻辑,给它输入,然后生成输出(预测)。因为我们有标签,我们可以将我们的逻辑预测与预期输出(标签)进行比较,看看我们的预测是否准确。

训练数据的准确性是有用的,因为我们假设训练数据非常类似于我们最终想要对其使用该逻辑的未标记的真实世界数据。训练数据的良好准确性通常也转化为现实世界的良好准确性。如果训练数据不像真实世界,那么基本上不可能产生好的预测。这通常用短语“垃圾进,垃圾出”来描述

如果我们发现我们的逻辑是而不是输出好的预测,那么我们可以将标签用于它们的第二个目的:指导我们逻辑的改进。事实上,这正是“监督”一词的来源:像这样的算法通常有一个学习器元素,它是问题的模型/逻辑。他们还有一个教师元素,监督学习者并使用标签提供对预测的反馈。

让我们看一个简单的例子。假设你希望能够准确预测汽车的耗油量,你该如何去做呢?你可以很容易地做的一件事就是指着路上的汽车说:“我想那辆车每加仑跑 X 英里。”然而,如果没有任何形式的反馈,那就不太可能提高你的猜测。你不仅不知道你的猜测是否接近,你也不知道它们是如何错的;它们是太高还是太低?他们是在球场上还是在远处?

如果没有反馈,流程会停止,但我们可以通过收集更多数据来停止。那么,假设你去了一个汽车展,那里有数百辆汽车的橱窗上贴着(字面上的)标签,上面列出了油耗等信息。现在你可以看着一辆车,做一个预测,然后将这个预测与窗口中列出的实际油耗进行比较。假设一开始你猜轿车 100mpg 左右,SUV 更好 120mpg 左右。接触甚至两三个不同的标签示例就足以让你意识到这两个猜测都太高了,事实上 SUV 比轿车(总的来说)的油耗更低。

你得到的反馈越多,你就越能认识到一些趋势,比如大型汽车的油耗越低,大型发动机的油耗越低,新车的油耗比旧车高。从长远来看,所有这些模式都有助于做出更好的整体预测。不仅如此,当你预测未标记的数据时,它们会给你一个很好的错误概念。如果你预测的平均误差是 5mpg,那么当你做一个新的预测时,你应该确信它接近真实值。如果你的平均误差是 20 英里/加仑,那么用现有的数据做出准确的预测是不可能的。在这两种情况下,监管为我们的预测模型提供了至关重要的信息。

无监督学习是……嗯,没有监督。基本上“无监督的”变成了一个包罗万象的术语,指任何不遵循教师/学习者模式,没有监督元素的事物。事实上,根据某些定义,无监督学习甚至根本不是机器学习*,因为没有“教师”元素,同样也没有“学习者”元素。根据这一论点,无监督学习只是统计分析。*

然而,根据大多数定义,无监督学习仍然算作机器学习,我们在这里涵盖它。很难像上面我们对监督学习所做的那样解释无监督学习,因为每种无监督方法都倾向于解决不同的问题,并做出不同的假设。我能想到的解释它的最好方式是说,在监督学习中,我们在数据中寻找模式,这样我们就可以将这些模式与标签联系起来,希望这种方式能让我们准确地预测标签。

无监督学习中,我们仍然在寻找模式,但是我们没有标签来关联这些模式。所以无监督的方法倾向于寻找特定类型的模式,基于这些模式通常重要的假设。例如,找到相似点的聚类,通常意味着这些点有一些共同点,即使我们不知道那是什么。找到对其余数据极端异常的点通常意味着这些点与其余数据相比具有非常独特的特征。如果没有进一步的调查,我们通常不会知道这个独特的特征是什么,但是识别异常点是这个过程中必要的第一步。

描述数据集

鉴于数据对机器学习的重要性,拥有一个描述数据的词汇最终是必不可少的。不幸的是,在数据科学中,许多概念有许多不同的等价术语。一线希望:这里的概念比看起来要容易理解得多。

在绝大多数机器学习应用中,数据集可以被认为类似于电子表格或表格。被称为特征变量。每个都是一个实例观察实例。示例通常也被称为数据点或仅仅是,因为在数学上它们代表了一个 n 维空间中的一个点,其中 n 是特征的数量。

在监督学习中,特征有其他名称,这取决于该特征是否是期望的输出(也称为标签),或者它是否是我们用来预测该标签的特征。我们用来预测输出的特征称为输入变量/输入预测器独立变量。期望输出被称为输出变量/输出响应变量因变量。这些通常是成对的:如果你看到术语“自变量”用于输入,你会期望“因变量”用于输出。在代码和方程中,预测值通常标记为X,而标签使用y

为什么同样的东西有这么多术语?机器学习背后的理论被许多领域使用并得到发展。经济学家一般使用“独立/因变量”,统计学家一般使用“预测器/响应”,计算机科学家更可能使用“输入/输出”。大多数情况下,我会使用“预测/反应”,因为我觉得它们是最直观的术语,也最容易记住哪个是哪个。“输入/输出”也很好,但它们在计算机科学中太常见了,含义略有不同,所以我宁愿避免使用它们。

最后,特性是一个特例,它可以描述任何列,但它最常用于我们不关心该列是预测还是响应的时候。因此,在无监督学习(没有预测器/响应)中,我们使用“特征”来描述一切。

噪音

所有数据都包含信息,但是该信息被分成两部分:信号和噪声。信号是我们想要的,它是数据中有价值和有用的部分。噪声可能来自许多来源,但其效果总是会给数据带来我们不想要且无法解释的变化。

让我们考虑一个例子:我们为一个学区工作,我们听说了一项研究,在学校增加更多的植物可以提高考试成绩。我们想尝试这种方法,但由于预算原因,该地区不想要真的植物,他们只想买一堆假植物,希望效果是一样的。他们决定先在一所学校尝试,然后在整个学区推广这个项目。

令许多人惊讶的是,在增加了塑料植物后,这所学校的考试成绩直线上升。负责人自然很激动,但是有没有可能这里发生了别的事情?

事实上是有的。在添加植物前一个月左右,学校与当地一所大学合作,让大学生来学校为高中生提供一对一的辅导。我们的分析没有考虑或控制这一点——这不是数据集的一部分——但辅导项目可能比假工厂对考试增加的贡献更大是有道理的。

现在让我们通过信号和噪声的框架来考虑这个问题。在这种情况下,“信号”是任何关于假植物特别是效果的数据。我们只想测量植物对考试分数的影响。然而,噪音已经以我们做了而不是测量的事情的形式悄悄进来,这些事情仍然影响着结果——特别是辅导项目。

不可测量的变量是一个极其常见的噪声源,还有其他的。当数据来自传感器时,另一个常见的噪声源是电磁干扰。干扰是(电话公司)最先广泛研究的噪音形式之一,因为当通过扬声器收听时,它会产生持续的静态嗡嗡声,所以它也是术语“噪音”的来源。

我们如何处理噪音?在大多数情况下,我们不知道,它只是我们数据集的固有部分。有时可以通过添加新特征(测量不可测量的量)、控制缺失变量和/或通过更先进的噪声消除技术来消除噪声。大多数噪声去除取决于噪声的类型及其来源,并且它们通常不能完全去除噪声。

幸运的是,机器学习算法在面对噪声时仍然有效,它们将根据给定的数据生成最佳模型。很多时候这就足够了,有无数有用的 ML 模型已经在嘈杂的数据集上进行了训练。然而,有时我们收到的数据并不能产生一个真正有效的模型。发生这种情况时,噪音通常是罪魁祸首。

展望未来,我不会过多地谈论噪声,除非算法有其他人没有的噪声问题。然而,这是应该永远记住的事情,因为它是数据科学的基础部分。

下一个

上面的概念对所有类型的机器学习都是通用的,所以在前进的过程中有一些熟悉是有帮助的。接下来,我们进入监督学习。

Python 中的主成分分析示例

原文:https://towardsdatascience.com/machine-learning-part-15-dimensionality-reduction-with-principal-component-analysis-a5b3bb7353bc?source=collection_archive---------9-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Markus Spiske on Unsplash

主成分分析或 PCA 用于在不损失太多信息的情况下减少特征的数量。拥有过多维度的问题在于,它使得数据难以可视化,并且使得训练模型在计算上更加昂贵。

为了让我们对 PCA 有一个直观的理解,假设我们想要建立一个预测房价的模型。我们将从收集该地区房屋的数据开始。假设我们收集了数以千计的样本,每个样本都包含了一个给定房屋的属性信息。这些属性包括卧室数量、浴室数量和面积。常识会让我们相信,卧室的数量、浴室的数量和房子的面积之间存在某种关系。换句话说,我们怀疑房子的面积越大,包含的卧室和浴室就越多。如果变量高度相关,我们真的有必要为同一基本特征(即大小)设置三个独立的变量吗?主成分分析用于确定哪个变量(即浴室数量或平方英尺)占房价的最大差异,并将它们结合起来。

假设我们绘制了一个任意变量的三个样本。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

平均值等于所有数据点的总和除以样本总数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

单个数据点的方差就是它与平均值的距离。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

整个数据集的方差是所有这些距离的平方和除以样本总数。我们最终将这些值平方,因为在坐标系中,平均值左侧的距离将为负,并且会与平均值右侧的距离抵消。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在二维空间中,为了计算其中一个变量的方差,我们将数据点投影到它的轴上,然后遵循与前面相同的过程。一个特征(即薪水)的均值和方差是相同的,不管它所绘制的其他特征是什么。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可惜的是,xy 方差本身并没有包含足够的信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

尽管两个图有明显的差异,但它们导致相同的 xy 方差。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,我们利用另一个叫做协方差的性质。计算协方差时,我们将 x 和 y 坐标相乘,而不是取平均值的距离的平方。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

协方差和相关性是不同的概念。然而,它们都描述了两个变量之间的关系。更具体地说,两个变量之间的相关性实际上是协方差除以第一个变量的方差的平方根乘以第二个变量的方差。因此,当相关或协方差为负时,x 的增加导致 y 的减少,当相关或协方差为正时,x 的增加导致 y 的增加。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两个变量协方差矩阵由左上角第一个变量的方差、右下角第二个变量的方差和对角线上剩余两个位置的协方差组成。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作为 PCA 算法的一部分,协方差矩阵用于计算特征值和特征向量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

假设我们画出了两个不同变量之间的关系。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

首先,我们将数据居中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,我们在特征向量的方向上画两个向量,它们的大小与特征值相等。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后我们选择方差最大的一个,因为当我们删除另一个维度时,它会导致最少的信息损失。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后,数据点被投影到直线上。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

后者用作新特征的一维图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

密码

让我们看看如何用 python 实现主成分分析。首先,导入所有必需的库。

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris

在本例中,我们将使用 iris 数据集,该数据集可以通过 sklearn API 轻松导入。

iris = load_iris()X = pd.DataFrame(iris.data, columns=iris.feature_names)
y = pd.Categorical.from_codes(iris.target, iris.target_names)

正如你所见,有 4 个特点。凭直觉,我们可以预测萼片长度和萼片宽度之间有很强的相关性,花瓣长度和花瓣宽度之间也有很强的相关性。因此,我们应该能够将维数从 4 减少到 2。

X.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如我们前面看到的,方差是通过从平均值中取距离的平方和来计算的。因此,如果一个要素的尺度比另一个要素大得多,那么即使相对离差可能较小,它的方差也会大得多。因此,我们必须扩展数据。在缩放数据时,平均值设置为 0,标准偏差设置为 1。

scaler = StandardScaler()
X = scaler.fit_transform(X)

接下来,我们将使用 PCA 将维数从 4 减少到 2。

pca = PCA(n_components=2)principal_components = pca.fit_transform(X)new_X = pd.DataFrame(data = principal_components, columns = ['PC1', 'PC2'])

让我们来看看这两个新特性。

new_X.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,我们可以使用一个 scree 图来可视化每个主成分解释的方差的百分比。

per_var = np.round(pca.explained_variance_ratio_ * 100, decimals=1)labels = ['PC' + str(x) for x in range(1, len(per_var) + 1)]plt.bar(x=range(1, len(per_var)+1), height=per_var, tick_label=labels)
plt.ylabel('percentange of explained variance')
plt.xlabel('principal component')
plt.title('scree plot')
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后的想法

总而言之,我们采用一个多维数据集并绘制它(虽然我们不能可视化任何大于 3 维的东西,但数学仍然会解决)。然后我们计算协方差矩阵和特征向量/特征值。后者将告诉我们哪些特征是高度相关的,并且可以在没有太大信息损失的情况下被压缩。产生的特征可用于训练我们的模型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

朴素贝叶斯分类器

原文:https://towardsdatascience.com/machine-learning-part-16-naive-bayes-classifier-in-python-c9d3fa496fa4?source=collection_archive---------17-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Green Chameleon on Unsplash

与其他通过多次迭代来收敛到某个解决方案的机器学习算法相比,朴素贝叶斯仅基于条件概率对数据进行分类。朴素贝叶斯有以下优点:

  • 训练和预测速度极快
  • 可解释的
  • 不需要超参数调整

在决定是否使用朴素贝叶斯时,您应该考虑朴素假设是否实际成立(在实践中非常罕见),以及您正在处理的数据是否具有很高的维数。

贝叶斯定理

很多时候,我们想知道某个事件发生的概率,假设另一个事件已经发生。这可以象征性地表示为 P(E|F)。如果两个事件不是独立的,那么这两个事件发生的概率由下面的公式表示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例如,假设您从一副标准的 52 张牌中抽取两张牌。这副牌中一半是红色的,一半是黑色的。这些事件不是独立的,因为第二次抽签的概率取决于第一次抽签的结果。

P(E) = P(第一次抽黑牌)= 25/52 = 0.5

P(F|E) = P(第二次抽黑牌|第一次抽黑牌)= 25/51 = 0.49

利用这些信息,我们可以计算连续抽两张黑牌的概率,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Baye 定理是条件概率最常见的应用之一。例如,baye 定理被用来计算一个在特定疾病筛查测试中呈阳性的人实际患有该疾病的概率。贝叶斯定理可以表示为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你已经知道 P(A),P(B)和 P(B|A ),但想知道 P(A|B ),你可以使用这个公式。例如,假设我们正在测试一种罕见的疾病,这种疾病会感染 1%的人口。医学专家已经开发了一种高度敏感和特异的测试,但还不十分完善。

  • 99%的病人测试呈阳性
  • 99%的健康患者测试呈阴性

贝叶斯定理告诉我们:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

假设我们有 10,000 人,100 人生病,9,900 人健康。此外,在对所有人进行测试后,我们会让 99 名病人进行测试,但也让 99 名健康人进行测试。因此,我们会以下面的概率结束。

p(生病)= 0.01

p(没病)= 1 - 0.01 = 0.99

p(+|有病)= 0.99

p(+|未患病)= 0.01

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

针对单个单词的垃圾邮件过滤器

朴素贝叶斯通常用于构建垃圾邮件过滤器,将电子邮件分类为垃圾邮件或 ham(非垃圾邮件)。例如,我们可能会开发一个垃圾邮件过滤器,根据某个单词的出现将一封电子邮件归类为垃圾邮件。例如,如果一封电子邮件包含单词 【伟哥】 ,我们将其归类为垃圾邮件。另一方面,如果一封电子邮件包含单词 money,那么它有 80%的可能是垃圾邮件。

根据贝叶斯定理,给定包含“单词”的邮件是垃圾邮件的概率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

虽然我们不知道分母的值,但可以用下面的公式计算出来。简单地说,找到该单词的概率是在垃圾邮件中找到该单词的概率乘以电子邮件是垃圾邮件的概率,加上在垃圾邮件中找到该单词的概率乘以电子邮件是垃圾邮件的概率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,公式变为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

训练集包含足够的信息量来计算等式的右边。

p(垃圾邮件)

被归类为垃圾邮件的电子邮件数量

火腿

被归类为垃圾邮件(非垃圾邮件)的电子邮件数量

p(word|spam)

包含“单词的垃圾邮件数量

p(单词|火腿)

包含“*单词”*的垃圾邮件数量

结合单词的垃圾邮件过滤器

实际上,仅仅根据一个单词的出现来进行分类是不够的。有些词本身是无害的。当它们与特定的其他单词结合使用时,我们更应该将其归类为垃圾邮件。例如,根据包含单词“ 女孩 ”的事实来过滤电子邮件,最终会将与您女儿的足球队相关的电子邮件放入您的垃圾邮件文件夹中。理想情况下,我们能够针对特定的句子,如“ 你所在地区的漂亮女孩 ”。

天真的假设

通常,在我们的训练集中,我们不会有带有适当标签的准确句子。换句话说,如果我们试图确定一封包含“ 你所在地区的漂亮女孩 ”的电子邮件是否应该被归类为垃圾邮件,我们会查看我们的训练数据,看看是否有任何包含该句子的电子邮件已经被归类为垃圾邮件。如果没有,我们有两个选择,要么获取更多的数据,要么通过查看句子中的每个单词来计算给定的概率。

为了使数学更简单,我们做了简单的假设,文本中的单词是相互独立的**。换句话说,文本中包含某些单词的事实对在文本中找到给定单词的概率没有影响。然而在现实中,某些词往往会被组合在一起使用。例如,如果你在一篇关于机器学习的文章中找到单词,很可能你也会找到单词*和 训练 。*****

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

假定一封电子邮件同时包含单词“有吸引力的”和“女孩”,则该电子邮件包含垃圾邮件的概率可以写为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

密码

我们将从导入所需的库开始。

**from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics**

在前面的例子中,我们将使用新闻文章的语料库。幸运的是,sklearn 提供了一个简单的 API 来导入数据。

**newsgroups = fetch_20newsgroups()**

顾名思义,新闻文章分为 20 类。

**print(newsgroups.target_names)**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

语料库包含超过 11,000 个文档。

**print(newsgroups.filenames.shape)**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了了解我们在做什么,让我们打印第一个文档。

**print(newsgroups.data[0])**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了简单起见,我们将使用类别的子集。

**categories = ['alt.atheism', 'talk.religion.misc', 'comp.graphics', 'sci.space']train_newsgroups = fetch_20newsgroups(subset='train', categories=categories)
train_X = train_newsgroups.data
train_y = train_newsgroups.targettest_newsgroups = fetch_20newsgroups(subset='test', categories=categories)
test_X = test_newsgroups.data
test_y = test_newsgroups.target**

接下来,我们使用 TfidfVectorizer 类来解析每个文档中包含的单词,并根据相关性对它们进行排序。如果你想了解更多关于 TF-IDF 是如何工作的,我会在后续文章中详细介绍。

**** [## 自然语言处理:使用 TF-IDF 的特征工程

自然语言处理(NLP)是人工智能的一个子领域,处理理解和处理…

medium.com](https://medium.com/@corymaklin/natural-language-processing-feature-engineering-using-tf-idf-e8b9d00e7e76)

vectorizer = TfidfVectorizer()
train_vectors = vectorizer.fit_transform(train_X)
test_vectors =  vectorizer.transform(test_X)

我们使用多维朴素贝叶斯,因为我们试图将数据分为多个类别。与其他机器学习算法相比,朴素贝叶斯的训练过程几乎是瞬时的。

classifier = MultinomialNB()
classifier.fit(train_vectors, train_y)

我们使用 f1 分数来衡量我们模型的性能。

predictions = classifier.predict(test_vectors)score = metrics.f1_score(test_y, predictions, average='macro')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

另外,我们可以写一个函数来预测一个句子属于哪一类。

def predict_category(sentence):
    sentence_vector = vectorizer.transform([sentence])
    prediction = classifier.predict(sentence_vector)
    return train_newsgroups.target_names[prediction[0]]

正如你所看到的,这个模型正确地将这个句子归类到了计算机图形学中。

predict_category('determining the screen resolution')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后的想法

朴素贝叶斯特别适合对具有大量特征的数据进行分类。与其他机器学习模型不同,朴素贝叶斯几乎不需要训练。当试图做出一个包含多个特征的预测时,我们通过做出天真的假设这些特征是独立的来简化数学。****

Python 中的 AdaBoost 分类器示例

原文:https://towardsdatascience.com/machine-learning-part-17-boosting-algorithms-adaboost-in-python-d00faac6c464?source=collection_archive---------2-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Franki Chamaki on Unsplash

boosting 方法背后的一般思想是顺序训练预测器,每个预测器都试图纠正其前任。两种最常用的增强算法是 AdaBoost 和梯度增强。在接下来的文章中,我们将介绍 AdaBoost。在高层次上,AdaBoost 类似于随机森林,因为它们都汇总了森林中每个决策树所做的预测,以决定最终的分类。然而,还是有一些细微的差别。例如,在 AdaBoost 中,决策树的深度为 1(即 2 个叶子)。此外,每个决策树做出的预测对模型做出的最终预测有不同的影响。

算法

在前面的例子中,我们将使用一个数据集,该数据集根据某些特征对人进行分类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 1:初始化样品重量

在 AdaBoost 的第一步中,每个样本都与一个权重相关联,该权重指示它对于分类的重要性。最初,所有样本都具有相同的权重(1 除以样本总数)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二步:用每个特征建立一个决策树,对数据进行分类并评估结果

接下来,对于每个特性,我们构建一个深度为 1 的决策树。然后,我们使用每一个决策树对数据进行分类。然后,我们将每棵树的预测与训练集中的实际标签进行比较。在分类训练样本方面做得最好的特征和对应的树成为森林中的下一棵树。

例如,假设我们建立了一棵树,将聪明的人归类为有吸引力的,不聪明的人归类为没有吸引力的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

决策树错误地将一个人归类为有吸引力的人,因为他们很聪明。我们对所有的树重复这个过程,并选择错误预测最少的树。

步骤 3:计算树在最终分类中的重要性

一旦我们决定了决策树。我们用前面的公式来计算在最后的分类中它的数量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中总误差是错误分类样本的权重之和。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

回到我们的例子,总误差等于如下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过将误差代入我们的公式,我们得到:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如我们将在后面看到的,这个数字用于确定整个森林所做的预测。

步骤 4:更新样本权重,以便下一个决策树将考虑前一个决策树产生的错误

我们查看当前树分类不正确的样本,并使用以下公式增加它们的相关权重。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里没什么特别的。我们将 e 提升到上一步中计算的显著性的幂,因为我们希望新的样本权重呈指数增长。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后,我们查看树正确分类的样本,并使用以下公式减少它们的关联权重。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个等式和之前的一样,只是这次我们把 e 提升到负指数的幂。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里的要点是,先前残肢错误分类的样本应该与较大的样本权重相关联,而正确分类的样本应该与较小的样本权重相关联。

请注意,如果我们将所有样本的权重相加,我们会得到一个小于 1 的数字。因此,我们对新的样本权重进行归一化,使它们加起来等于 1。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 5:形成新的数据集

我们首先创建一个与原始数据集大小相同的新的空数据集。然后,想象一个轮盘赌台,其中每个口袋对应一个样品重量。我们随机选择 0 到 1 之间的数字。每个数字所在的位置决定了我们将哪个样本放入新数据集中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因为被错误分类的样本相对于其他样本具有更高的权重,所以随机数落入它们的分布部分的可能性更大。因此,新数据集将倾向于包含被之前的树错误分类的样本的多个副本。因此,当我们返回到评估每个决策树所做预测的步骤时,得分最高的决策树将会正确地对前一个决策树误分类的样本进行分类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 6:重复步骤 2 到 5,直到迭代次数等于超参数指定的次数(即估计数)

步骤 7:使用决策树森林对训练集之外的数据进行预测

AdaBoost 模型通过让森林中的每棵树对样本进行分类来进行预测。然后,我们根据他们的决定把树分成组。对于每个组,我们把组内每棵树的重要性加起来。森林作为一个整体所做的最终分类是由具有最大总和的组确定的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

密码

让我们看看如何在 Python 中实现 AdaBoost。首先,我们导入以下库。

from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_breast_cancer
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.preprocessing import LabelEncoder

在这个例子中,我们将使用 AdaBoost 将肿瘤分类为恶性或良性。我们使用 scikit-learn API 将数据集导入我们的程序。

breast_cancer = load_breast_cancer()X = pd.DataFrame(breast_cancer.data, columns=breast_cancer.feature_names)
y = pd.Categorical.from_codes(breast_cancer.target, breast_cancer.target_names)

每当我们处理分类特征时,我们必须把它编码成数字。对于这个问题,我们将恶性设为 1,良性设为 0。

encoder = LabelEncoder()
binary_encoded_y = pd.Series(encoder.fit_transform(y))

我们将数据分为训练集和测试集,以评估模型的性能。

train_X, test_X, train_y, test_y = train_test_split(X, binary_encoded_y, random_state=1)

接下来,我们构建模型并使其适合训练集。max_depth=1用于告诉我们的模型,我们希望我们的森林由具有单个决策节点和两片叶子的树组成。n_estimators用于指定森林中的树木总数。

classifier = AdaBoostClassifier(
    DecisionTreeClassifier(max_depth=1),
    n_estimators=200
)classifier.fit(train_X, train_y)

我们使用我们的模型来预测肿瘤是恶性的还是良性的。

predictions = classifier.predict(test_X)

最后,我们使用混淆矩阵评估模型。该模型以 2 个假阳性和 3 个假阴性结束。

confusion_matrix(test_y, predictions)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后的想法

像随机森林一样,AdaBoost 通过对每个样本应用多个决策树并结合各个树的预测来进行预测。然而,在 AdaBoost 算法中,每个决策树对最终预测的贡献是不同的,而不是取森林中每个决策树所做预测的平均值(或分类情况下的大多数)。

梯度推进决策树算法讲解

原文:https://towardsdatascience.com/machine-learning-part-18-boosting-algorithms-gradient-boosting-in-python-ef5ae6965be4?source=collection_archive---------1-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by NeONBRAND on Unsplash

在接下来的文章中,我们将看看如何在 Python 中实现渐变增强。梯度增强类似于 AdaBoost,因为它们都使用决策树的集合来预测目标标签。然而,与 AdaBoost 不同,梯度增强树的深度大于 1。在实践中,您通常会看到梯度增强的最大叶子数在 8 到 32 之间。

算法

在我们深入研究代码之前,重要的是我们要理解梯度增强算法是如何实现的。假设,我们试图根据房子的年龄、面积和位置来预测房子的价格。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 1:计算目标标签的平均值

当处理回归问题时,我们从一片叶子开始,它是我们想要预测的变量的平均值。在接下来的步骤中,这一页将用作接近正确解决方案的基线。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二步:计算残差

对于每个样本,我们用下面的公式计算残差。

残差=实际值-预测值

在我们的示例中,预测值等于上一步中计算的平均值,实际值可以在每个样本的 price 列中找到。计算残差后,我们得到下表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 3:构建决策树

接下来,我们构建一棵树,目标是预测残差。换句话说,每片叶子将包含一个关于残差值的预测(不是期望的标签)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果残差比叶子多,一些残差将在同一个叶子中结束。当这种情况发生时,我们计算它们的平均值,并将其放入叶子中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这样,树就变成了:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 4:使用集合中的所有树预测目标标签

每个样本通过新形成的树的决策节点,直到它到达给定的线索。所述叶中的残差用于预测房价。

通过实验表明,朝着解决方案采取小的增量步骤可以实现具有较低总体方差的可比偏差(较低的方差导致训练数据之外的样本具有更好的准确性)。因此,为了防止过度拟合,我们引入了一个叫做学习率的超参数。当我们做一个预测时,每个残差都要乘以学习率。这迫使我们使用更多的决策树,每一棵都向最终解决方案迈出一小步。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 5:计算新的残差

我们通过从上一步的预测中减去实际房价来计算一组新的残差。如步骤 3 所述,残差将用于下一个决策树的叶子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 6:重复步骤 3 到 5,直到迭代次数与超参数指定的次数(即估计数)相匹配

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 7:一旦训练完毕,使用集合中的所有树对目标变量的值进行最终预测

最终预测将等于我们在第一步中计算的平均值,加上组成森林的树木预测的所有残差乘以学习率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

密码

在本教程中,我们将使用来自 scikit-learn 库中的GradientBoostingRegressor类。

from sklearn.ensemble import GradientBoostingRegressor
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.datasets import load_boston
from sklearn.metrics import mean_absolute_error

对于前面的示例,我们将使用波士顿房价数据集。

boston = load_boston()
X = pd.DataFrame(boston.data, columns=boston.feature_names)
y = pd.Series(boston.target)

为了评估我们模型的性能,我们将数据分为训练集和测试集。

X_train, X_test, y_train, y_test = train_test_split(X, y)

接下来,我们构建并拟合我们的模型。max_depth是指每棵树的叶子数量(即 4 片),而n_estimators是指集合中树的总数。如前所述,learning_rate超参数缩放每棵树的贡献。如果将其设置为较低的值,集合中将需要更多的树来适应训练集,但总体方差会更低。

regressor = GradientBoostingRegressor(
    max_depth=2,
    n_estimators=3,
    learning_rate=1.0
)
regressor.fit(X_train, y_train)

staged_predict()方法测量每个训练阶段的验证误差(即一棵树、两棵树……),以找到最佳的树数。

errors = [mean_squared_error(y_test, y_pred) for y_pred in regressor.staged_predict(X_test)]best_n_estimators = np.argmin(errors)

现在,我们可以使用最佳数量的树来构建和拟合我们的模型。

best_regressor = GradientBoostingRegressor(
    max_depth=2,
    n_estimators=best_n_estimators,
    learning_rate=1.0
)
best_regressor.fit(X_train, y_train)

Sklearn 提供了许多指标来评估我们的机器学习模型的性能。我发现特别有用的是,他们根据适用的问题领域对每个指标进行分类。例如,精度只在分类的上下文中有意义。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://scikit-learn.org/stable/modules/model_evaluation.html

我们使用平均绝对误差,它可以解释为预测值和实际值之间的平均距离。

y_pred = best_regressor.predict(X_test)mean_absolute_error(y_test, y_pred)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ARIMA 模型 Python 示例-时间序列预测

原文:https://towardsdatascience.com/machine-learning-part-19-time-series-and-autoregressive-integrated-moving-average-model-arima-c1005347b0d7?source=collection_archive---------0-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://www.pexels.com/photo/white-printer-paper-590011/

基于历史观察做出预测的能力创造了竞争优势。例如,如果一个组织有能力更好地预测一种产品的销售量,它将在优化库存水平方面处于更有利的地位。这可以增加组织现金储备的流动性,减少营运资本,并通过减少积压订单来提高客户满意度。

在机器学习领域,有一组特定的方法和技术特别适合于根据时间预测因变量的值。在接下来的文章中,我们将讨论自回归综合移动平均(ARIMA)。

我们将按时间顺序索引(或绘制)的一系列数据点称为时间序列。时间序列可以分解成 3 个部分。

  • **趋势:**向上&数据在很长一段时间内随时间的向下移动(即房屋升值)
  • **季节性:**季节性差异(即夏季对冰淇淋的需求增加)
  • **噪声:**尖峰信号&随机间隔的低谷信号

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://commons.wikimedia.org/wiki/File:Mae.timeseries_decomposition.commonswiki.svg

在对时间序列应用任何统计模型之前,我们希望确保它是平稳的。

数据是静止的意味着什么?

序列的平均值不应该是时间的函数。下面的红色图表不是静止的,因为平均值会随着时间的推移而增加。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

序列的方差不应该是时间的函数。这种性质称为同质性。请注意红色图表中数据随时间变化的分布。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,第(i+m)项的第 I 项的协方差不应该是时间的函数。在下图中,你会注意到随着时间的增加,传播变得越来越近。因此,对于红色系列,协方差随时间不是常数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果一个时间序列是平稳的,并且在给定的时间间隔内具有特定的行为,那么可以有把握地假设它在以后的某个时间点将具有相同的行为。大多数统计建模方法假设或要求时间序列是平稳的。

密码

statsmodels库提供了一套处理时间序列数据的函数。

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from statsmodels.tsa.stattools import adfuller
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.arima_model import ARIMA
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()

我们将使用一个包含某一天飞机乘客数量的数据集。

df = pd.read_csv('air_passengers.csv', parse_dates = ['Month'], index_col = ['Month'])df.head()plt.xlabel('Date')
plt.ylabel('Number of air passengers')
plt.plot(df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如前所述,在我们建立模型之前,我们必须确保时间序列是平稳的。有两种主要方法来确定给定时间序列是否是平稳的。

  • 滚动 统计:绘制滚动平均值和滚动标准差。如果时间序列随时间保持不变,则时间序列是静止的(用肉眼观察这些线是否是直的并且平行于 x 轴)。
  • 扩展的 Dickey-Fuller 检验:如果 p 值较低(根据零假设),并且 1%、5%、10%置信区间的临界值尽可能接近 ADF 统计值,则认为时间序列是平稳的

对于那些不理解平均价格和滚动平均价格之间区别的人来说,10 天的滚动平均价格是作为第一个数据点的前 10 天的收盘价的平均值。下一个数据点将删除最早的价格,添加第 11 天的价格并取平均值,依此类推,如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

rolling_mean = df.rolling(window = 12).mean()
rolling_std = df.rolling(window = 12).std()plt.plot(df, color = 'blue', label = 'Original')
plt.plot(rolling_mean, color = 'red', label = 'Rolling Mean')
plt.plot(rolling_std, color = 'black', label = 'Rolling Std')
plt.legend(loc = 'best')
plt.title('Rolling Mean & Rolling Standard Deviation')
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如您所见,滚动平均值和滚动标准差随着时间的推移而增加。因此,我们可以得出结论,时间序列不是平稳的。

result = adfuller(df['Passengers'])print('ADF Statistic: {}'.format(result[0]))
print('p-value: {}'.format(result[1]))
print('Critical Values:')
for key, value in result[4].items():
    print('\t{}: {}'.format(key, value))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ADF 统计值远离临界值,p 值大于阈值(0.05)。因此,我们可以得出结论,时间序列不是平稳的。

取因变量的对数是降低滚动平均值增长率的简单方法。

df_log = np.log(df)
plt.plot(df_log)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们创建一个函数来运行这两个测试,以确定给定的时间序列是否是平稳的。

def get_stationarity(timeseries):

    # rolling statistics
    rolling_mean = timeseries.rolling(window=12).mean()
    rolling_std = timeseries.rolling(window=12).std()

    # rolling statistics plot
    original = plt.plot(timeseries, color='blue', label='Original')
    mean = plt.plot(rolling_mean, color='red', label='Rolling Mean')
    std = plt.plot(rolling_std, color='black', label='Rolling Std')
    plt.legend(loc='best')
    plt.title('Rolling Mean & Standard Deviation')
    plt.show(block=False)

    # Dickey–Fuller test:
    result = adfuller(timeseries['Passengers'])
    print('ADF Statistic: {}'.format(result[0]))
    print('p-value: {}'.format(result[1]))
    print('Critical Values:')
    for key, value in result[4].items():
        print('\t{}: {}'.format(key, value))

我们可以对时间序列进行多种变换,使其保持平稳。例如,我们减去滚动平均值。

rolling_mean = df_log.rolling(window=12).mean()
df_log_minus_mean = df_log - rolling_mean
df_log_minus_mean.dropna(inplace=True)get_stationarity(df_log_minus_mean)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以看到,减去均值后,滚动均值和标准差是近似水平的。p 值低于阈值 0.05,ADF 统计值接近临界值。因此,时间序列是平稳的。

应用指数衰减是另一种转换时间序列使其稳定的方法。

rolling_mean_exp_decay = df_log.ewm(halflife=12, min_periods=0, adjust=True).mean()
df_log_exp_decay = df_log - rolling_mean_exp_decay
df_log_exp_decay.dropna(inplace=True)get_stationarity(df_log_exp_decay)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

指数衰减比减去滚动平均值表现更差。然而,它仍然比原来更稳定。

让我们再尝试一种方法来确定是否存在更好的解决方案。当应用时移时,我们用前一个点减去每个点。

空、(x1 x0)、(x2 x1)、(x3 x2)、(x4 x3)、……、(xn xn 1)

df_log_shift = df_log - df_log.shift()
df_log_shift.dropna(inplace=True)get_stationarity(df_log_shift)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

时间偏移的效果不如减去滚动平均值。然而,它仍然比原来更稳定。

自回归模型

自回归模型在过去的值对当前值有影响的前提下运行。AR 模型通常用于分析自然、经济和其他时变过程。只要假设成立,我们就可以建立一个线性回归模型,根据前几天的值,尝试预测因变量今天的值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AR 模型的阶数对应于公式中包含的天数。

移动平均模型

假设当天因变量的值取决于前一天的误差项。该公式可以表示为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你还会遇到这样的等式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中μ是级数的平均值, θ 1、…、 θq 是模型的参数, εtεt—1、…、εt—q 是白噪声误差项。 q 的值称为 MA 模型的阶数。

自回归移动平均

ARMA 模型是 AR 和 MA 模型的简单组合。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

自回归综合移动平均模型(ARIMA)

ARIMA(又名 Box-Jenkins)模型增加了 ARMA 模型的差异。差分从以前的值中减去当前值,可用于将时间序列转换为静态时间序列。例如,一阶差分处理线性趋势,并采用转换zi = yi — yi-1。二阶差分处理二次趋势,并采用一阶差分的一阶差分,即zi = (yi — yi-1) — (yi-1 — yi-2),等等。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

三个整数(p,d,q)通常用于参数化 ARIMA 模型。

  • p:**自回归项数(AR 顺序)
  • **d:非季节性差异数(差异顺序)
  • **问:移动平均线数量(MA 顺序)

自相关函数

当前时间点的观测值与所有先前时间点的的观测值之间的相关性。我们可以使用 ACF 来确定 MA 项的最佳数量。术语的数量决定了模型的顺序。

部分自相关函数(PACF)

顾名思义,PACF 是 ACF 的一个子集。PACF 表示在两个时间点进行的观察之间的相关性,同时考虑来自其他数据点的任何影响。我们可以使用 PACF 来确定在 AR 模型中使用的最佳项数。术语的数量决定了模型的顺序。

让我们看一个例子。回想一下,PACF 可以用来计算 AR 模型的最佳阶数。水平蓝色虚线代表显著性阈值。垂直线代表在时间点的 ACF 和 PACF 值。只有超过水平线的垂直线被认为是显著的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,我们将在自回归方程中使用前两天。

回想一下,ACF 可以用来计算 MA 模型的最佳阶数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,我们在移动平均方程式中只使用昨天。

回到我们的例子,我们可以用 2 阶 AR、1 阶差分和 2 阶 MA 来创建和拟合 ARIMA 模型。

decomposition = seasonal_decompose(df_log) 
model = ARIMA(df_log, order=(2,1,2))
results = model.fit(disp=-1)
plt.plot(df_log_shift)
plt.plot(results.fittedvalues, color='red')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后,我们可以看到该模型如何与原始时间序列进行比较。

predictions_ARIMA_diff = pd.Series(results.fittedvalues, copy=True)
predictions_ARIMA_diff_cumsum = predictions_ARIMA_diff.cumsum()
predictions_ARIMA_log = pd.Series(df_log['Passengers'].iloc[0], index=df_log.index)
predictions_ARIMA_log = predictions_ARIMA_log.add(predictions_ARIMA_diff_cumsum, fill_value=0)
predictions_ARIMA = np.exp(predictions_ARIMA_log)
plt.plot(df)
plt.plot(predictions_ARIMA)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

假设我们有过去 12 年每个月的数据,并希望预测未来 10 年的乘客数量,我们使用(12 x12)+ (12 x 10) = 264。

results.plot_predict(1,264)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后的想法

在机器学习的领域中,有一套操作和解释依赖于时间的变量的技术。其中包括 ARIMA,它可以删除趋势成分,以准确预测未来值。

机器学习,第 2 部分:监督学习

原文:https://towardsdatascience.com/machine-learning-part-2-supervised-learning-632621f77188?source=collection_archive---------16-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image by the author

机器学习基础

  1. 基本概念
  2. 监督学习(你在这里)
  3. 无监督学习
  4. 强化学习

介绍

我们在第一部分讨论了基本的、通用的机器学习概念。现在我们转向机器学习问题,这里我们有一个带标签的数据集的好处——我们知道所有输入示例的期望输出值。有两个主要的监督问题:分类和回归。

监督分类法

监督分类可能是最常用的机器学习技术。顾名思义,它是“受监督的”:它利用已标记的训练集来建立逻辑,然后最终将该逻辑用于未标记的数据。

它解决的问题是分类。分类是将每个训练样本分配到不同的类别。一个类本质上是一个个体例子的特征(就像一个动物的种类),有一些特殊的条件。具体来说,类的数量是有限的,并且我们知道并且拥有我们期望分类的所有类的例子。如果我们有一个没有训练例子的班级,我们就不知道在分类的时候要找什么。每个例子只属于一个类。我们不能说一个例子属于不属于类,同样,我们也不能把它归为多于一类。

给定一个这样的问题,我们如何找到一个逻辑来将项目分类?我们通常寻找符合两个标准的预测值:1)同一类中的所有示例都具有与该类中的其他示例相似的属性值。2)同一类中的所有示例都具有与不同类中的示例不同的属性值。

监督分类算法对数据使用统计方法,并寻找其值与特定类别不同的特征(或特征组合)。独特的值实现了上述两个目标:它们将一个类的项目分组,并将其他类的项目分开。

例子

假设我们在一个园艺中心工作,在那里我们种植两种植物,百日菊和矮牵牛。该中心的所有者刚刚购买了一台机器,它可以测量三样东西:植物的heightcolor,以及土壤的ph水平。他们聘请我们编写一个程序,根据这些测量值自动区分这两种植物。

由于这是一个监督问题,我们得到了一个包含这三个预测值的数据集,所有的例子都标有species。不要深入任何特定算法的细节,让我们只考虑如果要求手动操作,我们将如何解决这个问题。

或许我们可以从一些统计数据开始。具体来说,我们将数据分为百日菊和矮牵牛,并查看每组的汇总统计数据。希望在这些汇总统计数据中,我们能找到以下值:1)同类花之间的相似值,2)牵牛花和百日菊之间的不同值,以及 3)足够不同的值,我们可以用它们来区分两者。

在此过程中,我们发现了一些值得注意的事情。首先,土壤ph似乎和species没有任何关系,最好忽略掉。这并不是说ph完全没用。如果我们试图回答一个不同的问题,如植物的健康,这样的数据点可能是有用的,但对于我们分离物种的问题来说,它是没有用的。

其他功能更好。就目前而言,百日菊几乎总是超过 12 英寸高,牵牛花几乎总是低于 12 英寸。也许最有用的是,牵牛花总是红色、紫色或白色,而百日菊总是红色、橙色或黄色。

有了这些信息,我们可以设计一个简单的分类器。如果一朵花是白色或紫色的,那它就是矮牵牛花。橙色或黄色的花是百日菊。对于红色的花来说,如果 T9 大于 12”,它可能是百日菊,如果它小于 12”,它可能是矮牵牛。我们不能完全有把握地区分红花,但这种方法在大多数情况下是正确的。使用这套简单的规则,我们只用最少量的信息就能得到非常准确的分类器。

每种机器学习分类算法的方法都不同,但其中一些算法执行的步骤几乎与我们刚刚做的完全相同。决策树算法寻找将数据分成比前一组更“纯净”的组的方法。即使不理解它背后的确切术语或数学,这也是我们已经做的:我们发现使用color允许我们生成几个完全纯的组。最后一组,红色的花,不能使用任何属性完全纯,但height得到最接近完美的分离。

从这个例子中需要记住的一件重要事情是,标签对我们的过程至关重要。如果没有标签,我们可能会意识到有高的和矮的花,甚至可以认识到黄色的花通常是高的。然而,如果没有标签,我们无法确切地说出那群高大的黄色花朵意味着什么。

监督回归

在监督回归中,就像在监督分类中一样,我们有一个可用于改进模型的标注数据集。分类和回归的不同之处在于输出的类型,或者说“响应”在回归分析中,答案是一个数字,这个区别比可能立即显现的差异更大。首先,让我们来谈谈如何识别回归问题,作为一个数字的回答是一个很大的线索,但是有可能有一个数字的回答是而不是回归问题。**

在回归中,响应是一个数字,可以像数字一样对待。我们可以用它来做数学运算,较大的值和较小的值相比意味着什么。此时你可能会问“什么样的数字不能像数字一样处理?”这种情况最常见的例子是当数字被用作 id 或类标签时。**

例如,以邮政编码 80123 和 60652 为例。80123 变大意味着什么吗?一点也不,它只是科罗拉多州一个地方的数字代码,而 60652 是伊利诺伊州。同样,如果我们减去这两个,我们将得到 19471。巧合的是,这是宾夕法尼亚州的一个邮政编码,但它没有任何实际意义。没有公式或说明来计算邮政编码。

除此之外,你看到的大多数数字都像数字一样。如果我们看两栋价格分别为 40 万美元和 20 万美元的房子:40 万美元越大,意味着房子越值钱,具体来说,我们可以用 40 万美元/20 万美元(即:用它们做数学计算)找到 2 倍多的房子。我们也可以通过取$400K-$200K = $200K来找出价格的差异。乘法$400K*$200K呢?这实际上并没有给我们一个有意义的输出,但没关系,不是每个操作者都必须给出有意义的输出。

所以回归反应首先是一个数字。我们稍后会谈到为什么这很重要。回归问题的第二个要求是响应是连续的 T2。在实际意义上,这意味着三件事:有无限多的响应,任何一组输入都应该导致有效的输出,类似地,任何有效的输出都有一组输入会导致有效的输出。连续输出使得这个问题与分类如此不同。

回想一下,在分类中,我们说过类是有限的,并且每个类都有一个例子。在回归中,可能的响应数量可以是无限个*,自然,我们不会有这些输出的例子。*

如何使用有限数量的训练样本来预测潜在的无限数量的输出?如果我们继续使用监督分类中的假设,这是不可能的,因为在分类中,我们需要总结单个输出的所有示例,以寻找共同因素。

那么,我们需要的是一套新的关于问题如何工作的假设,允许处理无限数量的可能输出。在回归中,核心假设是被解决的问题包含趋势并且预测器和响应具有函数关系。换句话说,趋势可以用一个数学函数来描述,利用这个函数,我们可以预测任何输入的任何输出值,而不仅仅是我们之前已经看到的组合。如果我们可以在训练数据的帮助下近似这个函数,那么我们已经使用了有限的数据来总结无限数量的输出。

例子

这很容易通过例子看出。考虑下面的数据,它描述了相对于房子大小的价格:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A simple regression dataset

一栋 2000 平方英尺的房子价格是多少?…

如果你说 200,000 美元,那么恭喜你,你已经为一个我们没有数据的输入值预测了一个我们从未见过的输出值。尽管这一壮举令人印象深刻,但它可能并不觉得很难。人类可能不像我们一样擅长识别趋势和关系,但对我们来说仍然相当直观,在这个例子中,趋势非常明显。

至于你是如何做出评估的,你可能是通过两种方式中的一种来完成的。第一,你意识到价格只是平方英尺乘以 100 美元,然后算了一下。第二,你注意到 2000 平方英尺介于 1500 和 2500 之间,于是你选择了介于这两个价格之间的价格,即 20 万美元。

这两种方法都可行,而且实际上都得到了相同的基本概念——我们的预测可以通过在由下式定义的直线上找到一个点来生成:

price = sqft * 100

此外,一旦我们有了这个等式,我们就可以为sqft的任意值生成一个预测。回归就是要找到这些方程,或者更具体地说,是要找到与预测值相关的一组系数。系数可以解释为将预测值增加 1 的效果。这里我们只有一个预测器,sqft,它的系数是100。因此,如果我们将sqft值增加 1,我们预计价格会上涨$100

让我们看一个更复杂的例子。这可以用纸和笔来解决,但显然比上一个要困难得多。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A more complex regression dataset

你可以试着自己解决这个问题。看看两栋房子之间只有一点不同的例子会特别有帮助。

系数的正确值为:

  • 每平方英尺 75 美元
  • 每间卧室 1 万美元
  • 每个浴室 5000 美元
  • 所有房屋的固定费用为 50,000 美元

您可能会认为这些系数的值本身就很有趣。你不会是第一个;这一观察导致了回归分析领域的出现,在该领域,关注的重点不是生成最准确的预测,而是找到最准确的系数。

你有没有看到过这样的广告或新闻:“获得这个学位可以为你的工资每年增加 10,000 美元!”?这个数字(希望)是通过回归分析计算出来的,用包括degree_earned在内的多个预测因子预测yearly_income,发现该学位的系数值大约为 10,000 美元。换句话说,如果两个人之间的唯一区别是一个人有学位,而另一个人没有,那么模型预测有学位的人会多挣大约 1 万美元。

回归分析本身是一个深入而广泛的领域。生成良好的系数估计需要很多东西,我们没有时间在这里讨论,但我想提到它,因为它是一种非常有用和广泛使用的方法,值得进一步研究。

到目前为止,明显缺少的是对计算机如何找到这些系数值的解释。原因是,答案远不如监督分类那么直接,并且涉及大量的高等数学,我不想在介绍性的帖子中深入讨论。

然而,简单的版本是我们定义一个叫做成本函数的函数,它告诉我们我们的预测有多远。在成本函数中,值越低越好,因此目标是找到成本函数的最低可能值。在有噪声的数据集中,该值将而不是为零,因为不是所有的点都可以完美拟合。

在此之后,主要有两种方法。使用线性代数可以(当数据集不太大时)直接使用正规方程找到最小化成本函数的系数值。不然可以用渐变下降更直观一点。

本质上,梯度下降是利用微积分寻找成本更低的方向。换句话说,我们是否需要提高或降低一个给定的系数来制作一个更好的模型?通过找到这些“梯度”,并在每一步将系数在这些方向上移动一小段,我们逐渐将模型移动得越来越接近最佳系数。经过(通常)数千次迭代,我们的模型“收敛”在最优值上。

更简单地说,梯度下降的诀窍是,虽然我们不知道最佳系数,但我们知道如何建立一个比我们当前模型略好的模型。通过一遍又一遍地重复这个小的改进,我们最终得到了一个我们无法改进的模型,我们知道我们已经达到了最佳状态。**

结论

监督分类和回归涵盖了大量的机器学习问题。监督分类本身可能是最常见的最大似然问题,如果监督回归排在第二位,我也不会感到惊讶。特别是分类,有一系列令人眼花缭乱的算法可以用来实现这一点,虽然我们没有在这里涵盖其中的绝大多数,但它们都遵循相同的基本逻辑,即在数据和标签中寻找模式之间的联系。接下来我们讨论无监督学习,我们仍然在寻找模式,但我们不再有标签来帮助指导我们对这些模式的解释。

Keras 中的神经网络脱层解释

原文:https://towardsdatascience.com/machine-learning-part-20-dropout-keras-layers-explained-8c9f6dc4c9ab?source=collection_archive---------3-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://www.pexels.com/photo/colleagues-looking-at-survey-sheet-3183153/

机器学习最终用于在给定一组特征的情况下预测结果。因此,我们可以做的任何概括模型性能的事情都被视为净收益。放弃是一种用于防止模型过度拟合的技术。Dropout 的工作原理是在训练阶段的每次更新时,将隐藏单元(组成隐藏层的神经元)的输出边缘随机设置为 0。如果你看一下 Keras 关于辍学层的文档,你会看到一个由 Geoffrey Hinton 和 friends 撰写的白皮书的链接,该白皮书探讨了辍学背后的理论。

密码

在前面的例子中,我们将使用 Keras 构建一个神经网络,目标是识别手写数字。

from keras.datasets import mnist
from matplotlib import pyplot as plt
plt.style.use('dark_background')
from keras.models import Sequential
from keras.layers import Dense, Flatten, Activation, Dropout
from keras.utils import normalize, to_categorical

我们使用 Keras 将数据导入我们的程序。数据已经分为训练集和测试集。

(X_train, y_train), (X_test, y_test) = mnist.load_data()

让我们看看我们在做什么。

plt.imshow(x_train[0], cmap = plt.cm.binary)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在我们完成模型的训练后,它应该能够识别前面的图像为 5。

我们必须事先进行一点预处理。我们将像素(特征)归一化,使它们的范围从 0 到 1。这将使模型更快地收敛到一个解。接下来,我们将给定样本的每个目标标签转换为 1 和 0 的数组,其中数字 1 的索引表示图像代表的数字。我们这样做是因为,否则我们的模型会将数字 9 解释为比数字 3 具有更高的优先级。

X_train = normalize(X_train, axis=1)
X_test = normalize(X_test, axis=1)
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

没有辍学

在将二维矩阵输入神经网络之前,我们使用一个展平层,通过将每个后续行附加到其前面的行,将其转换为一维数组。我们将使用两个由 128 个神经元组成的隐藏层和一个由 10 个神经元组成的输出层,每个神经元代表 10 个可能的数字中的一个。softmax 激活函数将返回样本代表给定数字的概率。

model = Sequential()
model.add(Flatten(input_shape=(28, 28)))
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dense(10))
model.add(Activation('softmax'))model.summary()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因为我们试图预测类别,所以我们使用分类交叉熵作为损失函数。我们将使用准确性来衡量模型的性能。

model.compile(
    loss='categorical_crossentropy',
    optimizer='adam',
    metrics=['accuracy']
)

我们留出 10%的数据进行验证。我们将用它来比较一个模型在有和没有辍学的情况下过度适应的趋势。批量大小为 32 意味着在通过神经网络传递 32 个样本后,我们将计算梯度并在梯度方向上迈出一步,其幅度等于学习速率。我们总共这样做 10 次,具体次数由历元数决定。

history = model.fit(
    X_train,
    y_train,
    epochs=10,
    batch_size=32,
    validation_split=0.1,
    verbose = 1,
    shuffle=True
)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以通过使用由 fit 函数返回的历史变量来绘制每个时期的训练和验证精度。

loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(loss) + 1)
plt.plot(epochs, loss, 'y', label='Training loss')
plt.plot(epochs, val_loss, 'r', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

正如你所看到的,在没有丢失的情况下,验证损耗在第三个时期后停止下降。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

acc = history.history['acc']
val_acc = history.history['val_acc']
plt.plot(epochs, acc, 'y', label='Training acc')
plt.plot(epochs, val_acc, 'r', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

如您所见,在没有丢失的情况下,验证精度往往在第三个历元左右趋于平稳。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用这个简单的模型,我们仍然能够获得超过 97%的准确率。

test_loss, test_acc = model.evaluate(X_test, y_test)
test_acc

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

拒绝传统社会的人

关于 dropout 应该放在 activation 函数之前还是之后还有一些争论。根据经验,对于除之外的所有激活功能,将 dropout 放在 activate 功能之后。在传递 0.5 时,每个隐藏单元(神经元)以 0.5 的概率被设置为 0。换句话说,有 50%的变化,给定神经元的输出将被强制为 0。

*model_dropout = Sequential()
model_dropout.add(Flatten(input_shape=(28, 28)))
model_dropout.add(Dense(128))
model_dropout.add(Dropout(0.5))
model_dropout.add(Activation('relu'))
model_dropout.add(Dense(128))
model_dropout.add(Dropout(0.5))
model_dropout.add(Activation('relu'))
model_dropout.add(Dense(10))
model_dropout.add(Activation('softmax'))model_dropout.summary()*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

同样,由于我们试图预测类别,我们使用分类交叉熵作为损失函数。

*model_dropout.compile(
    loss='categorical_crossentropy',
    optimizer='adam',
    metrics=['accuracy']
)*

通过提供验证分割参数,模型将分离训练数据的一部分,并将在每个时期结束时评估该数据的损失和任何模型度量。如果 dropout 背后的前提成立,那么我们应该会看到与以前的模型相比,验证准确性有显著的不同。洗牌参数将在每个时期之前洗牌训练数据。

*history_dropout = model_dropout.fit(
    X_train,
    y_train,
    epochs=10,
    batch_size=32,
    validation_split=0.1,
    verbose = 1,
    shuffle=True
)*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如您所见,验证损失明显低于使用常规模型获得的损失。

*loss = history_dropout.history['loss']
val_loss = history_dropout.history['val_loss']
epochs = range(1, len(loss) + 1)
plt.plot(epochs, loss, 'y', label='Training loss')
plt.plot(epochs, val_loss, 'r', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如您所看到的,该模型收敛得更快,并在验证集上获得了接近 98%的准确性,而之前的模型在第三个时期左右达到稳定。

*acc = history_dropout.history['acc']
val_acc = history_dropout.history['val_acc']
plt.plot(epochs, acc, 'y', label='Training acc')
plt.plot(epochs, val_acc, 'r', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在测试集上获得的准确性与从没有丢失的模型中获得的准确性没有太大的不同。这很可能是由于样本数量有限。

*test_loss, test_acc = model_dropout.evaluate(X_test, y_test)
test_acc*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后的想法

Dropout 可以通过将给定神经元的输出随机设置为 0 来帮助模型泛化。在将输出设置为 0 时,成本函数对改变反向传播过程中权重更新方式的相邻神经元变得更加敏感。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值