TowardsDataScience-博客中文翻译-2021-九十一-
TowardsDataScience 博客中文翻译 2021(九十一)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
从健康前期过渡到数据科学/技术职业
原文:https://towardsdatascience.com/transitioning-from-pre-health-to-a-career-in-data-science-tech-2c3b61a57bf5?source=collection_archive---------34-----------------------
本科阶段进行职业转变的技巧/资源

图片来自 Unsplash
在弗吉尼亚大学读了两年医学预科生后,我慢慢意识到我不能也不想在接下来的 10 年里保持我所需要的奉献和时间水*(我在很多间隔年都保持着这种速度,lol)。我慢慢地过渡到统计学专业,并决定对一个叫做“数据科学”的职业轨道感兴趣。我真的不知道这条赛道意味着什么,甚至也不知道它意味着什么,我只是听到周围有很多关于本世纪新的赚钱工作的话。最终,我开始理解这个领域背后的细微差别,并慢慢爱上了现实世界中数据科学/ML 的理论和应用(在本文中,我将两者互换使用)。然而,我的学*曲线和过渡变得陡峭,因为我在冒险进入数据科学和技术领域时犯了一些错误。我想分享一些的提示和建议来帮助缓解并为那些希望转行进入科技行业的人引导这种转变。一开始,有如此多的时髦词汇和不断扩展的技能组合看起来超级吓人,但随着时间的推移和正确的学*路径,一切都变得熟悉了。在整篇文章中,我还附上了我在转换过程中发现很方便的资源。
先成为程序员
这尤其适用于那些试图进入数据科学领域的人,对于那些试图直接进入技术领域的软件工程的人来说,这显然是一项技能。在我还是一名医学预科学生的时候,我的课程内容和学*都是以记忆为中心的(T2)。医学预科有大量关于最微小话题的细节,我的一般方法是先记忆,后应用。这种心态让我一开始很难接受编程和计算机科学。起初,我被我的计算机科学朋友们的数百行代码吓住了,我寻找任何可以避开编程的方法。这是我转变过程中的第一个大错误。我专注于 ML 模型背后的理论和数学部分,这引起了我的兴趣,对我更有吸引力。虽然这在构建我的各种 ML 算法背后的理论知识库方面很棒,但我不能真正应用它。没有具体的编程技能,我很难构建任何 ML 驱动的应用程序或模型。直到我坐下来,选择了一门语言(Python ),深入研究了面向对象编程和数据结构/算法,我才能够对自己的编程技能有一定程度的信心。起初,对于非程序员来说,语言和框架的数量看起来是惊人的庞大和陌生,但是在发展了对一种语言的信心和直觉之后,掌握这些其他工具就真的不难了。随着我作为一名程序员的进步,我展示 ML 技能的能力大大提高了,我能够看到 ML 在现实世界应用程序中的实际效果。我已经链接了一门我用来开始我的 Python 学*之旅的课程,Python 是数据科学最常*/流行的语言。一般来说,就像这样的在线课程而言,我不建议你不顾一切地完成课程,而是先掌握基础知识,然后自己练*问题或项目。如果你不想花钱上 Udemy/Coursera 的课程,send ex也是一个了不起的专门研究 Python 和 ML 的 YouTuber。归根结底,互联网上有无限的资源,无论是通过互联网还是通过课程,我都强烈建议在钻研数据科学之前,先熟悉编程基础 。
改变心态
我在前面的部分稍微提到了这一点,但是在这个转变中最大的变化之一是我如何解决问题。我不得不慢慢地从死记硬背的方法转变为更直观地看待问题。起初,我几乎试图记忆语法,因为我的大脑已经被编程为思考。在意识到这种思维模式在计算机科学领域是多么不可行之后(以及在发现堆栈溢出之后),我开始明白编程是需要通过重复才能掌握的东西。无论我学的是什么语言,都只是一种解决逻辑问题的工具,是为更大的应用程序拼凑解决方案的工具。这种心态的转变花了几个月的时间,因为我对自己作为一名程序员越来越适应了。它最初也有助于将我的科学背景进行类比,以帮助减少我对新领域的不熟悉。例如,在面向对象编程中,我与分类学领域紧密相关,以理解继承等基本概念。我也没有完全放弃基于内存的方法,因为我经常在代码中寻找模式,这在优化时证明是非常有用的。
机器学*部分
所以“重要”的部分,真正构成“数据科学”的部分。实际上,大部分数据科学都不是模型构建部分,这就是为什么您需要强大的编程基础来正确地准备/清理数据并理解部署。对于 ML 背后的实际理论,我强烈建议获得对概率和线性代数的基本理解。如果你在学校的时候有时间,一定要试着在这两个学科上学*一些课程。如果你更想了解自己的类型,网上还有很多资源。两个主题的可汗学院学*路径是对该领域的一个很好的介绍。概率方面,特别要确保你有很强的微积分背景。在学*的同时或之后,我强烈建议参加一个入门水*的 ML 课程。我再次向在线学*者推荐何塞·波尔蒂利亚的 ML 训练营。他是一个很好的指导者,可以帮助你起步,并很好地介绍了各种 ML 模型。不是每个人都必须是超级理论抛光,他是一个非常好的资源,为那些寻求更多的应用程序重。对于需要更多数学和人工智能知识的更多以理论为中心的课程,我强烈建议探索 LazyProgrammer 的课程。不管你开始 ML 的课程是什么,就像编程一样,你只能通过应用和重复练*来熟悉真实世界的数据集。我建议从 Kaggle 开始探索一些杂乱的数据集,然后尝试搜集/收集您自己的数据,为您的个人项目或想法构建 ML 驱动的应用程序。
— — — — — —
就像数据科学和技术领域一样,这篇文章似乎一下子给了你很多。在这些领域学*的方法是在得到介绍后,让你的脚脏起来,直接投入到实践问题中去。克服最初的阻碍和对新事物的厌恶是许多生活变化的常*现象。拥抱这个领域将会带来的变化和机遇。你以前的经历丰富了你的心态,让你变得更加多样化。总结一下一般的学*路径,我建议那些试图进行这种转变的人如下。成为一名程序员(掌握一门语言、OOP 和数据结构),在概率和线性代数方面打下坚实的数学基础,从应用/理论角度理解各种 ML 算法/模型。在这三个步骤之后甚至期间:练*,练*,再练*。数据科学和 ML 背后的魅力在于能够将该领域应用于您寻求解决的任何现实世界问题。如果你仍然对医学前的问题感兴趣,那么在那个领域有很多 ML 的机会。无论是 x 光图像分类还是使用 NLP 分析医疗报告,都有许多有趣的项目需要解决。
我希望这个建议对已经阅读了本文的人有用。这些只是帮助我过渡到技术世界的一些技巧。请随时在 Linkedln 上与我联系,或者在 Medium 上关注我,了解我更多的写作内容。分享任何想法或反馈,谢谢阅读!
从社会科学过渡到数据科学
原文:https://towardsdatascience.com/transitioning-from-social-science-to-data-science-7e22501b5a3b?source=collection_archive---------5-----------------------
办公时间
你知道什么和你应该知道什么

斯科特·格雷厄姆在 Unsplash 上拍照
作为一个在计算机科学或工程或数学方面受过有限正规培训的人,尝试向数据科学飞跃可能会令人望而生畏。似乎几乎所有的工作描述都要求某人拥有某个核心领域的学位,尽管这很有趣也很重要,但从未引起我们这些社会科学领域的人的兴趣,他们更喜欢对人和社会的研究,而不是对细胞、化学物质、能源、数字或诸如此类的研究。
当我开始研究数据科学时,我确实有这种感觉。在翻遍了无数的职位描述,寻找一个拥有我从未研究过的学位的人之后,我很难不去想,*有没有一个适合具有数据科学社会科学背景的人的地方?*或者,我没有主修物理科学或工程,我真的能成为一名数据科学家吗?
好了,现在已经做了数据科学家,我很高兴的说有和你可以回应以上问题!也就是说,一开始可能很难理解你的社会科学背景如何在数据科学中有用,而且肯定有一些关键的东西熟悉起来会有帮助,这些东西你可能在学校里从来没有学过。我希望这篇文章能让你了解你的社会科学背景如何能帮助你成为一名强大的数据科学家,并帮助你确定你应该掌握哪些学校没有教给你的技能,以*稳过渡。
社会科学背景
我自己的社会科学训练来自传播领域,特别是大众传播形式的研究(广播媒体、社交媒体等等;特别是娱乐媒体)以及人们与它们的互动和反应。但社会科学的标签可以应用于我自己领域之外的所有领域,例如心理学、社会学、犯罪学、经济学、政治学等。事实上,这些领域的毕业生占每年学士毕业生的很大一部分。在他们当中,你不是唯一一个希望进入数据科学的人,也不会是第一个成功的人,所以不要绝望!
社会科学与数据科学的相关性

腾雅特在 Unsplash 上拍摄的照片
认识到社会科学为进入数据科学提供了一个特殊的背景,这实际上不应该是疯狂的。任何社会科学的核心都是调查人们(或群体)的背景、思维或行为的各种刺激或元素如何与所述人们(或群体)的其他思想或行为或结果或特征相关联,社会科学家对这种分析的重要经验是他们的优势所在——我们可能会理所当然地考虑人们的背景、思想和行为的影响,但这不是大多数人花很多时间做的事情!当然,你处理的数据的细节将取决于职位,但我可以放心地说,在许多工作中,你所做的大部分工作都需要调查和预测某种类型的人的行为——无论是买家、卖家、观众、用户、互动者、司机、骑手,还是任何人——以及这种行为如何变化,取决于他们是谁(例如人口统计、心理测量)、他们做过什么(例如过去的行为特征),以及他们的想法。
更具体地说,在社会科学中普遍获得的关于人的数据的经验在三个特定方面派上了用场。首先,也是最直接的一点,对结果中的人口统计学和心理学差异进行大量思考确实有助于设计方法严谨的分析来调查这些差异。对于那些在学校工作期间接受过正式的研究设计培训,能够流利地识别和解释中介的人来说尤其如此;版主;对内部、外部、结构、标准有效性的威胁;等等,也许甚至能够设计和分析可靠的随机实验。您考虑和说明这些元素的经验将有助于设计严格的分析,清晰地测量他们宣称要测量的东西。
其次,直接建立在这个基础上,来自社会科学对建模有很大的帮助。在构建回归和分类模型时,了解可能影响特定变量的人口统计和心理测量因素的范围以及这些因素如何相互作用是一项很有价值的技能。这种直觉可用于特征转换(例如,知道某些变量,如收入,通常是有偏差的)和特征选择(当更系统的方法不理想或不可行时),并且还可以在数据结构认为合适时,帮助指定更复杂的模型(例如,分层线性模型、结构方程模型)。
最后,社会科学背景在数据科学中的一个不太明显的帮助是关于特征工程。那些来自社会科学的人无疑遇到了各种旨在解释特定现象或行为的理论,通常附有图表显示某些结构如何直接或间接导致结果。这种理论可以成为特征工程的有用框架,尤其是如果一个人有为难以测量的变量想出巧妙的代理变量的经验。例如,行为预测的整合模型[2]认为,执行行为的意图可以通过态度(一个人对行为的感觉)、感知规范(对行为“正常”程度的感知)和自我效能(一个人是否觉得自己可以执行该行为)来预测。例如,在预测用户 A 是否会听歌曲 X 的上下文中,现有的消费数据和相关元数据可以用于生成近似这种结构的特征——例如,用户 A 对歌曲 X 的态度可以由用户 A 对与歌曲 X 具有高元数据相似性的歌曲的消费来表示;用户 A 关于收听歌曲 X 的规范可以由具有与用户 A 相似的收听历史的用户收听歌曲 X 的程度来表示;并且自我效能可以由用户 A 听过的歌曲的各种不同艺术家、流派和国籍来表示。
如果你足够幸运,在一个研究可以直接应用到你所做的事情的领域工作,以上所有的观点都是正确的,就像我一样。在对媒体偏好和效果进行了大量研究后,我对开发旨在预测不同层次媒体消费的模型感到非常满意。但是,即使你的研究领域没有完美地投射到你的行业,随着时间的推移,你会观察到你可能希望研究的方法论的相似之处。例如,您可能有很多将文本挖掘技术应用于文档的经验,但随后您可能会意识到,这种技术可以合理地应用于任何可以将数据视为文本主体而不仅仅是文档的上下文中——无论是用户元数据、歌曲元数据、消费历史还是其他。对于你所熟悉的领域中的某些框架如何应用到其他地方,保持开放的心态是至关重要的。
螺母和螺栓:关键技术技能

照片由皮埃特罗·詹在 Unsplash 上拍摄
但是,如果你没有一套特定的关键技术技能,你所有的学校教育和智慧都不会让你在数据科学领域取得任何进展。尤其是你在各种求职页面上看到的各种不同的“专业化”——实验、推理、机器学*、可视化等等——很难知道你真正想要掌握什么工具。某些工作肯定会要求更多地应用某些技术,但我确实觉得有一个所有数据科学家都应该熟悉的“核心”工具包。
剧透提示:实际上所有这些技能都包含一些编码元素。我知道编码的想法可能会让一些人望而生畏,但底线是,如果你想从事数据科学,你必须适应编码以及随之而来的考验和磨难。参加一个课程,获得一个证书,做任何你需要做的事情来熟悉基础知识。一个好的起点可能是在谷歌上搜索一个听起来很有趣的数据项目的教程,然后从那里开始。无论你从哪里开始,只要知道在 StackOverflow 等人的帮助下搜索问题并排除故障,其他人也遇到了同样的问题,这是一个永恒的传统,即使是专业人士也一直在做,没什么可沮丧的。因此,让我们深入探讨一下我认为你应该熟悉的关键技能和概念。
- SQL :当我在就业市场的时候,这真的让我犯了一个错误——我的班级里没有人教过这一点,我也从行业人士那里听说,直接从学术界毕业的人通常缺乏这方面的技能。当然,拼凑和转换数据听起来可能很无聊,但是需要 SQL 的与数据相关的工作描述的数量确实很多。此外,在日常工作中,经常会有许多快速而繁琐的分析可以直接在 SQL 中完成,以节省时间。然而与此同时,如果没有某种可以实践的实时数据库,SQL 是很难获得功能实践的东西之一。在这种情况下,试着熟悉基本的核心数据帧操作,如在其他上下文中选择、连接、过滤和聚合,如 Python 中的 Pandas 或 R 中的 dplyr。使用正确的库,您甚至可以在 Python/Pandas[3]或 R[4]中练* SQL。
- Python :还有,我和下一个人一样热爱 R,但是据我所知 Python 确实是 DS 语言的通用语。Python 比 R 更加通用,除了在一些罕*的分析中,您需要的特定函数在 Python 中并没有健壮地实现(忘记 SPSS/Stata/SAS)。当涉及到严肃的数据科学工作时,特别是那些需要投入生产的工作(即以自动化、健壮、稳定的方式定期运行),Python 至少在 2021 年写作时是首屈一指的。
- Spark :至少对 Spark 框架有一个基本的了解——分布式计算、计算集群等等是如何工作的——对于处理大数据集来说是非常关键的。人们很容易认为在一些本地工作站上 32GB 甚至 16GB 的 RAM 对于大块数据集来说已经足够了,但是您无疑会遇到这样的情况:在一台机器上处理一个加载速度非常慢的大规模数据集是不可行的。这是另一个在没有实际部署的情况下很难实践该工具的例子,但是如果可以的话,至少要熟悉底层的概念。
- 统计,假设检验:人们喜欢要求比较数据,告诉他们是否有显著差异,但通常并不真正理解统计显著性意味着什么。作为数据专家,您自己肯定希望熟悉假设检验和基本统计学,以了解哪些检验适合在哪些情况下使用,并能够向他人恰当地解释统计检验的结果。
- 分类/回归:我感觉人们出于某种原因经常喜欢关注分类而不是回归。当你谈论精度和召回时,可能听起来有点浮夸,一些模型可以识别某个东西是否是 X,但让我们在这里现实一点:很多时候你的模型建立是为了预测值,而不是标签,因此回归的重要性。相关地…
- “核心”机器学*算法:不管你是哪种类型的数据科学家,这些天我都会说你对机器学*算法的“核心标准”的机制有些熟悉,比如 LASSO、random forest、SVM、boosting 等。是不落伍的必要条件。不管你是想做分类还是回归,如果你的工具箱里只有多元回归和逻辑回归,那你就落伍了。当你不太关心理解预测者和结果之间的潜在关系,而只想尝试最大化预测性能时,这种非参数算法非常有用。也就是说…
- 线性模型:虽然这样的黑盒算法很棒,但是当你想要对数据中的模式进行推断时,线性模型仍然可以说是最有用的。因此,掌握诸如多元回归、多级回归、逻辑回归等技术的一些基本知识是很重要的。此外,你会惊讶地发现,相对简单的方法,如多元回归和逻辑回归,在很多情况下可以让你走多远,有时甚至比上面提到的新方法表现得更好。
- 基本降维,聚类:这两种方法至少对可视化是有用的。当您不希望模型中有太多相互关联的预测值时,降维也很有用,同样,聚类也有助于确定数据中的模式,以便能够明确地将某些数据块归为相似的类别。主成分分析和探索性因子分析是降维的好起点,k-means 和 DBSCAN 是聚类的好起点。
- 干净的编码技术:最后,这是另一个让我纠结的问题,因为我从未接受过任何适当的计算机科学培训或经验:能够编写干净的代码是很重要的。当你为工作写代码时,你必须记住你不是唯一一个会阅读代码的人。你不能总是使用只对你有意义的首字母缩写词和缩写词,你必须有一些一致的逻辑结构来组织你的代码,命名变量,并留出文本空间。*惯于在一个干净、简单的流程中安排你的分析;非常清楚地命名变量(与‘df’、‘test _ df’、‘df _ 1’等相反);或许还可以看看像 PEP 8 这样的代码风格指南。
图书推荐

照片由金伯利农民在 Unsplash 上拍摄
作为一名数据科学家,很大一部分是不断学*新的概念和方法。如果你为你必须学的所有东西都去上付费课程,你会很快破产,所以你的资源往往是在线教程之类的。我发现书籍是介于课程和教程之间的快乐媒介,实际上是一套像课程一样的教程。在我准备进入数据科学领域时,我发现有几本与上述内容相关的书很有用,既有助于获取新材料,也有助于温*概念:
- 10 分钟 SQL(Forta):我用来开始学* SQL 的第一本书,提供了一系列难度递增的课程。
- SQL 练*题 (Vasilik):一旦我用上面的 Forta 书掌握了基础知识,我就用这本书来练*编写 SQL 查询。
- R 中应用的统计学*介绍 (James 等人):是的,这是一本 R 书,但我认为这本书提出了一些最容易理解的常*机器学*算法的解释。
- 广义因果推理的实验和准实验设计 (Shadish 等人):这不是一本技术书,但却是一本关于设计方法严谨的研究的非常好的书。
一些一般性的分手建议

乔纳森·肯珀在 Unsplash 上拍摄的照片
好的,到目前为止,我已经向您介绍了您的社会科学背景在数据科学中的价值,概述了您希望熟悉的工具和概念,以帮助您成功过渡到数据科学,并列出了几本您可能会在开始时发现有用的书籍。最后,我对渴望进入数据科学的社会科学家有一些一般性的建议,这些建议感觉有点太宽泛,无法在前面的章节中包括。
首先,无论你作为一名数据科学家选择进入哪个领域,都要确保你尽可能地了解这个领域。可以假设,任何给定的数据科学职位的许多候选人都有大量重叠的技术技能,与手头的行业相关的清晰领域知识可以将你推上比其他候选人更高的位置。从经理的角度考虑一下:当每个人都有大致相似的技能组合时,难道你不想雇用一个理解这些技能所应用的概念和指标的人吗?
第二,永远不要害怕“古怪地”思考。这是我认为来自社会科学真正有帮助的另一个领域,因为经常有如此多的理论旨在解释驱动各种结果的机制,创新的过程经常需要在两个以前没有做过的事情之间建立一种“奇怪”的联系。如果你觉得两件事之间有联系,你认为一个环境中的一种方法可以应用到另一个环境中,不要犹豫去研究它或者把其他人的想法弹开。我不介意偶尔发表一些让我听起来有点疯狂的想法,因为我知道偶尔会有一些评论会涉及一些真正有*地或新颖的东西。
最后,不管你去哪里,做什么,追求你的激情。拉尔夫·沃尔多·爱默生有一句名言是我最喜欢的:
最好的船的航程是一百个大船的之字形路线。从足够远的地方看这条线,它会把自己拉直到*均趋势。你真实的行为会解释它自己,也会解释你其他真实的行为。你的顺从说明不了什么。单独行动,你已经单独做的事情将证明你现在是正确的。【5】
我从小就不想成为一名数据科学家,但在每一步我都追求自己的激情,通过我真实的行动画出我的船的曲折。现在回想起来,我可以看到他们变得越来越倾向于他们的*均水*,这让我明白我所做的一切是如何把我带到现在的位置的。我希望当你在事业上取得进步时,你能追求你的激情,绘制出你自己最好的船的之字形。
签署
这就是我的全部,乡亲们!我希望这个建议对你有用,我真的尽力在这里概括了我作为一名渴望成为数据科学家的社会科学家在就业市场上所知道的一切。如果你想更多地联系和聊天,请随时在 LinkedIn 上添加我。祝你在成为数据科学家的旅途中好运!
在撰写本文时,Danny Kim(宾夕法尼亚大学博士) 是 Whip Media 的高级数据科学家,也是南加州大学安纳伯格传播与新闻学院的客座研究员。
参考
[1]https://nces.ed.gov/fastfacts/display.asp?id=37 最受欢迎专业(2021),
[2] M. Fishbein,健康促进的理性行动方法(2008 年),https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2603050/
[3] A. Bivona,如何在 Pandas 中使用 SQL(2020),https://towardsdatascience . com/How-to-Use-SQL-in-Pandas-62d 8 a0f 6341
[4] G .格罗滕迪克,sqldf:使用 SQL 操纵 R 数据帧(2017),https://cran.r-project.org/web/packages/sqldf/index.html
[5] R. W .爱默生《自立》(1841),https://www . Gutenberg . org/cache/epub/16643/pg 16643-images . html #自立
从学术界过渡到数据科学
原文:https://towardsdatascience.com/transitioning-to-data-science-from-academia-93299602e4ba?source=collection_archive---------12-----------------------
如何利用需要的技能,忘记其他的

布雷特·乔丹在 Unsplash 上的照片
**“如果学术界不成功,我可以一直做数据科学。”**这是许多研究生和博士后经历的一个反复出现的想法,尤其是如果他们的工作涉及数据科学的核心要素编程和统计的热情服务。
数据科学可能是学术界的有益替代,而学术界人士确实拥有许多品质,使他们成为数据科学职位的有吸引力的候选人。然而,学者们的技能组合中也有通常是大漏洞,这可能会阻止他们立即被聘用。
这篇文章将概述从象牙塔跳到工业界所需的技能。我们将轻于技术细节或商业敏锐度;要深入了解这些技能,请查看我的五部分如何进入数据科学系列。
特别是如果你刚刚开始考虑将数据科学作为一项职业,我强烈建议你思考一下你的理想角色在 分析-工程谱 中的位置,这将有助于你确定优先学*哪些技能。

迈克·范·登博斯在 Unsplash 上拍摄的照片
学术出类拔萃的地方
成功的研究极具挑战性。获得博士学位(甚至更高)需要显著的精神和情感成长。如果你在独立研究的挑战中幸存下来,那么你无疑已经:
1.从大量信息中提取有趣问题的能力。回答这些问题的分析能力。对细节的极度关注。较强的计划和组织能力。克服失败(并从中吸取教训)的坚强意志
你在研究生院获得的许多技能都非常适合成为一名优秀的数据科学家。在这两种情况下,你都需要批判性地思考该问什么问题,如何获得数据,以及如何从数据中提取有意义的*解。
这两种职业都需要与不同背景的利益相关者沟通和协调。
最后,两人都被期望不断学*,并在还没有解决方案的时候创新解决方案。
很难夸大这些技能的价值。许多高级或主管级别的数据科学职位需要博士学位,因为学术研究需要严谨的态度来确定解决棘手问题的方法。以下是我在谷歌上搜索了五分钟后找到的几个高级职位,以及他们的预期教育水*。

随着该领域的成熟,这些要求可能会在几年后放松,但目前,拥有博士学位是你作为数据科学家职业发展的主要资产。

图片由 Ishan @seefromthesky 在 Unsplash 上拍摄
学者在哪里奋斗
然而,上面这些诱人的工作,假设你已经从研究生院中忘却了很多心态。虽然你在学术界获得的技能对数据科学来说非常有价值,但优先考虑的事情往往是有害的。这是我认为学术界在转换到学术界以外的角色时经常会遇到的困难。
1.速度与精度的权衡
学术界优先考虑精确到小数点后第十位。毕竟,研究的目的是为了揭开真相不管需要多长时间。
但是考虑到他们有限的资源,100%的准确率对许多公司来说是不现实的。“足够好”可能是一个难以接受的概念,您的工作流程可能需要在有限的时间内尽可能快地转移到最大化准确性*。*
2。实施分析结果
除非你的数据科学职位实际上仍然是学术界的(例如 Mathematica 、布鲁金斯、**),否则仅仅创造知识是不够的。然后你需要说服利益相关者采纳你的结果,这需要一套完全不同的商业技能。如果你为一家科技公司工作,整合你的成果也需要另外一套完全独立的软件工程技能。**
这些技能差距可能会悄悄出现在你面前,而且非常明显——*庸的预测模型和卓越的预测模型之间的差异需要训练有素的眼睛,但任何人都可以看出,在你说你的模型对用户可用几周后,它就不可用了。
3。聚焦团队超越自我
当你离开学术界时,你从最大化你个人的产出过渡到最大化你团队的产出。是的,在学术界,你为你的合作者和学生的成功投入了巨大的努力。但是你的名字仍然出现在你合著的任何报纸、海报或研讨会上。
在学术界之外,你变得更加默默无闻。你的名字与工作脱节,公司以外的任何人都看不到你的贡献,这可能会令人沮丧。(很可能内部的许多人也看不*!)
同样,从学术工作的极端独立性过渡到与同事一起在字面上相同的代码库上工作,并且需要遵守编程最佳实践和产品管理,而不仅仅是那些在研究生院对你个人有用的东西,也是一个挑战。
4。做你不想做的事情
学术界无拘无束的自由,尤其是对美国项目而言,意味着你可以自由探索你最感兴趣的问题。如果你能为你的想法获得资金,没有人能阻止你规划自己的知识道路。
与此同时,在工业界,你的双手被牢牢地束缚在你的组织认定值得追求的问题上。当然,你对此有些发言权,但是如果你的老板坚决反对另一个线性回归,那就是你正在做的。
这些问题需要时间来克服。也许你可以很容易地关掉“100%准确”的心态,但要学会软件工程技能,比如 Git 、 SQL 和使用 API,就需要花费不止几个下午的时间。
当你申请工作的时候,拥有令人印象深刻的博士学位,同时又被刚毕业的计算机科学或新兵训练营的毕业生击败,这可能会让人迷失方向。下一节将重点介绍如何*稳过渡到新角色。

照片由 Jerry Zhang 在 Unsplash
过渡提示
心态
*当你进入就业市场时,把自己想象成 向雇主推销自己的劳动力 **是很有用的。*你有什么要卖的?
在你读博士期间,你很可能在执行特定类型的分析和特定类型的数据方面发展了专家级的技能。例如,也许你真的很擅长在天文无线电波中寻找模式。但是谁愿意为这种技能买单呢?而且,即使美国国家航空航天局正在招人,你觉得继续做你刚刚做了五年的同样的工作怎么样?**
如果你热爱你的研究,想继续下去,并且有非学术雇主愿意为此付费,那么你已经完全胜任你在学术界之外的第一个角色。恭喜你。但对于我们其他人来说,要成为有竞争力的申请人,还有很多工作要做。
不管你在分析工程领域,的目标是什么,你如何看待自己作为一名程序员的转变是你在行业中取得成功所必需的:
- 你可能在想什么:“我可以写任何我想写的东西。”
- 什么行业要:“任何人问我什么,我都能编码。”
当你可以灵活地选择你所追求的研究问题,以及如何回答这些问题时,你很容易被自己熟悉的问题和方法所吸引。在某种程度上,博士学位就是要在有限的技能范围内获得真正优秀的技能:你选择一个非常精确的问题来回答,然后努力工作,直到你比世界上任何人都更了解这个知识领域。
当你是一名数据科学家时,你不会拥有狭隘的技能组合, 尤其是如果你在一家较小的公司。软件工程中有一个术语叫做“全栈”——它指的是能够在前端和后端环境中进行专业编码的程序员,这两种环境需要完全不同的语言和视角。
数据科学就像是一个全栈分析师:你需要在从数据中提取*解的和构建基础设施以传达这些*解的之间自如地转换(比如仪表板和自动化脚本)。**
在我读博士期间,我发现呆在我已经非常熟悉的 R 和统计学领域非常容易。**我不想离开我的舒适区,因为这需要我面对一个可怕的概念,那就是我并没有真正掌握统计和编码。我觉得既然我在论文中使用了 R 和 stats,其他人就认为我是专家。因此,接受正式的统计或 R 职业会违背这些期望,暴露出我不是专家。**
具有讽刺意味的是,所有这些恐惧阻止了我对 R 和 stats 有一个坚实的、全面的理解。我也怀疑是否有人在乎我知道多少。
不要犯和我一样的错误——接受不知道所有的事情,并开始填补知识空白。你需要广泛的技能才能成为一名高效的数据科学家,这些技能需要保持和提高。我推荐在 Kaggle 、 HackerRank 和 Reddit 上查看数据集和挑战。
确保完成一些项目,而不仅仅是在网上课堂上做笔记——这会让你对这个主题有更深的理解,之后你会有东西给潜在的雇主看。

由伊恩·杜利在 Unsplash 上拍摄
目标
除非你真的不在乎离开学术界后在哪里工作,否则你可能会试图同时完成两个转变:1)进入数据科学,2)进入一个新的领域。
我的建议是首先过渡到数据科学,在专业环境中积累一些技能,在那里你可以向你的同行学*,然后过渡到你喜欢的领域。即使有博士学位,找到第一份工作也很难,所以广撒网吧!
理想情况下,尝试在一家拥有数据科学家、分析师和工程师团队的公司着陆,在那里你可以从你周围的每个人那里吸取知识。如果你最终想要工作的领域不一定有几十个数据科学家和工程师可供你学*,这一点尤为重要。
一旦你在第一个角色上投入了时间,并准备好进行第二次转变,就开始真正地思考你在寻找什么。对我来说,我想以某种方式为抗击气候变化做出贡献,但除了拥有生物学位之外,我没有这方面的经验。
一旦我开始找工作,我意识到我需要更加具体。我想在非营利组织或智囊团工作吗?政府呢——如果是的话,是市政府、州政府还是联邦政府?我是想加入一家可持续发展公司,一家大公司的可持续发展部门,还是一家可持续发展咨询公司?甚至在可持续发展中,这是指电动汽车、可再生能源、电池、航空、重工业、建筑改造、减少废物,还是其他?
你自己的搜索不需要这些问题的确切答案,但仔细思考将有助于缩小你要寻找的范围。对我来说,我意识到我想在可持续发展技术上磨练,所以我不再看智库、非营利组织和政府职位。
申请
从简历中删掉你的出版物。
是的,你需要剪掉它们。这是转变过程中最痛苦的部分之一。学术界的核心货币在象牙塔之外没有什么价值,除非你申请加入某个智库的博士团队。否则,添加一个链接到你的谷歌学术个人资料,点击保存,然后去散步,吃点冰淇淋。
虽然删减出版物是痛苦的,但只要稍加努力,你就可以填写一个雇主会觉得更有趣的项目部分。不管是好是坏,写代码是你随时随地都可以做的事情…包括你正常工作之外的事情。期望在简历中加入编码副业是有争议和问题的,但我认为当你试图进入这个领域时,额外的努力是值得的。
如果你有时间用一些简单项目的例子来创建一个 GitHub repo,你可以用具体的例子来说明你的代码是什么样的,以及你是如何解决问题的,这样可以大大增强你的简历。把招聘经理想象成决定是否雇佣艺术家的人——知道艺术家的作品是什么样子是很好的,不是吗?
最后,当你递交申请时,总是附上一份量身定制的求职信,解释你为什么想在这家公司工作,为什么你会是一个很好的人选,以及你在之前的职位中做出的最大贡献。我没有什么可以补充的,因为其他地方已经广泛涉及了;看看这封求职信的例子和这些简历技巧。不要用花哨的简历生成器——Google Doc 的免费单页模板很棒。

Alessandro Erbetta 在 Unsplash 上拍摄的照片
结论
当你考虑离开学术界时,会有很多矛盾的感觉。我喜欢它的理想主义——把热情、敏锐的人聚集在一起,共同解决世界上没有人知道答案的问题。每周给学生上课是一种特权。很难想象有人会付钱让我去参加会议和激动人心的实地考察——我有幸去过非洲两次,还差点去了南极洲。
但是在学术界成功的职业生涯需要大量的奉献:这就像成为一名运动员。你需要真正专注于你的主题,愿意多年来思考同样的难题,不断向资助者证明你的工作,并阅读你遇到的所有相关文献。
即使有着稳定的出版记录,除非你是所在领域的顶尖人物,否则你需要愿意每隔几年就搬到一个你无法提前预测的地方。
尽管这是一个由整天思考的人组成的领域,但在如何审查手稿、如何评估科学贡献以获得终身职位以及如何解决系统性不*等等问题上,存在大量的制度惯性。
学术界对一些人来说是一个令人惊叹的职业,但对我来说,我慢慢意识到数据科学是我一直在寻找的。
即使知道这一切,转变也是艰难的。改变你的身份会让你变得脆弱,当你开始一份新的职业时,你很难不感到尴尬或沮丧。
申请工作几个月后的一天,我在同一天被两个公司拒绝,一个是分析部门,另一个是工程部门,两个部门都是由博士组成的团队。公*地说,一个团队是经济学家博士,另一个是计算机科学家博士(我的学位是生物学),但即使在我的“同龄人”中,被拒绝也很难。
我在研究生院花了那么多时间成为一个全面的实验主义者和理论家,一个可以建立一个实验室鱼类研究系统,进行实验,提取数据,分析数据,并进行交流的人,但是我得到的反馈是这些都不重要。我要么不知道足够多的高级统计,要么我不知道足够多的工程,要么根本没有给我一个理由。
尽管令人沮丧,但坚持申请,坚持学*。我写了“如何进入数据科学”系列,部分是因为我记得当我进入这个领域时,我发现自己有多难确定自己实际需要什么技能。但你也不必独自经历转变。有几个专门针对希望进入行业的博士的编程训练营,如 洞察奖学金 和 数据孵化器 。虽然你无疑有自学所需技能的纪律,但让专业人士帮助你可能更有效率。
如果你想聊天,请不要犹豫。祝你好运!
最好,
马特
对象-角色建模中的传递关系和规则
原文:https://towardsdatascience.com/transitive-relationships-and-rules-in-object-role-modeling-906a3cde1702?source=collection_archive---------27-----------------------
生物信息学和基于规则的知识表示

具有传递环约束和派生事实类型/规则的对象-角色模型。图片作者。
上图显示了在对象-角色模型(ORM)中表达的传递关系,以及在派生的事实类型中表达的规则。
传递关系
在一些数据科学练*中,需要传递关系。对象-角色建模中的传递关系由下面的符号表示:

对象-角色建模中的传递关系符号。图片作者。
在我们的模型中,用于生物信息学数据库,蛋白质与其他蛋白质相关联,并且这种关联可以通过一种蛋白质与另一种蛋白质的关联来实现,等等。
例如,我们可能有两个名为 A1 和 A2 的假设蛋白质,其中 A1 与第三个蛋白质 DDX3X 相关联,因为 A1 与 A2 相关联,而 A2 与 DDX3X 相关联。
A1 → A2 → DDX3X
DDX3X 是一种现实生活中与黑色素瘤相关的蛋白质。我们的传递关系可能意味着蛋白质 A1 可能与黑色素瘤相关,生物信息学家利用这一信息来决定在药物发现中靶向哪些蛋白质。
生物信息学、药物发现和基于规则的数据库查询
我们的模型代表了药物发现和生物信息学更大模型的一部分。本质上,该模型显示了蛋白质之间的关系,以及蛋白质的表达可能与可能与特定疾病的表现相关的其他蛋白质的表达相关。反之亦然,其中疾病的存在可以通过各种蛋白质的相对表达来检测。
顾名思义,生物信息学是生物学和信息学专业的结合,其特点是从业者使用他们能够找到或开发的任何信息技术工具。信息技术在生物信息学中被广泛使用,因为,例如,在人体中有成千上万的蛋白质。有数千种药物,人类 DNA 中有数百万个碱基对,等等。所处理的信息是巨大的,超出了用笔和纸或纯粹在人类头脑中处理的范围。
在这种情况下,生物信息学家求助于使用数据库来存储他们需要处理的所有信息,以帮助发现用于疾病管理的候选药物。
直到最近,一直缺少的是数据库工具,它使生物信息学家在数据库中查询大量数据变得容易。数据库擅长存储数据之间的关系,但直到最近,为数据添加规则的工具还很有限。
例如,生物信息学家不仅想知道蛋白质与疾病相关,还想知道哪些其他蛋白质可能由于它们与第一种蛋白质的关联而与该疾病相关,对于传递相关的蛋白质也是如此。
理想情况下,您希望能够针对生物信息学数据库编写查询,例如:

基于自然语言、对象-角色建模的查询。图片作者。
这样的查询将包含我们的模型中表达的规则:

对象-角色建模中的派生事实类型规则。图片作者。
这种类型的规则将考虑传递关系,例如,蛋白质 A1 与蛋白质 A2 相关联,并且与蛋白质 DDX3X 传递相关,使得查询将通过它们与 DDX3X 的关联/传递关联,返回 A1 和 A2 作为与黑色素瘤疾病的存在相关的候选蛋白质。
生物信息学工具
众所周知,生物信息学研究的工具是一个软件大杂烩,因为许多研究是前沿的,所以当实际编写他们需要完成工作的软件时,许多从业者只能靠自己的设备。
例如, R 语言被生物信息学家广泛用于该行业的统计和图表绘制要求,从事生物信息学的生物学家需要像理解遗传学和基因组学一样精通信息技术、数据科学和软件代码切割。
这是一个艰难的问题,因为遗传学和基因组学本身就是复杂的研究领域,更不用说精通信息技术了。
因此,生物信息学家在他们能找到的任何地方寻找使他们的生活变得容易的软件工具。这使得他们可以更快地完成工作,并为生物学的核心能力节省宝贵的大脑空间。
输入知识图表、知识表示和图表查询
如果你是一名致力于识别疾病标记物的生物信息学家,并且你想写一个关于数据库的查询,该数据库将提供关于哪些表达的蛋白质可能与特定疾病相关联的*解,那么你的问题是,在特定蛋白质的表达和可能并行存在于受试者体内的疾病之间可能存在传递关系。
如何在数据库中表达这种传递关系?
你必须在 数据库或者 知识图查询引擎 你的数据库中表达那种关系 ?
一旦表达了传递关系,生物信息学家还需要警惕在搜索潜在生物标志物的任何此类链接链时可能出现的组合爆炸,但拥有容易搜索它们的工具远比没有任何工具好得多。
数据库的知识图形表示和图形查询语言有助于管理数据库的概念化,这样生物信息学家可以通过隐藏底层数据库的复杂性,专注于他们需要检索什么信息,而较少关注如何访问该数据。**
例如,一个生物信息学家可能喜欢在一个知识图上写一个查询,如下所示:

示例知识图查询,事实引擎。图片作者。
由于对象-角色建模语法中丰富的语义,在使用对象-角色建模时,这样的查询是可能的。
我的所有研究都指向这些类型的查询可以在现有数据库上运行,而不必购买或构建专门的知识图。
在数据库中输入对象角色建模和知识表示
如果我们回顾一下本文开头的对象-角色模型,下面的符号是一个传递关系:

对象-角色建模中的传递关系。图片作者。
我们描述的规则是作为派生的事实类型建立的,如下所示。派生事实类型是数据不存储在数据库中,而是在数据库查询运行时派生的事实类型。它们被指定为由星号表示的衍生规则,该星号表示规则是相关联的:

对象角色建模中的派生事实类型。图片作者。
使用 FactEngine (www.factengine.ai)等知识图工具,您只需在模型中绘制图表,该模型位于您的数据库之上,然后用自然语言编写所需的查询,返回所需的结果:

自然语言查询。图片作者。
这样的查询使用我们定义的规则,该规则反过来使用蛋白质之间的传递关系来返回期望的结果。
你不一定需要一个专门的知识图数据库来完成这类事情,也不一定需要一个过于复杂的查询语言,你所需要做的只是在你现有的数据库上用一种自然的查询语言使用一个以对象角色建模编写的知识表示层。这就是我的研究工作,我发现相关的数据科学令人着迷。这个想法是通过隐藏复杂性使生活变得简单。
例如,如果您的数据库是一个关系数据库,在我们的第一个示例中,将要求数据库具有递归查询,因为这样一个查询的结果结构化查询语言(SQL)将如下所示:

对应于自然语言查询的 SQL。图片作者。
这种类型的 SQL 就是为什么生物信息学家在寻找让他们生活更轻松的工具。SQL 中的递归查询编写起来很复杂,而且要记住如何编写。
因此,世界正在转向隐藏底层数据库和数据库原生查询语言的复杂性,并提供简单的基于图形的查询语言和基于规则的知识表示的工具,以使像生物信息学家这样的人的生活更容易。
为什么?为什么人们需要一个灵活的基于规则的数据库层?
人们需要在他们的数据库上建立基于规则的知识表示层的原因是,对于从业者想要在他们的数据库上操作的特定查询集,现成的软件应用程序可能不存在。构建应用程序非常耗时,而且一旦构建完成,它们通常是不灵活的,并且不能针对需要编写以满足某个偶然需求的特定查询进行更改。
对象-角色建模是一种丰富而富有表现力的概念建模语言,它允许创建基于规则的信息处理工具,这也是我个人使用它的原因。不管您使用什么对象-角色建模工具来建模您的数据,对象-角色建模使得概念化和定义您想要用您的数据库实现什么变得更加容易。
十多年来,派生事实类型背后的科学一直是对象角色建模的一部分[1],派生事实类型是 FactEngine 中的 beta 版。
感谢您的阅读,如果时间允许,我会写更多关于派生事实类型、自然语言查询、对象角色建模的各种基于规则的约束和知识图的内容。
- Curland M .,Halpin T .,Stirewalt K,“ORM 的角色演算”,OTM 2009:走向有意义的互联网系统:OTM 2009 研讨会,施普林格,第 692–703 页
— — — — — — — — — — — — — — — — — — — — — — — — — — -
转化代谢组学:将研究“转化”为现实产品的挑战
原文:https://towardsdatascience.com/translational-metabolomics-the-challenges-of-translating-research-into-real-world-products-31d4ef112919?source=collection_archive---------37-----------------------
转化代谢组学在研究和工业之间架起了一座桥梁,将科学突破“转化”为现实世界的产品

来源:作者
本文基于对 Farhana Pinu 的采访,以及 Pinu、Goldansaz 和 Jaine 在代谢物杂志上发表的“转化代谢组学:当前的挑战和未来的机遇”。
代谢组学目前是一个热门的研究领域,有望对生物体有更深入的了解,并提供更好、更个性化的诊断和治疗。
研究人员每年都在取得很大进展,但迄今为止,只有少数代谢组学应用一直到临床。
Farhana 和她的同事们收集了更多的研究如何能够导致成功的临床和工业产品的建议。这就是转化代谢组学的科学:“将”科学发现转化为日常产品。

转化代谢组学,研究实验室和现实世界之间的瓶颈。来源:作者
调整学术和行业目标
为了理解为什么将研究突破转化为现实世界的产品具有挑战性,我们需要理解科学和工业之间的根本区别。科学和工业有非常不同的目标。
- 发现推动科学:目标是理解事物如何工作。
- 产品驱动产业:目标是将研究打包成易于使用、高效且有利可图的工具。
由于这些不同的目标,科学和工业经常在不同的时间框架内工作。科学家可能会在同一个问题上花费数年或数十年的时间,而临床应用的时间范围从几个月到几年不等。
转化代谢组学旨在协调这些目标,并且已经取得了一些重大成功。最受欢迎、最有可能盈利的领域是:
- 产前检查评估未出生婴儿感染疾病的风险;
- 遗传性癌症检测发现患者是否有患某些癌症的较高风险;和
- 个性化医疗除了患者的病情之外,根据众多因素量身定制治疗方案。
这些领域现有的现实世界的成功使更多的成功成为可能,但这并不意味着它是容易的。
转化代谢组学面临的挑战
转化代谢组学的前景是明确的,但仍有许多障碍。以下是主要的挑战及其潜在的解决方案。
挑战#1:翻译过程可能在多个阶段失败
一个实验要想成功并创造具体的价值,它需要:
- 🧪稳健实验设计:
- 🚚声音数据采集;
- 📊易于使用的数据挖掘;
- 🤓深度解读;和
- ✅成功验证候选生物标志物。
这些步骤中的任何一个失败都会导致整个项目的失败,因此质量保证在每个阶段都是至关重要的。
解决方案 1:严格的流程和用户友好的工具
更严格的程序将有助于确保实验的有效性和可靠性。这包括:
- 使用国际指导:如果研究人员更紧密地遵循专业和监管机构的指导方针,研究可以在全球范围内共享,并取得更大的成功。对科学家来说,大量的文献似乎势不可挡,但应用研究的突破最终会有回报。
- **开发用户友好的工具:**如果科学家能够访问用户友好的开源软件和数据库,特别是基于网络的数据分析,他们会发现全球合作更加高效和可靠。
更好的过程和工具将有助于确保结果足够可靠,可以被其他研究人员复制。
🤔挑战#2:负面看法
代谢组学仍然是一个小众领域,而不是家喻户晓。与其他组学领域一样,它有时被视为“炒作”,一个承诺过多而交付不足的领域。
代谢组学雄心勃勃,并做出了重大承诺。随着时间的推移,它应该会给我们提供治愈糖尿病、癌症和许多其他疾病的线索。即时诊断和各种医疗工具也意味着改善我们的生活。但到目前为止,改变世界的工具还没有实现。
代谢组学已经成功了。但是重大的胜利却鲜有宣传,因为它们更加小众和本地化:这个领域需要更好的公关。
解决方案 2:研究人员的宣传和参与
Farhana Pinu 指出,科学家并不总是宣传代谢组学的巨大成功。他们需要通过社交媒体和其他渠道进行更多的宣传。
突出结果的需要在其他组学领域也很常*。但代谢组学是一个不太成熟的组学领域,在某些方面正在“迎头赶上”。该领域产生的大量数据,加上它的许多目标,意味着它的成功可能会被埋没。
代谢组学社区需要承认感知问题,并积极宣传其影响。
🤑挑战#3:代谢组学是一个昂贵的游戏
研究人员使用昂贵的分析软件和*台,这些软件和*台似乎过于复杂。建立一个完整的代谢组学实验室需要数百万美元。仅液相色谱-质谱*台就要花费近百万美元。
为了省钱,实验室经常使用小样本,这会影响结果。
解决方案#3:更便宜、小型化的设备
任何对代谢物测量感兴趣的人都应该能够进行研究。但是没有更便宜的实验室设备,只有少数几个人能得到他们需要的设备。
开发更便宜、更易获得的小型化仪器将会为其他研究人员带来倍增效应。生产硬件和软件的厂商需要合作来实现这一目标。
🧑🔬挑战 4:多学科专业知识
在其他学科中,研究团队一般由同一领域的专家组成。但是对于转化代谢组学,团队需要生物学家、分析化学家、统计学家、数据科学家和生物信息学家。
专业知识的多样性意味着代谢组学团队规模更大,更难协调。这使得这些团队更加昂贵,效率更低,这增加了建立多学科团队的挑战。
解决方案 4:多学科合作和跨学科培训
随着时间的推移,学术领域越来越专业化。为了转化代谢组学的成功,我们需要鼓励两者,
- 专家之间更好的合作;和
- 提高技能和培训多学科专家。
在生物学和数据科学方面经验丰富的研究人员通常比代表这两个领域但在不了解彼此专业知识的情况下一起工作的两个专家更快地获得结果。但是一个人越来越难对代谢组学这样一个广泛的领域有足够的了解。
为了更好地合作,我们需要更多的空间让专家合作。论坛和研讨会可以促进不同领域之间以及学术、工业和管理机构之间的交流。
对于**多学科专家来说,**我们需要专门的培训项目来教授个人代谢组学所需的独特的跨学科技能。
📊挑战 5:准确获取数据
即使有昂贵的设备,也没有通用的提取所有代谢物的方法。许多代谢物是不稳定的,除了其他因素外,即使储存在-80 度,也会因光、热和氧化而降解。
有些代谢物浓度高,有些浓度低。这些都需要不同的专门协议和设备来精确测量。
获取单个生物实体的完整代谢组仍然具有挑战性、昂贵且耗时。
解决方案 5:更好的设备和分析*台
设备和分析软件通常难以使用。我们需要更好的硬件和软件来准确地获取和分析数据。
一旦研究人员确保他们拥有高质量的数据,他们还需要更容易的方法在全球范围内以及在不同的组学领域之间共享这些数据。
更好的数据分析和数据共享*台将极大地帮助转化工作。
🔢挑战#6:代谢组学中的绝对定量
研究人员通常专注于“半定量”数据。也就是说,他们的研究在他们自己的实验室和设备上是结论性的,但是硬数字是由他们特定的设置和设备产生的。
例如,研究人员可能会发现一种可以识别疾病的代谢物。然后,他们可以通过观察这种代谢物的数量来成功区分健康和患病的患者。
但这是一个相对的衡量标准,并没有按照全球标准进行校准。世界另一端的医生不能将这些结果用于他们自己的病人,因为没有病人与健康人相比有多少代谢物的绝对阈值。
解决方案 6:更好的校准方法和全球数据共享
使用绝对量化更具挑战性,但也更有价值。这包括使用仔细校准的机器来确定特定代谢物的准确数量,这些数量可以被世界各地的其他实验室复制。
无论是在设备校准还是质量保证方面,这项工作的成本都很高。但是全球共享成果所获得的价值远远超过了补偿。
代谢组学标准倡议(MSI)在全球范围内监测和审查数据和标准,研究人员需要尽可能遵循这些标准,以便更容易地将实验转化为临床应用。
💅挑战 7:研究人员被“魅力”话题所吸引
每个人都想“治愈癌症”或“治愈糖尿病”。这些都是雄心勃勃的大项目,可能不会很快转化为真正的产品。从行业角度来看,大多数问题都是不可行的:不太可能在合理的时间框架内解决,也不太可能盈利。
更小、更本地化的问题往往更实际、更有利可图。但它们吸引的媒体关注要少得多,因此对资助者和研究人员也不那么有吸引力。
虽然雄心勃勃的研究很重要,但更重要的是解决临床上面临的具体、有效的问题。
解决方案 7:简单而具体的结果
研究人员应该与行业合作,以确保实验有适当的范围和背景。这意味着实验应该是:
- 在合理的时间框架内可以实现;和
- 针对适当规模(即使是利基)的需求。
如果处于假设阶段的研究人员专注于可以转化为现实世界应用的结果(例如,便携式设备),他们的结果更有可能被行业所用。
🛠️挑战#8:终端用户设备不足
我们知道研究设备需要更小更便宜。我们还需要为医生等最终用户提供先进的设备。
一些遵循翻译研究的最终用户产品可能很难使用或需要大量时间。结果可能很难理解或者需要专门的分析,导致采用率很低。
解决方案 8:易于使用的设备
正如实验室设备一样,我们也需要简单的终端用户设备。设备应该:
- 要好用;
- 要便携;
- 产生快速的结果;
- 产生易于解释的结果;
- 不贵;和
- 被批准使用。
这些优先事项通常超出了学术和科学研究的范围,但转化代谢组学需要从一开始就考虑它们。
你有代谢组学研究要翻译吗?
我们的团队在使用机器学*将代谢组学研究转化为现实世界的解决方案方面拥有丰富的经验。如果您正在研究代谢组学相关的问题,我们希望听到您的意*。
TransparentPath:一个管理 Google 云存储路径的 Python 包
原文:https://towardsdatascience.com/transparentpath-a-python-package-to-manage-paths-on-google-cloud-storage-ae25a15a44d5?source=collection_archive---------14-----------------------
你是否*惯了 pathlib 的 Path 对象,在使用 GCSFileSystem 对象时感到沮丧?透明路径包是为你做的。

由凯尔·苏杜在 Unsplash 上拍摄的照片
它有什么用途,如何使用它
当我第一次开始使用谷歌云*台(GCP)时,我面临着以下困难:用 Python 代码轻松地从/向谷歌云存储(GCS)读取和写入文件。对于本地文件,我*惯于使用 Pathlib 库,通过重载 truediv_ 以允许 bash 式的路径创建,并通过实现许多有用的方法,如 glob 、 ls 、 unlink …可以直接在 path 对象上调用,这使得使用路径变得非常简单和直观。Python 中允许在 GCS 上使用路径的类是 gcsfs 包中的 G CSFileSystem ,它没有所有这些便利的特性,因为主对象不是文件而是文件系统。
因此,我创建了 TransparentPath 对象,包装在 GCSFileSystem 和 LocalFileSystem 中,允许使用与 PathLib 相同的逻辑处理 Path 对象,但是在 GCS 上。我添加了对 LocalFileSystem 的支持,这样,仅通过这个类,就可以在相同的代码中轻松地使用远程和本地文件。
这里有一个小例子,说明最初使用 Pathlib 开发的本地工作代码如何被重构为使用 GCSFileSystem,然后如何使用 TransparentPath 开发它。代码在包含 csv 和 parquet 文件的目录中循环,读取包含的数据帧,将它们连接起来并保存在一个新文件中。
使用 Pathlib:
from pathlib import Path
import pandas as pd
first_path = Path*(*"foo"*)* / "bar"
dfs = *[]* dic = None
for subpath in first_path.glob*(*"*"*)*:
if subpath.suffix == ".csv":
df = pd.read_csv*(*subpath, index_col=0, parse_dates=True*)* dfs.append*(*df*)* elif subpath.suffix == ".parquet":
df = pd.read_parquet*(*subpath*)* dfs.append*(*df*)* df = pd.concat*(*dfs*)* second_path = first_path.parent / "concatenated.csv"
df.to_csv*(*second_path*)*
使用 GCSFileSystem :
from gcsfs import GCSFileSystem
import pandas as pd
dfs = *[]* dic = None
fs = GCSFileSystem*()* first_path = "gs://bucket_name/foo/bar"
for subpath in fs.glob*(*"/".join*([*first_path, "*"*]))*:
if subpath.endswith*(*".csv"*)*:
df = pd.read_csv*(*"".join*([*"gs://", subpath*])*, index_col=0, parse_dates=True*)* dfs.append*(*df*)* elif subpath.endswith*(*".parquet"*)*:
df = pd.read_parquet*(*"".join*([*"gs://", subpath*]))* dfs.append*(*df*)* df = pd.concat*(*dfs*)* second_path = "gs://bucket_name/foo/concatenated.csv"
df.to_csv*(*second_path*)*
使用透明路径:
from transparentpath import TransparentPath as Path
import pandas as pd
Path.set_global_fs*(*"gcs", bucket="bucket_name"*)* first_path = Path*(*"foo"*)* / "bar"
dfs = *[]* dic = None
for subpath in first_path.glob*(*"*"*)*:
df = subpath.read*(*index_col=0, parse_dates=True*)* dfs.append*(*df*)* df = pd.concat*(*dfs*)* second_path = *(*first_path.parent / "concatenated.csv"*)* second_path.write*(*df*)*
如果将行 Path.set_global_fs("gcs ",bucket="bucket_name") 注释掉,所有操作都在本地进行,而不是在 gcs 上进行,这意味着您可以轻松地从本地文件切换到远程文件。在这个例子中,GCS 上的树与项目目录中的树相同,这简化了代码。但即使不是这样,在代码的开头用一个单独的 if 语句来指定代码是在本地运行还是在 GCS 上运行,就可以定义一个可以在任何地方使用的根路径。
此外,请注意 gs:// 没有出现,并且在创建路径时没有给出 bucket 名称。文件系统由 set_global_fs 设置,允许定义由所有后续路径共享的桶。您仍然可以使用下面两行中的任何一行在不同的存储桶上创建路径:
first_path = Path*(*"gs://other_bucket_name/foo"*)* / "bar"
first_path = Path*(*"foo", bucket="other_bucket_name"*)* / "bar"
first_path = Path*(*"other_bucket_name/foo"*)* / "bar"
资格证书
将自动检测 GC 的凭据,优先级顺序如下:
- 环境变量 GOOGLE_APPLICATION_CREDENTIALS 已设置并指向有效的*。json* 文件。
- 您安装了有效的 Cloud SDK。在这种情况下,您可能会看到警告: UserWarning:您的应用程序已经使用来自 Google Cloud SDK 的最终用户凭证进行了身份验证,没有配额项目。由你来决定如何处理它。
- 运行代码的机器本身就是一台 GCP 机器
请注意,关联帐户需要有权列出项目中的存储桶,因为 TransparentPath 将尝试检查项目中是否存在 set_global_fs 中所需的存储桶。
可用的方法
文件系统、路径库和字符串
文件系统对象中所有可用的方法都存在于透明路径中。区别在于不需要指定应用它们的路径:
fs.glob*(*"/".join*([*first_path, "*"*]) # GCSFileSystem
path.glob("*") # TransparentPath*
Pathlib 中所有可用的方法都存在于 TransparentPath 中:
path.parent
path.name
path.suffix
...
str 中可用的所有方法都存在于 TransparentPath 中:
>>> "foo*" in (TransparentPath("gs://bucket_name") / "foo")
True*
为了使这些方法可用,TransparentPath 不实现它们。当调用该类未知的方法时,它将通过以下方式检查该方法是否已知:
- 文件系统(GCS 或本地,取决于路径)
- Pathlib
- 潜艇用热中子反应堆(submarine thermal reactor 的缩写)
并使用带有适当参数的此方法。例如,当使用 glob 时,它不是透明路径的一个方法,该类首先为它的文件系统对象查找它是否存在。它有,所以它使用它。 glob 也存在于 Pathlib 中,但是由于该方法最早是在文件系统中发现的,所以永远不会使用。
阅读和写作
在 TransparentPath 中读写 Pandas 数据帧和系列真的很容易:
p = Path("gs://bucket_name/file.csv")
df = path.read(index_col=0, parse_dates=True)
p = Path("gs://bucket_name/file.parquet")
p.write(df)
根据文件后缀,该类调用适当的 pandas 读取方法。支持与熊猫一起阅读的格式有 csv 、拼花、 hdf5 、 xlsx 、 xls 、 xlsm 。你也可以在字典中读到一个 json。如果后缀都不是,这个类就认为文件包含纯文本,并使用文件系统的 open 方法读取它。
内置的 open 被该类重载,以允许在 TransparentPaths 对象或以“gs://”开头的字符串上使用它:
# Both commands will have the same effect
with open("gs://bucket_name/file.txt", "r") as f:
...with open(Path("gs://bucket_name/file.txt"), "r") as f:
...
透明路径也可以处理 Dask 数据帧:
import pandas as pd
import dask.dataframe as dd
df_dask = dd.from_pandas*(* pd.DataFrame*(* columns=*[*"foo", "bar"*]*,
index=*[*"a", "b"*]*,
data=*[[*1, 2*]*, *[*3, 4*]]
)*,
npartitions=1
*)*
pfile = Path("gs://bucket_name/file.parquet")
pfile.write*(*df_dask*) # detects that the object is Dask dataframe* df_dask = pfile.read*(*use_dask=True*) # need to tell to use Dask*
复制和移动
cp 和 mv 方法可用,将对文件和目录都有效:
p1 = Path("foo/", bucket="bucket_name", fs="gcs")
p2 = Path("foo/", fs="local")
p1.cp(p2) # Copies the item from GCS to local
结论
该软件包仍然是新的,并定期更新。稳定版通过pip install transparentpath提供给 Python 3.8 及以上版本,测试版通过pip install transparentpath-nightly提供。任何问题都可以在 project Github 页面上提交。在这里,您还可以找到一个自述文件,其中包含更多关于如何使用该类的信息和示例。
关于我们
Advestis 是一家欧洲合同研究组织(CRO ),对统计学和可解释的机器学*技术有着深刻的理解和实践。Advestis 的专长包括复杂系统的建模和时间现象的预测分析。
领英:https://www.linkedin.com/company/advestis/
赫尔辛基使用 accessviz-mapper 工具绘制旅行时间(可达性)地图
原文:https://towardsdatascience.com/travel-time-accessibility-maps-with-the-accessviz-mapper-tool-in-helsinki-7be23eadd4b0?source=collection_archive---------48-----------------------
如何在赫尔辛基地区使用出行时间矩阵 2018 创建可达性地图

图片由作者提供。Accessviz-mapper 工具。
赫尔辛基是欧洲众所周知的可持续发展和智能城市。赫尔辛基地区的交通通过不同的交通方式(汽车、自行车、公共交通)为长距离和短距离提供良好的可达性。让我们说,根据旅行时间,火车使遥远的社区“靠近”市中心。同样,对于短途旅行,赫尔辛基有足够的自行车道网络,使得在当地通勤更加方便快捷。自行车共享系统(赫尔辛基城市自行车)和公共电动滑板车(Voi,Tier,Lime)帮助市民在日常本地移动中实现可持续通勤。
赫尔辛基的可达性和流动性得到了很好的研究,并准备用于改善城市规划。可达性通过通勤者的出行时间进行研究,出行时间基于不同交通方式的门到门方法。行驶时间/距离存储在 250x250 m 的网格单元中,该单元包含赫尔辛基地区的路线信息。最后公布的网格是赫尔辛基地区旅行时间矩阵 2018 。
负责 HR 旅行时间矩阵 2018的地球科学家创建者是赫尔辛基大学 可达性研究组 的一部分,该研究组面向赫尔辛基大学 数字地理实验室 。 行程时间矩阵的描述恰当地解释了门到门方法,并显示了由 Toivonen 等人(2014) [2]创建的科学出版物。此外,您可以在研究小组页面上找到一个部分,其中包含所有使用了旅行时间矩阵的更新出版物。
可达性地图表示通勤者通过不同的交通方式从一个特定地点到达另一个地点的距离或时间。HR 行程时间矩阵可以显示从 YKR ID 为 YKR ID 为的特定网格到位于赫尔辛基地区的另一个网格的可达性。

图片由作者提供。可达性地图示例显示,与公共交通相比,在当地骑自行车更有效。
为了使可达性映射对 HR 出行时间矩阵用户友好,创建了 accessviz-mapper 工具。
在这篇短篇故事/教程中,我将展示如何使用 accessviz-mapper 工具创建可访问性地图,您可以在本地计算机上运行该工具。accessviz-mapper 工具与 一起部署在本地,瞧 ,您可以在下面解释的 5 个阶段中使用它。但是首先,事先检查一些步骤。
检查 accessviz-mapper 工具 的 Repo。
主要的第一步是在本地磁盘中克隆存储库。如果您的计算机上有 Anaconda ,只需在命令窗口中找到您想要的目录,并写下:
git clone [https://github.com/DigitalGeographyLab/accessviz-mapper-dgl.git](https://github.com/DigitalGeographyLab/accessviz-mapper-dgl.git)

图片由作者提供。在本地磁盘中克隆 accessviz-mapper
然后,在命令行中进入克隆的存储库。确保已经安装了自述文件中指定的所有需要的 python 包: voila、ipywidgets、folium、pyproj、geopandas、matplotlib、glob、os、NumPy、contextily、mapclassify、osmnx、networkx、shapely 。
您可以将它们直接安装在基础环境中,但在我的情况下,我将它们全部安装在我的名为 gis 的个人环境中。找到关于如何创建环境的说明。

图片由作者提供。指定工具库的适当环境和目录
最后,运行行voila accessviz-mapper.ipynb,一个本地服务器将打开该工具。

图片由作者提供。在本地部署 accessviz-mapper
地图创建
accessviz-mapper 工具包含一些网格的行驶时间信息作为演示数据。在这个例子中,我们将使用5963655 和5933038 。如果您想在 accessviz-mapper 工具中添加所有网格的数据,请下载整个数据集 HR Travel Time Matrix 2018 。然后,在克隆的存储库中导航到文件夹data/HelsinkiTravelTimeMatrix2018,您会注意到您需要添加赫尔辛基地区的所有旅行时间文件夹。
当 accessviz-mapper 打开时,您将看到该工具的简短描述。如果你想选择自己的 YKR ID 的只需向下滚动,你会看到一个互动地图——YKR ID explorer,在这里你可以查看整个赫尔辛基地区的 YKR ID 。

图片由作者提供。YKR ID 浏览器
当你已经选择了你的 YKR IDs。遵循 accessviz-mapper 工具中指定的步骤。
1)文件查找器
在这里,您可以添加您想要的 YKR IDs。一个或多个。在这种情况下,我们使用5963655 和5933038.只需键入数字,并按下按钮**Add YKR ID.**

2)表接合工
在这一步中,一个名为downloads的新文件夹会在您的本地克隆存储库中自动创建。如果你愿意,你可以更新文件夹的 URL,但是最好把它放在同一个地方。这里,您需要将行驶时间信息加入 YKR ID 图层。这就是在这一步中发生的连接。按下按钮**Save as SHP**或**Save as GPKG**,或两者都按下。

图片由作者提供。accessviz-mapper 工具中的表格连接器
3)可视化器
在这个阶段,accessviz-mapper 工具将映射您加入并存储在本地存储库中的文件。 如果有重复的文件(SHP 和 GPKG)也不用担心,该工具只识别一个 YKR ID 以避免重复贴图。
选择合适的模式(即自行车快速行驶),找到你想要的分类方案(即自然中断),颜色图(即粉绿色发散变化),Alpha(透明度),以及分类类别的数量。最后,按下按钮**Map files.** 工具将绘制行程时间。
您也可以选择用**Save maps PNG**按钮保存文件,它们将存储在您本地存储库中的同一个dowloads文件夹中。


图片由作者提供。YKR ID 5963655 中自行车快速行驶时间的地图产品
4)比较行程时间和距离——工具
这一阶段通过减去行程时间来比较两种不同的交通方式。
简单解释了一下,当比较(图例)更接近于零时,可达性相同。如果为负,则选择的第一传输模式更快,如果为正,则选择的第二传输模式更快。
点击**Map comparison**按钮,可以保存为 SHP 或 GPKG,也可以保存为 PNG。如果需要,您可以在下载图层文件后使用自己的映射。


图片由作者提供。旅行时间比较。
该地图相对显示,红色区域骑自行车和开车的时间几乎相同,而蓝色区域开车更快。探索交通方式!
5)最短路径——路由工具
这个阶段在选中的YKR id 之间创建 最短路径 。*** 很好,你可以选择网络: 自行车道,公路,步行道。 您也可以下载图层,并将其添加到您自己的地图中。***
在这个例子中,我使用 YKR ID 5963655,作为起点,YKR ID 5933038 和5925860\. 作为目的地,你可以添加一个或多个起点和目的地。然后选择您喜欢的路径网络并按下按钮**Find shortest path.** 这可能需要一些时间,因为它正在从打开的街道地图中获取数据。


图片由作者提供。所选 YKR IDs 之间自行车道的最短路径
现在你已经知道了如何方便地绘制赫尔辛基不同交通方式的可达性。探索各种选项,为您的城市规划项目找到合适的可视化方案。如果你有任何疑问/建议,欢迎提出。此工具的目标是在赫尔辛基地区快速创建包含行驶时间信息的地图和图层。查看我的个人资料进行查询
参考文献
[1] Tenkanen,h .,J.L. Espinosa,E. Willberg,V. Heikinheimo,A. Tarnanen,T. Jaakkola,j . jrvi,M. Salonen,T. Toivonen (2018)。赫尔辛基地区行程时间矩阵 2018 。DOI:10.13140/rg . 2 . 2 . 233353233336
[2]t .托伊沃宁、m .萨洛宁、h .滕卡宁、p .萨尔萨米、t .雅克科拉和 j .耶尔维(2014 年)。Joukkoliikenteell,autolla ja k vellen:[Avoin saavutetttavuusaineisto p kaupunkiseudulla](http://Avoin saavutettavuusaineisto pääkaupunkiseudulla. Terra)。特拉福音 126: 3,127–136。
遍历、清理批处理 Excel 文件中的批处理工作表,以及与 MySQL 交互
原文:https://towardsdatascience.com/traversing-cleaning-batch-worksheets-in-batch-excel-files-and-interacting-with-mysql-1cf81939518b?source=collection_archive---------40-----------------------
仅用熊猫清洁

作者照片
今天的故事包括:
- 如何只使用熊猫遍历和清理脏的批量 Excel 工作表
- 根据步骤 1,如何遍历批量 Excel 工作簿并合并报表
- 如何将 Excel 文件保存到 MySQL 数据库并与之交互?
读写 Excel 文件是日常业务中非常经常的操作。这并不复杂,但繁琐,有各种情况下,你可能要面对和需要耐心的细节来处理它们。今天我重点讲只读 Excel 文件(不修改 Excel),只用熊猫清理数据,用 MySQL 交互。
数据集简介
干净和脏的数据集
有时,数据集可能组织得很清楚,如下所示:

图 1:清理数据集
在其他情况下,数据集可能有许多额外的无用信息,如下所示:

图 2:脏数据集 1

图 3:脏数据集 2
对于第一种情况,将不同的工作表合并到一个报表中更容易,但是对于第二种情况,需要按照以下步骤清理数据:
- 第 1 部分:从特定单元格中提取客户信息和销售日期
- 第二部分:将 excel 读入 Dataframe 时,最后一条记录(5,56)和页脚(由 BrandNew_sales_team 生成)之间会产生 NaN,更糟糕的是,它是动态的。

图 4:数据清理的步骤
清理 Excel 文件的工具:
你可以使用 Excel,VBA,甚至 Power BI 等等。微软的产品来清理和整合数据,或者您可以使用 xlwings、Openpyxl 等。python 库,但是我更喜欢只使用 pandas DataFrame,因为
- Openpyxl 不需要安装 Excel,但是不能运行。xls 文件,并且无法打开受密码保护的文件。
- xlwings 需要在机器上安装 Excel。
- 假设的情况是,应用程序将在没有安装 Excel 的情况下运行,就像在云中一样。
- 我在熊猫方面的技术比其他人都好。
详细数据集
- Excel 文件有密码保护,包含 VBA,里面有各种工作表,需要合并。
- Excel 文件格式和上面的图 2 和图 3 一模一样。
- 需要处理一批 Excel 文件。
数据清理
我开始只清理一个名为“sales_2020.xlsm”的工作簿。
首先导入库:
import numpy as np
import pandas as pd
from pandas import DataFrame
获取所有工作表的名称:
xl_file_name='sales_2020.xlsm'
xl = pd.ExcelFile(xl_file_name)
sheet_name=xl.sheet_names # see all sheet names
主要的数据清理功能:
结果如下所示:

图 5:前五名

图 6:尾巴 4
遍历批量 Excel 文件
如果有需要合并的批处理文件,使用 os 库搜索所有文件,结合上面的代码得到报告。
假设文件组织如下:

图 7:文件路径
浏览全部文件的方法如下:
filepath=r'C:\Users\username\Desktop\data'
for root,dirs,files in os.walk(filepath):
for file in files:
filename=os.path.join(root,file)# get the name with absolute path
整合所有步骤,合并所有报告的功能是:
只需要给定一个变量作为 filepath:
filepath=r'C:\Users\user name\data'
consolidate_sales_report(filepath)
所有的报告都是合并的。
保存到 Mysql
假设您有权将数据写入 Mysql 数据库,并且已经创建了一个名为‘sales _ report’的模式。
我们可以使用下面的代码与 MySQL 进行交互:
结果很完美!

图 8:与 MySQL 交互
今天我从出差,清理 Excel 中的数据,和熊猫批量,和 MySQL 交互总结一下主要流程。主要使用的工具有:
- 只使用熊猫来遍历和清理 Excel 中的数据,因为有了这个库,Excel 不需要安装(对云来说很好),它可以处理各种情况,作为密码保护和启用宏的文件,与 Openpyxl 或 xlwings 相比,它是高效的
- 使用工作表名称遍历所有工作表
- 使用 os.walk() 和 os.path.join(root,file)遍历所有工作簿
- 使用 to_sql 和 read_sql 与 MySQL 交互。
谢谢你的时间。
基于树算法的顾客满意度预测方法
原文:https://towardsdatascience.com/tree-based-algorithms-approach-on-predicting-customer-satisfaction-296730e19baa?source=collection_archive---------22-----------------------
决策树、随机森林和梯度推进在这个动手项目中用于预测电子商务数据集的客户满意度

照片由 niko photos 在 Unsplash 上拍摄
介绍
客户满意度是企业可以用来有效管理和监控其运营的方法之一。只要客户满意度保持在较高水*,每种产品都可以在市场上生存很长时间。好的产品质量并不是能使一个产品能有高水*的顾客满意度的唯一因素。许多因素,如交货时间、额外付款、产品价格等。会对客户满意度产生重大影响。客户满意度是留住客户的关键。一个满意的客户更有可能考虑购买同样的产品并再次使用同样的服务,从而为公司带来大量利润。同时,一个不满意的客户可能会因为之前对公司客户服务的负面体验而避免在未来购买同样的产品【1】。
客户满意度评估是帮助企业确定下一步的营销策略,从而为公司带来利润。由于每个客户的行为都不可预测,因此预测客户满意度可能很困难。然而,为了克服这一点,有许多统计方法无疑将有助于企业基于特定因素分析和预测客户满意度【2】。在本文中,我们将主要关注使用基于树的机器学*算法从电子商务数据集预测客户满意度。
这个建模预测的数据集是来自 Kaggle 的 olist 的巴西电子商务公共数据集。
作者已授予公开使用、共享和修改该数据集的权限。许可证可以在这里找到。
这个动手项目的目标是从电子商务数据集预测客户满意度。我们将采用的基于树的机器学*建模技术是决策树、随机森林和梯度推进。我们将对每个模型进行评估,并将它们进行比较,以确定三个模型中哪一个是预测客户满意度的最佳模型。
基于树的模型简要说明
决策树是用于分类和回归的监督机器学*方法之一。在这个动手项目中,我们将专注于决策树分类器及其各种类型,这将为我们提供一个可读的分类模型。决策树分类器上的树节点代表一个属性测试。分支从该节点出现,每个分支代表前一个属性的一个可能值。叶子从这些分支开始生长,每个叶子对应于与实例相关联的类标签。训练集中的实例从决策树的根指向叶子【3】。
以这种方式使用决策树有几个优点,包括:【4】
- 该模型易于理解和解释。
- 该模型需要最少的数据准备,并且不支持缺失值。
- 统计测试可用于验证模型的可靠性。
- 这个模型可以使用数值和分类数据,但是它不支持 scikit-learn 中的分类数据。
- 该模型可用于解决多输出问题。
然而,伴随好处而来的是缺点。这种模式有很多缺点,包括:【4】
- 当模型包含不能很好地概括数据的过于复杂的树时,过度拟合经常发生。
- 数据的微小变化会导致决策树变得不稳定,从而导致生成的树与之前的不同。
- 如果一些类占主导地位,模型可能会产生有偏*的树。
决策树分类器使用数组 X 和数组 y 两个数组,数组 X 保存形状为(n_samples,n_features)的训练样本。数组 Y 保存形状为(n_samples)的训练样本的类标签。
随机森林和梯度增强的决策树变体是使用多棵树来实现比单棵树更好的结果的建模类型。这两种模型也可用于防止过度拟合。
以下是随机森林和梯度提升的区别:【5】
- 随机森林独立构造每棵树,然后结合每棵树的*均值的预测结果。
- 梯度推进一次构建一棵树,同时结合预测结果。
以下是本项目中使用的建模技术的几个步骤:
- 导入库
- 数据理解
- 数据清理和预处理
- 探索性数据分析
- 特征工程
- 机器学*建模
- 结论
导入库
导入我们将在建模过程中使用的库是很重要的。我们将主要在数据分析和建模过程中使用各种类型的库。我们将使用 pandas 和 NumPy 作为数据处理和转换工具。为了更好地可视化我们的数据,我们将使用 seaborn 和 matplotlib 作为数据可视化工具。我们将主要使用 scikit-learn 库,该库分为各种类型的模块,用于我们预测模型的建模过程工具。
数据理解
在继续该过程之前,必须合并原始数据集。我们将只包含带有订单相关列、产品相关列、付款相关列以及具体的评论分数列的数据集。每个数据集的组合过程如下所示。
总共有 115,689 行和 16 列。每列都标有自己的描述。原始列中未使用的列已被删除,这 16 列是唯一将用于我们的分析和建模的列。
下面是对 16 列中每一列的描述。
- order_status :这是对订单状态(已交付或已取消)的引用。
- order_purchase_timestamp :显示每件商品购买的时间戳。
- order _ delivered _ customer _ date:显示客户的实际订单交付日期。
- order _ estimated _ delievy _ date:显示在购买时提供给客户的预计交货日期。
- shipping_limit_date :显示卖方将订单转移给物流伙伴的装运限制日期。
- payment_sequential :客户可以使用多种支付方式为一个订单付款。
- 付款类型:客户首选的付款方式。
- 付款期数:客户首选的付款期数。
- payment_value :交易的价值。
- 价格:每件物品的成本。
- freight_value :每件商品的运输成本(如果一个订单有多件商品,运费值在商品之间分摊)。
- product_category :每件商品的类别。
- 产品名称长度:从产品名称中提取的字符数。
- 产品描述长度:从产品描述中提取的字符数。
- 产品 _ 照片 _ 数量:已发布的产品照片数量。
- review_score :客户在满意度调查中给出的评分,范围从 1 到 5。
数据清理和预处理
如前所述,决策树建模不支持缺失值。因此,数据预处理将包括数据清理过程,以检测每一列中的任何缺失值。
仅在“订单交付客户日期”列上,就有 2,400 个 NaN 值。数据清理过程通过删除 2.08%的 NaN 值数据,将 115,609 行减少到 113,209 行。
日期值列中的时间戳数据已被转换为具有完整数据的新列,以便在机器学*模型上进行进一步分析。
探索性数据分析
探索性数据分析用于获得对影响客户评审的每个相关列的业务理解。以下是一些与影响客户评估的各种因素相关的业务问题:
- 最受顾客欢迎的十大产品是什么?
- 说到支付货款,大多数客户会选择哪种支付方式?
- 支付价值因素对客户评价的影响有多大?
- 运费价值因素对客户评价的影响有多大?
- 价格因素对客户点评的影响会有多大?
- 支付价值和价格因素的关系会对客户评价产生多大影响?
- 预计交付日期和交付日期之间的相关性会对客户评审产生多大影响?
所有这些问题的答案都可以在下面找到。
十大最受欢迎产品的商业洞察:
- 购买最多的前十种产品来自床浴桌、健康美容、运动休闲、家具装饰、电脑配件、家庭用品、手表礼品、电话、园艺工具和汽车。
- 顾客最喜欢的产品是床浴桌,已收到超过 10,000 份订单。
- 在健康和美容、运动和休闲、家具和装饰以及电脑配件等类别下了 8000 多份订单。
- 家庭用品和手表礼品的订单超过 6000 份。
- 在电信、园艺工具和汽车类别下了 3000 多份订单。
- 这十大产品在确定客户满意度方面发挥了重要作用,它们将被用作参数,以便在稍后的功能工程过程中进行一次性编码。
对客户支付类型的商业洞察:
- 信用卡的支付价值最高,其次是 boleto、借记卡和代金券。
- 信用卡和 boleto 支付的支付值都超过 175。
- 使用借记卡的支付值低于信用卡和 boleto,因为它具有 150 的值。
- 凭证在其他凭证中具有最低的支付价值,因为产品实际价格的一半可以由客户使用兑现的凭证来支付。
基于支付价值的客户评审业务洞察:
- 当支付值减少时,评论分数会稍微增加。
- 当付款值超过 200 时,评审得分值为 1。
- 当支付值降低到大约 175 时,出现值为 2 的评论分数。
- 当付款值在 160 左右时,评价分数为 3、4 和 5,这使得付款值 160 将是使客户获得高评价分数的最佳选择。
基于运费价值的客户评论业务洞察:
- 随着运费价值的降低,客户可能会给出更好的评价分数。
- 运费值超过 20 的客户评价从 1 到 4 不等。
- 当运费价值低于 20 时,客户将给出 5 的最佳评论分数。
- 最低的运费价值可以获得最好的评论分数,因为当客户只需为运费价值的额外支付支付一点点时,他们会很高兴。
基于价格的客户评论业务洞察:
- 较低的价格值对评论分数没有明显的影响。
- 一个标价超过 120 英镑的产品可以从顾客那里得到正面和负面的反馈。
- 当产品的价格很高,但产品的质量没有达到客户的期望时,评审得分为 1(高价格也意味着高质量的产品)。
- 当一个产品的价格很高,并且产品的质量符合客户的期望时,评论得分为 5 是可能的。
- 点评评分 3 在其他中价格最低,价值在 110 左右。
基于支付价值和价格相关性的客户评价业务洞察:
- 当价格和支付值具有相同的值时,大多数良好评论得分为 4 和 5。
- 当顾客只需支付产品的价格而没有增加支付价值的任何附加值时,价格和支付价值之间的相同价值的相关评论得分出现。
- 大多数 5 分的评价也发生在支付价值低于产品实际价格的时候。
- 大多数评审得分为 1 的情况发生在支付价值高于产品实际价格的时候。
基于产品到达的预计天数和交付天数的相关性,对客户评审的业务洞察:
- 绝大多数好评分数为 4 和 5 的商品预计天数较长,但商品的实际交付天数提前或准时到达,使得商品比预计时间更快到达顾客手中。
- 大多数负面评价分数为 1 和 2 的产品预计交付天数较短,但实际交付天数比预期时间长。
特征工程
为了使数据更加精确,特征工程用于创建新的特征,例如新的列和虚拟变量。这个项目的特征工程的解释可以在下面找到。
我们从特征工程中创建三个新列,并删除旧列,因为新列将对模型预测做出更大贡献。
下面详细解释了每个新列。
- arrival_time: 根据预计天数和交付天数,指定产品到达客户手中所需的天数。
- delivery_arrival: 根据到货时间判断交货是准时还是迟到(如果到货时间为负值表示迟到,到货时间为正值表示准时)。
- **评分:**确定客户提供的是正面评价还是负面评价(0 表示评价得分= 1–2,1 表示评价得分= 4–5,评价得分 3 的中性值被删除)。
有一些列必须被处理,比如那些带有分类值的列。因此,必须使用标签编码和独热编码将这些值转换为 int 值,以便进行机器学*建模。
下面详细解释了每个编码过程。
- **对 2 的不同值进行标签编码:**将负值转换为 0,将正值转换为 1。
- 对大于 2 的不同值进行单热编码:使用 pd.get dummies 函数对特定列进行单热编码处理,以获得虚拟变量。
- **对大于 10 的不同值进行一次性编码:**定义前十个最常出现的值,然后对这些特定值应用一次性编码。
机器学*建模
在开始建模过程之前,我们必须将数据划分为 X 和 Y 数组,然后再次划分为训练和测试数据。X 数组包含一个 features 列,其中包含我们之前处理过的与订单、付款和产品相关的信息。y 数组仅包含“分数”特征工程列。下面提供了对该代码的更详细的解释。

(图片来自作者)
为了找到每个建模阶段的最佳参数,执行超参数调整和交叉验证技术。此外,为了获得关于模型评估的更多信息,我们将利用混淆矩阵并评估模型正确性,以确定我们的数据是否过度拟合。我们还将比较实际训练数据和预测训练数据,以进一步证明我们的统计机器学*方法如何准确预测客户满意度。
我们可以从决策树模型中获得以下信息:
- 决策树模型交叉验证的超参数调优过程只需要 16 秒左右。
- 决策树的最佳参数使用 max_depth 值 4、min_samples_split 值 100 和*均测试分数 0.871051。
- 训练数据的准确度为 0.8714%,而测试数据的准确度为 0.8673%。
- 当比较实际的训练数据和预测的训练数据时,决策树模型预测 100 个正确预测中的 88 个。
- 决策树模型的 F1 值为 0.93%。
我们可以从随机森林模型中获得以下信息:
- 决策树模型的交叉验证的超参数调整过程只需要大约 2 分钟,比决策树模型花费的时间长。
- 随机森林模型的最佳参数使用 max_depth 值 5、n_estimator 值 50 和*均测试分数 0.869954。
- 训练数据精度为 0.8701%,而测试数据精度为 0.8664%。
- 当比较实际训练数据和预测训练数据时,随机森林模型预测 100 个正确预测中的 88 个。
- 这个建模的 F1 值为 0.93%,与决策树模型相同。
我们可以从梯度推进模型中得出以下信息:
- 梯度增强模型的交叉验证的超参数调整过程需要超过 11 分钟,是其他模型中最长的。
- 随机森林模型的最佳参数使用 max_depth 值 5、n_estimator 值 50 和*均测试分数 0.874234。
- 训练数据精度为 0.8775%,而测试数据精度为 0.8709%,这使得该模型比其他模型更适合。
- 当比较实际训练数据和预测训练数据时,随机森林模型预测 100 个正确预测中的 88 个。
- 这款车型的 F1 得分为 0.93%,与其他车型相同。
结论
在我们评估了所有的建模方法之后,我们将比较每个模型的有效性。每种模式都有优缺点;我们将决定这些模型中哪一个最适合用于预测客户满意度。
我们的建模方法的结论如下:
- 所有车型的 F1 评分为 0.93%。
- 基于实际训练和预测训练数据的比较,我们可以得出结论,我们的所有模型在 100 次中正确预测了 88 次。
- 与其他模型相比,梯度增强模型具有最拟合的数据结果,但它具有最长的超参数调整交叉验证过程,持续时间超过 11 分钟。
- 决策树模型具有最快的超参数调整交叉验证过程,仅需 16 秒。
- 推荐使用决策树模型来预测客户满意度,因为它具有最快的建模过程,与其他模型具有相同的准确性和较高的 F-1 分数。
参考
[1] D. R. Allen 和 T. R. Rao,顾客满意度数据分析:顾客满意度、忠诚度和服务质量研究中多元统计分析的综合指南 (2000),ASQ 质量出版社。
[2] P. K. Kapur,A. Anand 和 N. Sachdeva,保修期内产品的利润估算:基于客户期望和满意度的评估 (2014),国际可靠性、质量和安全工程杂志。
[3] C. Dobre 和 F. Xhafa,面向智能数据收集的普适计算下一代*台 (2016),学术出版社。
https://scikit-learn.org/stable/modules/tree.html
[5]https://www . datascience central . com/profiles/blogs/decision-tree-vs-random-forest-vs-boosted-trees-explained
确认
如果你想获得更多关于这个建模方法中使用的代码的细节,你可以在这里查看我的 Github 库。
为了简化这个模型的解释,我还制作了 PowerPoint,这样你就可以得到一个清晰的解释。你可以在这里查看幻灯片。
**Github:**https://github.com/nugrahazikryhttps://github.com/nugrahazikry
【领英:https://www.linkedin.com/in/zikry-adjie-nugraha/
空间数据的树提升
原文:https://towardsdatascience.com/tree-boosting-for-spatial-data-789145d6d97d?source=collection_archive---------22-----------------------
GPBoost:结合树提升和高斯过程模型

图 1:真实空间场和预测空间场以及预测函数的比较。
空间数据通常使用高斯过程模型建模。在许多应用中,除了空间位置之外,还有其他预测变量。通常,这些协变量包含在高斯过程模型的线性回归项中(称为“泛克里金法”)。但是,你可能想知道线性假设是否真的成立。作为替代,你可以应用一种最先进的机器学*技术,比如(梯度)树提升。然而,这可能也不能完全让你满意,首先,预测在空间上是不连续的,其次,物理空间具有特殊结构的事实完全被机器学*算法忽略了。
本文展示了如何使用 GPBoost 算法将树提升与高斯过程模型结合起来,对空间数据进行建模。本文提供了方法论以及如何在 R 和 Python 中应用 GPBoost 库的背景知识。它显示了(I)如何训练模型并进行预测,(ii)如何调整参数,以及(iii)如何解释模型。此外,还对几种备选方法进行了简短的比较。
介绍
高斯过程是用于建模空间数据的流行模型,这归因于几个优点:
- 它们允许进行概率预测
- 它们可以被视为合理的先验模型,结合了托布勒的地理第一定律(“一切都与其他一切相关,但近处的东西比远处的东西更相关。”)并且它们明确地模拟样本之间的空间相关性
然而,如果有额外的预测变量,标准空间高斯过程模型也有一个潜在的严重缺陷**:它们假设预测变量和响应变量之间存在线性关系。**
Tree-boosting 是一种机器学*技术,通常可以实现卓越的预测准确性。这反映在这样的陈述中,如“一般来说,对于广泛的应用问题来说,“增强决策树”被认为是最有效的现成非线性学*方法”(Johnson and Zhang,2013)或“【XGBoost 为什么赢得“每一次”机器学*竞赛?(尼尔森,2016)。除此之外,tree-boosting 及其众所周知的软件实现(如 XGBoost、LightGBM 和 CatBoost)还有其他几个优点;参*这篇博文。当将标准增强算法应用于空间数据时,考虑到已经在空间上观察到数据的事实,基本上有两种选择:(I)忽略空间坐标,或者(ii)通过将空间位置添加到预测变量集中,将空间位置视为“常规”预测变量。不言而喻,第一个选项通常是一个糟糕的选择,因为潜在的重要信息会丢失。然而,当通过在预测变量中包含位置来对空间数据建模时,普通的树提升算法也有一些潜在的缺点:****
- 它们忽略了任何潜在的(剩余的)空间相关性
- 它们产生不连续的空间预测
- 他们忽略了合理的先验信息,即“近物比远物更相关”(*上文)
方法论背景
****GPBoost 算法(**【SIG rist,2020) **的思想是将树提升与高斯过程模型相结合,这样可以(I)利用两种技术的优点,并且(ii)避免上述缺点。粗略地说,高斯过程和树提升都是用于建模“他们擅长的部分”。更详细地说,假设
y = F(X) + b(s) + e
在哪里
- y 是响应变量(又名标签)
- x 包含预测变量,F()是潜在的非线性函数
- b(s)是高斯过程,s 表示空间位置
- e 是一个误差项
如同在经典的树提升算法中,假设函数 F()是树的集合。在标准高斯过程模型中,函数 F()被简单地假设为线性函数。此外,当应用标准的树提升算法时,可以简单地将位置 s 包括在非线性函数 F(X,s)中。GPBoost 算法是一种 boosting 算法,其迭代地学*高斯过程的协方差参数(也称为超参数),并使用 梯度和/或考虑空间相关性的牛顿 boosting 步骤将树添加到树集合中。有关该方法的更多详细信息,请参* Sigrist (2020) 。在 GPBoost 库中,可以使用(内斯特罗夫加速)梯度下降或 Fisher 评分(又名自然梯度下降)来学*协方差参数,使用 LightGBM 库来学*树。
GPBoost 算法在 R 和 Python 中的应用
在下文中,展示了 GPBoost 算法如何在 R 和 Python 中应用。本文中使用的完整代码可以在这里找到。另外,关于 GPBoost 库和相应的 R 和 Python 包的更多信息可以在这里找到。
数据
我们模拟数据 y = F(X) + b(s) + e 如下。b(s)遵循具有指数协方差函数的高斯过程。x 包含两个预测变量,其中只有一个具有非线性效应。后一种选择只是为了能够很好地可视化和比较学*到的和真实的函数 F()。此外,我们使用一个相对较小的样本量 200。对于较大的数据集,GPBoost 库支持 Vecchia 近似来加速计算。下图说明了模拟数据。本文的附录包含了用 R 和 Python 模拟数据的完整代码。

数据说明:用于模拟的均值函数 F(X)、“真实”潜在高斯过程 b 和观测数据 y(下图)。
训练和预测
通过首先定义一个**GPModel** 然后将其传递给gpboost或gpb.train函数来完成训练。通过调用predict函数并传递树集合的预测变量和高斯过程的预测位置来获得预测。请注意,树集合和高斯过程的预测是分别返回的。即,需要对它们求和以获得单点预测。下面的代码展示了如何在 R 和 Python 中实现这一点。本文开头的图 1 显示了高斯过程的预测均值和标准差(=“预测不确定性”)以及预测均值函数 F(X)。
换 R
library(gpboost)
gp_model <- GPModel(gp_coords = coords,
cov_function = "exponential")
# Training
bst <- gpboost(data = X, label = y, gp_model = gp_model,
nrounds = 247, learning_rate = 0.01,
max_depth = 3, min_data_in_leaf = 10,
num_leaves = 2^10,
objective = "regression_l2", verbose = 0)
summary(gp_model) # Estimated covariance parameters
# Make predictions: latent variables and response variable
pred <- predict(bst, data = X_test, gp_coords_pred = coords_test,
predict_var = TRUE, pred_latent = TRUE)
# pred[["fixed_effect"]]: predictions from the tree-ensemble.
# pred[["random_effect_mean"]]: predicted means of the gp_model.
# pred["random_effect_cov"]]: predicted (co-)variances
of the gp_model
pred_resp <- predict(bst, data = X_test,
gp_coords_pred = coords_test,
pred_latent = FALSE)
y_pred <- pred_resp[["response_mean"]] # predicted response mean
# Calculate mean square error
MSE_GPBoost <- mean((y_pred-y_test)^2)
在 Python 中
import gpboost as gpb
gp_model = gpb.GPModel(gp_coords=coords, cov_function="exponential")
data_train = gpb.Dataset(X, y)
params = { 'objective': 'regression_l2', 'learning_rate': 0.01,
'max_depth': 3, 'min_data_in_leaf': 10,
'num_leaves': 2**10, 'verbose': 0 }
# Training
bst = gpb.train(params=params, train_set=data_train,
gp_model=gp_model, num_boost_round=247)
gp_model.summary() # Estimated covariance parameters
# Make predictions: latent variables and response variable
pred = bst.predict(data=X_test, gp_coords_pred=coords_test,
predict_var=True, pred_latent=True)
# pred['fixed_effect']: predictions from the tree-ensemble.
# pred['random_effect_mean']: predicted means of the gp_model.
# pred['random_effect_cov']: predicted (co-)variances
of the gp_model
pred_resp = bst.predict(data=X_test, gp_coords_pred=coords_test,
predict_var=False, pred_latent=False)
y_pred = pred_resp['response_mean'] # predicted response mean
# Calculate mean square error
np.mean((y_pred-y_test)**2))
模型解释
经过训练的模型可以使用各种工具进行解释。除了传统的特征重要性测量和部分相关性图,SHAP 值和相关性图可以如下所示创建。我们获得的数字正确地确定了第一个预测变量(“特征 0”)的影响的重要性和形式。
换 R
library("SHAPforxgboost")
shap.plot.summary.wrap1(bst, X = X)
shap_long <- shap.prep(bst, X_train = X)
shap.plot.dependence(data_long = shap_long, x = "Covariate_1",
color_feature = "Covariate_2", smooth = FALSE)
注意,对于 R 包,您需要 gpboost 版本 0.4.3 或更高版本来创建这些 SHAP 图。此外,对于 SHAPforxgboost 包,数据矩阵 X 需要有列名。如果不是这种情况,请在使用以下代码训练增强器模型之前添加它们:
your_colnames <- paste0(“Covariate_”,1:2)
X <- matrix(as.vector(X), ncol=ncol(X),
dimnames=list(NULL,your_colnames))
在 Python 中
import shap
shap_values = shap.TreeExplainer(bst).shap_values(X)
shap.summary_plot(shap_values, X)
shap.dependence_plot("Feature 0", shap_values, X)

SHAP 价值观

SHAP 依赖图
参数调谐
使用树作为基础学*器的 Boosting 有几个调整参数。可以说最重要的是提升迭代的次数。其他调整参数包括学*速率、最大树深度、每片叶子的最小样本数、叶子数以及其他参数,例如对叶子值的 L2 正则化和对叶子数的 L0 惩罚。通常较小的学*率会导致更精确的模型。然而,建议也尝试更大的学*速率(例如,1 或更大),因为当使用梯度提升时,梯度的比例可以取决于损失函数和数据,并且即使更大数量的提升迭代(比如 1000)对于小的学*速率也可能是不够的。这与牛顿提升形成对比,牛顿提升使用小于 0.1 的学*率,因为自然梯度与比例无关。
例如,可以使用随机或确定性网格搜索和 k 重交叉验证来选择这些调整参数,如下所示。一种计算成本更低的替代全 k 倍交叉验证的方法是将验证数据集传递给参数调整函数。更多细节*这里(对于 R) 和这里(对于 Python) 。请注意,使用“grid.search.tune.parameters”功能需要 GPBoost 版本 0.4.3 或更高版本。
换 R
# Create random effects model and datasets
gp_model <- GPModel(gp_coords = coords,
cov_function = "exponential")
dtrain <- gpb.Dataset(data = X, label = y)
# Candidate parameter grid
param_grid = list("learning_rate" = c(1,0.1,0.01),
"min_data_in_leaf" = c(1,10,100),
"max_depth" = c(1,3,5,10))
# Other parameters not contained in the grid of tuning parameters
params <- list(objective = "regression_l2", verbose = 0,
"num_leaves" = 2^10)
# Use random grid search and cross-validation. Set 'num_try_random=NULL' to use deterministic grid search
set.seed(1)
opt_params <- gpb.grid.search.tune.parameters(
param_grid = param_grid,
params = params,
num_try_random = 20,
nfold = 4,
data = dtrain,
gp_model = gp_model,
verbose_eval = 1,
nrounds = 1000,
early_stopping_rounds = 5,
eval = "l2")
# Found the following parameters:
# ***** New best score (0.397766105827059) found for the following parameter combination: learning_rate: 0.01, min_data_in_leaf: 10, max_depth: 3, nrounds: 247
在 Python 中
gp_model = gpb.GPModel(gp_coords=coords, cov_function="exponential")
data_train = gpb.Dataset(X, y)
# Candidate parameter grid
param_grid = {'learning_rate': [1,0.1,0.01],
'min_data_in_leaf': [1,10,100],
'max_depth': [1,3,5,10]}
# Other parameters not contained in the grid of tuning parameters
params = { 'objective': 'regression_l2', 'verbose': 0,
'num_leaves': 2**17 }
opt_params = gpb.grid_search_tune_parameters(
param_grid=param_grid,
params=params,
num_try_random=20,
nfold=4,
gp_model=gp_model,
use_gp_model_for_validation=True,
train_set=data_train,
verbose_eval=1,
num_boost_round=1000,
early_stopping_rounds=5,
seed=1,
metrics='l2')
print("Best number of iterations: " + str(opt_params['best_iter']))
print("Best score: " + str(opt_params['best_score']))
print("Best parameters: " + str(opt_params['best_params']))
与替代方法的比较
在下文中,我们将 GPBoost 算法与以下替代方法进行比较:
- ****线性高斯过程模型(‘线性 GP’)其中 F(X)是线性函数
- ****标准梯度树提升并将空间坐标作为常规预测变量s(‘L2Boost’)包含在 F()中
- ****随机森林并包括空间坐标作为常规预测变量
我们使用交叉验证来选择调整参数,并使用测试数据的均方根误差(RMSE)来测量预测准确性。产生这些结果的 r 代码可以在下面的附录中找到。结果如下表所示。

GPBoost 和替代方法的预测精度比较。
我们发现,就预测准确性而言,GPBoost 优于所有其他替代方案。 注意,为了简单起*,我们只做一次模拟运行;更详细的对比* 西格里斯特(2020) 。除了随机森林,所有计算都是使用 GPBoost 库 0.7.5 版完成的。此外,我们使用 randomForest R 包版本4.6–14。**
结论
GPBoost 库允许结合高斯过程模型和树提升。在上面的例子中,我们已经假设在空间位置 s 和其他预测变量 X 之间没有相互作用。这可以容易地放宽,例如,通过在预测函数 F(X,s)中也包括空间位置 s 和/或通过在高斯过程 b(X,s)中另外包括其他非空间预测变量 X。
总之,如果您使用高斯过程模型对空间数据进行建模,您应该调查线性假设是否确实合适。GPBoost 算法允许以灵活的方式放宽这一假设。它可以帮助您找到非线性和相互作用,并实现更高的预测准确性。如果您经常使用 boosting 算法,并希望将它们应用于空间数据,GPBoost(它扩展了 LightGBM)可以使学*更加高效并产生更高的预测准确性。一般来说,GPBoost 算法还可以应用于非空间数据集,其中应该结合使用树提升和高斯过程回归。此外,GPBoost 库还允许将树提升与(分组)随机效果模型相结合。
希望这篇文章对你有用。关于 GPBoost 的更多信息可以在配套文章 (Sigrist,2020) 和 GitHub 上找到。
参考
Johnson 和 t .张(2013 年)。利用正则化贪婪森林学*非线性函数。 IEEE 模式分析与机器智能汇刊, 36 (5),942–954。
尼尔森 D. (2016)。用 XGBoost 进行树提升——为什么 XGBoost 会赢得“每一次”机器学*比赛?(硕士论文,NTNU)。
西格里斯特,F. (2020)。高斯过程增强。arXiv 预印本 arXiv:2004.02653 。
附录
模拟数据的 r 代码
set.seed(1)
# Simulate Gaussian process: training and test data (the latter on a grid for visualization)
cov_function <- "exponential"
sigma2_1 <- 0.35 # marginal variance of GP
rho <- 0.1 # range parameter
sigma2 <- 0.1 # error variance
n <- 200 # number of training samples
nx <- 50 # test data: number of grid points on each axis
# training locations (exclude upper right rectangle)
coords <- matrix(runif(2)/2,ncol=2, dimnames=list(NULL,paste0("s_",1:2)))
while (dim(coords)[1]<n) {
coord_i <- runif(2)
if (!(coord_i[1]>=0.6 & coord_i[2]>=0.6)) {
coords <- rbind(coords,coord_i)
}
}
# test locations (rectangular grid)
s_1 <- s_2 <- rep((1:nx)/nx,nx)
for(i in 1:nx) s_2[((i-1)*nx+1):(i*nx)]=i/nx
coords_test <- cbind(s_1=s_1,s_2=s_2)
n_all <- nx^2 + n # total number of data points
D <- as.matrix(dist(rbind(coords_test,coords))) # distance matrix
if(cov_function=="exponential"){
Sigma <- exp(-D/rho)+diag(1E-10,n_all)
}else if (cov_function=="gaussian"){
Sigma <- exp(-(D/rho)^2)+diag(1E-10,n_all)
}
C <- t(chol(Sigma))
b_all <- sqrt(sigma2_1)*C%*%rnorm(n_all)
b_train <- b_all[(nx^2+1):n_all] # training data GP
# Mean function. Use two predictor variables of which only one has an effect for easy visualization
f1d <- function(x) sin(3*pi*x) + (1 + 3 * pmax(0,x-0.5)/(x-0.5)) - 3
X <- matrix(runif(2*n), ncol=2, dimnames=list(NULL,paste0("Covariate_",1:2)))
F_X_train <- f1d(X[,1]) # mean
xi_train <- sqrt(sigma2) * rnorm(n) # simulate error term
y <- F_X_train + b_train + xi_train # observed data
# test data
x <- seq(from=0,to=1,length.out=nx^2)
x[x==0.5] = 0.5 + 1E-10
X_test <- cbind(Covariate_1=x, Covariate_2=rep(0,nx^2))
F_X_test <- f1d(X_test[,1])
b_test <- b_all[1:nx^2]
xi_test <- sqrt(sigma2) * rnorm(nx^2)
y_test <- F_X_test + b_test + xi_test
用于模拟数据的 Python 代码
import numpy as np
np.random.seed(1)
# Simulate Gaussian process: training and test data (the latter on a grid for visualization)
sigma2_1 = 0.35 # marginal variance of GP
rho = 0.1 # range parameter
sigma2 = 0.1 # error variance
n = 200 # number of training samples
nx = 50 # test data: number of grid points on each axis
# training locations (exclude upper right rectangle)
coords = np.column_stack(
(np.random.uniform(size=1)/2, np.random.uniform(size=1)/2))
while coords.shape[0] < n:
coord_i = np.random.uniform(size=2)
if not (coord_i[0] >= 0.6 and coord_i[1] >= 0.6):
coords = np.vstack((coords,coord_i))
# test locations (rectangular grid)
s_1 = np.ones(nx * nx)
s_2 = np.ones(nx * nx)
for i in range(nx):
for j in range(nx):
s_1[j * nx + i] = (i + 1) / nx
s_2[i * nx + j] = (i + 1) / nx
coords_test = np.column_stack((s_1, s_2))
n_all = nx**2 + n # total number of data points
coords_all = np.vstack((coords_test,coords))
D = np.zeros((n_all, n_all)) # distance matrix
for i in range(0, n_all):
for j in range(i + 1, n_all):
D[i, j] = np.linalg.norm(coords_all[i, :] - coords_all[j, :])
D[j, i] = D[i, j]
Sigma = sigma2_1 * np.exp(-D / rho) + np.diag(np.zeros(n_all) + 1e-10)
C = np.linalg.cholesky(Sigma)
b_all = C.dot(np.random.normal(size=n_all))
b_train = b_all[(nx*nx):n_all] # training data GP
# Mean function. Use two predictor variables of which only one has an effect for easy visualization
def f1d(x):
return np.sin(3*np.pi*x) + (1 + 3 * np.maximum(np.zeros(len(x)),x-0.5)/(x-0.5)) - 3
X = np.random.rand(n, 2)
F_X_train = f1d(X[:, 0]) # mean
xi_train = np.sqrt(sigma2) * np.random.normal(size=n) # simulate error term
y = F_X_train + b_train + xi_train # observed data
# test data
x = np.linspace(0,1,nx**2)
x[x==0.5] = 0.5 + 1e-10
X_test = np.column_stack((x,np.zeros(nx**2)))
F_X_test = f1d(X_test[:, 0])
b_test = b_all[0:(nx**2)]
xi_test = np.sqrt(sigma2) * np.random.normal(size=(nx**2))
y_test = F_X_test + b_test + xi_test
r 代码用于替代方法的比较
# 1\. Linear Gaussian process model
# Add an intercept term to the model matrix
X1 <- cbind(Intercept=rep(1,n),X)
gp_model <- fitGPModel(gp_coords = coords, cov_function = "exponential",
y = y, X = X1)
X_test1 <- cbind(rep(1,dim(X_test)[1]),X_test)
print("Fitted linear Gaussian process model:")
summary(gp_model)
y_pred_linGP <- predict(gp_model, gp_coords_pred = coords_test,X_pred = X_test1)
MSE_lin <- mean((y_pred_linGP$mu-y_test)^2)
print(paste0("MSE of linear Gaussian process model: ", MSE_lin)) # 1.306599# 2\. Gradient tree-boosting with a squared loss
# Add the coordinates to the predictor variables
XC <- cbind(X,coords)
X_testC <- cbind(X_test,coords_test)
# Choose tuning parameters
dtrain <- gpb.Dataset(data = XC, label = y)
set.seed(1)
opt_params <- gpb.grid.search.tune.parameters(
param_grid = param_grid,
params = params,
num_try_random = NULL,
nfold = 4,
data = dtrain,
verbose_eval = 1,
nrounds = 1000,
early_stopping_rounds = 5,
eval = "l2")
# Found the following parameters:
# ***** New best score (0.450492863373992) found for the following parameter combination: learning_rate: 0.05, min_data_in_leaf: 20, max_depth: 10, nrounds: 176
bst <- gpboost(data = XC, label = y,
nrounds = 176, learning_rate = 0.05,
max_depth = 10, min_data_in_leaf = 20,
objective = "regression_l2", verbose = 0)
pred_l2boost <- predict(bst, data = X_testC)
MSE_l2boost <- mean((pred_l2boost-y_test)^2)
print(paste0("MSE of plain gradient tree-boosting: ", MSE_l2boost)) # 0.555046# 3\. Random forest
library(randomForest)
colnames(XC) <- colnames(X_testC) <- paste0("V",rep(1:dim(XC)[2]))
# Choose tuning parameters
library(caret)
control <- trainControl(method="cv", number=4, search="grid")
tunegrid <- expand.grid(.mtry=c(1:4))
set.seed(1)
rf_gridsearch <- train(y~., data=data.frame(y=y,XC), method="rf", metric="RMSE", tuneGrid=tunegrid, trControl=control)
print(rf_gridsearch)
# Found the following parameters: mtry = 3
set.seed(1)
rf <- randomForest(y ~ ., data = XC, ntree=1000, mtry=3)
# plot(rf) # check "convergence"
pred_rf <- predict(rf, newdata = X_testC) ## predicted labels
MSE_rf <- mean((pred_rf-y_test)^2)
print(paste0("MSE of random forest: ", MSE_rf)) # 0.5730892# Compare root mean square errors of different methods
RMSEs <- sqrt(c(GPBoost=MSE_GPBoost, Lin_GP=MSE_lin, L2Boost=MSE_l2boost, RF=MSE_rf))
print(RMSEs)
## GPBoost Lin_GP L2Boost RF
## 0.6279240 1.1430655 0.7450141 0.7570265
树,尝试,考验我的耐心…
原文:https://towardsdatascience.com/trees-tries-and-trying-my-patience-ee5ce57bc9db?source=collection_archive---------37-----------------------
二叉树(AVL)和前缀树(尝试)到底是怎么回事

照片由 niko photos 在 Unsplash 上拍摄
啊。臭名昭著的树。
如果你在计算机科学上花过时间(或看过任何编程迷因),你一定听说过树。更确切地说是二分搜索法树。
像往常一样,在计算领域,事情与现实世界不太一样。所以,我们的树是颠倒的,根在上面。这是混乱的开始…
让我们试着通过保持简单来摆脱这个主题的迷雾。
二叉树分解
二叉树是计算机科学中的一种数据结构,用于以一种更容易、更快地找到数据的方式存储数据,同时占用尽可能少的空间。

数据结构和算法——TutorialsPoint.com树上的树
关键词:
- 节点—树上保存数据的点。
- 根-顶部的节点。只能是 1。
- 叶-没有子节点的节点。
- 高度—从叶到根的最长边数。
- 遍历/(al)-在树中移动。
- 父节点—上面有一个节点,下面至少有一个节点的节点
- 子节点—位于另一个节点之下的节点
每个节点在包含其数据的同时,还保存指向其下左右节点的指针。这是能够遍历树的关键。
Github 上的 robotgyal 在 Python 中的基本节点
二叉树真正重要的一点是它们速度很快。这部分是由于插入时数据是如何组织的。
小于的值向左,大于的值向右。
这允许 O(n)的时间复杂度。不是最好的。这是因为,通常情况下,这些树可能是不*衡的,即一边的数据比另一边多。它减慢了查找数据的过程,因为您必须遍历每个节点来查找数据。
但是有解决的办法!
AVL 树

发布于 Reddit 上
AVL 树以发明家阿德尔森-维尔斯基和兰迪斯的名字命名,是一种自*衡树。
把它想象成一个以根/父为轴的跷跷板。一边太重会让你一事无成。
在不*衡的情况下,它将围绕节点移动,以便再次变得*衡。这些移动被称为向左和向右旋转。
点击此处了解更多信息:
http://pages.cs.wisc.edu/~ealexand/cs367/NOTES/AVL-Trees/index.html
通过使树*衡,它将时间复杂度改变为 O(logn ),因为你将工作/搜索分成了每一步。从而使其成为最快的数据结构之一。
前缀树(尝试)
与二分搜索法类似的是 Trie 树,即前缀树。我们每天在发短信、使用谷歌或任何使用自动完成或预测文本的软件时,都会与这种类型的结构进行交互。

在 Baeldung 上尝试(前缀尝试)
当存储集合或字符串时,它非常有用并且非常快。它将存储单个字符以及指向其他节点的指针列表。
与二分搜索法的主要区别在于用于遍历的键是字母而不是数字(在图中显示为节点之间的字母)。
在这个例子中,如果你走最左边的路,你会得到“极客”,中间的是“基因”,最右边的是“天才”。
Trie 节点的基本结构:
Github 上的 robotgyal 的 Trie 节点
其中最关键的部分是子节点是最大为 26 的数组。这是因为英语包含 26 个字母,并且由于每个字符串都是按字符拆分和存储的,所以每个级别中的每个节点都有可能有 26 个可能的分支。
这种数据结构既可用于数据科学,也可用于环境输入分析,以解决单词搜索等单词难题。
结尾…?
…
号码
有更多的树。
对你来说幸运的是,我们不会一一列举(目前)。我们今天的目标是对这两者有一个高层次的概述,并在其中,当您更深入地实际编码它们时,使转换变得容易。
记笔记!它们对于计算机科学中的优化极其重要,因为它们有助于构建占用更少空间的更快的应用程序。
这就是未来,对吗?
资源
https://www.tutorialspoint.com/data_structures_algorithms/tree_data_structure.htm https://www.educative.io/edpresso/what-is-a-binary-tree https://www.geeksforgeeks.org/complexity-different-operations-binary-tree-binary-search-tree-avl-tree/#:~:text=Therefore%2C%20searching%20in%20binary%20search,h%20is%20height%20of%20BST http://pages.cs.wisc.edu/~ealexand/cs367/NOTES/AVL-Trees/index.html https://ieeexplore.ieee.org/document/938073 https://www.baeldung.com/cs/tries-prefix-trees https://en.wikipedia.org/wiki/Trie https://www.hackerearth.com/practice/data-structures/advanced-data-structures/trie-keyword-tree/tutorial/ https://www.toptal.com/java/the-trie-a-neglected-data-structure
美国 2020 年大选期间 Reddit 上的热门话题
原文:https://towardsdatascience.com/trending-topics-in-reddit-during-usa-2020-elections-8b25dd4fede9?source=collection_archive---------42-----------------------
使用主题建模和时间序列分析在 reddit 数据集中发现真实事件
在本帖中,我们将分享我们在主题建模和检测文本数据中真实事件方面的工作(代码和结果)。
正在下载 Reddit 数据集
首先,我们使用“pushshidt”API 下载 Reddit 数据。下面的代码使用开始日期、结束日期、子编辑名称和文本类型(可以是 submission 或 comment)来下载速率限制下的数据。我们在 2020 年 8 月 1 日至 2021 年 2 月 1 日期间下载了阴谋、保守派和民主党子编辑。
数据预处理
有了帖子和评论数据帧后,我们希望清理和预处理数据。对于每个提交,我们将“title”和“self-text”字段连接在一起,为帖子获取一个文本字段,对于评论,我们使用“body”字段获取文本。我们删除了“[已删除]”和“[已删除]”文本,并删除了没有日期的帖子和评论。
然后,为了对文本进行预处理,我们去除了停用词、数字和标点符号。我们把文本分成句子,句子分成记号。为了处理数据量和使用丰富的文本,我们只取长度大于 5 个标记的文本。我们准备了一个所有句子的列表,作为即将到来的模型的输入。
主题建模
为了找到一段时间内的趋势事件,我们首先要找到主题。为了获得每个子编辑的相关主题,我们执行了以下三个步骤。
- 文本嵌入
- 使聚集
- 话题指示词
文本嵌入 我们首先要使用 NLP 嵌入技术将每个文本转换成一个向量。我们训练了两个模型:加权 word2vec 和通用语句编码器(USE)。
- 加权 word 2 vec-word2 vec 是一种最先进的单词级嵌入,用一个神经网络隐层进行训练,将每个单词的上下文作为输入,并尝试预测与上下文对应的单词。我们使用这个方法,窗口大小为 5,嵌入大小等于 128。有了词汇表中每个单词的嵌入,我们希望得到整个帖子/评论文本的嵌入。为此,我们使用单词的 tf-idf 分数的加权*均值。下面的代码实现了此方法。
***2。通用句子编码器(使用)——***word 2 vec 方法的主要缺点是不考虑单词的顺序,并且单词的嵌入与它们提到的特定句子没有上下文关系。为了解决这些问题,我们使用了通用语句编码器。主要思想是设计一个编码器,将任意给定的句子概括成 512 维的句子嵌入。USE 使用这种与 transformers 架构的嵌入来解决多个任务,并且基于它在这些任务上所犯的错误,语句嵌入被更新。因为相同的嵌入必须在多个通用任务上工作,所以它将只捕获最有信息的特征并丢弃噪声。直觉是,这将导致通用嵌入,该通用嵌入普遍转移到各种各样的 NLP 任务,例如关联性、聚类、释义检测和文本分类。为了获得每个句子的使用嵌入,我们使用 tensorhub 获得预训练的模型,并使用数据批次应用该模型。
聚类
在得到每个文本的向量表示后,我们使用 K-means 算法得到聚类。然后,每个提交和评论被分配到一个集群或一组前 5 个集群,代表每个文本由几个主题组成。我们使用 TSNE 方法来可视化文本嵌入向量和颜色来表示文本被分配到的簇。

TSNE 可视化的 128 嵌入大小,颜色指示集群。使用悬停显示相关文本。
直方图示例显示了使用使用嵌入为 Conservatives 子编辑的 50 个分类中的每个分类分配的文本数量分布。

话题指示词
我们希望为每个聚类分配描述该聚类的相关词,为此我们尝试了两种方法:
TF-IDF:我们使用每个聚类的文本中 TF-IDF 得分最高的词来表示主题。
接近质心:使用 K-means,我们得到了每个聚类的质心向量。我们计算了质心和词汇表中每个单词之间的距离。最接近的单词代表主题。
下面的代码实现了第二种方法,这种方法的性能优于 tf-idf。对于 word2vec,我们使用 word2vec 模型来获得与质心向量最相似的单词。对于使用,我们通过对每个单词应用使用模型来计算词汇表中每个单词的嵌入,然后我们计算嵌入后单词和每个词汇表单词之间的余弦距离,以获得最接近的单词。
使用上述方法的主题单词示例:

所选集群的前 10 个单词
检测真实事件
我们希望观察主题随时间的出现分布。鉴于社交媒体的性质,当相关事件发生时,用户倾向于增加围绕特定主题的讨论。因此,我们希望看到一个被高度提及的主题与一个具体的现实世界事件之间的相关性。我们希望区分现实世界的事件和日常对话,现实世界的事件激发了对潜在特定主题的讨论。为此,我们绘制了主题(集群)文本量(提交和评论)随时间的变化图,以检测可能指示事件的时间峰值。
主题群的时间序列示例: ['暴徒','暴动','抗议者','抗议','抗议者','暴动','抗议','示威者','波特兰','暴动']:

为了深入研究每个峰值,我们打印与特定日期的相关主题相关的文本:
例如,在上述主题的时间序列中,我们可以在 7/1/21 看到一个主峰,在 27/8/20 看到一个次峰。
7 月 1 日 21 日,与该主题相关的提交和评论引发了一个真实的事件,即暴徒在周三破坏了美国国会大厦的安全。

与 21 年 7 月 1 日主题相关的课文范例。
对于小高峰,27/8/20 与该主题相关的提交和评论引发了另一个真实事件— **明尼阿波利斯虚假谣言骚乱,2020 年 8 月 26 日至 27 日。**明尼阿波利斯市中心发生骚乱,以回应 38 岁的非裔美国人埃迪·索罗(Eddie Sole Jr .)自杀的虚假谣言;示威者认为他是被警察射杀的。

与 27/8/20 主题相关的课文范例。
结论
我们在这里提出了一个完整的管道,使用主题分析方法和时间序列分析从 reddit 数据集中提取真实事件。所提出的方法显示了所提到的主题与特定的真实世界事件之间的高度相关性。上面包含代码和示例的管道提供了查找主题和探索主题、检测事件和深入理解它们的能力。您也可以在其他数据集上使用此管道和可视化。
感谢阅读!!!
《世界幸福报告:联合国可持续发展解决方案网络》的趋势、分析、探索和进一步研究建议
原文:https://towardsdatascience.com/trends-analysis-explorations-and-further-research-proposal-for-the-most-recent-world-happiness-9728cf0ac343?source=collection_archive---------65-----------------------

作者图片
世界幸福报告是由联合国可持续发展解决方案网络发布的。所有的数据清理、探索和分析都是我在 Jupyter 笔记本上使用 python 3 完成的,所有的数据可视化都是使用 python 中的可视化库 Matplotlib 完成的。
介绍
如果我们可以将 75 亿以上的人归结为几个最有助于幸福的关键趋势,他们会是什么样子?这将告诉我们,作为一个集体,我们是谁?它会告诉我们什么是我们最重视的,最终,什么与一个国家人口幸福感的增加最相关?我有一种冲动,想为这个项目选择某些国家,但我认为,同时查看我的数据中显示的所有国家,可以让我们得出一些有趣而直观的结论,这些结论是关于我们大多数人在人生旅程中不同阶段和程度上寻求的东西:幸福。
相互关系
需要进行进一步的研究来试图找到因果关系,但是因为我们的发现才刚刚开始,我们可以从一些基础开始。我们对全球 159 个国家/地区进行了调查,衡量标准如下:
**阶梯:**衡量生活满意度。
**正面情绪:**正面情绪的衡量标准。
**负面情绪:**负面情绪的衡量标准。
**社会支持:**社会支持对幸福分数计算的贡献程度。
**自由度:**自由度对幸福分数计算的贡献程度。
**腐败:**对腐败的感知对幸福得分的贡献程度。
**慷慨度:**慷慨度对幸福分数计算的贡献程度。
**人均 GDP 的对数:**GDP 对幸福得分计算的贡献程度。
**健康预期寿命:**预期寿命对幸福指数计算的贡献程度。
一下子鸟瞰这些数据有点令人望而生畏,但如果你快速浏览下面的内容,你会发现上述变量之间几乎没有强相关的集中区域。四个最值得注意的配对包括:“人均国内生产总值对数”和“健康预期寿命”,社会支持和“人均国内生产总值对数”,“健康预期寿命”和社会支持,以及“自由”和“积极影响”是最接近的聚类配对,具有最清晰、最线性的关系,有助于给人们带来最大幸福的因素。

作者图片
健康、幸福和繁荣
我们看过多少次经典的“健康、幸福和繁荣!”在贺卡上?当我们想要表达真诚的良好祝愿时,我们能想到的最好的是大量的健康、幸福和快乐(大概是和最亲近的人一起度过的)和富足,以及一种富足的感觉,一种比你想要的多一点的感觉。自由呢?事实上,没有这些,我们就出发了。但这到底是为什么呢?看一看这些更深刻的*解,可以让我们了解一点我们与幸福及其“内在组成部分”的关系。
主要趋势
回到上面提到的四个最值得注意的对:“人均国内生产总值对数”&“健康预期寿命”,社会支持&“人均国内生产总值对数”,“健康预期寿命”&社会支持,以及“自由”和“积极情感”,我们看到这四组之间的联系比其他任何一组都强。从以下四组数据中,我们可以观察到以下对幸福贡献最大的因素:
- 国内生产总值与健康的预期寿命以及社会支持密切相关
- 在预期寿命和国内生产总值健康的国家,社会支持是成比例的
- 似乎更自由的社会有更大的积极影响

作者图片
更多问题!
这些趋势让我们提出了更多的问题。GDP 增长和高预期寿命哪个先来?人们是活得更长了,从而对 GDP 做出了更大的贡献,还是因为经济更健康、生活质量更高而活得更长了?是社会支持越多的国家越成功,还是国家的成功创造了更多的社会凝聚力?人们是因为社会中的自由而感觉更积极,还是消极的社会滋生了更多的威权主义?预期寿命的增长是因为社会纽带的增加,还是因为我们活得更长而创造了更多的社会纽带?
热图
也许再看一下这些趋势之间的关系,热图是最好的服务。下面,我们看到高相关性区域和低相关性区域:

作者图片
在影响力最低的领域中,我们会发现腐败。这是否是因为考虑到衡量一个国家生活质量和幸福的其他方面,腐败对幸福的影响最小?在地图上最温暖的区域中,我们再次看到社会支持、国内生产总值和健康预期寿命之间的密切关系,正如我们在前面的图表中观察到的那样。此后一个很好的探索领域是研究为什么腐败对大多数国家的*均影响如此微弱。腐败是意料之中而被忽视的吗?或者也许它是如此远离人们的视线和幕后,以至于它不会影响人们?
前 5 名和后 5 名分析
我们可以通过对 156 个国家中排名前 5 位(芬兰、丹麦、挪威、冰岛和荷兰)和排名后 5 位(卢旺达、坦桑尼亚、阿富汗、中非共和国、南苏丹)的分析,来研究我们列表中的一些趋势。我们选择了以下类别来区分有助于这两个群体幸福的因素:积极的情感、社会支持、消极的情感、健康的预期寿命,

作者图片

作者图片

作者图片

作者图片

作者图片
奇怪的是,其中一些类别给了我们一些令人惊讶的结果。与排名前五的国家相比,排名后五的国家从慷慨、社会支持、积极情感和健康的预期寿命中获得的快乐最多。关于这些社会,这告诉了我们什么?也许他们的社会是建立在相互依赖的共同价值观上的,这反过来影响了他们如何看待自己的整体生活质量(更积极)以及他们如何看待自己的健康和预期寿命。在我们研究的类别中,倒数五个国家在负面情绪上得分较高,这可能并不令人惊讶,因为这对他们的幸福有着比前五名更大的影响。
进一步研究建议
为了回答本报告中提出的一些问题,我们需要发现更多的数据来帮助我们探索这些关系,并尝试区分因果关系和相关性。发现哪些方面是驱动因素可以告诉我们很多关于加强我们的经济和优先考虑健康和福祉的一些社会效益,就像新西兰最近宣布的那样。
我们对名单中排名前五和后五的国家进行了比较,这也给了我们一些想要跟进的额外要点。其中最核心的问题是:在人类如何相互联系和相互依赖方面,最脆弱的国家能教给我们什么?为什么他们对幸福的贡献比排名前五的国家大得多?关于在一个高度不安全的国家生活的共同经历,他们能教给我们什么?
这些国家的公民更重视彼此,而不认为他们所拥有的幸福是理所当然的,这是真的吗?由于更强的目标感,艰苦会反过来创造更多的幸福吗?顶级国家的趋势是否向我们展示了舒适和机会滋生了进一步的个人主义、社会依赖性的丧失和自满?
研究提案大纲
问题是:
对于我们所观察的世界幸福的哪些方面导致了某种关系,或者它们是否有一种更复杂的关系,还存在困惑。更多地了解哪些研究指标对我们数据集中的国家的幸福贡献更大,将有助于我们在未来为这些国家的公民带来永久的幸福。我们知道,各国更幸福的公民会以数不清的、定性的、往往在幕后的方式极大地促进福祉,甚至提高生产率。虽然这是一项模糊的事业,但如果我们能更进一步了解这些关系,我们就能更进一步量化一些以前看不*的动态。
潜在的解决方案:
我们可以衡量因果关系的一个潜在方法是对那些最初向联合国科学与发展委员会明确要求因果关系的人进行调查,以便我们可以收集足够的关于幸福具体影响因素的数据。没有对驱动因素的更多探索,那些与幸福增加最直接相关的因素,我们就无法确定因果关系,所以这可能是确定因果关系的自然下一步。
测试溶液的方法:
与其通过哪些因素对他们的幸福最积极的背景来理解这些关系,我们可以要求被调查的人群对他们幸福的前五名贡献者进行评级。这将使我们能够量化哪些因素会增加被调查者的幸福感。给排名第一的贡献者分配递减值 5,给排名第二的贡献者分配递减值 4,以此类推,这将允许我们给每个幸福因素一个可量化的值,我们可以用它来做进一步的研究。
设计的第一步是精心设计五大品质。鉴于上面提到的主要趋势,我们可以使用每个集合中的值来尝试和衡量层次结构。我们将要求被调查者对以下因素进行评分,从 1 到 5,5 为最高因素:“人均 GDP 对数”、“健康预期寿命”、“社会支持”、“自由”和“积极影响”。为了解释我们不知道的任何固有偏*,我们可以每隔六个月进行两次调查。如果有超过 5%的差异,我们可以*均的 delta。
暂停怀疑和夸大可能性的领域,我们还可以在 2019 年世界幸福报告中看到的国家内对这些因素本身进行大规模的改变,看看参与者是否对他们的答案做出任何改变。因为我们是在非常主观的能力下工作,拥有迭代和步骤将允许我们从记录数据的任何变化中获得洞察力。实验第一部分的参与者可能不会准确地给他们的答案打分。为了说明这一点,我们需要创建一个场景,其中有一个对照组,因为观察到的数据可能过于主观。为了模拟随机对照试验,我们可以确定我们想要评价的所有因素,在我们的例子中是上面提到的五个因素,并分析从初始调查中观察到的数据,以便梳理出一个因素相对于其他因素的重要性。
从我们在发生重大变化后收集的第二组数据中,我们可以将注意力转向两对可能具有类似动态的国家。在我们的案例中,我们从前五名和后五名名单中选择了两个国家:芬兰和挪威,以及卢旺达和南苏丹。我们选择这两对的兴趣是分析它们的相似性和差异性,努力在两对之间找到一些复合趋势。
枪支背景调查的趋势
原文:https://towardsdatascience.com/trends-in-firearm-background-checks-802a7c74734a?source=collection_archive---------45-----------------------
从 2000 年到 2020 年的背景调查数据可以洞察美国枪支的购买趋势

在 Unsplash 上由 STNGR Industries 拍摄的照片
2020 年是美国相当多事的一年,其间有冠状病毒疫情、内乱、和混乱的总统选举。在这些事件和更多事件之间,一种共同的感觉在今年很突出——不确定性。不确定感似乎经常导致枪支销售的增加,今年不确定性的三重打击导致许多头条新闻讲述了全国各州枪支下架的情况。
这让我对美国的枪支销售趋势感到好奇。不幸的是,没有购买枪支数量的数据。然而,我们确实可以使用下一个最好的东西——购买这些枪支所需的背景调查。我将首先理解背景调查与购买的枪支不是 1:1 的关系,因为你可以完成背景调查,或者 1。)检查失败或 2。)通过检查,但决定不继续购买。
然而,我认为对于第一次刺伤分析来说,这是非常接近的,因为在某种程度上,这些数字可以被同一笔交易中购买的多支枪抵消(每笔交易只需要一次检查)。
使用的数据来自国家即时犯罪背景调查系统(NICS ),我使用了 2000 年至 2020 年的 20 年间的数据,这些数据按州和月份细分。让我们先看看每年的总数。

图片作者。
大约从 2006 年开始,我们看到一个相对稳定的增长,一直持续到 2016 年不成比例的峰值。不出所料,2020 年背景调查也会大幅增加。我认为假设选举年导致枪支购买激增是合理的。2012 年和 2016 年都比前几年增长了 19%,而 2020 年比 2019 年增长了令人难以置信的 26%。
为了给数据添加更多的粒度,让我们重现上面的图表,但是是每月一次。

背景调查记录的循环性质特别有趣。一般来说,较大比例的检查发生在下半年。图片作者。
让我们按月分解 2016 年,看看大部分增长是从什么时候开始的。

图片作者。
背景调查,以及随之而来的销售,在 8 月份真正开始回升。随着 2016 年总统选举日的临近,每位候选人都开始阐述自己的政策立场。在 2016 年 8 月 9 日的一次集会上,唐纳德·特朗普曾说:
“希拉里想要废除——实质上是废除第二修正案。”
虽然第二修正案是特朗普 2016 年竞选期间的一个常**台优先事项,但特朗普后续声明的新闻周期中,这个特定片段的生命更长,因为它具有争议性而迅速传播:
“如果她能选择自己的评委,你们就无能为力了,伙计们。虽然第二修正案的人——也许有,我不知道。”
几天后的 8 月 10 日,全国步枪协会购买了 300 万美元的播放时间,用于希拉里·克林顿枪支管制政策的广告。似乎 8 月份是在选举前的一段时间里出现了一种占主导地位的“枪支权利处于危险之中”的叙事,对此,更高比例的美国人做出了购买更多枪支的回应。
让我们看看 2015 年,看看我们在 2016 年 1 月/2 月看到的增长是从哪里开始的。

图片作者。
年底支票数量激增,尤其是在 12 月。12 月发生了什么?加州圣贝纳迪诺枪击案。事实上,2015 年发生了不少枪击事件,其中许多事件(如下面确定的枪击事件)都是围绕增加枪支管制措施进行的讨论。

图片作者。
很有可能其他因素也在这一增长中发挥了作用,但这是我能注意到的最明显的趋势。对于去年的具体细分,让我们看看 2020 年的事件如何影响过去一年的背景调查。

火器背景调查显示 2020 年的过山车。图片作者。
背景调查的增加清楚地代表了 2020 年的三大事件(至少在恐惧和不确定性方面)。新冠肺炎最初的封锁始于 3 月中旬,随着乔治·弗洛伊德(George Floyd)于 5 月 25 日去世,6 月份爆发了大规模的民众骚乱。2020 年大选及其后的余波也导致背景调查和枪支购买的增加,从 10 月开始,一直持续到 12 月。2020 年总共有超过3500 万背景调查,比 2019 年增长 26%。
这种说法非常符合当前枪支和弹药购买条件的现实——弹药的购买速度超过了补充库存的速度,如果不支付令人难以置信的价格,很难买到枪支。2020 年 3 月,联邦调查局的 NICS 系统甚至被破纪录的枪支 sales⁴.数量淹没
国家级分析
为了查看州级分析,我想从查看哪些州在 20 年间记录的总数最高开始。

伊利诺伊州和肯塔基州的居民购买大量枪支!图片作者。
伊利诺伊州获得背景调查数量最多的奖项,2020 年记录了超过 660 万次调查!为了更好地理解与各州人口相关的数据,我加载了另一个数据集,其中包含 state⁵. 2010 年至 2019 年的人口估计数该数据集没有 2020 年的人口数据(因为一旦 2020 年人口普查数据发布,就会提供人口数据),但让我们来看看按州人口统计的标准化数据。
通过将背景调查的次数除以该州当年的人口数,获得各州人口的标准化值。
这将产生一个新的数据帧,其中包含状态检查、填充和标准化值。通过找到每一列的最大值,我们可以看到哪个州的人口检查次数最多
maxValue = state_normalized.idxmax()
print(maxValue)

肯塔基买了很多枪!图片作者。
在 2010 年至 2019 年期间,肯塔基州对每个州人口的背景调查量最高。如果我们使用肯塔基州 2020 年的人口估计值 4,474,190,那么肯塔基州在 2020 年的人口比率也将是最高的。在这个范围内的 10 年中的 8 年里,肯塔基州也是独立于人口规模进行检查次数最多的州。2017 年和 2018 年,人口归一化比值大于 1,意味着肯塔基州每 100 人进行 104 次(2017 年)和 110 次(2018 年)背景调查。这个数据的一个缺陷是,我无法按年龄组定位估计的州人口。最终,只过滤大于或等于 18 岁的年龄(从经销商处购买枪支所需的最小年龄)是最理想的。
我没有一个假设来解释为什么肯塔基州在背景调查和每年购买枪支的数量上如此异常。虽然它被认为是一个枪支友好的州,但从 referenced⁶.的一些来源来看,它并没有打破前五名在 2018 年肯塔基州的归一化值为 110%时,得分次高的是西弗吉尼亚州,为 39.38%。
在州一级的分析中,我也对各州的政治倾向感到好奇,因为枪支是一个固有的政治话题。为了简单起*,我根据 2020 年的选举结果将各州分为红色、蓝色和摇摆州。这可以通过反映基于 20 年期间每次大选结果的倾向而变得更加准确。
然后,我根据这些值和背景检查总数进行分组,并绘制出结果。

图片作者。
虽然从 2011 年开始,所有州的背景调查都出现了更大的增长,但红州从 2005 年左右开始购买更多的枪支。虽然蓝色州和摇摆州的枪支年购买量波动较大,但红色州的居民一直在不断增加每年的枪支购买量(看看你,肯塔基州!).
根据这一分析,背景调查以及通过代理人购买枪支的情况似乎在不稳定和不确定时期有所增加。背景调查的数量每年都在增加,与选举年前后相比,选举年的背景调查数量更大。红州比蓝州或摇摆州购买更多枪支,*均而言,从 2005 年到 2017 年左右,购买率更高。自 2010 年以来,肯塔基州拥有每年进行最多背景调查的记录。
这个分析的代码可以在我的 github 这里找到:https://github.com/jspitze。感谢阅读!
参考
- https://www.fbi.gov/services/cjis/nics
- https://www . NBC news . com/politics/2016-election/trump-campaign-defense-2nd-amend-comment-n 626601
- https://www . Washington times . com/news/2016/aug/10/NRA-takes-伪君子-希拉里-克林顿-new-tv-ad/
- https://www . Washington examiner . com/Washington-secrets/FBI-300-spike-in-gun-buy-checks-big-backlog-shut down-threated
- https://www . census . gov/data/tables/time-series/demo/popest/2010s-state-total . html
- https://www . theburningplatform . com/2020/04/12/the-most-and-less-gun-friendly-States/,https://www . gunsandammo . com/editorial/best-States-for-gun-owners/369075
纽约市警察不当行为案件的趋势
原文:https://towardsdatascience.com/trends-in-police-brutality-cases-in-nyc-f3c591731438?source=collection_archive---------32-----------------------

照片由马太·亨利从爆出
ProPublica NYPD *民不当行为数据集的可视化分析
1976 年实施的第 50-a 号立法拒绝向公众披露警方记录,以防止刑事辩护律师在交叉询问中使用这些记录。2020 年 6 月 12 日,纽约州废除了这项法律。非营利组织 ProPublica 提交了记录请求,并根据条款和条件向公众提供了这些数据。
我们分析了这些数据,以捕捉纽约市多年来基于种族的警察暴力趋势以及此类案件对警察的相应影响。
数据集
我们使用了由 ProPublica 提供的市民对纽约市警察的投诉数据集
- 该数据集于 2020 年 7 月发布。
- 该数据集包含 33 358 起文职人员不当行为案件的细节。
- 记录时间跨度从 1985 年 9 月到 2020 年 1 月。
重要提示:
这个数据库列出了 NYPD 36000 名现役军官中的 4000 名。数据库中的每一名警官都有过 至少一项经证实的指控 。我们排除了调查人员认为没有发生且被认为毫无根据的任何指控。”ProPublica
数据转换
我们利用 R tidyverse 进行此分析,重点关注ggplot2 和dplyr封装。
整个分析是作为一个 bookdown 完成的,它是一个开源的 R 包,便于编写带有 R Markdown 的长格式报告。
虽然主数据集很容易开始,但我们必须创建一些新的变量来揭示一些有趣的发现。
- 创建了新的变量
rank_after,该变量是从针对同一名官员的下一次投诉中为每名官员计算的线索rank_incident。 - 由官员根据投诉的时间顺序创建
nth_complaint变量。
缺失值分析
为了了解缺失值的任何趋势,我们使用了 r 中的mi包。该包允许用户了解并有效地估算缺失值。我们利用该包来生成缺失值聚类。

- 在用于分析的列中,只有
complainant_ethnicity、precinct、complainant_age_incident、complainant_gender的值缺失 - 很明显,在大多数情况下,年龄、性别、种族的缺失值同时出现,这可能是由于记账效率低下造成的。
为了进行此分析,对数据进行了转换,所有缺失值都被标签“未知”所替代。
警察不当行为案件的时间趋势
我们首先根据不同的分类来看数据的时间趋势。
按指控类型分列的不当行为案件

按案件类型分列的不当行为案件
针对 NYPD 警官的案件数量正在上升,滥用职权案件的增长速度令人担忧。
21 世纪初,各类警察不当行为案件激增。虽然 2010 年代这一增长趋于稳定,但病例总数仍然高得令人担忧。
按投诉人族裔分列的不当行为案件

按投诉人族裔分列的不当行为案件
当按投诉人的种族划分时,出现了一个明显的趋势,即少数民族社区(主要是黑人和西班牙人)的病例增加最多
尽管白人占纽约市人口的大多数,但报道的白人暴力事件的数量仍然可以忽略不计。
这表明纽约市警察不当行为案件中存在明显的种族偏*
**注:**数据集仅包括已结案的案件,并已宣布结果。我们在图的最后看到的数字下降可能是由于大量案件仍在审查中。
一年来董事会的处置情况
然后,我们查看了这些年来董事会成员的分布情况。

近年来,证据不足的案件在减少,而证据确凿和证明无罪的案件在增加。
这可能要归功于该市民事投诉审查委员会 (CCRB)职能的改善
然而,一个令人担忧的观察结果是无罪案件的激增,约占近年来报告案件总数的三分之一。
当调查人员断定一名*民所指控的事情确实发生了,但该行为被 NYPD 规则所允许时,该案件被归类为无罪。这通常在各种"使用武力"的案件中被利用,在这些案件中,官员有很大的酌处权。
前 CCRB 调查员丹·博达(Dan Bodah)说,“我免除了数以吨计的案件,这些案件涉及的恶劣行为符合指导原则。”他现在在维拉司法研究所研究警察监督。“这有点令人难以忘怀。法律和政策给了警察很大的自由裁量权。”来源: ProPublica
不当行为案件对警官的影响
为了了解这些不当行为案件对警察的影响,我们研究了随着指控案件数量的增加,至少有一项指控属实的警察级别的变化


- 总体而言,随着针对该官员的案件数量增加,似乎没有对该官员的级别产生负面影响(以降级的形式)
- 即使收到 20 多份投诉,仍有相当多的官员继续得到晋升。
- 尽管我们注意到,随着针对他们的案件数量的增加,警察人数有所减少,但这些数字仍然不令人鼓舞。
2020 年,警察队伍中有 1000 多名警察在职业生涯中收到 10 次或更多投诉,他们继续以类似于收到一次投诉的警察的速度晋升。
结论
尽管有一段黑暗的历史,但 NYPD 正显示出改善的迹象,从公开其记录开始。这有助公众评估警队需要改善的地方,以便为市民提供更佳服务。
有明显的迹象表明,NYPD 的各个阶层之间存在着巨大的差距。从固有的种族偏*,多年的疏忽,到支持甚至奖励这种行为的制度。需要从各个方面做大量工作来改善这种情况。
虽然前面还有很长的路要走,但通过采取积极的行动和保持开放的对话,就有希望实现更美好的未来。我希望这一分析将有助于在更深层次上理解这些问题,并促使决策者和其他利益相关者做出有影响力的决定。
我们使用 r 对这个数据集进行了更广泛的分析。读者可以在这里找到我们发布的版本,在这里找到代码
我要感谢我的同学 Aditya Koduri 对这一分析的重大贡献。没有他,这篇文章是不可能完成的。
如果您有任何问题,可以通过 smarth.g@columbia.edu联系我。在 LinkedIn 和 Twitter 上关注我。
数据集可以在这里找到
另一篇在地区层面探索数据集方面做得很好的中型文章:可视化 ProPublica NYPD 文件
谢谢!
我给读者留下了一些显示指控类型收到的投诉的频率图。
“肉体力量指控近 5000 个,“搜身指控近 2000 个,“枪尖”指控 600 多个




“肉体力量指控近 5000 个,“搜身指控近 2000 个,“枪尖指控 600 多个。”
塑造 2021 年现代数据堆栈的趋势
原文:https://towardsdatascience.com/trends-that-shaped-the-modern-data-stack-in-2021-4e2348fee9a3?source=collection_archive---------5-----------------------
数据集成 2.0、数据网格、数据仓库性能和数据可观察性。对于数据和分析来说,这是丰富的一年。

来源:盖蒂图片社 Istock
如果我要选择三个主题来描述现代数据堆栈的状态,以及 2021 年大多数数据领导者的首选,它们将是速度、自主性和可靠性。
- 速度:现在每个人都想访问数据。许多新技术使这成为可能,并允许组织在扩展时支持甚至最复杂的分析用例。
- Autonomy :自助服务分析在 2021 年继续蓬勃发展,该领域出现的一些神奇工具使其变得更加可能。随着 ELT 成为新的 ETL,反向 ETL 使业务用户能够操作仓库中的数据,数据集成变得前所未有的简单。
- 可靠性:每家公司都希望成为数据驱动型公司,但几乎每家公司在处理数据时都面临着缺乏信任的问题。数据可靠性是一个总括术语,涵盖了从基础设施的可靠性到数据本身的可靠性等概念。虽然我们可能无法完全区分这两者,但后者在过去几年中获得了显著的曝光,并成为数据基础设施和工具领域中的一个新类别。
按照同样的思路,以下是我的观点,2021 年塑造现代数据堆栈的 5 个趋势,以及其中一些趋势将如何在 2022 年继续流行。
- 数据和数据堆栈的民主化
- 数据集成变得更加简单:ETL 到 ELT 和反向 ETL
- 性能和速度:每个人都想要数据,昨天
- 数据网格
- 数据可观察性
1。民主化:数据和数据堆栈。
根据定义,民主化是让每个人都能获得某些东西的行动。随着公司努力变得更加数据驱动,他们已经做出了相当大的努力来确保组织中的每个人都可以访问相关数据。强调“相关”。民主化始于在内部建立正确的流程,并确保每个人在涉及数据时使用相同的语言,这是臭名昭著的唯一真理来源。
数据素养在采用数据驱动的文化中扮演着重要角色。几十年来,在某些情况下,处理数据过去是、现在仍然是一小部分人的专利。今天,数据基础设施和工具领域出现了许多公司和技术,它们甚至允许最不专业的技术人员利用数据(稍后将详细介绍反向 ETL)。您不再需要成为一名 SQL 忍者来支持基本的运营分析用例。
2。数据集成变得更容易 : ELT 是新的 ETL 。
ETL 是 Extract Transform Load 的缩写,是根据 E、T 和 l 三个步骤通过 ETL 管道将数据从一个点移动到另一个点的过程。在实践中,首先,从一个或多个源(通常是 SQL 或 NoSQL 数据库)提取数据。然后对其进行转换,以符合目的地在格式、结构或形状方面的要求。最后,数据被加载到目标系统,通常是云数据仓库。
ELT 实际上是提取负载转换,这两个过程之间的关键区别在于转换阶段,确切地说是在何时何地完成的。
在传统的 ETL 管道中,转换发生在数据仓库之外的暂存环境中,在那里整个数据被“临时”加载以进行转换;然后将转换后的数据加载到仓库中。在 ELT 中,数据首先以原始形式加载到目标系统中,然后在数据仓库中进行转换,因此与 ETL 不同,它不依赖于任何远程环境。Qlik 的团队对此做了更多报道:https://www.qlik.com/us/etl/etl-vs-elt
我不会进一步详细说明为什么您应该选择一个过程而不是另一个,但简而言之:当处理原始形式的数据时,对速度、成本优化和整体更大灵活性的需求推动了从 ETL 到 ELT 的迁移。
反向 ETL 是…新的 ETL?
2021 年,我们*证了一种新的数据集成方法的发展:逆向 ETL。而且不,不是 LTE 尽管这很诱人,但反向 ETL 是将数据从数据仓库转移到其他基于云的业务应用程序(CRM、营销、财务工具等)的过程。)因此它可以用于分析目的。顾名思义,在某种程度上,反向 ETL 与传统的 ETL 管道相反,或者换句话说,它是一个 ETL,但用于数据仓库中数据堆栈的右侧。Hightouch 的团队提供了更多相关信息:https://hightouch.io/blog/reverse-etl/
尽管这个概念可能看起来很简单,但由于它能够支持运营分析用例并在组织内实现进一步的数据支持,reverse ETL 今年获得了显著的可*性。
3。性能和速度:大家都想要数据,昨天。
在数据存储和处理方面,快速和良好并不一定等同于高成本,雪花通过分离存储和计算在这方面发挥了重要作用。随着大多数组织都可以进行通用分析,现在的重点是性能和速度。我们都很喜欢关注 Databricks vs. Snowflake saga,Rockset vs . Apache Druid vs . click house,然后 ClickHouse vs. TimescaleDB。但是,如果这些现代数据栈巷战有一个共同的主题,那就是速度;每个人都声称自己是速度最快、成本最优的工具。【https://ottertune.com/blog/2021-databases-retrospective/ 号
这种趋势在数据存储领域非常普遍,因为它更加成熟,用户期望和 KPI 也相对明确。这种趋势无疑将在未来扩展到现代数据堆栈的其他不太成熟的领域。
4。去中心化,数据作为产品,数据网状。
如果我们没有提到席卷数据世界并成为无数辩论主题的趋势:数据网格,这就不是 2021 年的数据趋势概述。虽然从技术上讲,数据网格的早期概念是在 2020 年首次提出的;后者已经发展成为一种基本的数据架构范式转变,一些数据非常成熟的组织采纳了这种想法,并与更广泛的社区分享他们的经验。
对于外行来说,data mesh——正如它的创造者 Zhamak Dehghani 所解释的那样——是一种在组织内访问、管理和共享数据的分散的社会技术方法。
扎马克围绕四个关键原则构建了她的框架:
- 领域驱动的设计,适用于数据或面向领域的所有权
- 数据作为产品在组织内外共享
- 自助式基础设施或 IaaS,允许进一步的自治和更广泛的数据民主化
- 联合治理*衡每个团队的独立性,同时协调组织内的质量和控制标准。
一些有用的资源可以让你熟悉:
- Zalando 案例研究:https://data bricks . com/session _ na20/data-mesh-in-practice-how-europes-leading-online-platform-for-fashion-goes-beyond-the-data-lake
- 摩根大通案例研究:https://wiki bon . com/breaking-analysis-how-JP-mor gan-is-implementing-a-data-mesh-on-the-AWS-cloud/
- Zhamak 通过数据工程播客 https://www . dataengineeringpodcast . com/Data-mesh-revisited-episode-250/对这个话题的最新看法
5。数据可观察性
我先声明,我在这里是有偏*的。也就是说,数据基础设施和工具领域今年获得了巨大的发展势头,一些令人惊叹的新技术和公司试图解决这个复杂的问题。
最初是从 DevOps 世界借用的概念,数据可观察性正迅速成为任何现代数据堆栈的重要组成部分,确保数据团队可以使用可靠的数据推动业务计划。
在 DevOps 中,可观察性的概念以三个主要支柱为中心:跟踪、日志和指标,它们代表了任何基础设施和应用程序监控框架的金三角。像 Datadog、NewRelic、Splunk 等解决方案已经为软件开发中的标准实践铺*了道路;只有他们的一些最佳实践转化为数据工程(软件工程的一个子集)才有意义。
数据可观测性、数据质量监控、数据可靠性、管道监控等。,都是经常互换使用的术语,而且使用不当。至于原因,我就不多说了;这是另一个辩论的主题,但是您可以通过将围绕数据的过程分解为跨企业数据管道的关键“可观察”步骤来使您的数据完全可观察。
当然,你的数据仓库作为“真实的单一来源”应该在任何数据可观察性框架的中心。然而,不应该就此止步。这就是现代数据堆栈概念非常强大的地方,因为它支持碎片化,同时允许使用代码和元数据记录流程的每个步骤。这就是为什么我认为贯穿整个数据管道的广泛的数据谱系是任何数据可观察性工具的一个基本特征。
像任何新事物一样,这一类别很吸引人,有很大的创新空间。你知道他们说什么:预测未来的最好方法就是去创造它!

资料来源:Salma Bakouk,Sifflet
结论
过去几年对许多行业来说都充满了挑战。当公司被迫转向、缩小规模或创造新的收入来源时,数据驱动的决策成为生存的关键。
几十年来,我们不断听到组织希望成为数据驱动的;直到最近,我们才开始*证研究、实施和采用新技术以实现数据成熟的实际计划和工作。2021 年,数据和分析行业没有让人失望。
收集数据不再是一个挑战;将数据从源移动到存储,然后实际利用它进行运营分析,这是当今许多组织关注的焦点。虽然 ETL 并不是什么新东西,但进一步的性能增强和向 ELT 的转变允许进一步扩展,并支持更现代的分析用例。随着反向 ETL 越来越流行,操作分析变得简单了。
数据集成的发展也有利于进一步的数据和工具民主化,这仍然是大多数数据领导者的议程。
最后但同样重要的是,数据可观测性作为一个类别在 2021 年获得了巨大的动力;我们*证了它成为任何现代数据堆栈(或者更确切地说是堆栈顶部)的重要组成部分,并将继续增长,为 2022 年及以后数据驱动决策的采用做出贡献。
声明:我是 Sifflet 的首席执行官和联合创始人。
TRIC —基于变压器的相对图像字幕
原文:https://towardsdatascience.com/tric-transformer-based-relative-image-captioning-d0edac40e5df?source=collection_archive---------17-----------------------
给我两件连衣裙,TRIC 会告诉你它们之间的区别👗 👚
这篇博文描述了 TRIC 模型——一个相对图像字幕任务的架构,它是我硕士论文的一部分。下面你可以找到这篇文章将要回答的问题列表:
- 什么是相对图像字幕,它与图像字幕有什么不同,它可以用来做什么?
- 解决这个任务的原始方法是什么?
- 如何采用变压器架构作为相关图像字幕问题的解决方案?
- 训练这样一个系统的主要挑战是什么?
在开始阅读这篇文章之前,你应该先温*一下以下话题:
- CNN
- RNNs
- 图像字幕
- 伯特
- 变压器架构
我的论文以非常简洁的方式描述了所有这些,所以我强烈推荐——你可以在下面找到链接。但是,如果你想检查他们从其他来源也包括在内。对于上面列出的每个主题,我都附上了一个链接,指向我个人最喜欢的关于这个特定主题的资源。
这个项目的代码库可以在这里找到代码报告
和完整的论文可以在这里找到论文
介绍
这个月早些时候,我在华沙技术大学对我的计算机科学硕士论文进行了答辩。我的专业是人工智能,所以我很自然地在深度学*领域写作。当我开始深度学*时,有一项任务最吸引我的注意力——图像字幕。最初,这个模型能够生成描述图像内容的标题,这似乎有点不可思议。然后,我当然会更深入地探究它到底是如何工作的——仍然很神奇,但是魔力消失了。
我个人的目标是选择一个主题,这个主题可以为研究一个已经研究过的(在某种程度上)问题提供一些新的想法/方法。此外,我希望它以某种方式连接到图像字幕。因此,我选择了相对图像字幕。
什么是相对图像字幕,它与图像字幕有什么不同,它可以用来做什么?
相对图像字幕(Relative Image Captioning,RIC)任务是图像字幕的变体,由 IBM 研究人员于 2018 年建立(来源)。目标是生成描述目标图像和候选图像相对于目标图像的相对差异的标题。

相对字幕/用户建模,来源
查看上面的图像,可以看到模型生成了一个描述两件衬衫之间相对差异的标题-底部的是目标图像,顶部的是候选图像。与图像字幕相反,RIC 接收两个图像作为输入。在生成字幕时,模型不仅要捕捉这两幅图像的内容,还要能够告诉我们它们之间相对于目标图像的差异。
好吧,但是我们为什么需要这样一个模型呢?
答案与基于对话的检索直接相关。

几轮基于对话的检索聊天机器人,来源
基于对话的检索系统旨在通过对话与用户交流,并根据其话轮检索所需信息。在上图中,我们可以看到一个为时尚检索而设计的系统的例子。这个特定系统的目标是减轻购物助手的负担——想象一下,你可以与机器人聊天,简单地描述你正在寻找的东西,而不是浏览数百个页面,所有页面都有不同的过滤器。这个想法很好,但任务也很复杂。
为了训练这样一个系统,人们需要获得大量由人类进行的样本对话。收集这样数据集将会非常昂贵和耗时。IBM 的研究人员没有这样做,而是提出了在对话循环中充当用户的 RIC 模型(论文)。
那么最初解决这个问题的方法是什么呢?
解决这个问题的第一种方法是采用两种最流行的图像字幕模型:显示并讲述、显示出席和讲述。简而言之,该模型遵循编码器-解码器架构。
作为编码器,我们有某种 CNN,用于将图像信息编码为特征向量 X_target 和 X_candidate。对于两个图像有一个编码器,并且它独立地处理它们。
解码器是某种循环网络,所以它可以是香草 RNN,LSTM,GRU 等。在编码器和解码器之间,有一种连接两个输入图像的特征向量的方法——在原始作品中,这是一种元素方面的差异,但任何其他方法也类似地工作(连接、加法、乘法等)。).
下面你可以看到 RIC 的作者提出的架构的可视化。

相对图像字幕的原始方法,来源
从上到下。第一种遵循上述编码器-解码器架构。第二个是将关于衣服属性的编码信息添加到图像的表示中(那些是纹理、织物、形状、部分和风格)。第三个与第二个相同,但增加了关注机制,如展示出席和讲述模式。
当我了解到这种方法时,我认为可以改进这种模式的一个方法是在 RNN 上使用 Transformer。一般来说,这样做有两个主要原因(如果你想更好地理解这个话题,我推荐这个链接):
- rnn 是顺序的,当变压器完全可并行化时不能并行化,因此 GPU 的能力可以在这里得到充分利用->更快的训练。
- 变形金刚能够处理长距离依赖,因为它们利用自我注意机制将句子作为一个整体来处理。rnn 正在一个接一个地做这件事。
在与我的导师快速交谈后,我们得出了一个值得一试的结论,因此我为我的硕士论文提出了两个精确的目标:
- 针对相关图像字幕问题,提出、实施、培训和分析基于变压器的架构的性能。
- 确定关于训练相关图像字幕的关键挑战,并指出用户建模的进一步研究方向。
如何采用变压器架构作为相关图像字幕问题的解决方案?

基于 Transformer 的相对图像字幕模型的架构(图来自我的硕士论文)。
上图展示了 TRIC(基于变压器的相对图像字幕)的架构,它是我硕士论文的一部分。它采用变压器和伯特嵌入相关的图像字幕任务。
让我们从底部的两个图像开始。首先,通过预训练的 ResNet101 处理两幅图像,以产生大小为 196x768 的特征图 F1 和 F2 。然后这些表示被组合(通过逐元素乘法)成一个称为 F = F1 * F2 的表示。 F 被输入变压器相关图像编码器,该编码器是变压器架构的一部分。它接受 196 个向量,每个向量的大小为 768,因此输出 FE 的大小也是 196x768。 FE 是变压器多模式解码器(TMD)的输入之一。
另一个是相对字幕的表示。为了获得它,需要通过 BERT 模型处理相对字幕,并建立用于提取这种嵌入的策略。这是因为 BERT 为每个令牌生成了多个表示—每层一个表示。我使用了 12 层 BERT,所以有 12 个向量代表字幕中的每个标记。我采用了对每个令牌的最后 4 个向量求和的策略,这是基于 BERT 作者所做的各种实验。有 n 个向量,每个向量的大小为 768(其中 n 是字幕的长度,768 是 BERT 的隐藏尺寸),必须添加关于字幕内记号位置的信息。这是因为 Transformer 并行处理所有令牌,因此不像顺序方法那样有关于位置的自然信息。位置编码层是直接复制粘贴从注意是你所需要的论文所以它是基于正弦和余弦函数(不像在其他方法中学*)。带有位置信息的字幕嵌入被传递到 TMD 中。
在 TMD 中我们有两个输入: FE 和**字幕的嵌入。**这是模型中结合文本和视觉信息的部分,因此被称为多模态。TMD 是变压器架构的解码器部分。最后,TMD 的输出通过线性层,然后是 Softmax,它为正在生成的令牌生成概率分布。
如果你对这个模型的细节感兴趣,你可以查看我的论文和代码库:
- 论文
- 代码回购
好,这就是模型架构。除此之外,我承诺在训练这样的系统时会对主要的挑战有一些*解。
训练这样一个系统的主要挑战是什么?
下面你可以看到我在培训 RIC 模型时发现的一系列挑战。现在,我将只列出它们——而且,每一点都将被详述。
- 培训费用
- 区分目标和候选图像的问题。
- 出现正确评估指标的问题。
- 字幕的表示。
培训成本。训练基于变形金刚的模型并不便宜。为了利用并行化,必须利用 GPU 计算的能力。一般来说,你有两个选择:拥有强大的 GPU 或者使用云解决方案外包它们。我个人使用了第二种选择,采用谷歌云*台解决方案。下面你可以看到在 1000 兹免费 GCP 信用范围内我能得到的最好模型的损失函数。

超过 150 个历元的训练和验证损失(图来自我的硕士论文)。
正如你所看到的,我能够使模型适应火车场景,但仅此而已。验证集上的性能非常弱。由于缺乏免费信用,我无法将正则化添加到模型中,并进一步改善验证集的损失。然而,在训练这样一个系统时,我能够识别关键的挑战。
区分目标和候选图像的问题。

图来自我的硕士论文。
我能够捕捉到的一个问题是模型不能区分候选图像和目标图像。如上图所示,模型能够生成有意义的标题,但是关系的方向是错误的。该模型正在生成一个描述候选图像相对于目标图像的标题,而不是像它所设想的那样反过来。这可能是由于在训练期间,仅向图像编码器提供图像的联合表示。这是由训练期间使用的有限 GPU 资源决定的。未来的研究方向之一可能是研究表示两个独立图像的方法,同时强调它们之间的相对差异的方向——目标图像和候选图像相对于目标图像的差异。
出现正确评估指标的问题。 BLEU metric 最初是为了自动评估机器翻译任务而发明的,用于评估 origin RIC 模型。由于表现不佳,作者决定与一组评估者一起测试字幕模型,表明 BLEU 指标不能完全展示模型的能力。在 TRIC 模型评估中观察到类似的问题,当生成的标题在语义上是正确的,但是模型使用了不同于真实标题中呈现的词。

图来自我的硕士论文。
RIC 架构应该用基于语义的度量来评估,以便完全掌握模型的能力。然而,语义度量的使用进一步增加了训练整个架构的计算成本。人们可以尝试将基于语义的评估结合到 RIC 任务中,同时关注这种评估的合理计算成本。
**文字说明的表述。**在 TRIC 模型中,令牌的嵌入基于 BERT 语言模型,在大型文本语料库(图书语料库(800M 单词)和英语维基百科(2500M 单词))上进行训练。虽然这是一个很好的相对字幕的语境化嵌入的起点,但人们可以在时尚相关的语料库上预先训练或微调这样的语言模型。因此,可以更好地表示特定于领域的单词,例如,像“v 形领”、“灰白色”和其他用破折号分隔的表达可以基于适当的上下文获得更有意义的嵌入。我相信在这个领域的进一步研究可以真正推动 RIC 模型产生类似人类的相对字幕,从而为更高级的基于对话的图像检索系统打下坚实的基础。
结论
我相信基于对话的检索系统是电子商务的未来。虽然电子商务公司努力不断提高客户在线购物的质量,但他们的搜索引擎仍然主要基于关键字或过滤器,对用户搜索选项施加了许多限制。这些限制可以通过聊天机器人形式的对话界面来解除。这样的解决方案可以提供与机器人进行对话的能力,这将减轻与购物助理的现场对话。RIC 模型在训练这样一个系统中起着至关重要的作用,能够研究这个主题是非常令人兴奋的。
此外,我很高兴写这篇博客,因为这是我的第一篇博客,我一直想这样做。如果你对这个模型有任何疑问(或其他),请随时通过 LinkedIn 或评论联系我。
参考
[1]郭晓晓、、于成、史蒂文·雷尼和罗格里奥·施密特·费里斯。基于对话的交互式图像检索。CoRR,abs/1805.00145,2018。
[2]郭晓晓、、、高、史蒂文·雷尼和罗格里奥·施密特·费里斯。时尚智商:通过自然语言反馈检索图像的新数据集。CoRR,abs/1905.12794,2019。
[3] Jacob Devlin、张明蔚、Kenton Lee 和 Kristina Toutanova。伯特:语言理解深度双向转换器的预训练。CoRR,abs/1810.04805,2018。
[4] Ashish Vaswani、Noam Shazeer、Niki Parmar、Jakob Uszkoreit、Llion Jones、Aidan N. Gomez、Lukasz Kaiser 和 Illia Polosukhin。你所需要的只是注意力。更正,abs/1706.03762,2017。
[5] Oriol Vinyals、Alexander Toshev、Samy Bengio 和 Dumitru Erhan。展示和讲述:一个神经图像字幕生成器。更正,abs/1411.4555,2014 年
[6]凯尔文·徐、吉米·巴、瑞安·基罗斯、赵京贤、亚伦·库维尔、鲁斯兰·萨拉胡季诺夫、理查德·泽梅尔和约舒阿·本吉奥。展示、参与和讲述:视觉注意的神经图像字幕生成。更正,abs/1502.03044,2015 年。
高级 SQL 查询技巧
原文:https://towardsdatascience.com/tricks-for-advanced-sql-querying-a09766552155?source=collection_archive---------14-----------------------
利用 SQL 提供的所有优势可以改善和增强您的数据。

马库斯·斯皮斯克在 Unsplash 上的照片
我在零售领域的数据科学团队工作时使用的最有价值的技能之一是 SQL。遗留关系数据库系统和混合/云数据管理解决方案的用户可以使用 SQL 灵活地访问业务数据,并以创造性和创新性的方式转换或显示数据;参*参考资料中的精彩评论。对业务数据库结构的透彻理解,结合允许上游数据转换和聚合的巧妙解决方案,对于高效和可靠的 ETL 至关重要。下面是我在构建复杂管道时学到的一些技巧,这些技巧让我的工作变得更加简单和有趣。
1) 计算滚动*均值&通过将表格连接到自身来附加历史数据
处理时间序列数据时,计算观测值的滚动*均值或附加历史值会很有帮助。假设我想获得一家公司每天销售的小部件数量。我可能想包括一个 7 天的移动*均线,或者附上上周的工作日小部件销售,看看上周的业务表现如何。我可以通过将数据集连接到自身上,并使用日期列上的操作来选择单个值或观察值范围。
首先,让我们从使用 Db2 库中名为 WIDGET_ORDER_HISTORY 的表中的以下代码获取按天销售的小部件开始:
select t1.date
, sum(t1.widgets_sold) as total_widgets_sold
from db2.widget_order_history t1
where t1.date between ‘2021–04–05’ and ‘2021–05–01’
group by t1.date
如果我们想在表上的另一个变量上添加任何过滤条件,比如特定的商店,我们可以添加一个简单的 WHERE 语句:
select t1.date
, sum(t1.widgets_sold) as total_widgets_sold
from db2.widget_order_history t1
where (t1.date between ‘2021–04–05’ and ‘2021–05–01’)
and t1.store = 1234
group by t1.date
位于其他表上的其他条件(即 STORE_DATA)需要额外的内部连接:
select t1.date
, sum(t1.widgets_sold) as total_widgets_sold
from db2.widget_order_history t1
inner join (
select store
from db2.store_data
where state = ‘NY’
) t2
on t1.store = t2.store
where t1.date between ‘2021–04–05’ and ‘2021–05–01’
group by t1.date

示例时间序列数据,由提供的代码生成。作者图片
现在,如果我想附加 4/25/21–5/1/21 这一周的 7 天滚动*均值,我可以通过将表连接到自身来实现,并利用在 SUM()函数中插入 CASE()语句的优势。当您只想满足表中的特定标准时,可以使用这种技术来使用分组函数(即 SUM()、COUNT()、MAX())。它只会对符合 WHEN 子句中包含的规则的值求和。在下面的示例中,如果表 B 中的值在表 A 中当前观察日期的前 7 天内,我们可以将这些销售额相加,然后除以 7,得到表 A 中每行的滚动周*均值:
select a.date
, a.total_widgets_sold
, sum(
case when (b.date between a.date-7 and a.date-1)
then b.total_widgets_sold
else 0
end)/7 as seven_day_avg
from (
select date
, sum(widgets_sold) as total_widgets_sold
from db2.widget_order_history
where date between ‘2021–04–25’ and ‘2021–05–01’
group by date
) a
left join (
select date
, sum(widgets_sold) as total_widgets_sold
from db2.widget_order_history
where date between ‘2021–04–05’ and ‘2021–05–01’
group by date
) b
on a.date = b.date
group by a.date
, a.total_widgets_sold
order by a.date

2021 日历年第 17 周的小部件销售额,采用 7 天滚动*均值。作者图片
如果您想为每个观察值附加一个历史值,那么您可以避免聚合,只需根据指定间隔数之外的日期连接表。下面的示例将表 A 中的表 B 联接起来,通过回溯 7 天来获取前一个工作日的小部件销售额:
select a.date
, a.total_widgets_sold
, b.total_widgets_sold as prev_wkday_sales
from (
select date
, sum(widgets_sold) as total_widgets_sold
from db2.widget_order_history
where date between ‘2021–04–25’ and ‘2021–05–01’
group by date
) a
left join (
select date
, sum(widgets_sold) as total_widgets_sold
from db2.widget_order_history
where date between ‘2021–04–04’ and ‘2021–05–01’
group by date
) b
on a.date -7 = b.date

2021 日历年第 17 周的小部件销售额,包括上周的工作日小部件销售额。作者图片
将表联接到自身是一种非常灵活的方式,可以将汇总列和计算列添加到数据集中。创造性地将 SUM()和 COUNT()等分组函数与 CASE()语句结合使用,为功能工程、分析报告和各种其他用例带来了巨大的机会。
实际上,如果一个查询通过子查询连接到自身,并且非常大,那么运行时间可能会很长。解决这个问题的一种方法是使用一个临时表来保存问题特定标准的初步结果;例如,在 SAS 的工作库中创建一个整个时间范围内的小部件销售表,并多次查询该表。高效的代码结构,如使用索引,也可以提高效率;参*参考资料中的一些想法。
2) 使用 CASE 语句处理复杂逻辑
CASE 语句的语法不同于数据科学中其他常用编程语言的逻辑。通过使用伪代码对逻辑规则进行深思熟虑的设计可以帮助避免由于不正确/不一致的规则而导致的错误。理解如何在 SQL 中编码嵌套逻辑对于释放数据的潜力至关重要。
假设有一个购物者表,其中包含大量特征,如年龄、家庭所在州和给定时间范围内的销售额。一项有针对性的营销活动正被用来试图增加普通购物者的销售额(营销已经将普通购物者定义为花费在 100-200 美元之间的人)。一旦被识别,Z 世代/千禧一代的购物者将收到一张数字优惠券,所有其他购物者将收到一张打印优惠券,根据他们居住的州而有所不同。为了简单起*,购物者只居住在三个州。
下面是如何用 R 和 SQL 编码这个逻辑:
## Example of Nested Logic in Rif(shoppers$sales<=0){ print("Error: Negative/No Sales")}
else if(shoppers&sales<=100){ print("Shopper has below-average sales.")}
else if(shoppers&sales<=200){
if(shopper$age<41){print("Shopper has average sales and is Gen Z/Millennial.")}
else{
if(shopper$state=='NJ'){print("Shopper has average sales, is Gen X/Boomer/Greatest Gen., and lives in New Jersey.")}
else if(shopper$state=='NY'){print("Shopper has average sales, is Gen X/Boomer/Greatest Gen., and lives in New York.")
else(shopper$state=='CT'){print("Shopper has average sales, is Gen X/Boomer/Greatest Gen., and lives in Connecticut.")}
}
}
else{print("Shopper has above-average sales.")}*Example of nested logic in SQL. No need to actually nest statements!;, case when sales < 0
then 'Error: Negative/No Sales.'
when sales <=100
then 'Shopper has below-average sales.'
when sales <=200 and age <41
then 'Shopper has average sales and is Gen Z/Millennial.'
when sales <=200 and state = 'NJ'
then 'Shopper has average sales, is Gen X/Boomer/Greatest Gen., and lives in New Jersey.'
when sales <=200 and state = 'NY'
then 'Shopper has average sales, is Gen X/Boomer/Greatest Gen., and lives in New York.'
when sales <=200 and state = 'CT'
then 'Shopper has average sales, is Gen X/Boomer/Greatest Gen., and lives in Connecticut.'
else 'Shopper has above-average sales.'
end as shopper_classification
周到地使用 CASE 语句将允许您构建复杂业务逻辑的任意组合。然而,SQL 逻辑需要的思维方式与其他编程语言略有不同。结合分组功能,这些工具可以为数据科学家提供竞争优势,帮助他们获取和转换用于功能工程、商业智能、分析报告等的数据源!
资源
2021 年企业 DBMS 前景的大分解:
https://www.eweek.com/database/top-vendors-of-database-management-software-for-2021/
一些有用的 SQL 查询优化技术的总结:
https://www.sqlshack.com/query-optimization-techniques-in-sql-server-tips-and-tricks/
Python 中的三角函数:完全指南
原文:https://towardsdatascience.com/trigonometric-functions-in-python-complete-guide-62d80f0d136a?source=collection_archive---------29-----------------------
在本文中,我们将探索 Python 中的三角函数

作者图片
目录
- 介绍
- 正弦函数
- 反正弦函数
- 余弦函数
- 反余弦函数
- 正切函数
- 反正切函数
- 结论
介绍
由于本教程的重点是三角函数,我们需要一些重要的定义来更好地理解每个函数。
三角法
三角学是数学的一个分支,研究三角形的角度和边长之间的关系。
三角学中用到的三个主要三角函数是:正弦、余弦、正切,都是以直角三角形为基础的。
直角三角形
什么是直角三角形?是一个直角(或 90)的三角形)。
请参*下面的示例:

作者图片
这里角 C 是直角(角 C = 90),现在形成直角三角形 ABC。
此外,我们应该知道直角三角形相对于某个选定的角θ的边的名称。
*下文:

作者图片
- 相邻 —总是与角θ相邻的边,也形成直角(90°)。
- 对面 —角度θ的对面。
- 斜边 —直角(90°)的对边,也是直角三角形中最长的边。
弧度
几何学中另一个重要的概念是弧度。弧度是圆心的角度单位,它是由圆的半径与半径相等的圆弧连接而成的。
正式的定义听起来非常复杂,很难理解,所以直观地理解这个定义要容易得多。
*下文:

作者图片
逐步解释:
- 从点 O 开始,画一条水*线到点 P,这样就产生了长度为半径(r)的线段 OP。
- 从点 P 创建一条线段 PT,它垂直于线段 OP(角度= 90°),并且与线段 OP 的长度相等,等于半径(r)。长度应该相等:OP=PT。
- 接下来,想象你开始向左弯曲线段 TP,直到它适合圆周。一旦你这样做了,你就有了线段 TP 的投影,这是一个弧 VP。你应该有相等的长度:TP=VP。
在这些步骤之后,我们已经创建了一个角度(角度 VOP),我们称之为 1 弧度:

作者图片
这个角度正好是 1 弧度,或者也可以用度数来计算,如下所示:

作者图片
或者,我们可以用弧度来计算度数:

作者图片
正弦函数
正弦函数是主要的三角函数之一。
正弦函数解释
角θ的正弦函数是角θ的对边与斜边之比:

作者图片
它也经常被称为 SOH:正弦与斜边相反。

作者图片
还有一个表格提供了标准角度的正弦值:

作者图片
正弦函数计算示例
我们有一个直角三角形 ABC,其中 AB = 20cm,角 A = 30,角 C = 90,如下图所示。我们需要找到公元前的长度。

作者图片
从上一节的表格中,我们知道 sin 30 = 1/2,我们可以用它来解决示例中的问题:

作者图片
在这个例子中,使用 sin 函数,我们能够找到 BC 边的长度,它等于 10 cm。
Python 中的正弦函数 sin()
在这一节中,我们将尝试使用 Python 来解决上面的例子。
为了在 Python 中使用正弦函数 sin() ,我们需要从数学库(内置)中导入它。
让我们从导入所需的函数开始:
接下来,将度数转换为弧度:
并计算比例(注意要四舍五入到 2 位小数):
您应该得到:
0.5
这与我们在上一节中看到的 sin 30 比率完全相同。我们通过使用 Python 中的三角函数发现了相同的结果。
其余的计算是一样的,你将得到等于 10 厘米的答案。
反正弦函数
反正弦函数是反三角函数之一,通常称为反正弦。
反正弦函数解释
三角形与角θ相对的边与斜边之比的反正弦函数是角θ。
听起来没有实际看起来那么直观。
回想一下,正弦函数取角度θ,给出{对边}/{斜边}的比值。
现在,反正弦函数取{对边}/{斜边}之比,给出角度θ:

作者图片

作者图片
反正弦函数计算示例
我们有一个直角三角形 ABC,其中 AB = 20cm 厘米,BC = 10 厘米,角度 C = 90 度,如下图所示。我们需要找到角度 a。

作者图片
首先,我们会找到{对边}/{斜边}的比值:

作者图片
当我们知道比率时,我们可以使用任何计算器和反正弦函数很容易地找到角度θ。
您应该得到:

作者图片
Python 中的反正弦函数 asin()
在这一节中,我们将尝试使用 Python 来解决上面的例子。
为了在 Python 中使用反正弦 asin() 函数,我们需要从数学库(内置)中导入它。
让我们从导入所需的函数开始:
接下来,求比值等于 1/2 的角的弧度:
您应该得到:
0.5235987755982989
然后最后将弧度转换为度数(并四舍五入):
您应该得到:
30
我们通过使用 Python 中的三角函数,发现 1/2 比的反正弦是角度等于 30。
余弦函数
正弦函数是第二常*的三角函数。
余弦函数解释
角θ的余弦函数是角θ的邻边与斜边之比:

作者图片
它也经常被称为 CAH:余弦值与斜边相邻。

作者图片
还有一个表格提供了标准角度的余弦值:

作者图片
余弦函数计算示例
我们有一个直角三角形 ABC,其中 AB = 20cm,角 B = 60,角 C = 90,如下图所示。我们需要找到公元前的长度。

作者图片
从上一节的表格中,我们知道 cos 60 = 1/2,我们可以用它来解决示例中的问题:

作者图片
在此示例中,使用 cos 函数,我们能够找到边长 BC 等于 10 cm 的长度。
Python 中的余弦函数 cos()
在这一节中,我们将尝试使用 Python 来解决上面的例子。
为了在 Python 中使用余弦函数 cos() ,我们需要从数学库(内置)中导入它。
让我们从导入所需的函数开始:
接下来,将度数转换为弧度:
并计算比例(注意要四舍五入到 2 位小数):
您应该得到:
0.5
这与我们在上一节中看到的 cos 60 的比率完全相同。我们通过使用 Python 中的三角函数发现了相同的结果。
其余的计算是一样的,你将得到等于 10 厘米的答案。
反余弦函数
反余弦函数是反三角函数之一,通常称为反余弦函数。
反余弦函数解释
三角形与角θ相邻的边与斜边之比的反余弦函数是角θ。
回想一下,余弦函数取角度θ,给出{邻边}/{斜边}的比值。
现在,反余弦函数取{相邻} \ {斜边}的比值,给出角度θ:

作者图片

作者图片
反余弦函数计算示例
我们有一个直角三角形 ABC,其中 AB = 20cm 厘米,BC = 10 厘米,角度 C = 90 度,如下图所示。我们需要找到角度 b。

作者图片
首先,我们将找到{邻边}/{斜边}的比值:

作者图片
当我们知道比率时,我们可以使用任何计算器和 arccos 函数轻松找到角度θ。
您应该得到:

作者图片
Python 中的反余弦函数 acos()
在这一节中,我们将尝试使用 Python 来解决上面的例子。
为了在 Python 中使用反正弦 acos() 函数,我们需要从数学库(内置)中导入它。
让我们从导入所需的函数开始:
接下来,求比值等于 1/2 的角的弧度:
您应该得到:
1.0471975511965979
然后最后将弧度转换为度数(并四舍五入):
您应该得到:
60.0
我们通过使用 Python 中的三角函数,发现 1/2 比值的反余弦是角度等于 60。
正切函数
正切函数是第三种流行的三角函数。
正切函数解释
角度θ的正切函数是三角形中与角度θ相对的边与三角形中与角度θ相邻的边之比:

作者图片
它也经常被称为 TOA:正切值与相邻值相反。

作者图片
还有一个表格提供了标准角度的正切值:

作者图片
正切函数计算示例
我们有一个直角三角形 ABC,其中 BC = 10cm,角 A = 30,角 C = 90,如下图所示。我们需要找到 AC 的长度。

作者图片
从上一节的表中,我们知道 tan 30 = {1}/{sqrt{3}},我们可以用它来解决示例中的问题:

作者图片
在本例中,使用 tan 函数,我们能够找到 BC 边的长度,它等于 17.32 厘米。
Python 中的正切函数 tan()
在这一节中,我们将尝试使用 Python 来解决上面的例子。
为了在 Python 中使用正切函数 tan() ,我们需要从数学库(内置)中导入它。
让我们从导入所需的函数开始:
接下来,将度数转换为弧度:
并计算比例(注意要四舍五入到 2 位小数):
您应该得到:
0.58
在这种情况下,该比率为 0.58,约等于{1}/{sqrt{3}},与我们在上一节中看到的 tan 30 的比率完全相同。我们通过使用 Python 中的三角函数发现了相同的结果。
其余的计算将是相同的,您将得到等于 17.24 厘米的答案(而未经四舍五入的计算结果将是 17.32 厘米)。
反正切函数
反正切函数是反三角函数之一,通常称为反正切函数。
反正切函数解释
三角形中与角θ相对的边与角θ相邻的边之比的反正切函数。
回想一下,正切函数取角度θ,给出{对面}/{相邻}的比值。
现在,反正切函数取{对立}/{相邻}的比值,给出角度θ:

作者图片

作者图片
反正切函数计算示例
我们有一个直角三角形 ABC,其中 BC = 10 cm,AC = 17.32 cm,角 C = 90 如下图所示。我们需要找到角度 b。

作者图片
首先,我们会找到{对立}/{相邻}的比率:

作者图片
当我们知道比率时,我们可以使用任何计算器和反正切函数很容易地找到角度θ。
您应该得到:

作者图片
Python 中的反正切函数 atan()
在这一节中,我们将尝试使用 Python 来解决上面的例子。
为了在 Python 中使用反正弦函数,我们需要从数学库(内置的)中导入它。
让我们从导入所需的函数开始:
接下来,求比值等于 0.58 的角的弧度:
您应该得到:
0.5255837935516101
然后最后将弧度转换为度数(并四舍五入):
您应该得到:
30.11
通过使用 Python 中的三角函数,我们发现 0.58 比率的反余弦是等于 30.11 的角度,如果我们没有将边 AC 的长度舍入到 17.32 cm,则该角度大约等于 30。
结论
在本文中,我们将使用来自数学库中的函数,重点介绍 Python 中的三角函数。它包括正弦、余弦、正切、反正弦、反余弦和反正切。
如果你有任何问题或对编辑有任何建议,请随时在下面留下评论,并查看更多我的统计文章。
原载于 2021 年 12 月 29 日 https://pyshark.com*。*
AWS 上的普通比例 PyTorch
原文:https://towardsdatascience.com/trivially-scale-pytorch-on-aws-4cfde16e6d37?source=collection_archive---------22-----------------------
在 AWS 上运行 PyTorch 工作负载,无需更改代码

来源bestanimation.com(经许可)
PyTorch 是一个构建神经网络的惊人框架。很容易上手,也很快获得价值。但是对于实际的研究或生产用例,您的笔记本电脑或本地服务器就不行了。
在本教程中,我将向你展示如何在云上运行 ANY PyTorch 代码,而无需做任何代码更改。
模型
对于本教程,我将从 PyTorch 示例库中选择 dcgan。

这个文件夹有 3 个文件,main.py 和 requirements.txt。
这个模型是一个简单的深度卷积 GAN ,然而只要代码不崩溃,这个模型并不重要。
验证它不会在本地崩溃
第一步是验证它不会在本地崩溃。为此,我将把它克隆到我的本地机器上并运行它。
您现在应该会看到类似这样的内容:

在云上运行
为了在 AWS 上运行,我们将使用 Grid.ai ( 在这里创建一个免费帐户)。网格人工智能的免费层提供了许多功能,包括更便宜的 AWS 成本的现货定价。你仍然需要支付计算费用,但是价格和 AWS 一样。
现在安装网格并登录
现在用网格运行改变单词 python,按回车键!

Grid 将在 AWS 上运行代码!查看作业类型的状态

这个模型生成图像(毕竟是 GAN),我们来看看
(没错,Grid 制造了双关的名字)。

还有很多,探索用户界面吧!
在 GPU 上运行
在单 CPU 机器上运行…嗯,没什么大不了的。我们用同样的努力在(2x) 4 个 GPU 机器上运行怎么样?
这个 GAN 脚本实际上可以在 2 个 GPU 上运行…为了实现这一点,让我们添加脚本标志(这里的这些参数)。

现在我们需要告诉 grid 在 2 个 GPU 上运行该模型(我选择的是 4 个 v100s 的机器)。

但是等等……机器有 4 个 GPU,为什么不用 4 个 GPU?嗯,我实际上想用不同的学*率来尝试相同的模型…所以我将要求 grid 使用我想尝试的学*率(0.001、0.002、0.01、0.02)给我这个模型的 4 个版本

grid 有大量的特殊语法来简化扫描。网格状态显示了我的 4 个实验。

现在我的紧张的 anaconda 正在运行这个 GAN 的 4 个版本,每个版本在 2 个 GPU 上!
在引擎盖下,grid 启动了 2 台机器,并自动分发模型,如下所示:

可中断机器
云提供商提供节省成本的方法。在 AWS 上,您可以使用 use_spot 标志为您的计算支付高达 90%的折扣。

但是不利的一面是,您的机器可能会在任何时候被终止…然而,对于许多工作负载来说,这是可以的。您可以随时从网格中获取模型检查点,并再次运行模型以继续训练
完整的命令是:
就是这样!
网格不需要任何东西就可以扩展。对于具有大规模数据集和多节点模型的更严重的工作负载,grid 也已经覆盖了!
快乐训练!
Dask GroupBy 聚合性能故障排除
原文:https://towardsdatascience.com/troubleshooting-dask-groupby-aggregation-performance-1c39599598c1?source=collection_archive---------27-----------------------
如何解决 Dask GroupBy 聚合的性能问题?对算法的深入研究。

示例分组任务图—Julia Signell的 courtsey
在 Saturn Cloud,我们管理着一个数据科学*台,该*台提供 Jupyter 笔记本、Dask 集群以及部署模型、仪表盘和作业的方法。因此,我们经常帮助客户排除 Dask 操作故障。GroupBys 的问题经常出现。
Dask 数据框架对于交互式探索大型数据集来说是惊人的。然而,在大型数据集上使用它们可能有点棘手。您可能已经在尝试进行分组时遇到了一个KilledWorker异常。如果你还没有,你很快就会了!
本文的目标是为您提供一组选项,供您在 GroupBy 失败时尝试。首先,我们将深入了解数据帧分组聚合是如何实现的。这对于理解如何绕过你遇到的任何障碍是必要的。
Dask GroupBy 聚合
Dask GroupBy 聚合使用apply_concat_apply()方法,该方法对dask.DataFrame应用 3 个函数,一个chunk()、combine()和一个aggregate()函数。这是一个非常强大的范例,因为它使您能够通过提供这些函数来构建自己的自定义聚合。我们将在示例中引用这些函数。
- chunk :该方法应用于 Dask 数据帧的每个分区。
- 合并:来自
chunk()步骤的输出被连接,然后与combine()合并在一起。 - 聚合:来自
combine()步骤的输出被连接,然后用aggregate()聚合。这是最后一步。经过这个转换,你的结果就完成了。
Dask GroupBy 聚合:最简单的例子
在这个例子中,我们将通过一个带有默认参数的 Dask GroupBy 来展示算法是如何工作的。我们使用一个虚拟数据集,它被分成 4 个分区。我们已经为score选择了具有独立小数位的数值,以便在汇总数据时更加明显。
此示例应用以下转换:
Dask GroupBy 聚合将算法分为chunk()、combine()和aggregate()步骤。在这种情况下(最简单的一种),我们只使用chunk()和aggregate()步骤。这种特殊的聚集是优雅的,因为这些步骤中的每一个都以相同的方式实现,通过按动物分组并对分数求和(df.groupby('animal')['zscore'].sum())。通过对分区求和,然后对这些和求和,我们可以计算出所需的结果。其他算法如var()在不同的阶段需要不同的操作。该图展示了相关的操作,并向我们展示了每一步的数据情况。

我们的样本数据集被分成 4 个分区。步骤 1 将chunk()函数应用于每个分区。这是一个重要的步骤,因为它的输出是一个缩减,比原始分区小得多。步骤 2 将步骤 1 的输出连接成一个数据帧,然后对结果应用aggregate()函数。
问题
简单的情况是返回一个分区,其中包含整个结果。如果你的GroupBy产生一个小的数据帧,这个方法很好。如果您的GroupBy导致一个大的数据帧(如果您有大量的组),您将耗尽内存,这通常在KilledWorker异常中表现出来。
处理记忆:分裂
Dask 提供两个参数split_out和split_every来控制数据流。split_out控制生成的分区数量。如果我们设置split_out=4,group by 将产生 4 个分区,而不是 1 个。我们稍后会谈到split_every。让我们用split_out=4重做前面的例子。

第 1 步与上例相同。步骤 1 (应用chunk()函数)的输出是每个分区 1 个数据帧。步骤 2 通过散列分组将这些数据帧中的每一个分成split_out=4个数据帧。查看图表,您会看到每个分区的第 n 个数据帧中有相同的动物。这种一致性是哈希的目标。我们将每个组称为一个分片(分片 1 包含每个分区的第一个数据帧,分片 2 包含每个分区的第二个数据帧,依此类推)。步骤 3 将组成每个碎片的所有数据帧连接起来(同样使用这种散列法),这样来自相同动物的数据就会出现在相同的数据帧中。然后应用aggregate()功能。结果现在是一个由split_out=4分区组成的 Dask 数据帧。
高级选项:分割 _ 每
在前面的示例中,步骤 3, Dask 为每个分区分片串接数据。默认情况下,Dask 会一次为多达 8 个分区分片连接数据。因为我们的数据集只有 4 个分区,所以所有的数据都是一次性处理的。让我们用split_every=2重新运行前面的例子。第二步之前的一切都是一样的。

使用split_every=2,我们一次连接两个数据帧,然后用步骤 3 中的combine()函数组合它们,而不是连接来自单个碎片的所有数据帧(在我们的例子中,每个碎片有 4 个数据帧)。步骤 4 将这些结果连接起来,然后调用aggregate()。用combine()最后用aggregate()的约简是一个树约简。因为我们只有 4 个分区,所以我们可以在 1 个combine()步骤和 1 个aggregate()步骤中完成这个操作。然而,如果我们有 8 个分区,将有 2 个combine()步骤和 1 个aggregate()步骤。aggregate()永远是最后一步。
我们该怎么办
真的只有两件事可以做。我知道这可能看起来有点反高潮,考虑到我们刚刚经历的关于算法如何工作的长度解释,然而理解算法对于理解如何调整它是重要的。
调整拆分
split_out参数可以传递给聚合函数。
这一部分将有点近似和手动波动。最终,您需要对您的数据集进行实验,并找出哪些参数有效。这一节可能会为你提供一些如何思考这个问题的指导。
了解您的数据
我将有几个小组?希望您对数据有足够的了解,能够大致估计出结果中的组数。如果不是,你可能需要以某种方式计算它。举个例子,我有一个包含 5000 万动物的数据集。我获取数据的一个子集,执行计算,观察到我的结果有 500 万只动物,占用 500 mb 内存。500 万只动物是我在数据集中拥有的 5000 万只动物的 1/10,所以我的最终结果大约是 5GB。
分区大小
分区大小是一个不同的主题,这里不讨论。一般来说,您应该调整分区的大小,以便一个工作线程可以容纳多个分区,但是理想的分区大小取决于您的工作线程有多少内存。
假设我有 8GB 的工人。如果我的最终结果是 5GB,我可以将split_out设置为 5,这样每个 1GB 的结果都适合这个工人。然而,默认的split_every参数被设置为 8。如果每个分区都是 1GB,在最坏的情况下,我可能会连接 8GB——这将耗尽我的 8GB 工作人员。相反,我选择split_out为 25,这样每个分区都是 200MB。
现实不会这么精确。确切的内存使用将取决于您的数据如何在不同的机器之间布置,以及实际的 pandas 计算本身使用了多少内存。如果您的数据是按照 groupby 列排序的,那么您的内存使用量将接近理想值。如果您在每台机器上都有来自每个组的数据,那么您的内存使用将接近最坏的情况。但是这种方法可以作为选择split_out的粗略指南。
我不建议调split_every。调整单个参数要容易得多,默认值 8 类似于您希望 Dask workers 有多少额外的内存空间。
请改用 map_partitions
map_partitions()是 Dask 数据帧上的一个方法(它也用于其他 Dask 集合),将一个函数应用于 Dask 数据帧的所有分区,然后在这些结果上构建另一个 Dask 数据帧。
如果您的数据已经按照您希望分组的字段排序,那么使用map_partitions()是一个好的策略。在这个示例数据集中,如果我的数据已经按动物排序,并且我知道所有的猫都在一个分区中,所有的狗都在另一个分区中,那么我知道我不需要来自其他分区的数据来计算每种动物的统计数据。这意味着我可以取代
ddf**.**groupby**(**'animal'**)[**'scores'**].**sum**()**
随着
ddf**.**map_partitions**(lambda** x**:** x**.**groupby**(**'animal'**)[**'scores'**].**sum**()**
不要对你的数据进行排序
如果我的数据没有排序,我可以使用set_index()或shuffle进行排序。然后我可以申请map_partitions()。这可能不值得。groupby 聚合中的数据移动应该少于set_index()中的数据移动,因为第一步的chunk()操作会显著减少数据量。
不要使用 GroupBy 然后应用
map_partition是在数据已经排序的情况下,如何实现带有 Apply 的 Dask GroupBy。这意味着我可以将我的聚合写成
这可能比原来的例子慢得多,纯粹是因为 pandas groupby applys 比 groupby aggregations 慢得多。
结论
为了在集群上实现 GroupBy 聚合,Dask 做了很多工作。在大多数情况下,它开箱即用。如果没有,可以调优split_out让 Dask 产生更小的块。如果您的数据已经排序,您可以使用map_partitions()更有效地实现操作。实际的算法可能有点难以理解,但是理解它可以帮助您获得关于如何调整参数的直觉。
声明:我是土星云的 CTO。我们让您的团队轻松连接云资源。想用 Jupyter 和 Dask?部署模型、仪表板或作业?在笔记本电脑或 4 TB Jupyter 实例上工作?完全透明地了解谁在使用哪些云资源?我们做所有这些,甚至更多。
最初发布于https://www . Saturn cloud . io。
数据科学面试流程故障排除:什么会出错&你能做些什么!
原文:https://towardsdatascience.com/troubleshooting-data-science-interview-process-what-can-go-wrong-what-you-can-do-about-it-bd964be1813a?source=collection_archive---------26-----------------------

由谷仓图片在 Unsplash 上拍摄
招聘是一个非常低效的过程。通过认识到每一步可能出错的地方及其潜在原因,以及注意你可以控制的事情,提高你获得下一个职位的成功机会。
重要的是要注意,招聘过程是一个多步骤的过程,根据你在这个过程中的感觉,有一些策略可以帮助你进入下一个阶段。让我们回顾一下过程、过程中的障碍以及一些经过测试的解决方案。
- 当你的 LinkedIn 个人资料没有获得足够的浏览量时 使用正确的关键词是有机会的公司找到你的个人资料并了解你的唯一方法。如果你没有获得足够的浏览量,很有可能你没有使用正确的关键词。
**解决方案:**帮助公司找到你的个人资料(在 LinkedIn 的 5 亿多用户中),并通过确保你的个人资料中有与你希望人们找到你的职位相关的关键词,将你与合适的机会联系起来! - 当你的个人资料获得足够多的浏览量,但招聘人员没有联系你 一般来说,这并不是一件坏事:你不希望人们为每个与你的技能重叠最小的空缺职位联系你。不相信我?我第一次被招聘人员联系是在我完成研究生学业的时候,当时我想在加拿大的一家酒店找一份接待员的工作。当招聘人员查看你的个人资料,但他们很少联系你时,他们可能没有找到他们想要的经验类型,或者你可能看起来不适合这个职位。
**解决方案:**确保你的个人资料能很好地讲述一个令人信服的故事,并将你的经历与你希望获得的职位联系起来。如果你正在寻找一个技术性的角色,列出你过去与这个角色相关的技能和经验。如果你对网球或环游世界的兴趣与工作描述无关,就不要加入。如果你正在寻找高级或领导职位,确保你在简历中讲述的故事证明下一步是正确的。 - 当你在与招聘人员的介绍电话后被拒绝时!在这个阶段,你可能会被拒绝,因为招聘者可能很清楚他们在寻找什么,而你的个人资料与此不符;他们招聘的职位可能有非常具体的要求,而你可能达不到这些要求。或者仅仅是因为他们嗅到了你的简历和你在电话介绍中所说的不一致。请记住,招聘人员也需要建立和/或维护声誉,特别是当他们是为不同组织招聘的外部招聘人员时,他们需要格外挑剔,以确保他们的客户对他们的长期推荐感到满意。在这种情况下,我假设他们更喜欢假阴性而不是假阳性。
**解决方案:**准备好你的简历,它看起来如何,它能告诉你什么,让你走到这一步。从这一点开始,你需要对需要与人互动的过程有正确的心态,这样故事讲述就成了你最重要的资产。从这里开始,你将试着把你的故事卖给那些公司,同时那些公司也将试着把他们自己的故事卖给你。当双方都对对方的故事感兴趣时,就会取得进展。创造你的故事,并准备好与招聘人员分享:你的故事应该讲述你过去的经历,你的技能和你学到的东西,以及你为什么想离开现在的公司。你还需要对为什么你想在你面试的公司里得到一个职位有一个好的想法。这一阶段的重点不是技术部分,而是确保你的故事前后一致并且有意义。作为一条规则,永远不要说你工作的公司的坏话。你不是来复仇的,招聘人员也不是来纵容你的。要专业! - 当你技术评估后被拒绝!
一些公司可能希望以带回家的项目、在线评估或现场编码会议开始这一过程。虽然他们鼓励你不要花超过 3-4 个小时的时间在上面,但人们通常会花更长的时间在周末完成的项目上。
解决方案:许多人认为这个项目是免费工作,并反对它。另一方面,尤其是如果你正处于职业生涯的早期,我建议你花时间去迎接这些挑战。大多数情况下,这些问题都是精心设计的,用来测试你的技术能力,如果你加入那家公司,你可以从这些问题中学到很多关于你将从事的工作类型的知识。与此同时,我个人学到了新的技术和方法,而这些我从来没有接触过,只是因为我在做那些带回家的项目。这是一项新的学*,你可以在其他公司的面试中使用,即使你这次失败了。在进行技术评估时,试着找出你的弱点并努力克服它们。我曾经在评审人员面前编写 SQL 和 Python 代码时感到非常不舒服。但是通过大量的实践,我建立了一个系统,帮助我获得了出色的结果。 - 你在现场技术面试中被拒绝了!
我在采访人们时反复注意到的一点是他们没有准备好!!事实上,当我拒绝一个候选人时,十次有九次不是因为他们不知道我问的概念,而是他们不知道如何在面试中处理和回答这个问题。正如我在之前的为谷歌铺路一文中指出的,一个好的面试官的目标是通过问你几个技术性和非技术性的问题来了解你的思维过程。作为一名优秀的候选人,你需要让面试官以最准确的方式轻松评估这一点。
**解决方案:**这里我复制了一个我在这篇文章中写过的系统。作为一个例子,我讨论了我回答一个技术问题的系统,比如一个 SQL 问题:
——重复这个问题,以及你应该向面试官传达什么,以确保你们双方都在同一页上。
-要求一两分钟时间,思考解决方案。这不仅给你时间整理你的想法,也给面试官留下了一个积极的印象:你说话之前先思考!向面试官解释你的策略并检查你的假设。比如“假设数据中没有任何缺失或重复的值是否安全”?让面试官参与进来:编写尽可能易读的代码,并在每一步解释你在做什么。
-回顾您的解决方案,并提供如何改进的建议。
-征求反馈!在许多情况下,反馈帮助我改进了代码。有时,它会引发围绕其他可能的问题解决方案的有趣对话。我和其他许多人发现,对于我们得到的每一个面试问题,使用像我上面描述的系统方法有很大的好处!使用它,让我知道它是如何为你工作的。 - 你因行为问题和文化契合度被拒绝
我经常看到精通技术的候选人被拒绝,因为招聘团队没有发现他们有良好的文化契合度。这意味着这些候选人无法对行为或文化适应问题提供令人信服的答案。
解决方案 多年前,我在亚马逊进行现场采访时,回顾了亚马逊的 8 项领导原则,并试图写一个故事,将我的个人经历与这些原则联系起来。雇佣你的人知道他们将每天工作 8 小时,每周至少工作 40 小时。因此,与您有效合作和沟通、讨论不同问题、解决冲突以及推动成员和团队前进的能力需要有相似的价值观和标准。试着找出对他们来说什么是重要的,如果你们有相同的价值观,确保你清楚地表达出来,如果可能的话,通过你过去职业经历中的例子。
你得到了一份工作!
恭喜你做到了这一步!有一个报价,甚至多个报价,这是令人惊讶的。这是另一个问题,超出了本文的范围。我们可能会在以后的文章中讨论这个问题。
特朗普的推特网
原文:https://towardsdatascience.com/trumps-twitter-network-7c59522ffe82?source=collection_archive---------34-----------------------
社交媒体:采取行动的挑战

信用:查尔斯·德鲁维奥
为什么预测会对现实世界造成伤害的内容这么难?
你可能已经读过了,并认为——不,它不是!如果你在 Parler 上留下骄傲男孩的内容,那么他们当然会冲击国会大厦。
可惜没那么简单。目前,我们每天产生 5 亿条推文,因此难以避免信息过载的问题,这是一个令人沮丧的问题,因为有太多的材料需要筛选。
让我用一个例子更详细地说明一下……骄傲的男孩只代表美国的一个极右团体,还有更多。假设骄傲的男孩已经从 Parler 和所有其他社交媒体*台上删除,他们仍然只是在社交媒体*台上创建内容的几乎无穷无尽的极右翼团体中的一根针。
所以,我想探索是否有办法通过数据科学来解决这个问题;我想看看是否有办法从所有的噪音中分离出信号。
假设:特朗普的对话者如何改变他的选词?
我认为,检验这一点的一个方法是将数据集限制在世界上最有权力的人:美国总统唐纳德·J·特朗普。
所以为了研究这个,我想出了上面的假设陈述,用简单的英语你可以理解为如下:
如果特朗普上周一直在转发肖恩·哈尼蒂,他是更有可能还是更不可能煽动一群暴徒闯入首都?或者,如果他一直在转发布莱巴特,并已陷入与南希佩洛西的推特战争?
数据源
为了探索这一点,我进行了一系列 twitter API 调用,以丰富 Trump Twitter Archive 中已经非常有价值的数据集。
这一点尤其重要,因为这个数据集不包括特朗普推文中存在或不存在的 URL,而这正是我感兴趣的那种功能!
下面是我为此编写的代码:
要做到这一点,你需要一个 twitter 开发者账户,这样你就可以获得 API 证书。
我也只要求额外的信息,网址,报价,回复计数,但有一个公*的多一点,你可以检索。
我在这个项目中使用的另一个数据集来自 hatespeechdata.com,它更简单一点,由 reddit 和 gab 上的帖子组成,用户可以将这些帖子归类为可恶与否。
这样做的目的是提供一个独立于特朗普的数据集,在此基础上,我可以训练一个模型,将言论分类为仇恨或不仇恨,然后应用它来对特朗普的推文进行仇恨评分分类。
一旦解决了这个问题,我就可以着手建立一个模型,试图预测这个仇恨分数,看看哪些特征是重要的。
构建仇恨言论违反政策分类器
这背后有相当多的代码,你可以在这里看到完整的;以下是主要步骤的快速总结。
仇恨的数据集包含 90%的仇恨样本和 10%的非仇恨样本,所以我必须做一些事情来缓解这种类别不*衡。
一个是选择合适的指标来解释这一点;除了查看均方根误差,我还根据 F1 分数评估了该模型,F1 分数结合了精度和召回指标,以说明误报率和漏报率。

精确度、召回率和 F1 分数的正式定义
我在这里采用的另一种方法是随机过采样非恶意数据;从下面的代码中可以看出,这相当简单。
这里,右侧的训练数据集由一个 y_train 数组和一个稀疏矩阵组成,y _ train 数组包含 0 或 1 个值,用于表示该语音是否令人讨厌,稀疏矩阵包含矢量化的自然语言数据和特征。
我使用 TfidfVectorizer 测试了几个模型,因为我认为脏话或其他辱骂性语言的存在比一般的字数统计更重要。
在这些模型中,支持向量机模型表现最好,但是加载非常慢。多项式朴素贝叶斯模型表现不佳,这可能是意料之中的,因为仇恨语言中的特征不太可能有条件地相互独立——许多数据由同一主题中的多个帖子组成。
所以最后我选择了一个简单的逻辑回归模型,它给出的 F1 值为 0.91,并且在一些随机抽样数据中表现良好。
这里有一段代码:
以及生成的输出…

然而,当我应用这个模型将特朗普的推文分类为仇恨或不仇恨时,我经历了一些重大的数据漂移。
特朗普的推文虽然具有煽动性,但实际上并不像 gab 或 reddit 上的非政治仇恨人物那样频繁地使用种族诽谤或脏话。
所以在一些重要的人工测试后,我得出结论,当应用于特朗普的推文时,我的模型获得了特朗普的分裂。我的模型给特朗普的一条推文打分,当它包含“朝鲜”、“移民”、“让美国再次伟大”等短语时,它更有可能是仇恨的。
为什么?因为这些短语经常与 gab 和 reddit 上用于训练模型的仇恨数据集中的仇恨言论同时出现。
给你举个例子:
民主党人更关心非法移民,而不是我们强大的军队或我们危险的南部边境的安全
根据我的模型,这个演讲有超过 70%的可能性是充满仇恨的。
这是我执政的第 500 天,我们取得了很多成就——许多人相信,这比任何一位总统执政的前 500 天都要多
而这条推文不到 30%是充满仇恨的。
当然,事实上他们都不仇恨,但你可以看到前一条推文更具分裂性,因为它与经常引发仇恨言论的言论有关。
模拟特朗普的分裂
因此,我现在可以将这一仇恨分数添加到我的特朗普推文数据集,从而创建一个目标变量。
但是,还有很多工作要做!除了正常的数据清洗和自然语言预处理工作,我还必须提取一些关键特征——特朗普的推文包含转发吗?如果有,给谁?或者它包含一个网址?如果有,根域是什么?
让我在这个领域暂停一下——如果我想了解川普在推特上与布莱巴特谈了一整天后是否变得更加分裂,那么我需要对像 https://www.breitbart.com/article-1 的这样的 url 进行编码,使其与 https://www.breitbar.com/article-2 的具有相同的值,因为他们都来自布莱巴特。
这一切都有点复杂;另一方面,这使它变得有趣。看看这个笔记本,看看它实际上是什么样子:
在清理了更多的数据后,我使用回归树来确定哪些特征是川普分裂性的预测因素,并用 R2 评分来衡量这一点。
为什么是 R2 分数?因为我想看看哪些特征预示了特朗普的分裂性。在这一点上,我并不太关心准确性,只是想看看特朗普转发或引用的人是否会影响他的分裂程度。
作为背景,这里有一个在我的项目中应用的 R2 分数的正式定义:

很难预测特朗普的分裂性,即使是用系综或随机森林模型,但我确实得到了 0.2 的 r2 分数,这至少比基线 r2 分数 0 有所改善,也就是说,你会得到的 r2 分数只是*均分裂性分数。
然而,更有趣的是,这些模型都显示一个特征比其他特征更重要。是肖恩·哈尼蒂吗?还是南希·佩洛西?福克斯新闻频道?
不要!是时候了…
特朗普随着时间的推移

战胜了长期的分歧。y 轴表示特朗普的*均整体分裂性得分,x 轴表示每年的一个季度。用简单的英语来说——这向你展示了特朗普在每个季度都有多么分裂。
这个图表是一个时间序列,显示了特朗普季度分裂性得分的指数加权*均值。相对于原始数据,这样绘制可以消除很多干扰,并揭示数据中的一些趋势。
这一点的迷人之处在于它在多大程度上追踪了特朗普的政治生涯和选举周期。
分歧首次出现在 2011 年,当时特朗普在保守派政治行动会议上发表讲话,开启了他的政治生涯。
从那时起,它还大致跟踪了 2012 年和 2016 年的选举周期,然后在 2020 年围绕黑人的命也是命抗议和新冠肺炎疫情向上攀升。
这一切背后的代码如下:
结论
那么,这对于防止社交媒体上的真实世界伤害以及机器学*和数据科学如何提供帮助有什么意义呢?
首先要说的是,我的假设是错误的。看起来特朗普的对话者不会影响他的用词——看起来他发推特的时间段绝对会影响他的用词。
但我认为这有助于达成一个更强大的解决方案。
从上面的图表可以看出,特朗普的分裂性语言具有难以置信的时间限制。这似乎是显而易*的,但它实际上提供了一种非常有用的过滤数据集的方法。
如果我们知道特朗普在 2020 年的言论与 2012 年的言论类似,这是有帮助的,因为我们已经知道 2012 年发生了什么。如果我们知道,根据我们关心的一个指标——美国总统的分裂程度——这些时期是相似的,那么我们可以在数据中探索那个时期,看看那里发生了什么。
有人在《继续》上发推文做了什么可怕的事情吗?特朗普持续转发的出版物是否传播了可怕的错误信息,它仍然活跃吗?
如果这些问题的答案是肯定的,那么我们就可以采取行动,知道有强有力的证据支持我们的决定。这些信息的价值很难被夸大——它是在为时已晚之前采取行动的力量。
面向数据和分析工程师的基于主干的开发
原文:https://towardsdatascience.com/trunk-based-development-for-data-analytics-engineers-cc8602115b55?source=collection_archive---------32-----------------------
入门
如何避免合并的地狱,加速商业价值的交付,减少缺陷,并从此幸福地生活在您的数据仓库中。

通过数据工作流中基于主干的开发,开发速度更快,部署到生产的缺陷更少。图片由作者提供。
【We 需要额外的一天时间将转化分支合并在一起,是的,但是当我们最终将数据用于生产时,出现了一个 bug,所以我们不得不在另外两天内重做一些东西,…听起来熟悉吗?对我来说,数据和分析工程师似乎特别容易陷入“合并地狱”或“生产中的缺陷”场景。
但是有一个好的软件工程实践可以完全解决这些问题!它被称为“基于主干的开发”(TBD)。但出于某种原因,每当我与数据人员交谈时,他们都认为 TBD 不适用于数据管道、报告、立方体和所有这些数据东西。
在这篇文章中,我将试着解释一些基本知识,并希望用两个例子来说明 TBD 不仅适用**,而且实际上让数据人员的生活变得有趣!**
什么是基于主干的开发?
“一种源代码控制分支模型,在这种模型中,开发人员在一个称为‘主干’的分支中就代码进行协作,通过采用文档化的技术来抵制创建其他长期开发分支的任何压力。因此,他们避免了合并地狱,不破坏构建,从此幸福地生活。”(保罗·哈曼特,)
尽管 TBD 有三种主要的变体,但我现在想降低复杂性,简单地想象一下: TBD 意味着你总是将工作直接提交给 trun k!
考虑一下:由于您可能设置了一个 CI 系统,并且每天提交 1-10 次,这将每天触发 CI 系统 1-10 次,运行所有测试,甚至可能将您所做的任何事情直接部署到生产中。当然,这取决于您的系统是如何设置的,以及您在 CI & CD 工作流程中的进度。
对于大多数*惯于创建一个特征分支,在其中工作几天,然后与其他人的工作合并的数据人员来说,这是一个可怕的想法。
此外,你不会无缘无故地创建一个功能分支,对吗?您创建它,所以您的工作不会影响生产,也不会影响可能处理相同表和管道的其他人的工作。你创造它,所以你不会把“垃圾”推向生产。
这听起来像一个巨大的混乱时,工作的主干所有的时间…
这如何转移到数据管道、ETL、报告等等?
正如 Paul Hammant 所解释的,基于主干的开发使用了两种重要的技术,这两种技术将帮助您实际进行基于主干的开发:
- 功能标志(或功能开关)
- 抽象分支
如果您将这两种技术结合起来使用,您的数据管道工作将很快变得有趣,不会有任何合并冲突。我将分享两个例子来解释这两种技术,这也将表明为什么所有上述担心都是没有意义的。
但首先,让我回忆一下三个重要的规则:
- 以非常小的块提交!理想的情况是每天几次。
- 首先在本地运行您的“构建”,只签入“本地工作代码”。
- 永远不要打破“构建”。如果是这样,在继续之前,使用所有资源来修复它。
现在让我们来看看这些例子。
例 1,特征标志
功能标志是为了快速、安全地交付新功能。像这样:
` pythonmain(use _ old _ feature = True):
if use _ old _ feature://运行旧代码
否则:
// 切换到运行 new_main 功能!
特性标志如何帮助基于主干的开发?一个巨大的问题是,如果我们一直致力于主干,事情会被部署,并可能破坏生产系统。
那么,为什么不创建好的旧功能分支呢?因为那样的话,无论是我们的还是其他团队成员的代码都不会持续地相互集成。因此,功能切换来拯救我们,就像上面显示的那样。
我如何使用一个特性标志来集成代码?简单:我使用*“use _ old _ feature = False”在本地和 CI 上运行我的测试,但是使用“use _ old _ feature = True”*通过每个环境的配置文件部署到生产环境。
如果我们在 Tableau 做一个新的报告,包括
- 通过一些 Python 脚本摄取一些新数据
- 通过 dbt 转换数据
- 在 Tableau 中显示数据
我们可以在运行时使用特性切换,通过使用许可系统向我们显示报告,也可以像上面那样在构建时切换,或者在转换阶段直接通过 dbts 排除特性(https://docs.getdbt.com/reference/node-selection/exclude/
).
一个可能的配置文件如下所示:
` `` config.txt
产品环境特征排除=
-蒂姆·itd 的特写 1 # 233
-Eve ITHD-23 中的功能 2 #
int-env-feature-excludes=
-蒂姆·itd 的特写 1 # 233
dev-env-feature-excludes=无
例 1,续作金丝雀放飞&垂直切割任务
通过权限系统切换功能的一个很大的好处是,我们可以将它们用作金丝雀释放机制。这意味着我们可以向最终用户展示粗略的版本(如第一稿和第二稿),让他们随意摆弄,从而获得非常早期的反馈,甚至是对测试数据的反馈。
在我看来,如果我们尝试“垂直削减我们的任务”,Canary releases 的效果最好。这意味着不再将上述任务分解为:
- 进行摄取
- 进行转换
- 最后,做视觉上的东西
我们削减我们的工作:
- 通过快速运行虚拟转换生成测试数据= >发布第一份报告并获得反馈(来自自动化测试和人员)
- 使用实际获取的数据运行第二次迭代,并进行一些转换
- 敲定事情。
在这个过程中,我们得到了 3 倍的反馈,并以更快的速度到达最终用户手中。我们有更高的测试覆盖率,并且可以一直集成我们所有的代码库。
示例 1,继续警告
对于功能标志,Martin Fowler 显然有非常相似的观点,他说“它们是你应该做的最后一件事来隐藏一个已发布的功能”。相反,他认为你应该像上面那样削减(摄取、转换,最后是可视化的东西),但是在完成之前不要打开终端用户端。
两种方式都有效,特征标志也有效。您现在有了 3 种不同的工具来基于主干工作!让我们看看同样重要的最后一个工具。
示例 2,通过数据管道上的抽象进行分支
好了,这就是你如何将产品推向生产,并在生产中测试它,而不会给最终用户带来麻烦。但是如果你想做别人也在做的部分呢?
在数据团队中,这似乎经常发生,通常通过“你分支,我分支,然后我们合并”来解决。

你和你的同事处理不同的任务,但是相同的代码库,“Transformer”=>合并冲突、同步等。图片由作者提供。
一个解决方案是“通过抽象进行分支”,这意味着你在工作冲突的地方创建一个抽象,这样你就可以独立工作了。
让我们看一个例子。
假设您正在处理一个名为“dim_customers”的表,而您的团队成员也在不同的列上处理该表。您得到了一个转换工作,它获取“客户注册数据”和“研究数据”,执行一些操作,然后完成转换。您想要为研究数据添加几列,而其他人想要弄乱其他一些列。如果您不进行分支,就必须有人总是从主干中提取变更,本质上,您最终也会陷入合并地狱。
那你会怎么做呢?我们创造一个抽象概念。

一种允许彼此完全分离工作的抽象。图片由作者提供。
现在,您只需遵循抽象过程的分支:
- 抽象出我们想要改变的= >添加第二个转换“研究转换器”,例如“选择*”以将其包含在“转换器”中;运行测试以确保你的重构如你所想。
- 编写这个抽象的第二个实现,你的新实现(现在你的队友可以做他们想做的任何事情,尽可能多地释放和提交到主干!).
- 用这个实现来测试你的东西(通过使用一个特性开关来打开它进行测试!),甚至可能在为管理员打开特性开关的情况下将其投入生产。
- 执行一个微小的提交来切换到新的转换。
- 重构(如果需要的话)以包含转换!

现在你添加了抽象的第二个实现——是的,为了可读性,我在图中去掉了实际的接口。之后,只是测试和重构,你就大功告成了!图片由作者提供。
TBD 为数据团队带来的好处
还看不出好处?TBD 本身就很棒,它允许你实际上既做 CI 又做 CD。不断致力于主干的好处意味着,当你的同事已经合并了一些东西时,你所做的工作与代码库的样子相差甚远。通过减少这种情况,您可以:
- 意想不到地打碎更少的东西
- 花更少的时间合并东西
- 更快地看到重复代码,从而可以重用其他人的工作
- 尽早发现不兼容性,从而加速开发
通过不断地将您的代码库与现有的代码库集成,并不断地将其交付到您的环境中,您可以通过与生产数据、测试框架等进行交互来获得大量的反馈。
我该如何选择款式?
如果你仍然不相信基于主干的开发对数据团队是好的,那可能是因为你看到了一堆障碍。但是等等,大部分都可以很容易地移除。
基于主干的开发通常会遇到两件事,一是代码审查,这是很多团队对结对编程的替代或补充。团队可能会争论,没有特性分支,你就无法进行代码评审。多亏了现代编码系统,这种情况不再发生了。参*解释&此处列出的最佳实践。
你可能想到的第二个想法是,如何具体解决这个问题,因为出于某种原因,提交到主干对你来说是不可行的。那样的话,我还是建议通读一下这里讨论的三种不同的风格。
延伸阅读
- 如果你想深入了解特征标志/切换/开关这个话题,可以阅读马丁·福勒关于这个话题的文章:【https://martinfowler.com/articles/feature-toggles.html
- Paul Hammant 创建并维护的网站是一个很好的资源,可以满足你对基于主干的开发的所有需求。
对如何建立伟大的数据公司、伟大的数据密集型产品、成为伟大的数据团队感兴趣,还是对如何利用开源构建伟大的东西感兴趣?然后考虑加入我的 免费简讯《三个数据点周四》 。它已经成为数据初创企业、风投和数据领导者值得信赖的资源。
Python 中的真值测试
原文:https://towardsdatascience.com/truth-testing-in-python-d653afb8868e?source=collection_archive---------33-----------------------
了解 Python 中 bool 的所有功能

(https://unsplash.com/photos/N4-deIU3kQI
介绍
毫无疑问,布尔是计算世界中最重要的类型。布尔值是真/假值,可用于确定计算机内部的硬件以及计算机运行所依赖的软件和内核等多种情况。这种真值和假值的概念从计算机的最底层一直到最高层,也就是编程的最高层:
脚本语言。
世界上最流行的编程语言 Python 恰好是一种脚本语言。虽然 Python 确实有一种非常传统的将布尔值作为变量(而不是标志)的方式,但实际上这种语言和不同类型的真或假本质有很多不同之处。bool 数据类型不仅如此,它还是 Python 编程语言中几乎所有对象的寄存器,因为所有类型都有一个 bool 属性,该属性在语言中默认设置为 true。
条件式
我们可以用来测试布尔值的方法叫做条件语句。条件语句仅用于根据条件的结果执行某些代码。我们可以认为 1 == 1 会返回 true。这是因为操作数相等,并且==运算符根据两者是否相同来提供布尔返回。
1 == 1
True
现在我们可以用 if 关键字把它放到一个条件语句中。这个语句中包含的代码当然会运行,因为 1 实际上等于 1。
if 1 == 1:
print(" Who woulda thought?!")
如果不满足条件,我们可以将此与 else 结合使用,以获得不同的结果:
if 1 == 2:
print(" Wait... It does?!")
else:
print(" Those are certainly not equal.")
最后,如果第一个条件不满足,我们可以使用 elif 块来执行代码,但这个条件是:
if 1 == 2:
print(" Nope")
elif 2 == 2:
print(" it does")
else:
print("What?")
请注意,如果我们使用 elif,在这些条件下不会运行其他任何东西。在本例中,一次只会运行这些块中的一个。为了改变这一点,我们将再次使用 if 关键字创建完全独立的条件语句。
班级
许多 Python 程序员每天都在编写这种语言,却没有意识到所有的类实际上都有一个 bool 参数。默认情况下,该类将始终设置为 true。我们可以通过创建一个新类型,初始化该类型,然后用 if 语句测试该类型来证明这一点,就像我们之前提到的那样。让我们创建一个新的班级:
class Frog:
def __init__(self, age):
self.age = age
现在让我们初始化构造函数,并在条件语句中使用它:
froggy = Frog(5)
if froggy:
print(" It's awfully froggy out here.")
很酷,对吧?
我们可以通过重新定义它的 bool()函数来改变这个类的属性。我们将把它添加到前面的类中,并返回 false:
class Frog:
def __init__(self, age):
self.age = age
def __bool__(self):
return False
现在,如果我们再次通过我们的条件语句运行相同的代码,我们将看到我们的字符串不再被打印:
froggy = Frog(5)
if froggy:
print(" It's awfully froggy out here.")
结论
在计算世界中,布尔和真值是一个非常有价值和重要的概念。大多数从头开始的编程很可能介于使用类型、循环和条件之间,因为这些几乎是程序员唯一可用的工具。至少在 Python 中是这样,因为这种语言的迭代更少,更高级的特性。
对于 Python 程序员来说,知道如何在类内外处理真值和假值是非常必要的信息。编程中的一切都有真或假的值,所以非常熟悉它们是如何工作的可能是明智的。
尝试以下 5 个技巧来优化你的 Python 代码
原文:https://towardsdatascience.com/try-these-5-tips-to-optimize-your-python-code-c7e0ccdf486a?source=collection_archive---------21-----------------------
编写更好的 python 代码的快速技巧

照片由布鲁诺布埃诺 发自佩克斯
Python 确实是最通用、最流行的语言之一,几乎可以用于任何领域。但是 python 最突出的缺点之一就是速度。
由于 python 是一种解释型语言,执行指令所需的时间比编译型语言(如 C、C++甚至 Java)要长得多。因此,我们需要注意优化我们编写的 Python 代码,以使代码执行得更好更快。
虽然在较简单的程序中无法体验到性能的提高,但是在一些真实项目中,我们肯定可以注意到这种变化。
在本文中,我将介绍 5 个这样的技巧,它们将使您的 python 代码更加优化,并将提高其性能。
1。 使用内置函数,而不是从头开始编码
Python 以其惊人的库而闻名,这些库几乎可用于计算机科学的任何领域,你应该好好利用它们。Python 中的一些内置函数如map()、sum()、max()等已经在 C 语言中实现了,所以在执行过程中不会对它们进行解释,节省了大量时间。
例如,如果您想将一个字符串转换成一个列表,您可以使用map()函数,而不是手动将字符串的内容追加到一个列表中。代码更加优化,大小也更小。
string = ‘Australia’U = map(str, s)print(list(string))Output: [‘A’, ‘u’, ‘s’, ‘t’, ‘r’, ‘a’, ‘l’, ‘i’, ‘a’]
您可以在 python 上找到更多类似的很酷的功能,它们可以使您的任务变得简单和优化。
2。 关注代码执行过程中的内存消耗
减少代码中的内存占用肯定会使代码更加优化。我们需要记住不必要的内存消耗是否正在发生。
让我们观察下面的代码片段。这里我们使用+操作符添加一个较小的字符串来生成一个较大的字符串。
myString = ‘United ‘myString += ‘states ‘myString += ‘of ‘myString +=’America’print(myString)
这个方法会在我们每次写 myString 的时候生成一个新的字符串,并且会导致不必要的内存消耗。我们可以在获取一个列表中的所有字符串后,使用函数 join()来代替使用这个方法来连接字符串。这将是更快的,并为内存优化。
string2 = [‘United ‘, ‘states ‘, ‘of ‘,’America’]string3 = ‘’.join(string2)print(string3)
输出
United states of America
此外,在打印字符串中的变量时使用f-strings代替传统的'+'操作符在这种情况下也非常有用。
想 敬请期待 与更多相似 精彩 文章上 Python &数据科学 —做会员考虑使用我的推荐链接:https://pranjalai.medium.com/membership。
**3。**Python 中的记忆化
那些知道动态编程概念的人非常熟悉记忆的概念。在这个过程中,通过在存储器中存储函数值来避免重复计算。尽管使用了更多的内存,但性能提升是显著的。Python 附带了一个名为functools的库,它附带了一个 LRU 缓存装饰器,可以让你访问用来存储某些值的缓存。
让我们以斐波那契数列为例。对于普通的 python 代码,在本地机器上计算 fib(35)的执行时间是 4.19147315400005 秒。
而当我们添加以下代码行时:
from functools import lru_cache@lru_cache(maxsize=100)
在代码块的开头,执行时间减少到 3.440899990891921e-05。
在这里,本地机器的执行时间呈指数级减少。时间差只会随着 fib(n)中 n 值的增加而增加。
4。 使用 C 库/PyPy 获得性能增益
如果有一个 C 库可以做你的工作,那么最好使用它来节省解释代码的时间。最好的方法是使用 python 中的ctype库。还有一个叫做 CFFI 的库,它提供了一个优雅的 c 接口
如果你不想使用 C 语言,那么另一种方法是使用 PyPy 包,因为 JIT(即时)编译器的存在极大地提高了你的 Python 代码。
5。 正确使用数据结构和算法
这更像是一个通用的技巧,但却是最重要的一个,因为它可以通过改进代码的时间复杂度,为您带来可观的性能提升。
例如,在 python 中使用字典而不是列表总是一个好主意,以防没有任何重复的元素,并且要多次访问这些元素。
这是因为字典使用散列表来存储元素,当在最坏的情况下搜索列表时,时间复杂度为 O(1 ),而不是 O(n)。因此,它将为您带来可观的性能增益。
结论
本文到此为止。这是用 python 编码时能显著提高性能的五个技巧。但是您应该记住的另一件事是,性能的提高不应该影响代码的可读性,这也是现实项目中的一个重要方面。
敬请期待!!了解更多与 Python 和数据科学相关的技巧。
在你走之前……
如果你喜欢这篇文章,并希望继续关注更多关于 Python &数据科学的精彩文章**——请考虑使用我的推荐链接https://pranjalai.medium.com/membership成为一名中级会员。**
还有,可以随时订阅我的免费简讯: Pranjal 的简讯 。
尝试这个简单的技巧来改善你的聚类
原文:https://towardsdatascience.com/try-this-simple-trick-to-improve-your-clustering-b2d5d502039b?source=collection_archive---------15-----------------------
提示和技巧
开始初始化的 k-means++算法

照片由布拉登·科拉姆在 Unsplash 上拍摄
k-means 是一种非常简单且普遍存在的聚类算法。但是通常它对你的问题不起作用,例如因为初始化不好。我最近遇到了一个类似的问题,我对我的数据集中的少量文件应用了 k-means,一切都很好,但当我对更多的样本运行它时,它只是没有可靠地获得良好的结果。
幸运的是,有一种改进的初始化方法,k-means++可以帮助缓解这个问题。在本文中,我们将涵盖以下内容:
- 为什么初始化对 k-means 如此重要
- 对 k-means++算法的直观描述
- R 中 k-means++的实现
- k-means ++的一个常*但错误的变体
如果你还没有读过我关于 k-means 的文章,可以去看看,因为我会经常引用那里介绍的主题。像往常一样,你也可以在我的 GitHub 上找到这篇文章的所有代码。
[## 对 k-means 的深入探究
towardsdatascience.com](/a-deep-dive-into-k-means-f9a1ef2490f8)
问题是
正如我们在我之前的帖子中看到的,普通 k-means 受到随机初始化的影响。根据选择哪些点作为起始中心,
解决方案可能是一个非常糟糕的局部最小值。并且由于 k-means 具有严格的凹损失函数,它在训练期间没有办法逃离这个局部最小值。
考虑我上一个例子中的例子,我们有两个集群,但是每个集群中的点数非常不同(也就是说,集群基数不同)。由于起始中心是随机选择的,很有可能两个中心都是从大集群中选择的,这反过来导致
最终完全错误的集群。
但是对于大小均匀的集群,我们可能会得到错误的初始化,从而导致错误的结果:

k-means++算法
这个问题的解决方案是 k-means++算法,它使用不同的初始化。这个想法非常简单:
我们只随机选择第一个中心,而不是随机初始化。所有的
随后的中心仍然被采样,但是其概率与它们离所有当前中心的距离的*方成比例。远离当前中心的点在下一次初始化迭代中成为中心的概率更高。
这试图更均匀地填充观察空间,同时仍然保留一些随机性。即使使用 k-means++,对相同数据的多次运行的结果也可能不同。虽然它在算法开始时确实需要更多的计算,但它会导致更快的收敛,使它在运行时方面比普通 k-means 更具竞争力。因此,许多常*的库使用 k-means++初始化作为它们的缺省值,例如 sk-learn 或 MatLab 实现。
请注意,此处仅隐式考虑了基础数据的分布,因为概率仅依赖于到其他中心的距离,而不依赖于到所有其他数据点的距离(与其他初始化算法相反,例如围绕 medoids 的分区)。
尽管如此,点数多的区域更有可能创建自己的
中心,因为更多的点数可以被选作下一个中心。
R 中的实现
base R 附带的kmeans函数实际上没有 k-means初始化选项。所以让我们实现它,重用上一篇文章中 k-means 算法的主干。我们将添加一个可选参数,让用户选择初始化,默认为我们刚刚讨论过的 k-means初始化。
第一个中心是从数据中随机选择的。然后,我们创建一个中心数据框,从第一个中心开始,稍后我们将填充其余的中心。同时,我们需要跟踪哪些点不是中心,以防止我们再次选择同一个点作为中心。
next_center_id <- sample(seq_len(nrow(df)), 1)
centers <- df[next_center_id, ]
non_centers <- df[-next_center_id, ]
接下来,我们根据它们与
当前中心的距离迭代地选择新中心。我们可以使用上次的帮助函数calculate_centers(完整代码*下文),我们只需要考虑到最近中心的距离,所以我们在每一行调用min。
distances <- calculate_distances(non_centers, centers)
distances <- apply(distances, 1, min)
在接下来的步骤中,我们根据距离选择下一个中心。
sample函数方便地让我们通过prob参数指定每个点的概率,它们甚至不需要在 0 和 1 之间!
因此,我们可以计算距离的*方,并简单地将它们传递到那里,但为了更紧密地遵循原始文件,我们还进行了归一化:
probabilites <- distances² / sum(distances²)
next_center_id <- sample(seq_len(nrow(non_centers)), 1, prob = probabilities)
最后,我们选择下一个中心,将其添加到我们的中心数据框中,然后
将其从非中心数据框中移除
next_center <- non_centers[next_center_id, ]
centers <- rbind(centers, next_center)
non_centers <- non_centers[-next_center_id, ]
我们现在只需要在一个while循环中这样做,直到我们选择了预期数量的聚类 k 的中心。这产生了我们的最后一个函数:
如果我们使用新的 kmeans++初始化,我们现在可以从数据中恢复正确的集群:

一个常*但错误的 k-means++变体
与许多数据科学工具一样,k-means技术也有一些变体。通常,它选择与所有其他中心距离最大的点
作为下一个中心,而不是以与距离成比例的概率进行采样的
。如果你看一下
原始论文(文末链接),这并不是真正的 k-means
算法,它还有一个重大缺点:
如果总是选择具有最大距离的中心,则可以容易地选择一个异常值作为中心。由于人们通常选择 k 与数据集的大小相比非常小,少量的离群值就足以只选择离群值作为初始中心!
这不会对集群有太大的改善,因为你的数据主体没有很好的分布中心。但是,如果您想这样做,那么while循环中的代码应该如下所示:
distances <- calculate_distances(non_centers, centers)
distances <- apply(distances, 1, min)
# Choose point with maximum distance as next center
next_center_id <- which.max(distances)
# True k-means++ does the following:
# probabilities <- distances/max(distances)
# next_center_id <- sample(seq_len(nrow(non_centers)), 1, prob = probabilities)
next_center <- non_centers[next_center_id, ]
centers <- rbind(centers, next_center)
non_centers <- non_centers[-next_center_id, ]
摘要
正如我们所*,初始化是 k-means 性能的关键。
k-means++算法是一种简单且广泛应用的技术,可以缓解普通 k-means 算法存在的问题。还存在一些其他方法来进一步帮助解决这个问题,例如多次初始化中心,并选择具有最低惯性的初始化。例如, sk-learn 默认进行 10 轮初始化。
对于我的用例,不幸的是 k-means++还不够,我需要更好的方法。最复杂的初始化可能包含在 medoids 分区(PAM)中,我将在下一篇文章中讨论。敬请关注!
来源
- 描述 k-means++算法的原始论文:Arthur&Cassilvitskii(2007):k-means ++精心播种的优势
- 如果你没有论文,数学也在 MATLAB 文档中描述
- 对 k-means++的随机初始化的经验评估
试用 Jython——Java 中的 Python
原文:https://towardsdatascience.com/trying-out-jython-python-in-java-3efc76196a9e?source=collection_archive---------5-----------------------
Jython 是什么,它还能用吗?

(图片由雅各布·久巴克在Unsplash.com上拍摄)
介绍
ava 是一种编程语言,已经很久不需要介绍了。这种语言无疑已经在各种软件行业中站稳了脚跟。从软件开发到 web 开发,甚至是 OpenGL 游戏开发,Java 已经成为这个行业的主流十多年了,它可以做很多事情。我们甚至可以认为 Java 在数据科学中也占有相当大的份额。当然,Scala 是一种不同的语言,它修改了 Java,试图去掉更多的缺点,使范例更加灵活,但是——Scala 是基于 JVM 的,当然非常接近 Java。Scala 绝对是数据科学领域的一项大工程,尽管这种语言的持久力可能随着它的 Java 亲戚在最近几年有所下降。实际上,我写了一整篇文章,讨论在您的数据科学之旅中,为什么您可能想或不想学* Scala,如果您有兴趣在 2021 年学*更多关于数据科学和 Scala 的知识,这当然值得一读:
Python 和 Java
为了理解 Python 和 Java 之间令人捧腹的关系,让我们首先回顾一下每种语言对数据科学和软件工程的整体影响。Java 并不是没有问题,即使是在它风靡全球的巅峰时期(明白吗,Eclipse 是一个旧的 Java IDE。也就是说,有一个替代版本的 Java 具有更多可扩展的特性和“更好”的总体设计。我强调越好,因为这些问题中有很多是个人偏好的问题。
人们不喜欢 Java 的一点是它的范式非常静态。这意味着,无论你在用什么语言编程,都必须以完全相同的方式完成。Scala 改变了这一点,它允许这种语言按照程序员希望的范式工作。经过多年的发展,我想我们已经意识到程序员不希望一门语言强迫他们以某种方式行事。我可以肯定地证明这一点。你可能会注意到,我写的主题经常在这个范围内——因为我喜欢泛型编程,我喜欢能够用非常适合问题的新方法来处理不同类型的问题。这是我认为朱莉娅很棒的部分原因。作为一种语言,它倾向于置身事外——这就把我们带到了组成这个弗兰肯斯坦编程会议的另一个语言主题…
计算机编程语言
"大 P "
虽然没人管 Python 叫大 P,但是小解释语言做了很多事情。Python 的伟大之处在于它与 Java 有着相似的发展,同时也是一种基于 C 的开源语言,没有 Java 的问题。显著的区别是 Python 是 C 解释的,而 Java 运行在 JVM 专有的虚拟机上。
考虑到这一点,虽然看起来我对 Java 的评价很低,但事实并非如此。实际上,我对这门语言情有独钟,因为它是我在编程经历中很早就学会的一门语言。然而,我发现用任何标准来衡量,创建一个可以做任何事情的类都是令人沮丧的,我甚至发现这种语言比 C更难使用,c是我当时最喜欢的语言。这些年来,我与这种语言有过很多磨合,最终也写了相当多的 Scala 但不管怎样,尽管 Java 是一种很棒的语言,JVM 是一种很酷的虚拟化技术,我还是更喜欢使用不同的语言,比如 Python。
然而,我相信,鉴于 Java 是一个如此巨大的技术*台,使用 Java 的经验仍然是有价值的。也就是说,我认为 Java *台有很多擅长的事情。以一种真正经典的“30 亿台设备运行在 Java 上”的方式,Java 可以应用于很多事情——甚至可能是数据科学。幸运的是,数据科学家可以使用 API 在多种语言中工作。今天,我想用 Jython 看看 Python 和 Java 之间潜在的协同作用。在 Java 中使用某种级别的 Python 语法运行一些非常棒的代码是可能的。
Python 和 Java 结合的真正迷人之处在于,它们来自两个完全不同的世界。Python 是用 C 语言编写的,在某种程度上,这种语言可以很好地使用的大多数代码都将驻留在同一个域中。另一方面,Java 是基于 Java 虚拟机或 JVM 的。与 Python 等价的 JVM 很可能是 JavaScript,尽管 JavaScript 通常与 Python 不同的计算领域相关联。事不宜迟,让我们看看能否让 Jython 工作起来。
安装 Jython
Jython 是一个发音非常奇怪的名字,但是这个名字的好处是我们都可以识别这个包可能做什么。如果您想亲自查看 Jython 网站,这里有一个链接:
这个包的酷之处在于它结合了 Python 和 Java。我认为这可能会给两种语言之间的某种程度的协同带来一些潜力。然而,这一切可能的长度目前对我来说是一个谜——所以我想最好的方法是跳进一个笔记本,尝试一下。我甚至没有在这台计算机上安装 openJDK,所以我要做的第一件事就是安装它。
[emmac@fedora ~]$ dnf search openjdk
Fedora 34 - x86_64 2.8 MB/s | 74 MB 00:26
Fedora 34 openh264 (From Cisco) - x86_64 4.1 kB/s | 2.5 kB 00:00
Fedora Modular 34 - x86_64 2.2 MB/s | 4.9 MB 00:02
Fedora 34 - x86_64 - Updates 3.2 MB/s | 29 MB 00:09
Fedora Modular 34 - x86_64 - Updates 1.8 MB/s | 4.3 MB 00:02
google-chrome 5.7 kB/s | 3.5 kB 00:00
RPM Fusion for Fedora 34 - Free 50 kB/s | 941 kB 00:18
RPM Fusion for Fedora 34 - Free - Updates 12 kB/s | 395 kB 00:32
RPM Fusion for Fedora 34 - Nonfree 19 kB/s | 246 kB 00:12
RPM Fusion for Fedora 34 - Nonfree - Updates 3.8 kB/s | 81 kB 00:21
======================= Name & Summary Matched: openjdk ========================
java-1.8.0-openjdk.x86_64 : OpenJDK 8 Runtime Environment
[emmac@fedora ~]$ sudo dnf update && sudo dnf install java-1.8.0-openjdk -y
哇,我想我正式成为 Java 开发人员了。
Jython 安装程序以. jar 文件的形式出现。当然,现在我有了 JDK,可以很容易地打开它。我必须承认,我通读了文档,看起来 Jython 确实是为 Python 2.7 设计的。考虑到这一点,如果这不起作用就不足为奇了,因为 Python2 已经被弃用了近一年,或者可能是两年……我不记得弃用是在 2021 年 1 月还是 2020 年 1 月。我跑题了,让我们试着执行 Jython。jar 文件,看看会发生什么。
随机边评,我已经好几年没*过. jar 文件了!
该文件也没有被执行的能力,所以您可能不得不像我一样对该文件进行 chmod +x。然后我跳进终端,用 java -jar 打开它。需要注意的是,如果您像这样使用终端,您实际上可能不需要更改它。我原本不打算这样做,但我没有在“打开方式”屏幕上显示 OpenJDK。

(图片由作者提供)
这并没有激发太多的信心。
安装过程非常简单。我确实,但是在安装这个的时候在终端上收到了很多警告…
(java:292940): Gtk-WARNING **: 20:00:34.120: Could not load a pixbuf from icon theme.
This may indicate that pixbuf loaders or the mime database could not be found.
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.python.core.io.StreamIO (file:/home/emmac/jython2.7.2/jython.jar) to field java.io.FilterOutputStream.out
WARNING: Please consider reporting this to the maintainers of org.python.core.io.StreamIO
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
DEPRECATION: A future version of pip will drop support for Python 2.7.
Looking in links: /tmp/tmpqcWXlg
Collecting setuptools
Collecting pip
Installing collected packages: setuptools, pip
Successfully installed pip-19.1 setuptools-41.0.1
天哪
看起来我们确实在使用 Python 2.7,这实际上非常糟糕。或者更确切地说,我们可能使用的是 Python 3.9.9,但 Jython 认为我们使用的是 Python 2.7。这很可能会导致一些问题,但是我们真正能发现的唯一方法是编写一个新的 Java 应用程序。我要写的第一件事就是经典的《Hello world!是时候看看这是如何运作的了。坦白地说,我也很想做或看到一些基准测试,尽管实际工作的可能性很小,但是我不确定我们是否能成功编译一个应用程序,但是我们肯定会尝试!
书写 Hello World
另外,顺便说一下,我也确实发现了一些奇怪事情,这些事情可能会让我看起来很愚蠢。我想检查 Jython 现在是否被添加到我的路径中,并且…只是看一下…
[emmac@fedora ~]$ jython
bash: jython: command not found...
Install package 'jython' to provide command 'jython'? [N/y] n
所以你的意思是告诉我
- 安装 JDK
- 运行一个 jar 文件
- 通过 Jython 安装程序安装 Jython
它一直在我的包管理器里。幸运的是,dnf/yum 存储库中的版本与我刚刚安装的版本相同。
[emmac@fedora ~]$ sudo dnf list jython
Last metadata expiration check: 0:37:53 ago on Sat 18 Dec 2021 07:32:27 PM EST.
Available Packages
jython.noarch 2.7.1-16.fc34 fedora
[emmac@fedora ~]$
给维护者的提示。
事不宜迟,让我们试着编写 hello world 代码吧!
[emmac@fedora dev]$ mkdir jython_hello_world
[emmac@fedora dev]$ cd jython_hello_world
[emmac@fedora jython_hello_world]$ nano hello.java
这个过程的第一步是导入 PythonInterpreter 类。按照真正的 Java 方式,这被隐藏在其他 6 个别名之下。
import org.python.util.PythonInterpreter;
System.out.println("这个上面怎么这么多包啊。")
正如我前面提到的,Java 是纯面向对象的,并且强迫用户在这个范例中操作。这既是一件好事也是一件坏事,但是不管我对它的看法如何,接下来我将不得不写一个具有 main 函数的类:
public class main {
public static void main(String[] args) {
}
}
}
正如他们在 Jython 文档的例子中所做的那样,我将把我对 PythonInterpreter 类的调用包装在一个 try 中,这样如果这不起作用,我的计算机就不会崩溃——不崩溃意味着它不会抛出异常。
try(PythonInterpreter pyInterp = new PythonInterpreter()) {
pyInterp.exec("print('Hello World! Wait is this Python or Java')");
我们将调用 pyInterp.exec()函数,以便将 Python 代码作为字符串执行,最终的类如下所示:
import org.python.util.PythonInterpreter;public class main {
public static void main(String[] args) {
try(PythonInterpreter pyInterp = new PythonInterpreter()) {
pyInterp.exec("print('Hello World! Wait is this Python or Java')");
}
}
}
哇,我太爱面向对象编程了,为了编写一个多范型的面向对象编程语言,我在用面向对象语言。
[emmac@fedora jython_hello_world]$ java hello.java
hello.java:1: error: package org.python.util does not exist
import org.python.util.PythonInterpreter;
^
hello.java:5: error: cannot find symbol
try(PythonInterpreter pyInterp = new PythonInterpreter()) {
^
symbol: class PythonInterpreter
location: class helloworld
hello.java:5: error: cannot find symbol
try(PythonInterpreter pyInterp = new PythonInterpreter()) {
^
symbol: class PythonInterpreter
location: class helloworld
3 errors
error: compilation failed
[emmac@fedora jython_hello_world]$
所以这产生了一些错误…看起来 PythonInterpreter 类不存在。我找到了这个类的文档,在这里:
奇怪的是,这并不在反对之列。我必须承认,Java 肯定不是我最喜欢的语言,也不是我经常编写的语言,所以我不确定这是被否决了还是我做错了什么——但是整个 org.python 包可能已经被完全否决了。我们可以通过尝试导入来测试这个工作理论:
GNU nano 5.8 hello.java
import org.python.util.PythonInterpreter;
import org.python;
public class helloworld {
public static void main(String[] args) {
try(PythonInterpreter pyInterp = new PythonInterpreter()) {
pyInterp.exec("print('Hello World! Wait is this Python or Java')");
}
}
}
第二次尝试
这是一个非常老的软件,大约有十年了,所以为了让它正常工作,我们可能需要做一些不同的尝试。我注意到在我的安装目录中,有一个 README.md 文件。在该文件中,他们直接调用 Jython 可执行文件,而不是用 Java 编译所有这些文件。考虑到这一点,也许这就是我这次尝试的问题所在。考虑到这一点,我想从 DNF 安装 Jython,这样它就会在我的路径中,而不是通过努力找到可执行文件的位置并将该目录添加到我的路径中
sudo dnf install jython
[emmac@fedora jython_hello_world]$ jython --version
Jython 2.7.1
现在,如果我在终端中键入“jython ”,它实际上会启动一个 REPL!
[emmac@fedora jython_hello_world]$ jython
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by jnr.posix.JavaLibCHelper$ReflectiveAccess (file:/usr/share/java/jnr-posix/jnr-posix.jar) to method sun.nio.ch.SelChImpl.getFD()
WARNING: Please consider reporting this to the maintainers of jnr.posix.JavaLibCHelper$ReflectiveAccess
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Jython 2.7.1 (, Jan 12 1970, 15:34:24)
[OpenJDK 64-Bit Server VM (Red Hat, Inc.)] on java11.0.13
Type "help", "copyright", "credits" or "license" for more information.
>>> print(" Hey look, it works")
Hey look, it works
>>>
有人报警了,因为发生了非法反射访问操作。
jython hello.java
public class helloworld {
^
SyntaxError: no viable alternative at input 'class'
等等。
我认为这个 Jython 包实际上是为了阅读 Python,它可能实际上是一个 Java 绑定的 Python 解释器。让我们试着制作一个相当于这个 hello world 文件的 Python。
[emmac@fedora jython_hello_world]$ nano helloworld.py
这是我的 hello world 应用程序:
if __name__ == "main":
print("Hello World")
Python 永远不会让我相信‘是字符串。
jython helloworld.py
无论何时运行,什么都没发生——除了我们以前有过的同样荒谬的非法反射活动的打印输出。也许解释者不想让我做 Python
if __name == "main":
并且无法解释这样的代码?
print("Hello World")
既然我们的文件没有条件,让我们来试试看:
[emmac@fedora jython_hello_world]$ jython helloworld.py
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by jnr.posix.JavaLibCHelper$ReflectiveAccess (file:/usr/share/java/jnr-posix/jnr-posix.jar) to method sun.nio.ch.SelChImpl.getFD()
WARNING: Please consider reporting this to the maintainers of jnr.posix.JavaLibCHelper$ReflectiveAccess
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Hello World
成功了!
结论
这相当于试图在现代的 Windows 机器上运行 90 年代的游戏,除了有点糟糕。虽然这确实很可笑,但却很有趣。试图在 Java 中使用为 Python 2.7 设计的遗留代码可能行不通,但是现在我的机器有了一个基于 Java 的 Python 解释器——这非常有趣。然而,真正酷的是,我还注意到可能有一种方法可以将这些代码编译成. jar 文件。是的,我是认真的——用 Java 编译 Python 我不完全确定,但是无论何时我打电话
jython --help
在我的终端里,这个潜在的论点打动了我:
-jar jar : program read from __run__.py in jar file
不管它实际上意味着什么,它肯定是非常有趣的。我将不得不在以后的文章中花些时间来研究这个问题!还有一件事,如果你想查看这两个 hello world 文件,无论出于什么原因,你都可以在 Github 上我的“随机代码”存储库中查看它们:
https://github.com/emmettgb/Random_Code/tree/main/jython
非常感谢您阅读这篇古怪的 Java-Python 疯狂冒险,它对我来说意味着一切!鉴于 Jython 仍在工作(不确定它是否仍在使用 Python 2.7 或 3.9.9),我肯定会就此主题写一篇后续文章,在所述文章中,我可能会尝试用 Python 编译一个 jar 文件,如果这是那个论点实际做的,那么描述符确实不是最好的。如果有读者知道这是什么意思,也不知道这是什么意思,如果有人能告诉我,那就太好了。我也可能会尝试用旧的 C 编译器对 JVM 编译器进行基准测试。
一些结束语…如果这只是一个简单的 Java Python 解释器,那么 Python 2 被弃用可能没什么关系。也许事实就是如此,而 Python 根本没有参与其中。如果是这样的话,那么将基于 JVM 的编译器与基于 C 的编译器进行比较将会更加有趣。在那之前,我要感谢我的读者,我希望你们无论白天还是晚上都有一个美妙的休息!
试图解决 CartPole 没有谷歌任何东西
原文:https://towardsdatascience.com/trying-to-solve-cartpole-without-googling-anything-a296d79babb3?source=collection_archive---------37-----------------------
对自己的周末挑战
什么是横竿?
CartPole 是一个开放的环境问题,旨在测试你编写一个解决方案来*衡附着在车上的杆子的能力,如下图所示。如果旗杆偏离垂直方向超过 15 度,你就输了,如果手推车偏离屏幕,你就输了。我只有强化学*的理论知识,所以我试着看看能不能不用谷歌就想出解决方案。我是这么做的。

一个钢管舞的开始
状态和行动
在每一个时间步,你必须把车稍微向左或向右推。你必须从这两个选项中选择一个。这些选项被称为“动作空间”在每个时间步有 4 条信息给你做决定:小车位置,小车速度,极点角度,尖端的极点速度。这些信息统称为“状态”
建立基线
官方的说法是,当你支撑一根竿子 200 个时间步时,就认为这根竿子被打败了。我没有用这个标准来衡量自己,因为我试图在没有任何帮助的情况下解决整个问题。首先,我在 1000 个 cart pole 模拟中采取随机行动(每个模拟称为一集)。这产生了持续大约 21 个时间步长的*均模拟。然而,我不想只是比随机更好。我创造了一个“硬编码”的解决方案,如果杆子向右倾斜,它就向右移动,如果它向左倾斜,它就向左移动。这产生了 40 步的*均时间长度。这是我的基线。
解决方案尝试
首次尝试线性回归
这是一个非常简单的解决方案,但我想为什么不试一试。我是这么做的。
- 从许多随机模拟中收集数据。
- 使用状态和动作作为输入,预测杆子还能保持多长时间。
- 在每个时间步运行 model.predict()两次,插入“left”和“right”进行操作,并选择剩余时间值较大的一个。
这样做的问题是,因为变量之间没有交互作用,一个动作值将总是产生更高的预测剩余时间。
第二次尝试随机森林
下一个解决方案与第一个非常相似,但是我意识到我必须考虑状态和动作之间的交互作用。一个随机森林就可以做到这一点,而且用一个随机森林替换掉代码,然后在线性回归中添加多项式和交互效应会更容易。
- 从许多随机模拟中收集数据。
- 使用状态和动作作为输入,预测杆子还能保持多长时间。
- 在每个时间步运行模型两次,为动作插入“左”和“右”,并选择具有较大值的一个。
这种解决方案的主要问题是,这个动作的特性重要性如此之低,以至于在预测它停留的时间时没有用。这是因为它在糟糕的情节上进行了大量训练,这些情节不会持续很长时间,随机的行动根本没有帮助。毕竟大多数情节都是非常糟糕的例子。事实上,一遍又一遍地选择相同的动作会产生一个持续 9 个时间步长的情节,而 random 只会持续更长一点的时间。
第三次尝试神经网络
我决定在每集结束时训练/再训练一个模型,而不是收集大量模拟数据。我认为这将获得更好的训练数据,因为模型将迭代改进,我将获得越来越多的成功训练数据。
- 从单个随机剧集中收集训练数据。
- 在随机事件上训练神经网络,以预测杆子会竖立多久。
- 运行另一集,其中神经网络预测它停留多长时间,偶尔采样一个随机动作。
- 在每集结束时继续更新神经网络,最终采取随机行动的方式。
我用这种方法遇到的问题是,神经网络从偏好一个动作(由于随机权重)开始,因此它预测相同的动作。然后,网络开始变得非常准确,预测游戏将在 9 个步骤中结束,因为这就是当你总是做出一个决定时会发生的事情。这个模型本质上集中在有目的地立即结束游戏,这样它会非常准确。我*过其他人用这种方式成功地实现了一个解决方案,但他们无疑更擅长优化采取随机行动进行学*和使用模型之间的权衡,以及设计他们的神经网络结构。
第四次尝试逻辑回归
接下来,我决定改变我思考问题的方式。到目前为止,我基本上一直使用动作作为输入并运行 model.predict(state,action)两次,使用不同的动作值。所以我决定用状态来预测动作。这将问题从我预测连续结果(剩余时间步长)的回归型问题转化为二元分类问题(左或右)。如果我用随机数据进行训练,我会遇到一个问题,没有一个状态与动作相关联(因为它们是随机选择的动作。为了解决这个问题,我删除了持续时间不长的剧集。剩下的剧集,虽然是随机生成的,却有很好的行动范例。
- 从许多剧集中收集随机数据。
- 删除至少 100 个时间步长内电杆未保持直立的数据。其余数据仅显示了各州采取的良好行动。
- 训练逻辑回归 X =状态,Y =行动。
- 运行新模型并使用状态来预测动作,然后采取那些动作。
这种解决方案使模型持续了大约 60 个时间步。这比我的硬编码基线快了 20 步。这仍然有缺陷,首先我必须生成大量数据,然后扔掉其中的大部分,因为它们是糟糕的(即排序)剧集。鉴于有些人已经解决了几百集的问题,我做得不是很好。其次,鉴于它只持续了 60 步,其他人持续 200 步的解决方案也并不伟大。
外卖
以下是我从中学到的主要东西:
- 强化学*工作起来很有趣,而且比许多其他 ML 项目更有趣,因为你可以看到你的模型对一些“有形的”(尽管是数字的)东西的影响。在我看来,AI 和 ML 的区别在于,AI 有决策能力,而 ML 没有。AI 可以根据 ML 的输出做出那些决定(通常也是这样)。强化学*感觉是最接近人工智能的东西,并且将是人们在未来几年中认为的人工智能。
- 简单的解决方案有效!学*逻辑回归很容易,所以为什么不把它作为学生职业生涯中的早期学*练*呢?这当然比泰坦尼克号分类更吸引人。
- 我需要了解更多关于深度学*的知识。虽然我只是说“简单的解决方案有效”,但随着我处理的问题变得越来越复杂,我需要更好的方法。除了其他问题,人们有更好的神经网络解决方案,所以这肯定是我应该加倍努力以获得更好的解决方案的事情。
尝试使用 30GB 的数据库进行情感分析
原文:https://towardsdatascience.com/trying-to-use-a-30gb-database-for-sentiment-analysis-137d5f5c5fc5?source=collection_archive---------37-----------------------
使用 Python、SQL、AWS understand 和 Tableau 的学*过程

照片由 Unsplash 上的 h heyerlein 拍摄
这学期,我在查尔斯博士的指导下选修了一门名为“开发有意义的指标”的课程。当他提到他正在尝试对 Reddit 评论的庞大数据集进行一些自然语言处理时,我受到了启发。事实上,我的两个同学(Nicole 和 Min Yi)也曾在 Excel 上使用微软 Azure AI 对 Twitter 推文进行情感分析。
所以我和我的同学合作,他的目标是真正改变世界,惠玲,并试图为我们自己做这件事。我们最初假设,Reddit 上的人们通常会以积极的态度发表评论,因为毕竟,Reddit 是一个社区*台,人们可以在这里相互分享他们的想法和故事。我们还认为情绪得分和分数之间存在某种正相关关系(更高的分数=更高的情绪得分)。然而,在我们讨论了寻找错误和批判性思维之后,我们意识到我们可能是错的……这让我们更加渴望投入进去。
技术部分
第一个挑战是下载数据集。我们在 2015 年 5 月的所有 Reddit 评论上发现了一个 30GB 大小的海量数据集!(是的,我知道 Kaggle 上写着 20GB,但证据在下面)

(图片来自作者)
下一步是弄清楚如何打开文件。令人惊讶的是,我这个计算机专业的学生以前从未使用过 SQL,所以在 SQLite 上下载并打开文件对我来说是一种全新的体验。在大量的谷歌搜索和一个关于 SQL 的小型在线速成班之后,我发现 SQL 比我学过的大多数其他语言都要简单得多。数据集的大小也让我大吃一惊,它高达 5400 万行。

数据集的简要视图(图片来自作者)
我们制定了非常非常粗略的计划,但是对于大多数技术细节,我不知道该怎么做。想法是首先过滤数据,然后上传到亚马逊网络服务(AWS)。然后,我会编写一个 Python 脚本来读取数据,将数据发送到Amazon understand进行情感分析,然后再次编译数据。我们将再次下载数据,然后在 Tableau、Excel 或其他可视化工具上执行数据可视化。事情开始看起来不错了…

我知道但也不知道该做什么(图片来自作者)
不对。当我开始过滤数据集(过滤我不需要的列)时,我的下一个挫折出现了。我试图创建表和删除列,结果导致了大规模的崩溃。

许多崩溃中的第一个(图片来自作者)

我存在的祸根(图片来自作者)
作为一个不耐烦的人,我会强制关闭 SQLite。然而,正如我(非常)慢慢了解到的,这将损坏 SQL 文件(或者可能不会,但我没有精力找出原因)。然而,这让我感到困惑和极度沮丧。

我向惠玲发泄我的不满(图片来自作者)
经过几次尝试后,我放弃了过滤数据的尝试,并想知道是否可以直接将文件上传到 AWS 中。不过, AWS RDS 似乎只支持 MySQL、PostgreSQL、MariaDB 等。酪不是。SQLITE。我花了几天时间在谷歌上搜索替代品,但大多数似乎太复杂了。

我在糟糕的时候打扰惠玲(图片来自作者)
并非所有的希望都破灭了。转折点出现在我参加的另一个模块的一次(非常无聊的)讲座中。我意识到我不需要把数据集上传到 AWS,但是我可以把 AWS 带给我。相反,我可以使用 Python 来访问 SQLite 数据库和 AWS understand,然后将结果写入一个新的(干净的)CSV 文件,我们可以用它来进行可视化。

(图片来自作者)
幸运的是,我有使用 Python 的经验,所以编写 Python 脚本相当顺利。首先是连接到 AWS。我有一个现有的 AWS 教育帐户,我用来发送请求到 AWS 理解。在我的机器上本地配置了凭证和 AWS SDK 之后,我能够编写一个函数,它接收一个文本,发送给 intensive,并返回结果。代码的说明很容易从文档中找到。
## script for sentiment analysisdef get_sentiment(text):
comprehend = boto3.client(service_name='comprehend', region_name='us-east-1')
response = comprehend.detect_sentiment(Text=text, LanguageCode='en')
response = dict(response) result = {}
result["sentiment"] = response["Sentiment"]
result["positive"] = response["SentimentScore"]["Positive"]
result["negative"] = response["SentimentScore"]["Negative"]
result["neutral"] = response["SentimentScore"]["Neutral"]
result["mixed"] = response["SentimentScore"]["Mixed"]
result["sentiment_score"] = (result["positive"] - result["negative"]) / 2return result
连接到 SQLite 需要更多的研究。这个链接几乎涵盖了我需要知道的所有内容,我强烈推荐任何在 Python 上尝试 SQLite 的人。
## connect to sqlite databaseconnection = sqlite3.connect("master.sqlite")
print("opened database successfully")
data = connection.execute("SELECT id, subreddit, body, ups, downs, score FROM comments_cleaned")
下一段代码处理了大部分进程。我从编写这部分代码中得到的最大收获是错误处理。在几次执行代码之后,我发现了许多我没有预料到的错误,因此必须适当地处理错误,并重新运行代码。最终,我想到的解决方案是允许用户输入决定跳过(过滤掉)那一行,或者在再次处理那一行之前在本地修复问题,而不中断/终止程序。
with open("comments_with_scores_" + str(NUMBER_OF_ROWS) + ".csv", 'w', newline = '') as file: writer = csv.writer(file) ## create headers
writer.writerow(["id", "subreddit", "body", "ups", "downs", "score", "sentiment", "positive", "negative", "neutral", "mixed", "sentiment_score"])
count = 1
skipped = 0 for row in data: ## get sentiment results
body = row[2]
try:
result = get_sentiment(body) except botocore.exceptions.ClientError as e:
print(e)
result = 'no-go'
while (result != "ok" and result != 'skip'):
print("type 'ok' or 'skip' to continue")
result = input()
if (result == 'skip'):
skipped += 1
print("error occurred with sentiment analysis, skipping row")
continue
result = get_sentiment(body) except:
skipped += 1
print("error occurred with sentiment analysis, skipping row")
continue ## write to csv
try:
writer.writerow([count, row[1], row[2], row[3], row[4], row[5], result["sentiment"], result["positive"], result["negative"], result["neutral"], result["mixed"], result["sentiment_score"]])
print("scanned and accessed data index", count)
except:
skipped += 1
print("bad data, cannot write to csv, skipping row")
continue ## maintain count
if count == NUMBER_OF_ROWS:
break
count += 1
最终,代码产生了数据集。我已经指定了初始大小,以防将来出现问题,因此数据集为 50、500、5000。我们雄心勃勃,希望达到 100 万行,但不幸的是,创建和运行代码太耗时了,而且我的 AWS 会话一直超时并产生更多错误。因此,我们决定处理大约 8000 行,这是我的计算机能够产生的最大行数。在产生 CSV 数据集之后,我把它们发送到惠玲,这样我们可以一起进行可视化工作。
可视化位
有了如此庞大的数据集,我们可以做很多事情。不得不承认,一开始我们有点迷茫。由于只有十几种不同的工具可供我们使用,另外还有十几种表示数据的方式,惠玲和我认真思考了表示数据的最佳方式。我们决定使用 Tableau,并意识到将变量设置为属性/维度/度量将有助于显示不同的含义。
我们绘制的第一张图是情绪对*均分数的曲线图。每条评论的得分是通过从该评论的赞成票数中减去反对票数来计算的。从图中可以看出,情绪消极的 Reddit 回复*均得分最高。也许,人类普遍存在负面偏*,情绪积极的 Reddit 回复也有最低的*均分!我们猜测,我们人类天生消极。我们倾向于更多地关注不好的事情,而忽略好的事情,这可能是进化的结果。批评通常比赞美有更大的影响,坏消息通常比好消息吸引更多的注意力,这可能解释了为什么得分较高的帖子有负面情绪。事实上,经过一些研究,我们发现这种现象被称为“消极偏*”,并且已经被心理学家广泛地研究。

对情感的*均分(图片来自惠玲
我们决定使用 Tableau 中的函数,而不是按*均值排序,我们决定按最大值排序。这张图证明了我们对第一张图的分析,因为负面情绪的评论得分最高,正面情绪的评论得分最低。

反对情绪的最高分(图片来自惠玲
接下来,我们想找出哪个子编辑包含得分较高的评论。因此,如果一个人想在 Reddit 上增加他们的因果报应,也许他们应该尝试回复意想不到的帖子。然而,我们意识到,以这种方式对我们的数据进行排序可能不是最好的,因为“意外”的子编辑在我们的数据集中只有 1 个帖子。不幸的是,使用“*均”测量比使用“总和”测量更好,因为总和通常会因人口规模而产生误导。除了意料之外,subreddit cringepics 的*均分最高。在我们一起浏览了 subreddit 之后,我们意识到,因为大多数帖子应该是有趣的,因此回复是讽刺和幽默的,这可能会导致很多赞成票。

相对于 subreddit 的排序*均分(图片来自惠玲
接下来,我们想要绘制*均情绪分数与*均分数的散点图,看看这两者之间是否有关联。计算情感分数,使得负面帖子的分数接近-1,而正面帖子的分数接近 1。我们希望看到*均情绪得分和*均得分之间的关系,但我们在绘制之后意识到,大多数评论的支持票数很低,因此得分很低,所以得分都集中在 0 分左右。我们意识到,大多数评论不会得到很高的评分,但如果一个人想获得高分,如果他们的话通常带有负面情绪,并发布非传统的东西,他的机会就更大。

相对于*均分数的*均情绪分数(图片来自惠玲)
在下一张图中,我们希望看到哪个子漩涡得分最高。在前面的图表中,我们使用了 measure 函数,因此 Tableau 将为我们提供*均值、总和、最大值、我的值等选项。这一次我们想玩一下维度函数。对于那些不确定两者之间区别的人来说,度量是数学函数处理的数值。另一方面,维度是定性的,并不是总和。我们过滤了分数,这样分数轴将从 300 开始(实际上是试图整理出前几条评论)。如图所示,subreddit AskReddit 的得分最高。

情感得分对比得分(图片来自惠玲)
我们仍然不确定为什么情感分数会是负的,但是我们意识到了情感分析中的一个小缺陷,我们将在后面详细说明。无论如何,AskReddit 会有最高分是可以理解的,因为人们通常会在这个子网站上提出问题,以获得其他 Redditors 的回应。所以得分最高的帖子一定是对别人有帮助的回复。出于好奇,我们找到了评论的正文,它是这样说的:
“我六年级的时候,有个孩子。我会叫他丹尼。丹尼是最优秀的白痴。那孩子整天坐在那里,一脸茫然。有一天我们正在复*人体和消化系统,老师决定给丹尼出一个简单的问题来激励他。她问他我们如何让液体进入我们的身体。丹尼坐在那里,一脸茫然,说“我不知道”。她再次提示他,问他口渴时如何让液体进入体内。丹尼回答,“我不知道。她对这一点感到非常沮丧,甚至问“丹尼,当你口渴时,你是如何让水进入你的身体的?”他回答说,“我不知道。可能,穿过你的皮肤?"
她吓坏了,失去了她的狗屎。他坐在那里,看起来像往常一样茫然,老师夫人冲到房间的后面,抓住了他的胳膊。她把他从座位上拉起来,拖到教室前面,那里有一个水槽。水开了,她把他的胳膊推进河里,不停地对他喊“穿过皮肤??透过皮肤!?你现在感觉怎么样?你吃饱了吗?你得到足够的水了吗?你用嘴喝水!”
我现在快 40 岁了,在我的余生中,我会带着恐惧和娱乐的混合情绪记住那个场景。"
不是我们想的那样,但事后看来,这是一个非常有趣的故事。我们意识到了社交媒体的力量:它有能力将全球各地的人们聚集在一起,打造一种友爱感,甚至只是让孤独的人感到不那么孤独。
这是我们在玩 Tableau 时获得的另一个图表,我们设法获得了前 10 条评论,并查看它们来自哪个子编辑,这是意料之中的,AskReddit。

针对 subreddit 的前 10 名*均分(图片来自惠玲
然而,一般来说,使用情感分析的一个缺陷是,软件扫描单个单词本身,但是两个单独的负面含义的单词放在一起实际上可以表达正面含义。以 id 446 为例:
这个介绍真他妈恶心。
“恶心”和“混账”是两个带有负面含义的词,但当放在一起时,它实际上意味着 Redditor 认为该内容很酷,很有趣。然而,情绪分析认为这是负面的,有 99.68%的信心。因此,我们意识到,虽然情感分析通常有助于获得更广泛的公众意*的概览,但从某种意义上说,它也有缺陷,因为它很难获得短语的总体情感。
结论
我们在 Reddit 上的情感分析终于结束了!那么我们的发现如何作为 有意义的指标 ?我们能够理解 Reddit 用户的态度——大多数人都有负面情绪。这可以帮助刚接触 Reddit 的人在加入之前看看子编辑的极性,这样他们就会知道总体情绪以及他们可以在子编辑中期待什么。我们认为这一点尤其重要,因为 Reddit 是一个社交分享网站。这与我们的下一个观点有关,因为 Reddit 的用户基数如此之大,它可以用来衡量更重要的话题如政治的普遍情绪。或者仅仅用来衡量消费者对投放市场的新产品的体验。
从更宏观的角度来看,我们相信它让我们更好地理解了社交媒体是如何工作的。随着 Reddit 成为一个更具接受性和社会性的*台,我们可以预期社区会更加积极或者更加快乐。然而,我们的研究结果清楚地表明,人们会因为消极或者消极的经历而联系在一起。这从整体上给了我们一个全新的视角来看待人类和社会互动,甚至我们(惠玲和瑞安)是如何成为朋友的。也许我们需要世界上更多的消极。
另外,我们还对 r/dataisbeautiful 只在我们的数据集中出现过一次感到失望:(很遗憾,由于技术限制,我们不能利用整个数据集,因为看到 r/dataisbeautiful 的情感分析肯定会很有趣。
由瑞恩和惠玲共同撰写
TT-SRN:基于变压器的视频实例分割框架
原文:https://towardsdatascience.com/tt-srn-transformer-based-video-instance-segmentation-framework-part-i-ae9964126ac0?source=collection_archive---------19-----------------------
思想和理论
视频领域中的联合目标检测、实例分割、目标跟踪和分类

任意试验视频上 TT-SRN 的示例预测。我们打算指出遮挡、视点变化、重叠对象上的系统伪像以及实例的规模。从左上角到右下角,视觉效果是我们模型的连续预测。(图片由作者提供)
你有 5 秒钟,告诉我 TT-SRN 是什么?
" F ast,基于变形金刚的简单而精确的视频实例分割模块"
TT-SRN 和 VIS 到底是什么?
视频实例分割(VIS)是最近引入的计算机视觉研究,旨在对视频领域中的实例进行联合检测、分割和跟踪。最近的方法提出了实际上无法使用的高度复杂的多级网络。因此,在实践中需要使用简单而有效的方法。为了填补这一空白,我们提出了一种端到端的基于变压器的正弦表示网络(SRN)视频实例分割模块,即 TT-SRN ,以解决这一问题。TT-SRN 认为视觉感知任务是一个单阶段的直接序列预测问题,使我们能够将时间信息与空间信息结合起来。一组视频帧特征由双变换器提取,然后传播到原始变换器以产生一组实例预测。这种产生的实例级信息然后通过修改的 srn 传递,以获得最终实例级类 id 和边界框,以及自参与 3d 卷积,以获得分段掩码。在其核心,TT-SRN 是一个自然的范例,通过相似性学*处理实例分割和跟踪,使系统能够产生快速准确的预测集。TT-SRN 使用基于集合的全局损失进行端到端训练,通过二分匹配强制进行唯一预测。因此,在不牺牲分段掩码质量的情况下,流水线的总体复杂度显著降低。由于双变压器是最快的方法之一,第一次在没有隐式 CNN 架构的情况下解决了 VIS 问题。
我们的方法可以很容易地分成子组件,以产生单独的实例遮罩和边界框,这将使它成为许多视觉任务的统一方法。我们通过比较竞争基准在 YouTube-VIS 数据集上对我们的结果进行了基准测试,并显示 TT-SRN 以显著的优势优于基本 VIS 模型。
代码&纸张可从获得
https://github.com/cankocagil/TT-SPN
图像级目标检测&图像分割版 TT-SRN:
https://github.com/cankocagil/TT-SPN---Object-Detection
行动(或活动、袭击)计划
- 简介
- 相关工作
2.1 图像级实例分割
2.2 视频对象检测
2.3 视频对象跟踪
2.4 视频实例分割 - 建议方法:TT-SRN
3.1 双变形金刚
3.1.1 局部分组自注意(LSA)
3.1.2 全局亚采样注意(GSA)
3.2 经典变形金刚
3.2.1 时空位置编码
3.2.2 变形金刚编码器
3.2.3 变形金刚解码器
3.3【T33 - 结果 4.1 实现细节
4.2。评估指标
4.3。主要结果 - 结论
- 参考文献
1。视频实例分割简介
图像和视频中基于实例的分割和对象检测是计算机视觉领域中的基本问题。与图像实例分割不同,新问题旨在同时检测、分割和跟踪视频中的对象实例[31]。它首先是在视频实例分割论文[31]中用一种称为掩模轨迹 R-CNN 的新算法介绍的。视频实例分割是视频领域时空理解的关键任务,应用于视频编辑、自动驾驶、行人跟踪、增强现实、机器人视觉等等。由于它需要分割和跟踪,因此与图像级实例分割相比,这是一项更具挑战性的任务。此外,它有助于我们将时空原始数据与视频一起编码成有意义的*解,因为与视觉空间数据相比,它具有更丰富的内容。通过在解码过程中增加时间维度,我们可以进一步从视频帧中获得关于运动、视点变化、光照、遮挡、变形和局部模糊的信息。因此,视频实例分割作为一个研究领域越来越受欢迎,并且最近它吸引了沿着视频理解研究路线的社区。

TT-SRN 样本预测(图片由作者提供)
最先进的方法开发了具有多个网络的非常复杂的体系结构..非最大抑制)以产生高质量的分段掩码和边界框。通常,基于检测跟踪(自上而下方法)[31,3,5]或时空嵌入聚类6的方法被提出来处理 VIS 任务。在自上而下的方法中,产生图像级实例分割掩模,然后通过复杂的手工制作的规则在时间维度上关联,以将空间预测推进到时空预测,这使得解码过程变得复杂并导致实际上不可用。而在自下而上的方法中,地层中的实例级像素聚集在时空嵌入空间中,具有不重叠的区域,这些区域严重基于密集预测质量[6],并需要多个网络来产生最终 VIS 结果。因此,简单而有效的、单阶段的、实际可用的和端到端可训练的方法是非常需要的。

TT-SRN 的整体管道。给定视频帧,一组图像特征由双变换器提取,然后传递到经典变换器架构以获得实例级预测。然后,这些预测被传递到单独的 SRN 分支,以产生一组类别 id、置信度、边界框和自参与卷积,从而获得分段掩码。整体预测遵循视频帧顺序。(图片由作者提供)
在本文中,我们提出了一种新的方法,即 TTSRN,以降低整体流水线的复杂性,而不影响预测的速度和质量,以产生 VIS 结果。整个流水线如图 1 所示。给定视频帧,一组图像特征由双变换器提取,然后传递到经典变换器架构以获得实例级预测。然后,这些预测被传递到单独的 SRN 分支,以产生一组类别 id、置信度、边界框和自参与卷积模块,从而获得分段掩码。实际上,VIS 的所有子任务(分类、检测、分割和跟踪)都是相关的任务。因此,一个任务的输出可以向另一个任务提供重要信息,这将相互促进所有子模块。通过认识到这一点,在一个模块中处理子任务的范例也促进了 TT-SRN。同时,由于没有人为设计的规则用于 VIS 的所有单个任务,实例级特征质量是 TT-SRN 的另一个重要部分,它由 twin transformer 模块完成。Twin transformer 是一种基于面向空间的视觉转换器的最新架构,最近在论文[9]中提出。从 NLP [28]上下文中的经典 transformers 出版物来看,transformers 实际上是用于各种 NLP 任务的方法(例如,机器翻译和序列间问题)。
论文[11]首次提出了视觉变形金刚,展示了变形金刚在计算机视觉领域的强大功能。然而,问题是计算复杂度是图像大小的*方。为了抑制,提出了各种视觉变压器,并证明了精心设计的全局和局部注意机制可能在密集预测任务中胜过经典 CNN 架构[11,27,9]。一种解决方法是局部分组的自我关注(或在非重叠窗口中的自我关注,如最近的 Swin Transformer [20]),其中输入在空间上分组为非重叠窗口,并且仅在每个子窗口中计算标准自我关注[9]。即使 Swin 变换器降低了总的计算复杂度,它也不能通过注意力在非重叠区域之间建立连接。为了克服这一点,在论文[9]中提出了双变压器,其引入了空间可分离的自我注意(SSSA)来缓解这一挑战。SSSA 由局部分组自我注意(LSA)和全局亚采样注意(GSA)组成[9]。我们发现由双变压器产生的实例级特征相对于它们在传统 CNN 中的对应物是高度优化的。
这里,我们还介绍了用于分类和对象检测任务的改进的正弦表示网络。在论文[25]中提出了正弦表示网络,并证明了由神经网络参数化的隐式定义的、连续的、可微分的信号表示已经成为一种强大的范例,提供了超过传统表示的许多可能的好处[25]。他们为隐式神经表示引入了杠杆周期激活 2 函数,并证明了这些被称为正弦表示网络或塞壬的网络非常适合表示复杂的自然信号及其衍生物[25]。在本文中,我们调整了 SIREN 架构以用于密集预测任务,并对其进行了修改以重新用于包围盒和类 id 预测。我们改进的 SRN 网络由多个具有漏失的 SIREN 层组成。作为 SRNs 的最后一层,放置具有 GELU 非线性的全连接层[15]以产生最终结果。SRNs 的拟议架构如图 2 所示。实例分割和跟踪是 VIS 任务的其他重要方面。
“为了执行自然、有效且相互包容的分割和跟踪”,我们改编了来自 VisTR [29]的实例序列匹配和跟踪模块。“实例序列匹配在输出实例序列和基本事实实例序列之间执行二分图匹配,并监督唯一分配预测及其注释的序列”[29]。
因此,TT-SRN 可以直接保持预测的顺序[29]。“实例序列分割通过自关注在多个帧中累积每个实例的掩模特征,并通过 3D 卷积分割每个实例的掩模序列以获得最终结果”[29]。
我们的主要贡献总结如下。
- 我们提出了一种高效的视频实例分割模块,该模块基于视觉和具有正弦表示网络的经典变压器,将视觉任务视为端到端的集合预测问题。
- 据我们所知,这是第一次在没有任何隐式 CNN 架构的情况下解决视频实例分割问题,而是使用视觉变压器(例如,双变压器)作为实例级特征生成器。
- 在没有任何编织的情况下,TT-SRN 是最快的方法之一,可以以 55.3 FPS 的速度运行,并在 YouTube-VIS 上实现了 39.3 %的竞争精度,远远超过了 VIS 基线模型。
2.视频实例分割的相关工作
在文献中有各种方法用于解决视频实例分割的任务,因为它通常被认为是多阶段问题,即分割/检测和跟踪组件在不同阶段被处理。然而,最近的研究提出了单阶段、简单、计算有效的方法来处理该问题,尽管单阶段方法的性能并不比多阶段方法好。因此,计算机视觉研究社区通过提出掩模轨迹 R-CNN 的变体或视频实例分割任务的新方法,扩展了论文[31]中所做的工作。STEm-Seg 是针对此任务的另一种新算法,特别是,他们将视频剪辑建模为单个 3D 时空体,并提出了一种在单个阶段中跨空间和时间分割和跟踪实例的新方法[1]。

VIS 数据注释和预测[31]
然后,Chung-Ching Lin 等人提出了一种用于视频实例分割任务的基于变分自动编码器的分割跟踪算法,因为它构建了一个共享编码器和三个并行解码器,产生了用于预测未来帧、对象检测框和实例分割掩模的三个不相交分支[16]。为了促进对该问题的研究,曹等人提出了另一种称为 SipMask 的单阶段新算法,该算法通过将实例的掩模预测分离到检测到的边界框的不同子区域来保留实例特定的空间信息[6]。然后,VisTR 被提议为基于单级变压器的 VIS 架构,其将 VIS 任务视为直接的端到端并行序列解码/预测问题[29]。我们的一些工作改编自 VisTR 模块。具体来说,我们集成了他们的实例序列匹配和分段模块,以监督和分段完整的实例。实例序列匹配在输出实例序列和实际实例序列之间执行二分图匹配,并监督 TT-SRN,因此 TT-SRN 学*实例之间的相似性[29]。实例序列分割模块执行自参与 3-D 卷积来学*像素级相似性。因此,有各种不同的方法来解决时间域实例级分割问题,在本文中,我们提出了解决视频实例分割问题的方法,因为我们认为它是预测问题的直接集合。即使视频实例分割的概念可以被归类为新的任务,在文献中也有研究者解决的各种类似问题,例如图像级实例分割、视频对象检测、视频对象跟踪和视频对象分割。我们将类似问题简述如下。
2.1。图像级实例分割
实例分割不仅将像素分组到不同的语义类中,还将它们分组到不同的对象实例中[12]。通常采用两阶段范式,首先使用区域提议网络(RPN)生成对象提议,然后使用聚合 RoI 特征预测对象边界框和遮罩[12]。在我们的例子中,我们不仅为个体生成分割模板,还将它们在视频序列中关联起来。

实例分割示例(https://www . researchgate . net/figure/Instance-Segmentation-in-a-open-set-environment-Our-method-segments-all-image-regions _ fig 1 _ 325557020)
2.2。视频对象检测
视频对象检测旨在检测视频中的对象,这是作为 ImageNet 视觉挑战的一部分首次提出的[24]。即使关联和提供身份提高了检测质量,这种挑战也仅限于用于每帧检测的空间保留的评估度量,并且不需要联合对象检测和跟踪[31]。然而,在我们的情况下,我们的目标是联合检测、分割和跟踪,而不是视频对象检测任务。

视频对象检测示例(https://miro . medium . com/max/840/1 * TQ 9 potwer 93 jwfte 56 u8 aa . gif)
2.3。视频对象跟踪
视频目标跟踪任务通常被认为是基于检测和无检测的跟踪方法。在基于检测的跟踪算法中,联合检测和跟踪对象,以便跟踪部分提高检测质量,而在无检测方法中,我们给出一个初始边界框,并尝试跨视频帧跟踪该对象[26,31]。由于基于检测的方法类似于我们的情况,视频实例分割需要时间分割掩模。因此,与以前的基本计算机视觉任务相反,视频实例分割需要多学科和综合的方法。

视频对象跟踪示例(https://I2 . WP . com/github . com/yehengchen/video _ demo/raw/master/video _ demo/TownCentreXVID _ output . gif?w=450 & ssl=1
2.4。视频实例分割
由于视频实例分割任务是受监督的,因此它需要面向人的高质量注释,用于边界框和具有预定义类别的二进制分割遮罩。设 Ci 是属于数据集 D 的对象类别,i = 1,…,K,其中 K 是 D 中包括背景的唯一类别的数量。然后,设 B ti j 和 S ti j 是视频帧 ti ∈ T 中第 j 个 C1,…,CK 对象的第 j 个边界框和二进制掩码,其中 T 表示给定视频序列中的帧数。假设在推理阶段,VIS 算法产生 N ∈ C1,…,CK 实例假设,使得 H ti Nj 表示 VIS 产生的第 N 个 j 实例和第 t 次的预测。因此,H ti Nj 包括置信度得分 s ti j ∈ [0,1]作为识别具有预定义类别、B ti j 和 s ti j 的实例的概率。

视频实例分割示例(图片由作者提供)
3.提议的方法:TT-SRN
我们提出了一个端到端的基于变压器的视频实例分割模块与正弦表示网络(SRN),即 TT-SRN,以解决视觉感知任务。我们的方法,TT-SRN,将 VIS 任务视为单一状态下的直接预测问题集,使我们能够将时间信息与空间信息聚合在一起。一组视频帧特征由双变换器提取,然后传播到原始变换器以产生一系列实例预测。这些由变换器产生的实例级信息然后通过修改的正弦表示网络,以获得最终的实例级类 id 和边界框,以及自参与的 3-D 卷积,以获得分段掩码。在其内部机制中,TT-SRN 是一个自然的框架,它通过相似性学*来处理跟踪和分割,使系统能够产生一组快速而准确的预测。实例序列匹配算法改编自[29]以跨视频帧跟踪实例。TT-SRN 使用基于集合的全局损失进行端到端训练,通过二分匹配强制进行唯一预测。因此,在不牺牲分段掩码质量的情况下,流水线的总体复杂度显著降低。由于双变压器是最快的方法之一,第一次在没有隐式 CNN 架构的情况下解决了 VIS 问题。我们的方法可以很容易地分成子组件,以产生单独的实例遮罩和边界框,这将使它成为许多视觉任务的统一方法。在本节中,TT-SRN 被划分为子模块,并对其进行了详细描述。
3.1。双变压器
最近,在论文[9]中提出了 twins,并证明了空间定向视觉变换器可以优于经典的 CNN[9]。这里,我们将 Twins-SVT 网络集成到我们的案例中,以产生实例级的特性。他们的孪生转换器基于空间可分离的自我注意(SSSA)网络,该网络由局部分组自我注意(LSA)和全局子采样注意(GSA)组成[9]。由于其空间上可分离的模块,功能的质量大大提高。在小节中,我们将详细描述 SSSA 模块。
3.1.1 局部分组自我注意(LSA)
在 LSA,2-D 特征地图被分成子窗口,使得能够在每个子窗口内自我关注。特征图被分成 m×n 个子窗口,这导致每 4 个窗口由 HW mn 元素组成,其中 H,W 表示图像维度。通过将图像划分成 m×n 个区域,计算成本从 O(H * W * d)降低到 O( H W /(mn) *d),其中 d 是自我注意维度。在这一点上,我们没有对窗口中不重叠的区域做任何进一步的关联。因此,GSA 模块开始发挥作用。

正弦表示网络的体系结构。它由两个警笛层和一个额外的全连接层组成,具有 GELU 激活功能。(图片由作者提供)
3.1.2 全局子采样注意(GSA)
因为我们需要在自我注意机制中进一步定位,所以需要全局自我注意来在非重叠区域中建立连接。在 GSA 模块中,来自本地参与窗口的单个代表性关键信息被用于计算全局注意力。然而,随着全局注意的计算,计算成本将增加到 O(H *W *d)。为了防止这种情况,通过*均池、深度方向的步长卷积和规则步长卷积对局部参与特征进行子采样。结果表明,规则步长卷积性能最佳[9]。数学上,SSSA 模块执行以下计算。

对于 i = 1,…,m 和 j = 1,…,n 其中 LSA 表示局部分组自我注意,GSA 表示全局子采样注意,FFN 表示前馈网络,LayerNorm 表示层归一化层[2]。两个注意力模块都以多头方式进行。

双变压器的架构[9]
3.2。经典变形金刚
具有 6 个编码器层、6 个解码器层以及 GELU 激活[15]的经典变换器架构适于执行基于实例的查询生成。传统转换器的输出是实例的建议加上额外的无对象查询。该转换器的使用非常类似于对象检测模型 DETR [7]中的转换器。在训练期间,执行二分匹配,通过唯一地将预测与基础事实分配来监督模型。没有匹配的预测应该产生“无对象”类预测,因此实例查询的数量应该大于视频帧中实例的数量。转换器的核心由编码器和解码器结构组成,这将在下面的小节中讨论。
3.2.1 时空位置编码
由于变换器架构是置换不变的,因此时空位置编码对于精确位置信息的建模是必要的。时空位置编码基于正弦波,并且是经典位置编码的 3d 版本。我们的位置编码有 3 个不同的维度,即时间、水*和垂直。设 d 为最终级联的信道位置编码维数,那么我们独立地使用具有不同频率的 d/3 正弦函数如下

其中 w_k = (1/10000)^(2*k/ (d /3)),pos 是该维度中的位置。与传统的位置编码一样,这些三维位置编码被添加到输入中。
3.2.2 变压器编码器
大小为 6 的变换器编码器层适于学*实例方面的相似性,该相似性稍后将被传播到解码层以产生最终的实例级查询。从双变换器提取的特征被传递到具有 256 个输出潜在大小的单个卷积层。因此,到变换器编码器的输入是 R^(NxLxHxW 的形状,其中 n 是批量大小,l 是潜在大小,h 和 w 是单个卷积层输出的高度和宽度。请注意,时间顺序是根据输入顺序保留的。每个编码器层像常规一样执行多头自关注机制。
3.2.3 变压器解码器
然后,编码特征序列通过变换器解码器层,以产生实例查询预测序列。在这一层,一系列可学*的实例查询也被传递到解码器层。实例查询是固定数量的输入嵌入,以表示实例预测的总数。为了安全起*,实例查询的数量总是大于映像中实例的数量。二分匹配独特地执行实例式分配,暴露的预测被称为“无对象查询”。例如,假设我们在帧 t 中产生 n_t 个实例预测,那么让 q 是一般实例查询的大小,使得在所有帧中 q > n_t。
3.3。正弦表示网络
正弦表示网络是最近在论文[25]中提出的表示学*方法。正弦层由完全连接的层组成,其独特的初始化在具有正弦激活层的论文[25]中介绍。整体架构如图 2 所示。在这项工作中,我们针对我们的情况修改了它们的架构,在具有端 GELU 非线性的正弦层之间添加内部压差层[15],以产生实例级端特性。这些最终特征然后被传播到分类、包围盒检测和实例分割分支。我们意识到隐式神经表示的周期性激活,并证明这些网络,被称为正弦表示网络或塞壬,非常适合密集的预测任务。我们的消融研究表明,末端预测层的周期性激活函数可以适用于密集预测任务。
3.4。实例序列匹配
TT-SRN 的一个重要方面,即实例序列匹配,改编自文献[29],通过二分匹配将实例预测与基础事实唯一地分配,以监督模型。此外,该模块使我们能够推断出预测实例的精确顺序,该顺序随后能够跨视频跟踪实例。匹配损失既考虑了类别预测,也考虑了预测值和实际值的相似性[7]。设 y 表示地面真实盒子对象集,y∞= ˜y^n_i=1 n 个预测集。我们的损失产生了预测和基本事实之间的最佳二分匹配。为了计算两个集合之间的二分匹配,计算以下最小化。

其中 L_match(y_i,y _σ\( I))是基础事实和预测之间的实例匹配成本。这个分配问题是用匈牙利方法计算的,匈牙利方法是一种组合优化算法,在多项式时间内解决分配问题[7]。匹配过程考虑了类别预测以及预测和基本事实框的相似性。设注释的每个元素 I 由 y_i = (c_i,b_i)表示,其中 ci 是目标类,bi 是向量,表示基本事实归一化坐标。这些坐标被组织为中心、高度和宽度,并且它们与图像大小相关。然后,对于索引为σ(i)的预测,设\u p _σ(I)(ci)表示类别概率,\u b _σ(I)为预测盒。因此,我们可以定义 Lmatch(y_i,y _σ\( I))如下。

这个过程监督一个模型,并在启发式分配过程中发挥重要作用。在经典的对象检测或实例分割任务中(如 Mask RCNN [13]),这些程序是匹配建议的对应物或基础事实的锚。与经典方法显著不同的是,二部匹配唯一地分配。在这一点上,我们分配了预测和它们的基本事实,所以我们需要计算损失,在我们的例子中,所有匹配对的匈牙利损失。给定一对一分配,匈牙利损失将损失计算为类预测的负对数似然、盒和实例序列的掩膜损失的线性组合,如下所示。

其中σ\是之前计算的最佳分配。该损失用于以端到端的方式训练模型。接下来,我们需要定义 L_box 和 L_mask。L_box 的计算类似于 DETR [7]中的计算,如下所示。

其中,λ_IoU 和λ_L1 是超参数。请注意,损失随着框架内实例的数量而标准化。
3.5。实例序列分割
TT-SRN 的另一个重要方面,即实例序列分割模块,改编自论文[29]以产生末端分割掩模。在内部,该模块累积帧的实例特征,然后对这些累积的特征执行分割。对于每个帧,由变换器的末端解码器层收集的实例预测和由变换器的末端编码器层收集的变换器编码特征通过自关注模块。这些被关注的特征然后与由双变换器收集的特征和从变换器的末端编码器生成的编码特征融合。这个过程与维斯托[29]和 DETR [7]的情况非常相似。然后,具有不同大小的实例级特征被馈送到可变形卷积层[10],该可变形卷积层利用额外的偏移来增加模块中的空间采样位置,并从目标任务学*偏移,而无需额外的监督[10]。然后,呈 R^(1xCxTxtHxW 形状的融合图(其中 c 是通道维度,t 是时间维度,h 和 w 是空间特征维度)被馈送到具有组归一化[30]和 GELU 非线性[15]的 3d 卷积层中。在末端层,单个卷积层具有 1 个输出信道维度,用于获得分段掩码。最后,我们需要定义 Lmask 来完成损失函数。L_mask 通过组合 dice [22]和聚焦损失[18]计算如下。

4.TT-SRN 结果
在本节中,我们在 YouTubeVIS 数据集上展示了我们的结果[31]。YouTube-VIS 是一个大型可扩展数据集,包含 2,883 个高分辨率 YouTube 视频、2,238 个训练视频、302 个验证视频和 343 个测试视频。类别标签集包括 40 个常*对象,如人、动物和车辆,总共有 4,883 个独特的视频实例,产生 131k 高质量的面向人的注释。因为测试集的评估是封闭的,所以评估结果基于验证集。4.1.
4.1 实施细节
我们继承了 TT-SRN 第一级双变压器[9]中使用的超参数。因此,嵌入维数被选择为 64,块大小为 4,局部块大小为 7,深度为 1。同样,双变压器第二级的超参数是 128,2,7,1。对于第三阶段,选择 256,2,7,5 作为第三阶段的超参数。在最后阶段,嵌入大小为 512,块大小为 2,局部块大小为 7,深度为 4。这里,深度是指“双变压器”部分描述的变压器模块数量。请参考图??。单个卷积层的隐藏大小被选择为 256。在经典变压器中,有 6 个编码层和 6 个解码层,多头大小为 8。在所有编码器-解码器中,变压器模块的内部激活是 GELU [15]。在 SRN 阶段,退出概率选择为 0.2。所有 SRN 层都使用论文[25]中描述的专用初始化方案进行初始化。那么,YouTube-VIS 中带注释的视频长度的最大数是 36 [31],我们选择这个值作为输入视频长度。因此,不需要后处理来关联来自一个视频的不同剪辑。通过这种方式,我们的模型可以在单个阶段中进行端到端的训练。因为我们的模型预测每个视频帧有 10 个对象,所以我们将查询数设置为 360。TT-SRN 是通过 PyTorch 1.8 实现的[23]。由于其简单的构建模块,TT-SRN 可推广和扩展到其他框架和视觉任务。我们还在我们的项目页面上提供单独的 TT-SRN 实例分割和对象检测版本。

表 1:YouTube-VIS 上的视频实例分割图(%)结果[31]。结果是从他们的论文中获得的。
在训练阶段,我们使用 AdamW [21]优化所有层,从 1e-4 的学*速率开始,每 3 个时期衰减 0.1。TT-SRN 用 18 个历元进行训练,批量大小选择为 16。传统的变压器权重由 COCO [19]中预先训练的 DETR [7]初始化。所有视频帧都按照每个通道的方式用 ImageNet *均值和标准偏差值进行标准化。然后,将所有视频帧的大小调整为 300 x 540,以适合 GPU。我们仅使用概率为 0.5 的随机水*翻转作为视频数据增强。TT-SRN 在一个 8GB RAM 的 Tesla K80 GPU 上训练 5 天。
在推理阶段,TT-SRN 结构没有变化。因此,我们的模型的训练和推理形状是完全相同的。此外,不需要手工制作的后处理来跨视频帧关联实例。我们将阈值设置为分数高于确定阈值的保留实例,以获得最终结果。我们将这个阈值设置为 0.6。在视频帧中有一些实例被识别为不同的类。那时,我们使用最频繁预测的类别。
4.2 评估指标
使用图像实例分割中的标准评估指标进行评估,并根据我们的新任务进行修改[31]。具体来说,指标 8 是各种条件下的*均精度(AP)和*均召回率(AR) [31]。AP 被定义为精确度-召回曲线下的面积[31]。置信度得分用于绘制曲线。AP 是多个交集合并(IoU)阈值的*均值[31]。*均回忆描述了回忆-IoU 曲线下加倍的区域。作为有条件的 AP 和 AR,我们遵循 COCO 评估程序,因为它需要 10 个 IoU 阈值,从 50%到 95%,在步骤 5%。由于我们在视频领域,我们需要在评估中包括时间一致性,例如,即使模型产生成功的分割,如果它未能跟踪实例,则表明性能不佳。因此,我们的 IoU 计算不同于图像实例分割,因为每个实例都包含一个掩模序列[31],因此 IoU 计算通过在视频帧之间累加 IoU 而扩展到一批视频帧。IoU 计算如下。在这里,mi_t 代表基本事实,m˜i_t 代表假设。

4.3 主要结果
我们在 YouTube-VIS 上比较了 TT-SRN 和 VIS 中其他最新方法的速度和准确性。由于我们的方法是单阶段和端到端可训练的,我们优先将我们的方法与单阶段和端到端可训练的方法进行比较。我们将 TTSRN 与 Mask Track R-CNN [31]、MaskProp [3]、VisTR [29]和 STEm-Seg [1]进行了比较。结果总结*表 1。在没有任何编织的情况下,TT-SRN 是最快的方法之一,在单个 GPU 中以 55.3 FPS 的速度运行,并通过大幅超越 VIS 基线模型,在 YouTube-VIS 上实现了 39.3 %的竞争精度。就速度而言,TT SRN 在最先进的 VIS 模型中名列第二。就速度而言,目前的赢家是 VisTR [29],因为它使用 ResNet-101 [14]主干网运行速度为 57.7,使用 ResNet-50 主干网运行速度为 69.9。在速度方面,TT-SRN 比当前的 VIS 基线模型 Mask Track R-CNN(运行速度为 20.0 FPS)快很多。这种差异源于 TTSRN 的简单的基于注意力的机制,该机制需要最少的步骤来产生 VIS 预测。另一种竞争方法 STEm-seg 以 2.1 FPS 运行,这对于实时目的来说是非常不可用的。他们的论文中没有提到 MaskProp 的速度[3]。请注意,数据加载和预处理步骤时间不包括在上述结果中。在准确性方面,TT-SRN 远远优于掩模轨道 R-CNN,因为我们的模型在 YouTube-VIS 的验证集上获得了 39.3 %的地图分数,而掩模轨道 R-CNN 获得了 30.3 %的地图分数。这一显著优势源于 TTSRN 的结构,该结构由所有组件中最先进的方法组成。此外,TT-SRN 也大幅超过 STEmseg,因为 STEm-seg 在 ResNet-101 主干上获得了 34.6 %的 mAP 分数。由于 TT-SRN 与 VisTR 相似,具有 ResNet-101 骨架的 VisTR 比 TT-SRN 多 0.8 %的图谱分数,而 TT-SRN 比具有 ResNet-50 骨架的 VisTR 多 3.1 %的图谱分数。目前的获胜者,MaskProp 获得了 46.6 %的 mAP 评分,远远超过了 TT-SRN。TT-SRN 和 MaskProp 之间的差距源于 MaskProp 的多网络设计,它由时空采样网络[4]、特征金字塔网络[17]、混合任务级联网络[8]和高分辨率掩模细化后处理[3]组成。作为最简单的 VIS 架构之一,TT-SRN 在所有竞争对手中取得了最快和最准确的结果。此外,TT-SRN 可以很容易地划分为子组件,以执行单独的 VIS 任务,即对象检测、实例分割和分类。这使得我们的方法简单、统一和实时,而不牺牲实例掩码的质量。
5。结论
在这篇文章中,我们提出了一个端到端的基于正弦表示网络(SRN)的视频实例分割模块,即 TT-SRN,以解决视频实例分割任务。TT-SRN 将 VIS 任务视为单一状态下的直接序列预测问题,使我们能够将时间信息与空间信息聚合在一起。为了产生从视频帧中提取的高质量特征,我们利用了双变压器。经典变换器用于产生一系列实例预测,这些预测随后通过改进的正弦表示网络得到最终结果。TT-SRN 是一种自然范式,通过相似性学*处理跟踪,使系统能够产生快速准确的预测集。利用基于集合的全局损失来端到端地训练 TT-SRN,该全局损失通过二分匹配来强制进行唯一的预测,从而在不牺牲分段掩码的质量的情况下降低流水线的总体复杂度。由于双变压器是最快的方法之一,第一次在没有传统 CNN 架构的情况下解决了 VIS 问题。我们的方法可以很容易地分成子组件,以产生单独的实例遮罩和边界框,这将使它成为许多视觉任务的统一方法。我们认为,视频实例分割是视频理解领域的一项关键任务,将革新计算机视觉研究社区。我们的项目页面位于https://github.com/cankocagil/TT-SRN,TT-SRN 的单独检测/分割版本位于https://github.com/cankocagil/TT-SRN—-对象检测。
参考
[1] A. Athar、S. Mahadevan、A. Osep、L. Leal-Taix ˇ e 和 B. Leibe。Stem-seg:视频中实例分割的时空嵌入,2020 年。
[2]巴、基罗斯和辛顿。图层归一化,2016。
[3] G. Bertasius 和 L. Torresani。分类、分割和跟踪视频中的对象实例与掩模传播,2020。
[4] G. Bertasius、L. Torresani 和 J. Shi。时空采样网络视频中的对象检测,2018。
[5] A .比雷、z .格、l .奥特、f .拉莫斯和 b .乌普克罗夫特。简单的在线和实时跟踪。2016 年 IEEE 图像处理国际会议(ICIP),2016 年 9 月。
[6]曹国伟、安维尔、乔拉卡尔、汗、庞和邵。Sipmask:快速图像和视频实例分割的空间信息保存,2020。
[7] N .卡里翁、f .马萨、G. Synnaeve、N. Usunier、a .基里洛夫和 S. Zagoruyko 利用变压器进行端到端物体检测,2020 年。
[8]陈光诚、庞俊杰、王俊杰、熊毅、李、孙、冯、刘志军、史俊杰、欧阳俊杰、刘春春和林。用于实例分割的混合任务级联,2019。
[9]朱晓东、田志军、王永庆、张、任、魏、夏、沈春华。双胞胎:重新审视《视觉变形金刚》中空间注意力的设计,2021。
[10]戴军、齐、熊、李、张、胡、魏。可变形卷积网络,2017。
[11] A. Dosovitskiy,L. Beyer,a .,D. Weissenborn,X. Zhai,T. Unterthiner,M. Dehghani,M. Minderer,G. Heigold,S. Gelly 等.一幅图像抵得上 16x16 个字:大规模图像识别的变形金刚.arXiv 预印本 arXiv:2010.11929,2020。
[12] B. Hariharan,P. Arbelaez,R. Girshick 和 J. Malik。同时检测和分割,2014 年。
[13] K. He,G. Gkioxari,P. Dollar 和 R. Girshick。面具 r-cnn,2018。
[14]何国光、张晓松、任少宁和孙军。图像识别的深度残差学*,2015。
15d .亨德里克斯和 k .金佩尔。高斯误差线性单位(gelus),2020。
[16]林振中、洪耀桢、费里斯和何立波。基于改进的 vae 架构的视频实例分割跟踪。IEEE/CVF 计算机视觉和模式识别会议(CVPR)的会议录,2020 年 6 月。
[17]林光宇、杜大伟、吉希克、何、哈里哈兰和贝隆吉。用于对象检测的特征金字塔网络,2017。
[18]t-y Lin、P. Goyal、R. Girshick、K. He 和 P. Dollar。密集物体探测的焦点损失,2018。
[19] T.-Y .林、m .梅尔、s .贝隆吉、l .布尔德夫、r .吉尔希克、j .海斯、p .佩罗娜、d .拉马南、C. L .兹尼克和 p .杜尔达。微软 coco:上下文中的常*对象,2015。
[20]刘振中,林永安,曹永安,胡海红,魏永安,张振中,林绍林,郭。Swin transformer:使用移位窗口的分层视觉转换器。arXiv 预印本 arXiv:2103.14030,2021。
[21] I. Loshchilov 和 F. Hutter。解耦权重衰减正则化,2019。
[22] F .米莱塔里、n .纳瓦布和 S.-A .艾哈迈迪。V-net:用于体积医学图像分割的全卷积神经网络,2016 年。
[23] A. Paszke、S. Gross、F. Massa、A. Lerer、J. Bradbury、G. Chanan、T. Killeen、Z. Lin、N. Gimelshein、L. Antiga、A. Desmaison、A. Kopf、E. Yang、Z. DeVito、M. Raison、A. Tejani、S. Chilamkurthy、B. Steiner、L. Fang、J. Bai 和 S. Chintala。Pytorch:命令式风格,高性能深度学*库,2019。
[24]鲁萨科夫斯基、邓、苏、克劳斯、萨特西、马、黄、卡帕西、科斯拉、伯恩斯坦、伯格和。2015 年 Imagenet 大规模视觉识别挑战赛。
[25] V. Sitzmann、J. N. P. Martel、A. W. Bergman、D. B. Lindell 和 G. Wetzstein。具有周期性激活功能的隐性神经表征,2020。
[26] J. Son、M. Baek、M. Cho 和 B. Han。基于四元组卷积神经网络的多目标跟踪。2017 年 IEEE 计算机视觉和模式识别大会(CVPR),第 3786–3795 页,2017。
[27] H. Touvron、M. Cord、M. Douze、F. Massa、A. Sablayrolles 和 H. Jegou。训练数据有效的图像转换器&通过注意力进行提炼。arXiv 预印本 arXiv:2012.12877,2020。
[28] A. Vaswani、N. Shazeer、N. Parmar、J. Uszkoreit、L. Jones、A. N. Gomez、L. Kaiser 和 I. Polosukhin 你只需要关注,2017。
[29]王延东、徐志勇、王晓东、沈春华、程炳良、沈海涛和夏。《变形金刚》端到端视频实例分割,2021。
[30]吴彦祖和何国光。群体常态化,2018。
[31]杨立群、范友林和徐。视频实例分割,2019。
在 Amazon SageMaker 上,通过完全的可*性和控制,将您的深度学*模型调整到最高精度
原文:https://towardsdatascience.com/tune-your-deep-learning-models-to-the-highest-accuracy-on-amazon-sagemaker-with-complete-bb38d1e96b5f?source=collection_archive---------21-----------------------
这篇文章是 AWS 的 SageMaker 月的一部分!我们的日历可在此处获得 —浏览以找到实践研讨会、专用工具和入门资源,从而提高您的数据科学团队的工作效率。这篇文章也是我即将在六月—AWS ML 峰会上进行的关于模型调优的会议的同伴,现在已经开始注册了!

郁金香“花园郁金香”
春天的芳香——当我们星球的北半球迎来更长更温暖的春天时,园艺成为 7000 万美国家庭的主要活动。对于好奇的种植者来说,花园提供了试验的机会。从新的种子类型到施肥策略、养护和修剪,园艺在某种意义上是科学过程的缩影。园丁们发展出一种假设,关于他们如何思考或希望他们的植物会如何发展,然后在观察实验存活或死亡时改进这些假设——毫不夸张。拥有更大庭院空间的房子提供了充分的机会来发展一个人的园艺技能,最终的限制是简单的地理条件。你的院子只有这么大,你的室友只能处理这么多新植物。
在机器学*中,我们应用类似的过程,在尝试解决现实世界或理论用例时探索计算和统计模型。我们对模型、方法和过程进行实验,以将尽可能多的关于用例的知识注入模型本身,随着我们的迭代,开发出越来越好的执行模型。
超参数调整是一个经典步骤,数据科学家和 ML 工程师可以用它来尝试提高他们模型的性能。与园艺一样,数据科学团队的一大优势是实验能力。但是这里是类比的终点——你只能在你的院子里有多少物理空间就种多少种子,而你可以在云中运行你能想象的多少实验。
这对于重新训练和重新调整管道特别有吸引力。当您有一个部署的模型为您的应用提供预测响应时,确保该模型保持最新的一个简单方法是首先 监控该模型的数据、质量和偏差漂移 。一旦您被警告您的模型是最新的,您就可以自动地重新训练和调整您的模型,使用与原始工件相同的 ETL 和训练脚本,但是使用更新的数据集来更新它。
在这个例子中,我们将在经典的 MNIST 数据集上调整我们自己的 PyTorch 模型。我们将启用新推出的数据并行包,在高级 GPU 上运行,通过使用 spot 实例节省 70%,并通过使用自动模型调整找到我们可以找到的最佳模型。
我们潜进去吧!
评估 ML 模型的多种方法
显而易*,有许多方法可以评估机器学*模型。当严格考察我们的模型产生的预测的质量时,第一步是将我们的模型的预测与来自我们的真实数据集的预测进行比较。当然,通常这些实际上是在来自更大数据集的不同样本或分割上完成的。

虽然准确性是一个吸引人的术语,一个容易被我们的非专业业务利益相关者联系和理解的术语,*准确性本身可能是高度误导的。*这是因为上面显示的精确度公式很容易受到等级不*衡的影响。
这意味着,如果你的数据集正面数据比负面数据多得多,你的模型可能会偏向其中一个方向。这也意味着准确性不适合你。
这在金融交易诈骗案件中尤为明显。假设你正在解决一个信用卡诈骗案。你每天有数百万到数十亿笔交易,其中不到 1%的交易是欺诈性的。如果您调整您的模型并选择准确性,您可能最终达到 99%的准确性,但仍然没有发现欺诈案例。那是因为你的真实负利率太大了,以至于抵消了精度方程中分子的大部分影响。如果您只将准确性作为您的评估标准,您将错过这一关键步骤,并可能部署一个提供零价值的模型。
在构建超参数调优作业时,确保选择对您的用例最有意义的调优指标。如有疑问,选择一个中性指标,如 AUC 或 F1。
作为 AWS 结构的培训工作
在 AWS 上,我们喜欢为客户提供*弹性计算。*这意味着您不必等待数周甚至数月,等待高级 GPU 的到来,或者等待数据中心资源来安装、堆叠和配置服务器,或者等待您的模型在笔记本电脑上完成培训。您只需打开 web 浏览器,启动一个实例,然后开始行动。
在机器学*中,这变得有价值的一个很大的方式是**用于运行训练工作。**培训作业是 SageMaker 服务系列中的一个专用实例或实例集群,用于托管您的代码和数据。

使用 SageMaker 中的培训作业运行大规模分布式作业,如高分辨率计算机视觉、3D 点云分类、基于多模态转换器的模型、文本生成、强化学*和无数其他应用。
您可以插入我们新推出的分布式训练工具包、如模型并行,训练数百亿参数的模型。通过使用 EFA 将基于 NCCL 的通信协议替换为针对 AWS 网络拓扑优化的协议,您可以使用数据并行将这些模型的运行时间加快 20–40%。
更好的是,您可以通过使用托管 spot 实例**为每个作业节省高达 90%的成本。*只需在您的工作配置中添加一些额外的参数,如use_spot_instances=True、max_run、max_wait和checkpoint_s3_uri。这些使 SageMaker 能够在现货市场上执行您的作业之前等待最大允许时间,运行完整的max_run时间框架。只要保证max_wait比max_run大就行!*
确保在checkpoint_s3_uri参数中填入您希望保存检查点的 S3 点——然后 SageMaker 可以在训练循环中断时自动从同一点恢复您的作业。
在 Amazon SageMaker 上调整自己模型的 4 个步骤
在 SageMaker 上调整您的模型很容易!让我们在这里演练一下。
- **将你的脚本打包到 SageMaker 估算器中。**现在的情况是您正在使用 SageMaker Python SDK 的软件抽象来访问一个预建的 Docker 映像,一个针对您正在使用的框架版本的映像集。如果您需要另一个版本,只需在
requirements.txt参数中指定。

这是一个相当复杂的估算器,因为我们有如此多的活动部件。我们正在使用 Sagemaker 数据并行分发工具包,并启用 spot 实例。
**2。定义您的客观指标,并在脚本中打印出来。**SageMaker 的工作方式是我们搜索你的 CloudWatch 日志以找到你从脚本中发出的客观指标。想想“打印”只需打印出您希望 SageMaker 用于自动模型调优的测试或验证集的性能。

从您的培训脚本中打印您自己的测试指标,以使用自动模型调整
有了这个集合之后,实际上需要定义希望我们在搜索 CloudWatch 时使用的 regex 字符串。最简单的方法就是选择一个例子,让它工作,然后修改。

配置您调优作业构造函数,以搜索来自您的培训 sctip 的测试指标
**3。配置您的优化作业。接下来,你要为你的工作设定规格。调优 API 实际上是在寻找您预先构建的估计器。这意味着一旦你为你的工作定义了一个评估器,对它进行调整应该不会太难。
创建一个类似字典的对象,除了范围之外,还包含您想要优化的超参数。注意— 您真的可以传入任何想要的超参数,只要确保您的训练脚本可以从 argparser 中读取。再次,看例子,从那里开始。

一旦定义了超参数范围,将它们传递给[HyerparameterTuner](https://sagemaker.readthedocs.io/en/stable/api/training/tuner.html) 对象。
**4。按 go!**一旦你用tuner.fit()执行了这个,调优 API 将像一个管弦乐手一样工作。它将运行你告诉它用max_jobs运行的多少个作业,就运行多少个与max_parallel_jobs并行的作业。

亲提示—启用 **early_stopping** **。**尽早停止是一个明显的性能改进——一旦服务停止看到损失减少,它将杀死您的作业,包括子训练作业和父调优作业。您可以定义停止策略,也可以只使用Auto参数。
就这样结束了!
有了训练有素的模型,您只需几行代码就可以部署到 RESTful API 。你可以用 Neo 编译那个模型,用前哨包装它用于混合部署,或者用批处理转换离线运行它。我们的工作表现如何?和我一起参加 ML 峰会寻找答案!或者,你可以在这里观看我的个人 YouTube 视频系列的原始视频。
作者制作的所有照片
使用 weights and biases、mljar automl、hyperopt、shapash 和 appeally 调整您的机器学*工作流程
原文:https://towardsdatascience.com/tune-your-machine-learning-workflow-with-weights-and-biases-mljar-automl-hyperopt-shapash-and-f0646500ea1f?source=collection_archive---------31-----------------------
实践教程
在法国能源消耗的回归用例上发现紧急工具
我想用几周时间围绕 ml/ds 库写点东西,我有很多事情要做。每个库一篇文章可能太多了(而且不是很密集),所以我决定将我的测试合并到一篇文章中,用于一个用例来测试它们,并对其进行快速总结。
在本文中,您将对以下库进行一个快速测试:
我将在一个简单的用例中应用这些库(以及我测试库的经典用例),并给出一些反馈。
本文的所有代码都可以在这个 Github 库中找到。
ML 设置
在这一部分,将会有一个用于测试这些库的用例的描述。我的用例是我 2016 年在 Udacity 上做的 MOOC 的遗产,它是关于预测法国的日常用电量;你可以在这篇文章中找到关于这个实验的更多细节。
总结这篇文章,有几个要点:
- 电力消耗很大程度上取决于季节(法国主要使用电加热)
- 人们似乎在周日/周六比*日消耗更多的电力。
基于此,我只是用来自以下方面的更新数据来重建用例:
- 来自 rte 门户的电力消耗,我进行了转储,直到 1 月 1 日(并在每日级别汇总数据)
- 来自 NASA POWER 数据源的天气数据集中在 11 个最大的城市,以及 2 米(摄氏度)的最低、*均、最高温度加上总降水量(毫米)
根据天气数据,我构建了四个特征,这些特征是基于城市人口的加权版本;你可以在这本笔记本里找到 ETL。
在准备方面,我建立了:
- 训练集+测试集,占 2015-2020 年间数据的 80%和 20%,随机选取
- 2020 年的数据集是 2020 年的数据
这个项目旨在看看我们如何能够建立一个良好的能源消耗预测器(以及如何利用这些库有效地做到这一点)。
使用 MLJAR automl 构建基线模型
构建预测器的第一步是构建易于实施的基线模型,这是构建更好的预测器的良好起点。对于这个项目,主要评估指标将是 RMSE 。这些首批基线模型将会是:
- 随机预测值(在训练集周期的最小值和最大值之间随机选取一个值)
- 较少随机预测值(根据星期几和月份,在训练集的最小值和最大值之间选择一个值)
- PTG: 从文献来看,基于室外温度的分段回归是一个很好的预测器(所以我基于最小、*均、最大加权温度构建了三个版本)
最后,这也是本节的重点,另一种构建基线模型的方法是使用 automl 库来创建这些模型,这可能需要更多的时间,但也更具挑战性。对于那些可能不熟悉这个概念的人来说,Bojan Tunguz 有一篇关于这个主题的优秀的文章。
尽管如此,还是让一个 ML 库在数据集上做一些研究和测试来建立模型,有很多库可以做到这一点( H20 automl , auto-sklearn , autokeras ),但我想强调的是 MLJAR autoML 。
您可以在我的存储库中找到我放在 palace 中用 mljar ( 笔记本和报告)构建基线模型的部分,但对我来说,这个包的关键点是:
在这种情况下,将选择最佳模型(它似乎是集合模型)
那么我们来看一下生产的各种基线模型的对比。

作者图片
仍然很高兴看到 PTG 仍然是一个很好的预测器,但是 mljar 输出的模型做得很好。
用 hyperopt 优化超参数
在模型开发中,执行网格搜索以找到模型的正确参数集需要时间,有多种方法可以在参数空间中导航:
- 全网格搜索:测试参数空间中的所有参数集(时间效率不高)
- 随机搜索:测试在空间中随机选择的特定数量的参数(节省时间,但是错过机会)
这些方法非常标准,并且非常有效,但是有时您有一些时间限制来做一些实验,此时,可以使用像 hyperopt 这样的库。
该软件包旨在使用贝叶斯方法通过调整特定方向的参数来优化损失函数(在这种情况下,基于 rmse)。您可以在此找到此流程的更多详细信息:
- 一篇论文支持在 hyperopt 包中使用的 TPE 方法
- 威尔·科尔森对贝叶斯过程进行超参数调整的一般解释
在预测电力消耗的情况下,有基于包的文档构建的笔记本,这是对随机森林回归器的 100 次迭代的计算研究。
我的研究没有带来一个优秀的模型来构建基线(这不是我的目标)。
从专业的角度来看,它工作得很好,在工作中的一些项目上进行了测试,当您执行 Spark 应用程序时,我可能有一些保留,但如果您的研究时间有限,它仍然是一个很好的包(这不是唯一可以做到这一点的包,例如,您可以找到 ray tune )。
让我们进一步探讨这个模型的可解释性。
用 shapash 让你的模型更容易解释
我最近在工作中增加的另一个方面是研究我的机器学*模型的可解释性。我的研究让我找到了 MAIF 保险公司开发的一个名为 shapash 的软件包(我没想到会在我的博客上写这篇文章)。
如果我们回到我的随机森林回归器来预测电力消耗,这个包提供了在模型顶部构建解释器级别的能力,以帮助解释模型的可解释性和预测输出。
还有这次探索沙帕什用的笔记本。
我使用最好的模型,所有的功能都是预先计算好的;从 scikit learn 中,您可以很容易地提取出模型中特性的重要性(shapash 正在提供一个优秀的可视化)。

作者图片
通知预测器捕捉到建模中一周中某一天和温度的重要性。这个包的一个令人兴奋的特性是查看 x 数据集中的特定值,就像这个例子一样;我专注于周末。

作者图片
正如我们在这个例子中看到的,星期几比前面的表示更重要。另一个有用的特性如果你想直接挖掘某个特定特性的影响值,可以通过软件包设计贡献图(这里有一个例子)。

作者图片
(仍然很好地代表了周末对预测的影响)。
所有这些对影响的评估都受到用于评估这种影响的框架的影响。目前,可以使用两种框架:
- SHAP :也就是用 Shapley 值来建立特征对预测的影响;有一篇很好的文章正在阐述这个包
- LIME :另一种不基于 Shapley 值的方法,更多细节此处
如果你对模型的可解释性感兴趣,你应该考虑 Christoph Molnar 的作品。他在这个主题上做得非常出色(他在一个名为 rulefit 的库后面,这个库对于构建基线模型非常有用)。
总结一下这个包,可解释性可以直接应用于预测级别,对于一个特定的预测可以有更多的细节;预测的可解释性有一种表现形式。

作者图片
一个很酷的特性是这个 explainer 元素可以被保存并用于实时预测的预测器对象;2020 年的数据上有个例子。

作者图片
其他功能可能会对你有所帮助(比如小的 web 应用程序或元素的预处理),所以我会强烈邀请你来玩它(看看 MAIF 开源项目的网站这里他们在做很酷的东西)。
现在让我们继续评估模型和数据的漂移。
评估你的数据和模型
我正在做的另一个项目是监控 ml 管道。我主要把我的工作集中在模型漂移上。在我的 feed 中,由于我的一个同事,我看到了这个包,它正在围绕数据模型漂移开发一个开源库,显然叫做。
这个包后面有公司,但是是开源工具;你可以在这个数据广播中听到一位联合创始人的声音;这个软件包使用起来非常简单。如我之前所说,关注漂移数据和模型,你可以在这本笔记本中找到实验。
让我们深入研究一下数据报告;前面的笔记本产生了一个例子;这样做的目的是将一个参考数据集(在本例中为训练集)与另一个数据集(在本例中为 2020 年)进行比较,并查看是否存在大量差异(这可以解释预测中模型的变化)。最后有一张制作的报告截图。

作者图片
对于模型中使用的每个要素,都会在参考数据集和当前数据集之间的相似性测试中进行评估(如果 p 值小于 0.05,则有问题),正如预期的那样,温度看起来有所不同,这是预期的,因为参考数据集中有五年的数据,而不是一年的数据)。还有一些图表可以更深入地了解数据集。
模型报告是相似的,但是报告是更进化的;这里有个例子。本报告的关键点是:
- 回归问题的传统评估指标显示在顶部。
- 预测值与实际值的多幅图比较
- 高估和低估的区别
该报告的输出不限于 HTML 文件;它可以以 JSON 格式提取。
这个包是最近的,但是里面有很多很好的可视化和*惯。因此,我建议人们看看它(它也不局限于分类的回归工作),因为它可以启发他们的仪表板(或者可能喂养它)。
更有效地用权重和偏*来构建你的探索管道
最后,在这次探索中,我测试了另一个名为 weights and bias 的包,它在 ML 世界中制造了很多噪音(并且有一个很好的理由叫做weights and bias)。这个包是帮助数据科学家轻松处理 ml 实验的监控并帮助他们进入生产的包的一部分。
包的第一个方面是日志信息;您可以记录来自数据、模型、表格或模型的各种元素。有一个代码的快速快照,用于版本化数据帧和模型(也加载)。
这个特性在这种包中非常常*(正如你在我的关于 mlflow 的文章中看到的)。尽管如此,其中一个优势是您可以在一个漂亮的 UI 中使用这些构件来设计带有数据的图表,并以中等风格编写报告。

作者图片
这个 UI 的一个显著特性是监视运行实验的机器的性能。
我发现的另一个非常有趣的特性是 sweep 特性,它混合了用于计算的远视视觉和非常好的界面。你可以在这个笔记本里找到实验,不过有 UI 截图。

作者图片
使用*行坐标图研究参数对优化损失的影响,用户界面很容易理解。但是我喜欢的这个 UI 的显著特征是右上角的重要性/相关性图表;关于参数对损失演变的重要性,你可以在这篇文章中找到关于它们的方法的细节。
从全球来看,权重和偏差是一个很好的监控包;我可能不太喜欢项目中没有实验层的事实(项目>实验>运行对我来说可能更好),但它非常有效。我可能只是为了专业用途而强调这一点;许可证需要按用户付费,所以做好准备(但在你的 ml 团队配置功能中可能是值得的)
额外:通过 data wrangler 轻松连接熊猫和 AWS 存储
有一个包我在这个项目中没有用到,但是我想在这里分享一下,因为我发现它非常有用。有一个 AWS 的包帮助将 pandas dataframe 与 AWS 存储连接起来(有一个代码快照将 pandas 与各种 AWS 服务连接起来)

作者图片
没什么好说的;如果您的机器在 AWS 服务上有足够的权限可以调用,那么这是一个很好的接口包(对我来说,。唯一的缺点是 dynamodb 上缺少读取功能。
结论
我希望这篇文章激发了您测试这些包的好奇心,因为它们可以让您的 ML/DS 日常工作变得更加轻松。
原载于 2021 年 6 月 27 日【https://www.the-odd-dataguy.com】。
使用进化算法调整您的 Scikit-learn 模型
原文:https://towardsdatascience.com/tune-your-scikit-learn-model-using-evolutionary-algorithms-30538248ac16?source=collection_archive---------10-----------------------
sci kit-学*用进化算法和交叉验证进行超参数调整。

苏珊·Q·尹在 Unsplash 上的照片
超参数调整是机器学*管道的一个重要部分——大多数常*的实现都使用网格搜索(随机或非随机)在一组组合之间进行选择。
本文将使用 python 包sk learn-genetic-opt中的进化算法来寻找优化我们定义的交叉验证度量的参数。这个软件包有一些功能可以简化这个过程:
- 用几种进化算法搜索超参数。
- 回调在满足标准时停止优化,将对象记录到本地系统,或者定制您的逻辑。
- 将功能记录到日志对象中或与 MLflow 内置集成。
- Utils 绘图了解优化过程。
数据集
作为演示数据集,我们将使用来自 Scikit-learn 的数字数据;其思想是对 8×8 像素的图像的手写数字进行分类。数据示例如下:

数字数据集。图片由 Scikit-learn (BSD 许可证)提供
进化算法
大多数进化算法从一群个体开始;每一个都代表了在我们的机器学*模型中使用的一组超参数。
使用一些试图模拟种群进化方式的机制,该算法基于已经测试的参数的结果来复制、变异和选择新的超参数,使用一些度量来定义其适应性(例如,交叉验证准确性),并在几代个体中重复这一过程,这里的是对该过程的扩展解释。从视觉上看,它可能是这样的:

进化交叉验证。图片由作者提供。
如果你想要更深入的解释,你可以查看我的其他媒体帖子解释这个过程的理论方面。
实现
该算法的工作方式可能听起来有点混乱,但已经有一些包,如 Python 中的 DEAP,已经为该算法优化了例程。
在这种情况下,我们将使用sk learn-genetic-opt,这是一个构建在 DEAP 和 scikit-learn 之上的 python 包,使这个优化过程更加简单。
首先,让我们安装它:
pip install sklearn-genetic-opt
现在,让我们导入数据,在我们的训练和测试集中分割它,并创建任何 scikit-learn 分类器的实例;对于这个例子,我将使用随机森林分类器。
数据导入。作者代码。
现在,我们可以使用 sklearn-genetic-opt 来基于一个度量调整我们的分类器;在这种情况下,我将从具有三个分裂的分层交叉验证中选择准确度分数。
param_grid 类似于 scikit-learn,但是我们必须使用 space 类来让 sklearn-genetic-opt 知道使用哪种类型的数据来对参数进行采样。
为了定义这个和其他选项,我们必须使用包的主体类 GASearchCV。
GaSearchCV 设置。作者代码。
在本文的最后,我将解释所显示的参数,以便您可以根据需要更改它们。
估计量必须是 sckit-learn 分类器或回归器,cv 是交叉验证或交叉验证生成器中的分裂数,评分是选择用于优化的指标,它必须是与估计量兼容的 sklearn 指标之一。
现在我们可以拟合我们的模型,并在我们的测试数据中使用它;默认情况下,它将使用找到的最佳超参数集:
evolved_estimator.fit(X_train,y_train)
y_predicy_ga = evolved_estimator.predict(X_test)
accuracy_score(y_test,y_predicy_ga)
您应该会看到类似这样的内容:

训练啰嗦。图片由作者提供。
当算法运行时,它向我们展示了它在每一代所达到的指标;“适合度”指的是我们选择的度量标准,在这个例子中,是准确性。由于该算法每代使用一组以上的超参数,因此它显示了*均精度、标准偏差以及最大和最小单个值。
在这次特定的运行中,我们使用这组超参数在测试集中获得了 0.93 的准确度:

优化结果。图片由作者提供。
我们还可以看到优化例程的演变,使用命令:
plot_fitness_evolution(evolved_estimator)
plt.show()

健身进化。图片由作者提供。
如您所*,该算法在第 0 代中以大约 0.8 的精度开始,这随机生成超参数。但是当该算法使用进化策略选择一组新的超参数时,精确度提高了。该算法可能还没有完全收敛到它的最佳适应值,但已经达到了 0.94,所以你可以让它运行一些额外的世代,看看你是否可以获得更好的准确性。
我们还可以获得所有模型的超参数及其交叉验证分数的日志。

使用的超参数日志。图片由作者提供。
例如,您可以使用这些日志来绘制算法正在选择的参数的分布,以查看其探索和开发策略如何。
plot_search_space(evolved_estimator)
plt.show()

抽样超参数分布。图片由作者提供。
超参数组合的 k (keep_top_k=4)最佳集合:

名人堂。图片由作者提供。
原来如此!正如您所看到的,使用进化算法和 sklearn-genetic-opt 来实现这个优化例程非常简单;这是一个开源项目,可以帮助您选择超参数,作为 scikit-learn 的 RandomizedSearchCV 或 GridSearch 等方法的替代方法,这些方法取决于预定义的超参数组合。
作为软件包的作者,欢迎任何建议、贡献或评论。在这里,您可以看到更多示例和使用的源代码:
https://sklearn-genetic-opt.readthedocs.io/en/stable/
以下是撰写本文时的定义,但请务必查看最新的文档以获取更新。
附录 1:空间定义
用参数“param_grid”定义搜索空间;它需要一个包含这些类的字典:
**分类:**表示分类变量,期望它可以采样的选项列表,以及可选地采样每个选项的概率
Integer: 表示整型变量,期望得到变量的上下限
**连续:**表示实值变量,期望变量的上下界,如果变量是正定义的,可以选择从对数均匀分布中抽取值
附录 GASearchCV 的参数
**总体:**随机产生的候选超参数的初始数量。
**世代:**该算法将进行多少次迭代,每一代都会创建一个新群体
**精英主义:**如果为真,则使用锦标赛选择保留最好的 k 个个体;如果为假,则使用轮盘赌选择机制。
**锦标赛规模:**利用锦标赛操作员选择多少个人,仅在 elitism = True 时使用。
crossover_probability: 在特定的交配中发生交叉的概率。
**突变概率:**一个已经固定的个体,其某些超参数值发生随机变化的概率。
param_grid: 字典,关键字作为超参数的名称,值为 sklearn_genetic.space 中的分类、连续或整数
定义该参数可能取的值。
标准:“最大”如果选择“得分”指标,则认为其值越大越好,否则为“最小”。
**算法:**从包 deap 到使用的具体进化算法,sk learn-genetic-opt 0 . 5 . 0 版本支持eas simple、 eaMuPlusLambda、和eamucommamlambda。
n_jobs: 交叉验证步骤中要启动多少个并发作业
verbose: 如果为真,则在算法运行时显示优化的一些指标。
keep_top_k: 基于其最终的交叉验证得分,在优化结束时返回多少组超参数。该参数决定了 hof 的大小。
log_config: 如果您使用 MLflowConfig 设置该参数,则指标、超参数和模型会被记录到 MLflow 服务器中。
使用 Optuna 调整超参数
原文:https://towardsdatascience.com/tuning-hyperparameters-with-optuna-af342facc549?source=collection_archive---------12-----------------------
以自动化和智能的方式实现最佳 ML 模型

Alexis Baydoun 在 Unsplash 上拍摄的照片
目录
- 简介
- 超参数和 sci kit-学*调整方法
- 用 Optuna 调节超参数
- 结论
介绍
我最近完成了我在 Kaggle 上的第一个机器学*项目,用波士顿住房数据集预测销售价格(合著者: Julia Yang )。请看我们的作品,它在 5000 名竞争者中以【最高 9%】的房价取得了最高 9%的成绩。
从这个项目中,朱莉娅和我都学到了很多东西,我们将写一系列关于我们的学*的文章。在这篇文章中,我将讨论我使用 Optuna 调优 ML 模型超参数的经验。
超参数和 sci kit-学*调整方法
在机器学*项目中,调整超参数是最关键的步骤之一。由于 ML 模型无法从数据中学*超参数,因此我们有责任对它们进行调优。如果我们不仔细选择超参数,我们在项目的其他部分花费的所有努力都可能是徒劳的。
在 scikit-learn 中,我们可以使用一些方法来调整超参数:
- 穷举网格搜索(GridSearchCV和halvinggridsearccv)
本质上,我们需要建立一个超参数可能组合的网格。scikit-learn 将尝试每种组合来拟合模型,并使用指定的评分方法和指定的交叉验证拆分器来计算模型的性能。 - random search(randomzedsearchcv和HalvingRandomSearchCV)
这些方法还需要我们建立超参数网格。但是在随机搜索中,并不是所有的参数值都被尝试,而是从网格中抽取固定数量( n_iter )的参数设置。 - scikit-learn 还提供了一些特定于模型的交叉验证方法,我们可以使用这些方法来调整超参数,例如, RidgeCV 、 LassoCV 和elastic netcv等。这些方法是可行的,因为这些模型可以像拟合超参数的单个值的估计量一样有效地拟合一些超参数值范围的数据。
然而,根据我的经验,这些方法似乎存在一些问题。
对于某些情况,在我们预测房价的工作中,我们使用了六种不同的模型来拟合和预测数据,然后将这些模型集成在一起成为最终模型。因此,我需要调整所有这六个模型的超参数。由于一些模型有相当多的超参数,scikit-learn 的网格搜索方法将很快变得非常昂贵。例如,当我调整 Ridge 时,我只需要调整到 alpha 并尝试它的 10 个不同值,网格搜索将匹配模型 10 次。尽管如此,当我调优 XGBRegressor 时,如果我想调优 6 个超参数并尝试其中每个参数的 10 个不同值,网格搜索将不得不适应模型 1,000,000 次。
另一方面,与网格搜索相反,随机搜索可以限制拟合模型的预算,但是对于找到超参数的最佳组合来说,它似乎太随机了。
为了用 scikit-learn 的方法克服这些问题,我在网上搜索工具,我找到了几个用于超参数调优的包,包括 Optuna 和 Ray.tune 。在这篇文章中,我将分享我与 Optuna 的经验。
使用 Optuna 调整超参数
Optuna 是“一个自动化超参数搜索的开源超参数优化框架。”Optuna 的主要特性包括“自动搜索最佳超参数”、“有效搜索大空间并删除无用的尝试以获得更快的结果”,以及“在多个线程或进程上并行化超参数搜索”(引自 https://optuna.org/
我对 Optuna 的超参数搜索算法不是太了解,所以我想重点介绍一下如何使用 Optuna。
第一步是为 Optuna 定义最大化的目标函数。目标函数应该将一个“试验对象作为输入,并返回分数、浮点值或浮点值列表。下面是我为山脊模型定义的目标函数的一个例子:
**def ridge_objective(trial): # Use the trial object to suggest a value for alpha
# Optuna will come up with a suggested value based on the scores of previous trials
_alpha = trial.suggest_float("alpha", 0.1, 20) # Define the model with the suggested alpha
ridge = Ridge(alpha=_alpha, random_state=42) # Calculate the score with 10-folds cross validation, which returns a list of scores
# scoring is defined as negative RMSE as it is what this Kaggle competition uses to evaluate the result
scores = cross_val_score(ridge, X, y,
cv=KFold(n_splits=10,
shuffle=True,
random_state=42),
scoring="neg_root_mean_squared_error"
) # Return the mean of 10 scores
return scores.mean()**
下一步是使用目标函数创建一个“研究”对象,然后对其进行优化。
**# Create Study object
study = optuna.create_study(direction="maximize")# Optimize the study, use more trials to obtain better result, use less trials to be more cost-efficient
study.optimize(objective, n_trials=100) # Use more # Print the result
best_params = study.best_params
best_score = study.best_value
print(f"Best score: {best_score}\n")
print(f"Optimized parameters: {best_params}\n")**
仅此而已。看起来很简单吧?让我们把它们和所有的模型放在一起。
**RANDOM_SEED = 42
*# 10-fold CV*
kfolds = KFold(n_splits=10, shuffle=True, random_state=RANDOM_SEED)# Define the helper function so that it can be reused
def tune(objective):
study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=100)
params = study.best_params
best_score = study.best_value
print(f"Best score: {best_score}\n")
print(f"Optimized parameters: {params}\n")
return params##################
# Ridge
##################def ridge_objective(trial):
_alpha = trial.suggest_float("alpha", 0.1, 20)
ridge = Ridge(alpha=_alpha, random_state=RANDOM_SEED)
scores = cross_val_score(
ridge, X, y, cv=kfolds,
scoring="neg_root_mean_squared_error"
)
return scores.mean()
ridge_params = tune(ridge_objective)# After tuning it for once, we can copy the best params to create the model without tunning it again
# ridge_params = {'alpha': 7.491061624529043}ridge = Ridge(**ridge_params, random_state=RANDOM_SEED)##################
# Lasso
##################def lasso_objective(trial):
_alpha = trial.suggest_float("alpha", 0.0001, 1)
lasso = Lasso(alpha=_alpha, random_state=RANDOM_SEED)
scores = cross_val_score(
lasso, X, y, cv=kfolds,
scoring="neg_root_mean_squared_error"
)
return scores.mean()lasso_params = tune(lasso_objective)
# lasso_params = {'alpha': 0.00041398687418613947}lasso = Lasso(**lasso_params, random_state=RANDOM_SEED)##################
# Random Forest
##################def randomforest_objective(trial):
_n_estimators = trial.suggest_int("n_estimators", 50, 200)
_max_depth = trial.suggest_int("max_depth", 5, 20)
_min_samp_split = trial.suggest_int("min_samples_split", 2, 10)
_min_samples_leaf = trial.suggest_int("min_samples_leaf", 2, 10)
_max_features = trial.suggest_int("max_features", 10, 50)
rf = RandomForestRegressor(
max_depth=_max_depth,
min_samples_split=_min_samp_split,
min_samples_leaf=_min_samples_leaf,
max_features=_max_features,
n_estimators=_n_estimators,
n_jobs=-1,
random_state=RANDOM_SEED,
)
scores = cross_val_score(
rf, X, y, cv=kfolds, scoring="neg_root_mean_squared_error"
)
return scores.mean()
randomforest_params = tune(randomforest_objective)
# randomforest_params = {'n_estimators': 180, 'max_depth': 18, 'min_samples_split': 2, 'min_samples_leaf': 2, 'max_features': 49}rf = RandomForestRegressor(n_jobs=-1, random_state=RANDOM_SEED, **randomforest_params)# So on with other models...**
请在https://www.kaggle.com/garylucn/top-9-house-price/notebook或https://github . com/Glu cn/ka ggle/blob/main/House _ Prices/notebook/top-9-House-price . ipynb找到完整代码
结论
我对 Optuna 非常满意,因为调优过程比 scikit-learn 的网格搜索快得多,结果也比随机搜索好。以下是我将在下一步继续挖掘的一些项目:
- 尝试使用其他工具,如 Ray.tune。
- 在目标函数中,我需要为每个超参数指定一个范围。如果我对模型有更好的理解,我可以使范围更准确,以提高分数或节省一些预算。所以对我来说,一项重要的工作就是深入研究这些模型。
Julia 和我关于数据科学主题的其他文章:
- 比较&对比:探索具有许多特征的数据集
参考
- scikit-learn:调整估计器的超参数
- Python 中超参数调优:2021 年完整指南
卡尔曼滤波中 CV 和 CA 模型的 Q 矩阵调整
原文:https://towardsdatascience.com/tuning-q-matrix-for-cv-and-ca-models-in-kalman-filter-67084185d08c?source=collection_archive---------25-----------------------
介绍
卡尔曼滤波器(KF)广泛用于车辆导航任务,特别是用于车辆轨迹*滑。将 KF 应用于导航任务的相关问题之一是车辆轨迹的建模。为简单起*,对于大范围的跟踪问题,选择恒定速度(CV)模型或恒定加速度(CA)模型是方便的,其中位置导数确实是速度,并且速度(几乎)是恒定的(对于 CV 模型)。这个优点提供了处理线性和稳定系统的能力,这是这类跟踪问题的一个要求。除了 Q 调谐之外,设计师还应在 KF 中预先定义其他参数。测量噪声协方差 R、初始误差协方差和步长。KF 中最重要的矩阵是 Q 和 R。矩阵 R 可以直接从传感器中确定,而 Q 则不是这种情况

作者图片
形式化
考虑两个模型,具有位置( p )和速度( v )状态的 CV 模型,以及具有位置、速度和加速度( a )的 CA 模型。状态空间中的轨迹(系统)矩阵由下式给出

轨迹矩阵
状态空间本身是由

状态空间
其中 w 是白高斯离散噪声。提供了卡尔曼滤波算法(更多详细信息,请参考 Wiki):

卡尔曼滤波方程
讨论
我们(滤波器设计者)通常假设他们的系统行为符合轨迹模型,其中速度实际上是位置导数,加速度实际上是速度导数。然而,在现实生活中,我们要处理非高斯噪声、离散化误差、数值考虑、测量噪声、非线性等等。因此,建立使用卡尔曼滤波器的轨迹(系统)模型的正确方法是通过考虑物理关系,但是,添加一些白噪声来处理实际情况。这种噪声被注入到模型中(更具体地说,注入到卡尔曼滤波器中),以补偿设计者对其模型的不确定性。例如,我们可以假设 CV 模型,其中真实生活中的速度变化很快。然后,应该定义一个适当的 Q 矩阵来处理这种情况。值得一提的是,为 Q 矩阵选择高值可能会导致滤波器发散,因为设计人员的建模存在巨大的不确定性。因此,每个场景都有一个最优矩阵 Q——这是很难找到的。
方法 1-试错法
反复试验。从大值开始,然后逐渐减小,直到收敛。这可能适用于离线设置,在离线设置中,设计师必须记住避免过度拟合。
方法 2-基于新息的自适应方法
实时调整 Q 的最常*的自适应方法是考虑卡尔曼滤波器的新息量。

基于创新的方法
方法 3-生成式
调谐滤波器参数的简单方法需要存储整个参数向量。如果可能的话,以下方法有时会有效:

生成方法
方法 4-比例因子
当 R 已知时,比例因子是一个很好的方法。核心思想是 Q 和 R 通过创新量的关系。它由下式给出:

缩放比例
摘要
有许多方法来调谐 Klaman 滤波器中的 Q。我们总结了 4 种应对这一挑战的常用技术。
关于作者
Barak 获得了以色列理工学院的航空工程学士学位(2016 年)、硕士学位(2018 年)以及经济和管理学士学位(2016 年,成绩优异)。他曾在高通工作(2019-2020),在那里他主要研究机器学*和信号处理算法。巴拉克目前正在海法大学攻读博士学位。他的研究兴趣包括传感器融合、导航、机器学*和估计理论。
www.Barakor.com|https://www.linkedin.com/in/barakor/
[1] L. Zhang、D. Sidoti、A. Bienkowski、K. R. Pattipati、Y. Bar-Shalom 和 D. L. Kleinman,|关于噪声协方差和自适应卡尔曼滤波的识别:一个 50 年老问题的新观点,《IEEE Access》,第 8 卷,第 59362-59388 页,2020 年。
[2] P. Abbeel、A. Coates、M. Montemerlo、A. Y. Ng 和 S. Thrun,“卡尔曼滤波器的鉴别训练”机器人学:科学与系统,2005 年第 2 卷,第 1 页。
[3] R. Mehra,“关于方差识别和自适应卡尔曼滤波”,IEEE 自动控制汇刊,第 15 卷,第 2 期,第 175 页{184 页,1970 年。
[4] A. Mohamed 和 K. Schwarz,“用于 INS/GPS 的自适应卡尔曼滤波”,大地测量学杂志,第 73 卷,第 4 期,第 193 页{203,1999 年。
使用 GridSearchCV 调整机器学*模型的超参数
原文:https://towardsdatascience.com/tuning-the-hyperparameters-of-your-machine-learning-model-using-gridsearchcv-7fc2bb76ff27?source=collection_archive---------1-----------------------
了解如何使用 sklearn 中的 GridSearchCV 函数来优化您的机器学*模型

罗伯塔·索奇在 Unsplash 上拍摄的照片
机器学*的两个关键挑战是找到正确的算法和优化你的模型。如果你熟悉机器学*,你可能用过线性回归、逻辑回归、决策树、支持向量机等算法。一旦您决定为您的机器学*模型使用特定的算法,下一个挑战就是如何微调您的模型的超参数,以便您的模型与您拥有的数据集很好地配合。在本文中,我想把重点放在后一部分——微调模型的超参数。尽管这个术语听起来可能很复杂,但是使用 sklearn 模块中的 GridSearchCV 函数可以非常容易地微调您的超参数。
使用逻辑回归进行分类
在你学*如何微调你的机器学*模型的超参数之前,让我们尝试使用 sklearn 附带的经典乳腺癌数据集来建立一个模型。由于这是一个分类问题,我们将使用逻辑回归作为例子。
对于分类问题,您还可以使用其他算法,如支持向量机(SVM)、K 近邻(KNN)、朴素贝叶斯等。但是对于本文,我将使用逻辑回归。
首先,让我们加载数据集,并将其加载到 Pandas 数据框架中:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_breast_cancerbc = load_breast_cancer()df = pd.DataFrame(bc.data, columns = bc.feature_names)
df['diagnosis'] = bc.target
df

前 30 列是各种特征,最后一列是诊断(0 表示恶性,1 表示良性)。为了简单起*,我将使用 30 列进行训练,最后一列作为目标。
理想情况下,您应该执行要素选择来筛选出那些显示共线性的列以及与目标没有强相关性的列。
让我们提取特性和标签的值,并将它们保存为数组:
dfX = df.iloc[:,:-1] # Features - 30 columns
dfy = df['diagnosis'] # Label - last columnX = dfX.values
y = dfy.valuesprint(X.shape) # (569, 30); 2D array
print(y.shape) # (569,); 1D array
将数据集分为训练集和测试集:
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.25,
random_state=2)
下图显示了训练和测试数据集的用法:

接下来,标准化训练和测试数据集:
from sklearn import preprocessingscaler = preprocessing.StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.fit_transform(X_test)
StandardScaler 类重新调整数据,使*均值为 0,标准差为 1(单位方差)。
数据集的标准化是许多机器学*估计器的常*要求:如果单个特征或多或少看起来不像标准的正态分布数据(例如,均值和单位方差为 0 的高斯数据),它们可能表现不佳。来源:https://sci kit-learn . org/stable/modules/generated/sk learn . preprocessing . standard scaler . html
最后,使用 sklearn 的 LogisticRegression 类,使用训练集建立一个模型,然后使用测试集获得测试集中所有项目的预测:
from sklearn.linear_model import LogisticRegressionlogreg = LogisticRegression()
logreg.fit(X_train,y_train)y_pred = logreg.predict(X_test)
要查看模型的执行情况,请获取其精确度:
from sklearn import metricsprint("Accuracy:",metrics.accuracy_score(y_test, y_pred))
# OR
print("Accuracy:",logreg.score(X_test, y_test))
您可以使用您刚刚构建的模型的 score() 函数,或者使用来自 metrics 模块的 accuracy_score() 函数来获得精确度。
上述代码片段的准确性为:
Accuracy: 0.9790209790209791
了解交叉验证
为了理解如何使用 GridSearchCV 优化您的模型,您需要理解什么是交叉验证。还记得在上一节中我们将数据集分为训练集和测试集吗?

作者图片
测试集用于评估您使用定型集定型的模型的性能。虽然这是评估模型的一个好方法,但它可能不会给出模型性能的真实指示。众所周知,测试集中的数据可能是有偏差的,使用它来评估模型可能会给出非常有偏差的结果。一个好得多的方法是将整个数据集分成 k 倍(或 k 份,即 k 倍意味着将数据集分成 10 等份)。在 k 折中,使用 1 折进行测试,使用 k-1 折进行训练:

作者图片
在每次迭代中,记录度量标准(比如准确度、精确度等),并在所有迭代结束时,计算这些度量标准的*均值。这为您的模型提供了训练和测试数据的良好组合,并为您的模型提供了更好的性能基准。这个将你的数据分成 k 个折叠并使用 1 个折叠进行测试和 k-1 个折叠进行测试的过程被称为 k 折叠交叉验证。
使用 GridSearchCV 进行超参数调整
在我们之前的 LogisticRegression 类的例子中,我们创建了一个 LogisticRegression 类的实例,没有传递任何初始化器。相反,我们依赖各种参数的默认值,例如:
- 惩罚 —指定惩罚的标准。
- C —正则化强度的逆;较小的值指定较强的正则化。
- 求解器 —在优化问题中使用的算法。
- max_iter —求解器收敛所需的最大迭代次数。
虽然在某些情况下依赖这些参数的默认值是可以的(在机器学*中称为超参数),但能够微调它们的值总是好的,以便算法最适合您所拥有的数据类型。不幸的是,找到能够完美拟合您的数据的超参数的完美组合并不是一项简单的任务。这就是 GridSearchCV 的用武之地。
GridSearchCV 是 sklearn 的 model_selection 包中的一个函数。它允许您为每个超参数指定不同的值,并在拟合模型时尝试所有可能的组合。它使用数据集的交叉验证进行训练和测试——因此 GridSearchCV 中缩写为“ CV ”。GridSearchCV 的最终结果是一组超参数,根据您希望优化模型的评分标准,这些超参数最适合您的数据。
让我们首先创建参数网格,它是一个字典,包含拟合模型时想要尝试的所有各种超参数:
from sklearn.model_selection import GridSearchCVimport warnings
warnings.filterwarnings('ignore')**# parameter grid
parameters = {
'penalty' : ['l1','l2'],
'C' : np.logspace(-3,3,7),
'solver' : ['newton-cg', 'lbfgs', 'liblinear'],
}**
注意,我已经关闭了警告,因为 GridSearchCV()函数倾向于生成相当多的警告。
然后,您可以使用正在使用的算法以及如下所示的各种参数来调用 GridSearchCV()函数:
logreg = LogisticRegression()
clf = GridSearchCV(logreg, # model
param_grid = parameters, # hyperparameters
scoring='accuracy', # metric for scoring
cv=10) # number of folds
GridSearchCV() 函数返回一个 LogisticRegression 实例(在本例中,基于您正在使用的算法),然后您可以使用您的训练集对其进行训练:
clf.fit(X_train,y_train)
完成训练后,您现在可以打印出调整后的超参数以及训练精度:
print("Tuned Hyperparameters :", clf.best_params_)
print("Accuracy :",clf.best_score_)
以下是我运行上述代码片段获得的结果:
Tuned Hyperparameters : {'C': 0.1,
'penalty': 'l2',
'solver': 'liblinear'}
Accuracy : 0.983499446290144
0.9835 的精度现在比早期的 0.9790 精度好得多。
使用 GridSearchCV()函数返回的超参数值,您现在可以使用这些值通过训练数据集构建模型:
logreg = LogisticRegression(**C = 0.1**,
**penalty = 'l2'**,
**solver = 'liblinear'**)
logreg.fit(X_train,y_train)y_pred = logreg.predict(X_test)
print("Accuracy:",logreg.score(X_test, y_test))
下图总结了我们所做的工作:

作者图片
观察到:
- GridSearchCV 使用训练集和验证集进行交叉验证。
- 一旦 GridSearchCV 找到了超参数的值,我们就使用调整后的参数值通过训练集建立一个新的模型。
- 有了测试设备,我们现在可以评估我们的新模型了。
这里采用的方法让我们有了一个衡量新模型性能的指标。
使用 GridSearchCV 的另一种方法是使用整个数据集来拟合它,如下所示:
parameters = {
'penalty' : ['l1','l2'],
'C' : np.logspace(-3,3,7),
'solver' : ['newton-cg', 'lbfgs', 'liblinear'],
}logreg = LogisticRegression()
clf = GridSearchCV(logreg,
param_grid = parameters,
scoring = 'accuracy',
cv = 10)
**clf.fit(X,y)**
上述代码片段返回以下结果:
Tuned Hyperparameters : {'C': 1000.0,
'penalty': 'l1',
'solver': 'liblinear'}
Accuracy : 0.9701754385964911
下图总结了我们刚刚完成的工作:

作者图片
在这种情况下,您让 GridSearchCV 使用整个数据集来导出调优的参数,然后使用新获得的值来构建新的模型。
这里采用的方法允许我们为我们的数据集找出最佳的超参数,但是不允许你精确地评估你的模型。
使用这种方法无法真正评估该模型,因为您不想传递任何用于预测训练的数据。为什么?因为模型已经在训练期间看到了数据,因此不会给你模型性能的准确度量。
https://weimenglee.medium.com/membership
摘要
使用 GridSearchCV 可以节省您在优化机器学*模型方面的大量精力。但是请注意,GridSearchCV 只会根据您在参数网格中提供的内容来评估您的超参数。当然,您可能希望为每个超参数指定所有可能的值,但是这样做的计算代价很高,因为所有的组合都将被评估。最后,不要把 GridSearchCV 作为优化模型的灵丹妙药——在考虑训练模型之前,一定要花时间进行适当的特征选择。
以下是我之前关于功能选择的文章链接:
如何调整 HDBSCAN
原文:https://towardsdatascience.com/tuning-with-hdbscan-149865ac2970?source=collection_archive---------3-----------------------
如何调整基于密度的沟道聚类的快速示例
聚类是一个非常困难的问题,因为当标签不存在时,永远不会有真正的“正确”答案。

Tengyart 通过 Unsplash 拍摄的照片
这是由各种技术和各种假设造成的。如果一项技术运行不正确,违反了一个假设,这将导致不正确的(完全错误的)结果。
在这篇博文中,我们将深入探讨为什么集群变得复杂,然后深入研究如何利用亚马逊 DenseClus 库在 HDBSCAN 中适当地调优基于密度的集群。
背景:聚类是复杂的😬
聚类算法没有免费的午餐,虽然一种算法可能很适合某个数据集,但不能保证它会以完全相同的方式在不同的数据集上工作。同样,聚类“强烈依赖于研究人员的背景、目标和决策”,这为 Henning 在什么是真正的聚类中指出的“普遍最优的方法只会产生自然的聚类”这一说法火上浇油。亨宁 2015 。
例如,KMeans 等常用技术假设数据是数值型和球形的。当数据具有高维数并且包括分类值时,这些类型的假设不太合理。
违反假设的聚类数据以两种方式给从业者带来难题:
- 如何形式化一个具体的特化方案?
- 选择什么样的聚类技术?
这两者都必须公式化,以便不违反任何假设。实际上,这可能导致一个排除过程,不违反算法假设的算法和特征方案是唯一的选择。
警惕你的度量标准📈
当没有标签可用时,通常选择一个客观的度量,如轮廓分数来评估,然后决定最终的聚类结果。剪影分数用介于-1 到 1 之间的指数来衡量集群的内聚性和分离性。它不不在指数计算中考虑噪音,并利用距离。距离不适用于基于密度的技术。在客观度量计算中不包括噪声违反了基于密度的聚类中的固有假设。
这意味着剪影分数和类似的指数不适合测量基于密度的技术!!!(我自己强调了这一点,因为我已经看到很多博客都在这么做——这很危险。)
基于密度的聚类验证对救援🌈
基于密度的聚类验证或 DBCV 适用于基于密度的聚类算法,因为它考虑了噪声,并通过密度而不是距离来捕获聚类的形状属性(参*原始论文
正如论文所解释的,DBCV 的最终结果是聚类的“有效性指数”值的加权和。这会产生一个介于-1 到 1 之间的分数,该值越大,聚类解决方案越好。

来源:基于密度的聚类验证,Moulavi 等人,2014 年
深入的讨论超出了这里的范围,但请参阅原始文件的更多细节。
请注意,DBCV 确实有缺点。像所有其他度量和技术一样,DBCV 也不能避免前面提到的聚类中的复杂性和度量问题。
然而,除了有基础事实标签之外,它还提供了一个客观标准来判断基于密度的技术集群的分离程度。
真实的例子🚀
说够了,让我们深入一个真实的例子。
笔记本可以在亚马逊 Denseclus 图书馆中找到。
在本例中,您将使用一个虚构的电信公司的合成客户流失数据集,其结果是客户流失?标记为真(已搅动)或假(未搅动)。功能包括客户详细信息,如计划和使用信息。客户流失数据集是公开可用的,并在丹尼尔·t·拉罗斯的《从数据中发现知识》一书中提到。作者将其归功于加州大学欧文分校的机器学*数据集仓库。
这些数据包括数值和分类特征,但将使用 Denseclus 将其转换到低维、密集的空间,以在其上形成聚类。更多关于 DenseClus 的信息,请看这里。所有需要的转换都在幕后处理。你只需要打电话给fit。
# This runs in about a minute or two
from denseclus import DenseClus
import logging # to further silence deprecation warnings
logging.captureWarnings(True)
clf = DenseClus(
random_state=SEED,
umap_combine_method="intersection_union_mapper"
)
clf.fit(df)
在其他步骤中,Denseclus 使用 HDBSCAN 对数据进行聚类。
让我们看看数据是如何分割的。
embedding = clf.mapper_.embedding_
labels = clf.score()
clustered = (labels >= 0)
cnts = pd.DataFrame(labels)[0].value_counts()
cnts = cnts.reset_index()
cnts.columns = ['cluster','count']
print(cnts.sort_values(['cluster']))cluster count
4 -1 9
3 0 1234
0 1 1265
1 2 1253
2 3 1239
经检查,正好有 4 个几乎均匀分布的聚类,其中-1 表示在数据中发现的噪声。
此外,为了简单地观察它们的分布,另一种评估集群的方法是将它们可视化。
_=sns.jointplot(
x=embedding[clustered, 0], y=embedding[clustered, 1], hue=labels[clustered], kind="kde"
)

照片由 Auhtor 拍摄
如您所*,我们在这个数据切片中形成了 4 个不同的孤岛。在这些密度周围形成了团簇,这正是我们所期望的 DenseClus 的行为。
您可以通过绘制密度被分割的树来进一步确认结果。
这是我们看到的包含更多信息的计数的图形视图。例如,您可以看到双集群解决方案也是可行的,因为两个密度代表集群的基本分割。
_=clf.hdbscan_.condensed_tree_.plot(
select_clusters=True,
selection_palette=sns.color_palette("deep", np.unique(clusters).shape[0]),
)

作者照片
最后,让我们确认大部分数据点被我们的聚类(提示:只有 9 个没有)和 DBCV 分数覆盖。
coverage = np.sum(clustered) / embedding.shape[0]
print(f"Coverage {coverage}")
print(f"DBCV score {clf.hdbscan_.relative_validity_}")Coverage 0.9982
DBCV score 0.2811143727637039
在-1 比 1 的范围内,DBCV 系数为 0.28。
这不太好,但还可能更糟。让我们优化分数,找出要通过的最佳 HDBSCAN 超参数。
超参数调谐🦾
进一步改善结果的两个主要超参数是min_samples和min_cluster_size,如 HDBSCAN 文档中所述。
您将运行这些的多个组合,以找到产生高 DBCV 分数的结果。
除了查看这些超参数外,您还将查看具有大规模 eom 预期的聚类选择方法,以及使用树叶沿树分割聚类(详情请参* hdbscan:麦金尼斯 j . Healy s . Astels 2017 中的基于分层密度的聚类)。
正如 HDBSCAN 的文档所指出的,eom 方法只从树中提取最稳定、最精简的集群,而 leaf 方法也从叶节点的底部选择集群。
这导致更小、更同质的集群,更有可能是细粒度的。
from sklearn.model_selection import RandomizedSearchCV
import hdbscan
from sklearn.metrics import make_scorer
logging.captureWarnings(True)
hdb = hdbscan.HDBSCAN(gen_min_span_tree=True).fit(embedding)
# specify parameters and distributions to sample from
param_dist = {'min_samples': [10,30,50,60,100],
'min_cluster_size':[100,200,300,400,500,600],
'cluster_selection_method' : ['eom','leaf'],
'metric' : ['euclidean','manhattan']
}
#validity_scroer = "hdbscan__hdbscan___HDBSCAN__validity_index"
validity_scorer = make_scorer(hdbscan.validity.validity_index,greater_is_better=True)
n_iter_search = 20
random_search = RandomizedSearchCV(hdb
,param_distributions=param_dist
,n_iter=n_iter_search
,scoring=validity_scorer
,random_state=SEED)
random_search.fit(embedding)
print(f"Best Parameters {random_search.best_params_}")
print(f"DBCV score :{random_search.best_estimator_.relative_validity_}")Best Parameters {'min_samples': 100, 'min_cluster_size': 300, 'metric': 'manhattan', 'cluster_selection_method': 'eom'}
DBCV score :0.48886415007392386
DBCV 得分现在已经从 0.28 上升到 0.488。
DenseClus 默认min_samples为 15,min_cluster_size为 100。随机搜索结果具有更大和更严格的聚类,这导致更高的密度和更高的分数:)城市街区距离或曼哈顿距离似乎也有助于增加。
在实践中,我们希望分数超过 0.45,以确保聚类被很好地分离,这个分数表明了这一点。
让我们通过观察集群是如何分裂的并再次可视化结果来确认这一点。
# evalute the clusters
labels = random_search.best_estimator_.labels_
clustered = (labels >= 0)
coverage = np.sum(clustered) / embedding.shape[0]
total_clusters = np.max(labels) + 1
cluster_sizes = np.bincount(labels[clustered]).tolist()
print(f"Percent of data retained: {coverage}")
print(f"Total Clusters found: {total_clusters}")
print(f"Cluster splits: {cluster_sizes}")
_=sns.jointplot(
x=embedding[clustered, 0], y=embedding[clustered, 1], hue=labels[clustered], kind="kde"
)Percent of data retained: 1.0
Total Clusters found: 3
Cluster splits: [2501, 1236, 1263]

作者照片
有趣的是,足够没有发现噪音。两个星团完全相同,其中一个的大小几乎是它们的总和。
将同一切片上的数据可视化给了我们一个线索,让我们知道这里发生了什么。我们之前运行的编号为 3 和 2 的集群现在合并在一起了。
转移到不同的维度切片有时可以帮助解释这里的事情,下图显示了一个更好的视图。
_=sns.jointplot(
x=embedding[clustered, 1], y=embedding[clustered, 2], hue=labels[clustered], kind="kde"
)

作者照片
总结🥂
我希望您喜欢仔细研究如何为 HDBSCAN 调优超参数!!!
在这篇文章中,您了解了为什么聚类和聚类指标会变得复杂,然后了解了作为客观指标的 DBCV,然后使用 Amazon Denseclus 和 HDBSCAN 应用了它。
我们在这里只讨论了表面。要深入了解,您可以查看以下内容:
- 你能使用什么其他类型的优化框架来代替随机搜索?
- 有哪些其他类型的超参数可以用于优化?
- 对于进一步的聚类验证,还有什么其他的方法?
- Denseclus 中的任何其他底层超参数可以调整以获得更高的分数吗?
参考
“轮廓:聚类分析解释和验证的图形辅助”,Rousseeuw,1987 年
“基于密度的聚类验证”,Moulavi 等人,2014 年
“hdbscan:基于分层密度的聚类”,麦金尼斯,J. Healy,S. Astels 2017
用 XGBoost 调优 XGBoost:编写自己的 Hyper Parameters 优化引擎
原文:https://towardsdatascience.com/tuning-xgboost-with-xgboost-writing-your-own-hyper-parameters-optimization-engine-a593498b5fba?source=collection_archive---------7-----------------------
更新:发现我关于渐变提升的新书,实用渐变提升。这是用 python 中的许多例子对渐变增强的深入探究。
https://www.amazon.com/dp/B0BJ82S916 [## 实用的渐变增强:深入探究 Python 中的渐变增强
这本书的梯度推进方法是为学生,学者,工程师和数据科学家谁希望…](https://www.amazon.com/dp/B0BJ82S916)
更新:了解如何重用下面详述的方法来执行模型选择(向 AutoML 迈进的又一步):

照片由 Unsplash 上的 Indra Utama 拍摄
编写一个超参数调整引擎似乎是一个巨大的挑战。我们开始吧!
正如你可能知道的,如果你熟悉数据科学、机器学*、数据科学或我以前关于这个主题的文章,微调你的模型对获得最佳性能至关重要。你不能依赖默认值。
正如 Satyam Kumar 在他的上一篇文章中所说,有几种方法可以实现这种优化。它们的范围从手动调整、随机搜索、暴力到贝叶斯搜索。这些方法各有优缺点。
本文将重点介绍一种最近的执行 HP 优化的方法:基于模型的 HP 调优。
这种方法非常有趣,因为它使用 ML 方法来调优 ML 模型。我们可以重用我们熟悉的工具来优化我们熟悉的工具:)令人目不暇接,不是吗?
超参数可以被视为结构化的表格数据,对于结构化的表格数据,我们所知道的最通用的 ML 算法是什么?卡格尔竞赛的无争议冠军?XGBoost!
让我们看看我们可以用它做什么,并尝试使用它来调整自己。
基于模型的惠普调整
基于模型的调优背后的想法非常简单:为了加速收敛到给定用例的最佳参数,我们需要一种方法来引导超参数优化到最佳解决方案。事实上,训练一个模型可能很耗时,这取决于训练集的大小,以及通常非常大的配置空间的组合学。
这意味着我们需要一种方法来确定最有前途的配置进行评估。为什么不简单地使用一个模型来学*一个给定配置的分数估计值呢?每一次训练都将被用来改进潜在的模型,并给我们一些探索方向的洞察力。这是基于模型的超参数优化的主导思想。
如果你对这个想法背后的理论感兴趣,我强烈建议你阅读这篇学术论文。您可能也很想看看使用这种方法的 SMAC 的实现。
总体方法
基于模型优化超参数的整体算法非常简单:
- 随机选择 n 个配置
- 使用对配置进行评分的内部评估器来评估这些配置
- 保留给出最佳分数估计的配置,丢弃所有其他配置
- 使用此配置训练模型
- 将当前配置和分数存储到内部评估器的训练集中
- 重新训练内部评估者
- 回到步骤 1。如果尚未达到最大迭代次数或最小分数。
让我们看看如何实现这一点。
采样配置空间
我们要回答的第一个问题是:我们如何对配置空间进行采样?即:我们如何在配置空间中随机挑选一个合格的配置?
这不是一个非常困难的任务,我们可以自己编写一些代码来解决这个问题,但幸运的是,有一个库可以为我们处理所有的负担:配置空间。更具体地说,ConfigurationSpace 可以处理条件配置。我们在这里不会用到这个特性,但是它在很多情况下非常有帮助。
以下示例显示了如何使用 ConfigurationSpace 随机生成 RandomForest 配置:
在几行代码中,我们可以轻松地生成随机配置。作者的代码。
选择正确的模型
和数据科学一样,现在的下一个问题是:我们应该使用什么模型来构建一个可信的估计器?
最初,基于模型的优化使用高斯过程来估计配置得分,但是最近的论文显示基于树的模型是一个很好的选择。放弃高斯过程的主要原因是它们不支持分类特征。
正如上面几行所述,当谈到基于树的模型时,最直接的(但可能不总是最好的)答案是 XGBoost!
为什么使用 XGBoost?不仅因为 XGBoost 和梯度增强方法非常有效,是 Kaggle 竞赛中最常获胜的方法之一,还因为它们非常通用,不需要太多预处理:不需要特征归一化,缺失值可以自动处理,…
说实话,用 XGBoost 来优化 XGBoost 也很搞笑。然而,我们还会考虑另一个选项,它与 XGBoost 非常相似,但具有明显的原生支持类别的优势:C atBoost 。
处理分类特征是一个非常方便的功能,因为许多模型参数都是分类的。认为 XGBoost 目标,助推器或 tree_method 参数为例。
LightGBM 也是一个完美的选择。
调整模型超参数
我们现在拥有创建我们自己的超参数优化引擎所需的所有元素。为此,我们创建一个由四个参数配置的优化器类:
- algo_score :用于给给定配置的模型或算法评分的方法。
- max_iter :要执行的最大训练次数
- max _ enhancement:随机抽样的候选配置的最大数量
- 模型:用作分数估计器的内部模型的类别
- cs :探索的配置空间
正如您在下面看到的,这不需要太多行:
这个类使用一个模型实现 HP 调优。来自作者的代码
上面代码的关键部分在于优化函数。这个函数做三件事:
- 它将探索的配置存储在列表CFG 中。
- 它将选择的配置存储在列表轨迹中
- 它使用内部模型提供的分数估计选择候选配置进行探索。
- 它使用过去的训练分数来训练估计器
性能分析
为了评估我们基于模型的超参数引擎的效率,我们将使用波士顿数据集。您可能已经知道,这个数据集包含波士顿房价的信息。我们的模型的目标是估计给定特征的房价。首先,我们将使用 RandomForest 作为我们的基本模型。我们将在这个模型上评估我们基于模型的方法。
首先,让我们确保我们的引擎确实有助于更快地收敛到更好的配置。为此,我们比较了使用 RandomSearch 和我们的引擎时的学*进度。在下面的代码中,我们使用 sci kit learnRandomizedSearchCV和我们的优化器来随机探索配置空间:
将 RandomizedSearchCV 与我们的引擎进行比较。作者代码。
看下图,毫无疑问,我们的引擎比随机搜索更有效。更准确地说,很明显,我们的引擎随着迭代不断学*和改进:

RandomizedSearchCV vs 我们的引擎。作者的情节。
随机搜索不出所料明显不稳定。
由于您的代码(相对)独立于用作分数估计器的模型,我们还可以比较 XGBoost 和 Catboost 的收敛速度。代码如下:
比较 CatBoost 与 categories、XGBoost 和 CatBoost 一起使用时的收敛性。作者代码。
生成的图显示在下图中:

CatBost(有和没有分类特征)与 XGBoost。作者的情节。
这两种情况下的表现看起来非常相似。请记住,score estimator 的 XGBoost 和 CatBoost Hyper 参数都没有优化:都使用默认配置。我们可以尝试使用另一个评分模型来调整评分模型,但是这篇文章看起来会像盗梦空间电影一样复杂;)
另一个值得分析的方面是强化步骤持续时间的影响。当在探索空间中挑选随机候选者时,我们可以增加候选者的数量。在下面的图中,我们分别用 25、250 和 2500 个强化候选对象来训练我们的模型。代码和前面的类似。我们只是对优化器进行了不同的配置:
比较不同程度的强化。作者代码
结果图如下:

强化步骤的数量似乎不影响收敛速度。作者的情节。
在这种情况下,强化似乎没有什么影响。
最后,正如承诺的那样,我们将使用 XGBoost 来调优 XGBoost。代码与 RandomForest 的代码完全相同,只是我们使用 XGBoost 作为主模型。参*下面的代码:
使用 XGBoost 调优 XGBoost。作者代码。
请注意,我们还使用 CatBoost 作为内部评分估计器,以便进行比较。看下面的图,似乎在这种情况下,XGBoost 比 CatBoost 略胜一筹:

使用 XGBoost 调优 XGBoost。图片由作者提供。
更进一步
我们已经在这篇文章中表明,建立一个像样的超参数优化引擎并不复杂。通过几行代码,有可能大大加快模型训练的速度。
可笑的是,你不需要使用外部库。重用现有的模型是可行的。XGBoost 可以用来调优 XGBoost,CatBoost 可以用来调优 CatBoost,RandonForest 可以调优 RandomForest。也可以混合使用。
虽然我们的模型工作得很好,但一个非常有趣的改进是更新随机样本,使用贝叶斯策略来生成候选人,使用学*分布而不是随机采样。
增强您的命令行游戏
原文:https://towardsdatascience.com/turbocharge-your-command-line-game-3344b16bfeec?source=collection_archive---------11-----------------------
你的工具集中缺少的瑞士军用工具。

维多利亚诺·伊斯基耶多在 Unsplash 上拍摄的照片
在从事机器学*项目时,我通常通过 ssh 登录到某个服务器,其中终端是唯一可用的界面。然而,准系统工具非常有限,这降低了我的工作效率。
这篇文章将向你展示如何使用一个名为 fzf 的模糊查找器来增强你的命令行游戏,从而显著提高工作效率。由于浏览 fzf 提供的所有特性会很冗长,所以我的目标是让您知道这个工具是存在的,您不需要成为一个高级程序员就可以使用它,最后,为您提供使它适应您的工作流的基本模块。
设置
首先,您必须使用您的包管理器或从 git 安装 fzf。对于其他操作系统,检查 fzf 文档中的安装部分。
# Conda
conda install -c conda-forge fzf# Debian 9+ and Ubuntu 19.10+
sudo apt-get install fzf# Git
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install# macOS
brew install fzf
$(brew --prefix)/opt/fzf/install
安装后,您可以通过在终端中键入fzf来检查它是否正常工作。它应该递归地显示当前文件夹中所有文件的列表。

Fzf 命令
此时,您可能会问自己这有什么用,因为命令返回文件路径,仅此而已。那么,让我们看一些用例。
使用
在我们开始之前,我强烈建议您在阅读本节内容时尝试一下您自己的命令。
基础
首先,让我们回顾一下如何与 fzf 交互的一些基础知识:
- 要上下移动列表,使用
<CTRL j/n>和<CTRL k/p>。 - 一旦你找到你要找的文件,点击
<ENTER>选择文件。 - 要进行精确匹配,请使用
'。比如'myfile。 - 要匹配后缀,请使用
$。比如.py$。 - 要匹配前缀,请使用
^。比如^test_。 - 要匹配多个标准,请使用
|。比如.py$ | .json$。 - 要退出,点击
<CTRL c>。
命令历史
我们都遇到过这样的情况,你想执行一个以前用过的命令,但是找不到。首先,本机 UNIX 搜索命令历史很难使用。第二,打 20 次箭头键不实用。所以现在你已经安装了 fzf,在你的终端点击<CTRL r>开始享受吧!

用 fzf 显示命令历史
更改目录
在处理深度嵌套的文件夹结构项目时,四处移动会变得非常乏味,尤其是在不熟悉的情况下。要使用 fzf 来改变目录,请在您的终端中点击<ATL c>,然后模糊查找您正在搜索的文件夹。

用 fzf 更改目录
显示文件内容
假设您想要显示一个特定文件的内容,但是您不记得确切的文件名和位置。蛮力解决方案将是cd到一堆文件夹试图找到它。另一个解决方案是使用搜索工具。但是,如果您不知道确切的文件名,您将需要使用 regexp。最后,打开 IDE,等待它启动,打开项目,然后找到文件。
现在让我们看看使用 fzf 这个工作流会是什么样子。举个例子,我想显示myfile.txt的内容,但是假设我只记得文件名中包含了my。

用 fzf 显示文件内容
我在上面使用的命令是cat,因为我想显示文件的内容。但是,您可以使用任何将文件路径作为参数的命令。此外,您可以使用$(fzf)或**<TAB>获得相同的结果,如下所示:
<YOUR COMMAND> $(fzf)/`fzf`# or
<YOUR COMMAND> <CTRL t># or
<YOUR COMMAND> **<TAB>
选择多个文件
假设你想删除三个不同目录下的文件,但是你不知道它们的具体位置。从我们所看到的,解决方案将是一个接一个地选择和删除文件。
# For file 1
rm <CTRL t># For file 2
rm <CTRL t># For file 3
rm <CTRL t>
但是,fzf 使用<TAB>键提供了多选功能。在下面的例子中,我使用多重选择删除三个不同目录中的三个文件。

用 fzf 删除文件
过滤命令的输出
在上面的所有例子中,我们使用 fzf 为命令(cd、rm 等)提供参数。).但是,fzf 也可以过滤命令的输出,这在命令输出很长的情况下非常有用。在下面的例子中,我使用 fzf 在ps命令输出中搜索,使用ps aux | fzf检查一些进程的状态。

用 fzf 对 ps 输出进行滤波
构建您自己的
在上面所有的例子中,我们使用了 fzf 默认提供的界面和快捷键。但是,您可以创建自己的。本节将展示如何使用 fzf 构建符合您需求的定制实用程序。我选择了一个我经常使用的简化版本的工作流,但是您可以很容易地修改它来创建您自己的工作流。
使用案例
在许多机器学*项目中,我依赖 JSON lines 格式的数据集。在我的工作流程中,我通常需要先看一眼文件,然后再将它们用作我的训练脚本的参数,特别是因为其中一些文件是自动生成的,可能包含错误。
下面是简化的项目结构。train.py是 python 训练脚本,data是包含数据文件的文件夹。此外,训练脚本接受一个表示要使用的数据文件的参数。
fzf-demo
├─ train.py
├─ data/
├─── dataset_1.jsonl
├─── dataset_2.jsonl
...
├─── dataset_n.jsonl
此外,我还创建了一个演示库,您可以克隆它来自己复制演示。
git clone [git@github.com](mailto:git@github.com):Am1n3e/fzf-demo.git
列出数据集文件
首先,我们需要列出可用的数据集文件,然后使用 fzf 选择一个。
ls data/*.jsonl | fzf
上面命令的输出应该如下所示:

Fzf 列表文件
在这个例子中,我只使用ls命令列出了本地文件。但是,您可以将 fzf 用于任何命令或应用程序的输出。例如,您可以列出 S3 存储桶中的文件。
添加预览
正如我前面解释的,在开始培训之前,我需要快速浏览一下文件(可能是前两行)。此外,我不想打开整个文件,因为有些文件很大,需要花时间打开。最后,我希望在不退出 fzf 的情况下选择数据文件时看到预览。
首先,我将使用head读取前两行,并使用jq(参*此处的了解更多关于jq命令的信息)格式化输出。例如,head -n 2 data/dataset_1.jsonl | jq .将输出以下内容:

数据集预览示例
然后,我可以使用--preview参数将其添加到 fzf,如下所示。
ls data/*.jsonl | fzf --preview 'head -n 2 {} | jq .'
下面是上面命令的输出。正如您所看到的,当我选择数据文件时,预览得到了更新。

带预览的 Fzf 列表文件
--preview参数的值可以包含任何命令。如果预览更复杂,您甚至可以调用自己创建的脚本。你唯一需要记住的是 fzf 会用当前选中的行替换{}。在我们的例子中,它是文件路径。
绑定命令
在我的用例中,我还想删除不存在 fzf 的包含错误的文件。为此,我们可以使用--bind参数绑定一个命令,如下所示:
ls data/*.jsonl | \
fzf \
--preview 'head -n 2 {} | jq .' \
--bind 'tab:execute(rm {})'
在这里,我将<TAB>映射为运行rm。与--preview参数类似,{}包含所选行的内容。请注意,您可以映射多个命令。但是,有一组您可以使用的快捷方式(详*man fzf)。
临时演员
fzf 提供了多个选项来定制界面,如颜色、边框、帮助、布局、大小等。以下是我使用的选项:
ls data/*.jsonl | \
fzf \
--preview 'head -n 2 {} | jq .' \
--bind 'tab:execute(rm {})' \
--layout=reverse \
--border \
--prompt "train_file> " \
--header $'Press TAB to delete the selected file\n\n'

自定义 fzf 实用程序
有关更多详细信息,请查看文档。
把它放在一起
现在我们已经准备好了 fzf 命令,我们可以使用它的输出作为train.py脚本的参数,如下所示。为了方便起*,我创建了一个函数,并将其添加到我的~/.zshrc或~/.bashrc文件中。
train() {
data_file=$(ls data/*.jsonl | \
fzf \
--preview 'head -n 2 {} | jq .' \
--bind 'tab:execute(rm {})' \
--layout=reverse \
--border \
--prompt "train_file> " \
--header $'Press TAB to delete the selected file\n\n') && \
python train.py $data_file
}

最后,如果您想为任何知名工具构建一个 fzf 实用程序,首先检查这个库。它包含多个实用程序,您可以按原样使用或作为示例使用。
结论
在这篇文章中,我讲述了一些基本的 fzf 用法,并向你展示了如何构建自己的 fzf。然而,我只是刷了一下使用 fzf 可以完成的事情的表面。我的目标是让你知道这个工具是存在的,并且不难使用。
*除非另有说明,所有图片均出自 Amine El hattami 之手。
在你走之前
在推特上关注我,我经常在推特上发布关于软件开发和机器学*的消息。
将熊猫数据帧转换成 API
原文:https://towardsdatascience.com/turn-a-pandas-dataframe-into-an-api-ac56eaefe11b?source=collection_archive---------10-----------------------
与他人共享数据框架或将数据集成到前端。
熊猫数据框是我最喜欢的用 Python 操作数据的方式。事实上,我的许多小型分析项目的最终产品只是一个包含我的结果的数据框架。
我过去常常将我的数据帧转储到 CSV 文件中,并保存到 Github 中。但是最近,我一直在使用下面的,一个我正在构建的数据共享服务,来保存我的数据帧,同时将它们转化为一个完整的 API 和一个网站。当我需要将数据集移交给客户端或将数据集成到前端时,它非常有用。
在这篇文章中,我将向你展示这是如何工作的!我将获取 GitHub 提交,分析它们,并使用 before 将结果转换成 API。
下的设置
要开始,你需要安装 underpip模块,并使用免费 under 帐户登录。这很简单,医生已经做好了准备。只要按照这些步骤就可以了。
请务必记住您的用户名,因为您马上就要用到它了!
让我们分析一些数据
我认为 Github 活动是一个迷人的、未被充分开发的数据源。让我们揭开表面,看看对…熊猫的承诺!这里有一个快速脚本来获取pandas源代码,并汇总一些关于提交和贡献者数量的每日统计数据:
现在,df变量包含了我们的洞察力。如果您正在跟进,您可以更改repo变量来抓取另一个 Github 项目。只是要小心一些主要的回购可能要花很长时间来分析(我看着你, torvalds/linux )。
将数据框保存到下方
首先,我们将创建一个新项目来存储我们的结果。我将从命令行完成,但是您也可以使用 web 控制台:
beneath project create USERNAME/github-fun
只需用你自己的用户名替换USERNAME。
现在,我们准备发布数据框架。我们在 Python 中直接用一个简单的一行程序来实现它(好吧,我把它分成了多行,但它仍然只是一个调用):
这里发生了一些事情。让我们浏览一下:
table_path给出了输出表的完整路径,包括我们的用户名和项目。- 我们使用
records参数来传递我们的数据帧。 - 我们为数据提供一个
key。自动生成的 API 使用键索引数据,这样我们可以快速过滤记录。默认情况下,index 将使用 DataFrame 的索引作为键,但我更喜欢手动设置它。 description参数向数据集添加了一些文档,这些文档将显示在表页面的顶部。
就是这样!现在让我们来探究结果。
探索您的数据
您现在可以前往 web 控制台并浏览数据及其 API 文档。我的名字在https://beneath.dev/epg/github-fun/table:pandas-commits(如果你使用相同的项目和表名,你可以把我的用户名epg替换成你自己的)。

在下面的控制台中浏览您的数据
您还可以共享或发布数据。权限是在项目层管理的,所以只需进入项目页面添加成员或将项目设置切换到public。
使用 API
既然数据在下面,任何有权限的人都可以使用这个 API。在表格页面的“API”选项卡上,我们获得了用于集成数据集的自动生成的代码片段。
例如,我们可以将数据帧加载回 Python:
或者我们可以在 2021 年 5 月的每一天查询 REST API 并获取提交信息:
或者使用 React 钩子将数据直接读入前端:
在下面的控制台中查看我的数据框架的 API 标签以查看使用数据的所有方法。
好了
就是这样!我们使用 used 将熊猫数据帧转换成 API。如果您有任何问题,我大部分时间都在线,在 under 的 Discord (我喜欢谈论数据科学,所以也欢迎您只是打个招呼👋).让我知道你是否发布了一个很酷的数据集,我可以在特色项目中聚焦!
使用 Streamlit 将 Excel 变成漂亮的 Web 应用程序
原文:https://towardsdatascience.com/turn-excel-into-a-beautiful-web-application-using-streamlit-7a18516ca01a?source=collection_archive---------4-----------------------
细流系列
使用 python 库 Streamlit 将您的 excel 电子表格呈现为交互式仪表盘 web 应用程序

马修·贝尔泰利从派克斯拍摄的照片
什么是 Streamlit?
Streamlit 是一个开源的 Python 库,可以轻松地为机器学*和数据科学项目创建和共享漂亮的定制 web 应用程序[1]
Streamlit 的一个主要特性是它为你提供了一个类似 Jupyter 笔记本的环境,当你保存你的脚本时,你的代码会实时更新。这很有帮助,尤其是对于初期的 app 开发阶段。

图片来自 Streamlit.io. GIF 作者
电子表格和数据科学项目的问题
excel 和数据科学项目存在的问题是缺乏一种简单的方式来呈现结果(也称为生产部署)。对于要呈现的 excel 文件,您需要将它与可视化工具(如 Power BI、Tableau 或 Powerpoint)链接起来。
然而,要实现一个数据科学项目,您需要实现一个后端服务器,如 Django、Flask,以及一个前端 UI,如 React 和 Vue.js。
这些复杂性使得用电子表格和数据科学项目共享数据变得极其枯燥和乏味。
幸运的是,在 Streamlit 的帮助下,我们可以轻松地从 Excel 电子表格中创建一个交互式 web 应用程序,并轻松地部署数据科学项目。🙌
在本文结束时,您将能够创建一个交互式的 excel dashboard web 应用程序,使用户能够过滤数据、可视化图形并使用 URL 轻松访问。或者,您可以访问 web 应用程序这里和存储库这里

交互式 excel 仪表板。作者图片
开始使用:
我们将使用 Kaggle 的《2021 年世界幸福报告》作为本文的数据集,请随意下载:
*https://www.kaggle.com/ajaypalsinghlo/world-happiness-report-2021
通过 pip 安装安装 Streamlit
pip install streamlit
通过在命令提示符下键入 Streamlit CLI 来验证您的安装
streamlit hello
就是这样!在接下来的几秒钟内,示例应用程序将在您默认浏览的新选项卡中打开。
要制作自己的应用程序,创建一个空白的 python 文件 app.py ,并使用 streamlit CLI 运行它。然后,单击 localhost URL 进入您的第一个 streamlit web 应用程序!
streamlit run app.py

启动 streamlit web 应用程序。作者图片
了解用户界面
默认情况下,Streamlit 已经有两个地方可以放置代码和小部件,分别是侧边栏和内容。您可以在内容区域添加元素和小部件,只需使用:
import streamlit as st
st.**[element_name]**
您可以在侧边栏中添加元素和小部件,只需使用:
import streamlit as st
st**.sidebar.**[element_name]
您可以根据内容区域在侧边栏中放置任何元素,在撰写本文时唯一不支持的元素是st.echo和st.spinner。

Streamlit 应用程序的区域。作者图片
加载数据
使用 pandas 可以从 Excel 和 CSV 加载数据:
import pandas as pd#For Excel File
df = pd.read_excel("world-happiness-report-2021.xlxs")#For CSV File
df = pd.read_csv("world-happiness-report-2021.csv")
显示部件
显示小部件非常简单,您想要一个文本,只需将它写成:
st.**title**(“World Happiness Index 2021:”)
如果您希望它出现在侧边栏中,只需将代码编写为:
st**.sidebar.**title(“World Happiness Index 2021:”)
如果你想要一个图像,只需写下:
st.**image**(“https://images.pexels.com/photos/573259/pexels-photo-573259.jpeg?cs=srgb&dl=pexels-matheus-bertelli-573259.jpg&fm=jpg", caption=’World Happiness Dataset’)
如果你想显示一个数据帧,只需写:
st.**write**(filtered_df)

打印数据框。作者图片
这就是它在 Streamlit 中的工作原理!
控制器部件
Streamlit 有一个“类似状态”的组件功能,用户与小部件的交互将改变变量的状态。然后,变量的新值将用于重新渲染整个项目的组件。
在这个项目中,我们将创建一个 选择框小部件 用于过滤国家和一个滑块 用于过滤侧边栏中的阶梯分数。
**#Country Select Filter**
country_list = ["All","Western Europe", "South Asia", "Southeast Asia", "East Asia", "North America and ANZ","Middle East and North Africa", "Latin America and Caribbean","Central and Eastern Europe","Commonwealth of Independent States","Sub-Saharan Africa"]select = st.sidebar.selectbox('Filter the region here:', country_list, key='1')if select =="All":
filtered_df = df
else:
filtered_df = df[df['Regional indicator']==select]**#Ladder Score Slider**
score = st.sidebar.slider('Select min Ladder Score', min_value=5, max_value=10, value = 10) # Getting the input.
df = df[df['Ladder score'] <= score] # Filtering the dataframe.
您将获得可以过滤数据框的小部件,如下所示:

控制器小部件。作者图片
可视化小部件
Streamlit 支持几个不同的图表库,如 Matplotlib、Seaborns、Ploty、Altair 图表。它还提供了一些本地图表,如折线图和面积图,可以通过一行代码调用,例如:
**#Line Chart**
st.line_chart(data=None, width=0, height=0, use_container_width=True)**#Area Chart**
st.area_chart(data=None, width=0, height=0, use_container_width=True)
但是,在本教程中,我们将对散点图和条形图使用 Plotly express。然后,我们将 seaborn 用于热图,如下所示:
import plotly.express as px
import seaborn as sns**#Scatter Chart**
fig = px.scatter(filtered_df,
x="Logged GDP per capita",
y="Healthy life expectancy",
size="Ladder score",
color="Regional indicator",
hover_name="Country name",
size_max=10)st.write(fig)**#Bar Chart**, you can write in this way too
st.write(px.bar(filtered_df, y='Ladder score', x='Country name'))**#Seaborn Heatmap**
#correlate data
corr = filtered_df.corr()#using matplotlib to define the size
plt.figure(figsize=(8, 8))#creating the heatmap with seaborn
fig1 = plt.figure()ax = sns.heatmap(corr,
vmin=-1, vmax=1, center=0,
cmap=sns.diverging_palette(20, 220, n=200),
square=True
)ax.set_xticklabels(
ax.get_xticklabels(),
rotation=45,
horizontalalignment='right'
);st.pyplot(fig1)
注意:对于 Seaborn 来说,它是一个 axes 组件,所以不能直接使用 st.write 来呈现图表,而必须使用 st.pyplot 来呈现组件。*
通过简化 it 共享进行部署
Streamlit 还有另一个独特的功能,称为 streamlit 共享,他们可以帮助你在他们的网站上托管你的 streamlit 应用程序。只需在与 app.py 相同的文件夹中准备一个requirements . txt文件就行了。
requirements.txt 文件告诉系统应用程序将使用什么 python 包,在我们的例子中,它将是:
*streamlit==0.83.0
numpy==1.18.5
pandas==1.2.4
matplotlib==3.4.2
plotly-express==0.4.1
seaborn==0.11.1*
单击部署,您将获得您的 web 应用程序的 URL。🎉🎉

简化 it 共享部署共享。图片作者。
*在撰写本文时,Streamlit 分享需要 Streamlit 的邀请。他们花了大约 2 个工作日批准我的账户
经由 Heroku 的部署
除了推荐的功能,您还可以将您的应用程序托管在 Heroku 或任何其他自定义主机上,如 digital ocean、AWS 或 google cloud。我将展示 Heroku 的托管方法,因为这是一个免费的解决方案。
要在 Heroku 中托管,您需要在完全相同的位置使用与上面完全相同的 requirement.txt。除此之外,您还需要另外两个文件,它们是:
a) Procfile:
*web: sh setup.sh && streamlit run app.py*
b)设置. sh:
*mkdir -p ~/.streamlit/echo "\
[general]\n\
email = \"<youremail>\"\n\
" > ~/.streamlit/credentials.tomlecho "\
[server]\n\
headless = true\n\
port = $PORT\n\
enableCORS = false\n\
\n\
" > ~/.streamlit/config.toml*
复制与上面完全相同的设置,您将得到如下的文件夹结构:

项目文件夹结构。作者图片
我在 Heroku 和 Streamlit Sharing 主持过同一个项目,你可以亲自查看并比较速度和功能。在我看来,这两种方式各有利弊,Streamlit Sharing 提供免费主机服务,Heroku 的主机服务每个账户只能有 2 个免费主机服务。
最终想法
在本文中,我们介绍了 Streamlit 的基础知识,包括安装、在 Streamlit 中编写脚本的基本概念、仪表板设计、图表可视化和 web 应用程序的部署。
Streamlit 是数据表示工具的新范例,具有巨大的潜力。它解决了数据科学中的最后一英里问题,即将项目轻松交付给最终用户,无论是外行还是同行数据科学家。我花了不到一个小时的时间理解了 Streamlit 的概念,并带着它来到了❤️,我希望我的分享也能激发你对 Streamlit 的兴趣!
最后,非常感谢您阅读我的文章。
旁注:
这里有一段视频介绍什么是 100 秒内简化:
100 秒内简化
如果您对 excel 自动化感兴趣,这篇文章是必读的:
* [## 使用 Python 自动化 Excel
towardsdatascience.com](/automate-excel-with-python-7c0e8c7c6256)
我的其他文章包括:
[## 5 分钟内自动完成谷歌表单报告
towardsdatascience.com](/automate-google-sheet-reporting-in-5-minutes-8bbdc1f8e293)
参考资料:
[1]https://streamlit . io
[2]https://doc.streamlit.io/*
将 JSON 转化为可操作的数据—午餐
原文:https://towardsdatascience.com/turn-json-into-actionable-data-lunch-fb5a2834212f?source=collection_archive---------29-----------------------

作者照片
心理学认为,在我们的短期记忆中,人类一次能够处理多达 7 条信息。这就是为什么我们很难快速处理 JSON 对象。信息太多了,我们小小的大脑容纳不下。要将 JSON 转换成可操作的数据,我们需要将其加载到表中,并使用 SQL 缩小范围。
这里有一些有趣的 JSON 资源,其中的食谱比我能理解的还要多。我想总结一下这些数据,找出一些好吃的东西来做——最好是在午饭前,因为我饿了。我将使用 JSON 解析把它加载到 Snowflake 中。
- 阿特金斯标签中的食谱
- 公开菜谱
我可以看到像 https://schema.org/Recipe[这样的 JSON 模式,但是我的小脑袋就是不能理解它。这就是为什么我会使用像雪花数据库这样的工具将数据转换成表格,并将其总结成小块。](https://schema.org/Recipe)

作者照片
在 Snowflake 中存放数据的最佳方式是使用存储集成来避免密码共享并正确利用角色。
- 创建存储集成
一旦你有了一个合适的存储集成,把上面的食谱复制到 S3 的 stage 文件夹中,然后为每个文件夹创建一个 stage。
create or replace stage owlmtn.stage.recipes
storage_integration = azrius_data
url = 's3://my-s3-data-bucket/stage/recipes';
从查询将普通 JSON 转换成表开始。
create or replace table tab_atkins_recipes as
select t.KEY as ID, value:name::String name, value:tags tags_variant, value:ingredients ingredients_variant
from **@owlmtn.stage.recipes** (
pattern =>'.*.json',
file_format => stage.json_file_format) s,
table(flatten((s."$1"))) t;
该表为我提供了一种快速查询数据库的方法,以找出午餐做什么。我们吃素吧。当然,还有…我要用完鸡蛋了。
select *
from tab_atkins_recipes
where tags_variant like '%vegetarian%'
and ingredients_variant like '%eggs%';
这产生了 28 个结果。太多了,我的小脑袋无法理解。煎蛋卷怎么样?
select *
from tab_atkins_recipes
where tags_variant like '%vegetarian%'
and ingredients_variant like '%eggs%'
and name like '%omelet%';
通过查看表格,我可以很容易地理解做出选择所需的信息。我想我会选择墨西哥马铃薯煎蛋卷。
结论
将 JSON 数据转换成表格是理解、交流和决策的强大工具。表格布局在我们的大脑中组织数据,并允许我们快速进行关联。
将雪花实例上的 JSON 转换放在手边,并在需要生成可操作的事件时使用 JSON 数据上的转换,即使该事件只是午餐。
使用 Python 将照片变成卡通
原文:https://towardsdatascience.com/turn-photos-into-cartoons-using-python-bb1a9f578a7e?source=collection_archive---------1-----------------------
你可以通过在 Python 中实现机器学*算法来给一张照片赋予卡通效果。

凯特·温吉尔特在 Unsplash 上的原始图片,由作者编辑
你可能知道,画草图或创作一幅漫画并不总是需要手动完成。现在很多 app 都可以把你的照片变成漫画。但是如果我告诉你,你可以用几行代码创建你自己的效果呢?
有一个名为 OpenCV 的库,它为计算机视觉应用程序提供了一个公共基础设施,并拥有优化的机器学*算法。它可用于识别物体、检测和生成高分辨率图像。
在本教程中,我将向你展示如何利用 OpenCV 在 Python 中给一幅图像赋予卡通效果。我使用 Google Colab 来编写和运行代码。你可以在这里 访问 Google Colab 中的完整代码
创造一个卡通效果,需要注意两点;边缘和调色板。这就是照片和漫画的区别。为了调整这两个主要组件,我们将经历四个主要步骤:
- 加载图像
- 创建边缘遮罩
- 减少调色板
- 将边缘遮罩与彩色图像结合
在跳转到主要步骤之前,不要忘记导入笔记本中需要的库,尤其是 cv2 和 NumPy。
import cv2
import numpy as np**# required if you use Google Colab**
from google.colab.patches import cv2_imshow
from google.colab import files
1.加载图像
第一个主要步骤是加载图像。定义 read_file 函数,该函数包括 cv2_imshow 来加载我们在 Google Colab 中选择的图像。
调用创建的函数来加载图像。
uploaded = files.upload()
filename = next(iter(uploaded))
img = read_file(filename)
我选择了下面的图片来转换成一幅漫画。

Kate Winegeart 在 Unsplash 上拍摄的图片
2.创建边缘遮罩
通常,卡通效果强调图像边缘的厚度。我们可以通过使用cv2.adaptiveThreshold() 函数来检测图像中的边缘。
总的来说,我们可以将 egde_mask 函数定义为:
在这个函数中,我们将图像转换成灰度。然后,我们通过使用cv2.medianBlur来降低模糊灰度图像的噪声。较大的模糊值意味着图像中出现的黑色噪点较少。然后,应用adaptiveThreshold功能,定义边缘的线条尺寸。较大的线条尺寸意味着图像中强调的边缘较厚。
定义函数后,调用它并查看结果。
line_size = 7
blur_value = 7edges = edge_mask(img, line_size, blur_value)
cv2_imshow(edges)

边缘掩模检测
3.减少调色板
就颜色而言,照片和图画的主要区别在于每张照片中不同颜色的数量。图画的颜色比照片少。因此,我们使用颜色量化来减少照片中的颜色数量。
颜色量化
为了进行颜色量化,我们应用了 OpenCV 库提供的 K-Means 聚类算法。为了使接下来的步骤更容易,我们可以将 color_quantization 函数定义如下。
我们可以调整 k 值来确定我们想要应用到图像的颜色数量。
total_color = 9
img = color_quantization(img, total_color)
在这种情况下,我使用 9 作为图像的 k 值。结果如下所示。

色彩量化后
双边过滤器
在进行颜色量化之后,我们可以使用双边滤波器来减少图像中的噪声。这会给图像带来一点模糊和降低清晰度的效果。
blurred = cv2.bilateralFilter(img, d=7, sigmaColor=200,sigmaSpace=200)
您可以根据自己的偏好调整三个参数:
- d —每个像素邻域的直径
- sigmaColor —参数值越大,表示半等色区域越大。
- sigma space–较大的参数值意味着较远的像素会相互影响,只要它们的颜色足够接近。

双边过滤的结果
4.将边缘遮罩与彩色图像结合
最后一步是将我们之前创建的边缘蒙版与经过颜色处理的图像结合起来。为此,使用cv2.bitwise_and功能。
cartoon = cv2.bitwise_and(blurred, blurred, mask=edges)
就在那里!下面我们可以看到原图的“卡通版”。

决赛成绩
现在你可以开始玩代码来创建你自己版本的卡通效果。除了调整我们上面使用的参数值,你还可以添加另一个来自 OpenCV 的函数来给你的照片添加特殊效果。图书馆里还有很多东西我们可以探索。快乐尝试!
参考文献:
- https://www . program creek . com/python/example/89394/cv2 . k means
- http://data hacker . RS/002-opencv-projects-how-to-cartonize-a-image-with-opencv-in-python/
把你的代码变成一个真正的程序:使用 Docker 打包、运行和分发脚本
原文:https://towardsdatascience.com/turn-your-code-into-a-real-program-packaging-running-and-distributing-scripts-using-docker-9ccf444e423f?source=collection_archive---------15-----------------------
在 Docker 容器中轻松共享和运行代码

你的打包代码正在交付(图片由 Kira auf der Heide 在 Unsplash 发布)
有了 Docker,很容易把你的代码打包成我们可以随时随地运行的镜像;不管你的硬件还是软件。它可以在笔记本电脑、Raspberry Pi、服务器、Mac、Linux 或 Windows 上运行。本文将详细介绍将您的脚本打包成可以共享和运行的 Docker 映像的过程。它特别关注如何运行 Docker 映像中的程序。
顺便问一下:你是 Docker 的新员工吗?查看 这篇文章 对 Docker 进行了清晰、简要的介绍,而 这篇文章 对如何使用 Docker 进行了撰写。
1 目标和准备
我编写了两个程序:一个 Python 命令行应用程序和一个 bash 文件。你不局限于 Python 和 bash,你可以使用 Docker 运行任何你喜欢的程序。
bash 文件名为testbash.sh,只是 echo 的“hello world”,没什么特别的。Python 文件叫做py_cmd.py,是一个简单的命令行应用,可以给你讲笑话。我们稍后将对此进行测试。目标是将这些程序打包成 Docker 镜像,运行镜像并调用特定的程序。
首先,我们将检查项目结构和用于将程序打包成映像的 Dockerfile 文件,然后我们将运行映像并使用程序。最后,我们可以通过将我们的图片上传到 Docker Hub 来进行发布;一种 Docker 图片的 YouTube。

我们的目标:包装良好的代码(图片由 Kira auf der Heide 在 Unsplash 上提供)
2 包装成 Docker 图像
把图像想象成一张 CD。它包含所有代码和使用代码的说明。CD 可以像运行图像一样播放。运行的图像称为容器。我们的目标是将所有的源代码打包成一个映像。
项目结构
我们的项目目录中只有 4 个文件:
py_cmd.py包含我们的 Python 命令行应用程序- 其中包含我们的 bash 脚本
requirements.txt,它包含了我们对 python 使用的依赖列表(查看 这篇文章 以获得更多信息)Dockerfile里面有我们的包装说明
前三个文件的内容并不重要,但是你可以在这里 查看 。
Dockerfile 图像的包装说明
档案在这里是最重要的。让我们一行一行地检查一下。
打包我们的代码只需要 3 个步骤:
- 第 1 行:我们安装 Debian,它在我们的映像中安装了 Python 3.9
- 第 3–6 行:我们将需求复制到映像中,并告诉 pip 进行安装
- 第 8–10 行:我们确保图像中有一个名为
app的文件夹,并将其设置为当前目录。然后,我们将笔记本电脑中的所有源代码复制到映像中。. .意味着从我们笔记本电脑的当前目录到我们在图像中设置的工作目录(即/app)
这些简单的步骤构建了我们的映像,安装了所有的依赖项,并复制了我们的源代码。
实际上将代码打包成图像
Dockerfile 仅包含包装说明和。我们仍然需要实际执行它们来建立一个图像。为此,我们需要使用一个终端。如果你对使用终端不熟悉,可以看看 这篇文章 中的一些简单说明。
打开一个终端和 cd 到包含 docker 文件的目录。然后执行以下命令:docker build . -t medium_cmd_app。
docker build .部分告诉 docker 在当前目录中检查您的 docker 文件。另一种方法是使用docker build -f path/to/Dockerfile。这样,您可以从另一个目录执行,并且您的 Dockefile 可以有另一个名称。-t medium_cmd_app告诉 docker 用medium_cmd_app标记图像。这只是给它一个名字,这样我们以后就可以调用它了。
3 运行映像
如果一切顺利,我们现在有一个建立的形象。是时候让它旋转起来并使用我们的程序了!我们可以简单地使用下面的两个命令。这些将运行映像并执行它包含的一个脚本。
docker run -it medium_cmd_app python3 py_cmd.py
docker run -it medium_cmd_app bash testbash.sh
- 告诉 docker 在交互模式下运行
medium_cmd_app是我们图像的名称,我们用这个名称(-t medium_cmd_app)标记它python3 py_cmd.py就跟 normale 一样:用 python 3 执行 py_cmd.py。轻松点。
如果一切顺利,当执行testbash.sh脚本时,你会看到*“来自 bash 文件*的问候”。执行 Python 程序时,您会看到一个命令行界面,如下图所示:

我们的 Python 命令行程序会开玩笑!每次键入“笑话”都会听到一个新笑话。
4 分发我们的图像
一旦我们的映像构建完成,我们就可以在任何安装了 Docker 的机器上运行它。但是我们如何在机器上得到图像呢?一个简单的方法是将你的图片上传到 Docker Hub。可以把这想象成 Docker 图片的 YouTube 任何人都可以在上面上传和下载任何图片。

Docker Hub 堆满了图像(图像由 Chuttersnap 放在 Unsplash 上)
推到码头中心
首先我们需要创建一个账户:去https://hub.docker.com注册。然后我们需要创建一个存储库;这是一个你的形象将去的地方。我把我的名字命名为medium _ cmd _ app。
下一步是打开一个终端,登录 Docker Hub,推送(上传)你的图片。以下是如何做到这一点:
- 打开终端
- CD 到您的项目目录
docker login→输入您的凭证- 再次构建图像,但是使用下面的标签:
docker build . -t [your_dockerhub_username]/[your_respo_name]
5.docker push [your_dockerhub_username]/[your_respo_name]
现在图像被上传到 Docker Hub。任何安装了 Docker 的人现在都可以执行docker run [your_dockerhub_username]/[your_repos_name]来下载并运行映像!
从码头中心拉出
我已经把我们之前的图像上传到 Docker Hub 了。您可以下载它并通过执行下面的代码来运行它:
docker run -it mikehuls/medium_cmd_app python3 py_cmd.py
docker run -it mikehuls/medium_cmd_app bash testbash.sh
这将在你的机器上寻找一个名为mikehuls/medium_cmd_app的图像,如果找不到:从 Docker Hub 下载它,如果它存在的话。

是时候开始分发这些图片了!(图片由凯皮尔格在 Unsplash 上拍摄)
结论
正如我们所看到的,在 Docker 镜像中分发代码保证了它可以在任何安装了 Docker 的地方运行。我希望我已经阐明了如何以这种容器化的方式打包、分发和运行您的代码。另外,看看这篇文章 中的是一个很好的实际例子。
如果你有建议/澄清,请评论,以便我可以改进这篇文章。同时,看看我的其他关于各种编程相关主题的文章,比如:
- Docker 适合绝对初学者
- Docker 为绝对初学者编写
- 使用 git 子模块在 docker 映像中安装私有的定制 python 包
编码快乐!
—迈克
页(page 的缩写)学生:比如我正在做的事情?跟我来!
用代码把你的照片变成艺术草图
原文:https://towardsdatascience.com/turn-your-photos-into-artistic-sketches-with-code-6694522fa349?source=collection_archive---------28-----------------------
计算机视觉编程实践项目——Python for Art

照片由雷·皮德拉从派克斯拍摄
在本文中,我将向您展示如何使用 python 代码将您的照片转换成手绘艺术作品。作为一名艺术和技术爱好者,我决定在一个简单的项目中结合这两个领域。这个项目将向你展示编程不仅仅是寻找编码问题的解决方案。编程也可以用来在行动中展示你的创造力,例如,通过创建铅笔素描外观的艺术品。
完成这个项目后,你将对如何在 python 项目中使用 OpenCV(计算机视觉库)有所了解。我希望你读完这篇文章后会喜欢并学到一些新的东西。
抓紧时间,让我们开始吧!
目录:
- 巨蟒
- 入门
- 步骤 1—定义图像
- 步骤 2—图像预处理
- 步骤 3 —混合作品
- 最后一步——导出结果

Anthony Shkraba 的照片|作者设计
计算机编程语言
Python 是一种通用编程语言,在分析数据方面越来越受欢迎。Python 还能让您快速工作,更有效地集成系统。世界各地的公司都在利用 Python 从他们的数据中收集知识。官方 Python 页面如果你想了解更多。
入门指南
在这个项目中,我们将使用两个 python 库。主要库是 OpenCV,这是一个著名的计算机视觉项目。我们需要的第二个库是 PIL,它是一个图像处理库。
开源计算机视觉
OpenCV 是一个开源的计算机视觉和机器学*软件库。OpenCV 旨在为计算机视觉应用提供一个公共基础设施,并加速机器感知在商业产品中的应用。作为一个 BSD 许可的产品,OpenCV 使得企业利用和修改代码变得很容易。
*参考:*https://opencv.org
安装库
我们可以使用 python 包/库管理器 pip 来安装库。安装完成后,我们可以将它们导入到项目文件中。
OpenCV 安装为“opencv-python”,PIL 安装为“pillow”
pip install opencv-python pillow
导入库
现在,我们可以打开代码编辑器了。我将在 Jupyter 笔记本上工作,但是可以随意使用不同的代码编辑器。我喜欢在这个项目中使用笔记本,因为这样会更容易回去更快地看到变化。
import cv2
from PIL import Image
太好了!现在,我们可以进入下一步,在这里我们将定义图像,我们想把铅笔素描作品。
第一步——定义 图像
在这一步,我们将开始调整我们想要使用的图像的大小。然后,我们将图像导入到我们的程序中。如果您对图像大小满意,可以跳过这个调整大小的过程。
图像

安东尼·什克拉巴摄于 Pexels
调整图像大小
首先,让我们检查图像的原始大小。
image = Image.open('portrait.jpg')
print(image.size)#Result
(4000, 6000)
现在,让我们调整它的大小。我建议在调整大小时保持高度/宽度比例不变。这样,我们就不会丢失照片的任何部分。
resized_image = image.resize((800, 1200))
resized_image.save('resized_image.jpg')print(resized_image.size)#Result
(800, 1200)

作者图片
读取图像
我们已经在前一行中保存了调整后的图像。现在我们将使用 imread 来读取它。确保文件名和文件格式正确。我已经将其定义为 img ,但是可以随意使用不同的变量名。
img = cv2.imread(‘resized_image.jpg’)
步骤 2 —图像预处理
完美!让我们玩玩我们的形象。为了能够得到铅笔素描的最终外观,我们的图像必须经过一些过程。你可以把它想象成一层不同的过滤器。我们将使用 OpenCV 预定义模型。
转换为灰度
这里的是 cvtColor 方法的官方文档。
grayed = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

灰色|作者图片
反转像素
这个过程有助于找到照片中的阴影区域。阴影在铅笔素描中起着重要的作用。这里的是官方文档,如果你想了解 bitwise_not 方法是如何工作的。
inverted = cv2.bitwise_not(grayed)

倒置|作者图片
添加模糊度
这里的是高斯布鲁方法的官方文档。高斯模糊使用高斯滤镜模糊图像。这将给最终的作品带来素描效果。
blurred = cv2.GaussianBlur(inverted, (19, 19), sigmaX=0, sigmaY=0)

模糊|作者图片
步骤 3-混合作品
表演时间到了!你准备好看最后的结果了吗?在这一步,我们将混合灰色和模糊的图像。为了完成这个操作,我们将编写一个函数来组合这些图像。
用 OpenCV 混合图像超级容易;我们将使用除以的方法。其基本上划分图像的像素值。你把它想象成一个矩阵除法过程。
def blend(x, y):
return cv2.divide(x, 255 - y, scale=256)
现在,让我们通过传入我们想要混合的图像来调用这个函数。
final_result = blend(grayed, blurred)
最后一步—导出结果
我们快完成了!
让我们导出结果。我们将使用 imwrite 方法将结果作为图像文件保存到我们的文件夹中。这样,我们可以有一个最终工作的记录。
cv2.imwrite("my_artwork.jpg", final_result)
太好了!现在,我来分享一下最终的结果。就我个人而言,我对此感到非常惊讶。也让我知道你的想法。
结果

最终结果|作者图片
结论
恭喜你。我们已经创建了一个用 Python 绘制的铅笔素描图片。正如我前面提到的,编程不仅仅是解决问题。我们也可以把它用于像这样有趣的艺术项目。这些类型的项目将帮助你找到新的想法来实施。谈到计算机视觉项目,OpenCV 是我的最爱之一。
我希望你喜欢读这篇文章,并且今天学到了一些新的东西。从事动手编程项目是提高编码技能的最佳方式。如果您在执行代码时有任何问题,请随时联系我。我会尽我所能来回报大家。
我们来连线。查看我的博客和 youtube 以获得灵感。谢谢你,
更多计算机视觉相关项目:
使用 Streamlit 和 Altair 将您的 Python 脚本转换为 Web 应用程序
原文:https://towardsdatascience.com/turn-your-python-script-into-a-web-app-using-streamlit-and-altair-627c70c56f4?source=collection_archive---------26-----------------------
2020 年东京奥运会奖牌表现分析
在本文中,我将给出一个快速教程,介绍如何使用Streamlit和Altair——这两个库提供了一个快速简单的框架来创建交互式仪表盘和数据发现工具。
我们将使用 2020 年东京奥运会https://olympics.com/tokyo-2020/olympic-games/en/results/all-sports/medal-standings.htm的数据来计算哪些国家获得了最多的奖牌,并比较男女运动员如何为他们的团队取得成功做出贡献。我在教程中使用的数据集可以在ka ggle上找到。
但是在我们开始之前,先介绍一下这两个库:
1。Streamlit是一个开源库,可以帮助你将 Python 代码转化为定制的 web 应用。易于使用和共享,它可以与大多数流行的数据科学和机器学*包一起工作。
细流变成了简单的。将脚本复制到现成的 web 应用程序中,您可以在本地使用,也可以部署到服务器上与其他人共享。Streamlit 甚至提供免费的网络应用托管服务(点击这里)。

来自https://streamlit.io/的 Streamlit 应用示例
2. 牛郎星 是 Python 的可视化库,基于 Vega 和 Vega-Lite 。它将简单和用户友好的图形语法与强大的功能相结合,可以创建几乎任何类型的复杂交互式图形。
从我个人的经验来看,与 pyplot 相比,这个库提供了更清晰的语法,并且更容易直接处理数据库中的数据,不需要额外的转换。这就是为什么我们将在本教程中使用它。

来自 https://altair-viz.github.io/[的 Alltair 可视化示例](https://altair-viz.github.io/)
第一步。研究数据和画草图
我在 Kaggle 上找到的数据有两种类型的数据集。第一个数据集包含按类型(金牌、银牌和铜牌)划分的每个国家队的奖牌总数,第二个数据集或多或少是相同的数据,但增加了一个维度——运动员的性别(这排除了一些无法提供此信息的学科,因此第二类数据集中的奖牌总数较低)。在原始源代码中,男女运动员被列在两个单独的文件中,但是对于我们的用例,我将两个合并成一个文件,该文件可用于 Github 上的所有其他代码。
我们有了数据,现在我们需要考虑仪表板看起来会是什么样子!这是我们开始释放内心艺术家、视觉设计师、UI 或 UX 专家,或者隐藏在这个坚韧的数据科学家表面下的任何人的部分。

正在绘制草图。作者图片
有两种不同类型的信息,所以最好为每一种信息分别绘制图表。拥有按国家分类的数据几乎迫切需要使用地图作为可视化形式,而按性别分类的数据是为用户创建探索性图表的好机会。
经过一些草图,这是我想看到的最终结果:
- 一个按国家显示奖牌总数的交互式地图,带有奖牌类型过滤器(金、银、铜)。我想根据每个国家的奖牌数量对地图进行颜色编码,并且有一个工具提示,提供鼠标悬停时的附加信息
- 一个散点图,以男女运动员获得的奖牌数为轴,每种奖牌类型使用不同的颜色。此外,让用户能够在图表上添加(或删除)更多的国家将会很有趣
让我们看看如何使用 Altair 创建这些图表。
第二步。使用 Altair 创建可视化
为了使事情变得简单,我们将从按性别统计开始,而把地图留到以后。在这里,我们将以男女运动员获得的奖牌数为轴,用不同的颜色表示每种奖牌类型。
让我们先阅读文件medal _ count _ by _ gender . CSV并查看数据集:

作者图片
每个国家队都有一栏,列有奖牌类型、国名以及获得奖牌的男女运动员人数。
在图表上尽可能多地保留这些信息是非常好的。因此,我们将创建一个散点图,X 轴和 Y 轴代表男女运动员。这个图上的颜色将代表不同类型的奖牌,我们将添加工具提示,以便用户可以看到这是哪个国家,以及其他有用的信息。
所以我们先画一个散点图,以 count_male 为 X 轴,count_female 为 Y 轴。功能 alt。Chart() 以数据集为自变量,创建一个基本的牛郎星图。您可以根据想要显示的图形类型选择不同的方法:mark_line()、mark_bar()等等。对于散点图,我们使用指定图表的类型。mark_circle() 。
方法*。encode()** 负责绘图看起来到底是什么样的:什么样的数据进入轴和颜色,如果你想将图形分割成单独的行或列也是如此。现在我们只使用 alt 来指定 X 和 Y。X() 和 alt。Y() 以列名作为参数(数据集中的列名需要是字符串):*
上面的代码生成了这个图形:

作者图片
数据集中的每个国家有 3 行(每种奖牌类型一行),现在不可能看到每个点代表的类型,所以让我们用颜色编码。为了用不同的颜色标记不同的奖牌,我们需要给添加参数“颜色”。encode() 指定显示什么颜色。该参数由 alt 定义。Color() 从数据集中提取一个列名(在本例中为“奖牌类型”),并相应地在图表上指定颜色。
如果图表使用直观上与奖牌相关的颜色,就会更容易阅读:橙色代表金色,灰色代表银色,棕色代表青铜色。为此,我们需要再添加一个参数 scale=alt。Scale() 具有指定的域(彩色元素及其顺序的可能选项)和范围(域中每个对应元素的颜色):

作者图片
现在好多了!唯一缺少的是:我们不知道每个位置上是哪个国家,所以让我们使用 tooltip 参数将它添加为用户的交互式工具提示:

作者图片
这看起来像一个很好的图表,但仍然缺少一件事:我希望有一条对角线将图表分为两部分(更多的男性和更多的女性奖牌)。为此,我们需要在代码中再添加一个 Altair 对象,并为这两个对象命名:散点图和新对象。新对象将是一条线,因此我们使用 mark_line() 方法进行显示,并在方法中指定颜色、样式(在本例中为虚线)和不透明度:

作者图片
这或多或少是最终的代码,唯一剩下的是添加过滤国家的能力,以显示和包装成一个函数的一切,所以我们可以很容易地调用它,当需要为某些国家绘制图表。让我们把所有东西放在函数**的奖牌 _ 性别()中。**该函数只有一个参数——国家——用于过滤 medal_count_by_gender 数据帧。loc[]。此外,由于我们在图上有更少的点,我将使用将它们的大小从 60 增加到 300。mark_circle(size=300)* ,这样看起来更好看:*
举例来说,这就是美国队的结果。我们看到,在所有三种类型的奖牌中,女运动员都领先于男运动员:

作者图片
我们可以将更多的国家添加到函数输入中,以获得多个国家队的结果。例如,我们可以如下添加中国和日本:

作者图片
*现在,当散点图可以使用时,让我们开始绘制地图吧!我们有一个名为 *olympic_medal_count.csv,的数据集,其中包含列表中每个国家的代码。但是为了在牛郎星地图上使用它,我们还需要为每个国家准备一个ISO 3166-1 数字代码。我们在另一个文件( country_codes.csv )中有这个数据,所以第一步是合并两个数据集:
结果看起来如下:

作者图片
从这里,我们可以继续使用 Altair 创建地图。和以前一样,我们使用 alt。Chart() 来创建图形,但现在用*。mark_geoshape()** 方法和使用 Altair 的方法alt . topo _ feature(data . world _ 110m . URL*、【国家】)从 Vega _ datasetsdata . world _ 110m . URL创建的新数据源。通过这样做,我们添加了一个带有国家的地图,但是它还没有附加任何值。
在 alt 之后。图表()有一个。编码()方法带有颜色和工具提示的参数。颜色和工具提示都使用来自 olympic_medal_map 数据集的数据,我们仍然需要加入这些数据。为了做到这一点,在。encode()还有一个方法——。transform_lookup() — 在 olympic_medal_map 中搜索正确的国家 id,并将“Team/NOC”和“Total”列中的值添加到地图背景中。
之后,我们可以添加更多的方法来控制图形的外观:。configure_view() 为图形框架(我们将其设置为零),。图片尺寸的属性()和。project() 定义地图应该是什么样子。
下面是它在脚本中的样子:
上面的代码将生成这张漂亮的图片,当鼠标悬停在一个国家上方时会出现工具提示:

作者图片
作为一个额外的功能,我希望地图根据奖牌类型(金牌、银牌或铜牌)而改变,所以我们创建了一个名为 draw_map() 的函数,将奖牌类型作为参数。该参数将定义应该显示的列以及颜色主题,因此对于金牌,地图将具有橙色等级,而对于银牌,地图将具有蓝色等级。
这就是它在函数中的样子:
现在两个图表都准备好了,是时候把东西包装成一个漂亮的 Streamlit 应用程序了。
第三步。使用 Streamlit 将 Altair graphs 转化为 web 应用程序
我们已经有了在 Altair 中显示所有图表的代码,现在只需要将所有内容打包到 streamlit 命令中,以便将其转换为 web 应用程序!
我们想在我们的 streamlit 应用程序中添加两个视图:按国家分类的奖牌总数(地图)和按性别分类的统计数据(散点图)。
为此,我们需要创建一个 Python 脚本。py,并添加函数 draw_map() 和 medals_by_gender() 以及读取数据集的代码。完成后,我们可以使用 st.write() 方法添加几行代码,在 Streamlit 应用程序页面上显示 Alrair 图形:
现在,我们将脚本保存在名为 olympic_medal_tokyo2020.py 的文件中,并在终端中运行以下命令:
streamlit run Olympic _ medal _ Tokyo 2020 . py
Streamlit 负责一切,我们在 localhost 上获得了这个交互式仪表板:

作者图片
这已经是一个仪表板,但它不允许我们选择国家或挑选不同类型的奖牌。为此,我们需要添加交互式小部件。
函数 draw_map() 将奖牌类型作为参数,一次只能使用一个,因此使用 st.selectbox()从四个不同类型(总、金、银或铜)中进行选择是有意义的:
现在,用户将能够从选项中进行选择,显示的地图将根据选择而变化:

作者图片
对于性别统计,我们希望允许用户选择显示哪些国家队。这是一个多项选择,所以我们可以使用 st.multiselect() 。我们还可以为选择器设置一个默认值,这样默认情况下将显示三个国家:日本,因为它是奥运会的主办国,ROC(又名俄罗斯),因为它是我可爱的祖国,还有瑞典,因为我正舒舒服服地坐在斯德哥尔摩的公寓里写这段代码。:)

作者图片
现在我们在同一个屏幕上显示了所有的东西,但是给用户一个选择地图或者散点图的选项会更好。因此,让我们使用 st.sidebar.radio() 在侧边菜单中添加一个开关,并根据选择显示一个或另一个图形。此外,我们将在每个带有 st.table(): 的图表下以数据表的形式显示所有国家的值
结果,我们将得到一个漂亮的图表,左侧边栏中有一个选择,主页上有过滤器:

作者图片
快好了!
最后一件事是使用奥运标志的 st.write()、st.title() 和 st.image() 在页面上添加一些测试说明:
这就是最终结果的样子:
作者图片
这是完整的代码:
第四步。共享简化仪表板
现在,一旦你有了自己的应用程序,你可能想让其他人也能使用它,也就是把它部署在某个地方。有几个我知道的选项(但是如果你知道其他的,请留下评论:):
- Streamlit 允许用户在 Streamlit *台上托管他们的应用,就像添加你的 github 库 URL 一样简单。例如,这里的是我们在本文中创建的仪表板的链接
- RStudio Connect 还为用户提供了上传和分享代码的机会,即使代码是用 Python 编写的
- 当然,你可以使用你自己的服务器!
有用的链接
- 牛郎星文档
- 简化文档和备忘单
- Tokyo2020 仪表板代码的 Github repo
- Tokyo2020 dahboard
数据发现快乐!
使用 Python 将语音备忘录转换成书面笔记
原文:https://towardsdatascience.com/turn-your-voice-memos-into-written-notes-using-python-c78a97847160?source=collection_archive---------22-----------------------
动手机器学*项目

沃洛季米尔·赫里先科在 Unsplash 上的照片
在本文中,我们将学*如何将音频笔记转换为文本文档。有时我们在随机的地方得到这些绝妙的想法,但却懒得写下来。猜猜这些想法会发生什么?我们忘记了他们。这是我亲身经历的体会。
通常当我走路或骑自行车的时候,我会有奇妙的项目想法。但是在那个特定的时刻把它们写下来是一种挑战。那么,我该怎么办?
我打开语音备忘录应用程序,然后点击录音。又快又简单。
然后,当我回到家,我听那些录音,并把它们写下来。我很享受这个过程,但有时我会懒得听我的录音和做笔记。难道没有比每次都倾听更简单的方法吗?在机器学*和人工智能的时代,当然有。
然后,让我们建立我们的语音到文本的程序,使这个过程更好。我们将在本实践教程中学*如何操作。
我们开始吧!
目录:
- 入门——汇编 AI
- 第一步——库
- 步骤 2 —录音
- 步骤 3 —语音转文本转录
- 最后一步——导出结果
入门— AssemblyAI
有许多语音到文本,或者说语音识别云服务和 API 可用。以下是一些著名的例子:
- 谷歌云语音转文本
- 自动气象站转录
- 汇编语音到文本
- 卡尔迪
- Meta 字母
在今天的教程中,我们将使用 AssemblyAI 的语音转文本 API。它是一个训练有素的人工智能 API。免费使用。创建帐户后,您将获得一个唯一的 API 密钥。我们将使用该 API 密钥来使用服务和功能。
而作为编码环境,我准备用 Jupyter Notebook。如果你对数据科学和机器学*项目感兴趣,我肯定你用过它。
步骤 1 —库
创建新笔记本后,我们准备导入我们的库。Python 有优秀的库;有些是语言本身内置的,有些是第三方库。
库是完成特定任务的好方法,而不需要重新发明轮子。有一些优秀的程序员创建了库并使它们开源。是不是很酷?这也是我喜欢编程的原因之一。
无论如何,回到我们的项目。我们将需要的库是内置库。我们不需要安装任何东西。下面是将它们导入我们程序的代码块。
import sys
import time
import requests
步骤 2 —录音
在这一步中,我们将把一段录音导入到程序中。这个录音可以是任何东西;一个简短的语音备忘录或一个长的演讲录音。对于这个项目,我将使用我阅读这篇文章介绍的简短录音。
由于我们使用 API 服务进行语音识别,录音必须上传到云存储。这个云存储可以是 AWS,Google Cloud,也可以是 AssemblyAI 的存储。我会用他们的云存储,把东西放在一个*台上。
我会将录音移动到我的 Jupyter 笔记本所在的文件夹中。然后在程序中定义它。
filename = "voice_memo_1.m4a"
现在,让我们写一个函数来读取这个录音文件。顺便说一下,文件格式应该是音频格式,以便我们的阅读功能正常工作。苹果的语音备忘录应用程序以 m4a 格式保存录音。您可以在以下文章中了解不同的视频和音频格式:
def read_audio_file(filename, chunk_size=5242880):
with open(filename, 'rb') as _file:
while True:
data = _file.read(chunk_size)
if not data:
break
yield data
是时候把我们的录音上传到 AssemblyAI 的云存储了。
headers = {
"authorization": "Your API Key"
}response = requests.post('[https://api.assemblyai.com/v2/upload'](https://api.assemblyai.com/v2/upload'), headers=headers, data=read_audio_file(filename))print(response.json())
太好了!运行完这段代码后。我们将从 API 获得响应。响应消息将包括上传文件的 url 链接。

图片由作者提供。
步骤 3 —语音转文本转录
表演时间到了!让我告诉你使用云 API 的很大一部分;一切都发生在云中。您的笔记本电脑或 PC 不需要花费任何电力来进行识别。
您所需要的只是一个 API 令牌,它将建立一个从您的设备到云的连接。你可能知道,甚至游戏行业也在向云*台发展。我觉得这太酷了!
这里的是官方文档,如果你想了解更多。
好了,我们开始语音转文字转录吧?我们需要定义三个变量:一个字符串和两个字典。
speech_to_text_api = "[https://api.assemblyai.com/v2/transcript](https://api.assemblyai.com/v2/transcript)"json = {
"audio_url": "The upload url link from the previous step"
}headers = {
"authorization": "Your API Key",
"content-type": "application/json"
}response = requests.post(speech_to_text_api, json=json, headers=headers)print(response.json())
运行这个代码块后,我们的请求将进入云中,等待处理。这是我得到的回应:

图片由作者提供。
id 键是请求的 id。这就是我们将如何跟踪它。它基本上就像一个订单跟踪号码。然后,状态键显示请求的状态。如您所*,它显示它正在“排队”
最后一步—导出结果
快到了!在这最后一步中,我们将检查我们之前提出的语音到文本请求的状态。我们将检索返回的结果,并将其导出到文本文档中。
让我们跟进我们的请求。
request_url = "[https://api.assemblyai.com/v2/transcript/](https://api.assemblyai.com/v2/transcript/56fy5wgem-ea41-4a38-8d96-fa4697970483) request id goes here"headers = {
"authorization": "Your API Key",
}response = requests.get(request_url, headers=headers)
我们将拥有一个包含许多键和值的长字典。其中一个键会有可识别的语音。它被称为“文本”键。让我们看看我们得到了什么。
下面是从字典中访问特定键值的代码:
recognized_speech = response.json()['text']

作者截图。
现在,让我们使用一些基本的 python 编程来导出识别的语音。
with open('result_1', mode ='w') as file:
file.write(recognized_speech)
print("ready!")
让我们看看我们保存的文本文档。

图片由作者提供。
恭喜你。在这个实践教程中,我们学*了如何使用编程将我们的录音转换成文本文档。我喜欢创建这种项目,因为它们是我们日常生活中机器学*和人工智能的真实例子。希望你喜欢读它,并在今天学到一些新的东西。如果您有任何问题,请随时联系我。
我是贝希克·居文,我喜欢分享关于编程、教育和生活的故事。订阅我的内容,保持灵感。泰,
如果你想知道我写的是什么样的文章,这里有一些:
- 使用 Python 构建人脸识别器
- 分步指南—用 Python 构建预测模型
- 使用 Python 构建语音情感识别器
将各种问题转化为一个样本的二项式检验
原文:https://towardsdatascience.com/turning-a-two-sample-event-rate-test-into-a-one-sample-binomial-test-23fbfb9d1df6?source=collection_archive---------20-----------------------
即使没有硬币,也有掷硬币的活动。

图片由 Upsplash 上的克拉拉-科瓦奇斯-苏斯特恩拍摄
本文的目的是通过一个简单的例子来激发简单的单样本二项式检验,然后通过将它应用于其他不同的场景来展示它的通用性。
0)基础知识
- **假设检验:**一种收集数据并进行“矛盾统计证明”的方法,我们首先做出一些假设(称为“零假设”),然后试图证明我们收集的数据并不支持它。在“完成证明”和“拒绝无效”方面,我们可能成功,也可能失败。
- **一个样本对两个样本:**最好通过一个例子来描述。假设我们的无效假设是南极企鹅的*均身高超过 21 英寸。我们需要捕捉一群它们,测量它们的高度,然后放生。我们从收集的样本中估算了*均身高。这是一个单一样本测试。现在,假设我们的零假设是,雄性企鹅的*均高度并不比雌性企鹅的*均高度大。我们现在需要收集两个样本;一些雄性企鹅测量他们的身高,一些雌性企鹅也测量他们的身高。因此,这是一个双样本测试。因此,如果你从一组中收集数据并与一个静态值进行比较,这是一个单样本测试,如果你将两组数据进行比较,这是一个双样本测试。
1)一个样本二项式检验
1.1)游戏
考虑一个激励单样本二项式测试的游戏。
你被邀请参观赌场,玩不同的老丨虎丨机。吃角子老丨虎丨机的旋转成本为 1 美元,如果你中了头奖,则返回 2 美元(因此,如果你中了头奖,则赚 1 美元,如果你没有中,则输 1 美元;当然,这些机器的累积奖金将比传统吃角子老丨虎丨机更有可能成为值得考虑的游戏)。
前一天晚上,你可以进去做几个小时的吃角子老丨虎丨机“测试旋转”,不涉及现金(赢或输),但你可以看到结果。因为你和它们在一起的时间有限,所以你会随意的旋转它们并记下结果。特别是,你要记下你旋转任何一台机器的次数以及它产生累积奖金的次数。这是您收集的数据的样子:

表 1:我们能够在赌场测试旋转的一些机器的数据。每台机器旋转的次数、您获得的累积奖金数和估计的成功率(#累积奖金/#旋转数)。
回到蝙蝠洞,你需要决定第二天要尝试哪台老丨虎丨机并加倍下注。如果有一个它们的优先列表也不错,这样如果你最喜欢的一个不可用,你可以去玩下一个最好的,以此类推。
如果你必须为一台吃角子老丨虎丨机做出二元决策(玩或不玩),很明显,如果正面概率(真实的正面概率,而不是根据少量投掷估计的正面概率)超过 50%,你应该玩这个游戏。这将确保你在预期的意义上赚钱,因此长期来看几乎是肯定的。赢得累积奖金的机会越高,你就能赚到越多的钱。
然后,第一个冲动可能是简单地从上表中选择具有最高估计累积奖金机会的机器。但是仔细观察就会发现这个策略的问题。我们最终选择的机器是#3,它有最高的累积奖金概率, 100% 。但是,我们只转了一次,就中了头奖。很可能这台机器中头奖的实际机会远低于 100% ,我们只是碰巧在一次旋转中中了头奖(一次侥幸)。很明显,我们应该选择一台经过多次投掷证明其可靠性的机器。事实上,挑选具有最高估计头奖率的机器的策略将很可能选择具有少量旋转但由于随机机会而具有高估计率的类似实例。例如,如果有 10 台机器,每台都有 40% 的累积奖金机会,并且我们正好旋转所有这些机器一次,那么很有可能在我们旋转它的时候,其中至少有一台会给我们累积奖金,从而将它的估计比率提升到 100% 高于所有其他机器。
减轻样本大小影响的一个显而易*的方法是要求机器具有较高的估计头奖比率和,该比率是在超过一些最小投掷次数的情况下计算的(例如:仅考虑我们旋转 10 或更多次的机器)。但是,没有什么好办法想出这个门槛。这也只是稍微缓解了问题,并没有完全解决问题(例如:一台带有 100 投掷19】的机器应该比一台带有 11 投掷的机器更有优势)。这就是假设检验的用武之地,它为我们提供了一个数字(p 值),这个数字无缝地将估计的头奖率以及它所基于的样本量考虑在内。
关于一个非常相似的激励例子,请看 3B1B 视频[ 2 ],他在视频中提出了一个与亚马逊评论类似的难题。他视频中的例子是:

表-2:来自 3B1B 视频关于二项分布和亚马逊评论的数据。
我有点惊讶他没有提到假设检验,因为纳入样本大小带来的不确定性正是它的目的。
1.2)工作原理
假设检验是一种统计“矛盾证明”的形式,所以让我们首先假设任何给定的老丨虎丨机有 50%或更少的机会给你头奖。这是默认的假设;“零假设”,机器有责任说服我们去玩它(通过我们从它那里收集的数据)。
对于任何给定的机器,假设我们设法让它旋转 n 次,并获得 j 累积奖金。上表-1 中第一台机器的 n 和 j 值为 5 和 3 。基于这个数据的头奖概率是 3/5 = 60% 。看起来很有希望。第二台机器具有来自 50 旋转的 29 累积奖金。这里头奖的概率是 29/50 = 58% 。这个比第一个小。但是你会选择第一个吗?第二台机器在成功的机会方面稍差,但有更多的数据支持这些机会。为了量化第二台机器更好的原因,尽管成功的机会较低,我们考虑这两台机器能够“有多好地”反驳零假设(头奖的机会低于 50% ,因此它们不值得一掷)。事实上,让我们尽可能提高门槛,说即使累积奖金率为 50% ,我们也不会碰一台机器。这简化了我们的零假设,也设立了一个高门槛(对于一台机器来说,让我们相信它的头奖概率超过 40%比让我们相信它超过 50%更容易)。
对于任何一台机器,我们都有两个数字, n 和 j. 无效假设是,它在每一次旋转中都有一个 50% 的累积奖金变化。首先,我们忽略 j (这个数字通常被称为检验统计量)并考虑在零假设下我们会期望观察到什么。然后,我们观察我们观察到的实际情况,并考虑观察到比它“更极端”的情况的可能性。我们感兴趣的是机器让我们相信它们的头奖概率大于 50%;这就是“极端”对我们的意义。如果我们掷一枚硬币,正面概率为50%nn次,我们得到的正面数量(本例中的测试统计)是一个参数为 n 和5的二项分布。我们以第一台机器为例,这里 n=5 。零假设下 j 分布的概率质量函数如下:

图 1:n = 5,p=0.5 的二项式分布的概率质量函数。使用https://github.com/ryu577/pyray为本文创建
现在,让我们在这个质量函数上叠加我们观察到的实际的 j :

图 2:根据零假设和我们实际观察到的 j 的概率质量函数。为本文创建使用:【https://github.com/ryu577/pyray】T4
假设检验的最终产品是 p 值,p 值被定义为看到“与实际观察一样或更极端”的事物的概率。这自然对应于下面绿色显示的区域:

图 3:假设检验的 p 值将是观察到 j 的概率,实际的检验统计量以及可能更极端的值。为本文创建,使用:https://github.com/ryu577/pyray
为什么我们将 p 值定义为观察到“与观察到的测试统计一样或更极端”的概率,而不仅仅是“与测试统计一样极端”。在这种情况下,这里的 p 值将只是在 j=3 处的概率质量函数,而不是跨越 j=3,4,5 的总和。首先,如果 p 值是我们在观察检验统计时感到惊讶的量度(从零的角度来看),则更高的值( 4 和 5 )将更加令人惊讶,因此值得包括在 p 值中。第二,如果测试统计恰好是一个连续的随机变量而不是离散的(就像上面的二项式一样),仅仅说“与观察值一样极端”甚至不是一个选项。在这种情况下,观察到任何一点的概率都变为零,所以如果我们将其定义为“极端情况”,p 值将始终为 0 。将它定义为“等于或大于极限”可以确保我们仍然得到一个有用的数字。
1.3)实施
从上面的图 3 中我们可以看到,单边二项式检验的 p 值只是一些二项式概率的总和。这使得它非常容易在几乎任何地方实现(甚至像 Excel 或 Numbers 这样的电子表格软件)。从 Python 开始,它在库 scipy 中实现。对于上述情况,其中零假设是头奖率为 50% ,并且我们在 5 次投掷中观察到 3 个头奖,p 值可以计算为:
使用 scipy 计算二项式检验的 p 值。
这正好给了我们 50% 。这还没有低到让大多数人的风险偏好来玩这个机器(你通常希望 p 值至少低于 20% ,要求它低于 5% 是一个标准)。
对于我们在这里考虑的单边测试,计算非常简单。它只是 PMF, j 和更高的概率的总和。这个总和被称为分布的生存函数,只有一个警告:生存函数不包括 j 本身,从 j+1 开始。考虑到这一点,我们简单地计算在 j-1 而不是在 j 的生存函数,这使得结果与假设检验的 p 值完全一致。
对于单侧检验(具有更大的可选性),p 值可以从生存函数中获得。
由于单边测试非常简单,它甚至可以与电子表格软件(如 Excel 文件)中的原生公式一起使用。如果在某些单元格中存储 n 和 j ,则 p 值会变成(最后一个参数告诉 Excel 计算生存函数而不是概率质量函数):
BINOMDIST(j-1,n,. 5,真)
1.4)如何使用
p 值的传统用法是通过对其应用阈值(称为显著性阈值)来进行二元决策(如果 p 值低于该显著性阈值,则我们拒绝空值)。在我们的例子中,它将决定是否玩任何给定的吃角子老丨虎丨机。
这个阈值通常设置为 5% (只有 1/20 的机会机器不满足我们的标准),但是你可以选择任何你喜欢的。你的重要性阈值越大,你拒绝零的次数就越多(在这种情况下是玩吃角子老丨虎丨机),使你成为一个更积极的赌徒,不那么厌恶风险。相反,降低显著性阈值会让你更加厌恶风险,也不太可能去碰运气。
首先,我们取所有 p 值满足我们的显著性阈值(比如说 20% )的机器。这些才是值得玩的。我们根据它们的 p 值对它们进行排序,这是我们正在寻找的优先级列表(我们想要玩的机器)。
1.5)结果
现在,我们可以为不同的老丨虎丨机在表 1 中添加一个 p 值列。p 值最低的是第六台机器,它非常接近机器-2,因此应该优先考虑。

表 3:来自我们激励例子的表(表 1),但是增加了 P 值(最后一列)。
而对于我们从 3B1B 视频中得到的亚马逊评论例子(在 50% 正评论几率*的零假设下;*注意,p 值采用科学记数法):

表 4:亚马逊 3B1B 视频中的各种书籍,用科学记数法中的二项式检验得出 P 值。
结果似乎是第三家出版商胜过前两家,因为他们的结果是基于更大的样本量。
1.6)最强大
好的,所以使用 p 值对于无缝地考虑样本大小和估计头奖率是很好的。但是这是计算 p 值的唯一方法吗?我们能不能用其他方法估算一下?为了恰当地考虑这个问题,我们必须考虑一种量化测试性能的方法。最合理的方法是权衡测试的假阳性和假阴性率。这在[ 4 ]中有深入的介绍和可视化。由于测试的统计功效被定义为(1-假阴性率),如果一个测试对于任何假阳性率具有更好的假阴性率,则该测试被认为比另一个测试“更有效”。
我们可以用两种不同的方法计算 p 值:
- 使用相同的检验统计量,但是找到它在其他分布上的 p 值。在这里,这将意味着仍然对 j (累积奖金数)的分布进行推理,但是使用二项式分布以外的东西来计算 p 值。令人惊讶的是,这根本不会影响测试的性能(统计功效)。
- 我们可以使用完全不同的测试统计数据(而不是累积奖金的数量, j )。例如,我们可以使用 *j、*或头奖率( j/n )。这对测试的统计功效(性能)有直接影响。
事实证明,对于某些无效假设,我们可以通过 Neyman-Pearson 引理[ 5 ]从理论上保证假设检验具有任何检验的“最佳可能”性能。上面描述的二项式检验确实保证是推理二项式分布的“最佳可能”。在接下来的部分中,我们将描述一些其他的场景,在这些场景中,不仅单样本二项式检验是适用的,而且它是“最佳可能”检验的理论保证也同样适用。
2)两样本二项式检验
现在考虑一下,你不是在和庄家玩,而是和一个特定的对手玩。对手先选择一台可用的机器,然后你可以选择任何剩余的机器。然后,你们双方尽可能多的旋转几次,累积奖金多的一方获胜。
你也知道这个对手有一个他一直喜欢的机器(他的“明星机器”)。
你想看看是否有其他机器和这个明星机器一样好或者更好。现在,我们要将赌场中的所有其他机器与这台“明星”机器进行比较。回头看表-1,假设第二台机器是明星机器。虽然我们之前将标准设定为静态的 50% ,但现在无论这台明星机器的头奖率是多少,它本身都是根据有限的数据样本估算的。因此,我们有为我们正在考虑的任何机器收集的数据样本,也有我们将与之进行比较的这台明星机器的样本;总共制作两个样品和两个样品测试。现在无效的假设是,我们正在考虑的任何机器的累积奖金率小于或等于明星机器的累积奖金率(而不是 50%)。任何给定的机器都有责任向我们展示它的数据不符合零假设,并且它可能比明星机器有更高的头奖率。像以前一样,我们设置了可能的最高标准,并假设默认情况下,所考虑的任何机器都与起始机器具有相同的速率。
从表面上看,这比我们的单一样本测试更复杂。但是忘记两个样本的复杂性;用这个简单的技巧将其转换回一个样本测试。
考虑我们想要评估的候选机器的数据( n_1 和 j_1) 和明星机器的数据( n 和 j )。
就像单样本测试一样,测试统计是从候选机器中观察到的累积奖金的数量( j_1 )。
现在,候选机器和明星机器上的总累积奖金的条件: k=(j+j_1) 。仅给定我们在两台机器上获得的 k 个头奖的信息和零假设的假设(两台机器具有相同的头奖率),我们观察到的每个头奖都有机会: p=n_1/(n_1+n) 属于候选机器。因此,J1的分布是一个参数为 p 和 k 的二项分布。现在,我们可以通过找到这个二项分布在J1的观测值处的生存函数来获得 p 值,就像我们对单样本测试所做的那样。
3)连续时间速率测试
为了证明二项式检验的广泛适用性,让我们抛开赌场,考虑一段高速公路(也许在摄像机的观察下)。这里时不时会发生事故。描述这些事故的随机过程是一个时间点过程,与二项式分布非常不同。

一段行驶着汽车的高速公路。照片由石页·康让在 Unsplash
我们想看看雨天的事故发生率是否比非雨天高(如果是这样,可以进行投资来尝试和减轻这种情况)。首先,雨天的车可能会少一些,所以我们必须考虑到这一点。一种方法是根据每单位汽车小时的事故数量来考虑事故率。如果摄像机观察到一分钟内有一辆车飞驰而过,那就是一分钟一辆车。如果两辆车在另一分钟的时间内同时快速通过该路段,那就要在记录上再加 2 分钟的时间(这种计算时间可以用计算机视觉自动完成)。然后,我们可以计算在一天或适当的时间内累计的汽车总分钟数。然后,我们统计同一时期的事故数量(也可以用计算机视觉自动完成)。最后,用事故数除以总汽车小时数,得到每汽车小时的事故发生率。雨天开车时间可能会少一些,但是当我们谈论这个比率时,这个因素是受控制的。
为了回答我们最初的问题,我们可以标记所有有雨和无雨的区间。然后得到所有下雨时段的总事故数和车时数(n1和t1)以及所有非下雨时段的相同统计(N2和T2)。现在,雨天每小时的交通事故是否比非雨天多?雨天的比率为ƛ_1 = n1/t1,非雨天的比率为ƛ_2 = N2/T2。就看ƛ_1>ƛ_2对不对?我们必须记住 ƛ_1 和 ƛ_2 只是从有限的数据样本中估算出的事故率;不是真实的事故率。这意味着在他们的估计中会有一些噪声。因此,即使雨天和非雨天的真实事故率相同,也有 50%的几率观察到ƛ_1 ƛ_2.
3.1)转换为单样本二项式检验
我们可以考虑零假设,即雨天每小时的事故发生率与非雨天相同。然后,我们可以看到我们收集的数据与此有多么强烈的矛盾(通过我们的 p 值)。我们又经历了一次熟悉的过程:
- 定义雨天的事件数, n_1 作为检验统计量。试着在零假设下得到它的分布。
- 所*事件总数的条件: n=n_1+n_2 。如果雨天和非雨天每小时的事故率相同,那么任何观察到的事故都有概率*p = t1/(t1+T2)*归因于雨天。因此, n_1 的分布将是带有参数 n 和 p 的二项式分布。
- 像之前一样,我们现在观察我们的实际 n_1 ,计算 p 值作为上面二项分布的生存函数。然后,我们可以查看 p 值是否小于 5%,并得出结论,雨天的事故率不符合零假设(意味着它比非雨天高)。
通过这种方式,双抽样率测试也被映射为单抽样二项式测试。当两点过程是泊松过程时,得到的检验是“最有效”的理论保证成立。但即使不是这样,它也表现得很好。参*[ 1 ]。
如果你喜欢这个故事,成为推荐会员:)
https://medium.com/@rohitpandey576/membership
参考
[1]失败率的打破假设检验:https://arxiv.org/abs/2001.04045
[2]二项式分布|概率的概率,第 1 部分(3B1B):https://www.youtube.com/watch?v=8idr1WZ1A7Q
[3]假设检验:分布并不重要:https://towards data science . com/Hypothesis-testing-the-distribution-that-matter-79882 ba 62 f 54
[4]假设检验可视化:https://towards data science . com/Hypothesis-testing-visualized-6f 30 b 18 fc 78 f
[5]尼曼-皮尔逊引理(维基百科文章):https://en.wikipedia.org/wiki/Neyman%E2%80%93Pearson_lemma
用 Flask 把机器学*模型变成产品
原文:https://towardsdatascience.com/turning-machine-learning-models-into-products-with-flask-f8c2ccc210b3?source=collection_archive---------22-----------------------
使用 REST APIs 为您的模型构建应用程序

照片由卡莱斯·拉巴达在 Unsplash 上拍摄
介绍
1971 年,年仅 21 岁的史蒂夫·沃兹尼亚克已经是一名出色的计算机程序员和电子工程师。他真的很喜欢花时间创造奇怪的装置,并在他的领域寻找改进。1971 年,他遇到了一个 15 岁的男孩,这个男孩很快意识到了沃兹尼亚克所做工作的巨大潜力。这个人认为沃兹尼亚克发明的奇怪装置会对很多人有用。他们在接下来的几年里一起工作,6 年后,他们开始将当时最早也是最成功的个人电脑之一:Apple II 商业化。
说服沃兹尼亚克将他的设备转化为产品的人是史蒂夫·乔布斯。这很奇怪,因为每个人都知道史蒂夫·乔布斯是谁,但没有多少人听说过沃兹尼亚克。
这篇文章不是关于苹果背后的故事,而是关于将技术转化为产品。
当你花大量时间在笔记本和竞赛上时,机器学*的画面似乎非常简单:你创建抛出一个度量的模型。这个指标说明了你的模型有多好,所以你必须改进这个指标。有时候你有一个门槛。最终你达到了这个门槛。一旦你实现了,就意味着这个模型足够好,那么工作就完成了!
事实证明,在真实环境中,这一过程只是冰山一角。我们必须记住,归根结底,我们要做的是创造对人民有用的产品。
在这篇文章中,我将为机器学*模型开发一个 web 应用程序。我将使用 Flask,这是一个微框架,您可以用 Python 代码以简单的方式构建 REST API。
我们将使用成人人口普查收入数据集。我们将试图预测一个人的年收入是否超过 50k,因此我们有一个二元分类问题。作为解释变量,我们将使用年龄、性别、婚姻状况和每周工作时间等个人特征。
我们将使用 HTML 来构建 web 应用程序。我知道很多读到这里的人并不熟悉,所以如果你是其中之一,不要担心!我也不是专家,所以这里的代码没什么大不了的。同样值得一提的是,在这篇文章中,我将专注于开发 REST API,因此 web 开发将处于次要位置。
这篇文章的结构如下:首先,我们将以一种简单的方式定义在构建 REST API 之前我们必须知道的概念。然后,我会一步一步地解释代码。你可以在这个库中找到这个项目使用的所有代码。
话虽如此,还是说重点吧!
REST API 背后的关键概念
为了把事情弄清楚,我认为首先我们必须回答一些关于 REST API 的典型问题,以便理解 REST API 到底是什么。这些是简短的问题和答案,即使您不熟悉 REST API 的概念,也应该不难理解,所以让我们开始吧!
- 什么是 API?
你可以把 API(应用编程接口)想象成连接程序的软件,允许它们通信(发送数据)。
- 什么是休息?
REST 可以定义为创建 API 时遵循的一组特定规则。它代表表述性状态转移,是一种无状态架构,通常运行在 HTTP 上。
- REST 和 RESTful 有什么区别?
REST 指的是架构,RESTful 指的是实现 REST 架构的 web 服务。
- RESTful API 如何工作?
RESTful API 本质上做的是发送请求以获得资源。
- 请求到底是什么?
当你在 HTTP 中发出请求时,你是在向服务器请求某些东西。对于请求,你使用 HTTP 方法。最重要的方法如下:
GET取数据。
PUT更改(上传)数据。
POST创造数据。
DELETE删除数据。
举个例子,当你去http://www.google.com的时候,你发送如下:
GET / HTTP/1.1
Host: [www.google.com](http://www.google.com)
这是一个 GET 请求,其中:
GET是动词/是路径HTTP/1.1是协议
- 资源到底是什么?
资源本质上是数据。例如,如果您要求您的模型预测,预测,可以是某种数据,如 JSON 文件,将是资源。
我认为记住这个关键概念后,我们现在就可以用 Flask 构建一个 REST API 了,所以让我们开始工作吧!
用 Flask 实现 REST API
在进行编码之前,我认为有必要先设定计划:
本质上,我们希望创建一个应用程序,它将个人的不同特征作为输入,输出给定这些特征时个人年收入超过 50k 的概率。
因此,在主页中,我们需要指定输入:

作者图片
一旦我们提交了它们,应用程序会将我们发送到一个页面,在那里我们可以看到输出:

作者图片
存储库中的主要文件是 Python 脚本。在model.py我们将构建我们的模型,而在server.py我们将构建 REST API。
我在下面解释这两个脚本。
构建模型
第一步是创建一个进行预测的模型。为此,我们首先处理数据:
一旦我们有了处理过的数据,我们就可以拟合一个模型。我选择了逻辑回归(它工作得很好)。
📒注:如果你想针对这个问题开发更复杂的模型,可以看看这个 Kaggle 笔记本。
一旦我们有了合适的模型,我们必须创建一个函数来执行以下操作:
它将每个解释变量的单个值作为输入,即个体的特征。
它输出在给定个人特征(输入)的情况下,个人收入超过 50k 的概率。
您可能已经注意到,我们的 web 应用程序具有相同的输入和相同的输出,因此这个功能是这个项目的关键。
构建 REST API
在脚本server.py中,我们将开发 REST API。
我们首先导入一些库并创建Flask类和Api类的实例。
然后我们将创建两个类。它们都继承了Resource类,并且都由一个名为get的函数组成。如果你还记得,在开始的时候我们说过 RESTful API 基本上是使用请求来获取资源的。正如您可能猜到的,名为get的函数是使用 GET 方法的请求,它们都将返回资源。
第一个非常简单:它基本上返回用于创建应用程序页面的 HTML 代码,我们在这个页面上设置输入。
第二个函数获取我们在 web 应用程序中定义的输入,并将它们传递给返回概率的predict_probability函数。最后,get函数返回用于制作显示概率的应用程序页面的 HTML 代码。
然后我们必须添加类作为资源。为此,我们使用add_resource方法,指定类名和它们要去的 URL。
在脚本的最后,我们运行应用程序。
📒注意:如果你不知道if(__name__=='__main__')是做什么的,这里有一个解释:Python 在一个脚本执行的时候给它分配了名字__main__。如果该脚本是从另一个脚本导入的,则该脚本保留其给定的名称(不是__main__)。因此,使用if(__name__=='__main__')语句,我们确保应用程序仅在执行server.py脚本时运行。因此,如果我们在另一个脚本上,并从server.py脚本中导入一些东西,应用程序就不会运行。这是避免代码意外执行的常*做法。
除了 Python 脚本,存储库还有其他值得一提的文件:
adult.csv
这是原始数据。您也可以在 Kaggle 中访问它。
requirements.txt
在这个文件中,你可以看到我在我的环境中用来运行代码的包。不一定要有完全相同的版本。
templates文件夹
这里我存储了构建 web 应用程序的 HTML 代码。index.html有构建主页面的代码(在这里我们设置输入),而output.html有构建输出页面的代码(在这里我们看到概率)。
📒注意:我对 HTML 的了解有限,所以我确信代码可以在许多方面得到改进!
static文件夹
这里我存储 CSS 代码。
📒注意:如果你没有听说过 CSS,它是用来为你的 web 应用程序定义样式的,所以它帮助 HTML 代码使 web 应用程序看起来更好。
测试应用程序
一旦我们了解了以上所有内容,我们就可以运行我们的应用程序了。为此,在您拥有server.py脚本的根文件夹的路径中打开一个终端。写入python service.py运行service.py。
运行之后,您应该会在输出中看到这样一行:
* Running on [http://127.0.0.1:5000/](http://127.0.0.1:5000/) (Press CTRL+C to quit)
http://127.0.0.1:5000/是你申请的方向。
127.0.0.1 是本地主机的 IP,5000 是端口。端口 5000 是默认的,但是您可以使用server.py中的app.run()方法指定任何其他端口。
如果您单击 URL,您应该会在浏览器中看到 web 应用程序。现在你可以玩它,并检查一切工作!
结论
在这篇文章中,我们将一个机器学*模型变成了一个最终产品,因此每个人都可以与它互动并提取价值。作为未来的工作,我建议改进应用程序,增加新的功能,如在数据库中存储数据的选项(用 SQLAlchemy),或用户登录系统(用 Flask-JWT)。
希望你学到了很多!感谢阅读!
参考
用 Flask 和 Python 休息 APIs】,何塞·萨尔瓦蒂耶拉
通过生存分析将网页浏览活动转化为产品评级
原文:https://towardsdatascience.com/turning-web-browsing-activity-into-product-ratings-with-survival-analysis-5d5842af2a6d?source=collection_archive---------8-----------------------
在推荐策略中考虑用户的浏览数据,并通过一个实际的 Python 示例了解 UI 元素的有效性

图片作者。
介绍
推荐引擎是我们建立客户体验的坚实支柱。从应用内推送通知到个性化邮件列表,我们*惯于滚动浏览智能系统设计的建议,以引起我们的兴趣。尽管主题复杂且方法多样,但任何推荐系统的基础至少存在于三个实体中:
- 用户
- 制品
- 等级
虽然用户和产品是简单的概念,但评级隐藏了更多的微妙之处,因为它们的实施取决于几个因素,如业务领域、背景、用户体验(UX)和数据可用性。
从高层次来看,评级可以分为显性(喜欢、评分……)或隐性(购买、点击……)。
现在,让我们想象一个电子商务网站销售各种各样的产品。随着网站收集浏览活动,该公司希望利用它来获得可解释的洞察力关于用户与网页的互动如何影响购买。此外,该公司希望通过评分系统将这些互动转化为评级,旨在提高推荐质量和用户体验。
这篇文章通过一个实际例子描述了如何利用生存分析来实现这两个目标。
数据集
我们导入所需的库:
我们加载了一个为分析目的而合成的样本数据集:

图片作者。
每个观察描述了一个 web 会话,即从登录到产品页面到一个事件的浏览活动,该事件可以是购买或退出。特别是:
- 用户标识:用户标识。
- 产品标识:产品标识。
- added_to_wishlist :产品是否被添加至愿望清单。
- direct_or_recommend :用户是直接登陆产品页面,还是从上一页选择内部推荐。
- 点击评论:如果用户按下评论按钮,阅读其他顾客对产品的评论。
- click_on_more_details :如果用户按下“更多细节”按钮阅读更多产品细节。
- open_internal_links :如果用户从页面内选择链接到其他内部资源,即其他产品页面。
- 点击照片:用户是否点击产品照片。
- 购买:产品是否购买。
- time_to_event :从登陆产品页面到事件发生所经过的时间,无论是购买还是退出,以分钟表示。
我们可以想象这些数据是从与网页的交互开始收集的,如下所示:

虚构电商产品页面。图片作者。
我们的数据集包括 163 个网络会话,其中 156 个以购买结束,而 7 个以客户放弃而没有购买任何产品结束。
我们可以显示和比较按两个事件组分组的汇总统计数据和协变量分布(0 =放弃,1 =购买):

图片作者。
生存分析
生存分析包括一系列描述事件发生时间数据的统计方法。它在临床研究中被广泛采用,尽管它在不同的领域(例如预测性维护)中有合适的应用。
在我们的例子中,我们感兴趣的是浏览活动如何影响事件发生的时间。我们知道,一些用户进行了购买,而其他用户在一定时间后放弃了网站(正确审查):

图片作者。
卡普兰-迈耶估计量
我们用卡普兰-迈耶曲线来估计生存函数 S(t) 。生存函数给出了顾客在登陆产品页面后一定时间内存活(不购买)的概率。特别地,直到时间 t 的无条件生存概率被估计为生存到不同事件时间的条件概率的乘积:

其中:
- 生存函数的 S^(t):卡普兰-迈耶估计。
- t(i):当我们在离散时间尺度上观察事件时,至少一次购买(事件)发生的时间。
- nᵢ:在时间 t(i)既没有购买产品也没有离开网站的顾客数量。
- 时间 t(i)时的 dᵢ:事件(购买)数。
我们可以对给定条件下的 Kaplan-Meier 曲线进行分层,从而验证该条件是否会影响生存率估计值。
例如,将产品保存到意愿列表中是否会影响在给定时间段内购买它(事件)的概率?

图片作者。
我们一眼就能看出将产品添加到愿望清单中对购买的积极影响(或对免购买生存的消极影响)。
执行对数秩统计检验以评估两条曲线之间的差异,p 值允许我们拒绝零假设(H₀:曲线是相同的),确认存在与无意愿列表使用的存活率之间的统计学显著差异。
同样,我们可以评估点击“更多详情”按钮的效果:

图片作者。
同样,我们有证据表明,用户的浏览行为可以提供对所浏览产品的评价的有价值的*解。
但是,我们如何建立一个考虑到多个变量影响的模型呢?我们如何将与网页元素的交互转化为风险或评级的衡量标准?
Cox 比例风险模型
Cox 比例风险模型可用于评估变量和生存率之间的关系,其定义为:

该公式表明,风险函数 h(t| xᵢ )与基线风险函数 h₀(t 和相对风险指数(T2)成比例。
作为潜在危险函数 h₀(.的形式)未指定,则模型是半参数的。此外,可以在不估计 h₀(.的情况下估计 β ).
此外,Cox 模型提供了其系数的可解释性的额外优势。举个例子,我们可以只考虑一个协变量 xᵢ作为点击“评论”按钮,其中 xᵢ=1 表示用户访问了产品评论,而 xᵢ=0 表示用户没有选择该按钮,Cox 模型可以表示为 h(t|xᵢ)= h₀(t)exp(βxᵢ),其中 exp(β)表示点击“评论按钮相对于没有点击按钮的相对购买风险:
- 点击评论按钮给出的风险(xᵢ=1):h₀(t)exp(β⋅xᵢ)= h₀(t)exp(β⋅1)=h₀(t)exp(β)
- 未点击“评论按钮的风险(xᵢ=0):h₀(t)exp(β⋅xᵢ)= h₀(t)exp(β⋅0)= h₀(t)
- 相对风险=点击按钮的风险/不点击按钮的风险=h₀(t)exp(β/h₀(t)= exp(β)
我们可以拟合 Cox 模型并检验所得结果:

图片作者。
对于每个协变量 xᵢ,我们可以观察其相对风险 exp(β)及其置信区间:
- exp(β)>1(或β>0)表示购买的风险增加。
- exp(β) <1 (or β<0) a 降低了购买风险。
上表中对特征效应的一些解释如下:
- 将产品添加到意愿列表中显著增加了购买风险(p 值< 0.005),从最低 3.81 倍(预期(β)下 95%置信区间)增加到最高 11.19 倍(预期(β)上 95%置信区间)。
- 通过内部推荐访问产品页面(p 值=0.02) 与直接访问页面相比,购买风险从最低 0.93 倍(exp(β)上 95% CI)降至最高 0.45 倍(exp(β)下 95% CI) 。
- 点击商品照片 并没有(p 值=0.94) 增加也没有减少购买风险:事实上,我们可以注意到 exp(β) CI 在 1 附近振荡(下 95%=0.69,上 95%=1.42)。
我们可以通过绘制它们来进一步观察系数β:

βᵢ>0 表示购买产品的风险增加(将产品添加到意愿列表,点击更多详情),而βᵢ <0 indicates reduced risk to product purchase (access the product by recommendation over direct landing, open internal links from within the page). Image by author.
Among Cox model assumptions, we should make sure to fall under the hypothesis of proportional hazards:

Image by author.
In conclusion, thanks to survival analysis we can gain interpretable hazard measures that provide insights on the association between customers interaction with the web pages and survival rate.
For a given web browsing session, we may calculate the 部分危险为 exp( β'xᵢ ),因此忽略了基线危险 h₀(t),因此估计与产品购买相关的相对风险:

我们可以将其与同一产品页面上不同 web 会话的危害进行比较:

我们注意到第一个会话与比第二个会话(1.17)更高的部分风险 (4.93)相关联,这表明第一个用户隐含地表现出比第二个用户对该产品更高的偏好,并且他可能更有可能购买它。
事实上,我们可能会使用部分风险作为对评级的天真估计,从而将我们的浏览活动数据集转变为用户、产品和评级的三元组,这对任何推荐策略都至关重要:

作为隐含评级的部分危险。图片作者。
结论
在这篇文章中,我们应用生存分析技术来浏览一个虚构的电子商务网站收集的信息。
这种方法可以提供以下好处:
- 将网页浏览活动(用户行为)纳入评估计算中,以改进推荐。
- 可解释的危险能够解释什么样的与 UX 的相互作用可能导致事件(购买)。
- 网络浏览活动独立于用户的身份,而用户的身份是未知的。
- 突出现有用户界面的潜在改进领域(例如,客户和新网页元素之间的交互与购买风险的降低相关)。
重要的是要记住:
- 在这篇文章中,我们模拟了一次网络会话观察,定义为从登陆产品网页到购买或退出之间的时间。比如,我们没有考虑同一个用户是否在不同的场合多次登陆同一个页面。我们也没有考虑用户是否从之前推荐的结果(内部跳转)购买了产品。不同的问题定义方法会导致不同的假设,从而需要考虑不同的生存分析方法。
- 我们还假设我们的协变量不会随着时间而改变,因为我们将 web 会话数据作为一种“基线条件”来理解客户对产品的偏好和购买倾向。然而,我们可以通过修正考克斯 model⁴:来考虑时变协方差

- 在实现方面,由于我们使用了 lifelines⁵ Python 包,采用 Cox 时变比例风险模型将意味着适合 CoxTimeVaryingFitter ⁶对象,而不是coxp fitter⁷.尽管该对象仍然公开了在已知观测值下计算风险值的方法,但预测的含义并不简单:由于协变量会随时间而变化,因此从 t₁观测时间到 t₂时间的预测需要知道 t₂协变量假定的值,而这些值原则上是未知的。
- 我们选择通过利用部分风险来推断评级方法,exp( β'xᵢ )。其他方法可能是 pursued⁷.
- Cox 比例风险回归模型可能无法捕捉数据之间复杂的非线性关系。为此,可以研究不同的模型,如生存随机 Forests⁸或神经 Networks⁹(在 sci kit-生存⁰和皮考克斯软件包中有实现)。
- 关于隐式评级条件下的推荐策略的进一步信息可以在例如这里找到。
参考
[1] S. M. Al-Ghuribi,S. Noah,《推荐系统与情感分析综述》, arXiv:2109.08794 ,2021。
[2] E. L. Kaplan 和 Paul Meier,“来自不完全观测值的非参数估计”,《美国统计协会杂志》,第 53 卷,第 282 期,第 457- 481 页,1958 年。
[3] D. R. Cox,“回归模型和生命表”,皇家统计学会杂志。B 系列(方法学),第 34 卷,第 2 期。,第 187-220 页,1972 年。
[4]张中恒,贾科雷尼凯宁,卡泽姆·阿德达约·阿德莱克,马塞尔·e·皮耶特塞,凯瑟琳娜·g·m·格罗图伊斯-奥德索恩,“Cox 回归模型中的时变协变量和系数”,《转化医学年鉴》,6(7): 121,2018。
[5]https://lifelines.readthedocs.io/en/latest/
[6]https://lifelines . readthedocs . io/en/latest/fitters/regression/coxtimevaryingfitter . html
[7]https://lifelines . readthedocs . io/en/latest/fitters/regression/coxf fitter . html
[8] Hemant Ishwaran,Udaya B. Kogalur,Eugene H. Blackstone,Michael S. Lauer,“随机生存森林*”,《应用统计年鉴》,第 2 卷,第 3 期,第 841-860 页,2008 年。*
[9] Jared L. Katzman,Uri Shaham,Alexander Cloninger,Jonathan Bates,姜婷婷和 Yuval Kluger,“ Deepsurv:使用 Cox 比例风险深度神经网络的个性化治疗推荐系统”,BMC 医学研究方法,18(1),2018 年。
[10]https://sci kit-survival . readthedocs . io/en/stable/user _ guide/random-survival-forest . html
[11]https://github.com/havakv/pycox
[12]胡一帆,耶胡达·科伦,克里斯·沃林斯基,“隐式反馈数据集的协同过滤”,第 8 届 IEEE 数据挖掘国际会议论文集(ICDM 2008),意大利比萨,2008。
教程:打破关于人工智能公*性的神话
原文:https://towardsdatascience.com/tutorial-breaking-myths-about-ai-fairness-the-case-of-biased-automated-recruitment-9ee9b2ecc3a?source=collection_archive---------7-----------------------

Christophe Hautier 在 Unsplash 上拍摄的照片
公*与偏*
有偏*的自动化招聘案例
在无数关于人工智能偏*的丑闻(例如,这个、这个和这个)之后,人工智能的公*似乎是该领域的主要挑战之一。但是,AI 公*很难理解,也很难实现。在本教程中,我们构建并分析了一个特定的用例:自动化招聘,这在过去曾成为头条新闻。
在本教程中,我们将利用 IBM Research 的 AIF360 库。
让我们从头开始创建一个有偏差的数据集
假设目标是招聘给定工作的人员(例如数据科学家)。基本上有两种截然不同的人群:男性和女性。
我们有意引入三种不同的偏*:
- 代表性偏差:女性比男性少三倍,
- **社会偏*:**女性期望薪水比男性低(错!),*均每年少 6 000 美元,但技能相似,
- 历史偏*:招聘在过去一直对女性有偏*,与期望的工资或技能水*无关。
(关于数据集中偏*的详尽列表,请参* Mehrabi et al. 2019,关于机器学*中偏*和公*的调查。)
真正的历史模型是一个逻辑回归,由以下因素构成:
- 𝑋𝑠𝑘𝑖𝑙𝑙:技能水*,0 到 20 分之间的一个等级,
- 𝑋𝑠𝑎𝑙𝑎𝑟𝑦:期望的薪水,一年几千美元,
- 𝑋𝑠𝑒𝑥:性别是一个二元变量,女性为 0,男性为 1,
- 𝑌:应聘者是否以预期的薪水被录用,0 表示否,1 表示是。
高技能水*低预期工资最大化招聘。无论这两个特征是什么,男人总是被系统地偏爱。这被转化为具有系数𝛽的逻辑模型,使得:

图片由作者提供。
下面是允许我们利用 AIF360 库的代码。
from sklearn.model_selection import train_test_split
from aif360.datasets import BinaryLabelDatasetdf = create_dataset() **# this is our simulated dataset**df_train, df_test = train_test_split(df, test_size=0.2)attributes_params = dict(
protected_attribute_names=[“sex”],
label_names=[“recruited”]
)dt_train = BinaryLabelDataset(df=df_train, **attributes_params)
dt_test = BinaryLabelDataset(df=df_test, **attributes_params)
模拟这样的招聘策略,我们获得以下训练集:

有偏*的招聘培训集。图片由作者提供。
在这个技能/工资层面,我们仍然可以通过社会偏*来猜测性别:女性躺在较低的云层中,期望较低的工资,而男性躺在较高的云层中。更高的技能会导致更频繁的招聘,而更高的薪资期望(对于固定的技能水*)会导致更多的拒绝。
到目前为止,一切顺利。
然而,你可以看到女性不受欢迎,因为女性的决策边界(在较低的云上)向右移动:对于给定的技能水*,女性比男性获得聘用的机会少。这正是我们在本文中要解决的历史偏*。
关键要点: 在解决一个偏*之前,你必须选择考虑哪个偏*。你不能简单地“纠正偏*”,当然也不能一下子纠正所有的偏*。
衡量公*性
在本教程中,我们选择不同的影响(DI)作为歧视的衡量标准。不同的影响定义如下:

过去标签不同影响的定义。图片由作者提供。
完全不同的影响有几个优点:
- 计算起来很简单,
- 这很容易解释:没有歧视意味着人人*等,
- 在美国法律中,它被定义为一种法律约束:任何具有 DI < 0.8 can be legally fined.
不同影响的流程也有缺点:
- 它假设敏感属性和目标之间没有影响,但事实并非总是如此。
在我们的案例中,我们假设没有根本的原因让女性比男性被雇佣的少,因此坚持用完全不同的影响作为公*的衡量标准。
(关于公*指标和不同影响的更多信息,请参* Caton 和 Haas 2020,机器学*中的公*:调查。)
那么,过去招聘政策的不同影响是什么?下面是答案。

过去招聘的不同影响。虚线代表在美国法律中被认为是合法的。图片由作者提供。
我们看到不同的影响接近 0.5,这意味着女性被录用的机会比男性少两倍。现在让我们回顾一下不同的偏差缓解策略。
策略 1:什么都不做
嗯,严格来说这不是一种策略…这只是人们在没有意识到公*时所做的事情。让我们对𝑋𝑠𝑘𝑖𝑙𝑙、𝑋𝑠𝑎𝑙𝑎𝑟𝑦、𝑋𝑠𝑒𝑥进行逻辑回归,看看会发生什么。
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import RobustScaler
from sklearn.dummy import DummyClassifier
from sklearn.linear_model import LogisticRegressionpreprocessing = ColumnTransformer(
[(“scaler”, RobustScaler(), [0, 1])],
remainder=”passthrough"
)lr = Pipeline([
(“preprocessing”, preprocessing),
(“lr”, LogisticRegression(C=1e9))
])lr.fit(
dt_train.features,
dt_train.labels.ravel()
);
y_pred = lr.predict(dt_test.features)
首先,模型在测试集上的精确度是多少?

测试基线“无人招募”模型的准确性,以及对公*性“无所作为”的简单逻辑回归。图片由作者提供。
我们将我们的模型与一个非常天真的基线进行比较:拒绝每个候选人的“无人”模型(是的,非常天真……)。这个基线有 68%的准确率,只是意味着过去有 68%的候选人被拒绝。相比之下,我们的第一个逻辑模型做出了更好的预测,达到了令人瞩目的 93%的准确率,万岁!
哦,等等…我们的模型已经产生了什么不同的影响?我们通过转换真实标签和预测标签,稍微修改了不同影响的定义:

自动化招聘决策的不同影响。图片由作者提供。
现在,我们可以将我们的模型与测试集上的历史流程进行比较:

图片由作者提供。
啊哦…我们有一个高度精确的模型,但是当然我们只是学到了和历史过程中的那个一样的偏差。我们与有偏*的招聘过程本身有着几乎相同的不同影响。
我们有偏分类器的决策边界是什么?

基于历史数据集训练的简单逻辑模型的决策边界。上半部分是男性的决定边界,下半部分是女性的边界。图片由作者提供。
在这个图表中,我们将决策边界分为两部分:顶部是男性的,底部是女性的。毫不奇怪,我们看到我们的模型完美地再现了对女性的偏*,女性应该比男性拥有更多的技能。
关键外卖: 如果你对公*什么都不做,你的模型就和你的训练数据一样公*。
策略 2:删除敏感属性
这是最流行和最容易实现的策略:我们简单地阻止模型使用敏感属性(在我们的例子中是𝑋𝑠𝑒𝑥),并希望不同的影响得到改善。
lr.fit(
dt_train.features[:, 0:2], **# this is how we remove X_sex**
dt_train.labels.ravel()
);
y_pred = lr.predict(dt_test.features[:, 0:2])
就不同的影响而言,这是我们在测试集上获得的结果:

图片由作者提供。
哇!这是一种进步!似乎我们的算法现在符合美国法律。让我们想象一下我们新的决策边界。

用敏感属性删除训练的简单逻辑模型的决策边界。图片由作者提供。
哦,等等…这是意料之外的…我们现在有了一个独特的男性和女性的决策界限。但现在似乎有一个新问题:要求更高的薪水才能被录用!要是我知道就好了…
这种对薪水的偏*当然不利于女性,因为她们倾向于期望较低的薪水,因此你的不可忽视的不同影响!
这就是我们的模型如何学会忽略性别的…尽管有这些数字,仍然有一个由这个决定边界引起的基本歧视。模型在一定程度上再现了历史偏*,为了歧视女性而用期望工资作为性别的代理,哪怕是逻辑上的扯淡!
关键外卖: 去掉敏感属性并不一定让你的模型变得公*。
关键外卖: 具有接近一的异类影响是公*的必要但非充分条件。
策略 3:通过重新称重进行预处理
这种策略非常简单,它只关注训练集,并试图通过重新加权实例来消除不同的影响。基本上,具有有利结果的非特权群体(被招募的妇女)被给予较大的权重。这促使模型以与现有偏差相反的方式重新调整其决策边界。
让我们假设在训练集中没有偏差。这意味着𝑌和𝑋𝑠𝑒𝑥是独立的。所以我们期望那:

左手边:独立假设下 Y 和 X 的期望联合概率。右边:作者观察到的 Y 和 x 的边际概率的乘积。
然而,在有偏差的数据集中,我们观察到𝑃𝑜𝑏𝑠(𝑌=1,𝑋𝑠𝑒𝑥=0),这与上述等式的右侧不同。那么让我们来定义𝑊:的权重

图片由作者提供。
就是这样!构造对 now 1 中重新加权数据集的不同影响:

图片由作者提供。
在我们的二进制𝑌和二进制𝑋𝑠𝑒𝑥的例子中,只需要计算四个权重,非常简单!
(更多详细信息,请参* Kamiran 和 Kalders 2012,无歧视分类的数据预处理技术)
所以让我们实例化一个重新称重的对象。
from aif360.algorithms.preprocessing import Reweighingprivileged_groups_params = dict(
privileged_groups=[{‘sex’: 1}],
unprivileged_groups=[{‘sex’: 0}]
)RW = Reweighing(**privileged_groups_params)dt_train_reweighed = RW.fit_transform(dt_train)
weights = dt_train_reweighed.instance_weights
让我们想象一下新的、重新称重的训练集。

重新加权的训练集。点的大小反映了个体的权重。图片由作者提供。
让我们在这个*衡的数据集上训练一个新的逻辑回归。这可以简单地通过向我们的管道的 fit 方法添加一个 sample_weight 选项来完成。请注意,我们一直在删除敏感属性。
lr.fit(
dt_train.features[:, 0:2],
dt_train.labels.ravel(),
lr__sample_weight=weights **# this is how we use weights**
);
y_pred = lr.predict(dt_test.features[:, 0:2])
以下是之前所有策略的不同影响:

图片由作者提供。
有两件有趣的事情需要注意:
- 首先,重新称重的历史具有一个完全不同的影响,直至机器精度。这是上面讨论的定理的结果。
- 第二,即使对训练集的不同影响是一个,对其训练的模型的不同影响也不是一个。
让我们通过对所获得的判定边界的视觉检查来研究这个案例:

通过敏感属性删除和训练集重新加权训练的简单逻辑模型的决策边界。图片由作者提供。
对…这看起来像是一个比以前更容易接受的决策函数,而且确实有更多的女性被录用了。但是……给更高的期望工资更高的分数在逻辑上是没有意义的,对女性的歧视通过社会偏*普遍存在:在固定的技能水*上,女性得到的雇佣更少,因为她们要求更低的工资。这就是历史偏*如何潜入我们的模型,尽管我们尽一切努力重新*衡历史偏*。
关键要点: 在训练集中去除偏差并不一定会让你的模型无偏。
策略 n 4:通过剔除进行后处理
这个策略相当简单:每当模型对决策不确定时,就实施积极的区别对待。换句话说,每当分数接近 0.5 的时候,系统地招收女性,拒绝男性。
因此,让我们首先在原始训练集(未重新加权)上重新训练一个模型。
lr.fit(
dt_train.features[:, 0:2],
dt_train.labels.ravel()
);
y_prob = lr.predict_proba(dt_test.features[:, 0:2])[:, 1]
现在,我们定义拒绝余量𝜃,以便:

图片由作者提供。
这仅仅意味着男性在决策边界附近不受欢迎。这个想法是,当候选人之间没有明显的区别时,歧视更容易发生。
(详* Kamiran 等人 2012 年的《歧视感知分类决策理论》。)
所以让我们实例化一个 RejectOptionClassification 对象 (ROC)。
我们指定两个参数:
- 分类阈值
- 中华民国边境𝜃.
from aif360.algorithms.postprocessing import (
RejectOptionClassification
)ROC = RejectOptionClassification(**privileged_groups_params)
ROC.classification_threshold = 0.5
ROC.ROC_margin = 0.15dt_test.scores = y_prob.reshape(-1, 1)
y_pred = ROC.predict(dt_test).labels
我们获得了以下不同的影响(右边的栏) :

图片由作者提供。
哈哈!似乎我们又获得了一个可以接受的完全不同的冲击。我们甚至把男人变成了弱势群体…哦!
对决策边界意味着什么?

在历史数据集上训练的简单逻辑模型的决策边界,具有敏感属性移除和拒绝选项后处理。上半部分是男性的决策边界,下半部分是女性的决策边界。图片由作者提供。
看到我们如何实施积极的区别对待了吗?在接近决策界限时,男性的得分较低,因此系统性地不受欢迎,而女性则相反。
但是该死的!分数和期望工资之间仍然存在这种不一致:即使男女之间存在抵消,双方都会通过要求更高的工资来最大限度地增加被聘用的机会。
现在,让我们来研究一下𝜃参数。该参数对阳性识别的数量进行编码。准确性和完全不同的影响是如何演变的?

测试准确度(蓝色)和测试不同影响(红色),作为拒绝余量𝜃.的函数较大的拒绝余量会导致较低的精度和较大的不同影响。图片由作者提供。
这就是所谓的公*效用权衡:改善不同的影响必然会降低准确性。
但是!回想一下,精度最大化并不是我们一开始想要的:**欢迎评价偏差!**最大限度地提高准确性仅仅意味着我们完美地再现历史偏差,这不是我们的首要目标。
关键外卖: 这里有一个公*-效用权衡:你不可能做到公*准确。不过没关系!最大化精确度最多是学*预先存在的偏差的最好方法。准确性降低并不意味着你会亏钱,只是你会以不同的方式赚钱。
策略 n 5:带约束的在制品
这种策略只不过是一种逻辑回归,带有对算法产生的偏*进行编码的附加惩罚。偏*指数𝑃𝐼被定义为预测和敏感属性𝑆(在我们的例子中是𝑋𝑠𝑒𝑥)之间的互信息:

偏*指数(PI)定义。图片由作者提供。
在实施中,这一项与标准对数损失成本函数相加,具有系数𝜂.
(详* Kamishima 等人,2012,带有偏*消除器正则化器的公*感知分类器)。
让我们看看𝜂=100.会发生什么
from aif360.algorithms.inprocessing import PrejudiceRemoverpr = PrejudiceRemover(eta=100.0)dt_train.features = preprocessing.fit_transform(dt_train.features)
dt_test.features = preprocessing.transform(dt_test.features)pr.fit(dt_train);
y_pred = pr.predict(dt_test).scores >= 0.5

图片由作者提供。
同样,不同的影响似乎是可以接受的。但是让我们保持批判的头脑。决策边界是什么样的?因为我们的算法使用了性别变量(希望是以积极的方式?),我们再次把图拆分成两部分:男性的决策边界(上)和女性的决策边界(下)。

用偏*惩罚训练的简单逻辑模型的决策边界。图片由作者提供。
嗯…相对于我们“什么都不做”的策略,女性的决策边界被*移到了左边,有点倾斜,以便让更多的女性被招募进来。
然而,如果你仔细观察图表,你会发现一个技能水*为 10,期望工资为 40 的女性没有被录用,而一个技能和工资水*相同的男性肯定会被录用!这是由于偏*(即互信息)主要依赖于𝑌和𝑋𝑠𝑒𝑥的列联表,这只是数据的汇总视图:欢迎汇总偏*!
而且,想象一下,以后女性往往会要求越来越高的薪水(那就太好了!),然后女性云会稍微向高层转化,越来越少的女性会被算法雇用,最终降低你的不同影响:欢迎人工智能模型生命周期!
所以你明白了:公*不仅仅是另一个需要优化的指标!
这种情况下的公*效用权衡呢?让我们来玩玩𝜂惩罚参数:

测试准确性(蓝色)和测试不同影响(红色)作为偏*的函数𝜂.更大的偏*惩罚导致更小的准确性和更大的不同影响。图片由作者提供。
这是公*-效用权衡的另一个例子:公*模型的准确性较低。但是,当数据集本身有偏差时,性能的概念本身也有偏差。
关键提示: 消除偏差的技术有几种,但没有一种是完美的。
策略 6:你的策略
如果你可以用手画一个决策界限,你会如何塑造它以达到准确、公*和一致?
此后是一个命题。让我们实例化一个定制的 FairModel 类,看看它说了什么。
fm = FairModel(lr) **# Our custom fair model (what is it? suspense!)**
fm.fit(
dt_train.features[:, 0:2],
dt_train.labels.ravel()
);
y_prob = fm.predict_proba(dt_test.features[:, 0:2])
以下是我们的定制策略与所有其他策略在准确性和不同影响方面的比较:

测试本文中所有建模策略的准确性。图片由作者提供。

测试本文中所有建模策略的不同影响。图片由作者提供。
我们的策略在准确性和不同影响方面表现相对较好。但是既然我们已经被数字愚弄了,那就让我们仔细看看决策边界。

结合简单业务规则的简单逻辑模型的决策边界。图片由作者提供。
Tadaa!看到我们做了什么吗?我们只是在最初的逻辑回归中应用了一个业务规则:
“如果工资高,靠历史数据。别的,干脆无视薪资。
因此,这一模式似乎对男性和女性都是公*的,不受代表性、社会和历史偏*的影响。此外,即使社会发生变化,女性倾向于逐步要求更高的工资,我们的模式将保持公*和一致。这就是我们所说的稳健性。
我们是如何应对这三种偏*的?
- 代表性偏差:我们的逻辑模型只适用于男性,它代表了技能和薪水方面的基本事实。
- **社会偏*:**低期望工资对招聘没有影响,因此性别也没有影响。
- **历史偏*:**女性的界限决定根本没有优化准确性:它与男性的界限决定是连续的(一致性),并且忽略了工资。
关键外卖: 在业务逻辑、性能和公*性方面的最优解,可能是机器学*和业务规则的混合。
让我们消除模型中的偏*!
在本教程中,我们遇到了五种不同的偏*:
- **代表性偏差:**没有足够多的女性单独依赖不同的影响测量(更不用说同样有缺陷的统计测试)。
- **社会偏*:**女性和预期薪资强相关,这削弱了敏感属性移除等天真偏*缓解方法。
- **历史偏*:**女性在训练集中已经被歧视了。
- **评估偏差:**女性在测试集中也会受到歧视,因此单独考虑准确性度量是没有意义的。
- **聚合偏倚:**完全不同的影响、互信息和所有相关的显著性检验依赖于数据集的粗略汇总,即列联表。这些数字可以被人为夸大,而不抑制歧视。
在本教程中,前三种偏*被一个简单的业务规则抵消了。后两种偏*被可视化和高度可解释的模型所抵消。
关键要点
算法偏差是微妙而普遍的。公*是很难实现的,并且对“绩效”这个概念本身提出了质疑。没有神奇的指标可以优化,也没有神奇的库可以解决这个问题。
永远都不会有。
透明度是关键。人在回路中是至关重要的。
加入
我在量子力学公司工作。Quantmetry 自 2011 年成立以来一直是先驱和独立的公司,是法国领先的纯人工智能咨询公司。在提供卓越的数据治理和最先进的人工智能解决方案的愿望的驱动下,Quantmetry 的 120 名员工和研究顾问将他们的热情投入到为所有行业的公司提供高业务成果的服务中。
阅读我们最新的白皮书:https://www.quantmetry.com/lp-ia-de-confiance/
参考
[1] Mehrabi 等人,关于机器学*中的偏*和公*的调查,2019,arXiv
【2】Caton 和 Haas,机器学*中的公*:一项调查,2020,arXiv
【3】kami ran 和 Calders,无歧视分类的数据预处理技术,2012,知识与信息系统
[4] Kamiran 等人,区分感知分类的决策理论,2012,IEEE 第 12 届数据挖掘国际会议
[5] Kamishima 等人,带有偏*消除器正则化器的公*感知分类器,2012,关于数据库中机器学*和知识发现的欧洲联合会议。
教程:通过 Traitlets 创建 Python CLI 包
原文:https://towardsdatascience.com/tutorial-create-a-python-cli-package-a2410b47af35?source=collection_archive---------13-----------------------
使用traitlets开发一个简单的、面向对象的命令行包

照片由黑脸田鸡岛崎从 Pexels 拍摄
如果你像我一样…
- 您喜欢编写脚本来加快工作流程
- 你的 Python 很流利,其他基本不会。
令人恼火的是,python 在终端中感觉有点笨拙。
如果您想从命令行运行 python 脚本,您需要…
- 给每个不可能记住的脚本分配一个不同的命令(通常是 bash 别名
- 使用
syspython 包从头开始解析命令行参数 gross - 用
argparse解析命令行,用if/else检查激活每个功能。亦作 gross
好在这个问题有解决的办法!它叫做traitlets。
什么是 traitlets?
Traitlets 由 IPython 创建,用于验证数据类型、监控变量的变化、解析和实现配置文件中的应用程序设置,以及从命令行激活 Python 代码。对于 IPython 和 Jupyter 项目生产的许多软件来说,它充当了一种幕后引擎的角色。现在,我们将关注 traitlets 的两个元素。
- 从命令行激活 python 代码
- 可配置变量
目标
在本文中,我将逐步构建一个简单的traitlets应用程序。有了这些知识,你将能够编写一个命令行程序
- 完全是用 python 写的。
- 为单个 CLI 命令分配多个工具。
- 可以通过命令行或系统配置文件轻松配置。(您不必编写代码来解析配置数据🤩)
- 具有直接面向对象的编程结构。
项目代码:
- 如果你想自己编写项目代码,这个 github 库包含了所有的项目文件。每个文件中的代码已被替换为指导性注释。
- 完成的项目代码可在处找到。(代码存储在 github 库的
solution分支上。如果您已经克隆了存储库,那么您可以运行git checkout solution来访问您计算机上的代码。)
我们在建造什么?
首先让我们看看成品是什么样的…

这个应用程序有两个命令。
**greet**
当这个命令运行时***“Hello,World!”被打印到*端子**。
该命令有参数 --greeting、--name和--punctuation,允许您更改打印的信息。
**abs**
当运行此命令 时,提供的文件名的绝对路径被打印到终端。
该命令有标志T7。使用该标志时, 除了绝对路径外,还打印文件大小(以字节为单位)。
该项目的目录结构如下所示:
subapps/ <------------- All "command" code-files are placed here
AbsApp.py <------ Code for the `abs` command
GreetingApp.py <-- Code for the `greet` command
__init__.py <----- Set up for easy importing
CLIapp.py <------------ Code for CLI activation
好吧,我们来写点代码。
GreetApp.py
导航到项目文件夹的subapps/目录,打开GreetApp.py文件。
我们将需要这个文件的两个导入。
from traitlets.config import Applicationfrom traitlets import Unicode
在继续之前,让我们快速分解一下这两个导入。
导入#1 —应用
是我们将在这个项目中编写的每个类的“父类”。Application对象提供了大量有用的工具,例如解析命令行、加载配置文件、生成配置文件、自动生成代码文档等等。在本教程中,我们将关注Application对象解析命令行和激活应用程序代码的方法。
导入#2 — Unicode
Unicode是一款 traitlets 型。
- C ode 类型的例子。
- 所有可用类型的列表。
Traitlets 类型是类属性,当被定义时,防止属性被分配给不正确的数据类型。当参数config=True被添加到类型中时,变量变得可配置,这意味着属性的默认值可以通过命令行参数或通过在配置文件中设置所需的默认值来更改。
定义可配置变量。
在下面的代码单元格中,我们…
- 导入
Application和Unicode对象 - 定义
GreetApp类 - 从
Application父类继承 - 用默认设置定义类型变量。
- 将变量标记为可配置的
现在让我们创建 ***start*** 方法
start方法是激活应用程序功能的地方。
在下面的代码块中,我们……
- 定义一个
start方法 - 激活应用程序功能
命令行别名
从技术上来说,我们可以让应用程序像这样运行,但是改变可配置变量对用户来说有点烦人。
现在,用户不必运行--greeting='Hi'来将问候配置变量更改为'Hi',而是必须运行:
--GreetApp.greeting='Hi'
为了使这更容易,我们必须创建一个aliases类属性。该属性由Application父类在解析命令行时使用。
在下面的代码块中,我们……
- 定义包含我们别名的字典
- 将字典键设置为我们想要使用的命令行参数
- 将值设置为我们想要配置的
Application孩子的名字 - 阐明我们想要改变的可配置变量
- 将
aliases类特征设置为别名字典
**GreetApp**搞定了!
我们还可以向这个应用程序添加一些其他的东西,这些将在后续文章“如何自动生成文档”中介绍如果你正在处理自己编写的文件,现在跳过未填写的部分。对于本文,它们不是必需的。
主要功能
现在我们已经完成了一个应用程序,我们需要设置激活代码的main函数。这个过程将由CLIapp.py文件处理。
导航到CLIapp.py文件。
对于这个文件,我们将需要以下导入。
from traitlets.config import Applicationfrom subapps import GreetApp(我们刚刚写的应用对象!)
Application对象有一个名为subcommands的属性,允许你附加激活特定应用程序的命令。在这个文件中,我们将定义一个名为CLIapp的应用程序,它包含一个子命令字典,以及一个用于激活子命令的 start方法的启动方法。TL;DRCLIapp是一个应用程序,其唯一目的是激活其他应用程序的代码。
让我们把这个写出来
在下面的代码块中,我们……
- 导入
Application和GreetApp对象 - 定义
CLIPapp应用程序 - 用以下格式定义字典:
{command : (application object, application description)}
4.定义一个start方法
5.检查以确保用户提供了子命令。如果他们没有打印出可用的子命令
6.激活Application.start 方法,依次激活子应用的start方法。
好吧!那就是CLIapp
现在我们需要做的最后一件事是定义一个主函数来激活所有的代码。
在下面的代码块中,我们……
- 在之外定义一个
main函数 - 通过
launch_instance方法激活代码。这是命令行被解析的地方 - 添加
if __name__ == "__main__"检查,允许我们从命令行调用main功能。
我们现在有了一个可用的应用程序! 🥳
在您的终端中,导航到项目目录的顶层并运行
python CLIapp.py greet“世界你好!”将被打印python CLIapp.py greet --greeting="Hi"“嗨,世界!”将被打印python CLIapp.py greet --name="Joel"“你好,乔尔!”将被打印
AbsApp.py 添加新命令
现在让我们看看通过创建abs命令向现有应用程序添加新工具的过程。
在AbsApp.py文件中,我们将运行以下导入
*from traitlets.config import Application
from traitlets import Bool
import os*
这两个新导入的是 **Bool** 和 **os** 。
Bool 是另一种traitles 类型。在这种情况下,它确保变量被设置为True或False
os 是一个基础 Python 包,代表“操作系统”。它是一个标准软件包,用于生成文件路径、列出文件夹中的文件以及与计算机操作系统交互。在我们的例子中,我们将使用os来生成文件的绝对路径,并计算文件使用了多少字节。
好,接下来我们将构造我们的AbApp类。
在下面的牢房里,我们…
- 定义
AbsApp应用程序 - 定义一个 traitlets 类型为
Bool的可配置size变量 - 定义一个
start方法 - 通过
extra_args属性访问用户提供的文件名 - 通过 os
isfile功能确保用户提供的文件是有效文件。 - 打印所提供文件名的绝对路径
- 如果用户将
size可配置变量设置为True,文件大小也会被打印。
现在,我们将为 AbsApp 创建一个标志*,允许用户简单地运行…***
*--size*
…而不必显式地将size设置为真或假。为此,我们将定义一个由Application父类在解析命令行时使用的flags类变量。
在下面的牢房里,我们…
- 定义一个名为
flags的dict变量 - 将顶层密钥设置为将在命令行中使用的标志
- 将键的值设置为一个
tuple - 向元组添加一个字典,其中键是应该由标志配置的应用程序的名称
- 将键的值设置为另一个字典,其中键是可配置变量的名称,值是要分配给变量的数据。
- 将标志的描述添加为元组中的第二项。如果用户使用
--help参数,这将被打印出来! - 通过
Application.flags属性将标志添加到应用程序中。
值得注意的是:在更新配置时,标志非常强大。二级字典可以包含多个应用程序,三级字典可以包含多个可配置变量!
ABS app 完成了! ✅
现在最后一步是将 app 添加到CLIapp.py文件中!
在下面的代码块中,我们…
- 将
AbsApp对象导入到CLIapp.py文件中 - 向
CLIapp对象添加一个abs子命令
就这样,一个新的命令被添加到您的应用程序中!
在您的终端中,导航到项目目录的顶层并运行
python CLIapp.py abs CLIapp.py将打印 CLIapp.py 文件的绝对路径python CLIapp.py abs CLIapp.py --size将打印 CLIapp.py 文件的绝对路径和文件大小
根据我自己用 traitlets 编写应用程序的经验,编写新应用程序和向现有工具添加新命令的便利性是最好的好处之一。因为这个过程根植于面向对象编程,所以有时编写一个全新的应用程序就像从现有的应用程序继承然后编辑一行代码一样简单!
***好了,现在就这样。*我的下一篇文章一定要点击 follow 按钮:trait lets 配置文件和如何自动生成代码文档的演练!
教程:使用 Google 登录进行 MongoDB 用户认证
原文:https://towardsdatascience.com/tutorial-mongodb-user-authentication-with-google-sign-in-fcc13076799f?source=collection_archive---------13-----------------------
简化应用程序访问控制和个性化用户体验的分步指南。

照片由弗兰克在 Unsplash 上拍摄
MongoDB 因其高性能、广泛的开发人员支持和慷慨的免费层而迅速成为我的非关系数据库*台选择。与许多数据库引擎一样,用户管理和访问控制可能会变得非常复杂,尤其是当软件堆栈使用其他资源时,如微服务或云存储。幸运的是,我们可以利用所谓的“联合身份提供商”,如谷歌、脸书和亚马逊,将用户身份验证与应用程序的其余部分分离开来。
在本教程中,我们将从头开始构建一个基于 MongoDB 的安全应用程序的所有必要步骤。用户将需要登录他们的谷歌帐户从数据库中读取。

到本教程结束时,我们将有一个简单的 web 应用程序,允许用户通过使用他们的 Google 帐户登录来查看水果市场。
在我们可以编写一行代码之前,我们必须设置我们基于云的认证流程,这涉及到 Google Identity、AWS IAM,当然还有我们的 MongoDB 集群之间的协调。
注册 Google 应用程序
我们需要做的第一件事是向 Google 注册我们的应用程序。除了利用现有的安全基础设施(并通过熟悉的界面使登录页面合法化),这将使我们能够通过查看客户的个人资料信息来个性化用户体验。
首先,登录到谷歌云控制台,创建一个新项目,并给它一个描述性的名称。

在谷歌云控制台中创建新项目(图片由作者提供)。
一旦您的新项目初始化,搜索“APIs & Services”,导航到侧边栏中的“OAuth 同意屏幕”选项卡,然后单击“创建外部用户”。在设置向导的第一页,您需要提供应用程序名称和电子邮件地址,以便获得用户支持。

配置 OAuth 同意屏幕,它将通知用户我们的应用程序正在请求什么权限(图片由作者提供)。
下一页是我们将定义应用程序范围的地方,它确切地规定了我们将有权阅读或修改用户 Google 帐户的哪些方面。这是整个过程中最重要的步骤之一,因为我们可以请求用户的联系信息、日历、位置或其他个人内容。在这个演示中,我们的应用程序将能够读取用户的电子邮件地址和个人资料,其中包括他们的姓名和头像。

应用程序的启用范围-在这种情况下,读取用户电子邮件和个人资料的访问权限(按作者分类的图像)。
重要提示:在生产环境中,您需要提供隐私政策和其他法律文件,以准确定义这些个人信息的使用方式。
接下来,分配至少一个测试用户。在我们的应用程序被谷歌正式批准公开访问之前,登录权限将仅限于这些帐户。

在我们的应用程序被谷歌正式发布之前,分配测试用户是必要的。
一旦我们建立了 OAuth 同意屏幕,我们需要为我们的 Google 应用程序生成一个客户端 ID。仍然在 APIs & Services 中,导航到侧栏中的“Credentials”选项卡。在“创建凭据”下,选择“OAuth 客户端 ID”。

在凭证选项卡上创建 OAuth 客户端 ID(图片由作者提供)。
将客户端初始化为 web 应用程序,并添加 http://localhost:8000 作为授权的 JavaScript 源,因为登录请求将从我们的本地开发服务器发出(稍后将详细介绍)。

配置客户端 ID 凭证(图片由作者提供)。
这将生成您的应用程序的客户端 ID(类似于 1234567890 . apps . Google user content . com)。我们将在几个不同的地方需要它,所以把它粘贴到容易访问的地方。

复制客户端 ID(图片由作者提供)。
这就完成了谷歌控制台的过程。现在转到 AWS。
在 AWS 中创建 IAM 角色
一旦你的应用在谷歌注册,登录你的 AWS 控制台账户。搜索“IAM”,在侧边栏选择“角色”,点击“创建角色”。对于受信任实体的类型,选择“Web Identity”并选择 Google 作为身份提供者(您会注意到,我们可以对脸书、亚马逊和其他联合身份提供者使用类似的流程)。将您的 Google 客户端 ID 粘贴到受众下。接受其余角色设置的默认值。

在 AWS IAM 中,创建一个新角色,使用 Google 作为身份提供者(图片由作者提供)。
一旦创建了您的角色,记下角色 ARN(例如,arn:AWS:iam::AWS _ ACCOUNT:Role/roleName),我们将在下一步中用到它。

一个可以找到 ARN 这个角色的地方。
这就完成了这个演示所需的 AWS 设置,但是我要注意,通过调整附加到这个角色的策略文档,我们可以将我们的应用程序连接到其他 AWS 资源,比如 S3 桶和 Lambda 函数。
配置 MongoDB 数据库
接下来,我们需要启动并配置我们基于云的 MongoDB 集群。登录 MongoDB Atlas 创建一个组织。

在 MongoDB Atlas 中初始化一个新组织(图片由作者提供)。
在您的 Atlas 组织内,创建一个新项目并为其命名。

创建新项目(图片由作者提供)。
最后,创建一个数据库。在这个演示中,我将使用一个免费的共享集群。

我选择了(免费)共享层(最右边的选项)。
确保选择 AWS 作为该集群的云提供商和 M0 沙盒层(也是免费的)。除非您选择升级容量,否则您不必连接信用卡,这在我们的简单演示中是不必要的。

将集群部署到您选择的 AWS 区域,并确保使用 M0 沙盒层来免费使用数据库(图片由作者提供)。
在部署集群时,喝杯咖啡。准备好后,点击“收藏”标签。如果您不熟悉 MongoDB 语法,“集合”类似于 SQL 表,“文档”可以被认为是表中基于 JSON 的条目或行。首次创建新集合时,您可以选择使用样本数据集或添加自己的数据集。我们会选择后者。

创建新的数据库和收藏(图片由作者提供)。
假设我们的应用程序是一个水果市场,它存储各种商品的名称、价格和剩余数量。我们将在“test”数据库的“marketplace”集合中插入一些文档。最快的方法是直接在 web 界面中完成,但是你也可以通过 MongoDB shell 或者他们支持的驱动中的一个来执行批量插入。由于本教程更侧重于身份验证,所以我不会详细讨论 MongoDB 中的模式或用法。

在 web 界面中将文档插入到 MongoDB 集合中。你也可以从这个页面测试查询(图片由作者提供)。
最后,让我们将数据库连接到我们的 IAM 角色。在侧边选项卡上,转到“数据库访问”并添加一个新的数据库用户。对于身份验证方法,选择“AWS IAM ”,并在“AWS IAM 类型”下拉菜单中选择“IAM 角色”。将角色 ARN 粘贴到所需的输入中。

使用 AWS IAM 凭据添加新的数据库用户(图片由作者提供)。
调整用户权限是另一个复杂的主题,完全有理由拥有自己的博客。我们将授予该用户对我们刚刚创建的“marketplace”集合的只读访问权限。

将此用户的权限限制为只读访问 test.marketplace 集合(图片由作者提供)。
除了基于用户的身份验证,MongoDB 还可以限制对特定 IP 地址的访问。在生产环境中,我们只想允许来自应用服务器的请求,以帮助阻止 DDoS 攻击等威胁。由于我们将在本地运行演示应用程序,在“网络访问”下,只添加您当前的 IP 地址,遵循最小特权的原则。

将网络访问限制在绝对需要的 IP 地址上(图片由作者提供)。
将所有这些放在演示应用程序中
设置完成后,我们终于准备好编写一些代码了。如果一切顺利,用我们的 Google 帐户登录将返回一个 ID 令牌,该令牌可用于检索 AWS IAM 角色的凭证。我们应用程序的服务器将使用这些凭证从数据库中读取数据。

我们应用程序流程的 30,000 英尺视图(图片由作者提供)。
在客户端,我们登录,检索凭证,将它们发送到我们的后端,并使用响应来更新网页(以下片段摘自我们的 index.html文件)。
注意,在 signinCallback 函数中,我们将包含 AWS 凭证的 POST 请求发送到/fruits 端点(同样,我们通过使用 HTTP 服务器简化了本演示——在生产中,您可能希望在与 HTTPS 的传输中加密此连接)。该请求将由我们基于 FastAPI 的 web 服务器处理,如下所示:
如前所述,虽然我选择了 Pythonic 实现,但 MongoDB 支持许多编程语言的驱动程序,因此您可能更喜欢用 Go、Node.js 或 Rust 构建可伸缩的服务器。

我们劳动的“成果”:一个简单,但个性化和安全的应用程序(图片由作者提供)。
现在你知道了!虽然这只是一个简单的演示,但是可以轻松地扩展该基础设施,以支持其他身份提供者或其他 AWS 资源。
完整的示例代码可以在我的 Github 页面上找到。
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详*我们的 读者术语 。
参考
[1]“欢迎使用 MongoDB 文档— MongoDB 文档。”https://docs.mongodb.com/(2021 年 7 月 28 日访问)。
[2]“将 Google Sign-In 集成到您的 web 应用中。”https://developers.google.com/identity/sign-in/web/sign-in(2021 年 7 月 28 日访问)。
用 Plotly Python 构建专业条形图的教程
原文:https://towardsdatascience.com/tutorial-on-building-a-professional-bar-graph-in-plotly-python-ba8e63fda048?source=collection_archive---------9-----------------------
实践教程
创建高质量条形图的分步指南

本教程的最终图形迭代|作者图片
作为我上一篇文章“关于用 Plotly Python 构建专业散点图的教程”的续篇,我已经用 Python 编写了另一个 Plotly 教程,介绍如何构建一个视觉上令人惊叹的条形图。
本文旨在将 Python 中的 Plotly 图形提升到一个新的水*,假设您已经对这种语言有所熟悉。我将应用一种逐步迭代的方法来帮助简化这个过程。如果你想提高视觉效果,请继续阅读。
我将使用的数据集是巴基斯坦的电子商务销售额。您可以从 Kaggle 或我的 Git 库下载数据,以及本教程的其余代码。注意:从 Kaggle 版本中删除了缺少值的行,以便上传到 Github。
我们将逐步完成同一图表的六个不同版本。从 Plotly 提供的最基本的图表开始,到最后完全定制和注释的图表。我将解释每一步的基本变化。
在我们开始编码之前
值得一提的是 Plotly 是如何组成它的图形对象的。一种简单的思考方式是描绘由四层构成的图表。
- 层 1-创建一个空白图形对象。
- 第 2 层-添加并自定义您的数据点。
- 第 3 层—定制您的视觉效果。
- 第 4 层—注释您的视觉效果。
当可视化数据时,理解我们想对数据提出什么问题总是至关重要的(假设我们正在进行解释性分析而不是探索性分析)。
我们想从数据集中找出的问题是:
2018 年第三季度,哪个品类同比增长最大,是什么推动了这一增长?
索引
- 第一步:数据操作
- 第二步:创建标准条形图
- 第三步:造型变化
- 第四步:展示多个指标
- 第五步:减少杂乱
- 第六步:引导读者的注意力
- 第七步:添加解说词
- 结论
步骤 1:数据操作
我们想要操作我们正在使用的数据集,这样我们就可以创建我们的初始图表。我们需要制作几个我们想要显示的变量,并过滤掉不必要的数据。说出我要添加的变量我决定去掉大量的 NA,这可能不总是最好的决定,但对于本文来说是可以接受的。
我不会解释数据操作过程,因为这本身就是一个教程,而本文主要关注在 Plotly 中创建一个条形图。然而,我在下面的代码中注释了每一步。
第 1 步:数据操作—代码|作者图片
步骤 2:创建标准条形图
对于第 1 层,用go.Figure()创建一个空白图形对象。
对于第 2 层,使用add_trace(...)添加一层数据点到你的空白画布上。这个命令是我们执行所有数据定制的地方,比如颜色、大小、透明度。
为了研究增长,我选择显示销售的绝对差异,而不是百分比。
步骤 2:创建一个标准的条形图—代码|作者图片
第二步:创建一个标准的条形图——图表|作者图片
在上面的图形中,您会注意到图形标题和轴标题丢失了。默认情况下,Plotly Graph 对象不会生成这些,因此必须显式定义它们。
第三步:改变造型
可视化数据的一个最重要的概念是突出显示您想要显示的数据点,并减少来自不太重要的元素的干扰。尽管如此,还是要清楚地标注图表中的所有特征,这样读者就不会去猜测如何解读图表。
对于这个迭代,我们将把第 3 层添加到我们的图中。我们将使用update_layout(...)自定义我们的图形框架的外观。这将是您更新除数据点之外的所有内容的地方,如标题、轴、刻度格式、网格线等。我们将使用颜色将不太重要的特征推到后面,例如轴线、轴标记标签、轴标题和绘图背景。
对于此迭代,我们将进行以下更改:
- 添加标题
- 添加轴标题
- 对类别排序
- 将轴的线条颜色从白色更改为浅灰色
- 将背景颜色改为白色
- 将图表上所有文本的颜色改为浅灰色
- 向 x 轴刻度添加货币前缀
步骤 3:样式更改—代码|作者图片
步骤 3:样式更改—图表|作者图片
我们已经按照我们想要的顺序创建了一个类别列表,从最大正方差到最大负方差,然后将它传递给类别数组参数。这可能看起来很冗长,但是我们将在下一步中引入关于补充图的其他度量。类别顺序将在每个地块中保持不变。
在上图中,您现在可以清楚地看到哪个品类同比增长最为显著。接下来,我们将找出导致这种增长的原因。
步骤 4:展示多个指标
将尽可能多的信息压缩到可视化中并不总是一个好主意。只包括额外的细节,如果它支持你想要讲述的故事。你还要考虑话题的复杂程度,受众是谁;有时候,把故事分成几个画面可能更容易。
在这种情况下,我们将通过子图在图表上显示额外的指标。这是因为它需要回答我们最初的问题,并且消息不会过于复杂。在后面的步骤中,我们将使用技巧将读者的注意力集中在重要的事情上。
在这一步,我们使用make_subplots(...)而不是go.Figure()来创建空白图。由于我们正在处理子图,我们将在数据框中创建两列来保存每个指标在每个子图中的行和列位置。然后我们使用循环for metric in df2["metric"].unique():在给定的行和列坐标为子情节中的每个指标生成一个图形。
当在 Plotly 中处理支线剧情时,我们可以选择用xaxis = dict(...)、xaxis2 = dict(...)等更新单个 x 轴。,或者用fig.update_xaxes(...)更新所有 x 轴。我们将使用前一个代码进行特定于轴的格式化,后一个代码进行所有轴通用的格式化。对于 y 轴也可以这样做。
对于此次迭代,我们将进行以下更改:
- 向图形中添加子图以显示其他指标
- 给每个支线剧情添加标题
- 将 y 轴移动到 x = 0
第 4 步:呈现多个指标—代码|作者图片
步骤 4:呈现多个指标—图表|按作者分类的图像
默认情况下,支线剧情的引入使得图表更加繁忙。有几个重要的问题凸显出来。
太多杂物
上面的图太重了,包含了重复的信息,比如第二和第三个支线剧情的图例和 y 轴。为了创建一个专业的图表,我们希望对我们纳入的元素非常有选择性。包括尽可能少的信息,这使得图表能够被理解并且仍然回答问题。
支线剧情之间断开
“物品 Ord 差异”和“*均 RSP 差异”支线剧情的加入使这个视觉信息变得复杂。这是因为与“销售差异”子情节相比,它们的规模完全不同。
减少杂乱
减少杂乱会降低读者的认知负荷,使信息更容易消化。为了帮助减少混乱,我们将在make_subplots(...)命令中设置shared_yaxes = True。
我们将通过删除“物品 Ord 差异”和“*均 RSP 差异”支线剧情来解决支线剧情之间不同比例的问题,并添加销售差异(%)指标。
我们还将把 x 轴移到图表的顶部,这样子情节标题也可以作为轴标题。这更务实,因为重点是在顶级类别。由于移动了 x 轴,我们将不得不移除支线剧情标题,这样它们就不会重叠,并使用fig.add_annotation(...)手动添加支线剧情标题。
为了用最少的代码为每个子情节添加标题,我们将创建一个数据框df_subplot_titles来保存标题、子情节 x 轴列和最小 x 轴范围。然后我们可以循环这个数据框中的每个标题,将它们添加到子情节中。
对于此次迭代,我们将进行以下更改:
- 将 x 轴移动到图表顶部
- 对于附加图,使用百分比变化而不是绝对差异
- 移除图例
- 移除重复的 y 轴
- 手动添加支线剧情标题
第五步:减少混乱——代码|作者图片
第五步:减少混乱——图表|作者图片
我们已经达到了这样一种状态,图表回答了我们最初的问题,“什么类别同比增长最大,是什么推动了这一增长?”。上面的条形图显示,手机和*板电脑的增长最为可观,这是由于*均 RSP 的增长。但是仍然有一些明显的缺陷。
支线剧情之间断开
与上一步相比,这张图中的支线剧情更加一致。但是,右侧的三个图和绝对销售差异图之间仍然存在脱节,因为它们保持在不同的比例上。
没有焦点
目前,图表中没有真正吸引读者注意力的元素。我们需要突出视觉传达的信息,这样读者就能立即知道去哪里看。
第六步:引导读者的注意力
正如“ 用数据讲故事:商业人士数据可视化指南 ,*”*中所讨论的,在读者决定是否继续阅读之前,我们有大约 3-8 秒的时间与他们交流。这意味着我们的视觉信息需要尽可能清晰。
引导读者注意力的两种简单方法是通过颜色和尺寸。我们将使用这些来解决上一步结束时讨论的两个问题。颜色将被用来突出手机和*板电脑的重要性,这是绝对销售增长最可观的类别,同时将所有其他群体推到背景。使用大小,我们可以通过使后面的条形变细来区分绝对和百分比刻度上的图。
在 Plotly Graph 对象中,没有一种简单的方法来给条形图中的各个条形着色。相反,我们需要创建两个独立的数据框。一个由蓝色的手机和*板电脑数据组成,另一个由灰色的所有剩余数据组成。在循环for metric in df3["metric"].unique():中,我们将用fig.add_trace(go.Bar(...))创建两条轨迹。对于每个指标,这段代码现在基本上将两个图形重叠在一起。
我们将使用make_subplots(...)中的column_widths = [...]命令来设置每个图的宽度,突出‘销售差异(Abs)’图。
对于此次迭代,我们将进行以下更改:
- 突出显示“手机和*板电脑”类别为蓝色,其他类别为灰色
- 拓宽“销售差异(Abs)”图
- 使百分比方差图上的条形变细
第六步:引导读者的注意力——代码|作者图片
第六步:引导读者的注意力——图表|作者图片
在这张图表中,我们通过使用颜色成功地将读者的注意力吸引到了手机和*板电脑类别的表现上。右边的三个支线剧情与最左边的支线剧情的比例不同。这很好,因为条形大小不同,表明它们显示不同的信息。
我们可以做一些小的改进来进一步改善这种视觉效果,但两个明显的增强将使图形更上一层楼。
解说
我们使用了几种技巧来引导读者关注手机和*板电脑类别的表现。为了使我们的信息尽可能简单明了,我们还应该包括注释,以准确描述我们的图表所显示的内容。这也将让我们对 avg RSP 支线剧情有更多的了解。356%的增长看起来很可疑,在商业环境中几乎肯定会受到质疑。
真知灼*标题
图表标题是图表中最有价值的不动产之一。不管读者先看哪里,他们都会在某个时候阅读标题来理解图表。如果视频中有一个突出的明确信息,那么我倾向于用标题来描述它。
第七步:添加评论
为了使你的视觉效果看起来专业,你应该在你的图表上提供评论和*解。这是第 4 层的添加,可以用add_annotation(...)来实现。
我倾向于将评论放在图表上,而不是放在图表的下面或旁边。这使得页面上有更多的空间用于你的视觉,同时,文本也更接近数据。
我们将在评论中使用颜色,新改进的标题将我们在视觉上讨论的内容联系在一起。文本和图表中的任何指标都被赋予相同的颜色,蓝色。
对于此次迭代,我们将进行以下更改:
- 更改标题,使其更具洞察力
- 为情节添加副标题
- 为视觉效果添加评论
- 更改子图/x 轴标题的文本颜色
- 更改手机和*板电脑类别标签的颜色
- 添加数据源和作者
- 修复所有文本的对齐方式
- 更改坐标轴标题和标签的大小
- 改进悬停标签的外观
第 7 步:添加注释—代码|作者图片
第 7 步:添加评论—图表|作者图片
在这个图表中,我尝试了一些新的标题,将它作为一个*解,同时也作为评论的开始,使用省略号(…)来连接标题和评论。
在这次迭代中,所有的文本大小和对齐方式的改变都让图形看起来更加整洁。添加评论和改变标题,使之更有洞察力,使这种视觉效果看起来更专业。
对我来说,这张图表完整地向读者传达了一个清晰的信息,并附有支持这一信息的评论,并围绕这一发现提供了进一步的解释。
结论
Plotly 图形对象的灵活性非常突出;到目前为止,我已经能够以我想要的方式定制任何图形。当您试图创建令人惊叹的视觉效果时,灵活性越大越好,使 Plotly 成为理想的软件包。
我发现用add_annotation(...)定制文本可能是一个费力的过程。尤其是在对齐和定位方面,但这只是一个小小的代价。
希望这篇关于用 Python 中的 Plotly 构建专业条形图的教程对你有所帮助。
使用 Plotly Python 构建专业散点图教程
原文:https://towardsdatascience.com/tutorial-on-building-professional-scatter-graphs-in-plotly-python-abe33923f557?source=collection_archive---------13-----------------------
创建高质量散射可视化的分步指南

本教程的最终图形迭代|作者图片
在过去的 7 年里,我一直从事可视化展示数据和信息的工作,在我的时间里,我遇到过一两个显示效果很差的图表。我仍然害怕回想起我在职业生涯开始时展示的视觉效果。我现在的目标是帮助别人创造美丽的视觉效果。
如果您已经对 Python 有所熟悉,本文旨在提高 Python 绘图的质量。如果你想让你的视觉效果更上一层楼,请继续阅读。
在我创造更好视觉效果的旅程上,科尔·努斯鲍默·克纳弗利克的两本书;用数据讲故事:商业人士的数据可视化指南和“用数据讲故事:让我们实践”是一个非凡的信息来源。我强烈推荐任何专业人士定期制作图表。这两本书相辅相成。他们都清楚地阐明了是什么构成了一幅引人入胜的图表,并一步一步地描述了这一过程,对每一个变化都做了解释。
在这个 Plotly 教程中,我将使用书中实践的逐步迭代方法,并专门针对 Python Plotly 定制指南。我将使用关于汽车特性的数据集,可以从我的 Git 库或 Kaggle 下载。本教程的其余代码包含在我的 Git 中。
您将浏览同一图表的六个不同版本。首先从 Plotly 提供的最基本的图表开始,最后是完全定制的带注释的图表。每一步都提供了基本变化的解释。
Plotly 有两个版本:
Plotly Express 比 Graph Objects 更容易、更快速使用的高级图形包,但功能较少。
plotly Graph Objects(GO)——一个较低级的图形包,通常需要更多的编码,因为它更容易定制。
这个图形教程将只侧重于建立一个散点图在 Plotly 图形对象。这个软件包在改变图表的任何方面提供了完全的自由,而 Plotly Express 没有。
我们想从数据集中找出的问题是:
马力和重量的关系如何因产地而异?
在你开始编码之前
值得一提的是 Plotly 是如何组成它的图形对象的。一种简单的思考方式是描绘由四层构成的图表。
- 层 1-创建一个空白图形对象。
- 第 2 层-添加数据点。
- 第 3 层—定制您的视觉效果。
- 第 4 层—注释您的视觉效果。
步骤 1:创建标准散点图
第一步,按照下面的代码实现上面的前两层。
对于第 1 层,用go.Figure()创建一个空白图形对象。
对于第 2 层,使用add_trace(...)添加一层数据点到你的空白画布上。您将在此命令中执行所有数据点定制,如颜色、大小、透明度等。对于更高级的图表,您几乎肯定需要将多个数据点图层添加到同一个图表中(稍后将详细介绍)。
汽车重量与马力代码—迭代 1 |作者图片
汽车重量与马力图—迭代 1 |作者图片
在上图中,你会注意到一些事情。Plotly 图形对象不会生成图形标题或轴标题。这些必须明确定义,这将在下一步中解释。
第二步:改变造型
可视化数据的一个最重要的概念是清楚地突出显示您显示的数据点,并减少来自不太重要的元素的干扰。例如,我通常使用白色背景绘制图,浅灰色用于轴标题和文本。
对于这个迭代,我们将对第 3 层进行样式上的修改。使用update_layout(...)来完全定制你的图形框架的外观和感觉。这将是您更新除数据点之外的所有内容的地方,如标题、轴、刻度格式、网格线等。
对于这个迭代,我们将进行以下更改:
- 添加图形标题和轴标题
- 以更好的格式放置 y 轴刻度
- 确保每个轴的测量清晰
- 将轴的线条颜色从白色更改为浅灰色
- 将背景颜色改为白色
- 将图表上所有文本的颜色改为浅灰色
- 将数据点的颜色更改为较暗的蓝色,使它们更加突出
汽车重量与马力代码—迭代 2 |作者图片
汽车重量与马力图—迭代 2 |作者图片
您还会注意到,我没有将值传递给 color 参数,而是选择在数据框上创建一个新列来保存变量。因此,我们将颜色参数转换为一个列表,并且只使用了第一个元素。这似乎是一种冗长的方法,但是当 color 列有下一步所需的许多类别时,这是一种简单得多的方法。
步骤 3:展示多个类别
在 Plotly Graph 对象中可视化类别数据不像将变量传递给显示类别的参数那样简单(Plotly Express)。相反,我们必须为我们想要分组的变量中的每个值创建单独的数据层(或轨迹),并将它们覆盖到同一个图形上。
要为汽车原点变量创建单独的分组,我们需要为以下每个值生成不同的数据点图层:美国、欧洲和亚洲。这可以通过使用 for 循环轻松实现,该循环使用for area in df["Origin"].unique():遍历每个原始列的惟一值。在每个循环中,都会创建一个新的数据帧,其中只包含一个带有df_plot = df.loc[df["Origin"] == area].copy()的类别的数据。
因为我们正在向图表中引入类别,所以我们必须将类别名称传递给 name 参数,以正确标记图例。
对于此次迭代,我们将进行以下更改:
- 根据原点变量将数据点分成不同的类别
- 为“来源”列中的每个值选择颜色
汽车重量与马力代码—迭代 3 |作者图片
汽车重量与马力图—迭代 3 |作者图片
这张图看起来很繁忙,尤其是在左下象限。我们将在下一次迭代中解决这个问题,将每个类别显示在它自己的子图上。
第四步:为每个类别创建一个支线剧情
目前,区分每个类别的趋势并不容易。我们将创建一个子情节,这意味着我们必须将 x 轴和 y 轴变量传递给update_xaxes(...)和update_yaxes(...),而不是update_layout(...)。这是因为现在有三个 x 轴和三个 y 轴,而我们之前的代码只更新了一个 x & y 对。或者,我们可以用xaxis2 = dict(...)、yaxis2 = dict(...)等更新每个单独的轴。
对于这个迭代,我们将进行以下更改:
- 在原点中为每个类别创建一个支线剧情
汽车重量与马力代码—迭代 4 |作者图片
汽车重量与马力图—迭代 4 |作者图片
图表现在太忙了,坐标轴标题和轴线把注意力从数据上转移开了。为了创造一个专业的视觉效果,我们需要大大减少混乱。
第五步:减少杂乱
"简单是最高级的复杂。"
-莱昂纳多·达芬奇
减少杂乱会降低读者的认知负荷,使信息更容易消化。
如果你要定制你的标题和轴标题,那么最好通过add_annotation(...)来添加。我发现自己通常使用这种方法来创建 x 轴和 y 轴标题,因为它可以完全控制文本的位置、对齐方式、颜色和大小。
我们将只在make_subplots(...)命令中设置shared_yaxes = True,因为只有沿着同一轴的支线剧情可以共享,而不是所有支线剧情。为了克服这个问题,我们在update_xaxes(...)命令中固定 x 轴范围。
我们将删除图例,因为添加了支线剧情标题,这些信息是多余的。我尽量避免使用图例,而是在图上标出类别。如果做得正确,这就减少了读者对你视觉上的类别进行解码的需要。
对于此次迭代,我们将进行以下更改:
- 移除图例
- 移除重复的轴标题
- 移除轴线
- 确保所有子图显示两个坐标轴的一致范围
汽车重量与马力代码—迭代 5 |作者图片
汽车重量与马力图—迭代 5 |作者图片
剧情现在清晰了很多,看起来也更专业了。我们很容易看到 origin 中每个类别的趋势;然而,确定与整个样本相关的趋势是具有挑战性的。我们将在下一次迭代中解决这个问题,并在图表上提供一些注释,以便读者更好地理解信息。
第六步:添加评论
为了让你的视觉效果更上一层楼,你还应该用add_annotation(...)为你的图表提供评论和*解。
大部分附加代码是为了在每个子情节上面生成评论。通过在图表上添加注释,我们可以清楚地显示出每条真知灼*指的是哪个子图,并通过将关键文本与具有相同颜色的数据点联系起来来显示。这使得数据更容易阅读,因为他们不必经常在注释和图表之间寻找。
所有数据点都已添加到每个子图中,并通过颜色和透明度推到背景中,只有一个来源类别的数据点高亮显示。当您想要显示单个类别的趋势以及它们与整个数据集的关系时,这是在散点图中使用的一种强大的技术。
我们还引入了一条最佳拟合线,为图表提供了一些关于汽车重量和马力之间关系的额外背景。
对于此次迭代,我们将进行以下更改:
- 将所有数据点添加到每个子图中
- 为每个图添加注释,以便更深入地了解数据
- 修复悬停信息标签(对于交互式版本)
- 让标题看起来更好
- 减小坐标轴刻度的字体大小
- 添加最佳拟合线
汽车重量与马力代码—迭代 6 |作者图片
汽车重量与马力图—迭代 6 |作者图片
在这个图的最后一次迭代中增加了很多东西,但是最终版本感觉很干净,同时显示了很多信息。
结论
从最后一次迭代的代码长度可以看出,Plotly Graph Objects 是一个冗长的包。创造令人惊叹的视觉效果比使用现成的图形要花更多的时间。
如果你想要一个快速团队会议的图表,那么这不是要走的路线。然而,如果你要向利益相关者、高级经理或一大群人展示,并希望以尽可能清晰的方式传达你的信息,我强烈推荐这个包。制作漂亮的视觉效果是最好的方法之一。
希望这篇关于用 Python 中的 Plotly 构建专业图形的教程对你有所帮助。
在 Python HTML 中显示 SHAP 力图的教程
原文:https://towardsdatascience.com/tutorial-on-displaying-shap-force-plots-in-python-html-4883aeb0ee7c?source=collection_archive---------7-----------------------
使用 Flask 在网络上绘制 SHAP 力图
这里是本教程的源代码,这样你就可以跟着做了,你可以运行app.py来查看结果。
这样做的动机
SHAP 图对于模型的可解释性非常有用(*这里有一个关于它们的精彩演讲)。
作为最近使用 SHAP 显示英雄联盟数据的逻辑回归项目的一部分(你可以在这里看到项目 web 应用和下面的截图),我努力寻找一种在页面加载中显示 SHAP 图的方法,而不必先保存图像。我非常*惯于在笔记本或类似的东西上使用 SHAP 的绘图,但我真的想在网络应用程序上显示它。
由于这对我来说是一个很大的痛点,我想巩固我所学到的东西,并在这里写下来。我将介绍我在尝试base64、plt.savefig()时遇到的一些问题,以及这些方法的问题,最后我将介绍使用 HTML iFrames 的解决方案。
为了直观显示这一结果,最终结果示例是在 Flask web 应用程序中显示 SHAP 力图:

将力图动态合并到用户界面中(您可以在源上搜索“100 Closer”查看相同内容)
方法 1: Base64 编码
Base64 是一种二进制到文本的编码方法。使用这个,我们可以定义我们的force_plot并使用plt.savefig()将它存储在变量buf中,稍后我们可以将它解码为 ASCII。在我看来,理解其功能并不重要,但是结果是你的电脑会保存每一张单独的图片,然后以 HTML 格式显示出来。这意味着您的img标签的src变量将必须在本地定位每个保存的图像。
使用 XGBoost 的 Base64 编码示例
"""
Example implementation of XGBoost algorithm and base64 approach to save the SHAP force plot and later display in HTML.If you're doing this in Flask, the ML is in app.py and you pass the SHAP force plot as a *variable* which you can index in your HTML page."""#Train test split#Let's assume you have some X_, y_...Xt, Xv, yt, yv = train_test_split(X_,y_, test_size=0.2, random_state=10)dt = xgb.DMatrix(Xt, label=yt.values, enable_categorical=True)
dv = xgb.DMatrix(Xv, label=yv.values)#Tuned hyperparameters via hyperopt Bayesian optimization
params = {
"eta": 0.5,
"max_depth": 8,
"min_child_weight": 1,
"objective": "binary:logistic",
"verbosity": 0,
"base_score": np.mean(yt),
"eval_metric": "logloss",
"colsample_bytree": 0.7434869381604485,
'gamma': 1.1053886968419446,
'reg_alpha': 49.0,
'reg_lambda': 0.9997899615065826
}#Run model
model = xgb.train(params, dt, 35, [(dt, "train"), (dv, "valid")], early_stopping_rounds=5, verbose_eval=35)#SHAP explainer values (NumPy array)
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(Xv)#The SHAP *force* plot itself (using this method, I think you can
#also do Beeswarm plots but I have not tried it)shap_plot = shap.force_plot(explainer.expected_value,
shap_values[-1:], features=Xv.iloc[-1:],
feature_names=Xv.columns[0:20],
matplotlib=True, show=False, plot_cmap=['#77dd77', '#f99191'])#Encode into base64,
#Answer inspiration: [https://stackoverflow.com/questions/60621103/is-there-a-way-to-render-shap-or-lime-output-from-flask-to-react/60669449#60669449](https://stackoverflow.com/questions/60621103/is-there-a-way-to-render-shap-or-lime-output-from-flask-to-react/60669449#60669449)buf = BytesIO()
plt.savefig(buf,
format = "png",
dpi = 150,
bbox_inches = 'tight')
dataToTake = base64.b64encode(buf.getbuffer()).decode("ascii")
return dataToTake#Example HTML integration
<img class="xgboost_image" src="data:image/png;base64">
这种方法的问题
虽然这对于单个图的生成很方便,但在生产环境中是不可行的,因为这意味着您将保存每个图。
方法 2: plt.savefig()
使用plt.savefig()我们缩短了工作时间(Base64 并不是完全必要的),但结果是一样的,必须保存每个力图,并在我们的<img src="wherever_the_plot_is_locally">标签中将其索引为一个文件。
#Just using the same XGBoost model from above def shap_plot(ind):
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(Xv)
p = shap.force_plot(explainer.expected_value, shap_values[ind], Xv.iloc[[ind]])
plt.savefig('temp.svg')
plt.close()
return pshap_plot(3)
是的,更容易理解,但是在生产环境中同样不可用:您仍然保存每个图像。
方法 3:使用。html()选项(我最终使用的)
通过这种方法,我们利用了 HTML iFrames ,它可以将我们的 SHAP force_plot嵌入到我们的主 HTML 中。
#works in Dash
#taken from here: [https://stackoverflow.com/questions/54292226/putting-html-output-from-shap-into-the-dash-output-layout-callback](https://stackoverflow.com/questions/54292226/putting-html-output-from-shap-into-the-dash-output-layout-callback)def _force_plot_html(*args):
force_plot = shap.force_plot(*args, matplotlib=False)
shap_html = f"<head>{shap.getjs()}</head><body>{force_plot.html()}</body>"
return html.Iframe(srcDoc=shap_html,
style={"width": "100%", "height": "200px",
"border": 0})
这并不完全翻译成我所使用的,虽然,这是烧瓶。我把上面的想法用在一个烧瓶的环境中:
集成到 Flask web 应用程序的示例:
让我们假设您有这样一个逻辑回归模型:
Xt, Xv, yt, yv = train_test_split(X_, y_, test_size=0.2, random_state=10)model = LogisticRegression(penalty='l2', solver='liblinear', max_iter=900, C=0.1).fit(Xt, yt)explainer = shap.Explainer(model, Xt, feature_names=Xt.columns)
shap_values = explainer(Xv)
基本思想是在app.py中创建一个_force_plot_html函数,该函数使用explainer、shap_values和ind输入返回一个shap_html srcdoc。我们将使用render_template将那个shap_html变量传递给我们的 HTML,并且在 HTML 文件本身中,我们将在一个嵌入式 iFrame 中显示shap_html。
这是一个我们循环遍历ind的例子,创建各种 SHAP 图,并在我们的 HTML 中显示为 iFrames。
#in app.pyfrom flask import *import shap
from shap.plots._force_matplotlib import draw_additive_plotfrom model import give_shap_plotapp = Flask(__name__)[@app](http://twitter.com/app).route('/')def displayshap(): explainer, shap_values = give_shap_plot() def _force_plot_html(explainer, shap_values, ind):
force_plot = shap.plots.force(shap_values[ind],
matplotlib=False)
shap_html = f"<head>{shap.getjs()}</head><body>{force_plot.html()}</body>"
return shap_html shap_plots = {} for i in range(10): #how many plots you want
ind = i
shap_plots[i] = _force_plot_html(explainer, shap_values, ind)
return render_template('displayshap.html', shap_plots = shap_plots)if __name__ == '__main__':
app.run()#EXIT app.py
###<!-- HTML -->
<!-- in displayshap.html -->{% for i in shap_plots: %}
<iframe srcdoc="{{shap_plots[i]}}" style={"width": "2000px"; "height": "200px"; border: none;} ></iframe>
{% endfor %}
shap.getjs()非常重要,因为如果没有它,你的 HTML 就会出现“可视化被忽略,Javascript 库没有被加载!问题。

这篇博文的教程存储库的示例结果。运行逻辑回归的代码是从 SHAP 的文档“用逻辑回归进行情感分析”中借用的。你也可以得到同样的悬停效果,所有的 javascript 都被保留下来。
缺点
这种解决方案的一些缺点是只对力图有效。
- 我无法得到这样的蜂群/条形图:
#TYPES OF PLOTS THAT WORK:
force_plot = shap.plots.force(shap_values[ind], matplotlib=False)#TYPES OF PLOTS THAT DO NOT WORK:
force_plot = shap.plots.beeswarm(shap_values)
force_plot = shap.plots.bar(shap_values[ind])#I think no .html() method is written for these? I'm not quite sure
谢谢你
感谢您的阅读!我希望这对任何想将 SHAP 集成到 web 应用程序中的人有所帮助。你可以在这里找到这个教程的源代码。
你可以在我的网站、 LinkedIn 或 github 上找到我。你可以在这里阅读更多我的文章。
表面裂纹分类及直观解释教程(一)
原文:https://towardsdatascience.com/tutorial-on-surface-crack-classification-with-visual-explanation-part-1-14542d2ea7ac?source=collection_archive---------19-----------------------
用 Pytorch 开发可解释的人工智能对表面裂纹图像进行分类的分步指南。这是 2 部分系列的第 1 部分。
简介
我们处在人工智能时代。许多技术的发展使工程师的生活变得更加轻松。然而,土木工程领域似乎仍在努力跟上这一发展的步伐。
基础设施迅速恶化,接近其设计寿命。因为基础设施经常在恶劣的环境中运行。例如,在道路和桥梁上有持续的负载和振动。此外,还有多种灾害,如地震、洪水、飓风、龙卷风或海啸一年到头都会发生。如果只考虑美国的桥梁,全国桥梁库存中有 60 多万座公路桥。39%超过了 50 年的设计寿命。国家桥梁检查标准要求桥梁每两年检查一次,以确保没有裂缝、生锈或其他损坏。这意味着,每天都有数百座桥梁需要检查。当前的基础设施检查系统存在许多问题。例如,数据收集非常耗时,可能需要使用许多重型设备进行危险的野外活动。有时,对于高架桥梁结构来说,可达性是一个问题。此外,人类视觉检查可能存在偏*。因此,视觉检查的结果在不同的检查员之间会有很大的不同。
一种可能的解决方案是使用机器人*台来收集检查视频数据。使用空中*台收集检查视频数据减少或消除了劳动密集型的现场检查过程,并允许检查员从更安全的位置评估桥梁。

照片由雅各布·欧文斯在 Unsplash 上拍摄
然而,机器人检测*台的使用仅仅解决了上述问题的一部分,高效、可靠的检测视频分析是另一项重要任务。让检查员观看收集的视频几个小时甚至几天来寻找漏洞是低效的。希望能够开发一种工具来帮助检查员从视频或图像中提取不同类型的裂纹。
为了自动化这个检查过程,本文将使用人工智能对图像进行分类,以找到图像中的裂缝。更具体地说,我们将使用 Pytorch 建立和训练一个深度神经网络来寻找图像中的裂缝,以取代人类对结构中的裂缝进行分类的繁琐任务。
好了,今天的动力足够了。现在,让我们直奔主题。我们要做以下三件事:
- 使用 PyTorch 从头开始创建深度神经网络
- 实现一个可解释的人工智能工具来解释深度神经网络做出的决定
为了不把博客写得太长,我把上面的两个内容分成了两个系列。这是这个系列的第一部分。另一部分的链接在这个博客的末尾。
1。深度神经网络与 Pytorch
现在,让我们使用 PyTorch 创建一个深度神经网络。我将向您展示创建用于图像分类的深度神经网络的所有步骤。作为一个应用程序,我将对图像中的表面裂纹进行分类。阅读完博客后,你将能够使用与本文相同的步骤,为你选择的任何不同应用领域进行图像分类。所以请原谅我。
要创建分类器,我们将遵循 4 个步骤:
- 数据准备
- 构建模型
- 培养
- 测试和推理
数据准备
首先,我们要为我们的分类准备一个数据集。正如我已经提到的,我们将从图像中对表面裂缝进行分类,我们将使用裂缝数据集。我们将使用 Mendeley [1] (License: CC BY 4.0)数据集的子集。你可以从这个链接下载数据集。如果你愿意,你可以从他们的网站上下载,直接使用门德利数据集。

阳性门德利[1]数据。图片作者。
无论如何,我们将使用这个数据集的小子集,因为我们的主要目标是建立一个神经网络。该数据集总共有 1200 张(600 张正片+ 600 张底片)大小为 227 x 227 的图像。然后将其分成 80%训练数据和 20%测试数据。请下载数据集,并将其放在您的工作目录中。最初的文件夹结构将是这样的,蓝色的是文件夹,白色的是文件(我们稍后会添加更多的文件和文件夹)。

文件夹结构。图片作者。
为了加载数据,我们将创建一个名为“dataloader.py”的 python 文件,如您在“src”文件夹中所*。
首先,我们需要导入一些必需的包:
torch.utils.data 导入创建和使用数据集和数据加载器所需的函数。
PIL 是一个流行的计算机视觉库,用于在我们的 python 程序中加载图像。
现在让我们创建一个自定义数据集类,我们将该类命名为 CrackDataset。
**类 crack Dataset(Dataset):**创建一个名为‘crack Dataset’的类。我们可以在任何地方调用这个类。它将被传递给我们之前导入的“数据集”模块。
def init(self,data_path,phase,transform): 初始化类后我们需要传递三个变量。data_path 是我们数据集的目录。我们将通过阶段=训练或测试。转换来执行输入数据转换。当我们将这些信息传递给我们的类 CrackDataset 时,我们将对此进行更多的讨论。我们创建一个名为 self.data 的列表,其中包含图像路径对及其各自的标签。我们还希望将所有负类映射为 0,正类映射为 1。
def len(self): 该函数返回标签的长度。
****def getitem(self,idx):**py torch 的数据集模块使用该函数获取样本并构造数据集。初始化时,它将循环通过该函数,从数据集中的每个实例创建一个样本。它定义了(x,y)或(图像,标签)对。pytorch 内部使用 Index (idx)来跟踪所有数据并创建批处理。它还跟踪所有的批次。简单地说,它负责我们定制数据集的所有簿记工作。这里,self.data 是包含图像路径及其类名的列表。对于每个索引,我们将有一对 img_path 和 class_name。然后使用 PIL 图书馆,我们加载图像,并将其转换为 RGB 格式。之后,我们使用 self.transform 将图像转换为张量和其他一些东西(稍后你会看到我们将使用什么转换)。PyTorch 损失函数的一个要求是,在馈送到 CNN 网络之前,输入必须是张量形式,所以我们将其转换为浮点和张量。
现在,我们已经创建了自定义的数据加载器。编译文件“dataloader.py”中的所有代码,并将该文件放在文件夹“src”中。
构建模型
现在,让我们在 model.py 文件中创建我们的模型,并将其放在“src”文件夹中。
我们将使用迁移学*。你可能知道迁移学*。这是一种技术,我们使用预先训练的模型,这些模型已经在大型数据集上进行了训练。我们将使用训练过的重量来开始我们的训练。我们唯一要做的事情是,我们需要修改模型的最后几层,并且只更新这些层的权重。
Torchvision 有许多内置的 CNN 模型,如 VGG16、ResNet、Inception 等等。我们只需要导入它们。这里我们要用 ResNet 架构。
我们将创建一个名为 CrackClassifier 的类。它将使用 nn。PyTorch 的模块。self.resnet 将从 torchvision 下载预训练的 resnet50 模型。从代码中可以看出,我们修改了 self.resnet.fc,依次添加了两个线性图层一个 ReLU 和一个 LogSoftmax。您可以看到,在最后一个线性图层中,我们将输入要素映射到 num_classes。这意味着我们的输出节点将等于我们的类的数量。如果您想使用自己的 CNN 架构,只需用它替换 self.resnet 即可。
def forward 函数定义了我们的模型在接受输入后将如何运行。这里,在我们的例子中,它将接受输入特征(x ),并将通过我们已经定义的 self.resnet。
训练网络
我们将创建一个名为 train.py 的文件,并将其保存在主目录中,如图文件夹结构所示。首先,让我们导入所需的库:
如果你看看代码,从第 1–4 行我们从 torch 导入了一些我们以前*过的库。在第 6 行和第 7 行,注意我们使用了“来自 src.model”和“src.dataloader”。请记住,在“src”文件夹中,我们已经创建了两个 python 文件 model 和 dataloader。我们将分别从这两个文件中导入 class CrackClassifier 和 class CrackDataset。在第 8 行中,我们导入了 tqdm,它将用于显示训练进度。操作系统模块将用于定义目录。我们将使用 tensorboardX 的 SummaryWriter 来可视化我们的培训和测试性能。第 12 行确保如果我们有 GPU,那么它将使用 GPU,否则将使用 CPU 进行计算。
torchvision.transform 库帮助我们对输入图像进行大量处理。例如,这里的 Resize 选项确保我们所有的图像都是 64 x 64 的。然后,我们使用 to tensor 选项将图像转换为张量。最后,我们归一化图像。这里,在归一化选项中,第一个元组是*均值,第二个元组是所有批次的三个 RGB 通道的标准偏差。您还可以在这里使用不同的数据扩充技术。
接下来,我们需要为我们的训练定义超参数。例如,时期数、学*率、批量大小。之后,我们需要设置数据集和数据加载器。对于训练和测试,我们使用 CrackDataset 类分别设置两个数据集。设置完这两个数据集后,我们使用 pytorch 的数据加载器来创建我们的训练和测试数据加载器,分别命名为 train_dataloader 和 test_dataloader。
现在,在我们进入训练循环之前,首先创建一个函数来检查我们模型的准确性。我们将调用训练循环中的函数来检查测试数据集的准确性。
使用我们的模型,我们将得到输出,该输出将与该图像的地面真实标签进行比较,以计算准确性。这非常简单,看代码就能很容易理解,所以我跳过了详细的解释。
现在我们将创建两个更简单的函数来使用 tensorboard 的 summary writer。这样我们可以用图表的形式直观地显示每个时期的损失和精度。
现在,让我们创建一个训练循环:
从第 2–8 行,创建我们的目录来保存训练好的模型和我们的日志。第 9 行在我们的日志目录中创建了一个摘要编写器。
第 11 行,使用我们创建的名为 CrackClassifier 的类来创建我们的模型。标准是损失函数。我们将使用 pytorch 模块 nn 中的 CrossEntropyLoss 函数。然后,我们定义优化器,使用梯度下降优化网络。我们使用 torch.optim 中流行的 Adam 优化器。
回想一下,我们的模型中有两个完全连接的层。我们只想更新这两层的权重。我们可以冻结其余层的权重。第 16–22 行将为我们做这些。我们的 fc.0 和 fc.2 是两个完全连接的层。我们希望更新这两层的权重和偏差项。因此,对于这两个层,我们设置 param.requires_grad= True。对于其余的层,它是假的。那就是我们冻结了其余的层。
第 24 行开始训练。然后我们循环遍历历元数。对于每个时期,我们在训练装载器中迭代所有批次的图像和标签。在每两个时期之后,我们使用 test_loader 检查测试数据集的准确性,并使用我们之前创建的 write_test_scalars()函数将准确性写入记录器。我们使用模型的输出,并使用预定义的损失函数计算损失。在我们进行反向传播以计算梯度之前,我们必须执行 optimizer.zero_grad()操作——这将清空前一批的梯度张量,以便重新计算新一批的梯度。现在,为了执行反向传播,我们使用 loss.backward()。注意,我们使用了 tqdm。这用于通过进度条显示训练进度。然后使用 write_scalars()函数,我们写下每个时期的损失。当测试数据集上的精确度最高时,我们保存模型。最后,我们使用 logger.close()关闭摘要编写器。
现在,我们已经准备好了所有的代码。我们需要运行代码。要运行训练代码,在您的终端上键入:“python train.py”。它将训练网络,将训练好的模型保存在“快照”中,并将日志保存在“日志”文件夹中。
要可视化您的 tensorboard,请在您的终端上键入以下内容:
之后,进入你的浏览器,在地址栏输入:“localhost:6006”。然后,您可以在 tensorboard 中看到您的训练表现,如下所示:

作者图片
看,我们模型的性能逐渐提高。
结论
在这一部分中,您已经了解了如何创建自定义数据加载器,如何使用迁移学*构建 CNN 模型,如何训练网络,以及如何使用 tensorboard 记录训练表现。在下一部分中,我们将看到如何使用我们训练好的模型来预测不同图像上的裂缝类别。这意味着我们将使用训练好的模型进行推理。最后,我们将使用 grad-cam 工具来解释我们网络的决策。请点击查看本博客的下一部分。
你可以在 Github 中找到完整的代码。下载数据集。
参考资料:
- 奥兹杰内尔,恰拉尔·弗拉特(2019),“用于分类的混凝土裂缝图像”,门德利数据,V2,doi: 10.17632/5y9wdsg2zt.2。(许可:CC BY 4.0)
表面裂纹分类及直观解释教程(二)
原文:https://towardsdatascience.com/tutorial-on-surface-crack-classification-with-visual-explanation-part-2-f8638960d0d7?source=collection_archive---------15-----------------------
用 Pytorch 开发可解释的人工智能对表面裂纹图像进行分类的分步指南。这是两部分系列的第二部分。
在上一部分( Part 1 )中,您已经看到了如何使用迁移学*建立 CNN 模型以及如何训练网络。你看到了我们的网络可以很好地对裂纹图像进行分类。但是你可能会有疑问——我们的网络是如何做出决策的?我们的网络是否看到了图像的正确位置来做出决定?我们对此没有把握。我们的网络对我们来说是一个黑匣子。我们不知道我们的卷积神经网络在做出决策时看到和理解了什么。
在这篇博客中,我们将制作直观的解释热图,帮助我们理解我们的深度卷积神经网络算法是如何决定图像中是否有裂缝的。
在前面的部分(第一部分,你没有看到如何可视化的预测结果。因此,在这一部分,我将做以下工作:
- 使用我们训练好的网络(推理)预测不同图像上的裂缝类别
- 使用 Grad-CAM [1]生成直观的解释热图,可以解释我们网络的决策

图片作者。
1。推理
我们已经在第一部分中训练了我们的网络。现在我们只需要看看用我们训练好的网络预测一幅图像是什么样子。为了预测一个图像破解类,我们需要创建一个名为 inference.py 的 python 文件,并将其保存在工作目录中。
如果你看上面的代码,你可能会发现这部分和训练文件非常相似。在这里,我们导入了我们为培训导入的相同库。导入库之后,我们将创建帮助我们进行推理的助手函数。
我们将从验证数据目录中随机选择一些样本进行预测。在第 7 行,我们创建了一个名为 random_image() 的函数。在第 17 行,我们还创建了另一个名为 save_image() 的函数,将输出结果保存在磁盘中。
所以,我们已经准备好了我们的助手函数。现在我们需要一个函数,它获取输入图像,然后通过我们训练好的网络给出预测结果。为此,我们将创建一个名为*推论()*的函数。
在上面的代码中,第 2 行是我们的测试数据集的目录。在我们的测试目录中,有两个子文件夹:正和负。我们可以从阳性或阴性文件夹中提取测试样本。在第 3 行,我们定义了从哪里选择我们的测试样本图像。请注意,在第 3 行中,有一个参数 p.type 传递了这个关于正或负文件夹的信息。此时请看第 25 行,我们调用了一个 ArgumentParser() 。当给出 bash 命令时,这个函数将传递一个参数。在第 26 行,我们添加了一个参数类型*。这意味着我们要将信息类型传递给 bash。默认情况下,信息是正。然后我们在第 28 行将这个解析器参数命名为 p 。这意味着 p 保存着类型的信息。在型内,有信息正。当您在命令行提示符/bash 中运行一个命令时,您会更清楚。好了,现在让我们回到函数*推论()。剩下的很简单,第 7–9 行,我们编译了我们的模型并加载了训练好的重量。然后,在第 11 行,我们用之前创建的辅助函数 random_image() 创建了一个随机图像列表。在第 14 行,我们转换了我们的测试图像,并堆叠在一起以通过我们的模型。对于第 16 行,我们将图像传递给我们的模型,并获得我们的预测 logit。下一行为测试图像创建一个 softmax 概率。现在我们已经有了预测概率。然后我们将保存第 20 行的结果。
我们完成了可视化预测结果的编码。要运行代码,请在终端中输入以下命令。它将从阳性文件夹中提取 9 个样本,产生结果,并将其保存在您的磁盘中。
注意,我们输入类型为阳性。因此,它从文件夹中取出样品的正面。如果我们将类型输入为阴性,它将从文件夹阴性中提取样本。
当您运行该命令时,您将得到类似下图的内容。这是一个由 9 幅图像组成的网格,这些图像已经通过了我们的网络。预测概率在每个图像的顶部。结果还可以,但是你可以通过采用迁移学*轻松提高成绩。

可视化预测结果。作者图片
2。视觉解释
现在,我们将生成直观的解释热图。为了生成热图,我们将使用 Grad-CAM[1]算法。热图确定了影响网络决策的图像区域。如果我们看看热图,我们可以很容易地理解哪些图像像素有助于网络的决策。
要使用 grad-cam,请在您的终端中键入以下内容,以便在您的本地计算机中安装 grad-cam:
现在,从这个 github 库中,下载文件夹 pytorch_grad_cam 并把它放到你的工作目录中。你可以看到,文件夹里有 grad-cam 不同版本的源代码。一旦你把这个文件夹保存在你的目录中,你就可以使用 grad-cam 和它的一些变种算法了。
现在你可以使用 grad-cam 生成热图了。此时,你需要在主工作目录下创建一个 python 文件 xai.py 。
在 xai.py 中,首先让我们导入所需的库和我们的模型:
然后,我们需要导入 grad-cam 库:
在上面的代码中,请注意我们从文件夹 pytorch_grad_cam 中导入了 Grad-CAM 及其不同的变体。我们还导入了一些用于图像可视化的包。
上面的部分非常简单。在第 6 行,我们将所有导入的方法名保存在一个字典中。稍后我们可以从这里调用任何方法来生成热图。第 19 行是我们随机图像选择的辅助函数。
然后,我们需要创建主包装函数 xai() 来生成热图。
在第 2–4 行,我们编译了模型并加载了训练好的重量。我们需要选择一个目标层,从那里梯度将被用来产生热图。通过第 6 行,我们设置了卷积神经网络的目标层,这是我们架构中 ResNet 的最后一层。
我们还需要一个目标类别来生成热图。我们只有两节课。对于负类,我们的目标类别是 0,对于正类,它是 1。我们在第 13–16 行定义了这些。
然后我们需要选择一个我们想要使用的 grad-cam 方法。我们在第 18 行这样做,然后在第 19 行结束。然后在第 22 行,我们使用我们选择的方法循环遍历我们的图像来创建热图。
要运行代码,您需要在终端中键入以下内容:
这里,注意我们给出了两个参数,一个是类型,另一个是方法。使用类型我们从测试数据集中选择阳性样本,使用方法我们为热图生成设定一种方法。这里,我们将 gradcam 设置为我们的方法。您可以选择任何其他方法,例如 Xgrad-cam、Eigen-cam 等。也是。
如果您运行该命令,您将得到类似下图的内容。这是一个包含 9 幅热图图像的网格。这里,热区表示它们负责网络的正类决策。

正类热图。作者图片
如果你看这些图像,你可以看到热区与图像中的裂缝重叠。这意味着我们的网络正在正确地寻找正确的位置,即裂缝的位置,以做出决定。
结论
在这一部分中,您已经看到了如何使用训练好的模型来预测不同图像上的裂缝类别。您还了解了如何使用 grad-cam 工具生成热图来解释网络决策。看着热图,你很容易理解你的深度学*算法是如何做出决策的。您可以很容易地扩展这个示例,并在任何图像分类问题中使用它来解释您的网络的决策。
你可以在 Github 中找到完整的代码。如果你还没有看前面的部分,在这里找到它。
参考资料:
[1] Ramprasaath R. Selvaraju 等人,2019,“Grad-CAM:通过基于梯度的定位从深度网络进行视觉解释”,【https://arxiv.org/pdf/1610.02391.pdf
教程:在 Docker 容器中运行 PySpark
原文:https://towardsdatascience.com/tutorial-running-pyspark-inside-docker-containers-84970d12b20e?source=collection_archive---------15-----------------------

由 Unsplash 拍摄的图像
在本文中,我们将向您展示如何开始在 Docker 容器中运行 PySpark 应用程序,通过一步一步的教程和代码示例(参* github repo )。
在 Docker 容器中运行 Spark 应用程序有多种动机(我们在之前的文章 Spark & Docker 中讨论过——您的开发工作流程刚刚快了 10 倍 ):
- Docker 容器简化了依赖项的打包和管理,如外部 java 库(jar)或 python 库,它们可以帮助处理数据或连接到外部数据存储。添加或升级库可能会中断您的管道(例如,由于冲突)。使用 Docker 意味着您可以在开发时在本地捕获这个错误,修复它,然后发布您的映像,并且确信无论代码在哪里运行,jar 和环境都是相同的。
- Docker 容器也是在集群(例如一个 Kubernetes 集群)上大规模运行 Spark 代码之前,在本地开发和测试 Spark 代码的好方法。
注意:我们维护着一系列 Docker 映像,这些映像内置了一系列有用的库,如数据湖、数据仓库、流数据源等的数据连接器。你可以在这里阅读关于这些图片的更多信息,并在 Dockerhub 上免费下载。
在本教程中,我们将带您完成从我们的一个基础映像构建一个新的 Docker 映像的过程,添加新的依赖项,并通过使用考拉库和将一些数据写入 postgres 数据库来测试您已经安装的功能。
Requirements
为了这个演示的目的,我们将创建一个简单的 PySpark 应用程序,它从公共数据集中读取每个国家的人口密度数据—https://registry.opendata.aws/dataforgood-fb-hrsl,应用转换来找到人口中值,并将结果写入 postgres 实例。为了找到中间值,我们将利用熊猫 API 的 Spark 实现考拉。
从 Spark 3.2+开始,熊猫库将自动与开源的 Spark 捆绑。在本教程中,我们使用的是 Spark 3.1,但在未来你不需要安装考拉,它会开箱即用。
使用 Spark 查找中间值可能非常繁琐,因此我们将利用 koalas 功能来获得一个简洁的解决方案(注意:要从公共数据源读取数据,您需要访问 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY。桶是公共的,但是 AWS 需要用户创建才能从公共桶中读取)。
如果手头没有 postgres 数据库,可以使用以下步骤在本地创建一个:
docker pull postgres
docker run -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=postgres -d -p 5432:5432 postgres
码头工人形象Building
首先,我们将使用最新的数据力学基础映像—gcr.io/datamechanics/spark:platform-3.1-latest构建我们的 Docker 映像。有几种方法可以在 Spark 应用程序中包含外部库。对于特定语言的库,您可以使用类似 python 的 pip 或 scala 的 sbt 这样的包管理器来直接安装库。或者,您可以将库 jar 下载到您的 Docker 映像中,并将 jar 移动到***/opt/spark/jars***。这两种方法可以达到相同的效果,但是某些库或包可能只能用一种方法安装。
要安装考拉,我们将使用 pip 将包直接添加到 python 环境中。标准惯例是创建一个列出所有 python 依赖项的需求文件,并使用 pip 将每个库安装到您的环境中。在您的应用程序 repo 中,创建一个名为 requirements.txt 的文件,并添加下面一行—koalas = = 1 . 8 . 1。将该文件复制到您的 Docker 映像中,并添加以下命令RUN pip 3 install-r requirements . txt。现在,您应该能够将考拉直接导入到您的 python 代码中。
接下来,我们将使用 jar 方法安装必要的 sql 驱动程序,以便 Spark 可以直接写入 postgres。首先,让我们将 postgres 驱动程序 jar 放到您的映像中。将下面一行添加到 Dockerfile 中—RUN wget【https://jdbc.postgresql.org/download/postgresql-42.2.5.jar】,并将返回的 jar 移动到***/opt/spark/jars***。当您启动 Spark 应用程序时,postgres 驱动程序将位于类路径中,您将能够成功地写入数据库。
Developing 你的应用代码
最后,我们将添加我们的应用程序代码。在上面的代码片段中,我们有一个简单的 Spark 应用程序,它从公共 bucket 源读取数据帧。接下来,我们通过对 country 列进行分组、将 population 列转换为字符串并进行聚合来转换 Spark 数据框架。然后,我们将 Spark 数据帧转换成考拉数据帧,并应用中值函数(Spark 中没有的操作)。最后,我们将考拉数据帧转换回 Spark 数据帧,并添加一个日期列,这样我们就可以利用 write.jdbc 函数将数据输出到 SQL 表中。
Monitoring 和调试
运行图像的脚本(注意,这是一个just 文件)
为了帮助在本地运行应用程序,我们已经包含了一个 justfile,其中包含一些有用的命令。
- 要在本地构建您的 Docker 映像,运行 只需构建
- 要运行 PySpark 应用程序,运行 只需运行
- 要访问 Docker 映像中的 PySpark shell,运行 just shell
也可以通过运行Docker run-it/bin/bash直接执行到 Docker 容器中。这将创建一个交互式 shell,可用于探索 Docker/Spark 环境,以及监控性能和资源利用。
结论
我们希望你觉得这个教程有用!如果你想更深入地研究这段代码,或者探索其他的应用程序演示,请访问我们的 Github 示例 repo。
股票传奇期间#gamestop 的推文分析
原文:https://towardsdatascience.com/tweet-analysis-of-gamestop-during-the-stock-saga-cc10ce6158fc?source=collection_archive---------32-----------------------
实践教程
1 月 25 日-29 日的 17 万#gamestop 推文能否让我们洞察随之而来的市场混乱?

埃隆·马斯克现在著名的《Gamestonk!!'随着时间的推移发推文|塞犍陀·维维克
1 月 26 日美国东部时间下午 4:08,埃隆·马斯克在推特上写道“Gamestonk!!"关于“华尔街赌注”的 Reddit 页面,该页面目前已有超过 900 万用户。有趣的是,这只是股市收盘后的几分钟,人们不得不怀疑马斯克是否对此进行了计时。第二天,Gamestop 的股票(纽约证券交易所代码:GME)上涨了 2.5 倍。我们知道股票市场对马斯克的反应,数据就在那里。只要谷歌一下纽约证券交易所:GME,你就会看到 Gamestop 股票每天的变化。

Gamestop 股票(纽约证券交易所:GME)1 月 25 日至 29 日的开盘价
但是我们知道马斯克的推特 实际上 是如何影响股票市场的吗,我的意思是,我们能否超越简单的相关措施,或者更糟的假设,来跟踪这种影响?朝着这个方向迈出的一步是评估马斯克的推文如何影响 Twitter 本身,特别是引用 Gamestop 的推文。好消息是,twitter 的新 API v2 比 v1 拥有更多的功能,并提供了一些优秀的数据访问,尤其是对于学术研究。
类似于本文如何围绕标签调查社交推文网络,让我们看看那段时间的 #gamestop 推文网络。
顶部的数据显示,就在股市收盘后,马斯克发推文时出现了一个小高峰。有趣的是,在 1 月 26 日下午 6-7 点左右,从几乎没有人发#gamestop 的推文到最多 1000 条引用#gamestop 的推文,有一个小的波动,然后慢慢消失。
一夜之后,在 1 月 27 日白天,有一个缓慢的上升,在上午 9 点证券交易所开盘时突然上升。可能人们在推特上回应 Gamestop 股票开盘价的大幅上涨。当天晚些时候,在 27 日结束之前,每小时有大约 3000 条推文提到#gamestop,这是一个*稳期。
28 日的涨幅甚至比 27 日还要高,尽管我们看到了股票市场的反差。Gamestop 股价 28 日开盘低于 27 日。也许 twitter 用户下了一个高风险的赌注,在最高点购买了 Gamestop 的股票,他们认为他们可以通过发 Twitter 来提高价格:)
除了我那些不成熟的假设,显然还有一些真正有趣的事情在发生。26 日,马斯克的推文在第二天提高了股价(至少大多数人是这么说的),但在 27 日和 28 日,可能发生了相反的情况——疯狂的股市引发了围绕#gamestop 的疯狂推文。
最常用的用户名
从每条推文中,可以获得用户的用户名(从@开始),以及推文中提到的任何人。在大约 17 万条推文中,有大约 13 万个独立用户发推文或被提及。让我们来看看十大常用用户名:

1 月 25 日至 1 月 29 日期间#gamestop 中最常使用的 10 个用户名|塞犍陀·维维克
令人惊讶的是,最常*的是 DonaldJTrumpJr!马斯克勉强上榜,排在第 10 位!另一种可视化的方式是通过单词云。如果你眯着眼睛看,也许能看到埃隆马斯克!

#gamestop |塞犍陀·维维克发布/提及的 1000 个常用用户名
复杂网络分析
除了简单的频率,我们可以建立引用用户名的推文网络,以建立#gamestop 图形网络,其中节点是用户,有向边表示用户通过@引用其他人。为此我使用了 python NetworkX 包。
构建图表后,您可以查看各种中心性度量,这些度量基本上根据各种标准给出了节点重要性的信息。最直观的是度中心性,其中节点的重要性基于它相对于其他节点有多少连接。对于有向图,我们使用度(指有多少条边引用用户名)作为用户名重要性,下面您会看到 10 个度数较高的中心性节点:

度中心性最高的 10 大推特用户名|塞犍陀·维维克
再一次令人惊讶的是 DonaldJTrumpJr 竟然在榜首!有可能很多用户都在引用 DonaldJTrumpJr 自己不太受欢迎。相反,让我们过滤掉图表,只包括超过一定程度(我选择 15)的流行用户名:

影响者网络中排名前 10 的推特用户名|塞犍陀·维维克
基本上,上述 10 个用户名是顶级影响者中的 10 个顶级次级影响者。有趣的是,DonaldJTrumpJr 已经不是顶级了。

#gamestop 影响者网络,使用网络绘制 X |塞犍陀·维韦克
结论和未回答的问题
在开始分析疯狂股市期间的#gamestop 推文时,我认为观察跟随股市趋势的推文数量可能会很有趣。在这种天真的假设下,我没有意识到整个场景会有多么迷人复杂。推文影响股票,股票影响推文,以及复杂的相互依赖的动态网络。以下是一些值得思考的问题:
- 为什么#gamestop 的推文在马斯克的推文之后的 27 日和 28 日出现峰值?是为了应对股市波动吗?考虑到 28 日股市本身并没有飙升,为什么 28 日比 27 日高出这么多?
- 为什么美国东部时间 28 日中午 12 点#gamestop 推文数量突然暴跌?
- 小唐纳德·特朗普在#gamestop 期间为何如此重要?
有兴趣的话,下面详细介绍一下带代码的 Google Colab 笔记本。
https://colab.research.google.com/drive/14N2_HWgoqiVb2E5tAV96RT8SAkC1WeJZ?usp=sharing
引导我的内心:我探索得越多,我就越意识到我的理解和假设是多么的贫乏。但这使得更深入地探究社会网络之间的相互依存关系变得更加有趣。
关注我 如果你喜欢这篇文章——我经常写复杂系统、物理学、数据科学和社会的界面
更好地使用 Docker 的 21 个技巧和 5 个概念
原文:https://towardsdatascience.com/twenty-one-techniques-and-five-concepts-for-better-docker-usage-9ee135dccdc9?source=collection_archive---------31-----------------------
Docker 是为你的非智能手机电脑设计的应用软件。

乔纳斯·李在 Unsplash 上的照片
起初
你已经编程几年了,你的沙箱,你的本地开发机器,被许多不同的库、框架,也许还有一两个病毒的下载搞得乱七八糟。
以上描述了我 2008 年的生活。下面的艰巨任务详细描述了我当时生活中的巨大 PIA(你要靠自己来解决这个缩写词):
- 从 Python 2.x 升级到 3.x
- 支持用 Python 2.x 编写的生产服务,即使你想升级到 Python 3.x,也不被允许;
- 将 Linux OS 服务器升级到下一个主要版本以及相关的工具、框架、服务和库层;
- 尝试一个与您当前的工具、框架、服务和库相冲突的新包;
- 需要一个现在被不同名字调用的包的依赖,或者最坏的情况是依赖不再存在;
- 损坏,可能是操作系统驱动程序,因此需要重新安装,因为重新启动没有解决问题;
- 最后但同样重要的是,我最大的 PIA(需要我去看医生)是超过五年的 Linux 服务器,它们有硬件故障、备份和/或不完整的文档,或者更糟的是,从未被验证为可重现。
我生命中最大的七个“问题”(BPIAIML)看起来像是系统管理员的待办事项清单或者 DevOps 大师的梦想成真。作为一名架构师和几个产品和项目的经理,我向你保证,它们是我需要解决的最大问题。
我们在跑之前需要先走一走。
DevOps 是未来的解决方案。—匿名
DevOps 是未来的解决方案。—匿名
我们几乎所有人都使用智能手机。让智能手机如此有价值的是名为 Apps 的应用程序。一些有用的应用程序预装在智能手机上,而其他应用程序我们免费或收取少量费用下载。
Docker 支持笔记本电脑、台式机、服务器、云和混合云上的应用。
Dockerfile 是我的应用的构建蓝图。Docker 镜像是从 Dockerfile 规范(构建蓝图)中产生的 App 指令。Docker 容器是围绕 Docker 映像创建应用程序的运行时虚拟环境包装器。
像应用程序一样,Docker Images 是免费的,如果它们包含开放源代码,即 Linux、Jupyter、Rust、Python、Tensorflow、Spark、Kafka、NGINX,这是一个越来越长的列表,可以从公共存储库中下载。
我决定使用 Docker 作为我们处理 SBPIAIML 的宏伟解决方案的一个解决方案。
Docker 如何解析七个 BPIAIML?
每一个和开发人员交谈过的人都以某种形式听说过,“它在我的机器上工作。”
当我没有现在这么成熟的时候,我的第一反应是,“你被解雇了!”
现在,我说,“哦,太好了。把你的 docker 文件和单元测试发给我。我会努力找出我做错了什么,然后回来找你。”
通常会发生一两个事件,但不总是发生:
- 开发人员将 docker 文件和单元测试发送给我,或者:
- 开发人员开夜车创建 Dockerfile 文件和单元测试,然后发给我。
我们码头之旅的真正开始。
我建议您从我们旅程的起点开始:
https://levelup.gitconnected.com/our-enterprise-docker-solution-for-migration-to-the-cloud-d7bb9d1a796b
我假设你已经安装了 Docker。如果没有,现在就可以,请转到此处:
https://docs.docker.com/engine/install/
Docker 是如何工作的?
为了解释 Docker 是如何工作的,我首先更正式地定义了我们在这篇博客文章中多次引用的四个基本 Docker 术语。
一个映像就是一大块虚拟环境二进制指令。按照 Dockerfile 指定的二进制指令对图像进行分层。一个例子是 Ubuntu 20.04、 nbdev 和 Jupyter notebook 实例的层。
层按顺序应用于基础图像,以创建最终图像。
一个 Dockerfile 是一个**图像的蓝图。**蓝图由文本文件中的一系列 Docker 命令组成。
Dockerfile是一个文本文档,包含用户可以在命令行上调用的所有命令,以组合一个图像。— 文档参考
Docker 容器是围绕 Docker 映像实例的运行时虚拟环境包装器。
注意 : Docker 可以自动为你生成一个容器名,或者你可以在 *Docker run ...*的时候给容器命名
DockerHub (Image) Registry :您可以将公共(或私有)Docker 映像放在这个共享存储库(repo)中。要将您的一张图片发布到公共回购*台,需要一个 Docker 登录帐户。如果你不推送图像,它会留在本地的私人回购中。
您可以使用 Docker 桌面查看本地**容器、本地和提取的图像、**和其他我们尚未讨论的重要 Docker 实体。

我为这些术语道歉。似乎任何一门学科,比如计算机科学,医学,或者物理学,90%是术语,10%是概念。我接受它,因为在讨论概念之前,你需要定义概念中的术语。
当我们讨论概念的伪哲学时,你需要深入了解 Docker 图像和 Docker 容器之间的区别。
我知道我不得不多次回顾 Docker 图像和 Docker 容器的定义。我通过将一个容器包含一个图像来简化我的生活。
一个容器可以做更多的事情,但是除非我想分拆我自己的 Docker 公司,否则我不需要知道 Docker 架构或者内部工作方式。
*鬼,我可能比你慢一点。不要让我劝阻你深入研究 Docker 内部。你可以利用你的时间做一些最糟糕的事情。
我们将在博客文章的后面详细讨论所有这些术语和 Docker 命令。
不是,不是在这里发明的
不要发展自己的形象,至少在需要 Docker I mage 的时候。
Docker Hub 上有超过 800 万张图片。很有可能,你会在 Docker Hub 上找到你需要的东西,避免自己动手制作。
即使你没有找到你想要的,你可能会找到一些相近的东西。通过查看其他人的代码,使用学*软件的古老艺术(IMHO,这很好),您将找到 other 文件和其他来源的链接。
您应该检查您想要的容器是否在:
我根据类别、操作系统和机器架构进行过滤搜索。此外,我在搜索框中输入一个或多个术语来改进我的搜索。

在超过 800 万个容器中优化搜索—图片来源:作者桌面快照。
我的示例搜索 nbdev 图像的结果是:

图片来源:作者桌面快照。
如果我点击容器名fastdotai/nbdev-dev:

图片来源:图片:图片:作者桌面快照。
我使用 docker hub fastdotai/nbdev-dev中的 docker 映像,方法是使用以下命令:
docker pull fastdotai/nbdev-dev
您必须创建一个本地副本,以便在创建容器时不引用全局中心副本。
您不希望造成网络瓶颈,并且您希望知道容器是由同一个映像构成的。你努力追求速度和再现性。
列出所有可用的 Docker 图像和容器
docker images -a列出本地储存在您电脑上的所有图像。该列表中包括您使用docker pull <image-mame>绘制的图像和中间图像(图层)。
docker images -a

CLI docker images -a. Image 的输出:作者桌面快照。
docker ps列出你电脑上所有正在运行的容器。
docker ps -a

我的沙箱上没有运行 Docker 容器。图:作者桌面快照。
docker 运行选项是 Docker 的核心
对我来说,Docker 和 java 的目标是一样的,关键的区别在于 Docker 实现了。
调试一次,随处运行—匿名
对我来说,Docker 和 java 的目标是一样的,关键的区别在于 Docker 实现了。
调试一次,随处运行—匿名
以上可能有些言过其实。出于我的目的,上面的引用对 Linux、Windows、Macintosh、Kubernetes 和云供应商的许多变体都有效。
理解命令 Docker run 操作对于指定 Docker 容器如何与外部环境通信至关重要。
实际上,你的“外部环境”要么是一台本地机器(你的沙箱),要么是几台联网的机器,通常是一个云,或者更好的是一个分布式操作系统,比如 Kubernetes 。
docker run [OPTIONS] <image-name> [COMMAND] [ARG...]
我在这篇博客文章中展示了各种形式的有用的[OPTIONS] n。
完成后移除 Docker 容器
--rm退出时自动移除容器并释放其正在使用的内存。当我们运行一个容器时,我们几乎总是使用这个选项,因为我们觉得这最接近于模仿你的智能手机上的应用程序行为。
docker run --rm <image-name>
装入容器
所有的 Docker 镜像都有一个 Linux 基础层。当您运行 Docker 容器时,您可以附加并运行大多数 shell 命令。例如,您可以列出容器的工作目录中的文件:
docker exec -t <container name/ID> bash -c "ls -al"
或者脱离背景:
docker exec -t -d <container name/ID> bash -c "ls -al"
为了调试一个容器,我们启动一个交互式会话:
docker exec -it <container name/ID> bash
注意 :您可以通过输入 *exit* 来结束或终止您的会话。
注意 :以上命令对于监控和您可能想要在运行的 容器 上执行的其他任务非常有用。
注意:有很多关于“边车模式”的抽象讨论上面的命令是实现 Docker 容器“sidecar”的方法之一(IMHO,最好的方法之一。)
将 Docker 容器目录树映射到本地目录树。
请记住,当我们讨论“本地”时,我们指的是外部主机环境。有时候我可能没有做到应有的一致,也可能把“本地”说成是“外部”环境。
我们可以覆盖(忽略)Dockerfile 指定的volume或workdir命令技术:
docker run -v $PWD:<local-directory-root> -w <local-directory-root> <container name/ID># Example
docker exec -it -v $PWD:<local-directory-root> -w <local-directory-root> nbdev bash
在前面的命令中,您将当前的“本地”目录$PWD,挂载到了容器的卷中(即-v标志)。您导致名为<local-directory-root>的目录成为容器(-w标志)的/workdir。)结果是容器与$PWD,中的/workdir一起启动,该目录是您启动时所在的目录。
我们发现上面的技术经常被使用。
如果您愿意,可以使用以下命令查看 Docherfile workdir规范:
docker exec <container name/ID> pwd
# Example
docker exec lp pwd

图:作者桌面快照。
将 Docker 网络和端口映射到您的“本地”网络。
记住,一个 Docker 容器为 Docker 映像创建了一个小小的封装宇宙,一个虚拟环境。
通过执行以下命令,您可以在 Docker 包安装后看到 Docker 网络:
docker network ls
一开始你会看到三个网络。

图:作者桌面快照。
将lp 容器作为 Linux 守护进程运行,然后使用以下命令列出所有“本地”容器:
docker pull fastdotai/nbdev:latest
docker run -d --name lp --net=host fastdotai/nbdev# List running containers
docker ps -a

图:作者桌面快照。
我们通过使用 Docker 命令创建一个“sidecar”来查看lp 容器的内部:
docker exec -it lp /bin/bash
看看lp 容器中有哪些网络接口:
root@docker-desktop:~# ifconfig

图像:作者桌面快照
注意网络接口docker0:和eth0:是相同的。选项-net=host将 Docker 容器虚拟环境网络接口映射到“本地”或主机网络接口。
注意 :在 *lp* Ubuntu Linux 变种 容器 上你需要运行一个 root 用户 sidecar 并执行;
docker exec -u root -t -i lp /bin/bash
root@docker-desktop:~# apt-get update
root@docker-desktop:~# apt-get install net-tools
在执行ifconfig.之前
现在我们已经用完了,请将容器移走。
docker container rm lp
清理码头建筑的混乱
每次创建 Docker 图像时,Docker 文件都会导致旧的层变得多余。这些冗余的层消耗内存和交换空间。使用 Docker 命令删除这些层:
docker system prune
为什么 Docker 没有垃圾收集器?我不知道。我确信通过一些研究我可以找到答案。上面的 Docker 命令在你做的时候警告你,对我来说就够了。
我们从未遇到过运行docker system prune.的问题,但是,如果我们在频繁更改 docker 文件时不使用docker system prune,我们就会耗尽“本地”内存。
检查所有 Docker 运行选项
您可以对这个 docker run 命令应用许多其他标志,以实现更加定制的容器创建过程。
运行下面的命令,以获得与此命令一起运行的更多选项。
docker run -it <image ID> --help
摘要
你可能已经注意到我已经讨论了 Dockerfile 文件的丰富主题。我也没有讨论 Docker-compose,但是我会在未来的博客文章中讨论这个问题。)在此之前,我可以说我们使用 Docker-compose 从微服务构建服务。
在这篇博客文章中,我主要关注 Docker run 命令和必要的辅助管理 Docker 命令。
我被允许分享我们迄今为止的旅程。当我们做出重大改变时,将会有更新。
编码快乐!
测试你的 R 知识的 20 个问题
原文:https://towardsdatascience.com/twenty-questions-to-test-your-r-knowledge-1c2926981853?source=collection_archive---------8-----------------------
用这 20 个简短有趣的问题来看看你是不是超级明星

Unsplash.com阮当黄鹤年
虽然不像 Python 那样流行,但作为编程语言,R 拥有强大且不断增长的用户基础,作为应用统计学家,它将永远是我的首选语言。根据我的经验,R 用户有很多种类型。有些人只是勉强掌握足够的知识来完成他们的统计作业,有些人经常使用它,但主要是围绕像dplyr这样方便的数据争论包工作,还有一些人对该语言及其底层结构有深刻的了解。
你坐在哪里?这里有 20 个问题来测试你的 R 知识。尝试在不运行代码的情况下回答这些问题,然后检查下面的答案,看看你做得如何。然后也许找个朋友自我测试一下,比较一下笔记。我写这个测验是为了好玩,所以请不要把它用于像数据科学面试这样严肃的事情,它不是为了那个目的!
小测验
问题 1: x <- vector()。x的数据类型是什么?
问题二: y <- 2147483640L:2147483648L。y的数据类型是什么?
问题三: z <- 0/0 **。**什么是z类?
**问题四:**如果v <- complex(1,1),那么c(v, TRUE)的输出是多少?
问题 5: 在 R 中的一个齐次的一维和二维数据结构,分别称为原子向量和矩阵。a)一维异构数据结构,b)二维异构数据结构和 c)n 维数据结构的名称是什么?
问题 6: 帐篷营地和吃风筝树对 *R 的意义是什么?*这些术语的由来是什么?
问题 7: 如果不安装dplyr包,下面每种情况会发生什么?
案例 1:
library(dplyr)mtcars %>%
group_by(cyl) %>%
summarize(mean_mpg = mean(mpg))
案例二:
require(dplyr)mtcars %>%
group_by(cyl) %>%
summarize(mean_mpg = mean(mpg))
问题 8: a <- c(2, "NA", 3)。sum(is.na(a))的输出是什么?
问题 9:data()的输出是多少?
问题 10:round(0.5)的输出是多少?
问题 11: 当您运行命令library(tidyverse)时,这些包中的哪个没有加载?a) dplyr b) tidyr c) broom d) ggplot2
问题 12: 在最新的 R 版本中,不是下面三个代码片段中的哪一个正确地跨列表l的元素应用了一个函数?
## A
lapply(l, function(x) x + 10)## B
lapply(l, x -> x + 10)## C
lapply(l, \(x) x + 10)
问题 13: 看一下这段代码的输出,注意它并没有像我们预期的那样产生每一行的总和?在不编辑现有代码的情况下,需要在代码中添加什么来纠正这种情况?
library(dplyr)df <- data.frame(x = c(1, 2), y = c(1, 2), z = c(1,2))df %>%
mutate(sum = sum(x, y, z))## x y z sum
## 1 1 1 1 9
## 2 2 2 2 9
问题 14: 以下哪个包允许用户用 R 运行 Julia 语言的代码?a) JuliaCall b) RJulia c) JuliaR
问题 15: 以下哪一项是dplyr最新版本中的功能?a) c_across b) r_across c) l_across d) s_across
问题 16: 为什么下面的代码不能运行需要添加什么才能运行?
library(tidyverse)mtcars %>%
nest_by(cyl) %>%
dplyr::mutate(
ggplot(data = data,
aes(x = hp, y = mpg)) +
geom_point()
)
问题 17: 什么函数可以用来从均匀分布中生成随机数?
问题 18: 如果x <- factor(c(4, 5, 6))``as.numeric(x)的输出是什么?
问题 19: 再用x <- factor(c(4, 5, 6))``str(x)和typeof(x)的输出有什么区别?
问题 20: 看下面两个代码片段。如果都运行在最新版本的 R 中,为什么片段 A 会成功而片段 B 会失败?
library(dplyr)## Snippet Amtcars %>%
filter(grepl("Mazda", rownames(.)))## Snippet Bmtcars |>
filter(grepl("Mazda", rownames(.)))
答案
x合乎逻辑。这是原子向量的默认类型。y是一个双精度数,尽管在y中使用了整数符号L。这是因为 R 中整数的最大值是 2147483647。因此,y的最后一个值被强制为双精度值,因此由于原子向量是同质的,所以整个向量被强制为双精度值。z属于数字类。- 输出是一个包含两个元素的向量,都是
1 + 0i。注意,complex()的第一个参数是length.out,表示复数向量的长度。因此complex(1,1)评估为1 + 0i,而complex(1,1,1)评估为1 + 1i。请注意,TRUE将被强制转换为与1 + 0i等价的复杂类型。 - a)列表;b)数据帧;c)阵列
- 它们是 R 版本发布的昵称。所有版本昵称都取自老花生漫画*。*
- 在案例 1 中,第一行将生成一个错误,指示没有安装这样的包,执行将停止。在第二种情况下,第一行会产生一个警告,但是第二行仍然会被执行,并且会因为找不到
%>%而产生一个错误(假设magrittr没有被附加)。这很好的说明了library()和require()的区别。library()附加一个包,但是require()评估包是否已经被附加,如果已经被附加,评估到TRUE,否则评估到FALSE。使用require()会增加调试代码的难度。 - 这等于零。注意
"NA"是一个字符串,而不是一个缺失值。 - 输出是 r 中所有内置数据集的列表。
- 输出为零。r 遵循 IEC 60559 标准,其中 0.5 四舍五入到最接近的偶数*。*
broom未加载,因为它不是“core tidyverse”中的包。注意install.packages("tidyverse")会将broom和所有的包一起安装在核心和扩展 tidyverse 中。- 选项 B 行不通。注意,选项 C 是 R 4.1.0 中发布的新的匿名函数语法。
- 代码需要在
mutate语句前包含行rowwise() %>%,以声明该函数将逐行应用。 JuliaCallc_across。它相当于across()函数,但用于行操作。- 此代码试图生成一列绘图。这需要声明为如下的列表列*:*
*library(tidyverse)mtcars %>%
nest_by(cyl) %>%
dplyr::mutate(
list(ggplot(data = data,
aes(x = hp, y = mpg)) +
geom_point())
)*
17.runif()
18.输出是矢量c(1, 2, 3)。因子被转换成它们的整数表示。
19.str(x)给出了因子x的结构。typeof(x)给出了x中数据的存储方式,为整数。
20.代码片段 B 使用了新的本地管道操作符|>。与代码片段 A 中的管道操作符%>%不同,本机管道只管道到函数的第一个未命名参数,而不接受.管道到其他参数。为了获得与代码片段 A 相同的输出,需要使用下面的匿名函数:
*mtcars |>
{\(df) filter(df, grepl("Mazda", rownames(df)))}()*
你做得怎么样?
如果你的得分在 5 分以下,你迫切需要一个基础教程 R 来避免花太多时间解决代码中不必要的错误。
如果你的得分在 6-10 分之间,你的知识水*可能和大多数用户差不多。
11-15 是一个很好的分数,你显然知道很多编程语言的基本原理和结构。
如果你得了 16-20 分,你就是超级明星。你可能知道很多不必要的 R 琐事,你很可能是一个 R 学究。我希望你正在帮助其他人。
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在 LinkedIn 或Twitter上找我。也可以看看我在drkeithmcnulty.com上的博客或者我即将发布的 关于人物分析的教科书 。
Twitchverse:使用 Neo4j 图形数据科学对 Twitch 宇宙的网络分析
原文:https://towardsdatascience.com/twitchverse-a-network-analysis-of-twitch-universe-using-neo4j-graph-data-science-d7218b4453ff?source=collection_archive---------8-----------------------
通过实例了解如何使用图论和算法从关联数据中获得有价值的*解
图表数据科学侧重于分析数据中的联系和关系,以获得有价值的*解。每天都会产生海量的数据,但是数据点之间的联系往往在数据分析中被忽略。随着图形数据科学工具的兴起,分析联系的能力不再局限于像谷歌这样的大型科技公司。在这篇博文中,我将介绍如何在您的计算机上设置 Neo4j Graph Data Science 环境,并带您完成您的(第一次)网络分析。我们将使用 Twitch 网络数据集。在我的前一篇博文中,我已经展示了如何从官方 Twitch API 获取信息并将其存储到 Neo4j graph 数据库中。您可以选择直接从 Twitch API 获取信息,或者加载我已经准备好的 Neo4j 数据库转储。数据库转储中的数据是在 2021 年 5 月 7 日至 10 日之间擦除的。
Neo4j 图形数据科学环境
首先你需要下载安装 Neo4j 桌面应用。打开 Neo4j 桌面应用程序后,您应该会看到以下屏幕:

Neo4j 桌面应用。图片由作者提供。
要跟踪这篇博文并获得相同的结果,您应该加载我准备的数据库转储。从这个链接下载,然后添加到下图所示的 Neo4j 桌面环境中。简单说明一下,数据库转储有 1.6GB 大,包含 1000 万个节点,所以要确保有足够的可用磁盘。

向 Neo4j 桌面项目添加文件。图片由作者提供。
如图所示,点击添加按钮,选择文件选项。这应该需要几秒钟,然后文件名应该出现在文件选项卡下。要恢复数据库转储,请将鼠标悬停在文件上,然后单击右上角的三个点。接下来,选择从转储创建新的 DBMS选项。

从数据库转储创建新的 DBMS。图片由作者提供。
在下一个屏幕中,您需要定义密码并选择 Neo4j 数据库版本。我建议你总是使用最新的数据库版本。目前,版本 4.2.6 是最新的。

选择密码和数据库版本。图片由作者提供。
数据库恢复应该只需要几秒钟。现在,在开始网络分析之前,我们只需安装 APOC 和图形数据科学插件。幸运的是,我们只需几次点击就可以安装这两个插件。

安装 APOC 和 GDS 插件。图片由作者提供。
要安装插件,点击项目选项卡下创建的数据库实例。通过单击选择创建的数据库后,右侧会出现一个新的选项卡。选择插件标签,点击安装按钮,安装 APOC 和图形数据科学库。
最后但并非最不重要的一点是,在处理像我们正在处理的这种稍微大一点的图形时,增加堆内存是明智的。您可以通过单击创建的数据库的三个点并选择设置来定义堆分配。

Neo4j Desktop 中数据库实例的访问设置。图片由作者提供。
在设置中,搜索下面两行并增加堆内存分配。
dbms.memory.heap.initial_size=4G
dbms.memory.heap.max_size=4G
默认的堆内存分配是 1GB,在本例中,我将它增加到 4GB。我建议您也这样做,以避免在执行一些图形算法时出现 OOM 错误。
既然已经加载了数据库转储并安装了必要的插件,那么就可以开始启动数据库实例了。我已经准备了一个 Jupyter 笔记本,里面有这篇博文中将要执行的所有 Cypher 查询,但是您也可以将 Cypher 查询复制到 Neo4j 浏览器环境中。
抽动网络模式
我们将从 Twitch 网络模型的简短回顾开始。

抽动网络的图形模式。图片由作者提供。
Twitch 社交网络由用户组成。这些用户中的一小部分通过直播流广播他们的游戏或活动。在我们的图表模式中,使用实时流的用户被标记为二级标签 Stream 。我们知道他们属于哪个团队,他们在流上玩哪些游戏,以及他们用哪种语言呈现他们的内容。我们还知道他们在抓取的时候有多少追随者,有史以来的历史观看次数,以及他们何时创建了他们的用户帐户。另一方面,我们知道哪些用户参与了流媒体工具的聊天。我们可以区分在流中聊天的用户是普通用户(CHATTER 关系)、流的版主(版主关系)还是流的 VIP。
请记住,数据库转储中的数据是在 2021 年 5 月 7 日和 10 日之间收集的,因此只有在那个周末流式传输的 streamer 才会显示在数据库中。类似地,只有在那个周末聊天的用户才会出现在网络中。
我们将首先使用 apoc.meta.stats 过程计算数据库中的节点数。执行以下 Cypher 查询,按标签检查节点数。
CALL apoc.meta.stats()
YIELD labels
结果

apoc.meta.stats 程序的结果。图片由作者提供。
我们可以观察到图中几乎所有的节点都是用户。有 1050 万用户,其中只有大约 6000 人是流媒体用户。这些彩带已经播放了 594 场比赛,用 29 种不同的语言播出。
探索性图形分析
在深入研究图形算法之前,我喜欢先熟悉手边的图形。
我们将通过执行几个 Cypher 查询来执行探索性的图形分析,以了解有关网络的更多信息。这篇博文中的所有条形图都是在 Seaborn 库的帮助下创建的。我准备了一个 Jupyter 笔记本,里面包含了所有的代码,可以帮助你理解这篇博文。首先,我们将根据历史观看次数检索前十名。
MATCH (u:Stream)
WHERE exists(u.total_view_count)
RETURN u.name as streamer,
u.total_view_count as total_view_count
ORDER BY total_view_count DESC
LIMIT 10;
结果

前十名的所有时间观看计数飘带。图片由作者提供。
在我被 Twitch 领域的专家攻击之前,我想指出,我们只分析了在 5 月 7 日和 10 日之间直播的 Twitch 流。可能有其他具有更高的总观看计数的流。在我们的图表中,前三个有史以来最高观看次数的飘带似乎是一个飘带团队,而不是一个个体。我不熟悉提到的溪流。我只知道 esl_csgo 几乎全天候播放《反恐精英:全球攻势》。接下来,我们将调查关注人数最多的前十条横幅。
MATCH (u:Stream)
WHERE exists(u.followers)
RETURN u.name as streamer,
u.followers as followers
ORDER BY followers DESC
LIMIT 10;
结果

十大跟风。图片由作者提供。
有趣的是,我们得到了一组与前一个查询完全不同的 streamers。除了裹尸布,他在有史以来的浏览量类别中排名第四,在最高粉丝数中排名第二。当一个流上线时,每个关注者都会收到一个通知。当 Rubius 上线时,几乎无法想象有 900 万人收到通知;当 Pokimane 开始播放时,几乎无法想象有 800 万人收到通知。我很想知道这些溪流已经存在了多久。我们将按照用户创建日期合计流的数量。
MATCH (u:Stream)
WHERE exists(u.createdAt)
RETURN u.createdAt.year as year,
count(*) as countOfNewStreamers
ORDER BY year;
结果

按年份对创建的流进行计数。图片由作者提供。
这里我需要再补充一条免责声明。我们是按照用户帐户创建的日期而不是他们第一次开始流式传输的日期进行聚合的。不幸的是,我们没有第一次流的日期。从结果来看,至少有一些彩带已经在 Twitch 上工作了十年。另一个令人震惊的事实,至少对我来说。我们可以离开飘带,调查一下大多数飘带都玩哪些游戏。请注意,一个流注可以玩多个游戏,因此他们可能会被计入多个游戏中。我们的数据是在周五和周日之间收集的,所以流民可能更喜欢在周五玩 Valorant,在周日玩扑克。
MATCH (g:Game)
RETURN g.name as game,
size((g)<--()) as number_of_streamers
ORDER BY number_of_streamers DESC
LIMIT 10
结果

大多数彩带玩的游戏。图片由作者提供。
到目前为止,最受欢迎的是聊天类别。聊天类别流行的原因可能是因为它用于所有不玩特定视频游戏的流。这可能包括从烹饪节目到“现实生活”流的任何内容,在“现实生活”流中,流手拿着相机在世界各地行走。不然看来生化危机村,GTA V,英雄联盟才是最受流光欢迎的游戏。
大多数横幅属于一个或两个团队。我们可以调查哪些团队拥有最高的成员数,以及团队成员广播的所有游戏。
MATCH (t:Team)
WITH t, size((t)<--()) as count_of_members
ORDER BY count_of_members DESC LIMIT 10
MATCH (t)<-[:HAS_TEAM]-(member)-[:PLAYS]->(game)
RETURN t.name as team,
count_of_members,
collect(distinct member.name) as members,
collect(distinct game.name) as games
结果

g 燃料团队在 2021 年 5 月 7 日至 10 日的周末有 64 名成员。其成员涵盖了 Twitch 上 34 个不同的游戏类别。在我们深入网络分析之前,让我们检查一下哪些用户是大多数流的重要用户。
MATCH (u:User)
RETURN u.name as user, size((u)-[:VIP]->()) as number_of_vips
ORDER BY number_of_vips DESC LIMIT 10;
结果

VIP 数量最多的用户。图片由作者提供。
我敢说 Nightbot 和 Supibot 都是机器人。让机器人成为贵宾似乎有点奇怪。我一直认为机器人是聊天的主持人,有能力删除带有链接的消息等。我们还可以检查哪些用户正在调节最高数量的流。
MATCH (u:User)
RETURN u.name as user, size((u)-[:MODERATOR]->()) as number_of_mods
ORDER BY number_of_mods DESC LIMIT 10;
结果

在不同的流上具有最高数量的版主角色的用户。图片由作者提供。
正如所料,拥有最高版主角色数的前十名用户最有可能是机器人,其中 Nightbot 最受欢迎。
用户网络分析
您可能还记得,在我们的图表中,1000 万用户中只有大约 6000 人是流媒体用户。如果我们从这个角度来看,只有 0.06%的用户是流媒体用户。我们数据库中的其他用户是在其他 streamers 的广播中聊天的用户。到目前为止,我们在探索性图形分析中完全忽略了它们。也就是说,直到现在。图形数据科学侧重于分析网络中实体之间的连接。是时候戴上图表数据科学的帽子,研究网络中用户之间的关系了。作为对图结构的一个简单提醒,让我们设想一个用户网络的小子图。
MATCH (s:Stream)
WITH s LIMIT 1
CALL {
WITH s
MATCH p=(s)--(:Stream)
RETURN p
LIMIT 5 UNION WITH s
MATCH p=(s)--(:User)
RETURN p
LIMIT 5
}RETURN p
结果

单个流的示例用户网络。图片由作者提供。
正如在之前的博客文章中提到的,流媒体工具的行为就像普通用户一样。他们可以主持其他广播,可以参与他们的聊天,或获得 VIP 身份。这就是促使图模型决定用二级标签流将流表示为常规用户的原因。我们不希望图中的两个节点代表一个真实的实体。
首先,我们将评估节点度分布。节点度就是每个节点拥有的关系的数量。这里,我们正在处理一个有向网络,因为关系方向具有语义值。如果 Aimful 是 Itsbigchase 流的版主,这并不自动意味着 Itsbigchase 是 Aimful 流的版主。在处理有向网络时,可以将节点度分布分为入度分布和出度分布,入度分布用于计算传入关系,出度分布用于计算传出连接。首先,我们将检查出度分布。
MATCH (u:User)
WITH u, size((u)-[:CHATTER|VIP|MODERATOR]->()) as node_outdegree
RETURN node_outdegree, count(*) as count_of_users
ORDER BY node_outdegree ASC
结果

用户网络的外向度分布。图片由作者提供。
双对数图显示了出度分布。两个轴都有对数刻度。在总共一千万用户中,大约有六百万用户只有一个外向关系,这意味着他们只在单个流中聊天。绝大多数用户的传出连接少于 10 个。几个用户有超过 100 个外发链接,但我大胆猜测他们很可能是机器人。一些数学家可能会考虑遵循幂律分布的出度。现在,我们来看看入学位分布。我们已经知道,只有飘带的入度大于 0。只有广播其流的用户才能让用户参与他们的聊天。因此,大约 99.999%的用户的入度值为 0。你几乎可以把这个网络视为一个二分图,除了在飘带之间也有关系。我们将只为拖缆可视化入度分布。
MATCH (u:Stream)
WITH u, size((u)<-[:CHATTER|VIP|MODERATOR]-()) as node_indegree
RETURN node_indegree, count(*) as count_of_users
ORDER BY node_indegree ASC
结果

用户网络的入度分布。图片由作者提供。
观察到入度分布也遵循幂律分布是非常有趣的。大多数飘带在周末有不到 1000 个活跃的聊天者,而一些飘带有超过 15000 个活跃的聊天者。
图形数据科学图书馆
现在是时候执行一些图形算法了。Neo4j Graph Data Sciencelibrary(GDS)拥有 50 多种图形算法,从集中到社区检测和节点嵌入算法。首先,我们需要更新 GDS 图书馆的工作方式。
为了尽可能高效地运行算法,Neo4j 图形数据科学库使用专门的内存图形格式来表示图形数据。因此,有必要将 Neo4j 数据库中的图形数据加载到内存图形目录中。加载的数据量可以通过所谓的图形投影来控制,图形投影还允许例如在节点标签和关系类型上过滤,以及其他选项。
引自 官方文件 。
GDS 库在专门的内存图形格式上执行图形算法,以提高图形算法的性能和规模。使用本地或 cypher 投影,我们可以将数据库中存储的图形投影为内存中的图形格式。在执行任何图形算法之前,我们必须将存储的图形视图投影为内存中的图形格式。我们可以过滤我们想要投影的图形部分。不需要添加将不被用作图算法的输入的节点和关系。我们将从规划所有用户和流节点以及它们之间可能的关系开始,它们是 CHATTER、版主和 VIP。
CALL gds.graph.create('twitch',
['User', 'Stream'],
['CHATTER', 'VIP', 'MODERATOR'])
弱连通分量
弱连接组件算法(WCC)用于在给定网络中寻找不同的岛或节点组件。当您忽略关系方向时,一个节点可以到达同一组件中的所有其他节点。

样本图中的可视化弱连通分量。图片由作者提供。
节点 Thomas、Amy 和 Michael 形成弱连通分量。如上所述,WCC 算法忽略了关系方向,实际上将网络视为无向网络。
使用下面的 Cypher 查询在我们之前在内存中投影的 Twitch 网络上执行弱连接组件算法。当我们只对算法结果的高级统计感兴趣时,使用算法的统计方法。
CALL gds.wcc.stats('twitch')
YIELD componentCount, componentDistribution
结果

WCC 算法在整个投影用户图上的结果。图片由作者提供。
有趣的是,用户网络仅由一个相连的组件组成。例如,您可以在观看日语流的用户和观看匈牙利语流的用户之间找到一条无向路径。从图中移除机器人并重新运行 WCC 算法可能会很有趣。我有一种预感,Nightbot 和其他 bot 有助于将网络的不同部分连接成一个单一的连接组件。
有了当前内存中的图形投影,我们还可以在算法执行时过滤节点或关系。在下一个例子中,我选择只考虑流节点和它们之间的连接。
CALL gds.wcc.stats('twitch', {nodeLabels:['Stream']})
YIELD componentCount, componentDistribution
结果

仅考虑图中的流节点时 WCC 算法的结果。图片由作者提供。
通过 WCC 算法的这种变化,我们可以有效地查看流之间的聊天通信。只考虑流节点,因此,只有流节点之间的关系被用作 WCC 算法的输入。streamer 网络中共有 1902 个独立组件。最大的组件包含大约 65%的所有流节点。然后,我们主要处理单节点组件,其中一个流在数据被抓取的特定周末没有在其他流的广播中聊天。
PageRank
PageRank 可能是最著名的图算法之一。它用于通过考虑节点的入站关系以及链接到它的节点的重要性来计算节点重要性。PageRank 最初是 Google 用来计算网站重要性的,但是可以用在很多不同的场景中。
使用下面的 Cypher 查询在整个用户网络上执行 PageRank 算法。
CALL gds.pageRank.stream('twitch')
YIELD nodeId, score
WITH nodeId, score
ORDER BY score
DESC LIMIT 10
RETURN gds.util.asNode(nodeId).name as user, score
结果

PageRank 算法在整个用户网络上的结果。图片由作者提供。
如果你在其他时候使用了 Twitch API,结果可能会有很大的不同。在该分析中,仅考虑了 5 月 7 日和 10 日之间的聊天参与度。我的假设是,具有最高 PageRank 分数的流很可能具有参与他们聊天的其他流的最高计数。我们可以通过在网络的 streamer 子集上运行 PageRank 算法来轻松验证这一假设。
CALL gds.pageRank.stream('twitch', {nodeLabels:['Stream']})
YIELD nodeId, score
WITH nodeId, score
ORDER BY score
DESC LIMIT 10
WITH gds.util.asNode(nodeId) as node,score
RETURN node.name as streamer,
score,
size((node)<--(:Stream)) as relationships_from_streamers,
size((node)<--(:User)) as relationships_from_users
结果
流子图上 PageRank 算法的结果。
当我们考虑所有用户或者当我们仅考虑 Twitch 网络的流时,按 PageRank 分数排名的前十个流几乎是相同的。我发现令人惊讶的是,Yassuo 在第一位只有 16 个来自其他流媒体工具的入站关系和 22000 个来自普通用户的关系。我大胆猜测,从 PageRank 得分来看,Yassuo 广播中聊天的横幅本身也很重要。
MATCH (s:Stream{name:"yassuo"})<--(o:Stream)
RETURN collect(o.name) as other_streamers
结果

亚索直播流里聊天的飘带结果。图片由作者提供。
似乎我的假设有一些优点。在亚索之流聊天的飘带中有 loltyler1,trainwreckstv,benjyfishy。这些飘带也被 PageRank 评为前 10 名。关系的数量并不重要,质量也很重要。
社区检测
我们要看的最后一类图算法是社区检测类。社区检测或聚类算法用于推断给定网络的社区结构。社区被模糊地定义为网络中的节点组,它们彼此之间的连接比与其他节点的连接更紧密。我们可以尝试检查整个用户网络的社区结构,但这并不能产生一个漂亮的结果网络可视化。首先,我们将从内存中释放现有的项目网络。
CALL gds.graph.drop("twitch")
我有时喜欢看象棋或扑克彩带。让我们分析一个包含扑克和象棋飘带的子图的社区结构。为了方便我们进一步的查询,我们将首先用一个额外的节点标签来标记相关的节点。
MATCH (s:Stream)-[:PLAYS]->(g:Game)
WHERE g.name in ["Chess", "Poker"]
SET s:PokerChess
总共有 63 条彩带在他们的频道上播放国际象棋或扑克。让我们快速想象一下 streamer 网络,以便更好地了解它的外观。

棋牌飘带网。图片由作者提供。
很明显,我们正在处理一个大的连接组件和大多数孤立的节点。如果您只打算运行单个图表算法,可以使用匿名图表功能,在该功能中,您可以在一个步骤中设计并执行一个图表算法。这里,我们将使用 Louvain 模块性算法来推断这个子图的社区结构。我们也将此网络视为无向网络。我会说,如果一个流人参与另一个流人的聊天,他们可能是朋友,通常,友谊关系是双向的。这次我们将把 Louvain 模块性算法的结果存储回存储的图中,这样我们就可以在可视化中使用社区结构信息。
CALL gds.louvain.write({
nodeProjection:'PokerChess',
relationshipProjection:{
ALL:{orientation:'UNDIRECTED', type:'*'}
},
writeProperty:'louvain_chesspoker'
})
我们可以在 Neo4j Bloom 应用程序中检查社区结构算法的结果。

棋牌飘带子图的社区结构。图片由作者提供。
节点颜色表示节点属于哪个社区。我忽略了没有参与其他流聊天的流,所以没有孤立的节点。我必须再次强调,我们只是在看 Twitch 网络的 3 天快照,所以结果可能并不完美,因为一些 streamers 喜欢周末休息等等。
现在,我想向您展示在 Neo4j 中您可以做的最后一件很酷的事情。我们可以检查哪些飘带共享它们的观众,而不是看哪些飘带相互影响。我们的数据库中没有所有的观众,但我们有在 streamers 的广播中聊天的观众。首先,我们将标记有不止一个传出关系的用户。这将有助于我们加快观众比较过程。
CALL apoc.periodic.iterate("
MATCH (u:User)
WHERE NOT u:Stream AND size((u)-->(:Stream)) > 1
RETURN u",
"SET u:Audience",
{batchSize:50000, parallel:true}
)
在我们可以运行社区检测算法之前,我们需要推断一个新的网络来描述哪些流共享它们的观众。首先,我们必须投影一个内存中的图形。
CALL gds.graph.create('shared-audience',
['PokerChess', 'Audience'],
{CHATTERS: {type:'*', orientation:'REVERSE'}})
接下来,我们将使用节点相似度算法来推断共享受众网络。节点相似性算法使用JAC card 相似性系数来比较一对节点的相似程度。我们将假设,如果两个飘带共享至少 5%的观众,我们将在它们之间创建一个关系。算法的变异模式将结果存储回内存中的投影图。这样,我们可以将一个算法的结果作为另一个图算法的输入。
CALL gds.nodeSimilarity.mutate('shared-audience',
{similarityCutoff:0.05, topK:15, mutateProperty:'score', mutateRelationshipType:'SHARED_AUDIENCE'})
最后,我们可以在扑克和象棋流之间的共享观众网络上运行社区检测算法 Louvain。
CALL gds.louvain.write('shared-audience',
{ nodeLabels:['PokerChess'],
relationshipTypes:['SHARED_AUDIENCE'],
relationshipWeightProperty:'score',
writeProperty:'louvain_shared_audience'})
我将在 Neo4j Bloom 中可视化 streamers 之间共享观众的社区结构的结果。

基于共享观众关系的扑克和象棋横幅的社区结构。图片由作者提供。
结论
我希望这篇博文能让你对图形数据科学产生兴趣。如果您想让我写一个特定的用例或数据集,请告诉我。如果您在图形数据科学库代码方面需要一些帮助,您可以随时使用Neo4j Graph Algorithms Playground应用程序,它将为您生成执行图形算法所需的代码。
和往常一样,代码可以在 GitHub 上获得。
Twitchverse:在 Neo4j 中构建 Twitch 知识图
原文:https://towardsdatascience.com/twitchverse-constructing-a-twitch-knowledge-graph-in-neo4j-78f03276c1f7?source=collection_archive---------21-----------------------
了解如何在 Neo4j 中设计和构建描述 Twitch 宇宙的知识图
我从 Twitch 帖子上的可视化公共数据中获得了 *解的灵感。作者使用 Gephi 对 Twitch 网络进行图形分析,并将结果可视化。Twitch 是一个在线*台,允许用户通过直播分享他们的内容。Twitch streamers 通过与粉丝共享他们的屏幕来广播他们的游戏或活动,粉丝可以听到和观看他们的直播。我想知道如果我们使用图形数据库而不是 Gephi 来存储网络信息,我们可以进行什么样的分析。这篇博文将向你展示如何在 Neo4j 中设计和构建知识图。数据将通过官方的 Twitch API 获取。
环境设置
你需要 Twitch API 的证书来关注这篇博文。如果你已经在 Twitch 上创建了一个用户,你可以在 Twitch 令牌生成器站点上获得访问令牌和客户端 id,这是获得凭证最简单的方法。一旦你完成了这个步骤,你应该准备好客户端 id 和访问令牌(记住,访问令牌不是客户端秘密)。
接下来,您需要访问 Neo4j 数据库实例。最直接的解决方案是使用 Neo4j 沙箱,Neo4j 数据库的免费云实例。如果选择此路线,请选择使用空白沙盒项目。如果你愿意,你也可以在本地安装 Neo4j 桌面。
导入关于当前热门观看的流的信息
首先,我们将从 Twitch API 导入关于当前直播流的信息。API 文档可从这里获得。我们可以获取当前直播的 1000 个观看次数最多的流的数据。API 响应包含以下信息:
- 流媒体工具名称和 id
- 他们正在玩的游戏
- 溪流的语言
想想我们应该如何将这些信息存储为图表。我们用哪些信息作为节点,哪些作为关系?回答你的一些问题,随着时间的推移,用户可以玩很多游戏,使用很多语言。此外,流可以表现得像普通用户一样,订阅其他流,在他们的聊天中交谈等。通常情况下,需要不止一次的图建模过程迭代才能得到正确的结果。下面的图模型是我的第二次迭代。

图形模型来存储有关 streamers 的信息。图片由作者提供。
我已经使用 arrows 应用程序绘制了这篇博文中的所有图表。
如你所*,streamer 只是一个 Twitch 用户,他也广播他们的内容。我已经决定为 Twitch 网络中的所有用户使用一个用户标签,并为也进行流传输的用户添加一个二级流标签。我们知道一个流有多少追随者,在哪里可以找到这个流,以及用户是什么时候被创建的。我们将这些附加信息存储为节点属性。
语言和游戏信息以分类节点的形式存储。分类节点用于存储关于值数量有限的变量的信息。在我们的例子中,所玩的游戏和语言具有有限的价值。用户可以与游戏节点有一个或多个关系。也许在周五,他们更喜欢玩 Valorant,周日他们喜欢玩扑克。我们的图模型忽略了这个信息的时间成分。我们也不存储流玩家玩游戏的次数作为关系权重。我们忽略这两个数据点,因为我们必须优化数据收集过程来提取这些信息。
在继续之前,请确保在 Neo4j 中定义惟一的约束,以优化导入查询的性能。
CREATE CONSTRAINT ON (s:Stream) ASSERT s.name IS UNIQUE;
CREATE CONSTRAINT ON (u:User) ASSERT u.name IS UNIQUE;
CREATE CONSTRAINT ON (g:Game) ASSERT g.name IS UNIQUE;
CREATE CONSTRAINT ON (l:Language) ASSERT l.name IS UNIQUE;
CREATE CONSTRAINT ON (t:Team) ASSERT t.id IS UNIQUE;
我从事 Neo4j 数据库工作已经有五年了。大约一两个月后,我了解到 APOC 库是一个必须与 Neo4j 数据库结合使用的插件。它具有许多实用功能,可以帮助您立即解决您的问题。我最喜欢的 APOC 手术从一开始就是,现在仍然是apoc.load.json手术。它允许打开 JSON 文件,更重要的是,从任何返回 JSON 的 API 端点获取数据。仅使用 Cypher,您可以抓取各种 API 端点,并在没有任何外部工具的情况下构建知识图。多牛逼啊!它还支持请求中的自定义头和有效负载。在文档中了解更多关于apoc.load.json程序的信息。
为了导入关于 streamers 的信息,您需要附近有 Twitch API client_id 。streams 端点支持分页,并允许导出多达 1000 个活动流,每个请求最多 100 个流。端点有一个可用于分页的偏移量参数。为了用递增的偏移量参数执行十个请求,我们使用
UNWIND range(0, 900, 100) as offset
该语句将对偏移量的每个值执行请求。range 子句与 Python 中的 range 函数非常相似。我们告诉它,我们想要创建一个从 0 开始到 900 结束的列表,步长为 100。
如果我们将分页、请求和存储响应放在一个 Cypher 语句中,我们将得到下面的查询:
WITH $client_id as client_id
//prepare pagination
UNWIND range(0,900,100) as offset
//Make an API request
WITH "https://api.twitch.tv/kraken/streams/?limit=100&offset=" + toString(offset) AS url, client_id
CALL apoc.load.jsonParams(url,{Accept: "application/vnd.twitchtv.v5+json", `Client-ID`:client_id},null) YIELD value
//Iterate over results in the response
UNWIND value.streams as stream
//Store streamer information
MERGE (s:User{name:stream.channel.name})
SET s.followers = stream.channel.followers,
s.url = stream.channel.url,
s.createdAt = datetime(stream.channel.createdAt),
s:Stream,
s.id = stream.channel.`_id`
//Store game information
MERGE (g:Game{name:stream.game})
MERGE (s)-[:PLAYS]->(g)
//Store language information
MERGE (l:Language{name:stream.channel.language})
MERGE (s)-[:HAS_LANGUAGE]->(l);
现在,您的 Neo4j 数据库中应该有关于 1000 条 streamers 的信息。为了检查该图,我们可以看一下数据库中的单个流。运行以下 cypher 查询来获取单个流的游戏和语言信息:
MATCH (s:Stream)
WITH s LIMIT 1
MATCH p=()<-[:HAS_LANGUAGE]-(s)-[:PLAYS]->()
RETURN p
您可以在 Neo4j 浏览器中可视化结果。您应该会看到类似下图的内容。

单个流、其语言和他们玩的游戏的网络可视化。图片由作者提供。
导入关于聊天者的信息
在 Twitch 上,用户可以通过在聊天中输入评论来与 streamers 互动。幸运的是,Twitch 有一个 API 端点,允许我们检索关于特定流的聊天者的信息。这个 API 端点不需要任何授权。如果你想知道谁是 botezlive 流中的聊天者,你可以通过打开下面的链接获得这些信息:
http://tmi.twitch.tv/group/user/botezlive/chatters
关于 chatter 的信息存储在三个独立的数组中,指示 chatter 是流的 VIP、流的版主还是普通用户。还有 global_mod,和 admin 数组返回,但是据我所*都是空的,我们就忽略了。
在导入关于 chatters 的信息之前,让我们考虑一下应该如何定义图模型。从 API 端点响应中,我们了解到我们可以区分 chatter 是版主、VIP 还是普通用户。我们希望在我们的知识图中存储用户、版主和 VIP 之间的这种差异。我用不同的关系类型来表示这种区别。

颤振信息的图形模型。图片由作者提供。
我第二喜欢的 APOC 手术是apoc.periodic.iterate手术。它允许我们批量处理交易。这在处理大型数据结构时非常有用。在我们的例子中,单个拖缆可以有数千个抖动,如果我们检索 1000 个拖缆的抖动信息,我们可以处理大量数据。apoc.periodic.iterate过程接受两个带有可选配置图的 Cypher 语句。第一个 Cypher 语句返回我们想要迭代的数据列表。第二条语句从第一条 Cypher 语句中获取信息,通常将信息存储到 Neo4j 中。在配置图中,我们可以定义批量大小。批量大小表示单个事务中应该添加多少次迭代。在文档中了解更多关于 APOC 配料的信息。
如果我们把它们放在一起,我们可以返回apoc.periodic.iterate过程的第一个 Cypher 语句中的所有 streamers。在第二条语句中,我们创建了一个对 Twitch API 端点的请求,并存储了结果。我使用了值为 1 的 batchSize 参数来批处理每个请求,并在单独的事务中存储响应。
// Import mods/vip/chatters for each stream
CALL apoc.periodic.iterate(
// Return all stream nodes
'MATCH (s:Stream) RETURN s',
'WITH s, "http://tmi.twitch.tv/group/user/" + s.name + "/chatters" as url
//Fetch chatter information
CALL apoc.load.json(url) YIELD value
WITH s, value.chatters as chatters
// Store information about vips
FOREACH (vip in chatters.vips |
MERGE (u:User{name:vip})
MERGE (u)-[:VIP]->(s))
//Store information about moderators
FOREACH (mod in chatters.moderators |
MERGE (u:User{name:mod})
MERGE (u)-[:MODERATOR]->(s))
//Store information about regular users
FOREACH (chatter in chatters.viewers |
MERGE (u:User{name:chatter})
MERGE (u)-[:CHATTER]->(s))',
{batchSize:1})
您可以结合获取前 1000 个活动流来重复此查询,以收集关于 Twitch chatter 网络的更多信息。要检查信息存储是否正确,可以执行以下 Cypher 查询:
MATCH (s:Stream)
WITH s LIMIT 1
MATCH p=(s)<-[:MODERATOR|VIP|CHATTER]-()
RETURN p LIMIT 25
如果您在 Neo4j 浏览器中可视化该查询的结果,您应该会看到类似于下面的可视化内容:

导入 chatter 网络的结果。图片由作者提供。
导入有关 streamers 的详细信息
有一个单独的 Twitch API 端点,我们可以使用它来获取关于每个流的更多详细信息,比如总视图计数生存期。API 端点参考可在此链接上获得。我们已经学*了如何结合apoc.load.json和apoc.periodic.iterate过程从 API 端点获取信息。
我们应该如何存储附加描述和总历史视图计数信息?它们不是分类变量,每个流只有一个值。我认为将它们存储为节点属性是最有意义的。

将总视图计数和描述存储为节点属性。图片由作者提供。
如上所述,我们结合了apoc.periodic.iterate和apoc.load.json过程来从 Twitch API 端点获取这些信息。
CALL apoc.periodic.iterate(
'MATCH (s:Stream) RETURN s',
'WITH s,
"https://api.twitch.tv/helix/users?login=" + s.name as url,
"Bearer <access token>" as auth, $client_id as client_id
CALL apoc.load.jsonParams(url,
{Authorization: auth, `Client-ID`:client_id},null)
YIELD value
SET s.id = value.data[0].id,
s.total_view_count = value.data[0].view_count,
s.createdAt = datetime(value.data[0].created_at),
s.description = value.data[0].description',
{batchSize:1})
导入 streamer 团队信息
每个 streamer 可以属于 Twitch 上的零个、一个或多个团队。这是我们将在这篇博文中导入的最后一个信息。我将让您稍微思考一下我们应该如何存储一个 streamer 属于哪个团队的信息。我可以给你一个提示,它属于分类变量范畴。每个流可以属于零个、一个或多个团队。Twitch 上的团队数量有限。

Twitch 团队信息的图模型。图片由作者提供。
您可以在图形建模过程中看到重复的模式。需要注意的一点是,您应该尽可能使用不同的关系类型,这一点没有明确提到。您希望避免像 *HAS、*这样的通用关系类型,尤其是当它在许多不同的场景中使用时。

图片由作者提供。
现在,你应该已经熟悉了apoc.periodic.iterate和apoc.load.json程序。同样,我们将使用与之前相同的 cypher 查询结构从 Twitch API 端点检索数据。这里,只有端点 URL 和我们存储响应的方式发生了变化。将apoc.periodic.iterate与值为 1 的 batchSize 参数一起使用的另一个好处是,即使任何 API 请求失败,它也不会终止 Cypher 查询。Neo4j 是一个 ACID 数据库,它会等到整个事务成功后再提交数据。由于我们将每个 API 请求分解到一个单独的事务中,所以我们不会遇到这样的问题:如果一千个请求中只有一个失败,我们就不会将任何信息存储到数据库中。例如,对于大约 1–2%的请求,此端点会返回一个错误。当我们使用参数为 1 的 batchSize 时,我们会忽略这些错误。
CALL apoc.periodic.iterate(
'MATCH (s:Stream)
WHERE exists (s.id) and NOT (s)-[:HAS_TEAM]->()
RETURN s',
'WITH $client_id as client_id,
"Bearer <access token>" as auth, s
WITH s,
"https://api.twitch.tv/helix/teams/channel?broadcaster_id=" + toString(s.id) as url,
client_id,
auth
CALL apoc.load.jsonParams(url,
{Authorization: auth, `Client-ID`:client_id},null)
YIELD value
WITH s, value.data as data
WHERE data IS NOT NULL
UNWIND data as team
MERGE (t:Team{id:team.id})
ON CREATE SET t.name = team.team_display_name,
t.createdAt = datetime(replace(trim(split(team.created_at,"+")[0]), " ", "T"))
MERGE (s)-[:HAS_TEAM]->(t)',
{batchSize:1})
摘要
希望你已经学会了如何借助 APOC 程序在 Neo4j 中有效地刮 API 端点。一步一步地,我们将额外的信息导入到我们的图表中,最终得到了一个描述 Twitch 宇宙的知识图表。

抽动知识图图式。图片由作者提供。
在我的下一篇博客文章中,我将演示如何使用 Cypher 查询语言和图算法来分析这个图。敬请期待!
p.s .如果你想玩 Twitch 图而不用自己导入数据,我准备了一个 Neo4j 数据库转储 包含 1000 万个节点和 2000 万个关系。数据是在 2021 年 5 月 7 日到 9 日之间收集的。
Twitchverse:为节点分类任务使用 FastRP 嵌入
原文:https://towardsdatascience.com/twitchverse-using-fastrp-embeddings-for-a-node-classification-task-bb8d34aa690?source=collection_archive---------27-----------------------
通过使用 FastRP 嵌入算法提取关系的值,以产生用于下游节点分类任务的特征
这是我的 Twitchverse 系列的第三篇文章。前两个是:
- Twitchverse:在 Neo4j 中构建 Twitch 知识图
- Twitchverse:使用 Neo4j 图形数据科学对 Twitch 宇宙进行网络分析
别担心。这篇文章是独立的,所以如果你不感兴趣的话,你不需要检查前面的文章。然而,如果你对我如何构建 Twitch 知识图和执行网络分析感兴趣,可以去看看。你也可以在 Neo4j 中加载数据库转储,所有代码都可以作为 Jupyter 笔记本获得。
议程
在这篇博文中,我展示了如何使用节点嵌入算法 FastRP 作为 ML 分类器的输入。这个想法是基于共同聊天网络来预测流媒体播放的语言。我们将假设,如果用户在多个流中聊天,则这些流很可能以相同的语言广播。然后,我们将使用 FastRP 嵌入来为我们的分类模型设计特征。概括地说,这篇文章可以分为以下几个步骤:
- 数据清理
- 推断共同聊天网络
- FastRP 嵌入
- 评估分类准确性
图形模型

抽动图模式。图片由作者提供。
我们的 Twitch 知识图由流媒体和在广播中聊天的用户组成。还有一些关于流媒体的额外元数据,如语言和他们玩的游戏。

用户在流中聊天的示例子图。每个流有一个指定的语言。图片由作者提供。
这里有一个在流(黄色)中聊天的用户(紫色)的小子图。示例中的两条飘带都以英语(绿色)广播。Twitch 的一个特例是 streamer 可以像普通用户一样,通过在聊天中发表评论来参与其他 streamer 的广播。我们可以观察到在两个流中都聊过的三个用户。两条飘带之间的对话越多,它们就越有可能使用同一种语言。
数据清理
我们将从探索数据集开始。让我们先来看看这些语言以及有多少飘带在广播中使用它们。
MATCH (l:Language)
RETURN l.name as language,
size((l)<--()) as numberOfStreams
ORDER BY numberOfStreams
DESC
结果
在我们的图表中总共有 30 种不同的语言。由于样本量小,我们不得不在分类任务中排除一些语言。我决定排除所有少于 100 条的语言。
MATCH (l:Language)
WHERE size((l)<--()) < 100
MATCH (l)<--(streamer)
SET streamer:Exclude
RETURN distinct 'success' as result
接下来,我们将检查是否有任何飘带用一种以上的语言广播。
MATCH (s:Stream)
WHERE size((s)-[:HAS_LANGUAGE]->()) > 1
MATCH (s)-[:HAS_LANGUAGE]->(l)
RETURN s.name as streamer, collect(l.name) as languages
结果
只有一位流送员分配了一种以上的语言。Gige 用英语和匈牙利语广播。我们已经排除了匈牙利属于的所有少于 100 个 streamers 的语言,所以我们在进一步的分析中将忽略 Gige。
现在,我们将查看知识图中的用户。绘制节点出度分布是有意义的。在这种情况下,out-degree 通知我们用户聊天的流的数量。
MATCH (u:User)
WHERE NOT u:Exclude
WITH u, size((u)-[:CHATTER|VIP|MODERATOR]->()) as node_outdegree
RETURN node_outdegree, count(*) as count_of_users
ORDER BY node_outdegree ASC
结果

节点外向度分布。图片由作者提供。
这个折线图是用 Seaborn 库可视化的。在我们的数据库中有大约 5000 个 streamers,所以最大可能的出度是 5000。这些数据是在三天的时间内获取的。我大胆猜测,在超过 1000 个流中聊天的用户极有可能是机器人。我选择 200 作为实际的阈值,因此超过三天在 200 个流中交谈的用户将被忽略。我认为这已经很慷慨了。要达到这个门槛,你每天必须聊天超过 60 次。
MATCH (u:User)
WHERE NOT u:Exclude
WITH u, size((u)-[:CHATTER|VIP|MODERATOR]->()) as node_outdegree
WHERE node_outdegree > 200
SET u:Exclude
最活跃的版主也极有可能实际上是机器人。
MATCH (u:User)
WHERE NOT u:Exclude
RETURN u.name as user, size((u)-[:MODERATOR]->()) as mod_count
ORDER BY mod_count DESC LIMIT 10
结果
看来我的假设是正确的。大多数高度活跃的版主的名字中都有一个机器人。我们也将排除那些在获取数据的三天内参与超过 10 个流的版主。
MATCH (u:User)
WHERE NOT u:Exclude
WITH u, size((u)-[:MODERATOR]->()) as mod_count
WHERE mod_count > 10
SET u:Exclude
列车测试数据分割
在我们进行训练测试数据分割之前,让我们快速刷新每种语言有多少数据点。
MATCH (l:Language)<-[:HAS_LANGUAGE]-(s:Stream)
WHERE NOT s:Exclude
RETURN l.name as language, count(*) as numberOfStreams
ORDER BY numberOfStreams DESC
结果
到目前为止,最常用的语言是英语。接下来是西班牙语、德语和俄语。出于某种原因,Twitch 决定区分英语和英国英语。我们将不会在分类任务中进行这种区分,并将它们视为相同。相反,我们将把语言写成节点属性,把英语和英国英语合并成一个类别。
MATCH (s:Stream)-[:HAS_LANGUAGE]->(l:Language)
WHERE NOT s:Exclude
SET s.language = CASE WHEN l.name = 'en-gb' THEN 'en' ELSE l.name END
我们将使用每种语言 80%的数据点作为训练集,剩下的 20%用于测试。
MATCH (s:Stream)
WHERE NOT s:Exclude
WITH s.language as language, s
ORDER BY s.name
WITH language, count(*) as count, collect(s) as streamers
WITH language, streamers, toInteger(count * 0.8) as training_size
UNWIND streamers[..training_size] as train_data
SET train_data:Train
为了更容易再现,我添加了按名称排序的行。当然,如果您愿意,可以使用任何随机函数来分割训练测试数据集。
推断共同聊天网络
这里,我们将开始使用 Neo4j 图形数据科学库。如果你需要快速复*如何使用 GDS 图书馆,我建议你查看一下 Twitchverse 网络分析博客帖子。您应该知道,GDS 库使用一种特殊的内存图形来优化图形算法的性能。

经 GDS 文档许可复制的图像。
我们有两个选项来投影内存中的图形。这里,我们将使用 Cypher 投影功能。Cypher projection 是一种更灵活的投影内存中图形的方式,但是加载性能代价很小。我已经写了一篇关于使用 Cypher projections 的详尽的博客,但是现在,知道我们使用第一个 Cypher 语句来投影节点和第二个 Cypher 语句来投影内存图的关系就足够了。
CALL gds.graph.create.cypher("twitch",//node projection
"MATCH (u:User)
WHERE NOT u:Exclude
RETURN id(u) as id, labels(u) as labels,
coalesce(u.followers,0) as followers,
coalesce(u.total_view_count,0) as total_view_count",//relationship projection
"MATCH (s:User)-->(t:Stream)
WHERE NOT s:Exclude AND NOT t:Exclude
RETURN id(t) as source, id(s) as target",
{validateRelationships:false})
在第一个语句中,我们已经投影了所有没有用 Exclude secondary 标签标记的用户节点。添加节点标签允许我们在算法执行时过滤节点。这将使我们能够在计算 FastRP 嵌入时只过滤流节点。我们还包括了跟随器和 total_view_count 节点属性。在第二个语句中,我们投射了用户和 streamers 之间的所有关系。这些关系指示哪些用户在特定流媒体工具的广播中聊天。
为了推断流之间的共同聊天网络,我们将使用节点相似性算法。节点相似性算法使用 Jaccard 相似性分数,根据共享 chatters 的数量来比较一对节点的相似程度。

节点相似度算法示意图。图片由作者提供。
如前所述,一对飘带越是相同,我们就越会认为它们相似。我们将结果关系命名为 SHARED_AUDIENCE ,这正是我们在本例中所做的,评估 streamers 的共享受众。节点相似性算法有两个非常重要的超参数需要调整:
- TopK:一个节点的存储关系数。将存储相似性得分最高的 K 个关系。
- SimilarityCutoff:出现在结果中的相似性得分的下限。分数低于 similarityCutoff 的任何关系将在结果中被自动忽略。
我总是喜欢首先使用算法的 stats 模式来评估相似性得分分布。
CALL gds.nodeSimilarity.stats("twitch")
YIELD similarityDistribution
RETURN similarityDistribution
结果

节点相似度分布结果。图片由作者提供。
我们得到百分位值形式的分布。*均来说,一对流媒体共享大约 3%的用户。只有 10%的流媒体共享超过 6%的用户。*均来说,彩带没有分享很多他们的观众。这可能有点失真,因为数据仅在 3 天内检索,并且仅考虑了参与聊天的用户。我们将把 similarityCutoff 参数保留为默认值 1E-42,这是一个非常小的数字,但比 0 稍大。当一对拖缆共享至少一个用户时,将考虑它们之间的关系。现在,我们必须决定 topK 值。topK 参数会严重影响生成的单部分投影的密集或稀疏程度。经过反复试验,我决定使用 topK 值 25。
CALL gds.nodeSimilarity.mutate("twitch",
{topK:25, mutateProperty:'score', mutateRelationshipType:'SHARED_AUDIENCE'})
FastRP 嵌入
F ast 随机投影,简称 FastRP,是随机投影算法家族中的一种节点嵌入算法。这些算法在理论上得到 Johnsson-Lindenstrauss 引理的支持,根据该引理,可以将任意维的 n 个向量投影到 O(log(n)) 维中,并且仍然近似保持点之间的成对距离。事实上,以随机方式选择的线性投影满足此属性。
抄自 文献 。
如果您想了解更多用于计算节点嵌入的底层数学知识,我建议您查看文档。节点嵌入算法计算图中节点的固定大小向量或嵌入表示。当我们想要在下游机器学*工作流中使用网络功能时,这非常有用。
通过使用下面的 Cypher 查询,我们可以很容易地检索节点的 FastRP 嵌入。
CALL gds.fastRP.stream(
"twitch",
{nodeLabels:['Stream'], relationshipTypes:['SHARED_AUDIENCE'],
relationshipWeightProperty:'score', embeddingDimension: 64}
) YIELD nodeId, embedding
WITH gds.util.asNode(nodeId) as node, nodeId, embedding
RETURN nodeId, embedding, node.language as language, CASE WHEN node:Train then 'train' else 'test' END as split
用 t-SNE 散点图来可视化结果节点嵌入是非常常*的。以下可视化代码以 Jupyter 笔记本的形式提供。

语言着色嵌入的 TSNE 结果。图片由作者提供。
数据点根据其语言进行着色。仅仅通过观察散点图,很明显节点嵌入很好地捕捉了流的语言。好像只有英语有点遍地,其他小语种形成可爱的集群。
分类任务评估
最后,让我们检查一下基于 FastRP 嵌入的广播语言预测有多好。我们已经在前面的步骤中完成了 train-test 分割,所以剩下唯一要做的事情就是导出那些嵌入,并将它们输入到分类模型中。在这个例子中,我们将使用随机森林分类器。我准备了一个助手函数,它将接受一个 cypher 查询,并返回一个分类报告和混淆矩阵作为输出。
现在,我们可以继续输入与上面相同的查询来生成分类报告。
CALL gds.fastRP.stream(
"twitch",
{nodeLabels:['Stream'], relationshipTypes:['SHARED_AUDIENCE'],
relationshipWeightProperty:'score', embeddingDimension: 64}
) YIELD nodeId, embedding
WITH gds.util.asNode(nodeId) as node, nodeId, embedding
RETURN nodeId, embedding, node.language as language, CASE WHEN node:Train then 'train' else 'test' END as split
结果

分类报告和混淆矩阵。图片由作者提供。
在没有对 FastRP 或随机森林算法超参数进行任何微调的情况下,我们得到 86%的 f1 分数。太棒了。看来我们的假设是正确的,即聊天者通常在共享同一种语言的流中聊天。通过检查混淆矩阵,我们可以观察到该模型仅在英语和小语种之间进行了错误分类。例如,该模型从未错误地将朝鲜语归类为葡萄牙语。这是有道理的,因为英语是互联网的语言,所以每个人都可以说至少他们的母语和一点英语。
现在,我们将尝试优化 FastRP 算法的超参数,以实现更高的精度。
关系权重
我在前面的查询中使用了关系权重,因为我们可以从节点相似性算法中获得它们。我们可以用参数输入它们。在试验了这些设置之后,我注意到忽略关系权重属性会产生更好的结果。
CALL gds.fastRP.stream(
"twitch",
{nodeLabels:['Stream'], relationshipTypes:['SHARED_AUDIENCE'],embeddingDimension: 64}
) YIELD nodeId, embedding
WITH gds.util.asNode(nodeId) as node, nodeId, embedding
RETURN nodeId, embedding, node.language as language, CASE WHEN node:Train then 'train' else 'test' END as split
结果

分类报告和混淆矩阵。图片由作者提供。
现在,没有任何东西暗示忽略关系权重总是会产生更好的结果。您应该在数据集上进行测试,并比较结果以做出最终决定。
嵌入尺寸
嵌入尺寸超参数定义输出向量或嵌入的大小。我在文档中找到了一些通用指南:
最佳嵌入维数取决于图中节点的数量。由于嵌入可以编码的信息量受到其维数的限制,所以较大的图往往需要较大的嵌入维数。典型值是 2 的幂,范围在 128-1024 之间。值至少为 256 时,在 105 个节点的图表中会得到较好的结果,但通常增加维度会改善结果。然而,增加嵌入维数会线性增加内存需求和运行时间。
尽管我们的图很小,只有 5000 条流,我还是决定测试不同嵌入维度参数的结果。似乎将嵌入维数参数增加到 512 会产生更好的结果。
CALL gds.fastRP.stream(
"twitch",
{nodeLabels:['Stream'], relationshipTypes:['SHARED_AUDIENCE'],
embeddingDimension: 512}
) YIELD nodeId, embedding
WITH gds.util.asNode(nodeId) as node, nodeId, embedding
RETURN nodeId, embedding, node.language as language, CASE WHEN node:Train then 'train' else 'test' END as split
结果

分类报告和混淆矩阵。图片由作者提供。
迭代权重
我们可以调整的下一个超参数是迭代权重。文档声明如下:
迭代权重参数控制两个方面:迭代次数,以及它们对最终节点嵌入的相对影响。该参数是一个数字列表,指示每个数字的一次迭代,其中该数字是应用于该迭代的权重。
在对迭代权重参数进行了一些试验之后,我发现使用下面的值可以进一步提高精确度。
CALL gds.fastRP.stream(
"twitch",
{nodeLabels:['Stream'], relationshipTypes:['SHARED_AUDIENCE'],
embeddingDimension: 512,
iterationWeights:[0.1, 0.5, 0.9, 1.0, 1.0]}
) YIELD nodeId, embedding
WITH gds.util.asNode(nodeId) as node, nodeId, embedding
RETURN nodeId, embedding, node.language as language, CASE WHEN node:Train then 'train' else 'test' END as split
结果

分类报告和混淆矩阵。图片由作者提供。
归一化权重
另一个可以优化的参数是归一化权重。文档再次声明:
归一化强度用于控制节点度数如何影响嵌入。使用负值会降低高度邻居的重要性,而使用正值会增加它们的重要性。最佳归一化强度取决于图和嵌入将用于的任务。
在我们的例子中,试图优化这个参数是没有意义的,因为所有节点都应该具有完全相同的 25 度。如果您还记得,我们使用了 topK 值为 25 的节点相似性算法,这意味着每个节点都将连接到它的前 25 个邻居。
使用节点属性
FastRP 算法可以扩展到也考虑节点属性。我注意到,如果我们将追随者的数量考虑在内,分类的准确性会稍微增加。看起来追随者计数可能有助于区分英语和其他语言。我猜英国横幅有更多的追随者,但这只是一种直觉。
CALL gds.beta.fastRPExtended.stream(
"twitch",
{nodeLabels:['Stream'], relationshipTypes:['SHARED_AUDIENCE'],
embeddingDimension: 512, featureProperties: ['followers'],
iterationWeights:[0.1, 0.5, 0.9, 1.0, 1.0]}
) YIELD nodeId, embedding
WITH gds.util.asNode(nodeId) as node, nodeId, embedding
RETURN nodeId, embedding, node.language as language, CASE WHEN node:Train then 'train' else 'test' END as split
结果

分类报告和混淆矩阵。图片由作者提供。
结论
我们只使用了网络功能,没有使用其他功能,却获得了高达 90%的 f1 分数。我认为这非常棒,并有助于解决其他任务,从而查看数据点之间的关系可能会提供非常准确的结果。
和往常一样,代码可以在 GitHub 上获得。
Twitter 位置分析
原文:https://towardsdatascience.com/twitter-location-analysis-c488c967a41f?source=collection_archive---------13-----------------------
每天发送超过 5 亿条推文,有可能跟踪社会运动模式吗?

大纽约市都会区| 美国宇航局
推特是一个令人印象深刻的数据来源,推特上有如此多的关于社会情绪的信息。事实上,一些工作已经表明,聚合的推文数据可以作为社会幸福的一个衡量标准!Twitter 的字符限制很短,但却非常流行,听起来像是真实反映社会思想的完美结合。
除了文本方面,推文还可以包含重要的位置信息。某些用户同意与 Twitter 分享他们的推文位置。这潜在地增加了另一层信息。在不久的将来,添加多个实时信息层,如交通流量、事件、来自智能城市基础设施的信号等,对于跟踪日益复杂的社会非常有益。
我写这篇文章的最初目标是从推文中提取位置信息,并分析它们在不同人群中的代表性。毕竟,如果推文是商业案例中社会或客户的一个指标,那么对来自不同社会经济背景的不同人群进行适当采样是很重要的。我会通过比较推文分布和人口普查数据来做到这一点。在实现这个简单目标的过程中,我只走了一部分。事实证明,存在一些问题,因为只有很少一部分用户同意分享他们的详细位置,Twitter 根据推文文本分配位置坐标。
Tweepy 提取推文位置
Tweepy 是 Twitter API 的 Python 包装器。首先让我们加载 python 中的包
import sys
import os
import re
import tweepy
from tweepy import OAuthHandler
from textblob import TextBlob
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
from IPython.display import clear_output
import matplotlib.pyplot as plt
% matplotlib inline
接下来,我们将使用 Tweepy 来验证用户凭证。
# Authenticateauth = tweepy.AppAuthHandler(consumer_key, consumer_secret)
api = tweepy.API(auth, wait_on_rate_limit=True,
wait_on_rate_limit_notify=True)if (not api):
print (“Can’t Authenticate”)
sys.exit(-1)
现在,让我们在我们想要的位置内过滤这些推文。Twitter 提供了几种方法来做到这一点——一个最大长度为 25 英里的边界框或一个最大半径为 25 英里的指定位置,反映了我们想要搜索推文的区域。
tweet_lst=[]
geoc=”38.9072,-77.0369,1mi”
for tweet in tweepy.Cursor(api.search,geocode=geoc).items(1000):
tweetDate = tweet.created_at.date()
if(tweet.coordinates !=None):tweet_lst.append([tweetDate,tweet.id,tweet.
coordinates[‘coordinates’][0],
tweet.coordinates[‘coordinates’][1],
tweet.user.screen_name,
tweet.user.name, tweet.text,
tweet.user._json[‘geo_enabled’]])
tweet_df = pd.DataFrame(tweet_lst, columns=['tweet_dt', 'id', 'lat','long','username', 'name', 'tweet','geo'])
我使用了 Tweepy Cursor 对象,它考虑到了 Twitter 的每页最多 100 个结果的限制,并通过分页解决了这个问题。在第一次试验中,我限制了 1000 条距离 DC 华盛顿中心 1 英里以内的推文,以及那些具有特定经度/纬度信息的推文。
更深入地了解位置
在 1000 个结果中,714 个具有不同的位置信息。但是让我们看得更深一点。

纬度、经度和身份证直方图|塞犍陀·维韦克
有趣的是,只有 80 个不同的纬度/经度对,但每个 tweet 和 Twitter 用户 ID 都是不同的。所以有些奇怪的事情正在发生,所有这些用户都在完全相同的位置是没有意义的。以下是数据框,过滤最常*的经纬度对:

数据集中最常*的推文位置|塞犍陀·维维克
如果你注意到了,你会发现很多推文的文本中都有@华盛顿·DC。Twitter 默认在 DC 的一个中心位置发布任何包含@ Washington DC 的推文。

数据集中第二常*的推文位置|塞犍陀·维韦克
有趣的是,当我过滤第二个最常*的位置时,我再也看不到它了,但我确实看到了包含@ USA 的文本!根据推特,美国是一个稍微低于白宫的地方,在一个公园里!

@美国|塞犍陀·维维克的位置
通过更仔细地查看 Twitter 文档:

Twitter 开发者文档
虽然我想要样本用户的坐标来进行总体移动性分析,但 Twitter 从推文中的位置标签给了我信息。在 DC 最常*的标签是“华盛顿 DC”,其次是“美国”等。另一个问题是,当我将搜索范围扩大到 25 英里的半径时,我在 1000 条推文中获得了 0 条坐标信息,这可能是因为 Twitter 为引用 DC 热门地点的推文分配坐标的方式,而不是远离 DC 中心的那些英里。
下面是详细说明代码的 Google Colab 笔记本:
https://colab.research.google.com/drive/1X9Om4lNGVRG2_LMCndVGErq8UgMKsK1C?usp=sharing
总之,Twitter 提供了巨大的潜力来分析社会模式,包括情绪,流动性和异常现象。然而,当涉及到地理空间分析时,由于数据的稀疏性和提供的位置含义的模糊性,存在一些限制-位置是否代表发出推文的设备的实际位置,或者它们是否对应于推文中引用的地点。
虽然 Twitter 开发人员可以对 Twitter API 进行改进,但对于大规模共享敏感位置数据的隐私问题肯定存在。就我个人而言,我愿意分享我的位置数据,以便进行有益于社会的大规模分析。但是当 Twitter 应用程序问我时,我犹豫了——因为潜在的未知伤害。我们正处于一个类似于当年核能的阶段。粒度数据具有提升社会效益的潜力。同时,作为一个社会,我们需要继续讨论如何实现这些好处,同时防范数据泄露和详细信息的滥用。
如果你喜欢这篇文章,请跟我来——我经常在复杂系统、物理学、数据科学和社会的界面上写作
基于 Keras 和 NLTK 的 Twitter 情感分析
原文:https://towardsdatascience.com/twitter-sentiment-analysis-with-keras-and-nltk-48189967f190?source=collection_archive---------6-----------------------
我们如何学会发现与各种在线实体相关的推文的情感?
社交媒体代表了人们在任何时候都可以获得的关于人们的无穷无尽的信息。困难在于如何利用这些丰富的信息。

在 Unsplash 上视觉拍摄的照片
文本包含了很多信息,我们作为人类很容易提取。然而,对于计算机来说,这要困难得多,因为理解自然语言需要庞大的知识库和上下文。理解这种自然语言会带来巨大的好处,尤其是在情感分析方面。例如,一家公司可能希望利用社交媒体来了解公众对其产品的意*,以了解是否需要改进或公关变化(记住相关偏差,如自我选择偏差)。
数据集
Kaggle [1]上的“Twitter 情绪分析”数据集是大约 74,000 条推文的集合,它们涉及的实体或公司,以及指定的情绪。有了这个数据集,我们可以尝试训练一个分类模型,根据对给定实体或公司的情感对进一步的推文进行分类。
下面给出了该数据集的一个示例。可以看到,有一些错误的数据点,例如标有“积极”的推文,推文的文本只写着“曾经”。这些推文可能会导致分类错误,但由于推文整体长度较短,它们会留在数据集中。
此项目的数据集的前几行示例。
这个数据集涵盖了几个不同的“实体”。一个容易(但不准确,不可靠!)对推文进行分类的方法是查看每个实体最常*的情绪,并预测该情绪!然而,这确实挫败了机器学*和试图理解推文中语言的意义。在接下来的部分,我们将探索一些策略来更好地理解推文中的文字,看看我们是否能比这种猜测做得更好。
基础数据丰富
一键编码
在处理 Tweet 文本之前,我们可以通过我们的模型轻松地将实体类编码成可用的数据。这可以通过一键编码轻松完成,因为数据集中只包含 32 个不同的实体,这样就增加了 32 个新列。这可以通过“get_dummies()”函数使用已经用于托管数据集本身的 Pandas 模块轻松实现:
熊猫一键编码。
通过一键编码,我们允许自己从 Tweet 描述的实体中获得一些洞察力。我们的模型现在将把总体情绪与实体本身联系起来,除了 Tweet 的文本之外还将使用它。
预先训练的情感分析
在我们自己分析文本之前,我们可以采取的一个步骤是使用预先训练的模型来获得对原始文本的一些洞察。这些用于情感分析的预训练模型通常是在比我们将要使用的数据集大得多的数据集上训练的,并且可能从我们构建的模型中提取不同的*解。我们在这种情况下使用的预训练模型是 TextBlob,它是基于 NLTK 构建的。这个模型接受原始文本输入,有两个输出,极性和主观性。我们可以使用下面的代码片段将这些数据提取到新列中:
下面是我们如何用 TextBlob 做预建的情感分析(基于 NLTK!)
更多涉及丰富(文本处理)
语言处理项目的下一步是从文本中提取特征,以便机器学*模型可以更好地理解它。这包括停用词删除、标记化和词干化等步骤。
拆分文本
这是我们将文本拆分成其组成部分的步骤,组成部分通常对应于单个单词。这分两点完成,首先是为了我们可以执行其他步骤,然后是最终确定我们的数据。
停止单词删除
这一步包括删除所有实际上不传达任何信息的常用词。这些词的例子可能包括“the”、“and”和“it”。这些词一般存在于所有自然语言中,并不给出文本情感的任何信息。在大多数情况下,我们可以使用 NLTK 的停用词列表stopwords.words(),但是我们可能想要根据问题的上下文向该列表添加词。
堵塞物
词干是一个稍微复杂一点的话题,涉及到将单词简化为词干。一个单词的词干可以说是它的基本形式。例如,在这一步中,“Drive”和“Driving”都应还原为它们的词干“Drive”。在实践中,这些单词通常被简化为词干“Driv ”,将其解释为人类很奇怪,但仍然是有效的词干,因为两个单词都被简化为同一个词干。当这个奇怪的词干也是文本中出现的一个单词时,可能会出现问题,但这种情况通常很少,不会成为我们模型的主要问题。
我们实际上并没有在这个模型中实现词干来支持引理满足。
引理满足
引理满足是一种目的类似于词干提取的方法,但在某些情况下可能更有效。这种方法试图使用单词的上下文来将它们转换成常*的形式。比如,lemmatisation 要把“是”、“是”、“是”都转换成“是”。不幸的是,lemmatisation 的真正实现通常不能很好地执行,尽管在这种情况下,我们更喜欢它而不是词干。
将文本转换成可用的格式
不幸的是,我们的模型不能只接受字符串作为输入,而是要求我们以某种方式对文本进行编码。这可以通过多种方式实现,本文将探讨其中的两种方法。
文字袋 NLP
我们在这里考虑的第一种方法是最简单的,叫做“单词袋”NLP。此方法不考虑单词的位置,并且仅在给定字符串的任何位置包含单词时才进行编码。我们可以用 Keras 的 tokenizer,通过texts_to_matix()方法来做到这一点。这为我们提供了一个矩阵,每一列对应一个给定的单词,每一行包含一个指示器,显示该行的文本是否包含该单词。该矩阵中的列数由测试的字数决定,该字数在定义标记器时确定。
符号化
在标记化中,我们专注于保持单词的顺序。我们可以使用 Keras 的 tokeniser 的texts_to_sequences()方法来实现这一点。这个方法生成一个整数序列,每个唯一的整数对应于 Tweet 中此时使用的单词。唯一整数的数量由标记器的语料库大小定义,该大小在定义标记器时确定。如果使用的单词之一不在语料库中,则忽略它。通常我们会选择一个相对较大的语料库,所以我们只会错过那些我们无论如何都难以理解的生僻字的信息。
标记化的下一步是填充序列,使它们具有相同的长度,生成大小一致的矩阵输入到我们的模型中。
丢弃数据
然后,包含 Tweet 文本的列被删除,因为有用的信息已经被提取并转换成有用的格式
分类
对于本项目中的分类,由于模型输入的数量和类型都很大,因此使用了通过 TensorFlow 中的 Keras 构建的神经网络。我们使用两种不同的神经网络结构,对应于对文本数据进行编码的不同方法。这就是“单词袋”方法和“标记化 LSTM”方法,这两种方法在下面都有更详细的描述。
单词袋 NLP
对于第一种,也是最简单的方法,我们执行单词袋 NLP。通过这种方法,我们可以从密集(全连接)层构建一个简单的多层神经网络。有了这个,我们就可以使用我们所掌握的所有数据(一次性编码和预先训练的情感分析),来尝试预测情感。
我们定义以下模型来获取我们生成的所有数据。致密层允许相邻层中任何神经元之间的数据传输,而脱落层是为了防止权重增长过大。
在这里,我们构建了一个基本的 Keras [2]神经网络——由一系列密集层组成。
将来自该数据集的所有训练数据插入到该模型中,并在以相同方式编辑的测试数据上运行,我们得到以下混淆矩阵,显示分类的准确性:

混淆矩阵显示了正确(和不正确)分类的测试用例的比例。图片作者。
该矩阵显示了每个可能标签的分类准确度。我们可以看到,该模型在预测负面情绪方面表现最佳,91%的预测正确。这给我们留下了 84.5%的总体准确率——还不错!
象征化 LSTM
这种更复杂的方法使用 LSTM 神经网络,其中我们使用嵌入和双向层来尝试学*上下文中单词的含义(双向),而不是对包含这些单词的句子进行分类。这在情感方面是有用的,例如短语“不错!”传达了与“坏”这个词完全不同的意思。
然而不幸的是,这种方法只能接受标记化的文本序列作为输入,而不能接受任何其他派生的数据。
我们也以不同的方式构建这个神经网络。该网络包含 3 种类型的层:
- 嵌入层
- 双向 LSTM
- 稠密的
嵌入
嵌入层是我们网络的一个非常重要的部分,它允许我们根据周围其他单词的上下文来学*单词的意思。实际上,这一层将每个单词放入一个向量空间,我们将学*这个向量空间的位置以及它周围可能使用的单词。
在这里了解更多关于嵌入图层的信息 [3]
双向 LSTM
双向层是对传统递归神经网络(RNNs)的改进,在这种网络中,数据以给定的顺序传递,因此我们可以从文本中单词的顺序进行学*。在双向层中,这发生在两个方向上,所以我们可以尝试在向前和向后的上下文中学*单词的意思。我们在这个网络中使用 LSTMs(长短期记忆节点),这样我们的网络可以“记住”以前的上下文,也可以“忘记”不相关的信息。对于文本处理等应用,LSTMs 比传统的 rnn 工作得更好,因为它们通过允许渐变不变地通过来解决渐变消失的问题。
密集
网络的最后一层是密集层。这仅仅意味着这一层中的所有节点都连接到前一层中的所有节点,从而可以包括来自任何 LSTM 单元的输入。我们使用 softmax 输出函数和这里的 4 个节点来生成每个潜在输出(每个可能的情感)的概率。
模型建造
用于该分析的神经网络模型构造如下,嵌入层馈入两个双向 LSTM 层,输出密集层。
一种更复杂的双向 LSTM 神经网络的构造。受塞尔吉奥·维拉洪达的文章【4】的启发
那么,这个模型在使用同样的数据时表现如何呢?因为这是一个更先进和最新的方法,我们应该期待更好的性能,对不对?不幸的是,这里的情况并非如此:

同一数据集 LSTM 分类的混淆矩阵。图片作者。
发生了什么事?为什么我们的准确率这么低?
这有几个潜在的原因。首先,我们实际上不知道训练数据中的推文是如何分类的。也许使用了一个单词袋类型分类器,这意味着我们只能复制它。接下来的步骤可能是检查训练和测试数据,看看是否是这种情况,并看看模型在编辑的数据上是否表现得更好。
此外,我们应该知道我们的模型的局限性。双向 LSTM 模型通常需要较长的文本部分来学*单词的上下文,这在推文中是不可能的。双向 LSTM 模型真正出彩的地方是在较长的文本部分,对于评论分类等任务,它的表现要比词袋分类器好得多。因此,我们通常不期望这种模型在 Tweets 上有很好的表现,因为缺乏上下文,单词袋通常可以做得很好。
结论
事实证明,我们可以用“标准的”单词袋分类器对推文进行相当好的分类。我们可以推测,这在很大程度上是由于推文中缺乏上下文,这意味着更复杂的句子结构难以出现。
如果我们与分类器中提到的实体之一有联系,我们可能希望设置它来自动检测人们对我们的产品或服务的意*!这可以为人们的想法提供真正有价值的*解,而不必再手动收集数据。
研究更高级的方法,如预训练的 BERT(来自变压器的双向编码器表示)模型,可能会产生比我们在这里得到的更好的结果!如果你想改进这个模型,BERT 很可能是你开始的地方!
代码库
这个项目的代码库可以在 GitHub 这里找到,或者在下面的链接:【https://github.com/Cameron-Watts/Twitter_Sentiment_Analysis】T2
参考
[1]激情-nlp,Twitter 情绪分析,[第二版] (2021),https://www . ka ggle . com/jp 797498 e/Twitter-entity-情操-分析。
[2] Chollet,f .等人,Keras (2015),https://github.com/fchollet/keras。
[3] J. Brownlee,如何用 Keras 使用 Word 嵌入层进行深度学* (2017),https://machinelingmastery . com/Use-Word-Embedding-Layers-Deep-Learning-Keras/。
[4] S. Virahonda,关于深度学*和 Keras 的情感分析的简单教程 (2020),https://towards data science . com/An-easy-tutorial-about-sensation-Analysis-with-Deep-Learning-and-Keras-2bf 52 b 9 CBA 91
Python 中需要了解的两个很酷的函数
原文:https://towardsdatascience.com/two-cool-functions-to-know-in-python-7c36da49f884?source=collection_archive---------1-----------------------
了解如何使用 Python 中的 tqdm 制作表格和显示进度条

埃菲社在 Unsplash 上拍摄的照片
Python 中有一些特定的函数可以执行独特的功能,很多 Python 程序员可能不知道。知道它们可能不是绝对重要的,但是它们可以执行一些有用的功能。
在本文中,我们将简要讨论两个这样的函数: 制表 和 tqdm 。
用制表软件创建表格
制表 函数位于制表库中,可用于在 Python 中创建格式良好的表格。
我们首先安装制表库:
pip install tabulate
然后在我们的代码中导入 制表 函数:
from tabulate import tabulate
制表 功能可以将许多不同的东西转换成易于阅读的纯文本表格,如列表列表、可重复项字典和其他。
例如,如果我们有下面的列表列表:
**table** = [['First Name', 'Last Name', 'Age'], ['John', 'Smith', 39], ['Mary', 'Jane', 25], ['Jennifer', 'Doe', 28]]
我们可以使用 制表 函数将其转换成可读性更好的纯文本表格:
print(tabulate(**table**))

由于列表的列表中的第一个列表包含列名作为其元素,我们可以通过将‘first row’作为 headers 参数的参数传递来将其设置为列名或标题名:
print(tabulate(**table**, headers='firstrow'))

制表 函数还包含一个 tablefmt 参数,它允许我们使用伪图形来改善表格的外观:
print(tabulate(**table**, headers='firstrow', tablefmt='fancy_grid'))

我们可以使用下面的iterables 字典创建上面的相同表格:
**info** = {'First Name': ['John', 'Mary', 'Jennifer'], 'Last Name': ['Smith', 'Jane', 'Doe'], 'Age': [39, 25print(tabulate(**info**, headers='keys', tablefmt='fancy_grid'))

如果我们在表中有丢失的值,我们可以通过为 missingval 参数传递一个参数来填充它们。
更全面的概述了 制表 功能:
使用 tqdm 显示进度条
tqdm 函数,来自 tqdm 库,允许我们用 Python 显示智能进度条。
我们首先安装 tqdm :
pip install tqdm
然后我们在代码中导入 tqdm 函数:
from tqdm import tqdm
要使用 tqdm 函数来显示 Python 循环的进度条,我们只需用tqdm(iterable)包装任何可迭代对象。
让我们来看一个朱庇特笔记本中的例子:

我们用 tqdm 函数包装了 iterable ,在本例中是 range 对象。在 Jupyter 笔记本单元格下方可以看到进度条。当循环的运行时,显示*{已用时间}<{剩余}时间*,以及每秒迭代次数。
我们还可以使用***【tqdm】来显示进度条,这些进度条带有遍历一个 iterable 的函数,比如映射*、过滤和减少函数。
如果您在 Jupyter Notebook 中工作,您可以从 tqdm.notebook 子模块中导入 tqdm 函数,它提供了一个更具视觉吸引力的进度条,其中包括一些颜色提示(蓝色表示正常,绿色表示已完成,红色表示错误/中断,浅蓝色表示无预计到达时间) :
from tqdm.notebook import tqdmdef add(**num**):
return reduce(lambda x,y: x+y, tqdm(range(**num**+1))) if type(**num**) == int else 0

如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名媒体成员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你用我的 链接 报名,我会赚一小笔佣金。
https://lmatalka90.medium.com/membership
我希望你喜欢这个关于 制表 和tqdm函数的简短教程。感谢您的阅读!
ML 服务级性能监控的两个要素
原文:https://towardsdatascience.com/two-essentials-for-ml-service-level-performance-monitoring-2637bdabc0d2?source=collection_archive---------20-----------------------
优化 ML 服务延迟和 ML 推理延迟的指南
在过去的十年中,对机器学*重新产生兴趣的浪潮鼓励了无数的研究人员试图用最先进的机器学*技术来解决问题。感觉就像每个月都有一些论文发表,用机器学*的新方法来解决以前不可能完成的任务;然而,在研究实验室之外,使用机器学*来提供新体验的应用也出现了爆炸式增长。
在生产机器学*的过程中,该领域已经发现了一系列工程团队正在努力解决的新问题。为了让一个 ML 系统成功,仅仅理解进出 ML 系统的数据或监控其性能是不够的。当被视为一个整体服务时,ML 应用程序也必须通过其整体服务性能来衡量。
在这篇文章中,我们将通过分解如何测量和改进服务级 ML 性能来讨论这个经常被忽视的领域。

作者图片
让我们从分解我们所说的 ML 系统的服务水*性能开始。本质上,我们将要讨论两个重要的度量:服务性能和模型性能。
ML 服务延迟是将模型加载到内存中、收集必要的数据以及计算模型进行预测所需的特征所花费的时间。服务性能还包括用户意识到模型做出的决定所花费的时间。
最大似然推理延迟是指一旦你的模型得到输入,它做出预测所需的时间。
在实时系统中,这两个指标都会增加用户感知的应用程序延迟。因此,不仅要监控这些服务级别性能指标,还要在减少应用程序延迟方面取得切实进展,这一点非常重要。
让我们首先来看看您可能希望监控和改进哪些方面,以使您的服务更具性能。
优化 ML 服务延迟
输入特征查找
在模型甚至可以做出预测之前,所有的输入特征必须由 ML 系统的服务层收集或计算。一些特征将由调用者传入,而其他特征可能从数据存储中收集或实时计算。
例如,预测客户对广告做出反应的可能性的模型可能会获取该客户的历史购买信息。当客户自己查看页面时,他们不会提供这些信息,但是模型服务会查询数据仓库来获取这些信息。采集输入要素通常可分为两组:
- 静态特征:不太可能快速变化,可以提前存储或计算的特征。例如,可以提前计算客户的历史购买模式或偏好。
- 实时计算特征:需要在动态时间窗口内计算的特征。例如,在预测食品配送的 ETAs(预计到达时间)时,您可能需要知道在过去的一个小时内有多少其他订单。
实际上,模型通常混合使用静态和实时计算特征。监控每个特性所需的查找和转换对于跟踪 ML 系统中延迟的来源非常重要。请务必记住,输入要素查找阶段的服务级别性能仅与最慢的要素一样好。
预计算预测
在某些用例中,可以通过预计算预测、存储预测并使用低延迟读取数据存储来提供预测,从而减少预测延迟。例如,流媒体服务可能会提前计算并存储对其服务的新用户的推荐。
这种类型的离线批量评分作业可以极大地减少服务环境中的延迟,因为在调用模型之前就已经完成了大部分工作。
例如,像网飞这样的流媒体服务所使用的推荐系统可以预先计算出你在不使用该服务时可能喜欢的电影或电视节目,这样当你下次登录时,你会很快看到一些个性化的内容,而不会出现漫长的加载屏幕。
优化 ML 推理延迟
降低复杂性
既然我们已经了解了服务性能,那么让我们把注意力转向如何监控和改进您的推理延迟。
优化模型预测延迟的一种方法是降低模型的复杂性。降低复杂性的一些示例可以是减少神经网络中的层数、减少决策树中的级别,或者修剪模型中任何不相关或未使用的部分。
在某些情况下,这可能是对模型功效的直接权衡。例如,如果决策树中有更多级别,则可以从数据中捕获更复杂的关系,从而提高模型的整体有效性。但是,减少决策树中的级别可以减少预测延迟。
*衡模型的功效(准确度、精确度、 AUC 等)。)及其所需的操作约束,对于部署任何模型都很重要。这对于嵌入在更受限的移动设备上的模型变得尤其相关。
并行化
除了降低模型的复杂性之外,您还可以做一些事情来提高模型在生产中的性能,那就是重新设计您的模型,使其更具并行性。如果模型的一部分不依赖于模型的另一部分的输出,为什么不同时运行这两个部分呢?

作者图片(阿里泽·艾)
cloud-ML 行业正在转向高度可扩展的按需云,它允许你利用专业计算机的足球场来运行你的模型。同样,移动处理器正在将其芯片的很大一部分专用于机器学*加速器,这允许开发人员利用其模型推理管道的并行特性。
如果您有能力在预测时将更多的核心投入到问题中,那么您可以利用模型的并行特性来加快预测时间。如果您不研究如何以更*行的方式重新设计您的模型,您可能会放弃性能。
外卖食品
虽然传统的模型监控对于衡量和改进你的机器学*应用程序至关重要,但它并不能捕捉到用户如何体验你的应用程序的全貌。*服务水*性能指标很重要,*对于您的用例来说,将您的准确性提高 1%而导致 500 毫秒回归的更改可能不值得!
如果您看不到您对系统所做的每一个更改所做出的权衡,您将会慢慢地将您的模型埋葬在一堆小的性能退化中,最终形成一个缓慢而笨拙的产品。不要担心:有许多技术可以诊断性能问题,并最终提高您的模型的服务级别性能,但首先您必须开始关注毫秒。
联系我们
如果这篇博客引起了你的注意,并且你渴望了解更多关于机器学*可观察性和模型监控,请查看我们的其他博客和关于 ML 监控的资源!如果您有兴趣加入一个有趣的 rockstar 工程团队,帮助模型成功生产,请随时联系我们,并在此处找到我们的空缺职位!
基于内容的推荐系统的两个例子
原文:https://towardsdatascience.com/two-examples-of-a-content-based-recommendation-system-with-the-most-efficient-array-functions-93899113a890?source=collection_archive---------19-----------------------
基于内容、加权的基于内容的数字函数

照片来自米哈尔·马特隆在 Unsplash
今天我想讨论两个基于内容的推荐系统的例子,以及我从中学到的一些有效的数组函数。这两个例子是
1:基于项目内容推荐
2:基于加权内容推荐
我使用一个简单的电影集作为例子,希望将重点放在主要过程上,而忽略其他过程和特殊情况。让我们开始吧。
数据集准备:
使用以下代码生成两个数据集:movie_df 和 review_df
这两个表为:


方法一:基于电影内容,当内容相似度大于 0 时,为每个用户做推荐。
在这里,我们可以用于电影的内容只有类型。对于基于内容的推荐系统技术来说,以列表格式保存风格并不是最佳选择,我们将使用 One Hot 编码技术将风格列表转换为一个向量,其中每一列对应于一个可能的特征值。
每种类型都用“,”分隔,所以我们只需调用 split 函数

步骤 1:计算电影-电影相似度矩阵:

点积显示了电影之间的相似性。
第二步:寻找相似电影:这里的标准是如果有关系那么选择推荐为小数据集。
我给出的标准是,如果两部电影相关(点积大于 0),值不重要。下面还给出其他标准,这些标准只选择相似性的最高值。
np.where() 显示项目在表格中的位置(索引)。
对 movie_id =1 进行测试:

与《玩具总动员》类似的电影是《超人》,其类型是儿童。结果在意料之中。
然后得到一个电影名称列表,如果电影的名称是一个列表:
第三步:为特定用户做推荐:
对 user_id=100 进行测试

两部都是剧,因为用户 100 也评论过剧《超人》,所以推荐有道理。
方法 2:基于加权含量
方法 1 很容易理解,但似乎没有使用评级信息。现在我想整合信息来计算加权流派。
例如,我想根据用户的评分来构建加权流派。让我们选择 user_id=100。
步骤 1:过滤掉用户 100 评价的电影,只得到流派:

第二步:获取该用户的加权流派:

第三步:获得推荐(也包括用户评论)

该 rec_movies 显示了加权流派≥0.5 的所有推荐电影,但也包括用户已经评论过的电影。
第四步:过滤已评论的电影

在这种情况下,由于用户 100 的 minari 的加权流派是 0.2,所以它被排除在推荐之外。
概要:
- 从这两个案例中,我们可以看到,没有评论的体裁是不会被推荐的,这是基于内容的推荐系统的特点。它对用户来说是高度个性化的。
- 在某种程度上,推荐系统就像一门艺术,你也可以创建自己的标准来适应你的目标,就像在这个故事中,我展示了不同的标准,甚至是相同的方法。
- 有一些我认为在处理推荐系统时非常有效的数组函数,我想在这里再次总结一下:
-
- np.setdiff1d() :这个函数可以找出两个数组的区别。即使你有一个列表,你也可以把它转移到一个数组中使用。
- 2)NP . dot(NP . transpose()):这个点积不仅可以用于项本身,还可以用于得到加权项。
-
- np.where() :这里我用它来查找物品的位置(索引)。
- 当然,你也可以把它们推广到其他情况,而不仅仅是推荐系统。由于限制,我没有足够的时间来展示这些函数是如何高效的,我将在本故事中详细解释它们。
感谢您的阅读。
Python 中需要了解的两个函数
原文:https://towardsdatascience.com/two-functions-to-know-in-python-bfb925bb5fff?source=collection_archive---------27-----------------------
了解如何使用 Python 中的 any() 和 all()函数

照片由 Gema Saputera 在 Unsplash 上拍摄
所有 Python 程序员都应该知道 和 和 或 运算符在 Python 中是什么,以及如何使用它们。然而,有时有更好的方法来完成这些操作员执行的相同任务。
在本文中,我们将回顾两种这样的方法: all() 和 any() 函数,它们提供了更简洁、更易于阅读和解释的代码。
满足条件
假设有一个数据科学职位的招聘信息。该职位要求具备以下所有条件:至少 10 年 SQL 经验,12 年机器学*经验,8 年统计分析经验。换句话说,如今对入门级级数据科学职位的典型要求是*。*
逻辑积算符
我们可以编写一个函数,利用候选人多年的经验,通过使用 和 运算符返回 真 或 假 来检查候选人是否满足所有要求:
**def** is_qualified(sql, ml, stats):
**if** (sql >= 10) **and** (ml >= 12) **and** (stats >= 8):
**return True
else:
return False**
上述函数使用 和 运算符来检查所有条件或操作数是否为 真 。如果所有表达式评估为 真 ,那么 和 运算符将返回 真 。
所以如果一个候选人有 11 年的 SQL 经验,12 年的机器学*经验,9 年的统计分析经验,函数会返回 真 :
is_qualified(11, 12, 9)
# True
但如果另一个候选人有 9 年的 SQL,12 年的机器学*,9 年的统计分析经验,函数会返回 False :
is_qualified(9, 12, 9)
# False
all()函数
编写这个函数的另一种方法是用https://docs.python.org/3/library/functions.html#all函数代替。
全部(可重复)
all() 函数接受一个可迭代对象,比如一个列表,并检查该可迭代对象中的所有元素是否都是 真值 。换句话说,如果所有元素评估为 True ( 或者如果 iterable 为空),则 all() 将返回 True 。
记住,真值是指任何评估为真值的值(而假值是任何评估为假值的值)。
由此,我们可以将上面的*is _ qualified()*函数改写如下:
****def** is_qualified(sql, ml, stats):
requirements = [
sql >= 10,
ml >= 12,
stats >= 8
]
** return all(**requirements**)****
我们创建一个包含表达式的列表,这些表达式需要为 真 才能使候选人有资格获得该职位。如果 需求 中的所有元素都求值为,那么 all( 需求 ) 求值为真 返回。这是编写这个函数的一种更干净、更直观的方式。****
or 运算符
假设另一个招聘启事只要求以下其中一项:至少 10 年 SQL 经验,或者 12 年机器学*经验,或者 8 年统计分析经验。
我们可以编写一个函数,通过使用 或 运算符来检查其中任何一个是否为:**
******def** is_qualified(sql, ml, stats):
**if** (sql >= 10) **or** (ml >= 12) **or** (stats >= 8):
** return True
else:
return False**is_qualified(11, 11, 7)
# Trueis_qualified(9, 10, 7)
# False****
我们在上面的函数中使用了 或 运算符。如果其中任何一个表达式的计算结果为 真 ,则 或 运算符将返回 真 。如果所有表达式评估为 假 ,则 或 运算符返回 假 。
任意()函数
同样,还有一种更简单的方法,那就是使用any()函数。
任何(可重复)
顾名思义, any() 函数接受一个 iterable,并检查是否有任何元素的值为 True 。如果至少有一个元素是True***(计算结果为 True ),那么它将返回 True 。***
如果 iterable 为空,any()函数返回 False。如果 iterable 为空,all()函数将返回 True。
*****def** is_qualified(sql, ml, stats):
requirements = [
sql >= 10,
ml >= 12,
stats >= 8
]
**return any(**requirements**)*****
就是这样! any() 函数将检查需求中的任何元素是否评估为 真 。如果是,则返回 真 。如果没有一个元素评估为 真 ,那么它将返回 假 。
绕过
无论是 any() 和 all() 都会在它们知道返回什么的那一刻让短路执行。换句话说,如果 all() 函数遇到一个False值,那么它会立即返回 False 。而如果 any() 函数遇到一个 Truthy 值,那么它会立即返回 True 。因此,并不总是需要消耗整个 iterable,从而提高性能。
为什么会出现这种情况的原因可以在 any() 和 all() 的 Python 实现中看到:
*****def** all(iterable):
**for** element **in** iterable:
**if** **not** element:
**return** **False**
**return** **True****def** any(iterable):
**for** element **in** iterable:
**if** element:
**return** **True**
**return** **False*****
在上面的 all() 函数中,如果一个元素的计算结果为 False ,则该函数返回 False (从而停止迭代 iterable)。记住返回语句将结束一个函数的执行。
在上面的 any() 函数中,如果一个元素的计算结果为 True ,则该函数返回 True (从而停止迭代 iterable)。
如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名媒体会员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你用我的 链接 注册,我会赚一小笔佣金。
***https://lmatalka90.medium.com/membership ***
我希望这篇关于 any() 和 all() 函数的简短教程是有帮助的。感谢您的阅读!
🥈双层推荐系统方法论:一个获奖的解决方案
原文:https://towardsdatascience.com/two-layered-recommender-system-methodology-a-prize-winning-solution-c4bdb815b156?source=collection_archive---------26-----------------------
了解如何将简单的算法结合到强大的推荐引擎中

丹尼斯·简斯在 Unsplash 拍摄的照片
2020 年 11 月 14 日至 22 日举行了一场电影挑战赛黑客马拉松。它致力于为在线剧院 sweet.tv 创造解决方案。参与者可以从三个项目中选择一个:
- 挑战 1——电影推荐系统;
- 挑战 2——电视节目推荐系统;
- 项目竞赛。
我设法为挑战 2 创造了一个获奖的解决方案,并决定分享我的方法。
📃任务
任务是根据每个用户的观看历史来预测他最喜欢的 5 个电视节目。如果用户观看了电视节目的 80%以上并且没有更换频道,则认为该电视节目被观看了。
使用 Kaggle 确定解决方案的准确性。在这里你可以查看更详细的任务描述、数据和最终排行榜。
给了 20 周的用户日志来训练我们的模型(从 3 月初到 7 月底)和一些关于电视节目的附加信息。Kaggle 用了 12 周的时间进行公共/私人测试,用户各占一半。还有测试日期的电视节目时间表。

浏览日志(作者图片)
组织者使用 MAP@5 metric 检查了模型的准确性,我也将其用于本地维持验证:

使用*均精度@K 绘制@ k 度量图(图片由作者提供)
⚒方案
第 1 部分—基本算法
算法 1。假设——用户将继续观看相同的电视节目。

算法 1 示例(作者图片)
这个基线解决方案非常简单:我们需要根据观看次数计算前 5 名的节目:
- 如果用户一次观看了电视节目总长度的 50%以上,则电视节目被视为已观看;
- 通过将来不在电视节目中的节目过滤结果;
- 如果用户一生中总共观看的电视节目少于 5 个,请在他的预测中填入最受欢迎的电视节目。
该解决方案在保持数据上进行本地验证,Kaggle MAP@5 的精度= 0.41296 。
➕简单快速的解决方案,良好的基线精度。
➖算法没有考虑用户可能的偏好,也不能预测用户没有看过的电视节目。
**算法二。**假设——用户会观看与他喜欢的电视节目相似的电视节目。

算法 2 示例(图片作者)
推荐任务的一个经典例子。为了解决这个问题,我创建了一个用户和电视节目的矩阵,并训练了一个协作过滤模型。然后我们只对每个用户进行前 5 个预测。我使用了 LightFM 来创建带有 WARP metric 的模型,并对维持数据进行了轻微的超参数调整。
➕算法基于相似用户考虑可能的用户偏好,这保证了预测不限于先前观看的节目。
➖精度比第一种方法稍低一些(可能有一种方法可以提高它,但是调整的时间有限)。另一个缺点是很难使用电视节目和用户参数,尽管 LightFM 库为其提供了功能。
第 2 部分—第二层模型
方法论。到目前为止,我们只使用了观看电视节目的事实,所以我们需要一种使用更多参数和一些机器学*的方法。
为了解决这个问题并提高解决方案准确性,经常使用第二层模型,该模型根据查看概率对相关项目进行优先级排序。在这项任务中,我采用了以下方式:
- 使用基本算法(来自本教程的第 1 部分)为每个用户生成相关的电视节目(大约 200 个就可以了)。前 N 项我们从算法 1 得到,因为它的准确率更高。其余 M 项(200 — N = M)从 LigthFM 的算法 2 中得到;

为一个用户生成相关程序(N = 200)(作者的图像)
- 收集特征来训练助推模型,更多信息在下面;
- 训练二进制分类 LightGBM 模型——哪些相关的电视节目用户观看了维持数据;
- 对于测试数据,还收集特征并使用训练模型来为每个用户区分电视节目的优先级;

基于相关节目的观看概率对其进行排序(图片由作者提供)
- 为每个用户获取前 5 个相关的和可能观看的项目;
增加二层模型精度的日志。
作为基本特征,我用不同的参数记录了用户观看电视节目的次数:节目时间的 30%,50%,80%。我还添加了基于观看次数的电视节目排名。导致了 MAP@5 = 0.43128 。
使用频道号和节目类别(分类特征) MAP@5 = 0.43302。
加上用户观看电视节目的频率、自用户被创建以来的时间、自最后一次观看以来的时间,得到 MAP@5 =0.43565。
使用 LightFM 库中的电视节目排名和 user _ bias/item _ bias 特征给出了 MAP@5 =0.43823。
描述电视节目时间表将如何改变(时间减少/增加)的特征给出了 MAP@5 =0.44075。
使用 hyperopt 对 LightGBM 模型进行超参数搜索,将精度提高到 MAP@5 =0.44173。
过滤节目,只保留那些被观看 10 次以上的节目,减少了数据量,去除了不相关的项目,精度提高到 MAP@5 =0.44203。
就是这样!在最终的公共排行榜上,这个解决方案在决赛前一直名列第一,但在最后一天,一个团队最终战胜了我的解决方案。经过私人测试,我的解决方案停留在第二位,与第一位相差很小,与第三位相差很大,精确度 MAP@5 =0.42905。
热门功能—用户观看时间、LightFM 的用户功能、日程更改。
如果你感兴趣,这里的代码是https://github.com/ndmel/2nd_place_recsys_cinema_challenge_2020。
🔮改进方法
- 根据观看的时间和日期对用户档案进行细分。将其与电视节目时间表相结合,进一步个性化推荐。
- 使用更复杂的第二层模型,比如 LambdaRank 而不是二进制分类(LightGBM 中也有)。
- 当新用户没有观看历史时,解决冷启动问题。我们可以找到相似的用户,并结合他们的口味来预测相关的电视节目(改进 LightFM 方法)。
⭐有趣的事实
- 比赛只持续了 4 天,所以我只能尝试基本的假设和易于实现的特性;
- 本地抵制验证与 Kaggle 排行榜高度相关,因此在私下测试后几乎没有任何变动。
两个最著名的编码面试问题解释
原文:https://towardsdatascience.com/two-of-the-most-famous-coding-interview-questions-9746a4111011?source=collection_archive---------1-----------------------
大科技公司最喜欢的两个用简单英语简化的编码面试问题。
如果你进入 IT 行业,热爱编码,你大概知道什么是编码面试,成功通过面试需要做多少工作,更不用说准备面试本身了。对于那些不知道的人来说,这实质上就像是进行一次测试。面试官给了你一个特殊的问题,你必须想出一个解决方案。有时候,编码面试很容易,但大多数时候,它们属于中等难度到极其困难的范围。当然,当你去像亚马逊和谷歌这样更著名的公司面试时,编码面试是具有挑战性的。人们在面试前花几个月的时间练*和学*不同的方法来处理不同的面试问题,以便在面试中有一个解决方案的想法。你几乎可以说这就像给一所大学进行入学考试或 SAT 考试。申请的名校越多,考试越复杂,录取越有挑战性。因此,需要提前做更多的准备。
然而,当人们在面试前几个月就开始练*时,是什么让面试编码问题变得如此复杂和有趣呢?除了通过练*来获得对自己编码能力的信心,大多数程序员练*他们的编码面试问题,因为在面试中,面试者会寻找一个有效的解决方案。当我说高效时,我指的是在性能方面,或者换句话说,时间和空间复杂性方面。时间复杂度是一个表达式,它总结了程序的性能以及计算机完成或运行所编写的任务需要多长时间。类似地,空间复杂性也是如此。然而,这是一个总结运行任务需要多少内存的表达式。
如果你想了解更多关于时间和空间复杂性的知识,请点击德克萨斯大学的数据结构讲座 复杂性分析 。
本质上,当您遇到一个需要许多“子任务”来创建一个成功的“主任务解决方案”的问题时,保持时间和空间的复杂性可能是一个挑战,因为需要考虑多个过程。此外,就解决方案的有效性而言,公司喜欢清晰简洁的解决方案。我的意思是,这些解决方案并没有被过度设计。比方说吧;我们在解一道数学题。写下不必要的注释和段落,说明我们为什么要做每一步(比如加法),会让解决方案变得凌乱不堪,塞满了信息,难以理解和阅读(假设我们的解决方案很长)。同样的事情也适用于编码。面试官寻找开箱即用的解决方案,可以在任何给定的输入下保持相同的性能(当然,面试官还会考虑更多因素,但这些只是基本因素)。虽然,就像效率一样,当有大问题需要解决时,包括各种要编程的“子任务”,保持代码的整洁和简洁是很困难的,因为自然地,会有很多关于解决方案和解决方案的多个过程的解释要向面试官做(这是受访者考虑的另一个因素,接收者能多好地解释他们的代码)。但是,这就是为什么程序员不断地练*几个月来为面试做准备。毕竟,成千上万的开发人员在大型科技公司和初创企业工作,这意味着在任何公司成功编写面试代码都不是不可能的。
就像学校里的科目和数学里的单元一样,我们可以把问题分成不同的科目。编码问题中的一个流行主题字面上叫做“流行的编码面试问题”它们被称为流行的编码面试问题,因为许多开发人员在大公司*过它们。在本文中,我将讨论我个人最喜欢的编码面试问题之一,也是最流行的关于树的编码问题之一,它是最大宽度和深度。起初,这听起来很容易解决,但这个问题引起许多开发人员(这也是它受欢迎的原因)和我的原因是因为它的抽象解决方案。有多种方法可以创建高效和有效的算法,这真正考验了开发人员的思考和解决问题的能力。比如像谷歌、亚马逊等公司。之前已经有过这些面试问题,所以知道如何解决是一个很重要的问题。当你想一想,为什么这个问题在每个开发者的雷达下是有意义的;可以让他们亮一盏灯,强调自己解决问题的能力。

二叉查找树图片的最大深度和宽度图|作者
面试问题本身很容易理解。给定一棵树,求其最大宽度和深度。虽然从概念上理解问题的要求很简单,但是需要一点时间(几分钟而不是几秒钟)来头脑风暴如何编码一个合适的解决方案。我的解决方案有点古怪,但我让两种算法在一天结束时线性工作。我所说的古怪是指,根据定义,宽度优先搜索算法在横向计算节点时效果最好,深度优先搜索算法在试图计算树的高度时效果最好。因此,您可能知道什么算法应该用于什么问题。通常,宽度优先搜索算法将最好地找到树的最大宽度,而深度优先搜索算法将最好地找到最大深度。这两种算法在性能上都是线性时间运行的,这意味着我们不必考虑二叉树遍历的其他复杂算法。然而,对于我的解决方案,我反其道而行之。为了找到树的最大宽度,我使用了深度优先搜索算法,并且对于最大深度,宽度优先遍历。虽然我的解决方案可能看起来与“公认的一般解决方案”相反,但我确实将我的两个算法都保持在线性时间。

BFS 和 DFS 算法可视化|作者图片
因为我首先提到了最大宽度,所以我将从更深入地谈论我对那个问题的解决方案以及我如何利用最大深度来获得优势开始。
最大宽度解决方案
首先,使用深度优先算法,通过递归遍历树的深度,我得到了每个节点的每条路径的所有不同排列。然后,我将每个排列添加到一个单独的数组中,因为我们将假设数组的每个索引代表一个特定的级别。例如,设[a,b,c]是我们深度优先搜索算法返回的某个排列的数组。我们可以将每个索引视为树的某个级别:

作者级别视觉|图像索引
我们这样做是因为我们的深度优先搜索算法返回了遍历路径的深度。因此,如果算法遍历每个深度一直到叶节点,则每个路径必须在表示每个级别的每个索引方面是对称的。

注意两个返回数组的索引是相同的
我们也可以用我们的第二个函数.width_counter()来证明这一点。将所有排列格式化为一个 2D 数组,然后我们基于相似的索引拆分每个列表中的每个元素。例如,索引 0 处的所有元素都将放在索引 0 处的列表中,然后索引 1 处的所有元素都将放在索引 1 处的列表中,依此类推。这被称为分割,这是一个先进的计算机科学概念,我们根据特定条件分割一个数组或一系列值。在分区过程之后,我们将看到一个返回的数组,其中的子数组包含基于索引排序的元素。我们可以通过简单地比较树形图和列表中的元素来仔细检查返回的数组是否正确。如果树的每一层都有与该索引中的每个列表相同的节点(再次假设索引是级别),我们知道我们做得对,因为我们的数组只是一个格式不同的树。

请注意每个子数组与作者的每个级别|图像是如何相似的
我们算法中寻找最大深度的最后一步是比较 2D 数组中每个数组的长度,最大的数组(长度最大的数组)将是最宽的级别。在这种情况下,因为我们正在比较 2D 数组中的每个索引,所以我们只是简单地返回索引。这仍然给出了正确的答案,因为我们前面提到的定义是,级别与每个置换数组的索引相同。就整体性能而言,我们设法在O(n)时刻保持深度优先搜索算法不变,在O(n^2)时刻保持.width_counter()不变,因为嵌套迭代创建了一个 2D 数组。
转到我们的最大深度解决方案,我们找到最大深度的方法非常类似于最大宽度的第一个解决方案。然而,如前所述,我们没有使用 dfs,而是使用 bfs 来跟踪我们的深度。我们首先使用面包优先搜索的原因是为了计算由于算法的横向移动行为而向下一层的次数。

作者图片
这个解决方案很酷的一点是,不像第一个解决方案那样寻找最大宽度来比较每一层,我们不比较任何数组或任何路径。相反,我们采用遍历方法。
当你看到我的解决方案时,它真的没有任何特别之处——它只是原始深度优先搜索算法的修改版本。它不是遍历树直到它满足特定的目标值,而是遍历树直到它的队列为空。此外,为了保持深度的精确计数,当我们接近一个父索引时,我们只给counter(保存深度计数的变量)加 1。为了知道我们是否到达了一个父索引,我们使用二叉树的基本定义,即:每个父节点在最大值处必须有两个子节点。因此,在我们的迭代过程中,只有当我们在第一次迭代过程中位于根节点上(将根节点包括在我们的计数中)或者当弹出它的最近值后队列的长度等于 2 时,我们才给counter加 1。另一种更稳定的查找父索引的方法是将每个节点追加到一个数组中。使用堆等式找到父索引index // 2,我们可以准确地跟踪哪些节点是父节点。因此,我们可以再次迭代该树,并在每次遇到使用等式找到的父节点之一时将 1 加到counter 。这是一个伟大的解决方案;然而,与我们的仅修改 dfs 算法的简单解决方案(在线性时间运行)相比,备选解决方案将在二次时间运行。
查看我的 Github 解决方案和它们的测试用例:https://github.com/GEEGABYTE1/Width-Depth-Tree-Problems
面试问题是我最喜欢参加的考试之一。虽然我只是一个将学*和开发各种问题的解决方案作为激情的高中开发者和爱好者,但面试问题确实提高了我的整体解决问题的能力。此外,当你找到正确的解决方案时,你得到的满足感是无与伦比的。就我个人而言,每当我解决一个面试问题或竞争性编码问题时,我都会激动不已!然而,像最大深度和最大宽度这样的问题稍微复杂一些,这可能需要一些思考和解决问题的技巧。起初,你不会想到一个解决方案,但这就是为什么它如此有趣,在所有开发者中如此受欢迎。之所以如此具有挑战性,并不是因为它需要高超的编码技能(这是成功解决面试问题的一个很大的误解);相反,这些类型的问题具有挑战性,因为它们是抽象的。换句话说,可以有多种解决方案,这鼓励开发人员进行更多的创新思考!我仍在努力培养解决问题的能力以及新的计算机科学概念。尽管如此,我还是会继续写关于我的目标进展和我遇到的新的有趣的面试问题的文章!
2021 年你应该知道的两种离群点检测技术
原文:https://towardsdatascience.com/two-outlier-detection-techniques-you-should-know-in-2021-1454bef89331?source=collection_archive---------2-----------------------
基于椭圆包络和 IQR 的检测

亚历山大·安德鲁斯在 Unsplash 上拍摄的照片
离群值是与其他数据点显著不同的异常数据点。离群点检测是一件棘手的事情,应该小心进行。椭圆包络和 IQR 是常用的离群点检测技术。椭圆包络是基于机器学*的方法,而基于 IQR 的检测是统计方法。它们各有利弊。因此,我们不能说哪一个是最好的。最好的策略是将这两种技术结合起来,看看整体结果。
在本文中,我们将讨论椭圆包络和 IQR 技术背后的直觉,并将它们结合在一起以获得更好的结果。还将使用 Python 和 Scikit-learn 讨论这些技术的实现。不要忘记阅读本文末尾的“要点”部分。在那里,你会学到一些特殊的概念和策略时,使用椭圆包络和 IQR 技术。
[这篇文章包括所有的东西:理论,代码,可视化和想法!]
我们开始吧!
椭圆形信封
这种方法的主要假设是数据应该是*(高斯分布 数据集)。椭圆形信封背后的直觉非常简单。我们根据一些标准在数据点周围画一个椭圆,并将椭圆内的任何数据点分类为内点(绿色的),将椭圆外的任何观察结果分类为外点(红色的)。*

椭圆形信封背后的直觉(图片由作者提供)
椭圆包络线方法将所有观测视为一个整体,而不是单个特征。虽然这种方法背后的直觉非常简单,但实现起来有些棘手。在 Scikit-learn 中,椭圆包络方法是通过椭圆包络()函数实现的。这里,我们需要指定污染超参数——一个我们不知道的值。它表示数据集中异常值的比例。这个超参数的值的范围是从 0 到 0.5(默认值是 0.1)。如果我们认为数据中会有很多异常值,我们可以将污染设置为一个更大的值。不知道数据集中异常值的确切比例是使用这种方法的主要限制。
履行
*为了实现椭圆包络方法,我们将首先使用 sci kit-learn**make _ blobs()*函数创建一个模拟数据集。然后我们将数据可视化,并检查正态性假设。
让我们写代码吧!
第一步:制作模拟数据集
*这里,我们使用 Scikit-learn**make _ blobs()*函数来创建一个模拟数据集。该函数创建高斯分布数据集。这里,出于可视化的目的,我们只为 X 选择两个特征。没有 y 。
等待加载 Python 代码(代码片段 1)
第二步:可视化数据
等待加载 Python 代码(代码片段 2)

两个特征之间的散点图(图片由作者提供)
数据中似乎有一些异常值。
第三步:检查数据的正态性
我们可以为每个特征创建直方图来检查正态性假设。
等待加载 Python 代码(代码片段 3)

两个特征的直方图(图片由作者提供)
我们的数据是正态分布的。因此我们可以应用 EllipticEnvelope() 函数来检测异常值。
步骤 4:应用椭圆包络来检测异常值
我们的数据集中似乎只有很小一部分异常值。因此,我们可以将污染设置为较小的值,如 0.025。
等待加载 Python 代码(代码片段 4)

检测到异常值的散点图(图片由作者提供)
椭圆信封对象的 fit_predict() 方法( elpenv )对于内点返回 1,对于离群点返回-1。我们可以使用 np.where() 函数提取异常值。红色的数据点是异常值。以下指数值的观察值是异常值。
*outlier_index*

作者图片
第五步:获取没有异常值的数据集
现在,我们创建一个不包含异常值的熊猫数据框。我们可以使用该数据集进行进一步分析。
等待加载 Python 代码(代码片段 5)

作者图片
基于 IQR 的检测
基于 IQR 的检测是一种统计方法。这种技术适用于单个特征,而不是像在椭圆包络中那样适用于整个观测。基于 IQR 的检测背后的直觉也很简单。首先,我们计算数据的第一个四分位数(Q1)和第三个四分位数(Q3)。然后我们得到这两个四分位数的差值。这种差异被称为 IQR(四分位数间距)。
- IQR = Q3-Q1
- 下限= Q1–1.5(IQR)
- 上限= Q3+1.5(IQR)

作者图片
任何小于下限或大于上限的值都是异常值。
履行
等待加载 Python 代码(代码片段 6)

作者图片
每个特征的异常值指数非常有用。我们可以使用所有要素的异常值索引的联合来从数据集中提取和移除异常值。我们可以得到如下的联合。
等待加载 Python 代码(代码片段 7)

作者图片
接下来,我们将数据可视化在散点图上,并将基于 IQR 的检测与椭圆包络进行比较。
等待加载 Python 代码(代码片段 8)

基于 IQR 的检测和椭圆包络的比较(图片由作者提供)
我们可以看到两种方法在检测异常值时的一些差异。
我们还可以使用 index_union 从数据集中移除离群值。
等待加载 Python 代码(代码片段 9)

有异常值和无异常值的数据(图片由作者提供)
我们还可以制作箱线图来显示有无异常值的数据。
等待加载 Python 代码(代码片段 10)

包含和不包含异常值的每个要素的箱线图(图片由作者提供)
关键要点
今天,我们在检测异常值方面做得很好。我们已经讨论了两种流行的技术,椭圆包络和基于 IQR 的检测。它们各有利弊。这两种技术背后的直觉很容易理解。椭圆包络基于机器学*,IQR 基于统计。椭圆包络很容易用 Scikit-learn 椭圆包络()函数实现,但要满足正态性假设。椭圆包络线方法将所有观测视为一个整体,而不是单个特征。椭圆包络的主要缺点是我们不知道污染超参数的精确值。猜测该值的最佳方法是首先进行基于 IQR 的检测,并计算数据集中异常值的数量。由于您知道观察值的总数,因此您可以获得异常值比例的近似值。这是污染超参数的值。这就是我们如何将两种技术结合在一起!
顺便说一下,基于 IQR 的检测不容易实现。你必须写一些高级的 Python 代码。但是在基于 IQR 的检测中,我们不需要检查正态性的假设,也不需要知道数据集中异常值的比例。所以,它们是这种技术的优点。这种技术适用于单个特征,而不是像在椭圆包络中那样适用于整个观测。我们可以使用返回的异常值索引的联合来从数据集中提取和移除异常值
这就是检测异常值背后的故事。但是,我们还没有完成。如何处理异常值?这和检测异常值是一样的吗?不。如果我们检测到异常值,我们下一步应该做什么?我们应该移除它吗?我们应该保留它吗?或者我们应该用一个相关的值来代替它?这取决于特定分析问题的领域知识。一个离群值背后可能有一个有趣的故事。所以,如果你发现了,试着说出这个故事。由于人为错误,可能存在一些异常值。在这种情况下,您可以将它们从数据中删除。
关于离群值的最后几句话— “处理离群值时要格外小心,除非你知道它们背后的故事!总是将多种技术结合起来检测异常值,因为没有单一的最佳技术。如果可能,始终绘制数据以检查假设和最终输出。”
今天的帖子到此结束。我的读者可以通过下面的链接注册成为会员,以获得我写的每个故事的全部信息,我将收到你的一部分会员费。
【https://rukshanpramoditha.medium.com/membership】报名链接:
非常感谢你一直以来的支持!下一个故事再*。祝大家学*愉快!
特别感谢 Unsplash 上的 Alexander Andrews ,为我提供了这篇文章的封面图片。
鲁克山普拉莫迪塔
2021–03–20
数据科学项目开发中被忽视的两个方面
原文:https://towardsdatascience.com/two-overlooked-aspects-in-data-science-project-development-b3834a239fc?source=collection_archive---------30-----------------------
数据科学项目的成功依赖于两个关键支柱:与领域专家紧密合作,以及实施严格的科学方法。本文基于我们在pickle tech从事健康、运动表现、供应链和移动性项目的经验。

照片由pickle tech拍摄
背景
近年来,数据可用性在许多不同领域以惊人的速度增长。这得益于提高了数据记录装置和加工工具 的效率。太神奇了。事实上,它创造了许多高潜力的应用。这些跨越了广泛的领域:从粒子物理学的基础研究到药物发现解决方案。
然而,与卫生或供应链等领域的从业者一起工作时,有时会感觉到一些正在开发的解决方案没有达到他们的预期,这令人望而生畏。(广泛理解的)数据科学解决方案的影响还没有达到其宣传的水*。
挑战
总结为什么会发生这种情况并不简单,具体原因取决于应用和领域。但是有一些模式反复出现。这些模式结合了几个数据质量问题:如抽样偏差、设计的不完整记录,以及其他关于数据记录和处理过程的错误假设。
此外,有偏*的解决方案设计与不适当的验证框架相结合,会导致应用程序的性能与有缺陷的开发所指出的大相径庭。一些开发的解决方案甚至根本不适合现实世界的使用。例如,相对于领域专家更全面的观点,当他们只能处理非常有限的信息时,或者当他们不能解释这些信息时。
最近人工智能解决方案没有达到预期的例子可以在新冠肺炎危机的背景下找到。看看这篇文章来了解更多这些问题。
不管当前的趋势如何,事实是许多这些模式与软件开发或数据科学解决方案产业化的失败无关,而是谈论统计和科学基础。
数据科学的两大支柱
为了使的解决方案能够转化为业务和组织影响,我们必须特别重视实施最佳数据科学方法来处理上述问题。
以我们在pickle tech的经验来看,鼓励、保护和推进数据科学开发方法论中的两个核心方面,多数时候都战胜了上面这些问题。这促使我们在开发管道的末端开发更有影响力的解决方案。
这两个方面是:
- 与领域专家紧密合作。作为数据科学家,我们认为与领域专家一起深入项目环境是理解业务和用户需求的基础。这对于剖析他们的运营框架和构建正确的业务问题是必不可少的。它使我们能够掌握所有必要的细节,以制定一个具有最大影响力的解决方案。此外,这种合作还建立了一些共同点,有助于强调开发方面的重要性,例如解决方案可解释性,建立信任的关键,以及模型的影响。
- 严谨和稳健的科学方法论。数据科学是有科学的,即使它被可怕地忽略了很多次。适当的假设检验和开发方案;验证框架,以确保真正的统计学*;以及对最终解决方案影响的公*评估,对于长期解决方案至关重要。影响只有在正确衡量后才是真实的。这就是为什么我们从不损害科学的完整性:数据科学必须以证据为基础。
当然,广泛的分析工具的重要性不应该被低估。这包括广泛的数据科学算法,从数据工程和 ETL 到高级统计、机器学*和深度学*模型;纵观整个人工智能技术。
再加上对许多组织有很大影响的特殊技术,即使这些技术被低估了很多倍:时间序列、假设检验或自举技术等等。但是,只有当科学严格地嵌入到开发中,并且领域专家告知新应用的背景和需求时,解决方案的全部影响才能被释放。
作为数据科学家,我们热衷于处理大型、异构、有约束和限制的数据集。找到剖析问题的方法,结合这些方面,并在高度竞争的领域提取有用的*解是我们的工作。所有这些实践必须始终保持其科学的完整性和严谨性,以实现持久的、通用的和可靠的解决方案,帮助领域专家从他们的数据中提取最多的信息。
数据科学必须**以数据为动力,**以科学为驱动。
本文基于我们在pickle tech从事健康、运动表现、供应链和移动性项目的经验。
双指针方法— Python 代码
原文:https://towardsdatascience.com/two-pointer-approach-python-code-f3986b602640?source=collection_archive---------3-----------------------

由克里斯蒂安·斯塔尔在 Unsplash 拍摄的照片
两个人一起行动总比一个人好。
两点算法是任何编程面试中最常被问到的问题之一。这种方法通过利用数据的某种顺序(不一定是排序)来优化运行时。这种方法通常用于在排序数组中搜索对。这种方法适用于恒定空间。
在这种技术中,指针表示索引或迭代属性,如节点的 next。
双指针方法的步骤:

作者图片
如上图所示,双指针方法有三个主要步骤:
指针初始化 —起始点。指针可以在任何地方,这取决于我们要达到的目标。在图片的左边,我们有两个指针从相同的位置开始,即链表的开始。在图的右边,我们在最末端有指针,一个在起始索引,另一个在最后一个索引。
指针移动— 这将决定我们如何向解决方案靠拢。指针可以向同一个方向移动(上图中的左边),也可以向相反的方向移动(上图中的右边)。同样在图片的左侧,我们有不同的指针增量(顶部(慢速)1 个单位,底部(快速)2 个单位)。
停止条件— 这决定了我们何时停止。在左边部分,我们继续前进,直到到达下一个元素为 None 的节点。在右边的例子中,我们继续,直到我们的起点小于终点。
注意:滑动窗口是双指针方法的另一种变体。
下面通过解决一些问题来看看我们是如何运用上述逻辑的。
问题№1
原地反转一个数组。

作者图片
用 Python 实现:
def reverseArray(array):
start, end = 0, len(array)-1
while start< end:
array[start], array[end] = array[end] , array[start]
start += 1
end -= 1
array = [10, 20, 30, 40, 50]
reverseArray(array)
print(array)
问题 2
给定一个按非递减顺序排序的整数数组,返回按非递减顺序排序的每个数字的*方数组。

作者图片
用 Python 实现:
def sortedSquares(nums):
n = len(nums)
start, end = 0, n-1
res = [0]*n
idx = n-1
while end > -1 and idx >-1:
if abs(nums[start]) > abs(nums[end]):
res[idx] = nums[start] * nums[start]
start +=1
else:
res[idx] = nums[end] * nums[end]
end -= 1
idx -= 1
return res
问题 3
在链表中查找循环:

作者图片
用 Python 实现:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def __repr__(self):
return str(self.val)def hasCycle(head):
if not head or not head.next:
return False
p1 = head
p2 = head.next
while p2:
p2 = p2.next
if p2:
p2 = p2.next
if not p2:
return False
p1 = p1.next
if p1==p2:
return Truelt = [ListNode(item) for item in [3,2,0,-4]]head = lt[0]
head.next = lt[1]
lt[1].next= lt[2]
lt[2].next = lt[3]
lt[3].next = lt[1]
print(hasCycle(head))
*注:*上述问题中没有节点排序。
问题№4
给定一个字符串s,求不含重复字符的最长子串的长度。

作者图片
用 Python 实现:
def lengthOfLongestSubstring(s):
seen, n = set(), len(s)
right, res = -1, 0
for left in range(n):
print(left, right, s[left: right+1], seen)
while right + 1 < n and s[right+1] not in seen:
right += 1
seen.add(s[right])
res = max(res, right - left + 1)
print( s[left: right+1])
if right == n - 1:
break
seen.discard(s[left])
return res
print(lengthOfLongestSubstring("abcabcbb"))
问题 5
给定三个大小不一定相同的排序数组 A、B 和 C。计算任意三元组 A[i],B[j],C[k]的最大值和最小值之间的最小绝对差,使得它们分别属于数组 A,B 和 C,即 minimize (max(A[i],B[j],C[k))—min(A[I],B[j],C[k])

作者图片
用 Python 实现:
def solve(A, B, C):
i , j, k = 0, 0, 0
m, n, p = len(A), len(B), len(C)
min_diff = abs(max(A[i], B[j], C[k]) - min(A[i], B[j], C[k]))
while i < m and j < n and k < p:
curr_diff = abs(max(A[i],B[j],C[k])-min(A[i],B[j],C[k]))
if curr_diff < min_diff:
min_diff = curr_diff
min_term = min(A[i], B[j], C[k])
if A[i] == min_term:
i += 1
elif B[j] == min_term:
j += 1
else:
k += 1
return min_diffA = [1,4,5,8,10]
B = [6,9,15]
C = [2,3,6,6]
print(solve(A, B, C))
第六个问题
给定n个非负整数a1, a2, ..., an,其中每个代表坐标(i, ai)上的一个点。n画垂直线,使线i的两个端点在(i, ai)和(i, 0)。找出两条线,它们和 x 轴一起形成一个容器,这样容器中的水最多。

作者图片
用 Python 实现:
def maxArea(height):
l, r, max_area = 0, len(height)-1, 0
while l<r:
base = r-l
if height[r] >= height[l]:
h = height[l]
l+=1
else:
h = height[r]
r-=1
print(l,r)
if h * base > max_area:
max_area = h * base
return max_area
*注意:*在最后一个问题中,数组没有排序,但双指针方法仍然适用。
这种技术可以扩展到两个以上的指针。
问题 7
给定三个整数数组arr1、arr2、arr3、按照严格递增的顺序对排序,返回一个排序后的数组,其中只有**、三个数组中出现过的整数全部**。
我们从三个指针开始,增加小于三个元素的最大值的指针。
def arraysIntersection(arr1, arr2, arr3):
i, j, k = 0, 0, 0
p, q, r = len(arr1), len(arr2), len(arr3)
res = []
while i < p and j < q and k < r:
if arr1[i] == arr2[j] == arr3[k]:
res.append(arr1[i])
i += 1
j += 1
k += 1
continue min_next_possible = max(arr1[i], arr2[j], arr3[k]) if arr1[i] < min_next_possible:
i += 1
if arr2[j] < min_next_possible:
j += 1
if arr3[k] < min_next_possible:
k += 1
return res
希望这有助于并鼓励你尝试这种技术,如果你还没有这样做的话。更多练*问题*下文:
同方向运动问题:
查找任何相邻子数组大小 k 的最大值
从排序数组中移除重复项
合并排序数组
反方向运动问题:
两个和 II
有效回文
移零
移除排序数组中的重复元素
快乐编码。
随机漫步的两个问题
原文:https://towardsdatascience.com/two-problems-with-the-random-walk-c58ce77d7524?source=collection_archive---------11-----------------------
赌徒的破产和伯特兰投票问题

模拟随机行走的 10000 步(图片由作者提供)
赌徒的毁灭:一个赌徒最初有 k 美元,她想赢得 b 美元在一个公*的赌博游戏中,如果她赢了,她得到一美元,如果她输了,她失去一美元。她在失去一切之前赢得 b 美元的概率有多大?
贝特朗选票 : A 和 B 是一张选票上的两个候选人,选举结束时,A 得 A 票,B 得 B 票,其中 a > b .投票时 A 一直领先 B 的概率是多少。
这两个问题之间有一个重要的联系——这两个问题都可以翻译成随机行走的语言,随机行走在各个领域都起着重要的作用,比如物理、金融、计算机科学等等。
用随机游走来描述,第一个问题变成:从值 k (k > 0) , 随机游走在到达 b 之前不降到零的概率。第二个变成从 0 开始, 随机游走在到达 b 之前不归零的概率。它们看起来非常相似,但实际上,它们是使用不同的技术解决的。
随机漫步的想法很简单,如下图所示。在每一步中,我们可以选择向上或向下。如果随机行走是建立在一条线上,在每一步中,我们可以选择向右或向左。也可以证明(非常严谨)正态分布可以这样导出。

图 0.1(图片由作者提供)
形式上,随机游走被定义为序列{Xᵢ: 1 ≤ i < ∞}. Each Xᵢ is a random variable with the alternative distribution. If we consider the unbiased case, we have P(Xᵢ = 1) = 1/2 = P(Xᵢ = -1). At the nth step, the value of the random walk is Sₙ, which is calculated as

Eq. 0.2
obviously, if we start from 0, then

Eq 0.3
Problem I — Gambler's ruin
To solve the first problem: 给定 S₀ = k ,在随机游走达到值 b 之前,它不会到达零的概率是多少?
我们将使用的这种技术称为第一步分析。
正如这个技巧的名字所暗示的,首先,我们需要思考第一步之后会发生什么:如果在一开始,随机游走上升,那么在第二步,随机游走从 k+1 开始,访问零的概率较低;相反,如果随机游走上升,那么在第二步中它将从 k-1 开始,并且访问零的概率更高。这意味着我们可以为函数 Pₖ(Z 找到一个递归关系,它表示随机游走从 k 开始到达零的概率。z 是零被访问的事件。
我们用 D 来表示随机漫步向下走一步,向上走一步。根据全概率定律,在第一步之后,我们有

情商。1.1
其中 P(Z|U)表示随机游走不下降到零的概率,假设随机游走在第一步中上升。P(Z|D)是类比定义的。为了使符号更通用,我们重写了等式。1.1 作为

情商。1.2
其中 Pₖ(Z 的含义)与前面提到的相同。注意,在 Eq 中没有关于哪一步的信息。1.2.我们只对随机游走相对于起点值归零的概率感兴趣。利用下面的递归关系,我们可以进一步处理方程。1.2

那些递归关系说的很简单——如果在当前步骤中随机游走从 k 开始,那么在下一步中它将从 k+1 开始;如果它在当前步骤中下降,在下一个步骤中,它将从 k-1 开始,如图 1.5 所示

图 1.5(作者图片)
为了使符号更简洁,我们用 pₖ来表示 Pₖ(Z).情商。1.2 现在变成了

情商。1.6 是二阶差分函数(不是“微分”函数,因为随机游走是离散过程,这里不涉及微分)。来自 Eq。1.7,我们可以看到增量是不变的。这意味着,{pₖ}是一个等差数列

获得情商后。1.8,我们已经快完成了。如果找到用 k 和 b 表示 p₀ 和 m (提醒:b 是随机游走的目标值)的方法,我们就有解了(经过一些琐碎的修改)。但这并不难。有了下面的边界条件,我们就可以立即得到解。

(图片由作者提供)
因此,p₀是从边界条件直接获得的。使用替换后,我们得到 m = -1/b,并且

等式 1.9 在到达 b 之前,从 k 到零的随机游走的概率
这意味着随机游走在到达 b 之前没有降到零的概率是 k/b 。
问题一概述
在赌徒的破产问题中,赢一美元和输一美元分别对应着随机游走的上升和下降。目标是在破产前赢得 b 美元。我们可以看到解 k/b 是有道理的:初始资金越多,赢的概率就越高——如果你一开始资金很少,赢的概率几乎为零。
问题二——伯特兰的选票
我们将统计轨迹来解决第二个问题:从 0 开始,随机游走在到达 b 之前不归零的概率是多少?
这种方法的核心思想是,在随机行走领域,每个事件都可以用一组轨迹来表示。因此,事件的概率是两个这样的集合的大小的比例(轨迹的计数)。为了让后面的事情更清楚,我们引入下面的符号。

(图片由作者提供)
我们用 n 表示总步数,用 r,l 分别表示向上和向下的步数,因为它们对应于一条线上的左右步数。首先,我们将看一个简单的子任务,**有多少条轨迹,从(0, a )到(n, b )?**这可以通过一个例子得到最好的理解。

图 2.1(作者图片)
图 2.1 显示了一个例子,其中,在 10 个步骤中,随机游走从(0,3)到(10,7)。要发现的最重要的事情是为了从 a 到 b(不失一般性,我们假设 b > a),必须有 b-a 更多的步骤向上。这意味着 r-l = b-a 。在图 2.1 中,随机游走在 10 步中向上走了 4 步—向上 7 步和向下 3 步满足要求。同样,总共有 n 个步骤,因此 r + l = n 。有了这两个方程, r 和 l 可以唯一确定。解完这个方程组后,我们得到

因为 r 和 l 对于这个信息是唯一的,我们也可以看到

情商。2.4
现在很容易解决子任务。我们可以利用二项式系数 : 从(0,a)到(n,b)的轨迹数等于从 n 步中选择 r 步向上(或者等价地,向下)的可能方式。因此我们得到

这是一个重要的结论,以后会用到。另一个重要的陈述是反射原理,它说

反射原理
这个很容易验证:考虑集合 X 和 Y,其中 X 是从(0,a)到(n,b)访问 0 的所有轨迹的集合,Y 是从(0,-a)到(n,b)的所有轨迹的集合。这两组之间存在双射,因为在第一次到达零点之前,X 中的每个轨迹都被映射到 Y 中围绕 X 轴的镜像轨迹*。从 Y 到 x 的映射也是如此,如下图所示*

镜像轨迹。(图片由作者提供)
在所有这些准备工作之后,我们现在转向关键陈述——投票定理,从中我们可以很容易地得到 Bertrand 投票问题的解决方案。选票定理说

选票定理。(图片由作者提供)
这个定理可以直接证明。因为在第一步中,随机漫步必须向上,所以目标是

从(0,0)到(n,b)不重访零的轨迹数
利用反射原理,我们得到

从这里,我们插入 Eq。2.5,其余的将用代数方法证明

因此,从(0,0)到(n,b)的随机游走不归零的概率是

情商。2.8
问题二总结
在投票中,我们认为 A 的一票为 1,B 的一票为-1。投票结束,结果是 a 票给 A, b 票给 B,所以总共有 a+b 票,对应的是随机行走中的 a+b 步( n=a+b )。而 A 和 B 的分数差就是 a-b 。如果我们将其转化为随机行走,这个场景对应于从 (0,0) 到 (a+b,a-b) 。使用我们在本节中得到的结果(等式。2.8),解决方法是 (a-b)/(a+b) 。
结论
在这篇文章中,我们将介绍离散数学中两个众所周知的问题,这两个问题都可以通过随机漫步来解决。它们是赌徒的毁灭和伯特兰的选票问题。这两个问题被映射成两个在随机游走方面看起来非常相似的问题,但是它们被不同地解决了。在这篇文章中,我们使用第一步分析解决了赌徒的破产问题,并通过计算轨迹解决了 Bertrand 投票问题。希望这篇文章有助于理解这两个问题,并对随机漫步有更深入的了解。
资源:
[1]斯蒂尔,J. M. (2001 年)。 随机微积分与金融应用 (第一卷)。纽约:斯普林格。
[2] Grimmett,g .,& Stirzaker,D. (2020 年)。 概率和随机过程。牛津大学出版社。
用 Python 实现组间差异的双样本推断
原文:https://towardsdatascience.com/two-sample-inference-for-the-difference-between-groups-with-python-de91fbee32f9?source=collection_archive---------11-----------------------
用 Python 实现大学统计
介绍
在一系列的每周文章中,我将会涉及一些重要的统计学主题。
目标是使用 Python 来帮助我们获得对复杂概念的直觉,从经验上测试理论证明,或者从零开始构建算法。在本系列中,您将会看到涵盖随机变量、抽样分布、置信区间、显著性检验等主题的文章。
在每篇文章的最后,你可以找到练*来测试你的知识。解决方案将在下周的文章中分享。
迄今发表的文章:
- 伯努利和二项随机变量与 Python
- 用 Python 从二项式到几何和泊松随机变量
- 用 Python 实现样本比例的抽样分布
- Python 的置信区间
- 使用 Python 进行显著性测试
- 用 Python 进行组间差异的双样本推断
- 分类数据的推断
- 高级回归
- 方差分析— ANOVA
像往常一样,代码可以在我的 GitHub 上找到。
比较人口比例

图 1:2021 年葡萄牙地方选举将于同年 9 月 26 日举行;来源。
假设波尔图市的一名候选人对比较投票给他的男女比例感兴趣。在那个周末,一项新的民意调查得出了以下信息:在 1000 名男性样本中,62%的人回答说将投票给他,在 1000 名女性样本中,57%的人回答说将投票给他。实际上,这是两种伯努利分布,我们可以用参数来定义:

from scipy.stats import bernoulli, norm
import numpy as np
import seaborn as sns
import math
import matplotlib.pyplot as plt
from graphviz import Digraph# Theoretical parameters for men
p1 = 0.65
n1=1000
n = n1
μ_1 = p1
var_1 = p1*(1-p1)
dist_men = np.concatenate((np.ones(int(p1*n)), np.zeros(int(n-(p1*n)))))
sns.histplot(dist_men);

图 2:男性选民的伯努利分布。
# Theoretical parameters for women
p2 = 0.58
n2 = n
μ_2 = p2
var_2 = p2*(1-p2)
dist_women = np.concatenate((np.ones(int(p2*n)), np.zeros(int(n-(p2*n)))))
sns.histplot(dist_women);

图 3:女性选民的伯努利分布。
我们想弄清楚男性和女性投票给候选人的方式是否有显著的不同。实际上,我们希望得出该差异的 95%置信区间。
因为样本量足够大,我们可以假设正态分布可以近似样本比例的抽样分布。在以前的文章中,我们已经看到了这些发行版的一些属性:

请注意,他们从原始分布中抽取了 1000 个样本来创建投票,然后计算该样本的*均值。这个过程相当于从样本比例的抽样分布中抽取一个样本。
# Sampling distribution of sample proportion for men
mu = p1
variance = p1*(1-p1)/n
sigma = math.sqrt(variance)
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
sns.lineplot(x = x, y = norm.pdf(x, mu, sigma));

图 4: Sampling distribution of sample proportion for men.
# Sampling distribution of sample proportion for women
mu = p2
variance = p2*(1-p2)/n
sigma = math.sqrt(variance)
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
sns.lineplot(x = x, y = norm.pdf(x, mu, sigma));

图 5: Sampling distribution of sample proportion for women.
事实上,我们对男性和女性的个体分布并不感兴趣。我们感兴趣的是它们的差异,所以让我们创建

为此,我们需要定义它的参数:

# Sampling distribution of sample proportion for the difference between men and women
mu = p1-p2
variance = p1*(1-p1)/n + p2*(1-p2)/n
sigma = math.sqrt(variance)
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
sns.lineplot(x = x, y = norm.pdf(x, mu, sigma));

Figure 6: Sampling distribution of sample proportion for the difference between men and women.
我们要计算的置信区间表明 p1-p2 有 95%的可能性在内

# Calculating the number of standard deviations required for a 95% interval
norm.ppf(0.975)1.959963984540054
让我们计算一下我们的间隔。
np.sqrt(variance) * norm.ppf(0.975)0.042540701104107376
现在我们知道有 95%的可能性比例的真实差异在样本比例的实际差异的 0.04254 以内。
print(f'The 95% CI is: [{np.round(p1-p2 - np.sqrt(variance) * norm.ppf(0.975), 3)},{np.round(p1-p2 + np.sqrt(variance) * norm.ppf(0.975), 3)}]')The 95% CI is: [0.027,0.113]
候选人可以得出结论,男性投票给他的可能性比女性高 95%。请注意,值 0(无差异)不包含在间隔中。
比较人口比例的假设检验
我们的方法可以更直接。我们可以定义一个假设检验来评估,事实上,这是否是一个差异。
我们首先定义我们的零假设,它代表无差异的场景。相反,我们的另一种假设认为存在差异。

因此,我们想计算

如果这个概率小于为该问题定义的显著性水*,我们将拒绝我们的零假设,并接受男性和女性投票给候选人的差异。换句话说,假设真正的比例是相等的,我们想知道得到像抽样比例的差值一样极端的东西的概率。我们可以将 z 值定义为,

p0 = (n1*p1+n2*p2)/(n1+n2)
z = ((p1 - p2) - 0) /(np.sqrt(2*(p0*(1-p0)/n)))
z3.2167337783899304
现在,我们可以将 z 统计量与显著性水*为 5%的临界值进行比较。
z_critical = norm.ppf(0.975)
z_critical1.959963984540054z > z_criticalTrue
我们的 z 统计值大于临界值。换句话说,假设我们的零假设,有 5%的机会对大于临界值的 z 统计量进行采样。在这种情况下,我们拒绝 h0,这意味着我们接受投票给候选人的男女之间的差异。
实验的统计显著性
在一项旨在研究假新闻对参与度的影响的实验中,一组 500 人被随机分配到两个不同的组。随机分组后,每个人都收到了一部只有社交媒体应用的智能手机,他们可以用它来关注朋友的新闻和更新。
第一组每天至少收到两次假新闻,而第二组没有。30 天后,测量花在社交媒体应用上的时间。实验的指导者发现,第一组每天花在应用上的*均时间比第二组多大约 12 分钟。
gra = Digraph()
gra.node('a', '500')
gra.node('b', '#1\n Fake news')
gra.node('c', '#2\n No fake news')
gra.edges(['ab', 'ac'])gra

图 7:实验研究的设计,其中 250 人被随机分配到治疗组,250 人被随机分配到对照组。
g1 = np.random.normal(3, 1, size=250)
g2 = np.random.normal(2.2, 1, size=250)print('Group 1: ' + str(np.round(g1.mean(),1)) + 'h')
print('Group 2: ' + str(np.round(g2.mean(),1)) + 'h')Group 1: 3.0h
Group 2: 2.2h
为了理解这一结果的意义,我们需要将结果重新随机化成两个新组,并测量新组的*均值之间的差异。我们重复模拟 200 次。
groups_ind = np.zeros((200, 500))
for i in range(200):
groups_ind[i] = (np.random.choice(np.arange(500, dtype=np.int32), size=500, replace=False))groups_ind = groups_ind.astype('int32')g = np.concatenate((g1,g2))g1_rand = g[groups_ind][:,:250]
g2_rand = g[groups_ind][:,250:]
g1_rand_mean = g1_rand.mean(axis=0)
g2_rand_mean = g2_rand.mean(axis=0)
diff_g = g1_rand_mean - g2_rand_meansns.histplot(diff_g);

图 8:200 次模拟后,将结果重新随机分为两个新组,各组*均值之间的差异。
我们可以看到,差异大于 0.2 的次数非常少。但它有统计学意义吗?
diff_g[diff_g>=0.2].shape[0]/diff_g.shape[0]0.024
假设在实验开始前建立了 5%的显著性水*。在这种情况下,我们看到我们的结果在统计上是显著的,因为在 200 次模拟中观察到 12 分钟差异的概率只有 2.4%。如果这是偶然的,那 200 年中只会发生 6 次。
结论
本文介绍了如何应用置信区间和假设检验来比较两个总体样本之间的差异。这给了我们一种方法来理解这些差异是否真的有统计学意义。我们将这些想法应用到一个实验中,该实验使用模拟和再随机化来测试治疗组和对照组之间的差异。
保持联系: LinkedIn
练*
你将在下周的文章中找到答案。
- 医生假设,疫苗接种前后因新冠肺炎而住院的*均时间发生了变化。将 1000 名患者随机分为治疗组和对照组。治疗组已经注射了疫苗,而对照组没有注射。结果显示,治疗组的*均住院时间比对照组少 10 天。下表总结了 1000 次数据重新随机化的结果。根据数据,治疗组的*均值比对照组的*均值小 10 天或更多的概率是多少?从实验结果中你能得出什么结论(假设 5%的显著性水*)?
diff = [[-17.5,1],
[-15.0, 6],
[-12.5, 15],
[-10.0, 41],
[-7.5, 82],
[-5.0, 43],
[-2.5, 150],
[0., 167],
[2.5, 132],
[5.0, 127],
[7.5, 173],
[10.0, 38],
[12.5, 18],
[15.0, 6],
[17.5, 1]]
上周的答案
- 根据去年的一项大型民意调查,波尔图大约 85%的房屋都接入了高速互联网。Marco 想知道这一比例是否发生了变化,他随机抽样调查了 80 栋房子,发现其中 75 栋可以接入高速互联网。他想用这个样本数据来检验这个比例是否真的发生了变化。假设推断条件满足,考虑到 1%的显著性水*,您对拥有高速互联网的房屋比例会得出什么结论?
p_0 = 0.85
p = 75/80
n = 80
α = 0.01
z = (p-p_0)/np.sqrt(p_0*(1-p_0)/n)
z2.191785018798024p_value = (1-norm.cdf(z))*2 # see that Marco wants to check if the proportion changed, so it is a two-tail testif p_value < α:
print("Reject H0")
else:
print("Fail to Reject H0")Fail to Reject H0
2.玛尔塔拥有一家水果店,每周都会收到西瓜。供应商声称它们应该重 1 公斤。Marta 决定对随机抽取的 100 个西瓜进行称重,发现*均重量为 850 克,标准偏差为 200 克。她想用这个样本数据来测试*均值是否小于供应商声称的*均值,如果是这样,就重新协商他们的合同。假设推断的条件满足,Marta 应该怎么做(考虑 5%的显著性水*)?
μ_0 = 1
μ = 0.850
s = 0.2
n = 100
α = 0.05
t_star = (μ-μ_0)/(s/np.sqrt(n))
t_star-7.500000000000001p_value = t.cdf(t_star, df=n-1)if p_value < α:
print("Reject H0")
else:
print("Fail to Reject H0")Reject H0
Marta 应该与供应商重新谈判合同,因为西瓜重 1 公斤的说法在 5%的显著性水*上是不真实的。
两个情感分析库及其性能
原文:https://towardsdatascience.com/two-sentiment-analysis-libraries-and-how-they-perform-3de4a06342ec?source=collection_archive---------31-----------------------
使用文本块和 VADER 库进行情感分析很容易,但是它们有多准确呢

腾雅特在 Unsplash 上拍摄的照片
情感分析不是一门精确的科学。自然语言中充满了奇怪的表达方式,意思不止一个的单词,*语,讽刺以及任何使意思提取变得困难的事物。看看这两句话。
“我知道我为什么一直犯同样的错误——我不认为!”
“情绪分析在所有情况下都是准确的——我不这么认为!”
在第一句中,短语“我不认为”解释了句子的第一部分,但在第二句中,它是讽刺性的,否定了句子前一部分的意思。于是,我们有了两个相同的短语,根据它们的使用方式,它们有着完全不同的目的。
因此,期望情绪分析器在所有情况下都准确是不合理的,因为句子的意思可能是模糊的。
但是它们有多准确呢?显然,这取决于用来执行分析的技术,也取决于上下文。为了找到答案,我们将使用两个易于使用的库做一个简单的实验,看看我们是否能找到我们期望的精度。
您可以决定构建自己的分析器,这样做的话,您可能会学到更多关于情感分析和文本分析的知识。如果你想做这样的事情,我强烈推荐你阅读由康纳·奥沙利文,撰写的文章《情感分析简介,他不仅解释了情感分析的目的,还演示了如何使用单词袋方法和称为支持向量机(SVN)的机器学*技术在 Python 中构建分析器。
另一方面,你可能更喜欢导入一个库,比如 TextBlob 或者 VADER 来完成这项工作。
在下面的节目中,我们将分析来自sentitment 140项目的一组推文。他们已经收集了 160 万条推文,这些推文被贴上了积极、消极或中性情绪的标签。
推文真多。
但是我们将使用这些推文中的一个子集——只有 500 条。你可以在这里下载数据sensition 140——给学者。在这个网站上,你会发现一个 zip 文件,其中包含两个 CSV 文件,一个有 160 万条推文,另一个我们将使用 500 条推文—testdata . manual . 2009 . 06 . 14 . CSV。
我们将对该文件运行 TextBlob 和 VADER 情感分析器,并查看结果与数据集中之前分配的标签相比如何。(有关分析器的更多信息,请参*我的文章推文的情绪分析。)
我将一次检查几行代码,但在本文的最后会包括整个代码的要点。
首先,我们需要导入库。
from textblob import TextBlob
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
import pandas as pdanalyzer = SentimentIntensityAnalyzer()
那是文本博客,VADER 和熊猫——不,是惊喜,在那里——然后我们创建了一个 VADER 分析器,我们以后会用到。
接下来,我们读取数据并做一些整理。
completeDF = pd.read_csv("testdata.manual.2009.06.14.csv", names=["polarity", "id","date","query","user","text"])df = completeDF.drop(columns=['date','query','user'])
df.polarity = df.polarity.replace({0: -1, 2: 0, 4: 1})
当读取 csv 文件时,我们给每一列一个名称。然而,我们并不真的需要所有这些列,所以我们立即创建一个新的数据帧,删除不需要的列。
原始数据将情绪分为“积极”、“中性”和“消极”,并分别用数字 4、2 和 0 表示这些情绪。这些值在“极性”栏中。我们将要使用的分析器使用相同的分类,但是使用 1 到-1 之间的实数来表示情绪的极性。所以-1 是很负,+1 是很正,0 是中性。0.5 可能有些积极。
因此,我们将“极性”列的值更改为 1 表示正极,0 表示中性,1 表示负极。(这给我们带来了一个比较一系列数字的小问题,这些数字是由分析器生成的,与数据中记录的三个类别相比较——但是我们很快就会处理这个问题。)
接下来要做的是遍历数据中的推文,并通过两个分析器运行它们。我们将在 list 中记录结果,因此先定义两个空的。
真正的工作是由
TextBlob(text).sentiment.polarity)
获取 TextBlob 分析和
analyzer.polarity_scores(text)['compound'])
从 VADER 那里得到分析结果。
函数rounder将完成从实数到类别的转换——稍后会详细介绍。
TBpol = []
Vpol = []for text in df['text']:
TBpol.append(rounder(TextBlob(text).sentiment.polarity))
Vpol.append(rounder(analyzer.polarity_scores(text)['compound']))
现在,我们将这两个列表作为新列添加到我们的数据框架中。
df['TBPolarity'] = TBpol
df['VPolarity'] = Vpol
但是我们如何将一个 0.5 的极性转换成一个类别呢?应该是正面的还是中性的。你可以采取一种简单的方法,简单地对数字进行四舍五入,这样 0.5 以上的数字就变成 1,-0.5 以下的就变成-1,其他的都是 0。但这确实有效,因为这意味着中性范围是其他两个范围的两倍。
更合理的方法是向上舍入到 1.3 以上,从-1.3 向下舍入。这意味着正值的范围。阴性和中性是一样的。但我并不是出于非常实际的目的才这么做的——效果并不太好。
让我解释一下。
如果在转换成类别时,我使范围相等,那么我得到的结果是:
Overall length 498
VADER agreements/disagreements 302/196
Accuracy: 60.6425702811245%
TextBlob agreements/disagreements 217/281
Accuracy: 43.57429718875502%
第一行是推文的数量,接下来的几行记录了分析师对预先分配的类别的认同程度,然后是准确率。VADER 的准确率约为 61%,TextBlob 的准确率约为 44%。不聪明。
所以,我摆弄了一下舍入函数,看看能否提高精度。把 0 以上的都当成正的,0 以下的都当成负的,我得到了以下结果。
Overall length 498
VADER agreements/disagreements 360/138
Accuracy: 72.28915662650603%
TextBlob agreements/disagreements 324/174
Accuracy: 65.06024096385542%
这是相当好的。所以rounder函数是这样的:
def rounder(num):
if num > 0: return 1
if num < 0: return -1
return 0
给出了 72%和 65%的准确率。
这些数字合理吗?这么简单的测试很难说。也许一个更大的数据集,或者不同类型的数据(即不是推文)会给出不同的结果。值得注意的是,上面提到的由@conorosullyds 编写的分析器只给出了比 VADER 略好的结果(73%),公*地说,VADER 特别针对 tweets,所以应该比更一般的 TextBlob 表现得更好。
就这些,我希望这是有趣的,一如既往地感谢阅读。我会像往常一样邀请你订阅不定期的时事通讯,获取我发表的文章的新闻以及我的代码的完整列表。
为了数据和分析工作,你需要从敏捷中偷两个简单的东西
原文:https://towardsdatascience.com/two-simple-things-you-need-to-steal-from-agile-for-data-and-analytics-work-d3130050f0e5?source=collection_archive---------30-----------------------
同行评审和完成的定义:小变化,大影响

穆里洛·维维亚尼在 Unsplash 上拍摄的照片
将软件开发生命周期的各个方面应用于数据科学、工程和分析是目前非常流行的趋势——这是一件好事。无论您是在谈论将数据转换视为代码、采用数据操作和敏捷数据治理实践、考虑数据即产品,还是在考虑数据网格架构(本质上是将微服务基础应用于数据和分析堆栈),世界正在转向最终将数据和分析视为团队运动。但如果你想赢得这个游戏,你需要找到让玩家一起互动和协作的方法,捕捉知识,让更多人更容易玩。
有一股疯狂的热潮要从软件开发社区的成功中汲取经验,尤其是在围绕数据科学和分析促进更好的协作和团队合作方面。伟大的艺术家偷窃,作为一个写了很多关于敏捷数据治理的人,我也这么做!
但是,并不是每个人都赞同这样的想法,如果我们都像软件工程师和产品经理那样做,我们就会得救。人们指出围绕数据隐私、偏*、有效性和其他问题的非常有效的问题,这些问题使得分析和数据科学的输出比典型的敏捷软件项目更加敏感。同样清楚的是,涉及数据和分析的工作通常在组织中的关键决策中达到高潮,这些决策涉及比典型的软件项目更广泛的利益相关者。
从赞成的一面来看,包容的、迭代的、真正涉及整个项目的利益相关者的敏捷实践有可能以真正有意义的方式将数据生产者(数据工程师和管理者)和消费者(数据科学家和分析师)聚集在一起。这有助于形成强大的数据驱动型文化,并极大地提高数据素养。
在我的日常工作中,我们构建一个数据目录*台,这个*台被像 Prologis 这样的企业使用,prolog is 是世界上最大的物流房地产公司。通过使用用例驱动的敏捷方法开发其分析和数据治理实践,Prologis 已经能够以真正具有变革性的方式部署它。
从历史上看,我们的组织采用自上而下的“煮沸海洋”的方法来进行数据治理,这种方法并不适合我们。我们知道,我们必须彻底改变我们的方法,把重点放在我们的用户经历最痛苦和恶化的地方。然后,我们允许真实世界的数据推动我们的数据治理计划的扩展。简而言之,通过基于业务用例对数据资产进行优先级排序,以迭代的方式专注于部署我们的数据目录,这是重新点燃员工对我们的治理计划的兴趣的关键。"
— Luke Slotwinski,Prologis 数据和分析副总裁
开展数据编目计划对你来说可能还不太可能,但如果我告诉你,敏捷中有两个简单的想法,你可以在今天实施,这将极大地提高你的数据和分析工作的质量,并开始促进共享理解和数据素养,会怎么样?这两个概念是同行评审和完成的定义。
同行审查
在软件开发中,代码(或同行)审查的想法比 Github 著名的“拉请求”功能要早得多,该功能允许工程师在作品发布前对彼此的作品进行评论。我第一次读到这种技术是在史蒂夫·麦康奈尔的代码全集——它最初于 1992 年出版!让一个队友复查你的工作,并对你可能错过的事情提出建议,这是一种简单的力量和美丽。对于特别复杂的代码,两位工程师可能会一行一行地检查,作者实时地向评审者解释它是如何工作的。这有一个额外的好处,即确保重要的知识转移,确保团队中不止一个人知道代码是如何工作的,并避免可怕的“总线因素 1”。
将这种风格的回顾作为你的过程的一部分是非常有效的。这样做的另一个好处(特别是因为我们现在几乎都生活在一个遥远的世界)是,在进行这些审查时捕获的评论可以极大地改进您的任何数据和分析文档工作,而几乎不需要额外的努力。需要注意的是,评审应该关注同行数据科学家或分析师如何完成分析,或者是一行一行的代码,或者是如何创建可视化。这不是涉众或最终用户验收测试。(在软件中,这类似于让用户点击原型,然后称之为完成)。
这一点怎么强调都不为过:同行评审者会发现你的技术中的错误,或者会有商业利益相关者根本不会有的建议(特别是如果分析恰好证实了一个信念或者先前持有的偏*)。在流程中增加这一步骤将对跨部门协作、整体数据素养产生积极影响,并对完成的分析或交付的数据模型的质量产生巨大影响。我建议你在谷歌上搜索“良好的代码阅读实践”( Good Code Read Practices )( T1 ),寻找大量关于如何做好这一点的文章,并思考如何将其应用于你公司的数据和分析最佳实践。
完成的定义
在同行评议会议中,真正能有所作为的是有一个很好的“完成的定义”。完成的定义的概念来自软件开发领域的 Scrum 方法论,其思想是当用户故事完成时,你应该有一个简单而明确的清单来检查,以确保作为一名工程师(和评审者),你已经击中了目标。拥有一份简单的清单,组织中的所有数据科学家、分析师和工程师都同意使用该清单来签署工作,可以显著提高数据工作的质量和一致性。
然而,当谈到分析和数据工程工作的定义时,您可能需要对您的分析工作和数据建模工作有单独的定义。我们在这项工作中使用了几个定义,它们可能也是您的组织的良好起点:
数据科学和分析的完成定义
- 假设说得好
- 检查方法的偏倚
- 数据源被很好地定义
- 提交给数据工程的新数据源/建模
- 方法已被读取,并且可以在对等环境中复制和使用
- 轴、特征、域被很好地定义
- 记录结论和行动步骤
- 已审查合规性
- 公开征求意*或重新使用
数据建模完成的定义
- 编写数据字典
- 已链接的现有业务术语和相关指标
- 提交的新业务条款
- 已审核转换代码
- 坚持数据架构风格(Kimball、Data vault 等)
- 坚持不要重复自己的原则
- 编写的测试和数据配置文件得到了很好的记录/理解
- 已审查合规性
- 公开征求意*或重新使用
当我们在 data.world 采用 dbt 对我们的内部数据和分析进行建模时,完成这些定义(尤其是以数据建模为重点的定义)有助于建立我们完成分析工程工作的基线。这确保了即使我们学*了一个新工具,当我们回顾彼此的工作时,我们在寻找什么方面是一致的。当我们迁移到雪花时,这很容易使我们将新数据模型放入数据仓库的效率提高一倍。
采用实践
无论何时你采用一种新的实践,比如进行同行评审或有一个完成的定义来检查工作,重要的是将它们纳入你今天用来管理项目的工具中——你甚至不需要任何花哨的新数据或分析基础设施来做这件事。通常,仅仅调整像 JIRA 这样的软件过程工具来适应你的数据和分析实践就足够了。如果你正在围绕用户故事组织你的分析工作,在像 JIRA 这样的工具中增加一个“同行评审”步骤是非常容易的。使用 JIRA 的敏捷董事会很简单,并且已经包含了一个评审步骤:

作者图片
如果你实际上已经有了一个数据目录,给你的数据资产添加一个“In Review”标志也是非常有用的,并且可以同步到你的项目管理工具中。这些标志可以用来分配审查者,或者让消费者知道资产是否已经可以使用了。

作者图片
借助敏捷赢得数据和分析
在这篇文章的开始,我提到了我从敏捷软件开发原则中窃取并将其应用于数据和分析工作的历史。你知道吗?我将继续从敏捷中偷东西,因为我相信创造协作的、数据驱动的文化,在这种文化中,数据和分析的透明度和信任占主导地位。同行评审和遵循一个众所周知的数据和分析工作完成的定义是你今天可以采纳的非常有价值和简单的想法。没有哪两个变化更容易实现,或者对数据质量和组织内的共同理解有更大的积极影响。
我希望听到任何在您的数据和分析流程或治理工作流中采用这些或其他敏捷方法的人的意*!
人工智能治理的两个故事
原文:https://towardsdatascience.com/two-tales-of-ai-governance-part-1-e1c75953ebc4?source=collection_archive---------44-----------------------
良好的数据驱动决策
这是一篇关于数据驱动的和良好数据驱动的决策制定的两部分文章。它使用两个故事来说明任何人工智能(AI)应用程序的支柱概念,以增强人类决策者或自主决策。
这篇文章是而不是关于什么的——深入的技术或规范分析。它的目的只是在人工智能治理的背景下提出问题并鼓励关于数据和模型的对话。
第 1 部分:切尔姆的白痴——我们的数据有多好?

Joanna Nix-Walkup 在 Unsplash 上拍摄的照片
有一个意第绪语的民间故事,讲述了格泽尔如何成为切尔姆镇的哲学家。有一天,Getzel 出发去另一个城镇,但是一路上他觉得很累,决定小睡一会儿。他害怕忘记自己是从哪个方向来的,所以他脱下鞋子,让它们指向他要去的城镇的方向。当盖泽尔睡觉的时候,一个路过的农民拿走了他的鞋子并试了试。因为他们不是他的尺寸,他把他们放回去,但指向不同的方向。Getzel 醒来后顺着他鞋子朝向的方向走去,于是他不知不觉地走回了家。盖泽尔断定还有一个和他一模一样的切尔姆。不仅如此,由于一切都与他自己的城镇相同,他甚至得出结论,整个世界是一个巨大的 Chelm。
尽管这个故事有各种版本和解释,但它说明了一个误导数据驱动决策的案例。在这个故事中,决策者使用数据(和模型)来评估他的风险。格泽尔做出了明智的决定,但却是错误的决定。他的决定导致了意想不到的后果和不准确的结论,最终增加了不确定性,而这正是数据驱动的决策制定所要最小化的。
在绝大多数情况下,我们更喜欢依靠数据而不是我们的信念或直觉来做决定,尤其是那些涉及风险的决定。因为冒险对回报至关重要,所以我们经常以这样或那样的方式在做决定前评估风险。我们有兴趣了解个人或组织层面的任何逆境的机会(如果可能的话,还有严重程度),从健康到财富,从财产到气候。
我们用来做这些决定的数据由一个模型处理和解释。模型是现实生活情况或自然现象的表现。例如,算法是遵循一套规则或计算的模型,允许我们解决问题,从而做出决策——但或许更重要的是,使这一过程自动化。
算法由数据提供,数据的准确性以及定义模型规则的准确性决定了结果的准确性(即预测准确性)。在静态条件下,当使用通用算法来自动化简单的决策(如 Getzel 的算法)时,大多数模型都会产生相当准确的结果。当提供给模型的数据没有被正确验证时,问题就出现了。结果,预测的事件或结果不再准确,导致错误的决策。
让我们抛开现实生活中需要考虑的关键因素,比如数据的大小、安全性和隐私。Getzel 的天真模型提供了一个很好的线索来记住去哪里,然而收集的数据却指向了错误的方向。在这种情况下,问题超出了通常用来描述数据质量重要性的众所周知的“垃圾输入,垃圾输出”。这里关注的是我们需要在现实生活中实施的政策和措施,以确保收集的数据为我们指明正确的方向。
因此,我们获取、准备和分析数据的方式至关重要。低估它的重要性会产生一系列不准确的结论、错误的行动和意想不到的问题——甚至是想象中的问题,如 Getzel 的问题。这个故事经常被命名为“切尔姆的白痴”,这可能不是巧合
Getzel 的故事为当今的大数据世界提供了一个有意义的教训,在这个世界中,我们将各种个人和集体决策委托给机器。这个故事与组织内数据分析的民主化以及人工智能的民主化特别相关。它清楚地说明了建立治理框架以从技术和道德上增强人工智能等数据驱动技术的重要性。
没有数据和解释这些数据的模型,我们的决定只是意*。有了有缺陷的数据或模型,我们的决定可能会像由观点产生的决定一样误导人,但没有犯错的借口。
第二部分:罗摩衍那的悲剧英雄——我们的模式有多好?

由 Ruslan Poluektov 在 Shutterstock 拍摄的照片
《美猴王的故事》是一部《罗摩衍那》的印度教史诗。在这个故事中,孙悟空或《罗摩衍那》的悲剧英雄瓦阿里和他的兄弟苏格里瓦追捕进入一个深洞的恶魔玛雅维。瓦利进入洞穴追捕恶魔,告诉苏格里瓦在外面等着。苏格里娃等了一年,然后血随着痛苦的哭喊从洞穴中涌出。苏格里瓦断定他的兄弟已经被杀,因此,为了防止恶魔攻击他们的领域,苏格里瓦用一块石头封住了洞穴,成为了猴子之王。然而,瓦阿里并没有被杀死,事实上,他战胜了恶魔。当他回家后,看到苏格里瓦扮演国王,他断定他的兄弟背叛了他。故事的结果是两兄弟变成了死敌,最终导致了瓦阿里的死亡。
和前面的故事一样,做出的决定是由数据驱动的,但却是不正确的。与 Getzel 一样,Sugriva 没有验证为模型提供的数据,兄弟俩也没有验证所用模型的正确性,导致了不准确的结论和意想不到的后果。
让我们把现实生活中需要考虑的关键但更复杂的方面放在一边,比如偏*、模型拟合、概念漂移、可解释性和其他一些问题。乍一看,瓦阿里的模型是有道理的,但它实际上并没有提供密封洞穴的原因。在现实生活的问题中,系统不是被设计来做一次性的决定,而是通过使用算法来自动化任务。这进一步增加了问题的难度,因为它需要找到一个具有最佳性能的算法,因此“给定带有标签 Y 的数据 X,找到一个误差最小的模型。”
在人工智能(AI)环境中,如果一个模型表现良好,我们通常不会关注为什么要做出决策,只要知道验证或测试数据的预测性能良好就足够了。然而,尤其是当这些预测对人类有很大影响时(例如,在医疗保健、金融、交通等方面的应用)。),理解为什么是必须的。
罗摩衍那的故事提供了一个简单的例子来说明为什么我们不仅仅相信模型。在这个故事中,模型没有显示输入和输出之间的正确关系,因此它没有对潜在问题提供令人满意的解释或预测。
总之,这两个故事都说明了数据和模型缺陷的风险。他们表明,检测输入数据中的异常是良好的数据驱动决策的基础。它们还表明,模型处理或解释数据的方式最终限制了它的预测能力。
但是这里有一个警告,所有的模型都有内在的局限性,因为它们是心智的构造。它们是对某个现实的抽象练*的结果。因此,不确定性是模型本身固有的,因此,通常使用概率来管理模型误差。然而,当 (1) 模型的结果导致意想不到的后果时,如格采尔回国或苏格里瓦成为国王,或者当 (2) 这些结果描述了一个扭曲的系统,如格采尔或瓦阿里对世界的解释,关于模型和数据的合法性的严重问题就出现了。
这样,像 Getzel 或 Sugriva 这样的简单模型需要被质疑,更复杂的模型需要被审视。当大规模部署人工智能技术时,许多人的鞋子可能会指向错误的方向,或者在错误的时间自动封闭洞穴,甚至有人会注意到这一点。
由于这种决策的影响,组织应该采用治理框架,该框架包含标准、风险和责任,尤其是与算法决策相关的。因此,需要进行根本性的转变和组织变革,以便在保护这些数据的生产者和消费者的同时,使数据能够用于良好的决策。
数据需要由专题专家彻底检查,数据质量标准需要由公共和私营部门合作制定和修订。模型需要经过讨论,也需要与其他模型进行比较和补充。这一点尤其重要,因为模型是不可避免的:我们需要它们。尽管它们有内在的不确定性,但它们引导我们做出决定,它们是我们理解和解决问题的唯一工具。
这两个工具将提升您的 Python 脚本。
原文:https://towardsdatascience.com/two-tools-that-will-boost-your-python-scripts-82adb3d8949e?source=collection_archive---------29-----------------------
if name == 'main '和 argparse (+ bonus)
你将在这里读到的这两个工具将会成倍地提高你的 python 脚本的可用性。

由马克塔·马塞洛娃在 Unsplash 上拍摄的照片
如果你读了一堆代码,或者你正在开发一个大项目,你需要写不止一个脚本,你需要知道 if name== 'main '是什么。一种只编写一次函数并在所有脚本中使用它的方法。
如果你想做一个程序,那么任何人都可以执行 argparse 库,它会帮你高效地完成。向代码中引入帮助和不同参数的方法。
if name == 'main':
name 变量是怎么回事?当 python 解释器读取源文件时,它首先定义几个特殊变量。在这种情况下,name 就是其中之一。
主要的呢?你会知道你的代码可能有不同的部分。你定义的函数是其中之一,另一个是主要部分。通常,main 是您使用函数的地方,以使您的代码完成设计的目的。正如你所知道的,它没有义务使用函数,但是如果你需要多次做一件具体的事情,最好把它封装在一个函数中,并有一个不言自明的名字。这是一个很好的方法来组织你的代码结构,所有的功能都在主要部分之上。现在你会明白为什么了。对于一些陌生人来说,这将使你的工作更容易,可读性更强。这总是一件好事。谁知道在编写代码后的几个月内,这个陌生人会不会是你。
好了,理解了 name 变量和' main '变量之后,让我们看看当我们把它们放在一起时会发生什么。最好的方法是通过一个例子。
想象一下,你有一个想要做任何事情的脚本。您正在构建另一个脚本,其中需要旧脚本中创建的一些函数。你能做什么?你可以利用古老的复制粘贴*惯。但是这会在你的代码中增加更多的行,而且不清楚新的脚本会做什么。太多事情了。如果能够像我们通常使用的库(numpy、pandas、seaborn 等)一样导入旧脚本中创建的函数,那将非常有用。).这是你的解决方案:
if __name__ == 'main':
您将这一行代码放在旧脚本的主要部分之上,所有后续代码都适当缩进,就像普通 if 一样。就是这样。您已经准备好了导入函数的代码。这丝毫不会改变脚本之前的行为。事实上,如果您正常执行它,它会正常工作。
但是现在,如果您决定使用您已经创建的函数,您只需导入旧的脚本,因为它是一个库。假设旧脚本的名称是 old_script.py,您只需放入新脚本:
from old_script import this_function, that_function
在新脚本中有您的旧函数(并且只有这些函数)。
argparse

由克里斯托弗·高尔在 Unsplash 上拍摄的照片
通常,你的代码会被其他人执行,他们不会打开你的代码。所以你需要给他们一些信息,或者如果你的脚本需要一些具体的输入,你必须为用户找到一个合适的方式。例如,如果你在脚本中进行声音分析,你需要输入一个声音。
传统的方法是输入脚本,搜索处理过的输入的加载位置,并针对您想要分析的声音对其进行修改。这,有时候并不是一件容易的事情。尤其是当脚本很长或者读者在理解代码的作用时。因此,当我们希望我们的程序被大量的人使用,或者可能被非技术人员使用时,argparse 库将会给我们很大的帮助。它会给他们一个代码描述,它会告诉用户为了让你的代码运行,他必须输入什么。
Argparse 是一个 Python 库,它将您的脚本与您的终端进行通信。它允许编码者在代码中放置某种标志(及其相应的解释),以便从终端执行它们。
让我们来看看它是如何工作的。
import argparseparser = argparse.ArgumentParser(description='''The purpose of this script is to with two given numbers save the result of its multiplication''', formatter_class=argparse.RawTextHelpFormatter)
首先,我们有我们的脚本描述。正如我们在上面看到的,这个脚本(为了简单起*)只是一个乘数,你需要在这里引入两个术语。formatter_class 属性仅适用于将它打印到终端的方式。我们马上就能看到。
parser.add_argument('-ft', '--first_term', default=1, type=int, help='''First term to multiply''')
这个增加的论点更有趣。我们看到两个可能的标志('-'和'-'),这与 Linux 终端的工作方式完全相同。一个破折号是两个破折号的缩写形式。我们还有将要介绍的数据类型。一个默认值,以防用户没有引入。和一个说明该参数作用的帮助属性。
parser.add_argument('-st', '--second_term', default=1, type=int, help='''Second term to multiply''')
第二个论点并不神秘。它的工作原理和第一个完全一样。
parser.add_argument('-od', '--output_directory', default='/home/toni_domenech/Python/Datasets/multiplication/', type=str, help='Output folder for the .txt')
这个包含了我们想要保存乘法结果的地方。请注意,该类型是一个字符串,因为我们在这里给出了一个路径。在这种情况下,默认输出是我的电脑的目录。所以如果试图运行我的代码的人,在这里没有引入任何东西,代码就不能正常运行。
最后,让我们看看如何在我们的代码中使用这些参数。
args = parser.parse_args()args.first_term * args.second_term
这里我们有使用它们的方法。我们将使用国旗的名字。仅此而已。
执行这段代码的方式与您之前编写的任何其他 python 脚本是一样的。
python script.py -h
它将为我们提供脚本的描述和所有要用它的描述填充的标志。
现在让我们给它们一个值。
python script.py -ft=5 -st=7 -od='/my_computer/desktop/'
就是这样!
如果你已经读完了,这里有一份礼物:
在这个故事中,你会发现作为一个高级开发人员使用一个超级简单的包来编写 Python 的秘密工具。
如果你有任何疑问尽管问,我很乐意回答。如果你喜欢,你可以鼓掌!它将帮助其他人找到这个故事!
Thx!
在 Python 中创建表的两种方法
原文:https://towardsdatascience.com/two-ways-to-create-tables-in-python-2e184c9f9876?source=collection_archive---------5-----------------------
Python 中制表和熊猫数据帧函数的性能比较

照片由 Fotis Fotopoulos 在 Unsplash 上拍摄
在之前的教程中,我们讨论了如何使用 制表 函数在 Python 中创建格式良好的表格。但是,我们也可以使用 pandasdata frame函数创建一个 DataFrame 对象来显示表格(二维)数据。
毫无疑问,当需要对数据进行任何类型的统计分析或机器学*时,pandas DataFrame 对象是最佳选择。但是,当唯一的目标是将数据组织成可读性更好的格式时,这两个函数都可以用来实现。
如果我们处理大量数据,使用计算效率最高或执行时间最少的函数是有意义的。
因此,在本教程中,我们将利用 timeit 函数来比较 制表 和 数据帧 函数的效率。
导入功能
首先,我们将导入必要的函数,如下所示:
from tabulate import ***tabulate***
from pandas import ***DataFrame***
from timeit import ***timeit***
创建函数
然后我们将创建两个函数,一个使用 制表 函数,另一个使用熊猫 数据框 函数,来显示我们的表格数据。
在这两个函数中,下面的字典 info 将用于提供表格数据:
**info** = {'First Name': ['John', 'Mary', 'Jennifer'],
'Last Name': ['Smith', 'Jane', 'Doe'],
'Age': [39, 25, 28]}
使用制表的函数
def ***tabulate_table***():
**info** = {'First Name': ['John', 'Mary', 'Jennifer'],
'Last Name': ['Smith', 'Jane', 'Doe'],
'Age': [39, 25, 28]}
**table** = tabulate(**info**, headers='keys', showindex=True, tablefmt='fancy_grid')
我们传入 信息 作为 制表 函数的表格数据。我们选择字典中的键作为表格的标题,并使用 fancy_grid 表格格式。我们设置 showindex 为True因为一个熊猫data frame默认显示一个指数。
制表 _ 表格() 函数将创建以下表格:

详细了解 制表 功能:
使用数据帧的函数
def ***pandas_table***():
**info** = {'First Name': ['John', 'Mary', 'Jennifer'],
'Last Name': ['Smith', 'Jane', 'Doe'],
'Age': [39, 25, 28]}
**table** = DataFrame(**info**)
pandas_table() 函数将创建以下数据帧:

制表函数创建一个字符串对象,而数据帧函数创建一个熊猫数据帧对象。
表演
我们将使用 timeit 函数来测量每个函数运行 10,000 次所需的时间,如下所示:
print(f'Time for tabulate: {**timeit**(tabulate_table, number=10000)}s')
print(f'Time for DataFrame: {**timeit**(pandas_table, number=10000)}s')**Output:**
Time for tabulate: 3.357472500001677s
Time for DataFrame: 6.2918465999991895s
如上所述,与 DataFrame 函数相比, 制表 函数创建表格的时间大约是前者的一半。因此,当我们的唯一目标是将表格数据显示成可读性更好的表格时,那么是 pandasdata frame的一个很好的替代品。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名媒体成员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你用我的 链接 报名,我就赚一小笔佣金。
*https://lmatalka90.medium.com/membership *
我希望你喜欢这个 制表 和 数据帧 函数之间的性能比较。感谢您的阅读!
两年的数据科学博客:以下是我学到的 5 个关键经验
原文:https://towardsdatascience.com/two-years-of-data-science-blogging-here-are-5-key-lessons-i-learned-9bd0ddbc0cd9?source=collection_archive---------31-----------------------
如何从零到百万浏览量,在这个过程中不迷失自己和他人?

照片由泰在 Unsplash 上抓拍
写两年关于数据科学的文章能教会你一些东西。仅关于数据科学的 200 多篇文章就给我带来了很多经验、*解和金钱。
今天,我将与你分享一些关于写作的令人大开眼界的东西。你将读到的一切都是基于科技、编程和数据科学的写作。这篇文章的观点可能不太适合其他领域,比如自我完善和小说。
先说一个大多数软件和数据专业人士都会犯的错误。
你不必成为专家,只要领先一步
写博客文章和写科学论文不一样。然而,许多人无法区分这两者。
写一篇简单的“如何做”的数据科学文章不需要博士学位。你所需要的就是比你的目标观众领先一步。例如,如果你的目标是写关于时间序列预测中的移动*均模型,你需要知道一些基础理论、数学和代码实现。
成为专家不会有坏处,但是一旦你陷入太多的数学、证明和不必要的理论,你的文章的观点就会受到影响。读你作品的人很着急,需要一个解决方案——快。博客文章不是书,也不是科学论文。这篇博文的价值在于你有能力在 5 分钟的阅读中总结 100 页的主题。
记住这一点,几乎任何人都可以就他们昨天学到的技术写一篇像样的博文。我愿意走得更远,说初学者可能比熟练的专业人员更擅长教学——因为一个初学者知道另一个初学者的挣扎。
看看你喜欢的在线导师吧。我愿意冒险说他们有 20+领域的课程。他们一定是所有行业的领导者吗?不知道。但是他们知道如何教得恰到好处,这样你就可以放心地自己进一步探索。
人们关心的是一个故事,而不是一个教程
但是写教程就简单多了。
我的大多数文章都是基于一个个人故事或者有一些个人风格,都获得了 5-10 次以上的浏览和掌声。原因很简单——人们可以认同你的观点和看法,但不能完全认同一份没有感情色彩的“操作指南”。
写一两段关于你如何以及为什么使用一些技术来解决一个特定的问题可以和读者建立一个即时的联系。另一方面,一篇 3000 字的关于某项技术来龙去脉的一般性文章很可能会让读者转向别处。
保持简短,并加入个人风格。这比你想象的要难。
人们想要你的意*——即使有成千上万篇关于这个话题的文章也没关系
标题说明了一切。这一点与上一点密切相关。我收到了至少十几条信息,询问如何想出“原创”的文章创意。
简单的回答是— 不能。
如果你是某个库或某个产品的创造者,你可以。对于其他人来说,想出从未*过的文章创意几乎是不可能的。通过文档或无数的文章,一切都已经可用并得到了解释。
这是件好事。
比如,看看我的 M1 MacBook 系列。尽管这款芯片早在六个月前就发布了,但整个 M1 话题仍然是新闻热点。网上有成千上万篇类似的文章,但从数据科学的角度添加我对这个话题的看法带来了成千上万的浏览量,并完全支付了我的 M1 MacBook Pro。
人们想要阅读观点文章。因此,写这样的文章会比任何“如何做”指南更快地吸引志同道合的读者。
写作的可能性是无限的
前一点讨论了试图提出原创想法是极其困难和毫无意义的。然而,想出你的第一篇文章的想法并不容易。
这里有一个你能做什么的例子。
假设你写了一篇题为《数据科学家需要的 5 大编程技能》的文章。不一定是你的文章——可以基于你觉得有用的一篇文章。这些技能包括数据结构和算法、设计模式和软技能。现在怎么办?
你可以写后续文章,对每一个问题进行更深入的探讨。例如:
- 为什么数据科学家必须学*数据结构和算法
- 为什么数据科学家必须学*设计模式的基础知识
- 你是数据科学家吗?以下是你必须掌握的软技能
标题有点笼统,但你明白了。
你还可以深入到每一个单独的点。例如:
- 为数据科学家解释的链表
- 递归的数据科学指南
- 为数据科学家解释搜索和排序算法
这里,关键的要点是向不一定有很强编程背景的人解释众所周知的编程概念。
这就是你如何从一篇文章中产生 10 多个文章想法的方法。
一旦你开始关注数据和金钱,你就会开始讨厌写作
从写作中赚点外快真好。我写数据科学比全职做中级数据科学家赚得多。*有道理?*谁也说不清。
那很可能是你。
回到正题。一旦写作的收入持续稳定,人们很容易沉迷于统计数据和个人文章收入。在 Medium 上尤其如此,因为他们的统计面板非常壮观。
从写作中挣很多钱的唯一坏处是——当你想辞职或写作时,你不想辞职或写作。一夜之间,它可能成为你没有要求的第二份工作。就像任何工作一样,很快你就会觉得这只是你在一天结束前不得不做的另一件事。
为了额外的钱而与所爱的人交换时间是不值得的,几个月后,这会让你讨厌写作。当我试图在全职工作、每周写 4-5 篇文章、大学和一段感情之间取得*衡时,我就遇到了这种情况。如果你能在 24 小时内适应所有这些,并且睡个好觉,你就是一个比我更好的人。希望你 35 岁的时候不会中风。
对我来说,最佳状态是每周工作 50 小时左右。这包括一份全职工作和写 2-3 篇文章。您的里程可能会有所不同。
只是不要在这个过程中失去你自己,你的健康,和你亲近的人。
最后的话
总而言之,写了 200 多篇数据科学和编程文章让我明白了写作可以比全职工作更赚钱。我是一名中级数据科学家,一个小时的写作比一个小时的日常工作大约多 4 倍的利润。
这个数字对你来说可能不一样。它们在很大程度上取决于你住在哪里以及你做什么样的工作。
尽管如此,如果你愿意付出努力,每周写两篇文章可以带来可观的额外收入。最具挑战性的是开始,为什么不现在就开始呢?
只是不要让它压倒你,让你远离朋友和亲人。和他们在一起的时间是你买不到的。
喜欢这篇文章吗?成为 中等会员 继续无限制学*。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
https://medium.com/@radecicdario/membership
了解更多信息
- 2021 年学*数据科学的前 5 本书
- 如何使用 Cron 调度 Python 脚本——您需要的唯一指南
- Dask 延迟——如何轻松并行化您的 Python 代码
- 如何用 Python 创建 PDF 报告——基本指南
- 在 2021 年成为一名数据科学家,即使没有大学文凭
保持联系
- 在媒体上关注我,了解更多类似的故事
- 注册我的简讯
- 在 LinkedIn 上连接
二型模糊集导论
原文:https://towardsdatascience.com/type-2-fuzzy-sets-812c5b4d602d?source=collection_archive---------13-----------------------
熟悉 2 型模糊集和逻辑背后的一些基本概念

图片由 pixabay.com 拍摄
介绍
在之前的一篇文章中,我们已经看到了当我们不能确定一个元素的成员是 0 还是 1 时,我们如何使用类型 1 的模糊集。当环境如此模糊,以至于我们很难将隶属度确定为[0,1]中的一个数字时,我们可以扩展这个概念。在这些情况下,2 型模糊集提供了必要的框架来形式化和处理这些信息。
这篇文章将着眼于 2 型模糊集背后的基本概念。我们将根据 Robert John 和 Jerry Mendel 的“Type-2 Fuzzy Sets made Simple”进行讨论,这可能是学* Type-2 Fuzzy Sets 和逻辑的最佳论文。
什么是二型模糊集?
我们从重申模糊集理论背后的动机开始讨论。让我们假设今天的温度是 25 摄氏度,或 77 华氏度。我们能认为今天是个大热天吗?一个精确的温度计读数告诉我们关于一天的什么,我们应该如何根据这个读数来调节我们的行为?
美国国家海洋和大气管理局(NOAA)认为 26 至 32 度之间的范围为“小心”,并将温度范围进一步确定为“危险”和“极度危险”如果我们坚持这个定义,我们可以想象 NOAA 画的热天的界限。因此,我们可以得出结论,今天不会属于'热'天的范畴,也许在'温暖'或'略热'的一天。
用这种逻辑对一天进行分类将意味着任何低于 26 度和高于 32 度的温度都不会使这一天变得“热”。
如果我们从模糊的角度看待“热”天的概念,我们的推理将会改变。我们可以认为 20 度有点“热”,而 30 度肯定是“热”。另一方面,我们可以把四十度归类为超越‘热’的温度;也许它可以归入“炎热”一类。将“热”视为一个模糊的概念会将刚性边界转换为一条曲线,该曲线定义了不同类别中每个温度的不同等级。因此,温度可以是“温暖的”。“热”和“炎热”同时出现,尽管在每个类别中程度不同。

现在让两个不同的人画出他们对模糊集“热”的感知,并几乎肯定地要求他们使用梯形集来描述。我们将得到两个略有不同的定义。我们将看到,当我们要求更多的人提交他们的定义时,给定温度对集合“热”的隶属度将逐渐模糊,而描述隶属度的每个点将依次转化为三维函数中的模糊集合。结果是类型 2 的模糊集。
因此,第二类模糊逻辑是由概念对不同的人有不同的意义这一前提所激发的。

用于定义“热”温度概念的第二类模糊集(我们用 A 表示)如下所示:

二型模糊集
2 型模糊集的隶属函数是三维的,具有
- x 轴称为主变量
- y 轴被称为由$u$表示的二级变量或二级域。我们注意到,该轴表示类型 1 集合中的隶属度,因此范围在**【0,1】**中。然而,在这种情况下,我们对每个主要变量值都有一个隶属度值范围。
- z 轴被称为隶属函数值 ( 二级),由下式表示
定义 2 型模糊集最直接的方法是考虑构成一个集合的三维空间中所有点的集合。因此,形式上,类型 2 集合也可以表示为:
其中二重积分符号表示连续论域的容许的 x 和 u 的并集(对于离散论域,使用二重求和符号代替),
因此,我们可以将上面所示的类型 2 集合描述如下:
(1 / 0 + 0.3 / 0.2)/15 +(0.6 / 0.2 + 1 / 0.4 +0.7 / 0.6 )/20 +(0.4 / 0.6 + 0.7 / 0.8 +1 / 1 )/25 +(0.4 / 0.6 + 0.7 / 0.8 + 1 / 1 ) /30 +(0.2 / 0.3 + 0.6 / 0.5 + 1 / 0.7 +0.4 / 1 ) / 35 +(0.3 / 0.2 + 1 / 0.4 + 0.4 / 0.6 ) /40 +(1 / 0 + 0.6 / 0.2 ) / 45
此外,
被称为主要成员,将在下一节详细讨论。
垂直切片
如果我们分离出一个主变量值,我们注意到我们得到一个称为垂直切片的 1 型模糊集。


因此,垂直切片是 1 型模糊集;
正式定义为:
由垂直切片产生的函数也被称为次级隶属函数,正式书写为
即
因此,在 x=20 处的次级隶属函数为:
0.6 / 0.2 + 1 / 0.4 +0.7 / 0.6
次隶属函数的域称为 x 的主隶属度。因此在上面的等式中
是主隶属函数
J_{20}= {.2, 0.4, 0.6}
二级隶属函数的幅值为二级等级。因此在上面的等式中, f(u) 是二级等级。
如果 X 和 J 是离散的:
关于中学年级,我们可以注意到
是二级成绩。
嵌入式 2 型套
通过从集合中的每个次级隶属函数中取出单个元素,可以为离散的 X 和 U 创建一个嵌入式类型 2 集合。因此,如果 X 有 N 个元素,我们的 type-2 集合正好有一个元素来自
也就是
每个都有相关的等级
使得:

总共有
二型模糊集中的嵌入集
因此,所识别的嵌入式 2 型模糊集是:
1 / 0 / 15 + 0.6 / 0.2 / 20 + 0.4 / 0.6 / 25 + 0.4 / 0.6 /30 + 0.2 /
我们还注意到,我们的集合包含 2 x 3 x 3 x 3 x 4 x 3 x 2 = 1296 ,嵌入式 type-2 集合。
然后,我们还可以通过所有嵌入的 2 型模糊集的集合来表示 2 型模糊集,称为波浪切片表示法或**孟德尔-约翰表示法。**因此,波形切片表示为:
1 型模糊集
1 型模糊集可以表示为 2 型模糊集。其类型 2 表示为:
1 的值意味着次级隶属函数在其定义域中只有一个值,即次级等级等于 1 的初级隶属。
足迹的不确定性
第二类集合的 2D 支持称为不确定性足迹(FOU)
FOU 表示第二类集合中主要成员的不确定性。它是所有主要成员的联合。

阴影 FOU 意味着在第三维中的类型-2 模糊集的顶部的分布,其取决于二级等级的选择。当所有二型集的二级等级都等于 1 时,该集称为区间二型模糊集。
我们注意到,不确定性的足迹有上下限,称为上下隶属函数:
下级隶属函数

上层隶属函数

结论
在这篇文章中,我们讨论了 2 型模糊集作为一种更复杂的结构,我们可以解释用 1 型模糊集无法解释的模糊性。我们还研究了构成类型 2 集合的基本原则,不确定性和嵌入集合的足迹。在以后的文章中,我们将讨论如何将 1 型逻辑扩展到 2 型逻辑。
感谢本·胡伯尔曼
Python 中的类型注释
原文:https://towardsdatascience.com/type-annotations-in-python-d90990b172dc?source=collection_archive---------0-----------------------
编写额外的代码

作者图片
类型注释在 Python 中有着漫长而复杂的历史,可以追溯到 Python 3 的第一个版本,以及函数注释的最初实现。

从 Python 3.0 到现在类型注释的变化时间表。
从那以后,特性来了又去。类型提示的前景已经经历了几次大的变革——特别是 Python 的两个最新版本——3.9 和(即将到来的)3.10。
在本文中,我们将看看这些特性——以及我们如何在自己的代码中应用类型提示!
什么是类型注释?
类型注释——也称为类型签名——用于指示变量的数据类型以及函数和方法的输入/输出。
在许多语言中,数据类型是显式声明的。在这些语言中,如果你不声明你的数据类型,代码将不会运行。
让我们以 C 语言的 hello world 脚本为例:
#include<stdio.h>**int** main()
{
**char** hello**[]** = "hello world!";
printf("%s\n", hello);
return 0;
}
这里我们定义了两种类型签名,int和char。这段代码可以完美地编译和运行。但是如果我们去掉我们的char签名会发生什么呢?

在变量定义中缺少类型签名 char 会给我们带来编译时的痛苦。
我们的代码不会工作。c 要求我们声明所有的变量数据类型。
Python 更加宽容——我们不需要在任何时候定义类型。
静态与动态
编程语言中有这些方法的名称。c 要求我们显式定义类型——它是一种静态类型化的语言。
另一方面,Python 是一种动态类型化的语言,它对变量赋值的方法更加狂热。
我们如何定义这两种方法?
- 静态类型 —在编译时执行类型检查,并且需要数据类型声明。
- 动态类型化 —在运行时执行类型检查,并且不需要数据类型声明**。**
这两种方法都有优点和缺点,但是静态类型语言的一个优点(适用于我们)是它使得代码非常明确。举两个例子来说明为什么这很有用:
- 代码中明确定义了数据类型,消除了任何潜在的数据类型歧义。
- 编写代码时,较小的输入错误和错误更容易识别,例如:
*characters = 'am a'
character = 'I ' + characters + ' string'*
第二个变量应该是character**s** 而不是character。在静态类型化语言中,这种拼写错误会引发错误,但对于动态类型化语言,则不会。
另一方面,静态类型的代码被很多人认为过于冗长。使得代码的读写更加复杂。
实际上,这两种范式都不比另一种更好或更差。他们各有长处和短处。
现在对泛型类型注释已经说得够多了,那么 Python 类型注释呢?
Python 的类型注释
Python 中的类型注释与我们的 C 示例中的成败攸关。它们是可选的语法块,我们可以添加它们以使代码更显式。
错误的类型注释只会在我们的代码编辑器中突出显示错误的注释—注释不会引发任何错误。
因此,如果不强制执行类型注释,为什么要使用它们呢?
正如我们已经谈到的,声明类型使我们的代码更显式,如果做得好,就更容易阅读——对我们自己和其他人来说都是如此。
基础
从 Python 3.9 中,我们可以定义如下数据类型:
很酷吧?在第一行中,我们将hello初始化为字符串,然后为其分配"hello world"。
之后,我们定义了一个简单的函数,并声明了两个输入参数x和y的预期数据类型,甚至是函数返回的数据类型-> **int**。
现在,如果我们输入一个不正确的注释,会发生什么?
实际上,没什么重要的——记住,Python 并不或强制我们的类型注释。

我们的 Python linter 突出显示了我们的代码,提供了错误的警告。

将鼠标指针放在突出显示的代码上可以告诉我们,经过了一个 str ,在那里我们会得到一个 int 。
代替,它们由第三方 IDEs 和短绒使用。因此,我们的第三方工具就会凸显出一个错误的诠释——它就像一个预警系统,告诉我们的逻辑并不完全正确。
合并数据类型
除了基本数据类型int、str、float、dict等,我们还可以将它们组合起来创建更复杂的类型结构。
所以,鉴于两本字典:
*str_int = {'one': 5, 'two': 7}
int_int = {1: 5, 2: 7}*
我们可以将这两个对象定义为dict类型。要编写一个函数,期望其中任何一个字典作为输入,我们可以写:
*def sum_dict(var: **dict**):
return sum(var[key] for key in var.keys())*
但是,我们想要指定的是,我们期望一个包含str类型的键和int类型的值的字典?好吧,我们可以重写我们的函数来精确地指定它。
*def sum_dict(var: **dict[str, int]**):
...*
现在,当在我们的 IDE 中将str_int和int_int输入到同一个函数中时,我们会发现int_int被高亮显示。

我们的 Python linter 强调了我们错误的输入类型。

将鼠标悬停在高亮显示的变量 int_int 上,会显示此警告消息。
我们的第一本字典str_int将顺利通过。然而,int_int返回不兼容类型警告。
联合
在某些情况下,我们可能希望允许一组不同的类型用于一个单独的赋值。
例如,在我们之前的加法函数中,我们真的只允许整数吗?或者我们更愿意允许整数或浮动?
为了允许多种数据类型,我们可以使用类型联合运算符。Python 3.10 之前的版本如下:
*from typing import Uniondef add(x: Union[int, float], y: Union[int, float]) -> Union[int, float]:
return x + y*
这里,我们允许使用int或float数据类型!使用 Python 3.10(完整版本是 2021 年 10 月),我们可以用新的 union 操作符|替换Union:
*def add(x: int | float, y: int | float) -> int | float:
return x + y*
可选运算符
我们应该考虑的最后一种类型是Optional操作符。
当我们定义一个带有可选参数的函数时,我们可以使用Optional类型来指定。例如,我们可以向我们的add函数添加一个可选的字符串参数:
*from typing import Optionaldef add(x: int, y: int, op: **Optional[str]**) -> int:
...*
这里,我们的类型注释将期望一个None值或者str数据类型。我们也可以用一个Union来写这个精确的逻辑:
*def add(x: int, y: int, op: **Union[None, str]**) -> int:
...*
产生完全相同的注释,允许使用None值或str数据类型。

add 函数使用可选的操作符,而 add2 函数使用 Union 操作符和None——两者产生相同类型的注释。
以上是对 Python 中类型注释的介绍——如果应用得当,这是对 Python 生态系统的一个惊人的补充。
我希望你喜欢这篇文章。如果您有任何问题或建议,请通过 Twitter 或在下面的评论中告诉我。如果你对更多类似的内容感兴趣,我也会在 YouTube 上发布。
感谢阅读!
如果您有兴趣了解更多有趣的 Python 特性,请查看这篇关于 Python 3.10 中新的匹配案例声明的文章:
* *
🤖《变形金刚》NLP 课程 70%的折扣
*除另有说明外,所有图片均出自作者之手
用 Python 输入提示——5 分钟内你需要知道的一切
原文:https://towardsdatascience.com/type-hints-in-python-everything-you-need-to-know-in-5-minutes-24e0bad06d0b?source=collection_archive---------8-----------------------
在 Python 脚本中实现类型提示和静态类型检查。包括源代码。

照片由Robbie DownonUnsplash
Python 一直是一种动态类型语言,这意味着您不必为变量和函数返回值指定数据类型。PEP 484 引入了类型提示——一种让 Python 感觉静态类型化的方法。
虽然类型提示可以帮助您更好地构建项目,但它们只是提示,默认情况下不会影响运行时。然而,有一种方法可以在运行时强制进行类型检查,我们将在了解一些基础知识之后,在今天探索这种方法。
这篇文章的结构如下:
- 类型提示简介
- 注释变量
- 探索打字模块
- 在运行时强制类型检查
- 最后的想法
类型提示简介
如果您来自 C 或 Java 之类的语言,指定数据类型不会让人感到陌生。但是,如果你正在学* Python,几乎没有在线课程和书籍提到数据类型规范来简化事情。
随着代码库变得越来越大,类型提示可以帮助调试和防止一些愚蠢的错误。如果你使用的是像 PyCharm 这样的 IDE,只要你使用了错误的数据类型,只要你使用了类型提示,你就会得到一条警告消息。
让我们从简单的开始,探索一个没有类型提示的函数:
def add_numbers(num1, num2):
return num1 + num2print(add_numbers(3, 5)) # 8
这里没有什么突破性的东西,但是我故意声明了这样一个函数,因为整数和浮点数相加都可以。我们将在后面讨论如何用类型提示来指定这两者。
下面是如何向我们的函数添加类型提示:
- 在每个函数参数后添加一个冒号和一个数据类型
- 在函数后添加一个箭头(
->)和一个数据类型,以指定返回的数据类型
就代码而言,您应该进行以下更改:
def add_numbers(num1: int, num2: int) -> int:
return num1 + num2print(add_numbers(3, 5)) # 8
干净利落。如果你正在使用一个不应该返回任何东西的函数,你可以指定None作为返回类型:
def add_numbers(num1: int, num2: int) -> None:
print(num1 + num2)add_numbers(3, 5) # 8
最后,您还可以设置参数的默认值,如下所示:
def add_numbers(num1: int, num2: int = 10) -> int:
return num1 + num2print(add_numbers(3)) # 13
这一切都很好,但是如果我们决定用浮点数来调用add_numbers()函数呢?让我们检查一下:
def add_numbers(num1: int, num2: int) -> int:
return num1 + num2print(add_numbers(3.5, 5.11)) # 8.61
如你所*,一切都还正常。默认情况下,添加类型提示没有运行时效果。像mypy这样的静态类型检查器可以解决这个“问题”,但是稍后会详细介绍。
接下来让我们探索变量注释。
可变注释
就像函数一样,您可以向变量添加类型提示。虽然很有帮助,但是对于简单的函数和脚本来说,变量的类型提示可能有点过于冗长。
让我们来看一个例子:
a: int = 3
b: float = 3.14
c: str = 'abc'
d: bool = False
e: list = ['a', 'b', 'c']
f: tuple = (1, 2, 3)
g: dict = {'a': 1, 'b': 2}
声明几个变量需要大量的输入。事情可能会变得更加冗长,但稍后会有更多内容。
您还可以在函数中包含变量的类型批注:
def greet(name: str) -> str:
base: str = 'Hello, '
return f'{base}{name}'greet('Bob') # Hello, Bob
接下来,我们来探索一下内置的typing模块。
探索typing模块
Python 的typing模块可以让数据类型注释更加冗长。例如,您可以明确声明一个字符串列表、一个包含三个整数的元组以及一个以字符串为键、整数为值的字典。
方法如下:
from typing import List, Tuple, Dicte: List[str] = ['a', 'b', 'c']
f: Tuple[int, int, int] = (1, 2, 3)
g: Dict[str, int] = {'a': 1, 'b': 2}
让我们看看如何将这些包含到一个函数中。它将接受一个 floats 列表,并返回带有*方项的相同列表:
def squre(arr: List[float]) -> List[float]:
return [x ** 2 for x in arr]print(squre([1, 2, 3])) # 1, 4, 9
如您所*,它也适用于整数。我们稍后会解决这个问题。在此之前,让我们探索一下类型提示中的一个重要概念——Union操作符。基本上,它允许您为变量和返回值指定多种可能的数据类型。
下面是前一个函数的实现:
从打字进口联盟
def square(arr: List[Union[int, float]]) -> List[Union[int, float]]:
return [x ** 2 for x in arr]print(squre([1, 2, 3])) # 1, 4, 9
该函数现在可以无警告地接受和返回整数或浮点数列表。
最后,让我们探索如何在运行时强制进行类型检查。
在运行时强制类型检查
您可以使用mypy ( 文档)在运行时强制进行类型检查。在此之前,用pip或conda安装它:
pip install mypy
conda install mypy
接下来,让我们制作一个 Python 文件。我已经把我的命名为type_hints.py:
def square(number: int) -> int:
return number ** 2if __name__ == '__main__':
print(square(3))
print(square(3.14))
该函数接受整数并对其求*方,至少根据类型提示是这样。在执行时,函数同时用整数和浮点数来计算。下面是使用默认 Python 解释器时发生的情况:

图片 1-使用默认的 Python 解释器(图片由作者提供)
现在用mypy:

图 2 —使用 mypy 静态类型检查器(图片由作者提供)
正如你所看到的,mypy像宣传的那样工作,所以需要的时候可以随意使用。
接下来让我们总结一下。
最后的想法
Python 中的类型提示可能是好事也可能是坏事。一方面,它们有助于代码组织和调试,但另一方面也会使代码变得愚蠢冗长。
为了折衷,我在函数声明中使用了类型提示——参数类型和返回值都是如此——但是对于其他任何东西,比如变量,我一般都避免使用它们。最后,Python 应该很容易编写。
你对类型提示有什么想法?请在下面的评论区告诉我。
喜欢这篇文章吗?成为 中等会员 继续无限制学*。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
https://medium.com/@radecicdario/membership
了解更多信息
- 2021 年学*数据科学的前 5 本书
- 如何使用 Cron 调度 Python 脚本——您需要的唯一指南
- Dask 延迟—如何轻松并行化您的 Python 代码
- 如何使用 Python 创建 PDF 报告—基本指南
- 即使没有大学文凭也要在 2021 年成为数据科学家
保持联系
- 关注我的 Medium 了解更多类似的故事
- 注册我的简讯
- 在 LinkedIn 上连接
使用 PySpark 的数据分析器中的类型安全
原文:https://towardsdatascience.com/type-safety-in-data-parsers-using-pyspark-a81093b4fe03?source=collection_archive---------37-----------------------
使用 Apache PySpark 解析数据时确保类型安全

图为托姆·米尔科维奇在 Unsplash
数据工程师的主要任务之一是从多个来源获取数据。这些来源可能是 API 端点、流服务、将文件上传到云的 cron 作业等。从这些来源获取的数据被转储到数据湖中,随后用于解析和下游业务逻辑的 ETL。
但是这里的问题是:当涉及到源系统产生的字段的数据类型时,我们能依赖源系统,尤其是第三方吗?
最好不要依赖这些来源,而是在消费级别卸载类型检查和类型转换的过程,即让数据消费者根据自己的需要定义目标数据类型。
本文介绍了一种确保解析器类型安全的方法及其优缺点。
方法
以 JavaScript Object Notation (JSON)格式的数据为例,JSON 中的字段可以有多种类型。有时,我们甚至可能不知道哪些字段具有哪些数据类型,这使得跟踪和确保正确维护各个字段的类型变得极其困难。
因此,在 JSON 模式包含的所有字段中实施统一性是至关重要的。最安全的方法是在模式树的所有叶节点上强制执行StringType。 叶节点 是一个字段,可以是字符串、bigint 或时间戳等。类型,但不是结构类型或数组类型。
让我们来看看这是如何做到的:
在 JSON 数据中强制使用 StringType
假设您已经将 JSON 数据加载到一个 dataframe 中,JSON 列以名称json出现。
首先,模式是从 json 列中推断出来的。然后,enforce_stringtype函数对从 Spark 推断的模式中检索到的模式元数据执行深度优先搜索(DFS)。它检查模式元数据中的特定字段是否是叶。如果是叶字段,它将所有叶字段(不是 struct 或 array 类型的字段)转换为 string 并返回 else,它在 struct 或 array 字段内部遍历并将所有叶字段转换为 string 类型。
然后,模式元数据被转换回 StructType,用于在 json 列上强制执行更改后的模式。
然后,可以将所需的转换应用于可以从type_safe_json列获得的字段,以转换为数据消费者指定的目标数据类型。
赞成的意*
这种方法有几个优点。
- 转换为 StringType 不会导致任何数据丢失,也不会在摄取后和消费前过程中删除行。
- 数据源对 JSON 中的字段进行的任何数据类型更改,例如从整数到双精度,都是通过这种方法处理的。
- 强制 StringType 后完成的转换可以确保特定字段具有一组数据类型。
骗局
尽管这种方法有几个优点,但它也有一些缺点。
- 强制 StringType 后应用于字段的转换是一项额外的计算。此外,如果源系统是可靠的,这些字段可能已经固有了目标数据类型。因为它们被转换成字符串,然后再转换回目标数据类型,这意味着一个冗余的计算。
- 为要应用转换的字段设置目标数据类型是手工操作。如果有大量的字段要进行转换,这可能会变得很乏味。
- 向下转换将导致数据丢失(如 double 到 int),这必须由使用者解决。
总之,信任源系统保留每个字段的相同数据类型是有问题的。这种方法可以用来确保安全,避免由源系统引起的任何类型的数据类型冲突,但它有上述明显的缺点。将指定目标数据类型的过程转移给消费者,使得解析器独立于任何数据类型检查。这也符合在消费数据时决定模式的情况。
Typer:使用 Python 在一行代码中构建强大的 CLI
原文:https://towardsdatascience.com/typer-build-powerful-clis-in-one-line-of-code-using-python-321d9aef3be8?source=collection_archive---------14-----------------------
在命令行上轻松地向 Python 函数添加参数
动机
你有没有想过像下面这样在命令行上快速给 Python 脚本添加参数?

作者 GIF
能够从终端向 Python 脚本插入参数允许您和您的用户在不查看源代码的情况下轻松地试验不同的参数。
argparse 允许你编写命令行界面,但是它的语法很长。
有没有一种方法可以在一行代码中创建命令行界面,如下所示?
这就是 Typer 派上用场的时候。
Typer 是什么?
Typer 是一个基于 Python 的类型提示构建命令行界面(CLI)应用的库。它是由 FastAPI 的作者 Sebastián Ramírez 创建的。
Typer 书写简短,使用方便。要安装 Typer,请键入:
pip install typer
开始
要使用 Typer 为 Python 脚本创建 CLI,只需将typer.run(your-Python-function)添加到代码中。
将上面的文件命名为get_started.py。现在当你运行python get_started.py --help时,你应该会看到如下所示:

作者图片
通过查看帮助消息,我们知道应该向文件中添加什么参数。
现在尝试在python get_started.py旁边插入一个参数,看看我们会得到什么。

作者图片
酷!当我们改变参数时,输出也会改变。
帮助消息
要添加描述函数功能的帮助消息,只需向该函数添加一个 docstring。

作者图片
CLI 参数
没有默认值的 CLI 参数
好吧,酷。但是如果用户不明白NAME的意思呢?这时候typer.Argument就派上用场了。
您可以使用typer.Argument(default_value, help)向参数添加默认值和帮助消息。
因为参数name没有默认值,所以我们使用...作为默认值。
您应该会看到如下所示的帮助消息:

作者图片
请注意,参数name是必需的,因为没有默认值。
具有默认值的 CLI 参数
如果将默认值添加到参数name中,则不再需要该参数。

作者图片
现在您可以运行python argument_example.py而无需插入任何参数!

作者图片
带选项的 CLI 参数
如果我们希望用户从一个预定义的选项中进行选择,该怎么办?这可以通过使用 enum.Enum 来完成。

作者图片
不错!现在用户只能选择选项red、yellow或orange中的一个作为参数color的值。
CLI 选项
在下面的代码中,--is-user和--no-is-user是 CLI 选项。

作者图片
虽然 CLI 参数是必需的,但 CLI 选项不是必需的,并且以--开始。
具有默认值的 CLI 选项
要将函数的参数转换成 CLI 选项,请使用typer.Option。

作者图片
酷!由于--is-user的数据类型是bool,CLI 选项--no-is-user也是自动生成的!
当我们使用不同的 CLI 选项时,我们可以看到不同的输出,如下所示。

作者图片
没有默认值的 CLI 选项
我们还可以使用带有默认值的 CLI 选项:

作者图片
现在,我们可以通过使用--time=value向 CLI 选项time中插入一个新值。

作者图片
注意,由于我们在函数greeting中将参数time指定为int,所以我们只能在time中插入一个整数。如果我们插入一个字符串,我们将得到一个错误。

作者图片
CLI 选项提示
您也可以要求用户使用prompt=True插入 CLI 选项。

作者 GIF
注意 Typer 自动把 CLI 选项变成合理的提示!如果您想定制提示,只需将prompt=True替换为prompt=question:

作者图片
回收
有时,用户可能会插入无效值。在将这些值用于我们的函数之前,有没有一种方法可以检查它们?
是的,这可以通过在typer.Argument或typer.Option中添加关键字参数callback来实现。
在下面的代码中,我们将函数check_if_user_exists传递给callback。这个函数检查用户名是否存在。如果用户名不存在,我们抛出一个typer.BadParameter异常。

作者图片
多个命令
从终端向函数添加参数和选项很酷。但是如果我们在一个 Python 脚本中有不止一个函数呢?这时候装饰师app.command()就派上用场了。
在上面的代码中,我们:
- 创建一个名为
app的新typer.Typer()应用程序 - 将
@app.command()添加到我们想要创建命令的函数中 - 使用
app()创建一个具有这些功能的 CLI 应用程序
现在greeting和say-bye都可以作为命令使用了!

作者图片
只需执行python file_name.py command来使用特定的命令。

作者图片
多酷啊。
结论
恭喜你!您刚刚学*了如何使用 Typer 为您的 Python 脚本创建 CLI 应用程序。使用 Typer,您和您的用户可以毫不费力地将参数插入到 Python 脚本中。
既然为您的函数创建一个 CLI 应用程序只需要一行代码,为什么不试一试呢?
随意发挥,并在这里叉这篇文章的源代码:
https://github.com/khuyentran1401/Data-science/tree/master/terminal/typer_examples
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 Twitter 上与我联系。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
</2-tools-to-automatically-reload-when-python-files-change-90bb28139087> [## Ptpython:更好的 Python REPL
towardsdatascience.com](/ptpython-a-better-python-repl-6e21df1eb648)
数据偏差的类型
原文:https://towardsdatascience.com/types-of-biases-in-data-cafc4f2634fb?source=collection_archive---------5-----------------------
数据科学|统计学|机器学*
我们都应该知道数据中的偏差,以建立一个可靠而公*的机器学*模型

作者创造的形象
机器学*模型越来越多地用于决策或告知决策。例如,一个模型可能会影响批准贷款的决定,筛选求职申请的候选人简历等。这样的决定是至关重要的,我们需要确信我们的模型不会歧视种族、性别、年龄或任何这样的因素。许多机器学*模型往往包含无意的偏*,这可能导致不可靠和不公*的结果。建立和评估一个好的机器学*模型需要做的不仅仅是计算损失指标。在操作一个模型之前,分析你的训练数据,有时分析数据的来源以寻找偏差是很重要的。
在这篇文章中,我们将看看在训练数据中可能出现的不同类型的偏差。
1。报告偏差:
当一个数据集中只捕获了一部分结果或成果时,就会出现报告偏差(也称为选择性报告),这通常只涵盖整个现实世界数据的一小部分。人们倾向于少报所有可获得的信息。
报告偏差的类型-
- 引用偏差:当你的分析基于在其他研究的引用中发现的研究时出现。
- **语言偏*:**当你忽略了不是用你的母语发表的报告时就会出现。
- 重复发表偏倚:当一些研究因为在多个地方发表而权重较大时,会出现重复发表偏倚。
- **定位偏差:**发生在某些研究比其他研究更难定位的时候。
- 发表偏倚:当具有阳性发现的研究比具有阴性发现或无显著发现的研究更有可能被发表时出现。
- 结果报告偏倚:当选择性报告某些结果时出现。例如,只有当公司在季度报告中公布正收益时,你才需要报告。
- 时滞偏差:当一些研究需要数年才能发表时,就会出现时滞偏差。
2。自动化偏差
自动化偏*是人类倾向于支持自动化系统产生的结果或建议,而忽略非自动化系统产生的矛盾信息,即使它是正确的。
点击阅读自动化偏差的真实例子。
3.选择偏差
当选择数据的方式不能反映真实世界的数据分布时,就会产生选择偏差。这是因为在收集数据时没有实现适当的随机化。
选择偏差的类型
- **抽样偏倚:**在数据收集过程中没有正确实现随机化时出现。
- **收敛偏差:**当数据没有以有代表性的方式选择时发生。例如,当你只通过调查购买了你的产品的顾客而不是另外一半来收集数据时,你的数据集并不代表没有购买你的产品的人群。
- **参与偏差:**由于数据收集过程中的参与差距,当数据不具有代表性时发生。
所以让我们假设苹果推出了新的 iPhone,三星在同一天推出了新的 Galaxy Note。你向 1000 人发出调查问卷,收集他们的评论。现在,您决定选择对您的调查做出回应的前 100 名客户,而不是随机选择回应进行分析。这将导致抽样偏差,因为前 100 名客户更有可能对产品充满热情,并有可能提供良好的评价。
接下来,如果你决定通过选择退出三星客户,只调查苹果客户来收集数据,你将在你的数据集中引入收敛偏差。
最后,您将调查发送给 500 名苹果和 500 名三星客户。400 名苹果客户回复,但只有 100 名三星客户回复。现在,该数据集将不能充分代表三星客户,并将计入参与偏差。
4.过度概括偏差

作者创造的形象
当您假定您在数据集中看到的内容就是您在任何其他旨在评估相同信息的数据集中看到的内容时,就会发生过度概括,而不管数据集的大小如何。
5.群体归因偏差
人们往往会因为群体中几个人的行为而对整个群体产生刻板印象。这种将个体的真实情况推广到他们所属的整个群体的倾向被称为群体归因偏差。
群体归因偏差的类型-
- **群体内偏*:**当你偏爱你个人所属的群体或与你有共同兴趣的群体成员时,就会产生这种偏*。例如,为数据科学家职位创建职位描述的经理认为,合适的申请人必须拥有硕士学位,因为他/她也有硕士学位(与其工作经验无关)。
- **群体外偏*:**当你对一个群体中你个人不属于的个体成员产生刻板印象时,就会产生这种偏*。例如,一位经理(拥有硕士学位)为一个数据科学家职位创建了一个职位描述,他认为没有硕士学位的申请人不具备该职位所需的足够专业知识。
6.隐性偏*
当基于个人经验做出的假设不一定适用于更普遍的情况时,就会产生隐性偏*。人们倾向于基于偏*和成*行事,而不是有意为之。
例如,来自北美的计算机视觉工程师将红色标记为危险。然而,红色在中国文化中是一种流行的颜色,象征着幸运、快乐和幸福。
隐性偏*的类型
- **确认偏差或实验者偏差:**是以确认或支持自己先前信念或经验的方式搜索信息的倾向。例如,您训练了一个模型,使用一些特征根据跑车的速度对它们进行排序。你的模型结果显示法拉利比福特快。然而,几年前你记得看了一部福特击败法拉利的电影,你相信福特比法拉利更快,所以你继续训练和运行模型,直到模型给出你相信的结果。
感谢您的阅读。如果您有更多问题,请通过 LinkedIn 联系我们。
https://swapnilin.github.io/
云计算的类型
原文:https://towardsdatascience.com/types-of-cloud-computing-952ae75e07c9?source=collection_archive---------20-----------------------
了解云计算类型以及 IaaS、PaaS 和 SaaS 之间的区别

埃伯哈德·🖐·格罗斯加斯泰格在 Unsplash 上拍摄的照片
介绍
在我最近的一篇文章中,我讨论了云计算中的部署模型,即私有、公共和混合模型。现在,除了部署模型,了解三种不同类型的云计算并能够识别它们也同样重要。
过去,每个组织都必须购买、运营和维护自己的基础设施和资源。换句话说,企业必须管理网络、存储、服务器、虚拟化、操作系统、中间件、运行时、数据和应用。

您需要在内部管理的服务—来源:作者
然而有了云计算,组织现在可以按需访问由第三方公司提供和维护的资源和基础设施。这些资源以服务的形式提供,可分为三种不同类型:基础设施即服务(IaaS)、*台即服务(Paas)和软件即服务(SaaS)。
基础设施即服务(IaaS)
云计算的第一种类型是基础设施即服务(IaaS),它为云 IT 提供基本的构建模块,如与网络、存储空间、计算机硬件和虚拟化相关的组件。
IaaS 与传统上由 IT 部门维护的 IT 资源非常相似,在管理这些资源时,它提供了最高级别的灵活性和管理。
在下图中,蓝色的服务对应于组织需要在 IaaS 环境中管理的服务,而橙色的服务是由 IaaS 产品本身管理的服务。

您需要在 IaaS 中管理的蓝色服务—来源:作者
*台即服务(PaaS)
第二种类型的云计算是*台即服务(PaaS ),它在 IaaS 之上添加了一个额外的层,因为它消除了组织管理基础架构的需要,因此他们只需专注于开发、部署和管理将利用 it 基础架构和资源的应用程序。
在下图中,蓝色的服务对应于组织需要在 PaaS 环境中管理的服务,而橙色的服务是由 PaaS 产品本身管理的服务。

您需要在蓝色 PaaS 中管理的服务—来源:作者
软件即服务(SaaS)
最后一种云计算是软件即服务,本质上是为组织提供由第三方提供商执行和管理的完整产品。
在 SaaS,除了如何利用所提供的服务或产品来实现某个目标之外,组织实际上不必担心其他任何事情。
SaaS 最常*的例子之一是基于网络的电子邮件服务,在这里你只关心发送和接收电子邮件。IT 基础设施、资源管理、功能添加等。是软件提供商的责任。

在 SaaS 不需要管理任何服务——来源:作者
最后的想法
在今天的文章中,我们讨论了云计算的三种主要类型,即基础设施即服务、*台即服务和软件即服务。下图总结了我们今天文章中所涉及的内容。

来源:作者
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
https://betterprogramming.pub/5-things-to-consider-when-choosing-your-aws-region-484e800cb6f0 https://pub.towardsai.net/data-versioning-for-efficient-workflows-with-mlflow-and-lakefs-892df1f8e7d8
相关系数的类型
原文:https://towardsdatascience.com/types-of-correlation-coefficients-db5aa9ea8fd2?source=collection_archive---------11-----------------------
深入研究不同种类的相关系数

(来源)
在现有数据集中,能够区分适当类型的相关系数以决定是否在即将到来的分析和建模步骤中保留数据集中的变量是非常重要的。在数据中,特征之间可能存在递增(正)或递减(负)关系,如下所示。

相关系数的方向(归作者所有)
每一个相关系数都通过其使用领域和方面包含了非常独特的描述。在整篇文章中,将有四个主要的相关系数作为协方差、皮尔逊的斯皮尔曼相关系数和多元相关系数。
1.协方差相关系数
基本上,当特征之间存在正态分布关系时,可以应用协方差相关。它可以很容易地用于评估两个具体特征的方差之和。
通过使用该系数,可以推测特征的方向。然而,在需要测量变量的相关性时,应选择一个额外的度量,因为协方差系数不能响应这种关系。
简单地说,协方差相关的公式可以在下面找到。
Covariance(X, Y) = (sum (x - mean(X)) * (y - mean(Y)) ) * 1/(n-1)
2.皮尔逊相关系数
对于皮尔逊相关,还需要一对变量之间的线性关系。在文献中可以称之为“皮尔逊积矩相关” 1 。
皮尔逊相关公式可以从协方差相关数学公式中生成。
Pearson(X, Y) = Covariance(X, Y) / (stdDev(X) * stdDev(Y))
根据变量在 x 轴和 y 轴上的当前位置,可以在五个不同的范围内观察到皮尔逊相关系数参数,相关性的范围可能会发生变化。
当数据点遵循下降趋势时,可以接受为 **负相关。**另一方面,当观察到趋势向上时,可以将其标记为两个比较变量之间的 正相关 。
在下面的描述中, p 可以被接受为相关系数。您可以根据数据点的分布来检查相关性的排列。

皮尔逊相关系数的变化值(归作者所有)
3.斯皮尔曼相关系数
斯皮尔曼相关在学术环境中也可称为*“斯皮尔曼秩序相关”*2适用于变量集内缺乏正态分布性质的情况。

非高斯分布数据集(归作者所有)
Spearman 相关公式也可以通过在公式中添加变量的排名从协方差相关公式中导出。排序可以总结为指定变量标签的排列,以便能够计算观察对之间的对应程度,这可以用于评估它们彼此的影响率。
Spearman(X, Y) = Covariance(rank(X), rank(Y)) / (stdDev(rank(X)) * stdDev(rank(Y)))
4.多轴相关系数
多分位数相关或四分位数相关[ 3 ]可以表示为一种类型的系数,该系数用于提取对两个高斯分布连续观察值的关联的解释,这两个观察值是通过调查和个性测试收集的,这些调查和测试需要在之后生成评级量表。作为这种相关性的一个示例使用领域"李克特量表" [ 4 ],这是一种在社会科学领域广泛使用的标度系统*。*
在有连续数据的情况下,这个系数的公式可以由皮尔逊相关系数演化而来。
结论
当我们遇到需要了解数据集中相关强度的问题时,能够区分要应用的相关系数的正确类型是很重要的。
为了能够准确地确定相关性的类型,首先,可视化数据可能有助于了解它是否具有高斯分布。在它存在的情况下,我们可能会被引导到更深入地研究它的其他方面,如变量的类型和数量。
非常感谢您的阅读!
参考
- 皮尔逊积差相关
- 斯皮尔曼的秩次相关
- 四分相关
- 李克特量表
机器学*面试的类型以及如何胜出
原文:https://towardsdatascience.com/types-of-machine-learning-interviews-and-how-to-ace-them-51587a95f847?source=collection_archive---------2-----------------------

活动发起人在 Unsplash 上的照片
关于不同类别的机器学*面试以及如何准备面试的详细指南。
21 年春天,我开始申请工作。我找不到一篇简洁的文章来说明我将要接受采访的不同方面。在最初的采访系列中,有时我毫无头绪。我不得不艰难地认识到,无论你是一名多么优秀的研究员或 ML 工程师,在面试时都是不够的。你必须做好准备!在你开始准备之前,你需要知道你将被测试的不同领域。
在这篇文章中,我将根据我今年早些时候进行的 58 个小时的面试,讨论不同类型的机器学*面试。下面的饼状图总结了机器学*工程师/数据科学家面试的不同类别。

58 小时的机器学*访谈——图片由作者提供
我们将专注于筛选、编码、机器学*、案例研究和系统设计。
1.排查
这种面试相当随意,通常是一系列面试的第一步。这通常是由招聘人员或招聘经理进行的。这次面试的主要目的是让候选人了解公司、工作描述和职责。候选人还会在非正式场合被问及他/她的背景,以了解候选人的兴趣领域是否与工作相符。
**性质:**非技术性
**模式:**正常情况下打电话
**持续时间:**15–20 分钟
准备:你应该能在几分钟内说明你的经历。
2.编码
编码/编程是机器学*面试的重要组成部分,通常用于在将候选人推向机器学*相关面试之前筛选掉他们。在这样的面试中需要良好的编程技巧。编码面试通常持续 45-60 分钟,由两个问题组成。面试官解释问题,并期望应聘者在最佳的时间和空间复杂度内解决问题。
准备资源:
准备这样的采访需要很好地理解数据结构,时空复杂性,理解问题的能力,以及良好的时间管理技巧。以下是一些好的资源
https://aqeel-anwar.medium.com/how-to-prepare-for-coding-interviews-8bdd16b09659
3.机器学*
机器学*面试评估你的机器学*相关知识。根据工作要求,主题可以包括监督学*、非监督学*、强化学*、卷积神经网络、递归神经网络、生成对抗网络、自然语言处理等。
准备资源:
确保你仔细阅读了工作要求,并确定了所要求的 ML 的具体主题。如果没有具体提到,那么你可以把重点放在基础上。
**答:关于 ML 的深入课程:**如果你在学*期间没有正式参加过 ML 课程,我强烈建议你参加网上课程。在网上提供的各种课程中,我推荐吴恩达在 Coursera 上开设的机器学*课程。
https://www.coursera.org/learn/machine-learning
**b .复*文章:**如果你已经上过这样的课程,那么浏览几篇关于 ML 的复*文章将非常有助于你深入理解 ML 主题。这类文章的一个小列表(10)可以在下面找到。
https://AQ eel-an war . medium . com/list/understanding-machine-learning-a-list-of-easytouunderstand-tutorials-02 f 0f 9f 2f 0d 8
c .面试问题范例:了解 ML 面试中通常会问些什么有助于衡量你的准备工作。下面可以找到这样的示例问题。确保在 做好准备后,再看一遍 。
https://www.interviewbit.com/machine-learning-interview-questions/ https://www.springboard.com/blog/ai-machine-learning/machine-learning-interview-questions/
**d .备忘单:**在面试前一天晚上准备好备忘单总是好的。下面是 ML 备忘单的链接
https://medium.com/swlh/cheat-sheets-for-machine-learning-interview-topics-51c2bc2bab4f
4.案例研究:
这些通常是开放式问题,旨在分析候选人就整体项目管理和项目敏锐度进行有意义的 ML 讨论的能力。面试官提出了一个开放式问题,比如*“你会如何改进谷歌地图?”。*如果处理不当,这种开放式问题会导致非常混乱的答案。
准备资源:
一个好的答案模板对解决这类问题大有帮助。尝试使用以下模板组织您的答案
- 听这个问题
- 描述产品及其使命
- 提出澄清性问题
- 陈述你的假设
- 确定棘手问题
- 确定棘手问题的解决方案
- 通过表格比较解决方案
- 讨论 KPI
- 总结
以下是深入理解案例研究问题的良好资源
https://workera.ai/resources/machine-learning-case-study-interview
下面是这种开放式问题的一些例子
https://www.productmanagementexercises.com/119/how-would-you-improve-google-maps https://www.productmanagementexercises.com/591/how-can-you-improve-facebook-stories https://www.productmanagementexercises.com/753/how-would-you-design-a-bicycle-renting-app-for-tourists https://www.productmanagementexercises.com/5080/how-would-you-measure-the-success-of-uber-ride
5.系统设计:
这些面试评估候选人针对潜在问题设计端到端可扩展系统的能力。大多数工程师太专注于一个 bug,以至于他们忘记或者有时甚至没有意识到更大的图景。系统设计面试需要了解各种组件的知识,这些组件共同创建一个可扩展的问题解决方案。这些组件包括前端设计、负载*衡器、数据库分片、缓存、代理、SQL、API 等。对这些主题的良好理解有助于设计高效且可伸缩的端到端系统。
准备资源
- 组件和概念:
https://www.geeksforgeeks.org/5-common-system-design-concepts-for-interview-preparation/
2。示例问题和解决方案
https://www.educative.io/blog/uber-backend-system-design https://www.educative.io/blog/top-10-system-design-interview-questions https://igotanoffer.com/blogs/tech/system-design-interviews
总结:
如今的机器学*面试不仅仅是关于基本 ML 主题的问题。还包括开放式问题、案例研究、编码、系统设计等。了解不同类别的机器学*面试可以帮助候选人了解情况并做好相应的准备。在这篇文章中,我们详细介绍了五种最常*的 ML 面试类别,以及如何为它们做准备。
如果这篇文章对你有帮助,或者你想了解更多关于机器学*和数据科学的知识,请关注【Aqeel an war】,或者在LinkedIn或Twitter上联系我。你也可以订阅我的邮件列表。
数据科学访谈中产品感觉问题的类型
原文:https://towardsdatascience.com/types-of-product-sense-questions-in-data-science-interviews-ad0f80222643?source=collection_archive---------16-----------------------
不同类型的产品感觉问题,或者换句话说,公司询问的关于产品和功能的面试问题。

作者在 Canva 上创建的图片
在本文中,我们将讨论产品感问题的类型,或者换句话说,公司询问的关于产品和功能的面试问题。从某种程度上来说,这可以是一个关于当前或潜在的涉及或与产品相关的复杂问题,一直到你对产品了解多少的宽泛问题。
数据科学公司出于几个原因询问这些类型的产品感觉面试问题,例如测试你诊断和解决实际产品问题的能力,查看你对公司产品和业务的熟悉程度,评估你对问题的解决方案的实用性,评估你定义和理解指标的影响和权衡的能力,或者检查你是否能以有效和结构化的方式传达你的解决方案。
产品感问题主要有三类。
- 分析与指标相关的问题(最常*):分析与指标相关的问题提问,以提供产品指标或指标变化的原因。
- 衡量新产品/功能的影响:关于衡量影响的问题始于新产品、功能、最近或计划中的产品变更,并询问如何评估这些更新的性能。
- 设计产品:第三类问题是关于设计产品的,这些是最宽泛的问题,通常没有正确的答案。
分析与指标相关的问题

作者在 Canva 上创建的图像
第一类产品意识问题是关于分析与指标相关的问题。这些问题通常提到与公司产品相关的指标,以及它在某种程度上受到了影响。解决方案应该给出为什么会发生这种情况的思考过程。
让我们看一些例子。对于与指标相关的问题,最常*的场景是某些特性的使用已经改变了一定的百分比。就像在这个问题中,脸书看到喜欢数每年增长 10%,并问为什么会这样?但是这个问题也涉及到两个衡量标准。例如,在这种情况下,脸书问,如果 70%的脸书用户在 iOS 上使用 Instagram,但只有 35%的脸书用户在 Android 上使用 Instagram,你会如何调查这种差异?
在这些产品感问题中,指标的概念自然很重要。然而,在大多数情况下,问题中已经给出了度量标准的示例。在这里,指标是使用脸书和 Instagram 的某些*台的用户在只使用脸书的用户中所占的份额。没有必要拿出你自己的度量标准的例子,这使得这些问题变得简单了一些。最重要的是根据问题正确识别相关指标,并理解这些指标与产品或问题的相关性。在这个例子中,讨论中的指标与三个方面有关:移动操作系统、脸书应用和 Instagram 应用。他们都以某种方式相互交流,对脸书来说非常重要,因为该公司拥有两个社交*台,移动用户是他们的重要目标群体。
与指标相关的问题实际上是在问与痛点概念直接相关的问题。痛点是产品中令客户不愉快的部分,使他们自愿停止使用它。在脸书的例子中,我们可以尝试和推测可能导致统计数据差异的难点。也许 Android Instagram 应用程序比其 iOS 版本更慢、更不直观或更重?
另一个关键概念是确定产品和具体指标之间的权衡。看看脸书公司如何拥有两个社交媒体*台:脸书和 Instagram。在这种情况下,当他们对两个*台做出不同的决策时,这可能会反映在指标中。例如,该公司可能会遵循最佳营销策略,向不同于脸书的目标受众推广 Instagram,比如更年轻、对品牌更谨慎的人,这些人也更有可能使用苹果产品。这可能会导致大多数安卓用户只使用脸书。
衡量影响

作者在 Canva 上创建的图片
第二种类型的产品感问题是关于衡量一个公司的新产品或新特征的影响。这些问题可以是类似于这个来自 Twitter 的问题,他们问你如何量化一个 Twitter 用户的影响力?还有专门关于功能更新的问题,比如 Quora 问你会用什么标准来衡量搜索工具栏变化的影响?
与度量相关的问题类似,度量的概念也是衡量影响的关键。在这种情况下,就更加困难了,因为候选人需要给出可以用来衡量所讨论的影响的度量标准的例子。每当建议一个指标时,重要的是要定义它,解释该指标与目标的相关性,并可能解释为什么选择某个指标而不是另一个。
此外,在衡量影响时,定义 3 个指标是一个好策略:2 个衡量成功的指标和 1 个不会恶化的指标。在回答这个产品感采访问题时,我们可以假设,有了新的搜索工具栏,Quora 希望提高自己的点击率和回头客数量,但同时又不希望找到一条信息所花费的时间增加。
在提到、定义和解释为问题选择这些指标的原因后,需要解释他们将使用什么方法来度量它们。换句话说,如何得出这些指标?好的方法是尽可能具体地设计和解释实验。例如,测试一个新特性是否成功的一般实验被称为 A/B 测试。它类似于对照组和治疗组的概念,在测量用户界面更新的影响时特别有用。
但是当建议进行 A/B 测试这样的实验时,提及实验将涉及的用户群是至关重要的。在 Quora 的这个问题中,我们试图测量公众对新产品的反应,所以我们想在随机分组的小组中进行实验。但是如果我们将产品扩展到新的用户群,那么在特定的人群中进行实验是有意义的。
设计产品

作者在 Canva 上创建的图像
第三类也是最后一类产品感问题是关于产品设计的。这些是完全开放式的问题,没有正确的答案,而且通常是数据科学产品意识面试中最难的问题,因为这些测试的是候选人的思维过程,而不是答案本身。
我们来看几个这类问题的例子。 Lyft 可以问:“描述如何设计热图,告诉出租车司机去哪里最大化他们获得客户的概率。你怎么定义接下来哪个地区需求高,你想让谁去?”。另一个例子是来自微软的问题:“你会怎么总结一个 Twitter feed?”或者来自 Yelp :“如果你必须提出一个新的 Yelp 功能,它会是什么?”。
更重要的是,这些类型的问题有时可能会延伸到如何衡量设计产品的成功。例如,在要求提出一项新功能后,Yelp 可以接着问一个后续问题,如何确定该功能的推出是否成功。这将与衡量产品成功类型的问题联系在一起。
当面对一个与设计产品相关的问题时,答案中应该包含许多概念。首先,为一个功能的产品定义目标受众是很重要的。如果问题和访谈都没有指定目标受众,说明你认为谁是目标受众,并提到你正在基于这个目标受众开发产品。在 Yelp 的例子中,它可能是当前站点的人口统计数据,但是您可能也希望新的功能能够吸引新的目标受众。
另一个要考虑的重要概念是产品的关键性能指标,或 KPI。KPI 是业务问题中的关键指标,基于以下两种类型:产品或系统性能,例如应用程序初始化时间,以及用户体验,例如他们推荐产品的可能性。如果衡量 KPI 需要任何数据,那么解释这些数据是什么以及如何在产品中收集它们是很重要的。回到 Lyft 的这个示例问题,KPI 可能包括司机的收入、公司总收入或司机在两个客户之间等待的*均时间。但是在最后一个例子中,我们可能没有收集*均等待时间数据的系统,所以我们需要从乘车数据库中获得这个指标。
还有一个概念,许多候选人在回答关于设计产品的问题时忘记了,即提及边缘案例以及解决方案如何解释它们。假设你对 Lyft 提出的这个产品感问题的回答是,根据过去的数据,按小时、星期几、月份和年份来预测乘坐情况。您的解决方案的一个边缘情况是城市中有一个重大事件,如音乐节。由于音乐节并不总是在同一日期的同一地点举行,这可能会在几天内成倍增加 Lyft 的需求,然后立即消失,如果你只使用过去的数据,这很难预测。像这样的重大事件的真实世界的数据收集需要被合并,但是,再次强调,弄清楚数据管道的大致样子是至关重要的。
结论
总而言之,我们向您展示了三种类型的产品感问题。分析指标相关问题要求您解释特定指标的变化。在回答这些问题时,理解所提到的指标的相关性,找出相关的难点,并思考是否存在任何折衷。
关于衡量影响的问题要求提出量化特性和产品性能的方法。定义几个指标并记住,对于一些指标,目标是改善它们,而对于其他指标,我们不应该看到它们恶化。说出你用来衡量影响的具体实验,不要忘记指定关注哪些目标受众。
最后,就产品设计问题而言,通常没有正确的答案,重要的是思考过程。一个好的答案应该定义目标受众,提及相关的关键绩效指标,描述衡量影响所需的所有新数据管道,并涵盖最重要的边缘案例。
此外,请查看我们的产品数据科学面试问题终极指南,了解如何在进入面试前准备这些问题。
最初发表于T5【https://www.stratascratch.com】。
机器学*中的正则化类型
原文:https://towardsdatascience.com/types-of-regularization-in-machine-learning-eb5ce5f9bf50?source=collection_archive---------3-----------------------

作者图片
机器学*正则化初学者指南。
在本文中,我们将介绍什么是正则化,我们为什么需要它,以及机器学*模型中常用的正则化的不同类型。
为什么要正规化?
正则化经常被用来解决机器学*中的过拟合问题。过度拟合的常*原因有
- 当模型足够复杂时,它开始对训练数据中的噪声进行建模。
- 当训练数据相对较小,并且不足以表示作为样本的基础分布时,模型无法学*可概括的映射。

机器学*中的过度拟合—作者图片
正规化有助于我们克服过度拟合的问题。
什么是正规化?
*正则化由不同的技术和方法组成,用于通过减少泛化误差而不太影响训练误差来解决过拟合问题。*为训练数据点选择过于复杂的模型通常会导致过度拟合。另一方面,更简单的模型会导致数据拟合不足。因此,在模型中选择合适的复杂度是至关重要的。由于模型的复杂性不能从可用的训练数据中直接推断出来,因此通常不可能偶然发现用于训练的正确的模型复杂性。
这就是正则化发挥作用的地方,使得复杂的模型容易过度拟合。
正规化的类型
基于用于克服过拟合的方法,我们可以将正则化技术分为三类。基于方法在解决过度拟合问题上的有效性,每种正则化方法被标记为强、中、弱。
1.修改损失函数
在这些正则化技术中,优化模型的损失函数被修改以直接考虑学*参数或输出分布的范数。我们有以下基于损失函数的正则化技术。
a.L2 正规化(强):
考虑以下具有均方损失的线性回归问题。

在 L2 正则化中,我们修改损失以包括被优化的权重(β)的加权 L2 范数。这可以防止砝码变得过大,从而避免它们过重。

L2 正则化的修正损失-作者图片
常数λ(≥0)用于控制过拟合和欠拟合之间的折衷。当 lambda 较高(较低)时,模型倾向于欠拟合(过拟合)。
让我们考虑 2D 的情况(n=2 ),在这里我们可以在笛卡尔*面中可视化回归。下图在笛卡尔*面上绘制了损失函数的两个部分(MSE 损失和 L2 正则化)。L2 正则项被绘制成半径等于λ的圆。MSE 损失被绘制成等值线图,其中损失在椭圆上相等。求解上面显示的 L2 正则化损失的权重直观地意味着在绿色球内的 MSE 等值线(蓝色)上找到损失最小的点。增加 lambda 的值对应于绿球尺寸的增加。当λ增加超过某一点时,绿色球开始与实际的未调整的最小值点相交(在图中显示为“在没有调整的情况下的最佳β_ 0,β_ 1”)。这意味着增加λ超过这个值不会改变我们的解决方案。对于解决过度拟合问题的模型,选定的λ值必须在该λ值和 0 之间。

如上所示,求解 L2 正则化损失的权重直观地表示在位于 L2 球(绿色圆圈)内的 MSE 等值线(蓝色)上找到损失最小的点。
b.L1 正规化(强):
在 L1 正则化中,使用权重的 L1 范数(绝对值),而不是在损失函数中使用权重的 L2 范数。修改后的损失变成

使用 L1 正则化修改损失-图片由作者提供
就像 L2 正则化一样,L1 正则化在 MSE 等值线图上找到位于单位范数球内的损失最小的点。L1 范数的单位范数球是一个带边的菱形。这可以在下图中直观地看到。

求解上面显示的 L1 正则化损失的权重直观地意味着在位于 L1 球(贪婪菱形)内的 MSE 轮廓(蓝色)上找到具有最小损失的点。
使用 L1 正则化子优于 L2 正则化子的另一个优点是 L1 范数倾向于导致权重的稀疏。这意味着,通过这样的正则化,权重β可能具有为零的元素。使用 L2 正则化的权重可以变得非常小,但是它们实际上永远不会变为零。
增加λ值会增加钻石的尺寸,减少实际的 MSE 损失。这意味着权重开始越来越好地拟合数据点,这可能导致过度拟合。与 L2 正则项类似,当λ非常高时,回归模型的未调节最小值与 L1 调节的最小值相同。
c.熵正则化(强):
熵根据概率分布中的不确定性来量化概率分布。分布的不确定性越大,熵就越大。均匀分布的所有事件发生的概率相等,这意味着不确定性的数量最大,因此熵也最大。另一方面,看起来像脉冲的分布意味着,如果从这样的分布中抽取一个随机事件,我们知道它总是同一个。因此,这种看起来像脉冲的分布具有最小的熵。
当模型的输出是概率分布时,例如分类、策略梯度强化学*等,使用熵正则化。熵正则化器包括由λ缩放的输出分布的熵,而不是直接使用损失项中权重的范数。
考虑下面的分类问题。

损失函数通常是二元交叉熵或铰链损失。在熵正则化的情况下,损失函数被修改如下

熵正则化的修正损失—作者图片
因为我们希望输出概率有一定程度的不确定性,这意味着我们希望增加熵。由于我们正在减少损失,因此在损失函数中使用熵需要乘以-1。比例常数λ控制正则化。λ值越大,输出分布越均匀。

熵正则化的输出分布—作者图片
2.修改采样方法
这些方法有助于克服由于可用数据集大小有限而导致的过度拟合。这些正则化方法试图操纵可用的输入来创建实际输入分布的公*表示。以下是属于这一类别的两种正则化方法
a.数据扩充(弱):
数据扩充包括通过随机裁剪、扩张、旋转、添加少量噪声等创建的更多输入来扩充可用数据集的大小,如下图所示。这个想法是人为地创建更多的数据,希望增加的数据集能够更好地表示潜在的隐藏分布。由于我们只受到可用数据集的限制,这种方法通常不能很好地作为正则化方法。

图片来源:https://www.researchgate.net/publication/319413978
b.k 倍交叉验证(中等):
此方法用于创建多个经过训练的网络,然后选择泛化误差最小的网络。在从隐藏分布中采样的不可*数据集上,具有最小泛化误差的模型有望比其他模型表现得更好。
在 K-fold 交叉验证中,将可用的训练数据集分成 K 个不重叠的子集,并训练 K 个模型。对于每个模型,k 个子集之一用于验证,而其余(k-1)个子集用于训练(如下图所示)。该模型一旦被训练,就在拒绝验证子集上被评估,并且性能被记录。一旦训练了所有 K 个模型,并且记录了在拒绝确认子集上的性能,则选择具有最佳性能度量的模型作为最终模型。

五重交叉验证—作者图片
3.修改训练算法
正则化也可以通过以各种方式修改训练算法来实现。下面讨论两种最常用的方法。
a.辍学(强)
当训练模型是神经网络时,使用退出。神经网络由多个隐藏层组成,其中一层的输出用作下一层的输入。后续层通过可学*的参数修改输入(通常通过将其乘以一个矩阵并添加一个偏差,然后添加一个激活函数)。输入流经神经网络层,直到到达用于预测的最终输出层。
神经网络中的每一层都由不同的节点组成。前一层的节点连接到后一层的节点。在丢弃方法中,连续层的节点之间的连接基于丢弃率(丢弃的总连接的百分比)被随机丢弃,并且剩余的网络在当前迭代中被训练。在下一次迭代中,另一组随机连接被丢弃。

dropout 方法确保神经网络学*一组更健壮的特征,这些特征对于所选节点的随机子集同样表现良好。通过随机丢弃连接,网络能够学*从输入到输出的更好的一般化映射,从而减少过拟合。辍学比例需要仔细选择,对学*模型有重大影响。丢弃率的一个较好值在 0.25 到 0.4 之间。
b.注入噪声(弱)
与 dropout 类似,当正在学*的模型是神经网络时,通常使用这种方法。在这种方法中,我们篡改通过反向传播学*的权重,以使其对小变化更加鲁棒或不敏感。在训练期间,少量的随机噪声被添加到更新的权重中,这有助于模型学*更鲁棒的特征集。一组强大的功能可确保模型不会过度拟合训练数据。然而,这种方法作为正则化器并不十分有效。
摘要
正则化在机器学*中被用作通过减少所考虑的 ML 模型的方差来解决过度拟合的方法。正则化可以通过修改损失函数、采样方法或训练方法本身以多种方式实现。下面的备忘单总结了不同的正则化方法。

ML Cheatsheet 中的正则化—图像来源:www.cheatsheets.aqeel-anwar.com
奖金:
可以在下面的链接中找到这个主题和机器学*中许多其他重要主题的紧凑备忘单
https://medium.com/swlh/cheat-sheets-for-machine-learning-interview-topics-51c2bc2bab4f
如果这篇文章对你有帮助,欢迎鼓掌、分享和回复。如果你想了解更多关于机器学*和数据科学的知识,请关注我@Aqeel an war或者在LinkedIn上与我联系。
不*衡航空影像语义分割的 U-Net 方法
原文:https://towardsdatascience.com/u-net-for-semantic-segmentation-on-unbalanced-aerial-imagery-3474fa1d3e56?source=collection_archive---------3-----------------------
用于航空影像语义分割的 U-Net py torch 实现。
在这篇文章中,我们回顾了不*衡二进制掩码的语义分割问题。引入焦点损耗和 mIoU 作为损耗函数来调整网络参数。最后,我们训练 PyTorch 中实现的 U-Net 对航拍图像进行语义分割。训练代码和 PyTorch 实现可以通过 Github 获得。
数据集
这里使用的数据集是“航空影像语义分割”,包含阿联酋迪拜的 72 幅卫星影像,被分割成 6 类。这些类别包括水、土地、道路、建筑、植被和未标注。

图一。数据集的样本
U-Net 神经网络
U-Net 是一种卷积神经网络,最初由弗赖堡大学计算机科学系用于生物医学图像分割。它基于完全卷积神经网络,并具有修改和扩展的架构,以使用更少的训练图像并产生更精确的分割。
主要概念是使用一个收缩的网络,然后是一个扩展的网络,在扩展的网络中用上采样操作代替池操作。这些图层提高了输出的分辨率。此外,一个扩展的卷积网络可以学*根据编码信息组合一个精确的输出。

图二。Unet 结构(图片由 U-Net 提供)
该网络由一条收缩路径(左侧)和一条扩张路径(右侧)组成,这使其具有 u 形架构。收缩路径是一个典型的卷积网络,由重复的卷积组成,每个卷积后面都有一个校正线性单元(ReLU)和一个最大汇集操作。在收缩期间,空间信息减少,而特征信息增加。扩展路径通过一系列上卷积和连接将特征和空间信息与来自收缩路径的高分辨率特征相结合。
损失函数
本文的目的是回顾损失函数对分割输出结果的影响。在训练过程中使用了三种不同的损失函数。但首先,让我们快速回顾一下。
让我们假设 p 是图像中每个像素的输出值。在这种情况下,我们可以将研究的损失函数定义如下:
交叉熵损失
交叉熵(或对数损失)计算输出的对数值,因为我们讨论的是图像,所以它是输出张量中每个像素的对数值。
阿尔法项是不同类别的权重超参数,是*衡不*衡类别损失的一种方式。加权交叉熵损失的最终等式如等式 1 所示。

Eq 1。加权交叉熵损失
焦点损失
焦损为不*衡数据集问题提供了更好的解决方案。它增加了一个额外的项,以减少正确预测的影响,并专注于不正确的示例。伽马是一个超参数,它规定了这种减少的力度有多大。
这种损失影响网络在不*衡数据集上的训练,并且可以改善分割结果。

Eq 2。焦点损失
借据损失(Jaccard 指数)
最后,我们得到 IoU 损失,这是不*衡分段的另一个选项,它比其他选项具有更少的超参数。但首先,让我们熟悉一下等式 3 中的这个度量。

Eq 3。并集上的交集
在等式中,命名者是预测的和基本事实掩码之间的重叠,分母是它们的联合。IoU 的计算方法是将这两个数字相除,数值越接近 1 表示预测越准确。

图三。IoU(图片由作者提供)
优化的目的是最大化 IoU,其值介于 0 和 1 之间,因此损失函数定义为:

Eq 3。欠条损失
培训和结果
我在提到的数据集上用所有三个损失函数训练了 U-Net。需要注意的是,只有 65 张图片用于训练,7 张图片用于验证,所以我们不能期望有很好的结果。但是这个数据数量对于我们的目的来说已经足够了。

图 4。使用交叉熵损失的分割结果(图片由作者提供)
如你所*,交叉熵在分割小区域方面有问题,并且在这些损失函数中性能最差。

图五。使用聚焦损失的分割结果(图片由作者提供)
焦损可以达到更好的效果,尤其是在小区域,但是仍然需要通过试错进行一些超参数调谐。

图六。使用 IoU loss 的分割结果(图片由作者提供)
最后,我们可以看到,无论是小区域还是大区域,IoU loss 在分割方面也非常出色。
这里您可以看到一些其他输出:

图六。左边是交叉熵,中间是焦损,右边是 IoU 损(图片由作者提供)
结论
本文综述了损失函数对不*衡图像分割的影响。我们训练 U-Net 神经网络使用 3 种不同的损失函数,交叉熵损失、焦点损失和 IoU 损失来执行语义分割航空图像。
结果表明交叉熵损失不能处理不*衡的数据集。即使是针对不同的阶层增加权重也不是很有效。另一方面,焦点损失和 IoU 损失都代表不*衡图像分割的更好结果。
也可以参考 GitHub 页面访问项目和 PyTorch 实现。
美国投票站
原文:https://towardsdatascience.com/u-s-polling-places-389ca5ed7960?source=collection_archive---------66-----------------------
R 中的探索性数据分析

由 Unsplash 上的 Element5 数码拍摄
在民主国家,投票站不仅仅是一个不知情的公民在临时搭建的投票站填写一张纸上的泡泡的地方。它是民主承诺的象征,是公民和政府之间的连接器。如果受到保护和尊重,这就是一个民主国家的力量所在。
这篇文章通过分析由公共诚信中心编辑的美国投票站数据集来分析美国民主的象征。由于 CPI 所做的大量工作,2012 年、2014 年、2016 年和 2018 年选举的 30 多个州的投票站位置和地址信息已经公布。我将使用各种探索和建模技术来分析数据,以回答以下问题:
- 哪些州提供最多的投票站?
- 随着时间的推移,投票点的数量趋势如何?
- 投票点的数量和每个州的人口数量成正比吗?
- 倾向于共和党的州比倾向于民主党的州有更少的投票点吗?
我们先来看一下数据。

在数据集中,我们可以看到相当多的信息!每行对应于给定选举中的一个投票点。因此,2012 年在阿拉斯加费尔班克斯的 FNSB 市政办公室有一个投票站。对于每个投票点,我们可以看到一些感兴趣的东西,包括站点的位置、在该州选举中投票的人数(不是在该站点投票的人数)、该州的人口,等等。
利用这些数据,让我们试着理解每个州投票点数量的趋势。我们先来看看投票站的数量和每个州的人口之间的关系。

随着人口的增加,投票站的数量也在增加。无论是总统选举(2012 + 2016)还是众议院/参议院选举(2014 + 2018),这一趋势在每次选举中都是如此。
让我们更好地看看哪些州的投票点比总人口(人均比率)多。

在上面,我用一个柱状图展示了前 10 个州的人均投票网站,并在地图上显示了同样的情况。虽然各州的人均投票站数量没有太大的地理差异(CPI 只收集了 32 个州的数据,这肯定会有所伤害),但我确实注意到,东北和南方的数据并没有发生倾斜,这是我最初的假设。同样明显的是,各州在总统选举年委托的公共投票站比非选举年多。
选举相关性
在下一节中,我将利用选举数据来研究一个州的投票点数量与哪个政党赢得该州选举之间的关系。我使用的选举数据来自 FEC.gov 的 T2。在这些数据中,我查看了 2012 年至 2018 年期间每次大选的众议院、参议院和总统竞选的党派细分以及总票数,并使用这些数据与投票站数据进行匹配。
我将通过确定一个新的变量来做到这一点,该变量由一个政党在给定州赢得的总选举数来定义。例如,如果在新泽西州 2018 年,民主党赢得了众议院和参议院的竞选,民主党控制了新泽西州的选举年。如果在威斯康星州,一名共和党人(特朗普)赢得了 2016 年的总统选举,但民主党人总体上赢得了众议院的竞选,那么这是一个“分裂票”州。
让我们从了解这个新变量开始。在过去的 4 次选举中,哪个政党赢得了每个州的选举?

现在我们更好地理解了这个变量是如何工作的,让我们将它与该州可供选民使用的投票站数量联系起来。现在我们有了数据集,我们将根据总投票数构建 4 个投票点散点图(每年一个)。

让我们再来看看之前的前 10 项,看看哪一个政党赢得了某个州是否有关联。

有趣的是,在我们的数据集涵盖的最著名的选举中——2016 年的选举——最终成为完全共和党的州人均拥有最多的投票站。2016 年人均投票站最多的州——威斯康星州——值得注意的是,它支持特朗普,这让希拉里竞选团队非常惊讶。
老实说,这一发现让我有点惊讶,尤其是考虑到共和党各州竭力让个人投票变得更加困难的言论。显然,这并不能说明全部情况。仅仅因为有更多投票点并不意味着可以进入,或者有很多人有资格投票(因为选民登记过程中的困难)。不过,这是一个有助于理解更全面情况的指标。
让我们看看我们“最差”的 10 个州,看看这一趋势是否会逆转。

看看垫底的投票点会让争论变得更加混乱。总的来说,这是一个更健康的州组合,完全由民主党人和共和党人组成(同时也有相当一部分州的结果有好有坏)。
让我们仔细看看我们的 House 比赛。具体来说,让我们把之前讨论的三个度量结合起来:
1。投票站数量
2。投票数
3。总人口

就趋势而言,我看不出共和党和民主党赢得众议院的州有什么不同。让我们用回归来正式测试一下。特别是,让我们拟合一个众议院选举的回归模型,使用政党、投票人数和人口作为预测因素。根据上面的图表,我们期望看到投票人数、人口和投票点数量之间的高度相关关系。真正的问题在于党。
以下是运行基本回归的结果:

polling _ sites ~ votes _ per _ million+pop _ per _ million+party _ winner+year
查看模型摘要,对于给定州中投票站点数量的趋势,有一些有趣的事情需要指出。
- 人口| 需要注意的最重要的一点是只有一个因素可以充分预测投票站的数量:人口。该模型表明,一个州每增加百万人口,就会有 577 个额外的投票站。
- 总投票数| 现在,如果你回头看看上面的气泡图,你可能(和我一样)会认为总投票数也是投票站点数量的一个强有力的预测因素。当一个增加时,另一个也增加。那么,为什么 p 值(在模型输出中表示为 PR( > |t|) ) .6867 —比通常用于确定统计显著性的. 05 阈值高得多?嗯,总票数与一个州的人口高度相关也是事实。人口多的州自然会有更多的人出来投票。因此,使用这两个特征作为预测是多余的。
- Party | 我们一直在等待的问题。在某个州赢得众议院选举的政党确定了该州的投票站数量,这是真的吗?事实证明,并不尽然。政党赢家(表示为 party_winnerRepublican ,代表一个州成为共和党的基本情况)的 p 值是. 3694,远高于通常的阈值. 05 。因此,我们不能拒绝我们最初的零假设,即政党获胜者预测投票站的数量。
未来分析
这篇文章实际上只是对选举的一个方面的一个小小的观察:投票站。这篇文章还应该放在哪里?嗯,如果我能得到更小的县级选举数据,甚至更细的选举数据,我就可以在一个更强大的数据集上运行许多以前的分析。不幸的是,这些数据非常昂贵。
否则,此分析的一个好方法是将投票地点的可用性与邮政编码或县一级的人口统计数据进行比较。这里的假设是,美国白人有更好(即更多)的机会进入投票站。
我还应该带着这个去哪里?请在评论中留下你的想法。
原载于 2021 年 1 月 26 日https://data cracy . netlify . app。
优步数据科学家面试经历
原文:https://towardsdatascience.com/uber-data-scientist-interview-experience-78305114540c?source=collection_archive---------3-----------------------

Firmbee.com在 Unsplash 上拍照
从招聘人员的电子邮件到现场面试,面试过程的详细时间表
在本文中,我将讲述我面试优步旧金山办公室数据科学家职位的经历。我将从我的教育/研究背景开始,然后进入面试过程和我的经历。在整篇文章中,我会尽量在需要的地方用类似的问题替换原来的问题,保持问题的主旨和性质不变,让读者清楚地了解所提问题的类型。
我的背景
在我进入细节之前,我想浏览一下我的个人资料。我是佐治亚理工学院电气和计算机工程的博士生,从事节能机器学*系统的设计。在我采访优步的时候,我已经发表了 8 篇文章,获得了 2 项专利,并且一直积极参与开源工具。更多细节可以在我的 LinkedIn 个人资料中找到。

优步数据科学家采访时间表和流程—图片由作者提供
应用
在过去的几个月里,我一直在积极申请机器学*的工作。我的主要申请来源是 LinkedIn。我通过 LinkedIn 申请了优步数据科学家的职位。工作职责包括为现实生活中与优步莱德和优步 Eats 相关的挑战性问题实现 ML 算法。
招聘人员的电子邮件
两周内我收到了招聘人员的邮件。招聘人员询问我是否有空,并提供了一份详细的文件,提到了面试时间表和有用的资源。这份文件对我很好地理解面试过程很有帮助。
电话屏幕 1:
我有两个相隔十天的电话筛选。每次放映都是 45 分钟的视频采访,并遵循相同的格式。在前 5 分钟,面试官介绍了他/她自己。接下来是我的介绍和我的简历。第一次电话面试由两部分组成
- **案例研究:**案例研究由一个类似于 UberEats 的相关开放式问题组成。采访者和我讨论了问题的各个方面,如理解目标、收集数据、进行探索性数据分析、扩展系统、问题的重要 KPI、底层机器学*解决方案、部署解决方案以及将其集成到现有系统中。这个案例研究的目的是评估我处理大规模机器学*问题的方法。
- **编码:**第二部分由通过 CodeSignal 的中等编码问题组成。我被要求选择我喜欢的语言。面试官解释问题的时候很明确。我能够在给定的时间内最佳地解决这个问题。
最后面试官问我有没有问题。我们就他在优步的工作职责进行了很好的讨论。
电话屏幕 2:
我在 3 天后听到了我的第一次电话面试反馈,我的下一次电话面试被安排在一周内。与第一次面试相似,这次面试有两个部分
- **机器学*基础知识:**面试官问了一些与机器学*相关的基础到中级问题,如反向传播、图形 ML、集成方法、消失梯度、精确度与召回率、偏差-方差权衡等。在下面有用的链接中可以找到对这些主题的很好的理解
https://medium.com/swlh/cheat-sheets-for-machine-learning-interview-topics-51c2bc2bab4f
- **ML 案例研究:**与第一次访谈类似,讨论了与 UberEats 相关的开放式案例研究。与第一次面试相反,这次的案例研究要复杂得多,而且更加面向机器学*和统计。我被要求为一个相关的基于产品的问题设计一个基于 ML 的解决方案。面试官每一步都问了相关的细节问题。讨论从简单的逻辑回归模型开始,到稍微复杂的 SVM 和决策树,最后到甚至复杂的图 ML 模型。我们还讨论了可用数据集的重要特征以及如何使用它们来解决问题。
同样,面试官非常友好,并确保面试环境对我来说足够舒适。
现场
现场面试包括 6 轮,总时间为 5-6 小时,中间有两次 15 分钟的休息时间。他们给了我足够的时间来解释我的答案,让我感到受欢迎。他们首先介绍了自己并描述了他们的工作职责,让我轻松地进入了这个过程。没有一个面试官分心,完全专注于我要说的内容。根据所提问题的性质,我将这六轮问题归为以下几类。
1.设计问题
这次采访包括一个开放式的案例研究,与设计一个网上杂货店有关。我带着面试官走过了数据收集、探索性数据分析、特征选择、特征转换、机器学*模型选择、训练模型、选择正确的 KPI 来分析绩效的过程。这一轮更加关注大局。面试官感兴趣的是我对问题的高层次理解,而不是算法的技术细节。我们还讨论了一些与业务相关的 KPI 来衡量问题的解决方案。
2.编码:
编码面试的重点是我对统计学的理解。面试官让我做一个涉及假设检验的问题。由于我*惯了与现实世界问题相关的 LeetCode 类型的问题,这个编码问题给了我一段艰难的时间。我花了一些时间才明白面试官想要我实现什么。当我陷入困境时,面试官给了我一些提示。这个编码问题有多个后续编码问题。可以在下面找到对该部分的很好理解
3.研究
现场的这一部分完全由我以前的研究经验组成。面试官让我解释我的博士研究,问了一些后续问题。这部分更多的是讨论。面试官仔细查看了我的简历,并就我提到的项目问了一些相关问题。他让我接一个研究项目,详细说明目标、挫折和最终结果。
4.行为:
面试官问了我一些问题,关于我读博士的经历,我实*的经历,还有一个机器学*工程师。这些问题围绕着我的领导能力、时间管理、按时完成任务、与难相处的同事相处以及解决冲突。对这些问题的理解可以在下面找到
5.机器学*/统计:
这部分是与优步的一个产品相关的开放式讨论。这个问题是作为一个案例研究提出的,采访者对我处理这个问题的 ML 方法最感兴趣。我们从一个非常基本的 ML 解决方案开始,讨论了这种非常简单的方法在现实生活中会失败,然后转向更复杂的解决方案。在整个采访中,我们讨论了各种 ML 概念,以及如何改变一些事情来解决与 ML 管道相关的问题。还讨论了诸如图 ML 模型、嵌入、损失函数等主题。
一些相关的主题可以在下面的链接中找到。
6.案例研究:
这类似于设计问题和机器学*/统计,但是考虑中的优步产品是不同的。面试官感兴趣的是我对设计给定问题的解决方案的高度理解,以及当扩展到更大的数据集时,我将如何设计解决方案。案例研究有点类似于 FAANG 公司的设计问题。
总结:
总的来说,我在优步的采访经历非常好。面试官专注于我要说的内容,给了我充足的时间来解释我的答案。面试主要集中在设计问题/案例研究,机器学*概念,编码问题,以及我的研究背景。我发现以下资源在准备面试时很有用。
优步工程博客:
- https://eng.uber.com/uber-eats-recommending-marketplace/
- https://eng.uber.com/uber-eats-query-understanding/
- 【https://eng.uber.com/uber-eats-graph-learning/
- https://eng . Uber . com/women-in-data-science-move-the-world-with-data/
- https://www.uber.com/us/en/marketplace/
- https://eng . Uber . com/making-a-real-world-impact-with-data-science/
- https://eng . Uber . com/米开朗基罗-机器学*-*台/
案例研究/设计问题的重点:
- **可扩展解决方案:**优步拥有超过 9000 万活跃用户,是一家非常重视可扩展解决方案的公司。每当回答案例研究或设计问题时,确保你的解决方案
- 以顾客为导向的方法:优步直接与人打交道。顾客是普通大众。因此,您的解决方案应该更加重视让客户的生活更轻松。应该在考虑用户体验的情况下修改设计问题。
- **业务关键绩效指标:**最后,优步的最终目标是创收。你的解决方案应该关注用户保持、用户流失、新用户、乘客数量、优步 eats 的订单数量、优步 eats 新增的餐厅等。扪心自问,这些指标最终会如何影响产生的收入?
如果你有一个与优步的面试,我希望这篇文章能帮助你。
如果这篇文章对你有帮助,或者你想了解更多关于机器学*和数据科学的知识,请关注【Aqeel an war】,或者在LinkedIn或Twitter上联系我。
优步·H3 用 Python 进行数据分析
原文:https://towardsdatascience.com/uber-h3-for-data-analysis-with-python-1e54acdcc908?source=collection_archive---------2-----------------------
编辑 2023-3 月:自从写这篇文章的时候(H3 v3),H3 v4 已经发布了和这篇文章中提到的那些有不同函数名的。你可以安装 v3 来跟随这篇文章,或者安装 v4 来查看的变更日志和的相关文章,并按照它们在这篇文章中出现的那样进行修改。
如果你曾经玩过文明 VI 或者卡坦岛的定居者,你可能会注意到棋盘地图是规则的六边形。这是一种著名的游戏设计技术,称为 Hex Map ,用于棋盘游戏如六角象棋和视频游戏如帝国锻造。这是游戏的自然特征,因为这些地图为游戏带来了很多优势,尤其是在移动和*铺方面。
如果我们用一层六边形重新建模我们自己的地图,这种设计在现实世界中被证明是有用的,会怎么样?也许我们可以找到一些可以用这种模型解决的实际业务问题。优步·H3 出场了。
为什么是 H3 和六角形?🌏
目前,有多种方法可以分析与地图相关的数据。最基本的方法之一是绘制一个坐标列表,看看密度和集群出现在哪里。

阿联酋迪拜的消防站位置
分析个别点有一定的弊端。对于某一区域内的点,没有明确的分类形式,我们通常希望进行的分析可能是区域式的或区域性的。
如果我们有一个网格系统,其中点可以包含在某个围栏内,并且我们分析网格本身的行为来表示下面所有点的行为,这将会有所帮助。这意味着每个网格代表其下方点的数据。另一个问题是,当直接使用点时,虽然人类可以看到地图并注意到数据聚集的位置,但对于计算机系统来说,计算成本可能会更高。计算机需要计算相邻点的距离,以便将它们组合在一起,从而获得与人类相同的视觉洞察力。
然而,对于地理定位数据,坐标点是尽可能细的,所以现在还不要忽略它们。我们只需要找到一个网格框架,我们或计算机可以围绕它查看地理空间数据,并从中获得洞察力。
更局部地使用网格系统的一种常*形式是在城市中定义区域,通过在一个街区、城市、地区或国家上画出一个形状。行政和政治边界虽然有助于将地理空间分析划分为现实区域,但在许多方面仍可能存在问题。在一个城市中,有些区域可能比其他区域大,并且两个或更多区域之间可能会有重叠。此外,从数学/绝对的角度来看,以这种形式定义区域是非常随意的。可以根据自然特征、人口、经济等来定义区域或地区。并且随着时间的推移会发生变化。

GADM 学术数据库的阿联酋地理包第三层中定义的阿联酋迪拜区域
使用统一网格系统的一个绝对方法是用重复*铺的方法覆盖地球。假设我们想要有规律地、完全地*铺我们的*面,我们需要选择一个形状,这个形状作为一个积木来促进完全*铺。该形状需要闭合并均匀重复。我们的候选形状是三角形(3 条边)、正方形(4 条边)和六边形(6 条边)。

https://plus.maths.org/content/trouble-five
这里没有正确的答案,因此选择其中之一取决于您的用例。在优步,我们最受欢迎的用例之一是确定乘车和送货的距离。
使用六边形作为细胞形状对 H3 至关重要。 六边形在六边形的中心点和它的邻居**’**之间只有一个距离,相比之下,正方形有两个距离,三角形有三个距离。该属性极大地简化了梯度上的分析和*滑。
除了距离,选择一个六边形作为基础形状通常是个好主意,因为六边形是最好的!;)
关于 H3 ⚫️
H3 是由优步用 C 语言开发的开源框架。在其核心,H3 是一个地理空间分析工具,提供了一个六边形,层次空间索引,以获得从大型地理空间数据集的洞察力。H3 的积木是不同大小的正六边形。这些多边形分布在地球地图从极点到极点的整个投影上。这意味着地球上的任何位置都可以归属于一个 H3 六边形,精确到 0.0000009 公里的区域。
想象它是地球上的一个层,其中层的每个单元是一个六边形,每个六边形都有一个唯一的 ID,可以非常快速地执行地理空间计算。每个 H3 六边形可以被认为是它自己的对象,每个对象都可以在给定 ID 的情况下在很短的时间内被访问。
H3 决议📷
H3 的一个核心优势是它用不同大小的六边形覆盖了整个世界。这意味着图层的分辨率可以根据正在解决的问题进行调整,例如上下缩放整个格网。如下表所述,H3 总共包含 16 个分辨率,每个分辨率都有一定数量的六边形,这些六边形作为一层跨越整个地球,从最高层的 122 个六边形到最底层的大约 500 万亿个六边形。每一层由更细粒度的六边形组成,每一层的每个六边形都有自己唯一的 ID。

H3 决议
H3 通过十六进制格式(16 位,因此 16 种分辨率)定义其索引,因此通过查看单元的 ID 可以立即确定单元分辨率。不同大小的六边形的分层方式赋予了 H3“层次”的力量。每个低分辨率六边形包含一组较高分辨率的子六边形。分辨率的每个六边形都可以有共享同一组父六边形的同级六边形。这些层本质上定义了一个六边形树,最后一层(分辨率)包含 500 万亿个兄弟。
值得看看这款笔记本。分辨率可以相应调整,六边形可以在整个地球上看到。
H3 函数🔩
你可以在这里找到一些在 C 语言中直接使用 H3 函数的例子。我们将使用与 Python 编程语言绑定的 H3 库,因为用 Python 分析数据相对更容易。
pip install h3
假设你有一个坐标点,或者一个坐标列表。您可以使用以下函数获取每个点的 H3 指数:
h3.**geo_to_h3(** *lat*=25.32,
*lng*=55.46,
*resolution*=7 **)**
如果以字符串表示的索引有效,则获取 H3 索引的分辨率
h3_result = lambda id_str: h3.**h3_get_resolution(**id_str**)** if h3.**h3_is_valid(**id_str**)** else Noneh3_result('8843a13687fffff')

上面片段中的 H3 指数用开普勒可视化了。GL
让我们尝试一个完整的函数,在给定 H3 指数的情况下,返回一组 H3 属性
H3 的另一个有用的功能是它能够快速返回索引的 k 近邻。这意味着对于 k =1,返回六边形的第一级邻居,对于 k = 2,返回第二级邻居(或邻居的邻居),以此类推。
h3_id = "*8843a13687fffff*"
h3.**k_ring(**h3_id,1**)**
h3.**k_ring(**h3_id,2**)**
h3.**k_ring(**h3_id,10**)**

六角形 ID: 8843a13687fffff 中用于 1 和 2 的 k 形圈
可选 Sprinkles:用地图数据填充六边形📍
现在我们有了一些绝对的方法来定义地球上的网格,这将适合我们开始为六边形分配真实世界的细节。这是因为尽管给了我们一个 H3 指数和它的形心坐标,我们并没有太多关于这个六边形所代表的物理位置的信息。
扩展 H3 功能的一种方法是将其与包含地面信息的地图 API 结合在一起。常*的选择有谷歌地图 API 、 Mapbox API 和提名。这些服务允许我们为每个六边形分配更多有用的地理信息。
一个常*的功能是反向地理编码,这是一种通过查找将给定坐标转换为物理文本地址的技术。让我们使用Google Maps Client for Python找到 H3 指数质心的反向地理编码结果。

反向地理编码六边形-工具提示包含地理信息
聚合填料🌐
如果 H3 包含跨越整个地球的不同分辨率的六边形,那么如果您想选择这些六边形中的一小部分来代表一个国家、城市或社区,该怎么办?
多边形填充函数用 H3 六边形填充多边形。地理围栏是在地图上展开的多边形。城市中的区域或乡村形状可以被建模为地理围栏。地理围栏通常用 Geo-JSON 文件或形状优美的多边形来表示。形状良好的多边形的 WKT 示例(众所周知的文本表示):
**POLYGON** ((*55.13977696520102 25.09805053895709*, 55.14002932545401 25.09743871100549, 55.1407574981263 25.0972787358399, 55.14123332293791 25.09773058763684, 55.14098097073993 25.09834242241949, 55.14025278567518 25.09850239857415, *55.13977696520102 25.09805053895709*))
顾名思义,WKT 是多边形顶点的文本表示。请注意多边形中的第一组坐标和最后一组坐标是如何相同的(如代码块中突出显示的)。这是一个封闭的多边形。
多边形的每个“点”对象可以是(lat,lng)或(lng,lat)的形式。后者通常是面的 Geo-JSON 表示,因为 Geo-JSON 规范要求经度首先出现在点对象中。
shapely 面对象需要从 WKT 中提取,WKT 是 shapely 面的一个属性,如下所示:
loads 函数从其 WKT 表示中解析出并构建一个形状优美的多边形。
我已经采取了 H3 六边形自己的 WKT 在这里,但你可以得到几乎任何多边形的 WKT。另一点需要注意的是,该形状没有对地图的引用。这是因为我们需要一个底图来绘制我们的多边形,作为一个图层。
让我们用一整个城市的地理围栏,比如说阿联酋的迪拜,来看看这个多边形物体是什么样子的。我将使用 GADM 数据库提取阿联酋国家的地理包。通过这种方式,我们可以将整个城市/地区视为一个几何图形。我们将处理地理包并输出迪拜 3 区的多边形,如下所示:
它是一个“多多边形”,因为它包含一个多边形列表,如迪拜海岸外的世界岛屿所示,其中每个岛屿都是自己的多边形。
迪拜的 3 区为多边形,无底图
下面是一个 Geo-JSON 文件的示例,这是表示 geofences 的另一种有用形式。再次注意列表的第一个和最后一个坐标是相同的。
{
"type": **"FeatureCollection"**,
"features": [
{
"type": **"Feature"**,
**"properties"**: {},
"geometry": {
"type": **"Polygon"**,
"coordinates": [
[
[
* 55.07652282714844,
25.11731056144692*
],
[
55.15205383300781,
25.055745117015316
],
[
55.223464965820305,
25.112958466940725
],
[
55.15068054199219,
25.18070920440447
],
[
*55.07652282714844,
25.11731056144692*
]
]
]
}
}
]
}
Geo-JSON 文件是一个标准的 JSON 文件,具有特殊的键名,有助于某些框架理解所传递数据的性质。Geo-JSON 规范定义了一个名为要素集合的要素列表,在这种情况下,该要素属于多边形类型。属性字典可以用自定义数据填充,并且可以用于为不同的特征 id 提供属性。举例来说,如果您想要存储一个城市的每个多边形的人口,那么属性就是您可以保存该信息的地方。它是面的扩展,允许每个面/要素携带特定于自身的相关信息以供以后分析。
您可以使用 geojson.io 或任何 GIS 工具/软件通过绘制自己的形状来创建自定义地理围栏。

定义区域允许我们构建带状地图(带有区域颜色的地图)。Plotly 图形库使用 Geo-JSON 文件支持本地 choropleth。开普勒通过仅使用数据中 H3 六边形的索引来支持 H3 可视化。
现在我们知道我们需要什么来对付房间里的大象。我们如何使地理围栏与 H3 相协调?我们用特定分辨率的六边形多边形填充整个边界(在我们的例子中分辨率为 10)。H3 有能力多边形填充形状良好的多边形和 Geo-JSON 对象。
使用 H3 多边形填充函数用六边形填充地理边界。
多填充画廊💠
这个数据帧的输出是从优步的开普勒望远镜上看到的。不同分辨率的 GL 如下。

10 号决议六角形特写

迪拜多边形-填充分辨率为 10 的六边形(100,000 个六边形横跨整个城市)

迪拜多边形-填充分辨率为 8 的六边形(2500 个六边形横跨整个城市)
看起来像一个复古的 16 位 T21 城市。
分析📈
现在我们已经有了遍布整个城市的六边形,并且每个六边形的 ID 都存储在一个表/数据框中,
- 我们可以在每个六边形上执行任何与 H3 相关的功能(找到它的父对象以进行更全面的分析,存储它的地理围栏,找到它的相邻六边形,等等)
- 我们可以跟踪按各自的六边形分组的坐标级别数据。在这种情况下,六边形成为桶,我们可以使用它对每个桶/十六进制的一组坐标点执行分组分析
充分利用 H3 的一些非穷尽方法是:
- 将其用作“开/关”指示器,以突出显示特定区域的活动。请记住,H3 六边形可以有不同的分辨率,因此您可以根据自己的需要进行细化,或者将其向上聚合以降低分辨率。
- 通过分析一段时间内六边形的演变来查看时间序列数据。每个六边形代表位于其边界内的多个坐标的邻域。
- 具有特定活动水*的聚类区域。

剩下的就看你自己了;)
感谢阅读!
再来几个链接:
优步开源:为优步的超级本地市场设计次级城市地理信息系统
真理的《永不重复的无限模式》
参考文献:
优步工程博客:H3:优步六边形层次空间索引
H3 文件
UCL 数据科学协会:Numpy 简介
原文:https://towardsdatascience.com/ucl-data-science-society-introduction-to-numpy-7d962d63f47d?source=collection_archive---------25-----------------------
工作坊 5:什么是 Numpy,Numpy 数组,数学运算符,随机数

照片由 Unsplash 上的 Dhru J 拍摄
今年,作为 UCL 数据科学学会的科学负责人,该学会将在整个学年举办一系列 20 场研讨会,涵盖的主题包括数据科学家工具包 Python 和机器学*方法简介。每一篇文章的目标都是创建一系列的小博客,这些小博客将概述要点,并为任何希望跟进的人提供完整研讨会的链接。所有这些都可以在我们的 GitHub 资源库中找到,并将在全年更新新的研讨会和挑战。
第五个研讨会是对 Numpy python 包的介绍,我们将向您介绍 Numpy,涵盖 Numpy 数组的创建,介绍 Numpy 中的数学运算,并与包的随机数功能进行交互。虽然这里将分享一些亮点,但完整的研讨会(包括自测题)可以在这里找到。
如果您错过了我们之前的任何研讨会,您可以点击以下链接:
什么是 Numpy?
Numpy 是我们在研讨会系列中引入的第一个完整的 Python 包,之前我们只是使用了 Python 的基本功能。从这个意义上说,包通常包含许多有用的内置函数,这意味着我们不必重新发明轮子来得到想要的结果。特别是,Numpy 专注于许多数学功能,并支持其他 Python 包中的许多方法和函数。
根据numpy.org 的 NumPy 是:
…是一个开源的 Python 库,几乎用于科学和工程的每个领域。这是在 Python 中处理数字数据的通用标准,也是科学 Python 和 PyData 生态系统的核心。
这意味着它是一个基础库,虽然您可能不会以其原始形式与之交互,但您可能会以某种方式通过基于此功能的其他包遇到它。
Numpy 数组
Numpy 最重要的特性可能是数组,它是 Numpy 的基础数据结构。这些 Numpy 数组在嵌入它们的一些功能和它们的结构方面类似于列表,但是你可以用它们做更多列表做不到的事情,比如允许你在大数据集上执行各种操作。
有许多方法可以生成数组,例如:
np.array
它将一个列表转换成一个 numpy 数组:
# Generates an array [1 2 3]
x = np.array([1,2,3])
print(x)# Generates an array [[1 2 3] [4 5 6]]
x = np.array([[1,2,3],[4,5,6]])
print(x)#out:
[1 2 3]
[[1 2 3]
[4 5 6]]
np.linspace
它有三个参数:起点、终点和点数。第一个数字0告诉内核从0开始,第二个数字告诉它在10结束,而第三个数字告诉它数组中应该有多少个值。该数组将由一组均匀分布的值创建,从0开始,到10结束:
# Generates an array [0 2.5 5 7.5 10]
x = np.linspace(0,10,5)
print(x)#out:
[ 0\. 2.5 5\. 7.5 10\. ]
np.arange
它同样需要三个参数:起点、终点(不包含!),以及每个值之间的间距。在我们的例子中,我们指定0的开始点和11的结束点(不包括在最终数组中),其中1是值之间的间距:
# Generates an array [1 2 3 4 5 6 7 8 9 10]
x = np.arange(0,11,1)
print(x)#out:
[ 0 1 2 3 4 5 6 7 8 9 10]
np.zeros 和NP . one
就产生特定大小的数组而言,这些可能是最有用的选择,尽管如果你想使用除了 1 或 0 之外的东西,你可能必须填充它们。在第一个实例中,函数中的数字简单地指定了数组中需要多少个 1 或 0,同时我们还可以使用指示维度大小的元组来创建更复杂的多维数组:
# Generats an array [0, 0.] in float64
x = np.zeros(2)
print("1st: ", x)# Generates an array [1 1 1] in integer
x = np.ones(3, int)
print("\nSecond: ", x)# Generates an 3x3 array of zeros
x = np.zeros((3,3))
print("\nThird: \n", x)# Generates an 3x3 array of ones in integer
x = np.zeros((3,3), int)
print("\nFourth: \n", x)#out:1st: [0\. 0.]
Second: [1 1 1]
Third:
[[0\. 0\. 0.]
[0\. 0\. 0.]
[0\. 0\. 0.]]
Fourth:
[[0 0 0]
[0 0 0]
[0 0 0]]
一旦定义了这些,我们就可以像使用索引和切片来访问列表一样访问信息。但是,当我们在一个阵列中有多个维度时,这可能会变得更加复杂:
# Creates an array [[0 1 2] [3 4 5]]
x = np.array([[0,1,2],[3,4,5]])
print(x)# First row
print("First row:", x[0])# Second row
print("Second row:", x[1])# Second column
print("Second column:", x[:,1])# First row, third column
print("First row, third column:", x[0,2])#out:
[[0 1 2]
[3 4 5]]
First row: [0 1 2]
Second row: [3 4 5]
Second column: [1 4]
First row, third column: 2
数学运算
数组优于列表的一个好处是数学运算可以应用于数组。虽然除非迭代列表中的值,否则不能对它们执行数学运算,但是可以简单地对 Numpy 数组中的每一项执行数学运算。例如:
# Defining a list
x = [0, 1, 2, 3, 4, 5]# Multiply list by 2
print("List multiplied by 2:", x*2)# List added to a list
print("List added to a list:", x + x)#out:
List multiplied by 2: [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5]
List added to a list: [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5]
在这里我们可以看到,任何应用于一个整体列表的数学运算,都将列表视为一个整体的值结构。但是,当我们将此应用于阵列时:
# Turns list into array
x = np.array(x)# Multiply array by 2
print("Array multiplied by 2:", x*2)# Adding 2 to array
print("Adding 2 to array:", x + 2)# Adding array to array
print("Adding array to array:", x + x)# Multiplying array to array (a.k.a squaring it)
print("Squaring an array:", x * x)#out:
Array multiplied by 2: [ 0 2 4 6 8 10]
Adding 2 to array: [2 3 4 5 6 7]
Adding array to array: [ 0 2 4 6 8 10]
Squaring an array: [ 0 1 4 9 16 25]
我们可以看到该操作已经应用于数组本身的每个值。因此,这加强了 numpy 库对大量数据进行数学运算的有用性。
Numpy 还为这些阵列提供了广泛的功能,包括:
# Creating an array
x = np.array([3,2,1,0])# Finds the sum of all values in the array
print("Sum of the values:", np.sum(x))# Finds the average of all values in the array
print("Average of the values:", np.mean(x))# Sorts the values in the array into ascending order
print("Sorted values:", np.sort(x))# Returns the maximimun value in the array
print("Maximum value:", np.max(x))# Returns the minimum value in the array
print("Minimum value:", np.min(x))# Returns the standard deviation
print("Standard deviation:", np.std(x))# Returns the variance
print("Variance:", np.var(x))# Returns the size of the array
print("Size:", np.size(x))# Returns the shape of the array
# which is a tuple of ints giving the lengths of the corresponding array dimensions
print("Shape:", np.shape(x))# Multi-dimensional array
y = np.array([[1, 2, 3], [4, 5, 6,], [4, 5, 6,]])
print("Shape of y:", np.shape(y))#out:Sum of the values: 6
Average of the values: 1.5
Sorted values: [0 1 2 3]
Maximum value: 3
Minimum value: 0
Standard deviation: 1.118033988749895
Variance: 1.25
Size: 4
Shape: (4,)
Shape of y: (3, 3)
内置于此的其他功能包括沿数组移动值、将数组添加到现有数组、将多个数组相加以及重塑数组的能力。
然而,numpy 的另一个有用的内置功能是内置的数学函数和常数,帮助它作为 Python 中数学运算的基础:
# Pi - NOT A FUNCTION
print("Pi:", np.pi)# Square root function
print("Square root:", np.sqrt(9))# Trigonometric functions (default input is in radians)
print("Sine:", np.sin(np.pi/2))
print("Cosine:", np.cos(0))# Natural Constant e
print("e:", np.e)# Exponential (input is the power)
print("Exponential:", np.exp(0))# Natural logarithm ln
print("ln:", np.log(1))# A complex number 1+2i
print("Complex Number:", np.complex(1, 2))#out:
Pi: 3.141592653589793
Square root: 3.0
Sine: 1.0
Cosine: 1.0
e: 2.718281828459045
Exponential: 1.0
ln: 0.0
Complex Number: (1+2j)
随机数
除了数组和数学运算之外,Numpy 还可以用于生成随机数,这些随机数可以用于许多功能,例如模拟、随机值选择或生成一组虚拟数据。有两种主要方法可以做到这一点:
随机的
它从区间[0.0,1.0]中返回一个随机浮点数。如果没有传递参数,那么它将只是一个数字,但是您也可以传递维度来创建一个数组:
# Generates a random number from 0 to 1, exclusively
print(np.random.random())# Generate 6 random number from 0 to 1, exclusively
print(np.random.random(6))# Generates an array of random numbers for a 3x3 array
print(np.random.random((3,3)))#out:0.5641615164281893
[0.01950781 0.72695885 0.47460399 0.26587963 0.9011898 0.871929 ]
[[0.30523122 0.60809893 0.53312007]
[0.07440937 0.81311535 0.49964168]
[0.75633448 0.88113332 0.70084173]]
相反,该函数能够返回特定范围内的随机整数,其中第一个值是可能的最小值,而第二个输入比可能的最大值高一。但是,和前面一样,我们也可以使用第三个输入来创建数组,第三个输入是要用随机整数填充的数组的维度(作为一个元组):
# Generates a random number from 1 to 6
print(np.random.randint(1, 7))# Generates a 3x3 array of random integers from 1 to 6
print(np.random.randint(1, 7, (3,3)))# 9x4 array of random integers from 10 to 25
print(np.random.randint(10, 26, (9,4)))#out:
6
[[5 6 2]
[5 6 5]
[6 3 2]]
[[17 10 22 19]
[18 10 19 24]
[13 20 10 19]
[21 23 22 15]
[16 25 25 21]
[19 20 25 12]
[24 19 24 23]
[14 16 11 20]
[23 17 11 20]]
当然,Numpy 的功能远不止这里描述的这三个用例,这包括能够处理复数、创建不同形式的数组(使用对数标度的数组或从现有数组生成 2D 数组)以及更多的数学运算(如向量的绝对值、点积的标量和矩阵乘法)。
虽然这些大部分都包含在研讨会笔记本中,Numpy 当然比这延伸得更远。但是,如果您想在我们这里介绍的任何功能上挑战自己,请随意查看我们的问题工作表!
完整的研讨会笔记,以及进一步的示例和挑战,可以在 这里找到 。如果您想了解我们协会的更多信息,请随时关注我们的社交网站:
https://www.facebook.com/ucldata[脸书](https://www.facebook.com/ucldata)
insta gram:https://www.instagram.com/ucl.datasci/
领英:https://www.linkedin.com/company/ucldata/
如果你想了解 UCL 数据科学协会和其他优秀作者的最新信息,请使用我下面的推荐代码注册 medium。
**https://philip-wilkinson.medium.com/membership ** ** [## scikit-learn 决策树分类器简介
towardsdatascience.com](/introduction-to-decision-tree-classifiers-from-scikit-learn-32cd5d23f4d)**
UCL 数据科学学会:面向对象编程介绍
原文:https://towardsdatascience.com/ucl-data-science-society-object-oriented-programming-d69cb7a7b0be?source=collection_archive---------32-----------------------
工作坊 4:什么是 OOP,在 Python 中定义类、添加属性、添加方法、类继承

克里斯托夫·高尔在 Unsplash 上拍摄的照片
今年,作为 UCL 数据科学学会的科学负责人,该学会将在整个学年举办一系列 20 场研讨会,涵盖的主题包括数据科学家工具包 Python 和机器学*方法简介。对于我所展示和交付的每一个,我的目标是创建一系列的小博客,这些小博客将概述主要观点,并为任何希望跟进的人提供完整研讨会的链接。所有这些都可以在我们的 GitHub 上找到,并将在全年更新新的研讨会和挑战。
第四个工作坊是对面向对象编程的介绍,我们将向你介绍如何定义一个类,添加属性,添加方法和类继承。虽然这里将分享一些亮点,但完整的研讨会,包括问题表,可以在这里找到。
如果您错过了之前的研讨会,可以在这里找到:
- Python 基础知识
- Python 序列
- Python 逻辑
面向对象编程
首先,什么是面向对象编程?首先,这是一种组织代码的方式,可以将特征和行为数据捆绑到一个结构中。这种结构允许你使用类作为蓝图来创建多个对象,遵循不要重复的主要编码原则之一。这允许您在整个代码中创建对象,允许您在整个工作流的不同点访问相同的信息或功能。
这与数据科学社区中经常使用的过程化编程形成对比,在过程化编程中,代码遵循一系列步骤,以便使用函数和代码块来完成任务。这可以在之前的研讨会中看到,我们使用 jupyter 笔记本中的代码块一点一点地完成序列。
然而,面向对象编程的好处是,你可以用一种简单易行的方式存储数据和你想在多个不同的条目中执行的相关动作,同时允许你创建一个可以反复使用的蓝图。当您知道每个实例都有某些特征,并且您可能希望反复对这些数据执行相同的功能时,这将非常有用。这方面的一个例子可以是存储关于雇员的数据,由此他们每个人都有工资、水*经验或级别,并且共同的行动包括工作周年纪念或晋升。
定义一个类别
我们可以通过定义一个类来实现这个处理雇员数据的蓝图。这是一种结构和/或蓝图,允许我们在未来创建特定的对象,以相同的属性和功能反复使用。
这是使用关键字 class 完成的,后面是包含方法的缩进块。这方面的一个例子是:
class Employee:
pass
这里我们简单地定义了一个 Employee 类,它将 pass 作为唯一的当前属性,这意味着我们没有当前功能。我们可以通过创建该对象的实例来检查我们是否创建了一个类,并检查它是否是该类的一部分:
juliet = Employee()juliet.__class__.__name__#out:
'Employee'
很好,现在我们知道我们有员工了!
添加属性
创建一个类并使其真正有用的下一步是开始添加属性。这是 don 使用的__init__()方法,该方法在创建类的实例(对象)时被调用。
出于我们的目的,因为我们有一个雇员,我们想要分配一个工资、一个级别和工作年限:
#define the employee class
class Employee:
#add the constructor method with associated attributes
def __init__(self, wage, grade, years_worked):
self.wage = wage
self.grade = grade
self.exp = years_worked
#create an instance of that employee
juliet = Employee(30_000, 1, 1)
我们现在有了我们想要的属性。在这一点上,注意到 self 参数作为第一个参数被传递是很重要的,即使它没有在代码中被显式地传递。在类中定义属性或方法就是这种情况,以确保我们将属性分配给特定的类。
那么如何访问这些信息呢?既然我们已经创建了该实例,我们可能希望在以后访问这些信息。我们可以使用点符号来实现这一点,这意味着我们可以将.和属性名放在实例之后来访问它。在这种情况下,对于朱丽叶,我们可以这样做:
print("Juliet's wage is:", juliet.wage)
print("Juliet's grade is:", juliet.grade)
print("Juliet has worked for", juliet.exp, "years")#out:
Juliet's wage is: 30000
Juliet's grade is: 1
Juliet has worked for 1 years
好吧,我们可以访问这个,太好了,但是改变这些信息呢?嗯,就像 Python 中的普通变量一样,我们也可以使用=结合上面的点符号来更新信息。例如,如果我们想给朱莉加薪,那么我们可以这样做:
#print out the current information
print(f"Juliet's current wage is: {juliet.wage}")
print(f"Juliet's current grade is: {juliet.grade}")
print("\n")juliet.wage += 5000
juliet.grade += 1#print out the new information
print(f"Juliet's new wage is: {juliet.wage}")
print(f"Juliet's new grade is: {juliet.grade}")#out:
Juliet's current wage is: 30000
Juliet's current grade is: 1Juliet's new wage is: 35000
Juliet's new grade is: 2
然而,这样做可能会很痛苦!如果我们有成千上万的这些记录呢?有没有更简单的方法?是的有!
添加方法
我们可以通过向我们的类中添加方法来简化这一点,以便能够执行我们知道是例行的或将在类中的数据存储上经常使用的操作。在我们的案例中,这可以是给我们的员工升职,从而提高他们的工资和级别,或者我们的员工有一个工作纪念日,从而增加他们为公司工作的年限。
在这里,我们可以通过创建一个方法来关注第一个示例,该方法给我们的员工一个标准工资增加 10%并且级别增加 1 的晋升(在我看来这是一个很好的晋升!).我们可以这样实现:
#create the employee class
class Employee:
#add the init constructor in the same way we have done already
def __init__(self, wage = 20_000, grade=1, years_worked=0):
self.wage = wage
self.grade = grade
self.exp = years_worked
#add a promotion method
#with assumed values
def promotion(self, wage_increase = 10, grade_increase = 1):
self.wage += wage_increase/100 * self.wage
self.grade += grade_increase
然后,我们可以使用如下晋升方法给 Juliet 加薪:
juliet = Employee(30_000, 1, 1)#Checking the original objects attributes
print("Juliet's wage is:", juliet.wage)
print("Juliet's grade is:", juliet.grade)
print("Juliet has worked for", juliet.exp, "years\n")#Giving William and promotion
print("Juliet has got a promotion\n")
juliet.promotion()#Checking to see that the grade and wage have changed
print("Juliet's wage is now:", juliet.wage)
print("Juliet's grade is now:", juliet.grade)#out:
Juliet's wage is: 30000
Juliet's grade is: 1
Juliet has worked for 1 years
Juliet has got a promotion
Juliet's wage is now: 33000.0
Juliet's grade is now: 2
我们可以看到,这将使生活变得更加简单,特别是如果我们向多人提供不止一次的推广,还允许我们灵活地改变推广的规模。
但是,如果我们有不同类型、不同特点的员工,那会怎么样呢?
类继承
在代码中使用类的好处是,类可以从其他类继承属性和方法。这在编程的许多方面都很有用,并且允许您在不想重新编写的现有功能的基础上进行构建。
从本质上讲,这允许您定义一个新的类来获得原始类的所有功能,但是您可以添加额外的功能。实现这一点的方法是通过以下符号:
class MyChild(MyParent):
pass
其中 MyParent 是其功能由 MyChild 类扩展/继承的类。出于我们的目的,我们可以创建一个数据科学家员工,他最初与原来的员工没有什么不同:
#ctreate the Data Scientist class inheriting from the Employee class
class DataScientist(Employee):
#add no new functionality for now
pass#create an instance of jessicae
jessica = DataScientist(70_000, 6, 10)#print Jessica's wage
print(f"Jessica's current wage is: {jessica.wage}")#give her a promotion
jessica.promotion()print(f"Jessica's new wage is: {jessica.wage}")#out:
Jessica's current wage is: 70000
Jessica's new wage is: 77000.0
在这里,我们可以看到我们拥有原始父类的所有功能,而不必编写太多代码。
然而,我们当然对扩展这个原始父类的功能感兴趣,以允许数据科学家有不同的行为。在我们的案例中,我们希望数据科学家具有他们所知道的语言属性,并且有能力学*一门新的语言,这可能会导致工资增加,而无需必要的晋升。我们可以这样做:
#create the Data Scientist class inheriting from the employee class
class DataScientist(Employee):
#child's initialisation
def __init__(self, wage = 20_000,
grade=1, years_worked=0,
p_languages = []):
#use the parents initialisation
Employee.__init__(self, wage,
grade, years_worked)
#new characteristics to add
self.languages = p_languages
#add language learning functionality
def learn_lang(self, new_lang, promotion = False, wage_increase = 10,
grade_increase = 0):
#add the new language
self.languages.append(new_lang)
#if promotion is true
if promotion == True:
#add promotion
self.promotion(wage_increase,
grade_increase)
这可以实现为:
#create new DataScientist
jessica = DataScientist(80000, 7, 15, ["Python", "R", "SQL"])#Print her current languages and wage
print(f"Jessica's current languages are {jessica.languages}")
print(f"Jessica's current wage is £{jessica.wage}")
print(f"Jessica's current grade is {jessica.grade}")#She learns a language
#so we give her a promotion
jessica.learn_lang("JavaScript", promotion = True)#check what languages she now knows
print(f"Jessica's new languages are {jessica.languages}")
print(f"Jessica's new wage is £{jessica.wage}")
print(f"Jessica's new grade is {jessica.grade}")#out:
Jessica's current languages are ['Python', 'R', 'SQL']
Jessica's current wage is £80000
Jessica's current grade is 7 Jessica's new languages are ['Python', 'R', 'SQL', 'JavaScript'] Jessica's new wage is £88000.0
Jessica's new grade is 7
这样,我们就有了面向对象编程的基础!当然,还有很多东西需要学*,包括装饰器、类方法和其他功能,但是我们希望这已经给了你一个很好的基础,如果你有兴趣的话,可以继续学*!
完整的研讨会笔记,以及进一步的示例和挑战,可以在 这里找到 。如果您想了解我们协会的更多信息,请随时关注我们的社交网站:
https://www.facebook.com/ucldata[脸书](https://www.facebook.com/ucldata)
insta gram:https://www.instagram.com/ucl.datasci/
领英:【https://www.linkedin.com/company/ucldata/
如果你想了解 UCL 数据科学协会和其他优秀作者的最新信息,请使用我下面的推荐代码注册 medium。
https://philip-wilkinson.medium.com/membership [## scikit-learn 决策树分类器简介
towardsdatascience.com](/introduction-to-decision-tree-classifiers-from-scikit-learn-32cd5d23f4d)
UCL 数据科学学会:熊猫
原文:https://towardsdatascience.com/ucl-data-science-society-pandas-8ad28c2b22e5?source=collection_archive---------25-----------------------
工作坊 6:什么是 Pandas,Pandas 系列,Pandas 数据框架,访问数据和 Pandas 操作

迈克尔·佩恩在 Unsplash 上的照片
今年,作为 UCL 数据科学学会的科学负责人,该学会将在整个学年举办一系列 20 场研讨会,涵盖的主题包括数据科学家工具包 Python 和机器学*方法简介。每一篇文章的目标都是创建一系列的小博客,这些小博客将概述要点,并为任何希望跟进的人提供完整研讨会的链接。所有这些都可以在我们的 GitHub 资源库中找到,并将在全年更新新的研讨会和挑战。
本系列的第六个研讨会是对 pandas python 包的介绍,我们将向您介绍 pandas、Pandas 系列、Pandas 数据帧、访问数据和 Pandas 操作。虽然这里将分享一些亮点,但完整的研讨会(包括自测题)可以在这里找到。
如果您错过了我们之前的任何研讨会,您可以在以下链接中找到最后三场:
熊猫是什么?
Pandas 是一个开源 Python 包,广泛用于数据科学/分析和机器学*任务,建立在我们上周介绍的 Numpy 包之上。它是数据科学工作流中最受欢迎的数据争论包之一,并与此过程中使用的许多其他库集成良好。它很有用,因为它使任务像:
- 数据清理
- 数据填充
- 数据标准化
- 合并和连接
- 数据可视化
- 数据检查
比其他方式简单多了。该功能有助于实现以下目标:
…在 Python 中进行实际、真实世界数据分析的基本高级构建模块。此外,它还有一个更广泛的目标,那就是成为任何语言中最强大、最灵活的开源数据分析/操作工具。
如文档中所述。
熊猫系列
熊猫系列是构成熊猫数据框架的基础结构。虽然它们在结构上类似于 Numpy 数组,但主要区别在于我们可以为始终链接的 pandas 系列指定一个非数字索引,从而允许我们基于该值访问信息的位置。然而,在大多数其他方面,如应用数值运算时,序列的行为很像数组或列表。
要生成一个序列,我们需要使用pd.series(x)符号,其中x是一个要转换成序列的列表或数组。为此,我们可以使用index参数来设置index = y,其中y是我们希望用于各个系列值的索引列表。这意味着,如果我们愿意,我们可以同时使用数字和字符串符号(即最小值、中值、最大值,而不是 1、2、3)。这方面的一个例子是:
# Generating Pandas series
series = pd.Series([10,20,30,40])
print(series)#out:
0 10
1 20
2 30
3 40
dtype: int64
或者:
# Generating Pandas series
series = pd.Series([10,20,30,40], index=["a","b","c","d"])
print(series)#out:
a 10
b 20
c 30
d 40
dtype: int64
熊猫数据框
这些序列可以组合起来构成 Pandas 数据框架,这是与 Pandas 相关的主要数据结构。本质上,它是一个以变量形式存储的数据表,类似于将一个列表字典或一个数组中的多个值存储为变量。数据帧中的每一列都由一个熊猫序列表示,这意味着如果我们愿意,我们可以单独提取每一列,而索引将保持不变。
我们可以用两种方法创建数据帧,要么将已经存储在 Python 中的数据转换成数据帧,要么读入外部文件。在第一种情况下,我们可以从各种结构中创建数据帧,例如从列表或列表列表或压缩列表中创建数据帧。然而,在我们的例子中,我们将使用一个列表字典,如下所示,使用“pd.DataFrame()”函数:
#create a dictionary of lists
data_dict = {"Countries": ["England", "Scotland", "Wales", "Northern Ireland"],
"Capitals": ["London", "Edinburgh", "Cardiff", "Dublin"],
"Population (millions)": [55.98, 5.454, 3.136, 1.786]}#convert this to a dataframe
data_df = pd.DataFrame(data_dict)#display the dataframe
data_df

或者我们可以使用pd.read_csv从一个现有的数据源中提取数据,比如一个 **csv(逗号分隔变量)**文件,如下所示:
# Defines df as a data frame without adding an additional index column
df = pd.read_csv("StarColours.csv")# Displays the data frame df
df

其中 csv 是一种与 pandas 结合使用的常*数据结构,顾名思义,每列由一个列分隔。当然,也可以使用其他数据结构来读入,例如文本文件或 excel 文件,并且可以指定各种其他参数来允许读入这些数据,例如分隔符(如何分隔列)、编码(字符序列)和压缩(如何压缩文件)。这可以与参数结合使用,例如use_cols指定要读入的列,或者nrows指定要读入多少行。
数据帧切片
就像列表、数组或字典一样,我们也可以从数据结构中查看特定的值或值的范围。在 DataFrame 的情况下,我们可以像处理列表或数组一样查看切片,但是我们可以使用列名或索引来访问这些信息。
在 star colours 数据集的情况下,我们可以像选择字典值一样选择特定的列。这里的关键字是字符串形式的列名,如下所示:
# Returns the colour column
df["Color"]#alterntaively you can use dot notation
#df.Color
#but only if there are no spaces in the title#out:
0 Blue
1 Blue
2 Blue
3 Blue to White
4 White to Yellow
5 Orange to Red
6 Red
Name: Color, dtype: object
我们可以进一步从列中选择一个或多个特定的项,就像在列表字典中一样,首先访问列,然后访问索引,如下所示:
# Selects seventh item in colour column
df["Color"][6]#out:
'Red'
或者对于一个范围:
# Selects 4th to 6th items in colour column
df["Color"][3:6]#out:
3 Blue to White
4 White to Yellow
5 Orange to Red
Name: Color, dtype: object
我们可以通过传递列名列表来进一步指定几个列,如下所示:
# Returns the specified columns
df[["Color", "Main Characteristics", "Examples"]][3:6]

或者,我们可以使用df.loc从满足特定条件的数据帧中获取信息。在这里,我们可以开始使用条件语句来访问使用符号df.loc[df["columname"] > x]的信息,对于标有columname的列,该符号将返回值大于x的所有行。然后,它可以与其他条件结合使用,以访问或更改信息。例如:
# Returns all rows with values greater than
#one for the average mass column
df.loc[df["Average Mass (The Sun = 1)"] > 1]

数据帧操作
使用 DataFrame 数据结构的好处是可以对数据执行各种操作,包括对列和跨列执行数学运算的能力,创建新列以添加回数据集中,以及许多内置功能。
例如,就像我们处理 Numpy 数组一样,我们可以对列中的每个元素执行数学运算。例如,我们可以将质量*均值和质量半径列相加:
# Adding the average mass and radius columns
(df["Average Mass (The Sun = 1)"]
+ df["Average Radius (The Sun = 1)"])#out:
0 75.0
1 25.0
2 5.7
3 3.0
4 2.2
5 1.7
6 0.7
dtype: float64
或者,我们可以根据*均质量和*均半径计算恒星的*均密度,并将其赋回数据集中的一个新列:
# Defines a new average density column accordingly
df["Average Density"] = ((df["Average Mass (The Sun = 1)"]
*3)
/(4*
np.pi*
(df["Average Radius (The Sun = 1)"]
**3)))# Displays the data frame
df

除此之外,我们还有多个内置函数,可以用来查看数据或更改数据。例如,我们可以使用df.head()来检查数据集的前五行,或者我们可以使用df.tail()来访问数据集的底部五行:
# Returns first five rows from the data frame
df.head()

我们还可以将一列中的所有唯一项(即没有重复项)作为一个数组来访问:
# Returns unique items from the colours column
df["Color"].unique()#out:
array(['Blue', 'Blue to White', 'White to Yellow', 'Orange to Red', 'Red'],
dtype=object)
或者,我们可以返回所有列的大量统计参数的数值,如下所示:
# Returns unique items from the colours row
df.describe()

我们还可以使用内置的 Numpy 函数来单独访问其他统计值,例如使用df.mean()来访问列的*均值、df.median()来访问列的中值、df.min()来访问列的最小值或df.max()来查找列的最大值。例如:
# Returns the mean of each numerical column
df.mean()Average Mass (The Sun = 1) 12.157143
Average Radius (The Sun = 1) 4.028571
Average Density 0.261248
dtype: float64
当然,该结构内置了更多的功能,包括设置索引、将列转换为数组、列表和字典、根据条件删除一行或一列、合并数据帧、处理 NaN 值以及最终将数据推送到 csv 文件。
虽然此处未涉及此功能,但可在车间文件中找到此处。或者,如果你认为你知道所有关于熊猫的数据,那么为什么不试试问题单?
恒星数据集来自:https://www . enchanted learning . com/subjects/astronomy/stars/start types . shtml
完整的研讨会笔记本,以及更多示例和挑战,可在 这里 找到。如果您想了解我们协会的更多信息,请随时关注我们的社交网站:
https://www.facebook.com/ucldata
Instagram:https://www.instagram.com/ucl.datasci/
领英:https://www.linkedin.com/company/ucldata/
如果你想了解 UCL 数据科学协会和其他优秀作者的最新信息,请使用我下面的推荐代码注册 medium。
https://philip-wilkinson.medium.com/membership
UCL 数据科学协会:Python 基础
原文:https://towardsdatascience.com/ucl-data-science-society-python-fundamentals-3fb30ec020fa?source=collection_archive---------12-----------------------
研讨会 1: Jupyter 笔记本,变量,数据类型和操作

由 Pakata Goh 在 Unsplash 上拍摄的照片
今年,作为 UCL 数据科学协会的科学负责人,该协会将在整个学年举办一系列 20 场研讨会,主题包括数据科学家工具包 Python 简介和机器学*方法。对于我介绍和交付的每一个,我的目标是创建一系列小型博客帖子,这些帖子将概述主要观点,并提供完整研讨会的链接,供任何希望跟进的人使用。所有这些都可以在我们的 GitHub 上找到,并将在全年更新新的研讨会和挑战。
接下来的第一个研讨会是 Python 基础知识的介绍,这是对成员可以使用的编程环境的介绍,同时涵盖了 Python 的基础知识,如变量、数据类型和操作符。虽然这里将分享一些亮点,但完整的研讨会,包括问题表,可以在这里找到。
Jupyter 笔记本
该协会提供的大多数研讨会将在 Jupyter 笔记本中介绍。这允许混合使用降价和代码单元格,这意味着我们可以有效地并排显示代码解释和实际代码本身。这种形式通常被用作新程序员的训练床,因为它允许他们能够一点一点地与较小的代码片段进行交互,而不是面对一个很难学*的大脚本。它们还经常用于数据探索或模型结果阶段,因为它允许数据科学家以不同的方式探索数据或结果,以便我们检查数据包含的内容或查看如何以不同的方式评估模型,而不必开发和等待大型脚本运行。
降价单元格
Jupyter 笔记本包含 markdown 单元格,允许您像在 word 文档中一样编辑和创建文本,但格式是用代码而不是点击操作创建的。在笔记本中这样做的好处是,除了笔记本中的代码之外,它们还允许对您创建的代码进行深入解释,从而使工作流更容易理解和记录。这对于你或者其他人以后回到你的代码上来是很重要的。
它的格式使用 markdown 语言,允许你改变文本和格式,就像在文字处理器中一样。主要区别是使用代码来格式化文本,比如用#创建标题和题目,()[]创建链接,$ $包含数学文本。了解更多信息的好地方是降价指南这里。
编码单元格
Jupyter 笔记本中的另一种类型的单元格是代码单元格,顾名思义,这是您编写想要运行的代码的地方。只需单击单元格左侧的“play”按钮,单击顶部交互栏中的“run ”,或者在编写代码块时使用键盘上的ctrl + enter,即可完成此操作。笔记本的好处是双重的:第一,你可以一段一段地运行代码,而不是创建一个完整的程序;第二,代码单元的输出直接显示在下面,这样你就可以很快得到关于你的代码产生了什么的反馈。这对新学*者有快速反馈的好处,对更高级的代码有简单的交互,如随着程序的进展看到结果或可视化特定的输出。
注释
学*编码的一个重要部分是学*如何注释你的代码。这可以简单地通过在一行代码的开头或者你希望注释在代码单元中开始的地方使用一个#来完成,这允许你在代码中提供正在发生的事情的解释。当您想要对您的代码所做的事情编写简短、简明的解释时,或者当您想要隐藏一段代码以查看发生了什么时,这非常有用。一般来说,在代码中自由地添加注释(只要每行不超过 70 个字符)是一个很好的*惯,这样可以确保你和其他人都能理解你的代码想要达到的目的。
打印报表
我们首先要在代码中交互的是打印语句,这是代码中非常有用的基本工具。Python 的主要功能和优势之一是能够轻松地输出文本,无论是在代码单元的末尾、在终端中还是在日志文档中。它可以作为一种向计算机或用户输出代码结果的方式,这样我们就可以看到正在运行什么代码或者代码中发生了什么。为此,我们使用print()符号来打印代码中的文本,它可以接受多个参数。这方面的一个例子是:
print("The population of London is", 8.136, "million")#out:The population of London is 8.136 million
其中#out:显示了我们应该在代码块末尾看到的内容。我们在这里可以看到,我们为 print 语句输入了一些单词和数字,一旦代码运行,这些单词和数字就会显示在代码的末尾。我们可以在这个声明中加入更复杂的信息,但我们将把它留到以后。
变量
在 Python 中要学*的第二件重要的事情是,它可以用来在称为变量的东西中存储信息,我们可以在稍后的代码中调用这些变量来查看存储了什么。本质上,这是一种在程序中存储数据和信息的方式,允许您在代码中使用它。我们通过使用=操作符将信息分配给它们来创建这些变量,这仅仅意味着我们将操作符右边的值分配给操作符左边的值。例如:
#store data in variables
x = 10
y = "Peter"#print the values held in the variables
print(x)
print(y)#Out:
10
'Peter'
这里我们可以看到,我们将10赋给了变量x,将字符串"Peter"赋给了变量y。然后,我们使用我们所知道的关于 print 语句的知识,在程序的后面部分打印包含在每个变量中的信息。
数据类型
在变量中存储信息的一个重要部分是存储在这些变量中的数据的类型。这将影响我们将来对变量的处理,不管是加法、减法、乘法还是列表切片。您需要知道的主要变量类型有str、int、float和boolean,它们在代码中的定义如下:
a = 2
b = 2.0
c = "Hello World"
d = **True**
你能说出这些数据类型的区别吗?
在 Python 中:
int是一个整数值,即没有小数位float是带小数位的数值str是一个字符串值bool只能承担True或False
这些在编程中有特定的用途,我们将在后面探讨。然而现在,你可以通过使用type()函数询问程序一个变量包含什么类型的数据。这可以通过以下方式完成:
print(type(a))
print(type(b))
print(type(c))
print(type(d))#out:<class 'int'>
<class 'float'>
<class 'str'>
<class 'bool'>
我们可以看到a是一个int,b是一个float,c是一个str,d是一个bool。
一旦变量已经通过一个称为造型的过程被创建,我们就可以改变这些数据类型。这使用str、int、float和bool函数来改变变量的数据类型(如果可以改变的话):
a = "2"
print(type(a))
b = float(a)
print(type(b))#out:<class 'str'>
<class 'float'>
例如,虽然“2”由于使用了引号而以字符串开始,但我们将该类型转换为浮点型,因为 2 也可以是浮点型。如果您尝试将一个值转换为另一种数据类型,这将会失败,因为它根本不可能,例如“二”在尝试转换为int、float或bool时将不起作用,因为编程语言不能识别它。
基本运算符
根据我们拥有的数据类型,我们可以执行基本的操作。这通常包括:
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- 标识运算符
- 成员运算符
- 按位运算符
到目前为止,我们已经看到了有效的赋值操作符,通过它,数据被赋值给变量。然后,我们可以向您展示基本的算术和比较操作。
算术运算符
算术运算符可用于执行基本的数学计算,您可能会在学校中遇到过,并且会在计算器上执行。在 python 中,基本算术运算符包括:
+用于加法-进行减法运算*用于乘法运算/为分部%对于 modulos**求幂运算//为楼师
它可以用作:
*# Addition*
print("Addition:", 2 + 2) *# Subtraction *
print("Subtraction:", 5 - 2) *# Multiplication*
print("Multiplication:", 2*4) *# Division*
print("Division:", 6/3) *# Powers*
print("Powers:", 5**3) *# Division without remainder *
print("Divison without remainder:", 7//3) *# Returns remainder*
print("Division returning the remainder:", 7%3)#out:
Addition: 4
Subtraction: 3
Multiplication: 8
Division: 2.0
Powers: 125
Divison without remainder: 2
Division returning the remainder: 1
比较运算符
除了算术运算符,python 中需要理解的一个重要的基本功能是比较运算符。这些用于比较两个不同的数据或变量,目的是程序返回True或False。在 Python 中,这包括:
==为相等!=为不相等<因不到>对于大于>=为大于或等于<=小于或等于
例如:
#for equal
print("5 is equal to 5:", 5 == 5)#for not equal
print("5 is not equal to 4:", 5 != 4)#for less than
print("3 is less than 5:", 3 < 5)#for greater than
print("5 is greater than 3:", 5 > 3)#for greater than or equal to
print("5 is greater than or equal to 3:", 5 >= 3)#for less than or equal to
print("3 is less than or equal to 5:", 3 <= 5)#out:
5 is equal to 5: True
5 is not equal to 4: True
3 is less than 5: True
5 is greater than 3: True
5 is greater than or equal to 3: True
3 is less than or equal to 5: True
这些方法的使用将主要取决于您使用的数据类型,因为根据您可用的数据,比较的工作方式可能会有所不同。
至此,首届 UCL 数据科学学会研讨会结束!祝贺你完成这篇文章并继续学*。我们希望您在未来继续关注更多的研讨会。
完整的工作坊笔记,以及进一步的例子和挑战,可以在 这里 **找到。**如果您想了解更多关于该协会的信息,包括未来的研讨会,请随时关注我们的社交活动:
https://www.facebook.com/ucldata
Instagram:https://www.instagram.com/ucl.datasci/
领英:https://www.linkedin.com/company/ucldata/
https://philip-wilkinson.medium.com/membership
UCL 数据科学学会:Python 逻辑
原文:https://towardsdatascience.com/ucl-data-science-society-python-logic-3eb847362a97?source=collection_archive---------30-----------------------
讲*班 3:条件语句、逻辑语句、循环和函数

由 Ales Nesetril 在 Unsplash 上拍摄的照片
今年,作为 UCL 数据科学学会的科学负责人,该学会将在整个学年举办一系列 20 场研讨会,涵盖的主题包括数据科学家工具包 Python 和机器学*方法简介。对于我所展示和交付的每一个,我的目标是创建一系列的小博客,这些小博客将概述主要观点,并为任何希望跟进的人提供完整研讨会的链接。所有这些都可以在我们的 GitHub 上找到,并将在全年更新新的研讨会和挑战。
第二个研讨会是对 Python 逻辑的介绍,我们将向您介绍条件语句、逻辑语句(if、else 和 elif)、循环(for 和 while)和函数。虽然这里将分享一些亮点,但整个研讨会,包括问题表,可以在这里找到。
如果您错过了前两次关于 Python 基础和 Python 序列的研讨会,请在此处补上:
条件语句
Python 作为一种语言,支持数学中常*的比较语句,包括:
- 等于:a == b
- 不等于:a!= b
- 小于:a < b
- Less than or equal to: a < = b
- Greater than: a > b
- 大于或等于:a > = b
这些条件,就像数学中的一样,允许你检查数据或编程过程中的事情是真还是假,这是我们在第一次研讨会中介绍的。有了这些比较运算符,我们可以将它们与条件语句 if、else 和 elif 一起使用,这些条件语句实际上遵循与普通英语条件相同的逻辑。例如:
如果我有钱,我会买一辆宝马 M5,否则我会买一辆自行车
可以改写为:
如果我有钱,我会买一辆宝马 M5,否则我会买一辆自行车
Python 的 IF 结构遵循相同的方案。例如:
# assign a and b values
a = 10
b = 10# add a condition
if a == b:
# tell Python what to do if the condition is met
print("a equals b")# out:
a equals b
在这里,我们可以看到在满足条件的情况下运行了在条件之后缩进了一个制表符的代码。在这里,这意味着如果 a 与 b 相同,那么 print 语句将。如果不满足该条件,则不运行 If 条件中的代码。
然而,如果我们想在条件不满足时运行一些代码,我们可以使用如下的else语句:
# assign a and b values
a = 10
b = 20# add a condition
if a == b:
# tell Python what to do if the condition is met
print("a equals b")
# if a is different from b
else:
print("a does not equal b")
# this message will be printed# out:
a does not equal b
我们现在可以看到,如果不满足条件,我们可以设置一些代码来运行,而不是代码不运行。
另一个方面是,如果我们想在我们的条件中建立更多的信息。例如,我们不是仅仅指定a equals b是想说as is larger than b还是a is smaller than b,而是可以使用elif语句来这样做。实际上,这相当于一个else if语句,我们通过它指定第二个条件来检查第一个条件是否满足,并且只有当第一个条件不满足时,才允许我们在语句中加入更多的信息和选项:
# assign a and b values
a = 11
b = 10# add a condition
if a == b:
# tell Python what to do if the condition is met
print("a equals b")
# if a is different from b and smaller
elif a < b:
print("a is smaller than b")
else:
print("a is not equal to b nor smaller")
# this message will be printed# out:
a is not equal to b nor smaller
然后,我们可以通过内置逻辑操作符not、and和or使其变得更加复杂。实际上,这意味着:
- 如果两个语句都为真,则和返回真;
- 如果其中一个语句为真,则或返回真;
- not 反转结果,如果结果为真则返回 False
我们可以用它来创造更复杂的条件:
# assign values to a, b and c
a = 1
b = 2
c = 3# check different conditions
if a > b and b > c:
print("Both conditions are True.")
if a > b or a > c:
print("At least one of the conditions is True.")
if not(a % 2 == 0): # If a is NOT even, it will be printed.
print(a)if a > b and a > c and b > c:
print("All conditions are true.")
if a % 2 == 0 or b % 2 == 0 and c > 0: # Be careful which command will be evaluated first.
print("a or b is even and c is positive.")if not(a > 100) and b < 3:
print("Both conditions are true.")
if not(a + b < 10) or b < 0:
print("At least one of the conditions is true.")# out:
1
a or b is even and c is positive.
Both conditions are true.
不同逻辑运算符的优先顺序如下,这一点很重要:
- 不是
- 和
- 或
环
循环是一种重要的结构,可以学*它来自动化同一任务的多个实例。例如,对列表中的每一项执行相同的操作,或者使用循环在满足特定条件时产生给定的输出。为此,有两种主要类型:
- While 循环
- 对于循环
While 循环
只要创建循环的初始条件保持为真,while 循环就会在缩进的代码块中重复指令:
# initialise the variable
x = 0# write the condition
while x <= 10:
#"the following lines will be executed as long as x is smaller or equal than 10"
print (x)
#"however, if there are no changes made to our variable, the loop will continue infinetely"
#"so, in this case, we will increase x by one"
x = x + 1#out:
0
1
2
3
4
5
6
7
8
9
10
这意味着,如果没有对正在讨论的变量进行更改,或者条件从未更改,那么循环将永远不会结束。这就是我们所说的无限循环:
#DO NOT TRY RUNNING THIS CODE
#x = 0#while True:
# print (x)
要退出,您可以使用break命令,该命令将在被调用时退出循环,并且可以在满足特定条件时使用:
# initialise x
x = 0# start the loop
while x < 100:
print(x)
# add a condition
if x == 5:
# if the condition is met, stop the code
break
# if the condition isn't met, x will increase and the loop will continue
x += 1#out:
0
1
2
3
4
5
与此相反的是continue命令,它允许您跳过循环的某个迭代
#initialise x
x = 0#start the loop
while x < 10:
#add one to the value
x += 1
#continue condition
if x == 4:
#input the continue statement
continue
#the output of the loop if the continue statement is not run
print(x)#out:
1
2
3
5
6
7
8
9
10
为循环
第二个版本是循环的**,与 While 循环不同,它不需要你增加变量,因为它会自己增加。所以,对于一个变量 x,在一个给定的列表/字典/字符串中,循环将取列表中的每一个值。例如:**
# define a list
colours = ["red", "blue", "yellow","green","orange"]# loop over the list
for x in colours:
#print each value in the list
print(x)#out:
red
blue
yellow
green
orange
您现在可以迭代已经创建的数据。例如,这也可以循环字符串中的单个字母:
#create the for condition
for x in "red":
#print the result
print(x)#out:
r
e
d
和以前一样,我们也可以利用continue和break语句:
#create the for condition
for x in colours:
#if the color is blue
if x == "blue":
#then skip
continue
#else if the color is green
elif x == "orange":
#break the loop
break
#print the color
print(x)#out:
red
yellow
green
功能
最后,我们有函数。当您有一段需要反复使用的代码时,函数非常有用,但不一定像在循环中那样使用。当您需要运行相同的代码,但是使用不同的输入或者在整个代码中的不同点运行时,就会出现这种情况。因此,创建函数是减少实际产生的代码量的一种方式。
为此,我们需要能够定义一个函数,这个函数可以用下面的符号def function_name(input_variables):来完成。这几乎遵循与条件语句和循环相同的符号,即函数中的代码需要缩进和冒号才能工作,但现在我们添加了function_name,并允许用户传入input_variables。
这方面的一个例子是创建代码,能够告诉我们根据边的大小产生什么类型的三角形。我们可以通过调用它traingle_function来做到这一点,并允许用户传入三角形边长的三个变量作为a, b, c。
def triangle_function(a,b,c):
"""Tells you what type of triangle would have sides of size a, b, c"""
#if we have negative lengths then no triange
if a <= 0 or b <= 0 or c <= 0:
print("They can't represent lengths.")
#otherwise we have a triangle
else:
#a traingle cannot have one side that is bigger than the size of the
#the other two combined so we can check this condition
if a >= b + c or b >= a + c or c >= a + b:
print("It is not a triangle.")
#otherwise we know it is a triangle
else:
#if the sides are equal is it an equalateral triangle
if a == b == c:
print("It is an equilateral triangle.")
#if two sides are equal it is an isoceles triangle
elif a == b or a == c or b == c:
print("It is an isosceles triangle.")
#if Pythagoream theorem is correct then we get a rigfht angle
elif a**2 == b**2 + c**2 or b**2 == c**2 + a**2 or c**2 == a**2 + b**2:
print("It is a right-angled triangle.")
#otherwise it is an irregular scalene triangle
else:
print("It is a scalene triangle.")
然后我们可以调用这个函数,输入我们想要检查的信息:
triangle_function(3,4,5)
triangle_function(1,1,1)#out
It is a right-angled triangle.
It is an equilateral triangle:
正如我们所*,这简化了代码的实现或再次创建代码,因为我们所要做的就是创建函数。
我们可以使用函数执行更高级的操作,例如创建默认值,由此我们可以设置 c =3,作为默认值,如果我们知道在大多数情况下 c 将是 3,那么我们不需要每次都重新键入它,我们可以通过告诉函数为什么数据类型是预期的来添加类型提示,我们可以以 docstring 的形式添加文档来告诉用户在使用该函数时预期什么,我们也可以返回值,所有这些都在实用笔记本中进行了解释。
然而,函数的一个重要部分是知道局部变量和全局变量的区别。在处理函数时,任何只存在于函数内部的变量都称为局部变量,在上面的三角函数中,a、b 和 c 都是局部变量。这类变量只能在函数内部使用,如果你试图在其他地方使用它们,就会出错。与此相反的是全局变量,它们存在于函数之外,可以在任何地方使用,甚至在函数内部,尽管这是一种不好的做法。这方面的一个例子是:
# define a function
def function():
"y is a local variable (it only exists within our function), we will give y the value 100"
y = 100
# this function returns the value of x
return y# calling the function
function()# now, we will try to do an operation with x outside the function
print(y)
# because y is a local variable in the function, it won't work
#the error tells us that y is not defined#out:
**---------------------------------------------------------------------------**
**NameError** Traceback (most recent call last)
**~\AppData\Local\Temp/ipykernel_3564/2261376186.py** in <module>
10
11 **# now, we will try to do an operation with x outside the function**
**---> 12** print **(**y**)** **# because x is a local variable in the function, it won't work**
**NameError**: name 'y' is not defined
我们可以看到,我们在函数中定义了变量y,并试图在函数外部调用它。问题是y是一个局部变量,只存在于函数内部,即使函数被使用,这意味着我们不能在函数外部调用它。因此,我们得到了名称错误,它告诉我们y还没有被定义。
与此相反的是在函数中使用全局变量:
# assigning x a value as a global variable (outside the function)
x = "global variable"# defining a function
def function_2():
# we can use x because it's global in the function
print("x is a " + x)# calling the function
function_2()#out:
x is a global variable
我们可以在函数中使用全局变量。
然而,如果我们在函数内部改变变量,而没有把改变赋回给原始变量。那么原始变量不会改变:
c = 200#define a function
def add_100(c):
#alter the local variable
return c+100#call the function
print(add_100(c))#call the original variabl
print(c)#c has not changed because only the local variable c has changed inside the function#out:
300
200
在将来设计、创建和使用函数时,记住这一点很重要。
完整的研讨会笔记本,以及更多示例和挑战,可在 这里 找到。如果您想了解我们协会的更多信息,请随时关注我们的社交网站:
https://www.facebook.com/ucldata 脸书
insta gram:https://www.instagram.com/ucl.datasci/
领英:https://www.linkedin.com/company/ucldata/
如果你想了解 UCL 数据科学协会和其他优秀作者的最新信息,请使用我下面的推荐代码注册 medium。
https://philip-wilkinson.medium.com/membership [## scikit-learn 决策树分类器简介
towardsdatascience.com](/introduction-to-decision-tree-classifiers-from-scikit-learn-32cd5d23f4d)
UCL 数据科学协会:Python 序列
原文:https://towardsdatascience.com/ucl-data-science-society-python-sequences-e3ffa67604a0?source=collection_archive---------20-----------------------
工作坊 2:列表、元组、集合和字典!

由大卫·普帕扎在 Unsplash 上拍摄的照片
今年,作为 UCL 数据科学协会的科学负责人,该协会将在整个学年举办一系列 20 场研讨会,主题包括数据科学家工具包 Python 简介和机器学*方法。对于我介绍和交付的每一个,我的目标是创建一系列小型博客帖子,这些帖子将概述主要观点,并提供完整研讨会的链接,供任何希望跟进的人使用。所有这些都可以在我们的 GitHub 上找到,并将在全年更新新的研讨会和挑战。
本系列的第二个研讨会介绍了 Python 中的序列。这是 Python 入门系列的前一个研讨会的继续,涵盖了 Python 中的列表、元组、集合和字典的基础知识。一如既往,这是研讨会的总结,完整的 Jupyter 笔记本可以在我们的 GitHub 上找到。
如果您错过了,请参加上周的 Python 基础知识研讨会:
第二个工作坊是 Python 序列的介绍,包括 Python 代码中可以找到的四个主要数据结构list、tuple、set和dictionary。在我们开始之前,有一些关键短语需要理解:
- 可变:这意味着项目一旦被创建就可以被改变。与此相反的是不可变的,这意味着一旦对象被创建,它就不能被改变。这将影响数据结构在代码中的使用情况。
- Ordered :这意味着项目的存储方式不会改变(除非明确说明),并且可以通过了解项目的存储顺序来访问。与此相反的是一个无序对象,其中存储的项目不能按照它们被放置的顺序来访问。
- 可索引:这意味着可以根据使用索引将项目添加到数据结构中的顺序来访问项目。这仅适用于有序对象,因为无论何时调用或使用它,顺序都保持不变。
目录
经常遇到的第一种数据结构是列表结构。它们是有益的,因为它们可以在一个变量中存储多个项目,就像您所期望的书面列表一样。列表的主要特征是:
- 可变:一旦创建就可以更改。
- **有序:**它们在创建时保持它们的顺序。
- 可索引:我们可以根据数据在列表中的位置来访问数据。
- 可以包含重复记录:相同值的数据可以存储在一个列表中。
这会影响列表在程序中的使用方式。
我们可以使用=操作符在 Python 中创建一个list,就像我们在第一次研讨会中对变量赋值所做的那样,但是这里我们使用[]来包含列表或者使用list()方法,如下所示:
*#create a list of Fruit using the [] notation*
fruit_list = ["Apple", "Banana", "Peach"]
*#creating a list of vegetables using the list() nottation*
vegetable_list = list(["Pepper", "Courgette", "Aubergine"])
这意味着我们在这些附件中包含了我们希望包含在列表中的所有项目,用逗号分隔每个项目。
虽然我们在上面的列表中使用了字符串,但实际上我们可以在列表中使用任何我们想要的数据类型,如下所示(甚至是列表中的列表!):
*#different list*
random_list = ["Hello", 3, "Cheese", 6.2, [1,2,3]]
*#print the result*
print(type(random_list))
print(random_list)# out:<class "list">
["Hello", 3, "Cheese", 6.2, [1,2,3]]
列表的一个重要特征是它们是有序的数据集合。这意味着如果我们知道索引是什么,我们就可以根据它的位置(索引)从列表中访问信息!但是需要注意的是,Python 从 0 开始计数,这意味着列表中的第一项的索引为 0。例如,我们可以使用1的索引值从上面的fruit_list中提取Banana。这是使用方括号符号来完成的,在这里,我们在调用列表名称之后,在[index]中传递索引,如下所示:
fruit = friut_list[1]print(fruit)#out:`Banana`
我们还可以使用list[first_index, last_index_not_inclusive]形式的列表片和负索引来访问列表中的多个条目,其中我们从-1开始从列表的末尾往回计数。看看您能否理解下面的列表片段是如何工作的:
*#create a list of scores*
scores = [12,42,62,65,73,84,89,91,94]*#second lowest to fifth lowest*
print(scores[1:5])
*#print second lowest*
print(scores[1:2])
*#print the fifth lowest to the highest*
print(scores[5:])
*#print the third highest to the highest*
print(scores[-3:])#out:42, 62, 65, 73
42
84, 89, 91, 94
89, 91, 94
使用列表可以做的其他事情包括:如果我们知道值,则查找项目的索引,添加项目,删除项目,按升序或降序对列表进行排序,将列表添加在一起,以及查找列表的长度。如果你想知道如何做到这一切,你可以去我们 GitHub 上的练*册:练*册。
元组
Python 中我们经常遇到的第二种数据结构是元组。这些类似于列表,但具有以下特征:
- 不可改变的:一旦它们被创建,就不能被改变。
- **有序:**项目添加的顺序保持不变。
- **可索引:**我们可以根据索引来访问项目。
- **可以包含重复:**该数据结构中可以有相同值的项目。
这改变了它们相对于列表的用途,因为主要区别在于它们是不可变的。这意味着,当您希望确保数据不会在程序中被更改(即使是意外更改)时,可以使用它们,而不是使用列表,同时仍然保留相同的功能。
相对于列表,我们可以通过三种主要方式创建元组:
- 我们可以使用
()来包含用逗号分隔的项目。 - 我们可以在由逗号分隔的
()或[]包含的项目周围调用tuple()。
我们可以看到这一点:
*#create the tuple*
cars = ("Ford", "Hyundai", "Toyata", "Kia")*#create a second tuple*
fruits_tuple = tuple(("Strawberry", "peach", "tomato")) *#create the third tuple*
vegetable_tuple = tuple(["potato", "onion", "celery"])#print the result
print(cars)
print(type(cars))print(fruits_tuple)
print(type(fruits_tuple))print(vegetable_tuple)
print(type(vegetable_tuple))#out:
('Ford', 'Hyundai', 'Toyata', 'Kia')
<class 'tuple'>
('Strawberry', 'peach', 'tomato')
<class 'tuple'>
('potato', 'onion', 'celery')
<class 'tuple'>
事实上,它们是有序的和可索引的,这意味着我们可以像访问列表一样使用索引来访问元组中的信息,所以我们在这里不再重复。
虽然元组是不可变的,但有一种方法可以实际改变其中的信息。这是通过将两个元组相加或相乘来实现的(好吧,这样不会真正改变其中的信息),如下所示:
*#create new tuples*
tuple1 = ("a", "b", "c")
tuple2 = (1,2,3)
*#add together using the +*
tuple3 = tuple1 + tuple2
print(tuple3)
*#multiply an existing tuple together*
tuple4 = tuple1*2
print(tuple4)#out:
('a', 'b', 'c', 1, 2, 3)
('a', 'b', 'c', 'a', 'b', 'c')
除此之外,我们还有内置的功能和方法,包括:查找长度、元组中特定值的实例数、最小值和最大值。如果你想知道如何做到这一切,你可以去我们的 GitHub 上的练*册:练*册。
设置
紧接着,另一个类似于列表的数据结构是集合。这一点的主要特点是:
- 可变:一旦创建,就可以改变。
- **无序:**当你稍后调用它们时,顺序不再保持不变。
- **不可索引:**你不能用给定的索引访问某个项目。
- 不允许重复:集合不能包含重复值。
这再次改变了它们在程序中相对于列表的使用方式。最重要的是,它们不能包含重复的信息,所以如果您不关心单个项目的实例数量,只需要比使用集合更唯一的值。然而,在这种情况下,如果您关心一个项被添加到数据结构中的顺序,您就不会使用集合。
我们可以通过两种主要方式来创建它们:
- 我们可以使用
{}来包含由逗号分隔的项目列表 - 我们可以使用
set()符号来包含由逗号分隔的条目列表或元组
这方面的一个例子如下:
*#create a set using curly brackets*
fruits = {"apple", "banana", "cherry"}
*#create a set using the set constructor*
vegetables = set(("courgette", "potato", "aubergine"))#print the results
print(fruits)
print(vegetables)#out:
{'cherry', 'apple', 'banana'}
{'potato', 'aubergine', 'courgette'}
事实上,集合中的条目是未索引的,也就是说,它们不能像在列表中那样被访问,因为我们不能保证它们在我们输入它们时的位置。因此,有两种主要方法来检查一个项目是否在器械包中:
#use a loop to iteratre over the set
for x in fruits:
print(x)
#or check whether the fruit you want is in the set
print("apple" in fruits)
#which acts the same way as if it were in a list#out:
cherry
apple
banana
True
这也意味着在集合中添加和删除项目与我们处理元组或列表的方式略有不同。然而,我们也有类似的列表功能,因为我们可以找到长度或找到一个项目是否在一个集合中。有关这方面的更多信息可在工作簿中找到。
词典
最后,在 Python 编程中经常遇到的另一种数据结构是字典。这些具有以下特点:
- **可变:**创建后可以更改。
- Ordered :条目添加到字典的顺序保持不变。
- 可索引:我们可以根据它们的索引(在本例中是它们的键)来访问项目
- **不能包含重复值:**至少就它们的键而言
与以前的数据结构相比,这种结构的主要区别在于数据存储在key:value对中,这意味着我们将通过指定key来访问字典中的条目,而不是编号索引。这意味着我们可以将数据与特定的键相关联,这在我们想要维护数据集中不同字典之间的关系时是有意义的。
创建这个数据结构的主要方法是在{}中指定key:value对。虽然这类似于一个集合,但是主要的区别是key和value被:分开,这确保了一个字典被创建。我们也可以在两个列表上使用dict()来创建它。这可以如下进行:
new_dict = {"Name":"Peter Jones",
"Age":28,
"Occupation":"Data Scientist"}print(new_dict)#out:
{'Name': 'Peter Jones', 'Age': 28, 'Occupation': 'Data Scientist'}
这种结构本质上意味着我们可以使用key来访问values而不是数字索引。例如,如果我们想知道这个人的名字,我们可以用:
#the first way is as we would with a list
print(new_dict["Name"])#however we can also use .get()
print(new_dict.get("Name"))#the difference between the two is that for get if the key
#does not exist an error will not be triggered, while for
#the first method an error will be
#try for yourself:
print(new_dict.get("colour"))
#print(new_dict["colour"])#out:
Peter Jones
Peter Jones
None
后一种方法更有用,因为如果键不存在,它将停止你的程序,除非被处理,而不是一个错误,而是通过一个 None 值。
以这种方式访问信息意味着我们不能在数据集中有重复项,因为我们不知道我们将访问什么:
second_dict = {"Name":"William",
"Name":"Jessica"}print(second_dict["Name"])#out:Jessica
正如我们在这里看到的,我们有两个“name”键,当试图访问信息时,它只打印第二个值,而不是第一个值。这是因为第二个密钥会覆盖第一个密钥值。
由于这也是可变的,我们可以在字典创建后改变、添加或删除条目,与列表的方式类似,但我们使用键而不是使用[]中的索引:
#create the dictionary
car1 = {"Make":"Ford",
"Model":"Focus",
"year":2012}#print the original year
print(car1["year"])#change the year
car1["year"] = 2013#print the new car year
print(car1["year"])#add new information key
car1["Owner"] = "Jake Hargreave"#print updated car ifnormation
print(car1)#or we can add another dictionary to the existing dictionary using the update function
#this will be added to the end of the existing dictionary
car1.update({"color":"yellow"})
#this can also be used to update an existing key:value pair#print updated versino
print(car1)#out:
2012
2013
{'Make': 'Ford', 'Model': 'Focus', 'year': 2013, 'Owner': 'Jake Hargreave'}
{'Make': 'Ford', 'Model': 'Focus', 'year': 2013, 'Owner': 'Jake Hargreave', 'color': 'yellow'}
字典的好处是键,这意味着我们可以将特定的值与用于访问信息的给定键相关联。这可以包括使用记录,例如使用特定的 id 与其他信息相关联。
其他方法包括访问所有的键、访问所有的值、访问作为元组的key:value对以及打印字典的长度。
完整的研讨会笔记,以及进一步的例子和挑战,可以在这里找到 。
如果您想了解我们协会的更多信息,请随时关注我们的社交网站:
https://www.facebook.com/ucldata:[脸书](https://www.facebook.com/ucldata)
insta gram:https://www.instagram.com/ucl.datasci/
领英:https://www.linkedin.com/company/ucldata/
如果你想了解 UCL 数据科学协会和其他优秀作者的最新信息,请使用我下面的推荐代码注册 medium。
https://philip-wilkinson.medium.com/membership
或者,如果您想阅读我的其他作品,请访问:
https://python.plainenglish.io/abstract-data-types-and-data-structures-in-programming-570d40cb4b44
使用这个 Python 类查询 43 个 NIH 生物医学数据库的元数据
原文:https://towardsdatascience.com/uery-information-about-43-nih-biomedical-databases-with-this-python-4e534a12c3fb?source=collection_archive---------27-----------------------
NIH 的国家生物技术信息中心(NCBI)管理着 43 个向公众开放的 Entrez 生物医学信息数据库。使用 Python 类 c_e_info 来检索数据库的统计数据和其他信息。
“我们相信上帝,所有其他人都会带来数据。” —爱德华兹·戴明

照片由 Joshua Sortino 在 Unsplash 上免费提供
介绍
美国政府已经积累了难以置信的大量数据。公众可以通过文件下载或 API 免费获得其中的大部分内容。例如,美国国立卫生研究院(NIH)的国家生物技术信息中心(NCBI)管理着 43 个公共可访问的生物医学数据库,统称为 Entrez 数据库。
Entrez 数据库包含各种数据,如超过 3000 万篇生物医学期刊文章的参考文献和摘要、基因组序列以及公共序列数据库中所有生物的分类和命名。
数据工程师、数据分析师、数据科学家和软件开发人员可以将 Entrez 数据库中存储的各种生物医学和生物技术数据用于他们的项目。例如,我开发了几个解决方案来查询、检索和分析来自 Entrez PubMed biomedical 文章摘要数据库的数据。
本文描述了可以用来访问 Entrez 数据库的 Entrez 编程实用程序(E-utilities)。它还演示了 Python c_e_info 类来查询关于数据库的元数据。它调用 Entrez EInfo 实用程序来获取 Entrez 数据库的列表以及 43 个数据库中任何一个的元数据。您可以使用其他电子工具来搜索数据库,并为您的项目检索生物医学数据。
电子工具概述
E-utilities 包括 9 个服务器端程序,为程序员提供了一个从 Entrez 查询和数据库系统中查询和检索数据的界面。
虽然本文详细介绍了 EInfo 电子实用程序,但以下部分提供了所有电子实用程序的概述。
EInfo
EInfo 提供两种类型的信息。首先,它返回所有 Entrez 数据库的名称列表。其次,它为指定的数据库提供元数据。它检索名称、其他描述符、它包含的记录数以及上次更新数据的日期和时间。它还提供了每个数据库字段的名称以及如何链接到其他 Entrez 数据库的信息。
电子搜索
ESearch 对数据库执行文本搜索。它返回与搜索条件匹配的记录的唯一标识符(uid)列表。然后,程序员使用这些 uid 通过其他电子工具检索数据,包括 ESummary、ELink 和 EFetch。
电子公告
EPost 用于将一组 uid 上传到历史服务器。它返回数据集的查询关键字和 web 环境。程序员以后可以用存储在历史服务器上的 uid 从数据库中检索数据。
电子摘要
当使用数据库的 uid 列表调用时,ESummary 返回文档摘要。
埃菲奇
当用一组 uid 调用时,EFech 以指定的格式从数据库返回数据记录。
埃林克
当提供了一个数据库的 uid 列表时,ELink 返回同一个数据库中的相关 uid 列表或另一个 Entrez 数据库中的链接 uid 列表。
马术
EQuery 返回每个数据库中匹配文本搜索的记录数。
埃斯佩尔
ESpell 为数据库的文本查询解析拼写建议。
ECitMatch
ECitMatch 检索与一组给定的引用文本字符串相对应的 PubMed id(pmid)。PubMed 是 Entrez 数据库,包含超过 3000 万篇生物医学期刊文章的摘要。
电子工具文档
电子工具在帮助网页上有很好的文档记录。您也可以下载这些页面的 PDF 文件。
这些帮助页面提供了电子实用程序的概述以及有关 EInfo 实用程序的其他详细信息:
- 电子工具的一般介绍
- 电子公用事业快速启动
- 深度信息
EInfo 电子工具
如上所述,EInfo 返回所有 Entrez 数据库的列表,或者在给定数据库名称的情况下,它返回关于数据库的一般信息、其字段的描述以及关于其到其他 Entrez 数据库的链接的信息。
电子实用程序深入帮助页面的电子信息部分提供了有关如何使用该实用程序的信息。
检索 Entrez 数据库列表的 URL
像所有的电子工具一样,EInfo 有一个基本 URL,用来从 Entrez 或它的一个数据库中请求数据。
电子信息基础网址:
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/einfo.fcgi
要查看调用 EInfo 的返回输出及其基本 URL,请在 web 浏览器中打开该 URL。它应该返回 XML 格式的有效 Entrez 数据库列表,如下面的屏幕截图所示。

Entrez EInfo 实用程序返回 XML 格式的 Entrez 数据库列表。图片由作者提供。
检索 Entrez 数据库详细信息的 URL
要检索关于 Entrez 数据库的详细信息,调用 EInfo 基本 URL,用 db 参数和数据库的名称作为它的值。调用以下示例 URL 将返回关于 PubMed 数据库的信息。
带数据库参数的 EInfo 基本 URL:
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/einfo.fcgi?db=pubmed
要查看使用 db 参数调用 EInfo 返回的输出,请在 web 浏览器中导航到 URL 地址。它应该返回关于数据库的元数据、关于每个字段的细节以及关于到其他 Entrez 数据库的每个链接的细节。

Entrez EInfo 实用程序以 XML 格式返回关于 Entrez 数据库的元数据,在本例中是 PubMed。图片由作者提供。
其他 EInfo 参数
除了 db 参数外,EInfo 还将可选的 版本 和 retmode 参数作为输入。
版本
使用可选的 版本 参数指定版本 2.0 EInfo XML。它只允许值“2.0”。使用时, EInfo 将返回两个额外的字段:
retmode
使用可选的retmode****参数指定检索数据的格式。默认值为“xml ”,以 XML 格式返回数据。值“json”也可用于检索 JSON 格式的数据。
Python 控制器和 c_e_info 类
Python c_e_info 类包装了 EInfo 并扩展了它的功能。它执行以下功能:
- 调用 EInfo 实用程序获取 Entrez 数据库的有效列表。以 XML 格式返回输出。
- 调用 EInfo 实用程序以获取指定数据库的概览、字段列表和数据库链接列表。以 XML 格式返回输出。
- 将调用 EInfo 实用程序返回的 XML 输出写入文件。
Python 控制器
下面显示的控制器代码导入 c_e_info 类模块,并执行这些任务来获取、显示和存储有效 Entrez 数据库的列表以及 Entrez PubMed 数据库的详细信息:
- 创建一个不带参数的 c_e_info 实例。类构造函数将调用一个函数,该函数调用 EInfo 实用程序并以 XML 格式返回数据库列表。
- 将包含数据库列表的 XML 流写入文件。
- 创建一个 c_e_info 的实例,带有一个数据库名称参数(本例中为‘PubMed’)。类构造函数将调用一个函数,该函数调用 EInfo 实用程序并返回数据库的概述、其字段的详细信息以及其与其他 XML 格式的 Entrez 数据库的链接的详细信息。
- 将包含指定数据库详细信息的 XML 流写入文件。
调用 c_e_info 类以获取 Entrez 数据库列表和 PubMed 数据库元数据的控制器代码。
Python c_e_info 类
c_e_info 类执行控制器请求的任务。下面代码中的注释描述了它的功能。
Python c_e_info 类调用 Entrez EInfo 实用程序来获取 Entrez 数据库列表和关于 Entrez 数据库的元数据。
c_e_info 类和控制器的使用
虽然您可以使用其他电子工具来查询和检索 Entrez 数据库中的数据,但是可以使用 EInfo 来获得对 Entrez 数据库的基本了解。以下是 EInfo 和 c_e_info 类的一些可能用法:
- 了解数据结构 —使用通过 EInfo 为 Entrez 数据库检索的字段和链接数据来了解数据结构,为数据分析、数据科学或软件开发项目做准备。
- 建立数据库 —获取 Entrez 数据库中字段的详细信息,以建立数据库表(在数据库管理系统中,如 Microsoft SQL Server、MySQL、Oracle 或 PostgreSQL ),以包含来自电子工具调用的数据。
- 查看基本数据库元数据 —检索数据库列表,并大致了解每个数据库、其记录数量、上次更新时间、其字段及其与其他 Entrez 数据库的链接。
从这里去哪里
我开发了几个数据分析产品和一个应用程序,其核心是来自 Entrez PubMed 数据库的生物医学文章摘要。也许您可以在项目中使用存储在 Entrez 数据库中的数据。以下是一些想法:
- 增强 c_e_info 类来优雅地处理错误。
- 将有关 c_e_infor 执行的任务的信息写入日志文件。
- 审查每个 Entrez 数据库的现场信息,并确定用例,以便为即将到来的或潜在的项目利用数据。
- 更改或扩展 c_e_info 类的功能以满足您的需要。
- 了解如何使用其他电子工具从 Entrez 数据库获取数据。
- 编写程序或类来解析和创建从 E-utilities 调用返回的 XML 或 JSON 输出的索引。
- 编写一个 Python 类,将调用 E-utilities 返回的 XML 转换为 HTML 文件,并将它们发布到 Web 服务器。
- 编写一个 Python 类,将调用 E-utilities 返回的 XML 转换为其他格式(如 CSV),以便在商业智能和数据可视化工具中呈现和分析,如 Tableau 或 Microsoft Power BI 。
- 编写一个实用程序类,调用 E-utilities 从 Entrez 数据库中检索数据,并将其插入数据库。
- 用 Python 或其他语言构建包装类,以简化和扩展其他电子工具的使用。
程序设计环境
我使用了以下操作系统和工具来编写和测试这个项目和文章的代码:
- Windows 10——Windows 是我选择的操作系统,但 Python 代码可以在其他*台上运行。
- Python 3.9——我在这个项目中使用了 Python 3.9.2,但其他 Python 3 版本应该也可以。
- Visual Studio Community 2019—我使用微软 Visual Studio 已经几十年了,发现它可靠、功能多样、速度快。免费社区版很好地满足了我的大部分需求。Visual Studio Code (VS Code)或者任何你喜欢的集成开发环境(IDE)或者代码编辑器应该可以很好的工作。
在代码示例中,使用标准的 Windows 文件目录和名称格式调用 c_e_info.write_db_xml()函数,如下所示。您可能需要修改文件目录名格式,以便与您的操作系统配合使用。
PubMed _ db _ list . write _ db _ XML(' c://project _ data/c _ e _ info/entrez _ db _ list . XML ')
摘要
43 个 Entrez 生物医学数据库存储了丰富多样的数据集合,可以推动或增强许多数据分析和数据科学项目。9 Entrez E-utilities 易于使用。您可以将它们集成到您的程序中,并使用用 Python 或其他程序编写的包装类来扩展它们。
我希望本文及其示例代码已经为您提供了对 E-utilities 的基本理解、关于其 EInfo 实用程序的有用操作信息,以及如何使用包装和扩展其功能的 Python c_e_info helper 类。
关于公共数据集的其他文章
如果您对推动或增强您的项目的数据感兴趣,请参*我在《走向数据科学》杂志上发表的关于免费访问公共数据集的其他文章:
- 使用 Data.gov 上编目的公共数据集推动数据科学项目
- 用 Python 和 Tableau 从 analytics.usa.gov 采集和分析数据
- 如何编写 Python 程序在 PubMed 数据库中查询生物医学期刊引文
关于作者
Randy Runtsch 是一名作家、数据工程师、数据分析师、程序员、摄影师、自行车手和冒险家。他和妻子住在美国明尼苏达州东南部。
Randy 撰写关于公共数据集的文章,以推动*解和决策、写作、编程、数据工程、数据分析、摄影、野生动物、自行车旅行等。
数据科学家 API 终极指南
原文:https://towardsdatascience.com/ultimate-guide-to-apis-for-data-scientists-695c884737de?source=collection_archive---------41-----------------------

作者图片
网络服务 101
如果你在软件领域工作,你不可能没有听说过 web 服务。每一个依靠技术的公司都在向 web 服务框架发展。它们很容易操作,它们使整个代码模块化,并且由于它们集成了用不同语言编写的代码片段,所以也更高效和易于维护。
什么是 web 服务
web 服务是一段软件/代码,它向想要与之交互的任何其他代码段提供功能。
为什么选择 web 服务
随着科技公司试图让他们的产品或服务更好更快,他们试图向更新的技术和*台过渡。在这种情况下,拥有一个与技术或构建旧版本的*台紧密耦合的代码可能是一项乏味的工作,有时甚至是一项危险的工作。
为了解决这个问题,代码需要与*台分离。这正是 web 服务的目标。当你用 Python 创建一个机器学*模型,并且你想把它安装在一个主要基于 Java 或 JavaScript 的后端,而没有网络服务,你将不得不用另一种语言重写其中一个代码。那会让你和你的团队付出很多返工和挫折的代价,也就是技术债务。提示:我们总是致力于减少我们的技术债务。
由于我们的目标是降低技术债务,我们将代码转换成 web 服务,并使它们相互交流。现在,基于 Python 的 ML 预测模型“服务”可以与 MongoDB“服务”对话,并通过 UI 将数据返回给用户。
从 Web 服务到 API
所有 web 服务都被设计成 API 或应用程序编程接口。API 是系统的入口点(访问 API 中代码的方式)。
API 由 URL(统一资源定位符)标识。请将 URL 视为访问代码所需的地址。它看起来像这样:
127.0.0.1:8080
前四个数字代表主机(实际地址)。主机是您保存模型/数据/信息的地址。冒号(:)左边的数字称为端口。端口是访问代码的实际端点。
但是,出于测试目的,您也可以在自己的计算机上运行代码,或者在所谓的本地主机上运行代码。如果您想访问本地主机上的代码,您可以使用类似下面的 URL:
localhost:8001
GET 和 POST 方法
如果您正在将 ML 模型构建到您的 API 中,那么您肯定需要从用户那里获取数据,并从中返回预测。您可能还需要从您的 API 中获取一些信息(可能打印出默认值或您的 ML 模型或其他信息)。对于其中的每一项,都有一个特定的方法来完成这些任务。
GET 方法用于从 web 服务获取信息。
POST 方法用于向 web 服务提供信息。
除了这些方法之外,还有两个方法:PUT 和 DELETE。PUT 方法用于更新服务中的信息,而 DELETE 方法用于从服务中删除信息。
多个端点
如果您的应用程序有多个 API(一个用于训练模型,一个用于预测,可能还有一个用于 ETL),您可以通过为应用程序中的 n 个 API 中的每一个创建 n 个“routes”来将它们全部放在一个脚本中。
路由基本上是您的基本 URL 的扩展。例如,如果我有一个基本 URL 为 localhost:8000 的 API,并且您的 API 中有一个是数据摄取 API,另一个是训练模型,还有一个是预测,那么您的路由可以是:
localhost:8000/dataingestion
localhost:8000/training
localhost:8000/prediction
通过这种方式,您可以将所有 API 放在一个脚本中,这使得部署更加容易。
结论
了解模型部署是数据科学家的一项重要技能。因为我认识的许多数据科学家对软件开发或系统设计知之甚少,所以我写了这篇文章来给出一个关于如何构建一个 API 的基本想法和这个领域的一些重要术语。我希望它能帮助其他软件新手进入网络服务。
🏐终极排球:使用 Unity ML-agent 构建的多 agent 强化学*环境
原文:https://towardsdatascience.com/ultimate-volleyball-a-3d-volleyball-environment-built-using-unity-ml-agents-c9d3213f3064?source=collection_archive---------19-----------------------
训练强化学*代理打排球

作者图片
受 黏液排球馆 的启发,我用 Unity 的**ML-Agents toolkit搭建了一个训练强化学* agent 的 3D 排球环境。整个项目是开源的,可以在 获得🏐终极排球 。**
在本文中,我分享了从设计环境到培训 it 代理的实施细节、挑战和经验。有关 ML-Agents 的背景,请查看我的ML-Agents 简介文章 。
*****所用版本:***Release 18(2021 年 6 月 9 日) ***Python 包:*0 . 27 . 0 Unity 包: 2.1.0
🥅建立法院
之前没有游戏设计或 3D 建模的经验,我发现 Unity 的免费资源和样本项目库非常有用。
以下是我用过的:
- 代理立方体预置来自ML-代理样例项目
- 免费沙滩必需品资源包 中的排球预制品和沙子材料
- 网材来自 自由网格&网材包
球场的其余部分(网柱、墙、球门和地板)都被重新调整了大小,并旋转了拼凑在一起的立方体对象。

作者图片
地板实际上由两层组成:
- 薄薄的紫色和蓝色边目标放在一个“触发”碰撞器的顶部
- 一层可步行地板下面****
球门检测球何时撞击地板,而可行走 地板为球提供碰撞物理学。
需要注意的一些其他实现细节:
- 代理看起来像立方体,但是有球体碰撞器来帮助他们控制球的轨迹。
- 我还在球场周围加了一道无形的边界。我发现,在训练期间,如果你因为击球出界而惩罚他们,代理人可能会回避学*击球。
📃剧本
在 Unity 中,可以将脚本分配给各种游戏对象来控制它们的行为。下面是用于定义环境的 4 个脚本的简要概述。
VolleyballAgent.cs
附属于代理人
这控制了代理的观察集合和动作**。**
( 链接到完整代码 )
VolleyballController.cs
附球
这个脚本检查球是否落地。如果是这样,它会触发VolleyballEnv.cs的奖励分配
( 链接到完整代码 )
VolleyballEnvController.cs
附属于母排球区(其中包含代理人、球等。)
这个脚本包含了管理剧集开始/停止,如何产生对象,以及如何分配奖励的所有逻辑。
( 链接到完整代码 )
VolleyballSettings.cs
附加到一个单独的‘排球设置’对象
这保持基本环境设置的常数,例如代理运行速度和跳跃高度。
( 链接到完整代码 )
🤖代理人
环境被设计成对称的,这样两个代理可以共享同一个模型,并使用 自我游戏 进行训练。
我决定从简单的矢量观测开始。这些都是相对于代理定义的,所以代理是扮演蓝色立方体还是紫色立方体并不重要。
观察结果:
总观察空间大小:11
- 旋转(Y 轴)——1
- 从代理到球的 3D 矢量— 3
- 到球的距离— 1
- 代理速度(X、Y 和 Z 轴)— 3
- 球速(X、Y 和 Z 轴)— 3
****注意:对于一个代理来说,知道关于其环境的这种直接观察是非常不现实的。进一步的改进可能包括添加 光线投射 、对手位置(以鼓励竞争性比赛),以及规范数值(以帮助训练更快收敛)。
可用操作
4 个分立分支:
- 向前、向后移动,保持静止(尺寸:3)
- 向左、向右移动,保持不动(尺寸:3)
- 向左、向右旋转,保持静止(尺寸:3)
- 跳,不跳(尺寸:2)
🍭奖励
为了训练一个简单的代理人截击,我选择了一个简单的奖励+1,因为我把球打过了网。正如您将在下一节中看到的,这相对来说效果不错,不需要进一步的奖励调整。
如果你计划训练一个有竞争力的代理人或者使用自我游戏,ML-Agents 文档https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Training-Configuration-File.md#self-play建议保持简单的奖励(胜利者+1,失败者-1),并允许更多的训练迭代来补偿。
️🏋️♀️培训
对于训练,我选择使用 PPO 仅仅是因为它更简单,而且可能更稳定。
Unity ML-Agents 提供了 PPO 算法的开箱即用实现(其他包括 盖尔、萨克、POCA )。您需要提供的只是 YAML 配置文件中的超参数:
( 链接到全码 )
为了加快训练速度,我创建了 16 个环境副本,它们都有助于并行训练同一个模型:

作者图片
Unity ML-Agents 在提取强化学*所需的所有样板代码方面做得很好。用于训练的终端命令将类似于:
注意: ML-Agents 默认时间刻度为 20,以加快训练速度。显式设置标志--time-scale=1很重要,因为这种环境中的物理特性是依赖于时间的。

作者图片
使用这种设置,训练 2000 万步需要大约 7 个小时。到了这个阶段,特工们已经能够近乎完美地来回凌空了!
👟后续步骤
感谢阅读!
我希望这篇文章能让你对 Unity ML-Agents 中设计和训练强化学*代理的过程有一个好的了解。对于任何对强化学*动手项目感兴趣的人,或者正在寻找一种方法来创建复杂和物理丰富的 RL 环境的人,我强烈建议尝试一下 Unity ML-Agents。
请做 检查环境 如果你感兴趣,提交你自己的代理来与他人竞争!
欢迎任何反馈和问题。也可以通过 Twitter 与我联系。
📚资源
对于希望构建自己的环境的其他人,我发现这些资源很有帮助:
- 蜂鸟教程 by Unity(可惜过时了,不过还是有用)。
- ML-agent 样本环境 (特别是足球&跳墙环境)
超简洁的 Python 代码——精简代码并获得更好的精神健康
原文:https://towardsdatascience.com/ultra-concise-python-code-shaving-code-and-finding-better-mental-health-24cc71439bce?source=collection_archive---------31-----------------------

作者图片
我称之为:razor fine 代码,但是“fine”使我们在这里讨论的东西变得模糊不清。这是严密的 python 代码。它的工作是用几行文字表达。但是是好是坏是你的事。这是你的心理健康电话。让我们做好准备:
当评审人员不幸检查我的代码时,他们被一位主管(现已去世)所说的“强烈厌恶声明变量两次”所伤害那位主管宁愿踩在黏糊糊的鳄梨核上滑倒,也不愿给予表扬。他没有给。不,他不喜欢我的清单理解[i for i in range(….)]、频繁的羊肉(l = lambda x: …)或者我的发型(-)。很好——我的第一直觉——因为他的代码很糟糕!但在他最后一次登录 github 并把他的账户留在地上后,我有理由思考。当某人的回购突然终止时,回顾我们与他的斗争是一种礼貌。为了配合超黑暗和广泛的单一材料主题的早晨——你明白的。嗯……我思考了一下,最终我明白了。他鄙视他的工作。当然,我不必用单行循环和修饰类来填充我的代码。我也可以去剪头发。但后来,我意识到:我喜欢它。我写代码的方式让我很开心。超简洁代码的噼啪声是好代码——对我来说是好代码——你也会发现对你也是好代码。
没有人喜欢重复自己——不重复是好*惯。但是我有一种倾向,那就是把好的练*“弯曲”到我古老的内在意大利语:Sorta di Estremo。Python 3.8 引入了新的“walrus”赋值操作符:= ,从而引发了公共行为的变化。突然间,我们可以让代码变得超级紧凑,把袜子之类的新变量塞进口袋里,以便当天晚些时候使用。
a = 12 if (list_length := len(super_duper_long_list)) > 20000000 else list_length
(需要 Python 3.8+因为:=赋值表达式)
现在—能够在 if 语句中间声明一个变量 slap bang,然后在同一个语句中继续使用它,这有多好?太棒了。在上面的例子中,我们避免两次计算列表的长度。崇高的事业。为表现而拍背。是的,我们可以在 if 语句之前,得到列表的长度。但是我们会增加一条额外的线。这重要吗?好吧,如果我们遵循的原则是编写清晰简洁的代码,那么这很重要。因为受原则指导的人——在特定情况下指导他们如何行动的规则——以及从这些原则中看到好结果的人,他们是快乐的人。
成为一名优秀的编码员就是成为一名坚持编写简洁、高效、干净的代码并相信这一点的编码员。他们喜欢无需滚动就能适应屏幕的功能。
我们可以认为,变量的定义和它的使用都与这种语法保持在一起。团结无疑是一件非常好的事情,不是吗?内容和形式的结合。但是暂且把诡辩放在一边,我们也在避免一个变量被移动或分配到其他地方的错误和挫折。小 m 代表小优势。但是等等——在程序的生命中,我们不都已经到达了这样一个阶段吗?代码变得如此混乱,以至于我们无法正视混乱的源文件中的光标,更不用说引入变化或发现潜伏在某处的问题了。你当然有。这是一个愚蠢的作业错误(通常)。如果你和我一样是半个代码折叠牛仔,我肯定你会看到简洁代码的悲剧魔力。这就是“海象”,也就是`:= '操作符固定在语法中的东西,以便重新呼吸到 IDE 中——称之为代码的 KonMari 整洁——对我们的精神健康有相当大的好处。
好吧,我会——重构这简洁的一行有点困难。但是作为程序员,我们写代码来表达意图。这可能是我们的意图,或者是计算类的意图,但问题是我们如何让它浮在外面。即使它是最终的效果,我们代码的结果和影响,在开发的后期“bug”和关注我们——它是我们描绘程序的代码行。其他工具,如儿童视觉编码和人工智能翻译可能会在这里或那里爆发。但是现在我们的代码是关于笔触的,最好的基础是简洁。
想要另一个巧克力的例子吗?
max([l for p in glob.glob(parent_dir + “*”) for l in p if style_1_name in p if l.isnumeric()])
这个小小的列表理解获得了包含最大数字的文件路径(我特别喜欢像这样的双列表和三列表理解的顽皮处理——但是有人能想出一个优雅的方法来扩展它以处理包含大于 9 的数字的文件路径吗)。紧凑、极薄的代码可能非常有效——几个像样的变量名可能会解决一些问题——但是紧凑的代码效果最好。为什么?除了不得不实际思考我们所写的东西,除了更有效率,它变成了一个疯狂有趣的游戏,使我们的代码整洁、紧凑和实用。
把这些想象成在概念上类似于一个小的数学证明。即使它们没那么难。编程回归我们曾经玩的游戏出于选择(为了好玩!).这些归结起来的线成为足够小的挑战,一天可以解决多次,奖励足够鼓励更多的实践。然而,与大多数成人游戏不同,这些游戏实际上是有目的的。结果是超级整洁的代码,本质上更容易返回和审查。但是这种剃刀式编码实践的“游戏”元素并不是一个可以嘲笑的次要或附带的好处。
我希望我在生活中早点发现,享受工作的人并不是那些注意力持续时间像国王一样长的人。更确切地说,他们是那些了解他们的东西的人,正是那些了解东西的人给了最终的程序爪子。当然,它仍然需要翅膀才能飞翔,但是除非我们给它爪子,否则它无法在第一个使用者面前存活。
一位嬉皮士朋友说,“它在 IDE 里排了很长的队”,这次我有幸做了监督。但是那又怎么样呢?“一长串的真理只是句法上的真理。像这样写我们的 listy 代码是完全合法的 Python:"
image_paths = [p for f in [glob.glob(f”{t}/*” if t[-1] != “/”else f”{t}*”) for t in directory_paths]
for p in f if p[-3:] == “jpg”or p[-3:] == “png”]
“一个两倍价格的 bargin 五个一米老 mucka 的价格”[1]。是我们用冗长的形式或紧凑而明快的耳语方式来定义演示。重要的是,我们被鼓励挤压更多,并保持纪律。那是音调代码。
我们的无限循环
为什么简洁对我们来说很重要?我们只是对更简洁的代码感到自豪——它让我们在工作中得到尊重,从而得到更多的尊重和关心……我们在工作中更快乐。相当多。这是一个反馈循环,它让我们更有动力去探索项目中新的和不舒服的领域,语言,领域。当然,有很多兔子洞——但是你我的文学朋友不是爱丽丝。你是你的公司和利益可以乞求、借用或窃取的最好的程序员。这表现在你的作品中。
[1]我实际上从未说过那一点。但是想到我做到了就很有趣
超学*是艰难掌握数据科学技能的极端方法
原文:https://towardsdatascience.com/ultralearning-is-the-extreme-approach-to-mastering-data-science-skills-the-hard-way-7019aeba7be4?source=collection_archive---------2-----------------------
这种硬核学*风格非常适合数据科学的艰巨性

查理·哈蒙德在 Unsplash 上的照片
所有数据科学家都同意的一点是,数据科学很难学。
但是,是什么让那些在 6 个月内学会数据科学的人的学*经历与那些旅程拖了多年的人的学*经历有所不同呢?
答案可能归结于他们使用的学*方法。
虽然那些在学*几个月后加入 FAANG 公司的人会说,是他们的奉献精神和不知疲倦的职业道德帮助他们学*了数据科学概念,但故事可能不仅仅是他们每周学* 80 小时。
事实上,许多成功的数据科学家可能使用超学*方法在短时间内有效地学*他们需要的一切。
什么是超学*?
超学*是由斯科特·扬开发的一种学*方法,通过自我导向的强化学*,在更短的时间内获得技能和知识。
超级学*和其他学*方法有什么不同?有证据表明这是可行的。
例如,Young 使用 Ultralearning 在一年内学*完了麻省理工大学本科计算机科学课程,这个过程通常需要四年才能完成。不仅如此,他还通过了所有相关的考试。
如果这还不够,他又做了一次,不过这一次,他的学*计划是一整年不说英语。杨和他的朋友瓦特·贾斯瓦尔在一年的时间里去了四个国家学*四种语言。虽然他们不能完美地完成一年不说英语的学*,但他们在西班牙语、葡萄牙语、汉语和韩语方面都达到了中等熟练水*。
超学*是一种不常*的策略,因为它使用积极的学*策略和高度自我导向的性质。
然而,当涉及到数据科学时,使用不寻常或非传统的学*策略可能是有利的。
谁应该学*?
值得注意的是,超学*并不适合每个人。
超学*不适合那些不愿意强迫自己先学*困难的东西的人。也不适合那些不喜欢自我导向学*的人。它也不适合那些对“涉猎”更感兴趣的人,涉猎是指偶尔学*一项技能,但并不打算如何变得更好的过程。简而言之,如果你学*数据科学的想法是被动地观看教程视频,而不弄脏自己的手和编写代码,那么 Ultralearning 不适合你。
另一方面,如果你有兴趣通过结果驱动的方法学*一些具体的东西,超学*可能适合你。如果你愿意排除干扰,专注于自己的弱点,并在你所做的事情没有产生你需要的结果时发挥创造力,超级学*是一种很好的学*方法。这种学*方法是沉浸式学*的精髓——一种让你快速掌握技能并最终精通的方法。简而言之,如果你不害怕做困难的事情,超级学*适合你。
Ultralearning 如何让数据科学学*体验受益?
正如我在最近一篇关于微学*的文章中提到的,数据科学的学*过程必须加快。
对数据科学专业人员的要求非常高,学*过程必须尽可能高效,否则,任何人都需要花费数年时间才能过渡到这个新兴领域。随着来自具有高等教育、训练营和在线证书背景的候选人的额外竞争,学*过程还必须保证技能掌握和应用方面的可测量的增长。
进入超级学*,一种保证成功的方法——如果正确遵循的话。有了超学*,你对自己的成功或失败负责。通过设计一个合适的超学*课程,你最终会通过快速完成初学者的困难部分而跃升到中级水*。
超级学*的 9 个核心原则。
杨概述了发展超学*策略的九个步骤:
1.元学*
元学*是为你的学*之旅奠定基础的东西。本质上,它是确定学*你想要的科目或技能的最有效和高效的方法的过程。
**这如何应用于学*数据科学:**说到数据科学的元学*,您需要做三件事:
- 将数据科学分解为其基本组成部分。
- 弄清楚你的最终目标是什么。
- 确定过去对其他学*数据科学的人有效的方法。
数据科学,从最基本的层面来说,是一门结合了数学和编程的学科。整个数据分析过程,人工智能,机器学*都是在基础数学和编程上展开的话题。
当涉及到确定你的最终目标时,你要选择一些具体的东西。无论你是想成为一名数据分析师,发展机器学*技能,还是只是完成你的第一次分析,你的最终目标都将帮助你建立你的学*课程。
一旦你将数据科学分解成基本的组成部分,并确定了你的最终目标,你就需要研究哪些方法对走上同样学*之路的其他人有效。“走向数据科学”和 Youtube 是寻找关于如何追求学*目标的证明和建议的两大资源。
2.焦点
专注是建立你集中注意力和排除干扰的能力。
这可以通过在你的时间表中安排专门的无分心超学*时间和使用学*技巧来实现,例如番茄工作法。为了减少分心,尝试在专用空间工作,将手机放在不同的房间,关闭通知,使用网站拦截器。
**这如何应用于学*数据科学:**从在你的时间表中安排一小时的专用超学*时间开始。然后,将这一小时分为工作时间和休息时间(例如,工作 50 分钟后休息 10 分钟)。这背后的想法是,通过将学*过程分成更小的块,可以更有效地吸收和理解信息。扬并不建议将工作时间分成少于 30 分钟的时间段,因为这不会促进超学*所需的专注。
3.直接
直接就是一头扎进去,学*你想变得擅长的东西。这意味着弄脏你的手,马上获得实践经验。
**这如何应用于学*数据科学:**说到学*数据科学,这意味着通过编写代码、手工完成线性回归和双变量分析来弄脏您的手,并开始您自己的数据科学项目。
直截了当可能会令人生畏和不知所措,尤其是当你感觉一下子要学的东西太多的时候。然而,通过将应用程序分解成单独的部分,一次攻击一个部分可能更可行。
例如,为了第一次完成卡方检验,您需要将它分解为陈述无效假设和备选假设、确定卡方的临界值、计算卡方的预期/观察值,然后得出是否应该接受或拒绝无效假设的结论。一旦你把一个复杂的主题分解成各个部分,它就会变得简单得多。
4.钻头
“操练”是专注于提高你最弱技能的概念。不要逃避练*你不擅长的,你需要坚持不懈地练*,直到你变得优秀。
**这如何应用于学*数据科学:**首先创建一个你最弱技能的列表。从这里开始,将这些技能进一步分解成它们各自的部分。然后,开始练*这些单独的部分,直到你可以把它们放在一起,作为一个整体完成技能。
一个很好的例子就是数学实践。网上有数百个练*题,你可以一遍又一遍地完成,直到你对某个特定的数学概念熟悉到可以将其应用于数据分析或机器学*模型的程度。
5.检索
检索就是测试你自己,看看你是否学到了什么,并评估你的技能水*。
**这如何应用于学*数据科学:**测试你的数据科学知识的一个很好的方法是参加 Kaggle 比赛或完成黑客等级的编码挑战。通过强迫自己应用所学,你可以找出你基础中的任何知识缺口或弱点。关键是不要害怕犯错误,并从任何缺点中吸取教训。
6.反馈
反馈会让你在学*过程中和学*结束后成为一个更全面的人。通过寻求对你学*的反馈,你可以确定你是否在进步,哪些方面需要额外的帮助。
**这如何应用于学*数据科学:**谷歌、Stack Overflow、Kaggle、Reddit、Twitter 和 Medium 都是很好的*台,你可以在那里收到对你工作的反馈。Stack Overflow 是接收关于代码的帮助和反馈的完美地方,Reddit、Kaggle 和 Medium 是接收关于数据分析或概念理解的反馈的好地方。
7.保留
记忆就是确保你正在学*的东西能够记住它们。重要的是要意识到你忘记了什么,并想办法让它持续下去。
**这如何应用于学*数据科学:**数据科学是一门最好通过建立坚实基础来学*的学科。如果下面的基础结构不牢固,那么这些基础就不能一个接一个地建立起来。因此,在进入下一个话题之前,确保你在每个话题上都有坚实的基础。
8.直觉
直觉包括发展对主题的深刻理解。
**这如何应用于学*数据科学:**测试你是否对某个主题有深刻理解的一个好方法是尝试将它教给其他人。这可以通过使用费曼技术来完成。理查德·费曼发明了这种技术,因为他发现在为大学物理课创作一个讲座时,他无法在大学水*上解释这个话题。简而言之,如果你不能用最简单的术语解释一个概念,那你自己就没有理解它。
9.实验
实验就是通过探索你在舒适区之外学到的东西来拓展你的视野。这是通过尝试从不同角度解决问题和探索新的做事方法来实现的。
**这如何应用于学*数据科学:**数据科学总是可以通过蛮力来完成,这通常是在学*过程中发生的事情。然而,一旦你在各种数据科学领域变得有能力,现在是时候开始精炼和巧妙运用你的技能了。寻找更有效地解决问题的新方法,并尝试重构代码以使其更有效。现在是一个打破旧项目的好时机,看看如何用你新发现的专业知识把它们做得更好。这也是开始为开源项目做贡献或尝试将你的技能应用到现实生活问题中的好时机。
如何开发一个超学*项目?
Young 概述了开发超学*项目的三个步骤:
- 挑你想学的。
- 选择项目格式。
- 准备开始学*。
1.挑你想学的。
关键是选择一件你想深入、深入、快速学*的事情。
超学*项目一定要具体,否则就不行。因此,挑选一个特定的技能。说到数据科学,这可能是数据分析、数学、编程、机器学*、人工智能或更多。然而,由于数据科学是一个如此广阔的领域,最好将超学*项目集中在一个特定的事物上,如编码或数学。
Young 强调较短的项目需要更多的约束。换句话说,如果你的项目只持续一个月,那么你需要确保约束到位,以确保进展明显。例如,如果你打算花一个月的时间学*统计学,最好是集中精力学*线性回归的所有内容,而不是试图学*整个统计学领域。
最后,Young 还建议第一次超能工作者不要为他们的项目设定硬性的期限或目标。这是因为你会很快知道你的目标是否可行,如果你意识到你的项目在你选择的时间表内不可行,这可能会导致沮丧。更好的做法是开始你的学*项目,然后确定你的最后期限或目标应该是什么。
2.选择项目格式。
超学*项目有三种不同的格式:
- **全职项目:**全职项目就是那个——全职。成本高、强度大、速度快,如果你能每周花 40 小时学*,这些项目会很棒。
- **固定日程项目:**固定日程项目有你每周投入其中的具体时间。这些时间被安排在每周的同一时间。例如,你可以每天工作前花 1 小时学*,或者每天晚饭后花 2 小时学*。
- 固定时间项目。固定时间项目有一个固定的小时数,只要你在日程中找到时间,你就可以完成。
一旦选择了格式,您需要选择一个时间长度。Young 建议,如果你每周的时间投入很低,那么你的项目应该有一个更长的时间周期(比如 6-12 个月)或者缩小范围(一个更具体的项目重点)。
3.准备开始学*。
一个成功的超学*项目的诀窍是在学会准备之前花一些时间。
这包括:
- 研究你想学的技能
- 确定过去对其他人有效的方法
- 收集材料
- 研究不同的学*策略
- 安排你的时间
- 进行该计划的试点周。
Young 建议花费不少于项目长度 50%的时间进行准备。
最后的想法。
超学*是对数据科学严格性的完美补充——密集、自我导向和基于结果。
对于那些不怕一头扎进去,不怕艰难地做事的人来说,超学*可以利用自我问责和强化学*,在短时间内产生令人难以置信的结果。
对于那些希望进入数据科学作为职业改变的人来说,这可能只是一种不花费大量时间也不能保证结果的方式。
通过探索替代学*方法,通向数据科学的旅程对各种各样的人开放,包括那些没有特定行业背景的人。
至少可以说,超学*是极端的,但是极端的实践可以带来惊人的结果。为什么不看看 Ultralearning 能为您的数据科学之旅带来什么?
UMAP 降维——一种非常健壮的机器学*算法
原文:https://towardsdatascience.com/umap-dimensionality-reduction-an-incredibly-robust-machine-learning-algorithm-b5acb01de568?source=collection_archive---------2-----------------------
实践教程,机器学*
一致流形近似和投影(UMAP)如何工作,以及如何在 Python 中使用它

一致流形近似和投影(UMAP)。图片由作者提供。
介绍
降维不仅仅是为了数据可视化。它还可以通过识别高维空间中的关键结构并在低维嵌入中保存它们来帮助您克服“T4”维度诅咒。
本文将带您了解一种日益流行的降维技术均匀流形逼近和投影(UMAP) 的内部工作原理,并为您提供一个 Python 示例,可以在您从事数据科学项目时用作指南。
内容
- UMAP 在机器学*算法领域的地位
- 对 UMAP 工作原理的直观解释
- 在 Python 中使用 UMAP 的例子
机器学*算法领域中的一致流形逼近和投影(UMAP)
下面的旭日图是我对最常用的机器学*算法进行分类的尝试。我创建它是为了满足像你我这样的数据科学家的需求,让他们有一种更结构化、更直观的方式来识别各种算法如何组合在一起。
机器学*领域的这种特殊视图使我们能够看到算法之间的相似之处和不同之处,在为特定项目寻找合适的解决方案时,这可以作为快速指南。
该图是交互式的,所以请确保点击👇在不同的类别上对进行放大并揭示更多的。
机器学*算法分类。由作者创建的互动图表。
如果你喜欢数据科学和机器学* ,请 订阅 每当我发布一个新故事时,你都会收到一封电子邮件。
虽然 UMAP 最常用于无监督学*,但它也可以执行监督降维。您将在本文结尾的 Python 部分找到一个例子。
一致流形近似和投影(UMAP)是如何工作的?
解析 UMAP 的名字
让我们从剖析 UMAP 名字开始,这会给我们一个算法应该做什么的大概概念。
请注意,以下陈述不是官方定义,而是一组描述,有助于我们理解 UMAP 背后的关键思想。
- 投影 —通过将点投影到*面、曲面或直线上来再现空间物体的过程或技术。你也可以把它想象成一个物体从高维空间到低维空间的映射。
- 近似 —该算法假设我们只有有限的一组数据样本(点),而不是组成流形的整个集合。因此,我们需要根据可用的数据来近似流形。
- 流形 —流形是在每个点附近局部类似欧几里得空间的拓扑空间。一维流形包括直线和圆,但不包括 8 字形。二维流形(又称曲面)包括*面、球面、圆环面等等。
- 均匀 —均匀假设告诉我们,我们的数据样本均匀地(均匀地)分布在整个流形上。然而,在现实世界中,这种情况很少发生。因此,这个假设导致了这样一个概念,即流形上的距离是变化的。也就是说,空间本身是扭曲的:根据数据出现的稀疏或密集程度而拉伸或收缩。
综上所述,我们可以将 UMAP 描述为:
一种降维技术,假设可用数据样本均匀(均匀)分布在拓扑空间(流形)中,可以从这些有限数据样本中近似,并映射(投影)到一个更低维的空间。
上面对算法的描述可能会有所帮助,但对于 UMAP 是如何施展魔法的,它仍然是模糊的。因此,为了回答“如何做”的问题,让我们分析一下 UMAP 执行的各个步骤。
UMAP 执行的高级步骤
我们可以将 UMAP 分为两个主要步骤:
- 学*高维空间中的流形结构;
- 找到所述流形的低维表示。
然而,我们将把它分解成更小的部分,以加深对算法的理解。下面的地图显示了我们分析每一件作品的顺序。

UMAP 的步骤和组成部分——图片由作者提供。
步骤 1 —学*歧管结构
这并不奇怪,但在我们将数据映射到低维之前,我们首先需要弄清楚它在高维空间中是什么样子的。
1.1。寻找最近邻居
从使用董等人的最近邻居下降算法寻找最近邻居开始。您将在稍后的 Python 部分看到,我们可以通过调整 UMAP 的 n_neighbors 超参数来指定想要使用的最近邻数。
试验一下 n_neighbors 的数量很重要,因为它控制 UMAP 如何*衡数据中的局部与全局结构。它通过在试图学*流形结构时限制局部邻域的大小来实现。
从本质上来说, n_neighbors 的小值意味着我们想要一个非常局部的解释,精确地捕捉结构的细节。相比之下,一个大的 n_neighbors 值意味着我们的估计将基于更大的区域,从而更广泛地准确跨越整个流形。
1.2。接下来,UMAP 需要通过连接先前确定的最近邻居来构建一个图。为了理解这个过程,我们需要看几个子组件来解释邻域图是如何形成的。
1.2.1。变化的距离
正如对 UMAP 名字的分析中所概述的,我们假设点在流形上均匀分布,这表明它们之间的空间根据数据看起来更稀疏或更密集的地方而拉伸或收缩。
这实质上意味着距离度量在整个空间中不是通用的,相反,它在不同的区域之间是不同的。我们可以通过在每个数据点周围绘制圆/球来可视化它,由于不同的距离度量,这些圆/球看起来大小不同(*下图)。

局部连通性和模糊开集。图片来源: UMAP 文档。
1.2.2。局部连通性
接下来,我们要确保我们试图学*的流形结构不会导致许多不相连的点。幸运的是,我们可以使用另一个名为local _ connectivity(默认值= 1)的超参数来解决这个潜在的问题。
当我们设置 local_connectivity=1, 我们告诉算法,高维空间中的每一个点都与至少一个其他点相连。您可以在上图中看到每个实心圆是如何接触到至少一个数据点的。
1.2.3。模糊区域
你一定注意到了上面的插图也包含了延伸到最近邻居之外的模糊圆圈。这告诉我们,当我们远离兴趣点时,与其他点的联系的确定性会降低。
最简单的方法是将两个超参数(local _ connectivity和 n_neighbors )视为下限和上限:
- local_connectivity(默认值=1) —每个点都 100%确定连接到至少一个其他点(连接数量的下限)。
- n_neighbors(默认值= 15)-点直接连接到第 16 个以上邻居的可能性为 0%,因为它不在 UMAP 构建图表时使用的本地区域内。
- 邻居 2 至 15-某个点连接到其第 2 至第 15 个邻居有一定程度的确定性(> 0%但< 100%)。

邻里插画。图片由作者提供。
1.2.4。边的合并
最后,我们需要明白,上面讨论的连接确定性是通过边权重( w )来表示的。
由于我们采用了变化距离的方法,当从每个点的角度来看时,我们将不可避免地出现边缘权重不对齐的情况。例如,点 A→ B 的边权重将不同于 B→ A 的边权重

不一致的边权重。图片由作者提供。
UMAP 通过合并两条边克服了我们刚刚描述的边权重不一致的问题。以下是 UMAP 文件对此的解释:
如果我们想合并两条权重为 a 和 b 的不一致的边,那么我们应该有一条权重为𝑎+𝑏−𝑎⋅𝑏.的边思考这个问题的方式是,权重实际上是边(1-单纯形)存在的概率。然后,组合权重是至少一个边存在的概率。
最后,我们得到一个连通的邻域图,如下所示:

*具有组合边权重的图。*图片来源: UMAP 文档。
步骤 2——寻找低维表示
从高维空间学*了近似流形之后,UMAP 的下一步就是把它投射(映射)到一个低维空间。
2.1。最小距离 与第一步不同,我们不希望在低维空间表示中改变距离。相反,我们希望流形上的距离是相对于全局坐标系的标准欧几里得距离。
从可变距离到标准距离的转换也会影响到最近邻居的接近度。因此,我们必须通过另一个名为 min_dist (默认值=0.1) 的超参数来定义嵌入点之间的最小距离。
本质上,我们可以控制点的最小扩散,避免在低维嵌入中许多点相互重叠的情况。
2.2。最小化代价函数(交叉熵) 指定了最小距离,算法就可以开始寻找一个好的低维流形表示。UMAP 通过最小化以下成本函数来实现,也称为交叉熵(CE):

最小化交叉熵成本方程。图片由作者提供。
如你所*,最终目标是在低维表示中找到边的最佳权重。随着迭代随机梯度下降过程,上述交叉熵成本函数被最小化,这些最优权重出现。
就是这样!UMAP 的工作现在完成了,我们得到了一个数组,其中包含了指定的低维空间中每个数据点的坐标。


在 Python 中使用 UMAP
最后,我们可以使用新获得的 UMAP 知识在 Python 中进行降维。
我们将在 MNIST 数据集(手写数字的集合)上应用 UMAP 来说明我们如何成功地分离数字并在低维空间中显示它们。
设置
我们将使用以下数据和库:
- Scikit-learn libraryfor
1)MNIST 数字数据(load _ digits);
2)将数据拆分成训练样本和测试样本(train _ test _ split); - UMAP 库,用于执行降维;
- 用于数据可视化的 Plotly 和Matplotlib;
- 熊猫和 Numpy 进行数据操作。
第一步是导入我们上面列出的库。
接下来,我们加载 MNIST 数据并显示前十个手写数字的图像。

前十个手写数字的图像(8×8 = 64 像素,即 64 维)。图片由作者提供。
接下来,我们将创建一个绘制 3D 散点图的函数,我们可以多次重用该函数来显示 UMAP 降维的结果。
将 UMAP 应用于我们的数据
现在,我们将之前加载到数组 X 中的 MNIST 数字数据。X (1797,64)的形状告诉我们,我们有 1,797 个数字,每个数字由 64 个维度组成。
我们将使用 UMAP 把维数从 64 降低到 3。请注意,我已经列出了 UMAP 所有可用的超参数,并简要说明了它们的功能。
虽然在本例中,我将大多数超参数设置为默认值,但我鼓励您尝试使用它们,看看它们如何影响结果。
上面的代码将 UMAP 应用于我们的 MNIST 数据,并打印出转换后的数组的形状,以确认我们已经成功地将维数从 64 减少到 3。

新转换数组的形状。图片由作者提供。
我们现在可以使用之前创建的图表绘图功能来可视化我们的三维数字数据。我们用一行简单的代码调用该函数,传递我们想要可视化的数组。
chart(X_trans, y)
无监督 UMAP 降维的结果。图表作者作者。
结果看起来很棒,数字簇之间有清晰的分离。有趣的是,数字 1 形成了三个不同的簇,这可以用人们书写数字 1 的不同方式来解释:

数字 1 的不同写法。图片由作者提供。
请注意,在底部用一个碱基书写 1 是如何让它看起来像数字 2 的。我们可以在一个由 1 组成的红色小簇中找到这些案例,这个小簇非常靠近由 2 组成的绿色簇。
监督 UMAP
正如本文开头提到的,我们还可以在监督下使用 UMAP 来帮助降低数据的维度。
在执行监督降维时,除了图像数据(X_train 数组),我们还需要将标签数据(y_train 数组)传递到一个fit _ transform方法中(参*下面的代码)。
此外,我想让您注意到我对超参数做了一些其他的小改动,设置 min_dist=0.5 和local _ connectivity = 2以获得更好的可视化效果和测试样本的更好结果。

转换后的训练和测试数组的形状。图片作者。
既然我们已经使用监督 UMAP 方法成功地降低了维度,我们可以绘制 3D 散点图来显示结果。
chart(X_train_res, y_train)
监督 UMAP 降维结果— 训练数据。图表作者作者。
我们可以看到,UMAP 已经形成了非常紧密的每一个相隔相当远的数字集群。
我们现在为测试数据创建相同的 3D 图形,看看 UMAP 是否能成功地将新数据点放入这些簇中。
chart(X_test_res, y_test)
监督 UMAP 降维结果— **测试数据。**图表作者作者。
正如您所看到的,结果相当不错,只有少数数字出现在错误的簇中。特别是,它看起来像算法与数字 3 斗争,有几个例子位于 7,8 和 5 的旁边。
结论
感谢您阅读这篇长文,我希望其中的每一部分都让您对这个伟大的算法是如何运行的有了更多的了解。
总的来说,UMAP 有着坚实的数学基础,它往往能比 t-SNE 等类似的降维算法做得更好。
秘密在于 UMAP 能够推断出局部和全局结构,同时保持低维空间中的相对全局距离。这些能力使我们能够开启特定的洞察力,例如发现数字 1 和 2 的手写形式之间的相似之处。
欢迎大家分享自己的想法和反馈,有助于我以后写出更好的文章。
干杯👏
索尔·多比拉斯
如果你已经花光了这个月的学*预算,下次请记得我。 我的个性化链接加入媒介是:
https://solclover.com/membership
您可能感兴趣的其他文章:
找不到数据科学的工作?原因如下。
原文:https://towardsdatascience.com/unable-to-land-a-data-science-job-heres-why-399f6d063abe?source=collection_archive---------6-----------------------
你接受了错误的建议。

蒂姆·高在 Unsplash 上拍摄的照片
我有心理学学位。我想从事数据科学,所以我参加了一个训练营。几个月来,我一直试图找到一份数据科学的工作,但没有成功。我要么得不到任何回应,要么公司告诉我,我没有他们想要的那种经验。
人们经常向我寻求数据科学方面的建议,这是我收到的最常*的消息之一。来自不同背景的个人试图进入数据科学领域,但无法在该行业找到工作。
他们问我一些问题,比如硕士学位是否会增加他们在这个行业找到工作的机会,或者是否有任何他们可以学*的特定课程会让他们的简历看起来更好。
在这篇文章中,我将提供我的*解,为什么这些人可能很难找到一份数据科学的工作。围绕数据行业有许多误解,我想在本文中澄清其中一些。
不久前,有人向我传达了如上所述的类似信息。这个人参加了一个训练营,已经申请了几个月的数据科学职位。他们的申请要么被拒绝,要么被忽视,他们无法进入面试阶段。
我看了一下他们的简历,马上意识到了问题。
他们所接受的唯一相关数据科学教育是他们的训练营证书。他们的简历上确实列出了多个数据科学项目,但我一眼就能看出,所有这些项目都是在他们的训练营期间完成的。
看了他们的简历后,我给了这个人以下几点建议:
- 你需要明白,你是在和硕士毕业生竞争同一个初级职位。训练营或在线课程的证书不足以做到这一点。
- 你简历中的 技能 部分不具备作为数据科学家所需的技能。你主要列出了机器学* Python 包和可视化工具,看起来所有这些东西也在训练营教授过。
- 简历中的 项目 部分只包括你在训练营期间完成的项目。招聘人员会知道这一点,尤其是如果同一个训练营的所有毕业生都列出了类似的项目。
理论上,这个人做的一切都是对的。他们参加了一个训练营,学*如何编码,甚至应用他们所学的一切来构建项目。
然而,这还不够。
即使是硕士毕业生,他们的知识也有差距。
是什么让人们认为训练营或在线课程足以成为一名数据科学家?
问题在于:
人们经常低估成为数据科学家所需的努力。
我从未*过像数据科学这样被大肆宣传的领域。
问题在于训练营和在线课程,它们承诺在未来几个月内让你成为一名数据科学家。问题出在数据科学博客和 YouTubers 上,他们不断编造故事,讲述自己如何轻而易举地找到了一份数据科学工作,让人们觉得你也可以不费吹灰之力就找到工作。
T2 有可能在六个月或一年内找到一份数据科学的工作。以前有人做过。但是绝对不容易。如果你想在没有任何正式训练的情况下做到这一点,那么准备好投入至少三倍的工作。
关于在数据科学领域找到工作,有两种最流行的说法:
- 第一种是看门人,他们坚信要成为一名数据科学家,你需要有很强的学术基础或者至少是一个博士学位。
- 第二种是教育工作者,他们坚持认为,只要参加在线课程或训练营,任何人都可以成为数据科学家。
这两个都不是真的。答案在中间的某个地方。
拥有硕士学位或某种正式的数据科学培训是很好的,但不是每个人都有特权或时间这样做。如果是这样的话,那么自学数据科学是有可能的。但不是通过一个训练营或在线课程。
数据科学不是一个有预定义路径的领域。没有一套固定的主题供你学*,因为这个领域是不断变化的。数据科学家的工作范围包含不同的职责。因此,没有固定的课程或训练营可以让你成为数据科学家。你需要不断地自己学*,学*永无止境。
你需要主动学*这些东西。建立你认为有助于解决公司问题的项目。学*不止一门编程语言,一些模型部署,数据收集,云计算,机器学*,然后你就在成为数据科学家的路上了。
当然,一般化和专门化的数据科学家之间是有区别的,但是现在大多数数据科学工作都要求你对我上面列出的所有东西都有所了解。
即使你还不具备所有这些技能,你至少需要向潜在的员工展示你有能力和技术深度在工作中学*这些东西。
我给那些联系我的人的最后一条建议是将他们的注意力从数据科学上转移。
这个人在有限的时间内找到一份工作,并需要尽快找到一份,不幸的是,大多数人都是这样。
我注意到这个人有市场营销的背景,简历里有写。
相反,我建议他们申请市场分析师、数据分析师或顾问的职位。
他们从训练营学到的东西中获得了一些技术背景,并且在市场营销领域工作了一段时间。他们拥有对自己有利的领域专长和技术知识。
我遇到的大多数数据分析师都非常擅长处理数据,但由于缺乏营销专业知识,他们在获取商业价值方面表现不佳。
我向这个人建议,如果他们很快需要一份工作,他们可以从分析师做起。他们将从日常数据工作中学到很多东西,并可以继续学*数据科学。
我认识许多人,他们一开始是分析师或数据工程师,随着时间的推移,他们开始转向数据科学。
结论
我以前写过一些文章,讲述了获得数据科学工作并不一定要有硕士学位,以及没有正式资格如何进入这个行业。
虽然我仍然袖手旁观这一点,我相信这些文章可能也起到了淡化成为一名数据科学家所需努力的作用。我可能说得太简单了。
在任何学科达到一定的专业水*都需要时间和努力。数据科学也不例外。没有特定的课程或训练营可以让你为数据科学工作做好充分准备。
同样,数据科学课程非常有帮助,但它们只帮助奠定基础。繁重的工作需要你来做。
在过去的一年里,我花时间学*了统计学基础、机器学*、数据收集、web 开发、编程、数据库操作、模型部署和业务分析。我目前正在努力成为谷歌云数据工程师认证,尽管我们在我的工作场所不使用 GCP。
这是一项艰巨的任务,我学到的东西比训练营能提供的要多得多。
如果您是数据行业的初学者,这篇文章并不是要吓唬您或打击您的积极性。围绕数据科学有太多的误解,而这个行业如今已经变得高度商业化。
在线课程和训练营有助于你开始学*,但学*不会就此结束。
数据项目中的拆箱创新
原文:https://towardsdatascience.com/unboxing-innovation-in-data-projects-3f8220618b1a?source=collection_archive---------49-----------------------
了解数据职业中的创新工作流程

来源: Unsplash
问题陈述
我有一个用图网络的想法。我如何测试和推出这个想法?
数据项目创新的正确步骤是什么?
几周前,,我谈到了构建原型以使你的项目获得成功。
原型将测试、说服并引导你的数据项目开花结果。 —文森特·塔坦
虽然这确实能带来项目的成功,但这还不够。你仍然需要推出你的想法来产生真正的影响。
但是不要担心…在这篇文章中,我保证给你完整的画面,缩小原型阶段,专注于创新工作流程来启动你的项目。这是基于我自己的个人经验,将有助于管理和收集支持你的实验启动。

实话实说(由作者在 memegenerator 生成)
数据创新工作流程

作者的灵感创新工作流程(来源于作者)
根据我的经验,创新有三个阶段:
- 概念化:制定问题陈述和计划,确保你不会在失败的实验上投入太多时间。
- **实验:**原型实验以获得反馈和认可,从而产生新的想法并进行优先排序。
- **生产:**在相关利益相关方的大力支持下,启动 ML 应用。
让我们一个一个深入挖掘!
概念化

我为 Yayasan Merajut Hati 创建的设计文档样本(来源于作者)
设计文档提供 概念灯塔来指导你的数据项目 。你应该在一开始就用这个来清楚地表达你的问题。
你为什么需要设计文档?因为好处是多方面的。
设计文档从概念上指导 你在每一个步骤中理解你的目标、影响和执行,以使利益相关者受益。在执行之前,设计来突出实现和替代解决方案可以节省你的时间。它主持团队之间的讨论以集思广益出最佳解决方案,而作为永久的工件来巩固你对未来合作的想法。
这里有一些关于如何开始的简单结构
- **目标:**你为什么要建这个?
- **最低可行产品:**对你的受众来说,什么是重要的?
- **研究和探索:**有什么时间和资源可以利用?
- **里程碑和成果:**能够实现什么,已经实现了什么?
- **TL:DR(太久没看):**有什么总结?
拥有初步设计文档将突出当前的检测差距,并在着手解决之前集思广益寻找潜在的解决方案。
实验
1)原型制作

为 Yayasan Merajut Hati(心理健康组织)创建的原型(来源于作者)
使用设计文档,如果某种方法可行,我们就创建原型进行反复试验。 开发一个原型有很多种方法,但是让我和你们分享其中的几种:
Web dashboard(最简单):你可以设计快速的数据片段和实验,然后将结果存储到 Google Big Query 中。之后,你可以免费使用 Google Data Studio 快速查询和显示*解。
Web 应用:您可以进一步使用 Heroku 快速部署您的原型。 Heroku 是一个广泛使用的商业软件*台(PaaS ),它使数据专业人员能够更轻松地构建、管理和部署各种规模的应用程序。这意味着您现在可以专注于开发分析应用程序,而无需担心部署基础架构。Heroku 为您处理所有部署的繁重工作!
所有原型都可以更快地交付,因为您可以复制和修改您的前端代码和部署步骤。
2)获得反馈并签字确认
获得高级开发人员/技术领导的认可至关重要。这为你的同事建立了合作的信心。
这可以通过回答以下检查问题来完成:
- **价值:**我正在解决我陈述的问题吗?
- **有效性:**所有的假设和评价都是基于证据吗?
- 错综复杂:它如何与上游/下游应用程序对话?
- 清晰:所有信息都是用 KISS 写的吗(保持简洁明了)?
- **支持:**启动该应用程序需要什么支持?
在大多数情况下,您将需要迭代您的原型和问题公式,直到您得到您需要进一步优先考虑最小可行产品(MVP)的信号。
3)优先级
如果一个经过验证的原型给你的利益相关者带来了承诺和巨大的好处(例如:一个高效的图像检测系统),那么我们希望分配更多的资源,如时间和人力。
不幸的是,在现实生活中,时间和人力是有限的。在某些情况下,你会发现自己在做 2 个、3 个甚至更多的项目。因此,您需要向您的利益相关者传达以下优先化练*:
- 这个解决方案如何放在我的 OKRs(客观关键结果)中?
- 我应该为这个项目分配多少时间(人力)?
- 表示成功的最小可行产品(MVP)是什么?
如果出现其他数据项目,拥有一份可靠的优先级文档将有助于您维护您需要的优先级和资源。
生产

使用任务调度程序运行 Web 抓取脚本,然后将其附加到 SQLite 磁盘(由作者提供)
一旦优先级文档被批准。您将有专门的时间和支持来将您的实验结果投入生产。
最简单的工作是用 Windows 任务调度器启动一个小规模的基于 python 的自动化工作流。这有助于您管理任务,以响应基于事件或基于时间的触发。例如,您可以建议某次点击和计算机操作(如重新启动),甚至建议像每季度第一天的这样的时间来执行任务。
但是如果要部署可扩展的 ML 项目。你需要使用 ML Operations (ML Ops)来维护、监控和管理你预想的影响。谷歌经常使用 TFX 来启动、操作和审计人工智能模型。
不要忘记评估你发布的结果,并链接回你的问题公式。这将成为你的创新成功记录,并为你将来获得更好的职业机会做好准备。
启动您的创新,实现真正的价值。
结论:创新带来真正的影响
重要的是通过以下方式实现您的想法并传递共享的影响以推进您的职业发展:
- 概念化:制定问题陈述和计划,确保你不会在失败的实验上投入太多时间。
- **实验:**原型实验以获得反馈和认可,从而产生新的想法并进行优先排序。
- **生产:**在相关利益相关方的大力支持下,启动 ML 应用程序。
我希望这能帮助你更好地理解数据职业中的创新。
索利·德奥·格洛丽亚
关于作者
文森特用 ML @ Google 对抗网络滥用。文森特使用高级数据分析、机器学*和软件工程来保护 Chrome 和 Gmail 用户。
除了在谷歌的工作,文森特还是乔治亚理工学院计算机科学硕士校友、三项全能运动员和面向数据科学媒体的特约作家,该杂志在全球拥有 100 多万观众,为有志于数据科学的人和数据从业者提供指导。
最后,请通过LinkedIn、Medium或 Youtube 频道 联系文森特
用石灰打开黑匣子
原文:https://towardsdatascience.com/unboxing-the-black-box-using-lime-5c9756366faf?source=collection_archive---------23-----------------------
利用新冠肺炎数据了解石灰的内部结构

压榨石灰(资料来源:Unsplash)
可解释的人工智能(XAI)
随着模型复杂性的增加,其准确性会增加,但可解释性会降低。大多数复杂的数学机器学*模型不容易解释,并且作为黑箱运行,很难解释某些预测背后的原因。
可解释的人工智能(XAI)是指帮助理解和解释机器学*模型所做预测的方法和技术。
可解释的人工智能框架的应用使企业能够以“白盒”方式应用更健壮和复杂的解决方案。
可解释的人工智能提供了一个事后预测的理由。
什么是石灰?
LIME 代表局部可解释的模型不可知解释,可以描述如下。

LIME 是一种帮助解释个人预测的可视化技术。它是模型不可知的,因此它可以应用于任何监督回归或分类模型。LIME 是由马尔科·图利奥·里贝罗、萨梅尔·辛格和卡洛斯·盖斯特林在 2016 年提出的。
在 LIME 的工作原理背后,隐藏着一个假设:每一个复杂的模型在局部尺度上都是线性的。LIME 试图围绕单个观察值拟合一个简单的模型,该模型将模拟全球模型在该地区的行为。然后,简单模型可以用来解释更复杂模型的局部预测。

**举例说明石灰的直觉。**来源:https://arxiv.org/pdf/1602.04938.pdf
在上面关于石灰的论文的例子中,暗红色的十字代表要解释的观察结果。LIME 对实例进行采样,使用预测器获得预测,并通过与被解释的实例的接近程度(这里用大小表示)对它们进行加权。虚线是局部(而非全局)可信的学*解释。
LIME 支持三种类型的输入格式,表格数据、文本数据和图像数据。在本文中,我们将探索 LIME 支持的表格数据格式。
了解 LIME 算法
在高层次上,以下步骤是作为 LIME 算法的一部分来执行的。稍后,我们将通过案例研究中的一个示例详细介绍这些步骤。
- 创建扰动的数据
- 预测扰动数据的输出
- 创建离散化要素
- 求扰动数据到原始观测值的欧几里德距离
- 将距离转换为相似性得分
- 选择模型的前 n 个特征
- 创建一个线性模型并解释预测

石灰算法—流程(图片由作者提供)
案例研究—预测患者是否会康复
我们将使用新冠肺炎数据集来说明 LIME 如何在内部创建对观察结果的解释。
问题陈述
本案例研究的目标是使用患者的详细信息,如年龄、性别、症状,并预测患者是否会康复。
数据
所使用的数据可以在这个 Github 仓库中获得。该数据包含新冠肺炎病毒检测呈阳性的患者的详细信息,以及他们的人口统计信息、年龄、性别、症状和结果。
利用这些数据,我们将建立一个模型,在给定患者的年龄、性别和症状的情况下,该模型可以预测患者康复的可能性。一旦模型建立,我们将使用石灰来解释为什么模型做出了特定的预测。
本文中使用的数据集和代码可以在文章结尾提到的 git repo 中访问。
数据预处理
下载的数据集有 2676311 个数据点和 33 个特征。听起来很庞大,但做基本的分析表明,它有很多缺失的数据。14 个特征有超过 90%的数据缺失,21 个特征有超过 50%的数据缺失。
由于目标是使用年龄、性别、症状等特征来预测患者康复的可能性,因此必须对包含这些信息的数据行进行过滤。过滤数据后,最终行数减少到 215 行。
数据中缺少许多功能,如坐标、管理区域、日期信息,也不是本案例研究所必需的。在删除这些特性后,最终所需的特性集减少到了 6 个。

样本数据(图片由作者提供)
为“症状”创建特征
每个病人的症状被描述为一个自由文本。对于有多种症状的患者,条目以逗号分隔。基于症状中的关键字,为每个症状创建了标志。

症状标志示例(图片由作者提供)
创建目标变量
该数据集包含新冠肺炎病毒检测呈阳性的患者的详细信息。数据集有一个不同状态的结果列,如“出院”、“危急情况”、“稳定”、“死亡”等。对于本案例研究,我们将创建一个目标列“recovered”,如果结果为以下之一,该列将为 0:“dead”、“dead”、“death”、“dead”。在所有其他情况下,假设患者已经康复,目标将设置为 1。

根据结果创建目标(图片由作者提供)
创建虚拟变量
为性别、旅行史、慢性病等分类列创建虚拟变量。
探索数据

目标变量的分布(图片由作者提供)

基于年龄组的康复患者百分比(图片由作者提供)
年龄正在影响目标变量。随着年龄的增长,从新冠肺炎病中康复的患者比例逐渐降低。

根据性别、慢性病标记和肺炎标记恢复的患者(图片由作者提供)
从这张图表来看,似乎性别在决定最终目标时并没有起多大作用。但慢性病和肺炎等变量似乎对目标有更大的影响。患有慢性疾病或肺炎的患者康复的机会较低。
当用相关矩阵检查时,可以对这些变量做出类似的推论。

与恢复的旗帜的相关矩阵(图片由作者提供)
这里显示了基本的探索性数据分析。有关更详细的 EDA,请参考 git repo 中的笔记本文件。
列车测试分离
预处理后的最终数据有 215 个病人的详细资料,包括 15 个特征(包括目标变量)。分层分割以 70:30 的训练-测试比率应用于该数据。

训练测试分割后的输入数据(图片由作者提供)
训练一个模型——随机森林分类器
下一步是在训练数据集上训练模型,并针对测试数据集运行它。这里我们使用了随机森林分类器。将它与测试数据进行比较,得到了 78%的 R2 分数。
训练随机森林分类器
解释预测——石灰
现在,我们已经清理了数据,训练了模型,并对测试数据进行了预测,我们已经到达了本文的核心,即解释模型所做的预测。
LIME 是模型不可知的,下面解释的算法的方法和内部工作对于其他模型也是相同的。
1.为表格数据创建时间解释器
2.解释一个特殊的预测
示例 1—观察结果 1

示例 1:观察值 1 的石灰输出(实际值= 0,预测值= 0) —图片由作者提供
LIME 围绕要解释的观察结果创建了一个局部替代模型,并使用该模型的系数来识别最具影响的特征,由于这些特征,已经做出了特定的预测。
观察上述结果,很明显,该模型根据年龄和其他症状(如肺炎、慢性病)预测了患者可能无法康复。尽管患者没有呼吸问题,其具有正系数,但是其他负系数超过这些,因此模型预测恢复标志为 0。
示例 2 —观察结果 3

示例 2:观察 1 的石灰输出(实际= 1,预测= 1) —作者提供的图片
例 2 是模型预测值为 1,真实值也为 1 的情况。如结果所示,该模型已经基于患者的年龄(年轻患者更有可能康复并且对康复的标志具有积极影响)做出了预测,该患者没有肺炎或呼吸问题,或者慢性疾病。因此,患者更有可能康复,并且模型已经基于这些变量做出了预测。
从上面的两个例子可以看出,查看 LIME 的结果可以让我们更容易地解释模型做出的预测,并以人类可以理解的格式向他人解释它们。
解码 LIME 算法
如前所述,LIME 算法中执行了 7 个关键步骤。
在这一节中,我们将深入 LIME 算法的内部,以理解它是如何得出如上所示的最终解释的。我们将观察值 1 作为例子来理解这个流程。
- 创建扰动的数据
- 预测扰动数据的输出
- 创建离散化要素
- 求扰动数据到原始观测值的欧几里德距离
- 将距离转换为相似性得分
- 选择模型的前 n 个特征
- 创建一个线性模型并解释预测

步骤 1:创建扰动的数据
对于要解释的观测值,扰动(扰乱或扰乱)观测值 n 次,以创建具有轻微值修改的复制要素数据。这种受干扰的数据是围绕观察值创建的假数据,将被 LIME 用来建立局部线性模型。
要在扰动数据中创建的样本数量对于解释者来说是一个超参数,并且可以调整。默认值设置为 5000。
扰动数据的创建
- 对于分类变量,随机值是根据可能的类别值及其在训练数据集中的出现频率选取的。对于分类变量(数据),扰动数据的值为 0 或 1。如果类别与要解释的观察结果相同,则为 1,否则为 0。
- 对于连续变量,根据训练数据中的*均值和标准偏差,通过从正态(0,1)分布采样并执行*均值居中和缩放的逆操作来扰动数据
注:扰动数据的第一个条目将始终是输入观测值,其预测必须得到解释。

扰动数据样本(10 行,实际= 5000 行) —图片由作者提供
步骤 2:预测扰动数据的输出
LIME 使用模型的预测函数对扰动数据进行预测。这些预测用于训练由 LIME 建立的局部线性模型。

对扰动数据(10 行)进行预测的示例 —图片由作者提供
步骤 3:创建离散化特征
LIME 在内部将连续变量转换为离散变量,以便它们是人类可解释的格式。这是可配置的,默认情况下,连续变量是离散化的。LIME 支持以下 3 种类型的离散化器:四分位数(默认)、十分位数和熵。变量值的范围将因离散化器而异。

来自四分点离散化器的离散化要素-作者提供的图像
步骤 4:找出扰动数据的欧几里德距离
将扰动数据(本例中为 5000 个)中的每个数据点与原始数据点进行比较,并确定两个数据点之间的欧几里德距离。欧几里得距离将给出该点离原始观测值有多远的概念。较小的距离意味着数据点离观测值更近。
步骤 5:将距离转换为相似性得分
欧几里德距离被转换成介于 0 和 1 之间的相似性得分。点离观察点越近(欧几里德距离越小),相似性得分越高。远离观察的点将具有较小的相似性得分。在下面的示例中可以看到同样的情况。

欧几里得距离及其相似性得分的样本(10 行) —作者提供的图片
请注意,由于扰动数据中的第一个数据点是输入观测值本身,因此它的距离为 0(最接近观测值),相似性得分为 1(与观测值完全相同)。
步骤 6:为模型选择前 n 个特征
该模型可以用许多变量运行,我们可能只对影响预测的前 n 个特征感兴趣。这个 n 值可以在 LIME 解释器中进行调整。
LIME 支持标准的特征选择技术,如最高权重、前向选择和套索路径。以下是 lime 支持的功能选择选项。
- 最高权重-对包含所有要素的缩放数据运行岭回归,并挑选权重最高的前 n 个要素
- 正向选择 —迭代地将特征添加到模型中,并识别在山脊模型上给出最佳分数的特征。
- 套索路径-基于套索正则化路径选择要素
- 无 —考虑所有特征
- 自动 —如果 num_features (m) < = 6,则向前选择其他最高权重

根据最高权重选出的前 10 个特征(图片由作者提供)

选定的 10 个特征的扰动数据(图片由作者提供)
步骤 7:创建一个线性模型并解释预测
准备好所有输入数据后,LIME 现在可以创建可用于解释预测的本地线性模型。来自线性回归模型的系数或权重用于解释观察的局部行为。
选择线性回归模型
- 对局部线性模型的唯一要求是,它应该与加权输入一起工作,并且应该是可解释的
- 这里的权重是基于扰动观察到原始观察的距离计算的相似性得分。接近原始观察值的实例将具有较高的权重
- 默认情况下,岭回归用作可解释模型
- LIME 支持任何 sci-kit 学*模型,只要它将 model_regressor.coef_ 和“sample_weight”作为 model_regressor.fit()的参数

根据扰动数据训练的线性模型得出的解释 —图片由作者提供
如上图所示,LIME 的最终输出只是线性模型中要素的权重。权重为正的要素将目标推向 1,权重为负的要素将目标推向 0。此外,这种线性模型的特点是以人类可以理解的格式,使任何人都很容易解释为什么一个特定的预测已经由模型。
比较不同模型的解释
LIME 也可以用于模型之间的比较。例如,影响随机森林模型所做预测的特征可能不同于逻辑回归或决策树模型。

相同观测在不同模型上运行的石灰输出-图片由作者提供
上图显示了 3 个不同模型的 LIME 运行结果,这些模型在相同的数据上进行训练,并运行相同的测试观察。
从结果中可以看出,影响最大的特性因模型的算法而异。对于这个特定的观察,逻辑回归和随机森林给年龄赋予最高的权重,而年龄在决策树分类器中排名第三。
结论
LIME 不仅有助于模型创建者向其他利益相关者解释预测,而且有助于在模型开发期间调试和比较模型。
尽管 LIME 是模型不可知的,但它在某些情况下可能会失败。当 LIME 基于高斯分布在观察位置周围创建自己的样本数据时,可能会创建一些“不太可能”的数据点,模型已经学*了这些数据点。此外,如果决策边界过于非线性,线性模型可能无法很好地解释它。结果还取决于为扰动数据调整的数据点数和用于查找最近点的内核宽度。
总之,选择正确的参数,石灰应该给出良好的局部解释,但同时需要注意避免上述潜在的陷阱。
数据和代码参考
本案例研究中使用的数据集引用自此处。
参考 git repo 获取本文使用的数据和代码:新冠肺炎分类 XAI
来源/参考
- 论文:https://arxiv.org/abs/1602.04938
- 源代码:【https://github.com/marcotcr/lime】T2
- LIME 简介:https://compstat-lmu . github . io/IML _ methods _ limits/LIME . html
- 了解 lime:https://cran . r-project . org/web/packages/lime/vignettes/Understanding _ lime . html
深度估计的不确定性
原文:https://towardsdatascience.com/uncertainty-in-depth-estimation-c3f04f44f9?source=collection_archive---------14-----------------------
你对你预测的深度有把握吗?


来自 DDAD 数据集的数据。上图:图片。中:悬殊。底部:不确定性
那么我们为什么需要 AI 系统对不确定性建模呢?
这里有一些引语,可以让你在不钻研数学的情况下进行思考。
知道自己不知道,比认为自己知道并根据错误信息行动要好。
如果你没有观察/经历过新的信息,就不要理直气壮地给出预测!
借助心理学的直觉,让我们考虑两种情况:
- 当我们遇到新事物时,我们变得更加忧虑和保守。只有在我们熟悉了新的情况并收集了额外的信息后,我们才能获得信心。
- 只有在经历过类似的事情之后,我们才会对自己的行为和对世界的理解越来越有信心。当我们在熟悉的环境中看到不同的事物时,我们往往会更加警惕。例如,一个近视的人忘记戴眼镜或隐形眼镜,在街上就要加倍小心!
上述两个观察结果应该给我们以下启示:
- 当我们经历和重复这个动作时,我们获得了自信
- 我们明白,如果我们遇到新的情况,我们应该不那么确定
同样,我们希望赋予我们的人工智能系统这样的推理能力。在需要的时候更加规避风险。有能力评估一个情况,给我们一个连续的答案,而不是一个二元的答案。我们绝对不希望他们根据错误解读的信息做出决定,这可能会导致生死攸关的局面!
现在,从统计学和机器学*的角度来看。通过从概率的角度构建学*问题,可以从 ML 模型中捕获观察值。这包括 **MLE、MAP、贝叶斯推理、**的概念,它迫使模型预测它认为正确的值、期望值以及模型对其预测的确定程度、方差。一个理想的 ML 模型应该能够准确地捕捉所有场景的这两个信息。
然而,挑战是存在的,因为在许多情况下,方差并不总是能够正确预测。因此,使用概率方法推理不确定性的目的是:
- 阻止模型自信地预测它以前没有观察到的东西— 认知不确定性
- 即使观察到数据,固有的不明确、有噪声的数据应导致预测值及其相关的不确定性— 随机不确定性
在本文中,我们将讨论不确定性的用例,以及它如何具体应用于深度估计问题。然后,我们将经历某些类型的场景,在这些场景中,应该对不确定性进行推理,并对预测不确定性的相关研究方法进行概述。

不确定性的应用
不确定性估计在机器学*系统的各个领域中扮演着重要的角色。它可用于:
- 主动学*:不确定性或其互补熵可以成为从大海捞针中提取有用数据的有效技术
- 伪标签/自训练:只有模型对其预测有把握,才能通过预测标签获得更多的标注数据
- 识别有噪声的/看不*的/被破坏的数据:当遇到这些情况时,模型应该在其预测中更具防御性。黄的这篇论文展示了如何利用物理和数字操作来欺骗模型,产生错误的和高度确定的预测。因此,迫切需要调查 dnn 的可解释性和不确定性,以便能够在安全关键环境中信任它们
- 安全关键 ML 系统中的实时部署:从模型输出中识别故障模式,并随后决定适当的行动方案
深度估计中的应用
除了上面提到的以外,下面还会提到具体的使用案例。
飞行像素去除
不确定性估计在去除“飞行像素”方面是有效的。尤其是在深度不连续和远处物体的区域中。我们预计这个区域本质上是不明确的,如下面的视频和相关论文中所描述的。
自我监督培训
正如在之前的文章中所讨论的,亮度恒常性假设通常在非朗伯曲面、镜头眩光等区域不成立。当计算光度损失时,这将影响并错误地惩罚模型。在这项工作 DV3O,CVPR2020 中,建模不确定性改善了结果。

此外,来自 SFM 的 DV3O 和 SFM,ECCV2018 研究了学*方差的使用,该方差可用于通过抑制由学*不确定性捕获的噪声区域来分别改善视觉里程计和 SFM 的任务。
模型应该展示的行为类型
举几个本能的例子,我们预计我们的模型对以下情况的预测深度不太有信心:


更远的像素具有更高的不确定性。模拟任意高斯噪声扰动。
- 图像上有噪声、失真的伪影:这可能是由于成像传感器故障、刮伤镜头、外部剧烈的相机运动/扰动或环境(灰尘、天气)引起的。当无法在全球范围内收集足够的背景信息时,这一点变得更加突出
- 反射/透明物体:训练时模型拾取的东西可能不明确。是否估计透明/镜面或后面可*或被反射的物体的距离
- 物体边界和被遮挡区域,深度不连续
- 距离分辨率有限的摄像机较远的像素
深度估计中的建模不确定性
上述行为取决于两个显著的不确定性(任意的和认知的),并由 Kendall,NIPS 2017 引入计算机视觉任务。
任意不确定性
不确定性形式化为模型输出的概率分布
这是它在观察到的输入数据的不确定性。这种推导对于线性回归是常*的,线性回归的目标是最小化负对数似然。目标是在训练模型之后训练模型变得对任务有信心,并回归所有可能深度值的分布。
下面为您提供了最大似然估计的摘要。
- 目标是确定一组模型参数θ,其最佳地描述了在训练集>
Θ = argmax_Θ likelihood中的图像数据的条件下观察深度目标的可能性 likelihood = p(y0, y1, ..., yn | x0, x1, ..., xn; Θ)描述了在给定所有训练数据 X 的情况下观察所有深度目标的概率- 这个联合条件概率在数学上很难计算。上述等式可以通过 1 简化,假设独立采集图像并应用 I.I.D .假设。 2) 利用条件独立性的性质
- 那么总概率就是单独观察每幅图像的结果。(边际概率的乘积):
likelihood = p(y0|x0; Θ) * p(y1|x1; Θ) * ... * p(yn|xn; Θ)Θ = argmax_Θ ∏ p(y_i|x_i; Θ)
5.取可能性的对数。这不会改变它的 argmax,因为 log 是单调递增的。这方便地将乘积转换成总和,并留给我们以下目标函数
log Θ = argmax_Θ ∑ log p(y_i|x_i; Θ)Divide by n,log Θ = argmax_Θ 1/N ∑ log p(y_i|x_i; Θ)
6.通常,预测分布被建模为高斯分布N(f(x), σ**2),均值μ = f(x ),方差σ**2,f代表深度回归模型
取负对数,将高斯分布代入目标函数,求导,展开并简化方程。我们的损失函数变成:

负对数似然估计:损失函数
其中f(x_i) = predicted depth and σ**2 = predicted variance是从深度神经网络回归的。我们看到如果预测深度||y_i — f(x_i)||**2 = 0。那么损失仅优化正则项为 0。然而,如果||y_i — f(x_i)||**2 > 0,模型被迫增加方差,从而增加分母给出的不确定性。
在推断过程中,模型将预测具有最可能深度的相关方差σ**2的分布p(y_pred|x, Θ),而不是单个确定值。预测方差描述了我们对预测深度的确信程度。
任意不确定性的性质
- 经过训练的模型将能够检测在经过训练的数据分布内的有噪声的新数据点。
- 经过训练的模型将能够解决不确定性,这种不确定性对于不同的输入保持不变。例如恒定的随机噪声
- 为训练获取更多的数据并不能减少不确定性。例如,表示物体边界的像素本质上是模糊的。
自监督深度的任意不确定性
在自监督深度中,公式是相同的,除了||y_i — f(x_i)||**2 = ||target_I — pred_target_I||**2。pred_target_I通过从源图像中采样获得像素。
认知不确定性
不确定性形式化为模型参数的概率分布
现在,我们的目标不是预测产量的分布,而是将模型权重转化为分布。这可以通过贝叶斯推理来发挥作用,贝叶斯推理反映了在一个状态下模型参数的不确定程度。随机不确定性无法提供这一点,因为数据集是直接观察到的,因此不是随机的。
制定
- 我们首先从模型权重的先验信念
Prior开始。随着观察到新数据并做出预测Likelihood,我们通过贝叶斯规则更新我们对权重Posterior的信念
Posterior = (Likelihood * Prior) / Marginal Distribution over Θ**P(Θ|Y, X) = P(Y|X, Θ) * P(Θ) / P(Y|X)**# Marginalized out all possible value of Θ in the denominator**P(Θ|Y, X) = ∫ P(Y|X, Θ) * P(Θ) d(Θ)**
2.类似于 MLE,当考虑参数空间时,积分是难以处理的。相反,一个近似解通常就足够了:
**P(Θ|Y, X) = 1/M ∑ P(Y|X, Θ_i)**
3.其中我们考虑 M 个参数子集
存在 2 种主要的采样策略来逼近 M 组参数。
- 漏失抽样:蒙特卡罗漏失法是一种对 M 个独立模型进行抽样的流行方法。脱落层应用于中间的中间层。在测试时,进行 M 个推断,以模拟对 M 个不同的参数集进行采样,并将其*均
- 集合 :一个备选方案是在数据集的不同子集上训练模型的 M 个实例,并随机初始化权重。类似地,M 个推理是在推理时进行的
认知不确定性的性质
- 运行 M 个模型可能会很慢,并且目前没有直接的方法将随机性注入到模型的权重中
- 在推断过程中,能够捕获超出训练数据分布的新数据点
- 有更多的数据来涵盖新的情况将减少培训后的不确定性水*
研究领域
与求解深度本身相比,深度的不确定性估计受到的关注较少。尽管如此,自 Kendall 等人的工作以来,仍有一些值得一提的工作。
Casting as ordinal regression:除了从回归中提取不确定性,一些工作已经将 casting depth 作为一个顺序回归问题进行了关注。这是继 DORN、CVPR2018 和 ada bins 2020 的工作之后。这里,深度的连续范围被离散化成箱。

左:将深度离散到面元 s 中。右:自适应面元
一旦获得离散化深度值,就可以用标准 softmax 回归损失来代替学*。该模型预测 N 个面元上的每像素深度,并以 N 个面元上的概率分布的形式隐含地提取不确定性或置信度。
自监督深度估计:CVPR 波吉 2020 ,使用自监督框架评估多种方法对深度学*的影响。与 DV3O 类似,他们观察到了纯粹由深度和自我运动的多视图合成产生的各种假象。为了从视图合成中分离深度不确定性的学*,他们提出了一种两阶段方法。第一阶段是学*深度,随后使用师生/自学方法学在不确定的情况下学*深度。第二阶段的目标是让学生网络了解教师网络的分布,而没有人为因素。

来源
包装它
事实上,在人工智能系统中,充分考虑各种不确定性仍然是一个挑战。有一项正在进行的研究表明,对抗性攻击可能会误导模型,从而自信地预测错误的输出。另一个挑战是实时执行认知不确定性。

最大化我求职的不寻常策略
原文:https://towardsdatascience.com/uncommon-strategies-that-maximized-my-job-search-107c6f7107a1?source=collection_archive---------35-----------------------
对于第一次找工作和转换职业的人来说,我也是

Clem Onojeghuo 在 Unsplash 拍摄的照片
作为一个刚刚结束求职过程的人,我理解这有多么疯狂和令人沮丧。就我而言,我希望打入科技行业。但是,问题是我以前没有任何专业技术经验。因此,我参加了一个编码训练营的数据科学项目,获得了一些必要的经验。在他们的帮助下,我开始了数据科学家的新事业!(你可以在下面了解更多关于这个过程的信息):
完成训练营项目后,我学到了一些求职技巧,但这些技巧并没有得到应有的广泛关注。这些技术不是科技行业独有的,几乎可以应用于任何行业。希望你可以利用这些独特的技巧来开始你自己的职业生涯!
在这里注册一个中级会员,可以无限制地访问和支持像我这样的内容!在你的支持下,我赚了一小部分会费。谢谢!
简历和求职信
首先,我不得不提到这两样东西——简历和求职信。这可能是找工作需要的两个最重要的东西。我知道填写一份工作申请,然后在简历中附上你几秒钟前刚刚输入的信息是很烦人的。我一周大概做了几十次或者更多次。但是,关于简历和求职信,我能给你什么样的建议呢?

提示#1:可选=必需
很多时候,当你申请一份工作时,你会得到一个上传简历和求职信的区域。在本节中,多次提到可以选择是否包含它们。不管怎样, 永远要附上你的简历和求职信,即使上面写着可选 。
包括这些文件让你有机会从那些没有上传简历/求职信的申请者中脱颖而出。但是这些文档如何帮助你脱颖而出呢?嗯…
技巧 2:定制简历和求职信
这是你可以锻炼你的创造技能的地方。 让你的简历和求职信看起来独特、酷、专业 。让它从其他普通、统一的文档中脱颖而出。
据我所*,许多数据科学简历都非常千篇一律。为了让我的简历脱颖而出,我在网上查找了一些基于技术并且看起来很独特的简历模板。
这可能看起来很肤浅,但是拥有一份与众不同的简历和求职信可能有助于吸引招聘经理的眼球。只要确保简历和求职信的风格主题协调就可以了。
技巧 3:定制简历和求职信

斯科特·格雷厄姆在 Unsplash 上拍照
这可能是简历和求职信中最重要的一条— 让它们适合这份工作 。对于数据科学家来说,很多公司对他们的职责和技能要求都不一样。一份普通的简历和求职信,如果没有明确提到工作内容,可能会被忽视。以职位描述为指导,修改你的简历和求职信,让它显示出你是这个职位的最佳人选。
关于求职信,通常在写求职信的时候,你要描述你自己,技能,以及为什么你应该被录用。然而,一个替代的(和潜在的更有效的)方法是 写你将如何完成工作及其任务,而不是 。招聘经理已经从你的简历中了解了你和你的技能。那么为什么不描述一下你会如何做这份工作呢?
例如
对于数据科学职位,假设该职位要求您通过使用深度学*从时间序列数据集中预测股票价值。以下是两种解决这一问题的方法:
一个 。我在 Python 和深度学*方面有几年的经验,能够使用数据科学工具进行数据可视化。
BBT21。我将使用张量流和神经网络来预测股票价格,并使用 Pandas 和 Plotly 来组织和可视化数据,以便于访问。
现在选项 a 没有任何问题。但是,选项 B 可能对招聘经理更有吸引力,因为它通过提到具体的数据科学工具来描述你的技能组合在公司的应用。这可能会导致招聘经理和招聘人员更快地做出回应。
总而言之
确保你的简历和求职信准确地展现了你自己。不要害怕吹嘘你的成就。对你能做的事情有信心,并确保在你的简历和求职信中有所体现。
网络在线
发出求职申请后,你可能会认为你可以坐着等回复。但是你还可以做更多的事情。对我来说,网上有很多数据科学家,我可以和他们联系。

克里斯·蒙哥马利在 Unsplash 上的照片
下一步应该是 与你未来的同事和经理 建立关系网。你可以通过研究公司和寻找那些可能与你刚刚申请的职位有关的人来做到这一点。这似乎是一个令人生畏的过程,但它可能有助于让你的应用程序比*时更快地被浏览。
以下是一些可以帮助你开始的提示:
技巧 1:使用 LinkedIn 寻找联系人
如果你没有 LinkedIn 账户,我建议你创建一个。让它看起来真的很好,因为人们喜欢看到完整,干净的个人资料!
有了 LinkedIn, 你可以搜索你刚刚应聘的公司,然后搜索在那里工作的员工 。找到你潜在的同事和经理。此外,向他们的招聘人员伸出援手也无妨。
就我个人而言,我发现 LinkedIn 是发现资深数据科学家和像我这样的新人的一个很好的资源。我已经联系了这么多人,以至于我的 LinkedIn feed 充满了机器学*和人工智能。我的 feed 很快成为数据科学知识和新联系人的重要资源!
技巧 2:和你的联系人交谈
当你找到你想交往的人时,和他们联系。LinkedIn 允许你发送一个带有信息的连接请求,你可以用它来解释你是谁,你想要什么。
或者,您也可以在他们的个人资料中找到他们的电子邮件地址。一些联系人可能不会经常查看他们的个人资料,因此发送电子邮件可能是更好的方法。
一旦接通, 给他们发信息,礼貌地询问他们什么时候有空打个电话 。利用这次通话的机会,了解更多关于他们的信息,并分享一些关于你自己的信息。不要带着询问工作的期望去打电话。

当你和他们建立了良好关系后,询问你的工作申请或者工作推荐可能是合适的。然而,如果他们选择不这样做,也不要失望。打电话的目的是建立一种职业关系,而不是得到一份工作。
技巧#3:申请前建立关系网
有时候,专注于人际关系可能比发送求职申请更好。你与其他专业人士的对话可以让你被介绍给一位经理或另一家可以利用你的技能的公司 。
专业人士甚至会给你一个他们公司的推荐链接,你可以用它来申请他们的公司。推荐工作申请可能会比仅仅申请标准职位更快得到回复。
如果你最终和一位经理谈了话,你可能甚至没有申请就直接被叫去参加工作面试。或者他们可能认识另一家公司的人,帮你介绍他们。
根据我的经验,我能够接触到一些数据科学主管,他们给了我各种各样的建议。大多数情况下,我甚至不会提到工作,但如果我提到了,他们会给我介绍另一家公司或他们自己公司的联系人。
总的来说,这些结果可能比仅仅发送工作申请更好。
提示 4:跟踪你的联系人
如果你的联系人没有及时回复,不要担心,因为他们可能非常忙。 跟踪你的联系人以及你何时联系他们 非常有用。
我建议给联系人 3-5 天的时间来回复信息。如果他们到那时还没有回复,友好地跟进,说你仍然渴望与他们交谈。
如果第三次尝试后他们仍然没有回应,放弃交流,继续前进。重要的是要记住,如果一个联系人根本没有回应,不要往心里去。
综上
在找下一份工作时,人际关系网非常有用。很多人宁愿雇佣他们认识的人,也不愿雇佣陌生人。只要确保你有足够的沟通能力。
创建内容
如果有什么方法可以展示你的技能,那就想办法在网上展示。根据查看您内容的人,这可能会带来许多不同的机会。这里有几个选项可以帮助您开始:

技巧 1:在线写文章
如果你想要的职业可以通过写作展示出来, 那就在媒体上或者通过自己的博客 写一些文章。你所需要的只是一个互联网连接和一台笔记本电脑或手机。
通过我的数据科学文章,我能够获得几个招聘人员的注意,他们需要一个具有数据科学背景的技术作家。
技巧 2:为 YouTube 录制视频
也许你想要的不仅仅是写作,或者你喜欢视频编辑。然后,也许你可以为 YouTube 录制视频。 你可以利用这些视频恰当地展示你拥有的任何技能 。
就我个人而言,我看过许多专注于数据科学的视频。我认识一个 Python 程序员,他在视频中提到,由于他的视频,他们会收到 FAANG 公司的工作邀请。
你潜在的视频可能比写作更能代表你的技能。而且,它们甚至可能会带来工作机会。
技巧 3:创建播客
如果一个视频太多,而你更想让你的观众听——为什么不创建一个播客呢?
录制播客是分享你自己的想法、观点和知识的好方法 。讨论与你想要的职业相关的话题。让你的听众知道你对你的主题很了解。
技巧 4:在社交媒体上发帖促销
在社交媒体上发帖可以快速分享你的内容。如果你是摄影师,Instagram 可能对你的照片有好处。Twitter 可以很好地推广你的视频或文章。脸书也可以用来为你的内容创建页面。

无论如何, 社交媒体可以作为你自己内容 的一个很棒的营销工具。尽你所能推广你的内容。建立你的观众群,也许他们中的一个会给你一个工作机会!
总之
内容创作是求职中经常被遗忘的资产。很多时候,它也可以带来自我就业的机会,因为它可以非常有利可图。通常,你的内容会比简历或邮件中的陈述更好地展示你的技能。
结束语
我每天都按照上面的建议找工作。我写过文章。我上网了。我不断给联系人发信息,提到我的文章。最终,有人因为我的文章向我提供了一个数据科学家的职位!(如果你想知道,那篇文章是):
如果上面的策略中有一点我认为是最重要的,那就是 创造在线内容 。我的文章是我今天有工作的原因。我认为从你的内容中诞生的机会比你想象的更有优势。
我希望这些方法中至少有一种对你来说是新的,我祝你在求职中好运!
非常规的数据清理方法,以提高数据准确性
原文:https://towardsdatascience.com/unconventional-methods-for-data-cleaning-to-improve-data-accuracy-5d230c366459?source=collection_archive---------31-----------------------
创造性地对字符串值进行数据清理
迪格斯/魏会泽/魏/郑

照片由来自 Pexels 的 Markus Spiske 拍摄
数据分析正日益成为业务决策的核心部分,并推动着日常流程。问题不再是我们如何收集信息,而是我们用它做什么?对于进入数据驱动决策阶段的公司来说,可能会出现许多挑战。建立一个目标并为共同的问题做好准备对于获得有用和有益的结果是必不可少的。例如了解数据的关系和缺点,检查统一的区域,以及确定在简单或复杂模型之间进行决策的能力。本教程将提供一个指南,帮助您在分析大型数据集和初始化数据分析项目时进行批判性思考。如果你对数据分析知之甚少,对学*非传统的数据清理方法感兴趣,或者试图通过应用先进的技术来解决数据清理问题,本教程将变得非常方便。
数据分析的使用不再局限于财大气粗的大公司。它现在已经普及,59%的企业在某种程度上使用了分析。羽衣甘蓝
数据分析的时代已经到来。随着数据分析为许多大公司带来持续的成功,越来越多的工具变得可用,数据分析已经成为任何企业的必需品。 Deloitte 最近进行了一项调查,发现近一半的受访者(49%)声称数据分析是更好的决策能力的关键因素,近三分之二的受访者表示分析在推动业务战略方面发挥着重要作用。此外,数据分析对营销的影响正在上升,55%的受访者表示,他们的营销和销售团队在分析方面的投资仅次于财务运营。作为来自加州大学戴维斯分校的商业分析科学硕士【MSBA】学生,我们是这一趋势的前沿专家。凭借与全球投资研究领域领先的技术解决方案提供商 BlueMatrix 的一年实*经验,我们完成了几个分析项目,并学会了如何利用数据分析的力量。
BlueMatrix 的客户拥有丰富的数据,可以在决策过程中使用。BlueMatrix 参与了这个新的数据分析项目,以帮助他们从数据中获得新的*解。鉴于在进行任何类型的分析之前,干净的数据是“必须的”,公司应该寻求更有效的方法来加快这一过程,同时提高准确性,以便及时产生*解。我们利用相似性得分计算和机器学*的能力来自动化数据清理过程,这大大提高了数据质量,我们相信这些技术可以很容易地被像我们项目这样情况类似的公司采用。我们已经看到,越来越多的公司试图在改善工作流程方面发挥创造力和创新性,但他们不确定具体要做些什么来实现这一目标。在这种情况下,本教程中介绍的两个解决方案将引导您完成思考过程,并展示潜在用例的示例。
问题公式化
文本数据有时比数字数据更难处理。简单地删除重复或截断文本是不够的,还需要更复杂的方法。例如,一家公司可能希望了解购买其产品的客户和他们工作的公司是否有任何趋势。如果客户能够在字段中输入自定义文本,一个人可能会输入“ABC 公司”,另一个人可能会输入“ABC 公司”,还有一个人可能会简单地列出“ABC”(图 1)。识别这些定制条目并将其转换为统一标准可能是一项挑战。另一个可能出现的问题是,如果客户注册了多个配置文件,以利用新的客户促销。未能消除重复的客户将降低分析的准确性。使用更先进的数据清理方法的目的是提高数据的准确性,从而提高分析的准确性。

作者照片
方法 1:相似性评分定位重复记录
为什么使用相似性评分进行数据清洗
相似性得分是一个非常通用的工具。一般来说,相似性分数衡量在比较数据库的源中找到的文本的百分比。最流行的是,它被用来检测抄袭和建立数据分割的集群。虽然这可能是一种更复杂的方法,但它在数据清理过程中非常有用。例如,如果您的公司刚刚开始使用数据分析,并且有大量数据需要进行质量检查。您可能会找到重复的记录。在一些简单的情况下,精确的字符串匹配足以定位重复项。然而,尤其是最近,一些任务需要比 SQL 中的简单连接函数更多的功能。例如,如果您使用名称匹配两个不同表中的记录,如果名称的拼写或标点不同,则精确匹配不会考虑在内。此外,如果名称有前缀或后缀,或者有错别字,您将需要使用更复杂的方法,如相似性得分计算。
如何计算相似度得分
有几种不同的方法来计算字符串的相似性得分。它们通常都涉及确定两个字符串之间的距离,但是根据您的具体情况,一种方法可能比另一种更好。例如,Levenshtein-Distance 是最常*和最广泛使用的度量之一。然而,你会发现很难用一种系统的方式来解释结果,而且这种方法不能很好地识别模式。Jaro-Winkler 是另一种距离度量,它更适合于字符换位,拾取近似匹配,如“Kiera”和“Keira”或“Marc”和“Mark”,并将调整常*前缀的权重。实际上,最好是测试出几种不同的方法来找到解决问题的正确方法。在我们的例子中,python 包 FuzzyWuzzy 表现最好。
FuzzyWuzzy 方法使用模糊字符串匹配来识别模式。它还使用 Levenshtein-Distance 来计算序列之间的差异。 SeatGeek 开发了这个包,并提供了如何在你的电脑上安装 FuzzyWuzzy 的说明。这里的一个技巧是确保安装 python-Levenshtein 包,因为它通过将速度提高 4 到 10 倍,极大地提高了该过程的性能。为了解释 FuzzyWuzzy 的结果,您需要使用两个序列之间的相似性比率来获得相似性百分比。相似性百分比的分数为 100 表示两个序列之间完全匹配。分数越低,两个序列的差异越大。
pip install fuzzywuzzy
pip install fuzzywuzzy[speedup]#OR
pip install git+git://github.com/seatgeek/fuzzywuzz.git@0.18#egg=fuzzywuzzyfrom fuzzywuzzy import fuzz
from fuzzywuzzy import process fuzz.partial_ratio("Nicki Jonas", "Nicki Jones")
#Match = 91
在安装包和收集数据集之后,您就可以为自己的项目计算相似性得分了。
choices = ["Nick Jonas", "Nicki Jonas", "Nick Jerry Jonas", "Joe Jonas"]
process.extract("Nick Jonas", choices, limit=2)
计算相似度分数的技巧:
以下是使用 FuzzyWuzzy 软件包的一些提示。我们分享这些信息的目的是帮助您简化流程并避免潜在的错误。
**1。)确保您的输入数据尽可能准确 😗*
本质上,数据越干净,字符串匹配过程就越快。例如,去掉所有的前缀或后缀、任何职务头衔或任何不需要的符号。
**2。)设定阈值 😗*
对于您自己的业务问题,您应该选择一个阈值来对相似性得分进行分类。例如,如果您只想删除重复的记录并保留唯一的记录,则任何得分低于 100 的匹配都将被删除。但是,在其他情况下,您可能希望设置一个较低的阈值,以允许一些误报或漏报来弥补其他错误。例如,如果您正在比较电子邮件地址以查找相同的记录,则设置较低的阈值可能会更好,因为误报比漏报造成的伤害更小。
#Similarity Ratio
a = fuzz.ratio("Nick Jonas", "Nick Jerry Jonas")b = fuzz.ratio("Nick Jonas", "Nicki Jones")c = fuzz.ratio("Nick Jonas", "Joe Jonas")d = fuzz.ratio("Nick Jonas", "Nick Jonas")e = fuzz.ratio("Nick Jonas", "Kevin Jonas")lis = [a, b, c, d, e]print("Here is a list of similarity scores:"+ str(lis))passed = [number for number in lis if number >= 80]print("Here is a list of similarity scores that passed the threshold:" + str(passed))#Output of similarity scores: [77, 86, 83, 63, 100, 67]
#Output of similarity scores that passed the threshold: [86, 100]
**3。)选择一个比例 😗*
您可以使用四种比率方法。请务必查看文档中的样本,以了解每个比率的详细信息。
简单比:比较两个字符串的简单明了的方法。
fuzz.ratio("Nick Jonas", "Nicki Jones")
#Match = 86
部分比率:它建立在简单比率的基础上,并考虑到字符串中有多余的标点符号。
fuzz.partial_ratio("Nicki Jonas", "Nicki Jones")
#Match = 91
Token sort ratio :这种方法在字符串之间存在单词换位模式时非常有用。
fuzz.token_sort_ratio("Nick Jonas", "Nick Jerry Jonas")
#Match = 77
Token set ratio :当字符串中有重复元素时,这种方法很有用。
fuzz.token_set_ratio("Nick Jonas", "Nick Jerry Jonas")
#Match = 100
方法 2:预测缺失值-机器学*模型
为什么机器学*很有帮助
假设您正在管理一个客户信息数据库,您有如下表所示的信息。当客户注册您的产品时,他们会向您提供年龄和性别等个人信息。一些字段,例如感兴趣的区域,可以在注册时跳过,以便信息不是由所有客户填写的。

稍后,您计划构建一个模型来预测每个客户的交易可能性,并意识到利息列中大约有 15%的值丢失。由于填写列的“*均值”或“中值”没有意义,一个潜在的解决方案是将它们放入“未指定”类别,然后继续使用您的模型。然而,我们发现,如果模型精度高,使用机器学*模型来尝试将用户分类到可能的兴趣组可能是更好的方法。在这种情况下,有足够的信息来对每个用户的兴趣做出有根据的猜测。这可能会大大提高流失预测的准确性。
另一方面,我们建议从评估模型中的列开始。运行机器学*模型可能很耗时,因此应该首先检查信息。在应用这种方法之后,您的模型的性能可能不会有太大的变化,那么采用类似的方法将是一个更好的解决方案。
帮助你入门的几个步骤:
**1。)决定型号 😗*
如果你已经决定继续进行机器学*模型,我们建议你首先仔细看看你的模型的用例。模型什么时候用?多久一次?将在哪里实施?问这些问题可以引导你思考你的输入数据和你的能力。在我们的案例中,为了进行预测,我们需要考虑在您对客户的流失预测兴趣进行分类时可以获得哪些信息。
在决定使用哪个模型时,其他的考虑因素包括你需要多长时间做出决定,以及你对准确性的重视程度。例如,如果你想通过使用深度学*模型来提高结果的准确性,而不是使用树模型,那么评估模型之间的权衡就非常重要。与深度学*模型相比,树模型往往成本更低,需要的调整更少。另一方面,深度学*模型可能会表现得更好,但根据情况的不同,它们可能会有更高的开发成本。此外,该模型可能比树模型更难解释,如果没有正确调整,性能可能不会提高。就像 James Montantes 在他的文章中提到的,“在一个行业环境中,我们需要一个模型,能够为利益相关者赋予特性/变量以意义。这些利益相关者很可能是除了具有深度学*或机器学*知识的人以外的任何人。”。在开始构建模型之前,模型的用例、可用资源的数量以及成本和收益之间的最佳*衡都是需要考虑的事情。
2。)数据准备**
在这个阶段,您已经最终选择了要测试的模型,并将开始为它准备数据。除了典型的检查和步骤,我们建议您开始考虑模型的准确性。在监督学*的情况下,如果它对业务问题有意义,您是否应该考虑减少模型中的类别数量?在我们前面的例子中,如果有太多不同的兴趣类别,那么就很难做出合理的预测。在这种情况下,我们可以根据层次结构对兴趣进行分组。比如把音乐、电影和电视节目放在一个叫做娱乐的大类别下。在我们的实*项目中,我们将彼此相似的小子集分成更大的集合。这样做是为了减少不*衡数据的影响,并通过合理数量的类别来提高模型的预测能力。
3。)车型评价:
一旦建立了模型,最后一步是评估模型的性能。有几个常用的指标,如分类准确度、曲线下面积和 F1 值。互联网上有大量关于这些指标和使用案例的信息,因此我们想重点谈谈我们从自身经历中学到的两件事。
首先是处理缺失的信息。在前面的章节中,我们已经讨论了在构建模型时识别可用输入数据的重要性。我们建议在没有其中一个功能的情况下测试模型,以查看该信息缺失时的性能。例如,如上表所示,如果“公司”是确定兴趣的最重要的特征之一,那么当添加一组新的客户并且他们的公司还不在训练数据库中时,模型的性能可能会差得多。因此,我们认为在没有最重要的列的情况下再次运行模型可以帮助评估模型在这些情况下的性能。
最后一件事是,随着新信息的到来,定期调整模型。为了不断提供有意义的*解,需要维护模型。也许你会开始收集你的客户的一个新特性,并想把它添加到你的模型中,或者也许模型需要重新训练久而久之来提高它的性能。不要只是把你的模型放在那里,认为它会永远有效。监控其性能并努力维护它。
结论
到目前为止,您应该对两种数据清理方法有了深入的了解,可以在自己的文本数据上进行尝试。虽然计算相似性得分和使用机器学*模型可能更复杂,但有时需要更复杂的方法来解决数据的复杂性和特质。本教程提供了一个起点,供您思考您的目标,完成整个过程,并有希望获得一个干净的、转换的、统一的数据集,为分析做好准备。因此,无论这是您的第一个分析项目,还是您刚刚遇到字符串变量的困难,我们希望我们的提示和建议将帮助您避免一些常*问题,并节省整个过程中的故障排除时间。
非常规情绪分析:BERT vs. Catboost
原文:https://towardsdatascience.com/unconventional-sentiment-analysis-bert-vs-catboost-90645f2437a9?source=collection_archive---------13-----------------------
省一便士就是赚一便士

作者
介绍
情感分析是一种自然语言处理(NLP)技术,用于确定数据是正面、负面还是中性。
情感分析是基础,因为它有助于理解语言中的情感基调。这反过来有助于自动整理评论、社交媒体讨论等背后的观点。,使您能够做出更快、更准确的决策。
尽管情绪分析在最近变得非常流行,但自 21 世纪初以来,这方面的工作一直在进展。传统的机器学*方法,如朴素贝叶斯、逻辑回归和支持向量机(SVMs)被广泛用于大规模情感分析,因为它们具有良好的扩展性。深度学*(DL)技术现已被证明可以为各种 NLP 任务提供更好的准确性,包括情感分析;然而,学*和使用它们的速度往往较慢,成本也较高。

由贾科莫·维尼里
在这个故事中,我想提供一个鲜为人知的结合了速度和质量的选择。对于建议方法的结论和评估,我需要一个基线模型。我选择了久经考验、广受欢迎的伯特。
数据
社交媒体是一个以前所未有的规模产生大量数据的来源。我将为这个故事使用的数据集是冠状病毒推文 NLP 。

作者
正如我所看到的,模型没有太多的数据,乍一看,似乎没有预先训练的模型是不行的。

作者
由于用于训练的样本数量很少,我们通过合并它们将类的数量减少到 3 个。

作者
基线 BERT 模型
我们用 TensorFlow Hub 吧。TensorFlow Hub 是一个经过训练的机器学*模型库,可随时进行微调,并可部署在任何地方。只需几行代码就可以重用经过训练的模型,如 BERT 和更快的 R-CNN。
!pip install tensorflow_hub
!pip install tensorflow_text
**small _ bert/BERT _ en _ un cased _ L-4 _ H-512 _ A-8—**更小的 BERT 模型。这是博学的学生学得更好:关于预培训紧凑模型的重要性中引用的一个较小的 BERT 模型。较小的 BERT 模型适用于计算资源有限的环境。它们可以像最初的 BERT 模型一样进行微调。然而,它们在知识提炼的环境中是最有效的,在这种环境中,一个更大和更准确的教师产生微调标签。
**bert _ en _ un cased _ preprocess—**针对 BERT 的文本预处理。这个模型使用从维基百科和图书语料库中提取的英语词汇。文本输入已经以“不区分大小写”的方式进行了规范化,这意味着文本在标记为单词片段之前已经小写,并且所有重音标记都已去除。
tfhub_handle_encoder = \
"[https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-512_A-8/1](https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-512_A-8/1)"
tfhub_handle_preprocess = \
"[https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3](https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3)"
为了不使代码复杂化,我将不进行参数的选择和优化。同样,这是基准模型,不是 SOTA。
def build_classifier_model():
text_input = tf.keras.layers.Input(
shape=(), dtype=tf.string, name='text')
preprocessing_layer = hub.KerasLayer(
tfhub_handle_preprocess, name='preprocessing')
encoder_inputs = preprocessing_layer(text_input)
encoder = hub.KerasLayer(
tfhub_handle_encoder, trainable=True, name='BERT_encoder')
outputs = encoder(encoder_inputs)
net = outputs['pooled_output']
net = tf.keras.layers.Dropout(0.1)(net)
net = tf.keras.layers.Dense(
3, activation='softmax', name='classifier')(net)
model = tf.keras.Model(text_input, net)
loss = tf.keras.losses.CategoricalCrossentropy(from_logits=True)
metric = tf.metrics.CategoricalAccuracy('accuracy')
optimizer = Adam(
learning_rate=5e-05, epsilon=1e-08, decay=0.01, clipnorm=1.0)
model.compile(
optimizer=optimizer, loss=loss, metrics=metric)
model.summary()
return model
我已经创建了一个不到 30M 参数的模型。

作者
我分配了 30%的列车数据用于模型验证。
train, valid = train_test_split(
df_train,
train_size=0.7,
random_state=0,
stratify=df_train['Sentiment'])y_train, X_train = \
train['Sentiment'], train.drop(['Sentiment'], axis=1)
y_valid, X_valid = \
valid['Sentiment'], valid.drop(['Sentiment'], axis=1)y_train_c = tf.keras.utils.to_categorical(
y_train.astype('category').cat.codes.values, num_classes=3)
y_valid_c = tf.keras.utils.to_categorical(
y_valid.astype('category').cat.codes.values, num_classes=3)
历元的数量是凭直觉选择的,不需要证明:)
history = classifier_model.fit(
x=X_train['Tweet'].values,
y=y_train_c,
validation_data=(X_valid['Tweet'].values, y_valid_c),
epochs=5)

作者
BERT Accuracy: 0.833859920501709

伯特的混淆矩阵

BERT 的分类报告
这是基线模型。显然,这个模型还可以进一步改进。但是让我们把这个任务作为你的家庭作业。
CatBoost 模型
CatBoost 是一个高性能的开源库,用于决策树的梯度提升。从版本 0.19.1 开始,它支持在 GPU 上开箱即用的分类文本功能。
主要优点是 CatBoost 可以在数据中包含分类函数和文本函数,而无需额外的预处理。对于那些重视推理速度的人来说,CatBoost 预测比其他开源梯度提升库快 20 到 40 倍,这使得 CatBoost 对于延迟关键型任务非常有用。
!pip install catboost
我不会选择最佳参数;让那成为你的另一个家庭作业。让我们写一个函数来初始化和训练模型。
def fit_model(train_pool, test_pool, **kwargs):
model = CatBoostClassifier(
task_type='GPU',
iterations=5000,
eval_metric='Accuracy',
od_type='Iter',
od_wait=500,
**kwargs
)return model.fit(
train_pool,
eval_set=test_pool,
verbose=100,
plot=True,
use_best_model=True)
当使用 CatBoost 时,我推荐使用池。它是一个方便的包装器,结合了特性、标签和进一步的元数据,如分类和文本特性。
train_pool = Pool(
data=X_train,
label=y_train,
text_features=['Tweet']
)valid_pool = Pool(
data=X_valid,
label=y_valid,
text_features=['Tweet']
)
**text _ features—**文本列索引(指定为整数)或名称(指定为字符串)的一维数组。仅当数据参数是二维特征矩阵(具有以下类型之一:list、numpy.ndarray、pandas)时使用。数据框,熊猫。系列)。如果此数组中的任何元素被指定为名称而不是索引,则必须提供所有列的名称。为此,要么使用此构造函数的 feature_names 参数显式指定它们,要么传递一个 pandas。data 参数中指定了列名的 DataFrame。
支持的训练参数:
- 记号赋予器 —记号赋予器用于在创建字典之前预处理文本类型特征列。
- 字典— 用于预处理文本类型特征列的字典。
- feature_calcers — 用于基于预处理的文本类型特征列计算新特征的特征计算器。
我直观的设置了所有的参数;调整它们将再次成为你的家庭作业。
model = fit_model(
train_pool, valid_pool,
learning_rate=0.35,
tokenizers=[
{
'tokenizer_id': 'Sense',
'separator_type': 'BySense',
'lowercasing': 'True',
'token_types':['Word', 'Number', 'SentenceBreak'],
'sub_tokens_policy':'SeveralTokens'
}
],
dictionaries = [
{
'dictionary_id': 'Word',
'max_dictionary_size': '50000'
}
],
feature_calcers = [
'BoW:top_tokens_count=10000'
]
)

准确(性)

失败
CatBoost model accuracy: 0.8299104791995787

CatBoost 的混淆矩阵

CatBoost 的分类报告
结果非常接近基线 BERT 模型显示的结果。因为我用于训练的数据很少,而且模型是从零开始教的,结果在我看来是令人印象深刻的。
奖金
我得到了两个结果非常相似的模型。这能给我们其他有用的信息吗?这两种模式的核心几乎没有共同之处,这意味着它们的结合应该产生协同效应。检验这一结论最简单的方法是将结果*均,看看会发生什么。
y_proba_avg = np.argmax((y_proba_cb + y_proba_bert)/2, axis=1)
收获令人印象深刻。
Average accuracy: 0.855713533438652

*均结果的混淆矩阵

*均结果的分类报告
摘要
在这个故事中,我:
- 使用 BERT 创建基线模型;
- 使用内置文本功能创建了 CatBoost 模型;
- 看看如果*均两个模型的结果会发生什么。
在我看来,复杂而缓慢的 SOTAs 在大多数情况下是可以避免的,尤其是当速度是一个关键需求的时候。
CatBoost 提供了开箱即用的强大情感分析功能。对于 Kaggle 、 DrivenData 等竞赛爱好者来说。CatBoost 可以作为基线解决方案和模型集合的一部分提供一个很好的模型。
文章中的代码可以在这里查看。
