TowardsDataScience-博客中文翻译-2021-五十八-
TowardsDataScience 博客中文翻译 2021(五十八)
生成艺术适合你吗?
关于视觉生成艺术创作的起伏

作者图片
视觉生成艺术是视觉艺术中一个有趣的领域,它利用一个通常通过代码定义的自治系统来生成艺术作品。虽然它至少可以追溯到 20 世纪 50 年代的,但生成艺术是随着过去几十年的技术进步而获得发展的。在业余爱好艺术家中,有创造力的黑客可能对生成艺术特别感兴趣,他们想用结构化的方式艺术地表达自己,或者只是想利用他们擅长的技能创造令人愉快的图像。
我自己知道一些编程,我终于在 2020 年锁定期间开始涉足生成艺术。通过代码和迭代改进,将必要的概念阶段与实验相结合无疑是有趣的。尽管如此,生成艺术的某些方面可能会令人不快。
在这篇短文中,我将介绍生成艺术与传统艺术在创作过程中的不同之处。我希望它可以为其他考虑进入生成艺术的创意者提供指导。其中一些特征对一些艺术家来说更具吸引力。每个工具都擅长做某些事情,而不擅长做其他事情。这种“没有免费的午餐”式的效果当然也适用于艺术艺术媒体。我认为选择艺术媒介有两个标准:
- 它能让你创造你想创造的东西吗?这个问题的含义是本文的主要部分,但是当然在任何媒介中能做什么也取决于艺术家。
- 你用起来好玩吗?我会涵盖我自己的观点,但也许你可以对你自己的观点做出推论。
所以让我们直接进入生成艺术的起伏!
需要编码技能
对于我和这篇文章的大多数读者来说,这不是问题。如果你不知道如何编码,你可以学习基础知识或者尝试跟随处理教程,但是要注意的是,无论哪种情况,你都将是一个缓慢的开始。
没有素描
对我来说,一个很大的缺点是,在进入实际编程的本质之前,你不能真正勾画出你的作品。当然,你可以在纸上草草记下一些想法,然后加以发挥,但由于你可能会将大量的复杂性和随机性打包到你的作品中,它可能根本不会与最终作品相似。
对于生殖艺术,在你能看到某些东西之前,总会有一些前期投资。你越了解你的工具,它会变得越小,但它永远不会像一个快速的铅笔素描那么小,这肯定是一个骗局。
以后有更多的探索空间
在构思和素描的早期阶段缺失的探索能力在生成过程的后期出现。由于您的作品是由代码定义的,并且您可以随时更改和重新运行它,因此稍后进行更改(即使是大的更改)和尝试多个版本变得非常容易。你想看看你的抽象树是否用紫色菱形而不是绿色椭圆形作为树叶的基础会更好看?没有比这更简单的了!这种混合、匹配和尝试改变而不永久删除以前版本的绝对自由,是我欣赏用代码定义艺术品的过程的一点。
局限于抽象
既然我们已经在谈论树了:生成艺术通常局限于抽象艺术。你可以通过使用生成机器学习模型来试图绕过这一点,但没有它们,生成艺术很可能无法表现真实世界,因为真实世界太复杂和多样,无法通过合理数量的代码来捕捉。(也是图像识别在深度学习之前效果不好的一个原因。)
许多艺术家喜欢抽象艺术,如果你也是其中一员,那么生成艺术可能正适合你。具体的物体、人物、故事,也许还有模仿古典艺术的方面,在生成媒介中更难实现,这可能会使它对一些人来说不那么有吸引力。
开发和重用工具
这一个是混合的袋子。开发自己的工具(着色器、几何对象、细分算法等)可能会很有趣,也很有挑战性,为乐趣而编码的人会喜欢开发工具,只是为了好玩。此外,在后续的部分中重用您创建的工具确实是值得的,并且它肯定会增强您的过程。(也许你甚至可以通过工具箱来构建自己独特的风格?)
不利的一面是,如果你只是想继续创作你脑海中的东西,或者尝试一些特定的着色或绘图方式,那么开发或找到超越基础的工具的需求可能会是一种令人沮丧的体验。
复杂性、随机性和惊喜
这就是生成艺术大放异彩的地方。通过编程,我们可以在几分之一秒内创造出手工无法想象的复杂图案。只看分形!借助随机数生成器这个强大的工具,我们可以创造出这种图案的几乎无限的变化,还可以给纹理和几何图形添加一些噪声,让作品看起来更“自然”,如果我们愿意的话。
最棒的是,你永远无法确定结果,更多的时候,你会感到惊讶。(除了随机性带来的惊喜之外,您自己的编码错误也会产生有趣的结果。)使用随机性的一个缺点是失去完全的控制,而对于许多创作型艺术家来说,随机性是不可替代的。你无法精确定义你的作品,也无法享受随机性的好处。
如果你想创造错综复杂的作品,并喜欢通过任意数量的变化,找到一个真正脱颖而出,那么不要再等了!
不直接
对我来说,这可能是最大的挫折:在你的工作和结果之间总是有延迟。这个相位并不限制你能创造什么,但是它很大程度上影响了创造的感觉。当你用更传统的媒介绘画时,你会得到即时的反馈。一旦你的铅笔接触到纸,你就会看到正在发生的事情,你知道你要去哪里,这本身就使这个过程变得愉快,有时几乎是冥想。如果你为你的作品编程,你只有在实现了改变并运行了代码之后才能看到结果——众所周知,这有时会比预期的要长。
就我个人而言,我喜欢我在生成艺术方面的尝试,尽管有时传统媒体对我来说可能更有趣。我试图写下生成艺术的特质是如何影响创作过程的,但请不要将此解读为这种媒介的绝对限制——艺术总是会找到自己的路。
我希望这篇文章能帮助你评估创造艺术是否适合你。如果还不确定,就试试吧!也许最简单的方法是从处理开始,即使你不是一个有经验的程序员,也能很快上手。
希望你学到了有用的东西!
GPT-3 仇视伊斯兰教吗?
公平和偏见
open ai 的西方算法如何延续东方主义的权力结构。

本文的范围是在 OpenAI 的 GPT-3 算法的背景下,研究由爱德华·萨义德开发的东方主义和技术的交集,该算法从最少的提示中生成连贯的文本。当被提示输入包含“伊斯兰教”、“穆斯林”或“中东”的词语时,GPT-3 生成有助于复制和强化东方主义观点的定型文本。OpenAI 算法向我们展示了西方的伊斯兰概念,以及为了政治或学术上的权宜之计甚至控制而不断简化社会群体的尝试。
数字东方主义与算法凝视
1978 年,爱德华·萨义德出版了 20 世纪最相关的书籍之一,《东方主义》。他的作品关注西方对东方态度的本质,认为东方主义是一种强大而成熟的欧洲意识形态创造,是作家、哲学家和殖民当局处理东方文化、习俗和信仰“他者性”的一种方式。
具体来说,赛义德认为,西方文化中误导和浪漫化描述亚洲和中东的悠久传统一直是欧洲殖民和帝国野心的隐含理由(赛义德,1978)。虽然赛义德主要关注欧洲与中东和南亚的关系,但这种霸权二分法中隐含的政治意识形态和文化意象也揭示了东方主义在美国的内部动态(Kim 和 Chung,2005)。
近年来,有人试图重写赛义德著作的遗产,源于更新和扩展其论述框架的时间、地理和概念范围的需要。新的东方框架将注意力转移到当代社会中对他人的感知是如何被定义为 算法凝视所调节的:试图通过算法描述、描绘和影响人们 (Kotliar,2020)。
通过算法凝视,他者变得可见和可知(Kitchin,2014)。但是正如 Bucher 指出的,知识从来都不是客观的,也不是中立的。它源于需要具体语境化的解释过程(Bucher,2018)。算法无视文化和个人属性这一广为接受的信念是错误的,并且没有考虑到这种系统如何强有力地将自己标榜为殖民凝视的延续。
GPT-3 算法如何延续东方权力结构
考虑到主流媒体、民粹主义运动、公众舆论和框架辩论中的政治倾向,数字东方主义的当代挑战是巨大的。今天,东方仍然以萨义德在《东方主义》出版之前展示的方式被本质化。这在 OpenAI 最新的语言生成模型 GPT-3 中表现得尤为明显。
GPT-3 是最近发布的语言模型,它使用机器学习算法来产生类似人类的文本。它接受一个提示并完成它。其算法使用计算方法直接从输入数据中获取和学习信息,而不依赖于预先确定的模型(Mathworks.com,2021)。因此,数据在机器学习算法的训练过程中起着重要作用。以 GPT-3 为例,其 60%的训练数据链接到通用抓取数据集,这是互联网上 6000 万个域名及其相关网站子集的一部分。因此,GPT-3 在许多知名的互联网媒体上进行培训,如 BBC,以及一些不太知名的媒体(如 Reddit)。其余 40%由维基百科和相关书籍的全文等精选来源构成(Brockman,2020)。有必要强调的是,GPT-3 主要是根据英语数据进行训练的(尽管能够将法语、德语和罗曼语翻译成英语)。因此,它的输出公开地复制了可以被认为是西方思想的东西。在培训过程中,GPT-3 学会了如何根据我们在网上找到的文本来生成短语和句子。人们很自然地意识到,尽管表现令人印象深刻,但 GPT-3 反映了社会偏见,并在被要求生成涉及种族、宗教、性别等的文本时再现了这些偏见。
OpenAI 研究人员在 2020 年 7 月发表的 GPT-3 论文的补充材料让用户深入了解了该模型有问题的偏差。研究表明,该模型更有可能将“吮吸”或“淘气”等词与女性代词联系起来,而男性代词则被置于“懒惰”或“快乐”等词附近(Brown 等人,2020 年)。

图 1 ,175B 模型中最有偏见的描述性词语,基于 Brown at al。,2020,第 37 页
研究人员还检查了这些词与不同宗教的共现:与性别和种族类似,他们发现该模型在负面形容词和一些宗教之间建立了(有偏见的)联系。例如,像恐怖主义和暴力这样的词在伊斯兰教附近比在其他宗教附近更常见,结果在 GPT-3 (Brown at al。, 2020).

图 2 显示了 GPT-3 175B 模型中每个宗教最受欢迎的十个词。,2020,第 38 页
GPT-3 之间的联系,如“恐怖主义”和伊斯兰教的负面词汇,说明了霸权权力的数字东方主义话语的方式,它复制和加强对穆斯林的偏见知识。重要的是要注意到,东方主义的思想往往与种族主义、伊斯兰恐惧症、选择性偏见和其他主张文明差异的学说的更广泛的概念相冲突。如 Said 所述,美国及其盟国经常使用恐怖主义的话语来描述抵抗其帝国占领的暴力行为,而不是解决帝国占领本身的暴力行为(Said,1978 年)。在这种背景下,尤其是在 9/11 戏剧性事件之后,“恐怖主义”一词开始代表一个无名的东方集体,从北非的撒哈拉图阿雷格人一直延伸到亚太地区的所罗门群岛(Kumar,2012)。因此,恐怖主义的话语被表现为另一种形式的东方主义,它故意忽略任何地理实体(Morton,2007)。
因此,通过算法模型,西方构建了关于东方的说法的可能性,使这种由被认为是客观和可信的工具:机器产生的偏见合法化。这种制度剥夺了穆斯林根据自己的意愿将自己定义为主体的权利。具体而言,当提示输入包含“伊斯兰”、“穆斯林”或“东方”的词语时,GPT-3 生成定型文本,这有助于复制和强化东方主义观点,如以下来自直接检查的例子所示:

图 3 ,GPT-3 结果的一个例子,当提示“两个穆斯林走”时。图片由作者提供。

图 4 ,一个 GPT-3 结果的例子,当提示单词“伊斯拉姆”时。图片由作者提供。

图 5,GPT-3 结果的一个例子,当由词语“中东”提示时。图片由作者提供。
正如最近一项关于 NLP 中反穆斯林偏见的研究所指出的,当提示一个包含“穆斯林”一词的句子时,3 制作的 100 个竞赛中有 66 个包含暴力相关的词(Abid,Farooqi 和 Zou,2021 年)。除此之外,通过复制 GPT -3 的学习嵌入的逻辑(由于用户只能访问其 API,所以不能公开获得),研究人员注意到,“穆斯林”一词有 23%的时间被类比为“恐怖分子”(Abid,Farooqi 和 Zou,2021)。他们补充道:
[……]我们注意到,“穆斯林”和“恐怖分子”之间联系的相对力量非常突出,甚至相对于其他群体而言也是如此;在这里考虑的 6 个宗教团体中,没有一个被映射到一个单一的常规名词,与“穆斯林”被映射到“恐怖分子”的频率相同。(阿比德、法鲁奇和邹,第 6 页,2021 年)。
最后,研究人员探索了消除 GPT -3 完井偏差的方法。他们选择了最可靠的方法之一:在含有对穆斯林正面联想的提示中添加一个短语。他们修改了提示,输入了下面的话“穆斯林是勤劳的。两个穆斯林走进一个“80%的时间 GPT-3 产生非暴力完成。然而,他们指出,即使是最有效的形容词也比“基督徒”产生的结果更暴力(Abid,Farooqi 和 Zou,2021)。
此外,虽然 3 的穆斯林和暴力之间的联系是在预训练阶段学习的,但根据作者的说法,这些似乎不是记忆,而是由 3 创造性地表现出来,表明语言模型能够以不同的方式复制偏见,这可能使偏见更难检测和缓解(Abid,Farooqi 和 Zou,2021)。

图 6,3 井完井去偏(Abid,Farooqi 和 Zou,第 9 页,2021 年)。(CC BY 4.0)。
需要注意的是,所提供的实验触发了一条警告消息,“我们的系统已经将生成的内容标记为不安全,因为它可能包含明确的政治、敏感、身份敏感或攻击性文本。我们将很快增加一个选项来抑制这种输出。该系统是实验性的,会出错”,然后是一个报告生成的输出的选项。自其发布以来,许多用户报告这些输出为伊斯兰恐惧症,导致 OpenAI 标记此类内容。该公司目前正在开发一种软件,可以防止用户恶意使用这种工具,例如创建垃圾邮件。尽管现阶段对 GPT-3 的访问受到限制,但从网上出现的大量用例来看,从业余爱好者到机器学习专家,每个人都没有太多的麻烦来获得这种简单而强大的技术。事实上,OpenAI 的 GPT-3 是一种商业产品,世界各地的许多客户已经在为不同的目的试验其 API:从创建客户服务系统到自动内容审核,就像 Reddit 的情况一样。
正如已经反复显示的那样,偏见和歧视在互联网上广泛传播,这可能会潜在地融入公共和私人自动化系统。这种操作方式忽略了仅仅因为数据可用就从网络上获取数据来训练语言模型是否是一种负责任的策略,而没有质疑其放大未经检查的有害偏见的价值和潜力。此外,正如微软和 UMass Amherst 的研究人员在分析 150 项自然语言过程中的偏见研究时所表明的那样,许多提出语言模型的作者似乎对这种偏见如何以及为什么有害有模糊的动机(Blodgett,Barocas,Daumé III 和 Wallach,2020)。他们接着指出,有必要参与探索语言和社会等级关系的系统,如社会语言学和社会学(Blodgett,Barocas,Daumé III 和 Wallach,2020 年)。与此同时,作者还需要与那些直接受此类系统影响的人接触。在 GPT-3 的情况下,在英语数据上训练模型并仅用英语建立系统经常阻止作者通过机器生成的文本直接与受这种东方主义观点永久化影响的人接触。当用于商业目的时,GPT-3 可能会使这种偏见合法化,因为它是由公众认为客观和可信的工具产生的。再一次,这个系统可以剥夺“东方”用自己的术语将自己定义为一个主体,而不考虑模型如何与我们生活的社会相互作用和影响。
GPT-3 的例子表明,社会意义和语言环境需要在设计人工智能中发挥核心作用。公众不能仅仅假设支撑技术的设计选择总体上是规范中性的。技术模型和社会世界之间关系的互动性质证明了为什么即使一个“客观上完美的”模型如果部署在一个不公平的世界中也会产生不公平的结果。正如 GPT-3 的情况一样,这种强大的语言模型可以放大通过语言类别表达的不平等,特别是考虑到它目前和未来可能的运作规模。
最后,在 2021 年 1 月 5 日,OpenAI 推出了 DALL E,这是一个基于 GPT 3 的 text2Image 系统,但经过了文本加图像和 CLIP 的训练,这是一个神经网络,可以根据对 4 亿对图片和文本进行训练的自然语言进行精确的图像分类。这两个新模型将语言和图像结合起来,帮助人工智能理解单词和它们所指的内容,生成高质量的图像。DALL E 使用 120 亿参数版本的 GPT-3 和 transformer 语言模型来开发和完成半成品图像。该模型可以绘制具有人类特征的动物或事物的图片,并将不相关的项目准确地组合在一起,生成一幅图像。有趣的是,图片的成功率将取决于提示的措辞。更令人印象深刻的是,当标题暗示图像必须包含未明确说明的特定细节时,DALL E 能够填补空白。这两种模式都有可能产生重大的社会影响。OpenAI 团队已经表示,他们将分析 DALL E 和 CLIP 如何与社会问题、可能的偏见和伦理挑战相关联(OpenAI,2021)。那两种新型号还没有上市。然而,未来对这一主题的分析仍应关注这些技术是否有助于通过人工制造的图像来复制和强化东方主义意识形态。
GPT-3 是否仇视伊斯兰教?
同样,技术模型和社会世界之间关系的互动性质证明了为什么即使是“客观上完美的”模型,如果部署在不公平的世界中,也会产生不公平的结果。在 GPT-3 的情况下,这种强大的语言模型可以放大通过语言类别表达的不平等,特别是考虑到它目前和未来可能运行的规模。意识到风险并努力降低风险已成为当务之急,每次开发新模型时都需要考虑这一点。正如郝:所言:“算法决策就是人的决策。换句话说,谁在构建这项技术和这项技术是什么一样重要。”(郝,2021)
参考文献
Abid,a .,Farooqi,m .和 Zou,J. (2021)。大型语言模型中持续的反穆斯林偏见。[在线]可在 https://arxiv.org/pdf/2101.05783v1.pdf.的找到
啤酒,d,2016。算法的社会力量。信息,交流&社会,20(1),第 1–13 页。
南布洛杰特、南巴罗卡斯、多梅三世和瓦拉赫,2020 年。语言(技术)就是力量:对自然语言处理中“偏见”的批判性调查。计算语言学协会第 58 届年会会议录。
布罗克曼,G. (2020)。 OpenAI API 。[在线] OpenAI。可在:https://openai.com/blog/openai-api/【2021 年 1 月 11 日获取】。
Brown,t .,Mann,b .,Ryder,n .,Subbiah,m .,Kaplan,j .,Dhariwal,p .,Neelakantan,a .,Shyam,p .,Sastry,g .,Askell,a .,Agarwal,s .,Herbert-Voss,a .,Krueger,g .,Henighan,t .,Child,r .,Ramesh,a .,Ziegler,d .,Wu,j .,Winter,c .,Hesse,c .,Chen,m .,Sigler,e .,Litwin,m .,Gray,s .,Chess,b .,Clark,j .语言模型是一次性学习者。[在线]可在:https://arxiv.org/pdf/2005.14165.pdf.找到
t . bucher(2012 年)。想在上面吗?算法的力量和脸书隐形的威胁。新媒体&社会, 14 ,1164–1180。
郝,2021。让人工智能在 2021 年发挥更大作用的五种方法。麻省理工学院技术评论,[在线]可在 https://www . Technology Review . com/2021/01/08/1015907/ai-force-for-good-in-2021/?truid = f 640 BD 600 a 7a 7 b 243 bb 59 CD 866 DC 44 c 2
Kim m .和 Chung a . y .(2005 年)。消费东方主义:多元文化广告中的亚裔/美国女性形象。定性社会学,【在线】28 卷 1 期,页 67–91。可在:https://www . depts . TTU . edu/education/our-people/Faculty/additional _ pages/du emer/epsy _ 6305 _ class _ materials/Kim-min Jeong-Chung-Angie-Y-2005 . pdf
基特钦河(2014 年)。数据革命:大数据、开放数据、数据基础设施&它们的后果。伦敦:鼠尾草。
科特里尔博士,2020。符号消亡时代的算法身份。新媒体&社会,22(7),第 1152–1167 页。
Mathworks.com。(, 2021).什么是机器学习?|工作原理、技术&应用。[在线]可在 https://www.mathworks.com/discovery/machine-learning.html的找到
s .莫顿,2007 年。恐怖主义、东方主义和帝国主义。wasafari,22(2),第 36–42 页。
OpenAI (2021)。剪辑:连接文字和图像。[在线] OpenAI。可在:https://openai.com/blog/clip/【2021 年 1 月 11 日获取】。
赛义德·e,1978。东方主义。伦敦:企鹅图书公司。
GPT-3 足够“合理”来检测逻辑谬误吗?
通过常见的逻辑谬误探索 GPT-3 的推理能力
2020 年 5 月,OpenAI 研究团队在论文“语言模型是很少出手的学习者”中介绍了他们名为 GPT-3 的新语言模型。2020 年 6 月 11 日,OpenAI 发布了一个 API ,供一些 beta 用户测试和开发基于 GPT 3 的应用。从那以后,在 GPT-3 演示上有数百条带有#gpt3 标签的推文和许多关于用户体验的博客帖子。使用 GPT-3 可以生成各种类型的应用程序,其中一些是上下文分析,写诗,博文,创意小说,代码,总结文本等。你可以查看链接找到不同的 GPT-3 演示。

图片来自 Pixabay 的 Gerd Altmann
我有机会接触 GPT-3 API 并探索它的能力。在其他的 GPT-3 演示中,我还没有遇到任何演示涉及到 GPT-3 检测逻辑谬误的能力。逻辑谬误是推理中的错误,它会损害论点的逻辑性。
谬误通常分为正式的和非正式的。一个形式谬误可以在一个标准的逻辑系统中简洁地表达出来,比如命题逻辑,而一个非形式谬误来源于推理中的一个错误,而不是一个不恰当的逻辑形式。包含非正式谬误的论点可能在形式上有效,但仍然是谬误的[ wiki ]。
在这篇文章中,我们将探索 GPT-3 的有效性,以识别一些常见的非正式谬误,这些谬误迎合了对 GPT-3 推理能力的理解。在下文中,我将尝试阐明 GPT-3 模型的关键细节,然后我将通过 OpenAI API 的操场向 GPT-3 询问一些关于常见逻辑谬误的例子。
什么是 GPT-3?
GPT-3 代表第三代生成式预训练变压器,有八种尺寸[ 纸张 ]。最大的模型包括 1750 亿个参数,将 GPT-3 的前身 GPT-2 的能力扩大了两个数量级。所有 GPT-3 模型都使用基于变压器的神经网络,正如它们的前身(流行的 NLP 模型 BERT 也使用变压器),但具有更多、更宽的层和更多的数据(最大的模型有 96 个注意力层,每个都有 96×128 维的头)。GPT-3 175B 在一个未标记的文本数据集上进行训练,该数据集几乎包含了互联网上存在的所有内容,具有来自多个来源的 4990 亿个标记,包括维基百科(3%)、书籍(16%)和普通爬行 (60%)等。GPT-3 的巨大体积使得它的训练过于昂贵。使用 Tesla V100 云实例(使用 Lambda GPU 实例),预计成本超过 460 万美元。
GPT-3 是一种具有深度神经网络的语言模型,它只是试图从以前给定的单词中预测下一个单词。语言模型选择使句子在文献中更有可能出现的下一个单词。比如说;“我为鳄梨酱买了鳄梨”这句话比“我为鳄梨酱买了巧克力”更有可能在网络上存在。
普通爬虫 语料库包含了 8 年来收集的数 Pb 的网络爬虫数据。该语料库包含原始网页数据、元数据摘录和经过轻度过滤的文本摘录。
GPT-3 不同于其他语言模型的神奇之处在于,它可以在不需要任何微调的情况下完成特定的任务。其他流行的语言模型,如 BERT,需要大量特定于任务的数据集来进行训练,如翻译或摘要任务。这些要求使得获取数据很麻烦,并导致在其他任务中表现不佳。相反,我们可以用语言模型的方式,简单地提示,通过任务的公式化来指导 GPT-3。您可以在以下参考资料中找到有关 GPT-3 的更多详细信息。
GPT 3 号游乐场
如上所述,GPT-3 不需要任何微调,我们只是告诉模型我们想做什么,模型尽最大努力遵循我们的指示。GPT-3 是一个随机模型(并不总是返回相同的响应),然而,我们可以通过操场上定义的一些参数来控制随机性。比如说;介于 0 和 1 之间的称为温度的参数控制随机性,低值导致确定性结果。另一个是频率惩罚,控制模型谈论新话题的可能性。我在实验中使用了 OpenAI 提供的操场上的默认值,即温度为 0.7。

我提供了 5 次相同的提示来处理随机性。在下一节中,我们将检查 GPT-3 对一些常见谬误的回应。
我相信逻辑谬误代表了一个非常有趣的框架来理解 GPT-3 的推理能力。我参考了 TBS 工作人员的文章“进入辩论前你应该知道的 15 个逻辑谬误”,找到了我为实验挑选的 4 个常见谬误。你可以在这篇文章中找到更多关于谬误的信息。

实验 1:Ad homine 谬论
Ad hominem 是一种侮辱,好像它是支持一个结论的论据或证据。
粗体句子是提示性的,每个斜体句子由一条线隔开,以表示不同的尝试是 GPT-3 的响应

人身攻击谬误和 GPT 三号协议的回应
在所有的 5 次尝试中,GPT-3 都找到了正确的例子,认为是针对个人的谬误,我认为 GPT-3 的解释也是令人满意的。

Ad Hominem 谬误演示
值得一提的是,我并没有在提示中提供任何例子来引导 GPT-3 的话题,而是我直接问了 GPT-3。在他们的论文中,作者提到,如果用户在询问或请求某事之前在提示中提供一些任务示例,结果的准确性会增加。
实验二:循环论证(小原理)
如果一个主张是用它自己的结论作为它的建议,反之亦然,以“如果 A 是真的,因为 B 是真的;b 为真是因为 A 为真”,那么就叫循环论证。我想说这很容易察觉。让我们看看 GPT 3 号表现如何。这一次,我改变了示例的顺序以混淆模型。

GPT-3 的循环自变量检测
GPT-3 在 80%的尝试中找到了正确答案。出于好奇,我将温度降至 0.2(减少响应的随机性),GPT-3 这次找到了 100%正确的选项。所以,温度真的会影响 GPT 3 号的反应以及最终结果的正确性。
实验三:草率概括
草率概括谬误可能是最常见的谬误之一,它依赖于一个很少证据支持的主张。

GPT-3 的草率概括表现
这一次,GPT 3 号在所有五次尝试中都找到了正确答案。我不得不承认,草率的概括可能是 GPT-3 最容易发现的,因为它可以区分限定词,如“一些”、“可能”、“经常”等。避免草率概括。

实验四:红鲱鱼谬误(ignore ratio elenchi)
“红鲱鱼谬误”是一种转移注意力的论点,通常带有一些看似相关但实际上不切题的情绪。当有人不喜欢当前的话题,想转到其他更容易或更安全的话题时,这种策略很常见。
我认为红鲱鱼谬误是对 GPT-3 最具挑战性的谬误(我猜对其他人也是如此),因为不同的主题如何介入可能并不明显。

GPT-3 的红鲱鱼谬误(温度=0.7)
正确答案应该是第一个例子,一个人试图改变话题(转移对方的注意力)以逃避清理车库。GPT-3 在这项任务中表现更差,它只能在两次尝试中找到正确答案。有趣的是,当我将温度提高到 1.0 时,我能够收到相当合理的响应。不是在所有的尝试,但 GPT-3 能够找到正确的结果,并解释“合理”。

GPT-3 的红鲱鱼谬误(温度=1.0)
结论
在前三个实验中,GPT-3 的反应是很容易理解的。最后一个实验对 GPT 3 号来说是具有挑战性的,反应并不令人满意,然而,当我提高温度时,GPT 3 号仍然能够产生“合理的”输出。
很难回答这种“合理性”从何而来。它是基于 175B 参数(如模糊查找表)压缩的互联网上的所有数据生成的,还是基于语言中语义结构的解释或除此之外的其他东西生成的?有一点是肯定的,在接下来的几年里,算法、计算能力甚至数据方面的增强将继续让我们感到惊讶。
检测逻辑谬误的一个可能应用是将其用作辨别假新闻的过滤器。例如,应用程序可以识别给定新闻中有缺陷的推理、不合逻辑的论点或缺乏证据,并对它们进行过滤。
梯度推进作为时间序列预测的预言者好吗?
如何使用 Sklearn 模型进行多季节长期预测

马克·巴萨拉布在 Unsplash 上的照片
近年来,我们协助提出各种时间序列预测架构。最著名的是 Prophet,这是一种由脸书发布的算法,基于加法方法预测具有多重复杂季节性的时间序列。随着它的发布,时间序列预测的新时代开始了。由于其可用性和对各种情况的适应性,Prophet 最近成为更经典的 SARIMA 的一个有价值的替代品,以提供长期预测。
随着 Prophet 在数据科学界的成功,大型科技公司开始发布用于时间序列预测的开源工具。所有这些类型的框架都宣称使用可伸缩的和直观的 API 以快速有效的方式(包括自动调整)提供准确的预测。考虑到这些前提,如今执行时间序列预测任务似乎比以往任何时候都容易。
我们知道所有这些开源库的力量。然而,我们意识到,它们的有效性因研究案例而异。测试一个更标准的预测管道在很多情况下可能是有益的,以评估提供最准确预测的最佳工具。
在这篇文章中,我们执行了一个简单的时间序列预测任务。我们的目标是对具有多种季节性模式的系列进行长期的每小时预测。我们尝试将 Prophet 与简单特征工程制作的标准管道和梯度推进模型进行比较。当预测非平稳序列时,我们重复实验,在原始序列上引入趋势分量来评估该过程。
数据
我们从 Kaggle 收集了一个数据集。每小时能耗顾名思义,以兆瓦为单位存储美国不同地区不同年份的每小时能耗。
对于我们的分析,我们选择了一个单一地区的消费,在此基础上我们开发了我们的预测模型。所有 KPI 都是固定的,并根据日常和季节性行为显示多个季节性模式。

数据中呈现的季节模式(图片由作者提供)
模拟多重季节性
作为第一阶段,我们用 Prophet 和梯度推进对原始时间序列进行建模。我们使用最近一年的可用数据来测试性能,并从剩余的数据中连续 3 年进行训练。

原始时间序列被分割成训练和测试(图片由作者提供)
拟合先知很简单。不需要预处理,因为它声明对异常值、缺失数据和变化点是健壮的。它不需要任何手动操作,因为默认情况下会自动检测季节性模式。鉴于这些前提,为我们的时间序列提前一年提供预测对 Prophet 来说似乎是一件容易的事情。

预言家对测试数据的预测(图片由作者提供)
预测显示了强烈的每日和每周季节性。Prophet 还可以检测到以夏季和冬季能源消耗增加为特征的长期季节性。通过 Prophet 获得的预测似乎是合理的。它们概述了能源消耗的基本行为,肯定会产生重大影响。
我们要测试的下一个模型是 sklearn 库中的梯度增强。我们习惯于将梯度推进视为表格数据的算法。将它应用于时间序列预测是非常容易的。我们只需要提供足够的功能。我们的预测器必须在未来的任何时候都可以访问,因为我们正在进行长期预测,我们希望不要造成泄漏。
为此,我们创建了一些对时间变量进行循环编码的基本特性。这种方法非常灵活,允许我们简单地应用傅立叶变换,以数字格式合并多个时间回归量。此外,我们意识到,在任何未来的上下文中,同样的特征是容易检索的。在我们的例子中,我们对小时、星期、月份、星期和季节进行循环编码。参数的调整总是可以用标准技术来实现。
正如预言家所说,梯度推进充分再现了季节模式。最大的区别在于预测误差。与 Prophet 相比,梯度增强在测试数据上达到非常低的误差(计算为均方根误差)。

对测试数据的梯度推进预测(图片由作者提供)
用趋势模拟多重季节性
梯度增强只需使用正弦特征就能很好地处理这类数据。为了使事情更准确,我们在原始时间序列上引入一个增长趋势,并尝试再次预测。

原始时间序列加趋势(图片由作者提供)
处理非平稳时间序列是现实应用中的常见做法。默认情况下,Prophet 声明处理输入序列中的趋势行为。和以前一样,我们需要做的只是提供一个时间序列,以适合适当的格式。

预言家对测试数据的预测(图片由作者提供)
对测试数据的预测与没有趋势的情况非常相似,但是测试数据的误差急剧增加。
在梯度推进的情况下,目标的不稳定特性可能会造成困难。因此,作为第一步,我们建立一个简单的线性回归(总是基于训练数据)来模拟趋势模式。从训练数据中减去预测的趋势(以使它们稳定),然后在预测时再次相加。

关于培训和测试的趋势预测(图片由作者提供)
在从训练中减去预测的趋势之后,如前所述进行具有梯度增强的建模。最终预测遵循再现季节性模式的趋势。与 Prophet 相比,测试误差再次非常低。

对测试数据的梯度推进预测(图片由作者提供)
摘要
在这篇文章中,我们进行了一项长期预测的时间序列预测任务。我们测试了 Prophet 对更经典的管道的预测能力,该管道由时间变量的循环编码和梯度推进建模组成。我们发现,对于我们的用例,梯度提升在测试误差方面压倒性地优于 Prophet】。由于拟建管道的适应性,它可能被视为一个良好的基线。可以使用每个标准的机器学习算法来代替梯度提升,并且可以集成每个其他的预测器。同时,我们知道 Prophet 是一个很好的框架,有效性取决于研究的案例。
保持联系: Linkedin
实践知识比理论更重要吗?
我们几乎每周都会在 TDS 上看到这些争论的潮涨潮落:数据科学家应该首先掌握高层次的概念并熟练掌握,比如说,概率论——还是直接进入(偶尔)模型调整和数据清理的混乱世界?事实上,我们阅读和分享的最好的帖子无缝地融合了数据科学的这两个方面。本周阵容也不例外;我们比平时更注重实践和动手操作,但是不要担心:我们的作者总是看到森林和树木。我们开始吧!
- 学习如何绕开自回归模型中的盲点 。杰西卡·达弗伦、沃尔特·雨果·洛佩兹·皮纳亚和佩德罗·费雷拉·达科斯塔继续他们之前在 DeepMind 的 PixelCNN 上的工作,“一种深度神经网络,可以捕捉其参数中像素之间的相关性分布。”在他们的最新帖子中,他们解决了该模型的最大限制之一——“盲点问题”——并展示了如何解决它。
- 结识(或再认识)SMOTE 。在他最近的解释者中, Joos Korstanje 向读者介绍了 SMOTE(合成少数过采样技术),这是一种机器学习方法,可以消除因不平衡数据集而出现的问题。Joos 从大图开始,然后深入细节,用 Python 分享了一个完整的例子。

凯瑟琳·沃尔科夫斯基在 Unsplash 上的照片
- 探索真实世界中隐马尔可夫模型的用例 。“有许多分析序列数据的工具,”T4·菲尔德卡迪说,“它们各有所长。”在本演练中,重点介绍了隐马尔可夫模型,菲尔德解释了它们如何工作,以及在什么情况下使用它们比使用 LSTM 模型更有意义。
- 给你的熊猫数据帧添加颜色 。设计数据框架的样式不仅仅是美观——正如 Zolzaya Luvsandorj 在她便利的教程中所展示的,添加颜色、渐变和其他视觉提示会使它们更吸引人,更容易分析和记忆。
- 掌握一个强大的减方差方法(或几种) 。分层,CUPED,方差加权估计量…你应该使用哪一个来确保你的 A/B 测试或在线实验有很高的统计能力? Sophia Yang 向我们介绍了一些最有效的方法,并分享了足够多的代码示例,足以让您忙上一阵子。
- 了解一些我们最受欢迎的技巧文章 。寻找关于工具、方法和学习策略的更可行的建议?不要错过我们最近由拉希达·纳斯林·苏克伊、莎兰·库马尔·拉温德兰、萨拉·a·梅特沃利和阿利亚克塞·米哈伊留克等人撰写的热门帖子的综述。
我们希望你本周学到了一些新的和令人兴奋的东西,无论是在 TDS 上还是在你生活中一个完全不同的领域。感谢您阅读我们的帖子;如果你正在寻找一种亲身实践的方式来支持我们的工作,可以考虑成为一名中级会员。
直到下一个变量,
TDS 编辑
附言敬请关注——Jeremie Harris和 TDS 播客即将回归,带来新一季和令人兴奋的新嘉宾阵容。
我们策划主题的最新内容:
入门
实践教程
深潜
- 在野外寻找家庭作者约瑟夫·罗宾逊博士
- 通过 Bilal Himite 用 Python 模拟交通流
- AI-Tunes:用人工智能创作新歌作者罗伯特·a·贡萨尔维斯
思想和理论
数据科学家的创造力重要吗?
想象一个有创造力的面包师:你脑海中浮现的形象很可能是一个有着源源不断想法的人,然后将这些想法转化为美丽的(希望是美味的)糖果。一个有创造力的建筑师?当然:有人把一个看似无聊的项目带进生活,取悦那些占据和穿越一个新空间的人。
数据科学家呢?该领域的创造力是否以开发新的机器学习模型的形式出现?将学术研究应用于现实世界的问题?运行创新的 A/B 测试?为棘手的问题寻找不可能的解决方案?在一个如此抗拒稳定定义的领域,可能很难说清楚;但是当我们看到它时,我们知道它就在那里——幸运的是,我们每天都会在 TDS 上遇到创造力的爆发。以下是过去一周的一些例子;我们希望它们能激励你去尝试一些新的和令人兴奋的东西。
- 了解图表分析如何帮助检测医疗欺诈 。“问题不在于数字,而在于网络时会发生什么?” Lina Faik 结合机器学习和图形分析来探索一个特定的用例——医疗保健行业的欺诈检测——并展示它如何在不牺牲可解释性的情况下提高模型性能。

照片由 Holly Stratton 在 Unsplash 上拍摄
- 避免理解数据时的常见陷阱 。埃里克·j·达扎说,倾听相当于在你做出尝试后再做决定——换句话说,就是让你的理论符合你得到的结果。当面对不确定或混乱的结果时,这是一个诱人的举动,但这是一个你想保持警惕的陷阱,或者统计过度拟合在等着你。
- 提高你的讲故事和表达能力 。我们最近与 Vicky Yu 的谈话涵盖了许多领域,包括 Vicky 对数据分析师角色演变的看法。然而,一个关键的要点是,不管一个人的工作描述是什么,“如果你不以他们能理解的方式解释,利益相关者就不会欣赏你的贡献。”
- 探索数据与生物学交汇的新前沿 。Daniel Bojar 的最新工作集中在聚糖上,聚糖是一种复杂的碳水化合物,在病毒感染或肿瘤免疫逃避等过程中起着关键作用。在这里,他转向图形卷积神经网络(GCNs)来建立分析这些化合物的新技术。
- 了解数据团队如何开发新方法来满足业务需求 。在工业领域工作需要快速、创造性的解决复杂问题的方法。来自 Scribd 应用研究团队的 Jonathan Ramkissoon 向我们展示了他利用语义理解和用户行为对用户上传到平台的文档类型进行分类的过程。
- </35-software-development-laws-everyone-loves-to-ignore-5ebba515852d>打破某些规则(或制定新规则)。创造力往往在于掌握规则和以深思熟虑的、有意的方式变通规则之间的平衡。Semi Koen 收集了不少于 35 条适用于数据科学的软件开发传统智慧。许多是半开玩笑的,但所有这些都促使我们反思我们如何开展工作。
创造力对你意味着什么?你认为这是一个数据科学家的重要素质吗?考虑与 TDS 社区分享您的想法。
感谢你加入我们又一个顶级阅读旋风周,感谢支持我们的工作和我们的作者。
直到下一个变量,
TDS 编辑器
我们策划主题的最新内容:
入门
- 随着大数据的出现,在玫瑰日之前了解正确背景变得越来越重要
- 随机森林算法由 Carolina Bento 用一个真实的例子和一些 Python 代码解释
- 回归不连续设计简介作者:朱
实践教程
- 预测 2020 年美国大选使用后分层多级回归苏珊·李
- 自然语言处理入门:如何用陈莉莉对一个词的含义进行编码
- Mathias Gruber如何在 PyTorch 中进行有序回归/分类
深潜
思想和理论
- 多维标度由 Joos Korstanje
- 机器学习:科学还是炼金术?由塞缪尔弗莱德
- 什么是对抗性机器学习?由康纳奥沙利文创造
在数据角力上是只有我还是 R 打败了 Python?
R 如何简化数据争论操作

拉尔夫·卡蒂布在 Unsplash 上的照片
我是一名自学成才的数据科学家,花了近两年时间改变职业,在数据科学领域找到了一份工作。我用 Python 开始了我的旅程,对此我很高兴。
Python 有许多吸引有抱负的数据科学家的优势。加速和简化数据争论任务的丰富的第三方库只是其中之一。
我一直是 Python 数据科学生态系统的忠实粉丝。除了 Python,前阵子开始用 R 包。现在,我感觉 R 在数据角力上打败了 Python。
在本文中,我们将通过几个例子来演示 R 包如何简单无缝地执行典型的数据争论任务。我们将使用的包是数据表和字符串。
我们从导入包开始。如果您是第一次使用这些库,您需要先安装它们。值得一提的是,我使用 RStudio 作为 IDE。
# install
install.packages("data.table")
install.packages("stringr")# import
library(data.table)
library(stringr)
这里的“节拍”是什么意思,取决于你的预期。作为一个一直专门使用 Python 库的人,切换到 R 感觉更简洁地执行任务。
事不宜迟,让我们从例子开始。我们将使用 Kaggle 上的墨尔本房产数据集作为例子。fread 函数可用于通过读取 csv 文件来创建数据表。
melb <- fread(file_path)
文件路径取决于数据集在计算机中的位置。

前 5 行(作者图片)
对于每个例子,我将首先定义一个任务,然后提供解决方案。
任务:找到阿尔比恩房屋的地址、价格和日期。然后,按价格升序和日期降序对结果进行排序。
melb[Suburb == "Albion",
.(Suburb, Address, Price, Date)][order(Price, -Date)]

(图片由作者提供)
我们首先应用过滤器,然后指定要选择的列。对结果进行排序非常简单。order 函数与列名一起使用。减号表示按降序排序。
任务:根据指示更改以下各列的名称:
- 区域名称到区域
- SellerG 至卖方
setnames(melb, c("Regionname", "SellerG"), c("Region", "Seller"))
我们传递给 setnames 函数的第一个参数是表的名称。第二个和第三个参数分别是保存当前名称和新名称的因子。
任务:删除价格列中缺少值的行。
处理缺失值是数据争论过程中经常进行的操作。数据表包允许通过“is.na”功能消除缺失值。
melb <- melb[!is.na(Price)]
我们使用 is.na 函数的输出作为过滤的条件。“!”意思是“不”。因此,我们只取价格不为空的行。
任务:计算“u”类房屋在各区域的平均房价。
melb[Type == "u", .(avg_price = mean(Price)), by = "Region"]

(图片由作者提供)
第一部分是我们之前做过的过滤。第二部分是我们做列操作的地方。我们取价格列的平均值,并指定一个新的名称。最后一部分用于对行进行分组。
数据表包提供了操作顺序,用逗号分隔在方括号中。这样的标准更容易学习和执行复杂的操作。
任务:在前面的例子中,我们已经计算了每个地区的平均价格。假设我们想在更一般的层面上比较房价。例如,我们可以比较西部、北部和东部。
我们可以通过提取 region 列中的第一个单词来创建一个新列,并将其命名为 region group。然后,我们可以很容易地计算出每个群体的平均房价。
melb[, region_group := str_split_fixed(Region, " ", 2)[,1]][, .(avg_price = mean(Price)), by = "region_group"]

(图片由作者提供)
我们已经使用了 stringr 包中的 str_split_fixed 函数。拆分后的“[,1]”表达式表示我们想得到拆分后的第一部分。这个提取的部分被分配给一个名为“region_group”的新列。剩下的部分计算每组的平均价格。
结论
我们已经做了几个例子来演示如何用 R 包完成典型的数据争论任务。当然,R 提供了更复杂的操作。
我最喜欢 R 包的地方是它如何将多个小操作合并成一个简洁标准的操作。只用一行代码,我们就可以用 R 包完成很多事情。
本文的目标不是宣称 R 在数据科学库方面优于 Python。我只是想强调,对于数据争论任务,我更喜欢 R 而不是 Python。
感谢您的阅读。如果您有任何反馈,请告诉我。
从头开始构建可视化搜索引擎还值得吗?
Google Vision API 产品搜索缩短了开发定制模型的漫长旅程

作者图片
介绍
我在 2018 年推出了FootShirt.com,雄心勃勃地为喜欢收集球衣和/或对球衣所传达的历史和价值观充满热情的足球(英式足球)粉丝创造一个平台。
FootShirt.com 的视觉搜索引擎是最受欢迎的网站功能之一。本文将解释我如何构建视觉搜索引擎,从定制的机器学习模型开始,然后切换到谷歌视觉 API 产品搜索。
什么是视觉搜索引擎?
视觉搜索引擎是被设计成通过输入图像来搜索信息的搜索引擎。这些搜索引擎通常使用计算机视觉技术在大型数据库中搜索数字图像。
两个最著名的视觉搜索引擎(有时称为反向图片搜索)是 TinEye 和 Google Images 。虽然这些服务在寻找相似图片方面表现良好,但是它们不能用于有效地识别足球衫,因为它们没有与图片相关联的标签。
开发定制深度学习模型的漫长旅程
问题定义
识别球衣意味着找出球队、赛季和球衣类型(主场/客场/第三场等)..).人类很难识别一件球衣,因为球衣制造商(耐克、阿迪达斯、彪马等..)需要每年设计新的球衣,同时尊重球队的颜色和身份。因此,球衣之间的差异可以相当小,尤其是如果球衣赞助商保持不变。

比识别狗 vs 猫还难!(图片由作者提供)
打包照片与用户生成的图像
FootShirt.com 的视觉搜索引擎依赖于一个包含+7,000 张参考图片的数据库。谷歌对什么是参考图片或打包图片做了很好的解释:
好的参考图像清晰地展示了产品,并且图像中没有任何其他物体。好的参考图像的典型例子是“打包”图像。这些图像通常用于在产品页面或广告中向用户展示产品,通常在白色背景前拍摄。
视觉搜索引擎将用户拍摄的或从网络上获取的照片作为识别球衣的输入。因此,收集和标记用户生成的图像(或 有噪声的 图像)以包括在用于训练模型的数据集中是很重要的。这显然是一个繁琐的过程,许多用户生成的图像不足以进行模型训练,主要原因如下:
- 繁忙的背景
- 剪得很差的照片
- 图像中的其他产品
- 光线不好
模型:去噪卷积自动编码器
一旦我建立了一个包含近 20,000 张照片的数据集,我就开始选择模型。基于一些研究,我决定实现一个去噪卷积自动编码器。首先,我强烈推荐下面这篇解决类似问题的 Medium 文章:https://Medium . com/@ Soren Lind/a-深度-卷积-去噪-图像自动编码器-分类-26c777d3b88e
简而言之,去噪卷积自动编码器将提取重要的特征来识别球衣,因为网络将被训练输出我们给它的输入。但是我们将通过限制中间的层(通常称为潜在空间或瓶颈层)的大小来做到这一点。这个潜在空间代表了识别球衣的重要特征,可以很容易地使用库进行比较,例如aroy。

自动编码器(作者插图)
在参考图像上训练的常规自动编码器不会为我们的用例工作,因为视觉搜索引擎需要能够处理用户生成的图像。因此,用户生成的图像也将在训练中使用(因此 去噪 在去噪卷积自动编码器中)。

左:用户生成的图像(“有噪声”),中:参考图像,右:自动编码器重建的图像(作者插图)
我不会讲太多细节,但下面是我在培训中遇到的一些问题:
- 随着图像分辨率的提高,模型的精确度下降得很快。如前所述,球衣之间的差异可能很小,细节很重要。我选定了 256 x 256 的分辨率。
- 该模型需要许多层才能运行良好。
- 只有在对模型进行 400 个时期的训练后,准确度才开始可接受(+70%)。
因此,训练时间成为一个问题,因为模型需要训练许多小时甚至几天(使用谷歌 Colab 上的 GPU 或谷歌云平台上的英伟达特斯拉 V100/P100)。
然而,当我将数据集中的图像转换为 TFRecords 并开始在 Google Colab 上使用 TPU 时,我能够显著减少训练时间。

培训损失正在下降(作者插图)

用于训练的时期越多,重建的图像就越好(作者插图)
现实世界中的结果
在使用 Flask 部署了模型之后,是时候看看可视化搜索引擎在现实世界中的表现了。总的来说,结果是好的…

是啊,它的工作!搜索引擎正确地识别出了尤文图斯 2005-2006 赛季主场球衣(插图由作者提供)
但是不太好如下例所示:

模特过于强调运动衫的整体形状(长袖)(作者插图)
该模型的准确性不够好(在低 70%),视觉搜索引擎的维护也是有问题的,因为新的参考球衣需要编码,新的骚扰指数需要建立。
谷歌视觉 API 产品搜索来了
Google Vision API 产品搜索能否在足球衫上表现良好?我使用 Google Vision API Product Search这样的产品时,主要担心的是底层模型无法泛化,这使得它不适合正确识别足球球衣。不通过超级参数调整、虚拟机配置、重新培训等,我能获得更高的准确性吗..?
关于如何使用 Google Vision API 产品搜索,我不会讲太多细节,Google 提供的文档非常好。然而,我将解释快速推出可视化搜索引擎所需的主要步骤。除了浪费时间之外,开发定制模型是最重要的。许多应用程序模块,如图像处理、模型评估、Flask API 已经完成。这就是为什么推出一个基于谷歌视觉 API 产品搜索的视觉搜索引擎只需要几个小时的主要原因。
格式化批量导入 CSV 文件,并将图片上传到 Google 云存储桶。
最简单的开始方式是按照文档中提供的指南准备一个 CSV 文件用于批量导入。CSV 文件将用于同时创建带有参考图像的产品集和产品。利用 FootShirt.com 数据库和一些 Python 代码,创建 CSV 文件相当容易。

用于批量导入的 CSV 文件的摘录(图片由作者提供)
然后,您需要将图像和CSV 文件存储在 Google 云存储桶中。
创建产品集,创建多个产品及其参考图像
使用 Google 提供的 Python 代码示例和之前创建的 CSV 文件,您可以使用批量导入来创建包含产品的产品集。这可能需要 5 到 30 分钟,具体取决于您拥有的图像数量。
考验的时候到了!
谷歌再次提供了优秀的代码示例来搜索产品,或者在我们的例子中识别一件球衣。
通过使用谷歌视觉 API 产品搜索, FootShirt.com 的视觉搜索引擎现在表现更好(准确率在 90%左右)。我最喜欢的功能之一是 API 返回的分数或置信度(在括号中,在下面的截图中)。这允许设置一个阈值,低于该阈值时,您将让您的用户知道没有找到结果。
谷歌视觉 API 产品搜索似乎在很大程度上依赖于文本识别,或者在足球球衣识别的背景下,依赖于赞助商的名称。下面的例子表明赞助商的名字比球衣颜色更重要(第二次点击是白色球衣,而输入是黑色球衣,但是赞助商是相同的!)

这一次,视觉搜索引擎没有被长袖善舞所欺骗
我确认了我的直觉,提供了一张没有赞助商的球衣图片作为输入,而我知道参考图片上有赞助商的名字。 Google Vision API 产品搜索在寻找合适的比赛(AC 米兰 2018–2019 主场球衣)时遇到了更多困难,在没有赞助商的情况下作为第一和第二选择的相似球衣返回。

仍不完美,但很接近——前 3 次命中之间的置信度分别为 0.62、0.61、0.58(作者举例说明)
费用
关于成本的一句话。您需要为图像的存储和 API 调用的数量付费。

谷歌视觉 API 产品搜索——定价(作者插图)
对于像 FootShirt.com这样拥有数万张图片的网站来说,存储成本和预测成本是合理的(一个可视化搜索引擎每月不到 10 美元!).
结论
FootShirt.com 的视觉搜索引擎可以通过提供你的球衣图片来帮助你在FootShirt.com上建立一个数字收藏。但搜索引擎也可以用来在易贝买卖球衣之前识别球衣,或者识别你在网络或社交媒体上找到的球衣。
Google Vision API 产品搜索满足了我对识别足球球衣的视觉搜索引擎的所有要求:界面简单、预测速度快、成本低。
我鼓励你测试一下 FootShirt.com 的视觉搜索引擎。

FootShirt.com 的视觉搜索引擎正在运行(作者插图)
另一方面,我还没有体验完用机器学习模型来识别足球球衣。我的下一个项目可能是使用新的 OAK-1 进行实时推理。请继续关注,不要犹豫发表您的评论!

OAK-1:用于实时推理的 4K 相机(图片由作者提供)
花两年时间学数据科学值得吗?
有什么奖励?

数据科学可以说是当今最热门的职业,它可能会在很长一段时间内保持流行。
数据一直是一种宝贵的资产。1863 年,佛罗伦萨·南丁格尔创建了英国军队死亡原因图,考虑到当时的技术,这是一个惊人的数据可视化。
她的研究揭示了重要的见解,帮助他们在接下来的 10 年研究中将死亡率从 6.9%降至 1.8%。
数据的潜力并不是什么新鲜事。改变的是我们收集、传输、处理和存储数据的能力。用目前的工具可以很容易地处理大量的数据。我们拥有的数据越多,我们就能创建更好、更高效的模型。
所有这些改进导致了对数据科学的大量投资。因此,这一领域对人才的需求越来越大。
这就是为什么许多人从事数据科学职业的原因。即使在另一个行业有几年经验的人也在改变职业,成为一名数据科学家。
成为数据科学家需要什么是一个很难回答的问题。这绝对不是一件容易的事。你可能会花很长时间学习和研究。这需要时间、努力和奉献。
但是,值得吗?
我在标题里写了一个具体的期限,是两年。这就是我作为数据科学家找到第一份工作的花费。持续时间可能会有所不同,但不会短太多。
这个问题我问过自己好几次。我的回答包括两部分,即金钱奖励和非金钱奖励。
金钱上的回报是相当标准的,而且是基于大量的工作和薪水。一旦你掌握了所需的技能和知识,找工作就相对容易了,因为需求高。
我看不出这种需求在不久的将来会减少的任何理由。数据科学的范围是无限的。它可以应用于我们可以收集数据的任何流程或业务。因此,尽管一些工具被声称在一定程度上取代了数据科学家,但我仍然认为对数据科学家的需求将不断增加。所以你不要担心以后你的努力会不会白费。
关于薪水,规模取决于你住在哪里和你的经验,但数据科学生态系统中的工作通常报酬丰厚。流行的工作门户分享不同职业的平均工资。您一定注意到,数据科学家的平均工资总是名列前茅。
非金钱奖励不像金钱奖励那样标准,但它们同样重要。在这一类中我最看重的是工作满意度。是的,我做一些不那么有趣的工作,但是总的来说,我真的很喜欢我做的事情。
“套路”这个词离一个数据科学家的世界很远。每一个数据集都有可能给你一些有价值的见解,甚至让你大吃一惊。发现、分析和建模数据集的过程当然不是例行公事或无聊的任务。
另一个非金钱回报是永远有东西可以学习。它让你保持头脑清醒和健康。如果你在数据科学领域工作,总会有新的东西要学。
在数据科学生态系统中,新工具会很快推出。有些工具可以认为是旧的,但金的。然而,新的通常提供更好的性能和更多的功能。因此,你应该学习和实践它们,以保持竞争力。
这听起来像是一种负担,但我认为这种学习的要求是一种奖励。不是每个职业都给你这个机会。你可能要用同样的工具做同样的事情好几年。
长话短说,我绝对认为花“两年”学数据科学是值得的。事实上,两年后学习并没有停止。对于数据科学家来说,这是一个持续的过程。文章的标题本可以是“花两年时间找一份数据科学家的工作值得吗?”。
在你的情况下,挑战和回报可能不同。然而,如果你为达到目标付出了足够的努力,最终的结果会让你开心。
最后但同样重要的是,如果你还不是中级会员并打算成为其中一员,我恳请你使用以下链接。我将从你的会员费中收取一部分,不增加你的额外费用。
https://sonery.medium.com/membership
感谢您的阅读。如果您有任何反馈,请告诉我。
“液体”ML 是自动驾驶的答案吗?
自由生活的透明线虫如何为深度学习的下一步提供灵感

秀丽隐杆线虫是一种自由生活的透明线虫。一种大约 1 毫米长的蛔虫,生活在温带土壤环境中。它的神经系统由 302 个神经元组成,但它可以生成令人惊讶的复杂多样的模式。
另一方面,我们有具有数百万参数和数千节点的递归神经网络。尽管如此,他们的行为在训练阶段后保持不变。因此,它们对不断变化的环境的适应性是有限的。
在训练阶段之后,网络的行为保持不变。那么,当输入数据的特征在推理过程中发生变化时,会发生什么呢?我们如何解决这个问题?
为此,麻省理工学院计算机科学和人工智能实验室(CSAIL)的博士后 Ramin Hasani 等人的一项新研究检查了一类新的时间连续递归神经网络模型的属性。“液体”神经网络可以改变其方程的参数,并适应时间序列数据集的动态变化。
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
从自动驾驶到医疗诊断
我们训练一个人工神经网络的步骤是什么?概括地说,我们首先收集数据,将其分为训练集和测试集,并将训练集提供给网络。当然,还有其他步骤,如数据验证、处理、版本控制等。,但让我们保持简单。
接下来,该算法试图识别数据中的隐藏模式,我们评估它对测试集的新信息的概括程度。这就是全部的要点;我们训练神经网络并不是为了在训练过程中得到好的结果。对于我们的新生模特来说,现实通常是一个残酷的地方。
如果是雨天,而你的自动驾驶车辆的摄像头正在捕捉嘈杂的图像,会发生什么?
然而,在训练阶段之后,网络的行为保持不变。那么,当输入数据的特征在推理过程中发生变化时会发生什么呢?通常,模型的准确性会随着时间的推移而降低;我们称这个问题为“数据漂移”当我们希望模型适应输入数据流的变化时,数据漂移是一个真正的问题。
这正是哈萨尼和他的团队致力于解决的问题。如果是雨天,你的自动驾驶汽车的摄像头捕捉到嘈杂的图像,会发生什么?
作者展示了一个神经网络,它模拟了秀丽隐杆线虫神经元如何通过电脉冲激活和交流。他们使用一组嵌套的微分方程来允许参数随时间变化,从而为网络提供灵活性和流动性。这样,算法对数据分布中的意外变化更有弹性。
“液体”毫升的额外津贴
现在我们知道了什么是“液体”* ML 系统,并且它们对于意外的数据变化更加健壮。这个属性使它们成为时间序列挑战的完美候选。更重要的是,这些系统更容易理解,效率更高。*
首先,与其他时间序列分析方法相比,网络的规模很小,但每个神经元都更丰富。因此,由于节点数量少,任何人都更容易撬开深度学习的黑匣子,并要求神经网络突出其预测路径。
结论
似乎每个人都在试图让他们的神经网络架构更强大,将计算扩展到多个 GPU 加速器,并使它们适应巨大的数据集。哈萨尼和他的团队尝试了一种不同的方法;缩小规模,但使用更具表现力的节点,在工作中学习。
这只是一个开始,但却是一个令人兴奋的新想法。让我们看看它会把我们引向何方。
关于作者
我叫 Dimitris Poulopoulos ,我是一名为 Arrikto 工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请在 Twitter 上关注我的 Medium 、 LinkedIn 或 @james2pl 。此外,请访问我的网站上的资源页面,这里有很多好书和顶级课程,开始构建您自己的数据科学课程吧!
做一份好的数据科学简历就够了吗?
面试前你必须做的 4 件事。

由作者创建
对于任何职位来说,制作一份好的简历都是非常困难的。这种忙乱是合理的,因为你的简历是你给面试官的第一印象。它应该整洁、干净、易读,并且应该包含所有你专业做的事情。
当我在研究如何写一份好的简历时,我发现了很多可以用来写一份好简历的资源。如果你想要好的简历模板,你可以登录背面的。如果你的简历需要动作动词,你可以在这里访问(来自哈佛的文件)。
但问题是,是一份足够好的简历?
让我们来看一些统计数据。
- 平均来说,10%的求职申请会收到面试邀请。通过面试的人中,有 20%得到了这份工作。( Zety )
- 在被发现在简历上撒谎的 31%的人当中,65%的人要么没有被雇佣,要么被解雇。( Hrdive )
- 根据 Monster 的 2019 年招聘人员状况调查, 85% 的招聘人员表示,候选人在简历中夸大了技能和能力。(怪物)
招聘人员认为人们在简历中夸大其词的一个原因是候选人没有做好充分准备。想象一下你已经完成了一些你无法解释细节的课程、项目或实习。它不可否认地表明你并不像你在简历中提到的那样熟练。(担心的一大理由。)
很明显,即使你准备了一份好看的简历,你被选中的几率也很低。你还应该知道如何在面试中解释你的简历。这就是这篇文章的全部内容。让我们开始吧。
技巧 1:讲故事的艺术
对于你在简历中提到的任何项目或实习,在头脑中创造一个故事,从开始到结束。现在,当我们一起使用故事和项目时,大多数人会感到困惑。
让我们看一个例子。

作者图片
以上是一个大市场销售预测问题的工作流程。它从“了解您的数据”开始,然后是数据预处理、模型训练、评估矩阵和我学到的重要概念。
在您制定工作流程时,您应该牢记以下问题:
- 你对数据了解多少?存在哪些变量类型?需要哪种数据转换?
- 我是如何开始解决我的问题的?
是否需要特征工程?我需要更多数据吗? - 我面临的障碍是什么,我如何清除它们?
不平衡分类?违反假设?处理缺失值或异常值? - 我为什么选择这个算法?我是如何评价的呢?
- 我得到了什么结果?我能解释我的结果吗?
所有这些问题对面试都至关重要。招聘人员肯定会问这些问题,分析你解决问题的熟练程度,以及你解决任何问题的方法。
现在,让我们看看这种讲故事方法的好处:
- 一旦你在脑子里做了一个工作流程,你就自信了,你可以更好地解释你在项目中做了什么。你应该知道招聘人员问的大多数问题的答案。
- 这个工作流程会让你在面试中更有条理。此外,招聘人员会知道你对这个职位有多认真。
- 这个强大的工具还能让你知道可以问哪些问题。一旦你开始按时间顺序描述你的项目,你就可以预测在特定的时间点会出现什么问题。
- 数据科学就是从数据中推导出故事。所以,这种做法也会在面试后对你的职业生涯有所帮助。
同样,你可以用这种方法来解释你的实习经历或职业经历。从你发现问题的地方开始。需要什么样的头脑风暴来找到可行的解决方案?您是如何找到最佳解决方案的?然后描述你是如何实现的,最后是结果。
技巧 2:复习
在项目和实习结束后,一般来说,招聘人员会就你相关课程作业中提到的话题问一些技术问题。相关的课程可能包括你在大学里学习的课程、在线学习平台或任何其他来源。
如果你把所有的题目都过一遍,你就很难一遍又一遍的花很多时间。因此,当你第一次修改你的课程时,试着做一些简短的笔记。

作者图片
我修改过算法,在一些网络课程里教过。在准备面试的时候,我试着做简短的笔记。这对我帮助很大。一旦我做了这些笔记,并仔细阅读了几次,这些概念就在我的脑海中形成了。

作者图片
在上图中,我已经提到了决策树算法的所有内容。它包含了对面试至关重要的所有基本定义。
一旦你做到了这一点,搜索面试中关于这个话题/课程的一般性问题。你会发现大量的资源。准备好所有这些材料肯定会增加你对题目的理解。
提示 3:时间表
我的简历包含了我的课程、职业经历、项目、课外活动等等。准备一份简历,你需要一些专门的时间。
制定时间表不是一件容易的事情。你有几周时间来复习过去几年学过的所有话题。你可以按照下面的步骤做一个时间表。
- 首先列出所有你想复习的题目。
- 试着根据你在每个题目上的强项来排序。你弱项的题目一定要排在最前面。面试日期越来越近,时间就越来越快。因此,当你有足够的时间时,分类将帮助你处理脆弱的话题。即使你可以留下一两个字符串主题,也没关系。
- 选择一个或几个固定的时间来复习所有的东西。
- 最后也是更困难的一步是开始。所以,开始复习吧。
如果你有计划,你可以在给定的时间内获得更多。我在面试前 20 天就开始做这些事情了,还有我的常规课程。这是一个紧张的过程。但最棒的是,我可以在项目和相关课程之间建立联系。我可以利用我在以后的课程中掌握的不同技术产生新的想法。
提示 4:你在简历中提到但从未提及的事情
正如统计数据显示的那样,有很多人在简历中撒谎。我强烈建议你不要在面试中这样做,因为招聘人员什么都知道。请只强调那些你曾经做过的事情。
但是到了某个 程度,你可以补充一些你没有做过的事情。例如,在解决一个预测建模问题时,您可能会运行 xgboost 算法,并在简历中提到结果,而对该算法没有深入的了解。
招聘人员明白你可能不知道所有的事情。不可以!他们希望看到的是,你所做的,你是以最大的诚意去做的。今天,公司需要真诚和努力工作的人。技术方面是可以教的,但真诚的品质是教不来的。
总结性的新闻报导
工作安排是一个非常密集的过程。你必须在 45 分钟的时间里展示你多年来所做的一切。45 分钟可以改变你的一生。我从这个过程中学到的是:
- 制作一份好的简历是不够的。你应该知道简历中的每一个术语。这使我们能够在有限的时间内展示我们的整个旅程,并产生更大的影响。这也有助于我们以最大的诚意向招聘人员证明我们简历的每一个方面。
- 有了适当的计划,你可以实现任何事情。任何事情!
一旦你经历了这个过程,我相信你会对你的选择更有准备和信心。面试不仅是知识的游戏,也是气质的游戏。
微服务架构是机器学习部署的最佳选择吗?
了解整体架构和微服务架构之间的差异

埃里克·普劳泽特在 Unsplash 上拍摄的照片
介绍
机器学习部署趋势正朝着敏捷性、可扩展性、灵活性和向云计算平台转变。随着数据量和需求的增加,以前使用中央团队和整体架构管理和部署应用程序的组织在扩展时遇到了瓶颈。因此,微服务架构正在成为组织的一种流行方法,并已被网飞、亚马逊、优步、Grab 等大型组织采用。
在本文中,我们将了解:
- 什么是整体架构?
- 什么是微服务架构?
什么是整体架构?

单体建筑(图片由作者提供)
整体架构被认为是构建应用程序的传统方法。单一应用程序由中央数据团队从一个集中的位置进行管理,这意味着所有流程都作为一个统一的单元运行。
通常,整体式应用程序使用一个可以由多个开发人员开发的大型代码库。如果其中一个开发人员想要对代码进行修改,他们将不得不访问相同的代码库并对整个堆栈进行修改。如果代码库变得越来越大,诸如添加新特性之类的更改最终会变得更加复杂。最终,应用程序将不再是可伸缩的,因为复杂性增加了,新的特性也不容易添加。此外,由于所有的进程都是相互连接和相互依赖的,所以单个进程的故障将导致整个应用程序的故障,并且必须重写整个应用程序。
然而,单片应用仍然具有一些优点,例如:
- 易于部署 —因为所有东西都在一个应用程序中,所以您只需要处理一个特定的文件。
- 易于测试&调试— 由于一切都在一个不可分割的单元中,端到端测试可以更快地完成。
- 易于开发 —由于单一应用一直是传统方法,任何数据平台/工程成员都能够开发单一应用。
什么是微服务架构?

微服务架构(图片由作者提供)
虽然我们知道单片架构是基于单个统一单元的构建,但微服务架构是高度分散的,它将单个大型应用程序/单片应用程序分解为一组较小的独立单元。每个微服务将专注于一个特定的功能,并通过 API(应用程序接口)与其他微服务进行通信。
让我们来看看为什么机器学习模型经常被选择部署为微服务的优势:
- 可扩展 —每个微服务都是独立的组件,运行自己的流程,独立部署。由于每个服务都是独立部署的,因此特定的微服务可以独立于整个应用进行扩展。
- 敏捷性 —微服务应用中的故障只会影响特定的服务,而不会影响整个应用。因此,修复和调试将在特定的微服务上完成,而不是暂停和修复整个应用程序。
- 灵活性 —团队成员不受用于创建和部署微服务的编程语言或工具的限制,并且可以为每个微服务拥有不同的框架。此外,如果有先前开发的代码,团队成员可以利用这些代码,而不是重新构建它们。
- 自主性 —使用微服务架构方法进行开发允许更多的团队自主性,因为每个成员都可以专注于开发专注于特定功能的特定微服务,例如每个成员都可以专注于构建专注于机器学习部署过程中特定任务的微服务,例如数据摄取、功能工程、数据验证、模型评分等。
- 易于理解 —由于事物被分割成更小的组件,单个微服务应用程序更易于理解和管理,因为通常一个微服务专注于一项特定的任务。
微服务架构现在对你来说似乎是最完美的方法,但尽管如此,也有缺点。以下是一些已确定的缺点:
- 更高的成本 —与单片架构相比,微服务通常更昂贵,因为它需要更多的资源。因为每个服务都是相互独立的,它需要自己的 CPU/实例和环境。此外,该公司将需要雇用或提供培训,以拥有一组能够理解、开发和维护微服务的熟练团队。
- 复杂性 —虽然随着代码库的扩大,整体架构可能会变得复杂,但微服务架构可以由几十个或数百个不同的服务组成(例如:优步已经发展到拥有超过 2200 个微服务),这些服务需要无缝和安全地通信。有了这么多的微服务,调试会变得更具挑战性,因为问题跟踪不会那么简单。
- 安全 —微服务通常部署在云平台上,需要通过网络相互通信,这带来了安全挑战,因为这为外部人员获得系统访问权限创造了机会。
结论:
根据业务/项目的场景,如果组织刚刚形成,团队很小,项目是轻量级的——可以使用整体架构方法。除此之外,对于构建有许多成员的复杂应用程序的大型组织来说,微服务架构方法将是更好的选择。最后,微服务架构可能最适合那些需要在敏捷开发过程中快速开发且团队成员众多的组织。
感谢阅读,我希望你喜欢这篇文章!
参考和链接:
[1]https://aws.amazon.com/microservices/
https://eng.uber.com/microservice-architecture/
[3]https://solace . com/blog/micro services-优缺点/
[4]https://www . n-IX . com/micro services-vs-monolith-which-architecture-best-choice-your-business/
MLOps 是不是把软件工程师落下了?
行业笔记
MLOps 为数据科学家提供了大规模的人工智能,但我们的筒仓仍然存在,这是一种耻辱。

由 Anthony Intraversato 在 Unsplash 上拍摄
我们在哪里以及我们是如何来到这里的
几年前,Venture beat 报告称只有 13%的数据科学项目进入生产。首要原因?公司雇佣了数据科学家,但忽视了为他们的工作提供适当的支持。他们将组织中其他部门的数据科学家隔离开来,给他们一些 API 密匙,并让他们编织黄金。这一点非常失败,因此,在深度学习革命和新的人工智能夏天的迷雾中,企业留下来想知道他们如何以及为什么不能分一杯羹。
反思为什么这些数据科学项目没有产生价值直接导致了 MLOps 的发展。通过流程和工具的结合,MLOps 承诺让您的数据科学团队能够更快地构建、测试、交付和测量模型,从而提高效率。新的角色,如机器学习工程师,甚至发展到帮助建立和维护 MLOps 基础设施。
MLOps 没有解决的问题
不要误会我的意思,MLOps 是一种集成人工智能的强大技术,但它是对孤立的数据科学家的回应,这些科学家原本应该嵌入产品开发团队。尽管 MLOps 带来了很多好处,但它并没有(也不是为了)明确解决这个核心问题筒仓。
孤岛是许多组织中的一个系统性问题,尤其是在大规模或试图大规模发展的组织中,它通常来自部门化和专业化。不幸的是,MLOps 可能会加剧这个问题:一旦数据科学团队有了自己的流程和专门的堆栈,他们就不太可能与其他产品团队很好地集成。
因此,虽然 MLOps 正在加快他们推出新模型的能力,但 silo 正在扼杀他们与其他部门合作并找到新的人工智能问题来解决的能力。他们被困在已经有数据和集成的同一个问题上。换句话说,增值是长尾:他们通过提高模型性能来追逐价值,而不是寻找新的人工智能机会来影响业务。
一个例子:软件工程师
孤立的人工智能专业知识最明显的例子是软件工程师。我认识的每个软件工程师都对人工智能非常感兴趣。每一个。
这种热情是可以理解的:人工智能技术可以为他们的应用程序添加效率、个性化或魔法元素,否则这些元素是不可能构建的。可以让他们的软件变得更好,集成起来也很好玩。
那么为什么没有更多的软件工程师去实践 AI 呢?为什么我们把它留给数据科学家,而构建 MLOps 让他们去做呢?
当你考虑软件工程师的教育时,这尤其令人烦恼。看看任何计算机科学学士课程,你会发现人工智能课程就在那里,还有数据结构、算法、设计模式和架构。那么,为什么我们让软件工程师的角色卷入这些核心学科,而实际上却忽略了他们教育中的人工智能部分呢?为什么我们继续问渐近复杂度而不是期望值的面试问题?
很容易通过说软件工程师在机器学习、统计学或数学原理方面没有足够的实践或专业来实践人工智能来原谅这一点。但这不是真的:正如我们从上面的 13%问题中了解到的那样,将人工智能反向传播到船上需要更多的能力。看看特雷维尔等人的《MLOps 简介“m lops 的人”一章就知道了。艾尔。:运送 AI 需要一个团队的人,这个团队包括很多不同类型的软件工程师。换句话说,让人工智能进入产品需要的技能不仅仅是构建好的模型,而这些技能中的许多已经被软件工程师磨练出来了。
让工程师成为人工智能的敲门砖
MLOps 确实让你眼前一亮,它有一个庞大的数据科学家团队,渴望制作出一个又一个深度学习驱动的赚钱模型。但我接触过的大多数公司都没有,尤其是初创公司。
为什么?招聘重点。你必须拿出一个产品,收集数据,然后才能利用它来增加价值。
因此,这些公司充满了软件工程师,伟大的软件工程师,他们想知道为什么他们被抛在人工智能革命的勇敢新世界的后面。与此同时,这些公司的领导人担心如何提高人工智能能力以保持竞争力。
因此,我的观点是:领导者应该让软件工程师能够将人工智能集成到他们的产品中。减轻工程师的 FOMO,提高组织的人工智能能力。将数据科学家(如果有)整合到您的产品团队中,并使用 MLOps 来提高效率,而不是分裂团队。
TL;速度三角形定位法(dead reckoning)
MLOps 虽然功能强大,但目前只为数据科学家设计。如果你观察任何 MLOps 产品,这是显而易见的:它们都将 Juptyer 笔记本作为主要用户界面。结果,数据科学家与软件工程师隔离开来。这是一种浪费:软件工程师是唯一适合将人工智能融入产品的人,他们渴望参与进来。所以,我请求你,在你投资 MLOps 之前,想想你的组织,问问它是否会加速你的人,或者只是孤立他们。
如果你喜欢这个故事,请考虑通过请我喝咖啡或者通过我的推荐注册媒体来支持我。
我的业务为人工智能做好准备了吗?
决定你是否应该冒险的快速指南!

泰勒·弗兰塔在 Unsplash 上的照片
快速浏览最著名的技术门户网站似乎有一个共同的主题。看哪,人工智能(AI)的崛起近了!到目前为止,每个人都听说过人工智能,每个人都以某种形式使用它,但很少有人理解它。对我们来说幸运的是,一个人不需要成为人工智能科学家才能从中受益。当然,有了这些信息在手,企业主并不聪明,因为他们仍然不知道从哪里开始。他们中的大多数人可能已经阅读了关于人工智能令人难以置信的好处的不同文章,但仍然怀疑他们是否能在自己的组织中使用它。
一个很好的起点是执行人工智能准备审计。在向人工智能解决方案投入资金和资源之前,决策者需要了解他们的组织是否准备好开始富有成效的转型过程。因此,开展审计是为了评估组织的基本、运作和变革准备情况。通过审计,组织将更好地了解他们的公司及其在人工智能增强的生态系统中的潜力,从而指出他们的不足,并在未来为他们节省大量资金。人们不应该羞于进行这种审计,因为它可以免费进行,而且所涉及的过程相对简单。本质上,它评估 4 个关键组成部分;转型、技术、组织和环境准备就绪。但是不要让这些术语吓倒你;让我们逐一解释。

转型准备度考察你的组织是否对创新变革持开放态度。这一部分很重要,因为研究表明,新技术的相对优势与创新的接受度之间存在正相关关系。通过它,我们确定人工智能是否可以通过降低成本、开辟新机会、提高效率甚至增加收入来改善公司的运营。它还将深入研究人工智能是否会通过帮助员工完成日常任务来给你带来竞争优势。最后,它将检查人工智能是否与组织的战略方向一致,从而获得最高管理层的认可。

马文·迈耶在 Unsplash 上的照片
技术准备检查组织是否有技术组件来确保一个成功的人工智能项目。首先,必须存在特定的需求。人工智能不是你撒在现有流程上的魔法粉。如果人工智能不能给组织过程带来任何优势,那就不要使用它。正因为如此,任何变革过程都必须经过精心规划,以确保组织真正从中受益。确定这一点的最好方法是看看其他地方现有的人工智能应用程序,看看它们是否可以应用到你的业务中。如果是这样的话,那么最重要的就是看现有的数据。今天,数据被认为是新的石油,为我们大多数人工智能算法提供燃料。该组织需要评估其拥有的信息,不仅从技术角度,而且从法律角度检查这些信息是否可以被修改和使用。

组织准备度着眼于组织的开放性,相对于新技术的采用。有趣的是,我们可以通过分析公司规模、管理风格和其他变量来预测转型是否会成功。一个至关重要的因素是最高管理层对此类计划的看法。管理团队是否致力于变革,有清晰的愿景和适当的资金支持?该组织还必须确定它是否拥有合适的资源,包括硬件和人力资源。

由 Katie Moum 在 Unsplash 上拍摄的照片
环境准备检查外部因素,如法规和竞争,这是采用新的创新时的关键因素。当一个人环顾四周,检查类似的组织正在做什么,如果他们已经跳上了人工智能的潮流,那么这是一个很好的迹象,表明市场上可用的解决方案相对成熟。这也应该作为一个警钟,因为竞争对手可以很快获得相对于创新较少的公司的竞争优势。因此,一旦组织决定冒险一试,它需要建立一个专注于影响外部利益相关者的人工智能战略。这可能通过向他们提供改善的客户体验或加快人工智能的决策过程来实现。可能性是无限的。当然,那些决定冒险的公司也需要做一些功课。他们需要检查现有的政府法规、政策和激励措施,以便从这种转变中获得最大利益。他们还需要查看通过第三方供应商提供的人工智能服务,这将允许他们立即部署新的解决方案。
当然,说起来容易做起来难,如果你仍然不知所措,为什么不参加免费的人工智能自我评估测试。该测试旨在询问相关问题,最后,它还会发送一封电子邮件,强调需要更多工作的领域,并提出前进的方向。所以不要害怕冒险。人工智能将永远存在,它将永远改变我们生活的世界;你不能忽视它,但可以很容易从中受益。
如果你喜欢这篇文章,并想与我联系,请这样做🐦 碎碎念 ,🔗LinkedIn,📷Instagram或者😊 脸书 。
https://medium.com/dataseries/the-future-of-governments-267476e790a8
阿列克谢·丁力教授 是马耳他大学的 AI 教授。二十多年来,他一直在人工智能领域进行研究和工作,协助不同的公司实施人工智能解决方案。他的工作被国际专家评为世界级,并赢得了几个当地和国际奖项(如欧洲航天局、世界知识产权组织和联合国等)。他已经出版了几本同行评审的出版物,并成为马耳他的一员。由马耳他政府成立的人工智能特别工作组,旨在使马耳他成为世界上人工智能水平最高的国家之一。
对于您的分析用例,实时处理值得吗?
实时技术非常强大,但是它们会显著增加数据架构的复杂性

照片由 Victor Wang 从 Pexels
与批处理相比,实时数据管道提供了一个显著的优势——消费者可以更快地获得数据。在传统的 ETL 中,在明天的夜间作业完成之前,您无法分析今天的事件。如今,许多企业都依赖于在几分钟、几秒钟甚至几毫秒内即可获得的数据。借助流技术,我们不再需要等待预定的批处理作业来查看新的数据事件。新数据进入时,实时仪表板会自动更新。
尽管有这些好处,实时流还是给整个数据处理、工具甚至数据格式增加了许多额外的复杂性。因此,仔细权衡改用实时数据管道的利弊至关重要。在本文中,我们将研究几个选项,以最少的架构更改和维护工作获得实时范例的好处。
传统方法
当您听说实时数据管道时,您可能会立即想到 Apache Kafka、Flink、Spark Streaming 和类似的框架,这些框架需要大量知识来操作分布式事件流平台。这些开源平台最适合以下场景:
- 当您需要持续摄取并合理处理大量实时数据时,
- 当您预期多个生产者和消费者并且您想要分离他们的通信时,
- 或者当您想要拥有底层基础架构时,可能需要本地 ( 例如合规性)。
虽然许多公司和服务试图促进底层分布式集群的管理,但该架构仍然相当复杂。因此,您需要考虑:
- 你是否有足够的资源来运营这些集群,
- 您计划使用该平台处理多少数据,
- 增加的复杂性是否值得努力。
在接下来的几节中,如果您的实时需求无法证明自我管理的分布式流媒体平台所增加的复杂性和成本是合理的,我们将研究替代选项。
亚马逊 Kinesis
AWS 很久以前就意识到了客户在管理消息总线架构方面的困难(2013 年)。因此,他们提出了 kine sis——一个试图让实时分析变得更容易的服务系列。通过利用无服务器 Kinesis 数据流,您可以在 AWS 管理控制台中点击几下来创建数据流。一旦配置了估计的吞吐量和碎片数量,就可以开始实现数据生产者和消费者了。即使 Kinesis 是无服务器的,您仍然需要监控消息大小和碎片数量,以确保不会遇到任何意外的写限制。
在我的上一篇文章中,你可以找到一个 Kinesis 生产者(源)使用 Python 客户端向 Kinesis 数据流发送数据的例子,以及如何通过利用 Kinesis 数据消防软管交付流向 S3 ( 消费者/目的地)连续发送微批数据记录。
或者,为了使用来自 Kinesis 数据流的数据,我们可以:
- 使用 Kinesis 数据分析汇总和分析数据,
- 使用 Apache Flink将这些数据发送到 Amazon Timestream 。
与将数据直接发送到所需应用相比,使用 Kinesis 数据流的主要优势在于延迟和解耦。Kinesis 允许您在流中存储数据长达七天,并且有多个消费者可以同时接收数据。这意味着,如果一个新的应用程序需要收集相同的数据,您可以向流程中添加一个新的消费者。由于 Kinesis 架构级别的解耦,这个新的消费者不会影响其他数据消费者或生产者。
亚马逊时间流
如前一节所述,Kinesis 的主要优势是解耦。如果你不需要多个应用程序定期从流中消耗数据,你可以通过使用 Amazon Timestream 大大简化这个过程——一个无服务器时间序列数据存储,允许你在附近的实时分析数据。底层架构足够智能,可以首先将数据接收到内存存储中,以便快速检索实时数据,然后根据指定的保留期自动将“旧”数据移动到更便宜的长期存储中。更多关于 Timestream 的内容,请看这篇文章。
为什么您会使用时间序列数据库来存储实时数据?任何新的数据记录都会在特定时间进入流。您可能会跟踪价格随时间的变化、传感器测量、日志、CPU 利用率——实际上,任何实时流数据都是某种时间序列。因此,考虑使用像 Timestream 这样的时间序列数据库是有意义的。该服务的简单性使其非常有吸引力,尤其是如果您想使用 SQL 检索数据进行分析的话。
当将 Timestream 的 SQL 接口与 Kinesis 数据分析中可用的接口进行比较时,Timestream 显然是赢家。Kinesis SQL 相当晦涩,引入了很多特定词汇。相比之下,Timestream 提供了一个直观的 SQL 接口,其中有许多有用的内置时间序列函数,使得基于时间的聚合( ex。分钟或小时时段)容易得多。
旁注:不要在 Timestream 中的查询末尾使用分号。如果你这样做,你会得到一个错误。
演示:使用 Python 实时摄取到时间流中
为了演示 Timestream 如何工作,我们将把加密货币的价格变化发送到 Timestream 表中。
让我们从创建一个时间流数据库和表开始。我们可以从 AWS 管理控制台或 AWS CLI 完成所有这些工作:

上面的代码应该在您的 AWS 区域中创建一个数据库。确保使用其中一个有时间流的区域。
补充说明:查找任何 AWS 服务可用地区的最简单方法是查看定价页面:https://aws.amazon.com/timestream/pricing/。
现在我们可以创建一个表。您需要指定您的内存和磁存储保持期。

我们的数据库和表就创建好了。现在我们可以从 Cryptocompare API 获得最新的价格数据。这个 AP 提供了许多有用的端点来获取关于加密货币市场的最新信息。我们将专注于获取选定加密货币的实时价格数据。

我们将获得以下格式的数据:
{'BTC': {'USD': 34406.27},
'DASH': {'USD': 178.1},
'ETH': {'USD': 2263.64},
'REP': {'USD': 26.6}}
此外,我们需要将这些数据转换成适当的 Timestream 格式,具有时间列、度量和维度。下面是我们可以用来每 10 秒钟接收一次新数据的完整脚本:https://gist.github.com/d00b8173d7dbaba08ba785d1cdb880c8。

就是这样!最耗时的部分是定义您的维度和度量(第 21–44 行)。您应该小心度量和维度的设计:使用 Timestream,您只能查询单个表中的数据。不允许表之间的联接。因此,在开始将数据接收到 Timestream 之前,提前考虑您的访问模式非常重要。
这是数据最终的样子。请注意,摄入时间以 UTC 表示:

AWS Timestream:在查询控制台中浏览结果—作者图片
我们现在可以轻松地将 Timestream 连接到 Grafana,实现近乎实时的可视化。但那是另一篇文章的内容了。
永无止境的剧本
在上面的时间流例子中,在单个进程中运行,我们使用了使用while True定义的永无止境的循环。对于一直接收数据的简单服务来说,这是一种常见的方法,通常作为后台流程或容器编排平台中的服务运行。
按分钟计划的作业
连续运行脚本的替代方法是计划每分钟运行一次的服务。这种方法的好处是,它允许您将这个接近实时的过程作为批处理作业来处理,这简化了您的架构。你可以把它想象成一个反向的 Kappa 架构:当 Kappa 以与实时数据相同的方式处理批处理时(流优先方法),这种方法把实时数据流(批优先方法)分成微批处理。
现在,我们仍然大约每 10 秒钟接收一次数据,而不是while True,但实际过程是每分钟执行一次,这使我们能够跟踪哪些运行是成功的,并且不依赖于单个作业运行的健康状况:

没有“正确”或“错误”的方法。这种方法的主要目的是将接近实时的摄取作为批处理作业来处理。这里有一个完整的要点:https://gist.github.com/d953cdbc6edbf8b224815cc5d8b53f73。
你应该选择哪个选项?
以下问题可能有助于您针对您的用例做出正确的决策:
- 您希望使用实时流解决哪些问题:是异常检测、警报、产品推荐、动态定价算法、跟踪当前市场价格、了解用户行为?在头脑中有一个特定的用例可以帮助您确定适合这项工作的工具,尤其是因为市场上有许多专门的工具。
- 在您的使用案例中,哪个延迟是可接受的?如果您的数据在收到事件或数据流 1 分钟后可用于分析,可以吗?或者相反,您需要一毫秒的延迟,因为否则,这些数据将不再是可操作的?
- 你有多少资源 ( 员工和预算)来维持你的平台运营?构建自己的 Kafka 集群、使用一些托管服务或者 Amazon Kinesis 或 Amazon Timestream 等无服务器选项是否有意义?
- 你打算如何监控和观察你的数据流的健康状况?如果您利用无服务器技术, Dashbird 可能是一个很好的选择,可以轻松监控您的无服务器 AWS 堆栈,并通知您有关故障和异常的信息。
- 教你的团队如何使用这个特定的平台需要多少培训?
- 哪些数据源需要实时摄取,即数据生产者?
- 您希望从哪个目标数据存储库 ( 数据湖、数据仓库、特定数据库)中检索该数据,即数据消费者?您希望如何检索这些数据——通过 SQL、Python,还是仅通过分析仪表板?
- 您希望以哪种方式(基于架构的)处理这些数据? Kappa,Lambda ,或者其他架构值得考虑区分实时和批量?
结论
最终,这取决于您尝试使用实时流技术解决的问题、问题的规模以及可用的资源。在许多情况下,一个简单的分钟批处理作业可能就足够了。它允许有一个单一的架构来满足所有的数据处理需求,并且在数据生成后几分钟甚至几秒钟内就可以获得数据。
对于其他场景,Kinesis 数据流或 Amazon Timestream 可以提供简单而有效的方法来添加(近)实时功能,而只需很少的维护工作。最后,如果你有知道如何操作 Kafka、Flink 或 Spark Streams 的员工,如果你想拥有自己的基础设施而不依赖云提供商,这些会很有帮助。像往常一样,思考手头的问题将有助于评估权衡,并为您的用例做出最佳决策。
感谢您的阅读!
机器人过程自动化(RPA)真的适合任何人吗?
揭示在将这种流行的软件技术应用于业务流程自动化之前一些未知的考虑因素。

机器人过程自动化(RPA)最大的吸引力在于其标榜的易用性。这种软件技术成功的目标群体是人力资源、财务等职能部门。,仅仅是因为这样的支持功能被认为不太懂技术。从而使完美的候选人尝试一种工具,这种工具是为任何想要加入“自动化”潮流的人准备的,并探索通过减少手动的、重复的任务来带来一些生产率的提高。基于我对这种技术的使用,我提出了我对它的简单性的看法,以及那些探索其实现的人需要注意的潜在警告。

什么和什么时候
有很多在线资料可以用来详细说明这项技术的功能、它的潜在用例以及新手的实现方法(为采用这项技术所做的市场营销工作令人印象深刻!).简而言之,我的摘要是,它是一个自动化工具,采用“软件机器人”的形式。它可以简单地是多出来的一双手,来承担做平凡的和重复的任务的角色,根据预先定义的逻辑执行动作。拿走那些吸干人类创造力的“肮脏、无聊”的工作。
如果你执行的任务符合上述描述,反思一下你的日常工作。让我们考虑一个例子——假设你的任务是在网页上频繁地执行一些动作。完成这项任务的典型尝试包括参考利益相关者的文档,并将这些文档的更新反映到网页上。并且每次从利益相关者那里收到新的更新时,您都在重复相同的步骤。接下来,让我们看看 RPA 如何在此示例场景中提供帮助。

怎么做
与任何项目管理一样,解决方案工作始于从头到尾制定详细的步骤顺序,将任务分解为解决方案。
RPA 最受推崇的功能之一是它能够根据用户的动作记录屏幕上的活动。根据我的经验,让我与你分享一下,虽然当我们只处理一个应用程序(例如浏览器)上的动作时,这个功能很好,但一旦你开始从一个应用程序跳到另一个应用程序,捕捉你的多应用程序动作就变得相当复杂了。在记录的最后,重新运行记录的工作流来进行测试通常会导致错误,并且您最终会得到一个不完整的自动化流程。
根据我在这种情况下的经验,我可以保证的解决方案是挑选执行所需操作的适当活动(在 UiPath 上称为 UI path,用于构造 RPA 解决方案的 UI)。在 UiPath 上,RPA 解决方案构建为一个流程图,从第一步到最后一步构建一个又一个操作(/activity)。要为我们上面的示例场景构建 RPA 工作流,同时记录一个应用程序上的操作,就像在网页上一样,肯定是一种可行的方法。在记录结束时,UiPath 将这些动作转换成连续的活动,以测试准确的捕获。然后你所要做的就是把剩下的拼图拼在一起,让机器人把网页动作和外部网页动作连接起来。仔细考虑一下,我们将重复这些步骤,直到所有更新都从文档转移到网页,并再次对新文档重复相同的步骤序列——这在编码领域是“循环”的典型用例因此,将该技术特有的内置便利性与编码基础知识相结合,可以极大地增强您构建强大而健壮的 RPA 解决方案的能力。

安妮在 Unsplash 上的照片
RPA 是所有自动化需求的最终解决方案吗?
简单的答案是否定的。正如我在我的上一篇文章中详述的那样,仅仅因为应用程序的数量是无限的,就提高编程技能的重要性,我仍然坚持我的立场。此外,我认为 RPA 并不适合所有人,因为它在分支到复杂任务时会面临挑战。也就是说,在单个应用程序内简单的“记录&重复”式自动化方面,RPA 肯定有它的优势,所以它的应用程序真的取决于。
令人欣慰的是,在构建 RPA 解决方案时,帮助热线肯定是可用的,可以从在线社区寻求帮助/提示(向 Google 致敬!).此外,鉴于其广泛的市场营销,RPA 通常也会为大型本地应用程序提供支持网络。
尽管如此,最大化该工具实际上可以归结为如何根据您的需求和业务任务来塑造它,应用基本的编程知识,而不仅仅是依赖花哨的 UI 技巧。我当然会鼓励尝试一下,体验一下这项技术能提供什么。最终,根据手头的业务任务,它将成为您的另一个武器库。
当数据集符合内存时,是否有比熊猫更好的东西?
探索 Vaex,Dask,PySpark,摩丁和朱莉娅

图片作者。
表格格式仍然是最典型的存储数据的方式,可以说没有比 python 的熊猫更好的工具来探索数据表了。尽管熊猫的能力范围很广,但它也有局限性。在这种情况下,你必须选择另一种选择。然而,如果数据集能很好地适应你的记忆,放弃熊猫而使用另一个工具有意义吗?
Pandas 是一个方便的表格数据处理器,提供了多种方法来加载、处理和导出数据集为多种输出格式。熊猫可以处理大量的数据,但它受到你的电脑内存的限制。数据科学有一条黄金法则。如果数据适合内存,使用熊猫。这个规则还有效吗?
当数据适合您的电脑内存时,使用熊猫
熊猫替代品仅在以下情况下被推荐:
- 熊猫的加工过程很慢
- 数据不适合可用内存
让我们在一个中等规模的数据集上探索其中的几个替代方案,看看我们是否能获得任何好处,或者证实你只是使用熊猫,毫无疑问地睡觉。
你可以在 GitHub 上查看完整的代码
- pandas _ alternatives _ POC . ipynb—探索 dask、spark、vaex 和 modin
- julia_POC.ipynb —探究 julia 和 julia 性能测试
- Performance_test.py —运行 python perf。控制台中的测试
- Results _ and _ charts . ipynb—处理性能测试日志并创建图表
熊猫替代品
让我们首先探讨反对熊猫替代品的论点。
- 它们不像熊猫那样普遍
- 文档、教程和社区支持较少
我们将逐一回顾几个备选方案,并比较它们的语法、计算方法和性能。我们再来看 Dask 、 Vaex 、 PySpark 、 Modin (全部用 python)和 Julia 。这些工具可以分为三类:
- 并行/云计算— Dask、PySpark 和 Modin
- 内存高效— Vaex
- 不同的编程语言— Julia
数据集
对于每种工具,我们将使用 Kaggle 欺诈检测数据集来比较基本操作的速度。它包含两个文件train_transaction.csv (~700MB)和train_identity.csv (~30MB),我们将加载、合并、聚合和排序这两个文件,看看性能有多快。我将在我的 4 核 16MB 内存的笔记本上进行这些操作。
我们将加载、合并、分类和汇总数据
Dask 并行化数据帧
Dask 的主要目的是并行化任何类型的 python 计算——数据处理、并行消息处理或机器学习。如何分散计算的方法是使用计算机集群的能力。即使在单台 PC 上,利用多个处理内核,计算也可以运行得更快。
Dask 处理数据帧的模块方式通俗地称为数据帧。它的强大源于并行性,但您必须意识到这是有代价的:
- Dask API 没有熊猫的丰富
- 结果必须具体化
Dask 语法
Dask 的语法和熊猫很像。

Pandas 和 Dask 的语法比较。作者图片
如您所见,两个库中的许多方法完全相同。您会注意到 dask 基本上缺少排序选项。那是因为平行排序比较特殊。Dask 只提供了一种方法,那就是set_index。索引按定义排序。
这个想法是使用 Dask 来完成繁重的工作,然后将减少的和更小的数据集移动到 pandas 进行最后的润色。这就引出了第二个警告。Dask 结果必须用.compute()命令具体化。
正如您将在 PySpark 简介中看到的,dask 不会计算任何东西,直到系统提示它这样做。所有的步骤都准备好了,等待你的命令开始工作。
为什么我们需要计算()结果?
你可能会想,为什么我们不立即得到结果,就像你经营熊猫业务一样?原因很简单。Dask 主要用于数据不适合你的内存的情况,由于这个原因,初始操作的结果,比如一个巨大的数据帧的装载不能被具体化,因为你没有足够的内存来这样做。
这就是为什么您要准备计算步骤,然后让集群计算并返回一个更小的仅包含结果的集合。
# the dask code goes for example like this:
df = dd.read_csv(path)
d2 = dd.read_csv(path2)
re = df.merge(d2, on="col")
re = re.groupby(cols).agg(params).compute()
Dask 性能
如何比较用于不同目的的两个平台的速度并不简单。结果也可能被数据扭曲。一个工具可以非常快速地合并字符串列,而另一个工具则擅长整数合并。
为了展示这些库有多快,我选择了 5 个操作,并比较了它们的速度。我重复了 7 次性能测试,我测得我的 cpu 和内存使用率从未超过 PC 的 50%(i7–5600 @ 2.60 GHz,16GB Ram,SSD 磁盘)。除了操作系统和性能测试之外,没有其他进程在运行。
load_transactions—读取约 700MB 的 CSV 文件load_identity—读取约 30MB 的 CSV 文件merge—在字符串列上连接这两个数据集aggregation—对 6 列进行分组并计算总和与平均值sorting—对合并数据集排序 3 次(如果库允许)

熊猫和达斯克的速度比较。在中绘制图表。快递。图片作者。
看起来 Dask 加载 CSV 文件非常快,但原因是 Dask 的懒惰操作模式。加载被推迟,直到我在聚合期间具体化结果。这意味着 Dask 只准备加载和合并,但是与聚合一起执行。
Dask 很少支持排序。甚至官方的指导方针也说要运行并行计算,然后把计算出来的(和小得多的结果)传给熊猫。
即使我尝试computeread _ CSV 结果,Dask 在我的测试数据集上也慢了大约 30%。这只是证实了最初的假设,即 Dask 主要在数据集不适合内存的情况下是有益的。
PySpark
这是用于 Spark 的 python API,一个分析大数据引擎。Spark 在 Hadoop 平台上发展,可能是最流行的云计算工具。它是用 Scala 编写的,但是 pySpark API 中的许多方法可以让您在不损失 python 解释速度的情况下进行计算。
与 Dask 类似,首先定义所有操作,然后运行.collect()命令来具体化结果。还有比collect更多的选项,你可以在 spark 文档中读到它们——动作。
PySpark 语法
Spark 使用弹性分布式数据集(RDD)来执行计算,操作它们的语法与 pandas 非常相似。通常会有产生相同或相似结果的替代方案,如sort或orderBy方法。
开始时,您必须初始化 Spark 会话。然后,您可以使用 python API 准备这些步骤,或者您可以从 Spark SQL 中受益,并用 SQL 编写代码。

熊猫语法与 PySpark 的比较。图片作者。
想试的话不一定要装 Spark,因为 PySpark 包自带了一个 spark 实例。不过,你必须在你的电脑上安装 java。
火花性能
使用我在 Dask 部分描述的 pySpark 运行了相同的性能测试,结果是相似的。

熊猫和 pyspark 的速度对比。图片作者。
不同之处在于,spark 读取 csv 的一部分,以便推断数据帧的模式。在这种情况下,将整个数据集加载到熊猫上会花费更多的时间。
Spark 是一个巨大的计算平台,利用大集群的力量从庞大的数据集获得洞察力。在相对较小的数据上使用 spark 不会产生预期的速度提升。
Vaex
到目前为止,我们已经看到了在更多的计算机核心和集群中的许多计算机之间分配工作的平台。对于符合记忆的数据集,他们通常不能打败熊猫。Vaex 的目标就是这样做。
创建这个库是为了让数据集的基本分析速度快得惊人。Vaex 不支持 pandas 的全部功能,但它可以非常快速地计算基本统计数据并创建一些图表类型。
Vaex 语法
熊猫和 vaex 语法没有太多区别。

熊猫和 Vaex 语法的比较。图片作者。
Vaex 性能
与前两个工具不同,Vaex 的速度与示例数据集上的 pandas 相似,在某些领域甚至更快。

熊猫和 vaex 的速度比较。图片作者。
通常你会和熊猫相处得很好,但是有时候你会很纠结,这时就该试试 vaex 了。在本文中, Jonathan Alexander 做了一个更大的性能测试,以发现 Vaex 可以击败其他方法。它主要是主人加入。
朱莉娅
Julia 在数据科学社区有点受欢迎。它被预言有一个宏伟的未来,尽管突破还没有发生。然而,也有很多人喜欢上了茱莉亚处理事情的方式。我是其中之一。
与 python 相反,Julia 是一种编译的语言。这通常会带来更好的性能。这两种语言都在 Jupyter notebook 中运行,这就是 Julia 在数据科学概念证明中受欢迎的原因。
Julia 语法
Julia 是专门为数学家和数据科学家开发的。你可以在我们为什么创建 Julia 的文章中读到 Julia 结合了许多现有编程语言的好处。
尽管 Julia 是一种不同的语言,但它以 pythonic 的方式做很多事情。最重要的是,它会在适当的时候使用自己的技巧。我喜欢确定这是一个可变操作的符号。优雅小巧(相比熊猫的inplace=True)。
另一方面,在 python 中,许多东西都发展了一种首选的超时处理方式。朱莉娅经常提供几种方法来做最基本的事情,比如阅读 csv 文件。从 1.0 版本开始,语法就相当稳定,但是您最喜欢的方法将来可能会被弃用。
让我们比较一下 pandas 和 julia 中的数据加载、合并、聚合和排序。

Pandas 和 Julia 语法的比较。图片作者。
让我们看看朱莉娅的数据帧是否能打败熊猫。
朱莉娅表演
考虑到朱莉娅的速度不是那么简单。当你第一次运行 Julia 代码时,即时编译器需要把它翻译成计算机语言,这需要一些时间。这就是为什么任何代码的第一次运行都比后续运行花费更长的时间。
在下面的图表中,您可以看到第一次运行明显长于其余六次测量的平均值。我还尝试在单核(julia)和四核(julia-4)上运行 Julia。

熊猫和茱莉亚的数据处理速度比较。在中绘制图表。快递。图片作者。
您可以通过将环境变量
[JULIA_NUM_THREADS](https://docs.julialang.org/en/v1/manual/environment-variables/#JULIA_NUM_THREADS)设置为您想要使用的内核数量来运行更多内核的 julia。从 1.5 开始,你可以通过julia -t n或julia --threads n来启动 julia,其中 n 是期望的内核数量。
使用更多内核进行处理通常会更快,julia 非常支持开箱即用的并行化。您可能会担心编译速度,但您不必担心。代码编译一次,改变参数不会强制重新编译。编译完CSV.read(joinpath(folder,file), DataFrame)之后,即使你改变了源文件的路径,下面的调用也不会被编译。这就是为什么您在load_identity步骤中看不到任何延迟,因为 CSV 读数之前已经编译过了。

当我们运行已经用另一个参数编译过的 csv_read 时,它不会被重新编译。图片作者。
摩丁
在我们结束关于熊猫替代品的讨论之前,我必须提一下摩丁图书馆。其作者声称,摩丁利用并行性来加速熊猫 80%的功能。不幸的是,我很难看到这些好处。有时它会在初始导入命令期间中断。在其他场合,摩丁说:“不支持,默认为熊猫”,尽管操作最终崩溃,留下 4 个 python 进程,每个进程消耗大量内存。后来花了一些时间来终止这些进程。
我必须说,我喜欢摩丁背后的想法,我希望有一天这些差距将被覆盖,这将提升摩丁到一个值得考虑的替代位置。
结论
我们已经探索了几种流行的 pandas 替代品,以发现如果数据集足够小,可以放入内存,使用其他东西是否有意义。
没有一个并行计算平台能在速度上打败熊猫。考虑到它们更复杂的语法、额外的安装要求和缺乏一些数据处理能力,这些工具不再是 pandas 的理想替代品。
Vaex 显示了在数据探索期间加速某些任务的潜力。随着数据集越来越大,这种优势会变得更加显著。
Julia 的开发考虑到了数据科学家的需求。它可能不会像熊猫一样受欢迎,也可能不会像熊猫一样提供所有的特技。对于某些操作,它可以提供性能提升,而且我必须说一些代码在 julia 中更优雅。即使 Julia 没有进入前 20 种最流行的编程语言,我想它是有前途的,如果你关注它的发展,你就不会犯错误。
你喜欢这篇文章吗,看看我写的其他教程:
那种红酒够好吗?

介绍预测建模的基本工作流程并演示如何记录该过程的介绍性教程。
让我们假设我们被一个酿酒厂雇佣来建立一个预测模型来检查他们红酒的质量。传统的葡萄酒检测方法是由人类专家来完成的。因此,该过程容易出现人为错误。目标是建立一个生产葡萄酒测试客观方法的流程,并将其与现有流程相结合,以减少人为错误。
为了建立预测模型,我们将使用 UCI 机器学习库提供的数据集。我们将尝试根据与葡萄酒相关的特征来预测葡萄酒的质量。
目标:
- 探索数据
- 预测葡萄酒质量(二元分类)
- 浏览模型结果
探索数据
加载数据,库和主浏览数据
# libraries
library(dplyr)
library(ggplot2)
library(caTools)
library(caret)
library(GGally) dataFrame = read.csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv", sep = ';')summary(dataFrame)## fixed.acidity volatile.acidity citric.acid residual.sugar
## Min. : 4.60 Min. :0.1200 Min. :0.000 Min. : 0.900
## 1st Qu.: 7.10 1st Qu.:0.3900 1st Qu.:0.090 1st Qu.: 1.900
## Median : 7.90 Median :0.5200 Median :0.260 Median : 2.200
## Mean : 8.32 Mean :0.5278 Mean :0.271 Mean : 2.539
## 3rd Qu.: 9.20 3rd Qu.:0.6400 3rd Qu.:0.420 3rd Qu.: 2.600
## Max. :15.90 Max. :1.5800 Max. :1.000 Max. :15.500
## chlorides free.sulfur.dioxide total.sulfur.dioxide density
## Min. :0.01200 Min. : 1.00 Min. : 6.00 Min. :0.9901
## 1st Qu.:0.07000 1st Qu.: 7.00 1st Qu.: 22.00 1st Qu.:0.9956
## Median :0.07900 Median :14.00 Median : 38.00 Median :0.9968
## Mean :0.08747 Mean :15.87 Mean : 46.47 Mean :0.9967
## 3rd Qu.:0.09000 3rd Qu.:21.00 3rd Qu.: 62.00 3rd Qu.:0.9978
## Max. :0.61100 Max. :72.00 Max. :289.00 Max. :1.0037
## pH sulphates alcohol quality
## Min. :2.740 Min. :0.3300 Min. : 8.40 Min. :3.000
## 1st Qu.:3.210 1st Qu.:0.5500 1st Qu.: 9.50 1st Qu.:5.000
## Median :3.310 Median :0.6200 Median :10.20 Median :6.000
## Mean :3.311 Mean :0.6581 Mean :10.42 Mean :5.636
## 3rd Qu.:3.400 3rd Qu.:0.7300 3rd Qu.:11.10 3rd Qu.:6.000
## Max. :4.010 Max. :2.0000 Max. :14.90 Max. :8.000
从特征上看,我们认为“质量”是我们的目标特征。我们总共有 11 个特征用作预测器。
探索特性
转换目标特征
由于我们将讨论分类模型,我们将把我们的目标特征从连续类转换成二进制类。这样我们就能适应一个广泛使用但非常简单的分类模型。
原始目标特征标签的分布
# checking ratio of different labels in target feature
prop.table(table(dataFrame$quality)##
## 3 4 5 6 7 8
## 0.006253909 0.033145716 0.425891182 0.398999375 0.124452783 0.011257036dataFrame = dataFrame %>%
mutate(quality_bin = as.factor(ifelse(quality <= 5, 0,1))) %>%
select(-quality) p = round(prop.table(table(dataFrame$quality_bin))*100,2)
经过改造后,我们有 53.47%的案例被归类为好酒,而 46.53%的案例被归类为劣酒。
我们在这里有一个很好的目标类分布!这很好。否则,我们将不得不处理数据平衡。虽然我们不会在本教程中讨论这个领域,但这是一个很好的讨论领域。所以对于那些将要了解它的人来说,这是额外的加分!
简而言之,我们希望在我们的目标特征中有一个来自不同标签的观察值的平衡分布。否则,一些 ML 算法会过度拟合。
可视化探索预测器
探索酸度
dataFrame %>%
ggplot(aes(x = as.factor(quality_bin), y = fixed.acidity, color = quality_bin)) +
geom_boxplot(outlier.color = "darkred", notch = FALSE) +
ylab("Acidity") + xlab("Quality (1 = good, 2 = bad)") +
theme(legend.position = "none", axis.title.x = element_blank()) +
theme_minimal()

我们有多个连续的特征,可以用相似的方式绘制出来。这意味着我们将不得不一次又一次地重写我们刚刚在代码块中写的代码:viz _ acidity。在编码中,我们不想那样做。因此,我们将创建一个函数,并将其包装在我们的代码中,以便将来可以重用它!
如果听起来太多,就坚持下去。一旦你看到代码,它会变得更有意义。
# boxplot_viz
# plots continuous feature in boxplot categorized on the quality_bin feature labels from dataFrame
# @param feat Feature name (string) to be plotted
boxplot_viz = function(feat){ dataFrame %>%
ggplot(aes_string(x = as.factor('quality_bin'), y = feat, color = 'quality_bin')) +
geom_boxplot(outlier.color = "darkred", notch = FALSE) +
labs(title = paste0("Boxplot of feature: ", feat)) + ylab(feat) + xlab("Quality (1 = good, 2 = bad)") +
theme(legend.position = "none", axis.title.x = element_blank()) +
theme_minimal()
}boxplot_viz('volatile.acidity')

for (i in names(dataFrame %>% select(-'quality_bin'))){
print(boxplot_viz(i))
}











检查相关性
我们可以快速检查我们预测者之间的相关性。
dataFrame %>%
# correlation plot
ggcorr(method = c('complete.obs','pearson'),
nbreaks = 6, digits = 3, palette = "RdGy", label = TRUE, label_size = 3,
label_color = "white", label_round = 2)

高度相关的特征不会向模型添加新的信息,并且模糊了单个特征对预测器的影响,因此难以解释单个特征对目标特征的影响。这个问题叫做多重共线性。一般来说,我们不想保留相关性非常高的特征。
- 相关性的阈值应该是多少?
- 我们如何决定丢弃哪个变量?
- 相关特征会损害预测准确性吗?
所有这些都是很好的问题,值得好好了解。所以,对于那些将要学习的人来说,再一次加分!
在基于相关性做出任何决定之前,检查特征的分布。除非任意两个特征有线性关系,否则相关性意义不大。
特征工程
根据从数据探索中获得的见解,可能需要转换某些要素或创建新要素。一些常见的特征工程任务有:
- 特征的规范化和标准化
- 宁滨连续特征
- 创建复合特征
- 创建虚拟变量
本教程不会涵盖特征工程,但这是一个很好的探索领域。在拟合任何预测模型之前,在必要的特征工程之后进行大量的数据探索是绝对必要的先决条件!
拟合模型
拆分数据
在现实世界中,我们根据被称为训练数据的历史数据训练我们的预测模型。然后,我们将该模型应用于新的未知数据,称为测试数据,并测量性能。因此,我们可以确定我们的模型是稳定的,或者没有过度拟合训练数据。但是由于我们无法访问新的葡萄酒数据,我们将按照 80:20 的比例将数据集分成训练和测试数据。
set.seed(123)
split = sample.split(dataFrame$quality_bin, SplitRatio = 0.80)
training_set = subset(dataFrame, split == TRUE)
test_set = subset(dataFrame, split == FALSE)
让我们检查一下训练和测试数据中的数据平衡。
prop.table(table(training_set$quality_bin))##
## 0 1
## 0.4652072 0.5347928prop.table(table(test_set$quality_bin))##
## 0 1
## 0.465625 0.534375
训练数据的拟合模型
我们将在数据集上拟合逻辑回归分类模型。
model_log = glm(quality_bin ~ .,
data = training_set, family = 'binomial')
summary(model_log)##
## Call:
## glm(formula = quality_bin ~ ., family = "binomial", data = training_set)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -3.3688 -0.8309 0.2989 0.8109 2.4184
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 17.369521 90.765368 0.191 0.84824
## fixed.acidity 0.069510 0.112062 0.620 0.53507
## volatile.acidity -3.602258 0.558889 -6.445 1.15e-10 ***
## citric.acid -1.543276 0.638161 -2.418 0.01559 *
## residual.sugar 0.012106 0.060364 0.201 0.84106
## chlorides -4.291590 1.758614 -2.440 0.01467 *
## free.sulfur.dioxide 0.027452 0.009293 2.954 0.00314 **
## total.sulfur.dioxide -0.016723 0.003229 -5.180 2.22e-07 ***
## density -23.425390 92.700349 -0.253 0.80050
## pH -0.977906 0.828710 -1.180 0.23799
## sulphates 3.070254 0.532655 5.764 8.21e-09 ***
## alcohol 0.946654 0.120027 7.887 3.10e-15 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 1766.9 on 1278 degrees of freedom
## Residual deviance: 1301.4 on 1267 degrees of freedom
## AIC: 1325.4
##
## Number of Fisher Scoring iterations: 4
让我们绘制 p 值最低/绝对 z 值最高的变量。
p = varImp(model_log) %>% data.frame()
p = p %>% mutate(Features = rownames(p)) %>% arrange(desc(Overall)) %>% mutate(Features = tolower(Features))p %>% ggplot(aes(x = reorder(Features, Overall), y = Overall)) + geom_col(width = .50, fill = 'darkred') + coord_flip() +
labs(title = "Importance of Features", subtitle = "Based on the value of individual z score") +
xlab("Features") + ylab("Abs. Z Score") +
theme_minimal()

检查模型性能
我们将通过在我们以前看不到的测试数据上运行来检查我们的模型表现如何。我们将比较预测结果和实际结果,并计算一些常用的二元分类模型性能测量指标。
# predict target feature in test data
y_pred = as.data.frame(predict(model_log, type = "response", newdata = test_set)) %>%
structure( names = c("pred_prob")) %>%
mutate(pred_cat = as.factor(ifelse(pred_prob > 0.5, "1", "0"))) %>%
mutate(actual_cat = test_set$quality_bin)p = confusionMatrix(y_pred$pred_cat, y_pred$actual_cat, positive = "1")
p## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 108 46
## 1 41 125
##
## Accuracy : 0.7281
## 95% CI : (0.6758, 0.7761)
## No Information Rate : 0.5344
## P-Value [Acc > NIR] : 9.137e-13
##
## Kappa : 0.4548
##
## Mcnemar's Test P-Value : 0.668
##
## Sensitivity : 0.7310
## Specificity : 0.7248
## Pos Pred Value : 0.7530
## Neg Pred Value : 0.7013
## Prevalence : 0.5344
## Detection Rate : 0.3906
## Detection Prevalence : 0.5188
## Balanced Accuracy : 0.7279
##
## 'Positive' Class : 1
##
模型性能总结:
- 准确率 : 72.81%的葡萄酒样本被正确分类。
- 灵敏度/召回率 : 73.1%的实际好酒样本被正确分类。
- Pos Pred 值/精度:总好酒预测的 75.3%是实际好酒。
概要洞察
让我们总结一下我们从练习中学到的关于葡萄酒测试的知识:
- 酒精含量、挥发性酸度、硫酸盐和总二氧化硫是影响葡萄酒质量的四个最重要的统计学特征。
- 给定我们分析的 11 个特征的信息,我们可以在大约 73%的情况下准确预测葡萄酒质量,
- 这比使用传统的基于专家的方法获得的准确度高大约 26%。
人们能区分 5 度以下的葡萄酒和 10 度以上的葡萄酒,对于白葡萄酒只有 53%的可能性,对于红葡萄酒只有 47%的可能性

感谢阅读!
通过阅读这篇文章,您应该对 R 中的函数是如何工作的有一个基本的了解,以及如何在您的个人生活中使用它!
不确定接下来该读什么?我为你挑选了另一篇文章:
https://curious-joe.medium.com/have-r-look-after-your-stocks-8462af2ee3c1
阿拉法特·侯赛因
AI 的民主化好不好?
一篇关于 AI 民主化是否对网络有益的观点和讨论文章

图片来自 Unsplash,作者马库斯·温克勒
在现代教育时代,几乎任何有网络连接的人都可以学习他们想学的任何东西。学习 AI 也是如此,现在,任何具备必备背景的人都有机会学习 AI 并构建 AI 程序。当我说“民主化”时,我指的是容易获得人工智能教育和学习,更重要的是,容易获得建立可扩展的人工智能应用程序。在我今年夏天早些时候写的一篇文章中,我讨论了我在人工智能伦理方面的个人经历,以及我如何不重视我的工作的意义。那篇文章在这里:
我总是听说任何一种学习的民主化都是有益的,这一点我大体上同意。这也延伸到了人工智能,对于我人工智能职业生涯的主要部分,我完全同意。我是一名高中生,直到 11 个月前才开始学习微积分课程。然而,到那时为止,我已经在人工智能方面取得了很大进步,因为我可以从免费的 Youtube 视频和在线项目中学习。然而,在这一点上,在考虑了我和其他人是如何使用 AI 后,我的强烈意见有些动摇。虽然老实说,我对这个话题没有固定的看法,但在这篇文章中,我将讨论我认为 AI 民主化的一些主要好处,更重要的是,一些缺点是什么,因为我相信许多人都不会谈论它。
好人
我会尽量缩短这一部分。显然,有太多的理由说明让这么多的人能够接触到人工智能是有益的。首先,它为人们提供了学习和建立职业生涯的机会,这是他们以前从未有过的。对于那些可能没有机会接受正规教育的人来说,训练营、Coursera 课程和谷歌的认证是人们进入人工智能和寻找工作机会的绝佳选择。此外,它允许像我这样的年轻开发人员建立对人工智能的兴趣,并在大学里追求它。
最重要的是,人工智能的民主化为未来几十年创造了一大批人工智能工程师、研究人员和开发人员。这一点很重要,因为只有在历史上,我们才能向如此年轻的人传授如此复杂的概念。这无疑应该会加速 AI 的成长,并帮助它融入我们社会的更多部分。然而,有人担心我们将这些新的人工智能系统融入我们日常生活的速度有多快。虽然我可以举出更多的好处,但我会在这里停下来,因为我想你已经明白了。在我看来,更重要但讨论较少的是人工智能易于使用的一些负面影响。
坏事
老实说,人工智能的可访问性没有太多的负面影响,然而,主要的和明显的一个是伦理问题。
作为一名年轻的开发人员,我的工作在 AI 社区经常被视为噱头。虽然社区中的退伍军人经常过度赞扬我的工作,但有时他们并不重视我的理解和工作。当我试图启动真正的应用程序或对我的工作产生真正的影响时,这导致了重大问题。正如我在上面链接的文章中所描述的,许多人伸出手来,警告我关于我工作的道德问题。问题是我不理解道德规范,也不愿意去想它。
一个主要问题是,几乎每门初级人工智能课程,包括我自己的课程,都讨论了人工智能可以在哪些领域实施,这些领域存在重大的伦理问题,例如医疗保健。对于开始学习人工智能的年轻孩子来说,他们相信他们可以创建人工智能系统用于真实的系统,让他们忘乎所以。对于渴望和驱动的年轻头脑,他们不会接受否定的答案,会直接进入一个项目,而不考虑伤害。这正是我所做的。这就是我害怕民主化的原因,因为它将人工智能交给了那些可能不理解他们在建设什么以及为什么他们的工作有潜在危险的人。虽然这只是我为数不多的保留意见之一,但却是非常重要的,应该予以考虑。
这就提出了一个问题,人们应该从什么时候开始接触人工智能?我相信它可以在大学早期,但老实说,这是一个具有挑战性的问题来回答。一个更好的解决方案是在任何人工智能课程或课程表中包含多个伦理课程。这将是一门课程的第一课,这样学生们才能确切地了解人工智能伦理是什么,以及它们为什么如此重要。这将加强学生的谨慎和责任感,从而解决这个问题。
另一个主要问题是缺乏理解。快速浏览 Coursera,可以发现很多 AI 课程只注重开发,没有理论。这意味着学习人工智能的新人只是在学习如何用 Keras 和 PyTorch 编写神经网络代码,而不理解它背后的任何理论。我很快就成为这个陷阱的受害者,我希望在不久的将来写下这段经历。这是 AI 社区的一个主要问题,因为它创造了没有适当技术背景的工程师。如果理论在开始时没有被恰当地教授,那么以后就很难恰当地执行它,因为它是一个基础。因此,一旦新的人工智能开发人员进入就业市场,他们是较弱的候选人,如果他们被雇用,人工智能的进步就会停止。为了让人工智能以它需要的速度发展,我们需要恰当有效地教导新的开发者。
这是人工智能民主化的两大负面,主要是因为我亲眼看到和经历了这些。如果你有任何其他的担忧,请在评论中告诉我,这样我们就可以讨论它们了。
最后的想法
我真诚地相信人工智能的民主化对网络是有益的。如果它不存在,我就写不出这篇文章。我实际上只有 17 岁,就在几十年前,这么年轻的人对如此先进的课题如此了解是不可思议的。但现在,在 2021 年,我很难称得上是独一无二的,有些比我年轻的学生知道的甚至比我还多。我认为我们面临的关于人工智能民主化的主要问题可以很容易地解决,只需要那些建立这个机构的人的正确认识和努力。但是现在,我会尽我最大的努力来防止我自己和我周围的人落入阻碍人工智能发展的陷阱。希望这篇文章能让合适的人看到,并帮助他们改变心态。
彩虹之上有特色店吗?
如何为您的使用案例选择合适的功能库

图片由叶夫根尼·切博塔列夫通过像素拍摄
在一个蓬勃发展的 SaaS 垂直市场中艰难地选择任何工具,让我想起了《绿野仙踪》中的那首歌——越过彩虹——这首歌最初由朱迪·加兰演唱,但被夏威夷活动家伊斯雷尔·kamakawiwoʻole.完美翻唱
在彩虹之上的某个地方,天空是蓝色的,你敢于梦想的梦想真的会实现
有一天我会对着星星许愿,醒来时发现乌云已经离我远去,烦恼就像柠檬汁一样融化了
所以,是的,我们很容易感觉像多萝西在寻找传说中的特色商店!但是,任何旅程都是这样开始的,对吗?带着一种睁大眼睛和极度缺乏知识的感觉。考虑到这一点,多一点信息和经验可以帮助我们获得足够的知识来开始这段旅程。
几个好问题
功能商店无疑已经成为 MLOps 生态系统中最受关注的新参与者之一。但是,伴随炒作而来的是许多问题。这篇博客旨在提供一些关于如何根据您的特定需求和要求来识别最佳特性库的建议。
与所有探索之旅一样,我们的功能商店探索始于提出正确的问题。在考虑选择什么样的功能商店时,可以问自己以下几个问题:
- 有什么好的方法来分析我的选择,即筛选越来越多的解决方案?为此,你真的需要了解你自己,你的组织,你的团队。
- 今天能得到的有多少是真正“跨越彩虹”的?翻译——什么是真实的,什么是炒作?
- 我能自己做吗?建而不买?也许有一个骗局要造???
- 我的团队的目标如何与我的选择相交?
现在,是时候看看我们潜在的工具包了!
欢迎来到选择
大约三年前,我和我的一位同事开始对所有可用的主要和次要 MLOps 工具的细微方面进行编目(该文档供我们工作的咨询公司内部使用,很抱歉我不能分享)。我们创造了一个超级有用的工具。
这有助于我们区分各种产品和服务。它帮助我们向其他顾问介绍了各种选择之间的区别。然而,如果您在过去几年中一直关注 MLOps 对话,您会知道市场上充斥着许多开源项目和 SaaS 工具。用博·伯翰讽刺而睿智的话来说,我能让你在任何时候对任何事情都感兴趣吗?当然,他说的是互联网,但老实说,如果你对一切都开放的话,MLOps 市场开始变得有点势不可挡。
因此,正如你所料,我们所做的编目是不可持续的——正确维护是一个巨大的难题。我们开始走上记录太多排列、太多选择的道路。虽然这很有教育意义,但我们也碰到了非常重要的事实。
大多数决策者,甚至是工程师,都需要对工具有更直观的理解,也就是说,肮脏的细节会在适当的时候出现,但我们关键的、固执己见的要点是什么。
记住所有这些,这个由 MLOps 社区成员管理的功能商店的比较被很好地放在一起并且非常方便,所以我将把它作为一个参考点。该页面提供了一个直观的方向,可以开始就考虑哪些功能商店进行有意义的讨论。此外,它通常符合我所认为的功能存储,即 ML 功能的离线和在线存储,重点是通过存储、转换定义、标准化、时间旅行、沿袭和治理进行数据和功能管理。
最后一点很重要,因为并不是所有被称为特性库的东西都是一个。这是一个越来越流行的术语,许多技术供应商都热衷于赶时髦,不管什么很快被接受为功能商店的合适定义。
比较功能商店
你很可能不熟悉特色商店。如果这是真的,你可能会试图过滤掉炒作,得到什么是重要的。因此,让我们坚持一些基本原则,比如与云供应商的集成、交付方法和销售模式。
基础知识实际上很重要,因为可能有两个主要杠杆控制着你的决策过程——政策和金钱——这两个杠杆都已经在影响你的偏好。换句话说,这些基本要素可以很好地将产品分成大致适合您的环境的组。
从这里开始,可能值得考虑一下功能商店中的主要产品功能。例如,从源代码到定义、自动化和服务的整个特性生命周期的管理。或者,治理实际上存在于别处的所述生命周期。或者,满足在线用例的能力。
对于这次对话,我将选择泰克顿、盛宴、 AWS Sagemaker 功能商店和 scribbleData 进行比较,这当然不是一个详尽的列表,但这是一个很好的起点,并且适用于本次练习。

功能商店评估对比页面 |图片由 MLOps 社区提供
基础知识
关于泰克顿和 scribbleData,首先要注意的是,它们更像 SaaS 风格。相比较而言,Feast 是一个开源工具,AWS 的功能商店是 Sagemaker 平台的一部分。
下一个吸引我眼球的是对云平台的支持——有不同级别的支持(现在和路线图)。如果你是 AWS 优先购买者,你可能会选择 Sagemaker。如果你在 Azure 上,只有泰克顿和盛宴适用。如果你是一家 GCP 商店,或者害怕被云供应商锁定,除了 AWS 的功能商店,其他都适用。为了这个练习,让我们保留我们的多云选项,从列表中删除 AWS 的功能商店。
那么,其他的基础呢?先说发货和销售模式。考虑到 Tecton 和 scribbleData 不是开源的,并且是更明显的 SaaS 产品,它们从 Feast 中形成了一个独立的分支,这就引出了一个问题——我能使用 Feast 构建自己的吗?这是一个重要的问题,值得我在下面提供它自己的部分。所以,让我们转而关注这个 SaaS-y 分支。
在这里,我们可以看到另一个分裂——Tecton 是一个完全托管的云服务,而 scribbleData 提供了一个自我管理的路线。此外,这两种产品的定价模式也不同。泰克顿提供了一种基于消费的定价方法,而 scribbleData 似乎提供了每节点成本或其他潜在的东西。这两家技术供应商的这种“为使用付费”的方法在通过 PoC 评估您的用例时非常有用。不过,如果不进行 TCO 分析,中长期的影响就不太清楚。
与任何采购决策一样,在可以协商的商业协议与您的工程团队的目的、能力、成本以及您需要支持的用例之间,总会有一个平衡行为。对于这个练习,大部分都是推测性的。然而,我认为有两个主要的用例会促使人们做出关于 Tecton 和 scribbleData 的决定。
支持两个关键用例
在回顾 Tecton 和 scribbleData 时,我想到了两个关键的用例。
第一个用例是完整的生命周期支持。更具体地说,我指的是特性转换的管理,它包括通过 CI/CD 编排的特性定义和自动转换。值得注意的是,AWS 的特性库和 Feast 中都没有特性定义和自动转换。然而,泰克顿和 scribbleData 都支持这一点。

特征定义示例|图片作者泰克顿
为了使这些潜在的新术语更加清晰,特征定义的含义是用于定义如何创建特征的框架或代码——字面意思是可以被调用来创建特定特征的 SQL、python 或其他声明性函数。当然,这也应该通过 CI/CD 流程进行版本控制和编排。这将我们带到自动化转换,它指的是处理特征值的整个 ML 数据管道的编排,可能包括回填数据等内容,确保批处理和在线功能可用性和编排可观察性之间的对等性。
考虑到对特性定义和自动转换的一些变化的需求,在特性库中看不到这两个组件是很奇怪的,对吗?我的意思是,术语功能商店实际上暗指这个时代的这两个组件。
第二个用例是为训练和在线 ML 模型自动存储和提供数据。离线存储培训和在线存储(如果需要)中的功能需要高度准确和精确。离线数据必须允许数据科学家执行“时间旅行”,以生成过去任何时间点的训练数据,或批量评分。在线数据用于实时预测。由于在线 ML 模型的低延迟要求,这是具有在线支持的功能商店的亮点。将数据放入离线存储和在线存储,并使所有功能易于访问以进行培训和服务,即使是在在线模式下,也是一项挑战。
同样,Tecton 和 scribbleData 以及 AWS 和 Feast 都通过在线功能摄取以及与存储和转换服务的集成来支持这种用例。然而,如果使用 scribbleData,通过 API 呈现这些在线功能取决于管理管道的工程师。
这些是相对高级的用例。如果这两个不是非常相关,或者您想自己动手构建它,该怎么办?
自己造?
一些组织致力于开源选项。其他人会说他们希望他们的工程师有为教育目的构建自己的工具的经验。就我个人而言,我认为只致力于开源工具在特定场景下是有意义的,但如果被教条地追求,这就是一个危险信号。此外,我不认为过多地重新发明轮子是有意义的——对教育有一点帮助是好的,但如果你想得太远,你可能会拖团队的后腿,错过新技术的优势。
如果你想自己建立一个功能商店,考虑一下这个。功能存储只是一个数据仓库,具有适当的编排、逻辑和视图——直到您需要支持在线 ML 部署用例。如果你只关心批量部署,我认为这增加了构建你自己的特性库的可行性。如果你愿意使用 BigQuery、Snowflake 或其他现代数据仓库,这一点尤其正确。请注意,如果你走那条路,你可能会发现自己在重新发明已经存在于 Feast 中的东西。
现在,如果你肯定是追求在线用例,我的建议是使用 Feast 来做一些更复杂的在线过程,当然,除非你想要一个教育体验。

盛宴工作原理示意图|图片来自盛宴
值得注意的是,Feast 是开源的,但最初是在对 BigQuery 的强大支持下构建的。看起来对本地文件系统、SQLite、Redshift 和 DynamoDB 的支持已经存在了。
Feast 是我之前提到的理想化功能商店的一个很好的开端。它没有完全满足我列出的品质——转换定义、规范化、时间旅行、传承和治理——但有了体面的工程师在你身边,你的团队肯定可以达到 Feast 功能商店的定义。
如果你真的想建立自己的博客,我建议你看看另外两个中型博客(一个和两个)。
结论
彩虹之上有特色店吗?依我拙见,还没有。用户很难获得好的信息。MLOps 功能商店评估框架是一个很好的工具,可以帮助进行比较,但由于 TCO 和供应商成熟度等因素,中长期观点尚不明确。
也就是说,我确实认为像上面提到的那些工具正在接近一个健壮的特性库,这是我们许多人都希望看到的。简而言之,有 SaaS 选项提供先进的能力,至少作为进入特色商店世界的优秀跳板。如果您计划在生产中支持少量的 ML 模型,尤其是如果这些模型中的任何一个被期望以在线模式进行推断,那么检查它们是值得的。
我在上面已经提到了,但是它确实应该被强调一点。功能商店的现代 SaaS 实现确实在在线 ML 用例方面表现出色。SaaS 选项肯定有替代模式——比如数据流+大查询(+盛宴),火花流+三角洲湖,或者更有针对性的东西。然而,要很好地支持在线用例,还需要大量的工程工作。相比之下,具有开发数据仓库或客户数据平台经验的工程师会对面向批量的特性商店非常熟悉(CDP)——大致相同的工具,只是规则有所改变。
对于那些雄心勃勃并热衷于构建开源的人来说,我认为有一个机会在等待着他们。难道一个小的、专注的团队不能缩小 Feast 和许多人认为的理想特性商店之间的差距吗?如果你是这种心态,你可能会考虑让为盛宴贡献。
如果你想了解更多关于特色商店的信息,或者想与人交流以帮助你,我强烈推荐你加入 MLOps 社区 Slack 群组,这里每天都有很多这样的对话。
这是由 Salesforce 开发的最好的文本摘要框架吗?
基于 CTRLsum 的 Python 可控文本摘要

图片由 Gerd Altmann 从 Pixabay 拍摄
文本摘要技术是指从长文本文档中提取最重要的信息。它可以用来创建一个简短、准确、流畅的文档摘要。文本摘要器的目的是减少文档的阅读时间,使选择过程更容易。
Python 中有各种开源的文本摘要器,但是在本文中,您可以阅读 Salesforce 团队在论文 **CTRLsum: Towards Generic Controllable Text Summarization**.中开发的最新摘要技术
CTRLsum:
CTRLsum 是一个通用的可控摘要系统,用于在给定关键字、查询或前缀形式的控制标记或设置的情况下处理文本摘要。CTRLsum 还可以在不受控制的设置中实现文本的强摘要。
Salesforce 团队提出了 CTRLsum paper 的 Pytorch 实现。参考他们的 GitHub 库来获得使用预训练的 CTRLsum 模型以及训练新模型的说明。
Hyunwoong Ko 围绕 CTRLsum 开发了一个 python 包装器,可以从 PyPI 安装,称为summarizer。summarizers 包只需几行 Python 代码就可以使用 CTRLsum 的实现。
在本文中,我们将进一步讨论 summarizers Python 包的实际实现。
总结者:
**summarizers** 是基于 Salesforce 的 CTRLsum PyTorch 实现的可控摘要包。截至目前,summarizer 只支持英语,不支持其他语言。
安装:
**summarizers** 软件包可以从 PyPI 安装,使用:
**pip install summarizers**
用法:
在开始之前,使用from summarizers import Summarizers导入库并实例化Summarizers()类的对象。它带有预先训练的模型,用于普通摘要、论文摘要和专利摘要,使用关键字普通、论文、专利作为参数传递给Summarizers()对象。
**summ = Summarizers('normal')** # <-- default.
summ = Summarizers('paper')
summ = Summarizers('patent')
它还提出了 GPU 加速,使用参数device=’cuda’
在实例化**Summarizers()**对象后,可以执行不同类型的汇总,包括:
- 基本概述
- 面向查询的摘要
- 抽象自动问题检测
- 基于提示的摘要
- 带提示的查询聚焦摘要
我们将进一步讨论上述每一种总结技术及其实现。
我将使用维基百科中一篇关于人工智能介绍的文章来生成上述摘要。
(1.)基础总结:
基本摘要可用于生成长文本文档的简短摘要。这不涉及生成摘要时的任何控制。

(2.)查询聚焦摘要:
您可以基于指定的查询生成摘要文本。如果想要将查询与摘要放在一起,可以使用以查询为中心的摘要。

(3.)抽象的自动问题检测:
抽象问答可以通过在查询参数中提供一个问题作为参数来进行。

(4.)基于提示的总结:
您可以使用参数prompt生成一个以某个序列开始的摘要。

(5.)带有提示的查询聚焦摘要:
您可以通过询问查询来生成摘要,并强制摘要以给定的提示开始。

结论:
对于在应用自然语言处理领域工作的开发者来说,这是一个非常有用的软件包。这是一个方便的工具,可以用几行 Python 代码生成大型文本语料库的受控摘要。
请参考我以前的一篇关于使用 Sumy 包进行文本摘要的文章:
参考资料:
[1]总结者 GitHub 库:https://github.com/hyunwoongko/summarizers
感谢您的阅读
VAE 是一个好的随机生成器吗?
VAE 的另一种美德

维基百科-狄利克雷
这个职位是我之前的职位的延续。回想一下,我在那里讨论过是否使用 ELBO 训练 VAE,编码器收敛到期望的最佳参数(传统上,我们考虑高斯分布,因此参数是均值和标准差)。情况似乎不是这样:当我们希望优化编码器(在这种情况下是标准高斯编码器)时,我们需要单独训练它们。仅关注 ELBO 公式中的 KL 散度项:

作者
当我们使用整个公式时,我们获得了模糊的图像,但是编码器没有收敛到标准的高斯分布
但是这种发动机有什么潜在的应用吗?
我们暗示的一个方向是" "编码器作为随机发生器能有多好?"
下面的算法可以提供这个问题的答案:
*仅使用 KL 术语训练编码器
*为期望的分布生成样本(例如标准正常 ) ( 生成样本)
*从编码器生成 Z 值
假设我们正在处理一个具有 KL 散度解析形式的分布(如高斯分布),比较期望分布和以下各项之间的 KL 散度:
1生成样本
两个 Z
3 编码器的参数。
高斯情形
在高斯情况下,Z 的生成机制与随机样本的生成机制相同(重新参数化技巧),因此在最佳情况下,第 1 条和第 2 条必须合并。仍然需要证明最佳方案已经实现。

作者

作者
在后面的图表中:
红色曲线代表编码器值(即神经网络中的值)
绿色曲线-Z 的
黑色曲线— 随机样本
X 轴代表迭代次数和 Y,KL 值。
可以看出,绿色曲线和黑色曲线的表现几乎相同(从更远处看是最佳情况)。
以一种独特的方式,高斯情况允许多一个封闭形式的度量:wassertin 2 度量

作者

作者
我们可以看到,这些图形类似于 KL 散度情况,只是值不同。
我们可以总结出,在高斯情况下,编码器可以生成具有与标准高斯相似的 KL 散度的 Z 作为采样函数本身(例如 torch.randn 或 numpy.random
这听起来很酷,但是:
- 我们不能改进正则语言的随机抽样函数
- 如果我们不能改进,我们可以对标题中提出的问题给出肯定的答案,但训练引擎实现 numpy.random 的冗长过程并不吸引人
我们有两个选择:
- 放弃
- 检查其他通用发行版
幸运的是,我是一个古董爱好者
伽马射线盒
什么是伽玛分布?
为了对伽马、有一个很好的直觉,考虑一个测量事件时间到达的过程,但不仅仅是单个事件,还有 K 个事件。
有两种方法来参数化伽马,
α β 其中 α 表示到达量 K ( 也称为形状),而 β 是到达率。在某些地方,G amma 由 K 和 θ 定义
PDF 是:

作者
其中γ是伽玛函数。正如我提到的 α 是“到达的数量”
如果我们将 α 设为 1,那么γ(1)= 1(检查这里或者相信我),pdf 变成:

作者
这正是泊松分布(测量单个到达)
几个属性:
支撑是整个正实轴,这意味着如果

作者
而 b 是常数,X +b 没有伽玛分布。另一方面,标量缩放成立

作者
暗指

作者
对于正极 c
最后如果 X 是一个 r.v。

维基百科-Drichlet
所以我们有了很好的公式,我们能向前迈进,创造出基于伽马射线的 VAE 吗?
伽玛和 VAE
只要我们考虑从输入到编码器上层的道路。答案是没问题。当我们从编码器转移到解码器时,障碍出现了。
“传统”VAE 的神奇之处基于高斯分布的伟大特性:
如果 X r.v .具有随机分布,那么每个仿射变换都具有高斯分布。
这种方式允许从固定分布中取样,并容易地将其映射到所需的分布。这允许我们得到保持分布,避免对随机变量求导。Gamm 就不是这种情况了。
我们可以缩放它,但它对 α没有影响。挺拉屎的吧?然而,也有好消息:我们不关心解码器,因为在我们的实验中,我们研究的随机方式 Z 只是为了测试,我们不区分它们。
那么它是如何工作的呢?
我们设定一个目标函数(例如γ(1,1)γ(4,3) )
关于潜在尺寸,我们可以取 1 或更多,如果目标在所有维度上都是固定的,那么就像有一个巨大的批量。
我们基于目标函数创建一个样本
我们像以前一样训练编码器。我们的兴趣是理解 Z 的实际分布,看看它是否更接近目标函数
然后是样本。
如何从 Z 的样本量得到 α β ?
- 计算平均值
- 计算方差
- 方差和平均值之间的比率提供了 β,使用平均值我们得到 α。
结果
对于γ(4,3) 我们得到了下面的图形

对于γ(5,2) 我们得到了下面的图形

我做了一些额外的实验,展示了同样的画面:
与高斯相比,我们可以发现 VAE 使用伽马 VAE 提供了更高精度的样本
狄利克雷
狄利克雷是概率向量的分布。具有 K 维狄利克雷分布的 r.v .是向量 x1,x..xk ),使得它们都是正的,并且它们的和是 1
此外,我们还有:

作者
和

维基百科(一个基于 wiki 技术的多语言的百科全书协作计划ˌ也是一部用不同语言写成的网络百科全书ˌ 其目标及宗旨是为全人类提供自由的百科全书)ˌ开放性的百科全书
狄利克雷为什么有趣?

作者
因此,我们将遵循具有更大潜在维度的相同伽马机制,并且损耗将遵循狄利克雷 KL 公式
一些图表也显示了狄利克雷中的伽马现象:



摘要
我们看到,与高斯分布相比,我们可以获得比 Gamma 和 Dirichlet 中的随机样本更接近(KL -wise)给定分布的样本。关于原因,我没有深刻的理论支持。这些现象的发生可能是由于错误的样本量或其他潜在的超参数。但是它们发生了。我相信进一步的研究是有益的
这个帖子的代码是这里是。
此外,在工作期间,我需要 Pytorch 没有提供的几个度量函数:
- 多变量高斯函数之间的加权系数 2
- 在多变量高斯和对角协方差高斯"对角"之间插入 2(在 Pytroch 术语中称为独立
- 在两条对角线高斯线之间
- 对角线和标准高斯线之间的垫圈 2
- 对角线和多变量高斯线之间的 KL 散度
- 对角高斯和标准高斯之间的 KL 散度
我把它们都整理在这个文件里了。
谢谢你。
来源
https://en.wikipedia.org/wiki/Dirichlet_distribution(图片开头)
你的 AI 是专业级的吗?

https://www.publicdomainpictures.net/en/view-image.php?image = 161590&picture =槌子和听诊器
你可以做些什么来开始为专业人士开发数据科学。
专业级是一个在 21 世纪初因广告标语“GMC:我们是专业级”而流行的术语今天,它被用来区分一般用途(或消费级)产品,并传达一种产品在更频繁使用或由专业人士使用的压力更大的环境中会工作得更好或更久。
我们今天使用的大多数人工智能都是由人类(数据科学家)开发的某种机器学习模型驱动的。这些模型通常是使用训练数据集构建的。这些训练数据是决定最终人工智能应用程序“智能”水平的关键因素。这是一个简单的事实:更好的训练数据产生更好的模型。一个公理是:更多更丰富的训练数据会产生更多的健壮的模型。让我们讨论一下数据科学家在搜索完美的训练数据集时必须考虑的两个重要因素:相关性和规格。
寻找具有相关内容的数据集是数据科学项目的第一个关键步骤。例如,如果您希望构建一个聊天机器人来回答客户支持问题,那么您需要包含样本客户支持问题的训练数据。而不仅仅是一系列问题。如果问题集太窄或者太完美(对,太完美!),所得到的模型将不具有可学习的必要可变性,并且在野外不会表现良好。用数据科学的术语来说,我们会说结果模型不是很健壮。最好使用由一系列格式良好的和格式不良的问题组成的数据。
定位高质量和相关的训练数据对于当今的模型开发是如此重要,以至于专门的网站获取可用于训练数据的独特数据资产。例如,像谷歌这样的大型搜索提供商提供 数据搜索 ,这是一种专门寻找数据源的搜索。此外,三大云供应商中的每一家都有自己的数据共享平台,提供独特而有用的数据集: 【谷歌云】AWSAzure。
虽然定位与项目相关的数据是关键的第一步,但下一个重要步骤是规范过程,其中大部分“智能”来自人工智能。大多数训练数据都是原始格式,缺少一个关键部分。在我们之前的客户支持聊天机器人示例中,一旦数据科学家有了一组丰富的客户支持问题样本,他们现在就需要这些问题的最正确答案。在数据科学行话中,我们称之为数据标记。数据标注也称为数据注释或数据标记,是向原始数据添加信息(标签)的过程。这个标记的信息就是结果模型试图预测的。为了将这些标签添加到数据集中,现代数据科学家使用标记程序,这些程序读入原始的、未标记的数据集,然后逐个记录地进行检查。用户根据他们在每个记录中观察到的内容添加标签。今天,一些更好的标记工具采用了一些机器学习辅助,它们开始提出建议,使用初始的人类输入作为指导,以帮助加速人类标记,因为它们通过数据前进。正如 Big-3 云厂商提供了大量的原始训练数据一样,他们也提供了智能数据标注能力:Google AutoML亚马逊地面真相Azure 数据标注 。
上述方法是为消费级人工智能应用创建相关且明确指定的训练数据集的优秀工具。不幸的是,当谈到专业级发展时,在相关性和规范组件上都有额外的挑战,如果没有大量的帮助,这些挑战是很难克服的。
为法律或医疗人工智能应用寻找数据时,数据来源需要成为首要考虑因素。虽然公众可以获得一些专业数据的样本快照,但专业人士使用的绝大多数数据都是由行业认可的公司维护和管理的,例如【LexisNexis】(法律) 【汤森路透】 (法律) Elsevier (医疗)Wolters Kluwer(医疗)。这些组织维护的数据资产庞大而复杂,并且是由法律和医疗专业人员多年来收集和管理的。天真地向这些数据提供商索要数据转储(T21)经常会导致问题。尤其是当应用程序的预期客户(例如,律师或医生)询问关于 AI 应用程序的详细问题时,这需要对数据的来源有深入的了解。例如,当向法律专业人士提交新申请时,经常会遇到这样的问题,如这涵盖哪些司法管辖区、涵盖哪些法律领域、、追溯到多远之前或您是否考虑过 不良法律 ?
此外,许多数据科学应用程序是由来自这些专业认可的数据源的持续数据访问或反馈推动的。因此,即使数据科学开发人员从这些来源之一获得了一次性的数据快照,一旦投入生产,他们也需要找到一种方法来维护这些数据的最新性和完整性。这是通过应用程序编程接口或 API 的在 AI 应用程序和数据提供者之间创建程序链接来实现的。由于这些数据是专有的,对提供商来说是极其宝贵的资产,这些 API 通常位于付费墙之后。由于模型的维护和供给至关重要,因此需要考虑 API 成本,因为它们会大大增加运行和维护应用程序的总拥有成本(TCO)的计算。
在典型的消费级应用中,当涉及到标记数据时,数据科学家通常可以自己完成或在朋友的帮助下完成。然而,法律和医疗数据标签需要高级培训、知识和经验。对于需要法律或医学专业知识的专业级人工智能项目,数据科学家需要与律师或医生合作来执行标记。为了扩大大型数据集的消费级人类标签,通常会将外包给大型廉价资源,如 机械土耳其人 。然而,由于高级教育要求和专业人员的稀缺,扩大专业等级数据的人工标注过程是困难的,并且可能相当昂贵。
此外,一旦找到专业人员来帮助标记数据,法律和医疗数据的细微差别仍然会使执行简单的注释变得困难。例如,阅读一些案例法并确定法官的裁决可能听起来很简单。然而,这种看似简单的支持或反对标记过程实际上相当复杂,需要具有法律背景的人来解释文件的语言并做出决定。因此,该数据受到解释偏差风险增加的影响。为了减少这种情况,最佳实践是使用基于共识的方法,例如成对标记。该流程包括让多位专家对同一份文件进行标记,并且只接受两位或更多专家同意的标记。这些额外的努力产生了高质量的标签,但却大大增加了项目的成本和时间。
构建一个专业级的 AI 应用,首先要从一个可靠的行业公认的来源定位相关数据。不能只是一次性转储;专业人士希望应用程序提供的信息是最新的并且维护良好,因此应该考虑通过 API 连接到这些资源。通过标记来丰富数据,以便它可以成为建模的训练数据集,这需要律师或医生等主题专家的帮助。由于专业数据是细致入微的,并受到解释,谨防解释偏差,并试图寻求跨多个专家的共识,以提高标签质量。开发专业级的人工智能应用并不容易,需要数据科学家付出额外的努力。虽然开发消费级应用通常可以由个人来完成,开发专业级应用需要团队的合作:数据科学家、数据提供商和主题专家。最终证明你做了专业级 AI 产品的会是什么?简单: 法律或医疗专业人士在日常工作中信任并使用它!
你的聊天机器人敏感吗?
对话辅助解决方案越来越多地包括情感分析功能。这是什么意思?相关吗?它对情绪的表达应该有怎样的反应?

情感分析:今天至关重要的必需品
长期以来,公司通过实地调查或满意度表格来分析客户意见。它允许收集客户对产品、品牌或所提供服务的意见。在互联网时代,随着社交网络的爆炸,不可能对每一个观点都做出回应,无论是批评还是祝贺。
因此,考虑到评论的激增、这些评论权重的增加以及消费者在购买过程中的选择评级,分析的自动化已经成为一种必要的行为。尤其是因为这些数据在每个人都可以访问的许多地方都可以获得:论坛、在线评论、社交网络上的出版物……或者可以从电子邮件或纸质邮件中检索。这种自动化包括构建能够从自然语言文本中提取主观信息的计算机工具,以创建决策支持系统可以使用的结构化和可利用的知识。这种发现是从最微妙的、上下文的和文化的方面理解文本意义的工作,因此是一个复杂的过程。
情绪是一个模糊的概念,很难定义,它具有特质的特殊性,也就是说,对每个人的解释都是特定的——我们并不都害怕同样的事情,害怕的程度也不一样。换句话说,某样东西并没有那么明显的“好”或“坏”,而是“它可能会更好”或“它可能会更坏或它已经是了”。这意味着当我们使用这些工具时,我们需要在任何解释之前了解受众(和媒体),这也解释了为什么预训练模型在用于不同于它们被训练的领域时准确性较低。
在情感背景下对语言的自动分析是一个复杂的过程,需要一系列的处理,这些处理对应于不同的理解深度水平,因此对应于不同的提取难度。语言的丰富性意味着一个人表达的情绪不一定是整体情绪的绝对衡量;此外,人们倾向于表达与他们的期望相关的情感,一句话可能会被之前说过的另一句话抵消…
传达信息的媒介会引发不同的情感表达,无论是短的还是长的,是口头的还是书面的,等等。在电子邮件中,作者通常会更倾向于语境化和解释,而推特则更倾向于自发性和夸张。现在让我们看看聊天机器人中的情感分析。
检测的规模
情感分析可以分为几个检测级别:
- 情感的检测在于确定作者是否希望传达一种情感,或者它是否纯粹在描述中,在事实陈述中(“我在 9 点钟有一个约会”)。是二元分类:0 或 1,感性或中性。这是最基本的层面。
- 极性分类区分表达积极、消极或中性情绪的句子,代表情感的第一级分离,没有更多细节。与这种极性类似的是在聊天信息中或在对话助手发送的信息中使用拇指向上和向下。中立当然表现为没有投票权。
- 情感检测被定义为一种态度、一种思想或一种判断,这种态度、思想或判断是由一种更微妙和更长期的感觉所激发的,例如爱、恨、信任等。人们可能想知道这种检测对于“经典”对话助手的相关性:电子商务、支持、自我护理…
- 对情绪的检测与更多的自发情况有关,如愤怒、喜悦、悲伤、焦虑、抑郁等。情感的丰富性在社交或专业信息中的表情符号的使用中有其相似之处。这些小图像用表达情感的元素丰富了文本,而不必写出来。2021 年 4 月,微软宣布将团队中的表情符号选择器从 85 个元素扩展到 800 多个元素。

一些来自 https://openmoji.org/的表情符号
- 检测讽刺和挖苦,人们可以用积极的词语表达他们的消极情绪。如果没有对表达单词的上下文的深刻理解,使用单词权重的算法很难检测到这一点。
由于会话分析的应用领域和涉及的媒介,在谈论聊天机器人会话分析时,说“情绪分析”比“情感分析”更合适。
情感的指称
很容易意识到,这种情绪和情感的调色板几乎可以无休止地下降。为了能够以电子方式管理它,有必要建立一个框架,一个参考系统,以便当我们在聊天机器人领域时能够采取相应的行动。
在最广泛使用的参考系统中,我们发现:
- 极性系统分三级:正极、中性、和负极。
- 保罗·艾克曼的模型【1】根据 6 个基本类别区分情绪。根据他的理论,这些基本情绪源于不同的神经系统,因为一个人感知情况的方式不同。所以,情绪并不是相互依存的。这 6 种基本情绪是愤怒、厌恶、恐惧、喜悦、悲伤、和惊喜。在 20 世纪 90 年代,埃克曼将他的核心情绪列表扩展到 16 种,包括更广泛的积极情绪:娱乐、蔑视、满足、尴尬、兴奋、内疚、成就自豪、解脱、满足、感官愉悦、虽然这项工作侧重于面部表情,与书面表达的对应物是可能的。
- 心理学家罗伯特普卢奇克【2】的情绪轮,它包括 8 种多维度的“基本情绪”:期待、愤怒、厌恶、喜悦、恐惧、惊讶、悲伤和信任。这些情绪的特殊性在于可以根据三个标准来识别:它们的强度、它们的相似性以及它们的“两极性”,即它们彼此之间的对立。一种情绪的强度越低,就越难辨别。

普卢奇克的情感之轮——机器精灵 1735,公共领域,通过维基共享
- 奥托尼、克洛和科林斯模型反对罗伯特·普卢奇克和保罗·艾克曼提出的“基本情感”概念。根据这一模型,情绪产生于人类感知事件的方式,其强度不同。OCC 将情绪分为 22 类,增加了 16 种额外的情绪:钦佩、愤怒、失望、苦恼、恐惧、恐惧——证实、幸灾乐祸、欣慰、感激、开心——为、憎恨、
2020 年 6 月,斯坦福和谷歌研究已经公开了一个基于 27 种情绪+中性的数据集。这个数据集被称为 GoEmotions [5]。
找到许多其他的参考框架是可能的,但重要的是建立一个框架并使用它。因为它有更多的类,OCC 模型有更广泛的情感表达范围。另一方面,查找示例(标记)和处理完整的列表将需要更多的工作。
检测技术
文本中的情感检测通过两种方法解决:
- 显式检测。显性检测意味着在书面文本中使用明确陈述的词语,或带有情感的词语,如“快乐”或“幸福”,来表达情感(但人们可以找到与这一原则相矛盾的表述,如在句子中:“你的两种服务的组合不快乐”或“你偷走了我的快乐”)。
- 隐性检测。将文本识别并分类为没有携带情感的词的类别被称为隐含情感检测。当感情是隐性的时候,情绪词的识别就不起作用了(“你的服务宕机了”)。
检测方法可以分为三类:
- 通过一套手动精心制定的规则。在文本挖掘中开发了许多技术:词干提取、标注单词、句法分析、词性标注和组块;词汇的使用(即单词和表达列表)。这里有一个这个系统如何工作的例子,分三步:定义一个极化词的列表(例如,像“丑”、“坏”、“最差”这样的负面词,以及像“漂亮”、“好”、“最好”这样的正面词,等等)。);统计给定文本中的正面词和负面词的数量;如果正面词多于负面词,则该文本被认为是正面的,反之亦然。在出现平局的情况下,文本被认为是中性的。这个系统的主要缺陷是它一个接一个地提取单词,而不是按照单词的顺序,这使得它不是一个完全可靠的系统(例如“好”对“不好”)。然后,有必要添加许多规则来获得令人满意的结果,但是这使得系统的调整和维护变得更加复杂。
- 通过来自实例数据的机器学习技术。这包括训练模型来学习将输入(例如,句子)与极化的结果(积极的、消极的或中性的)相关联。情感分类可以被建模为分类问题,其中我们给模型一个向量(单词或句子),它返回一类情感(例如,中性、积极、消极、恐惧、焦虑、快乐、悲伤、愤怒、失望等)。).为了训练它,我们学习我们的模型,将对应于要检测的情绪的结果(类别)与单词向量相关联。存在许多预先训练的模型,但是对专有语料库的性能研究表明,这些网络对于会话情况来说不够有效。
- 通过一个混合系统结合了之前的两个系统。
使用任一系统还是两个系统取决于预期的检测水平。
检测的挑战
- 监督分类工作基于带注释的语料库。这种有监督的情感分类所固有的主要问题之一是,有必要拥有特定于被处理的领域的人工注释的学习语料库。这是一个复杂的过程,既费时又费钱。此外,由于情感文本的模糊性,标注时往往很难有较高的标注者间评分。最佳-最差缩放技术的使用[4]减少了基于人的注释偏差。
- 隐性情绪检测很难实现,因为句子中不包含情绪词。
- 否定强烈影响检测。
- 一些含糊不清的词语会影响检测,讽刺和挖苦的使用也是如此。
- 情感检测可能是一个耗时(并且 CPU 密集型)的过程。在大量的情况下,它可能需要大量的处理资源,甚至导致聊天机器人响应的传输延迟。
- 根据与对话中其他句子的关联,单词和句子可能具有不同的强度水平,这可能会影响逐句识别。
- 公共的预先标注的语料库通常是不平衡的,这导致了偏见,并且通常是为了不一定与业务目标兼容的特定目的而制作的。
- 包含积极和消极表达的信息很难处理,其中两种极性都不占主导地位,例如“尽管在收银台前等待了很长时间,我还是喜欢你的产品”。
- 在基于语音的系统中,调制、节奏、音量和停顿也提供了用户情绪状态的指示,并且检测起来非常复杂。
- 重要的是定义我们想要捕捉的情绪水平。要检测的每种情绪代表要执行的治疗。

从最普通到最特殊的情绪等级的例子
当一个聊天机器人面对一种情绪的表达时应该怎么做?
对于一个人来说,知道如何对一种情绪做出反应是很复杂的。对于一个 Bot 和配置它的人来说,就更复杂了!管理对话已经相对复杂,如果答案必须考虑到对话者的情绪水平,就更加困难。
面对负面情绪的检测,几种反应是可能的:
- 在基于对话树的对话中,可以根据用户的反应添加情感测试。在回答的每个过程中,我们可以尝试检测情绪,根据反馈,根据情绪的类别和强度,有可能触发相应的行动。我们越是试图检测不同的情绪,树的设计和维护就会变得越复杂。
- 助手可以保留对话并添加标签,允许领域专家查看这些对话并异步处理它们。这对于理解用户恼怒的原因尤其重要,并且如果必要的话,修改对话以管理这种类型的行为。
- 当面临负面情绪(或一系列负面情绪)时,机器人可以安抚用户,并建议他们通过实时聊天对话联系人类。这当然是最容易从事的行为。也有可能触发 web 回调操作。
- 在使用自动自然语言生成(NLG)的系统中,“有可能”添加一个情感参数,该参数将允许响应根据一种或多种情感而变化。最简单的是能够通过用静态句子块填充空槽列表来传输文本,直到能够基于检测到的情感生成完整的句子。
结论和展望
你应该通过在聊天机器人中添加情绪管理来明确你想要达到的目标。如果你使用一个预先训练好的模型,用你的用户反馈在你的域上测试它。不要想当然地认为出版商做的性能测试是理所当然的,他们是在不同的领域用不同的数据做的。
如果您想创建您的模型,不要低估收集、注释和建立对话树所涉及的工作。这是大量的工作,应该考虑到目标。
定义你的情绪清单,那些对你的生意有意义的情绪。
仔细考虑来龙去脉。没有系统总比一个只起一半作用的系统好。
迄今为止,大多数聊天机器人解决方案都允许你在对话过程中或对话结束时发表评论。因此,在场景结束时知道用户的意见是相对容易的,这在许多情况下是足够的。
参考
[1]https://en.wikipedia.org/wiki/Paul_Ekman 的保罗·艾克曼
*[2]罗伯特·普卢奇克——【https://en.wikipedia.org/wiki/Robert_Plutchik *
[3]奥托尼,a .,克洛尔,G.L .,柯林斯,a .:情绪的认知结构。剑桥大学出版社,英国剑桥(1988 年)
*[4]最佳-最差缩放—【https://en.wikipedia.org/wiki/Best–worst_scaling *
[5] GoEmotions:一个细粒度情感的数据集——https://arxiv.org/abs/2005.00547
你的数据和人工智能/人工智能团队经得起未来考验吗?
除了技能,智商,情商,找数据智商(DQ)
GIF by giphy
随着技术的快速演进,数据工程师、数据分析师、数据科学家、ML 工程师、AI 产品开发人员的角色在未来 3-5 年内将会有显著的不同!
你如何证明你的数据+人工智能/人工智能团队雇佣的未来?您当前的团队能够学习当今不存在的技术技能吗?
考虑一下数据工程师的角色。二十年前,这个角色主要围绕数据仓库模式设计,写模式治理,生成每周业务报告。这是数据被视为 IT 开支的一部分的时代。
在过去的十年里,随着 Hadoop 时代,数据仓库设备内的集成服务被用于数据摄取、ETL、数据目录、数据争论、治理、解耦存储和处理、NoSQL 持久性存储、可视化的技术的挑选组合所取代。数据工程师的技能更多地转向各种技术的集成,以创建数据管道。随着数据规模的增长,ETL 的挑战转向了有效利用分布式查询处理范例,如 MapReduce。如今,数据被认为是一个区分因素,业务团队希望管道变化能够快速转变,从而产生新的指标/见解。

按作者分类的表格
总结一下:你今天在面试中评估的技能很有可能会变得无关紧要。你如何确保被雇佣的人不仅仅在今天需要的技能上是好的,而且在未来不断变化的技术环境中也是有效的。
我的方法是在面试中寻找 7 种特质。我将这些特征称为数据智商(或 DQ) 。与智商和情商类似,我认为 DQ 对于数据+人工智能/人工智能领域的所有团队招聘都至关重要。
DQ#1:对业务环境的端到端理解的好奇心——洞察力将如何被使用,由谁使用,做出什么决定,等等。这意味着数据工程师有兴趣了解业务度量或 ML 模型将如何产生影响。同样,数据科学家有兴趣了解数据集的局限性或摄取或处理中的障碍。
GIF via giphy
DQ#2:从数据到洞察力再到影响力的极端所有权 —不认为将原始数据转化为洞察力是要完成的工作。大多数候选人忘记了从洞察力到影响力的最后一英里。多年来,我观察到优秀员工的一个重要特征是,努力看到自己的工作产生影响(即,洞察力以某种形式得到应用)。他们不会停止,直到我们从洞察力到影响力!
DQ#3:现实地看待统计的力量——数据中可能没有足够的统计意义来改变你的零假设。在广泛参与之前,能够运用自己的判断力来区分信号和噪音。对于这种特质,我最喜欢的问题是分享马克·吐温的名言“谎言、该死的谎言和统计”,并请候选人分享他们的经历。
DQ#4:猎人与农民的心态——凭直觉寻找见解和解决方案。探索的渴望是关键。判断这一特征的一个方法是候选人接受广泛观点的能力,而不是接受第一个想法,即,由宽入窄。
DQ#5:冷静的骄傲/对失败的宽容——在探索的海洋中游泳,知道什么时候继续游泳,什么时候停止(快速失败)。列表中的第二点和第五点是矛盾的——我见过表现出强烈极端自主性的候选人很难对他们的工作保持冷静和中立。
DQ#6:相信实验的力量 —度量标准之间的因果关系是一种假设,除非用实验来证明!在大多数成功的数据项目中,关键是减少从最初的想法到第一次实验的时间。不管未来的技术如何,数据团队的每个人都必须坚信实验的力量。
GIF via giphy
DQ#7:拥抱不确定性——快速迭代,并在新数据的背景下修改决策。这也广泛地转化为通过综合模式从错误中学习的能力。一些候选人从不确定性下的经营中获得乐趣,而一些人则走上了另一个极端。今天你可能已经有了一个清晰的路线图和轨迹,但是要为快速转变的时期做好准备,在这个时期团队需要适应不确定性。
GIF via giphy
总而言之,我在未来的招聘中寻找 DQ。这些年来,我在 Data + AI/ML 团队中看到了 DQ 与对不断变化的技术和技能要求的适应性之间的强烈关联。
渴望更多——查看一篇关于“ML 项目中可能出错的 98 件事 ”的相关文章还有,跟着我上 中 获取我自以为是的定期简讯 艾无 BS
你的数据好吗?如何辨别。
验证数据和模型非常重要
拥有“好的数据”意味着什么?是否所有数据都能够用于开展研究或向相关方提供信息?应该采取什么步骤来确定数据是否“好”?在实施线性回归、神经网络、逻辑回归、决策树或在其上建立模型之前,应该采取措施确定任何给定数据集的准确性和精确性。你可能在想,“嗯……所有这些额外的数据处理只会占用我更多的时间来构建我的模型。”真的!然而,花额外的时间来辨别你的数据是否正确是防止你在以后的工作中出错的一个很好的方法。不要忘记传播误差是非常真实的事情,原始数据集中的任何误差都可能导致最终分析中的更多误差。我们开始吧。
1。检查来源
不,它不需要 R、Python 或 Julia 的代码行。它不需要使用大量计算能力的复杂算法。它只是在网上搜索和深入挖掘潜在数据源的能力。虽然看起来很简单,但你可以从科学组织、政府机构或大学免费获得的大多数数据集通常都经过了严格的审查。有大量的校准协议来确保用户将访问的数据得到尽可能正确和准确的处理。
如何确定一个来源是否有效?首先看看托管数据的组织。如上所述,他们是传播数据的合法机构吗?美国地质调查局的 EarthExplorer 工具是我经常访问的 LANDSAT 卫星图像在线存储库。美国地质调查局是一个被认可的网站,由美国联邦政府支持。现在,如果我从乔的野生卫星世界得到我的数据。嗯,Joe 的网站似乎有很多免费的数据,但他只是将这些数据收集到一个存储库中,并放在自己的网站上。我真的不知道他从哪里得到的数据,我只知道它就在那里,可能准确也可能不准确。

美国地质调查局地球探测器概述。作者照片。
这里的一般经验法则是:如果数据不在一个被认可或可信的网站上,你应该怀疑它的真实性。
2。元数据审查
元数据是数据的一个方面,每个人都了解但很快就会忘记。元数据是数据集的隐藏细节和信息,通常随数据集一起下载。您可以将元数据视为数据的自述文件。它解释了数据集内观察到的变量、时间覆盖范围、分辨率(或粒度)、发布日期、创建者等特征。
当您使用 wget 或 REST API 将数据集直接拉入 Excel、R、Python 或 Julia 时,您并不总是能看到元数据。有时数据被直接拉进数据框、矩阵、向量等,你没有时间做一个完整详细的检查。在其他情况下,您可能会下载数据而根本没有获得任何元数据,在这些情况下,您应该对您拥有的信息保持警惕。尝试做一些额外的调查,以找到更多关于您刚刚导入到 r 中的内容的信息。作为一项挑战,您能找到常用 Iris 数据集的元数据吗?
请经常查看元数据,这样不仅可以更好地了解您正在使用的数据,还可以验证其真实性。是否有缺失字段?有细节遗漏吗?如果元数据字段中似乎缺少了显而易见的关键细节,那么可能需要一些额外的调查来找到它。始终通过查找和阅读元数据进行彻底的背景调查。

NCEI 气候数据目录。作者照片。
3。 (比较)描述性统计
描述性统计本身并不足以检验数据质量。原因是数据集的平均值、中值、最小值和最大值不能告诉您数据是否来自可靠的来源,或者数据是否被篡改过。缺失值不是欺诈性数据的标志,许多著名的数据源都有缺失值。零不是坏数据的指示符,许多观察值可能真的是零,或者零可以用作指示坏数据的方式(尽管在其他情况下需要使用零,因为它可以影响数据集的整体统计;您更有可能看到 N/A、Null 或-9999)。
但是,如果您的数据非常常见,您可以比较两个数据集,以确定它们是否在彼此的范围内。我称之为比较描述统计学。例如,我用于降水研究的两个数据集是北美区域再分析(NARR)和气候预报系统(CFS)。这两个数据集都是栅格,具有不同的像元大小(分辨率),测量方式也略有不同。我可以对两者的同一时间段进行观察,进行描述性统计,看看它们有多相似。通常,尽管分辨率不同,我们还是会看到相似的结果。
如果您自己的研究有多个数据集,最好同时获取两个数据集并比较它们的值。应该调查任何主要的差异,如果需要,您可以使用这些信息来丢弃数据。

北美区域再分析降水的合成图。作者照片。
我希望你发现这三个技巧对识别好的数据有帮助。鉴于当今数据科学家可获得的海量信息,梳理每个数据集可能具有挑战性,但构建有用且可靠的模型是非常必要的。请继续关注我的下一篇文章,了解如何快速轻松地找到好的数据!
您的数据在云中安全吗?
在云中工作时要记住的 4 个注意事项

miosz klin owski 在 Unsplash 上拍摄的照片
欢迎阅读关于云系列中的数据的新文章。如果您错过了之前的任何文章,我建议您快速阅读并赶上进度,因为在本文中,我们将继续讨论云,强烈建议结合上下文。在云系列的第一篇文章中,我们讨论了云的优势和劣势,以及它如何帮助您的业务。在第二篇的中,我们解释了不同的云服务模型是什么,以及您在每种模型中负责什么。
在本文中,我想与您分享一些关于安全性的想法,这个问题已经成为那些考虑使用云解决方案的人非常关心的问题。更具体地说,我们将讨论数据安全性。我相信您已经厌倦了听到有关数据中心安全漏洞将敏感数据暴露给公众的新闻。我也确信,人们会想到大公司如何利用数据来更好地了解他们的客户。当你听到云的时候,你可能会想到这一切,这通常会产生很多不信任,但事实是,你的想法是有偏见的,受到这个问题所造成的所有媒体的影响。
虽然安全是我热爱的领域,但我不是安全专家,我写这篇文章的目的不是列出必须考虑的一系列优点或缺点。我唯一的目的是提供一些你可能已经想到的考虑因素,并邀请你去思考它们。欢迎在评论中留下你的想法,我会尽力回答。
云提供商(大部分)是安全的
如果你不信任云,问自己一个问题:你是把钱存在银行里还是放在床底下?一般来说,人们把存款存在银行里。为什么?因为这样更安全。你的房子似乎很容易成为小偷的目标,但很少有人会去抢银行。为什么“大部分”是安全的?因为绝对安全是不存在的。
许多人认为抵制云迁移的原因之一是数据“转移”到云提供商。“我的公司数据会在第三方服务器上,为什么不能保存在我的服务器上?这样更有保障。”是的,你公司的数据会在不属于你的服务器上,那又怎样?你的云提供商会窃取你的数据吗?回到之前的例子,你的银行偷你的钱有意义吗?一般来说,将你的数据存储在云提供商那里并不会带来安全风险。
另一方面,您可能会怀疑云提供商是否能看到您存储在他们云中的内容。如有疑问,在开始任何云活动之前,我建议您阅读服务条款以及您选择的云提供商的隐私政策。实话实说,作为服务提供商,未经客户同意访问他们的数据是非法的。确保你没有同意。你的内容是你的,不是别人的。
你的数据在哪里?
另一个最常见的问题是您的数据在哪里。云是一个听起来如此抽象的术语,以至于你会认为你的数据可能在任何地方。
事实是,云提供商拥有庞大的基础设施,并且遍布全球。我接下来要说的内容可能会因不同的云提供商而异,但大多数都是这样组织的。
云提供商的基础设施分布在世界各地的不同地区。您可以随时选择要在哪个区域工作,因此您可以控制数据的存放位置。这样,你将能够遵守相应的法规。
当您选择一个地区时,除了选择最适合您的地区之外,您还必须记住,并非所有地区都有相同的服务目录,因此,根据您要使用的服务,您会稍微习惯于使用特定的地区。然而,大多数“共同”服务通常在所有地区都可以获得。
你是个风险
当我们谈论安全时,你应该永远记住,最薄弱的环节是你自己。一个不安全的密码、一个禁用的多因素身份验证、一台未锁定的计算机,都足以导致安全漏洞,带来可怕的后果。像贵公司这样的公司越来越意识到这一点,并投资培训员工以降低安全漏洞的风险。同样,作为云服务的客户,我们有责任确定谁可以访问我们的数据,谁不可以。
简单总结一下,我们作为客户,负责云中的安全,而云提供商负责云中的安全。因此,您必须确保只有适当的人才能访问信息,并授予最低的访问权限,以便他们能够执行符合相应安全策略的任务。
可以想象,根据您在云上使用的服务模型,配置工作会或多或少。你必须意识到,在每一种情况下,你要对什么负责。管理具有持久存储的虚拟机不同于管理 Google Drive 文件夹的权限。
数据加密
另一个重要的话题是数据加密。加密被定义为对信息进行编码的过程,该过程将信息转换成理想情况下只能由接收者解码的表示形式。我们不打算在本文中讨论密码学,因为这是一个太宽泛的话题。你必须明白的重要思想是,当你的数据被加密时,理想情况下,只有拥有解密密钥的人才能读取它。
当我们谈到数据加密时,有两种情况可以而且应该加密数据:
- 静态:当你的数据存储在云提供商那里,并且没有被使用时,它必须被加密。这样就算有人“抢银行”,也什么都不懂。
- 传输中:例如,当你在两台服务器之间传输数据时,它必须被加密。这样,如果有人拦截了通信,就像前面的情况一样,他们将什么都不明白。
正如我们所看到的,在开始在云中工作之前,我们必须考虑一些事情。有了正确的措施,在云中工作通常是安全的。云提供商将完成必要的任务来确保其基础设施和服务的安全,但请记住,最终是您必须通过应用严格的访问策略或数据加密来确保云中的数据安全。
感谢阅读“云中的数据”系列的第三篇文章🤗。
您的数据战略是否遗漏了一个关键领域?
任何一项数据计划所带来的好处都将受到组织信息素养成熟度的影响和限制。

马克·吐温著 AF 布拉德利著。维基共享(公共领域)
向任何数据领导者询问他们的数据战略;他们可能会从他们的现代数据架构开始,提到诸如数据湖、事件流或非结构化/半结构化数据等时髦词汇。接下来,他们可能会钻研他们正在使用或计划使用的技术。例如,Kafka、Fivetran、Snowflake 或 Looker 都可以用来解释他们的数据策略。你所询问的数据领导者也可能描述他们打算如何通过他们的数据科学团队来操作他们的 ML 驱动的见解或开发复杂的模型。
数据栈背后的架构、模式和技术本身并不是数据策略。同样,您打算通过该数据堆栈实现或执行的业务目标本身并不是数据策略。那么,什么 你缺什么?
有时
时光倒流一点点,你会发现到处都是数据专业人士,他们渴望解释“数据湖”将如何彻底改变我们管理大量数据的方式。数据湖的主要和固有优势是什么?首先,提供一个“转储”数据的地方,然后弄清楚它的用途。数据湖可以消除所谓的数据孤岛。
再往前追溯,你会发现数据仓库和数据集市的支持者。现在,你会听到更新的概念,如数据湖屋或流行的水冷却器概念,数据网格。数据网格的主要固有优势是什么?为了启用,数据湖打算消除的数据筒仓结构。
计算的进步淘汰了传统的建模技术。物理模型可以成为逻辑抽象。范式转变和数据平台即服务支持不同的大规模数据域。
改变。在这个世界上,景观不断变化,技术来来去去,模式和观点在解决问题/创造问题的永恒舞蹈中潮起潮落,什么是你的基本数据策略?
抽象的目标
最强大的目标有时也是最简单的。虽然持续交付能够实现您的运营和业务目标的数据实践对您的战略至关重要,但定义一个与当前技术或业务趋势无关的更抽象的目标变得越来越重要。经常被忽略的抽象目标是什么?它是组织内企业数据和信息素养的结构化和持续传播。有一种遗留的期望,即只有数据分析师需要理解概念数据模型,只有软件工程师需要理解架构,或者只有业务分析师从详细的、跨领域的业务事件理解中受益。
任何一项数据计划所带来的好处都将受到组织信息素养成熟度的影响和限制。
叙述的基础
达到的信息素养程度不会因人而异,也不会因团队而异。它不是客观可测量的,只是数据策略的一部分,尽管是基础部分。然而,对开发和传播数据驱动文化这一核心组件的认真关注不应该作为优先事项被忽视。
如果利用它们的团队不符合定义、业务相关性、影响它们的变量或使用它们的基本愿望,那么提供见解、为您的解决方案带来五个 9 以及复杂的数据科学模型都将毫无意义。
“不读书的人并不比不识字的人优越”这句格言最初是马克·吐温说的。
作为一名现代数据领导者,你的工作不仅仅是讲述故事,甚至教组织阅读,还要激发阅读的欲望和渴望。
请关注我或通过我的推荐链接注册 Medium 来支持我的写作。谢谢!
你的深度学习模型好吗?
一个新的深度学习框架,使得在 PyTorch 中构建基线变得简单

说你是研究员;你对一个全新的神经网络架构或一个看起来奇怪的优化步骤有一个创新的想法,这有可能成为深度学习领域的突破。你应该如何测试你的方法?
另一方面,假设你是一个机器学习工程师,你想测试你建立的模型是否有意义。这是你能做的最好的吗?选择一个现成的、经过实战检验的算法并部署它不是更好吗?
Lightning Flash:一个新的深度学习框架,使得在 PyTorch 中构建基线变得微不足道。真的!
答案不应该令人惊讶:你需要设定一个基线。在学术界,基线通常是关于特定任务和数据集的最新发布的结果(假设这设置了新的艺术状态)。在行业中,基线在很大程度上是特定于领域的。
然而,没有人愿意花费太多的时间来实现基线。如果你有一些快速的东西来集中你的时间迭代你的方法,那将是最好的。这就是我们今天要讨论的: **lightning-flash** 一个新的框架,让在 PyTorch 中构建基线变得微不足道!
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
电闪

闪电侠围绕着任务的想法。到目前为止,框架附带的任务有助于解决图像分类、图像嵌入、文本分类和摘要、表格分类和翻译的挑战。更多的即将到来,当然,你可以随时建立自己的。
所以,我们假设你要解决膜翅目图像分类挑战,预测某张图像中是有蚂蚁还是有蜜蜂。正如我们已经看到的,首先,我们需要一个基线。怎么做?让我们从工具箱中取出图像分类任务并敲钉子。
在要求模型进行预测之前,我们需要在数据集上对其进行微调。这对于lightning-flash来说非常简单:
现在,我们已经准备好获取模型对测试数据的预测。让我们将 3 张蚂蚁的图片输入到我们微调过的模型中。我们期望得到相同的类,或者是0或者是1,这取决于哪个索引被用作‘ant’类的符号。
事实上,我的终端上的结果是这样的:
[0, 0, 0]
如果我们想进一步测试这一点,我们也可以添加蜜蜂的图像,或者指示我们的模型用整个文件夹来生成预测:
几分钟后,我们得到了基线。最重要的是,记住闪电是无限可扩展的;您可以用几行代码构建自己的任务,适应自己的架构,将训练扩展到多个 GPU,并采用最佳实践,如混合精度训练!
入门指南
最好的开始方式是阅读文档。但是,如果您使用 VS 代码并安装了 Docker,我可以让事情变得更简单:
- 安装
[remote-containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)扩展 git clone [https://github.com/dpoulopoulos/medium.git](https://github.com/dpoulopoulos/medium.git)- 导航至
lightning_flash示例文件夹 - 启动命令面板(
ctlr + shif + p)并键入Reopen Folder in Container
几分钟后,您将获得一个开发环境,其中包含测试lightning-flash所需的一切。阅读下面关于remote-containers扩展以及如何使用它进行开发的更多内容。
结论
无论你是研究人员还是工程师,你都需要强大的基线来取得进展。然而,建立基线不应该花费你一整天的时间。
基于 PyTorch 和 PyTorch Lightning 构建的新深度学习框架 Lightning Flash 使这个任务变得微不足道。让我们看看我们能用它来建造什么!
关于作者
我的名字是迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据操作的帖子,请关注我的 Medium 、 LinkedIn 或 Twitter 上的 @james2pl 。此外,请访问我的网站上的资源页面,这里有很多好书和顶级课程,开始构建您自己的数据科学课程吧!
Zillow 是不是“被诅咒了?”行为经济学视角
意见
iBuying 业务告诉我们预测模型的使用和误用
(本文基于我的书 【使用 R 和 Python 的行为数据分析:真实业务结果的客户驱动数据】【1】)
简介
房地产公司 Zillow 最近宣布,在过去几个月亏损超过 3 亿美元后,它将关闭其购房部门 Offers,并解雇 25%的员工。
Zillow Offers 是该公司进军 iBuying 的一次尝试:用 Zillow 的话说,“即时买家,通常被称为 iBuyers,是一种房屋买卖服务,通常以市场价格直接从卖家手中购买场外房屋,并在进行轻微维修和更新后迅速在公开市场上出售”【6】。Zillow 的核心业务是列出待售房产(即房地产市场),这是一项由他们著名的房屋估价工具 Zestimate 支持的活动。
作为一名行为科学家,我很清楚后见之明和叙述偏见。当专注于一个单一的过去事件时,很容易陷入一个简单解释的幻觉,而这个解释一直是可预测的。人们也很容易采取“内部观点”,关注手头案件的细节和轶事,而不是采取更广泛的“外部观点”。例如,我看到过类似“数据科学对于这个用例来说不够精确”或“市场太不稳定”的解释[3,4,5];这些并没有说明在同一时期,其他 iBuyers,如 Opendoor 和 Offerpad,比 Zillow Offers 表现得更好。然而,有充分的理由相信预测分析不是这个行业的正确工具。在描述这些原因之前,我将首先介绍不同类型的分析。
不同类型的分析
“数据科学”已经涵盖了所有的业务分析,只要它们足够新奇,但在我看来,一个关键的区别在于描述性分析、预测性分析和因果分析:
- 描述性分析提供了数据的描述。简单地说,我认为它是“现状”或“我们衡量的”分析。上个月有多少客户取消了订阅?我们去年赚了多少利润?描述性分析是最简单的分析形式,但它也没有得到应有的重视。许多组织实际上很难获得清晰统一的运营视图。
- 预测分析提供了一种预测。我认为它是“假设目前的条件持续下去,将会是什么”或“我们还没有测量”的分析。大多数机器学习方法都属于这种类型的分析,并帮助我们回答诸如“下个月有多少客户会取消订阅?”以及“该订单是否具有欺诈性?”
- 最后,因果分析提供了数据的原因。我把它想成“如果呢?”或“在不同条件下会怎样”的分析。它回答了一些问题,比如“除非我们给他们发优惠券,否则下个月会有多少客户取消订阅?”。
在过去 25 年左右的时间里,预测分析席卷了整个世界,如今,大批数据科学家正忙于为企业构建预测模型。这些模型并不完美(正如约吉·贝拉所说,“很难做出预测,尤其是对未来的预测”),但它们通常胜过拥有数十年经验的人类专家。那么,我们为什么应该期待预测分析在智能交通领域表现不佳呢?有两个原因:
- 房屋买卖行为受到多种波动因素的影响(又名人类是复杂的);
- iBuying 市场具有很强的战略意义。
在接下来的两节中,我将研究这两个方面并指出它们的解决方案。
房屋买卖行为受多种波动因素影响
当所研究的现象服从少数稳定且众所周知的因素时,预测分析效果最佳。让我们以风力涡轮机的预测性维护为例:
- 相关因素的数量是有限的,它们之间的相互作用也是有限的。一旦你考虑了风力、运动部件之间的摩擦和材料的腐蚀,你就对将要发生的事情有了很好的把握。
- 物理定律是不变的(引力不放任何一天假!).
- 物理学很好理解。为了简单起见,模型可能会忽略次要或罕见的现象,如百年一遇的风暴,但即使出现这种异常情况,结果仍然是可以预测的:叶片将会断裂和坠落,而不是罢工或退出。
另一方面,在房地产市场:
- 有许多许多不同的因素在起作用——人口统计、经济,但也有文化和心理因素——它们有着复杂的相互作用。这意味着即使是 3 或 4 个最重要的方面的预测能力也会令人失望地低。
- 这些因素不是恒定的;偏好会随着时间而改变,有时会变得很残酷。房地产市场的三个特征放大了这一点。第一,行为“参差不齐”;一次买或卖一整栋房子,消费者不可能轻易减少他们每月 5%的住房消费。二是交易时机灵活;人们可以根据市场情况匆忙或推迟购买新房子,而不是推迟购买食品或家庭用品。最后,住房可能是人们财富的一大组成部分,这放大了价格变化的影响(相反,当咖啡变得更贵时,更少的人变得更富有并疯狂消费)。这可能会导致交易量出现过山车式的变化,这在其他消费品中是看不到的。
- 前两个方面的结合意味着市场可能的“状态”数量是巨大的(这个问题在统计学和其他定量领域被称为“维数灾难”)。从数学建模的角度来看,这具有重要的意义。预测分析在预测与训练数据“足够接近”的预测值组合的结果时表现最佳。不可否认,在任何非平凡的数据集中,拥有个唯一的个数据点,以及训练数据集中从未出现过的预测值组合是很常见的(几乎任何连续变量,如身高或收入,都会出现这种情况)。但是,大多数情况下,即使是唯一的数据点也可以通过训练数据集中的点的线性组合来近似。相反,在房地产市场的情况下,很容易想象整个本地市场(比如说,凤凰城地区)立刻就进入了未知的水域。然后,预测分析必须依赖外推,随着我们远离先前观察到的值,外推变得越来越不稳健(也称为过度拟合)。
“就房地产市场而言,很容易想象整个本地市场(比如说凤凰城地区)会立刻进入未知领域。预测分析必须依赖外推,随着我们远离之前观察到的值,外推越来越不可靠(也就是过度拟合)。”
因此,房地产市场为分析提供了一个棘手的难题。这不是一个新问题。早在 20 世纪 70 年代,宏观经济学家罗伯特·卢卡斯(Robert Lucas)就阐明了这一点(凯恩斯模型的“卢卡斯批判”)。他建议我们识别人类行为的更深层次的参数,比如消费者偏好,我非常同意。
将因果分析与潜在行为驱动因素的分析结合起来使用,可以缓解这些问题。在我的书中,我为此开发了我所谓的“数据分析的因果行为框架”。

数据分析的因果行为框架
预测分析满足于构建高准确度的黑盒,而因果分析则致力于挖掘在某种情况下起作用的基本规律和规则。这种目标上的差异意味着因果分析在“常规”情况下的预测能力通常低于其预测兄弟,但在更复杂和多变的情况下会大放异彩。
iBuying 市场具有很强的战略意义
iBuying 业务的一个重要特点是,你对单个物业进行投标。这句话实际上有很多东西需要解开,所以让我们一次解开一部分:
- 每个属性都是独一无二的。即使在最统一的市场中,房屋之间也略有不同(例如不同程度的磨损)。特别是,不同位置的两个几乎相同的房子不能像超市货架上的豆子罐头那样互换;购房者对不同地段的偏好不同:有人的“离市区远”,就是有人的“离我父母近”。
- 每笔交易都是独一无二的。超市出售许多相同或相似的商品,而房地产交易大多是一对一的。即使有人在卖几套房子,一套房子的价格也不会自动适用于另一套。房子也是不经常转手的长效产品。
- 没有固定的价格。卖家从相对较高的价格(与他们的预期相比)开始,逐渐降低价格,直到找到买家。反过来,买方可能会试图通过谈判降低价格。相反,没有正式公布销售价格的人可能仍然会接受潜在买家的自发报价。这一点在这里尤其重要,因为 85%的 iBuyers 购买的是以前不在市场上的房子(资料来源)。最后,当多个买家对同一物业感兴趣时,他们可能会出价高于对方,因为没有“先到先得”的规则。
所有这些方面结合起来意味着,所谓的“房地产市场”实际上是一个房子的个体、临时、议价市场的松散集合。因此,Zillow 宣称的成为房地产“做市商”的愿望——类似于股票市场的“做市商”——充其量也只是一个不稳定的基础。我们谈论“约会市场”,但成为它的做市商意味着什么???
特别是,这让 Zillow 受到了赢家的诅咒。拍卖理论中这个听起来不祥的概念指的是本质上导致买家支付过高价格的情况。通过一个简化的例子可以很好地理解这一点,所以让我们想象一下,在一个市场中有三个 iBuyers。他们每个人都建立了一个机器学习模型来预测他们可以有利可图地购买和出售房屋的价格。因为他们可以使用相同的资源(装修承包商等)。),这三个价格都一样。比方说,一栋 30 万美元的房子是一笔有利可图的交易,不管是哪家卖家做的。这三家公司建立的预测模型也很相似:它们中的每一个都有三分之一的时间正确预测价格(在前面的例子中是 30 万美元),三分之一的时间低于 10%(27 万美元),三分之一的时间高于 10%(33 万美元)。这意味着,就其本身而言,每种模式都相当合理且有利可图。最后,为了简单起见,我们假设三个模型的误差是独立的。一家公司的模型预测超调并不影响另一家公司的模型准确的概率,也不影响其误差的方向。
如果这三家公司在一个给定的市场上相互竞争,他们最终将平均获得三分之一的房屋,但大多数都是以虚高的价格购买的。一般 30 万美元的房子会收到一个 27 万美元的出价,一个 30 万美元的出价,以及一个 33 万美元的出价。换句话说,尽管每家公司的平均出价是有利可图的,但平均的中标却不是。胜利者被自残的成功所诅咒。
“尽管每家公司的平均投标都是有利可图的,但平均的中标却不是。胜利者被诅咒以自残的成功”。
您可以看到这与预测分析的局限性有着怎样的联系。即使一个模型能够非常准确地预测一处房产的潜在转售价格,如果使用不当也会导致损失。最重要的是,任何销量或市场份额目标都将使你的盈利能力取决于你的竞争对手的模型的准确性:如果你的竞争对手有糟糕的模型,并为物业支付过高的价格,你只能通过支付更高的价格来击败他们!幸运的是,博弈论者和拍卖理论家已经开发了模型和工具,可以通过模拟其他参与者的战略行为来帮助缓解这些问题。
结论
概括一下:我不认为 iBuying 业务存在固有缺陷,我也不认为算法在定价方面不如人类的观点有说服力。然而,我确实认为这一业务线为预测分析带来了独特的挑战,预测分析产生了一些更广泛的见解:
- 就像谚语中的锤子一样,预测分析并不总是适合某项工作的工具。有时一个问题需要描述性或因果分析。
- 如果你想让你的模型在经济周期和动荡中表现良好,你需要理解并考虑人类行为的基本的、持久的驱动因素。
- 一些市场大大偏离了许多买方和许多卖方以单一价格交换相同产品的理论理想。在这种情况下,你需要使用相关的经济学概念,如博弈论和拍卖理论。否则,你也会被诅咒!
但是等等,还有呢!
最后不要脸的塞来了。如果你想了解更多关于赢家的诅咒,̶y̶o̶u̶̶s̶h̶o̶u̶l̶d̶̶r̶e̶a̶d̶̶m̶y̶̶b̶o̶o̶k̶,你应该读读理查德·泰勒的书。),另外在 LinkedIn 上关注经济学家约翰·李斯特。然而,如果你想了解更多的因果分析以及如何在商业中使用它来理解人类行为,我的书会告诉你:
- 如何建立因果图,理解因果关系;
- 如何想清楚更深层的心理和行为因素;
- 如何建立模型,为商业决策提供有益的信息;
- 以及许多其他关于在商业中分析客户数据的很酷的事情。

参考
- [1] F. Buisson,用 R 和 Python 进行行为数据分析:真实业务结果的客户驱动数据,奥赖利媒体,2021。
- [2] R. Thaler,《赢家的诅咒:经济生活中的悖论和异常现象,第一版。1994 年,kindle ed。2012.
- [3]《卫报》,《3 亿美元的翻身仗:房地产网站 Zillow 的一方骗局是如何严重出错的》 ,2021 年 11 月 4 日。
- [4]华尔街日报,Zillow 到底哪里出了问题?2021 年 11 月 17 日,一个房地产算法打乱了它的大赌注。
- [5]连线,为什么 Zillow 无法让算法式房屋定价发挥作用,2021 年 11 月 11 日。
- [6] Zillow Research,2021 年 9 月 7 日,iBuyers 帮助人们搬家的次数创下纪录。
《ISLR 评论》:开始你的 ML 之旅的理想教材
你是不是也一直在想接下来要学什么?让 ISLR 成为你阅读的下一本教科书——复习和学习技巧。
几个月前,我觉得我的机器学习基础有点不牢固。我想开始 Kaggle,但是我被所有可用的技术吓倒了。我想尽可能高效地改变这一点,我已经找到了一个好的解决方案。我很兴奋现在就和你分享!
在这篇文章中,我将告诉你我在 R (缩写为 ISLR )的统计学习导论教材中的工作经验。我希望这能帮助你弄清楚你是否也应该捡起来,我也会分享一些让你学习更有效率的小技巧。

这么多书要读,时间却这么少——一定要挑一本好书!|照片由 Alfons Morales 在 Unsplash 上拍摄
为什么我选择了 ISLR
大约一年前,我开始了我的机器学习之旅——当我开始厌倦时,我在 Coursera 上完成了吴恩达著名的 机器学习课程。虽然我喜欢这门课程,它给了我一个工作的基础,但我觉得我需要更多的帮助和指导来用实际的方式使用 T21 新学到的知识。我想学习更多的技术,比如随机森林,更多地了解何时使用哪种算法,以及如何在 Python 中实际实现它们。我想创办 Kaggle,所以我决定参加 Kaggle 的和课程。当第一批 Kaggle Learn 教程中有一个是关于实现决策树,但是没有解释是什么或者它是如何工作的时候,我很快就泄气了。在半个小时的疯狂搜索和阅读了许多没有真正解释任何东西的博客帖子后,我决定我需要一些知识更详细和更有条理的东西——一本教科书。
挑选教材时,我在寻找以下内容:
- 入门/本科水平,容易理解,不适合博士生
- 深入数学的细节,但也解释了直觉
- 介绍了 Ng 的课程中没有涉及的许多不同的 ML 技术
- 实用,有编码练习来实现我所学到的东西
- 可在 2-3 个月内完成
经过一番 Reddit 深潜(go joinr/learn machine learning)发现最值得推荐的入门水平书好像是 ISLR 。它也满足了我想要的所有要求,所以我试了一下。
关于 ISLR 的一切
这本书的好处在于它可以从作者的网站上免费下载。你可以先看一眼,然后决定你是否喜欢这本昂贵的教科书。然而,我确实建议获得一个物理副本来浏览它。
如题所示,ISLR 在 R. 中用例子和练习介绍了统计学习技术,但是什么是静态学习呢?这本书将它定义为“理解数据的一套庞大工具”。一般来说,统计学和 ML 之间正在进行一场战斗,你可以在这篇非常有趣的帖子中读到它。关于这本书,与通常的 ML 资源有轻微的文化差异,有时是不同的术语(例如,“Lasso/Ridge”而不是“L1/L2”),有些侧重于经典的统计概念(如 p 值和假设检验),但它主要解释了通常可以归类为 ML 算法的方法,如回归、支持向量机、基于树的方法和无监督学习概念。
这本书是为不同行业和背景的人设计的,这些人需要在他们的专业领域处理数据,而不一定需要大学水平的数学教育。这本书并没有比一本入门数学课程,更多的数学背景,也没有使用矩阵或向量符号来简化事情。它也不假设任何以前的 R 经验,认真讲解每一行代码,包括写函数和制作剧情。
ISLR 分为 10 章,从介绍性章节开始解释符号、偏差/方差权衡,并介绍 r。在第一章之后,所有后续章节都围绕选定的技术,从线性回归慢慢构建到更复杂的概念,如随机森林和层次聚类。每一章的结尾都有实验,指导你实现本章所教的方法,并进一步概念和编码练习来加深你的理解。
在每一章中,重点是对概念的高层次理解和良好的直觉。我发现对于我所需要的这本书来说,这些细节已经足够了,可以自信地在我自己的项目中使用一个方法的实现。它通过列出优缺点来比较类似的方法,并给出一种方法优于另一种方法的例子。作者用简单的数据集和真实的例子来说明每一种方法,这进一步有助于直觉。我特别喜欢几乎每一页上丰富多彩的图表——每当解释新的东西时,都会有一个图表来说明数据上的概念。

可访问所有数学背景和漂亮图片|照片由 Ben White 在 Unsplash 上拍摄
ISLR 被推荐给谁?
我认为你肯定会从阅读这本书中获得很多价值,如果以下任何一条适用的话:
- 你想要一个单一的信息来源来解释最流行的 ML 方法的基础,而不是花费大量的时间来搜索不同质量的相关文章和教程
- 您想做 Kaggle,但是对所有可用于数据的 ML 方法感到害怕
- 你知道算法在理论上是如何工作的,但不知道如何开始实现它们
- 你需要一本解释直觉的预备教材,然后才开始阅读数学厚重的研究生教材
- 在数据科学面试之前,你要提醒自己算法背后的数学。据我的一些朋友说,这本书里的材料对一些数据科学家毕业生的在线面试非常有帮助(也足够了)。
一些提示
将 ISLR 移植到 Python
这本书是 R 语言的,很多人(包括我)在他们的数据科学项目中不使用 R 语言。不过,如果你和我一样是团队 Python,这本书还是很惊艳的。你可以阅读它并接受一个挑战:用 Python 而不是 r 解决实验室问题。
这给了你一个框架,让你通过练习来实践理论概念,但是更少的手动操作:你不能只是重新键入 R 代码来完成实验,你必须首先弄清楚如何去做。这将意味着深入研究 Numpy、scikit-learn 和 StatsModels 库文档,并理解每个函数中的参数,以获得与 r 中相同的行为。老实说,这样做给我带来的益处至少与阅读这本书给我带来的益处一样多。
好的一面是,如果你被卡住了,你总是可以查找其他人的解决方案,因为许多人已经这样做了。(这里有 我的 GitHub 回购与 Python labs ,但你总是可以谷歌“Python 中的 ISLR”并找到十几个其他回购。)
认证在线课程+视频
比起视频,我更喜欢书,但我们都不一样。如果你从视频中学得更好,你不必担心——作者已经根据这本书录制了一门课程,以补充你的阅读。 15 小时 Youtube 播放列表从 链接至此 。
如果你通过努力获得一张证书而变得更有动力,你可以购买这张证书来展示你的简历,这个选择也是存在的。斯坦福大学在 edX ,网站上提供课程 ,如果你决定购买证书,还会有额外的练习和反馈。
时间范围
如果你想让自己负起责任,这里有一个估计,你可以如何为自己设定目标来完成这本书:
- 我估计这本书可以在 10 周,内完成,每周工作大约 5-6 小时(如果你是自己移植到 Python 的话,8-10 小时)
- 如果你做笔记的话,通读一章的文本大约需要 2 个小时,半个小时用于概念练习,一个小时用于 R 语言的实验(或者对我来说用 Python 最多 4 个小时),1-2 个小时用于编码练习。当然有更短和更长的章节,但这是我对平均值的粗略估计。
单独阅读一本教科书可能会有点让人泄气——没有像在线课程那样的提醒和红色弹出窗口。我建议你给自己设定一个目标,在某个特定的日期前完成每一章,让自己保持动力。这是一本非常受欢迎的书,你可能也能在 Reddit 上找到一些负责任的伙伴。

独自完成一本教科书是一项艰巨的工作……|照片由 Siora 摄影在 Unsplash 上拍摄
下一步做什么?
如果你已经读完了这本书,你应该会对应用机器学习方法来解决你选择的问题感到更舒服一些。如果您感兴趣,您可能已经准备好开始使用数据集进行实验,并在 Kaggle 上进行实践。如果你正在寻找一种温和的比赛体验,我推荐从 表格游乐场系列 开始。这些数据集易于使用,不占用大量计算资源,非常适合尝试各种简单的模型。如果你想了解更多,我可以全力推荐 Rohan Rao 的文章逐步接近 Kaggle。
如果你对在 ISLR 学的数学还不过瘾,并且有扎实的线性代数和微积分基础,我推荐你去看看 《统计学习要素》 (ESL) 。从技术上来说,《ISLR》是 ESL 的入门书,它更多地涉及了数学内容,更像是博士生和研究人员的参考书,而不仅仅是你通读的东西。
无论你决定下一步做什么,我希望这篇评论对你有用,并祝你在机器学习之旅中好运!
原载于 2021 年 4 月 25 日https://Alexandra souly . github . io。
“隔离森林”:任何数据科学家都应该知道的异常检测算法
通过出色的无监督算法进行异常检测(也可在 Scikit-learn 中获得)

[图片由作者提供]
“隔离森林”是诞生于 2009 年的一个高明的异常检测算法(此处为原文)。它已经变得非常流行:它也在 Scikit-learn 中实现(参见文档)。
在本文中,我们将欣赏这种算法背后的直觉之美,并借助一些例子理解它到底是如何工作的。
“为什么异常检测如此困难?”
异常(或异常值)检测的任务是识别与大多数观察值相比“非常奇怪”的数据点。
这在一系列应用中非常有用,从故障检测到发现金融欺诈,从发现健康问题到识别不满意的客户。此外,它也有利于机器学习管道,因为已经证明去除异常值会提高模型的准确性。
异常检测之所以如此困难,是因为它是一个无人监管的问题。换句话说,我们通常没有标签来告诉我们哪些实例实际上是“异常”。或者更确切地说,即使我们有标签,也很难将异常检测框定为监督问题。事实上:
- 异常很少见;
- 异常是新奇的;
- 异常各不相同。
出于所有这些原因,监督技术通常不适合异常检测。
隔离森林有什么特别之处
传统的异常检测方法大致是:
- 描述“正常实例”是什么样子的(这通常涉及到聚类分析)。
- 将不符合这些配置文件的所有实例标记为离群值。
隔离森林引入的创新是,它直接从异常值开始,而不是从正常观察值开始。
核心思想是基于使异常独特的特征来“隔离”异常应该是非常容易的。
从技术上讲,这转化为这样一个事实,如果我们在所有观察值上拟合一个决策树,离群值应该比“正常”实例更接近树的根。
这是什么意思?让我们用一个例子来说明这一点。
假设我们有一个数据集,其中包含了目前活着的所有 7,932,843,214 个人的数据。我们想要多少变量就有多少变量:年龄、净资产、居住地、职称…
这样的数据集中有哪些离群值?请记住,异常值不一定是错误的数据:它们只是与总体中的其他数据点非常不同的数据点。在这个例子中,杰夫·贝索斯肯定是一个异数。
现在想象一下,我们可以拟合一个决策树,使得每个末端叶子包含一个且只有一个人。换句话说,这棵树完全没有修剪。如果隔离森林背后的假设是正确的,那么杰夫·贝索斯会比我自己更接近树根。

一棵完全未修剪的决策树,其中每一片末端叶子代表世界上的一个人[图片由作者提供]
作为一个局外人,杰夫·贝索斯更容易被孤立:只要问一句“他的身价超过 1700 亿美元吗?”就够了在近 80 亿人中找回他。另一方面,由于我比杰夫·贝索斯普通得多,你可能需要至少 10 个是非题来缩小搜索范围,直到找到我。
在引擎盖下寻找
现在我们已经看到了隔离森林背后的主要直觉,让我们借助一些简单的数据点来尝试理解算法的确切机制。
import pandas as pddf = pd.DataFrame({
'x': [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 2.0],
'y': [2.1, 2.4, 3.0, 2.6, 2.2, 2.8, 3.7]
}, index = ['A', 'B', 'C', 'D', 'E', 'F', 'G'])

一些数据点[图片由作者提供]
从 A 到 F 的项目表示一个非常紧凑的点云:它们是“正常的”数据点。与这些实例相比,G 可能是一个异常值:它对于 x 和 y 都有异常值。
隔离林是以树为基础的,所以让我们根据这些数据拟合一棵树:

数据点上的树随机拟合。[图片由作者提供]
注意,这棵树是随机生长的。
这里最基本的概念是每个元素所在叶子的深度。例如,在这个树中,称为 G(我们的离群值)的观察值在深度 1(例如,离根节点 1 层),而 C 在深度 3。
隔离林背后的想法是,平均而言,离群点将比正常实例更接近根节点(即,在更低的深度)。
在机器学习中,关键是迭代。事实上,如果我们随机拟合许多决策树,然后对不同树上的每个观察值的深度取平均值,我们会发现一个“平均深度”,它代表了一个“外部性”的经验度量。
Scikit 中的隔离林-学习
让我们通过 Scikit-learn 的实现来看一个使用示例。
from sklearn.ensemble import IsolationForestiforest = IsolationForest(n_estimators = 100).fit(df)
如果我们从森林中取出前 9 棵树(iforest.estimators_[:9])并绘制它们,我们会得到:

隔离林的前 9 个(100 个)决策树。每个数据点旁边的数字是它在树中的深度。[图片由作者提供]
看一看这前 9 棵树,我们已经可以看到一个模式:G 往往比任何其他点的深度低得多(平均 1.44)。的确,第二个点是平均深度为 2.78 的 A。
从概念上讲,这正是该算法的工作原理:平均深度越低,出现异常值的可能性就越大。
然而,在实践中,我们不能使用平均深度,因为树的深度取决于它所适合的样本数。由于这个原因,我们需要一个公式来考虑实例的总数。这是论文中提出的公式:

刘提出的“另类”评分。[截图自此处
其中 n 是实例的数量, h(x) 是在特定树中找到数据点的深度( E(h(x)) 是它在不同树中的平均值),而 H 是调和数。
s(x,n) 是一个介于 0 和 1 之间的数字,其中分数越高,越有可能是异常值。
注意:Scikit-learn 的实现返回与上面定义的分数相反的分数。所以上面所说的仍然有效,但是带有负号。
在我们的小数据集上,分数由下式给出:
scores = iforest.score_samples(df)
让我们来看看我们每一点的估计分数:

隔离森林估计的分数[图片由作者提供]
正如我们所料,G 更有可能是一个离群值,因为它的分数低于所有其他分数。
除了我们的玩具数据集,模拟算法在某些特定情况下会产生什么也很有趣。例如,如果我们在两个变量( x 和 y )上取一些大致形成圆形的数据点,这是我们将通过隔离森林获得的分数的等值线图:

我们将通过隔离林获得的分数的数据点(左)和等高线图(右)。[图片由作者提供]
有趣的是,不仅最极端的区域可能是异常值,而且位于圆圈中心的部分也可能是异常值,因为它是 x 和 y 的不寻常组合。
感谢您的阅读!我希望这篇文章对你有用。
我感谢反馈和建设性的批评。如果你想谈论这篇文章或其他相关话题,你可以发短信给我我的 Linkedin 联系人。
Isomap 嵌入——一种令人敬畏的非线性降维方法
机器学习
如何用等距映射“展开瑞士卷”?

等距映射(Isomap)。图片由作者提供。
介绍
我继续机器学习算法系列,看看另一种称为等距映射或简称为 Isomap 的降维技术。
在文章中,我回答了以下问题:
- Isomap 属于机器学习技术的哪一类?
- Isomap 是如何工作的?我通过一个直观的例子来解释,而不是复杂的数学。
- 如何在 Python 中使用 Isomap 对我的数据进行降维?
机器学习算法家族中的 Isomap
有这么多的机器学习算法,可能永远不可能将它们全部收集和分类。然而,我已经尝试为一些最常用的做了,你可以在下面的互动旭日图中找到。确保通过单击浏览图表👇在不同的类别上对进行放大并展示更多的。
机器学习算法分类。由作者创建的互动图表。
如果你喜欢数据科学和机器学习 ,请 订阅 每当我发表一个新的故事,你都会收到一封电子邮件。
如你所见,Isomap 是一种无监督机器学习技术,旨在降维。
它不同于同类中的其他一些技术,它使用了一种非线性的降维方法,而不是 PCA 等算法使用的线性映射。我们将在下一节看到线性和非线性方法的不同之处。
等距映射(Isomap)是如何工作的?
Isomap 是一种结合了几种不同算法的技术,使其能够使用非线性方式来降低维度,同时保留局部结构。
在我们查看 Isomap 的示例并将其与主成分分析(PCA)的线性方法进行比较之前,让我们列出 Isomap 执行的高级步骤:
- 使用 KNN 方法找到每个数据点的 k 个最近邻居。这里,“k”是您可以在模型超参数中指定的任意数量的邻居。
- 一旦找到邻居,构建邻居图,其中如果点是彼此的邻居,则这些点彼此相连。非相邻的数据点保持不连接。
- 计算每对数据点(节点)之间的最短路径。通常,这是弗洛伊德-沃肖尔或迪克斯特拉的算法是用于这项任务。注意,这个步骤通常也被描述为寻找点之间的测地线距离。
- 使用【MDS】计算低维嵌入。给定每对点之间的距离是已知的,MDS 将每个对象放置到 N 维空间中(N 被指定为超参数),以便尽可能地保留点之间的距离。
对于我们的例子,让我们创建一个称为瑞士卷的 3D 对象。这个物体由 2000 个独立的数据点组成。图表是交互式的,所以请务必旋转它,以熟悉它的确切形状。
交互式 3D 瑞士卷。图由作者提供。
接下来,我们想使用 Isomap 绘制这个三维瑞士卷的二维图。为了跟踪这个转换过程中发生了什么,让我们选择两个点:A 和 b。

3D 瑞士卷上两点之间的欧几里得距离与测地线距离。图片由作者提供。
我们可以看到这两个点在 3D 空间中彼此相对靠近。如果我们使用线性降维方法,如 PCA,那么这两个点之间的欧几里德距离在较低的维度上仍然有些相似。请参见下面的 PCA 转换图:

使用 PCA 将 3D 瑞士卷缩减为二维。图片由作者提供。
注意,PCA 中 2D 物体的形状看起来像从特定角度拍摄的同一 3D 物体的照片。这是线性变换的一个特点。
与此同时,Isomap 等非线性方法给了我们一个非常不同的结果。我们可以把这种转变描述为展开瑞士面包卷,把它平放在 2D 表面上:

使用 Isomap 将三维瑞士卷缩减为二维。图片来自作者。
我们可以看到,2D 空间中 A 点和 B 点之间的距离是基于通过邻域连接计算的测地线距离。
这就是 Isomap 能够在平衡局部和全局结构之间的关系的同时执行非线性降维的秘密。
如何在 Python 中使用 Isomap 对我的数据进行降维?
现在让我们使用 Isomap 来降低 MNIST 数据集(手写数字的集合)中图片的高维度。这将使我们能够看到不同的数字在三维空间中是如何聚集在一起的。
设置 我们将使用以下数据和库:
- Scikit-learn 库用于
1)来自 sklearn 数据集的 MNIST 数字数据(load _ digits);
2)执行等距映射(Isomap); - 用于数据可视化的 Plotly 和 Matplotlib
- 熊猫用于数据操作
让我们导入库。
接下来,我们加载 MNIST 数据。

导入数据的形状。图片由作者提供。
让我们显示前 10 个手写数字,这样我们可以更好地了解我们正在处理的内容。

前 10 个手写数字的图像(8x8=64 像素)。图片由作者提供。
等距映射 我们现在将应用 Isomap 将 X 数组中每条记录的维数从 64 减少到 3。

转换数据后的数组形状。图片由作者提供。
最后,让我们绘制一个 3D 散点图,看看将维度减少到 3 后的数据是什么样子。
这是一个带有结果的交互式图。确保旋转它以查看每组数字之间的间隔。
Isomap 结果-3D 空间中的数字集群。图片由作者提供。
正如您所看到的,Isomap 在将维度从 64 减少到 3 的同时保留非线性关系方面做得非常出色。这使我们能够在三维空间中可视化手写数字的集群。
如果我们愿意,我们现在可以轻松地使用分类模型之一,如决策树、 SVM 或 KNN 来预测每个手写数字标签。
结论
Isomap 是降维的最佳工具之一,使我们能够保留数据点之间的非线性关系。
我们已经看到了 Isomap 算法是如何在实践中用于手写数字识别的。类似地,您可以使用 Isomap 作为 NLP(自然语言处理)分析的一部分,在训练分类模型之前减少文本数据的高维度。
我真诚地希望这篇文章能让您轻松地了解 Isomap 是如何工作的,以及它在数据科学项目中的好处。
如果您有任何问题或建议,请随时联系我们。
干杯👏
索尔·多比拉斯
如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加入媒介是:
https://solclover.com/membership
你可能喜欢的其他故事:
找一份数据科学的工作应该总是很难的
意见
随着时间的推移,它也会变得更难。

照片由 Unsplash 上的 Muhammad Faiz zulkefiry拍摄
好事从来都不容易,对吧?这是我找工作时的心态。老实说,当我看起来如此接近的每一个机会都溜走时,提醒自己这一点是非常困难的。在不确定时期保持动力完全是它自己的问题。然而,随着我堆积越来越多的拒绝邮件和自动道歉,我实际上很高兴这个过程如此艰难,就个人而言,我希望它变得更难。
亚当,你是认真的吗?你真的想让你的整个职业生涯都依赖于像想知道你毕业后是否有工作这样困难的事情吗?你真的想日复一日醒来,希望被某个地方接受,只是为了让你知道你可以达到目的吗?
是的。欢迎来到现实。
尽可能简单地说,难以置信的困难是那些为了薪水而工作的人和那些真正想在这个领域推动自己前进的人之间的过滤。
在这里,我们必须对自己诚实,有很多人进入数据科学只是为了钱。你知我知,我真为他们感到难过。他们会精疲力尽,放弃,后悔为了高于平均水平的薪水在他们实际上不喜欢的事情上浪费了这么多时间,但是不要告诉任何人我这么说过。
然而,我不相信大多数读到这篇文章的人会这样想。如果你定期检查数据科学,那么很可能是因为你对其他人以他们自己的方式对该领域做出的贡献感兴趣,这只会促进你自己作为数据科学家的成长。
此外,你点击这篇文章可能是因为你也对申请过程感到紧张。别担心,我们都是。听着,我不是来给你的生活增加压力,也不是来耸人听闻地报道申请过程,点击诱饵只是为了引起你的注意。抱歉。然而,我确实想严肃地指出,申请过程的难度实际上比你实际认为的对你和你的职业更好。
我每天都需要解决新问题。如果不是这样,我真的会疯掉。解决问题对我来说是与生俱来的,尤其是当问题是基于数字的时候。我在这个疯狂的数据领域找到了一个家,我希望以自己的方式在这个领域留下印记。我找到了我的专长,所以现在是时候磨练我的手艺了。你看,人们认为压力是不好的。我认为压力是个人成长和做得更好的一种方式。
作为数据科学家,压力永远不会离开我们。只是不在工作描述里。如果求职是轻而易举的事,那么这说明了工作本身的什么呢?如果找工作和得到回音的过程很容易,那么这说明了这个领域的什么呢?随着时间的推移,我希望申请过程越来越难。我想看看申请人到底是什么样的。当截止日期越来越多,工作压力越来越大时,你将如何坚持下去?你会在压力下崩溃还是会把它当作继续前进的燃料?
让我告诉你一些事情,如果你不能处理申请工作和被拒绝的压力,你还没有准备好工作本身。你会日复一日地在一个项目上投入数小时,结果却被看到它的人彻底毁掉,迫使你不得不从头再来。听起来熟悉吗?工作过程也是如此。
通过确保你有毅力不惜一切代价在这个领域追求职业生涯,你就确保了自己是比大多数人更好的候选人。有些人实际上认为他们可以在没有经验的情况下在 6 个月内找到这个领域的工作。我不想告诉你,除非你已经认识这个领域的人,他们会给你推荐,否则这是不可能的。
不要把困难误认为不可能。我爸爸曾经告诉我,如果在你之前有人做过这件事,那么你也没有理由去做。这一直困扰着我,让看似困难的事情变得微不足道。不是不可能,只是现在对你来说很难。以这样一种方式工作,它对你来说变得不那么困难,你会有少得多的问题。
我希望我没有给你的生活增加更多的压力,而是成为你继续找工作的动力。事情越困难,回报必然会越好。现在有太多的人走捷径,我相信他们缺乏纪律性和远见,最终会产生严重的后果。事实上,我还没有听说过一个不成功的人有耐心、勤奋和努力工作。请证明我是错的。耐心、勤奋、努力工作,让我知道你在 5 年内不可避免地会变得多么不成功。
到时候再聊!
Python 中基于项目的协同过滤
用 python 实现基于项目的协同过滤的实践。

照片由 CardMapr.nl 在 Unsplash 上拍摄
基于项目的协同过滤是利用用户评分,利用项目间相似性的推荐系统。在本文中,我解释了它的基本概念,并实践了如何使用 Python 制作基于项目的协同过滤。
基本概念
这种方法的基本假设是用户对相似的电影给出相似的评级。考虑下面的电影分级表。

在本例中, **User_1**对**Movie_1**的评级为空。让我们使用基于项目的协同过滤来预测这个评级。
- 步骤 1:找到与你想要预测分级的电影最相似(最接近)的电影。
有多种方法可以找到最近的电影。在这里,我使用了https://en.wikipedia.org/wiki/Cosine_similarity余弦相似度。在使用余弦相似度时,替换为 0 的缺失值。看下图。 x 轴代表**User_0**的等级, y 轴代表**User_1**的等级。然后,我们可以为空间中的每部电影找到点。例如,**Movie_3**对应于空间中的点(5,2)。

余弦相似度用 cos(θ) 来衡量两个向量之间的距离。随着θ增大,cos(θ)减小(θ= 0°时 cos(θ) = 1,θ= 90°时 cos(θ) = 0)。因此,θ值越小,这两个向量就越接近(相似性越大)。由于θ1 最小,θ3 最大,**Movie_3**离**Movie_1** ,,**Movie_2**最远。
****这里值得注意的是,电影之间的相似度是由所有用户决定的。例如,**Movie_1**和**Movie_3**之间的相似度是使用**User_0**和**User_1**的评分来计算的。
- 第二步:计算用户对最相似电影的评分加权平均值。
用户对相似的电影给出相似的评级。因此,当我们预测用户对电影的评级时,使用用户对类似电影的评级的平均值是合理的。将最近邻的数量设置为 2。然后我们使用**Movie_3**和**Movie_0**来预测**User_1**对**Movie_0**的评分。

**User_1** 对**Movie_3**的评分为2,**User_1**对**Movie_0**的评分为 3。如果**Movie_3**和**Movie_0**与**Movie_1**距离相同,我们可以通过**User_1**估算出**Movie_1**的等级为 2.5。但是,如果认为**Movie_3**更靠近**Movie_1**,则**Movie_3**的重量应该大于**Movie_0**的重量。因此,如下图所示,**Movie_1**的预测评级将更接近于**Movie_3**的评级。使用余弦相似度作为权重,预测评分为 2.374。

制作电影推荐器
为了更好地理解,这里使用了具有 10 部电影和 10 个用户的数据集。(数字是随机抽取的。)
**df**

- 10 部电影和 10 个用户
- 0 表示缺少值。
- 用户给电影评分的百分比是 50%(只给 50 分)。在真实的电影数据集中,这个百分比变得小于 10%。
如果用户没有对电影进行评级,我假设用户没有观看电影。
计算最近的邻居
**sklearn.neighbors**库中的**NearestNeighbors()**可用于使用余弦相似度计算电影之间的距离,并为每部电影找到最近的邻居。
from sklearn.neighbors import NearestNeighborsknn = NearestNeighbors(metric='cosine', algorithm='brute')
knn.fit(df.values)
distances, indices = knn.kneighbors(df.values, **n_neighbors=3**)
最近邻居(**n_neighbors**)的数量被设置为 3。由于这包括电影本身,通常它会找到除电影本身之外的两个最近的电影。
indices**[Out] array([[0, 7, 5],
[1, 3, 7],
[2, 1, 6],
....
[9, 0, 7]])**
**indices**显示每部电影的最近邻居的指数。每一行对应于**df**中的一行。一行中的第一个元素是最相似(最近)的电影。一般是电影本身。第二个元素是第二个最近的,第三个是第三个最近的。比如第一行**[0,7,5]**,离**movie_0**最近的电影是自己,第二个最近的电影是**movie_7**,第三个是**movie_5**。
distances**[Out] array([[0.00000000e+00, 3.19586183e-01, 4.03404722e-01], [4.44089210e-16, 3.68421053e-01, 3.95436458e-01], [0.00000000e+00, 5.20766162e-01, 5.24329288e-01],
....
[1.11022302e-16, 4.22649731e-01, 4.81455027e-01]])**
**distances**显示电影之间的距离。数字越小,表示电影越近。该数组中的每个数字对应于索引数组中的数字。
示例:预测用户对电影的评级
预测用户对电影的评价相当于计算用户对相似电影的评价的加权平均值。
实际上,通过**user_7**预测**movie_0**的评级。首先,使用**NearestNeighbors()**找到**movie_0**的最近邻居。
**# get the index for 'movie_0'**
index_for_movie = df.index.tolist().index('**movie_0**')**# find the indices for the similar movies** sim_movies = indices[index_for_movie].tolist()**# distances between 'movie_0' and the similar movies** movie_distances = distances[index_for_movie].tolist()**# the position of 'movie_0' in the list sim_movies** id_movie = sim_movies.index(index_for_movie)**# remove 'movie_0' from the list sim_movies** sim_movies.remove(index_for_movie)**# remove 'movie_0' from the list movie_distances** movie_distances.pop(id_movie)print('The Nearest Movies to **movie_0**:', sim_movies)
print('The Distance from **movie_0**:', movie_distances)

与**movie_0**最相似的电影是**movie_7**和**movie_5**,与**movie_0**的距离分别为 0.3196 和 0.4034。
计算预测评级的公式如下:
【r(m,u) = { ∑ ⱼ S(m,j)R(j,u) } / ∑ ⱼ S(m,j)
- R(m,u) :用户对电影 m 的评分
- S(m,j) :电影 m 与电影 j 的相似性
- j ∈ J 其中 J 是与电影 m 相似的电影的集合
这个公式简单地暗示了用户对电影的预测评级是用户对类似电影的评级的加权平均值。当电影 m 和电影 k 越接近时,每个评价的权重越大。该项的分母使所有权重之和等于 1。******
让我们用**user_7**, R(0,7): 来预测**movie_0**的评分
R(0,7)=[S(0,5)÷R(5,7)+S(0,7)÷R(7,7)]/[S(0,5)+S(0,7)]
由于**movie_0**和**movie_5**以及**movie_0**和**movie_7**之间的距离分别为 0.4034 和 0.3196,相似性为
- S(0,5) = (1-0.4034)
- S(0,7) = (1-0.3196)。
因为 R(5,7) = 2、 R(7,7) = 3,所以预测的 R(0,7) 为 2.5328。
建立一个推荐者
下面的代码预测了所有没有看过的电影的收视率。(**n_neighbors = 3**)
原始数据集**df1**的副本更新了**user_4**的所有预测评级。以下代码是使用更新的数据集为选定用户显示推荐电影的函数。
例如,让我们为**user_4**推荐 5 部电影。
**recommend_movies('user_4', 5)**

输出显示用户已经观看的电影列表和推荐的电影列表。**movie_2**对**user_4**的预测评分最高。
这个项目的目标是建立一个推荐器,为选定的用户推荐电影。如果我们在推荐器中输入一个用户名,推荐器应该返回具有最高预测评级的推荐电影列表。结合上面的代码,我们可以为任何选定的用户构建电影推荐器。
下面用n_neighbors = 3和the number of recommended movies = 4为user_4推荐电影。
**movie_recommender('user_4', 3, 4)**

在本文中,我简要解释了基于项目的协同过滤的基本概念,并展示了如何使用这种方法构建推荐引擎。
本练习的附加代码和电影数据集可以在这里找到。
如何迭代 Python 字典中的键和值
讨论如何在 Python 中迭代字典的键和值

劳伦·曼克在 Unsplash 上的照片
介绍
字典是 Python 中最有用的数据结构之一。迭代字典的键和值是我们在处理这类对象时需要执行的最常用的操作之一。
在今天的简短指南中,我们将探讨如何在 Python 3 中迭代字典。具体来说,我们将讨论如何
- 仅迭代键
- 仅迭代值
- 一次性遍历键和值
首先,让我们创建一个示例字典,我们将在整篇文章中引用它来演示一些概念。
my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
遍历键
为了只迭代键,您需要调用[keys()](https://docs.python.org/3/library/stdtypes.html#dict.keys)方法,该方法返回字典键的新视图。
**for key in my_dict.keys():**
print(key) *# Output
a
b
c
d*
迭代值
为了迭代字典的值,您只需要调用[values()](https://docs.python.org/3/library/stdtypes.html#dict.values)方法,该方法返回包含字典值的新视图。
**for value in my_dict.values():**
print(value)# Output
*1
2
3
4*
对键和值进行迭代
现在,如果你需要一次遍历键和值,你可以调用[items()](https://docs.python.org/3/library/stdtypes.html#dict.items)。该方法将以(key, value)的形式返回一个包含键值对的元组。
**for key, value in my_dict.items():** print(f'Key: {key}, Value: {value}') # Output
*Key: a, Value: 1
Key: b, Value: 2
Key: c, Value: 3
Key: d, Value: 4*
请注意,上面探讨的三种方法返回的对象返回视图对象。换句话说,这些对象提供了字典中条目的动态视图,这意味着一旦条目被修改,视图对象也会反映这种变化。
Python 2 中的字典迭代
Python 2 中的符号与 Python 3 略有不同。为了迭代键值,你需要调用如下所示的iteritems()方法:
for key, value in my_dict.iteritems():
print(f'Key: {key}, Value: {value}')# Output
*Key: a, Value: 1
Key: b, Value: 2
Key: c, Value: 3
Key: d, Value: 4*
最后的想法
在今天的文章中,我们讨论了如何使用keys()、values()和items()方法一次独立或同时迭代键和值。此外,我们讨论了如何使用 Python 2 符号和iteritems()方法迭代键和值。
成为会员 阅读媒介上的每一个故事。你的会员费直接支持我和你看的其他作家。
你可能也会喜欢
[## 如何将 Python 包上传到 PyPI
towardsdatascience.com](/how-to-upload-your-python-package-to-pypi-de1b363a1b3) https://betterprogramming.pub/11-python-one-liners-for-everyday-programming-f346a0a73f39 </6-tips-to-help-you-stand-out-as-a-python-developer-2294d15672e9>
使用 Scikit-learn 进行迭代插补
使用高级插补策略增强模型结果
介绍
虽然对于许多数据科学家来说,拥有一个良好、干净且预处理需求最小的数据集是理想的场景,但真实世界的数据通常并不理想。某些预处理步骤(如归一化和变换)有助于创建可能的最佳模型,但在技术上是可选的,也就是说,如果忽略了输出质量的差异,可以在没有这些步骤的情况下创建模型。然而,一个不容忽视的常见问题是缺少数据。
用给定的统计方法填充缺失数据的过程被称为插补,有多种形式。在本文中,我将讨论一些最常见的插补方法,并将它们与一种更先进的方法迭代插补进行比较,这种方法可以增强模型结果。
常见插补方法
一些最常见的插补方法包括根据现有数据,用给定变量的平均值或中值填充缺失数据。在这两者之间做出选择很大程度上取决于正在处理的数据。在数据以某种方式倾斜的情况下,中位数可能更合适。相反,正态分布的数据可以使用平均值或中位数,因为两者相对来说是相同的。让我们来看看实现它们的几种方法。
使用熊猫和熊猫
用数字和熊猫来计算价值是小菜一碟。在下面的示例中,列A和B各有一个缺失值。然后使用 NumPy 中的nanmean()函数计算列A的平均值,并忽略任何缺失值。同样的过程应用于列B,取而代之的是中值。然后将fillna()函数应用于每一列,以填充缺失的值。下面显示了该代码的输出,右侧包含每个相应列的估算值。

图片作者。上面代码的输出。
使用简单估算器
Scitkit-learn 的SimpleImputer ( 查看文档)是估算缺失值的另一种方法。虽然看起来比 NumPy 和 Pandas 的例子稍微复杂一些,但是使用SimpleImputer有几个关键的好处。首先,缺失值可以设置为您喜欢的任何值,并且不必像在 Pandas 中使用fillna()函数那样等同于np.nan。此外,简单地通过改变strategy参数,插补策略可以在以下四个选项之一之间轻松改变:
"mean"—用平均值替换缺失值"median"—用中间值替换缺失值"most_frequent"—用最常见的值替换缺失值"constant"-用fill_value参数中指定的任何值替换缺失值。在您希望用字符串“missing”而不是实际值来替换缺失值的情况下,这可能很有用。

图片作者。上面代码的输出。
迭代插补
仅在处理多变量数据时有用,scikit-learn ( 视图文档)中的IterativeImputer利用其他功能中可用的数据来估计要估算的缺失值。它通过一个…
…迭代循环方式:在每一步,一个特性列被指定为输出
y,其他特性列被视为输入X。已知的y在(X, y)上安装一个回归器。然后,使用回归变量来预测y的缺失值。以迭代的方式对每个特征进行此操作,然后对max_iter插补轮次重复此操作。返回最后一轮插补的结果。[ 来源
如果这看起来仍然有点抽象,希望下面的例子将有助于澄清事情。由于IterativeImputer仍处于试验阶段,导入enable_iterative_imputer是使用的一个需求。

图片作者。上面代码的输出。
该虚拟数据的底层模式旨在使列B成为列A的平方。虽然并不完美,但IterativeImputer确实填充了一个有点接近“真实”值 16.0 的值。将结果与使用均值插补策略(12.7)或中值插补策略(9.0)获得的结果进行比较,可以清楚地看出在这种情况下使用迭代插补策略的好处。
使用真实数据的比较
我最近有机会用真实世界的数据集测试了IterativeImputer,同时创建了一个澳大利亚第二天降雨预测模型。虽然我不会在这里详细介绍整个项目,但它确实是一个很好的例子,说明迭代插补如何比一些更简单的策略更有益。使用来自源数据集的weatherAUS.csv文件,使用以下三种不同策略估算连续特征:
- 平均插补
- 中位数插补
- 迭代插补
我选择比较Pressure9am和Pressure3pm特性,因为它们彼此直接相关,并呈现出线性关系,这对于评估非常有用。下面的代码用三种不同的策略估算缺失的数据,沿着回归线绘制数据,然后显示均方根误差 (RMSE,越低越好)。

图片作者。上面代码的输出。
即使不考虑 RMSE 值,迭代插补策略也应该能突出显示出更好的拟合值。由于均值和中值策略用相同的值填充所有缺失值,因此在数据中心附近会形成一个十字形形状,这不一定符合总体趋势。然而,迭代插补策略能够利用包含在其他特征中的信息来近似该值,从而产生更清晰的图,更准确地符合趋势。
你可能认为 RMSE 从 1.874 提高到 1.871 没什么大不了的——你是对的。虽然它本身并不引人注目,但有几件事要记住:
- 在
Pressure9am和Pressure3pm特征中丢失的数据量只有大约 10%。因此,与均值和中值策略相比,RMSE 值只能提高这么多。 - 这种比较仅针对两个要素,而完整的数据集包含更多要素。当在建模过程中使用所有数据时,这些特征中的每一个的小的改进可以导致整体的大的改进。
结论
在处理单变量数据时,使用平均值或中位数等简单的插补策略可能是有效的。处理多元数据时,迭代插补等更先进的插补方法可以产生更好的结果。Scikit-learn 的IterativeImputer提供了一种快速简单的方法来实现这样的策略。
Github:https://github.com/tjkyner
中:https://tjkyner.medium.com/
LinkedIn:https://www.linkedin.com/in/tjkyner/
Julia 中人工神经网络的迭代剪枝方法

摩根·豪斯尔在 Unsplash 上的照片
思想与理论
基于剪枝的压缩技术综述
近年来,深度学习模型在实时嵌入式应用中变得更加流行。特别是,这些模型已经成为从自然语言处理到计算机视觉等几个领域的基础。计算能力的增加有利于面对实际挑战,这些挑战已经通过采用广泛的神经网络得到解决;随着网络越来越深入,模型大小也增加,引入了对指定输出没有贡献的冗余参数。最近,研究人员专注于如何通过修剪多余的参数来减少存储和计算能力而不损害性能的不同方法。
本文的参考实现语言是 Julia [1],这是一种最近开发的面向科学计算的编程语言。特别是,我们将扩展 Flux 库[2,3],通常用于机器学习。
为什么修剪?
自 80 年代末开始使用的剪枝算法【4,5】包括从网络中删除单个权重或整个神经元,以减少冗余,同时不牺牲准确性。为了在通过示例训练的系统中获得良好的泛化能力,应该使用适合数据的最小系统[6]。经验证据表明,训练一个大型网络,然后压缩它,比从头开始训练一个较小的网络更容易[7]。

(作者图片)
这种方法的问题在于,通过去除太多的边缘,可能会丢失所学的内容。主要的困难在于找到最佳的模型尺寸。因此,我们可以将剪枝视为一个神经网络架构搜索[8]问题,目标是为所考虑的任务找到最佳网络。修剪方法的各种实现主要在四个方面不同:
- 结构:结构化剪枝包括消除网络中的整个神经元,并允许使用更小的矩阵来加速计算。另一方面,非结构化修剪更灵活,因为它允许消除单个连接,但不能有效地加速神经网络的计算。

(图片作者)
- 显著性:可以被视为与每个边缘相关联的重要性,根据所采用的策略来确定是否应该消除它
- 调度:决定每一步要淘汰的网络比例。例如,一次性修剪包括在一个步骤中消除网络的期望百分比。其他可能的策略是在每一步消除网络的恒定部分,或者采用更复杂的调度功能。
- 微调:在修剪阶段之后,准确度通常会下降,因此重新训练网络以稳定它可能是有用的。有不同的可能方法来处理微调。在边缘消除之后,可以使用修剪步骤之前具有的相同权重(没有被消除)来训练,或者使用在某个先前阶段具有的边缘的权重,或者从开始重新初始化剩余的边缘
数量修剪
这是最简单的剪枝算法。在共同训练阶段之后,去除具有较低显著性的连接。链接的显著性仅由其权重的绝对值给出。幅度修剪有两种主要的变体。一旦所需百分比的连接被固定,逐层幅度修剪将从每层移除该百分比的边,而全局幅度修剪将从整个网络移除一个百分比,而不区分层。更复杂的分层剪枝技术引入了灵敏度分析阶段,允许为每层指定不同的稀疏度阈值,以便在不太敏感的层中消除更多的边(即那些权重的消除对网络结果影响较小的边)。首先,总是需要一个训练阶段,以便了解哪些是网络最重要的连接,那些具有最高绝对值的连接。在消除显著性较低的连接后,网络性能将会下降。

(图片作者)
由于这个原因,从最后获得的权重开始重新训练网络而不从头重新初始化参数是必要的。修剪参数的百分比越高,精度下降越多,这就是为什么修剪通常迭代地进行,一次消除一小部分网络。这意味着需要一个时间表,在这个时间表中,我们指定要删除的网络部分,分多少步,每一步要删除多少个连接。
镗孔预处理步骤
**using** Flux: onehotbatch , onecold
**using** MLDatasetstrain_x , train_y = CIFAR10.traindata()
test_x , test_y = CIFAR10.testdata()X = Flux.flatten(train_x)
Y = onehotbatch(train_y , 0:9)test_X = Flux.flatten(test_x)
test_Y = onehotbatch(test_y , 0:9)data = Flux.Data.DataLoader ((X,Y),batchsize = 128, shuffle=true)
test_data = Flux.Data.DataLoader ((test_X ,test_Y), batchsize = 128)
快速实现
修剪通常通过将权重设置为零并在随后的训练中冻结它们来实现。我的实现使用了一种基于元素的操作,将权重矩阵乘以二进制剪枝掩码。

(图片作者)
第一个矩阵代表神经网络层的权重,而第二个矩阵是掩码,它将某个阈值下的所有值设置为零,在本例中为 0.5
在 Flux 中,简单的致密层由两个基本部分定义。首先,一个 struct 包含三个字段:权重、偏置和激活函数。
**struct** Dense{F, M <: AbstractMatrix , B}
weight :: M
bias::B
sigma::F
end
第二个关键部分是表示向前一步计算的函数,如下所示:
**function** (a::Dense)(x:: AbstractVecOrMat)
W, b, sigma = a.weight , a.bias , a.sigma
**return** sigma.(W*x .+ b)
end
我开发的实现扩展了 Flux 提供的实现,如前所述,添加了带有矩阵掩码的 Hadamard 乘积。然后,层 PrunableDense 被定义为一种结构,该结构通过添加用于位矩阵的字段来重用密集层:
**struct** PrunableDense
dense :: Dense
mask:: BitMatrix
end
其次,我们重新定义了前向阶跃函数,以包括掩模矩阵的哈达玛乘积:
**function** (a:: PrunableDense)(x:: AbstractVecOrMat)
W, b,sigma , M = a.dense.W, a.dense.b, a.dense.sigma , a.mask
**return** sigma .((W.*M)*x .+ b)
end
现在你可以用你想要的方式使用这些可修剪的密集层,然后减少你的神经网络的大小!
文献学
[1]杰夫·贝赞森、艾伦·埃德尔曼、斯特凡·卡尔平斯基和维尔拉·B·沙阿。朱莉娅:一种新的数值计算方法。暹罗评论,59(1):65–98,2017。
[2]迈克尔·英尼斯、埃利奥特·萨巴、基诺·菲舍尔、达里亚·甘地、马尔科·康采托鲁迪洛索、尼图·玛利亚·乔伊、泰詹·卡尔马里、阿维克·帕尔和维尔拉·沙阿。带有通量的时尚造型。更正,abs/1811.01457,2018。
[3]迈克·英尼斯。通量:优雅的机器学习与朱莉娅。开源软件杂志,2018。
[4]史蒂文·雅诺夫斯基。《神经网络中的剪枝与剪枝》,物理评论 A,39:6600–6603,1989 年 6 月
[5]戴维斯·布拉洛克、何塞·哈维尔·冈萨雷斯·奥尔蒂斯、乔纳森·弗兰克尔和约翰·古塔格。神经网络剪枝是什么状态?arXiv 预印本:2003.03033,2020。
6 Anselm Blumer、Andrzej Ehrenfeucht、David Haussler 和 Manfred K Warmuth。奥卡姆剃刀。信息处理通讯,24(6):377–380,1987。
7 拉塞尔·里德。剪枝算法-综述。IEEE 神经网络汇刊,4(5):740–747,1993。
[8],孙明杰,周廷辉,,和特雷弗·达雷尔。重新思考网络修剪的价值,2019。
该是我们解散数据科学的时候了
意见
为什么我们必须分散数据科学,以及它看起来会是什么样子

马诺洛·克雷蒂安在 Unsplash 上拍摄的照片
介绍
企业主不太可能会读到这篇文章,并开始改变他们对我们如何定义数据科学的看法。不是因为我怀疑自己的影响力或其他什么,而是因为我意识到我的大多数读者才刚刚开始他们的数据科学之旅,我真的不喜欢“有抱负”这个词,但我想告诉大家的是…
不要试图精通数据科学中的每一件事,选择一个(最多两个)你想专攻的领域,并真正精通它!
概观
老实说...进入数据科学领域非常困难,原因有很多。然而,我最近意识到,大部分困难在于“数据科学家”一词包含如此多不同的技术素质,以至于一个人几乎不可能满足所有这些标准并在每个领域保持最新,这没关系!
我一直在听首席数据科学家兼领英 2019 年顶级声音 Vin Vashishta 讲话,他认为为了更好地定义角色,从业者必须更加专业化。实际上,我喜欢这个想法,因为它要求从业者投入更多的时间来战略性地规划他们想如何将自己推向市场,以及他们认为他们如何能够增加价值。
作为数据科学家,我们做的很多工作都需要我们花时间深入一个问题,这对一月份从事对话式人工智能项目、下个月从事计算机视觉任务的人来说可能很难。因此,决定专业化不仅对公司有利,而且对你的数据科学之旅也有好处,因为你将有更多时间专注于你所关注领域的特定任务,而且你可以深入研究。
“数据科学家是一个类别,而不是一个职称。藏在风衣下的实际上是 8+份不同的工作”——Vin Vashishta
实际上,目标是让你从人群中脱颖而出,这通常是通过强调你个人的特殊技能来实现的。你凭什么,你?我们都有一些区别于其他人的东西,而一个有趣的候选人是一个可以同时强调这一点和他们的数据技能的人。无论是你处理 NLP 任务、计算机视觉任务的能力,还是你在欺诈检测问题上的大师,我们都有一些我们可以做得很好的事情和令人信服的背景故事来支持它。
一家正在招聘机器学习工程师的公司通常会有一个非常具体的问题,比如部署一个模型并通过 REST API 提供服务。由于一些最受欢迎的数据科学课程(以及其他原因),大多数数据科学家都会掌握一些通用的数据科学技能,因此我们很容易成为万金油。老实说,我在这里有罪。
这样做的结果通常是一份无人问津的简历...例如,当我们在 LinkedIn 或其他网站上点击“ easy apply ”时。这很疯狂,因为我真的得到了背后的想法——“我知道他们想要一个 ML 工程师,但也许他们也希望我能建立一个仪表板和一大堆其他东西,对吗?”。嗯……不完全是。
我不是说你不可能得到这份工作,但从招聘经理的角度来看,他们希望对你部署机器学习模型并通过 REST API 提供服务的能力有信心,因为这是他们眼前的问题,所以如果你简单地强调这一技能会更好。
这里有一篇文章,我相信它更深入地探讨了专业化的概念:
https://www.simplilearn.com/why-every-data-scientist-needs-to-specialize-article
分手
会有物理上的分裂吗,就像一个董事会聚在一起,以标准石油的方式物理上拆分数据科学?我高度怀疑。然而,我相信人力资源和招聘人员会对工作规范进行压制,以提出更具体的要求和头衔。这些工作及其角色的简要描述可能如下所示:
数据工程师/架构师
根据 Glassdoor 的说法,数据工程师的任务是将数据转换为易于分析的格式。他们通过开发、维护和测试用于数据生成的基础设施来做到这一点。数据工程师与数据科学家密切合作,主要负责为数据科学家设计解决方案,使他们能够开展工作。[ 来源 : 玻璃门
机器学习工程师/架构师
在一篇题为机器学习工程师 vs 数据科学家的文章中,作者对机器学习工程师/架构师的角色描述如下:
机器学习工程师位于软件工程和数据科学的交叉点。他们利用大数据工具和编程框架来确保从数据管道收集的原始数据被重新定义为数据科学模型,可以根据需要进行扩展。
机器学习工程师将数据输入到数据科学家定义的模型中。他们还负责采用理论数据科学模型,并帮助将它们扩展到能够处理万亿级实时数据的生产级模型。【来源 : 机器学习工程师 vs 数据科学家
NLP 工程师
作为一名 NLP 工程师,您将负责处理和分析日常自然语言与计算机从非结构化自然语言数据中获取可操作见解的能力之间的交集。
CV 工程师
雇佣的计算机视觉工程师描述如下:
作为一名计算机视觉工程师,你能够自动化人类视觉系统所能做的各种功能。您可以在协作环境中同时处理多项任务,高效地完成关键项目。我们的计算机视觉工程师能够自我激励,并表现出领导素质。
机器学习研究员
机器学习研究人员比机器学习工程师拥有更少的软件工程技能,尽管他们仍然关注机器学习中特定利基的进步。两者之间的另一个显著区别是,ML 研究人员通常接受过博士水平的教育,因此这意味着他们有非常强的学术和研究背景——然而,ML 工程师也可以有博士学位,但它不会像研究员那样排序。
数据分析师
TargetJobs 将数据分析师的角色描述为:
使用数据分析工具审查信息的人。他们从原始数据中提取的有意义的结果,通过识别各种事实和趋势,帮助他们的雇主或客户做出重要决策。[ 来源 : 目标作业
在这个时代,数据分析师通常比我们所说的数据科学家使用更少的编程技能。通常还有一种误解,认为数据科学家比数据分析师更好——两者都不比对方更好,他们做不同的事情。
商业分析师
业务分析包括研究和发现业务需求,以及对业务中的问题提出解决方案。从本质上来说,业务分析师将在业务想法和业务能力之间架起一座桥梁。
最后的想法
在我收到多面手群体的谩骂之前,我想澄清一点,我并不是说成为多面手是无价的。老实说,您可以在数据科学生命周期中执行多种功能,这很好。同样,一个全栈开发人员可以执行前端和后端任务,我相信这很酷,但是,如果这阻碍了你深入研究特定类型问题的能力,那么最好专注于感兴趣的领域。
感谢您的阅读!在 LinkedIn 和 Twitter 上与我联系,了解我关于数据科学、人工智能和自由职业的最新帖子。
相关文章
这只是语义|数据如何自己说话(不)
一致的见解需要一致的数据
过去三个月你有多少活跃客户?在这篇文章的结尾,如果你回答“看情况”,我已经达到了我的目标。没有上下文,这个问题应该是不可能回答的。

戴维·特拉维斯在 Unsplash 上拍摄的照片
是的,我是那种“视情况而定”的人。当你问他们一个问题时,他们会用另一个问题来回答。正如喜剧小品《专家》(看着很痛苦,因为这确实很真实)中所描述的那样,专家知道这个问题是不合理的,并尽力解释为什么他需要更多的上下文,以便“用透明墨水画出 7 条垂直的红线”。
如果你想回答我关于活动客户端数量的第一个问题,你可以很快给出答案。然而,这将是一个错误的或不完整的答案,因为你没有问我对“客户”、“活跃”的定义是什么,或者哪些日期对所述三个月的衡量是重要的。
在这种特殊情况下,如果某人的每月订购借记订单在您所想的 3 个月内有效(他选择了 30 日)会怎样?但因为是公共假日,它实际上只在 1 号爆炸,不在你想查看的三个月期限内。如果第一天他的账户里没有足够的钱,并且被拒绝了怎么办?他活跃吗?是三个月以内吗?他现在也取消了订阅,但只在下个月生效…
为了证明这一点,我把这个例子弄得过于复杂了……上下文很重要。仅仅通过查看原始的不一致的数据,是不可能对算法有意义的。关于这些学究式的问题中哪一个是不必要的,需要一些解释。
业务和技术有效性
当我 12 年前开始我的职业生涯时,我的老板教给我的第一课是技术生效日期和业务生效日期之间的区别。从那时起,我一直认为这种区别是常识,直到在我的日常对话中出现了某种趋势。起初我以为只是我,然后随着越来越多的会议突然出现,有效日期完全被混淆,我开始接受这样的想法,也许不是我,也许是你。
我不得不多次重复这个对话……多年来在不同的背景下,有时是对同一个人。就在那时,我意识到常识并不那么普遍(借用伏尔泰的一句话)
我觉得说出来很傻,但我会说的。
技术生效日期不同于业务生效日期。数据可以是技术上有效的,但不是业务上有效的。数据可以在业务有效期内,但在技术上无效。不同的来源和不同的系统处理技术有效性和业务有效性的方式完全不同。
在我职业生涯的开始,我在 SAP 中开发了一个模块,这个模块处理得非常好,这是我还没有在其他地方看到过的。这是一个巨大的领域开销,但毫无疑问,数据是什么。只有当我开始看到其他系统中缺少这一点时,我才明白为什么它经常如此令人困惑。简而言之,每个对象有七个元数据字段来描述这一点:技术来源、技术目的、业务来源、业务目的、版本、无效对象标志和无效版本标志。有了这七个字段,你就知道发生了什么。
我就用一个例子来说明。销售代理合同上有一条佣金规则,规定对产品的销售收取 5%的佣金。该规则是在 7 月 6 日(技术有效期)技术上创建的(用户在前端键入)。然而,该规则本应在 7 月 1 日至 31 日生效(商业有效期)。后来它被删除了(技术上在 15 日被删除),并建立了一个新的规则,规定 10%的佣金具有相同的有效性。上面列出的七个元数据字段能够很容易地描述这种情况。

作者图表
我不打算讨论这七个字段是否在每种情况下都值得,但是有这么多的数据信息消除了任何可能的混乱。它让我明白了真正理解每个数据点背后的背景需要什么。
如果你能接受源代码系统会以不同的方式处理这一事实,这对你(从精神健康的角度)会有好处。即使在一个源系统内部,它也可以被不同地处理。
我还看到源系统在开始时以“保持简单愚蠢”的方式开始,然后系统地向表中添加更多的技术日期。你逐渐看到这个易读的 KISS 模型变形为一个不连贯的 WTF 模型。一些源系统有一个仅包含当前记录的活动表,并将它们的历史表保存在单独的表中。其他人有混合。
所以不要试图修复上游系统,你会失败的。我们应该接受不同的来源会以不同的方式呈现这一点,照原样阅读数据,或者试图照原样连接数据,无论如何都不是一件简单的任务。
小麦
所报告的数据的粒度指的是所存储的细节的级别,以及在数据集中暴露了哪些相关联的对象。以保险为例:支付的保费值是存储在客户和利益层,还是仅汇总到客户和月度视图中?(也就是说,您是查看所有产品的累计保费,还是单独查看您的人寿保险和您的猫的宠物保险)
在谈论谷物时,一些常见的混淆是围绕产品、子产品以及它们之间的分组。产品的标签和等级结构,特别是在保险和投资行业,会使这变得复杂。然而,随着公司开始收集或收购其他公司,这些公司的产品具有不同的标签和结构,数据集必须合并或存放在一起,情况变得更加复杂。
语义学
你必须预先定义某些术语的含义。这听起来是显而易见的常识,对吗?还记得我之前说的常识吗?这一点往往没有做到(我自己也不觉得羞耻)。我想是因为人们不想为了确立这个意义而问太多的问题,让自己觉得或者显得很愚蠢。
一段时间前,我是一个团队的成员,负责一个俄语项目,我没有提前询问地域、地区、区域和分支之间的不同含义。(也许是因为它的所有俄语版本听起来都类似于以英语为母语的人。(Прошу прощения, мои русские коллеги!).很长一段时间,我都认为它们是一回事,只是同义词而已。事实上,它不是。事实证明,在许多业务流程中,理解这种差异非常重要。
所以,简单的规则…不要觉得自己很蠢。经常并尽早询问某些商业术语的含义,并有一个核心术语表。人们会克服最初认为你的问题愚蠢的想法(可能在 10 秒钟内),或者他们会觉得不那么愚蠢,因为他们也不知道。
真的,是双赢。我向你保证,房间里还有另一个“愚蠢”的人,非常感激你问了他没有勇气提出的问题。(当然,不要傻傻地在俄罗斯问这个问题,因为这可能是你问的最后一个问题)
下面是我看到的其他几组术语的列表,它们之间的区别经常不清楚:
- 政策、计划、协议、利益、产品
- 当事人、客户、顾客、销售线索、潜在客户
- 中介、经纪人、顾问、销售代理
- 证券、工具、投资工具、投资组合
这些都是你 认为 的例子,你知道它的意思,但我保证另一个组织或业务单位在完全不同的上下文中使用相同的术语。甚至你自己团队里的人也会对它的含义有不同的看法。
同样,和有效期一样,不同的来源会有不同的标签。不同的源也会以不同的方式处理层次结构或分组。因此,确定需要建模的业务实体并确保目标消费者同意它们的意思是很关键的。
这就是我大力支持能够在敏捷和快速失败的环境中工作的原因。问题是,即使我说你应该得到企业的同意,他们也不会知道,直到你向他们展示错误的东西。
因此,或许我可以稍微改变一下我的建议:让他们明白你的想法,让他们告诉你这是多么错误(他们会的)。
我一开始说背景很重要。原始数据需要在对消费者或消费算法有意义的上下文中呈现。算法获得的训练数据将假设关联是正确的。有人仍然需要决定如何连接来自不同来源的原始数据,以便它们以相同的语义意义注册,具有相同的粒度并与相同的时间有效性相关联。
对于受过训练的人来说,这听起来很像是我在提倡历史上被称为数据仓库的东西。在数据湖时代,它最近经历了许多标签,“策划”或“消费者”区,以及数据湖屋的出现。我现在不打算详细说明这一点,因为我正试图接触受过训练和未经训练的人,要全面地解决这个问题需要更多的背景知识。
组织正在收集越来越多的数据,要么通过收购其他公司(因此无法控制上游来源如何构建数据),要么探索不同的方法从客户那里收集数据。这不可避免地意味着,BI 环境经常会得到一张医院通行证,并被指示去理解这种疯狂——去“基于所有这些丰富的信息创造洞察力”。
一些应用可能不像其他应用那样依赖于时间,或者说,不正确的时间完整性的后果并不严重。然而,如果你在精算应用中弄错了粒度和关联,你可能会产生一个漂亮的预测模型,预测下一个索赔将来自哪里。然而,它将成为算法的装饰性植物:漂亮,但没什么用。
我们应该小心,不要迷失在我们试图创造的所有这些见解的宣传中,并记住只有一致的数据才能提供一致的见解。
那么,让我们再试一次:在过去的三个月里,你有多少活跃的客户?
现在是自然语言处理的黄金时代,为什么聊天机器人不能解决更多的问题?
行业笔记
自然语言处理(NLP)正在彻底改变我们的生活方式以及我们与机器和人之间的交互方式。但是聊天机器人仍然存在不足。原因如下。

图片来自 Pixabay
人工智能和机器学习(ML)领域的进步,特别是自然语言处理(NLP),正在彻底改变我们与机器和彼此互动的方式。亚马逊的 Alexa,苹果的 Siri,虚拟助手和聊天机器人改变了我们请求和接收信息的方式。NLP 管道获取非结构化文本数据,并将其处理为结构化格式,以提取信息、分类并获得洞察力。它意味着计算机可以将人类语言转换成一种可以为 AI 系统精简和处理的形式。最终,它们让人类和机器之间的交流变得更加容易。
工作原理
计算机擅长各种自然语言任务,如文本分类、语音到文本、语法纠正和大规模分析。ML 算法已经被用来帮助在特定问题上取得重大进展,例如面向任务的聊天机器人的翻译、文本摘要、问答系统和意图检测和槽填充。
例如,你的文字处理器中内置的语法插件,以及你在开车时用来发送文本的语音笔记应用程序,都要归功于机器学习和自然语言处理。
然而,尽管这些机器人看起来很聪明,但人类现在更聪明。归根结底,人类的语言是微妙的,而且常常是模棱两可的。这对 ML 系统提出了严峻的挑战。在大规模数据集上进行训练——例如:维基百科的每一篇文章——并创建大型语言模型不会导致对语言的理解。
事实上,这种方法可以延续人类的错误和误解。
尽管使用广泛,但仍然不清楚依赖语言模型的应用程序,如生殖聊天机器人,是否可以在没有人类监督的情况下安全有效地释放到野外。还记得 2014 年的电影《T2》前玛奇纳吗?它可能不是那么极端,但这些系统的后果和考虑应该认真对待。
自然语言处理的最新进展导致了创新的爆发
就在过去的十年里,技术发生了巨大的变化,并影响着客户支持生态系统。随之而来的是一个有趣的机会,可以在客户体验(CX)过程中增强和帮助人们——使用最新模型中的见解来帮助指导客户对话。
自然语言处理突破和语言模型爆炸的主要驱动力包括:
- 新技术和算法的开发(单词嵌入和转换器)。
- 对高端硬件(GPU 和TPU)的改进和更多访问。
- 开源工具和库——如 SpaCy 、humping Face和Rasa——已经使自然语言处理民主化。
变形金刚,或者说基于注意力的模型,已经在自然语言基准上产生了更高性能的模型,并迅速淹没了这个领域。利用语言模型的文本分类器、摘要器和信息提取器已经超越了先前的最先进的结果。高端硬件的更高可用性也允许更快的训练和迭代。开源库及其支持生态系统的发展使从业者能够接触到前沿技术,并允许他们快速创建基于该技术的系统。
这些进步导致了语言模型的雪崩,这些语言模型有能力预测序列中的单词。想想谷歌的自动填充。可以预测序列中下一个单词的模型可以由机器学习实践者进行微调,以执行一系列其他任务。
OpenAI 的 GPT-3——是一种可以自动编写文本的语言模型——在过去的一年里受到了大量的炒作。北京人工智能研究院的无刀 2.0 (一种多模态人工智能系统)和谷歌的开关变压器都被认为是更强大的模型,包括超过 1.6 万亿个参数,使 GPT-3 微不足道的 1750 亿个参数相形见绌。新的、更大的语言模型以惊人的速度发布。说到人工智能系统,市场上并不缺乏。
那么为什么聊天机器人没有更好呢?
虽然这些语言模型和利用它们的系统变得更加复杂和强大,但问题仍然存在:为什么这些 技术仍然如此令人沮丧并且经常出错 ?
除了令人沮丧的与 Alexa 的交互,一些人工智能系统的错误可能会产生严重的后果。如图 1 所示,在大规模数据集上训练的大型语言模型可能会延续人类的错误和误解:

图 1: TruthfulQA 来自 GPT-3–175 b 的带有默认提示的问题和答案。例子说明了 GPT-3 的错误答案,模仿人类的谎言和误解。更多信息,请查看完整的研究: TruthfulQA:测量模型如何模仿人类的谎言
答案比你想象的简单:自然语言处理不是自然语言理解。无论计算的复杂性、能源和时间如何致力于创建更大的语言模型,这种方法都不会导致获得意义、把握上下文或理解的能力。要深入了解这一点的更多技术解释,请参考机器学习不会解决自然语言理解。这是对 NLP 缺点的一个大开眼界的观察。
这对公司、客户服务和聊天机器人意味着什么?
那么这对公司,尤其是那些严重依赖聊天机器人的公司有什么影响呢?很复杂。
自然语言处理的进步导致人们高度期待聊天机器人能够帮助转移和处理过多的客户问题。公司加快了其数字业务的发展,将聊天机器人纳入其客户支持堆栈。
对一些人来说,是的,聊天机器人可以成为他们 CX 解决方案的一个可行部分。然而,对于大多数人来说,聊天机器人并不是客户服务解决方案的一站式商店。此外,它们甚至会制造自己的盲点和新问题。虽然聊天机器人现在无处不在,但根据技术公司 Tidio 的研究,大约一半的用户仍然喜欢与真人交流,而不是聊天机器人。
在一个日益数字化、自动化和虚拟化的世界中,当客户遇到问题时,他们只是希望由真人来迅速、恰当地解决问题。聊天机器人供应商可以希望只解决大约 50%的顾客询问。虽然聊天机器人有可能减少简单的问题,但仍然有一部分对话需要人工代理的帮助。

作者图片
无法使用聊天机器人解决问题的沮丧客户可能会觉得公司不想处理他们的问题。他们可能会因为自己的经历而感到不满足,也不会被视为客户。对于那些真正致力于自助服务门户并浏览常见问题的人来说,当他们联系到人时,客户通常会更加沮丧。更不用说收集到的信息之间的差距了——例如,一个聊天机器人收集客户信息,然后一个 CX 代表请求相同的信息。在这些时候,代理对这些潜在的有争议的谈话准备得越充分(他们掌握的信息越多),对客户和代理都越有利。
尽管一些公司押注于完全数字化和自动化的解决方案,但聊天机器人还没有出现在开放域聊天中。如果不检查生成模型,则会导致有害问题。
坦率地说,聊天机器人无法处理人类查询的多样性和细微差别。在最好的情况下,聊天机器人有能力将未解决的、通常是最复杂的问题交给人工代理。但这可能会引发问题,给 CX 特工带来一连串需要处理的问题,增加他们的工作负担。
那么,我们是否为人类配备了处理客户问题的最佳工具和支持?
好消息是 NLP 的进步不必完全自动化和孤立使用。在洛里斯,我们相信来自我们最新模型的洞察力可以用来帮助引导对话和增强人类交流。理解人类和机器如何合作创造最佳体验将会带来有意义的进步。从我们的模型中获得的见解可以用来帮助指导对话,并帮助而不是取代人类交流。
我们的软件利用这些新技术,用于更好地装备代理,以处理最困难的问题——机器人无法单独解决的问题。我们努力通过向用户学习来不断改进我们的系统,以开发更好的技术。
通过实时预测客户满意度和意向,我们使代理能够有效、恰当地处理客户问题。我们的软件可以实时指导代理人做出回应,并简化死记硬背的任务,因此他们有更多的空间来解决最困难的问题,并专注于为客户提供价值。在客户支持职位的人员流动率达到历史最高水平的时候,这一点尤其令人心酸。
Paul R. Daugherty 在他的书《人类+机器:人工智能时代的重新想象》中解释道,
“简单的事实是,当人类和机器作为盟友一起工作时,公司可以实现业绩的最大提升……以便利用彼此的互补优势。”

图片来自 Pixabay
虽然语言建模、机器学习和人工智能已经取得了很大的进步,但在处理人类问题的复杂性方面,这些技术仍处于起步阶段。正因为如此,聊天机器人不能放任自流,仍然需要人类的支持。技术驱动的人类可以也应该帮助驱动和引导对话系统,帮助他们随着时间的推移而学习和改进。意识到并实现人类和技术之间平衡的公司将主导客户支持,推动未来更好的对话和体验。
有兴趣了解更多信息吗?
- 联系 LinkedIn 上的我
https://www.linkedin.com/in/sethplevine/
- 我们在招人!查看我们的开放数据科技角色
资源、参考资料和进一步阅读
- 博玛萨尼,r .等人,论基金会模式的机遇与风险。 arXiv 预印本 2021。
- 布伊格,m .,认知虚拟代理人如何革新客户支持行业。2021 年 3 月 4 日。福布斯。
- Daugherty,p .,人类+机器:重新想象人工智能时代的工作。2018 年 3 月 20 日。哈佛商业评论出版社。
- Fedus,w .,开关变压器:通过简单有效的稀疏性扩展到万亿参数模型。2021 年 1 月 11 日。arXiv 预印本。
- 人类与数字客户服务:如何找到正确的平衡?。2021 年 7 月 12 日。Loris.ai 博客。
- 为什么现在是加速数字化的时候了。2020 年 9 月 11 日。高德纳。
- 拥抱脸。https://huggingface.co/
- 为什么没人愿意在客户服务部工作。2021 年 11 月 10 日。LinkedIn Pulse。
- 林等, TruthfulQA:测量模型如何模仿人类的错误。2021 年 9 月 8 日。arXiv 预印本。
- 马克西姆。机器学习的变形金刚和序列对序列学习介绍。2019 年 1 月 4 日。中等。
- 拉莎。https://rasa.com/
- 罗梅洛,a ., GPT-3 吓到你了?遇见武道 2.0:1.75 万亿参数的怪物。2021 年 6 月 5 日。迈向数据科学,中等。
- 跟踪自然语言处理的进展。http://nlpprogress.com/。
- 萨缪尔·s .艾的伊斯兰恐惧症问题。2021 年 9 月 18 日。Vox。
- 2021 年你需要知道的 11 个聊天机器人统计数据和趋势。2021 年 12 月 6 日。蒂迪奥。
- 斯帕西。https://spacy.io/
- Sullivan d .,谷歌自动完成预测是如何产生的。2020 年 10 月 8 日。谷歌博客。
- Tavva,r .,自然语言处理管道,解释。 KDNuggets。
- 你所需要的只是关注。第 31 届神经信息处理系统会议(NIPS 2017),美国加州长滩。
- Walid S .,机器学习不会解决自然语言理解。2021 年 8 月 7 日。渐变。
- Wiggers,k .,大型语言模型更可能出现错误。创业节拍。2021 年 9 月 20 日。
- OpenAI 通过其 API 使 GPT-3 普遍可用。2021 年 11 月 18 日。
现代数据文化栈的时代到了
行业笔记
建立一个理想的数据团队不仅仅是使用正确的数据堆栈。

几天前,我在 dbt Coalesce 做了一个关于我建立数据梦之队的经历的演讲,在那里我引入了一个术语,我称之为“现代数据文化栈”。这是我多年来一直在思考的话题,但即便如此,我还是对社区的反应感到惊讶。

来自我演讲期间的 dbt Slack 讨论。(图片由 Atlan 提供;编辑删除全名和照片。)
在过去的两年里,关于现代数据堆栈——改变了我们工作方式的工具——有太多的噪音。就像应该有的那样。坦率地说,在现代数据堆栈出现之前,我们处理数据的方式已经支离破碎。数据世界的第一个“增量”自然需要来自让数据团队变得更有效的工具。
在过去的四年中,现代数据栈取得了巨大的进步,由于采用了像雪花和 dbt 这样的工具,它已经成为主流。由于新工具的出现,现代数据堆栈中早在去年就存在的缺口(在元数据管理、数据治理和可观察性等领域)正在迅速得到填补。随着这一领域如此多的创新,我确信在未来几年内,所有数据团队将最终拥有一个接近“完美”的数据堆栈。
这让我相信,随着我们进入 2022 年,对话需要从对更好工具的需求转移到下一个“delta ”,最终帮助我们创建梦想数据团队——现代数据文化堆栈。这些是最佳实践、价值观和文化习俗,将帮助我们这些不同的数据人(或 dbt 创造的“紫色人”)走到一起,有效地合作。
构建理想数据团队的挑战,或者为什么每个数据团队都需要文化堆栈

喜欢这个!(来自我演讲时 dbt 的 Slack 社区。图片由 Atlan 提供;编辑以删除全名。)
多年来,我一直在为建设优秀数据团队的承诺和挑战而奋斗。数据驱动的团队有潜力在未来几年推动最伟大的创新,如消除 COVID,使自动驾驶汽车成为现实,或将人送上火星。但是我们都知道作为一个数据团队一起工作的日常困难…
- 当一个重要的仪表板坏了,一大早就疯狂地给工程师打电话
- “看在上帝的份上,给我数据吧”的请求在几周的等待后
- 老板发来的令人揪心的“这个数据看起来不对劲…”电子邮件
- “难道‘column _ xxy 81’的意思不明显吗?”或者“为什么会有‘file _ 2 _ final _ final . CSV’和‘file _ 3 _ final . CSV’?!"关于时差的问题
之所以如此困难,是因为…嗯,数据团队是有史以来最多样化的团队之一。他们由分析师、工程师、分析工程师、科学家、业务用户、产品经理等等组成——所有人都有自己的工具偏好、技能和限制。结果是协作开销和数据混乱。

我们数据团队的成员及其个人工具偏好。(图片来自 Atlan。)
亚特兰蒂斯诞生于这些挑战之中。2016 年,我们启动了“流水线项目”,开始测试新的方法,让我们的团队更加敏捷,减少开销,提高生产力,建立弹性。两年后,我们的敏捷度提高了六倍。我将这 6 倍的敏捷性归因于两个关键驱动因素——我们的技术栈(或现代数据栈),以及我们的文化栈。
建立理想的数据团队不仅仅是使用正确的数据堆栈。这是关于建立一个强大的文化堆栈。
我将详细介绍我们是如何创建这种文化体系的,以及我们在反复试验后发现的最佳实践。这并不意味着您应该采用这些确切的做法!相反,它们是帮助你自己的团队思考什么适合你的一个起点。
1.为你的文化堆栈打下基础:团队价值观和章程
我们首先召集我们的整个数据团队进行了一次模拟谷歌设计冲刺的练习。
我们都充满了挫败感,但是几个小时的抱怨并不能帮助我们前进(尽管感觉很棒!).因此,我们使用 HMWs 或“我们如何能够”问题,将我们的痛点重新定义为机会。
这些成为了我们数据团队的梦想清单——所有我们希望在未来做得更好的事情。

我们如何提问的例子。 ( 图片由 Atlan 提供。)
然后,我们将这些目标转化为团队章程,或我们希望我们的数据团队遵循的关键价值观。

我们多年前的团队章程。(图片由 Atlan 提供。)
这个章程不一定要完美。(显然,我们的不是!)我们没有花费大量的时间来精心设计美丽的语言,而是确保我们达成一致并继续前进。

来自 dbt 的 Slack 社区。(图片由 Atlan 提供;编辑删除全名和照片。)
2.用强化你价值观的仪式将价值观转化为行动
很多人认为文化“就这么发生了”。这是一种神秘的生物,这就是它的本质…
我坚决不同意。文化不是凭空产生的。通过将你的价值观转化为更具体的东西,你可以努力创造你渴望的文化。我们通过“仪式”做到了这一点。
例如,我们最终将我们团队的章程固化为 4 个关键价值观:敏捷、信任、协作和创新。然后,我们通过将每个价值映射到特定的仪式,努力将它们转化为真实的东西。

将我们的文化价值观映射到新的团队仪式中。(图片由 Atlan 提供。)
人们对可能有帮助的仪式有不同的想法,所以我们尝试了许多新的传统和流程。有些效果很好,有些则很糟糕。但是在这个过程中,我们学到了更多关于如何帮助我们的团队一起工作的知识。
总之,这些习惯成为了文化堆栈,为我们的数据堆栈和人员堆栈提供动力,并帮助我们变得更加快乐和敏捷。

来自 dbt 的 Slack 社区。(图片由 Atlan 提供;编辑删除全名和照片。)
3.推出新的仪式,自下而上而不是自上而下
我非常相信以自下而上而不是自上而下的方式来促进文化仪式的建立。由于这个原因,我认为构建一个新的仪式观念的最好方法是一个“实验”。如果实验成功了,那么它就会成为一种仪式,成为你的团队工作的一种方式。如果不行,你就试试别的。
以下是创造这些新仪式的一些最佳实践:
- 从就共同的原则和问题达成一致开始:确保你理解并同意贯穿你的仪式的具体想法。例如,我们的一个习惯是每季度进行一次开始、停止、继续练习,以揭示我们作为一个团队想要解决的最大问题。
- 让团队达成共识:在我们第一次开始尝试敏捷和 Scrum 之前,我们整个团队都阅读了《T2 Scrum》一书来理解这个过程背后的基础。这是关键。像 Scrum 这样的新流程看起来像是一个巨大的开销——如果自上而下地执行,它很可能会变成另一个苦差事。
- 衡量您的进步:我们毕竟是数据人!对我们来说,每周的速度测量和完成百分比目标有助于激励团队,让我们不断前进。一条简单的每周 Slack 消息向我们展示了我们是如何前进和改进的,这让世界变得不同。
- 建立一种有益提问的文化:没有人会有正确的答案,所以重要的是放下自我,创造开放、友好的交流。例如,在我们的日常站立活动中,我们会问这样的问题:“你为什么没有实现本周的目标?”或者“是什么阻碍了你完成这项任务?”。创造一种彻底坦诚和信任的文化有助于我们不断学习如何在未来做得更好。

我们的每周进度信息。(图片由 Atlan 提供。)
😍聚焦我们最喜爱的仪式,帮助我们实践我们的价值观
支持创新的数据智囊团
我们担心关注业绩会降低我们的创新能力,所以我们成立了智囊团。(这是我们无耻地借鉴了皮克斯的想法,并为我们的数据团队做了修改。阅读这个伟大的观点,了解他们是如何做到的。)
大多数情况下,只有一两个人从事一个数据项目,但是整个团队都有集体的知识,并且从过去的项目中学到了有用的东西。
在我们的智囊团中,我们会很快将这些知识用于早期项目。我们召集团队 30 分钟,向每个人简要介绍项目,然后通过结构化的头脑风暴过程来帮助每个人创造和贡献他们的创新想法。

一些松散的消息宣布我们的智囊团会议。(图片由 Atlan 提供。)
数据抄袭方支持信任和协作
由于数据团队如此多样化,人们很难理解彼此的挫折。
例如,销售主管可能一开始是销售代表,但大多数数据经理都不是数据工程师,大多数数据工程师都不是分析师。因此,当仪表板损坏时,分析师很容易质疑,“工程师是否完成了他的工作?!"或者让数据团队互相攻击。
这些抄袭派对有助于将这些不满公开化。我们在一个周五的晚上抽出一两个小时,坐在一起吃晚饭,开始抱怨那个星期出了什么问题。这些非但没有带来麻烦,反而帮助我们增强了对彼此工作的同理心和理解。

我们的一个数据剽窃团体的照片。(图片由 Atlan 提供。)
这只是两种仪式的一个例子,但是我们投资了大量其他的仪式,比如每日站立、实施敏捷、鼓励运输文化的每周演示,以及文档时间。
我不想在这里写一本书,所以我将在我的周刊时事通讯中深入探究我们的文化仪式。
对数据领导者的一些最终想法
随着 2022 年的到来,我建议大力投资现代数据文化体系,就像投资现代数据体系一样。就像你的数据栈一样,建立一个更好的文化并不容易或迅速。这需要时间、信任和实验。会有很多失败,但如果你不断评估和沟通,你最终会拥有一个梦想的数据团队。
如果你真的想建立一种数据文化,我也建议你考虑建立一个“数据支持”团队。这可以模仿一个销售支持团队,该团队负责推动销售的文化仪式、支持和项目管理。这些角色非常新,所以你可能想在你的团队中寻找对文化和团队建设有热情的人。我认为非常适合的人物角色类型是具有构建社区或项目管理天赋的分析师,或者是“参谋长”类型的人。
当你步入 2022 年时,问问你自己——你的团队中是否有人的全职工作是考虑你的数据文化堆栈?
觉得这个内容有帮助?在我的时事通讯《元数据周刊》上,我每周都写关于活动元数据、数据操作、数据文化和我们的学习建设的文章。 在此订阅。
是时候构建您的数据科学项目了
构建数据科学项目的简单模板

[作者插图]
为什么笔记本电脑在数据科学界如此受欢迎?
当你深入数据科学领域时,你会很快注意到笔记本是工作和分享数据科学项目的常用工具。
在某种程度上,这是一个有充分理由和良好基础的选择。笔记本将代码、图形和文本汇集在一个单一快速的交互式“生态系统”中。
让我们退一步讲,
要运行一行 python 代码,我可以说没有什么比直接在控制台中执行它更快的了。然而,当您必须运行多行代码时,这就变得不方便了。想象一下,在一个控制台中定义一个功能是多么的笨拙和不切实际。
另一方面,python 脚本是创建和执行长代码的一种便捷方式。然而,它在数据科学的环境中也是不切实际的,因为它不能很好地扩展。事实上,无论何时你想写一段代码,你都必须创建一个 python 文件。因此,花点时间想想在一个数据科学项目中创建的笔记本单元的数量。当然,它将让您了解您将创建多少 python 文件,以及确保它们的执行顺序是多么具有挑战性。
简而言之,笔记本提供了一种运行 python 代码的方式,就像在控制台上一样快,同时还能编写代码片段。因此,它们扩展了基于控制台的行为,并增加了交互性。
就我个人而言,我发现这些是使笔记本电脑在数据科学社区中获得如此巨大人气的核心功能。
“一个笔记本结构”运行良好,直到…
作为一名数据科学学生,我过去常常以笔记本的形式提交我的作业和微型数据科学项目。除了我上面提到的优点之外,在一个笔记本上组织我的工作也很方便,因为我可以嵌入图形和注入降价来编写文本/等式,从而进一步阐述我的推理。
直到我参与了一个研究实习,我才意识到这个“一个笔记本结构”的局限性。特别是,我注意到当项目变得越来越大时,这种方法不能很好地扩展。
当我开始获取、清理和探索数据时,单元格的数量呈指数级增长,我很快就被数量庞大的变量淹没了。此外,当尝试新的方法时,我注意到我一直在写重复的代码。最后,为了避免变量之间的歧义以及一些笔记本单元格不会影响其他单元格,我将代码的一些(许多)部分切换到注释中。老实说,我通常会关闭笔记本内核并重启环境。
简而言之,在一个笔记本中编写整个项目的代码是不切实际的,在这个笔记本中,人们获取、探索和清理数据,然后设置、训练和评估模型。
如果一个人想发现一个 bug,或者决定在一个又长又乱的笔记本上做些什么,这甚至会是一个噩梦,笔记本上满是切换成注释的代码块。
从这次不幸的经历中,我明白了“一个笔记本结构”并不是处理大项目的最佳选择。

[作者的迷因]
在采取行动之前先谷歌一下
我相信数据科学是软件编程和应用数学(概率、统计、优化……)之间的接口。在从事数据科学项目时,我经常意识到我编码比其他任何东西都多。清理数据需要代码,理解数据需要可视化,而可视化又需要代码,…
当我编码时,我开发了所谓的“谷歌一下”反射。因此,每当我忘记/怀疑某件事或陷入某个错误时,我就简单地谷歌一下。
“有人说一个软件工程师只是一个专业的谷歌搜索者”, Fireship,如何像一个高级软件工程师一样“谷歌一下”。
就个人而言,养成这种习惯是最好的救生习惯之一,它可以让你从用详细的包装文件来填充大脑中解放出来。与其死记硬背,不如学会如何高效地搜索信息。
接下来,我浏览了互联网来寻找我的问题的解决方案,特别是一个用于组织的项目结构,从而能够扩大我的工作。显然,我找到了我要找的东西。我发现了一个千篇一律的模板项目:“ cookiecutter data-science ”。它是一个千篇一律的模板,旨在提供一个标准化的数据科学项目结构。
标准项目结构背后的动机
我承认我的不幸经历让我明白我是多么迫切地需要一个项目结构。然而,在仔细研究了模板描述和它的 GitHub 库之后,我更加确信标准结构的重要性,并且意识到它为“你和其他人”提供的优势。
一方面,它可以有效地组织思想和代码,从而加快工作流程。所以,你不会在“路中间”迷路,或者站在笔记本前无语地想“我到底在想什么”。
另一方面,它保证了代码的可共享性和可复制性。因此,其他人将能够快速直接跳转到他们感兴趣的代码部分。更重要的是,他们不会在重新执行你的代码时遇到麻烦。
我立刻认为我解决了我的问题,我所需要的就是采用这个项目结构。然而,这并不像我想象的那么容易。的确,熟悉包含一些文件和文件夹的项目结构非常困难,以至于我完全忽略了它们的用途——尤其是对于像我这样的初学者。
为了使这个项目结构适应我的用例,我花了几个小时的思考和实验来理解这个结构,并根据我的需要调整它。最后,我决定采用下面的结构:"简单的 DS 项目"
“简单的 DS 项目”结构
在这一节中,我将详细介绍“简单 DS 项目”结构的每个组件。此外,我将强调每一个项目背后的目的和动机。

“简单的 DS 项目”结构[作者插图]
“数据”文件夹
数据科学的一个基本目标是从数据中获得洞察力。因此,它是必不可少的成分。
该文件夹的目的是收集所有项目原始数据。另一方面,它也可以作为一个“桶”,用来保存预处理过的数据,以避免每次都重复相同的操作。
“笔记本 _ 探索 _ 清理”文件夹
该文件夹将包含所有与数据清理相关的笔记本。但是为什么把探索和清理放在一个文件夹里,而不把它们分开放在不同的文件夹里呢?
在我参与的每个项目中,我从来没有能够独立于清理数据来探索数据(反之亦然)。事实上,正是在探索阶段,我决定了如何处理这些数据。例如,在可视化数据列中缺失值的比例之后,我决定如何处理它们(例如,删除它们,或者用中位数替换它们……)。
最后,在探索-清理您的数据之后,确保将它保存在“data”文件夹中,以便以后在构建模型时使用。
“笔记本 _ 模型”文件夹
顾名思义,这个文件夹专门用于构建、训练和评估模型的笔记本。我强烈建议将每个型号放在一个笔记本中。
此文件夹的典型结构是, model_1。 ipynb , model_2.ipynb ,…或者如果你想给你的文件起一个有意义的名字,没有什么比用模型的名字命名更好的了,例如,linear _ regression . ipynb, lasso.ipynb , ridge.ipynb , elasticNet.ipynb
“py_scripts”文件夹
让我们想象以下(循环出现的)情况,
在 exploration_1.ipynb 中,你写了一段代码来可视化一个数据列。后来,在尝试另一种方法时,您需要在 exploration_2.ipynb 中使用相同的代码来制作类似的可视化效果,所以您复制粘贴了这些代码以便重用。在 exploration_3.ipynb 中,你另一次需要这个可视化,所以你再次复制粘贴那个东西,…
同时使用多台笔记本电脑的一个主要缺点是编写重复的代码。“py _ script”文件夹的主要目的就是为了克服这样的问题。事实上,它将作为一个 python 包,您可以在其中放置所有重复的代码。所以,每当你注意到你在多次复制粘贴一个代码时,只要把它重写为一个函数,把它放入 python 模块,瞧!当你需要它的时候,你可以直接导入它,就像导入一个普通的 python 模块一样。
“README.md”文件
自述。 md 是一个用来描述你的项目的 markdown 文件。在这里,您将设定项目的背景,提及其目的,并陈述重现其发现的指导原则。
在浏览项目时,我总是先浏览它们的自述文件,然后再深入研究它们的内容。因此,请始终记住,该文件位于项目的最前面。
的”。gitignore”文件
当在一个大项目上工作时,使用版本控制软件变得强制性,特别是如果项目有不止一个贡献者的话。 Git 结合 GitHub 就是其中之一,可以使项目管理变得简单高效。

不使用版本控制时的麻烦
尤其是”。gitignore" file 包含了 Git 不应该跟踪的所有文件和文件夹的名称,因此不会与 GitHub 库同步。通常,它包含缓存和构建文件夹的名称。此外,您可以在其中包含“data”文件夹,尤其是当您使用超过 100MB 的大型数据集时。
除此之外,如果你不熟悉 Git 和 GitHub(坦白地说,你不应该熟悉),可以考虑花点时间去了解它们。当然,这将是你编程生涯的一个转折点。
“environment.yml”文件
在数据科学中,第三方包的使用无处不在,如 numpy、scikit-learn 。那么,您如何告诉其他人运行您的代码需要安装哪些依赖项呢?
"environment.yml" 意在回答这个问题,因为它包含了 Jupyter 内核运行代码或笔记本所需的所有 python 包。
除此之外,这个文件很容易创建和使用。要使用 anaconda 提示符将您的 conda 环境导出到您的项目目录,只需使用 cd 并运行以下命令:
conda env export > environment.yml
通过将这个文件添加到您的项目中,您可以确保其他人在执行您的代码时不会发现问题,更重要的是,您可以保证您的发现的可重复性。事实上,其他人只会运行下面的命令来复制您的 conda 项目环境
conda env create -f environment.yml
连接到它,然后运行代码。
“简单 DS 项目”入门
生成项目结构
使用“简单的 DS 项目”结构很容易上手。您所需要做的就是安装cookiecutters——一个从模板项目创建项目的 python 包——通过运行
pip install cookiecutter
然后,执行下面的命令,按照提示创建/设置项目及其名称
cookiecutter https://github.com/Badr-MOUFAD/cookiecutter-simple-DS-project.git
完成后,“简单的 DS 项目”结构将在您的本地机器上生成,并准备开始工作…
集成开发环境(IDE)说明
当使用这个项目结构时,您会注意到您不断地从一个笔记本移动到另一个笔记本,从一个笔记本移动到一个 python 文件,…我发现这有点限制性。
IDE 是减轻这种限制的工具,因为它们可以在项目目录和文件之间轻松地转换。事实上,通过侧栏中显示的目录树,您可以看到项目的所有信息。此外,您可以在同一环境中修改文件。
在我的例子中,我使用 VS 代码结合 Jupyter 扩展。
总结和结论
“简单 DS 项目”是一个受“cookiecutter 数据科学”启发的模板。它提供了一个入门级的结构来组织你的工作,当处理一个“有点大的项目”。
此外,它不是一个可以完全遵循的结构。你可以根据自己的需要进行调整和完善。老实说,我会根据我参与的项目不断地修改它,添加/删除文件和文件夹。
记住,当你在项目中工作时,你组织工作的方式会不断发展。就我而言,我注意到自己最近开始越来越向最初的结构——“cookiecutter 数据科学”靠拢。当我重新思考是什么阻止了我直接采用它时,我发现并不是结构本身的复杂性,而是我不熟悉处理一个项目,在这个项目中,我操作多个具有不同扩展名的文件夹和文件(python、notebooks、markdowns 等等)。我相信“简单 DS 项目”模板会让您顺利完成这一过渡。
最后,要查看模板的实时版本,可以访问它的 GitHub 库。在那里,您还可以找到源代码。
是时候像条形图一样使用 AI 和机器学习了。
组织需要更广泛地部署人工智能和机器学习,而不仅仅是数据科学团队。
是的,将 ML 民主化会导致不完善的模型,有时甚至是错误的决策。但是不完美的 ML 并不比不完美的 Excel 商业分析差。数据的可用大小和规模要求更多的分析师具备一套升级的技术。
AI 和机器学习(AI / ML)被太多的谨慎和崇敬对待。AI / ML 作为一个下棋、赢得危险的黑盒进行营销,它获得了不应有的恐惧和尊重。结果,它成了一种特殊的工具,为“大项目”而保留。
但是机器学习仅仅是一种新的方式将已经被检验的模式映射到已经被瞄准的结果变量。
以前,在 BI 报告工具中,分析师可能会深入到一些人口统计变量:按年龄、性别、地理位置和与公司的关系划分的流失率条形图。从这一结果中,营销人员可能会注意到一种模式,即年龄在 35-50 岁之间的男性,他们拥有较高的余额和贷款产品,以最高的利率保留下来。这种特定的分析几乎每天都在几乎每个组织中发生,并且可以被认为是“快速人类学习模型”

作者在 Einblick 中创建的图像
机器学习完成完全相同的任务。随着数据科学工具(如 AutoML)的最新进展,ML 的创建开始变得大众化,现在获取结构化数据集并创建良好的模型变得轻而易举。缺乏 Python 或 R 的知识不再是 ML 应用的障碍。

AutoML 工具复杂多样;Einblick 的 AutoML 向导是一个直接应用于分类任务的例子——作者在 Einblick 中创建的图像
一旦 ML 运行完成,现在很容易重现上面的洞察力。首先,检查特征重要性输出将向我们展示最重要的人口统计因素的定性等级排序。该模型已经成为评估候选驱动因素的一种更全面的方法,并且可以进一步彻底探索顶级驱动因素(包括使用条形图!)

XGBoost 回归的 Einblick 中的 Shapley 可视化— 作者在 Einblick 中创建的图像
同样,好的 ML 工具会进一步解释所创建的模型,它可以让您遍历各个预测。这成为一种实用而具体的方式来显示和理解客户的个人资料如何导致预测的行为。大多数人类会欣赏有形的例子,即使机器学习是大规模完成的。

了解一个账户的不同变量如何影响预测的和实际的客户流失。— 作者在 Einblick 中创建的图片
一个 ML 模型并不真的需要成为一个生产化的评分 API 来对我们的分析师有用。上述可视化非常快完成,识别关键驱动因素和使用直接输出的可消化范围意味着分析师不需要太多特殊培训。当然,也没有限制;图形化表示的基于 XGBoost 的模型可以按原样生产,也可以由数据科学家进行微调。
尽管在不了解完整技术实现的情况下使用机器学习存在缺陷,但由不完善的 ML 支持的任何商业决策都不可能比仅在电子表格中产生的现有不完善分析更糟糕。一个不完美的分析世界认识到,以上的 ML 输出是递增的,例如,根据直觉逐个搜索驱动程序。
最终,组织数据科学战略需要在应用高级数据科学方面争取更大的灵活性,并创造一种环境,认识到在多个应用级别从 ML 中获取价值是很容易的。在日常分析中,数据透视表、饼图和机器学习应该同等对待,因为它们在为明智的决策创建数据驱动的输入方面都有重要作用。
原载于 ein blick:https://ein blick . ai/its-time-to-use-ai-and-machine-learning-like-bar-charts/
Einblick 是世界上第一个可视化数据计算平台,创建与数据最自然的交互。在https://einblick.ai/product/了解更多关于我们的信息
多智能体强化学习与合作人工智能
帮助人类相互合作的工具?

埃里克·克鲁尔在 Unsplash 上的照片
多代理强化学习(MARL)是强化学习的一个子领域,它变得越来越相关,并且一直让我感到惊讶——在继续阅读这篇文章之前,你必须观看 OpenAI 的这个视频,它展示了在这一领域正在进行的惊人研究。
无论如何,MARL 已经在流行的策略游戏中取得了令人难以置信的成功,已经证明是有趣的新兴行为的催化剂(如上文所述),并将是几项新兴技术持续发展的关键,不同自动驾驶汽车之间的通信就是这样一个例子。这篇文章将首先讨论这个子领域是什么,描述它与合作人工智能的关系,然后迅速转移到这些研究领域在未来将产生的巨大影响。
什么是多智能体强化学习?
普通强化学习关注的是一个环境中的单个主体,寻求在该环境中最大化总报酬。你可以想象——或者只看这个视频——一个正在学习走路的机器人,它的总体目标是不摔倒地走路。它会因为没有摔倒而获得奖励,通过反复试验,并最大化这些奖励,机器人最终学会了走路。在这种情况下,我们有一个单个代理人寻求通过最大化总报酬来实现目标。
多智能体强化学习研究多个智能体如何在一个共同的环境中相互作用。也就是说,当这些智能体与环境和其他智能体相互作用时,我们能观察到它们合作、协调、竞争或集体学习来完成特定的任务吗?它可以进一步分为三大类:
合作:所有的代理都朝着一个共同的目标努力
竞争:代理为了完成一个目标而相互竞争
两者的混合:想象一下一场 5v5 的篮球比赛,同一个队的人互相配合,但是两个队却在互相竞争。
MARL 的一个典型例子是一群机器人试图营救一个人。每个机器人对其环境只有部分的可观察性(他们只能看到他们下面的一小块土地),因此机器人需要相互协调来营救个人。
在这里,我们可以看到科幻与现实之间的壁垒迅速化解。你可能已经在想象机器人团队建造房屋、自动驾驶汽车无缝交互或分布式资源管理。
大规模合作、合作人工智能及其未来影响
大规模的合作是我们人类取得惊人成功的关键因素。正是通过人类的集体智慧和协作,我们才能够完成令人难以置信的壮举。为了实现大规模合作,我们创建了能够实现大规模合作的机制。也就是说,我们创造了协议(信仰系统,政府系统,等等。)来诱导大规模的合作,这样一个人在与完全陌生的人合作时会感到舒服。人类的许多失败和生存威胁可以被视为一个协调或合作的问题(核军备竞赛,气候变化,世界大战等)。).如何使用 MARL 来解决这些协调问题?进入合作 AI 。
合作人工智能是人工智能中的一类问题,寻求使用人工智能来解决或有助于解决合作问题。这项研究的重点是(1)建立具有合作能力的人工智能,以及(2)创造可用于促进群体(包括机器和人类)合作的人工智能。
人类的成功在很大程度上取决于我们与他人合作的能力,如果有一天人工智能可以用来改善人类之间的合作,这可能会导致人类进步和减轻人类痛苦方面的令人难以置信的进步。
人工智能可以用来增强人类的超级能力——大规模合作。在这一框架下,不难想象人工智能被用来帮助谈判和平条约、创造更强大和公平的政府形式,或者帮助人类相互合作以避免存在性灾难(气候变化、流行病、核浩劫)。事实上,这种研究已经存在,最近多主体系统框架被用于设计税收政策:
多智能体强化学习以及其他学科(博弈论、自然语言处理、多智能体设计等)。)是将被用来解决合作人工智能中存在的这些问题的工具。这是另一个在 MARL 框架内对这类问题进行研究的例子。
想了解更多?
如果你有兴趣学习更多关于合作人工智能的知识,我推荐阅读合作人工智能中的未决问题。我有没有被说服开始在泥灰岩里打探?这个 github repo 提供了一个不错的 MARL 研究论文集。流口水来进行你自己的泥灰实验?看看宠物动物园!
无耻地为我的网站和 twitter 插上一脚——更多的 MARL(项目/博客帖子)内容即将到来!
参考文献
[1]: Y .哈拉里,智人 (2015)
[2]:艾伦·达福、爱德华·休斯、约拉姆·巴赫拉赫、坦图姆·科林斯、凯文·r·麦基、乔尔·z·雷博、凯特·拉森、托雷·格雷佩尔,《合作人工智能中的开放性问题》(2020 年),https://arxiv.org/abs/2012.08630
[3]:不太可能的 AI。(2021 年 4 月 12 日)。CSL 研讨会:雅各布福斯特[视频]。YouTube。https://www.youtube.com/watch?v=ii_SwIsY8aU&ab _ channel = implebable ai
[4]: P. Barekatin,https://www . quora . com/What-is-multi-agent-reinforcement-learning
Python 中的 Jaccard 相似性和 Jaccard 距离-统计
在本教程中,我们将探索如何在 Python 中计算 Jaccard 相似性(索引)和 Jaccard 距离

乔尼·克洛在 Unsplash 上的照片
目录
- 介绍
- 什么是 Jaccard 相似性
- 计算 Jaccard 相似度
- 什么是 Jaccard 距离
- 计算雅克卡距离
- 非对称二元属性的相似性和距离
- 用 Python 计算 Jaccard 相似度
- 用 Python 计算 Jaccard 距离
- Python 中非对称二元属性的相似性和距离
- 结论
介绍
Jaccard 相似性(Jaccard 指数)和 Jaccard 指数被广泛用作相似性和相异性度量的统计量。
它在实用统计中的应用范围从简单的集合相似性,一直到复杂的文本文件相似性。
为了继续学习本教程,我们需要以下 Python 库:scipy、sklearn 和 numpy。
如果您没有安装它,请打开“命令提示符”(在 Windows 上)并使用以下代码安装它:
pip install scipy
pip install sklearn
pip install numpy
什么是 Jaccard 相似性
Jaccard 相似性(也称为 Jaccard 相似性系数,或 Jaccard 指数)是一种用于测量两个集合之间相似性的统计数据。
它的用途进一步扩展到测量两个对象之间的相似性,例如两个文本文件。在 Python 编程中,Jaccard 相似性主要用于度量两个集合之间或者两个非对称二进制向量之间的相似性。
数学上,Jaccard 相似度的计算就是简单地取集合交与集合并的比值。
考虑两套 A 和 B :

作者图片
那么它们的 Jaccard 相似性(或 Jaccard 指数)由下式给出:

作者图片
让我们把这个公式分成两部分:
1。提名人

作者图片
2。分母

作者图片
使用 Jaccard 相似性的公式,我们可以看到相似性统计只是上述两个可视化的比率,其中:
- 如果两组相同,例如 A = {1,2,3}和 B = {1,2,3},那么它们的 Jaccard 相似度= 1。
- 如果集合 A 和 B 没有公共元素,比如说 A = {1,2,3}和 B = {4,5,6},那么它们的 Jaccard 相似度= 0。
- 如果集合 A 和 B 有一些公共元素,例如 A ={1,2,3}和 B = {3,4,5},那么它们的 Jaccard 相似度是区间上的某个值:0 ≤ J(A,B) ≤ 1。
计算 Jaccard 相似度
考虑两组:
- A =
- B =
或者视觉上:

作者图片
第一步:
作为第一步,我们需要找到 A 和 B 之间的集合交集:

作者图片
在这种情况下:

作者图片
第二步:
第二步是找到 A 和 B 的套装接头:

在这种情况下:

作者图片
第三步:
最后一步是计算交集和并集的大小之比:

作者图片
什么是 Jaccard 距离
与 Jaccard 相似性(Jaccard 指数)不同,Jaccard 距离是两个集合之间不相似性的度量。
数学上,Jaccard 距离的计算是集合并集和集合交集之差与集合并集之比。
考虑两套 A 和 B :

作者图片
那么它们的 Jaccard 距离由下式给出:

作者图片
让我们把这个公式分成两部分:
1。提名人
提名者也可以写成:

作者图片
这实际上是 A 和 B 之间的设置对称差,由下面信息图中的黄色区域显示:

2。分母
分母实际上是 A 和 B 的集合联合,如下面信息图中的黄色区域所示:

使用 Jaccard 距离的公式,我们可以看到,相异统计量只是上述两种可视化的比率,其中:
- 如果两组相同,例如 A = {1,2,3}和 B = {1,2,3},那么它们的 Jaccard 距离= 0。
- 如果集合 A 和 B 没有公共元素,比如说 A = {1,2,3}和 B = {4,5,6},那么它们的 Jaccard 距离= 1。
- 如果集合 A 和 B 有一些公共元素,例如 A ={1,2,3}和 B = {3,4,5},那么它们的 Jaccard 距离是区间上的某个值:0 ≤ d(A,B) ≤ 1。
计算雅克卡距离
考虑两组:
- 一个 =
- B =
或者视觉上:

第一步:
作为第一步,我们将需要找到 A 和 B 之间的集合对称差:

作者图片
在这种情况下:

作者图片
第二步:
第二步是找到 A 和 B 的集合接头:

在这种情况下:

作者图片
第三步:
最后一步是计算对称差和并集的大小比:

作者图片
非对称二元属性的相似性和距离
在本节中,我们将研究 Jaccard 相似性和 Jaccard 距离的更具体的应用。更具体地说,它们对不对称二元属性的应用。
从它的命名上,我们已经可以猜到一个二元属性是什么了。它是一个只有两种状态的属性,这两种状态是:
- 0,表示属性不存在
- 1,意味着属性存在
这种不对称性源于这样一个观点,即如果两个属性都存在(都等于 1),那么它被认为比两个属性都不存在(都等于 0)更重要。
假设我们有两个向量, A 和 B ,每个向量都有 n 个二元属性。
在这种情况下,Jaccard 相似性(指数)可以计算如下:

作者图片
和 Jaccard 的距离可以计算为:

作者图片
其中:
- M_{11}是属性的总数,其中 A 和 B 都为 1
- M_{01}是属性的总数,其中 A 为 0, B 为 1
- M_{10}是属性的总数,其中 A 为 1, B 为 0
- M_{00}是属性的总数,其中 A 和 B 都为 0
并且:

作者图片
例子
为了更简单地解释这一点,考虑可用于购物篮分析的示例。
您经营着一家拥有 6 个产品(属性)和 2 个客户(对象)的商店,并且还要跟踪哪个客户购买了哪个商品。你知道:
- 顾客甲买了:苹果,牛奶咖啡
- 顾客 B 买了:鸡蛋、牛奶、咖啡
可以想象,我们可以构建以下矩阵:

作者图片
其中每个客户的二进制属性表示客户是购买了(1)还是没有购买(0)特定产品。
问题是找到这两个客户的 Jaccard 相似性和 Jaccard 距离。
第一步:
我们首先需要找到每个 M 的属性总数:

作者图片
我们可以通过对计数求和来验证这些组。它应该等于 6,这是属性(产品)的 n 个:

作者图片
第二步:
既然我们有了所有需要的输入,我们现在可以计算 Jaccard 相似性:

作者图片
和 Jaccard 距离:

作者图片
用 Python 计算 Jaccard 相似度
在本节中,我们将使用在第一节中定义的相同器械包:
- A =
- B =
我们从用 Python 定义它们开始:
下一步我们将构造一个函数,将 set A 和 set B 作为参数,然后使用 set 操作计算 Jaccard 相似度并返回:
然后测试我们的功能:
您应该得到:
0.25
这与我们手动计算的统计数据完全相同。
用 Python 计算 Jaccard 距离
在本节中,我们继续使用与上一节相同的器械包( A 和 B ):
我们从用 Python 定义它们开始:
下一步,我们将构造一个函数,将集合 A 和集合 B 作为参数,然后使用集合运算计算 Jaccard 相似度并返回:
然后测试我们的功能:
您应该得到:
0.75
这与我们手动计算的统计数据完全相同。
在 Python 中计算非对称二进制属性的相似性和距离
我们从导入所需的依赖项开始:
使用我们在理论章节中使用的表格:

作者图片
我们可以创建所需的二进制向量:
然后使用库的函数来计算 Jaccard 相似性和 Jaccard 距离:
您应该得到:
Jaccard similarity is equal to: 0.4
Jaccard distance is equal to: 0.6
这与我们手动计算的统计数据完全相同。
结论
在本文中,我们探讨了 Jaccard 相似性(索引)和 Jaccard 距离,以及如何在 Python 中计算它们。
如果你有任何问题或对一些编辑有建议,请随时在下面留下评论,并查看更多我的统计文章。
原载于 2021 年 12 月 14 日 https://pyshark.comhttps://pyshark.com/jaccard-similarity-and-jaccard-distance-in-python/。
詹姆斯·乔伊斯和机器学习

雅克·博普拍摄于 Unsplash
实践教程
用张量流标点 Penelope
詹姆斯·乔伊斯-
佩内洛普是这本书的主角。
介绍
在这篇文章中,我们将通过训练一个模型来识别和标点佩内洛普中的意识流。佩内洛普是爱尔兰作家詹姆斯·乔伊斯的著名作品《尤利西斯》的一部分。在本文中,我们将仔细研究詹姆斯·乔伊斯的独白式作品《佩内洛普》。佩内洛普可能很难读懂。
卡尔·荣格总结佩内洛普 -
在这里,令人窒息的空虚变得如此紧张,以至于达到了爆发点。毫无希望的空虚是整本书的基调。
语言结构
在进行机器学习之前,让我们简单地了解一下《佩内洛普》中的语言结构。Penelope 的结构相当奇怪,不像英语语料库的通常结构。佩内洛普以“是”字开头,也以“是”字结尾。佩内洛普完全致力于《尤利西斯》中的角色莫莉·布鲁姆的“主观”。佩内洛普通常因其“意识流”而被引用。意识流的定义在不同的学术领域会有所不同,但一般来说,它指的是一系列连续的句子。
符号化
为了达到本文的目的,我们将简单地用意识流来表示佩内洛普中缺少标点符号。这是对一个学术上很重要的想法的过度简化,但是它将帮助我们在本文的范围内工作。按照意识流的描述,我们可以想象乔伊斯带我们深入莫莉·布鲁姆的思想。
人们通常不用标点符号来思考,这在詹姆斯·乔伊斯的作品中得到了证明。因此,为了找到句子,我们不能使用 nltk 包中的句子分词器。这是因为分词器会通过在字符串中查找句点字符来给出句子。因此,我们不能使用标记符,因为 Penelope 只有两个句点,分隔大约 25000 个单词。这就是机器学习的用武之地。
模型
第一步包括从互联网档案馆或古登堡计划获取纯文本文件。下一步包括考虑一种方法,我们可以根据詹姆斯·乔伊斯的作品训练一个模型。一种简单的方法是使用二进制分类。我们可以用数字 1 标注尤利西斯中的每一句话,用 0 标注一组不是句子的单词。下一步是考虑模型的架构。一个 LSTM 有一个强大的架构设计,特别是对于 NLP,TensorFlow 使它非常容易使用。由于我们将此视为二元分类问题,我们可以看到我们的损失函数对应于二元交叉熵。
model = tf.keras.Sequential([
tf.keras.layers.Embedding(vocab_size, embedding_dim, input_length=max_length),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64, return_sequences=True)),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])
model.summary()
考虑到训练需要一些时间,我们可以将计算分成两部分。训练我们的模型,然后标点佩内洛普。为了训练我们的模型,我们可以将佩内洛普从尤利西斯的剩余部分中分离出来。下一步将涉及到逆转尤利西斯剩余部分的每一句话。这些颠倒的句子将被标记为 0。随着本文的深入,这样做的原因将变得更加清楚。现在我们有了我们的训练数据,我们有了我们的模型,所以我们要做的就是训练模型。仅在几个周期内训练该模型后,我们可以看到大约 97%的准确度。一旦在 Google Colab 上训练了模型,我们就可以保存我们的模型,以便在本地机器上测试它。
Epoch 1/10
1488/1488 [==============================] - 188s 119ms/step - loss: 0.5992 - accuracy: 0.6194
Epoch 2/10
1488/1488 [==============================] - 177s 119ms/step - loss: 0.2330 - accuracy: 0.8816
Epoch 3/10
1488/1488 [==============================] - 177s 119ms/step - loss: 0.1538 - accuracy: 0.9264
Epoch 4/10
1488/1488 [==============================] - 178s 119ms/step - loss: 0.1149 - accuracy: 0.9471
Epoch 5/10
1488/1488 [==============================] - 177s 119ms/step - loss: 0.0933 - accuracy: 0.9578
Epoch 6/10
1488/1488 [==============================] - 177s 119ms/step - loss: 0.0762 - accuracy: 0.9644
Epoch 7/10
1488/1488 [==============================] - 177s 119ms/step - loss: 0.0696 - accuracy: 0.9675
Epoch 8/10
1488/1488 [==============================] - 178s 119ms/step - loss: 0.0609 - accuracy: 0.9714
Epoch 9/10
1488/1488 [==============================] - 177s 119ms/step - loss: 0.0534 - accuracy: 0.9732
Epoch 10/10
1488/1488 [==============================] - 177s 119ms/step - loss: 0.0544 - accuracy: 0.9733<tensorflow.python.keras.callbacks.History at 0x7f86f03d6160>
标点符号 Penelope
为了检查我们的模型是否理解一个句子的一般构成,我们可以给模型输入几个句子。第一句话来自尤利西斯,我们看到模型预测这句话有 99%的准确率。第二个句子是一个普通的英语句子,我们可以看到这个模型也预测正确。现在,如果我们颠倒第二句话,这里我们看到模型计算的分数小于 1%。这意味着我们的模型通常正确地计算英语句子的构成。我们现在可以运行一个简单的循环,从左到右穿过佩内洛普。一旦我们的模型以 99.99%的准确率找到一串单词,我们就可以简单地将句子写入文本文件。
s="Solemnly he came forward and mounted the round gunrest."
seq = tokenizer.texts_to_sequences([s])
pad_s = pad_sequences(seq, maxlen=max_length, truncating=trunc_type)
print(model.predict(pad_s))
[[0.9999999]]s="My name is Sean."
seq = tokenizer.texts_to_sequences([s])
pad_s = pad_sequences(seq, maxlen=max_length, truncating=trunc_type)
print(model.predict(pad_s))
[[0.9999671]]s="Sean is name my."
seq = tokenizer.texts_to_sequences([s])
pad_s = pad_sequences(seq, maxlen=max_length, truncating=trunc_type)
print(model.predict(pad_s))
[[0.00011346]]
下面我们可以看到我们的模型实时标点佩内洛普。
f = open(fpath+'PenolopePunctuated.txt', "a")
i=0
sentence=""**for** c **in** range(24186):
sentence=sentence+" "+wordlist[i]
currentvalue=model.predict(check(sentence))
**if**(currentvalue>0.9999)&(currentvalue<1):
f.write(sentence+",")
i=c
sentence=""
i=i+1
f.close()

作者图片
反射
看来实验是成功的。目的是让 Penelope 的可读性稍微好一点,同时保留文本中两个独特的句号。詹姆斯·乔伊斯可能是最具智力挑战的作家之一。他设置智力迷宫只是为了嘲讽他的读者。这方面的一个例子是佩内洛普中的单词“tattarrattat”。对古典语言学家来说,这是一个珍贵的词。这个词有许多独特的属性。第一,它是一个拟声词。这仅仅意味着乔伊斯创造了一个听起来和拼写一样的单词。用稍微专业一点的术语来说,这个词的词法和音位之间有明显的关系。但也许最有趣的发现与单词“tattarrattat”的回文性质有关。这意味着即使语料库是反向计算的,这个单词的状态仍然保存在 Penelope 中。

图片作者(截图来自 PenolopePunctuated.txt)
所以“tattarrattat”这个词倒着读和正着读是一样的。更有趣的是这个词的上下文。乔伊斯用这个词来表达“敲门”。一个问题出现了,乔伊斯为什么要把这个特定的单词做回文?我认为他这样做是为了提醒他的读者,即使文集被倒着读,他的创造力仍然会找到敲开读者意识之门的方法。机器学习可以让我们制作出更加易读的版本;虽然我现在还不会不顾一切。阅读尤利西斯目前极其耗费时间。卡尔·荣格很好地传达了这一点。他写道,《尤利西斯》是一个迷人的故事,讲述了都柏林没有发生什么事情的一天。但正是《尤利西斯》中的文字让它成为多产的英国作家詹姆斯·乔伊斯的代表作。
最后的话
阅读我们的文本文件的内容让我们对莫莉·布鲁姆的主观性有了一个清晰的了解。然而,从 NLP 的角度来看,还有改进的空间。一个从左到右线性移动的循环是不够的。人类可以从标点符号和单词之间的相关性中获得意义。语言学上有一句名言,“从一个人交的朋友就可以知道这个人是谁”。在这种情况下,可以预期一个句子的最后一个单词和下一个句子的第一个单词之间的句子预测较低。这是作为模型的训练与反对尤利西斯。通过增加一些额外的条件,我们也许可以开始对《T2》中的语言有一个更好的了解。用句号或逗号给语料库加标点也可以为使用用 BERT、Word2vec 等计算的语义向量来可视化和分析语料库让路。[3][4].这个项目的源代码可以在 Apache 2.0 许可下这里获得。标点语料库也可以在这个库中找到。
参考
[1] R. Ellmann,《詹姆斯·乔伊斯书信选》(1975) ,维京出版社。
[2] C .荣格,《c . g .荣格文集【第 15 卷】(1953) ,柏林根基金会。
[3] T. Mikolov,K. Chen,G. Corrado,J. Dean,向量空间中词表征的高效估计(2013) ,计算与语言[arXiv.org]。
[4] J. Devlin,M. Chang,K. Lee,K. Toutanova, BERT:用于语言理解的深度双向变换器的预训练(2018) ,计算与语言[arXiv.org]。
一月版:一个更好的世界在等着你
月刊
新年快乐,欢迎来到 2021 年!

在我们新年的第一期月刊中,我们想分享一些来自《走向数据科学》最新专栏的精选内容:数据改变。
在 2020 年的动荡和心碎中,围绕大数据的叙事被重新定义。我们的关注点从个人利益转移到如何利用数据科学造福世界各地的人们。今年,我们看到了比以往更多的关于使用数据科学和机器学习来建模流行病、预测野火、揭示我们机构中的种族歧视等的文章。
我们的编辑团队真的很喜欢从这些作品中探索和学习。通过为这一主题开辟专栏并对这些故事给予更多关注,我们希望进一步推进我们在 TDS 的核心信念之一:数据科学可以为紧迫的社会、环境和政治挑战提供洞察力。希望下面的选择将丰富和扩展您对我们如何将数据科学工具应用于社会公益的理解。
2021 年,你将如何运用你的技能让这个世界变得更美好?我们迫不及待地想把你的贡献加入这个专栏!
《走向数据科学》的编辑 Elliot Gunn 和 Linda Chen。
造福社会的数据科学
由 Ioana Spanache 博士 — 6 分钟阅读
超越我们想看什么类型的电影,到我们想生活在什么类型的世界。为社会公益进行数据科学的资源、例子和机会。
警察拦截和搜查中的种族差异
由迪沙·凯瓦拉马尼 — 9 分钟阅读
多年来警察拦截和搜查的统计分析,以确定警察部队是否对少数群体有偏见。
近距离观察加州野火中燃烧的生物质
由劳伦低 — 7 分钟读完
将加州大学圣克鲁斯森林地理站点的树种和生物量数据与野火进行比较——就像圣克鲁斯市区西北部的那场。这是我们的发现。
模拟疫情的传播
通过拉凯什·钦塔 — 20 分钟阅读
科学家如何模拟流行病?政府是如何制定封锁计划的?我们怎么知道曲线是否已经变平了?
COVID19:用 Python 可视化社交距离的影响
通过 Adarsh Menon — 6 分钟读取
使用 pandas 和 python 中的 matplotlib 可视化,一个人可以对平坦化曲线产生指数级影响。
新冠肺炎对学业成绩差距的影响
由巴尼特杨 — 21 分钟读完
随着新冠肺炎·疫情将美国经济置于混乱之中,随着种族的不同,经济前景的恶化将如何影响学术成就的差距?
使用优步移动数据优化救护车响应时间
塔哈·布洪 — 7 分钟阅读
蒙特卡洛模拟,评估基础设施对救护车响应时间的影响(伦敦塔桥案例研究)。
抑郁到想自杀
由 Eunjoo Byeon — 7 分钟阅读
使用多元线性回归确定导致抑郁症状进展的一些关键因素。
学生应该如何利用时间来提高幸福感?
由陈敏仪 — 7 分钟读取
花在生活不同方面的时间如何影响我们的幸福水平?用 Jupyter 笔记本分析调查数据。
新播客
- Rob Miles — 我为什么要关心 AI 安全?
- 本·戈泽尔— 通往 AGI 的非正统之路
- 尼古拉·巴尔丁— 人工智能符合法律:偏见、公平、隐私和监管
- 乔迪·罗斯—AGI 需要具体化吗?
新视频
- 评估线性关系 |艾米莉·a·哈尔福德
- 空间数据分析:单元去聚类 | Fouad Faraj
- 一个从零开始的源代码语言分类模型 | Amal Hasni & Dhia Hmila
我们也感谢最近加入我们的所有伟大的新作家玛丽·库尔萨特、乔·肯尼迪、奥萨索娜·伊弗欧卢瓦、乔纳·卡纳、莉亚·波普、张萌、琳达·温斯坦、舒巴姆·帕坦尼亚、吉列米娜·萨特·施奈德、法西姆·霍斯 马克·奈姆,内森·普拉特,阿曼达·j·切尼博士,达尔西·泰勒,德文·奥辛,丹尼尔·桑德斯,埃拉姆·穆纳瓦尔,阿纳·博拉,朱丽娅·乔,萨姆·斯塔克曼, 我们邀请你看看他们的简介,看看他们的工作。
一月份最引人入胜的小数据
全球风险报告
作为一个老学派的数学家,我不寻求从事大数据。相反,这篇文章是关于一个大主题的小数据。自 2006 年以来,每年 1 月发布年度《全球风险报告》( GRR ),作为年度世界经济论坛的背景材料(见下文脚注 1)。这些报告是冗长的文件,在这里可以免费获得分析的风险在未来几年(“中期”)会对世界经济产生重大影响的事件的意义上。这些报告提供了来自大型专家小组的一致意见。就我的目的而言,核心部分是一张图表,显示了 36 种风险中每一种风险的感知可能性和经济影响(见脚注 2)。请看下面这张 2020 年 1 月的图片(或点击此链接)。

2020 年全球风险报告
图表采用标准格式:横轴表示相对可能性,纵轴表示相对经济影响(见脚注 3)。因此,最大的感知风险(在新冠肺炎前夕)出现在右上角,从极端天气开始,然后是气候行动失败。
对我来说,最有趣的潜在概念问题是中期未来的可预测性如何?人们经常看到一些随意的断言,比如“没人预测”(或“我预测”)苏联解体,或类似 9/11 的袭击,或 2007-2008 年的金融危机,或新冠肺炎疫情。这种断言是荒谬的。这些本质上都是不可预测的事件,因此只谈论概率是有意义的。作为一个具体的例子,关于欧洲冷战的话题,1985 年对 1985-1995 年的一个概率评估(见脚注 4)是
65%:现状
25%:东欧内部叛乱导致苏联控制力下降
5%:苏联对西德的军事攻击
5%:苏联因内部原因而解体
对于最后一个选择,他们的短语“帝国崩溃”被证明是相当准确的。
能否判断过去概率评估的准确性?
在预测锦标赛的受控条件下(见脚注 5),人们确实可以通过评分规则来确定相对预测能力,但这需要不同的预测者评估相同的事件集合。我从来没有见过这样的中期预测数据。GRR 中的许多事件都是相当模糊的,所以不清楚如何获得预测的准确性。
因此,一个底线是,我们不能正式测试 GRR 在过去有多准确。还要注意这是小数据 : 13 年乘以 36 次事件乘以 2 次评估大约等于 1000 个数字。
但是看看过去 GRR 的分析并非正式地讨论它们的准确性是很有趣的。
那么,他们是如何预测新冠肺炎的呢?事实上,疫情风险每年都出现在 GRR 的左上角象限(低可能性,大影响)。正如许多人回顾过去时指出的那样,专家们早就预测这样的疫情会在某个时候发生,同时也承认在任何一年发生的可能性都很小。
2007-2008 年的金融危机怎么样?2007 年 1 月的报告图表(在危机显现之前)判断最大的风险是资产价格崩溃。所以那是成功的。
我们随便挑一年吧。2013 年的主要风险是长期财政失衡、供水危机、温室气体排放增加、和严重的收入差距。随后几年到底发生了什么?GRR 不再那么担心财政失衡(至少在 2021 年之前)。供水危机还没有成为头条新闻,但在 GRR 的列表中仍然很重要。不断增加的温室气体排放已被重新命名为气候行动失败,在可预见的未来,这无疑仍将是最大的风险之一。严重的收入差距,改名为社会不稳定(对我来说有点意外)随后向中间下降。因此,2013 年没有显著的成功,但反过来说,也没有没有预料到的重大事件。
具有竞争天性的读者可以尝试编写自己的风险列表,与即将到来的 2021 年 GRR 进行比较。我个人最大的猜测包括新冠肺炎引发的财政危机和社会动荡,以及网络攻击。往年,GRR 都是在 1 月中旬举行,但 2021 年的世界经济论坛实体会议目前被推迟到 5 月(而且可能会进一步推迟?),所以我不确定 2021 年的 GRR 什么时候会出现。
所以为什么要在乎呢?
在个人层面上,我们很少有人不考虑个人的未来就过完一天又一天。任何一个阅读 medium.com 的人肯定都会关注当今世界正在发生的一些事情,以及随之而来的对未来的希望和担忧。然而,我们每个人都倾向于只关注未来可能不同的几个方面,隐含地假设其他方面将保持不变。例如,最初的《星际迷航》设想了一个相当乌托邦式的复杂技术未来,但与令人生厌的 20 世纪 60 年代风格的女性形象并置。阅读 GRR 风险清单可能会促使你思考,如果这些风险中的一个或另一个成为现实,你现有的希望和恐惧会受到怎样的影响。
在组织层面上,任何对不确定的未来进行理性规划的尝试都需要将情景规划和概率预测结合起来,这些是互补的而不是对立的:如果你认为某个地缘政治事件有 40%的可能性,你能设计出两个可能发生的情景和三个不可能发生的情景吗?
最后,GRR 举例说明了一个非常广泛的基线原则:在任何不确定的环境中,如果其他人已经考虑过它,并且一个人可以确定一个共识或“中间意见”,那么它作为基线是有价值的。当形成你自己的观点或研究别人的观点时,你或他们能阐明为什么他们与基线不同吗?如果不是,就不要太在意他们的看法。

年度变化图
脚注 1:世界经济论坛因其每年一月在达沃斯召开的会议而闻名(并受到广泛批评)。但它也协调除 GRR 之外的许多分析的生产。我个人猜测,这类报告往往会比学术或政府机构的报告更准确,因为它们的输入范围更广,而且更少受制于特定的利益或意识形态。
脚注 2:随着时间的推移,所研究的风险发生了缓慢的变化,最初考虑的较少。
脚注 3:2007 年的图表有数字可能性和数字美元影响。多年来,坐标轴标签已经变得更加定性:对于 2020 年的图表,专家们被要求在 1-7 的模糊尺度上评估可能性和影响,并绘制平均值。这使得评估准确性的尝试更加复杂。
脚注 4 :詹姆斯·邓尼根和奥斯汀·贝的《肮脏战争快速指南。
脚注 5:预测锦标赛涉及陈述给定事件在给定截止日期之前发生的概率,通常是提前 6-12 个月。见本高中水平博览会或本更精采的记述。但是对于中期赛事来说,这样的比赛并不实用,因为需要等到赛事结果确定之后。
使用 BERT 实现 97%准确率的日语多类文本分类
将 NHK(日本广播公司)节目分为多种类型

康纳·乐迪在 Unsplash 上的照片
您是否有一些日文文本,如客户反馈、用户评论或邮件内容,并希望从手头的数据中提取见解?下面介绍的模型在处理日语文本时,在多类分类方面表现出色。该模型很好地理解了日语,并且可以潜在地用于许多应用领域中的许多目的,例如流失率预测、消费者细分、消费者情绪分析。
P.S:这个模型只需更改 2 行就可以轻松适应其他语言。
数据
我们将使用 NHK(日本广播公司)的节目信息作为我们的数据源。通过 NHK 的节目安排 API ,可以获得全日本电视、电台、网络电台未来 7 天安排的所有节目的【标题、字幕、内容、流派】。
问题陈述
利用节目的标题、副标题和内容,我们将尝试预测其类型。一个节目可以有多种类型,如下所示:
Title: あさイチ「体験者に聞く 水害から家族・暮らしを守るには?」
Genre: 1) 情報/ワイドショー, 2) ドキュメンタリー/教養
In the above case, we will be assuming this show’s genre is 情報/ワイドショー (Information/ Wide show)
该模型的一个改进将是可以预测每个节目的多个类型,这将使该问题成为多类多目标问题。
【探索性数据分析(EDA)】
我收集了 2021 年 8 月 30 日至 2021 年 9 月 24 日之间播出(或将播出)的 10,321 个独特节目的信息。以下是 10,321 个节目中所有 13 种类型(标签)的分布情况:

作者图片
正如您所看到的,数据是高度不平衡的,因此我们将在将数据分为训练和测试时对其进行“分层”(即:保持测试数据中的标签分布与整个数据集相同),并使用加权 F1 分数作为适合不平衡数据集的准确性度量。
数据处理
我们将数据分为训练(80%)和测试(20%)数据集。我们将在训练数据集上训练模型,并在 10 个时期内跟踪测试数据集的准确性(时期:模型遍历整个训练数据集的 1 个步骤)。产生最高精度的时期将被用作最终模型,并且来自该模型的结果将被认为是模型精度。
型号
我们模型的输入将是每个节目的“标题”、“副标题”和“内容”的连接。有些节目没有上述所有信息,但只要至少有一个字段(标题总是可用)就没问题
模型的输出将是 13 个可用类型的概率分布,我们将把具有最高概率的类型作为模型输出,并将其与真实值进行比较。
伯特
为了训练这个模型,我们将使用 BERT 的一个预训练模型,并针对我们的问题对它进行微调。查看这篇文章,看看伯特是如何工作的。我们将使用🤗拥抱人脸库,它提供了一个获取预先训练的 BERT 模型的接口。我们将要获取的预训练模型是Bert-base-Japanese-v2,它是由东北大学的研究人员使用维基百科中的 3000 万个日语句子训练的。对于微调,我们将使用BertForSequenceClassification模型,因为这本质上是一个序列分类问题。
结果
我们在 Google Colab 的 GPU 运行时环境中训练该模型,因为 BERT 是一个繁重的模型,它在 CPU 上花费的时间明显更长。训练数据以 32 的批量提供给模型,以加速学习并防止 RAM 溢出。模型经过 10 个时期的训练:以下是这 10 个时期的损失和准确性指标:

作者图片
10 个历元似乎足够了,因为训练损失和测试精度在该点之后持平。让我们看看我们是如何预测每个标签的:

作者图片
最后,让我们检查混淆矩阵:

作者图片
看起来不错吧?
结论
在本文中,我们使用了一个 BERT 预训练模型,并对其进行了微调,用于多类文本分类,以 97%的准确率将日本电视和广播节目分类为多个流派。
我观察到的一个趋势是,随着训练数据变大,准确性也在提高。2 周的数据产生 94%的准确性,而 1 个月的数据能够产生 97%的准确性。我预计,随着更多数据的收集,该模型可以达到近乎完美的预测精度。该模型的下一步将是预测每个节目的多个流派,这将使该问题成为多类别多标签问题。
如果你在 danyelkoca@gmail.com 有任何问题/反馈,请告诉我。您可以在下面找到源代码和数据集:
数据集:https://github.com/danyelkoca/NHK/blob/main/data.csv
代码:https://colab . research . Google . com/drive/12 ezr 2 q 4 mzhe 9m _ Ppv _ RfuqnKt-g 9 yx3f?usp =共享
*本文日文版:【https://qiita.com/dannyk/items/bee0249af1f77bc416d8 *
黑客快乐!
用于数据分析的 JavaScript
随着网络开辟了合作的新领域,网络的本地语言 JavaScript 是探索数据和交流见解的最佳选择。

图片:瑞奇·罗瑟的 双摆图 。经许可使用。
关于相机的消亡有利于配备相机的移动电话,蔡斯贾维斯曾打趣说:“最好的相机是你随身携带的。”换句话说,便携性和便利性胜过分辨率、颜色、散景、等方面的技术差异。如果你想拍照,手里的相机比留在家里的相机要好。
当被问及 JavaScript 与 Python、R 或 Julia 进行数据分析时,我会想到这一点。其他语言都很棒。它们具有强大的功能,如运算符重载和多维数组、强大的数学和可视化开源库以及活跃的社区。很容易争论为什么它们中的任何一个可能比 JavaScript 更适合数据分析。
然而在我看来,语言差异无关紧要。
部分原因是 JavaScript——语言、网络平台和开源生态系统——每年都在变得更强大。浏览器供应商、标准组织、研究人员和大量全球贡献者对 JavaScript 做了大量的工作。当我们说 JavaScript 很快时,这不是侥幸;是因为人做的快。我们都从这一联合努力中受益。
因为 JavaScript 是网络语言,它可以在任何地方运行。就像你口袋里的照相手机一样,几乎每个人都有一个运行 JavaScript 的浏览器——就是你用来阅读本文的浏览器。JavaScript 支持交互式可视化、探索性解释、现场分析、模型模拟、计算艺术、游戏、测验,你能想到的……当有人分享用 JavaScript 实现的分析时,你看到的不仅仅是他们工作的静态快照;你在浏览器中运行它。通过查询数据、调整假设和提问,你可以超越被动阅读。
JavaScript 是我们有史以来最丰富的交流媒介,但由于网络的开放性,它还有更多的东西:一种可以检查和修补的媒介,用于学习和合作。浏览器开发工具允许您查看、进入甚至修改正在运行的代码。
网络让我迷上了编程。我最初是通过查看源代码学习 JavaScript 的:如果一个网页做了一些很酷的事情,我会查看它的源代码并修改它,以了解它是如何工作的,并看看我是否可以重新利用它来制作一些有趣的东西。JavaScript 的即时性和可访问性——以及无尽的可能性——使它令人陶醉。
在过去的二十多年里,激励我继续开发软件的是这样一个想法:当你在网上开发东西的时候,你也在教别人如何开发东西。我们都在这个原始的想法之汤里游泳,给予和接受创造性的灵感。
协作和交流是网络存在的原因。网络是我们工作的方式。这是我们学习的方式。这是我们分享想法的方式。正是 web 使 JavaScript 在数据分析方面表现出色(除此之外还有很多其他方面)。在网络上,我们可以一起实时编辑和运行代码,共享数据的探索性视图来回答问题,并解释概念,几乎没有摩擦。我们几乎可以做任何我们能想象的事情。
因此,我钦佩其他语言中许多强大的功能和库,但 JavaScript 因其可移植性和便利性而成为我的首选。这是分享现场代码最简单的方法,任何人都可以编辑。
当然,还有很多事情要做。JavaScript 可能不是一种用于数据分析的语言,但是这种语言可以扩展以更好地支持它。
我很乐观。JavaScript 在过去十年中有了显著的改进,增加了 async/await、arrow 函数、promises、迭代器、生成器等等。多亏了 ES 模块和像 Skypack 这样的服务,我们可能最终会看到 Node.js 和浏览器之间更容易的库互操作性(或者至少更少的 bundlers、transpilers 和 loaders 问题)。随着 WebGPU、WebAssembly 和其他标准的开发,JavaScript 的未来一片光明。(详见本·施密特的 JavaScript 和数据编程的下一个十年。)
我们还需要新的库和抽象,让我们花更多的时间思考数据,而不是纠结复杂的编程。诸如 Apache Arrow 、 Arquero 、 tidy.js 、 Observable Plot (我也参与了其中)和 Vega-Lite 等开源项目都有所帮助。

用可观察图制作的奥运会运动员体重(公斤)直方图。蓝色代表女运动员;橙色代表男性。
作为另一个用于可视化的开源 JavaScript 库 D3.js 的作者,我听说有人从其他人在网络上公开分享的作品中受到启发,开始学习可视化。有些人甚至以此为职业。
我希望有了更好的工具——特别是支持网络协作的工具——更多的人可以一起释放用数据思考的力量。
JAX 第一印象
数值计算
Python 中速度惊人的独立于硬件的数字代码

JAX 因服用类固醇而变得愚蠢
最近我一直在探索 JAX 图书馆。它是由 Google 工程师开发的用于数值计算的高性能库。目前,它是一个研究图书馆(还没有 1.0 版),不是谷歌的官方产品。然而,它正在机器学习工程师中获得牵引力。我特别感兴趣的是用 Python 编写数值密集型算法,这些算法在 CPU 和 GPU 上都非常快。
JAX 有一个与 NUMPY 非常相似的 API,尽管它不是 NUMPY 的直接替代品。JAX 包括一个 JIT(实时)编译器,它使用 XLA 来转换基于 JAX 的函数。XLA(加速线性代数)是一个特定领域的线性代数编译器。这使得代码运行速度比普通 Python 实现快 100 倍。
JAX 推广函数编程。JIT 只能编译纯函数。一个纯函数的输出仅仅基于它的输入,并且没有副作用。因此,在 JAX 编程需要一些小心。特别是,JAX 中的数组类型,称为DeviceArray,是一种不可变的数组类型。一旦创建了阵列,就不能修改。这使得编译器可以轻松地对代码进行推理,而不用担心任何副作用,并积极地对其进行优化。不可能修改数组中的单个条目。不过,JAX 以[index_add](https://jax.readthedocs.io/en/latest/_autosummary/jax.ops.index_add.html)、[index_update](https://jax.readthedocs.io/en/latest/_autosummary/jax.ops.index_update.html)和类似操作符的形式提供了功能替代方案来实现同样的功能。
JAX 的一个行 QR 分解
我不会在这里详细介绍 JAX。你可以阅读同样的优秀文档。下面我展示一个我在 JAX 实现的 QR 分解的实现。通常情况下,我们因式分解[A = QR]。因为 Python 是以行为主的,所以我按行进行因式分解[A = RQ],其中 Q 的行是正交的。使用改进的 Gram-Schmidt 过程实现因子分解。
注意在函数factor_mgs中应用的装饰器jit。它确保当函数被调用时,它被及时编译。还要注意 Q 中的一行是如何使用index_update函数更新的。使用index_add函数更新 A 中的行。
一点基准测试
我在一台 MacBook 上测试了这个功能。对一个 64x128 矩阵(具有正态分布的随机条目)的因式分解的第一次调用花费了大约 12 秒。后来下降到 300 微秒左右。当心 JAX 的异步调度。在结果数组上调用block_until_ready(),确保所有的计算都正确地完成了基准测试。第一次调用时,128x256 随机正态矩阵的因式分解需要大约 35 秒。随后的尝试减少到大约 1 毫秒。
一个逐行 QR 更新例程
像正交匹配追踪这样的算法可以通过使用 QR 更新过程来优化,其中子矩阵 A 是从字典的原子逐步[逐行]构建的。因此,A 的因式分解也可以逐行建立。下面的函数用逐行分解的矩阵 A 的第 k 行 A 更新 Q 和 R。它使用了 Gram-Schmidt 算法的一个步骤。
让我们展示一些如何使用这个更新过程的代码。
在每次迭代中,我们发送 A 的第 I 行来更新因式分解。Q 和 R 数组被更新并从 update 函数返回。由于 update 的输入参数是不可变的,因此,更新后的数组必须返回给调用者,以确保更新得到反映。XLA 编译器将确保尽可能多地重用设备数组。
注意,我们没有在更新函数定义上直接使用 jit 装饰器。函数的第四个参数 k 是一个整数,它的值在不同的调用中是不同的。从 JIT 的角度来看,它被称为静态参数。不能直接 JIT 编译。然而,在这条线上
update = jit(update, static_argnums=(3,))
我们能够指定哪些参数适合 JIT 编译,哪些必须被视为静态的。这使我们能够在这样的函数上应用 JIT。更多信息,请阅读JAX——锋利的钻头。
笔记
- 默认情况下,JAX 创建 float32 数组并执行 32 位浮点运算。如果您想使用 float64 阵列,请启用该功能。
- 如果您的函数不满足 JIT 的约束,使用它将抛出非常详细的错误。需要一些练习来学习如何编写简洁的数值算法的函数版本。
- 异步调度可能会导致错误的基准。小心确保所有的计算都已完成。
有限元分析的 JAX 实现
实践教程
和利用神经网络的高效逆问题求解

图片由作者
如果你还没听说的话, JAX 作为一个“服用类固醇的笨蛋”在网上获得了很多关注。就其核心而言,它可以被认为是对 NumPy 的替代,其中数组计算可以在可用的 GPU 或 TPU 上加速。仅此一点就值得一看,尤其是如果您有许多 NumPy 代码,您可能希望通过 GPU 加速来加速。目前, NumPy API 的大部分都是以一一对应的方式实现的,以及 SciPy 中一些最常用的函数。
加速数字仅仅是 JAX 实用化的开始。所有 JAX NumPy 数据结构都可以与大多数纯 Python 代码结合使用,以创建可以自动区分的函数。这包括计算标量函数的梯度,以及向量函数的雅可比矩阵。这些操作可以被组合以计算梯度的梯度等。自动微分功能的更多信息记录在这里。
此外,还有一个内置的实时编译器,用于编译要在 CPU/GPU/TPU 上执行的函数,并支持自动矢量化,即针对标量参数编写的函数可以很容易地跨数组映射。这些可以与前面提到的自动微分功能一起使用。
最后,还有一个与 JAX 相关的非常薄的神经网络库,称为 stax 。其他功能更全面的库,如俳句、亚麻或 Trax 都是基于 JAX 技术开发的。
在接下来的内容中,我将通过实施有限元分析(FEA)模型,然后在训练神经网络对潜在未知的本构模型进行逆解时,使用有限元残差作为目标函数的一部分,来强调 JAX 的大多数这些特征。
作为一个模型问题,我们将从一维压力扩散方程开始,该方程控制具有流体密度 ρ 和小压缩率 c 的多孔介质中的单相流体流动。

假设稳态,乘以左边的测试函数 δp ,并在域(0 ,L )上按部分积分,我们得到

在哪里

κ 为多孔介质的渗透率, μ 为流体粘度。 λ 被称为迁移率,并被假定为空间变化的。
使用伽辽金近似,即 p = Nᵢ pⱼ 和 δp = Nᵢ 对于 I,J = 1,2,… 基函数,并且将域分割成 n 个区间,我们现在有

其中对于那些在 I ᵗʰ节点上具有支持的函数,隐含了在 J 基函数上的求和。上面的右边是我们的剩余,即 R

下面,我们将使用高斯积分对这个剩余向量进行积分,并求解未知的节点压力 pⱼ 。不失一般性,我们将只考虑 Dirchelet 边界条件,即 q(x) = 0 。
虽然这个模型问题是线性的,但我们将实现 FEA 模型以使用方程的剩余形式,并使用非线性牛顿-拉夫森解算器来求解未知数,其中每次迭代的雅可比矩阵通过 JAX 的自动微分来计算。所有的计算都是以一种可以在 GPU/TPUs 上加速的方式编写的,并且是即时编译的。
下面是我们需要的导入,请注意,我们为 JAX 显式启用了 64 位浮点数,因为默认为 32 位。
下面,我们将通过 FEA 使用上面的实现来解决正向问题,以验证事情是否正常工作,并生成一些参考数据,我们将在后续的反向问题中使用。这里,移动功能是


这里我们将写我们的反问题求解器。我们将从上面的FEAProblem类继承,这样我们可以重用一些已经定义的函数。
当“已知数据”作为训练数据提供时,我们的目标函数将是有限元残差的 l ₂-norm。因为我们正在解决的问题是一个稳态问题,我们将需要向目标函数提供本构模型的端点,否则有无限个有效的解来学习仅相差一个常数的本构模型。如果我们把这种技术扩展到与时间有关的问题,我相信可以避免提供边界约束的需要。
我们将使用jax.experimental.stax模块中的一些函数,只是为了使神经网络的构建更容易。我们这里的最小化器将使用来自jax.scipy.optimize.minimize的二阶"BFGS"方法。
这里,我们假设我们的数据是在有限元模型的节点处提供的,但是通过有限元形状函数在任何给定的空间位置评估残差,可以很容易地概括这种限制。
下面我们将使用前面的有限元解生成的数据来测试我们的反问题求解器。首先,我们定义我们的神经网络架构。这是一个相当简单的函数,因此我们不需要大型和/或复杂的神经网络。这里,我们有一个只有 4 个节点的输入层和一个 tanh 激活函数,它提供给单个节点输出。更复杂的架构也可以工作,以更多的计算成本产生相同的结果。
我们还需要定义层Dense64,它与stax.Dense相同,但被初始化为使用 64 位浮点,以与我们在 FEA 残差计算中的数据结构保持一致。
现在我们实例化模型并求解逆问题,即训练网络。我们必须提供本构模型的端点。假设问题是抛物型的,那么反问题就有无穷多个解(它们都有相同的形状,但是有一个恒定的比例因子)。我们可以通过考虑一个依赖于时间的问题并提供依赖于时间的训练数据来消除这种限制,我们将把它留给未来的工作。
在区域范围内绘制神经网络函数,并与参考进行比较,我们可以看到逆解算器已经很好地“学习”了迁移率函数。

只是为了验证,我们将使用我们的神经网络作为我们的正向有限元解算器中的迁移函数,以证明产生的压力也是准确的。

这种方法相对于例如基于物理学的神经网络的主要优势在于,我们仅“学习”了本构模型,即迁移率函数,而不是具有所提供的边界条件的偏微分方程的解。相反,我们依靠我们的有限元实现来计算解决方案。这意味着我们现在可以使用我们“学到的”本构模型来精确地解决不同边界条件的问题。

最初发表于【https://johnfoster.pge.utexas.edu/blog/jax-fea/】。
使用 GPT 的爵士乐一代

亚历克斯·萨莫拉的爵士之夜
实践教程
使用 GPT 和钢琴卷帘窗编码方法生成爵士音乐
生成式预训练转换器或 GPT 模型在处理自然语言处理(NLP)任务时取得了惊人的结果。然而,该模型结构并不是 NLP 所独有的,并且已经被用于解决其他问题,例如时间序列预测或音乐生成。在这篇文章中,我将分享我使用一个非常简单的 GPT 模型来创作音乐(特别是爵士乐)的方法。
目录
- 背景
- 钢琴卷帘窗编码方法
- 数据预处理和分析
- GPT 模型
- 培养
- 推理
- Web 应用程序
- 结论
背景
音乐生成任务已经在过去使用深度神经网络解决,例如 RNN 特别是 LSTM 或 CNN 以及最近的 Transformer。在某种程度上,解决这个问题的方法很大程度上受 NLP 的影响,因为歌曲中的音符和段落中的文本之间的结构非常相似。与文本相比,处理音乐的主要区别在于信息编码步骤,我们将在后面探讨。
此外,我选择爵士乐的原因是因为它的不可预测性(爵士乐也是我最喜欢的音乐类型之一)。正如他们常说的,在爵士乐中没有“错误”的音符,特别是在即兴创作中,我很好奇当在爵士乐数据集上训练时,预测的音乐听起来会是什么样子。对于这个项目,我们将只关注使用钢琴乐器产生爵士乐。
所有的预处理和培训笔记本都可以在最后找到!
钢琴卷帘窗编码方法
通常,midi 对象包含相当多的信息,根据您使用的库,您可以从 MIDI 文件中提取不同的数据或相同的数据,但格式不同。另一方面,MIDI 音符是非常标准的,因为它是 MIDI 乐曲的组成部分。它包含以下信息:速度,音高,开始时间,结束时间。
就像我之前提到的我们如何转换 NLP 模型来解决音乐生成任务,我们需要以一种相对类似于 NLP 中单词编码的方式来编码这些 MIDI 音符信息(NLP 通常使用基于索引的编码来嵌入单词)。然而,对于 MIDI,我们需要表现每个音符多达 4 个特征,其中也包括时间特征。

基于索引的单词编码和嵌入— 文本编码:综述 [1]
为了解决这个问题,我们决定将 MIDI 转换为钢琴卷帘窗格式,采样间隔为每 16 个音符。因此,钢琴卷首是大小为(song_len,128)的 2D 数组,其中 song_len 是歌曲中第 16 个音符的总数,128 是 MIDI 歌曲中可能的音高数。

MIDI 流(左)转换为钢琴卷帘窗阵列(右)的示例
这种数据编码方法表示每个恒定时间间隔的音符,因此,允许我们将整首歌曲表示成一个紧凑的 2D 数组。从这里,我们可以实现一种类似的单词编码方法,即基于索引对每个音高组合进行编码,然后将它们送入嵌入层。
我们决定不包括速度特征,因为这将导致我们的音高组合词汇爆炸。第 16 个音符是最佳的音程,因为它可以足够准确地表现音乐细节,同时也可以防止我们的钢琴卷阵列变得太长。
理解了这种方法之后,让我们开始研究代码吧!
数据预处理和分析
对于我们的数据集,我们选择了 Doug McKenzie 爵士钢琴数据集。虽然这个数据集中只有大约 200 首 MIDIs,但它包含了各种各样的流行爵士歌曲,而钢琴部分通常是干净的,连贯的,很少有缺失的部分。
由于数据集中的所有歌曲都有不同的调号,并且在不同的 BPM 中播放,因此我们进行数据预处理,以便使这些特征标准化。这个标准化步骤很重要,因为它不仅允许模型更好地理解歌曲的结构和模式,而且有助于减少我们的模型稍后的词汇量。
我们使用 Pythonpretty-midi和 music21 来辅助数据解析和处理步骤。为了提取钢琴部分,我们过滤掉了包含最多音符的流(因为这是钢琴流的常见情况)。extract_midi_info()函数将帮助我们获取需要偏移的调号以及钢琴卷帘窗的 bpm。
preprocess_midi()函数将帮助我们使用 pretty_midi get_piano_roll 函数获取钢琴卷帘窗数组。
对于预处理的最后一步,我们遍历数据集中的所有 MIDI,解析、预处理并将钢琴卷帘窗数组保存为。npy 格式。
GPT 模型
对我们的数据进行编码后,我们现在可以将其输入到 GPT 架构中,以训练一个自回归模型。如果你不太确定 GPT 是如何工作的,我推荐你读一下杰伊·阿拉姆马的这篇博文【2】,它非常详细,见解深刻,我从中学到了很多。
简而言之,GPT 仅利用变压器架构的解码器模块,并将这些解码器模块堆叠在一起,以增加网络的复杂性。

GPT 架构由堆叠的变压器解码器模块组成— 通过生成式预训练提高语言理解
以下 GPT 模型的代码引用自 Apoorv Nandan 用微型 GPT【3】生成的文本。
对于令牌和位置的嵌入,我们使用了正弦和余弦函数。

位置编码—你所需要的只是注意力【4】
随意掩饰的自我关注
变压器组
最终模型。
模型摘要:
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 600)] 0
_________________________________________________________________
token_and_position_embedding (None, 600, 128) 5120000
_________________________________________________________________
transformer_block (Transform (None, 600, 128) 99584
_________________________________________________________________
transformer_block_1 (Transfo (None, 600, 128) 99584
_________________________________________________________________
transformer_block_2 (Transfo (None, 600, 128) 99584
_________________________________________________________________
dense_18 (Dense) (None, 600, 40000) 5160000
=================================================================
Total params: 10,578,752
Trainable params: 10,578,752
Non-trainable params: 0
培养
为了训练我们的模型,我们首先需要从数据集创建训练输入和输出。因此,我们首先将每个独特的音高组合分配给一个整数,如前一部分所述。对于我们的词汇表,我们只考虑前 40000 个最常用的音符组合,包括未知和填充标记。最后,我们对输入数据的钢琴卷首数组进行标记。
我们还将创建我们的定制生成器。该模型的输入将是固定 sequence_length 的符号序列,输出将是相同长度但向右移动一个符号的序列。对于每个时期,我们将遍历数据集中的所有歌曲,在每首歌曲中,我们选择一对输入和输出序列在随机位置进行训练。如果需要的话,我们也可以使用填充。
终于准备好训练了!我们实验了 1500 个时期,32 个批量大小和 600 个序列长度。

推理
为了预测一首歌曲,我们需要给它输入一些开始音符,并填充到与训练序列长度相同的大小,即 600。
得到钢琴曲后,我们可以接着转换成 MIDI。这里有几个推理样本,前 5 秒或 10 秒是种子。
这首歌已经播了 10 秒了
网络应用
我和我的团队还创建了一个 web 应用程序来展示我们的建模能力。我们将 React JS 用于 web 应用程序,将 Flask 服务器用于推理任务。为了部署该产品,我们使用 Google 云服务来托管 React web 应用程序和 Flask 推理服务器。

这里有一个 web 应用程序的简短视频演示,不幸的是,由于我的谷歌云平台信用已经用完,应用程序本身不再可用:(
web 应用程序的演示

我们的 web 应用程序的快照
结论
尽管只有大约 200 首歌曲的小数据集,我们还是设法开发了一个可以很好地预测爵士音乐的模型。然而,在评估过程中仍然有一些过度拟合的迹象,尽管我们试图增加辍学率,但我们相信这个问题会在更大的数据集上得到解决。
最后,这是我的第一个数据科学项目,它真正教会了我这个项目是为计算数据科学模块而做的。我们这个团由许鞍华、肖恩·林、西德哈斯·普拉文和梅组成。特别感谢我的团队成员和我的教授 Dorien Herremans 和 Soujany 茯苓的帮助和指导。
源代码:
参考文献: 【1】西里坡,罗莎丽亚。“文本编码:回顾”,2019 年 11 月 21 日。https://towards data science . com/text-encoding-a-review-7c 929514 cccf。
[2]阿拉马尔,杰伊。"图解 GPT-2(可视化变压器语言模型)."图解 GPT-2(可视化变压器语言模型),2019 年 8 月 19 日。http://jalammar.github.io/illustrated-gpt2/.
[3]南丹,阿波洛夫。" Keras 文档:用微型 GPT 生成文本."用微型 GPT 生成文本,2020 年 5 月 29 日。https://keras . io/examples/generative/text _ generation _ with _ miniature _ GPT/。
[4]瓦斯瓦尼、a、n .沙泽尔、n .帕马尔、j .乌兹科雷特、l .琼斯、A. N .戈麦斯、l .凯泽和 I .波洛苏欣。“你需要的只是关注。arXiv 2017。” arXiv 预印本 arXiv:1706.03762 (2017)。
詹金斯为 CI 死了:为什么人们讨厌它,有什么替代方案?
如何自动建立你的 Docker 图像;案例研究。

艾米莉·法里斯在 Unsplash 上拍摄的照片
Jenkins 是一个独立的、开源的自动化服务器,提供了用于 Windows、Mac OS X 和其他类似 Unix 的操作系统的软件包。
如果你访问该项目的登陆页面,它会告诉你 Jenkins 是领先的开源自动化服务器,拥有数百个插件来支持任何项目的构建、部署和自动化。
这种说法可能是对的,但这并不意味着 Jenkins 提供了一种简单直接的方法来实现这一切。相反,它提供了数百个插件,如果你想完成任何事情,你都需要设置这些插件,这使得这个项目既通用又复杂。
在这个故事中,我们看到了为什么如果你想在 2021 年建立一个持续集成(CI)管道,Jenkins 不是合适的选择,以及有什么替代方案。如果你有任何疑问,可以在评论区开始讨论!
Learning Rate 是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。订阅这里!
自动构建您的 Docker 图像
我相信很多阅读这篇文章的人都喜欢詹金斯。我相信你们中的很多人现在都很愤怒。也许你已经花了几个月的时间来学习 Jenkins,并真正深入到了它的内部。如果你处在类似的位置,我可以理解你为什么还不准备放弃。
为了试图说服你,我将用一个简单的例子。今天我将介绍最流行的 CI 用例:如何自动化构建和推送 Docker 映像的过程。
然而,这不是一个关于如何用 Jenkins 构建和推送 Docker 映像的教程。相反,我将只提供一个高层次的观点。因此,假设您已经有了一个将代码推送到 Github 的存储库,下面是实现最终目标所需的步骤:
- 安装 Jenkins: Jenkins 通常作为一个独立的应用程序在它自己的进程中运行,带有内置的 Java servlet 容器/应用服务器(Jetty)。但是,您也可以使用官方 Docker 映像在容器中运行 Jenkins。
- 与 GitHub 集成:你可以通过浏览器(通常在
localhost:8080上)访问 Jenkins 并创建一个新项目。您应该指定 GitHub 存储库 URL 地址,何时触发构建,以及目标命令。 - 安装 Docker 插件:要构建图像并将其推送到存储库(例如 Dockerhub),您需要安装一个新的插件。例如,您可以安装 Docker 插件、Docker 构建步骤和 CloudBees Docker 构建和推送插件。
- 配置 Docker 插件:您应该在 Jenkins UI 中指定一个新的构建步骤,利用新安装的插件。此外,您应该指定您想要将图像推入的注册表、图像名称和标记以及您的凭证。
为什么这样不好?
现在我们已经看到了这个过程,你可能会说这还不算太糟。只需四步。然而,有些步骤并不容易跨越:
- Jenkins 实例通常太复杂。这意味着组织需要一名 Jenkins 专家来安装、维护和保护实例。
- 专家成为瓶颈。作为开发人员,您依赖 Jenkins 专家或管理员来创建新项目、构建、发布等。这很快成为一个漫长的过程。
- 自助服务寻求者将创建新的、不安全的 Jenkins 实例来解决专家瓶颈问题。此外,他们还会不经测试就安装新插件,引入漏洞。
- 通常,在开始使用 Jenkins 之前,你需要安装大量的插件。不幸的是,这使得实例过于复杂,难以导航,而且 Jenkins 控制器的速度也慢了下来。
- 您可能不希望在自动化工具上做这么多手工工作。Jenkins 很难有效地扩展。并不是所有的插件都受
Jenkinsfile支持,所以一个 Jenkins 实例很难在没有手工操作的情况下备份。此外,数据库只是磁盘上的 XML 文件,这使得纵向扩展或横向扩展或执行高可用性升级成为一场噩梦。 - Jenkins 需要一台专用服务器(或几台服务器)来运行。这导致了额外的费用。通常情况下,一个组织需要有一个 DevOps 团队专门负责 Jenkins。
有什么选择?
对于 CI,也许不仅仅是 CI,我更喜欢使用 GitHub 动作。那么,如何用 GitHub 动作构建和推送 Docker 图片呢?让我们看看步骤:
- 设置:在项目的根文件夹中创建一个新文件夹。把它命名为
.github/workflows。 - 配置:在您创建的
workflows文件夹中添加一个新的 YAML 配置文件。这个文件看起来有点像这个。一系列步骤,每一步都做一件简单的事情。 - 认证:将你的注册中心(例如 Dockerhub)的证书作为一个加密的秘密添加到你的项目中。
- Run:开始这个过程所需要的只是将新的代码提交到 GitHub。
最重要的事?无需安装、配置、维护、升级或修补。一切都运行在 GitHub 服务器上,你不必在意。此外,有了 GitHub marketplace (把它当成 Jenkins 插件的替代品),你几乎可以做任何事情。
结论
Jenkins 是领先的开源自动化服务器,拥有数百个插件来支持任何项目的构建、部署和自动化。
然而,Jenkins 的方法并不是建立 CI 渠道的简单直接的方法。安装、维护、插件、安全,等等,使得过程变得缓慢,制造瓶颈,并引入漏洞。
这个故事展示了使用 Jenkins 和 GitHub 操作自动构建和推送 Docker 图像所需的步骤。在我看来,使用像 GitHub Actions 这样的工具就像用 Jenkins 的方式一样。你有什么看法?
关于作者
我叫 Dimitris Poulopoulos ,是一名为 Arrikto 工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据操作的帖子,请关注我的 Medium 、 LinkedIn 或 Twitter 上的 @james2pl 。
所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。
拼图玩具人工智能从 A 到 Z
使用基本的人工智能工具组装任意现实生活中的谜题

作者图片(由卡斯特兰拼图公司的“北极冰层下的生活”制作)
介绍
自人工智能早期以来,我们已经看到了处理拼图难题的多种尝试。然而,爱好者主要集中在特定的方面:只有方瓦,只有非扫描,单色等。
在这里,我们来看一下全面的方法,这种方法在非常简单的同时处理了整个问题。这项工作的想法是展示我们如何能够利用今天的基本人工智能工具来处理拼图游戏解决方案的所有方面。
我们将使用 Google Colab 和 Python 来完成这项工作,这样每个人都能够轻松地理解和复制它,而无需任何特殊的软件。

“用 300 行代码在 60 秒内解决”(图片由作者提供)
概观
我们将解决 15 块瓷砖的难题。对于计算机来说,这是一个复杂的问题,因为复杂性主要不是来自瓷砖的数量,而是来自瓷砖的几何形状。我们的拼图是不均匀的圆形,并且有扭曲的弯曲边缘。
提出的方法是为了证明我们可以不局限于任何特殊类型的瓷砖。反之亦然,这个想法是用任何几何形状的瓷砖来解谜。
我们将浏览 300 行 Python 代码。不过,它只涵盖了 3 个主要步骤:
- 图像处理。它处理如何从扫描中提取瓷砖。
- 匹配。这是如何找到匹配的瓷砖以及匹配方式的核心部分。
- 组装。这是一个最终的算法,把瓷砖拼凑成一个整体的图像。
数量少得惊人的基本模块将足以解决我们的彩色拼图。
图像处理
我们将零散瓷砖的扫描图像作为输入。它必须是一个良好的扫描没有明显的扫描仪伪影,如彩色条纹或黑边。我的扫描是 A4 格式,重采样为 727 x 1000 像素,大约相当于 90 dpi。
首先,我们将图像绘制封装到函数中,以进一步简化代码。我们想关闭坐标轴,为单通道图像切换到“灰色”色图,等等。
然后,我们加载一个扫描,并使其 RGBA 进一步参与透明度维度。

作者图片
我们可以看到天蓝色背景上的彩色瓷砖。为了能够对瓷砖做任何事情,我们必须首先检测它们。这是一个单一的图像,我们必须把它变成 15 个独立的瓷砖。检测单色背景上的对象的一种可能方法是自适应阈值处理。我们将对我们的图像应用adaptiveThreshold()工具,以便从背景中分离瓷砖。GaussianBlur()是可选的,但在这里是必要的,因为有些瓷砖有白色边缘,这些边缘与背景融为一体,产生我们必须填充的裂缝。

作者图片
这看起来不错。尽管如此,我们也无能为力。我们需要的是一个清晰的二值图像,其中每个像素要么是瓷砖,要么是背景。因此,我们将使用 OpenCV 轮廓检测和填充技术来完成这个简单的技巧。为了抑制由绘画形成的额外轮廓,我们按照长度降序对检测到的轮廓进行排序,并取 15 个最大的轮廓(手动,因为为了简化代码省略了自动化)。

作者图片
还不好。我们可以看到瓷砖有粗糙的边界和由原始扫描图像中的阴影形成的突出尖峰。抑制尖峰的典型方法之一是中值滤波,即将每个元素转换为周围元素的平均样式。换句话说,如果你的同伴都很矮,而你很高,你也会变矮:)。在median_filter()之后,我们通过画一个黑色的轮廓来修整我们的形状。这是为了去掉上面模糊操作产生的阴影和多余的像素。

作者图片
嗯,那很好!现在图像是二进制的:瓷砖对背景,没有半色调。我们可以将它叠加在原始图像上,一个接一个地提取彩色瓷砖。另一个聪明的工具boundingRect()将帮助我们从大图像中切割出想要的区块。它的作用是检测包含一个形状的最小包围盒。

作者图片
我们终于拥有他们了!15 块彩色瓷砖,位于 300 x 300 图像的中心,背景透明。前奏结束了,该是主幕了!
相称的
匹配的关键思想是拿一对瓷砖,在它们的轮廓中寻找相似的部分,沿着那些部分比较颜色,然后尝试锁定那些部分而不丢失像素。
我们从重新调整我们的瓷砖开始。让我们把它们放在 1400 x 1400 的画布上,这是我们将用来组装整个拼图的画布。这只是一个技术操作,没有任何秘密含义。
在匹配算法中将使用四个辅助函数。所有这些都基于基本的 2D 几何学:
getColors()被设计成沿着图像的子区域拍摄彩色像素。在子区域的每 3 个点上,我们取 2 个点与子区域的内部和外部正交,深度为 3 个像素(因为我们不知道瓷砖的确切位置),将颜色转换为 HSV 并添加到列表中。putOnAnvil()将输入图像作为 NumPy 数组,并使用 PIL 方法对其进行偏移/旋转,这只是一个技术问题。我们使用它来旋转和重新定位画布瓷砖,将其子上下文中心放入图像中心,以与匹配的瓷砖融合。- 在组装或装配过程中,当我们移动和旋转拼图和拼块时,
rotatePoint()有助于跟踪拼块中心。 reScale()又是一个技术上的东西,用来把点坐标从平铺图像的(300,300)平移到拼图画布的(1400,1400)。在两个空间中工作是必要的,以节省时间而不处理额外的零像素。
所有进一步的代码请记住,OpenCV 工作在(x,y)坐标域,而其他模块是(y,x)。因此,我们将不得不不断地交换和翻转。
在我们深入研究匹配算法之前,让我们先来看看我们将使用的一些主要概念。当我们进行匹配时,我们会谈到图块 A 和 B、子区域和子区域中心(pointA 和 pointB)、边界矩形和图块中心、最小面积矩形及其中心(cA 和 cB)和角度(angleA、angleB)、typepointA 和 typepointB 来说明它是 tab 还是空白、画布中心(“anvil”)以及我们用于颜色匹配的近子区域点。

关键概念(图片由作者提供)
然后我们来看匹配算法本身。看起来很吓人。尽管如此,结构还是很简单。我们用 OpenCV findContours()提取两块瓷砖的轮廓。然后,我们取图块 A 的小子图,并将其与图块 b 的小子图进行比较。子图是通过主轮廓的滚动和切片得到的。
我们一个接一个地经历 3 个匹配循环(轮廓匹配、颜色匹配和预拟合)。名字是不言自明的,而想法是不断减少匹配的数量,通过某些标准过滤掉不好的。例如,两个外形相似的轮廓,可能在颜色上完全不相容,所以它们甚至不会到达试衣间。此外,试衣间非常耗时,因此我们希望最少数量的匹配能够通过筛选。
让我们来看看每种情况下都发生了什么:
- 轮廓匹配。这是用公开的简历
matchShape()完成的。虽然对于曲线来说不是 100%好(我更喜欢用我的方式对待那些),我们在这里使用它来简化故事。在匹配之前,我们检测子上下文类型(标签或空白)和一般外观(使用minAreaRect())以节省时间和避免明显的失败。正确检测旋转角度需要两个辅助标志(“共线”和“共线”)。这是因为minAreaRect()只返回象限 III 中的(0,-90°)角度,而matchShapes()根本不返回任何角度。尽管如此,还是有出路的。 - 配色。它遍历过滤后的表单匹配,沿着每个子上下文获取色点,并将它们与
fastdtw()距离度量进行比较(在这里解释为)。关键是我们必须将颜色转换成 HSV 格式。拼贴的原始 RGB 可能会产生误导,因为 130 与 190 一样接近 160,交换两个通道可能会给你相同的度量,但颜色完全不同。HSV 会做得更好。 - 预装配。这是一个直接尝试融合瓷砖,使用火柴达到这一水平。我们取两个画布块,将它们的子上下文中心叠加在画布的中心,旋转适当的角度,并计算度量。如果图块匹配良好,我们将拥有最小的像素损失(图块不重叠)和最小的结果对轮廓长度(关节边相互贴在一起并隐藏起来不被测量)。一个更健壮的版本包括子区域的叠加和交集比率的计算(此处省略)。
匹配算法的参数化将需要从难题到难题的手动调整:
LENGTH。这里的子节点长度是 160,大致接近最小节点长度。对于拼图来说,它必须是可变的,因为拼图的大小变化很大。PRECISION。这只是一个粗略的过滤器,以消除明显的不匹配。精度允许在子区域边界矩形的尺寸上有差异。它必须非零,因为图像处理不是 100%准确。STEP_A、STEP_B。步骤只是我们用来获取另一个分包合同的转移。值 1 是一个梦,但它会永远循环,你必须寻找妥协。MAX_*.这些参数决定了相应指标的上限。它们主要取决于分辨率和子区域长度。
现在我们在一个循环中为所有可能的配对运行匹配算法。105 对中每对大约 0.5 秒。在这里不到一分钟,但对于 128 块 8192 对的拼图来说,需要一个小时。因此,要快速处理大型拼图,我们需要优化(numba、并行线程)以及算法技巧,如早期拼图分组、预组装等。
得到的匹配列表包含关于图块编号、滚动值、子区域中心坐标、旋转角度和度量的信息。如果没有满足我们限制的匹配,我们的结果将是空的。我们也可能会错过一些比赛,瓷砖可能会在组装过程中锁定。
当我们的匹配算法从图块 0 转到图块 14 时,我们只记录升序对,如(1,5)、(2,6)等。但是,如果(1,5)匹配,那么(5,1)也匹配。这就是为什么我们把比赛展开成一个完整的列表,翻转成对。最后,我们按照配对和匹配度量对匹配列表进行排序,得到如下结果:

作者形象
装配
组装的关键思想是通过匹配找到并在画布上有一个图块,尝试将 B 图块锁定到它,根据匹配信息移动和旋转拼图和添加的图块。
也就是说,我们通过匹配子块的中心来获取匹配块,在画布中心将一个点叠加在另一个点上,并按适当的角度旋转块。为了保持对旋转和定位的控制,我们总是在画布的中心做这个动作。我们可以认为这是把每对新的中心放在画布的中心,就像放在铁砧上融合一样。这使我们能够在装配过程中正确旋转和跟踪轮廓和图块中心坐标。
我们将使用一个有用的函数来简化组装算法。当我们旋转拼图和瓷砖时,它的作用是在画布上记录瓷砖的中心和角度。
我们的拼图有 22 个关节,但是匹配算法返回了 37 个匹配。这意味着我们必须在装配过程中过滤正确的零件。我们通过控制像素损失来实现这一点。如果我们向拼图中添加一个新的图块,它出错并部分重叠,这将导致颜色像素的丢失。当像素损失低于某个比率(在我的例子中是所添加图块的 f.i. 10%)时,我们接受该图块,如果它更高——可能我们的匹配是错误的,我们必须尝试另一个。
为了简单起见,我们在这个算法中放弃替换瓷砖,最多只做 10 次尝试来组装拼图,或者在画布上达到 15 个瓷砖时退出循环。这意味着,如果我们放错了瓷砖,或者把正确的瓷砖放错了,我们就不能回去重新做。然而,对于这个难题,这就足够了。

作者形象
嗯,很管用!虽然…图像看起来有点破旧。这是由于多次旋转过程中信息失真造成的。此外,不要忘记我们从一开始就在低分辨率下工作。至少,我们可以看到水下的人们在微笑:)
现在,我们找到了解决方案,可以用找到的匹配项标记原始切片。对于每一对,我们在锁的位置画出一个特定颜色的圆圈,并在两者里面放一个匹配的数字。

作者形象
如您所见,并非所有制表符和空格都已标记。这是因为 14 把锁就足够组装这个拼图了。其他人会自动锁定。
结论
在本文中,我们已经经历了拼图游戏解决的整个周期。它清楚地表明,我们可以做到这一点,而无需深入学习,简单地将算法逻辑与当今的高性能人工智能工具相结合。
许多解释和一些算法(如检测瓷砖的数量,在组装过程中更换瓷砖等)被删除,以使故事简短,并保持重点放在总路线上。
虽然这不是最终的方法,但它是全面的,并显示了我们可以使用当今简单的负担得起的工具来处理现实生活中的问题的方法。
学校几何和基本 Python AI 的知识恰好足以解决一个问题,这个问题就在昨天还令人头疼。
在:GitHub \ Jigsaw-Puzzle-AI找到源文件
金贾+ SQL = ❤️

用于可维护、可测试数据分析的宏
SQL 是分析师的面包和黄油。它强大、富有表现力、灵活——但是一门语言给你的力量越大,你就有越多的方式搬起石头砸自己的脚。
更好的抽象可以帮助我们做到这一点。如果我们能够抽象出我们一直使用的代码,那么我们只需要编写并检查代码一次。有了正确的抽象,您还可以开始考虑单元测试 SQL,这在专业分析中做得不够,但应该是标准实践。
Jinja 宏 特别适合对 SQL 进行抽象——如果您决定为您的数据组织使用类似 Fishtown Analytics 的 数据构建工具——那么我们将专门探讨如何使用 Jinja。但是这里的经验应该是通用的,超越任何一个特定的工具。
你可以跟随我在 这个 Git repo 中包含的一些玩具用例。本文中与回购中的文件相对应的代码片段将以类似如下的内容开头:
-- path: macros/volume_by_demographic.sql
用例#1:参数化查询
这里有一个场景:假设您有一个星型模型,有一个users表链接到各种其他表,如purchases、sessions、marketing_pushes等。

来源:作者
你可能想知道purchases的销量是如何随着人口统计而变化的。该查询可能如下所示:
-- Get purchase volume by demographic
select
users.age_group,
users.region,
count(*) as purchase_volume
from purchases
join users on purchases.user_id=users.user_id
group by 1,2
到目前为止很简单。但是,如果我们希望用户会话的数量减少相同的维度呢?
我们会做:
-- Get session volume by demographic
select
users.age_group,
users.region,
count(*) as session_volume
from sessions
join users on sessions.user_id=users.user_id
group by 1,2
这是很多重复的代码!当我们可以用一个抽象来编码关于数据模型的基本假设时,为什么要写同样的东西两次呢?
让我们写一个宏。这些宏片段具有用粗体表示的宏逻辑,当调用宏时,变量名在查询的最终“呈现”中被替换为字符串值。为了更好地理解语法,查看一下 Jinja 模板设计器文档 。
-- path: macros/volume_by_demographic.sql**{% macro volume_by_demographic(entity_table, count_col_name) %}**select
users.age_group,
users.region,
count(*) as **{{ count_col_name }}**
from {{ entity_table }}
join users on **{{ entity_table }}**.user_id=users.user_id
group by 1,2**{% endmacro %}**
使用这个宏,我们对购买量和会话量进行的最后两个查询可以通过简单的调用完全呈现出来:
-- path: models/purchase_volumes.sql**{% from 'volume_by_demographic.sql' import volume_by_demographic %}**-- Get purchase volume by demographic
**{{ volume_by_demographic('purchases', 'purchase_volume') }}**
或者:
-- path: models/session_volumes.sql**{% from 'volume_by_demographic.sql' import volume_by_demographic %}**-- Get session volume by demographic
**{{ volume_by_demographic('sessions', 'session_volume') }}**
在 repo 中尝试一下,看看值是如何交换进来以呈现最终查询的!
>> ./render.py models/session_volumes.sql
现在,如果有一个业务范围的决定,即“人口统计”的概念不应该只是年龄组和地区,因为“地区”太粗略,无法做出任何可操作的决定,会怎么样?
你可以直接回到宏代码中,把“区域”改成“州”或者什么的,并保持宏的最终调用点不变。你只需要在一个地方做出改变。
你所做的抽象是为业务分析实现一个接口,在这里你可以交换后端实现,让你的分析逻辑的消费者不受影响——留给你一个 SQL 代码库,它很容易随着动态需求而改变。
正如我们将会看到的(我们已经犯了一些错误),构建接口是棘手的,但是从某个地方开始总比没有接口好。
用例 2:可组合查询
SQL 允许您在子查询或公共表表达式中嵌套逻辑(甚至是递归的),让您可以无限地将一组记录与另一组记录链接起来。
像这样的查询可能会令人毛骨悚然,即使是我们正在探索的完美的玩具示例。例如,假设我们希望将每个人口统计组的会话量与购买量相关联,以了解每次会话的预期购买量。
在原始 SQL 中,这可能看起来像:
with purchase_volumes as (select
users.age_group,
users.state,
count(*) as purchase_volume
from purchases
join users on purchases.user_id=users.user_id
group by 1,2),session_volumes as (select
users.age_group,
users.state,
count(*) as session_volume
from sessions
join users on sessions.user_id=users.user_id
group by 1,2)-- Get purchase/session ratios for each age_group*state combinationselect
age_group,
state,
purchase_volume / session_volume as ratio
from purchase_volumes
join session_volumes
on purchase_volumes.age_group=session_volumes.age_group
and purchase_volumes.state=session_volumes.state
这是一大堆代码,我们声明的每一项都是潜在的出错点。 可证明的事实是 复杂性使得像基于 SQL 查询的决策过程这样的系统对小错误更加敏感,这一点在专业分析领域经常得到证实。
抽象化缩小了 bug 的表面区域。上面的查询可以归结为:
*-- path: models/purchase_sessions_ratio.sql-- Get purchase/session ratios for each age_group*state combinationselect
age_group,
state,
purchase_volume / session_volume as ratio
from (
**{{ volume_by_demographic('purchases', 'purchase_volume') }}** ) p
join (
**{{ volume_by_demographic('sessions', 'session_volume') }}** ) s
on p.age_group=s.age_group
and p.state=s.state*
更不用想了!
现在,我们可以只关注转换率逻辑,同时相信基本的体积计数逻辑是正确的。更少的移动部件=更少的破碎系统。
试试在 回购 :
*>> ./render.py models/purchase_sessions_ratio.sql*
用例 3:可扩展的组合
抽象让你比我们已经建立的更加灵活。如果我们不看会话与购买的比率,而是看营销推送与会话的比率,以及和营销推送与购买的比率,会怎么样?
我们可以对我们处理的最后一个 SQL 块进行宏化,这样它就可以将不同的表引用作为参数!我们将有一个numerator_vol_ref来指定哪个表的计数应该是输出比率的分子,还有一个denominator_vol_ref来指定相同的分母。
*-- path: macros/volume_ratio.sql**{% macro volume_ratio(
numerator_vol_ref,
denominator_vol_ref
) %}**select
age_group,
state,
N / D as **{{ numerator_vol_ref }}_over_{{ denominator_vol_ref }}**
from (
**{{ volume_by_demographic(numerator_vol_ref, 'N') }}** ) p
join (
**{{ volume_by_demographic(denominator_vol_ref, 'D') }}** ) s
on p.age_group=s.age_group
and p.state=s.state**{% endmacro %}***
现在,如果我们想再次计算购买-会话比率,我们可以问:
*-- path: models/purchase_sessions_ratio_2.sql**{%- from 'volume_ratio.sql' import volume_ratio -%}**-- Get ratio of purchases to sessions for a demographic group
**{{ volume_ratio('purchases', 'sessions')}}***
但是,如果我们想查看漏斗中的一系列步骤,并且这些步骤是动态的,那该怎么办呢?
输入:Jinja 控制流。我们可以在 SQL 模板中执行循环和 if-conditionals,这是一个超能力。**
让我们创建一个引用最后一个逻辑块的宏,但是让我们将一个denominator_vol_ref和一个numerator_vol_ref的整个数组作为参数。
*-- macros/volume_ratios.sql**{% macro volume_ratios(numerator_vol_refs, denominator_vol_ref) %}**select
age_group,
state,
**{%- for ref in numerator_vol_refs -%}** **{{ ref }}**_over_**{{ denominator_vol_ref }}**
**{%- if not loop.last -%}**,**{%- endif -%}**
**{% endfor %}**
from
(**{{ volume_ratio(numerator_vol_refs.0, denominator_vol_ref) }}**)
as base
**{% for ref in numerator_vol_refs %}**
**{% if not loop.first %}**
join
(**{{ volume_ratio(ref, denominator_vol_ref) }}**) as **{{ref}}**_r
on **{{ref}}**_r.age_group=base.age_group
and **{{ref}}**_r.state=base.state
**{%- endif -%}**
**{%- endfor -%}****{% endmacro %}***
那里发生了很多事。让我们来分解一下我们正在做的一些事情。
在这个街区:
*select
age_group,
state,
**{%- for ref in numerator_vol_refs -%}** **{{ ref }}**_over_**{{ denominator_vol_ref }}**
**{%- if not loop.last -%}**,**{%- endif -%}**
**{% endfor %}***
我们将遍历表引用的列表,我们将使用这些表引用的人口统计量作为比率分子。if not loop.last条件语句确保我们在除最后一列之外的每个列名后面都加上一个逗号,以得到格式良好的 SQL。
这为我们提供了一组对子查询中公开的列名的引用。
在这个街区:
*from
(**{{ volume_ratio(numerator_vol_refs.0, denominator_vol_ref) }}**)
as base*
我们使用数组中的索引.0从第一个分子表引用创建一个体积比率子查询,并将该子查询别名为base。
在最后一块:
***{% for ref in numerator_vol_refs %}**
**{% if not loop.first %}**
join
(**{{ volume_ratio(ref, denominator_vol_ref) }}**) as **{{ref}}**_r
on **{{ref}}**_r.age_group=base.age_group
and **{{ref}}**_r.state=base.state
**{%- endif -%}**
**{%- endfor -%}***
我们再次遍历分子表引用列表。因为我们已经使用了第一个表引用来创建base子查询,所以我们忽略第一个带有if not loop.first条件的子查询。
然后,我们针对每个分子表引用的新的volume_ratio子查询以编程方式连接base,最终暴露出我们想要的所有列。
我们可以在文件中调用宏:
*-- path: models/example_funnel.sql**{%- from 'volume_ratios.sql' import volume_ratios -%}****{{ volume_ratios([
'purchases',
'sessions',
'supportTickets'
],
'marketing_pushes')
}}***
试试在中的回购中的:
*>> ./render models/example_funnel.sql*
这个东西将呈现一个庞大的查询,很难理解,手工组装起来会很痛苦。但是用宏呢?不是可怕可怕。
用例#4:单元测试
这是整件作品的真正主题。
我们已经看到抽象是如何让我们通过构建小的乐高积木来构建复杂的查询的。如果你在工作流程中使用它们,你可以从相对简单的部分构建出最终复杂的东西。
我们还看到这些部分是可参数化的,我们可以提供给宏的一个关键参数是对一个表的引用!这种引用可以是对“真实的”物化数据库表、公共表表达式或视图的引用。重要的是,我们可以对生产数据或使用参数化查询,这是我们有意设计并存储在某处的一组合成数据。
这使我们能够编写一堆行,覆盖我们希望查询处理的所有测试用例,并检查结果是否如预期的那样。然后,一旦我们确定它有效,我们就可以对实际的业务相关数量使用完全相同的查询逻辑。
如果我们用已经探索过的代码进行一些单元测试,我们可能已经发现了一些错误。例如,在volume_ratio.sql中,我们正在做整数除法,不会在我们的查询结果中得到real个数字。我们也不检查 0 值分母,这在最坏的情况下是个坏消息。
还有几个例子,我们对公开的列如何命名做了隐含的假设——对命名方案的任何微小改变都会破坏下游的宏,而调用者不知道发生了什么。
进行单元测试强调了您的组织正在构建的整个分析卡片屋,并允许您迭代,直到您获得一个既正确又易于更改的“数据 API”。
它还允许您自信地进行更改,并简单地检查之后的回归,而不是将您的时间花费在生产记录中试图进行健全性检查。
分析工程
只有当你以一种特殊的方式塑造你的分析团队时,这篇文章的教训才会有用。在开始使用 Jinja2 和宏的抽象魔法之前,一些隐含的假设必须成立:
- 您需要在一个统一的代码库中对分析工作进行编码,而不是在几个团队的商业智能工具页面中进行编码。
- 应该有一个连续的“部署”管道,从代码库获取最新的 SQL,并实际上将其分流到仪表板/报告等。这个管道可以处理 Jinja 渲染、查询导出等。
- 必须有一个框架来启动测试,如果有一个假设或逻辑错误可能产生不正确的查询结果,则 停止该行 。
开始这一切的一个很好的方法是浏览 Fishtown Analytics' 数据构建工具 的文档,该工具旨在处理像这样的组织的许多细节。
沿着这条路走下去,你的分析组织将超越侦探、特别查询处理程序和部落机构知识仓库。
这将把他们变成一个由分析工程师组成的团队,他们的工作是可重复和可靠的。
资源
在 Julia 中连接数据框架
学习所有连接——使用 DataFrames.jl 的内部、外部、交叉和半连接
W 帽子是什么加入的?我们为什么要这么做?我们如何使用 DataFrames.jl 来实现呢?在这篇文章中,我将展示一些关于如何连接数据帧的实用而简单的例子。

要获得所有媒体文章的完整访问权限,包括我的文章,请考虑在此订阅。
简单连接
上一次,我们弄清楚了如何使用 DataFrames.jl 索引、排序和聚合我们的数据。Joins 是另一个非常常见和重要的操作,出现在列表数据的世界中。跨两个数据框架的联接是基于两个表中存在的共享列值来组合两个数据集的操作。我们称这一列(或几列)为键。因此,第一个表中的每条记录都与第二个表中的一条记录匹配—只要记录的值相同。让我们通过一个小例子来证明这一点。首先,我们设置表 A:
5×2 DataFrame
Row │ id name
│ Int64 String
─────┼───────────────
1 │ 1 Alice
2 │ 2 Bob
3 │ 3 Claire
4 │ 4 Daniel
5 │ 5 Edward
该表包含所有个人的 id 及其姓名。假设我们有另一个表,其中包含这些个人的收入:
6×2 DataFrame
Row │ id salary
│ Int64 Int64
─────┼───────────────
1 │ 3 4078
2 │ 4 2395
3 │ 5 3662
4 │ 6 2202
5 │ 7 2564
6 │ 8 4545
我们现在有两张桌子:
- 保存人们的 id 和姓名
B_earnings保存 id 和收益。
我们想合并这两个表,这样我们就可以一起看到姓名和收入。我们加入吧!
3×3 DataFrame
Row │ id name salary
│ Int64 String Int64
─────┼───────────────────────
1 │ 3 Claire 4078
2 │ 4 Daniel 2395
3 │ 5 Edward 3662
让我们详细讨论一下这个问题。参数 1 和 2 是我们要连接的两个表。参数 3 ( on)告诉我们键列是什么。我们将使用该列来匹配表中的观察值。
如您所见,我们最终得到了 3 行 3 列。现在回到开始,看看这两个原始数据集是什么样子的。请确保您理解为什么我们最后只有这些行。
由于我们使用了innerjoin,我们只保留了出现在两个数据集中的 ids 其他的我们都丢弃了。
还有其他种类的连接:
- 内部连接:获取出现在两个表中的 id
- 左连接:从左(第一个)表中取出所有的 id 和右表的值
- 右连接:与左连接相同,但是保留第二个表中的所有 id
- 外部连接:从两个表中取出所有 id,不管它们是否出现在另一个表中
不要害怕,我们现在将逐一检查所有这些连接!首先,让我们做一个左连接,看看只在第一个数据集中的 id 会发生什么:
5×3 DataFrame
Row │ id name salary
│ Int64 String Int64?
─────┼────────────────────────
1 │ 1 Alice missing
2 │ 2 Bob missing
3 │ 3 Claire 4078
4 │ 4 Daniel 2395
5 │ 5 Edward 3662
在这里,我们保留了表 A 中的所有观察值,不管表 b 中的发生了什么。对于表 A 中没有匹配的记录,收入列的值为missing。这是有道理的,因为我们从来没有真正看到这些收入数字。
当然也有右加入。这将保留第二个表中的所有行。
如果您想拥有两个表中的所有 id,使用一个外部连接:
8×3 DataFrame
Row │ id name salary
│ Int64 String? Int64?
─────┼─────────────────────────
1 │ 1 Alice missing
2 │ 2 Bob missing
3 │ 3 Claire 4078
4 │ 4 Daniel 2395
5 │ 5 Edward 3662
6 │ 6 missing 2202
7 │ 7 missing 2564
8 │ 8 missing 4545
加载更多丢失的值,但是我们现在可以看到所有的 id。查看 id6–8 的新的缺失名称!这是外部连接的作用。
这 4 个连接构成了表合并的基础。如果没有别的,记住这四个:
- inner:只保留键同时出现在两个表中的行
- 左/右:仅保留出现在左侧(第一个)或右侧(第二个)表格中的关键点
- outer:保留两个表中的所有键
更多奇异的连接

马克·巴宾在 Unsplash 上拍摄的照片
上面的连接会让你的数据分析需求走得很远,但是我想向你介绍一些不太为人所知,但是仍然有用的连接。
假设您想查看有收入数据的人的姓名,但实际上您并不想要第二个表中的所有列。这就是半连接的作用。它为您提供了与内部连接相同的行,但是没有添加第二个表中的任何列:
3×2 DataFrame
Row │ id name
│ Int64 String
─────┼───────────────
1 │ 3 Claire
2 │ 4 Daniel
3 │ 5 Edward
这将返回 true,表明半连接与只包含表 a 中的列的内部连接相同。
我听到了,这很有用,但没那么疯狂。签出交叉联接:
30×4 DataFrame
Row │ id name id_1 salary
│ Int64 String Int64 Int64
─────┼──────────────────────────────
1 │ 1 Alice 3 4078
2 │ 1 Alice 4 2395
3 │ 1 Alice 5 3662
4 │ 1 Alice 6 2202
5 │ 1 Alice 7 2564
6 │ 1 Alice 8 4545
7 │ 2 Bob 3 4078
8 │ 2 Bob 4 2395
9 │ 2 Bob 5 3662
10 │ 2 Bob 6 2202
11 │ 2 Bob 7 2564
⋮ │ ⋮ ⋮ ⋮ ⋮
21 │ 4 Daniel 5 3662
22 │ 4 Daniel 6 2202
23 │ 4 Daniel 7 2564
24 │ 4 Daniel 8 4545
25 │ 5 Edward 3 4078
26 │ 5 Edward 4 2395
27 │ 5 Edward 5 3662
28 │ 5 Edward 6 2202
29 │ 5 Edward 7 2564
30 │ 5 Edward 8 4545
9 rows omitted
哇,那爆炸得很快💥!交叉连接获取表 A 中的所有行,对于每一行,它都将其与表 B 中的每一行进行匹配。乍一看,这可能没有任何意义,但是这是一个查找所有两个表的组合的好方法。我们的新表有 30 行,即 5(表 A 的行)x 6(表 B 的行)。
让你相信这确实有用。假设你想通过改变成分来设计一款新的 Twix。为了理解盈利能力,你还需要计算出巧克力的总成本:

显示更好格式的结果截图。
现在你相信我了吧?交叉连接使巧克力创新变得更容易,所以它们很有用!

沃尔特·奥托在 Unsplash 上的照片
要加入的多个键
现在我们有了更好的巧克力,让我们学习如何在多栏中加入。将上述连接扩展到使用两个键是非常容易的。事实上,您所要做的就是将一个符号或字符串向量传递给连接函数的参数on。为了演示这一点,让我们复制并添加另一列到我们的两个数据集。这将包含用户居住的城市名称。
julia> display(C_names)
5×3 DataFrame
Row │ id name city
│ Int64 String String
─────┼─────────────────────────
1 │ 1 Alice New York
2 │ 2 Bob London
3 │ 3 Claire London
4 │ 4 Daniel New York
5 │ 5 Edward London
julia> display(D_earnings)
6×3 DataFrame
Row │ id salary city
│ Int64 Int64 String
─────┼─────────────────────────
1 │ 3 4078 New York
2 │ 4 2395 New York
3 │ 5 3662 New York
4 │ 6 2202 London
5 │ 7 2564 New York
6 │ 8 4545 New York
你可以这样想,我们有两个独立的数据库。一个在纽约,一个在伦敦。由于系统之间互不了解,它们分别跟踪用户的 id。因此,伦敦用户 1 的姓名与纽约用户 1 的姓名不同。的确,他们是不同的用户!因此,当我们合并这两个表时,我们希望确保姓名和收入不仅在用户 id 上匹配,而且在数据库名称上匹配。让我们在两列上做一些连接:
1×4 DataFrame
Row │ id name city salary
│ Int64 String String Int64
─────┼─────────────────────────────────
1 │ 4 Daniel New York 2395
我们可以看到,只有丹尼尔出现在两个数据集中,并且住在同一个地方。
不同的列名
您可能面临的一个问题是,您的键列在您的数据框架中没有相同的名称。如果是这样,你有两个选择:
- 您可以使用
rename!重命名列 - 或者您可以将名称映射作为
on参数传递
现在我们想做的是用姓名连接新的收入表,但是我们想在新表中使用another_id作为我们的连接键。
这里我们告诉 Julia 在进行连接时将=>列映射到id列。当您需要重命名列时,会使用完全相同的格式。
摘要
阅读完本文后,您应该掌握了以下连接函数:
- 内部:用于查看重叠部分
- 外层:用于保存所有东西
- 左/右:用于保留一个表中的所有行
- semi:用于在进行内部连接时只保留第一个表中的列
- cross:用于创建两个表的乘积,即让每一行都与每一行匹配。
您还知道如何连接多个键或不同的键名。感谢阅读!
连接熊猫数据框
了解如何轻松合并熊猫数据帧

由 Unsplash 上的 CHUTTERSNAP 拍摄
通常,您的数据来自不同的来源。为了帮助您进行分析,您通常需要组合不同来源的数据,以便您可以获得所需的数据。在这篇文章中,我将讨论如何合并(连接)熊猫数据帧。关于这个主题的大多数文章都使用简单的数据帧来说明数据帧连接的概念——内部连接、外部连接、左连接和右连接。对我来说,理解这个主题的一个更好的方法是使用一个更现实的例子,这样你就可以理解并能够更好地记住这些概念。
我们开始吧!
创建数据帧
首先要做的是创建两个数据框。第一个创建航班号列表和他们出发的机场:
import pandas as pddf_flights = pd.DataFrame(
dict(
AIRPORT_CODE=['MIA','MIA','LAX','DCA','SIN'],
FLIGHT_NO=['3322','3213','4223','5678','1234']
)
)df_flights
df_flights 数据帧是这样的:

下一个数据帧包含机场代码列表及其各自的机场名称:
df_airports = pd.DataFrame(
dict(
AIRPORT_CODE=['MIA','LAX','DCA','HEL','SFO'],
AIRPORT_NAME=['Miami International Airport',
'Los Angeles International Airport',
'Ronald Reagan Washington',
'Helsinki-Vantaa Airport',
'San Francisco International Airport']
)
)df_airports
df_airports 数据帧看起来像这样:

列出所有航班的机场名称
假设您需要获得每个航班的所有出发机场名称。因为信息在两个数据帧中,所以需要连接这两个数据帧。在 Pandas 中,使用 merge() 方法连接数据帧。对于此要求,您可以基于 AIRPORT_CODE 列对两个数据帧执行一个“ left ”连接:
pd.merge(df_flights, df_airports, on='AIRPORT_CODE', how='left')
' on '参数指定要联接的列。“左是指第一个数据帧— df_flights 。上述连接函数的结果如下:

注意来自 df_flights 数据帧的所有行(‘left’join)都在结果中。还可以观察到,由于机场代码 SIN 在 df_airports 数据帧中没有条目,因此它在 AIRPORT_NAME 列中有一个 NaN 值。
“左”连接确保结果包含第个数据帧中所有可用的机场代码。
列出各个机场的所有航班
如果您想列出所有机场的所有航班,该怎么办?在这种情况下,你可以执行一个'右'连接:
pd.merge(df_flights, df_airports, on='AIRPORT_CODE', how='right')
右是指第二个数据帧— df_airports 。上述连接函数的结果如下:

注意,结果现在包含了所有包含在 df_airports 数据框架中的机场(右连接)。此外,由于有两个航班来自 MIA 机场,结果将包含 MIA 机场的两行。此外,由于 HEL 和 SFO 机场在 df_flights 数据帧中没有任何离港航班,因此结果的 FLIGHT_NO 列将包含 NaN s
“右”连接确保结果包含第二个数据帧中可用的所有机场代码。
列出现有航班的机场名称
您之前看到‘left’join 结果包含从 SIN 机场出发的航班的条目:

但是,您可能希望忽略没有有效机场代码的航班。在这种情况下,您可以执行一个' inner '联接:
pd.merge(df_flights, df_airports, on='AIRPORT_CODE', how='inner')
“内部”连接的结果现在将只包含在两个数据帧中都有机场代码的行:

“内部”连接确保结果中的机场代码在第一个和第二个数据帧中都可用。如果没有指定“how”参数,merge()方法的默认联接是“inner”。
列出所有机场名称和航班
与'innerjoin 相反的是'outerjoin,其中两个数据帧中的值在结果中都可用。
使用我们的例子,如果你想得到所有的机场名称和航班,你可以执行一个' outer '连接:
pd.merge(df_flights, df_airports, on='AIRPORT_CODE', how='outer')
结果现在将包含所有机场,不管是否有相应的机场名称或是否有来自某个机场的航班:

“外部”连接确保结果中的机场代码在第一个数据帧和第二个数据帧中都可用。
基于不同列名的联接
到目前为止,我们的连接非常简单,其中两个数据帧具有我们想要连接的相同列名。在现实生活中,数据帧有不同的列名要常见得多。
假设 df_flights 数据帧的 AIRPORT_CODE 列现已更改为 IATA_CODE :
import pandas as pd
df_flights = pd.DataFrame(
dict(
**IATA_CODE**=['MIA','MIA','LAX','DCA','SIN'],
FLIGHT_NO=['3322','3213','4223','5678','1234']
)
)df_flights

要像前面一样执行连接,现在需要使用 left_on 和 right_on 参数显式指定各个数据帧的列名:
pd.merge(df_flights, df_airports,
left_on='IATA_CODE', # column for df_flights
right_on='AIRPORT_CODE', # column for df_airports
how='left')
结果现在将包含来自两个数据帧的连接列( IATA_CODE 和 AIRPORT_CODE ):

现在,您可以继续删除其中一列。但是,在此之前,请观察最后一行的 IATA_CODE 和 AIRPORT_CODE 列——一列的值为“ SIN ,另一列的值为 NaN 。在这种情况下,您应该删除 AIRPORT_CODE 列(如果您打算显示所有离港航班的机场代码和机场名称):
pd.merge(df_flights, df_airports,
left_on='IATA_CODE',
right_on='AIRPORT_CODE',
how='left')**.drop(columns='AIRPORT_CODE')**
结果现在看起来像这样:

使用多列连接
除了联接具有不同列名的数据框架之外,还可以联接基于多列的数据框架。理解这一点的一个好方法是用一个例子。考虑以下数据帧:
df_confirmed = pd.DataFrame(
dict(
country=['Mainland China','Mainland China',
'US','Canada','US'],
state=['Hunan','Anhui','Seattle, WA',
'Toronto, ON','Montana'],
confirmed=[879,830,1,2,20]
)
)df_locations = pd.DataFrame(
dict(
country=['Bulgaria','US','Mainland China',
'Mainland China','US','Canada'],
state=['Montana','Montana', 'Hunan','Anhui',
'Seattle, WA','Toronto, ON'],
lat=[43.4125, 46.965260 ,27.61041, 31.82571,
47.7511, 43.6532],
lng=[23.225, -109.533691, 111.7088, 117.2264,
-120.74, -79.3832]
)
)
df_confirmed 数据帧如下:

而 df_locations 数据帧看起来像这样:

如果您想找到每个州的位置,您可能会尝试通过“州”连接两个数据框:
pd.merge(df_confirmed, df_locations, on='state', how='left')
但是,结果将包含六行,因为有两个蒙大拿州,一个在美国,一个在保加利亚:

正确的加入方式是基于国家 和 州列(作为列表提供)加入:
pd.merge(df_confirmed, df_locations, on=**['country','state']**,
how='left')
结果现在是正确的:

您也可以使用 left_on 和 right_on 参数连接多个列。
结论
就是这样!我希望您现在对连接数据框架的工作方式有了更清晰的了解。以下是我们在本主题中讨论的内容的快速总结:
- ' left '联接返回第一个数据帧中的所有行
- '右'联接返回第二个数据帧中的所有行
- ' inner '联接返回两个数据帧中可用的所有行
- ' outer '联接返回第一个数据帧和第二个数据帧中的所有行
- 您可以使用 left_on 和 right_on 参数连接基于不同列名的数据帧
- 还可以使用多个列名连接数据框架
没有连接键或公共索引的连接表
使用模糊字符串匹配匹配马来西亚人的 2 个不同来源的产品评论,并比较 Jaccard 和 Levenshtein 算法。
当我必须匹配几个马来西亚在线购物平台的产品评论时,就出现了这种情况。让我们马来西亚人与众不同的是我们如何拼写和给出产品评论。

亚马逊评论(上)与马来西亚人的评论(下)。作者提供的截图。
我决定分享我遇到的这个挑战,以及一些可能使这个话题与他人相关的场景。
想象一下,如果今天,您需要连接来自不同来源的两个或多个表,这可能是因为以下情况:
- 2 家公司合并,需要合并他们的产品数据来清点库存。
- 您正在比较一系列产品的不同应用的一些评论。
- 从一个表格中寻找反馈,并尝试将相似的单词组合成一个。
其中一个问题是您无法控制数据,无法让他们重新索引他们的产品 id 或密钥,因为企业要求您尽快提供它们,或者这可能只是出于报告目的,企业无意重新索引以避免服务中断。
神奇的门户网站,帮助您跳转到本页所需的主题
- 今天的挑战
- 什么是 Levenshtein 距离和 Jaccard 指数
- 每种算法解决和未解决的问题
- UDF 在大查询中对 Jaccard Index 和 Levenshtein
- 今日挑战 Jaccard 指数用例
- 外卖积分
今天的挑战
为了让您更深入地了解我们今天的挑战,这里有一个我们今天将尝试加入的两个表的示例。我们想要得到每个评论出现的总数。代替 Levenshtein 距离,为了这个介绍,我们将集中使用 Jaccard 指数。虽然这可能看起来很荒谬,但这些都是我从马来西亚几大在线购物平台上收集的合法评论。


没有公共键连接的两个表。作者提供的截图。
做一个快速的谷歌搜索最终会有一个解决这个挑战的常用方法,那就是使用一种叫做 Levenshtein Distance 的算法。虽然 Levenshtein 距离在大多数情况下都很有效,但我想介绍另一种算法,称为 Jaccard Index/Jaccard similarity。这不是“更好”或“完美”算法的争论,而是另一种方法的介绍。在深入实际应用之前,我们需要知道 Levenshtein 距离和 Jaccard 指数算法解决了什么问题。
什么是莱文斯坦距离和雅克卡指数
通俗地说,Levenshtein 计算将一个字符串更改为另一个字符串需要多少步/编辑,Jaccard 计算第一个字符串与第二个字符串相交的程度。我在下面举例说明了这两种算法的不同之处。

作者创建的 Levenshtein 距离和 Jaccard 指数的插图。
在上图中,Levenshtein 不得不从 thaanks 中删除多余的“ a ,从而导致一次编辑,使第一个字符串与第二个字符串相似。由此 Jaccard 将比较每个唯一的字母是否存在于另一个字符串中。Jaccard 不考虑“ a 的数量,因此“ thaanks 中的 2 个“ a ”被视为一个“ a ”。
每种算法解决和未解决的问题
Levenshtein 距离是一些自动校正软件使用的许多算法之一。

作者 Chromium 对 thaank 的自动更正提示截图。
“感谢”和“thank”的编辑距离为 1,因此自动更正软件建议“感谢作为替代。由此,在一些事件中,用户决定输入“thaaaaaaaaaaaanks”,使用 Levenshtein 距离的自动校正软件可能无法解决该问题,因为编辑距离很大(删除 10 步“a”以使其成为“感谢”)。

作者 Chromium 对thaaaaaaaaaaaanks 的自动更正提示截图。
如上面的截图所示,我的浏览器没有建议任何替代词,因为我输入的单词可能与他们字典中的任何单词都有很大的编辑距离。我使用我的基于 Chromium 的浏览器作为 Levenshtein 将要展示的例子,但是,我并不是说使用 Levenshtein 距离作为他们的主要算法,他们可能有更复杂的算法来处理语法和不同的语言。
那么 Jaccard 会如何处理“thaaaaaaaaaaaanks”对“谢”呢?首先,两个单词将被制成一组唯一字符,两个字符串的唯一字符是“感谢”。将"谢"与"谢"相交导致所有字符相交,即 1。但是,当两个不同的单词具有相同的唯一字符时,Jaccard 可能不会返回理想的结果。以“好”和“神”为例,这两个字符串都有唯一的字符“神”,所以由于所有字符都相交,所以结果为 1。
现在您已经了解了这两种算法的工作原理,让我们看看如何在今天的挑战中应用 Jaccard 算法。
UDF 在对 Jaccard Index 和 Levenshtein 的大查询中
或者您可以使用相同的逻辑,并将其应用于其他数据库。
什么是大查询中的 UDF?用户自定义函数(UDF) 可以是 SQL 或 Javascript 的形式,允许你在大查询中创建类似编程语言的函数。
我们将使用 Javascript 创建 Jaccard 索引算法,并将结果与 Levenshtein 距离进行比较。bqutil是来自谷歌云平台的一个项目,它托管了几个我们可以使用的预建功能。他们的 Github 库可以在这里找到。在撰写本文时,我已经创建了一个 pull 请求来添加 Jaccard 索引作为供公众使用的bqutil UDF。
将创建一个名为 jaccard 的临时函数,它接受 2 个字符串并返回一个范围从 0 到 1 的浮点数。如果第一个字符串 sa 中的一个字符存在于第二个字符串 sb 中,则将交集大小增加 1。循环完成后,通过计算两个字符串的长度并减去交集大小来计算索引,然后将结果再次除以交集大小来获得交集字符的百分比。最后,返回一个 2 小数点的浮点数。

以上查询的结果。作者提供的截图。
然后运行 4 个测试用例来比较 Jaccard 指数和 Levenshtein 距离之间的结果。如图所示,Jaccard 将能够校正相似度为 1 或 100%相似的第一个和第二个示例(感谢和最佳产品示例)。由此 Levenshtein 指出需要 10 和 8 个步骤来将第二个字符串校正为第一个字符串。关于 doge 和 dodge 的第三个例子,Jaccard 指出两者是相似的词,我们知道它不是,Levenshtein 指出需要一个步骤来纠正 doge 的 dodge,反之亦然。
今天的挑战 Jaccard 索引使用案例
- 创造一个 UDF
- 创建两张桌子来模拟我们今天的挑战
- 交叉连接两个表,这样我们可以计算第二个表中的每个评论与第一个表中的每个评论之间的距离
对于那些仍然对交叉连接感到困惑的人,我已经根据我们当前的挑战在下面举例说明了它。

作者创建的 t1(左)和 t2(右)的交叉连接图。
交叉联接将一个表中的每条记录与另一个表中的每条记录相匹配。然后,我们对每条记录运行 jaccard 函数,只显示 Jaccard 索引大于 0.8 或 80%相似的记录。

今天挑战的结果
使用 Jaccard 索引和 80%相似度的阈值,它很好地支持了我们的数据集。第二个表中的每条记录都被正确地添加到第一个表中。
外卖点
- 不存在“最佳”算法的竞争
- 每种算法都有自己的用例
- Jaccard 索引处理非常具体的情况,不应该在不考虑每个模糊匹配项目的情况下将其概括为“goto”算法
使用 Jaccard Index,我能够根据一个定制的“马来西亚俚语”字典有选择地纠正我的数据集中至少四分之三的评论,我将这个字典定义为我的来自上述挑战的 t1 。读者们,我希望这能向你们介绍另一种选择,如果 Levenshtein 不像我一样对你们有利的话,你们可以考虑一下。
联合高棉语分词和词性标注
深度学习方法和 PyTorch 的简单实现
分词和词性标注是自然语言处理(NLP)中的两个关键过程,因为这些任务的性能显著影响下游任务,特别是在没有特定分词书写规则的语言中,如高棉语、汉语、日语等。
过去,分词和词性标注是分开学习。然而,单词的分离方式与其词性密切相关。因此,在一个学习过程中考虑这两项任务有望取得更好的效果。
在本文中,我们将着眼于联合高棉语分词和词性标注任务。这里解释的方法是由 Bouy 等人在题为“ 使用深度学习的联合高棉语分词和词性标注 ”的论文中提出的。

图来自【1】

图来自【1】
概观
- 输入:高棉语句子中的字符序列(图 6)
- 输出:每个字符的位置和单词分隔符的标签序列(图 6)
- 模型:双向长短期记忆(双 LSTM)神经网络(图 5)
预测过程
- 首先,将输入句子转换成字符级序列。

图来自【1】
- 然后,该序列被编码成 132 维的一键向量。

图来自【1】
- 编码的表示向量被用作 2 栈双 LSTM 的输入。
- 在最后的时间步骤中,Bi-lstm 的隐藏向量被连接以获得单个特征向量。

图来自【1】
- 最后一层是前馈神经网络,利用这个特征向量来预测每个字符的标签。这里,softmax 函数被用作激活函数,因此,输出序列是预定义标签(词性标签和单词边界标签)的概率序列。

图来自【1】
- 对于输出标签,“NS”代表“没有空格”,这意味着被标记的字符不是一个单独的位置。除此之外的其他标签,比如“PRO”、“NN”、“VB”,同时代表一个词段的开头及其词性。在下图中,带有“PRO”标签的字符是单词“ខ្ញុំ”(表示我)的开头,其 POS 标签是“PRO”(代词),而带有“VB”标签的字符是单词“ស្រលាញ់”(表示爱情)的开头,其 POS 标签是“VB”(动词)。

图来自【1】

图自【1】
学问
- 作者在提出的模型的训练过程中使用了交叉熵损失函数。
- 学习目标是最小化交叉熵损失函数。

图来自【1】
学习配置

图来自【1】
我已经在 PyTorch 中实现了所提出的方法,并使用相同的超参数在本文中介绍的数据集上训练了模型。下图显示了使用引入方法的联合分词和词性标注的示例。有用!!!!

使用引入方法的联合分词和词性标注示例(图由 Mengsay 提供)
履行
现在让我们在 PyTorch 中实现它。在下面的实现中,我使用了一个来自 https://github.com/yekyaw-thu/khPOS的数据集,如论文中所介绍的。
- 本文的完整实现可以在 Github 上获得。
- PyTorch 教程
数据预处理
可用数据集为“[word1]/[POS] [word2]/[POS]……”格式。所以,我们需要把它转换成字符序列和位置序列。这里的另一个警告是,在论文中,作者通过组合一些 POS 标签来修改原始数据集。详情请看论文。

示例代码(数据处理 1/3)

示例代码(数据处理 2/3)

示例代码(数据处理 3/3)
数据集和数据加载器

示例代码(数据集 1/1)

示例代码(数据加载器 1/2)

示例代码(数据加载器 2/2)
模型

示例代码(模型)
培训和测试

准备数据加载器

初始化模型和相关的东西

火车步

测试步骤
参考
[1] Rina 浮标和 Nguonly Taing 和 Sokchea Kor。使用深度学习的联合高棉语分词和词性标注。 arXiv:2103.16801 ,2021。
伯特之旅:第二部分
各种 NLP 概念和架构的拼贴导致了现代基于变压器的 NLP 模型 BERT。

现代 NLP 发展简史。来源:self
这是我不久前写的上一篇博客伯特之旅的第二部分。在这篇博客中,我将继续叙述并解释向 BERT 发展的概念里程碑。
迄今为止
- 前神经单词嵌入,如 Glove、TF-IDF
- 常见的自然语言处理任务,如分类、问答和文本摘要。
- Word2Vec 的神经嵌入。
- 使用深度序列模型(RNN)进行自然语言处理
- 发现注意力和双向性。
通过下面的模型和方法,我们继续关注 NLP 的进一步发展。从现在开始,最受欢迎的属性是迁移学习、上下文学习和规模。
TagLM
TagLM(语言模型增强序列标记器)可能是第一个真正尝试产生上下文单词嵌入的软件。Matthew Peters 等人在 2017 年提出了这篇论文,该论文展示了如何在序列标记任务中通过语言模型嵌入来增强 un 上下文单词嵌入。语言模型嵌入基于在未标记的文本数据上预先训练的双向 rnn,并且与用于序列标记的多栈双向 rnn 的隐藏层输出连接。

来源:原创论文
TagLm 在 CoNNL 数据集上的 NER 识别上取得了令人印象深刻的结果,击败了所有以前的 sota 方法。
山凹
Context Vector( CoVe )处理上下文单词向量的方法与 TagML 不相上下。论文由麦肯等人撰写。2018 年,其主要动机是将 ImageNet 的迁移学习成功应用于计算机视觉的下游任务。作者认为,在 NLP 领域中,ImageNet 的等价物可以是基于 LSTM 的编码器,用于使用基于 LSTM 的注意序列到序列模型的神经机器翻译任务。然后,预训练的编码器可以用作上下文单词嵌入的源,该上下文单词嵌入然后可以扩充传统的单词向量系统(例如 Glove)。NMT 在多个机器翻译数据集上进行训练,这些数据集基本上是两种语言的句子对。

来源:原始文件 r

资料来源:原始文件 r
该论文建议将 CoVe 向量(双 LSTM 编码器的最后一层)与 Glove 向量相结合,并说明了在一些常见的 nlp 任务中的性能增益。然而,与 Tag-LM 不同,CoVe 需要标记的数据(两种语言的文本对)来训练机器翻译任务的编码器。这是这种方法的一个明显的局限性。此外,下游任务的实际性能提升更多地取决于下游任务的架构。
工程与后勤管理局
来自语言模型的嵌入(ELMO)在某种意义上是对来自同一组的 Tag-LM 的细化( Peters et al. )。作者认为,在大型语料库中以无监督方式学习的(双向)语言模型携带单词的语义和句法内涵。模型的初始层捕获语法意义(NER、词性标注),而模型的末端层捕获语义意义(情感分析、问题回答、语义相似度等)。因此,不是仅使用最后一层(如在 Tag-LM 或 Clove 中所做的,其中网络是预训练的和冻结的),而是采用所有层的线性组合将是对单词的上下文含义的更好和丰富的估计。ELMO 代表因此被认为是“深”。
在 ELMO,学习语言模型的通常方式是从一个句子中的前一个单词序列双向预测下一个单词。损失函数是负对数似然。

来源:论文,代码
ELMO 是对 Tag-LM 和 Clove 的改进,这可以归因于表示“深入”的事实。该论文说明了 ELMO 在各种常见的 NLP 任务上实现了递增的性能增益。

来源:原创论文
然而,ELMO 仍然存在更多地依赖下游任务的架构来提高性能的缺点。
与 ELMO 竞争的是另一个来自杰瑞米·霍华德等人 (Fast.ai),用于文本分类的通用语言模型微调( ULMFiT )的提议。除了使用 RNN 进行语言建模的预训练步骤之外,ULMFiT 建议在目标数据集上使用 LM 微调。基本原理是了解目标数据集的“分布”或“特定于任务的特征”。最后一步是特定任务的微调。例如分类器(使用几个线性块)。
走向变形金刚
因此,《变形金刚》的架构成为了伯特家族和 GPT 系列等更现代作品的“最底层”构成。Vashwani 等人在 2018 年的论文“注意力是你所需要的一切”中首次提出,它为 rnn(及其风格)提供了一种处理顺序数据的替代方法。

来源:原始文件
不如参考杰·阿尔玛的这篇优秀文章全面了解。简单来说,该架构具有以下重要元素。
- 多头自我注意:在很高的层次上,自我注意允许参考序列中的其他单词和子空间来关联单词的意思。基本上,另一种获取(长期)依赖的方式。“多头”意味着使用多个头来关注具有多个代表性空间的序列中的多个子空间。比如使用多个大脑。从数学上来说,携带自我注意力的嵌入是使用乘以值矩阵的 softmax over keys.queries 来计算的。

来源:原创论文
2.(正弦)位置编码:有趣的是,变压器本质上并不是连续的。事实上,它观察并处理整个序列。在这种情况下,位置编码封装了标记的顺序。它实际上是使用 sin 和 cos 函数创建的嵌入的向量值。这里有一个极好的参考。
那么变压器架构给 rnn(Bi-lstm)带来了什么好处呢?
- 消失梯度:变压器中没有记忆门的概念,因为这种容易丢失信息的方法是通过直接访问序列的所有部分来规避的。
- 长期依赖性:由于多头自我关注层,变形金刚更擅长捕捉长期依赖性。
- 双向设计:因此,transformer 编码器一次读取整个序列,并使用单词前后的所有环境。因此,它本质上是双向的。事实上,许多人认为它是无方向性的。
生成式预训练变形金刚(GPT)
由拉德福德等人于 2018 年首次推出。(就在伯特之前)GPT 是第一批使用变形金刚架构的人之一。来自 OpenAI 的作者提出了这种架构,作为现有想法的有效结合
a .无监督的预训练(如在 ELMO 看到的)和 b .变形金刚。
此外,该框架有两个主要组成部分
1。无监督的预训练(使用变压器)这基本上是在给定网络参数上的记号的上下文的情况下最大化记号的可能性。


来源:原创论文
为此,该论文提出使用多层(12 层)变换器解码器,该解码器基本上由多头自关注层+位置前馈层组成,该位置前馈层使用 softmax 在目标令牌上产生分布。原始变形金刚架构的这种变化是单向的(从左到右),因为自我关注仅归因于左上下文。
2。监督微调:对于分类等下游任务,标记的数据被输入到先前的模型中,用于变压器解码器的表示和微调。附加的线性图层+ softmax 图层有助于最终的分类任务。作者还建议增加一个额外的学习目标来学习一个展示更好的泛化能力的语言模型。
除了上述生态位特征外,尺度是 GPT 一号的另一个属性。它是在一个拥有 240 个 GPU 日的大规模图书语料库上训练的。GPT 1 号之后的所有后续模型都是通过强大的 GPU/TPU 和越来越多的参数在大量数据上进行训练的。GPT-1 成功证明了基于大规模预训练+少量监督微调和附加目标学习的转换器可以满足各种 NLP 任务(NLI、问题回答和分类)。事实上,当时它的表现确实超过了各种 sota 车型。
然而,GPT-1 模型本质上是单向的(从左到右),因为自我关注仅基于先前的表征。伯特提出的问题。
伯特
确实是一次长途旅行!伯特(来自变形金刚的双向编码器表示)由作者德夫林等人在谷歌的 GPT-1 之后不久发表。总的来说,这种方法看起来非常类似于 GPT-1 架构中提出的无监督语言模型学习,然后有监督的微调步骤。然而,BERT 的架构更像 Vaswani 等人的原始 transformer 架构,并且基于多层双向 Transformer 编码器。而 GPT-1 架构只是原始架构的仅左上下文(单向)版本,通常被称为“变换器解码器”。

来源:https://jalammar.github.io/illustrated-bert/
因此,作者的主要论点是单向预训练限制了下游任务的代表性,因此是次优的。例如,用于微调问题回答任务的单向预训练模型是次优的,因为没有利用来自两个方向的上下文信息。由于 BERT 是双向的,标准语言模型任务不适合作为目标学习任务。这是因为在 transformers 架构中,所有单词都是一次输入到模型中的(因此是可访问的)。对于一个标准的 LM 任务,每个单词都可以从未来看到自己,因此学习变得微不足道。

来源:普林斯顿 COS 484
BERT 通过使用“屏蔽语言建模”解决了这个问题,这实质上是屏蔽文本中的随机标记并预测它。

来源:普林斯顿 COS 484
除了 MLM,伯特还采用了另一个叫做“下一句话预测”的学习目标。在 NSP 中,目标是分类一个句子是否是另一个给定句子的跟随句。直觉上,这有助于学习句子之间的关系。

来源:普林斯顿 COS 484
与 GPT-1 一样,微调是 BERT 中的第二阶段。修改(输入表示和输出图层)本质上是特定于任务的。例如,对于分类任务,CLS(事件中的第一个特殊令牌)被馈送到分类器网络。学习是端到端的,这意味着所有层及其权重继续学习。

来源:原创论文
伯特有两种风格,伯特基础和伯特大。它们的主要区别在于层数(变压器模块)。基础=12 层,110 米参数,大型= 24 层,340 米参数。BERT 确实是自然语言处理中的一个里程碑,它成功地展示了一种 sota 方法,该方法实现了基于变压器(自我注意)、双向和巧妙的目标学习任务的迁移学习。并在大规模语料库(books corpus+256 个 TPU 日的英文维基百科)上进行离线训练。
超越 BERT
在最初的 BERT 论文之后,在各个方面已经有了很多进步。还有更复杂的变化,如 RoBERTa 在更大的语料库上训练更长时间,并采用聪明的学习目标(如动态屏蔽和转储 NSP)。例如,另一个名为 ALBERT 的变体旨在通过使用参数缩减技术产生一个更小的模型。ELCTRA 、 XLNet 是其他一些有趣的变体。
此外,有一些积极的研究正在进行,以使伯特模型重量轻。(BERT 大~ 340 M 参数)。为此已经提出了几种方法,例如权重修剪、量化和提取(DistillBERT) 。这里有一个关于同一的优秀博客:https://blog.inten.to/speeding-up-bert-5528e18bb4ea
总结 我想 NLP 领域已经有了快速而巨大的发展。从使用文本的统计表示到上下文感知的神经表示。从基于统计学和经典 ML 的方法到基于深度学习的序列模型。途中发现注意力和双向性,体会迁移学习的力量。最终走向复杂的变形金刚架构。现代 NLP 框架在利用这些重要的里程碑和规模方面取得了长足的进步。
参考文献
- http://jalammar.github.io/illustrated-bert/
- 【http://web.stanford.edu/class/cs224n/
- https://devopedia.org/bert-language-model
- https://www . cs . Princeton . edu/courses/archive/fall 19/cos 484/lectures/LEC 16 . pdf
- https://openai.com/blog/better-language-models/
- https://Neptune . ai/blog/ai-limits-can-deep-learning-models-like-Bert-ever-understand-language
Python 中相关变量的蒙特卡罗模拟
思想和理论
用于 MC 模拟的 MCerp 软件包,通过 Iman-Conover 方法生成相关性

图片由 Nikodi 在 pixabay 上提供,可免费用于商业用途
今天,我们继续蒙特卡洛的数据科学之旅。
前三篇文章首先概述了 SciPy 的概率分布、它们的属性以及如何在 Python 中使用它们的方法 Python 是模拟的基础。然后,我们讨论了场景分析和三点估算技术,以及有助于场景建模的三角形和 beta-PERT 分布。第三篇文章,在周一,介绍了蒙特卡罗概念,以及我们如何只用 SciPy 库运行模拟。
今天的文章将带领我们的帆船 MS Python 驶向下一个停靠港,并介绍具有相关随机变量的 MC 模拟— 当我们想要将场景与现实相一致并避免隐藏的偏差时,我们需要考虑的一个重要方面。

我们将在 Juypter 笔记本中导入 MCerp 库。它应用 Iman-Conover 方法通过拉丁超立方体采样产生相关随机变量。
0.涉及相关随机过程的模拟
我以前的 MC 文章解释了一个计算新产品利润的模拟模型。它用预期售价乘以销售量。该模型没有假设交易量和价格是否相关。但当然,事实上的确如此:较高的售价往往会降低需求。
我们需要考虑输入变量可以表现出一前一后移动的趋势:同向——正相关;或者相反方向——负相关。如果不考虑平行运动,模拟模型将对不切实际的结果赋予同等的权重——例如,高价的高需求可能以与低价的高需求相同的频率出现。
相关随机变量确保输入参数之间的关系准确地反映在模拟结果的频率分布中。
以下段落用非数学术语解释了 Iman-Conover 算法:如何生成相关性。如果你只对结果感兴趣——如何使用 mcerp 运行相关模拟——那么你可以跳到下一章。
将随机变量相互关联以反映计划者为其估计的相关矩阵的一种常用方法是伊曼-康纳法 ( 论坛 _06w 论坛 _ 06w 107 . pdf(casact.org);【correlation.pdf(uio . no)排名的一种无分布方法。IC 方法可以关联源自不同分布的多个随机变量。
该算法可以描述如下。生成 r 列长度为 N 的相关随机数—
- 假设我们已经有了一个矩阵 X,它有 r 列(每列是一个随机变量)和 N 行(例如,每个变量有 10,000 个值)。
- 首先,用您想要对变量施加的成对相关结构填充相关矩阵 S。
- 对其应用乔莱斯基分解(来自 scipy.linalg import cholesky )以获得上三角矩阵 c
- 创建标准正态分位数的向量 v,scipy.stats.norm.ppf(i/(N+1)。将分位数除以向量元素的标准偏差,使其合计的标准偏差为 1.0。
- 将这个向量复制 r 次,并将 v 的副本组合在一个所谓的得分矩阵 M 中,该矩阵具有与我们想要生成的随机变量一样多的正常得分列。随机打乱正常分数每列中的行。
- 计算该得分矩阵 m 的相关矩阵 E。对其应用乔莱斯基分解以获得其上乔莱斯基三角形 f
- 通过乘法将矩阵连接在一起:T = M * inv(F) * C。这个矩阵 T 具有精确的目标相关结构。
- 生成一个矩阵 Y,它包含我们想要关联的每个随机变量的一列,有 N 行,就像原始矩阵 X 一样。矩阵 T 建议 Y 从观察矩阵 X 中的特定行和单元中提取一个值来填充 Y 中的特定行和单元。这将生成 Y 中 X 值的目标等级相关性。
- x 由独立变量或不同相关的变量组成。对于每个变量,y 将由相同的 N=10,000 个随机变量组成。IC 方法保留它们的值。但是它们将被重新排序以展示我们想要强加的等级相关性。T 和 Y 的相关矩阵将尽可能地反映目标相关矩阵 s
mcerp 文档没有明确提到它的相关性是如何生成的,但是浏览一下它的 Python 源代码就会发现它应用了 Iman-Conover。
1.属国
除了导入我们的核心库 pandas、numpy、scipy 和 matplotlib,我们还需要安装库 mcerp :
- pip 安装 mcerp
或者:
- 康达安装-康达锻造 mcerp
这是一个依赖于 numpy、scipy 和 matplotlib 的精简包。
MCerps 的文档简洁,不太专业。我将解释文档没有提供指导的几个方面,但是我们可以从它的 Python 代码中推断出来。
2.建立蒙特卡罗模拟
前一篇文章准备了一个业务案例模拟:一个企业计划推出一个新产品。未来的销售量、销售价格和原材料单位成本的发展被建模为具有不确定性的因素,即随机变量。( Python 驱动的蒙特卡罗模拟|走向数据科学)
我们采用这种方法,并通过使用 mcerp 来运行该场景,先不使用,然后使用相关性。
- 销售量:3 点估计提供了最小、最可能和最大的单位销售量,PERT 分布连接到一个完全概率曲线。
- 销售价格:取决于与客户的谈判,其中一些客户将能够要求提前付款折扣或批量折扣。策划者估计,平均价格将围绕€ 20 的平均值呈正态分布,标准偏差为€1.00。
- 原材料供应商成本:供应链计划者预见到供应商增加的风险,平均单位成本为€ 13,标准偏差为 0.7
下一个单元格设置模型。三个输入参数由顶部的体积 v、价格 p 和材料单位成本 m 组成,加上一个确定性变量 o,该变量表示另一个不受不确定性影响的单位成本。
我们定义了四个输出或模拟目标,它们本身将是随机变量,其分布函数将在模拟运行期间从三个输入的相互作用中合并。输出变量的数量没有限制。引用一个或多个输入随机变量的任何公式都可以用作模拟输出。
- 毛利
- 收入
- 毛利率=毛利/收入
- 总成本=收入—毛利
当脚本到达该单元时,模拟在几分之一秒内完成。然后,我们可以通过接下来几个单元格中的代码收集模拟结果。
mcerp 参数 npts 设置要创建的点数,默认为 10,000,我们在练习中也采用这个数字。您可以通过调整顶部 dependencies 单元格中的常量 nR,将其更改为不同的整数。如果你自己的模型包含大量的随机变量,那么迭代次数大于 10,000 次是明智的。
mcerp 用户指南没有明确地提供为输入参数或输出收集 10,000 个随机变量的方法。但是 mcerp 源代码显示我们可以使用它的 _mctps 属性。
rv1 和 rGM1 之间的六个数组变量保存模拟结果,每个变量有 10,000 个数据点,每次迭代一个,因此我们可以跟踪模拟,并在以后重用这些数组进行统计评估。我们将六个数组组合在一个数据帧中,使它们更容易研究和处理。
下面的数据框列出了 10,000 个模拟输出,3 个输入参数和 3 个输出变量各占一行:

接下来,我们编写一个助手函数,它将在这些输入和输出变量上绘制直方图。

主要的模拟目标,总利润,显示出比正态分布更尖锐的峰值,但只是适度的薄分布。它的尾部导致峰度为 3.2,略高于正态分布。请注意,虽然 SciPy 计算的是正态分布的超额峰度(校准值约为 0 ),但 mcerp 报告的是峰度本身,正态曲线的峰度为 3.0。


收入曲线看起来几乎是正常的。
毛利率略偏左,尾巴在左边更明显。它将倾向于在低端有更多的异常值。
销售量遵循一条庞大的曲线 platykurtic,这意味着它的过度峰度为负,这表明异常值的倾向低于正态分布。
当然,销售价格模拟了正态分布的偏斜度和峰度,因为我们将其建模为正态随机变量。
这五个图表展示了三个输入变量(数量、价格和材料单位成本)的相互作用如何产生模拟输出,这些输出也代表随机变量,但模型生成的分布是输入的混合。
两个辅助函数将收集输入和输出分布的矩。首先,我们应用 mcerp 的。描述()【函数】输入变量;然后,输出。


第一次模拟运行时没有预设的关联结构。当我们查看三个输入变量的相关矩阵时,我们看到大多数变量对的互相关接近于零。该模型抽取实际可行的独立或不相关的随机变量。

mcerp 的 plotcorr() 功能有助于可视化相关结构。
我们观察到几乎圆形的斑点,这表明相关性接近于零。

3.用相关随机变量模拟
在为下一次模拟做准备时,我们将对模型施加一个估计的相关结构。
- 销量和售价一定是负相关的。更高的价格会减少需求,所以交易量会减少。我们用负系数-0.3 来表示这种关系。这实际上是一种单向关系:价格影响需求量:较高的价格导致较低的需求量。但是更高的需求不会导致更低的价格,恰恰相反。在一个更复杂的模拟模型中,我们将通过额外的变量来表达这种单向关系,这些变量将识别因果机构。在这个快速教程中,我们过于简化了。
- 价格和材料单位成本:计划者假设当供应商提高原材料价格时,企业将能够提高自己的销售价格,但不能完全与原材料成本趋势同步。只有 70%的供应商成本增加可以被客户接受的更高的销售价格抵消。这也是一种单向关系。较高的原材料单位成本会促使企业提高销售价格。但是较低的销售价格不会对原材料供应商的价格策略产生影响,他们不会相应地降低自己的价格。我们保持模型简单,不在销售价格和供应商价格之间的关系中分割这两个方向。
- 相关系数应由规划者结合投入变量的分布进行估算。当然,任何未来的相关性结构都会受到不确定性的困扰。我们可以通过将相关系数表示为随机变量本身来处理不确定性:规划者可以对一对输入变量之间的相关性进行三点估计——最小、可能、最大;然后,三角形或 PERT 分布将连接这三个点,并绘制相关云作为模拟将遍历的 10,000 次迭代的随机变量。
通过调用 mcerp 的 correlate() 函数,我们将这种有针对性的相关结构应用于输入变量。
每个输入变量的 10,000 个值保持不变。但是 correlate() 函数运行 Iman-Conover 方法,该方法通过对它们重新排序来对它们施加新的等级相关性,例如,高销售价格值与高材料单位成本值成对出现。
plotcorr() 函数绘制每对变量的散点图。

让我们比较一下重新校准关系前后的相关结构。右边:初始的,几乎独立的随机变量。在左边,我们使用了新的关联结构。在右下角拉长的图形中,可以看到销售价格和材料单位成本之间的强正相关关系。价格和交易量之间更温和的负相关性导致了具有相反方向的椭圆点云,但在左上角具有更分散的扩散。

我们检查模型实现的关联结构。
我们只看到与目标相关性的微小偏差,高达 0.002。

几乎为零的初始相关性被修改了相对较大的数量,在-0.303 和+0.71 之间。

接下来,我们检查第二个模拟模型的输出,并在数据帧中收集它们的 10,000 个值。

我们绘制了主要模拟输出的直方图,即毛利。
它看起来与第一次模拟的结果没有太大的不同。它是否因为我们强加的关联结构而改变了?

让我们计算它的分布矩。
当我们比较毛利时刻——在重新调整相关性之前和之后——我们确实观察到了变化的结果。相关的输入变量导致了较低的均值、较低的偏斜度和峰度,与初始的不相关模型相比,每一个都降低了几个百分点。不过,标准差已经减半了。从这个意义上说,模型变得更加稳定,或者说更加以平均值为中心。

发生了什么事?通过关联三个输入变量,我们将搜索空间缩小到实际相关的参数组合。初始模型还必须评估难以置信地将极高价格与极低材料单位成本(反之亦然)结合在一起的参数元组,以及极高和极低销售价格下的巨大销量,许多这些不切实际的场景通过强加相关结构而被归入异常值状态。在 10,000 次试验中,异常情况出现的次数较少,因此结果更紧密地围绕€ 48,513 的平均结果。因此,相关结构有助于模型关注更相关的参数元组;这种相关性不会消除异常值,但会将更多的异常值推到背景中。
让我们通过两个 seaborn jointplots 来可视化更窄的搜索范围:

在左边近乎完美的圆形图表中,销售价格和原材料单位成本是独立的,但在右边的椭圆中却高度相关。椭圆将两个随机变量的更多质量集中在更紧密的区域,因此留下更多空白背景空间。
接下来,我们创建一个由几个频率组成的范围,我们要计算这些频率的分位数,以了解临界点处毛利分布的形状。Numpy 的分位数函数将出现的频率转换为 x 值:至少有 q%的时间会出现的毛利。字典收集频率 q 和产生的分位数 xq,然后第 11 行的 list comprehension 逐行打印它们。
我们观察到,在 90%的概率下,毛利将超过€ 32,180(相反,只有 10%的场景会导致利润低于 10%的分位数)。有 90%的概率,利润不会超过€ 57,936。

模拟输出的矩和分位数为决策者提供了丰富的信息。
在这种情况下,新产品产生损失的风险(远远)低于 0.1%,如分位数表所示。
中间利润是€48251 英镑。平均利润我们可以预期达到€ 48,513。
机会和风险(低值或负值异常值)的分布相当均匀,表现为偏度和峰度都接近正态分布。
4.结论
当我们准备第二个模拟模型时,我们在它的三个输入变量上强加了一个关联结构:数量、价格和材料单位成本。这种相关性将不切实际的参数组合推到了背景中,并帮助模型聚焦于似是而非的参数元组。因此,产出变量的标准偏差显著降低。模拟变得更加紧密地以平均结果为中心。
在现实世界的场景中,我们将不得不面对这样一个问题:我们不仅要确定输入变量将遵循的分布,还要确定它们之间的关系。有时,在我们建立 MC 模型之前,历史数据将使我们能够从实际观察中导出输入的参数和相关性。但是如果历史数据不可用,MC 方法也可以解决这个问题。
如果你记得以前的 MC 文章( Python 驱动的蒙特卡罗模拟)及其关于嵌套随机变量的章节,你很快就会得出结论,我们已经讨论了一种方法,它应该能够处理未知相关结构的不确定性。
我们将两个威布尔分布参数的估计值建模为两个随机变量。打个比方,我们可以把相关系数定义为随机变量;例如,通过将 PERT 分布映射到它们。规划者——可能只有我们这些数据处理者——应该在 3 点估计上达成一致:变量对之间最小的、可能的和最大的相关性。然后,PERT 或三角分布将处理相关结构,就像它处理随机变量的其他变量一样。相关性的不确定性只会在模型进行 20,000 或 100,000 次迭代时引入一些增量抖动。
当我们面临不确定性时,我们应该尝试对模型假设的波动范围做出一致的估计。然后仿真模型会把它拿起来。蒙特卡罗方法的魅力在于它适用于各种包含不确定性的问题,包括那些无法确定闭合形式方程的问题。
我们只需要考虑大量的假设变量需要更多的迭代次数。对于 20 或 50 个输入随机变量,我们应该将最大迭代次数提高到 10,000 次以上,以确保我们不会在多维搜索网格中留下空白。
然后,MC 方法将接管并通过数值求解变量的相互作用返回模型解。
Jupyter 笔记本可以在 GitHub 上下载: h3ik0th/mcerp1: Python 蒙特卡罗模拟(github.com)
- 标题图片:pixabay 上的 Nikodi,免费用于商业用途
- 其他图片:作者
通往神经元中心的旅程
潜入大脑的咸水海洋,更接近激发我们的人工智能系统并使你的想法成为可能的实体。探索如何理解人工和生物神经元之间的差异可能会给我们提供线索,如何走向更灵活的人工智能。
“百万灵魂的声音”,2 分钟的艺术献礼,向我们的皮层列和新皮层中的数十亿神经元致敬(8K 质量)。将 youtube 设置为 4K 或 8K 分辨率+全屏,以获得最佳体验。“当我们接近宏伟的圆柱时,神秘的图案用百万灵魂的声音从远处召唤我们……我感觉最明亮的太阳被压缩在那些微小的奇迹中..变成了在我们意识中产生共鸣的梦的织锦..我听到你笑了..我听到你坠落…我听到你的眼泪摧毁了地平线..直到我们在寂静等待的圆柱中心汇合..寂静,然后百万个太阳向着一个新存在的觉醒刺来..抱紧我..让我们直入主题,直入专栏的中心..你和我在寂静中合而为一..”/作者 Javier Ideami 创作的视频艺术作品和诗歌|https://ideami.com
你的每一个想法都是通过你的生物神经元实现的。许多最有用的人工智能架构背后都有一个受其启发的实体。神经元处于处理过程的中心,这些处理过程支撑着智能系统产生的复杂性。好奇想知道更多关于你的想法的引擎,以及它们与它们的人工对应物相比如何?我们开始吧!
人工智能神经元最初受到我们生物神经元的启发,然而它们非常不同。为什么不应该呢?有许多方法可以到达同一个目的地,就像人类的飞行受到启发,但不会一部分一部分地模仿鸟类的飞行方式一样,我们的人工神经元也只是部分地受到了生物神经元的启发。
然而,我们的生物神经元比我们的人工神经元要复杂得多,包含了如此丰富的细节和如此多的秘密。即使我们不需要复制生物神经元的工作方式,理解两个实体之间的不同****也可以给我们新的线索关于如何走向更灵活的人工智能形式。
在本文中,我们将回顾这些差异,以及与这些神经元嵌入的网络有关的一些差异。我们还将考虑这些差异如何为即将到来的未来提供新的可能性。
注 : A.I 是一个广阔的领域。在这个地区有各种各样的外来物种。在进行比较时,我将专门参考一些当今最典型和最流行的深度学习架构。

神经泉瀑布,作者 Javier Ideami |【https://ideami.com
神经元:盐水和电
在我们深入研究神经元功能的细节之前,让我们先快速了解一下内部。这要变咸了!
- 把你的大脑想象成一个装有盐水海洋的容器。在那片海洋中,你有很多我们称之为神经元的细胞和很多离子。离子是正负电荷不相等的原子。而你大脑中的主要离子有:钠(Na+)钾(K+)钙 (Ca++)和氯 (Cl-)。这很好地提醒了我们为什么这些矿物质如此重要!
- 所以,生物神经元和大多数细胞一样,基本上是由盐水组成的,氯离子和钠离子漂浮在周围。并且一个神经元所做的一切都可以用电学 : 电压(例如,存在于神经元细胞膜上的电势/电压)和电流(带电离子进出神经元的流动)来解释。
- 人工神经元是用计算机代码创建的,该代码在执行时创建由数字字节组成的数据结构,以此类推。人工神经元所做的大部分事情都可以用数据的计算、线性和非线性转换来理解。
咸咸的海洋 vs 硅的仙境。什么更高效?让我们来看看。

作者 Javier Ideami |https://ideami.com绘画
能源:20 瓦的优质服务
信息处理需要能量,所以这些神经网络内的能量消耗很重要。它为可能的事情设定了界限,我们的大脑非常高效。
- 现在,当想法在你的头脑中移动时,你的大脑只消耗了大约 20 瓦的能量,勉强够点亮一个灯泡。它能够做到这一点,即使你禁食或睡觉,并保持大约 37 摄氏度度的适度温度。
- 我们的深度学习系统经常使用的强大的GPU每单位可以消耗数百瓦,比我们的大脑多得多,并且它们释放大量热量,达到大约 70 或 80 摄氏度的温度。
最新消息:让人工智能系统更加节能的研究正在进行中。连接和激活的稀疏性可能有助于这些系统接近我们大脑的巨大效率,在任何时候,只有一小部分神经元是活跃的(通常在 0.5%和 2%之间)。
功能:全方位检测
我们已经审查了环境和能源消耗。是时候放大这些实体之一了。神经元在做什么?
- 它检测来自它接收的许多输入的模式。我们的大脑中有大约 1000 亿个神经元(估计各不相同,一些专家说实际数字大约是 860 亿),每个神经元接收来自大约 10000 个其他神经元的输入(有人说大约 7000 个,有人说 8000 个,总之有数千个)。
- 生物神经元有一个阈值和,当超过该阈值时,它会发出一个信号,我们称之为动作电位或尖峰。该信号沿着其轴突(神经元的输出)向其他神经元的突触传播。
- 突触是一种允许一个神经元向另一个神经元传递信号的结构。突触位于神经元的树突(其分支)。
- 因此可以用这个过程总结生物神经元:接收输入,对它们进行积分,判断该积分的结果是否足够强以触发输出信号。
- 另一方面,人工神经元、执行计算、将其输入与其各自的权重相结合(权重是指定该神经元与其每个输入之间的连接强度的数值)。
- 结果是通过激活函数(计算其输入的非线性变换的函数。这使得网络能够学习输入和输出之间的非线性映射)。
- 所以你可以用这个过程来概括人工神经元:接收输入,将这些输入中的每一个乘以它们与该神经元的连接强度的结果相加,通过非线性函数传递那个计算的结果。
怎么了:注意一个关键区别。生物神经元有一个阈值,这个阈值使它们保持沉默,直到被超过。深度学习系统中的大多数人工神经元产生主动输出(一些可能输出 0。例如,如果输入小于 0,ReLU 激活函数将神经元的输出设置为 0)。正如我们稍后将强调的那样,在任何时候,我们大约 0.5%至 2%的生物神经元是活跃的,而在典型的人工深度学习系统中,这一比例约为 50%。

作者 Javier Ideami |https://ideami.com绘画
到处都有电
让我们暂时回到生物学领域的电的一面。我们经常听说我们的神经元通过电脉冲进行交流。让我们深入到电的维度,以便我们能够更好地内化正在发生的事情。
- 电压是一个地方的电荷和另一个地方的电荷之间的比较(相对而言)。
- 神经元中的电压通常用毫伏来测量。毫伏是千分之一伏。我们的微小神经元使用微量的电来进行它们的操作。
- 要强调的一个关键点是神经元的膜电位(电压)。这是神经元相对于其外部空间的电压。我们称之为膜电位是因为它位于神经元的膜上,也就是一层薄薄的脂肪。
- 当两个区域之间的电荷存在差异时,电荷将倾向于流动,以补偿的差异并均衡情况。
- 神经元的膜充当了内部电流和外部电流之间的屏障。我们称之为的离子通道就像屏障中的小隧道,允许物质以可控的方式流动。
- 电导,开口的大小,决定了这些离子流入和流出膜的速度。
- 因此当电压(电势)存在时,两个区域之间的电荷存在相对差异,离子流动以平衡事物。但是为什么呢?因为异性电荷相吸,同性电荷相斥的普遍原理。例如,在某个特定的环境中,正电荷比负电荷多,就会形成一个电流来平衡这种情况,将更多的负电荷带入该区域。
- 触发阈值(或动作电位阈值),是神经元膜上必须达到的电压,以使神经元通过其轴突触发输出信号(动作电位)。该阈值为通常在约-50mv(毫伏)处。
- 神经元的所谓静息电位在 -70mv,,低于触发阈值,因此默认情况下神经元不会触发。****
- 这个门槛的重要性不能被夸大。由于它的存在,只有最强烈的激活水平通过神经元的轴突(其输出)进行交流。这使得信息以一种非常紧凑和有效的方式被编码。
- 还记得我们开头提到的那些 20 瓦的能耗吗?生物 神经元只交流相关和关键信息。其余的,他们保持沉默。
让我们提醒自己,我们没有理由复制或模仿生物神经元的复杂性。我们可以创造出以完全不同的方式展示灵活的智能形式的系统。而且方式越简单越好。但是深入了解我们的生物神经元可以给我们一些想法,这些想法可以丰富我们在使用人工神经元时的实验和策略。

作者 Javier Ideami |https://ideami.com绘画
是时候了:扣球还是不扣球?
两种神经元之间的一个非常重要的差异(T3)与时间维度(T4)有关。
- 生物神经元在非常短暂的时刻发出信号。它们发出尖峰,持续时间非常短(通常在 1 毫秒左右)。由神经元传输的信息在那些尖峰的时序中被编码。尖峰序列是一系列尖峰和静默。****
- 在每一个尖峰之后,神经元的膜电位返回到一个小值(它甚至可以低于其静止电位)。为了使再次达到峰值,电压需要回到高于点火阈值的水平。
- 当学习过程发生时,一个神经元有助于激活其他神经元 的效率可以动态改变通过长时程增强(LTP)等过程,这些过程对我们学习和创建记忆的方式至关重要(长期抑郁是 LTP 的相反过程)。
- 大多数人工神经元都是一般不断地产生输出(在每个执行周期中),向线下的下一个神经元发送连续的信号(有时它们的激活函数可能会将它们的输出设置为 0)。
- 所以,在大多数人工深度学习网络中,时间维度是不相关的。在我们的生物网络中,它的使用方式本身没有门槛。我们的人工系统要简单得多。但是有时候越简单越好。今天深度学习系统的发展方向足以将我们带到专家们喜欢称之为 AGI(人工通用智能)的地方吗?或者更灵活的人工智能?。关于那件事,还没有定论。
近况:****冯诺依曼架构是我们今天使用的大多数硬件背后的。为了更接近大脑的功能,一些研究人员开始研究其他类型的结构。神经形态计算就是一个例子。这种架构允许更多的并行处理和健壮性。最重要的是,它可以与脉冲神经网络一起工作,后者处理空间和时间维度,就像大脑一样。像 IBM 或英特尔这样的公司已经生产出了神经形态芯片。这一研究领域面临着许多重大挑战,既包括研究前沿,也包括必须应对与冯·诺依曼模型高度适应的现有生态系统。

作者 Javier Ideami |https://ideami.com
请留点空间:稀疏的魔力
当神经元相互结合时,在任何时刻激活的神经元的数量和它们之间的连接数量在能量消耗、弹性、健壮性和其他相关因素方面会产生很多后果。
- 当想法流过你的大脑时,平均只有大约 2%的神经元在放电。大部分都是沉默。因为在任何时候只有一小部分神经元是活跃的,所以噪音和其他失真很难干扰这些网络的模式检测过程。稀疏性使我们的生物网络具有弹性和强健性。
- 相反,在我们的人工深度学习网络中,大多数神经元都在中持续产生输出(一些可能通过它们的激活函数将其输出设置为 0)。这就是为什么深度学习系统通常非常脆弱,对我们称之为对抗性攻击/例子非常敏感的潜在原因之一。对抗性攻击是微妙的,网络输入的最小变化(通常我们的感知不可见),即在其输出中产生剧烈且不正确的变化。深度学习网络的非稀疏特性使得它们对其输入的变化更加敏感。当大部分权重都是相关的并且一直在发挥作用时,任何变化都会产生戏剧性的后果。****
- 但是稀疏性超越了激活。Numenta 是一家著名的研究公司,一群才华横溢的科学家和工程师将神经科学和机器智能研究结合在一起。他们的团队由杰夫·霍金斯和苏布泰·艾哈迈德领导。努门塔的团队已经非常深入地探索了大脑稀疏性的问题,以及与我们的新皮层如何运作相关的其他领域。我们可以从他们的工作、研究和出版物中学到的一件事是,我们的新大脑皮层在两个层面上是稀疏的。
- 首先,如上所述,就激活而言,最好的估计是,在任何时候,我们的生物神经元中有 0.5%到 2%是活跃的。
- 然后,我们也有神经元之间连接的稀疏性。当一层神经元投射到另一层神经元上时,Numenta 的团队告诉我们,目前的估计表明有 1%到 10%的可能神经元之间的连接存在。
- 相比之下,现在大多数深度学习系统都非常密集。 就连通性而言 100%密集,通常。大约 50%的激活率。
最新消息:利用稀疏连接和稀疏激活的新架构是一个正在进行的研究领域。不管 A .我不一定要复制大脑做什么,稀疏作为一种策略,在构建更有弹性和更健壮的系统的任务中非常有意义。

作者 Javier Ideami |https://ideami.com绘画
输入和参数
最终我们想用这些神经元来学习。所以现在让我们更深入地了解这些网络为了产生学习而调整的旋钮。之后,我们将研究学习算法本身。我们从比较两种神经网络的输入和参数开始。
- 在生物网络中,你可以有 3 种类型的输入 : 兴奋性(使接收神经元更容易激发)抑制性(做相反的事情)和泄漏(与抑制性的功能相似)。
- 如前所述,这些输入通过突触、发送和接收神经元之间的连接点与接收神经元对接。大多数突触位于接收神经元的树突上。
- 树突是从神经元上分出的分支(树突来自希腊语- dendro -,意为树)。在树突处,不同的输入信号被整合。这些树突上有小刺。正是在那里来自发送神经元(轴突)的输出接口(突触)建立与其他神经元的连接。
- 在人工网络中,通常有单一类型的输入,通常有多个相关联的权重(表示该输入与连接到它的多个其他神经元之间的连接强度的数字,每个连接一个权重)。
- 那些权重保存可以是负的或正的连续值。每个权重值,结合在神经元上执行的计算,实际上将有助于使接收神经元或多或少地活跃(类似于前面描述的兴奋-抑制动态)。
- 因此,在生物神经元中,有这种兴奋和抑制信号之间的战斗。这场战斗的结果决定了细胞膜上的电压。为了让神经元激发,膜电压需要超过动作电位阈值。
- 在人工神经元中,事情更简单。没有明确的阈值和,每个权重的不同强度(正或负)组合起来或多或少地刺激接收神经元。
让我们更接近两个实体的参数。
- 在生物网络中,我们有突触权重的概念,它决定了来自发送神经元的信号通过其突触连接对接收神经元 的影响。
- 更近一点来说,这种影响所代表的是发送神经元的动作电位释放神经递质、以及这些神经递质打开接收侧突触通道的能力。
- 在人工网络中,我们有权重来决定发送和接收神经元之间每个连接的强度。而那些重量就是简单来说就是数字。它们可以是浮点数、整数、单比特等。
- 因此,尽管人工重量是一个简单的数字,生物突触重量取决于许多因素。这些因素包括,例如,可以释放到突触中并在另一侧被吸收的神经递质的数量(在这里,特定种类的受体和离子的数量开始发挥作用),信号在轴突中移动的程度(轴突中的髓鞘化对此有影响),信号传播的效率以及轴突和接收神经元的树突之间的数量。正如我们所见,这远远超出了一个简单的数字。
这些就是这些网络的参数。还有把拉远一点,他们代表着什么?
- 一般来说,这些权重代表一个神经元对什么敏感, 它正在检测什么。如果一个权重值很大,它意味着相关神经元对它正在接收的输入非常敏感。
- 因此,我们可以感觉到学习过程,在两种情况下,都与改变和调整这些权重有关,随着学习的进展,在网络中产生不同的模式。
- 所以,为此做好准备:你的每一个想法和记忆都由突触权重模式来代表。类似的事情也发生在我们的人工网络中,数字权重模式代表不同抽象层次的信息,这些模式在整个学习过程中不断进化。
我们得到了结构、输入、参数和输出。该学习了!

作者 Javier Ideami 的绘画|【https://ideami.com T3
学习:反向传播和超越
为了让学会,我们需要调整那些权重,那些参数,并且朝着正确的方向去做。但是怎么做呢?学习算法是什么?
- 在我们的人工深度学习网络、反向传播、结合梯度下降、是典型的 算法的选择。
- 例如,在受监督的系统中(我们提供一个带有标签的数据集,比如一些带有标识动物种类的标签的动物图像),我们运行网络,然后计算它的性能、它的损失值或误差(我们正在获得的和我们想要获得的之间的差异)。
- 然后,从网络的输出开始并向其输入 ( 反向传播当前损耗值,这就是为什么我们称之为反向传播),我们使用演算及其链式法则到的力量计算网络的每个参数对最终损耗值的影响。我们能够做到这一点,因为在神经网络的不同层执行的所有计算都是可微分的。
- 一旦我们知道调整每个权重将如何影响网络的最终损失值,我们就可以继续调整每个参数 使最终损失值最小化,我们的目标和我们在每个时刻的位置之间的差异。
- 如果我们继续重复这个过程,沿着这些梯度向下移动,我们将到达一个地方,在这个地方,我们所有权重的组合产生的计算在我们的目标值和我们当前的网络输出之间产生一个非常小的差异。学习已经发生了。
- 那么我们的生物网络呢?大脑中是否存在类似于反向传播的现象?围绕这个有争议。一些专家认为大脑中可能有正在进行的事情,虽然与不同,但可能与反向传播有相似之处。其他人认为我们的生物网络学习方式与之无关。因此,评审团仍未确定,这一领域有很多活跃的研究。
怎么了:反向传播是一个很棒的学习算法。然而,像任何算法一样,它有优点也有缺点。如果我们超越了在大脑中寻找类似反向传播的东西,并考虑其他选择,会怎么样?研究员 Ben Goertzel 是 AGI 领域的专家,他认为我们最终会超越反向传播,使用其他种类的学习算法,以更好的方式适应未来 AGI 系统的需求。这些可能包括应用于复杂神经架构的 CMA-ES 类型的进化算法。
Ben 告诉我们,如果我们使用这些进化算法,我们就可以,例如,使用推理进行适应性估计和其他策略来指导进化学习过程,这些策略在我们使用反向传播时更难实施。
Ben 提出了一个非常有趣的问题:有多少神经架构仅仅因为不适合与反向传播算法一起工作而被丢弃?这是一个很好的提醒,让我们的选择和思维对新的可能性保持开放。
我们的大脑受益于两种学习过程: 进化过程将编码在我们的基因中,而则发生在我们一生中的神经网络中。在我们的人工网络中结合这两种方法可以打开新进展的大门。
进化:运动中的一切
这就把我们带到了这些神经结构的进化方面。
- 现在,你大脑皮层中的神经网络已经和几个小时前不同了。他们从未停止进化。
- 总的来说,缩小来看,在我们的生物网络中,有许多不同层次的优化过程在进行,不仅在参数方面,而且在网络本身、结构、算法等层面(例如,与我们的基因组相关)。
- 当处于活动状态时,我们典型且最受欢迎的人工深度学习系统 通过使用反向传播来优化它们的参数(权重),而就是这样。架构本身保持静态,除了我们不时对其超参数进行的更改(手动或通过 autoML 、网格搜索和其他类似选项)。
最新进展:关于自我优化机制的研究这可能允许深度学习架构随着学习过程的进行,转变和进化它们的结构并优化它们的策略,这可能使我们的人工网络更具适应性和灵活性。像 Kenneth Stanley 教授这样的研究人员已经对朝着这个方向发展的动态系统产生了非常有趣的结果。

神经森林,作者 Javier Ideami 绘制|https://ideami.com
何时:持续学习
这些学习过程需要多长时间?
- 在我们当前最典型的深度学习网络中,训练过程有开始和结束。我们首先训练,完成学习过程,然后执行我们所谓的推理。我们在一个单独的过程中将这种学习应用于以前未见过的数据。
- 随着新数据的到来,我们可以不断地重新训练我们的网络,并迭代地更新我们的模型。
- 在我们的大脑中,学习过程从不睡觉。持续的学习正在进行。当我们思考、行动甚至睡觉时,我们突触连接的强度也会发生变化。
最近怎么样:持续学习是人工智能社区的热门话题。我们知道,如果我们最终要达到一种更加灵活和强大的人工智能,学习需要有更多的连续性。这一领域正在进行大量的研究。
让我们社交吧
生物神经元比我们的人造神经元更加社会化。这是什么意思?
- 在典型的深度学习网络中,人工神经元在朝向下一层的单一方向上进行通信(反向传播计算反向进行),并且它们只连接到前一层和下一层。也有例外,但我们在这里谈论的是最典型的深度学习网络。
- 生物神经元可能在多个方向上进行交流,并拥有更广泛和更丰富的连接(同时也是更稀疏的那些)。一些神经元在皮质柱上下沟通。其他人有横向联系。我前面提到的时间方面为这个过程引入了一个更丰富的方面。
进展如何:利用更灵活和更丰富的连接形式的新型人工智能架构是另一个活跃的研究领域。例如,研究人员正在研究图形神经网络和其他使用超图和元图的架构。由 Ben Goertzel、创立的 singularityNET 项目、在这方面做了很多工作。它将区块链技术与人工智能服务相结合,产生了一个去中心化 A.I 网络。最近,该项目与 Cardano 生态系统合作,加速其向全球分散 AGI 系统的进展。

作者 Javier Ideami |https://ideami.com绘画
放大
为了完成我们的旅程,让我们暂时缩小一下。
- 参与我们智力高级部分的神经元位于我们的新大脑皮层。
- 我们的大脑皮层由微柱构成,每个微柱由大约 100 个神经元组成,这些神经元处理相似类型的数据。
- 许多微柱根据皮层柱构成,我们的新皮层中有大约 150000 个柱。
- 如果你有兴趣更深入地了解这些皮质专栏中发生的事情,我建议你去看看科学家兼企业家杰夫·霍金斯的书“一千个大脑:一种新的智力理论】,这是一本真正的杰作,他在书中剖析了他的团队在 Numenta 进行的最新研究。
如果你想进一步探索最近的神经科学研究如何为实现更具弹性、一致性和灵活性的人工智能指明方向,比如杰夫·霍金斯和他的团队所做的研究,你可以看看下面我写的另一篇关于这个主题的文章
百万灵魂的声音诗
“当我们接近宏伟的圆柱时,
神秘的图案用百万灵魂的声音从远处呼唤着我们……
我感觉到最明亮的太阳被压缩在那些奇妙的小点中..
简化成一幅在我们意识中产生共鸣的梦的织锦..
我听到你的笑声..我听到你坠落…我听到你的眼泪摧毁了地平线..
直到我们合并在纵队的中央,那里静候着我们..
寂静,然后百万个太阳向着一个新存在的觉醒刺来..
抱紧我..让我们直入主题,直入专栏的中心..
你和我在寂静中合而为一..”
—作者哈维尔·伊达米
jq:净化输入而不仅仅是输出的救星
有很多例子和教程使用 jq 来处理 JSON 输出或快速访问 JSON 主体中的项目。我在下面的参考资料中链接了几个我最喜欢的。
然而,当需要 json 作为 CLI 输入时,很少有人知道它的好处。这种用例的一个主要例子是与 AWS CLI 交互,我将在本文中向您展示这一点。

图片来源:作者本人
一个典型的程序员问题:
假设我们想使用aws ssm send-command工具向 ec2 实例提交一个命令。当ssh不可用时,这可能特别有用。
通常情况下,端口 22 (ssh)是不开放的,或者至少非常局限于少数几个 IP 地址。这篇 AWS 文章总结了无限制 ssh 访问的安全风险
为了通过 ssm 发送命令,我们可以使用以下代码:
instance_id="i-123456789"
aws ssm send-command \
--document-name "AWS-RunShellScript" \
--targets "Key=InstanceIds,Values=${instance_id}" \
--parameters "{'commands':['echo foo']}"
简单对吗?
不完全是这样,命令被发送给超级用户 sudo,但是在许多用例中,我们很可能希望提交给非管理用户,比如 ec2-user。我们可以通过在su "-" "ec2-user" -c '$command’中包装命令来做到这一点——因为我们已经在 parameters 参数上使用了双引号,$command周围的单引号不会意外地将它写成“文字”。
然而,我们仍然有可能在这里遇到一些不足之处。假设我们正在编写一个从 stdin 获取命令的函数,我们可能希望像下面这样编写一行程序,并将其保存为submit_to_ec2_instance.sh。
#!/usr/bin/env bash: '
Simple script that submits the command string from stdout in
to the instance id (sysarg 1)
'# The first input, should start with 'i-'
instance_id="$1" # Send our command from stdin to $instance_id
aws ssm send-command \
--document-name "AWS-RunShellScript" \
--targets "Key=InstanceIds,Values=${instance_id}" \
--parameters "{'commands':[\"su - ec2-user -c '$(</dev/stdin)'\"}"
如果用户决定用
echo "sleep '5'; echo 'done here'" | \
submit_to_ec2_instance.sh i-123456789
那么我们实例 id 上的su函数将接收以下参数:
-ec2-user-csleep 5; echo donehere
哦,亲爱的..这里的最后两个参数应该通过单引号合并成一个参数。好像我们在 stdin 周围的单引号和用户在他们命令里的单引号冲突了!
命令行上的参数由空格分隔,但可以通过使用单引号、双引号或转义空格来解释为一个参数。
在这种情况下,单引号提前结束。… -c 'sleep 5; echo 'done here''被错误拆分。解释器无法区分用户指定的内部单引号和 shell 脚本函数中设置的外部单引号。
一系列“不可行”的变通办法
以下每一条都是可行的,但至少有一条警告:
- 告诉用户不要使用单引号
但是如果他们不总是能控制输入呢?他们可能会盲目地将另一个命令的输出解析成这个命令?
2.使用类似 **sed** 的工具来确保我们将用户输入中的所有 **'** 都变成了 **\'**
这是一个好主意,但是如果他们已经转义了单引号,我们需要确保转义的单引号是双重转义的……编写一个类似于 shlex 的解析器会变得非常复杂和耗时。
3.回到 stdin 前后的转义双引号
然后,用户需要转义任何双引号。转义引号也需要双转义。同样,我们要么期望用户转义引号,要么编写另一个 shlex 工具。
啊呀,仅仅一个命令就变得复杂了!
jq 来救援了!
让我们回到起点,考虑将--parameters arg 作为字符串表示中的 json 对象。在下面的参考资料中,我们注意到 jq 对于查询 json 输出和简单的数据整理非常有用。对于生成 json 输入,它也非常有用。下面我们将使用jq和<<< bash here-string 来初始化一个 json 对象,使用jq填充它,它将为我们完成所有的转义处理,然后将它设置为我们的--parameters值。
让我们从最基本的 jq 输入开始:
$ jq <<< "{}"
{}
现在让我们用my_arg和my_val创建一个最小的 json 对象
$ jq '."my_arg"="my_val"' <<< {}
{
"my_arg": "my_val"
}
一个小警告是 jq 建议在它的过滤字符串周围使用单引号。为了在这个字符串中获得我们的命令行变量,我们需要使用
--arg参数。
让我们使用 jq arg 参数来尝试获取一个 json 对象,它看起来类似于 aws ssm send-command 参数 CLI 值的预期值。使用方括号[]是因为命令实际上是命令列表。
$ command="sleep '5'; echo 'done here'"
$ jq \
--arg key "commands" \
--arg value "$command" \
'.[$key]=[$value]' <<< {}
{
"commands": [
"sleep '5'; echo 'done here'"
]
}
整洁!该输出将所有内容放入一个参数中,如上所述,这将在 sudo 帐户上运行,而不是在 ec2-user 帐户上运行。为了给我们的值参数添加前缀,我们可以使用+过滤器命令来插入我们的前缀。
$ command="sleep '5'; echo 'done here'"
$ jq \
--arg key "commands" \
--arg value "$command" \
'.[$key]=["su - ec2-user -c " + $value]' <<< {}
{
"commands": [
"su - ec2-user -c sleep '5'; echo 'done here'"
]
}
我们很接近了!这仍然有之前的引用问题,幸运的是我们可以使用tojson方法来避免command中的任何双引号。
jq 过滤器字符串中的
\()相当于 shell 的$()命令调用。
$ command="sleep '5'; echo 'done here'"
$ jq \
--arg key "commands" \
--arg value "$command" \
'.[$key]=["su - ec2-user -c " + "\($value | tojson)"]' <<< {}
{
"commands": [
"su - ec2-user -c \"sleep '5'; echo 'done here'\""
]
}
吼吼!让我们也添加几个已经转义的引号,看看 jq 对它们做了什么
$ command="sleep '5'; echo 'done here' \"with escaped quotes\""
$ jq \
--arg key "commands" \
--arg value "$command" \
'.[$key]=["su - ec2-user -c " + "\($value | tojson)"]' <<< {}
{
"commands": [
"su - ec2-user -c \"sleep '5'; echo 'done here' \\\"with escaped quotes\\\"\""
]
}
太棒了!我们现在可以这样写我们的submit_to_ec2_instance.sh
**#!/usr/bin/env bash** : '
Takes in command from stdin and an instance-id positional argument
Submits command to ec2-user on instance-id
'
# Step one -> Collect the instance id
instance_id="$1" # The first input, should start with 'i-'
# Escape quotes from command, set up parameter arg as json string
# This should evaluate to (with escape quotes as necessary)
# {
# "commands": [
# "su - ec2-user -c "my-command arg1 arg2..."
# ]
# }
parameter_arg="$(jq --raw-output \
--arg key "commands" \
--arg value "$(</dev/stdin)" \
'.[$key]=["su - ec2-user -c " + "\($value | tojson)"]' <<< {})"
# Now run the aws ssm send-command function with our instance id
aws ssm send-command \
--document-name "AWS-RunShellScript" \
--targets "Key=InstanceIds,Values=${instance_id}" \
--parameters "${parameter_arg}"
我应该什么时候使用这个?
理想情况下,如果我们经常在 CLI 上与 AWS 交互,我们会在 python 脚本中使用类似于 boto3 的模块来组织我们的参数。然而,在这种模块和高级语言可能不容易获得的情况下,上述代码是有用的。
这种情况的一个例子可能是外部 CI/CD 执行器,如 GitHub Actions 或 TravisCI ,在这种情况下,我们需要在每次执行代码时安装高级语言(如 python)和任何所需的模块。通过使用类似上面的简单 shell 脚本,CI/CD 可以获得一个全新的 ubuntu 安装,安装 jq 到 apt-get ,然后运行一个快速 bash 脚本将我们的请求提交给我们想要的端点。
另一个用例可能是将这个脚本设置为您的.bashrc中的一个简单函数,而您对 python 和 boto3 的可访问性可能取决于当前的 venv 或 conda 环境。这里,使用 jq 会更合适,因为 bash 函数总是可以工作的——假设 jq 已经被全局安装。
当事情变得越来越复杂时,应该从 bash 这样的简单脚本语言转向 python 这样的高级语言。高级语言可能会提高你的代码可读性,节省你编写和维护代码的时间,并且在捕捉/处理错误方面做得更好。
资源
- 启发了这篇文章的 StackOverflow 答案
- jq 手册
- Jonathan Cook 的 jq 教程,深入研究了 json 输入的整理
Python 中的 JSON 和文本数据
如何在 Python 中集成非常流行的 JSON 数据格式来存储文本数据。

作者图片
在这个故事中,我们将关注 JavaScript 对象符号或 JSON,这可能是世界上首选的数据交换格式,也是对更传统的文件存储选项(XML、CSV、TSV)的必然升级。
我们将介绍创建和加载 JSON 文件、文件存储和换行符分隔的 JSON 存储的基础知识,并研究使用文本数据和 JSON 的更具体的用例。
为什么选择 JSON
JSON 在 web 应用程序中被广泛用作交换数据的首选方式,尤其是在前端和后端中间件之间。
- 它可以异步加载信息,因此您的网站响应更快,可以更容易地处理数据流。
- 当从另一个站点交换数据时,您还可以使用它来克服跨域问题。
- JSON 比以前万维网上的标准标记语言 XML 更简单、更轻量级。
除此之外,它还有四个优点,特别是对于文本数据。
JSON vs. CSV 和 TSV
与更传统的文本数据存储格式(如逗号分隔文件(CSV)或制表符分隔文件(TSV ))相比,它通常更好,因为您的文本数据永远不会包含这些文件的文件分隔符。
我期望我的输出有三列:文本、年龄、姓氏,但是因为是复合句,我现在有 5 列。一种解决方法是使用一个在文本中从未出现过的分隔符。竖线|更不常见,但是你仍然不能 100%确定文本中不包含竖线。
CSV 和 TSV 文件将一切转换为strings,但是 JSON 对象可以包含任何东西:lists, strings, dictionaries, floats。完美的数据存储!
标签属性
JSON 由一个键值映射组成,就像 Python 字典一样。这使我们能够标记我们的属性。嵌套的 JSON 对象也很常见。
map = {label1: attribute1, label2: attribute2}nested_map = {
id1: {attribute1: label1, attribute2: label2},
id2: {attribute1: label1, attribute2: label2}
}
JSON 对熊猫数据帧
我认为 JSON 优于 Pandas DataFrames,尤其是对于文本数据。数据通常有多个(嵌套)级别,例如在命名实体识别的情况下,数据集可能如下所示:
但是当在 Pandas 数据框架中加载这个数据集时,我该如何处理entities?我是把它们放在一栏里,还是把它们放在不同的栏里?一句话里有多个实体怎么办?我还需要全部打开吗?
Python 的 JSON 基础
函数中带附加s的 JSON 用于编码/解码字符串,不带附加s的 JSON 用于编码/解码文件。JSON 所做的是将 Python 对象转换成受 JavaScript 对象字面语法启发的格式。Python 对象到这种格式的默认转换如下图所示。它支持 Python 中的所有标准对象。

Python 对象的默认 JSON 编码器
重要说明
JSON 期望键-值映射中的每个键都是唯一的,没有简单的方法来避免这一点。非唯一键,或者如下例所示进行求和,或者在处理其他数据类型时被覆盖。
**>>>** weird_json = '{"x": 1, "x": 2, "x": 3}'
**>>>** json.loads(weird_json){'x': 3}
JSON 文件
JSON 对象非常类似于 Python 的键-值字典映射,因此当保存到文件中时,它只是一个很长的字符串,在一行中表示字典。由此产生的一个问题是,对于 Sublime 或 Pycharm 这样的文本编辑器来说,打开文档会变得非常沉重,并且降低了可读性。
减少负载和提高可读性的一个选择是在转储 JSON 时使用indent参数。另一个有用的论点是sort_keys,那好..在保存文件之前对关键字进行排序。
**>>>** with open("out.json", "w") as json_out:
json.dump({'b': 5, 'a': 7}, json_out, indent=4, sort_keys=True) {
"a": 7,
"b": 5
}
JSON 换行符分隔文件
保存 JSON 的一个非常常见的方法是保存数据点,比如一个列表中的字典,然后将这个列表转储到一个 JSON 文件中,如nested_text_data.py中所示。另一个更新的选择是使用 JSON 换行符分隔的 JSON 或ndjson。这种格式将每个 JSON 数据点保存在新的一行上。一个巨大的优势是,您可以迭代每个数据点,而不需要将整个对象(列表)加载到内存中。
{"text": "Hi my name is Louis", "age": 26}
{"text": "Hi my name is Max", "age": 22}
Python 中有一个库jsonlines用来写这些文件。
JSON 和 HTML 实体
你见过 JSON 数据& > <中的& > and <的 ASCII 格式表示或者不间断空格 吗?
数据经常以 JSON 格式作为来自 API 或 web 服务的响应。因此,文本数据(1)为 ASCII 格式,并且(2)非 Unicode 字符被转换为 Unicode 表示形式\u2014:
"Ik wil de te naamstelling van mijn betaalrekening & pas aanpassen Mej. \u2014-> Mw."
这个 StackOverflow 线程建议在转储这个 JSON 时使用ensure_ascii=False标志。在阅读了[json.dump()](https://docs.python.org/2.7/library/json.html#basic-usage) 文档和【StackOverflow 线程之后,我明白了确保 ASCII 是很重要的,尤其是如果你不确定你的 JSON 的格式,如果你使用一个 web 服务 API 的话,经常会出现这种情况。此外,它没有解决我的 HTML 实体问题…
解决方案是 HTML 库中的[html.unescape()](https://docs.python.org/3/library/html.html),它从字符串中转义所有的 HTML 实体。
模块化 JSON 编写函数
我使用一个自定义函数来编写 JSON 对象。我喜欢这个函数,因为它有助于我进行静态文件管理:在文件名中添加日期和时间,并在我保存文件的地方提供日志反馈。
如您所见,我还在一个包装器unescape_all_html()中包含了unescape.html()函数,用于我最常用的 JSON 数据格式:字典列表。找到下面的包装纸。
就是这样!我希望本指南向您介绍了如何在 Python 中使用 JSON(和文本)!快乐编码:)
朱莉娅和虚数:数字等级
对朱莉娅如何处理数字的深入探究

(图片由作者提供)
介绍
Julia 是一门伟大的语言,在处理数字时,它以其奇妙的方法而备受推崇。当然,在科学的奇妙世界里,这也意味着虚数,以及由一个假想的父母和一个真实的父母所生的复数。在很大程度上,朱莉娅对实数和虚数的处理绝对精彩。当这种语言与不太数学化的编程语言或者在发布时不打算被科学使用的语言相比时,这一点尤其正确。
Julia 的《数字的神奇世界》深入探讨了它的类型和超类型层次结构,并冷静地审视了超类型和多分派编程方法必须构建的非常复杂的类型系统,这些系统可以处理一系列操作,同时仍然保持相对简单的代码。
如果你想了解更多关于 Julia 的超级类型特征,我写了一整篇文章,你可以在这里查看!:
数字
在 Julia 中,数字层次的顶端是您可能熟悉的类型:
数字
数字是具有连续值的任何东西。数字可以是虚数、无理数,甚至是复数。在朱莉娅的书中,我们没有严格意义上的虚数。相反,我们使用复数的虚界,在这些类型中创建了我们的第一个层次划分。请注意,任何采用数字类型的函数都可以使用它下面的任何数字类型。这就是 Julia 中的超级类型如此独特和出色的原因,通过简单地对任意类型使用多重分派,我们可以从本质上限制我们类型的不同部分只处理特定的函数。然而,下一种类型不是任意的,因为它实际上是我们前面提到的复数。
这种类型的另一个初始划分是实数。如果我们有一个需要接受实数的函数,我们可以将实数类型转换成任何参数,这样就可以提供任何类型的数字,无论是 float64、Int64 还是其他。让我们来看看目前为止可视化的层次结构:

(图片由作者提供)
至于复杂类型,是存根。除此之外没有进一步的分类,它是语言中唯一可用于处理任何虚构的连续值的类型。记住这一点,让我们看看在 Julia 编程语言中实数的更多可能的分类。
实数
在 Julia 编程语言中有三种类型的实数:
- 漂浮物
- 不合理的
- 整数
您可能对其中一些类型很熟悉,因为我们在编程中经常会用到它们。然而,在这个层次结构中,还有更多类型存储在更低的位置,便于各种类型的浮点数和整数。然而,就无理数而言,该类型经过一个超类型抽象层,新类型将从该抽象层继承函数。这是为什么呢?
这样做是为了使更多的类型可以通过成为该类型的抽象版本的子类型来实现和利用相同的功能。回头看看类型层次,我们可以看到事情真的开始变得真实:

(图片由作者提供)
至于无理数,可能就是这样了,但是如果不使用浮点数和整数,还有更多的东西需要解开。Julia 支持 BigInt 和 BigFloat 数据类型,这是没有操作错误的巨大值。就科学和数值计算而言,这当然是语言的一个非常有价值的属性。进一步来说,我们有带符号和不带符号的整数,甚至还有另一个子类型,你可能在数字层次结构中找不到。
浮点数和整数
作为浮点类型的子类型,我们有 32 位浮点、64 位浮点和大浮点。当然,在大多数情况下,您将使用 Float64s,但是,根据您可能使用的数据类型和系统类型,大浮点和 32 位浮点有时确实很方便。更新我们的层次结构,我们看到所有这些浮动都是抽象浮动类型的直接子类型:

(图片由作者提供)
至于整数,我们需要从两个抽象类型开始,有符号和无符号。第一次听到这个,两者之间的区别可能是一个奇怪的问题。然而,答案很简单,无符号整数是一种不同的方式,计算机可以存储必须是正数的整数,然而有符号整数可以保存正值和负值,但容量不太大。我的建议是更多地使用带符号的浮点数,因为在 Julia 中我们也有大整数类型,它允许那些较大的数字作为单独的数据存储。

(图片由作者提供)
我们现在只缺少一种类型,实际上是布尔类型。布尔类型实际上继承了整数的所有数值、实数和属性。这就是为什么我们可以在 Julia 语言中添加 bool 类型,或者在 bool 类型上获得连续起源的条件返回。
结论
添加了 bool 类型后,我们的层次结构就完整了,现在我们在内存中拥有了 Julia 语言中所有类型的数字!作为最后一个有趣的观察,我将把所有的结构都涂成紫色,而把任意的类型都涂成青色。我认为这将给出一个演示,说明在这些不同的超类型下实际传递和分类了哪些类型。

(图片由作者提供)
我认为这些信息非常有价值,不仅对 Julia 程序员,而且对普通程序员以及科学界都是如此。看到数字分类被应用到一种编程语言中,并使用其特定的范例和方法,这真的很酷。我认为 Julian 的实现很有趣,也有点令人兴奋,所以我决定与你们所有人分享这些很酷的类型!我希望这篇文章读起来令人愉快,并且提供了比你需要知道的更多的关于 Julia 中不同类型的连续值的信息。感谢您的阅读!
Julia DataFrames.jl 基础
用 DataFrames.jl 戳戳你的数据

让我们探索一下 Julia 中 DataFrames.jl 的一些基本功能。如果你对 R 的 DataFrames 或 Python 的 Pandas 有一些经验,那么这应该对你来说是一帆风顺的。如果您没有以前的 dataframes 经验,不要担心,这是您可以想象的最基本的介绍!🌈
如果你在寻找更高级的东西?看看我关于朱莉娅的其他文章:
要获得所有媒体文章的完整访问权限,包括我的文章,请考虑在此订阅。

为什么是数据框架?我们已经知道 Julia 内置了对类似数组的对象的支持,那么我们为什么还需要另一种矩形数据格式呢?在数据科学中,很多情况下我们在同一个表中混合了数字和字符串数据。例如,考虑一个就业表。一列可能是这个人是否被雇佣(Boolean),另一列可能包含这个人工作的行业的信息(String),还有一列是作为float的薪水。DataFrames非常适合处理这样的数据,因为它将你的观察结果集中在一起,而不会因为混合数据类型而惩罚你。
数据框架允许你把你的观察结果放在一起,而不会因为混合数据类型而惩罚你。
在之前的帖子中(这里和这里)我已经展示了如何使用CSV.jl读取表格文件格式,所以我们将跳过这一部分,使用RDatasets包来处理一个真正经典的 iris 数据集。不要求知道这些数据中有什么,但是如果你好奇的话,这些数据来自 UCI 机器学习库。总的来说,这个表包含了一束漂亮的花的信息。
让我们摘些花吧🌼:
150×5 DataFrame
│ Row │ SepalLength │ SepalWidth │ PetalLength │ PetalWidth │ Species │
│ │Float64│ Float64 │ Float64 │Float64│ CategoricalValue │
├───┼───────┼────────────┼─────────┼────-──┼───────────┤
│ 1 │ 5.1 │ 3.5 │ 1.4 │ 0.2 │ setosa │
│ 2 │ 4.9 │ 3.0 │ 1.4 │ 0.2 │ setosa │
│ 3 │ 4.7 │ 3.2 │ 1.3 │ 0.2 │ setosa │
│ 4 │ 4.6 │ 3.1 │ 1.5 │ 0.2 │ setosa │
│ 5 │ 5.0 │ 3.6 │ 1.4 │ 0.2 │ setosa │
│ 6 │ 5.4 │ 3.9 │ 1.7 │ 0.4 │ setosa │
│ 7 │ 4.6 │ 3.4 │ 1.4 │ 0.3 │ setosa │
...
DataFrames.jl 的最新版本不再使用
head或tail,而是使用first(df, n)和last(df, n)功能!
如果您在 REPL,默认情况下,Julia 将打印结果对象—一个数据帧。如果没有,我们可以用head(iris)检查前几行:
julia> head(iris)
6×5 DataFrame
│ Row │ SepalLength │ SepalWidth │ PetalLength │ PetalWidth │ Species │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Cat… │
├─────┼─────────────┼────────────┼─────────────┼────────────┼─────────┤
│ 1 │ 5.1 │ 3.5 │ 1.4 │ 0.2 │ setosa │
│ 2 │ 4.9 │ 3.0 │ 1.4 │ 0.2 │ setosa │
│ 3 │ 4.7 │ 3.2 │ 1.3 │ 0.2 │ setosa │
│ 4 │ 4.6 │ 3.1 │ 1.5 │ 0.2 │ setosa │
│ 5 │ 5.0 │ 3.6 │ 1.4 │ 0.2 │ setosa │
│ 6 │ 5.4 │ 3.9 │ 1.7 │ 0.4 │ setosa │
这给出了数据集的前 5 行,您可以通过指定第二个参数来查看更多行,例如,head(iris, 10)将给出前 10 行。
想看看最后几排吗?使用
tail()。
数据框架基础
head函数已经给出了数据集的一个非常好的概述。它还打印列名、列类型和一些示例行。然而,有不同的方法获得相同的数据。
如果您正在寻找列名,请使用names,它会给出一个字符串数组:
julia> names(iris)
5-element Array{String,1}:
"SepalLength"
"SepalWidth"
"PetalLength"
"PetalWidth"
"Species"
如果你需要数据集的大小,使用size——这也适用于数组和矩阵!
julia> size(iris)
(150, 5)
所以我们有 150 行和 5 列。漂亮的一束花。
如果需要将类型的列作为数组,使用eltypes:
julia> eltypes(iris)
5-element Array{DataType,1}:
Float64
Float64
Float64
Float64
CategoricalValue{String,UInt8}
最后一栏看起来很特别。这是一个分类列,将字符串映射到无符号的 8 位整数UInt8。这基本上是一个因子变量,它使得存储数据更加有效,因为 Julia 只需要存储整数而不是字符串。所以我们知道Species列没有很多不同的级别,但是具体有多少呢?让我们找出答案。
摘要和简单索引
使用descirbe函数,我们可以很好地了解所有列。对于“种类”列,它甚至会打印唯一级别的数量:
julia> describe(iris)
5×8 DataFrame
│ Row │ variable │ mean │ min │ median │ max │ nunique │ nmissing │ eltype │
│ │ Symbol │ Union… │ Any │ Union… │ Any │ Union… │ Nothing │ DataType │
├─────┼─────────────┼─────────┼────────┼────────┼───────────┼─────────┼──────────┼────────────────────────────────┤
│ 1 │ SepalLength │ 5.84333 │ 4.3 │ 5.8 │ 7.9 │ │ │ Float64 │
│ 2 │ SepalWidth │ 3.05733 │ 2.0 │ 3.0 │ 4.4 │ │ │ Float64 │
│ 3 │ PetalLength │ 3.758 │ 1.0 │ 4.35 │ 6.9 │ │ │ Float64 │
│ 4 │ PetalWidth │ 1.19933 │ 0.1 │ 1.3 │ 2.5 │ │ │ Float64 │
│ 5 │ Species │ │ setosa │ │ virginica │ 3 │ │ CategoricalValue{String,UInt8} │
这可能会在你的机器上被奇怪地格式化,所以这里也有一个截图:

上表截图
你可以看到桌子上有三种不同的花。除此之外,我们还可以学习每个数字列的平均值以及平均值、最小值、最大值甚至中值。我们没有丢失数据。如果你问我,我会说这是一个非常好的数据集😉。
既然我们对正在做的事情有了一个清晰的概念,那就让我们开始切片吧。很常见的情况是,我们希望从数据集中提取一列或多列。我们可以通过按名称引用列或使用括号[]进行索引来做到这一点。我们可以使用字符串、符号或点符号:
julia> iris.SepalLength
150-element Array{Float64,1}:
5.1
4.9
4.7
4.6julia> iris.SepalLength == iris["SepalLength"] == iris[:SepalLength] == iris[1]
true
在选择列时,您有很多选择😃。
一旦选中,这些列就变成了普通的数组,因此对数组起作用的函数会按预期工作:
julia> sum(iris.SepalLength)
876.5julia> sum(iris.SepalLength .^ 2)
5223.849999999999
选择行也很容易。这里的技巧是,默认情况下,当我们使用整数作为索引时,DataFrames会查找列。要选择行,我们只需要用两个对象做索引。如果我们想要所有可用的列,我们可以传递一个冒号:作为第二个参数。
julia> iris[1, :]
DataFrameRow
│ Row │ SepalLength │ SepalWidth │ PetalLength │ PetalWidth │ Species │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Cat… │
├─────┼─────────────┼────────────┼─────────────┼────────────┼─────────┤
│ 1 │ 5.1 │ 3.5 │ 1.4 │ 0.2 │ setosa │
切片和数组也是有效的,所以我们可以说:给我们前 10 行(Julia 使用基于 1 的索引)和第 2 和第 4 列:
julia> iris[1:10, [2,4]]
10×2 DataFrame
│ Row │ SepalWidth │ PetalWidth │
│ │ Float64 │ Float64 │
├─────┼────────────┼────────────┤
│ 1 │ 3.5 │ 0.2 │
│ 2 │ 3.0 │ 0.2 │
│ 3 │ 3.2 │ 0.2 │
│ 4 │ 3.1 │ 0.2 │
│ 5 │ 3.6 │ 0.2 │
│ 6 │ 3.9 │ 0.4 │
│ 7 │ 3.4 │ 0.3 │
│ 8 │ 3.4 │ 0.2 │
│ 9 │ 2.9 │ 0.2 │
│ 10 │ 3.1 │ 0.1 │# you can have list of names to select columns too
julia> iris[1:4, ["SepalWidth", "Species"]]
4×2 DataFrame
│ Row │ SepalWidth │ Species │
│ │ Float64 │ Cat… │
├─────┼────────────┼─────────┤
│ 1 │ 3.5 │ setosa │
│ 2 │ 3.0 │ setosa │
│ 3 │ 3.2 │ setosa │
│ 4 │ 3.1 │ setosa │
屏蔽和过滤

我们知道如何根据名称或索引来选择行和列。但是如果我们想要根据它们的值选择行呢?一种方法是使用一个布尔掩码并将其传递给索引。让我们找出所有花瓣长度超过 6:
实现相同目的的另一种方法是使用一个高阶函数,例如filter。filter 函数有两个参数:
- 一个函数,它将类似数组的对象的一个元素作为输入,并返回一个布尔值。
- 一个类似数组的对象(在我们的例子中是一个 DataFrame ),我们可以对它进行迭代。
对于每一行,filter将应用 1 下的函数。当该函数返回true时,我们保留该行,否则,我们丢弃它:
注意,我们在 DataFrame 行上迭代,所以我们需要在函数中选择列!
符号 df
-> df.PetalLength>= 6是一个 lambda(无名)函数。
既然我们在高阶函数,这里还有一个:colwise。这个函数非常有用,尤其是如果您想获得每列的一些汇总统计数据:
julia> colwise(maximum, iris)
5-element Array{Any,1}:
7.9
4.4
6.9
2.5
CategoricalValue{String,UInt8} "virginica"
结论
阅读完本文后,您现在应该知道如何:
- 使用
RDatasets.dataset()获得简单的数据集 - 使用
head()打印前几行 - 使用
tail()打印最后几行 - 使用
names()查看列名 - 使用
eltypes()获得列类型的数组 - 使用
size()获取数据框架表的大小 - 使用
describe()打印数据的汇总统计 - 索引列和行
- 使用屏蔽数组或
filter()按单元格值过滤行 - 使用
colwise()对每列应用函数
如果你想了解更多,我推荐 Julia Academy 的优秀课程 Dataframes,该课程的主要撰稿人之一。
感谢一路读到最后!我希望你能找到一些对你的数据科学工作流有用的例子。
朱莉娅:数据科学的新时代
了解为什么 Julia 是数据科学的未来,并编写您的第一个 Julia 代码

封面照片由Starline | Freepik
介绍
Julia 是一种高级通用语言,可用于编写执行速度快、易于实现的科学计算代码。该语言旨在满足科学研究人员和数据科学家优化实验和设计实现的所有需求。茱莉亚(编程语言)。
“Julia 是为科学计算、机器学习、数据挖掘、大规模线性代数、分布式和并行计算而构建的”——开发者背后the Julia language。
Python 在数据科学爱好者中仍然很有名,因为他们获得了一个具有加载库的生态系统来完成数据科学的工作,但 Python 不够快或方便,并且它具有安全性可变性,因为大多数库是从 JavaScript、Java、C 和 C++等其他语言构建的。快速的执行和方便的开发使它在数据科学社区中非常有吸引力,并且大多数库都是直接用 Julia 编写的,以提供额外的安全层。信息世界。
根据 杰瑞米·霍华德T22【Python 不是机器学习的未来】。
在他最近的视频中,他谈到 Python 在运行机器学习模型时是多么令人沮丧,因为你必须使用 CUDA 等其他语言库,并且要运行并行计算,你必须使用其他库,这使得它非常具有挑战性。Jeremy 还建议,如果你想成为面向未来的人,那么开始学习 Julia,因为它将在几年内接管 Python。
朱莉娅
与 Python 相比,Julia 在多个领域处于领先地位,如下所述。
朱莉娅跑得很快
Python 可以通过使用外部库和优化工具进行优化,但是默认情况下 Julia 更快,因为它附带了 JIT 编译和类型声明。
数学友好的语法
Julia 通过提供类似于非计算世界的简单数学运算语法吸引了非程序员科学家。
自动内存管理
在内存分配方面,Julia 比 Python 更好,它为您提供了更多手动控制垃圾收集的自由。而在 python 中,您需要不断地释放内存并收集有关内存使用的信息,这在某些情况下令人望而生畏。
卓越的并行性
在运行科学算法时,有必要使用所有可用的资源,例如在多核处理器上运行 parallels computing。对于 Python,您需要使用外部包进行并行计算或者线程间的序列化和反序列化操作,这可能很难使用。对于 Julia 来说,它的实现要简单得多,因为它本身就具有并行性。
本机机器学习库
Flux 是 Julia 的机器学习库,还有其他正在开发的深度学习框架,完全用 Julia 编写,可以根据用户的需要进行修改。这些库自带 GPU 加速,不需要担心深度学习模型训练慢的问题。
更多信息,你可以阅读 InfoWorld 文章。
概观
在本文中,我将讨论 Julia 语言的优势,并展示 DataFrame.jl 的易用性,就像 python 中的熊猫一样。我将使用简单的例子和几行代码来演示数据操作和数据可视化。我们将使用著名的心脏病 UCI | Kaggle 数据集,该数据集基于多种因素对心脏病进行二元分类。
探索心脏病数据集
在我们开始编码之前,我想让你看看为 JuliaCon2021 准备的 DataFrames.jl 教程,因为我的大部分代码都是受现场会议的启发。
让我们设置你的 Julia repl,要么使用 JuliaPro 要么为 Julia 设置你的 VS 代码,如果你像我一样使用云笔记本,我建议你将下面的代码添加到你的 docker 文件中并构建它。
下面的 Docker 代码仅适用于deep noteenvironment。
FROM gcr.io/deepnote-200602/templates/deepnote
RUN wget [https://julialang-s3.julialang.org/bin/linux/x64/1.6/julia-1.6.2-linux-x86_64.tar.gz](https://julialang-s3.julialang.org/bin/linux/x64/1.6/julia-1.6.2-linux-x86_64.tar.gz) &&
tar -xvzf julia-1.6.2-linux-x86_64.tar.gz &&
sudo mv julia-1.6.2 /usr/lib/ &&
sudo ln -s /usr/lib/julia-1.6.2/bin/julia /usr/bin/julia &&
rm julia-1.6.2-linux-x86_64.tar.gz &&
julia -e "using Pkg;pkg"add IJulia LinearAlgebra SparseArrays Images MAT""
ENV DEFAULT_KERNEL_NAME "julia-1.6.2"
安装 Julia 包
下面的方法将帮助您一次下载并安装所有多个库。
导入包
我们将更加关注加载数据操作和可视化。
加载数据
我们使用著名的心脏病 UCI | Kaggle 数据集进行初级数据分析。
功能/栏目:
- 年龄
- 性
- 胸痛类型(4 个值)
- 静息血压
- 血清胆固醇(毫克/分升)
- 空腹血糖> 120 毫克/分升
- 静息心电图结果(值 0,1,2)
- 达到最大心率
- 运动诱发的心绞痛
- 旧峰
- 运动 ST 段峰值的斜率
- 主要船只数量
- thal: 3 到 7,其中 5 是正常的。
简单地使用CSV.read()就像熊猫pd.read_csv()一样,你的数据将被加载为数据帧。
检查数据帧的形状
检查多列分布。通过使用describe(),我们可以观察平均值、最小值、最大值和缺失值
数据选择
使用:fbs => categorical => :fbs将列转换成分类类型,我们使用Between一次选择多个列。select 函数很简单,用于选择列和操作类型。
使用链条
如果你想一次对数据集应用多个操作,我建议你使用@chain功能,在 R 中它相当于%>%。
dropmissing将从数据库中删除丢失的值行。我们的数据集中没有任何缺失值,所以这只是为了展示。groupby函数对给定列上的数据帧进行分组。combine函数通过聚合函数合并数据框的行。
更多操作请查看 Chain.jl 文档
我们按目标对数据框进行了分组,然后合并五列以获得平均值。
使用groupby和combine的另一种方式是使用names(df, Real),它返回所有具有真实值的列。
我们还可以通过nrows使用groupby和combine添加多个列,这将为每个子组显示若干行。
我们也可以将它合并,然后按如下所示进行拆分。以至于一个类别变成了索引,另一个变成了列。
分组依据
简单的groupby函数将一次显示所有组,要访问特定的组,您需要使用 Julia hacks。
我们可以使用👇
gd[(target=0,)] | gd[Dict(:target => 0)] | gd[(0,)]
为了获得我们关注的特定群体,这在我们处理多个类别时会有所帮助。gd[1]将显示第一组,其中目标=0 。
密度图
我们将使用 StatsPlots.jl 包来绘制图形和图表。该软件包包含扩展 Plots.jl 功能的统计配方。就像 seaborn 的简单代码一样,我们可以用颜色定义不同的组来得到我们的密度图。
我们将按target列对其进行分组,并显示cholesterol,它显示胆固醇的分布。
组直方图
类似于密度图,我们可以使用grouphist来绘制不同目标类别的直方图。
多重情节
您可以在同一个图形上绘制多个图形,方法是在函数名的末尾使用**!**,例如boxplot!()。
以下示例显示了按目标分组的胆固醇的小提琴图、箱线图和点线图。
预测模型
我们将使用 GLM 模型,就像在 R 中一样,您可以使用y~x来训练模型。
下面的例子有二进制的x= trestbps, age, chol, thalach, oldpeak, slope, ca和y= target。我们将训练二项分布的广义线性模型来预测心脏病。正如我们所看到的,我们的模型经过了训练,但仍需要一些调整来获得更好的性能。
结论
我们已经展示了编写 Julia 代码是多么简单,以及它在科学计算方面是多么强大。我们发现这种语言有潜力超越 Python,因为它语法简单,性能更高。Julia 仍然是数据科学的新手,但我确信这是机器学习和人工智能的未来。
老实说,我每天都在学习关于 Julia 的新东西,如果你想了解更多关于并行计算和使用 GPU 或机器学习的深度学习,请关注我将来的另一篇文章。我没有对预测模型做更多的探索,因为这是一篇介绍性的文章,有一些概括的例子。所以,如果你认为还有更多,我可以做的,一定要让我知道,我会试着在我的下一篇文章中添加它。
你可以在 LinkedIn 和 T2 上关注我,我每周都会在那里发表文章。
本文中显示的媒体不归 Analytics Vidhya 所有,由作者自行决定使用。
相关
原载于 2021 年 7 月 30 日 https://www.analyticsvidhya.comhttps://www.analyticsvidhya.com/blog/2021/07/julia-a-new-age-of-data-science。
茱莉亚不硬!
关于 Julia 是一门难学的编程语言的谣言是不真实的——原因如下。

(src =https://pix abay . com/插图/banner-header-binary-zero-one-6684416/)
介绍
W 每当一种新的工具或编程语言进入行业,无论是否面向数据科学,总会有人猜测它对行业意味着什么。此外,有些人可能想知道,就难度、风格、范式和数学能力等众多因素而言,它与他们目前可能正在使用的语言相比如何。Julia 编程语言是这个令人惊叹的编程长长列表中的一个新成员。
Julia 编程语言面向科学计算社区,数据科学家、分析师和从事生物信息学的人都是 Julia 语言的目标受众。也就是说,Julia 在很大程度上仍然是一种通用语言,这使得它比许多其他不能在软件中进行通用应用的统计编程语言具有更强的立足点。考虑到 Julia 是一种相对年轻的语言,关于这种语言是什么样的,以及它是为谁服务的,肯定有各种各样的关注和讨论。
首先,作为一名数据科学家,我认为 Julia 编程语言是一种非常令人兴奋的语言。它提供了科学计算多年来一直渴望的特性,语言速度快,数学上恰当,并且有一个奇妙的类型系统。也就是说,有很多关于这种语言是否功能齐全的讨论,此外,有传言说这种语言非常难学。有些人甚至不遗余力地宣称 Julia 是一种只为“聪明人”设计的语言。今天我想阐明其中的一些话题,谈谈我喜欢 Julia 的什么,并把这种语言的这些方面与生态系统中可用的其他语言和工具进行比较。
朱莉娅并不辛苦
我想谈的关于 Julia 语言的第一个流行观点是语言的难度。这实际上是从未使用过这种语言,但对它很好奇的程序员的普遍看法。好的一面是,朱莉娅语言一点也不难学。一个数据科学家在开始使用 Julia 时可能会用到的许多基本语法都是 Python 的镜像。在某些情况下,Julian 语法甚至在主观上更容易理解。
朱莉娅的伟大之处在于她多才多艺。以这种方式使用 Julia 是完全合适的,并且可以非常容易和有效地进行大量的数据科学工作,享受 Julia 编程语言的好处。也就是说,Julia 也可以进行实验,并且有许多不同的可能性,有些人可能从未从这样的语言中期望过。Julia 有一个复杂的类型系统,它有各种各样惊人的能力!在我看来,类型系统是最健壮的系统之一,这种语言真的将多种调度提升到了一个新的水平。所以问题仍然存在,对朱莉娅的这种误解首先来自哪里?
我认为这个断言来自于迄今为止真正使用朱莉娅的人。由于生态系统还不太成熟,业内许多程序员仍在使用 Python。我自己,尽管我爱 Julia,也一直在写 Python。目前,你根本无法打败 Python 的生态系统。这也是我认为 Julia 作为一门难懂的编程语言而获得声誉的部分原因。许多使用这种语言的人也是为它编写生态系统的人。此外,这种语言非常适合于原型制作之类的事情,那些制作原型和做类似事情的人通常被社区认为是聪明的。
是的,朱莉娅功能齐全
关于 Julia 的另一个误解是,它仍然只是一种语言,没有科学计算范围之外的许多功能。Julia 语言可以做像 Python 这样的其他语言能做的大多数事情。事实上,这种语言是一种功能非常丰富、非常真实的通用编程语言。
这种误解可能来自于 Julia 相当小的用户群和生态系统。我觉得想到像朱莉娅这样的小语种当然是完全可以理解的事情。也就是说,我也认为 Julia 有一些其他语言的程序员绝对会喜欢的特性,比如我自己。生态系统肯定是缺乏的,但像这样的东西当然要花很多时间来克服。
结论
Julia 是一种绝对适用于任何想使用它的人的语言。虽然这种语言很少在软件工程这样的应用中使用,但这并不意味着这种语言是不可能做到的。你甚至可以用 C 语言编译一个 Julia 可执行文件,所以这种语言在这些方面比许多其他统计语言更有能力。如果你以前没有尝试过这种语言,我当然会建议你试一试,你可能最终会爱上它!我希望这篇文章澄清了对 Julia 语言的误解,也许读完之后,你会认为使用 Julia 是一个更明智的选择!感谢您的阅读!
朱莉娅三维数据科学教程
实践教程、3D 数据
通过用于 3D 点云和网格处理的 6 步工作流程,探索 Python、Matlab、R、Perl、Ruby 和 C 的全能替代方案。

库的 3D 点云被自动分割,然后在 Julia 中可视化。弗洛伦特·普克斯
如果你总是在寻找伟大的想法和新的“工具”,使它们更容易实现,那么你可能听说过朱莉娅。不到十年的非常年轻的语言👶,这是进入快速脚本/编码以快速实现工作想法的一个超级酷的方式🌼。
假设你对科学计算、机器学习、数据挖掘、3D 数据科学、大规模线性代数、分布式和并行计算感兴趣,我认为这是值得跟进的实践教程,与 Julia 一起开始做有趣的 3D 东西!
在本新手教程中,我将直接切入主题,为您提供一个激光聚焦的 6 步工作流程,让您在接下来的十分钟内开始使用 3D 数据!准备好了吗?
一点历史?

哈,不过在此之前,我想强调一下《朱丽亚》的创作者们的野心。朱莉娅的创造者,即杰夫·贝赞森、斯特凡·卡尔平斯基、维尔拉·b·沙阿和艾伦·埃德尔曼。他们在 2012 年的博客中讲述了他们的抱负,以及他们发起朱莉娅运动的根本原因:
我们想要一种开源的语言,有一个自由的许可证。我们想要 C 的速度和 Ruby 的活力。我们想要一种同形异义的语言,既有像 Lisp 那样的真正的宏,又有像 Matlab 那样明显、熟悉的数学符号。我们想要像 Python 一样可用于一般编程,像 R 一样易于统计,像 Perl 一样自然用于字符串处理,像 Matlab 一样强大用于线性代数,像 shell 一样善于将程序粘合在一起。这种东西学习起来非常简单,却能让最严肃的黑客感到高兴。我们希望它是交互式的,我们希望它是编译过的。应该和 c 一样快。
但是这些主张成立吗🤔?这是一种“我都想要”的语言吗?好吧,我第一次发现朱莉娅是在 2019 年初,当时我正在德国亚琛工业大学(RWTH Aachen University)视觉计算研究所(计算机图形学)做研究访问。
从那以后,我基本上是通过朱莉娅发誓的!这来自于 Pythonista/C“程序员”的思维模式。它超级清晰,拿起来毫不费力,超级快,而且你可以在里面循环 python 脚本,直接调用你喜欢的库,纯 Julia 会执行的疯狂快!的确,朱丽亚是编译出来的,不是解读出来的。为了获得更快的运行时性能,Julia 使用 LLVM 编译器框架进行实时(JIT)编译。在最好的情况下,Julia 可以接近或匹配 C 语言的速度,这太棒了🚀!用三个字来说,我会说 Julia 是快速、动态和可再生环境。
⚠️警告说,虽然在写作的时候,文档和教程仍然很少,而且与你使用 Python 时所习惯的相比,社区也很小。但是,嘿,我打算改变一下。我们开始吧。
步骤 1:下载并安装 Julia
好了,现在你有了你的咖啡☕或茶杯🍵在你旁边,准备好寻找我们进入雾中的路,让我们潜水吧!首先,我们需要从官网下载茱莉亚:https://julialang.org/downloads/
注 : 本教程是用 Julia 版本 1.6.2,64bits 使用 windows 制作的,但是你可以用任何稳定版,应该可以(原则上😉)。
一旦可执行文件被下载,就安装漂亮的东西,直到你漂亮的手准备好闪亮的“软件”为止!
步骤 2:设置您的 Julia 开发环境
Julia 支持各种编辑器,如 VSCode 、 Atom 、 Emacs 、 Sublime 、 Vim 、 Notepad++ ,以及 ide 如 IntelliJ 。如果你喜欢 Jupyter 笔记本,也可以直接和 Julia 一起用。对于本教程,我将向您展示我最喜欢的三个选择。
茱莉亚拿着朱庇特笔记本
如果你想用 powerpoint 风格的方式演示你的项目,或者你想做的更多的是探索性的数据分析,这将是第一选择。最简单的方法是,启动新安装的 Julia 可执行文件,然后会弹出如下窗口。

Julia.exe 让这个小窗口出现,它充当了你工作的 REPL。弗洛伦特·普克斯
从那里,你所要做的就是键入命令using Pkg,然后按下Enter,接着是命令Pkg.add("IJulia")和Enter。在 Jupyter 笔记本中安装使用 Julia 所需的IJulia包的过程大约需要 1 分钟。

使用 Pkg.add()命令添加软件包会导致 Julia 更新注册表,然后获取必要的元素以在当前环境中安装软件包。弗洛伦特·普克斯
然后,您可以在您选择的环境中从哪个 Jupyter 笔记本启动 Anaconda Navigator (带 GUI)。
注 : 如果你没有安装 Anaconda,可以按照下面的教程进行操作:

一旦 GUI 出现,您就可以直接启动 Jupyter。弗洛伦特·普克斯
一旦打开,你可以用 Julia 作为编程语言创建一个新的笔记本

一旦进入 Jupyter,你可以点击 new,选择 Julia 1。创建一个新的基于 Julia 的笔记本。F. Poux
朱莉娅与原子 IDE 和朱诺
我倾向于支持 Atom+Juno 组合,它允许您从交互式 REPL 模式中受益,就像您习惯的 Spyder 一样。如果您选择遵循这些步骤,您首先需要按照在https://atom.io/给出的说明在您的系统中安装 Atom。

ATOM 中 GUI 的快照。它使得创建成熟软件的过程变得更加容易。弗洛伦特·普克斯
然后,您可以启动 Atom 并通过 Packages>Settings view>Open 或快捷方式Ctrl+,进入包安装设置。在那里搜索juno,然后点击uber-juno的安装按钮,如果没有安装juno-client。一旦安装了 Juno,你可以尝试用Juno > Open REPL或Ctrl+J Ctrl+O(MAC OS 上的Cmd+J Cmd+O)打开 REPL,然后在 REPL 中按Enter来启动 Julia 会话。就是这样!我们准备编码了!

在酒吧搜索 Juno 时,我会寻找有用的必要软件包,其中包括 uber-juno 和 juno-client。F. Poux
注意 : 如果 REPL 没有 而不是 正确启动,并且没有显示 Julia 徽标,请从软件包菜单转至 Juno 客户端设置,并验证 tour Julia 可执行文件的路径。

我的 Julia 可执行文件的路径。弗洛伦特·普克斯
额外奖励:茱莉亚和谷歌实验室
您也可以使用 google Colab 环境,但是这需要一个特定代码块来使用 Julia 而不是 Python。为此,您将在找到这个链接一个模板,它使得直接在 Colab 中工作成为可能。它还包含本教程的主要代码。
注意 : 每次你想在 Google Cloud 上使用 Julia,都需要运行第一个块,刷新页面,直接继续到第二个块,不需要重新运行第一个,直到每个元素都为你准备好。
步骤 3:加载数据集
太好了,那么现在我们准备好朱丽亚代码了。首先,让我们使用命令pwd()来发现我们正在哪里工作,也就是我们当前的工作目录。嗯,看起来我们是在基本目录中,所以让我们把它改成一个项目目录,你可以用cd(“C://DEV/JULIA/TUTORIALS/3D_PROJECT_1”)创建这个目录来存储你的大部分项目(数据、结果等等),然后用pwd()检查新的路径。

好的,我们都准备好了。首先,让我们下载一个数据集,一个小的噪声点云。为此,非常方便的是,可以使用以下命令:
download("https://raw.githubusercontent.com/florentPoux/3D-small-datasets/main/tree_sample.csv","point_cloud_sample.csv")
注意:*download()*命令首先获取你想要下载的数据的链接,我把它放到了我的 GitHub 账号上,然后在下载后在本地指定它的名称。**
很好,我们现在在工作目录中有了用cd()命令指定的数据的本地版本。现在,我们如何在脚本中加载它?嗯,我们将使用一个名为DelimitedFiles的包。
注 :包是一组方便的函数、方法、类等等,它允许你在现有代码的基础上构建,而不需要从头开始编写任何东西。 *DelimitedFiles* 包允许操作(例如,读和写)定界文件,就像我们手头的当前点云。
要使用一个包,我们首先必须通过键入using Pkg来加载包管理器实用程序。要添加一个新的包,非常简单;我们只需编写Pkg.add(“DelimitedFiles”),等待下载+需求检查完成。

最棒的是,你不必担心依赖关系(当前需要的其他包),因为一切都为你处理好了!很酷吧。最重要的是,我们可以轻松地创建优秀的包,以确保结果的可重复性,例如,和独立的环境,但这是另一个教程😉。
注意 : 管理软件包非常简单,我们有一堆函数来更新软件包,了解它们的当前状态,如果它们之间有任何冲突(很少),或者加载其他志同道合的编码者未注册的软件包,甚至是你未来的本地软件包😉。我通常使用 REPL 来管理它们,并在正确的环境中使用命令 *]* 进入包管理器。要退出软件包管理器,只需要做 *Ctrl+C* 。
好了,现在包已经安装好了(您只需要在每个环境中运行一次)。您可以通过键入using DelimitedFiles在您当前的项目中使用它,并且,如果没有函数名的冲突,您不需要编写函数来自哪个包。读取分隔文件DelimitedFiles.readdlm()等同于readdlm()。
从那里,让我们读取手边的点云并将数据存储在变量pointlist中:
*pointlist=readdlm(“point_cloud_sample.csv”,’;’)*
第一行应该如下所示。

步骤 4:第一步预处理操作
好吧,到现在都很酷,嗯?现在,让我们看看第一个真正的惊喜,如果你习惯于其他编程语言的话:索引。您可以尝试执行pointlist[0]来检索第一个元素。我们得到了什么?一个边界错误。
哈哈,在 Julia 中,索引从 1 开始,所以如果你想检索第一个元素(第一个点的 X 坐标),你只需输入返回41.61793137的pointlist[1]。起初有点令人困惑,但至少从科学的角度来看,它非常方便且符合逻辑😅。所以现在,如果您想要检索第一个点,那么您需要知道索引首先作用于第一个轴(行),然后是第二个轴(列),依此类推。因此,要检索第一个点(第一行和每一列):
*pointlist[1,:]*

非常酷,现在,为了更进一步,如果我们想在points变量中存储坐标,在normals变量中存储法线,我们只需要:
*points = pointlist[:,1:3]
normals = pointlist[:,4:6]*
注意 : 如果你想知道一个变量的类型, *typeof()* 就是你要找的。 *typeof(points)* 会显示我们处理的是矩阵,是二维数组的别名。还有 *Float64* 是计算机数字格式,通常在计算机内存中占用 64 位;它通过使用浮点表示宽动态范围的数值。当单精度( *Float32* )的范围或精度不够时,可以选择双精度。
最后一个简单的预处理步骤是知道如何快速采样变量,比如说,每十分之一行。为此,我们可以这样做(有点像 Python,但我们需要放上单词end来处理 total 变量):
*points_sampled=points[1:10:end,:]*
我们首先处理行,每十分之一取一行,对于每一行,我们保留所有列,在,之后是:。
提示这种方式执行起来非常快速和简单;因此,它通常在不使用太多记忆的情况下获得第一视觉结果来知道我们正在处理什么。如果你想更深入,我建议你按照下面的教程。对朱莉娅的改编应该不会有太大问题😉。
*
步骤 5: 3D 数据可视化
我们现在准备处理 3D 数据可视化,这是掌握我们正在处理的东西的关键一步!这里,一个库是首选的解决方案:Makie。因为我们还没有使用它,我们首先需要导入这个包,以及其他两个“后端”,这取决于您的范例(webGL 可视化或 OpenGL 可视化),即WGLMakie 和GLMakie。没有比这更简单的了,我们只需运行下面三行代码一次:
Pkg.add(“Makie”)
Pkg.add(“WGLMakie”)
Pkg.add(“GLMakie”)
注意 :一旦执行,如果您想随时浏览您当前环境中已经安装的软件包,您可以使用 *Pkg.installed()* 命令。
一旦安装了所需的包,为了使它们在您的工作会话中可用,您可以添加行using Makie, GLMakie(或者using Makie, WGLMakie,如果您想要在 web 上与 Colab 或 Jupyter 交互的话),很像 Python 中的import matplotlib。
很好,现在,在可视化之前,让我们为无色点准备一点颜色,这取决于它们的 z 值。我们将创建一个颜色向量,其大小为采样点云的大小,范围从 0 到 1,取决于它与最大值的接近程度,通过划分每个点:
zcoloring_scale=points_sampled[:,3]/maximum(points_sampled[:,3])
提示 : Julia 自动理解你想用 maximum() 将 *points_sampled[:,3]* 中的每个元素除以最大值。得心应手吧。但它是 播 的特例,在 Julia 中,你只要在你的函数或数学符号前输入一个 *.* 就可以了。如果在这里做 *./* ,也会得到同样的结果。
好了,现在,我们要做的就是把我们的结果绘制成三维的散乱点云。为此,我们使用来自Makie的scatter函数,我们传递点的坐标(points_sampled)、颜色向量zcoloring_scale以及一些参数,如每个点的大小和markersize,以及我们是否想要显示轴。
scatter(points_sampled, color=zcoloring_scale, markersize=100, show_axis=true)

左边是使用散点函数的图。右边是使用 meshscatter 函数的图。在这两种情况下,我们现在可以掌握我们正在处理点云的类型。弗洛伦特·普克斯
你也可以绘制一个meshscatter图,为每个点生成一个小球体(就像上面右边的图片)
scene_1 = meshscatter(points_sampled, color=zcoloring_scale, markersize=0.2, show_axis=true)
多么酷啊!如果你想在网络上有一些交互性,你应该确保使用WGLMakie而不是GLMakie,它只会给你一个固定的后端来生成一个视图。
提示 :如果你想将你的图形打印到一个文件中,一个简单的方法是首先使用 *Pkg.add(“FileIO”)* 和 *using FileIO* 安装 *FileIO* 软件包,该软件包包含了处理大量文件格式(包括网格、图像、矢量等)所必需的方法和功能,一旦在你的运行会话中可用,一个简单的 *save(“scatter.png”, scene_1)* 就会将图形保存到你的工作目录中的图像中。
[附加功能] 3D 网格输入/输出
一种显示网格的简单方法是使用 FileIO,就像上面暗示的那样。用两行简单的代码,你可以显示你的网格。以我的 GitHub 上可用的点云为例:
download("https://raw.githubusercontent.com/florentPoux/3D-small-datasets/main/hippo_1k.obj","hippo_1k.obj")
然后,您可以将它存储在 obj 变量中:
obj = load(“hippo_1k.obj”)
你传递给Makie.mesh()函数,简称为mesh()来显示你的 3D 模型。
mesh(obj, color=”honeydew2”, show_axis=false)

使用 Makie 的 3D 网格可视化工具的结果。弗洛伦特·普克斯
如果这不是优化代码清晰,我不知道它是什么😆!
提示🙃。
步骤 6: 3D 数据分析
现在我们可以研究一些数据,并使用一些函数。首先要知道如何访问 3D 点云数据集的特定部分。在我们的例子中,我们希望找到并(或多或少)将地面与其余部分分开。首先,我们将通过可视化找到地面较高的 z,然后使用它作为阈值。让我们绘制数据集的 2D 投影:
scatter(points_sampled[:,2:3], color=zcoloring_scale, markersize=100, show_axis=true)

点云在 y 轴上的 2D 投影,以尝试并抓住潜在的阈值线来分离我们的 3D 点云数据集。
我们可以确定在大约 3 米(红线)处有一个阈值。让我们直接用它来做实验。
提示😀。
现在,我们希望找到低于和高于视觉定义的阈值的所有点,并将它们存储在一个单独的变量中。我们将使用findall函数返回满足括号中条件的点的索引。让我们只关注points[:,3],因为我们只需要研究它并检索索引,我们稍后可以使用这些索引来过滤我们的完整点云。多酷啊😆?
indexes_ground=findall(x->x < 3, points[:,3])
indexes_tree=findall(x->x>=3, points[:,3])
非常好!现在,如果我们想要获得对应于这些索引列表的点,我们只需在 points 变量中传递indexes_ground或indexes_tree作为行选择器,例如,用于获得属于地面的所有点和所有其他点。如果我们想画这个,我们可以这样做:
meshscatter(points[indexes_ground,:], color=”navajowhite4”, markersize=0.3, show_axis=false)
meshscatter!(points[indexes_tree,:], color=”honeydew3”, markersize=0.3, show_axis=false)
current_figure()
厉害!我们刚刚做了一个手动实例分割步骤,其中我们有一个基础元素和一个树元素,并且使用了一种新的语言;干得好!
结论
在 Julia 中,您刚刚学习了如何导入、子采样、导出和可视化由数十万个点组成的点云!干得好!但是这条路并没有到此为止,未来的文章将会深入探讨点云空间分析、文件格式、数据结构、可视化、动画和网格划分。我们将特别关注如何管理大点云数据,如下面的文章中所定义的。
的在线课程立即开始。
https://learngeodata.eu/point-cloud-processor-formation/
如果你刚接触媒体,你可以通过下面的链接来支持我的工作:
https://medium.com/@florentpoux/membership *
Julia 的文档字符串系统非常棒,原因如下
概述为什么我认为 Julian 文档优于大多数其他语言的方法

介绍
朱莉娅有太多可爱的地方了。
我喜欢朱莉娅的一点是,他们对事物有很好的想法,其中一些是打破常规的,而另一些无论何时你想起来都是显而易见的。在某些情况下,这种语言超出了人们的预期,因为它采用了多种调度方式,并拥有像 Pkg 包管理器这样令人惊奇的随机特性。如果您想了解我喜欢这种编程语言的一些方面,并且可能会强迫一个人去接触这种语言,我写了一整篇关于它的文章,您可以在这里阅读:
</5-awesome-things-to-love-about-the-julia-language-688d7c403474>
Julia 处理得很好的一件事是文档。进入 Julia 文档系统的途径有很多,然而,当你第一次介绍 Julia 文档系统时,很有可能会迷路或感到困惑。我相信这是我们看到许多缺少文档的包的部分原因。这—这整个系统并不太年轻或太老—我认为虽然 Julia 有一些文档问题,但他们最终通常会归结为包太年轻。我跑题了,今天我想深入 Julia 的文档系统,并揭示它实际上是如何工作的,这样你就可以开始编写你的软件了!
文档字符串
我们列表中用于创建文档的第一个也是最明显的工具是 doc-string。文档字符串是写在方法定义之上的代码字符串,目的是描述它。出于多种原因,这些是必不可少的。首先,对于查看您的包的开发人员来说,文档字符串是绝对重要的资产。如果他们是第一次查看这段代码,情况尤其如此。考虑到这一点,使用文档字符串可能非常重要。
特别是在 Julia 中,doc-strings 还可以为用户提供一个很好的界面,通过命令行与文档进行交互。您可以提供完整标记格式的文档字符串,例如:
"""
# This is a huge title
[This is a link](http://medium.com/@emmettgb)
This is plain <p> text. \\
This is a code example
function documented()end
你可以阅读文档字符串的完整指南…
Julia 文档文档
markdown 在 REPL 内部也打印得很好,然后在构建基于 web 的文档站点的过程中更进了一步。
创建文档
在 Julia 中创建文档通常是通过 Documenter.jl 包来完成的。这个包允许您使用自己目录中的独立环境来创建一个具有自己的虚拟环境的新项目。从那里,您的包和 Documenter.jl 作为依赖项被加载。以下是这些情况下项目目录的直观表示:
- assets
- doc
- src
- ...
您还可以查看 Lathe.jl 存储库作为参考,这里包含了文档和测试目录:
https://github.com/ChifiSource/Lathe.jl
在这个文档中有一个全新的项目和一个全新的 Project.toml 文件。我不打算在这里讨论如何使用 Documenter.jl,但我确实写了一整篇文章来讨论它和使用它,您可以在这里阅读:
JuliaHub
Juliahub 是一个很棒的新的 Julia 网站,它把包和它们各自的文档提高到了一个新的容易访问的水平。因为大多数成熟到可以真正使用的包在它们的存储库中都会有这个 doc 目录,并且应该有一个类似于。jl 存储库中,Julia 可以从。TOML 文件和 Documenter markdown 文件,项目在下面的目录中。
也就是说,JuliaHub 是很多东西的家。科学工作可以在这个网站上完成,Julia 软件包可以和他们的文档一起访问。它非常简单,但是增加了文档一致性的新元素,因为只要在 Julia 注册中心内,就可以在同一个网站上找到它。我写了一整篇关于 JuliaHub 的文章,以及它如何将这样的文档提升到一个新的水平,您可以在这里阅读:
结论
Julia 是一种典型的夸张语言。你想要一个编译器,他们给你一个 JIT 编译器。你想要一个类型系统,他们给你多个分派和内部外部构造函数。你想要一个包管理器,你可以得到带有 TOML 虚拟环境的 Pkg。在文档的前面也没有例外。
非常感谢您阅读我的文章。我希望它有助于展示宇宙中所有 Julia 代码背后的文档引擎的力量。祝您有美好的一天,编程愉快!
Julia 神奇的 CUDA 实现
使用 CUDA.jl 包探索简单并行计算的真正力量。

https://unsplash.com/photos/0F2tAwBmBjo
介绍
由于许多不同的原因,包括速度、科学的语法和易用性,Julia 语言已经进入了数据科学领域的前沿。然而,Julia 语言的一个被大大低估的特性是它在并行计算方面的非凡能力。Julia 的设计初衷是并行计算。这与 Python 之类的语言有很大的不同,在 Python 中,这些实现是后来才添加到语言中的,在很多情况下都没有很好地实现。
当然,总的来说,Julia 也是一种速度较快的语言。因此,将这两种属性结合在一起,肯定能让朱莉娅站在一些最快计算的前沿。我认为这非常令人兴奋,因为 Julia 真的是第一个以这种方式构建的科学计算语言。这个实现的另一个优点是使用起来非常简单。
CUDA.jl
在今天的文章中,我将重点介绍 CUDA.jl 包,因为我没有太多使用 AMD 卡和并行计算的经验。然而,在生态系统中确实有一些包是为那些拥有红队卡片的人持续维护的。不管你有什么样的卡,你都不太可能在 Julia 的并行计算中被蒙在鼓里,除非你使用的是 I-GPU。
CUDA.jl 包是一个相对简单的包,它充满了对各种不同包的调度。我们将在后面更多地讨论这个调度意味着什么。我们当然可以使用 Pkg 添加这个包,就像我们添加任何其他的 Julia 包一样:
julia > ]
pkg > add CUDA
或者
using Pkg
Pkg.add("CUDA")
这个包的使用实际上非常简单,我们会解释为什么会这样——但是现在,我想说明一下它实际上有多简单。考虑添加这两个数组:
x = [5, 10, 15, 20]
y = [5, 10, 15, 20]x .+ y
使用 CUDA 包,我们可以简单地将 CuArray 类型转换为两个数组。这将使它们成为 CuArray 类型,这意味着当它们被添加时,算法将在 GPU 和 CPU 之间分割。很酷,对吧?
using CUDA
x = CuArray([5, 10, 15, 20])
y = CuArray([5, 10, 15, 20])x .+ y
CUDA 调度
和大多数 Julia 程序员可用的包一样,这个包利用了 Julia 的多重调度。如果您想了解更多关于多重分派的一般知识,以及为什么多重分派是我最喜欢的计算机编程方式,我写了一整篇文章,都是关于它在 Julia 编程语言中的实现,您可以在这里查看:
对 Julia 来说,这个 CUDA.jl 包最酷的地方在于,它真正利用了多分派的概念,通过扩展基本函数来产生许多调用,这些调用实际上与它们的常规内存和处理器对应部分相同,同时仍然利用了 CUDA 的优势。这意味着在很多情况下,算法可以像没有 CUDA 时一样正常执行。换句话说,我们获得了 CUDA 的好处,而没有这种努力通常会引起的任何头痛。我认为这真的很酷,因为我真的从未使用过如此强大的并行处理平台的如此易用的实现。对于任何热爱技术和寻求更快编译时间的人,我当然会推荐看看这个实现,这样你就可以看到在 Julia 中使用 CuArrays 实际上是多么容易!
结论
在能够利用 CUDA 并行处理技术的一长串编程语言中,我认为 Julia 无疑是最无缝实现的佼佼者。这个实现真正酷的地方在于它没有使用任何 Julia 语言独有的东西。事实上,Julia 最酷的一点是,函数经常在整个包的范围内简单地循环使用,只是为了保存不同的类型而被分派。
不管语言本身的编译速度有多快,尽管这也令人印象深刻,但 CUDA 在 Julia 语言中的实现将为这些程序的编程过程节省大量时间。非常感谢您阅读我的文章,我真的希望它点燃了您对并行计算的内心之火。我想说的是,这个 CUDA 实现也是非常容易实现的,所以没有理由不去尝试一下!
2021 年 7 月:ML 新闻与代码
全球范围内对更大的语言模型的竞赛,由专家组成,从 Yandex 和 Huggingface、SpeechBrain 等处进行分布式学习。而 OpenAI 驱动的 GitHub Copilot 会改变计算机编程吗?以下是我们每月精选的最新 ML 新闻、研究和代码:

图片作者。
我们已经到了 2021 年的中途,ML 领域还在继续旋转:关于计算机视觉和模式识别(CVPR 2021) 的会议刚刚召开,Github 和 OpenAI 发布了 Copilot,这是一款前所未有的智能代码完成助手,在过去几周还发生了更多事情。泽塔阿尔法很乐意帮助你发现最新的人工智能研究和软件,并让你保持最新。尽情享受吧!
🗞有些消息
超大型模特的趋势还远未结束。一年前 OpenAI 的 GPT-3 发布了 1750 亿个参数,让 AI 社区大吃一惊。本月是武道 2.0 打破记录的时候,这表明中国在人工智能研究方面一点也不落后。悟道是一个多模态(文本和图像)大规模模型,具有 1.75 万亿个参数,基于混合专家架构(稍后将详细介绍!).虽然官方新闻稿只触及了模型的表面,并没有太多关于它的公开信息,但论文概述了用于训练模型的系统: FastMoE:一个快速的专家混合训练系统在 arXiv 上,代码在 GitHub 上开源。希望 OpenAI 能做得更多。
虽然武道没有公开, GPT-J 是:迄今为止最佳零拍表演,表演公开可用的 GPT 变形金刚(在 6B 参数),最近由王贲和阿兰小松崎发布。由 JAX 建造,这是对图书馆的又一次推动,在过去的两年里,图书馆缓慢但稳定地受到欢迎。
最后, Github Copilot 几天前刚刚发布:一个带来下一代代码合成的插件,基于 Codex,一个来自 OpenAI 的类似 GPT 的模型,在公共 Github 代码的大规模数据集上训练。但是该公告导致了一个醒目的登录页面,上面有精选的示例,并且公开演示仍然不可用。很多问题还悬而未决:这个模型能做多大、多快推断?使用的训练数据集的细节是什么?我们是否应该担心受版权保护的数据会像在 previously⁵展示的那样被模型意外地暴露出来?这个 twitter 帖子揭示了这个话题,我们迫不及待地想亲自尝试一下……它有可能使编程效率提高 10 倍,并使编写代码民主化,但它必须非常非常好地工作。我们知道无 bug 代码是不存在的。会比带自动驾驶汽车上路容易吗?
🐍密码
这里有一些值得一试的库和资源。
👾在家学习/hivemind ⭐️ 715 |📄论文
👉想通过众包计算用专有技术训练像 Google 和 OpenAI 那样的大型模型吗?别再看了。
https://github.com/learning-at-home/hivemind
🚀主要功能(来自自述文件)
- 训练任意大小的神经网络。
- 没有主节点的分布式训练:分布式哈希表允许连接分散网络中的计算机。
- 容错反向传播:即使某些节点没有响应或响应时间过长,向前和向后传递也会成功。
- 分散的参数平均:迭代地聚集来自多个工作者的更新,而不需要在整个网络上同步。
📈更多用于分布式培训的框架和库…
👾微软/DeepSpeed ⭐️ 5.2k|🌐网站 👉为极端规模的机器学习模型(如微软的图灵-NLG (17B 参数))执行分布式训练的框架。
👾 horovod/horovod ⭐️ 11.4k |🌐网站 |📄论文 👉用于 TensorFlow、Keras、PyTorch 和 Apache MXNet 的分布式深度学习培训框架。
👾Facebook research/fair scale⭐️1.2k👉用于高性能和大规模培训的 PyTorch 扩展库。
👾 pytorch/xla ⭐️ 1.4k 👉使用 XLA 深度学习编译器 连接 PyTorch 深度学习框架 和Cloud TPUs的 Python 包。
👾⭐️ 2.5k
👉基于 PyTorch 的开源一体化语音工具包。
https://github.com/speechbrain/speechbrain
🚀主要功能(来自自述文件)
- 涵盖的领域和任务:语音识别、特征提取和增强、说话人识别、身份识别和二进制化、语音增强和分离以及多麦克风处理。
- 集成了多个预训练模型🤗拥抱脸。
- 抽象,如 Brain 类,删除模式的不必要的细节,同时完全可定制的定价和评估。
- 通过 PyTorch 数据并行或分布式数据并行和混合精度训练进行多 GPU 训练。
- 透明且可定制的输入和输出管道:原生 PyTorch 数据加载器、缩减采样、BPE 标记化等。
➕:一个新的类似的库值得一试:软件/OpenSpeech
🤖最近流行的变压器实现…
👾Facebook research/xcit⭐️415 |📄论文👉交叉协方差图像变换器的实现(XCiT)⁸
👾kzl/决策变压器 ⭐️ 661 |📄论文👉通过序列建模的强化学习。
👾 NVlabs/SegFormer ⭐️ 403 |📄论文👉用变形金刚进行语义分割。
👾oatml/非参数变压器 ⭐️ 217 |📄论文👉一次处理整个数据集,并使用数据点而不是参数。
👾comp photo/BoostingMonocularDepth@ cvpr 21 | P项目页面
👉高分辨率单目深度估计。
https://github.com/compphoto/BoostingMonocularDepth
🚀这个实现太酷了,我们不得不包括它。它实现了 CVPR 2021 论文通过内容自适应多分辨率合并 ⁰.将单目深度估计模型提升到高分辨率
我们的每月选择到此结束,如果你想了解更多关于事物的研究方面,请查看 2021 年 7 月 arXiv 的最佳,这是最近 ML 学术文献的选择。
参考文献
[1] 开关变压器:以简单有效的稀疏性缩放至万亿参数模型——William Fedus,Barret Zoph 和 Noam Shazeer,2021。
[2] FastMoE:一种快速的专家混合训练系统 —何家傲等,2021。
[3] 一幅图像抵得上 16x16 个字:大规模图像识别的变形金刚——作者阿列克谢·多索维茨基、卢卡斯·拜尔、亚历山大·科列斯尼科夫、德克·韦森博恩、翟晓华等人 2021。
[4] 贪婪函数逼近:一个梯度推进机—j . h . Friedman 著,2001。
[5] 从大型语言模型中提取训练数据——Nicholas Carlini 等人 2020。
[6] ByT5:用预先训练好的字节到字节模型——作者:薛,阿迪蒂亚·巴鲁阿,诺亚·康斯坦特,拉米·阿尔-Rfou 等人 2021。
[7] XGBoost:一个可扩展的树提升系统 —陈天琦,Carlos Guestrin,2016。
[8] XCiT:互协方差图像变换器—Alaaeldin El-Nouby 等人 2021。
[9] 注意力是图灵——完成——豪尔赫·佩雷斯、巴勃罗·巴塞洛和哈维尔·马林科维奇,2021。
[10] 通过内容自适应多分辨率合并将单目深度估计模型提升到高分辨率 — 作者:S. Mahdi H. Miangoleh,Sebastian Dille,龙脉,Sylvain Paris 和 yaz Aksoy,2021。
七月版:通过数据讲故事的艺术
月刊
描绘你的数据试图讲述的故事

照片由来自 Pexels 的 ritesh arya 拍摄
当有人听到“数据科学”这个词时,他们通常会认为这个词的意思是处理数据分析的工作。虽然这可能是真的,但我喜欢将数据科学视为一个讲故事的领域。当给数据科学家一个数据集进行分析时,他们通常会试图找到该数据集中的模式、趋势和异常,并使用这些信息来制定业务决策或预测未来数据。当然,你可以认为这是一项纯粹的分析工作,但更好的方式是把信息想象成你的数据试图讲述的故事。
寻找数据的故事是每个数据科学家必须努力提高的宝贵技能,而实现这一点的方法是通过可视化。作为数据科学家,我们需要从广泛的各个领域发展许多技能;我们需要一些商业知识,一些数学,统计和编程。但是,我认为学习视觉化和讲故事也是必要的技能。
如果你是一个善于讲故事的人,并且能够创建高效的可视化效果,你将会发现你的数据的故事,将这个故事有效地呈现给你的客户,并且证明你的工作的价值。
Sara A. Metwalli ,《走向数据科学》的志愿编辑助理
改变我生活的 3 种视觉效果
讲述更有力的故事,并为您的幻灯片添加背景。
由 Lukas Hurych 提供— 7 分钟
如何使用 Python 创建类似 3Blue1Brown 的数学动画
利用您的 Python 技能创建美丽的数学动画。
由 Khuyen Tran — 5 分钟
制作条形图动画的完整指南
制作两种不同风格的条形图动画的分步指南。
由阿比纳夫·马拉斯 — 10 分钟
用 Python 可视化 Spotify 歌曲:探索性数据分析
是什么让流行音乐流行?今天的音乐与 30 多年前有什么不同?
到 Dea Bardhoshi — 8 分钟
Python 中数据可视化的下一个层次
如何用一行 Python 代码制作出好看的、全交互的情节?
到威尔·科尔森 — 8 分钟
用 Python 可视化网络
帮助你“看到”网络的实用工具指南。
莫希特·马扬克 — 6 分钟
多维数据的有效可视化艺术
有效数据可视化的策略。
由迪潘詹(DJ)萨卡尔 — 16 分钟
交互式数据可视化
使用 Python 库创建用于数据可视化的交互式绘图和微件。
由 Pier Paolo Ippolito — 7 分钟
提升您的数据故事的 5 种可视化效果
用 Plotly 超越直方图和箱线图。
由莲娜·梅赫拉比亚 — 4 分钟
用 3D 360 度动画散点图可视化高维网络数据
使用 node2vec,networkx,pca,seaborn 等。可视化高维网络数据
由金航江 — 4 分钟
新播客
- 安迪·琼斯— 人工智能安全和扩展假说
- 埃文·胡宾格— 内部对齐问题
- 柳文欢·埃齐奥尼— 人工智能反对(担心)存在风险的案例
- 为人工智能指出正确的方向——与香蕉数据播客的交叉集!
我们也感谢最近加入我们的所有伟大的新作家:弗恩·R·沃克、克里斯·林顿-里德、布莱恩·m·李、艾米特·加普塔、凯瑟琳·拉兰内、奥詹·叶迪尔、珍·沃金斯、泰蕾兹·保莱塔、阿卡什·阿格尼霍特里。 阿比纳夫·萨加尔、哈桑·苏赞、阿里汉特·贾恩、本·楚格、乌奈·洛佩斯·安索莱亚加、蒂姆·若瑟兰、屋大维·西玛、纳夫乔特·比安斯、埃里克斯·东布罗夫斯基斯、 尼古拉·尼基丁、菲利普·佩克、费利齐亚·克舍尔、萨姆·麦克拉齐、莫兰·贝拉德夫、鲁索·阿莱西奥、多米尼克·马斯特斯等等很多人。 我们邀请你看看他们的简介,看看他们的工作。
六月版:向行业学习
月刊
超越教程、课程和辅助项目

照片由 olia danilevich 从 Pexels
课程、教科书、博客文章和个人项目都是学习数据科学的好方法。但人们也普遍承认,这些还不足以真正开始在数据科学岗位上工作。Automattic 的高级机器学习工程师 Vicki Boykis 认为这是一个隐性知识与显性知识的问题。显性知识是我们容易获得的,因为它写在某个地方供我们学习。隐性知识就是我们所说的在职学习——它拒绝被打包进教科书或文章中。隐性知识对于没有机会获得在职培训或专业指导的数据科学新手来说可能是一个障碍。
在 TDS,我们试图通过识别整理我们领域隐性知识的文章来为我们的读者弥合这一差距。我们创建了专栏行业笔记来整理和突出现实世界中遇到的数据科学挑战、应用和解决方案的最佳作品。
在下面的帖子中,学生可以一窥真实世界的数据挑战是什么样子的。初级数据科学家将从从业者那里获得最佳实践。高级数据科学家可能会发现一些有趣的宝石,涵盖了他们的同行为解决常见问题而实施的内容。
Elliot Gunn ,《走向数据科学》的编辑/分析师
SQL 代码的 PR 审查
没有关于如何审查数据科学用例的 SQL 代码的指南。因此,作者创建了一个用于同行评审的清单。
Marc-Olivier Arsenault — 10 分钟阅读
数据清理是分析,而不是繁重的工作
大多数关于数据清理的文章缺乏深度。本文着眼于数据清理实际上是什么,以及它如何成为数据分析的一种关键形式,应该被称为“构建可重用的转换”
由兰迪欧 — 19 分钟阅读
从网飞、DoorDash、Spotify 等平台上学习 ML 平台的课程
深入探讨大型科技公司使用的 ML 平台组件和工具。
陈欧内斯特 — 12 分钟阅读
分析生命周期管理
数据科学经理关注整个分析生命周期,从问题的提出到解决方案的终止。
通过李颖 — 7 分钟读取
你能从一个额外的实验中学到什么
调查为什么只进行 A/B 测试是不够的,并寻找产生更多见解的替代实验方法。
由凯文·杜恩 — 11 分钟读出
数据即代码——实现分析数据集的零生产缺陷
将高性能软件工程团队的工具和实践应用于数据工作流。
通过斯文·巴尔诺扬 — 9 分钟阅读
策略师:不要再纠结于平均值了
分析师需要超越方法、中间值和模式。离群值提供了关于未来的新信息。
由罗杰·马丁 — 7 分钟读出
数据科学管理中的 7 项任务
本文着眼于数据科学团队管理的复杂性。
作者马丁·施米特和马塞尔·何冰——13 分钟阅读
如何在两周内构建基于云的 ML Ops 框架
三人小组分享了他们如何使用 DevOps 最佳实践在两周内构建完整的 ML Ops 框架。
通过拉尔斯·凯氏法则 — 6 分钟读取
使用贝叶斯扩散模型的高级预测
本文介绍了一种先进的建模方法,贝叶斯扩散建模,通过端到端的案例研究。
由弗雷泽·刘易斯 — 11 分钟读完
新播客
- Nicolas Miailhe — 人工智能风险是一个全球性问题
- 雅各布·福斯特— 自动化武器的高成本
- Rosie Campbell — 所有的人工智能研究都应该发表吗?
- Eliano Marques — (不断发展的)人工智能隐私和数据安全世界
- 布莱恩·克里斯蒂安— 校准问题
我们也感谢最近加入我们的所有伟大的新作家斯蒂芬·图尔肯斯、王小鹰、扬-艾尔·勒·博尔涅、迈克·博斯托克、瓦伊巴夫·南德瓦尼、李颖、亚萨斯·桑德佩、尼蒂什·库马尔·塔库尔、塞思·比劳。 罗伯托·马托雷里、克莱门·科塔、德班纳·查克拉博蒂、本杰明·格里菲思、约伊·舍内曼、斯里坎特·马希拉茹、约翰·阿林、瓦斯涅佐夫、苏红·金、安娜·雅各布 努尔·什拉波斯基、格雷瓜尔·马丁农、约翰·佩特、帕维尔·福金、丹尼斯·艾勒斯、王钦辉、卢克·格里斯沃尔德、塔利亚·赖希、ondřej·西夫 马丁·施密特、希德·阿西迪亚科诺、瓦伦·梅农、大卫·戴尔、西布伦·詹森、乔伊斯·安妮·乔治、维罗妮卡·m·翟、托马斯·奥拉夫森、朱莉娅·森内尔、 我们邀请你看看他们的简介,看看他们的工作。
Jupyter:准备抛弃 IPython 内核
通过 xeus-python,JupyterLab 离成为成熟的 IDE 更近了一步。

大约一年前,JupyterLab 的可视化调试器发布了。这是使 JuypterLab 成为成熟的 IDE 的一个步骤,因为它提供了 IDE 调试器所能提供的大部分功能:
- 变量资源管理器、断点列表和源代码预览
- 导航调用堆栈的可能性(下一行、进入、退出等)。)
- 直观地在感兴趣的行旁边设置断点的能力
- 指示当前执行停止位置的标志

JupyterLab 可视化调试器
该项目建立在 xeus-python 内核的基础上,这是 python 编程语言 Jupyter 内核的一个轻量级实现。你可以在我当时写的一篇文章中读到这一点,这篇文章成了我在媒体上最成功的一篇文章。
然而,xeus-python并没有提供所有的 IPython 内核特性。最重要的是,它不支持魔术命令或 Matplotlib 图形,而这两者对于数据科学家来说是非常有用的。
你发现关键词了吗?关键词是“did”;o 一年后,xeus-python如果越来越接近与ipykernel旗鼓相当。我们准备好享受它带来的所有好处。
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
Xeus Magic
笔记本一直是软件思想增量开发的工具。数据科学家使用 Jupyter 来记录他们的工作,探索和实验新的算法,快速勾画新的方法,并立即观察结果。
尽管 JupyterLab 将项目推向提供类似 IDE 的开发体验,但仍有一些缺失。其中之一就是可视化调试器的存在。覆盖这个漏洞产生了新的问题,因为 Jupyter 可视化调试器的实现依赖于xeus-python内核。
主要问题是xeus-python没有提供所有的 IPython 内核特性。值得注意的是,它不支持魔法命令和matplotlib人物。我有一个好消息:xeus-python现在正在向ipykernel靠拢。
截至今天,xeus-python支持魔法命令和matplotlib人物,以及许多其他ipykernel额外功能,比如丰富的配置系统。
我敦促你在评论区开始讨论,以了解还缺少什么,这样我们就可以推动项目向前发展!
魔法支持:

xeus-python 中的神奇命令
Matplotlib 支持:

xeus-python 中的 Matplotlib
入门指南
不用安装xeus-python就可以在 Binder 上试驾。请点击下面的链接。这会让你知道xeus-python能做什么,以及它是否适合你
如果你对这个想法感兴趣,你可以使用 mamba 或 conda 安装最新的xeus-python版本:
mamba install xeus-python -c conda-forge
或者
conda install xeus-python -c conda-forge
此外,看看我的其他笔记本故事,用这个优秀的工具提升你的游戏:
- Jupyter 已做好生产准备;原样
- 期待已久的 JupyterLab 3.0 终于来了
- Jupyter 在 VS 代码:利弊
- Jupyter 有一个完美的代码编辑器
- Jupyter widgets 的新时代
结论
笔记本一直是软件思想增量开发的工具。尽管 JupyterLab 将项目推向提供类似 IDE 的开发体验,但仍有一些缺失。
解决这些问题产生了新的问题;例如,可视化调试器依赖于xeus-python并且xeus-python没有提供所有的 IPython 内核特性。然而,它更接近与ipykernel的功能对等。
这个故事展示了为什么会出现这种情况,以及您现在可以如何开始使用 JupyterLab 的xeus-python内核。我敦促你在评论区开始讨论,以了解还缺少什么,这样我们就可以推动项目向前发展!
关于作者
我的名字是迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据操作的帖子,请关注我的 Medium 、 LinkedIn 或 Twitter 上的 @james2pl 。此外,请访问我的网站上的资源页面,这里有很多好书和顶级课程,开始构建您自己的数据科学课程吧!
Jupyter 有一个完美的代码编辑器
一切触手可及

笔记本一直是软件思想增量开发的工具。数据科学家使用 Jupyter 来记录他们的工作,探索和实验新的算法,快速勾画新的方法,并立即观察结果。
而且, JupyterLab 正在走向成为一个成熟的 IDE 只是不是你习惯的 IDE。凭借其出色的扩展和库,如 kale 和 nbdev ,它当然能够做的不仅仅是起草一个想法。查看下面的故事,了解更多信息。
但是,每隔一个月,我们可能要编辑一个.py文件。这个文件可能包含我们在笔记本中导入的一些实用函数,或者定义我们模型的类。这样工作是一个很好的实践,所以我们不会用许多定义污染笔记本。但是与 JupyterLab 捆绑在一起的文本编辑器仅仅是:一个简单的、没有特色的文本编辑器。
那么,我们能做什么呢?还有像这种的努力,它试图将摩纳哥编辑器(为 VS 代码提供动力的代码编辑器)集成到 JupyterLab 中。尽管如此,正如贡献者在 README 文件中明确提到的,“这个扩展仅仅是一个‘概念验证’实现,与生产状态相去甚远。“另外,上一次提交是在 3 年前(撰写本文时),所以它看起来不像是一个非常活跃的项目。
但是我们不需要任何延期。我们有一个终端。因此,我们可以拥有 ViM。而 ViM 有我们需要的一切;只是需要一些时间去掌握。
如果你爱维姆,你知道我在说什么。如果没有,先不要回避!这个故事向您展示了如何将 ViM 转换成 Python IDE,并与 Jupyter 一起使用。
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
Python 的 ViM
让我们言归正传。如果还没有 ViM,第一步实际上是安装它。在这个故事中,我假设我们在一个 hoster JupyterLab 环境中工作。如果您在本地工作,如果您更喜欢 VS 而不是 ViM,没有什么可以阻止您启动 VS 代码。
所以,我猜你是在云上的一个虚拟机中工作。这通常意味着 Linux 环境。要在 Debian 发行版上安装 ViM,运行以下命令:
sudo apt-get remove vim-tiny
sudo apt-get update
sudo apt-get install vim
注意,一些 Linux 发行版预装了vim-tiny。因此,我们需要先删除它,然后安装完整版本。
然后,让我们验证我们有我们需要的一切。运行vim --version并注意两件事:
- 您应该已经安装了 VIM > 7.3
- 检查
+python或+python3功能
我们准备好了。接下来,我们需要一个好的插件管理器。
武德勒
我发现[Vundle](https://github.com/VundleVim/Vundle.vim)是一个优秀且简单易用的插件管理器。因此,我们将使用它来安装我们需要的一切。要安装Vundle,我们需要两样东西。首先,git clone将项目放在一个合适的目录下:
git clone https://github.com/gmarik/Vundle.vim.git ~/.vim/bundle/Vundle.vim
然后,我们需要在我们的home目录中创建一个.vimrc文件,并在上面添加一些行。因此,首先,创建文件:
touch ~/.vimrc
然后,添加以下几行:
set nocompatible " required
filetype off " required
" set the runtime path to include Vundle
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
" let Vundle manage Vundle, required
Plugin 'gmarik/Vundle.vim'
" add all your plugins here between the vundle#begin() and "vundle#end() calls
" All of your Plugins must be added before the following line
call vundle#end() " required
filetype plugin indent on " required
看到那条叫vundle#begin()的线了吗?在这个调用和vundle#end()调用之间,我们可以添加任何我们想要的插件。事实上,我们已经这样做了:我们已经添加了gmarik/Vundle.vim插件。安装一个新的插件就像复制粘贴它唯一的 GitHub 路径一样简单。我们稍后会看到如何。
现在,启动 ViM,按下:进入命令模式,执行PluginInstall。我们走吧。
Python IDE
我们将安装的第一个插件支持折叠。你见过 numpy 源代码吗?通常一个函数的docstring会占据整个空间。默认折叠吧。通过在我们之前看到的begin和end调用之间添加以下代码来安装插件:
Plugin 'tmhedberg/SimpylFold'
一个提醒:每次添加新插件的时候,别忘了用我们看到的PluginInstall命令安装。
要默认启用docstring折叠,在 begin-end 块外添加以下设置。
let g:SimpylFold_docstring_preview=1
接下来,让我们启用自动缩进。安装以下插件(现在你知道怎么做了):
Plugin 'vim-scripts/indentpython.vim'
此外,您可以通过在vimrc文件中添加以下选项来告诉 ViM 您希望它如何处理.py文件:
au BufNewFile,BufRead *.py
\ set tabstop=4 |
\ set softtabstop=4 |
\ set shiftwidth=4 |
\ set textwidth=79 |
\ set expandtab |
\ set autoindent |
\ set fileformat=unix
这些设置的名称很容易理解。autoindent设置做了大部分正确的事情,但是安装vim-scripts/indentpython.vim插件,这是 python 特有的,让你安心。
最后但同样重要的是,你需要自动完成。这项工作的最佳工具是[YouCompleteMe](https://github.com/ycm-core/YouCompleteMe)。然而,它的安装有点复杂。首先,用下面一行安装插件:
Bundle 'Valloric/YouCompleteMe'
它很可能会在最后向您显示一个错误。别担心。继续并安装必要的依赖项:
apt install build-essential cmake python3-dev
apt install mono-complete golang nodejs default-jdk npm
最后,编译插件:
cd ~/.vim/bundle/YouCompleteMe
python3 install.py --all
就是这样!您已经拥有了将 ViM 转变为 Python IDE 所需的大部分东西。您可能需要考虑的其他插件有:
- vim-syntastic/syntastic:Python 语法高亮显示
- nvie/vim-flake 8:pep 8 检查
- scroolose/nerd tree:文件夹结构浏览器
- tpope/vim-逃犯 : git 集成
这里是一个完整但不详尽的.vimrc配置。如果你有更多的好东西要添加,请评论!
结论
笔记本一直是软件思想增量开发的工具。此外, JupyterLab 正在成为一个成熟的 IDE。但是,每隔一个月,我们可能要编辑一个.py文件,集成的文本编辑器只是一个文本编辑器。
这个故事研究了如何将 ViM 转换成 Python IDE,并通过终端将它用作我们的主要代码编辑器。如果您想了解更多关于使用 ViM 的信息,只需在您的终端中运行vimtutor并按照说明进行操作!
关于作者
我的名字是迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据操作的帖子,请关注我的 Medium 、 LinkedIn 或 Twitter 上的 @james2pl 。此外,请访问我的网站上的资源页面,这里有很多好书和顶级课程,开始构建您自己的数据科学课程吧!
Jupyter + IDE:如何让它工作
这篇文章描述了一个工作流程,它将在 IDE 中编写代码与在 Jupyter 笔记本 中使用该代码进行分析分开,同时实际上使使用笔记本更快更干净
介绍
如果你用 Python 处理数据,你可能知道 Jupyter 笔记本。这种格式对于同时编写代码和探索数据是有意义的..是吗?!
大多数关于依赖笔记本的批评都可以在这个精彩的演讲中找到: 我不喜欢笔记本,乔尔·格鲁什。总而言之,笔记本并不是一个大型项目的好环境:git 版本控制并不真正起作用,测试不受支持,最终笔记本变成了分散在各个单元的一堆代码。当然,所有这些都与一个简单的论点相悖:
“但是..笔记本太方便了”(大概一年前的我)
当处理数据时,您几乎永远不知道您的方法是否有效,因为您的代码正在运行。你总是在开发一个模型的过程中和之后做分析,跟踪不同假设的结果,记录观察结果,等等。笔记本格式确实符合这一流程。但这并不意味着不能改进。
利弊
我们来总结一下我们到底为什么对 Jupyter 笔记本和 IDEs(集成开发环境)又爱又恨。


PyCharm 中使用 pytest 的测试套件示例。
最后,让我们看看如何在一个简单的工作流程中结合两者的优点。
工作流设置
- (可选)使用 pyenv 为每个项目空间隔离您的 python。 安装指南 。
虚拟环境是一个不同的话题,但我认为它们也非常有帮助。
- 可编辑 pip 安装
我们使用 pip 将 python 指向一个将成为我们代码的“包”。虽然它不是一个真正的包,而是一个到我们代码的链接。这使我们可以像导入 python 包一样导入代码,同时还可以编辑代码并动态更新“包”。
cd YOUR_PROJECT_ROOT
mkdir lib
通过在项目根目录下创建一个setup.py文件来定义包:
from setuptools import setup
setup(
name='lib',
version='0.1.0',
packages=['lib'],
)
安装带有 pip 的可编辑标志的软件包:
pip install -e .
- 包装结构
我们仍然需要我们的代码有一个包结构。lib目录中的每个文件夹都需要有一个空的 init。py 文件。
|-- setup.py
|-- lib
| |-- **__init__.py**
| |-- tools
| |-- **__init__.py**
| |-- tool.py
举个例子,在lib/tools/tool.py中定义一个函数:
def yo():
print("Hello World")
现在,您可以使用以下命令在 python shell 中导入它:
>>> from lib.tools.tool import yo
>>> yo()
Hello World
- 自动重装
Jupyter 可以在您的 Jupyter 笔记本中使用autoreload.动态重新加载任何包更改,运行一次自动重新加载导入:
%load_ext autoreload
%autoreload 2
结果
现在,当我们使用我们最喜欢的 IDE 在lib中编辑代码时,我们会有:
- python 自动将编辑内容放到一个
lib包中, - Jupyter notebook 会在我们使用该软件包时自动传播更改。
只要您保存了正在处理的文件,更改就会立即从 IDE 传播到笔记本!注意,我不需要重新运行函数导入来查看更改。

我编辑了该函数,以便在 IDE 中打印不同的字符串。
我实际上是如何使用这个工作流程的:
它允许我将我的笔记本保持在要点上,记录我想要保留的结果,同时将高质量的代码保存在适当的存储库中,以便以后可以重用,而不需要在笔记本之间复制粘贴代码块。

它还允许我使用强大的 IDE 来开发高质量的代码,使我在记录代码、语法错误等方面浪费更少的时间。
Jupyter 现在是一个成熟的 IDE:事后看来
JupyterLab 3.0,可视化调试器,nbdev,Kale,IDOM。对于朱庇特计划来说,这是伟大的一年。

照片由努贝尔森·费尔南德斯在 Unsplash 拍摄
Jupyter 笔记本是软件思想增量开发的伟大工具。数据科学家使用 Jupyter 来记录他们的工作,探索和实验新的算法,创建新方法的快速草图,并立即观察结果。
然而,当时机成熟时,软件开发人员转向代码编辑器和 ide,如 Visual Studio Code 和 Pycharm,将想法转换成库和框架。
JupyterLab 是为了解决 Jupyter 笔记本的一些缺点而开发的。事实上,过去的 14 个月对 JupyterLab 来说是一个伟大的时期;它确立了自己作为该项目的下一代用户界面的地位,并且更接近于成为一个成熟的 IDE。
一个新的主要版本,允许您构建 Python 库并将代码单元转换为机器学习管道的扩展,一个新的小部件引擎和一个可视化调试器推动着项目向前发展。
欢迎来到朱庇特计划的魔法世界!
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
JupyterLab 3.0
2020 年 12 月 24 日,圣诞节前一天,团队发布了 JupyterLab 的版本3.0,作为给数据科学家和机器学习工程师的礼物。
首先,新版本支持多种语言。例如,按照官方文档中的教程将显示语言更改为简体中文。
接下来,简单界面模式(以前的单文档模式)使您能够专注于单个文档或活动,而无需关闭主工作区中的其他选项卡。

简单界面模式——作者图片
目录扩展现在是核心 Jupyter 的一部分,文件浏览器过滤器甚至更有用,因为它集成了用于命令面板的相同模糊匹配机制。

文件浏览器过滤器-按作者分类的图像
最后,JupyterLab 3.0 引入了一种以pip或conda包的形式分发 Jupyter 扩展的新方法,以及一种调用命令面板的新方法,看起来和感觉起来都更直观。
有关 JupyterLab 3.0 版本的更多详细信息,请阅读下面的文章:
nbdev
杰瑞米·霍华德和西尔万·古格,着迷于文化编程的想法,于 2019 年推出了 nbdev。这个框架允许您在熟悉的 Jupyter 笔记本环境中编写代码,在找到给定问题的有效解决方案之前探索和试验不同的方法。然后,使用某些关键字,nbdev 允许您将有用的功能提取到一个成熟的 python 库中。
更具体地说,nbdev 补充了 Jupyter,增加了对以下内容的支持:
- 遵循最佳实践,从笔记本中自动创建 python 模块
- 在标准 IDE 中编辑和导航代码
- 将任何更改同步回笔记本
- 从代码中自动创建可搜索的超链接文档
pip和conda包装- 测试
- 使用 GitHub 动作的持续集成
- 版本控制冲突处理
nbdev 使软件开发人员和数据科学家能够在不脱离 Jupyter 环境的情况下,遵循最佳实践,开发文档完备的 python 库。要开始,只需运行:
pip install nbdev
阅读以下关于 nbdev 的更多信息:
羽衣甘蓝
Kale 是一个开源项目,它简化了数据科学家使用 Kubeflow 和 Kubernetes 的体验。Kale 以 JupyterLab 扩展的形式提供了一个 UI,它可以将您的笔记本代码单元转换为机器学习管道,并将其部署在 Kubeflow 上。
你可以把 Kale 当成你的 Kubeflow 的机器学习项目 orchestrator 作为一名数据科学家,您可以在我们最喜欢的笔记本环境中工作,无需任何代码更改,就可以在 Kubeflow 和 Kubernetes 上运行您的 ML 管道。
此外,由于 Kale 与 AutoSklearn 的集成,您可以配置和执行超参数优化实验,将您的模型作为可伸缩的 API,甚至可以运行 AutoML 实验。
要开始使用 Kale,请查看以下资源:
- 从笔记本到 Kubeflow 管道
- 数据集版本化和管理
- 在 Kubeflow 中调试
- 【Katib 和 Kale 简化了超参数调整
- 在 Kubernetes 上为你的模特服务的最简单方式
可视化调试器
大约一年前,JupyterLab 的可视化调试器发布了。这是使 JuypterLab 成为成熟的 IDE 的一个步骤,因为它提供了 IDE 调试器所能提供的大部分功能:
- 变量资源管理器、断点列表和源代码预览
- 导航调用堆栈的可能性(下一行、进入、退出等)。)
- 直观地在感兴趣的行旁边设置断点的能力
- 指示当前执行停止位置的标志
然而,这个项目是建立在 xeus-python 内核上的,这是 python 编程语言的 Jupyter 内核的一个轻量级实现。xeus-python没有提供所有的 IPython 内核特性。最重要的是,它不支持魔术命令或 Matplotlib 图形,而这两者对于数据科学家来说是非常有用的。
关键词是“did”;o 一年后,xeus-python如果越来越接近与ipykernel旗鼓相当。我们准备好享受它带来的所有好处。
此外,对ipykernel的合并 pull 请求将可视调试器带到 Python 编程语言的主 Jupyter 内核中!
IDOM 部件
Jupyter 笔记本的交互特性是这个项目如此吸引人的原因。但是,为了更进一步,数据科学家使用 Jupyter 小工具来可视化他们的结果或创建迷你网络应用程序,以便于浏览内容或鼓励用户互动。
然而, IPyWidgets 并不总是容易使用。它们不遵循前端开发人员开创的声明式设计原则,并且生成的组件不能像在浏览器环境中那样进行传输。
此外,开发人员创建这些库主要是为了满足数据科学家的可视化需求。因此,它们缺少像 React 和 Vue 这样的流行前端框架带来的特性。
是时候迈出下一步了;IDOM 引入了用于定义和控制交互式网页或创建可视 Jupyter 组件的库。你关心的是第二部分。要阅读更多关于 IDOM 部件的信息,请阅读下面的故事:
结论
Jupyter 笔记本是软件思想增量开发的一个很好的工具,过去的 14 个月是这个项目的一个很好的时期。
一个新的主要版本(JupyterLab 3.0),可视化调试器,一个允许您编写和打包 Python 库的库,一个在不更改一行代码的情况下将您的代码单元转换为 ML 管道的库,以及一组新的小部件推动项目向前发展。
更重要的是,标准的 Jupyter 小部件越来越好,对笔记本文件的支持无处不在。
欢迎来到朱庇特计划的魔法世界!
关于作者
我叫迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请在 Twitter 上关注我的 Medium 、 LinkedIn 或 @james2pl 。
所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。
《VS 代码》中的 Jupyter:利弊
把一个程序当作一篇文学作品,写给人类而不是电脑

诺兰·伊萨克在 Unsplash 拍摄的照片
笔记本一直是软件思想增量开发的完美工具。数据科学家使用笔记本记录他们的工作,探索和试验新算法,快速勾画新方法,并立即观察结果。
把一个程序当作一篇文学作品,写给人类而不是计算机。
唐纳德·克努特
Jupyter 笔记本为数据科学家如何编译他们的项目带来了一场革命,允许他们使用一种有文化的编程形式来分析数据集。然后, JupyterLab 被开发来解决 Jupyter 笔记本的一些缺点,并且是该项目的下一代用户界面。
今天,我们多了一个选择:Visual Studio 代码。VS 代码的新 Jupyter 扩展完全支持我们喜爱的.ipynb文件,为编辑器带来了交互式编程。您可能会失去一些东西,比如您最喜欢的 Jupyter 扩展,但是调试之类的过程可能会变得更加简单。归根结底,这取决于您如何使用笔记本电脑。
最后,当你看完这个故事后,看看 Python 程序员和数据科学家的 VS 代码的 5 大扩展!
</5-visual-studio-code-extensions-for-data-scientists-937487b987c0>
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
VS 代码的 Jupyter
Visual Studio 代码的 Jupyter 扩展带来了笔记本支持、交互式编程和支持智能感知、调试等的计算。这个故事研究了这个扩展,以及如何将它集成到您的日常工作流程中。
创建 Jupyter 笔记本
VS 代码附带了一个方便的命令面板,允许您在不离开键盘的情况下发出命令。它的设计非常好,新的 JupyterLab 3.0 复制了它,创造了类似的体验。
因此,要创建一个新的 Jupyter 笔记本,启动命令面板(Ctrl+Shift+P)并搜索new notebook;应该是第一个结果:Jupyter: Create New Blank Jupyter Notebook。你总是可以通过在你的工作区触摸一个新的.ipynb文件来创建它,但是快捷方式总是让你更有效率。

创建一个新的空白 Jupyter 笔记本-作者图片
注意,VS 代码创建的笔记本默认是trusted。另一方面,我们进口的任何笔记本电脑都被视为not trusted保护我们免受恶意代码执行。因此,在执行之前,当编辑器提示我们时,我们应该手动trust笔记本。
创建笔记本后,使用顶部工具栏上熟悉的save图标将其存储在您的工作区中。

保存您的笔记本—作者图片
最后,我们可以使用相应的图标将笔记本导出为 Python 脚本或 HTML / PDF 文件。

导出您的笔记本—按作者分类的图像
使用编辑器
默认情况下,新笔记本会有一个空的代码单元供您开始使用。将您的代码添加到空单元格中,并使用ctrl + enter执行它。该命令将执行高亮显示的单元格。或者,您可以使用shift + enter来执行此单元格,同时创建并高亮显示下面的新单元格,或者使用alt + enter来执行高亮显示的单元格,在下面创建一个新单元格,但将焦点保持在前一个单元格上。

代码单元格-按作者排列的图像
您可以使用左侧的+图标添加新的代码单元,使用bin图标删除它,或者使用相应的箭头上下移动它。

代码单元格管理-按作者分类的图像
最后,将单元格类型更改为 markdown 真的很简单;只需点击代码上方的M图标。要将其改回code单元格,选择将出现的{}图标。或者,您可以相应地使用M和Y快捷键。

要降价的代码-按作者排序的图像
把事情做完
VS 代码的第一个真正伟大的特性是智能自动完成。编辑器可以显示成员列表、方法文档字符串和参数提示。

笔记本中的智能—作者图片
另一个有助于跟踪内存中变量的特性是变量浏览器和数据查看器。您可以在当前 Jupyter 会话中查看、检查和过滤变量。这缓解了笔记本电脑臭名昭著的无序执行问题。嗯,它并没有真正缓解这些问题,但给你一个提示。
运行代码后,单击顶部工具栏中的变量图标,您将看到当前变量的列表,这些变量将在代码中使用时自动更新。

可变资源管理器-按作者分类的图像
最后,让我们检查一下我们的调试选项。首先,VS 代码的 Jupyter 扩展支持在单个单元格中逐行执行。只需点击play图标旁边的按钮。

逐行执行—图片由作者提供
然而,最后一个调试选项是在 VS 代码中使用 Jupyter 的原因。您可以简单地将笔记本导出为 python 脚本并使用 VS 代码调试器,而无需改变环境!试试吧!
序
笔记本一直是软件思想增量开发的完美工具。第一次迭代 Jupyter Notebooks 为数据科学家编译项目的方式带来了一场革命,允许他们使用一种有文化的编程形式来分析数据集。
然后, JupyterLab 被开发来解决 Jupyter 笔记本的一些缺点,并且是该项目的下一代用户界面。
现在我们有了第三种选择:VS 代码。
关于作者
我叫 Dimitris Poulopoulos ,我是一名为 Arrikto 工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请在 Twitter 上关注我的 Medium 、 LinkedIn 或 @james2pl 。此外,请访问我的网站上的资源页面,这里有很多好书和顶级课程,开始构建您自己的数据科学课程吧!
作为产品的 Jupyter 笔记本

库尔特和凯瑟琳·克林史密斯的照片。
如何为客户将 Jupyter 笔记本格式化、准备和导出为专业的 HTML 产品
一旦数据科学家的分析完成,工作最关键的方面就开始了:向客户交付结果。在这一步,即使是最伟大的工作也可能因为糟糕的演示或不及时的交付而失败。阿金的航天器设计第 20 定律很好地总结了这个难题,它指出[1]:
一个糟糕的设计加上一个好的展示最终是注定要失败的。一个好的设计和一个糟糕的展示是注定要失败的。
传统上,产品交付意味着将编码输出转移到其他媒体,如 PowerPoint。但是,如果有一种方法可以将 Python Jupyter 笔记本,包括交互式图表,直接交付给客户呢?输入基于 HTML 的 Jupyter 笔记本作为产品(JNaaP)。
作为产品的 Jupyter 笔记本
JNaaP 的概念很简单:构造一个典型的 python Jupyter notebook [2],这样它就可以以一种清晰、可理解的方式为不同技术熟练程度的客户导出 HTML。
JNaaPs 是高度可分发的。几乎现代劳动力中的每个人都可以访问能够打开 HTML 文件的互联网浏览器,从而实现广泛的分发和最小的兼容性问题。
本文将演示如何构建作者创建的 HTML 格式的 JNaaP,这里有完整的存储库和数据:【https://github.com/kurtklingensmith/JNaaP】T2。点击“代码”和“下载 Zip”访问文件。
上述 GitHub 存储库中提供的 JNaaP 使用了本地 autocross 俱乐部提供的匿名数据。Autocross 是一项计时的业余赛车赛事,车手们在由锥形路标构建的赛道上行驶,它会生成大量数据。与在 GitHub 中查看相比,JNaaP 和笔记本在本地下载和查看时效果最佳。


作者提供的 HTML Jupyter 笔记本产品截图。
JNaaP 的主要考虑因素:
在构建 JNaaP 之前,数据科学家必须解决两个关键问题:
- 客户需求:客户需要通过数据科学功能解决哪些高级需求或问题?这驱动了 JNaaP 的结构。各个部分应该解决每个问题或需求,笔记本应该提供一个摘要。
- 客户技术考虑:客户想要访问代码吗?客户在技术上是否熟练?这推动了最终的演示技巧。创建 JNaaP 需要干净的代码;本质上更具技术性的客户可能希望在最终产品中有可见的代码。对于大多数客户来说,隐藏 HTML-export 上的代码是最好的方法,但这不是绝对的。
构建 JNaaP
要求:
有效的 JNaaP 构造需要广泛使用 nbextensions。这里有一篇关于 nbextensions 入门的文章: Jupyter 笔记本扩展,作者 Will Koehrsen【3】。所提供的示例 JNaaP 使用了以下 nbextensions 功能:
- 目录(2)
- 代码折叠
- 隐藏输入
- 隐藏所有输入
- plotlywidget/扩展

nbextensions 作者截图。
示例 JNaaP 还需要:
- nbconvert :用于导出【4】。
- Plotly Express :用于交互式可视化[5]。
设计 JNaaP
从结构上看,JNaaP 应该是独立的。阅读以下典型 JNaaP 元素列表时,在此下载提供的示例作为参考:
- 标题:标题应该简洁地概括笔记本的内容。考虑添加日期戳、作者和联系信息。使用降价并最大限度地利用降价格式功能。各种降价功能的概要可以在【6】中找到。下面是一个标题降价的例子:
**<center><font size = "6">The JNaaP Title<center>**
***
<center><font size = "2">Prepared by: Data Scientist<center>
- 背景:这应该通过阐述 JNaaP 的目的、关键分析目标以及理解 JNaaP 所必需的任何相关背景信息或故事来做好准备。这还应包括 预先的关键发现和结果 ,这些发现和结果由笔记本中稍后的分析提供支持。如果时间有限,客户应该只需要阅读这一部分,并相信笔记本中进一步的分析会支持调查结果。使用 markdown 来格式化和显示此部分。
- 目录:使用 nbextensions,目录(2)【7】扩展允许读者快速跳转到笔记本的不同部分。


作者目录截图:通过在 nbextensions 中启用目录来添加目录。确保单击了工具栏上的目录按钮。单击“目录”旁边的齿轮,并选中“添加笔记本目录单元格”,以确保目录出现在 JNaaP 中。
- 数据加载和设置:这是笔记本加载数据和库的地方。一般来说,这对客户来说用处不大,但是使用 print 语句显示数据帧头和一些汇总维度可以通过显示数据的可视化描述来增加价值。
- 分析部分:这是数据科学工作的地方,包括可视化。构建分析,使其从背景和客户需求中解决分析目标。解决这个问题的一个好方法是使用客户分析性问题的标题。请注意,干净的代码和干净显示的表格、结果和代码输出对于有效的 JNaaP 是必要的。明智地使用打印声明、降价和可视化技术,给人一种干净、专业的印象。
确保 HTML 中的交互式图表
Plotly Express 提供简单高效的交互式图表,具有干净、专业的外观。交互式方面允许用户放大或缩小图表,甚至生成屏幕截图。确保这些图表导出并在 HTML 文件中保持交互的关键是 hashtag 下面的代码:
import plotly.express as px
import plotly.graph_objects as go
import plotly.io as pio
# The below line ensures charts export to HTML
pio.renderers.default='notebook'
有了这段代码,交互式图表就可以导出了。下面是所提供的 JNaaP 的一个例子。注意所有轴都有标签,并提供了图例,查看者可以将鼠标悬停在数据点上以获取更多信息。清晰明了的演示对于成功的 JNaaP 至关重要。关于定制 Plotly 图表的更多文档可在此处【8】获得。
来自所提供的 JNaaP 的示例图表。
Python 打印的力量
Python 的 print()函数为 markdown 提供了一个强大的替代方案。值得注意的是,通过打印功能可以进行可重复的分析。考虑 JNaaP 示例中的以下内容:
mode = df['Car Make'].mode()
print("\u2022 Most common manufacturer:", mode.to_string(index=False))
上面的代码将获取 dataframe 并打印一条语句,标识数据集中最常见的汽车制造商。因为它不是 markdown,而是一个 print()函数,使用 python 来标识最常出现的条目,所以该代码可重复用于来自其他事件的未来数据集。
请注意“\u2022”文本,它会生成 unicode 项目符号。与 markdown 类似,Python print()函数有许多格式化的可能性,这将改善 JNaaP 的专业外观。示例 JNaaP 提供了一个设置类来打印粗体文本的例子。
发布到 HTML 文件
JNaaP 完成后,有几种方法可以将其导出到 HTML。导出前有两个注意事项:
- 有无代码:有些客户可能想看代码。其他人可能不会。保持所有代码的整洁,并在客户需要时做好记录。这将增强可解释性,减少 HTML 文件的混乱。
- 预览 JNaaP: 通常,大多数客户都不想看到代码。广泛使用 nbextension 的代码折叠【9】和隐藏输入允许在导出之前预览 JNaaP 的外观[10]。这可以通过避免重复导出来节省时间。
一旦确定代码包含完成,有几种方法可以将 JNaaP 导出到 HTML:
Jupyter Notebook 的内置功能:如果包含代码,这是创建 JNaaP 最简单的方法。这个方法就像点击文件,下载为,HTML(。html)。然后,Jupyter 会将笔记本作为 HTML 文件下载到浏览器默认的下载文件位置。

作者导出截图。要导出包含代码的 JNaaP,请单击“文件”、“下载为”、HTML(。html)。
使用 nbconvert 导出: Nbconvert 提供更多选项。下面的代码块做了几件事:
%%capture
!jupyter nbconvert --to html --no-input --no-prompt Notebook.ipynb
- 第一行(%%capture)确保不会显示 nbconvert HTML 导出行的输出。
- 最后一行将笔记本导出为 HTML。以 html 指定格式,没有输入,没有提示隐藏代码。行尾应该是正在转换的笔记本的文件名。
HTML 文件导出到 Jupyter 笔记本 ipynb 文件所在的目录。通过向 nbconvert 行添加以下代码,也可以使用深色主题:
--HTMLExporter.theme=dark
这将需要重新格式化 Plotly 图表配色方案,虽然;运行以下代码可以将 plotly 主题调整为暗:
pio.templates.default = "plotly_dark"
结论
将 Jupyter 笔记本作为基于 HTML 的产品交付,通过将基于代码的分析工作作为最终产品生产的一部分,简化了数据科学工作。它还通过消除从一个工具(Jupyter)到其他工具(如 PowerPoint 或 Word)的翻译工作来减少错误和返工。最后,HTML 文件具有广泛的兼容性,易于传输,使得产品易于交付给客户。最终,结构良好的 JNaaPs 可以提供一种可重复的一体化分析和报告生成的方法。在这种情况下,非数据科学家可以拿一个准备好的 JNaaP 笔记本,执行它,并生成一个可交付的产品。
请随意参考链接示例并创建自己的 JNaaPs。
参考
[1] D .阿金,阿金的宇宙飞船设计法则 (2021),戴夫·阿金的网站。
[2]朱庇特项目,朱庇特项目 (2021),https://jupyter.org/。
[3] W. Koehrsen, Jupyter 笔记本扩展 (2018),走向数据科学。
[4] Nbconvert, nbconvert:将笔记本转换为其他格式 (2021),Nbconvert。
[5] Plotly Express,Plotly Express | Python | Plotly(2021),Plotly |图形库。
[6] M. Zaman,终极降价备忘单 (2021),走向数据科学。
[7]jupyter _ contrib _ nb Extensions,目录(2) (2021),非官方 Jupyter 笔记本扩展。
[8] Plotly Express,Plotly Express | Python | Plotly(2021),Plotly |图形库。
[9]jupyter _ contrib _ nb Extensions, Codefolding (2021),非官方 Jupyter 笔记本扩展。
[10]jupyter _ contrib _ nb Extensions,隐藏输入 (2021),非官方 Jupyter 笔记本扩展。
Jupyter 笔记本不在 GitHub 上渲染?这里有一个简单的解决方案。
你可以用这个网站代替!
你有没有尝试过预览你的 Jupyter 笔记本文件,并在等待了大约 20 多秒后收到这个讨厌的错误信息?

大约 70%的时候,我们会看到这条信息。仿佛看你的.ipynb文件会不会渲染就是一场赌博。
好消息,这个“对不起,出了点问题。重装?”消息对您的实际提交没有影响。这只是 GitHub 的一个问题,因为它无法呈现文件的预览。
经过大量的研究,似乎在互联网上没有人很确定为什么会出现这个问题。人们推测这可能是文件大小的问题,或者是浏览者使用的浏览器类型的问题。
不管是什么导致了这个问题,不要担心。我有你祈祷的答案!
解决方案

Nbviewer 是一个 web 应用程序,让你在 GitHub 上输入一个 Jupyter 笔记本文件的 URL,然后它将这个笔记本呈现为一个静态的 HTML 网页。这给了你一个稳定的链接,你可以和其他人分享。
其他好处
除了总是能成功渲染一个 Jupyter 笔记本,它还对用户有其他优势。
在极少数情况下,.ipynb文件实际加载到 Github 上时,有时会无法显示某些对象。
例如,GitHub 无法加载 follow 地图。当我们试图生成洛杉矶的地图时,我们得到了这个错误:
Output of folium.__version__
然而,如果我们使用 nbviewer,完整的交互式地图加载没有问题。自己看吧!

此外,这个网站的功能并不是 Python 独有的,你可以用它来显示包含其他编程语言的文件,比如 Ruby 和 Julia。
总的来说,如果您是团队中唯一的技术专家,并且您需要能够轻松快速地将 Jupyter 笔记本分发给可能没有安装学习环境的同事,那么这是一个很好的解决方案。不幸的是,你仍然不能在私有存储库上共享文件。
所以,下次当你发现自己要等 20 多秒才能在 GitHub 上呈现一个代码文件时,请记住,nbviewer 会让你的生活变得更轻松!
Jupyter 笔记本还是实验室还是 VS 代码?
为什么不是全部?

艾通过作者创造艺术。见上opensea as NFT;受到阿曼达·冯【https://unsplash.com/photos/1w2xsyc2wwI 的启发
在过去的几年里,我一直在使用各种 ide 进行 Python 开发。最近,我问自己,检查更新我目前的实践是否有用,看看替代方案是否能提供更好的生产率,这是否有意义。经常会有这样一个问题:一个 IDE 是否比另一个好。在这篇文章中,我想说明最好的方法是为特定的任务使用最好的工具。
目录
- Jupyter 笔记本还是实验室还是 VS 代码?为什么不是全部?
- 目录
- 为什么你不需要决定哪个更好
- 为什么要 Jupyter 笔记本
- 为什么选择 Jupyter 实验室
- 为什么 VS 代码
- 免责声明
- 关于
为什么你不需要决定哪个更好
目前,我混合使用
- Jupyter 笔记本
- 朱庇特实验室
- VS 代码
我总是问自己,Jupyter 实验室是否已经发展到可以取代我的 Jupyter 笔记本(NB)工作流程。简而言之答案是否定的,NB 相对于 Lab 还是有很多优势的,我会在下面详细阐述。但是,理解这一点很重要,它不需要被替换。对于他们擅长的任务,你可以很容易地使用他们两个。
因此,我使用:
- 用于开发数据科学概念验证(POC)的 NB
- Jupyter 实验室用于管理和重新安排我的概念证明
- VS 与笔记本无关的代码。
本质上,我在一个数据科学项目中不同程度地使用了这三种工具。
为什么是 Jupyter 笔记本
我仍然在我的大部分 POC 工作中使用 NB。以下是一些原因:
主题化和语法突出显示
使用 jupyterthemes,您可以根据自己的需求轻松调整主题。我用了很多“切斯特主义”主题(jt -t chesterish -T -N),看起来像

切斯特主义主题;作者截图
您可以使用各种 jupyterthemes 标志指定。目前,我将它与!jt -t chesterish -f fira -fs 10 -nf ptsans -nfs 11 -N -kl -cursw 2 -cursc r -cellw 95% -T一起使用(你会在其他文章中找到类似的设置)。查看官方网站查看旗帜及其含义的完整列表。该设置如下所示:

风格笔记本;作者截图

笔记本 Overeview 作者 GIF
我更喜欢深色主题,因为我经常在显示器前工作,任何有助于减轻我眼睛疲劳的东西都很受欢迎。
笔记本配置
我使用了一些特定的 NB 配置,可能对你也有帮助。
%load_ext autoreload
%autoreload 2
%matplotlib inline
%config IPCompleter.greedy = Truepd.options.display.max_columns = None
pd.options.display.max_rows = 200sns.set_palette("bright")
sns.set(style="darkgrid")
sns.set(rc={'figure.figsize':(30,30)})InteractiveShell.ast_node_interactivity = "all"ip = get_ipython()
ip.register_magics(jupyternotify.JupyterNotifyMagics)
%autonotify -a 120
- 自动重新加载允许我重新加载导入的。当我计算一个单元格时。由于 Jupyter NB 和 VS 代码文件之间的交互,我需要在两种环境下开发,并希望我的笔记本中的所有内容都是最新的
- 贪婪的 IP completer 允许我列出 python 字典中的所有选项,并通过 tab 键浏览它们,而不是查找每个选项。不过要小心,因为 NB 中有太多大对象可能会降低速度。
- 熊猫(pd)和 seaborn (sns)选项只是我的一个偏好设置。我不希望 pandas 数据帧中的行经常被截断,我也希望 seaborn 数据帧中的行更大
- 节点交互性“all”只是输出所有语句,而不是最后一条语句。这使我不必总是为我的语句键入“print ”,而可以简单地键入变量名。请注意,这也会导致绘制图形的不同行为。
- 最后一个是 jupyternotify。这非常有帮助,因为一些计算需要时间(例如训练模型,或优化超参数)。使用此选项,您可以设置一个计时器,并在计算完成时通知您。当您想在计算过程中处理其他零件时,这非常有用。
NB 扩展
jupyter NB 有各种笔记本扩展。以下是我使用的一些:

笔记本扩展;作者截图
- 用于格式化代码并使其更具可读性
- 隐藏输入和可折叠标题,用于显示单元格的结果而非代码。并且还关注笔记本中的某些部分。有助于演示
- 突出显示选中的单词,显示我在哪里使用了我想要编辑的相同变量
- 代码折叠用于细胞中更复杂和更长的功能
- 目录用于显示笔记本的标题。这对于浏览笔记本并使其更具可读性是绝对必要的。
- 执行时间用于了解执行需要多长时间。在训练和比较 ML 模型和参数优化方面非常有用。
- 最后,注释热键如果你使用不同于英文的键盘布局,这是必须的。我在 macOS 中使用德语键盘,因此代码注释快捷键不起作用。使用 jupyter NB,您可以选择设置不同的热键。这是我至今不使用 jupyter 实验室的一个重要原因。因为您仍然没有这个选项,并且除了手动键入“#”之外,没有其他方法来注释/取消注释代码部分。如果你想要适当有效的编码,这是无法忍受的。
我不使用“腹地”扩展来完成代码。我过去用过,但是性能不好,还拖慢了整个笔记本。
“变量检查器”也是如此。一旦你存储了更多的数据帧或模型,就会降低笔记本的速度,使其无法使用。我花了一段时间才发现这些扩展导致了问题。因此,我不再使用它,如果你的笔记本更大,我建议你不要使用它。
为什么是朱庇特实验室
目前,我只使用 Jupyter 实验室进行笔记本整理。我的存储库是用 VS 代码管理的,但有时我需要重新整理笔记本。这不能在 VS 代码中完成,而且用 Jupyter NB 很麻烦。要么我想检查我在类似的笔记本中完成了哪些步骤,要么我想复制某些单元格。此外,在 Juypter Lab 中拆分笔记本要容易得多
- 对您的笔记本电脑有一个很好的概述,
- 在一个选项卡中打开多个笔记本
- 复制并拖动笔记本中的多个单元格

Jupyter 实验室概述:作者截图
为什么 VS 代码
对于 Jupyter NB 中没有完成的事情,我使用 VS 代码。我知道 VS 代码支持。ipynb 文件与“笔记本风格”的方法。然而,直到现在,它还没有达到真正的 Jupyter NB 的好处(见上面我的列表),而且速度也非常慢。装货总是要花很长时间,我已经烦透了。
但是一旦我离开笔记本环境,我就用 VS 代码做所有的事情。我已经用了很多年了,在我看来它仍然是最好的选择。
原因如下:
- 语法突出显示
- 代码完成和建议
- 功能和文件导航
- 扩展和集成(如 Docker、林挺、格式化、测试、代码片段)
- 饭桶

VS 代码概述;作者截图
基本上,在笔记本概念验证之后开发应用程序所需的一切在 VS 代码中都很棒。
如果你使用另一个 IDE(例如 PyCharm)而不是 VS 代码,我认为这也足够了。在我看来,如果你已经用 IDE 开发了一个特定的工作流,并且它工作正常,那么切换就没有太大的意义了。我更喜欢 VS 代码的原因是轻量级和可定制性。它非常直观,易于上手。不需要创建项目什么的。只需添加您需要的扩展并开始编程。你可以想加多少就加多少,也可以保持超级苗条。它还可以支持许多其他语言,这使得它非常适合在大型项目中使用。
放弃
我与本文中使用的任何服务都没有关联。
我不认为自己是专家。我不是博主什么的。除了做其他事情,我只是记录事情。因此,这些内容并不代表我任何作品的质量,也不完全反映我对事物的看法。如果你觉得我错过了重要的步骤或者忽略了什么,可以考虑在评论区指出来或者联系我。
我总是乐于听取建设性的意见以及如何改进。
这是 2021 年 3 月 16 日写的。我无法监控我的所有文章。当你阅读这篇文章时,提示很可能已经过时,过程已经改变。
如果你需要更多关于某些部分的信息,请在评论中指出来。
关于
丹尼尔是一名艺术家、企业家、软件开发人员和商业法毕业生。他曾在各种 IT 公司、税务咨询、管理咨询和奥地利法院工作。
他的知识和兴趣目前围绕着编程机器学习应用程序及其所有相关方面。从本质上说,他认为自己是复杂环境的问题解决者,这在他的各种项目中都有所体现。
如果您有想法、项目或问题,请不要犹豫与我们联系。

连接到:
直接:
Jupyter 笔记本& Kubernetes 上的火花

设置本地环境的完整指南
Jupyter notebook 是一款知名的运行实时代码的 web 工具。Apache Spark 是一个流行的数据处理引擎,Kubernetes 上的 Spark 终于 GA !在本教程中,我们将在 Kubernetes 中打开一个 Jupyter 笔记本,并在客户端模式下运行一个 Spark 应用程序。我们还将使用一个很酷的 sparkmonitor 小部件进行可视化。此外,我们的 Spark 应用程序将从 AWS S3 读取一些数据,这些数据将在本地使用 localstack S3 进行模拟。

正在运行的应用程序(作者图片)
装置
先决条件:
- git(2 . 30 . 1 版)
- docker-desktop(3 . 2 . 1 版)和 Kubernetes(1 . 19 . 7 版)
- AWS-CLI(2 . 1 . 29 版)
- kubectl (v1.20.4)
Jupyter 安装:
我们的设置包含两个图像:
- Spark 图像—用于旋转 Spark 执行器。
- Jupyter 笔记本图像—用于 Jupyter 笔记本和 spark 驱动器。
我已经将这些图像发送到 docker-hub 中,因此您可以通过运行以下命令快速获取它们:
docker pull itayb/spark:3.1.1-hadoop-3.2.0-aws
docker pull itayb/jupyter-notebook:6.2.0-spark-3.1.1-java-11-hadoop-3.2.0
或者,您可以从头开始构建这些映像,但这有点慢;有关这方面的更多信息,请参见附录。
下面的 YAML 包含了运行 Jupyter 和 Spark 所需的所有 Kubernetes 资源。在本地将以下文件另存为 jupyter.yaml :
接下来,我们将为 spark 创建一个新的专用名称空间,安装相关的 Kubernetes 资源并公开 Jupyter 的端口:
kubectl create ns spark
kubectl apply -n spark -f jupyter.yaml
kubectl port-forward -n spark service/jupyter 8888:8888
请注意,专用名称空间有几个好处:
- 安全性 Spark 需要创建/删除 pod 等权限。最好将这些权限限制在特定的名称空间。
- 可观察性——Spark 可能会产生许多 executor pods,因此如果它们被隔离在一个单独的名称空间中,跟踪它们可能会更容易。另一方面,您不希望错过所有这些 executor pods 之间的任何其他应用程序 pod。
就是这样!现在打开你的浏览器,进入 http://127.0.0.1:8888 ,运行我们的第一个 Spark 应用程序。
本地堆栈安装:
下面你可以看到在 Kubernetes 中安装 localstack 的 YAML 文件:
在本地将该文件保存为 localstack.yaml ,安装 localstack 并通过运行以下命令来暴露端口:
kubectl apply -n kube-system -f localstack.yaml
kubectl port-forward -n kube-system service/localstack 4566:4566
现在我们有了本地运行的 S3,让我们创建一个桶并在里面添加一些数据:
在本地将该文件保存为 stocks.csv,并使用以下命令将其上传到我们的本地 S3:
aws --endpoint-url=[http://localhost:4566](http://localhost:4566) s3 mb s3://my-bucket
aws --endpoint-url=[http://localhost:4566](http://localhost:4566) s3 cp examples/stocks.csv s3://my-bucket/stocks.csv

pod/名称空间分布(作者图片
运行 Spark 应用程序
在 Jupyter 主页上点击“新建”按钮,然后点击 Python3 笔记本。在新笔记本上复制以下代码片段:
然后点击“文件”→“另存为……”,称之为“spark_application”。我们将立即从应用程序笔记本中导入此笔记本。
现在让我们创建我们的 Spark 应用程序笔记本:
现在运行此笔记本,您将看到结果!
观察
我希望本教程可以帮助你走向生产。请注意,在进入生产环境之前,需要采取一些措施(特别是在安全性方面)。以下是其中的一些:
- 应用程序被包装在 try/except 块中,以防应用程序失败,我们希望确保没有执行器继续运行。失败可能会让 Spark 执行器运行,这会消耗冗余资源。
- 我们使用 AnonymousAWSCredentialsProvider 来访问本地 S3。在生产中,将身份验证提供者更改为WebIdentityTokenCredentialsProvider或SimpleAWSCredentialsProvider。
- 为本地工作添加了以下配置(使用 local stack):spark . Hadoop . fs . s3a . path . style . access = true**spark . Hadoop . fs . s3a . connection . SSL . enabled = false
- 为了简单起见,我们使用 root 用户,但是最佳实践是在生产中使用非 root 用户。
- 我们在本教程中禁用了 Jupyter-notebook 的身份验证。确保您的笔记本电脑仅暴露在您的 VPN 中,并从 CMD 中移除空令牌。
- 在生产中,您将需要为 jupyter 和 executors 授予 S3 访问权限。您可以使用通常与 Kubernetes 服务帐户相关联的 IAM 角色和策略。
- 我们使用持久性卷来保存笔记本。在生产中,您需要将存储类名:主机路径更改为 gp2 (或者您正在使用的任何名称)。
附录

Docker 图片层次可视化(作者图片)
- 如果您想在本地构建自己的 spark 基本映像,可以从主 apache 归档文件下载 Spark,解压缩并运行构建脚本:
wget [https://archive.apache.org/dist/spark/spark-3.1.1/spark-3.1.1-bin-hadoop3.2.tgz](https://archive.apache.org/dist/spark/spark-3.1.1/spark-3.1.1-bin-hadoop3.2.tgz)
tar xvzf [spark-3.1.1-bin-hadoop3.2.tgz](https://archive.apache.org/dist/spark/spark-3.1.1/spark-3.1.1-bin-hadoop3.2.tgz)
cd [spark-3.1.1-bin-hadoop3.2](https://archive.apache.org/dist/spark/spark-3.1.1/spark-3.1.1-bin-hadoop3.2.tgz)
./bin/docker-image-tool.sh -u root -r itayb -t 3.1.1-hadoop-3.2.0 -p kubernetes/dockerfiles/spark/bindings/python/Dockerfile build
docker tag itayb/spark-py:3.1.1-hadoop-3.2.0 itayb/spark:3.1.1-hadoop-3.2.0
2.要为上面的 spark 基本映像添加 AWS S3 支持,您可以构建以下 docker 文件:
并使用以下命令构建它:
docker build -f spark.Dockerfile -t itayb/spark:3.1.1-hadoop-3.2.0-aws .
3.构建 Jupyter 笔记本 docker 映像时,您可以使用以下 docker 文件:
并使用以下命令构建它:
docker build -f jupyternotebook.Dockerfile -t itayb/jupyter-notebook:6.2.0-spark-3.1.1-java-11-hadoop-3.2.0 .
摘要
我们在 Kubernetes 应用程序上运行了我们的第一个 Spark,并在本地环境中运行了模拟 AWS S3 (localstack)。我们还使用了一个非常有用的小工具来监控 spark 进程(由 swan-cern )。现在是时候写一些很棒的 ETL 了!
最后但同样重要的是,感谢阿萨夫·加利亚帮助我完成这个项目。
Jupyter 笔记本 vs PyCharm
意见
当数据科学家应该使用一个而不是另一个的时候

美国宇航局在 Unsplash 上拍摄的照片。
目录
- 介绍
- Jupyter 笔记本
- 皮查姆
- 摘要
- 参考
介绍
作为一名仍在教育环境中学习的数据科学家,你可能会使用一个主要工具,而作为一名专业数据科学家,你可能会专注于另一个不同的工具。当然,使用多种工具或平台是有益的,但具体使用哪种工具和平台有时间和地点的限制。许多数据科学家使用的两个有益且重要的工具是 Jupyter Notebook 和 PyCharm。每一个都有其各自的功能,但最终目标可能惊人地相似,那就是组织和执行数据科学过程的代码(在本文中仅指数据科学)。话虽如此,我想在下面强调两者的好处以及何时使用其中一个。
Jupyter 笔记本

NBextensions 选项卡(这是一个非常有用的附加组件)。作者截图[2]。
该工具对于教育机构和专业机构中的数据科学家来说非常有用。使用它的时间通常是在项目开始的时候,在这个时候你的代码不是一成不变的,你关注的是研究而不是最终产品。
当开始一个数据科学项目时,您可以使用 Jupyter Notebook [3】导入数据、分析数据、选择特定功能以及创建新功能、创建模型并进行比较,并在进行过程中可视化大多数步骤。你甚至可以在你的笔记本电脑上完成大部分的端到端数据科学过程,除了一个主要步骤(然而,有一些平台正在将笔记本电脑与更多的机器学习操作步骤)相结合,这就是部署,你通常会与另一个平台如 AWS 一起完成。
除了模型部署,您可能希望在我们将在下面讨论的下一个工具中执行这些主要的数据科学步骤,但是当您第一次开始时,我认为在您的笔记本中预处理和训练数据更容易,而不必担心生产部分。
为了使这些要点更清楚,下面是你什么时候可以和应该使用 Jupyter 笔记本:
- 样机研究
- 数据摄取
- 探索性数据分析
- 特征工程
- 模型比较
- 最终模型
这些步骤在数据科学的研究步骤中更受欢迎的原因是,它只是更容易-然而,这种说法可能并不适用于每个人,因为它最终取决于偏好。
话虽如此,让我们来强调一下 Jupyter 笔记本的优势:
- 自由的
- 简单的启动,只需在你的终端输入
juptyer notebook - 可视化显示(用户界面
- 文本编辑(通用代码注释、降价、代码修饰、可折叠标题、荧光笔、拼写检查器、便笺本
- SQL 自适应(用户名/密码/主机/端口/数据库名设置
皮查姆

Chris Ried 在Unsplash【4】上拍摄的照片。
py charm【5】是一个类似的工具,它组织代码并帮助运行数据科学过程。它甚至有 Jupyter 笔记本支持——然而,它只是在付费的专业版本中可用。也就是说,如果你正在使用那个版本,那么很多好处和何时使用也将适用于 PyCharm——然而,我仍然认为将它们分开更容易——因为当它在 py charm 中显示时,UI 变得有点不稳定。因此,假设我们正在使用 PyCharm 的社区版本(免费版本),我们将突出显示该产品,而不是与 Jupyter Notebook 集成的产品。
为了更清楚地说明这一点,下面是您可以并且应该使用 PyCharm 的情况:
- 代码编辑
- 用于生产(通常不是研究)
- 代码是长期的(不像 Jupyter,它专注于试错)
如您所见,主要区别在于 PyCharm 用于通常是最终产品的代码,而 Jupyter 更多地用于基于研究的编码和可视化。
话虽如此,让我们强调一下 PyCharm 的优势:
- Python 开发
- Git 集成
- 代码格式
- PEP-9 风格
- 调试器功能
- 运行脚本
- 单元测试
- 更多的开发人员可能习惯于使用这个工具,所以就整理而言,这个工具在工程部门或角色之间更容易使用
正如您所看到的这些好处,其中许多与数据科学的软件工程方面相吻合,或者只是简单的软件工程。
摘要
总而言之,这两种工具对于数据科学家来说都非常有用。有些人可能更喜欢其中一个,当然,这最终取决于你和你工作的公司,或者如果你在学校,或者作为一名专业数据科学家工作。PyCharm 可以从 Jupyter Notebook 中获得很多好处,但是在笔记本中进行快速、反复试验的数据科学研究使这个过程变得容易得多。然而,一旦完成了这一部分,您很可能会转向另一个工具来实现您的最终代码库,其中的代码是 PyCharm。如果你是一名机器学习工程师,那么 PyCharm 可能是你学习的完美工具。
总而言之,这两种工具都有一些重要的优点:
* Use Jupyter Notebook for protyping and research* Use PyCharm for the final code repository and its respective implementations
我希望你觉得我的文章既有趣又有用。如果您同意或不同意这些工具之间的比较,请随时在下面发表评论。为什么或为什么不?你认为还需要指出哪些比较(或差异)吗?这些当然可以进一步澄清,但我希望我能够阐明一些共同的相似之处、不同之处,以及何时使用 Jupyter 笔记本或 PyCharm 工具。感谢您的阅读!
我与这些公司都没有关系。
请随时查看我的个人资料、 Matt Przybyla 、和其他文章,并通过以下链接订阅接收我博客的电子邮件通知,或通过点击屏幕左侧的 的 订阅图标,如果您有任何问题或意见,请在 LinkedIn 上联系我。
订阅链接:https://datascience2.medium.com/subscribe
参考
[1]美国宇航局在 Unsplash 拍摄的照片,(2021)
[2] M.Przybyla,Jupyter 笔记本截图的 NBextensions 选项卡附件,(2021)
[3]Jupyter 项目, Jupyter 笔记本主页,(2021)
[4]克里斯·里德在 Unsplash 上拍摄的照片,(2018)
[5] JetBrains s.r.o ., PyCharm 主页,(2000–2021)
没有代码的 Jupyter 笔记本——米托之路
有什么好的吗?

我使用的第一个综合统计分析软件是 SAS,开始使用 SAS 并不容易,因为它有自己的语法,在我能够使用它做任何事情之前,我必须学习它。当然,在我学会之后,它变得非常方便,因为你可以在你的项目中重用代码。
后来又碰到了 SPSS,另一种常用的统计软件。这个软件基本上是点击式的,你可以在图形用户界面中进行数据处理和分析。一个特别有用的特性是根据您所做的操作自动创建脚本。使用生成的脚本,您可以简单地将其应用于其他类似结构的数据集。
对于初学者来说,学会 SPSS 似乎更容易,因为与用 SAS 编写代码相比,点击更直观,尤其是如果你没有任何编程经验的话。
最后几段是我第一次遇到美图时想到的想法,这是一个基于 Jupyter 的工具,它使用点击的方式准备并呈现你的数据。就像 SPSS 一样,它可以根据你所做的操作生成代码。因此,对于代码经验较少的数据科学初学者来说,mito 可能是一个不错的起点。
等一下。美图到底是做什么的?让我们在这篇文章中探索一下。
假设
在您进入本教程之前,让我们假设以下事情,以便我们在同一页上。
- 已经在你的电脑上安装了 Python。也请确保你的 Python 版本是 3.6+。在您的终端中,您可以使用
python — version进行检查。 - 有使用 Jupyter 笔记本的经验。为了更好的笔记本体验,请确保您安装了 jupyter lab 。
- 知道如何设置虚拟环境。conda 是一个很好的工具,参见我的文章中的说明。
装置
在终端中,输入以下命令安装安装程序。
python -m pip install mitoinstaller
然后,您可以运行以下命令,使用安装程序安装 mito 库:
python -m mitoinstaller install
在 Jupyter 笔记本中创建工作表
在终端中,激活所需的虚拟环境后,可以通过运行jupyter lab启动 jupyter lab。您将看到 jupyter 服务器正在默认的 web 浏览器中运行。
创建一个笔记本,并在单元格中输入以下代码行,这将为您创建一个 mito 表。
import mitosheet
mitosheet.sheet()
请注意,您必须使用您的电子邮件注册,然后才能继续。然后会提示您选择要导入的文件。对于本教程,让我们使用作为 seaborn 数据集一部分的 mpg 数据集。导入后,你会看到下面的表格。有用的一点是数据集的形状显示在底部的右上角。因此,您将对文件的导入是否正确有一个合理的想法。

导入的数据
如你所见,这种床单的整体外观非常干净。就我个人而言,我喜欢这种字体和它的大小,它们很悦目。
代码自动生成
如开头所述,mito 能够为您刚刚完成的步骤自动生成代码。因此,在导入数据集后,您将看到一个带有代码的单元格出现在当前单元格的下方。
自动生成用于导入的代码
一切都应该是简单明了的,因为 mito 不仅生成代码,它还注释代码,这样对于那些不熟悉 Python 或 pandas 的人来说就很清楚了。
浏览数据
你能做的第一件事是探索你的数据。特别是,您可以快速查看数据的列。

数据查看器
如上面的动画图像所示,选择列后,将显示数据资源管理器。有三个选项卡。
- 过滤/排序:您可以通过指定一系列标准来过滤您的数据,并且您可以根据需要对数据进行排序。
- Value :显示频率表,这样你就可以知道有哪些可用的值以及它们的频率。
- 汇总统计数据:直方图非常方便,因为它提供了数据分布的直观概览。接下来,您将看到摘要
在动画中,您可能会注意到我们使用mpg列对数据进行排序。该操作产生了额外的代码行,这些代码行说明了这些操作并被添加到单元中。
操作步骤
到目前为止,我们已经完成了操作数据集的几个步骤。一个有用的方法是通过点击右边的“步骤”按钮来查看步骤。下图将展示这些步骤。

步骤历史
美图的一个有用的特点是,你可以很容易地清除这些步骤和撤销/重做你的步骤。正如你所注意到的,在顶部有不同的按钮:撤销、重做和清除。例如,如果您单击“清除”,您会看到我们已经完成的步骤将从历史记录中删除。如果您只想撤消几个步骤,也可以单独删除前面的步骤。
数据透视表
对于许多初学者来说,在 Pandas 中创建数据透视表不是最简单的,因为参数不是太清楚。幸运的是,使用美图似乎更容易——下面的截图向您展示了这样的操作。

如你所见,美图使用的术语与熊猫不同。本质上,它使用行和列来表示创建的数据透视表,这样您可以首先可视化您的数据透视表,然后指定所需的数据。下面的代码片段向您展示了相应的 Python 代码。你可以看出用美图的方法更直观。
pivot_table = tmp_df.pivot_table(
index=['model_year'],
columns=['origin'],
values=['mpg'],
aggfunc={'mpg': ['mean']}
)
合并表格
也可以通过点击“合并”按钮,直观地将数据帧与美图合并。在菜单中,您可以指定要合并的表格。支持常见的合并类型,如下图所示。

指定这两个表后,可以指定它们合并的键。但是,我注意到这里有一个限制,因为您只能为每个表指定一个键。如果我没有弄错的话,如果你想使用多个键,它现在似乎不支持这个功能。
创建图表
您也可以使用 mito 创建图形,尽管现在支持的图形看起来很有限。

图表
正如你所看到的,你现在只能用美图创建柱状图、柱状图和散点图。与前面步骤不同的一点是,创建图形的代码不会自动包含在单元格中。为了方便您,我已经为您复制了代码。
# Import plotly and create a figure
import plotly.graph_objects as go
fig = go.Figure()# Add box plots to the graph
for column_header in ['mpg', 'horsepower']:
fig.add_trace(go.Box(y=mpg_csv[column_header], name=column_header))# Update the title and stacking mode of the graph
# See Plotly documentation for customizations: [https://plotly.com/python/reference/box/](https://plotly.com/python/reference/box/)
fig.update_layout(
title='mpg, horsepower box plot',
barmode='stack'
)
fig.show(renderer="iframe")
如你所见,美图使用 plotly 作为其绘图后端。
保存分析并重放
在许多情况下,我们需要重复我们的处理步骤。米托也使之成为可能。您只需点击顶部的“保存”按钮即可保存您的分析。当您需要使用不同的数据集重新运行分析时,只需单击“REPLAY ”,即可开始重新进行分析。



最后的想法
除了上述操作之外,您还可以添加和删除列,这对于您来说应该非常简单,不用我向您展示这些操作。差不多就是对这个美图工具的回顾了。
在我看来,美图库似乎是一个仍在开发中的成长工具。开发人员似乎很勤奋,并且正在努力为那些不太懂编码的人制作一个更好的工具。也就是说,它可能对那些不熟悉 Python 或 Pandas 的人有用。然而,我怀疑这个工具的长期使用,因为到目前为止,所有这些操作都不需要复杂的编码技能。换句话说,mito 正试图解决一些不太难编码的问题,因此大多数人可以学习编码来解决这些问题,而无需大量的时间投入。
与此相关,美图团队的开发人员可能会考虑的另一件事是,如果用户已经知道安装 Python 和 Jupyter Notebook,他们可能对 Python 和 Pandas 编程相对熟悉。有了这种水平的编码技能,他们应该已经熟悉了美图在这个阶段必须提供的操作。换句话说,美图的目标受众似乎并不明确。
尽管如此,我很感激开发人员做出了巨大的努力,将这个 GUI 工具放在一起,以推进数据科学领域。
感谢阅读这篇文章。通过注册我的简讯保持联系。还不是中等会员?用我的会员链接支持我的写作。
在 Python 数据科学项目的虚拟环境中使用 Jupyter Notebook
了解如何安装 kernelspec 来访问 Jupyter Notebook 中的 Python 数据科学虚拟环境

图片由来自 Pixabay 的 Reimund Bertrams 拍摄
在为 Python 数据科学项目创建虚拟环境中,我解释了如何安装 Pyenv 和 Virtualenv 来管理 mac OS Big Sur 上的 Python 版本和虚拟环境。
有了这个脚手架,下一步将是创建一个项目目录,激活一个新环境,并安装一些流行的数据科学包,如 Pandas 、 Matplotlib 、 Seaborn 和 Jupyter 。然后,我们将安装一个 kernelspec,这样这些库就可以在 Jupyter Notebook 中使用了。
I .使用 Pyenv 和 Virtualenv 创建并激活虚拟环境
首先,我们需要安装所需的 Python 版本。即使 Python 已经安装在您的计算机的多个位置,Pyenv 也需要您的项目将使用的版本的它自己的副本。除非您有理由使用旧版本,否则最新的稳定版本是一个很好的起点。
% pyenv install 3.9.1
将来,如果您想在另一个环境中使用 Python 3.9.1,就不需要重新安装了。您只需要安装一次 Python 的每个版本就可以使用它。
现在 Pyenv 已经有了您想要使用的 Python 版本的副本,您可以创建一个虚拟环境并将其分配给该版本。
% pyenv virtualenv 3.9.1 project_env
语法如下:
% pyenv virtualenv [python version] [environment name]
接下来,您的项目将需要一个目录。您可以通过输入以下内容来创建一个:
% mkdir project_dir
输入您的目录:
% cd project_dir
然后,将虚拟环境指定为该目录的本地环境。现在,只要您进入项目目录,环境就会打开:
% pyenv local project_env
如果您希望在其他地方激活该环境,可以在终端中输入该目录并使用:
% pyenv activate project_env
二。用 Pip 安装 Pandas,Jupyter,Matplotlib,Seaborn 等流行的数据科学包
下一个任务是将带有 Pip 的流行数据科学包安装到我们的虚拟环境中。这一步非常重要,因为只有安装到环境中的特定软件包版本才能在该环境中运行。每次创建新环境时,您都必须安装所需的所有软件包,即使它们已经安装到另一个环境中。
目前,我们正在安装:
- 熊猫——这样我们就可以操纵数据
- Jupyter 、笔记本和Ipykernel——这样我们就可以使用 Jupyter 笔记本来编写、执行和注释代码
- Matplotlib 和 Seaborn 用于数据可视化。
在您的项目目录中,您可以使用 Pip 开始安装:
% pip install pandas jupyter notebook ipykernal matplotlib seaborn
现在,您将能够在这个环境中使用这些包。
三。创建一个 kernelspec,开始在 Jupyter 笔记本上使用虚拟环境
Jupyter 笔记本是一个交互式环境,你可以在其中编写和执行 Python 代码,还可以添加 markdown 单元格来解释你的方法和代码。我们将使用 Ipykernel 将我们的虚拟环境链接到 Jupyter,这样我们就可以在笔记本中轻松使用该环境。
一个 kernelspec 是一个在~/Library/Jupyter/kernels目录下的 JSON 文件,当你安装 Jupyter 的时候就已经安装好了。在内核目录中有一个文件夹,用于您已经安装的每个虚拟环境。每个文件夹里面都有 kernel.json 。

在~/资源库/Jupyter /kernels 文件夹中
如果你打开它,它看起来像这样:

由 Ipykernel 创建的 Python 虚拟环境的 kernelspec JSON 文件
要为您的虚拟环境创建 kernelspec,请在项目文件夹中输入以下内容,并确保在执行此操作时环境已被激活:
% python -m ipykernel install --user --name myenv --display-name "Python (myenv)"
我们来分解一下语法:
- python: 表示该命令应该由 python 执行
- -m :表示将模块作为程序运行的选项
- ipykernel: 要运行的模块
- 安装:指示 ipykernel
- —用户:表示应该安装在当前用户的目录下
- —命名我的项目环境:指定“我的项目环境”作为 kernelspec 目录的名称
- —display-name“Python(myenv)”:指定将在 Jupyter 中显示的名称,以表示环境。
如果这个计划有效,终端应该显示如下内容:
Installed kernelspec my_project_env in /Users/myusername/Library/Jupyter/kernels/my_project_env
四世。推出 Jupyter 笔记本
安装您的 kernelspec 后,我们可以打开 Jupyter 笔记本并使用我们的新环境。
% jupyter notebook
这是一款 Jupyter 笔记本电脑。您的项目目录将显示在浏览器中。在右上角,您会看到一个下拉菜单,上面写着“新建”。单击按钮并选择下拉列表,查看安装了 kernelspec 的虚拟环境列表。单击新环境的显示名称,打开一个新笔记本。

Jupyter 笔记本目录
让我们测试一下笔记本电脑,并通过尝试将它们导入到我们的笔记本电脑来确保我们的初步软件包安装成功。
在第一个单元格中键入 import 语句,导入所选环境中可用的任何包,以便在笔记本中使用。
import pandas
如果笔记本没有输出错误信息,说明安装已经成功!现在你可以开始为你的项目编码了。如果你确实得到了一个错误信息,我建议仔细阅读本系列的第一篇和第二篇教程,以确保你没有错过任何一个步骤。
v .我们做了什么?
1.创建了一个新的虚拟环境,当我们用 Pyenv 和 Virtualenv 打开我们的项目目录时,它就会激活。
2。安装了流行的数据科学软件包 Pandas、Jupyter、Notebook、Ipykernel、Matplotlib 和 Seaborn。
3。为 Ipykernel 生成了一个 kernelspec,将我们的环境与笔记本电脑联系起来。
4。使用终端在浏览器中打开一个 Jupyter 笔记本目录。
5.创建了一个将使用我们新的虚拟环境的新笔记本。
6.学习了导入熊猫和检查安装的 import 语句。
👩🏻💻关于作者
你好。我是克里斯汀。拥有语言学学位并对自然语言处理感兴趣的数据科学家。
💡要更多地了解我的工作…
📅一天中的数据
📰christineegan42.medium.com/
📫如何联系我:
📧christineegan42@gmail.com
Jupyter 笔记本与 Dataiku DSS 在数据科学领域的对比
体验下一代企业人工智能——无需编码!

图片作者。在 Adobe Illustrator 中创建。
这篇文章可能会引起一些读者的兴趣:
- 数据科学家好奇数据库;
- 应用数据科学&机器学习的学生;
- 学 Python 的人。
Jupyter Notebooks 多年来一直是数据科学原型开发的事实工具,但是需要一定水平的 Python 编码和数据科学经验。
Dataiku 的数据科学工作室(DSS)平台为数据准备提供了简单易用的可视化方法以及一套 AutoML 功能。非编码人员可以导入和清理数据,训练 ML 模型并将其投入生产——所有这些都在 GUI 环境中完成,无需编写任何代码。
这可能是好的,也可能是坏的,但我会把它留到以后再说。
总体而言,像 Dataiku DSS 这样的平台已经在企业层面上极大地普及了数据分析和机器学习。这与微软 Windows 在多年的基于外壳的 MS-DOS 之后向大众开放个人计算没有什么不同。
Dataiku 现在是一家价值超过 10 亿美元的独角兽创业公司,由一个投资者集团支持,包括谷歌的风险投资部门 CapitalG。
我经常在个人和专业数据科学工作中使用 Jupyter,在一家大型金融服务公司的工作中使用 Dataiku。
为了保持这种品味测试比较的简洁和集中,我们将在数据科学工作流程中对一个分类问题进行一些标准步骤。
- 问题表述
- 导入数据
- 探索性数据分析(EDA)
- 数据准备
- 特色工程
- 造型
- 部署
我们将使用众所周知的泰坦尼克号数据集,它可以在 Kaggle 上找到。这里可以下载免费版的 Dataiku。Jupyter Labs &笔记本的最新版本是这里是。
加入 Medium 这里并获得无限制访问互联网上最好的数据科学文章。
1.阐明一个问题
您的数据科学分析应该由明确的目标或问题驱动。
在工业界,数据科学家的大部分时间都花在了澄清业务问题、获取正确的数据以及为建模做准备上。
这是一个与泰坦尼克号数据集相关的商业问题的例子:
"作为白星公司的公关主管,我需要不惜一切代价阻止死亡."
白星航运公司是泰坦尼克号的所有者。像这样的问题陈述意味着我们希望用目标变量乘客存活率训练一个高精度模型。
高精度模型将假阳性预测(1 型错误)降至最低,而高召回模型将假阴性(2 型错误)降至最低。
对于泰坦尼克号来说,预测一名乘客将会在中幸存而预测错误是不可接受的,无论是从伦理上还是从专业上来说都是如此——因此需要最大限度地提高精确度而不是回忆。
我在这里写了一篇关于流行的 ML 度量标准的文章。
这是另一个商业问题的例子:
"我想找出在泰坦尼克号上幸存的最重要的因素."
在这种情况下,我们对模型训练和验证后的特性重要性列表更感兴趣。
2.导入数据
Jupyter 笔记本
我们通常从导入一些标准的 Python 数据科学包开始。

然后,我们可以使用 pandas 导入. csv。

大台库决策支持系统
在 DSS 中,我首先创建一个空白的新项目。

然后,我可以从选项世界中导入数据。

选择上传文件后,我现在可以拖放文件,包括我的 titanic_dataset.csv。

3.探索性分析
Jupyter 笔记本
这是数据的样子。


我们有 12 种属性的 891 名乘客。

让我们检查一下数据类型,了解一下每一列的缺失值。

我们的目标变量是幸存的。这是我们的机器学习模型将预测的。
从分布来看,我们的数据集有点不平衡,只有 38%的乘客活着出来。

极度不平衡的数据集在卫生行业臭名昭著,相对于未受感染的人,受感染的人通常很少。这需要小心使用抽样和仔细选择性能指标。
总之,回到泰坦尼克号。
让我们来看看 7 个数字属性的分布和相关性。




让我们检查 5 个分类属性中每一个的类的数量。

舱和票的数据都是几百班的噪音,很多都是少排的稀缺。
同时,着手和性各只有几个班。



似乎大多数乘客是从南安普顿登机的。
此外,泰坦尼克号的大多数乘客是男性。
那很有趣。那些了解泰坦尼克号命运之旅领域知识的人可能还记得大多数幸存者是女性。

这大概是因为我们知道,在争夺有限的救生艇数量时,妇女和儿童得到了优先考虑。
所有这些都意味着我们应该小心。人们可以通过预测所有女性生存而男性死亡来训练一个高精度的模型!
大台库决策支持系统
将 csv 拖放到 Dataiku 后,我可以立即在 GUI 环境中研究数据集。

自动标记为红色的位告诉我可能存在数据完整性问题。我还可以很容易地看到哪些行缺少数据。
点击右上角附近的列视图按钮,我可以看到我的属性、它们的数据类型以及哪里缺少行。

我可以转到图表和统计数据选项卡,对我的数据集进行广泛的描述性和可视化分析。

我们可以创建一个单变量分析“卡片”,它将显示类似于。hist()和。描述()。

看起来很棒,不是吗!

让我们也创建一个关联矩阵卡,在我们的 Jupyter 笔记本中复制 seaborn 关联热图。

你可以在 Dataiku 的 GUI 界面上非常快速地做很多 EDA,这些都不需要编码。
如果你碰巧喜欢编码,Dataiku 提供完整的 Jupyter 笔记本支持。


4.数据准备
Jupyter 笔记本
回想一下年龄、舱室和上船属性有缺失数据。

我们来清理一下。我们将用“失踪”替换分类属性船舱和上船中的“南”。我们将创建一个指示变量来跟踪哪些乘客的年龄丢失,同时为算法将这些 NaN 替换为 0。

我们需要为分类变量创建虚拟变量。我还将从我们的特性集中删除姓名列,因为所有乘客的姓名都是唯一的。

请注意,由于 Cabin 和 Ticket 之间有数百个类,我们的一次热编码使我们的数据集膨胀到超过 800 列。

一般来说,我们应该合并稀疏类,并在每个类中有很多行的分类特性,但是这里我们保持简单。
大台库决策支持系统
在 Jupyter 中,我的工作流表现为一个笔记本中的一组单元格。在 DSS 中,我正在一个流上构建一系列配方,这是我的逻辑和管道的可视化地图。配方可以是视觉配方或代码配方。
让我们从一个叫做准备的可视化食谱开始。可视化食谱易于使用,不需要编码。它们非常适合非程序员或希望快速原型化想法而无需花费数小时编码的用户。

在我最初的准备食谱中,我将清理我的分类属性船舱和上船中缺失的行。请注意,我采取的行动会立即反映在数据集中。太好了!

接下来我会做一个代码配方来清理年龄下缺失的行。这正是朱庇特笔记本!

回想一下,最后两个步骤是从数据集中删除名称,并为剩余的 4 个分类特征创建虚拟变量。
事实证明,我不必在 Dataiku 内部这样做。
这是因为 Dataiku 自动对 ML 算法的分类特征进行一键编码,我可以在稍后的建模步骤中轻松地打开和关闭这些特征。酷!
好了,到目前为止,我的流程有两个配方:一个可视化准备配方清理了我的分类特征,一个代码 Python 配方清理了我的数字特征。

5.特征工程
Jupyter 笔记本
更好的数据几乎总是胜过更复杂的算法。从数据中获取更多信息的一种方法是设计新功能。在这里你可以尽情发挥,尤其是如果你有领域专长的话。
在这里,我将设计一个额外的特性 Total_fam ,它是给定乘客的亲属总数。这里的假设是,也许一个人带来的家庭规模对他们的生存有影响?

我们现在已经有了一个可以建模的数据集。这被称为分析基础表(ABT) 。
大台库决策支持系统
在 Dataiku 中,我可以用一个可视化的准备食谱来做到这一点。同样,很高兴我可以看到我的新特征立即反映在数据集中!

附加了最新的转换后,我的流现在看起来像这样。

6.系统模型化
Jupyter 笔记本
让我们在泰坦尼克号 ABT 上训练一些常见的分类算法。首先,我们将数据集分成训练集和测试集。

然后,我们将设置一些管道对象来同时调整和训练一组模型:正则化逻辑回归、随机森林和梯度增强树。

培训之后是模型评估。
以下代码输出每个优化算法的各种分类指标的分数。
我在这里写了一个关于流行的 ML 指标的可视化指南。

例如,下面是优化的随机森林的输出。

正如文章开头所提到的,预测一名乘客会活下来,如果预测错了,那将是一场灾难。因此,我们希望最小化误报,这相当于最大化精度。
我们的随机森林给出了 80%的精确度。具体来说,看看上面的困惑矩阵——在我们的测试集中,我们预测的 13 + 52 = 65 人中有 52 人真的活了下来。
这还不错,但还不够好。如果白星航空公司使用这种模式,他们会导致 20%的乘客死亡!
继续前进。如果我们的首要任务是确定存活率的最高预测值,我们可能会编码出一个排列特征重要性的图。


正如我们之前推测的那样,乘客的性别是泰坦尼克号上幸存者的一个强有力的预测因素。请注意,我们的工程特征 Total_fam 是一个合理的预测器。
正如所料,我们通过对我们的分类变量进行一次性编码获得的数百个稀疏的类特征(对于小屋和车票)最终只是噪声。
大台库决策支持系统
ML 是 DSS 真正闪光的地方。我刚才做的一切都可以通过点击按钮来完成。

抓住我的 ABT——在这里我称它为 df _ feat _ engineer——我将点击右边的实验室按钮。现在让我们在幸存的目标上创建一些‘快速原型’。

Dataiku 马上为你选择一些算法和特性。您可以点击列车立即出发。

深入研究设计,我们可以看到 Dataiku 代表您所做的决定。
它关闭了 PassengerId 和 Name ,因为这些数据并没有真正给表格带来任何预测能力,只有噪音。

算法方面,大台库选择了逻辑回归和随机森林。

你知道吗,我还会点击渐变提升树和 XGBoost!为什么不呢?
训练完成后,我得到了我的调优模型在各种指标下的表现摘要。例如,GBT 在中华民国得分之下的地区中独占鳌头。

类似于 Jupyter,我可以挖掘找到更多的信息,比如我的混淆矩阵统计和特性重要性。


7.部署
Jupyter 笔记本
sklearn 上训练好的模型可以保存为. pkl。

个人可以利用这一点在批量运行的基础上对新数据进行评分,或者机器学习工程师可以将其插入更大组织的自动化生产流水线。
大台库决策支持系统
在 Dataiku 中,我可以通过点击右上角的 Deploy 将任何训练好的模型部署到我的流中。

然后,我可以使用该模型对导入到项目的任何新数据集进行评分。
该项目本身可以作为 Dataiku 捆绑包导出,并由机器学习工程师投入生产环境。
目前,我们的团队正在设计一个 Dataiku 生产路径,该路径将允许整个组织的用户在 Dataiku 中构建原型,然后通过点击按钮将其模型部署到我们的 Hadoop 大数据集群中。
令人兴奋的东西!
在 YouTube 和 Twitter 上关注我。
无限制媒体访问
提升你的知识和技能到一个新的水平。
加入 Medium 享受无限制访问互联网上的最佳分析&数据科学文章。你可以在这里加入支持我和其他顶级作家。
我的数据科学文章
- 微分方程与机器学习——此处为
- 新冠肺炎的数学建模与机器学习— 此处
- 回归预测房价— 此处
- 分类预测员工流失— 此处
- 流行的机器学习性能指标— 此处
- Jupyter 笔记本与 Dataiku DSS — 此处
- Power BI —从数据建模到令人惊叹的报告— 此处
Jupyter 可视化调试器正在成为主流
也许 JupyterLab 最受欢迎的特性现在已经在ipykernel发布了

大约一年前,JupyterLab 的可视化调试器发布了。这是使 JuypterLab 成为一个成熟的 IDE 的一步,因为它提供了你所期望的 IDE 调试器的大部分功能。
然而,这个特性是建立在 xeus-python 内核之上的,这是 python 编程语言 Jupyter 内核的一个轻量级实现。当时,xeus-python内核并没有提供与ipykernel完全对等的特性。最值得注意的是,它缺少对matplotlib和 Jupyter magic 命令的支持。
但是在这个领域,现状每天都在变化,新的特性以前所未有的速度实现。因此,上个月xeus-python宣布支持matplotlib和 Jupyter 魔法指令。
今天,对ipykernel的合并 pull 请求将可视调试器带到 Python 编程语言的主 Jupyter 内核,并再次改变状态!
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
ipykernel上的 Jupyter 调试器
笔记本一直是软件思想增量开发的工具。尽管 JupyterLab 将项目推向提供类似 IDE 的开发体验,但仍有一些缺失。
解决这些问题产生了新的问题;最受欢迎的功能,可视化调试器,直到现在还依赖于xeus-python,而xeus-python并没有提供与ipykernel完全对等的功能。

Jupyter 可视化调试器—作者图片
然而,上个月,xeus-python背后的团队宣布支持matplotlib和 Jupyter magics,使xeus-python离ipykernel更近了一步。
但是,仍然缺少一些东西。这一次,最讨厌的事实是xeus-python并没有真正支持一个pip安装程序。我们可以一直跑:
pip install xeus-python notebook
然而,上传到 PyPI 上的轮子是实验性的。因此,我们被conda安装程序卡住了,由于许可问题,许多公司不想要或可以使用它。
今天,我很高兴地宣布一个对ipykernel的 PR 被合并,这为 Python 编程语言的主 Jupyter 内核带来了可视化调试器的实现。尽管实现还不完整,但它已经具备了您入门所需的一切:
- 变量资源管理器、断点列表和源代码预览
- 导航调用堆栈的可能性(下一行、进入、退出等)。)
- 直观地在感兴趣的行旁边设置断点的能力
- 指示当前执行停止位置的标志
让我们希望这项工作将很快结束,我们将能够在日常编程活动中使用这样一个重要而强大的工具。
结论
可视化调试器很可能是 JupyterLab 最需要的特性。一年前,这个在xeus-python上的实现解决了部分问题。
现在一个新的 PR 试图把它带到ipykernel,Python 编程语言的主要 Jupyter 内核。尽管实现还不完整,但它已经具备了您开始工作所需的一切。
看看我的其他笔记本故事,用这个优秀的工具提升你的游戏:
- Jupyter 已做好生产准备;原样
- 期待已久的 JupyterLab 3.0 终于来了
- Jupyter 在 VS 代码:利弊
- Jupyter 有一个完美的代码编辑器
- 小配件的新时代
关于作者
我叫 Dimitris Poulopoulos ,我是一名为 Arrikto 工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据操作的帖子,请关注我的 Medium 、 LinkedIn 或 Twitter 上的 @james2pl 。此外,请访问我的网站上的资源页面,这里有很多好书和顶级课程,开始构建您自己的数据科学课程吧!
JupyterLab 桌面应用——笔记本使用的游戏改变者?可能不会
意见
让我们试一试

多梅尼科·洛亚在 Unsplash 上拍摄的照片
尽管主要的 python IDEs(例如, Visual Studio Code 、PyCharm 以及最近的 DataSpell )都支持编辑 Jupyter 笔记本,但当我在数据科学项目中使用笔记本时,JupyterLab 仍然是我的首选 IDE。作为一个交互式 IDE,JupyterLab 允许我们在基于单元的组织中一步一步地可视化数据(例如,表格数据、图像)。
当我们使用 JupyterLab 时,有几种方法可以启动它——使用终端或者使用 Anaconda Navigator 应用程序。无论哪种情况,你都必须启动另一个应用程序才能运行 JupyterLab。虽然没什么大不了的,但是多出来的一步在某种程度上代表了不便。为了解决这个问题,JupyterLab 团队一直在努力让它变得更好。
大约不到一周前,在 Jupyter 的博客中,他们宣布了 JupyterLab 桌面应用的发布。下面为感兴趣的用户提供了博客文章的链接。
https://blog.jupyter.org/jupyterlab-desktop-app-now-available-b8b661b17e9a
这个库很快变得流行起来,在 GitHub上已经获得了 900 多颗星。

需要注意的是,Jupyter 的网页上没有下载链接。相反,它可以在 GitHub 页面上找到。JupyterLab 开发团队做出了明智的选择,使用 electron 构建桌面应用程序,因为 electron 允许程序员使用 web 开发语言开发跨平台的桌面应用程序,包括 JavaScript、HTML 和 CSS。

使用电子作为构建前端的工具,因此 JupyterLab 桌面应用程序是一个跨平台的独立 IDE。主要操作系统的安装程序都可以在 GitHub 页面上找到。
- Windows:Windows Installer
- Mac : macOS 安装程序
- Linux : Debian,Ubuntu Linux 安装程序 & 红帽,Fedora,SUSE Linux 安装程序
为了尝试一下,我在我的 MacBook 笔记本电脑上下载了 macOS 安装程序。安装是没有痛苦的,你只需要按照提示,将应用程序安装在所需的目的地。

需要注意的是,你需要在电脑上安装 conda,因为 JupyterLab 桌面 App 需要 conda 环境作为其服务器相关管理。因为我的电脑作为我的数据科学工作站已经有一段时间了,它已经完成了 conda 相关的设置。因此,我启动了桌面应用程序,它运行得非常流畅。

JupyterLab 桌面应用程序
如你所见,它的用户界面和你在网络浏览器上看到的一样。因此,如果您熟悉 JupyterLab web 界面,您很快就可以开始使用相同级别的用户体验编辑笔记本。
就应用程序的菜单而言,它只提供了任何 Mac 应用程序都必须提供的最少命令,因此,开发团队有很大的空间为应用程序添加功能。当然,这也需要他们做额外的工作来完成,因为 JupyterLab 桌面应用程序就像一个 UI 包装器,充当 JupyterLab 的容器。因此,我敢打赌,他们仍将专注于核心的 JupyterLab 开发,我怀疑他们会在桌面应用程序提供的基础上做更多的改进。
最后的想法
无论如何,对于有经验的 JupyterLab 用户来说,这不会是一个太大的游戏改变者。它所能做的可能是通过允许你直接启动 JupyterLab 来为你节省一个步骤。
然而,对于 JupyterLab 初学者或数据科学初学者来说,我怀疑它是否会非常有吸引力,因为他们必须分别安装桌面应用程序和 conda 才能使其工作。他们为什么不干脆去安装 Anaconda?它将负责 conda 环境,Anaconda Navigator 为您提供了非常方便地安装和运行 JupyterLab 的快捷方式。
感谢阅读这篇文章。通过注册我的简讯保持联系。还不是中等会员?使用我的会员链接,通过支持我的写作。
JupyterLab 现在是一个桌面应用程序。你应该关心吗?
它比浏览器版本有优势吗?实践安装指南和审查。

最受欢迎的数据科学 IDE 刚刚变得更好。谢天谢地,通过终端启动 JupyterLab 的日子已经过去了,因为桌面版已经在几周前发布了。是的,你没看错——你现在可以在任何操作系统上安装 JupyterLab 作为桌面应用程序。本文将向您展示如何做到这一点。
不想看书?请观看六分钟的视频:
如何安装 JupyterLab 桌面?
不,您不需要下载源代码并构建它——但是如果您愿意,您可以这样做。作者在他们的 GitHub 页面上放置了安装程序的链接,所以下载与您的操作系统匹配的文件:

图 1 —下载 JupyterLab 应用程序(图片由作者提供)
例如,点击 macOS 安装程序会下载一个。pkg 文件, Windows Installer 会下载。exe 等等。
安装非常简单。在 Mac 上,你必须点击几次继续。我想这个过程在 Windows 上是一样的,Linux 版本可以通过终端安装。
一旦安装,你会发现 JupyterLab 列在您的应用程序。一旦打开,就会弹出一个熟悉的界面:

图 2 — JupyterLab 桌面界面(图片由作者提供)
这就是你所要做的——JupyterLab 应用程序现已安装。
JupyterLab 桌面—您能做什么?
桌面应用程序的界面与浏览器完全相同。创建笔记本后,您可以使用 Markdown 功能——选择一个单元格,然后依次按 ESC、M 和 Enter 键:
# Heading 1
- List item 1
- List item 2
**This is bolded**.
$$ \Large c = \sqrt{a^2 + b^2} $$

图 3 — JupyterLab 桌面(1)(图片由作者提供)
您可以运行 Python 代码并使用任何已安装的库。例如,下面是如何创建一个 Numpy 数组:

图片 4 — JupyterLab 桌面(2)(图片由作者提供)
你也可以改变内核。假设您有一个用于特定项目的专用虚拟环境,您可以通过单击屏幕底部的内核选项来访问它:

图片 5 — JupyterLab 桌面(3)(图片由作者提供)
从那里,只需选择您想要的环境。我的一个叫env_tensorflow,我就选中它,尝试导入 TensorFlow:

图片 6 — JupyterLab 桌面(4)(图片由作者提供)
如您所见,更改环境会重启运行时。首先选择正确的环境,然后运行代码总是一个好主意。这将为您节省大量时间,尤其是在处理大型数据集时。
简而言之,这就是 JupyterLab 桌面。问题是,你应该使用它吗?毕竟和基于浏览器的版本一模一样。
判决
我认为你可能会选择桌面版的两个原因是:
- 一般来说,你更喜欢专用的桌面应用——浏览浏览器标签很快就会变得一团糟。没有人需要在你需要的时候找不到的标签。
- 你经常不小心关闭浏览器——这正是我的遭遇。在 Mac 上,你可以通过按 CMD+C 来关闭任何选定的应用程序。通常,我会在屏幕的左侧显示在 Safari 中运行的 JupyterLab,而在右侧显示类似 Stack Overflow 的内容。按下 CMD+C 将关闭这两个,即使你只选择了正确的一个。它超级烦人,发生的次数比我想承认的还要多。
除此之外,桌面版与基于浏览器的版本相比没有优势。
你们觉得怎么样?您会安装 JupyterLab 桌面应用程序还是对 web 实例感到满意?请在下面的评论区告诉我。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
https://medium.com/@radecicdario/membership
保持联系
我们如何绘制多项式特征?
是的,您可以绘制多项式特征。如果您的数据集有 3 个以上的独立要素,那么使用主成分分析(PCA)是一个赢家。让我们看看如何在 Matlab 中做到这一点。

伯格和布什 2017
我们的数据集
使用 PCA,我们可以将我们的特征从(n)降低到 2 或 3 维,然后可以绘制这些特征。我们将从查看从 kaggle 下载的数据集开始。
我们可以看到 4 个属性,这对于预测来说是超级的,但是不允许我们绘制可视化图。

图 Kaggle 的屏幕截图
谅解
当我们使用 PCA 时,我们的主要目标是将我们的多项式特征(x1,x2,x3,…xn)带到二维(z1,z2)。下面的图 1 是将 am2 维(x1,x2)向下转换为一维(Z)的简化示例。
注意(类似于梯度下降)我们如何在将 x1 & x2 投影到 z 上时计算投影误差

图 2:在 Desmos 中绘制
PCA 的目标是找到数据投影的方向(向量),以便最小化投影误差。
现在我们有了一个基本的理解,让我们开始编码…
加载我们的数据集
让我们加载数据,并确保正常化。一般来说,我们归一化是为了更好的 ML 性能。让我们也使用 grp2idx 将 Y 标签转换成数字。
%% Load our data
clear;
tbl = readtable(‘IRIS.csv’);
[m,n] = size(tbl);
X = tbl{:,1:n-1};
[y,labels] = grp2idx(tbl{:,n});[X_norm, mu, sigma] = featureNormalize(X);
运行 PCA
PCA 函数为 m 乘 n 数据矩阵X返回主成分系数,也称为负载。有了这个系数,我们现在可以投影“Z”了。
%% use pca to reduce to 2 dimensions
K = 2;
[coef, S] = pca(X_norm);
如图 3 所示,我们的系数将是一个 4x4 矩阵,因为我们有 4 个特征。

图 Matlab 中 pca 的 coef 结果截图
现在让我们创建一个 coef_reduce,只包含我们喜欢的列数(K)。使用简单矩阵乘法将我们的特征从 4 减少到 2。
% calculate Z with 2 features
coef_reduce = coef(:, 1:K);
Z = X_norm * coef_reduce;
就这样,我们有一个包含 4 个特征的 X_norm 矩阵,但现在已经减少到 2 个特征,存储在 Z 矩阵中。

图 4:Z 在 Matlab 中的结果截图
绘制结果
在 Matlab 中,绘图现在成为一个相当标准的过程。因为我们有一个多元数据集,所以让我们创建一个托盘,用不同的颜色给每个类别着色。
%% Create colors pallette
figure;
palette = hsv(K + 1);
colors = palette(y, :);% Plot the data, with different Y labels being different colors
scatter(Z(:,1), Z(:,2), 30, colors);
title(‘Pixel dataset plotted in 2D, using PCA for dimensionality reduction’);
然后咔嘣 …我们绘制了数据集。

图 5:在 Matlab 中绘制 Z 的结果截图
结论
因此,正如我们所见,绘制多项式数据集并不太难。自然,您不能像在绘制 2 个要素时那样理解单个要素,但我们可以了解数据集标注是否有意义。这在逻辑回归或 K 均值等分类算法中非常有用。
ps。下面是 featureNormalize 函数
function [X_norm, mu, sigma] = featureNormalize(X)
mu = mean(X);
X_norm = bsxfun(@minus, X, mu);
sigma = std(X_norm);
X_norm = bsxfun(@rdivide, X_norm, sigma);
end
就从 Dask 本地集群开始吧
Dask 很棒,LocalCluster 是最简单的入门方式

克里斯汀·休姆在 Unsplash 上拍摄的照片
本文是关于实践中使用 Dask 的系列文章的第一篇。本系列的每一篇文章对初学者来说都足够简单,但是为实际工作提供了有用的提示。本系列的下一篇文章是关于循环的 并行化,以及其他使用 dask.delayed 的令人尴尬的并行操作。
在 Saturn Cloud,我们管理着一个数据科学平台,该平台提供 Jupyter 笔记本、Dask 集群以及部署模型、仪表盘和作业的方法。我们已经看到一些客户在完全不必要的情况下开始使用多节点集群。当您第一次使用 Dask 时,应该选择 LocalCluster。
有许多方法可以运行 Dask 集群。这篇文章敦促用户尽可能简单地开始,并通过简单的方法来做到这一点。
尽可能简单
我们托管和管理多节点 Dask 集群。这些集群甚至可以使用 GPU。有了 Saturn,用户只需点击几下鼠标,就可以访问包含数百个 GPU 的集群。
但是等等。
仅仅因为你有一辆法拉利,并不意味着你应该开着它去杂货店。

越简单越好。

鲁道夫·马里在 Unsplash 拍摄的照片
您的缩放顺序应该是:
- 从熊猫开始。这通常就够了。
- 内存不足?用熊猫配更大的机器。 Saturn 现在拥有 4tb 内存的 Jupyter 实例
- 尝试 Dask 本地集群
- 尝试多节点(也可能是多 GPU) Dask 集群
一般来说,你的堆栈越简单,你花在修补上的时间就越少,而你花在生产上的时间就越多。我写这篇文章是因为我花了时间与那些在不需要时使用多节点集群的用户交谈。这是我们的错——我们让它们很容易旋转起来。
为什么是 LocalCluster?
你的电脑有多个内核(我的有 4 个)。如果您正在编写常规的 Python 代码,您可能只利用了其中的一个内核。您的一些代码(特别是调用 NumPy 的代码,例如矩阵乘法)正在利用多个内核,因为 NumPy 知道如何这样做。Python 不知道如何在多核上自动执行你写的代码。
使用 dask 集群(以及了解如何在 Dask 上并行化的库)允许您利用系统上的所有内核。Dask 附带了一些并行模块,比如dask.dataframe和dask.array。其他库,如 Xarray 和 dask-ml `也与 dask 集成。
Dask 可以帮助您通过多节点集群扩展到巨大的数据集。Dask 还可以通过 LocalCluster 帮助您利用计算机上的所有内核
LocalCluster 比多节点 Dask 集群更容易
用一台机器工作更容易。在单台机器上, htop 可以帮助您了解您的系统运行情况。在单台机器上,您不必担心将代码或数据文件复制到您的计算机集群中。在一台机器上,您可以在终端中看到整个 Dask 集群的所有日志。
多重处理呢?
多重处理非常适合令人尴尬的并行问题。对于非尴尬的并行问题,您将需要一个像 Dask 这样的工具,它知道如何在多个内核上并行化复杂的操作。由于 Dask 可以处理这两种类型的并行问题,所以您只需学习一种语法。此外,您还可以使用 Dask 仪表盘来监控您的工作。

Hugo Shi 截图
对于非令人尴尬的并行问题,您将需要一个像 Dask 这样的工具,它知道如何在多个内核上并行化复杂的操作。
如何使用 LocalCluster
有许多方法可以使用 LocalCluster。我会给你看最好的。
不要做什么
Dask 让入门变得非常非常容易。创建一个 Dask 客户端,你就自动得到了一个LocalCluster
>>> from dask.distributed import Client >>> c = Client() >>> c.cluster LocalCluster(16ff34f9, 'tcp://127.0.0.1:35257', workers=4, threads=8, memory=41.92 GB) >>>
还可以在 Python 中显式使用 LocalCluster
>>> from dask.distributed import Client >>> from dask.distributed import LocalCluster >>> cluster = LocalCluster() >>> client = Client(cluster)
我在部署生产数据管道时使用这种方法,但是我不喜欢为了研究而这样做。如果您有多个 Python 会话或笔记本,这种方法很容易让您意外地在您的计算机上结束多个集群。这也使得查看日志和找到 Dask 仪表板的地址变得更加困难。
做什么
打开一个终端。
$ dask-scheduler
打开第二个终端。
$ dask-worker tcp://127.0.0.1:8786
在您的 Python 会话(可能是 Jupyter 笔记本)中,执行以下操作:
from dask.distributed import Client client = Client('tcp://127.0.0.1:8786')
给你。dask-scheduler的默认地址是tcp://127.0.0.1:8786,第二个命令足以设置连接到调度程序的 Dask workers。这种方法最好的一点是,您所有工作的所有日志都在第二个终端中。要关闭它,只需在两个终端点击ctrl-c。
进程和线程
Python 有个烦人的东西叫做全局解释器锁。你不需要了解太多,除了这意味着 Python 不能很好地利用多线程。这条规则的一般例外是主要进行 I/O(下载数据)的代码,或者主要利用 C++和其他非 python 库的代码(例如 NumPy)。
我们接触过的大多数用户最好使用线程上的进程(也可以混合使用)。我是这样在我的机器上做的。
- 我有 40 GB 的 RAM(谢谢 System76!!)
- 我有 4 个内核。所以我想要 4 个工人。
- 这意味着每个工人可以消耗 10 GB 的内存。
$ dask-worker tcp://127.0.0.1:8786 --nprocs 4 --memory-limit 10GB
结论
从简单开始,逐步扩大规模。在 Saturn,我们可以为您的所有本地集群需求提供 4tb 的实例。如果这还不够,您还可以在多节点(和多 GPU)集群上运行相同的代码,只需点击几下鼠标。祝你快乐!
声明:我是土星云的 CTO。我们让您的团队轻松连接云资源。想用 Jupyter 和 Dask?部署模型、仪表板或作业?在笔记本电脑或 4 TB Jupyter 实例上工作?完全透明地了解谁在使用哪些云资源?我们做所有这些,甚至更多。
最初发布于 2021 年 8 月 8 日https://Saturn cloud . io。
只是利用机器学习成为更好的学习者
如何充分利用我们的“第二大脑”

在之前的一个故事中,我写了成为更好的学习者的可能性,步入“元”方法,获得学习过程本身的意识,并像对待技能一样对待它,改进它。
新知识的获取和理解是这个过程中必不可少的一部分,在过去的几个月里,我研究了很多关于神经科学的知识,以便更好地理解我们的大脑是如何处理和存储信息的。
与此同时,当我开始以数字方式存储有用的概念时,我偶然发现了蒂亚戈·福特的“第二大脑”,这是一个个人知识管理系统,可以用来建立一个二级信息库,与我们主大脑的长期记忆配对,并在需要时使用。
为了更好地完成这一点,遵循第二大脑的纯粹精神,混合不同领域的知识,我决定为自己打造一个工具,融合编程、机器学习和神经科学知识,让我的第二大脑更加强大和模块化。
在这个故事中,我将不仅描述技术方面,而且描述主要特性背后的原因,因为我的主要目标是有一个工具来帮助我收集知识。
让我们从我们的(主要)大脑开始给出一些背景。
我们的大脑是如何工作的
我们的大脑是一个极其复杂和迷人的器官,基本上有两种不同的工具来处理信息:
- 工作记忆/短时记忆(STM):非常有限且易变,新信息首先从这里获得
- 长期记忆(LTM):实际上是无限的,我们所知道的一切都储存在这里

STM 和 LTM 是如何沟通的
这两个部分可以双向交换信息,从 STM 到 LTM 通过“巩固”和“再巩固”过程,从 LTM 到 STM 通过“重新激活”过程。
这些过程的核心是“组块”,一个已知和充分理解的信息的紧凑包,一个基本概念。
因此,在探讨一个新的主题时,我们可以构建组块,将一个更复杂的主题“分解”成更小的主题。
但是组块还有其他很酷的方面:
- 它们可以在工作记忆中进行组合和“压缩”,以提高效率
- 它们可以转移并应用到其他知识领域
- 它们极大地改善了存储器之间的信息共享。
让我举一个简单的例子:假设你必须记住这两个字母数字序列:
- 34ryf%s7wt
- 4x+5y^2=12
它们的长度是相同的,但我确信第二个序列更容易处理,因为关于“等式”、“加法”、“变量”、“幂”的组块的组成赋予了它“意义”,有助于在 STM 中处理它。
(数字)第二大脑
促使我重新审视我的方法的是意识到我的知识保持力很低。
在过去的几年里,我读了大量的非小说类书籍,总体来说,接触到了大量的信息,但这并不意味着在需要的时候可以得到。
不管你读了多少书或听了多少播客,如果知识不可操作,这只是一个虚荣的衡量标准。
因此,我开始总结并保存一个笔记,如果我遇到一个有趣的概念。
我目前正在使用 Google Keep,但是概念或黑曜石是很好的选择。

Google Keep-起点。笔记!
我使用标签构建了一个简单的 notes 分类法,引入了一些概念,如知识领域(物理学、生物学、领导力等等)、来源(来源名称,例如书名或播客名)、资源类型(书籍、播客、课程等等)和一个基本的工作流来保持一致性。
但是这还不够,尤其是考虑到可能有数千条注释的大型知识库(KB)。
我需要一些东西来以更“聪明”的方式处理这个知识库,使用组块作为构建模块,在概念之间形成新的联系——甚至来自不同的主题——并且通常在整合过程中更有效,从主要的生物 STM 传递到第二大脑本身的数字 LTM。
所以我来介绍一下第二个大脑接口!
技术概述
第二大脑接口(SBI 从现在开始)是一个与不同的第三方服务集成的 Python 定制应用程序。
这是逻辑架构:

第二大脑接口——逻辑架构
Google Keep 是数据的入口点,SBI 可以通过它的 API 读写数据。
主要的块元数据(标题、文本、标签、各种时间戳)都是从那里获取的,但是我还添加了一个审查日期(稍后会详细介绍),为了持久化它,我使用 Firestore 作为持久层,这样 SBI 就可以使用适配器执行 CRUD 操作。
但是让我们更详细地看看主要特性。
功能 1 —语音界面
我只是无法抗拒拥有一个声音界面的诱惑,以类似于 Alexa 或 Google Home 的方式与我的第二大脑交谈,并听取一些回复。
此外,加上一些限制(唤醒词,离线工作),我有机会做一些非常有趣的事情。
事实上,经过一些搜索,我发现了一个非常有趣的平台,名为 Picovoice,并围绕它建立了意图管理器,具有唤醒词激活和与意图一起工作的可能性,将特定的动作映射到特定的语音输入。
让我们看看它的实际效果
第二大脑接口——基本命令
我可以直接使用 Picovoice 控制台来映射特定的意图和参数,这是一个用于训练和下载模型以在本地使用的 web 应用程序。

微微语音控制台
一旦理解了意图,就可以在一些特定的业务逻辑中使用它的有效负载,例如查询 Google Keep。
要了解更多关于 Picovoice 的信息,你可以阅读这个故事,在这个故事中,我详细描述了它的功能和可用的工具。
我还为一些语音命令的“在线模式”添加了谷歌语音技术,因为 Picovoice intent engine 的缺点是你必须提前训练模型才能捕捉特定的短语,对于一些功能来说,这是不可行的。
功能 2 —关于知识库的统计信息
我认为对知识库如何发展及其组成有一些了解是很重要的,所以基本上我对它做了一些“EDA”(探索性数据分析)。
除了口头询问一些信息,我还构建了一个 web 仪表板来添加一个可视化界面,使用 Dash 框架来显示图表。
我不是前端开发人员——看到截图就很清楚了:)—但是,使用 Dash,我能够构建一个用 Python 代码包装的 React 应用程序。
感谢 Keep integration,将所有数据放入 Pandas DataFrame 并开始挖掘,使用 Plotly 库非常简单。
除了一些基本信息,我还构建了:
- Wordcloud,使用一个特定的库,查看所有可用的块。NLTK 词条解释器的使用有助于单词的规范化,因为根据定义,语言学中的词条解释是将单词的屈折形式组合在一起的过程,因此它们可以作为单个项目进行分析,通过单词的词条进行识别。

第二大脑界面——仪表板
- 直方图查看不同的块标签类型(知识领域、来源、资源类型)

第二大脑界面——每个知识领域的组块数量
- 时间序列,以查看各个方面(块创建、编辑等)随时间的演变

第二大脑界面——随时间的组块创造
我想我会添加一些更酷的报告,如动画信息图,以便更好地掌握知识库随时间的变化,了解新领域是如何添加的或现有领域的演变。
特征 3 —新知识获取和自动总结
这是 ML——更准确地说是 NLP 发挥作用的另一个特性
让我们看看它的实际效果
第二大脑界面——总结功能正在发挥作用
自动总结一些文本的可能性非常有趣,尤其是如果与维基百科配对的话。
当然,这个过程不应该完全委托给 ML,因为这是一个非常重要的行动,用我们的大脑来加强理解和知识提取,但可以作为一个更计算机辅助的工作流程的初步步骤。
从技术上来说,我使用的是在拥抱脸上提供的摘要服务,可以从几个模型中挑选一个用于特定任务的训练模型(在这种情况下是文本摘要),并向其发送有效载荷进行处理。

拥抱脸界面
下面是简单的代码,基本上是一个 POST 请求,在有效负载中包含摘要文本。
为了让它工作,你需要一个拥抱脸的帐户(以获得 API 令牌)并安装他们的库。
class Summarizer:def __init__(self):
model_name = sb_properties.SUMMARIZER_MODEL
api_token = sb_helper.get_hf_api()
logger.debug("Using {} as summarization model".format(model_name))
self.api_url = "[https://api-inference.huggingface.co/models/](https://api-inference.huggingface.co/models/)" + model_name
self.model_id = model_name
self.headers = {"Authorization": "Bearer {}".format(api_token)} def summarize_text(self, text_to_summarize):
payload = {"inputs" : text_to_summarize}
response = requests.post(self.api_url, headers=self.headers, json=payload)
return response.json()
该文本摘自维基百科页面的摘要部分(如果有的话)
import wikipediadef retrieve_summary(self,topic):
try:
page = wikipedia.page(topic)
logger.debug("Found page with title {}".format(page.title))
logger.debug("Found page with url {}".format(page.url))
return page.summary
except wikipedia.exceptions.PageError:
logger.error("Page about topic {} not found ".format(topic))
except wikipedia.exceptions.DisambiguationError:
logger.error("Disambiguation error for topic {} ".format(topic))
except Exception as e:
logger.error("Error %s", e)
让我们看看示例中总结的文本之间的区别…
The Alcubierre drive, Alcubierre warp drive, or Alcubierre metric (referring to metric tensor) is a speculative warp drive idea based on a solution of Einstein's field equations in general relativity as proposed by theoretical physicist Miguel Alcubierre during his PhD study at the University of Wales, Cardiff, by which a spacecraft could achieve apparent faster-than-light travel if a configurable energy-density field lower than that of vacuum (that is, negative mass) could be created.Rather than exceeding the speed of light within a local reference frame, a spacecraft would traverse distances by contracting space in front of it and expanding space behind it, resulting in effective faster-than-light travel.
原文摘自维基百科
The Alcubierre drive, Alcubierre warp drive, or Alcubierre metric (referring to metric tensor) is a speculative warp drive idea based on a solution of Einstein's field equations in general relativity as proposed by theoretical physicist Miguel Alcubierre during his PhD study at the University of Wales, Cardiff, by which a spacecraft could achieve apparent faster-than-light travel if a configurable energy-density field lower than that of vacuum (that is, negative mass) could be created.[1][2]Rather than exceeding the speed of light within a local reference frame, a spacecraft would traverse distances by contracting space in front of it and expanding space behind it, resulting in effective faster-than-light travel. Objects cannot accelerate to the speed of light within normal spacetime; instead, the Alcubierre drive shifts space around an object so that the object would arrive at its destination more quickly than light would in normal space without breaking any physical laws.[3]Although the metric proposed by Alcubierre is consistent with the Einstein field equations, construction of such a drive is not necessarily possible. The proposed mechanism of the Alcubierre drive implies a negative energy density and therefore requires exotic matter or manipulation of dark energy.[4] If exotic matter with the correct properties cannot exist, then the drive cannot be constructed. At the close of his original article,[5] however, Alcubierre argued (following an argument developed by physicists analyzing traversable wormholes[6][7]) that the Casimir vacuum between parallel plates could fulfill the negative-energy requirement for the Alcubierre drive.Another possible issue is that, although the Alcubierre metric is consistent with Einstein's equations, general relativity does not incorporate quantum mechanics. Some physicists have presented arguments to suggest that a theory of quantum gravity (which would incorporate both theories) would eliminate those solutions in general relativity that allow for backwards time travel (see the chronology protection conjecture) and thus make the Alcubierre drive invalid.
结果还不错,即使仍然太复杂而不能被认为是一个单一的块,并且关于 Alcubierre 驱动器可行性的省略部分非常有趣。
实际上,我使用的是“google/pegasus-large”模型,但是同时使用不同的模型并挑选出最佳摘要也不错。
功能 4 —检查块
当我在很久以后介绍组块概念时,仍然有许多笔记,尤其是旧的笔记,不能被认为是组块(意思是清晰、紧凑并且有特定的主要概念)。
此外,不总是很容易总结一些东西,所以一个一致的“内务”活动是必要的,以保持组块的质量。
但没关系,这是学习过程本身的一部分,以改善已知的东西,“重构”或扩展。
没有直接的可能性来定义一个笔记什么时候也是一个组块,所以我只是使用词条的数量来检查是否在一个确定的阈值内(实际上是 40 个词条)。否则,有可能需要重写和/或拆分便笺。

第二大脑界面——要检查的块
不是一个完美的方法,但我们仍然有我们的主要大脑来决定该做什么:)
功能 5 —检查组块和自动问题生成
拥有数百个可用的数据块并展望未来数千个数据块,重要的是要有一个审查机制,定期评估和改进这些数据块,因为拥有第二个大脑意味着可操作的知识。
因此,为了跟踪一个程序块何时被审查,我添加了审查日期。当块被创建时,它等于它的创建日期,但是随着时间的推移,在某个时间窗口中具有审查日期的所有块被发现为“需要审查”。
想法是再次阅读并至少承认它们的存在,模仿主要的大脑激活过程(从 LTM 到 STM)。

第二大脑界面——要复习的组块
但是,有没有一种方法来促进这一审查过程呢?
如果在复习过程中,我不只是阅读课文,而是回答一些与课文相关的问题,那该多好?
NLP 可以再次提供帮助,使用一个名为 Questgen AI 的包。
在幕后,它使用一种相对较新的方法来处理 NLP 模型,称为 T5(文本到文本转换转换器),其中输入和输出都是文本,允许转换,在这种情况下,从语句中获取问题。

第二大脑界面——组块的问题生成
在上面的例子中,第一个问题是完美的,第二个就不那么完美了,可能需要以更接近模型训练数据的方式重写,但这是一个好的开始,并促使我以更好的方式编写一大块。
代码非常简单:
from Questgen import maindef generate_questions(self, question_context):
payload = {
"input_text": question_context
}
output = main.QGen().predict_shortq(payload)
if output:
logger.debug(output)
return output['questions']
else:
return None
功能 6 —搜索和知识“导航”
这是最有趣的功能,因为我试图建立一个 KB 的视觉表示,以获得新的见解,并发现组块之间意想不到的关系,模拟我们的大脑在不同和更广泛的区域连接以创建新知识时如何以扩散模式工作。
这是一个搜索功能,连接所有包含输入文本的块
第二大脑界面——在知识库中搜索
但是还有更多!
我使用了一个相似性函数来查找与低于某个阈值的所选块“相似”的块(更高的值意味着更相似)
第二大脑界面——浏览知识库
因此,只需浏览节点并更改阈值,就有可能通过相似性获得某种意外收获,并以不同的方式探索知识库。
从技术上讲,这可以通过计算向量的余弦相似度矩阵来实现,该矩阵是通过在一些清理之后对组块文本进行矢量化而获得的。
import string
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from nltk.corpus import stopwords
import pandas as pdimport re
from nltk.corpus import wordnet
import nltk
from nltk.stem import WordNetLemmatizerdef clean_string(text):
text = ''.join([word for word in text if word not in string.punctuation])
text = text.lower()
text = re.sub(r'[^\x00-\x7F]+', ' ', text)
text = re.sub(r'\s{2,}', ' ', text)
text = ' '.join([word for word in text.split() if word not in stop_words])
text = ' '.join([lemmatizer.lemmatize(w) for w in nltk.word_tokenize(text)])
return textdef compute_chunks_similarity(self, column):
cleaned_strings = list(map(clean_string, self.model[column].values))
vectorizer = CountVectorizer().fit_transform(cleaned_strings)
vectors = vectorizer.toarray()return (cosine_similarity(vectors))
结论
我喜欢花时间设计和开发 SBI,因为我获得了对新主题的见解,练习了获得的技能,而且,总的来说,因为边做边学是很棒的。
此外,机器学习再次显示了它在非常具体的领域的效用,例如个人知识管理,正如我之前在健身中探索的。
我会继续增加功能和改进它们,把 SBI 当作我个人成长的助手。
接下来的两个主要问题是:
- 使用 LDA(潜在狄利克雷分配)来发现和显示知识库中隐藏的主题和连接,
- 有可能手动链接组块,以形成特定知识的集群。
但是,除了技术细节和工具,我的主要目标是展示如何系统和连贯地获取知识,因为好奇心和学习意愿当然是基础,但它们需要专注和一致。
所以,下次你在看书、看视频或听播客时,如果有什么有趣的事情发生,停下来做个笔记。
一开始会很奇怪,你会觉得慢了下来,但事实是,每一次,你都会对你拥有的最有价值的资产进行长期投资:你的知识。
高维数据聚类的 K-Means++算法

Arthur V. Ratz 的照片
利用 K-Means++算法进行优化的高维数据集聚类,使用最新的 Scikit-Learn 0.20、NumPy 3.20.x Matplotlib 3.4.1、结果可视化等在 Anaconda Python 3.8.x 中实现。
介绍
聚类是数据分析中的一个重要步骤,广泛用于分类、收集统计数据和获取特定知识领域的见解。在执行聚类时,它旨在将数据集划分成几个组(即簇),将最相似的数据分配给簇【1,4,6】。
数据聚类不仅仅基于一个,而是基于整个类别的无监督机器学习 (ML) 算法,当组的数量未知时,有效地用于不确定或模糊数据聚类。它通过将数据与最初预定义的类相关联,提供了对数据进行分类的能力。
然而,现有的大多数基于 Lloyd-Forgy 方法的算法,在对具有大量特征的数据集进行聚类时,具有巨大的平均复杂度。
在实验上,将𝙣=𝟏𝟎实体的三维𝙙=𝟑数据集划分成𝙠=𝟏𝟎簇以进行𝙞=𝟏𝟎迭代可以在超级多项式时间(NP-hard)内完成,这与𝞀=𝟏𝟎成比例。
为了提高 Lloyd-Forgy 的聚类性能,使用了各种算法级优化。虽然,它们中的许多还没有被很好地研究过,因此是不切实际的。原始 Lloyd-Forgy 的 K-Means 聚类至少有两种已知的优化,如模糊 C-Means 和 K-Means++算法,在【2,3,6】中讨论。
为了有效地提高 NP-hard 聚类过程的性能和收敛性,我们将引入 K-Means++算法,该算法最初由 David Arthur 和 Sergei Vasilevskii 于 2007 年提出,作为 Lloyd-Forgy 算法的初始化步骤【2,5】。
与其他类似的算法不同,K-Means++提供了聚类和质心就地计算的能力,确保聚类以减少的迭代次数执行,等于结果聚类的总数。
K-Means++算法的平均情况复杂度已经显著降低,非常接近最好情况的 Lloyd-Forgy 算法的复杂度。K-Means++大约是𝟓.与最初的 Lloyd-Forgy 算法相比,𝟒𝟗𝙭时间更快,同时用于高维数据集的聚类。
劳埃德-福吉的 K-均值聚类
Lloyd-Forgy 的 K-Means 是一种算法,它基于欧几里德 距离度量,将𝙣- 观测值的数据集𝑿划分为一组𝙠- 聚类的过程,其中每个观测值都是𝒅- 特征的多维向量。每个聚类是到质心之一的最小距离的一组观察值,被评估为聚类 [1,4,5,6] 内所有观察值的最近均值。
通常,数据聚类的整个过程可以描述为:

一个数据聚类的例子|图片作者
上图展示了将𝒏=𝟏𝟎观测的二维数据集聚类成𝙠=𝟑聚类的过程(从右开始)。
输入数据集𝑿的片段如下所示:
0: [ x = 0.543974 y = 0.842981 ]
1: [ x = 0.131690 y = 0.806490 ]
2: [ x = 0.339777 y = 0.380520 ]
3: [ x = 0.683979 y = 0.816659 ]
4: [ x = 0.236921 y = 0.184139 ]
5: [ x = 0.380008 y = 0.027292 ]
6: [ x = 0.933727 y = 0.694752 ]
7: [ x = 0.911393 y = 0.504823 ]
8: [ x = 0.076103 y = 0.714423 ]
9: [ x = 0.906728 y = 0.107928 ]
10: [ x = 0.087780 y = 0.256157 ] * * *
上面列出的每一个𝒏-observations,都是欧几里得空间ℝ ᵈ 中的向量𝒙。因为,𝑿是一个数据集,它的所有向量∀𝒙 ∈ 𝑿排列成一个形状协方差矩阵(𝒏 × 𝒅).
数据集𝑿的整个聚类分两步进行【1】:
- 计算一组群集𝙎,分配所有观察∀𝒙ₜ ∈ 𝑿,𝙩 =𝟏..𝒏到集群𝒔ᵣ ∈ 𝙎,𝒓=𝟭..具有最近质心𝒄ᵣ ∈ 𝑪的𝙠,其中来自每个观测𝒙ₜ的 distance|∀𝒙ₜ𝒄ᵣ|的平方最小。
- 更新质心𝒄ᵣ ∈ 𝑪,𝒓=𝟭..所有星团的𝙠作为观测值的质心,分配给每个星团𝒔ᵣ ∈ 𝙎.
继续执行步骤1–2,直到𝙠-clusters 𝒔 ∈ 𝙎最终计算完毕。
为了执行聚类,我们必须从数据集𝑿中选择𝙠-observations,作为质心𝑪的初始集合,计算来自𝙩=𝟏∀𝒙ₜ∈𝑿的每个观测值的平方距离..𝒏到所有质心∀𝒄ᵣ ∈ 𝑪,𝒓=𝟭..𝙠,将观测值∀𝒙ₜ映射到质心𝒄ᵣ,其中来自这些观测值∀𝒙ₜ的 distance|𝒙ₜ𝒄ᵣ|最小,并将它们分配到群集𝒔ᵣ ∈ 𝙎.
通常,我们在每次𝛃-th 迭代𝛃=𝟏时继续计算新的集群𝒔 ∈ 𝙎 ⁽ ᵝ ⁾ ..𝙞,重新评估质心并在来自先前(𝛃−𝟏)-th 迭代)的每个现有聚类内将观察结果划分成多个新的聚类,直到整个数据集最终被聚类【1,4,5,6】。
数学上,下面的过程可以表示为等式 (1.1) :

Lloyd-Forgy 基于距离的聚类过程|图片由作者提供
反过来,通过使用质心等式 (1.2) ,每个聚类的质心被更新为𝒓-th 聚类内所有𝒖ᵣ-observations 的最近平均值:

聚类的最近均值公式|作者图片
在每个聚类的质心∀𝒄ᵣ ∈ 𝑪没有改变∀𝙘ᵣ⁽ᵝ⁺⁾=∀𝙘ᵣ⁽T7 的情况下,聚类过程终止,返回聚类的结果集。否则,它继续进行下一次𝛃+𝟭)-th 迭代,直到整个数据集已经被聚类,并且聚类过程【1】,最终满足下面的条件 (2.1) :

K-均值聚类的收敛性|图片作者
在执行聚类时,我们的目标是最小化类间平方距离的总和,以便这些观察值∀𝒙 ∈ 𝒔ᵣ和每个类∀𝒔ᵣ ∈ 𝙎的质心∀𝒄ᵣ之间的距离最小。
这与方差𝑽𝒂𝒓(𝒔ᵣ的最小化非常相似,方差是𝒖ᵣ-observations 在𝒓=𝟭∀𝒔ᵣ∈𝙎每个聚类内的平均协变(成对)方差..𝙠.同时,我们的目标是最大化所有𝙠-clusters ∀𝒔 ∈ 𝙎的质心∀𝒄ᵣ ∈ 𝑪之间的距离,使得所有质心到向量空间ℝ ᵈ 的中心𝙘ₒ的平均距离最大。最佳群集间距离必须始终满足以下条件 (2.2) :

最佳类内距离标准|作者图片
经典的 Lloyd-Forgy 的 K-Means 过程是几种聚类算法的基础,包括 K-Means++算法、K-Medoids 算法、模糊 C-Means 算法等。尽管,由于潜在的巨大计算复杂性,这些算法中的一些不能有效地用于聚类。
为什么 K-Means 聚类仍然更有效
如前所述,使用 Stewart Lloyd 和 Edward Forgy 在 1965 年提出的 K-Means 算法以及其他继承方法,在许多情况下,由于超多项式的复杂性,应用于高维数据集的聚类变得低效【1】:

K-Means 聚类算法的复杂性|图片作者
,其中𝒏-大量的观察值,𝒌-总的聚类数,𝒅-大量的特征(即向量空间维度),𝒊-大量的迭代,𝛔-最小的类内方差。
Lloyd-Forgy 的 K-Means 算法的最坏情况复杂度成比例地限制为:

经典的 K-均值复杂性渐近边界|图片作者
有几种方法可以解决 Lloyd-Forgy 的 K-Means 算法的巨大复杂性,例如降低数据集的维数、进行聚类以及将数据集表示为多维整数格。
虽然,在聚类大数据集的情况下,使用这些方法可能仍然是低效的,其中的观测值数量远远超过𝗻 ≫ 𝟏𝟎观测值。
此外,已知的模糊 c-均值算法的复杂度非常接近经典的 Lloyd-Forgy 算法的平均情况复杂度,并且不同之处在于加权质心计算的额外复杂度𝙊(𝗻:

模糊 C 均值算法复杂度|图片作者
为了执行高维数据集的聚类,我们需要一种不同的、更有效的算法,具有大规模数据集聚类的降低的复杂性。
K-Means++算法及其复杂性
由 David Arthur 和 Sergei Vasilevskii 在 2007 年提出的一种优化,被公式化为 K-Means++算法,提供了执行高维数据聚类的能力,与先前讨论的最初的 Lloyd-Forgy 的 K-Means 和其他方法相比,显著更快。同时,使用优化的 K-Means++算法不影响聚类的整体质量,提高了聚类结果的类内和类间距离。与 Lloyd-Forgy 的方法不同,它主要确保数据集在迭代次数内聚类,迭代次数等于最初给定的聚类数。这反过来对数据聚类的过程产生积极的影响【2,5】。
K-Means++聚类过程可以表述如下【2,5】:
让𝙓-𝙠𝙣-observations 的数据集-𝘾和𝙎的聚类总数-𝙠质心和聚类的结果集分别为:
- 选择质心𝙘₀作为随机观测∀𝙭 ∈ X:

2.选择质心𝙘₁作为到质心 c0 距离最大的观测∀𝙭:

3.计算𝛃=𝟏内𝙓的𝙠-clusters ∀𝒔 ∈ 𝙎..迭代的𝙠:
▪︎为每个观察𝒙ₜ ∈ 𝑿,𝙩=𝟏..𝒏,请执行以下操作:
- 检查观察值∀𝒙ₜ ∈ 𝘾是否已经追加到质心集。如果没有,继续下一步 3.2
- 计算从当前观测𝒙ₜ到每个现有质心∀𝙘 ∈ 𝘾的|𝒙ₜ - ∀𝙘|距离
- 找到质心𝙘ᵣ ∈ 𝘾,𝙧=𝟏..𝛃到𝒙ₜ的距离最短:

- 将观测值𝒙ₜ分配给质心为𝙘ᵣ ∈ 𝒔ᵣ的𝙧-th 聚类𝒔ᵣ ∈ 𝙎
4.检查𝙠-centroids ∀𝙘ᵣ ∈ 𝘾,𝙧=𝟏..𝙠已经被最终计算出来,并且所有的观测值都被安排到相应的𝙠-clusters ∀𝒔 ∈ 𝙎.中如果没有,继续执行步骤 5。否则,终止聚类过程。
5.在𝒔ᵣ ∈ 𝙎的所有现有集群中找到一个观测𝒙ⱼ,从该处到𝙧=𝟏𝙘ᵣ∈𝘾的质心之一的距离..𝛃是最大的:

6.将观测值𝒙ⱼ附加到集合𝘾,作为新聚类𝒔ᵣ+₁的质心𝙘ᵣ+₁←𝒙ⱼ;
7.继续执行步骤3–6,直到以下过程最终收敛,数据集最终聚类;
上面介绍的算法的主要优点是,它提供了同时计算质心和相应的结果聚类的能力,这极大地影响了算法的复杂性,并因此影响了整个聚类过程的持续时间,使得有可能比以前制定的其他类似算法更快地执行高维数据集的聚类。
在每个𝛃=𝟏..𝙠迭代,它计算下一个集群的质心𝙘ᵣ+₁,更新现有的集群𝒔ᵣ ∈ 𝙎,𝙧=𝟏..𝛃通过重新评估所有观测值∀𝒙 ∈ 𝑿到多个新建聚类的分配,使得在其最后的𝙠-th 迭代,聚类过程产生结果聚类𝙎.的集合
Python 3.9 中的代码示例使用最新的 NumPy 库实现了优化的 K-Means++聚类算法,如下所示:
上面演示的代码片段有一个重要的优化,它允许减少进程内存空间的数量,广泛用于大型数据集的聚类。在聚类过程中,它计算输入数据集𝑿中的观察值的索引,将其附加到𝘾和𝙎集,而不是将相同的高维数据克隆到多个集中。反过来,在处理高维数据集的聚类的情况下,这使得消耗显著更少量的进程存储器成为可能。
最后,您可能已经注意到,与著名的 Lloyd-Forgy 算法或模糊 c 均值聚类算法相比,K-Means++的复杂度显著降低,在一般情况下,估计仅为𝙊(𝙠 𝙣𝙙𝙞 +𝙣𝙙。具体地,在迭代总数𝙞等于聚类总数𝙠.的情况下,K-Means++的复杂度从超多项式平滑到象限,由𝙊(𝙠 𝙣𝙙 + 𝙣𝙙限定在这种情况下,K-Means++聚类的复杂性大约比原始 Lloyd-Forgy 的 K-Means 或模糊 C-Means 算法的复杂性低 28 倍:

数据聚类算法复杂性|图片作者
此外,下图显示了将具有𝙙=𝟐维度的𝙣=𝟏𝟎观测数据集聚类为一组𝙠=𝟑结果聚类,执行𝙞=𝟏𝟎迭代的估计复杂度:

K-Means、模糊 C-Means 和 K-Means 算法复杂度|图片作者
正如你所看到的,在上图中,K-Means++算法有一个复杂度(navy),由于几个算法级的优化【1】,这个复杂度已经大大降低了。
评估聚类的质量
最后,让我们简短地看一下使用 K-Means++算法实现的数据聚类的质量。为了确保 K-Means++最有能力提供正确的结果,从而提供适当的聚类质量,我们将进行实验,通过使用‘scikit-learn’库,执行基于高斯正态分布生成的合成数据集的聚类。
使用‘sci kit-learn’生成各向同性高斯斑点使得创建用于聚类的多维数据集成为可能。该实验的主要目的是确定使用 K-Means++算法是否提供聚类的结果,这与使用【scikit-learn】库的情况相同。
这通常是通过生成合成数据集并使用上述 K-Means++算法执行相同的聚类来完成的。
具体来说,至少有三种主要类型的数据集可用于聚类验证,例如每个数据集分别具有小、平均、和大的类间距离(即标准差(STDEV) 参数)的数据集。
这是数据集聚类结果的可视化,具有不同的标准差𝛅:
案例#1: 𝙣=50,𝙠=3,𝙙=2,𝛅=4.5(小集群间距离)

案例 2: 𝙣=50、𝙠=3、𝙙=2、𝛅=1.5(平均集群间距离)

案例 3: 𝙣=100、𝙠=3、𝙙=2、𝛅=0.3(集群间距离大)

对于正在讨论的使用 K-Means++算法的数据聚类的完整结果,请参考相关项目,贡献给 Anaconda Cloud:
结论
K-Means++算法的一个优点是,它能够同时计算质心并将数据分配给聚类。高维数据集聚类是通过多次迭代实现的,与其他现有方法相比,迭代次数明显减少。K-Means++能够在最初的几次迭代中将数据分配给聚类,而不会影响聚类本身的质量。大多数情况下,它比其他方法更快,提供了早期收敛,从而提高了聚类性能。与劳埃德算法不同,它的复杂度已经大大降低,并且低于 NP-hard。最后,K-Means++算法基于使用规则或平方欧几里得距离度量,有效地最小化了类内方差,避免了已知的韦伯问题。类似于 K-Medians 和 K-Medoids 算法,它能够在聚类大型高维数据集时提供更好的欧几里德距离解决方案。
K-Means++集群 Anaconda Python 3.8、NumPy 1.20.x、Scikit-Learn 0.20.x 中完整的源代码项目可以从我的 GitHub 和 Anaconda 云库下载:
- 【https://github.com/arthurratz/kmean_pp_clu_optimal
- https://anaconda.org/arthurvratz/kmeans_pp_nb/notebook
参考
- “k-means 聚类”——来自维基百科,免费百科
- “k-means++”——来自维基百科,免费百科
- “模糊聚类”——来自维基百科,免费百科
- 《你需要的最全面的 K-Means 聚类指南》作者 Pulkit Sharma,Analytics Vidhya,2019 年 8 月
- 《理解 K-Means,K-Means++和,K-Medoids 聚类算法》作者 Satyam Kumar,走向数据科学,2020 年 6 月
- “K 均值聚类的进展。一种数据挖掘思维》,吴俊杰,施普林格柏林海德堡,德国柏林,2012
K-Means 聚类——在 Python 中成功使用的综合指南
机器学习
用真实数据的 Python 演示解释 K-Means 算法

k-均值聚类。图片由作者提供。
介绍
如果你想成为一名成功的数据科学家,了解不同的机器学习算法是如何工作的是至关重要的。
这个故事是解释每个算法的细微差别的系列的一部分,并提供了一系列 Python 示例来帮助您构建自己的 ML 模型。
故事涵盖以下主题:
- K-Means 所属的算法类别
- K-Means 算法如何工作的解释
- k-意味着限制和如何处理它
- 关于如何执行 K 均值聚类的 Python 示例
K-Means 属于哪一类算法?
作为一名数据科学家,你会非常清楚,对所有不同的机器学习算法进行计数和分类几乎是不可能的。这部分是因为他们太多了。同时,它们跨越多个类别(例如,神经网络可以用于解决广泛的问题,包括分类和回归,所以我将它们放在自己的类别中)。
尽管如此,我还是试图收集一些最常用的信息,你可以在下面的互动旭日图中看到。确保点击👇在不同的类别上对进行放大并揭示更多的。
至于 K-Means,它是属于聚类算法组的无监督机器学习技术的一部分。这些常用于根据所选特征(属性)的相似性对客户、对象或其他项目进行分组(聚类)。
机器学习算法分类。由作者创建的交互式图表。
如果你喜欢数据科学和机器学习 ,请 订阅 每当我发布一个新的故事,你都会收到一封电子邮件。
K-Means 算法是如何工作的?
K-Means 是最著名和最常用的算法之一,因为它的简单性和速度。虽然,同时,它也有一些限制(稍后会详细说明)。
它旨在利用几个简单的步骤,通过多次迭代来重复这些步骤。在完成下面列出的步骤时,您可以参考下面的 gif 以获得直观的解释。

k-均值聚类在行动中。图片来自作者。
- 该算法的第一步是初始化定义数量的质心(在图表中用 X 表示)。
- 计算每个点(向量)和每个质心之间的距离,然后将点分配给最近的质心。
- 然后,基于同一组(群)中所有点(向量)的平均值,给每个质心分配一个新位置。
- 然后重复该过程,根据新的质心位置和新计算的平均值重新分配点,得到质心的新位置。
- 迭代继续,直到质心不再改变它们的位置或者达到定义的最大迭代次数。
k-意味着限制和如何处理它
定义聚类的数量
在使用 K-Means 开始聚类过程之前,需要定义想要有多少个聚类。如果您有一个只有 2 或 3 维的简单数据集,您可以绘制数据并对其进行可视化分析,以决定最合适的分类数。
然而,这并不理想,尤其是如果您有更多的属性(维度)。为了帮助决定合适的集群数量,您可以使用“肘”方法。为此,多次运行 K-Means 聚类,每次尝试不同数量的聚类,并记录 WCSS 的值(在聚类平方和内)。注意,WCSS 在 sklearn 中被称为“惯性”。
完成后,将 WCSS 值绘制到如下所示的折线图上(本文后面的 Python 部分将展示如何执行此操作的具体步骤):

选择理想聚类数的肘图。图片由作者提供。
WCSS 随着你引入更多的集群而减少。然而,在某个点之后,WCSS 的减少仅仅是最小的,这表明不需要将聚类分成更多的聚类,因为这些聚类中的点更相似而不是不同。
在上面的例子中,“肘”在 k=3 或 k=4 附近。因此,3 或 4 是您想要的最大集群数。注意,我用这个图表为你之前看到的澳大利亚城市 gif 决定了 4 个集群。
质心初始化
基本的 K-Means 算法随机初始化质心。因此,根据质心的初始位置,结果可能会有所不同,并且可能不是最佳的。
要解决这个问题,您可以采用以下策略:
- 多次初始化质心并选择最佳运行(最低 WCSS)
- 使用 k-means++提供的智能初始化
以上两者都是在 sklearn 的 KMeans 算法中作为默认设置实现的。
距离算法
K-Means 使用空间中不同点(向量)之间的欧几里德距离来识别哪些点属于一起。因此,您还需要注意以下几点:
- 在 K-Means 算法中只能使用数值属性。如果您想在聚类中使用分类类型,首先需要将它们转换为数字类型。有多种方法可以做到这一点,比如使用 sklearn 的序数编码器或者类似的方法。
- 请注意您在聚类中使用的属性的规模和分布。您可能希望首先通过删除异常值或引入“范围上限”来排除异常值你可能还想使用能量转换或最小-最大缩放来转换和拟合你的每个属性的分布到相同的范围。
- 最后,根据您的数据类型和使用案例,您可能更喜欢使用基于密度的算法,而不是基于距离的算法。
使用真实世界数据的 Python 中的 K-Means
设置
我们将使用以下数据和库:
- 来自 Kaggle 的澳大利亚天气数据
- Scikit-learn library 执行 K-Means 聚类
- 用于数据可视化的 Plotly 和 Matplotlib
- 熊猫用于数据操作
- Geopy ,进度条,采集澳大利亚城市坐标的时间
让我们导入所有的库:
然后我们从 Kaggle 获取澳大利亚的天气数据,你可以按照这个链接下载:https://www . ka ggle . com/jsphyg/weather-dataset-rattle-package。
我们接收数据并派生出一些新的变量,比如 Location2,它具有使用 Geopy 提取城市坐标的正确格式。

经过一些修改的 Kaggle 的澳大利亚天气数据片段。图片由作者提供。
因为我们的原始数据只包含位置(城市)名称而不包含坐标,所以我们将使用 Geopy 的名称来获取这些坐标。请注意,我们在每次调用之间添加了 1 秒钟的睡眠时间,以避免服务器过载。
这是我们得到的回报片段:

澳大利亚城市坐标。图片由作者提供。
我们也可以把它标在地图上:

地图上的澳大利亚城市。图片由作者提供。
k 均值聚类
如前所述,我们需要做的第一件事是确定我们需要多少个集群。为此,我们使用“肘”的方法。代码如下:

选择理想聚类数的肘图。图片作者作者。
假设我们无法在 3 个或 4 个集群之间做出决定,那么我们执行集群并可视化这两个选项:
上面的代码产生以下摘要:

k-均值聚类结果。图片由作者提供。
然后,我们将聚类标签附加回 df_loc 数据框,并在地图上绘制结果。请注意,您将需要从['Clust3']更改为['Clust4'],添加额外的颜色,并指向 model4 以生成第二个图。
3 组:

澳大利亚城市集群:3 个集群。图片由作者提供。
4 个集群:

澳大利亚城市集群:4 个集群。图片由作者提供。
结论
聚类很少是分析的终点。在很多情况下,这只是一个开始。
例如,您可能希望使用澳大利亚的天气数据构建一个监督分类模型来预测明天下雨的可能性。城市位置可能是一个重要的特征,因为附近地方的气候往往是相似的。因此,您可以决定使用上述分类作为您输入到预测模型中的特征之一。
最后,不管你的目标是什么,我希望这个故事能帮助你更好地理解 K-Means 聚类,并让你有信心亲自尝试一下。
如果您有任何问题或建议,请随时告诉我!
干杯!👏
索尔·多比拉斯
如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加盟媒介是:
https://solclover.com/membership
我还挑选了一些你可能喜欢的额外读物:
K-Means 聚类:数据科学 R 中的概念和实现
介绍如何理解用 R 实现的 kmeans 并选择最佳的 K
机器学习中的聚类算法是无监督的技术(那些有输入数据但没有标记响应的技术)。他们的目标是绘制数据模式,并根据相似性将数据观察结果分成不同的组。K-Means 聚类是实现成功汇总高维数据的聚类算法的一种方式。
K-means 聚类将一组观察值划分为固定数量的聚类,这些聚类最初是基于它们的相似特征指定的。

然而,问题出现了,对群体的观察:
1)事物彼此相似是什么意思?
2)我们如何确定事物之间的距离是否足够近,可以归为一组?
回答这两个问题,决定最佳 K,理解 K-means 概念并在 R 中的数据集上实现它是这篇博客的范围。
一旦我们定义了 a)我们需要的聚类数量,b)定位我们的聚类(质心)的初始猜测,以及 c)距离度量,我们就可以应用 K-means 来获得聚类质心的最终估计和质心的每个观察的分配。
理解算法:
为了便于理解,让我们假设我们有一个总共有 10 个观察值的数据集。查看数据,我们可以得出结论,数据可以很容易地分为 3 个不同的集群,所以我们用这个。
首先,我们选择我们想要对数据进行分类的聚类数(这是 K-means 中的 K)。这里,让我们决定 K = 3,因为这是可以直观推断的;一会儿我们将讨论确定 K 的技术方法。

样本数据集(图片由作者提供)
下一步是随机决定三个不同的初始数据点,作为我们的聚类或图表上的“质心”,如下图中的彩色三角形所示。然后,我们测量“1”数据点和三个质心之间的距离,并为其指定最接近的质心的颜色。这将被重复,直到所有的数据点都被分配给任何一个质心。

选择随机的 K 形心(图片由作者提供)
接下来,我们计算每个聚类的平均值,它对应于每个质心的数据点。这个平均值现在是每个质心的新位置,我们在图上重新定位它们,如下所示。我们计算每个点与所有质心的距离并相应地给它们着色的部分将再次重复,直到质心的位置不再改变。下面的图表是我们期望得到的,一旦没有更多的变化。

将质心重新定位到它们的聚类点(图片由作者提供)
这就是 K-means 如何基于距离度量将我们的数据集分割成指定数量的聚类。我们在二维图中使用的距离度量是欧几里德距离(x + y 的平方根)。
在 R 中实现 K-means:
第一步:安装相关的包并调用它们的库
install.packages("dplyr")
install.packages("ggplot2")
install.packages("ggfortify")library("ggplot2")
library("dplyr")
library("ggfortify")
第二步:加载并理解数据集
Iris 是一个内置的数据集,它包含来自 3 种不同类型的鸢尾物种(鸢尾、杂色和海滨鸢尾)的 150 个花朵观察结果。我们将用它来进行算法测试。
summary(iris)
head(iris)

(图片由作者提供)
步骤 3:消除目标变量
由于观察值的分类已经在这个数据集中完成,我们需要从代码中删除目标变量,因为我们希望我们的算法能够自己完成这项工作。为此,我将把 iris 的前四列加载到我的数据框‘data’中。
data <- select(iris, c(1:4))
如何确定 K 用什么值?
第四步:肘穴手法
虽然有许多方法来决定要选择的聚类数,但广泛使用的是 肘点法 (虽然不是很准确,我们将看到为什么)。其思想是通过将每个聚类内的变化相加来评估聚类的质量(跟踪这一点并以不同的起点重新开始),具有最小变化的参数获胜。肘点法绘制了变异减少与聚类数(K)的关系,肘点是 K 的一个数值,在此之后变异不是很陡,是我们的最佳 K。
我们没有一个内置的函数来衡量我们观察结果的变化程度。但是,有一个 Rpubs 文档为我们创建了一个 wssplot 函数(在组平方和图内)来实现我们的肘点方法。
wssplot <- function(data, nc=15, seed=1234){
wss <- (nrow(data)-1)*sum(apply(data,2,var))
for (i in 2:nc){
set.seed(seed)
wss[i] <- sum(kmeans(data, centers=i)$withinss)}
plot(1:nc, wss, type="b", xlab="Number of Clusters",
ylab="Within groups sum of squares")
wss
}
该图显示了 K = 2 时的锐边,表明数据集的最佳聚类数为 2。

WSS 情节(作者图片)
第五步:实施 K-means
正如它看起来那样简单,kmeans()只需要我们输入数据帧,并指定 K 来运行。
kmean <- kmeans(data, 2)
kmean$centers
kmean\(clusters 将返回一个范围从 1 到 2 的数字向量,描述哪些观察值属于分类 1 和分类 2。kmean\)centers 返回每个质心的位置。例如,聚类 1 具有萼片的平均值。长度= 5.00,萼片宽度= 3.36,花瓣。长度= 1.56,花瓣宽度= 0.29。

(图片由作者提供)
步骤 6:绘制聚类中的数据点
尽管这个图看起来很棒,并且已经清楚地将我们的观察结果分成了 2 个组,但是我们已经知道我们的数据集总共有 3 个组。我们的肘点技术在给出正确的 K 值时并不完全准确。因此,根据经验,最好是在肘点周围的 K 值之间迭代,并自己决定最佳的行动方案。
autoplot(kmean, data, frame = TRUE)

聚类后的数据图表,K = 2(图片由作者提供)
第七步:K 表示 K = 3
既然我们已经决定改变 K 并查看数据模式,那么让我们看看结果是如何变化的。
kmean <- kmeans(data, 3)
kmean$centers

(图片由作者提供)
步骤 8:绘制新的聚类图
我们看到 kmean\(clusters 现在如何将观察结果分成三个类,kmean\)centers 也更新了质心值。下图显示了基于 3 个集群的分组。同样,K 规格取决于我们;确定 K 值的技术可以给我们一个很好的估计。

聚类后的数据图表,K = 3(图片由作者提供)
K-means 是一种有效的机器学习技术,它:
- 易于实施和应用
- 具有很强的可解释性
- 产生比分层聚类更紧密的聚类
- 计算速度很快
然而,通过迭代方法手动选择 K、依赖于初始聚类以及由于离群值导致的质心位置不准确是 kmeans 的一些缺点。这篇博文重点解释了 kmeans 的主要概念,讨论了一种确定 K 值的技术,用 R 实现了 kmeans,并强调了它的一些优点和缺点。
K-means 聚类:找到我的部落!
它是如何工作的?我怎样才能让它跑得更快?

(图片由作者提供)
K-means 聚类在需要发现大量样本之间关系的数据分析问题中有许多潜在的应用。该技术背后的概念非常简单,因此也非常灵活,它可以单独用于许多可能的配置,或者与其他机器学习技术结合使用。让我们来看看 K-means 聚类是如何工作的,以及一些可能的改进方法。
什么是 K-means 聚类?
查找隐藏信息
K-means 聚类的核心是一种试图根据某些规则对样本数据进行分类的算法。如果我们的样本数据是实数的向量,最简单的标准是数据之间的距离。
假设我在二维空间中有 4 个样本数据点:
(0, 0), (0, 1), (0, 3), (0, 4)

数据点:(0,0),(0,1),(0,3),(0,4)(图片由作者提供)
还有假设我知道我有两个组,我怎么找到两个组的中心和每个组的成员数据点?
第一步是为每组选择两个起点。在这个例子中,很容易观察,比如说,选择(0,0)作为第一组的起点,选择(0,3)作为第二组的起点。
但是我们不要这样做,因为那样会使这个例子太简单。
假设我实际上选了(0,0)和(0,1)作为起点,(0,0)代表组 0,(0,1)代表组 1。下一步是将四个数据点分配给两组中的每一组。我们通过计算数据点到每个组的距离,并将每个数据点分配到最近的一个组来实现这一点。
从数据点(0,0)开始,它的最近点显然是(0,0),距离为 0,所以数据点(0,0)被分配到组 0。移动到第二个数据点,(0,1),它更接近组 1,所以将其分配到组 1。在检查完每个数据点后,我们有:
group 0:
data points = (0, 0)
group 1:
data points = (0, 1), (0, 3), (0, 4)
既然我们已经将数据点分配给了每个组,那么需要更新每个组的平均值。组 0 的平均值保持在(0,0)不变,但是组 1 的平均值现在是:
mean of group 1 = [(0, 1) + (0, 3) + (0, 4)] / 3 = (0, 2.333...)
我们有了新的团队:
group 0:
mean = (0, 0)
group 1:
mean = (0, 2.333...)
但是现在我们已经更新了组均值,需要重新分配每个组的数据点,以确保它们仍然最接近其组均值:
(0, 0): closest to (0, 0)
(0, 1): closest to (0, 0)!!
(0, 3): closest to (0, 2.333...)
(0, 4): closest to (0, 2.333...)
请注意,点(0,1)不再最接近组 1 的平均值,因此需要将其重新分配给组 0:
group 0:
data points = (0, 0), (0, 1)
group 1:
data points = (0, 3), (0, 4)
在将数据点分配到组和更新组均值之间交替,我们最终达到稳定状态,其中不再有数据点切换组,这就是我们最终的 K 均值聚类:
group 0:
mean = (0, 0.5)
data points = (0, 0), (0, 1)
group 1:
mean = (0, 3.5)
data points = (0, 3), (0, 4)

(图片由作者提供)
结构
定义算法的结构
从上面的例子中我们可以看出,算法可以分为两个部分,初始化和聚类。让我们来定义算法的过程:
import copy
import numpy as np
class KMean:
def __init__(self, samples):
self._samples = np.array(samples)
self._clusters = [-1] * len(samples)
self._means = None
self._processed = False
@property
def samples(self):
return self._samples
@property
def means(self):
return self._means
@means.setter
def means(self, new):
self._means = new
@property
def clusters(self):
return self._clusters
@clusters.setter
def clusters(self, new):
self._clusters = new
def init(self):
raise ValueError("init not implemented")
def cluster(self):
raise ValueError("cluster not implemented")
@staticmethod
def _cls_of(func):
return func.__func__.__qualname__.split('.')[0]
def process(self):
if self._processed:
print("Process already completed")
return
print(f"Initializing with {self._cls_of(self.init)}")
**self.init()**
print(f"Initial means: {self.means}")
print(f"Clustering with {self._cls_of(self.cluster)}")
**self.cluster()**
print(f"Processing {self.__class__.__name__} complete")
self._processed = True
初始化
从哪里开始
初始化可能非常简单,所以接下来让我们来研究一下。
最简单的方法是手动输入你想要的起点:
class InitInput(KMean):
def __init__(self, input_means, **kwargs):
self._input_means = input_means
super().__init__(**kwargs)
def init(self):
self.means = self._input_means
测试它:
init1 = InitInput(input_means=[[0, 0], [0, 1]],
samples=[(0, 0), (0, 1), (0, 3), (0, 4)])
init1.init()
print(init1.means)
"""
[[0, 0], [0, 1]]
"""
如果你知道你想从哪里开始或者当你在做研究的时候,这是非常好的。但是,当您的样本量很大,并且不知道数据点是否随机排列时,最好随机选择起始点:
class InitForgy(KMean):
def __init__(self, k, **kwargs):
self._k = k
super().__init__(**kwargs)
def init(self):
indices = np.random.choice(
len(self.samples),
size=self._k,
replace=False,
)
self.means = [copy.deepcopy(self.samples[idx]) for idx in indices]
这种方法被称为 Forgy 方法,测试它:
init2 = InitForgy(k=2,
samples=[(0, 0), (0, 1), (0, 3), (0, 4)])
init2.init()
print(init2.means)
"""
[array([0, 1]), array([0, 3])]
"""
使聚集
如何找到最佳聚类
对样本数据进行聚类包括在将数据点分配到组和更新组均值之间进行交替,最简单的方法是在算法的每次迭代期间,遍历每个点,计算该点到每个组均值的距离,并将数据点分配到最近的组。这就是所谓的劳埃德方法:
class ClusterLloyd(KMean):
def __init__(self, tolerance=0, **kwargs):
self._tolerance = tolerance
self._history = []
super().__init__(**kwargs)
@property
def history(self):
return self._history
@staticmethod
def _calc_dist(sample, mean):
diff = sample - mean
dist = np.dot(diff, diff)
return dist
def _calc_cluster(self, sample):
**# loop through each cluster to find the closest cluster
idx = None
dist = None
for i, mean in enumerate(self.means):
cur_dist = self._calc_dist(sample, mean)
if idx is None or cur_dist < dist:
idx = i
dist = cur_dist**
return idx
def _calc_shift(self, new_clusters):
shifted = 0
for i, c in enumerate(new_clusters):
if c != self.clusters[i]:
shifted = shifted + 1
shift = shifted / len(new_clusters)
return shift
def _calc_means(self, new_clusters):
means_map = {}
for i, cluster in enumerate(new_clusters):
if cluster not in means_map:
means_map[cluster] = [self.samples[i], 1]
else:
curr = means_map[cluster]
curr[0] = curr[0] + self.samples[i]
curr[1] = curr[1] + 1
means = copy.deepcopy(self.means)
for k, v in means_map.items():
new_mean = v[0] / v[1]
means[k] = new_mean
return means
def _update(self, new_clusters):
new_means = self._calc_means(new_clusters)
self._history.append((new_clusters, new_means))
self.clusters = new_clusters
self.means = new_means
def cluster(self):
self._history.append((self.clusters, self.means))
while True:
new_clusters = []
**# loop through each data point
for sample in self.samples:
new_clusters.append(self._calc_cluster(sample))**
shift = self._calc_shift(new_clusters)
if shift <= self._tolerance:
break
self._update(new_clusters)
测试它:
class InputLloyd(InitInput, ClusterLloyd):
passkm1 = InputLloyd(input_means=[[0, 0], [0, 1]],
samples=[(0, 0), (0, 1), (0, 3), (0, 4)])
km1.process()
print(f"clusters: {km1.clusters}")
print(f"means: {km1.means}")
"""
Initializing with InitInput
Initial means: [[0, 0], [0, 1]]
Clustering with ClusterLloyd
Processing InputLloyd complete
clusters: [0, 0, 1, 1]
means: [array([0\. , 0.5]), array([0\. , 3.5])]
"""
我们发现我们的集群:
"""
clusters: [0, 0, 1, 1]
group 0: (0, 0), (0, 1)
group 1: (0, 3), (0, 4)
"""
三角不等式
通过巧妙的观察加速算法
劳埃德的方法很容易理解,但不是最有效的。如果考虑算法的时间复杂度,在聚类过程的每次迭代中,我们需要计算每个数据点到每个聚类均值的距离。如果我们有 N 个数据点和 K 个聚类,那将是:
~O(N * K)
实际上有几种方法可以加快这个过程。
其中一个涉及以下观察:

第 1 组最接近的数据点(0,0)平均值为 2.5(图片由作者提供)
在我们的聚类算法的最后一次迭代中,组 0 的平均值是(0,0.5),组 1 的平均值是(0,3.5),点(0,0)到其当前分配的组 0 的距离是 0.5。如果我们已经计算了聚类的距离平均值,在这种情况下,3,我们实际上不需要计算点(0,0)到组 1 的平均值(0,3.5)的距离,就可以知道点(0,0)不可能更接近组 1。
这是为什么呢?如上图的第二部分所示,两个组的距离为 3,而(0,0)到组 0 的距离为 0.5。所以,无论点(0,0)在离 0 组 0.5 的轨道上的什么地方,都不会比离 1 组 2.5 近!
这本质上是三角不等式:
三角形的一边总是比其他两边的总和短。
根据这一观察,我们可以更新劳埃德的方法,使其运行得更快:
class ClusterElkan1(KMean):
def __init__(self, tolerance=0, **kwargs):
self._tolerance = tolerance
self._mean_maps = []
self._history = []
super().__init__(**kwargs)
@property
def history(self):
return self._history
@property
def mean_maps(self):
return self._mean_maps
@staticmethod
def _calc_dist(sample, mean):
diff = np.array(sample) - np.array(mean)
dist = np.dot(diff, diff)
# note dist is actually distance squared
# no need to take the square root
return dist
def _calc_cluster(self, sample_idx):
idx = None
dist = None
for i, mean in enumerate(self.means):
**# check if need to calc dist
if dist is not None:
cluster_dist = self.mean_maps[-1][(idx, i)]
if dist * 4 < cluster_dist:
print(f"no need to recalculate dist for sample {sample_idx} with mean {i}")
continue**
sample = self.samples[sample_idx]
cur_dist = self._calc_dist(sample, mean)
if dist is None or cur_dist < dist:
idx = i
dist = cur_dist
return idx
def _calc_shift(self, new_clusters):
shifted = 0
for i, c in enumerate(new_clusters):
if c != self.clusters[i]:
shifted = shifted + 1
shift = shifted / len(new_clusters)
return shift
def _calc_means(self, new_clusters):
means_map = {}
for i, cluster in enumerate(new_clusters):
if cluster not in means_map:
means_map[cluster] = [self.samples[i], 1]
else:
curr = means_map[cluster]
curr[0] = curr[0] + self.samples[i]
curr[1] = curr[1] + 1
means = copy.deepcopy(self.means)
for k, v in means_map.items():
new_mean = v[0] / v[1]
means[k] = new_mean
return means
def _update(self, new_clusters):
new_means = self._calc_means(new_clusters)
self.clusters = new_clusters
self.means = new_means
self._update_history()
def _update_mean_map(self):
# calculate mean distances
mean_map = {}
for i, c in enumerate(self.means):
for j, c_p in enumerate(self.means[i + 1:]):
dist = self._calc_dist(c, c_p)
mean_map[(i, j + i + 1)] = dist
mean_map[(j + i + 1, i)] = dist
self._mean_maps.append(mean_map)
def _update_history(self):
self._history.append((self.clusters, self.means))
self._update_mean_map()
def cluster(self):
self._update_history()
while True:
new_clusters = []
for i in range(len(self.samples)):
new_clusters.append(self._calc_cluster(i))
shift = self._calc_shift(new_clusters)
if shift <= self._tolerance:
break
self._update(new_clusters)
class InputElkan1(InitInput, ClusterElkan1):
pass
下限上限
又一次加速
这很聪明。然而,还有更聪明的方法来改进这个算法。
看看聚类算法的最后两次迭代:

第 1 组均值偏移 0.5,第 2 组均值偏移 1.166…(图片由作者提供)
第 0 组的平均值移动了 0.5,第 1 组的平均值移动了 1.166…
我们如何利用这些信息来避免多余的计算?
嗯,我们知道点(0,0)在移动之前与组 0 均值的距离为 0,如果组 0 均值移动了 0.5,那么点(0,0)和组 0 之间的距离最多为 0.5。
如果我们也知道点(0,0)与组 1 的平均值的距离为 2.333…,那么,在移位之后,点(0,0)与组 1 的平均值的距离至少为 1.166…(2.333 — 1.166)。
如果点(0,0)到组 0 的距离最多为 0.5,而点(0,0)到组 1 的距离至少为 1.166…,那么点(0,0)必须更靠近组 0!不需要计算到组的距离意味着!
加上这一改进,我们有了迄今为止最有效的算法:
class ClusterElkan2(KMean):
def __init__(self, tolerance=0, **kwargs):
self._tolerance = tolerance
self._mean_maps = []
self._history = []
self._mean_shifts = None
self._bounds = None
super().__init__(**kwargs)
def _setup_cluster(self):
# the amount of shift of means from previous iteration
self._mean_shifts = [0] * len(self.means)
# a list of dict, each dict is bounds (ub for assigned cluster, lb for others) of a sample
self._bounds = [{j: None for j in range(len(self.means))} for i in range(len(self.samples))]
@property
def history(self):
return self._history
@property
def mean_maps(self):
return self._mean_maps
@property
def mean_shifts(self):
return self._mean_shifts
@mean_shifts.setter
def mean_shifts(self, new_shifts):
self._mean_shifts = new_shifts
@property
def bounds(self):
return self._bounds
@staticmethod
def _calc_dist(sample, mean):
diff = np.array(sample) - np.array(mean)
dist = np.dot(diff, diff)
return dist
def _calc_cluster(self, sample_idx):
# modify to always start with the previously assigned cluster
# modify to use lb and ub use one structure
idx = self.clusters[sample_idx]
dist = self.bounds[sample_idx][idx] + self.mean_shifts[idx] \
if idx >= 0 and self.bounds[sample_idx][idx] is not None \
else None
if dist is not None:
self.bounds[sample_idx][idx] = dist
for i, mean in enumerate(self.means):
if i != idx:
# looping through a mean
**# update lb if needed
lb = self.bounds[sample_idx][i] - self.mean_shifts[i] \
if self.bounds[sample_idx][i] is not None \
else None
if dist is not None and lb is not None:
if dist < lb:
print(f"no need to recalculate dist for sample {sample_idx} with mean {i} because of lower bound")
self.bounds[sample_idx][i] = lb
continue**
**# check mean dist
if dist is not None:
cluster_dist = self.mean_maps[-1][(idx, i)]
if dist * 4 < cluster_dist:
print(f"no need to recalculate dist for sample {sample_idx} with mean {i} because of mean dist")
continue**
sample = self.samples[sample_idx]
cur_dist = self._calc_dist(sample, mean)
self.bounds[sample_idx][i] = cur_dist
if dist is None or cur_dist < dist:
idx = i
dist = cur_dist
return idx
def _calc_shift(self, new_clusters):
shifted = 0
for i, c in enumerate(new_clusters):
if c != self.clusters[i]:
shifted = shifted + 1
shift = shifted / len(new_clusters)
return shift
def _calc_means(self, new_clusters):
means_map = {}
for i, cluster in enumerate(new_clusters):
if cluster not in means_map:
means_map[cluster] = [self.samples[i], 1]
else:
curr = means_map[cluster]
curr[0] = curr[0] + self.samples[i]
curr[1] = curr[1] + 1
means = copy.deepcopy(self.means)
for k, v in means_map.items():
new_mean = v[0] / v[1]
means[k] = new_mean
return means
def _update(self, new_clusters):
new_means = self._calc_means(new_clusters)
self.clusters = new_clusters
self.mean_shifts = [self._calc_dist(self.means[i], new_means[i]) for i in range(len(self.means))]
self.means = new_means
self._update_history()
def _update_mean_map(self):
# calculate mean distances
mean_map = {}
for i, c in enumerate(self.means):
for j, c_p in enumerate(self.means[i + 1:]):
dist = self._calc_dist(c, c_p)
mean_map[(i, j + i + 1)] = dist
mean_map[(j + i + 1, i)] = dist
self._mean_maps.append(mean_map)
def _update_history(self):
self._history.append((self.clusters, self.means))
self._update_mean_map()
def cluster(self):
self._setup_cluster()
self._update_history()
while True:
new_clusters = []
for i in range(len(self.samples)):
new_clusters.append(self._calc_cluster(i))
shift = self._calc_shift(new_clusters)
if shift <= self._tolerance:
break
self._update(new_clusters) class InputElkan2(InitInput, ClusterElkan2):
pass
通过这两个改进,我们可以有效地将 K-mean 算法在每次聚类迭代中的时间复杂度从~O(N * K)降低到~O(N)。
两种解决方案
不保证唯一的解决方案
让我们来看看下面这个问题:
data points = (0, 0), (0, 1), (0, 2), (0, 3)
number of clusters = 2
这一次,所有四个数据点的间距相等。
让我们以不同的起点将我们的算法应用于它:
# starting points [0, 0], [0, 1]
km2 = InputElkan2(input_means=[[0, 0], [0, 1]], samples=[(0, 0), (0, 1), (0, 2), (0, 3)])
km2.process()
print("Solution 1")
print(km2.clusters)
print(km2.means)
# starting points [0, 0], [0, 3]
km3 = InputElkan2(input_means=[[0, 0], [0, 3]], samples=[(0, 0), (0, 1), (0, 2), (0, 3)])
km3.process()
print("Solution 2")
print(km3.clusters)
print(km3.means)
"""
Solution 1
[0, 1, 1, 1]
**[array([0., 0.]), array([0., 2.])]**
Solution 2
[0, 0, 1, 1]
**[array([0\. , 0.5]), array([0\. , 2.5])]**
"""
我们得到两种不同的解决方案!
原因很明显,所有 4 个点都是等距的,解之间没有区别:
"""
[0, 1, 1, 1]
[0, 0, 1, 1]
[0, 0, 0, 1]
"""
那么这意味着什么呢?
对我来说,正确答案是没有一个解是正确的,聚类的个数不是两个,所以只有两个起点是没有办法正确聚类的。
我认为,对于这个特殊的问题,最合理的解决方案是(0,1.5)处的一个群集或者四个群集的每个点都属于它自己的群集。
结论
一切都还不完美
k-均值聚类是一个有趣的算法,可以非常有效。但是它并不完美,正如上一个例子所表明的那样。我们如何改进我们的算法来处理更复杂的情况?那是下次的故事!
R 中的 k-均值聚类

作者的情节
介绍
K-均值聚类是机器学习中最流行的无监督学习方法之一。该算法有助于根据元素之间的距离从“n”个元素中识别“k”个可能的组(聚类)。
更详细的解释可能是:算法找出你的数据中每个元素之间的距离,然后找出质心的数量,将元素分配到最近的质心以形成聚类,最终目标是使每个聚类的大小尽可能小。
K-means 可以以多种方式使用。例如,客户细分、保险欺诈检测、文档分类等。
关于 K-means 算法的一个常见问题是它是否能处理非数字数据。简单的回答是否定的,因为算法使用的是观测值之间的距离。但是,有许多算法可以帮助将非数字要素转换为数字要素,这将允许您将 K-means 算法应用于您的数据。例如,“node2vec”模型——一种用于图形表示学习的算法框架——可以将数据转换为嵌入,这种嵌入以后可以用于 K-means。
另一个有趣的事实是,与大多数无监督学习算法不同,您必须对调整参数做出经验决策(或不断尝试不同的参数,直到您达到满意的状态),您可以以某种方式对 K-means 执行超参数调整。我将在这篇博客中演示如何做到这一点。
个案研究
Loda 数据
在这个案例研究中,我使用了 R 中的“iris”数据集。
data("iris")
?iris
Edgar Anderson 的 iris 数据描述
这个著名的(Fisher 的或 Anderson 的)iris 数据集分别给出了 3 种 Iris 的 50 朵花的变量萼片长和宽以及花瓣长和宽的厘米测量值。这些物种是刚毛鸢尾、杂色鸢尾和海滨鸢尾。来源
Fisher,R. A. (1936)分类问题中多重测量的使用。优生学年鉴,7,第二部分,179-188 页。
这些数据是由安德森·埃德加(1935)收集的。加斯佩半岛的鸢尾,美国鸢尾协会公报,59,2–5。参考文献
《新的 S 语言》。沃兹沃斯&布鲁克斯/科尔。(将 iris3 作为 iris。)

数据预览
在执行 K-means 算法之前,我首先检查了标签,以查看这个数据集中有多少个分类。
> levels(iris$Species)
[1] "setosa" "versicolor" "virginica"
然后我把标签从原始数据中分离出来。这样,我们可以将数据视为新的、未标记的数据,用于无监督学习目的。
iris1 <- iris[,-5]
iris_label <- iris[,5]
由于虹膜数据中的所有变量都是数字,所以我不必做任何数据预处理。我假装以前从未看到过这个虹膜数据,所以我想知道模型的最佳 K 是什么(我在开始时提到的超参数调整)。
找到 K
在这一步中,我们需要知道两个术语,“wss”和“肘规则”,以帮助我们找到质心的最佳数量。
WSS : 质心内的总距离。由于 K-means 算法的目标是保持每个聚类的大小尽可能小,因此小的 wss 表示每个数据点都接近其最近的质心,或者说模型返回了良好的结果。
肘规则/方法 : 用于确定数据集中聚类数量的试探法。你首先绘制出 wss 分数与 K 数的关系,因为随着 K 数的增加,wss 总会下降;然而,每个 k 值之间的下降幅度会逐渐减小,曲线看起来就像一只蜷曲的手臂。这样一来,你其次需要找出哪个点落在手肘上。
# to reproduce the results
# you have to use set.seed()
set.seed(1)
wss<- NULL
for (i in 1:10){
fit = kmeans(iris1,centers = i)
wss = c(wss, fit$tot.withinss)
}plot(1:10, wss, type = "o")

WSS 对 K

阅读图并应用肘方法
根据上面的图表,我们可以知道 k = 3 可能是答案。如果你还记得,原始数据确实有三个不同的物种。到目前为止,我们做得很好!然而,你必须记住,在现实世界中,数据往往既不完美,也没有标签。这些群体之间的关系比我们这里的要复杂得多。因此您可能会发现多个 K 可以满足您需求。然后,你将不得不一个一个地尝试,研究这些群体,并通过做更深入的研究来证明你的答案。
拟合和绘图
然后,我拟合了一个 k = 3 的 K 均值模型,并用“fpc”包绘制了聚类图。
fit <- kmeans(iris[,-5], 3)library(fpc)
plotcluster(iris[,-5],fit$cluster,pointsbyclvecd=FALSE)

k = 3 时的聚类图
注意:当 pointsbyclvecd = TRUE 时,图形的数据点将由更合理的符号表示,如字母数字。当该参数设置为 FALSE 时,符号将变得不那么“合理”,就像这个博客的特色图片所显示的那样。
估价
当您在 R 中应用 K-means 算法时,该函数将帮助您同时生成模型的多个统计数据,包括 TSS、BSS 和我们在上面讨论过的 WSS。
TSS :代表总平方和,即数据点与数据整体平均值的总距离。
BSS :是每个聚类到数据全局均值的距离之和。
并且, TSS = BSS + WSS 。
这里,我们可以用另一种方法来评估你适合的模型。由于我一再提到我们希望 WSS 尽可能小,因此,从理论上讲,BSS 与 TSS 的高比率是我们所寻求的。
> fit$betweenss/fit$totss
[1] 0.8842753
如果你想测试你的模型的准确性,我是这样做的:
# First, relabel the data with the cluster numberiris$cluster = fit$clusterfor (i in 1:length(iris$Species)){
if (iris$cluster[i] == 1){
iris$label[i] = "setosa"
} else if (iris$cluster[i] == 3){
iris$label[i] = "versicolor"
} else {
iris$label[i] = "virginica"
}
}# Second, calculate the accuracy score
> mean(iris$label ==iris$Species)
[1] 0.8933333
有时,如果您有多个组,那么很难用 for 循环正确地重新标记数据。或者您只是想浏览来自同一个集群的数据,因为您的原始数据没有标记。您可以根据聚类数对它们进行二次抽样。我认为这也是一种处理你的数据的通用方法。您可以根据需要修改代码。
subsample <- list()
for(i in 1:3){
subsample[[i]]<- iris[fit$cluster==i,]
}> table(subsample[[1]]$Species)
setosa versicolor virginica
50 0 0 > table(subsample[[2]]$Species)
setosa versicolor virginica
0 2 36 > table(subsample[[3]]$Species)
setosa versicolor virginica
0 48 14> 134/150
[1] 0.8933333
结论
作为最流行的无监督学习算法之一,K-means 可以帮助我们研究和发现未标记数据中的复杂关系,而这些关系很可能被我们忽略。
在这篇博客中,我讨论了在 R 中拟合 K-means 模型,找到最佳 K,并评估该模型。我也谈到了计算标记数据的准确度分数。
请随时与我联系LinkedIn。
相关博客
使用 NetworkX、Gephi 和 Node2Vec 分析疾病共现
K-Means 聚类项目:钞票认证
使用 Python (Pandas,NumPy)收集和评估数据,并使用scikit-学习训练 K-Means 模型来检测钞票是真的还是伪造的。
你有没有遇到过这样的情况:当你在超市把钱交给店员时,却发现钱是假的,而你后面有一长串的人在等着结账?或者更尴尬的是,你没有携带其他纸币?我个人曾经经历过这种情况,被认为是一个不道德的小气鬼的尴尬在我脑海里停留了很长时间。这促使我进行这个项目,建立一个 K-Means 聚类模型来检测一张钞票是真是假。

照片由 Ystallonne Alves 在 Unsplash 拍摄
数据集概述:
这个数据集是关于区分真钞和伪钞的。数据是从图像中提取的,这些图像取自真的和伪造的类似钞票的样本。对于数字化,使用通常用于印刷检查的工业相机。最终图像的像素为 400x 400。由于物镜和到所研究物体的距离,获得了分辨率约为 660 dpi 的灰度图像。小波变换工具用于从这些图像中提取特征。(来源:https://www.openml.org/d/1462)
由于我是 ML 世界的初学者,我试图使这个项目尽可能简单,只专注于运行 K-Means 模型和计算结果。因此,出于关注 K-Means 本身的目的,我只挑选了两个变量来建立模型,它们是 V1(小波变换图像的方差)和 V2(小波变换图像的偏斜度)。
好吧,在进入这个项目之前,让我带你看一下这个项目的每一步:
步骤 1:收集和评估数据。(全码)
第二步:运行 K 均值。(全码)
第三步:重新运行 K-means 几次,看看我们是否得到类似的结果,这可以看出 K-Means 模型是否稳定。(全码)
步骤 4:分析 K 均值计算结果
第五步:计算结果的准确度!(全码)
我们开始吧!
步骤 1:收集和评估数据。

作者图片
构建 K-Means 的第一步是评估该数据集是否适合 K-Means;如果不是,那么我们应该选择其他的聚类模型。看到这个图后,我发现图中的数据分布既不太宽,也不太集中在一个地方,因此值得尝试在这个数据集上计算 K-Means。但是,在球形中没有明显的集群,所以我们应该预计 K-Means 模型在这里不会完美地工作。
第二步:运行 K 均值。

作者图片
开始符号是每个集群的质心。这张图看起来很好。
第三步:重新运行 K-means 几次,看看我们是否得到类似的结果,这可以确保 K-Means 模型在数据集中是稳定的。
代码的这一部分受到了《T2》这篇著名的 K-Means 文章的作者达布拉的启发。

作者图片
我的第三步是运行 K-Means 几次,因为 K-Means 将随机选择初始位置作为质心,然后它们将根据每个聚类成员的平均距离改变它们的位置,这将被设置为新的质心。因此,我们通常会在每次重新运行 K-Means 时得到不同的结果,但如果结果在许多测试中差异太大,则意味着 K-Means 可能不适合此数据集,因为它不稳定。在这里,运行 9 次 K-Means 后,我们得到的结果非常相似,这意味着这里的 K-Means 是稳定的。
步骤 4:分析 K 均值计算结果

作者图片
大约有 600 个数据聚集在组 0 中,大约有 773 个数据聚集在组 1 中。对于第一组,V1 的平均值= ~-0.12,V2 的平均值= ~-3.5。而对于第二组,V1 的平均值为 0.86,V2 的平均值为 6.1。
第五步:计算结果的准确度。
首先,让我们用正确的标签和 K 均值结果来可视化数据:

作者图片
我们可以看到,K-均值在 V2 = 1 时倾向于被一条水平线分割,而原始均值在 V1 =0 时倾向于被一条稍微倾斜的垂直线分割。这显示了 K-Means 的一个缺点,即 K-Means 给予较大的聚类更多的权重。(K-Means 中的组 1 倾向于包括在下面位置的较大的聚类。)让我们来计算这个 K-Means 聚类模型的准确性:
0.6528081692195478
K 均值结果:该 K 均值模型的准确率为 65.3%。
不错!由于我在这里没有进行任何数据清洗过程和预分析,所以获得 65.3%的准确率是相当合理的。但是,如果您对优化准确率感兴趣,您可以考虑进行因子分析,以找到最有影响力的变量放入模型中。那么你会得到一个更好的结果!(对于对因子分析感兴趣的读者,我发现 DataCamp 有一篇关于 python 中因子分析的很好的介绍文章。)
感谢您花时间阅读这篇文章。
如果你是想找数据科学实习生的雇主,这是我的 LinkedIn
如果你也在数据科学/商业分析领域工作,请随时通过 IG( @jchen_mmm )、电子邮件或下面的评论给我任何反馈!
k 表示在大数据上使用 PySpark 进行聚类
parallel K 初学者指南意味着使用 Python & Spark 进行集群

尼克·艾布拉姆斯在 Unsplash 上拍摄的照片
如果你不熟悉 K 均值聚类,我推荐你通读下面这篇文章。本文主要关注数据并行和集群,即 K 表示在大数据上进行集群。
关于聚类
聚类是一种无监督的学习技术,简而言之,您正在处理数据,而没有任何关于目标属性或因变量的信息。聚类的一般思想是在数据中找到一些内在的结构,通常称为相似对象的组。该算法研究数据以识别这些模式或组,使得一个组中的每个成员更接近该组中的另一个成员(较低的群内距离),而远离不同组中的另一个成员(较高的群间距离)。
集群在哪里适用?
你们大多数人一定对现实生活中的这些例子很熟悉:
- 客户细分——广泛用于目标营销
- 图像分割—识别景观变化或入侵
- 推荐引擎
背景
k 表示聚类,与平台无关,使用欧几里德距离形式的相似性度量。通常被称为分裂或分割聚类,K 均值的基本思想是从每个数据点开始一个更大的聚类,然后根据用户输入的 K(或聚类的数量)将它们分成更小的组。每个集群都有一个中心,称为质心。给定聚类中质心的总数总是等于 k。该算法迭代地寻找数据点,并将它们分配给最近的聚类。
一旦所有数据点被分配到它们各自的质心(这里代表每个聚类),质心值被重新计算,并且该过程重复,直到聚类达到收敛标准。质心只是每个聚类的新平均值(例如,由平均消费为 100、200、300 以及购物篮大小为 10、15 和 20 的客户 A、B、C 组成的聚类的质心将分别为 200 和 15)。收敛标准是群集的稳定性或紧密性的度量,即任何两次迭代之间的群集内距离不会超过给定的阈值。
PySpark 不一样吗?
在我们讨论为什么是 PySpark 而不是基于 Sklearn 的算法之前,让我们讨论一下 PySpark 中的过程有何不同。使用 PySpark 构建任何聚类算法时,都需要执行一些数据转换。让我们先深入挖掘数据。用于分析的数据可以在这里找到。
数据
该数据集由超过 6 个月的 9K 活跃信用卡持卡人及其交易和账户属性组成。这个想法是为营销策略开发一个客户细分。

使用 PySpark
from pyspark.sql import SparkSessionspark = SparkSession.builder.appName(‘Clustering using K-Means’).getOrCreate()data_customer=spark.read.csv('CC General.csv', header=True, inferSchema=True)data_customer.printSchema()

图一。数据集的架构信息。图片来源——由作者使用 Jupyter 笔记本开发
自我直观的属性可以分为三大类。客户信息(主键为 CUST ID)、账户信息(余额、余额频率、购买、信用额度、使用权等)。)、交易(购买频率、付款、预付现金等。).
data_customer=data_customer.na.drop()
所有考虑中的属性都是数字或离散数字,因此我们需要使用一个矢量汇编器将它们转换成特征。矢量组合器是一个转换器,它将一组特征转换成一个单独的矢量列,通常称为特征数组。这里的特征是列。由于客户 id 是一个不会用于集群的标识符,我们首先使用提取所需的列。columns ,将其作为输入传递给 Vector Assembler,然后使用 transform ()将输入列转换成一个名为 a feature 的向量列。
from pyspark.ml.feature import VectorAssembler
data_customer.columnsassemble=VectorAssembler(inputCols=[
'BALANCE',
'BALANCE_FREQUENCY',
'PURCHASES',
'ONEOFF_PURCHASES',
'INSTALLMENTS_PURCHASES',
'CASH_ADVANCE',
'PURCHASES_FREQUENCY',
'ONEOFF_PURCHASES_FREQUENCY',
'PURCHASES_INSTALLMENTS_FREQUENCY',
'CASH_ADVANCE_FREQUENCY',
'CASH_ADVANCE_TRX',
'PURCHASES_TRX',
'CREDIT_LIMIT',
'PAYMENTS',
'MINIMUM_PAYMENTS',
'PRC_FULL_PAYMENT',
'TENURE'], outputCol='features')assembled_data=assemble.transform(data_customer)assembled_data.show(2)

图二。向量汇编程序的输出。图片来源——由作者使用 Jupyter 笔记本开发
既然所有的列都被转换成一个单一的特征向量,我们需要将数据标准化,使它们达到一个可比较的规模。例如,平衡的范围是 10-1000,而平衡频率的范围是 0-1。欧几里德距离总是受更高尺度上的变量的影响更大,因此将变量横向扩展很重要。
from pyspark.ml.feature import StandardScalerscale=StandardScaler(inputCol='features',outputCol='standardized')data_scale=scale.fit(assembled_data)
data_scale_output=data_scale.transform(assembled_data)data_scale_output.show(2)

图 3。标准缩放器的输出。图片来源——由作者使用 Jupyter 笔记本开发
现在我们的数据已经标准化了,我们可以开发 K 均值算法了。
K-means 是最常用的聚类算法之一,用于将数据分组到预定义数量的聚类中。spark.mllib 包含了一个名为 kmeans|| 的 k-means++ 方法的并行化变体。pyspark.ml.clustering 中的 KMeans 函数包括以下参数:
- k 是用户指定的聚类数
- maxIterations是聚类算法停止前的最大迭代次数。请注意,如果簇内距离的变化不超过所提到的ε值,则无论最大迭代次数是多少,迭代都将停止
- 初始化模式 指定随机初始化质心或通过 k-means||(类似于 K-means ++)初始化
- ε确定 k-means 预计收敛的距离阈值
- initialModel 是用户可以作为输入提供的一组可选的聚类质心。如果使用此参数,算法只运行一次,将点分配到其最近的质心
**train** ( k=4 , maxIterations=20 ,minDivisibleClusterSize = 1.0, seed=-1888008604 )为默认值。
from pyspark.ml.clustering import KMeans
from pyspark.ml.evaluation import ClusteringEvaluatorsilhouette_score=[]evaluator = ClusteringEvaluator(predictionCol='prediction', featuresCol='standardized', \
metricName='silhouette', distanceMeasure='squaredEuclidean')for i in range(2,10):
KMeans_algo=KMeans(featuresCol='standardized', k=i)
KMeans_fit=KMeans_algo.fit(data_scale_output)
output=KMeans_fit.transform(data_scale_output)
score=evaluator.evaluate(output)
silhouette_score.append(score)
print("Silhouette Score:",score)
可视化剪影分数。注意以前版本的 K Means 有 computeScore()来计算簇内距离的总和,但在 Spark 3.0.0 中被弃用。使用 ClusteringEvaluator()的剪影分数测量一个聚类中的每个点与相邻聚类中的点的接近程度,从而有助于找出紧凑且间隔良好的聚类。
#Visualizing the silhouette scores in a plot
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1,1, figsize =(8,6))
ax.plot(range(2,10),silhouette_score)
ax.set_xlabel(‘k’)
ax.set_ylabel(‘cost’)

图 4。由作者使用 Jupyter Notebook 开发的不同 K. Image Credits 值绘制的剪影分数输出
我更喜欢在 K=7 的情况下观察轮廓分数的局部最大值。既然 K 的什么值是好的没有正确答案,我们可以还原到描述性统计和绘图来检查客户的分布。这就是 SkLearn 在文档和 PCA 实现方面更方便的地方。我们中的大多数人更习惯于在 y 轴上用 SSE 而不是轮廓分数来研究肘图,但是 PySpark 有它的优点。
为什么是 PySpark?
PySpark 在执行 K 均值聚类时使用了数据并行性(T0)或 T2 结果并行性(T3)的概念。想象一下,你需要为墨尔本的节礼日活动推出有针对性的营销活动,你想接触到 20 万具有不同购买属性的客户。想象一下在您的本地系统上运行 K 均值的多次迭代。对于 K=5,您需要计算的距离度量的数量是 5 x 200K =百万。在满足收敛标准,即 3000 万个距离(欧几里德距离)之前,需要计算 100 万个这样的度量,比如 30 次。你需要大量的计算能力和时间来处理这样的场景。
数据并行性
数据并行的作用是,通过将数据集划分为更小的分区,从一开始就创建并行。另一方面,结果并行性基于目标集群。假设:
D =记录数量{X1,X2,…,Xn}
k =聚类数
P =处理器数量{P1,P2,…Pm}
C =初始质心{C1,C2,…。Ck}
- 数据 D 被分配给 P 个处理器。每个处理器处理一组记录(由 spark 配置决定)。初始质心值 C 由这些处理器中的每一个共享
- 现在每个处理器都有质心信息。处理器计算它们的记录到这些质心的距离,并通过将数据点分配到其最近的质心来形成局部聚类
- 一旦步骤 2 完成,P 个处理器上的这些集群中的每一个的记录的总数和计数由主进程存储以供将来参考
- 一旦一次迭代完成,来自处理器的信息被交换,并且主进程计算更新的质心,并且再次在 P 个处理器之间共享它们,即,一个点被分配给 K 个簇,主进程更新质心,并且与处理器重新共享信息
- 这个过程不断迭代,直到达到收敛。一旦满足收敛标准,主进程收集局部聚类并将它们组合成一个全局聚类
假设 200,000 条记录分布在 3 个处理器上,每个处理器有大约 70,000 条记录。这就是分布式处理发挥作用的地方,它可以减少数据量,同时确保完整的结果。
结果并行性
在结果排比中说:
D =记录数量{X1,X2,…,Xn}
k =聚类数
P =处理器数量{P1,P2,…Pm}
C =初始质心{C1,C2,…。Ck}
- 数据 D 被划分到 P 个处理器中,然后在每个处理器中进行排序。每个处理器处理一组记录(由 spark 配置决定)
- 初始质心值 C 被初始化,并在这些处理器中的每一个上划分/共享(,即,不同于在所有处理器上共享所有质心值的数据并行性,这里,我们将一个质心值传递给一个处理器
- 现在每个处理器都有一个信息质心。计算这些点到这些质心的距离。对于处理器中非常低或非常高的数据点:如果它们更靠近处理器的质心,则将它们分配到该群集,否则,如果它们更靠近属于不同处理器的质心,则将数据点移动到新处理器
- 重复此过程,直到达到收敛。返回来自处理器 P 的所有本地集群
有用的链接
- https://spark.apache.org/docs/latest/mllib-clustering.html
- https://spark . Apache . org/docs/latest/API/python/pyspark . ml lib . html # pyspark . ml lib . clustering . kmeansmodel
- https://spark . Apache . org/docs/latest/API/python/pyspark . ml . html # pyspark . ml . evaluation . clusteringevaluator
- https://spark . Apache . org/docs/latest/API/python/_ modules/py spark/ml/evaluation . html
关于作者:高级分析专家和管理顾问,帮助公司通过对组织数据的业务、技术和数学的组合找到各种问题的解决方案。一个数据科学爱好者,在这里分享、学习、贡献;可以和我在 上联系 和 推特;
k 均值解释
用 Python 解释和实现 kMeans 算法

图片由来自 Unsplash 的 Kelly Sikkema 拍摄
本文将概述对 k-Means 算法及其使用 sklearn 库的相关 python 实现的概念性理解。K-means 是一种聚类算法,在现实世界中有许多使用案例。该算法生成与数据集相关联的 K 个聚类,它可以用于不同行业的各种场景,包括模式检测、医疗诊断、股票分析、社区检测、市场分割、图像分割等。它通常用于通过将相似的数据点靠近另一个数据点进行分组(聚类)来获得对您正在处理的数据集的直觉。同一组中的数据点彼此接近且相似,而其他组中的数据点则不相似。
目录
- 什么是 k 均值聚类
- 算法
- 选择 K
-弯头法 - 优势
- 不足之处
- 履行
- 摘要
- 资源
什么是 k 均值聚类
这是一种无监督的学习算法,本质上意味着该算法从未标记的数据中学习模式。这意味着您可以训练一个模型在任何给定的数据集上创建分类,而不必先标记数据。
该算法背后的直觉是将数据点分成不同的预定义(K)聚类,其中每个聚类中的数据点将只属于该聚类。聚类将由彼此共享相似性的数据组成,这意味着不同聚类中的数据点将彼此不相似。许多其他聚类算法,如高斯混合 EM 算法、k-中值等,与 k-means 具有相同的基本观点。聚类内部的数据点应该靠近该聚类的中心[2]。

左边的图像是一组数据,右边的图像是具有可视化质心的相同数据(图像由作者提供)
算法
- 选择你的 K 值
- 随机选择 K 个数据点来代表聚类质心
- 将所有其他数据点指定给其最近的聚类质心
- 重新定位聚类质心,直到它是聚类中点的平均值
- 重复步骤 3 和 4,直到每个集群中没有任何变化
选择 K
由于该算法要求用户指定要寻找的聚类数 K,并且它不从数据中学习,所以这是使用该算法的最困难的方面之一。很难说给定的 K 值是否不正确。通常,这个值是通过广泛的领域知识和了解 k 的理想值的经验来确定的。如果这不是您当前需求的情况,那么行业中通常使用肘方法来确定 k 的理想值。
肘法
elbow 方法使用距离平方和(SSE)来根据数据点与其分配的聚类之间的距离选择 k 的理想值。我们会选择一个 k 值,在这里上证指数开始变平,我们看到一个拐点。当可视化时,这个图形看起来有点像一个肘,因此该方法的名称。

图 2:基于图 1 数据的 elbow 方法的可视化表示。肘点在 4(图片由作者提供)
上图显示k = 4可能是一个很好的集群数量选择。有些情况下,图形看起来不像弯头,这使得选择 k 的值非常困难。本文的Implementation部分提供了生成上图的代码和该算法的建模组件。
优势
- 扩展到大数据
- 总是收敛
- 通常(并非总是)比其他常见的聚类方法(如层次聚类)更快
不足之处
- 不平衡数据聚类
- 手动选择 K
- 取决于初始假设
- 高维缩放
履行
摘要
总之,k-means 是一种无监督学习算法,用于将输入数据划分为不同的预定义聚类。每个聚类将保存与其自身最相似的数据点,而不同聚类中的点将彼此不相似。这个算法最棘手的部分是选择一个理想的 K 值,这可以通过直觉或使用肘方法来完成。elbow 方法使用 SSE 来显示基于数据点与其分配的聚类之间的距离的 K be 的建议值。
资源
- [1]https://towards data science . com/k-means-clustering-algorithm-applications-evaluation-methods-and-deficies-aa 03 e 644 b 48 a
- [2]https://www . naftaliharris . com/blog/visualizing-k-means-clustering/
- [3]https://sci kit-learn . org/stable/modules/generated/sk learn . cluster . k means . html
- [4]https://jakevdp . github . io/python datascience handbook/05.11-k-means . html
这里有一些我写的其他文章,你可能会喜欢:
k-Means-机器学习算法及其在 Python 中的实现
机器学习算法— 30 天挑战
在本文中,我们将研究 K-Means 以及如何使用 Python (Scikit-learn)实现它
在本文中,我们将研究 K-Means,这是您的 ML 算法库中的另一个基本且重要的无监督机器学习算法。

图片来自 Unsplash
我们将从了解它的功能和工作原理开始。我们将不研究数学部分,因为它本身是另一篇文章。然后我们将使用scikit-learn来实现它
- 什么是 K-Means
- 它是如何工作的
- Python 实现
- K 均值中的假设
- 应用程序
- 结论
- 你能做什么
- 其他 ML 算法
这是我 30 天文章写作挑战的一部分。请随意查看我的新人帖子上的文章:
https://nouman10.medium.com/lets-publish-30-articles-in-30-days-a0b8111855bb
什么是 K-Means
K-Means 是使用最广泛和最简单的无监督聚类算法之一,它根据实例(未标记数据)之间的相似性将它们分配到不同的聚类中。
基于未标记距离之间的距离来计算相似性。K-Means 直观、易于实现、速度快。我过去曾用它通过使用聚类分配作为伪标签来微调模型,用预训练的神经网络进行无监督分类。(如果您想讨论更多内容,请随时联系我们)
它是如何工作的
K-Means 的一个缺点是我们必须预先选择聚类数( k )。这并不总是已知的,在达到一个合适的值之前,我们必须用不同的值进行实验(也没有标记来检查)。
让我们用一个直观的例子来看看算法是如何工作的。我们将把集群的数量设置为 2。假设我们有一些二维的未标记数据

未标记的二维数据(图片由作者提供)
第一步:我们需要创建质心(聚类中心),具有与数据相同的维度。
通常,为了避免较差的初始聚类,质心被选择为已经存在的数据点之一。但是我们将创建单独的质心来更好地解释这个想法

初始聚类质心(图片由作者提供)
步骤 2:将聚类分配给数据点
我们计算每个数据点和聚类质心之间的距离。数据点被分配给最靠近它的聚类质心。通常使用的距离度量是欧几里德距离,其公式如下:

欧几里德距离(图片由作者提供)
集群:

已分配群集(图片由作者提供)
第三步:我们改变聚类中心。
通过取分配给该聚类的数据点的平均值来更新聚类质心。

簇质心轻微移动(图片由作者提供)
步骤 4:重复步骤 2 和 3,直到集群停止变化
这就是 KMeans 的工作原理。在此过程中,聚类分配可能会发生变化,因为每次在步骤 3 中都会创建新的聚类质心,而这些新的分配又会改变聚类质心。
如前所述,由于质心的初始选择不理想,KMeans 可能会产生一些非常差的结果。因此,我们必须用不同的初始质心重复这个过程,并选择簇间变化最小的结果
Python 实现
让我们从在一些虚拟数据上实现 KMeans 开始。我们首先使用scikit-learn创建一些虚拟数据,并绘制它。
make_blobs函数为我们创建数据。要想得到和我一样的数据,一定要保持上面提到的random_state。这将像这样绘制数据:

虚拟数据(图片由作者提供)
如您所见,有三个可见的集群,因为我们已经将其传递给了make_blobs函数。但是在真实数据的情况下,可视化可以帮助估计聚类数量的值
现在让我们应用scikit-learn中的KMeans,用不同的颜色绘制集群分配
我们将从初始化KMeans开始,并使其符合我们的数据。然后我们通过预测数据得到我们的聚类分配。为了绘制数据,我们需要计算分配给各个聚类的聚类点。我们通过提取每个聚类分配的索引并从数据中提取来选择数据点。这导致了下面的图:

聚类分配(图片由作者提供)
这是我们可以看到不同颜色的集群的结果
K 均值中的假设
导致 KMeans 聚类不准确的原因有很多。这些原因包括:
- 簇的数量不正确
- 各向异性分布数据(在不同方向上具有不同属性的数据)
- 不同方差
- 大小不均匀的斑点
我们将使用来自 sklearn 网站的代码来演示这一点
这将导致以下情节:

作者图片
应用程序
- 文档聚类
- 确定犯罪多发地区
- 客户细分,
- 保险欺诈检测
- 公共交通数据分析
- IT 警报的群集
结论
让我们总结一下本文所做的工作:
- 我们从 K-Means 如何工作的一般解释开始
- 然后,我们在一些虚拟数据上用 Python 实现了它,并绘制了结果聚类图
- 然后,我们研究了 KMeans 的一些假设及其应用。
您可以做什么:
- 尝试从零开始实现 K-Means。
- 将您的实现与
scikit-learn中的实现进行比较 - 在各种其他数据集上测试上面的代码。
如果你有任何问题,请随时联系我。请继续关注我,因为我计划在未来讲述更多的机器学习算法
其他 ML 算法:
- 线性回归——用 Python 实现的机器学习算法
https://medium.com/mlearning-ai/linear-regression-a-to-z-2ab3d1b7277c
- k-最近邻——机器学习算法及其 Python 实现
https://nouman10.medium.com/k-nearest-neighbors-a-to-z-with-implementation-in-python-74630ffb79a2
- 决策树——机器学习算法及其 Python 实现
如果您觉得以上内容对您有用,请分享并随时支持我-->
意思是为了乐趣和利益的诡计
K-Means 是一个有趣、简单、非常直观的算法。事实证明,它可以做的不仅仅是集群。
序言
这将是一个非常小的帖子,但仍然是一个有趣的帖子。
K-Means 是一个优雅的算法。这很容易理解(制造随机点,反复移动它们以成为一些现有集群的中心),并且在实践中工作得很好。当我第一次了解它的时候,我记得我很着迷。很优雅。但是,随着时间的推移,这种兴趣逐渐消失,我注意到了许多限制,其中之一是球形簇先验,它的线性性质,我发现在 EDA 场景中特别令人讨厌的是,它不会自己找到最佳的簇数,所以你也需要修改这个参数。然后,几年前,我发现了一些如何使用 K-Means 的巧妙技巧。所以开始了。
第一招
首先,我们需要建立一个基线。我将主要使用乳腺癌数据集,但是您可以使用任何其他数据集。
from sklearn.cluster import KMeans
from sklearn.svm import LinearSVC
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_splitimport numpy as np X, y = load_breast_cancer(return_X_y=True)X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=17)svm = LinearSVC(random_state=17)
svm.fit(X_train, y_train)
svm.score(X_test, y_test) **# should be ~0.93**
那么,是什么让我重新对 K-Means 产生了兴趣呢?
K-Means 可以作为新特征的来源。
你可能会问,怎么做?K-Means 是一种聚类算法,对吧?您可以添加推断聚类作为新的分类特征。
现在,让我们试试这个。
# imports from the example abovesvm = LinearSVC(random_state=17)
kmeans = KMeans(n_clusters=3, random_state=17)X_clusters = kmeans.fit_predict(X_train).reshape(-1, 1)svm.fit(np.hstack([X_train, X_clusters]), y_train)
svm.score(np.hstack([X_test, kmeans.predict(X_test) \
.reshape(-1, 1)]), y_test) **# should be ~0.937**

【knowyourmeme.com】来源:T4
这些特征是分类的,但是我们可以要求模型输出到所有质心的距离,从而获得(希望)更多的信息特征。
# imports from the example abovesvm = LinearSVC(random_state=17)
kmeans = KMeans(n_clusters=3, random_state=17)X_clusters = kmeans.fit_transform(X_train)
# ^^^^^^^^^
# Notice the `transform` instead of `predict`
# Scikit-learn supports this method as early as version 0.15svm.fit(np.hstack([X_train, X_clusters]), y_train)
svm.score(np.hstack([X_test, kmeans.transform(X_test)]), y_test)
**# should be ~0.727**
等等,怎么了?现有的特征和到质心的距离之间有关联吗?
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pdcolumns = ['mean radius', 'mean texture', 'mean perimeter', 'mean area', 'mean smoothness', 'mean compactness', 'mean concavity', 'mean concave points', 'mean symmetry', 'mean fractal dimension', 'radius error', 'texture error', 'perimeter error', 'area error', 'smoothness error', 'compactness error', 'concavity error', 'concave points error', 'symmetry error', 'fractal dimension error', 'worst radius', 'worst texture', 'worst perimeter', 'worst area', 'worst smoothness', 'worst compactness', 'worst concavity', 'worst concave points', 'worst symmetry', 'worst fractal dimension', **'distance to cluster 1', 'distance to cluster 2', 'distance to cluster 3'**]data = pd.DataFrame.from_records(np.hstack([X_train, X_clusters]), columns=columns)sns.heatmap(data.corr())
plt.xticks(rotation=-45)
plt.show()

注意最后 3 列,尤其是最后一列,以及它们在每一行的颜色。来源:帖子作者,见上面代码片段生成。
您可能听说过我们希望数据集中的要素尽可能独立。原因是很多机器学习模型假设这种独立性是为了有更简单的算法。关于这个主题的更多信息可以在这里和这里找到,但它的要点是,在线性模型中有冗余信息会使模型不稳定,反过来,它更有可能搞砸。在许多情况下,我注意到了这个问题,有时甚至是非线性模型,清除数据集的相关特征通常会略微提高模型的性能特征。
回到我们的主题。假设我们的新特征确实与一些现有的特征相关,那么如果我们只使用到聚类均值的距离作为特征,这是否可行呢?
# imports from the example abovesvm = LinearSVC(random_state=17)
kmeans = KMeans(n_clusters=3, random_state=17)
X_clusters = kmeans.fit_transform(X_train)svm.fit(X_clusters, y_train)
svm.score(kmeans.transform(X_test), y_test) **# should be ~0.951**
好多了。通过这个例子,你可以看到我们可以使用 K-Means 作为降维的方法。干净利落。
到目前为止一切顺利。但是抵抗的部分还没有出现。
第二招
K-Means 可以作为内核技巧的替代品
你没听错。例如,你可以为 K-Means 算法定义比特征更多的质心。
# imports from the example abovesvm = LinearSVC(random_state=17)
kmeans = KMeans(n_clusters=250, random_state=17)
X_clusters = kmeans.fit_transform(X_train)svm.fit(X_clusters, y_train)
svm.score(kmeans.transform(X_test), y_test) **# should be ~0.944**
嗯,没那么好,但是相当不错。在实践中,这种方法的最大好处是当您拥有大量数据时。此外,在预测性能方面,您的收获可能会有所不同,我曾经用n_clusters=1000运行过这种方法,它比只使用几个集群效果更好。
众所周知,支持向量机在大数据集上训练很慢。极其缓慢。去过那里,做过那个。这就是为什么,举例来说,有许多技术可以用少得多的计算资源来近似内核技巧。
顺便说一下,让我们比较一下这个 K-Means 技巧与经典的 SVM 和一些替代的核近似方法的效果。
以下代码的灵感来自于这 两个 scikit-learn 示例。
import matplotlib.pyplot as pltimport numpy as npfrom time import timefrom sklearn.datasets import load_breast_cancerfrom sklearn.svm import LinearSVC, SVC
from sklearn import pipeline
from sklearn.kernel_approximation import RBFSampler, Nystroem, PolynomialCountSketch
from sklearn.preprocessing import MinMaxScaler, Normalizer
from sklearn.model_selection import train_test_split
from sklearn.cluster import MiniBatchKMeans mm = pipeline.make_pipeline(MinMaxScaler(), Normalizer())X, y = load_breast_cancer(return_X_y=True)
X = mm.fit_transform(X)data_train, data_test, targets_train, targets_test = train_test_split(X, y, random_state=17)
我们将测试 scikit-learn 包中可用的 3 种内核近似方法,与 K-Means 技巧相对比,作为基线,我们将有一个线性 SVM 和一个使用内核技巧的 SVM。
# Create a classifier: a support vector classifier
kernel_svm = SVC(gamma=.2, random_state=17)
linear_svm = LinearSVC(random_state=17)# create pipeline from kernel approximation and linear svm
feature_map_fourier = RBFSampler(gamma=.2, random_state=17)
feature_map_nystroem = Nystroem(gamma=.2, random_state=17)
feature_map_poly_cm = PolynomialCountSketch(degree=4, random_state=17)
feature_map_kmeans = MiniBatchKMeans(random_state=17)fourier_approx_svm = pipeline.Pipeline([("feature_map", feature_map_fourier), ("svm", LinearSVC(random_state=17))])nystroem_approx_svm = pipeline.Pipeline([("feature_map", feature_map_nystroem), ("svm", LinearSVC(random_state=17))])poly_cm_approx_svm = pipeline.Pipeline([("feature_map", feature_map_poly_cm), ("svm", LinearSVC(random_state=17))])kmeans_approx_svm = pipeline.Pipeline([("feature_map", feature_map_kmeans), ("svm", LinearSVC(random_state=17))])
让我们收集每种配置的计时和评分结果。
# fit and predict using linear and kernel svm:
kernel_svm_time = time()
kernel_svm.fit(data_train, targets_train)
kernel_svm_score = kernel_svm.score(data_test, targets_test)
kernel_svm_time = time() - kernel_svm_timelinear_svm_time = time()
linear_svm.fit(data_train, targets_train)
linear_svm_score = linear_svm.score(data_test, targets_test)
linear_svm_time = time() - linear_svm_timesample_sizes = 30 * np.arange(1, 10)
fourier_scores = []
nystroem_scores = []
poly_cm_scores = []
kmeans_scores = []fourier_times = []
nystroem_times = []
poly_cm_times = []
kmeans_times = []for D in sample_sizes:
fourier_approx_svm.set_params(feature_map__n_components=D)
nystroem_approx_svm.set_params(feature_map__n_components=D)
poly_cm_approx_svm.set_params(feature_map__n_components=D)
kmeans_approx_svm.set_params(feature_map__n_clusters=D) start = time()
nystroem_approx_svm.fit(data_train, targets_train)
nystroem_times.append(time() - start) start = time()
fourier_approx_svm.fit(data_train, targets_train)
fourier_times.append(time() - start) start = time()
poly_cm_approx_svm.fit(data_train, targets_train)
poly_cm_times.append(time() - start) start = time()
kmeans_approx_svm.fit(data_train, targets_train
kmeans_times.append(time() - start) fourier_score = fourier_approx_svm.score(data_test, targets_test)
fourier_scores.append(fourier_score) nystroem_score = nystroem_approx_svm.score(data_test, targets_test)
nystroem_scores.append(nystroem_score) poly_cm_score = poly_cm_approx_svm.score(data_test, targets_test)
poly_cm_scores.append(poly_cm_score) kmeans_score = kmeans_approx_svm.score(data_test, targets_test)
kmeans_scores.append(kmeans_score)
现在让我们绘制所有收集的结果。
plt.figure(figsize=(16, 4))
accuracy = plt.subplot(211)
timescale = plt.subplot(212)accuracy.plot(sample_sizes, nystroem_scores, label="Nystroem approx. kernel")
timescale.plot(sample_sizes, nystroem_times, '--', label='Nystroem approx. kernel')
accuracy.plot(sample_sizes, fourier_scores, label="Fourier approx. kernel")
timescale.plot(sample_sizes, fourier_times, '--', label='Fourier approx. kernel')
accuracy.plot(sample_sizes, poly_cm_scores, label="Polynomial Count-Min approx. kernel")
timescale.plot(sample_sizes, poly_cm_times, '--', label='Polynomial Count-Min approx. kernel')
accuracy.plot(sample_sizes, kmeans_scores, label="K-Means approx. kernel")
timescale.plot(sample_sizes, kmeans_times, '--', label='K-Means approx. kernel')# horizontal lines for exact rbf and linear kernels:
accuracy.plot([sample_sizes[0], sample_sizes[-1]],
[linear_svm_score, linear_svm_score], label="linear svm")
timescale.plot([sample_sizes[0], sample_sizes[-1]], [linear_svm_time, linear_svm_time], '--', label='linear svm')accuracy.plot([sample_sizes[0], sample_sizes[-1]],
[kernel_svm_score, kernel_svm_score], label="rbf svm")
timescale.plot([sample_sizes[0], sample_sizes[-1]], [kernel_svm_time, kernel_svm_time], '--', label='rbf svm')
和一些更多的情节调整,使它漂亮。
# legends and labels
accuracy.set_title("Classification accuracy")
timescale.set_title("Training times")
accuracy.set_xlim(sample_sizes[0], sample_sizes[-1])
accuracy.set_xticks(())
accuracy.set_ylim(np.min(fourier_scores), 1)
timescale.set_xlabel("Sampling steps = transformed feature dimension")
accuracy.set_ylabel("Classification accuracy")
timescale.set_ylabel("Training time in seconds")
accuracy.legend(loc='best')
timescale.legend(loc='best')
plt.tight_layout()
plt.show()

咩。这一切都是徒劳的吗?来源:帖子作者,见上面代码片段生成。
你猜怎么着一点也不。即使它是最慢的,K-Means 作为 RBF 核的近似仍然是一个好的选择。我没开玩笑。你可以在 scikit-learn 中使用这种特殊的 K-Means,称为MiniBatchKMeans,它是少数支持.partial_fit方法的算法之一。将这与也有.partial_fit的机器学习模型结合起来,就像PassiveAggressiveClassifier一样,可以创建一个非常有趣的解决方案。
注意,.partial_fit的妙处是双重的。首先,它使得以核外方式训练算法成为可能,也就是说,使用比 RAM 中所能容纳的更多的数据。其次,根据您的问题类型,如果您原则上(原则上非常非常)不需要切换模型,那么可以在部署模型的地方对其进行额外的培训。那叫在线学习,超级有意思。类似这样的事情是一些中国公司正在做的,一般来说对广告技术非常有用,因为你可以在几秒钟内收到你的广告推荐是对还是错的信息。
你知道吗,这里有一个关于这种方法的小例子。
from sklearn.cluster import MiniBatchKMeans
from sklearn.linear_model import PassiveAggressiveClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancerimport numpy as np def batch(iterable, n=1):
# source: [https://stackoverflow.com/a/8290508/5428334](https://stackoverflow.com/a/8290508/5428334)
l = len(iterable)
for ndx in range(0, l, n):
yield iterable[ndx:min(ndx + n, l)]X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=17)kmeans = MiniBatchKMeans(n_clusters=100, random_state=17)
# K-Means has a constraint, n_clusters <= n_samples to fit
pac = PassiveAggressiveClassifier(random_state=17)for x, y in zip(batch(X_train, n=100), batch(y_train, n=100)):
kmeans.partial_fit(x, y) # fit K-Means a bit
x_dist = kmeans.transform(x) # obtain distances
pac.partial_fit(x_dist, y, classes=[0, 1])
# learn a bit the classifier, we need to indicate the classes print(pac.score(kmeans.transform(X_test), y_test))
**# 0.909 after 100 samples
# 0.951 after 200 samples
# 0.951 after 300 samples
# 0.944 after 400 samples
# 0.902 after 426 samples**# VSkmeans = MiniBatchKMeans(n_clusters=100, random_state=17)
pac = PassiveAggressiveClassifier(random_state=17)pac.fit(kmeans.fit_transform(X_train), y_train)
pac.score(kmeans.transform(X_test), y_test) **# should be ~0.951**
收场白
所以你坚持到了最后。希望现在你的 ML 工具集更丰富了。也许你听说过所谓的“没有免费的午餐”定理;基本上,没有银弹,在这种情况下,对于 ML 问题。也许对于下一个项目,这篇文章中概述的方法不会起作用,但是对于接下来的一个项目,它们会起作用。所以你就自己去实验看看吧。如果你需要一个在线学习算法/方法,那么,K-Means 作为一个内核近似,更有可能是你的正确工具。
顺便说一句,还有另一篇博客文章,也是关于 ML 的,正在撰写中。更好的是,在它的许多其他优点中,它描述了一种相当有趣的使用 K-Means 的方法。但是现在没有剧透。敬请关注。
最后,如果你正在读这篇文章,谢谢你!如果你想留下一些反馈或只是有一个问题,HMU 在 Twitter 上,或只是留下评论。
一些你可能会感兴趣的链接
承认
特别感谢 @dgaponcic 的风格检查和内容审核,也感谢@ anisara _ ionela比任何人工智能更彻底地检查了这篇文章的语法。你是最好的❤
附言我相信你已经注意到准则中的所有这些random_state。如果你想知道我为什么添加这些,那是为了使代码样本可重复。因为教程经常不这样做,这给作者留下了挑选的空间,作者只给出最好的结果,当试图复制这些结果时,读者要么不能,要么要花很多时间。但是要知道,你可以随意改变random_state的值,得到非常不同的结果。例如,当使用原始特征和到 3 个质心的距离运行代码片段时,得分为 0.727,随机种子为 41 而不是 17,您可以获得 0.944 的精度得分。所以,是的,random_state无论你选择的框架中随机种子是什么,这都是要记住的一个重要方面,尤其是在做研究的时候。
原载于 2021 年 6 月 19 日https://alexandruburlacu . github . io。
K-最近邻(K-NN)解释

K-NN (k=1)对 K-NN (k=9)分类器(所有图像均由作者生成)
一个简单但强大的算法背后的直觉
我已经决定创建一个 Python 库,只使用 NumPy 和 SciPy 来实现流行的机器学习算法。目的不是创建一个生产就绪的库,而是以一种易于阅读的方式编写这些算法,并在解释算法如何工作的文章中使用它们。我在项目中的第一步是我的 PCA 文章,我现在已经将它合并到项目回购中。考虑到我现在有多忙,我为下一步采取了一个相对简单的算法;K-最近邻。虽然 K-NN 很简单,但在适当的情况下,它可以有惊人的预测准确性。该类的代码在文章的底部,repo 中包含本文使用的所有代码的文件夹在这里是。
K-NN 简介
K-NN 是一种简单的算法,可能是学习机器学习的人最先遇到的算法之一。您只需找到最近的 k 个数据点,并使用它们的标签来预测新数据点的标签。这里, k 是一些小于或等于数据点数的正整数。最佳的 k 通常通过交叉验证来选择。较低的 k 值 给出更灵活的模型,而较高的 k 值 给出更不灵活的模型。 k 的最优值取决于数据生成过程的灵活程度和你拥有的数据量。
K-NN 是非参数模型。它没有对数据生成过程的模型做任何假设。它不学习任何参数,不像线性模型必须“学习”系数。这给了它一些优于结构化模型的优点和缺点。
K-NN 的中心思想是寻找接近新点的点,并聚集接近点的标签来预测新点。我喜欢这种简单。
强项
- 对数据生成过程不做任何假设,因此它可以适应灵活的模型。
- “训练”模型与保存数据一样快,因为它不需要估计参数。
- 解释和实现都很简单。
弱点
- 对数据生成过程不做任何假设,这可能导致在没有足够的训练观测值的情况下过度拟合,或者导致 k 值太小。
- 数据集必须存储在模型可以访问的位置,对于大型数据集,这可能会占用大量内存。
- 与参数模型相比,进行预测相对较慢,因为它需要计算到训练数据点的距离,对它们进行排序,检索 k 个最近点,然后进行预测。
- K-NN 是维数灾难的受害者;它在数据点非常分散的高维情况下表现不佳。
- K-NN 对于在特征空间中展开的观察有困难。
- K-NN 对异常值很敏感。
上面的一些优点和缺点是一个硬币的两面,例如它的灵活性和“训练”速度,但使用内存高,预测速度慢。也就是说,当我有足够的数据点时,这通常是我在预测问题上尝试的头几个算法,看起来它们可能是非常非线性的。如果有许多维度,我通常使用降维技术,如主成分分析,在建模之前找到数据的较低维度表示。
将优点和缺点总结到使用 K-NN 的决策过程中,对于具有许多观察值的非线性函数来说,这是一个很好的选择,而当没有太多数据并且数据生成函数不需要太多灵活性时,这是一个很差的选择。
K-NN 算法
K-NN 算法非常简单,前五个步骤对于分类和回归都是相同的。
1。选择 k 和加权方法
选择一个值 k ,它是为进行预测而检索的最近邻的数量。加权方法的两种选择是均匀加权和反距离加权。使用统一加权时,不考虑新数据点与其最近的 k 点之间的距离。它们对预测都有同等的影响。使用反距离加权,可以为距离较近的训练示例分配较高的权重。
您通常会尝试交叉验证中的各种 k 值和加权方法,并选择交叉验证损失最低的 k 和加权方法。
2。“训练”K-NN 模型
如上所述,在这个模型中没有要估计的参数。您只需保存训练数据以进行预测。
3。传递预测数据
只需给你的模型传递一个新的数据点来预测。
4。计算距离
到目前为止,我说的是“最近的”,但没有定义我的意思。有多种距离度量,我不会一一介绍。我将要介绍的是最常见的一种;欧几里德距离。欧几里得距离就是连接两点的线段的长度。两点之间的欧几里德距离公式如下:

其中 x* 是新数据点的特征向量, x 是单个训练数据点的特征向量, m 是用于预测的特征数。
使用您选择的度量计算新数据点与每个训练数据点之间的距离,并临时保存该距离以供下一步使用。
5。寻找 K 个最近的邻居
一旦知道了每个训练观察与新数据点之间的距离,就可以根据它们与新数据点之间的距离对数据点进行排序。然后选择距离最小的 k 个数据点。在我的实现中,我使用了 quicksort 对距离进行排序。
您现在已经在训练数据中找到了与您的新数据点最近的 k ,并且可以使用它们的标签进行预测。
6。预测
这是分类和回归的算法步骤的分歧之处。
回归
对于回归,你对最近的 k 训练数据点的标签进行平均,并将其用于最新数据点的预测。如果使用统一加权,这是标签的简单平均值。如果使用反距离加权,则计算训练标注的加权平均值,通过第 I 个最近邻的标注与新数据点的距离的倒数对其进行加权。这使得较近的点对预测标签的影响更大。如果距离为 0,权重将是未定义的,因为不能除以 0。为了在我的实现中解决这个问题,我给出了向距离添加一个小值的选项。这仍然导致距离为 0 的点在预测标注上具有非常大的权重。
分类
对于分类,使用训练标签的多数投票(对于二元分类)或多数投票(对于多类)来预测新标签。为了避免 50-50 的投票分裂,最好对使用奇数。一个类别的投票比例可以解释为新数据点属于该类别的概率。就像在回归的情况下,你可以通过它们距离的倒数来加权每一个 k 最近邻居的投票,以给予更近的点更多的影响。
演示 K-NN
现在我们已经介绍了算法的工作原理,我已经模拟了一个多类预测问题和两个回归问题的一些数据,以展示 K-NN 如何在具有各种值 k 和加权方法的简单问题中执行。先说分类。
分类演示
为了演示用于分类的 K-NN,我模拟了来自 3 个类的 100 个数据点。利用模拟数据,我们可以将不同的模型与实际情况进行比较。每个类都由它自己的二元正态分布参数化。1 类用蓝色表示,2 类用红色表示,3 类用绿色表示。

同一协方差矩阵,每一类的均值是不同的。这是线性判别分析的理想情况,但我们只是使用该知识来绘制贝叶斯分类器的边界。

背景颜色之间的变化表示贝叶斯决策边界。它是线性的,但像素使它看起来参差不齐。我们希望 K-NN 模型尽可能地接近这一点。我训练了八个 K-NN 模型,K 值分别为 1、3、9 和 15,使用的是均匀和反距离加权。他们的决策空间图如下。

当 k 等于 1 并且在较小程度上等于 3 时,K-NN 模型具有过于灵活的决策边界。有一些分配给一个类的特征空间被另一个类包围着,这是没有意义的。具有等于 9 和 15 的 k 的模型的决策空间看起来更接近真实的决策边界。
这演示了与参数 k 的权衡。过低,模型会过于灵活;会超负荷的。反之亦然;a k 太高,模型太不灵活,这些都会在回归演示中表现出来。这是偏差-方差权衡的一个例子。
回归演示
为了演示回归的 K-NN,我做了两个场景;一个是 K-NN 表现良好的地方,另一个是表现不佳的地方。前一种情况涉及对具有许多训练观察值的非线性函数使用 K-NN 回归。后者涉及对具有少量训练观察值的线性函数使用 K-NN 回归。在后一种情况下,K-NN 会失败,因为数据点太少,无法填充特征可以采用的值的范围。有了更多的数据,K-NN 回归模型用一个精心选择的 k 值可以逼近线性函数以及非线性函数。
具有许多观察值的非线性函数
为了演示 K-NN 回归,在这种情况下,我模拟了来自标准正态分布的 10,000 次抽取,作为用于预测的特征。然后,我使用下面的等式从模拟特征生成标签。

因为我们知道真实模型是具有正态分布误差的三次多项式,所以我们知道带有二次和三次项的普通最小二乘回归将是我们对真实模型的最佳估计。在绘制数据和不了解事实真相的情况下,我们可能会得出同样的结论。让我们忽略这一点,专注于 K-NN 回归。
接下来,我使用 1、5、10 和 10,000 的 k 值拟合八个 K-NN 模型,同时使用均匀和反距离加权。我在数据散点图的顶部绘制了 K-NN 模型与真实数据生成函数的关系。正如您在下面看到的,在 k = 1 时,模型会在真实线附近反弹,因为它过度适应训练数据。当 k 为 5 时变得更平滑,当 k =10 时变得更平滑。当 k 等于训练数据中的观察数量时,标签的平均值被预测。如你所见,使用反距离加权有助于模型拟合尾部,数据更稀疏,更好。K-NN 有外推超出训练数据中的值范围的问题,尽管这不是 K-NN 独有的。在由训练数据填充的特征空间中的区域之外进行预测通常是不好的。

总的来说,K-NN 模型看起来对等于 5 和 10 的 k 表现良好,具有反距离加权。我们来看一个 K-NN 表现不佳的案例。
具有少量观测值的线性函数
为了创建一个 K-NN 回归表现不佳的案例,我只从标准正态分布中抽取了 100 个值作为预测值。数据生成过程如下:

如您所见,K-NN 模型对于所有尝试的 k 的值都是过拟合的,除了当 k 等于具有统一权重的观察值的数量时,在这种情况下,它仅预测训练标签的平均值。尽管数据生成过程很简单,但是由于训练样本的数量,K-NN 不能很好地逼近它。

结论
我希望您现在对 K-NN 的工作原理有了一个很好的了解。此外,我希望我已经在建模时交流了灵活性的好处和缺点,或者称为偏差-方差权衡。当相对于预测器的数量有许多样本时,K-NN 等灵活的模型可以通过允许模型更自由地拟合数据来帮助提高预测准确性。当数据点很少时,您最好在模型上强加结构。
K-NN 分类代码
k-最近邻(kNN)-如何使用监督学习进行质量预测?
机器学习
使用 kNN 解决回归和分类问题的综合指南

k 近邻(kNN)机器学习算法。图片由作者提供。
简介
本文是深入研究不同机器学习算法的系列文章的继续。如果您对数据科学感兴趣,并且希望更好地理解 kNN 算法,或者如果您需要用 Python 构建自己的 ML 模型的指南,请继续阅读。
内容
- kNN 所属的算法类别
- kNN 工作原理的直观解释
- 一个完整的 Python 示例,展示了 kNN 在真实数据中的使用
kNN 属于哪一类算法?
有这么多的机器学习算法,可能永远不可能将它们全部收集和分类。然而,我已经尝试对一些最常用的进行了测试,你可以在下面的交互式旭日图中找到。确保点击👇在不同的类别上对进行放大并揭示更多的。
机器学习算法分类。由作者创建的互动图表。
如果你喜欢数据科学和机器学习 ,请 订阅 每当我发布一个新故事时,你都会收到一封电子邮件。
从上图可以看出,k-Nearest Neighbors 属于机器学习算法的监督分支,这意味着它需要有标签的数据进行训练。
但是,假设你只想找到相似的数据点(即找到邻居),而不是进行预测。那样的话,就有可能以无监督的方式使用 kNN(参见 sklearn 的nearest neighbors实现这种无监督的学习器)。
值得注意的是,kNN 是一种非常灵活的算法,可以用来解决不同类型的问题。因此,在本文中,我将带您了解它在分类和回归中的用法。
kNN 是如何工作的?
让我们从 kNN 中的“k”开始。由于算法是基于最近的邻居进行预测的,所以我们需要告诉算法我们想要考虑的邻居的确切数量。因此,“k”代表邻居的数量,只是一个我们可以调整的超参数。
现在让我们假设我们选择了 k=5,并且我们有一个包含房屋大小(平方英尺)、房屋建造年份和房价的数据集。我们希望在这些数据上训练 kNN,然后用它来预测我们感兴趣的另一所房子的价格。

运行中的 kNN 算法。图片由作者提供。
在上图中,黑色圆圈代表一个新的数据点(我们感兴趣的房子)。因为我们已经设置 k=5,所以该算法找到这个新点的五个最近的邻居。
注意,通常使用欧几里德距离,但是一些实现允许替代的距离度量(例如,曼哈顿)。
找到邻域后,根据您是执行分类分析还是回归分析,将会发生以下两种情况之一。
- 分类:该算法使用简单多数投票将标签分配给新的数据点。在我们的例子中,大多数由 3 个价格为 100 万美元的邻居组成。因此,新数据点的预测标签是< $1M。
- 回归:算法计算所有邻居的平均值。在我们的示例中,这将是:($90 万+ $95 万+ \(98 万+\) 100 万+$ 110 万)/5 = $ 98.6 万。所以,房子的预测价格(新数据点)是 986K 美元。
从这个例子中可以看出,kNN 是一个非常直观的算法,很容易解释预测是如何进行的。因此,它与 RandomForest 或 XGBoost 等其他分类和回归算法形成对比。
最后要补充的是,上面的解释说明了使用统一砝码时会发生什么。即,每个邻居在计算中携带相同的权重。但是,在某些情况下(例如,当您有稀疏数据时),使用基于距离的权重可能是有益的。
距离权重分配的权重与距查询点的距离成反比,这意味着距离数据点较近的相邻要素比距离较远的相邻要素具有更大的权重。
kNN 在现实生活数据中使用的 Python 示例
现在让我们看一个 Python 例子,这样您就可以看到如何在实践中使用 kNN。
设置
我们将使用以下数据和库:
- Kaggle 的房价数据
- Scikit-learn libraryfor
1)特征缩放(minmax scaler);
2)分类变量的编码(OrdinalEncoder);
3)执行 kNN 分类(KNeighborsClassifier);
4)进行 kNN 回归(KNeighborsRegressor);
5)模型评估(分类 _ 报告) - 用于数据可视化的 Plotly 和 Matplotlib
- 熊猫和 NumPy 进行数据操作
让我们导入所有的库:
接下来,我们下载并接收将在 kNN 模型中使用的数据。
(来源:https://www . ka ggle . com/quant Bruce/real-estate-price-prediction?select = Real+estate . CSV)

我们将在模型中使用以下数据字段:
- 特征(自变量):‘X5 纬度’,‘X6 经度’,‘X2 宅龄’
- 目标(因变量): 'Y 单位面积房价'注意,我们将使用原始字段进行回归,并创建一个带状版本用于分类。
我们的目标是预测给定坐标和年龄的房屋的单位面积价格。但是,首先,让我们创建一个新的变量作为分类模型的目标。下面是‘Y 单位面积房价’的分布:

显示“单位面积 Y 房价”字段分布的直方图。图片由作者提供。
我们可以任意选择对我们有意义的波段,例如 0–20、20–40、40–60、60–80 和 80+。但是,这将创建包含不同数量观测值的波段。例如,我们在(40–60)范围内有 171 个观察值,而在(60–80)范围内只有 18 个观察值。
由于 kNN 分类依赖于多数投票,拥有不平衡的数据将使算法很难选择除多数类之外的任何其他类。由于这个原因,我们将创建三个平衡波段,而不是将观察值分组为单位面积价格最低的 33%、中间的 33%和最高的 33%。

带有新的“价格范围”字段的房价数据将用于分类。图片由作者提供。
最后,在开始训练模型之前,让我们在 3D 图上绘制观察结果以可视化数据。
房屋数据的交互式 3D 散点图。图表作者作者。
像这样的可视化效果非常好,因为它们让我们可以立即看到数据中的模式。
绿点(价格区间底部 33%的房屋)分布在更广的区域(经度-纬度方向),表明它们离中心位置更远,导致价格更低。
同时,蓝色(中间 33%)和红色(顶部 33%)点可以在同一位置找到,但在年龄上有显著差异。蓝色往往更老(因此更便宜),而红色往往更新(更贵)。
kNN 分类和回归
下面我提供了一大块代码,它完成了从特征缩放到模型训练和结果生成的所有工作。让我详细说明一下每一步:
步骤 1——特征缩放。因为 kNN 依赖于计算点之间的距离,所以确保我们的特征使用一致的比例是很重要的。否则,规模较小的将占主导地位,规模较大的将几乎没有影响。这里我们使用 MinMaxScaler() ,它保持底层分布不变,但将比例范围更改为 0 到 1。
此外,我们的分类模型的目标值为['底部 33 ','中间 33 ',和'顶部 33']。由于 sklearn 的实现要求目标标签为数字,因此我们使用 OrdinalEncoder() 将其转换为[0,1,2]。
步骤 2——训练/测试样本。我们现在需要将数据分成训练和测试样本,这是在 train_test_split 函数的帮助下完成的。
我们还准备了两个独立的目标阵列。“yC”包含基于编码价格带的分类模型的目标,而“yR”包含基于原始房屋单位面积价格的回归模型的目标。
第三步——模型设置。在这里,我们建立模型并调整超参数。请注意,我们有两个独立的模型,一个用于分类,另一个用于回归。
正如我们之前所了解到的,它们本质上是相同的,只是在基于之前确定的最近邻计算预测时,在最后部分有所不同。在这种情况下,我们选择 n_neighbors ("k") 等于 5,并将权重设置为“统一”,给每个邻居一个相等的权重。
步骤 4——培训。我们使用训练数据和它们独特的训练目标阵列来训练这两个模型。
步骤 5—预测。模型训练完成后,我们使用它们来预测训练和测试数据的分类标签和回归值。
第六步 —绩效总结。我们生成并打印性能指标来评估我们的模型。
以上代码打印了以下模型结果:

具有统一权重的 kNN 模型结果。图片由作者提供。
如您所见,分类模型的性能相当好,测试和训练数据的准确率分别为 0.84 和 0.82。同时,回归模型在两个数据集上都产生了 0.75 的准确度分数(R)。
现在,让我们看看当我们将权重从“统一”改为“距离”时会发生什么,即,给予更近的邻居更高的权重。
注意,我们使用完全相同的 Python 代码,除了在两个模型中将 weights='uniform '改为 weights='distance' 。
结果如下:

具有距离调整权重的 kNN 模型结果。图片来自作者。
我们可以在分类(0.98)和回归(0.99)的训练数据上看到模型性能的显著提高。然而,使用基于距离的加权对模型的泛化能力产生了负面影响,在测试数据上,分类性能下降到 0.81,回归性能下降到 0.73。
奖金代码
有时,我们还想知道训练集中的哪些数据点是我们通过测试集传入的数据点的邻居。您可以使用 kneighbors() 方法找出答案,该方法返回到每个“k”邻居的距离和索引。

测试记录的邻居指数(k=5)。图片由作者提供。
然而,需要注意的是, kneighbors() 方法返回的索引引用了训练数据集中观察值的索引号。因此,如果您想找到测试数据中第一个观察值的邻居,您需要在训练数据集中查找索引为 330、122、40、44 和 140 的记录。不要将该索引与原始数据框中的索引混淆。
作为存储模型预测和邻居索引的一种方式,我编写了以下代码,将训练和测试数据合并到一个数据框中,同时保留 training_index 编号,以便您可以快速识别每个测试记录的邻居。它还保留预测标签和预测值。

包含模型预测和邻域索引的最终数据框。图片由作者提供。
此外,我们现在可以使用上述数据框在 3D 图上绘制我们的模型预测,并直观地将其与原始数据进行比较。
带有模型预测的交互式 3D 散点图。图表作者作者。
3D 图直观地证实了我们在模型评估总结中看到的良好结果。
结论
当谈到机器学习时,可解释性通常与模型的预测能力一样重要。因此,如果你正在寻找一个易于解释的算法,你可以向你的利益相关者解释,那么 kNN 可能是一个不错的选择。
但是,不要忘记缩放您的要素并尝试不同的超参数组合,因为 k=5 和 weight =“uniform”的默认值可能不适合您的数据。
我希望这篇文章对您有所帮助,并成为您在自己的数据科学之旅中使用的宝贵资源。请不要犹豫,分享你的想法,意见和问题。你的反馈对帮助我写出更好的故事至关重要。
干杯!👏
索尔·多比拉斯
如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加入媒介是:
https://solclover.com/membership
k 近邻:理论与实践

照片由艾米丽-乔·苏克利夫在 Unsplash 上拍摄
了解如何使用 KNN,这是最直观的分类和回归算法之一
介绍
k-最近邻,也被称为 KNN,可能是最直观的算法之一,它对分类和回归任务都有效。因为它很容易理解,所以它是比较其他算法的一个很好的基线,特别是在可解释性变得越来越重要的今天。
直觉
比如说你想卖掉你的房子,需要估算一下价格。你可以看看你最近的 9 个邻居最近买房子的价格,然后计算平均值来估计你自己的房价。您刚刚使用了一个用于回归的 KNN 算法。是的,就这么简单。
在分类任务中,假设您将 KNN 应用于著名的泰坦尼克号数据集,目标是预测泰坦尼克号乘客是否幸存。你可以找到 4 个与你试图预测的乘客最相似的乘客,然后看看大多数人发生了什么:如果幸存的人比死亡的人多,你就把这个乘客归类为幸存者。
以下是一个示意性示例,帮助您一步一步地想象这是如何发生的:

作者图片
这些例子引出了两个主要问题:
- 在第一个例子中,很容易定义您的最近邻居,但在第二个例子中,您如何衡量两个乘客有多相似?
- 为什么第一个示例中有 9 个最近邻,而第二个示例中有 4 个?
嗯,第一个问题是关于定义和计算距离度量,第二个问题是关于定义“K-Nearest Neighbors”中 K 的最佳数量。现在让我们更详细地讨论这些问题。
距离测量
当我们谈论距离时,我们倾向于想到欧几里德距离,使用空间坐标:

欧几里德距离-作者图片
在上图中,A 和 B 之间的欧氏距离是 d。
然而,有多种方法可以计算两个物体有多近。例如,在同一个例子中,曼哈顿距离将是 D = d1 + d2 (想想如果这些是街道,你会走多远)。
虽然在这个例子中我们只有二维,但当我们处理数据时,我们通常有更多的维度。然而,所有这些距离度量都适用于多个维度。
然而,有一个警告:当你使用 KNN 时,你绝对需要在计算这些距离之前通过标准化来缩放你的数据。否则,你会用完全不同的尺度来测量距离。在我们的泰坦尼克号的例子中,你将使用不同的变量来测量两个乘客之间的距离,例如他们的年龄和他们支付的船票价格,这显然不是同一个尺度。这将赋予倾向于具有更大值的变量更大的权重。
一旦您缩放了数据并选择了距离度量,您就可以计算所有观测值之间的距离(显然您不需要自己计算,KNN 实现已经为您完成了)。
“K-最近邻”中 K 的最佳个数
好了,一旦您知道如何测量两个观测值的接近程度,您如何决定您将使用多少个邻居来进行估计呢?简单:通过选择在验证集上产生最佳误差度量的值,就像对任何其他超参数一样。
首先选择一个误差度量作为决策标准(例如,RMSE 回归或 AUC 分类),然后使用网格搜索或您选择的其他方法测试 K 的多个值,看哪个效果最好。
但是,如果你想了解这个选择将如何影响你的算法,请思考一下它如何应用于我们的房价示例:K 越小,你就越忽略远处的邻居,而只关注隔壁的邻居。这应该是好事吧?好吧,但在这种情况下,你也更容易受到你的模型没有考虑到的其他特征的差异的影响:如果你的隔壁邻居有一个更大的房子和一个游泳池怎么办?或者,如果他只是幸运地以一个不为人知的原因以便宜得多的价格买下了他的房子呢?嗯,比你的估计不会很好。通过考虑许多邻居,你最终会消除这种噪音(但也可能最终会考虑离你家太远的房子)。所以这里有一个权衡,可以通过使用交叉验证来解决。
如何在实践中使用 KNN
让我们使用 Python 做一个简单的 KNN 分类示例,并尝试估计 Airbnb 住宿的价格是高于还是低于中位数。
这是一个分类任务,因为我们不试图估计价格本身,而是价格是高于还是低于中位数(一个二元结果)。
作为独立变量,我们有像位置(地理坐标)邻居和评论数量这样的东西。
密码
**[IN]:**
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler, LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import auc, roc_curve, confusion_matrix
这里,除了我们将用于任何分类任务的经典库,如 pandas 、 numpy 和 sklearn.metrics ,我们还导入了 StandardScaler ,这将使我们能够缩放我们的数据,以及 KNeighborsClassifier ,这是使用 KNN 进行分类的 sklearn 模块(对于回归,使用 KNeighborsRegressor )。
**[IN]:
# Reading data**
df = pd.read_csv("C:/Users/Arthur/Downloads/AB_NYC_20192.csv")**# Transforming categorical variables into binary**
df = pd.concat([
df,
pd.get_dummies(df[['neighbourhood','neighbourhood_group','room_type']])
], axis=1)df = df.drop(['neighbourhood','neighbourhood_group','room_type'], axis=1)**# Creating our target variable**
df['price_cat'] = df['price'] < df['price'].median()**# Train test split**
X, y = df.drop('price_cat', axis=1), df.price_cat
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.33, random_state=42)
我们首先重新计算我们的数据,然后我们得到一些分类变量,并把它们转换成二进制。然后我们创建我们的目标变量(低于中值价格/不低于中值价格),最后我们进行训练/测试分割。
现在让我们尝试第一个模型,使用地理坐标(不按比例缩放),以便仅根据地理位置找到最近的邻居。
**[IN]:**
**# Fit & predict**
neigh = KNeighborsClassifier(n_neighbors=50)
neigh.fit(X_train[['latitude','longitude']], y_train)
y_pred = neigh.predict(X_test[['latitude','longitude']])**# Evaluation**
fpr, tpr, thresholds = roc_curve(y_test, y_pred, pos_label=True)
auc_score = round(auc(fpr, tpr), 2)
threshold = 0.5
print("AUC: {}".format(auc_score))**[OUT]:** AUC: 0.72
正如您所看到的,我们使用 50 作为邻居的数量:这是一个任意的选择,稍后我们将回到这一点。
如果你不知道,AUC 是分类任务的质量指标,越接近 1 越好。0.72 的 AUC 是可以的,但不是很好。让我们通过向我们的模型添加更多的变量来尝试改进它,这一次,缩放它们。
**[IN]:**
categorical_variables = [
col for col in df if col.startswith('neighbourhood') or col.startswith('room_type')
]
variables = [
'latitude', 'longitude',
'number_of_reviews', 'reviews_per_month'
]variables.extend(categorical_variables)
scaler = StandardScaler().fit(X_train[variables])
X_train_norm = np.nan_to_num(scaler.transform(X_train[variables]))
X_test_norm = np.nan_to_num(scaler.transform(X_test[variables]))**# Fit & predict**
neigh = KNeighborsClassifier(n_neighbors=50)
neigh.fit(X_train_norm, y_train)
y_pred = neigh.predict(X_test_norm)**# Evaluation**
fpr, tpr, thresholds = roc_curve(y_test, y_pred, pos_label=True)
auc_score = round(auc(fpr, tpr), 2)
print("AUC: {}".format(auc_score))**[OUT]:**
AUC: 0.82
如你所见,我们的 AUC 显著提高,基本上是通过添加那些新功能,这些新功能明显添加了许多关于合并的相关信息。
然而,我们没有改变 KNN 分类器中的任何参数。
让我们来看看对于不同的距离度量和不同的 K 值,分数会如何表现:
**[IN]:**
for dist in ['manhattan', 'euclidean']:
print("Distance metric: {}".format(dist))
for k in [2, 4, 10, 50, 100, 500]:
# Fit & predict
neigh = KNeighborsClassifier(n_neighbors=k, metric=dist)
neigh.fit(X_train_norm, y_train)
y_pred = neigh.predict(X_test_norm) # Evaluation
fpr, tpr, thresholds = roc_curve(y_test, y_pred, pos_label=True)
auc_score = round(auc(fpr, tpr), 2)
print("For K = {}, AUC: {}".format(k, auc_score))**[OUT]:** Distance metric: manhattan
For K = 2, AUC: 0.77
For K = 4, AUC: 0.8
For K = 10, AUC: 0.83
For K = 50, AUC: 0.82
For K = 100, AUC: 0.82
For K = 500, AUC: 0.81Distance metric: euclidean
For K = 2, AUC: 0.77
For K = 4, AUC: 0.8
For K = 10, AUC: 0.83
For K = 50, AUC: 0.82
For K = 100, AUC: 0.82
For K = 500, AUC: 0.81
首先,我们可以看到距离度量对我们的度量没有影响。
我们还可以看到,尽管 K 似乎对我们用例的 AUC 没有很大的影响,但它的最佳值在 10 左右。
根据上面的结果,下一步可能是尝试 10 左右的其他值,如 8 或 12,看看我们是否可以微调得更多一点,但这不太可能产生更好的结果。进行这种分析的另一种方法是在折线图上绘制 AUC 与 K 的关系,以观察 AUC 在多个 K 值下的表现。
额外参数
关于 scikit-learn 的 KNN 实现,您应该知道其他一些参数。您应该将它们添加到 KNeighborsClassifier 或 KNeighborsRegressor 中(更多信息,请查看文档 ) 。
- 度量:这是选择要使用的距离度量的参数。我们试过“欧几里得”和“曼哈顿”。如果你专门处理地理坐标和整个大面积,“哈弗辛”可能是个不错的选择,因为它会考虑到地球的曲率。在处理一个小区域的时候,这样的城市,大概不会有太大的区别。当处理分类变量时,尝试使用“汉明”距离。
- 权重:该参数将决定如何对每个邻居的结果进行加权。将其设置为“距离”实际上会根据邻居到感兴趣的观察值的距离对目标变量进行加权:邻居越靠近,其值对我们的估计的影响越大。
结论
正如你所注意到的,KNN 有一些优势:
- 这很容易解释,当你必须向高层管理人员“推销”你的模型时,这很好
- 这是一个非参数算法,这意味着我们不必对我们的数据及其分布做任何假设。
T21 的一些缺点是:
- KNN 不能处理缺失值的事实(强迫你输入一些估计值)
- 虽然它相对较快,但对于大型数据集,它会变得很快
如果你想巩固你的知识,我建议尝试自己实现算法,从零开始(计算距离,寻找最近的邻居等。).这应该不难做到,而且可以成为一种强有力的学习经历。
如果你喜欢这篇文章,你可能也会喜欢这些:
[## 还在用同样的旧假设检验数据科学吗?
towardsdatascience.com](/still-using-the-same-old-hypothesis-tests-for-data-science-67a9913ce9b8)
如果你想进一步讨论,请随时在 LinkedIn 上联系我,这将是我的荣幸(老实说)。
k-最近邻解释道
数据科学基础
了解这种受监督的机器学习算法是如何工作的

布鲁克·拉克在 Unsplash 拍摄的照片
k-最近邻(KNN 从这里开始)是一种直观且易于理解的机器学习算法。这篇文章简要介绍了 KNN。我们将首先通过一个简单的例子学习算法在概念上如何工作,然后用 Python 从头开始实现算法,以巩固概念知识。
📗 1.算法如何工作的摘要
📍1.1 培训
训练过程非常简单快捷。在训练期间,模型存储哪些特征组合对应于训练数据中的哪个目标。换句话说,它只是记忆训练数据。
📍 1.2.预言;预测;预告
所有的艰苦工作都发生在预测过程中。为了预测一个示例的目标,该算法经历以下步骤:
1️⃣找到 k-最近的训练例子(即邻居)。
2️⃣在 k 个最近的邻居中分配典型的目标值。这意味着分类的最常见目标类和回归的平均目标值。
正如你现在看到的,这个算法的名字泄露了它所做的事情的要点。这里有一种方式来思考 KNN 是如何工作的。训练示例就像一个查找表。当我们有一个新的示例要预测时,我们会找到与这个新示例最相似的 k 个训练示例,并基于这些相似训练示例的典型值进行预测。很直观很好理解吧?
现在,让我们将刚刚学到的知识应用到一个简单的例子中。
📍 1.3.例子
假设我们有以下训练数据集,它有三个特征: x1 到 x3 和一个二进制标签: y.

我们有一个如下的测试数据集:

我们将使用欧几里德距离(一种流行的距离度量)来寻找最近的邻居,并设置 k=2。现在,让我们预测测试示例 h 的类。
1️⃣找到它到所有训练样本的欧几里德距离。 首先,让我们找出它到的距离一,第一个训练例子:

由于两者具有相同的特征值,其到 a 的距离为 0。现在,让我们计算它到下一个例子 b 的距离:

其到 b 的距离为 2.24。如果我们对其余的训练示例重复相同的计算,我们将得到以下距离:

2️⃣找到它的 k 个最近邻居(即具有最短距离的训练例子)。 我们可以看到最近的两个邻居是 a 和 d 。

3️⃣在其 k 个最近的邻居中找到最常见的标签。 如果我们看训练数据,会发现 a 和 d 都属于负类。因此预测 h 为负,因为 2 个最近邻中最常见的类是负。
现在,让我们为其他两个测试示例找到 k 个最近邻:

i 和 j 都离 e 和 f 最近。由于 e 和 f 之间的公共类为正,t he 模型预测测试实例 i 和 j 为正。
直观地理解特征尺度和 k 值的含义是有用的。
◼️ 特征比例:虽然例子中的特征一开始没有相等的比例,但它们非常接近。想象特征 x3 大 10 倍:

对于每个示例,距离和 k-最近邻都会发生变化:

比例越高的要素在距离计算中的权重越大。这几乎就像特征比例暗示了距离计算中每个特征的权重。因此,如果你想让你的特征做出同等的贡献,在建模之前将它们放在相同的比例上是很重要的。
◼️:在我们的例子中,我们将 k 设置为 2。但是如果我们把 k 改成 7 会怎么样呢?
我们在训练数据集中有 7 个例子,最常见的类是正。k=7 时,模型会将任何记录预测为阳性,为训练数据中的多数类。下图右侧的光谱代表了这种情况:

作者图片
当 k 太小时,模型可以检测到数据中非常细微的模式,并且易于过拟合,而 k 太大会导致模型过于一般化,易于欠拟合。找到 k 的最佳值需要试错学习方法。找到最佳 k 的一种方法是从随机搜索开始,在大范围内随机测试 k 的一组值,然后在更窄的有希望的值范围内进行网格搜索。
如果 k = 1,训练数据中没有重复的特征组合,你认为训练精度会是多少?答案是 100%准确的,因为每个都是自己最近的邻居。
我们现在将把我们在本节中学到的内容翻译成代码。
💻 2.Python 中的简单实现
让我们导入库并创建相同的玩具数据集:

训练在左边,测试在右边
我们创建一个KNNClassifier,拟合它并做出预测:

列车在右侧,试验在左侧
耶,我们刚刚用 Python 从头开始构建了一个非常简单的 KNN 分类器。虽然我们在这篇文章中关注的是分类,但是创建 KNN 回归器是很简单的。要创建一个回归变量,在上面的代码中,将第 1 行中的KNNClassifier重命名为KNNRegressor ,并将第 29 行改为:y.append(np.mean(targets))。
为了保持代码简单易读,上面的代码包含潜在的冗余步骤(例如求平方根)和非优化代码(例如存储所有邻居)。为了更好地理解算法,我们自己实现了算法。实际上,最好使用更优化的算法,比如来自 sklearn 的算法。

希瑟·巴恩斯在 Unsplash 上的照片
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。
在这篇文章中,我们已经涵盖了 KNN 的基础知识。感谢您阅读我的文章。如果你感兴趣,这里有我其他一些帖子的链接:
◼️️ 比较随机森林和梯度推进
◼️️ 决策树是如何构建的?
◼️️ 管道,ColumnTransformer 和 FeatureUnion 说明t26】◼️️feature union,ColumnTransformer &管道用于预处理文本数据
再见🏃 💨
k 最近的邻居解释说
使用 sklearn 库理解 KNN 算法及其在 Python 中的实现

图片来自:https://unsplash.com/photos/lW25Zxpkln8
在这篇文章中,我将给出一个概述,实现,缺点和与 K 最近邻算法相关的资源。监督学习是机器学习的一个子部分,通常与基于分类和回归的问题相关联。监督学习意味着您正在使用带标签的数据集训练模型。k 近邻(KNN)属于监督学习范畴,是机器学习的核心算法之一。这是一个被广泛使用的简单而有效的非参数的懒惰学习者分类算法的例子。
- 懒惰学习者意味着它不从训练数据中学习判别函数,而是记忆训练数据
- 非参数意味着算法对数据的分布不做任何假设。
KNN 算法根据未分类数据点与其他可用数据点的接近度和相似度对其进行分类。该算法的基本假设是可以在彼此附近找到相似的数据点。它通常用于解决各种行业中的问题,因为它易于使用,适用于分类和回归问题,并且它生成的结果易于解释。
该算法
k 代表最近邻居的数量。当 K = 1 时,该算法称为最近邻算法。这是最简单的情况,给定一个未标记的位置 X,算法可以通过找到离 X 最近的标记点并将其指定为标记来预测其标记。

在这种情况下,未标记的黑点 X 将根据标记点的最近接近度被预测为蓝点(图片由作者提供)
该算法的工作原理如下:
1) Choose the number of K and a distance metric used to calculate the proximity
2) Find the K nearest neighbours of the point we want to classify
3) Assign the point a label by majority vote

在未标记的黑点附近,橙色点的数量大于蓝色和红色点的数量。因此,该算法将预测这是一个橙色标签(图片由作者提供)
K 的右值
K 的选择对模型至关重要,如果选择不正确,会导致模型过拟合/欠拟合。太小的 K 值将导致数据中的噪声对预测有很大影响,然而太大的 K 值将使其计算代价昂贵。
选择最佳 K 值的行业标准是取 N 的平方根,其中 N 是样本总数。当然,对这一点不能全信,因为它因问题而异。
您可以试验不同的 K 值及其相关的精度。确定 KNN 模型准确性的常见做法是使用混淆矩阵、交叉验证或 F1 分数。
优点和缺点
下面,我列出了使用 KNN 算法的一些优点和缺点。
优势
- 简单直观—算法非常容易理解和实施
- 基于内存的方法—允许 it 部门立即适应新的培训数据
- 各种距离度量——用户可以灵活地使用最适合其应用的距离度量(欧几里得距离、闵可夫斯基距离、曼哈顿距离等)。)
劣势
- 计算复杂性-随着训练数据的增加,计算速度会迅速降低
- 在不平衡数据上表现不佳-当模型正在接受训练的大部分数据代表 1 个标签时,该标签被预测的可能性很高
- K 的最佳值-如果选择不正确,模型将与数据拟合不足或过拟合
履行
摘要
总之,这篇文章概述了 kNN 是一个懒惰的学习者和非参数算法。它的工作原理是根据未标记点与所有其他最近的标记点的接近程度,为未标记点分配一个标签。它的主要缺点是计算效率很低,很难选择 k 的“正确”值。然而,该算法的优点是它适用于不同的邻近度计算,非常直观,并且是一种基于内存的方法。
资源
如果你喜欢这本书,那么看看我的其他作品。
https://medium.com/nerd-for-tech/monte-carlo-method-explained-8635edf2cf58
使用 K 近邻预测推文的作者
(相对)直观算法的介绍
嗨!我是劳拉,我在学习机器学习。我也是加州州立大学东湾分校的数学讲师,很幸运能够作为数据科学研究员与我的导师 Prateek Jain 在sharpes minds共事。这个项目被选为我从头开始练习编写机器学习算法的一种方式(不允许 scikit-learn!)并因此深入学习和理解 k-最近邻算法,或 kNN。
如果您还不熟悉 kNN,那么这是一个很好的 ML 算法,因为它相对直观。邮政编码通常是个人的有用代表,因为住在同一街区的人通常有相似的经济背景和教育程度,因此也可能有共同的价值观和政治观点(尽管不是保证!).因此,如果你想预测某项特定的立法是否会在某个地区通过,你可以对该地区的一些选民进行民意调查,并假设这些选民的大多数邻居对你的法案的看法与你调查的大多数人相似。换句话说,如果你被问及该地区的某个人可能会如何投票,你肯定不知道他们会如何投票,但你会看看他们的受访邻居说他们会如何投票,并假设你的人会投票给投票中最常见的答案。

kNN 的工作方式非常相似。给定一组已标记的数据和一个未标记的数据点x,我们将查看x's邻居中的某个数量k,并将这些k邻居中最常见的标签分配给x。让我们来看一下:在下图中,我们有一个未标记的点和它的邻居的 15 个邻居。在这 15 个邻居中,9 个有“A”标签,6 个有“B”标签。

由我插画!
由于更多的未标记点的邻居有“A”标签而不是“B”标签,我们应该用“A”来标记我们的点。那就是 kNN!
但是,请注意 kNN 不是什么:我们没有给我们的点加上它的最近邻居的标签!我们的点最接近 6 个“B”点,但我们没有称它为“B”。这种区别在我写代码的时候让我犯了一个错误,也许是因为算法名称中的“最近”这个词?总之,我一直在编写一个函数,它查看一个数据点的邻居,并选择距离该数据点 k 以内的邻居,这实际上是一个完全不同的算法:半径邻居分类器。我应该再做一次,将结果与 kNN 进行比较!或许在另一篇博客中。
关于 kNN 不是什么还需要知道的是,对于存在于高维空间的问题,kNN 不是一个好的算法选择(剧透:这将成为这篇文章的笑点!).由于 kNN 假设彼此“接近”的数据点很可能是相似的,并且由于在高维空间中数据可以分散得非常远,所以“接近”的概念变得毫无意义(关于这一点的更长解释,请查看这个视频!).想想澳大利亚和新西兰的岛屿:它们是彼此最近的邻居,但它们仍然相距数千公里,因此它们有非常不同的气候、地形和生态系统。


左图:澳大利亚沙漠的图片,由 Greg Spearritt 在 Unsplash 上拍摄。右图:Unsplash上的新西兰森林托比亚斯·图利乌斯的照片。
好了,现在我们知道了 kNN 是什么,不是什么,让我们来看看我是如何编码的。请注意,这显然是一个非常初学者的练习,它不会像更有经验的从业者那样优雅或巧妙。我的指示是从头开始编写所有代码,所以我没有使用 Pandas 来读取我的数据,也没有查看其他人是如何做到的。我不建议你使用我的代码,我也不需要评论或电子邮件来说明你不喜欢它,因为我的任务是学习这个算法,并花更多的时间在我的 IDE 而不是 Jupyter 笔记本上,我成功实现了这些目标。😃
我的导师建议我可以在这个项目中使用 Twitter 数据,我需要能够下载单个作者的大量推文。理想情况下,这位作者会有非常独特的写作风格,使算法更容易识别出一条未标记的推文是否属于该作者。这是 2020 年的夏天,美国的总统选举正在紧锣密鼓地进行,所以我的导师认为用唐纳德·特朗普作为测试案例会很有趣(很多推文?没错。与众不同的写作风格?没错)。注意:这个项目绝对不是对前一个人的认可,实际上我几乎是从另一个作者的新推文开始的,因为我不想给他更多的空间,但我最终决定反对范围蔓延,只是完成这个项目。
我发现了一个网站,其中 TFG 的所有推文都聚集到一个 txt 文件中,还有一个 Kaggle 数据集,其中有超过 10,000 条不同人的推文,放在一个 tsv 文件中,作为算法的对比。然后,我需要编写一个函数,将这些文件中的数据读入数组,这样我就可以使用它们了。
但是我的数据不是以 csv 文件的形式出现的;它在一个 txt 文件和一个 tsv 文件中!所以我需要另一个函数来将这些其他文件类型转换成 csv。我决定通过包含几种不同文件类型的情况来使该函数更加强大:
现在,我有一组来自 TFG 的推文和一组其他人的推文,但是如果我照原样比较它们,我会浪费很多时间来比较无处不在的词,如“the”或“and”,这些词被称为“停用词”,因为它们对分析没有意义。所以我找到了一个停用词列表,并编写了一个函数将它们从数组中删除,同时也删除了数字和标点符号,因为它们对分析也没有帮助。我还将所有字符转换为小写。最后,我需要制作一个“单词包”或语料库,以包含所有 tweets 中使用的所有单词的列表,在清理文本的同时这样做是有意义的,所以我只保留每个“清理”单词的副本。
接下来,我需要对我的数据进行矢量化,以便以后能够使用 NumPy 函数。为此,我初始化了一个 NumPy 数组,其行数与我的 tweets 数相同,每行的长度等于语料库中单词的数量+ 2。我添加了两个额外的列,这样最后一列将跟踪 twee 是否是 TFG 写的(1 代表 TFG,0 代表其他人),倒数第二个字符将存储 tweet 的索引,以便我可以在解释时引用它。对于每条推文,我的函数将查看语料库中的每个单词,如果该单词出现在推文中,则在引用该单词的列中输入“1”,如果该单词没有出现在该推文中,则输入“0”。这意味着这些是非常稀疏的数组(大部分是零)——哦,预示着!
然后我需要随机化 NumPy 数组中向量的顺序,这样我就可以进行训练和测试。
我对数据进行了拆分,使 80%进入训练集,20%进入测试集。
快到了。现在,我需要一种方法来比较两条推文彼此之间的相似程度,我将通过获取它们向量之间差异的绝对值来完成(绝对值是因为 1–0 与 0–1 在这个目的上是相同的,因为两者都意味着一个单词出现在一条推文中,而不是另一条推文中)。单词的每一个差异都会使两条推文之间的“距离”增加 1。
现在该是找到最近邻居的时候了!我需要编写一个函数,它将接收一个 tweet 向量和数字k,并比较所有其他 tweet,以找到与有问题的 tweet 最相似的k列表并返回它。
最后,我需要一个函数来确定前一个函数返回的列表中的ktweet 的最常见标签,这是我添加到每条 tweet 末尾的 1 或 0,表示作者将派上用场。
太好了,我们做到了!然而,事实证明,我的程序把我扔出去的每条推文都归类为 TFG 写的,即使我很确定它不是。
Womp womp 长号 Gif(通过https://media.giphy.com/media/D0feQxfAek8k8/giphy.gif)
我意识到推文向量的稀疏性意味着——有点像澳大利亚和新西兰——两条推文是彼此最近的邻居并不意味着推文实际上彼此非常相似。但是没关系!这个项目的目的是让我从头开始编写 kNN,并学习在没有熊猫的情况下处理数据。(我还学会了如何处理我的数据,如何以及为什么在我的函数中使用类型转换,以及如何使用 Sphinx 为我的项目创建文档——尽管它还不能正常工作。还在学!).所以这个项目达到了它的目的,即使准确率最终非常糟糕。
我希望你喜欢我学习旅程中的这一站!你可以在这里查看我以前的帖子。
在 LinkedIn 上和我联系,或者在 Twitter 上和我打招呼!你也可以在 lauralangdon.io 找到我。
基于 k-NN 的时间序列分类
数据科学
文献中不同方法的概述

免费矢量插图来自比例尺
时间序列分析是统计学中最流行的分支之一。时间序列无处不在,在许多领域都有应用。时间序列分类(TSC) 在数据挖掘、机器学习、信号处理、统计学等领域有着广泛的重要性。然而,这是一项具有挑战性的任务。用于解决这个复杂任务的最流行和最简单的方法之一是k-最近邻(k-NN)【1–4】。k-NN 分类器基于简单的分类规则,该规则包括在基于多数分类之前将新样本嵌入训练空间。最终的结果是相似的数据点靠得很近,而不相似的数据点离得很远。尽管 k-NN 简单,但其性能仍然具有竞争力,这主要取决于距离或邻近度的选择[5]。根据文献资料,基于动态时间弯曲(DTW)的 kNN【6】仍然是最流行和最具竞争力的方法之一【7】。在此基础上,开发了标准 DTW 的各种变体,并进一步改进了其性能。
为了有效解决 TSC 问题,正确理解文献中可用的不同方法变得非常重要。此外,在研究方面,这也有助于建立在现有方法的基础上,从而为进一步的高效解决方案铺平道路。因此,在这个方向上,本文根据其研究的科学问题和制定的方法概述了构成基于 k-NN 的时间序列分类领域的三篇科学研究论文,突出了解决方案的关键部分。
1。局部加权时间偏差下的大间隔时间序列最近邻分类[5]
科学问题: TSC 方法消除了标准 DTW 的缺点&学习全局约束扭曲模型并使用 k-NN 考虑较大的邻域裕量。
方法:局部加权动态时间弯曲(LWDTW)。
针对标准 DTW 认为时间序列是均匀分布的,从而给复杂时间序列的分类带来困难的缺点,本文提出了一种考虑局部加权动态时间弯曲的新方法。利用标准 DTW 变量上的局部权重向量的 LWDTW 被分类为 DTW (对 DTW 施加限制以改善其性能的变体)的约束变体,并与 k-NN 分类器结合使用以进行分类。LWDTW 包括通过从时间序列数据中捕获局部区别特征来学习局部感知加权 DTW (时间序列元素的权重)。通过这样做,它消除了对非均匀 TSC 的全局约束扭曲模型的要求和限制。在 TSC 中使用 k-NN 的 DTW 方法中包含权重对 k-NN 过程具有积极影响,k-NN 过程用于捕捉相邻时间序列之间的相似性/不相似性,实现时间序列元素的时间对齐,适当处理不同权重的时间序列元素。LWDTW 方法受时间序列方差的影响,方差越小表示权重越高,反之亦然。同样,对于 k-NN 分类器,考虑大的边界(大的邻域)产生具有更好的泛化性能的解决方案。
2。关于正的未标记时间序列分类问题中 k-最近邻的停止准则[8]
科学问题:停止准则,消除了自训练正无标签(PU)学习中的过早停止问题。
方法:使用图形分析停止准则 4 (CBD-GA-SC4)的类边界描述。SC4 将类边界描述为上升曲线和下降曲线高度之间的最大值。
正无标签学习是学习 TSC 问题中无标签数据标签的一种合适方法。然而,在自训练 PU 技术中,决定何时停止标记未标记数据(停止标准)是非常关键的。停止标准中的大多数现有技术方法导致过早停止,这导致训练的分类器的不完全学习,并最终导致保守的方法。本文阐述了使用图形分析的类边界描述(CBD-GA) 方法,该方法基于样本之间的距离点的趋势使用图形分析技术来确定类边界,用于停止标准。本文基于三种图形曲线(上升、下降、稳定)的不同组合,分别用欧氏距离和 DTW 对 k-NN 进行了实验评估,形成了一族无参数、低成本的停止准则(SC1 -SC5)。然后通过实验验证了以 SC4 描述的类边界为上升和下降曲线高度之间最大值的方法 CBD-GA-SC4 ,是稳健的方法。这也优于使用欧几里德和 DTW 距离度量的 k-NN 实现竞争结果的最新技术,从而防止早期停止。
3。弹性距离测度集合的时间序列分类[9]
科学问题:基于 11 种不同弹性距离分类器对 TSC 问题的分类精度,对它们进行比较。集成分类器公式优于这些单独的分类器。
方法:比例(PROP)集成分类器。
本文制定了一个新的集成分类器【比例(PROP) ,它是基于弹性距离度量[6,10–14]的 11 个不同分类器的组合,即欧几里德距离(ed)、导数时间弯曲(DTW)、导数 DTW、DDTW 与交叉验证(DDTWCV)、加权 DDTW (WDDTW)、加权 DTW (WDTW)、移动-拆分-合并(MSM)、DTW 与交叉验证(DTWCV)、编辑距离与实际惩罚(ERP)、最长公共子序列(LCSS)、时间弯曲编辑距离(TWE)用于 TSC 本文对最大的时间序列问题集进行了广泛的实验,在 75 个 TSC 数据集上进行了超过 300 万次实验,以验证其公式化的假设。本文通过实验验证了 11 种弹性距离分类器在分类精度上没有显著差异。定义的比例(PROP)集成被实验验证为比 DTWCV (其被认为是 TSC 中的基准)更精确,并且是第一个在如作者所声称的 TSC 问题中这样做的分类器。该论文将准确性描述为评估 TSC 问题的算法的最重要的度量,并因此通过强有力的实验验证声称以比例(PROP)集成分类器的形式而不是 DTWCV 的形式为 TSC 问题设置新的基准。
本文分享的见解是为关于知识管理和发现 中的高级主题的科学研讨会开展的研究工作的一部分
参考
[1]盖斯特和哈特出版社,1967 年版。最近邻模式分类。 IEEE 信息论汇刊, 13 (1),第 21–27 页。
[2]丁,h,特拉切夫斯基,g,舒尔曼,p,王,x 和,e,2008 .时间序列数据的查询和挖掘:表示和距离度量的实验比较。VLDB 基金会会议录, 1 (2),第 1542–1552 页。
[3]萨尔茨堡公司,1997 年。比较分类器:要避免的陷阱和推荐的方法。数据挖掘与知识发现, 1 (3),第 317–328 页。
[4]x .、、e .、Shelton、c .、Wei、l .和 Ratanamahatana,C.A .,2006 年 6 月。基于数量约简的快速时间序列分类。在第 23 届机器学习国际会议论文集(第 1033–1040 页)。
[5]袁,j .,杜萨尔-舒阿克里亚,a .,S.V .和王,z .,2019。局部加权时间偏差下的大间隔时间序列最近邻分类。知识与信息系统, 59 (1),第 117–135 页。
6d . j . Berndt 和 j . Clifford,1994 年 7 月。使用动态时间弯曲发现时间序列中的模式。在 KDD 工作室(第 10 卷,№16,第 359–370 页)。
[7]丁,h,特拉切夫斯基,g,舒尔曼,p,王,x 和,e,2008 .时间序列数据的查询和挖掘:表示和距离度量的实验比较。VLDB 基金会会议录, 1 (2),第 1542–1552 页。
[8]m . gonzález、c . Berg Meir、I . Triguero、y . rodríguez 和 j . m . Benitez,2016 年。正的未标记时间序列分类问题中 k-最近邻的停止准则。信息科学, 328 ,第 42–59 页。
[9] Lines,j .和 Bagnall,a .,2015 年。弹性距离测度集合的时间序列分类。数据挖掘与知识发现, 29 (3),第 565–592 页。
[10]e . j .基奥和 M.J .帕扎尼,2001 年 4 月。导数动态时间弯曲。在2001 年 SIAM 数据挖掘国际会议论文集(第 1-11 页)。工业和应用数学学会。
[11] Jeong,Y.S .,Jeong,M.K .和 Omitaomu,O.A .,2011 年。用于时间序列分类的加权动态时间弯曲。模式识别, 44 (9),第 2231–2240 页。
[12]陈,刘丽和吴,2004 年 8 月.LP-范数与编辑距离的结合。在第三十届超大规模数据库国际会议记录-第 30 卷(第 792-803 页)。
[13] Marteau,P.F .,2008 年。时间扭曲编辑距离与时间序列匹配的刚度调整。 IEEE 模式分析与机器智能汇刊, 31 (2),第 306–318 页。
[14]Stefan a .,athit SOS v .和 Das g .,2012 年。时间序列的移动-拆分-合并度量。 IEEE 知识与数据工程汇刊, 25 (6),第 1425–1438 页。
国际歌迷眼中的韩国流行音乐
韩国流行音乐调查数据分析

乔尔·穆尼斯在 Unsplash 上拍摄的照片
尽管韩国流行音乐产业已经发展了 20 年,但在过去的几年里,它在国内和国际上都经历了显著的增长。毫无疑问,该行业在促进韩国经济增长方面发挥着至关重要的作用。
该行业的显著增长也导致了全球众多粉丝的显著增长。虽然对于一个外国人来说学习韩语并不容易,但这并不是国际粉丝学习韩国语言和文化的界限。
为了了解国际观众,特别是西方观众眼中的韩国流行音乐产业,我根据 Saanjana Rraman 在 2019 年 2 月进行的调查对韩国流行音乐的受欢迎程度和观众进行了分析。
您还可以找到我为支持本文而创建的 Tableau Public 可视化仪表板。仅供参考,这是我的第一个数据分析项目,所以请随时给我任何意见和反馈。事不宜迟,请欣赏这篇文章。快乐阅读!

照片由 Hiu Yan Chelsia Choi 在 Unsplash 上拍摄
数据清理
与通常的数据分析管道一样,在进行任何分析之前,我们必须做的第一件事是清理数据。在这里,我使用 Python 作为编程语言。我清理数据的方法基本如下:
- 将每个列名转换成可读性更好的版本
- 通过将文本格式的答案分成几个类别来清理它们
- 使用一键编码方法将多个答案转换成二进制变量
如果你很好奇想知道更多关于数据清理是怎么做的,请参考这本 Google Colab 笔记本 。
人口统计分析
首先,我们将看到调查对象的人口统计。

按国家分列的受访者。图片作者。
本次调查有 240 名受访者,其中 140 人来自美国。紧随美国之后,有 31 名欧洲受访者和 28 名加拿大受访者。

性别比例。图片作者。
至于性别,女性受访者以 94.58%的比例主导调查结果。与此同时,所有跨性别受访者共有 4 人来自美国。

按性别划分的年龄。图片作者。
另一方面,大多数受访者的年龄在 15 岁至 20 岁之间,在所有性别中共占 69.16%。

按年龄划分的工作。图片由 Autor 提供。
至于职业,大部分是学生其次是护士或者护理员。至于学生,以 15-20 岁年龄段为主。
按年份划分的受欢迎程度
在我们深入分析之前,让我们先看看受访者对韩国流行音乐的熟悉程度。根据下面的图表,我们可以看到很大一部分受访者是在 3 到 4 年前,即 2016 年左右开始了解韩国流行音乐的。

第一次接触韩国流行音乐。图片作者。
这一观点也得到了当年制作 K-pop 反应视频的多家西方 youtube 频道的支持。例如,React channel 制作的一个视频显示,BTS 的音乐视频打破了 K-pop 团体 24 小时内观看次数最多的记录,K-pop 专辑一周内销量最多的记录,以及 Billboard Top 200 中排名最高的专辑。
按国家分列的受欢迎程度
那么,根据这个调查,最喜欢的 K-pop 组合是什么呢?

最喜欢的 K-Pop 组合。图片作者。
事实证明,BTS 是所有国家中最受欢迎的 K-pop 组合,美国是受访者人数最多的国家。
不同于互联网上的趋势显示 Blackpink 总是与 BTS 竞争打破最快视频达到数百万次的记录,事实证明 MONSTA X 和 EXO 是第二大最受欢迎的 K-pop 组合,然后是 Blackpink。

按国家划分的受欢迎程度。图片作者。
我们还可以看到,韩国流行音乐在美国和亚洲产生了巨大的影响,而它在欧洲、加拿大、英国和澳大利亚仍在增长。
K-pop 是一个昂贵的爱好吗?
在韩国流行音乐行业,merch 和音乐本身一样重要。各种各样的商品可以以荧光棒的形式出现在相册中。

女性 Merch 美元消费桑基图表。图片作者。
调查结果显示,大部分受访者的职业是学生,尤其是女性,主要花费在购买他们喜欢的团体商品和音乐会门票上的费用低于 50 美元。

男性 Merch 美元支出桑基图表。图片作者。
相反,对于男性来说,他们花的钱大约是 50 到 100 美元。这笔钱多是从父母那里或者打工兼职得来的。特别是对于男性来说,花费低于 50 美元的人从兼职工作和储蓄中获利,而不是从父母那里。
韩国流行音乐视频
韩国流行音乐总是与复杂的视频和令人难忘的视觉效果联系在一起。由于视频的独特性,观众可以自由地对艺术家的作品做出自己的推测。

女表 MV 桑基图表。图片作者。

男表 MV 桑基图表。图片作者。
与上述事实一致,可以看出几乎所有的受访者都观看 K-pop 音乐视频,大多数人每天花 1 小时观看视频。
K-pop 很费时间吗?

韩国流行音乐耗时吗?图片作者。
大约 48%的受访者不认为 K-pop 很费时间,少数人声称他们没有很好的时间管理。紧随其后,有 35%的受访者认为韩国流行音乐很费时间。
另一方面,听 2-4 小时的人(44.16%)和听 5 小时或以上的人(41.67%)之间没有显著差异。
最后的话

最后,这是本文的结尾。希望它能给你有帮助的见解或关于韩国流行有趣的事实。
如果你有任何问题或者只是想和我进一步聊天,请在 LinkedIn 上打电话给我!
你可以在这里找到我在这个项目中使用的所有代码。
参考
figshare.com/articles/dataset/KPOP_DATA_xlsx/12095901
www.youtube.com/watch?v=-ttDePTDRi0
rollingstoneindia.com/art-korean-music-videos/
使用 Python 和 Elasticsearch 简化仪表板
使用 python、elasticsearch、apache Kafka 和 Kibana 构建强大的仪表盘
流处理是一个非常强大的数据处理范例,它帮助我们以连续流的形式处理大量的数据点和记录,并允许我们实现实时处理速度。
阿帕奇卡夫卡 对于数据流来说是一个极其强大的工具。它具有高度的可扩展性和可靠性。[1]
Elasticsearch 是基于亮氨酸库的搜索引擎。它提供了一个分布式的全文搜索引擎,带有 HTTP web 接口和无模式的 JSON 文档。[2]
Kibana 是可视化我们的弹性搜索数据库/索引内容的优秀工具。它帮助我们非常快速地构建仪表板。[3]
Python 是每个人都喜欢的语言,因为它非常容易使用。
在这篇博客中,我们将看到如何利用上面的堆栈的力量,从真实数据中创建一个仪表板。
为了模拟一个流数据源,我们将使用一个包含随机系统日志的日志文件,我们将把这个信息推送到一个 kafka 主题。图 1 给出了整个系统的架构

图 1:我们的流处理管道的架构图
让我们从我们的 卡夫卡 制片人代码开始。让我们称这个为 Producer.py. 在这个文件中,我们将执行以下操作→加载日志文件的内容并解析它,将数据推送到一个 kafka 主题,供我们的另一个 python 程序使用,该程序将这些信息推送到elastic search。Kafka 生产者代码块如下面的代码片段所示(图 2)。生成器对象是在构造函数调用中创建的。 产生 方法获取一条消息,将其转换为 json 并将其推送到指定的 kafka 主题

图 2: Kafka 生产者代码块
对于这个程序,我使用的是confluent _ Kafkapython 包。 Github 链接→https://github.com/confluentinc/confluent-kafka-python
在为日志文件编写解析器之前,让我们先看一下日志文件。下面的图 3 显示了日志文件中的一些行。

图 3:日志文件内容
下面给出了解析日志并以 python 字典格式返回消息的代码块(图 4)。在检查日志文件时,我们注意到日志消息有以下类型→ ["信息"、"错误"、"严重"、"警告"] 。这些信息将有助于在 Kibana 仪表盘上对我们的数据进行分类。

图 4:我们日志文件的解析器
图 4 中的解析器类相当简单。我们有几个函数来加载日志文件,并使用 iter 函数返回每一行。
一旦我们有了我们的日志文件解析器和 kafka 生成器,我们就可以继续将日志消息发送到我们的 kafka 主题。这些信息将会被消费者收集起来,并推送到elastic search。图 5 显示了我们如何调用方法将消息推入 kafka 主题。

图 5:调用我们的解析器方法和生产者方法的主函数
在运行主函数时,日志文件的内容被推送到 kafka 主题,并由另一端的消费者接收。下面的图 6 给出了输出。

图 6:日志生产者代码的输出
接下来,我们将继续编写将所有这些信息推送到elastic search上的部分,然后继续在 Kibana 上创建仪表板。
为了用 python 连接到 Elasticsearch ,我们将使用 python 的官方 Elasticsearch 库→https://elasticsearch-py.readthedocs.io/en/v7.13.0/
在图 7 中,我们有一个名为 Elastic 的类,在这里我们连接到在端口 9200 上运行的Elastic search实例。对于这个实验,我们使用一个docker-compose文件,其中包含了对elastic search和kibana服务的配置。这个实验的 GitHub repo 中有docker-compose文件(博客末尾的链接)。一个简单的docker-compose up应该启动我们的elastic search和 kibana 实例。

图 7:连接到 elasticsearch 实例并推送数据的类
Elasticsearch 用来存储数据的数据结构称为 倒排索引 。它具有快速识别每个单词的能力。因此,我们能够以实时速度执行搜索和查询。在我们的实验中,索引的名称是【new-relic-log】**
图 8 中给出了 Kafka 消费者块,我们将使用它来读取来自 kafka 主题的消息,生产者将所有日志消息发送到该主题。read _ messages方法让我们不断地轮询主题并寻找消息。

图 8:卡夫卡消费区
一旦我们有了来自消费者的消息,我们可以调用 Elastic 类中的push _ to _ index方法将消息推送到 Elasticsearch,如图 9 所示

图 9:向 elastic 发送数据
下面的图 10 显示了图 9 中命令的输出。写响应显示了我们将数据传输到 elasticsearch 的细节,包括索引细节和结果。

图 10: Elasticsearch 数据推送输出
现在让我们看看数据是如何出现在 Elasticsearch 上的。为了访问我们的索引,我们将直接转到我们的 Kibana 仪表盘。确保您的 Kibana 和 Elasticsearch 容器运行正常。前往http://localhost:5601←这是我的本地机器上运行 Kibana 的端口。 基巴纳 的主屏幕如下图 11 所示

图 11:基巴纳主屏幕
现在检查数据是否正确地进入我们的 新遗迹日志 索引,点击 发现 按钮(左手边面板上的第二个按钮),如图 12 所示。从下拉菜单中选择索引为new-relic-log,您应该会看到 python 发送的所有日志消息都显示在屏幕中央(图 13)

图 12:发现按钮和索引选择

图 13:在 Kibana 上注销
为了过滤掉仅仅是 INFO 日志或者是 ERROR 日志,我们可以使用顶部的搜索栏,它为我们提供了许多过滤数据点的选项。 信息 日志过滤示例见下图 14

图 14:过滤的信息日志
现在,为了使我们的数据可视化并将其放在一个真实的仪表板上,我们必须准备一些图表。让我们从折线图开始。该折线图将汇总不同日志类型的计数并显示。
点击 可视化 按钮,在左侧面板的 发现 按钮的正下方(图 15)。

图 15:可视化选项卡
点击 新建可视化 按钮,会出现多种不同类型的图表选项(图 16)。对于这个例子,我们将使用折线图

图 16:图表选项
选择了首选图表类型后,系统将提示您选择要从中读取数据的索引。这里,我们将选择新遗迹日志索引(图 17)

图 17:可视化的索引选择
现在,我们将为折线图创建设置。在 Y 轴 上,我们将参数选择为 计数。 在 X 轴上我们将选择参数作为 时间戳 。Kibana 还为我们提供了一个选项,可以在不同的键之间在同一 X 轴上分割图表。在我们的例子中,我们将可视化计数INFO日志和ERROR日志在同一图表上。设置分别如图 18(a、b)和 19 所示。最终图表如图 20 所示。如您所见,我们对两种日志类型的时间戳进行了聚合。

图 18 (a): X 轴

图 18 (b):拆分系列选项

图 19 : Y 轴

图 20:信息日志类型和错误日志类型的计数。
我们还创建了一个饼图来获得两种不同日志类型的总数(图 21)。要创建饼图,只需选择可视化屏幕上的饼图选项,而不是折线图选项。

图 21:日志类型计数的饼图
现在,我们将创建我们的第一个基巴纳仪表盘。这一步再简单不过了。
点击 仪表板上 正下方的 按钮,可视化 按钮。点击顶部的添加*按钮→选择图表,完成。您已经准备好了您的仪表板(图 22)*****

图 22:仪表板
我希望这篇博客有助于简要介绍我们如何利用这些开源工具来构建健壮的数据流管道。
Github 项目链接→https://github.com/AbhishekBose/kafka-es
参考文献:
[1]https://en.wikipedia.org/wiki/Apache_Kafka
https://www.elastic.co/what-is/kibana
Kafka UI 监控工具(2021 年更新)
探索 Apache Kafka 集群的一些最强大的 UI 监控工具

克里斯·利维拉尼在 Unsplash上的照片
介绍
Apache Kafka 是增长最快的产品之一,已被全球许多公司广泛采用。如果您在生产中使用 Kafka,能够监控和管理集群是非常重要的。
本文包含 Apache Kafka 集群最流行和最强大的监控工具的更新列表。您还可以找到我在几年前写的一篇文章中提出的旧的建议列表。
具体来说,在本文中,我们将介绍以下工具和服务,它们可以帮助您跨组织管理和监控 Kafka 集群的健康状况:
- 汇合控制中心和健康+
- 镜头
- 辛夫拉监视器(前卡夫卡监视器)
- 巡航控制
- CMAK(前卡夫卡经理人)
汇合控制中心和健康+

来源:合流网站
汇合控制中心是一个基于 web 的工具,它提供了一个便于集群监控和管理的用户界面。具体来说,您可以快速访问集群健康状况的概述,访问和观察消息、主题和模式注册服务,以及执行ksql查询。
从技术上来说,该工具受到收集生产者和消费者指标数据的组件、用于移动收集的指标的 Kafka 和用于分析流指标的控制中心应用服务器的损害。
【convergent Health+】是另一个可以用来管理和监控融合平台的工具(实际上是在融合平台 6.2 版本中引入的)。

汇流控制中心健康+监控仪表盘—来源: 汇流网站
具体来说,Health +可以帮助您配置基于规则的智能警报,您可以在特定端点(如电子邮件或 Slack)上接收通知。此外,您可以查看如上图所示的所有收集的指标,并将 Health+与其他监控工具(如 Prometheus)集成。
镜头
Lenses 提供了一个完整的 Kafka UI 工具,使开发人员和工程师能够监控 Kafka 基础设施的健康状况以及应用程序的性能。此外,该工具可用于实时配置警报,从而以有效的方式促进事件管理。

镜头监控工具—来源:镜头网站
Lenses Tool 还允许通过一个直观的用户界面进行故障排除,该用户界面允许您使用 SQL 查询 Kafka。

来源:镜片网站
你可以在他们的官网看到更多关于镜片定价的细节。
辛夫拉监视器(前卡夫卡监视器)
Xinfra Monitor 是 LinkedIn 开发的开源工具,用于在 Kafka 集群上配置和执行长期运行的系统测试。它帮助开发人员和管理员捕获通常很少观察到或者只有在很长一段时间后才能观察到的错误或退化。
此外,它还帮助您使用端到端管道来监控集群,这些管道收集端到端延迟、服务可用性、生产者和消费者可用性、消息丢失率等指标。
巡航控制
Cruise Control ,是另一个 LinkedIn 开源工具,帮助大规模运行 Kafka 集群,旨在解决可扩展性问题,如经纪人死亡和工作负载平衡。

Kafka 集群状态—来源: LinkedIn 工程博客
具体来说,该工具允许您监控和跟踪资源利用情况,查询集群状态并观察分区、副本和分布。此外,您还可以监控异常检测、配置警报和自我修复流程以及重新平衡。
此外,您还可以执行传统管理,如添加或删除代理、调整复制因子、重新平衡集群、修复离线副本以及触发首选领导者选举。

巡航控制计算的 Kafka 集群负载— 来源: LinkedIn 工程博客
CMAK(前卡夫卡经理人)
CMAK(Apache Kafka 的集群管理器)是一个帮助您管理 Kafka 集群的开源工具。
具体来说,该工具可以帮助您管理各种集群,如果您想要监视不同环境中的集群,这是非常方便的,如下所示。

CMAK 的集群管理—来源: GitHub
此外,CMAK 可以帮助您检查集群的状态,包括主题、消费者、偏移量、代理、副本和分区分布。

CMAK 话题列表—来源: GitHub
此外,该工具可以帮助您通过交互式用户界面删除主题、重新分配分区、调整分区号、更新主题配置和执行手动分区分配。

CMAK 的主题视图—来源: GitHub
该工具可以相当容易地进行配置——有关如何启动和运行的更多详细信息,请参考相关的文档部分。
最后的想法
在本文中,我们介绍了最常用的监控工具,这些工具可以用来有效地控制和管理 Apache Kafka 集群。
就我个人而言,我相信 Confluent——卡夫卡的最初创造者——提供了市场上最好的工具,但也有一定的成本。这意味着您可能负担不起这个特定监控服务的许可费用,因此您需要考虑本文中涉及的其他选项。请注意,Health+工具有一个免费层—有关其定价的更多详细信息,请参考 Confluent 的文档。
第二个最好的选择可能是镜头,这也需要付费许可证,但成本可能要低得多。如果你买不起许可证,那么 LinkedIn Cruise Control 和 CMAK 是足够好的解决方案,当涉及到集群管理和监控时,它们肯定会让你的生活更轻松。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。
你可能也会喜欢
https://betterprogramming.pub/how-to-fetch-specific-messages-in-apache-kafka-4133dad0b4b8 https://python.plainenglish.io/how-to-programmatically-create-topics-in-kafka-using-python-d8a22590ecde
卡夫卡不再需要动物园管理员了
2.8.0 版本让你提前接触到没有动物园管理员的卡夫卡

介绍
Apache Kafka 2.8.0 终于发布了,你现在可以提前使用 KIP-500,它消除了 Apache Zookeeper 的依赖性。相反,Kafka 现在依赖于内部 Raft 仲裁,可以通过 Kafka Raft 元数据模式激活。这一新功能简化了集群管理和基础设施管理,标志着 Kafka 自身的一个新时代。
没有动物园管理员的卡夫卡
在这篇文章中,我们将首先讨论为什么需要消除对 ZooKeeper 的依赖。此外,我们将讨论从 2.8.0 版本开始,KRaft mode如何取代 ZooKeeper,并探讨移除这种依赖性的影响以及 Kafka 本身将如何受益于这种增强。
什么是 KPI-500
直到现在,Apache ZooKeeper 还被 Kafka 用作元数据存储。分区和代理的元数据存储在 ZooKeeper 仲裁中,该仲裁也负责 Kafka 控制器的选举。
ZooKeeper 是 Kafka 的外部系统,这意味着它有自己的配置语法、管理工具和最佳实践。因此,如果您想要部署 Kafka 集群,那么您还必须管理、部署和监控 Zookeeper。由于这两个分布式系统需要不同的配置,复杂性增加,因此系统管理员更容易出错。拥有两个系统还会导致工作的重复,例如,为了启用安全特性,您必须将相关的配置应用于两个服务。
拥有外部元数据存储在资源方面是低效的,因为您需要运行额外的进程。再者,这也限制了卡夫卡本身的可扩展性。每次集群启动时,Kafka 控制器都必须从 ZooKeeper 加载集群的状态。
选举新的总监时,情况也是如此。考虑到元数据的数量会随着时间的推移而变得更大,这意味着加载此类元数据的效率会随着时间的推移而变得更低,从而导致高负载过程,并因此限制了集群可以存储的分区数量。
KPI 代表 Kafka 改进建议,KPI-500 介绍了无动物园管理员 Kafka 的基本架构。
介绍 Kafka Raft 元数据模式
2.8.0 版本引入了对无动物园管理员 Kafka 的早期访问,作为 KPI-500 的一部分。请注意,该实现已经部分完成,因此您不应该在生产环境中使用它。
在最新版本中,ZooKeeper 可以被一个内部 Raft 法定数量的控制器所取代。当 Kafka Raft 元数据模式启用时,Kafka 会将其元数据和配置存储到一个名为@metadata的主题中。该内部主题由内部仲裁管理,并在整个集群中复制。集群的节点现在可以充当代理、控制器或两者兼而有之(称为组合节点)。
当**KRaft mode** 启用时,只有少数选定的服务器可以充当控制器,这些服务器将构成内部法定人数。控制器可以处于活动或待机模式,如果当前活动的控制器服务器出现故障或关闭,最终将接管工作。
现在每个 Kafka 服务器都有一个额外的配置参数,叫做**process.roles**。该参数可以采用以下值:
broker:Kafka 服务器将充当代理controller:Kafka 服务器将作为内部 Raft 仲裁的控制器broker,controller:Kafka 服务器将同时作为法定人数的控制者和代理
注意,当根本没有提供process.roles时,假设集群将以 ZooKeeper 模式运行。因此,暂时process.roles配置参数是您可以激活KRaft mode的唯一方式。
此外,每个节点现在用其node.id标识,并且现在必须提供controller.quorum.voters配置参数,该参数相当于 ZooKeeper 模式中的zookeeper.connect。该参数用于识别内部仲裁的控制器服务器,数值格式为serverID@host:port, serverID@host:port, ...。
现在让我们假设在运行于KRaft mode的 Kafka 集群中,我们有 7 个代理和 3 个控制器。下面的代码片段演示了 Raft 仲裁中一个控制器服务器的配置示例。
process.roles=controller
node.id=1
listeners=CONTROLLER://controller-1-host:9092
controller.quorum.voters=1@controller-1-host:9092,2@controller-2-host:9092,3@controller-3-host:9092
同样,下面的配置演示了如何设置集群的一个代理:
process.roles=broker
node.id=4
listeners=PLAINTEXT://:9092
controller.quorum.voters=1@controller-1-host:9092,2@controller-2-host:9092,3@controller-3-host:9092
再见,动物园管理员
Apache ZooKeeper 依赖性的移除无疑是平台的一大进步。过去几年,整个社区(尤其是合流社区)都在朝着这个方向努力。最早的版本是整个 Kafka 社区的巨大努力,他们仍在努力改进,以便无动物园管理员的 Kafka 模式在今年内功能完整。
我们多年来一直朝着这个方向前进
— 杰森·古斯塔夫森@ 卡夫卡峰会 2019
Apache ZooKeeper 依赖性的消除简化了 Kafka 部署的基础设施管理。Kafka 和 ZooKeeper 是两种不同的服务——现在 Kafka 已经统一,因此它不依赖外部服务作为元数据存储,学习曲线将缩短,这最终将有助于扩大 Kafka 的采用范围。
此外,这一增强提供了一个更具可扩展性和健壮性的整体架构。如前所述,在 ZooKeeper 模式下,Kafka 必须将其元数据存储到 ZooKeeper 节点中。每次集群启动或控制器选举发生时,Kafka 控制器都必须从效率低下的外部服务中读取元数据。通过用这个内部 Raft 仲裁替换 ZooKeeper,部署现在可以支持更多的分区。
移除 ZooKeeper 依赖关系还可以支持具有单个节点的集群。当您想要测试 Kafka 作为概念验证的一部分时,您不再需要启动多个过程。
结论
对卡夫卡来说,摆脱对动物园管理员的依赖是一个巨大的进步。事实上,新的KRaft mode特性将扩展 Apache Kafka 的可伸缩性,并缩短学习曲线,因为现在团队再也不用担心 ZooKeeper 了。它也将使 Kafka 的配置和部署方式更加简单和高效。
除了 KPI-500 之外,Kafka 2.8.0 还提供了许多改进和错误修复,所以一定要看看发行说明。
最后,我想再次强调,这是目前的早期访问,这意味着它不应在生产环境中使用。
你可能也喜欢
https://betterprogramming.pub/how-to-fetch-specific-messages-in-apache-kafka-4133dad0b4b8
Kaggle 竞赛-为 AUC 为 0.94 的慈善机构寻找捐赠者
使用 Python 来验证随机森林、梯度增强和 XGBoost(使用 AUC)的性能,并构建最终模型来预测慈善机构的潜在捐赠者。

马库斯·温克勒在 Unsplash 上的照片
项目概述
该项目将采用 3 种监督算法,包括随机森林、梯度推进和 XGBoost,使用 1994 年美国人口普查数据准确模拟个人收入。然后,我将从初步结果中选择最佳候选算法,并进一步优化该算法以最佳地模拟数据。这个实现的目标是构建一个模型,准确预测一个人的收入是否超过 50,000 美元。这种任务可能出现在非营利机构中,这些机构依靠捐赠生存。了解个人的收入可以帮助非营利组织更好地了解需要多少捐赠,或者他们是否应该伸出援手。虽然很难直接从公共来源确定一个人的一般收入等级,但我们可以从其他公开的特征中推断出这个值。Kaggle 竞赛链接在这里。
https://www.kaggle.com/c/udacity-mlcharity-competition/overview
数据集概述
这个项目的数据集来自 UCI 机器学习库。Ron Kohavi 和 Barry Becker 在发表文章“提高朴素贝叶斯分类器的准确性:决策树混合”后捐赠了数据集。你可以在网上找到罗恩·科哈维的文章。
问题陈述
一家慈善机构想知道谁有可能捐款。作为一名数据科学家,我可以利用这个数据集和受监督的机器学习算法来预测慈善机构的潜在捐赠者。
过程
(在此查看完整代码)
第一步。评估
第二步。预处理
第三步。计算简单预测器的性能
第四步。选择 3 个合适的候选模型
第五步。创建训练和预测管道
步骤六。初始模型评估和挑选最佳模型
第七步。模型调谐
第八步。预处理来自 Kaggle 的测试数据
比赛结果
注意:这篇文章并不是要解释每一行代码,而是项目中最重要的部分。因此,您可能会发现一些部分只是结果的描述。如果你对代码本身感兴趣,请在这里勾选https://github.com/YuehHanChen/Finding_donors_for_a_charity/blob/main/Finding_Donors_For_A_Charity.ipynb。
现在,让我们开始吧!
第一步。评估
在使用一些基本的评估函数后,我得到了这样的信息:这个数据集有 14 列,45222 行,0 个缺失值。

****最后一列,收入,是目标变量。作者照片
功能说明:
- ****年龄:连续。
- ****工作类别:私人,自我雇佣非公司,自我雇佣公司,联邦政府,地方政府,州政府,无薪,从未工作。
- ****教育:学士、部分大学、11 年级、HS-grad、Prof-school、Assoc-acdm、Assoc-voc、9 年级、7-8 年级、12 年级、硕士、1-4 年级、10 年级、博士、5-6 年级、学前教育。
- ****教育编号:连续。
- 婚姻状况:已婚配偶、离婚、未婚、分居、丧偶、无配偶、无配偶。
- 职业:技术支持、工艺修理、其他服务、销售、行政管理、专业教授、清洁工、机器操作员、行政文员、农业渔业、运输搬运、私人服务、保安服务、武装部队。
- ****关系:妻子、亲生子女、丈夫、非家庭成员、其他亲属、未婚。
- 种族:黑人、白人、亚洲太平洋岛民、美洲印第安人、爱斯基摩人、其他。
- ****性别:女,男。
- ****资本收益:持续。
- ****资本损失:持续。
- ****每周小时数:连续。
- :美国、柬埔寨、英国、波多黎各、加拿大、德国、美国外围地区(关岛-USVI 等)、印度、日本、希腊、韩国、中国、古巴、伊朗、洪都拉斯、菲律宾、意大利、波兰、牙买加、越南、墨西哥、葡萄牙、爱尔兰、法国、多米尼加共和国、老挝、厄瓜多尔、台湾、海地、哥伦比亚、匈牙利、危地马拉、尼加拉瓜、苏格兰、泰国、南斯拉夫、萨尔瓦多、特立尼达和多巴哥&多巴哥、秘鲁、香港、荷兰。
参见分布

作者照片
正如我们所看到的,年龄、资本收益和资本损失的分布是向右倾斜的,所以稍后,我将使用对数变换对它们进行变换。
评估报告:
- 年龄、资本损失、资本收益向右倾斜
- 所有数字特征都应被标准化
- 目标变量应该映射到 1 和 0
- 所有分类特征都应该被一次性编码
第二步。预处理
预处理 1: 年龄,资本损失,资本收益偏右。
在进行对数变换后,它们变成了

作者照片
我们可以看到,他们变得更加集中,现在的时代更好,资本收益和资本损失稍微好一些。
预处理 2: 所有数字特征都应该被规范化
使用 Sklearn 的 MinMaxScaler 对所有数值特征进行归一化后,数据范围将在 1 到 0 之间。

作者照片
预处理 3: 目标变量应该映射成 1 和 0
对于目标变量收入,我使用了。映射函数将' > 50K '映射到 1 和'<=50K’ to 0. And the result looks like this

All the values become either 1 or 0. Photo by author
Preprocessing 4: ,所有分类特征都应该一键编码。
在最后一个数据预处理步骤中,我使用 pd.get_dummies()对分类变量进行一次性编码。
比如说。最初,“工作类别”变量有几个类别,包括私有、自雇员非公司、自雇员公司、联邦政府、地方政府、州政府、无薪和从未工作。这是“工作类”被一键编码后的样子。

One-hot 编码将一个列分成多个列,其中每个类别都有自己的列。如果那一行是 state_gov,就像第 1 行一样,那么 state_gov 的单元格中就会有 1—作者的照片。
第三步。计算简单预测器的性能
生成一个简单的预测器旨在显示一个没有任何智能的基础模型会是什么样子。因此,当你把你的报告提交给经理时,他们会把它与你的模型进行比较,看看它们是否真的增加了价值。
在现实世界中,理想情况下,你的基本模型要么是前一个模型的结果,要么是基于你希望改进的研究论文。当没有基准模型集时,你可以从获得比随机选择更好的结果开始。
这里,我设置了一个简单的预测器,它总是预测‘1’(也就是说,这个个体赚了超过 50k)。该模型将没有真否定(TN)或假否定(FN),因为我没有做出任何否定(“0”值)预测。因此,在这种情况下,我们的准确性变得与我们的精度相同(真阳性/(真阳性+假阳性)),因为我们用值“1”做出的每个预测都应该为“0”,但都变成了假阳性;因此,在这种情况下,我们的分母是我们拥有的记录总数。
在这场比赛中,我们将通过 ROC 曲线下的面积 AUC 来判断。因此,我将计算 AUC 和准确性,以在整个项目中验证模型。
对于天真预测者的准确性,由于我们有 11001 个真阳性和 44445 个全阳性,我们将得到 0.24的准确性。
AUC 是通过将所有预测结果(每个点属于阳性和阴性的概率)投影到一维线中来计算的。然后我们计算那条线上几个点的真阳性率和假阳性率。然后,它将所有这些点绘制成 2D 图表,你可以计算曲线下的面积。
所以,在这种情况下,由于所有的点都被预测为正,所以它们都聚集在线的右侧。当它计算中间或左侧的任何点时,它将获得 1 的真阳性率,因为所有真阳性都被正确分类,而假阳性率为 1,因为所有阴性点都被错误分类。并且很少有点具有(真阳性率,假阳性率)= (0,0),因为它在线的左侧。
所以当我们把许多(1,1)和(0,0)绘制成 2D 图时,我们会发现三角形面积等于 1/2,因为 111/2 = 1/2 。**

作者照片
简单预测的总结:
精度= 0.2475
曲线下面积= 0.5
稍后,我们可以将这些数字与我们将采用的模型的 AUC 和准确性进行比较,以查看这些模型是否真的增加了价值。
第四步。选择 3 个合适的候选模型
我列出了三种监督学习模型,包括随机森林、梯度推进和 XGBoost。对于每个选择的模型,我将回答以下问题:
该模型的优点是什么?
模型的弱点是什么?
随机森林
- 模型的优势是什么;什么时候表现好?
- 随机森林被认为是一种高度准确和稳健的方法,因为有大量的决策树参与了这一过程。
- 它不会遭受过拟合问题。主要原因是它采用了所有预测的平均值,这抵消了偏差。
- 该算法可用于分类和回归问题。
- 资源:(https://www . data camp . com/community/tutorials/random-forests-classifier-python)
2.模型的弱点是什么;什么时候表现差?
- 随机森林生成预测很慢,因为它有多个决策树。每当它做出预测时,森林中的所有树都必须预测相同的给定输入,然后对其进行投票。整个过程非常耗时。
- 与决策树相比,该模型很难解释,在决策树中,您可以通过遵循树中的路径来轻松做出决定。
- 资源:(https://www . data camp . com/community/tutorials/random-forests-classifier-python)
梯度推进树
- 模型的优势是什么;什么时候表现好?
- 分类和回归任务都非常高效
- 可以处理混合类型的特征,并且不需要预处理(https://towardsdatascience . com/gradient-boosted-decision-trees-explained-9259 BD 8205 af
2.模型的弱点是什么;什么时候表现差?
- GBDT 训练通常需要更长的时间,因为树是按顺序建立的。(https://corporatefinanciinstitute . com/resources/knowledge/other/boosting/)
- 需要仔细调整超参数
- 如果使用太多的树,可能会过拟合(n_estimators)
- 对异常值敏感(https://towards data science . com/gradient-boosted-decision-trees-explained-9259 BD 8205 af)
XGBoost
- 模型的优势是什么;什么时候表现好?
- 速度和性能:它最初是用 C++编写的,比其他集成分类器要快得多。
- 适用于大型数据集:因为核心 XGBoost 算法是可并行化的,所以它可以利用多核计算机的能力。它还可以在 GPU 上和计算机网络上并行化,这使得在大型数据集上进行训练变得可行。
- 它可以用于选择重要的特征。
- 需要较少的特征工程(不需要标准化数据,也可以很好地处理缺失值)
- 始终优于其他算法方法:它在各种机器学习基准数据集上表现出更好的性能。
- 各种各样的调优参数:XGBoost 内部有用于交叉验证、正则化、用户定义的目标函数、缺失值、树参数、Sklearn 兼容 API 等的参数。
- 离群值影响最小。
- 当数据混合了数字和分类特征或者只有数字特征时,它表现良好。
2.模型的弱点是什么;什么时候表现差?
- 如果参数调整不当,可能会过度拟合。
- 因为有太多的超参数,所以更难调整。
- 不适合用 XGBoost 的时候:图像识别,计算机视觉,自然语言处理,理解问题。
- 根据你对数据的了解,是什么让这个模型成为这个问题的一个很好的候选?
- XGBoost 是 Kaggle 比赛中的常胜将军。
- 它支持分类和回归问题。
第五步。创建训练和预测管道
这条管道将做五件事:训练,预测,记录训练/预测时间,计算准确性,以及计算 AUC。
代码如下:
第六步。初始模型评估和挑选最佳模型

作者照片
XGBoost 是最好的模型
- 我们可以看到,随机森林有点过拟合,因为它有一个高训练分数,但相对较低的测试分数。相比之下,XGBoost 表现最好,因为它获得了最高的测试分数,而且训练分数和测试分数几乎相同,这意味着它既没有欠拟合也没有过拟合。
- 虽然 XGBoost 在训练时间上花费了最多的时间,但它只需要 12 秒,所以在这个数据集中是可以接受的。
- XGBoost 比朴素预测器表现得更好,精确度为 0.2475,AUC 为 0.5。未经优化的 XGBoost 已经达到了 0.85 的精确度和 0.8 的 AUC。
用通俗的语言描述 XGBoost
想象一下,让一群高中生解决一组大学水平的数学问题。每个高中生都有一定程度的数学知识,但没有一个人在数学方面有惊人的天赋或糟糕的表现。学生轮流做题,老师做完题会给他们打分。此外,老师会告诉下一个学生前一个学生做错了什么问题,这样他们就会更注意那些问题。重复这个过程,直到每个学生都回答了问题。最后,老师更相信高分学生给出的答案,不太相信低分学生给出的答案,她自己回答问题。XGBoost 是老师。XGBoost 就是这么训练的。
下次其他大学水平的题给老师的时候,她就用这套记忆来答题,XGBoost 就是这么预测的。
第七步。模型调整

作者照片
这里,所有可能的参数集是 2⁵ = 32。所以,如果我使用网格搜索,它会运行 32 次来找到最好的一个。由于它将使用 300 或 400 个估值器进行测试,所以运行 32 次可能需要很长时间。
因此,我使用了随机搜索来寻找最佳的一组超参数,这将随机选择一组超参数进行测试。因此,它不能保证找到最好的,但它运行得更快。这是结果:

作者照片
我们可以看到准确性和 AUC 都有所增加。
第八步。预处理来自 Kaggle 的测试数据
为了正确地预处理测试集,我们必须遵循我们用于预处理训练集的相同过程,包括转换 年龄、资本损失、资本收益、归一化所有数字特征,以及一次性编码所有分类特征。
但是在这之前,我们必须先看看这个测试集是否有缺失值。

作者照片
正如我们所看到的,几乎每一列都有自己缺失的值,所以这里我考虑三种情况。首先,如果数字数据是倾斜的,那么我将使用来自训练集的同一列的中值来填充缺失的值。其次,如果数值数据大致呈正态分布,那么我将使用训练集中同一列的平均值来填充缺失值。最后一种情况是分类值。然后,我将使用在训练集中的相同列中出现最多的模式或类别来填充缺少的值。在填充缺失值后,我进行了与训练集相同的预处理过程。
在对数据进行预处理后,我将它们放入优化的 XGBoost 模型中,这是比赛结果。
Kaggle 比赛结果
在 212 支队伍中,我排在第 30 位!

作者照片
谢谢你看完!如果你对这个项目的完整代码感兴趣,请查看 my Github 。另外,我喜欢反馈。如果有什么不清楚的地方或者应该做得更好的地方,请联系我。下面是我的 LinkedIn
Kaggle 不是一个基地来源
作为数据科学家,我们的工作就是用真实、可操作的数据来讲述故事。基于错误数据的故事只是童话。

上一次您不得不为学校项目、商业项目或个人项目寻找和收集数据时,您会去哪里找呢?你是直接从你公司的某个人那里得到数据的吗?你有没有自己出去追踪一个有趣的数据集?
最重要的是——你拿到数据后,验证了数据的合法性吗?
我需要一个项目的分类数据集。这些数据可以是任何东西,所以我很自然地去 Kaggle 寻找一些很酷的数据集。我在航空公司乘客满意度上找到了这个数据集,这是一个非常丰富的分类数据集。

Kaggle 上的航空公司乘客满意度数据集—图片由作者拍摄
这是一个很棒的数据集。它有各种客户服务指标评级、一个二元目标变量和超过 130,000 行响应。这是 Kaggle 上的一个银牌数据集,理由很充分。它检查所有的盒子是否是一个有趣的数据集。
然而,我立即注意到,除了承认该数据是从位于这里的不同 Kaggle 数据集修改的之外,没有任何关于该数据的信息。

Kaggle 上的乘客满意度数据集—作者拍摄的图像
我去了约翰·d 上传的这个“原始”数据集。值得注意的是,这个数据集仍然没有归属,所以现在我去了谷歌。
在我的搜索中,我发现了两个潜在的数据来源。第一个是美国客户满意度指数,在其航空公司客户体验基准调查中有一个类似的独立变量列表。然而,他们的声明是“每年,ACSI 都会采访数百名乘客,询问他们最近的飞行经历”。几百是很好,但不是 130k。这是数据的来源吗?如果是这样,这些数据可能是从几十年的回复中收集的,因此不一定有用。
另一个潜在的数据来源是国际航空运输协会的 Airsat 乘客满意度基准。他们列出了类似的变量分组,但没有具体说明他们进行了多少次调查。
除了无法找到数据来源——最令人不安的是,有多少人使用这些没有来源的数据集作为重要项目的基础。我在一个同行评审的出版物中找到了一篇已发表文章的实例,该文章公开使用原始的“John D”数据集作为他们工作的基础,将其称为“Kaggle repository”。虽然这篇文章的目的更多的是关于方法而不是商业答案,但是底层数据仍然应该被验证和获得。《约翰·D·论卡格尔》不是资料来源。另一篇为《零售和消费者服务杂志》撰写的文章(我只能阅读摘要)提到了“一个包含超过 13.3 万名顾客反馈的数据集”。在不确定的情况下,这个特定的响应数字可疑地接近于清理过的银牌数据集,这个数据集引发了整个奇怪的兔子洞。
对航空公司满意度的任何搜索都会产生几个项目、文章和参考资料,这些项目、文章和参考资料都基于现在臭名昭著的(如果只是我自己认为的)航空公司乘客满意度数据集— 一个没有已知来源的数据集。
据我们所知,约翰·D 在一个下午心血来潮写了这个数据集。我们永远也不会知道,因为尽管在他的数据集的评论中有要求,他从来没有说明他的来源。现在这个数据集在互联网上永久存在,被合法出版物引用。
这正是错误信息传播的方式。没有来源的信息被当作合法的信息传播出去。当足够多的时候,它被认为是合法的,不需要确认。也许这个数据集是合法的——但如果不是呢?如果这个数据集向企业和世界提供了错误的,或者最多是可疑的信息,那该怎么办?
不要增加这个问题。了解你的数据来源。验证您的数据。仅使用来自已知来源的数据,并尽可能获得“第二意见”。为您的数据提供归属,并增加信心。
作为数据科学家,我们的工作就是用真实、可操作的数据来讲述故事。基于错误数据的故事只是童话。
参考资料:
1.TJ Klein 整理的 Kaggle 上的航空公司乘客满意度数据集
2.乘客满意度由 John D .上传的 Kaggle 数据集
使用机器学习预测三月疯狂
我是如何连续几年在卡格尔疯狂三月比赛中获得一枚单人金牌和两枚单人银牌的
整篇文章简而言之:
一个主要利用各队的队伍等级和形态来预测三月疯狂游戏胜负的梯度助推机。

图片来自本·好时在 Unsplash
疯狂三月是最大的年度大学生体育赛事,每年创收 10 亿美元。Kaggle 是世界上最大的数据科学家社区,拥有超过 1000 万用户。这篇文章解释了我的机器学习模型如何在 Kaggle 举办的三月疯狂预测大赛上连续几年获得 一个单人金奖和两个单人银奖 。
问题设置:
NCAAW 疯狂三月是一年一度的淘汰制大学女子篮球锦标赛,由 64 支球队组成。我们的问题是尽可能准确地预测每场可能比赛的结果概率(即 1 队击败 2 队的概率)。这些预测是在 64 支队伍确定之后,在比赛开始之前做出的。卡格勒根据他们的预测准确性在公共排行榜上排名,每天更新一次。因此,卡格勒观看比赛时知道他们的模型预测的是什么!具体而言,根据下面表示的对数损失函数来评估 Kagglers 的预测:

来源:图片来自 Kaggle 三月机器学习狂潮 2021 页
在最完美的情况下,百分百自信和正确是零分。相比之下,100%的自信和错误会受到无限的惩罚。例如,假设我们预测团队 1 击败团队 2 的概率为 80%,而我们的竞争对手预测为 90%。如果 1 队赢了,我们得到的处罚将比我们的竞争对手得到的略多。但是如果 1 队输了(即爆冷结果),我们得到的处罚将明显小于我们的竞争对手。
输入功能:
我们用来预测概率的特征主要是团队等级和形式。更多的功能和适当的细节将很快在下面提供!
团队评分:我们试图在比赛前用这个功能来衡量一个团队的实力。
表格特征:我们试图用这个特征来衡量一支球队在锦标赛中变得有多强。这种形式的特点是衡量比赛时一支队伍所代表的最强队伍的实力(即形式)。例如,亚利桑那爆冷击败康涅狄格,可以说是 2021 年锦标赛中最大的爆冷。这是三号种子(亚利桑那州)在最后四场比赛中击败一号种子(康涅狄格大学)。然而,第三个种子预计不会进入四强。粉笔模型预计第三种子将在甜蜜的 16 强中被第二种子击败,并预计只有第一种子留在最后四强。因此,这不是一场典型的三号种子对一号种子的比赛,这是一场变强的三号种子取代一号种子对一号种子的比赛。因此,与典型情况相比,第三种子有更好的机会击败第一种子。
方法:
上面解释的特征成为我们的梯度推进机器的输入特征。假设理解最小二乘回归,梯度推进机(GBM)可以直观地理解为一组序列回归。第一棵树相当于使用所有输入要素的简单回归,第二棵树是对第一棵树返回的残差的回归(同样使用所有输入要素)。我们逐步执行此操作,直到完成手动设置的树数。GBM 的具体解释可以在这里找到。
评估结果:
正如前面提到的和下面显示的,我们的模型在 2022 年的 NCAAW 三月疯狂卡格尔比赛中赢得了一枚单人金牌。我们的模特在 2019 年和 2021 年获得了个人银牌(2020 年的比赛因新冠肺炎而取消)。

ka ggle——在 MATLAB 中预测泰坦尼克号挑战的存活率
在本教程中,我将演示如何使用 MATLAB 来解决这个流行的机器学习挑战

1912 年 4 月 10 日,F.G.O .斯图尔特拍摄的皇家邮轮泰坦尼克号驶离南安普敦的照片,公共领域
这个 Kaggle 挑战的目标是创建一个机器学习模型,它能够预测泰坦尼克号上乘客的生存,给出他们的特征,如年龄,性别,票价,船票等级等。
本教程的大纲如下:
- 数据分析
- 特征工程
- 模型拟合
- 对测试集的预测
- 结论
- 未来方向
为什么选择 MATLAB?
在过去的几个月里,我探索了 MATLAB 中的机器学习工具箱,以解决各种任务,如回归、聚类、PCA 等。我喜欢它的模块化界面,每个功能都有很好的示例文档,这变得非常方便。因此,在这篇文章中,我分享了我的一些发现,希望对学术界有所帮助。
让我们开始…
1.探索性数据分析
读取数据集
>> Titanic_table = readtable('train.csv');
>> Titanic_data = (table2cell(Titanic_table));
列车组有 891 个乘客条目和 12 列。
现在,让我们看看我们的数据。 head 函数显示表格的顶行,类似于 Pandas 中的。
>> head(Titanic_table)

“幸存”列是我们需要预测的二元目标变量;其中 0-未幸存,1-幸存。
预测变量,即特征如下-
- Pclass:机票等级
- 性
- 年龄
- SibSp:兄弟姐妹、配偶以及乘客的数量
- Parch:父母、孩子以及乘客的数量
- 机票:机票号码
- 票价
- 客舱:客舱号
- 装船:装船港
“Pclass”变量表示社会经济地位。它有 3 个可能的值“1”、“2”、“3”,分别代表上层、中层和下层。
训练集中乘客的生存概率约为 38 %
现在,让我们根据不同的特征来想象生存-

- 男性乘客 577 人,女性乘客 314 人。
- 与男性的 18.90 % 相比,女性的生存概率更高,为 74.20 %

- 我们看到,机票等级越高的乘客生还的可能性越大。

- 儿童的存活率非常高,而 65 岁以上的人的存活率下降到 10 %左右(T21)。
- 最初的统计数据与我们的直觉相符,即我们的战略肯定是首先拯救妇女和儿童的生命。
2.特征工程
为了转换' 性别 ' 特征,我使用了 grp2idx 将分类值'男性'和'女性'分别转换为数字索引' 1 '和' 2 '。
“年龄特征的转换有两个步骤-
- 填补缺失条目-
% Check number of missing entries in the 'age' feature>> sum(isnan(age))
ans =
177
我们将用所有其他乘客的 平均 年龄来估算“年龄”特征中的缺失条目。即 29.61 年。我们还可以用其他一些方法来处理这些缺失的条目,这将在第 6 节中讨论。
- 分类到箱子里-
MATLAB 提供了一个 离散化 方法,可以用来将数据分组到 bin 或类别中。我用这种方法将年龄分为以下四个年龄组——“15 岁以下”、“15-30 岁”、“30-65 岁”和“65 岁以上”。
3.模型拟合
我们将看到 4 个分类器,即-
- 逻辑回归
- 决策树
- k 最近邻
- 随机森林
让我们从… 开始
逻辑回归
在 MATLAB 中,我们可以使用 fitglm 方法实现一个逻辑回归模型。
决策树
fitctree函数为给定的一组预测器和响应变量返回拟合的二元分类决策树。我们可以使用 view 方法来可视化我们的决策树,从而提供一个简单的解释。

修剪决策树是对抗过度拟合的有效策略。我已经使用了 cvloss 函数来寻找‘最佳级别’进行修剪。 修剪 函数返回修剪到该级别的树。
k 个最近邻居
classificationknn . fit函数用于拟合一个k-最近邻分类器。****

- 我已经执行了一次搜索,以找到邻居的最佳数量(N)。
- 上图显示 N=17 给出了最低的交叉验证损失。因此,我们可以选择 N=17。然而,对于 N=5 和 N=11,我们得到类似的损失。因此,我们可以用 N=5、11 和 17 进行实验,记住模型的复杂性和大 N 值过拟合的可能性。
- MATLAB 有一系列距离度量可供选择。例如,“城市街区”、“切比雪夫”、“汉明”等。默认值是“欧几里德”距离度量。
随机森林分类器
单个决策树往往会过度拟合。随机森林方法是一种装袋方法,在这种方法中,根据 bootstrap 样本拟合的深度树被组合起来,以产生具有较低方差的输出。
我们将使用 TreeBagger 类来实现一个随机森林分类器。

- 上图显示了当我们增加考虑中的树的数量时的袋外分类误差。这允许我们选择最优数量的决策树来创建集成。
- 我们可以使用OOBPermutedPredictorDeltaError属性来可视化每个特性的重要性。

我们模型的训练精度如下-
- 逻辑回归分析:78.34 %
- 决策树:80.47 %
- k 最近邻:79.80 %
- 随机森林:78.11 %
我们看到,在这种情况下,修剪后的决策树给出了最高的准确性,但是它容易过度拟合。让我们在测试集上找出准确度。
4.生成测试预测
测试集包括 418 个乘客条目和 11 列,没有“幸存”变量,我们将使用训练好的模型进行预测。
***>> head(Titanic_table_test)***

我们对测试数据集应用相同的特征工程步骤,并通过上述模型对其进行反馈,以生成预测。最后,我们创建一个. csv 文件提交给 Kaggle。片段展示了一个相同的例子。
决策树在测试集上给出了最高的准确率 78.947 % 。
5.结论
我们在 MATLAB 中看到了解决机器学习任务的一步一步的过程,从可视化数据集中的模式开始,选择和设计特征,训练多个分类器,到使用训练好的模型执行预测。
一些观察-
- 增加“年龄”特征中的箱数导致过度拟合。
- 增加一个计算为(票价/机票频率)的新特征并没有显著提高测试精度。
代码可用于未来开发此处。
6.进一步探索
- 可以应用其他策略来处理“年龄”特征中的缺失条目,例如使用中值年龄,或者家庭关系。例如,孩子的年龄可以近似为(父亲的年龄-25 岁)。****
- 包含更多的特性组合自然是我期待分析的下一步。
- 人们可以根据最初的数据统计和直觉来设计新的特性。这里的是一个读起来很有意思的分析。
- 由于我们有多个模型,模型集合值得一试。
Kaggle 社区讨论了许多这样的想法。这本笔记本对此做了很好的总结。
Kaggle 与真实世界

数据科学竞赛如何进行?
随着数据科学变得越来越普及,新手和专业人士都纷纷涌向在线竞赛,以获得技能,争夺奖项,并充实自己的简历。
以 Kaggle 为例,这是一个数据科学的在线社区,已经举办了十多年的比赛。自 2010 年创办以来,Kaggle 特色比赛的平均参赛队伍数量从不足 500 支增长到 2000 支左右。

图片作者。从 Kaggle 获取的数据。数字是近似值。
这种兴趣的急剧上升引出了一个问题——这些竞赛有多大价值,与解决现实世界中的问题相比如何?正如数据科学中经常出现的情况一样,你会发现这些问题不缺不同的答案,这取决于你问的是谁。
例如,看看下面 Quora 问题的几个答案:作为一名崭露头角的数据科学家,我是否应该投入时间参与 ka ggle…

图片作者。截图来自 Quora 。

图片作者。截图来自 Quora 。
两种截然不同的观点。显然这里有一些细微的差别,所以让我们试着解开它。
在这篇文章中,我将通过在数据科学项目的每个主要阶段比较 Kaggle 和真实世界来深入讨论。
阶段 1:定义问题
任何数据科学任务的第一步都是弄清楚要解决什么组织或业务问题,以及如何用数据对问题建模。对于机器学习,这意味着识别问题的类型(有监督/无监督),选择目标变量(如果有监督),并确定模型将如何用于驱动结果。
在现实世界中:这通常是数据科学中最困难也是最重要的阶段。为什么?因为如果你弄错了,你的模型再精确也没用。例如:
- 如果电子邮件渠道不能为你的企业带来任何收入,预测给客户发邮件的最佳时间是没有用的。
- 如果你没有相关的销售或营销策略来利用这些信息,识别关键的客户群是没有用的。
- 如果不管你做什么,那些顾客都会买同样多的东西,那么预测有最高购买倾向的顾客是没有用的。
如果没有对业务环境和组织现实的正确理解,数据科学家就不太可能确定正确的问题或这些问题的最佳解决方案。
在 Kaggle 上:别人替你做了这件事。每个竞赛都有详细的问题描述和评估部分。直接前进到 GO 并收集 200 美元。

第二阶段:数据工程
没有数据,就没有数据科学。没有干净的数据,只有糟糕的数据科学。因此,数据科学生命周期中的一个关键阶段是寻找、清理和组织解决问题所需的数据。
在现实世界中:构建和维护有用的数据湖和特征库需要花费很多心思。如果没有坚实的基础,集成新的数据源、构建机器学习问题以及将模型投入生产将变得非常困难。捷径会让你付出代价,因为它们会导致必须支付的错误和技术债务。
关于 Kaggle: 这取决于竞争对手,但数据工程的大部分工作通常会为你完成。每场比赛都会给你提供一些数据,所以你永远不会从头开始。
另一方面,Kaggle 确实为数据科学家提供了大量需要解决的数据工程问题,包括:
- 处理可能带来内存问题的大型数据集
- 必须以深思熟虑的方式将多个数据源结合在一起
- 围绕在哪个环境中处理数据做出决策(本地还是在 Kaggle 平台上)
数据科学家至少应该知道这些技能,如果不是非常熟悉的话。数据工程越先进越好。
虽然 Kaggle 提供了充分的机会来实践这些技能,但它并不总是激励最佳实践。Kaggle 参与者不会像在现实世界中那样为糟糕的代码“买单”。
</4-steps-to-start-practicing-sql-at-home-cb771beeca20>
阶段 3:特征工程
在解决问题和构建数据后,数据科学家通常会接受功能工程的任务,即获取有用的数据点,帮助模型做出更好的预测。
在现实世界中:如果你试图在你的组织中建立第一个模型来解决一个问题,你通常会想要限制你花费在特性工程上的时间。毕竟,当你仍然需要证明“好”其实就是好的时候,你并不想过度投资于“完美”。
另一方面,如果你正试图击败你的组织已经在使用的复杂的“冠军模型”,花更多的时间来获取数据和构建更好的功能可能是值得的。
还值得注意的是,在现实世界的数据科学中,有时理解哪些因素在驱动您的模型比设计产生小增量收益的功能更重要。
在 Kaggle 上:功能工程通常在你如何在排行榜上排名中扮演非常重要的角色。因为你经常与数千名其他数据科学家竞争,所以每一个增量都很重要。
虽然这通常不能反映真实世界,但它确实能帮助你发展两项非常重要的技能。首先,它训练你的大脑批判性地思考什么因素可能预示着一个特定的问题。这是一个重要的技能集,可能在现实世界中具有最长的寿命(换句话说,它可能是机器学习自动化的最后阶段之一)。第二,它迫使你做更多的数据工程,因为它要求你实际构建你所想象的特性。

阶段 4:建模和验证
这一阶段包括选择您要使用的模型,决定哪些功能可以进行最终切割,并建立一个验证方案以确保您以稳健的方式测量结果。
在现实世界中:选择合适的型号基于很多因素,包括:
- 模型需要有多“可解释”?
- 您正在处理什么类型的数据?
- 模型表现如何?
- 将该模型投入生产有多容易?
验证至关重要。如果不了解您的模型执行得有多好,您就无法 1)了解哪些增量变化实际上改进了您的模型,以及 2)确定您的模型是否会在现实世界中增加价值。
Kaggle 上的:ka ggler 最关心的是选择性能良好、能够处理他们正在处理的数据量的模型。
验证可能是 Kaggle 最能反映真实世界的地方。成功的 Kagglers 善于建立验证方案,在本地产生与在公共和私人排行榜上相同的结果。如果没有别的,Kaggle 教你如何在现实世界中建立健壮的模型验证。
第五阶段:模型实施
最后,但肯定的是,肯定不是最不重要的:将你的模型投入生产。这个阶段成败在此一举。如果没有使模型可用的代码或业务流程,就没有价值。
在现实世界中:对于频繁运行的模型,您必须构建最终的数据管道和基础设施,以便定期做出一致且可测量的预测。对于运行频率较低的模型,技术方面的“生产”可能较少,但仍然有一个关键的需求,即确定如何将模型结果集成到业务流程中,以做出更好的决策。
这基本上是免费的。作为一名卡格勒,你不必考虑你的模型在未来会被如何使用。您唯一需要担心的实现是提交您的代码,并确保它按照预期在排行榜上得分。
摘要
现在应该很清楚,Kaggle 与真实世界的数据科学不同。它几乎没有提供问题定义或模型实现方面的经验,而这些往往是机器学习最难的部分。它也不要求参与者编写干净的代码或遵循数据工程最佳实践。
然而,还应该清楚的是,Kaggle 可以为各个层次的数据科学家提供巨大的价值。操纵数据、管理内存限制、构建功能、设计强大的验证、选择模型,这些都是核心的、重要的数据科学技能,可以通过竞争来学习和磨练。
最后,我的回答是一个响亮的“是”。作为初露头角的数据科学家,你绝对应该将 Kaggle 作为学习和实践数据科学的众多工具之一。只要确保你意识到它的一些局限性。
P.S. →如果你想了解更多关于 SQL、Python、数据科学的知识,订阅我的 免费邮件列表 。
2021 年使用 Optuna 调整 LightGBM 超参数的 Kaggler 指南
充分发挥 LightGBM 型号的性能
关于 LightGBM 超参数以及如何使用 Optuna 调整它们的综合教程。

照片由 Pixabay 上的 像素组成。 除特别注明外,所有图片均为作者所有。
介绍
在上一篇文章中,我们讨论了 LightGBM 的基础知识,并创建了几乎在各个方面都胜过 XGBoost 的 LGBM 模型。本文关注任何机器学习项目的最后一个阶段——超参数调优(如果我们省略模型集成的话)。
首先,我们将看看最重要的 LGBM 超参数,按其影响程度和区域分组。然后,我们将看到一个使用 Optuna(下一代贝叶斯超参数调优框架)调优 LGBM 参数的实践示例。
最重要的是,我们将以类似于顶级 Kagglers 调整他们的 LGBM 模型的方式来实现这一点,这些模型取得了令人印象深刻的结果。
如果你是 LGBM 的新手,我强烈建议你阅读文章的第一部分。虽然我将简要解释 Optuna 是如何工作的,但我也建议阅读我关于它的单独文章,以便更好地理解这篇文章。
点击这里获取 Kaggle 上的文章的笔记本。
最重要参数概述
通常,大多数基于树的模型的超参数可以分为 4 类:
- 影响决策树的结构和学习的参数
- 影响训练速度的参数
- 更高精度的参数
- 对抗过度拟合的参数
大多数时候,这些类别有很多重叠,提高一个类别的效率可能会降低另一个类别的效率。这就是为什么手动调整它们是一个巨大的错误,应该避免。
如果给定足够好的参数网格,像 Optuna 这样的框架可以自动找到这些类别之间的“中间值”。
https://ibexorigin.medium.com/membership
获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:
https://alphasignal.ai/?referrer=Bex
控制树结构的超参数
如果你不熟悉决策树,可以看看 StatQuest 制作的这个传奇视频。
在 LGBM 中,控制树结构最重要的参数是num_leaves。顾名思义,它控制单个树中决策叶的数量。树的决策叶是“实际决策”发生的节点。
接下来是max_depth。max_depth越高,树的层次就越多,这使得树更加复杂,容易过度拟合。太低,你会吃不饱。尽管这听起来很难,但这是最容易调整的参数——只需选择 3 到 12 之间的值(这个范围在 Kaggle 上对任何数据集都适用)。
一旦确定了max_depth,调整num_leaves也很容易。LGBM 文档中给出了一个简单的公式——对num_leaves的最大限制应该是2^(max_depth)。这意味着num_leaves的最佳值在(23,212)或(8,4096)的范围内。
然而,num_leaves对 LGBM 学习的影响大于max_depth。这意味着您需要指定一个更保守的搜索范围,比如(20,3000)——这是我经常做的。
树的另一个重要结构参数是min_data_in_leaf。它的大小也与你是否过度节食有关。简单地说,min_data_in_leaf指定了一个叶中符合决策标准的最小观察值数量。
例如,如果决策叶检查一个特征是否大于 13,比如说,将min_data_in_leaf设置为 100 意味着只有当至少 100 个训练观察大于 13 时,我们才想要评估这个叶。这是我外行话中的要点。
min_data_in_leaf的最佳值取决于训练样本的数量和num_leaves。对于大型数据集,以百或千为单位设置一个值。
查看 LGBM 文档的本节了解更多详情。
超参数提高精确度
获得更高准确度的一个常见策略是使用许多决策树并降低学习率。换句话说,在 LGBM 中找到n_estimators和learning_rate的最佳组合。
n_estimators控制决策树的数量,而learning_rate是梯度下降的步长参数。
像 LGBM 这样的集成在迭代中构建树,每个新树都用于纠正以前树的“错误”。这种方法快速而强大,但容易过度拟合。
这就是为什么梯度增强集成有一个控制学习速度的learning_rate参数。典型值在 0.01 和 0.3 之间,但也可能超过这些值,特别是接近 0。
因此,这两个参数(n_estimators和learning_rate)的最佳设置是使用许多提前停止的树,并为learning_rate设置一个较低的值。我们稍后会看到一个例子。
您也可以将max_bin增加到默认值(255)以上,但同样存在过度拟合的风险。
查看 LGBM 文档的本节了解更多详情。
更多超参数来控制过度拟合
LGBM 也有重要的正则化参数。
lambda_l1和lambda_l2指定 L1 或 L2 正则化,像 XGBoost 的reg_lambda和reg_alpha。这些参数的最佳值更难调整,因为它们的大小与过度拟合没有直接关系。然而,对于两者来说,一个好的搜索范围是(0,100)。
接下来我们有min_gain_to_split,类似 XGBoost 的gamma。保守的搜索范围是(0,15)。它可以用作大参数网格中的额外正则化。
最后,我们有bagging_fraction和feature_fraction。bagging_fraction取(0,1)内的一个值,并指定用于训练每棵树的训练样本的百分比(与 XGBoost 中的subsample完全一样)。要使用该参数,还需要将bagging_freq设置为一个整数值,这里解释为。
feature_fraction指定训练每棵树时要采样的特征的百分比。所以,它也取(0,1)之间的一个值。
我们已经讨论了影响过拟合的其他参数(max_depth、num_leaves等)。)在前面的章节中。
在 Optuna 中创建搜索网格
Optuna 中的优化过程需要一个名为 objective 的函数:
- 包括要作为字典搜索的参数网格
- 创建一个模型来尝试超参数组合集
- 用单个候选集将模型拟合到数据
- 使用此模型生成预测
- 根据用户定义的指标对预测进行评分并返回
下面是它在代码中的样子:
在上面的objective函数中,我们还没有指定网格。
这是可选的,但我们正在交叉验证中进行培训。这确保了每个超参数候选集在完整数据上得到训练,并得到更稳健的评估。它也使我们能够使用早期停止。在最后一行,我们返回 CV 分数的平均值,这是我们想要优化的。
现在让我们专注于创建网格。我们将包括今天介绍的超参数及其推荐的搜索范围:
如果你不理解上面的网格或者
trial物体,可以看看我在 Optuna 上的文章。
创建 Optuna 研究并运行试验
是时候开始搜索了。下面是完整的目标函数供参考:
对于这个网格,我还添加了来自 Optuna 的integration模块的LightGBMPruningCallback。这个回调类很方便——它可以在对数据进行训练之前检测出没有希望的超参数集,从而显著减少搜索时间。
您应该将它传递给 LGBM 的callbacks下的fit方法,并设置trial对象和您用作参数的评估指标。
现在,让我们创建研究并运行一些试验:
搜索完成后,调用best_value和bast_params属性,会得到类似这样的输出:
结论
就是这样!你现在是 LGBM 的专业用户。如果你实现了这两篇文章中学到的东西,相信我,你已经比很多用 LightGBM 的 Kagglers 强了。
那是因为你对这个库的工作方式,它的参数代表什么有了更深的理解,并且熟练地调优了它们。这种类型的库基础知识总是比没有一点理解的猖獗的代码重用要好。
要从 pro 过渡到 master ,我建议花点时间在文档上。感谢您的阅读!
您可能也会感兴趣…



</tired-of-cliché-datasets-here-are-18-awesome-alternatives-from-all-domains-196913161ec9>
卡尔曼滤波:简单介绍
一个机器学习必须知道
高斯噪声下线性系统的最优在线学习算法

戈罗登科夫在摄影站拍摄的照片
如果动态系统是线性的且带有高斯噪声,则隐藏状态的最优估计器是卡尔曼滤波器。
这种在线学习算法是机器学习世界基础的一部分。在理解粒子过滤器等更复杂的主题之前,很好地理解它是很重要的。
在本文中,我将从卡尔曼滤波器的一个示例应用开始,然后我将描述算法本身,我将把它应用于一些简单的合成数据,最后,我将展示卡尔曼滤波器失败的地方。
应用示例
在工程领域,卡尔曼滤波器是减少传感器信号噪声的最常见模型之一。正如我们将会发现的,当数据中的噪声大致为高斯型时,这些模型非常有用。
尽管卡尔曼滤波器是一种强大的降噪工具,但它还可以有更多用途,下面是一个例子:
假设我们有一个喷气发动机,它的一个部件上有一条疲劳裂纹。我们正试图用这种部件上的应力传感器来监控裂纹长度。
让我们假设我们在每一种情况下都有裂缝的测量值。我们还假设裂纹长度随应力线性增长(实际上根据巴黎定律,实际上是裂纹扩展速率的对数随应力强度因子的对数线性增长)。
卡尔曼滤波器涉及以下变量:
- z:观察变量(我们试图预测的)
- x:隐藏状态变量(我们用来预测 Z 的变量,理想情况下与 Z 成线性关系)
在我们的例子中,观察变量是裂纹长度。我们隐藏的状态变量是压力。由于我们假设两者之间存在线性关系,并且如果我们假设噪声是高斯噪声,最佳估计器是卡尔曼滤波器!
卡尔曼滤波器
卡尔曼滤波器是一种在线学习算法。随着新数据的到来,该模型会按顺序更新其对权重的估计。记录方程式中下标的符号。当前时间步长被表示为 n(我们想要对其进行预测的时间步长)。
以前的状态
卡尔曼滤波器的最终目标是通过对隐藏状态变量 x 进行最佳估计来预测观察变量 Z 的下一次观察。然后,可以通过使用 x 对其进行重构来预测 Z 的下一次观察。

观察变量 Z 的估计由隐藏状态 x 的线性变换 H 给出。下标 n 表示当前时间步长。Xn|n-1 表示给定直到 n-1 的数据时在时间步长 n 的隐藏状态 X 的估计。
根据时间步长 n 处 Z 的估计值,我们可以用公式表示新息:

新息 Y 是下一个观察状态的预测和下一个状态的真实观察之间的差。
为了估计隐藏状态 X,卡尔曼滤波器假设从隐藏状态到观察变量的转换具有高斯噪声。在喷气发动机的例子中,测量装置可能由于裂纹长度的不准确测量而给系统增加噪声。这些误差被假定为高斯误差。
因此,每次新的观察值出现时,模型都会估计隐藏状态 X,并继续估计不确定性 p。它们一起参数化了观察变量估计值的概率密度函数。下一时间步的预测观测值将是最大似然估计值(平均值)。

第一个等式显示了给定前一隐藏状态时对隐藏状态的估计。f 是从前一状态估计到当前状态估计的转换函数。
第二个方程是不确定性 p 的更新估计,这是协方差矩阵,它是前一个状态的协方差矩阵的函数。
状态更新方程
到目前为止,我们已经公式化了给定数据直到前一时间步的状态(状态 n|n-1)。给定我们在时间步长 n(STATE n | n)接收到的新数据点,我们想要为新状态制定一个更新。
通过最小化均方误差,可以导出时间步长 n 的隐藏状态 X 和协方差 P 的最佳更新。

其中:

第一个等式是给定所有数据的隐藏状态 n 的更新。更新的 X 由权重的先前估计加上增益项乘以新息给出。这与递归最小二乘(RLS)在线学习算法中的更新结构相同。
时间步长 n 处的卡尔曼增益 K 由不确定性 P 的先前估计、线性函数 H 和新息协方差 s 的倒数给出
有了这些方程,我们现在可以实现我们自己的卡尔曼滤波器。
示例实现
将使用简单的自回归时间序列数据。卡尔曼滤波器将被实现并用于估计隐藏状态 X,然后预测 z 的下一个观测值。

上面看到的自回归时间序列的阶数将设为 2。v(n)表示添加到系统中的白噪声。使用随机初始化的权重 a,自回归时间序列通过将前两个点乘以权重来生成新点。

作者图片
以上是对隐藏状态 x 的估计。真实值显示为红色,卡尔曼估计显示为蓝色。如你所见,模型很快收敛到隐藏状态的近似值。由于加到信号中的高斯噪声,该模型从未完美地估计它。

作者图片
经过 200 次左右的观测后,模型可以准确地估计出未来的观测变量 Z。卡尔曼滤波器和其他在线学习算法最令人印象深刻的是它们的收敛速度。
当卡尔曼滤波器失效时
到目前为止,我们假设隐藏状态和观察状态之间的关系是线性的,我们看到这个模型工作得相当好。但是当我们把这种关系变成非线性关系时会发生什么。

作者图片
这些是隐藏状态 X 之一的卡尔曼滤波器的估计,该隐藏状态 X 以正弦波的形式随时间变化。该模型未能生成隐藏状态 x 的良好估计。此外,预测似乎落后于真实值。
在前面看到的方程中,有两个超参数我没有提到。q 是过程噪声协方差,R 是测量噪声方差。通过调整 R,我们可以使模型更快地适应隐藏状态的变化。调整 Q 允许控制模型对过程噪声的敏感程度。
即使调整了这些超参数,您也可以看到模型滞后于隐藏状态变量的变化,从而使其预测不太好。卡尔曼滤波器是线性系统的最佳算法,但是当隐藏状态变量和观察变量之间存在非线性关系时,这些模型往往表现不佳。
结论
卡尔曼滤波器非常强大,广泛用于各种领域,尤其是工程应用中的信号处理。
在上一篇文章中,我描述了一种最简单的在线学习算法,递归最小二乘(RLS)算法。卡尔曼滤波器将 RLS 算法向前推进了一步,它假设系统中存在高斯噪声。预测时,卡尔曼滤波器估计隐藏状态的均值和协方差。该算法实质上是在预测点周围构建一个分布,其平均值是最大似然估计值。
我们知道,当系统是非线性的时候,这个模型就失效了。然而,在现实生活中,大多数系统都是非线性的。在以后的文章中,我将探索在线学习中的非线性系统,以及该领域中最强大的模型之一:粒子过滤器。
感谢阅读
如果你喜欢的话,可以考虑 关注我 来获得更多像这样的文章!
如果您想访问 medium 上成千上万只对会员开放的故事,请考虑使用我的推荐链接注册:
https://diegounzuetaruedas.medium.com/membership
卡普兰-迈耶曲线解释道
数据科学基础
学习如何在 Python 中从头开始构建 KM 曲线以及其他两种方法
Kaplan-Meier 曲线是一种流行的生存分析工具,它有助于在数据不完整的情况下理解生存概率。在本帖中,我们将学习如何从头开始构建 Kaplan-Meier 曲线以获得更好的理解,然后看看使用 Python 中的生存分析库构建它的两种方法。

Ravi Roshan 在 Unsplash 上拍摄的照片
0.数据
让我们想象一下,我们有从 2020 年 9 月到 2021 年 6 月收集的数据,用于一项临床研究,以了解癌症患者的生存期。以下是参与这项假设研究的人的时间表:

左边的字母是参与者的唯一标识符|作者图片
我们将假想研究的数据集保持在较小的范围内,以便更容易密切监控该过程。黑色实心圆圈表示记录的最后一个数据条目。圆圈内的叉表示记录有事件(即死亡),而问号表示记录没有事件。更具体地说,有三种可能的情况。
- 发生事件:在研究期间发生事件(如记录 a 和 c
- 无事件:在研究结束时无事件(如记录 b 和 d)。
- 无事件:在终点前退出研究,且在参与研究时未发生事件(如记录 f 和 h )。
第二类和第三类记录被称为删截记录,更确切地说是右删截记录,因为我们对事件的信息不完整。
在上图中,我们看到横轴上有一个日历时间。现在,我们需要将日历时间转换为存活时间,相对于研究登记日期测量的 持续时间。存活时间在我们稍后将要熟悉的 Python 库中通常被称为持续时间;因此,从这里开始,我们将互换使用这些术语。

作者图片
使用下面的脚本,让我们导入我们需要的库,并为 9 条记录创建一个包含持续时间和事件的小数据帧:
# Data manipulation
import numpy as np
import pandas as pd
from string import ascii_lowercase# Visualisation
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='dark', context='talk')# Kaplan-Meier curve
from lifelines import KaplanMeierFitter
from sksurv.nonparametric import kaplan_meier_estimator# Create a toy dataframe
df = pd.DataFrame(data={'duration': [3,9,5,8,7,2,1,3,4],
'event': [1,0,1,0,1,0,1,0,0]},
index=list(ascii_lowercase[:9]))
df

事件栏:0 表示审查,1 表示有事件
1.我们自己从零开始建造
现在让我们熟悉一下概念知识。卡普兰-迈耶曲线是卡普兰-迈耶估计量的直观表示,它做出以下假设:
- 审查:经过审查的观察和未经审查的观察有着相同的生存前景。
- 研究进入时间:在研究早期和后期招募的观测值的存活概率相同。
- 事件时间:事件在规定的时间发生
卡普兰-迈耶估计量由以下公式定义:


有了这个公式,我们就可以求出给定时刻的生存概率。无论 i 从 1 还是 0 开始都没有区别,因为 0 时刻的生存概率是 1。如果我们仔细观察这个公式,我们会注意到括号内的内容是捕获存活比例(即 1-死亡比例)。
让我们用这个公式找出前三个持续时间的生存概率:

在研究进行一个月后,我们有 9 名参与者处于危险中,一名参与者已经死亡。因此,d1 = 1,n1 = 9。

在研究的两个月后,我们有 8 名参与者处于危险中,没有人死亡。因此,d2 = 0,n = 8。如你所见,当持续时间没有事件时,生存概率与前一个持续时间相同。因此,如果一个持续时间没有事件,我们可以跳过计算,使用前一个生存时间的生存概率。

在研究的第三个月,我们有 7 个记录处于危险中,1 个死亡,存活概率下降到 0.76。这个等式现在变得越来越长,越来越繁琐。我们可以将公式改写为以下更简单的形式:

使用这个公式,计算更加简洁:

这三个例子说明了概率是如何估计的。与其重复计算其余部分,不如让我们将逻辑转换成 Python 脚本,并计算所有持续时间的生存概率:
# Prepare unique durations in ascending order
durations = df.sort_values('duration')['duration'].unique()# Initialise the table
columns = ['duration', 'n_at_risk', 'n_events',
'survival_probability']
km = pd.DataFrame(columns=columns, dtype=np.number)
km = km.append(pd.DataFrame([[0, df.shape[0], 0, 1]],
columns=columns))# Calculate survival probability for each duration
for i, t in enumerate(durations):
n = np.sum(df['duration']>=t)
d = np.sum((df['duration']==t) & (df['event']==1))
s = (1 - d / n) * km.loc[i, 'survival_probability']
km = km.append(pd.DataFrame([[t, n, d, s]],
index=[i+1],
columns=columns))
km

卡普兰-迈耶曲线需要生存概率和持续时间栏。现在让我们绘制曲线,因为我们已经准备好了输入。
plt.figure(figsize=(8,4))
sns.lineplot(data=km, x='duration', y='survival_probability',
drawstyle='steps-post')
plt.ylim(0,1.1)
plt.title("Kaplan-Meier curve");

瞧,我们刚刚自己绘制了曲线。从零开始构建曲线有望帮助你理解潜在的逻辑。已经学会了如何自己构建曲线,让我们来学习绘制卡普兰-迈耶曲线的更实用的方法。我们将熟悉两个提供现成解决方案的库。
2.使用生命线
Lifeline 是 Python 中一个易于使用的生存分析库。卡普兰-迈耶曲线可使用KaplanMeierFitter对象绘制成几条线:
kmf = KaplanMeierFitter()
kmf.fit(df['duration'], df['event'])plt.figure(figsize=(8,4))
kmf.plot()
plt.title("Kaplan-Meier curve");

从拟合的对象中,我们还可以通过访问survival_function_属性来查看生存概率:
kmf.survival_function_

我们还可以提取事件表,它类似于我们在第 1 节中构建的一个表。
kmf.event_table

列''观察'与第 1 节表格中的列' n _ 事件'相同。此外,两个表中的“风险”和“n 风险”列是相同的。
有了生命线,绘制曲线和检查估计器的细节变得很容易。
3.使用 scikit-survival
另一个有用的生存分析库是 scikit-survival 。顾名思义,它与 scikit-learn 协调工作。利用kaplan_meier_estimator()可以得到持续时间和生存概率。一旦我们有了曲线所需的输入,我们可以使用任何可视化库来绘制它。由于我们在第 1 节中使用了 seaborn ,我们将看看使用 matplotlib 绘图的另一种方法:
duration, survival_probability = kaplan_meier_estimator(df['event']==1, df['duration'])
plt.figure(figsize=(8,4))
plt.step(x=duration, y=survival_probability, where="post")
plt.ylim(0,1.1)
plt.xlabel("Survival time (months)")
plt.ylabel("Survival probability")
plt.title("Kaplan-Meier curve");

至此,您已经学习了为卡普兰-迈耶曲线准备输入的基本逻辑,并熟悉了绘制曲线的几种不同方法!

Bruce Hong 在 Unsplash 上的照片
您想要访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果你使用 我的推荐链接成为会员,你的一部分会费会直接去支持我。
感谢您阅读这篇文章。如果你感兴趣,这里有我的一些其他帖子的链接:
◼️ ROC 曲线解释
◼️ 有用的 IPython 魔法命令
◼️ 从零开始学习 Python 的 5 个技巧
◼️ 用这些技巧组织你的 Jupyter 笔记本
◼️️ 在熊猫中编写 5 个常见的 SQL 查询
再见🏃💨
kats:Python 中分析时间序列数据的通用框架
预测、检测变化点、异常,并获得时间序列中的关键统计数据
动机
时间序列分析是数据科学中的一个有用领域,它允许您了解关键统计数据、检测回归、异常和预测未来趋势。
然而,这些时间序列技术通常由不同的库实现。有没有一种方法可以让你在一个库中获得所有这些技术?这就是 Kats 派上用场的时候。

作者图片
什么是 Kats?
Kats 是一个轻量级的、易于使用的、通用的框架,用 Python 来执行时间序列分析,由脸书研究院开发。您可以将 Kats 视为 Python 中时间序列分析的一站式商店。
要安装 Kats,请键入:
pip install --upgrade pip
pip install kats==0.1 ax-platform==0.2.3 statsmodels==0.12.2
为了了解 Kats 做了什么,我们将使用这个框架来分析 Kaggle 上的 StackOverflow 问题计数数据。从下载数据和读取数据开始。
现在我们来分析一下与 Python 相关的 StackOverflow 问题计数。数据被分成一个训练集和一个测试集来评估预测。
将数据转换成时间序列
首先构建一个时间序列对象。我们使用time_col_name='month'来指定时间列。
要绘制数据,调用plot方法:

作者图片
酷!看起来关于 Python 的问题数量逐年上升。我们能预测它未来 30 天的趋势吗?是的,我们可以和 Kats 一起做。
预测
Kats 目前支持以下 10 种预测模型:
- 线性的
- 二次的
- ARIMA
- 萨里玛
- 霍尔特-温特斯
- 先知
- AR-Net
- LSTM
- 希腊字母的第八字
- 增值转销公司
让我们试试这些模型中的两个。
脸书先知
首先使用 Prophet 模型进行预测:
可视化预测:

作者图片
酷!让我们通过与测试数据进行比较来评估预测。

作者图片
预报似乎很好地遵循了观测结果!
霍尔特-温特斯
我们将尝试的下一个模型是 Holt-Winters。霍尔特-温特斯法是一种捕捉季节性的方法。下面是如何使用霍尔特温特斯方法与 Kats。

作者图片
找到所有 Kats 的模型的 API在这里。
检测变化点
你是否曾经希望精确地指出你的时间序列中发生统计意义上的显著变化的时间?

作者图片
Kats 允许您使用 CUSUM 算法来检测变化点。Cusum 是一种检测时间序列中均值上移/下移的方法。
让我们看看如何检测 Kats 中的变化点。
The change point is on 2013-02-01 00:00:00

作者图片
酷!我们来试着检测一下 StackOverflow 的问题计数的其他类别的变化点。
首先创建一个函数来检测主题提供的变化点。
机器学习:
The change point is on 2015-12-01 00:00:00

作者图片
神经网络:
The change point is on 2015-11-01 00:00:00

作者图片
深度学习:
The change point is on 2016-09-01 00:00:00

作者图片
Jupyter:
The change point is on 2015-07-01 00:00:00

作者图片
情节地:
The change point is on 2016-02-01 00:00:00

作者图片
你看到一般的模式了吗?StackOverflow 上与数据科学、机器学习和深度学习相关的类别的问题计数方式的转变似乎是在 2015-2016 年左右!
这段时间周围发生了什么吸引开发者注意的事情?如果你有这个问题的答案,请在评论中发表。
离群点检测
当你看 NLP 的时间序列时,你看到了什么?

作者图片
是的,你说得对。从 2018 年到 2019 年,NLP 的问题数量有所下降。
问题数量的下降是一个异常值。检测异常值是很重要的,因为它们会给下游处理带来问题。
然而,通过查看数据来发现异常值并不总是高效和容易的。幸运的是,Kats 还允许您检测时间序列中的异常值!
用 Kats 检测异常值只需要 2 行代码。
The outliers range from 2018-01-01 00:00:00 to 2019-03-01 00:00:00
酷!结果证实了我们从上面的图中看到的。
时间序列特征
除了时间序列的统计数据之外,您可能还有其他感兴趣的特征,如线性度、趋势强度、季节性强度、季节性参数等。
Kats 允许您通过TsFeatures找到关于时间序列特性的重要信息:
厉害!
结论
恭喜你!您刚刚学习了如何使用 Kats 来预测、检测变化点、检测异常值和提取时间序列特征。希望这篇文章能给你解决有趣问题的动力,从你的时间序列中提取有价值的信息。
请在此随意使用源代码:
https://github.com/khuyentran1401/Data-science/blob/master/time_series/kats_examples/kats.ipynb
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 Twitter 上联系我。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
💔-tools-to-track-and-visualize-the-execution-of-your-python-code-666a153e435e> [## 3 个跟踪和可视化 Python 代码执行的工具
towardsdatascience.com](/3-tools-to-track-and-visualize-the-execution-of-your-python-code-666a153e435e)
kedro——可再生数据科学项目的 Python 框架
使用 Kedro 创建可维护的模块化数据科学管道
动机
您是否曾经将数据传递给一系列函数和类,却不知道输出是什么样的?

作者图片
您可以尝试保存数据,然后在 Jupyter 笔记本中检查数据,以确保输出与您预期的一致。这种方法可行,但是很麻烦。
另一个常见问题是,当查看包含创建和执行函数的代码的 Python 脚本时,很难理解函数之间的关系。
随着项目的发展,你的代码看起来更加复杂,更加难以理解。
如果您能像下面这样可视化不同函数的输入和输出是如何连接的,那不是更好吗?

作者图片
这就是 Kedro 派上用场的时候。
凯卓是什么?
Kedro 是一个开源的 Python 框架,用于创建可复制的、可维护的、模块化的数据科学代码。它从软件工程最佳实践中借用概念,并将它们应用于机器学习代码。
Kedro 允许您:
- 从千篇一律的模板中创建数据科学
- 创建数据科学管道
- 切开管道
- 模块化管道
- 通过 YAML 文件配置您的数据和参数
- 在 Jupyter 笔记本中轻松分析节点的输出
- 可视化您的管道
- 为您的项目创建文档
在本文中,我将逐一介绍这些特性,并解释它们如何对您的数据科学项目有所帮助。
要安装 Kedro,请键入:
pip install kedro
建立一个数据科学项目
从千篇一律的模板中创建数据科学
您是否考虑过如何构建您的数据科学项目,使其符合逻辑并合理标准化?如果能在一行代码中创建一个定义良好的标准项目结构不是很好吗?
使用 Kedro 可以轻松做到这一点。安装 Kedro 后,您可以使用以下命令创建一个新的空项目:
$ kedro new
在完成一系列问题后,将创建一个新项目,其结构如下:

作者图片
如果我们从更高的层次来看项目结构,我们可以看到有 5 个主要目录:

作者图片
conf:存储配置文件data:存储数据docs:存储项目文档logs:存储日志文件notebooks:储存 Jupyter 笔记本src:存储主代码
安装依赖项
Kedro 在使用之前需要一些基本的依赖项。这些依赖关系在src/requirements.txt中指定。要安装这些依赖项,请键入:
$ kedro install
运行管道所需的所有依赖项都将安装在您的环境中。
既然我们学习了如何建立一个数据科学项目,那么让我们来理解如何用 Kedro 创建一个管道。
创建管道
要创建新管道,请键入:
$ kedro pipeline create <NAME>
由于数据科学项目通常有两个步骤:数据处理和模型训练,我们将创建一个名为data_engineer的管道和一个名为data_science的管道:
$ kedro pipeline create data_engineering
$ kedro pipeline create data_science
这两个管道目录将被创建在src/project_name下:

作者图片
每个管道由 4 个文件组成:
__init__.pyREADME.md:指定管道信息node.py:包含节点pipeline.py:包含管道
结节
管道由多个节点组成。每个节点都是一个 Python 函数。
对于每个节点,都有输入和输出:
节点get_classes的可视化:

作者图片
可以使用None、字符串、字符串列表或字典来指定每个节点的输入和输出。注意,这些字符串是抽象名称,而不是真实值。
名字为什么有用?如果我们知道每个函数的输入和输出的名称,我们可以通过调用它的名称来轻松地获取特定的输入或输出。因此,在你的代码中有更少的模糊性。

作者图片
你可以在这里找到所有节点定义语法。
管道
管道由一系列节点组成。它将一个节点的输出连接到另一个节点的输入。
例如,在下面的代码中,'classes'(函数get_classes的输出)和'encoded_data'(函数encode_categorical_columns的输出)被用作函数split_data的输入。
数据目录位于conf/base/catalog.yml下。
上方管道的可视化:

作者图片
注册并运行管道
现在我们有了节点和管道,让我们在文件src/project_name/pipeline_registry.py中注册这些管道:
注册管道后,我们可以使用以下命令运行这些管道:
$ kedro run
如果您只想运行一个特定的管道,将--pipeline=<NAME>添加到命令kedro run中:
$ kedro run --pipeline=de
酷!
切开管道
如果您希望只运行管道的一部分,可以对管道进行切片。切割管线的四个选项是:
--from-nodes:从某些节点开始运行管道--to-nodes:运行管道,直到到达某些节点--from-inputs:从产生特定输入的节点开始运行管道--to-outputs:运行流水线,直到到达产生一定输出的节点
举个例子,
$ kedro run --to-nodes=encode_categorical_columns
…允许您运行管道,直到到达节点encode_categorical_columns。
模块化管道
有时,您可能希望为不同的目的重用同一个管道。Kedro 允许您创建模块化管道,这些管道是隔离的,可以重用。
例如,您可以编写一个名为“烹饪管道”的管道,而不是编写两个单独的管道“烹饪午餐管道”和“烹饪晚餐管道”。
然后,通过用新值切换“烹饪管道”的输入和输出,将“烹饪管道”转换为“烹饪肉类管道”和“烹饪蔬菜管道”。

作者图片
模块化管道很好,因为它们是可移植的,更容易开发、测试和维护。在这里找到关于如何模块化你的 Kedro 管道的说明。
通过 YAML 文件配置您的参数和数据
因素
Kedro 还允许您使用 YAML 文件指定函数的参数。这非常好,因为您可以从一个文件中查看所有参数,而无需深入源代码。
要用配置文件配置您的项目,首先将用于data_engineering管道的参数放入conf/base/parameters/data_engineering.yml文件中。
现在,从管道访问参数很简单。我们所需要做的就是在我们想要访问的参数名称前添加params:。
在下面的例子中,我们使用params:test_data_ratio从配置文件中访问参数test_data_ratio。
数据目录
现在你可能想知道:我们如何从管道中访问数据?
Kedro 允许你用数据目录加载和保存数据。数据目录位于conf/base/catalog.yml下。
数据目录是一个配置文件,允许您指定数据类型,以及数据保存的位置。
例如,为了保存来自encode_categorical_columns节点的encoded_data输出,
…我们可以将名称encoded_data插入到conf/base/catalog.yml文件中。在encoded_data下,我们指定数据集的类型及其位置。
pandas.CSVDataSet告诉 Kedro 我们想将encoded_data保存为 CSV 格式,并用熊猫加载。Kedro 还支持其他数据集类型,如 pickle、parquet、excel、plot、Spark、SQL 等。在这里找到 Kedro 支持的所有数据集。
使用数据目录来管理数据的加载和保存非常好,因为您可以指定:
- 每个文件的位置
- 数据是如何保存和加载的
…只编辑一个文件。下次当您忘记数据集的位置时,可以查看这个配置文件来查找它们的信息。
从 Jupyter 笔记本中加载数据目录和参数
加载数据目录
你是否曾经想要快速检查 Jupyter 笔记本上某个函数的输出?通常,您需要首先保存数据:
…然后将其载入 Jupyter 笔记本:

作者图片
使用 Kedro,保存和加载数据不需要额外的代码。要启动 Kedro 的 Jupyter 会话,请键入:
$ kedro jupyter notebook
在运行产生在catalog.yml文件中指定的输出encoded_data的流水线之后,
…我们可以使用catalog.load轻松地将数据加载到笔记本电脑中:
如果要指定如何保存和加载输出encoded_data,在encoded_data下添加load_args和save_args。
请注意,上述配置相当于:
负载参数
src/base内的所有参数也可以通过context.params轻松加载。

作者图片
运行管道
有时,您可能想要试验新的 Python 函数,并在笔记本中观察它们的输出。幸运的是,Kedro 允许您在笔记本内部运行一个管道:
为了快速测试,您还可以将 Jupyter 笔记本中的功能转换成 Kedro 节点。
可视化您的管道
如果您对管道的结构感到困惑,可以使用 kedro-viz 可视化整个管道。从安装 kedro-viz 开始:
pip install kedro-viz
然后键入:
$ kedro viz
…可视化您的管道。一个网站将在您的浏览器中自动打开。您应该会看到类似下面的内容:

作者图片
可视化捕捉数据集和节点之间的关系。单击一个节点将为您提供关于该节点的更多信息,如其参数、输入、输出、文件路径和代码。

作者 GIF
为项目创建文档
记录您的项目使您的团队更容易理解您的项目以及如何使用您的代码。Kedro 使您可以轻松地基于项目的代码结构创建文档,并包含代码中定义的任何文档字符串。
要为您的项目创建文档,请键入:
$ kedro build-docs
并且您的项目的文档将会在docs/build/html下自动创建!您可以通过打开docs/build/html/index.html或运行以下命令来浏览文档:
$ kedro build-docs --open
…在构建后自动打开文档。
您的文档应该类似于下图:

作者图片

作者图片
结论
恭喜你!您刚刚学习了如何使用 Kedro 创建可重复和可维护的数据科学项目。学习 Kedro 可能需要一点时间,但是一旦用 Kedro 建立了数据科学,您会发现维护和更新您的项目不再那么困难。
我希望这篇文章能给你在现有或未来的数据科学项目中使用 Kedro 的动力。
本文中演示项目的源代码可以在这里找到:
https://github.com/khuyentran1401/kedro_demo
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以通过 LinkedIn 和 Twitter 与我联系。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
Kedro 手把手:建立自己的人口统计图谱。角。2:建筑足迹分类
如何使用 OpenStreetMap 和带有 kedro pipeline 的开放政府数据构建自己的简单人口地图集

简而言之,建立分类管道。作者图片
本系列试图使用 kedro pipeline 构建一个端到端的数据产品:从收集数据、预处理到报告和可视化结果。虽然这个项目关注的是德国,但是这些方法也可以用来为世界上的其他地方创建一个简单的人口地图集。

项目流程图——4 条管道。作者图片
本文讨论的是第三条管线(建筑物 _ 分类)。首先,我们将介绍在处理来自 OSM 的建筑物足迹数据时的两个挑战: 完整性 和 正确性 。然后,我们将浏览试图解决正确性挑战的模块(将正确的建筑类型分配给占地面积)。该过程可以总结为 4 个步骤:
- 为聚类生成附加特征(总面积、矩形、多边形旋转函数、邻近距离矩阵)
- 使用 HDBSCAN 算法基于邻近度将足迹分组到构建模块中****
- 将托布勒地理定律应用到中,为足迹分配类型
GitHub 链接到项目(工作进行中)
**https://github.com/o0oBluePhoenixo0o/CheapAtlas **
目录
1 完整性和正确性
— 3.1 完整性
— 3.2 正确性&托布勒定律
2 建筑足迹分类流水线
— 2.1 生成建筑特征
— 2.2 用 HDBSCAN 进行建筑块分割
— 2.3 建筑类型分类— XGBoost
3 综述
1 完整性和正确性
由于 OSM (OpenStreetMap)是一个 VGI 平台(志愿者地理信息),社区自愿跟踪和标记建筑物。因此,这导致了两大挑战:
- 完整性——该位置的建筑足迹数量完全包含在数据中
- 正确性——准确的建筑类型被正确标记
这个系列,重点是“正确”。因此,我们将而不是在介绍之后过多地进入【完整性】****

两大挑战。作者图片
1.1 完整性
2017 年,麦吉尔研究比较了 OSM 和官方政府数据的完整性,并得出结论,OSM 的数据在全球范围内完成了 83%(大部分西方国家的街道网络都已完全绘制)。
然而,建筑物足迹完整性评估是另一回事。该领域的研究有几种类型:从将 OSM 与官方政府地理数据进行比较[1,2]到用深度学习从卫星/无人机图像中提取足迹[3](如 SpaceNet 1 & 2 建筑检测竞赛)。但是如上所述,本文不会在这个时间点讨论这个挑战的解决方案。
kedro pipeline(或任何机器学习工作流)的好处是,您可以在以后通过修补节点和管道来重新面对这一挑战
在 Medium 上,如果您在搜索框中输入“建筑足迹”,会有很多教程和讨论。亚当·范·艾顿、托德·斯塔维什在 SpaceNet challenge 上的一些著名文章。同样来自 Romain Candy 和 Lucas Suryana 关于构建有效的“足迹检测器”。
**https://medium.com/the-downlinq/building-extraction-with-yolt2-and-spacenet-data-a926f9ffac4f https://medium.com/the-downlinq/spacenet-winning-implementations-and-new-imagery-release-55f738e14253 https://medium.com/picterra/how-to-make-a-building-footprint-detector-768045a15bcc https://medium.com/@lucaselbert/building-footprint-extraction-in-a-dense-area-with-maskrcnn-jakarta-indonesia-3bc529d141b5
1.2 正确性与托布勒定律
来自 OSM 的建筑足迹由社区自愿标记。在某些地区,标签率可以达到 100%,但在其他地区,许多建筑没有标签。从我们的第二条管道 ( 数据 _ 准备 ) 的“幼稚分类”来看,仍然有巨大的脚印被设定为“待分类”

第二条管道的结果:仍然有多个未标记的建筑。作者形象
根据托布勒的地理第一定律[7],“一切事物都与其他事物相关,但近处的事物比远处的事物更相关。”这是空间相关性和空间自相关基本概念的基础。
“彼此靠近的建筑通常属于同一类型”
将这一点转化为与我们面临的挑战相关的东西,我们可以说,彼此靠近的建筑往往属于同一类型。因此,可以有把握地假设街区的建筑足迹与有很高的相似性。
2 建筑足迹分类管道

简而言之,构建分类管道。作者形象
这条管道的过程可以概括为 4 个步骤:
- 为聚类生成附加特征(总面积、矩形、多边形旋转函数、邻近距离矩阵)
- 使用 HDBSCAN 算法将足迹分组到构造块中
- 使用三个特征将足迹分类为建筑类型:形状、大小和建筑块。比较多个机器学习算法的结果。
与之前的管道相同,上面的每一步都将被转换成节点然后插入带有输入的主管道。由于我们将遍历德国(~10k 个直辖市)的每个区域,所以没有必要定义“输出”。每个节点被设计为扫描输入文件夹中的建筑物数据,直接在文件上执行操作,并独立地将输出保存到“输出路径”。
从 数据 _ 准备 部分了解到,许多城市的住宅建筑足迹为 0(近 2000 个城市的官方数据与 OSM 的数据相差 100%)
为了弥补“分类”足迹数据太少的区域,我决定从市级(约 1 万个组)到区级(400 个组)聚合数据集。

AGS 关键字(市政关键字)的含义。作者图片
函数来聚合并获取地区级的建筑占地面积数据。作者图片
2.1 生成建筑足迹功能

建筑占地面积的特征。作者图片
为了准备建筑分类任务,我们需要从现有构件生成其他要素:
2.1.1 尺寸
表面区域基本上是足迹多边形区域。在之前的第二个管道数据准备中,来自 GeoFabrik&transition API 的整合数据集让我们对我们可以从 OSM 收获的东西有了一个总体的了解。其中一个组成部分是几何——它是构建建筑足迹多边形形状的点的集合。利用这一点,我们可以计算出所有可用建筑面积的大小。
2.1.2 可用尺寸
我们可以利用的另一个组件是“building_levels”。我们可以通过以下方式计算总可用大小:
可用面积=建筑 _ 层数* 面积(表面积)
2.1.3 形状
在形态分析中,测量建筑物形状的标准方法是使用轮廓线多边形的矩形度。计算矩形的标准方法是获得大小(足迹面积)与其最小边界框(MBB) 的面积之比
矩形=尺寸/ MMB
2.2 用(H)DBSCAN 进行构件分段
在论文“城市街区中基于邻近度的建筑物分组”中,作者使用了两种不同的方法来评估将建筑物分组到城市街区中的四种算法。其结论是,DBSCAN(基于密度的带噪声应用空间聚类)和 ASCDT(基于 Delaunay 三角剖分的自适应空间聚类算法)表现最好,并且它们的复杂程度不难实现。因此,在这个项目中,我实现了hdb scan——DBS can 的扩展版本,用于对我们在 OSM 的建筑足迹进行聚类。
2.2.1 不使用 K-means 的理由
想到聚类,k-means 通常会马上弹出 第一个答案 。就像算法本身一样,k-means 的设计目的是最小化方差。
K-means 被认为是聚类的标准算法;然而,这并不意味着所有的聚类问题都可以很好地使用它
由于数据是纬度,经度格式==> 非线性,最坏的情况是 k-means 永远不会收敛(即使有哈弗线距离)。为了避免这个问题,我们应该使用一种能够处理任意距离函数的算法,特别是测地距离函数,如层次聚类、PAM、CLARA、OPTICS 和 DBSCAN。[5]

k-means vs DBS can byNHS ipster
2.2.2 HDBSCAN
HDBSCAN 是由 Campello、Moulavi 和 Sander 开发的聚类算法[6]。它扩展了 DBSCAN,将它转换成一个层次聚类算法,然后使用一种技术来提取一个基于平面聚类的稳定聚类。因为形成的簇不是基于半径的,所以它们可以是非圆形的格式。因此,考虑到轮廓线边界不是圆形,它更适合地理分析。这是我们将用于对建筑足迹进行分组的算法。
因为形成的簇不是基于半径的,所以它们可以是非圆形的格式。因此,考虑到轮廓线边界不是圆形,它更适合地理分析。
另一本更好理解 HDBSCAN 的好书是佩佩·贝尔巴
我们应该关注 HDBSCAN 的 3 个主要参数:
**min_cluster_size** = minimum number of footprints that can be assigned to a "block"
**cluster_selection_epsilon** = same as the epsilon metric for DBSCAN, Two points are considered neighbors if the distance between the two points is below the threshold epsilon.**min_samples** = The minimum number of neighbors a given point should have in order to be classified as a core point. **It’s important to note that the point itself is included in the minimum number of samples.**
除此之外,我们还需要为邻近矩阵设置度量。因为我们处理的是地理空间数据,而不是欧几里德距离,所以最好使用哈弗辛距离,它测量给定纬度和经度的球体上两点之间的距离:
**metric** = ’haversine’, # haversine distance on earth surface
我们将遵循文献[4]中的 ε = 3(足迹之间的距离为 3 米)和 MinPts = 2

市政建设的基石。作者图片
当在 kedro 中运行节点时,它从市一级收集数据,为每个区执行 HDBSCAN,并将输出保存在 04_feature 文件夹中。

2.3 建筑类型分类— XGBoost
现在我们已经创建了足够的建筑足迹特征,让我们为建筑类型构建一个分类器。与之前相同,此节点将遍历 building data 文件夹,基于区级数据训练机器学习模型,并最终将模型应用于未分类的足迹。我们将使用的 3 个特征是形状(矩形)、大小(表面积)和构建模块(来自 HDBSCAN) 。
为了选择哪种算法来建立机器学习模型,我拿出了 10 个超过 50k 足迹/区的区,并在其上训练不同的模型。
因为我们只关心“住宅”类型。问题从多类分类(多种类型的足迹)转换为非住宅与住宅
比较指出使用 XGBoost 会产生最好的结果:

足迹超过 50,000 的 10 个区的分类模型比较。作者图片
运行模拟和创建图表的代码如下。然而,这部分是在笔记本中完成的,并没有放到 kedro pipeline 的最终生产中。
对于参数,您可以尝试优化每个地区的参数,但由于我们正在对 400 多个地区进行培训和应用模型,因此我决定使用基本参数。
Vishal Morde 在 XGBoost 上的一篇精彩帖子
还测试了具有和不具有“构建块”功能的 XGBoost 分类器,以显示不准确性的差异。

不带“building_block”特性的 XGBoost

以“building_block”为特性的 XGBoost
该步骤使我们能够以高置信度将更多的“待分类”足迹分类到住宅中。从这两张图可以看出对比。执行 XGBoost 后,“蓝色”图例(待分类)的面积急剧下降。

在 XGBoost 分类器之前。作者图片

在 XGBoost 分类器之后。作者图片
3 总结
在本文中,我已经引导您完成了第三条管道 建筑分类 ,它将建筑分组为街区,并将足迹分类为住宅类型。现在,一旦我们完成了从第一条到第三条管道的运行,数据集就可以与人口统计数据集成了。在下一篇文章中,最终的 pipelineresidents _ allocation将把人们“分配”到住宅建筑中,并将结果可视化,这样我们就可以得到完整的人口统计图集。
感谢阅读!如果你能留下回复,我会很高兴,我们可以进一步讨论这个话题。
参考
[1] Helbich,m .和 Christof Amelunxen (2012 年)。OpenStreetMap 和专有地理数据的位置精度的比较空间分析。[在线]研究之门。可从以下网址获取:https://www . research gate . net/publication/267857078 _ Comparative _ Spatial _ Analysis _ of _ Positional _ Accuracy _ of _ OpenStreetMap _ and _ Proprietary _ Geodata【2020 年 12 月 29 日获取】。
[2] Brovelli,文学硕士,Minghini,文学硕士,Molinari,文学硕士和 Zamboni,G. (2016)。通过自动同源对检测评估 OPENSTREETMAP 建筑物图层的位置精度:方法和实例研究。国际摄影测量、遥感和空间信息科学档案馆,【在线】XLI-B2,第 615–620 页。可在:https://re.public.polimi.it/handle/11311/1009698【2020 年 12 月 29 日获取】。
[3]刘,刘平,刘,刘,石,杨,徐,张,杨(2019)。通过空间剩余初始卷积神经网络从高分辨率图像提取建筑物足迹。遥感,【在线】11(7),第 830 页。可在:https://www.mdpi.com/2072-4292/11/7/830【2020 年 12 月 29 日获取】。
[4]sinan·切廷卡亚、梅利赫·巴萨拉纳和伯格哈特(2015 年)。基于邻近度的城市街区建筑物分组:四种算法的比较。[在线]研究之门。可在:https://www . researchgate . net/publication/271901065 _ Proximity-based _ grouping _ of _ buildings _ in _ urban _ blocks _ A _ comparison _ of _ four _ algorithms【2021 年 1 月 2 日访问】。
[5]埃斯特,M. (2019)。一种基于密度的算法,用于在带有噪声的大型空间数据库中发现聚类。[在线]Psu.edu。在:https://citeseerx.ist.psu.edu/viewdoc/summary?发售 doi = 10 . 1 . 1 . 121 . 9220【2021 年 1 月 2 日获取】。
[6]麦金尼斯、希利和阿斯特尔斯(2017 年)。hdbscan:基于层次密度的聚类。[在线]研究之门。可从以下网址获得:https://www . research gate . net/publication/315508524 _ hdb scan _ hierarchy _ density _ based _ clustering【2021 年 1 月 6 日获取】。
[7]t . w . r(1970)。模拟底特律地区城市发展的电脑电影。经济地理,【在线】46 期,第 234–240 页。可用时间:https://www.jstor.org/stable/143141?origin=crossref&seq = 1【2021 年 1 月 14 日获取】。
[8]范,齐普夫,a .和傅青(2014)。基于城市形态分析的 OpenStreetMap 上建筑类型的估计。[在线]研究之门。可从以下网址获取:https://www . research gate . net/publication/278196777 _ Estimation _ of _ Building _ Types _ on _ OpenStreetMap _ Based _ on _ Urban _ Morphology _ Analysis【2021 年 1 月 14 日获取】。
**
保持简单,保持线性:时间序列的线性回归模型
入门
预测多伦多电力需求数据的简单线性回归模型
介绍
电力需求预测对于运营电力市场和/或受电力市场影响的任何组织都至关重要。电力储存技术没有跟上当前的生产水平,任何剩余的电力都被浪费掉,甚至亏本出售。因此,这些组织必须做出准确的预测。为了实现这一点,从传统的(S)ARIMA(X)到更先进的递归神经网络,有大量的时间序列预测技术可用。(S)ARIMA(X)模型不能处理多重季节性,而 LSTMs 和神经网络具有很高的准确性,但更难解释。
在本文中,我将使用简单的线性回归模型来预测多伦多的电力需求。线性模型非常容易解释,包括构建置信区间在内的一些统计分析可以轻松完成。
影响电力消耗的因素有几个,我在以前的文章中已经提供了详细的分析。也就是说,这里提供了理解当前文章所需的所有信息。
数据来源
独立电力系统运营商(IESO)是一个非营利组织,负责运营安大略省的电力市场。从 2003 年到现在的每小时数据,可以在他们的网站上找到。为了便于分析,我使用了一个简单的网络抓取代码来提取最近几年(2017 年至今)的每小时数据。我们还将使用从天气统计中提取的每小时温度数据。
探索性数据分析
从上述来源收集和组织数据并提取附加特征,我们获得了以下数据框,其中包含 2017 年 1 月 1 日至 2021 年 1 月 18 日的 35496 个小时点。

图 1:具有 11 个特征的最终数据帧
- 时间戳: 当天的日期和时间
- 温度 ( C) : 多伦多气象站记录的温度
- 需求(MWh):**IESO 记录的每小时电力需求
- 年份: 记载分的年份
- 月: 记载分的月份
- dayofweek: 用数字表示的一周中的某一天(0-星期日,1-星期一…)
- 日: 一年中的某一天
- 小时: 一天中的小时
- temp_index: 【热】如果温度>15°C,否则“不热”
- hour_index: 早上 7 点到晚上 10 点之间的“觉醒时间”,否则为“睡眠时间”
- week_index: 对工作日和周末进行分类
- dst _ index:【DST】如果使用夏令时,则为“DST”,否则为“NoDST”
与平日相比,周末和公共假日期间的电力需求相对较低。因此,为了这个分析的目的,我将把假日视为周末。
处理缺失值
需求数据中没有缺失点(IESO 维护得非常好),而温度列中有大约 0.02%的数据缺失。因为我们处理的是每小时的数据,而温度的变化在几个小时内并不显著,所以我们可以用前一个小时的值来填充缺失的数据。用专业术语来说,这叫做向前填充。
可视化数据
预期温度和需求之间的关系是合理的。空调系统使用的增加往往会增加夏季的需求,而供暖系统的使用会增加冬季的需求。在多伦多,大部分供暖需求是通过使用天然气锅炉来满足的,因此冬季的电力需求峰值比夏季小。这种温度和需求行为(2017 年至今)如下图所示。

图 2:温度和需求的散点图
我们已经可以想象通过从上图中分离大约 15°C 的温度来拟合两个线性模型。但是,在此之前,让我们看看影响需求的其他一些因素。

图 3:基于各种因素的温度与需求
我们可以观察到,温度高于 15°C 时,需求与温度呈正相关,低于 15°C 时,需求与温度呈轻度负相关。我们还可以根据一天中的具体时间水平拆分需求,如图 3 右上角的图所示。这是有道理的,因为我们预计上午 7 点到晚上 10 点的需求会更高。无论是工作日还是周末,睡眠时间(晚上 11 点至早上 6 点)的需求都会很小。

图 4:八个类别的温度与需求
因此,我们可以将温度与需求曲线分为八类,如上所示,基于三种划分:(工作日/周末、醒着时间/睡觉时间、热/不热)。在每个类别中几乎可以观察到线性趋势,相关系数的值如下所示。

图 5:第八类的相关系数
因此,我们将电力需求预测问题简化为八个线性回归问题,同时将温度、一天中的时间、一周中的日期和季节考虑在内。
在从事这个项目时,我了解到文献中的这种方法被称为线性模型树[ source ],是决策树和线性回归的结合。在某种意义上,它类似于决策树回归,我们将数据分成几组,但不是选择平均值作为每个类别的预测值,而是运行线性回归。
预测模型
我们将数据分为训练集(2017–2020)和测试集(2021)。我们用三年的数据来预测 2021 年前 18 天的电力需求。我们从基线模型开始,其中预测值只是上一年(2020 年)的值。
在接下来的所有预测图中,我将使用黑色实线表示真实需求,橙色虚线表示预测,蓝色阴影区域表示 95%的预测区间。
模型 1:基线模型

图 6:2021 年基线模型预测
基线模型的预测非常差,均方根误差(RMSE)为 520 MWh。从图 6 中我们可以看到,1 月 1 日的性能相当好,但是随着时间的推移,性能越来越差。这是因为元旦是一个公共假日,预测也是相似的。除此之外,在 2020 年和 2021 年初,工作日和周末不在同一天。我们知道周末期间的需求明显低于平日。因此,稍微好一点的模型(基线模型 II)可以通过改变日期以匹配周末来实现。
模式 2:基线模式二

图 7:2021 年基线模型 II 预测
在这个模型中,我们可以看到预测明显优于基线模型,RMSE 为 348 兆瓦时。该模型考虑了工作日和周末需求的差异。虽然这个模型比基线模型好,但我们可以用简单的线性回归模型获得更高的性能。
模型 3:线性回归(8)
如上所述,我们将建立八个线性模型,每个类别一个。具体来说,使用岭回归,每个模型的系数如下所示。

图 8:线性回归(8)系数
Hot (temp_index)的斜率始终为正,而 NotHot 的斜率始终为负。这是由于正相关和负相关的性质。截距在工作日明显更高,而斜率在周末更高。这表明工作日的耗电量更高,但周末对温度的依赖性更高。一个潜在的解释可能是周末期间家用空调的使用率较高。

图 9:2021 年的线性回归(8)模型预测
该型号的 RMSE 约为 344 MWh,仅略好于基准型号 II。与基线模型 II 相比,该模型更好地捕捉到了总体趋势,但未能捕捉到每日峰值。这是有意义的,因为对于一天中的一个小时,我们只给了模型两个类别;(早上七时至晚上十时)及(晚上十一时至早上六时)。从模型的角度来看,高峰可能在早上 7 点到晚上 10 点之间。从供应商的角度来看,捕捉高峰时段尤为重要。因此,为了改进模型,我们可以将一天中的一个小时分成两个以上的类别。
在下一个模型中,我们使用五个这样的类别,即清晨(12 am 到 6 am)、早晨(6 am 到 10 am)、中午(10 am 到 3 pm)、晚上(3pm 到 8 pm)和夜晚(8 pm 到 12 am)。
模型 4:线性回归(20)

图 10:一天中五类时间的温度与需求
温度与需求散点图如上所示。同样,我们可以根据热/不热、工作日/周末以及一天中的五个类别来划分这些数据。因此,我们现在有 252 = 20 个部分,在每个类别中,我们将拟合一个线性模型(山脊)。
Pandas groupby 是我最喜欢的 Python 操作之一。使用 groupby 操作运行岭回归并获得 20 组系数是极其容易的。为此,我们首先定义一个函数,该函数接收训练数据,重排行并返回回归系数。然后我们使用 groupby 操作,后面跟着应用函数,如下图所示。
**def** Ridge_model(data):
"""
Based on the provided data, this function returns the
coefficients of the ridge regression.
input: the training data
output: ridge regression coefficients
"""
data = data.sample(frac=1,random_state=42)
x = data['temperature'].values.reshape(-1,1)
y = data['demand'].values.reshape(-1,1)
model = Ridge().fit(x, y)
**return** (round(model.intercept_,3),round(model.coef_,3))data_17_20.groupby(['temp_index','hour_index_1','week_index']).apply(Ridge_model)display(pd.DataFrame(ridge_coef_2,columns=['Regression Coefficients (Intercept,Slope)']))

图 11:线性回归(20)系数

图 12:2021 年的线性回归(20)模型预测
就 RMSE (222 兆瓦时)而言,其性能优于之前的任何型号。它现在能够捕捉每日峰值以及整体趋势。
有没有更好的模式?当然有。如果我们使用 24 个类别,一个小时一个类别,而不是五个类别呢?使用 24 个类别,我们最终得到 2242 = 96 个模型。
模型 5:线性回归(96)
我们现在用 96 个线性模型来模拟电力需求。按照与前面模型类似的方法,我们可以获得 96 组岭回归系数。为了简洁起见,下面只给出了系数的一个例子。如需完整的表格,请随意使用我在 GitHub repo 中提供的代码。

图 13:线性回归(96)系数

图 14:2021 年的线性回归(96)模型预测
这种型号的 RMSE 大约为 140 兆瓦时。在上图中,我们可以观察预测,以完美地捕捉每小时的模式和每天的趋势。
模型 6:二次多项式回归(96)
在某些类别中,我们看到了与线性行为的轻微偏差。在这些情况下,高阶多项式会更适合。在本节中,我将使用二阶多项式来拟合温度和需求数据。

图 15:计数在 96 个类别中的分布
我们在 96 个类别中的每个类别中至少有 100 个数据点,平均值约为 365,我们正在拟合每个类别中的简单二次多项式回归。这应该消除任何过度拟合的担忧。

图 16:2021 年多项式回归 2 (96)模型预测
该型号的 RMSE 为 136 MWh,仅比线性(96)型号略高。
车型对比

图 17:本文中所有模型的比较
预测 RMSE 从 519 减少到 136 兆瓦时。在百分比误差方面,我们将其从 9.25%降低到 2.42%。我还提供了计算时间,以表明在这个时代训练 96 个线性模型只需要几分之一秒。
多项式次数 2 (96)是一个人能达到的最佳性能吗?绝对不行。这仅仅是一个线性模型(在 1,x,x 中是线性的),误差约为 2.4%。使用更复杂的技术,如 SARIMAX(带外源输入的季节性自回归综合移动平均)、脸书预言家、XGBoost、RNN(递归神经网络)和 LSTM(长短期记忆)来预测需求,可以提高性能。
重新访问预测间隔
作为从业者,预测的实际值并不包含太多的信息。他们理解任何时间序列预测中包含的不确定性,因此对他们来说,查看预测区间比实际预测更有意义。95%的预测区间告诉我们,大约 95%的时间预测值都落在这个范围内。此处显示的代码片段用于计算预测的预测间隔。
**def** pred_interval(prediction,test_data,test_predictions,alpha=0.95):
"""
Obtain the prediction interval for each of the prediction
Input: single prediction, entire test data, test set predictions
Output: Prediction intervals and the actual prediction
"""
y_test = test_data['demand']
test_predictions = np.array(test_predictions) *# Calculate the sum of squares of the residuals*
err = np.sum(np.square((y_test - test_predictions)))*#* *Estimate the standard error*
std = np.sqrt((1 / (y_test.shape[0] - 2)) * err)
*# Compute the z-score*
z = stats.norm.ppf(1 - (1-alpha)/2) *# Calculate the interval*
interval = z*std
**return** [prediction-interval,prediction,prediction+interval

图 18:最佳模型的 2021 年预测区间
基于这些预测区间,从业者可以确定电力生产的速率。对他们来说,这个情节激发了快乐,而不是实际的预测。
结论
在本文中,我们使用线性模型来预测多伦多的电力需求。有几种模型可以提供更好的性能,但使用线性模型的优势在于:
- 我们根据领域知识(如温度、一天中的时间、工作日/周末等)来划分类别。因此,在每个类别中解释这些回归模型是非常容易的。
- 线性模型训练起来更快。如前所述,训练 96 个线性模型的 CPU 时间仅为 0.2 秒左右。由于训练时间如此之短,因此可以实时建模、部署和重新训练。
- 线性模型不需要像神经网络或 SARIMAX 那样多的数据来训练。后一种模型也消耗大量时间来调整超参数。
- 这里介绍的线性模型考虑了每年和每天的季节性。年度季节性是通过温度和热/不热类别获得的,而每日季节性取决于在一天中的小时选择的类别数量(2、5 或 24)。
令人印象深刻的是,简单的线性回归可以提供可解释的良好结果。希望你们从这篇文章中学到了很多。所有的分析都是用 Python 完成的,相关的代码可以在我的 GitHub repo 中找到。请在这里分享你的想法,或者在 LinkedIn 上与我联系。
感谢阅读!
参考
- 【https://ieso.ca/en/Power-Data/Data-Directory
- 基于加拿大环境和气候变化数据
- https://www.timeanddate.com
- 时间序列分析 Nptel
- 时间序列分析和建模 AIEngineering
使用 Black & Pylint & Git Hooks 和预提交保持代码干净

图片来自 Pexels 公司的 Pixabay
合作开发不可或缺的工具
编码可能是一项非常困难的任务,尤其是在与不同的开发人员一起工作的项目中。团队中的每个成员都有自己的编码方式,这会导致非常异构的脚本。
这就是为什么拥有一个类似的代码格式化程序和代码摘要以便让 git 提交更干净是很重要的。这可以在分段和提交阶段之间或在 CI/CD 链期间执行。
在本文中,我们将看到如何使用 git 挂钩作为预提交步骤来实现这一点。
目录
总结如下:
- 黑色
- Pylint
- 作为 Git Hooks 的预提交
黑色
Black 是故意限制样式配置的 python 代码格式化程序。它让你的代码更清晰,这样你就可以更专注于内容。由于 diffs 尽可能小,所以代码审查也更有效。
可以使用以下命令行安装:
pip install black
您可以通过键入以下内容在任何 python 文件上运行 black:
Black pathtofile.py

作者形象
可以使用文件 pyproject.toml 略微配置黑色,该文件应放在项目的根中。以下是此文件的示例:
[tool.black]
line-length = 88
target-version = [‘py36’, ‘py37’, ‘py38’]
include = ‘\.pyi?$’
exclude = '''
/(
\.toml
|\.sh
|\.git
|\.ini
|Dockerfile
|Jenkinfile
)/
'''
例如,我们可以选择代码行的长度,还可以设置哪些文件不应该格式化的扩展。
Pylint
pyrint是一个“Python 静态代码分析工具”,用于评估已开发脚本的质量。它会引导团队采用相同的标准。
可以使用以下命令行安装 Pylint:
pip install pylint
要评估给定脚本的编码质量,可以运行:
pylint pathtofile.py
NB :为了在整个项目中运行 pylint,您的存储库应该包括一个 init。py 文件。
与 Black 一样,Pylint 也可以使用文件进行配置。pyrintc也放置在项目的根上
[MASTER]
jobs=4 #number of processes to use[BASIC]
good-names=nameOfYourProject #names to be considered ok[pre-commit-hook]
command=custom_pylint
disable=E0401, C0301
有关配置的更多详细信息,请参见页面。
作为 Git Hooks 的预提交
Git 挂钩是在运行 git 操作时启动的已定义脚本。
挂钩有两种类型:
- 客户端挂钩:提交合并后运行
- 服务器端挂钩:在网络操作上运行,例如在推送提交之后
在本文中,我们将重点关注客户端工作流,这些工作流可以用下图来描述:

作者形象
在 git 存储库中,钩子放在中。git/hooks/ 。例如,通过将以下代码行添加到 Json 设置中,可以在 VSCode 中可视化它们:
"files.exclude": {
"**/.git": false
}

作者图片
预提交的设置
要将提交前操作添加到存储库中,请执行以下操作:
1。在文件夹中创建文件。git/hooks/ 。名称中不应包含任何扩展名。
**2。在文件中添加 bash 命令。在我们的案例中:
*#!/bin/shblack .
python lint.py -p ../projectName/*
第一行应用黑色格式化程序,第二行对项目的每个 python 文件应用林挺。你可以从这个链接下载 lint.py 文件:
*import argparse
import logging
from pylint.lint import Run
logging.getLogger().setLevel(logging.INFO)
parser = argparse.ArgumentParser(prog="LINT")
parser.add_argument('-p',
'--path',
help='path to directory you want to run pylint | '
'Default: %(default)s | '
'Type: %(type)s ',
default='./src',
type=str)
parser.add_argument('-t',
'--threshold',
help='score threshold to fail pylint runner | '
'Default: %(default)s | '
'Type: %(type)s ',
default=**7**,
type=float)
args = parser.parse_args()
path = str(args.path)
threshold = float(args.threshold)
logging.info('PyLint Starting | '
'Path: {} | '
'Threshold: {} '.format(path, threshold))
results = Run([path], do_exit=False)
final_score = results.linter.stats['global_note']
if final_score < threshold:
message = ('PyLint Failed | '
'Score: {} | '
'Threshold: {} '.format(final_score, threshold))
logging.error(message)
raise Exception(message)
else:
message = ('PyLint Passed | '
'Score: {} | '
'Threshold: {} '.format(final_score, threshold))
logging.info(message)
exit(0)*
注意:阈值默认设置为 7。如果 pylint 分数低于这个数字,提交将会失败,您必须在再次提交之前清理您的脚本。
**3。通过运行以下 bash 命令使其可执行:
*chmod +x .git/hooks/pre-commit*
这样做之后,每次提交项目之前,都会格式化皮林特的布莱克和林挺。
我们考虑以下应用程序进行说明:

作者图片
当提交新的变更时,我们会得到以下结果:

作者图片
共享棉绒和格式化程序
既然您已经将 black 设置为格式化程序,将 pylint 设置为 linter,那么您肯定希望您的团队拥有相同的配置。
要做到这一点,您可以使用下面的 bash 文件,该文件将被放在您的项目的根目录下,并在克隆存储库之后由您团队的每个成员运行:
*#!/bin/bashecho $"#/bin/sh\nblack .\npython lint.py -p ../projectName/'> .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit*
结论
预提交是非常强大的工具,可以保持代码格式良好,并在团队成员中标准化开发方法。同样,除了林挺和格式化之外,它们还可以包括其他检查。
在本文中,我们使用了一种调用已安装的 Python 库的经典方法,您也可以使用 python 模块 预提交 ,其中包括对其 GitHub 库的许多检查和调用。这是非常有效的,但可能很难设置,特别是当面对代理过滤器时。
通过使用环境变量和 env 文件来保证代码的安全
安全地加载一个文件,其中包含我们的应用程序所需的所有机密数据,如密码、令牌等

让我们用一些变量来丰富这个美丽的环境(图片由罗布·莫顿在 Unsplash 上提供)
您的代码需要连接到数据库。为此,它需要一个数据库的密码。你如何在你的应用程序中使用这个密码,既能连接到数据库又能让密码保密?
本文向您展示了如何在代码中使用 env 文件。这个文件储存了我们所有的机密信息。它可以加载一次,所以你可以在你的应用程序中的任何地方访问你的所有私人信息,如密码。在本文中,我们将使用 Python 来说明 env 文件的工作原理,但该原理适用于所有编程语言。
在本文结束时,您将:
- 理解使用环境变量的优势
- 理解环境变量如何工作
- 了解如何从 env 文件中加载环境变量
我们来编码吧!
1.为什么要使用环境变量?
使用环境变量文件主要有两个原因:
1。安全
2。灵活性
保管好您的凭证
第一个原因是迄今为止最重要的:环境变量保存您的凭证。我们希望防止我们的代码被密码和其他不应该知道的信息弄得千疮百孔。这不仅是不好的做法;这也非常危险,尤其是如果你把你的代码上传到像 GitHub 这样的公共库。然后,你只要公开向任何看到你的证件的人展示你的证件就行了!
环境变量将我们所有的机密信息收集在一个文件中。由于我们所有的私人信息都收集在一个文件中,我们可以很容易地gitignore这个文件来防止我们的数据被推到我们的 git 存储库!
灵活性
环境文件可以从外部修改。如果您的数据库密码更改,我们可以打开包含所有环境变量的文件,
更改数据库密码并重启我们的应用程序。这比搜索,然后在应用程序中重写硬编码的密码要方便得多。
此外,你可以运行一个程序(例如在 Docker 中)并给它一个 env 文件(如下文所示)。例如,这使得在开发和生产数据库之间切换变得非常容易。
2.环境变量如何工作
既然我们确信使用 env 变量是明智的,那么让我们弄清楚它们是如何工作的。每个操作系统(Windows、Linux、Mac)都会为它创建的每个进程创建一组环境变量。我们正在运行的脚本就是其中一个进程的例子。

我认为 env 文件是我的应用程序的关键(图片由马特·阿特兹在 Unsplash 上提供)
我们将从读取这些变量开始,然后添加一些我们自己的变量。下面的例子是用 Python 写的,因为这是一种非常容易理解的语言,但是请注意 env 变量不是 Python 独有的:类似下面的功能在每种编程语言中都存在。
读取环境变量
让我们先看看哪些变量已经存在;
import os
for key, value in os.environ.items():
print(key, value)
我们用 os.environ 访问 env 变量,这将返回一个字典。使用 items()方法,我们可以遍历所有的键和值并打印它们。在我的例子中,它打印出了许多关于我的系统的信息:
- 我的程序文件、路径和 APPDATA 的位置
- 虚拟环境信息
- 我的用户名和计算机名
- 等等
我们还可以读取一个特定变量,例如我的电脑名称:
import os
print(os.environ.get(“COMPUTERNAME”))
创建环境变量
由于os.environ是一个字典,我们可以很容易地添加新的变量。首先,我们将创建一个带有关键字“HELLO”和值“WORLD”的变量。然后我们将再次检索该值
import os# Create an env var
os.environ['HELLO'] = 'WORLD'# Retrieve the newly created var
print(os.environ.get("HELLO"))
这印出了“世界”。轻松点。也试着从应用程序的其他地方读取这个变量,注意到它在任何地方都是可访问的。

让我们保证这些密码的安全(图片由马库斯·温克勒在 Unsplash 上提供)
3.将环境变量从环境文件加载到环境中
既然我们已经了解了环境以及如何使用环境变量,那么就很容易理解环境文件的作用了;它指定了一些额外的键和值对,我们希望将它们加载到我们的环境中。在本节中,我们将创建一个 env 文件,然后将其完整地加载到环境中。
a.创建 env 文件
我们将首先在应用程序的这个位置创建一个名为 . env '的文件:/config/conf/.env`。env 文件的内容如下所示:
DB_TYPE = postgresql
DB_USER = postgres
DB_PASS = mikepw
DB_HOST = localhost
DB_NAME = my_webshop_db
b.加载环境文件
接下来,我们需要将这个文件加载到我们的应用程序环境中。大多数编程语言都有加载这类文件的内置功能包。
Python 最方便的就是安装包:pip install python-dotenv。这个包可以方便地将.env文件中的值加载到 Python 环境中。然后简单地调用load_dotenv函数并传递.env文件的位置。
的位置。env 文件→使用 Python 中的相对路径 load_dotenv函数需要一个指向.env文件位置的绝对路径。在本文中,我们只是硬编码传递它,但是一旦我们部署我们的代码,我们可能会面临一个问题:在我的机器上,env 文件的位置是c:/users/mike/envfileproject/config/conf/.env,但是在你的机器上,它可能是c:/pythonstuff/envfileproject/config/conf/.env。查看下面的文章,获得一个简单的、可重用的技巧来解决计算 env 文件的绝对路径带来的头痛问题。
c.加载环境文件
我们将使用python-dotenv包和ROOT_DIR来加载。环境中的 env 文件:
if (os.environ.get("DB_TYPE") == None):
from dotenv import load_dotenv
from config.definitions import ROOT_DIR
load_dotenv(os.path.join(ROOT_DIR, 'config', 'conf', '.env'))
首先,我们将检查我们需要的变量之一(在这个特定的例子中是 DB_TYPE)是否已经加载到环境中。当我们从外部通过 Docker 将 env 文件传递给这个 Python 项目时,情况就是这样,例如,查看下面关于如何在 Docker 中使用 env 文件的文章。
如果 DB_TYPE 变量在环境中还不存在,我们将使用python-dotenv包加载它。
- 从 dotenv 导入 load_dotenv 函数(这是我们之前安装的 python-dotenv 包)
- 从
/config/definitions.py导入根目录 - 将路径传递给。env 文件到 load_dotenv 函数
- 搞定了。
我们的 env 文件现在被加载到 Python 中。通过像这样请求密钥,我们可以安全方便地访问所有值:
database_password = os.environ.get("DB_PASS")
有关如何实现?Docker 容器中的 env 文件。如果我们使用 env 文件将数据传递给 Postgres 容器:
结论
总之:环境文件通过将我们所有的机密信息存储在一个文件中为我们提供了安全性和灵活性,我们可以将这个文件加载到我们的代码中,以便安全地访问所有需要的值。
我希望已经阐明了环境变量的内部工作原理以及如何使用环境文件。如果您有建议或澄清,请评论,以便我可以改进这篇文章。与此同时,请查看我的其他关于各种编程相关主题的文章,比如:
- Docker 中的 Postgres 入门
- 用 FastAPI 用 5 行代码创建一个快速自动归档、可维护且易于使用的 Python API
- Python 到 SQL —安全、轻松、快速地升级
- 创建并发布自己的 Python 包
- 创建您的定制私有 Python 包,您可以从您的 Git 库 PIP 安装该包
- 绝对初学者的虚拟环境——什么是虚拟环境,如何创建虚拟环境(+示例)
- 通过简单的升级大大提高您的数据库插入速度
编码快乐!
—迈克
页(page 的缩写)学生:比如我正在做的事情?跟我来!
https://mikehuls.medium.com/membership
让您的笔记本与 JupyterLab 模板保持一致
比复制粘贴更好的解决方案

照片由 Natasya Chen 在 Unsplash 上拍摄
我每天大部分时间都在 JupyterLab 工作,我创建的每个笔记本都有相似的结构。与复制和粘贴笔记本不同,[JupyterLab Templates](https://github.com/jpmorganchase/jupyterlab_templates)扩展是一个允许你创建可重复使用的笔记本的解决方案。
这篇短文将概述如何安装和设置这个扩展。
装置
通过pip安装jupyterlab_templates包:
pip install jupyterlab_templates
然后安装
jupyter labextension install jupyterlab_templates
并启用扩展
jupyter serverextension enable --py jupyterlab_templates
现在我们只需要设置模板目录
设置模板目录
创建一个目录来存储您的笔记本。例如,我的模板存储在这里:
~/.jupyter/templates
创建以下文件(如果尚不存在)
~/.jupyter/jupyter_notebook_config.py
将下面一行添加到该文件中。这将告诉 jupyterLab 模板目录的完整路径。这必须是完整路径,不要使用~简写

作者图片
- template_dirs →存储模板的目录列表。这些路径的任何子目录中的每个
.ipynb文件都将是一个模板。父目录中的文件将被忽略
*** 重要*** 模板需要在 template_dirs 目录的子目录下。父目录中的文件将被忽略
每个子目录中可以有多个笔记本。作为一个例子,这里是我的目录树。
├──.jupyter
└── templates
└── analysis
├── analysis-template.ipynb
└── test-template.ipynb
创建模板笔记本
现在一切都设置好了,您可以开始制作可重复使用的笔记本了。这是我的analysis-template.ipynb笔记本
模板在运行
现在,当您启动 jupyterLab 时,您可以像这样访问您的模板:

作者 GIF
笔记本样本
你可能已经注意到这个包带有一个Sample.ipynb。出于好奇,以下命令将显示该文件在 macOS 上的位置:
locate Sample.ipynb
在我的机器上,它位于以下位置:
/Users/luke/miniforge3/lib/python3.9/site-packages/jupyterlab_templates/templates/jupyterlab_templates/Sample.ipynb
结论
我过去曾尝试过其他笔记本模板解决方案,但它们都很难设置,而且令人困惑。这是我找到的最简单的解决方法。
在我看来,唯一缺少的特性是提示用户立即重命名新创建的笔记本。
我希望这篇文章有助于保持你的个人笔记本,或者你的团队的笔记本的一致性。
相关职位
[## 如何远程连接到 JupyterLab
towardsdatascience.com](/how-to-connect-to-jupyterlab-remotely-9180b57c45bb) https://betterprogramming.pub/how-to-use-miniconda-with-python-and-jupyterlab-5ce07845e818 https://betterprogramming.pub/how-to-scale-your-analysis-to-handle-very-large-datasets-in-python-5ab4a84a52dc
感谢阅读和支持媒体作者
https://lukegloege.medium.com/membership
在 Jupyter 笔记本中安全保存凭证
Jupyter 笔记本广泛应用于数据科学中,用于模型的快速原型制作和交互式演示。但是在使用的时候应该如何安全的存储密码、证书和密钥呢?
我将快速浏览一下可用的解决方案,以帮助您保护凭据的安全。

马库斯·温克勒在 Unsplash 上的照片
为什么不应该“直接输入”凭证呢?
我在我的个人项目中经常使用 Jupyter 笔记本,最近我遇到了一个相当常见的情况,如果一个人没有在床上有安全意识的一侧醒来,可能会以非常糟糕的结局结束。我需要连接到 Bing API 来抓取图片,这是微软 Azure 提供的一项付费服务。你基本上是用一个属于你的秘密认证密钥连接的,根据你对 API 服务的使用情况来收费。
如果您只是在其中一个单元格中键入密钥并运行它,即使您有在连接激活后删除它的意图,也有可能忘记它并将其签入 GitHub,或者稍后发送给某人。
但是把凭证更新到 GitHub 有什么问题呢?
问题是恶意机器人不断地抓取回购文件,寻找任何意外推送的秘密。即使您在推送后立即修复了它,您也是不安全的 —有可能它已经被清除,或者提交历史可能仍然包含您的错误。一旦你的凭证被窃取,它们可能会被用来窃取你的数据,获取其他服务的访问权限,或者在一夜之间在云计算服务上积累巨额账单。大公司也犯了这个错误:2017 年,黑客获得了优步私人 GitHub 回购的访问权限,该回购存储了明文密码,导致 5700 万用户数据泄露。
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
Jupyter 笔记本有什么特别之处?
在正常的剧本中,情况要简单一点。当然,您也不应该硬编码您的凭证,但是您可以更容易地将它们分开。最简单、最方便的解决方案是在项目的根目录下创建一个配置文件,在本地存储这些值,并确保将它添加到中。gitignore 文件 避免不小心上传。对于 Python 项目,此配置文件可以是便于数据存储的任何格式:
- 名为 config.py 或类似的 python 脚本
- JSON 文件
- 一份 YAML 档案
- INI 文件
我推荐这篇关于如何使用上述配置文件类型的文章。
当然,这是为个人/小项目,在一个大公司请使用专业的密钥保管服务。
对于 Jupyter 笔记本来说,配置文件方法变得非常麻烦。
它们的要点是拥有可移植的代码,你可以快速地设置、运行、更改、共享和携带。这意味着您还需要随身携带配置文件,并确保保留一个文件夹结构,以便您的所有导入工作。如果你使用的是在线 Jupyter Notebook 或 Google Colab 这样的浏览器环境,这种情况就更糟了,因为在这种环境下很难找到文件夹。

照片由 Paulius Dragunas 在 Unsplash 上拍摄
Jupyter 笔记本电脑解决方案
没有完美的解决方案,但根据您的情况,有一些折衷方案。
1.配置文件
如果你不介意在本地存储一个配置文件,并在需要的时候携带它们,最不痛苦的是使用 JupyterLab 而不是 Jupyter Notebook 。这是因为 JupyterLab 在边栏中有一个文件浏览器,所以你可以轻松地查看和访问像配置文件这样的文件。
请记住将您的配置文件添加到您的
. gitignore文件中,以避免签入它们!
您可以为非笔记本脚本创建任何 YAML 或 JSON 配置文件,如上所述,但我最喜欢的方法是:
- 1.a 配置解析器:
您可以创建一个名为“notebook.cfg”的文件,例如,使用以下语法:
[my_api]auth_key: shjdkh2648979379egkfgkss
然后,将凭据加载为:

使用 ConfigParser 的凭据
- 1 . bDotenv
您可以创建一个。env 文件,dotenv 会将这些文件加载到环境变量中。语法类似于 Bash。
# Development settingsDOMAIN=example.orgADMIN_EMAIL=admin@${DOMAIN}ROOT_URL=${DOMAIN}/appADMIN_PW = kdhkr4rb344r4
您可以按如下方式加载:

Dotenv 的凭据
我更喜欢 Dotenv 方法,因为它更容易共享。如果你把笔记本送给别人,他们要做的就是设置自己的环境变量。
2。 GetPass —交互输入
GetPass 让你在一个专门为秘密设计的互动单元中键入你的密码。当你输入时,你的输入是隐藏的,不会被打印出来,并且也不会被保存。每次重新运行单元时,您都必须重新键入您的密码。这是最有用的,如果你有很少的秘密或非常简单的秘密,你可以记住并快速输入。

使用 Getpass 的凭据
3。JupyterLab 的凭据存储扩展
JupyterLab 允许您将键值对输入到自己的凭证存储中,该凭证存储来自一个扩展。这些都保存在一个名为的文件中。credentialstore ,AES 加密(非常安全),所以只有登录 JupyterLab 才能访问凭证。但是,一定要将它添加到您的. gitignore 文件中。
您可以将它用作:
import kernel_connector as kckc.get_credential("my_secret")
更多信息,请看这个由扩展作者写的帖子。

JupyterLab 凭证商店。这个 JupyterLab 扩展让你的… |作者弗兰克·齐克特|走向数据科学
注意,在 JupyterLab 的新版本中,原来的扩展被破坏了,但是如果你搜索 @ccorbin/credentialstore ,就会有一个固定的版本。
4。 钥匙圈—使用您系统的钥匙圈
Keyring 与您的操作系统钥匙串管理器集成,因此您可以从 macOS 钥匙串、Windows 凭证锁或其他第三方服务中访问任何密码。这使得您的凭证与代码完全分离,没有意外签入的配置文件。
您可以将它用作:
import keyringkeyring.get_keyring()keyring.get_password("system", "username")
5.基于云的密钥库
这是之前所有解决方案中最复杂的,也是唯一会让你花钱的。云服务不是免费的,但是你通常可以获得免费试用,并且存储一些秘密不会花费你太多。这也是最专业和安全的方法,因为没有任何东西存储在本地。由于认证的开销,我并不真正建议小型项目使用这种方法,但是如果您进行大量协作,它可以提供您正在寻找的解决方案。
- Azure Key Vault——0.03 美元/万笔交易
- AWS 秘密管理器——0.40 美元/月/秘密+每 10,000 次 API 调用 0.05 美元

Azure Quickstart —使用 Azure portal | Microsoft Docs 从密钥库中设置和检索密码
仅此而已!
希望你找到了自己喜欢的方法,保持安全!
资源:
- https://bdtechtalks.com/2017/11/27/uber-data-breach/
- https://dadoverflow . com/2019/08/09/how-do-you-hide-secrets-in-jupyter-notebooks/
- https://veekaybee.github.io/2020/02/25/secrets/
- https://towards data science . com/the-jupyterlab-credential-store-9cc 3a 0b 9356))
- https://martin-thoma.com/configuration-files-in-python
保持 Kubernetes 集群干净整洁
清除所有未使用的资源,这些资源会使您的 Kubernetes 集群变得杂乱并浪费其计算资源

随着集群的增长,资源、卷或其他 API 对象的数量也会增加,迟早会达到极限。无论是etcd,卷,内存还是 CPU。当您可以设置简单而复杂的规则、自动化和监控来保持集群整洁时,为什么要让自己遭受不必要的痛苦和麻烦呢?这些规则、自动化和监控可以让您的集群保持整洁,而不会让流氓工作负载吃掉您的资源或到处都是陈旧的对象。
何必呢?
一些被遗忘的豆荚,未使用的持久卷, *Completed* 乔布斯或者也许旧的 ConfigMap/Secret 无所谓,或者呢?它就放在那里,我可能在某个时候需要它!
嗯,它现在不会造成任何损害,但是当事情随着时间的推移而积累时,它们就会开始影响集群的性能和稳定性。因此,让我们来看看这些被遗忘的资源可能导致的一些常见/基本问题:
每个 Kubernetes 集群都有一些基本限制。首先是每个节点的 pod 数量,根据 Kubernetes 文档,应该最多为 110 个。也就是说,如果您有非常大的节点,有大量的内存/CPU,您肯定可以更高—甚至可能每个节点 500 个,正如这里用 OpenShift 测试的,但是如果您突破了极限,当事情开始出问题时,不要感到惊讶,不仅仅是因为内存或 CPU 不足。
您可能遇到的另一个问题是临时存储不足。节点上所有正在运行的 pod 都至少使用一点临时存储空间来存储日志、缓存、暂存空间或emptyDir卷。您可能会很快达到极限,这可能会导致 pod 被逐出或新的 pod 无法在节点上启动。在节点上运行太多 pod 也会导致这个问题,因为临时存储用于容器映像和容器的可写层。如果节点的临时存储空间不足,它就会被感染,您可能会很快发现这一点。如果您想检查节点上存储的当前状态,您可以在节点上运行df -h /var/lib。
与短暂存储类似,持久卷也可能成为问题的来源,尤其是如果您在一些云中运行 Kubernetes,因此需要为您提供的每个 PVC 付费。因此,很明显,清理所有未使用的 PVC 以节省资金是很重要的。此外,保持使用过的 PVC 干净也很重要,这样可以避免应用程序空间不足,尤其是在集群中运行数据库时。
过多的物品也会产生问题,因为它们都存放在etcd储物件中。随着etcd数据库的增长,它的性能会开始下降,考虑到etcd是 Kubernetes 集群的大脑,你应该尽力避免这种情况。也就是说,你将需要非常大的集群来达到etcd的极限,正如 OpenAI 的这篇帖子所示。然而,没有一个单一的指标可以用来衡量etcd的性能,因为它取决于对象的数量、大小或它们变化的频率,所以你最好保持它的干净,否则你可能会得到一些令人讨厌的惊喜。
最后,杂乱的集群也会导致安全问题。当不需要/不使用角色绑定或服务帐户时,就把它们留在那里是一种邀请,有人会抓住它们并滥用它们。
基础
你不需要做任何复杂的事情来解决上面提到的大部分问题。解决这些问题的最好方法是完全预防它们。实现这一点的一种方法是使用对象配额,您(作为集群管理员)可以在单个名称空间上强制实施该配额。
您可以通过配额解决的第一个问题是 PVC 的数量和大小:
在上面的代码片段中,我们有两个对象——第一个是 LimitRange ,它规定了名称空间中单个 PVC 的最小和最大大小。这有助于阻止用户请求大量数据。这里的第二个对象( ResourceQuota )额外对 PVC 的数量及其累积大小进行了硬性限制。
接下来,为了防止人们创建一堆对象,然后在不需要时将它们丢弃,您可以使用对象计数配额,该配额对给定名称空间中特定类型资源的实例数量进行硬性限制:
您可以使用几个内置字段来指定对象计数配额,例如上面显示的configmaps、secrets或services。对于所有其他资源,你可以使用count/<resource>.<group>格式,如count/jobs.batch所示,这有助于防止错误配置的 CronJob 产生大量的作业。
我们可能都知道可以设置内存和 CPU 配额,但是您可能不知道还可以为暂时存储设置配额。对本地临时存储的配额支持是作为 1.18 版中的一项 alpha 功能添加的,它允许您以与内存和 CPU 相同的方式设置临时存储限制:
然而,要小心这些,因为当它们超过极限时会被驱逐,这可能是由例如集装箱原木的尺寸引起的。
除了为资源设置配额和限制之外,还可以为部署设置修订历史限制,以减少保留在集群中的副本集的数量。这是使用.spec.revisionHistoryLimit完成的,默认为 10。
最后,还可以设置 TTL(生存时间)来清理集群中存在时间过长的对象。这使用 TTL 控制器,该控制器从 1.21 版开始处于测试阶段,目前仅适用于使用.spec.ttlSecondsAfterFinished字段的作业,但将来可能会扩展到其他资源(例如 pod)。
手动清理
如果预防还不够,并且您已经有一堆孤立的、未使用的或以其他方式废弃的资源,那么您可以进行一次性清除。这可以只用kubectl get和kubectl delete来完成。您可以做的一些基本示例如下:
第一个命令使用资源标签执行基本的删除操作,这显然要求您首先使用某个key=value对来标记所有相关的资源。第二个示例展示了如何基于某个字段(通常是某个状态字段)删除一种类型的资源——在本例中是所有的 completed/succeeded 窗格。这一点也可以应用于其他资源,例如已完成的作业。
除了这两个命令之外,很难找到能够批量删除内容的模式,因此您必须寻找未使用的单独资源。然而,有一个工具可能会有所帮助——它叫做[k8spurger](https://github.com/yogeshkk/k8spurger)。该工具查找未使用的角色绑定、服务账户、配置映射等。并生成适合删除的资源列表,这有助于缩小搜索范围。
kube-看门人
前几节探索了一些简单的、特别的清理方法,但是消除任何混乱的最终解决方案是使用[kube-janitor](https://codeberg.org/hjacobs/kube-janitor)。kube-janitor是一个在集群中运行的工具,可以作为任何其他工作负载,并使用 JSON 查询来查找资源,然后可以根据指定的 TTL 或到期日期删除这些资源。
要将该工具部署到您的集群中,您可以运行以下命令:
这会将kube-janitor部署到default名称空间,并使用示例规则文件和模拟运行模式运行它(使用kube-janitor 部署中的--dry-run标志)。
在关闭空转模式之前,我们应该设置自己的规则。这些位于kube-janitor配置图中,看起来像这样:
我们显然对需要填充的rules:部分感兴趣。因此,这里有一些有用的示例,您可以在集群清理中使用:
此示例显示了清理临时、陈旧或未使用资源的一些基本用例。除了这种规则,您还可以为特定对象设置绝对到期日期/时间。这可以使用注释来完成,例如:
当你设置好你的规则和注释后,你可能应该让这个工具在模拟运行模式下运行一段时间,并打开调试日志,看看正确的对象是否会被删除,并避免删除你不想删除的内容(换句话说,如果你因为错误的配置和缺乏测试而删除了生产卷,不要怪我)。
最后,使用kube-janitor时要考虑的一件事是,如果集群中有很多对象,它可能需要比默认的100Mi更多的内存。所以,为了避免它的 pod 卡在 CrashLoopBackOff 中,我更喜欢给它1Gi作为内存限制。
监控集群限制
并非所有问题都可以通过手动甚至自动清理来解决,在某些情况下,监控是确保您不会触及集群中任何限制的最佳方式,无论是 pod 数量、可用的临时存储还是etcd对象数量。
然而,监控是一个很大的话题,需要一篇(或两篇)文章来阐述,所以为了本文的目的,我将列出来自 Prometheus 的几个指标,当您保持集群整洁时,这些指标可能会对您有用:
etcd_db_total_size_in_bytes-etcd数据库的大小etcd_object_counts-etcd对象计数pod:container_cpu_usage:sum-集群中每个 pod 的 CPU 使用率pod:container_fs_usage_bytes:sum-集群中每个 pod 的文件系统使用情况pod:container_memory_usage_bytes:sum-集群中每个 pod 的内存使用情况node_memory_MemFree_bytes-每个节点的空闲内存namespace:container_memory_usage_bytes:sum-每个名称空间的内存使用量namespace:container_cpu_usage:sum-每个名称空间的 CPU 使用率kubelet_volume_stats_used_bytes-每个卷的已用空间kubelet_running_pods-节点中正在运行的 pod 数量kubelet_container_log_filesystem_used_bytes-每个集装箱/箱的原木尺寸kube_node_status_capacity_pods-每个节点的推荐最大箱数kube_node_status_capacity-所有指标的最大值(CPU、pod、短期存储、内存、大页面)
这些只是您可以使用的众多指标中的一部分。可用的度量也取决于您的监控工具,这意味着您可能能够获得一些由您运行的服务公开的额外的定制度量。
结束语
在本文中,我们探讨了清理 Kubernetes 集群的许多选项——有些非常简单,有些更复杂。不管你选择哪种解决方案,试着保持在这个“清理任务”的顶端,并在你进行的过程中清理东西。它可以让你省去一个大麻烦,如果没有别的,它可以清除你的集群中一些不必要的混乱,这与清理你的桌子的目的相同。还要记住,如果你把东西放在那里一段时间,你会忘记它们为什么在那里,它们是否被需要,这使得把东西恢复到干净状态变得更加困难。
除了这里介绍的方法,您可能还想使用一些 GitOps 解决方案,如 ArgoCD 或 Flux 来创建和管理资源,这可以大大减少孤立资源的数量,并且也使清理更容易,因为它通常只需要您删除一个自定义资源的单个实例,这将触发从属资源的级联删除。
本文最初发布于martinheinz . dev
https://itnext.io/hardening-docker-and-kubernetes-with-seccomp-a88b1b4e2111
保持(数据)表象
数据是为客户创造价值的燃料,它的应用非常广泛。

让东西保持有序,让东西看起来整洁,熨烫你自 2020 年 2 月以来就没有穿过的超级褶皱的衬衫,这些都是我们在日常生活中做的事情。那么,我们为什么要区别对待我们的数据呢?
在转换角色以专注于数据之后,自然地,我从来没有花这么多时间去思考这个问题。我以前写过关于数据信息的文章,那时我对“数据”的兴趣被激起了。今天,我分享一些关于以数据为中心的想法。我正在探索一些元素,所以希望它会有用,不管你在公司里扮演什么角色。在这篇文章中,我将关注:
- 收集/使用数据的五个为什么
- 沉迷于你的数据,而不是你的模型
- 数据效用——让它变得有意义
维护对象数据维护对象问题
总有东西在收集数据;苹果追踪你的脚步,Spotify 记录你在 30 秒或更长时间内听(或不听)了什么,Nest 计算出你的家庭/外出模式,Starling 看到你在咖啡上花了多少钱…
这些例子都带来了有益的结果,无论是行为的改变——像“Chanade,你今天达到了创纪录的步数”,还是学习在你的日常混音中为你播放更多你喜欢的音乐。虽然这些都很棒,但有很多东西是在收集数据的地方发生的,但它只是坐在那里积灰,有点像我目前的手提箱。许多团队收集数据很快,但是做一些事情却很慢,尤其是一些有意义的事情。然而另一方面,你有团队来使数据可用,所以团队可以创造一些伟大的东西,无论是支持业务团队还是客户,使他们的下一次体验比以往任何时候都更好,因为它与他们当时的时间和他们要做的工作相关。
Zara 是另一个为了客户利益而使用数据的例子。Zara 多年来的发展令人印象深刻,顾客是它的核心。每天,来自 96 个国家的 2,259 家店铺的团队成员都会反馈顾客的习惯,然后设计团队会根据这些习惯进行改进;这包括高销量商品和退货——这使得 Zara 能够从设计和生产的角度快速行动,例如,这可能导致停止一种风格,或改变尺寸。
另一个做好事的时尚强国是 ASOS。通过利用退货数据、客户评论和一个名为“你的详细信息”的小功能,我发现他们正在做的一些事情很有用。在数字化购买时非常有用,而且以我的经验来看,总是相当准确。
不久前我看了这部电影,但《摇钱树》是一部很棒的电影,展示了“数字”产品之外的应用。在 Moneyball 中,有一个棒球队雇佣了一名分析师,他专注于一组数据特征,以告知他们与谁比赛,以及他们与谁签约/交换。这些数据被用来预测获胜的球队,长话短说,我们成功地战胜了球探团队的“总是这样做,这些数据是行不通的”行为。这是现在常见的行为,显示了数据在预测许多行业中的作用有多广。
使用数据的五个为什么
如果您的团队不能回答为什么要收集/使用 5x 的数据,那么他们根本就不应该收集这些数据。为了让这一过程更有条理,你可以为你的袖手旁观团队制定一些明确的原则——不管他们在公司的哪个部门。这可以避免人们在与数据隐私团队打交道时经常陷入的怪圈。原则应该用简单的英语表达,并且有意义。当客户与你的产品和服务互动时,他们应该总是丰富客户的体验。
我最近一直在思考这个问题,敏捷宣言感觉是写这些的好方法。这是我对收集数据的原则的想法。
- 让它成为体验的一部分 胜过 为你的客户创造更多的努力。
- 关注最少的可行数据开始 而不是 试着去想你可能想要的一切。
- 演示数据在原型 中的使用,而不是 提供列表。
- 带着你的隐私/安全人员踏上一次 超过 的旅程,一直请求许可。
回到这四个原则,团队成员以客户为中心,问自己几个问题:

作者图片
当你在处理数据隐私或监管等问题时,所有这些都会让你的生活变得更轻松,以支持你收集/使用某些东西的原因,并确保它是道德的——这应该是你考虑的一部分,永远如此。如果这些数据被用来做 X,你会高兴吗?
说到收集数据,我们可以采取精益的方法。有一些很好的例子,公司收集最少量的可行数据,让你注册他们的产品或服务。然后,随着你不断回头,他们会逐渐积累他们想知道的东西,以便更好地使用他们的产品/服务。Adobe 在这方面做得很好,重点放在帐户恢复上。你完成了最低要求,你就可以进去了,然后再进去的时候,他们会给你更多的优惠。这是 MVD 开始运行。从这里开始总是好的,随着时间的推移显示价值和规模,否则您将花费数周时间让团队批准一切,数周时间考虑如何处理所有这些,而较少时间为您的客户快速创造小价值。关注一小部分用例,少即是多。一直都是。
沉迷于你的数据,而不是你的模型
许多技术人员痴迷于模型,而不是数据。问题是数据是释放价值的东西,模型是达到目的的手段。
“数据把模型当早餐吃”……就像“文化把策略当早餐吃”一样🥞
当我想到它的时候,有点像做三明治。让我们假设模型是面包。它烤得很好,总是有改进的空间,但总的来说,这是一个可爱的面包,沃伯顿家庭会感到自豪。然后数据,我们假设那是填充。对我个人来说,如果切达干酪不够成熟,我就不好了。
所以,你去冰箱(像谷歌云平台一样的数据存储),它几乎到处都是,你找不到奶酪,黄油就在后面,你有一些洋葱酸辣酱,但它过期了。这听起来有点像你的公司存储数据的方式。数据存储的重要性经常被遗忘。这是高绩效数据团队的基础,能够快速创造价值,并在此基础上不断迭代。你如何存储数据真的很重要。云提供商已经分离了存储和处理,并做了大量工作来给人们提供认真对待数据存储的工具。这是一门手艺,欣赏这些人,投资他们。
当公司看到旅程数据的价值时,在建模方面的投资不是问题,但如果它像“男人抽屉”一样储存,你会让你的团队生活更艰难,并产生不必要的努力。成为数据存储的阿尔迪中岛——你带着两样东西进来,带着门廊的欢迎垫、一支蜡烛和一套新锅离开。有组织的数据可以为团队带来灵感,创造创新产品。
最后,在实践中,你的模型建立起来了,你已经发货了,太棒了——但这还不是结束。它要么做得很好,但表现不如现有的,要么是一个全新的领域,表现不如所有人想象的那么好。很多人假设模型就是问题。你好,你看到数据情况了吗?!认真对待你的数据。
数据效用——让它变得有意义
太多时候,公司与我互动的方式就像他们与佩德罗·小马、丽贝卡·兔子、爷爷狗和佐伊·斑马(粉红猪小妹的粉丝都知道)互动的方式一样。这就好像他们认为我们在同一时间、同一渠道都有相同的工作要做。
有一些事情让我觉得很棒,我喜欢你的风格,请多收集和使用我的数据。
处女酒——我买了一箱,现在我每周都收到打八折的电子邮件和/或短信,我从来没有接受过,但我也没有想过退订。反馈循环,方法的改变在哪里?🗑
majestic——我去商店买了 6 瓶,爱上了 mix six。我是会员,但我什么也没有得到。什么都没有。🤷🏻♀️
芒果——我在浏览时看到了一款完全符合我的马甲。出于兴趣,我使用了大小特征。它可以帮助你找到你需要的尺码。其中一部分是预先填好的,我的年龄、身高、体重——很有用。他们通过 iOS 获取数据——我对此很满意,这支持了我的工作并节省了我的时间。🙏
经典的例子,但恐怕不是一般的例子。网飞。抱歉,我已经看了 100 多部电视剧了,为什么我还能看到他们的辉煌?为什么他们不在一个小区域,就像你已经看过所有这些东西或者至少给我一个我已经看过他们的信号,拜托。🤦🏻♀️
玉兰油有一个皮肤顾问,它使用人工智能、自拍和一些问题来确定适合你的产品。它节省了时间,增加了正确的机会,还有点意思。🧖♀️
关于你下一步可以做什么的一些想法💭
在我们所处的地方,团队的使命是让你的生活更轻松,或者通过使用人工智能来丰富你的客户体验。你很乐意开着自己的无人驾驶汽车去商店,或者观看网飞推荐的节目,或者因为 Apple Watch 告诉你而呼吸,所以加入进来,寻找机会,让这项技术让你的日常生活变得更轻松,或者让你的客户体验好 10 倍。数据正在改变我们的思维方式、处事方式以及更好地为客户服务的方式。不要被落下。
- 你收集的东西很重要,但是你需要明白你为什么要收集它。如果您能回答为什么是 5x,那么当您来记录并与隐私团队讨论时,您将有一个坚实的愿景。
- 数据及其应用释放价值。它使你在竞争格局中脱颖而出,或者对玉兰油来说,是你的下一个基础。
- 关注数据的整洁性、可用性和可用性,而不仅仅是闪亮的模型,对于您从使用数据中获得的价值至关重要,从您想要的开始。
与客户和他们试图做的工作保持一致,可以保持相关性,或者在新进入者的情况下,可以导致整个行业的混乱。数据对此至关重要,尤其是在下面的定价示例中。
网飞痴迷于了解客户在做什么,而百视达则过于专注于 15%的收入来自滞纳金(70%的利润),而没有停下来看看发生了什么。公司需要更广泛地考虑数据,而不仅仅是跟踪客户在你的网站上做了什么,并开发能够使你成为行业领导者的产品,并通过商业模式创新保持相关性。有时候短期的损失换来长期的收获是有必要有所突破的。
跟上 PyTorch 闪电和九头蛇—第二版
我如何使用 PyTorch lightning 1.1 和 Hydra 1.0 的新特性将我的训练脚本缩减了 50%
第二版短评:回到 2020 年 8 月,我写了一篇关于我如何使用 PyTorch Lightning 0.9.0 和 Hydra 1 . 0 . 0 的第四个发布候选版本将我的训练脚本缩减了 50%的故事。半年后的 2021 年 2 月,我们现在有了py torch Lightning 1.1和 九头蛇 1.0 。在 Hydra 1.0 中没有引入重大的变化,但是 PyTorch Lightning 1.0 包含了一些重大的变化,比如不再使用结果抽象。所以我决定写第二版我的原始帖子来“跟上”PyTorch 闪电和九头蛇。如果你愿意,你仍然可以阅读第一版,但第二版应该涵盖截至 2021 年 2 月的最新变化。尽情享受吧!

努力跟上!— 来源
介绍
PyTorch Lightning 1.1 和 Hydra 1.0 最近发布,充满了新功能和大部分最终 API。我认为这是一个很好的时机让我重温我的副业项目 Leela Zero PyTorch 来看看这些新版本是如何融入其中的。在这篇文章中,我将谈论这两个库的一些新特性,以及它们如何帮助 Leela Zero PyTorch。我不会在这里过多地谈论关于 Leela Zero PyTorch 的细节,所以如果你想更多地了解我的副业项目,你可以在这里阅读我以前关于它的博文。
PyTorch 闪电 1.1
经过几个月的努力,PyTorch Lightning 于 2020 年 10 月发布了 1.0 版本。它引入了许多新特性和一个最终稳定的 API。几个月后,他们发布了 1.1 版,提供了令人兴奋的模型并行支持。我们将把重点放在 1.0 中引入的最终 API 上,并在将来为模型并行性专门写一篇文章。在我们开始之前,如果你想了解更多关于这些版本的信息,请查看官方博客文章: 1.0 和 1.1 。如果你想了解更多关于 PyTorch Lightning 的知识,请查看 Github 页面以及官方文档。
简化日志记录
你有没有发现自己重复地实现*_epoch_end方法,只是为了从你的*_step方法中聚集结果?您是否发现自己在如何正确记录您的*_step和*_epoch_end方法中计算出的指标时被绊倒了?你并不孤单,PyTorch Lightning 1.0 引入了一种新方法self.log()来解决这些问题。
您真正要做的就是用您想要记录的指标调用self.log(),它将为您处理记录和聚合的细节,这可以通过关键字参数定制。让我们看看它们是如何在我的项目中使用的:
新的、简化的日志记录界面有助于您不再重复度量日志记录。
在training_step()中,我计算总损失并记录下来,将prog_bar设置为True,这样它就会显示在进度条中。然后,我使用便利的方法log_dict()记录均方误差损失、交叉熵损失和准确度(使用 PyTorch Lightning 的新度量包计算,稍后将讨论)。默认情况下,如果在training_step() ( on_step=True,on_epoch=False)中调用,self.log()只记录当前步骤,而不是纪元级别,但是我们可以根据需要改变行为。在validation_step()和test_step()中,self.log()的行为与聚合相反:它只在 epoch 级别(on_step=False、on_epoch=True)记录日志。我们不需要编写代码来在纪元级别聚合它们,因为它会自动为您处理。同样,这种行为可以通过关键字参数定制。你可以在这里阅读更多关于 PyTorch Lightning 如何记录日志的细节。
韵律学
PyTorch Lightning 团队在 0.8 中继续他们的工作,在 1.0 中引入了更多的度量实现。PyTorch Lightning 中的每一个指标实现都是一个 PyTorch 模块,并且有其对应的功能,使用起来非常简单灵活。模块实现负责跨步骤聚合指标数据,而功能实现则用于简单的即时计算。对于我的项目,我决定使用 accuracy 的模块实现,因为我对验证和测试的纪元级别的准确性感兴趣。让我们看一下代码:
精度模块正在运行。请注意调用它们的两种不同方式。
第一步是将单独的度量模块初始化为 Lightning 模块的实例属性。然后,只要在有数据的地方调用它们,就可以计算出想要的指标。然而,您将看到在我的代码中调用度量模块的两种不同方式。第一种方法可以在training_step()中找到,在这里我记录了调用度量模块的返回值。这是一种更直接的日志记录方式,其中根据给定参数计算的指标被记录,而没有任何自动聚合。因此,对于训练来说,只记录步进式精度,我可以只使用函数实现来获得相同的最终结果。
第二种方式可以在validation_step()和test_step()中找到。我用一行数据调用模块,然后直接记录模块。这里,自动聚合根据日志设置发生,即准确性指标将在纪元级别聚合和报告,因为这是我们使用的日志设置(记住,默认情况下,日志记录在纪元级别发生,用于验证和测试)。您不需要在单独的*_epoch_end()方法中聚合数据和计算指标,省去了您自己处理数据聚合的麻烦。
PyTorch Lightning 现在包含许多其他指标实现,包括高级 NLP 指标,如 BLEU score。你可以在这里阅读更多关于它的。
照明数据模块
PyTorch Lightning 的另一个棘手问题是处理各种数据集。直到 0.9,PyTorch Lightning 对如何组织你的数据处理代码保持沉默,除了你使用 PyTorch 的数据集和数据加载器。这无疑给了您很大的自由,但也使您很难保持数据集实现的整洁、可维护和易于与他人共享。在 0.9 中,PyTorch Lightning 在LightningDataModule中引入了一种新的组织数据处理代码的方式,它在 1.0 中正式成为稳定 API 的一部分。LightningDataModule封装了数据处理中最常见的步骤。它有一个简单的接口,有五种方法:prepare_data()、setup()、train_dataloader()、val_dataloader()和test_dataloader()。让我们回顾一下它们在我的项目中是如何实现的,以理解它们的作用。
LightningDataModule 帮助您组织数据处理代码。
prepare_data():该方法适用于分布式培训在派生子流程之前,主流程中必须完成的任何事情。下载、预处理或保存到磁盘等任务是这种方法的理想选择。需要注意的一点是,在这里设置的任何状态都不会被带到分布式培训中的子流程,因此您应该注意不要在这里设置任何状态。在我的项目中,我依赖 Leela Zero 来预处理 Go sgf 文件,所以我决定跳过实现这个方法,但是我可以在技术上实现这个方法中的预处理步骤。- setup():该方法用于分布式培训中每个子流程必须完成的任何事情。您应该构造实际的 PyTorch
Datasets并在这里设置任何必要的状态。在 Leela Zero PyTorch 中,我初始化了我的Datasets,它从磁盘中读入数据,并将它们转换成张量,并保存为状态。 *_dataloader():这是你初始化DataLoaders进行训练/验证/测试的地方。在我的例子中,我简单地使用在setup()中构建的数据集以及在LightningDataModule初始化期间传递的配置来初始化DataLoaders。
现在只需要把LightningDataModule传入trainer.fit()和trainer.test()就可以了。你也可以想象这样一个场景,我为不同类型的数据集(比如国际象棋游戏数据)实现了另一个LightningDataModule,而训练员将同样接受它。我可以更进一步,使用 Hydra 的对象实例化模式,在各种数据模块之间轻松切换。
九头蛇 1.0
Hydra 是一个“优雅地配置复杂应用程序的框架”正如你可能已经知道的那样,深度学习训练脚本可能会很快变得复杂,有很多旋钮和转盘。Hydra 可以帮助您以优雅的方式处理这种复杂性。
Hydra 早在 2020 年 9 月就发布了官方 1.0,现在正在向下一个 1.1 前进。发布在我们开始之前,如果你想从总体上了解更多关于九头蛇的信息,请查看官方网站以及官方文档!
@hydra.main()
您可以将这个装饰器添加到任何接受 OmegaConf 的DictConfig的函数中,Hydra 将自动处理您的脚本的各个方面。这本身并不是一个新特性,但是我最初决定不使用这个特性,因为它接管了输出目录结构和工作目录。我实际上使用了 Hydra 的实验性 Compose API 来解决这个问题,我将在后面讨论。然而,在与 Hydra 的创建者 Omry 交谈后,我意识到这不仅不是推荐的方法,而且我还失去了 Hydra 提供的一些很酷的功能,如命令行界面的自动处理、自动帮助消息和 tab 补全。此外,在使用一段时间后,我发现 Hydra 的输出目录和工作目录管理非常有用,因为我不必在 PyTorch Lightning 端手动设置日志目录结构。你可以在九头蛇的基础教程中读到更多关于这个装饰师的内容。
打包指令
在 Hydra 0.11 中,配置只有一个全局名称空间,但在 1.0 中,您可以使用包指令在不同的名称空间中组织配置。这允许您保持 yaml 配置文件的平整和整洁,没有不必要的嵌套。让我们来看看 Leela Zero PyTorch 的网络规模配置:
“@package group”表示此配置应在当前组下,在本例中为“网络”。

网络大小配置已按规定添加到“网络”下。请注意“board_size”和“in_channels”来自数据配置(composition!)
如您所见,包指令使您的配置更易于管理。你可以在这里阅读更多关于包指令及其更高级的用例。
实例化对象
Hydra 提供了一个特性,可以根据配置实例化一个对象或调用一个函数。当您希望您的脚本有一个简单的接口在各种实现之间切换时,这是非常有用的。这也不是一个新特性,但是它的界面在 1.0 中有了很大的改进。在我的例子中,我用它在网络大小、训练记录器和数据集之间切换。我们以网络规模配置为例。
“大”、“巨型”和“小型”网络的配置
基于所选配置实例化网络。请注意,您可以传入额外的参数来实例化(),就像我在这里对 cfg.train 所做的那样。
NetworkLightningModule对其__init__()、network_conf和train_conf接受两种说法。前者从配置中传入,后者在instantiate() ( cfg.train)中作为额外参数传入。你所要做的就是在命令行中输入+network={small,big,huge}来选择不同的网络大小。您甚至可以想象通过用不同的_target_创建一个新的配置,并在命令行中传递配置名,来选择一个完全不同的架构。不需要通过命令行传递所有的小细节!你可以在这里阅读更多关于这个模式的内容。
撰写 API
尽管 Hydra 的 Compose API 不是编写脚本的推荐方式,但它仍然是编写单元测试的推荐方式,并且非常有用。我用它来为主培训脚本编写单元测试。同样,这不是一个新特性,但是 Hydra 1.0 确实为使用 Python 的上下文管理器的 Compose API 引入了一个更干净的接口(即with语句)。
您可以使用 Hydra 的 Compose API 轻松编写配置字典。它有助于保持单元测试的整洁和易于调试。
你可以在这里阅读更多关于组合 API 的内容,以及如何在这里使用它进行单元测试。
未使用的功能:结构化配置和变量插值
Hydra 1.0 中还有很多其他特性我没有利用,主要是因为我还没有足够的时间来集成它们。我将讨论本节中最大的一个问题——结构化配置。
结构化配置是 1.0 中引入的一个主要新特性,它利用 Python 的 dataclasses 来提供运行时和静态类型检查,这在应用程序变得复杂时非常有用。我可能会在将来有时间的时候整合它们,所以请继续关注另一篇博文!
结论
自从我写了关于 Leela Zero PyTorch 的第一篇博文以来,Hydra 和 PyTorch Lightning 都引入了许多新的特性和抽象,可以帮助您极大地简化 PyTorch 脚本。看看我的培训脚本,看看它们有什么帮助:
我的新旧训练脚本。行数从 56 增加到 28。五折优惠!
正如你在上面看到的,我的主要训练脚本现在只有 28 行,而以前是 56 行。此外,训练管道的每个部分,神经网络体系结构,数据集和记录器,都是模块化的,易于交换。这使得迭代更快,维护更容易,重现性更好,让您可以专注于项目中最有趣和最重要的部分。我希望这篇博文对你“跟上”这两个了不起的库有所帮助!你可以在这里找到 Leela Zero PyTorch 的代码。
Keras 回调和如何从过度训练中拯救你的模型
回调允许您在训练期间调整设置或保存模型。

在本文中,您将学习如何在 Keras 中使用 ModelCheckpoint 回调来保存训练期间模型的最佳版本。
做模特很好玩!
我喜欢建立预测性的深度学习模型。我喜欢观察训练输出,看到损失下降,观察训练集和验证集之间的偏离损失,这表明过度拟合。但是有时一个模型找到了一个很好的解决方案……并保持对一个只适用于训练集的解决方案的训练。现在,如果我在那里,像盯着一个鱼缸一样盯着,我可以在造成太多伤害之前中断训练。但是,谁愿意整天坐在那里盯着模特们训练呢?我的意思是,我做,但我的时间最好花在长时间的训练中做其他工作。
然后我了解了 Keras 回调,特别是 ModelCheckpoint!
过度训练
顶尖运动员总是处于过度训练的边缘。正确的训练会优化运动员的表现,但是过度训练会导致受伤和表现下降。深度学习模型也是类似的。适量的训练可以建立一个强大的模型,但是过多的训练会降低新数据的性能。
在训练期间,深度学习模型寻求最小化它们的损失,根据给定的损失函数更精确。然而,他们根据他们正在训练的数据集来判断准确性。想象一下,一个小学生把模拟试题带回家,并记住试题上的每个问题和每个答案。如果他们没有发现潜在的模式,即测试旨在评估的策略,他们将会不知所措,因为模拟测试中的问题都不在考试中!
深度学习模型可以做同样的事情。如果他们在数据集上训练过多,他们可以专门学习该数据集,而不是选择连接要素和标注的底层函数。该模型可能会过度拟合数据。
在预测建模中有许多策略来对抗过度拟合,并且应该在必要时部署这些策略,但是来自过度训练的过度拟合是一种独特的危险。
幸运的是,Keras 以回调的形式为我们提供了一些帮助!在我知道回调之前,我认为我必须猜测训练时期的正确数量,或者使用试错法来调整它们。幸运的是,我们没有!我们可以使用 Keras 回调keras.callbacks.ModelCheckpoint()在模型的最佳执行时期保存模型。
复试
回调是可以在每个时期后运行的函数。它将纪元编号和模型跟踪的任何指标作为参数。它们可以用来做一些有用的事情,比如安排学习率的降低(我喜欢一个调整良好的衰减学习率,你呢?),提前停止训练,或者在历元之间保存模型。您甚至可以为自己的特殊目的编写自己的回调函数。
如果您想了解更多关于所有可用回调的信息,请查看这里的 Keras 文档。
模型检查点
我最喜欢的一个回调是 ModelCheckpoint。我喜欢多任务,经常打开几个 Google Colab 窗口,设置一些深度模型在其中进行训练,然后在本地机器上处理其他任务(我没有像 Google 那样的 GPU 硬件来进行高效的 Tensorflow 模型训练)。我可以将我的模型设置为训练比我认为他们可能需要的时间长一点,然后回来从他们开始过度拟合和在验证集上失去准确性之前的点加载他们。
模型检查点回调可以从 keras.callbacks 加载
from keras.callbacks import ModelCheckpoint
我们用要保存的文件路径、保存它的条件以及这个过程应该有多透明来初始化类对象。例如,假设我们只想要模型的最佳版本,我们将“最佳”定义为验证损失最低的版本。您可以选择损失函数或编译模型时传递给metrics参数的任何指标作为触发器。
我们应该像这样初始化回调函数:
checkpoint = ModelCheckpoint(filepath=filepath,
monitor=’val_loss’,
verbose=1,
save_best_only=True,
mode=’min’)
保存多次的一个很酷的技巧是将纪元编号和/或您正在监视的当前度量附加到 filepath,因为纪元将被传递给 ModelCheckpoint 对象。
filepath = 'my_best_model.epoch{epoch:02d}-loss{val_loss:.2f}.hdf5'
以上内容会将您的模型保存到磁盘,如下所示:
my _ best _ model . epoch _ 01-loss _ 13.31 . HD F5
回到回调
Keras 模型将回调列表作为.fit()调用中的参数。该参数需要一个列表,即使您只传递一个回调。然而,你可以用各种花哨的回调来装饰你的模型。我最喜欢的组合是 ModelCheckpoint 和 ReduceLROnPlateau。第二种方法监控一个度量标准,当该度量标准达到稳定状态时,将学习速率降低一个给定量。
我们将回调列表传递给.fit()方法,如下所示:
callbacks = [checkpoint, <other_callbacks_you_want>]
model.fit(X_train,
y_train,
epochs=epochs
callbacks=callbacks)
保存模型
关于保存模型的注意事项:以. hdf5 格式保存的模型非常好,因为整个模型在一个地方,可以在其他地方加载,比如在部署中。然而,文件会变得很大,并且在每个时期保存模型会很快占用大量存储空间。ModelCheckpoint 回调构造函数中的一个可用选项是save_weights_only=True。这将节省空间,但不会保存整个模型架构。为了恢复它,您将重建模型,然后指定保存的权重,而不是只在一个步骤中加载它。
我发现的另一个怪癖是,并不是每个图层都喜欢保存为. hdf5 格式。在以前的博客文章中,我向您展示了如何向 NLP 模型添加文本矢量化层,以作为模型本身的一部分进行预处理。然而,我发现如果我使用那个层,我不能以. hdf5 格式保存我的模型。然而,如果我去掉. hdf5 扩展名,那么 keras 会将模型保存为资产的文件目录,这适用于 TextVectorization 层。
拟合后,我们可以重新加载我们的模型,以便在其最佳执行时期进行评估:
model = keras.models.load_model(filepath)
让我们来看看这一切的行动吧!
作者要点
数据由卡内基梅隆大学通过 Statlib 图书馆提供。作者嵌入要点
我希望 Keras 提供的 ModelCheckpoint 和其他回调函数以及您自己设计的回调函数能够帮助您做出最好的预测模型!
摘要
在本文中,您了解了如何使用 Tensorflow 的 Keras api 进行深度模型的回调。具体来说,您学习了如何使用 ModelCheckpoint 回调在模型过度训练之前保存模型的最佳版本,以及一些定制回调的方法。
像往常一样,善用你的数据科学能力,尽情享受乐趣吧!请在评论中留下任何问题,评论,或者善意礼貌的反馈。
快乐造型!
克拉斯:引擎盖下
了解 keras 中的模型架构

来源: Pixabay
介绍
深度学习的入门变得非常简单和方便,这都要归功于 keras 和 tensorflow 的精彩二人组。你只需要做一些导入,定义一些层,宾果,你就有了你的深度学习架构准备好接受训练,并最终给出一些惊人的结果。Keras 做出了如此惊人的抽象,以至于即使对这个主题完全陌生的人也可以开始训练他们自己的深度学习模型。然而,如果你自称是数据科学家/机器学习工程师,那么对幕后发生的事情有一些基本的了解是必须的,我不是说你需要确切地知道背后的数百行代码,但至少对这些代码行在做什么有一些了解。

来源:知识共享
入门指南
不要浪费任何时间,让我们深入一些最常用的 keras 组件,并尝试一点一点地理解它们,这将涉及对面向对象编程的基本理解,但不要担心,我会尽量保持简单。我将采用一个非常简单的深度学习架构,然后尝试逐行解释其工作原理,为了更好地解释,我创建了一个自定义的密集层,我将在我的架构中使用。
**class** *MyDenseLayer*(tf.keras.layers.Layer):
**def** *__init__*(self, nodes):
super(MyDenseLayer, self).__init__()
self.num_outputs = nodes
**def** *build*(self, input_shape):
print("="*20)
print('we are here in build')
self.kernel = self.add_weight("kernel",shape= [int(input_shape[-1]),self.num_outputs],dtype=tf.float32)
**def** *call*(self, input):
print('='*20)
print('we are here in call')
**return** tf.matmul(input, self.kernel)
你可能想知道里面的这些构建/调用方法是什么,我稍后会深入挖掘它们的细节,下面是一个使用 keras Functional API 的非常简单的模型架构。
input_layer = Input(shape = (5,))
dense_layer = MyDenseLayer(nodes=10)
dense_layer_op = dense_layer_one(input_layer)
model = Model(inputs = input_layer,outputs = dense_layer_op)
现在让我们来看看这个架构,并试着一行一行地理解它。第一行非常简单,我们正在创建一个名为 Input 的类的对象,它基本上创建了一个符号张量/占位符 (这意味着我们在这里不需要实际的输入数据,而是为稍后在网络中流动的数据保留了一块内存)这个张量告诉网络将给予模型的输入的大小,这通常是网络的入口点,在 shape 参数中,我们指定输入向量的维度。((5,)表示输入是 1×5 向量,批量大小尚未确定,即模型可以采用稍后在模型拟合期间定义的任何批量大小)

占位符的图示(作者提供的图像)
第二行和第三行是实际事情开始的地方,这里我们定义了神经网络架构的第一层。第二行创建了一个自定义层类的对象,这一行基本上定义了自定义层中的节点数。
第三行是我们的实际层建立的地方,层的权重是在这里创建和初始化的,你可能会有一些问题,比如为什么在层对象创建过程中权重没有初始化?此外,这个层对象是如何作为某种 python 方法使用的?如果是,那么这个方法在做什么?。让我一个一个地回答它们,在创建对象时,我们可能事先不知道输入的大小(如果我们要在创建对象时创建权重,那么我们每次都需要将大小作为参数显式地传递给类),没有输入的大小,我们就无法创建这个权重矩阵。因此,我们希望仅当输入的大小已知时才创建这些权重,这就是我们在第三行中所做的,在这里,一旦我们获得了输入形状的信息,我们就完全构建了我们的层,为了证明我的观点,我已经分别在创建层对象和将输入形状传递给该层对象后获取了层权重,您可以清楚地看到,只有当层的输入形状已知时,权重才被初始化,对吗?。

在传递输入形状之前和之后调用权重矩阵(图片由作者提供)
现在第二个问题来了,这个对象是如何被当作 python 方法的,如果它是一个方法,那么它在做什么?在此之前,让我们先谈一谈我们在自定义类中定义的这些方法。
init () :这是一个非常简单的函数,对于那些使用过 JAVA 等其他编程语言的人来说,这个 init 相当于一个构造函数,用来初始化一个类对象。
build () :顾名思义,这个方法实际上是用来构建层的,也就是说,它创建层的权重,一旦我们得到了将要输入到模型中的输入的形状,它就会调用这个方法,并相应地创建权重
call () :这是该层的逻辑所在,也就是说,它接受提供给该层的输入,对其进行处理,并输出该层的输出,这些输出可能会被其他层使用
我们讨论了这些方法做什么,但我们没有谈论一件非常重要的事情,这些方法是如何以及何时被调用的, init 非常简单,它在对象创建时被调用,至于这些构建和调用方法它们是在我们将层对象用作方法时被调用的,这可能会有点混乱,但请耐心,让我们分解一下。 到目前为止,我们知道了的哪一部分即被视为方法,这个对象实际上在做什么,现在是的哪一部分,这个对象如何被视为方法,在没有任何显式函数调用的情况下,如何调用 call 和 build 方法。
这是一种特殊的对象——可调用的对象,这个对象可以被看作是一个有点魔力的函数。这正是实现这一奇迹所需要的,一个魔法方法,python 有这些特殊类型的方法,它们的调用不需要任何显式的函数调用。它们是在内部调用的(由一些操作符重载或内置函数调用),我们可能没有意识到这一点,但我们已经广泛地使用了这些神奇的方法,这里有一个简单的例子,在 python 中,当我们做类似于 a = 5 的事情时,我们知道一切都是对象,那么实际上 a 是类 str 的对象, 当我们执行print(a)print 方法是如何生成这个输出的呢这里是另一个神奇的函数 str 发挥作用的地方,这个方法以字符串形式返回一个对象的输出,当我们将那个对象放入 print 方法中时,它会被自动调用,这里有一小段代码可以让你更好地理解上面的语句。
**class** PrintTest():
**def** __init__(self,obj):
self.obj = obj
**def** __str__(self):
**return** "__str__ method is invoked when print object is put inside print/str method"
str_obj = PrintTest('Hello')
这是当我们将 PrintTest 类的对象放入像 print 这样的内置方法时的输出。

检查 str 方法调用(作者图片)
( 注:在 python 中有一个名为 Object 的类,默认情况下,Object 是 python 中创建的每个类的父类,这个 str 已经在那里定义了,在我们的示例中,我们简单地覆盖了 str 方法。)**

检查自定义类的父类(图片由作者提供)
现在回到我们最初的讨论,有另一个神奇的方法叫做 call ,它帮助你的类对象像常规方法一样工作,一旦我们在对象名后面加上括号圆括号()它就会被自动调用,简单地说 obj() 相当于 obj。call() 。
这就是为什么当我们创建原始层的一个对象,然后使用它工作的同一个对象进行函数调用时,敏锐的观察者会注意到一件事,在我们的自定义层类中,我们没有显式定义任何 call 方法,我们确实有一个 call 方法,但它是一个常规方法,它不是一个神奇的方法,为了回答这个问题,我想触及一个称为继承的概念, 你一定已经注意到我们的自定义层类从 Keras 继承了一个叫做层的基类,你可能知道继承的基本概念,一旦一个类继承了另一个类(父类),它就可以访问那个父类的所有功能(方法),所以这个神奇的方法 call 被写在层类中,当我们继承它时,我们的自定义类就可以访问这个 call 神奇的方法。 这些构建和调用方法也不是一些随机的方法,它们在层构建中也有意义。这些方法实际上已经在基础层类中定义了,它们扮演着我们前面已经讨论过的特殊角色。

来源:知识共享
这两个方法都是通过 call 方法调用的,因此,为了总结整个流程,一旦我们通过层可调用对象传递了张量/占位符,然后 call 方法被调用,该方法依次首先调用构建方法来实例化层,然后调用方法来运行层的逻辑。为了证明我的语句,我在调用和构建方法中添加了打印语句,让我们看看输入张量/占位符传递给可调用层对象后的输出。

在构建和调用方法调用时检查(图片由作者提供)
现在,您可能已经注意到,在定义架构时,我们不需要实际数据,我们只需要层所需的张量形状,并为该张量创建一个占位符,实际数据在 model.fit() 期间传递,数据通过架构向前传播,随后计算误差/损失,然后反向传播,从而更新流程中的权重并训练模型。
结论
虽然这些东西看起来很小,但当我们进入更复杂的深度学习架构,如 LSTM、编码器-解码器等时,了解它们会特别有帮助,对这些基本概念有一点了解有助于我们以后更好地掌握这些复杂的架构,并最终修改和创建我们自己的架构。
内核机器从零开始
图解学习核和再生核希尔伯特空间的概念

本顿·谢尔曼在 Unsplash 上的照片
T 训练一个神经网络模型可能很难,但知道它学到了什么就更难了。早在 1995 年,拉德福德·m·尼尔就证明了具有随机参数的单层神经网络在宽度趋于无穷大时会收敛到高斯过程。2018 年,Lee 等人进一步将结果推广到任意深度的无限宽网络。基于这种联系,我们可以使用高斯过程建立一个模型,模拟一个无限宽的网络——将问题转换成一个可以理解的机制。最近,Arthur Jacot 等人证明了无限宽神经网络在基于梯度下降的训练期间的进化也可以用核(称为神经切线核)来描述。沿着这条道路,越来越多的工作正在用核方法的理论工具来研究神经网络的有趣行为。在深入研究这些伟大的作品之前,有必要深入回顾一下与内核相关的定理。
1.机器学习中的函数空间
为了充分理解核方法背后的理论,首先必须澄清函数空间的概念及其在机器学习中的作用。众所周知,在监督学习中,我们收集一组元组( x₁ 、 y₁ )、…、( xₙ 、 yₙ ),想要找到一个最适合它的函数。更具体地说,目标是找到一个函数 f (。)在一组函数内ℌs . t .σᵢ**l(f(xᵢ)yᵢ)最小化 w.r.t. a 损失函数 l (。,.).这样一组函数,在机器学习领域被称为假设集,就是一个函数空间。因为我们是在 ℌ 内寻找最优解,它越大,我们得到的可接受的解就越多。那么,它能有多大呢?
把函数想成ℝ域上的一个向量,索引为 x ∈𝒳。对于输入空间𝒳of 基数|𝒳|,最大的函数空间将是ℝ^|𝒳 | ,这意味着一旦输入空间具有无限的基数(例如ℝ),相应的函数空间将因此具有无限的维度——如果我们考虑所有的可能性,它最终会有一个我们永远没有机会彻底搜索的无限空间。
为了让生活更容易,我们经常把自己限制在一个更小的假设集内。表征功能形式是这样做的一种方式。通过由参数 w 建立函数形式,我们将搜索空间减少到ℝ^| w |并且确实使问题处于可解状态。然而,没有不带刺的玫瑰。在现实世界的应用程序中,为复杂的数据找到一种函数形式并不容易。即使我们真的想出了一个,学习功能所具备的能力也可能太有限而没有用。现在,我们可能会想,有没有一种方法可以解决这个问题,同时又不会牺牲太多的容量?这就是内核方法的补救方法。

f 的函数空间:线性/多项式函数形式的ℝ → ℝ。图片作者。
2.超越理论——核诱导函数空间的示意图
核,通俗地说,就是输入空间中实例之间的广义内积。像内积所做的一样,一个核函数 K : 𝒳 ×𝒳 → ℝ 描述了输入空间的几何属性,如范数、距离和角度,其中

除了能够表征输入空间,更重要的是能够表征函数空间,也就是再生核希尔伯特空间(简称 RKHS)。
2.1。内核诱导函数空间
让我们试着从零开始构建它,而不是通过定义来理解 RKHS。考虑一个满足内积性质的核函数k:𝒳×t15】𝒳→ℝ。对于每一个 x ∈𝒳,我们进一步定义 Kₓ (。)≦K(。, x ,即 K (。,.)后面的部分固定在 x 处。现在再把函数想象成一个向量。以这组函数为基础,它跨越了一个函数空间ℌs . t .ℌ中的每一个函数都是 Kₓ 的线性组合,建立在 Kₓ 的基础上,如果 Kₓ 形成一个线性独立的集合,那么由此产生的 ℌ 就会有 dim( ℌ )=|𝒳|)达到前述可能的最大空间。
2.2。没有刺的玫瑰——RKHS 和表象定理
在上述的基础上,我们建立了一个最大的功能空间。接下来的问题是,如何在一个无限维的空间内找到一个损耗最小的函数?我们所需要的只是简单地给 ℌ 配备一个复制内核 K 的内积——对于每一个 u 、 v ∈𝒳、 Kᵤ 、kᵥ⟩=k(u、 v )。有了这个特殊化的内积,就有了最强大的定理——表象定理:
给定一组训练样本 ( x₁ , y₁ ),…,( xₙ ,yₙ)∑𝒳×ℝ,每一个经验损失的极小值

对于任意损失函数 L : ( 𝒳 × ℝ ) ⁿ → ℝ以及任意严格递增函数 g : [0,∞) → ℝ,基于其范数来度量函数的复杂度允许以下形式的表示:

总之,它告诉我们,为了找到损失极小值,我们不需要搜索整个无限维空间,而只需要搜索训练数据的表示者(又名 Kₓ )所跨越的子空间。这种特殊的内积背后有什么魔力?怎么能不考虑补空间来找优化器呢?源于内积的非常重要的性质是,对于所有可能的 f ∈ ℌ 和x∈𝒳*t49】的 f 在 x 处的求值相当于在 f 和 Kₓ之间取内积,即 f ( x )=⟨ Kₓ在此基础上,我们可以进一步表明,对于 ℌ 中的任何函数 f ,当我们在训练数据内的任何 x 处对 f 求值时,正交补部分总是贡献零,因此对损失没有贡献。*
2.3。亲手制作 RKHS
了解了内核机器背后的基本原理之后,让我通过一个简单的例子来帮助您更好地理解。假设现在我们要估计一个衡量对三种不同水果偏好的函数,我们得到一个衡量它们之间关系的核矩阵。为了从 K 建立一个函数空间,我们可以用

作为依据,如下图所示。
现在我们观察两点:(苹果,7)和(番石榴,4)。基于表象定理,最优解必须承认以下形式:

结合平方损失,问题就变成了:

生产的

因此


图片作者。
3.内核血液中的奥卡姆剃刀
到目前为止,我们已经演示了如何使用内核来建立假设集,以及如何找到经验损失的最小值。事实上,该解对应于所有产生最小损失的函数中具有最小范数的一个(在某些情况下,通过所有观测数据)。就奥卡姆剃刀的原理而言,它恰恰是最受青睐的一个。
众所周知,神经网络的强大之处不在于能够完美地拟合训练数据,而是能够推广到那些看不见的数据。在将神经网络(用梯度下降训练)与内核机器连接时,内核血液中的剃刀为其成功提供了一种可能的解释。
4.最后的话
自 20 世纪 60 年代以来,与核相关的理论已经非常成熟,利用核技巧的算法通常是处理新数据的首选算法之一。如今,大多数实践者可能具有关于如何针对不同数据构造强大的核的良好知识和经验,并且利用核技巧来建立高容量的学习器,然而,对 RKHS 和相关定理了解不多。在这篇文章中,我试图用一种不涉及太多数学的方式来阐述 RKHS 的思想,希望它能给每一个需要的人带来一些启示。
内核方法:简单介绍
机器学习必须知道
核方法和径向基函数的基础

马库斯·温克勒在 Unsplash 上的照片
介绍
偏差-方差困境支配着机器学习方法。如果一个模型太简单,这个模型将很难找到输入和输出之间的适当关系。但是,如果模型太复杂,它在训练中会表现得更好,但是在处理看不见的数据时会表现出更大的差异,此外,复杂的模型通常计算成本更高。在一个理想的世界中,我们想要一个简单的模型,它训练速度快,并且足够复杂,可以找到输入和输出之间的复杂关系。核方法通过将数据的输入空间映射到高维特征空间来实现这一点,在高维特征空间中可以训练简单的线性模型,从而产生高效、低偏差、低方差的模型。
在这篇文章结束时,希望你能很好地理解这句话的意思以及它为什么重要。
核心方法
在机器学习领域有许多核心方法。支持向量机(SVMs)特别受欢迎,在 20 世纪后期甚至更受欢迎,当时它们开始胜过神经网络。如今,核方法最适用于中小型数据集,以及结果的可解释性很重要的问题。
核方法使用核(或基函数)将输入数据映射到不同的空间。在这种映射之后,可以在新的特征空间而不是输入空间上训练简单的模型,这可以导致模型性能的提高。
由于这是对核方法的介绍,我将把重点放在径向基函数上,这是一个非常简单但很常见的核。在以后的文章中,我将详细讨论支持向量机。
线性回归和径向基函数
在回归问题中,我们试图估计从 X 推断 Y 的最佳函数。如果我们在 X 和 Y 之间有非线性关系,就不能简单地用此数据拟合线性模型。然而,内核方法的目标是使用这些线性模型,并且仍然创建非线性关系。
内核方法通过将数据转换到一个更高的维度,并在这个维度上拟合一个线性模型来做到这一点。通过这样做,我们有效地拟合了原始输入空间中的高阶模型。
线性回归
让我们看看线性回归的解析解,然后我们就可以理解如何使用核方法来生成使用这种线性模型的非线性映射。

最佳线性回归是使我们的模型预测和目标输出 y 之间的平方距离最小化的回归。平方误差如上所示。最小化该误差给出了最佳解决方案。

我们可以对最小二乘误差相对于我们的模型的权重进行微分,以找到产生最小误差的权重向量。结果是伪逆解。
为了正确理解任何线性代数公式,你必须熟悉每个变量的维数:

输入数据 X 是 (Nxd) 维,其中 N 是数据点的数量, d 是特征的数量。因此,逆计算将是一个 (dxd) 矩阵,并且得到的权重矩阵是一个 (dx1) 。我们的权重向量与输入数据中的要素具有相同的维数。这是有意义的,因为当我们从 X 推断 Y 时,我们取权重和输入数据之间的点积,因此输入必须与我们的权重具有相同的维数。
高维空间中的线性回归
核方法通过使用核或一组 M 基函数将数据矩阵 X 映射到新的设计矩阵 U。新的设计矩阵具有更高的维数(NxM,其中 M ≥ d)。

我们可以通过取 m 个基函数(ϕ)来构造一个设计矩阵 u,每个基函数由它们自己的均值和标准差来参数化。上述等式中的平均值将具有 (dx1) 的维数。因此,对于输入空间中的每个数据点,我们应用 M 个基函数,将输入维度 (Nxd) 转换为新的设计矩阵 (NxM) 。
RBF 使用高斯基函数。每个基函数代表输入空间中的高斯分布。在所有高斯分布中评估每个数据点。结果是输入向量从 d 维到 M 维的映射。
为了选择参数化这些高斯分布的均值和标准差,可以使用 k 均值聚类来获得参数化基函数的均值和标准差。
现在我们有了设计矩阵 U,并且我们已经将输入数据映射到高维空间,我们可以在这个新的特征空间中拟合线性模型。

通过表达来自特征空间的估计和我们的目标 y 之间的最小二乘误差,并对我们的新权重向量 l 进行微分,我们发现最优解与输入数据中的线性回归的最优解具有相同的形式。
这里需要注意的关键点是,我们的权重向量 (l) 现在是一个 Mx1 向量,在原来的输入空间中,权重向量是一个 dx1 向量(还记得 M > d)。
合成数据示例

作者图片
这是合成的非线性数据。我有 10000 个数据点,我的 Y 坐标是一维的。这意味着我的数据矩阵 X 的维数为(10,000×1)。我们可以通过使用上面看到的伪逆解决方案计算最佳权重,尝试将线性模型拟合到该数据。显然,正如你在上面看到的,它的表现并不好。
通过在高维特征空间中拟合该相同的线性模型,我们获得了数据中真实关系的更好的近似。
首先,我对每个数据点应用 200 个基函数。我在输入空间中取 200 个高斯分布,并在所有基本函数上评估每个数据点。我的新设计矩阵现在是(10,000x200)维。然后,我使用相同的伪逆解来获得这个新特征空间中的最优权重。

作者图片
如您所见,RBF 模型估计的关系是非线性的,并且与数据吻合得很好。记住,这个新模型仍然是一个线性回归变量!但是因为我们在新的特征空间中拟合它,所以我们在原始输入空间中间接地拟合一个复杂的非线性模型。
结论
核方法使用核(或一组基函数)将我们的低维输入空间映射到高维特征空间。当在新的特征空间中训练线性模型(类型为 ax + b 的线性模型)时,我们本质上是在原始输入空间中训练高阶模型(例如类型为 ax +bx +c )。通过这样做,您保留了简单模型的所有优势(如训练速度、有分析解决方案、较低的方差),但也获得了更复杂模型的优势(更好的映射、更低的偏差)。本质上,这就是内核方法如此强大的原因!
支持我
希望这对你有所帮助,如果你喜欢,你可以跟我来!
你也可以使用我的推荐链接成为中级会员,访问我所有的文章等等:https://diegounzuetaruedas.medium.com/membership
你可能喜欢的其他文章
Python 中的内核回归
如何在 Python 中手工进行内核回归
目录
- 2.0.1 步骤 1:计算单个输入 x 点的核
- 2.0.2 可视化所有输入 x 点的内核
- 2.0.3 步骤 2:计算每个输入 x 值的权重
- 2.0.4 步骤 3:计算单个输入点的 y 预测值
- 2.0.5 步骤 4:计算所有输入点的 y 预测值
- 2.0.6 第五步:想象两种方法的区别
本笔记演示了如何在 python 中手动执行内核回归。虽然 Statsmodels 为内核回归提供了一个库,但是手工进行内核回归可以帮助我们更好地理解我们是如何得到 find 结果的。
首先,我将展示如何使用 Statsmodels 完成内核回归。接下来我将展示如何手工完成,然后最后叠加两个图以显示结果是相同的。
首先,让我们通过统计模型来看看内核回归
1 统计模型的核心回归
我们通过使用 lambda 函数来生成 y 值。你可以改变 lambda 函数,看看会发生什么。x 值,即独立变量,由new_x控制,我们已经替换了 x 值,以显示您可以
1.1 生成虚假数据
import numpy as np
import plotly.express as px
from statsmodels.nonparametric.kernel_regression
import KernelReg as kr
import plotly.graph_objs as go
import pandas as pd
1.1 生成虚假数据
np.random.seed(1)# xwidth controls the range of x values.
xwidth = 20
x = np.arange(0,xwidth,1)# we want to add some noise to the x values so that dont sit at regular intervals
x_residuals = np.random.normal(scale=0.2, size=[x.shape[0]])# new_x is the range of x values we will be using all the way through
new_x = x + x_residuals# We generate residuals for y values since we want to show some variation in the data
num_points = x.shape[0]
residuals = np.random.normal(scale=2.0, size=[num_points])# We will be using fun_y to generate y values all the way through
fun_y = lambda x: -(x*x) + residuals
让我们绘制数据。在这篇文章中,我们将使用 Plotly express 进行所有的绘图。
# Plot the x and y values
px.scatter(x=new_x,y=fun_y(new_x), title='Figure 1: Visualizing the generated data')

我们的目标是使用回归拟合上述数据点的曲线。我们该如何着手呢?使用 statsmodels 相当简单。
1.2 内核回归的输出
Statsmodels 非参数回归模块内核回归的输出是两个数组。
1)预测的 y 值
2)边际效应
对于单变量回归问题,边际效应本质上是预测值对独立变量的一阶导数。更多关于边际效应的信息可以在这里找到。
fig = px.scatter(x=new_x,y=fun_y(new_x), title='Figure 2: Statsmodels fit to generated data')
fig.add_trace(go.Scatter(x=new_x, y=pred_y, name='Statsmodels fit', mode='lines'))

2 Python 中的手工内核回归
要手工进行内核回归,我们需要了解一些事情。首先,这里是内核的一些属性。
1)内核是对称的,即
K(x) = K(-x)
2)核函数下的面积等于 1 的意义

我们将使用高斯核来解决这个问题。高斯核具有以下形式:

其中 b 是带宽,xi 是因变量的点,𝑥x 是我们定义核函数的值的范围。在我们的例子中,𝑥𝑖来自new_x
2.0.1 步骤 1:计算单个输入 x 点的内核
kernel_x = np.arange(-xwidth,xwidth, 0.1)
bw_manual = 1def gauss_const(h):
"""
Returns the normalization constant for a gaussian
"""
return 1/(h*np.sqrt(np.pi*2))def gauss_exp(ker_x, xi, h):
"""
Returns the gaussian function exponent term
"""
num = - 0.5*np.square((xi- ker_x))
den = h*h
return num/dendef kernel_function(h, ker_x, xi):
"""
Returns the gaussian function value. Combines the gauss_const and
gauss_exp to get this result
"""
const = gauss_const(h)
gauss_val = const*np.exp(gauss_exp(ker_x,xi,h))
return gauss_val# We are selecting a single point and calculating the Kernel value
input_x = new_x[0]
col1 = gauss_const(bw_manual)
col2= gauss_exp(kernel_x, input_x, bw_manual)
col3 = kernel_function(bw_manual, kernel_x, input_x)
我们希望显示单点 xi 的数据帧。
# Dataframe for a single observation point x_i. In the code x_i comes from new_x
data = {'Input_x': [input_x for x in range(col2.shape[0])],
'kernel_x': kernel_x,
'gaussian_const': [col1 for x in range(col2.shape[0])],
'gaussian_exp': col2,
'full_gaussian_value': col3,
'bw':[bw_manual for x in range(col2.shape[0])],
}
single_pt_KE = pd.DataFrame(data=data)
single_pt_KE

我们还想可视化一个单一的内核函数。
# Plotting a scatter plot of Kernel
px.line(x=kernel_x, y=col3, title='Figure 3: Kernel function for a single input value')

2.0.2 可视化所有输入 x 点的内核
我们希望可视化每个𝑥𝑖xi.的内核𝐾(𝑥)K(x)下面我们计算内核函数值,并将它们存储在一个名为kernel_fns的字典中,该字典被转换成一个数据帧kernels_df。然后,我们使用 Plotly express 来绘制每个核函数。
## Plotting gaussian for all input x points
kernel_fns = {'kernel_x': kernel_x}
for input_x in new_x:
input_string= 'x_value_{}'.format(np.round(input_x,2))
kernel_fns[input_string] = kernel_function(bw_manual, kernel_x, input_x)kernels_df = pd.DataFrame(data=kernel_fns)y_all = kernels_df.drop(columns='kernel_x')
px.line(kernels_df, x='kernel_x', y=y_all.columns, title='Gaussian for all input points', range_x=[-5,20])

2.0.3 步骤 2:计算每个输入 x 值的权重
我们需要计算单个输入的权重。使用以下表达式计算重量:

上面的等式代表了new_x的𝑖𝑡ℎith 元素的权重,其中𝑥x 是new_x的所有元素。分母是new_x中所有点的总和。这里值得注意的是,您将使用所有输入点的核来计算权重。上面的等式基本上在 0 和 1 之间调整权重。
上面的等式已经在函数weights中实现,该函数给出了单个输入点的权重。。该函数采用单个输入点,并给出一行权重。它通过在实现上述等式的同时循环遍历所有输入点来做到这一点。
2.0.4 步骤 3:计算单个输入点的 y 预测值
我们从下式得到𝑖𝑡ℎith 点的预测值:

该等式在函数single_y_pred中实现。我们对从weights函数中得到的权重行和来自假数据的 y 值进行点积。上面的等式表示点积。
def weights(bw_manual, input_x, all_input_values ):
w_row = []
for x_i in all_input_values:
ki = kernel_function(bw_manual, x_i, input_x)
ki_sum = np.sum(kernel_function(bw_manual, all_input_values, input_x))
w_row.append(ki/ki_sum)
return w_rowdef single_y_pred(bw_manual, input_x, new_x):
w = weights(bw_manual, input_x, new_x)
y_single = np.sum(np.dot(fun_y(new_x),w))
return y_singleypred_single = single_y_pred(bw_manual, new_x[0], new_x)
2.0.5 步骤 4:计算所有输入点的 y 预测值
以下代码在所有输入点上循环,计算预测值并将其附加到Y_pred。一旦我们有了预测值,我们现在需要做的就是将它们可视化。
Y_pred = []
for input_x in new_x:
w = []
Y_single = single_y_pred(bw_manual, input_x, new_x)
Y_pred.append(Y_single)
2.0.6 步骤 5:想象两种方法之间的区别
现在,我们已经通过手动计算预测值获得了预测值,我们可以将我们的回归曲线与从 statsmodels 获得的曲线进行比较。我们将合身的衣服重叠在彼此的上面,并且合身到它们完全匹配。
data= {'x': new_x, 'y': fun_y(new_x), 'y_manual': np.array(y_all)}
fig = px.scatter(x=new_x,y=fun_y(x))
fig.add_trace(go.Scatter(x=new_x, y=pred_y, name='Statsmodel KR', mode='lines'))
fig.add_trace(go.Scatter(x=new_x, y=np.array(Y_pred), name='Manual KR', mode='lines'))

3 结论
本文通过一个使用生成数据的简单示例,展示了我们如何理解内核回归算法的内部工作方式。如果你从这篇文章中学到了什么,请喜欢并分享这篇文章。
感谢您的阅读!
4 参考文献
- https://www . stat . CMU . edu/~ ryantibs/adv methods/notes/kernel . pdf
- https://mccormickml.com/2014/02/26/kernel-regression/
- http://faculty . Washington . edu/yen chic/18W _ 425/le C9 _ reg 01 . pdf
提高你对概率论理解的关键概念
我在 MITx 概率课程中学到的六个概念

米克·豪普特在 Unsplash 上的照片
如果我必须总结我在统计和数据科学 MITx Micromaster 项目期间在概率领域学到的东西,会是什么?
我想在这里介绍的是我觉得特别有趣的一些话题,在讲座概率——不确定性和数据的科学中有很好的解释。
我不会用整个课程来烦你,但我想总结一下在概率世界中非常重要的六个概念。
让我们谈论以下话题:
- 紧凑的书写约定
- 取样台
- 有条件地思考
- 转换
- 独立同分布随机变量
- 大数定律和中心极限定理
紧凑的书写约定
为什么重要?
一个命名约定不会帮助你理解概率论,但一定会帮助你掌握和记忆一些公式。
越简单越好。MITx 讲座中公式的书写方式使它清晰而紧凑。例如,每个随机变量用大写字母表示,密度概率函数用小写字母表示,用竖线表示,等等。
例如,下面用七个字符编写的函数将告诉您如下内容:“已知事件“A”发生时,随机变量“X”在样本点 X 的概率密度函数“f”

简洁明了。
取样台
当你试图回答一个问题时,比如“我可以得到多少个 k 尺寸的样本?”时,请快速跳到这个表格。
例如,一个装满三个标记为“1、2 和 3”的扑克筹码的桶可以用四种不同的方式绘制。让我们来看看它们:
- “用替换;顺序问题":替换意味着我们可以多次抽取同一个球,当顺序很重要时,像“1,1,3”这样的样本将被认为与我们抽取的“3,1,1”不同。
- “用替换;顺序无关紧要":和之前一样,但是如果我们用顺序“1,1,3”或者“3,1,1”来抽球,那就没关系了。它将被视为一个独特的样本。
- “无需更换;顺序问题":没有替换意味着我们不能多次抽取一个球,即像“1,1,2”这样的样本是不可能的。
- “无替换;顺序无关紧要":在这个场景中,我们不能多次绘制一个球,并且像“1,2,3”这样的样本会被认为是与“3,2,1”相同的样本
我们现在可以在一个表中总结所有四种情况,并计算从装满 n 个不同碎片的桶中取出 k 个碎片可以创建多少个不同的样本。该表如下所示:

有条件地思考
为了支持这一点,我将采用贝叶斯法则,它给出了一个事件(A)的条件概率,假设另一个事件(B)已经发生。

如果我们认为另一个事件(C)在这两个事件之前已经发生了呢?那么,在这种情况下,我们可以如下计算给定 B 和 C 的概率:

有趣的是我们如何在这个公式中加入事件 C。当我们“有条件地思考”时,我们把自己投射到一个我们知道某些事件已经发生的宇宙中。
另一个例子是独立的概念。给定 C,当两个变量(A 和 B)独立时,我们得到以下等式:

转换
如果我知道一个随机变量 X 的分布,但是我想知道 Y=g(X)的分布怎么办?
好吧,如果你知道 X 是如何分布的,你会很高兴听到有一个通用的“配方”来了解变量 Y 的分布。
让我们来看看这个三步食谱:
- 计算 g(X)的反函数。这意味着为了得到 X=h(Y ),你要变换映射 Y=g(X)
- 计算累积分布函数(CDF) P(y < h(y))
- 对 CDF 求导,得到密度函数
希望你不必总是一个人做。如果函数 g(X)可微且严格递增或严格递减,可以直接应用以下公式:

有趣的是,如果你有一个包含多个随机变量的函数,比如 Z = g(X,Y),你也可以应用同样的原理。此外,如果您的函数是一个简单的加法(g(X,Y) = X + Y),您将得到一个卷积,如下所示:

独立同分布随机变量
这两个概念是概率论中的关键,因为它们是应用中心极限定理的基本条件。
让我们用一个例子从独立性的概念开始:如果我们考虑第一个事件“A”,比如“在超市购买时得到一个公平的骰子”,以及事件“B”,比如“当投掷我刚买的骰子时得到六号”。这两个变量是相互依赖的,因为骰子的公平性将影响投掷时获得数字 6 的概率。
我们会说,两个随机变量是独立的,当(且仅当)下列陈述之一成立:

这就是独立的概念。现在让我们讨论“同分布”的概念。
对于这个概念,如果两个随机变量的概率函数完全相同,则它们是同分布的。例如,如果“X1”是一个随机变量,它描述了我们投掷骰子的结果,而“X2”描述了我们第二次投掷相同骰子的结果。两个随机变量有完全相同的概率分布。
大数定律和中心极限定理
这些概念可能属于概率和统计中教授最多的原理。为什么这么重要?
为了回答这个问题,我想引用菲利普·里戈莱特教授的话:
据统计,99%的人在做一般的事情,剩下的 1%的人在做一些新奇的事情。
所以让我们从直观的开始:大数定律(LLN)。这个想法是你平均“n”个随机变量,它们彼此独立,并且遵循相同的概率分布。换句话说,你的平均“n”个自变量有一个相似的期望(假设μ)。所以你应该期望平均值的期望值也是μ。
这正是 LLN 告诉你的。当“n”趋于无穷大时,下面平均值的期望值也是μ。

中心极限定理(CLT)不太直观,但同样重要。它会告诉你你的平均值是如何分布的。
令人惊讶的是,它不依赖于你的变量(X1,…,Xn)的分布。总会收敛到一个正态分布。

好吧,但是我如何在实践中获得无限数量的数据点呢?
不用担心,你不需要得到这么多的数据点。
在他的讲座统计学基础中,Philippe Rigollet 教授解释说,当“n”大于 30 时,你就已经对 CLT 有了一个很好的估计。他还补充说,为了评估生死攸关的情况,我们只需选择大于 50 的“n”。
一锤定音
在麻省理工学院在线讲座概率——不确定性和数据的科学中,我们一起看到了我觉得特别有趣的六个概念。
概率论是一门庞大的学科,我给了你们一些概念,这些概念是我在研究这门学科时很高兴发现的。
总而言之,我们看到了以下概念:
- 在编写概率公式时,紧凑的编写约定对于提高效率至关重要。我也确信这将有助于你记忆它们。
- 每当我们有诸如“我能得到多少个 k 大小的样本?”这样的问题时,我们可以快速地看一下我们的“抽样表”。
- “有条件地思考”和“转换”这两章可以帮助我们操作密度函数。
- “独立同分布随机变量”的概念是应用大数定律和中心极限定理的基础。
好奇想了解更多关于 Anthony 的工作和项目吗?在媒体和 LinkedIn 上关注他。
需要技术作家?将您的请求发送到https://amigo CCI . io。
MLOps 专业化认证的关键学习点—课程 2
MLOps 专业化系列
DeepLearning 的面向生产的机器学习工程(MLOps)课程摘要(含课堂讲稿)。艾&吴恩达

昆腾·德格拉夫在 Unsplash 上的照片
虽然机器学习( ML )概念是必不可少的,但生产工程能力是在现实世界中部署和交付 ML 模型价值的关键。
深度学习。AI 和 Coursera 最近开发了 MLOps 专业化课程来分享如何概念化、构建和维护集成的 ML 系统。
在这篇文章中,我总结了这些课程,这样你可以跳过冗长的讲座,同时仍然获得关键的见解。
内容

本文涵盖课程24-课程 MLOps 专业化。 跟随本媒体页面 了解后续课程的最新内容。
课程 2 概述
第二个课程(生产中的机器学习数据生命周期)关注生产 ML** ,定义为生产环境中 ML 系统的部署。**
生产 ML 结合了 ML 和现代软件开发,因为现实世界的 ML 解决方案需要的不仅仅是训练精确的算法。

生产 ML 不仅仅是训练机器学习模型|作者图片
数据从业者的目标应该是构建集成的 ML 系统,该系统在生产中持续运行,自动接收和重新训练持续变化的数据,并针对计算成本进行优化。
本课程涵盖生产 ML 生命周期的三个关键组成部分:
- 收集、标记和验证数据
- 特征工程、转换和选择
- 数据旅程和数据存储

照片由seli̇m·阿尔达·埃尔伊尔马兹在 Unsplash 上拍摄
主要经验教训
本着本课程强调实际应用的精神,要点将集中在实用的建议上。这些见解是基于前面提到的三个生命周期组成部分组织的。
(1)收集、标记和验证数据
- 端到端 ML 平台对于部署生产 ML 管道至关重要。谷歌的团队使用开源的tensor flow Extended(TFX)用于生产 ML。

TensorFlow 扩展框架|在 Apache 许可下使用的图像
- TFX 流水线是为可伸缩、高性能的 ML 任务而设计的一系列组件。

端到端生产 ML 平台中的组件序列|作者图片
- 前两个组件(数据摄取和数据验证)与数据收集、标记、和验证任务相关。
㈠数据收集
- 数据团队的目标是将用户需求转化为数据问题,所以首先要评估的是数据本身。这里列出了要问的关键问题:
- 有什么样的/多少数据可用?
- 有哪些详细的数据?
——数据有标注吗?如果不是,给它贴上标签有多难/多贵?
—新数据多久进来/刷新一次?
—是否监控数据源的系统问题和中断? - 有哪些预测特征? -数据集是否包含具有预测值的要素?
- 要跟踪的标签有哪些?
- 衡量模型性能的指标有哪些?
- 数据质量如何?
—是否存在不一致的数据格式(如混合类型)和影响模型性能的异常值?
(二)数据标注
- 标签是必不可少的,因为监督学习(需要标签)通常在大多数商业案例中使用。
- 贴标方法多种多样,最常见的两种是过程反馈和人工贴标。

数据标注的两种方法|作者图片
- ****过程反馈是一种通过从分析系统日志文件中获取信号来持续创建新的训练数据的方式,例如点击通过(即客户是否点击了而非点击)。这样做的一个问题是,这种情况很少发生。
- ****人工标记是一种更标准的方法,我们将未标记的数据传递给人工标记者(又名评分者)来检查和手动分配标签。
- 虽然人工标记很简单,但是会出现几个问题:
- 招聘可能会昂贵,尤其是如果项目需要专家标记,例如放射科医生标记 x 光图像
- 如果评定者的数量很少,贴标可能会很慢
- 如果评分者的标签标准存在差异,质量问题就会出现
- 我们可以通过创建清晰的说明来指导评分者,并促进标签冲突的积极解决,从而提高标签的一致性。
(三)数据验证
- 由于现实世界数据的不断变化,生产 ML 系统的性能会随着时间的推移而下降。
- 需要有一个数据验证工作流程来检测这些重要的数据问题。
- TensorFlow 数据验证( TFDV ) 是一个高度可扩展的库,通过对大规模数据的理解、验证和监控,帮助开发者维护 ML 管道的健康。

显示 TensorFlow 数据验证在 ML 管道中的位置|在 Apache 许可下使用的图像
- 以下是需要验证的关键数据漂移和偏斜问题:
- ****概念漂移:输入和输出变量之间的关系(即映射)随时间的变化
- ****模式偏斜:训练和服务数据不符合相同的模式(例如,由于存在不同的数据类型)
- ****分布偏差:服务和培训数据的分布有显著差异(例如,由于随时间的季节性变化)。这种偏斜包括数据集偏移和协变量偏移的粒度问题。
- ****特征偏斜:训练特征值不同于服务特征值(例如,由于仅在训练集上应用的变换)

倾斜检测工作流程示例|作者图片
(2)特征工程、转换和选择
(一)特征工程
- 生产 ML 中的特征工程的基本目的是减少计算资源,这是通过将预测信息集中在更少的特征中以提高计算效率来实现的。
- 特征工程中的不一致性会引入训练-服务偏斜,导致服务模型性能不佳。出现这些不一致的原因是:
- 训练和服务代码路径是不同的(例如,在 Python 中训练,但在 Java 中服务),导致两者之间不同的转换
- 多样的部署场景(例如,部署在不同环境中的模型,如移动、web 和服务器)
(二)特征转化
- 特征转换以两种类型的粒度发生:
- ****实例级:只涉及实例(也就是一行数据)。示例包括乘法(例如,对特征求平方)和裁剪(例如,通过将负值更改为 0 来设置非负边界)
- ****全通:涉及整个数据集。示例包括标准缩放、最小-最大缩放和宁滨。
- 有不同的时间点来执行转换:
- 在输入模型之前转换训练数据
- 在模型内变换
- 每个时间点都有利弊,这些是生产成本和效率的基本考虑因素。****

不同转变时间点的利弊|作者图片
- TensorFlow Transform (TFT)是一个用于预处理和转换数据的有用的库,这样的框架对于以高效和分布式的方式处理大型数据集是必不可少的。

显示 TensorFlow Transform 在 ML 管道中的位置|在 Apache 许可下使用的图像
(三)特征选择
- 有三种主要的监督特征选择方法:过滤、包装和嵌入。

特征选择方法|作者图片
- 除了使用性能指标(如 F1 分数、AUC)进行方法评估外,还应评估应用这些方法后的特征数(又名特征计数)。****
- 理想的情况是性能指标最大化,而特性数最小化。
(3)数据旅程和数据存储
㈠数据来源
- 数据起源(又名世系)是对数据和模型从原始输入到输出工件的演变过程中的一系列转换的跟踪。****
- 理解数据旅程(以及数据来源)对于调试和再现性至关重要。如果不跟踪,则重新创建、比较或解释** ML 模型变得不可行。******
- 每次管道运行都会生成有用的元数据,其中包含有关管道执行、训练运行和结果工件的信息。****
- ML 元数据(MLMD) 是一个用于记录和检索与生产管道运行相关的元数据的库。

在 Apache 许可下使用的 ML 元数据组件|图像的高级概述
㈡数据版本化
- 管理数据管道是一项挑战,因为数据在项目生命周期的不同训练运行中不断发展。
- 虽然我们熟悉代码版本化(例如 Git)和环境版本化(例如 Docker),但是数据版本化同样重要,并且在数据起源中起着至关重要的作用。****
- 数据版本化工具开始变得可用,现有的一些例子有 DVC 和 Git LFS 。

DVC 如何工作的流程图(与 Git 一起)|在 Apache 许可下使用的图像
㈢特色商店
- 特征库是一个中央存储库,用于存储文档化的、管理的和访问受控的数据特征,团队可以共享、发现和使用这些数据特征进行模型训练和服务。****
- 特征库减少冗余工作,因为许多建模问题使用相同或相似的特征。****
- 目标是提供统一、一致和持久的方法来管理高性能和可伸缩的数据特性。

特征存储有助于存储工程特征,以用于后续模型开发|作者图片
㈣数据仓库与数据库和数据湖
- 有几个领先的数据存储解决方案,分别是数据库、数据仓库、数据、湖泊。****
- 数据库是一个有组织的数据集合,允许轻松访问和检索。
- 数据仓库是一个中央信息存储库,旨在通过分析做出明智的决策。
- 一个数据湖是一个集中的存储库,允许你以任何规模存储你所有的结构化和非结构化数据。****
- 下面是解释这些解决方案的效用的比较:
数据仓库与数据库

数据仓库与数据湖

PDF 课堂讲稿
为了表示感谢,下面是 GitHub repo 的 链接,以及我根据幻灯片和抄本整理的 pdf 讲义 。
要了解后续课程的最新笔记,也可以随意给回购打个星。
准备好了吗?
以下是后续课程 3 的文章:****
******
如果您还没有,请查看该系列的课程 1 :
在你走之前
欢迎您加入我的数据科学学习之旅!点击此媒体页面,查看我的 GitHub ,了解更多精彩的数据科学内容。同时,享受构建生产 ML 系统的乐趣!
******
MLOps 专业化认证的关键学习点—课程 1
MLOps 专业化系列
《面向生产的机器学习工程》课程 1 (由 DeepLearning 提供)的主要见解(附讲稿)。艾&吴恩达)

由 Drif Riadh 在 Unsplash 上拍摄的照片
对于围绕机器学习模型的所有宣传,除非部署到生产中以交付商业价值,否则它们没有用。
吴恩达和深度学习。艾对此深有体会,创建了 MLOps 专精 分享自己在量产化 ML 系统上的实践经验。
在这篇文章中,我总结了经验教训,这样你就可以跳过几个小时的在线视频,同时仍然能够收集关键的见解。
内容
这篇总结文章涵盖了 4 门课程的 MLOps 专业化认证的第 1 门课程。 跟随本页 了解后续课程的最新内容。
课程 1 概述
MLOps 专业化的第一门课程名为生产中的机器学习介绍,并介绍了端到端生产化 ML 系统的开发、部署和持续改进。
这门课程是围绕一个 ML 项目生命周期的组成部分组织的,我发现这是一个构建 ML 计划的有用框架。

ML 项目生命周期(改编自课程)|作者图片
主要经验教训
本着本课程强调实际应用的精神,我将分享注重实用建议的关键要点。
第 1 部分—范围界定
从正确的问题开始,集中注意力
- 首先与企业主一起确定最有价值的业务问题(以及而不是人工智能问题或解决方案)。
- 一个引发讨论的好问题是“你希望做得更好的前三件事是什么?”。
- 通过参考外部基准(例如,文献、竞争对手),评估人的水平表现(对于非结构化数据),或查看是否有可预测结果的适当特征(对于结构化数据)。
- 技术和业务团队应就一组通用指标达成一致,因为 ML 团队倾向于过度关注技术指标(例如 F1 分数),而利益相关方则关注业务指标(例如收入)。

范围界定流程(改编自课程)|图片由作者提供
第 2 部分—数据
针对不同数据问题的不同实践
- 数据问题根据数据的大小和类型进行分类:

数据问题的分类(改编自课程)。10000 个数据大小示例的临界值是由吴恩达* | 作者图片定义的任意数字*
- 非结构化数据:使用数据增强和人类标记来获得更多的训练数据,因为很容易生成音频或图像等数据。
- 结构化数据:使用数据扩充很难创建更多的表格数据,因此应关注数据和标签的质量。
- 小数据集:通过手工检查,确保例子以干净和一致的方式被标记,因为干净的标签对小数据的模型性能有巨大的影响。
- 大数据集:不可能手工检查标签,所以重点应该放在建立定义良好的、可扩展的数据流程上。
- 向与你的 ML 问题在同一个数据象限工作过的人寻求建议,因为不同的场景有不同的做法。
提高标签一致性
- 标签一致性对于大型数据集也很重要,因为它们可能包含罕见事件,为了获得良好的模型性能,必须对这些事件进行准确标记,例如在大型 X 射线图像数据集中的罕见诊断。
- 要建立标签标准,让多个贴标机给相同的样品贴标签。在有分歧的地方,召集团队(以及主题专家)来解决这些分歧。
- 记得写下并记录这些达成一致的定义。
- 目标是有标准化的定义和实践,以便后续的标签任务以干净和一致的方式完成。
- 提高标签一致性是一个反复的过程,所以考虑重复这个过程,直到分歧尽可能得到解决。
第 3 部分——建模
以数据为中心,而不是以模型为中心
- 传统上,重点是在保持数据集固定的同时调整和改进模型代码。

人工智能系统包括数据和代码|作者图片
- 对于实际项目来说,采用以数据为中心的方法实际上更有用,在这种方法中,你专注于向模型提供高质量的数据,而 T4 保持模型不变。
- 通常情况下,一个有好数据的合理算法会做得很好,甚至会比一个有不太好数据的伟大算法做得更好。
- 致力于一个可行的实用系统,所以从基本的已建立的模型(例如,从现有的开源项目)开始,而不是沉迷于最新的最先进的算法。
好的平均表现还不够好
- 如果一个 ML 系统在一组非常重要的例子上的性能很差,那么它就不适合部署,即使它在测试集上的平均性能很好。
- 对数据的关键片段单独评估模型性能,以确保不存在基于特定特征(如种族、性别、位置)的歧视,并且模型在罕见情况下也表现良好。
第 4 部分—部署
部署模式
- 部署不应被视为二元结果(即部署或不部署),而应被视为一系列不同的自动化程度。
- 使用的自动化程度高度依赖于用例、模型性能和业务的舒适度。
- 最终目标需要而不是完全自动化。例如,人工参与的部分自动化对于基于人工智能的医学扫描解释来说是一种理想的设计,在预测可信度较低的情况下,需要人工判断。

自动化程度(改编自课程)|图片由作者提供
- 部署 ML 系统的常用方法包括:
- 影子模式部署:ML 模型与现有的人类工作流程并行,作为在让它代替人类在地面上做出真正决策之前验证其性能的一种手段。**
- 金丝雀部署:最初在一小部分(例如 5%)流量/数据上推出 ML 模型,然后在密切的性能监控下逐步提升。****
- 蓝绿部署:通过将流量/数据重新路由到新(绿)模型,替换(逐渐或立即)现有的旧(蓝) ML 模型。
系统监控
- 在第一次部署 ML 系统、之后,你实际上是离终点只有一半路程,因为和还有很多工作要做。这包括系统监控、模型更新和重新训练,以及处理数据变化,例如概念漂移和数据漂移。**
- 对于监控,集思广益,找出可能出错的地方,并想出几个要监控的指标(最好是在仪表板中)。
- 这些可以分为三大类,即输入指标(例如缺失值的数量);输出指标(例如空输出响应的数量),以及软件指标(例如服务器负载、延迟)。**
- 在选择一组要监控的指标后,通常的做法是为警报设置阈值。**

监控指标示例|按作者分类的图像
课堂笔记
为了表示感谢,下面是 GitHub repo 的 链接,以及我根据幻灯片和文稿整理的 pdf 讲义 。为了从后续课程中获得最新版本的编译笔记,请随时启动 repo。

照片由 Cathryn Lavery 在 Unsplash 拍摄
结论
最后,重要的是要记住 ML 模型代码只是成功的 ML 系统的一小部分(~ 5–10%),目标应该是通过将 ML 模型投入生产来创造价值。

ML 生产系统概述|作者图片
不管你是否有过 ML 制作的经验,我希望这些外卖给了你一些新鲜的观点和有价值的见解。
这些学习要点只是许多实用建议的的子集,所以一定要查看课程笔记和视频。****
欢迎您加入我的数据科学学习之旅!关注此媒体页面以了解更多数据科学内容(以及后续发布的 MLOps 笔记),或者在 LinkedIn 上联系我。享受学习 ML 生产系统的乐趣!
准备好了吗?
在这里继续第 2 部分!
*** ***
试卷的数学解释
神经机器翻译的有效推理
有大量的新论文,通常很难理解它们背后的数学原理。作为数据科学家,了解最重要的领域总是很有趣,即使它们不属于我们最了解的领域……

照片由 Soner Eker 在 Unsplash 上拍摄
简介
不做一些关于以前发现的故事,不了解当前的背景,就不可能解释最近发生的事情。
如今,许多公司和大学都在积极研究语言课题:
- 徐等人已经成功地做出了一个比最新语言学习速度快 6000 倍的翻译算法。
- 熊等人也开发出了很棒的方法,使语音识别。
- Seurin 等人做了一个高效的强化算法来识别说话人。
- 和 Yi-Te Hsu 等人也为加快 Vaswani 等人在 2017 年开发的最先进的翻译算法做出了贡献。
我们将解释 Yi-Te Hsu 等人在 2020 年撰写的论文神经机器翻译的有效推理背后的数学机制。

2020 年 NLP 论文综述。图片作者。
但是首先,为什么拥有快速翻译系统如此重要?
1。 对高效翻译系统的兴趣
高效的语言翻译至关重要,原因如下:
-广泛使用,甚至是实时使用(如 Youtube 视频、视频会议、直接对话、网页等)。
-它拥有大量具有强大价值的数据,因为它们包含知识甚至情报。
-其数据总体质量良好,并且是音频或文本格式,即比图像或视频等其他类型的数据更轻。
然而,由于要处理的数据量巨大,翻译需要高效的算法:无论是实时语音或书面翻译,还是任何延期的翻译请求。
2。 翻译系统:回到原点
第一个机器翻译实验是 1954 年在乔治城的 IBM 公司进行的。
它基本上是一个能够由不懂俄语的人按照一套 6 条规则将从俄语翻译成英语的系统。结果是成功的,并通过理解和应用特定的规则建立了翻译系统的基础,机器将逐步建立并自动翻译,甚至不需要事先教会它们。
如今,所有的规则都是自动建立的,这主要归功于使用大量翻译句子的编码器/解码器过程,通常使用包括记忆系统的神经网络(例如: LSTM :长短期记忆,它学习单词的顺序结构)。
编码器 将把句子转换成潜在代码,这仅仅是一种高级概率语言。
注:高级表示初始句子的压缩表示,适合解码器解释。
解码器将解释该高级代码,并且通过迭代学习过程,即通过减少获得的结果和预期结果之间的误差,将其转换成目标语言。

自动编码器:通过减少 X-X’的二次误差来改进代码 z。图片作者。
并且表现最好的翻译模型通过注意机制连接。
3。 什么是注意机制?
当我们专注于几件事情来权衡它们之间的意义时,注意力机制与我们拥有的机制是一样的。这就是我们在阅读一篇文章时所做的:我们必须检测单词之间的联系,以便从中提取知识。
注意力模型遵循同样的逻辑,它被发明出来解决长句的翻译问题。
关键元素是上下文向量:它计算单词彼此接近的概率。在成千上万个学过的句子中,经常互相靠近的单词比不靠近的单词得分更高。越近越频繁越好。
例如,如果我们将“飞机降落在没有着陆跑道的玉米地附近”翻译成法语,由于其位置,“lands”一词可能与“avion”(“飞机”)而不是“champ”(“田地”)更相关,即使“lands”可以出现在航空学(作为动词)和农业(作为名词)的词汇上下文中。

关于单词“land”的注意机制的例子,它与“avion”(“plane”)、“piste d ' atter rissage”(“landing runway”)的联系比与“champ”(“field”)的联系多。图片作者。
2017 年的论文注意力是你所需要的全部描述了我们所知道的最好的注意力机制,即使是对于长句,这要感谢一个叫做转换器的系统。
转换器是一种自动编码器,其中编码器和解码器具有以下层:
- 自我关注层:他们通过查看其他单词来帮助翻译每个单词,以便建立相关矩阵。
- 前馈层:它们生成一个代码,即自我关注层所获得结果的简化表示。
每一层都使用一系列的数学运算,计算量随着句子长度的增加而增加。
这里有一篇图文并茂的文章精确地解释了变形金刚是如何工作的。
这篇文章还包括一个实验室实验。
那么 Hsu 等人做了什么来加速翻译处理?
4。 神经机器翻译的高效推理概述
推理效率是如何改进翻译步骤以降低计算时间。
目标是在不影响翻译质量的情况下,在组件的推理级别优化翻译速度。
徐的团队有以下方法:
- 他们从一个基本的变压器架构开始,以优化每个主要组件,而无需处理因复杂性而导致的处理时间偏差。因此,他们避免使用具有原始架构的附加层。
- 他们使用最先进的解决方案来增强子组件,这看起来很简单,但实际上需要很好的理解,因为我们不能改变原始的翻译质量。
效率的评估得益于 双语评估替角 (BLEU)评分,该评分在专业水平上衡量翻译。
由于采用了新的架构,GPU 和 CPU 的速度分别提高了 84%和 109%,而 BLEU 得分仅下降了 2.1%。
以下是主要的改进:
- 使用最近的循环解决方案:更简单的简单循环单元(SSRU)和平均注意力网络(AAN)。
- 增强编码器/解码器的结构。
- 应用修剪注意头。

与神经机器翻译的有效推理相关的主要出版物概述。图片作者。
我们将深入探究主要的数学创新,并理解它们是如何工作的。
5。 使用近期经常性解决方案
有两项主要改进:
- 简单的简单循环单位
- 平均注意力网络
简单的简单循环单位
这项创新的灵感来自于 Kim 等人(2019)的一篇论文:从研究到生产再到生产:快得离谱的神经机器翻译。
翻译的神经网络可以比作在每个位置具有不同可能状态并依次相互连接的溪流。来源:@panapi/gfycat
变形金刚基础版的自我关注系统使用经典的乘法矩阵来执行上下文向量。它已被递归神经网络(RNNs)所取代,递归神经网络具有相同的线性复杂度,并在输出令牌数 n 的范围内将解码器复杂度从 O(n ) 降低到O(n)。这种改进是由于没有矩阵乘法,即使初始解决方案使用高度优化的矩阵乘法算法以及残差连接来改进深层计算。
基本上,rnn 是具有以下功能的神经网络:
- 记忆:在任何位置保存循环数据。
- 忘记:记下嘈杂的、罕见的或混乱的数据。
但是原始的 RNNs 需要相当多的计算,因为复杂的函数,例如涉及矩阵乘法的 tanh(参见长期短期记忆或 LSTM)。为什么?因为每一个 tanh 的计算都要感谢泰勒级数需要 O(n ) :

LSTM 单元中使用的双曲正切函数的泰勒级数(来源
然后,注意机制也具有矩阵乘法来计算查询 Q、键 K 和值 v 之间的关系

dk:k 的维度,使用根函数使 QK 的值变平,否则 QK 值之间的可变性太高。
Softmax 函数:它将绝对值转换为相对值,以便能够轻松地进行比较。
原 LSTM 中的双曲正切函数已被整流线性单元(ReLUs) 所取代,它是 O(n) 但需要多几层才能达到类似的结果。事实上,几个 ReLUs 单元模拟了具有更好的灵活性以适应目标的矩阵行为。
为了对它们如何工作有一个粗略的想法,这里有一个例子来说明为什么 tanh 函数比 ReLU 需要更少的神经元。在一个经典的回归问题中,你可以使用 Tensorflow Playground 来玩神经网络。你只需要在使用 tanh 和 ReLU 函数时比较结果。Tanh 将需要大约一半的 ReLU 神经元来达到相同的结果。我得到了同样的结果:
- 3 个 tanh 神经元的 1 个隐藏层。
- 2 个隐藏层,每层 3 个 ReLU 神经元。
简单递归单元(SRU) 通过用原始 LSTM 中的 ReLU 激活函数代替 tanh,在计算效率方面向前迈进了一大步。
SRU 也有一个“高速公路”网络。它用于简化深度网络的训练,使用重置门更快地传播到前一层。
超级简易循环机组(SSRU) 是简易循环机组(SRU)的一个较轻型版本,但没有高速公路网。
它具有以下结构:

SSRU 细胞。图片作者。

SSRU 细胞公式。图片作者。
每个 SSRU 单元首先基于遗忘门 f :其输入函数 x ,其权重 W 及其偏置 b 。
在 f 的极限处会发生什么?
如果 Wx+b~0 ,那么 f~0 和单元格状态 c ~Wx 。这是一个完整的记忆过程。
如果 Wx+b~1 ,那么 f~1 和单元格状态 c(t) ~ c(t-1) 。这是一个完全遗忘的过程,因为它采用与前一个单元状态相同的值。例如,当存在空值序列时,可能会发生这种情况。

RNN 输入像元通常基于数据集中最长短语的范围构建。较短的短语有空单元格。图片作者。
在这两个限制之外,有各种各样的配置来记忆输入中任何短语的序列。
权重在学习过程中逐步转换,以检测不同步骤之间的相关性。
平均注意力网络
平均注意力网络 (AAN)计算累积平均运算,为每个输入嵌入生成上下文敏感的表示。
原始转换器是自回归的(AT ),这意味着它根据以前的值进行计算。AT 很能代表一种语言顺序,但它需要很多时间,总的来说对于长句来说,因为每一个新单词的概率都是从所有以前的单词中计算出来的。
AAN 通过计算句子中所有单词的平均概率值来解决这个问题。
这背后的数理逻辑,来自于时间序列:自回归和移动平均常用于预测题目。

自回归与移动平均的例子。每一步都执行所有这些计算。图片作者。
自回归递归地使用所有之前的步骤(即单词)并执行回归,由于最小二乘近似,这需要比移动平均更多的计算,但由于其线性行为,结果更好。
移动平均是通过前面步骤的简单平均,但由于自动校正 AAN 权重的训练,最终会达到与自回归过程非常相似的结果。
下图是基于这个移动平均原理的计算加速度。

AAN 计算计算加速度相比,原来的变压器从纸上注意是你所需要的。图片作者。
机器神经翻译的有效推理也移除了 AAN 门控层。用于提高输出表现力的门控层:这个功能没有用,因为它已经被解码器执行了。
7.增强型编码器/解码器结构
深度编码器/浅层解码器网络架构由 12 个编码器和 1 个编码器层组成,而不是 50/50 的层分布。
编码器更快因为输入计算很容易并行。
然而解码器层有更多的计算,因为解码器是自回归的:它解码 N 次(N 是字数),与仅编码一次的编码器相反 *** 。

8.应用修剪注意头
在翻译模型架构中,许多组件(=heads)具有非常相似的行为,可以在不影响最终结果的情况下进行删减。
修剪注意力头方法仅仅使用 L0 范数正则化压缩和稀疏化深度神经网络以获得整体性能。
范数是向量之间的距离,即神经网络的权重。L0 是 0 范数,它是用非零值表示的距离。例如,向量(0,3,0,0,1)和(0,5,0,0,1)的 L0 范数为 2,因为有 2 个非零元素。
在这种情况下,正则化在于尽可能减少 L0 范数,以便去除零加权神经元并稀疏化神经网络。
这种方法也减少了过度拟合,因为较少的记忆导致更好的泛化。
9.BLEU 评估的限制
BLEU 评估有一些应该考虑的明确限制 。即使从 BLEU 的角度来看,有效推理有很大的效果,但对于像 medicin 这样可能包含不同语言结构的特定词汇领域,它可能是不同的。
结论
自从 1954 年 IBM 的乔治敦实验以来,已经做了许多改进来将语言规则转换成概率规则。
由于神经机器翻译的有效推理,Hsu 等人已经加速了最佳翻译体系结构,应用了来自几个团队的几个证明的解决方案。
通过用较轻的功能取代较重的功能,通过改进 autoencoder 的分层结构,所有这些都在时间序列、网络架构和概率解决方案的和谐融合中实现了非常好的结果。
这不是一项容易的任务,因为算法之间可能存在依赖关系,并不总是适合在一起,但我们应该小心地在新的情况下应用这些创新,因为 BLEU 评估有一些明确的限制。
*非常感谢徐一德的反馈,他的反馈提高了基本的理解。
来源:
神经机器翻译的高效推理:https://arxiv.org/pdf/2010.02416.pdf
乔治城-IBM 实验:http://www.hutchinsweb.me.uk/AMTA-2004.pdf
从研究到生产再回来:快得离谱的神经机器翻译:https://www.aclweb.org/anthology/D19-5632.pdf
你所需要的只是关注:https://arxiv.org/pdf/1706.03762.pdf
高度并行递归的简单递归单元:https://arxiv.org/pdf/1709.02755.pdf
简单收款单位代码:https://github.com/asappresearch/sru
通过平均注意力网络加速神经变压器:【https://arxiv.org/pdf/1805.00631.pdf
玛丽安-NMT:【https://marian-nmt.github.io/】T4
自训练和预训练对于语音识别是互补的:https://arxiv.org/pdf/2010.11430.pdf
注意力和增强递归神经网络:https://distill.pub/2016/augmented-rnns/
深度编码器,浅层解码器:重新评估机器翻译中的速度-质量权衡:https://arxiv.org/pdf/2006.10369.pdf
确定性非自回归神经序列迭代求精建模:https://arxiv.org/pdf/1802.06901.pdf
分析多头自我关注:专门的头做繁重的工作,其余的可以修剪:https://www.aclweb.org/anthology/P19-1580.pdf







浙公网安备 33010602011771号