TowardsDataScience 2023 博客中文翻译(七十二)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

选择正确的数据库模型,让你的数据摆脱电子表格

原文:towardsdatascience.com/choose-the-right-database-model-free-your-data-from-spreadsheets-8d1129626b42

你已经超越了 Excel:如何选择关系型、文档型或图数据库,并为未来做好准备

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

·发表于数据科学前沿 ·阅读时间 16 分钟·2023 年 5 月 8 日

打开一个空白的电子表格时,无尽的行和列似乎成为了无限可能性的画布。然而,许多数据工程师和其他数字知识工作者越来越将电子表格中交错的灰线视为限制——具有讽刺意味地像是监狱牢房的横竖金属栏杆!

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

诚然,为了使“电子表格监狱”的视觉隐喻生效,电子表格必须旋转 90°。但一旦你看到这种诡异的相似性,就不可能忘记。 照片插图由作者提供。 照片 WWW PROD 提供,来自 Unsplash

“电子表格监狱”发生在决定将数据存储在电子表格中,使组织在高效实现目标时陷入瓶颈。这主要是因为电子表格的单元格(无意玩笑)在查询和管理方面受到限制:例如,今天单元格K18可能表示某个物品的数量,但如果明天添加了一行和一列,K18可能完全指代其他内容。

对于较大的项目,“电子表格困境”还发生在存储的数据量超过电子表格的最大大小时(Google Sheets 为 1000 万个单元格;Microsoft Excel 为 1,048,576 行和 16,384 列)。在一个极端的例子中,一份财务数据清单在一名员工发现其大小与一个满员的 Excel 电子表格完全相同时被发现是伪造的,这一欺骗行为现在使公司的耻辱首席执行官面临数十年的实际监禁

对于那些未参与犯罪活动的我们来说,电子表格困境的风险不那么字面化,但我们不当使用电子表格往往是成本高昂且繁琐的。考虑以下问题:

  • 打开一个曾被认为是可靠和高效的信息查找方式的电子表格是否现在变成了令人恐惧的源头?

  • 您的组织是否有工作人员每天花费多个小时回答那些答案要么 (1) 深埋在一个电子表格中,要么 (2) 分散在多个电子表格中?

  • 是否有重要的分析问题让您的数据透视表专家也感到困惑?类似地,您的单元格公式是否脆弱,频繁出现错误或需要多个手动步骤来计算?

  • 重要信息是否被 relegated 到单元格值之外,例如作为电子表格中的“注释”或“评论”?

如果您对所有这些问题的回答都是“否”,祝贺您!当数据管理不会阻碍您实现目标时,您就不会陷入电子表格困境。没有必要用过于强大的数据库解决方案替换那些有效的方案。

然而,如果您对这些问题中的任何一个回答为“是”,那不幸的是,这表明您正陷入电子表格困境。好消息是,通过采用许多更适合您需求的数据库技术,您可以摆脱困境。

接下来,我将通过介绍三种数据库模型范式来帮助缩小选择范围,同时提供一个特别适合转换为该模型的电子表格示例。在查看这些描述时,您可能希望保留一个最具问题的电子表格副本,以尝试诊断导致您陷入电子表格困境的问题,并确定哪种数据库模型是最佳解药。

这些描述是针对一些具备技术知识的项目经理和高管编写的,旨在帮助他们更好地理解数据需求。数据专业人士也可以参考这篇文章,以找到倡导采用更强大数据库技术所需的语言。

关系型数据库

关系数据库由“表”组成,这些表在概念上类似于电子表格的二维网格,但每行数据通过“键”在表之间相互连接。“主键”是一个数据点,它表示其他表中的一个单独的行,而“外键”存储来自其他表的哪一行(或多行)与给定表中的行具有特定关系。

SQL —— 或称为“结构化查询语言” —— 常用于与存储在关系数据库中的数据进行交互,包括提问涉及多个表的数据。尽管一开始可能听起来令人畏惧,SQL 实际上相对容易学习且成本低廉(网上有许多免费的 SQL 课程,许多社区学院也提供 SQL 的入门课程)。

值得注意的是,自 1986 年 美国国家标准协会首次认可 SQL 的一种形式 以来,SQL 就成为了一个公共资源,这种形式可以在公司、政府机构和学术机构之间互换使用。如果你的目标是导入 开放数据 或导出内部数据用于学术研究,那么拥有一个可以通过 SQL 访问的关系模型数据库可以说是最安全的选择。

由于关系数据库和 SQL 的普及,确定最合适的解决方案可能会让人感到不知所措。像 Oracle 和 SQL Server 这样的最受欢迎的数据库通常对于只是从电子表格迁移且尚未运行完整应用程序的大多数组织来说,显得过于强大且成本过高。更合适的是包括 PostgreSQL 这样的免费和开源选项,它不在功能上打折扣,以及 SQLite 这样的轻量级选项,便于部署。

如果关系数据库模型很吸引人,但设置和学习 SQL 的投资成本过高,Airtable 是一个很好的折中方案。Airtable 的电子表格类似的图形界面不需要查询语言,但对于与从终端用户的角度来看,类似于关系数据库模型的功能进行交互效果很好。

电子表格诊断

如果你的数据目前存储在电子表格中,如果该电子表格有大量的“重复子行”,你应该考虑迁移到关系数据库。

这个电子表格跟踪了课后项目的参与者。注意到 Parent 是一个“重复子行”,特别是 Parent 2 单元格的值要么完全填充,要么完全为空。这使得电子表格的末端有一种“长条奶酪”的外观,行在末端呈现出磨损的效果。 示例数据由作者提供。

比如,你运营一个课后项目。你的电子表格中的每一行代表一个孩子的数据(姓名、年级、过敏信息等),并且你有子行代表每个孩子父母的数据(姓名、联系信息等)。多个孩子很可能有相同的父母,但如果你需要更新父母的联系信息,你必须确保捕捉到父母出现的每一子行。

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

这个简单的实体关系图,使用 乌鸦脚符号,展示了课后项目数据库中每个孩子都有一个姓名、年级、一份过敏清单(包括一个空列表)和一个或多个相关父母。每个父母都有姓名、电子邮件地址、电话号码和一个或多个相关学生。 图示由作者提供。

关系数据库通过将“子行”转换为一个引用存储在不同“父”表中的数据的“外键”单元来解决这个问题。如果你更新一个父表的信息,你会同时更新与该父表相关的每个子表的信息。由于不需要在重复数据上进行批量更新,使用关系数据模型时,数据完整性的维护变得容易得多。

课后项目的数据迁移到 Airtable 中。虽然从技术上讲这不是一个 SQL 数据库,但 Airtable 在保持熟悉的电子表格界面的同时,拥抱了关系数据范式。 示例数据由作者提供。

当然,大多数课后项目都是由志愿者和其他没有时间和技能来管理完整 SQL 数据库的人运营的。Airtable是这个使用场景的一个极好的无代码替代方案,额外的好处是它有内置工具如“表单”,允许引导数据输入。

面向文档的数据库

面向文档的数据库,或称为“文档存储”,非常适合处理结构松散的数据。如果关系数据库的范式是由“行”和“列”组成的“表”,那么文档导向数据库的范式是由“键”和“值”对组成的“文档”的“集合”。例如,Length (meters)的键可能与18的值配对,或者Locations的键可能与一个由["Portland", "Omaha", "San Antonio", "Savannah"]组成的列表配对。此外,值甚至可以是一个称为“子文档”的全新键值对集合。假设每个文档都有一个唯一的 ID,那么一个值也可以指向另一个文档,从而模拟 SQL 数据库的关系性。

对数字数据术语不熟悉的人可能会对“文档”一词感到困惑。我必须承认,当我第一次了解文档导向数据库时,我天真地认为这些系统是为了存储一堆 PDF 和 Word 文档(我后来发现这类技术的术语是“文档管理系统”)。然而,在这个上下文中,“文档”实际上指的是轻量级且流行的JSON格式,设计时考虑到人类和计算机都相对容易读取或写入。而关系数据库中的每一行必须符合表的模式(也就是“列”),而 JSON 文档在理论上可以具有任何所需的键值对。

由于这种灵活性,文档导向的数据库被认为是“适应性强”的数据库模型。随着时间的推移,当你发现有关所收集信息的更多数据时,你可以添加新的字段,而不会弄乱任何具有不同键值对的旧记录。此外,由于相同的键可以与不同的类型值关联,这种数据库模型非常适合数据的异质性。

利用这种异质性的一种实际方法是创建“占位符数据”,如一个文本字符串,稍后将扩展为子文档。它还使区分不同类型的空白数据变得更容易,例如通过(1)排除一个键来表示缺失数据,或者(2)将值设置为nullNone,如果没有要观察的数据,例如完全在线运营的组织的地理坐标,或一个还未到驾驶年龄的小孩的驾照号码。

文档存储非常适合那些处于探索阶段的组织,特别是转向文档导向数据库是改善 HealthCare.gov 网站命运的一部分,使其能够不断适应来自多个联邦和州机构的不断变化的数据输入。不过,如果数据库的工程师缺乏规范性并且在添加字段时不小心,数据库随着时间的推移可能会变得越来越混乱和难以管理。

最受欢迎的文档导向数据库解决方案是 MongoDB。凭借几乎但不完全被认为是开源的许可证协议,他们的免费 512MB 云层本地托管的社区版可以满足许多从电子表格过渡的用户的数据需求,而无需直接支出。此外,MongoDB 查询的基础(有时称为“MQL”)和其他数据导航工具如 Compass 可以在线免费学习。然而,与 SQL 不同,“MQL”实际上不是标准化的查询语言,而是一组特定语言的驱动程序和 API。这意味着虽然很难找到了解 MQL 的人才,但对于已经在特定编程语言(如 Python、JavaScript 等)中工作的人来说,学习 MQL 并实现 MongoDB 仍然很容易。

电子表格诊断

如果您的数据目前存储在电子表格中,且有大量单元格完全为空或数据过于拥挤(超过一半的电子表格是一个很好的经验法则),您应该考虑转向文档导向的数据库。您还需要注意那些仅用于输入少量数据的“临时列”或“杂项”备注列。

这个电子表格存储了本地社区目录的信息。注意到使用了|符号在单元格内创建了“迷你电子表格”。此外,电子表格中还有许多空单元格,使得整个电子表格呈现出一种“瑞士奶酪”般的外观。 示例数据由作者提供。

上述示例电子表格展示了一个假设的本地地点列表,这些地点除了有名称外,几乎没有共同之处。注意到有些地点的数据很多,比如 Joe’s Burgers,而有些地点如 Alcove Speakeasy 的数据稀少。许多单元格是空的,包括Restrictions列,该列仅包含一行数据。在Websites列下,不清楚单元格是否为空是因为数据丢失(如 Joe’s Burgers 的情况),还是因为该地点没有网站(如 Centennial Obelisk 的情况)。还有一些单元格包含大量嵌套数据,特别是在PhotosPricesScores列下。当然,还有一个Miscellaneous列,将三个潜在的列合并为一个,以防止电子表格变得过于庞大。

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

相同的本地社区目录以 JSON 文件的形式。这类似于数据在面向文档的数据库中存储的方式。 完整文件可以在此查看。作者提供的截图。

查看以 JSON 文件形式存储的相同社区目录,一些关键优势变得显而易见。

  • 文档的大小可以根据存储的实际数据量而有所不同。这意味着,与其使用 Miscellaneous 列来减少电子表格列的数量,不如为少量文档创建一个 Awards 属性。

  • 请注意,对于“Joe’s Burgers”,没有 Website 字段,而对于“Centennial Obelisk”却有。这是一种传达 Joe’s Burgers 的网站可能存在但在数据中缺失的方式,而 Centennial Obelisk 没有网站。与电子表格相比,这两种情况在电子表格中是不可区分的!

  • 数据的表现形式有更多的空间,比喻地说。PhotosPricesScores 字段挤在电子表格单元格中,但可以作为自身的子文档进一步扩展,或者在 Scores 的情况下,作为一个列表。

  • 使用 @id 字段作为“主键”创建了关系数据结构,而 TypeUser 等字段可以通过它们的 @id 查找文档。

图数据库

图数据库旨在描述连接。这通过同时管理两种不同的数据顺序来实现:“节点”和“关系”(注意,术语可能因具体的图数据库技术而异)。节点具有独立于任何模式或其他数据的自身存在,尽管节点可以使用“标签”进行分类(类似于关系数据库使用“表”以及面向文档的数据库使用“集合”进行分类)。关系作为图数据的第二种顺序,根据源节点和目标节点定义,并按照关系类型进行分类。类似于面向文档的数据库中的文档,节点和关系都可以具有任意数量的属性,以键值对的形式表示。

再次,对于数字数据领域的新手来说,“图”的术语可能会分散对这种模型类型实际意义的注意力。与“条形图”或“折线图”等常见数据可视化不同,这里的“图”指的是这种数据模型类型更像是一个由圆圈(作为节点)和线(作为关系)构成的思维导图。这种数据模型类型被认为与人脑的工作方式相似,这不仅对神经科学人工智能有影响,还意味着图数据模型对于技术不太熟悉的相关方相对容易理解。

具有讽刺意味的是,图数据库实际上比关系数据库更注重关系。虽然关系数据库通过在表之间匹配主键和外键来连接相关数据,但图数据库中的关系有其“存在”,因此可以加载额外的属性。这些属性可以描述关系的强度、质量、持续时间或其他特征。

领先的图数据库解决方案是Neo4j。他们的社区版是完全开源的,可以用于本地或自托管,免费云层的上限为 200,000 个节点和 400,000 个关系。Neo4j 查询语言叫做“Cypher”,可以免费学习,并且具有独特的可视化特性,使非开发人员容易理解。目前,Cypher 启发的“图查询语言”(或 GQL)的标准化正在进行中,甚至被认为是联合国可持续发展目标第 9 项——建立韧性基础设施、促进包容性和可持续工业化以及促进创新的一个步骤。

电子表格诊断

如果你们组织的数据目前都存储在电子表格中,你应该考虑跃迁到图数据库,特别是当你经常通过注释、评论和额外的列(这些列仅用于描述其他列中的数据)来上下文化数据时。

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

这个电子表格中的许多单元格都有一个“备注”,其中包含重要的背景数据,可以通过将光标移动到单元格上来显示。在 Microsoft Excel 中,带备注的单元格由右上角的红色三角形标识,使得电子表格看起来像是带有黑胡椒奶酪的外观。 下载文件在这里。屏幕截图由作者提供。

上述示例展示了一个名为“Fayette Advocacy Network”的虚构倡导组织的“权力映射”。权力映射用于追踪在特定问题上有影响力的人物、他们对该问题的态度,以及他们与组织的关系(无论间隔多少度)。

注意,这个图表中最有趣的数据并不在单元格的数值中,而是在每个单元格的备注中。例如:市议员纳迪亚·卡尔森和编辑委员会成员朱利斯·卡尔森是夫妻关系。斯科特·普尔不仅是 Fayette Teachers Union 的主席,还是 Fayette Public Schools 的员工,并且是 Fayette Advocacy Network 的活跃成员。尚未确认的 Fayette Advocacy Network 的原因已经被记录在案,因为这是通过他在社交媒体上的评论得知的。

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

在这个图表视图中,决策者用蓝色表示,其他人用品红色表示,组织用绿色表示,对问题的立场用灰色表示,而 Fayette Advocacy Network 则有一个大大的金色节点。节点之间的关系用箭头表示,这本身就是一种有价值的数据形式。 在 Arrows.app 中查看

由于图形数据库可以存储带有属性的关系,因此表格中仅备注的数据可以在图形数据库中突出显示。图形模型类型提高了这些宝贵的背景信息的组织性和可访问性。

当一次性查看所有数据时,它可能看起来是一团糟。可以通过查询更具体的问题来缩小数据范围,例如:“谁是与对问题的立场仍然未知的决策者有联系的 Fayette Advocacy Network 的成员?”作为参考,下面提供了一个相应的 Cypher 查询。注意,这段主要为计算机解析而编写的代码对于人类阅读相对简单。

MATCH (faynet:Organization)<-[:MEMBER_OF]-(member:Person)-[:CONNECTED*1..2]-(decisionmaker:Person)-[:STANCE]->(pos:Position)
WHERE faynet.name = "Fayette Advocacy Network"
AND pos.name = "Unknown"
RETURN member

这个查询返回一个Person的列表,这些Person是“Fayette Advocacy Network”的MEMBER_OF,并且与decisionmaker(其对问题的Position为“unknown”)有CONNECTED(或与连接到decisionmaker的某人连接)。即使你不了解 Cypher,你也应该能够通过花几分钟时间琢磨各种箭头和括号的含义来弄清楚查询的工作原理。

值得一提的是:为了帮助理清这些混乱,Neo4j 还提供了一套图数据科学包,以帮助识别模式并计算节点重要性的常见度量,如 度中心性中介中心性。越来越多的软件解决方案可用于可视化这些图数据,从 Neo4j 的简单内部解决方案 Bloom 一直到 虚拟现实头戴设备。不用说,这些查询、计算和可视化在单独使用电子表格时几乎是不可能完成的。

跳跃到数据库

本指南的动机原则是帮助你识别适合你数据需求的技术。很多时候,电子表格实际上会是合适的技术:用于以简单格式存储非关系数据,与技术水平较低的用户协作,快速处理一些数字,甚至作为数据驱动的头脑风暴和项目规划的创意场所。电子表格之所以有效,是因为它们将数据输入、工程、分析、协作和共享全部集中在一个空间中。

但将所有这些功能捆绑在一起的便利性,也可能使得电子表格对于你的数据来说变得限制重重。现实情况可能是,你需要关系数据库的关联性,或文档导向数据库的适应性,或图数据库的上下文化。即使你已经投入了数百小时来完善一个电子表格——实际上,你投入的时间越多,电子表格越可能阻碍你。

“电子表格无论输入什么内容看起来都很好。有人把电子表格带到会议中,它看起来如此精确。它有数字和图表,还有漂亮的字体。它感觉像是在告诉你世界的真相。感觉像是真理。”

— David Kastenbaum 在 电子表格!

电子表格陷阱发生是因为电子表格让人感到安全。与数据库技术不同,像 Microsoft Excel 和 Google Sheets 这样的工具捆绑在家庭办公室套件中,并且具有与我们的文字处理器和幻灯片制作器相同的熟悉界面。我们中的许多人是在学校里第一次学会使用电子表格的,有时处理电子表格也是联系同事的纽带。即使在 TikTok 上,也有社区专注于掌握电子表格的艺术

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

迈出一步。 图片插图由作者制作。 照片Sammie ChaffinUnsplash 上提供。

要将我们的数据从电子表格的囚笼中解放出来,需要一跃而起。我们必须相信,特定数据库模型的好处将超过采用陌生技术所带来的风险。好消息是,我们还有错误的余地:通过几行代码修复一个混乱的数据库比通过数百次鼠标点击修复笨重的电子表格要容易得多。此外,选择错误的数据库技术起步并不是世界末日:一旦电子表格被重新组织为表格(关系型)、集合(文档导向型)或标签(图形型),在这三种范式之间转换就会容易得多。

然而,逃离电子表格囚笼可能还有一个更重要的原因。随着我们将数据从电子表格中解放出来,我们也解放了对数据的想象力以及数据如何在组织中被利用。查找和输入数据从成为浪费时间的琐事变成了对日益激动人心和有价值的信息库的贡献。我们的数据从笨拙地保持的内部秘密变成了团队成员和外部合作伙伴的协作中心。

再仔细看一眼你的数据。如果电子表格囚笼阻碍了你实现目标,是时候深呼吸,勇敢地跃入数据库的世界了!

我的目标是架起数字数据与“现实世界”组织之间的桥梁。如果你欣赏这份指南,以下是你可以支持这篇及未来作品的方式:

选择正确的路径:流失模型与提升模型

原文:towardsdatascience.com/choosing-the-right-path-churn-models-vs-uplift-models-b8489306aa80

我们真的需要流失模型吗?也许提升建模能给我们更全面的答案?

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

·发表于 Towards Data Science ·阅读时间 5 分钟·2023 年 6 月 16 日

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

照片由 cmophoto.net 提供,来源于 Unsplash

让我们假设我们在电商领域工作,产品经理找到了我们并要求建立流失模型。

但实际上他问了我们什么?

流失模型能给我们什么?

好吧,这一切都与了解特定客户离开的可能性有关。我们的下一步由启发式方法驱动:

如果我们对可能流失的客户提供折扣,他们将会留下来。

但我们的目标稍有不同。让我们假设我们只能做两件事:给予优惠或不给予优惠,在我们的案例中就是折扣。有 4 种可能的结果。

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

图片由作者提供

  1. 利润让步。 我们提供了折扣,用户使用了它并购买了商品,但即使没有折扣用户也会进行购买。这是一个负面结果,因为利润被让步了。

  2. 处理成本。 我们提供了折扣,但用户没有使用,也没有进行购买。这也被视为负面结果,因为我们在处理过程中产生了成本,如发送短信,尤其是在处理大量用户时。

  3. 成功。 我们提供了折扣,用户使用了它,并仅仅因为这个优惠进行了购买。这是我们期望的结果。

  4. 流失客户。 我们提供了折扣,但用户最终离开了我们。例如,在订阅服务的情况下,用户收到了一则折扣通知,却发现自己在过去 6 个月里一直在支付订阅费用,最终决定取消。这是我们可能遇到的最负面的结果。

我们真正的目标不是估计流失的概率,而是为每个用户应用最合适的处理。

我们如何开始实现这一目标?

首先,进行一个简单的 AB 测试至关重要。这涉及向一个组提供折扣,同时保持一个没有折扣的对照组。

实验后我们有三种主要方法。

双模型方法

第一种方法涉及构建两个独立的模型:一个用于控制组(没有任何折扣),另一个用于处理组(有折扣)。为了构建这些独立模型,我们可以选择任何类型的机器学习模型。

通过将每个客户通过两个模型,我们可以计算提升作为预测结果之间的差异。

优点:

  • 实施很简单。

缺点:

  • 这并不能直接预测提升。我们估计的是用户行动(购买)的概率。

  • 两模型设置引入了双重误差建模,因为两个模型都有各自的误差,从而导致整体误差增大。

目标转换

第二种方法围绕目标变量本身的转换。通过创建一个表示提升的新目标,我们可以直接计算所需的结果。

我们使用以下公式引入一个新的目标变量:

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

作者提供的图片

这里,Y 表示原始目标变量,而 W 表示是否应用了目标处理。换句话说,Y 表示是否给予折扣,W 则表示是否进行了购买。

转换后的变量 Z 在两种情况下取值为 1:

  • 用户属于目标组(W = 1)且 Y = 1(用户收到了折扣并且进行了购买)。

  • 用户属于控制组(W = 0)且 Y = 0(用户未获得折扣且用户没有购买)。

然后我们只需要用新的目标训练模型(例如逻辑回归)。

计算提升时,我们可以使用以下公式:

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

作者提供的图片

优点:

  • 实施仍然很简单。

  • 由于只有一个模型,它比第一种方法更具鲁棒性和稳定性。

缺点:

  • 这仍然无法直接预测提升。我们预测的是转换后的变量。

基于树的模型

第三种方法利用了基于树的模型。

目标是识别数据集中对处理最为敏感的子群体,从而实现最大影响的有针对性干预。

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

基于树的提升模型。github.com/uber/causalml

用于提升目的的示例决策树如上方突出显示的图像所示。红色表示提升值。通过观察图像,我们可以得出总体提升差异为 0.0127(基于随机度量)。然而,当我们深入树中时,我们观察到某些子群体展示出更高的提升差异。

这些子群体成为我们的目标,因为它们拥有最大收益的潜力。

如何构建这棵树?

有很多关于构建决策树的教程,但在这里我将概述基本方法。

  • 选择特征并识别目标变量,在我们的案例中,目标变量是提升。

  • 选择一个分割标准来确定节点如何划分。

  • 通过递归地重复分割过程来构建树,直到满足停止标准。

值得注意的是,构建提升树时常用的分割标准有三种,按受欢迎程度排序如下:

  • KL 散度

  • 卡方

  • 欧几里得距离

优点:

  • 最准确的方法之一

  • 我们有一个决策树,因此我们可以构建树的森林和不同的集成方法,这些方法提高准确性并减少方差。

缺点:

  • 这是一种决策树方法,因此算法倾向于高估具有多个级别的分类变量。为了解决这个问题,我们可以使用均值插补。

结论

现在我们知道,解决客户流失问题需要超越仅仅估计流失概率的策略。终极目标是对每个用户应用最合适的治疗方案,并带来商业影响,而不仅仅是流失概率。

提升建模可以应用于超越流失的各种商业挑战,提供了一个有力的解决方案,并具有即时的商业影响。

关于提升建模仍然存在许多有趣的问题,例如处理多重治疗、估计不同的提升模型以及利用多臂老虎机进行生产,但我会将答案留到下一个帖子。

感谢阅读,不要害怕犯错和学习。这是进步的唯一途径!

为你的下一个数据科学网页应用程序选择合适的工具

原文:towardsdatascience.com/choosing-the-right-tool-for-your-next-data-science-web-application-3d7ec8293d61

Flask、Django、Streamlit:数据科学家进入网页开发的三种选择。

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

·发表在 Towards Data Science ·6 分钟阅读·2023 年 1 月 31 日

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

图片由 Campaign Creators 提供,来源于 Unsplash

依靠现代的先进计算能力,我们可以比以往更好地利用数据。从你家里的舒适环境中,通过使用笔记本电脑和通过互联网获得的大量数据,设计和实现可能改变生活的技术变得可能。

但有一个问题。如果一个令人印象深刻的机器学习模型或有洞察力的数据可视化工具仅仅是作为代码文件放在你的电脑上,那它对任何人来说几乎没有用处。要真正产生影响,你需要能够以紧凑、可用的方式与其他人分享你的发明。

传统的方法是通过一个网页应用程序来实现。通过将你的数据科学工具转变为一个应用程序,并将其托管在一个任何人都可以通过互联网访问的服务器上,你可以立即让数以百万计的人使用你的工具。

不幸的是,这并不像听起来那么简单。构建一个网页应用程序是一个相当复杂的编程任务,涉及的技能超出了许多数据科学家的专长。从零开始编写一个确实是一项挑战。

幸运的是,许多公司从事网页框架的业务。网页框架本质上是一个广泛的库,它提供了构建网页应用程序的基础结构,使得入门变得非常容易。

在这篇文章中,我将讨论 Python 中三种成熟的 web 框架的优缺点:Flask、Django 和 Streamlit。如果你刚刚开始,可能很难知道该使用哪个工具,我希望能帮助你确定哪个最适合你的技能水平和总体目标。请注意,这篇文章讨论如何实际使用这些工具构建应用程序的细节。

那我们开始吧?

Flask

Flask [1] 常常是介绍给新手 web 开发者的第一个框架。你常常会听到它被描述为极其轻量且如果你已经了解 Python,则相当容易学习。在这里,“轻量”一词意味着 Flask 没有任何外部依赖,它提供了构建 web 应用程序所需的最基本工具,而不会让你感到功能过多。

Flask 轻量得如此以至于常被称为“微型”框架。你可以从最简单的应用程序开始,根据需要选择更多功能。此外,它足够简单,如果你已经了解 Python,你不会觉得自己在学习一种全新的语言。

然而,这种简单性是把双刃剑。由于 Flask 轻量级,它也会为你自动完成较少的事情。换句话说,当你在构建 web 应用程序时,你将不得不自己解决许多问题。

我自己从未使用过 Flask,但我承认它已经被许多次推荐给我。在一般编程社区的眼中,它的好处似乎超过了成本。

让我们在继续之前回顾一下。

优点

  • 极其轻量(在某种意义上是“微型”框架)

  • 你可以选择所需的功能。

  • 由于上述两个特性,学习起来可以说更容易。

缺点

  • 内置功能不那么丰富。

  • 由于上述原因,你需要自己实现 web 应用程序的许多方面。

Django

这是我个人的框架选择。我最近才开始进行全面的 web 开发,之前只是使用了更简单的替代方案(见下文 Streamlit 部分)。我必须在 Django 和 Flask 之间做出选择,最终决定 Django 更适合我的需求。

Django 是 Flask 的完全对立面,因为它相当沉重。它有一个巨大的功能集——当你构建一个 Django 项目时,你会得到所有这些功能,无论你是否需要。这有积极和消极的方面。

好的一面是,由于许多功能已经内置,你需要从头开始实现的东西会更少。一个很好的例子是 Django 管理页面。所有 Django 项目自动实现一个数据库管理员网页,允许一个“超级用户”添加和删除数据,而无需编写任何代码。如果你想为一个需要管理相关数据库但没有相应编程技能的团队设计一个网络应用,这可能会非常有用。

另一方面,项目庞大、复杂且可能让人感到威慑,因为你一次性获得了一切。最简单的 Flask 应用可以写在一个代码文件中,但任何 Django 项目在你开始时都会自动创建大量的目录和相关文件。

Django 也有非常详细的文档和由开发者亲自编写的优秀教程 [3]。对一些人来说,这是把双刃剑,因为开发者意见非常明确。因此,当你在 Django 中做某事时,你必须按照“Django”的方式去做。然而,如果网页开发不是你主要的编程强项,你只是想开始,那么这不太可能成为问题。

总之 —

优点

  • 附带许多内置功能

  • Django 管理员是一个非常棒的附加功能,你无需额外工作即可获得

  • Django 提供了一整套由公司自行编写的详尽教程(确保信息准确并符合最佳实践)

缺点

  • 非常庞大——你在 Django 项目中获得所有功能,无论你是否需要它们

  • Django 的开发者对网页开发有强烈的意见,这些意见反映在使用 Django 编程时必须遵循的方式上。如果你不同意这些意见,可能会发现 Django 很让人沮丧。

Streamlit

Streamlit [4] 将数据脚本在几分钟内转换为可分享的网页应用。

完全使用 Python 编写。不需要前端经验。”

上述引言直接摘自 Streamlit 的首页,并且是一个相当扎实的总结。Streamlit 最初的设计目的是为了让缺乏网页编程技能的数据科学家能够轻松地将他们的数据科学工具部署到互联网上。

这是 Streamlit 的最大优势。你可以用 Python 编写你的数据科学工具,对照 Streamlit 的规范进行一些语法上的调整,添加一些头部代码行,然后你的应用程序就准备好了!至少在本地是这样的——不过 Streamlit 也提供了云支持作为下一步。

Streamlit 还具有一些不错的内置功能(滑块、按钮和其他小部件),可以用来为你的应用程序提供良好的提升。

不过,Streamlit 也有两个缺点。显而易见的一个是你实际上被限制在 Streamlit 的默认界面中,因此无法真正自定义应用程序的外观。Streamlit 并不是为了个性化设计的;它只是提供了一种快速发布工具并在需要时收集数据的方式。

此外,Streamlit 在处理大数据集时也存在一些问题。根据我的经验(以及我合作过的其他人的经验),执行潜在的高成本计算过程(例如渲染可视化)在 Streamlit 中可能会有一些延迟。这种经验得到 Streamlit 论坛讨论 [5] 的支持。

总的来说,Streamlit 学习快且容易,但灵活性远不如 Flask 和 Django。

优点

  • 为数据科学家设计

  • 需要最低限度的网页开发知识

  • 可以极其快速地构建和部署网页应用

缺点

  • 在自定义网页应用方面几乎没有自由度

  • 对于大数据集或高成本操作可能存在效率问题

最终想法

选择正确的框架既是个人偏好的问题,也是你具体需求的考虑。我无法了解你的偏好,因此我会简要地谈谈第二点以作结。

想快速测试一个工具,却没有太多时间来组装它?Streamlit 可能是你的最佳选择。如果你想学习网页开发并提升 Python 技能,选择 Flask 或 Django 会更合适。这两者都能很好地处理大型复杂应用,因此个人偏好在此时显得尤为重要。

与所有编程一样,从一篇文章中只能获得有限的信息。在此,我鼓励你亲自尝试每一种工具。我很想听听你的想法和反思,请在评论中分享。

祝你网页开发愉快!

想要在 Python 中脱颖而出? 点击这里获取我简单易读的免费指南。想在 Medium 上阅读无限故事?请通过下面的推荐链接注册!

[## Murtaza Ali - Medium

阅读 Murtaza Ali 在 Medium 上的文章。他是华盛顿大学的博士生,兴趣涉及人机交互…

murtaza5152-ali.medium.com](https://murtaza5152-ali.medium.com/?source=post_page-----3d7ec8293d61--------------------------------)

参考资料

[1] flask.palletsprojects.com/en/2.2.x/

[2] www.djangoproject.com/

[3] docs.djangoproject.com/en/4.1/intro/tutorial01/

[4] streamlit.io/

[5] discuss.streamlit.io/t/whether-streamlit-can-handle-big-data-analysis/28085/15

慢性肾病预测:新视角

原文:towardsdatascience.com/chronic-kidney-disease-prediction-a-fresh-perspective-6ad7fa85eb0d?source=collection_archive---------9-----------------------#2023-08-25

利用 SHAP 构建一个与医学文献一致的可解释模型

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

·

关注 发布于 Towards Data Science ·8 min read·2023 年 8 月 25 日

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

图片由 Robina Weermeijer 提供,来源于 Unsplash

引言

肾脏努力从血液中去除任何废物、毒素和多余的液体,其正常功能对于健康至关重要。慢性肾病(CKD)是一种肾脏无法像应该那样过滤血液的状况,导致血液中液体和废物的积累,长期可能导致肾衰竭。[1] CKD 影响了全球超过 10%的人口,并预计到 2040 年将成为全球第五大生命年损失原因。[2]

在这篇文章中,我的目标不是建立一个最准确的模型来预测患者发生 CKD 的情况。而是检查使用标准机器学习算法开发的最佳模型是否也符合医学文献中的最有意义模型。我使用了 SHAP(SHapley Additive exPlanations)的原则,这是一种博弈论方法,用于解释机器学习模型的输出。

医学文献怎么说?

医学文献将 CKD 的发展和进展与一些关键症状相关联。

  1. 糖尿病和高血压: 糖尿病和高血压是与 CKD 相关的两个最重要的风险因素。在 2011-2014 年在美国进行的一项研究中,糖尿病患者中 CKD(3-4 期)的患病率为 24.5%,前糖尿病患者为 14.3%,非糖尿病患者为 4.9%。在同一项研究中,高血压患者的 CKD 患病率为 35.8%,前高血压患者为 14.4%,非高血压患者为 10.2%。[2]

  2. 减少的血红蛋白和红细胞水平: 肾脏产生一种叫做红细胞生成素(EPO)的激素,这种激素有助于红细胞的生成。在慢性肾病(CKD)中,肾脏无法产生足够的 EPO,导致贫血的发展,即血液中的红细胞和血红蛋白水平下降。[3]

  3. 增加的血清(血液)肌酐: 肌酐是正常肌肉和蛋白质分解的废物,过量的肌酐通过肾脏从血液中排出。在 CKD 中,肾脏无法有效排除过量的肌酐,导致血液中肌酐水平升高。[4]

  4. 尿液比重降低: 尿液比重是肾脏浓缩尿液能力的指标。患有 CKD 的患者尿液比重降低,因为肾脏失去了有效浓缩尿液的能力。[5]

  5. 血尿和蛋白尿: 血尿和蛋白尿分别指尿液中存在红细胞和白蛋白。正常情况下,肾脏的过滤器阻止血液和白蛋白进入尿液。然而,过滤器的损害可能导致血液(或红细胞)和白蛋白进入尿液。[6][7]

数据集

本文使用的数据集是 Kaggle 上的‘慢性肾脏疾病’数据集,最初由 UCI 在其机器学习库下提供。该数据集包含来自 400 名患者的数据,包括 24 个特征和 1 个二进制目标变量(CKD 缺失 = 0,CKD 存在 = 1)。特征的详细描述可以在这里找到。

数据预处理

CKD 数据集有很多缺失值,需要在进一步分析之前进行填补。此图显示了缺失数据的可视化表示,黄色线条指示了该列中的缺失值。

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

缺失数据的可视化表示(由黄色线条标示)

缺失值以以下方式进行了填补:

  1. 对于数值特征,缺失值使用中位数填补。未使用均值,因为均值对异常值敏感,而中位数则不敏感。由于这些列中存在异常值,中位数更能准确反映中心值。

  2. 分类特征‘rbc’和‘pc’分别缺失了 38%和 16.25% 的数据。由于这是一个较大的缺失数据量,缺失值被填补为‘未知’。在这种情况下使用众数并不是最佳选择,因为将这么大一组观察结果归为同一类别可能会有一定风险。

  3. 其他所有分类特征的缺失数据都少于或等于 1%。因此,使用各自的众数填补了缺失值。

使用 SHAP 构建模型并检查可解释性

在填补缺失值之后,将数据分为训练集和测试集(70–30 拆分),并运行了一个简单的随机森林分类模型。测试准确率为 100%,即模型能够在 100%的时间里正确分类之前未见过的患者。混淆矩阵如下所示。

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

在测试数据上运行模型时生成的混淆矩阵

当然,我们现在有了一个很好的分类模型。但如果我们对解释性感兴趣,即每个特征如何对预测产生积极或消极的贡献呢?哪些特征是推动预测的最重要因素?结果是否与临床发现一致?这些问题是 SHAP 可以帮助我们回答的。

SHAP 是一种基于博弈论的数学方法,可以通过计算每个特征对预测的贡献来解释任何机器学习模型的预测。它可以帮助我们确定那些对预测起关键作用的特征,以及它们对目标变量的影响方向。[8] 我们为测试数据拟合了一个 SHAP 解释器,并生成了如下所示的全局特征重要性图。

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

使用 SHAP 生成的全局特征重要性图

驱动预测的前三个特征是血红蛋白水平(‘hemo’)、尿液的比重(‘sg’)和患者尿液中是否存在红血球(‘rbc_normal’)。由于特征重要性是通过计算该特征在所有样本中的绝对 SHAP 值的均值得出的,因此该图仅提供了重要性的顺序信息,而不涉及影响的方向。让我们生成一个更具信息性的图表,涵盖这两个目标。

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

使用 SHAP 生成的蜜蜂图

这个蜜蜂图是展示数据集中顶级特征如何影响模型预测的绝佳方式。粉色点表示预测为 CKD 的患者,蓝色点表示预测为非 CKD 的患者。现在我们已经知道了驱动预测的顶级特征,让我们看看它们的影响方向是否与本文前面展示的临床发现一致。

  1. 糖尿病(‘dm_yes’)和高血压(‘htn_yes’)的存在与 CKD 的出现有关。这与临床发现相匹配,尽管考虑到它们是与 CKD 相关的主要风险因素,预期它们在全球重要性中应位于更高的位置。

  2. 低血红蛋白水平(‘hemo’)、低红细胞压积(‘pcv’:血液中红血球的体积分数)和低红血球计数(‘rc’)与 CKD 相关。这也与临床发现一致,因为 CKD 患者无法生产足够的红血球。

  3. 低尿液比重(‘sg’)与 CKD 相关,这在临床上可以解释为肾脏失去浓缩尿液的能力。

  4. 尿液中的高白蛋白(‘al’)和高血清肌酐(‘sc’)水平与 CKD 相关,这与临床发现一致,因为肾脏失去有效过滤血液的能力。

  5. 尿液中红血球或异常尿液的存在(‘rbc_normal’;这是一个二元分类特征,其中值 = 1 表示正常尿液中没有 RBCs,值 = 0 表示异常尿液可能含有 RBCs)与 CKD 相关。这支持了临床发现,因为血尿在 CKD 患者中更为常见。

总之,顶级特征及其对预测的影响方向与医学文献一致。

结论

在这篇文章中,有两个主要收获:

  1. 医学文献将 CKD 的发展和进展与 ML 模型用于分类的相同顶级特征相关联,以判断患者是否预测为 CKD。

  2. 这些顶级特征对目标变量的影响方向支持临床发现,表明该模型不仅在预测 CKD 时 100% 准确,而且具有医学意义,结果完全可以解释。

本研究的一项可能局限性是样本量较小。一旦获得更多数据,应在更大的患者群体上测试模型,以检查其是否继续保持高精度。也有趣的是查看在更大患者群体中,特征的重要性排序是否发生变化。

在医学领域,最准确的模型可能并不总是最有意义的模型。在这项研究中,使用了 SHAP 来检查我们的模型是否符合医学文献。最终模型的优势在于它不仅具有高精度,而且易于解释,并得到临床发现的支持。该模型在远程医疗中具有很大用途,可以用于识别更高风险的慢性肾病患者。未来的研究可以深入个体观察,并查看哪些模型特征在个体层面上驱动了预测。

本项目的代码可以在 这里 找到。本文中的所有图片均由我通过 Google Colab 生成。

参考文献

原版数据集许可证: L. Rubini, P. Soundarapandian 和 P. Eswaran, 慢性肾病 (2015), UCI 机器学习库 (CC BY 4.0)

‘慢性肾病’ 数据集在 Kaggle 上: www.kaggle.com/datasets/mansoordaku/ckdisease

原版 SHAP 文档: shap.readthedocs.io/en/latest/api_examples.html#plots

[1] 慢性肾病基础知识 (2022), 《疾病控制与预防中心》

[2] C.P. Kovesdy, 慢性肾病流行病学:2022 更新 (2022), 《肾脏国际补充期刊》

[3] H. Shaikh, M.F. Hashmi 和 N.R. Aeddula, 慢性肾病性贫血 (2023), 《国家医学图书馆》

[4] 血清(血液)肌酐 (2023), 《国家肾脏基金会》

[5] J.A. Simerville, W.C. Maxted 和 J.J. Pahira, 尿液分析:综合评审 (2005), 《美国家庭医生》

[6] P.F. Orlandi 等, 血尿作为慢性肾病和死亡进展的风险因素:来自慢性肾功能不全队列(CRIC)研究的发现 (2018), 《BMC 肾脏病学》

[7] 尿白蛋白 (2016), 美国国家糖尿病和消化与肾脏疾病研究所

[8] R. Bagheri, SHAP 值及其在机器学习中的应用介绍 (2022), Towards Data Science

CI/CD 在 AWS 的多模型端点

原文:towardsdatascience.com/ci-cd-for-multi-model-endpoints-in-aws-18bf939e0a48?source=collection_archive---------7-----------------------#2023-06-22

一个简单、灵活的可持续机器学习解决方案的替代方案

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

·

关注 发表在 Towards Data Science ·14 分钟阅读·2023 年 6 月 22 日

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

图片来源于 VectorStock,授权给Andrew Charabin

自动化生产机器学习解决方案的再培训和部署是确保模型考虑到covariate shift的关键步骤,同时减少出错和不必要的人力投入。

对于使用 AWS 堆栈和特别是 SageMaker 部署的模型,AWS 提供了一种标准 CI/CD 解决方案,使用 SageMaker Pipelines 来自动化重新训练/部署,以及 SageMaker 模型注册表 来跟踪模型的传承。

虽然标准解决方案在标准情况下效果良好,但在更复杂的情况下存在若干限制:

  1. 输入数据需要从 AWS s3 获取。

  2. 设置动态预热超参数调整的难度。

  3. 需要额外的模型训练步骤来训练多个模型。

  4. 执行管道的启动时间较长。

  5. 调试工具有限。

幸运的是,AWS 推出了可以用来构建克服这些限制的 CI/CD 管道的新功能。以下功能可以在 SageMaker Studio 中访问,这是 AWS 的集成开发环境,用于机器学习:

本文的目的…

目的是通过 AWS 云探讨一种替代 CI/CD 解决方案的关键细节,该方案提供了更多灵活性和更快的市场速度。

解决方案组件概述:

1. 自定义 SageMaker Studio 图像用于 PostgreSQL 查询

2. 动态预热超参数调整

3. 在单个交互式 Python 笔记本中注册多个模型到模型注册表

4. 用新模型刷新多模型端点

5. 计划重新训练/重新部署笔记本以在设定的周期上运行

开始吧。

1. 自定义 SageMaker Studio 图像 用于 PostgreSQL 查询

虽然 SageMaker 管道允许从 s3 获取输入数据,但如果新输入数据位于数据仓库中,如 AWS Redshift 或 Google BigQuery 呢?当然,可以使用 ETL 或类似过程将数据批量移动到 s3,但这与直接从数据仓库查询数据相比,增加了不必要的复杂性/僵化。

SageMaker Studio 提供了几种默认镜像来初始化环境,其中一个例子是包含常用包如 numpy 和 pandas 的‘Data Science’镜像。然而,要在 Python 中连接到 PostgreSQL 数据库,需要一个驱动程序或适配器。Psycopg2是 Python 编程语言中最流行的 PostgreSQL 数据库适配器。幸运的是,可以使用自定义镜像来初始化 Studio 环境,尽管有特定的要求。我已经预打包了一个满足这些要求的 Docker 镜像,并在 Python Julia-1.5.2 镜像基础上添加了 psycopg2 驱动程序。该镜像可以在这个git 仓库中找到。然后,可以使用这里概述的步骤使镜像在 Studio 域中可用。

2. 动态预热启动超参数调优

模型重新训练在性质上与初始模型训练不同。在重新训练模型时,投资相同数量的资源来搜索最佳模型超参数以及相同的大范围搜索空间是不切实际的。特别是当仅期望对上一生产模型的最佳超参数进行微调时尤其如此。

因此,本文推荐的 CI/CD 超参数调优解决方案不会尝试通过 K 折交叉验证、预热池等方式快速重新调优。这些方法对于初始模型训练非常有效。然而,对于重新训练,我们希望从生产中已经有效的地方开始,并对新获取的数据进行小幅调整。因此,使用动态预热启动超参数调优是完美的解决方案。进一步地,可以创建一个动态预热启动调优系统,使用最新的生产调优作业作为父作业。以下是一个示例 XGBoost 贝叶斯调优作业的解决方案:

# Set Run Parameters

testing=False
hyperparam_jobs=10

# Set Max Jobs

if testing==False: max_jobs=hyperparam_jobs
else: max_jobs=1

# Load Packages

from sagemaker.xgboost.estimator import XGBoost
from sagemaker.tuner import IntegerParameter
from sagemaker.tuner import ContinuousParameter
from sagemaker.tuner import HyperparameterTuner
from sagemaker.tuner import WarmStartConfig, WarmStartTypes

# Configure Warm Start
number_of_parent_jobs=1

# Can be up to 5, but currently only a value of 1 is supported in the code
# Note base_dir needs to be set, can also be set blank

try: eligible_parent_tuning_jobs=pd.read_csv(f"""{base_dir}logs/tuningjobhistory.csv""")
except: 
    eligible_parent_tuning_jobs=pd.DataFrame({'datetime':[],'tuningjob':[],'metric':[],'layer':[],'objective':[],'eval_metric':[],'eval_metric_value':[],'trainingjobcount':[]})
    eligible_parent_tuning_jobs.to_csv(f"""{base_dir}logs/tuningjobhistory.csv""",index=False)
eligible_parent_tuning_jobs=eligible_parent_tuning_jobs[(eligible_parent_tuning_jobs['layer']==prefix)&(eligible_parent_tuning_jobs['metric']==metric)&(eligible_parent_tuning_jobs['objective']==trainingobjective)&(eligible_parent_tuning_jobs['eval_metric']==objective_metric_name)&(eligible_parent_tuning_jobs['trainingjobcount']>1)].sort_values(by='datetime',ascending=True)
eligible_parent_tuning_jobs_count=len(eligible_parent_tuning_jobs)
if eligible_parent_tuning_jobs_count>0:
    parent_tuning_jobs=eligible_parent_tuning_jobs.iloc[(eligible_parent_tuning_jobs_count-(number_of_parent_jobs)):eligible_parent_tuning_jobs_count,1].iloc[0]
    warm_start_config = WarmStartConfig(
    WarmStartTypes.TRANSFER_LEARNING, parents={parent_tuning_jobs})
    # Note that WarmStartTypes.IDENTICAL_DATA_AND_ALGORITHM can be used when applicable

    print(f"""Warm starting using tuning job: {parent_tuning_jobs[0]}""")

else: warm_start_config = None

# Define exploration boundaries (default suggested values from Amazon SageMaker Documentation)

hyperparameter_ranges = {
    'eta': ContinuousParameter(0.1, 0.5, scaling_type='Logarithmic'),
    'max_depth': IntegerParameter(0,10,scaling_type='Auto'),
    'num_round': IntegerParameter(1,4000,scaling_type='Auto'),
    'subsample': ContinuousParameter(0.5,1,scaling_type='Logarithmic'),
    'colsample_bylevel': ContinuousParameter(0.1, 1,scaling_type="Logarithmic"),
    'colsample_bytree': ContinuousParameter(0.5, 1, scaling_type='Logarithmic'),
    'alpha': ContinuousParameter(0, 1000, scaling_type="Auto"),
    'lambda': ContinuousParameter(0,100,scaling_type='Auto'),
    'max_delta_step': IntegerParameter(0,10,scaling_type='Auto'),
    'min_child_weight': ContinuousParameter(0,10,scaling_type='Auto'),
    'gamma':ContinuousParameter(0, 5, scaling_type='Auto'),
}
tuner_log = HyperparameterTuner(
    estimator,
    objective_metric_name,
    hyperparameter_ranges,
    objective_type='Minimize', 
    max_jobs=max_jobs,
    max_parallel_jobs=10,
    strategy='Bayesian',
    base_tuning_job_name="transferlearning",
    warm_start_config=warm_start_config
)

# Note a SageMaker XGBoost estimater needs to be instantiated in advance
training_input_config = sagemaker.TrainingInput("s3://{}/{}/{}".format(bucket,prefix,filename), content_type='csv')
validation_input_config = sagemaker.TrainingInput("s3://{}/{}/{}".format(bucket,prefix,filename), content_type='csv')

# Note bucket, prefix, and filename objects/aliases need to be set

# Starts the hyperparameter tuning job

tuner_log.fit({'train': training_input_config, 'validation': validation_input_config})

# Prints the status of the latest hyperparameter tuning job

boto3.client('sagemaker').describe_hyper_parameter_tuning_job(
    HyperParameterTuningJobName=tuner_log.latest_tuning_job.job_name)['HyperParameterTuningJobStatus']

调优作业历史将保存在基础目录中的日志文件中,示例输出如下:

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

作者提供的图表

日期/时间戳、调优作业名称以及元数据以.csv 格式存储,新调优作业会追加到文件中。

系统将动态地使用满足要求条件的最新调优作业进行预热启动。在这个例子中,条件在以下代码行中注明:

eligible_parent_tuning_jobs=eligible_parent_tuning_jobs[(eligible_parent_tuning_jobs['layer']==prefix)&(eligible_parent_tuning_jobs['metric']==metric)&(eligible_parent_tuning_jobs['objective']==trainingobjective)&(eligible_parent_tuning_jobs['eval_metric']==objective_metric_name)&(eligible_parent_tuning_jobs['trainingjobcount']>1)].sort_values(by='datetime',ascending=True)

因为我们需要测试管道的工作情况,所以提供了testing=True运行选项,这将强制仅进行一个超参数调优作业。添加了一个条件,只考虑具有多个调优模型作为父模型的作业,前提是这些是非测试的。此外,调优作业日志文件可以在不同模型间使用,因为理论上可以在模型间使用父作业。在这种情况下,模型通过‘metric’字段进行跟踪,符合条件的调优作业会过滤以匹配当前训练实例中的指标。

一旦重新训练完成,我们将把新的超参数调整作业追加到日志文件中,并将其写入本地以及 s3,同时启用版本控制

# Append Last Parent Job for Next Warm Start

eligible_parent_tuning_jobs=pd.read_csv(f"""{base_dir}logs/tuningjobhistory.csv""")
latest_tuning_job=boto3.client('sagemaker').describe_hyper_parameter_tuning_job(
    HyperParameterTuningJobName=tuner_log.latest_tuning_job.job_name)
updatetuningjobhistory=pd.concat([eligible_parent_tuning_jobs,pd.DataFrame({'datetime':[datetime.now().strftime("%Y/%m/%d %H:%M:%S")],'tuningjob':[latest_tuning_job['HyperParameterTuningJobName']],'metric':[metric],'layer':prefix,'objective':[trainingobjective],'eval_metric':[latest_tuning_job['BestTrainingJob']['FinalHyperParameterTuningJobObjectiveMetric']['MetricName']],'eval_metric_value':latest_tuning_job['BestTrainingJob']['FinalHyperParameterTuningJobObjectiveMetric']['Value'],'trainingjobcount':[latest_tuning_job['HyperParameterTuningJobConfig']['ResourceLimits']['MaxNumberOfTrainingJobs']]})],axis=0)
print(updatetuningjobhistory)

# Write locally

updatetuningjobhistory.to_csv(f"""{base_dir}logs/tuningjobhistory.csv""",index=False)

# Upload to s3

s3.upload_file(f"""{base_dir}logs/tuningjobhistory.csv""",bucket,'logs/tuningjobhistory.csv')

3. 在单个交互式 Python 笔记本中将多个模型注册到模型注册表

通常,组织会有多个 AWS 账户用于不同的用例(即沙盒、QA 和生产)。你需要确定在 CI/CD 解决方案的每个步骤中使用哪个账户,然后添加本指南中提到的跨账户权限。

推荐在同一账户中进行模型训练和模型注册,特别是沙盒或测试账户。因此,在下图中,‘数据科学’和‘共享服务’账户将是相同的。在该账户中,需要一个 s3 桶来存放模型工件并跟踪与流水线相关的其他文件的血统。模型/端点将在每个‘部署’账户(即沙盒、QA、生产)中分别部署,引用训练/注册账户中的模型工件和注册表。

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

来自AWS 文档

现在我们已经决定了用于训练和存放模型注册表的 AWS 账户,我们可以构建初始模型并开发 CI/CD 解决方案。

使用 SageMaker Pipelines 时,为数据预处理、训练/调整、评估、注册以及任何后处理创建独立的管道步骤。虽然这对于单个模型管道是可以的,但当需要多个模型来解决机器学习方案时,会产生大量的管道代码重复。

因此,推荐的解决方案是构建并调度三个交互式 Python 笔记本在 SageMaker Studio 中。它们按顺序运行,并通过一个自动化的笔记本作业一起完成 CI/CD 流水线:

A. 数据准备

B. 模型训练、评估和注册

C. 使用最新批准的模型刷新端点

A. 数据准备

在这里,我们将从数据仓库查询并加载数据,然后将其写入本地和 s3。我们可以使用当前日期设置动态的日期/时间条件,并将生成的日期下限和上限传递到 SQL 查询中。

# Connect to Data Warehouse

dbname='<insert here>'
host='<insert here>'
password='<insert here>'
port='<insert here>'
search_path='<insert here>'
user='<insert here>'

import psycopg2
data_warehouse= psycopg2.connect(f"""host={host} port={port} dbname={dbname} user={user} password={password} options = '-c search_path={search_path}'""")

# Set Dataset Date Floor and Ceiling Applied to Pass in & Apply to Query

datestart=date(2000, 1, 1)
pushbackdays=30
dateend=date.today() - timedelta(days=pushbackdays)
print(datestart)
print(dateend)

# Query data warehouse

modelbuildingset=pd.read_sql_query(f"""<insert query>""",data_warehouse)

# Write .csv

modelbuildingset.to_csv(f"{base_dir}datasets/{filename}", index=False)
modelbuildingset

# Upload to s3 for Lineage Tracking

s3 = boto3.client('s3')
s3.upload_file(f"{base_dir}datasets/{filename}",bucket,f"datasets/{filename}")

这一步骤以将准备好的训练数据保存到本地以及 s3 以进行血统追踪结束。

B. 模型训练、评估和注册

通过在 Studio 中使用交互式 Python notebook,我们现在可以在一个 notebook 中完成模型训练、评估和注册。所有这些步骤都可以构建为一个函数,并适用于需要重新训练的其他模型。为了说明,代码未使用函数提供。

在继续之前,需要在注册表中为解决方案中的每个模型创建模型包组(可以在控制台中创建,也可以通过 Python 创建)。

# Get the Best Training Job

best_overall_training_job_name = latest_tuning_job['BestTrainingJob']['TrainingJobName']

# latest_tuning_job was obtained from the hyperparameter tuning section
latest_tuning_job['BestTrainingJob']

# Install XGBoost

! pip install xgboost

# Download the Best Model

s3 = boto3.client('s3')
s3.download_file('<s3 bucket>', f"""output/{best_overall_training_job_name}/output/model.tar.gz""", f"""{base_dir}models/{metric}/model.tar.gz""")

# Open and Load the Downloaded Model Artifact in Memory

tar = tarfile.open(f"""{base_dir}models/{metric}/model.tar.gz""")
tar.extractall(f"""{base_dir}models/{metric}""")
tar.close()
model = pkl.load(open(f"""{base_dir}models/{layer}/{metric}/xgboost-model""", 'rb'))

# Perform Model Evaluation

import json
import pathlib
import joblib
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
import math
evaluationset=pd.read_csv(f"""{base_dir}datasets/{layer}/{metric}/{metric}modelbuilding_test.csv""")
evaluationset['prediction']=model.predict(xgboost.DMatrix(evaluationset.drop(evaluationset.columns.values[0], axis=1), label=evaluationset[[evaluationset.columns.values[0]]]))

# In the Example a Regression Problem is Used with MAE & RMSE as Eval Metrics

mae = mean_absolute_error(evaluationset[evaluationset.columns.values[0]], evaluationset['prediction'])
rmse = math.sqrt(mean_squared_error(evaluationset[evaluationset.columns.values[0]], evaluationset['prediction']))
stdev_error = np.std(evaluationset[evaluationset.columns.values[0]] - evaluationset['prediction'])
evaluation_report=pd.DataFrame({'datetime':[datetime.now().strftime("%Y/%m/%d %H:%M:%S")], 'testing':[testing], 'trainingjob': [best_overall_training_job_name], 'objective':[trainingobjective], 'hyperparameter_tuning_metric':[objective_metric_name], 'mae':[mae], 'rmse':[rmse], 'stdev_error':[stdev_error]})

# Load Past Evaluation Reports

try: past_evaluation_reports=pd.read_csv(f"""{base_dir}models/{metric}/evaluationhistory.csv""")
except: past_evaluation_reports=pd.DataFrame({'datetime':[],'testing':[], 'trainingjob': [], 'objective':[], 'hyperparameter_tuning_metric':[], 'mae':[], 'rmse':[], 'stdev_error':[]})
evaluation_report=pd.concat([past_evaluation_reports,evaluation_report],axis=0)
print(evaluation_report)

# Write .csv

evaluation_report.to_csv(f"""{base_dir}models/{metric}/evaluationhistory.csv""",index=False)

# Write to s3

s3.upload_file(f"""{base_dir}models/{metric}/evaluationhistory.csv""",'<s3 bucket>',f"""{layer}/{metric}/evaluationhistory.csv""")

# Note Can Also Associate a Registered Model with Eval Metrics, But Will Skip it Here

report_dict = {}

# Register Model

model_package_group_name='<>'
modelpackage_inference_specification =  {
    "InferenceSpecification": {
      "Containers": [
         {
            "Image": xgboost_container,
     "ModelDataUrl": f"""s3://{s3 bucket}/output/{best_overall_training_job_name}/output/model.tar.gz"""
         }
      ],
      "SupportedContentTypes": [ "text/csv" ],
      "SupportedResponseMIMETypes": [ "text/csv" ],
   }
 }
create_model_package_input_dict = {
    "ModelPackageGroupName" : model_package_group_name,
    "ModelPackageDescription" : "<insert description here>",
    "ModelApprovalStatus" : "PendingManualApproval",
    "ModelMetrics" :report_dict
}
create_model_package_input_dict.update(modelpackage_inference_specification)
sm_client = boto3.client('sagemaker')
create_model_package_response = sm_client.create_model_package(**create_model_package_input_dict)
model_package_arn = create_model_package_response["ModelPackageArn"]
print('ModelPackage Version ARN : {}'.format(model_package_arn))

通过打开注册表中的模型包组,您可以查看所有已注册的模型版本、注册日期和批准状态。

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

来自 AWS 文档 的图表

管道的主管可以查看在前一步中本地保存的评估报告,其中包含所有过去模型评估的历史记录,并根据测试集评估指标确定是否批准或拒绝该模型。稍后,可以设置条件,仅在模型获得批准后更新生产(或 QA)端点。

4. 用新模型刷新多模型端点

SageMaker 具有一个 MultiDataModel 类,允许部署可以托管多个模型的 SageMaker 端点。其原理在于可以在同一个计算实例中加载多个模型,共享资源并节省成本。此外,它简化了模型的重新训练/管理,因为只需更新一个端点以反映新模型并进行管理,而不必在每个专用端点之间重复步骤(这也可以作为替代方案)。MultiDataModel 类也可以用于部署单个模型,如果计划在未来向解决方案中添加更多模型,这可能会很有意义。

在首次训练账户中,我们需要创建模型和端点。MultiDataModel 类需要一个位置来存储可以在调用时加载到端点中的模型工件;下面我们将使用正在使用的 s3 bucket 中的“models”目录。

# Load Container

from sagemaker.xgboost.estimator import XGBoost
xgboost_container = sagemaker.image_uris.retrieve("xgboost", region, "1.2-2")

# One Time: Build Multi Model

estimator = sagemaker.estimator.Estimator.attach('sagemaker-xgboost-220611-1453-011-699894eb')
xgboost_container = sagemaker.image_uris.retrieve("xgboost", region, "1.2-2")
model = estimator.create_model(role=role, image_uri=xgboost_container)
from sagemaker.multidatamodel import MultiDataModel
sagemaker_session=sagemaker.Session()

# This is where our MME will read models from on S3.

model_data_prefix = f"s3://{bucket}/models/"
mme = MultiDataModel(
    name=model_name,
    model_data_prefix=model_data_prefix,
    model=model,  # passing our model - passes container image needed for the endpoint
    sagemaker_session=sagemaker_session,
)

# One Time: Deploy the MME

ENDPOINT_INSTANCE_TYPE = "ml.m4.xlarge"
ENDPOINT_NAME = "<insert here>"
predictor = mme.deploy(
    initial_instance_count=1, instance_type=ENDPOINT_INSTANCE_TYPE, endpoint_name=ENDPOINT_NAME,kms_key='<insert here if desired>'
)

之后,可以按照以下方式引用 MultiDataModel:

model=sagemaker.model.Model(model_name)

from sagemaker.multidatamodel import MultiDataModel
sagemaker_session=sagemaker.Session()

# This is where our MME will read models from on S3.
model_data_prefix = f"s3://{bucket}/models/"

mme = MultiDataModel(
    name=model_name,
    model_data_prefix=model_data_prefix,
    model=model,  # passing our model - passes container image needed for the endpoint
    sagemaker_session=sagemaker_session,
)

可以通过将工件复制到端点将使用的 {s3 bucket}/models 目录,将模型添加到 MultiDataModel 中。我们所需的只是模型包组名称,模型注册表将提供相应的源工件位置和批准状态。

我们可以添加一个条件,仅在模型获得批准后才添加最新模型,如下所示。如果需要立即部署进行数据科学 QA 并最终批准模型,可以在沙箱账户中省略此条件。

# Get the latest model version and associated artifact location for a given model package group

ModelPackageGroup = 'model_package_group'

list_model_packages_response = client.list_model_packages(ModelPackageGroupName=f"arn:aws:sagemaker:{region}:{aws_account_id}:model-package-group/{ModelPackageGroup}")
list_model_packages_response

latest_model_version_arn = list_model_packages_response["ModelPackageSummaryList"][0][
    "ModelPackageArn"
]
print(latest_model_version_arn)

modelpackage=client.describe_model_package(ModelPackageName=latest_model_version_arn)
modelpackage

artifact_path=modelpackage['InferenceSpecification']['Containers'][0]['ModelDataUrl']
artifact_path

# Add model if approved

if list_model_packages_response["ModelPackageSummaryList"][0]['ModelApprovalStatus']=="Approved":
    model_artifact_name='<model_name>.tar.gz'
    mme.add_model(model_data_source=artifact_path, model_data_path=model_artifact_name)

然后,我们可以使用以下函数列出已添加的模型:

list(mme.list_models())

# Output we'd see if we added the following two models
['modela.tar.gz','modelb.tar.gz']

要删除模型,可以在控制台中导航到关联的 s3 目录,并删除其中的任何一个;它们会在重新列出可用模型时消失。

模型在部署的端点中可以通过以下代码进行调用:

response = runtime_sagemaker_client.invoke_endpoint(
                        EndpointName = "<endpoint_name>",
                        ContentType  = "text/csv",
                        TargetModel  = "<model_name>.tar.gz",
                        Body         = body)

在首次调用模型时,端点将加载目标模型,从而导致额外的延迟。在模型已加载的未来调用中,推理将立即获得。在 多模型端点开发指南 中,AWS 指出,当端点达到内存使用阈值时,最近未调用的模型将被“卸载”。模型将在下次调用时重新加载。

当现有模型工件通过 mme.add_model() 或在 s3 控制台中被覆盖时,部署的端点不会立即反映变化。为了强制端点在下次调用时重新加载最新的模型工件,我们可以使用一个技巧,即通过任意新的端点配置更新端点。这将创建一个新端点,需要加载模型,并安全地管理旧端点和新端点之间的过渡。由于每个端点配置需要唯一的名称,我们可以添加带有日期/时间戳的后缀。

# Get datetime for endpoint configuration

time=str(datetime.now())[0:10]+'--'+str(datetime.now())[11:13]+'-'+'00'
time

# Create new endpoint config in order to 'refresh' loaded models to account for new deployments
create_endpoint_config_api_response = client.create_endpoint_config(
                                            EndpointConfigName=f"""<endpoint name>-{time}""",
                                            ProductionVariants=[
                                                {
                                                    'VariantName': model_name,
                                                    'ModelName': model_name,
                                                    'InitialInstanceCount': 1,
                                                    'InstanceType': instance_type
                                                },
                                            ]
                                       )

# Update endpoint with new config

response = client.update_endpoint(
    EndpointName=endpoint_name,
    EndpointConfigName=f"""{model_name}-{time}""")
response

运行此代码后,你会看到关联的端点在控制台中将显示“更新中”状态。在此更新期间,之前的端点将可用,且在新端点准备好后将被交换,此时状态将调整为“服务中”。新添加的模型将在下次调用时加载。

我们现在已经构建了 CI/CD 解决方案所需的三个笔记本 —— 数据准备、训练/评估和端点更新。然而,这些文件目前仅存在于训练 AWS 账户中。我们需要调整第三个笔记本,以便在任何部署的 AWS 账户中工作,在这些账户中将创建/更新相应的端点。

为此,我们可以添加基于 AWS 账户 ID 的条件逻辑。新的 AWS 账户也需要 s3 存储桶来存放模型工件。由于 s3 存储桶名称在 AWS 中需要唯一,因此可以使用这种条件逻辑。此外,这也可以应用于调整端点实例类型以及添加新模型的条件(即审批状态)。

# Get AWS Account ID

aws_account_id = boto3.client("sts").get_caller_identity()["Account"]
aws_account_id

# Set Bucket & Instance Type Across Accounts

if aws_account_id=='<insert AWS Account_ID 1>': 
    bucket='<insert s3 bucket name 1>'
    instance_type='ml.t2.medium'
elif aws_account_id=='<insert AWS Account_ID 2>': 
    bucket='<insert s3 bucket name 2>'
    instance_type='ml.t2.medium'
elif aws_account_id=='<insert AWS Account_ID 3>': 
    bucket='<insert s3 bucket name 3>'
    instance_type='ml.m5.large'
training_account_bucket='<insert training account bucket name>'
bucket_path = 'https://s3-{}.amazonaws.com/{}'.format(region,bucket)

最初创建和部署 MultiDataModel 的步骤需要在每个新的部署账户中重复进行。

现在我们有一个可以引用 AWS 账户 ID 并可以跨不同 AWS 账户运行的工作笔记本,我们将希望设置一个包含这个笔记本(以及可能包含其他两个用于传承追踪)的 git 仓库,然后在这些账户的 SageMaker Studio 域中克隆该仓库。幸运的是,借助 Studio/Git 集成,这些步骤非常直接/无缝,并在以下 文档 中进行了说明。根据我的经验,建议在 SageMaker Studio 外部创建仓库,并在每个 AWS 账户域中克隆它。

对于笔记本的任何未来更改可以在训练账户中进行,并推送到仓库。然后,通过拉取更改,可以在其他部署账户中反映这些更改。确保创建一个 .gitignore 文件,以便仅考虑这三个笔记本,而不是日志或其他文件;其传承将被追踪到 s3。进一步地,应当认识到每次运行笔记本时,控制台输出都会发生变化。为了避免在其他部署账户中拉取文件更改时发生冲突,必须在拉取最新更新之前恢复自上次拉取以来的文件更改。

安排重新训练/重新部署笔记本以按设定的节奏运行

最后,我们可以安排在训练账户中同时运行所有三个笔记本。我们可以使用新的 SageMaker Studio notebook jobs 功能来实现这一点。调度应被视为环境/账户依赖的——即在部署账户中我们可以创建单独的笔记本作业,但现在只是为了用最新的模型更新端点,并在新批准的模型自动部署到沙盒、QA 和生产账户之间提供一些滞后时间。其优点是,解决方案发布后唯一的手动部分变成了在注册表中的模型审批/拒绝。如果新部署的模型出现问题,可以在注册表中拒绝/删除该模型,然后手动运行端点更新笔记本,以恢复到之前的生产模型版本,从而争取进一步调查的时间。在这种情况下,我们将管道设置为按设定时间间隔运行(例如每月/每季度),尽管此解决方案可以调整为基于条件工作(例如数据漂移或生产模型准确度下降)。

结束语

CI/CD 目前是机器学习运维领域的热门话题。这是合理的,因为很多时候对于机器学习解决方案在初次部署后的持续性考虑较少。为了确保生产机器学习解决方案对协变量漂移具有鲁棒性,并且能够在长时间内可持续,需要一个简单而灵活的 CI/CD 解决方案。幸运的是,AWS 在其 SageMaker 生态系统中发布了一系列新功能,使这种解决方案成为可能。本文展示了一种成功实现这一目标的路径,适用于各种量身定制的机器学习解决方案,只需进行一次手动模型验证步骤。

感谢阅读!如果你喜欢这篇文章,关注我以获取我新帖的通知。同时,欢迎随时分享你的评论/建议。

数据处理应用程序的 CI/CD 管道在 Azure 上 第一部分:容器实例

原文:towardsdatascience.com/ci-cd-pipelines-for-data-processing-applications-on-azure-part-1-container-instances-6c8ec9578280?source=collection_archive---------4-----------------------#2023-10-31

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

图像由 AI Comic Factory 生成:huggingface.co/spaces/jbilcke-hf/ai-comic-factory

使用 GitHub Actions 部署 Docker 容器的逐步指南

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

·

关注 发表在 Towards Data Science ·7 分钟阅读·2023 年 10 月 31 日

介绍

手动创建和部署 Azure 及其他云提供商的资源相对简单,在某些情况下可能足够。然而,更多时候,已部署的资源需要随着时间的推移而更改,这反过来需要大量额外的工作来维护和重新部署资源。为了自动化这些任务,开发人员和数据专业人员可以使用基础设施即代码(IaC)方法,并创建用于持续集成和部署(CI/CD)的管道。这种方法使开发人员能够编写代码,自动定义和重新部署资源。

在这份逐步指南中,我们将构建用于数据处理应用程序的管道,以执行以下任务:

  • 配置一个容器注册表

  • 构建并推送 Docker 镜像到注册表

  • 创建一个运行数据处理工作负载的容器实例

  • 启用“托管身份”访问 Azure Key Vault,这样我们的应用程序可以检索到其他资源的访问密钥,例如存储帐户

  • 将上述资源部署到测试环境和生产环境中,并使用不同的触发器来运行管道

入门

为了演示,应用程序本身包括一个非常简单的 R 脚本,该脚本加载一个数据集,打印前几行,并将数据集返回到存储帐户。请记住,应用程序代码对其余的管道并不重要,可以轻松地用你自己的代码替代。

要开始使用,你需要一个 Azure 帐户。你也可能想要在本地系统上安装 Azure CLI。不过,你也可以选择通过 Azure 门户中的 Cloud Shell 运行 Azure CLI 命令。

由于我们的应用程序将数据传输到 Azure Blob 存储并返回,你可能会发现安装 Azure Storage Explorer 很有用,它可以稍微简化文件上传和验证应用程序是否正确运行及返回处理过的数据的过程。

步骤 1:克隆仓库并设置静态资源。

首先,你需要克隆这个仓库。README 文件详细说明了如何使用 RStudio 执行此操作,但你可以自由选择你喜欢的 IDE。

接下来,使用 Azure 门户创建以下资源:

  • 一个资源组,将包含所有其他资源。

  • 一个带有两个文件夹的存储帐户 Blob 容器:一个用于输入文件,另一个用于输出文件。在我们的案例中,这两个文件夹应分别命名为“input”和“output”。在输入容器中存储一个名为“input_data.csv”的小数据集。

  • 一个密钥库,你需要将存储帐户的主要访问密钥作为机密存储在其中。

在第 3 步中,你需要密钥库的名称以及包含主要访问密钥的机密名称。

步骤 2:将 GitHub 链接到 Azure

为了更新 Azure 资源,我们需要授予 GitHub 权限。

首先,使用 Azure CLI 登录到你的 Azure 账户。

az login

然后从 JSON 输出中复制 id 值,这是订阅 id。将订阅 id 粘贴到下面的命令中并运行。这会创建一个具有基于角色的访问控制的“服务主体”,可以视作在使用 GitHub Actions 工作流部署或更新资源时代表你的用户。

az ad sp create-for-rbac \
      --name "your-app-name" \
      --role Owner \
      --scopes /subscriptions/<your-subscription-id>/resourceGroups/<your-resource-group-name> \
      --sdk-auth

复制整个 JSON 输出,前往你的 GitHub 仓库,点击“设置” > “秘密和变量” > “操作”。

创建一个新的仓库秘密并将其命名为 AZURE_CREDENTIALS。将上述命令的 JSON 输出粘贴进去并保存。

第 3 步:修改脚本

在这种情况下,我们正在部署一个简单的 R 脚本,它的功能不多。因此,Dockerfile 也保持非常简单。这两个文件显然需要根据你的要求和首选编程语言进行修改。然而,如果你对这方面不太熟悉,最好先使用现有代码将你的流水线启动运行,然后再应用自己的代码。

如果你选择继续使用当前的 R 脚本 (script.R),你只需修改 {keyvault-name}{access-key-name}{storage-account-name} 的值(省略括号)。

接下来,修改 .github/workflows/ 目录下两个工作流文件 workflow.ymlworkflow_release_prod.ymlenv: 下的以下值:

env:
  RESOURCEGROUP_NAME: my-rg
  REGISTRY_NAME: my-cr
  SHORT_NAME: mycr
  ACI_NAME: my-ci-test
  KV_NAME: my-kv
  ENVIRONMENT: test
  CPU: 1
  MEMORY: 1.5

第 4 步:运行流水线和容器实例

当所有相关更改都已提交到“main”分支时,你应该可以在“操作”窗格下看到你的流水线运行。这是因为工作流设置了分支触发器,使其在主分支更新时运行。

如果没有遇到任何错误,你的容器实例应该在大约十分钟内准备好运行。前往 Azure 门户,找到你的新容器实例并点击“启动”。在日志窗格中,你可能会看到你的脚本在控制台中运行。完成后,验证是否在你的 blob 容器的“output”文件夹中出现了一个名为output_data.csv的新 cv 文件。

就这样!如果愿意,你现在可以手动触发第二个工作流,以创建一个用于生产工作负载的相同容器实例。

要了解 CI/CD 流水线中发生了什么,请阅读以下部分。

理解工作流逻辑

workflow.yml 文件定义了我们流水线中的五个步骤或作业,这些步骤将资源部署到测试环境。

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

作者提供的图片

首先,我们将之前设置的环境变量传递为 outputs,这些变量是后续步骤所需的。

 vars:
    runs-on: ubuntu-latest
    outputs:
      resource_group: ${{ env.RESOURCEGROUP_NAME }}
      acr_name: ${{ env.REGISTRY_NAME }}
      short_name: ${{ env.SHORT_NAME }}
      aci_name: ${{ env.ACI_NAME }}
      kv_name: ${{ env.KV_NAME }}
      environment: ${{ env.ENVIRONMENT }}
      cpu: ${{ env.CPU }}
      memory: ${{ env.MEMORY }}
    steps:
      - run: echo "Exposing env vars"

在第二步中,我们创建或更新现有的容器注册表。请注意,needs 键指示此步骤必须等待前一步完成。uses 键告诉我们此步骤使用了另一个文件,而 with 键用于传递所需的值。我们还需要传递或设置存储库的密钥。

 deploy-acr:
    needs: vars
    uses: ./.github/workflows/deploy_acr.yml
    if: github.ref == 'refs/heads/main'
    with:
      environment: ${{ needs.vars.outputs.environment }}
      resource_group: ${{ needs.vars.outputs.resource_group }}
      acr_name: ${{ needs.vars.outputs.acr_name }}
    secrets:
      azure_credentials: ${{ secrets.AZURE_CREDENTIALS }}

在用于此步骤的 deploy_acr.yml 文件顶部,我们看到脚本在工作流中每次调用时运行,以及我们在 workflow.yml 文件中提供的所需输入。

on: 
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
      resource_group:
        required: true
        type: string
      acr_name:
        required: true
        type: string

    secrets:
      azure_credentials:
        required: true

deploy_acr.yml 的底部,我们有一个多步骤过程运行三个预定义的操作。第一个操作检出代码库,然后我们使用我们创建并存储的服务主体凭据登录 Azure。最后,我们使用名为 azure/arm-deploy@v1 的操作来部署容器注册表。请注意,此步骤使用了 Bicep,这是一个用于配置和部署 Azure 资源的流行语言。在本文底部,你可以找到一些极好的资源来进一步了解 Bicep。

jobs:
  deploy-acr:
    name: Deploy ACR
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - uses: actions/checkout@v2
      - uses: azure/login@v1
        with:
          creds: ${{ secrets.azure_credentials }}
      - name: Deploy bicep
        uses: azure/arm-deploy@v1
        with:
          resourceGroupName: ${{ inputs.resource_group }}
          template: bicep/acr.bicep
          parameters:
            acrName=${{ inputs.acr_name }}
            acrSku=Basic
          failOnStdErr: false

然后,在第三步中使用名为 build_push_container.yml 的文件构建并推送 Docker 镜像到注册表,该文件运行 Azure CLI 命令以检索容器注册表的凭据,以及 Docker 命令以构建和推送 Docker 镜像。

在第四步中,容器实例根据我们的 Docker 镜像进行配置。此步骤通过名为 deploy_aci.yml 的文件进行,该文件使用了名为 ‘azure/aci-deploy@v1’ 的预定义操作。

在最后一步中使用 kv_access.yml 文件,我们授权容器实例通过“受管身份”访问密钥库,这意味着容器可以直接从密钥库中检索密钥,而无需使用访问密钥。为实现这一点,我们需要使用 Azure CLI 命令 az container create 更新已部署的容器实例,并提供我们之前使用的各种参数。此外,我们提供了以下设置:

— assign-identity — scope ${{ steps.rg_id_step.outputs.rg_id }}

最后,你可能已经注意到 workflow.yml 中的以下行:

on: 
  push:
    branches: 
      - main
  workflow_dispatch:

这些行指示了我们的管道应在何时以及在什么条件下运行。在我们的场景中,我们希望当更改推送到‘main’分支时管道运行。此外,我们还希望能够手动运行它。这通过添加 workflow_dispatch: 实现。在 workflow_prod_release.yml 文件中定义的生产管道中,你会注意到生产发布只有一个手动触发。还有许多其他方法可以配置管道运行的触发方式。例如,你可以忽略特定文件或文件夹中的更改,以便只有对应用程序代码的更改会触发新的部署。

进一步阅读

如果你想了解更多关于 GitHub Actions 和 Bicep 的内容,我强烈推荐 MS Learn 平台上的以下资源:

GitHub Actions

learn.microsoft.com/zh-cn/training/modules/introduction-to-github-actions/

learn.microsoft.com/zh-cn/training/modules/learn-continuous-integration-github-actions/

learn.microsoft.com/zh-cn/training/modules/github-actions-automate-tasks/

learn.microsoft.com/zh-cn/training/modules/github-actions-ci/

learn.microsoft.com/zh-cn/training/modules/github-actions-cd/

Bicep:

learn.microsoft.com/zh-cn/training/paths/fundamentals-bicep/

learn.microsoft.com/zh-cn/training/paths/bicep-github-actions/

类别不平衡与重采样:正式介绍

原文:towardsdatascience.com/class-imbalance-and-oversampling-a-formal-introduction-c77b918e586d?source=collection_archive---------12-----------------------#2023-10-07

让我们深入探讨类别不平衡问题,以及诸如随机过采样等重采样方法如何尝试解决这一问题。

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

·

关注 发表在 Towards Data Science ·6 分钟阅读·2023 年 10 月 7 日

最近,我在构建一个名为Imbalance.jl的 Julia 包来解决类别不平衡问题。在构建该包时,我花费了大量的精力阅读论文和查看实现,因此我认为分享我对类别不平衡问题的理解以及一些用于解决该问题的流行算法可能会有所帮助。这些算法包括朴素随机过采样、随机过采样示例(ROSE)、随机游走过采样(RWO)、合成少数类过采样技术(SMOTE)、SMOTE-名义型、SMOTE-名义型连续以及许多欠采样方法。对于这个故事,我们将正式定义类别不平衡问题,并讨论随机过采样作为有效解决方案。在后续文章中,我们将通过考虑其他技术理性地得出更多的解决方案。

目录

∘ 类别不平衡问题

∘ 解决类别不平衡问题

∘ 随机过采样

∘ 为什么要过采样?

∘ 欠采样

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

照片由 Artem KniazUnsplash 提供

类别不平衡问题

大多数(如果不是全部)机器学习算法可以被视为经验风险最小化的一种形式,其中目标是找到参数θ,使得某些损失函数L最小化:

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

例如,线性回归将L定义为平方损失,逻辑回归将其定义为交叉熵损失,SVM 将其定义为铰链损失,自适应提升将其定义为指数损失。

基本假设是,如果f_θ的参数允许它在数据集上最小化该经验风险,而数据集可以视为从总体中随机抽取的样本,那么它应该足够接近我们寻求的目标函数f,我们寻找的模型是使数据集以及整个总体上的相同量最小化。

在具有 K 个类别的多类别设置中,我们可以将经验风险写作

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

当一些类别的样本远少于其他类别时,就会发生类别不平衡问题。在这种情况下,对应于这些类别的术语对总和的贡献最小,这使得任何学习算法都可能找到一个近似解来最小化经验风险,而这个解主要只在显著的和上进行最小化。这会产生一个可能与真实目标f相差很大的假设f_θ,而这些少数类可能是所讨论应用中最重要的。

总结来说,以下是我们有类别不平衡问题的条件:

1 — 训练集中点在各个类别之间的分布并不“公平”;某些类别的点远少于其他类别。

2 — 模型在训练后对这些少数类别的点表现不佳。也就是说,学习算法没有像上面解释的那样适当地最小化少数类别的损失。

这个问题的严重程度取决于这些少数类别对应用程序的重要性。它们往往比多数类别更重要(例如,分类欺诈交易或稀有疾病)。

解决类别不平衡问题

从问题的描述中很明显,一个解决办法是给较小的类别(即少数类别)加权,以便学习算法更容易避免利用它们的不重要性来获得近似解。通常可以很容易地为此目的修改机器学习算法;特别是当它们明确是经验风险最小化的一种形式,而不仅仅是对于某些损失函数的等效形式时。

另一种试图解决问题而不需要对学习算法进行任何修改的方法是重新采样数据。最简单的形式可以看作是赋权的成本敏感方法。考虑以下算法:

给定: 一个不平衡的数据集,包含 K 个类别和每个类别的整数

需求: 一个数据集,其中每个类别的数据根据整数进行复制

操作: 将类别 k 中的每个点重复 c 次,其中 c 是与该类别相关的整数

插入总和时应该很明显,这相当于成本敏感方法;回想一下,最小化一个函数等同于最小化它的标量正倍数。

随机过采样

上述算法存在一个小问题;如果类别 A 有 900 个示例,而类别 B 有 600 个示例,则没有整数倍数可以用来过采样类别 B,使数据集达到完全平衡。我们可以通过随机选择点进行复制,扩展算法以处理非整数的复制比例。例如,如果我们想对类别 B 进行 300 个示例的过采样,以使系统达到平衡(相当于比例为 1.5),我们可以通过…

1 — 从类别 B 中随机选择 300 个点

2 — 复制这些点

这个算法称为朴素随机过采样,它正式的做法是:

1 — 计算每个类别所需生成的点数(根据给定的比例计算)

2 — 假设对于类别 k,这个数字是N_k,然后从属于该类别的点中随机选择N_k个点,并将它们添加以形成新的数据集

显然,这在平均上等同于前述算法,因此也等同于类别权重。如果类别 k 的比例为 2.0,则每个点平均会被随机选择一次。

这是我为三个类别(0、1、2)生成的随机不平衡数据集,展示了类别的直方图以及过采样前后的点的散点图。

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

作者图

请注意,下方的两个图形没有视觉上的差异,因为所有生成的点都是现有点的复制品。

为什么要过采样?

你可能还不太相信重新采样比类别权重在解决类别不平衡问题上更为突出;毕竟,我们已经展示了,朴素的随机过采样可以看作是平均上等同于类别权重的,只是训练时间更长(由于数据量增加)。这个论点唯一的问题是,一般情况下不可能使用类别权重;尤其是,当机器学习模型没有明确最小化损失时。

如果我们通过在数据集中自然地添加每个类别的点来收集更多数据,那么我们获得比朴素随机过采样(或类别权重)更好的结果是有道理的。例如,假设……

  • 我们希望检测一个交易是否为欺诈交易。

  • 我们收集了一个包含 1K 欺诈交易和 999K 有效交易的数据集。

显然,通过收集另外 998K 欺诈交易来解决不平衡问题比重复现有的 1K 交易 997K 次要好得多。特别是,在后者情况下,我们有很高的过拟合特定数据的风险。

现实显然是,通常情况下不可能为少数类收集更多数据;然而,可能可以模拟这样做的效果。也许,如果我们合成生成的数据对于少数类足够代表真实的新例子,那么理想情况下,这比重复例子或类别权重要好得多。这是最常见的过采样形式,其与收集真实数据的关系可能是其优于随机过采样和类别权重的最合理理由;因此,成为解决类别不平衡问题的值得方法。

欠采样

最后请注意,如果我们不是随机选择少数类中的例子来复制,而是随机选择多数类中的点进行删除,那么算法变成了朴素随机欠采样。这显然有丧失有用数据的缺点,但有时从“不是特别有用”的多数类中删除数据可以解决不平衡问题,并导致在“更有用”的少数类上的表现更好。还有其他欠采样方法,可以更仔细地选择排除哪些点,例如为了保持数据结构或允许更好的决策边界。

进一步的故事中,我们解释了最初在Imbalance.jl中实现的所有算法及其如何解决类别不平衡问题。

类别不平衡:探索欠采样技术

原文:towardsdatascience.com/class-imbalance-exploring-undersampling-techniques-24009f55b255?source=collection_archive---------10-----------------------#2023-10-07

让我们了解一下欠采样及其如何帮助解决类别不平衡问题

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

·

关注 发表在 Towards Data Science ·5 分钟阅读·2023 年 10 月 7 日

我们已经正式解释了之前类别不平衡的影响及其原因,并解释了几种能够解决这一问题的过采样技术,如随机过采样、ROSE、RWO、SMOTE、BorderlineSMOTE1、SMOTE-NC 和 SMOTE-N。在这个故事中,我们将尝试对欠采样技术进行类似的探讨,同时假设在之前的解释中,欠采样如何帮助解决不平衡问题已经显而易见。

目录

∘ 简介

∘ 朴素随机欠采样

∘ K 均值欠采样

∘ Tomek 链下采样

∘ 编辑最近邻下采样

介绍

下采样技术通常分为两大类:控制型和非控制型。在控制型技术中,算法接收一个数字,指示最终数据集中应有多少样本;而在非控制型技术中,下采样通常通过简单地删除满足某些条件的点来进行。事先无法知道有多少点会满足这些条件,显然也无法控制。在这个故事中,我们将介绍两种控制型下采样技术(随机和 K-Means 下采样)以及两种非控制型下采样技术(Tomek 链和编辑最近邻)。

天真随机下采样

在这种技术中,如果给定要从类 k 中移除 N_k 点,则会从该类中随机选择 N_k 个点进行删除(也可以随机选择要保留的点,以便移除 N_k 个点)。

下面展示了一个在有三个类 0、1 和 2 的数据中下采样两个主要类的示例。

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

作者使用 Julia 的 Imbalance.jl 包绘制的图

下面是一个动画,展示了不同下采样程度下的输出

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

作者使用 Julia 的 Imbalance.jl 包制作的动画

注意这是一个完全随机的过程;没有做出关于保留哪些点的具体选择。由于此过程,数据的分布可能会严重改变。

K-Means 下采样

我们可以通过更仔细地选择要移除(或保留)的点来保持数据的分布。在 K-Means 下采样中,如果需要为类 k 保留 N_k 点,则执行 K=N_k 的 K-Means 算法,得到 N_k 个最终中心点。K-Means 下采样让这些中心点(或每个中心点的最近邻;这是一个超参数)成为最终的 N_k 个点。由于中心点本身保留了数据的分布,这导致保留数据分布的点集更小。

下面展示了一个在有三个类 0、1 和 2 的数据中下采样两个主要类的示例。

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

作者使用 Julia 的 Imbalance.jl 包绘制的图

注意,相比于随机下采样,这种方法在保持数据结构方面更为小心,这在更多下采样的情况下尤为明显。我们用一个动画进一步说明这一点:

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

作者使用 Julia 的 Imbalance.jl 包制作的动画

注意中心点依赖于初始化,通常涉及随机性。

Tomek 链下采样

这是一种非控制型下采样技术,如果一个点是 Tomek 链的一部分,则可以被删除。如果两个点形成 Tomek 链,则:

  • 它们属于不同的类别

  • 每两个点都是彼此的最近邻

这里的理由是,这些点无法帮助改进决策边界(例如,可能更容易导致过拟合),并且它们可能是噪声。以下是应用托梅克链接的示例:

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

作者使用 Julia 中的 Imbalance.jl 包制作的图

注意下采样后如何更容易找到更线性的决策边界,并且这也使数据更好地平衡。在此过程中,我们跳过了绿色的少数类下采样,并在一个类别的点数接近时停止下采样。

要更近距离地观察这种情况,其中所有类别最终都被下采样,可以参考以下动画:

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

作者使用 Julia 中的 Imbalance.jl 包制作的动画

编辑最近邻下采样

尽管托梅克链接大多是那些无法形成更好决策边界的点或噪声点,并不是所有的噪声点都会形成托梅克链接。如果类别k_1中的一个噪声点存在于类别k_2中的一个密集区域内,那么噪声点的最近邻的最近点可能不是噪声点,这意味着它不会形成托梅克链接。与此条件相比,编辑最近邻下采样默认保留一个点,只有当它的大多数邻居来自同一类别时。也可以选择仅在所有邻居都来自同一类别时保留点,或者在存在来自同一类别的邻居时进行最小下采样。

这个动画展示了算法的实际操作:

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

作者使用 Julia 中的 Imbalance.jl 包制作的动画

注意它如何清除更多不利于决策边界或是噪声的点。如果邻居数 k 或保留条件以正确的方式改变,还可以进一步清除。这是另一种说明效果的动画。

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

作者使用 Julia 中的 Imbalance.jl 包制作的动画

“模式”和“仅模式”条件之间的区别在于,前者保留一个点,只有当它的类别是邻居中最常见的类别之一时;而后者仅在它的类别是唯一最常见的类别时保留点。

这结束了我们对一些有趣的下采样算法的介绍。希望这有助于你更多地了解受控和非受控的下采样。下次见,再见。

参考文献:

[1] 魏超,李志锋,夏汉,& 井尚杰。(2017)。基于聚类的类别不平衡数据下采样。信息科学,409–410,17–26。

[2] 伊万·托梅克。cnn 的两种修改。IEEE 系统、人类与控制论杂志,6:769–772,1976 年。

[3] Dennis L Wilson. 使用编辑数据的最近邻规则的渐近性质。IEEE 系统、人与控制论汇刊,页面 408–421,1972 年。

类不平衡:ROSE 和随机游走过采样(RWO)

原文:towardsdatascience.com/class-imbalance-from-random-oversampling-to-rose-517e06d7a9b?source=collection_archive---------7-----------------------#2023-08-29

让我们正式定义类不平衡问题,并直观地推导解决方案!

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

·

关注 发布于 Towards Data Science ·5 分钟阅读·2023 年 8 月 29 日

在这一系列故事中,我们解释了用于处理类别不平衡的各种重采样技术;特别是那些最初在Imbalance.jl Julia 包中实现的技术,包括朴素随机过采样、随机过采样示例(ROSE)、随机游走过采样(RWO)、合成少数类过采样技术(SMOTE)、SMOTE-名义型、SMOTE-名义型连续以及许多欠采样技术。在这个故事中,我们将假设对类别不平衡问题有一定了解,如之前正式解释的,并解释两种有助于解决这一问题的有趣算法;即 ROSE 和 RWO。

目录

∘ 随机过采样示例(ROSE)

∘ 随机游走过采样(RWO)

随机过采样示例(ROSE)

我们知道,我们收集的任何额外数据都遵循少数类的基础数据分布,那么如何近似这种概率分布,然后从中采样以模拟收集真实示例呢?这就是随机过采样示例(ROSE)算法的作用。

因此,ROSE 试图为每个类别 k 估计概率分布P(x|y=k),然后从中抽取所需的N_k样本。众所周知,估计这种密度的一种方法是通过核密度估计,你可以从更粗糙的版本如直方图分析中推导或直观理解。以下描述了 KDE:

给定: 数据点x 所需: P(x)的估计 操作: 选择一个核函数K(x),然后将*P(x)*估计为

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

通常,我们希望能够控制核函数的尺度(即,压缩或扩展),因为这可以改善对*P(x)*的估计,因此一般而言,我们有

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

从本质上讲,它是将核函数放置在每个点上,然后对它们进行求和和归一化,使其积分为 1。

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

将 KDE 应用于分布估计,作者:Drleft,维基媒体公有领域(许可证

核函数本身是一个超参数;可能,一个已被证明不那么重要的超参数,只要它满足平滑性和对称性等基本属性。简单的高斯核,尺度为σ,是一个常见的选择,ROSE 也使用这种 KDE。

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

正态分布公式中的标准差作为 h,因此未写出

ROSE 从对任何类别 k 的分布估计中抽取N_k点(生成P(x|y=k)),具体操作如下:

  • 随机选择一个点

  • 在其上放置高斯核

  • 从高斯分布中抽取一个点

这与随机过采样类似,只不过在随机选择一个点后,它在该点上放置一个高斯分布,并从高斯分布中采样生成新点,而不是重复选择的点。

在这个过程中,ROSE 使用一个称为 Silverman 的经验规则来设置带宽 h(或者在更高维度中是平滑矩阵,即正态分布中的协方差矩阵参数),以便均值积分平方误差最小化。特别地,

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

其中 D_σ是每个特征标准差的对角矩阵,d 是特征的数量,N 是点的数量。

在 Imbalance.jl 包中,这个值乘以另一个常数s以允许可选控制超参数。对于 s=1,保持原样;对于 s=0,ROSE 等同于随机过采样。以下使用该包生成的动画展示了增加 s 对生成点的影响。

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

作者所绘图。合成点以钻石形状显示。

注意,随着 s 的增加,由每个随机选择的原始点生成的合成点与其距离变得更远。

随机游走过采样(RWO)

当中心极限定理适用时,可以证明只需n个样本,就可以以 95%的概率满足均值估计 x̄=µ±1.96**σ/√n。假设少数类的σ较小(例如,σ=10),并且我们收集了 n=1000 个样本,那么 x̄=µ±0.6的概率为 95%,换句话说,如果我们的估计 x̄足够大,那么基本上 x̄≈µ。类似的论点可以用来证明估计的标准差S_x*将非常接近σ;至少在数据是正态分布的情况下。

这表明可以生成合成数据,以使估计的 x̄和S_x得以保持,以模拟收集新数据。可以证明,如果属于某类 k 的数据中的特征是独立的,其中 x̄是该类所有点的均值,S_x是它们的标准差(都是向量),那么如果通过应用

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

x 是属于某个类别的点;当对所有点进行 k 次这种操作时,会引入 k*n 个新样本。

然后渐近地,这些点不会改变原始的S_x。对于很容易看到,因为当生成的点数 N_k=kn 非常大时,会有sum(x_new)=ksum(x),因为sum®=0。因此,新数据集中包含旧例子和新例子的(k+1)/(k+1)=x̄*,所以均值得以保持。同样可以证明标准差也得以保持。

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

动画由作者制作。钻石形状代表合成生成的点。

动画中展示的实现方法适用于任何比例,通过从需要过采样的类别中随机选择点,而不是遍历所有点。

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

作者绘图

该方法称为随机游走过采样,因为在图中看起来像是通过在现有点上随机行走并放置新点来生成这些点。

希望这个故事能让你对机器学习中的类别不平衡问题及其解决方法有更多了解。让我们考虑 SMOTE 论文中提出的算法,以便了解下一个故事

参考文献: [1] G Menardi, N. Torelli, “使用不平衡数据训练和评估分类规则,” 数据挖掘与知识发现,28(1),第 92–122 页,2014 年。

[2] Zhang, H., & Li, M. (2014). RWO-采样:一种用于不平衡数据分类的随机游走过采样方法。信息融合,25,第 4–20 页。

类别不平衡:从 SMOTE 到 BorderlineSMOTE1、SMOTE-NC 和 SMOTE-N

原文:towardsdatascience.com/class-imbalance-from-smote-to-smote-n-759d364d535b?source=collection_archive---------3-----------------------#2023-08-30

探索四种算法以解决类别不平衡问题

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

·

关注 发表在 Towards Data Science ·12 分钟阅读·2023 年 8 月 30 日

前一篇文章中,我们解释了朴素随机过采样、随机过采样示例(ROSE)、随机游走过采样(RWO)算法的工作原理。更重要的是,我们还定义了类别不平衡问题,并直观地推导了其解决方案。我强烈推荐查看这篇文章,以确保对类别不平衡有清晰的理解。

目录

∘ 简介

∘ SMOTE(合成少数类过采样技术)

∘ BorderlineSMOTE1

∘ SMOTE-NC(SMOTE-名义连续)

∘ SMOTE-N (SMOTE-名义)

介绍

在这个故事中,我们将继续考虑 SMOTE、BorderlineSMOTE1、SMOTE-NC 和 SMOTE-N 算法。但在此之前,值得指出的是我们在上一个故事中考虑的两个算法适合以下实现框架:

  1. 定义算法如何对属于类 k 的数据进行 N_k 个样本的计算,并通过过采样生成这些样本

  2. 给定一些比率超参数,计算每个类需要添加的点数

  3. 对每个类运行算法,然后将所有新增点与原始数据结合起来,形成最终的过采样数据集

对于随机过采样和 ROSE 算法(如果比率足够大,可能也包括随机游走过采样),生成 N_k 个类 k 示例的算法也做了以下操作:

  • 从属于类 k 的数据中随机选择 N_k 个点,允许重复。

  • 对每个选择的点执行逻辑以生成新点(例如,复制或放置高斯分布然后从中采样)

我们将在本故事中考虑的其余算法也适合相同的框架。

SMOTE (合成少数类过采样技术)

因此,要解释 SMOTE 的作用,我们只需回答一个问题:为了生成 N_k 个新的示例,对每个从类 k 随机选择的 N_k 个示例执行了什么逻辑?

答案如下:

  • 找到该点的 k 最近邻(k 是算法的超参数)

  • 随机选择其中一个

  • 从点绘制到随机选择的邻居的线段

  • 随机选择该线段上的一个点

  • 将其作为新点返回

从数学上讲,

  • 如果点 x_i 有最近邻 z_i1, z_i2, …, z_ik

  • 如果 j[1,k] 范围内的随机数

  • 并且 r[0, 1] 范围内的随机数

然后,对于每个点 x_i,SMOTE 通过简单应用生成一个新的点 x_i’

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

这就是 SMOTE 算法所做的全部。从点 x_i 沿向量 z_ij — x_i 行进距离 r,然后放置一个新点。

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

图由作者绘制。黑色示例是合成生成的。

一个小的侧面说明是算法操作方式与论文中呈现的方式有少许差异。特别是,作者假设比率为整数(如果不是,则向下取整)。如果类别 k 的比率是整数 C,则对于每个点,在其内选择一个随机邻居,重复 C 次,然后应用我们描述的 SMOTE 逻辑。实际上,当实现 SMOTE 时,通常将其泛化为按我们描述的浮点比率工作,而是随机选择N_k个点,然后对每个点应用 SMOTE。对于整数比率如 C=2,平均每个点被选中两次,我们回到了原始算法。这应该是有道理的,因为这是从通过重复具有整数比率的过采样到随机过采样的相同转换,这在上个故事中已经解释过了。

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

作者制作的动画

此动画显示了在不平衡的鸢尾花数据集的偏好类别上改变过采样比例时,SVM 的决策区域如何变化。这里的比例相对于多数类的大小。也就是说,比率为 1.0 将N_k设置为使 versicolor 类具有与 virginica 类相同数量的示例。

你可能会想,为什么 SMOTE 比 ROSE 更好。毕竟,SMOTE 生成点的逻辑在论文中并未得到证明;与此同时,从*P(x|y)的估计中进行采样,就像 ROSE 中那样,更为合理和直观。可能的一个问题是获取P(x|y)*的良好估计需要大量数据;然而,我们知道少数类通常数据较少。如果我们没有大量数据,我们有两个选择:

  1. 选择带宽过小,我们回到了可能的过拟合,就像在随机过采样中一样。

  2. 选择带宽过大,在极端情况下等同于从特征空间中均匀添加随机点(即,不现实的示例)。

如果你仔细想想,我们应该更少地担心 SMOTE 中的这个问题。如果存在一个完全线性分离数据的超平面,那么应用 SMOTE 后这个解决方案仍然存在。事实上,SMOTE 生成点的方式可能使非线性超表面变得更加线性化,因此在导致模型过拟合的风险要低得多。

BorderlineSMOTE1

文献中有很多算法只是对 SMOTE 的修改或改进。一个流行的例子是 BorderlineSMOTE1,它应用以下修改:

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

在选择 x_i 时,不是随机从属于该类的所有点集中选择,而是随机从属于该类的边界(论文中称为 DANGER)点集中选择。 如果其 k 个最近邻的大多数,但不是全部,来自大多数/其他类,则该点是边界点。 逻辑上讲,靠近决策边界的点满足此条件,这些点也是决定决策边界或分类模型性能最重要的点。 忽略所有邻居都来自另一个类的点背后的理由是,这些可能是噪音。

另一个变种 BorderlineSMOTE2 在同一篇论文中描述,并且只是修改了用于查找边界点的条件。

以下是在 Julia 中使用 Imbalance.jl 包应用 BorderlineSMOTE1 的示例

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

作者绘制的图表

这是相应的动画:

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

SMOTE-NC (SMOTE-Nominal Continuous)

虽然 ROSE 和 SMOTE 似乎比朴素的随机过采样有显著改进,但它们的缺点是失去了处理分类变量的能力,这对于朴素的随机过采样来说并不是问题。 SMOTE 的作者们足够聪明,想出了一种方法来规避这个问题,通过开发这个 SMOTE 算法的扩展来处理同时存在分类特征的情况。

你可能认为编码分类特征可以绕过这个问题,然而这并不完全正确,因为 SMOTE 或 ROSE 会将它们视为连续的并为其生成无效值。 例如,如果一个特征是二进制的,那么沿线选择的点可能是 0.57,这不是 0 和 1. 将其四舍五入是一个坏主意,因为这等同于随机选择它是 0 还是 1。

回想一下,以下是 SMOTE 生成新点的方式:

  • 假设点 x_i 有最近的邻居 z_i1, z_i2, …, z_ik

  • j[1, k] 中的随机数

  • r[0, 1] 中的随机数

对于每个点 x_i,SMOTE 通过简单地应用公式生成一个新点 x_i’

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

显然,我们无法在存在分类特征的情况下应用相同的方法,除非我们通过回答以下两个问题来扩展它

  1. 如何找到 k 个最近邻? 欧几里得距离度量只在连续特征上运行

  2. 新点是如何生成的?我们不能应用 SMOTE 方程来生成 x_i’ 的分类部分

对于第一个问题,作者建议对欧几里得距离进行修改,以考虑分类部分。假设每个x_iz_ij涉及m个连续特征和n个分类特征,那么在修改后的度量中,连续特征自然被相减并平方,然后对于每对不同的分类特征添加一个常数惩罚。这个惩罚特别是所有连续特征方差的中位数,可以在算法开始时计算出来。

例如,要测量两个点x_1x_2之间的距离

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

如果标准差的中位数是m,则距离由下式给出

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

最后的两个项考虑了最后两个分类特征的不同。

虽然作者没有对度量提供理由,但观察到在分类特征之间测量距离的最常见方法之一是汉明距离。它简单地对每对不同的分类特征加 1。汉明距离为 6 表示两个点在 6 个分类特征上有不同的值。在我们的案例中,将惩罚设置为 1(如同汉明距离中)并不直观,因为如果连续特征经常发生强烈变化,那么 1 的值在总和中将非常微不足道,这等同于忽略分类特征的测量。使用任何两个连续特征之间的平均平方差作为惩罚应该能够解决这个问题,因为如果连续特征的方差通常很大,惩罚也会很大且不可忽略。唯一的问题是作者使用了方差的中位数而不是均值,这可能是由于其对异常值的鲁棒性。

回答第二个问题要简单得多,现在我们已经使用修改后的度量找到 k 个最近邻,我们可以像往常一样使用 SMOTE 公式生成新点的连续部分。为了生成新点的分类部分,简单地取 k 个最近邻分类部分的众数是有意义的。即,让邻居对分类部分的值进行投票,其中最常见的值将占主导地位。

因此,SMOTE-NC 生成新点的过程是……

  • 使用修改后的欧几里得度量找到点的 k 个最近邻(k 是算法的一个超参数)

  • 随机选择其中一个

  • 从该点到邻居在连续特征空间中画一条线段

  • 随机选择线段上的一个点

  • 让这条线段成为新点的连续部分

  • 对于新点的分类部分,取 k 个最近邻分类部分的众数。

SMOTE-N (SMOTE-Nominal)

应该很明显,当没有分类特征参与时,SMOTE-NC 会变成 SMOTE,因为那时惩罚为零,生成中的模式步骤被跳过。然而,如果没有连续特征参与,则算法处于一种不稳定的状态,因为没有定义惩罚,因为没有连续特征。你的解决办法可能是将其设置为 1 或其他值,然后按正常方式操作算法,但这并不理想,因为在计算最近邻居时会容易出现许多平局。如果一个点与另 10 个点之间的汉明距离是 7,它们真的都同样接近那个点吗? 还是它们只是共享在 7 个特征上与该点不同的共同点?

SMOTE-N 是作者在论文中提出的另一种算法,用于处理纯粹分类的数据。它通过在分类特征上采用另一种距离度量来对上述斜体问题作出负面回应。一旦找到 k 个最近邻居,模式计算决定了新点;然而,这次点本身也参与模式计算(投票)。

因此,足以解释在 SMOTE-N 中用于执行 K-NN 的距离度量。该度量称为“修改值距离度量”(Cost & Salzberg, 1993),其操作如下:给定具有 q 个分类特征和每个分类特征分别有 p_1, p_2, …, p_q 个可能值的两个特征向量。

  1. 通过长度为 K 的向量 V 对每个分类值进行编码,其中 K 是类别的数量。V[i]应为该值在第 i 类中的频率除以其在所有类别中的频率。

  2. 现在任何分类向量都由 q 个长度为 k 的向量组成的张量表示。

  3. 通过计算每对长度为 k 的向量之间的曼哈顿距离,然后取结果的 L2 范数,来计算该张量所表示的任意两个分类向量之间的距离。

例如,假设我们要找出以下两个分类向量之间的距离

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

然后给定 3 个类别,编码后假设我们得到了

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

计算每对向量之间的曼哈顿距离后,我们得到

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

这在取 L2 范数后评估为 1.428。

精确地说,论文指出可以使用 L1 范数或 L2 范数来表示大小,但没有决定算法使用哪种(这里我们选择了 L2)。

你可能会问为什么这比使用普通的汉明距离更好。明确的答案是作者并没有做出合理解释。然而,仅为了引入一些直观的理解,我们之前争论了汉明距离在 KNN 的距离计算中可能经常导致许多平局。假设我们有三个分类向量

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

在这里,汉明距离会建议 x_2x_3 距离 x_1 相同,因为两者的汉明距离都是 1。同时,修改值差异度量会先考虑每个值在各个类别中的分布,然后再决定哪个更接近。假设 B2 的类别频率为 [0.3, 0.2, 0.5],B3 为 [0.1, 0.9, 0],B1 为 [0.25, 0.25, 0.5]。在这种情况下,MVDM 会建议 x_3 更接近 x_1,因为 B1 比 B3 更接近 B2。从概率的角度来看,如果我们收集一个类别未知的新点,那么知道该类别是 B2 还是 B3 对于预测类别帮助不大,因此它们在这个意义上是相似的或可以互换的。

因此,总结来说,SMOTE-N 算法生成新点的过程如下:

  • 使用修改值差异度量找到点的 k 近邻(k 是算法的超参数)

  • 返回邻居的类别值的众数(包括点自身)以生成新点

就这样!现在你应该清楚了 SMOTE、BorderlineSMOTE1、SMOTE-N 和 SMOTE-NC 各自的工作原理。我们结束了对所有在 Julia 包 Imbalance.jl 中最初实现的重采样算法的解释系列,并附上了 这篇文章 关于欠采样的故事。

参考文献:

[1] N. V. Chawla, K. W. Bowyer, L. O. Hall, W. P. Kegelmeyer,“SMOTE:合成少数类过采样技术,”人工智能研究杂志,321–357,2002 年。

[2] H. Han, W.-Y. Wang, 和 B.-H. Mao,“Borderline-SMOTE:一种新的不平衡数据集学习过采样方法,”国际智能计算会议,2005 年,页码 878–8871

类别不平衡策略 — 带代码的视觉指南

原文:towardsdatascience.com/class-imbalance-strategies-a-visual-guide-with-code-8bc8fae71e1a?source=collection_archive---------2-----------------------#2023-04-24

了解随机欠采样、过采样、SMOTE、ADASYN 和 Tomek 链接

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

·

关注 发表在 Towards Data Science ·13 分钟阅读·2023 年 4 月 24 日

类别不平衡发生在分类问题中一个类别显著多于另一个类别。这在许多机器学习问题中很常见。例子包括欺诈检测、异常检测和医学诊断。

类别不平衡的诅咒

在不平衡的数据集上训练的模型在少数类别上表现不佳。在最佳情况下,这可能会导致业务损失,如客户流失分析。而在最糟糕的情况下,它可能会蔓延到面部识别系统的系统性偏见中。

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

一个平衡的数据集可能就是缺少的关键(来源:

Elena Mozhvilo 在 Unsplash)

处理类别不平衡的常见方法是重采样。这可能包括对多数类别进行过采样、对少数类别进行欠采样,或两者兼而有之。

在本文中,我使用生动的可视化和代码来说明处理类别不平衡的策略:

  1. 随机过采样

  2. 随机欠采样

  3. 使用 SMOTE 进行过采样

  4. 使用 ADASYN 进行过采样

  5. 使用 Tomek Link 进行欠采样

  6. 使用 SMOTE 过采样,然后使用 TOMEK Link 进行欠采样(SMOTE-Tomek)

我还将在真实世界数据集上使用这些策略,并评估它们对机器学习模型的影响。让我们开始吧。

所有源代码都在这里。

使用 Imbalance-learn

我们将使用 Python 中的imbalanced-learn包来解决类别不平衡的问题。这是一个开源库,依赖于 scikit-learn,并提供在处理不平衡类别分类时的工具。

要安装它,请使用以下命令。

pip install -U imbalanced-learn

数据集

我们使用的数据集是UCI 社区与犯罪数据集(CC BY 4.0),包含 1994 年美国社区的 100 个属性。我们可以用它来预测是否犯罪率高(定义为人均暴力犯罪超过 0.65)。数据来源于 UCI 机器学习库,由 La Salle 大学的 Michael Redmond 于 2009 年发布。

数据集中包含的变量涉及社区,如被视为城市的人口比例和家庭收入中位数,以及涉及执法,如人均警官数量和分配给毒品单位的警官比例。

此数据集存在类别不平衡。对于每一个高犯罪率社区,有 12 个低犯罪率社区。这非常适合我们的案例说明。

>>> from imblearn.datasets import fetch_datasets

>>> # Fetch dataset from imbalanced-learn library 
>>> # as a dictionary of numpy array
>>> us_crime = fetch_datasets()['us_crime']
>>> us_crime

{'data': array([[0.19, 0.33, 0.02, ..., 0.26, 0.2 , 0.32],
        [0\.  , 0.16, 0.12, ..., 0.12, 0.45, 0\.  ],
        [0\.  , 0.42, 0.49, ..., 0.21, 0.02, 0\.  ],
        ...,
        [0.16, 0.37, 0.25, ..., 0.32, 0.18, 0.91],
        [0.08, 0.51, 0.06, ..., 0.38, 0.33, 0.22],
        [0.2 , 0.78, 0.14, ..., 0.3 , 0.05, 1\.  ]]),
 'target': array([-1,  1, -1, ..., -1, -1, -1]),
 'DESCR': 'us_crime'}

我们将把这个字典转换成 Pandas 数据框架,然后分割成训练-测试集。

# Convert the dictionary to a pandas dataframe
crime_df = pd.concat([pd.DataFrame(us_crime['data'], columns = [f'data_{i}' for i in range(us_crime.data.shape[1])]),
           pd.DataFrame(us_crime['target'], columns = ['target'])], axis = 1)

# Split data into train test set
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(crime_df.drop('target', axis = 1), 
                                                    crime_df['target'], 
                                                    test_size = 0.4, 
                                                    random_state = 42)

注意,我们将仅对训练数据集执行欠采样和过采样。我们将不会对测试集进行欠采样和过采样。

数据集预处理

我们的目标是可视化一个不平衡的数据集。为了在二维图中可视化 128 维的数据集,在训练集上进行以下操作。

  • 缩放数据集,

  • 对特征执行主成分分析(PCA),将 100 个特征转换为 2 个主成分,

  • 可视化数据。

这是数据在 2D 中的可视化。

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

作者提供的图片

上述图的代码:

from sklearn.preprocessing import MinMaxScaler
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

# Scale the dataset on both train and test sets.
# Note that we fit MinMaxScaler on X_train only, not on the entire dataset.
# This prevents data leakage from test set to train set.
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

# Perform PCA Decomposition on both train and test sets
# Note that we fit PCA on X_train only, not on the entire dataset.
# This prevents data leakage from test set to train set.
pca = PCA(n_components=2)
pca.fit(X_train)
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)

# Function for plotting dataset 
def plot_data(X,y,ax,title):
    ax.scatter(X[:, 0], X[:, 1], c=y, alpha=0.5, s = 30, edgecolor=(0,0,0,0.5))
    ax.set_ylabel('Principle Component 1')
    ax.set_xlabel('Principle Component 2')
    if title is not None:
        ax.set_title(title)

# Plot dataset
fig,ax = plt.subplots(figsize=(5, 5))
plot_data(X_train_pca, y_train, ax, title='Original Dataset')

预处理完成后,我们准备对数据集进行重采样。

策略 1. 随机过采样

随机过采样通过替换从少数类别中复制现有样本来增加例子。每个少数类别中的数据点有相同的复制概率。

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

作者提供的图片

这是我们如何在数据集上进行过采样的方法。

from imblearn.over_sampling import RandomOverSampler

# Perform random oversampling
ros = RandomOverSampler(random_state=0)
X_train_ros, y_train_ros = ros.fit_resample(X_train_pca, y_train)

让我们比较随机过采样前(左)和随机过采样后(右)的数据。

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

在 Github 上绘图的代码。图片来源:作者

唯一的区别?在随机过采样之后,少数类中的重叠数据点更多。因此,少数类的数据点看起来更暗。

策略 2:随机欠采样

相反,随机欠采样会从多数类中移除现有样本。多数类中的每个数据点被移除的机会是相等的。

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

图片来源:作者

我们可以用以下代码来实现这一点。

from imblearn.under_sampling import RandomUnderSampler

# Perform random sampling
rus = RandomUnderSampler(random_state=0)
X_train_rus, y_train_rus = rus.fit_resample(X_train_pca, y_train)

# Function for plotting is in Notebook.
# Insert link here.

让我们比较随机欠采样前(左)和后(右)的数据。

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

图片来源:作者

欠采样后,数据点的总体数量显著减少。这是因为在类平衡之前,随机移除多数类中的数据点。

将机器学习应用于欠采样和过采样数据集

让我们比较在上面三个数据集(未修改数据集、欠采样数据集和过采样数据集)上训练的分类机器学习模型(SVM 模型)的表现

在这里,我们在三个数据集上训练了三种支持向量机分类器(SVC):

  • 原始数据

  • 随机过采样的数据

  • 随机欠采样的数据

from sklearn.svm import SVC

# Train SVC on original data
clf = SVC(kernel='linear',probability=True)
clf_ros.fit(X_train_pca, y_train)

# Train SVC on randomly oversampled data
clf_ros = SVC(kernel='linear',probability=True)
clf_ros.fit(X_train_ros, y_train_ros)

# Train SVC on randomly undersampled data
clf_rus = SVC(kernel='linear',probability=True)
clf_rus.fit(X_train_rus, y_train_rus)

# Function for plotting is in Notebook.
# Insert link here.

然后,我们可以可视化每个 SVC 从数据集中学到的内容。

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

图片来源:作者

上面的图总结了算法从数据集中学到的内容。特别是,它们学到了:

  • 一个落入黄色区域的新点被预测为黄色点(‘高犯罪率社区’)

  • 一个落入紫色区域的新点被预测为紫色点(‘低犯罪率社区’)

这里有一些观察:

  • 训练在原始数据集上的 SVC…相当无用。它基本上将所有社区预测为紫色。它学会忽视所有黄色点。

  • 训练在过采样和欠采样数据集上的 SVC 的偏差较小。它们更不容易错误分类少数类。

  • 训练在过采样和欠采样数据集上的 SVC 的决策边界有所不同。

使用 ROC 评估重采样模型

为了评估哪个 SVC 最佳,我们将评估 SVC 在测试集上的表现。我们将使用的指标是接收者操作特征曲线(ROC),以找到曲线下面积(AUC)。请搜索(Cmd+F)“附录 1”以了解 ROC 的介绍。

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

图片来源:作者

from sklearn.svm import SVC
from sklearn import metrics
import matplotlib.pyplot as plt

# Helper function for plotting ROC
def plot_roc(ax, X_train, y_train, X_test, y_test, title):
    clf = SVC(kernel='linear',probability=True)
    clf.fit(X_train, y_train)
    y_test_pred = clf.predict_proba(X_test)[:,1]
    fpr, tpr, thresh = metrics.roc_curve(y_test, y_test_pred)
    auc = metrics.roc_auc_score(y_test, y_test_pred)
    ax.plot(fpr,tpr,label=f"{title} AUC={auc:.3f}")

    ax.set_title('ROC Curve')
    ax.set_xlabel('False Positive Rate')
    ax.set_ylabel('True Positive Rate')
    ax.legend(loc=0)

# Plot all ROC into one graph
fig,ax = plt.subplots(1,1,figsize=(8,5))
plot_roc(ax, X_train_pca, y_train, X_test_pca, y_test, 'Original Dataset')
plot_roc(ax, X_train_ros, y_train_ros, X_test_pca, y_test, 'Randomly Oversampled Dataset')
plot_roc(ax, X_train_rus, y_train_rus, X_test_pca, y_test, 'Randomly Undersampled Dataset') 

在原始数据上训练的 SVC 表现不佳。它的表现比我们随机猜测结果还要差。

随机过采样的数据集优于欠采样的数据集。一个可能的原因是,从欠采样过程中移除数据点会丧失信息。相反,过采样不会丢失信息。

现在我们对过采样和欠采样技术有了理解,让我们深入探讨过采样和欠采样。

策略 3. 使用 SMOTE 进行过采样

SMOTE 是一种过采样方法。直观地说,SMOTE 通过在彼此之间插值的少数数据点之间创建合成数据点。

这是 SMOTE 工作的简化说明。

  1. 随机选择少数类中的一些数据点。

  2. 对于每个选定的点,识别其k个最近邻居。

  3. 对于每个邻居,添加一个新点,该点位于数据点和邻居之间的某处。

  4. 重复步骤 2 到 4,直到生成足够的合成数据点。

请搜索(Cmd+F)“附录 2”以查找其创作者对 SMOTE 算法的确切描述。

这是一个可视化。

让我们使用 SMOTE 对数据集进行过采样,并在其上训练一个 SVC。

from imblearn.over_sampling import SMOTE
from sklearn.svm import LinearSVC

# Perform random sampling
smote = SMOTE(random_state=0)
X_train_smote, y_train_smote = smote.fit_resample(X_train_pca, y_train)

# Train linear SVC
clf_smote = SVC(kernel='linear',probability=True)
clf_smote.fit(X_train_smote, y_train_smote)

# Plot decision boundary
# Function for plotting decision boundary is in Notebook
# Link: 

这是结果。

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

作者提供的图像

策略 4. 使用 ADASYN 进行过采样(+它与 SMOTE 的不同之处)

ADASYN 是 SMOTE 的一个变种:SMOTE 和 ADASYN 都通过插值生成新样本。

但有一个关键的区别。ADASYN 会在被 KNN 分类器错误分类的原始样本旁边生成样本。相反,SMOTE 区分了被 KNN 分类器正确或错误分类的样本。

这是 ADASYN 工作原理的可视化。

让我们使用 ADASYN 对数据集进行过采样,并在其上训练一个 SVC。

from imblearn.over_sampling import ADASYN

# Perform random sampling
adasyn = ADASYN(random_state=0)
X_train_adasyn, y_train_adasyn = adasyn.fit_resample(X_train_pca, y_train)

# Train linear SVC
from sklearn.svm import SVC
clf_adasyn = SVC(kernel='linear',probability=True)
clf_adasyn.fit(X_train_adasyn, y_train_adasyn)

# Plot decision boundary
# Function for plotting decision boundary is in Notebook
# Link:

让我们比较 SMOTE、ADASYN 和原始数据集。

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

作者提供的图像

这里有几点观察。

首先,两种过采样方法都会在原始数据点之间创建更多的合成数据点。这是因为 SMOTE 和 ADASYN 都使用插值来创建新的数据点。

其次,比较 SMOTE 和 ADASYN 时,我们注意到 ADASYN 会在少数(黄色)点附近的多数(紫色)数据点创建数据点。

  • 比较上面用蓝色圈出的区域,ADASYN 在只有少数紫色数据点的区域创建了较少的黄色数据点。

  • 比较上面用棕色圈出的区域,ADASYN 在紫色数据点较多的区域创建了更多的黄色数据点。

让我们比较到目前为止我们描述的所有过采样方法的 ROC 曲线。在这个例子中,它们表现同样出色。

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

作者提供的图像

策略 5. 使用汤姆克链接进行欠采样

汤姆克链接是一对非常接近但属于不同类别的点。汤姆克链接的数学定义可以在附录 3 中找到。

这是一个可视化。

要使用汤姆克链接进行欠采样,我们将识别数据集中所有的汤姆克链接。对于汤姆克链接中的每对数据点,我们将删除多数类别。

这里有一个动画,说明了使用汤姆克链接进行欠采样。

我们将对我们的数据集应用汤姆克链接欠采样。

from imblearn.under_sampling import TomekLinks
from sklearn.svm import LinearSVC

# Perform Tomek Link undersampling
tomek = TomekLinks()
X_train_tomek, y_train_tomek = tomek.fit_resample(X_train_pca, y_train)

# Train linear SVC
clf_tomek = SVC(kernel='linear',probability=True)
clf_tomek.fit(X_train_tomek, y_train_tomek)

# Code for plotting graph in notebook.
# Notebook link:

现在让我们比较 Tomek 欠采样和随机欠采样。

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

图片来源于作者

在我们的数据集中,移除 Tomek Link 对缓解类别不平衡几乎没有作用。这是因为数据集中 Tomek Links 的数量有限。

让我们看看 Tomek Link 欠采样的表现与随机欠采样有何不同。

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

图片来源于作者

我们观察到随机欠采样比 Tomek Link 欠采样效果更好。 这是因为 Tomek Link 没有像随机欠采样那样完全消除类别不平衡。

策略 6. SMOTEK:先使用 SMOTE 过采样,然后使用 Tomek Links 欠采样

现在我们已经了解了过采样和欠采样。我们可以将这些技术结合起来吗?

当然!SMOTE-TOMEK 是一种结合了过采样(SMOTE)和欠采样(通过 Tomek Links)的技术。

我们将其应用到我们的数据集上。

from imblearn.combine import SMOTETomek
from sklearn.svm import LinearSVC

# Perform random sampling
smotetomek = SMOTETomek(random_state=0)
X_train_smotetomek, y_train_smotetomek = smotetomek.fit_resample(X_train_pca, y_train)

# Plot linear SVC
clf_smotetomek = SVC(kernel='linear',probability=True)
clf_smotetomek.fit(X_train_smotetomek, y_train_smotetomek)

让我们比较 SMOTE、Tomek 和 SMOTE-Tomek。

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

图片来源于作者

比较 SMOTE-Tomek 和仅 SMOTE,我们可以看到差异被圈出了棕色的圈。SMOTE-Tomek 移除了接近边界的点。

最终,我们将比较上述描述的所有技术。结果是,SMOTE-TOMEK 表现最佳。

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

图片来源于作者

结束

总体来说,你可以使用过采样、欠采样或两者的组合来处理数据不平衡问题。如果你有计算资源,通常更好的方法是使用过采样和欠采样的组合;当数据点较少时,过采样是一种不错的策略;而当有许多类似数据点时,欠采样则表现较好。

处理不平衡数据集并不容易。我鼓励你探索许多其他重采样策略(包括不同的 欠采样方法过采样方法),以查看哪种策略在你的数据集上表现最好。

此外,评估不平衡数据集的性能可能会很棘手。确保使用正确的分类指标。幸运的是,ROC 曲线F1 分数几何均值分数 等指标已经可供使用。

我是 Travis Tang。我在 LinkedIn 和 Medium 上发布数据科学内容。关注我以获取更多内容 😃

附录

附录 1. 使用 ROC 评估类别不平衡问题中的模型

ROC 对类别不平衡不敏感,使其成为评估类别不平衡模型的绝佳工具。它不依赖于类别的普遍性。这与像准确率这样的评估指标形成对比,后者在类别不平衡时可能会产生误导。

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

由 CMG Lee 绘制,基于 commons.wikimedia.org/wiki/File:roc-draft-xkcd-style.svg

ROC 曲线绘制了 y 轴上的真实正例率 (TPR) 对 x 轴上的假正例率 (FPR) 的图像,用于所有可能的分类阈值。TPR 是正确分类为正例的正例实例的比例,而 FPR 是错误分类为正例的负例实例的比例。

一个性能良好的模型将具有接近图表左上角的 ROC 曲线,因为这表示更高的 TPR 和更低的 FPR。一个完全随机猜测的模型将落在 TPR = FPR 的线条上。

附录 2. SMOTE 算法的确切算法

少数类通过取每个少数类样本并沿连接任意/所有 k 个少数类最近邻的线段引入合成样本来进行过采样。根据所需的过采样量,从 k 个最近邻中随机选择邻居。我们目前的实现使用五个最近邻。例如,如果所需的过采样量为 200%,则从五个最近邻中选择两个邻居,并在每个邻居的方向上生成一个样本。合成样本的生成方式如下:取考虑中的特征向量(样本)与其最近邻之间的差异。将此差异乘以一个 0 到 1 之间的随机数,并将其加到考虑中的特征向量上。这会在两个特定特征之间的线段上选择一个随机点。这种方法有效地使少数类的决策区域变得更一般化。 [2]

附录 3. Tomek Links 的定义

给定两个属于不同类别的样本 Ei 和 Ej,d(Ei, Ej) 是 Ei 和 Ej 之间的距离。如果不存在样本 El,使得 d(Ei, El) < d(Ei, Ej) 或 d(Ej, El) < d(Ei, Ej),则 (Ei, Ej) 对被称为 Tomek link。[1]

参考文献

[1] Batista, Gustavo EAPA, Ronaldo C. Prati, 和 Maria Carolina Monard. “A Study of the Behavior of Several Methods for Balancing Machine Learning Training DataACM SIGKDD explorations newsletter 6.1 (2004): 20–29。

[2] Chawla, Nitesh V., 等. “SMOTE: synthetic minority over-sampling technique.Journal of artificial intelligence research 16 (2002): 321–357。

机器学习中的分类:入门

原文:towardsdatascience.com/classification-in-machine-learning-an-introduction-d52595e3dcab

了解机器学习中的分类,看看它是什么,如何使用,以及一些分类算法的示例

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

·发布在 Towards Data Science ·11 分钟阅读·2023 年 2 月 24 日

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

照片由Markus Winkler拍摄,发布在Unsplash

介绍

现在,许多行业处理着各种类型的大型数据集。手动处理所有这些信息可能会耗时,并且从长远来看可能没有增加价值。许多策略,从简单的自动化到机器学习技术,正在被应用以获得更好的投资回报。本概念博客将涵盖一个重要的概念:机器学习中的分类。

我们将首先定义机器学习中的分类是什么,然后阐明机器学习中的两种学习者类型,以及分类与回归之间的区别。接着,我们将介绍一些可以应用分类的实际场景。之后,我们将介绍所有不同类型的分类,并深入探讨一些分类算法的示例。最后,我们将提供几个算法实现的实践机会。

机器学习中的分类是什么?

分类是一种监督学习方法,其中模型尝试预测给定输入数据的正确标签。在分类中,模型使用训练数据进行全面训练,然后在测试数据上进行评估,之后才能用于对新的未见数据进行预测。

例如,一个算法可以学习预测给定的电子邮件是垃圾邮件还是正常邮件(非垃圾邮件),如下所示。

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

作者提供的图片

在深入了解分类概念之前,我们首先了解分类中两种类型的学习者的区别:惰性学习者和渴求学习者。然后,我们将澄清分类和回归之间的误解。

惰性学习者与渴求学习者

机器学习分类有两种类型的学习者:惰性学习者和渴求学习者。

渴求学习者是那些首先从训练数据集中构建模型,然后才对未来的数据集进行预测的机器学习算法。他们在训练过程中花费更多时间,因为他们渴望通过学习权重获得更好的泛化能力,但在进行预测时所需时间较少。

大多数机器学习算法是渴求学习者,以下是一些例子:

  • 逻辑回归。

  • 支持向量机。

  • 决策树。

  • 人工神经网络。

惰性学习者或基于实例的学习者,则不会立即从训练数据中创建模型,这就是惰性特性的来源。他们只是记住训练数据,每次需要进行预测时,他们会从整个训练数据中搜索最近的邻居,这使得他们在预测时非常缓慢。这类学习者的一些例子包括:

  • K 最近邻。

  • 基于案例的推理。

然而,一些算法,如 BallTreesKDTrees,可以用来提高预测的延迟。

机器学习分类与回归

机器学习算法主要分为四大类:监督学习、无监督学习、半监督学习和强化学习。

尽管分类和回归都属于监督学习的范畴,但它们并不相同。

  • 当目标变量是离散的时,预测任务是分类。一个应用是识别一段文本的潜在情感。

  • 当目标变量是连续的时,预测任务是回归。一个例子可以是根据一个人的学历、以往工作经验、地理位置和职位级别预测其薪资。

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

图片由作者提供

机器学习分类在现实生活中的例子

监督机器学习分类在我们日常生活的多个领域中具有不同的应用。以下是一些例子。

医疗保健

在历史患者数据上训练机器学习模型可以帮助医疗专家准确分析他们的诊断:

  • 在 COVID-19 疫情期间,机器学习模型被实施以有效预测一个人是否感染了 COVID-19。

  • 研究人员可以利用机器学习模型预测未来更有可能出现的新疾病。

教育

教育是处理最多文本、视频和音频数据的领域之一。这些非结构化信息可以借助自然语言技术进行分析,以执行不同的任务,例如:

  • 按类别对文档进行分类。

  • 在学生申请过程中自动识别其文档的底层语言。

  • 分析学生对教授的反馈情感。

交通

交通是许多国家经济发展的关键组成部分。因此,工业正在使用机器学习和深度学习模型:

  • 预测哪个地理位置的交通量会增加。

  • 预测由于天气条件可能在特定地点发生的潜在问题。

可持续农业

农业是人类生存的重要支柱之一。引入可持续性可以在不破坏环境的情况下提高农民的生产力:

  • 通过使用分类模型预测哪种类型的土地适合某种类型的种子。

  • 预测天气以帮助他们采取适当的预防措施。

机器学习中的不同类型的分类任务

机器学习中有四种主要的分类任务:二分类、多类别分类、多标签分类和不平衡分类。

二分类

在二分类任务中,目标是将输入数据分类为两个互斥的类别。在这种情况下,训练数据以二进制格式标记:真和假;正和负;O 和 1;垃圾邮件和非垃圾邮件等,具体取决于所处理的问题。例如,我们可能想要检测给定的图像是卡车还是船。

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

作者提供的图片

逻辑回归和支持向量机算法本质上是为二分类设计的。然而,其他算法如 K-Nearest Neighbors 和决策树也可以用于二分类。

多类别分类

多类别分类另一方面具有至少两个互斥的类别标签,其目标是预测给定输入示例属于哪个类别。在以下情况下,模型正确地将图像分类为飞机。

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

作者提供的图片

大多数二分类算法也可以用于多类别分类。这些算法包括但不限于:

  • 随机森林

  • 朴素贝叶斯

  • K-Nearest Neighbors

  • 梯度提升

  • SVM

  • 逻辑回归。

但是等等!你不是说 SVM 和逻辑回归默认不支持多类别分类吗?

→ 没错。然而,我们可以应用如一对一和一对多的二分类转换方法来使本质上的二分类算法适应多类别分类任务。

一对一:这种策略训练的分类器数量等于标签对的数量。如果我们有 3 类分类,将有三对标签,从而得到三个分类器,如下图所示。

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

图片由作者提供

通常,对于 N 个标签,我们将有 Nx(N-1)/2 个分类器。每个分类器在一个二分类数据集上进行训练,最终类别由所有分类器的多数投票决定。一对一方法在 SVM 和其他基于内核的算法中效果最佳。

一对其余:在这个阶段,我们首先将每个标签视为一个独立的标签,并将其余的标签组合成一个标签。对于 3 类,我们将有三个分类器。

通常,对于 N 个标签,我们将有N个二分类器。

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

图片由作者提供

多标签分类

在多标签分类任务中,我们尝试为每个输入样本预测 0 个或多个类别。在这种情况下,没有互斥关系,因为输入样本可以有多个标签。

这种情况可以在不同领域中观察到,例如自然语言处理中的自动标记,其中给定文本可以包含多个主题。类似地,在计算机视觉中,一张图像可以包含多个对象,如下图所示:模型预测该图像包含:飞机、船只、卡车和狗。

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

图片由作者提供

无法使用多类或二分类模型来执行多标签分类。然而,大多数用于这些标准分类任务的算法都有其专门用于多标签分类的版本。我们可以举例:

  • 多标签决策树

  • 多标签梯度提升

  • 多标签随机森林

不平衡分类

对于不平衡分类,每个类别中的样本数量分布不均,这意味着在训练数据中,某一个类别的样本可能比其他类别的样本更多。我们可以考虑以下的 3 类分类场景,其中训练数据包含:60%的卡车,25%的飞机和 15%的船只。

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

图片由作者提供

不平衡分类问题可能出现在以下场景中:

  • 金融行业中的欺诈交易检测

  • 稀有疾病诊断

  • 客户流失分析

使用传统的预测模型,如决策树、逻辑回归等,在处理不平衡数据集时可能效果不佳,因为这些模型可能会偏向于预测样本数量最多的类别,并将样本较少的类别视为噪声。

那么,这是否意味着这些问题就此被抛在了脑后?

当然不是!我们可以使用多种方法来解决数据集中的不平衡问题。最常用的方法包括采样技术或利用成本敏感算法的优势。

采样技术

这些技术旨在通过以下方式平衡原始数据的分布:

  • 基于聚类的过采样:

  • 随机欠采样:从多数类中随机删除样本。

  • SMOTE 过采样:从少数类中随机复制样本。

成本敏感算法

这些算法考虑了误分类的成本。它们旨在最小化模型产生的总成本。

  • 成本敏感决策树。

  • 成本敏感逻辑回归。

  • 成本敏感支持向量机。

深入探讨分类算法

现在我们掌握了实施一些算法所需的所有工具。本节将介绍四种算法及其在贷款数据集(Kaggle 上免费提供)上的实现,以展示之前涉及的一些概念,特别是针对不平衡数据集的二分类任务。为了简单起见,我们将只关注四种算法。

数据集中贷款的分布

  • 查看数据集中的前五个观测值。
import pandas as pd
loan_data = pd.read_csv("loan_data.csv")
loan_data.head()

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

  • 数据集中的借款人概况。
import matplotlib.pyplot as plt
# Helper function for data distribution
# Visualize the proportion of borrowers
def show_loan_distrib(data):
  count = ""
  if isinstance(data, pd.DataFrame):
      count = data["not.fully.paid"].value_counts()
  else:
      count = data.value_counts()

  count.plot(kind = 'pie', explode = [0, 0.1], 

              figsize = (6, 6), autopct = '%1.1f%%', shadow = True)
  plt.ylabel("Loan: Fully Paid Vs. Not Fully Paid")
  plt.legend(["Fully Paid", "Not Fully Paid"])
  plt.show()

# Visualize the proportion of borrowers
show_loan_distrib(loan_data)

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

作者提供的图像

从上面的图形中,我们注意到 84%的借款人偿还了他们的贷款,而只有 16%没有偿还,这使得数据集非常不平衡。

变量类型

在进一步操作之前,我们需要检查变量的类型,以便对需要编码的变量进行编码。

我们注意到,除了需要编码的目的属性之外,所有列都是连续变量。

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

作者提供的图像

# Check column types
print(loan_data.dtypes)

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

作者提供的图像

encoded_loan_data = pd.get_dummies(loan_data, prefix="purpose",   

                                   drop_first=True)
print(encoded_loan_data.dtypes)

将数据分为训练集和测试集

X = encoded_loan_data.drop('not.fully.paid', axis = 1)
y = encoded_loan_data['not.fully.paid']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, 

                                           stratify = y, random_state=2022)

采样策略的应用

我们将在这里探讨两种采样策略:随机欠采样和 SMOTE 过采样。

随机欠采样

我们将对多数类进行欠采样,该类对应于“完全还款”(类 0)。

X_train_cp = X_train.copy()
X_train_cp['not.fully.paid'] = y_train
y_0 = X_train_cp[X_train_cp['not.fully.paid'] == 0]
y_1 = X_train_cp[X_train_cp['not.fully.paid'] == 1]
y_0_undersample = y_0.sample(y_1.shape[0])
loan_data_undersample = pd.concat([y_0_undersample, y_1], axis = 0)

# Visualize the proportion of borrowers
show_loan_distrib(loan_data_undersample)

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

作者提供的图像

SMOTE 过采样

对少数类进行过采样

smote = SMOTE(sampling_strategy='minority')
X_train_SMOTE, y_train_SMOTE = smote.fit_resample(X_train,y_train)

# Visualize the proportion of borrowers
show_loan_distrib(y_train_SMOTE)

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

作者提供的图像

应用采样策略后,我们观察到数据集在不同类型的借款人之间分布均匀。

一些机器学习分类算法的应用

本节将把这两种分类算法应用于 SMOTE 过采样数据集。相同的训练方法也可以应用于欠采样数据。

逻辑回归

这是一个可解释的算法。它通过使用 sigmoid 函数对数据点属于给定类别的概率进行建模来进行分类。

X = loan_data_undersample.drop('not.fully.paid', axis = 1)
y = loan_data_undersample['not.fully.paid']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.15, stratify = y, random_state=2022)
logistic_classifier = LogisticRegression()
logistic_classifier.fit(X_train, y_train)
y_pred = logistic_classifier.predict(X_test)
print(confusion_matrix(y_test,y_pred))
print(classification_report(y_test,y_pred))

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

作者提供的图像

支持向量机

该算法既可用于分类,也可用于回归。它通过使用边际最大化原理来绘制超平面(决策边界)。这个决策边界通过两个最接近的支持向量绘制。

SVM 提供了一种名为核技巧的转换策略,用于将不可分的数据投影到更高维度的空间,使其变得线性可分。

from sklearn.svm import SVC
svc_classifier = SVC(kernel='linear')
svc_classifier.fit(X_train, y_train)

# Make Prediction & print the result
y_pred = svc_classifier.predict(X_test)

print(classification_report(y_test,y_pred))

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

作者提供的图片

这些结果当然可以通过更多的特征工程和微调来改进。但它们已经比使用原始不平衡数据要好。

该算法是一个广为人知的梯度提升树算法的扩展。它不仅是应对过拟合的绝佳选择,而且在速度和性能方面也表现出色。

结论

这篇文章涵盖了机器学习中分类的主要方面,并提供了它们应用于不同领域的一些示例。最后,它介绍了逻辑回归和支持向量机的实现,经过欠采样和 SMOTE 过采样策略来生成平衡的数据集以训练模型。

你可以从我的 GitHub 上获取笔记本

如果你喜欢阅读我的故事并希望支持我的写作,考虑 成为 Medium 会员。每月 5 美元的承诺,你将解锁对 Medium 上故事的无限访问。

你想请我喝杯咖啡 ☕️ 吗?→ 这里请!

欢迎在 MediumTwitterYouTube 上关注我,或者在 LinkedIn 上打个招呼。讨论 AI、ML、数据科学、NLP 和 MLOps 的话题总是很愉快的!

离开之前,请查看以下一些可能对你有帮助的文章:

Pandas 和 Python 在数据科学与数据分析中的技巧 — 第一部分

Pandas 和 Python 在数据科学与数据分析中的技巧 — 第二部分

Pandas 和 Python 在数据科学与数据分析中的技巧 — 第三部分

所有数据科学家和分析师应了解的统计学基础 — 带代码 — 第一部分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值