为您的应用选择最佳的 Python Web 抓取库
前 5 个库的概述以及何时使用它们。
生活在当今世界,我们被周围不同的数据所包围。在我们的项目中收集和使用这些数据的能力是每个数据科学家必备的技能。
关于如何使用特定的 Python 库来获取在线数据,网上有很多教程。然而,您很少能找到为您的特定应用程序选择最佳库的教程。
Python 提供了各种可以用来抓取 web 的库,如 Scrapy、Beautiful Soup、Requests、Urllib 和 Selenium。考虑到 Python 有多受欢迎,我很确定会有更多的库存在,并且很快会有更多的库发布。
在这篇文章中,我将涵盖我刚刚提到的 5 个库,将对它们中的每一个进行概述,例如,代码以及它们中的每一个的最佳应用和案例。
对于本文的其余部分,我将使用包含书籍的这个沙盒网站来解释每个库的具体方面。
1.Scrapy
Scrapy 是目前最流行的 Python web 废弃库之一。它是一个开源框架。这意味着它甚至不是一个图书馆;它是一个相当完整的工具,你可以用它系统地在网络上抓取和爬行。
Scrapy 最初被设计用来构建可以自己爬网的网络蜘蛛。它可以用于监控和挖掘数据,以及自动化和系统化的测试。
与其他抓取网页的 Python 方法相比,它的 CPU 和内存效率也很高。使用 Scrapy 的缺点是,安装它并在你的设备上正常工作可能有点麻烦。
概述和安装
要开始使用 Scrapy,您需要确保您运行的是 Python 3 或更高版本。要安装 Scrapy,你可以简单地在终端中写下下面的命令。
pip install scrapy
Scrapy 成功安装后,您可以通过键入以下命令来运行 Scrapy shell:
scrapy shell
当您运行此命令时,您会看到类似这样的内容:
作者截图
您可以使用 Scrapy shell 运行简单的命令,例如,您可以使用fetch
函数获取网站的 HTML 内容。所以,假设我想获取这个图书网站;我可以在 shell 中简单地实现它。
fetch("[http://books.toscrape.com/](http://books.toscrape.com/)")
现在,您可以使用view
函数在默认浏览器中打开这个 HTML 文件。或者你可以直接打印出页面的 HTML 源代码。
view(response)
print(response.text)
当然,你不会仅仅为了在浏览器中打开一个网站而吓到它。您可能希望从 HTML 文本中获得一些特定的信息。这是使用 CSS 选择器完成的。
在开始之前,您需要检查要获取的网页的结构,以便使用正确的 CSS 选择器。
何时使用 Scarpy?
使用 Scrapy 的最佳情况是当你想做大规模的网络抓取或者自动化多个测试的时候。Scrapy 的结构非常好,它允许更好的灵活性和对特定应用程序的适应性。此外,Scrapy 项目的组织方式使得维护和扩展更加容易。
我建议你避免使用 Scrapy,如果你有一个小项目,或者你想抓取一个或几个网页。在这种情况下,Scarpy 会使事情变得过于复杂,而不会带来额外的好处。
2.要求
Requests 是你可以使用的最简单的 HTTP 库。 Requests 允许用户向 HTTP 服务器发送请求,并以 HTML 或 JSON 响应的形式获得响应。它还允许用户向服务器发送 POST 请求来修改或添加一些内容。
请求展示了使用设计良好的高级抽象 API 所能获得的真正力量。
概述和安装
请求通常包含在 Python 的内置库中。但是,如果由于某种原因您不能立即导入它,您可以使用 pip 轻松安装它。
pip install requests
您可以使用请求来获取和清理组织良好的 API 响应。例如,假设我想在 OMDB 的数据库中查找一部电影。请求允许我向 API 发送一个电影名称,清理响应,并在不到 10 行的代码中打印出来——如果我们省略注释的话😄。
何时使用请求?
Requests 是您开始网络抓取时的理想选择,并且您有一个 API tp 联系人。它很简单,不需要太多的练习就能掌握使用。请求也不需要你手动添加查询字符串到你的 URL。最后,它有一个写得非常好的文档,并支持整个 restful API 及其所有方法(PUT、GET、DELETE 和 POST)。
如果您尝试或期望的网页包含 JavaScrip 内容,请避免使用请求。则响应可能无法解析正确的信息。
3.Urllib
Urllib 是一个 Python 库,允许开发者打开并解析来自 HTTP 或 FTP 协议的信息。Urllib 提供了一些处理和打开 URL 的功能,即:
- urllib.request: 打开并读取 URL。
- urllib.error: 捕获 urllib.request 引发的异常。
- urllib.parse: 解析 URL。
- urllib.robotparser: 解析 robots.txt 文件。
概述和安装
好消息是,您不需要安装 Urllib,因为它是内置 Python 库的一部分。然而,在一些罕见的情况下,您可能在 Python 包中找不到 Urllib。如果是这种情况,只需使用 pip 安装即可。
pip install urllib
可以使用 Urllib 来探索和解析网站;然而,它不会给你提供太多的功能。
何时使用 Urllib?
Urllib 比请求稍微复杂一点;然而,如果你想更好地控制你的请求,那么 Urllib 是一个不错的选择。
4.美味的汤
美汤是一个 Python 库,用来从 XML 和 HTML 文件中提取信息。美汤被认为是一个解析器库。解析器帮助程序员从 HTML 文件中获取数据。如果解析器不存在,我们可能会使用正则表达式从文本中匹配和获取模式,这不是一种有效或可维护的方法。
幸运的是,我们不需要这样做,因为我们有解析器!
Beautiful Soup 的优势之一是它能够检测页面编码,从而从 HTML 文本中获得更准确的信息。美丽的汤的另一个优点是它的简单和容易。
概述和安装
安装美丽的汤是非常简单和直接的。您所要做的就是在终端中键入以下内容。
pip install beautifulsoup4
就是这样!你可以开始刮了。
现在,Beautiful Soup 是我们刚刚提到的一个解析器,这意味着我们需要首先获取 HTML,然后使用 Beautiful Soup 从其中提取我们需要的信息。我们可以使用 Urllib 或 Requests 从网页中获取 HTML 文本,然后使用 Beautiful Soup 来清理它。
回到之前的网页,我们可以使用请求获取网页的 HTML 源代码,然后使用 Beautiful Soup 获取页面中< a >内的所有链接。我们只需要几行代码就可以做到。
什么时候用美人汤?
如果你刚开始学习 webs scarping 或 Python,Beautiful Soup 是最好的选择。此外,如果您将要抓取的文档不是结构化的,那么 Beautiful Soup 将是您的最佳选择。
如果你正在建立一个大项目,美丽的汤将不会是明智的选择。漂亮的汤项目不灵活,随着项目规模的增大,很难维护。
5.硒
Selenium 是一个开源的基于网络的工具。Selenium 是一个网络驱动程序,这意味着你可以用它打开网页,点击一个按钮,然后得到结果。它是一个主要用 Java 编写的自动化测试的强大工具。
尽管 Selenium 很强大,但它是一个初学者友好的工具,不需要很高的学习曲线。它还允许代码模仿人类行为,这在自动化测试中是必须的。
概述和安装
要安装 Selenium,只需在终端中使用 pip 命令。
pip install selenium
如果您想获得 Selenium 的全部功能——您很可能会这样做——您需要安装一个 Selenium WebDriver,以真实用户的身份在本地或远程设备上驱动浏览器。
您可以使用 Selenium 自动登录 Twitter——或者脸书或任何网站,真的。
什么时候用硒?
如果您是 web 抓取游戏的新手,但是您需要一个可扩展且灵活的强大工具,Selenium 是最佳选择。此外,如果您想浏览几页,这是一个很好的选择,但是您需要的信息在 JavaScript 中。
为您的项目使用正确的库可以节省您大量的时间和精力,这对项目的成功至关重要。
作为一名数据科学家,您可能会遇到所有这些库,在您的旅程中可能会遇到更多,在我看来,这是了解每个库的优缺点的唯一方法。这样做,你将会发展出一种第六感来引导你在未来的项目中选择和使用最好的库。
选择数据库技术
路线图和流程概述
奥利弗·鲁斯在 Unsplash 上拍摄的照片
选择数据库是数据架构师最近享受的一种奢侈。在过去,最常见的是,这是一个先前做出的决定,是一个需要接受的决定。责任、存储过程代码和太脆弱的数据管道带来了巨大的负担,每个人都不敢重新设计它们,因为害怕会损坏。数据库通常在应用程序之间共享,或者在许多情况下,功能是单个应用程序的模块。
现在,在多应用程序和多数据库的世界中,在一些作者称之为多语言持久性的世界中,情况有所不同。
大多数云提供商都有自己的技术,他们试图根据用例将用户引导到正确的数据库。
下面是我关于如何在数据库世界中做出技术选择的路线图。在某些情况下,您还可以扩展该方法来涵盖一般的技术选择。
这样的选择究竟是如何做出的?
根据我的经验,现实生活中做出这种决定的大致比例如下:
如何选择一个数据库?
- 技术原因:30%
- 用例适合度:30%
- 成本/总拥有成本/更换成本或实施成本:10%
- 利益相关者驱动(或者叫做“谁和谁打高尔夫?”): 30%.决策是由利益相关者的网络效应、与供应商的关系驱动的因素、销售人员、上级组织联系、共同投资者、交换交易和其他商业活动决定的。
选择和入围的过程
选择过程,从一个长名单开始,缩小到一个短名单
从候选人名单开始——一个“长名单”
- 作为一名顾问,您将从自己的经验、团队成员的经验、客户 IT 团队推荐的名字以及对 Gartner、Forrester、Bloor Research 和其他公司报告的研究中收集一份清单。
- 分析产品文献、特性和局限性
- 看看“民间讨论”发生的来源——论坛、stackoverflow、slashdot、reddit(!),github 问题,bug 报告
- 寻找独立的测试和排名( Jepsen 、 db-engines 和类似的来源)
定义一个合格标准。不符合资格标准将会取消选择。
作为数据库选择基础的能力和特征
技术能力、特性和非功能性需求
- NFRs 或“完整性”要求,如可扩展性、容量、可恢复性、耐用性。
- 上面给出了一些选择参数,以及与该参数相关的一些候选参数
- 数据大小— MBs、GBs、TBs、PBs — SQLite、MySQL、PostgreSQL、Oracle、Teradata、AWS 红移
- 大量并发用户—使用缓存、Redis、DynamoDB
- 快速响应时间要求— ElasticSearch,MemSQL
- 计算量大(矩阵计算、Python/R 集成)— SQL Server 与 R、存储过程
- 文档数据(JSON)、地理数据(GIS)、时间数据、多媒体数据—适合数据存储格式的数据库— MongoDB、PostGIS、TICK stack
- 点查询或批量数据查询— Redis、键值存储、雪花、Google Cloud SQL
- 平衡的读写,主要是读,主要是写,事务和分析处理— OLTP(在线事务处理),OLAP(在线分析处理),HTAP(混合事务和分析处理)
- 大量数据的快速接收、涓滴流、计划作业、数据湖(Cassandra、Kafka、Spark、Presto)
- 微服务 v/s 整体架构、ACID 要求、最终一致性要求
用例及适用性
- 现有的编程语言投资(Java,。NET)、市场上托管服务的可用性或技能可用性,以了解和管理技术的复杂性、云可用性、法律或地理或合同限制
- 在数据存储和处理以及数据库(如 Oracle 数据库云服务器或 Teradata)方面的现有投资
- 由云提供商提供的数据库,确保与云生态系统的良好集成,统一或相似的 API,以及相同的 DevOps 工具。
- 成本/总体拥有成本或实施/迁移成本
候选名单
从候选名单中剔除不符合资格标准的候选人后剩下的名单。
产生了最终的竞争者
接下来,一个非常详细的需求列表(包括技术、成本、用例以及适用性)和评分标准被制定出来。通常这是在以下格式的电子表格中完成的。
评分和加权要求
它总是有助于记录为什么分配一个特定的分数,或者为什么分配或调整一个权重。我可以向您保证,这样一个带注释的文档将在组织中被多次引用,因为注释和指定的分数一样有价值。
与客户的最终讨论总是在电子表格的基础上进行,客户及其技术、业务和 IT 团队可以对权重进行权衡和调整。
在这个过程的最后,通常会有 1-2 名候选人脱颖而出。
根据我的经验,在入围过程中,或者在前 2-3 名的选择之后,需要一个结构化的 PoC,以确保文档中的声明是真实的,并且可以解决提到的限制。
混合数据库架构的案例
每个数据库都有一些核心特性,以及一些为了“打勾”而添加的特性。这里的危险是,随着时间的推移,这些“其他”功能会被放弃,因为它们没有得到应有的关注。
数据库也不能孤立地考虑,而是要放在为请求服务的能力、应用程序架构和整个数据流的业务用例的整体环境中考虑。
出于上述原因,为了获得最佳性能,有时使用专门的数据处理组件比使用一个数据库来处理所有请求更有意义。
在这里,您可以看到 SAS Grid 等技术、SciDB 等专用数据处理平台或 Intersystems Cache shine。
在某些方面,Hadoop 堆栈(文件存储、Hive 元数据存储、HBase、Impala)或各种 Spark 组件(GraphX、Spark SQL、Spark streaming、Mlib)也是一种混合 DB 架构。
共享数据库的使用和集成需求
通用数据库仍然满足大多数需求。然而,正在发生变化的是数据库使用的共享模式。
以前,销售和营销、交易、财务和会计以及服务应用程序都将数据存储在同一个数据存储中(可能是相同的模式,也可能是不同的模式)。考虑到数据量小、许可成本高、DBA 预算有限,这是有意义的。它确实提供了单一存储位置、更少的模式差异和更低的复杂性的优势。
现在,每个应用程序都有单独的数据存储和数据库。数据鸿沟增加了。随着这种分离,集成需求增加了。公共数据和主数据的维护也有所增加。分析层现在使用来自所有这些不同数据源的数据。API 提供了应用程序之间的集成。企业应用程序集成(EAI)和提取-转换-加载或提取-加载-转换(ETL/ELT)的双重性,以及两者的重叠角色增加了,两者混合使用,导致了更大的复杂性,有时会导致更多的成本和开销。
结论
作为数据架构师,做出正确的技术选择非常重要。平衡适用性需求、降低运营和集成的复杂性和成本的需求,以及防止堆栈失控和激增的需求。使用正确的数据库和数据存储的案例应该只针对正确的应用程序和用例。
参考
m .福勒(2011 年 11 月 16 日)。bliki:多语种持久性。从https://martinfowler.com/bliki/PolyglotPersistence.html取回
在您喜欢的工具和实际完成工作的工具之间进行选择。
作为一名数据科学家、人工智能或机器学习工程师,你应该知道何时在使用你情有独钟的工具和实际上更容易更快完成工作的工具之间划清界限。
布雷特·乔丹在 Unsplash 上的照片
最终这是你做出的选择,做出这个选择有多难并不重要。重要的是你做了。
――卡桑德拉·克莱尔
作为不断编写代码的人,我们对某些工具和技术情有独钟,我们倾向于一直使用它们,即使它们在某些情况下不是最好或最可取的工具。然后,我们有责任知道何时在使用正确和适当的工具、技术或方法与使用我们喜欢的工具之间划清界限。
什么时候知道用什么
对于你作为数据科学家、人工智能或 ML 工程师承担的任何项目,一定要知道问题需要你构建什么样的解决方案。如果您对问题陈述理解得足够好,您会发现构建和实现您的解决方案相对更容易。在构建你的数据科学、AI 或 ML 解决方案时,一定要一步一步来。如果您的目标是构建能够经受时间考验的解决方案,那么使用系统的或逐步的方法来构建解决方案是非常必要的。确保遵循数据科学或 ML 项目的道德和普遍接受的工作流程。在工作流程的每个阶段,对解决手头问题的可能方法进行研究或案例分析,并查找可供您使用的工具和技术。完成这些事情后,权衡使用每种可用工具或技术的利弊,并根据自己的判断,选择有助于您更轻松、更快速地实现目标的工具或技术。如果有许多可用的选项可供选择,那么可以归结为选择一个拥有良好社区和围绕它构建的内容的人来帮助和指导您使用该工具或技术,以便您可以有效地利用该工具或技术。
选择是丰富的,难得的是正确的决定!
――穆罕默德·穆拉特·伊尔丹
为什么你不应该保留收藏夹
作为一名数据科学家、人工智能或人工智能工程师,你必须保持开放的心态,以便能够高效地工作。在工具和技术方面保持偏好只会限制你,让你意识不到可供选择的大量选项会帮助你更容易、更快、更有效地完成工作。如果你一直想在这个领域保持相关性,教会自己学习、忘却和再学习可能是你能教会自己的最重要的事情。你必须抛弃过去对你有用的工具、技术或方法,选择更新更有效的。在数据科学家、人工智能或人工智能工程师的生活中,时间是一个非常重要的因素,因此,在从事任何项目时,你应该始终坚持使用节省时间的工具、技术或方法。
乔恩·泰森在 Unsplash 上的照片
在正确的时间做出正确的决定,会让你的生活像鲜花一样绽放;否则,它将被视为荆棘。第一个你会享受,另一个你要承受。
――埃桑·塞加尔
我希望我已经能够告诉你为什么选择那些对你来说确实有效的选项来使你的工作更容易和更快是明智的,而不是选择那些你在多年的工作中已经形成的软肋。你有什么想法?在这个故事的回应部分分享你的观点和看法。
感谢您抽出时间阅读这个故事。我希望你学到了新的东西,这对你有所帮助。可以直接在 Twitter 或者 LinkedIn 联系我。最美好的祝愿!
非常感谢 安娜·阿依库 为我校对并纠正了我写这篇文章时犯的许多错误。
用动态规划快速选择
用真实世界的例子和 Python 代码简单解释背包问题。
马丁·范·登·霍维尔在 Unsplash 上的照片
终于到了,你要搬到三藩市成为一名著名的数据科学家了!你将在一家大公司工作,很快就会出名!但是,首先。你将住在一个小公寓里,比你现在在山谷里的房子要小得多。所以你必须决定带走哪些东西。因为你是一个数据科学家,你会以一种聪明而有效的方式来决定这件事。让我们找到最优解!
问题描述
目前你的房子是 100 平方米。你的东西所占的面积是 50 平方米。你的新公寓有 40 平方米,你希望你的东西最多占 20 平方米,因为你喜欢在地板上有一些自由空间。你以一种方式列出你的物品,你给它们分配它们占据的区域和它们给你的生活增加的价值。你的目标是最大化这 20 平方米的价值。
项目
你开始列出你的物品。你可以指定面积(以平方分米为单位)以及物品给你的生活带来的价值(从 0 到 100)。您最终得到了下面这本包含 29 个条目的字典:
好吧!例如,床占 4 平方米(= 400 平方分米),它给你的生活增加的价值是 100,游戏桌占 1.5 平方米,增加的价值是 30。
价值最大化
你如何最大限度地利用这本词典?您可以尝试所有可能的组合,并计算每个组合的总值。通过为 20 平方米的最大面积选择最大值,您将获得最佳解决方案。一个问题,这 29 个项目给了 2 个⁹选择项目的可能组合!超过 5.36 亿了!那需要一些时间!
你想想其他的选择。如果你从给你的生活增加最大价值的物品开始,然后是第二高价值的物品,以此类推,直到 20 平方米都满了,会怎么样?这又简单又快捷!但是它会给出最优解吗?你怀疑。如何快速解决问题,获得最佳解?
动态规划
幸运的是,一个朋友告诉你一个更聪明的处理问题的方法。他解释说,你可以用递归的方式把问题分成更小更简单的子问题。如果您将结果存储在记忆表中,您可以快速找到最佳解决方案,因为您可以重复使用这些结果。这样你就用记忆空间换取了时间。所以你从这个方法开始,叫做动态编程。事实上,一个小时后你就解决了这个问题,并且知道了你要把哪些东西带到新家去。
动态编程步骤
你需要完成四个步骤来获得你的 SF 公寓的最佳库存清单:
第一步。用条目及其包含的区域/值创建一个字典。
这是前面提到的带有条目的 stuffdict(见第一个代码块)。
第二步。从字典中创建面积和值列表。
你使用 stuffdict 创建两个带有面积和值的列表。
第三步。使用这些列表建立记忆表。
有了面积列表、数值列表、最大面积和项目数,就可以建立记忆表。
第四步。获取包含在记忆表最后一行中的项目。 记忆表的最后一行包含最优解。有可能存在多个最优解。例如,当您有两个具有相同面积和价值的项目时,或者当一些项目加起来与另一个项目的面积和价值相同时。
让我们更深入地研究这些步骤,并检查代码。
第一步。用条目及其包含的区域/值创建一个字典。 这是包含项目、区域和值的字典:
第二步。从字典中创建面积和值列表。
使用 stuffdict 创建两个包含面积和值的列表。为此,您可以使用下面的函数。输入是步骤 1 中的 stuffdict,它返回两个列表:一个包含区域,另一个包含值。
第三步。使用这些列表建立记忆表。 现在你将创建记忆表来寻找最优解。您需要步骤二中的面积和值列表,总面积 A 和项目总数 n 。表格有 n+1 行和 A+1 列。从第一行开始,零个条目,然后计算每个单元格的值。您将以自下而上的方式逐行执行此操作。数值表 V 看起来是这样的:
用代码创建表:
在第二和第三行,表被创建。创建完成后,您将填充表格的每个单元格。第六和第七行显示了基本情况:当面积或项目数为零时,值为零。第八行和第九行的意思是,当当前项的面积小于或等于单元格的面积时,根据以下公式计算单元格的值:
选择当前项目的值加上前一行的值和当前区域减去当前项目的区域之间的最大值(1),以及前一行的值加上当前单元格的区域(2)。第 10 行和第 11 行的意思是:如果单元格的面积小于当前项目的面积,则您将单元格的值设置为等于具有相同面积的前一行的值。
第四步。获取包含在记忆表最后一行中的项目。
你可以使用以下代码找到你的完美家具组合:
此代码返回:
['bike_stand', 'garbage_can', 'standing_lamp', 'chest_of_drawers', 'plant_3', 'plant_2', 'diner_table_with_chairs', 'bookshelf', 'armchair', 'table', 'desk', 'bed', 'couch_s']
现在你知道你需要带什么了吧!我们搬到旧金山去吧!
注意:注意,这段代码也返回重复项(面积和值对相同的项)!在这个例子中,情况并非如此。
结论
希望这篇文章能帮助你快速有效地找到最佳解决方案。您可以将面积值对替换为想要优化的其他参数,如权重和值或时间和改进。重要的一点是,通过存储更小的子问题的解,你可以更快地找到最优解,这种技术被称为动态规划。
额外收获:记忆表的热图
下面的热图很好地展示了记忆表。在 x 轴上,您可以看到可用的面积(2000 平方分米)。y 轴显示项目列表。您从一个空列表开始,然后开始添加项目。这些颜色代表某个区域内可用项目的总价值。你可以看到当你继续前进时,这个值会变得越来越高。
使用记忆表和 stuffdict 构建该热图的代码:
别忘了 订阅 如果你想在我发表新文章时收到电子邮件。
选择绩效指标
准确性、敏感性与特异性、精确性与回忆性以及 F1 分数
分类 _ 报告来自 scikit-learn。
准确度、召回率、精确度、F1 分数–如何选择衡量模型性能的指标?一旦你选择了,你想要宏观平均值吗?加权平均?对于这些指标中的每一个,我将更仔细地研究它是什么以及它的最佳用例是什么。我还将介绍如何从 scikit-learn 的[classification_report](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.classification_report.html)
中读取输出表,如上图所示。
准确(性)
我从准确性开始,因为我认为,从它的名字来看,我们觉得我们对它有一个直观的理解,而没有见过任何数学公式。“我们想要一个更准确的模型。”一直都是,我们甚至还没有严格意义上的定义。我确实从项目的准确性开始(现在仍然如此),因为它感觉熟悉而不专业。
从理论上讲,准确性就是预测正确的百分比,用 0 (0%的预测正确)到 1 (100%的预测正确)之间的小数表示。
作者图片
因为预测 TP(真阳性)、FP(假阳性)、TN(真阴性)和 FN(假阴性)对后面的指标很重要,所以让我们继续讨论它们与准确性的关系。
对于二元分类问题。作者图片
举一个例子,如果我们试图将图像分为两类,狗和非狗,我们的模型将只预测 1)图像是狗,在这种情况下它可能是正确的,并且图像确实是狗(TP),或者不正确的,并且图像不是狗,尽管模型认为它是(FP);或者 2)模型可以预测图像不是狗,在这种情况下,它可以再次是正确的,并且图像确实不是狗(TN),或者是不正确的,并且图像实际上是狗,尽管模型认为它不是(FN)。
从上面看,我们可以看出,无论我们使用哪种准确性定义,我们只是将模型正确的预测数除以其预测总数。
对于你遇到的大多数普通的、不复杂的数据集来说,准确性确实是一种“金发姑娘”。只要类别或多或少是平衡的(在前面的例子中,狗和非狗图像的数量相等),准确性在融合特异性和敏感性、召回率和精确度方面做得很好。特异性和灵敏度在这个例子中本身就是相当具体的词语,回忆和精度也是如此,接下来我们要谈到它们。
敏感性(回忆)和特异性
就像准确性一样,我认为我们已经对特异性和敏感性有了相当直观的理解,或者至少感觉我们有,但现实是它们在统计学领域有一些相当具体的定义。
TPR 代表真阳性率,FNR 代表假阴性率。作者图片
敏感度,剧透一下,和回忆是同一个东西,也被称为真阳性率(TPR) ,用通俗英语来说,就是所有被放入正确箱子的真阳性的分数;在前面的例子中,在实际上是的狗的图像中,模型得到了其中的多少部分,并且称之为狗?这个模型在捕捉“是”方面有多好?敏感度/回忆/TPR 就是这么回答的。
你会注意到一些有趣的事情:我们没有包括任何关于非狗的图片。事实上,如果你认真思考上面等式,你会意识到那些非狗或没有图像,以及模型预测或分类它们的成功或失败(TN 和 FP),根本不会影响灵敏度/回忆。事实上,再举一个早先的例子,一个对每一张图像都预测“是的,狗”的模型将具有完美的灵敏度/回忆/TPR。
这给了 sensitivity/recall/TPR 一个非常具体的用例,它可以归结为:当你所寻找的每一个实例都太珍贵而不能错过时,就使用它。例子包括检测恐怖袭击、检测疾病、检测欺诈等。在每一种情况下,一个以敏感度为中心的模型将捕捉所有真正的恐怖袭击,所有真正的心脏病病例,以及所有真正的欺诈性信用卡购买*,同时警告*它也将提取一些假阳性的实例:将有一些无辜的旅行者,一些健康的人,一些正常的目标购买被检测到。
特异性,也称为真阴性率(TNR),是敏感性的另一面。它关心敏感做的每一件事,但不关心“不”的情况(真的不是狗)。
TNR 为真阴性率,FPR 为假阳性率。作者图片
一个对每一张图像都称之为“不是狗”的模型将具有完美的特异性(因此,灵敏度为 0)。这与敏感性/回忆相反,通常两者之间的选择归结为你关注的是或否。在理想的世界中,你会得到一个在两方面都出色的模型,但有时我们被迫做出选择,特别是在医疗保健领域,特异性和敏感性之间的区别源于。
召回率和精确度
回想一下我们已经讨论过——它是敏感性——和精确性,第三方面——万圣节快乐,各位——是这样的:在所有被模型认为是(狗)的东西中,有多少是正确的(真的是狗)?
作者图片
像灵敏度和特异性一样,在计算精度时,有一个模型性能的元素被忽略,但这一次是模型判断为“否”的所有东西被忽略。如果有 1000 张照片,500 张狗的照片,500 张非狗的照片,而模型只正确地分类了 5 只狗,并将其他所有照片都称为非狗,那将是完美的,精度为 1.0(即使分类器错过了 495 张狗的照片)。
那么,Precision 也有一个非常具体的用例。当你想对模型给你的“是”有信心时,就把注意力集中在它上面。当然,它会错过一些是,但它会做什么,如果模型有很好的精度,你可以放心。
F1 分数
简答, F1 评分是召回率和准确率的调和平均值,取 0 到 1 之间的值。
作者图片
当您用它们的 TP/FP/TN/FN 定义替换 recall 和 precision 时,F1 分数的定义如下:
作者图片
也许,你和我一样,从来没有听说过谐音的意思是。这里有一个很好的视频用一个例子来解释它,但快速和肮脏的是,它最常见的用例是平均利率,我们熟悉的算术平均值并不足够。
如果你回到 F1 得分的第一个等式,你可以通过查看第二个定义,即分子中的召回率乘以精度,来判断如果召回率或精度为 0,那么 F1 得分也为 0。这使得它成为召回率和精确度之间的一个很好的折衷,这样你就不会遇到像我刚才给出的例子那样的极端情况。在最近的例子中,只有 5 张正确分类的狗的图片,精度是 1.0,但是回忆是 5/500 = 0.01,所以 F1 分数类似地被抑制在(大约)0.02。准确地说,是 0.51。
在这种情况下,精确度和 F1(分别为 0.51 和 0.02)都反映了较差的整体性能,但这是因为这是一个平衡的数据集。 在一个不平衡的数据集中,F1 分数而不是准确率会在查全率和查准率之间取得一个很差的平衡 。那是 F1 score 的用例。
一个例子:5 张狗的图片,995 张其他东西的图片(不平衡)。我们让一个分类器运行,它正确地将其中一张狗的图片分类,但称其他图片都不是狗。这意味着有 4 张错误分类的狗的图片。召回率是 0.2(相当差),精确度是 1.0(完美),但是精确度是 0.999,并没有反映出这个模型在捕捉这些狗的图片上做得有多差;F1 分数等于 0.33,反映了查全率和查准率之间的不均衡。
阅读分类报告
我的标记版本分类 _ 报告来自 scikit-learn。
第一次看到 scikit-learn 时,它对我来说非常难以理解,以至于我推迟了为项目选择指标,因为我无法找出它们在报告中的位置。我希望有人给了我上面的小抄。
我认为让它如此难以阅读的部分原因是它打印出了accuracy
,然后是macro avg
和weighted avg
,我的大脑认为是accuracy
;但那是错的,他们属于precision
、recall
、f1-score
。恰好有一个数字属于accuracy
,我在上面用红色画了一个虚线框。
精确度、召回率和 F1 分数,每个都在上面自己的绿框中,都按类别细分,然后给出每个的宏观平均值和加权平均值。宏观平均数是我们习惯看到的通常平均数。把它们加起来,然后除以它们的数量。加权平均值考虑了计算中每个类别的数量,因此一个类别的数量越少,意味着它的精确度/召回率/F1 分数对每个类别的加权平均值的影响就越小。橙色框中的support
表示每个职业有多少个:1 个class 0
,1 个class 1
,3 个class 2.
例如,阅读上面的图表可能是这样的:对于class 0
、class 1
和class 2
,精度分别是 0.5、0 和 1。这意味着在模型归类为 0 类的事物中,只有 50%是真实的;在模型归类为 1 类的事物中,0%是真实的;在模型归类为第二类的事物中,100%都是真实的。宏观平均精度为 0.5,加权平均精度为 0.7。此模型的加权平均值较高,因为精度下降的地方是类 1,但它在此数据集中的代表性不足(仅 1/5),因此在加权平均值中所占比例较小。
何时使用什么(概述)
- 使用精确度获得带有平衡数据集的模型性能的一般报告。
- 当你寻找的每一个实例都太珍贵而不能错过时,使用特异性/回忆性/敏感性。示例包括医疗保健、欺诈检测和安全事务中的测试。你会得到一些假警报,但这是让真正的疾病/欺诈/危险逃脱的较小的罪恶。
- 当你想确信你的模型是真的时,使用 precision 。您正在寻找的一些东西会跑掉,但您可以确信,当您的模型 pings 某个东西时,它确实是它所说的那样。想想申请人筛选。一些可行的申请人将会逃脱,但是当模型 pings 一个可行的申请人时,你可以对此有信心。
- 使用 F1 分数作为召回率和精确度的平均值,尤其是在使用不平衡数据集时。如果召回率或精确度是 0,F1 分数将反映 an 也是 0。举例来说,我最近试图按情绪对推文进行分类,积极的、消极的或中性的,但数据集不平衡,中性的评论比积极或消极的评论多得多。只有 macro F1 score 很好地描述了整体模型性能(同等关注所有三个类)。
进一步阅读
- https://en.wikipedia.org/wiki/Sensitivity_and_specificity
- https://en.wikipedia.org/wiki/Precision_and_recall
- https://en.wikipedia.org/wiki/F-score
- https://sebastianraschka . com/FAQ/docs/computing-the-f1-score . html
- https://towards data science . com/beyond-accuracy-precision-and-recall-3da 06 bea 9 f6c
- https://sci kit-learn . org/stable/modules/generated/sk learn . metrics . class ification _ report . html
选择正确的误差度量:MAPE 与斯马普
两种流行的误差度量标准的利弊
MSE、RMSE、MAE、MAPE、sMAPE……仅举几例。有大量不同的错误度量标准,每一个都有其优点和缺点,并且应该比前一个覆盖更多的情况。那么,如何决定在我们的项目中使用哪种度量呢?
我认为回答这个问题的关键是了解最流行的度量标准的优点和局限性。这样,我们可以选择最适合手头任务的指标。这就是为什么在这篇文章中,我介绍了我最近使用的两个指标。
平均绝对百分比误差(MAPE)
平均绝对百分比误差是评估预测性能的最流行的度量之一。它由下面的公式给出。
其中 A_t 代表实际值,而 F_t 是预测值。在这种情况下,我们可以将 t 解释为进行一般回归问题(预测人的体重或房屋价格)时的观察值,或者时间序列分析时的时间指数。
该公式通常包括将该值乘以 100%,以百分比形式表示该数字。
优势
- 以百分比表示,与尺度无关,可用于比较不同尺度的预测。但是我们应该记住,MAPE 的值可能超过 100%。
- 易于向利益相关者解释。
缺点
- 当实际值为零时,MAPE 会采用未定义的值,例如在需求预测中就可能出现这种情况。此外,当实际值非常接近零时,它采用极值。
- MAPE 是不对称的,它对负误差(当预测高于实际时)的惩罚比对正误差的惩罚更重。这是因为预测值过低时,百分比误差不能超过 100%。而过高的预测没有上限。因此,MAPE 将倾向于低估而非高估的模型。
- MAPE 假设变量的测量单位具有有意义的零值。因此,虽然预测需求和使用 MAPE 是有意义的,但当预测以摄氏度表示的温度(不仅仅是摄氏度)时就没有意义了,因为温度有一个任意的零点。
- MAPE 不是处处可微的,这在将其用作优化准则时会导致问题。
有关在商业环境中使用 MAPE 的更多信息,请参见本文。
对称平均绝对百分比误差
在讨论了 MAPE 之后,我们也来看看它的一个替代方案——对称 MAPE。它应该克服上面提到的不对称——预测高于实际的无限性。
sMAPE 有几个不同的版本。另一种流行且普遍接受的方法是在分母中的两个项上加上绝对值,以说明当实际值和预测值都等于 0 时 sMAPE 是不确定的。
优势
- 用百分比表示。
- 修复了原始 MAPE 的缺点-它同时具有下限(0%)和上限(200%)。
缺点
- 当真实值和预测值都非常接近零时,不稳定。当这种情况发生时,我们会用一个非常接近于零的数来处理除法。
- sMAPE 可以取负值,因此对“绝对百分比误差”的解释可能会产生误导。
- 0%到 200%的范围解释起来并不直观,因此 sMAPE 公式中分母除以 2 的部分经常被忽略。
- 每当实际值或预测值为 0 时,sMAPE 将自动达到上限值。
- 与 MAPE 关于有意义的零值的假设相同。
- 在修正无边界的不对称时,sMAPE 引入了另一种由公式的分母引起的微妙不对称。想象两种情况。在第一个例子中,A = 100,F = 120。sMAPE 为 18.2%。现在有一个非常类似的例子,A = 100,F = 80。这里我们得出了 22.2%的 sMAPE。
结论
在本文中,我描述了回归问题的两种流行的性能评估方法。虽然它修复了 MAPE 的一些缺点,但仍有一些问题和一些新的问题。您可以研究的一些其他指标有:
- 平均绝对标度误差
- 平均方向精度(MDA)
- 准确率的对数(预测值与实际值之比)
一如既往,我们欢迎任何建设性的反馈。你可以在推特或评论中联系我。
如果您对本文感兴趣,您可能也会喜欢:
这些网站将帮助您跟上数据科学的最新趋势
towardsdatascience.com](/my-10-favorite-resources-for-learning-data-science-online-c645aa3d0afb) [## 有助于时间序列分析的 5 种绘图类型
以及如何使用 Python 快速创建它们!
towardsdatascience.com](/5-types-of-plots-that-will-help-you-with-time-series-analysis-b63747818705) [## Python 统计块中的新成员:pingouin
图书馆的快速参观,以及它是如何从老守卫中脱颖而出的
towardsdatascience.com](/the-new-kid-on-the-statistics-in-python-block-pingouin-6b353a1db57c)
选择正确的数据库
如何根据您的需求选择合适的存储解决方案
存储解决方案和数据库—如何选择最佳方案?Jan Antonin Kolar 在 Unsplash 上拍摄的照片
想象一下——你正在参加一个系统设计面试,需要选择一个数据库来存储,比如说,一个电子商务系统中与订单相关的数据。您的数据是结构化的,需要保持一致,但是您的查询模式与标准的关系数据库不匹配。你需要你的事务被隔离,原子的和所有的东西都是酸的…但是 OMG 它需要像 Cassandra 一样无限扩展!!那么,您如何决定选择哪种存储解决方案呢?好吧,让我们看看!
首先,我们在处理什么样的数据?是记录、文件系统还是音频/视频内容?我们打算对这些数据做什么样的处理?我们需要搜索什么或者运行复杂的分析算法吗?
有哪些不同类型的存储解决方案?
根据我们的要求以及我们使用或访问数据的方式,我们可能会寻找以下存储解决方案:
缓存解决方案 —如果我们正在设计一个像 Twitter 或脸书这样的读负载系统,我们可能会捕获大量数据,甚至是完整的时间线,以满足低延迟要求。这里的一些选项可能是 Redis 或 Memcached 。
文件系统存储 —如果我们正在设计某种资产交付服务,其中我们可能需要存储图像或音频/视频文件,我们可能需要使用称为 blob 存储的东西。一个非常受欢迎的例子是亚马逊 S3。
文本搜索引擎 —如果我们正在设计一个像亚马逊一样的系统,并且需要实现一个搜索功能,该怎么办?关于搜索功能,我们也需要考虑错别字。假设用户想要搜索“衬衫”,但是却键入了“衬衫”。现在,如果我们不显示任何结果,这将是非常糟糕的用户体验。我们的系统需要足够智能,以显示“衬衫”或“短裤”的结果。这就是所谓的模糊搜索,这就是我们使用文本搜索引擎的地方,比如 Elasticsearch 。
数据仓库——我知道!我们一直在讨论数据和存储,怎么能不考虑大数据呢!有时,我们只需要将所有数据转储到一个存储中,然后我们可以在那里执行各种分析。这些系统更多地用于通常交易的离线报告。这就是我们最终使用像 Hadoop 这样的数据仓库解决方案的地方。
现在,您可能已经注意到,我们一直在谈论“存储解决方案”,而不是“数据库”。所以现在让我们来看看数据库!
SQL?NoSQL?这是怎么回事?
作者图片
嗯,我们可以根据几个因素来决定使用哪种数据库,这些因素是——数据的结构、查询模式和规模。
我知道有点困惑!这就是为什么我会附上我在这篇文章中提到的视频。他们解释得很好,但我们也将在接下来的章节中讨论它,所以请继续阅读。
在系统设计面试中选择最佳数据库——CodeKarle
现在,规模,结构,以及查询模式。没错。如果信息是结构化的,可以用表来表示,如果我们需要我们的事务是原子的、一致的、隔离的和持久的(ACID),我们就用关系数据库。最常用的是 MySQL。
现在,如果不需要 ACID 属性,那么您仍然可以使用关系数据库,或者您可以使用 NoSQL 替代方案。但是如果你的数据缺乏结构,它就不能用表格来表示,现在我们需要使用 NoSQL 数据库,比如 MongoDB、Cassandra、HBase、Couchbase、T19 等等。这就是查询模式成为决定性因素的地方。
psst:elastic search 是文档数据库的一个特例。
如果我们的数据中有各种各样的属性和各种各样的查询,我们使用一个文档数据库,比如 MongoDB 或 Couchbase 。但是,如果我们必须在非常大的规模上工作,但是我们需要运行的查询类型很少,那么我们会选择像 Cassandra 或 HBase 这样的列式 DB 。甚至在列数据库之间,你可能知道,HBase 是建立在 Hadoop 之上的。因此,在设置 HBase 时,我们首先需要设置 Hadoop 和相关组件,然后在其上设置 HBase。这增加了设置系统的复杂性,所以我个人会选择 Cassandra,即使只是为了简单。性能方面两者给出相似的结果。
现在,像 Cassandra 这样的列数据库的问题是,它们主要通过划分和复制数据来工作。因此,如果您可以选择分区键,使所有查询都在 where 子句中使用公共分区键,那么 Cassandra 是一个不错的选择。
我看到了“codekarle”写的这篇关于如何选择最佳存储解决方案的文章,这篇文章很好地解释了什么时候使用列式数据库与文档数据库可能是有意义的,并举例说明了优步如何与系统的司机端和骑手端进行交互。让我用同样的场景来解释一下。
假设优步已经将与乘车相关的信息保存在一个 Cassandra 中,并将司机 id 作为分区键。现在,当我们运行一个查询来获取某一天特定驱动程序的所有数据时,它会根据分区键驱动程序 id 来获取数据。这是卡珊德拉解决方案的隔断部分。现在,如果我们试图通过客户 id 查询客户在某一天的乘车情况会怎样。现在,查询将被发送到所有分区,效率也随之降低!这就是解决方案的复制方面的用武之地。我们可以简单地复制整个数据,现在使用客户 id 作为分区键。现在,当基于客户 id 的查询到来时,它将被定向到使用客户 id 作为分区键的实例。这就是卡珊德拉可以无限扩展的原因。还记得 Cassandra 的查询模式吗?我们提到过,只有在查询种类有限的情况下,它才是有用的。这是因为我们只能复制数据这么多次。
让我们现实一点,一个数据库够吗?
现在,我们已经看到了各种存储解决方案,以及如何根据我们的需求和需要存储的信息类型在各种数据库之间进行选择。但这就够了吗?参考上述文章中的另一个例子,在某些情况下,单个 DB 不足以满足我们的需求。例如,在 Amazon 的例子中,订单数据需要遵循 ACID 属性,但是它需要像列数据库一样具有无限的可伸缩性。在这种情况下,我们将使用 MySQL + Cassandra 这样的数据库组合。现在,所有关于正在进行的订单的信息,需要遵循 ACID 属性,将存储在 MySQL 数据库中,一旦完成,我们可以将它们移动到 Cassandra,这可以用作永久存储。因此,只要我们需要 ACID 属性,数据就会保留在关系数据库中,然后转移到一个列数据库中,该列数据库可以根据数据的大小进行伸缩。问题解决了!
我希望这能帮助你在下一次系统设计面试中提出一个参考清单。认为我错过了一个重要的数据库/存储解决方案?请在评论中告诉我!
另外,这里有一个 youtube 链接指向我提到的解决方案。
为 AWS 上的深度学习选择合适的 GPU
如何选择正确的亚马逊 EC2 GPU 实例进行深度学习训练和推理——从最佳性能到最具成本效益,以及介于两者之间的一切
最新更新:【2022 年 2 月 17 日。
-添加了新的** G5 和 G5g 实例类型
-添加了新的部分:“对忙碌的数据科学家的重要建议”
-更新了所有现有的部分和图形以代表当前的产品组合
-添加了一个电子表格,其中包含 AWS 上所有 GPU 及其特性的详细列表**
作者插图
就在十年前,如果你想使用 GPU 来加速数据处理或科学模拟代码,你要么找一个电脑游戏玩家,要么联系你友好的邻居超级计算中心。今天,你可以登录你的 AWS 控制台,从一系列基于 GPU 的 Amazon EC2 实例中进行选择。
你问 AWS 上可以访问哪些 GPU?您可以启动具有不同 GPU 内存大小(8 GB、16 GB、24 GB、32 GB、40 GB)、NVIDIA GPU 代(Ampere、Turing、Volta、Maxwell、Kepler)不同功能(FP64、FP32、FP16、INT8、Sparsity、TensorCores、NVLink)、每个实例不同数量的 GPU(1、2、4、8、16)以及与不同 CPU(Intel、AMD、Graviton2)配对的 GPU 实例。您还可以选择具有不同 vCPUs(核心线程数)、系统内存和网络带宽的实例,并添加一系列存储选项(对象存储、网络文件系统、块存储等)。)—总而言之,你有选择。
我这篇博客的目标是为您提供指导,告诉您如何在 AWS 上为您的深度学习项目选择正确的 GPU 实例。我将讨论各种 EC2 GPU 实例的主要特性和优势,以及最适合每种实例类型和规模的工作负载。如果你是 AWS 新手,或者 GPU 新手,或者深度学习新手,我希望你能找到为项目做出正确选择所需的信息。
这篇博文涉及的主题:
- 给忙碌的数据科学家/ML 从业者的主要建议
- 为什么您应该选择正确的 GPU 实例 而不仅仅是正确的 GPU
- 深入探讨 GPU 实例类型:P4、P3、G5 (G5g)、G4、P2 和 G3
- AWS 上的其他机器学习加速器和实例
- 为 ML 使用 GPU 实例时的成本优化技巧
- 在 AWS 上使用什么软件和框架?
- HPC 使用案例应考虑哪些 GPU?
- 所有 AWS GPU 实例及其特性的完整且详细的电子表格
关键建议针对忙碌的数据科学家/ML 从业者
赶时间?只想要没有深潜的最终推荐?我掩护你。这里有 5 个 GPU 实例建议,应该适用于大多数深度学习用例。但是,我建议您回来阅读本文的其余部分,这样您可以做出更明智的决定。
1。AWS 上性能最高的多 GPU 实例
实例: p4d.24xlarge
何时使用:需要你能得到的所有性能的时候。将其用于大型模型和数据集的分布式培训。
你得到的: 8 个NVIDIA A100GPU,每个 GPU 40gb GPU 内存。基于最新的 NVIDIA Ampere 架构。包括用于快速多 GPU 培训的第三代 NVLink。
2.AWS 上性能最高的单 GPU 实例:
实例: 你得到的: 1 x NVIDIA V100 GPU 配 16gb GPU 内存。基于较老的 NVIDIA Volta 架构。性能最好的单 GPU 仍然是 P4 实例上的 NVIDIA A100,但你只能在 P4 获得 8 个 NVIDIA A100 GPUs。在接下来讨论的 G5 实例上,这种 GPU 比 NVIDIA A10G 有轻微的性能优势,但 G5 更具成本效益,并具有更多的 GPU 内存。
3.最佳性价比,AWS 上的单 GPU 实例
实例: g5.xlarge
**何时使用:**当你想要高性能、比 P3 更低成本的更多 GPU 内存实例 你得到的: 1 x NVIDIA A10G GPU 拥有 24 GB 的 GPU 内存,基于最新的 Ampere 架构。NVIDIA A10G 可以被视为p4d.24xlarge
上 A100 的低功耗近亲,因此当您需要更多计算时,可以轻松迁移和扩展。如果您有更多的预处理或后处理步骤,请考虑使用g5.(2/4/8/16)xlarge
为具有更多 vCPUs 和更高系统内存的相同单 GPU 提供更大的尺寸。
4.最佳性价比,AWS 上的多 GPU 实例:
实例: p3.(8/16)xlarge
何时使用:性价比高的多 GPU 模型开发与训练。 你得到的: p3.8xlarge
有 4 个英伟达 V100GPU,p3.16xlarge
有 8 个英伟达 V100 GPUs,每个 GPU 上有 16 GB 的 GPU 内存,基于较旧的英伟达 Volta 架构。对于更大的模型、数据集和更快的性能,请考虑 P4 实例。
5.AWS 上的高性能 GPU 实例,价格适中
实例: g4dn.xlarge
**何时使用:**在模型开发和训练的成本上,性能低于其他选项。成本有效的模型推理部署。 你得到的: 1 x 英伟达 T4 GPU 配 16gb GPU 内存。基于上一代英伟达图灵架构。如果您有更多的预处理或后处理,请考虑使用g4dn.(2/4/8/16)xlarge
来获得更多的 vCPUs 和更高的系统内存。
有了这些,你应该有足够的信息来开始你的项目。如果你仍然渴望了解更多,让我们深入研究每个实例类型、GPU 类型及其在 AWS 上的特性,并讨论何时以及为什么应该考虑它们。
为什么您应该选择正确的“GPU 实例”而不仅仅是正确的“GPU”
或者为什么您应该着眼于整个系统,而不仅仅是 GPU 的类型
GPU 是深度学习系统的主力,但最好的深度学习系统不仅仅是 GPU。您必须选择合适的计算能力(CPU、GPU)、存储、网络带宽和优化软件,以最大限度地利用所有可用资源。
一些深度学习模型需要更高的系统内存或更强大的 CPU 来进行数据预处理,其他模型可能在更少的 CPU 内核和更低的系统内存下运行良好。这就是为什么你会看到许多亚马逊 EC2 GPU 实例选项,有些具有相同的 GPU 类型,但不同的 CPU,存储和网络选项。如果你是 AWS 新手,或者是 AWS 深度学习新手,做出这个选择可能会感到不知所措。
让我们从 AWS 上的高级 EC2 GPU 实例命名开始。GPU 实例有两个系列——P 系列和 G 系列 EC2 实例,下图显示了各种实例代和实例大小。
用于深度学习的亚马逊 EC2 GPU 实例
历史上, P 实例类型代表更适合高性能计算(HPC)工作负载的 GPU,其特点是更高的性能(更高的瓦数、更多的 cuda 内核)和对科学计算中使用的双精度(FP64)的支持。 G 实例类型的 GPU 更适合图形和渲染,其特点是缺乏双精度和更低的性价比(更低的瓦数,更少的 cuda 内核)。
随着近年来 GPU 上的机器学习工作量快速增长,这一切都开始发生变化。今天,新一代的 P 和 G 实例类型都适合机器学习。对于 HPC 工作负载和要求苛刻的机器学习培训工作负载,仍然推荐使用 P实例类型,对于机器学习推理部署和计算密集型程度较低的培训,我推荐使用 G 实例类型。在下一节讨论特定的 GPU 实例类型时,所有这些将变得更加清晰。
每个实例大小都有一定的 vCPU 计数、GPU 内存、系统内存、每个实例的 GPU 数和网络带宽。字母(P 3 ,G 5) 旁边的数字代表实例代。数字越大,实例类型越新。每个实例代可以有不同架构的 GPU,下面的时间线图像显示了 NVIDIA GPU 架构代、GPU 类型和相应的 EC2 实例代。
现在,让我们按照下面列出的顺序,按系列、代和规模来看一下这些实例。
我们将按照这里显示的顺序讨论每个 GPU 实例类型
亚马逊 EC2 P4:AWS 上性能最高的深度学习训练 GPU 实例类型。
P4 实例提供对基于 NVIDIA Ampere 架构的NVIDIA A100 GPU的访问。它只有一种尺寸——每个实例有多个 GPU,每个 GPU 有 8 个 A100 GPUs,每个 GPU 有 40 GB 的 GPU 内存,96 个 vCPU,以及 400 Gbps 的网络带宽,用于记录设置训练性能。
P4 实例特征一目了然:
- GPU 一代:英伟达安培
- 支持的精度类型 : FP64、FP32、FP16、INT8、BF16、TF32、第三代张量核(混合精度)
- GPU 内存:每颗 GPU 40 GB
- GPU 互连 : NVLink 高带宽互连,第三代
基于 NVIDIA Ampere 的 NVIDIA A100 GPU 在 P4 实例上有什么新功能?
每一代新的 GPU 都比上一代更快,这里也不例外。NVIDIA A100 明显快于 NVIDIA V100(在稍后讨论的 P3 实例中发现),但也包括适合深度学习的更新精度类型,特别是 BF16 和 TF32。
深度学习训练通常在单精度或 FP32 中完成。FP32 IEEE 标准格式的选择早于深度学习,因此硬件和芯片制造商已经开始支持更好地用于深度学习的更新精度类型。这是一个很好的例子,说明硬件的发展是为了满足应用程序的需求,而开发人员必须改变应用程序才能在现有的硬件上工作。
NVIDIA A100 包括用于深度学习的特殊核心,称为张量核心,以运行混合精度训练,这是首次在 Volta 架构中引入的。而不是在单精度(FP32)下训练模型,你的深度学习框架可以使用张量核在半精度(FP16)下进行矩阵乘法,在单精度(FP32)下进行累加。这通常需要更新您的训练脚本,但可以带来更高的训练性能。每个框架对此的处理方式不同,所以请参考您的框架的官方指南( TensorFlow 、 PyTorch 和 MXNet )来了解混合精度的使用。
NVIDIA A100 GPU 支持两种新的精密格式——BF16 和 TensorFloat-32 (TF32)。TF32 的优势在于 NVIDIA A100 上的 TF32 张量核心可以从深度学习框架中读取 FP32 数据,并使用和产生标准的 FP32 输出,但在内部它使用了降低的内部精度。这意味着与混合精度训练不同,混合精度训练通常需要对训练脚本进行代码修改,像 TensorFlow 和 PyTorch 这样的框架可以支持 TF32 开箱即用。BF16 是 IEEE FP16 标准的替代产品,具有更高的动态范围,更适合处理梯度而不损失精度。TensorFlow 已经支持 BF16 有一段时间了,你现在可以在使用p4d.24xlarge
实例时利用 NVIDIA A100 GPU 上的 BF16 precision。
P4 实例只有一种大小:p4d.24xlarge
。让我们仔细看看。
p4d.24xlarge:云中最快的 GPU 实例
如果你需要云中绝对最快的训练 GPU 实例,那么只需看看p4d.24xlarge.
就行了,这个头衔以前由p3dn.24xlarge
拥有,它拥有 8 个基于 Volta 架构的 NVIDIA V100 GPU。
您可以访问 8 个配有 40 GB GPU 内存的 NVIDIA A100 GPUs,通过第三代 NVLink 互连,理论上,与我们将在下一节讨论的 P3 实例类型上可用的 NVIDIA V100 上的第二代 NVLink 相比,第三代 NVLink 的 GPU 间带宽增加了一倍。这使得p4d.24xlarge
实例类型非常适合分布式数据并行训练,以及不适合单个 GPU 的大型模型的模型并行训练。该实例还允许您访问 96 个 vCPUs、1152 GB 系统内存(EC2 GPU 实例中最高的)和 400 Gbps 网络带宽(EC2 GPU 实例中最高的),这对于实现大规模分布式培训作业的近线性扩展非常重要。
在这个实例上运行nvidia-smi
,可以看到 GPU 内存是 40 GB。这是目前 AWS 上每 GPU 最大的 GPU 内存。如果您的模型很大,或者您正在处理 3D 图像或其他大批量数据,那么这就是要考虑的实例。运行nvidia-smi topo -matrix
,你会看到 NVLink 被用于 GPU 之间的通信。与 PCIe 相比,NVlink 提供了更高的 GPU 间带宽,这意味着多 GPU 和分布式培训作业将运行得更快。
Amazon EC2 G5:推理部署的最佳性价比单 GPU 实例和多 GPU 实例选项
G5 实例很有趣,因为在这种实例类型下有两种类型的 NVIDIA GPUs。这与 EC2 实例类型和 GPU 架构类型之间具有 1:1 关系的所有其他实例类型不同。
G5 实例类型有两个不同的子类别,具有不同的 CPU 和 GPU 类型
它们都有不同的实例大小,包括单个和多个 GPU 实例。
首先让我们看看 G5 实例类型,特别是g5.xlarge
实例大小,我在开始时的关键要点/建议列表中讨论过。
G5 实例:AWS 上单 GPU 实例的最佳性价比
G5 实例功能一览:
- GPU 一代 : NVIDIA Ampere
- 支持的精度类型 : 支持的精度类型 : FP64、FP32、FP16、INT8、BF16、TF32、张量核第三代(混合精度)
- GPU 内存 : 24 GB
- GPU 互连 : PCIe
G5 给你带来了什么?
GPU 实例:g5.(2/4/8/16)xlarge
为 AWS 上的单 GPU 实例提供了最佳的性价比。从g5.xlarge
开始,作为您的单个 GPU 模型开发、原型制作和培训实例。您可以将大小增加到g5.(2/4/8/16).xlarge
,以获得更多 vcpu 和系统内存,从而更好地处理依赖 CPU 能力的数据预处理和后处理。您可以访问单个和多个 GPU 实例大小(4 个 GPU、8 个 GPU)。NVIDIA A10G 的单 GPU 选项g5.(2/4/8/16)xlarge
为训练和推理部署提供了最佳的性能/成本配置。
如果你看一下g5.xlarge
实例的nvidia-smi
的输出,你会看到热设计功率(TDP),这是 GPU 可以汲取的最大功率,是 300W。将此与上面 P4 部分显示的nvidia-smi
的输出进行比较,后者显示的 TDP 为 400W。这使得在 G5 实例中的 NVIDIA A10G 是在 P4 实例类型上发现的 NVIDIA A100 的较低功率表亲。因为它也基于相同的 NVIDIA Ampere 架构,这意味着它包括 P4 实例类型支持的所有功能。
如果您的模型和数据规模增长,您需要进行分布式培训,或者如果您希望在更快的 GPU 上运行多个并行培训实验,这使得 G5 实例非常适合单 GPU 培训并将您的培训工作负载迁移到 P4。
g5.xlarge
上 nvidia-smi 的输出
虽然您可以访问多 GPU 实例大小,但我不建议将它们用于多 GPU 分布式培训,因为没有 NVIDIA 高带宽 NVLink GPU 互连,通信将回退到速度明显较慢的 PCIe。G5 上的多 GPU 选项意味着在每个 GPU 上托管多个模型,用于推理部署用例。
G5g 实例:良好的性能和成本效益的 GPU 实例,如果你对 ARM CPU 没问题的话
G5g 实例功能一览:
- GPU 一代:英伟达图灵
- 支持的精度类型 : 支持的精度类型 : FP32,FP16,张量核(混合精度),INT8
- GPU 内存 : 16GB
- GPU 互连 : PCIe
你用 G5g 得到了什么?
与 G5 实例不同,G5g 实例提供了基于旧的 NVIDIA 图灵架构的 NVIDIA T4G GPUs。NVIDIA T4G GPU 最接近的表亲是亚马逊 EC2 G4 实例上可用的 NVIDIA T4 GPU,我将在下一节讨论。有趣的是,G5g 实例和 G4 实例的关键区别在于 CPU 的选择。
G5g 实例提供基于 ARM 的 AWS Graviton2 CPU,而
G4 实例提供基于 x86 的英特尔至强可扩展 CPU。
GPU(T4 和 T4g)在性能方面非常相似
我们在这两者之间的选择应该归结为您更喜欢的 CPU 架构。我个人倾向于今天的机器学习是 G4 实例而不是 G5g 实例,因为更多的开源框架被设计为在英特尔 CPU 上运行,而不是基于 ARM 的 CPU。
亚马逊 EC2 P3:AWS 上最高性能的单 GPU 实例和经济高效的多 GPU 实例选项
P3 实例提供对基于 NVIDIA Volta 架构的NVIDIA V100 GPU的访问,您可以为每个实例启动单个 GPU 或多个 GPU(4 个 GPU、8 个 GPU)。单个 GPU 实例p3.2xlarge
就可以成为你深度学习训练的日常驱动。最强大的实例p3dn.24xlarge
可让您访问 8 个 V100,配有 32 GB GPU 内存、96 个虚拟 CPU 和 100 Gbps 网络吞吐量,非常适合分布式培训。
P3 实例特征一目了然:
- GPU 一代:英伟达 Volta
- 支持的精度类型 : FP64、FP32、FP16、张量核(混合精度)
- GPU 内存 : 16 GB 在
p3.2xlarge, p3.8xlarge, p3.16xlarge
,32 GB 在p3dn.24xlarge
- GPU 互连 : NVLink 高带宽互连,第二代
NVIDIA V100 还包括张量核心来运行混合精度训练,但不提供 P4 实例上提供的 NVIDIA A100 中引入的 TF32 和 BF16 精度类型。然而,P3 实例有 4 种不同的大小,从单个 GPU 实例大小到 8 个 GPU 实例大小,使其成为灵活培训工作负载的理想选择。让我们来看看下面的每个实例大小p3.2xlarge
、p3.8xlarge
、p3.16xlarge
和p3dn.24xlarge.
p3.2xlarge:单 GPU 训练的最佳 GPU 实例
如果你需要一个 GPU 并且性能是优先考虑的,这应该是你大多数深度学习培训工作的首选实例。G5 实例比 P3 的性能稍低,但更具成本效益。使用p3.2xlarge
,您可以访问一个 NVIDIA V100 GPU,它具有 16 GB GPU 内存、8 个 vCPUs、61 GB 系统内存和高达 10 Gbps 的网络带宽。在撰写本文时,V100 是云中最快的 GPU,并且支持张量核,如果您的脚本可以利用混合精度训练,则可以进一步提高性能。
如果您启动一个 Amazon EC2 p3.2xlarge
实例并运行nvidia-smi
命令,您可以看到实例上的 GPU 是支持 NVLink 的 V100-SXM2 版本(我们将在下一节讨论这一点)。在内存使用下,你会看到它有 16 GB 的 GPU 内存。如果您需要 16 GB 以上的 GPU 内存来处理大型模型或大数据量,那么您应该考虑p3dn.24xlarge
(下面有更多详细信息)。
p3.8xlarge 和 p3.16xlarge:小规模多 GPU 训练和运行并行实验的理想 GPU 实例
如果你需要更多的 GPU 用于实验,更多的 vCPUs 用于数据预处理和数据扩充,或者更高的网络带宽,可以考虑p3.8xlarge
(带 4 个 GPU)和p3.16xlarge
(带 8 个 GPU)。每个 GPU 都是 16 GB 内存的 NVIDIA V100。它们还包括用于高带宽 GPU 间通信的 NVLink 互连,这将为多 GPU 培训提供便利。使用p3.8xlarge
您可以访问 32 个虚拟 CPU 和 244 GB 系统内存,使用p3.16xlarge
您可以访问 64 个虚拟 CPU 和 488 GB 系统内存。这个实例非常适合两个用例:
多 GPU 培训工作:如果你刚刚开始多 GPU 培训,4 个 GPU 在p3.8xlarge
上或者 8 个 GPU 在p3.16xlarge
上可以给你一个不错的加速。您还可以使用该实例为更大规模的多节点培训作业准备您的培训脚本,这通常需要您使用 Horovod 、 tf.distribute.Strategy 或 torch.distributed 等库来修改您的培训脚本。参考我的使用 Horovod 进行分布式培训的分步指南:
并行实验:当您必须并行运行模型架构和超参数的变体以加快实验速度时,多 GPU 实例也会派上用场。使用p3.16xlarge
,您可以在多达 8 种型号上进行训练。与多 GPU 训练作业不同,由于每个 GPU 都独立运行训练,并且不会阻止其他 GPU 的使用,因此您可以在模型探索阶段提高工作效率。
p3dn.24xlarge: 高性能且经济高效的培训
这个实例之前拥有云头衔中最快的 GPU 实例,现在属于p4d.24xlarge
。这并不使p3dn.24xlarge
显得没精打采。它仍然是今天你能在云上找到的最快的实例类型之一,并且比 P4 实例更具成本效益。你可以访问 8 个 NVIDIA V100 GPUs,但与拥有 16 GB GPU 内存的p3.16xlarge
不同,p3dn.24xlarge
上的 GPU 拥有 32 GB GPU 内存。这意味着你可以适应更大的模型和更大批量的训练。该实例允许您访问 96 个 vCPUs、768 GB 系统内存和 100 Gbps 网络带宽,这对于实现大规模分布式培训作业的近线性扩展非常重要。
在这个实例上运行 nvidia-smi
,可以看到 GPU 内存是 32 GB。唯一一个拥有比这更多 GPU 内存的实例是p4d.24xlarge
,它是一个拥有 40gb GPU 内存的 A100 GPU。如果您的模型很大,或者您正在处理 3D 图像或其他大批量数据,那么这就是要考虑的实例。运行nvidia-smi topo — matrix
,你会看到 NVLink 被用于 GPU 之间的通信。与 PCIe 相比,NVlink 提供了更高的 GPU 间带宽,这意味着多 GPU 和分布式培训作业将运行得更快。
Amazon EC2 G4:用于训练的高性能单 GPU 实例和用于经济高效推理的多 GPU 选项
G4 实例提供对基于英伟达图灵架构的英伟达 T4 GPU 的访问。您可以为每个实例启动一个 GPU,也可以为每个实例启动多个 GPU(4 个 GPU,8 个 GPU)。在下面的时间线图中,你会看到 G4 instance 的正下方是 G5g instance,这两个实例都是基于采用 NVIDIA 图灵架构的 GPU。我们已经在前面的部分讨论了 G5g 实例类型,G4(英伟达 T4)和 G5g(英伟达 T4G)中的 GPU 在性能上非常相似。在这些情况下,您的选择将归结为 CPU 类型的选择。
G5g 实例提供基于 ARM 的 AWS Graviton2 CPU,而
G4 实例提供基于 x86 的英特尔至强可扩展 CPU。
GPU(T4 和 T4g)在性能方面非常相似
在 GPU 时间轴图中,您可以看到 NVIDIA Turing 架构是在 NVIDIA Volta 架构之后推出的,并为机器学习引入了几个新功能,如下一代张量核心和整数精度支持,这使它们成为经济高效的推理部署和图形的理想选择。
G4 实例特征一览:
- GPU 一代:英伟达图灵
- 支持的精度类型 : FP64、FP32、FP16、张量核(混合精度)、INT8、INT4、INT1
- GPU 内存 : 16 GB
- GPU 互连 : PCIe
G4 实例上的英伟达 T4 GPU 有什么新功能?
NVIDIA Turing 率先引入了对整数精度(INT8)数据类型的支持,这可以显著提高推理吞吐量。在训练期间,模型权重和梯度通常以单精度(FP32)存储。事实证明,要在训练好的模型上运行预测,实际上并不需要全精度,并且可以在半精度(FP16)或 8 位整数精度(INT8)中进行精度降低的计算。这样做可以提高吞吐量,而不会牺牲太多的准确性。准确性会有一些下降,下降的程度取决于具体到你的模型和训练的各种因素。总的来说,与其他 GPU 实例相比,G4 实例可以获得最佳的推理性能/成本。英伟达的支持矩阵显示了哪些神经网络层和 GPU 类型支持 INT8 等精度进行推理。
英伟达 T4(和英伟达 T4G)是 AWS 上任何 EC2 实例中功耗最低的 GPU。在这个实例上运行nvidia-smi
,你可以看到g4dn.xlarge
有一个 16gb GPU 内存的英伟达 T4 GPU。你还会注意到,与 NVIDIA A10G 的 300 瓦相比,功率上限为 70 瓦。
以下实例大小都可以让您访问单个 NVIDIA T4 GPU,并增加 vCPU、系统内存、存储和网络带宽的数量:g4dn.xlarge
(4 个 vCPU,16 GB 系统内存)、g4dn.2xlarge
(8 个 vCPU,32 GB 系统内存)、g4dn.4xlarge
(16 个 vCPU,64 GB 系统内存)、g4dn.8xlarge
(32 个 vCPU,128 GB 系统内存)、g4dn.16xlarge
(64 个 vCPU,256 GB 系统内存)。您可以在产品详情部分的产品 G4 实例页面上找到差异的完整列表。
G4 实例大小还包括两种多 GPU 配置:g4dn.12xlarge
4 个 GPU 和 g4dn.metal 个 GPU。但是,如果您的用例是多 GPU 或多节点/分布式训练,您应该考虑使用 P3 实例。在一个多 GPU g4dn.12xlarge
实例上运行nvidia-smi topo --matrix
,您将看到 GPU 并没有通过高带宽 NVLink GPU 互连进行连接。P3 多 GPU 实例包括高带宽 NVLink 互连,可以加速多 GPU 训练。
Amazon EC2 P2:对于 HPC 工作负载具有成本效益,不再推荐用于纯 ML 工作负载
P2 实例让你接触到基于英伟达开普勒架构的英伟达 K80 GPUs。开普勒架构已经有几代历史了(开普勒- >麦克斯韦- >帕斯卡- >、伏打- >图灵),因此它们不是最快的 GPU。它们确实有一些特定的功能,如全精度(FP64)支持,这使它们对于依赖额外精度的高性能计算(HPC)工作负载来说具有吸引力和成本效益。P2 实例有 3 种不同的大小:p2.xlarge (1 个 GPU)、p2.8xlarge (8 个 GPU)、p2.16xlarge (16 个 GPU)。
NVIDIA K80 是一个有趣的 GPU。单个 NVIDIA K80 其实就是一块物理板上的两个 GPU,NVIDIA 称之为双 GPU 设计。这意味着,当您启动一个p2.xlarge
实例时,您只能在物理 K80 板上获得这两个 GPU 中的一个。同样,当你启动一个p2.8xlarge
时,你可以在 4 个 K80 GPU 上访问 8 个 GPU,而使用p2.16xlarge
时,你可以在 8 个 K80 GPU 上访问 16 个 GPU。在p2.xlarge
上运行nvidia-smi
,你看到的是 NVIDIA K80 板上的两个 GPU 中的一个,它有 12 GB 的 GPU 内存
P2 实例特征一目了然:
- GPU 一代 : NVIDIA Kelper
- 支持的精度类型 : FP64、FP32
- GPU 内存: 12 GB
- GPU 互连 : PCIe
那么,我甚至应该使用 P2 实例进行深度学习吗?
不,上面讨论过有更好的选择。在亚马逊 EC2 G4 和 G5 实例推出之前,P2 实例是推荐的具有成本效益的深度学习训练实例类型。自从 G4 实例推出以来,我推荐 G4 作为深度学习培训的首选性价比培训和原型 GPU 实例。P2 对于科学计算中的 HPC 工作负载来说仍然是经济高效的,但你会错过几个新功能,例如支持混合精度训练(张量核)和降低精度推断,这已经成为新一代的标准。
如果您在p2.16xlarge
GPU 实例上运行 nvidia-smi
,由于 NVIDIA K80 具有双 GPU 设计,您将看到 16 个 GPU,它们是 8 个 NVIDIA K80 GPUs 的一部分。这是您在 AWS 上的单个实例中可以获得的最大数量的 GPU。如果你运行nvidia-smi topo --matrix
,你会看到所有的 GPU 间通信都是通过 PCIe,不像 P3 多 GPU 实例使用更快的 NVLink。
Amazon EC2 G3:不再推荐仅用于 ML 工作负载
G3 实例让您访问基于 NVIDIA Maxwell 架构的 NVIDIA M60 GPUs。NVIDIA 将 M60 GPUs 称为虚拟工作站,并将其定位于专业图形。然而,对于 P3、G4、G5、G5g 实例的深度学习,G3 具有更强大和更具成本效益的选项,因此不是深度学习的推荐选项。我把它包括在这里只是为了一些历史和完整性。
G3 实例特征一览:
- GPU 一代:英伟达 Maxwell
- 支持的精度类型 : FP32
- GPU 内存 : 8 GB
- GPU 互连 : PCIe
应该考虑深度学习的 G3 实例吗?
在 Amazon EC2 G4 实例发布之前,单个 GPU G3 实例在开发、测试和原型制作方面非常经济。尽管 Maxwell 架构比在 P2 实例上发现的 NVIDIA K80 的开普勒架构更新,但对于深度学习,您仍然应该考虑 G3 之前的 P2 实例。你的选择顺序应该是 P3 > G4 > P2 > G3。
G3 实例有 4 种大小,g3s.xlarge
和g3.4xlarge
(2 个 GPU,不同系统配置)g3.8xlarge
(2 个 GPU)和g3.16xlarge
(4 个 GPU)。在一个g3s.xlarge
上运行nvidia-smi
,你会看到这个实例让你访问一个 8 GB GPU 内存的 NVIDIA M60 GPU。
AWS 上的其他机器学习实例选项
NVIDIA GPUs 无疑是深度学习的主要产品,但 AWS 上还有其他实例选项和加速器,可能是您训练和推理工作负载的更好选择。
- CPU :用于训练传统的 ML 模型,原型和推理部署
- 基于英特尔 Habana-Gaudi 的 DL1 实例:借助 8 x Gaudi 加速器,您可以将其用作 P3dn 和 P4d GPU 实例的替代方案,用于培训
- Amazon EC2 Trn1 实例:使用多达 16 个 AWS Trainium 芯片,您可以使用它作为 P3dn、P4d 和 DL1 实例的替代方案进行培训
- AWS 弹性推理:通过利用 EI 为您的 CPU 实例添加适量的 GPU 加速来节省推理工作负载的成本在这篇博文中讨论
- Amazon EC2 Inf1 实例:最多 16 个 AWS 推理芯片,每个芯片上有 4 个神经元内核,这是推理部署的一个强大且经济高效的选项,在这篇博文的中有更详细的讨论。
关于推理部署选项的详细讨论,请参考关于为推理选择正确的 AI 加速器的博文:
博文:深度学习推理 AI 加速器完全指南——GPU、AWS 推理和亚马逊弹性推理
为 ML 使用 GPU 实例时的成本优化技巧
您有几个不同的选项来优化您的训练和推理工作负载的成本。
斑点实例
即时定价使高性能 GPU 更加实惠,并允许您以比按需费率更低的折扣访问多余的 Amazon EC2 计算能力。要按实例和地区查看最新的价格列表,请访问 Spot Instance Advisor 。在某些情况下,您可以节省 90%以上的培训成本,但您的实例可能会被抢占,并且只需 2 分钟的通知就可以终止。您的训练脚本必须实现频繁的检查点操作,并且能够在 Spot 容量恢复后恢复训练。
亚马逊 SageMaker 管理培训
在开发阶段,你的大部分时间都花在原型制作、调整代码和在你最喜欢的编辑器或 IDE(显然是 VIM)中尝试不同的选项上——所有这些都不需要 GPU。你可以通过简单地分离你的开发和培训资源来节省成本,而亚马逊 SageMaker 将让你轻松做到这一点。使用 Amazon SageMaker Python SDK,您可以在您的笔记本电脑、台式机、EC2 实例或 SageMaker 笔记本实例上本地测试您的脚本。
当你准备好训练时,指定你想要训练的 GPU 实例类型,SageMaker 将提供实例,将数据集复制到实例,训练你的模型,将结果复制回亚马逊 S3,并拆除实例。您只需为培训的确切时间付费。Amazon SageMaker 还支持管理现场培训,以提供额外的便利和成本节约。
下面是我的指南:亚马逊 SageMaker 使用 Spot 实例的快速指南
通过 Amazon Elastic 推论使用所需数量的 GPU
通过利用 EI 为本文讨论的 CPU 实例添加适量的 GPU 加速来节省推理工作负载的成本: 深度学习推理的 AI 加速器完整指南——GPU、AWS 推理和亚马逊弹性推理
通过提高利用率来优化成本
- 通过启用混合精度训练,优化您的训练代码,以充分利用 P3、G4 和 G5 实例张量核。每个深度学习框架都有不同的做法,你必须参考特定框架的文档。
- 对 G4 和 G5 实例类型使用降低精度(INT8)推理来提高性能。NVIDIA 的 TensorRT 库提供了将单精度模型转换为 INT8 的 API,在其文档中提供了示例。
在 Amazon EC2 GPU 实例上使用什么软件?
下载你最喜欢的深度学习框架很容易,对吗?只需pip install XXX
或conda install XXX
或docker pull XXX
就可以了,对吗?不尽然,您从上游存储库安装的框架通常没有针对它们将运行的目标硬件进行优化。这些框架旨在支持各种不同的 CPU 和 GPU 类型,因此它们将支持最小公分母的功能和性能优化,这可能会导致 AWS GPU 实例的性能大幅下降。
为此,我强烈推荐使用 AWS 深度学习 AMIs 或者 AWS 深度学习容器(DLC) 来代替。AWS 在所有亚马逊 EC2 GPU 实例上对它们进行了资格认证和测试,它们包括针对网络、存储访问以及最新的 NVIDIA 和英特尔驱动程序和库的 AWS 优化。深度学习框架在上游和下游依赖于更高级别的调度器和编排器以及更低级别的基础设施服务。通过使用 AWS AMIs 和 AWS DLCs,您知道它已经过端到端测试,并保证为您提供最佳性能。
HPC 使用案例应考虑哪些 GPU?
高性能计算(HPC)是另一个科学领域,它依靠 GPU 来加速模拟、数据处理和可视化的计算。虽然深度学习训练可以在从 FP32(单精度)到 FP16(半精度)的较低精度算法以及 Bfloat16 和 TF32 等变体上进行,但 HPC 应用需要高达 FP64(双精度)的高精度算法。NVIDIA A100、V100 和 K80 GPUs 支持 FP64 precision,这些分别在 P4、P3 和 P2 提供。
所有 GPU 实例及其特性的完整且详细的电子表格
在今天的“ 中,我把这个放在一起,因为我已经找不到一个“ 的贡献了,我向你呈现一个 AWS 特性列表上的 GPU。我经常想知道特定的 GPU 上有多少内存,或者 GPU 是否支持特定的精度类型,或者该实例是否有 Intel、AMD 或 Graviton CPU 等。在我启动一个 GPU 实例之前。为了避免浏览各种网页和 NVIDIA 白皮书,我煞费苦心地将所有信息汇编成一个表格。你可以使用下面的图片,或者直接进入文章末尾嵌入的 markdown 表,这个表由你选择的 GitHub 托管。尽情享受吧!
GPU 特性一览
您是否喜欢以图形格式消费内容,我也为您做了介绍!下图显示了 AWS 上所有 GPU 实例的类型和大小。没有足够的空间容纳所有的功能,因此我仍然推荐电子表格。
你好。感谢阅读!
感谢您的阅读。如果你觉得这篇文章很有趣,可以考虑给它一点掌声,然后在 medium 上跟我学。也请查看我在媒体上的其他博客帖子,或者在 twitter ( @shshnkp )、 LinkedIn 上关注我,或者在下面留下评论。想让我写一个特定的机器学习主题吗?我很想收到你的来信!
选择正确的性能指标可以挽救新冠肺炎的生命
评估深度学习模型的性能,以使用相关指标检测新冠肺炎
冠状病毒病例的地理分布显示,它几乎影响了所有国家
最近宣布的疫情新冠肺炎震撼了世界上所有的医疗保健系统。它已经显示出的指数增长率,并且已经传播到 164 个国家。每个国家都处于指数曲线的不同点,都在采取预防措施和实施降低增长率的政策。
各国正在通过使用技术并在其基础设施中纳入大数据分析和实时监控来跟踪潜在的感染者和与他们有过互动的人,从而抗击疫情。这标志着这种技术首次被用于防止疫情病毒的传播。
虽然采取了这些预防措施,但病例数量仍在迅速增加。原因之一是测试套件不可用(或者使用了有故障的测试套件)。另一个原因是像意大利这样的国家缺少医疗专家,那里的病人流入量远远超过了他们的处理能力。为了克服这种情况,学者和研究人员正在研究使用深度学习来帮助专家诊断这种疾病。来自中国的一项研究显示了深度学习在 CT 扫描上的使用,“以便在病原测试之前提供临床诊断,从而为疾病控制节省关键时间”。与此同时,蒙特利尔大学的一名学者已经编译并开源了一个数据集,这样研究就可以实施并测试不同的算法(比如在这里的上完成的)。
左:新冠肺炎阳性 x 光片。右图:链球菌感染。(两者都被授权为 CC-NC-SA)
随着更多的数据变得可用,来自不同研究人员和机构的更健壮和准确的实现将变得可用。部署这样的系统可以减轻医生和医院面临的负担,特别是在亚洲和非洲的发展中国家。
根据所用数据的类型以及模型的参数和超参数,这些系统将具有不同的精确度。大多数数据科学家和人工智能专家使用准确性作为标准衡量标准,来决定他们的模型有多有效,以及它与其他模型相比如何排名。他们力争最准确的型号,但在现实生活中,我们会想要最有用的型号。
通过使用在特定阶段有用的指标,有多种方法来衡量模型的性能。为了解释它们,我将使用疾病在地理位置上的两个阶段(在这种情况下是新冠肺炎):当在一个地区发现感染并开始传播时,我们称之为感染出现和当病原体感染的人数超过该地区的治疗能力时,即感染饱和。但是在进入这些阶段之前,我想解释一下什么是混淆矩阵。混淆矩阵显示了实际标签与预测标签的组合计数。它有四个街区。让我们以狗和非狗的图像分类器为例。
- 真阳性:有多少张狗的图片被模型标记为“狗”
- 假阳性:有多少非狗的图像(如猫、树等)被模型标记为“狗”
- 假阴性:有多少张狗的图片被模型标记为“非狗”
- 真阴性:有多少张非狗图片被模特贴上了“非狗”的标签
我们开始吧。
1.感染出现
让我们假设我们是深度学习专家,在一个出现了前 20 个案例的国家。我们有一个训练集,包括从全球收集的 400 个健康人的 CT 扫描和 100 个感染者的 CT 扫描。我们已经训练了两个模型,模型 A 和模型 B,它们都具有不同的架构。我们有一个 100 个 CT 扫描的测试集(70 个健康,30 个受感染),并对它们的预测制作一个混淆矩阵,以观察实际标签与预测的计数:
为了评估两个模型的性能,最常用的指标是准确性,它决定了模型正确预测的案例百分比,即它正确分配了多少标签。它的公式是:
模型 A 的准确度为 80% ,而模型 B 的准确度为 76% 。使用模型 A 进行诊断似乎是非常明显的。但模型 A 的问题是,在假阴性的情况下(即诊断受感染的患者为健康),它宣布 18 名患者为健康并让他们出院,让感染传播得更快。模型 B 做得更好,它宣布 10 个被感染的病人是健康的,从而多诊断了 8 个病人。在这种情况下应该使用的指标是**召回。**据维基百科:
Recall(也称为 sensitivity)是实际检索到的相关实例总数的一部分。
它的基本意思是,它衡量模型捕捉尽可能多的正面案例的能力。为了计算召回率,我们使用:
A 型召回 40%,B 型召回 **67%!**这意味着我们应该使用模型 B,因为它可以正确诊断更多受感染的患者。
关于模型及其召回,有一些事情需要注意:
- 模型 B 预测 14 名健康患者被感染,模型 A 预测 2 名。这意味着你将会隔离 12 名健康的人。如果最终目标是减缓传播速度并且隔离资源可用,这可能是一个有效的选择。
- 通过降低根据模型的预测概率决定标签的阈值,可以提高召回率。这也可能导致更多健康的人被隔离。同样,如果目标如前所述,那么这是一个有效的选择。
2.感染饱和度:
现在,让我们假设我们在一个传染病已经蔓延全国的国家。医院和隔离区已经接近满负荷。在这种情况下,你是否正确地诊断某人被感染并不重要,因为流入的病人太多了,难以处理。如何选择谁接受治疗是一个单独的话题。但是有一件事是有害的:将健康人诊断为感染者。当感染者没有机会接受治疗时,没有人会想把资源用在健康人身上。
让我们使用模型 A 和模型 b 的混淆矩阵。为了强调影响,我将数字乘以 50:
假设所有的医院都满负荷运转,只有一家医院能容纳 500 人。这些是模型 A 对模型 B 的预测,可以通过沿着预测轴将各个类别相加得到:
模型 A 和模型 B 的每类预测数
虽然模型 B 似乎更优越,但如果我们计算有多少预测实际上是正确的概率,我们会发现其他东西。我们来计算一下有多少结果实际上是正确的概率。对于模型 A,700 个病例中有 600 个实际被感染,也就是说,如果我们从这 700 个病例中随机选择 1 个人,他或她被感染的几率为 85.7%。相反,对于模型 B,如果我们随机选择一个人,他/她有 58.8% 的几率被感染。为了比较这种影响,我们将得到 420 名真正的 A 型患者和 290 名真正的 b 型患者。使用 A 型,将增加 130 名患者得到所需的治疗。这一指标被称为精度,它是实际案例占预测案例总数的百分比。根据维基百科:
精度(也称为正预测值)是检索实例中相关实例的分数。
使用以下公式计算:
真实世界场景
疫情的饱和总会有一个起点(即浮现)。这是一条连续的指数曲线。因此,为了防止最终的危机,你会想要一种模型,它不仅能捕获尽可能多的病人,而且不会因为允许健康的人占据隔离区和医院病床而成为资源的负担。为了量化这样一个场景,需要一个能够结合精确度和召回率属性的度量。一个简单的平均值似乎是合适的,但是如果任何一个单独的指标较低,则没有惩罚。如果模型 1 的精度为 0,召回率为 100%,而模型 2 的精度和召回率都为 50%,则两个模型的平均值都为 50,这意味着它们的性能相似。有一个称为 F1 得分的指标,它将两者结合起来,如果其中一个指标较低,也会导致较低的值。它通过采用精度和召回的调和平均值来实现:
因此,模型 1 的 F1 值为 0,而模型 2 的 F1 值为 25%
让我们以模型 A 和模型 B 的混淆矩阵为例
两个模型的 F1-分数对于模型 A 是 27.3%,对于模型 B 是 31%。这可以通过模型 B 在识别受感染患者方面相对较好并且将健康人标记为受感染的比率也不太差的事实来观察。对于这两个任务,它比模型 A 更平衡。
还有一种 F1 分数的加权形式,称为 F-Beta
如果 0 < beta < 1, then more weightage is given to precision and if beta > 1,则给予回忆更多的权重。
注意:上面讨论的度量标准有缺陷,因为它们都依赖于测试集的数量和分布。而且有黑才能 100%召回。但是,如果模型经过适当的训练,并且测试集中有大量的示例与真实世界的分布相匹配,那么这些度量是可以依赖的。
结论
根据为不同情景计算的模型 A 和模型 B 的指标,最合理的方法是在紧急情况下使用模型 B,并随着越来越多的情况出现而倾向于模型 A。但是如果你因为某种原因只能使用一种模式,你可以把钱押在模式 b 上。
[1]:王等。艾儿,一种深度学习算法利用 CT 图像来筛查冠状病毒疾病(新冠肺炎)
[2]: 新冠肺炎 CT 扫描数据集由约瑟夫·保罗·寇恩收集。蒙特利尔大学 Mila 博士后研究员。
编者注: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
使用 Plotly 的 Choropleth Maps - 101
使用 Plotly 图形库绘制 Choropleth 图的介绍。
谢栋豪在 Unsplash 上的照片
我已经做了将近 5 年的数据分析师,但是在这段时间里,我主要使用商业智能软件来完成我所有的数据可视化任务。所以我在可视化方面的经验仅限于知道何时绘制条形图,何时绘制折线图。为了纠正这一点,我最近开始学习 matplotlib 和其他绘图和图形库。这是朝着那个方向的尝试。你可以用它来指导 choropleth 地图,或者 plotly,或者两者都有。希望这有所帮助。
Choropleth 地图是一种专题地图,其中的区域按照统计变量的比例进行阴影化或图案化(来自维基百科)。例如,这张地图显示了 2016 年肥胖成年人的比例。
Plotly 是一家总部位于加拿大的公司,开发分析和数据可视化工具。他们为 Python 创建了一个开源的科学图形库,我正在这里使用它。
为了这个任务,我正在寻找美国宗教信徒的数据(来源:theARDA.com)。该数据包含 1980 年、1990 年、2000 年和 2010 年不同宗教团体的县级信息。它还包括该年各县的人口,以及其他一些信息。
因此,让我们首先加载我们将需要的数据和库。
***#import libraries*** %matplotlib notebook
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots***#import raw data*** df = pd.read_excel(‘RCMSMGCY.xlsx’, dtype={“FIPSMERG”: str})
df.head()
现在,接下来的 3 个步骤涉及清理、过滤和汇总数据以供分析,因此如果您愿意,可以跳过这一步,直接进入 Choropleth 图。
数据清理
为了绘制美国县数据,我将使用 FIPS 代码,存储在 FIPSMERG 列中。FIPS 代码是唯一的 5 位数字代码,用于标识美国的县。从上面的数据快照可以看出,在前 5 行中,FIPSMERG 只有 4 位数。这意味着前导零丢失了。让我们用 lambda 函数添加它。
***#adding 0 to FIPS code***
df[‘FIPSMERG’] = df[‘FIPSMERG’].apply(lambda x: str(0)+str(x) if len(str(x))<5 else x)
现在,每个宗教团体都被归类到一个宗教传统和家庭中,由 RELTRAD & FAMILY 列表示。我添加了这些类别的名称和州名,以使数据更容易理解。
***#religious family name mapping (FAMILY)***
rel_fam = pd.read_csv(‘religious_family.csv’)
***#religious tradition name mapping (RELTRAD)***
rel_trad = pd.read_csv(‘religious_tradition.csv’)
***#merging the 2 dataframes on group Code to get the corresponding religious family name & religious tradition catgeory*** df = pd.merge(pd.merge(df, rel_fam, left_on=’FAMILY’, right_on=’FAMILY’, how=’left’), rel_trad, left_on=’RELTRAD’, right_on=’RELTRAD’, how=’left’)
print(‘Shape: ‘+str(df.shape))***#state names mapping (STATEAB)***
state_code = pd.read_csv(‘us_state_code_data.csv’)
***#merging the dataframes***
df = (pd.merge(df, state_code, left_on=’STATEAB’, right_on=’Postal
Code’, how=’inner’)).drop([‘Postal Code’], axis = 1)
过滤数据
对于分析的第一部分,我想看看 2010 年州和县一级信徒的百分比。为此,我需要人口和信徒的数量。
***#filtering data for only 2010***
df_2010 = df[df['YEAR']==2010]***#population at county level (year wise)***
pop_county = df[[‘YEAR’,’FIPSMERG’,’STATEAB’, ‘State Name’, ‘CNTYNM’, ‘TOTPOP’]].drop_duplicates().reset_index(drop=True)***#population at state level (year wise)***
pop_state = pop_county.groupby(by=[‘YEAR’,’STATEAB’, ‘State Name’]).agg({‘TOTPOP’:sum}).reset_index()
汇总数据
下一步是计算州和县一级信徒的百分比。使用 pandas groupby 函数和人口估计值,我创建了两个数据框架,一个汇总了州一级的数据,另一个汇总了县一级的数据。
***#creating state level data for %of adherents***
adh_state = df_2010.groupby(by=['STATEAB','State Name']).agg({'ADHERENT':sum}).reset_index()
adh_state = pd.merge(adh_state, pop_state[['YEAR','STATEAB', 'TOTPOP']], left_on='STATEAB', right_on='STATEAB', how='inner')
adh_state['PER_ADH'] = np.round(adh_state['ADHERENT']/adh_state['TOTPOP']*100,decimals=1)
州级汇总
***#creating county level data for %of adherents***
adh_county = df_2010.groupby(by=[‘FIPSMERG’, ‘CNTYNM’, ‘STATEAB’]).agg({‘ADHERENT’:sum}).reset_index()
adh_county = pd.merge(adh_county, pop_county[[‘FIPSMERG’, ‘TOTPOP’]], left_on=’FIPSMERG’, right_on=’FIPSMERG’, how=’inner’)
adh_county[‘PER_ADH’] = np.round(adh_county[‘ADHERENT’]/adh_county[‘TOTPOP’]*100,decimals=1)
县级汇总
Choropleth 地图
现在,我们已经准备好了州和县一级的数据框架,我们可以绘制 Choropleth 图。我正在使用来自 plotly.express 的函数 choropleth
choropleth 函数的 locations 参数与 locationmode 参数协同工作。对于美国州数据,locationmode = "USA-states "和 location 参数将采用州代码(AL、CA 等)。
***#shows %adherents at state level for the year 2010***
fig1 = px.choropleth(adh_state, locations=adh_state[‘STATEAB’], locationmode=”USA-states”,
color=’PER_ADH’,color_continuous_scale=”inferno”,
range_color=(0, 100),scope=”usa”,labels={‘PER_ADH’:’%Adherents’},hover_name=’State Name’,
hover_data={‘STATEAB’:False,’State Name’:False,’ADHERENT’:False,’TOTPOP’:False,’PER_ADH’:True})fig1.update_layout(margin={“r”:0,”t”:0,”l”:0,”b”:0})
fig1.show()
要绘制各县的数据,请使用参数 geojson,该参数采用面的要素集合。你可以在这里 找到我们这些县 *的收藏。*同样,将位置参数设置为 FIPS 代码。
with urlopen(‘[https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json'](https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json')) as response:
counties = json.load(response)***#plot %adherents at county level for the year 2010***
fig1 = px.choropleth(adh_county, geojson=counties, locations=’FIPSMERG’, color=’PER_ADH’,color_continuous_scale=”inferno”,
range_color=(0, 100),scope=”usa”,labels={‘PER_ADH’:’%Adherents’},hover_name=’CNTYNM’,
hover_data={‘FIPSMERG’:False,’CNTYNM’:False,’STATEAB’:False,’ADHERENT’:False,
‘TOTPOP’:False,’PER_ADH’:True})
fig1.update_layout(margin={“r”:0,”t”:0,”l”:0,”b”:0})
fig1.show()
现在我们知道了如何创建 Choropleth 地图,让我们试着给它们添加更多的功能。对于分析的第二部分,我想看看各州最大的宗教传统团体在 1980 年至 2010 年间是如何变化的。我将在我的 choropleth 地图上添加一个滑块,并使用它来改变年份。
首先,我需要确定每个州每年最大的传统群体。
df_ = df.copy()reltrad = df_.groupby([‘YEAR’,’STATEAB’,’State Name’,’RELTRADNM’]).agg({‘ADHERENT’:sum}).reset_index()
reltrad = pd.merge(reltrad, pop_state, left_on=[‘YEAR’,’STATEAB’,’State Name’], right_on=[‘YEAR’,’STATEAB’,’State Name’], how=’inner’)
reltrad[‘PER_ADH’] = (reltrad[‘ADHERENT’]/reltrad[‘TOTPOP’])*100**#adding Ranks and filtering Rank = 1**
reltrad[‘RANK’] = reltrad.groupby([‘YEAR’,’STATEAB’])[‘PER_ADH’].rank(ascending=False,method=’first’)
reltrad_top = reltrad[reltrad[‘RANK’]==1].reset_index(drop=True)
要添加滑块,请使用函数 choropleth 的参数 animation_frame。
n = [‘Evangelical Protestant ‘,’Mainline Protestant ‘,’Black Protestant ‘,’Catholic ‘,’Orthodox ‘,’Other ‘]
cdm = dict(zip(n, [‘#003f5c’,’#444e86',’#955196',’#dd5182',’#ff6e54',’#ffa600']))figz = px.choropleth(reltrad_top, locations = ‘STATEAB’, locationmode = “USA-states”, scope = “usa”,
color = ‘RELTRADNM’, hover_name = ‘State Name’,
color_discrete_map = cdm,
hover_data = {‘YEAR’:False,’STATEAB’:False,’State Name’:True,’RELTRADNM’:False,
‘ADHERENT’:False,’TOTPOP’:False,’PER_ADH’:False,’RANK’:False},
animation_frame=’YEAR’)figz.update_layout(margin={“r”:0,”t”:0,”l”:0,”b”:0})
figz[“layout”].pop(“updatemenus”)
figz.show()
我认为滑块在这里没有达到预期的目的。当你不得不在几年之间不停地移动时,比较这些州是很麻烦的。所以,我认为支线剧情会更好。
现在,因为一个 choropleth 没有参考笛卡尔坐标系,我们不能在子情节中使用 plotly.express’ Choropleth 函数。所以我将在这里使用 plotly.graph_objects 中的 choropleth 函数。
ndf = reltrad_top[[‘YEAR’,’STATEAB’,’RELTRADNM’,’State Name’]]
ndf = pd.merge(ndf, df_[[‘RELTRADNM’,’RELTRAD’]].drop_duplicates(), left_on=’RELTRADNM’, right_on=’RELTRADNM’, how=’left’)
ndf[‘text’] = ‘State: ‘ + ndf[‘State Name’] + ‘<br>’ + ‘Tradition: ‘+ ndf[‘RELTRADNM’]years = (ndf[‘YEAR’].sort_values(ascending=True).unique()).tolist()cscale = [‘#003f5c’,’#444e86',’#dd5182',’#ffa600',’#ff6e54',’#955196']
rows = 2
cols = 2
fig = make_subplots(rows=rows, cols=cols,
specs = [[{‘type’: ‘choropleth’} for c in np.arange(cols)] for r in np.arange(rows)],
subplot_titles = years, vertical_spacing=0.1, horizontal_spacing=0)for i, y in enumerate(years):
fig.add_trace(go.Choropleth(locations=ndf.STATEAB[ndf[‘YEAR’]==y],z = ndf.RELTRAD[ndf[‘YEAR’]==y],
locationmode = ‘USA-states’, zmin=1, zmax=6, colorscale=cscale,hoverinfo=’text’,
hovertext=ndf.text[ndf[‘YEAR’]==y]), row = i//cols+1, col = i%cols+1)fig.update_layout(title={‘text’:’Religious Tradition by Year’, ‘xanchor’: ‘center’,’x’:0.5},
**{‘geo’ + str(i) + ‘_scope’: ‘usa’ for i in [‘’] + np.arange(2,rows*cols+1).tolist()},
coloraxis_showscale=False, margin={“r”:10,”t”:70,”l”:10,”b”:0},
hoverlabel=dict(bgcolor=’#e6e6e6', font_size=12, font_family=”Rockwell”))fig.update_traces(showscale=False)
fig.show()
现在,我们有了。希望这个指南能在某些方面帮助你。你可以在这里找到数据和完整的源代码。你也可以跳到 Neptune.ai 的 Plotly Python 教程这里获得更多的提示和技巧。
PS:仅将此用作 Plotly 和 Choropleth 地图的指南。不要把数据看得太重。数据来源基于 ARDA 进行的调查,因此可能遗漏了较小的宗教团体,尤其是在 1980 年和 1990 年。
PPS:第一次写作,所以请原谅我的错误。欢迎建设性的反馈。提前感谢。
带叶的 Choropleth 图
2018 年西班牙各社区总出生率的可视化
choropleth 地图是一个专题地图,根据地图上显示的统计变量对区域进行着色。这种可视化对于使用顺序配色方案来表示某个区域中测量值的可变性非常有用(测量值越高,颜色越强)。在这篇文章中,我们将学习如何使用叶子创建 choropleth 地图,以可视化西班牙各社区的**(每 1000 名居民的出生率)**。
探索性数据分析和数据清理
探索性数据分析包括分析数据集的主要特征,通常采用可视化方法和汇总统计。目标是理解数据,发现模式和异常,并在我们执行进一步评估之前检查假设。
在这篇文章中,我们采用了一个数据集,其中包含了从 1975 年到 2018 年西班牙各社区的总出生率(每 1000 名居民的出生率)的信息。
数据集(选项—CSV separado por;)可从以下链接下载:
[## tasa Bruta de Natalidad for community autonom。无尾。自治社区。印度人…
自治社区土著居民基本情况表。无尾。自治社区。民主指数…
datos.gob.es](https://datos.gob.es/es/catalogo/ea0010587-tasa-bruta-de-natalidad-por-comunidad-autonoma-anual-comunidades-autonomas-indicadores-demograficos-basicos-identificador-api-1432)
探索性分析的第一步包括使用Pandas . read _ CSV函数将 csv 文件加载到 Pandas 数据框中,并使用 pandas 可视化前 5 行。data frame . head方法。我们跳过了文件开头的 5 行(skip prows = 5)和底部的 2 行( skipfooter=2 ),因为它们不包含有用的信息(只是关于正在显示的数据的注释)。
很容易观察到,数据帧的最后一列不包含有用的信息,应该删除。此外,我们必须用一个更具描述性的名称来修改第一列的名称。
在删除并重命名列之后,我们可以使用 pandas 来评估数据类型和缺失值。DataFrame.info 方法。
如上所示,数据集不包含空值,但是数据类型不是预期的类型。列 1975–2018 属于 object 类型,但它们包含数字数据。我们可以使用 熊猫将这些列转换成浮动。Series.astype 函数,将逗号前的句点替换为熊猫。Series.str.replace****
正如我们所观察到的,我们已经成功地将 1975–2018 列的数据类型从对象修改为浮点数。
现在!我们有一个干净的数据集来创建 choropleth 地图:)
带叶的 Choropleth 图
数据帧的修改
****leave是一个 python 库,允许你创建多种类型的传单地图。为了创建一个 choropleth 地图,叶子需要一个 Geo JSON 文件,包括该地区的地理空间数据。对于西班牙的 choropleth 地图,我们需要一个 Geo JSON 文件来定义所有社区的边界。您可以从以下链接下载该文件:
** [## code for America/click _ the _ hood
permalink dissolve GitHub 是 4000 多万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/codeforamerica/click_that_hood/blob/master/public/data/spain-communities.geojson)
为了成功绑定数据框和 json 文件,数据框中的社区名称必须与 json 文件中的社区名称完全匹配。因此,我们必须分析 json 文件中包含哪些名称,并相应地修改数据帧中的名称。
以下代码显示了我们如何在 json 文件中获取社区的名称:
json 文件中的名称
如上图所示, json.load() 方法返回一个 Python 字典。然后,我们遍历字典来获得社区的名称。
现在,我们用 json 文件的名称来修改数据帧的名称。请注意,我们已经创建了一个 json 文件名列表,其顺序与它们在数据框中出现的顺序相同。
修改的数据帧
现在!我们准备使用叶子来创建 choropleth 地图。
choropleth 图的生成
首先,我们创建一个叶子地图对象,以【40.416775,-3.703790】为中心(位置参数允许将地图居中在一个特定的位置)。我们还提供了一个初始缩放级别为 6 的来放大地图。尽管有初始缩放级别,但生成的地图是交互式的,这意味着您可以轻松地放大和缩小。最后,我们指定了瓷砖** ( 雄蕊水彩)。**
一旦创建了地图对象,我们就使用显示 choropleth 地图。choropleth() 法(我们也可以用叶。Choropleth() 函数)。该方法将数据帧中包含的数据与 json 文件的几何图形绑定。
下图描绘了 2018 年西班牙各社区的毛出生率(每 1000 名居民的出生人数)。
正如你所观察到的,北部地区的出生率较低。
梅利利亚是一个西班牙自治城市,位于非洲西北海岸,与摩洛哥接壤。这座城市的出生率是西班牙最高的。为了正确观察梅利利亚,我们需要放大。
地图的定制
在叶中有多个参数可以自定义 choropleth 贴图。以下参数是我们之前在可视化中使用的参数:
地图功能
- 位置 →地图经纬度。
- zoom_start →地图的初始缩放级别。
- 平铺 →地图平铺。
Choropleth 函数
- 地理数据→JSON 文件的名称。该文件必须位于工作目录中。
- 数据→ 包含数据的数据帧的名称。
- 列→ 用于生成 choropleth 图的列。
- 包含国家名称的 json 文件中的 key_on → Key。
- 填充颜色→ 可视化中使用的颜色方案。
- fill_opacity →区域填充不透明度,范围 0–1(默认为 0.6)。
- 线不透明度 → GeoJSON geopath 线不透明度,范围 0–1(默认为 1)。
- 图例 _ 名称 →图例标题(默认空字符串)。
- smooth_factor → 在每个缩放级别上将折线简化多少。
接下来,我详细解释一下我认为特别相关的三个参数:(1) tiles 、(2) zoom_start 、(3) fill_color 。
瓷砖
follow 包含多个内置 tilesets 来定制您的可视化。当创建一个地图对象时,我们可以很容易地用关键字 tiles 指定一个地图块。
我们可以使用叶创建多个瓷砖层。Tilelayer() 函数并将它们追加到地图中。为了在图层之间切换,我们添加了一个图层控件对象(leav。LayerControl() )到贴图如下。
平铺层控制
缩放开始
在叶,地图是交互式的,这意味着我们可以很容易地放大和缩小。然而,当生成地图对象时,我们可以使用参数( zoom_start )指定初始缩放级别。如下所示,我们使用三种不同的初始缩放级别创建一个地图对象:(1) 2,(2) 4,(3) 6。
初始缩放级别的修改
填充颜色
正确传达你的信息的一个关键点是为你的设计选择一个合适的配色方案。配色主要有三种类型:(1) 顺序、( 2) 发散、(3) 定性。
- 顺序配色方案从低到高进行逻辑排列,非常适合表示不包含关键中点或有序分类数据(低/中/高)的数字数据。
顺序配色方案
- 发散配色方案突出显示高于或低于有趣的中点值(如平均值)的值。发散方案用于可以被中点有意义地分割的数据。
发散配色方案
- 定性颜色方案用于名义分类数据(即数据没有内在排序)。类别之间的差异以不同的色调显示,亮度和饱和度相似。
定性配色方案
在我们的地图中,我们使用了顺序配色方案,因为我们想要表示一个没有有趣中点的数字变量(总出生率)。如下图所示,我们尝试了四种不同的调色板:(1)“YlGnBu”,(2)“BuPu”,(3)“OrRd”,(4)“RdPu”。
颜色的修改
正如你所观察到的,叶子为设计 choropleth 贴图提供了极大的灵活性。看一看文档,发现更多的参数来定制您的地图!🍁!
[## 叶子——叶子 0.10.1 文件
使用用于绘制地图的 Python 和 fleed . js 类制作漂亮的交互式地图。基地…
python-visualization.github.io](https://python-visualization.github.io/folium/modules.html)
信息标签
作为一个附加功能,我们使用follow . features . geojsontooltip()函数在悬停时显示社区的名称。我们提供想要显示的 GeoJson “属性”的标签作为输入(在本例中为名称】)。接下来,我们定义标签的样式,用 CSS 语言提供一个字符串。该语言描述了 HTML 元素应该如何显示。
在创建了 GeoJsonTooltip 对象之后,您可以将它传递给由 Choropleth 函数创建的 geojson 对象。
带有社区名称的标签
瞧!有标签的地图!
我鼓励你尝试用叶子来创建 choropleth 地图,记住在所有的地图中,我们已经可视化了2018年总出生率(每 100 名居民的出生率)。如果您想显示另一个年份,您只需将年份提供给叶的参数(列)。Choropleth()函数。
在以后的文章中,我将解释如何用其他库如 Plotly 或 Geoviews 创建地图。Sooo,继续读!
🍀阿曼达🍀**
使用 Python 中的 NLTK 和 Fuzzy Wuzzy 构建故障故事并提高可靠性
NLP 如何应用于航空或其他机器的部件可靠性分析
来源: @flyingraffi 上未刷
O 操作员或机械师一般在看到机器(大型卡车、飞机或轮船)出现问题时,会在存储这类信息的历史故障手册或系统中描述并报告(mro)。
在航空领域,每个故障都必须报告(由飞行员或机械师)。通常,这些故障是手工编写的,并存储在计算机系统中。但是作为人类,错误或描述失败的方式并不总是一致的,或者可能有打字错误,这使得很难联系或创建一个慢性失败史。
在离开之前,我们将定义什么是故障历史:
想象一条时间线(图 1 ),其中每个向下的箭头代表机器上的一个故障或问题,向上的箭头代表故障的解决方案,颜色代表相同的故障,但在词汇上它们是不同的。
随着时间的推移,会出现许多故障和解决方案,因此系统之间一定存在某种关系或模式,这可能是我们在通常的分类形式中所看不到的(故障通常按机器系统进行分组,但并不总是正确分类)。在这种情况下,对于红色故障,解决方案 X 比 y 更有效。
图 1:机器 A 的故障历史
所以我们有可以改善的情况:
- 能够对同一故障模式下的故障进行分组。
- 能够确定这种故障模式的最佳可能解决方案,从而保证更好的可靠性。
首先,我们可以定义一个问题,其中我们有 3 台机器,我们将只关注其中的 3 个系统,每个系统都有独立的故障(MF),有不同的纠正措施。我们可以在图 2 中看到:
图 2:明确的问题
故障模式(MF)是部件的确切故障。我们不会深入 MF 的分类,但它可以通过专业工程师或部件手册进行组装。这是一个重要的输入,我们必须集中调查。无论如何,如果我们没有它,我们可以通过观察系统之间的单词可重复性来建立它,然后在专家工程师的支持下,定义故障模式。
噪声消除
让我们继续图 2 中提出的问题:我们有一个数据库,其中包含图 2 中 3 台机器的 MF 信息,它们的 3 个系统是:
- 我们将寻找与我们的任何失败都不相关的词,以及机械师已经写下的词,例如,“今天我发现了问题 X ”,在本文中,只有“ X ”是重要的,其他所有我们必须消除的词,在文献中这种词被称为“停用词”。为此,我们将使用 Python NLTK 库 。
- 在清理完我们所有的文本后,最好对我们归类为错误的单词进行第二次检查,但这第二步最好依靠专家工程师,我们将使用一种称为 标记化 的技术来进行单词处理。
这个过程可以在图 3 中清楚地看到:
图 3:文本数据处理
因此,用于标记化和文字处理的 python 代码如下:
图 4:实际情况
在前面的代码中,我们将机械师编写的所有内容进行了分组,并使用 NLTK 来消除单词 stop ,即使如此,在图 5 的图表中,我们可以看到我们可以继续移除与 MF 无关的单词,例如, found 、、 form 等。
图 Python 之后的词频
我们将继续清理我们的代码,我们将消除所有我们知道不是失败的单词(我们可以咨询专家),我们还将消除所有的数字。
开始开发吧!
现在,看上面的图,我们可以使用 pandas 来编写我们真正的代码(上一个是解释标记化的前一个)。我们将使用图 5 中的图表,我们将清理我们的代码,我们将删除停用词,然后我们将使用fuzzywuzzy匹配库,然后我们将对结果进行注释。
fuzzywuzzy匹配是每个人与每个人,按系统名称和每个人与每个人进行匹配会很有趣,在此之后,留下最佳结果(我们可以将此作为后续步骤)。
图 6:结果
在图 6 中,我们得到了问题的结果。
‘故障名称 _ 清除’列是我们去除了所有噪声的故障。
‘故障名称 _ 原始’列是由机械师编写的列。
‘模式 _ 故障’是每个系统 MF 词汇表的最佳匹配故障模式。
最后,列‘匹配’匹配‘故障 _ 名称 _ 清除’和‘模式 _ 故障’的百分比。
在绿色中,我们可以看到我们拥有的巧合,例如,我们成功地将 62%归类为“问题 v break”(“id _ failure”= 11),这非常好!另一方面,红色表示仍有大量噪声可以消除
下一步!
大型机器上的系统可能非常多样,MF 甚至更多,因此进行交错匹配、系统之间的测试或同一系统的测试并最终留下所有匹配中的最佳匹配将非常有用(因为一个系统有其自己的 MF,但有时系统的选择可能是错误的)。了解更多关于【NLTK】以及查看同义词或反义词选项也是不错的。另一方面,与专家坐下来消除所有可能的噪音是很好的,噪音总是存在的。
我们仍然必须分析纠正措施,选择最佳解决方案,这样我们就可以得到 MF 排名及其最佳纠正措施。这可以通过查看对于相同的故障和机器,哪个动作花费最长时间而不再次失败来确定。我们已经迈出了创建失败案例的第一步,现在还缺少拥有完整工具的下一步。
自然语言处理中的分块:解码
它在文本处理中起什么作用
当我开始学习文本处理时,我坚持了很长时间的一个话题是组块。(我知道,很难相信🙆)通常,我们可以在网上找到许多文章,从容易到难的主题,但当谈到这个特定的主题时,我觉得没有一篇文章可以对组块有全面的理解,然而下面的一篇文章是我迄今为止研究的所有与该主题相关的文章或视频的合并。
所以下面是我对组块的理解。
那么,什么是组块?
组块是从非结构化文本中提取短语的过程,这意味着分析句子以识别成分(名词组、动词、动词组等)。)然而,它没有具体说明它们的内部结构,也没有说明它们在主句中的作用。
它工作在词性标注之上。它使用词性标签作为输入,并提供组块作为输出。
简而言之,组块意味着将单词/标记分组为组块
为什么需要?
我曾经认为,在我进一步了解这些主题之前,通常文本处理是通过简单地将句子分解成单词来完成的。所以简单的打断文字并没有太大的帮助。知道这个句子涉及到一个人、一个日期、一个地点等等是非常重要的…(不同实体)。所以他们单独是没有用的。
组块可以将句子分解成比单个单词更有用的短语,并产生有意义的结果。
当你想从文本中提取信息时,比如地点、人名,组块是非常重要的。(实体提取)
让我们从头开始理解它。
一个句子通常遵循由以下部分组成的层次结构。
句子→从句→短语→单词
词组组成短语,有五大类。
- 名词短语
- 动词短语
- 形容词短语
- 副词短语
- 介词短语
短语结构规则:
S -> NP VP
NP–> { Det N,Pro,PN}
VP -> V (NP) (PP) (Adv)
PP -> P NP
AP -> A (PP)
组块:短语被分成组块(来源:https://www.nltk.org)
在深入研究组块之前,先简要了解一下语法树和语法规则是有好处的。
正如我们所见,这里整个句子被分成两个不同的名词短语。
现在让我们用 python 实验来理解这个概念。
- 基于正则表达式的分块
基于正则表达式模式的分块器代码段
解析树(名词短语基于给定的正则表达式生成)
这里,我们介绍了一个语法。
其中 NP(名词短语)由
DT 组合而成?→一个或零个限定词
JJ* →零个或多个形容词
NN →名词
我们用 NLTK 定义的正则表达式解析器来解析这个语法。正如我们所看到的,整个句子 S 被分成几个组块,并用树状结构表示。基于定义的语法,创建内部树状结构。所以你可以定义你的语法,基于这个句子将被分块。
2。基于标签的训练分块器
我使用了“conll2000”语料库来训练 chunker。conll2000 语料库使用 IOB 标签定义组块。
它指定了块的开始和结束位置,以及它的类型。
POS 标签员可以接受这些 IOB 标签的培训
块标签使用 IOB 格式。
IOB : Inside,Outside,Beginning
标签前的 B 前缀表示,它是块的开始
I 前缀表示它在块内
O 标签表示令牌不属于任何块
#Here conll2000 corpus for training shallow parser modelnltk.download('conll2000')
from nltk.corpus import conll2000data= conll2000.chunked_sents()
train_data=data[:10900]
test_data=data[10900:]print(len(train_data),len(test_data))
print(train_data[1])
“conll2000”数据集的记录
tree2conlltags,conlltags2tree 是分块实用函数。
→**tree 2 conltags**
,获取三元组(每个令牌的单词、标签、块标签)。然后,这些元组最终用于训练标签器,并且它学习 POS 标签的 IOB 标签。
→ **conlltags2tree**
从这些令牌三元组生成解析树
Conlltags2tree()是 tree2conlltags()的反转。我们将使用这些函数训练我们的解析器
from nltk.chunk.util import tree2conlltags,conlltags2treewtc=tree2conlltags(train_data[1])
wtc
tree=conlltags2tree(wtc)
print(tree)
def conll_tag_chunks(chunk_sents):
tagged_sents = [tree2conlltags(tree) for tree in chunk_sents]
return [[(t, c) for (w, t, c) in sent] for sent in tagged_sents]def combined_tagger(train_data, taggers, backoff=None):
for tagger in taggers:
backoff = tagger(train_data, backoff=backoff)
return backoff
tagger 是什么?
它读取文本并给每个单词分配一个 POS 标签。(单词、标签)
Unigram tagger :确定 POS 时,只使用一个单词。(基于单词上下文的标记器)
UnigramTagger
、BigramTagger
和TrigramTagger
是继承自基类NGramTagger
的类,基类本身继承自ContextTagger
类,后者继承自SequentialBackoffTagger
类
我们现在将定义一个类NGramTagChunker
,它将接受带标签的句子作为训练输入,获取它们的**(单词、词性标签、组块标签)WTC 三元组**并训练一个带有UnigramTagger
的BigramTagger
作为补偿标签。
我们还将定义一个 parse()函数来对一个新句子执行浅层解析。
from nltk.tag import UnigramTagger, BigramTagger
from nltk.chunk import ChunkParserI#Define the chunker class
class NGramTagChunker(ChunkParserI):
def __init__(self,train_sentences,tagger_classes=[UnigramTagger,BigramTagger]):
train_sent_tags=conll_tag_chunks(train_sentences)
self.chunk_tagger=combined_tagger(train_sent_tags,tagger_classes)def parse(self,tagged_sentence):
if not tagged_sentence:
return None
pos_tags=[tag for word, tag in tagged_sentence]
chunk_pos_tags=self.chunk_tagger.tag(pos_tags)
chunk_tags=[chunk_tag for (pos_tag,chunk_tag) in chunk_pos_tags]
wpc_tags=[(word,pos_tag,chunk_tag) for ((word,pos_tag),chunk_tag) in zip(tagged_sentence,chunk_tags)]
return conlltags2tree(wpc_tags)#train chunker model
ntc=NGramTagChunker(train_data)#evaluate chunker model performance
print(ntc.evaluate(test_data))
现在,我们将利用这个模型对我们的新闻标题样本进行浅层解析和分块。
import pandas as pd
sentence='No new emoji may be released in 2021 due to COVID-19 pandemic word'
nltk_pos_tagged=nltk.pos_tag(sentence.split())
pd.DataFrame(nltk_pos_tagged,columns=['word','POS tag'])
chunk_tree=ntc.parse(nltk_pos_tagged)
print(chunk_tree)
语法树
chunk_tree
解析树
你也可以根据需要定义基于分类器的分块器。你可以在这里了解更多。
https://www . geeks forgeeks . org/NLP-classifier-based-chunking-set-1/?ref=rp
分块的另一个子过程叫做“分块”
我们创建一个令牌序列,它不包含在块中。所以这是寻找洞察力或背景。(我不在这一部分讨论)
感谢您的阅读。🙏
我试图最大程度地涵盖这个话题。欢迎建议。
作为荣誉奖,我要感谢迪潘然(DJ)萨卡尔。我一直跟着他的教程从零开始学 NLP。
页(page 的缩写)这是我的第一篇技术文章。希望随着学习的进步,我会继续写作。
参考
- https://youtu.be/b4nbE-pG_TM
- https://towards data science . com/a-从业者-指南-自然语言-处理-第一部分-处理-理解-文本-9f4abfd13e72
- https://www . geeks forgeeks . org/NLP-chunking-and-chinking-with-regex/
- https://www . geeks forgeeks . org/NLP-training-tagger-based-chunker-set-1/
流失预测:使用 Apache Spark 的 Sparkify 案例研究
音乐流媒体平台用户的大数据建模
Soure:AWS
简介:
当前席卷各行业的数字化浪潮导致了数据的爆炸,因为信息正通过各种方式被利用。这一点,加上社交媒体的出现,极大地鼓励了对人工智能的倾向和匹配。这种倾向建立在从海量数据中获得洞察力的能力上这些数据有时是实时获得的,同时为依赖这些数据的产品提供动力。Apache Hadoop 和 Spark 正在支持处理这种大数据的技术。一台计算机无法处理如此大规模的数据集,需要使用计算平台(如亚马逊网络服务(AWS)、微软 Azure、IBM Watson 和谷歌云)在线托管多台计算机。这就引出了本文的目标,它将应用大数据技术(Spark)并在 AWS 上运行,以分析 12 GB 大小的大数据。这里的数据集来自一个名为“Sparkify”的伪音乐流媒体服务的 Udacity。一些用户在作为付费用户使用该服务一段时间后,最终取消了他们的订阅。因此,目标是能够预测此类用户的流失,此处定义为当用户在“取消确认”页面中被跟踪时,使用用户使用平台时测量的不同特征。
业务和数据理解:
使用探索性数据分析(EDA),可以了解不同用户在决定取消订阅之前的行为。有些事实是惊人的,而有些是清晰的。
-
Length: 每个用户花在流媒体歌曲上的平均时间长度的合计长度。这表明没有取消用户具有稍高的歌曲平均长度。
-
点赞: 通过每个用户竖起大拇指的总计数来聚集点赞显示,与后来取消的用户相比,没有取消的用户更倾向于对歌曲竖起大拇指。
图一。两个用户组在其他事件中的点赞百分比
- 不喜欢: 按每个用户的 page -thumbs_down 总数合计不喜欢。与后来取消的用户相比,没有取消的用户不太喜欢歌曲。
图二。两组用户对其他事件的不喜欢百分比
- 新增好友: 按每个用户页面新增好友总数合计新增好友。与后来取消的用户相比,没有取消的用户更倾向于添加朋友(通过“添加朋友页面”与所有其他页面的百分比来衡量)。
5.***Playlist_adds:***按每个用户添加到播放列表的页面总数合计“Playlist _ adds”,显示与后来取消的用户相比,未取消的用户在“add_playlist”页面中出现的百分比更高。
-
降级: 按页面总计数累计降级-每个用户降级,已知未取消的用户在“降级”页面中出现的百分比比后来取消的用户低。
-
已升级: 根据每个用户的页面升级总数进行升级,已知未取消的用户比后来取消的用户具有更高的升级百分比。
-
NumSongs: 通过每个用户的歌曲总数来聚集歌曲,已知没有取消的用户与后来取消的用户相比具有更高的歌曲平均数。“NextSong”页面类似于播放长度不是 None 的有效播放,这应该是歌曲计数的同义词,如果包括在内,不会给模型增加额外的好处。
图三。流失用户更多地使用 GET 方法。
-
Method_PUT: 按每个用户使用 Put 方法的次数汇总 Put 方法。这是因为用户可能使用了不止一种方法,因此,将其设置为简单分类将不会清楚地反映此功能的效果
-
Method_GET: 按每个用户使用 Get 方法的次数来聚合 Get 方法。与 PUT 方法的逻辑相同
-
性别: 根据性别对用户进行分组,因为没有用户拥有一个以上的性别。因此,性别是一个纯粹的分类特征。
-
【状态 _307: 按每个用户使用状态 307 的次数汇总状态。这是因为某些用户使用了不止一种类型状态
-
状态 _200: 状态由每个用户使用状态的次数 200 来汇总。
-
【状态 _404: 通过每个用户使用状态 404 来流传送歌曲的次数来聚集状态。
15.***Level _ payed:***根据每个用户使用付费级别播放歌曲的次数来汇总级别。
图 4。流失用户更多地作为免费用户流入
16。Level_free:** 根据每个用户使用免费级别播放歌曲的次数来汇总状态。
- 注销: 汇总每个用户注销的总次数。这表明取消的用户经常被发现已经注销。
特征工程:
这显然是任何机器学习中最重要的部分之一,因为无论你在这里做什么,都将决定你的模型能够在多大程度上对用户行为进行分类。对于这个项目,从对数据集(EDA)的探索性分析中获得了一些见解,以了解就其对因变量(此处为标签列)的影响而言可能重复的特征。一些列具有不特定于用户的子特征,因此给定用户可能具有不止一个这样的特征。每个用户使用的级别就是一个例子。有时,可能会发现用户使用了免费级别,后来又使用了付费级别。因为,在这种情况下,它们被设计成计数、总和或平均值的集合,这取决于哪个更有意义。另一方面,有些列是纯分类列,如性别。对于这些,简单的编码(使用字符串索引器)就可以了。其他列是可以使用每个用户的总和来设计的某些变量,例如每个用户的收听时长。在所有情况下,都要避免特征的重复,或者用两个特征来解释相似的事件。显示了一个列有所有所需特征的数据框:
图 5:简要查看用于建模的特征数据框架
空元素:
因为有些用户没有某些特性的值,所以它们被捕获为 NULL。实际上,考虑到使用了聚合,这些空元素是零值。因此,对于所有列,这些空元素都被替换为零。
缩放:
数据集中所有要素的值的范围显示出相当大的差异。因此,对于某些机器学习模型,如逻辑回归,它们需要被缩放。为了找到最合适的定标器,通过绘制所有列的直方图来检查所有特征的分布。这表明偏离了正态分布,在一些特征中存在异常值。因此,选择了 MinMaxScaler 而不是标准 Scaler。
降维:
使用主成分分析(PCA),可以减少为预测而设计的特征,以提高模型的性能,同时加速预测。一项旨在了解不同要素在解释数据集中的差异方面所起作用的测试显示,前 10 个要素解释了数据集中 99.9%的差异。因此,预测中使用了前 10 个特征。
建模:
首先在 sparkify 数据集上尝试了三种不同的机器学习模型,看看哪一种能给出更好的预测。F1 分数被用作决定性指标。F1 定义为精确度和召回率的调和平均值。请记住,精度是对所有肯定预测的真实肯定的度量,而召回是对所有肯定标签的真实肯定预测的度量。因此,F1-score 用于捕捉模型在其预测中区分两个类别的程度,同时量化正电子的预测(此处定义为流失或标签== 1)。这与准确性相反,准确性将不会捕捉对将取消其订阅的用户做出的预测有多好。由于这是一个简单的二进制分类问题,即“流失”(标签 1)或“不流失”(标签 0 ),因此使用 multiclassclarticationevaluator 作为评估器。
将数据分成训练集和测试集:
数据集按照 0.75/0.25 的顺序分成两部分,训练集具有较大的份额。对于每种机器学习技术,训练集用于拟合/建立模型,而建立的模型应用于测试集以研究性能
基线模型:
构建了一个基线模型,用作衡量要在数据集上测试的其他机器学习模型的性能的起点。作为一个典型的二元分类问题,首先想到的模型是逻辑回归模型。使用大多数默认参数,除了定义的elasticNetParam
、maxIter
和regParam
:
regParam
= [0.3]
elasticNetParam
= [0.8]
maxIter
= [10]
逻辑回归分析的准确率和 F1 值分别为 82%和 72%。查看所有对流失用户的预测{1}可以发现,它未能成功预测测试集中的流失。
随机森林分类器:
Spark 的分类模块有一个随机森林分类器的实现,它是树和集成分类器的成员。作为被吹捧为分类任务中性能最好的算法之一,这也进行了实验。超级参数针对树的数量numTree
和树构建的最大深度进行了调整,以使用折叠数量numFold
等于 3 的交叉验证技术来尝试maxDepth
。。此参数网格设置为:
numTree
:【3,5,8,10,12,15】
maxDepth:
[4,8]
交叉验证后,表现最好的模型的numTree
为 8,而maxDepth
为 4。这一最佳表现用于在测试集上进行预测,结果显示F1-得分 为 0.73。该模型能够预测一个正确的流失用户。
使用 RandomForest 进行流失预测
决策树分类器:
假设我们有一个少于 200 行的数据框架可用于训练,我认为在预测用户流失时应用一个不太复杂的树技术是明智的,特别是使用RandomForestClassifier 的不太好的性能。 超参数针对树的数量maxBins
和maxDepth
进行了调整。使用的参数网格是:
maxBins
:[2,10,32]
maxDepth:
【1,2,3】
交叉验证的最佳表现模型是 3 个模型中的maxDepth
和 32 个模型中的maxBins
。当该模型应用于测试集时,性能显示出 0.86 (86%)的*,0.85 (85%)的*,0.4 (40%)的*。***
另一种机器学习算法 梯度推进树 也被测试,以查看是否可以在预测方面有所改进。与 决策树分类器 相比,这种技术显示出较高的召回率为 60%,但较低的 F1 得分为大约 82%。**
结论:
该项目利用了了解 Sparkify 音乐流媒体平台上用户行为的机会。利用RandomForestClassifierdecisiontreeclassifier等机器学习模型,可以预测订阅平台的用户可能的离开/取消。由于用户标签中存在巨大的不平衡,这两者对所用数据集的测试集进行预测的能力受到了阻碍。该数据集主要具有未取消的用户,比例为 173/52,只留下很少的数据集用于训练。这使得预测可能的流失更加困难。
然而, 决策树分类器 表现更好,其 F1 得分 为 0.76,而 随机森林分类器 的 F1 得分 为 0.73,基准模型使用 逻辑回归 显示 F1 进一步提高性能的步骤包括添加新功能,如注销和长度*从总和变为每个用户的平均值,然后使用 PCA 将功能减少到 10 个最重要的功能(解释了 99.9%以上的差异),性能在结果(指标)和训练数据集的速度上都有显著提高。这使得 决策树 的 F1 分数从 76%提高到了 85%左右,同时召回率从 20%提高到了 40%。另一个提高性能的尝试包括测试另一个机器学习模型——梯度提升树 ,它看到了大约 82%的 F1 分数和 60%的召回率。***
这种改进很好,使我的最佳模型对可能流失的预测达到 60%——考虑到数据集中的不平衡,这个值足够大,不能称之为猜测。
此外,由于这种不平衡,有人试图通过 SMOTE 采样来增加流失用户的数量,改编自 github 的代码。然而,这种尝试并没有产生结果的改善。
建议:
进一步的工作应该包括测试其他机器学习算法,如 NaiveBayes。此外,通过对标签进行加权来增加数据集的另一种尝试,以便给予流失用户比非
流失用户更高的权重,可以帮助减轻数据集中不平衡的影响。最后,仍然可以设计更多的特征,同时仍然利用 PCA 将特征的数量减少到最多 10 个。
参考文献:
*https://github . com/Angkirat/Smote-for-Spark/blob/master/python code . py。
源代码可以在我的 GitHub 资源库 这里
我欢迎所有读者的评论和改进建议。在引用时,可以自由使用本书的内容和成果。
连接:
LinkedIn:Chijioke Idoko
基于 Spark 的 AWS 集群 Sparkify 客户流失预测
我的 Udacity 数据科学家 Nanodgree 的顶点项目
https://up swell . org/2018/10/01/what-heck-is-a-spark-talk/
流失预测,即预测可能想要拒绝服务的客户,是机器学习最常见的商业应用之一。这对那些提供流媒体服务的公司尤为重要。在这个项目中,分析了一个虚构的音乐流媒体公司 Sparkify 的事件数据集。完整数据集(12GB)的一小部分(128MB)首先在 Jupyter Notebook 中使用 Spark 中的可扩展脚本进行本地分析,然后在 AWS EMR 集群上分析整个数据集。在这里找到代码。
数据准备
我们先来看一下数据。迷你数据集中有 286500 行和 18 列(大数据集中有 26259199 行)。列和前五行如下所示。
数据帧的前五行
让我们检查数据集中缺失的值。我们将从下表中找到缺失值的模式:在“艺术家”、“长度”和“歌曲”列中有相同数量的缺失值,在“名字”、“性别”、“姓氏”、“位置”、“注册”和“用户代理”列中有相同数量的缺失值。
数据帧中缺少值
如果我们仔细观察“userId ”,它的“firstName”丢失了,我们会发现这些“userId”实际上是空字符串(在 bid 数据中是 Id 为 1261737 的用户),正好有 8346 条记录(在 bid 数据中有 778479 行),我决定将其视为丢失的值并删除。这可能是某个只访问过 Sparkify 网站而没有注册的人。
UserId 中的空字符串
缺失用户 Id 的数量
删除“有问题的”userId 后,还剩下 255 个独立用户(对于大数据,这个数字是 22277)。
让我们进一步挖掘剩下的缺失值。由于数据是事件数据,这意味着单个用户的每一个操作都被记录下来。我假设“艺术家”列中那些丢失的值可能与用户的某些操作(访问的页面)有关联,这就是为什么我检查与丢失的“艺术家”相关联的访问的“页面”,并与完整数据中的“页面”进行比较,发现:“丢失的艺术家”与除“下一首歌”之外的所有其他页面相结合,这意味着只有当用户点击“下一首歌”时,才会记录“艺术家”(歌曲的演唱者)信息。
“页面”列中的类别
如果我删除那些“空”艺术家行,数据集中就不会再有丢失的值,干净数据集中的唯一用户数仍然是 255。
在处理了丢失的值之后,我将时间戳转换为纪元日期,并简化了两个分类列,只从“location”列中提取“states”信息,从“userAgent”列中提取用户使用的平台(标记为“agent”)。
数据清理步骤至此完成,我们开始探索数据,找出更多的信息。由于最终目的是预测流失,我们需要先对流失的用户进行标注(降级也是用同样的方法标注的)。我使用“取消确认”事件来定义流失:那些访问了“取消确认”页面的流失用户被标记为“1”,没有访问的被标记为“0”。类似地,谁访问页面“降级”至少一次被标记为“1”,谁没有被标记为“0”。现在,包含 278154 行和列的数据集已经准备好进行一些探索性分析了。让我们比较一下被搅动的用户和留下来的用户。
已清理数据框中的列名和行号
流失和滞留用户的数量、性别、级别和降级情况
在小数据集中,有 52 个被搅动的用户和 173 个停留的用户(对于大数据,这些数字分别是 5003 和 17274),两组中男性略多于女性(下图)。在留下来的用户中,似乎有更多的人至少降级过一次他们的账户(下图)。
“级别”列有两个值“免费”和“付费”。有些用户可能不止一次更改了他们的级别。为了检查“级别”在流失和停留用户之间有什么不同,创建了一个“valid_level”列来记录最新的用户级别。如下图所示,入住用户中付费用户较多。
注册天数、每天的歌曲数量和每次会话的歌曲数量
显然,停留的用户比流失的用户注册了更多的天数,并且停留的用户平均每天播放的歌曲都比流失的用户多。
每个会话的每日平均项目和平均会话持续时间
如下图所示,停留用户的每日平均项目数略高于流失用户。
停留用户(标记为 0)和搅动用户(标记为 1)之间的平均每日项目数
停留用户的平均会话持续时间也比频繁使用的用户长。
流失(标记为 1)和停留(标记为 0)用户之间的平均会话持续时间
用户活动分析
为了分析搅动和停留用户之间的用户活动有何不同,计算了每个用户的“竖起大拇指”、“添加到播放列表”、“添加朋友”、“滚动广告”和“拇指向下”的日平均数。之所以选择这些功能,是因为它们是访问量最大的页面(见下表)。
因此,与不变的用户相比,不变的用户添加的朋友更少,竖起大拇指的次数更少,每天添加到播放列表中的歌曲也更少。而与留下来的用户相比,被搅动的用户每天给出更多的“否定”和滚动更多的广告。
两组用户的平台和位置
用户使用的平台(表中标记为“代理”)如下图所示。六种试剂的搅拌速率似乎不同。这意味着用户使用 Sparkify 服务的平台可能会影响用户流失。
类似地,不同州的搅拌率似乎也在变化(见下图)。
特征工程
在拟合任何模型之前,组装以下列以创建用于建模的最终数据集 df_model 。
响应变量
标签:1 表示搅动,0 表示未搅动
解释变量(分类变量)
降级:1 表示降级,0 表示未降级
性别:M 代表男性,F 代表女性
有效级别:免费或付费
代理:五类用户使用的平台(windows、macintosh、iPhone、iPad 和兼容)
解释变量(数值)
registered_days:通过“ts”(动作的时间戳)的最大值减去“registration”时间戳来计算,并转换为天数
avg_daily_song:每天平均收听的歌曲
songs_per_session:每次会话收听的平均歌曲数
avg_session:平均会话时长
朋友:用户每天添加的朋友数量
竖起大拇指:用户每天竖起大拇指的次数
否决:用户每天否决的次数
add_playlist:“添加到播放列表”操作的每日次数
滚动广告:每日“滚动广告”的次数
分类变量“gender”、“valid_level”和“agent”首先使用 StringIndexer 转换为索引。
# creating indexs for the categorical columns
indexers = [StringIndexer(inputCol=column, outputCol=column+"_index").fit(df_model) for column in ['gender','valid_level','agent'] ]pipeline = Pipeline(stages=indexers)
df_r = pipeline.fit(df_model).transform(df_model)
df_model = df_r.drop('gender','valid_level','agent')
数字变量首先使用 VectorAssembler 组装成一个向量,然后使用 StandardScaler 进行缩放。
# assembeling numeric features to create a vector
cols=['registered_days','friends','thumbs_ups','thumbs_downs','add_playlist','roll_advert',\
'daily_song','session_song','session_duration']assembler = VectorAssembler(inputCols=cols,outputCol="features")# use the transform method to transform df
df_model = assembler.transform(df_model)# standardize numeric feature vector
standardscaler=StandardScaler().setInputCol("features").setOutputCol("Scaled_features")
df_model = standardscaler.fit(df_model).transform(df_model)
最后,所有的分类和数字特征被组合并再次转换成一个向量。
cols=['Scaled_features','downgraded','gender_index','valid_level_index','agent_index']
assembler = VectorAssembler(inputCols=cols,outputCol='exp_features')# use the transform method to transform df
df_model = assembler.transform(df_model)
建模
由于目标是预测二元结果(1 表示流失,0 表示没有流失),因此选择了逻辑回归、随机森林和梯度提升树分类器来拟合数据集。计算 F1 评分和 AUC 作为评价指标。因为我们的训练数据是不平衡的(搅动的用户比停留的用户少)。从公司的角度来看,错误地识别出一个将要流失的用户会付出更大的代价。在这种情况下,F1-score 是一个比准确性更好的指标,因为它提供了对错误分类情况的更好的衡量(有关更多信息,请单击此处)。另一方面,AUC 为我们提供了一个关于模型在可分性方面有多好的视角,换句话说,区分 1(流失)和 0(停留)。
数据集首先被分成 80%的训练数据和 20%的测试集。
rest, validation = df_model.randomSplit([0.8, 0.2], seed=42)
逻辑回归模型
在整个数据集中,停留用户比流失用户多,在我们的训练集中,流失用户的数量是 42,只占总用户的 22%左右。为了解决这一不平衡问题并获得更好的预测结果,在模型中引入了类权重值。
如下构建具有加权特征的逻辑回归模型,并使用 BinaryClassificationEvaluator 评估该模型。
# Initialize logistic regression object
lr = LogisticRegression(labelCol="label", featuresCol="exp_features",weightCol="classWeights",maxIter=10)# fit the model on training set
model = lr.fit(rest)# Score the training and testing dataset using fitted model for evaluation purposes
predict_rest = model.transform(rest)
predict_val = model.transform(validation)# Evaluating the LR model using BinaryClassificationEvaluator
evaluator = BinaryClassificationEvaluator(rawPredictionCol="rawPrediction",labelCol="label")#F1 score
f1_score_evaluator = MulticlassClassificationEvaluator(metricName='f1')
f1_score_rest = f1_score_evaluator.evaluate(predict_rest.select(col('label'), col('prediction')))
f1_score_val = f1_score_evaluator.evaluate(predict_val.select(col('label'), col('prediction')))#AUC
auc_evaluator = BinaryClassificationEvaluator()
roc_value_rest = auc_evaluator.evaluate(predict_rest, {auc_evaluator.metricName: "areaUnderROC"})
roc_value_val = auc_evaluator.evaluate(predict_val, {auc_evaluator.metricName: "areaUnderROC"})
逻辑回归模型的得分如下:
The F1 score on the train set is 74.38%
The F1 score on the test set is 73.10%
The areaUnderROC on the train set is 79.43%
The areaUnderROC on the test set is 76.25%
特征重要性如下所示。该功能注册天数、每次会话收听的平均歌曲数和平均会话持续时间与客户流失呈负相关,而每次会话收听的平均歌曲数和降级行为与客户流失呈正相关。换句话说,每天听更多歌曲并且至少降级一次的用户更有可能流失。然而,一次会话持续的时间越长,每次会话听的歌曲越多,用户流失的可能性就越小。
一个人每天听的歌曲越多,他就越有可能流失,这听起来有点不合理。为了得出一个安全的结论,我将包含更多的样本来再次拟合模型。这将是以后的工作。
随机森林模型
以类似的方式,随机森林模型被拟合到训练数据中,参考原始代码这里。衡量标准如下:
The F1 score on the train set is 90.21%
The F1 score on the test set is 70.31%
The areaUnderROC on the train set is 98.21%
The areaUnderROC on the test set is 80.00%
明显存在过拟合的问题。F1 和 AUC 分数对于训练集来说都非常高,而在测试集中较差。特征重要性分析显示:除了注册天数和每天收听的歌曲,每天添加的朋友数量、竖起大拇指和竖起大拇指是关于流失预测的最重要的特征。作为未来的工作,我将在大数据集上再次拟合这个模型,看看添加样本是否会解决过度拟合问题。
梯度增强树模型
GBT 模型显示了更严重的过度拟合问题。改进的建议将与前面提到的相同。首先在大数据集上尝试,如果必要的话做更精细的特征工程或者尝试其他方法。
The F1 score on the train set is 99.47%
The F1 score on the test set is 68.04%
The areaUnderROC on the train set is 100.00%
The areaUnderROC on the test set is 64.58%
超参数调整和交叉验证
根据所有三个模型的 F1 和 AUC 分数,我决定选择逻辑回归模型来做进一步的超参数调整和 3 重交叉验证。
# logistic regression model parameters tuning
lrparamGrid = ParamGridBuilder() \
.addGrid(lr.elasticNetParam,[0.0, 0.1, 0.5]) \
.addGrid(lr.regParam,[0.0, 0.05, 0.1]) \
.build()
然而,除了在训练集上模型性能的明显改善。测试组的 F1 和 AUC 分数都较低。对于过度拟合的情况,参数调整有点棘手,交叉验证在这种情况下无助于提高模型性能,检查这里的链接可能会对这个问题有所了解。
The F1 score on the train set is 87.73%
The F1 score on the test set is 72.74%
The areaUnderROC on the train set is 91.27%
The areaUnderROC on the test set is 78.33%
参数调整和交叉验证后,逻辑回归的特征重要性显示出与之前不同的模式。注册日是最有希望的客户流失指标(服务提供商公司可能对该信息不感兴趣)。此外,竖起大拇指、添加好友、竖起大拇指和滚动广告的数量是最重要的功能。
结论
在这个项目中,流失预测是基于一个音乐流媒体提供商的事件数据集进行的。这基本上是一个二元分类问题。在加载和清理数据之后,我进行了一些探索性的分析,并对特征工程的下一步提供了见解。总共选择了 13 个解释性特征,并将逻辑回归、随机森林和梯度增强树模型分别拟合到训练数据集。
在小数据集上,模型性能对于逻辑回归是最好的,在测试集上 F1 得分为 73.10。其他两个模型都遭受过拟合。超参数调整和交叉验证对解决过度拟合没有太大帮助,可能是因为样本数量较少。由于时间和预算的限制,最终的模型没有在大数据集上进行测试。然而,完全可扩展的流程为使用 Spark on Cloud 解决大数据上的客户流失预测问题带来了曙光。
讨论
特征工程
如何选择合适的解释特征是这项任务中最关键的步骤之一。在 EDA 之后,我简单地包含了我创建的所有特性。我想创建更多的功能,然而,进一步的计算被有限的计算能力所拖累。在这个步骤中,特征工程中有一些技术(例如 Spark ML 提供的 ChiSqSelector)可能会有所帮助。“state”列有 58 个不同的值(大数据为 100)。我试图使用 StringIndexer 将它们转换成索引值,并将其包含到解释性特性中。然而,不可能构建索引超过 maxBins (= 32)的随机森林/GBTs 模型,这就是为什么我必须排除这个特性。如果可以使用该特性的虚拟变量,问题就可以避免。遗憾的是,我没有时间了,没能做进一步的实验。
计算能力
我花在这个项目上的大部分时间都是在“等待”结果。非常令人沮丧的是,由于集群内存不足,由于阶段错误,我不得不停下来一遍又一遍地从头运行代码。为了解决这个问题,我必须将我的代码分成两部分(一部分用于建模,另一部分用于绘图),并分别运行它们。我必须减少我创造的解释变量的数量。遗憾的是,我只成功地在 AWS 集群上运行了一次大数据集的简单版本代码(这里指的是代码)并且不得不停止,因为它花费了太多的时间和成本。不幸的是,构建模型在大数据集上的分数并不令人满意。但是,代码的最后版本(Github repo 中的 Sparkify_visualization 和 Sparkify_modeling)应该是完全可扩展的。如果要在大数据上再次运行最新的代码,那么模型在大数据集上的性能应该得到提高。
测试选择性抽样方法
因为训练数据集不平衡,带有“0”标签的行比“1”多,所以我想试试随机选择与“1”行数相同的“0”行是否会提高模型性能。由于时间的限制,这将只是未来的工作。
ps:一个额外的提示可能非常有用,在关键点上执行“缓存”来加速程序。
欢迎任何讨论!请通过 LinkedIn 和 Github 联系我
使用神经网络和 ML 模型的流失预测
这个故事是我上传到 Kaggle 上的一个笔记本的演练。最初,它只使用机器学习模型,从那以后,我添加了几个基本的神经网络模型。许多媒体博客和 Kaggle 上的笔记本广泛报道了客户流失预测主题,然而,很少有使用神经网络的。将神经网络应用于结构化数据本身在文献中很少涉及。我通过 Coursera 上的 deeplearning.ai 专门化和 Keras 的 Tensorflow 文档学习了神经网络。
简介
当客户或订户停止与公司或服务做生意时,就会发生客户流失或客户流失。客户流失是一个关键指标,因为保留现有客户比获得新客户更具成本效益,因为它节省了销售和营销成本。留住客户更具成本效益,因为你已经赢得了现有客户的信任和忠诚。
有多种方法可以计算这一指标,因为流失率可能代表客户流失总数、客户流失占公司客户总数的百分比、经常性业务流失的价值或经常性价值流失的百分比。但是,在这个数据集中,它被定义为每个客户的二进制变量,计算费率不是目的。因此,这里的目标是确定和量化影响流失率的因素。
这是一个相当简单的初级项目,变数较少。对于神经网络来说,这不是一个有用的应用,因为训练样本的数量相对较少,但是使用它很容易理解神经网络。
探索性数据分析
这里跳过了数据清理步骤。丢失的值只是微小的,在总费用栏中找到,因此被删除。由于多重共线性,没有要素被删除,因为只存在少数几个要素。
熟悉自己的功能。
数据分析的第一步是熟悉数据变量、特征和目标。该数据集包含 20 个特征和一个目标变量。客户 ID 特性是一个字符串标识,因此对预测没有用处。
恰好有 3 个类的分类特征的唯一值。
在分类特征中,有些特征是二进制的,有些正好有 3 个唯一值。在检查时,注意到只有合同和互联网服务在分类特征中具有不同数量的唯一值。在 Kaggle 的一些笔记本中,“无互联网服务”类可以被指定为“否”。然而,虚拟变量似乎是更好的编码选择,因为在前一种情况下,尽管有互联网服务,但客户选择不选择服务,将会丢失数据。在特征的数量较大的情况下,将考虑标签编码或映射,因为然后一个热编码将变成大的稀疏矩阵。
检查数据中提供的这些特征的分布是很重要的,以检查特征值是否公平分布。下面的函数用于绘制分布图。
def srt_dist(df=df,cols=cat_feats):
fig, axes = plt.subplots(8, 2,squeeze=True)
axes = axes.flatten()
for i, j **in** zip(cols, axes):
(df[i].value_counts()*100.0 /len(df)).plot.pie(autopct='**%.1f%%**',figsize =(10,37), fontsize =15,ax=j )
j.yaxis.label.set_size(15)
srt_dist()
一些分类特征的分布
据观察,很少是老年人,只有 30%有家属,只有 10%没有电话服务。因此,从这些变量中得出的相关性是值得怀疑的。
合同任期。
自然,月合同客户的任期低于两年合同客户。
目标变量的分布。
因此,目标变量有 73 %的“无流失”实例。机器学习模型将因此而被扭曲,并且在更多“流失”的情况下,在看不见的数据上不会表现得那么好。
抵消这种类不平衡的一种方法是使用分层交叉验证,这种方法使实例的折叠具有统一的比例。
sns.pairplot(df,vars = ['tenure','MonthlyCharges','TotalCharges'], hue="Churn")
从顶行中间图可以观察到,租期较短和月费较高的客户倾向于流失,几乎呈线性关系。可以注意到,如总费用分布所示,神经网络模型也表明总费用较低的客户会流失。但是,这可能是因为随着时间的推移,任期越长的客户总费用越多。
也正如你在下面看到的;逐月合同和光纤 obtic 互联网对客户流失概率有着巨大的影响。
cat_feats=['gender', 'SeniorCitizen', 'Partner', 'Dependents','PhoneService','MultipleLines', 'InternetService', 'OnlineSecurity', 'OnlineBackup','DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies','Contract', 'PaperlessBilling', 'PaymentMethod'] # As formed in notebook in upper blocks
fig,axes = plt.subplots(16)
axes = axes.flatten()
for i, j in zip(cat_feats, axes):
sortd = df.groupby([i])['Churn'].median().sort_values(ascending=False)
j=sns.catplot(x=i,
y='Churn',
data=df,
kind='bar')
j.set_ylabels("Churn Probability")
根据不同的分类特征,此处显示了合同的流失概率。
据观察,对于高度相关的功能,如无合作伙伴或依赖关系、无技术支持、按月合同等,客户流失的可能性很高。
系统模型化
数据集根据范围为 0 到 1 的最小最大缩放器进行缩放,训练集是根据分配的前 3993 个观察值。
以下函数用于分层交叉验证。
def stratified_cv(X, y, clf_class, shuffle=True, **kwargs):
stratified_k_fold = StratifiedKFold().split(X,y)
y_pred = y.copy()
for ii, jj in stratified_k_fold:
Xtrain, Xtest = X.iloc[ii], X.iloc[jj]
ytrain = y.iloc[ii]
clf = clf_class(**kwargs)
clf.fit(X_train,y_train)
y_pred.iloc[jj] = clf.predict(Xtest)
return y_predprint('Gradient Boosting Classifier:\n {}\n'.format(
metrics.classification_report(y, stratified_cv(X, y, ensemble.GradientBoostingClassifier))))
print('Support vector machine(SVM):\n {}\n'.format(
metrics.classification_report(y, stratified_cv(X, y, svm.SVC))))
print('Random Forest Classifier:\n {}\n'.format(
metrics.classification_report(y, stratified_cv(X, y, ensemble.RandomForestClassifier))))
print('K Nearest Neighbor Classifier:\n {}\n'.format(
metrics.classification_report(y, stratified_cv(X, y, neighbors.KNeighborsClassifier,n_neighbors=11))))
print('Logistic Regression:\n {}\n'.format(
metrics.classification_report(y, stratified_cv(X, y, linear_model.LogisticRegression))))
print('XGBoost Classifier:\n {}\n'.format(
metrics.classification_report(y, stratified_cv(X, y, XGBClassifier))))Code used for classification reports of ML model
模型的加权平均 F1 分数。
最大似然模型的超参数调整
对于随机森林,调整每棵树的估计器数量和最大特征数:
# Tuning Random Forest
from sklearn.ensemble import RandomForestClassifier
# Create param grid.
param_rf=[{'n_estimators' : list(range(10,150,15)),
'max_features' : list(range(6,32,5))}]
# Create grid search object
clf = RandomizedSearchCV(RandomForestClassifier(), param_distributions = param_rf, n_iter=50, cv = 5, refit=True,verbose=1, n_jobs=-1,)
# Fit on data
best_clf = clf.fit(X, y)
print(best_clf.best_params_)
best_clf.best_score_
Out[]:
{'n_estimators': 130, 'max_features': 6}
0.78967497404260
对于逻辑回归,调整逆正则化参数 C:
# Tuning Logistic Regression
from sklearn.linear_model import LogisticRegression
param_grid = [
{'penalty' : ['l1', 'l2'],
'C' : np.logspace(-5, 5, 20),
'solver' : ['liblinear'] }]
clf = RandomizedSearchCV(LogisticRegression(), param_distributions = param_grid, n_iter=20, cv = 5, refit=True,verbose=1, n_jobs=-1,)# Fit on databest_clf = clf.fit(X, y)
print(best_clf.best_params_)
best_clf.best_score_
Out[]:
{'solver': 'liblinear', 'penalty': 'l2', 'C': 8858.667904100832}
0.8043221203472578
神经网络
对于神经网络,两种类型的建模,预制估计和 Keras 序列模型都被使用。此外,我遇到的大多数参考资料是关于卷积神经网络和图像分类的超调预制估计器。Keras 模型对学习速率和层数进行了超调。超参数调整模型显示了类似的性能,因为数据集比通常的神经网络应用程序小。
为了使博客简洁,这里只展示了 Keras 模型。
使用一个 64–8–1 密集分层模型,学习率衰减,批量大小为 32。还使用了每一层的 L2 正则化和去除。
*# Model 1*
nn_model = Sequential()
nn_model.add(Dense(64,kernel_regularizer=tf.keras.regularizers.l2(0.001), input_dim=46, activation='relu' ))
nn_model.add(Dropout(rate=0.2))
nn_model.add(Dense(8,kernel_regularizer=tf.keras.regularizers.l2(0.001),activation='relu'))
nn_model.add(Dropout(rate=0.1))
nn_model.add(Dense(1, activation='sigmoid'))
lr_schedule = tf.keras.optimizers.schedules.InverseTimeDecay( 0.001,
decay_steps=(X_train.shape[0]/32)*50,
decay_rate=1,
staircase=False)
#This time decay means for every 50 epochs the learning rate will be half of 0.001 value
def get_optimizer():
return tf.keras.optimizers.Adam(lr_schedule)
def get_callbacks():
return [tf.keras.callbacks.EarlyStopping(monitor='val_accuracy',patience=70,restore_best_weights=True)]nn_model.compile(loss = "binary_crossentropy",
optimizer = get_optimizer(),
metrics=['accuracy'])
history = nn_model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=150, batch_size=32, callbacks=get_callbacks(),verbose=0)
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
根据被训练的时期的训练和准确性。
因此,由于批量较小,该模型在 20 个时期左右收敛得更快。测试集上的模型准确率为 80.72%。
估价
yprednn=nn_model.predict(X_test)
yprednn=yprednn.round()
print('Neural Network:**\n** **{}\n**'.format(
metrics.classification_report(yprednn, y_test)))
nn_conf_matrix=metrics.confusion_matrix(yprednn,y_test)
conf_mat_nn = pd.DataFrame(nn_conf_matrix,
columns=["Predicted NO", "Predicted YES"],
index=["Actual NO", "Actual YES"])
print(conf_mat_nn)
Out[]:
Neural Network:
precision recall f1-score support
0.0 0.92 0.84 0.87 2443
1.0 0.51 0.69 0.58 596 accuracy 0.81 3039
macro avg 0.71 0.76 0.73 3039
weighted avg 0.84 0.81 0.82 3039
Confusion Matrix :
Predicted NO Predicted YES
Actual NO 2042 401
Actual YES 185 411
使用 Keras 进行超参数调谐
Keras tuner 的文档对此做了很好的解释。这里隐藏单元的数量、隐藏层中神经元的数量、学习率和辍学率都是超调的。
根据吴恩达的课程,学习率是最重要的,其次是动量贝塔、小批量和隐藏单元的数量。
from tensorflow import keras
from tensorflow.keras import layers
from kerastuner.tuners import RandomSearch
import IPython
import kerastuner as kt
def build_model(hp):
inputs = tf.keras.Input(46,)
x = inputs
for i **in** range(hp.Int('num_layers', 1,3)):
x = tf.keras.layers.Dense(units=hp.Int('units_' + str(i),32,256, step=32, default=64),
kernel_regularizer=tf.keras.regularizers.l2(0.001))(x)
x = tf.keras.layers.BatchNormalization()(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Dense(
hp.Int('hidden_size', 4,64, step=4, default=8),
kernel_regularizer=tf.keras.regularizers.l2(0.001),
activation='relu')(x)
x = tf.keras.layers.Dropout(
hp.Float('dropout', 0, 0.5, step=0.1, default=0.5))(x)
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)model = tf.keras.Model(inputs, outputs)
model.compile(
optimizer=tf.keras.optimizers.Adam(
hp.Float('learning_rate', 1e-3,1e-1, sampling='log')),
loss="binary_crossentropy",
metrics=['accuracy'])
return model
tuner = RandomSearch(
build_model,
objective='val_accuracy',
max_trials=10,
executions_per_trial=1)
batch_size=32
tuner.search(X_train, y_train,
epochs=100,batch_size=batch_size,
validation_data=(X_test,y_test),
callbacks= [tf.keras.callbacks.EarlyStopping(monitor='val_accuracy', patience=40,restore_best_weights=True)],verbose=False)
best_hp = tuner.get_best_hyperparameters()[0]
best_hp.values
Out[]:
{'num_layers': 3,
'units_0': 96,
'hidden_size': 52,
'dropout': 0.5,
'learning_rate': 0.0075386035028952945,
'units_1': 64,
'units_2': 96}
超调建议采用 5 层模型,前三个单元如输出所示。
超调模型的历史图输出。
该图显示了一个复杂的模型可以有很大的差异。该模型的性能类似,但由于复杂性而略低。
超调对于小数据集可能没有大数据集有用。然而,在 Keras 文档的过拟合和欠拟合部分中,得出的结论是,随着神经网络的容量“变小”,精度会提高。因此,由于这是一个类似大小的数据集,我们也可以使用最多具有 64 到 128 个隐藏单元的 3 个隐藏层的网络。
测试不同的批量大小:小于 32 和大于 32 都会导致性能稍低。因此,此代码块可以跳过,但可以在笔记本中找到。具有 10e3 观测值的中小型数据集通常使用的批量大小为 8、32、64、128。8 的倍数使得批处理大小适合内存,并且运行更快。
批量大小为 1024 需要更长的时间来收敛,超过 100 个历元。
模型性能
混淆矩阵和 ROC 曲线给出了真正的正负准确性的意义,然而在不平衡的数据集中,正是精确-召回曲线给出了准确性的意义。在这个数据集中,负实例比正实例多,因此精确召回曲线显示了真实的性能。
ROC 可能过于乐观,因为如果模型正确地预测了负面实例,但在正面实例上失败,而精确召回曲线是基于正面实例的,则 ROC 会更乐观。
混淆矩阵值显示为百分比,因为神经网络模型使用一个集合验证,而不是 CV。XGBoost 性能与随机森林非常相似,因此这里没有显示。
1.随机森林性能
rf_conf_matrix = metrics.confusion_matrix(y, stratified_cv(X, y, ensemble.RandomForestClassifier,n_estimators=113))
conf_mat_rf = pd.DataFrame(rf_conf_matrix,
columns=["Predicted NO", "Predicted YES"],
index=["Actual NO", "Actual YES"])
print((conf_mat_rf/7032)*100)
cv=StratifiedKFold(n_splits=6)
classifier=RandomForestClassifier(n_estimators=113)
from sklearn.metrics import auc
from sklearn.metrics import plot_roc_curve
from sklearn.model_selection import StratifiedKFold
tprs=[]
aucs=[]
mean_fpr=np.linspace(0,1,100)
fig,ax=plt.subplots()
for i,(train,test) **in** enumerate(cv.split(X,y)):
classifier.fit(X.iloc[train],y.iloc[train])
viz=plot_roc_curve(classifier,X.iloc[test],y.iloc[test],name='ROC fold **{}**'.format(i),alpha=0.3,lw=1,ax=ax)
interp_tpr = np.interp(mean_fpr, viz.fpr, viz.tpr)
interp_tpr[0] = 0.0
tprs.append(interp_tpr)
aucs.append(viz.roc_auc)
ax.plot([0, 1], [0, 1], linestyle='--', lw=2, color='r',
label='Chance', alpha=.8)
mean_tpr = np.mean(tprs, axis=0)
mean_tpr[-1] = 1.0
mean_auc = auc(mean_fpr, mean_tpr)
std_auc = np.std(aucs)
ax.plot(mean_fpr, mean_tpr, color='b',label=r'Mean ROC (AUC = **%0.2f** $\pm$ **%0.2f**)' % (mean_auc, std_auc),lw=2, alpha=.8)
std_tpr = np.std(tprs, axis=0)
tprs_upper = np.minimum(mean_tpr + std_tpr, 1)
tprs_lower = np.maximum(mean_tpr - std_tpr, 0)
ax.fill_between(mean_fpr, tprs_lower, tprs_upper, color='grey', alpha=.2,label=r'$\pm$ 1 std. dev.')
ax.set(xlim=[-0.05, 1.05], ylim=[-0.05, 1.05],
title="Receiver operating characteristic example")
ax.legend(loc="lower right")
plt.show()
# Precision Recall # break code blockrfmodel=RandomForestClassifier(n_estimators= 130, max_features= 6,n_jobs=-1)
rfmodel.fit(X_train,y_train)
lg_probs = rfmodel.predict_proba(X_test)
lg_probs=lg_probs[:,1]
yhat = rfmodel.predict(X_test)
lr_precision, lr_recall, _ = precision_recall_curve(y_test,lg_probs)
lr_f1, lr_auc = f1_score(y_test, yhat), auc(lr_recall, lr_precision)
*# summarize scores*
print('RF: f1=**%.3f** auc=**%.3f**' % (lr_f1, lr_auc))
*# plot the precision-recall curves*
no_skill = len(y_test[y_test==1]) / len(y_test)
pyplot.plot([0, 1], [no_skill, no_skill], linestyle='--', label='No Skill')
pyplot.plot(lr_recall, lr_precision, marker='.', label='RF')
*# axis labels*
pyplot.xlabel('Recall')
pyplot.ylabel('Precision')
*# show the legend*
pyplot.legend()
*# show the plot*
pyplot.show()Out[]:
Confusion Matrix:
Predicted NO Predicted YES
Actual NO 70.036974 3.384528
Actual YES 6.143345 20.435154
Precision- Recall:
RF: f1=0.543 auc=0.603
2.逻辑回归
代码与上面类似。
Confusion matrix:
Predicted NO Predicted YES
Actual NO 65.799204 7.622298
Actual YES 12.044937 14.533561
Precision-Recall AUC:
Logistic: f1=0.543 auc=0.640
3.神经网络模型性能
Confusion Matrix:
Predicted NO Predicted YES
Actual NO 67.193156 13.195130
Actual YES 6.087529 13.524186
ROC:
No Skill: ROC AUC=0.500
Neural Network: ROC AUC=0.832
Precision-Recall:
Neural Network: f1=0.584 auc=0.628
我们可以看到,Random Forest 和 XGBoost 是最准确的模型,逻辑回归概括得最好,并且同样准确地预测了流失和不流失这两个类别。因此,根据精确召回曲线,逻辑回归具有最佳性能。神经网络在精确召回率上也比 RF 和 XGBoost 表现得更好。
因此,如果在看不见的数据中存在更多积极的实例,即流失标签,则逻辑回归将预测得更好。
4.特征重要性
1)根据逻辑回归的特征重要性。
weights = pd.Series(lgmodel.coef_[0],index=X.columns.values)
print (weights.sort_values(ascending = False)[:20].plot(kind='bar'))
逻辑回归模型使用的正负权重
2)根据随机森林的特征重要性
rf = ensemble.RandomForestClassifier(n_estimators=130,max_features=6, n_jobs=-1)
rf.fit(X, y)
feature_importance = rf.feature_importances_
feat_importances = pd.Series(rf.feature_importances_, index=X.columns)
feat_importances = feat_importances.nlargest(19)
feat_importances.plot(kind='barh' , figsize=(10,10))
3)神经网络特征重要性
因为 Keras 在文档中没有提供特性重要性特性,所以我演示了两种方法。参考是一个堆栈流答案。
from keras.wrappers.scikit_learn import KerasClassifier, KerasRegressor
import eli5
from eli5.sklearn import PermutationImportance
def base_model():
nn_model = Sequential() nn_model.add(Dense(64,kernel_regularizer=tf.keras.regularizers.l2(0.001),
input_dim=46, activation='relu' ))
nn_model.add(Dropout(rate=0.2))
nn_model.add(Dense(8,kernel_regularizer=tf.keras.regularizers.l2(0.001),
activation='relu'))
nn_model.add(Dropout(rate=0.1))
nn_model.add(Dense(1, activation='sigmoid'))
lr_schedule = tf.keras.optimizers.schedules.InverseTimeDecay(
0.001,
decay_steps=(X_train.shape[0]/32)*50,
decay_rate=1,
staircase=False)
def get_optimizer():
return tf.keras.optimizers.Adam(lr_schedule)
def get_callbacks():
return [
tf.keras.callbacks.EarlyStopping(monitor='val_accuracy',patience=70,restore_best_weights=True)]
nn_model.compile(loss = "binary_crossentropy",
optimizer = get_optimizer(),
metrics=['accuracy'])
return nn_model
my_model = KerasRegressor(build_fn=base_model)
my_model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=150, batch_size=32,
callbacks= get_callbacks(),verbose=0)
perm = PermutationImportance(my_model, random_state=1).fit(X[:500].values,y[:500].values,verbose=False)
eli5.show_weights(perm, feature_names = X.columns.tolist())
import shap
from tensorflow.keras import Sequential
*# load JS visualization code to notebook*
shap.initjs()
*# explain the model's predictions using SHAP*
*# (same syntax works for LightGBM, CatBoost, scikit-learn and spark models)*
explainer = shap.DeepExplainer(nn_model,data=X[:500].values)
shap_values = explainer.shap_values(X.values)
*# visualize the first prediction's explanation (use matplotlib=True to avoid Javascript)*
*#shap.force_plot(explainer.expected_value, shap_values[0,:], X.iloc[0,:])*
shap.summary_plot(shap_values, X, plot_type="bar")
结论
- 可以看出,总费用是最重要的功能,理所当然。如果客户发现服务昂贵或负担不起,他们会“流失”的首要原因。
- 任期也很重要,那些长期使用这项服务或签有长期合同的客户一般来说更便宜,不太可能流失。有趣的是观察到任期被列为更重要的神经网络模型。
- 正如在 EDA 中观察到的,大多数月合同的客户更有可能流失。可以假设,原因是由于客户的个人原因,对长期合同有所保留,或每月合同导致单位时间成本较高。
- 正如 EDA 中所看到的,其他重要的功能是在线安全、电子支付方式、光纤互联网服务、技术支持。
- 不重要的功能是性别、家属、伴侣、流媒体电视、备份和设备保护。
优惠和提高流失率:
- 折扣:由于最重要的特征是总费用,其次是月费用,通过建模确定的潜在客户应在下个月或几个月的合同中获得巨大折扣。这涵盖了 80 %的搅动原因。对于这个模型,应该最小化假阴性率或者最大化召回率,以便将折扣发送给最大的潜在顾客。
- 新合同:应执行六个月或四个月的合同。这将鼓励想要短期合同的保留客户,并增加他们在服务中的任期,从而使他们不太可能流失。
- 在线安全:这项服务应该得到更多的推广,并根据公司的成本在试用期内免费提供。没有在线安全的客户更有可能流失,因此此优惠可以与第一个提到的优惠相结合,折扣只能在此基础上提供。
- 光纤:光纤互联网的成本很高,因此要么向适当的目标受众推广,要么采用更好的技术来降低这项服务的成本。最终,市场研究团队必须决定这项服务的盈亏平衡点,它的利润是否与它造成的客户流失一样多。
另一种量化报价的方法是使用手动生成的特征及其对模型的影响。
参考
- 预测客户流失的随机森林与神经网络,Abhinav Sagar,Medium,https://towards data science . com/random-Forest-vs-Neural-Networks-for-Predicting-Customer-Churn-691666 c 7431 e
- 电信客户流失预测, Pavan Raj ,https://www . ka ggle . com/pavanraj 159/telecom-Customer-Churn-Prediction
- 电信客户流失预测,Melda Dede,https://www . ka ggle . com/meldadede/turn-Prediction-of-Telco-Customers
- 使用基本神经网络预测流失,Laurier Mantel,https://www . ka ggle . com/Laurier Mantel/using-basic-neural-networks-to-predict-churn
- 如何在 Python 中使用 ROC 曲线和精度召回曲线进行分类,Jason Brownlee,https://machine learning mastery . com/ROC-Curves-and-Precision-Recall-Curves-for-class ification-in-Python/
- Tensorflow、Keras、sklearn 文档
- 神经网络的特征重要性,StackOverFlow,https://stack overflow . com/questions/45361559/feature-importance-chart-in-Neural-Network-using-keras-in-python #:~:text = It % 20 most % 20 easily % 20 works % 20 with,using % 20it % 20is % 20very %直截了当。& text=At%20the%2