基于 Python 的图像隐写术
图片来源 UMassAherst 文章
理解 LSB 图像隐写术并使用 Python 实现!
今天,世界正在见证前所未有的数据爆炸。我们每天产生的数据量确实令人难以置信。福布斯文章**“我们每天创造多少数据?”**指出,以我们目前的速度,每天大约有 2.5 万亿字节的数据产生,但随着物联网(IoT)的增长,这一速度只会加快。仅在过去的两年里,世界上 90%的数据都是由。这个值得重读!
数据。本质上,现代计算世界围绕着这个词。但是它到底有什么吸引人的地方呢?在当今世界,企业已经开始意识到数据就是力量,因为它有可能预测客户趋势,增加销售额,并将组织推向新的高度。随着技术的快速发展和数据的不断创新,保护数据安全已成为我们的首要任务。随着每天成千上万的消息和数据在互联网上从一个地方传输到另一个地方,数据共享正在增加。数据的保护是发送者最关心的问题,我们以一种只有接收者能够理解的秘密方式加密我们的信息是非常重要的。
在本文中,我们将了解什么是最低有效位隐写术,以及我们如何使用 python 来实现它。
什么是隐写术?
隐写术是将秘密消息隐藏在较大消息中的过程,以这种方式,某人无法知道隐藏消息的存在或内容。隐写术的目的是保持双方之间的秘密通信。与隐藏秘密消息内容的加密术不同,隐写术隐藏了消息被传递的事实。虽然隐写术不同于密码学,但两者之间有许多相似之处,一些作者将隐写术归类为密码学的一种形式,因为隐藏通信是一种秘密消息。
使用隐写术优于密码学?
到目前为止,密码学在保护发送者和接收者之间的秘密方面一直有其最终的作用。然而,如今除了加密之外,越来越多地使用隐写技术来为隐藏的数据添加更多的保护层。与单独使用密码术相比,使用隐写术的优势在于,预期的秘密消息不会引起对其自身作为审查对象的注意。显而易见的加密信息,无论如何无法破解,都会引起人们的兴趣,而且在那些加密是非法的国家,这些信息本身可能会被定罪。[1]
隐写术的类型
隐写术工作已经在不同的传输介质上进行,如图像、视频、文本或音频。
作者图片
基本隐写模型
截图来自 Edureka 隐写术教程
如上图所示,原始图像文件(X)和需要隐藏的秘密消息(M)都被输入到隐写编码器中。隐写编码函数 f(X,M,K)通过使用最低有效位编码等技术将秘密消息嵌入到封面图像文件中。生成的隐写图像看起来与您的封面图像文件非常相似,没有明显的变化。这就完成了编码。为了恢复秘密信息,隐写对象被送入隐写解码器。[3]
本文将帮助您使用 Python 实现图像隐写术。它将帮助你编写一个 Python 代码,使用一种叫做最低有效位的技术来隐藏文本消息。
最低有效位隐写术
我们可以将数字图像描述为一组有限的数字值,称为像素。像素是图像中最小的单个元素,包含代表给定颜色在任何特定点的亮度的值。所以我们可以把一幅图像想象成一个包含固定数量的行和列的像素矩阵(或二维数组)。
最低有效位(LSB)是一种技术,其中每个像素的最后一位被修改并替换为秘密消息的数据位。
Edureka 隐写术教程的照片致谢
Edureka 的照片隐写术教程
从上面的图像可以清楚地看出,如果我们改变 MSB,它将对最终值产生较大的影响,但如果我们改变 LSB,对最终值的影响是最小的,因此我们使用最低有效位隐写术。
LSB 技术如何工作?
每个像素包含红、绿、蓝三个值,这些值的范围从 0 到 255 ,换句话说,它们是 8 位值。[4]让我们举一个例子来说明这种技术是如何工作的,假设您想要将消息“嗨”隐藏到一个具有以下像素值的 4x4 图像中:
[(225,12,99),(155,2,50),(99,51,15),(15,55,22),(155,61,87),(63,30,17),(1,55,19),(99,81,66),(219,77,91),(69,39,50),(18,200,33),(25,54,190)]
使用ASCII 表,我们可以将秘密消息转换成十进制值,然后转换成二进制值: **0110100 0110101。**现在,我们逐个迭代像素值,在将它们转换为二进制后,我们依次用该消息位替换每个最低有效位(例如,225 是 11100001,我们用第一个数据位(0)替换最后一位,右边的位(1)以此类推)。这只会将像素值修改+1 或-1,根本不会引起注意。执行 LSBS 后得到的像素值如下所示:
[(224,13,99),(154,3,50),(98,50,15),(15,54,23),(154,61,87),(63,30,17),(1,55,19),(99,81,66),(219,77,91),(69,39,50),(18,200,33),(25,54,190)]
使用 Python 隐藏图像中的文本
在本节中,我们可以找到使用 Python 代码的隐藏和显示过程的一步一步。打开一个谷歌协作笔记本并遵循以下步骤:
在开始编写代码之前,您可以使用左侧菜单栏中的上传选项上传您想要用于隐写术的图像(png)。
作者照片
第一步:导入所有需要的 python 库
**第二步:**定义一个将任意类型的数据转换为二进制的函数,我们会用这个在编解码阶段将秘密数据和像素值转换为二进制。
步骤 3: 写一个函数,通过改变 LSB 来隐藏秘密信息到图像中
步骤 4: 定义一个函数,从隐写图像中解码隐藏消息
步骤 5: 将输入的图像名称和秘密消息作为用户输入,并调用 hideData()对消息进行编码的函数
步骤 6: 创建一个函数,要求用户输入需要解码的图像名称,并调用 showData()函数返回解码后的消息。
**第七步:**主要功能()
输出/结果:
对邮件进行编码:
解码信息:
如果你对代码感兴趣,可以在 Github 上找到我的笔记本。
参考资料:
- https://towards data science . com/steganography-hiding-a-image-inside-another-77 ca 66 B2 ACB 1
- https://www.edureka.co/blog/steganography-tutorial
- https://www . Forbes . com/sites/Bernard marr/2018/05/21/how-mud-data-do-we-create-every-day-the-mind-blowing-stats-every one-should-read/# 191 d0b 0160 ba
- https://www . uk essays . com/essays/computer-science/steganography-uses-methods-tools-3250 . PHP
- https://www . thepythoncode . com/article/hide-secret-data-in-images-using-steganography-python
- https://www.youtube.com/watch?v=xepNoHgNj0w&t = 1922s
局部分类器的层次分类:你必须知道的调整和技巧
分级分类集成模型的最佳实践。
你有没有一个层次分类的任务,只是乞求一个机器学习模型?你是否已经决定选择一个局部分类器的集合,甚至决定了对于那个任务来说最好的局部分类器结构?你的键盘准备好了吗,手指准备好了吗?嗯,现在就一分钟。你可能想坐下来。
如果你读过我在之前关于等级分类的 帖子,你肯定已经了解了所有的基础知识。然而,有一些重要的最后细节你应该让自己熟悉。无论是如何选择你的训练样本和特征集,如何避免错误传播,还是处理分类不一致的方法 — 这是你在实现你的第一个现实生活中的层次模型之前想要阅读的一篇文章。
在我们开始之前
分层局部分类器的主题很长,理解下面描述的复杂性需要您熟悉:
如果不是这样,那就继续读下去吧。没事的。我们会等的。
在这篇文章中,正如我之前的一样,我将根据常见宠物的分类给出例子:
常见家养宠物的分类。我听说彩虹独角兽很难家养。
谈正事
你正在建立你自己的层次集合模型吗?您是否已经定义了您的数据分类法,挑选了您最喜欢的局部分类器结构,卷起袖子,准备好开始着手进行模型破解了吗?
你就快到了,冠军。但是在您打开数据科学引擎之前,还有几个要点需要您花时间考虑。
1.不一致性校正方法
“嗯……为什么我的模型输出坚持这个例子是一只暹罗犬?”
正如你已经知道的(如果你不知道,你为什么不继续点击这里,局部分类器集成模型可以吐出一些不一致的结果。
根据您的用例,您可能不希望您的测试集示例同时被标记为“Unicorn”和“French Bulldog”,也不希望父节点分类器说不而它的一个子节点投票赞成。不同层次的系综之间的不一致是我们非常希望避免的。那么,我们应该怎样做呢?
有几个方法——其中一些不必要地复杂。我将为您节省一些麻烦,并描述最简单和最直观的,考虑到手头的问题最有意义的:
第一种不一致的情况:不同层次的预测相互矛盾
(例如:“假”代表狗,“真”代表狮子狗)。
解决方案:类预测自顶向下的方法。 在测试阶段,您从分类树的顶部开始,并且每次向下一级,您只考虑作为预测类的后代的局部分类器。
有点太抽象了?让我们看几个例子,然后:
- 每父节点局部分类器(LCPN) :你有一只动物。它是什么物种,哦,如此强大的一级分类器?是一只狗?太好了。让我们只将这个特定的例子发送到“狗”本地分类器,然后——不需要咨询“猫”和“独角兽”的分类器。
- 每节点局部分类器(LCN) :又一个动物!万岁!让我们看看它是一只猫,一只狗,还是一只独角兽。猫分类器说“是”,狗分类器说“不是”,独角兽分类器说“是”?非常好。接下来,我们将只考虑不同品种的猫和独角兽的本地分类器。狗品种可以坐在这一个。(当然,这个例子只适用于多标签的情况。还有,你有没有想过独角兽猫长什么样?点击风险自担)。
第二个不一致的场景:一个标签问题的几个叶节点标签
(例如:一只彩虹-独角兽-法国-牛头犬)。
您正在使用 LCN ( 每个节点的本地分类器),但是您的问题是单标签问题?嗯,首先,我不知道你为什么要这样做——LCPN(每个父节点的本地分类器 ) 结构只是坐在那里,等待——但是如果你决定这样做,并且你在同一级别的多个本地分类器对同一个示例说“是”,这里是你要做的:选择可信度最高的那个。
是的,就这么简单。“独角兽”和“狗”都在争称号?向每个分类器询问一个置信度得分,并且只考虑更有把握的那个的答案。有点像现实生活,不是吗?
(该解决方案假设您也使用上述自顶向下的分类预测,只将示例发送到结果为肯定的父分类器的子分类器。如果不是,就应该)。
2.错误传播
“等等!误差传播呢?如果这些父节点分类器中的一个给出了假阳性,我们如何避免将错误向下传播?”
初级的,我亲爱的读者。我们用信任来阻挡。根据您的用例及其所需的确定性水平,确定一个阈值,如果预测的置信度得分没有达到阈值,则停止分类过程,并且不将该样本发送到该分类器的子节点。
不过,这种解决方案也是有代价的:最终的预测可能不太具体(例如,“猫”而不是“Sphynx 猫”),并且取决于您的具体问题和业务需求,您的最终用户可能对此不满意。
3.LCN 量词的正反例
“我正在构建一个每节点局部分类器的集成模型。每个二元分类器的训练集应该是什么样的?
当谈到 LCN(每个节点的本地分类器)方法时,如何训练本地分类器可能不是显而易见的,这些分类器都是二进制的。我们应该把什么样的例子作为正面的例子来喂它?哪些是负面的?
有几种不同的政策,每一种都有其合理性和独特之处。你很幸运,我费了很大劲才找到了对 LCN 来说最有意义的一个,因为其他的都有点难以理解,而且没有任何明显的好处。
它被称为“ 兄弟姐妹政策 ”,并且它将类 X 的正面例子定义为属于类 X 及其子类的那些,将负面例子定义为属于类 X 的兄弟姐妹类以及它们自己的子类的那些。
举例?当然:
说我想训练我的“狗”分类器。在这种情况下,我的正面例子将是那些既属于一般“狗”类(假设有一些例子,我知道它们是狗,但不知道是哪个品种),又属于它的所有特定品种(斑点狗、拉布拉多等)的狗。).
我的反面例子,另一方面,将会是所有的猫和所有的独角兽(我必须说,这听起来很棒)。
明白了吗?很好。让我们继续下一个调整。
4.相同与不同的特性/算法
“我应该对我的集成中的所有局部分类器使用相同的基础算法吗?同样的功能集怎么样?”
这个简单:不。
有大量证据表明,针对不同子问题的不同算法和特性可以提供更好的结果。这很有道理。你不会期望一个“它喵喵叫吗”的特性能很好的区分不同品种的狗,你会吗?
最后一个音符
如果你已经走了这么远,你已经准备好了。你有你的本地分类器结构吗?你的正反例子?不一致和错误传播问题都解决了?等等,你忘了什么吗?
一旦你建立了你的层次模型,你将会想要知道它做得有多好。虽然平面分类问题的性能指标是众所周知的——但当涉及到层次问题时,就不那么简单了。
所以,开始构建你的模型吧,但如果你也想测量它的性能,请查看我的下一篇文章。这将是一个爆炸。
Noa Weiss 是特拉维夫的一名人工智能机器学习顾问。
资料来源 : C.N. Silla & A.A. Freitas, 跨不同应用领域的层次分类综述 (2011),数据挖掘与知识发现,22(1–2):182–196
使用局部分类器的层次分类:掉进兔子洞
构建您的第一个层次分类模型?这篇文章是给你的。
分层数据无处不在。作为数据科学家,我们已经习惯于将其扁平化,忽略数据的自然分类,以便我们可以轻松地将其输入到我们的机器学习模型中。但是他们说,还有另一种方法。一个保存隐藏在层级中的珍贵信息的人。它可以帮助我们设计更加(人工)智能的分类模型,并更好地捕捉每个预测类别的独特性。
设计层次分类模型时,有一些标准方法。在这里,我们将集中讨论其中之一:建立一个由层次结构的局部分类器组成的集成模型。这种方法可以用不同的方式实现,每种方式都有自己的优点和缺点。在接下来的大约 1000 个单词中,我将介绍每个局部分类器结构的优缺点、它可能带来的独特挑战以及它最适合解决哪些问题。
换句话说,**这篇文章是关于你应该为你自己的层次分类项目选择哪种局部分类器结构的。**好奇?太好了。那我们就开始吧。
在我们开始之前
掌握层次分类器的来龙去脉,确实需要一些背景知识。我会尽我所能让这篇文章尽可能的简单易懂。然而,如果你发现自己在纠结数据分类学和层次分类的核心概念,你应该继续读下去——相信我,这是一本引人入胜的书。
在这篇文章中,我将根据常见宠物的分类给出一些例子:
常见家养宠物的分类。我一直想要一只独角鲸,但是我哥哥过敏。
本地分类器的不同结构(哪一个是最公平的)
哦,层次结构的局部分类器。这些聪明的集成模型建立了一个更小的分类器层次结构,从而以一种简单而迷人的方式抓住了层次分类的本质。如此迷人,我说的对吗?
如果你正在读这篇文章,你可能已经被它们不可否认的吸引力所吸引,这意味着你现在面临一个困难的问题:你应该选择哪种可用的结构?
别担心,你来对地方了。让我们来看看我们快乐的选择。
善意的提醒-三位选手是:
- 每个节点的局部分类器(LCN)
- 每个父节点的本地分类器(LCPN)
- 每级局部分类器(LCL)
每个节点的本地分类器(LCN)
这种情况下,每个节点都有一个二元分类器(例如:每个“猫”、“狗”、“独角兽”、“暹罗”、“波斯”等等都有一个单独的分类器;在我们家养宠物的例子中,我们总共有 13 个二元分类器。它也是文献中使用最多的一种,这使它成为真正的舞会佳丽。那么,你应该考虑哪些利弊呢?
优点:
- 这种方法就是天生的多标签。它通过传统的单标签算法实现了这一点,而没有设计和实现多标签算法的复杂性。(不过,你不必使用多个标签——在单标签问题的情况下,你可以简单地只分配可信度最高的标签——在我的下一篇文章中会详细介绍)。
缺点:
- 前后矛盾问题。如果“猫”的本地分类器投了反对票,而“波斯”的本地分类器投了赞成票,那该怎么办?如果“独角兽”和“法国斗牛犬”都是阳性呢?(假设独角牛头犬不幸不存在于我们的世界)。当使用 LCN 方法时,这些都是非常可能的结果。这不是一个无法解决的问题——事实上,我将在接下来的帖子中介绍一个简单的方法来避免它——但这是一个需要注意的问题,或者你应该准备好一些不一致的结果。
- 与其他局部分类器方法相比,LCN 要大得多,因为它需要更多的局部分类器。
每父节点本地分类器(LCPN)
这是其中每个父节点(例如,“狗”)得到一个多类分类器(例如:一个确定狗的品种)。
优点:
- 首先,这是一堆东西中最直观的一个,我相信这是有价值的。因为我们数据科学家不是在真空中工作,而且我们经常需要与同事或客户交流我们的工作,所以让我们的模型以一种其他人可以容易理解的方式构建是一个巨大的“地狱,是的”。
- 由于只有和父节点一样多的本地分类器,这种方法比前一种方法更加精简,更容易实现。
缺点:
- 还记得上次方法中的不一致性问题吗?嗯,这次也是这样。但是,同样,解决方案相当简单(将在我的下一篇文章中解决,非常非常快——我不会让你坐太久)。
每层本地分类器(LCL)
这是一个为分类法的每一层都有一个多类分类器的例子。在我们的例子中,这意味着一个分类器区分猫、狗和独角兽,另一个分类器区分所有的叶节点类:特定的狗、猫和独角兽品种。
这种方法在文献中是最少使用的。此外,它主要用作基线比较方法。让我们看看为什么:
优点:
- 这是一台 lean ,意思是分类机。嗯,很瘦。这么瘦。很少分类器。更少的代码行。
缺点:
- 还记得那个不一致的问题吗?这个问题不再那么容易解决了。没有什么可以阻止您在第一个分类器中使用“Cat ”,然后在第二个分类器中使用“Pegasus”。对此没有什么可做的——至少没有真正深入到野兽的肚子里。
- 在分类法的深层,分类器可能有太多的类别可供选择。例如,如果在我们的例子中有更多的物种,第二个分类器可能必须在 3 个猫品种、4 个狗品种、3 只神奇的独角兽、几只沙鼠、几只雪貂和两种小马中进行区分。有点过了,你不觉得吗?
- 这种方法完全忽略了训练中的亲子关系,嗯,这很愚蠢。这些关系可能包含非常有价值的信息——这不正是我们最初进入层级结构的全部原因吗?
开门见山,好吗?我应该使用哪种结构?
我承认,我一开始就有偏见。LCL 从来都不是我最喜欢的,我也怀疑过 LCN。但是最后一个通过了——如果你有一个多标签的问题,它是自然的选择。它可能有点笨重,但它弥补了它给多种标签的优雅轻松(从没想过你会有一只波斯猫也是一只狮子狗,你有吗?).
如果这是一个单一标签的问题,我会选择 LCPN 方法。它很直观,不太笨重,它做它需要做的事情。它的不一致性问题也很容易解决——而且这个解决方案也非常直观。
就这样了,伙计们
如果您已经做到了这一步,那么您应该已经知道哪种局部分类器结构最适合您的项目。
尽管如此,仍然有一些问题需要解决:如何处理不一致和错误传播,你应该如何定义你的正面和负面训练示例,甚至如何尝试测量这样一个结构奇怪的模型。这些都将在我的下一篇帖子中得到解答——敬请期待。
一如既往,我欢迎问题、反馈和特殊要求——请在评论区分享。如果你喜欢你在这里学到的东西,那就把这种快乐付诸实践吧:你的第一个层次分类模型正等着你呢。
诺亚·维斯是一名人工智能&机器学习顾问,总部位于特拉维夫。
资料来源 : C.N. Silla & A.A. Freitas, 跨不同应用领域的层次分类综述 (2011),数据挖掘与知识发现,22(1–2):182–196
等级聚类:凝聚和分裂——解释
聚集和分裂聚类算法及其实现综述
卢卡斯·布拉塞克在 Unsplash 上的照片
层次聚类是一种聚类分析方法,用于将相似的数据点聚类在一起。分层聚类遵循自顶向下或自底向上的聚类方法。
什么是集群?
聚类是一种无监督的机器学习技术,它将群体分成几个聚类,使得同一聚类中的数据点更相似,而不同聚类中的数据点不相似。
- 同一簇中的点彼此更接近。
- 不同簇中的点相距很远。
(图片由作者提供),样本二维数据集
在上面的二维数据集样本中,可以看到数据集形成了 3 个相距很远的聚类,并且同一聚类中的点彼此靠近。
除了层次聚类之外,还有几种聚类算法,如 k-Means 聚类、DBSCAN 等。阅读下面的文章,了解什么是 k-means 聚类以及如何实现它。
[## 了解 K-means、K-means++和 K-medoids 聚类算法
了解 K-means、K-means++和 K-Medoids 聚类算法及其关系的概述。这篇文章…
towardsdatascience.com](/understanding-k-means-k-means-and-k-medoids-clustering-algorithms-ad9c9fbf47ca)
在本文中,您可以了解层次集群及其类型。
有两种类型的层次聚类方法:
- 分裂聚类
- 凝聚聚类
分裂聚类:
分裂聚类算法是一种自上而下的聚类方法,最初,数据集中的所有点都属于一个聚类,并且当一个聚类在层次结构中向下移动时,会递归地执行分裂。
分裂聚类的步骤:
- 最初,数据集中的所有点都属于一个单独的聚类。
- 将集群划分为两个最不相似的集群
- 递归地进行以形成新的聚类,直到获得期望数量的聚类。
(图片作者),**第一张图片:**所有的数据点都属于一个聚类,第二张图片: 1 个聚类从前一个单个聚类中分离出来,**第三张图片:**再有 1 个聚类从前一组聚类中分离出来。
在上面的样本数据集中,观察到有 3 个彼此相距很远的聚类。所以我们在得到 3 个集群后就停止了。
即使开始进一步分离更多的簇,下面是获得的结果。
(图片由作者提供),样本数据集分为 4 个聚类
如何选择拆分哪个集群?
检查每个分类的误差平方和,并选择具有最大值的分类。在下面的二维数据集中,当前,数据点被分成 2 个聚类,为了进一步将其分成第 3 个聚类,找出红色聚类和蓝色聚类中每个点的误差平方和(SSE)。
(图片由作者提供),样本数据集分为 2 个聚类
具有最大 SSE 值的聚类被分成 2 个聚类,从而形成新的聚类。在上面的图像中,可以观察到红色星团有较大的 SSE,因此它被分成两个星团,总共形成三个星团。
如何拆分上面选择的集群?
一旦我们决定了分割哪个集群,那么问题就出现了,如何将选择的集群分割成两个集群。一种方法是使用沃德标准来追踪作为分割结果的 SSE 标准差异的最大减少。
如何处理噪音或异常值?
由于离群值或噪声的存在,可能导致形成其自己的新聚类。为了处理数据集中的噪声,使用阈值来确定终止标准,这意味着不生成太小的聚类。
凝聚聚类:
凝聚聚类是一种自下而上的方法,最初,每个数据点都是自己的一个聚类,随着层次结构的向上移动,更多的聚类对被合并。
聚集聚类的步骤:
- 最初,所有的数据点都是它自己的一个集群。
- 取两个最近的集群,将它们连接起来形成一个集群。
- 递归地进行第 2 步,直到获得所需的聚类数。
(图片由作者提供),**第一张图:**所有的数据点都是它自己的一个聚类,**第二张图:**两个最近的聚类(被一个黑色椭圆包围)结合在一起形成一个单独的聚类。
在上面的样本数据集中,观察到两个集群彼此相距甚远。所以我们在得到 2 个集群后就停止了。
(图片由作者提供),样本数据集分为两个聚类
如何将两个集群连接成一个集群?
为了获得期望数量的聚类,聚类的数量需要从最初的 n 个聚类减少(n 等于数据点的总数)。通过计算两个聚类之间的相似性来组合它们。
有一些方法用于计算两个聚类之间的相似性:
- 两个聚类中最近的两个点之间的距离。
- 两个集群中两个最远点之间的距离。
- 两个聚类中所有点之间的平均距离。
- 两个簇的质心之间的距离。
选择上述任何一种相似性度量标准都有一些优点和缺点。
实施:
(作者代码)
结论:
在本文中,我们讨论了凝聚和分裂层次聚类算法的深入直觉。分层算法的缺点是空间和时间复杂度大,不适用于大数据集。
感谢您的阅读
等级聚类:在世界货币中的应用
Geronimo Giqueaux 在 Unsplash 上的照片
亚洲货币的走势一致吗?新兴市场总体情况如何?像澳元和加元这样的商品货币也有密切的关系吗?或者还有其他我们不知道的更近的关系吗?
层次聚类是一种技术,用于沉淀变量宇宙中的统计关系。它要么采用自上而下的分裂方法,要么采用自下而上的聚合方法。在这个分析中,我使用了凝聚层次聚类技术来挑战和验证广泛使用的货币分组/配对,这是资产经理和交易者所熟悉的。
凝聚层次聚类
来源:维基百科。凝聚层次聚类算法的图形表示
好了,这里有一个关于凝聚层次聚类算法的快速注释。该算法首先将所有变量标记为单独的聚类。然后,它继续识别最接近的聚类以形成更大的聚类,并且结果聚类被类似地视为初始聚类。这种情况重复发生,直到形成一个包含所有变量的最终聚类。
所以在某种程度上,集群形成的顺序告诉你它们之间的接近程度。因此,产生的结构,称为树状图,在使用的变量之间有一个紧密的层次结构。
去噪相关矩阵
为了帮助我们研究相互依赖结构,我使用了 45 种货币和贵金属衍生的相关矩阵。
然而,众所周知,金融数据噪声特别大,这种噪声往往会馈入估计的相关矩阵。为了锐化我们想要的信号,需要降低噪声水平。所使用的技术改编自马科斯·洛佩兹·德·普拉多(Marcos Lopez de Prado)的《面向资产管理者的机器学习》。
首先,我们通过 PCA(主成分分析)将相关矩阵分解成其特征值和特征向量。然后使用第一个 n 个主分量重构去噪的相关矩阵,其中 n 通过最小化特征值的理论 Marcenko-Pastur 概率密度函数和经验导出的概率密度函数之间的误差平方和来确定。
原始相关矩阵(左)和去噪相关矩阵(右)
去噪后,我们可以继续进行分析,并将分层聚类应用于得到的相关矩阵。
结果
首先,让我们看看这些货币在过去十年(2010 年 1 月至 2019 年 12 月)的树状图。
10 年期的货币树状图
从最左边的聚类中,我们看到该算法将贵金属(铂、银、金和钯)分组在一起。除此之外,我们还有 NZD/AUD(新西兰元和澳大利亚元)和 EUR/GBP(欧洲元和英镑)的组合。
在中间,我们看到了另一个聚类,其中所有的新兴亚洲货币都被分组在一起。MYR 与韩国最接近,那么 MYR 与韩国的聚类与 TWD、菲律宾、印度尼西亚、泰国、印度卢比、CNY 和 HKD 相似。几乎所有的亚洲新兴市场货币都属于这一类,除了新加坡元(SGD ),有趣的是,该算法认为新加坡元与以色列谢克尔(ILS)最为相似。
其他新兴市场货币,如 ZAR、特里、MXN 和 BRL,也与铜、CLP、RUB 和 PEN 聚集在一起。
这些结果(大部分)并不令人意外,也验证了长期以来的观点,即某些货币会一起交易,就像新兴市场亚洲集团一样。
通过层次聚类分析确定的两组不同货币的聚类相关矩阵
然而,当我们审视今年发生的事情时,这个故事发生了转折。使用从 2020 年 1 月 1 日到 2020 年 5 月 15 日的 YTD(年初至今)数据,我们应用相同的技术,得出另一个树状图。
本年迄今货币树状图
在上面的树状图中,我们看到了货币分组的一点变动。在深入研究之前,我们首先注意到,新西兰元/澳元、欧元/英镑和贵金属之间的关系是稳定的,并保留在这个新的数据集中。
接下来,如果我们看看中间,新兴市场亚洲集团现在只有 6 个成员,CNY,新加坡,HKD 和 PHP 被排除在外。最令人惊讶的结果是,菲律宾比索现在与沙特里亚尔最为相似,交易方式类似于中东货币群(沙特里亚尔、伊尔斯、科威特第纳尔、OMR、BHD)。
此外,另一点需要注意的是,日元现在与瑞士法郎聚集在一起,这或许表明了这两种货币在全球疫情和衰退中的避险资产地位。
YTD 货币回报的聚类相关矩阵
在 YTD 聚类相关矩阵中,我们现在看到三个不同的聚类。第一个属于贵金属,新西兰元/澳元,欧元/英镑。第二组仅包含日元、瑞士法郎和 DKK,最后一组包含其余货币。
结论然而,从年初至今的数据来看,这些关系可能会破裂,尤其是在新冠肺炎疫情爆发这样的特殊时期。使用数据挖掘技术使我们能够超越偏见,客观地看待市场。
分层聚类—已解释
理论解释和科学学习范例
聚类算法是无监督的机器学习算法,因此没有与数据点相关联的标签。聚类算法寻找数据点之间的相似性或不相似性,以便可以将相似的数据点分组在一起。有许多不同的方法和算法来执行集群任务。在这篇文章中,我将介绍一种常见的方法,即层次聚类。
聚类简单地说就是将相似的事物组合在一起。然而,这并不像听起来那么简单。与聚类相关的挑战之一是,我们几乎总是不知道数据集内的聚类(或组)数量。
分层聚类的优点之一是我们不必指定聚类的数量(但是我们可以)。简短的介绍之后,让我们深入细节。
分层聚类意味着通过迭代分组或分离数据点来创建聚类树。有两种类型的分层聚类:
- 凝聚聚类
- 分裂聚类
凝聚聚类
聚集聚类是一种自下而上的方法。每个数据点首先被假定为一个单独的聚类。然后迭代地组合相似的聚类。让我们看一个例子来解释清楚这个概念。
我们有一个由 9 个样本组成的数据集。我选择与这些样本相关的数字来演示相似性的概念。在每次迭代(或级别)中,最接近的数字(即样本)被组合在一起。如下图所示,我们从 9 个集群开始。最接近的在第一级被组合,然后我们有 7 个集群。与蓝线相交的黑线的数量代表簇的数量。
系统树图
上图称为树状图,这是一个表示基于树的方法的图表。在层次聚类中,树状图用于可视化聚类之间的关系。
随着我们往上走,随着更多样本的合并,聚类的数量会减少。在级别 6 之后,所有样本被合并到一个大的聚类下。
这是一个非常简单的数据集来说明目的,但现实生活中的数据集显然更复杂。我们提到“最近的数据点(或聚类)”被组合在一起。但是算法如何识别最接近的呢?在 scikit-learn 中实现了 4 种不同的方法来测量相似性:
- 沃德连锁:最小化被合并的聚类的方差。目标是簇形心周围的总方差增加最少。
- **平均连锁:**两个聚类中每个数据点的平均距离。
- **完全(最大)连锁:**两个聚类中所有数据点之间的最大距离。
- **单一(最小)连锁:**两个聚类中所有数据点之间的最大距离。
默认选择是 ward’s linkage,它适用于大多数数据集。
完整(最大)和单一(最小)联动
层次聚类的优点之一是我们不必预先指定聚类的数量。但是,将所有数据点合并到一个聚类中是不明智的。我们应该在某个时候停止组合集群。Scikit-learn 为此提供了两个选项:
- 达到一定数量的簇后停止( n_clusters )
- 设置联动阈值(距离 _ 阈值)。如果两个聚类之间的距离超过阈值,这些聚类将不会被合并。
分裂聚类
分裂聚类在现实生活中并不常用,所以我将简单地提到它。简单而清晰的解释是分裂聚类是凝聚聚类的反义词。我们从一个包含所有数据点的巨大集群开始。然后数据点被分成不同的簇。这是一种自上而下的方法。
利弊
我将尝试解释层次聚类的优点和缺点,以及与 k-means 聚类(另一种广泛使用的聚类技术)的比较。
赞成者
- 不需要预先指定集群的数量。必须为 k-means 算法指定聚类数。
- 借助于树状图,它很容易实现和解释。
- 总是生成相同的聚类。k-均值聚类可能会产生不同的聚类,这取决于质心(聚类的中心)是如何初始化的。
缺点
- 与 k-means 相比,这是一种较慢的算法。分层聚类需要很长时间来运行,尤其是对于大型数据集。
层次聚类应用
如果基础数据具有某种层次结构,分层聚类是有用的,并且会给出更好的结果。
分层聚类的一些常见用例:
- 遗传或其他生物数据可以用来创建一个树状图,以代表突变或进化水平。种系发生树用于显示基于相似性和差异性的进化关系。如维基百科所述:
一个进化树或进化树是一个分支图或树,显示了各种生物物种或其他实体之间的进化关系,基于它们的物理或遗传特征的相似性和差异性。
这些树也被用来区分不同类型的病毒。
- 层次聚类也用于对文本文档进行分组。然而,由于数据的高维性,这是一项非常复杂的任务。
- 层次聚类的另一个常见用例是社交网络分析。
- 分层聚类也用于异常值检测。
Scikit 学实现
我将使用在 scikit learn 的数据集模块下可用的 iris 数据集。让我们从导入数据集开始:
import pandas as pd
import numpy as np
from sklearn.datasets import load_irisiris = load_iris()
X = iris.data
虹膜数据集包括 150 个数据点。我将只使用前 50 个数据点,以便树状图看起来更清楚。
X = X[:50, :]X.shape
(50, 4)
然后引入凝聚聚类类,建立模型。
from sklearn.cluster import AgglomerativeClusteringmodel = AgglomerativeClustering(distance_threshold=0, n_clusters=None)
请记住,如果 distance_threshold 参数不为 None,则 n_cluster 参数必须为 None。我不设置任何条件,只是为了可视化一个完整的树。
下一步是使模型符合数据:
model = model.fit(X)
在绘制树状图之前,我们可以使用可用的方法检查模型的细节:
# Number of clusters
model.n_clusters_
50# Distances between clusters
distances = model.distances_distances.min()
0.09999999999999964distances.max()
3.828052620290243
Scikit learn 不提供树状图,所以我们将使用 SciPy 包中的树状图。
from scipy.cluster.hierarchy import dendrogram
from scipy.cluster import hierarchy
我们首先创建一个关联矩阵:
Z = hierarchy.linkage(model.children_, 'ward')
我们使用模型中的孩子和一个链接标准,我选择它作为“病房”链接。
plt.figure(figsize=(20,10))dn = hierarchy.dendrogram(Z)
叶子的标签是数据点的索引。
我们可以通过调整距离 _ 阈值或n _ 集群参数来控制集群的数量。让我们检查计算出的集群之间的距离:
model.distances_
array([0.1 , 0.1 , 0.1 , 0.1 , 0.14142136, 0.14142136, 0.14142136, 0.14142136, 0.14142136, 0.14142136, 0.14142136, 0.17320508, 0.17320508, 0.18257419, 0.2 , 0.2081666 , 0.21602469, 0.21602469, 0.25819889, 0.27568098, 0.28284271, 0.29439203, 0.29439203, 0.31358146, 0.31464265, 0.31622777, 0.33166248, 0.33665016, 0.34641016, 0.36968455, 0.40620192, 0.42229532, 0.43969687, 0.43969687, 0.46726153, 0.54772256, 0.59441848, 0.6244998 , 0.6363961 , 0.66269651, 0.77628542, 0.81873887, 0.85556999, 0.90998199, 1.10513951, 1.25399362, 1.37126983, 1.91875287, 3.82805262])
距离按升序排列。如果我们可以将 distance _ thresold 设置为 0.8,则聚类数将为 9。有 8 个距离大于 0.8,因此,当组合时,将形成 9 个集群。
model = AgglomerativeClustering(distance_threshold=0.8, n_clusters=None)model = model.fit(X)model.n_clusters_
9
感谢您的阅读。如果您有任何反馈,请告诉我。
参考文献
- https://NLP . Stanford . edu/IR-book/html/html edition/hierarchical-agglomerate-clustering-1 . html
- https://en.wikipedia.org/wiki/Phylogenetic_tree
Python 中使用树状图和共生相关的层次聚类
将集群组织为分层树
Pierre Bamin 在 Unsplash 上拍摄的照片
介绍
在本文中,我们将研究 K 均值聚类的另一种方法,通常称为层次聚类。分层聚类技术不同于 K 均值或 K 模式,其中聚类机制如何工作的底层算法是不同的。k 均值依赖于质心和欧氏距离的组合来形成聚类,另一方面,层次聚类使用凝聚或分裂技术来执行聚类。层次聚类允许使用树状图来可视化聚类,树状图有助于通过有意义的分类法更好地解释结果。创建一个树状图不需要我们预先指定聚类的数量。
像 R、Python 和 SAS 这样的编程语言允许层次聚类处理分类数据,使得带有分类变量的问题语句更容易处理。
层次聚类中的重要术语
链接方法
假设在聚类(a)中有(a)原始观测值 a[0],…,a[| a | 1],在聚类(b)中有(b)原始对象 b[0],…,b[| b | 1],那么为了组合这些聚类,我们需要计算两个聚类(a)和(b)之间的距离。假设有一个点(d)还没有被分配给任何一个聚类,我们需要计算聚类(a)到(d)以及聚类(b)到(d)之间的距离。
现在,聚类中通常有多个点,需要不同的方法来计算距离矩阵。链接决定了如何计算聚类之间的距离,即点到聚类的距离。常用的连接机制概述如下:
- 单一关联-计算每对聚类中最相似成员之间的距离,然后根据最短距离合并聚类
- 平均关联-计算一个聚类的所有成员与不同聚类中所有其他成员之间的距离。然后利用这些距离的平均值来决定哪些聚类将合并
- 完全链接-计算每对聚类中最不相似成员之间的距离,然后根据最短距离合并聚类
- 中间联系—类似于平均联系,但我们使用中间距离,而不是使用平均距离
- Ward Linkage 使用方差分析方法来确定聚类之间的距离
- 质心连接-通过取分配给聚类的所有点的平均值来计算每个聚类的质心,然后使用该质心来计算到其他聚类的距离
这些距离计算公式如下图 1 所示。
图一。上述连杆机构的距离公式。图像信用——由作者开发
距离计算
两个或多个聚类之间的距离可以使用多种方法来计算,最常用的是欧几里德距离。然而,其他距离度量,如闵可夫斯基、城市街区、汉明、雅克卡、切比雪夫等。也可以与分层聚类一起使用。下面的图 2 概述了不同的距离度量如何影响层次聚类。
图二。距离计算和链接对集群形成的影响。图片来源:图片来源——GIF via gfy cat。
系统树图
树状图用于表示特征空间中对象之间的关系。它用于显示特征空间中每对顺序合并的对象之间的距离。在决定适合数据集的聚类数量之前,系统树图通常用于研究等级聚类。两个聚类组合的距离称为树状图距离。树状图距离是两个或更多个聚类是不相交的还是可以组合在一起形成一个聚类的度量。
图 3。使用中位数作为连锁类型的层次聚类。图片来源——由作者使用 Jupyter 笔记本开发
图 4。使用平均值作为链接类型的层次聚类的树状图。图片来源——由作者使用 Jupyter 笔记本开发
图 5。使用 Complete 作为链接类型的层次聚类的树状图。图片来源——由作者使用 Jupyter 笔记本开发
共生系数
上面的图 3、图 4 和图 5 表明了链接的选择如何影响集群的形成。直观地查看每一个树状图来确定哪个聚类链接工作得最好是具有挑战性的,并且需要大量的人工工作。为了克服这一点,我们引入了同伦系数的概念。
假设有两个群集,a 和 b,点 A₁、A₂和 A₃在群集 a 中,点 B₁、B₂和 B₃在群集 b 中。现在,要使这两个群集分开,点 A₁、A₂和 a 以及点 b、b 和 b 也应该彼此远离。Cophenet 指数是特征空间中的点的距离和树状图上的距离之间的相关性的度量。它通常采用数据中所有可能的点对,并计算点之间的欧几里德距离。(保持不变,与我们选择的链接算法无关)。然后,它计算聚类 A & B 组合的树状图距离。如果这些点之间的距离随着聚类之间的树状图距离而增加,则 Cophenet 指数更接近 1。
图 6。层次聚类中不同链接方法的 Cophenet 指数。图片来源——由作者使用 Jupyter 笔记本开发
决定聚类的数量
不像 K 均值算法使用肘形图来确定聚类数,在分层聚类中没有统计技术来确定聚类数。然而,一种常见的方法是分析树状图,并寻找在更高的树状图距离上组合的组。让我们看看下面的例子。
图 7。平均连锁法的系统聚类树状图。图片来源——由作者使用 Jupyter 笔记本开发
图 7 说明了当树在树状图距离为 3 处被切割时,存在 5 个聚类。总的想法是,所有 5 组聚类在一个高得多的树状图距离上组合,因此可以作为单独的组进行分析。我们也可以使用轮廓指数分数来验证这一点。
结论
在任何聚类工作中,决定聚类的数量都是一项单调乏味的任务。由于商业方面的业务更侧重于从这些组中获得一些意义,因此在二维空间中可视化集群并检查它们是否彼此不同是很重要的。这可以通过 PCA 或因子分析来实现。这是一种广泛使用的机制,用于向不同的利益相关者呈现最终结果,使每个人都更容易消费输出。
图 8。使用两种不同链接技术的层次聚类的聚类图。图片来源——由作者使用 Jupyter 笔记本开发
关于作者:高级分析专家和管理顾问,帮助公司通过对组织数据的商业、技术和数学的组合找到各种问题的解决方案。一个数据科学爱好者,在这里分享、学习、贡献;你可以和我在 上联系 和 上推特;
分层性能指标以及在哪里可以找到它们
如何衡量你的层次分类模型的性能?
考尔德 B 在 Unsplash 上拍摄的照片
分层机器学习模型是一个顶级技巧。正如在 之前的 帖子中所讨论的,在设计我们的模型时考虑数据的自然分类是非常值得的。我们能够使用它们,使我们的模型更智能、更准确,而不是变平并忽略那些内部层次。
“更准确”,我说——然而,他们是吗?我们怎么知道?毕竟,我们是从事科学的人,我们期望大胆的主张能得到数据的支持。这就是为什么我们有性能指标。无论是精确度、f1 分数,还是我们关注的任何其他可爱的指标——如果在我们的模型中使用层次提高了它们的性能,指标应该显示出来。
问题是,如果我们使用常规的性能指标(为平面、一级分类设计的指标),我们又会忽略数据的自然分类。
如果我们做等级制度,那就一路做下去。如果我们决定庆祝我们的数据的分类,并按照它的形象构建我们的模型,这也需要成为衡量其性能的一部分。
我们如何做到这一点?答案就在下面。
在我们开始之前
这篇文章是关于测量为分层分类设计的机器学习模型的性能。它假设你知道所有这些单词的意思。如果没有,查看一下我的 之前的 帖子上的话题。尤其是介绍主题的那个。真的。在学习如何测量之前,你会想知道什么是等级分类。这是一个很明显的问题。
在这篇文章中,我将根据常见宠物的分类给出一些例子:
常见家养宠物的分类。我的邻居刚刚收养了最可爱的小飞马。
哦,这么多指标
因此,我们已经有了一整套层次结构的局部分类器,随时准备执行我们的命令。我们如何评价他们?
这不是一个微不足道的问题,解决办法也不明显。正如我们在本系列前面的问题中看到的,不同的项目需要不同的处理方式。最佳指标可能会有所不同,这取决于项目的具体要求和限制。
总而言之,主要有三种选择。让我们介绍他们,好吗?
参赛者们,带着他们所有的优雅和荣耀:
实际的一个:平面分类度量
这些都是我们都知道并喜爱的分类指标(精确度、召回率、f 值——你能想到的),应用起来…嗯,很简单。
与最初的“扁平分类”方法相同(在本系列的第一篇文章中有所描述),这种方法完全忽略了层级。只考虑最终的叶节点预测(在我们的家养宠物例子中,这些是特定的品种),它们都被认为是平等的类,没有对兄弟类和非兄弟类的任何特殊处理。
这种方法很简单,但显然不理想。我们不希望不同等级的错误以同样的方式受到惩罚(如果我把飞马误认为独角鲸,那还不如误认为拉布拉多来得糟糕)。此外,没有一种明显的方法来处理最终预测不是叶节点预测的情况——如果您实现了前面提到的 置信阻塞 方法,这种情况肯定会发生。
潮人一号:定制尺码
不满意平坦的指标,并感觉到指尖有创意的火花?您可以想象出您自己的特殊度量,它特别适合您独特的用例雪花。
当模型需要适应一些不寻常的业务约束时,这可能是有用的。例如,如果你真的不在乎错误地将狗识别为独角兽,但 Sphynx 猫必须被正确地发现或完全失控,你可以相应地设计你的度量标准,给不同的错误或多或少的权重。
自命不凡的一个:常规分类指标的特定于层次的变体
这些都是众所周知的精度,召回和 f 分数指标的变化,特别是适应分层分类。
请原谅我在你的大致方向上抛出一些数学符号:
分别定义了层次精度(hP)、层次召回率(hR)和层次 f-measure (hF)。
然而,这一切意味着什么呢?
Pi 是由每个测试实例 I 的预测的最具体的类(或多个类,在多标签问题的情况下)及其所有祖先类组成的集合; Ti 是由测试例 I 的真最特定类及其所有祖先类组成的集合;当然,每个总和是在所有测试集示例上计算的**。**
这一个有点难解开,所以如果你发现自己困惑,检查一下附录,在那里我会更详细地解释。
现在,如果您已经用非强制叶节点预测实现了您的模型(意味着预测的最具体级别不一定是最深的级别),那么需要进行一些调整;我不会在这里深入探讨,但是如果你想了解更多,请告诉我。
哪个指标是最佳匹配?
永恒的问题。正如我之前提到的,没有一个显而易见的答案,但这里有我自己对这个问题的想法:
- Flat metrics: 这是一个足够简单的方法,但是它丢失了层次结构信息,如果您首先经历了构建层次集成模型的麻烦,您可能会认为这些信息很重要。我建议只对那些超快超脏的项目使用扁平指标,因为时间限制是一个很大的因素。
- **定制的、独特的指标:**可能更合适,但你要付出时间和努力。此外,由于您将使用未经同行评审的指标,您可能会错过一些重要的东西。只有当手头的项目有非常独特的需求,并且在评估模型性能时应该考虑到这些需求时,我才会推荐定制的度量标准。
- **常见分类指标的层次版本:**这种方法有些直观(一旦你掌握了它的窍门),对于一个层次模型来说很有意义。然而,它可能不是最适合您自己的用例(例如,没有为最深类的正确/错误预测增加权重——这在某些用例中可能很重要)。它还需要一些额外的实现时间。总而言之,我认为这是一个足够好的预制解决方案,应该是大多数项目的首选。
最后
没有性能指标,机器学习模型什么都不是,分层模型需要它们自己的特殊照顾。没有一个最好的方法来度量基于层次的分类:不同的方法各有利弊,每个项目都有自己最适合的方法。如果您已经做到了这一步,那么您很有希望知道哪种方法最适合您的方法,并且一旦您开始使用它,现在就可以测量您的模型了。
这篇文章总结了我关于层次分类模型的四篇系列文章。如果您已经阅读了所有这些内容,那么您应该拥有设计、构建和衡量一个出色的层次分类项目所需的所有工具。我希望你尽可能充分利用它。
该系列的前几篇文章:
Noa Weiss 是一名人工智能机器学习顾问,总部位于特拉维夫。
附录
搞不清那些讨厌的等级指标?我是来帮忙的。
在下面的表格中,我回顾了“普通家养宠物”层次模型的模拟结果,查看了“大麦町”类的度量(记住:精确度、召回率和 f 分数度量是按类计算的,将标签(预测的和真实的)视为二进制)。
我看了几个例子,检查了每个例子对精确度和召回分数的贡献。记住——最终的精确/回忆分数是所有这些例子的总和。
一次揭开一只狗的层级指标的神秘面纱。
评论举例 :
- 将一个不同的品种错误地归类为一只斑点狗:召回得满分(因为“狗”的部分被正确识别),但精确度只有半分(因为“狗”是正确的,但预测的“斑点狗”标签是错误的)。召回不会受到负面影响,因为此处遗漏的“拉布拉多”标签不属于此处测量的[狗、斑点狗]类别。
- 将独角鲸错误分类为斑点狗——精确度为零(因为“狗”和“斑点狗”预测标签都是错误的),但召回指标不受影响,因为真正的独角鲸标签与[狗,斑点狗]类别的测量无关。
- 完美预测——预测和回忆都加分。
- 将一只达尔马提亚狗错误地归类为不同的品种:精确度指标得满分(因为“狗”分类器是两个分类器中唯一正确的),但召回率只有半分(因为“狗”标签被正确识别,但“达尔马提亚”标签被遗漏)。
- 一只达尔马提亚狗被误归类为彩虹独角兽:召回率为 0(因为狗和达尔马提亚狗的标签都被遗漏了),但精确度分数不受影响。
- 这个例子没有告诉我们任何关于狗/斑点狗分类器的表现,所以它不影响分数是显而易见的。
资料来源 : C.N. Silla & A.A. Freitas, 跨不同应用领域的层次分类综述 (2011),数据挖掘与知识发现,22(1–2):182–196
通过分层强化学习打造更聪明的智能体
如今围绕强化学习(RL)有很多炒作。我相信这是有充分理由的:RL 在雅达利电子游戏中取得了超人的表现,甚至已经击败了世界上最好的围棋选手。目前,RL 还被应用于系统的管理和配置、自动驾驶、机器人等领域。RL 会接管世界吗?还没有,首先有许多问题要处理:
- 样本效率:人类需要练习才能成为一个像样的视频游戏玩家,但 RL 代理需要的练习量是疯狂的!对于像 Breakout 这样的简单视频游戏,我们谈论的是数千小时的游戏时间,当然,当你有一个强大的服务器并且正在玩视频游戏时,这不是问题,但如果你需要一个像样的性能并且事先没有访问环境的权限,该怎么办?有许多不同的方法可以解决这个问题,如少量的镜头学习或从演示中学习,但这仍然是 RL 研究中的一个热门话题。
- 缩放:当状态和动作空间增大时,效率变差。如果你想到表格 Q-learning,每个动作有一列,每个状态有一行,所以如果你有 10 个状态和 10 个动作,那么你有 100 个 Q 值要计算。例如,当你处理视频游戏时,状态是由可能有 100x100 像素的游戏帧定义的(只是为了四舍五入),其中每个像素可以取 0 到 255 之间的值,所以可能的状态数是 255 ⁰⁰⁰⁰,假设我们有 10 个动作,那么你将有 255 个⁰⁰⁰⁰⁰ q 值…哎呀。更糟糕的是,想想连续的状态或动作空间;这确实是一个复杂的问题。深度 RL 可以处理这种巨大的状态空间,但以一种简单有效的方式做到这一点仍然是一个挑战。
- 泛化和迁移学习:此外,RL 智能体可以很好地完成一项他们已经接受过训练的任务。如果他们开始新的任务,表现又会很糟糕。
正如我以前说过的,已经开发了许多方法来管理这些问题,分层强化学习就是其中之一。但是 HRL 到底是什么呢?
分层强化学习的拯救
走路并不像看起来那么简单【图片由 Kira auf der Heide 上 Unsplash 。]
比方说,当你正在读这篇文章的时候,门铃响了。你要怎么办?嗯,你可以考虑站起来走向门口,但实际上,你要做的事情要复杂得多:你必须控制许多肌肉才能站起来,然后你必须走向门口,为此你必须再次控制你的肌肉,也要保持平衡,直到你走到门口。然而,你只考虑高层次的行为(起床,走向门口),因为低层次的行为是自然而然的。
HRL 生来就有这种想法。不再只有一个策略来实现任务的目标,我们现在有几个子策略在一个层次结构中协同工作。这种方法带来许多好处:
- 改进探索:得益于高层次动作的使用,动作空间减少,探索更简单。
- 样本效率:状态也可以用分层的方式管理,低级别的策略可以对其高级别的策略隐藏不相关的信息。这也减少了状态空间,正如我之前解释的那样,这提高了采样效率。
- 迁移学习:子策略或低级策略可以在不同的任务中重用。假设一个代理学会了如何制作咖啡,但现在你想让它学习如何制作卡布奇诺,如果你将制作卡布奇诺的任务分成制作咖啡,然后加热牛奶并使其起泡,那么第一个机器人已经可以使用它制作咖啡的经验,这将加速这项新任务的学习。
在实践中有不同的方法来实现 HRL。我亲自挑选了一些,并为你做了一个总结:
期权框架
由萨顿和 T2·辛格于 1999 年引入的选项框架提供了一种在 RL 中实现层次和宏操作的方法。这可能是 HRL 最常见的表述之一。
在期权框架中,代理处于半马尔可夫决策过程(SMDP)中,这是马尔可夫决策过程的一种扩展,其中动作之间的时间不是常数,允许它为其动作包括不同级别的抽象。
选项框架引入了选项的概念,这是一个动作的概括,让我们可以引入宏动作。一个选项的例子可能是拿起一个物体(涉及某些肌肉抽搐),但也可能是一个单一的肌肉抽搐。在这两个例子中,第一个是由多个原语动作组成的宏动作,第二个是原语动作。萨顿等人(1999) 介绍了期权的概念,并对其进行了如下描述:
选项由三部分组成:策略π : S × A → [0,1],终止条件β : S+ → [0,1],以及初始集 I ⊆ S。当且仅当 st∈ I 时,选项⟨I,π,β⟩在状态 st 中可用。如果选择了选项,则根据π选择动作,直到选项根据β随机终止。
这意味着每次观察到新的状态时,检查初始集 I 以查看当前状态是否属于它,如果是,则选项开始:从现在开始,π确定在每个步骤中采取的动作(而不是全局策略),并且在每个状态中,检查终止条件β,如果它返回 True,则选项结束,并且我们回到使用全局策略。在下图中,我们可以看到如何使用选项来管理不同时间长度的动作和状态。
在 MDP,状态转换由相同持续时间的离散时间步骤表示,而在 SMDP,步骤具有不同的持续时间。选项允许我们以任何方式分析轨迹[图来自 Sutton 等人(1999) 。]
每个问题的选项的定义留给每个用例,增加了 RL 要处理的问题定义的复杂性。此外,Options 框架没有明确考虑任务分段。
封建强化学习
封建强化学习(FRL)定义了一个控制层级,其中一个级别的管理者可以控制子管理者,同时这个级别的管理者又被超级管理者控制。每个经理为其子经理分配目标,子经理采取行动实现该目标并获得奖励。
FRL 中管理人员的控制层级[图片来自 Pixabay。]
封建强化学习(FRL)定义了一个控制层级,其中一个级别的管理者可以控制子管理者,同时这个级别的管理者又被超级管理者控制。每个经理为其子经理分配目标,子经理采取行动实现该目标并获得奖励。
FRL 应用于一个迷宫[图来自于达扬&辛顿(1993 )。]
FRL 最初是为了解决一个迷宫问题。代理从迷宫中的任意位置开始,并且必须找到到达某个位置的路。经理的结构如左图所示,蓝色区域是任务的目标,“U”代表代理无法跨越的障碍。每个经理的行动是:北、南、东、西或*,是一个特殊的行动,意味着经理应该在其区域内探索。在顶层,经理只能执行,而在底层,经理只能执行 NSEW。学习在开始时自下而上进行,底层的每个经理都知道应该去哪里,然后还有一些自上而下的学习,优化迷宫中的整体轨迹。下图显示了每位经理学习的操作:
每个经理都有自己的行动和学习到的概率,圆圈(或*)代表在分配给经理的区域内探索的行动,区域上的颜色代表去 NSEW 的行动。每个行动的面积与其概率成正比[图来自 from 达扬&辛顿(1993 )。]
FRL 基于两个主要原则:奖励隐藏和(2)信息隐藏。奖励隐藏意味着经理必须奖励执行其命令的下级经理*,不管这是否满足了上级经理的命令。所以每个经理都学会了自己去满足上层。信息隐藏是指这样一个事实,即管理者只需要在他们自己选择的任务粒度上知道系统的状态。由于这一点,更高的级别在一个简化的状态下在更宽的粒度上工作。*
FRL 代表了 HRL 的一大进步,但它在不同领域的应用并不成功,在某些情况下效率非常低。
封建关系网(HRL 的乐趣)
2015 年,DeepMind 带回了 FRL,并应用于 Deep RL。他们在 FRL 的原始架构和一些原则中启发自己:他们创建了一个模块化的 NN,其中有一个管理器,它从环境中接收状态和奖励作为输入,并输出状态的嵌入和工人必须实现的子目标。工人选择行动,并努力实现经理设定的目标。
期权批评家架构
Option-Critic 架构改进了期权框架,能够学习期权的内部政策和终止条件,而无需提供任何额外的奖励或子目标。
在这种情况下,假设选项能够在任何状态下启动,并且内部策略和终止条件已被学习,因此不必预先定义选项。选项上的策略目标是决定在每一步中使用什么选项,并让该选项的子策略处于控制中,直到选项策略返回终止条件。政策和终止条件是根据来自 Sutton 等人(2000 年)的基于政策梯度定理的解决方案来学习的。
此外,选择批评家架构是基于行动批评家架构的。其中有一个尝试动作的演员和一个评论家,他们评估每个动作有多好,并将其传达给演员。选项内策略、终止函数和对选项的策略属于系统的参与者部分,而评论家由 Q_U 和 A _ω组成,Q _ U 是在状态-选项对的上下文中执行动作的值,A _ω是对选项的优势函数。您可以在下图中看到该架构:
期权批评家架构[图来自 Bacon 等人(2016 年)。]
你自己试试
如果您想亲自尝试一下,我在 Tensorflow 上找到了 Option-Critic 架构的实现,您可以从 Github 下载。资源库使用 OpenAI Gym,但是如果你想在其他环境中尝试,可以查看这个 RL 环境列表。
感谢您的阅读!
分层强化学习:封建网络
让电脑看到更大的画面
约翰·西门子在 Unsplash 上拍摄的照片
每个任务都可以自然地分成子任务。当我们准备晚餐时,我们不会微观管理我们手的每一个小动作。相反,我们将任务分成更小的部分(取出原料、切割、烹饪、上菜),然后,我们专注于如何单独完成每一项任务。这种分解的概念启发了强化学习的分层方法。具体来说,封建网络(FuNs)通过使用模块化神经网络在经理和工人之间划分计算。经理给员工分配局部的、具体的目标,以达到最佳的学习效果。与此同时,经理学会了如何最优地分配这些子目标,以最好地完成一个“更大的”任务。
在这篇文章中,我们概述了封建网络背后的架构、直觉和数学。
照片由 Jehyun Sung 在 Unsplash 上拍摄
FuN 的建筑
FuN 是一个模块化的神经网络(MNN ),由两个独立的网络组成:经理和工人。这里,我们描述一个具有离散动作空间的环境。
有趣的模块化神经网络架构
该架构可能看起来很密集,因此下面是图表上每个节点所代表的内容:
变量定义
退一步仔细分析发生了什么是有用的。给定一个学习任务,我们在两个实体之间分配劳动:MNN 的“经理”和“工人”部分。我们可以看到,变量 z 只是我们观察的另一种表示, x. 换句话说, z 携带的信息与 *x,*相同,只是变量不同而已!我们将相同信息传递给员工和经理,但两者处理信息的方式略有不同。
经理
在接收到 *z 之后,*管理器通过将 z 传递给另一个函数来创建一个不同的潜在状态( s )。这种潜在状态是环境的另一种表现形式,但是在更高的维度上。管理者在比工作者更高维的向量空间中操作,以编码管理者如何考虑更大的画面而不仅仅是局部信息。
然后,管理者将这种潜在状态( s )推入一个递归神经网络(RNN)中,从而输出一个员工要实现的目标。此目标代表员工状态的相对变化。更正式地说:
经理 RNN 转发功能
其中 h 代表 RNN 的隐藏州。目标正常化后,我们做一些特别的事情。我们在有限的时间范围内汇集所有的目标c,然后将结果无偏差地传递到线性转换中。这有效地从经理的向量空间转换到员工的向量空间,并对经理分配的先前 c 目标的表示进行编码。
线性变换后的汇集
向量 w 有 k 个维度和两个关键属性:
- 由于变换没有偏差,它永远不会产生一个不变的非零向量。因此,员工永远不会忽视经理的投入。总有一些“意义”需要工人去提取。
- 由于合用,经理的条件随着时间平滑地变化。这可以防止员工无法理解或处理的目标的任何不稳定变化。
约翰·施诺布里奇在 Unsplash 拍摄的照片
工人
一旦工作者接收到 *z,*它就将 z 传递到不同的递归神经网络中。然而,工作者的 RNN 输出矩阵,而不是输出向量。该矩阵有几行和 k 列,行数等于可能的动作数。
工人 RNN 前进函数
其中每个 h 代表 RNN 的隐藏状态。为了开发关于为什么我们输出矩阵而不是向量的直觉,我们看下面的等式:
工人的行动输出
这个输出是工人行动的概率分布。然而,让我们换一个稍微不同的视角。假设如果我们选择了相应的动作,那么 U 的每一行都对结果状态进行编码。然后,如果我们查看向量 Uw ,每个元素都是一行 U 和编码目标 w. 之间的点积,将点积视为相似性的度量,并且知道 SoftMax 保留相对排序,则该向量具有与实现经理目标的概率成比例的**元素,前提是工人选择该行动。**因此,根据这种分布对动作进行采样是有意义的。
整个转发过程如下图所示。
趣味前进
它是如何学习的
金伯利农民在 Unsplash 上拍摄的照片
让我们考虑一下这个。在执行一个动作后,我们会得到一个奖励和另一组观察结果。然后,我们可以通过优化工人采取的行动,用 TD-learning 对整个 MNN 进行日常培训。之后,我们也将这些梯度传播给经理。然而,这违背了分层学习的目的,因为管理器的输出 g 将失去所有语义。这将使乐趣与任何其他网络没有区别,因为 g 只是成为另一个内在的潜在变量。因此,我们改为独立培训经理和工人。
经理
直觉上,我们希望经理给员工的目标不仅是随着时间的推移回报最大化,而且是员工可以实现的**。**因此,我们最大化员工状态变化和经理设定的目标之间的相似性度量。
根据以下等式更新 MNN 的经理部分:
经理政策更新方程式
其中 d_cos 代表两个向量之间的余弦相似度, A 是管理者的优势函数, c 代表管理者的眼界。通过将相似性度量乘以优势函数,该更新规则**有效地找到了可行性和回报之间的最佳平衡。**使用经理的内部价值函数计算优势,并以类似于其他演员-评论家算法的方式进行更新。经理的奖励函数是根据手头的任务来定义的。
工人
我们希望鼓励员工遵循经理设定的目标。因此,让我们来定义一种内在奖励:
工人内在报酬
这种奖励是员工在有限的时间范围内对经理指示的平均遵循程度。该算法被训练成最大化由环境奖励和给定的内在奖励组成的加权和。利用这些,我们训练工人的价值函数,类似于管理者。然后,我们使用以下内容更新员工的策略:
员工政策更新公式
其中我们最大化由优势函数缩放的对数概率。这类似于典型的演员-评论家算法。
该算法指出,经理和员工可能有不同的折扣系数。因此,员工可以更关注眼前的、当地的回报,而经理则关注长期的事件。
结果呢
DeepMind 实验室迷宫的有趣表演
FuNs [1]上的论文使用了许多实验来展示算法的鲁棒学习能力,最著名的是在 Montezuma 的《复仇》和 DeepMind Lab 的游戏上。使用 A3C 训练的递归 LSTM 网络作为基线,在这两个实验中,FuN 优于其他方法。
关于蒙特祖马复仇的有趣表演
更令人难以置信的是,乐趣从语义上学习有意义的子目标。在上面的可视化图中,高柱代表经理持续管理的目标,每个目标对应于游戏中的大“转折点”。
就是这样!
封建网络为强化学习提供了一个巨大的垫脚石,让代理能够自主分解任务,产生语义上有意义的结果。下一次,我们将探索如何将这个算法扩展到各种多代理框架。
参考
[1] A. Vezhnevets,S. Osindero,T. Schaul,N. Heess,M. Jaderberg,D. Silver,K. Kavukcuoglu,封建等级强化网络学习(2017),ICML‘17 .
从经典到最新,这里有讨论多代理和单代理强化学习的相关文章:
多主体 RL 问题的行动者批评方法
towardsdatascience.com](/openais-multi-agent-deep-deterministic-policy-gradients-maddpg-9d2dad34c82) [## DeepMind 的虚幻算法解释
最佳深度强化学习
towardsdatascience.com](/how-deepminds-unreal-agent-performed-9-times-better-than-experts-on-atari-9c6ee538404e)
基于 BigARTM 库的层次主题建模
照片由 Unsplash 上的 Alina Grubnyak 拍摄
主题建模是一种统计建模,用于发现文档集合中的抽象“主题”。LDA(潜在狄利克雷分配)是最流行和最广泛使用的工具之一。然而,我将展示一个替代工具 BigARTM,它为主题建模提供了大量的机会(例如特殊的度量和正则化)。
首先,让我们制定我们的任务。最初,我们有文档中单词的分布,但是我们需要得到主题-单词分布和主题-文档分布。所以,这只是一个随机矩阵分解的任务。
作者的米罗形象
我将使用 NIPS 文件来说明图书馆的原则。
df = pd.read_csv(‘./papers.csv’)
all_texts = df.PaperText
all_texts[111]
’ 差分私有子空间聚类\n 宁王、于和阿提辛格\ n 机器学习部… ’
我们从用流水线预处理数据开始:
作者的米罗形象
预处理流水线
’ 差分私有子空间聚类王艺凝王玉祥阿尔提辛格机器学习部……'**
现在,我们已经准备好对句子进行分词,获得一个单词包,并进行主题建模。顺便说一句,n-grams 有时对于这个目的非常有用。它们有助于提取成熟的表达方式,更好地理解每个主题。我决定只得到二元模型,但是,你可以选择任何数字。我们将选择文档中出现频率最高的文档。
创造二元模型
10349
[‘机器学习’,‘神经网络’,‘下界’,‘国际会议’,‘上界’]
二元模型似乎很有用,它将帮助我们区分不同的主题。所有的预处理都已经完成,所以我们可以移动到我们的模型。要做到这一点,我们必须创建一个包含文档单词的矩阵,模型将它作为输入。
ARTM 模型
创建矩阵“文档上的单词”
ARTM 图书馆为你提供了影响学习过程的巨大功能。例如,它允许添加各种正则化器来控制学习过程,并将 phi 和 theta 矩阵变得更加稀疏。在顶层模型中,我添加了一个用于 theta 矩阵的稀疏正则化器和一个去相关器,它可以激发 phi 稀疏性。
此外,我们可以指定我们想要用于评估的度量(这里有 Perxplexity 和 matrices sparstities)。我们添加这些正则项是为了让主题更容易理解,但是我们必须小心翼翼地做,这样只会稍微减少困惑。
让我们看看主要措施:
作者图片
我们现在还可以观看我们已经获得的主题
for topic_name in model_artm.topic_names:
print(topic_name + ': ' + model_artm.score_tracker['TopTokensScore'].last_tokens[topic_name])
作者图像
每个文档的主题矩阵相当稀疏,所以我们得到了我们所需要的。
作者图片
阅读与特定主题相关的文章会很方便。所以在这里我们可以获得一个按主题概率排序的文章列表。
作者图片
建筑层次结构
我们得到的主题似乎相当模糊,尽管我们可以看到它们之间的差异。如果我们对某个特定的主题感兴趣,我们可能想看看这个主题的副主题,并缩小搜索范围。出于这样的目的,我们可以构建一个看起来像树的模型层次结构。我们将只使用一个额外的 50 个主题的水平
作者的米罗形象
作者图片
副标题中的一些单词示例:
[‘风险’,‘经验’,‘度量’,‘类’,‘推广’,‘假设’,‘距离’,‘估计量’,‘性质’,‘证明’,‘有界’,‘预期’],
[‘活动’,‘试验’,‘神经元’,‘尖峰’,‘刺激’,‘放电’,‘神经科学’,‘情境’,‘潜在’,‘反应’,‘亚单位’,‘放电率’],
[‘训练’,‘特征’,‘标签’,‘对象’,‘损失’,‘输出’,‘分类’,‘地图’,‘建议’,‘数据集’,‘输入’,‘区域’]
看起来更好!话题开始更加具体。因此,我们可以查看与我们感兴趣的主题最相关的副主题。
def subtopics_wrt_topic(topic_number, matrix_dist):
return matrix_dist.iloc[:, topic_number].sort_values(ascending = False)[:5]subtopics_wrt_topic(0, subt)
subtopic _ 7 0.403652
subtopic _ 58 0.182160
subtopic _ 56 0.156272
副主题 _13 0.118234
subtopic _ 47 0.015440
我们可以像以前一样选择副主题文档。
感谢阅读。我希望我简要地介绍了这个库的功能,但是如果你想更详细地介绍,可以参考文档,其中有很多附加信息和有用的技巧(模态、正则化、输入格式等等)。).
期待听到任何问题。
基于 SNE 和 DBSCAN 的高维聚类
浏览真实世界的数据科学案例—挑战和见解
全球病例——它已经扩散…像病毒一样!
聚类是一组无监督的机器学习方法,用于根据数据的特征将数据分组在一起。例如,使用国家信息(人口统计、社会指标、经济指标等)+ COVID 数据,我们能确定日本更像印度、美国还是波兰吗?
我们将使用 K-Means 和 DBSCAN 聚类模型以及 PCA 和 t-SNE 降维方法进行评估。回顾我上一篇关于 熊猫的文章,使用的是上个月的 COVID 数据集。
数据挑战
不出所料,良好的数据始终是首要问题。新冠肺炎已有 2 到 3 个月的历史,数据集面临成长的烦恼。我必须管理的典型事务:
- 周末有数据缺失— 数据人周末不工作??
- 列标题错误(日期格式突然改变!)
- 文件格式转换——从拉丁语到 UTF 语&一个随机出现/消失的字节顺序标记(BOM)
- 文件交付时间不一致(数小时后重新编辑文件)
- 不同的源有不同的连接键(“俄罗斯”对“俄罗斯联邦”当没有可用的 ISO 国家代码时)
- 某些国家+指标组合缺少数据
每个问题都有一个解决方案/窍门——我们将讨论其中的一些。关键点——你必须有一个嵌入式的数据质量保证流程作为你的工作流程/管道的一部分。
下面是我们如何从约翰·霍普斯金的 COVID 数据开始:
初始数据集-约翰·霍普斯金数据集的国家级确诊病例和死亡病例
应用窗口函数
我希望每天(国防部)都有病例变化,但数据一致性是个问题(有些天他们没有报告病例,而是把它们集中到第二天,这让国防部很紧张…).取 3 天、7 天、21 天的平均值将有助于平滑每日利率。
Pandas 有一个滚动窗口函数,使计算 n 天窗口变得容易:
计算各种滚动平均数(病例和死亡的每日变化)
这有助于消除像圣马力诺这样的小国的懒惰的卫生部门专员在星期六/星期日报告 0 例病例并等到星期一才报告的周末。我为我的目标数据集创建了 3–7–14 个滚动平均值。
使用滚动窗口平滑
添加经济和统计指标
我想要更多的特征,如人口和人口密度、铁路和航班数量、通货膨胀率、医院床位等,来添加到我的分析中。WorldBank.org 有一个很长的指标列表,使用我编写的一些函数,很容易获取并合并到我们的数据集中:
破解代码以提取单个指示器(我使用 csv API 而不是 json,因此需要解压缩)
使用添加度量值(…)我们可以运行一系列调用,向我的数据集中添加一系列不同的指标:
每行代表一个国家(第一行是美国,然后是西班牙、意大利、法国和德国)
我增加了 25 个特征——丰富到可以把国家聚集在一起?运行关联矩阵是可视化我们的特征和潜在识别缺陷的好方法:
特征之间的相关性。你真正要做的就是。数据帧上的 corr()!
观察结果:
- 航班和铁路与 COVID 高度相关
- GDP、航运、老年人口适度相关
- 污染、生育率和因疾病死亡人数高的国家呈低度负相关
- 也许病例、死亡及其 3-7-14 天的变异有太多的相关性…
但这就像一个科学实验,所以我们需要假设,测试,验证,并可能再次尝试!
缩放至标准化数值范围
大多数 ML 模型需要“缩放”输入,即值的标准化范围。人口以百万为单位,但其他值以小数或%为单位会导致模型偏差。
请注意,美国人口为 3.22 亿→比例为 1.809,西班牙人口为 4600 万→ 0.0267
25 维→2 降维(主成分分析和 t-SNE)
聚类分析模型不适用于维数很大的情况(大= 3+)。维度的诅咒详述了它——*tldr;*数据变得稀疏,用于确定彼此“接近”的点的距离算法不再有效。
我们的 25 维数据集可以折叠成 2 维,同时通过使用 PCA (主成分分析)或 t**-SNE**(t-分布式随机邻居嵌入)保留关键特征信息。25 →2 维缩减的下图:
二维 PCA 与 t-SNE(在我的 COVID+数据集上)——让你想起 CT 扫描?
主成分分析是一种古老而可靠的方法,而 t-SNE 是最新的东西(你可以从上面的图中看出原因)。解释 PCA & t-SNE 超出了本文的范围。但是参考 Pranay Dave 的[9] nice 俏皮话描述的一些差异:
PCA本质上的工作原理是通过分尽可能基于最高变化域******
******【TSNE】本质上是通过 分组 分 尽可能接近 的特点来分
聚类(K 均值和 DBSCAN)
聚类利用您的数据,系统地确定相似性,并将其分组为“聚类”。K-Means 是久经考验的真实模型,而 DBSCAN 是这个街区的新成员之一。
我为 K-Means vs DBSCAN 创建了自己的一行程序(请随意引用我的话):
" K-Means 需要选择 K 个聚类,随机尝试各种聚类中心,直到为每个聚类找到到相邻点的全局最佳距离。"
" DBSCAN 在随机点开始一个新的聚类,并递归地同化ε-范围内的邻居——迭代更多的新聚类,直到所有点都被同化。"
如下图所示——使用 t-SNE 处理后的数据——K-Means 和 DBSCAN 都可以工作,但 DBSCAN 可以更好地移除噪声点和隔离聚类。两个模型的超参数的微调需要测试(反复试验)。
将它们放在一起(模糊减少+聚类)
所以我们有:
- COVID 数据—按国家和日期列出的病例和死亡
- 计算出的 COVID 3–7–14 DoD 增量
- 增加了国家级数据,如人口、就业、污染等
- 使用 t-SNE 将 25 维减少到 2 维
- 使用 DBSCAN 聚类将国家分为不同的颜色组
接下来,我们将介绍最后两步——t-SNE 和 DBSCAN 参数的调整以及最终的可视化。
t-SNE 调谐:
SKLearn 的 t-SNE 函数有 1 个超参数要调:困惑!多么愚蠢的名字,但它是合适的,因为它是一种模糊(令人费解)的方式来调整#局部与全局点。显然,视觉反复试验是选择正确设置的最佳方式[6]。
简单的代码产生了一系列不同的困惑的情节
我尝试了 10-90 的数值范围乘以 10。嗯…挑哪一个…我猜你想要一个 w/可视分割/某种类型的集群。我不得不认为有比这种眼球法更好的方法,但是 30 看起来不错。
t-SNE 带着不同的困惑——就像随机的墨迹…选一个和你说话的!
DBSCAN 调谐:
这两个超参数是 eps 和 min_samp ,用于调整集群的数量。设置 eps 设置一个簇可以寻找相邻点的半径或最大距离。 min_samp param 定义了符合聚类要求的 eps 范围内的最小点数。它们一起决定簇的数量和簇的形状。
注意 DBSCAN 不需要声明每个点-移除一些没有 min_samp 邻居的异常值或在另一个聚类的 eps 范围内的异常值(显示为非彩色点)。与 K-Means 相比,这是一个关键特性/优势。
构建 n-samp 和 m-eps 参数的可视矩阵的代码
Hmmm 好乱,挑哪个?我喜欢 eps:1.25 samp:3
总装
通过困惑调整使用 t-SNE 进行降维后,应用DBS canw/hyper-parametersEPS和 min_samples — 我们应用国家标签并放大以查看哪些国家聚集在一起。我们可以观察(添加所有标签是有噪声的,所以我添加了一个随机集):****
不要介意颜色的变化,这是随机过程的一部分…
观察结果:
- 美国、法国和意大利紧密地聚集在绿色区域(G10 似乎聚集在一起)
- 俄罗斯、加拿大、中国、印度等被剔除——为什么?
- 中国和印度在右下方——有意思?
- 日本和白俄罗斯、波兰等分在一组——奇数?
- 相当多的国家按地理位置分组(巧合的是,中东、东南亚、拉丁美洲——为什么?)
进一步分析/潜在问题和作业
嵌入 t-SNE 的尺寸/特征的选择可能比参数的调整更重要。如果有更多的时间,我会专注于确保我们的模型输入有正确的特性。
下一步(如果你选择接受任务):
- 放弃一些高度相关的特征(如 3–7–14 天的病例/死亡)
- 衡量每个特性的影响(可以应用 LIME 或 Shapley 吗?)
- 尝试在一个 3-D 互动的情节上可视化(PlotLy/Seaborn 有更好的 3D 素材)
- 添加不同的指标或其他 COVID 病例数据
尝试所有这些方法,并在你的结果中留下评论。如果你有数据机器人或 H2O,你的生活将会大大简化:)
玩得开心!
参考资料:
- [0] — 介绍有 COVID 的熊猫,作者 Doug Foo
- [1] — 本文代码/笔记本,在 GitHub 上
- [2] — 约翰·霍普斯金全球 COVID 数据,在 GitHub 上
- [3] — USAfacts 美国地区 COVID 数据,关于USAfacts.org
- [4] — 国家指标,载于世界银行
- [5] — 降维,作者 DJ Sarkar (他是 DS/ML 文章的忠实粉丝)
- [6] — 微调 t-SNE ,作者克里斯·奥拉
- ****[7] — PCA 和 K-Means 教程,作者 Dmitriy Kavyazin
- [8] — 聚类介绍视频,希利&麦金尼斯在 Youtube 上发布
- [9] — PCA vs t-SNE ,作者普拉纳夫·戴夫
高医疗能力是抗击新冠肺炎的一个重要因素
比较新冠肺炎对澳洲和其他拥有顶级医疗保健能力的国家的影响
图片来源:freepik
作者:纳米塔·希巴&凯瑟琳·洛佩斯
自从新冠肺炎疫情于 2019 年 12 月在中国爆发以来,整个世界都在与这场前所未有的疫情进行斗争。不同国家在不同时期实施了封锁、关闭边境、宵禁等措施。由于没有一个国家对此做好充分准备,这些国家的卫生保健能力受到了不同程度的挑战。在平息了第一波之后,澳大利亚(像许多其他国家一样)不幸地经历了第二波。这给我们世界级的卫生系统带来了巨大的压力。
没有一个国家具备足够的卫生能力来应对这一挑战,包括像澳大利亚这样在诊所、医院和社区护理中心拥有顶级卫生能力的国家。
数据
我们在本次研究中使用的新冠肺炎公共数据如下:
- 确诊病例、死亡病例、痊愈病例数据来自约翰·霍普斯金大学
- 测试数据来自我们的世界中的数据
- 人口和人口密度数据来自世界人口统计
- 来自全球健康安全指数网站的健康能力得分,这是该国诊所、医院和社区护理中心的健康能力指数
包括澳大利亚在内的卫生能力最高的 10 个国家
澳大利亚在卫生能力得分最高的前 10 个国家(德国、南韩、芬兰、丹麦、澳大利亚、荷兰、克罗地亚、日本、爱尔兰和白俄罗斯)中排名第 第 5,即诊所、医院和社区护理中心的卫生能力,这是 : 的一项指标
- 更广泛的医疗保健系统可用的人力资源: 每 10 万人拥有的医生;每 10 万人拥有护士和助产士;更新卫生人力战略,解决人力资源短缺问题
- 设施容量: 每 10 万人医院床位数;隔离高传染性疾病患者的国内能力
基于确诊病例数的比较
在澳大利亚,与其他 9 个国家相比,第一波新冠肺炎开始并达到高峰的时间相对较晚。如下图 1 所示,澳大利亚和德国的确诊病例数(每百万)在这两个国家出现首例 10 例确诊病例后一个月左右开始急剧上升。
在曲线变平之前,包括澳大利亚、韩国和芬兰在内的这 10 个国家中的 50%已经成功地将第一波的规模限制在每百万确诊病例的 7 天平均计数的非常低的数字(~50)。虽然一些国家如爱尔兰在第一波中经历了大量的病例,但是这些国家中的大多数已经成功地控制了第二波,每百万人中确诊的病例数较低。澳大利亚、荷兰和丹麦已经正式进入第二波。
图 1:所列 10 个国家每百万确诊病例的 7 天平均计数
基于回收率的比较
尽管这些国家的确诊病例总数存在差异,但第一波期间的恢复率显示出显著下降,但随后大多数国家在 3 个月内收敛到 90%左右。然而,当第二波袭击澳大利亚时,恢复率再次下降,很可能是由于大量新的确诊病例。如下图 2 所示,澳大利亚和日本在经历了一段时间的下降后,恢复速度有所提高。较低的恢复率可能表明社区中存在大量活跃病例。更好的卫生保健能力当然有助于照顾患病人口和提高康复率,但这并不能提供保证。
图 2:列出的 10 个国家的回收率
基于致死率的比较
在第一波下降后,澳大利亚在 10 个国家中实现了几乎最低的死亡率,这反映了该国装备良好的医疗保健系统的力量,包括可用的人力资源和所需的设施能力,这有助于治疗大多数患者,从而降低了死亡人数。然而,由于死亡发生在感染开始/检测之后,与当前活跃病例相对应的死亡的真实值可能会在一段时间后得知,因此,由于澳大利亚第二波流行,死亡率可能会在未来
天进一步上升,如下图 3 所示。
图 3:列出的 10 个国家的死亡率
基于测试的比较
检测的重要性已经在世界范围内得到认可,拥有高医疗保健能力的国家通常具有进行大量检测的优势。如下图 4 所示,描述了 10 个国家每千人 7 天的平均累积检测次数,很明显,随着时间的推移,澳大利亚逐渐但显著地增加了检测次数。最近的趋势表明,与该集团中的其他国家相比,澳大利亚的每千人检测制度更加严格,这使澳大利亚成为仅次于丹麦的第二个国家,丹麦从疫情开始就一直在进行严格的检测。
图 4:列出的 10 个国家的每千人 7 天测试计数
大量的检测有助于在向其他人的传播尚未发生或仅限于少量传播的早期阶段识别阳性病例,从而通过及时追踪、隔离和检疫控制潜在的传播。由于大量测试可能无法提供信心或疾病传播程度的清晰图像,我们还研究了测试阳性率,即所有测试中总阳性病例的比率。下图 5 显示,与其他 9 个国家相比,澳大利亚除了达到最低的检测阳性率(0.44%)外,还进行了大量的千人检测。韩国(0.98%)和丹麦(0.80%)是另外两个检测阳性率非常低(低于 1%)的国家,由于对较低的传播率有较高的信心,它们对安全重新开放社区相对更有把握。虽然澳大利亚正在经历第二波疫情,但一旦我们能够控制热点地区(如墨尔本)的新增病例,并提供广泛的检测和高卫生能力,我们也将处于社区重新开放的有利位置。
图 5:10 个国家的阳性检测率
摘要
总结我们的研究结果,与世界上卫生能力最好的其他国家相比,澳大利亚在控制新冠肺炎确诊病例方面做得相对较好。除此之外,澳大利亚在进行大量检测方面也做得很好,实现了
最低的检测阳性率,并且与该集团的其他国家相比,将死亡率保持在较低的水平。然而,尽管我们装备精良,准备充分,拥有强大的医疗体系,但我们不能在与新冠肺炎的战斗中休息和放松。
在疫情期间,我们应该感谢有一流的医疗保健系统支持我们,我们都会照顾好自己,并保持受到保护,在这场与新冠肺炎的战斗中尽我们的一份力量来保护澳大利亚的安全!
Namita Chhibba是一位年轻、上进、鼓舞人心的数据科学家,他和我一样热衷于探索数据和利用新冠肺炎数据获得见解,并帮助人们更好地了解新冠肺炎。
欢迎访问ka ggle repo,我们欢迎您的反馈和意见。
NLP 模型的高级历史
我们是如何达到目前 NLP 任务的基于注意力的变压器架构的
使计算机能够理解人类语言的自然语言处理(NLP)并不是一个新概念。然而,过去十年见证了 NLP 技术进步的前所未有的飞跃,其中大部分进步是由深度学习实现的。NLP 技术发展如此之快,以至于数据科学家必须不断学习新的机器学习技术和模型架构。令人欣慰的是,自从发展了当前最先进的 NLP 架构,即基于注意力的模型,NLP 领域的进展似乎暂时放缓了。数据科学家终于有机会赶上了!
但是我们是如何达到 NLP 的当前状态的呢?第一个重大进步出现在 2013 对 Word2Vec 的突破性研究(详细内容见 Mikolov 的一篇论文)。Mikolov 等人意识到,当他们在 NLP 任务中训练神经网络时,网络被迫学习单词之间的相似性。这些单词的矢量表示存储在神经网络的嵌入层中,它们的发现为 NLP 任务增加了一个全新的维度。多亏了 Word2Vec,我们现在有了一种更有效的方法来创建单词向量。我们不再需要依赖传统的单词稀疏表示和一个热编码。此外,利用单词嵌入需要更少的内存,减少计算时间,并已显示出极大地改善下游模型性能。其他单词表示模型,如 GloVe,也随之出现。不再有一个热编码!
由于深度学习的进步和不断增加的计算能力,递归神经网络(RNN)和长短期记忆网络(LSTM),一种 RNN 的版本,在 2014 年和 2015 年越来越受欢迎。安德烈卡帕西的博客文章题为“循环神经网络的不合理的有效性”是一封写给 RNN 的著名且被广泛引用的情书。RNN 和 LSTM 使文本序列数据的处理成为可能。数据的顺序与序列数据有关,在 RNN 之前没有好的方法来处理序列数据。LSTM 对 RNN 的改进在于,对于长序列,网络会记住更早的序列输入。这对于 RNN 氏症来说是一个重大问题,也称为消失梯度问题。LSTM 记住了序列中哪些信息是重要的,并防止早期输入的权重降低到零。还有一个额外版本的 RNN,称为门控循环单位(GRU)。它与 LSTM 非常相似,但不同之处在于它有保留长序列信息的特殊门。几年来,RNN 和 LSTM 是 NLP 任务的支柱——每个人都使用他们。但是没过多久,它们就被一个更好的架构取代了:注意力网络!
基于注意力的网络在 2015 年到 2016 年期间变得流行起来。注意力网络是一种神经网络,允许关注数据输入的特定子集:你可以指定你希望网络关注什么。这些模型已经打破了许多 NLP 任务的性能记录,如神经机器翻译、语言建模和问答问题。注意力网络也更有效,需要更少的计算资源。这是一个重要的改进,因为它经常需要大量的 GPU 形式的计算能力(这并不总是可用的)来训练 RNN 氏症。
在 2017 中引入的一种特定类型的基于注意力的网络,即 Transformer 模型,在现代 NLP 架构中尤其占主导地位。转换器与 RNN 的相似之处在于它处理序列数据,但是数据不需要以任何特定的顺序输入到模型中。因此,Transformer 模型可以使用并行化更快地训练更多的数据。Transformer 模型导致了我们 NLP 目前的状态:BERT、ERNIE 2.0 和 XLNet 的时代。
来自变形金刚(BERT)模型的双向编码器表示由谷歌的研究人员在 2018 中引入。BERT 版本是可用的最先进的 NLP 模型之一。BERT 是一个深度双向无监督模型,用于预先训练单词表示,以便稍后在 NLP 任务中使用。双向在神经网络中至关重要,因为它允许信息在模型训练时前后流动,从而提高模型性能。
虽然 BERT 的概念类似于 Word2Vec 和 GloVe,但是 BERT 单词向量是上下文敏感的!使用 Word2Vec 和 GloVe,具有高度上下文多样性的单词(我感觉蓝色,蓝色是我最喜欢的颜色)由单个向量表示。您可以猜测这种类型的表示可能会导致下游的模型性能不佳,因为单词的含义严重依赖于上下文。有了 BERT,单词 blue 的两个上下文将会用不同的向量来表示。
BERT 只是基于注意力的架构的冰山一角。在 2019 年,卡内基梅隆大学和谷歌的研究人员创建了 XLNet 。这篇论文声称 XLNet“在 20 个任务上超过了 BERT,而且经常是大幅度超过。”与 NLP 的其他最新进展不同,其架构并没有太大的不同。像伯特一样,XLNet 利用了一个基于注意力的网络。在 2019 的夏天,一家中国科技公司在另一个基于注意力的网络 ERNIE 2.0 上发表了一篇论文。该论文声称 ERNIE 2.0 在 16 个任务上优于 BERT 和 XLNet,包括中文任务。像 BERT 一样,ERNIE 2.0 和 XLNet 都是预训练模型,利用了 transformer 架构和注意机制。虽然最初的 BERT 模型不再是王者,但诸如 RoBERTa 之类的 BERT 版本在 NLP 领先技术领域仍然具有竞争力。
总之,目前没有单一的、整体最佳的 NLP 模型。然而,基于注意力的变压器网络是占主导地位的架构。顶级模特在不同的任务上表现出色,每个都有自己独特的优点和缺点。面对所有这些相互竞争的模型,很难找出哪个模型最适合您的任务。我最喜欢的新资源之一是 paperswithcode.com。该网站根据特定的机器学习任务方便地组织研究论文,使您能够了解最新的模型和架构。
带代码的论文突出了 ML 研究的趋势和实现它的代码。
paperswithcode.com](https://paperswithcode.com/area/natural-language-processing)
这就是你要的 NLP 在过去十年中快速发展的简史。NLP 是一个不断变化和发展的领域,当然不适合喜欢模型稳定性的数据科学家。但这也是乐趣的一部分!我们将会看到基于注意力的网络时代会持续多久。
面向机器的高中数学:微分编程
子符号人工智能的符号:梯度(∇)代表关于机器学习系统所有参数的导数,是梯度下降算法的核心。(来源:半脑来自 Seanbatty (Pixabay) ,作者修改加框)
可微分编程让机器学习世界运转起来。PyTorch、TensorFlow 和任何其他现代机器学习框架在实际学习时都依赖于它。任何对人工智能感兴趣的人都有足够的理由去熟悉可微分编程。我们邀请您跟随我们,通过两个部分来解释推动当今人工智能行业大部分发展的概念框架。不需要博士!
可微分编程对机器学习至关重要,因为它是梯度下降的基础,梯度下降是一系列优化算法,在机器学习模型的训练中做繁重的工作。形容词可微分来源于名词微分,计算导数的数学过程。是的,你高中微积分课上学到的好的老导数。事实上,当涉及到人工智能时,你会在高中数学上取得惊人的进步。比如我们下面会看到,名字梯度下降中的梯度本质上是导数的集合。
为了使用梯度下降训练一个中等规模的深度神经元网络(DNN),你必须计算许多导数。这就是为什么训练效率取决于高效区分的能力。进入自动微分(AD)。AD 是计算机计算导数的方式。AD,尤其是其所谓的反向模式(又名反向传播),是当前人工智能淘金热背后的算法驱动力。没有它,严肃的机器学习应用将是不可行的——更不用说盈利了——即使是在现代的云基础设施上。事实上,如果你看到一个深层神经元网络在任何地方运行,它已经被反向模式 AD 训练过了。
今天的帖子将回答以下问题:
- 什么是软件 2.0,为什么可微分编程的概念可能比机器学习更重要?
- 我高中的微积分课和梯度下降(机器学习的工作马)有什么关系?
- 区分代码是什么意思?我们怎么可能计算一段 Python、Scala 或 C 代码的导数呢?
- 为什么差异化可以而且应该自动化?
软件 2.0,或填空编程
随着机器学习在 2010 年代末成为常态,Yann LeCun 或 Andrej Karpathy 等人工智能名人推广了软件 2.0 的想法:如果神经元网络这种特殊的计算机程序可以根据足够的训练数据来学习它们的最佳参数,那么我们为什么不设计所有的程序来根据描述它们正确行为的数据来优化它们自己呢?
为了说明这个想法,想象所有可能的程序的空间——巨大的程序空间,其中每个可能的计算机程序都由一个点来表示。软件 2.0 不是修复整个程序,而是选择程序空间的一个子集——一个可参数化的可能程序类——并让计算机在这个类中找到最佳选择。这就是安德烈·卡帕西所说的【填空编程】。你定义框架,软件 2.0 描绘画面。
可区分程序在程序空间的子集内自动优化。(受 软件 2.0 启发,A. Karpathy,2017)(来源:作者)
但是你如何向计算机解释你认为什么是最佳的呢?在这里,事实证明,计算机毕竟与人类软件开发人员没有什么不同。比起对软件需求的模糊口头解释,大多数开发人员更喜欢客观可测试的规范,准备集成到自动化测试套件中。因此,当我们为我们的软件 2.0 提供一大组测试时,计算机系统地尝试各种具体的程序,描绘出它的程序空间子集。对于这些程序中的每一个,它通过满足测试套件的程度来衡量它离最佳程序有多远。
从测试人员的角度来看程序。(来源:作者)
为了让这种方法工作,我们必须通过使用一种特殊的测试来帮助计算机,所谓的软单元测试 (SUT)。SUT 基本上是你常规的单元测试,唯一的区别是它不会给你一个二元的反应(绿灯表示成功,红灯表示失败),而是计算一个分数来量化你离期望值有多远。例如,测试加法时,SUT 会告诉你 2+2=4.1 比 2+2=-11 的误差小。
把黑匣子切开,露出它的内部参数。(来源:作者)
从测试人员的角度来看,程序是一个将输入转换成输出的黑匣子。给定一些输入 x ,它产生一个输出 f ( x )。当然,如果你打开黑盒,你会发现大量的内部参数。在传统的程序中,所有这些参数都是固定值。然而,在软件 2.0 中,通过调整这些参数,程序在程序空间中“移动”。
经过 n 次软单元测试的软件 2.0 程序调整其内部参数,以匹配输出 f(xᵢ和期望 yᵢ.(来源:作者)
每个 SUT 包括一个输入 x 和一个输出 y 。输入被插入到程序中,程序从中产生输出 f ( x )。将此输出与预期结果进行比较,当两个值大致相等时,将获得高分。比较的结果被反馈到软件 2.0 算法中,在该算法中,比较的结果被用于调整参数以逐渐提高测试分数。 y
在一次相对短暂的炒作之后,术语软件 2.0 并没有像发明者希望的那样成为热门词汇。然而,如果你在过去十年中接近过机器学习人群,你可能听说过软件 2.0 的最相关的子类:可微分代码,有时写成∂Code („∂是部分微分的象征)。
软件 2.0 一般描述自优化代码,而可微分代码是通过梯度下降方法自优化的代码。可区分代码如何帮助我们优化程序?天真地,我们可以随机尝试各种参数设置,直到我们合理地确定我们可以忍受剩余的误差。但这至少有两个主要问题。首先,程序空间的完全参数化子集通常是巨大的。即使只有一个连续的参数,理论上我们有无限多的选择。第二,每当我们找到一个看似不错的解决方案时,我们怎么能确定它旁边没有更好的解决方案呢?
这些都是古老的问题,绝不是机器学习所特有的。在数学中,这样的优化问题比比皆是。站在牛顿和莱布尼茨这样的巨人的肩膀上,我们可以用今天高中的数学知识来理解其中的大部分。
为了说明这些问题及其解决方案,让我们先来看一看可微编程。
第一可微程序
(本节思路改编自 可微函数编程 ,N. Welsh,2018)
想象你必须写一个相当简单的程序。要求如下:程序必须接受单个浮点数作为输入参数 x 。从这个输入,它必须产生一个输出 y ,另一个浮点。给你 200 个描述所需行为的软单元测试。每个测试由一个输入 x 和一个期望输出 ŷ 的对( x , y )定义。
因为单元测试是软的,所以必须有一个衡量程序在每次测试中表现好坏的标准。为此,我们引入了评分标准
公制𝓛⁽ⁱ⁾是第 i 次测试的所谓损失。最理想的情况是,它应该是零,因为这样输入 x ⁽ⁱ⁾将完全匹配预期输出 ŷ ⁽ⁱ⁾.我们程序的整体测试套件性能指标𝓛就是所有 200 个𝓛⁽ⁱ⁾的总和,或者,用数学家的 for-loop 来说,
𝓛越小,我们的整体表现越好。由于测试是成对的数字,我们可以在一个二维图中可视化所有 200 个,输入在 x 轴上,输出在 y 轴上。让我们假设您的测试数据如下图所示:
200 个软单元测试的图表。每个点代表一对输入和期望输出。(来源:作者)
现在,在您将开发任务交给算法之前,还有最后一个重大决策要做:选择一个合适的程序空间连续子集来搜索最优值。
考虑到测试套件中输入-输出关系的正弦性质,我们有一种预感
可能是个不错的选择。该函数中只有一个内部参数: ω (这是一个小写的“omega”),表示正弦的频率。因此,我们看到的是程序空间的一维子集,你可以把它想象成从 ω =-∞到 ω =∞的一条线,就像x-轴从 x =-∞到 x =∞。
每个可能的 ω- 值对应我们程序的另一个版本 f ( x )。假设我们将 ω 设为 12.345,那么我们的程序就变成了
所以,我们来试一试吧!让我们选择一些ω-值,看看我们是否不能满足所有那些单元测试。
测试参数值ω=0.75、2.25、1.0 和 1.5 的套件性能。左:程序的输出(实线)与预期的输出(圆点)。在一帧中,左侧的三个橙色条表示三个示例点的逐点误差ℒ⁽ⁱ⁾。右图:每个ω值的𝓛-score。
通过看上面的动画, ω = 1.5 是目前为止最好的结果。但是,比如说,在 1.54321,会有更好的解决方案吗?在这个例子中,没有。然而在现实中,通过随机选择,你可能已经尝试了几十或几百次来找到一个足够好的解决方案,你可能仍然没有达到非常接近正确的 1.5。
如何才能走出这个困境?考虑损失度量𝓛.这个函数中的参数,也就是未知数是什么?尽管有 200 个 x - y 对,𝓛的结构非常简单。不可否认,对于一个人来说,写出 200 项的总和(每个 SUT 一项)有点难,但是对于计算机来说,200 项的总和并不比两项的总和更可怕。剩下的就是一个简单的单参数函数,𝓛( ω 。如果你看看上面的定义,你会发现它完全由测试套件的 x⁽ⁱ⁾-和ŷ⁽ⁱ⁾-values.决定这意味着,根本不需要随机采样参数值。你已经知道了函数在*每一点的值!*你可以很容易地绘制出𝓛( ω ),就像其他任何函数一样:
程序的整体测试套件性能(损失分数)作为频率参数ω的函数。(来源:作者)
因此,要找到最优的 ω ,只需找到函数𝓛( ω 的最小值。寻找极小值——等一下,我们在高中微积分课上不是一直在这么做吗?确实如此。这与衍生品有关。幸运的是,𝓛( ω 不仅结构简单,而且可微。术语可微的意思是你可以计算𝓛( ω 的导数。事实上,我们在这里的小例子被称为可微编程的全部原因是,我们想要优化的函数𝓛( ω 是可微的,让我们刷新微积分记忆,看看导数如何帮助我们系统地优化。
微积分概述
函数 f ( x )在点 x 的导数测量函数的局部斜率。你可以把导数看作一个工具,它总是告诉你函数的上下位置。事实是,要理解梯度下降和可微规划的基本思想,你只需要知道这些。
更正式地说,如果对参数的导数大于 0,这意味着你将通过增加参数来上坡。如果小于 0,说明你会通过增加参数走下坡路。
为了了解导数与斜率的关系,让我们看看它的定义。通常,导数被写成f’(读作:“eff prime”)并被定义为数学极限的形式
你可以把导数想象成一条从点( x 、 f ( x ))到(x+δx、f(x+δx))的直线的斜率,随着你减少水平距离δx、使这些点越来越靠近。在数学极限 x 、 f ( x ))到(x+δx、f(x+δx))随着水平距离δx、δx→0的减小,点实际上是合并的。
左:导数是连接两点的直线在所述两点间消失距离的极限内的斜率。右图:斜率是高度变化除以位置变化,即δf*/δx .(来源:作者)*
于是,斜率很自然地被定义为
导数如此有用的原因之一是,在极值点——最小值,函数的谷底,最大值,函数的波峰——导数总是正好为 0。从绘制函数的最小值和最大值的斜率可以直接看出这一点。
在最小值和最大值中,斜率为零(水平),即 f′= 0。(来源:作者)
更棒的是!导数不仅告诉你,你现在是在最小值还是最大值,它还告诉你在哪个方向可以找到一个!方向这里的字面意思是你沿着 x 轴移动的方向,即你是否增加或减少参数 x 。
这是怎么回事?正如本节介绍中所承诺的,衍生工具是一种工具,它可以让你在任何时候知道什么是上涨,什么是下跌。如果你想最大化函数值,也就是你想找到你周围的最高点,那你就往上走。
这到底是什么意思?考虑你目前处于参数值 x₀ 。在那里,局部导数是f’(x₀)。如果导数大于零,这意味着增加 x 你上升,减少 x 你下降。那么,你怎么做才能更接近你的目标,最高点呢?你增加 x 。更精确地说,通过在正斜率方向上迈出一步,选择新的参数值 x :
其中 ɛ 量化了你的步长。在机器学习行话中,步长被称为学习速率。
这个公式自动涵盖了相反的情况,即导数小于零。负的f’意味着对于更大的 x ,你下降,远离你的目标,最高点。因此,在负f’(x₀)时,向上意味着向更小的**x*-值迈进一步。如果你想最小化函数值,你进行类似的操作,只是现在你采取ɛ-向负斜率(下坡)方向的步骤:*
该过程如下图所示。
**
导数用于迭代寻找局部最大值(左)或最小值(右)。(来源:作者)
敏锐的读者会注意到这种方法的几个问题。首先,你只会找到最接近你的起点的最小值或最大值。在上面的例子中,如果你碰巧开始更靠近 x ₘᵢₙ,₂,而不是 x ₘᵢₙ,₁,使用所述方法的最小化将总是把你带到 x ₘᵢₙ,₂,而不是 x ₘᵢₙ,₁,尽管这将是一个更低的点,即更好的点。**
这是一个众所周知的问题,源于导数本身的局部性质,也是一个难题。每一种基于导数的方法都有这个固有的缺点。这个问题甚至更大,尤其是在更高维度中,因为除了最小值和最大值之外,还有鞍点,其他具有f*′= 0 属性的实体,它们会干扰你对最优解的追求。*
不幸的是,到目前为止,人类还没有一种已知的方法来判断是否存在一个更好的点,更不用说如何系统地找到它了。已经发明了大量的工具来至少缓解这个问题,但是一个通用的解决方案可能还需要很长时间。
第二个问题是步长的选择 ɛ 。如果它太大,你就有超调的风险,也就是说,你可能会跳过一个最优值,而不是接近它。另一方面,如果它太小,你可能不得不采取许多步骤来接近最佳值。更糟糕的是,步长实际上不是 ɛ 而是ɛ⋅f*’因此与导数的值成比例。因为在极值点,当你接近它时,导数变为零,导数会变得越来越小,这反过来导致你的步长越来越小。为了克服这种减速和过冲问题,在实际应用中,自适应地选择ɛ*。**
向更高维度的旅行
但是,当我们不是只有一个参数,而是通常有成百上千个参数时,现实不是更复杂吗?不,不是真的。事实上,将上一节描述的方法从一个维度推广到任意多个维度几乎是令人惊讶的容易。
让我们从一维到二维开始。那相当于从单参数函数 f ( x )到双参数函数 f ( x , y )。就像 f ( x )的图是二维的(一维为输入 x ,一维为输出 f ( x )),而 f ( x , y )的图是三维的(两个输入+一个输出)。你可以把它想象成一幅风景,把 f ( x , y )想象成一幅高度图。
“风景”由一个二维函数 f(x,y)定义。(来源:作者)
我们正在尝试做和我们之前在一维中做的一样的事情,也就是找到一个局部最优。假设我们正在寻找一个局部最小值。我们在一维情况下的逻辑仍然完全适用:为了接近下一个局部最小值,应该走下坡路。但为此我们需要知道斜率。我们如何计算二维的斜率?
比如在 x ₀ x =-0.5 处平行于y*-轴的直线,可以看做常数为 x =-0.5 的函数y₀g(y)=f(-0.5, y )。这意味着在任意点( x ,y),我们可以将二维函数分割成两个一维函数。我们已经知道如何得到一个一维函数的斜率!我们简单地计算它的导数。*
**
在点(-0.5,0.5)垂直穿过 f(x,y)-风景,平行于 x 轴(左),平行于 y 轴(右)。(来源:作者)
但是首先,我们必须稍微改进一下我们的符号。既然有不止一个变量,符号 f 变得模糊不清,因为不清楚导数是关于 x 还是 y 。为了消除歧义,有一个更通用的符号。表示相对于 x 的导数
相对于 y 的导数为
符号 ∂有很多名字,比如“die”、“doh”或者——我最喜欢的——“dabba”,等等。但由于它是一个程式化的字母 d,你可以简单地把它读作“dee ”,而关于 x 的导数读作“dee eff dee ex”。如果你不习惯多元微积分,你可能会对一个分数突然被用来概括一个简单的质数符号感到困惑。这是很自然的,因为正如我们在上一节看到的,导数是的一个分数:
在极限过程的框架中,您可以将分子 ∂f 解释为 f 的差,将分母 ∂x 解释为 x 的差。
确定了符号之后,我们如何将两个 1-D 导数组合回一个二维实体,这样我们就可以知道在哪个方向改变我们的参数( x , y )?
这是微积分的伟大奇迹之一,只要你做足够小的步骤,你甚至不需要把它们结合起来。如果你沿着 y 方向迈出一小步,就像在一维情况下一样,也就是说,
在 x 方向上的另一小步,同样,就像在一维空间中一样,也就是说,
你已经有效地向正确的方向做了一个二维移动,直接向最小值移动。就步长而言,什么样的足够小*?严格来说,只有当步长是数学家所说的无穷小,即无限小时,两个一维步长才与一个二维步长相同。然而,我们在这里非常安全,因为忽略有限步长的 x -和 y 维度的相互作用所产生的误差随着步长的增大而增大。这意味着当你增加步长时,你会在混合维误差变得显著之前很久就感觉到来自单参数导数的误差(因为前者是𝒪( ɛ 的量级,而后者是𝒪( ɛ 的量级,并且 ɛ 很小)。*
当然,有一种更好、更简洁的方式来表达你实际上在为每个维度做同样的事情。首先,您可以定义 x 和 y 的简写:
第二,函数的所有 1-D 导数的集合,梯度由 ∇ f 表示,在 2-D 中定义为**
因此,您可以将两个一维优化步骤写成一个二维步骤:
既然我们已经看到了如何将一个二维问题完美地分解成两个一维问题,那么还有什么能阻止我们进入三维、42 维或任何其他可以想象的维数呢?什么都不会!
考虑任意正整数维度 N. 再次使用变量的简写
N 维的斜率可以写成 N 一维斜率的组合:
此外,以这种方式编写,在 N -D 中的优化步骤看起来与在 2d 中完全一样:
在这一点上,也许你认为计算高维导数的机制并不困难,毕竟,但是你仍然不太适应在 N 维空间中思考。如果是这样,不要担心,你在好公司!就像艾的元老之一 Geoffry Hinton 建议的那样:
为了处理 14 维空间中的超平面,想象一个 3 维空间并大声对自己说 14。每个人都这样做。
Geoffry Hinton(在他存档的 Coursera MOOC,讲座 2c:认知的几何观点),大约 1:00 分钟)
为了理解关于梯度的一切,你总是可以求助于像我们上面的例子中那样的三维景观,梯度下降就是沿着这种景观的山丘走下去。如果你甚至在 3d 中仍然为可视化梯度下降而挣扎,来自losslandcape.com的人们为你制作了一个美丽的动画(带有俗气的画外音)。
区分一些代码
现在我们已经谈了很多关于一维或多维数学函数的导数。但是一段计算机代码的导数是什么呢?让我们看看一些具体的编程语言,计算一些实际的代码导数。接下来,你要么应该熟悉初等函数的导数,比如 x、sin(x)和 exp(x),要么手边有参考文献。
例如,考虑用 Python 实现的这个简单函数:
*def f(x: float) -> float:
return 3.0 * x*
该函数实现了数学函数f*(x)= 3x。在微积分课上,计算它的导数是最简单的任务:f’(x)= 3。那么,在 Python 中,导数的最佳可能实现是什么样的呢?这个怎么样:*
*def fprime(x: float) -> float:
return 3.0*
这可以被公正地称为可能的最佳实现。它计算机器精度的导数值。人们甚至可以说,这个导数实际上是精确的*,并且只有它在给定的 x 处的评估引入了机器精度的近似值。*
让我们看看另一个例子,这次是在 Scala 中:
*def g(x: Double): Double =
math.sin(x)*
再次考虑这里实现的数学函数:g(x)= sin(x)。这个重要但初等的函数的导数简单来说就是g*'(x)= cos(x)。所以我们的 Scala 函数 g(x: Double): Double 的导数应该是这样的:*
*def gprime(x: Double): Double =
math.cos(x)*
这是最后一个例子,这次是用 C 语言,以确保我们理解正确:
*float h(float x) {
return exp(x) + 1.0/x;
}*
*我们需要一个函数 **float hprime(float x)。*会是什么样子?再次从代码中实现的实际数学函数开始
应用基本的微分法则,我们得到
这可以很容易地在 C 中再次实现!
*float hprime(float x) {
return exp(x) - 1.0/powf(x, 2);
}*
很简单,实现一个数学函数的代码的导数就是这个函数的导数的实现。
复杂的函数不过是简单函数的链
到目前为止,还不需要自动化。上一节示例中的导数可以简单地手工实现。但是更复杂的函数呢?每一个函数,无论多么复杂,都是由简单的运算组成的。为了说明如何从简单到复杂,让我们从
函数 h(x )可以看作是两个函数后续应用的结果
从这里可以看出:
通过将一个函数的结果插入到另一个函数中来创建新函数被称为函数组合*。有一个特殊的符号可以让你避免迷失在所有这些括号中:*
让我们更进一步,将 h ( x )插入另一个函数
结果将会是
当然,我们可以无限期地继续这个游戏,组合越来越多的功能:
有趣的是,函数可以由初等函数组成,这一事实也允许我们由这些初等函数的导数组成它的导数。你可能记得这是高中微积分的另一个概念,叫做 链式法则 :
如果 g ( x )本身是一个复合,链规则可以递归应用,以区分任意长的复合链。
因此,只要我们知道如何区分相对较小的一组初等函数,如 sin( x )、exp( x )、log( x )和 xⁿ ,以及基本运算,如函数的和与积,链式法则为我们提供了计算任何函数的导数的简单方法,无论它有多复杂。
*你现在可以用这个方法手动计算任何函数的导数,比如在一张纸上,然后用代码实现结果。从数学上来说,这种方法没有错。然而,实际上,即使你只有一个中等复杂的函数,例如,几十个因子的乘积,每个因子都由几个连锁的初等函数组成,这个过程也会变得冗长而容易出错。对于严肃的应用程序,例如,由成千上万个基本操作组成的 DNN 的训练,手工方法将是荒谬的。这回避了一个老问题,当面对大量繁琐的工作时,这个问题总是会出现:别人不能做吗?
是的,电脑可以!要让计算机区分任何可微分的函数,我们只需教会它如何区分简单的运算和链式法则——就大功告成了!*
链式法则的应用是一个纯粹的机械过程,我们可以很容易地将其转化为算法并交给计算机。这就是自动差异化背后的理念。它可以通过多种方式实现,例如使用预处理器生成微分函数的实际代码,就像我们在上面的例子中手动完成的一样。更常见的方法是在运行时观察你的程序,在所谓的磁带上记录基本操作的序列(或者说图形),然后动态地计算磁带代码的导数。
结论
今天的博文到此结束。我们已经了解了软件 2.0 的概念及其当前最重要的化身,差异化编程。在刷新了我们的高中微积分知识之后,我们已经看到了如何利用导数来针对得分函数进行迭代优化,也就是说,我们已经了解了梯度下降的本质。看例子,我们已经看到实现数学函数的代码的导数是所述函数的导数的实现。最后,我们展示了如何使用链式法则将任意函数的微分转化为纯机械过程,为自动微分开辟了道路。我希望你喜欢这篇博文,甚至可能学到一些新东西。
在后续的文章中,我们将更深入地探究可微分编程的算法细节,并关注以下几点:
- 自动微分(AD)如何工作
- 什么是正向模式和反向模式(反向传播)自动区分(AD)
- 为什么梯度下降需要反模式广告
- 如何计算 for 循环、条件和其他控制结构的导数
- 除了机器学习之外,还有什么可区分的编程可以使用
与此同时,您可能希望查看以下精彩的演示,以进一步深入了解差异化编程的世界:
- Ryan P. Adams,你应该用自动微分,2016
- Matthew J. Johnson,自动微分,深度学习暑期学校 Montreal 2017
- 诺尔·威尔士,可微函数编程,Scala Days 2018
- Viral B. Shah,可微分编程——深度神经网络的一个令人兴奋的概括,PyData Delhi 2019
最后但同样重要的是,如果你想深入了解广告背后的数学,那么我有一个特别的奖励给你:
- Conal Elliott,自动微分的简单本质,微软研究院 Talk (2018)
原载于 2020 年 5 月 11 日https://consilica . de*。*
LDA 和 TF-IDF 在文本分类中具有更高的准确率和更少的处理时间
帕特里克·托马索在 Unsplash 上的照片
文本分类中特征选择方法的实现
变量或特征的大小被称为数据集的维度。在文本分类方法上,特征的大小可以列举很多。在这篇文章中,我们将使用线性判别分析-LDA 实现 tf-idf 分解降维技术。
我们在这项研究中的途径:
1.正在准备数据集
2.将文本转换为特征向量
3.应用过滤方法
4.应用线性判别分析
5.构建随机森林分类器
6.结果比较
所有的源代码和笔记本都已经上传到这个 Github 仓库。
问题定式化
提高文本分类的准确性和减少处理时间。
数据探索
我们使用来自 Kaggle 数据集的“欧洲 515,000 酒店评论数据”。这些数据是从 Booking.com 搜集来的。文件中的所有数据对每个人都是公开的。数据最初归 Booking.com 所有,你可以通过 Kaggle 上的这个简介下载。我们需要的数据集包含 515,000 条正面和负面评论。
导入库
我们用过的最重要的库是 Scikit-Learn 和 pandas。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import requests
import jsonfrom sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import VarianceThreshold
from sklearn.metrics import accuracy_score, roc_auc_score
from sklearn.preprocessing import StandardScaler
from nltk.stem.snowball import SnowballStemmer
from string import punctuation
from textblob import TextBlob
import re
正在准备数据集
我们将只研究两类,积极的和消极的。因此,我们为每个类别选择 5000 行,并将它们复制到 Pandas 数据帧中(每个部分 5000 行)。我们在这个项目中使用了 Kaggle 的笔记本,因此数据集被加载为本地文件。如果您正在使用其他工具或作为脚本运行,您可以下载它。让我们看一下数据集:
fields = ['Positive_Review', 'Negative_Review']
df = pd.read_csv(
'../input/515k-hotel-reviews-data-in-europe/Hotel_Reviews.csv',
usecols= fields, nrows=5000)df.head()
使用 NLTK SnowballStemmer 对单词进行词干分析:
stemmer = SnowballStemmer('english')
df['Positive_Review'] = df['Positive_Review'].apply(
lambda x:' '.join([stemmer.stem(y) for y in x.split()]))df['Negative_Review'] = df['Negative_Review'].apply(
lambda x: ' '.join([stemmer.stem(y) for y in x.split()]))
删除停用词:
用countwordsfree.com列表理解和 pandas.DataFrame.apply 排除停用词
url = "[https://countwordsfree.com/stopwords/english/json](https://countwordsfree.com/stopwords/english/json)"
response = pd.DataFrame(data = json.loads(requests.get(url).text))
SW = list(response['words'])df['Positive_Review'] = df['Positive_Review'].apply(
lambda x: ' '.join([word for word in x.split() if word not in (SW)]))df['Negative_Review'] = df['Negative_Review'].apply(
lambda x: ' '.join([word for word in x.split() if word not in (SW)]))
移除数字并初始化数据集:
df_Positive = df['Positive_Review'].copy()
df_Positive = df_Positive.str.replace('\d+', '')df_Negative = df['Negative_Review'].copy()
df_Negative = df_Negative.str.replace('\d+', '')
将文本转换为特征向量
单词包和 TF-IDF 是用于检测文档主题的两种方法。它们之间的区别是,BoW 使用一个词在文档中出现的次数作为度量,而 TF-IDF 在检测主题时给每个词一个权重。换句话说,在 TF-IDF 中,使用单词分数而不是单词计数,因此我们可以说 TF-IDF 测量相关性,而不是频率。
在这一部分,我们为每一列使用了 Scikit-Learn TfidfVectorizer,并为矢量化构建了一个 N 元模型,该模型可用作估计器的输入。然后,我们添加一个目标列,对于正面评价,给定值为“1”,对于负面评价,给定值为“0”。注意,我们定义了“min_df=2”。
tfidf = TfidfVectorizer(min_df=2,max_df=0.5, ngram_range=(1,3))
features = tfidf.fit_transform(df_Positive)df_Positive = pd.DataFrame(
features.todense(),
columns=tfidf.get_feature_names()
)df_Positive['Target'] = '1'
df_Positive.head()
如您所见,结果显示了 7,934 个特征,这是一个很大的数字,在目标列中有值“1”。
对于负面评价,我们也会这样做:
tfidf = TfidfVectorizer(min_df=2,max_df=.05, ngram_range=(1,3))
features = tfidf.fit_transform(df_Negative)df_Negative = pd.DataFrame(
features.todense(),
columns=tfidf.get_feature_names()
)df_Negative['Target'] = '0'
df_Negative.head()
有 6,754 个特征,负面评价的目标值为“0”。现在我们将通过追加一个到另一个来合并这两个数据集。共同特征将被认为是一个,但目标是不同的。
df = df_Positive.append(df_Negative)
df.shape
#out[] (10000, 12676)
因此,最终数据集有 10,000 个实例(每个实例有 5,000 个实例)和 12,676 个要素,这意味着2,012 要素是相互的((7934+6754)-12676)。
#change the value of NaN to Zero
df = df.fillna(0)
定义训练/测试分割:
#define x and y:
x = df.drop('Target',axis=1)
y = df['Target']x.shape, y.shape
#out[] ((10000, 12675), (10000,))#define train-test-slpit:
x_train, x_test, y_train, y_test = train_test_split(
x, y, test_size = 0.2, random_state = 0, stratify = y)
应用过滤方法-移除常量要素
常量要素是数据集中所有输出仅包含一个值的要素。所以他们不能给我们任何有价值的信息来帮助分类器。因此,最好将它们移除。
constant_filter = VarianceThreshold(threshold = 0.0002)
constant_filter.fit(x_train)
feature_list = x_train[x_train.columns[
constant_filter.get_support(indices=True)]]print('Number of selected features: ' ,len(list(feature_list)),'\n')
print('List of selected features: \n' ,list(feature_list))
您可以看到所选功能的列表。它显示了之前被词干化的 716 个单词的数量。这个列表可以帮助我们通过分析列表及其项目与我们的主题(正面和负面评论)的联系来分析我们输出的质量。
x_train_filter = constant_filter.transform(x_train)
x_test_filter = constant_filter.transform(x_test)x_train_filter.shape, x_test_filter.shape, x_train.shape
#out[] ((8000, 716), (2000, 716), (8000, 12675))
因此,结果显示,94.35%的特征是不变的,而模型丢弃了它们。因此,我们删除了 11,959 个特征,这是一个相当大的数字。所以我们必须定义一个新的训练,测试数据帧:
x_train_filter = pd.DataFrame(x_train_filter)
x_test_filter = pd.DataFrame(x_test_filter)
应用过滤方法-移除相关要素
相关特征是在线性空间中彼此接近的特征。移除它们的函数写在下面。
def get_correlation(data, threshold):
corr_col = set()
cormat = data.corr()
for i in range(len(cormat.columns)):
for j in range(i):
if abs(cormat.iloc[i,j]) > threshold:
colname = cormat.columns[i]
corr_col.add(colname)
return corr_colcorr_features = get_correlation(x_train_filter, 0.70)
然后,在移除相关特征之后,我们定义新的数据帧。结果显示我们去除了 23 个相关特征。
x_train_uncorr = x_train_filter.drop(labels= corr_features, axis = 1)
x_test_uncorr = x_test_filter.drop(labels= corr_features, axis = 1)
x_train_uncorr = pd.DataFrame(x_train_uncorr)
x_test_uncorr = pd.DataFrame(x_test_uncorr)
x_train_uncorr.shape, x_test_uncorr.shapeout[] ((8000, 693), (2000, 693), (8000, 716))
应用线性判别分析— LDA
伊万·弗拉尼奇在 Unsplash 上的照片
现在,我们准备在数据集上建立 LDA 模型,进行特征选择,然后在其上运行随机森林分类器。
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDAlda = LDA(n_components=1)
x_train_lda = lda.fit_transform(x_train_uncorr, y_train)
x_test_lda = lda.fit_transform(x_test_uncorr, y_test)
构建随机森林分类器(RFC)
它是一种元估计器,将多个决策树分类器拟合到数据集的各个子样本上,并使用平均来提高预测精度和控制过拟合。
def runRandomForest(x_train, x_test, y_train, y_test):
clf = RandomForestClassifier(n_estimators=100, random_state=0, n_jobs=-1)
clf.fit(x_train, y_train)
y_pred = clf.predict(x_test)
print ('accracy is: ', accuracy_score(y_test, y_pred))
使用 LDA 模型运行随机森林分类器:
#Run calssifier **using** LDA model
%%time
runRandomForest(x_train_lda, x_test_lda, y_train, y_test)
LDA 模型的准确度为 97.95%,壁时间约为 709 毫秒。在非 LDA 模型中,结果仍可接受,这是因为 tf-idf 矢量化效果很好。但是正如你在墙下面看到的,时间是 14 秒,比 LDA 模型慢 19.74 倍。
##Run calssifier **without** using LDA model
%%time
runRandomForest(x_train, x_test, y_train, y_test)
所有的源代码和笔记本都已经上传到这个 Github 库中。我期待听到任何反馈。联系我。
此外,你可以在这里阅读更多关于 NLP“文本分类:来自 5 个 Kaggle 竞赛的所有提示和技巧”。
高阶数值微分方程(Python)
这篇文章展示了如何在 python 中使用高阶方法求解微分方程,以最小化截断误差并更快地收敛。
根据题目的性质,需要对微积分和基本编程有所了解。
进口
安装来自 https://www.anaconda.com/distribution/的巨蟒
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # For 3D Plotting of Systems
遵守代码
我鼓励你在 Google colab 上试验一下代码,链接是这里或者https://colab . research . Google . com/drive/14kt 0 slgfphrf _ qel 8 E3 by 7 tfny 0x kzq 5
背景
提供一些背景知识,说明为什么我们关心截断误差,以及为什么我们需要使用高阶方法来实现更低的截断误差
基本泰勒展开式
如果你对泰勒展开式感到困惑,我推荐 3blue1brown 关于这个主题的视频
什么是截断误差?
从微积分我们知道截断误差是泰勒级数的下一项,展开式的第(n+1)项。也就是说,它们是作为部分和逼近一个无穷和的误差。
就计算机而言,有一个术语叫做机器ε或双精度。超过这个精度,计算机就无法区分两个数字。这是机器ε的截断误差,虽然在数学中不被认为是精确的结果,仍然是近似值,但在科学计算中被认为是精确的。
机器 Epsilon
欧拉法
在上式中,h 或 dx 是时间步长。该方程的截断误差为 O(h ),这意味着要将误差从 e-8 减小到 e-10,新的时间步长必须比旧的时间步长小 e-2。这使得欧拉方法的精度增加极其缓慢。
动机
为什么收敛速度很重要?
现在有人可能会问,为什么收敛速度很重要。除了更高的收敛速度会减少大型计算的等待时间这一事实之外,还有另一个原因。原因是我们面临的另一个误差,叫做舍入误差。
舍入误差、【1】也称为舍入误差、【2】是给定算法使用精确算法产生的结果与相同算法使用有限精度舍入算法产生的结果之间的差异。
这实质上意味着我们做的每一个计算,每一个时间步,都会有一点点误差。时间步长越多,我们执行的计算越多,舍入误差就越大。存在一个舍入误差将超过截断误差的点,执行更多的计算将使结果值不准确。
上面的例子突出了两种不同近似的截断误差和舍入误差,一种用紫色表示截断误差~h,另一种用黄色表示截断误差~h⁴。
低阶方法的问题(欧拉方法)
请注意,在上图中,截断误差为 2 ~h 阶的紫色图(类似于欧拉法)比高阶的黄色图精度低得多(截断误差更高)。
这是因为误差仅以二次方式缩放,也就是说,如果将时间减少一半,误差会减少四分之一。而 4 阶的高阶方法,同样将时间步长减少一半,所得误差将减少十六分之一。
寻找高阶方法
这种方法适用于任何订单;然而,在本帖中,我们将重点关注 4 阶方法,特别是 RK4。
如果我们将泰勒展开式扩展到我们所希望的阶,我们将得到高阶方法。
然而,通常很难对微分方程进行微分以得到 d/dx(f(x)),但是不同的数学家发现了不同的四阶方法,本文将重点介绍的一种方法是由 Runge 发现的,它被称为 RK4。
RK4 方法
RK4 坡度估计值/权重
该函数具有截断误差~O(h⁴,这意味着从 e-8 移动到 e-10,时间步长的差异将是∜(e-2,这将使计算量低得多。
在这篇文章中,我不会太深入地研究数学,因为我相信在计算机科学中有很多实际的应用可以在不深入理解基础数学的情况下实现。我链接了下面的资源来帮助更好地理解数学。
解微分方程
最后,有趣的部分开始了,所以我们必须选择我们要解决的微分方程系统。我将展示一个更复杂的微分方程系统的例子,因为这将涵盖解决更简单的系统所需的技能。
我们今天要求解的系统是洛伦兹系统,更普遍的说法是蝴蝶效应。
常量的值
https://gist . github . com/cryogenic planet/04f 4f 580581488516662795373 e5d 859
上面的代码片段执行单个时间步长的操作,即 dt 以向量的形式在[dx,dy,dz]中移动。把它看作一个向量运算会更容易理解,这就是 NumPy 的亮点,它允许你把这个时间步长作为一个向量函数来求解。
上面的函数是一个通用的 rk4,时间步长,它对于高效求解高阶微分方程是必不可少的,然而,为了求解 Lorenz 系统,我们需要设置一些其他函数来使用这个公式。
首先,让我们用洛伦兹系统的常数建立函数 dx,dy,dz
# Constants of the Lorenz System
b = 8/3
s = 10
r = 28# Functions dx,dy,dz of the Lorenz Systemdef dx(t,x,y,z):
return s*(y-x)def dy(t,x,y,z):
return x*(r-z) -ydef dz(t,x,y,z):
return x*y - b*z
现在做一个函数来计算洛伦兹系统的点
https://gist . github . com/cryogenic planet/e 07988808d 14 be 57334 C1 ef 6d 8112 e 09
最后,我们可以从退出部分开始,图形化和可视化数据。
以 3D 方式可视化数据
这里我们将使用我们之前导入的 Axes3D 模块。
#Calling the previous function arbitrary start pointsx,y,z = lorenz(0,1,1.05,0,0.01)
fig = plt.figure(figsize=(12,10))# This is how we set the 3D plot
ax = fig.gca(projection='3d')# Plotting the values
ax.plot(x, y, z, lw=0.5,alpha=0.7)
# Plotting the final values
ax.scatter(x[-1],y[-1],z[-1],color=(1,0,0))#Very slightly different starting values
x_1,y_1,z_1 = lorenz(0,0.9,1.04,0,0.01)#Plotting slightly different starting values
ax.scatter(x_1[-1],y_1[-1],z_1[-1],color=(0,0,0))#Setting Axis Titles
ax.set_xlabel("X Axis")
ax.set_ylabel("Y Axis")
ax.set_zlabel("Z Axis")
ax.set_title("Lorenz Attractor")
上面函数调用的情节
这凸显了洛伦兹系统固有的混沌现象,即略微不同的起始值会产生截然不同的终点。同样,这篇文章不是关于洛伦兹系统的资源,你可以在这里了解更多https://en.wikipedia.org/wiki/Lorenz_system
概述
- 创建你的微分方程作为函数
- 用 RK4 作为向量求解微分方程组
- 创建 rk4 中所有点的列表
- 使用 Axis3D 和 matplotlib 绘制 3D 点
再一次,我强烈建议您亲自尝试一下这些代码,您可以登录https://colab . research . Google . com/drive/14kt 0 slgfphrf _ qel 8 E3 by 7 tfny 0x kzq 5
用 Plotly 突出显示折线图。表达
通过在其他线条的灰色背景上突出线条来强调你的观点
与本文中的所有图片一样,图片由作者提供
用 python 的 Plotly 创建交互式图形。从一个数据框表达像一个魔咒。只需一行代码,您就可以探索数据集的基本特征。再添加几行代码,你就可以变出一个非常奇特但非常有故事性的图表。
在本练习中,我将向您展示在并发事件的阴影进度顶部绘制一条粗线的过程。它有两个巨大的好处:
- 您想要突出显示的趋势清晰可见
- 灰色背景表示其他事件的分布
你可以用储存在 Github 上的笔记本和我一起创建所有的图表。在本文中,您将了解到:
- 如何轻松安装
- 如何使用
px.line(df, parameteres)
创建线图 - 如何使用
fig.update_traces
或color_discrete_map
给的一些线条上色 - 行的顺序很重要
- 如何在 Plotly 图表上定位注释
- 如何使用注释来标记、突出显示、创建图例或描述图表区域
- 如何添加交互按钮
- 如何用这种图表来展示排名的变化
数据集
我将使用两个数据集。第一个是关于世界各地旅游业的进展(游客人数,1995 年至 2018 年 215 个国家),第二个显示了过去 6 年冰球国家队的排名。
数据集在 github 上的 preprocess.ipynb notebook 中进行预处理,在 python 的 pickle 中存储。
装置
普洛特利。Express 是在版本 4.0.0 的 plotly 库中引入的,您可以使用以下命令轻松安装它:
# pip
pip install plotly# anaconda
conda install -c anaconda plotly
Plotly Express 还要求安装 pandas,否则当你尝试导入时会得到这个错误。
[In]: import plotly.express as px
[Out]: **ImportError**: Plotly express requires pandas to be installed.
如果您想在 Jupyter 笔记本中使用 plotly,还有其他要求。对于 Jupyter 实验室你需要[jupyterlab-plotly](https://plotly.com/python/getting-started/#jupyterlab-support-python-35)
。在普通笔记本上,我必须安装nbformat
( conda install -c anaconda nbformat
)
一个数据集和 70 多个图表。交互性和动画通常只需一行代码。
towardsdatascience.com](/visualization-with-plotly-express-comprehensive-guide-eb5ee4b50b57)
带有 Plotly Express 的基本折线图
用 plotly 创建折线图再简单不过了。语法是px.line(df, parameters)
。看起来很简单,但是的参数数量是相当大的。值得注意的是。Express 喜欢长数据结构(与宽结构相反),其中每个类别和每个值都是一列。
数据的长结构。对于类别/参数的每个组合,在一行中都有值。
我将为每个国家画一个折线图,显示所有 215 个国家每年的游客数量。Plotly 可以处理,但图表不会告诉你太多信息。你可以使用右边的菜单图例来关闭/打开线路,但是它太长了,你必须滚动才能找到你的国家。当您将鼠标悬停在这些行上时,会弹出一个工具提示,提供有关数据的详细信息。
# simple line chart with Plotly Express
px.line(long_df,
x="years",
y="visitors",
color="Country Name",
title="Growth of tourism 1995-2018")
在这种人口过剩的土地上,你几乎看不到任何趋势
仅对所需的线条着色
比方说,为了你的研究或营销目的,你应该介绍日本、🇯🇵和🇹🇷.的旅游业发展所以让我们模糊其他线,给他们一个类似背景的灰色阴影,并通过着色突出日本和土耳其线。你有几个选择来这样做。
# first option is to use, .update_traces()
fig = px.line(long_df,
x="years",
y="visitors",
color="Country Name")# set color of all traces to lightgrey
fig.update_traces({"line":{"color":"lightgrey"}})# color Turkish line to blue
fig.update_traces(patch={"line":{"color":"blue", "width":5}},
selector={"legendgroup":"Turkey"})# color Japanese line to red
fig.update_traces(patch={"line":{"color":"red", "width":5}},
selector={"legendgroup":"Japan"})# remove the legend, y-axis and add a title
fig.update_layout(title="Tourism Growth in Turkey and Japan",
showlegend=False,
yaxis={"visible":False})# plot the chart
fig.show()
惊喜吧。这些线条是有颜色的,但是它们上面覆盖着灰色的线条,所以几乎看不见。
使用fig.update_traces({"line":{"color":"lightgrey"}})
将所有线条的颜色变为浅灰色。然后我们使用[.update_traces()](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html#plotly.graph_objects.Figure.update_traces)
的patch
和selector
自变量。patch
设置生产线的参数,而selector
定义这些参数应用于哪条生产线。
如果您想知道我是如何知道向字典提供哪些值的,那么{"line":{"color":"blue", "width":5}
会改变行的属性,并且legendgroup
是通过Country name
识别行的正确参数。最简单的方法是读取fig["data"]
。每个 Plotly 图表都是一个字典,当您更新这个字典时,所有参数都可以更改。
**[In]:** fig["data"]
**[Out]:** (Scattergl({
'hovertemplate': 'Country Name=Aruba<br>years=%{x}<br>visitors=%{y}<extra></extra>',
'legendgroup': 'Aruba',
'line': {'color': 'lightgrey', 'dash': 'solid'},
'mode': 'lines',
...
每一张图都是一本字典。使用
fig.to_dict()
或fig[“data”]
查看数值。
对行进行排序
但结果并不是我们想要的。我们显示日本和土耳其旅游业发展的轨迹介于两者之间。一些灰线在它们上面,一些在下面。
我们可以尝试 Plotly 的参数category_orders
来影响行的顺序,但是添加category_orders={"Country Name":["Japan","Turkey"]})
会使情况变得更糟。首先显示这些轨迹,所有灰色线都在它们上面。
Category_order 参数定义行的顺序。如果您只指定我们想要的,它们会成为第一个。其他的都在上面。
我们可以在最后提供日本和土耳其的完整国家列表,但是对数据框架本身进行排序更容易。我们.map()
向日本订购 1,向土耳其订购 2,向所有其他线路订购fillna(3)
,然后按照该值对数据帧进行排序。
# sort the dataframe
sorted_df = long_df.copy()# map the value order
sorted_df["order"] = sorted_df["Country Name"].map({"Japan": 1, "Turkey": 2}).fillna(3)# sort by this order
sorted_df.sort_values(by=["order","years"], ascending=False, inplace=True)
最晚出现的线被画在最上面。
如何给线条上色的另一个选项是为 plotly 的color_discrete_map
参数提供一个字典,而不是应用fig.update_traces()
。dict 结构是{trace_name: color}
。
{'Aruba': 'lightgrey',
'Zimbabwe': 'lightgrey',
...
'Turkey': 'red',
'Japan': 'blue'}
要改变宽度,可以直接操作 Plotly 的后端字典。
for i,d in enumerate(fig["data"]):
if d["legendgroup"] in ["Japan","Turkey"]:
fig["data"][i]["line"]["width"] = 5
fig.show()
请记住,所有代码,包括关于如何影响 Plotly 图表外观的各种选项,都可以在 Github 上找到。
释文
图表看起来仍然很难看。我们已经去掉了图例和轴心,我们甚至不知道有多少游客来过这些国家。为了向观众展示重要的价值,我们必须注释情节。注释是添加到.fig.update_layout(..., annotations=[])
中的另一个字典。这个注释参数包含一个字典列表,每个字典都是一个注释。
turkey_annotation = \
[{"xref":"paper", "yref":"paper", "x":0, "y":0.15,
"xanchor":'right', "yanchor":"top",
"text":'7M',
"font":dict(family='Arial', size=12, color="red"),
"showarrow":False}, ... other annotations ...]
您可以影响注释的许多参数。它的位置、字体以及是否有箭头从注释文本指向图表上的某个点。文本的坐标x
和y
既可以指plot
也可以指 paper-canvas
。在第一种情况下,使用轴上显示的值指定位置,在第二种情况下,(0,0)
是绘图区的左下角,(1,1)
是右上角。
位置还取决于anchor
(上-中-下、左-中-右)、偏移和调整。可以通过设置字体来修改每个注释,或者可以在文本上应用 HTML 标签,如<b>
或<i>
。
看看这个要点和由此产生的图,以了解您在注释时的选项。
关于如何在 Plotly 中定位注释的各种选项。
如果您的注释不适合画布,您可以通过在.update_layout()
内放置margin={"l": pixels, "r": px, "t": px, "b": px}
来增加绘图周围的空间。
标注作为标签和图例
当我们对我们的旅游图表稍加研究时,我们可以取得相当好的结果。我们将xref
设置为paper
,并将0
设置为行的开始。添加xanchor="left”
将文本对齐到绘图区的左侧。您可以设置yref=”paper"
并尝试在 0 和 1 之间找到理想的位置,但是不将其设置为paper
并使用准确的位置更容易,例如3 300 000
(注意,从 python 3.6 开始,由于 PEP515 ,您可以在数字文字中使用下划线,并将百万写成3_300_000
)
因此,完整的图表如下所示:
用注释 Plotly 表示突出显示的折线图
我认为关于绘图区域之外的注释,最有趣的是你可以引用画布上的
x
和图表上的坐标y
。可以设置,"x":0 (on the canvas), "xanchor":"right
和"y": 7_000_000 on the plot, "ynachor":"middle"
。
交互式按钮
上面的图表非常令人印象深刻,不是吗,但是如果你可以添加更多的东西呢?如果您可以让用户选择突出显示他们想要的任何数据,会怎么样?这可以通过交互式按钮来实现。
通过fig.update_layout(updatemenus=[])
添加按钮。您现在可能已经习惯了这样一个事实,即每个元素都由一个 python 字典来描述,按钮也不例外。
每个按钮都有几个参数:
args
:点击按钮会发生什么args2
:取消选中时会发生什么(创建切换按钮)label
:按钮上写的是什么method
:按钮是否改变绘图、布局或两者
args
、args2
中的每一个也接受 3 个参数——轨迹变化、布局变化和受影响的轨迹列表。例如
args=[
# updates to the traces
{"line.color":["blue"],"line.width":5},
# changes to the layout
{"title":"Tourism growth in Japan",
"annotations": annotation_japan},
# which trace is affected
[1,2]
]
按钮集提供了影响其位置和样式的附加参数。与注释类似,您可以在绘图周围放置按钮。您还可以在单个按钮、一组按钮或下拉列表之间进行选择。
各种位置的 plotly 互动按钮和风格。
让我们添加按钮来打开/关闭关于日本和土耳其旅游的两个亮点。
按钮可以提高 Plotly 的交互性
Plotly Express 中的按钮不是万能的。如果您点击日本和土耳其按钮,而没有通过第二次切换-点击清除绘图,您将看到两条彩色线。我没有发现如何确保一个是染色的,而其他的都是灰色的。这样复杂的交互只有通过 Plotly 的仪表盘库才能实现——Dash。它的回调动作允许几乎所有可以想象的输出。
您可能还会注意到,如此多的行,Plotly 自动选择的 WebGL 格式被证明提高了具有许多数据点的 JavaScript 绘图的可用性。
显示排名——IIHF 排名
当我第一次遇到这种图表时,它显示了最受欢迎的国家公园的排名以及它是如何随着时间的推移而演变的。我再也找不到这个例子了,所以我决定创建一个我自己的等级演变图。我会看看过去 5 年里冰球国家队的排名。
因为最近换了 Linux,所以手动把数据收集到里。ods 电子表格。您可以使用pd.read_excel(path, engine="odf)
来收集数据,但是我必须安装pip install odfpy
来实现。
然后你重复上面的代码来显示排名的概况,并突出显示你喜欢的国家。不过,在这里我不得不处理一个新问题。我想显示标签,显示每年的排名,只有这一行突出显示(而它应该是隐藏的所有其他人)。
同样,这个问题有两个结果略有不同的解决方案。你可以使用fig.update_traces()
来设置颜色和标签。在这种情况下,您必须指定text
和mode
:
fig.update_traces(
patch={
"line":{"color":"yellow", "width":5},
"text":sweden["Ranking"].values,
"textposition":"top center",
"mode":"lines+text",
"textfont":{"size":15, "color":"blue"},
},
selector={"legendgroup":"Sweden"})
用这种方法,文本是一种丑陋的坚持行,我没有强迫它解除。当你简单地用fig.update_layout(annotations=[])
注释时,这就可以做到。迭代数据框,并准备一个包含每个注释的字典列表:
annotations = []
for index, row in sweden.iterrows():
annotations.append(
{"x": row["Year"],
"y": row["Ranking"],
"yshift": 6,
"text": row["Ranking"],
"xanchor": "center",
"yanchor": "bottom",
"showarrow":False,
"font":{"color":"blue", "size": 15}
}
)
如何突出显示和标记 plotly 的一条线的两个选项。
结论
我希望您喜欢这篇介绍 python 的 Plotly Express 的技巧的文章。您已经学习了如何创建包含大量信息的折线图,以及如何向受众突出显示这些数据的重要部分。您已经看到,实现相同目标的方法通常不止一种。最后,我们用同样的方法在灰色背景上用彩色线条来显示排名的变化。
对于这种类型的图表,您还有其他使用案例吗?
If you want to create inspiring graphics like those in this post, use [canva.com](https://partner.canva.com/vdek) (affiliate link, when you click on it and purchase a product, you won't pay more, but I can receive a small reward; you can always write canva.com to your browser to avoid this). Canva offer some free templates and graphics too.Other articles:* [Plotly Histogram - Complete Guide](/histograms-with-plotly-express-complete-guide-d483656c5ad7)
* [Everything you wanted to know about Kfold train-test split](/complete-guide-to-pythons-cross-validation-with-examples-a9676b5cac12)
* [How to turn a list of addreses into a map](/pythons-geocoding-convert-a-list-of-addresses-into-a-map-f522ef513fd6)
所有练习都可以在 Github 上的笔记本中完成—highlight _ Line _ Chart _ on _ Grey _ Lines _ Background