从招聘经理的角度来看:我在面试中对初级数据科学家的要求是什么
你的技术技能没有你想象的那么重要
89 号仓库在 Canva 上拍摄的照片
作为一名招聘经理,我总是在候选人身上寻找一些关键品质。我希望看到他们是聪明的,能够有效地沟通。此外,候选人必须对数据科学概念有很好的理解——但这并不像你想象的那么重要。最后,我也在寻找候选人有上进心和能够独立工作的迹象。以下是我在面试中寻找的一些具体的东西:
背景:我在一家大型政府机构中管理一个由数据工程师和数据科学家组成的小团队;因此,我们作为一个小单位服务于大量的观众。我对那些多面手的员工有偏见。我承认这些建议并不适合所有人。我们通常不构建工具,而是专注于构建数据驱动的能力,以识别我们监管的行业中的不良行为者。
1.对数据科学概念的理解:你是否很好地掌握了基本概念,如假设检验和机器学习?
毋庸置疑,对于一名数据科学家来说,对数据科学概念的深刻理解是非常重要的。数据科学概念将在工作面试中进行测试,以了解候选人是否具备所需的知识。一些可能被问到的常见问题包括:你如何向没有先验知识的人解释假设检验?有哪些最流行的机器学习算法,你认为这是为什么?通过能够回答这些类型的问题,这将表明候选人在数据科学概念方面有很强的基础,并将能够在他们的新角色中立即投入工作。
然而,正如我在介绍中提到的,至少对我的团队来说,我对这个问题的重视程度没有其他人高。让我解释一下。
2.沟通技巧:你能有效地解释你的思考过程和结果吗?
求职面试中最重要的沟通技巧之一就是有效地解释你的思维过程和结果。对于初级数据科学家角色来说尤其如此,在这种情况下,你的沟通技能将受到测试,以证明你可以与一线员工和团队成员一起工作。为了有效地交流你的思考过程和结果,你需要能够将复杂的概念分解成简单的术语。练习提供一个例子,向不了解数据的观众解释一个复杂的概念或结果。这里的关键词是“实践”
练习提供一个例子,向不了解数据的观众解释一个复杂的概念或结果。例如,如果您正在从事一个涉及预测客户流失的项目,您可能需要向不从事数据科学的人解释流失的概念。要做到这一点,你需要从解释什么是客户流失以及它对企业意味着什么开始。你还需要解释你的团队如何预测客户流失和你的分析结果。
3.动机:你对在我的组织中从事数据科学项目感到兴奋吗?
当在求职面试中被问及为什么想为某个特定的组织工作时,我诚实的回答总是,我对有机会从事能够产生真正影响的数据科学项目感到由衷的兴奋。在我之前的工作中,我是开发数据驱动方法以提高客户满意度得分的团队的一员。例如,你可以说,“我亲眼目睹了我们的工作如何改变了客户的生活,我渴望在我的下一份工作中继续发挥这种积极的影响。鉴于您的数据科学计划的前沿性质,我相信我可以在这个组织中继续成长为一名数据科学家,并为令人兴奋的项目做出最有影响力的贡献。”
4.独立性:你能在没有监督的情况下独立工作吗?
能够独立工作是任何数据科学家的重要技能,无论他们的经验水平如何。在工作面试中,潜在的雇主可能会问你是否能够在没有监督的情况下独立工作。这个问题旨在评估你在没有大量指导的情况下主动完成任务的能力。回答这个问题的最好方法是提供一个你能够成功独立工作的具体例子。例如,你可以提到一个你完全独立完成的项目或者一项你在正常工作职责之外承担的任务。通过给出一个具体的例子,你可以表明你具备雇主所寻求的独立解决问题的能力。
独立工作的一个重要部分是能够有效地管理自己的时间。假设你能证明你有能力在没有持续监督的情况下完成任务。在这种情况下,这将向雇主展示你拥有在数据科学岗位上取得成功所必需的自我激励和自律。
💔-critical-aspects-of-effective-stakeholder-management-for-data-science-projects-b2bf3a472da3>
5.态度:你有正确的态度吗?
众所周知,态度在职场中很重要。你的态度可能是事业成功和一系列没有前途的工作的区别。所以,毫不奇怪,雇主在工作面试中非常重视态度。如果你在面试一个初级数据科学家的职位,这里有一些小技巧可以确保你有正确的态度。
第一,要谦虚。对自己的能力有信心很重要,但你不想给人留下傲慢的印象。记住,你申请的是初级角色。面试官希望看到你愿意学习,并且足够谦虚来接受别人的指导。
第二,积极向上。积极的态度是有感染力的,可以在面试中给人留下好印象。一定要微笑,流露出自信,即使你内心感到紧张。
最后,准备好回答关于你态度的问题。许多雇主会特别询问你的态度,以及这与你申请的工作有什么关系。准备好你积极的态度对工作产生影响的例子。
虽然技术技能很重要,但软技能对数据科学家同样重要。为了在数据科学市场上取得成功,您必须通过展示您能够与其他团队成员有效沟通、独立工作以及有学习新事物的动力来脱颖而出。如果你能在面试中展示这些品质,你将有更好的机会获得这份工作。最后,要想在下一次面试中胜出,记得练习你的回答,因为良好的沟通技巧对任何职位来说都是必须的。
https://ilro.medium.com/membership
从厌恶到激情:如何用 Python 写文档
代码更多的是被阅读而不是被编写
帕特里克·托马索在 Unsplash 上的照片
到无论是谁在读这篇文章,你一定是世界上最关心文档的顶尖工程师之一:)。文档技术从来没有得到开发人员社区的足够重视。
为什么会有这种反感?嗯,写不难,写清楚很难。这适用于所有人,包括开发者。它需要我们组织自己的思想,并清晰地表达出来。通常,一个问题没有单一的解决方案,所以除了写下已经做了什么,我们还需要一个背后的基本原理。而如果你写得不好,只会适得其反。
但是对我来说,这种现象的主要原因是——没有文档不会阻止软件的功能。没有文档的蹩脚代码,只要还能用,还是会出货的。这就像是一笔科技债务,等待着一位先驱将其带到桌面上。对于快速增长的公司来说,它大多被搁置在积压订单的底部。
在这篇文章中,我不想说服你从今天开始处理那些过时的票。然而,我想告诉你一些小技巧,从项目一开始就让这个记录过程变得更容易、更愉快。你可以在你的下一个项目中运用它们,带着一个全新的思维和积极的记录态度。
作为这篇文章的范围,我将讨论记录你的源代码的 4 个步骤。自述文件或图表等一般项目文档不在此范围内。
创建 Python 文档的 4 个步骤
最简单的方法——不要记录任何东西
是的,你没看错。文档的一个大问题是,随着软件的发展,它们会过时。作为一个读者,如果你不断发现文档和代码之间的差异,你会在某个时候放弃阅读它。
这就是为什么自文档化代码的想法脱颖而出。Python 就是一个很好的例子。我想分享两个创建自文档化代码的技巧。
第一个技巧是尽可能多地跟随 Python 习语。Python 被设计成一种高度可读的语言。它更频繁地使用英语关键词,而其他语言使用标点符号。Python 确实带来了很多语法上的好处,所以代码 like 不需要注释。
如果你想更新你的 Python 习语的知识,看看这个 Youtube 视频和我的以前关于写 Python 代码的文章。
使用正确的 Python 习语有助于读者理解代码的最底层。但是为了理解代码在做什么,有必要阅读每一行吗?
这个问题把我们带到了第二个技巧——创建概念模型,从上到下设计代码结构。我们先来看这个例子。
该功能根据乘客的疫苗接种记录和聚合酶链式反应测试检查其是否被允许旅行。尽管代码遵循了 Python 习语,但它却因为放入了太多的信息而让用户陷入了困境。代码可以重构为更清晰的格式。我们来读另一个版本。
很明显,这个版本的台词更多。但是用户关心的仅限于函数is_allowed_to_travel()
,它本身读起来就像一个文档。用户可以决定是否要深入了解细节(例如,检查有效聚合酶链式反应测试的定义)。
如果我们将该功能分成几个逻辑单元,那将是—检索用户疫苗接种数据->验证用户疫苗接种记录->检索用户聚合酶链式反应测试数据->验证用户聚合酶链式反应测试。视觉表现是这样的:
逻辑表示(由高创建)
每个蓝框可能包含低级逻辑单元。经验法则是把你的顶层函数当作一个‘粘合函数’来缝合你的底层逻辑单元。每个逻辑单元都是一个动作。
这给我们带来两个好处。第一,代码可读性更好,并且可以自我解释。第二,通过分离独立的逻辑单元,代码库更易于维护、重用和测试。每当引入新的疫苗接种时,我们只需要改变VaccinationRecord
类,而不需要更新任何其他函数。这也被称为 关注点分离 — 一种将程序分成不同部分的设计模式。
除了分离逻辑,这段代码还创建了几个概念模型,如VaccinationRecord
、PCRRecord
和DBConnection
。每个模型管理其对象周围的属性和行为。我们正在逐渐进入面向对象编程的世界,在本文中我不会叙述太多。但总的来说,OOP 会把一个大问题分解成可解决的小块,这有助于开发者和用户解决或理解问题。
总之,遵循 Python 习语、分离逻辑单元和应用面向对象的设计提高了整体的可读性,从而将您从维护过时的文档中解放出来。
将文档链接到代码
编写自文档代码是一个很大的进步,但它不能解决所有的问题。这有点可悲,因为不是每个人都理解代码,因此开发人员必须用自然语言编写文档并保持更新。
问题是如何绑定文档和代码,使得一方的改变会影响另一方。我们寻求的解决方案是以下两种之一:
- 一个可以基于代码自动生成文档的框架。
- 一个可以基于文档自动生成代码的框架。
对于第一个场景,一个很好的例子是自动生成 Swagger ,这是一组围绕 OpenAPI 规范构建的工具,可以帮助您设计、构建和记录 REST API。许多现有的 Python API 框架如 FastAPI 和 connexion 都支持自动生成 Swagger UI,它描述了你的整个 API,包括端点、参数、认证等。它完全依赖于实际的实现,所以不需要注释或 docstring。
来源:https://swagger.io/tools/swagger-ui/
每次更改 API 设计时,Swagger UI 都会更新。所以开发者不需要担心它的新鲜度。
另一方面,第二个场景引入了一种不同的工作方式,在这种方式中,文档是预先创建的。在敏捷软件开发中,这个过程被称为行为驱动设计(BDD)——一个鼓励软件项目中开发者和企业之间协作的过程。与传统的软件开发不同,BDD 要求开发人员在编码前用结构化的自然语言列出需求。
这种语言被称为小黄瓜,它允许用消费者能够理解的逻辑语言来描述预期的软件行为。在 Python 中, pytest-bdd 实现了 Gehkerin 语言,以支持自动化项目需求测试并促进 bdd。
让我们在 pytest-bdd 中实现上面的例子。开发者首先用 Gherkin 语言描述预期的行为,给出关键字*, When,Then。*
特征文件中的示例
- 给定描述了测试前的前提条件和初始状态——乘客的情况。
- 当描述动作时——检查乘客。
- 然后描述动作的结果——乘客被允许/不被允许。
第二步是为每个语句创建一个测试函数。这是整合发生的地方。该测试将文档与代码连接起来,并确保一方的逻辑变化会影响另一方。
测试代码示例
对于特征文件中的每个语句,必须创建一个测试函数。Python 文件中的文本必须逐字符匹配特征文件。它的主要优点是确保文档的新鲜性和正确性。
我使用 pytest-bdd 大约有 2.5 年了。我发现它在协作主要发生在开发人员和非开发人员之间的环境中非常有用。协作的价值在于最初的头脑风暴会议,而不在于开发人员不断向不同的利益相关者解释事情应该如何运作的后续会议。利益相关者可能会感谢工程师的支持,但在我看来,这是一种浪费的合作,因为时间不是花在创造新东西上,而是花在解释现有东西应该如何工作上。
BDD 的方法鼓励多个涉众在最初的集思广益阶段进行高质量的合作。结果(也称为特征文件)成为程序的输入和商业用户的阅读材料。这将减少不必要的会议。
在本节中,我们看到了集成文档和代码的两种不同方式。目标是确保它的新鲜性和正确性,从而提高开发者和用户之间的协作效率。
Docstring v.s .注释
尽管 BDD 在开发过程中很有帮助,但它的主要目标受众是非技术用户。对于为开发人员设计的程序,编写特征文件可能是一项开销。开发人员通常更喜欢在他们的代码上记录和注释。
在我们深入之前,我们需要区分文档和注释。一般来说,文档向用户描述功能,而注释向维护人员和开发人员描述代码。
根据维基百科的说法,评论有多种用途:
- 规划和评审:在编写实际代码之前,编写伪代码来概述意图。应该在实现完成后删除它。
- 代码描述:总结代码,说明程序员的意图。注意,这可能是代码应该被重构和自我解释的标志。
- 基本原理:解释选择一种技术或算法的原因。
- 标签:添加代码标签,如 TODO、BUG、FIXME。它们也许可以被 IDE 工具搜索到,比如 vscode 中的 Todo Tree。
除了 PEP8 中定义的 72 个字符的最大长度外,评论的格式没有太多限制。另一方面,docstring 有自己的约定,在 PEP 257 中有描述。Docstring 可以进一步分为三类:
- 类文档字符串
- 包和模块文档字符串
- 脚本文档字符串
许多 Python 包中使用了一些众所周知的 docstring 格式。选择哪种格式并不重要,但是在整个项目中应该坚持使用相同的格式。
- reStructuredText :官方 Python 文档标准。这是一种非常丰富的格式,不仅适用于 docstring,还广泛用作文档化的 Markdown 格式。
重构文本的一个例子
- Google docstrings : Google 推荐的文档格式。这也是我最喜欢的格式。
Google docstring 的一个例子
- Numpy docstring: NumPy 的 reStructuredText 和 Google Docstrings 的组合。
Numpy docstring 的示例
可以使用类似于 Pyment 的工具来自动生成 docstring 或将 docstring 从一种格式转换成另一种格式。像 autoDocstring 这样的 Vscode 扩展也能够使用简单的快捷方式创建一个 Docstring 结构。
99%的软件和软件包都有 docstring 和注释,而不管其他格式的文档。一般来说,docstring 和 comments 应该保持简洁,以便于维护,但仍然要足够详细,以便新用户理解如何使用该对象。
Python 文档服务器
最后一步是在 web 服务器上发布 docstring,并使用户可以访问它。因此,用户能够在实际下载软件包之前理解如何使用它。有一些现有的工具可以基于文档字符串自动生成 HTML 文档。
- sphinx :迄今为止最全面的文档生成器。它最初是为 Python 创建的,现在已经将其功能扩展到了多种语言。它读取 reStructuredText 中的 docstring 并生成 HTML 输出。大多数著名的 Python 包都使用它来生成文档,如 Flask 、 Pytest 、 Jinja 等。但是老实说,假设你在一个新的项目上工作,设置需要一些努力。
- pdoc :一个轻量级的文档生成器。它比 sphinx 更简单,因为它不需要任何配置。适合小型项目。但是与 sphinx 相比,它的定制选项较少,因此不适合大型项目。
- Doxygen :另一个支持多种编程语言的文档工具。但是它在 Python 社区中不如 Sphinx 受欢迎,因为它主要不是为 Python 设计的,而且外观不如 Sphinx 好看。
他们产生的输出是 HTML 页面。您可以使用额外的工具,如Read Docs来托管这些静态文件,并将其公之于众。
结论
我们已经讨论了一些技术来使文档化过程变得更加容易和愉快。
编写自我文档化的代码是每个开发人员都应该做的事情。它保持了代码库的整洁,更容易维护和共鸣。Python 开发者应该利用 Python 的语法优势。
使用像 FastAPI 或 pytest-bdd 这样的框架来集成文档和代码。一方的逻辑变化会自动影响另一方,这样我们就可以避免过时的文档。
但是不可避免的是,随着程序变大或公开,开发人员将花费时间为用户和共同维护者编写 docstring 和注释。其目的是告知他人如何使用该物品或故意选择背后的理由。对于新用户来说,重要的是要保持文字简洁,但也要有足够的信息量。
最后但同样重要的是,您希望发布 docstring 以获得更多的读者。Sphinx 和 pydoc 等工具生成静态 HTML 页面,这些页面可以在 Nginx 等 web 服务器上托管并读取文档。
文档不仅仅是为了它而创建的。开发人员必须确保文档是在创造价值,而不是迷惑用户。我希望这篇文章能在一定程度上消除你对文档的厌恶。如果你有更多的建议,请在下面评论并告诉我们。
参考
https://kislayverma.com/programming/how-to-write-self-documenting-code/
从麦乐鸡到数据科学,使用 Python
原文:https://towardsdatascience.com/from-chicken-mcnuggets-to-data-science-using-python-78bd525338e2
梅根·赫斯勒在 Unsplash 上拍摄的照片
你的麦当劳订单将永远不会相同
“你在麦当劳点过 43 块麦乐鸡吗?”
当我第一次听到这个故事时,我完全惊呆了,但事实上,麦乐鸡有一个数学故事,而且非常有趣。
原来你只有几盒 6 、 9 和 20 麦乐鸡。当数学家亨利·皮乔托和他的儿子一起吃饭时,他开始思考他可以用这三个值的组合订购的实际数字。这个数字被称为https://mathworld.wolfram.com/McNuggetNumber.html。
我们将从给出我们正在考虑的离散域的深度细节开始,并最终解决关于它的一个优化问题。** 我们开始吧!**
1.数学问题
我们试图解决的数学问题被称为硬币问题 。这个问题最一般的表述如下:
给定 a1,a2,一个正整数,使得 gcd ( a 1, a 2,…,a)= 1,我们要找出不能表示为这个数的圆锥组合的最大数,也就是说:
我用 LaTeX2png.com 制作的图像
其中 k1、k2 和 kn 为非负整数。那我们的数字是多少?嗯……其实是 43 。
有几种方法可以找到这个结果,但我觉得下面的方法更直观。
我们有以下结果:
我用 LaTeX2png.com 制作的图像
对于所有大于 49 的值,我们可以简单地从这 5 个数字开始,加上 6 的倍数。让我们证明这一点:
给定一个数(大于 50),这个函数给出你需要给 44 到 49 中的一个数加多少个 6。例如,82 是 46+6x6= 6+2x20+6x6=7x6+2x20
很好,但是所有的数字都是真的吗?是的,的确是。这是一个从 50 到 1000 的例子:
好,我们知道不会有大于 43 的麦乐鸡数量。但是 43 是不是我们不能通过组合 6、9 和 20 个麦乐鸡创造出的最大数字呢?
我们来证明一下。
****注意!我确信有比我即将提出的方法计算量更低的方法。尽管如此,由于我们只考虑了最多 43 个麦乐鸡,代码运行速度非常快,不需要任何优化。
我们基本上想做一个超级简单的网格搜索**,搜索所有我们可以选择的可能数量的盒子。**
给定一个特定的数量,我们能做的第一件事就是找出只使用一个盒子可以订购的麦乐鸡的最大数量,而不超过这个数量。我用一个例子来解释最后一句话:****
假设我们想点 23 份麦乐鸡。我们知道,考虑 20x2、9x3 或 6x4 的麦乐鸡块进行网格搜索是没有意义的,因为如果我们考虑 4 盒 6 个麦乐鸡块,我们会得到 24 个,这大于 23,同样的推理适用于 20 和 9。
因此,根据您想要订购的麦乐鸡数量,我们希望找到 6 盒、9 盒和 20 盒的合理范围。然后我们将进行网格搜索,看看我们想要查找的值是否在网格中。要做到这一切,只需运行以下代码:
这里有一个例子:
而且,正如你可能看到的,43 是你不能点的麦乐鸡数量:(
让我们来看看你不能点的麦乐鸡的清单:
而且可以看到, 43 是最大的一个。
2.让我们来谈谈数据科学
我觉得这个问题超级酷。这个整数域的特殊性质是,它不遵循我们在处理连续数时习惯遵循的直觉推理。
如果你有三个整数,前面的系数可以是连续的,你实际上是在玩实定义域。当你强迫系数为整数时,你会得到一个充满“漏洞”的定义域。
但是如果我们想解决这个问题,在这个领域:
“我想尽可能多地吃麦乐鸡,用有限的预算,只用 6 块、9 块或 20 块麦乐鸡做成的盒子”。
最后,我们考虑一个离散线性优化问题。****
我们使用术语“优化”来表示我们:
- 想要最大化某事:那是我们的麦乐鸡数量,
- 我们的预算有一些限制
- 我们模型中的一切都是线性的
- 你不能订购 3.14 盒麦乐鸡,所以这实际上是一个离散的问题
我们希望最大化的功能如下:
x1,x2 和 x3 是你订购的 6,9 和 20 个盒子的数量,图片是我用 LaTeX2png.com 制作的
现在我们知道下面的麦乐鸡是这样的:
作者图片
因此约束变成:
我用 LaTeX2png.com 制作的图像
为了解决这个问题,我们使用了一个名为https://coin-or.github.io/pulp/的库。 最后你会知道,给定你的投入预算:
A.你要吃多少块麦乐鸡(例如 55 块麦乐鸡)
B. 你要吃多少块麦乐鸡(例如一个 6 盒、两个 20 盒和一个 9 盒)
重要的是要说这是最优解。这意味着给定一定的预算,你不能吃得比这个多。很酷吧?😃
下面是实现这一点的代码:
- 安装库:
2.定义问题:
3.您的最佳订单已经准备好了!
例如,如果你有 30 欧元,你可以订购 52 块麦乐鸡,订购 2 盒 20 块麦乐鸡和 2 盒 6 块麦乐鸡。这是你用 30 块钱最多能吃多少麦乐鸡:)
这是沙克的普通午餐:
3.结论
线性(离散)优化是如此有趣。我们倾向于认为线性模型是一个特殊且非常具体的领域,大部分时间都远离现实世界的问题。我希望我用这个有趣的例子向你们展示了,大多数时候,情况恰恰相反:)
如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:
A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。
从数据驱动到数据科学驱动
原文:https://towardsdatascience.com/from-data-driven-to-data-science-driven-f2db93f83d51
数据科学驱动是新数据驱动的三个原因
作者用 Pixabay 的图片创作的图片(左:Momentmal,右:sick-street-photography)
2010 年,当我还在研究生院攻读学位时,我创办了一家小型咨询公司,出售我的数据分析技能。我网站的口号是“数据驱动”就这样。我知道这是原创,但我试图捕捉 90 年代的潮流。
早在 20 世纪 90 年代和 21 世纪初,企业应该更加“数据驱动”的想法就像野火一样蔓延开来。越来越多的证据表明,创造一种数据驱动的决策文化有助于企业在缺乏数据知识的竞争中脱颖而出,越来越多的企业开始要求他们的领导者具备数据素养。
Gartner 和 Forrester 开始开发评估公司“数据驱动”程度的指标。公司开始收集更多的数据,供应商也在兜售能够自动化数据洞察工作流程的产品,这是领导者真正成为数据驱动型决策者所必需的。
然而,今天,数据驱动开始有点过时了。这个概念让人联想到结构化数据集和预制仪表板的图像。在当今的数字世界中,数据产生的速度如此之快,以至于它们很少能够很好地处理结构或洞察力,而是以杂乱的物联网消息流、网站中的嵌入式信息或文件共享中的大量扫描图像的形式出现。
数据驱动并不是不好,只是在当今的商业环境中不够用,需要改进。为了让大大小小的企业能够更好地应对这些新数据源,从而保持相关性和竞争力,学生、领导者和企业家需要开始培养数据科学驱动的思维模式。
在本文的剩余部分,我提供了 3 个理由,说明为什么我认为数据科学驱动的思维模式是我们用数据思考的下一步发展。
超级数字
早在 21 世纪初,数据驱动意味着你擅长使用数据来为决策提供信息。作为领导者,我们面临的最大挑战是利用数据获取洞察力的速度,这将有助于及时做出业务决策。为了实现这一目标,公司花费了大量资金来收集、组织、清理和自动化数据分析,以便在做出决策之前将信息掌握在正确的人手中。
从那时起,世界变得更加数字化,疫情只是加速了技术专家对全球经济数字化的预测。公司看到近 70%的员工在疫情的高峰期远程工作。
再加上脸书宣布建造元宇宙,一个大规模多模式的虚拟体验,我们剩下的是工作世界有史以来最大的数据足迹。
不幸的是,对于旧的数据驱动的思维模式来说,这些新的数字信息来源并没有变得更容易解释和分析。事实上,像物联网消息、互联网和保存的虚拟聊天视频这样的数据源在这个巨大的数字信息海洋中更具代表性,因为它们是非结构化的,非常嘈杂。
但亲爱的读者,不要害怕,因为有一个解决方案可以从这些新的数字流中学习,以解开它们隐藏的秘密,并利用它们不断发展的普遍性,这个解决方案就是数据科学。在当今世界,数据科学驱动的思维方式比单纯的数据驱动思维方式更有价值,这至少有 3 个主要原因。
原因 1:数据科学随处可见数据
过去,数据驱动意味着您能够快速使用数据以及时的方式为决策提供信息。这也意味着,当数据进入您的组织时,您可以应用于数据的结构越多,就越容易获得洞察力并做出明智的决策。
不幸的是,当今世界已经高度数字化,产生的许多信息都是嘈杂的、非结构化的信息,这些信息旨在为用户提供体验,而不是为决策者提供决策数据。因此,尽管在当今的商业环境中,许多领导者都懂数据,但许多人都忽略了这些新的数字信息流中包含的潜在价值。
拥有数据科学驱动的思维模式有助于我们摆脱这种限制,因为数据科学的工具和技术允许我们开始假设我们可能如何从这些非结构化的来源中获得结构。自然语言处理的数据科学领域使我们能够使用聚类分析或潜在狄利克雷分配等统计方法来将非结构化源组织成有意义的组。一旦结构化,就可以利用更传统的分析来支持数据驱动的下游决策,或者支持其他面向数据科学的任务。我们可以从网站到结构化数据集,以支持数据驱动的格式访问信息(见图)。
作者图片
理由 2:数据科学使我们能够预测、分类和识别数据中的可靠信号
仅仅使用数据科学来从非结构化来源中构建结构只是数据科学驱动的思维方式能够改善数据驱动的思维方式趋势的一种方式。更传统地说,数据科学还允许我们超越使用数据作为描述过去发生的事情的方式。数据科学使我们能够估计未来可能发生的事情,组织新数据,并为我们提供一种了解信号是否是真正可靠的信号的方法。
因此,那些发展数据科学驱动思维的人也将有更多的选择来了解数据如何在业务中操作。
形成这种思维模式的人可能会看到,分析和构建与特定公司和/或行业相关的新闻警报源可能会预测未来的股票价格。
培养数据科学驱动思维的人可能会理解,如何根据客户通过电子邮件发送的文档过去的发送历史,将这些文档自动发送给相应的响应团队。
那些发展数据科学驱动思维模式的人将会明白,相对于数字空间中的噪音,他们品牌周围的人口统计情绪差异何时是真正有意义的。
原因 3:数据科学支持更复杂的业务决策自动化
第三个也是最后一个原因是,数据科学驱动思维是对数据驱动理念的改进,是前两个原因的延伸。也就是说,了解数据科学的前景和局限性,可以确保领导者意识到业务决策流程可能会受益于更复杂的自动化。自动化允许我们在决策过程中考虑一些不确定性。
数据驱动在很大程度上与基于规则的思维相关联。基于规则的思考看起来有点像这样:如果这个信号是真的,那么就执行这个业务流程,否则就执行另一个流程。
数据科学驱动使我们在决策时更加细致入微。相反,我们认识到,如果对某件事情的真实性有 90%的信心就足以自动做出决定,那么数据科学就给了我们承担这种风险的方法。
数据科学如何做到这一切?统计数据
数据科学及其相关工具和技术能够做到这一切的主要原因与该领域的统计基础有关。统计学允许我们通过在那些信号周围建立噪声模型来在噪声数据中找到信号。然而,大多数领导者并不知道这种努力的价值,因为大多数统计学教授的重点是数学,而不是统计思维能让 https://iase-web.org/documents/papers/icots6/5b1_john.pdf?实现的思维方式 1402524962 。也就是说,传统上统计学没有得到很好的应用。另一方面,数据科学已经取得了如此大的成功,因为它的基础是从应用中诞生的。因此,begin data science driven 进一步鼓励和支持对统计思维的应用理解。
结论
所以,最后,我想引用 Samuel S. Wilks 的一句话,他在 1951 年向美国统计协会发表演讲时解释了赫伯特·乔治·威尔斯的话:
“总有一天,统计思维会像读写能力一样成为高效公民的必要条件!”
虽然我们在对待社会世界的方式上可能没有实现这样的社会进化,但商业世界为我们提供了自己的压力来推动思想的信封。数据驱动的思维减弱;数据科学驱动思维万岁!
比如参与学习数据科学、职业发展或糟糕的商业决策?加入我。
从数据科学到碳足迹合规:探索 TinyML 的世界
使用 TensorFlow Lite Micro
图由 itemis AG,https://info . item is . com/IOT-systems/download-tinyml-rock-paper-scissors-dataset/(经许可)
摘要
你想扩展你在人工智能方面的专业领域,并想探索一种更节能的机器学习(ML)方法。本文将向您介绍微控制器上的 ML(MCU),也称为微型机器学习(TinyML)。准备好在剪刀石头布上输给 MCU 吧。您将涉及数据收集和预处理、模型设计以及如何让您的模型在 MCU 上运行。我们的例子为您提供了自始至终完成您自己的 TinyML 项目所需的一切。
什么是 MCU
MCU 代表微控制器单元。MCU 具有连接到各种输入和输出引脚的弱处理器。与你的电脑不同,MCU 没有完整的操作系统,一次只能处理几个进程。MCU 还具有少量内存和 RAM。
对于我们的项目,来自 Espressif 的 ESP-EYE 板是理想的。该板将 ESP32 微控制器与已经连接的摄像头捆绑在一起,为我们节省了一些工作。
我为什么要在乎 TinyML?
像 DeepMind 和 OpenAI 这样的科技公司凭借专家和 GPU 的力量主导了 ML 领域。特别是自然语言处理(NLP)中的模型,如 GPT-3,需要几天的时间来并行使用几十个高性能 GPU 进行完整的训练周期。这伴随着高能耗,并且随着 NLP 模型每年进一步增长,它们对能量的需求也在增长。开发成本是单个训练周期的数倍,并且需要额外的计算时间来优化超参数。TinyML 通过变小来扭转局面。由于内存限制,大型人工智能模型不适合微控制器。下图显示了硬件要求之间的差异。
图由 itemis AG,https://app.hubspot.com/documents/761475/view/277264732?accessId=dc8033
与在云中使用人工智能服务相比,MCU 上的 ML 提供了哪些优势?我们发现您可能希望使用 TinyML 的七个主要原因。
成本
购买和运行微控制器都很便宜。
环保 在微控制器上运行 AI 几乎不消耗能源。
集成 微控制器可以轻松集成到现有环境中,例如生产线。
隐私和安全 数据可以在本地设备上处理。数据不一定要通过互联网发送。
快速原型 TinyML 使您能够在短时间内开发出概念验证解决方案。
自主可靠 微型设备可以在任何地方使用,甚至在没有基础设施的时候。
实时 数据在微控制器上无延迟处理。唯一的限制是 MCU 的处理速度。
你可能想知道这些点有多大,尤其是在能源消耗方面。本地加工真的这么重要吗?甚至一个谷歌搜索消耗的能量相当于给一个 60 W 的灯泡供电 17 秒。TinyML 的有效性被 Siri、Google Assistant 和 Alexa 等语音助手所利用,其中唤醒词识别在本地进行。最近,iOS 上的听写功能也可以在本地将语音转录为文本。那是 TinyML 在行动。从更大的角度来看,随着更多智能设备的上线,TinyML 是不可避免的。产生、共享、消费或存储的数据量呈指数级增长。2010 年,这一数字达到了 2 千兆字节(ZB),预计到 2025 年将增长到 181 千兆字节。TinyML 正好符合全球可持续发展的努力。
石头剪刀布
作者提供的数据
你曾经在石头、布、剪刀和人工智能的比赛中输过吗?还是想通过打败一个 AI 来打动朋友?您将使用 TinyML 与 ESP-EYE 板进行游戏。这个用例很好地概述了 TinyML 的功能。开发的模型使用卷积层,因此您将了解在 TensorFlow Lite Micro 中使用卷积层的复杂性。您也可以调整我们的项目来识别您的猫!这个项目也将展示 TinyML 在准确性方面的局限性。你需要采取五个步骤来实现你的项目。以下部分提供了必要步骤的高级概述。如果您想更深入地了解一下,请查看我们项目库中的文档。它解释了漂亮的细节。
收集数据
收集好的数据是 ML 的关键部分。为了让事情运转起来,你需要拍摄你的手形成石头、布、剪刀手势的图像。越独特的图像越好。人工智能将学习你的手可以在不同的角度,位置或灯光变化。数据集包含记录的图像和每个图像的标签。
最好使用同样的传感器和环境来运行你的人工智能,也用来训练它。这将确保模型熟悉传入的数据。例如,考虑温度传感器,由于制造差异,对于相同的温度具有不同的电压输出。就我们的目的而言,这意味着用 ESP-EYE 摄像机在统一的背景上记录图像是理想的。在部署期间,人工智能将在类似的背景下工作得最好。你也可以用网络摄像头记录图像,但可能会损失一些准确性。由于单片机的能力有限,我们记录和处理 96×96 像素的灰度图像。收集数据后,我们将数据分为训练集和测试集。
作者照片
按照上面的步骤,你收集的图像应该看起来像这样。如果你现在不想收集数据,你可以在这里下载我们现成的数据集。
预处理数据
在我们的数据集中,我们使用 ESP-EYE 和网络摄像头记录图像。由于 ESP-EYE 可以捕获分辨率为 96×96 的灰度图像,所以我们不需要在这里做进一步的处理。然而,我们需要将网络摄像头图像缩小并裁剪为 96×96 像素,并将它们从 RGB 转换为灰度格式。最后,我们归一化所有的图像。下面,你看到我们处理的中间步骤。
作者照片
设计一个模型
由于我们正在处理图像处理,卷积层对我们的模型至关重要。因为 MCU 上的内存非常有限,所以我们不能使用深度架构。即使是为边缘设备设计的型号,如 MobileNet 及其后继产品也太大了。因此,我们的模型依赖于三个卷积层模块,包括卷积、批量归一化和最大池。用 L2 和 L1 正则化来正则化卷积层,以减少过拟合。通常,我们使用 ReLU 激活。
在第三卷积块之后使用 9 个神经元的密集层。最后,是一个密集的 softmax 层。
超参数
我们使用随机搜索来调整超参数。与其他超参数优化方法相比,随机搜索易于实现、理解、并行化,并且搜索可以随时停止和恢复。使用随机搜索,我们为 100 个模型训练了 20 个时期,每个时期的挂钟持续时间为 10 小时。一个有趣的结果是 SGD 优化优于 Adam。我们知道,亵渎。搜索还应用于正则化参数、卷积滤波器的数量、内核大小和步幅以及学习速率。
转换模型
在训练我们的模型之后,我们获得了张量流格式的 AI 模型。因为 ESP-EYE 不能解释这种格式,我们将模型转换成微处理器可读的格式。我们从转换成 TfLite 模型开始。TfLite 是一种更紧凑的 TensorFlow 格式,它使用量化来减小模型的大小。TfLite 通常用于世界各地的边缘设备,如智能手机或平板电脑。最后一步是将 TfLite 模型转换为 C 数组,因为微控制器不能直接解释 TfLite。
嵌入式环境
在本节中,我们将讨论在 MCU 上运行的代码。你可能知道微控制器通常是用 C/C++编程的。嗯,有 MicroPython ,但那是另一个故事了。在继续之前,你至少应该对 C/C++有一个基本的了解。有大量有用的教程和初学者指南,可以学习一些人称之为所有编程语言之母的东西。
让我们看看在 MCU 上会发生什么。在下图中,您可以看到我们代码的结构。我们从读取相机传感器的原始数据开始,稍后我们可以将这些数据提供给模型。然后,我们将用于训练数据的相同预处理应用于输入的原始数据。之后,我们将预处理后的数据传输到主函数,在这个函数中,预测由 TensorFlow Lite Micro 库完成。由于我们使用 softmax 层,最大概率是给定图像的预测类。为了提高准确性,我们在短时间内拍摄 5 幅图像,以进行整体预测。最后一步是模型自己采取行动。
作者提供的数据
为了充分理解 C/C++方面发生了什么,我们建议您看一下代码。为此,我们想给你指出正确的方向。由于 C++程序是从 main.cpp 文件开始的,所以这可能是您希望所有内容都集中在一起的地方。但是,您应该查看 main_functions.cpp 及其循环函数。该功能在无限循环中执行,也称为超级循环,不断重复上图中的步骤。
部署模型
现在我们可以将我们的模型部署到微处理器上。在我们构建(编译)和刷新 C++程序之前,我们需要放置新的 C 数组,它将我们的模型编码到目标文件 micro_model.cpp 中。替换 C 数组的内容,不要忘记替换数组长度变量 micro_model_len。我们提供了脚本 model_to_mcu.py 来简化这个过程。就是这样!
结论
通过这篇文章,我们希望为您带来机器学习的新视角。大数据、云部署和昂贵的培训并不是数据科学的唯一发展方向。TinyML 减少了 AI 模型的碳足迹,并搭建了一座通往嵌入式系统和物联网世界的桥梁。边缘计算启发我们提出比云或桌面 PC 更自然的人工智能部署。TinyML 并非没有挑战,例如 C 和 C++的流行以及 TensorFlow Lite Micro 与经典 TensorFlow 相比的功能不完整性。
展开示例
挑战一下怎么样?人生的新目标?想打动老朋友还是找新朋友?通过添加蜥蜴和斯波克,将石头、剪子、布带到下一个级别。你的 AI 朋友将会是一个更接近统治世界的技能。嗯,首先你应该看看我们的石头、布、剪刀库并且能够复制上面的步骤。自述文件将帮助您了解详细信息。下图解释了扩展游戏的规则。你需要添加两个额外的手势和一些新的输赢条件。
照片由 itemis AG,https://info . item is . com/IOT-systems/download-tinyml-rock-paper-scissors-dataset/
开始你自己的项目
如果你喜欢这篇文章,并想开始自己的项目,我们为你提供了一个项目模板,使用相同的简单管道作为我们的石头,布,剪刀项目。你可以在这里找到模板。不要犹豫,通过社交媒体向我们展示你的项目。我们很好奇你能创造什么!
你可以在这里和那里找到更多关于 TinyML 的信息。皮特·沃顿的书是一个很好的资源。
参考
- 谷歌搜索的能源成本。访问时间:2022 年 10 月 26 日。
https://business . direct energy . com/blog/2017/11 月/powering-a-google-search - 创建数据的增长。访问时间:2022 年 10 月 26 日。
https://www . statista . com/statistics/871513/world wide-data-created/
从开发到部署:包含 MLflow、SageMaker 和 Streamlit 的端到端情感分类器应用
在本教程中,我们将从 DagsHub-MLflow 开始构建一个 NLP 应用程序,然后在 SageMaker 和 EC2 中进行部署,前端在 Streamlit 中。
图片由 Unsplash 上的 Yoann Siloine 拍摄
目录
— 1。设置 DagsHub repo 和需求
—创建您的 DagsHub repo
—设置虚拟环境
—用 DVC
— 2a 下载数据。在 MLflow 中启动您的第一个实验
—朴素贝叶斯模型作为情感分类的骨干
—建立 DagsHub MLflow 并运行实验
— 2b。做一个更通用的代码来核算不同的型号
— 3。在 MLflow 中注册您的模型并部署到 SageMaker 端点
—将模型添加到 MLflow 注册表
—设置 AWS IAM 角色以从 MLflow
部署— 将您注册的模型部署到 AWS SageMaker
— 4。在 EC2 实例上部署一个 streamlit 应用程序,并通过您的仪表板运行预测
—创建一个简单的 Streamlit 仪表板应用程序
—将您的仪表板部署到 EC2 实例
— 优点、缺点、局限性、未来要做的工作—
—结论
— 支持我的写作
欢迎来到这个关于机器学习的新教程。今天我们将使用以下工具开发一个完整的端到端应用程序,从模型开发到模型部署:DagsHub、MLflow、AWS SageMaker、AWS EC2 和 Streamlit。特别是,我们将使用 DagsHub 作为我们的 GitHub repo,因为它提供了 MLflow 和数据版本控制dvc
的集成版本。通过这种方式,我们不必在云上设置新的 MLflow 服务器和存储桶,因为一切都已准备好用于我们的新模型实验。
我们将实施情感分类模型,这是我们必须处理的工作的大纲:
- 我们将探讨如何建立 DagsHub 回购以及我们需要什么要求。
- 我们将致力于一个 tweet 情感数据集,分析不同的
sklearn
模型,并将在 MLflow 中跟踪它们。 - 一旦我们学会了如何比较模型,我们将跳到 AWS SageMaker 上的 MLflow 部署端。我们将回顾 IAM 用户和角色以及端点创建
- 最后,我们将把我们的分类模型包装在一个 Streamlit 应用程序中,托管在一个 EC2 实例上。
1.设置 DagsHub 回购和要求
在这里你可以找到我今天要处理的所有相关代码。
创建您的 DagsHub repo
图 1:一键创建一个新的 DagsHub repo。
图 1 显示了如何在 DagsHub 中创建一个 repo。只需点击你的个人资料图片旁边的“创建”按钮,然后给回购提供一个名称和描述,你就可以开始了。一旦创建了回购,与 Github 不同的是,您会看到更多的特性。如果你点击“远程”,窗口会显示 DagsHub 提供的 3 种服务:Git、DVC 和 MLflow。
设置虚拟环境
对于这个项目,我强烈建议你使用虚拟环境。因此,用以下代码克隆您的 DagsHub 存储库
git clone [https://dagshub.com/stefanobosisio1/sentiment_mlflow.git](https://dagshub.com/stefanobosisio1/sentiment_mlflow.git)
并创建一个 Python venv
在你的终端python -m venv venv
中键入这个命令将创建一个venv/
文件夹。使用venv/bin/pip install --upgrade pip
将pip
升级至最新版本
和 DVC 一起下载数据
正如我之前提到的,DagsHub 提供了一个基于dvc
的数据版本系统——你可以在这里找到更多信息。简而言之,DVC 是一个出色的 Python 工具,它允许您保持对数据的控制和版本。
我们将使用下面的数据。这些是来自 Twitter 的无版权数据,CC0 1.0 许可证,可从这里公开获得。在 Python: venv/bin/pip install dvc
中安装dvc
,并使用:venv/bin/dvc init
在终端dvc
中的存储库文件夹中初始化
现在你已经准备好克隆split-data
文件夹了:
venv/bin/dvc get https://dagshub.com/nirbarazida/tweet-sentiment-analysis-data split-data/
我们已经准备好第一次提交 DagsHub——注意我们是如何使用dvc
提交的:
venv/bin/dvc add split-data
git add .gitignore split-data.dvc
git commit -m "A NICE MESSAGE FOR COMMIT"
git push origin
2a。在 MLflow 中启动您的第一个实验
我们已经准备好处理 MLflow 了。首先,让我们用一个非常简单的朴素贝叶斯分类器为我们的代码创建一个主干,来学习如何构建模型和 MLflow 设置
作为情感分类骨干的朴素贝叶斯模型
在这里你可以找到代码。我们将尝试获取整个工作流的精髓,而不是深入数据科学的本质,因此我们将只使用这些文件:split-data/X_train
和split-data/y_train
。首先,我们需要预处理我们的数据,并清除它们:
- 停用词,如
and, but, a, an...
- 标点
- 特殊字符,如标签、标记、换行符或撇号
在 99%的情况下,这是每个 NLP 项目的第一步。因此,我们只需要三个简单的函数:remove_stopwords
、remove_punctuation
和remove_specific_chars
:
图 2:文本清理功能:用 NLTK 删除停用词,用 string 模块删除标点符号,而特定字符删除标签、新行以及撇号。
每个函数接收给定的文本作为输入,并创建一个新的outline
字符串。此外,在预处理之前,我们要将输入数据帧中的所有字符串小写,如图 3 所示:
图 3:输入文本的预处理和清理。
在设置 MLflow 之前,让我们完成第一个朴素贝叶斯分类器下的工作流(图 4)。在预处理位之后,数据可以分成训练集和验证集。要将字符串转换成数字,需要调用sklearn
矢量器(如CountVectorizer
或TfidfVectorizer
)。矢量化之后,输入数据可以被分类器读取,MultinominalNB
,我们可以继续进行训练和度量。
图 4:全模型循环。数据被清理,然后分成训练集和验证集。输入字符串用 CountVectorizer 进行矢量化,然后传递给朴素贝叶斯模型进行分类。
设置 DagsHub MLflow 并运行实验
要设置 DagsHub MLflow 服务器,我们需要来自 DagsHub 的跟踪 uri、跟踪用户名和密码。为什么?
- 跟踪 uri 是 MLflow 服务器的 url,工件将被报告到该服务器。我们需要这些信息来建立连接
- DagsHub 需要跟踪用户和密码来验证我们的实验并访问 MLflow 服务器
在您的 repo 中,单击远程按钮,您将找到所有需要的信息,如图 5 所示。
图 5:跟踪 uri、用户名和密码(隐藏)以设置 DagsHub MLflow 跟踪。
您可以将这些信息复制到一个setup_mlflow.txt
文件中,并在我们的主代码中解析它。然后,图 6 显示了如何在您的代码中设置 MLflow 跟踪,以及 MLflow 如何集成到您的主干代码中——记住在这里您可以找到完整的代码
图 6:模型代码中 MLflow 的设置。
简而言之,这些是 MLflow 用于跟踪实验的关键要素:
- 通过
mlflow.set_tracking_uri(mlflow_tracking_uri)
建立与 MLflow 服务器的连接 - 设置一个实验,如果已经存在
mlflow.create_experiment
和mlflow_client.get_experiment_by_name
,则检索其id
- 用上下文管理器
with mlflow.start_run(...)
开始实验 - 尽可能多地利用ml flow 自动日志功能,比如
mlflow.sklearn.autolog(...)
。自动记录功能使用 Python 模块inspect
跟踪实验以及为不同“风格”的模型(如sklearn
、torch
等)生成的人工制品和物体。) - 用
mlflow.end_run()
结束你的实验
实验运行后,您可以在 MLflow UI 中可视化指标和工件,可以通过两种方式访问:
- 将
.mlflow
添加到您的 DagsHub 回购协议中(例如【http://dagshub.com/stefanobosisio1/sentiment_mlflow.mlflow】T4 - 或者单击“远程”,并在“MLflow”部分下单击“转到 mlflow UI ”(图 5)
图 7 显示了 MLflow UI 应该是什么样子。通过点击“开始时间”,您将访问关于您的模型的更多信息,比如模型的参数、度量、标签和工件。在 artefacts 框中,您会注意到一个model
文件夹,它存储由 MLflow 自动生成的文件,以便在预测时调用您的模型,例如 condo 环境、python 需求和二进制文件。所有这些都在两行简单的代码中!
图 7:使用朴素贝叶斯运行第一个测试后的 MLflow UI 示例。
2b。编写一个更通用的代码来考虑不同的模型
通常最好的做法是有一个通用的代码,以考虑不同的场景和不同的模型。出于这个原因,我们将把我们的朴素贝叶斯代码发展成一个更通用的代码,在这里我们可以选择不同的单词矢量器,以及不同的模型。在这里你可以找到参考代码
第一件事是将我们所有的预处理函数和模型转换成一个sklearn
管道:
图 8:使用清理函数和情感分类器返回 sklearn 管道的函数。
在选择了我们想要使用的模型和矢量器之后,pipeline
就创建好了。[PreprocessTweets](https://dagshub.com/stefanobosisio1/sentiment_mlflow/src/main/multiple_models.py#L44)
现在是一个类,它包含了我们在上面中创建的所有清理函数。为了设置它,我们需要记住导入sklearn.base.BaseEstimator
和sklearn.base.TransformerMixing
,并在类定义中继承这些方法。核心功能在fit_transform
函数中,其中输入数据帧列text
被清理并作为numpy
数组返回,因此它可以被矢量器步骤接收。
第二步是拥有一个解析器功能,例如用argparse
图 9: Argparse 处理不同的输入,有一个更通用的接口。
通过这种方式,可以处理不同的模型,扩展代码并并行运行。
图 10:设置 MLflow 参数,直接调用跟踪器,安装管道并保存所有内容。
图 10 显示了概括的最后步骤。给定输入的解析参数,我们现在可以为不同的实验设置 MLflow(例如,一个实验将运行朴素贝叶斯,另一个是逻辑回归,另一个是随机森林)。我们可以用mlflow.start_run
直接开始跟踪,而不是把所有东西都包在mlflow
上下文管理器中。请记住,可以同时调用多个自动记录功能,MLflow 将能够记录不同型号口味的产品。最后,运行预测,保存模型并将其报告给 MLflow 服务器。
通过这种方式,您将能够并行地或者用一个简单的 bash 脚本运行多个实验(图 10)。对于本教程,我已经运行了一个朴素贝叶斯模型,一个逻辑回归模型,以及带有CountVectorizer
和TfIdfVectorizer
矢量器的随机森林。
图 11:提交多个实验和模型的 bash 脚本示例。
在这个阶段,在 MLflow tracking 中,所有这些模型都在同一个实验系列下,因此您可以对它们进行比较,并决定哪一个是最好的模型——图 12
图 12:在 MLflow 中,您可以立即比较您运行的所有实验,并检查它们的指标和图表。
3.在 MLflow 中注册您的模型并部署到 SageMaker 端点
向 MLflow 注册表添加模型
每次在 MLflow 中保存模型时,您都会在模型的工件框中看到“注册模型”选项。这个小按钮允许您将当前模型添加到 MLflow 数据库中,该数据库确定哪些模型已注册并准备好用于“试运行”和“生产”环境,以及在模型需要淘汰时用于“归档”。
图 13:带有“注册模型”选项的 MLflow 中的人工制品框。
只需选择性能最佳的型号,并注册到 MLflow 注册表中。如图 14 所示,这种手动操作可以在 Python 中轻松完成。这种方法对于 CI/CD 非常有用。
图 14: Mlflow Python API 允许通过运行 id 在注册表中添加模型。
选择您的模型应该处于的环境,即“暂存”或“生产”。您的模型将有一个来自模型注册中心的类似 uri:models:/NAME_OF_YOUR_MODEL_IN_THE_REGISTRY/environment
设置要从 MLflow 部署的 AWS IAM 角色
如果你已经准备好了所有的 AWS 角色,你可以跳过这一段,否则请跟我来。
假设你在 AWS 中有一个注册账户,让我们进入 IAM(身份和访问管理)下的 AWS 控制台——同样的操作可以在 Terraform 中完成。在这里,我们可以转到Users
下,点击add Users
。选择一个用户名,例如stefano
,点击access key
。这将允许您拥有对正确设置至关重要的aws_access_key_id
和aws_secret_access_key
。
图 15:创建一个新用户并选择访问密钥凭证类型。
在第二步中,将用户添加到组中。如果你没有 sagemaker 群,创建一个新的群。像sagemakergroup
一样设置组名,添加两个策略:AmazonSageMakerFullAccess
和AmazonEC2ContainerRegistryFullAccess
。这些是授予用户处理 SageMaker 和图像容器的所有权限的关键角色。继续剩余的步骤,最后下载您的凭证 csv 文件——或者记下访问密钥。
接下来,转到“角色”下,单击“创建角色”。在Trusted Entity Type
中选择AWS service
,在Use Cases
下寻找SageMaker
,选择Sagemaker — Execution
。继续,最后给角色起个名字(例如awssagemakerdeployment
)。一旦角色被创建,点击它并在某处复制arn
——它将类似于arn:aws:iam::YOUR_AWS_NUMBER:role/awssagemakerdeployment
。我们以后会需要这些信息。
最后,您需要设置 AWS CLI 界面。在您的终端类型aws configure
中,系统会提示您输入用户访问密钥和秘密访问密钥(包含在下载的 csv 文件中),并添加最适合您的项目的区域(例如,对我来说是eu-west-1
)和输出格式(例如json
)。这将为 MLflow 使用正确的用户和权限部署到 SageMaker 准备所有必需的凭证设置。
将您注册的模型部署到 AWS SageMaker
我们需要做的第一件事是在 AWS ECR 中创建 MLflow 模型启动器的图像。MLflow model launcher 是您在每个模型的 artefact box 中看到的东西,其中我们有一个模板化的代码,可以检索保存的模型并作为前端接口运行它,以进行预测。要创建这个容器,只需使用mlflow
并在您的终端中键入:
venv/bin/mlflow sagemaker build-and-push-container
图 16: MLflow 已在 ECR 中推送 mlflow-pyfunc 映像。
根据您的互联网连接,此命令将在 AWS ECR 上构建和推送基本 MLflow 映像。检索图像 uri,类似于YOUR_AWS_NUMBER.dkr.ecr.YOUR_REGION.amazonaws.com/mlflow-pyfunc:VERSION_NUMBER
。
从这里开始,您需要一小段代码,这里是链接,以将您的模型部署到 SageMaker——图 17。
图 17:将注册的 MLflow 模型部署到 SageMaker 端点。
在图 17 的 Python 代码中,我们使用了 create ECR image container uri、model uri——在本例中用于“staging”环境——和awssagemakerdeployment
的arn
。部署将需要几分钟时间。前往 SageMaker 推理页面,您将看到新的闪亮端点。请记住:端点是有成本的!所以实验完记得删。在这种情况下,我们使用一个ml.t2.medium
实例,它是最小和最便宜的。
这样一个端点可以很容易地从这个脚本中进行本地查询:
图 18:给定一条输入 tweet,从部署的 SageMaker 端点运行预测的脚本。
图 19:一旦模型被部署,模型在 Sagemaker 推断端点中是可见的。
4.在 EC2 实例上部署 Streamlit 应用程序,并通过您的仪表板运行预测
我们遗漏了什么?一个简单的前端,一个实用的用户界面,通过简单地输入我们的输入 tweet 来查询模型。为此,Streamlit 派上了用场。Streamlit 已经做好了一切准备,可以使用它简单而伟大的 Python 模块来创建一个伟大的界面,正如你从 Streamlit 图库中看到的那样。
我必须承认,我不是 Streamlit 中疯狂花哨设计的超级专家,但是,我知道如何用最少的努力创建一个简单的仪表板,以接收输入 tweet 并返回预测。
创建简单的 Streamlit 仪表板应用程序
首先,安装streamlit
版本 1.11.0,因为您可能会遇到新版本和 Python > 3.8 的错误:
venv/bin/pip install streamlit==1.11.0
然后,我们需要一些元素来创建一个紧凑的前端。从图 18 中,我们可以复制check_status
和query_endpoint
函数,它们将被用来调用端点。如图 20 所示,这些调用然后围绕 Streamlit 进行包装
图 20:在我们的 Streamlit 应用程序中接收输入 tweet 并返回情感的简单代码。
您可以通过调用streamlit
在本地测试这段代码,如下所示:
venv/bin/streamlit run dashboard.py
这将直接在您的浏览器中运行。如果一切正常,您就可以将这个应用程序部署到 EC2 实例了
将您的仪表板部署到 EC2 实例
在 AWS 控制台上,转到 EC2 并点击Launch Instance:
- 为您的机器选择一个名称。
- 在“应用程序和操作系统映像(亚马逊机器映像)”下,选择 Ubuntu——我用的是 22.04
- “实例类型”可以是一个
t1.micro
——我们不需要这个应用程序的超级能力 - 在“密钥对”上,单击“创建密钥对”。选择
RSA
和.pem
格式,并给密钥对命名,例如StreamlitDeployment
。一个.pem
文件将被下载到您的本地。 - “网络设置”:点击“编辑”并向下滚动,直到您可以添加一个“自定义安全组”,如图 21 所示。这里添加一个“自定义 TCP ”,可以访问 Streamlit 使用的端口“8501”。将来源保留为“任何地方”。请注意,对于公司的应用程序,这必须在您的 VPC 内得到保护。
图 21:选择 Add security group rule 为 Streamlit 使用的端口 8501 建立新的 TCP 连接。
保持所有其他设置不变,并创建虚拟机。然后,记下机器的“公共 IPv4 DNS”,其格式类似于ec2-MACHINE_IP.compute-1.amazonaws.com
。最后,检查机器的“用户名”,点击机器的“实例 ID ”,然后点击“连接”。在这种情况下,机器用户名应该是ubuntu
。
现在我们可以从本地命令行连接到机器。首先,我们需要对下载的pem
密钥对文件授予读取权限,然后我们可以使用以下命令对虚拟机进行ssh
:
chmod 400 StreamlitDeployment.pem
ssh -I "StreamlitDeployment" ubuntu@PUBLIC_IPv4_DNS
在前面的段落中检索到了PUBLIC_IPv4_DNS
。
在虚拟机中,我们需要安装所有缺失的依赖项:
sudo apt-get updatewget [https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh](https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh) -O ~/miniconda.shbash ~/miniconda.sh -b -p ~/minicondaecho "PATH=$PATH:$HOME/miniconda/bin" >> ~/.bashrcsource ~/.bashrcpip install streamlit
pip install pandas
pip install boto3
最后,我们可以将我们创建的dashboard.py
文件复制到虚拟机:
scp -i "StreamlitDeployment.pem" dashboard.py ubuntu@PUBLIC_IPv4_DNS:~/.
以及 AWS 存储在我们笔记本电脑上的~/.aws
下的credentials
文件
scp -I "StreamlitDeployment.pem" ~/.aws/credentials ubuntu@PUBLIC_IPv4_DNS:~/.aws/.
直接从终端,我们可以立即测试 Streamlit 应用程序:
streamlit run dashboard.py**You can now view your Streamlit app in your browser.**Network URL: **http://172.31.22.205:8501**External URL: **http://54.146.192.225:8501**
如果您连接到[http://54.146.192.225:8501](http://54.146.192.225:8501,)
、External URL
,您将能够与仪表板应用程序进行交互:
图 22:我们创建并从 EC2 实例运行的 Streamlit 应用程序示例。
一切都很好,但我们可以做得更好,利用TMUX
启动一个流会话,这样我们就可以从虚拟机注销,并在不保持连接的情况下与应用程序交互。让我们安装 TMUX:
sudo apt-get tmux
并开始流式会话:
tmux new -s StreamlitSession
现在我们可以自由运行 Streamlit,应用程序将在 tmux 会话中运行:
图 23:仪表板中给出的输入和来自情感分类器的输出结果的例子。
您可以通过按下Ctrl+B
离开 SSH 外壳,并在旁边按下D
键。这个组合将使您脱离tmux
会话,您将能够从 SSH 连接中注销。如果您想停止tmux
会话,只需重新连接到机器并寻找正在运行的作业的PID
ps aux | grep streamlit
并终止该进程
kill PID NUMBER
优点、缺点、局限性和未来的工作
在这个阶段,我们可以稍微回顾一下整个过程。我们可以立即指出一些优点:
- Git-DagsHub 接口通过提供一个专用的 MLflow 服务器和存储来减轻我们的负担。这节省了大量时间和麻烦,因为我们不必设置虚拟机或特定的 VPC 权限或基础架构(例如对等),就可以在我们的所有云工具之间共享 MLflow 系统
- 如果我们是基于 AWS 的 MLflow 提供了一个超级简单的接口来处理我们注册的模型。我们不需要担心创建 docker 文件或特定的 SageMaker 代码
还有一些缺点:
- 我们可能不基于 AWS。在这种情况下,MLflow 为 Azure 部署提供了一个很好的解决方案,但不适用于 Google 云平台。不久前我曾试图填补这一空白,但还需要进一步的工作,以在 MLflow 模型注册中心和 GCP 之间建立更无缝的接口
- 如果您想将这个模型升级到 Heroku,DagsHub 目前没有提供任何与这个部署提供者的 CI/CD 接口。因此,您需要创建更多的图像(docker-compose ),让注册的模型和端点接口被 Heroku 包装起来,并作为定制图像托管
- SageMaker 端点成本!在部署您的超级 ML 模型之前,考虑部署 SageMaker 批量转换作业而不是端点的可能性。这里是 GitHub 问题请求和到适应该批量转换请求的 MLflow PRs 的链接。
因此,我们需要从这个出发点考虑今后的工作。首先,我们可以找到一种合适的方式来填补 MLflow 和其他云提供商(不是 Azure,不是 AWS)之间的差距。额外的帮助可能来自谢顿。Seldon 提供了一个 MLflow 接口来托管和旋转模型——不管 Kubernetes 可能会带来哪些复杂问题。值得一提的是最近的 MLflow 实现,这是一个新的 mlflow 部署控制器,可以在多个云平台上铺平所有的部署道路。请继续关注,因为我将尝试与您分享类似的内容:)
结论
这是一个很长的教程,但我想你对最后的结果很满意。我们学到了很多东西,所以让我们来回顾一下:
- 我们学习了如何创建一个简单的模型并将其记录到 MLflow 中,如何向 MLflow 认证,以及跟踪我们的实验。关键要点:实现 MLflow Python bits、身份验证、跟踪概念。
- 我们看到了如何使我们的代码更通用,利用了
sklearn
管道的功能,创建了我们的定制转换器来处理数据,并使它们成为最终训练管道的一部分。 - 我们学习了如何将我们最好的模型部署到 AWS。首先,我们将模型注册到 MLflow registry,然后使用 MLflow sagemaker 部署方案并设置 AWS IAM 角色。
- 最后,我们用 Streamlit 为我们的模型创建了一个前端,并学习了如何设置 EC2 实例来适应这个应用程序。
我希望你喜欢这个教程,并感谢阅读它。
支持我的写作
通过我的推荐链接加入 Medium 来支持我的写作和项目:
https://stefanobosisio1.medium.com/membership
如果有任何问题或意见,请随时给我发电子邮件,地址是:stefanobosisio1@gmail.com,或者直接在 Medium 这里。
从图 ML 到深度关系学习
原文:https://towardsdatascience.com/from-graph-ml-to-deep-relational-learning-f07a0dddda89
走向深度关系学习
整合神经网络 与 关系学习 以达到超越当前状态的结构化深度学习模型,如图神经网络
深度关系学习旨在使神经网络能够进行 关系学习 ,即捕捉像关系逻辑(程序)的语言一样有表现力的学习表示。图片由作者提供。
图形结构化数据无处不在。随着最近深度学习的出现,研究人员开始用神经网络探索这种数据表示似乎是很自然的。目前,我们经历了*图形神经网络**【GNN】*类的爆炸,无数的模型以各种(吸引人的)名字被提出。然而,这些模型中的大多数都是基于相同的简单图形传播原理。
为了从更广阔的视角来看待这个问题,我们将在这里从 关系机器学习 的一般视角来揭示潜在的 GNN 原则,这一点我们在上一篇文章中讨论过。
- 与(主要)经验驱动的深度学习相反,关系机器学习在很大程度上建立在关系逻辑的形式语言上,而反过来又提供了一些用于表示和操作结构化数据的坚实原则,如各种集合、图表和关系数据库。
在这篇文章中,我们将探索一种优雅的方式来连接关系学习和 神经网络 。这将允许我们以一种非常透明的方式优雅地捕捉 GNN 模型,允许随后将推广到超越其当前状态的 深度关系学习 。
神经网络关系学习简史
虽然对于我们许多人来说,最近 GNNs 的普及可能是我们第一次遇到从结构化数据中学习的,但实际上已经有很长一段时间的研究旨在将机器学习模型外推至这些数据表示。
在 关系学习 的保护伞下,这个问题已经被根植于关系逻辑及其概率扩展的方法统治了几十年,这些方法被称为 统计关系学习 (SRL)。
然而,神经网络提供了高效的潜在表示学习,这超出了逻辑系统的能力。这里,不是将符号视为独立的原子对象,而是引入了学习嵌入的思想,即(离散)符号对象的分布式固定大小数值(向量)表示。
- 它可以追溯到线性关系嵌入[2],随后的论文提出了不同的模式来改善学习并将符号的嵌入扩展到它们的组合中。这个工作流还包括现在广泛流行的“word 2 vec”[3]。
学习结构的嵌入,如树*,然后追溯到递归自联想记忆【4】。在这些作品中,(逻辑)关系的表示通常作为对象对(嵌入)之间的相似性度量来处理,例如通过张量来参数化。这种方法后来成为流行的递归神经网络【6】。*
与此同时,关系学习社区也提出了各种修改,以使经典神经网络适应关系(逻辑)表示。在很大程度上本着 SRL 的精神,这里宣布的模型目标是正确地组合选择和聚集偏差,即学习如何选择关系模式以及如何同时从它们中聚集信息。
- 仅考虑这里的聚合设置对应于“多实例学习”,即从(独立的)样本集学习,这也在关系学习社区中提出[8]。最近,类似的模型也随着“深集”[7]和类似的架构而复活。
这种 SRL 观点激发了“关系神经网络”[9]——一种基于特定关系数据库模式的结构模型,样本将从该模式中抽取。然后引入了一种类似的方法,分别作为(原始) 图形神经网络 模型(GNN)【10】的图形数据。当时,在[11]和[12]中进一步回顾和比较了这两种“竞争”方法。
这里的重要见解是,这些方法遵循了动态构建 神经模型的 概念。这种计算模式的转变使得能够应用从原始关系数据中进行端到端学习的核心思想。与基于将结构预处理成固定大小的向量(张量)的(命题化)方法相比,这允许模型直接利用输入示例呈现的关系偏差。
图形神经网络的先验知识
现代的 GNN 变体可以被视为这一原始 GNN 概念的延续(尽管它们通常更简单[13])。这里一个常见的解释建立在“消息传递”的概念上,每个节点都被视为向输入图 Xi 中的邻居发送“消息”。虽然这一解释与魏斯费勒-雷曼启发法有一些重要的联系,但⁴直接通过其底层计算图 Gi 的结构来查看 gnn 可能更具启发性,类似于查看经典的深度学习模型。
从这个角度来看,⁵ GNNs 可以被视为标准的 CNN 技术的扩展,即卷积和聚集到不规则图结构 Xi ,在节点( N )之间具有任意边( E )。为了促进这一点,他们从每个输入图形 Xi 中动态展开每个计算图形* Gi ,而不是固定像素网格上的静态架构。*
这样,GNN 就是一个简单的“标准”多层前馈 CNN 架构,唯一需要注意的是,计算图 Gi 中每层 k 的结构准确反映了输入图* Xi 的结构。*
*一个典型 GNN(“g-Sage”)的计算图,在每一层内具有权重共享(“卷积”),在一些不规则输入图 X (紫色,左侧)上展开。单个卷积运算节点( C 、**、*橙色)之后是聚合运算( Agg 、蓝色),其形成输入到输入图的下一层表示( X )(浅紫色)。图片由作者提供(来自[32])。
P 具体来说,每个输入图 Xi 中的每个节点 N 都可以关联一个特征向量(或嵌入),形成计算图 Gi 中的输入层表示。
对于下一层 k 表示的计算,每个节点 N 通过聚集 A 【池化】 M : (N,M)∈ E 在输入图 Xi 中相邻的相邻节点的值来计算自己的隐藏表示 h(N) 。这些可以通过某个参数函数 C (卷积)进一步转换,该参数函数在各层 k 内与相同的参数化 W₁ 重复使用:**
- 在一些 GNN 模型中,该 h 表示通过另一个 Cw₂ 与来自前一层k1的“中心”节点的 N 表示进一步组合*,以获得层 k 的最终更新值,如下所示:*
然后,他的通用“聚合和组合”[17]计算方案涵盖了各种流行的 GNN 模型,然后简化为特定聚合 A 和激活/卷积 Cw 的选择。例如在 GraphSAGE [18]中,操作是
**
而在流行的图卷积网络[19]中,这些甚至可以合并成一个单一的步骤
同样的一般原则也适用于许多其他 GNN 作品[17]。⁰
***批判的视角。*最近,已经提出了这个计算公式的大量不同变体。本质上,每一个这样引入的 GNN 变体都提出了(共同的)激活和聚集功能的某种组合,并且/或者提出了用从其他神经架构借用的层来扩展该模型。最终,在新的 GNN 名字下引入这些普通 DL 模块的详尽组合导致了我们今天看到的 GNN动物园模型,具有很大程度上模糊的性能【21】。
要真正看透模型的原理,现在看来,在这个相当常见的“低挂果实”收集的早期研究阶段之后,GNN 领域可能会受益于一些更深入的见解…
对称的观点
M. Bronstein 等人对 GNN 模型类最近的®发展提出了一个非常有见地的观点,通过对每个领域中的 对称性 的基本假设来观察 DL 架构。从几何领域中常见的对称概念开始,这种方法后来被创造为“ 几何深度学习 ”(请在 Medium 上查看迈克尔·布朗斯坦的优秀文章系列)。
自然地,所有的机器学习模型本质上都试图探索输入数据分布中的对称性,即某种形式的重复规律。然而,在一些结构化模型类中,这种规律性也存在于模型参数空间中。
在深度学习中,这可能是最有名的 CNN,旨在反映像素网格中的不变性* w.r.t .平移(shift),这是这种几何对称最流行的例子。*
- 这意味着无论你将输入模式转移到哪里(在“感受野”的范围内),模型输出都将保持不变。
CNN 卷积层中的对称(规则)加权共享模式。图片由作者提供。
以类似的方式,递归和递归神经网络被设计成在线性和树形结构中反映递归对称性*。*
递归(左)和递归(右)神经网络的公共权重分配方案和对称性。图片由作者提供(来自[32])。
最后,gnn 试图用一般的图不变量做同样的事情,也就是关于图同构*(置换)对称的函数。*
应用于高度对称分子(甲烷)的图形神经网络中的规则权重分配模式。图片作者(来源)。
在集合上反映完全置换对称性的模型,例如“深集合”,可以被视为一种“基础情况”,其中所有可能的输入置换都被认为是等价的。**
- 而在前面的模型中,只有可能的输入排列的子集被不变地处理(想象一下,例如,移动一只猫的图像与随机移动它的所有像素)。
自然地,在每个学习领域中结合关于相应对称形式的正确先验最终导致更好的样本效率和泛化,并且历史证明允许利用这种先验的模型非常有用。
超越几何对称
传统上,大多数深度学习进展都是通过应用程序根据经验驱动的,而不是一些先前自上而下的理论分析。这也许也激发了对计算机视觉中出现的几何对称性的主要方向的探索,这是最普遍的应用领域。然而,神经网络中的对称性不需要局限于几何。
举例。为了简单的演示,让我们回顾一下上一篇关于神经符号整合的文章中的简单逻辑 XOR 例子。
- 在那里,我们解释了编码简单的逻辑函数,如 AND 和 OR,如何在神经网络的早期进化中发挥重要作用,早期“神经网络”无法学习 XOR 问题导致了重大挫折。
尽管几十年来 XOR 问题的解决方案已经广为人知,但有趣的是,即使使用现代的深度学习,正确地学习仍然是非常重要的!特别地,虽然最佳解决方案可以由少至 2 个(或者甚至 1 个)隐藏神经元组成,但是实际上很难正确地训练如此小的网络的参数,因为优化将大部分被次最佳解决方案卡住。(自己轻松试试吧!)
只有当我们采用普通的(“蛮力”)方法将网络参数化增加到比必要的维数高得多的维数时(app。10+隐藏神经元进行二进制异或),训练最终变得可靠。
虽然蛮力通常是深度学习中的一个答案,例如当诉诸数据集扩充时,我们可以通过将正确的先验纳入模型来做得更好。特别地,这里我们知道异或函数是对称的因为 XOR(x₁,x₂) = XOR(x₂,x₁).因此,我们不需要单独处理所有的排列,函数的神经参数化也应该有一些内部对称性。
因此,代替(常见的)过度参数化方法,我们实际上可以保持小的网络规模,并且通过绑定权重来进一步减少参数的数量。
二进制 XOR 函数学习的(自动诱导的)对称权重共享先验的例子。图片来自作者的学生马丁·克鲁茨基。
然后,这种权重共享显著地改进了逻辑函数的学习,类似于在计算机视觉(和其他应用)中通过卷积使用几何对称性的 DL 模型的⁵。
用逻辑捕捉对称
如果我们可以从将正确的先验知识编码到模型中开始,而不是在顶级通用模型上修补过度参数化和其他经验(蛮力)技巧,这不是很好吗?
几何深度学习运动现在用基于几何对称性的神经网络实践观点提出了这样一个有趣的观点。然而,这个原理长期以来也在 关系学习 领域中被研究,作为逻辑上的 背景知识并入。**
这两种方法之间有什么联系吗?关系逻辑与(几何)对称性有什么关系吗?
是的。尽管被 DL 支持者普遍忽视(或轻视),关系逻辑实际上是捕捉各种对称和离散领域规则的完美形式。⁶
到与“几何”解释一致,让我们从集合中置换对称的最简单概念开始。有了逻辑,就不需要为此重新发明轮子了,因为我们已经在逻辑中将集合定义为满足给定属性的对象 X 的枚举,即{ X | X 是一个节点}或简单的 N(X) 对于一些一元(属性)关系 N。请注意,在集合的这种表示中,没有关于元素 X 的任何排序的概念,因此相应的排列对称性在设计中得到考虑!
然后,这可以直接推广到图形,这只是一个二元逻辑关系的情况。因此,为了表示一个图,我们可以写 Edge(X,Y) 来表示它的所有边的集合。自然,我们在这里也可以将相应节点的集合指定为节点(X) 和节点(Y) 。同样,在这种表示中,没有关于节点或边的任何排序的概念。
- 此外,关系逻辑并不仅限于图,同样的原理直接应用于更高级的结构 Relation(X,Y,Z,…) 以及它们通过逻辑连接词的组合(例如,形成关系数据库和 SQL 的形式模型)。
虽然每个(以前的)计算机科学学生肯定都熟悉这种形式(数据库)表示和相应的关系代数/逻辑运算,但这种形式概念能否用于机器学习实践可能并不明显。
然而,这已经被确切地的观点 解除了建模 的范式【27】(在我们的以前的文章中描述了的关系学习),这里的的关系逻辑的表达形式主义已经被直接用于捕捉机器学习中的对称性问题。
重要的是,这里的对称不仅仅是描述性的,关系逻辑已经被直接用于编码图形模型,比如在流行的马尔可夫逻辑网络【16】。
分别来自深度学习和统计关系学习 (SRL)领域的 CNN(左)中卷积滤波器展开的对称权重共享模式和 MLN(右)中提升的逻辑模板之间的类比。作者图片。
然而,尽管用关系逻辑将领域对称性的先验编码到图形模型中已经研究了几十年,但在深度学习方面似乎令人惊讶地缺乏。
- 当然,深度学习社区对逻辑有一定的厌恶。尽管如此,考虑到神经网络和命题逻辑之间的历史相互作用,神经网络中基于逻辑的对称性缺乏基础似乎有些令人惊讶。
然而,正是标准神经网络的“命题固定”限制了它们在学习问题中捕捉有趣的(提升的)对称,并使深度学习与关系逻辑的集成变得复杂,正如上一篇文章中所概述的。
深度关系学习
但是等一下,现在我们有强大的 GNNs!他们不再受命题固定的困扰,因为他们可以捕捉图形数据。难道我们现在就不能把一切都变成图,用 GNNs 来解决我们所有的问题吗?
当然,图形是无处不在的,如果你尝试,你可以将手头的任何问题以某种方式转化为图形表示。因此,这是非常方便的只是应用一个过剩现成的 GNN 模型,看看你是否运气好一些调整。⁸
然而,请注意,这是另一种“如果你只有一把锤子……”的认知偏见,类似于之前讨论的“将一切都变成向量”的命题化方法论。
最后,gnn 只是一种特殊的图传播启发式算法,具有源于底层 WL 的固有限制。重要的是,即使 GNN 可以正确地捕捉图形结构(超越 WL),这仍然不能保证其实际的学习(泛化)能力,类似于它显然不足以坚持基于通用近似定理的简单 2 层神经网络【29】。
这就是为什么我们设计越来越复杂的模型和学习表示,直接反映我们问题的结构。因此,将复杂的关系学习表示和推理算法从图和图传播转回到 GNNs 可能不是最好的主意。
因此,如果我们不是试图将更复杂的关系问题表示嵌入到图和 gnn 中,而是可以将关系逻辑的表达用于一些成熟的“深度关系学习”,捕捉当前神经模型中的对称性作为特例,类似于提升的图形模型如何在 SRL 中概括标准图形模型,这不是很好吗?
正如你现在可能已经猜到的那样,有一个学习框架可以完全做到这一点。具体来说,它采用 提升建模 策略,并将其外推到深度学习设置中。然后,这种范式能够将神经网络和命题逻辑之间熟悉的对应直接带到关系层面。
因此,在命题逻辑被提升到关系逻辑的更高表达能力的同样意义上,该框架将经典神经网络提升到这些模型的更具表达能力的版本,称为“提升的关系神经网络”[34]。⁵
提升关系神经网络
与提升的图形化模型类似,“提升的关系神经网络”框架的核心是一种基于关系逻辑的语言,用于定义神经模型,进一步简称为“https://github.com/GustikS/NeuraLogic”。该语言直接源自 Datalog(或 Prolog),它通常用于高级数据库查询和逻辑编程,具有一个额外的特性——它是可微分的。**
- 虽然现在有许多可区分编程的框架,但 NeuraLogic 的显著不同在于它是声明性的。这允许以非常简洁和优雅的方式表达一些复杂的算法和原理,这特别适用于表现出各种规律性(对称性)的关系问题。
举例。**让我们跟进上面介绍的关系逻辑如何捕捉集合和图形中的对称性的形式原则,并在构建 GNN 时使其可直接操作。特别地,我们现在知道图是节点(节点(X) 和节点(Y) )之间的一组边(边(X,Y) )。然后,我们知道通用 GNN 计算规则是将节点的表示传播/聚集到它们的邻居,这可以放入逻辑规则中,如下所示:**
**node2(X) <= W node1(Y), edge(X, Y).**
…就是这样,真的!这是神经语言中 gnn(gcn[19],特别是⁰)的可运行代码。内容如下:
**"为了计算任何对象 X 的表示’ node2 ',聚合所有对象 Y、的 a 'W【T21 ‘-八分表示’ node1 ‘,其中’ edge '位于两者之间。"
- 那些倾向于关系逻辑的数据库解释的人可能会这样理解:“在 Y 列上连接表‘node 1’和‘edge’,按 X 分组,并聚合成一个新表‘node 2’”。
在神经对话框架中运行这个逻辑规则与在传统框架中运行 GCN 完全一致,也就是说,它将执行
前面讨论的公式。当然,激活(∑)和聚集( Agg )函数(以及其他超参数)的规范也可以添加到规则中。然而,您也可以像这样让它们保持默认值( tanh+avg )来享受 GCNs 的基本原理的清晰性,即节点和相应边的局部排列的不变性。
因此,在 NeuraLogic 中,模型对称性先验的定义成为模型本身的代码!
重要的是,这个规则是完全通用的,也就是说,在专门为图形或 gnn 设计的整个神经对话框架中没有特定的功能。
- 然后,类似的简单提升规则对深度学习模型中的各种递归/递归和其他对称权重共享(卷积)方案进行编码,本文通篇以图片中的颜色为例。
这意味着你可以轻松地编写任意的关系规则,编码新颖的神经建模构造具有高级对称先验的,捕捉复杂的关系学习原则 超越 GNNs【36】。
先睹为快“超越图神经网络与提升的关系神经网络”[32]
虽然我们在这里用提升的关系神经网络对深度关系学习进行了先睹为快的总结,但我们将在下一篇文章中详细探索神经对话框架,在那里我们将展示它的实际用途、表达能力和计算效率。
1.最直接,也是历史上占主导地位的方法是将关系数据转化为固定的张量表示,作为预处理(命题化)步骤,然而,正如前面和所讨论的,这隐藏了许多缺点。
[2] A .帕卡纳罗和杰弗里 e .辛顿。"使用线性关系嵌入学习概念的分布式表示."摘自:IEEE 知识与数据工程汇刊 13.2 (2001),第 232–244 页。刊号:10414347
[3]托马斯·米科洛夫、伊利亚·苏茨基弗、程凯、格雷戈·S·科拉多和杰夫·迪恩。"单词和短语的分布式表示及其组合性."载于:神经信息处理系统进展 26 (2013),第 3111–3119 页。
[4]乔丹·波拉克。"递归分布式表示."摘自:人工智能 46.1–2(1990),第 77–105 页。issn: 00043702。
5 杰弗里·e·辛顿。“将部分-整体层次映射到连接主义网络中。”摘自:人工智能 46.1–2(1990),第 47–75 页。issn: 00043702。
[6]理查德·索赫尔、齐丹·陈、克里斯托弗·曼宁和吴恩达。"用神经张量网络进行推理以完成知识库."神经信息处理系统进展。Citeseer。2013 年,第 926–934 页。
[7] Zaheer,Manzil 等,《深层集合》 arXiv 预印本 arXiv:1703.06114 (2017)。
[8] Ramon,j .,& DeRaedt,L. (2000 年)。多示例神经网络。在ICML-2000 关于属性值和关系学习研讨会的会议录。
[9]亨德里克·布洛克尔和沃纳·乌温特斯。"使用神经网络进行关系学习."摘自:ICML 2004 年统计关系学习及其与其他领域的联系研讨会。2004 年,第 23-28 页。
[10] Franco Scarselli、Marco Gori、Ah Chung Tsoi、Markus Hagenbuchner 和 Gabriele Monfardini。"图形神经网络模型."摘自:IEEE 神经网络汇刊 20.1 (2008),第 61-80 页
[11] Werner Uwents,Gabriele Monfardini,Hendrik Blockeel,Franco Scarselli 和 Marco Gori。"图形处理的两种联结主义模型:关系数据的实验比较."载于:MLG 2006 年,《利用图表进行挖掘和学习国际研讨会论文集》。2006 年,第 211-220 页
[12] Werner Uwents、Gabriele Monfardini、Hendrik Blockeel、Marco Gori 和 Franco Scarselli。"关系学习的神经网络:实验比较."载于:机器学习 82.3(2011 年 7 月),第 315–349 页。issn: 08856125。
[13] Lamb,Luis C .等人,“图形神经网络与神经符号计算的相遇:综述与展望”arXiv 预印本 arXiv:2003.00330 (2020)。
14.GNN 模型可以被视为用于图同构驳斥检查的著名的魏斯费勒-雷曼(WL)标签传播算法的连续、可微分版本。然而,在 GNNs 中,不是离散的标签,而是连续的节点表示(嵌入)被连续地传播到节点的邻域中,反之亦然,用于相应的梯度更新。
15.接受这种动态计算图的观点,这与之前介绍的递归网络非常相似,然后使模型无状态,这消除了源于输入图内的消息传递解释的可能的歧义。
理查森、马修和佩德罗·多明戈斯。“马尔可夫逻辑网络。”机器学习 62.1–2(2006):107–136。
[17]徐克玉路、胡、朱尔·莱斯科维奇和杰格尔卡。“图形神经网络有多强大?”载于:arXiv 预印本 arXiv:1810.00826 (2018)。
[18]威尔·汉密尔顿、之桃·英和朱尔·莱斯科维奇。"大型图上的归纳表示学习."神经信息处理系统进展。2017,第 1024–1034 页。
[19]托马斯·n·基普夫和马克斯·韦林。"图卷积网络的半监督分类."参加:2017 年 4 月 24 日至 26 日在法国 ICLR 土伦举行的第五届学习代表国际会议,会议记录。2017 年,OpenReview.net
20.我们注意到我们只讨论了“空间”表示的图形和运算。然而,一些 GNN 方法在频谱、傅立叶域中表示图形和卷积运算。然而,我们注意到,这些又大多遵循相同的“聚合和组合”原则,并可以相应地重写[17]。
[21] Dwivedi,Vijay Prakash 等,“基准图神经网络”arXiv 预印本 arXiv:2003.00982 (2020)。
22.更准确地说,由卷积滤波器的应用引起的共享权重引入了滤波器的相应变换,同时通过池化将聚合函数(例如,最大值或平均值)结合在顶部,将其进一步扩展到变换 i 方差。
23.尽管理论上在这里误差函数(例如交叉熵)中没有局部最小值,但是存在朝向参数空间和大鞍点的边界的发散区域,使得基于梯度的优化非常困难。
24.类似地,对于更简单的 AND 和 or 函数来说也是如此,然而,这些函数过于琐碎,不足以证明 NNs 的这种过度参数化问题的重要性。
有趣的是,虽然逻辑单元和神经元之间的功能并行性已经得到很好的认可,但就我们所知,以前没有工作利用相应神经权重中逻辑功能的平凡对称性来改善学习。
[25]马丁,克鲁茨基。探索深度学习中的对称性。理学学士论文。布拉格的捷克技术大学,2021。
26.自然地,逻辑更适合描述离散领域中的规律性,而几何解释在连续领域中更自然,如计算机视觉和机器人学。
[27] Kimmig,Angelika,Lilyana Mihalkova 和 Lise Getoor。"提升图形模型:一项调查."机器学习99.1(2015):1–45。
28.考虑到最近围绕 GNN 概念的大肆宣传,以及足够的超参数调整,人们确实已经成功地在广泛的问题上利用了 GNN,这现在变得更加诱人了。
果不其然,甚至逻辑表达式也可以转化为图形表示,如【13】所述。然而,这并不意味着 GNNs 是解决逻辑推理底层问题的合适算法!
29 乔治·西本科。"通过叠加一个 s 形函数的近似."控制、信号和系统的数学2.4(1989):303–314。
30.注意与 GCN 规则的经典矩阵视图 H = σ (W * H * A) 的对齐,其中 H 是节点表示矩阵,A 是邻接矩阵(类似于这里的‘边’谓词)。
31.一些重要的评论文章显示,与所有论文中传统上自称的最先进的结果相比,许多这些 GNN 修改的实际性能增益往往相当微不足道,有时甚至无法击败简单的(非结构化)基线模型[21],使得对大量 GNN 变体的需求有点可疑。
32.类似的工作也来自递归转换简化描述的旧思想[5],自动编码器和许多其他工作都建立在此基础上。
33.注意,原则上,递归神经网络可以被认为是递归神经网络的一般形式,它在序列上递归展开,而递归网络在(常规)树上展开。
[34] Sourek,Gustav,等人,〈提升关系神经网络〉。人工智能研究杂志 (2018)。
35.有趣的是,这种具有各种建模结构的方法,包括一些 GNN 和子图 GNN 变体,已经在 2015 年发表,后来(2017 年)也扩展到这种结构的自动学习。然而,对框架的解释根植于关系逻辑而不是(仅仅)图表,这对于 ML 观众来说可能看起来很奇怪。
[36]古斯塔夫·索雷克、菲利普·切列兹和 ondřej·库泽尔卡。"超越图神经网络与提升关系神经网络."机器学习110.7(2021):1695–1738。
作者深深地感谢 翁德雷 对于 底层概念中的无数想法解除了关系神经网络 。
从 Jupyter 笔记本到现实生活:MLOps
原文:https://towardsdatascience.com/from-jupyter-notebooks-to-real-life-mlops-9f590a7b5faa
为什么是必备?
在 Unsplash 上拍摄的 ThisisEngineering RAEng
我的第一个数据科学项目是预测二手车价格的机器学习模型。该项目的主要步骤是:
- 在网站上刮二手车广告
- 清理和预处理刮出的数据
- 探索性数据分析
- 模型创建
- 模型评估
最终结果相当令人满意,R 平方得分为 0.9。我的意思是,考虑到这是我的第一个项目,它超出了我的预期。如果你想了解更多,我写了一篇关于这个项目的文章。
注:这个故事最初发表于datasciencehowto.com。
这样的项目对于学习和实践来说是非常好的。在那个项目中,我花了很多时间使用 Pandas、Scikit-Learn、Beautiful Soup 和 Seaborn,它们是数据科学领域非常流行的 Python 库。
这个项目对我来说是一次很好的学习经历,它让我觉得我做出了开始学习数据科学的正确决定。
然而,这也是一个未完成的项目。我在 Jupyter 笔记本上做了上面提到的所有步骤,但这个项目从未投入生产。它没有被任何人用作价格预测服务。
我认为这是机器学习在现实生活中最具挑战性的部分。创建一个模型并利用它进行预测并不十分困难。将它部署到生产中并作为一项持续服务来运营是另一个世界。
构建这样一个 ML 系统需要许多不同类型的操作,这些操作需要同步并协同工作。这个过程指的是机器学习操作,又名 MLOps。
您可能听说过 DevOps,这是构建大型软件系统的常见做法。MLOps 可以被认为是机器学习系统的 DevOps。
MLOps 的动机
虽然在 Jupyter 笔记本上构建 ML 模型对学习有好处,但离创造任何商业价值还很远。另一方面,建立一个在生产中持续运行的 ML 系统才是机器学习真正有价值的地方。
让我们花点时间思考一下我的预测二手车价格的项目如何提供商业价值。如果你有买卖二手车的业务,你可以用它来查找低于市场价值出售的汽车。然后,你将使用机器学习来改善你的业务,增加你的利润。
使用这种模式的另一个有价值的资产可能是一个网站。人们会通过你的网站根据当前的市场情况来了解他们汽车的价格。
这两者都无法通过在 Jupyter 笔记本上创建和训练一次的机器学习模型来实现。
MLOps 面临的挑战
我想我们都同意,MLOps 是使机器学习成为有益的工具的一个基本要求。毫不奇怪,这不是一件容易的事。
MLOps 面临的主要挑战是可伸缩性、版本控制和模型衰退。为了克服这些挑战,ML 系统被视为软件系统,并按照 DevOps 原则运行。需要注意的是,机器学习代码是整个 ML 系统中非常小的一部分。
DevOps 的两个主要原则是持续集成(CI)和持续交付(CD ),它们也适用于 MLOps。除此之外,第三个玩家也加入了游戏,这就是连续训练(CT)。
CI 要求您测试和验证代码和组件。在机器学习系统中,你还需要对数据执行这些操作。数据验证可能基于模式。例如,如果输入数据中有新的或缺失的列,整个系统可能会崩溃。数据验证脚本应该处理这样的问题。
您还需要检查这些值,如果这些值与预期值相差很大,则需要采取必要的措施。在这种情况下,最好丢弃新数据并跳过模型训练。
持续培训对所有 ML 系统都至关重要。在我们预测二手车价格的例子中,有几个因素对汽车价格有影响,如市场状况、通货膨胀率、全球趋势等等。因此,您不能使用很久以前训练的模型。为了准确地反映当前条件,您需要不断地重新训练模型。
在典型的 ML 系统中,使用许多不同的软件工具和库。因此,您的工作流程中需要采用版本控制系统。
您还需要监控和评估模型输出。机器学习本质上是实验性的。不能保证您的模型总能产生准确可靠的结果。
最后但并非最不重要的一点是,所有这些都需要具有可伸缩性并且高效工作。你可能有最精确的模型,但如果它不可扩展,你的产品或服务很可能会失败。
MLOps 是将您的模型转换为 ML 系统的关键。我们在这篇文章中提到的只是这个领域中的亮点。MLOps 中使用了广泛的工具和软件包。我将会写关于这些工具以及如何在实践中使用它们。敬请关注更多 MLOps。
你可以成为 媒介会员 解锁我的全部写作权限,外加其余媒介。如果你已经是了,别忘了订阅https://sonery.medium.com/subscribe如果你想在我发表新文章时收到电子邮件。
*https://sonery.medium.com/membership
感谢您的阅读。如果您有任何反馈,请告诉我。*
从 Jupyter 到 Kubernetes:使用开源工具重构和部署笔记本
数据科学软件工程
从凌乱的笔记本到在 Kubernetes 上运行的流水线的一步一步的指南
照片由 Myriam Jessier 在 Unsplash 上拍摄
笔记本电脑非常适合快速迭代和原型制作,但很快就会变得凌乱不堪。在笔记本上工作之后,我的代码变得难以管理并且不适合部署。在生产中,代码组织对于可维护性至关重要(改进和调试有组织的代码比一个又长又乱的笔记本要容易得多)。
在这篇文章中,我将描述如何使用我们的开源工具来覆盖数据科学项目的整个生命周期:从一个凌乱的笔记本开始,直到代码在生产中运行。我们开始吧!
第一步,用自动化工具清理我们的笔记本;然后,我们将使用soorgeon
自动将我们的单片笔记本重构为模块化管道;之后,我们将测试我们的管道是否运行;最后,我们将把管道部署到 Kubernetes。这个工作流的主要好处是所有步骤都是完全自动化的,所以我们可以返回 Jupyter,迭代(或修复 bug),并毫不费力地再次部署。
清理笔记本
图片作者。
笔记本的交互性使得尝试新想法变得简单,但也产生了杂乱的代码。在探索数据的时候,我们经常在不考虑可读性的情况下匆忙编写代码。幸运的是,有像 isort 和 black 这样的工具可以让我们轻松地重新格式化代码以提高可读性。不幸的是,这些工具只能处理.py
文件;然而,soorgeon
使我们能够在笔记本文件上运行它们(.ipynb
):
注意:如果你需要一个示例笔记本来尝试这些命令,这里有一个:
查看本节开头的图片:我在左边的笔记本上引入了一些额外的空白。然而,在应用了soorgeon clean
(右图)之后,我们看到多余的空白消失了。所以现在我们可以专注于编写代码并应用soorgeon clean
来轻松使用自动格式化!
重构笔记本
在单个笔记本上创建分析是很方便的:我们可以在各个部分之间移动,并且很容易地编辑它们;然而,这有很多缺点:很难协作和测试。在多个文件中组织我们的分析将允许我们定义清晰的边界,因此多个管道可以在项目中工作,而不会相互妨碍。
从单个笔记本到模块化流水线的过程既耗时又容易出错;幸运的是,soorgeon
可以为我们做这些繁重的工作:
重构后,我们会看到一堆新文件:
图片作者。
Ploomber 自动将我们的笔记本变成一个模块化的项目!它生成一个带有基本指令的README.md
和一个requirements.txt
(从import
语句中提取包名)。此外,它创建了一个包含几个.ipynb
文件的tasks/
目录;这些文件来自原始的笔记本部分,由降价标题分开。计算出哪些部分依赖于哪些部分。
如果您喜欢导出.py
文件;您可以通过--file-format
选项:
soorgeon refactor nb.ipynb --file-format py
这次tasks/
目录会有.py
文件:
├── README.md
├── nb.ipynb
├── pipeline.yaml
├── requirements.txt
└── tasks
├── clean.py
├── linear-regression.py
├── load.py
├── random-forest-regressor.py
└── train-test-split.py
soorgeon
使用降价标题确定要生成多少输出任务。在我们的例子中,有五个人。然后,soorgeon
分析代码以解析各部分之间的依赖关系,并添加必要的代码以将输出传递给每个任务。
例如,我们的“训练测试分割”部分创建了一个变量X
、y
、X_train
、X_test
、y_train
和y_test
;最后四个变量由“线性回归”部分使用:
图片作者。
通过确定输入和输出变量,soorgeon
确定“线性回归”部分依赖于“训练测试分割”部分。此外,“随机森林回归”部分也依赖于“训练测试分割”,因为它也使用“训练测试分割”部分生成的变量。根据这些信息,soorgeon
构建了依赖图。
测试我们的管道
现在是时候确保我们的模块化管道正确运行了。为此,我们将使用工具箱中的第二个包:ploomber
。Ploomber 允许我们在本地开发和执行我们的管道。
这是输出:
ploomber
提供大量工具来管理我们的渠道;例如,我们可以生成一个图:
图片作者。
我们可以看到依赖图;有三个串行任务:load
、clean
和train-test-split
。在它们之后,我们看到两个独立的任务:linear-regression
和random-forest-regressor
。将我们的工作模块化的好处是我们团队的成员可以独立工作,我们可以隔离测试任务,并行运行独立任务。有了ploomber
,我们可以继续用 Jupyter 开发管道,直到我们准备好部署!
部署
为了简单起见,您可以使用 cron 部署 Ploomber 管道,并按计划运行ploomber build
。但是,在某些情况下,您可能希望利用现有的基础设施。我们掩护你!使用soopervisor
,您可以将您的管道导出到气流、 AWS 批次、 Kubernetes 、 SLURM 或 Kubeflow 。
soopervisor add
向我们的项目添加一些文件,比如一个预配置的Dockerfile
(如果我们愿意,我们可以修改它)。另一方面,soopervisor export
将我们现有的管道导出到 Argo 工作流,这样我们就可以在 Kubernetes 上运行它。
通过更改soopervisor add
命令中的--backend
参数,您可以切换到其他支持的平台。或者,你可以注册免费云服务,它允许你用一个命令在云中运行你的笔记本。
结束语
笔记本清理和重构既耗时又容易出错,我们正在开发工具来使这一过程变得轻而易举。在这篇博文中,我们从拥有一个单片笔记本到拥有一个在生产中运行的模块化流水线——所有这些都是使用开源工具以自动化的方式实现的。所以请让我们知道你想看什么功能。加入我们的社区,分享你的想法!
嗨!我叫爱德华多,我喜欢写关于数据科学的所有东西。如果您想了解我的最新内容。在 Medium 或 Twitter 上关注我。感谢阅读!
最初发布于ploomber . io。
从核密度估计到 Python 中的空间分析
如何将您的 KDE 转化为地理空间数据
图片作者。核密度估计的例子
核密度估计(KDE)是一个有用的分析和可视化工具,通常是可视化或分析工作流的最终产品。核密度估计是很好的可视化,但是它们的使用还可以更进一步。
在这篇文章中,我将展示一种使用 Python 获取内核密度估计图并将它们转换成地理空间数据以便进一步分析的方法。
核密度估计
在 Seaborn 的帮助下,使用 Python 创建内核密度估计图相当简单。我们从读入 GeoPandas 中的点数据集开始。我正在使用芬兰赫尔辛基的自行车共享站的数据集,从 OpenStreetMap 检索,但只要你的数据包含坐标或形状点,你应该没问题。
读入数据
自行车共享站数据框架
有了读入的数据,我们可以开始创建我们的核密度估计。我不会深入讨论 KDE 本身的细节,因为还有很多其他来源,比如 scikit-learn 文档,但是下一个代码块展示了 Seaborn 实现是如何工作的:
创建核密度估计。
这产生了 KDE 图,我们将把它转换成可用于空间操作的有形状的对象:
图片作者。KDE 情节。
为每个强度级别创建多重多边形
KDE 图的不同轮廓可以通过我们的 KDE 的collections
对象来访问。通过对该对象进行迭代,我们可以访问我们之前定义的每个亮度级别的每个轮廓的每个路径。
可能会出现轮廓不连续的情况,因此我们为相同强度级别的每条路径创建一个多边形,然后将它们组合成一个多多边形,为每个强度级别提供一个多多边形。
这里的方法受到了 StackExchange 上的这个线程的启发。
将我们的轮廓转换成多重多边形
转换为地理数据
现在我们已经有了一个包含我们的多多边形和相应强度级别的元组列表,我们可以创建一个 Pandas 数据框架,然后我们可以将其转换为 GeoDataFrame。
通过地理数据框架,我们可以访问轮廓的 Shapely 对象,并利用 Shapely 的所有内置操作,例如轻松计算每个轮廓的面积估计值。
转换到地理数据框架并导出数据。
生成的地理数据框架
上面的地理数据框架显示了我们生成的多重多边形以及每个估计等高线的面积计算。由于我们现在有了 Shapely 对象,我们可以使用 Shapely 的任何内置方法来扩展空间分析,或者由于我们已经将地理数据框架导出到地理包,我们可以在 QGIS 等中打开它。
图片作者。在 QGIS 中打开 Geopackage。
结论
在这篇文章中,我简单介绍了如何将你的 KDE 图转换成形状优美的物体和地理空间文件,以便你进一步分析。
从 ML 模型到 ML 管道
原文:https://towardsdatascience.com/from-ml-model-to-ml-pipeline-9f95c32c6512
数据科学基础
使用 Scikit-学习 Python
建立机器学习模型不仅仅是选择正确的算法和调整其超参数。在模型实验开始之前,大量的时间花费在争论数据和特征工程上。这些预处理步骤很容易淹没你的工作流,变得难以跟踪。将注意力从 ML 模型转移到 ML 管道,并将预处理步骤视为构建模型不可或缺的一部分,有助于使您的工作流程更有条理。在这篇文章中,我们将首先看看预处理模型数据的错误方法,然后学习一种正确的方法和两种构建 ML 管道的方法。
ML 管道根据上下文有多种定义。在本文中,ML 管道被定义为预处理步骤和模型的集合。这意味着当原始数据被传递到 ML 管道时,它将数据预处理为正确的格式,使用模型对数据进行评分,并弹出预测得分。
📦 0.设置
让我们导入库和一个样本数据:titanic 数据集的子集。
我们现在将定义常用变量,以便稍后轻松引用:
是时候看看第一种方法了。
❌ 1.错误的方法
在预处理时,像这样使用 pandas 方法并不少见:
仅部分输出
我们估算缺失值,在 0 到 1 之间缩放数值变量和一个热编码分类变量。预处理后,数据被分区并拟合模型:
好的,让我们分析一下这种方法有什么问题:
◼️ **插补:**数值变量应该用训练数据而不是整个数据的平均值进行插补。
◼️ **缩放:**最小值和最大值应根据训练数据计算得出。
◼️ **编码:**类别应该从训练数据中推断出来。此外,即使在预处理之前对数据进行了分区,使用pd.get_dummies(X_train)
和pd.get_dummies(X_test)
进行一次热编码也会导致不一致的训练和测试数据(即,列可能会根据两个数据集中的类别而变化)。因此,在为模型准备数据时,pd.get_dummies()
不应用于一次性编码。
💡测试数据应在预处理前搁置。用于预处理的任何统计数据,例如平均值、最小值和最大值,都应该从训练数据中导出。否则会出现数据泄露问题。
现在,让我们评估模型。我们将使用 ROC-AUC 来评估模型。我们将创建一个计算 ROC-AUC 的函数,因为它将有助于评估后续方法:
❔ 2.正确的方法,但是…
我们将首先对数据进行分区,并使用 Scikit-learn 的转换器对数据进行预处理,以通过正确的预处理来防止数据泄漏:
仅部分输出
很好,我们现在可以拟合模型了:
在评估之前,我们需要以同样的方式预处理测试数据集:
太棒了,这次方法是正确的。但是写好代码并不仅仅停留在正确上。对于每个预处理步骤,我们存储了训练和测试数据集的中间输出。当预处理步骤的数量增加时,这将很快变得非常乏味,因此很容易出现错误,比如在预处理测试数据时遗漏了一个步骤。这些代码可以变得更有条理、更简洁、更易读。这就是我们将在下一节中做的事情。
✔️ 3.优雅的方法#1
让我们使用 Scikit-learn 的Pipeline
和ColumnTransformer
来简化前面的代码。如果你不熟悉它们,这篇文章简明地解释了它们。
管道:
◼️将输入数据分成数字组和分类组
◼️并行预处理这两组数据
◼️连接来自两组的预处理数据
◼️将预处理数据传递给模型
当原始数据被传递到经过训练的管道时,它将进行预处理并做出预测。这意味着我们不再需要存储训练和测试数据集的中间结果。给看不见的数据打分就像pipe.predict()
一样简单。那很优雅,不是吗?现在,让我们评估模型的性能:
很高兴看到它与以前的方法的性能相匹配,因为转换完全相同,只是以更优雅的方式编写。对于我们的小例子来说,这是本文展示的四种方法中最好的方法。
Scikit-learn 的开箱即用的变压器如OneHotEncoder
和SimpleImputer
快速高效。然而,这些预构建的转换器可能并不总是满足我们独特的预处理需求。在这种情况下,熟悉下一种方法可以让我们更好地控制定制的预处理方式。
✔️ 4.优雅的方法#2
在这种方法中,我们将使用 Scikit-learn 创建定制的变压器。看到我们熟悉的相同预处理步骤如何转化为定制的转换器,有望帮助您掌握构建它们的主要思想。如果你对定制变形金刚的用例感兴趣,请查看GitHub 库。
与以前不同,这些步骤是按顺序一个接一个完成的,每个步骤都将其输出作为输入传递给下一个步骤。是时候对模型进行评估了:
耶,我们刚刚学会了另一种优雅的方式来达到和以前一样的效果。虽然我们在第三种方法中只使用了预构建的转换器,在第四种方法中只使用了定制的转换器,但是它们可以一起使用,只要定制的转换器被定义为与开箱即用的转换器一致地工作。
这就是这篇文章的全部内容!当使用后两种方法时,一个好处是超参数调整可以在整个管道上进行,而不仅仅是在模型上。我希望你已经学会了开始使用 ML 管道的实用方法。✨
迈克尔·泽兹奇在 Unsplash 上的照片
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。
谢谢你看我的帖子。如果你感兴趣,这里有我的一些帖子的链接:
◼️️ 管道,ColumnTransformer 和 FeatureUnion 解释
◼️️ FeatureUnion,ColumnTransformer &管道用于预处理文本数据
◼️️ 用
的两种方法创建自定义变压器◼️ 用这些技巧丰富你的 Jupyter 笔记本
◼️ 用这些技巧组织你的 Jupyter 笔记本
◼️ 解释 scikit-1
再见🏃💨
从 NLP 原型到生产
原文:https://towardsdatascience.com/from-nlp-prototype-to-production-c2b555488dc5
远远不同于粉笔和奶酪和粉碎技术债务
爱丽丝·帕斯夸尔在 Unsplash 上的照片
在英语中,我们有这样的说法:‘T4’粉笔和奶酪或者苹果和橘子。原型就像你从架子上摘下的苹果,而在生产环境中部署一个想法更像一个橙子。对我来说,将机器学习解决方案部署到生产中不太像橙子;这更像是种一棵橘子树,然后等待它结果。加上种树、修枝、浇水以及其他任何事情,相当于一个碾压级的技术债。
如果你在谷歌上搜索“将机器学习模型部署到生产中”,你会找到大量的材料和方法。事实上,在 Medium 上,也有大量的文章。例如, Isaac Godfried 提供了一篇出色的文章和一个有用的图表。此外,李宗德·韦恩用 Flask 和 HTML 用户界面提供了一个使用深度学习模型的好例子。
我的任务就是为求职者揭露 NLP 程序,帮助他们改进简历。你可以在的前一篇文章中看到迄今为止所做努力的总结。上次我们谈到了保护我们的原型:锁定我们的数据科学原型和隐私概念证明。这篇文章将总结我从原型到部署的服务以及这两者之间的一切的工作。如果您愿意,您可以观看应用程序部署的视频,这有助于很好地展示这个概念。
作者 YouTube 帐户-作者的视频。
主办;主持
如果你正在使用一个模型,并且需要取消一个预测,那么有大量的选择向你开放。其中绝大多数将涉及到模型的阶段化和围绕它包装一个 API。使用该模型需要一种机制来消费 API。例如,您可以建立一个推理服务器,全力以赴采用微服务方法。公开自然语言处理技术有点不同。
我使用了 EC2 实例,但是使用了由 AWS 提供的免费层津贴支持的 t2.micro 服务器。一般来说,我会认为 Heroku 或虚拟服务器,在这种情况下,我的直觉是 EC2。但是,同样,这取决于你能接受和支持什么。
堆栈
拥有一个全新的虚拟服务器是非常好的,但它只配备了一个操作系统、一个网络连接和一个防火墙。想象一下 10 年前,启动服务器是多么的不同。然后,它涉及到购买服务器,插入它,连接东西。Omg!
尽管如此,我还是需要在 Ubuntu 服务器上分层!
你可以把虚拟机想象成美味三明治中的第一片面包!我的三明治看起来像这样
- 面包 1 : AWS EC2 虚拟机。拥有一台能够按需改变电源的完整服务器让人感到坚定和自信。然而,安全问题是真实存在的,可能是一场噩梦。
- 黄油: apt 和 Ubuntu。所有的计算机都需要操作系统。我熟悉 Ubuntu,但你可以选择 Windows 或 Linux,或者在不同风格的 Linux 之间选择。他们都有不同的口味,有些比其他人更敏锐。黄油会变质,所以要给你的操作系统打补丁。
- 用 Python 填充 1: FastAPI 。提供 NLP 服务需要一个后端进程准备好服务这些传入的请求。我的 NLP 类包括常见的嫌疑人!
- 填充 2: Gunicorn 。这可能看起来有点奇怪!难道 Gunicorn 不是一种 WSGI 方法,而 FastAPI 是一种 ASGI 技术吗?是的,但是 Gunicorn 有一个伟大的工人和过程控制者。
- 灌装 3: 紫玉米。ASGI 服务器与 FastAPI 应用程序进行通信。部署 Uvicorn 很有趣,自然地,我使用了 Gunicorn worker 类。" guni corn-k uvicon . workers . uvicon worker "
- 蛋黄酱:主管。" Supervisor 是一个客户机/服务器系统,它允许用户在类似 UNIX 的操作系统上监视和控制许多进程。"。好吧,如果东西倒了,被打翻了,被消费者的需求或坏演员压垮了,难道你不想要一个主管来维持运转吗?
- Topping:使用 Vue.js 的用户界面。前端保持整洁;没有人想要一个混乱的三明治体验!
- 面包 2 : Nginx 。三明治的顶部需要结实,传达自信。如果我拿起这个三明治,它还会在一起吗?没人想全身都是三明治!添加 Nginx 可以提供负载平衡、静态文件服务和反向代理服务。
现在,这可能是世界上最神奇的三明治,为预期用户提供了很好的体验。多个 Gunicorn 工人和 Uvicorn 为由 Nginx 监督和代理 FastAPI 端点安排服务应该是一种很好的体验。如果你把你的三明治包在某个包裹里,那是最好的。当我想要一个赛百味三明治时,我知道去哪里,因此如果你想让客户访问你的应用程序,你需要发布你的地址。
马修·巴德梅克在 Unsplash 上拍摄的照片
包装产品
打包应用程序需要一些移动部件和大量的技术债务偿还!
- 一个域。首先,我需要一个用户友好的网址。https://www.justresumes.net 是我选择的,我是从 AWS 的 53 号公路上得到的。有很多可用的指南,AWS 会全程帮助你。
- 将服务器连接到一个地址需要一个固定的 IP 地址。你不会希望你的企业名称和地址是可变的!那会让所有人困惑。我使用了来自 AWS 的一个弹性 IP 地址,并将其连接到我的服务器实例(Bread 1)。
- 一个电子邮件地址,因为人们可能会有问题或反馈。你需要一个域的电子邮件地址来使用 SSL 证书并有一个联系页面。我使用了一个 Google workspace 账户,并按照指南将我的网址与我的收件箱账户连接起来。谷歌为你做这一切!" admin@justresumes.net "
- 一个 SSL 证书通过验证,安装了和相应的私钥。火狐、Chrome 和 Safari 对网站的安全性有自己的看法。因此,任何没有 SSL 证书的网页都显得“不安全”。我用了一个免费的教程使用 SSL 来做这一块。90 天的证书只是另一笔等待偿还的技术性债务。
- 一个博客——很自然地,我为此在媒体上建立了一个出版物!
下面是一些漂亮的截图因为这些东西伤透了我的心!
连接安全
作者显示登录页面安全信息的图片。
为电子邮件配置域
图片来自 53 号公路、托管区域、自定义域电子邮件服务的 DNS 设置—图片由作者提供。
证明
没有让我心碎的东西感谢 Auth0
那个看起来很酷的登录按钮——由作者截图
登录后,“注销”按钮会以冷红色显示。漂亮!
那个看起来很酷的注销按钮——由作者提供的 Vue.js 的 Auth0 starter 截图
你可以在我准备的的视频里看我吃那个三明治。
做三明治
编排整个应用程序堆栈有许多部分。事实上,给定开发应用程序所需的材料、步骤和解释,我可以写一本书。
突出
使用 FastAPI :最初,我想使用 FastAPI 应用程序提供静态和 JSON 内容(API 端点响应)。然而,那对我不起作用。所以,我决定使用 Nginx 提供静态内容,这意味着 index.html 和所有 vue.js 块都由 Nginx 直接提供。流量通过到套接字的 Nginx 反向代理流向 FastAPI 应用程序。在 Gunicorn 进程的控制下,Uvicorn 工人监控套接字,并对来自客户端的 API 调用做出必要的响应。应用程序由管理员监控和运行,这保证了服务器上应用程序的弹性。我用了一个教程帮我,很高明!
***https://blog.askjarvis.io/fastapi-with-nginx-gunicorn-and-supervisor-on-ec2-2e0258441d7c
**Nginx 配置:**设计有几个步骤。我用了教程来帮助我,这些都很有帮助。当我们谈论个人或敏感的个人数据时,安全性至关重要。
https://ubiq.co/tech-blog/nginx-ssl-configuration-step-step-details/ https://www.tecmint.com/nginx-web-server-security-hardening-and-performance-tips/ https://www.cloudsavvyit.com/3782/how-to-configure-cache-control-headers-in-nginx/
CORS: 我犯了 CORS 错误!所以我不得不使用 CORSMiddleware 来解决这个问题,我不认为这是一个好主意!
origins = ["*"]
# Creates app instance
app = FastAPI(openapi_url=None)
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
生产中的 Swagger UI:考虑到数据和安全问题,我不喜欢让 Swagger UI (FastAPI 文档)可用。关掉它很容易。
app = FastAPI(openapi_url=None)
**发送电子邮件:**两难的选择是在后台还是在前台发送。我选择从客户端在 vue.js 中做。到目前为止,我不确定这个决定是否明智。
https://www.freecodecamp.org/news/send-emails-from-your-vue-application/
**认证:**我使用了 Auth0
API 端点安全性是通过 FastAPI 的依赖注入实现的
@app.get("/api/private")
async def private(response: Response, token: str = Depends(token_auth_scheme)): result = VerifyToken(token.credentials).verify()
if result.get("status"):
response.status_code = status.HTTP_400_BAD_REQUEST
return resultreturn result
Auth0 再次提供了前端视图安全性,这里有一个 vue.js 组件作为例子。
<template>
<div>
<Highlighter v-if="$auth.isAuthenticated"/>
<Hero v-else />
</div>
</template>
如果用户执行了身份验证,屏幕上会显示一个“荧光笔”组件;否则就是登陆页的‘英雄板块’。
除此之外,做这个三明治并不容易!
关闭
从原型到生产应用远比看起来复杂。与粉笔或奶酪的类比大不相同,令人崩溃的技术债务水平让我夜不能寐。此外,安全是根本,互联网上的一切都在不断受到攻击。如果你不相信我,可以查看 Nginx 访问日志。暴力攻击每天都有!
我写这篇文章是为了与数据科学家、分析师和对在生产环境中部署自然语言服务感兴趣的人分享这一经验。我们都同意这不容易!然而,这些讨论是初创企业每天都要面对的,当你读到你的社交媒体账户出现重大中断时,也许你现在有了更好的见解。一个小小的改变可以打破一切!
Erik Mclean 在 Unsplash 上拍摄的照片
https://cognitivedave.medium.com/membership ***
从数字到范畴
原文:https://towardsdatascience.com/from-numerical-to-categorical-3252cf805ea2
存储数字要素的三种方法
弗兰克·麦凯纳在 Unsplash 上拍摄的照片
根据原始值所在的区间将宁滨数字要素分组可以提高模型性能。发生这种情况有几个原因。首先,可以基于领域知识来定义这些箱,以帮助模型更好地识别它正在寻找的模式。第二,数据总是有测量误差,宁滨可以减少这些误差的影响。
在基于领域知识的宁滨之外,有三种常见的方法:等宽度、等频率和 k 均值方法。(k-means 方法超出了本文的范围。)等宽取数值变量的范围,并将其分成大小相等的区间。这意味着组的大小是相同的,但是每个箱中的观测值的计数可以有很大的不同。这方面的一个例子是将个人的年龄分为五年或十年。等频箱该功能在每个箱中创建大致相等的计数。在年龄的情况下,如果大多数人都是二三十岁,宁滨十年甚至五年就能创造出无用的垃圾箱。宁滨通过频率,这些共同的年龄将更好地分开,更有利于模型。
熊猫中的宁滨
使用开源软件包 RasgoQL 从数据库中提取的天气数据,
dataset = rql.dataset('Table Name')
df = dataset.to_df()
使用 pandas 的cut
功能可以很容易地创建等宽箱。在这种情况下,创建了 4 个偶数大小的箱。
df['HIGH_TEMP_EQ_BINS'] = pd.cut(df.DAILY_HIGH_TEMP, bins=4,
labels=False, include_lowest=True)
类似地,qcut
可用于创建每个仓中计数大致相等的仓。
df['HIGH_TEMP_FQ_BINS'] = pd.qcut(df.DAILY_HIGH_TEMP, q=4,
precision=1, labels=False)
宁滨与 sci kit-学习
使用 scikit-learn 的预处理功能KBinsDiscretizer
也可以创建相同的库。为了创建与箱相等,我们将策略设置为“统一”。
est = KBinsDiscretizer(n_bins=4, encode='ordinal',
strategy='uniform')
df['HIGH_TEMP_SK_EQ_BINS'] = est.fit_transform(
df[['DAILY_HIGH_TEMP']])
类似地,将策略设置为“分位数”将创建大致相等的频率区间
est = KBinsDiscretizer(n_bins=4, encode='ordinal',
strategy='quantile')
df['HIGH_TEMP_SK_FQ_BINS'] = est.fit_transform(
df[['DAILY_HIGH_TEMP']])
无论哪种情况,要将模型投入生产,都需要为生产环境重写这些转换。在熊猫版本的情况下,需要从cut
或qcut
中提取截止值,并将其硬编码到生产代码中。在 scikit-learn 的情况下,要么需要删除截止,并重写整个转换以使用这些截止,要么需要保存预处理对象并将其重新加载到生产环境中。
除了将建模代码重构为生产代码之外,当处理大量数据时,这种方法在最好的情况下会很慢,在最坏的情况下几乎不可能。对于大量的数据,仅仅是等待数据传输到建模环境就浪费了大量的时间。如果数据足够大,它可能不适合 pandas 的内存,并且不是所有的数据都可以用于这些转换。
现代数据堆栈中的宁滨
通过利用开源 Python 包 RasgoQL ,这两个问题都可以避免。首先,因为 RasgoQL 直接在数据库中创建 bin,所以它可以处理任何大小的数据。其次,在创建这些 bin 并在 Python 中检查它们的过程中,底层 SQL 代码被保存在数据库中。这意味着,当新数据到达数据库时,它将随着应用的箱而自动可用。
为了创建等宽条,可以使用“等宽”类型调用 RasgoQL 函数bin
。
eq_bin = dataset.bin(type='equalwidth',
bin_count=4,
column='DAILY_HIGH_TEMP')
eq_bin.save(table_name="HIGH_TEMP_EWB")
或者,将类型设置为“ntile”将创建相等数量的箱。
fq_bin = dataset.bin(type='ntile',
bin_count=4,
column='DAILY_HIGH_TEMP')
fq_bin.save(table_name="HIGH_TEMP_NTB")
此时,这些数据集被发布回数据库,并可在建模和生产环境中使用。
虽然直接在 pandas 中宁滨数据或使用 scikit-learn 的宁滨函数很容易在传统的 Python 机器学习工作流中实现,但当处理存储在数据库中的大数据时,转换为 SQL 方法在速度上具有优势,并且易于推广到生产中。基于 SQL 的特征工程允许更快的处理、更容易的生产路径以及跨多个项目的特征重用。然而,大多数数据科学家更喜欢 Python(或 R)而不是 SQL,而且,对于许多计算来说,SQL 是复杂的。开源包 RasgoQL 允许数据科学家继续在 Python 中工作,但在数据库中执行计算。
如果你想查看 RasgoQL,文档可以在这里找到,在这里找到库。
从律师助理到数据科学家——我是如何在没有定量学位的情况下开始我的数据职业生涯的
分享我获得第一个数据角色的技巧和经验
为什么我要写这篇文章
我毕业时获得了国际关系学士学位,而且只修完了少数几门统计学和经济学课程。有了 5 年的工作经验后,我开始从事分析方面的职业。我在完成兼职数据科学训练营的一年内获得了我的第一个正式数据职位,同时全职工作。我希望我的经验和技巧能够对其他渴望进入数据科学领域的人有所帮助和鼓励。
我的策略是去最有职业发展潜力的公司工作。
我之前分享了我是如何从一家律师事务所工作到一家初创企业的第一次职业转型。我收到了多个不同角色的邀请,从客户成功到法律。最终,我接受了一份内部律师助理的工作。当我试图离开法律领域的时候,为什么我选择律师助理这个角色,这看起来似乎是违反直觉的。
因为我不确定我下一步想做什么,所以我更看重我在公司的职业机会,而不是头衔或我将从事的工作类型。在与我的经理进行持续的职业对话后,我表示有兴趣在公司尝试不同的角色。在她的支持下,我对客户体验(CX)团队进行了角色转换。
在新的 CX 职位上,我被数据分析工作所吸引,并确定了所有可能的资源来加快我的学习。
三种截然不同的经历脱颖而出,让我有了适用的工作经验。更重要的是,我在这些经历中都得到了经验丰富的专业人士的指导:
- 我参加了一个兼职数据科学课程,学习基础统计学和编程。这门数据科学课程与众不同,因为我的搭档是一位精通编程和 ML 技术的数据科学专家。
- 我申请并被德尔塔分析公司接受了为期六个月的奖学金,该公司为非营利组织提供无偿数据咨询。我有机会应用我在新兵训练营学到的东西,并与其他数据专业人员建立联系。
- 我与我在 CX 团队的经理和数据分析主管合作,制定了一个定制的轮换计划,在这个计划中,我将与数据分析团队密切合作。在轮换期间,我创建了一个对 CX 团队和整个公司都有用的数据产品。我还得到了经理和团队成员的指导,并对在集中式数据团队中工作有了很好的了解。
完成轮岗后,我开始求职,过渡到正式的数据角色。
在我找工作的过程中,我经历了许多拒绝,因为我无法提供结构化的回答来通过案例研究面试。
最初,我申请了不同领域和部门的许多类型的数据角色。一些人在业务运营团队中专注于财务指标,其他人是分析用户行为和漏斗指标的产品角色。
面对如此多样的角色和领域,准备案例研究和完成带回家的挑战是势不可挡的。我会花几个小时去学习我不熟悉的不同指标和产品领域。
尽管我尽了最大努力,但我不会比第一轮更进一步,因为我会在案例研究面试中惨败。比失败更糟糕的是,我很难知道如何准备未来的面试,因为我对自己不知道的东西感到不知所措。我花时间思考如何前进,并意识到我可以申请突出我的优势而不是强调我的弱点的角色。
为了提高我的面试成功率,我把重点放在了我的专业知识能够为案例研究和带回家的挑战提供结构化方法的职位上。
在无数次失败的面试后,我将我申请的数据角色缩小到客户体验和运营领域。通过这样做,我可以集中精力准备面试,并从不同公司的每一轮面试中学习——不管是否顺利。我在两个月内找到了一份新工作,我的专业知识让我很快进入状态。我知道该向商业伙伴提什么问题,并在几周内赢得了第一笔交易,尽管这是我的第一个正式数据职位。
给那些目前受雇的,但不是官方数据角色的提示汇总:
- **与您的经理合作,寻找工作中的数据机会,或设计/申请轮岗计划。**就我个人而言,这是启动我的分析职业生涯中最关键、最有影响力的经历。如果你已经在一家科技公司工作,问问你的经理你是否有专门的时间从事数据项目,并接受数据专家的指导。这对我来说是可能的,当时我在一个大约 500 名员工的 D 轮创业公司。这又回到了我之前关于决定在一家高增长的初创公司工作的观点——尽管没有正式的轮换计划,但我和我的经理能够迅速与数据分析主管合作,并在短短几周内确定轮换的要求和时间表。如果你在一家较大的公司,你可以向你的经理提出轮岗计划,或者直接申请轮岗(如果有提供的话)。如果你不确定,这也是一个在完全投入工作之前先了解一下工作的好方法。我遇到过一些年轻的专业人士,他们在自己的岗位上做一些数据工作,最终决定留在他们的运营岗位上。
- **完成数据科学课程,学习技术技能和基本概念,建立信誉。**这可能是老生常谈,但这是学习技能和增长知识的最快方式,而不是等待工作中的合适项目或改变工作职能的绝佳机会。等待这样的机会将比投入专门的时间要长得多。通过完成一个新兵训练营,你不仅有一个真实的项目组合来展示你的技能,而且还可以在你的职业转变中获得你的经理的支持。这可以让他们更有信心去寻找数据项目并将其分配给你,因为你已经展示了你的能力。
求职者招聘第一个数据角色的附加提示:
- 找工作时,对职位持开放态度。即使你完成了数据科学课程,产品或数据分析师职位也能提供类似的职业机会。你应该能够在面试过程中感受到这个职位的技术性,以及它是否适合你的技能。我遇到过一些成功的转行者,他们在接受不同职位的训练营后相对较快地找到了工作。分开来说,你永远不知道一个角色加入公司后会发生什么。许多公司已经重组了他们的数据团队,从分散模式到集中模式,反之亦然,并改变了职称,作为品牌重塑的一部分。
- 利用你过去的经验。你可能拥有其他技术人员可能没有的宝贵领域知识。如果你在银行工作,你可能对客户如何使用他们的账户或给企业带来风险有深刻的理解——利用这一点。业务运营或财务团队中的数据角色可能非常适合。如果您的背景是客户支持,您可以寻找与客户服务和代理绩效指标相关的数据角色。
- 寻找志愿者机会,向其他数据专业人士学习,并解决真实的数据问题,如 Delta Analytics 。我发现这比独立完成 Kaggle 项目更有帮助,因为我需要责任感。
结论
我希望这篇文章能给你一些鼓励和启发,让你从非传统背景的职业转变为技术角色。请记住——找到工作只是您数据职业旅程的开始,但随着您知识和经验的加深,您在准备旅程时的成长和学习心态将始终适用!
卷积神经网络:导论
从感知器到 DenseNet 的短暂旅程
杰姆·萨哈冈在 Unsplash 上的照片。
人们可能有理由怀疑,当网上有许多关于同一主题的介绍时,为什么有必要再介绍一次卷积神经网络。然而,本文将读者从最简单的神经网络感知机带到深度学习网络 ResNet 和 DenseNet,(希望)以一种可理解的方式,但肯定是以一种简洁的方式,在几个步骤中涵盖了深度学习的许多基础知识。所以我们开始吧——如果你想的话。
介绍
机器学习是人工智能的重要组成部分。它用于许多应用领域,如图像识别、语音识别、风力预测和药物设计。数据科学是一个与人工智能密切相关的新兴领域,专注于学习,预测专注于收集,可视化,推理和学习模型的预处理。特征是描述观察的变量。一个模式x∈ℝᵈ是一组特征。标签 y ∈ ℝ 是我们感兴趣的观察结果。模式-标签对形成了基本事实。
监督学习通过调整分类器的参数来适应训练模式,从而在训练阶段训练分类器。从形成 d 维训练集的一组模式-标签对(xᵢ,yᵢ)* 与 i = 1 …,n 与xᵢ∈ℝᵈ中,训练一个机器学习模型 f ,用于预测适当的标签信息在分类中,标签是离散的,例如 {0,1} 并被称为类或类别,而在回归中,标签是连续的。*
感知器
感知器[1]是一个简单的神经单元(f:ℝᵈℝ),汇总加权输入并将其输入激活功能
这里,x∈ℝᵈ是感知器的输入,w∈ℝᵈ是权重, b ∈ ℝ 是偏差, w x 是所有x的分量乘积之和****
激活函数 ReLU 图
功能σ:ℝℝ是一种激活功能,类似于整流线性单元,简称 ReLU,见图 1:
ReLU 可以计算得非常快,这解释了它在深度学习方面的成功。在众多进一步激活的功能中,乙状结肠功能是其中之一:
将输入映射到 0 和 1 之间的值和双曲正切值:
映射到区间 [-1,1] 。
将多个感知器分层允许分离更复杂的集合,也包括像 XOR 问题这样的非线性集合。密集层将众多的感知机放入一层。连续层的所有神经元相互连接,即密集连接。密集层也称为全连接(FC)层。输入层的神经元数量对应于模式的维度。一个多层感知器(MLP)由一个输入层和一个输出层以及一个或多个隐藏层组成,见图 2。
图 2:左:有一个隐藏层的 MLP 的插图。右图:多个图层允许非线性分类边界。
这个以神经元为节点的 MLP 图中的每条边都配备有自己的权重 w ᵢ.如果 x ∈ ℝᵈ 是一个层的输入并且w**∈ℝ^{k×d }是一个层的权重矩阵,那么
是有偏差的加权和b∈ℝᵏ。输出是一个 k 维向量,其元素被逐元素地馈送给激活函数σ,从而产生相应层的激活向量。如果需要处理通道信息(图像的 RGB 值),张量的扩展是合理的。信息从输入层传递到输出层。因此,与具有反向连接的循环网络相比,该网络体系结构被称为前馈网络。
网络权重和偏差通常统一初始化为小值,如-0.01 到 0.01。或者,Glorot 初始化旨在使一个层的输出方差等于其输入方差。Glorot 从以 0 为中心的正态分布中抽取样本,标准偏差基于输入和输出的数量。
损失函数
在分类中使用一个热编码,这意味着一个输出神经元对应于一个返回 1 的输出类,而所有其他神经元返回 0。例如,在数字数据集的 K=10 类的情况下,使用一个热编码的 MLP 采用 10 个输出神经元,每个表示一个类,例如y=(0,0,1,0,0,0,0,0,0,0)^t 用于数字 2* )。*
为了实现对 K 类的一个热编码,最后一层的 k = K 神经元的最终激活 y’被馈送到 softmax:
它将所有输出调整为 0 到 1 之间的值,而所有输出的总和为 1。这些值将被解释为类别概率。最后,提供 softmax 函数的最高输出的输出神经元确定 MLP 的分类决策,即:
利用交叉熵(也称为对数损失)来计算整个训练集的误差,该交叉熵面向香农熵原理。在所有数据训练样本上,我们得到总体平均交叉熵损失如下:
其中 n 是训练集大小或批量大小, yᵢⱼ ∈ {0,1} 是来自训练集的标签的地面真实概率, y’ᵢⱼ ∈ [0,1] 是来自 softmax 的第 I 个示例中第 j 个类的预测概率。由于一个热编码,每个图案和每个维度都有一个 yⱼ 。对于接近 1 的大差异,罚分产生大的分数,对于接近 0 的小差异,罚分产生小的分数。
在回归中,MSE 最常用作损失函数:
对于标签 y₁、…、yₙ ∈ ℝ 和输出 y’₁、…、y’ₙ ∈ ℝ 。引入的损失函数用于调整神经网络的权重。
损失函数用于训练模型,见下一节。但是为了评估分类的准确性,像召回率和精确度这样的测量是有用的。在分类中,一个模式可以被正确分类(真)或不被正确分类(假)。在两类分类场景中,我们可以区分正确分类为正的真正(TP)模式和真正分类为负的真负(TN)模式。假阳性(FP)模式被分类为阳性,但应该是阴性,假阴性(FN)模式被错误地分类为阴性。对于两个以上的标签(阳性和阴性),混淆矩阵是一个一般化。在矩阵的每个位置,它计算属于属于该行的类的模式的数量,并且被分类到属于该列的类。模型的精度定义为 TPs / (TPs + FPs ),表示正面预测的准确度。同时,被定义为 TPs/(TPs + FNs)的回忆表明实际阳性被发现的程度。
培养
学习就是体重适应。训练阶段的典型设置是调整网络的所有权重 w ᵢ 和偏差 bⱼ ,使得模式被 MLP 映射以校正训练集的标签。
神经学习中主要的权重自适应算法是反向传播。反向传播对权重执行梯度下降,以最小化损失函数 L ,该损失函数例如可以是交叉熵或 MSE。梯度下降是一种优化方法,它将搜索移动到梯度的相反方向。
点**处的梯度δl(w)w∈ℝᵏ是一个k*-偏导数的维向量∂l(w)/∂wᵢw . r . t .各参数 wᵢ、I*
梯度下降通常比无向随机搜索更快。对于回归问题,损失定义为残差平方和,对于分类,常见的损失函数是交叉熵损失,参见上面的等式。
如果损失函数 L 是可微的,可以计算偏导数 ∂L/∂w w. r. t .权重,从而得到梯度δl(w)。梯度下降通过以学习率 η 进入梯度的相反方向来执行最小化:
此更新也称为普通更新。
**对于简单的感知器 f(x) 与 f(x) = σ (wx + b) ,具有输入模式 x ,目标标签 y ,sigmoid 激活函数,以及损耗 L = 1/ 2 (y — σ (z),我们示例性地导出反向传播:
用链式法则。常数消失,又是链式法则,利用 sigmoid 的导数,我们得到:
在一个时期中,完整训练集的所有模式被呈现给网络。权重更新的一个成功变体被称为随机梯度下降(SGD)。SGD 在呈现一个模式后更新权重并计算梯度。因此,它试图通过一次只考虑一个训练样本来逼近真实梯度。如果训练集被打乱并分成不连续或重叠的批次,则训练可能是有效的。在小批量模式中,用训练样本子集的梯度来训练神经网络。SGD 不如 mini batch 健壮,但它允许更快的步骤。此外,它可能更少陷入局部最优。局部最优采用了比其邻域更好的适应度,但可能不是全局最优,见图 3。
图 3:局部最优的图示。
如果与整个训练集的真正梯度下降相比,小批量梯度下降是正常梯度下降和 SGD 之间的折衷。
动力
学习率 η 在训练网络中起着重要的作用。动量有助于避免权重更新的振荡,并允许更快的收敛。以下是对权重为 k 的多元变量的扩展,即δw,δl(w)∈ℝᵏ。在经典动量中,旧的权重变化δw再次应用递减因子β∈【0,1】😗*
termβδw在极端梯度的情况下减缓自适应过程,防止优化器超调。开始时,δw被设置为零矢量。左边的图 4 说明了动量原理。
图 4:动量图(左)和内斯特罗夫动量图(右)。
内斯特罗夫动量是动量更新的延伸。它为凸函数提供了更强的理论收敛保证。实际上,它比标准动量理论更有效。它将动量视为一种前瞻,即首先进入动量方向βδw*,并从那里计算现在略有不同的梯度∇l(w+βδw*)在新的前瞻位置:****
图 4(右)展示了内斯特罗夫的势头。过去已经提出了不同的权重更新变体,其中一个突出的变体是 Adam。
过度拟合
专注于适应训练模式的模型可能过度适应训练数据,并且可能学习复杂的适应,尽管期望的模型结构可能不太复杂。这导致模型的泛化能力不足。过度拟合可以通过正则化、交叉验证和退出来避免。
正则化基于权重的大小,例如所有权重的平方和,向误差分类或回归误差L(w)添加惩罚:
带参数 α 的情况下 L 正则化,其中
是权重向量 w 的 L 范数。大的重量与过度配合有关,而小的重量被认为可以防止过度配合。对权重的惩罚强制小权重,从而防止过度拟合。
交叉验证(CV)使用一组训练样本进行训练,并在独立的验证集上评估模型质量。推广到不止一个这样的交叉验证过程,N 重交叉验证将随机混洗的数据集分成 N 个分离的子集,参见图 5。每个子集都被排除一次作为验证集。对所有的 N 个折叠重复该过程,并对误差进行平均。对独立测试集的最终评估可用于说明模型质量。
图 5: CV 重复地(这里是 3 次 3 折 CV)留下一个(灰色)验证集,并在剩余的(蓝色)折叠上训练模型。
一个极端的例子是 N=n 的留一交叉验证(LOO-CV),即每个模式都是一个折叠。从统计学的角度来看,它是有用的,但是由于大量的训练过程,它是非常低效的,因此主要适用于小数据集。
控制遗漏验证集上的误差允许早期停止,即,在验证误差增大而训练误差进一步减小的情况下退出训练过程。
在训练阶段,Dropout 关闭每个神经元的概率为 p ∈ [0,1] ,称为 dropout rate。对于每个隐藏层、每个训练样本和每次迭代,随机分数 p 激活被忽略,也称为清零。在测试阶段,所有激活都被使用,但按系数 p 减少。这说明了在训练阶段缺少激活的原因。Dropout 也用于卷积层,参见 dropout 部分,它也随机地将激活置零。
图 6 显示了辍学情况。灰色神经元不参与训练过程。它们的权重不会更新。
图 6:在退出期间,神经元以概率 p 被去激活,这里示出了训练期间的灰色神经元。
Dropout 迫使网络学习类的多个独立表示,这防止了过度拟合。也可以理解为多个子网的集成学习,将它们的决策结合起来。
卷积层
卷积网络很早就已经推出[2],但 Alex Krizhevsky 在 2012 年的 ImageNet 大规模视觉识别挑战赛中使用 AlexNet 实现了图像识别的突破。图 7 示出了示例性的网络架构。卷积层充当平移不变特征学习器。
图 7:带滤波器和信道的卷积网络架构。
*设 X 为 H × W × C- 维度输入。一个卷积层由*C’乘以 C m × m 个滤波器核矩阵组成。对每个输入通道执行卷积运算,并对结果求和。该操作是针对每个过滤器内核执行的。卷积运算将一个 m × m- 维内核矩阵 w 从左上至右下移动到输入体积,参见图 8,计算:
*滤波器内核 w 通过反向传播进行调整,并学习有用的特征检测器。输入 x 和 w 之间的相似性产生高激活 a 。每个输入通道的激活被累加,因此由*C’被加数组成。该过程被重复C’次,导致C’输出通道用于输出 A 。
图 8:2D 卷积过程的例子。
例如,具有 32 × 32 彩色图像的 CIFAR-10 网络的第一卷积层可以采用 64×3 滤波器核 3 × 3 矩阵。该层将输出 64 个通道。
滤波器核在输入体矩阵上移动的步长称为步幅。它采用垂直轴和水平轴。两个轴的步幅都是一个常见的选择,见图 9。较高的值降低了计算和存储的复杂性。为了避免维度收缩,输入体积的边界可以用零填充,例如,通过添加W-m零。这个过程称为零填充。
图 9:1×1 步的图示。
偏差 b 可被添加到输出体积,即所有激活。卷积层的输出应用激活函数A’**=σ(A),例如 ReLU。汇集层减少了集中于最大或平均激活的维度。滤波器核的数量通常随着网络的深度而增加。**
联营
卷积层导致激活显著增加。为了减少数量,使用了池层,参见图 10。池化是一种基于渠道的操作。
图 10: Max pooling 返回输入体积内的最大值,该最大值通常以对应于体积维度的步幅移动(这里是 2x2)
设 A 为激活的特征图,最大池在每个通道上移动一个 m × m 方块,选择最大值:
平均汇集是使用每个方块的平均值的相应过程。汇集层也可用于替换密集层头(激活的最后一层)。
VGG-19 是早期卷积网络的一个例子。它由 19 个权重层组成,对于 224 × 224 RGB 图像的输入具有以下配置:
****
FC 表示全连接层。这三个 FC 也被称为 MLP 头。VGG-19 使用了 1.44 亿个参数,是深度架构的一个例子。
雷斯内特
一个网络使用的参数和权重越多,它就能代表越多。数百层是可能的,但是训练起来计算量很大。但是非常深的网络容易过度拟合。随着误差以倍增的方式通过网络向后传播,每层中的梯度更新变得更小。这种效应随着层数的增加而增加,称为消失梯度问题。ResNet [3]通过以恒等式 X 的形式提供快捷连接来解决这个问题,并将它们添加到一个模块的输出 R 中,这就变成了一个来自输入的残差。残差比恒等式更容易学习。ResNet 模块提供身份,并学习与他们的偏差。层和身份的总和成为一个 ResNet 模块 R :
而剩余的 R 就要学会了。为了匹配 R 和t18】xt20】的尺寸,可以添加投影矩阵 W ₚ ,从而得到:****
图 11 示出了基于两个卷积层的示例性 ResNet 模块。
图 11:ResNet 模块的标识快捷方式连接。
ResNet 原理可以应用于由全连接或卷积层组成的所有类型的模块。甚至快捷连接也可以由覆盖卷积层模块的一个卷积层组成。
对最优模型 f 的搜索可以被视为在函数类 F 中的搜索。在这个空间中,神经网络是由架构、超参数和权重定义的函数 f ∈ F 。改变函数类不一定会使其更接近 f 。一个 ResNet 模块实现了添加剩余部分的恒等式,从而表示一个嵌套函数,即它持有f’⊂f,这强制向最优 f* 移动,参见图 12。**
*图 12:用 ResNet 模块实现的嵌套函数类(右)更接近最佳函数 f ,非嵌套函数类(左)则不一定
原始论文中的 ResNet 架构采用 152 层,一个 7 × 7、64 步距 2 卷积和一个 3 × 3 最大池,步距 2 后接以下卷积 ResNet 模块:
由每三个回旋组成。在网络的末端,使用 1000 维全连接层和 softmax 进行平均池化。
DenseNet
在 DenseNet [4]中,各层以前馈方式与后续各层相连,参见图 13 或 DenseNet 模块。像泰勒级数展开一样,将函数分解成越来越高的项,DenseNet 用越来越深的层来表示函数。
图 13:在密集块中,卷积层的每个输出都被馈送到后续层的输入。密集块的最后一层是过渡层。
在 l 层的密集块中 l ⋅ (l + 1) / 2 连接被引入。每个卷积层接收所有先前层的输出作为输入,并向每个后续层产生自己的输出。先前层的输出被连接(不像在 ResNet 中那样被求和):
每一个密集块增加通道的数量。过渡层限制了模型的复杂性,瓶颈 1 × 1 卷积层减少了信道的数量,平均池层,例如,步幅 2 将高度和宽度减半。这样,过渡层减少了输入维度。密集架构允许具有相同性能的不太深(即,更浅)的网络,并且还解决了消失梯度问题。
结论
卷积神经网络不仅是人工智能中最重要的方法之一,其基本方法和原理也用于许多其他深度学习算法。例如,反向传播是几乎所有深度学习方法的优化主干,卷积层是众多神经架构的一部分。它们的应用不仅限于图像识别,而且在许多其他领域也得到了证明。如果您想更深入地了解上述主题和实现,请参阅进一步阅读部分的一些参考资料。Python 是深度学习的最佳编程语言,Keras 以及 PyTorch 可以让你轻松访问卷积神经网络。
除特别注明外,所有图片均为作者所有。
延伸阅读
- 潜入深度学习,张等人,
- 统计学习导论,第 2 卷,詹姆士等人,https://hastie.su.domains/ISLR2/ISLRv2_website.pdf
- 喀拉斯简介、https://keras.io/getting_started/
- Keras Simple conv net、https://keras.io/examples/vision/mnist_convnet/
一些(可能的)参考文献
[1] F. Rosenblatt,感知器——一种感知和识别的自动机,康奈尔航空实验室,报告№85-460-1(1957)
[2] Y. LeCun,B. Boser,J. S. Denker,D. Henderson,R. E. Howard,W. Hubbard,L. D. Jackel,反向传播应用于手写邮政编码识别,神经计算,1(4):541-551(1989)
[3]何克明,张晓明,任树生,孙杰,图像识别的深度残差学习,,第 770-778 页(2016)
[4]黄,刘,范德马滕,温伯格,稠密连接卷积网络.CVPR,2261-2269(2017)
从图表到仪表板:可视化技巧和窍门
原文:https://towardsdatascience.com/from-plots-to-dashboards-visualization-tips-and-tricks-f7e46bff5197
我们已经进入了秋季馅饼季节(这是我们刚刚发明的一个概念),这意味着圆形、切片、比例和尺寸是我们许多人的首选。现在是用一些新想法来充实我们复杂的 dataviz 技能组合的最佳时机吗?
撇开隐喻不谈,数据可视化的目标在很长一段时间内都是一致的:将复杂的关系和错综复杂的事实转化为清晰、易于解读的叙述。然而,我们用来创造有效视觉效果的工具和方法从未停止进化。本周,我们分享一些最近的文章,帮助你增加可视化工具包的深度和广度。让我们开始吃吧。
- 谁不喜欢互动图表? 比清晰的视觉效果更好的一件事是你的观众可以玩弄和操纵的图表。Erdogan Taskesen 最近推出了开源 Python 库 D3Blocks,它使用户能够创建 10 种不同类型的流畅的交互式可视化,从热图到桑基图。
- 【居 R 之术】 。也许,表格没有图表和绘图那么华丽,但它仍然是展示相互关联的数据的重要媒介。 Devashree Madhugiri 收集了 R 中的七个基本包来生成强大、有效的表。
- 为您的仪表板找到正确的方法 。放大开源面板库, Sophia Yang 和 Marc Skov Madsen 展示了即使使用单一工具,“也有多种方式来构建仪表板”,这取决于项目的范围和目标。它们提供了三种不同的方法,每种方法都针对一个特定的用例。
- 如何清晰地呈现比例和百分比 **。**即使我们庆祝秋季馅饼季节,我们也必须承认糕点的同名图表已经不受许多数据从业者的青睐。如果你正在寻找更现代的饼状图的替代品,Boriharn K 提供了不少于 9 个想法供你考虑(互动甜甜圈图,有人吗?).
如果你的阅读欲望还没有满足,这里有一些其他的近期亮点供你探索:
- 交互设计师、建筑师和首次 TDS 作者 Karen Asmar 发表了一篇引人入胜的深度探讨人工智能转变和增强数字设计工具的潜力。
- 在另一次 TDS 首次亮相中, Partha Sarkar 探索了数字孪生建模及其在诊断、预测和规定分析中的应用。
- 对于非专家来说,量子深度学习可能看起来密集而令人生畏,这使得 Holly 徽易于理解的量子卷积神经网络(QCNNs) 介绍特别有帮助。
- Florent Poux,博士继续他正在进行的 3D 模型拟合探索,亲自动手演练一个基于 Python 的点云项目。
- 我们将用新一代语言模型构建什么样的应用程序? Amber Teng 和 Jeremie Harris 一起在 TDS 播客上讨论这个经常性的问题。
谢谢你一如既往的支持。如果你想产生最大的影响,可以考虑成为中级成员。
直到下一个变量,
TDS 编辑
从明信片到雪花
原文:https://towardsdatascience.com/from-postgres-to-snowflake-f4b403548066
当我把 DWH 从波斯格里斯迁移到雪花时遇到的有趣的点
图片由 Paul Owens 在 Unsplash 上拍摄
我最近遇到了一个任务,似乎是许多使用 PostgreSQL 作为主数据库的公司在某个时候需要做的任务。
这是 ETL 脚本从 PostgreSQL 到雪花的迁移。
整个过程包括基于辛格和 DBT 技术从零开始构建 ETL 管道,我稍后可能会详细介绍,但现在我想集中讨论 PostgreSQL 和雪花 SQL 语法之间的差异。我希望它对那些发现自己处于类似情况并需要重写大量 SQL 的人有用。
数字
PostgreSQL 是一个关系数据库,具有所有优点和缺点,有时需要微调,包括转换到最适合的类型。但雪花的情况并非如此。
首先需要将int2
、int4
、int8
等类型转换为int
。第二个也是更容易出错的区别是,尽管两个数据库中都有一个类型numeric
,但雪花将这种类型的数据视为整数,而在 Postgres 中,它也可以包含小数。换句话说,雪花不会给出任何误差,但一切都会被四舍五入。
不同于
我相信对于大多数分析数据库来说,只需要获得最后一行或第一行是很常见的情况。Postgres 有一个针对它的distinct on
构造,但是 Snowflake 不支持它,所以必须使用row_number
窗口函数或qualify
构造来解决这个问题(https://docs . snow flake . com/en/SQL-reference/constructs/qualify . html)。例如,这就是我们如何获得第一个用户会话开始的时间戳。
JSON 空值
Snowflake 使用 JSON 很棒,但是有时那里的字段有null
值,结果 SQL is null
不起作用。有两种选择:要么使用特殊函数is_null_value (
https://docs . snow flake . com/en/SQL-reference/functions/is _ null _ value . html,要么通过strip_null_value (
https://docs . snow flake . com/en/SQL-reference/functions/strip _ null _ value . html函数去除空值,然后使用普通的is null
SQL 检查。我个人认为后一种解决方案更有吸引力。
过滤
在分析中向度量(聚合函数)添加过滤器是一种常见的做法,在 SQL:2003 的 Postgres 中有一个很好的语法。不幸的是,Snowflake 不支持它,所以解决方法是通过case
构造来走老路。例如,在这里,我们计算不同设备类型的会话数。
横向连接
雪花支持横向连接,此外,当需要解析 JSON 数组时,它被大量使用,但是有一些限制。其中一个限制是我们不能在横向连接中使用limit
。一种常见的情况是,我们只需要获得第一行就行不通了。解决方法是将其转换为 CTE。实际上,CTE 将在 Postgres 和雪花中工作,所以横向连接的解决方案只是对 Postgres 的优化,但我们在大多数情况下不需要对雪花进行这样的优化,因为引擎的工作方式不同。在下面的代码片段中,我们得到了每个会话的第一个事件。
递归
好消息是,雪花完全支持递归,它会工作。问题在于局限性。在 Snowflake 中,默认的递归深度是 100,它可以增加,但仍然有一些限制(我们在这里将 Snowflake 视为托管服务)。不幸的是,由于这些限制,雪花递归根本不能解决一些问题,例如库存操作列表的加权平均成本/价格。(在 Postgres 中,我们可以使用这个解决方案:https://stack overflow . com/questions/22426878/calculating-the-weighted-average-cost-of-products-stock)
我找到的唯一解决方案是要么在雪花之外进行计算,要么创建一个存储过程。
其他…
当然,在函数,过程,写 UDF 的方式,和存储过程方面还有很多不同,但是这篇文章的目的是分享我的经验,所以我希望它会有用。
从原始数据到干净的数据库:对多功能数据工具包的深入研究
数据库ˌ资料库
使用通用数据工具包(VMware 最近发布的一个框架)和 Trino DB 的完整示例
马库斯·温克勒在 Unsplash 上的照片
最近,VMware 发布了一款新的开源工具,名为通用数据工具包(简称 VDK),可以非常快速地管理数据。该工具允许用几行代码将不同格式的数据接收到一个数据库中。
在我之前的文章中,我描述了一个基本的例子,它使用了 VDK,并且描述了如何安装和运行它。总而言之,您应该:
- 有一个运行的数据库(VDK 以外)
- 在 VDK 中配置数据库接口,包括用户名、口令、主机和端口
- 在 VDK 定义如何使用 SQL 查询或用 Python 实现的更复杂的过程接收数据库中的数据。
一旦您在数据库中获取了数据,您就可以根据需要使用它们,例如,构建有趣的仪表板或可视化。
在本文中,我主要关注一个完整的例子,从数据接收开始,一直到数据处理。该示例使用 Trino 数据库和 MySQL 服务器来存储数据,使用 VDK 来接收数据库中的数据。
下图显示了一个可能的架构,包括 VDK、Trino 服务器和 MySQL 服务器:
作者图片
具体来说,文章组织如下:
- 场景的定义
- 数据库的设置
- VDK 的数据接收
- VDK 的数据处理
1 情景的定义
该方案的目标是分析美国不同地区的预期寿命,并将它们与该地区的国内生产总值(GDP)进行比较。为了实现这一目标,您应该下载与美国预期寿命相关的数据,并将其与相关的 GDP 合并。
这个例子展示了如何通过 VDK 提取和集成这个场景所需的数据。
我们可以使用以下两个数据集,它们都以 CSV 文件的形式提供:
之前的数据集是在美国政府工程许可下发布的。
除了前面的数据集,我们还可以使用以下附加数据集:
前两个数据集分别由美国经济分析局和美国人口普查局发布,两者都在公共许可下提供开放数据。
数据集2010-2015 年美国各州和人口普查区出生时预期寿命包含 73,121 条与 2010-2015 年期间美国人预期寿命相关的记录,按州和县划分。
下图显示了数据集的摘录:
作者图片
数据集“2018 年美国各州按性别划分的预期寿命”包含 156 条与 2018 年美国人预期寿命相关的记录,按州和性别(男性、女性、总数)划分。下图显示了数据集的摘录:
作者图片
数据集“美国各县国内生产总值”包含 3,163 条与美国各县实际国内生产总值相关的记录,涉及 2017 年至 2020 年期间。数据集包含许多列。下图显示了数据集的摘录:
作者图片
数据集“美国各县国内生产总值”包含 3,163 条与美国各县实际国内生产总值相关的记录,涉及 2017 年至 2020 年期间。数据集包含许多列。下图显示了数据集的摘录:
作者图片
2 数据库的设置
我们将所有数据存储在 Trino 数据库中,作为 MySQL 服务器的接口。 Trino 是一款用于大数据分析的分布式开源 SQL 查询引擎。它运行分布式和并行查询,速度非常快。对于 Trino 数据库的设置,你可以遵循我之前的教程。
在本例中,Trino 在本地运行,具有以下最小的config.properties
配置文件:
coordinator=true
node-scheduler.include-coordinator=true
http-server.http.port=8080
query.max-memory=5GB
query.max-memory-per-node=1GB
query.max-total-memory-per-node=2GB
discovery.uri=http://127.0.0.1:8080
http-server.https.enabled=false
此外,Trino DB 使用 MySQL 目录,配置如下(文件mysql.properties
位于 Trino 服务器的目录文件夹中):
connector.name=mysql
connection-url=jdbc:mysql://localhost:3306
connection-user=root
connection-password=
allow-drop-table=true
最后,这个例子假设 MySQL 服务器上存在一个名为life-expectancy
的空模式。
3 VDK 的数据接收
VDK 使用以下配置运行(config.ini
):
db_default_type=TRINO
ingest_method_default = trino
trino_catalog = mysql
trino_use_ssl =
trino_host = localhost
trino_port = 8080
trino_user = root
trino_schema = life-expectancy
trino_ssl_verify =
数据摄取将数据源部分中定义的两个 CSV 表上传到数据库中。对于每个表,通过以下步骤执行数据接收:
- 删除现有的表(如果有)
- 创建新表格
- 直接从 CSV 文件中摄取表格值。
前两步将使用 SQL 语言编写,而最后一步将使用 Python 编写。
每个数据集都将被包含在一个名称与数据集名称相似的表中。例如,美国出生时预期寿命(按州和人口普查区域)——2010–2015数据集将被纳入life_expectancy_2010_2015
表中。
3.1 删除现有表格
首先,我创建一个脚本,命名为01_delete_table_life_expectancy_2010_2015.sql
:
**DROP TABLE IF EXISTS** life_expectancy_2010_2015
脚本名称前面的数字01
表示 VDK 框架将把它作为第一个脚本运行。
我还创建了02_delete_table_life_expectancy_2018.sql
脚本,它删除了life_expectancy_2018
表,其他脚本删除了us_regions
和us_gdp
表。
3.2 创建新表
现在,我为新表创建模式,并将其存储在03_create_table_life_expectancy_2010_2015.sql
脚本中:
**CREATE TABLE** life_expectancy_2010_2015 (
State varchar(32),
County varchar(32),
CensusTractNumber varchar(32),
LifeExpectancy decimal(4,2),
LifeExpectancyRange varchar,
LifeExpectancyStandardError decimal(4,2)
)
与前面的脚本类似,我创建了04_create_table_life_expectancy_2018.sql
:
**CREATE TABLE** life_expectancy_2018 (
State varchar(32),
Sex varchar(32),
LEB decimal(3,1),
SE decimal(3,1),
Quartile varchar(32)
)
以及us_regions
和us_gdp
表:
**CREATE TABLE** us_regions (
State varchar(32),
StateCode varchar(2),
Region varchar(32),
Division varchar(32)
)**CREATE TABLE** us_gdp (
County varchar(32),
Year2017 bigint,
Year2018 bigint,
Year2019 bigint,
Year2020 bigint
)
3.2 直接从 CSV 文件摄取表格值
最后,我可以接收life_expectancy_2010_2015
表中的表值。我使用 VDK API 提供的IJobInput
类。我定义了一个将被 VDK 框架读取的run()
函数,并在其中编写了摄取代码:
import pandas as pd
from vdk.api.job_input import IJobInputdef **run**(job_input: IJobInput): # Read CSV file url = "http://data.cdc.gov/api/views/5h56-n989/rows.csv"
dtypes = {
"State": str,
"County": str,
"Census Tract Number": str,
"Life Expectancy": np.float64,
"Life Expectancy Range": str,
"Life Expectancy Standard Error": np.float64,
} df = pd.read_csv(url, dtype=dtypes).replace("'", "''", regex=True)
df.columns = df.columns.str.replace(" ", "") # Ingest CSV file job_input.**send_tabular_data_for_ingestion**(
df.itertuples(index=False),
destination_table="life_expectancy_2010_2015",
column_names=df.columns.tolist()
)
为了获取数据库中 CSV 的每一行,我使用了IJobInput
类的send_tabular_data_for_ingestion()
方法。
我们可以用同样的技术摄取其他数据集。
4 VDK 的数据处理
数据处理包括以下任务:
- 清洁桌子
- 合并已清理的表
4.1 清洁桌子
清洁life_expectancy_2010_2015
工作台包括以下两个操作:
- 按县分组记录
- 将列
LifeExpectancyRange
拆分成两个十进制列MinLifeExpectancyRange
和MaxLifeExpectancyRange
。
life_expectancy_2010_2015
工作台的清洗过程的输出被存储在一个名为cleaned_life_expectancy_2010_2015
的新表中。
前面的两个操作都可以通过 SQL 语句实现:
**CREATE TABLE** cleaned_life_expectancy_2010_2015 **AS**(**SELECT** State,
LifeExpectancy,
cast(split(life_expectancy_2010_2015.LifeExpectancyRange,'-')[1] AS decimal(4,2)) AS MinLifeExpectancyRange,
cast(split(life_expectancy_2010_2015.LifeExpectancyRange,'-')[2] AS decimal(4,2)) AS MaxLifeExpectancyRange,
LifeExpectancyStandardError
**FROM** life_expectancy_2010_2015
**WHERE** County = '(blank)'
)
在数据集中,所有带有County = '(blank)'
的行包含给定县的预期寿命总值。因此,只需选择这些行,我就可以轻松地按县分组。
下图显示了结果表:
作者图片
现在,我打扫桌子。清洁life_expectancy_2018
工作台包括以下操作:
- 将列
LEB
重命名为LifeExpectancy
- 将列
SE
重命名为LifeExpectancyStandardError
- 将列
Quartile
分成两个十进制列MinLifeExpectancyRange
和MaxLifeExpectancyRange
- 仅选择带有
Sex = 'Total'
的行。
前面的所有操作都可以通过一条 SQL 语句实现:
**CREATE TABLE** cleaned_life_expectancy_2018 AS(**SELECT** State,
LEB AS LifeExpectancy,
cast(split(life_expectancy_2018.Quartile,' - ')[1] AS decimal(4,2)) AS MinLifeExpectancyRange,
cast(split(life_expectancy_2018.Quartile,' - ')[2] AS decimal(4,2)) AS MaxLifeExpectancyRange,
SE AS LifeExpectancyStandardError **FROM** life_expectancy_2018
**WHERE** Sex = 'Total' and State <> 'United States'
)
下表显示了cleaned_life_expectancy_2018
表的示例:
作者图片
注意,清理之后,cleaned_life_expectancy_2010_2015
和cleaned_life_expectancy_2018
表具有相同的模式。
4.2 合并清理后的表格
最后,我准备合并所有的表。我执行以下操作:
- 垂直合并
cleaned_life_expectancy_2010_2015
和cleaned_life_expectancy_2018
工作台之间的; - 结果表与
us_regions
和us_gdp
表之间的水平合并。
垂直合并意味着将第二个数据集追加到第一个数据集,而水平合并向结果表添加三个新列,称为Period
、GDP
和Region
,结果表称为merged_life_expectancy
。仅针对带有Period = '2018'
的记录设置GDP
属性。对于其他记录,它被设置为0
,因为它不可用。
**CREATE TABLE** merged_life_expectancy **AS**(**SELECT** us_regions.State,
LifeExpectancy,
MinLifeExpectancyRange,
MaxLifeExpectancyRange,
'2010-2015' AS Period,
Region,
0 AS GDP
**FROM** cleaned_life_expectancy_2010_2015
JOIN us_regions
ON us_regions.State = cleaned_life_expectancy_2010_2015.State
)**UNION**(**SELECT** us_regions.State,
LifeExpectancy,
MinLifeExpectancyRange,
MaxLifeExpectancyRange,
'2018' AS Period,
Region,
Year2018 AS GDP
**FROM** cleaned_life_expectancy_2018
JOIN us_regions
ON us_regions.State = cleaned_life_expectancy_2018.State
INNER JOIN us_gdp
ON us_gdp.County = cleaned_life_expectancy_2018.State
**WHERE** Year2018 > 100000000
)
在第二个SELECT
语句中,WHERE
条件指定了Year2018 > 100000000
。这允许只选择县。
最终的表格如下表所示:
作者图片
摘要
恭喜你!您刚刚学习了如何在 VDK 接收和处理数据!这可以通过用 SQL 和 Python 编写简单的脚本来实现。
这个例子的完整代码可在这里获得。
下一步是构建显示处理结果的报告。敬请关注,了解如何操作:)
对于多功能数据工具包的问题或疑问,您可以直接加入他们的公共 slack workspace 或他们的邮件列表或在 Twitter 上关注他们。
如果你读到这里,对我来说,今天已经很多了。谢谢!你可以在这篇文章中读到更多关于我的信息。
相关文章
https://alod83.medium.com/how-to-represent-and-query-hierarchical-data-in-sql-69b6b77577e8