TowardsDataScience-博客中文翻译-2020-一百零四-
TowardsDataScience 博客中文翻译 2020(一百零四)
该不该考机器学习的博士?
探索攻读机器学习相关主题的博士学位的好处

科尔·凯斯特在 Unsplash 上的照片
你点击这篇文章可能有几个原因;也许你正在辩论是否要进一步提高你的学术资格,或者你可能对机器学习中的高级研究的思想着迷。
不管是什么原因,你现在在这里。
现在,这里是写这篇文章的目的。围绕机器学习已经有了大量的炒作,大量的个人正涌向学术机构以获得 ML 内部的学位,包括我自己。对于你想追求什么样的高级资格,做出正确决定的重要性怎么强调都不为过。
为了让决策变得简单一点,并提供一些清晰度,我将提出一个攻读机器学习博士学位的案例,并以我个人的观点作为结论。
为了给这篇文章一个结构,我将使用下面列出的三个标准作为指导信标来讨论攻读博士学位的好处。

里士满·阿拉克的引导信标
声明:我目前的最高学历是计算机视觉和机器学习理学硕士。请注意,我将试图从一个公正的角度来看待这篇文章/研究。如果你觉得我在公正的分析上有所失误,请在评论中指出。
介绍


右图:布拉登·科拉姆在 Unsplash 上的照片。左:照片由阿尔方斯·莫拉莱斯在 Unsplash 上拍摄
如果把学术界比作体育,那么博士学位可以类似于奥林匹克,因为它们都在各自的领域产生精英。在每届奥运会之间,运动员有四年的训练期;相比之下,对于博士生来说,这种考验在英国通常持续四年,在美国则长达六年。
机器学习博士学位需要在机器学习的许多子领域中探索和推进特定的主题。在人工智能行业——也包括其他行业——博士学位被视为一项有声望的成就。
让我们使用我们的引导信标来进一步分析一个攻读机器学习博士学位的案例。
收入和职业潜力
与理学硕士同行相比,拥有博士学位的机器学习从业者有可能获得更高的薪水。

莎伦·麦卡琴在 Unsplash 上的照片
对于机器学习研究员/科学家的角色,英国****90%的 ML 研究员角色要求申请者至少拥有博士学位;有些职位要求申请者在顶级会议上发表过论文,如 NAACL 或 NeurIPS 。
拥有博士学位无疑会为更多的职位打开更多的大门。我找到的招聘职位的平均工资是 8 万英镑(99607 美元)。要成为一名 ML 研究员,你必须持有证明你有能力进行研究的资格证书。
申请机器学习工程类角色怎么样?
ML 工程职位并不完全要求高级资格,如博士学位。也就是说,当一名 ML 工程师拥有博士学位,再加上几年的机器学习工作经验,那么申请人肯定会受到高度重视。
在浏览了几个角色之后,可以肯定地说,拥有博士学位和一些工作经验的申请人可以申请大量广告中的机器学习角色。
在过去的十年里,对 ML 从业者的需求急剧增加,ML 工程师的职位发布数量在 2015 年至 2018 年间增长了 300%以上,而且似乎不会很快放缓。需求的增加意味着公司和组织(甚至政府)正在寻找高技能的个人。幸运的是,拥有博士学位可以把你放在一个被认为是高质量的个人或特定领域专家的小组中。

雇佣机器学习领域顶尖人才的公司
人工智能领域的顶级公司,如 DeepMind 、 OpenAI 、 Google 、脸书等对机器学习研究人员的需求很高。这些公司本质上是人工智能行业的先驱。例如, Deepmind (负责 AlphaGo 的公司),有几个研究科学家的职位,最低要求的资格是博士。
在结束收入部分之前,我将提到最后一件关于博士学位获得者收入潜力的事情。大多数招聘职位的工资都有一个范围,例如,一个 ML 工程师的招聘职位的工资范围是 70,000 到 90,000。对高端职位申请的考虑是由经验、文化契合度、工作要求契合度以及资格等因素决定的。众所周知,PgD 患者的收入比 MSc 患者高 50%;这是几个行业的真实情况,不仅仅是人工智能。
影响

Clark Tibbs 在 Unsplash 上拍摄的照片
攻读博士学位的机会也提供了创造技术和社会影响的可能性。机器学习博士学位将你置于学术研究的前沿,促进特定领域的发展,这些领域有可能将人类进一步推向所有人的美好未来。
博士学位持有者在博士期间或之后发表的研究成果已经影响了全球的各个行业。物体检测的进步使得自主车辆中的视觉系统更好。自然语言处理的进步已经支持了高效和准确的语言到语言的翻译(想想谷歌翻译)。
我们提几个名字怎么样?

左:约瑟夫·切特·雷德蒙,中:安德烈·卡帕西,右:伊恩·古德菲勒
我相信你一定听说过这个名字伊恩·古德菲勒,如果你没有听说过,他是负责生成性敌对网络的个人之一。伊恩目前是苹果公司的机器学习总监。他拥有博士学位,曾在谷歌和 OpenAI 等公司工作过。
另一个熟悉的名字是 Andrej Karpathy,他目前是特斯拉的人工智能总监,之前曾在 DeepMind 和谷歌实习。我读过他的几篇博客文章,这里有一篇文章,可能与即将攻读博士学位的人有关。
《YOLO》的创作者约瑟夫·切特·雷德蒙也在华盛顿大学获得了博士学位。
毫无疑问,博士从事的工作可以彻底改变整个行业以及人工智能作为一个领域的发展方向。还有成吨的名字我没有提到,但我也不想把这篇文章写得有几万字那么长。
我的观点是,很多人都有可能基于他们在研究期间完成的工作或他们从研究中获得的技能,对技术、学术和社会产生影响。
知识
攻读机器学习博士学位可以获得丰富的知识。理论知识是在博士期间积累的,因为研究人员必须理解开发的技术和提出的算法中潜在的直觉、概念和逻辑。
深入的理论知识需要时间和奉献精神,只有基于博士的教育或研究形式才能允许。

帕特里克·托马索在 Unsplash 上的照片
撰写论文的研究人员必须参考和评估数十篇其他研究论文,才能得出他们当前论文的结果。仅仅从撰写研究论文中获得的知识量就足以让一个人成为各自领域的专家。
从攻读博士学位中获得的另一种形式的知识是编程、数学和技术。机器学习是一个高度专业化的领域,该领域要求的高技术要求意味着研究人员通常不仅仅是精通一套编程语言的数学高级主题,而是能够帮助实现神经网络。
在我的研究过程中,我偶然发现了一份由来自英国和美国顶尖大学的研究人员撰写的论文清单。简单浏览一下主题,并随意钻研这些丰富的知识。
不足之处

aaron Blanco Tejedor 在 Unsplash 上拍摄的照片
我在这篇文章中提到了攻读机器学习博士学位的许多好处,但我很可能错过了一些关键优势。
也就是说,至少简要强调一下攻读博士学位的一些缺点是不公平的。
我不会对缺点做过多的阐述,但是我会为好奇的个人提供足够的信息,让他们对提到的缺点进行个人研究。
- 博士学位通常需要独立的学习和工作。当然,一个学生配有一两个导师,但对许多人来说,4 到 6 年的紧张学习考验会对心理健康造成损害。
- 尽管博士生的学术发展势头强劲,但商业经验也是一种不言而喻的权衡。在攻读博士学位的 4-6 年里,与机器学习相关的行业进展如此之快,以至于几乎不可能跟上该行业的工作经验需求。
- 博士论文非常专注于机器学习中的特定子部分或主题。这意味着,尽管博士生可能是某个特定主题的专家,但他们可能缺乏更广泛的 ML 商业领域的知识。
最后的想法
让我以我个人对攻读机器学习博士学位的看法来结束这篇文章。
追求高级资格是一个个人决定,需要考虑几个因素,如家庭、资金、时间和承诺。不是很多人都有机会留下或回到广泛的学术生涯。
攻读博士学位需要特定的个性和心态;已经从事个人研究并超越机器学习主题中常规知识的个人可能更适合攻读博士。
相比之下,一些人不关心神经网络架构或对象检测算法背后的内部工作和理论推理,但他们关心技术的直接可用性和实用性。这种类型的人可能不适合博士学位带来的学术生活和责任。

Alex bljan 在 Unsplash 上拍摄的照片
我不认为我会很快攻读博士学位。尽管这可能会在未来 15-20 年内改变。
这让我想到另一点,学习不需要停止。
20 多岁、30 多岁、60 多岁都可以读博。
我希望你能从这篇相当长的文章中获得一些有用的见解。对于那些在未来几个月或几年要做出关键决定的人,我建议进行深入研究,看看你的博士生生活会是什么样子。
感谢阅读。
请随意查看一篇文章,在这篇文章中,我提出了获得机器学习硕士学位的理由。
包含来自理学硕士毕业生的想法和意见
towardsdatascience.com](/should-you-take-a-masters-msc-in-machine-learning-c01336120466)
希望这篇文章对你有用。
要联系我或找到更多类似本文的内容,请执行以下操作:
- 订阅我的 YouTube 频道 即将上线的视频内容 这里
- 跟我上 中
- 通过 LinkedIn 联系我
你应该参加更多的在线课程或硕士课程来提升你的数据科学工作简历吗?
办公时间
3 情景和建议

图片来自马库斯·温克勒 Unsplash
在与有抱负的数据科学家交谈时,我经常被问到:“我应该参加更多的在线课程来充实我的简历吗?”这篇文章总结了我的个人建议,以及如何在自学或接受额外教育后识别一个人何时“准备好”。
这篇文章可能对你有所帮助,如果…
在指导有抱负的数据科学家的过程中,以及与当前数据科学从业者(工业界和学术界)的交谈中,一个常见的问题是如何才能最好地从 Coursera、Udacity 或 edX 等在线平台自学机器学习。
作为一个附加层,那些确实使用这些平台进行自学的人,在完成一两门在线课程后会遇到一个决策点:“我应该参加更多的课程,还是这样就够了?”一个类似且常见的问题是“我是否应该获得数据科学/ CS /统计学硕士学位?”
最后一个共同点是,即使在参加了在线课程和自学之后,很多内容似乎也会像大学期中考试一样很快被遗忘。我也遇到过这种情况:“我不是刚上了 CNN 的那个 Coursera 课程吗?这个(概念)听起来很耳熟,但我怎么已经忘记细节了?”总的来说,这是一个可怕的认识,但是想象一下如果你在一个工作面试中!
如果以上任何一种情况引起你的共鸣,希望这篇文章能有所帮助。根据多年的个人经验,我分享一些可以帮助你确定什么时候你可以停止在线课程并知道你已经“准备好”了。
经验法则:边际收益递减
这条规则适用于在线课程的自我教育,或其他正规教育,如获得硕士学位。
边际收益递减是经济学中的一个概念:想象一家全新的餐厅准备开业。他们刚刚花钱买了一个全新的厨房。如果没有厨师,他们就没有产出,也就没有顾客或回报,不管他们的厨房有多棒。当他们雇佣第一个厨师时,产量和回报增加了很多,因为他们从服务零顾客到能够服务他们的顾客。
然后,餐馆变得更受欢迎,一个厨师无法处理更多的订单。雇佣了第二个厨师。这增加了产出和回报。然而,一旦过了某个点,也许当他们有 3 个厨师时,雇佣更多的厨师不会进一步增加回报。厨房可能会变得太拥挤,使每个厨师的产量减少!在这一点上,餐馆不应该雇用更多的厨师,而是在其他方面进行扩张,例如将厨房变得更大。
这个类比适用于在线课程和附加教育。如果你什么都没有,上一两门在线课程会有非常高的边际收益。过了某一点,你需要考虑以其他方式扩展你的技能,比如做一个副业——类似于餐馆例子中的扩大厨房,而不是雇佣更多的厨师。
你为什么要上在线课程呢?
现在我已经完成了一般的经验法则,我想帮助你把这个逻辑应用到你自己独特的情况中。由于有许多类型的人希望提高他们在数据科学领域的技能和可信度,我想给你一些工具,让你根据自己的教育背景和工作经验做出决定。下面,我列出了几个大致的人口统计数据供你参考。
我见过的最常见的原因和期望在线课程或额外教育的人群是有抱负的数据科学家。参加在线课程并获得结业证书是为了获得面试而写在简历上的东西,如果候选人能通过面试,就能在数据科学或机器学习行业找到工作。
我将把这些人分为两种类型:Type 1那些还没有任何工作经验,刚从学校或训练营毕业的人。Type 2是在其他领域(包括学术界)有工作经验的专业人士。他们希望转型或转向数据科学领域。
下一个群体,Type 3,是现有的数据科学家,他们希望扩展自己的知识或进入一个新的专业领域(例如,从 NLP 到强化学习)。
最后一种类型是那些喜欢为了乐趣而学习的人,没有任何明确的理由。他们不认为在线课程是去其他地方的一种方式,而仅仅是娱乐或精神满足。如果这是你,那么你应该忠于自己,继续参加在线课程,只要你觉得有趣!
所有类型的人都有一些共同点:他们有一个目前的位置,和一个他们未来想去的目标(数据科学/ML 工作或晋升)。他们希望在线课程可以填补空白,将他们从 A 点带到 b 点。
三类人可以从在线课程或额外教育中受益
我们已经确定,无论你是哪种类型,你的目标是使用在线课程或额外的教育来达到 B 点,这是你的目标。
我将介绍以下 3 个例子,但我的意图是,你可以将这个逻辑应用到你的个人情况中:
- [
Type 1]“我刚从大学毕业,但我听说我需要硕士学位才能进入数据科学领域。我是应该考网络硕士还是考证书?” - [
Type 2]“我想上这门 Coursera 课程,因为我的简历上几乎没有或根本没有机器学习相关的经验。我真的需要至少一些东西来吸引招聘人员的眼球,让他们给我回电和电话面试。” - [
Type 3]“我有兴趣在我当前的数据科学团队中向上或横向移动到一个使用强化学习(RL)的项目。我如何向我的经理和同事展示我在 RL 方面有足够的技能?”
3 种类型的逐步分析
类型 1
“我刚从大学毕业,但我听说我需要硕士学位才能进入数据科学领域。我是应该考网络硕士还是考证书?”
对于这个场景,这里的目标实际上是“获得一份数据科学的工作”。自然地,如果他们成功地找到了一份数据科学的工作,那么他们不需要参加更多的在线课程/证书,甚至是硕士课程。如果你用你现在所拥有的直接到达 B 点,没有必要走弯路,弯路是那些在线课程。
当我在一次咖啡聊天中被问到这个问题时,我通常会提出以下建议:
的确,什么类型的学士学位很重要。然而,不管这个学位的正式名称是什么,更重要的是你如何展示你在的两大支柱:统计和编程中的技能。对于你的第一步,我建议根据链接文章中的信息进行自我评估,并使用在线课程或额外教育将这两个支柱提升到基线水平。
尝试申请工作(入门级)。考虑到你在 2 支柱、统计和编程方面有足够的技能,把它当作一个学士学位就足够了。你必须重复简历和面试反馈——如果你没有得到回复,更新你的简历或者检查你是如何回答面试问题的。
不要做同样的事情,却期望不同的结果。如果几个月后,这些努力仍然不能让你在数据科学领域找到工作,那么考虑攻读硕士学位。如果一个学士学位毕业后需要 6~10 个月才能找到工作,那么这比完成同样的工作需要 2 年的硕士学位要节省时间。
当然,这里的主要风险是“如果我花了 10 个月试图获得一份数据科学工作,但失败了,然后决定接受更多教育,那将使我在硕士课程/在线证书课程/训练营中落后于我的同龄人 10 个月!”
- 这里的关键是在这 10 个月里,你可以在兼职项目或其他自定进度的在线课程(heh),这可以为你建立一个文件夹,无论如何都可以帮助你找工作。无论如何,建立一个兼职项目组合是你在硕士/训练营/认证期间和之后都会做的事情,所以为什么不在找工作的时候做呢?
- 如果你遵循了上面的建议,在最坏的情况下,你没有在 10 个月内找到一份学士学位的工作,你将获得所有你的硕士同学可能没有的东西:面试经验,一个杀手级的作品集,以及更多的自我学习。我认为这让你和那些同龄人平起平坐,而不是落后。
个人轶事:有一段时间我考虑过参加 OMSCS 在线 CS 硕士学位。当时我已经是一名数据科学家,并成功地向数百万客户交付了数据科学产品。我已经获得了经济学硕士学位,完成了这个目标。结论:除非未来的职业变动(更类似于Type 3场景)需要,否则不要读计算机科学硕士。
类型 2
“我想上这门 Coursera 课程,因为我的简历上几乎没有或根本没有机器学习相关的经验。我真的需要至少一些东西来吸引招聘人员的眼球,让他们给我回电和电话面试。”
对于这个场景,请记住这个人(可能是你吗?)已经有了一些工作经验。也许他们做了 3 年的项目管理,或者 1 年的工程,或者在学术界做了 5 年的教学/研究。
这个场景的目标是“至少得到一次面试机会”。所以,在这里你能做的最简单的事情就是开始申请工作!如果你“还不确定自己是否准备好了”,那也没关系。不要拖延,直到你完成了一些神奇的在线课程。
采取与你的目标相关的直接行动,如果两三个星期后你没有收到回复,这可能表明你确实没有足够的简历项目。但是你不知道这一点,直到你申请了一些工作。不要让你自己的不确定性为招聘人员和招聘经理说话。你不是他们。至于如果你没有收到任何工作申请的回复,你可以做什么,我在下面分解了更具体的细节,因为即使在Type 2中,也有很多变化。
在这里,关于参加更多的在线课程或额外的教育,我通常会提出以下建议:
如果你真的没有机器学习/数据科学方面的简历,一定要去做!参加 Coursera 的课程,完成作业,自豪地把它们列在你的简历上。然而,现在你已经学了几门课程,并且有信心掌握了 2 支柱:统计和编程(链接文章向你展示了如何自我评估自己的准备情况)的基础知识,我强烈建议你做一个副业。使用边际收益递减的经验法则。
原因很简单,当我筛选数据科学招聘简历时,副业比证书更能吸引我的眼球。(这个建议不包括在线硕士,我在Type 1的分析中作为一个单独的问题提到过)。我不能代表所有的招聘人员/招聘经理/数据科学家同事,但我会在这里阐明我为什么相信 side projects >在线课程,假设你已经学习了 2 支柱的基本知识:统计和编程。
数据科学工作招什么?他们雇佣用数据科学技术解决现实生活问题的人;能够完成没有教科书答案的项目的人,并且是每个独特的公司所特有的。什么证明了求职者可以做这些事情?
- 一个自我指导的兼职项目(不仅仅是 1000 人完成的在线课程作业)显示了数据科学工作招聘的那些特质。在线课程显示出兴趣和一些知识,但不能真正回答候选人是否有这些关键能力的问题。工作不会雇佣那些在线课程做得最多的人。
类型 3
“我有兴趣在我当前的数据科学团队中向上或横向移动到一个使用强化学习(RL)的项目。我如何向我的经理和同事展示我在 RL 方面有足够的技能?”
这太棒了!你在这个领域,正在寻找一些发展机会。很可能你的统计学和编程技能都处于良好的基础上(也许你在一个方面比另一个方面更强),所以你不需要像那些刚从学校毕业或从另一个领域转行的人那样花太多时间来温习它们。
在这里,我肯定会说去参加一些在线课程,以建立你在新主题中的基础知识,我的意思是,专门参加强化学习的在线课程,而不是一般的机器学习。此外,如果你觉得你的一个支柱不如另一个强大,例如,如果你更擅长一般软件开发,相对于 ML 算法的数学推导,考虑温习 ML 算法。
人们(包括我在内)似乎忘记了一件事,那就是最直接的行动是询问你的经理或同事你是否能调到新的项目或团队!不要等到你参加了一些在线课程后才问;现在就表明你的兴趣,这样,如果这个项目有空缺或者其他类似的机会,他们就会想到你。
如果上述努力足以让你转移到其他数据科学角色或工作中的专业项目,那就太棒了!你的新目标已经达成。如果没那么容易,那么下一步就是利用你从在线课程中学到的知识,建立一个关于这个主题的快速辅助项目。如果展示你在某个话题上的真实经历不能让你的经理/同事相信你是那个感兴趣的项目的好候选人,那么……在线课程不是这里真正的问题。
一般决策标准
简而言之,以下是我建议的一般决策标准:
如果你没有机器学习/数据科学相关的简历行项目:
- 是的,做网上课程和作业,并把它放在你的简历上!
如果你有一些在线课程,但不确定是否要学更多:
- 考虑做一个副业,这是一个更好的简历项目,给你的时间带来更好的投资回报
- 自我评估你的编程和统计技能是否超过了足够的基线。链接:如何找到您的基线水平
如果您已经掌握了统计学和编程的基本知识,并且掌握了一些数据科学知识,请继续填写:
- 在这里停下来,检查一下你是否有一个好的兼职项目组合。如果没有,请尽快处理!链接:如何选择数据科学边项目
- 开始申请工作(或者朝着你的目标直接行动),而不是陷入自我学习的怪圈。很多时候,即使你没有得到这份工作,面试也是找出你可以改进的地方的好方法。
结论——如何决定是否应该参加更多的在线课程
现在,我们已经浏览了针对多种场景类型的建议,以及这些建议背后的详细逻辑。当然,每个人有不同的教育背景、工作经历和其他情况,但我希望通过提供的逻辑,您可以将其应用到您自己的具体情况中!
如果有疑问,请记住:参加在线课程的边际收益是递减的。最初的几个会非常有益,然后你做得越多,随后的每一个给你的新好处就越少。同样的逻辑也适用于接受额外教育。
很容易陷入被动学习的循环,所以总的想法是,如果你已经可以用你现有的知识量达到目标,就暂停一下。副业或简单地开始工作申请过程会给你带来更好的时间投资回报。希望这有帮助!
原载于 2020 年 7 月 12 日【https://www.susanshu.com】。
该不该用无代码 AI 平台?限制和机遇
实施无代码人工智能解决方案后的经验教训

虽然大多数人工智能项目仍然没有进入生产,但对无代码人工智能平台的兴趣一直在上升。事实上,越来越多的初创公司和大型科技公司现在提出“易于使用”的 ML 平台。
能够在不是数据科学家的情况下构建和使用基于机器学习的解决方案,这一想法对小型和大型公司来说都是非常有趣的事情,这些公司可以赋予员工权力,同时将更多资源用于复杂的 ML 项目。
在这篇文章中,我将分享我在实现了这些无代码 AI 解决方案之一并分析了与该行业相关的几家初创公司后所学到的东西。作为一名人工智能顾问,我的目标是确定这些解决方案是否可以帮助我们增加更多项目从概念证明(PoCs)过渡到可扩展、相关和高效部署的人工智能解决方案的机会。
为什么使用无代码人工智能平台
从运营的角度来看,我们在一年中为几个部门开发了几个人工智能项目。由于缺乏数据、投资、领导力,或者仅仅是由于机器学习目前的成熟度,他们中的大多数人只是停留在概念证明阶段。
当涉及到项目时,复杂程度是不一样的。事实上,一些项目与“最近的”算法有关,而其他项目只是使用众所周知的算法,如线性回归、K-means、朴素贝叶斯等。我们的无代码人工智能平台的目标是确定这些解决方案是否可以帮助我们将一些合作者转变为公民开发者,并将更多的数据科学家分派到“复杂”的用例中。
公民开发者: 构建应用程序供他人使用的非专业开发者。虽然他们不直接向 IT 部门汇报,但他们使用 IT 部门认可的工具,如低代码平台。
请务必理解,产品经理等内部公民开发人员的晋升并不意味着对数据科学家的需求正在消失。这个想法是为了减轻数据科学家积压工作的负担,以便他们能够专注于更大、更复杂的项目。
显然,对于传统的 ML 工作流程来说,做“更少”的工作并加速特定用例的开发是很有吸引力的。有没有可能设想一个未来,经理们可以提出一个想法,构建它,并通过使用一个无代码的人工智能平台来运行项目?
传统 ML 与无代码 ML 流程
今天,大多数人工智能项目都遵循或多或少相同的步骤。事实上,你从识别一个用例开始,收集数据,建立模型,训练它,改进它,等等。为了确定无代码人工智能是否真的有帮助,我们应该首先了解“经典”ML 和无代码 ML 之间的差异。

如你所见,“传统”人工智能项目的一些步骤可以自动化,或者使用拖放工具变得简单。从这个角度来看,我认为无代码人工智能平台是加速原型和演示开发的一种省时的方式。
我相信无代码人工智能平台非常适合特定的项目。例如,我们希望预测客户流失、客户终身价值、动态定价等指标,或者分析几份合同的数据以帮助我们更好地进行谈判的用例。我们也相信这些工具在一些内部流程的自动化中是有用的。
新技能
可以肯定的是,无代码人工智能平台的兴起也将创造新的技能预期。在不久的将来,如果一个产品经理必须熟悉至少一个无代码人工智能工具,并且了解数据集管理,我不会感到惊讶。我希望看到越来越多与这些工具相关的在线培训。
特定的市场
无代码 AI 仍然是一个不断增长的市场。大多数玩家似乎首先把自己定位在技术的类型上(NLP,计算机视觉,等等。)或特定用例(CRM 管理等)。
在不久的将来,我希望看到完整的工具,使覆盖几乎所有用途成为可能,从而避免投资于多种工具和利用知识的需要。
这个行业由初创公司和开发自己工具的大型科技公司组成。出于显而易见的原因,初创公司似乎专注于特定的用例,而不是提供几种选择。
锁定战略和商业模式
这个行业最有趣的方面是大型科技公司如何试图吸引新客户,以增加他们的用户范围,同时使用锁定策略。
锁定策略:一种策略,在这种策略中,客户非常依赖一家供应商的产品和服务,如果没有实际的和/或感知的巨大转换成本,客户就无法转向另一家供应商。
我经常想,如果不专业化,无代码人工智能初创公司能否长期生存。事实上,大型科技公司的优势在于能够为客户提供一种无需动脑的方法来保持在该供应商的平台和路线图上。
理想情况下,大型科技公司(谷歌和微软)希望公司能够使用他们的软件开发工具和与数据管理相关的更广泛的服务生态系统。
虽然其中一些解决方案是免费的或基于订阅模式,但它们可能需要顾问和开发人员的干预来培训用户和执行云后端连接工程。
实施无代码人工智能解决方案后的我的看法
几个月来,我们决定测试一个无代码人工智能平台的有效性。在我看来,无代码人工智能的效率和实用性并不是神话。
对我们来说,最大的好处是,由于使用无代码工具创建了快速 PoC,数据科学家可以通过评估他们不完整的想法来帮助我们的营销部门。事实上,他/她可以建议他们进行无代码 PoC,并在需求稳定后再回来进行。
然而,必须做出一些让步。事实上,如果你想快速生产而没有发展,你必须能够降低你的期望。
通过无代码解决方案基于机器学习的项目的成功将在很大程度上取决于您的功能需求,当需求非常具体时,就有必要在实现速度和与功能相关的期望之间找到正确的平衡。

每个解决方案都有一个工具设计固有的边界。事实上,这些工具是基于模型的,要么编辑选择提出简单的模型,这些模型将易于理解和使用,但反过来将缺乏灵活性,因为人们只能在模型的框架内开发。
相反,其他平台选择了更精细的模型,这些模型提供了与通过编码开发应用程序相当的灵活性。另一方面,学习曲线和所需技能会高很多。

我强烈建议根据易用性和灵活性之间的平衡来选择工具。在某些情况下,重要的是要记住,一旦你在一个平台上开发了一个应用程序,只要这个应用程序还在运行,你就和这个平台联系在一起了。在 PoC 的上下文中,这不是问题,但是在预期持续的应用程序的上下文中,情况可能会不同。
事实上,你必须确保你的项目所需的可扩展性可以通过使用无代码人工智能平台来实现。我认为,对于“复杂”的用例,使用无代码人工智能平台是不可能有可扩展的解决方案的。
此外,契约关系 ( 数据所有权)必须在成本和可逆性方面仔细检查。
另一个关键因素是可维护性。我建议你从一开始就确定你的目标是仅仅测试一个想法的相关性还是构建一个持久的应用程序。在第一种情况下,如果可能,最好使用无代码 AI 解决方案快速创建一次性 PoC。否则,我建议您使用传统的 ML 方法,构建稳定且可维护的版本。
如果你的无代码 AI 供应商可以保证你的可扩展性(在某些用例中是可能的),我会建议你按比例评估许可的总成本,以确保长期的可维护性。
可能发生的最糟糕的事情是,使用“快速而肮脏”的方法创建概念证明,然后投入生产,尝试扩展相同的概念证明。
限制
在我看来,目前大多数(不是全部)无代码 AI 平台的极限是:
个性化程度 不管大多数人可能会怎么想,构建机器学习模型的困难不是编码,而是你可以支配的数据、特征工程、架构和测试。在一些无代码解决方案中,您缺乏微调和调整不同参数的能力。
另一个缺点与数据有关。事实上,你可能对数据偏差很熟悉。根据不同的用例,每个人都可以构建和导出这些模型。因此,增加了生成有偏差算法的危险。
显然,机器学习工程师也可以创建有偏见的解决方案……
如前所述,无代码人工智能工具可能是积极的,但它们需要特定的治理。事实上,如果你不能以一种治理和控制的方式集成它们,你只会引入更多的影子 IT 和更多的问题。
影子 IT: 这个术语指的是在企业的 IT 部门不知情的情况下被管理和利用的信息技术(IT)应用程序和基础设施。
数据科学家可能最终会花尽可能多的时间来修改同事的工作,而不是完成自己的任务。
依赖性 我对无代码 AI 工具开发的另一个担忧是与依赖性有关的。事实上,您的解决方案可能不需要数据科学家,但将来可能需要一些顾问来帮助您更好地理解 ML 或使您的解决方案可伸缩。因此,对精通技术的专家的依赖不会消失。
对数据的需求 所有的机器学习项目都需要同样的东西:数据
一个 ML 项目的成功高度依赖于你收集、管理和维护数据集的能力。然而,这通常是数据科学家的工作,我不确定“公民开发者”是否能完成这些任务。
可伸缩性 我最后关心的是可伸缩性。事实上,许多成功的概念验证在生产中失败了,因为我们无法构建一个能够以可扩展的方式服务于 ML 模型的系统。在使用大量敏感数据的行业,如医疗保健或银行业,这就更难了。
我本可以提到其他潜在的问题,比如部署、安全、与遗留系统的集成等。然而,我仍然相信无代码人工智能平台的有用性。使用无代码人工智能的项目的成功将在很大程度上取决于您的用例以及数据管理的成熟度。
我们仅仅处于这一趋势的开端,我很有信心越来越多的公司(尤其是中小企业)将会尝试利用这些工具。
您是否应该使用云提供商提供的 ML 监控解决方案?
Azure 和 AWS 与 AI 系统性能监控最佳解决方案的比较

资料来源:莫纳实验室公司。
随着人工智能系统在许多行业变得越来越普遍,监控这些系统的需求也在增加。与传统软件相比,人工智能系统对数据输入的变化非常敏感。因此,一类新的监控解决方案已经在数据和功能级别(而不是应用程序级别的基础设施)出现。这些解决方案旨在检测人工智能系统中常见的独特问题,即概念漂移、偏见等。
人工智能供应商领域现在挤满了兜售监控能力的公司。这些公司包括一流的/独立的解决方案,以及集成的人工智能生命周期管理套件。后者提供更基本的监控功能,作为次要重点。
为了进一步宣传,一些主要的云提供商开始宣传他们也为部署在他们云平台上的机器学习模型提供监控功能。按市场份额计算,AWS 和 Azure 是第一大和第二大提供商,它们分别宣布了各自 ML 平台下的具体功能——SageMaker 模型监视器 (AWS),和数据集监视器 (Azure)。到目前为止,谷歌(GCP)似乎只为服务模型和培训工作提供应用程序级别的监控。
在这篇文章中,我们提供了云提供商当前产品的概述(我们重点关注 AWS 和 Azure),并讨论了这些解决方案中的差距(通常由最佳解决方案很好地涵盖)。
云提供商产品概述
那么 Azure 和 AWS 在监控生产中的模型方面能提供什么呢?
轻触开关即可记录模型输入和输出
监控任何类型的系统的第一部分几乎总是记录系统操作的数据。在监控 ML 模型的情况下,这从模型输入和输出开始。
毫不奇怪,Azure 和 AWS 都允许您轻松地将这些数据记录到各自的数据存储中(AWS 的 S3 存储桶,Azure 的 blob 存储)。您所要做的就是在 python 代码中向模型运行调用添加一个数据捕获配置。请注意,并非所有输入类型都可以自动保存(例如,在 Azure 上,不会收集音频、图像和视频)。AWS 还允许为数据捕获配置采样率。
使用现有的分析和 APM 解决方案分析数据
一旦收集了输入和输出数据,平台建议的下一步是使用其现有的分析/APM 产品来跟踪数据。
Azure 建议使用 Power BI 或 Azure DataBricks 来获得数据的初步分析,而在 AWS 中,你可以使用 Amazon Cloudwatch。
由于数据保存在平台自己的存储系统中,通常很容易获得跟踪模型输入和输出的初始图表和图形。
漂移输入数据的基本跟踪
AWS 和 Azure 都提供了相当新的工具,用于警告模型输入数据的分布和行为的变化。对于 AWS 来说,这是“亚马逊 SageMaker 模型监视器”的主要部分,而对于 Azure 来说,这是通过一个叫做“数据集监视器”的非常新的功能来完成的。
在这两个平台上,工作流都是从创建基线数据集开始的,基线数据集通常直接基于训练数据集。
一旦您准备好了基线,平台允许您从如上所述捕获的推理输入数据创建数据集,将它们与基线数据集进行比较,并获得关于特征分布变化的报告。
这两种解决方案之间存在一些差异。AWS 的解决方案从基线数据集创建“约束”和“统计”文件,其中包含输入数据的统计信息。这允许您稍后与推断数据进行比较,以获得关于差异的报告。另一方面,Azure 的“数据集监视器”为您提供了一个仪表板,用于比较基线数据集和推理时间数据集之间每个特性的分布。然后,当分布的变化足够大时,它允许您设置警报。
然而,上述差异实际上是相同基本功能的实现细节——以您的特征集为例,查看它们在训练集中的基线分布,并将其与它们在推理时间中的分布进行比较。
够了吗?
因此,云提供商确实为数据和模型层提供了监控功能,但你能依靠这些功能来维持甚至改进生产级人工智能系统吗?我们认为你不能。这里有几个原因:
生产级监控需要丰富的上下文数据
跟踪您的模型输入和输出是很好的,但是这还不足以真正理解您的数据和模型的行为。你真正需要监控的不是单个模型——而是整个人工智能系统。很多时候,这将包括您的云提供商不容易访问的数据。
几个例子:
- 您有一个人类标记系统,并且您想要监控您的模型的输出与它们的标记相比如何,以获得您的模型的真实性能度量。
- 您的系统包含几个模型和管线,其中一个模型的输出用作后续模型的输入特征。第一个模型的表现不佳可能是第二个模型表现不佳的根本原因,您的监控系统应该了解这种依赖性,并相应地向您发出警报。
- 您有实际的业务结果(例如,您的建议模型选择的广告是否被实际点击)-这是衡量您的模型性能的一个非常重要的指标,即使输入功能从未真正改变,它也是相关的。
- 您不想(甚至不允许,例如,种族/性别)将元数据用作输入要素,但您确实希望对其进行跟踪以进行监控,从而确保您不会对该数据字段有偏见。
有关基于上下文的监控的更多信息,请查看这篇关于平台监控方法的文章。
跟踪数据的子部分
一个人工智能系统平均工作得很好,但在数据的子部分表现不佳,这种情况并不罕见。因此,对性能进行细致的检查至关重要。
考虑这样一种情况,您的模型对来自您的一个客户的数据表现非常不同。如果这个客户占了您的模型所接收数据的 5%,那么模型的总体平均性能可能看起来不错。然而,这位顾客不会高兴的。这同样适用于不同的地理位置、设备、浏览器或任何其他可以对数据进行切片的维度。
良好的监控解决方案会在子细分市场中发生异常行为时向您发出警报,包括在更细粒度的子细分市场中发生异常行为时,例如,来自特定地区的用户使用特定设备时。
可配置性
每一个 AI 系统都像一片雪花。它们都有特定的性能指标、可接受(或不可接受)的行为等。因此,一个好的人工智能监控平台必须是高度可配置的。
考虑这样一种情况,你有一个 NLP 模型来检测输入文本的情感。您知道对于短文本(例如,少于 50 个字符),您的模型不是很准确,而您对此没有意见。您希望监控您的模型输出,但是当短输入文本的相对比例增加时,您不希望收到低置信度分数的警报。您的监控平台必须允许您在考虑这一特定指标(但可能不考虑其他指标)时,能够轻松从监控的数据集中排除所有短文本。
还有许多其他例子可以说明微调的价值,从警报首选项到临时数据操作。完全自主的监控方法在理论上听起来不错,也很容易解释,但是当遇到现实世界的约束时就会失败。
结论
首先,看到主要的云提供商开始为生产人工智能提供更多工具是令人鼓舞的。然而,我们审查的解决方案是非常基础和实验性的(例如,Azure 还没有为上述解决方案提供任何 SLA)。对于这些供应商来说,监控当然不是最优先考虑的事情。
与此同时,业内越来越清楚的是,监控模型和整个人工智能系统是一项基本需求,不能被视为事后想法。为了让你的人工智能产品做好准备,并确保在商业 KPI 受到负面影响之前发现人工智能问题,这一点至关重要。同类最佳的解决方案无疑将监控作为其核心重点和优先事项。
那么,最佳品种在市场上会有优势吗?还有待观察。一个可以考虑的先例是杀伤人员地雷行业。云提供商长期以来一直为 IT 组织提供基本的解决方案,但市场催生了一批成功的一流企业,如 New Relic、AppDynamics 和 Datadog(以及许多其他企业)。一些购买者满足于更基本的功能,因为他们喜欢与更少的供应商打交道,而另一些购买者喜欢生命周期每个阶段中最深入的功能。
无论如何,观察和体验这一类别的演变肯定会很有趣。
参考
- GCP 监控模型(APM like):https://cloud . Google . com/ai-platform/prediction/docs/monitor-prediction
- AWS 宣布(12 月 19 日)“Sagemaker 模型监视器”:https://AWS . Amazon . com/blogs/AWS/Amazon-Sagemaker-Model-Monitor-fully-managed-automatic-monitoring-for-your-machine-learning-models/
- Azure 模型数据收集:https://docs . Microsoft . com/en-us/azure/machine-learning/how-to-enable-data-collection
- Azure 数据集监视器:https://AWS . Amazon . com/blogs/AWS/Amazon-sage maker-model-monitor-full-managed-automatic-monitoring-for-your-machine-learning-models/
原载于 2020 年 9 月 15 日https://www . monalabs . io。**
向我展示 ROI:业务分类指标
通过可操作的指标推动业务价值
沙欣·高赫尔博士
分类器的评估指标有助于确定模型从数据中学习的程度以及区分不同类别的能力。准确度、精密度、召回率、F1、AUC 和对数损失是评估分类器性能最常用的指标。在这篇文章中,我将谈论一些其他指标,即。累积收益、提升和捕获率,可用于向业务利益相关方展示分类模型的有效性和价值,使其成为“可操作的洞察”,并有助于在业务运营中战略性地使用预测。我将分享一个 python 实用函数,它将把预测概率和实际类(来自目标列的地面事实或训练数据中的“Y”)作为输入,并计算模型的累积增益、提升和捕获率。这也可以用于设置分类器的阈值。我还将分享一些来自不同垂直行业的用例示例,如预测性维护,医疗保健和营销,这些指标可用于推动业务价值。

物有所值
在建立机器学习模型以预测事件发生的可能性之后,例如机器故障的可能性、客户流失的可能性、患者发生医疗事件的可能性、成员响应外展的可能性等。下一步通常是设计一个基于模型预测的行动计划。经常出现的问题是最少的病例数是多少(顾客、病人、机器等)。)我可以以获得最佳结果为目标。这个问题的答案可以在捕获率分析、累积增益和提升图表中找到。这些指标相互关联,可以互换使用,但都回答了同一个业务问题,即如何获得最佳性价比。
下面我将简要描述这些指标是什么以及计算它们的步骤。在 GitHub 中可以找到 python 实用函数以及所使用的数据。该函数返回的输出如下,将用于绘图。

效用函数度量的输出 _roi
捕获率分析
捕获率分析(也称为十分位数分析)提供了一种快速直观的方法来测试模型预测预期结果的能力。为了分析捕获率,从模型中预测的概率按降序排列,并分成 10 个大小相等的区间或十分位数,我们查看每个十分位数中的实际事件率。实际事件率是十分位数中的事件数(实际阳性数)除以十分位数的大小,其中十分位数的大小就是实例总数除以 10。这些被绘制成柱状图,我们从上到下观察各个柱状图的相对高度,高度代表每个十分位数的事件发生率。
理想模式 —一个好的图形表现出阶梯效应,从顶部的十分位数到底部的十分位数下降。具有显示良好阶梯模式的条形的模型比没有条形的模型更有预测性,因为它表明模型是宁滨,即从最有可能成功到最不可能成功的实例。
不期望的图形 —一个坏的图形具有不显示阶梯效应的条,并且看起来是无序的或者看起来是相同的高度。这表明该模型并不比随机将宁滨实例分成十分位数表现得更好。

捕获率分析
阅读左边的第一个条形,我们可以看到,通过将 10%的记录作为目标,这些记录被模型列为“最可能的阳性”(前十分位数),将在目标组中产生 80%的阳性。
累积收益图
累积收益图显示了通过使用模型来确定目标或采取行动与随机确定目标相比所能获得的收益。
例如:在预测性维护场景中(该模型通常预测机器出现故障的可能性),如果您随机抽取 20%的机器进行定期维护,您可能会发现只有 20%的机器会出现故障(这将是您的基准)。但是,如果您的目标是 20%的机器,并且如果模型能够确保 60%将要失败的机器在这个组中,那么这将是您的模型的收益。
在累积增益图中,X 轴是抽样总体的百分比,Y 轴是样本中实际失败的比例。该曲线显示了通过针对案例总数的给定百分比而“获得”的案例总数的百分比。曲线离基线越远,增益越大。

累积增益曲线
在上面的增益图中,我们可以看到,通过使用模型预测的概率瞄准 50%的人口,我们将获得 75%的事件。通过使用来自模型的预测将 40%的人口作为目标,我们将仅获得 65%的事件,而通过将 60%的人口作为目标,我们将获得 82%的事件。
如果业务目标或 KPI 可以通过获得 65%的事件来满足,我们可以通过将所需的百分比映射到适当的临界值来使用它来设置分类器的阈值。阈值决定了如何将预测概率标记为正数或负数
电梯图表
提升图来源于累积收益图。在提升图中,X 轴是抽样人口的百分比,Y 轴是使用和不使用预测模型获得的结果之间的比率。这就是累积增益图中累积增益与基线的比值。提升曲线是预测模型通过选择相对较少的案例获得相对较大部分正面信息的有效性的另一种衡量标准,换句话说,就是我们可以有效地撇去奶油。
例如:在医疗保健领域,一个常见的场景是主动接触有风险的患者以进行干预。这可以用于糖尿病或高血压或任何其他疾病的干预。由于资源有限,始终需要优化外展计划,以覆盖大部分真正处于风险中的患者,同时最大限度地减少外展次数。

升力曲线
在上面的提升曲线中,你会注意到,提升将随着我们选择的目标人群的样本而变化。当只针对人口中的一小部分样本(具有高预测概率的实例)时,高提升是好的分类器的信号。随着我们的目标人群样本越来越大,Lift 将继续下降。
在本文中,我们使用 python 来计算分类器的一些业务指标。希望在这些指标的帮助下,您将能够为您的机器学习模型建立 ROI,这将有助于在业务运营中采用该模型。尽情享受吧!
@Shaheen_Gauher
Shaheen Gauher 的职业是人工智能沟通者、智能解决方案推动者和数据科学家。她帮助企业构建和部署预测解决方案,以最佳地利用他们的数据,并使他们能够通过技术和人工智能实现更多目标。她是训练有素的气候科学家和物理学家,并在塔夫茨大学艺术与科学研究生院的数据分析顾问委员会任职。
举手表决:谁愿意在可承受的范围内,分分钟内将净学费提高 6-15 %?

太久没读的是:学校可以通过使用机器学习来增加 6-15%的净学费。此外,他们还可以在 99%的情况下快速轻松地给出最佳上诉金额,减少 67%的熔化和 74%的违约。
人类是糟糕的评估者。当我们错误地认为自己擅长估算大部分事物的数量时——尤其是关于金钱的数量,这会助长我们饥渴的自我。几个月前,我们的人工智能(AI)公司——此前专注于生物医学、电子商务和金融科技——被要求应用机器学习(ML)来优化一所顶尖学校的财政援助,这是我们最近的一个证据。作为一个背景,他们并不是因为不善于分配财政援助而出名的。他们很擅长这个。
然而,一场“完美风暴”事件——全球疫情、另一场大衰退、销售和营销人员面临日益增加的数字复杂性,以及家庭关注支付意愿而非历史支付能力——促使他们寻找下一代解决方案。对于大多数不了解的人来说,ML 是一种人工智能,它使用超级强大的统计数据——需要几年时间才能计算的东西——来学习如何预测或分类事物。
即使你没有在工作中直接面对它,机器学习也变得无处不在。ML 是脸书为你谈论过的或谷歌搜索过的东西向你推送广告的方式。这是亚马逊推荐你应该阅读或购买的其他内容的方式。而且,这就是特斯拉的自动驾驶汽车自动驾驶的方式。
当学校有了聪明的想法来了解是否有人应用它来优化财政援助和净学费时,他们发现了以下情况(我们在研究市场时也发现了同样的情况),现在有三种选择——它们都很糟糕:(1)由财政援助存储系统(如 SSS、FACTS、TADS、FAST、FAFSA 等)提供的援助建议。);(2)帮助顾问使用他们的“专有算法”提出建议以及(3)具有低准确度和高价格(即$45,000 到$75,000)的初级 ML 推荐。
第一,财政援助系统推荐一个援助数字,但它只是使用算术——收入是这个,费用是那个,所有其他的他们可以花在教育上。几乎所有的录取和招生管理专业人士都会告诉你,这是低准确率和低价值的。金融援助供应商的基本算术援助建议还做出了一个致命的错误假设,即更关注援助的历史工作方式,而不是近年来的趋势。也就是说,家庭过去申请财政援助是因为他们需要。现在,少数人有,但越来越多的人现在要求得到它,因为他们想要它。援助申请者的家庭收入通常是几十万美元,净资产是这个数字的几倍。他们可以支付私人学费;他们不想这么做是因为选择——为退休、大学或更昂贵的生活方式存钱,他们不想牺牲这种生活方式(例如,“我们无法支付莎莉的学费,也无法保留毛伊岛的公寓”,等等。).
第二,私人顾问销售的专有“算法”通常不是算法;它们是基本公式,比财政援助系统或简单的电子表格好不了多少。他们很少甚至不使用统计数据,也不能告诉你成功的概率或测量的准确性。顾问通常希望你为他们的每次使用付费(例如,文件审查、申请人、年份)。一种相关的拆封方法是“分桶法”——也称为“金发姑娘法”——他们查看文件,将它们分成“轻、中、重”三类,然后随机向每一类投入一定数量的钱。统计分析表明,分桶法不如人工估计每个个体和个性化案例准确;这对预测和优化是不利的,而不是有利的。从本质上讲,他们只是将他们所知不多的文书处理外包给那些对其知之甚少的人,而没有任何可论证的或可比较的结果。因此,学校为了方便和速度而牺牲了质量。
第三,有两个组织(除了我们)将机器学习应用于录取和辅助数据。第一种是咨询公司,使用一种叫做决策树的基本或原始算法(或一组称为随机森林的算法),来估计给予申请人多少帮助或吸引力。虽然它们的表现优于人类评估者,但它们仍然只有大约 50–57%的准确率。为此,他们通常在第一年后每年收取 25,000 美元和 10,000 美元的额外费用。他们没有告诉你的是,这种元素类型的 ML 解决方案会退化,因为数据每年都不一样——它偏离了历史数据。如果第一年 58%准确,第二年可能只有 55%准确,第三年只有 50%准确,那么你已经为错误的事情比正确的事情付出了 45,000 美元。第二个应用机器学习的组织是一所研究型大学,他们采用集成,或初级或原始 ML 算法的组合,这些算法更精确一些,可能低于 60%的百分比。到目前为止,它们是最好的选择,但只有那些能够支付 75,000 美元年费的学校才有。在这两种情况下,分析也必须由数据科学家在数周或数月内完成——学生申请时无法实时获得,招生人员也无法使用。
我们发现拥有一个高度可预测的工具非常重要,它可以在招生人员需要时随时可用,并且他们可以通过拖放电子表格来简单轻松地使用它,而不是等待数据科学家几周或几个月。此外,在不确定的经济时期,它必须是负担得起的。
我们过去和现在所做的有三点不同:(1)我们使用了一种超级先进的技术形式,称为自动机器学习,在数千种算法中进行“烘烤”或竞赛,以始终拥有预测最准确的组合;(2)我们使用几十年来成千上万的家庭数据点来训练算法,以了解精确的数量——不多也不少——来激励学生入学或留在学校;(3)我们将它制作成一个简单易用的安全网络应用程序,您可以拖放匿名学生数据的电子表格,它会准确地告诉您提供多少帮助或上诉,或者流失、融化或违约的可能性。此外,任何被录取的人都可以在任何需要的时候使用它,几乎不需要任何培训。它的准确率在 1%以内,至少 67%,高达 99%,这取决于它是哪种工具。
对援助、上诉、减员和违约的自动 ML 预测的另一个及时的好处是,这些 ML 算法是种族和性别盲的。他们接受训练的数据是匿名的,不包括性别和种族。它还全面考虑了 12-24 个因素,以个性化每个家庭的需求——不仅仅是收入和资产,还包括地理多样性、家庭规模和经济差异。
关键问题是,我们如何知道它有效?很高兴你问了。我们把我们的工具应用到最初雇佣我们的那所名校的 10 年数据中。我们了解到,如果他们在此期间使用我们的 ML 工具,他们每年将从几乎相同的学生群体中多获得 108 万美元。只需花费谷歌估算表的一小部分价格,你就可以在定制数据上获得军用级别的精度,在几分钟内产生更好的结果。
然后,我们将同样的技术应用于上诉、流失和违约,发现它可以在几秒钟内准确预测 99%、67%和 74%的情况,只需将学校通常拥有的学生数据电子表格拖放到安全的网络应用程序上。
我们相信这些技术将改变中等和高等教育学校的招生和资助方式。因此,我们成立了一家名为 Ed AI 的子公司来做这件事。在接下来的几个星期里,我们会以很大的折扣签下早期采用者,这已经是录取和援助市场上最准确、最实惠、回报最高的工具了。如果你决定在几分钟内而不是几天或几周内处理援助和上诉,并在更好地服务家庭和学生的同时将净学费增加 6-15%,请给我发电子邮件,我们将开始…
Eric Luellen 是一位技术高管、连续创业者、数据科学领袖,担任bio informatix . io的联合创始人兼首席数据科学家。他还是《击败亚马逊:赢得电商战争的机器学习指南 】的作者,由社会正义出版社于 2020 年 2 月出版。他的在线读者超过 4 万人。
用于多文本分类的连体和双 BERT
在模型中插入变压器的不同方法

罗尔夫·诺依曼在 Unsplash 上的照片
对 NLP 的不断研究产生了各种预训练模型的发展。对于各种任务,如文本分类、无监督主题建模和问答,最先进的结果通常会有越来越多的改进。
最伟大的发现之一是在神经网络结构中采用了注意力机制。这项技术是所有被称为变形金刚网络的基础。他们应用注意力机制提取关于给定单词上下文的信息,然后将其编码到学习向量中。
作为数据科学家,我们可以利用许多变压器架构来预测或微调我们的任务。在本帖中,我们喜欢经典的 BERT,但同样的推理可以应用于其他任何变压器结构。我们的范围是在双重和连体结构中使用 BERT,而不是将其用作多纹理输入分类的单一特征提取器。这篇文章的灵感来自于这里的。
数据
我们从 Kaggle 收集了一个数据集。新闻类别数据集包含从赫芬顿邮报获得的 2012 年至 2018 年约 20 万条新闻标题。我们的范围是根据两种不同的文本来源对新闻文章进行分类:标题和简短描述。我们总共有 40 多种不同类型的新闻。为了简单起见,考虑到我们工作流的计算时间,我们只使用 8 个类的子组。
我们不应用任何类型的预处理清洗;我们让我们的伯特做所有的魔术。我们的工作框架是 Tensorflow 和巨大的 Huggingface 变形金刚库。更详细地说,我们利用了裸露的 Bert 模型转换器,它输出原始的隐藏状态,而没有任何特定的头在上面。它可以像 Tensorflow 模型子类一样访问,并且可以很容易地在我们的网络架构中进行微调。
单伯特
作为第一个竞争对手,我们引入了单一 BERT 结构。它只接收一个文本输入,这是我们两个文本源连接的结果。这是常态:任何模型都可以接收串联特征的输入。对于变压器,这一过程通过将输入与特殊令牌相结合而得到提升。
BERT 期望输入数据具有特定的格式:有特殊的标记来标记句子/文本源的开始([CLS])和结束([SEP])。同时,标记化涉及将输入文本分割成词汇表中可用的标记列表。用词块技术处理未登录词;其中一个单词被逐渐分成子单词,这些子单词是词汇表的一部分。这个过程可以由预先训练好的拥抱脸标记器轻松完成;我们只需要处理填料。
我们以每个文本源的三个矩阵(令牌、掩码、序列 id)结束。它们是我们变压器的输入。在单个 BERT 的情况下,我们只有一个矩阵元组。这是因为我们同时将两个文本序列传递给我们的标记器,这两个文本序列自动连接在一起(用[SEP]标记)。
我们模型的结构非常简单:变压器直接由我们上面构建的矩阵供电。最后,变压器的最终隐藏状态通过平均池操作来减少。概率得分由最终的密集层计算。

我们简单的 BERT 在测试数据上达到了 83%的准确率。这些表现记录在下面的混淆矩阵中。

双重伯特
我们的第二种结构可以定义为双 BERT,因为它使用两个不同的变压器。它们具有相同的组成,但是用不同的输入来训练。第一个接收新闻标题,而另一个接收简短的文字描述。输入被编码为总是产生两个矩阵元组(令牌、掩码、序列 id),每个输入一个。对于两个数据源,我们的转换器的最终隐藏状态随着平均池化而减少。它们被连接起来并通过一个完全连接的层。

通过这些设置,我们可以在测试数据上达到 84%的准确率。

暹罗伯特
我们最后的模型是一种连体建筑。它可以这样定义,因为两个不同的数据源在同一个可训练转换器结构中同时传递。输入矩阵与双 BERT 的情况相同。对于两个数据源,我们的转换器的最终隐藏状态是通过一个平均操作来汇集的。由此产生的串联在一个完全连接的层中传递,该层组合它们并产生概率。

我们的连体结构在测试数据上达到了 82%的准确率。

摘要
在这篇文章中,我们应用了 BERT 结构来执行多类分类任务。我们实验的附加价值是以各种方式使用变压器来处理多个输入源。我们从一个源中所有输入的经典连接开始,并在保持文本输入分离的情况下结束了模型。双体和连体变体能够实现良好的性能。因此,它们可以被视为传统单变压器结构的良好替代品。
保持联系: Linkedin
参考文献
两张床比一张床好
Kaggle: 伯特基 TF2.0
暹罗网络
针对初学者的逐行解释
摘要
Siamesse 网络是一类能够一次性学习的神经网络。这篇文章针对深度学习初学者,他们熟悉 python 和卷积神经网络的基础知识。我们将逐行解释如何使用 Python 中的 Keras 实现暹罗网络。当您浏览代码时,如果您觉得有些事情可以用更好的方式解释或完成,请随时发表评论。

图片由 Gerd Altmann 从 Pixabay 拍摄
介绍
让我们假设我们有一个 1000 名员工的公司。我们决定实施面部识别系统来记录你的员工的出勤情况。如果我们使用传统的神经网络,我们将不得不面对两个主要问题。第一个是数据集。从我们每个员工那里收集大量的数据集几乎是不可能的,我们最终会得到每个员工最多 5 张照片。但是传统的 CNN(卷积神经网络)无法学习如此小的集合的特征。我们最终还会得到 1000 个输出类。让我们考虑一下,不知何故,我们从每个员工那里获得了一个巨大的数据集,我们训练了一个非常好的 CNN 模型。当一名新员工加入我们的组织时会发生什么?我们如何将此人纳入我们的面部识别系统?所有这些缺点都可以通过使用连体网络来克服。在这篇文章中,我们将使用暹罗网络进行一次性学习实验,该网络专注于差异而不是特征匹配。
我们计算不同类别的图像之间的相似性得分,而不是使用每个类别的大量数据。这个网络的输入将是属于相同类别或不同类别的两个图像。输出将是范围在 0 和 1 之间的浮点数,其中 1 表示两个图像属于同一类,0 表示它们来自不同的图像。让我首先解释它与使用 CNN 架构的图像分类有何不同。
体系结构
在 CNN 模型中,有一系列卷积层和池层,后面是一些密集层和一个可能带有 softmax 函数的输出层。这里的卷积层负责从图像中提取特征,而 softmax 层负责为每个类别提供一个概率范围。然后,我们决定具有最高概率值的神经元的图像类别。
看看这篇伟大的文章了解更多关于 CNN 如何工作的信息。

传统 CNN 架构由苏米特·萨哈
对于暹罗网络,除了没有 softmax 层之外,它具有类似的卷积层和池层构成。所以,我们从致密层开始。如前所述,由于网络有两个图像作为输入,我们将得到两个密集层。现在我们计算这两层的差异,并将结果输出到具有 sigmoid 激活函数(0 到 1)的单个神经元。因此,这个网络的训练数据必须以这样一种方式构造,即有一个由两个图像和一个变量 0 或 1 组成的列表。

暹罗网络
注意:只有一个网络,两个图像通过同一个网络。只是有两个输入。因此,两个输入将从卷积层和密集层通过相同的权重矩阵。
如果你仍然不清楚这是如何工作的,参考这个链接。
密码
在这篇文章中,我使用了 Kaggle 的 Fruits 360 数据集。但是,可以随意试验其他数据集。代码托管在 Kaggle 中。如果您对代码有疑问,请随意使用下面的笔记本,亲自体验一下。
https://www.kaggle.com/krishnaprasad96/siamese-network
导入库
让我们从导入我们正在使用的库开始。如前所述,这段代码使用 Keras 构建模型,使用 NumPy,pillow 进行数据预处理。
注意:不要将 Keras 作为"从 tensorflow 导入 Keras
数据预处理
- 第 1 行:包含数据集的基础目录
- 第 2 行:表示将用于培训的百分比。其余的将用于测试
- 第三行:由于 Fruits 360 是一个用于图像分类的数据集,所以它每个类别都有很多图像。但是对于我们的实验来说,一小部分就足够了
- 第 6 行:从文件夹中获取目录列表。每个文件夹都属于一个类
- 第 10–13 行:声明三个空列表,记录 X(图片),y(标签),cat_list(记录每张图片的类别)
- 第 16–24 行:遍历类文件夹,从每个类中选择 10 张图像,将它们转换成 RGB 格式,并附加到一个列表中。在 cat_list[]中记录图像的类别,以备将来参考
- 第 26–28 行:将所有列表转换成 NumPy 数组。因为任何图像的范围都是从 0 到 255,所以为了简化,将数组 x 除以 255
列车测试分离
- 第 1 行:通过乘以 train_test_split 计算将用于训练的类的数量
- 第 2 行:从可用的总类中减去 train_size,得到 test_size
- 第 4 行:将 train_size 乘以每个类中的文件数,得到训练文件总数
- 第 7–15 行:将之前计算的值用于子集 X、Y 和 cat_list
生成批次
此部分用于生成用于培训的批处理文件。批处理文件应该具有 X 和 y。在图像分类的通常情况下,如果批处理大小为 64,图像大小为(100,100,3),则 X 的大小将是大小为 64 的列表,并且列表中的每个元素的大小将为(100,100,3)。
在我们的例子中,因为我们有 2 个输入,所以将有一个大小为 64 的列表(假设为“A”),并且“A”中的每个元素将有一个长度为 2 的列表(假设为“B”),并且“B”中的每个元素的大小将为(100,100,3)。为了训练,我们将生成一个批处理,使得一半的输入对 B[0]和 B[1]属于同一类别。给这些图像对赋值 0。对于另一半输入对,B[0]和 B[1]属于不同的类别。给这些图像对赋值 1。
- 第 3–7 行:将 x_train、cat_train 的值以及训练规模的开始和结束规模存储在一个临时变量中
- 第 9–11 行:将 Y 的 batch_size 的一半指定为 0,其他的指定为 1
- 第 13 行:从要使用的培训类别列表中随机生成一个类别列表。另外,追加两个 image_size*batch_size 数组
- 第 17–25 行:对于每次迭代,在 batch_x[0]的情况下,从类别列表中指定的类别中选择一个图像。对于 batch_x[1],如果 y[i]为 0,则从同一类别中选择图像,否则从除同一类别之外的任何其他类别中选择 batch_x[1]
暹罗网络
- 第 1 行:声明输入图像的形状。
- 第 2 行:用图像的形状声明两个输入。
- 第 6–7 行:声明初始化网络权重和偏差的参数。如论文中所述选择这些值。
- 第 9–20 行:声明一个具有 4 个卷积层和最大池层的顺序模型。最后使用一个平整层,然后是一个致密层。
- 第 22–23 行:将两个输入传递给同一个模型。
- 第 25–27 行:从两幅图像中减去密集层,并使其通过具有 s 形激活功能的单个神经元。
- 第 29–30 行:将带有损耗的模型编译为“二元交叉熵”和“亚当”优化器。
- 第 32 行:****siamese _ net的绘图模型函数输出如下。

暹罗网络
单向一次学习
这是一个验证一次性学习的过程,我们挑选“n”个输入对,使得只有一个输入对属于同一类别,而其他所有输入对都来自不同类别。如果我们考虑 9 路单次验证,并且网络的每个输入需要两个图像,则 x[0]对于所有 9 对都保持恒定,x[1]仅对于 9 对中的 1 属于 x[0]的相同类别,而对于其他所有的都不同。如果所有的 9 对都给了该模型,则预期属于同一类别的对将具有 9 对中的最低值。在这种情况下,我们认为这是一次成功的预测。
输入参数 n_val 是指验证步骤的数量。 n_way 指每个验证步骤的路数。记住,上面提到的 x[0]在每个验证步骤中都保持不变。

(更深入的理解,请叉开 Kaggle 的笔记本,尝试从该功能调试每一行)
- 第 3–7 行:将 x_val,cat_test 存储在一个临时变量中
- 第 9 行:这与批处理生成中的第 13 行相同,除了我们从测试集中创建了一批随机类别
- 第 11–24 行:对于每个验证步骤,我们遍历 n_way,从 class_list 中取出相应的类别列表,从该类别中挑选一个图像,并将其存储在 x[0]中。对于 x[1],如果它是第一次迭代,则从相同的类别中选择一个图像,而对于其他图像,则从不同的类别中选择。这个内部循环几乎与上面讨论的 batch_generation()方法相同。
- 第 26–31 行:对于每个验证步骤,使用模型预测输出,并检查结果[0]与其他结果相比是否有最小值。请注意,结果数组将是一个大小为 n_way 的列表。如果是,在 n_correct 上加 1。对所有其他验证步骤重复相同的步骤。
- 第 32 行:使用 n_correct 和验证步骤数计算精度。
训练模型
训练模型有 4 个超参数(时期,批量大小,n_val,n_way)
- 第 6–7 行:声明两个列表,记录损耗和精度值,以便进一步可视化。
- 第 8–20 行:对于每个历元,获取 x 和 y 的批次,使用这些输入训练模型,并将损失附加到列表中。对于每“N”(本例中为 250)个时期,通过进行 N 向一次性学习来检查模型的表现。
成果和未来工作
上面的代码在 Kaggle 中训练了 5000 个纪元。使用 GPU 将显著减少训练时间。

模型的训练损失

模型的准确性
我们能够在验证集上达到 90%的准确率。为了进一步提高精度,我们可以尝试从预先训练的模型中导入权重,如 VGG-16、雷斯网-50 等。
结束的
如果你有任何问题,请告诉我。我会尽力回应。由于这是我的第一篇博文,请告诉我它是否对你的项目有所帮助,或者我是否应该改变解释事物的方式。
我期待着创造更多关于计算机视觉的帖子。让我知道你希望涵盖的主题。黑客快乐!
Sidetable 为您提供了您不知道自己需要的熊猫方法
快速制作缺失值、频率计数、小计等数据帧🎉
Sidetable 是一个新的 Python 库,它为 pandas 中的探索性数据分析增加了几个方便的方法。在本指南中,我将向您展示如何使用 sidetable,以及它在您的数据科学工作流中的合适位置。
当我们探索 sidetable 时,我们将使用最近添加到 seaborn 可视化库中的企鹅数据集。企鹅数据集旨在取代过度使用的虹膜数据集。如果没有别的,它增加了一些多样性,并允许我们展示一些企鹅图片。😀

下颚带企鹅。资料来源:pixabay.com
Pandas 是使用 Python 的数据分析师和数据科学家的探索工具。🐼pandas API 很大,面向数据清理和数据争论。新的 sidetable 包为数据帧增加了方便的方法。这些方法使得查看缺失值、每列值的计数、小计和总计变得更加容易。
我们去看看吧!🚀
设置
要获得必需的软件包及其依赖项的最新版本,请取消注释并运行以下代码一次。
# ! pip install sidetable -U
# ! pip install pandas -U
让我们导入包并检查版本。
import sys
import pandas as pd
import sidetable
print(f"Python version {sys.version}")
print(f"pandas version: {pd.__version__}")
print(f"sidetable version: {sidetable.__version__}")Python version 3.7.3 (default, Jun 11 2019, 01:11:15)
[GCC 6.3.0 20170516]
pandas version: 1.0.5
sidetable version: 0.5.0
如果你的 Python 版本低于 3.6,建议你更新一下。如果你的版本低于 1.0,熊猫也一样。要了解更多关于熊猫 1.0 的更新,请点击这里查看我的文章。
企鹅数据🐧
我们将直接从托管 seaborn 数据集的 GitHub 存储库中的. csv 文件读取南极企鹅数据集。
数据是由 Kristen Gorman 博士和 LTER 南极洲帕尔默站收集和提供的。点击查看更多信息。
让我们将数据放入 pandas DataFrame 并检查前几行。
df_penguins = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/penguins.csv')
df_penguins.head(2)

好吧,看起来我们有一些企鹅。👍
或者,如果您安装了 seaborn 、import seaborn as sns并运行df_penguins = sns.load_dataset('penguins'),这个数据集可以通过 seaborn 加载。
在将一个新数据集读入 DataFrame 后,我的下一步是使用df.info()来获取关于它的一些信息。
df_penguins.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 344 entries, 0 to 343
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 species 344 non-null object
1 island 344 non-null object
2 culmen_length_mm 342 non-null float64
3 culmen_depth_mm 342 non-null float64
4 flipper_length_mm 342 non-null float64
5 body_mass_g 342 non-null float64
6 sex 333 non-null object
dtypes: float64(4), object(3)
memory usage: 18.9+ KB
我们看到了 6 列 344 行的一些基本信息。
让我们看看 sidetable 如何帮助我们探索数据。

阿德利企鹅。资料来源:pixabay.com
探索侧桌
所有侧表方法都使用.stb访问器。关于熊猫访问器 API 的更多信息,请参见 sidetable 的作者 Chris Moffit 的这篇文章。
stb.missing()
我们要检查的第一个侧置 DataFrame 方法是stb.missing()。下面是它的使用方法:
df_penguins.stb.missing()

结果是一个数据帧,每列有缺失值的数量,按从多到少排序。它还显示总行数和每列缺失值的百分比。
有了df.info(),我们将不得不心算。🤔
或者,我们可以用df.isna().sum()按列查看所有缺失的值。
df_penguins.isna().sum()species 0
island 0
culmen_length_mm 2
culmen_depth_mm 2
flipper_length_mm 2
body_mass_g 2
sex 11
dtype: int64
但是df.isna().sum()没有包括百分比,格式也不好。说到漂亮的格式,让我们让 sidetable 的输出更漂亮。💐
df_penguins.stb.missing(style=True)

通过style=True会清除百分比的列格式。
每当我有一堆缺少数据的列时,我打算使用stb.missing()。
stb.freq()
现在让我们看看 sidetable DataFrame 方法.stb.freq(),sidetable 包中的主要课程。🍲
让我们看看物种类别。
df_penguins.stb.freq(['species'])

stb.freq()的结果就像组合有和没有normalize=True参数的 value_counts、累积计数和累积百分比。与stb.missing()一样,我们可以通过传递style=true使样式更好。🎉
df_penguins.stb.freq(['species'], style=True)

那很方便。😀
注意,所有 sidetable 方法都在数据帧上操作并返回一个数据帧。
type(df_penguins.stb.freq(['species']))pandas.core.frame.DataFrame
你知道,这些数据是名义上的,而不是顺序的,我们可能不需要累积列。我们可以通过像这样传递cum_cols=False来去掉那些列:
df_penguins.stb.freq(['species'], style=True, cum_cols=False)


巴布亚企鹅。资料来源:pixabay.com
让我们看看如果我们将多个列传递给stb.freq()会是什么样子。
df_penguins.stb.freq(['species', 'island', 'sex'])

那是相当的崩溃。让我们只看岛一栏,探索一些更随意的论点。
df_penguins.stb.freq(['island'], style=True)

如果我们只想包括占总数 50%的岛屿,会怎么样呢?这个例子有点做作,但是我们试图展示它的功能,所以请配合我。😉
通过thresh=.5仅显示占总数 50%的岛屿。
df_penguins.stb.freq(['island'], style=True, thresh=.5)

请注意,这可能有点令人困惑。我们没有显示至少占总数 50%的所有岛屿。我们显示了达到累积阈值的所有岛屿。
以下是阈值为 0.9 时的情况。
df_penguins.stb.freq(['island'], style=True, thresh=.9)

如果你想改变提交值的标签,你可以像这样传递other_label='my_label':
df_penguins.stb.freq(['island'], style=True, thresh=.9, other_label='Other Islands')

传递value='my_column'对该列中的值求和并显示,而不是计算出现次数。这对于当前的数据集来说没有什么意义,但这是一个值得了解的好特性。下面是输出的样子:
df_penguins.stb.freq(['island'], value='flipper_length_mm')

在我们的例子中,原始列没有大写,但是 sidetable 创建的新列是大写的。如果希望列的大小写相匹配,可以调整生成的数据帧。
freq_table = df_penguins.stb.freq(['island'])
freq_table.columns = freq_table.columns.str.title()
freq_table

其他 EDA 选项
Sidetable 的stb.freq()很不错,因为它很轻便,内容丰富。在某些情况下,您可能需要不同的工具。
如果我在寻找数字数据的描述性统计,我经常使用df.describe()。
df_penguins.describe()

传递include='all'显示了一些关于非数字列的信息,但是事情有点混乱。🙁
df_penguins.describe(include='all')

如果你想要更多关于你的数据的信息,可以查看一下熊猫简介包。它提供了一个全面的报告,包括描述性的统计数据、直方图、相关性等等。挺牛逼的。然而,它可能需要一段时间来运行,并且对于许多用例来说有点多。
现在让我们看看最后一个 sidetable 方法。
stb .小计()
如果您想显示一个带有显示数字列总和的总计行的数据帧,使用stb.subtotal()。
df_penguins.stb.subtotal().tail()

这对于财务文档和其他想要在同一个表中显示数据和总计的情况非常方便。
通过组合df.groupby()和stb.subtotal(),你得到一个总计和格式良好的小计。
这是一个由物种和性别组成的分组,以及岛屿的数量。
df_penguins.groupby(['species', 'sex']).agg(dict(island='count'))

在我们的例子中,这不是什么惊天动地的信息,但是它显示了每个组中的计数。
如果有一些小计和总计,这些信息会更容易理解。stb.subtotal()为我们补充那些。🎉
df_penguins.groupby(['species', 'sex']).agg(dict(island='count')).stb.subtotal()

分类汇总通常对财务数据或序数数据很有帮助。让我在谷歌工作表或微软 Excel 中做预算和财务报告变得更加愉快。
包装
您已经看到了如何使用 sidetable 快速显示缺失值,制作格式良好的频率表,以及显示总计和小计。这是一个方便的小图书馆。👍
概述
以下是 API 的概述:
stb.missing()-显示关于缺失值的有用信息。stb.freq()-显示列的计数、百分比和累积信息。stb.subtotal()-向数据帧添加总计行。如果应用于 groupby,则添加每组的小计信息。
将style=True传递给stb.missing()和stb.freq()会使输出得到很好的格式化。还有许多其他参数可以传递给stb.freq()来修改输出。
我希望这篇 sidetable 的介绍对你有所帮助。如果你有,请在你最喜欢的社交媒体上分享,这样其他人也可以找到它。😀
我最初在这里为 Deepnote 发表这篇文章。获得早期访问权后,您可以在那里将文章作为笔记本运行。🚀
对于这篇文章,我使用了 Ted Petrou的新的 Jupyter to Medium 包来帮助从 Jupyter 笔记本转换到 Medium。谢谢你的大包裹,泰德!👍
我写关于数据科学、 Python 、 SQL 和其他技术主题的文章。如果你对这些感兴趣,请注册我的邮件列表,那里有很棒的数据科学资源,点击这里阅读更多内容,帮助你提高技能。😀
巴布亚企鹅。资料来源:pixabay.com
快乐的侧桌!🚀
使用深度学习的手语识别
双摄像头第一人称视觉翻译系统
TL;提出了一种使用卷积神经网络的双 cam 第一视觉翻译系统。开发了一个原型来识别 24 种手势。视觉系统由头戴式摄像机和胸戴式摄像机组成,机器学习模型由两个卷积神经网络组成,每个摄像机一个。
介绍
手语识别是一个多年来一直在研究中解决的问题。然而,在我们的社会中,我们仍然远远没有找到一个完整的解决方案。
在为解决这个问题而开发的工作中,大部分是基于两种基本方法:基于接触的系统,如传感器手套;或者基于视觉的系统,只使用摄像机。后者便宜得多,深度学习的蓬勃发展使其更具吸引力。
这篇文章介绍了一个使用卷积神经网络的双摄像头第一人称视觉手语翻译系统的原型。这篇文章分为三个主要部分:系统设计,数据集,深度学习模型训练和评估。
视觉系统
视觉是手语中的一个关键因素,每种手语都旨在被位于另一个人前面的一个人理解,从这个角度来看,一个手势是完全可以观察到的。从另一个角度看一个手势很难或者几乎不可能被理解,因为不是每个手指的位置和动作都能被观察到。
试图从第一视觉的角度理解手语也有同样的局限性,一些手势最终看起来也是一样的。但是,这种模糊性可以通过在不同的位置放置更多的摄像机来解决。这样,一台摄像机看不到的东西,可以被另一台摄像机完美地观察到。
视觉系统由两个摄像头组成:一个头戴式摄像头和一个胸戴式摄像头。有了这两个摄像头,我们可以获得标志的两个不同视图,俯视图和仰视图,它们一起工作来识别标志。

从俯视图和仰视图的角度看,与巴拿马手语中的字母 Q 相对应的标志(图片由作者提供)
这种设计的另一个好处是用户将获得自主权。这在传统方法中是无法实现的,在传统方法中,用户不是残障人士,而是需要在签名人进行签名时拿出带有摄像头的系统并对签名人进行对焦的第三人。
资料组
为了开发该系统的第一个原型,使用了来自巴拿马手动字母表的 24 个静态标志的数据集。

巴拿马手语字母(来源: SENADIS,Lengua de seas paname as)
为了将该问题建模为图像识别问题,诸如字母 J、Z、RR 和等动态手势被丢弃,因为它们增加了解决方案的额外复杂性。
数据收集和预处理
为了收集数据集,要求四个用户佩戴视觉系统,并在 10 秒钟内执行每个手势,同时两台摄像机以 640x480 像素的分辨率进行记录。
要求用户在三种不同的场景中执行该过程:室内、室外和绿色背景场景。对于室内和室外场景,用户被要求在执行手势时四处移动,以便获得具有不同背景、光源和位置的图像。绿色背景场景是为数据扩充过程设计的,我们将在后面描述。
获得视频后,提取帧并将其缩小到 125x125 像素的分辨率。

从左至右:绿色背景场景,室内和室外(图片由作者提供)
数据扩充
由于进入卷积神经网络之前的预处理被简化为仅仅是重新缩放,背景将总是被传递给模型。在这种情况下,模型需要能够识别标志,尽管它可能有不同的背景。
为了提高模型的泛化能力,人为地添加了更多的不同背景的图像来代替绿色背景。这样可以获得更多的数据,而不需要投入太多的时间。

带有新背景的图像(作者提供的图像)
在训练过程中,还添加了另一个数据扩充过程,包括执行一些转换,如一些旋转、光强变化和重新缩放。

旋转、光强度和缩放的变化(图片由作者提供)
选择这两个数据扩充过程是为了帮助提高模型的泛化能力。
顶视图和底视图数据集
该问题被建模为具有 24 个类别的多类别分类问题,并且该问题本身被分成两个更小的多类别分类问题。
决定哪些手势将被用顶视图模型分类以及哪些手势将被用底视图模型分类的方法是选择从底视图角度看太相似的所有手势作为将被从顶视图模型分类的手势,并且剩余的手势将被由底视图模型分类。所以基本上,俯视图模型是用来解决歧义的。
因此,数据集分为两部分,每个模型一部分,如下表所示。

深度学习模型
作为最先进的技术,卷积神经网络是面对这一问题的选择。它被训练成两个模型:一个模型用于俯视图,一个模型用于仰视图。
体系结构
相同的卷积神经网络架构用于俯视图和仰视图模型,唯一的区别是输出单元的数量。
下图显示了卷积神经网络的体系结构。

卷积神经网络体系结构
为了提高模型的泛化能力,在全连接层中使用层间丢弃技术来提高模型性能。
估价
这些模型在一个测试集中进行了评估,测试数据对应于系统在室内的正常使用,换句话说,在背景中出现了一个充当观察者的人,类似于上图中的输入图像(卷积神经网络架构)。结果如下所示。

虽然模型学会了对一些标志进行分类,比如 Q,R,H;总的来说,结果有点令人沮丧。这些模型的泛化能力似乎不太好。然而,该模型也用显示系统潜力的实时数据进行了测试。
底部视图模型用具有绿色均匀背景的实时视频进行测试。我戴着胸前安装的摄像机以每秒 5 帧的速度捕捉视频,同时在我的笔记本电脑上运行底部视图模型,并尝试用手指拼写单词 fútbol(我最喜欢的西班牙语运动)。每个字母的条目都是通过点击来模拟的。结果如下面的视频所示。
与实时视频一起运行的底视图模型的演示视频
注意:由于模型的性能,我不得不重复几次,直到我有了一个好的演示视频。
结论
如果我们考虑这种系统需要理解和翻译的所有可能的手势组合,手语识别是一个困难的问题。也就是说,解决这个问题的最好方法可能是将它分成更简单的问题,这里介绍的系统将对应于其中一个问题的可能解决方案。
该系统表现不太好,但它被证明可以仅使用相机和卷积神经网络构建第一人称手语翻译系统。
据观察,该模型往往会将几个符号相互混淆,如 U 和 w。但仔细想想,也许它不需要有完美的性能,因为使用正字法校正器或单词预测器会提高翻译准确性。
下一步是分析解决方案,研究改进系统的方法。通过收集更高质量的数据,尝试更多的卷积神经网络架构,或重新设计视觉系统,可以实现一些改进。
结束词
我开发这个项目作为我大学论文工作的一部分,我的动力来自于在新事物中工作的感觉。虽然结果不太好,但我认为这是一个很好的起点,可以让系统变得更好、更大。
如果你对这项工作感兴趣,这里有我的论文的链接
感谢阅读!
Linux 中的信号
我写这篇文章是为了做笔记的参考。我希望分享这篇文章对那些有兴趣了解 Linux 的人有所帮助。如果你发现任何错误或错别字,评论他们,我会尽快纠正。谢谢,继续学习。

一旦你开始熟悉 Linux 系统,信号是你经常会遇到的基本事物之一。了解它们是如何工作的很重要,因为信号在过程中起着很大的作用。
像往常一样,我们将从一些基础开始,然后转移到一些高级主题。
信号是对流程的通知,表示事件已经发生。信号有时被称为软件中断,因为在大多数情况下,它们会中断程序的正常执行流程,并且它们的到来是不可预测的。
信号可以由内核或进程发送。

接收信号的不同方式
在本文的其余部分,我们将关注内核发送的信号,而不是进程。
在下列情况下,内核可以向进程发送信号:
- 当出现硬件异常并且需要将该异常通知给进程时。例如,试图除以零,或引用不可访问的内存部分。
- 一些软件事件发生在过程的控制之外,但是影响了过程。例如,输入在文件描述符上变得可用,终端窗口被调整大小,进程的 CPU 时间限制被超过,等等。
- 用户键入了一些终端特殊字符,如中断(Ctrl+C)或暂停字符(Ctrl+Z)。
内核发送的通知进程事件的信号称为传统信号。
什么是待定信号?
由于某些事件而生成信号后,它不会直接传递给进程,而是保持在一个称为挂起状态的中间状态。这在以下情况下是必需的:
- 进程现在没有安排 CPU。在这种情况下,一旦该进程下一次计划运行,就发送一个挂起信号。
- 从流程的角度来看,为了确保某个信号不会在某个关键部分执行期间到达,流程可以将信号添加到其流程的信号掩码中,信号掩码是一组当前被阻止传递的信号。进程的信号掩码是每个进程的属性。如果信号在被阻塞时生成,它将保持挂起状态,直到后来被解除阻塞。有各种系统调用允许一个进程从它的信号掩码中添加和删除信号。
当信号到达时会发生什么?
当一个信号即将被发送时,根据该信号发生以下默认动作之一:
- 信号被忽略,也就是说,它被内核丢弃,对进程没有影响。(该过程仍然不知道该事件已经发生。)
- 进程被终止,也称为异常进程终止,与程序使用 exit()终止时发生的正常进程终止相反。
- 生成一个核心转储文件,并终止该过程。
- 暂停或恢复进程的执行。
一个进程可以不接受特定信号的默认动作,而是通过改变信号传递时发生的动作来设置信号的处理。程序可以设置以下配置之一:
- 默认动作应该发生。这有助于撤销之前对信号配置的更改,而不是将其更改为默认值。
- 该信号被忽略,而不是终止该过程的默认动作。
- 执行已建立的信号处理器。信号处理器是一个定制的功能,它执行适当的任务以响应信号的传递。当信号到达时通知内核应该调用一个处理函数,这被称为建立或安装一个信号处理程序。不可能将信号的配置设置为终止或转储核心,除非其中之一是信号的默认配置。
信号 SIGKILL 和 SIGSTOP 不能被捕捉、阻止或忽略。
怎么发信号?
可以使用 kill 系统调用或 kill 命令发送信号,并指定所需的进程 pid。
我们使用术语‘kill’是因为大多数信号终止一个进程的默认动作。
传递给 kill 的过程 pid 根据以下情况进行解释:
- 如果 pid > 0,则信号被发送到具有指定 pid 的特定进程。
- 如果 pid = 0,则信号被发送到同一进程组中的每个进程。
- 如果 pid < -1, then the signal is sent to every process in the process group whose process group id is modulus of |pid| specified.
- If pid = -1, then the signal is sent to all the processes for which the calling process has permission to send a signal, except init 和调用过程本身。以这种方式发送的信号被称为广播信号。
还存在另一个函数 raise() ,它向调用进程本身发送信号。这样发送信号,使得该信号甚至在 raise 函数返回之前就被进程接收到。请将此视为 IP 网络的本地回环类比。
对于单线程实现,int raise(int sig)被实现为kill(getpid(), sig)。
对于多线程实现,int raise(int sig)被实现为pthread_kill(pthread_self(), sig)。
零信号
发送信号的一个有趣的用例是检查进程的存在。如果调用 kill() 系统调用时,信号参数为‘0’,也称为空信号,则不会发送任何信号,它只是执行错误检查,以查看是否可以向进程发送信号。
这意味着我们可以使用这种机制来检查进程的存在。当试图发送空信号时,可能会出现以下响应之一:
- 如果出现错误 ESRCH,则意味着目标进程不存在。
- 如果出现错误 EPERM,那么这意味着目标进程存在,但是您(调用方进程)没有足够的权限向该进程发送信号。
- 如果调用成功,那么这意味着目标进程存在,并且调用者有权向它发送信号。
各种可用信号
通过对应一个特定的信号编号,我们可以使用 strsignal 函数来获得信号描述。此外,您可以查看信号的手册页。
下面列出了原始 POSIX . 1–1990 标准中描述的信号。
Signal Value Action Comment
────────────────────────────────────────────────────────────────────
SIGHUP 1 Term Hangup detected on controlling
terminal
or death of controlling process
SIGINT 2 Term Interrupt from keyboard
SIGQUIT 3 Core Quit from keyboard
SIGILL 4 Core Illegal Instruction
SIGABRT 6 Core Abort signal from abort(3)
SIGFPE 8 Core Floating point exception
SIGKILL 9 Term Kill signal
SIGSEGV 11 Core Invalid memory reference
SIGPIPE 13 Term Broken pipe: write to pipe with no
readers
SIGALRM 14 Term Timer signal from alarm(2)
SIGTERM 15 Term Termination signal
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
SIGCHLD 20,17,18 Ign Child stopped or terminated
SIGCONT 19,18,25 Cont Continue if stopped
SIGSTOP 17,19,23 Stop Stop process
SIGTSTP 18,20,24 Stop Stop typed at terminal
SIGTTIN 21,21,26 Stop Terminal input for background
process
SIGTTOU 22,22,27 Stop Terminal output for background
process
使用信号集来表示一组信号。像 sigaction() 和 sigprocmask() 这样的 API 可以使用信号集,它们允许程序指定一组信号。
每个进程的挂起信号集
如果一个进程接收到一个当前正在阻塞的信号,那么它将被添加到该进程的挂起信号集中。为了确定哪些信号对于一个进程是挂起的,一个进程可以使用int sigpending(sigset_t* set);系统调用,它通过修改set 结构返回调用进程挂起的信号集。
标准信号没有排队,因此当一个信号多次到达时,它被添加到待定信号集合(当然,它只有一个副本),并且当信号被解除阻塞时,它稍后仅被传送一次。
信号 API 概述
信号是对一个进程的事件已经发生的通知,可以由内核、另一个进程或它自己发送。信号的传递是异步的。您可以使用kill系统调用向进程发送信号。当信号到达时,可以通过使用signal()或sigaction()建立信号处理器来修改进程的行为。
标准信号不排队,也就是说,发送到一个进程的多个信号将只作为一个被检索。
信号集用于同时处理多个信号。许多系统调用接受信号集。
当一个信号到达时,一个进程可以选择阻塞它,并且在稍后的时间,可以使用sigpending()系统调用获取一组未决信号,这将给出一组处于未决状态的信号。使用pause()系统调用,进程可以暂停执行,直到信号到达。
签名欺诈检测-一种高级分析方法

签名欺诈检测
在我的上一篇文章中,我以一种通用的方式讨论了高级分析在欺诈领域的应用。在这篇文章中,我将深入研究欺诈的一个具体领域——签名伪造。难怪机构和企业认为签名是认证交易的主要方式。人们签署支票,批准文件和合同,验证信用卡交易,并通过签名验证活动。随着签名文档的数量(及其可用性)大幅增加,签名欺诈也在增加。
根据最近的研究,仅支票欺诈每年就给银行造成约 9 亿美元的损失,其中 22%的欺诈支票归因于签名欺诈。显然,美国每年签发的支票超过 275 亿张(根据 2010 年美联储支付研究),对每天处理的数亿张支票进行人工签名的可视化比较是不切实际的。
大数据、基于分布式 Hadoop 的平台(如 MapR)的出现,使得经济高效地存储和处理大量签名图像成为可能。这使企业能够使用全面的历史交易数据,通过开发算法来发现欺诈签名的模式,从而实现传统视觉比较的自动化。
签名的艺术和科学:
在介绍自动签名验证的类型和详细方法之前,让我们了解一些与签名过程相关的概念和一些流行的神话,签名伪造的类型,以及静态签名图像的传统视觉比较的漏洞。
误解:同一个人的真实签名在所有交易中都完全相似
现实:签名的身体动作需要协调大脑、眼睛、手臂、手指、肌肉和神经。考虑到游戏中的所有因素,难怪人们每次都不会签完全相同的名字:一些元素可能会被省略或更改。个性、情绪状态、健康状况、年龄、个人签名的条件、签名可用的空间以及许多其他因素都会影响签名到签名的偏差。
签名伪造的类型:
在现实生活中,签名伪造是一个伪造者主要关注准确性而不是流畅性的事件。
签名伪造分为以下三类:
1.随机/盲目伪造—通常与真实签名很少或没有相似性。这种类型的伪造是在伪造者无法获得真实签名的情况下产生的。
2.不熟练的(描摹)伪造:签名被描摹在上,看起来像下面纸上的一个淡淡的凹痕。这个缩进可以作为签名的参考。
3.熟练伪造——由能够接触到一个或多个真实签名样本并能在大量练习后模仿它的犯罪者制造。熟练伪造是所有伪造中最难鉴别的。

有效的签名验证系统必须能够通过可靠的定制算法来检测所有这些类型的伪造。
人工验证难题:
由于主观决定和因专业知识、疲劳、情绪、工作条件等人为因素而变化很大,人工验证更容易出错且不一致,在熟练伪造的情况下(离线方法)会导致以下情况:
错误拒绝:错误地拒绝标记欺诈性交易(当它们不是欺诈性交易时),对客户满意度产生负面影响,通常称为 I 型错误。
虚假接受:真实签名和熟练的伪造,操作者将其作为真实签名接受,导致财务和声誉损失,通常称为第二类错误。

精确验证系统目标是最小化两种类型的误差。
标志性特征:
让我们来了解一下人类文档检查人员区分欺诈和真实的签名特征。以下是用于签名验证的静态和动态特征的非详尽列表:
摇晃的笔迹(静态)
提笔(动态)
修饰的迹象(静态和动态)
字母比例(静态)
签名形状/尺寸(静态)
倾斜/成角度(静态)
两个或多个签名非常相似(静态)
速度(动态)
笔压(动态)
压力变化模式(动态)
加速模式(动态)
曲线的平滑度(静态)
根据验证环境和样本收集条件,并非所有特性都可供分析
自动签名验证系统的类型:
如所讨论的,根据可行的(可用的)签名特征提取和商业/功能需求,市场上存在两种类型的签名验证系统。
a)离线签名验证:部署在无法监控个人实时签名活动的地方。在仔细检查签名的纸质文档的应用中,只有静态的二维图像可用于验证。由于明显原因,在这种类型的验证引擎中,动态特性。为了解决这些重要信息的丢失并产生高度准确的签名比较结果,离线签名验证系统必须模仿人类法医文档检查员使用的方法和途径。这种方法严重依赖于繁琐的图像预处理(图像缩放、大小调整、裁剪、旋转、滤波、梯度方向直方图阈值、哈希标记等)。)和娴熟的机器学习技能。这里主要使用的特征本质上是静态的——图像纹理(小波描述符)、几何和拓扑(形状、大小纵横比等)。)、笔画位置、手写相似性等。
尽管存在许多限制,但在大多数现实生活中,支票交易和数字文档验证签名是预先执行的,并且没有实时签名监控的范围来捕捉动态特征。
对于离线签名验证,机器学习任务可以进一步分类为 1)一般学习(与人无关)-通过以 1∶1 的基础将被质疑的签名与每个已知签名进行比较来执行验证任务,以及 2)特殊学习(与人相关)-验证被质疑的签名是否落入同一个人的多个真实签名的变化范围内。
b)在线签名验证:签名是基于重复动作的反射动作,而不是故意控制肌肉,即使精确的伪造也比真正的签名需要更长的时间才能产生。顾名思义,这种类型的验证系统捕捉关键的动态特征,如速度、加速度和压力等。,是可行的。这种类型的系统更准确,因为即使对于复印机或专家来说,模仿原始签名者的独特行为模式和特征实际上也是不可能的。
实验简介:
让我们讨论一个在模拟环境中的简单的离线验证解决方案。对于该研究,从 40 个人中准备数据,每个人贡献 25 个签名,因此具有 1000 个真实签名。然后随机选择受试者伪造另一个人的签名,15 个/个人,这样就有 600 个(相当于欺诈的过度抽样)伪造。现在有 25 个真实签名/人和 12 个伪造签名/人,数据被随机分成训练(75%)和验证(25%)数据,确保在训练数据中至少有 15 个真实签名/人。目标是建立一个离线算法签名验证系统,该系统采用独立于个人的学习方法,是一个引擎,用于确定验证中的被质疑签名是否属于某个特定的个人。

图:真实签名样本图:个人样本(真实和伪造)
解决方案框架:
独立于个人的监督学习:学习问题被转换成两类分类问题,其中输入由一对签名之间的差异(相异度)组成,并且真实签名出现的几率根据从良好(真实的)和不良(伪造的)群体的距离(配对签名的相异度分数)的适当参数分布中引用的似然比(LR)来计算。然后,将一个人的来自其真实签名的被质疑签名拟合到该分布,以计算 LR 分数,并且基于 LR 和预先指定的阈值(基于最大准确度),对于特定的人,将采取被质疑签名(来自测试数据)是否是真实的分类决定。
模型方程

在哪里
P(Dg(i)|d)是距离 d 处 Dg(真实)分布的概率密度函数值
P(Db(i)|d)是距离 d 处 Db(伪造)分布的概率密度函数值
- n 是用于 1:1 比较的来自一个人的已知样本的数量
ψ是预先指定的大于 1 的阈值
尽管建模任务是直接的,但是需要大量的图像预处理来基于提取的静态特征计算签名对之间的距离/距离向量(d)。也适合参数模型的选择和最佳截止值的调整。
涉及的步骤:
a)特征提取:这是一个高度技术性的领域,涉及复杂的图像处理,以提取特定人的区别要素和要素组合。
1)图像预处理和网格形成:每个签名经过灰度变换后,进行椒盐噪声去除和倾斜归一化处理。然后,在适当的大小调整、裁剪和其他扩充过程之后,每幅图像都用 4x7 网格重新构建
2)二进制特征向量提取:从像素图像网格和相应的局部直方图单元中提取 GSC(梯度、结构和凹度)特征图,该特征图被量化为 1024 比特的二进制特征向量(G、S 和 C 特征的求和比特)。

图:图像网格和 1024 位二进制特征向量
b)相似性(距离)度量:开发用于成对图像的点对点匹配的高斯界标(exp(ri J2/2σ2))集,并且使用总体相似性或距离度量来计算表示两个签名之间匹配强度的分数。相似性度量将成对数据从特征空间转换到距离空间。几个。这里使用的是汉明距离法。

(很抱歉由于篇幅限制,没有在这里详细说明这些主题,我们将在另一篇文章中讨论。)
c)模型训练(分布拟合):训练数据的这些成对距离(d)被分类成两个向量,所有真实签名对之间的距离的 Dg 向量(样本真正来自相同的人)和所有伪造签名对之间的距离的 Db 向量(样本来自不同的人)。这两个距离向量可以使用已知的分布如高斯或伽马来建模。在这个例子中,伽马分布与数据吻合得很好。
d)似然比(LR)和分类决策:在上述预处理和距离得分(成对相异)点被投影到拟合的密度曲线上以获得 LR 值-P(Dg|d)/ P(Db|d)之后,来自未标记数据(这里来自验证)的特定人的可疑签名与该人的真实签名 1∶1 匹配。如果似然比大于 1,则分类决定是两个样本确实属于同一个人,如果比值小于 1,则它们属于不同的人。如果一个人总共有 N 个已知样本,那么对于一个有问题的样本,可以执行 N 个 1∶1 的验证,并且将似然比相乘。为方便起见,采用对数似然比(LLR)而不是似然比。

图:分布拟合和分类决策
性能评估:尽管有明显的重叠区域,上述分布在区分两个区域(真实和欺诈)方面做得相当好。显然,判决边界由 LLR 的符号给出,并且可以使用阈值α来构造修改后的判决边界,使得 log P(Dg | d)log P(Db | d)>α。定义为[1-((错误接受+错误拒绝)/2)]的模型精度在特定的α值时最大。这涉及模型调整,对于指定数量的已知样本,α的最佳设置表示为工作点。在由不同数量的已知样本(12-15 个)生成的 ROC 曲线中,工作点显示为' * '。整体准确率在 77%左右。

图:模型调优和性能
改进和前进的道路:
通过这个实验和简单的解决方案,达到了适度的准确性。然而,精度可以通过更大的训练数据、与其他模型的拟合和集成来提高,包括非参数方法(深度学习、CNN 等)。).此外,将图像对之间的其他距离度量(例如,Levenshtein 距离、切角距离)合并为附加特征和/或对这些相异特征进行简单/加权平均,将使相异度量更加稳健和可靠,从而为模型增加更多的辨别能力。
最后,尖端的签名验证系统需要具有适应性、灵活性和准确性。这需要对不断增长的数据集进行深入分析,并对生产模型进行持续更新,以便效率随着时间的推移保持稳定,这与人工操作员在高容量情况下获得的结果不同。
使用 Python 测试测量数据的重要性
如果驾驶员是盲目的,数据驱动的结果是无用的,但是显著性测试可以为您指明方向

对婚姻状况是否会影响人们投票方式的视觉探索。投票率明显高于平均投票率的群体(最左边一列)显示为绿色,较低的群体显示为红色,不显著的结果显示为白色。
世界上大多数人会通过猜测或凭直觉来做决定。他们要么是幸运的,要么是错误的。— 混合面板
Mixpanel 的6500 万美元投资者推介的开场白引人注目。要么你在用数据,要么你就是个傻子。我想补充一句口头禅。
世界上大多数人不去想 统计意义 。它们将是数据驱动的,但方向是错误的。— 盖尔
好吧,Mixpanel 的更好,但你明白了。
投票意向和婚姻状况
比方说,我们在政治民意调查中发现了一个趋势,可以帮助我们决定谁是我们竞选活动的目标。比如已婚人士。他们投票的方式与单身人士不同吗?我们应该在单身酒吧竞选吗?
开源库 Quantipy 可以读取所有主要的调查平台数据类型,包括 SPSS 的.sav文件。这张来自英国 2019 年大选。
import quantipy as qp
dataset = qp.DataSet('Elections 2019')
dataset.read_spss('election survey.sav')
让我们看看从原始数据中选择的几个列是什么样子的:
dataset[['Gender',
'VoteIntention',
'MaritalStatus',
'weight']].head()

为了加快计算速度,SPSS 将不同的答案存储为数字,然后使用元数据将这些数字映射到答案。(稍后,我们将讨论如何计算一个weight列来改进我们的结果)。现在让我们坚持投票意向:
dataset.meta('VoteIntention')

比较对元数据的回应,我们看到第一个回应都来自保守派选民,而这些相同回应的婚姻状况各不相同。它会影响人们投票的方式吗?让我们来计算一下:
dataset.crosstab('VoteIntention',
'MaritalStatus',
pct=True, #percentages, not frequencies
w='weight') #weigh the results

啊哈!所以,已婚人士投 CON,单身人士投 LAB。也许这是年龄的问题。但是民事伴侣关系中的人是怎么回事呢?他们更有可能投票给保守党而不是工党,在整个人口中,保守党的比例为 54%,工党为 16%,而保守党为 40%,工党为 33%。
在我们开始写新闻稿之前,我们必须问自己:这是真的吗,还是只是数据中的噪音?
使用 Python 测试测量数据的重要性
测试调查结果的重要性(sig 测试)可能是一项艰巨的任务。数据本身可能是复杂的,当它被加权以更好地代表被调查的人口时,它变得更加棘手。有时所谓的有效基数应该用于测试,有时不用于测试。市场研究行业还依赖于使用专有程序,如 UNICOM Intelligence(又名 Dimensions)和 Askia,能够复制这些应用程序的结果非常重要。
Quantipy 有助于应对所有这些挑战。让我们运行一个复制维度设置的基本 sig-test,它使用一个汇集的方差并控制由加权和重叠样本引入的偏差。
batch = dataset.add_batch(name='vote_intention')
batch.add_downbreak('VoteIntention')
batch.add_crossbreak('MaritalStatus')
batch.weights.append('weight')
batch.set_sigtests([0.05])
stack = dataset.populate(['vote_intention'])
stack.aggregate(['counts', 'cbase'],
batches=['vote_intention'], verbose=False)
stack.add_tests(['vote_intention'])
在上面的代码中,我们使用 Quantipy 的batch机制,以防我们想要计算大量变量来填充我们的表格或 PowerPoint 图表。当我们运行代码时,我们得到一个所谓的stack来存储我们所有的结果;计算出的百分比、基数和显著性矩阵。矩阵看起来像这样:

NaN 表示无显著差异,星号标记的结果有效基数太低(答卷人太少,不显著),一组数字表示显著差异。在上面的例子中,已婚的反对者拥有数组[1,4],因此明显高于单身投票者和同居伴侣。单身选民在工党一栏中有结果[2,4],因此比已婚选民和同居选民更有可能投票给工党,但重要的是,民事伴侣一栏没有足够多的回应,因此不重要。
我们现在可以利用任何 python 网络应用环境(Django、Flask 等)。)来显示一个交互式的显著性表。下面是一个 Django 应用程序,它使用下拉菜单进行过滤,并将相关的响应子集发送到 sig-test 中。当重要的测试被应用和可视化时,探索数据子组的不同投票意图呈现出一个全新的维度。

民意测验结果意义的交互探索。绿色表示 a 结果明显高于“整体”组,红色表示较低,白色表示没有显著差异(通常是因为回答的数量太低)。
所以,不要发出关于民事伴侣关系中的人们将如何投票的新闻稿,因为需要更多的数据来获得有意义的见解,以了解结果是否重要,或者它是否只是数据中试图将我们引入歧途的噪音。
盖尔·弗雷松是 Datasmoothie 的联合创始人,这是一个专门从事调查数据分析和可视化自动化的平台。如果你对使用开源软件进行调查数据分析感兴趣,注册我们的时事通讯,名为自发认知。
基于神经网络的有效波预测
使用 Pytorch 进行试驾并比较车型

序言
所以,现在我想用 PyTorch 测试一下我的技能。我是 PyTorch 的新手,以前我使用 Tensorflow 建立一个 ML 模型。我已经阅读了所有的基础教程,并准备使用真实的数据建立一个真实的模型。你最喜欢在哪个网站找到真实数据来测试你的模型?对我来说是 kaggle.com。在滚动所有可用的数据集后,我选择这个 wave 数据集。下载下来准备玩玩。
数据集的第一瞥

作者图片
这里我们有数据捕获的日期和时间,有效波高(Hs),最大波高(Hmax),过零波周期(Tz)(呃,我不知道这是什么),峰值能量波周期(Tp)(能量?在什么?我不知道),峰值方向(我想这是波从哪里来的一个方向?),最后是海面温度(SST)。我们有一个 30 分钟时间分辨率的数据集。-99.9是一个我认为没有数据的标志。我对海洋学数据不熟悉,但我会尽力而为。
在所有可用的列中,我所理解的只是 Hs、Hmax 和 SST(当然还有日期和时间)。我会试着预测他的。
Hs 预测
我只会玩我理解的数据(Hs,Hmax,SST)。让我们看看 Hs 和另外两个变量之间的相关性。在这个过程中,我们必须除掉-99.9。因此,在我们选择的 3 个变量中的任何一个变量中包含该数字的数据都将被忽略。这是代码
这是 Hs 和 Hmax 的散点图

作者图片
看起来非常好。他们的相关系数是 0.97,近乎完美。但是等等,Hmax是观测到的最高浪高,Hs是最高浪高的平均值。所以如果我们把这个变量作为 Hs 的一个预测因子包括进来,那只是多余的 Hs 。对于SST

作者图片
相关系数为 0.26。看起来很糟糕。所以最后的选择只是用Hs来预测Hs。我们将尝试使用Hs的历史时间序列来预测未来Hs。
对于第一次尝试,我们使用 3 小时的 Hs 数据来预测接下来的 30 分钟。在此之前,我们将首先尝试构建一个参数和标签数据集。如果我们每次尝试对模型进行实验时,都试图合并构建参数、标签部分和模型部分,这将会非常耗时。
现在使用已经构建的参数和标签数据,我们将尝试使用所有数据预测Hs。让我们使用一个多层感知器模型。
这里我们用最后的 10000 个数据作为测试数据,剩下的是训练数据。现在,我们如何对该模型进行基准测试?让我们用数据的标准差。为什么?如果你仔细看看标准差的公式,实际上和只输出数据平均值的模型的 RMSE是一样的。


如果我们对数据一无所知,这是最简单的预测方法。Hs 数据的标准偏差为 0.5。所以,模型的误差必须低于这个值才能做出好的预测。
我们 MLP 模型的 RMSE 是

0.077(图片作者)
是Hs数据标准差的 0.15。让我们看看这个 MLP 模型的训练和测试误差的图表。

作者图片
在早期阶段,它收敛得非常快,后来它慢下来。无论如何,在我在这里发布这个结果和图表之前,我尝试了 MLP 超参数的许多组合,对于每个超参数的组合,你都会得到稍微不同的结果和图表(是的,即使你不做任何改变,只是重新运行模型,你也会得到稍微不同的结果,因为这是神经网络的本质)。我觉得这是目前为止最好的组合。
我们能改善这一点吗?也许,让我们试着使用长短期记忆(LSTM)模型。
RMSE 是

0.76(图片由作者提供)
误差正在改善,但只是一点点。这是 LSTM 的训练和测试图。

它收敛的方式和 MLP 一样(图片由作者提供)
该模型在早期收敛非常快,之后像 MLP 一样以指数速度减慢。
下一次尝试,让我们只使用一部分数据。让我们只使用第 3400 个数据,然后倒数第 96 个将是测试数据。只需在代码中编辑testing_data_num、all_param和all_label即可。
这是 MLP 的结果

作者图片

作者图片
对于 LSTM 来说

作者图片

作者图片
耶,越来越好了,但这一次,MLP 比 LSTM 好。正如您在训练和测试图中看到的,尽管训练数据中存在波动,但测试数据的误差在稳步下降。这个故事的寓意是,当你的训练误差增加或波动时不要害怕,这并不意味着同样的事情会发生在你的测试数据中。这只是算法概括你的模型的一种方式。
收场白
这就是使用 PyTorch 的试驾。你还可以改进这个模型,比如尝试预测Hs但在未来多时间步,或者只是调整超参数以获得更好的结果。你可以在这里得到完整的代码。另一篇文章再见。
参考
https://www . ka ggle . com/jolasa/waves-measuring-buoys-data-mooloolaba(波浪数据集)
https://en.wikipedia.org/wiki/Standard_deviation
意义重大?你真的是说可辨别的
关于统计显著性的两个常见错误短语

伊恩·帕内洛在的照片 https://www . pexels . com/photo/放大镜教科书-4494644/
(注:2020 年 10 月 13 日,我将“检测”改为“辨别”,以避免与信号检测或异常检测等领域相关的分析混淆。)
统计学意义从来都不意味着科学上的重要性。…总之,“统计显著性”——不要说也不要用。( Wasserstein 等人,2019 年,在美国统计协会的出版物《美国统计学家》)
每当我听到一位讲师、主持人或研究人员说“显著的”,而他们的意思显然是“统计上显著的”,你可能会看到我抽搐(“T8”),这实际上与“临床上显著”或“科学上显著”没有任何关系。参见瓦瑟斯坦等人,2019 ,以及瓦瑟斯坦和耶戈,2016 。这些认知上的打嗝把我从他们原本谨慎的科学叙述中拉了出来——让我担心他们可能从根本上误解了他们的分析结果。
这肯定不是你想从你的统计同事那里听到的!因此,这里是我的简短尝试,以帮助纠正关于研究结果的两个常见短语。它们是错误的,因为它们通常被误解。
我将分享每个错误的短语,它的解释,和一个更好的短语。如果你感兴趣,我在最后提供了错误短语 1 的详细推理。(作为练习,你应该试着对错误的短语 2 应用类似的推理。)
(如果你想通过一个带有代码和一些数学的 R 中的工作示例来深入了解细节,请参见我之前的帖子: 混淆 P 值与临床影响:显著性谬误 )
错误短语 1:减少/增加
结果显示 D 显著降低。

照片由 Anthony 在拍摄 https://www . pexels . com/photo/animals-avian-beaks-birds-133615/
解释
- 常见误解:结果中出现了具有科学或临床意义的、重要的、有意义的或有用的 D 减少。
- 正确的解释*: 有显著的统计证据表明,平均结果存在真实的未知变化(即减少/增加),且不为零(例如非零)。如果这项研究设计和执行得当,那么这一证据表明,我们从样本中计算出的 D 的减少是对真实的未知的 c 变化的一个很好的估计。
相关的统计测试结果说绝对没有关于 C 在科学上或临床上是否显著、重要、有意义或有用的内容 ( Wasserstein et al,2019;瓦瑟斯坦和耶戈,2016 。它只是告诉我们,有足够的统计证据(随着样本量的增加而增加)来辨别C 可能不为空,因为我们的估计值 D(我们假设它是 C 的一个很好的估计值)表明 C 减少了。
一个更好的短语
结果中 D 的减少。
具体来说,在结果样本平均值中有一个统计学上可辨别的 D(我们假设是 C 的一个很好的估计)的减少。
错误短语 2:联想
变量 X 和 y 之间没有显著的联系。

照片由 Nextvoyage 在https://www . pexels . com/photo/white-boat-sailing-near-islands-during-golden-hour-1481096/
解释
- 常见误解:变量 X 和 y 之间没有科学或临床上显著、重要、有意义或有用的关系。
- 正确解释:没有显著的统计证据表明变量 X 和 Y 之间真实的、未知的统计关联不是空的(例如,零相关,线性关联)。如果这项研究设计和执行得当,那么这个证据表明我们从样本中计算出的关联 Z(基本上是零关联),是对真实的未知关联 a 的一个很好的估计。
相关的统计测试结果说绝对没有关于 A 在科学上或临床上是否显著、重要、有意义或有用的内容 ( Wasserstein et al,2019;沃瑟斯坦和耶戈,2016 年。它只是告诉我们,没有足够的统计证据(随着样本量的增加而增加)来辨别A 可能不为空,因为我们的估计值 Z,我们假设它是 A 的一个很好的估计值,表明基本上是零关联。
一个更好的短语
变量 X 和 Y 之间没有可识别的 表 关联。
具体来说,变量 X 和 y 之间没有统计上可辨别的联系,用 Z 来衡量(我们假设这是对 A 的一个很好的估计)
详细推理:错误短语 1
最初的短语调用了三个关键量:
- 平均结果中 C 的真实变化是未知的。如果我们有目标人群的所有相关数据,这就是我们简单计算的结果。
- 相反,我们必须从目标人群中抽取样本来估算这个数量。我们的特殊估计 D 可能接近也可能不接近 c。
- 非零(例如非零)C 的统计证据量定义为“矛盾证明”,如下所示。如果 C 真的为零(即,如果平均结果真的没有任何变化),观察到我们的估计值 D 或更极端值的概率是多少?这个概率被称为一个 p 值,通常是使用你的样本近似得到的。
对于像 D 这样的给定估计,这个 p 值随着样本量的增加而减小;即零假设的“矛盾”越来越大。“统计显著性”被宽泛地定义为这个 p 值的一些倒数:p 值越低,统计显著性越高。也就是说,如果我们从一个更大的样本中计算出相同的精确值 D,D 将会更有统计学意义。如果我们从一个更小的样本中计算出同样精确的 D 值,D 的统计意义会更小。
相关统计假设检验:
- 确实回答:“我们有多少证据证明非空 C 的存在呢?”换句话说,“我们有足够的证据来辨别一个非空的 C 吗?”
- 没有回答:“我们有多少证据证明 C 在科学或临床上是重要的、重要的、有意义的或有用的?”再次提醒,请记住的统计显著性与的科学/临床显著性完全不同。特别是, C 不可能永远具有统计显著性,因为真实数量是固定值,通常与用于估计它们的样本大小无关。
- 不回答:“D 近似 C 吗?”这是估计量(如样本平均值、MLE 估计量)和研究设计的一个属性。
这是对最后一点的一些粗略的直觉。
- 将你的评估者应用于你的整个目标人群(没有任何变化)。这只是计算某个固定的(即非随机的)量 t。
- 好的估计量对于 T 是统计一致的(即,对于样本量较大的 T 越来越无偏)。
- 但是你的估算者总会估算出一些东西!在统计机器学习中,如果你告诉它一个模式存在,你的聚类或预测算法总是会找到一个模式——即使没有模式。(感谢Daniela Witten教授在最近的一次演讲中清晰地展示了这一点,以及一些精彩的解决方案。)
- 确保 T=C 取决于你如何设计和执行你的研究:你如何制定你的科学假设,收集数据,并进行所有的分析。
所以通常的解释是错误的,原因有二:
- 它混淆了 D(已知样本量)和 C(未知总体量)。
- 它错误地声称你的样本提供了证据,证明 C 在科学或临床上是重要的、重要的、有意义的或有用的。
*注:错误短语 1
解释
- 另一个正确的解释:“有重要的统计证据表明,结果中存在真实的、未知的非空(例如,非零)均值变化(即,减少/增加)。”
这是一个微妙但重要的区别,从早期的解释,并可以暗示不同的估计方差。例如,在前后或成对设计中,如果结果对相互关联,则先取平均值然后取差值的估计量比先相减然后取平均值的估计量更易变。
实际正确的解释将取决于研究设计和统计假设。
关于作者
Daza 博士是一名生物统计学家和健康数据科学家,他为个人(n-of-1)数字健康开发因果推断方法。| ericjdaza.com🇺🇸🇵🇭@ ericjdazalinkedin.com/in/ericjdaza|statsof1.org@ stat sof 1@ fsbiostats
轮廓系数
验证聚类技术
在学习和应用了一些有监督的最大似然算法后,如最小二乘回归、逻辑回归、SVM、决策树等。我们大多数人都试图通过实现一些聚类技术,如 K-Means、DBSCAN 或 HDBSCAN,来进行一些实际操作的无监督学习。
我们通常从 K-Means 聚类开始。经过几个教程和中等故事,你将能够轻松实现 k-means 聚类。但是当你实现它的时候,一个问题开始困扰你:我们如何测量它的适合度?监督算法有许多指标来检查它们的拟合优度,如准确性、r 平方值、灵敏度、特异性等。但是,我们可以计算什么来衡量我们的聚类技术的准确性或良好性呢?这个问题的答案是剪影系数或者剪影分数。
轮廓系数:
轮廓系数或轮廓分数是用于计算聚类技术的良好性的度量。它的值范围从-1 到 1。
1:表示聚类彼此相距很远,并且可以清楚地区分。
0:表示聚类无关紧要,或者我们可以说聚类之间的距离不显著。
-1:表示以错误的方式分配簇。

作者图片
剪影得分= (b-a)/max(a,b)
在哪里
a=平均类内距离,即类内各点之间的平均距离。
b=平均聚类间距离,即所有聚类之间的平均距离。
计算轮廓分数
导入库:
import pandas as pd
import numpy as np
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
%matplotlib inline
生成一些随机数据:
为了运行聚类算法,我们生成 100 个随机点。
X= np.random.rand(50,2)
Y= 2 + np.random.rand(50,2)
Z= np.concatenate((X,Y))
Z=pd.DataFrame(Z) #converting into data frame for ease
绘制数据:
sns.scatterplot(Z[0],Z[1])
输出

作者图片
对两个聚类应用 KMeans 聚类:
KMean= KMeans(n_clusters=2)
KMean.fit(Z)
label=KMean.predict(Z)
计算剪影分数:
print(f'Silhouette Score(n=2): {silhouette_score(Z, label)}')
输出:剪影分数(n = 2):0.8062615881652
我们可以说,当轮廓分数接近 1 时,聚类彼此相距很远。
为了检查我们的轮廓分数是否提供了正确的信息,让我们创建另一个散点图,显示带标签的数据点。
sns.scatterplot(Z[0],Z[1],hue=label)
输出:

作者图片
从上图中可以清楚地看到,每个集群彼此相距很远。
让我们尝试 3 个集群:
KMean= KMeans(n_clusters=3)
KMean.fit(Z)
label=KMean.predict(Z)
print(f’Silhouette Score(n=3): {silhouette_score(Z, label)}’)
sns.scatterplot(Z[0],Z[1],hue=label,palette=’inferno_r’)
输出:
侧影分数(n = 3):0.5468638636786

作者图片
正如你在上面的图中看到的,集群没有很好的分开。簇 1 和簇 2 之间的簇间距离几乎可以忽略。这就是为什么 n= 3 的剪影分数(0.596)小于 n=2 的剪影分数(0.806)。
当处理更高维度时,轮廓分数对于验证聚类算法的工作非常有用,因为当维度大于 3 时,我们不能使用任何类型的可视化来验证聚类。
我们还可以使用轮廓分数来检查最佳聚类数。在上面的例子中,我们可以说最佳聚类数是 2,因为它的轮廓得分大于 3 个聚类的得分。
轮廓法——比肘法更好的寻找最优聚类的方法
k-Means 聚类中寻找最优聚类的剪影法深度分析

图片由 Mediamodifier 来自 Pixabay
H 超参数是定义模型的模型配置属性,在模型训练期间保持不变。可以通过调整超参数来改变模型的设计。对于 K 均值聚类,有 3 个主要的超参数需要设置,以定义模型的最佳配置:
- 聚类的初始值
- 距离测量
- 聚类数
聚类的初始值对聚类模型有很大的影响,有各种算法来初始化这些值。距离度量用于寻找到聚类中心的聚类中的点,不同的距离度量产生不同的聚类。
聚类数( k )是 K-Means 聚类中最重要的超参数。如果我们事先已经知道要将数据分组到的聚类数,那么就没有必要调整 k 的值。例如,对于 MNIST 数字分类数据集,k=10。
如果不知道 k 的最佳值,那么有各种方法可以找到 k 的最佳值。在本文中,我们将介绍两种这样的方法:
- 肘法
- 剪影法
弯头方法:
肘方法是一种为数据集寻找最佳聚类数的经验方法。在此方法中,我们选取一系列 K 的候选值,然后使用每个 K 值应用 K 均值聚类。找出聚类中每个点到其质心的平均距离,并在图中表示出来。选择 k 的值,此时平均距离突然下降。

(图片由作者提供),肘法求最优 k
随着聚类数(k)的增加,平均距离减小。要找到最佳聚类数(k ),请观察该图并找到距离急剧下降时的 k 值。这将是 k 的一个最佳点,在这里出现一个弯头。
在上图中,平均距离在 k=2、3 和 4 处急剧下降。这里出现了选择 k 的最佳值的困惑。在下图中,观察对于 k=2、3 和 4 形成的集群及其平均距离。

(图片由作者提供),k=2、3 和 4 时形成的簇的散点图
这个数据是 2-D 的,所以很容易可视化并挑选 k 的最佳值,即 k=4。对于更高维的数据,我们可以使用剪影法来寻找最佳 k,这是一种比肘法更好的替代方法。
剪影方法:
剪影法也是一种寻找最佳聚类数以及解释和验证数据聚类一致性的方法。剪影方法计算每个点的剪影系数,该系数测量一个点与其自己的聚类相比与其他聚类相似的程度。通过提供一个简洁的图形表示来显示每个对象的分类情况。
计算每个点的轮廓系数,对所有样本进行平均,得到轮廓分数。
剪影值是一个对象与其自己的聚类(内聚)相比与其他聚类(分离)相似程度的度量。轮廓值的范围在[1,-1]之间,其中高值表示对象与其自己的簇匹配良好,而与相邻簇匹配较差。如果大多数对象都有较高的值,那么集群配置是合适的。如果许多点具有低值或负值,则聚类配置可能具有太多或太少的聚类。
计算轮廓系数:
求第 I 个点的轮廓系数的步骤:
- 计算 a(i):该点与同一聚类中所有其他点的平均距离。
- Compute b(i):该点与离其聚类最近的聚类中所有点的平均距离。
- 使用下述公式计算 s(I)-轮廓系数或第 I 点。


(图片由作者提供),a(i)和 b(i)的图解表示,根据上述公式计算轮廓系数— s(i)
计算出每个点的轮廓系数后,将其平均以获得轮廓分数。
轮廓分析:
轮廓是对聚类算法执行情况的一种度量。在计算了数据集中每个点的轮廓系数之后,绘制它以获得数据集被聚类到 k 个聚类中的程度的可视化表示。轮廓图显示了一个聚类中的每个点与相邻聚类中的点的接近程度,从而提供了一种视觉评估聚类数量等参数的方法。这个度量的范围是[-1,1]。
**Important Points:
The Silhouette coefficient of +1** indicates that the sample is far away from the neighboring clusters.
**The Silhouette** coefficient **of 0** indicates that the sample is on or very close to the decision boundary between two neighboring clusters.
**Silhouette** coefficient **<0** indicates that those samples might have been assigned to the wrong cluster or are outliers.
使用轮廓分析找到“k”的最佳值:
与之前的 Elbow 方法类似,我们选取 K(聚类数)的一系列候选值,然后为每个 K 值训练 K 均值聚类。对于每个 K 均值聚类模型,在图中表示轮廓系数,并观察每个聚类的波动和异常值。

(图片由作者提供),Silhoutte 得分与聚类数

(图片由作者提供),KMeans 中每个聚类的轮廓分析和散点图,使用 n_cluster=[2,3,4,5,6]对整个数据进行聚类
从上面的轮廓图观察:
- 轮廓图显示了 3 的 n_cluster 值是一个糟糕的选择,因为 cluster_label=0 的聚类中的所有点都低于平均轮廓分数。
- 轮廓图显示 5 的 n_cluster 值是一个糟糕的选择,因为 cluster_label=2 和 4 的聚类中的所有点都是低于平均的轮廓分数。
- 剪影图显示了 6 的 n_cluster 值是一个不好的选择,因为 cluster_label=1、2、4 和 5 的群集中的所有点都是低于平均的剪影分数,并且还由于异常值的存在。
- 剪影分析在决定 2 和 4 之间更加矛盾。
- 当 n_clusters=2 时,cluster_label=1 的聚类的轮廓图的厚度在尺寸上更大,这是由于将 3 个子聚类分组为一个大聚类。
- 对于 n_clusters=4,所有曲线或多或少具有相似的厚度,因此具有相似的大小,这可以被认为是最佳“k”。
实施:
代码来源,作者编辑
结论:
肘和剪影方法用于寻找最佳数量的集群。对于选取 k 值的肘方法,会出现不确定性。侧影分析可用于研究所得聚类之间的分离距离,并且与肘方法相比,被认为是更好的方法。
剪影分析还增加了优势以发现异常值(如果存在于聚类)。
参考资料:
[1]维基百科:剪影(聚类),(2020 年 9 月 14 日)
[2] Scikit 学习文档:选择对 KMeans 聚类进行轮廓分析的聚类数
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一小部分会员费,不需要你额外付费。
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
satyam-kumar.medium.com](https://satyam-kumar.medium.com/membership)
感谢您的阅读
剪影还是手肘?这是个问题。
人工智能笔记
深入探讨集群中最常见的问题。

由 Vladimir Mokry 在 Unsplash 上拍摄的照片
当您想要对没有标注的数据集进行聚类时,您遇到的最常见的问题之一是“正确的聚类数是多少?”。例如,当您使用要求您固定聚类数的 k-means 算法时,这个问题经常出现。这个问题我遇到过很多次,我相信你也一样。
当您处理高维数据时,这个问题会变得更有争议。真实世界的数据通常是高维的,您需要降低它的维度来可视化和分析它。与降维空间相比,原始空间中的聚类结果可能不同。您使用了相同的算法,但您看到了差异。这意味着聚类结果对空间维度敏感,这主要是由于这些空间中的距离度量的性能,也称为维数灾难。
与降维空间相比,原始空间中的聚类结果可能不同。换句话说,聚类结果对空间维度很敏感。不要惊慌!
在这篇文章中,我不想解释剪影和肘方法背后的数学。你可能很容易在别处找到它。然而,我想分享我使用这些方法的经验,以及一些可能对你有帮助的见解。
—没有正确的集群数量,但有一个最佳数量。
让我直说吧。没有正确的集群数量,但有一个最佳的。例如,我假设你选择了 k-means 算法来解决这个问题。你必须连续运行几个 k 的算法,即聚类数。然后,您必须计算每个 k 的聚类性能。现在,您能够确定 k,以便它能够很好地解决您的问题。
首先,您必须选择一个可以根据需要评估集群质量的性能指标。然后,您必须使用几种配置运行聚类分析算法,并评估每次运行的性能。现在,您已经准备好确定适合您的问题的集群数量。
您必须回答的下一个问题是“评估集群性能的好指标是什么?”。答案是“当然要看情况”。
-可以使用惯性进行聚类,并使用轮廓进行评估。
聚类分析算法中的评分度量或目标函数可能与您要用于评估的性能度量不同。例如,k-means 算法旨在通过最小化类内方差之和(也称为惯性)来对数据进行聚类。但是,您可能希望使用轮廓系数来评估聚类性能。
由于优化的挑战,您不能轻易改变 k-means 算法中的目标函数。但是,您肯定可以使用不同的性能指标来评估 k-means 算法的结果。现在,你可能会问为什么我们不在两个阶段使用相似的度量标准?答案是,我也希望我们可以很容易地做到这一点,但 k-means 算法是一个 NP-hard 问题。在标准配置下,该算法在合理的时间内收敛到良好的局部最优。然而,如果你改变目标函数,并不能保证收敛到任何好的结果。注意,有一些工作修改了 k-means 算法中的目标函数,但是类似的问题仍然存在。
通常,当诸如聚类算法的优化问题中的目标函数变得更复杂时,搜索空间变得更粗糙。在这种情况下,搜索算法很可能不会按照需要收敛。
—那又怎样?
剪影和肘方法是两种简单但重要的方法,用于找到最佳的聚类数。剪影法用的是剪影系数,肘法用的是 k-means 算法中的原始评分函数惯性。
肘方法仅使用簇内距离,而剪影方法使用簇间和簇内距离的组合。所以,你可以预期他们最终会有不同的结果。
根据文献记载,肘法经常与惯性一起使用。然而,肘方法,一般来说,只使用一个启发式来确定曲线的肘作为一个特殊点。在聚类分析中,特殊点表示聚类的个数。所以,你可能想使用肘方法与不同的评分功能,而不是惯性,虽然它不是那么常见。
最后一句话
我建议使用剪影,因为它在评分函数中使用了簇间和簇内距离,而肘方法只使用了簇内距离。然而,这并不意味着剪影法更好。剪影法和肘形法是确定数据集中聚类数的多种方法中的两种。如果想了解更多,还可以阅读一下阿凯克信息准则、贝叶斯信息准则等信息准则方法。正如我上面所说的,它们没有更好也没有更差。它们都能捕捉到数据的不同特征。
感谢阅读!
如果你喜欢这个帖子,想支持我…
[## 通过我的推荐链接加入 Medium—Pedram Ataee 博士
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
pedram-ataee.medium.com](https://pedram-ataee.medium.com/membership)
简单的抽象文本摘要,带有预训练的 T5-文本到文本转换转换器
使用 T5 文本到文本转换器的文本摘要

图片来自 Pixabay 并由艺术 Chrome 插件风格化
T5 是 Google 的一个新的 transformer 模型,它以端到端的方式进行训练,以文本作为输入,以修改后的文本作为输出。你可以在这里了解更多关于的信息。
它使用在大型文本语料库上训练的文本到文本转换器,在多个自然语言处理任务上实现了最先进的结果,如摘要、问题回答、机器翻译等。
今天我们将看到如何使用 huggingface 的变形金刚库来总结任何给定的文本。T5 是一种抽象的总结算法。这意味着它将在必要时重写句子,而不仅仅是直接从原文中提取句子。
开始之前,请在您的 jupyter 笔记本电脑或 conda 环境中安装这些库:
!pip install transformers==2.8.0
!pip install torch==1.4.0
文本输入:
The US has "passed the peak" on new coronavirus cases, President Donald Trump said and predicted that **some states would reopen** this month.**The US has over 637,000 confirmed Covid-19 cases and over 30,826 deaths, the highest for any country in the world.**At the daily White House coronavirus briefing on Wednesday, Trump said new guidelines to reopen the country would be announced on Thursday after he speaks to governors.**"We'll be the comeback kids, all of us," he said.** "We want to get our country back."The Trump administration has previously fixed May 1 as a possible date to reopen the world's largest economy, but the president said some states may be able to return to normalcy earlier than that.
T5 汇总:
The us has over 637,000 confirmed Covid-19 cases and over 30,826 deaths. President Donald Trump predicts some states will reopen the country in **april**, he said. "we'll be the comeback kids, all of us," **the president** says.
分析输出:
如果你看到算法已经智能地总结了提及四月虽然它在最初的故事中从未被提及。还把何换成了总裁。缩短并删除句子“超过 30,826 人死亡……”中逗号后的额外信息
代码:
与一些用户报告的 Github Gist 无法加载的代码相同:
import torch
import json
from transformers import T5Tokenizer, T5ForConditionalGeneration, T5Config
model = T5ForConditionalGeneration.from_pretrained('t5-small')
tokenizer = T5Tokenizer.from_pretrained('t5-small')
device = torch.device('cpu')
text ="""
The US has "passed the peak" on new coronavirus cases, President Donald Trump said and predicted that some states would reopen this month.
The US has over 637,000 confirmed Covid-19 cases and over 30,826 deaths, the highest for any country in the world.
At the daily White House coronavirus briefing on Wednesday, Trump said new guidelines to reopen the country would be announced on Thursday after he speaks to governors.
"We'll be the comeback kids, all of us," he said. "We want to get our country back."
The Trump administration has previously fixed May 1 as a possible date to reopen the world's largest economy, but the president said some states may be able to return to normalcy earlier than that.
"""
preprocess_text = text.strip().replace("\n","")
t5_prepared_Text = "summarize: "+preprocess_text
print ("original text preprocessed: \n", preprocess_text)
tokenized_text = tokenizer.encode(t5_prepared_Text, return_tensors="pt").to(device)
# summmarize
summary_ids = model.generate(tokenized_text,
num_beams=4,
no_repeat_ngram_size=2,
min_length=30,
max_length=100,
early_stopping=True)
output = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
print ("\n\nSummarized text: \n",output)
# Summarized output from above ::::::::::
# the us has over 637,000 confirmed Covid-19 cases and over 30,826 deaths.
# president Donald Trump predicts some states will reopen the country in april, he said.
# "we'll be the comeback kids, all of us," the president says.
上面提到的汇总输出是-
The us has over 637,000 confirmed Covid-19 cases and over 30,826 deaths. President Donald Trump predicts some states will reopen the country in **april**, he said. "we'll be the comeback kids, all of us," **the president** says.
在上面的代码中需要注意的关键点是,在将文本传递给 T5 摘要生成器之前,我们在文本前面加上了" summary:"。
如果你看一下论文,对于其他任务,我们需要做的就是在我们的文本前面加上相应的字符串,例如:“将英语翻译成德语:”用于翻译任务。
祝 NLP 探索愉快,如果你喜欢它的内容,请随时在 Twitter 上找到我。
如果你想学习使用变形金刚的现代自然语言处理,看看我的课程使用自然语言处理生成问题
使用 HuggingFace DistilBERT 的简单快速的问题回答系统——提供了单个和批量推理的例子。

图片来自 Pixabay 并由 AiArtist Chrome 插件风格化(由我构建)
问题回答系统有很多用例,比如通过通读公司文件并找到完美答案来自动回复客户的查询。
在这篇博文中,我们将看到如何使用hugging face transformers库中的 DistilBERT 实现一个最先进的、超快的、轻量级的问答系统。
投入
输入将是一小段我们称之为上下文、和一个问题-
**Context :** The US has passed the peak on new coronavirus cases, President Donald Trump said and predicted that some states would reopen this month.The US has over 637,000 confirmed Covid-19 cases and over 30,826 deaths, the highest for any country in the world.**Question:** What was President Donald Trump's prediction?
输出
我们的问答系统的输出将是来自上下文段落的答案,如下所示—
**Answer:** some states would reopen this month.
让我们开始吧:
首先,我们来看看如何回答一个单题如上图。然后,我们将看到如何利用批处理从上下文中一次回答多个问题。
安装最新版本的变形金刚库-
pip install transformers==2.8.0
pip install torch==1.4.0
单项推断:
下面是用 DistilBERT 进行单一推理的代码:
输出将是:
**Question** What was President Donald Trump's prediction?**Answer Tokens:**
['some', 'states', 'would', 're', '##open', 'this', 'month']**Answer** : some states would reopen this month
批量推断:
现在让我们试着用批量推理做同样的事情,我们试着传递三个问题,并以批量的形式得到它们的答案
三个问题是-
**1.** What was President Donald Trump's prediction?
**2\.** How many deaths have been reported from the virus?
**3\.** How many cases have been reported in the United States?
下面是用 DistilBERT 进行批量推理的代码:
输出将会是—
**Context** : The US has passed the peak on new coronavirus cases, President Donald Trump said and predicted that some states would reopen this month.The US has over 637,000 confirmed Covid-19 cases and over 30,826 deaths, the highest for any country in the world.**Question**: What was President Donald Trump's prediction?
**Answer**: some states would reopen this month**Question**: How many deaths have been reported from the virus?
**Answer**: 30 , 826**Question**: How many cases have been reported in the United States?
**Answer**: over 637 , 000
如果你对从上下文自动生成问题感兴趣,而不是对问题回答感兴趣,你可以在下面的链接中查看我的各种算法和开源代码-
编码快乐!
使用自然语言处理的问题生成——教程
我推出了一个非常有趣的 Udemy 课程,名为“使用 NLP 生成问题”,扩展了这篇博文中讨论的一些技术。如果你想看一看,这里是链接。
祝 NLP 探索愉快,如果你喜欢它的内容,请随时在 Twitter 上找到我。
Python 中简单的数据可视化,你会发现很有用
将这些图用于您的数据科学项目
能够有效地使用数据可视化是数据科学家的一项重要技能。可视化数据有助于我们轻松地消化信息,并提取出难以提取的见解。在本帖中,我们将看看 5 种类型的图,分别是 Seaborn 和 Matplotlib ,以及它们在数据科学项目中的应用示例。

在 Unsplash 上paweczerwiński拍摄的照片
2020 年 9 月,Seaborn 发布了一个主要版本:v0.11.0。在这篇文章中,我们将使用这个版本的一些新特性和增强功能。特别是,如果您使用的是早期版本,您会发现第 3 节和第 4 节中示例数据集的列名和分布图的功能是不同的。因此,请确保您的 Seaborn 版本已更新。你可以在这里找到发布的详细信息。
0.资料组📦
让我们导入包并更新图表的默认设置,以节省调整单个图的时间,并为图表添加一点个人风格:
# Import packages
import seaborn as sns
import matplotlib.pyplot as plt# Update default settings
sns.set(style='whitegrid', context='talk',
palette=['#62C370', '#FFD166', '#EF476F'])
如果你想了解更多关于调整图表默认设置的信息,你可能会发现这篇文章很有用。我们将使用 Seaborn 内置的企鹅数据集:
# Import dataset
df = sns.load_dataset('penguins').rename(columns={'sex': 'gender'})
df

📍 1.热图:sns.heatmap():
让我们从我最喜欢的一个有很多应用的情节开始。简单地说,热图是一个颜色编码的表格。热图可用于检查缺失值。它有助于了解缺失数据的数量和模式。
plt.figure(figsize=(10, 6))
sns.heatmap(df.isnull(), yticklabels=False, cbar=False)
plt.title("Missing values");

缺失值在该图中显示为白色条带。我们可以立即看到性别有更多的缺失值。跨列的连接水平白线(在图的顶部和底部)向我们展示了一种模式,即在一个数字列中有缺失值的记录在其他数字列和性别中也有缺失值。
在检查变量之间的关系时,热图也很有用。例如,检查数值变量之间线性关系的相关矩阵可以如下所示:
plt.figure(figsize=(8, 3))
sns.heatmap(df.corr(), annot=True, cmap='seismic_r')
plt.title("Correlation matrix");

从这个图我们可以看出 flipper_length_mm 与 body_mass_g 有很强的正相关关系(r=0.87)。
预测能力得分矩阵是检查任何类型关系强度的另一种技术。让我们想象一下预测能力得分矩阵:
# Import package
import ppscore as pps# Calculate pps
pps_matrix = pps.matrix(df)# Prepare data to pivot table
pps_pivot = pps_matrix.pivot('x', 'y', 'ppscore')
pps_pivot.index.name, pps_pivot.columns.name = None, None# Plot
plt.figure(figsize=(10, 4))
sns.heatmap(pps_pivot, annot=True, cmap='YlGn')
plt.title("Predictive Power Score Matrix");

你可以从这里了解更多关于预测力评分的信息。
使用监督分类模型时,查看混淆矩阵有助于评估模型性能。为了使它更容易理解,花点额外的精力来标记和格式化它是值得的。现在,让我们建立一个简单的模型来预测物种。我们将把物种作为这篇文章剩余部分的目标,除了下一部分关于柱状图的后半部分。这里有一个例子:
# Import packages
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import confusion_matrix# Create list of numerical column names
numerical = list(df.select_dtypes('number').columns)# Partition data keeping only numerical non-missing columns
X = df.dropna()[numerical]
y = df.dropna()['species']
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=.3,
random_state=1)# Fit simple model to the data
model = RandomForestClassifier(random_state=123)
model.fit(X_train, y_train)# Predict
y_test_pred = model.predict(X_test)# Prepare confusion matrix
cm = confusion_matrix(y_test, y_test_pred)
fig, ax = plt.subplots(figsize=(6, 3.5))
sns.heatmap(cm, annot=True, cbar=False, cmap='BuGn', ax=ax)
ax.set_title('Confusion matrix')
ax.set_xlabel('Predicted')
ax.set_xticklabels(model.classes_)
ax.set_ylabel('Actual')
ax.set_yticklabels(model.classes_,
fontdict={'verticalalignment': 'center'});

正如您从示例中看到的,热图非常有用和实用。这些是我在探索性分析或建模阶段使用热图的一些最喜欢的方式。如果你需要可视化表格(如数据透视表或交叉制表)并使其更容易阅读,热图是你的好朋友。
📍 2.条形图:sns.barplot()和 sns.countplot()
大多数人都熟悉条形图。在条形图中,一个轴告诉我们类别,而另一个轴告诉我们与该类别相关的数值。因此,这对于可视化分类变量很有用。当使用某些类型的机器学习算法时,查看模型的特征重要性可以让我们了解模型认为哪些特征更重要。让我们用它来看看我们在上一节中构建的简单随机森林模型的特性重要性:
# Map feature importance to variable names
importances = pd.DataFrame(model.feature_importances_,
index=X_train.columns,
columns=['importance'])
importances.sort_values('importance', ascending=False, inplace=True)# Plot feature importance
plt.figure(figsize=(10, 4))
sns.barplot(data=importances, x=importances.index, y='importance')
plt.title('Feature importance');

如果有许多特征和/或特征的名称很长,使用这种格式会导致 x 轴上的特征名称重叠,使绘图难以阅读。一个简单的解决方案是交换 x 轴和 y 轴的映射:
plt.figure(figsize=(8, 4))
sns.barplot(data=importances, x='importance', y=importances.index)
plt.title('Feature importance');

在我们的下一个例子中,我们将使用两个条形图来获得每个分类变量的不同见解。第一个条形图将显示类别出现的频率。这有助于看到变量的总体分布,包括是否有任何主导或罕见的类别。为此,我们将使用sns.countplot(),它是直方图的分类等价物。第二个条形图将显示变量中每个类别的目标平均值。这有助于检查某些类别是否更有可能或更不可能与目标变量中的特定类相关联。为了说明,我们将添加一个随机的二元目标,将物种视为一个特征,并使用循环的为每个分类变量绘制两个条形图:
# Import package
import numpy as np# Create random target
np.random.seed(123)
df['target'] = np.random.randint(0, 2, df.shape[0])# Create list of categorical column names
categorical = list(df.select_dtypes(exclude='number').columns)# Plot counts for non-numerical variables
for var in categorical:
fig, ax = plt.subplots(1, 2, figsize=(14, 3.5))
sns.countplot(x=var, data=df, ax=ax[0])
ax[0].set_title(f"Counts of each category in {var}")
sns.barplot(x=var, y='target', data=df, ax=ax[1])
ax[1].set_title(f"Mean target by each category in {var}");

当在探索性分析期间第一次查看数据并试图判断哪些变量对模型可能更有用时,以这种方式可视化分类列非常有用。如果你有一个数字目标,右边的图表也可以。
📍 3.直方图:sns.histplot()和密度图:sns.kdeplot()
直方图和核密度图是检查数字列分布的好方法。直方图将数字数据划分为仓,并显示每个仓的频率计数。直方图可以被认为是一种特殊类型的条形图。另一方面,密度图使用核密度估计来显示密度。我们将再次使用循环的来绘制每个数值变量的直方图和密度图:
for var in numerical:
fig, ax = plt.subplots(1, 2, figsize=(15, 4))
sns.histplot(df, x=var, hue='species', bins=30, ax=ax[0])
ax[0].set_title(f"Histogram for {var}")
sns.kdeplot(data=df, x=var, hue='species', shade=True,
common_norm=False, ax=ax[1])
ax[1].set_title(f"Density plot for {var}")


我们使用hue参数来绘制物种的类别,以观察变量的分布在企鹅物种之间是否不同。因为每个物种的记录数量不同,这已经可以从直方图中看出,我们通过在sns.kdeplot()中指定common_norm=False来确保每个物种都有自己的标准化内核密度。这里有一个例子来说明我的意思:
fig, ax = plt.subplots(1, 2, figsize=(15, 4))
sns.kdeplot(data=df, x=numerical[0], hue='species', shade=True,
ax=ax[0])
ax[0].set_title(f"common_norm=True")
sns.kdeplot(data=df, x=numerical[0], hue='species', shade=True,
common_norm=False, ax=ax[1])
ax[1].set_title(f"common_norm=False");

曲线下的面积与第一个图中的物种频率成比例,因为common_norm=True将每个人的密度标准化。另一方面,右边的图在物种内是归一化的,所以曲线下的面积在物种间是相等的(注意 y 轴极限的差异)。
📍 4.散点图:sns .散点图和二元直方图:sns.histplot()
另一个简单的图是散点图,它对于查看两个数值变量之间的关系很有用。
一般来说,直方图指的是单变量直方图,其中单变量只是one(uni)variate(变量)的一种花哨说法。在本节中,我们将查看双变量直方图,以检查两个数值变量之间的关系。
让我们为数字列对的所有组合绘制它们。值得注意的是,这些图中的图例被故意排除在外,因为物种的颜色编码与之前相同,会阻挡一些数据点:
previous = []
for i, var in enumerate(numerical):
if i > 0:
for p_var in previous:
fig, ax = plt.subplots(1, 2, figsize=(15,4))
sns.histplot(df, x=p_var, y=var, hue='species',
alpha=0.6, ax=ax[0])
ax[0].get_legend().remove()
sns.scatterplot(data=df, x=p_var, y=var, hue='species',
size='gender', alpha=0.6, ax=ax[1])
ax[1].get_legend().remove();
previous.append(var)


在左边,我们正在看由物种进行颜色编码的二元直方图。在右边,我们正在看由物种编码的散点图。我们还将性别映射到散点图中点的大小。
与上一节不同,这两个图显示了非常相似的见解。这意味着你可以选择你最喜欢的一个,而不是两个都用。
📍 5.配对图:sns.pairplot()
在 Seaborn 中有一个很好的功能,可以用一行代码做出我们在第 3 节和第 4 节中看到的类似的图形:
sns.pairplot(df.drop(columns='target'), hue='species');

使用sns.pairplot()很棒,然而,我确实发现当变量数量增加时,每个图开始变得很小,这使得很难检查。因此,最好将其用于列数较少的数据集。
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。
谢谢你看我的帖子。我希望你能在你的数据科学项目中使用这些可视化。
如果你感兴趣,这里有我的一些帖子的链接:
◼️ 在 Seaborn (Python)
◼️ 在 Python 中进行探索性文本分析
◼️️ 给 pandas 用户的 5 个提示
◼️️ 在 pandas 中进行数据聚合的 5 个提示
◼️️ 在 pandas 中编写 5 个常见的 SQL 查询
◼️️ 在 pandas 中编写高级 SQL 查询
再见🏃💨
图形数据库的简单部署:JanusGraph

参考:https://unsplash.com/photos/ZiQkhI7417A
我最近一直在寻找一个开源的分布式图形数据库,因为我需要在某个地方持久地存储大量的图形数据。我的主要要求是,我想尽可能多地控制上述数据库背后的底层存储和索引系统。
我偶然发现了 JanusGraph ,这是 Linux 基金会下的一个图形数据库项目,它建立在 Apache TinkerPop 之上,包括 Gremlin 查询语言。Tinkerpop 还支持其他许多图形数据库,如 neo4j、Amazon Neptune、DataStax、Azure Cosmos DB 等。我选择 JanusGraph 是因为它的即插即用方法,例如,我可以替换后端存储(如 Cassandra、HBase、BerkeleyDB、ScyllaDB 或 Google Cloud Bigtable)和索引软件(如 Elasticsearch、Solr 或 Lucene)。我还没有评估所有现有的图形数据库,所以我不能说太多关于 JanusGraph 与其他解决方案相比如何。我的意图是首先了解底层技术是如何工作的,然后我才会冒险尝试其他数据库。
尽管如此,由于它的可定制性,探索 JanusGraph 在开始时可能会感到有点令人生畏,至少对于像我这样的第一次尝试者来说是这样。这也是我写这篇文章的原因。我想尽可能简洁地总结我的学习之旅,并指导您完成在远程服务器中部署 JanusGraph、执行查询和可视化数据集所需的步骤。
服务器端设置
在服务器中部署 JanusGraph 包括以下步骤。
设置一个服务器。在我的情况下,我选择了一个云提供商的廉价虚拟机(25 GB SSD + 1024 MB RAM,Ubuntu 18.04)。因为 JanusGraph 默认运行在端口 8182 上,所以我将这个端口开放给公众访问。为了简单起见(不是最安全的方式),我简单地通过 iptables 来实现。
iptables -A INPUT -p tcp -m tcp — dport 8182 -j ACCEPT
记下您服务器的 IP 地址为$ {服务器 IP 地址}。您可以通过运行以下命令来做到这一点。
ifconfig
拉下并运行骏图 docker。骏利已经提供了其系统的文档化实现。默认的是 BerkeleyDB 作为存储,Lucene 作为索引。下面的代码将从 docker 存储库中提取最新的 janusgraph 图像。
docker run -it -p 8182:8182 janusgraph/janusgraph
将图形数据集复制到 docker。 JanusGraph 支持几种数据格式,其中一种叫做 graphml。在引擎盖下,这些基本上都是邻接矩阵或列表。在我们的实验中,我们将使用 kelvinlawrence.net 的《T2》教程中的机场航线数据集。 air-routes.graphml 数据集可以从这里下载。我们需要将 graphml 数据复制到 janusgraph 容器( /opt/janusgraph/data/ ),以便稍后可以通过客户端发出的命令将它加载到 janusgraph。您可以通过运行 docker ps 来获取$ { Janus graph _ DOCKER _ ID }。
docker cp ${YOUR_CUSTOM_LOCATION}/air-routes.graphml ${JANUSGRAPH_DOCKER_ID}:/opt/janusgraph/data/.
客户端设置
我们将使用三种方法连接服务器:gremlin 控制台、gremlin python 和 graphexp。
Gremlin 控制台
我们将使用来自 Tinkerpop 的 janusgraph 分叉版本的专用 gremlin 控制台将数据集加载到 janusgraph。
下载并解压最新发布的骏图。你可以从这里得到文件。
为 gremlin 远程连接设置创建一个 remote.yaml 文件。我们将这个文件称为$ { REMOTE _ YAML _ LOC }/REMOTE . YAML
hosts: [${SERVER_IP_ADDRESS}]
port: 8182
serializer: { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}
运行小妖精控制台。我们将在控制台中做一些事情。
${janusgraph_latest_release}/bin/gremlin.sh
首先,我们将连接到远程 janusgraph 服务器。这是因为数据存在于服务器中,而这个客户端 gremlin 控制台将仅用于将任何查询转发给前者。
:remote connect tinkerpop.server *${REMOTE_YAML_LOC}/remote.yaml* session:remote console
接下来,我们将把 air-routes.graphml 数据加载到 janusgraph 中。我们将使用 janusgraph 的一个名为 graph.io 的 API。
graph.io(graphml()).readGraph(‘/opt/janusgraph/data/air-routes.graphml’)
小精灵蟒蛇
我们现在想使用 python 查询图表。这个想法是,我们可以获得一些子图,并在本地客户端内存中使用现有的 python 库(如 networkx)进一步分析它们。如果您想要处理整个原始图形(例如,运行 PageRank),将整个图形加载到您的本地客户端内存可能并不明智。选择 TinkerPop 的 GraphComputer API,您可以通过 VertexProgram 运行 OLAP 算法。更多详情见此处。
用 pip 安装 gremlin-python。
pip install gremlinpython
与远程服务器的 janusgraph 建立连接。加载图形遍历对象为 g 。在 python 控制台中完成这项工作。
from gremlin_python.process.anonymous_traversal import traversalfrom gremlin_python.driver.driver_remote_connection import DriverRemoteConnectiong = traversal().withRemote(
DriverRemoteConnection(‘ws://${SERVER_IP_ADDRESS}:8182/gremlin’,’g’))
运行查询。例如,如果我们想要获得机场列表,我们可以运行以下 gremlin 查询。要获得更多关于可以执行哪些查询的指导,请参考 Gremlin API 。这是因为 JanusGraph 是建立在 Gremlin 之上的,因此你也可以参考后者的文档来获得更多信息。
g.V().hasLabel(‘airport’).valueMap().toList()
Graphexp
有一些第三方库是为与 JanusGraph 接口而构建的。我发现 graphexp 是最容易使用的软件之一。可以从这个 github repo 下载。
git clone [https://github.com/bricaud/graphexp](https://github.com/bricaud/graphexp)
运行 graphexp。只需从浏览器中打开 graphexp.html。
输入您的远程服务器地址和端口,执行查询。在这个例子中,我正在查询新加坡樟宜机场的 ego 网络。

瞧啊。现在,您在远程服务器上有了一个正在运行的图形数据库,您可以从任何客户端计算机上进行查询。
参考文献
附加说明
在某些情况下,您可能希望在数据库中存储多个独立的图形。为此,您必须在部署之前修改您的 janusgraph yaml 配置文件。步骤几乎与 gremlin server 的设置相似(因为 JanusGraph 是建立在 gremlin server 之上的)。粗略地说,您需要做一些事情(这个例子是为 gremlin 服务器中的 TinkerGraph 做的)。
首先,编辑 gremlin-server yaml 文件。在这种情况下,我想要创建两个图形,因此我在 yaml 文件的 graphs 设置中添加了 graphA 和 graphB 。每个图形都在 conf/下的属性文件中定义。
graphs: {
graphA: conf/tinkergraph-empty.properties,
graphB: conf/tinkergraph-empty.properties
}
其次,更新初始 groovy 脚本。我们基本上想同时加载 graphA 和 graphB 。我们还想为它们创建遍历对象。
...
org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory.generateModern(graphA)
org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory.generateModern(graphB)...globals << [
gA : graphA.traversal().
withStrategies(ReferenceElementStrategy.instance()), gB : graphB.traversal().
withStrategies(ReferenceElementStrategy.instance())
]...
JanusGraph 的另一个有用特性是模式管理(就像任何典型的数据库一样)。然而,这超出了本文的范围。有关如何使用 JanusGraph 的 openManagement API 管理图表的更多信息,请查看这个全面的教程。
使用 Python 的简单边缘检测模型
机器使用边缘检测来更好地理解现实世界

来自佩克斯的阿纳斯塔西娅·舒拉耶娃的照片
在这篇文章中,我将向你展示如何检测图像的边缘。写一个边缘检测程序会让你对计算机视觉和自动驾驶汽车有所了解。边缘检测通常用于理解图像中的对象。这也有助于机器做出更好的预测。编写边缘检测程序是理解机器如何看待外部世界的一个很好的方式。这将使我们在计算机视觉方面有更好的视角。
我在以前的文章中介绍了一些计算机视觉概念:人脸检测、人脸识别和文本识别。今天,我们将使用 python 进行边缘检测。
目录
- 入门
- 导入库
- 边缘检测功能
- 选择一幅图像
- 运行程序
入门指南
我们将为这个项目使用两个主要模块:Numpy、Matplotlib 和 OpenCV。Matplotlib 是一个完整的库,用于在 Python 中生成静态、动画和交互式可视化。OpenCV 是一个高度优化的库,专注于实时应用。
OpenCV
OpenCV(开源计算机视觉库)是一个开源的计算机视觉和机器学习软件库。OpenCV 旨在为计算机视觉应用提供一个通用的基础设施,并加速商业产品中的机器感知。作为一个 BSD 许可的产品,OpenCV 使得企业利用和修改代码变得很容易。
让我们从安装库开始。
图书馆
我们必须安装这些库,这样我们的程序才能正常工作。如前所述,我们只需要两个库。
我们可以使用 PIP 库管理器在一行中安装它们:
pip install numpy matplotlib opencv-python
安装过程完成后,我们可以将它们导入到代码中。您可以在 Jupiter 笔记本或 Atom 等常规文本编辑器上工作。我将使用这个项目的原子文本编辑器。
import cv2
import numpy as np
import matplotlib.pyplot as plt
边缘检测功能
现在,我们可以转到有趣的部分,在这里我们将编写边缘检测函数。你会惊讶于使用 OpenCV 包是多么简单。这个 OpenCV 检测模型也被称为 Canny 边缘检测模型。我们的功能由三部分组成:边缘检测,可视化,最后,保存结果。
边缘检测
def simple_edge_detection(image):
edges_detected = cv2.Canny(image , 100, 200)
images = [image , edges_detected]
理解代码:
- Canny 是我们调用的使用 OpenCV 进行边缘检测的方法。
- Image 是函数的一个参数,这意味着我们在调用函数时会传递图像。这样,你可以很容易地用不同的图像测试你的程序。
- 100 和 200 是滞后阈值的最小值和最大值。
- 如果想了解更多关于 Canny 边缘检测的知识:(官方文档)。
形象化
location = [121, 122]
for loc, edge_image in zip(location, images):
plt.subplot(loc)
plt.imshow(edge_image, cmap='gray')
理解代码:
- 绘图部分需要位置数组。
- 然后,我们可视化原始图像和边缘检测图像。
- cmap 参数用于改变图像的颜色。在我们的例子中,我们将它们转换成灰色。
保存结果
该功能的最后一部分将保存边缘检测图像和比较图。感谢 OpenCv 和 Matplotlib 包; imwrite 和 savefig 函数为我们做了保存。在最后一行中, show 函数将向我们展示创建的图表。
cv2.imwrite('edge_detected.png', edges_detected) plt.savefig('edge_plot.png') plt.show()
选择图像
这将是一个简单的图像。我们将找到一个图像,我们想测试我们的 canny 边缘检测程序。我将使用免费的库存摄影页面来找到一些好的图片。这里是他们网站的链接。
下载图像后,确保将它们放在与项目相同的文件夹中。这将有助于轻松地将它们导入程序。让我们定义一个图像变量并导入图像。以下是如何使用 OpenCV 读取图像:
img = cv2.imread('test_image.jpg', 0)
这是我将测试模型的示例图像:

来自 Pexels 的 joo vítor Heinrichs 的照片
运行程序
最好也是最后一步,是时候运行程序了。到目前为止,没有任何东西触发该功能。我们必须调用函数,这样奇迹才会发生。哦,别忘了把你的图片作为参数传递。让我们调用这个函数:
simple_edge_detection(img)
以下是一些结果:

作者照片

作者照片

作者照片
干得好!您已经使用 Python 创建了一个边缘检测模型。Python 是一种非常引人注目的语言,使用 python 可以创造无限的东西。现在,你也知道如何在实际项目中使用计算机视觉。从事像这样的动手编程项目是提高编码技能的最好方式。
我很高兴你今天学到了新东西。如果您在执行代码时有任何问题,请随时联系我。😊
更多计算机视觉项目
使用 moviePy 库的动手机器学习项目
towardsdatascience.com](/rendering-text-on-video-using-python-1c006519c0aa) [## 使用 Python 构建条形码/QR 码阅读器
使用 Pyzbar 库的简单且可实际操作的机器学习项目
towardsdatascience.com](/building-a-barcode-qr-code-reader-using-python-360e22dfb6e5)
使用置信估计进行预测的简单示例

西蒙·艾布拉姆斯在 Unsplash 上拍摄的照片
在数据科学中,制作一个输出数值的模型——也称为回归——是一个古老的故事。但有时我们不仅对预测值感兴趣,还对该值周围的不确定性感兴趣,这被称为概率预测。本文将带您浏览一个示意性示例,在该示例中,我们让神经网络预测一个值以及一个置信度估计值。我们将使用 Python 和 tf.keras,以及像正态分布这样的基本概率结果。此处提供有代码的笔记本。
评估模型的标准方法及其缺点
经典方法是评估所有测试输入的模型输出,并根据自己喜欢的度量计算平均错误率。举个例子:假设你正在预测明天的温度,你的模型平均误差率为 5%,如果你的模型预测明天的温度为 30 度,你只需在这个数字上加上+- 5%就可以得到一个置信区间。
这并不完美,原因有很多。这里的主要问题是我们使用一个不依赖于数据点的平均误差估计。如果模型有时对某些输入非常确定会怎样?例如,如果你正处于雨季,模型可能 99%确定明天会下雨,5%的误差率太大了。另一方面,可能有些日子模型比平均值更不确定,这 5%可能会给你带来麻烦。总之,计算平均错误率是一个平均值。它没有考虑到你所预测的实际点的特殊性。
让我们改进这一点。如果模型本身不仅能输出单一的预测值,还能输出其可信度会怎样?通过这种方式,您将获得一个根据您预测的实际数据点量身定制的置信度评估,从而获得上下文感知。在现实生活中,了解估计的不确定性和实际预测一样重要。
这里我们将制作一个非常简单的神经网络,它使用不确定性估计进行回归。为了尽可能简单明了,我将使用一个虚拟的一维数据,一个单层网络,没有测试集。
我在试图理解这篇论文时举了这个例子: DeepAR:用自回归递归网络进行概率预测来自 D. Salinas 等人在那里他们建立了一个用于多时间序列预测的概率预测网络。
我们将把工作分成三部分:
- 产生具有变化的不确定性的伪数据
- 用简单的置信区间制作一个非常简单的经典回归模型
- 改进模型,使其输出置信度估计值
制作虚拟数据
我们生成两个变量:x是我们的自变量,它取 0 到 1 之间的值,y是我们想要预测的值。
我们根据以下公式生成 y:

数据生成方程
我们来分析一下。这意味着 y 相当于 x 加上一些噪声,噪声的大小取决于 x,所以,这是一个非常非常简单的预测!然而,y 上的不确定性与 x 成线性增长,因此,如果 x 较小,则很确定 y=x,但对于较大的 x 值,y 开始围绕其期望值扩散。

在我们的数据图中,我们可以看到 y 值随着 x 向 1 扩展。
经典回归模型
让我们制作一个基于x预测y的神经网络。我们只用一个单层神经网络。为此,我们将使用 tf.keras:

单层架构,没有比这更简单的了。
在用均方误差(MSE)损失和 Adam 优化器训练该模型 200 个时期后,我们得到以下预测:

朴素模型的预测。
好了,这差不多是我们预期的预测。我们的模型正确预测 y=x,MSE 为 0.011。
假设模型误差是高斯的,我们可以用这个 MSE 误差来计算置信区间。这些细节使用了高斯分布的一些属性,我们现在并不真正需要这些属性,所以让我们使用下面的公式,它给出了 95%的置信区间(CI):

95%置信区间的公式
在我们的简单模型上使用这个公式,并以图形方式显示结果,给出了下图。如您所见,CI 是正确的,因为我们有大约 95%的数据点在预测区间内。但是它完全忽略了数据噪音的可变性。

具有 95%置信区间的简单模型
向模型输出添加置信度信息
正如所承诺的,我们将修改我们的模型,使其输出不仅仅是一个预测,而是一个预测及其置信度。
这是获取技术的时候了。为了在预测中引入信心,我们需要讨论我们的预测值的分布,我们写为 P(y|x)。根据手头的数据,您期望的分布可能会有所不同。在我们的例子中,我们显然有一个正态分布,因为这是我们如何生成我们的数据,但这不是强制性的。
您如何知道哪个发行版与您的项目相关?绘制数据并查看模式的数量,围绕平均值和数据范围的对称性是一个良好的开端。根据这些参数,你应该找到一个符合这些特征的理论分布。
现在,正态分布是默认使用的分布,如果您正在处理实值数据,它应该是一个很好的起点。让我们继续这个例子。
正态分布由两个参数定义:平均值 𝜇 和标准差 𝜎 。从这两个值,我们已经完全确定了分布,我们可以计算我们可能需要的所有置信区间。所以,让我们的网络输出这两个值。这很简单:

具有概率输出的网络结构。
“左分支”计算标准偏差 𝜎 ,而“右分支”计算平均值 𝜇 。我对标准偏差输出使用了“relu”激活,因为标准偏差必须为正。在最后一层,两个输出被连接。
现在我们需要为模型选择一个损失函数。之前,我们使用了一个均方误差来惩罚预测误差。但是在这里,我们需要一种方法来惩罚预测和不确定性。
为此,我们将把问题写成概率的形式。我们的模型以 x 为输入,返回一个正态概率分布 N( 𝜇 ( 𝑥 ), 𝜎 ( 𝑥 ))。
如果这个分布与实际的数据分布相匹配,那么我们的训练就是成功的。我们如何对此进行量化?我们会说,如果获得我们的精确训练数据的概率很高,如果我们从我们的分布中提取数据,这是一个很好的匹配。
对于数据点(x,y),y 从 N( 𝜇 ( 𝑥 )、 𝜎 ( 𝑥 ))被采样的概率由下式给出:

如果我们的数据是从输出分布中抽样的,那么看到它的概率。
这只是高斯定律的概率密度函数。现在我们要使这个概率尽可能的高,也就是我们要找到使(|(【𝑥)**【𝑥)最大化的函数【𝑃】(|𝜇(𝑥)(*)*****
现在前面有几个有趣的计算,我打算跳过,因为它们非常简单:
- 我们应用对数,因为最大化 p 与最大化 ln( 𝑃 )是相同的。
- 我们删除常量,因为它们在优化中不起作用。
- 我们将否定整个表达式。这只是因为 Keras 喜欢最小化事情,如果我们最小化负面就像最大化原始。
最后,我们得到了一个 Keras 可以理解的损失:

概率损失
这是有效的损失吗?我们可以直观地检查它是否有意义。它将我们的目标值 y 与网络输出 𝜎 , 𝜇.结合在一起此外,我们可以单独理解每个术语:
- ln( 𝜎 ):这对于小 𝜎 来说会比较低,从而推动网络自信。
- 当 𝜇 接近 y 时,第二项将为低。这将推动网络减少预测误差。对于高 𝜎 值,该项也将为低。所以,当网络说它不自信时,这种损失对错误的惩罚较少(高 𝜎 )。
让我们将此实现为一个 Keras 自定义损失。
训练这个模型比前一个稍微复杂一点。这里有一个效果很好的迭代方法:
- 使用学习率范围测试选择学习率。
- 以此学习率训练 100 个纪元。
- 检查损失,如果低于-1.9 止损,否则返回步骤 1。
通常,这种方法在几百个纪元内有效。请注意,大约有一半的时间,它收敛到一个坏的局部最小值。在这种情况下,只需重新初始化模型并重新启动。
下面我们有一个样本训练曲线,我只需要重复上面的过程两次。正如你所看到的,我开始时的学习率是 0.01,然后根据范围测试结果移动到 0.1。

概率模型的训练曲线。
好了,现在我们的模型已经训练好了,是时候检查预测了。我们将绘制我们的模型结果。为此:
- 我们使用第一个输出 𝜇 作为预测。
- 我们使用第二个输出 𝜎 根据公式𝐶𝐼=𝜇1.96×𝜎.建立 95% CI

概率预测结果。预测的不确定性与数据中的不确定性相匹配。
就是这样。如你所见,我们的模型对小 x 值更有信心。
结论
在本文中,我们已经看到了如何进行预测以及不确定性估计。我们已经研究了 Keras 中的理论和实现。
从实践的角度来看,我们可以升级现有的网络,分两步返回置信度估计值:
- 添加分支以生成标准差输出
- 切换到概率损失
但是,理解理论是有好处的,这样我们就可以选择正确的分布和适当的损失。
最后,用真实数据呢?看看 DeepAR:用自回归递归网络进行概率预测,他们应用了一种更复杂的技术来获得销售预测的不确定性估计。
我用这个简单的例子来总结这篇文章,希望它也能对你有用。我还没有在真实数据集上尝试过。一定要让我知道你的想法!
Boruta 特征选择(Python 中的一个例子)
Python 中强大的 Boruta 特征选择库的快速示例

威廉·费尔克在 Unsplash 上的照片
如果您没有使用 Boruta 进行特性选择,那么您应该尝试一下。它可以用于任何分类模型。Boruta 是一种基于随机森林的方法,因此它适用于像随机森林或 XGBoost 这样的树模型,但也适用于像逻辑回归或 SVM 这样的其他分类模型。
Boruta 迭代地去除统计上不如随机探针相关的特征(由 Boruta 算法引入的人工噪声变量)。在每次迭代中,被拒绝的变量在下一次迭代中不被考虑。它通常以一个良好的特征选择全局优化而告终,这也是我喜欢它的原因。
我们将看一个简单的随机森林示例来进行特性选择。这个故事的唯一目的是向您展示一个简单的工作示例,这样您也可以使用 Boruta。
导入数据集
这个例子将使用 sklearn 附带的 breast_cancer 数据集。您可以使用可选的 return_X_y 让它直接输出数组,如图所示。
创建您的分类器或回归对象
只需将数据与您选择的模型相匹配,现在就可以为 Boruta 做准备了。
注意:在进行特征选择时,我会拟合整个数据集。消除特征后,您可以进行训练/测试分割。
创建你的 Boruta 对象
现在创建一个 BorutaPy 特征选择对象,并使您的整个数据适合它。在拟合过程中,Boruta 将根据数据集的大小进行多次迭代的特性测试。Boruta 创建你的特征(噪波)的随机阴影副本,并根据这些副本测试该特征,以确定它是否比噪波更好,因此值得保留。它会自动检查可能会损害模型的交互。对于每次迭代,Boruta 将输出确认的、暂定的和拒绝的变量。
拟合后,Boruta 对象具有有用的属性和方法:
- 。support_ attribute 是一个布尔数组,用于回答-是否应该保留特征?
- 。ranking_ attribute 是等级的 int 数组(1 是最佳特征)
- 。transform(X)方法应用建议并返回调整后的数据数组。通过这种方式,你可以让博鲁塔管理整个考验。
注意:如果你得到一个错误(TypeError: invalid key),在将 X 和 y 装配到选择器之前,尝试将它们转换成 numpy 数组。如果你遇到这个错误,需要帮助,请告诉我。
查看功能
下面是我写的一些快速代码,用来查看 Boruta 的输出结果。看起来我的 30 个特性中有 5 个被建议删除。代码的输出如下所示。
Feature: mean radius Rank: 1, Keep: True
Feature: mean texture Rank: 1, Keep: True
Feature: mean perimeter Rank: 1, Keep: True
Feature: mean area Rank: 1, Keep: True
Feature: mean smoothness Rank: 1, Keep: True
Feature: mean compactness Rank: 1, Keep: True
Feature: mean concavity Rank: 1, Keep: True
Feature: mean concave points Rank: 1, Keep: True
Feature: mean symmetry Rank: 1, Keep: True
Feature: mean fractal dimension Rank: 2, Keep: False
Feature: radius error Rank: 1, Keep: True
Feature: texture error Rank: 2, Keep: False
Feature: perimeter error Rank: 1, Keep: True
Feature: area error Rank: 1, Keep: True
Feature: smoothness error Rank: 3, Keep: False
Feature: compactness error Rank: 1, Keep: True
Feature: concavity error Rank: 1, Keep: True
Feature: concave points error Rank: 1, Keep: True
Feature: symmetry error Rank: 2, Keep: False
Feature: fractal dimension error Rank: 2, Keep: False
Feature: worst radius Rank: 1, Keep: True
Feature: worst texture Rank: 1, Keep: True
Feature: worst perimeter Rank: 1, Keep: True
Feature: worst area Rank: 1, Keep: True
Feature: worst smoothness Rank: 1, Keep: True
Feature: worst compactness Rank: 1, Keep: True
Feature: worst concavity Rank: 1, Keep: True
Feature: worst concave points Rank: 1, Keep: True
Feature: worst symmetry Rank: 1, Keep: True
Feature: worst fractal dimension Rank: 1, Keep: True
后续步骤
既然我们已经确定了要删除的特性,我们就可以放心地删除它们,继续我们的正常程序。您甚至可以使用.transform()方法来自动删除它们。你可能想尝试其他的特性选择方法来满足你的需求,但是 Boruta 使用了一种最强大的算法,并且快速易用。
祝你好运!
如果你遇到困难,请随时回复,我会尽我所能帮助你。
像我五岁一样解释:线性回归
让基本想法变得简单
我的小妹妹在我 10 岁时出生。我们很快成了好朋友,我会花很多个下午和她一起玩。当我们长大一点的时候,我们会一起尝试烹饪。后来我们会有各种建筑和游戏项目。总而言之,我们已经是一个团队 18 年了。我有机会和她分享我的知识。
几天前,我向她建议,我们应该测试一下一张动画预览图片会如何影响一篇中等帖子的点击量。她同意了——她会制作一个动画,我会测试它是否对点击量有积极的影响。但是,然后她问我:我们如何测试呢?
我感到剧痛。我忽略了作为一个哥哥的责任。我当然应该教我妹妹如何做实验。这种技能让我们在做任何事情时都有优势。为了弥补自己,我给她写了一篇关于如何使用线性回归分析实验结果的基本说明。
这是我对小姐姐的解释。以我们的动画实验为例。
1.我们在衡量什么
不久前,我写了我的第一篇文章,并在媒体上发表。让我的文章出现在媒体读者面前比我想象的要难一些。现在我有了更多的时间,我想用一部分时间来了解如何让媒体文章发挥作用。
和我妹妹一起,我们正专注于一个帖子的预览图片——也称为
缩略图。一个好的缩略图应该是相关的,真实的帖子,并鼓励人们点击帖子。一个改进的缩略图应该会增加点击帖子的人数。到目前为止,这似乎很符合逻辑。
下面是我写的一篇文章的原预览。这个女孩的照片是一个相当普通的,非动画的缩略图。
现在改善你的远程工作习惯,可以开启全新的机会
medium.com](https://medium.com/@manezki/enjoy-life-to-the-fullest-remote-efficiently-78af5e48f865)
帖子的点击数对作者是可用的,但它的名称不同。它们显示为浏览量的数量,也就是有多少人浏览了这个帖子。这是作者在帖子中看到的他们的观点:

这是一个作者在文章中看到的一些统计数据。如你所见,我们才刚刚开始。图片由作者提供。
对于我们的小测试,只查看看到动画缩略图的视图是有意义的。在我们的例子中,这些将是内部视图。他们是来自媒体的读者,他们肯定能看到动画缩略图。由于读者来自其他网站,如脸书,不清楚他们是否也看到了动画缩略图。因为我们对它们不确定,所以排除它们是个好主意。幸运的是,Medium 已经将它们算作外部视图,并且它们很容易被计算出来。

内部视图可以看到动画缩略图。然而,外部视图可能看不到
动画缩略图。图片由作者提供。
2.我们多快能获得浏览量
所以一个更好的缩略图会更快地获得浏览。我们怎么知道哪个更好?
原始缩略图和动画缩略图之间的差异很容易测试。我们可以在相同的时间内尝试两个缩略图,并比较最终哪个获得了更多的视图。但是原来的缩略图已经放在那里 99 天了。再过 99 天,我们可能会忘记整个实验。所以让我们试试别的。
相反,我们可以看看不同的缩略图获得视图的速度。
要知道这些,我们需要知道这篇文章每天有多少总浏览量。幸运的是,Medium 告诉我们每天有多少新的浏览量。

4 月 11 日 0 次查看。图片由作者提供。

3 4 月 12 日观点。图片由作者提供。

4 月 13 日观点。图片由作者提供。
按日期排列的总浏览量是所有前几天的总和。更重要的是,这些观点和自发布以来的天数的总和可以被绘制成一个图。像这样:

每天内部浏览的总和,使用原始缩略图。图片由作者提供。
这就是我们目前的情况。我们知道一段时间内的浏览量,但仅此而已。没什么有趣的信息。
3.比较缩略图
我们原来的问题是:一个动画缩略图会增加帖子的点击量吗?
目前,我们不知道。这是有道理的,但我们不知道,直到我们尝试一下。在我们尝试之后,我们将获得动画缩略图的浏览次数。现在,我为动画缩略图编了一些数字——这样我就可以展示测试的其余部分了。这里的数字是并排画的。

动画缩略图的一些虚构值。图片由作者提供。
从上面的图片中,我们可以看到动画缩略图已经生成了几乎与原始缩略图一样多的视图。但是,动画缩略图仅出现了 21 天。
我们完事了吗?动画缩略图似乎更好,对不对?
我们可以停在这里。但是我们仍然可以算出动画缩略图比好多少!这将是一件令人振奋的事情。这也有助于决定我们是否应该在这上面花时间。
为了感受不同之处,我们稍微改变了一下情节。我们添加一条直线,试图整齐地穿过两点之间。这条线是帖子获得浏览量的速度。线越陡越好。

对于这两个结果,我在两点之间添加了一条直线。图片由作者提供。
我们甚至可以通过一些简单的计算得到陡度的值。陡度等于天数除以这些天增加的观看次数。我把数值加到了下一张图片上。但是,请检查我们在点之间添加的线。为了使它更适合,它不会从第 0 天的 0 次查看开始。

右边的图计算了陡度。红色的文字告诉我们这条线有多陡——相当于
“我们每天有多少浏览量”。图片由作者提供。
为了获得改进值,我们将动画缩略图线的陡度除以原始缩略图的陡度。有了这个虚构的数据,动画缩略图会好 0.32/0.08 = 4 倍。所以有一个动画缩略图会很有用: )

这些是我们最后做的步骤。添加数据,添加直线,并计算直线的陡度。图片由作者提供。
我的小妹妹(和其他读者),这就是我们如何分析实验结果。
这不是唯一的方法,也不总是最好的方法。但是,这很简单,步骤也很容易与现实生活联系起来。许多事情正在幕后发生,但是当你开始时,理解它们是不必要的。更重要的是,我总是乐于助人。
NLP 中变压器的简单说明
NLP 中变压器的简单易懂的解释

克里斯·劳顿在 Unsplash 上的照片
先决条件:
在本帖中,我们将解决以下与 Transformer 相关的问题
- 我们为什么需要变压器,Sequence2Sequence 模型有哪些挑战?
- 变压器及其详细架构
- 深入探讨变形金刚中使用的术语,如位置编码、自我关注、多头自我关注、掩蔽多头自我关注
- 可以使用变压器的 NLP 任务
序列 2 序列(Seq2Seq)的挑战
- 顺序计算:在 Seq2Seq 中,我们以顺序方式在每一步向编码器输入一个单词,以便在解码器中一次生成一个单词的输出。我们可以通过并行化操作来实现计算效率,这在 Seq2Seq 建模中是不可能的

- 长期依赖:长期依赖是 Seq2Seq 的一个问题,因为需要对一个长句子执行大量操作,如下所示。

“它”这个词指的是“冠状病毒”或“国家”。
让我们深入变压器的架构和变压器的关键概念,了解变压器如何应对这些挑战
变压器架构
与 Seq2Seq 不同,Transformer 具有 6 个编码器和 6 个解码器的堆栈;编码器包含两个子层:多头自关注层和全连接前馈网络。
解码器包含三个子层,一个多头自关注层,一个对编码器输出执行多头自关注的附加层,以及一个完全连接的前馈网络。

高级变压器架构
编码器和解码器中的每个子层都有一个残差连接,然后是层归一化。

编码器和解码器的单一实例
编码器和解码器的输入
使用学习嵌入将编码器/解码器的所有输入和输出令牌转换成向量。这些输入嵌入然后被传递到位置编码。
位置编码
转换器的架构不包含任何递归或卷积,因此没有词序的概念。输入序列的所有字都被馈送到网络,没有特殊的顺序或位置,因为它们都同时流经编码器和解码器堆栈。
要理解一个句子的意思,理解单词的位置和顺序是必不可少的。
位置编码被添加到模型中,以帮助注入关于句子中单词的相对或绝对位置的信息
位置编码与输入嵌入具有相同的维数,因此两者可以相加。
自我关注
简单地说,注意力是为了更好地理解句子中单词的含义和上下文。
自我注意,有时被称为内部注意,是一种与单个序列的不同位置相关的注意机制,以便计算该序列的表示
自我关注层将所有位置与恒定数量的顺序执行操作连接起来,因此比递归层更快
转换器中的注意功能被描述为将查询和一组键和值对映射到输出。查询、键和值都是向量。使用句子中每个单词的标度点积注意力来计算注意力权重。最终得分是这些值的加权和。

来源:https://papers . nips . cc/paper/7181-attention-is-all-you-need . pdf
我们用一句话来理解这个吧, “我享受自然。”
输入是查询、键和值。向量的维数是 64,因为这导致稳定的梯度。
第一步:点积
为句子中的每个单词取查询和关键字的点积。点积决定了谁更关注输入句子中的其他单词。

第一步:点积
第二步:缩放
通过除以关键向量维数的平方根来缩放点积。维度为 64;因此我们将点积除以 8。

步骤 2:缩放点积
第三步:应用软最大值
Softmax 将缩放值规格化。应用 Softmax 后,所有值都是正的,加起来等于 1

步骤 3:应用 Softmax 来归一化缩放值
第四步:计算值的加权和
我们应用标准化分数和值向量之间的点积,然后计算总和

步骤 4:值的加权和
自我关注的完整方程式

对句子中的每个单词重复这些步骤。

句子中所有单词的注意力权重
多头注意力
变形金刚使用多个注意力头,而不是使用单一的注意力功能,在单一的注意力功能中,注意力可以由实际的单词本身支配。
每个注意力头部具有应用于相同输入表示的不同线性变换。变压器使用 8 个不同的注意头,并行独立计算。使用八个不同的注意头,我们有八组不同的查询、键和值,还有八组编码器和解码器,每组都是随机初始化的
"多头注意力允许模型在不同的位置共同注意来自不同表征子空间的信息."

多头关注;来源:https://papers . nips . cc/paper/7181-attention-is-all-you-need . pdf
利用多头注意力头,输入表征的每个部分与输入表征的其他部分相互作用,以获得更好的含义和上下文。由于多头注意力在不同位置观察不同的表征子空间,这也有助于学习长期依赖性。

“它”这个词指的是“冠状病毒”或“国家”。
使用多头注意力,我们得到上面句子中的单词“它”指的是“冠状病毒”。
掩蔽的多头注意力
解码器屏蔽了多头注意力,它屏蔽或阻止解码器输入进入后续步骤。在训练期间,解码器的多头注意力隐藏了未来的解码器输入。
对于使用转换器将句子“我享受自然”从英语翻译成印地语的机器翻译任务,解码器将考虑所有输入单词“我享受自然”来预测第一个单词。
下表显示了解码器如何阻止后续步骤的输入

训练期间掩蔽的多头注意力解码器输入和预测
编码器和解码器中的每个子层都有一个残差连接,然后是层归一化。
残差连接和图层归一化有什么帮助?
剩余连接是“跳过连接”,允许梯度流过网络,而不通过非线性激活函数。残留连接有助于避免消失或爆炸梯度问题。为了使剩余连接工作,模型中每个子层的输出应该是相同的。变压器中的所有子层产生维度 512 的输出。
图层标准化:标准化每个特征的输入,独立于其他示例,如下所示。层标准化减少了前馈神经网络的训练时间。在层标准化中,我们在单个训练案例上计算层中神经元的所有总输入的均值和方差。

图层规范化
全连接层
变换器中的编码器和解码器都有一个完全连接的前馈网络,它有两个线性变换,中间包含一个 ReLU 激活。
解码器的线性和软最大层
解码器的最后一层应用线性变换和 softmax 函数来转换解码器输出,以预测输出概率
变压器的特点
seq2seq 模型的缺点由 Transformer 解决
- 并行计算 : Transformer 的架构去除了 Seq2Seq 模型中使用的自回归模型,完全依靠自我关注来理解输入和输出之间的全局依赖关系。自我关注对并行计算有很大帮助
- 操作次数减少:变形金刚的操作次数不变,因为注意力权重在多头注意力中是平均的
- 长程相关性:影响长程相关性学习的因素基于信号在网络中必须经过的前向和后向路径的长度。输入和输出序列中任何位置组合之间的路径越短,就越容易了解长程相关性。自我注意层将所有位置与学习长程依赖的恒定数量的顺序执行的操作连接起来。
变压器处理的 NLP 任务
- 抽象文本摘要
- 神经机器翻译
结论:
变压器具有基于自关注机制的简单网络架构,并且不完全依赖于递归和卷积。计算是并行执行的,这使得变压器效率更高,并且需要更少的训练时间
参考资料:
吉米·巴雷、杰米·瑞安·基罗斯和杰弗里·e·辛顿的图层规范化
讨论:黑客新闻(65 分,4 条评论),Reddit r/MachineLearning (29 分,3 条评论)翻译…
jalammar.github.io](http://jalammar.github.io/illustrated-transformer/)
https://nlp.seas.harvard.edu/2018/04/03/attention.html
Python 中的简单人脸检测
如何使用 OpenCV 库检测图像中的人脸

在这篇文章中,我将向你展示如何使用 Python 构建一个简单的人脸检测器。构建一个检测人脸的程序是一个非常好的计算机视觉入门项目。在以前的帖子中,我展示了如何识别图像中的文本,这是在计算机视觉中练习 python 的一个很好的方法。今天我们来做一件更好玩更有趣的事情:人脸检测。
如何使用文本识别器改进笔记记录过程
towardsdatascience.com](/building-a-simple-text-recognizer-in-python-93e453ddb759)
顾名思义,我们将编写一个程序来检测图像中的人脸。当我说“程序”时,你可以理解为教一台机器做什么。我喜欢用教学而不是编程,因为这实际上是我们正在做的事情。最好的学习方式是教学,所以在教机器如何识别人脸的同时,我们也在学习。在我们进入项目之前,我想分享一下人脸检测和人脸识别器的区别。
人脸检测与人脸识别
这两件事听起来可能非常相似,但实际上,它们并不相同。让我们明白其中的区别,这样才不会漏掉重点。人脸检测是从一幅图像或一段视频中检测人脸的过程。这个程序除了寻找人脸之外什么也不做。但是另一方面,人脸识别,程序找到了人脸,也能分辨出哪张脸是谁的。所以它比仅仅检测它们更能提供信息。有更多的编程,换句话说,更多的教学🙂
假设你在看街,有车经过。人脸检测就像告诉路过的物体是一辆车。而人脸识别器就像是能够分辨出路过的汽车的型号。这里有一个很好的图像显示了实践中的差异。

我们开始吧!
我们将为这个项目使用一个模块库,它被称为 OpenCV。OpenCV 是一个高度优化的库,专注于实时应用。
OpenCV(开源计算机视觉库)是一个开源的计算机视觉和机器学习软件库。OpenCV 旨在为计算机视觉应用提供一个公共基础设施,并加速机器感知在商业产品中的应用。作为一个 BSD 许可的产品,OpenCV 使得企业利用和修改代码变得很容易。
使用 OpenCv 库进行实时人脸识别的分步指南
towardsdatascience.com](/building-a-face-recognizer-in-python-7fd6630c6340)
图书馆
首先,让我们安装软件包。
pip install opencv-python
安装完成后,我们可以将其导入到我们的程序中。
import cv2
OpenCV 已经包含了许多预先训练好的人脸、眼睛、微笑等分类器。这些 XML 文件存储在一个文件夹中。我们将使用人脸检测模型。
如果您有帐户,可以从 Github 下载 XML 文件。如果没有,可以从下面的链接中复制代码,粘贴到一个文本文档中,保存为“face_detector.xml”。
将文件保存到当前文件夹后,让我们将它加载到我们的程序中。
# Load the cascadeface_cascade = cv2.CascadeClassifier('face_detector.xml')
导入图像
在这一步中,您将选择一个要测试代码的图像。确保图像中至少有一张脸,以便我们的程序可以找到一张。这是一个人的图像示例。

选择图像后,让我们在程序中定义它。确保图像文件位于您正在处理的同一文件夹中。
# Read the input imageimg = cv2.imread('test.jpg')
人脸检测
你会惊讶于人脸检测代码有多短。感谢为 OpenCV 做出贡献的人们。下面是检测图像中人脸的代码:
# Detect faces
faces = face_cascade.detectMultiScale(img, 1.1, 4)
我们在前面的代码中定义了 face_cascade。在检测到人脸后,我们将在它们周围绘制矩形,这样我们就知道机器看到了什么。机器可能会出错,但我们的目标应该是教授最佳和最优化的方法,以便预测更加准确。
使用以下代码可以在检测到的人脸周围绘制矩形:
# Draw rectangle around the faces
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
- (255,0,0)是我们要绘制的矩形的颜色。你玩它,改变颜色。
- (2)是线条的粗细。您可以更改该值并查看其外观。
结果呢
这是最后一步,现在我们将我们的结果导出为图像文件。此图像将显示人脸检测的结果。为了保存一个新的图像文件,我们将使用 cv2 库中名为“imwrite”的方法。保存完成后,您将在终端上看到“成功保存”。
# Export the resultcv2.imwrite("face_detected.png", img) print('Successfully saved')

另一个例子:

恭喜你。!您已经创建了一个检测图像中人脸的程序。现在,你有了一个如何教机器为你做一些很酷的事情的想法。希望你喜欢这篇教程,并在今天学到一些新东西。在我的下一篇文章中,我将分享如何使用 python 构建人脸识别器。
谢谢你,
每当贝希克居文出版时收到电子邮件。通过注册,您将创建一个中型帐户,如果您还没有…
lifexplorer.medium.com](https://lifexplorer.medium.com/subscribe)
适合您的机器学习项目:
使用谷歌云语音 API 将您的音频文件转换为文本
towardsdatascience.com](/building-a-speech-recognizer-in-python-2dad733949b4) [## 使用 Python 构建条形码/QR 码阅读器
使用 Pyzbar 库的简单且可实际操作的机器学习项目
towardsdatascience.com](/building-a-barcode-qr-code-reader-using-python-360e22dfb6e5)
简单有趣的万圣节 Python 项目!
这是一个有趣的“不给糖就捣蛋”的游戏,让你在万圣节愉快地学习 python 编程

由 Unsplash 上ukasz niecioruk拍摄的照片
在今天的文章中,我们将通过一个简单而有趣的项目来了解 python 编程的一些基础知识。本文的后续部分也提供了完整的代码。
由于 10 月 31 日是许多国家庆祝的万圣节,我认为用我编的有趣的“不给糖就捣蛋”游戏来学习一些 python 编程是个好主意。
在我们进一步讨论问题陈述和我们今天将构建的简单有趣的游戏之前,让我们了解一下我们将在本文中试图实现的一些基本目标以及您可以期待的内容。
下面的 gif 代表了我们的项目的一部分,这将是我们在这个项目中建立的两只乌龟之间的小比赛

作者截图
本文旨在更好地理解函数,并在享受构建简单项目的过程中学习编程。我们将使用一些很酷的库,如 turtle 模块和 Google 文本到语音模块来构建这个项目,并获得更多关于这些库的知识。
不要担心,如果你不知道这些,因为我将触及所有的基本要求,在一个简单详细的方式,对这个项目的完整理解。
问题陈述:
你给用户一个选择的机会——不给糖就捣蛋。如果选择请客,那么你只需展示一只海龟到达终点,获胜的话你会得到一块饼干。图像,以及语音记录,需要建议胜利的奖励。如果选择的是一个诡计,那么用户可以在两个可用的海龟上下注。因此,用户有 50%的机会赢得蛋糕奖励,否则他得不到任何奖励。
如果你想让问题陈述更复杂一点,那么你也可以增加这一行。
如果用户失去了第一个 50%的机会,还可以添加石头、纸、剪刀游戏的附加 else 情况,以向用户提供赢得游戏的更高机会。
方法:
解决这个问题的方法很简单。我们将使用两个函数,即 trick()和 treat()。我们将为用户提供一个输入选项,要么选择安全对待()并赢得一个 cookie,要么选择通过选择 trick()来赢得更大的蛋糕奖励。
选择 treat()选项后,我们将有一只乌龟在乌龟图形窗口上运行,并为用户检索奖励。该选项将是一个无风险的选择,用户可以做出并获得一个 cookie 作为奖励。然而,如果用户想要更大的回报,并想冒一些风险,那么我们有 trick()选择可用。
trick()选项将允许用户在两只乌龟之间进行选择,即红色或蓝色。无论你赌哪个海龟,都是你的选择。如果你选择的乌龟赢了比赛,你会得到一个蛋糕作为奖励。但是如果你选择的海龟没有赢,你就没有奖励。(另一个选择是石头、布、剪刀游戏,我之前建议给用户另一个机会。)
每当你赢了,无论是一块饼干还是一块蛋糕,图像都会相应地显示出来,而且你还会从计算机那里得到一个声音响应,表明你已经成功地赢得了游戏。对于失败的情况,您也可以有一个备选的响应。
了解模块:
turtle 模块是一个有趣的图形模块,主要用于初级程序员向他们介绍 Python 编程的世界。python 中的 turtle 模块允许用户在图形窗口上绘图,还可以添加一些乌龟来构建一个令人愉快的项目。
在这篇文章中,我将简要介绍海龟模块。我还将详细介绍其他模块。gTTS 模块已经在另一篇文章中广泛讨论过了,如果您刚刚开始使用它,我强烈推荐您阅读这篇文章。首先,我将简要介绍一下简单的模块。
枕头(PIL)图书馆进口的图像功能,将用于显示图像的胜利。这些是将作为奖励展示的饼干和蛋糕的图像。如果您愿意,也可以使用 open-cv 模块来实现这一目的。
playsound 模块用于播放将由 gTTS 模块保存的录音。您也可以使用 python 中的 OS 模块来完成相同的任务,如果您在安装 playsound 模块时遇到困难,这是首选。然而,当我尝试播放声音时,我不喜欢额外的 VLC 或默认媒体播放器打开,这就是我使用 playsound 模块的原因。
随机模块用于随机生成给定范围内的数字。对于这个项目来说,只有关于随机模块的那么多信息就足够了。然而,我强烈建议您查看比例抽样指南,以了解关于该模块的更多细节。
[## 分步指南:使用 Python 进行数据科学的比例采样!
了解使用 python 进行数据科学所需的比例采样的概念和实现…
towardsdatascience.com](/step-by-step-guide-proportional-sampling-for-data-science-with-python-8b2871159ae6)
因为我还没有在其他地方介绍过海龟模块,所以这正是我在这篇文章中要做的事情。别担心,这只是你需要知道的一些事情。我将只检查这个项目所需的要点。你可以从官方文档中了解更多信息。
本项目 Turtle 模块所需命令快速指南:
1.移动和绘制命令:
- ()—沿着乌龟前进的方向,将乌龟向前移动指定的距离。
- 向后() —将乌龟向后移动距离,与乌龟前进的方向相反。不要改变海龟的方向。
- 右() —将乌龟向右旋转角度单位。(默认情况下,单位为度)。
- left() —将乌龟向左旋转角度单位。
2.绘图状态:
- penup() —向上拉笔,即移动时不绘图。
- pendown() —向下拉笔,即边移动边画。
- write() —根据 align ("left "、" center "或 right ")和给定的字体,在当前海龟位置按照' arg '的字符串表示形式书写文本。
- exitonclick() —将 bye()方法绑定到屏幕上的鼠标点击。
3.颜色:
- 颜色() —给你的乌龟一个特定的颜色。
- pencolor() —为绘图的笔赋予特定的颜色。
最后,我们将转移到这个项目所需的最终谷歌文本到语音模块。
文本到语音(TTS)是将单词转换成音频形式的过程。程序、工具或软件从用户处获取输入文本,使用自然语言处理方法,理解所用语言的语言学,并对数据进行逻辑推理。
该处理后的文本进入下一个块,在那里对处理后的文本数据进行数字信号处理。通过使用许多算法和转换,这个处理过的文本最终被转换成语音格式。这整个过程包括语音合成。下面是解释相同内容的文章的链接。
[## 如何使用 Python 开始使用 Google 文本到语音转换
从零开始的文本到语音转换简介
towardsdatascience.com](/how-to-get-started-with-google-text-to-speech-using-python-485e43d1d544)
Python 提供了广泛的库模块和框架,使其成为构建机器学习模型和从事数据科学项目最兼容的语言之一。除了所使用的标准库之外,本文旨在提供一些很酷的模块,供您的机器学习和数据科学项目使用。如果你们有兴趣了解更多关于其他模块的内容,我强烈推荐你们去看看。
[## 5+独特的 Python 模块,用于创建脱颖而出的机器学习和数据科学项目!
超过 5 个酷 Python 库模块的指南,用于创建令人敬畏的机器学习和数据科学项目。
towardsdatascience.com](/5-unique-python-modules-for-creating-machine-learning-and-data-science-projects-that-stand-out-a890519de3ae)
程序:
我的代码有两个功能。我将利用第一个函数对与 treat()选项相关的所有想法进行编码。第二个函数将针对与技巧选择相关的所有想法进行完整编码。
创建 treat 函数相当简单。我们将只画一条简单的跑道,一只红色的乌龟将参加比赛,并为主人拿到巧克力作为奖励。这可以通过下面的代码块来完成:
观察上面的代码块,并尝试解释这里到底发生了什么。我们正在为我们的海龟画一条跑道,并定义设置参数,这样跑道就建在图形窗口屏幕的中心。红海龟的位置在赛道的中心。
一旦海龟完成比赛,系统会提示你点击屏幕来结束图形窗口界面的运行。只要您点击屏幕,您就会收到祝贺您获得奖励的音频响应,并显示您赢得的 cookie 的图像。
下面是将为此项目显示的 cookie 的图像。我在代码块中将它重命名为“Cookies.jpg”。如果您想运行相同的程序,那么您也应该考虑这样做。

让我们以类似的方式编写下一个 trick()函数。
trick()函数将有一个参数,即用户选择的选项。默认颜色为红色,但是用户可以根据自己的喜好自由选择红色或蓝色的乌龟。
下面是实现特技功能的完整代码块。
trick()函数类似于 treat()函数。主要的区别是使用两只乌龟而不是一只。我们正在为我们的海龟画一条跑道,并定义好参数,这样跑道就在图形窗口的中心了。红海龟和蓝海龟的位置被放置在赛道中心附近。
当一只海龟越过终点线时,比赛就停止了。获胜的海龟将第一个冲过终点线。我们将计算每只海龟走过的总距离,谁走的距离更长,谁就赢得比赛。
我现在将对上面的代码执行一次测试。我选的乌龟是“红色”
让比赛开始吧!

作者截图
计算表明,红色显然赢得了比赛,因此,由于我选择的选项也是红色,那么蛋糕的奖励也将呈现给我!
下面的图像和一个祝贺的音频响应消息被提供给这个胜利案例的用户。

大卫·霍利菲尔德在 Unsplash 上拍摄的照片
这个项目植入的最终代码块是要给用户的选择选项。
第一个选择是不给糖就捣蛋。如果选择了特技选项,那么用户有两个选择。他们可以相应地选择红色或蓝色的海龟。
下面是这个实现的代码块以及一个示例输出。
Make Your Numerical Choice:
1\. Trick
2\. Treat
1
Enter red or blue: red
307 298
上面显示的示例输出是用户选择选项 1 的运行之一。第一个选项是 trick()函数,它会提示你选择一只海龟。如前所述,获胜的海龟会显示各自的输出。
让我们了解一些可以对这个简单项目进行的进一步改进。
进一步改进:
本文中展示的项目是一个非常基础的入门项目。这个“不给糖就捣蛋”的项目可以做很多改进。下面是一些有助于使项目更酷、更创新的改进:
- 如前所述,您可以自由地试验 else 的情况。你可以像选择另一个游戏一样添加各种选项,或者只是添加一个额外的命令,表明拒绝。
- 我强烈建议用 pygame 或 Tkinter 等其他模块来尝试项目的变体,以使它在图形和视觉上更吸引观众。
- 另一个更高级方法的建议是致力于构建深度学习或强化学习模型,以实现更好的结果。
- 改造项目,并加入你自己的想法,使其更加复杂和有趣。
- 项目的部署,以确保它达到更广泛的受众。

由 Riccardo Chiarini 在 Unsplash 拍摄的照片
结论:
学习编程的最好方法是享受和欣赏它的美丽。我们开发了一个简单的“不给糖就捣蛋”的游戏,理解了这项任务所需的一些模块,并对功能有了更多的了解。
我在这个项目中使用的方法和分析非常简单明了。它是以一种直观的方式来理解建立这个简单的游戏的基础。
提高编程语言效率的最好方法之一是改编和构建更多的游戏。你在娱乐的同时学习新的概念。所以这是一个双赢的局面!
查看其他一些可能对您的编程之旅有用的文章!
详细了解 python 中的匿名函数和高级函数及其实际应用…
towardsdatascience.com](/understanding-advanced-functions-in-python-with-codes-and-examples-2e68bbb04094) [## 机器学习和数据科学项目的 10 步终极指南!
详细讨论构建您的机器学习和数据科学项目的最佳方法…
towardsdatascience.com](/10-step-ultimate-guide-for-machine-learning-and-data-science-projects-ed61ae9aa301) [## 2020 年及以后最受欢迎的 10 种编程语言
讨论当今 10 种最流行的编程语言的范围、优缺点
towardsdatascience.com](/10-most-popular-programming-languages-for-2020-and-beyond-67c512eeea73)
谢谢你们坚持到最后。我希望你们喜欢阅读这篇文章。我希望你们都有美好的一天!
COVID 19 Choropleth 图
Choropleth 地图使用 Plotly 追踪 COVID 19 例。

Ashkan Forouzani 在 Unsplash 上的照片
这里有一个使用 Python 中的 Plotly 图形库绘制 Choropleth 地图的简单教程。
我从 世卫组织仪表盘 得到灵感,想自己实现一个。
事实证明这很容易做到,虽然这篇文章不是我通常的随机数据集系列的一部分,但像这样学习数据可视化技能,对于数据科学家交流见解非常重要。
让我们直接进入教程。
1)下载并清理数据集-
你可以从 世卫组织站点 下载数据集,但是要注意有很多特殊字符要删除。
此外,一些国家,如库拉索岛、圣巴泰勒米岛、留尼汪岛等。,格式不正确。因此,在将 CSV 文件导入熊猫数据框架之前,有大量的清理工作要做。
你可以跳过上面的麻烦,下载我已经清理过的数据集 的 ,但是这可能意味着在将来你决定为自己实现本教程的任何时候,数据都不是最新的。
2)导入清理后的数据集-
既然您已经自己清理了数据集,或者已经下载了预处理过的数据集,下一步就是导入这个数据集。
我们将删除一些不需要绘图的列。
3) Choropleth 地图
使用 Plotly 图形库绘制 Choropleth 地图非常容易。
我们必须创建一个数据对象,其中包含每个国家及其感染/死亡人数的实际信息,并创建一个布局对象来查看图表。
有 2 个 choropleth 图;一个追踪全世界的感染人数,另一个显示 COVID 死亡人数。
COVID 19 感染计数。作者 GIF
在中型文章中直接嵌入交互式 Plotly 可视化不再有效,所以我捕捉了一张我在不同国家上空盘旋的 gif 图,向你展示地图的样子。您可以通过点击下面的链接来查看交互式可视化。
[## COVID 19:全球感染计数| choropleth 由 Shrad09 | plotly 制作
编辑描述
plotly.com](https://plotly.com/~shrad09/1/)
这是你绘制这张地图的方法。
Once you execute the line, plot(fig_cases), the Choropleth Map will open up in your browser as an interactive map.
用同样的方法绘制世界各地的死亡率。
COVID 19 伤亡人数。作者 GIF。
再一次,点击下面的链接,你可以随意地玩这个交互式可视化游戏。
[## COVID 19:全球死亡人数| choropleth 由 Shrad09 | plotly 制作
编辑描述
plotly.com](https://plotly.com/~shrad09/3/)
这就对了。以下是如何用一种简单的方式绘制 Choropleths 地图。要记住的重要一点是以易于绘制的方式设置数据集。
如果你自己已经实现了一个,并且想弄清楚如何在媒体上嵌入你的交互式可视化,你可以看看这篇文章。
希望你觉得这个教程有用和有趣。可以看看我的其他 文章 有趣的机器学习教程和 我的 GitHub repo。
非常感谢您的阅读,我们很快会再见的!
解决贝叶斯定理问题的简单指南

树木是你的朋友
先说贝叶斯定理。贝叶斯定理是一个简单的概率公式,既通用又强大。它一直被誉为机器学习和数据科学中的热门新事物,直到神经网络出现并扮演了金·卡戴珊和贝叶斯的帕丽斯·希尔顿。与其他机器学习技术相比,贝叶斯定理特别有趣的是,公式本身已经有近 200 年的历史,而其他形式的机器学习通常有一个,比如说更年轻的年份。
概率可能是一个令人困惑的领域,你必须有足够的心智能力,能够在头脑中摆弄一些数字,以便能够解决一些更基本的问题。今天,我们将深入一个简单的方法来解决基本的贝叶斯定理问题。
一点背景

让我们来谈谈我们将要谈论的话题,嗯?贝叶斯定理是由英国长老会牧师托马斯·贝叶斯在 1763 年创立的。你们中的许多人可能会惊讶地听到神职人员负责,但在 20 世纪之前的几个世纪里,神职人员在很大程度上负责数学和科学的进步。遗传学的创始人格雷戈尔·孟德尔本人就是奥古斯丁修会的修士和修道院院长。
现在,贝叶斯定理作为一种方法被提出,通过这种方法,先前事件的知识将增加人们描述该事件或相关事件再次发生的概率的能力。例如,教科书中常见的一个例子是,如果健康问题的风险通常随着年龄的增长而增加,那么贝叶斯定理的应用允许我们更准确地评估已知年龄的个体的健康风险。如果你读了我之前关于朴素贝叶斯的文章,你就会知道这是怎么回事了。让我们看看公式,好吗?

好了,这似乎很容易。我们需要做的就是找到 P(B|A),P(A)和 P(B)的概率,把它们代入,瞧,我们就有了计算结果!现在,如果有更简单的方法来做这件事呢?如果你对概率的走向感到困惑怎么办?如果应用题是你的敌人怎么办?该死的,这是数学,不是阅读理解!
更简单的方法
为什么在不需要的时候做数学?— Yi Shuen Lim
让我们来看看解决贝叶斯定理的潜在替代方法,当你看到它时,将允许你理解问题的所有方面。我们将使用我在熨斗中遇到的一个问题,因为我不是数学老师,也没有人付钱让我做数学题。
托马斯想要一只新的小狗。
他可以选择从宠物店或动物收容所得到他的新小狗。他去宠物店的概率是 0.2。
他可以选择得到一只大、中或小的小狗。
如果他去宠物店,他得到一只小狗的概率是 0.6。他得到一只中型小狗的概率是 0.3,他得到一只大型小狗的概率是 0.1。
如果他去动物收容所,他得到一只小狗的概率是 0.1。他得到一只中型小狗的概率是 0.35,他得到一只大型小狗的概率是 0.55。
1。托马斯得到一只小狗的概率有多大?
2。鉴于他得到了一只大型小狗,托马斯去宠物店的概率是多少?
3。假设托马斯有一只小狗,他去宠物店还是去动物收容所的可能性更大?
所以对于这个问题,我们将使用另一种方法来计算公式。我们打算种树。树是伟大的,它们帮助我们分解问题,并把它重铸成一个清晰和容易理解的格式。所以我们开始画吧!我们要做的第一件事是画出我们树的基本分支。

嘣。我们已经有效地将这个单词问题分解成它的结构组件,并以一种易于理解的格式展示出来。我们从托马斯和他去宠物店或收容所的决定开始,然后一旦在宠物店或收容所,我们将进一步的决定细分为小型,中型或大型狗。下一步是输入我们的概率。

看到我做了什么吗?现在我们已经得到了这个问题中给我们的概率,并把它们放在我们的树上。我们知道托马斯有 20%的概率去宠物店,到了那里有 60%的概率得到一只小狗,30%的概率得到一只中号狗,10%的概率得到一只大型犬。同样的情况也适用于 80%的概率,他去收容所和相关的概率为小型,中型和大型狗。还要注意,每个交叉点上的这些概率的总和是 100%,因为我们不能有超过 100%的概率,而小于 100%的总概率意味着还有另一种选择。如果你得到了一个单词问题的不完整信息,知道这一点是很有用的。
现在,我们来看第一个问题。
托马斯得到一只小狗的概率有多大?
为了解决这个问题,我们需要确定托马斯在宠物店或收容所得到一只小狗的所有概率。我们只需要将概率相乘,然后将它们相加,如下所示:

沿着红色箭头的路线,我们追踪了托马斯的路线,他先是去了宠物店或收容所,然后在那里得到了一只小狗。为了找到所有可能购买小狗的概率,我们采用收容所或宠物店的概率,然后乘以相应的购买小狗的概率。然后我们把那些加在一起,求出托马斯买小狗的概率的答案!通过简单地跟踪树中的分支,我们能够跟踪必要的概率,并将它们组合起来以找到所有小狗的情况。
现在让我们超越自我,完成所有概率的计算:

太好了!现在我们有了一个现成答案的适当框架,准备回答关于托马斯选择的任何问题。如果我们想知道托马斯得到一只大狗的概率会怎样?好吧,让我们回头看看我们的树。宠物店大型犬有 0.02 的概率,收容所大型犬有 0.44 的概率。我们把这些加在一起,大狗的概率是. 46!
现在进入第二个问题。
假设托马斯得到了一只大狗,他去宠物店的概率是多少?
嗯,这确实是一个贝叶斯问题。如果我们把这个公式写出来,它会是这样的:

多亏了我们的树,我们不必绞尽脑汁去计算 P(大)需要构造什么样的概率。让我们回头参考我们的树来找到所需的组件。

因此,我们的公式看起来像这样:

这给了我们 .04347!
现在,进入最后一个问题!
假设托马斯得到了一只小狗,他去宠物店还是去动物收容所的可能性更大?
这个有点棘手。给定小型犬,P(宠物店|小型犬)和 P(收容所|小型犬)哪个更高?在这种情况下,我们将不得不重复公式,但两次,并确定哪个更高。
为了简化事情,我给你你需要的变量:
对于 P(宠物店|小狗):
P(小狗|宠物店)= .60
P(宠物店)= .20
P(小狗)= .20
对于 P(收容所|小型犬):
P(小型犬|收容所)= .10
P(收容所)= .80
P(小型犬)= .20
现在把这些代入贝叶斯定理,看看我们会得到什么数字?
以下是答案:
P(宠物店|小狗)= .60
P(收容所|小狗)= .40
由于 P(宠物店|小狗)比 P(收容所|小狗)大,鉴于托马斯给自己弄了一只小狗,托马斯去宠物店领狗的可能性更大!
结论
我希望你今天离开的时候,对贝叶斯定理的工作原理有了更好的理解,并且在面对这样的概率问题时,有了更多的安慰。视觉上分解事物几乎总是能帮助一个人理解他们所面临的情况,我认为这里的树对我们的理解有很大的帮助。这种方法的伟大之处在于,它几乎可以无限扩展,让你可以找到解决每个问题所需的概率。我将留给你们一个我在维基百科上找到的问题。自己建树,看自己能不能答出来!
假设我们有一个测试大麻使用的药物测试。现在,这种测试有 90%的真实阳性率,也就是说,90%的时候,它会检测到一个大麻使用者。它也有 80%的真实阴性率,即 80%的时间它将确认一个人没有使用大麻。不幸的是,它也会产生 20%的误报。考虑到所有接受测试的人中有 5%是大麻使用者,那么使用这种测试的大麻测试呈阳性的人是真正的大麻使用者的概率是多少?我给你一个开始的提示,你的树的第一个分支应该是大麻使用者。
玩得开心!
使用 Tensorflow 对初学者进行简单的 CNN 图像分类
通过做一个将使用卷积神经网络的项目,学习执行一个简单的图像分类任务。

资料来源:Unsplash 作者 Tran Mau Tri Tam
图像分类不再是一个困难的话题。Tensorflow 拥有所有内置的功能,为我们处理复杂的数学问题。在不知道神经网络细节的情况下,我们现在可以使用神经网络。在今天的项目中,我使用了卷积神经网络(CNN ),它是神经网络的高级版本。它把一幅画浓缩成一些重要的特征。如果您使用包含衬衫、鞋子和手袋等的 FashionMNIST 数据集。美国有线电视新闻网将找出图像的重要部分。例如,如果你看到一个鞋带,它可能是一只鞋,如果有一个衣领和纽扣,那可能是一件衬衫,如果有一个把手,那可能是一个手提包。
概观
我们今天将构建的简单 CNN 将对一组图像进行分类,它将由卷积和池组成。输入在卷积层中进行修改。您可以根据需要放置一个或多个卷积。输入经过几个过滤器,这些过滤器对输入进行切片,以学习输入的一些部分,例如衬衫的纽扣、手提包的把手或鞋子的鞋带。我今天不打算在这方面深入探讨。因为这篇文章是写给初学者的。
联营是 CNN 的另一个非常重要的部分。池像卷积一样在每个局部区域上工作,但是它们没有过滤器,并且是向量到标量的转换。简单地计算该区域的平均值,识别具有最高强度的像素,并消除其余的像素。2 x 2 池会将要素地图的大小减少一半。即使你不知道其中的数学部分,你仍然可以解决一个深度学习问题。我会解释每一行代码。如今,我们有如此丰富的库来执行所有这些惊人的工作,甚至不需要了解太多的数学或编码。让我们开始吧。
CNN 发展
我用的是谷歌 Colab 笔记本。如果你没有安装 anaconda 和 Jupiter 笔记本,你仍然可以在上面工作。每个人都可以使用谷歌的 collaboratory 笔记本。youtube 上有很多学习如何使用 Google Colab 的视频。如果你不知道 Google Colab,请随时查看。我们将使用包含猫和狗的图像的数据集。我们的目标是开发一个卷积神经网络,它将成功地从一张图片中对猫和狗进行分类。我们用的是 Kaggle 的数据集。
首先导入所有需要的包和库。
import osimport zipfileimport randomimport tensorflow as tffrom tensorflow.keras.optimizers import RMSpropfrom tensorflow.keras.preprocessing.image import ImageDataGeneratorimport shutil
是时候获取我们的数据集了。我们将使用名为“wget”的函数将数据集放入笔记本中。只是提醒一下,一旦你的 Google Collab 笔记本的会话结束,你必须再次导入数据集。让我们下载完整的 Cats-v-Dogs 数据集,将其存储为 cats-and-dogs.zip,并保存在名为“tmp”的目录中。
!wget –no-check-certificate \ "https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_3367a.zip" \ -O "/tmp/cats-and-dogs.zip"
现在从 zip 文件夹中提取数据,这将生成一个名为“temp/PetImages”的目录,其中有两个子目录,分别名为 Cat 和 Dog。这就是数据最初的结构。
local_zip = '/tmp/cats-and-dogs.zip'zip_ref = zipfile.ZipFile(local_zip, 'r')zip_ref.extractall('/tmp')zip_ref.close()
让我们检查猫和狗的文件夹。
print(len(os.listdir('/tmp/PetImages/Cat/')))print(len(os.listdir('/tmp/PetImages/Dog/'))
由于数据可用,现在我们需要创建一个名为 cats-v-dogs 的目录和子目录 training and testing。
try: os.mkdir('/tmp/cats-v-dogs/') os.mkdir('/tmp/cats-v-dogs/training/') os.mkdir('/tmp/cats-v-dogs/testing/')except OSError: pass
现在,为训练和测试拆分数据,用函数 split_data 将数据放在正确的目录中。Split_data 采用包含文件的源目录、数据切片将被复制到的训练目录、剩余数据将被复制到的测试目录以及分割数据的 split_size。
def split_data(SOURCE, TRAINING, TESTING, SPLIT_SIZE): cont = os.listdir(SOURCE) lenList = len(cont) shuffleList = random.sample(cont, lenList) slicePoint = round(len(shuffleList)*SPLIT_SIZE) for i in range(0, len(shuffleList[:slicePoint])): if os.path.getsize(SOURCE+cont[i]) !=0:
shutil.copy(os.path.join(SOURCE,cont[i]), training)
下面的代码块检查剩余文件的长度,并将它们放在测试目录中。
for j in range(len(shuffleList[slicePoint:])): if os.path.getsize(SOURCE+cont[j]) !=0: shutil.copy(os.path.join(SOURCE,cont[j]), testing)
功能就绪。使用 split_data 函数拆分源目录的数据,并将它们复制到培训和测试目录。
CAT_SOURCE_DIR = "/tmp/PetImages/Cat/"TRAINING_CATS_DIR = "/tmp/cats-v-dogs/training/cats/"TESTING_CATS_DIR = "/tmp/cats-v-dogs/testing/cats/"DOG_SOURCE_DIR = "/tmp/PetImages/Dog/"TRAINING_DOGS_DIR = "/tmp/cats-v-dogs/training/dogs/"TESTING_DOGS_DIR = "/tmp/cats-v-dogs/testing/dogs/"split_size = .9split_data(CAT_SOURCE_DIR, TRAINING_CATS_DIR, TESTING_CATS_DIR, split_size)split_data(DOG_SOURCE_DIR, TRAINING_DOGS_DIR, TESTING_DOGS_DIR, split_size)
检查培训和测试目录的长度。
print(len(os.listdir('/tmp/cats-v-dogs/training/cats/')))print(len(os.listdir('/tmp/cats-v-dogs/training/dogs/')))print(len(os.listdir('/tmp/cats-v-dogs/testing/cats/'))print(len(os.listdir('/tmp/cats-v-dogs/testing/dogs/')))
数据预处理完成。有趣的部分来了。我们将开发一个 Keras 模型来对猫和狗进行分类。在这个模型中,我们将使用三个卷积层和一个池层。你可以用更少或更多的卷积层来尝试。我们将使用一个激活函数和 input_shape 150 x 150。这个 input_shape 会将所有的图像重新塑造成这个相同的正方形。否则,现实世界中的图像将会有不同的大小和形状。在第一层中,我们的过滤器尺寸是 3×3,过滤器的数量是 16。最大池化 2 x 2 将像素浓缩 2 倍。我们还有两层不同数量的过滤器。您可以添加额外的“Conv2D”和“MaxPooling2D”层来观察结果。
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(150, 150, 3)), tf.keras.layers.MaxPooling2D(2,2), tf.keras.layers.Conv2D(32, (3,3), activation='relu'), tf.keras.layers.MaxPooling2D(2,2), tf.keras.layers.Conv2D(64, (3,3), activation='relu'), tf.keras.layers.MaxPooling2D(2,2), tf.keras.layers.Flatten(), tf.keras.layers.Dense(512, activation='relu'), tf.keras.layers.Dense(1, activation='sigmoid')model.compile(optimizer=RMSprop(lr=0.001), loss='binary_crossentropy', metrics=['acc'])
在编译函数中,我们至少应该传递优化器和损失参数。这里学习率是 0.001。选择合理的学习速度很重要。学习率太小和太大都会使网络效率低下。下一步是标准化数据。
from tensorflow.keras.preprocessing.image import ImageDataGeneratorbase_dir = '/tmp/cats-v-dogs'TRAINING_DIR = os.path.join(base_dir, 'training')train_datagen = ImageDataGenerator(rescale = 1.0/255)train_generator = train_datagen.flow_from_directory(TRAINING_DIR, batch_size=20, class_mode='binary', target_size=(150, 150))
ImageDataGenerator 有助于规范化像素值,使其介于 0 和 1 之间。您可能已经知道,最初的值可以是 0 到 255。然后我们批量传递我们的数据进行训练。在这里,我们提供的批量大小为 20。我们需要以同样的方式将测试数据标准化:
ALIDATION_DIR =os.path.join(base_dir, 'testing')validation_datagen = ImageDataGenerator(rescale = 1.0/255)validation_generator = validation_datagen.flow_from_directory(VALIDATION_DIR, batch_size=20, class_mode='binary', target_size=(150, 150))
现在训练模型。让我们用 15 个纪元来训练它。请随意测试更多或更少的纪元。你应该跟踪 4 个参数。损失、准确性、验证损失和验证准确性。随着每个时代的到来,损耗应该下降,精度应该上升。
history = model.fit_generator(train_generator, epochs=15, verbose=1, validation_data=validation_generator)
我在训练集上获得了 89.51%的准确率,在验证数据上获得了 91.76%的准确率。这里不得不提一件事。也就是说,如果训练集的精度非常高,而测试集或验证集的精度不是很好,这就是过拟合问题。这意味着模型很好地学习了训练数据集,它只知道训练数据很好,它对其他看不见的数据不好。但这不是我们的目标。我们的目标是开发一个对大部分数据集都有好处的模型。当您看到过度拟合时,您需要修改训练参数。大概是纪元数少,学习率不同。我们将在后面的文章中讨论如何处理过度拟合。
数据科学的简单介绍
数据科学基础
数据科学项目生命周期中的步骤

我们正在见证数据科学在我们周围的蓬勃发展。这已经成为新的技术行话,现在就像一个时髦词一样流传开来。在这篇文章中,我们将通过讲述以下内容来了解数据科学实际需要什么:
数据科学项目生命周期的步骤是什么?
因为从实用的角度来看,这是理解数据科学所有方面的最佳方式。
数据科学项目的生命周期
数据科学项目可以分为 7 个步骤:
1.理解业务问题

照片由达里娅·内布里亚希娜在 Unsplash 拍摄
这是任何数据科学项目开始的第一步,也是最重要的一步。理解你构建项目所基于的业务问题是非常重要的。这一步的任何模糊/混乱都可能让你在后期付出很大代价。这是任何想在数据科学领域取得成功的人最重要的特质之一。如果你正在为一个客户工作,一定要在这个初始阶段问尽可能多的问题。在你开始查看数据之前,你的头脑中应该对业务框架有一个绝对清晰的认识。
例如:如果您正在研究一个业务问题,该问题要求您建立一个预测模型来预测信用卡发行银行的哪些客户最容易流失。您可能想问的问题如下:
- 你如何定义自然减员?—这将有助于您了解业务利益相关者的前景。
- 总括损耗术语涵盖不同类型的行为。例如,在一种情况下,客户自愿关闭账户,而在另一种情况下,账户会休眠很长时间。—当您开始处理数据时,必须澄清每一个问题,以便能够成功地捕捉损耗。
- 模型的准确性更重要,是以牺牲模型的可读性为代价,还是必须优先考虑模型的可读性?—这将有助于回答模型方法——统计模型或 ML 模型。
- 谁将是这一模式的最终用户?这个模型是其他模型的支线模型还是独立模型?—这将有助于设计模型的输入输出结构。
你在这里得到了这个想法。还有问题吗?去问他们吧。这些信息构成了建模的基础。
2.数据采集

弗兰基·查马基在 Unsplash 上拍摄的照片
理解业务问题后的下一步是寻找数据源,从那里可以收集所有行为、性能、地理和各种描述业务问题的数据。最好你应该从稳定可靠的来源获取数据。
例如:如果您想将银行信用卡余额转账服务的客户群作为目标,您将需要大量的属性来确定客户的特征。你可以使用信用局的数据(交易,查询,拖欠等)。)、内部历史数据(过去报价接受率、月末未清余额、内部信用评分等。).简而言之,在统计上被确定为在区分特定类型的报价的好和坏账户时具有预测性的一组特征。
3.数据准备
一旦收集了数据,就进入数据准备阶段。数据准备通常也称为“预处理”。这是为数据科学项目的后续阶段清理和组织原始数据的阶段。在准备过程中,会认真检查原始数据是否有错误。此步骤的目的是消除不良数据(冗余、不完整或不正确的数据),并开始创建高质量的数据以获得最佳商业智能。
例如:您从第 2 阶段中讨论的各种来源获取数据,但是在我们准备数据的预处理阶段,现在我们意识到某个特定的数据源没有在级别(比如说帐户 ID 级别)上正确连接,并导致错误的属性列。我们可以在这个阶段删除数据源。同样,冗余、不完整或不正确在这个阶段都以同样的方式处理。
4.探索性数据分析
探索性数据分析(EDA)是一种分析数据集以总结其主要特征的方法,通常采用可视化方法。EDA 用于在建模任务之前可视化数据可以向我们展示的内容。查看一列数字或整个电子表格并确定数据的重要特征并不容易。通过查看表格形式的数据,似乎很难获得任何深刻的见解。探索性数据分析技术包括单变量分析 {(箱线图、直方图等。)查看数据中单个变量的基本趋势、最大值、最小值、四分位间距、异常值等。} 和双变量分析 {(散点图、条形图、折线图等。)来看看因变量-自变量的关系和趋势}
EDA 是在进入机器学习或统计建模阶段之前要执行的关键步骤。它为理解提供了一个重要的基础框架,并提供了为手头的问题开发合适的模型并正确解释其结果所需的背景。EDA 对于确保产生的结果是有效的、正确解释的,并且适用于期望的业务环境是有价值的。
5.预测建模
预测建模是预测未来行为的常用统计技术。预测建模解决方案是一种数据挖掘技术,通过分析历史和当前数据并生成模型来帮助预测未来结果。
有各种各样的预测建模技术,如回归、分类、聚类等。
这一步是最关键的一步。在开发预测模型时,确保在构建模型后对其进行评估,并开发 3-4 个挑战者模型,以便从中选择最佳模型。如果它是一个 ML 模型,你完全基于准确性来判断,因为大多数 ML 模型起着黑箱的作用。另一方面,如果它是一个统计模型,好好看看你在模型中使用的最终变量,并检查它们的业务相关性以及模型评估指标的结果。
6.可视化和交流

一旦模型准备好了,有效地传达它的结果是非常重要的。确保准备适当的文件,描述开发、验证和过时样本的模型结果,这些结果可以清楚地显示基尼系数/知识系数或其他评估指标。此外,传达结果还应包括清楚地描述构建模型时使用的假设。此外,敏感性分析是一种重要的可视化工具,可以描述模型的稳健性。你在这里得到的想法。明智地选择如何有效地沟通和展示你所开发的模型的准确性和作用。
7.部署和维护
现在,一旦模型被开发人员和业务涉众批准。它必须投入生产。一旦模型进入生产阶段,工作就不会结束。必须以适当的频率间隔连续监控模型。PSI(人口稳定性指数)和 CSI(特征稳定性指数)是一个很好的衡量人口分布如何符合开发样本的方法。如果差异显著,那么模型的结果可能变得不可靠,或者需要进一步深入研究。此外,应该监控模型预测的所有重要 KPI,如果在模型运行的两个月/两个时间段之间百分比变化变高,则可能需要重新校准或重新开发模型。
这些是数据科学项目的不同阶段。有几个数据科学团队专门从事我们上面讨论的某些阶段,而在 Kaggle 竞赛或许多公司中,您可能负责数据科学项目的端到端开发。无论哪种方式,所有阶段对于开发一个健壮可靠的模型都很重要,它可以帮助我们解决手头的业务问题。
每个阶段都包括许多进一步的技术子步骤,这些子步骤组合在一起构成一个阶段。但这篇文章是我试图解释一个没有任何技术术语描述的数据科学项目的整体观点。
观看此空间,了解更多关于数据科学、机器学习和统计的信息!
快乐学习:)
设置神经网络学习速率的简单直觉
学习率可能是训练神经网络要调整的最重要的超参数。

为训练神经网络的不同阶段设置良好的学习速率对于收敛以及减少训练时间是至关重要的。(图片来源)
学习率可能是训练神经网络要调整的最重要的超参数。
本文的目的是直观地了解调整学习率(LR)的各种最佳实践。
首先,我假设对 LR 和人工神经网络(NN)有一个大致的了解。详情请参考此处。简而言之,LR 是网络响应丢失而更新其参数的速率。在元水平上,LR 代表当面对失败时信念被修正的程度。
为了简单起见,我会考虑尝试学习两个简单的函数 f(x) -> x 和 f(x)-> 2x+5。因此,在第一种情况下,给定像 1,2,3 这样的数字,神经网络需要学会将这些数字返回。对于第二种情况,它需要学习一个线性函数。
对于第一种情况,忽略使用具有一个节点(输入)的网络的明显解决方案,我们考虑具有两个节点的 NN:一个输入和一个输出。因为我们知道它必须学习的函数,即 f(x) = 1*x + 0。我们不设置偏差参数。因此,只有一个参数需要调整,即权重,在本例中是一个标量。
*model = keras.models.Sequential([
keras.layers.Input(1),
keras.layers.Dense(1, use_bias=False)
])* model.summary()
Model: "sequential_28"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_33 (Dense) (None, 1) 1
=================================================================
Total params: 1
Trainable params: 1
Non-trainable params: 0
_________________________________________________________________
现在,让我们看看 keras 设置的随机权重。默认情况下,它使用 Xavier 初始化,但出于这个目的,我们可以认为这是一个小的随机浮点。
model.layers[0].get_weights()
[array([[1.3835369]], dtype=float32)]
太好了,NN 需要做的就是学会把 1.38…改成 1 就搞定了。大约 80 个训练例子应该足以学习这个参数。我们去看看。
我们首先使用 LR 为 0.1 的随机梯度下降优化器。
model = keras.models.Sequential([
keras.layers.Input(1),
keras.layers.Dense(1, use_bias=False)
])#saving the single weight in a list using callback for plotting
all_weights = []
save_weights = LambdaCallback(on_epoch_end=lambda batch, logs: all_weights.append(model.layers[0].get_weights()[0][0][0]))model.compile(loss='mae', optimizer=keras.optimizers.SGD(**0.1**), metrics=['mae'])
history = model.fit(X[:80], X[:80], epochs=100, validation_data=(X[80:], X[80:]), callbacks=[save_weights])Epoch 1/100
3/3 [==============================] - 0s 25ms/step - loss: 68.6347 - mae: 73.1572 - val_loss: 220.5727 - val_mae: 220.5727
...
Epoch 100/100
3/3 [==============================] - 0s 9ms/step - loss: 80.8392 - mae: 84.1430 - val_loss: 58.0744 - val_mae: 58.0744
经过大约 100 个时期的训练后,平均误差似乎降低了,但幅度不大。发生了什么事?

MAE 在整个时代都在波动,没有学到任何有用的东西。

我们期望权重 W 收敛到 1。它好像在做随机漫步。
W 图的尖峰告诉我,当神经网络预测的值过高时,它会过多地调整权重,从而导致它在另一个方向上调整过多。它从未能以“恰到好处”的方式调整它。现在,我将尝试通过将 LR 设置为 0.001 来重复这个实验。
model.compile(loss='mae', optimizer=keras.optimizers.SGD(0.001), metrics=['mae'])
history = model.fit(X[:80], X[:80], epochs=100, validation_data=(X[80:], X[80:]), callbacks=[save_weights])
...
Epoch 1/100
3/3 [==============================] - 0s 25ms/step - loss: 51.1354 - mae: 51.7827 - val_loss: 109.6049 - val_mae: 109.6049
Epoch 100/100
3/3 [==============================] - 0s 11ms/step - loss: 1.1278 - mae: 1.0618 - val_loss: 1.5589 - val_mae: 1.5589

好多了!MAE 下降非常快,但随后开始波动。

相反,权重开始收敛到 1,但永远不会完全达到 1。
似乎 LR 越低越好。让我再试一次。LR= 0.0001

设置较低的 LR 意味着学习非常慢。请注意比例的差异,W 接近 1,但需要近 200 个历元。但一旦开始,它会保持很紧。
因此,在开始时有较大的学习速率似乎有助于快速接近一个好的解决方案,而有较小的学习速率似乎有助于接近理想的解决方案。
衰退
学习率衰减的想法很简单,在每次迭代结束时,假设我们正在缓慢收敛,我们希望将学习率修改为更小的值。大多数优化器定义允许在每次迭代(小批量)后更新 LR 的单个衰减参数。优化器中指定的 LR 是 initial_lrate。
# decay works by:
# lrate = initial_lrate / (1 + decay * iteration)
model.compile(loss='mae', optimizer=keras.optimizers.SGD**(0.01, decay=0.01)**, metrics=['mae'])
history = model.fit(X[:80], X[:80], epochs=250, validation_data=(X[80:], X[80:]), callbacks=[save_weights])

好多了。然而,它似乎从来没有完全稳定下来,需要很长时间。
学习费率表
为了增加灵活性,我们可以指定回调,而不是使用优化器的衰减参数。在 Keras 中,回调是一个可定制的函数,在每个时期结束时调用。
在这里,我定义了一个函数来处理简单依赖于纪元编号的衰减。函数 lr_schedule 当然是可定制的。
def lr_schedule(epoch):
if epoch<5:
return 0.02
elif 5>=epoch>25:
return 0.01
elif 25>=epoch>50:
return 0.001
else:
return 0.0001
lrate = LearningRateScheduler(lr_schedule)
model.compile(loss='mae', optimizer=keras.optimizers.SGD(), metrics=['mae'])
history = model.fit(X[:80], X[:80], epochs=100, validation_data=(X[80:], X[80:]), callbacks=[save_weights, lrate])

在这种情况下,我们看到我们在开始时有一点波动,但在纪元 40 之前已经收敛了很多。我发现这也有助于开始小 LR 上升到最大,然后开始按比例缩小,直到它达到最小。这叫 LR 循环。对迁移学习特别有帮助。
适应性学习率
在上面这个非常简单的例子中,我从一个可怕的 LR 值开始,然后慢慢地调整这个过程。为 LR 设置的时间表取决于任务的复杂性、训练数据的大小、小批量大小、训练数据的质量等等。
像 RMSProp 、 Adagrad 和 Adam 这样的常用优化器使用像动量和前瞻这样的梯度特征来自动调整 LR。

对于这个简单的问题,Adam 似乎在没有任何超参数调整的情况下在 100 个时期内稳定。Adam 可以理解为有动量的 RMSprop 和 SGD 的组合。已经有了更新的提议,像那达慕,是对亚当的增强。
使用 Adam 这样的自适应优化器通常是一个不错的选择。然而,已经表明,有时 Adam 并不总是收敛到与带动量的 SGD 一样的最优解。因此,在最终确定解决方案之前,针对几个不同的超参数尝试 SGD 是一个很好的实践。增加了一点复杂性
当我通过要求神经网络学习 f(x) -> 2*x+5 并允许使用一个偏差变量来增加原始问题的复杂性时。
X = np.arange(100)
y = 2*X+5
X_train_full, X_test, y_train_full, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
X_train, X_valid, y_train, y_valid = train_test_split(X_train_full, y_train_full, test_size=0.2, random_state=42)model = keras.models.Sequential([
keras.layers.Input(1),
keras.layers.Dense(1)
])#all_weights = []
#save_weights = LambdaCallback(on_epoch_end=lambda batch, logs: all_weights.append(model.layers[0].get_weights()[0][0][0]))
model.compile(loss='mae', optimizer=keras.optimizers.Adam(), metrics=['mae'])
history = model.fit(X_train, y_train, epochs=200, validation_data=(X_valid, y_valid), callbacks=[lrate])

Adam 的默认设置没有在 200 个时期内收敛到一个解决方案。然而,它正在稳步取得进展。

给定更多的训练示例(1000),它似乎进展得更好,学习 a W = 2.004 和 b=1.94。它收敛到正确的权重,但未能收敛到好的偏移值。

在这种情况下,使用带有动量的 SGD 似乎做得更好。它在 200 个时代结束时学习的参数是 W=2.071 和 b= 0.23。

SGD 解决方案看起来并没有因为更多的例子而变得更好。它学习了 W=2.05 和 b=0.34。

W 稳定得相当快,但是偏置更新得很慢。(亚当)
在这篇简短的文章中,我们看到设置好的 LR 对于确保神经网络收敛以及优化收敛速度非常重要。我们还看到使用替代优化器,如 Adam、RMSProp、Nadam 等。帮助调整学习速度。最后,我们还看到了如何使用自定义函数来设置学习率衰减的时间表,以及 LR 循环如何有所帮助。
但是,为什么一个神经网络需要 1000 个样本和 100 次数据传递来学习一个简单的恒等函数,而这个函数对于只有几个样本的人来说是显而易见的?现在,这是另一个职位!
R 中的简单迭代编程和错误处理
有时候你有很多事情要做,你不需要因为错误而停下来
作为一名程序员,你会发现自己处于一些常见的情况。其中一种情况是,您需要在一个或多个循环的多次迭代中运行代码,并且您知道您的代码可能会在至少一次迭代中失败。您不希望您的代码完全停止,但是您确实希望知道它失败了,并记录它发生的位置。我将在这里展示一个简单的例子来说明如何做到这一点。
这是我为电视节目老友记构建互动角色网络可视化旅程的第二部分。第一步的教程——从网上抓取单集剧本——可以在这里找到。整个项目的最终产品可以在这里看到,所有代码在这里。
在我们停下来的地方,我们已经写了一个脚本,可以抓取 Friends 的每个在线集,找到并计算不同的场景,并列出每个场景中的角色。我们的抓取脚本输出了这样一个表:

我们现在要做的是创建一个网络边缘列表,以便我们可以分析和可视化该剧的角色网络。网络边列表是带有“从”和“到”列的简单的字符配对,其中如果字符在至少一个场景中一起出现,则它们是配对的。我们还将增加一个“权重”栏,统计这对情侣一起出现的场景数量——这是一种衡量联系“强度”的方法。我们希望每一季都这样做,我们不在乎我们网络中的方向——所以对我们来说,这对组合{“钱德勒”、“莫妮卡”}就是对组合{“莫妮卡”、“钱德勒”}。因此,总结我们的目标,我们希望:
- 让我们的抓取功能贯穿每一季每一集
- 将输出转换为每个场景的字符“对”
- 统计每一季剧中的角色对,形成一个“权重”。
在所有季节和剧集中运行我们的抓取功能
《老友记》一共播出了十季,每一季都有不同的集数,但从未超过 25 集——也有双集,这意味着一些集数在剧本名称中被跳过了。我不想编写精确定义多年来所有季节和剧集组合的条件代码。我更愿意做的是让我的抓取脚本抛出一个错误,返回一个空数据框,在我的控制台中将错误记录为一条消息,然后继续下一次迭代。然后,我可以查看记录的消息,并检查错误是否在意料之中,因为剧集并不存在。
因此,我将在这里做一些错误处理——我将使用tryCatch()函数来做这件事。tryCatch()接受一个命令,如果可以就执行它,然后接受特定的指令作为出错时的回调函数。在我的例子中,我将像这样使用tryCatch():
library(dplyr)# function developed in previous tutorial
source('edgelist_creation/scrape_friends.R')
season <- 1 # enter season no
episode <- 1 # enter episode number
scrape <- tryCatch(
scrape_friends(season, episode),
error = function(e) {
message(paste("Scrape failed for Episode", episode, "Season", season))
data.frame(from = character(), to = character(), stringsAsFactors = FALSE)
}
)
使用此代码,如果特定的季节和剧集组合不存在,代码将不会停止,而是会在控制台中显示特定的消息并返回一个空数据帧。这使得我们可以迭代每一季和每一集,而不用担心我们的代码会因为一个错误而停止。
将输出转换成字符对
因此,由于我们出色的tryCatch()解决方案,我们现在可以创建一个for循环的开始,该循环将迭代 10 季,每季 25 集,如下所示。请注意我在这里的评论,并特别注意我们接下来需要处理的 CAPS 部分:
for (season in 1:10) {
# start with empty dataframe
season_results <- data.frame(from = character(), to = character(), stringsAsFactors = FALSE)
# no season has more than 25 episodes, loop through them all
for (episode in 1:25) {
# keep track of where we are
message(paste("Scraping Season", season, "Episode", episode))
# run scraping function, pass empty df if scrape fails
scrape <- tryCatch(
scrape_friends(season, episode),
error = function(e) {
message(paste("Scrape failed for Episode", episode, "Season", season))
data.frame(from = character(), to = character(), stringsAsFactors = FALSE)
}
)
result <- data.frame(from = character(), to = character(), stringsAsFactors = FALSE)
if (nrow(scrape) > 0) {
# DO SOMETHING TO CREATE CHARACTER PAIRS HERE
}
# add episode output to season results
season_results <- season_results %>%
dplyr::bind_rows(result)
}
# add season results to overall results
raw_results <- season_results %>%
dplyr::mutate(season = season) %>%
dplyr::bind_rows(raw_results)
}
这就把我们带到了如何将一集的输出转换成每个场景的一组独特的字符对的问题上。回想一下,我们的抓取脚本的输出包含一组场景编号和每个场景的角色列表。
在一个场景中,我们需要将这个字符列表转换成一组唯一的无序对。让我们编写一个简单的函数,将一个字符向量转换成一组唯一的无序元素对。为此,我们需要遍历每个元素,直到倒数第二个元素,并与它后面的每个元素配对——例如,为了对向量("A", "B", "C", "D")进行这样的操作,我们会将"A"与"B"、"C"和"D"配对,将"B"与"C"和"D"配对,最后将"C"与"D"配对。
unique_pairs <- function(char_vector = NULL) {
vector <- as.character(unique(char_vector))
df <- data.frame(from = character(), to = character(), stringsAsFactors = FALSE)
if (length(vector) > 1) {
for (i in 1:(length(vector) - 1)) {
from <- rep(vector[i], length(vector) - i) # each element up to second last
to <- vector[(i + 1): length(vector)] # each element that follows it
df <- df %>%
dplyr::bind_rows(
data.frame(from = from, to = to, stringsAsFactors = FALSE)
)
}
}
df
}
让我们测试一下我们的函数,看看它是否有效:
> test <- c("A", "B", "C", "D")
> unique_pairs(test)
from to
1 A B
2 A C
3 A D
4 B C
5 B D
6 C D
看起来不错!现在我们只需要将它应用到这一集的每一个场景,所以这是我们可以替换到循环中的最终代码,而不是上面的 CAPS 注释。它遍历每个场景,将我们新的unique_pairs()函数应用于角色列表,然后将结果附加到一个数据帧中,该数据帧捕获该集的所有配对。
for (i in 1:max(scrape$scene)) {
result_new <- scrape %>%
dplyr::filter(scene == i) %>%
dplyr::pull(character) %>%
unique_pairs()
result <- result %>%
dplyr::bind_rows(result_new)
}
现在我们可以在所有的季节和剧集中运行整个循环。你可以在这里找到这个循环的完整代码。如果我们运行它,我们将看到被捕获的错误—例如,我们将看到:
Scraping Season 10 Episode 17
Scraping Season 10 Episode 18
Scrape failed for Episode 18 Season 10
Scraping Season 10 Episode 19
Scrape failed for Episode 19 Season 10
Scraping Season 10 Episode 20
Scrape failed for Episode 20 Season 10
Scraping Season 10 Episode 21
Scrape failed for Episode 21 Season 10
Scraping Season 10 Episode 22
Scrape failed for Episode 22 Season 10
Scraping Season 10 Episode 23
Scrape failed for Episode 23 Season 10
Scraping Season 10 Episode 24
Scrape failed for Episode 24 Season 10
Scraping Season 10 Episode 25
Scrape failed for Episode 25 Season 10
这是有道理的,因为第十季最后一集是第十七集(双集大结局)。
计算每对场景的数量
现在我们差不多到家了。我们需要计算每一季中一对角色一起出现在一个场景中的次数,以创建我们的“权重”栏。我们需要克服的唯一问题是字符的顺序在我们的raw_results数据帧中可能不一样。我们的迭代可能在一个场景中捕捉到了from = "Monica"、to = "Chandler",但在另一个场景中则相反。
对此的最佳解决方案是使用以下命令按字母顺序对每行中的对进行排序:
# order pairs alphabetically to deal with different orderings
for (i in 1: nrow(raw_results)) {
raw_results[i, c("from", "to")] <- sort(raw_results[i, c("from", "to")])
}
现在我们准备按季节生成我们的“体重”列,这现在相当简单:
# add up scenes to form season weights
edges <- raw_results %>%
dplyr::count(season, from, to, name = "weight")
我们可以快速浏览一下我们的edges数据框架的样本。正如您所料,它有成千上万行,但我们预计六个主要字符之间的权重相当高:
friends <- c("Phoebe", "Monica", "Rachel", "Joey", "Ross", "Chandler")
edges %>%
dplyr::filter(season == 1,
from %in% friends,
to %in% friends)
这将返回:

好了,我们已经有了边缘列表,现在我们准备继续这个项目的网络分析部分,在这里我们将查看六个主要角色的社区,并想象它们如何随着季节的变化而变化。在接下来的文章中,请留意这一点。
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在LinkedIn或Twitter上找我。也可以看看我在 drkeithmcnulty.com 的上的博客。

来自《老友记》,由 NBC 提供
简单线性回归
关于简单线性回归你需要知道的一切

格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片
当我们着手理解机器学习模型时,我们通常首先遇到的事情之一是简单的线性回归。这是进入机器学习的第一步,这篇文章将帮助你了解你需要知道的一切。让我们从了解什么是回归开始。
什么是回归?
回归一词最早出现在 19 世纪,用来描述一种现象,即高个子祖先的后代的身高倾向于向正常平均身高回归。换句话说,回归就是回归中庸(中庸)的趋势。有趣吧?
在统计学中,该术语被定义为输出变量和输入变量之间关系的量度。因此,线性回归假设前者和后者之间存在线性关系。根据输入变量的数量,线性回归可以分为两类:
- 简单线性回归(单一输入变量)
- 多元线性回归(多输入变量)
这篇文章的目的
这篇文章致力于解释简单线性回归的概念,这也将为你理解多元线性回归打下基础。除此之外,我们将在 Python 中实现线性回归,以了解它在机器学习中的应用。与此同时,我们还将了解一些重要的事实。说到这里,让我们开始吧。
数学上…
我们将输入变量表示为 X,输出变量表示为 Y,这是通常的做法。然后我们可以把 X 和 Y 之间的关系写成:

这里,两个常数项(β)是截距和斜率。你可能在你的学校代数中见过这个表达式,直线的一般表达式是,
y = c + mx
其中 c 是截距,m 是斜率。这就是我们在线性回归中要做的。我们试图拟合一条直线来观察输入和输出变量之间的关系,然后进一步用它来预测看不见的输入的输出。
让我们引入数据来理解这是如何工作的。
可视化数据
我们将使用南加州大学马歇尔商学院网站上的广告数据。你可以在这里下载。
这些数据被用在一本很受欢迎的书“统计学习入门”中,顺便说一下,如果你想了解机器学习的基本统计,这是必读的。
广告数据集包括一种产品在 200 个不同市场的销售额,以及三种不同媒体的广告预算:电视、广播和报纸。它看起来是这样的:

销售额(1000 台)与广告预算(1000 美元)
数据的第一行表示电视、广播和报纸的广告预算分别为 230.1k 美元、37.8k 美元和 69.2k 美元,相应的售出数量为 22.1k(或 22,100)。
现在,我们将尝试使用简单的线性回归来了解这三种媒体中的每一种是如何与销售相关联的。因此,我们的输入变量(X)将是广告代理商之一,输出变量将是销售额(Y)。
在下结论之前理解你的数据是很重要的。一个人必须注意测量单位和变量的规模,以讲述正确的故事。
绘制输入与输出
现在让我们观察一下我们的销售额与每个广告代理商的对比情况。
import pandas as pd#give the path of your directory containing the csv file as parameter to read_csv.data = pd.read_csv(.../advertising.csv)
加载 csv 文件后,运行以下代码来绘制变量。
import matplotlib.pyplot as plt
%matplotlib inlineplt.figure(figsize=(14,3))plt.subplot(1,3,1)
plt.scatter(data['TV'], data['sales'], 'blue')
plt.xlabel('TV')
plt.ylabel('sales')plt.subplot(1,3,2)
plt.scatter(data['radio'], data['sales'], color = 'red')
plt.xlabel('radio')
plt.ylabel('sales')plt.subplot(1,3,3)
plt.scatter(data['newspaper'], data['sales'], color = 'green')
plt.xlabel('newspaper')
plt.ylabel('sales')plt.show
上述代码将产生以下散点图。

销售额(1000 台)与广告预算(1000 美元)
通过观察第一幅图(左),人们可以推断出随着电视广告的增加,销售额有急剧上升的趋势。在描述广播广告的第二个图表(中间)中也可以观察到类似的趋势。然而,在最后一张图(右)中,趋势并不明显。这是什么意思?
相互关系
当观察到输入变量 X 的增加与输出变量 Y 的同时增加或减少时,这两者之间就有了关联。这是对 X 和 Y 之间关系的一种度量。通过可视化的数据,我们可以直观地看到电视和销售是强相关(高度相关)的。另一方面,报纸预算和销售之间的相关性似乎较弱。
相关性经常会误导人,因为它看起来像因果关系。仅仅因为两个变量相关,并不意味着一个变量会引起另一个变量的变化。我们需要深入挖掘,决定这是否只是一个相关的例子,或者是否也是因果关系。
线性回归将帮助我们确定这种关系的强度,即在给定特定广告媒体的情况下,我们预测销售额的准确度有多高。
建立简单线性回归模型
现在我们已经了解了数据,让我们建立一个简单的模型来了解销售和广告代理之间的趋势。在这篇文章中,我将使用电视作为代理来构建以下回归模型。我鼓励你为另外两个代理(广播和报纸)做这件事。
→ 𝑆𝑎𝑙𝑒𝑠 = 𝛽0 + 𝛽1 * 𝑇𝑉
这个回归模型将通过调整𝛽0 和𝛽1.这两个常数,找到能够代表数据的最佳直线最佳拟合是在给定输入值的情况下预测输出时显示最小量的误差的拟合。
稍后,我们将了解更多关于误差函数和模型评估的内容。在此之前,让我们编码并构建上述模型。
**#** **Importing required libraries**
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_splitfrom sklearn.linear_model import LinearRegression**# Defining X and Y**
X = data['TV'].values.reshape(-1,1)
Y = data['sales'].values.reshape(-1,1)**# Splitting the data into Train & Test** X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=1)**# Fitting the model on Train dataset** Model = LinearRegression(fit_intercept=True)
Model = Model.fit(X_train, y_train)**# Predicting and storing results for Test dataset** train_fit = Model.predict(X_train)
test_pred = Model.predict(X_test)
回归模型通过调整𝛽0 和𝛽1 这两个常数来寻找能够代表数据的最佳直线,从而以最佳方式代表数据。
请注意,我们已经将数据分成了两个子集:训练数据集和测试数据集。这是机器学习中的常见做法。这使我们能够在可见和不可见的数据上检查模型的性能。
你可以在这里找到完整的代码。现在,让我们在训练和测试数据集上绘制和可视化我们的模型。
plt.figure(figsize=(12,4))**# Plotting Regression line on Train Dataset**
plt.subplot(1,2,1)
plt.scatter(X_train, y_train, color='gray')
plt.plot(X_train, train_fit, color='blue', linewidth=2)
plt.xlabel('TV')
plt.ylabel('sales')
plt.title("Train Dataset")**# Plotting Regression line on Test Dataset**
plt.subplot(1,2,2)
plt.scatter(X_test, y_test, color='gray')
plt.plot(X_test, test_pred, color='blue', linewidth=2)
plt.xlabel('TV')
plt.ylabel('sales')
plt.title("Test Dataset")plt.show()

太好了!通过调整常数,我们的回归方程拟合出了最佳模型。正如我们所看到的,它在训练和测试数据中做了很好的直线处理。让我们检查截距和 x 系数(斜率)的值。
print("Intercept is ", Model_1.intercept_[0])
print("Coefficient is ", Model_1.coef_[0][0])
您应该会得到这些输出,其中可能有非常细微的变化:
Intercept is 7.032593549127693
Coefficient is 0.047536640433019764
截距是输入为 0 时输出的值。在这种情况下,它是在没有电视广告预算的情况下的估计销售额。这里截距的值是 7.033,也就是说在没有电视广告的情况下,售出的单位数是 7033(销售额*1000 单位)。
需要注意的是,截距并不总是与问题相关,可能只是作为调整回归线所需的常数。
系数或斜率是每单位输入变量变化时输出变量变化的量度。在这里,模型的系数是 0.048,这意味着如果我们增加 1 个单位(1000 美元)的电视广告预算,产品的销量将增加约 48 个单位(0.048*1000)。
试着找出广播和报纸的这些值。你认为哪种广告媒体对销售影响最大?
注意,这里的系数值是正的。然而,系数的负值意味着负相关,这意味着输出随着输入值的增加而减少。在我们的数据中,我们只在所有情况下观察到了一个正相关,即无论何时任何媒体的广告预算增加,销售额都会增加(这对任何企业都有意义)。
厉害!我们刚刚建立了简单的线性回归模型。但是我们如何知道在给定电视广告预算的情况下,它是否足以预测销售额呢?我们应该依靠模型做出正确的商业决策吗?如果是,那么涉及哪些损失?在真实的商业问题中回答这些问题很重要。为此,我们需要评估我们的模型,并测量在预测输出时产生了多少 误差 。
误差函数
误差函数可以被认为是当前状态和理想状态之间的距离。
例如,如果你必须从一个山峰下降,那么误差函数就是山峰的高度,并且你在减小误差(高度)的同时保持小幅度下降,直到你到达底部,即零误差状态。
类似地,模型从初始状态开始,在该初始状态下,它假设所涉及的参数的某个值,从而调整这些参数以减少误差函数。
在这种情况下,截距和广告系数是要调整的参数,而误差函数是实际销售额和预测销售额之间的总体差异。

垂直线表示模型预测中的单个误差
位于直线上或非常接近直线的点是模型能够正确预测的点。然而,有许多点远离回归线。每个这样的点离直线的距离就是误差的原因。
因此,第 i 个值的误差函数 e 可定义如下:

该误差项也被称为残差,根据模型是否高估或低估结果,该误差项可以是负数或正数。因此,为了计算净误差,将所有残差直接相加会导致项的消除和净效应的减小。为了避免这种情况,我们取这些误差项的平方和,称为 残差平方和(RSS)。

残差平方和
截距和斜率在线性回归中通过使用微积分最小化 RSS(残差平方和)来计算。令人欣慰的是,算法会处理这部分,我们不必担心它背后的数学问题。
RSS 可能是一个太大的数字,无法表示误差函数。因此,我们考虑以下措施来评估线性回归中的误差。
- 均方误差(MSE): 它是残差平方的平均值( e ),通过将 RSS 除以数据值的个数来计算。MSE = RSS/n

均方误差
2.均方根误差(RMSE): 顾名思义,就是均方误差的平方根,更适用于误差特别大的情况。

均方根误差
3。平均绝对误差(MAE): 我们取残差的绝对值并计算它们的平均值,而不是取平方。

绝对平均误差
我们不必担心计算这些值,因为它可以使用 Python 中预定义的函数来完成。让我们用测试数据集来检查我们的模型的这些值。
print('Mean Squared Error:', metrics.mean_squared_error(y_test, y_pred)) print('Root Mean Squared Error:', np.sqrt(metrics.mean_squared_error(y_test, y_pred)))print('Mean Absolute Error:', metrics.mean_absolute_error(y_test, y_pred))
您应该会看到下面的输出,如果有细微的变化的话:
Mean Squared Error: 10.186181934530222
Root Mean Squared Error: 3.191579849311344
Mean Absolute Error: 2.505418178966003
您可以将这些结果与您的训练集错误进行比较。你得到了相似的误差值还是与测试误差不同?
既然您有了测量误差的方法,您就可以决定接受该模型时允许的误差有多大。这取决于你正在解决的问题和你因错误预测而面临的损失惩罚。
关于线性回归的更多信息
如您所见,线性回归是一种非常简单的建模方法,如果数据过于分散,它会产生很高的误差。这是一个不灵活的模型,只假设变量之间的线性或直线关系。因此,它不适合大多数数据点,这使得它容易受到高 偏差 。这导致了过度泛化和 欠拟合 。当模型主要由于其不灵活而没有恰当地捕捉训练数据的本质时,就会发生这种情况。
尽管线性回归是一个非常简单的模型,但它确实有助于理解其他高级模型的工作方式。我们看到了当只有一个预测因子时简单的线性回归是如何工作的。你可以在这里找到这篇文章的完整代码。
您还可以阅读多元线性回归,它是简单线性回归的扩展,用于有多个输入变量的情况。感谢阅读,敬请关注。
一个完整的研究—模型解释→假设检验→特征选择
towardsdatascience.com](/multiple-linear-regression-8cf3bee21d8b)
如果你是数据科学和机器学习的新手,不知道从哪里开始你的旅程,请查看下面的链接,在那里我提到了学习数据科学的一步一步的方法,有很多资源可供你选择。
作为一个完全的初学者如何步入数据科学
towardsdatascience.com](/data-science-from-scratch-4343d63c1c66)
等不及了?如果你想一头扎进一门课程,请点击下面的链接查看适合你的数据科学职业轨迹。
使用 DataCamp 的视频教程&编码,按照您自己的步调,在您的浏览器中舒适地学习数据科学
www.datacamp.com](https://www.datacamp.com?tap_a=5644-dce66f&tap_s=910084-843f05&utm_medium=affiliate&utm_source=sangeetaggarwal)
(简单)线性回归和 OLS:理论介绍
简单线性回归和 OLS 估计的核心概念介绍
背景
回归分析是分析数据的重要统计方法。通过应用回归分析,我们能够检查因变量和一个或多个自变量之间的关系。在本文中,我将介绍最常见的回归分析形式,即线性回归。顾名思义,这种类型的回归是一种线性方法,用于建模感兴趣的变量之间的关系。
方法
线性回归用于研究一个因变量 (y)与一个或多个自变量 ( X )之间的线性关系。因变量和自变量之间的线性关系是模型的一个假设。该关系通过随机干扰项(或误差变量)ε建模。扰动是最重要的,因为我们无法捕捉到模型因变量的每一个可能的影响因素。为了捕捉影响因变量的所有其他因素(未作为自变量包括在内),将扰动项添加到线性回归模型中。
这样,线性回归模型采用以下形式:

在哪里

是模型的回归系数(我们要估计的!),K 是包含的自变量个数。该方程被称为回归方程。
简单线性回归
现在让我们后退一步。我们开始考虑只包含一个自变量的简单线性回归,而不是包含多个自变量。这里,我们开始用一个自变量 xi 对因变量 yi 建模:

其中下标 I 指的是特定的观察值(总共有 n 个数据点)。这里,β0 和β1 是需要从数据中估计的系数(或参数)。β0 是截距(常数项),β1 是梯度。
在简单线性回归中,我们实际上是使用自变量 xi 的得分来预测因变量 yi 的值,以观察 I
模型假设
为了能够获得可靠的系数估计值,并能够解释随机数据样本的结果,我们需要做出模型假设。有五个与线性回归模型相关的假设(这些被称为高斯-马尔可夫假设):
- 线性:因变量、自变量和扰动之间的关系是线性的。
- 随机样本:我们有一个大小为 n {(xi,易):i=1 的随机样本,..,n)},其中观察值彼此独立。
- 没有完美的共线性:没有一个自变量是常数,自变量之间没有精确的线性关系。
- 外生性:给定自变量的任意值,扰动项的期望值为零。换句话说,E(ε|xi)=0。
- 同方差:给定独立变量的任意值,扰动项具有相同的方差。换句话说,Var(ε|xi)= σ。
高斯-马尔可夫假设保证了普通最小二乘法(OLS)估计回归系数的有效性。
普通最小二乘法(OLS)
如前所述,我们希望获得可靠的系数估计值,以便能够研究感兴趣的变量之间的关系。列出的模型假设使我们能够做到这一点。基于模型假设,我们能够推导出最小化残差平方和(SSR) 的截距和斜率估计值。最小化 SSR 是期望的结果,因为我们希望回归函数和样本数据之间的误差尽可能小。最小化 SSR 的系数估计称为普通最小平方****【OLS】估计。
在这篇文章中,我们不会为 OLS 估计是如何得出的而烦恼(尽管理解 OLS 估计的推导确实会增强你对我们之前所做的模型假设的含义的理解)。
简单线性回归的 OLS 系数估计值如下:

其中系数上方的“帽子”表示它与系数估计值有关,x 和 y 变量上方的和“条”表示它们是样本平均值,计算如下

小例子
现在,我们已经定义了简单的线性回归模型,我们知道如何计算系数的 OLS 估计。我们如何解释系数估计值?这里,我们将考虑一个小例子。
假设我们对工作经验对工资的影响感兴趣,其中工资以年收入衡量,经验以经验年限衡量。为了研究工资(因变量)和工作经验(自变量)之间的关系,我们使用以下线性回归模型:

系数β1 衡量的是工作年限增加一个单位时年薪的变化。因为经验多(通常)对工资有正向作用,所以我们认为β1 > 0。
在这个例子中,我们使用了 30 个数据点,其中年薪从 39343 美元到 121872 美元不等,工作年限从 1.1 年到 10.5 年不等。正如您所想象的,仅包含 30 个数据点的数据集通常太小,无法提供准确的估计,但这对于说明来说是一个不错的大小。让我们制作一个散点图,以便更深入地了解这个小数据集:

图 1:工资数据集的散点图
看着这个散点图,我们可以想象线性模型在这里可能实际上工作得很好,因为看起来这个样本中的关系非常接近线性。
接下来,让我们使用前面导出的公式来获得这个特定应用的简单线性回归模型的 OLS 估计。通过使用这些公式,我们获得了以下系数估计值:

因此,将工资与经验联系起来的 OLS 回归线是

等式中工资顶部的“宽帽”表示这是一个估计等式。
现在,我们如何解释这个等式?我们可以用这个等式来预测不同工作年限的工资。当我们假设经验=5 时,模型预测工资为 73,042 美元。对于一个完全没有经验的人(即经验=0),该模型预测工资为 25,792 美元。
除了预测,我们还可以用这个等式来研究工作年限与年薪的关系。一个人多一年的工作经验,预计他的年薪会增加 9449 美元。这意味着(如我们所料),多年的工作经验对年薪有的正面影响。
为了完成这个示例,让我们在前面看到的散点图中添加回归线,以查看它与数据点的关系:

图 2:添加到散点图的回归线
感谢阅读!
我希望这篇文章能帮助你开始了解(简单)线性回归模型是如何工作的,或者如果你已经熟悉这个概念的话,为你澄清一些问题。
使用 Python 和 Numpy 从头开始简单的线性回归解释和实现
你是否经常使用线性回归,但却不知道它的本质是什么?这篇文章将帮助你理解这个重要的概念!

当我们开始研究机器学习时,大多数时候我们并不真正理解那些算法在引擎盖下是如何工作的,它们通常对我们来说就像是黑盒。今天,我想介绍一下回归任务中最基本也是最著名的算法之一——线性回归。在本文中,我将从头开始构建并解释 Python 中的线性回归模型,我们还将看到它在从sk learn . datasets . make _ Regression方法生成的回归数据集上的性能,与 Sklearns 的从sk learn . Linear _ Regression 生成的线性回归相比。线性回归 类。那么,我们可以开始了吗?
用于线性模型创建的数据集
在一个简单的例子中,假设我们只有一个变量— X. 基于对 X 的了解,我想预测未知变量 Y. 我还将定义训练集,它包含所有已知的( X_train,Y_train )变量对和验证集,我仅从中取 X_val 然后,我们可以在知道 Y_pred 和 Y_val 变量的情况下测量模型的性能。让我们在 Python 代码中定义训练和测试集:

在这里,我导入了 make_regression 方法,并创建了包含 1 个特征(即 X 和目标(即 Y. )的数据集。现在,让我们将数据集拆分为训练和验证部分。如上所述,这可以通过sk learn . model _ selection . train _ test _ split方法来完成。如上所述,我将在训练零件上训练线性回归模型,并在验证零件上评估模型。

如图所示,我将 70%的数据作为训练数据,另外 30%用于验证。现在,为了更好地理解我们的数据,我将绘制图片,显示我们的 X_train 和 Y_train 变量之间的关系。

因此,总而言之,我们的目标是建立一个模型,该模型将 X 作为输入,并预测相应的 Y 变量。让我们把它重写为函数:模型( X ) = Y. 考虑一个输入 X = -2,,那么模型 (-2) 将返回接近 -200 的值,如果输入 X =2 ,那么模型(2) 将返回接近 100 的值。总而言之,我将在 1 个特性案例中实现的模型如下所示:
型号(X) = W1X + W0*
W1 和 W0 为参数,将由模型在训练中学习。你可以看到,上面的函数只是直线的方程,因此,我们的线性模型的预测将形成直线,看起来像这样:

出现在图表上的线是最适合系列组的线。现在,当我准备好数据集后,让我们了解线性回归模型背后的直觉。
线性回归理论和直觉
正如我在上面解释的,主要思想是拟合一条线(在 1 个特征的情况下)或一个超平面(在 K 个特征的情况下),因此在 1 个特征的情况下,模型看起来像这样:
型号(X1) = W1X1 + W0*
在 K 特性的情况下,看起来是这样的:
型号(X1…Xk)= Wk * Xk+Wk-1 * Xk-1+…+W1 * X1+W0
注意,在这两种情况下,我们都有 W0 项,称为偏差。为了有效地训练模型,我们也可以将其重写为:
模型(X0,X1…Xk)= Wk * Xk+Wn-1 * Xn-1+…+W1 * X1+W0 * X0,其中 X0 = 1
简而言之,在 1 个特征的情况下,如果 W0 = 0 ,那么 W1 变量的任何选择将仅导致线围绕(0,0)点旋转。W0 项有助于移动直线或超平面,这通常导致更好的模型性能。
现在,接下来要了解的是如何选择这个 W0…Wk 术语。为此,你需要理解什么是损失函数以及梯度下降背后的想法。
https://www.youtube.com/watch?v=sDv4f4s2SB8
一般来说,损失函数显示模型的当前预测值(模型(X) )与真实的 Y 值有多接近。使用梯度下降,我们以这样的方式进行小步骤,即我们的损失函数减少(即,在训练模型 W1…Wk 的每一步,参数以这样的方式变化,即在一些步骤之后,我们的损失函数稳定在局部最小值。我的意思是:

https://stack overflow . com/questions/56794716/periodic-oscillating-loss-function-for-py torch-ccnn
在第一步,损失是高的(即预测和 Y 变量彼此远离)。每走一步,损失就会减少,预测值会变得更接近真实值。
让我们为我们的任务定义损失函数,我们将使用 MSE 作为损失函数:

同样,让我们计算损失对 Wj 的导数,

总而言之,以下是您在训练线性回归模型时要做的事情:
- 你随机初始化模型的 W0…Wk 变量。
对于一定数量的迭代(步骤数),您需要执行以下操作:
2.根据以下规则更新 W0…Wk :

这里 dL/dWj 是损失函数相对于 Wj 的导数。(上面我们已经定义了梯度的公式),这里的 learning_rate 只是模型的超参数,你要在训练前自己选择(我一般是从 learning_rate 0.001 开始)
嗯,基本上这就是你实现所需要的所有理论,我建议你重读几遍这部分,如果你没有得到什么,这完全没问题!现在我将用 Python 实现一个简单的线性回归模型类。
用 Python 实现线性回归模型
首先,让我们定义我们类的主要功能:

这里我用两种方法创建了 SimpleLinearRegression 类: fit 和 predict 。我们的模型将学习拟合方法中最佳拟合线的参数,我们将使用预测方法来预测未知的 X 变量。您还可以看到,类的构造函数( init )有两个变量(我们将在创建类实例时定义它们),它们是: learning_rate 和 n_steps 。我已经在直觉部分解释了这两个变量。
现在让我们实施拟合方法,如插入部分所述。我们还需要一种方法来计算每个 W 的损失梯度:

该函数是梯度计算函数的矢量化实现,但同时适用于所有权重:

其中 K—参数总数,W0 是偏置项。
现在有了梯度函数,让我们实现拟合方法,以如下方式迭代更新 W0…Wk 参数:

fit 函数现在应该是这样的:

理解该功能的每个部分至关重要。首先,我们添加如上所述的偏差项,np.c_ 在这里的作用如下:

这里的每一行代表一个单独的点,每一列是一个单独的特征。因此,对于每一行(点),我添加一个新的偏差特征。之后,我随机初始化权重并运行一个循环,在每一步我都更新所有的权重。这就是 fit 函数的全部功能!我们流程的最后一步是实现预测功能,如下所示:

正如您在这里看到的,我还添加了偏差项,并转移到该函数的矢量化实现 x^T * w。
实现如下:

这就是我们简单线性回归模型的全部实现!现在让我们在之前准备好的数据集上测试它。
简单线性回归模型测试和评估
作为第一步,我在本文第一部分定义的训练数据集上拟合模型。

到目前为止,我们的模型已经学习了 W1,W0 参数的最佳值(在我们的例子中是 1 个参数和偏置项)。现在我们可以调用 predict 方法,来获得对 X_val 点的预测。

现在让我们用 MSE 函数(我们用作损失函数的那个)来衡量预测质量。


让我们也做一个对(X_val,Y_val)和(X_val,Y_pred)的散点图

正如你所看到的,我们的模型已经学习了最佳拟合线(橙色的那条),它很好地描述了给定的一组点。
现在,我将对 sklearn.linear_model 执行相同的步骤。LinearRegression 模型类,做个比较。

如你所见,sklearns 实现的 MSE 误差要低一些,这是因为他们的模型比我们的要复杂一些。
结论
总而言之,今天我们已经完成了一项非常出色的工作——用 Python 从头开始实现了一个简单而有效的线性回归算法。我希望您能够轻松理解本文的每一点,如果需要的话,您可以自己实现相同的功能。我已经将这篇文章中的 Jupyter 笔记本完整加载到 github 中,所以请不要犹豫使用它并从中学习。
你可以在我的 网站 上查看其他帖子
使用 Python 的简单线性回归模型:机器学习
学习如何使用 Python 中的 Jupyter notebook 在机器学习中构建简单的线性回归模型

凯文·Ku 在 Unsplash 上的照片
在上一篇文章中, 线性回归模型, 我们已经看到了线性回归模型在理论上是如何使用 Microsoft Excel 工作的。本文将介绍如何在 Jupyter 笔记本中使用 Python 构建线性回归模型。
简单线性回归
为了预测两个变量之间的关系,我们将使用一个简单的线性回归模型。
在简单的线性回归模型中,我们将只使用一个自变量来预测一个称为因变量的变量的结果。
在本文中,我们将直接开始构建模型。更多关于线性回归模型和我们必须考虑的因素在这里详细解释。
构建线性回归模型
为了在 python 中构建线性回归模型,我们将遵循五个步骤:
- 阅读和理解数据
- 可视化数据
- 执行简单的线性回归
- 残差分析
- 测试集上的预测
阅读和理解数据
在这一步中,首先,我们将导入必要的库来导入数据。之后,我们将执行一些基本命令来理解数据的结构。
我们可以从这里下载我们将在本文中使用的样本数据集。
让我们假设我们有一个公司的数据,其中有花费在不同类型广告上的金额及其随后的销售额。
导入库 我们将导入 Jupyter 笔记本中的numpy和pandas库,并使用pandas读取数据。
数据集看起来像这样。这里我们的目标变量是销售列。

公司的广告数据
理解数据 让我们执行一些任务来理解数据,比如shape、info和describe。
我们数据集的shape是,
(200, 4)
使用info,我们可以看到数据中是否有空值。如果是,那么我们必须做一些数据操作。

数据集的信息
正如我们所观察到的,数据中没有空值。
使用describe,我们将看到数据值是否有任何突然的跳跃。

描述数据集
列中显示的值在整个数据中相当一致。
可视化数据
现在让我们使用matplolib和seaborn库来可视化数据。我们将绘制所有列的配对图,并查看哪些列与Sales最相关。
在两个数值变量之间使用散点图总是更好。上面代码的 pairplot 看起来像,

每个列的 pair plot w . r . t . Sales 列
如果我们不能使用散点图来确定相关性,我们可以使用 seaborn 热图来可视化数据。
热图看起来像这样,

数据中所有列的热图
从上面的图表中我们可以看出,电视栏目似乎与销售最相关。
让我们使用电视作为特征变量来执行简单的线性回归模型。
执行简单的线性回归
一元线性回归方程
y = c + mX
在我们的例子中:
y = c + m * TV
m 值称为模型系数或模型参数。
我们将分四步执行简单的线性回归。
- 创建 X 和 y
- 创建训练和测试集
- 训练你的模型
- 评估模型
创建 X 和 y 首先,我们将特征变量/列TV指定为X,目标变量Sales指定为y。
概括地说,
自变量代表X,y代表简单线性回归模型中的目标变量。
创建训练集和测试集我们需要将变量分成训练集和测试集。使用训练集,我们将构建模型并在测试集上执行模型。我们将把训练集和测试集分别分成 7:3 的比例。
我们将通过从sklearn.model_selection库中导入train_test_split来分割数据。
让我们来看看训练数据集,
X_train 数据拆分后是这样的。

分割后的 X_train 数据
y_train 数据拆分后是这样的。

拆分后的 y_train 数据
建立和训练模型 使用下面的两个包,我们可以建立一个简单的线性回归模型。
statsmodelsklearn
首先,我们将使用statsmodel包来构建模型。为此,我们需要导入statsmodel.api库来执行线性回归。
默认情况下,statsmodel库适合一条穿过原点的线。但是如果我们观察简单的线性回归方程y = c + mX,它的截距值为c。因此,要进行截取,我们需要手动添加add_constant属性。
一旦我们添加了常数,我们就可以使用OLS(普通最小二乘法)来拟合回归线。之后,我们将看到直线的参数,即c和m。
输出是,

直线的截距和斜率
让我们看看回归线拟合的所有不同参数的汇总,如R²、F-statistic和p-value的概率。
上述回归线的统计数据是,

上述最佳拟合线的所有统计数据
因此,我们主要关心的决定模型是否可行的统计数据是:
coefficients及其p-value(意义)R-squared值F-statistic及其意义

我们需要看的统计数据
1.电视的coefficient为 0.054,其对应的p-value很低,几乎为 0。这意味着coefficient在统计上是显著的。
我们必须确保 p 值总是小于这个系数才是有效的
2.R-squared值为 0.816,这意味着Sales方差的 81.6%可以通过使用此行的TV列来解释。
3.Prob F-statistic的p-value非常低,几乎为零,这让我们知道模型拟合在统计上是显著的。
由于拟合度很高,让我们继续观察直线与TV和Sales列之间的散点图的拟合度。
从这些参数中,我们得到了直线的intercept和slope的值。这条线的方程式是,
Sales = 6.948 + 0.054 * TV
图表看起来像这样,

最佳回归直线
这就是我们如何使用训练数据建立一个简单的线性回归模型。现在,在根据测试数据评估模型之前,我们必须执行残差分析。
残差分析
线性回归模型的主要假设之一是误差项是正态分布的。
Error = Actual y value - y predicted value
现在,从数据集中,
我们必须使用predict属性从 X 的训练数据集中预测 y 值。之后,我们将从预测数据中创建误差项(残差)。
现在,让我们画出残差的直方图,看看它是否像正态分布。
残差的直方图看起来像,

残差分布
正如我们所见,残差服从均值为 0 的正态分布图。
现在,确保残差不遵循任何特定的模式。
散点图看起来像,

残值散点图
由于残差遵循正态分布,不遵循任何特定的模式,我们可以使用我们建立的线性回归模型来评估测试数据。
对测试数据的预测或评估模型
现在,我们已经在训练数据集上拟合了回归线,我们可以对测试数据进行一些预测。类似于训练数据集,我们必须add_constant测试数据,并使用statsmodel中的predict属性预测 y 值。
测试数据的预测 y 值为:

预测 y 值
现在,让我们计算上面预测的 y 值的R²值。我们可以通过从sklearn.metrics包中导入r2_score库来实现。
使用上述代码得到的 R 值= 0.792
如果我们能从训练数据中记住,R 值= 0.815
由于测试数据的 R 值在训练数据的 R 值的 5%以内,我们可以得出结论,该模型相当稳定。这意味着,模型在训练集上学习的内容可以在看不见的测试集上推广。
让我们想象一下测试数据上的线。
具有最佳拟合线的散点图看起来像,

测试数据的最佳拟合线
这就是我们如何使用statsmodel包构建线性回归模型。
除了statsmodel,我们可以使用sklearn建立一个线性回归模型。使用来自sklearn的linear_model库,我们可以制作模型。
与statsmodel类似,我们将数据分成train和test。
对于简单的线性回归,我们需要添加一列来正确地执行回归拟合。
X_train 加列前的形状是(140, )。
训练和测试数据的 X 形状为(140, 1)。
现在,让我们将这条线与从sklearn.linear_model导入LinearRegression库的图相匹配。
现在,让我们找出模型的系数。
截距和斜率的值是,

系数值
我们得到的上述值的直线方程是,
Sales = 6.948 + 0.054 * TV
如果我们观察,这里得到的方程和statsmodel中得到的方程是一样的。
之后,我们将对数据进行预测,并通过比较 R 值来评估模型。
训练和测试数据的 R 值为
R train _ data = 0.816
R test _ data = 0.792
与statesmodel相同,测试数据的 R 值在训练数据的 R 值的 5%以内。我们可以在未来将该模型应用于未知的测试集。
结论
正如我们所见,我们可以使用statsmodel或sklearn构建一个线性回归模型。
我们必须确保遵循这五个步骤来构建简单的线性回归模型:
- 阅读和理解数据
- 可视化数据
- 执行简单的线性回归
- 残差分析
- 测试集上的预测
在下一篇文章中,我们将看到多元线性回归模型是如何工作的。
感谢您阅读和快乐编码!!!
点击这里查看我以前的文章
- 线性回归模型:机器学习
- 探索性数据分析(EDA): Python
- (CLT)中心极限定理:数据科学
- 推断统计:数据分析
- Seaborn: Python
- 熊猫:蟒蛇
- Matplotlib:Python
- NumPy: Python
参考
- 机器学习—线性回归:https://www . w3schools . com/python/python _ ml _ Linear _ Regression . ASP
- Python 中的线性回归:https://realpython.com/linear-regression-in-python/
- 线性回归(Python 实现):https://www . geeks forgeeks . org/Linear-Regression-Python-Implementation/
- 用 Scikit 学习 Python 线性回归的初学者指南:https://www . kdnugges . com/2019/03/初学者指南-线性回归-python-scikit-learn.html
简单线性回归:里面是什么?
让我们深入研究简单线性回归的数学意义并实现它。

第 0 步:开始
回归是一种统计方法,建议在其他自变量(数据)的帮助下预测因变量(目标特征)。回归是最广为人知和理解的统计方法之一。
线性回归是一种假设因变量和自变量之间存在线性关系的模型。线性回归进一步分为简单线性回归(SLR)和多元线性回归(MLR)。我们将探讨一元线性回归,即一个因变量和一个自变量的回归,因为它简单。SLR 的数学是许多其他机器学习模型的基础。
在这里,我将详细阐述简单的线性回归,以获得关于它如何工作的直觉。我将使用一个 NBA 比赛得分数据集(下面的链接)来演示单反,并最终将其与 Scikit-learn 的线性回归模型进行比较。
简单线性回归
要理解单反,我们来分解一下必须要经历的概念
- SLR 线及其系数
- 损失函数
- 梯度下降
- 导出系数(可选)
SLR 线及其系数
直线的斜率截距形式为 Y= MX+B。
y 是因变量(目标),X 是自变量(数据),M 和 B 是直线的特征。斜率(M)给出了相关变量 X 和 Y 的关系,截距(B)给出了当变化率被消除时因变量的值的信息。

来源: onlinemath4all
在单反中,等式写成 y = b0 + x b1。 b0 和 b1 分别是截距和斜率。它们由下面给出的公式确定,以找到最佳拟合线。


但是,在回归中情况并不总是如此。让我们在梯度下降部分了解一下为什么。如果你对我们如何偶然发现这些感到好奇,请查看可选部分。
损失函数
损失函数是表明预测值与实际值偏离程度的一种度量。有很多损失函数可用,我们将着眼于均方差(MSE)。

MSE,顾名思义,对每条记录的实际值和预测值之差求平方,求和,然后除以记录数。我们的目标是找到一个损失最小的模型。
梯度下降
梯度下降是一种优化算法,它迭代地更新参数,以找到损失最小的模型。具有一个或两个参数的模型的损失函数可以被部分微分以找到最小值。但是随着维度的增加,很难将参数可视化,更不用说每个解的特征值了。由于局部最小值的多次出现,我们将不得不遍历特征值的所有组合,以确保我们找到了全局最小值。尽管全局最小值问题没有完全解决,梯度下降有助于找到高阶模型的最小值。
但是我们还没有探索问题的基础:损失函数。MSE(作为二次函数)保证曲线上总有一个点的梯度为零,但有些损失函数不能保证梯度为零的点,或者梯度为零的点可能不总是全局最小值。为了克服这个问题,采用了梯度下降法。
具体到我们的情况,我们可以选择通过上面给出的公式来找到系数,或者我们可以从随机非零值开始,让它以最佳方式工作。梯度下降算法的数学意义本身就值得写一篇文章。现在,我将通过直觉来实现这个算法。数学方法类似于系数,我认为把它包括进来是多余的(如果你好奇,我会在最后把它联系起来)。
现在,让我们看看梯度下降是怎么回事。想象一个人在没有视觉的情况下徒步下山;这个人的目标是到达谷底。凭直觉,他向前迈了一步,如果坡度是向下的,他将继续前进,直到遇到坡度的变化。一旦这个人在移动中感觉不到提升,他/她就会停下来。

来源: kdnuggets
但是如上所述,采取确定长度的步骤然后评估路线修正是没有意义的,因为这个人可能已经通过了最小值,却意识到他/她向错误的方向移动。这就是学习率发挥作用的地方。它惩罚大步,以确保该人不采取一步超过最低限度。
人如何选择学习速度?
不幸的是,学习率没有“万能”的标准。我们可以粗略估计这个值的一种方法是通过反复试验。我们必须注意的问题是学习率的高低。这两种方法的计算量都很大,所以在开始时总是要运行几次模型来检查损失的变化。浪费的计算能力和时间。
一个适合高学习率的类比是金属球轴承和碗。当一个球从碗的边缘被释放出来时,它的速度会随着力的方向趋向最小值而不断增加。当它经过最小值时,球的方向会远离最小值,但作用在球上的力的方向会相反。这样,通过一些有损耗的振荡,它最终在碗的底部达到稳定的平衡。有损耗的振荡是计算能力和时间的浪费。

来源:深度学习向导
现在,我们把这个和单反合并一下。我们所指的人是 b0 和 b1 系数。我们看到的谷是 MSE 相对于 b0 和 b1 参数绘制的曲线。学习率(alpha)为我们提供了修改参数的步长,而不必在每次通过时跳过最小值。
推导系数(可选)
虽然不是关键,但探索模型的机制很有趣。让我们首先建立基本方程和推导方程的术语。在我们开始之前,确保你熟悉微积分的基础知识。

既然我们都有了方程,让我们开始研究 b0 和 b1。现在,如果我们绘制任何一个系数(保持另一个不变)对 E 的曲线,它看起来会像这样

函数的最小值可以通过对函数相对于系数进行部分微分并使梯度等于零来找到。现在我们的目标是
- 为了找到两个系数的梯度为零(近似)的点
- 找出一个仅是给定数据的函数的方程。
找到 b0

现在求最小值,将梯度等于零。

虽然我们确实找到了 b0 的值,但是它依赖于 b1。
找到 b1

代入 b0 的值并部分微分

类似于 b0,将梯度等于零

这检验了我们的目标;我们找到了 b1 的方程式,它只依赖于我们现有的数据。我们能够利用曲线的基本性质找到这些值。
实现
首先,让我们处理数据,然后使用
- 系数
- 梯度下降
- Scikit-learn 线性回归
数据
使用标准 python 库,让我们导入数据并可视化分布。
**import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns** %matplotlib inline*#load data*df=**pd.read_csv**('teampts_fg.csv')
X=df['TeamPoints'].**values**
y=df['FieldGoals'].**values***#plot data***plt.rcParams**["figure.figsize"] = (12,8)
**plt.xlim**(40,160)
**sns.scatterplot**(x='TeamPoints', y='FieldGoals', data=df);

*#define the loss function***def** loss(data, data_pred):
N=data.**shape**[0]
loss=**np.sum**(**np.square**(data-data_pred))/N
**return** loss
使用系数实现模型
Bc1=**sum**((X-**np.mean**(X)) * (y - **np.mean**(y)))/**sum**((X-**np.mean**(X))**2)
Bc0=np.mean(y) - Bc1*(np.mean(X))
x_coeff_model=np.linspace(40,160,1000)
y_coeff_model= Bc1*x_coeff_model + Bc0*#plot the line with the original data***plt.rcParams**["figure.figsize"] = (12,8)
**plt.xlim**(40,160)
**sns.scatterplot**(x='TeamPoints', y='FieldGoals', data=df);
**plt.plot**(x_coeff_model, y_coeff_model,c='r');
**plt.show**()
**print**("The value of b0 is {} and b1 is {}".format(Bc0, Bc1))

使用系数的最佳拟合线
使用梯度下降实现模型
loss_history=[]*#define gradient descent***def** gradient_descent(epochs, X , y , alpha):
B0=0.0001
B1=0.0001
N=X.**shape**[0]
for i in np.arange(epochs):
y_pred= B0 + B1*X
loss_history.append(loss(y,y_pred)) dB0=(-2/N)***np.sum**(y-y_pred)
dB1=(-2/N)***np.sum**(X*(y-y_pred)) B0= B0- alpha*dB0
B1= B1- alpha*dB1 **return** [B0,B1]*#call the gradient_descent function for 30 iterations on the data*Bgd0,Bgd1=**gradient_descent**(30, X, y, 0.00001)
现在根据获得的参数绘制直线。
x_gd_model=**np.linspace**(40,160,1000)
y_gd_model= Bgd1*x_coeff_model + Bgd0
**plt.rcParams**["figure.figsize"] = (12,8)
**plt.xlim**(40,160)
**sns.scatterplot**(x='TeamPoints', y='FieldGoals', data=df);
**plt.plot**(x_gd_model, y_gd_model,c='r')
**plt.show**()
**print**("The value of b0 is {} and b1 is {}".format(Bc0, Bc1))

使用梯度下降的最佳拟合线
我以很小的学习率存储了几百次迭代的每个值,以可视化模型如何成熟。使用 pyplot,我保存了所有的图来制作一个 gif。

现在让我们绘制模型的损失历史。
**plt.plot**(loss_history);
**plt.xlabel**("Number of iterations")
**plt.ylabel**("Loss")
**plt.show**()
**print**("Loss at iteration 25 is {}".format(loss_history[24]))

使用 scikit-learn 实现模型
**from** sklearn.linear_model **import** LinearRegression
lr= **LinearRegression**()
lr.**fit**(X.**reshape**(-1,1),y.**reshape**(-1,1))
x_lr_model=**np.linspace**(40,160,1000)
y_lr_model=lr.**predict**(x_lr_model.**reshape**(-1,1)).**reshape**(1,-1)[0]*#plot the line***plt.rcParams**["figure.figsize"] = (12,8)
**plt.xlim**(40,160)
**sns.scatterplot**(x='TeamPoints', y='FieldGoals', data=df);
**plt.plot**(x_lr_model, y_lr_model,c='r')
**plt.show**()

使用 scikit-learn 的最佳拟合线
对比
**plt.plot**(x_lr_model, y_lr_model,c='b', label="LinearRegression");
**plt.plot**(x_gd_model, y_gd_model, c='r', label="Gradient Descent");
**plt.plot**(x_coeff_model, y_coeff_model, c='g', label="Coefficient");
**plt.legend**()
**plt.show**()

*#let's print the loss between lines to see the difference***print**("The loss between Coeff model and Gradient descent {}".format(loss(y_coeff_model,y_gd_model)))
**print**("The loss between Coeff model and Linear Regression Model {}".format(loss(y_coeff_model,y_lr_model)))
**print**("The loss between Gradient descent and Linear Regression Model {}".format(loss(y_gd_model,y_lr_model)))

在上面的比较图中,我们可以看到线性回归线和系数线重叠。但是另一方面,梯度下降线稍微偏向线性回归线。这是什么意思?我们来调查一下。
loss_gd=loss_history[-1]
loss_lr=loss(Bc0+Bc1*X, y)
**print**("The loss of the LinearRegression line is {}".format(loss_lr))
**print**("The loss of the GradientDescent line is {}".format(loss_gd))

尽管线的损失有所不同,但所有模型的预测值和实际值之间的损失是非常相似的。我们可以有把握地推断梯度下降线——尽管它没有相同的参数——已经以近似等于理想状态的方式定位了自己。

步骤 steps_count[-1]:结束
最后,这是简单线性回归的内容。谢谢你。
参考
[## 如何用 Python-Machine Learning mastering 实现简单的线性回归
线性回归是一种已有 200 多年历史的预测方法。简单的线性回归是一个很好的开端…
machinelearningmastery.com](https://machinelearningmastery.com/implement-simple-linear-regression-scratch-python/) [## 使用梯度下降的线性回归
在本教程中,你可以学习梯度下降算法的工作原理,并从头开始用 python 实现它。首先…
towardsdatascience.com](/linear-regression-using-gradient-descent-97a6c8700931) [## 2014 年至 2018 年 NBA 球队比赛统计
2014 - 2018 nba 期间每场比赛的统计数据
www.kaggle.com](https://www.kaggle.com/ionaskel/nba-games-stats-from-2014-to-2018)
除引用图片外,所有图片均由作者制作
使用 Matplotlib 的简单小表格
如何创建一个漂亮的 Pyplot 表的注释示例

有时,我需要为包含几行和几列数据的文档创建一个图像。像大多数人一样,我将只使用屏幕截图来创建图像,但这种方法不太适合自动化任务,需要手工调整才能呈现。荒谬的是,我正在用熊猫和 Matplotlib 在我的 Jupyter 笔记本上工作,我正在截图以捕捉幻灯片和书面报告的表格。Matplotlib 呈现漂亮的图形。为什么不是漂亮的小桌子?
一种替代方法是使用 LaTeX 生成报告,LaTeX 具有强大的表格功能。采用 LaTeX 进行报告,只是为了渲染一个小表格,这种做法有些矫枉过正,而且常常是徒劳的。我真的很想用 Matplotlib 生成我的小网格,标题居中;没有无关文字;漂亮、干净的边框;可能还有一个小小的日期页脚。
由于 Jupyter 的输出单元渲染,熊猫可以在 Jupyter 笔记本上输出看起来不错的数据帧。它甚至可以使用pandas.Dataframe.style库来设计这些熊猫数据帧的样式。使用这些工具构建样式化表格的挑战在于它们以 HTML 呈现输出。将文件转换成图像格式需要调用其他外部工具的工作流,比如[wkhtmltoimage](https://wkhtmltopdf.org),将 HTML 转换成图像。
Matplotlib 可以将图表保存为图像。如果你搜索 Matplotlib 文档,你会发现它有一个matplotlib.pyplot.table包,看起来很有希望。它是有用的。事实上,我在这篇文章中使用了它。挑战在于matplotlib.pyplot.table创建的表格通常挂在堆叠的条形图下面,以向读者提供对上面数据的洞察。您希望只显示图表,并且希望图表看起来很漂亮。
当试图使用matplotlib.pyplot.table时,你可能会注意到的第一件事是,表格相当难看,并且不能很好地管理垂直单元格填充。第二,如果您试图隐藏图形,只显示表格网格,对齐问题就会暴露出来,使您永远无法得到您想要的漂亮的小表格。让桌子看起来漂亮需要一些工作,我将与你分享我自己做这项工作的心得。
Matplotlib 表示例
Matplotlib pyplot.table示例代码创建了一个表,但是没有展示如何用一个简单的表来显示数据。它生成一个表格,用作堆叠条形图的扩展。如果你跟随你的直觉,只隐藏图表,你会得到一个格式很差的图像,不适合你的文章或幻灯片演示。
在本文中,我将带您一步一步地将 Matplotlib 示例编写器提供的示例转换为您项目的一些简单表格代码。我解释了我在这一过程中所做的更改,这应该有助于您进行改进。我在文章的最后提供了完整的代码。
从示例中,您可以看到表格功能用于显示与相关堆积条形图相关的数据。

Matplotlib 表格演示示例(图片由作者提供)
示例的源代码(来自 Matplotlib 表格演示):
import numpy as np
import matplotlib.pyplot as pltdata = [[ 66386, 174296, 75131, 577908, 32015],
[ 58230, 381139, 78045, 99308, 160454],
[ 89135, 80552, 152558, 497981, 603535],
[ 78415, 81858, 150656, 193263, 69638],
[139361, 331509, 343164, 781380, 52269]]columns = ('Freeze', 'Wind', 'Flood', 'Quake', 'Hail')
rows = ['%d year' % x for x in (100, 50, 20, 10, 5)]values = np.arange(0, 2500, 500)
value_increment = 1000# Get some pastel shades for the colors
colors = plt.cm.BuPu(np.linspace(0, 0.5, len(rows)))
n_rows = len(data)index = np.arange(len(columns)) + 0.3
bar_width = 0.4# Initialize the vertical-offset for the stacked bar chart.
y_offset = np.zeros(len(columns))# Plot bars and create text labels for the table
cell_text = []
for row in range(n_rows):
plt.bar(index, data[row], bar_width, bottom=y_offset, color=colors[row])
y_offset = y_offset + data[row]
cell_text.append(['%1.1f' % (x / 1000.0) for x in y_offset])
# Reverse colors and text labels to display the last value at the top.
colors = colors[::-1]
cell_text.reverse()# Add a table at the bottom of the axes
the_table = plt.table(cellText=cell_text,
rowLabels=rows,
rowColours=colors,
colLabels=columns,
loc='bottom')# Adjust layout to make room for the table:
plt.subplots_adjust(left=0.2, bottom=0.2)plt.ylabel("Loss in ${0}'s".format(value_increment))
plt.yticks(values * value_increment, ['%d' % val for val in values])
plt.xticks([])
plt.title('Loss by Disaster')# plt.show()# Create image. plt.savefig ignores figure edge and face colors, so map them.
fig = plt.gcf()
plt.savefig('pyplot-table-original.png',
bbox_inches='tight',
dpi=150
)
整理数据代码并删除图形生成
现在,让我们开始工作吧。首先,我将打破表的图表。我根据自己的喜好重新格式化了图表数据,并删除了特定于堆积条形图的数据。这一步对你来说是可选的。当我从代码中的 Python 列表加载少量数据时,我更喜欢在数据数组中包含标签,并在适当的时候弹出它们。当我几个月后回来时,我可以更容易地阅读它。您可能会从外部 CSV 文件或数据库导入数据,并在 Pandas 数据框架中对其进行操作。将数据放在一个二维列表中使这个例子变得简单。
我还删除了plt.show()指令,并添加了将图像写入 png 文件的代码。如果在调用plt.savefig()之前调用plt.show(),图像将会是空白的,因为plt.show()重置了 pyplot 图形对象引用。记住plt.savefig()可以通过检测你提供的文件扩展名来输出其他图像类型(jpeg,svg,eps 等。).
注意:在我的实验中,我还对一些数据和标签做了微小的改动。为了与原始代码保持一致,我忘记在发布之前回滚它们。例如,“100 年”变成了“40 年”
data = [
[ 'Freeze', 'Wind', 'Flood', 'Quake', 'Hail'],
[ '5 year', 66386, 174296, 75131, 577908, 32015],
['10 year', 58230, 381139, 78045, 99308, 160454],
['20 year', 89135, 80552, 152558, 497981, 603535],
['30 year', 78415, 81858, 150656, 193263, 69638],
['40 year', 139361, 331509, 343164, 781380, 52269],
]# Pop the headers from the data array
column_headers = data.pop(0)
row_headers = [x.pop(0) for x in data]# Table data needs to be non-numeric text. Format the data
# while I'm at it.
cell_text = []
for row in data:
cell_text.append([f'{x/1000:1.1f}' for x in row])...fig = plt.gcf()
plt.savefig('pyplot-table-original.png',
bbox_inches='tight',
dpi=150
)
修复问题
让我们开始隔离和整理桌子。这需要几个步骤。我会带你穿过它们。
隐藏 x 和 y 轴
首先,让我们隐藏 x 和 y 轴,以及它们所有的刻度和标签。
ax = plt.gca()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)

x 轴和 y 轴已移除(图片由作者提供)
隐藏轴边框
坐标轴消失了,但我们留下了一个围绕条形图的边界。我们可以很容易地关掉它。
plt.box(on=None)

条形图边框已禁用(图片由作者提供)
把桌子放在图的中央
它越来越清晰,但是我们看到标题和表格之间有大量的空白。我们所要做的就是将现有的bottom校准改为center。这将使表格在隐藏轴区域居中。我们也应该从例子中去掉支线剧情的位置调整。
删除此行:
plt.subplots_adjust(left=0.2, bottom=0.2)
并将plt.table线改为居中loc:
the_table = plt.table(cellText=cell_text,
rowLabels=row_headers,
rowColours=rcolors,
colLabels=column_headers,
loc='center')

将表格居中(图片由作者提供)
缩放单元格以获得更多填充
这一改变很好地把桌子向上拉。现在,让我们解决单元格内过于紧凑的垂直空间。pylot.table不允许指定单元格的填充,但是我们可以用scale(x, y)函数的y参数将高度缩放 1.5 倍。这给了我们的细胞数据一点喘息的空间。您可以根据自己的喜好使用x和y值。
the_table.scale(1, 1.5)

缩放表格(图片由作者提供)
设置列标题和行标题的样式
让我们设置列颜色,并将行标题水平对齐设置为right。我们将填充两个颜色列表,一个用于每个行标题单元格,另一个用于每个列标题单元格。我们将只使用示例中使用的plt.cm.BuPm颜色图,尽管对于装饰颜色来说,有比线性颜色图更好的选择。我们将在创建表格时设置行和列标签的颜色和对齐方式。
rcolors = plt.cm.BuPu(np.full(len(row_headers), 0.1))
ccolors = plt.cm.BuPu(np.full(len(column_headers), 0.1))...the_table = plt.table(cellText=cell_text,
rowLabels=row_headers,
rowColours=rcolors,
rowLoc='right',
colColours=ccolors,
colLabels=column_headers,
loc='center')

样式行和列标题(按作者排列的图像)
给人物造型
我们可以显式声明图形,以便轻松控制其边框和背景颜色。我将在这里使用一些标记的颜色作为这种方法的例子,与上面使用的颜色图形成对比。我通常只使用白色作为背景,但是天蓝色很适合演示如何设置它的颜色。
fig_background_color = 'skyblue'
fig_border = 'steelblue'...plt.figure(linewidth=2,
edgecolor=fig_border,
facecolor=fig_background_color
)...plt.savefig('pyplot-table-figure-style.png',
bbox_inches='tight',
edgecolor=fig.get_edgecolor(),
facecolor=fig.get_facecolor(),
dpi=150
)

样式边框和背景(图片由作者提供)
在图形上居中标题
漂亮。像夏天一样。您可能注意到标题集中在轴数据上,不包括行标题。我们需要把它放在图的中心,修改三个代码。这些变化也提高了图中表格的居中一致性。
- 使用
plt.suptitle().`在图形上设置标题,而不是轴 - 在图形声明中为
tight_layout设置一个小的填充值。既然我们现在在这里声明一个紧凑的布局,我们应该从savefig中移除bbox='tight'。把它留在里面似乎会破坏桌子在图中的居中。如果您在图像生成过程中对中有困难,可以尝试此bbox设置。(实验人员:注意在save_fig中设置pad_inches=1与图形声明中调用的tight_layout={'pad':1}效果不一样。总有一天,我会找出原因。) - 可选地,在保存图形之前调用
plt.draw()。这可以解决图像渲染过程中图形边界裁剪和标题居中的问题。有时候没什么效果。
title_text = 'Loss by Disaster'...plt.figure(linewidth=2,
edgecolor=fig_border,
facecolor=fig_background_color,
tight_layout={'pad':1}
)...plt.suptitle(title_text)...plt.draw()...plt.savefig('pyplot-table-tighten-figsize.png',
#bbox_inches='tight',
edgecolor=fig.get_edgecolor(),
facecolor=fig.get_facecolor(),
dpi=150
)

将标题居中(图片由作者提供)
添加页脚
我们将使用图形文本来创建一个页脚,并调整位置值,直到它看起来合适为止。
footer_text = 'June 24, 2020'...plt.figtext(0.95, 0.05, footer_text, horizontalalignment='right', size=6, weight='light')

添加页脚(作者图片)
可选:使用明确的 figsize 缩小空间
表格图像看起来很好,但是自动布局并不总是产生我喜欢的空白。玩一个明确的数字大小往往可以拨入这个。猜测数字大小需要实验,并且可以改善或降低您的表格图像。
您可能还需要在bbox_inches='tight'中添加回savefig来重新计算边界框。否则,图像可能没有正确的左右填充。您可能会发现图像在 Jupyter 笔记本输出单元格中看起来很好,但在您保存的图像中没有对齐。让所有渲染者满意是一种平衡行为。您应该经常检查最终的输出图像,即使它们在 IDE 的预览中看起来很棒。
plt.figure(linewidth=2,
edgecolor=fig_border,
facecolor=fig_background_color,
tight_layout={'pad':1},
figsize=(5,3)
)...plt.savefig('pyplot-table-tighten-figsize.png',
bbox_inches='tight',
edgecolor=fig.get_edgecolor(),
facecolor=fig.get_facecolor(),
dpi=150
)

带有明确 figsize 的更紧凑的空白(图片由作者提供)
最终源代码
这个最终源代码不包括明确的图形大小声明。我喜欢更宽敞的外观。
import numpy as np
import matplotlib.pyplot as plttitle_text = 'Loss by Disaster'
footer_text = 'June 24, 2020'
fig_background_color = 'skyblue'
fig_border = 'steelblue'data = [
[ 'Freeze', 'Wind', 'Flood', 'Quake', 'Hail'],
[ '5 year', 66386, 174296, 75131, 577908, 32015],
['10 year', 58230, 381139, 78045, 99308, 160454],
['20 year', 89135, 80552, 152558, 497981, 603535],
['30 year', 78415, 81858, 150656, 193263, 69638],
['40 year', 139361, 331509, 343164, 781380, 52269],
]# Pop the headers from the data array
column_headers = data.pop(0)
row_headers = [x.pop(0) for x in data]# Table data needs to be non-numeric text. Format the data
# while I'm at it.
cell_text = []
for row in data:
cell_text.append([f'{x/1000:1.1f}' for x in row])# Get some lists of color specs for row and column headers
rcolors = plt.cm.BuPu(np.full(len(row_headers), 0.1))
ccolors = plt.cm.BuPu(np.full(len(column_headers), 0.1))# Create the figure. Setting a small pad on tight_layout
# seems to better regulate white space. Sometimes experimenting
# with an explicit figsize here can produce better outcome.
plt.figure(linewidth=2,
edgecolor=fig_border,
facecolor=fig_background_color,
tight_layout={'pad':1},
#figsize=(5,3)
)# Add a table at the bottom of the axes
the_table = plt.table(cellText=cell_text,
rowLabels=row_headers,
rowColours=rcolors,
rowLoc='right',
colColours=ccolors,
colLabels=column_headers,
loc='center')# Scaling is the only influence we have over top and bottom cell padding.
# Make the rows taller (i.e., make cell y scale larger).
the_table.scale(1, 1.5)# Hide axes
ax = plt.gca()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)# Hide axes border
plt.box(on=None)# Add title
plt.suptitle(title_text)# Add footer
plt.figtext(0.95, 0.05, footer_text, horizontalalignment='right', size=6, weight='light')# Force the figure to update, so backends center objects correctly within the figure.
# Without plt.draw() here, the title will center on the axes and not the figure.
plt.draw()# Create image. plt.savefig ignores figure edge and face colors, so map them.
fig = plt.gcf()
plt.savefig('pyplot-table-demo.png',
#bbox='tight',
edgecolor=fig.get_edgecolor(),
facecolor=fig.get_facecolor(),
dpi=150
)

简单的小桌子(图片作者)
结论
我分享了 Matplotlib pyplot.tables示例到一个简单、整洁的小表格的一步一步的转换,没有附带图表。表格排列整齐,适合您的出版物或演示文稿。这些步骤包括隐藏图表、使表格居中、设置颜色、插入页脚的代码更改,以及改进最终图像文件的对齐和间距的提示。也许有一天这些步骤会节省你的时间。
简单的机器学习管道
将所有必要的部分结合在一起,构建一个简单而强大的机器学习管道。这将包括 Keras/TensorFlow 模型训练、测试、自动再训练和 REST API

Alexei_other 在 Pixabay 上的照片
在这篇文章中,我将涵盖多个主题,并解释如何建立机器学习管道。什么是 ML 管道?这是一个帮助自动重新训练 ML 模型并通过 API 使其可用的解决方案。重新训练间隔可以通过调度程序配置,模型可以每天或以任何其他选定的间隔更新。
解决方案的简要架构:

简单的 ML 管道(作者:Andrej Baranovskij)
我正在使用 Keras 构建一个模型,它可以计算企业报表生成的等待时间。时间是根据报告 ID、报告参数和日部分计算的。有一个常见的规则,即模型在培训期间获得的规则,即报表运行速度较慢,参数较少,并且在一天的第二部分。
训练 Keras 模型的 Python 函数是获取数据,处理数据,然后调用 Keras API 来拟合模型。模型训练分十次进行,以选出最佳结果。最佳结果是根据模型评估结果和测试数据选择的,稍后会详细介绍。新模型是使用时间戳保存的,这使得如果有任何活动的调用同时发生,当前模型仍然可以得到服务(或者可能一些用户仍然喜欢调用以前的模型,这增加了额外的灵活性)。
从日程安排器执行模型再训练。我使用后台调度程序选项,这允许我们将它与 REST API 进程一起运行(我使用 PM2 来运行 Python 进程)。这使得控制更加简单,并且当重新训练任务运行时,REST API 调用不会被阻塞。
REST API 使用 Flask 库运行。模型预测函数是通过用 tf.keras.models.load_model API 加载最新的可用模型,并在其上调用预测函数来执行的。
型号
模型逻辑在report _ exec _ time _ model . py中实现。
函数 fetch_data 从 CSV 中读取数据。在本例中,它总是读取相同的数据(出于简单的原因),但是在实际实现中,对于每次重新训练,您很可能会读取新的数据。获取训练和测试数据集。对于报告参数特性,训练数据包含 0–10 个值,测试数据包含 11–20 个值。这是故意的,我们正在用训练中不知道的数据进行测试。这将允许我们检查模型是否能够获得正确的趋势——执行时间应该随着更多的报告参数而减少。特征报告参数通过计算 log 进行归一化,使值更小,从而帮助模型更好地学习它。这同样适用于训练和测试数据集。20%的训练数据用于验证。数据结构:

截图作者:Andrej Baranovskij
报告参数的测试数据来自不同的集合,并且在规模上不同于训练集合,但是使用 log 可以通过相同的规则标准化不同集合中的数据:
*# Normalize training feature - report_params*
eps=0.001
dataframe['report_params'] = np.log(dataframe.pop('report_params') +eps)
normed_df = dataframe
函数build _ feature _ layer定义张量流特征层。这是一个元数据层,有助于将数据自动转换为可用于训练算法的格式。特征报告 ID 和日部分是分类的。这两个特征都使用 TensorFlow 分类特征支持编码为指示器列。报表参数特性被定义为数值列。所有三列都定义为 TensorFlow 要素图层-这允许转换数据而无需额外的自定义处理:
feature_columns = []
report_id = feature_column.categorical_column_with_vocabulary_list('report_id', [1, 2, 3, 4, 5])
report_id_one_hot = feature_column.indicator_column(report_id)
feature_columns.append(report_id_one_hot)
feature_columns.append(feature_column.numeric_column('report_params'))
day_part = feature_column.categorical_column_with_vocabulary_list('day_part', [1, 2, 3])
day_part_one_hot = feature_column.indicator_column(day_part)
feature_columns.append(day_part_one_hot)
feature_layer = tf.keras.layers.DenseFeatures(feature_columns)
函数build _ dataset将熊猫数据转换为 TensorFlow 数据集。这种数据集可以直接发送到 Keras 模型训练:
batch_size = 16train_ds = df_to_dataset(train, shuffle=**False**,batch_size=batch_size)
val_ds = df_to_dataset(val, shuffle=**False**, batch_size=batch_size)
test_ds = df_to_dataset(normed_df_test, shuffle=**False**, batch_size = batch_size)
我用的是批量= 16。根据我的测试,这是在给定数据的模型训练期间找到最佳拟合的最佳批次。我们不需要打乱训练数据,在分成训练集和验证集的过程中已经打乱了。
函数 build_model 构建顺序 Keras 模型。该模型接受第一层——要素层(要素列表及其表示方式)。不需要指定输入维度。有三层,第三层是输出层(一个单位/神经元)。前两层分别设置 16 和 8 个单元/神经元和 relu 激活。通过试验不同的设置来选择层和单元的数量。
model = tf.keras.Sequential([
feature_layer,
layers.Dense(16, activation='relu'),
layers.Dense(8, activation='relu'),
layers.Dense(1)
])optimizer = tf.keras.optimizers.RMSprop(0.001)
model.compile(loss='mse',
optimizer=optimizer,
metrics=['mae', 'mse'])
该模型是在 train_model 功能中训练的。从零开始反复训练十次。结果保存了最佳模型。模型以 TensorFlow 格式保存。训练循环完成后,最佳模型被复制到 API 端点可访问的部署文件夹中。每个新模型都存储有时间戳,这允许实现模型版本控制。训练配置为提前停止回调,当 10 个周期没有改善时,训练停止。使用 TensorFlow 数据集的模型训练:
EPOCHS = 1000
*# The patience parameter is the amount of epochs to check
# for improvement*
early_stop = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)
history = model.fit(train_ds,
validation_data=val_ds,
epochs=EPOCHS,
verbose=0,
callbacks=[early_stop])
保存最佳模型。基于测试集评估模型。我将报表参数大于 10 的数据包含在测试集中,以便能够测试回归如何作用于看不见的数据。模型应该在训练过程中选择一个规则—报表参数越多,执行时间应该越短。我很高兴看到那个模特实际上正确地学习了这条规则:
loss, mae, mse = model.evaluate(test_ds, verbose=0)rmse = math.sqrt(mse)
print("Testing set RMSE Error:**{:5.2f}**".format(math.sqrt(mse)))
**if** rmse < best_rmse:
print("Saving model with RMSE Error **{:5.2f}**".format(math.sqrt(mse)))
model.save('./model_exec_time_temp/', save_format='tf')
best_history = history
best_rmse = rmse
将最佳模型复制到 API 可访问的目录中,以及用于版本控制的时间戳值:
ts = calendar.timegm(time.gmtime())
print('Creating new model:', ts)
copyDirectory('./model_exec_time_temp/', './model_exec_time/' + str(ts))
这是 RMSE = 8.02 秒的模型训练结果(这意味着在计算测试集数据的报告执行时间时出现约 8 秒的误差)。我们可以看到,在提前停止回调终止训练之前,大约需要 100 个时期:

截图作者:Andrej Baranovskij
函数 run_predict 接受输入数据进行推理,加载最新的可用模型,执行预测调用。
终点
端点逻辑在report _ exec _ time _ endpoint . py中实现
在这个脚本中,我实现了重新训练调度器和 REST API。重新训练在后台线程中运行,这允许保持 REST API 运行而不会阻塞。
计划程序被配置为每天运行一次,但是重新训练的时间间隔由您决定。当新数据可用时,重新训练是有意义的:
# create scheduler
scheduler = BackgroundScheduler()
scheduler.start()# Using UTC time to schedule job, once per day.
scheduler.add_job(
func=report_model.train_model,
trigger='cron',
hour='9',
minute='45')
REST API 通过 Flask 实现。请求参数被发送用于推理到模型中(自动从调度器中挑选出最佳的最新模型,或者你可以基于模型版本化实现其他逻辑)预测方法,结果被返回给客户端:
app = Flask(__name__)
CORS(app)[@app](http://twitter.com/app).route("/katana-ml/api/v1.0/predict/reporttime", methods=['POST'])
def predict():
report_id = request.json['report_id']
report_params = request.json['report_params']
day_part = request.json['day_part']
input_data = [[report_id, report_params, day_part]]
result = report_model.run_predict(input_data)
return str(result[0][0])# running REST interface port=3000
if __name__ == "__main__":
app.run(debug=False, host='0.0.0.0', port=3000)
我们来验证一下模型。以来自模型训练集的数据为例(报告 ID、报告参数、日部分=时间):
1, 10, 3 = 440
用 15 个报表参数做推断。正如所料,执行时间更短= 429,这意味着模型训练正确:

截图作者:Andrej Baranovskij
如果有 11 个报告参数,执行时间会稍微长一点,这是应该的:

截图作者:Andrej Baranovskij
您可以尝试不同的报告 ID 和日部分值,看看执行时间计算是如何变化的。
部署
Python 端点进程正在使用 PM2 管理器运行。用 PM2 命令启动进程:
pm2 start report_exec_time_endpoint.py

截图作者:Andrej Baranovskij
结论
希望本文描述的信息能够帮助您在生产中运行可扩展的机器学习管道。我认为核心部分是一个自动化的重新训练选项,这有助于在新数据可用时保持模型更新。在单独的线程中运行预定的再训练的能力允许我们在与 API 端点相同的过程中管理它。这使得管道更简单,更易于维护。
源代码 : GitHub repo。
带有 Amazon SageMaker、Lambda 和 AWS 阶跃函数的简单 Data Science SDK
使用 AWS 上的无服务器组件构建您自己的 ML CI/CD 管道。

介绍
随着机器学习领域的成熟,越来越需要简单的方法来自动化 ML 管道并将其部署到生产中。随着数据科学平台的爆炸式增长,公司和团队经常使用不同的机器学习平台进行数据探索、提取-转换-加载(ETL)作业、模型训练和部署。在这篇博客中,我们描述了用户如何使用 Docker 自带算法代码来构建训练和推理图像,使用 Amazon SageMaker 和 AWS StepFunctions 来训练和托管他们的模型。我们使用 Mask R-CNN,这是一种非常流行的实例分割模型,用于许多计算机视觉用例,如[1]。希望亲自了解这篇博客内容的读者可以参考我们的Github【2】。
使用的 AWS 服务
AWS code build:AWS code build 是一个完全托管的持续集成(CI)服务,允许用户将代码编译和打包成可部署的工件。在这里,我们将使用 CodeBuild 将我们的自定义 Mask R-CNN 容器打包到 Docker 映像中,我们将该映像上传到 Amazon Elastic Container Registry(ECR)
AWS Lambda:AWS Lambda 是一种服务,它允许您在不提供服务器的情况下运行代码。这里我们将使用 AWS Lambda 来部署一个代码构建作业。
AWS step functions:AWS step functions 是一个编排工具,允许用户构建管道并将微服务协调到工作流中。然后,AWS StepFunctions 可以以事件驱动的方式触发该工作流,而无需用户管理任何底层服务器或计算机。
亚马逊 SageMaker: 亚马逊 SageMaker 是一个完全托管的机器学习平台,用于构建、训练和部署机器学习模型。在这里,我们使用 Amazon SageMaker 编写培训和模型部署作业,使用 SageMaker Jupyter 笔记本编写 StepFunctions 工作流。
创建一个屏蔽 R-CNN 容器
因为我们在培训或托管中运行相同的映像,所以 Amazon SageMaker 用参数train或serve运行您的容器。当 Amazon SageMaker 运行训练时,你的train脚本就像一个普通的 Python 程序一样运行。托管与训练有着非常不同的模型,因为托管是对通过 HTTP 传入的推理请求做出响应。在这个例子中,我们使用我们推荐的 Python 服务栈来提供推理请求的健壮和可伸缩的服务:
集装箱
在“container”目录中,是您打包 Amazon SageMager 的示例算法所需的所有组件。
├── Dockerfile
├── build_and_push.sh
└── mask_r_cnn
├── nginx.conf
├── predictor.py
├── serve
├── wsgi.py
├── transforms.py
├── utils.py
├── coco_eval.py
├── coco_utils.py
├── engine.py
└── helper.py
让我们依次讨论这些问题:
**Dockerfile**描述如何构建 Docker 容器映像。更多细节见下文。**build_and_push.sh**是一个脚本,它使用 docker 文件来构建你的容器图像,然后将其推送到 ECR。我们将在本笔记的后面直接调用这些命令,但是您可以复制并运行您自己算法的脚本。**mask_r_cnn**是包含将要安装到容器中的文件的目录。
在这个简单的应用程序中,我们只在容器中安装了五个文件。我们将放入容器的文件是:
**nginx.conf**是 nginx 前端的配置文件。通常,您应该能够照原样接受这个文件。**predictor.py**是实际实现 Flask web 服务器和该应用程序的决策树预测的程序。**serve**容器启动托管时程序是否启动。它只是启动 gunicorn 服务器,运行在predictor.py中定义的 Flask 应用程序的多个实例。您应该能够照原样接受这个文件。**train**是运行容器进行训练时调用的程序。**wsgi.py**是一个用来调用 Flask app 的小包装器。您应该能够照原样接受这个文件。
我们已经定制了train.py和predictor.py用于在训练期间微调掩码 R-CNN,以及用于加载调整后的模型、反序列化请求数据、进行预测和发送回序列化结果。
文档文件
Dockerfile 文件描述了我们想要构建的图像。我们将从一个标准的 Ubuntu 安装开始,运行普通的工具来安装所需的东西,比如 python、torch、torchvision 和 Pillow。最后,我们将实现特定算法的代码添加到容器中,并设置合适的运行环境。docker 文件如下所示,
FROM ubuntu:16.04MAINTAINER Amazon AI <sage-learner@amazon.com> RUN apt-get -y update && apt-get install -y --no-install-recommends \
wget \
gcc\
g++\
python3 \
python3-dev\
nginx \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* RUN wget [https://bootstrap.pypa.io/get-pip.py](https://bootstrap.pypa.io/get-pip.py) && python3 get-pip.py && \
pip install cython numpy==1.16.2 scipy==1.2.1 pandas flask gevent gunicorn && \
(cd /usr/local/lib/python3.5/dist-packages/scipy/.libs; rm *; ln ../../numpy/.libs/* .) && \
rm -rf /root/.cache
RUN pip install torch torchvision fastai thinc PillowENV PYTHONUNBUFFERED=TRUE
ENV PYTHONDONTWRITEBYTECODE=TRUE
ENV PATH="/opt/program:${PATH}"# Set up the program in the image
COPY mask_r_cnn /opt/program
WORKDIR /opt/program
使用 AWS Lambda 和 CodeBuild 构建您的映像
SageMaker 集装箱项目
为了构建 SageMaker-ready 容器,比如上面讨论的 Mask R-CNN,我们使用开源的“SageMaker 容器”项目,可以在 https://github.com/aws/sagemaker-containers这里找到。SageMaker Containers 为您提供了创建 SageMaker 兼容的 Docker 容器的工具,并提供了用于创建框架的附加工具(可以运行任意 Python 或 shell 脚本的 SageMaker 兼容的 Docker 容器)。目前,这个库被以下容器使用: TensorFlow 脚本模式、 MXNet 、 PyTorch 、 Chainer 和 Scikit-learn 。要创建 Sagemaker 兼容容器,我们需要以下组件:
- train.py 文件和您的培训代码,以及
- Dockerfile,如上图所示
训练脚本必须位于文件夹/opt/ml/code下,其相对路径在环境变量SAGEMAKER_PROGRAM中定义。支持以下脚本:
- Python 脚本:将 Python 解释器用于任何带有。py 后缀
- Shell 脚本:使用 Shell 解释器来执行任何其他脚本
当训练开始时,解释器执行上面例子中的入口点:
python train.py
关于超参数和环境变量的更多信息,请参考https://github.com/aws/sagemaker-containers#id10。
使用 Lambda 和 CodeBuild 自动化容器构建
我们将使用云形成模板来自动化我们的掩模 R-CNN 的容器构建。该模板建立了以下体系结构:

Lambda 函数包含可以内联编辑的 train.py 文件和 Dockerfile 文件。一旦触发(手动或通过下一节所示的阶跃函数方法),Lambda 函数:
- 创建一个 ECR 存储库(如果还不存在的话),用于存储构建后的容器映像
- 将 train.py 和 docker 文件上传到 S3 存储桶
- 创建一个 Codebuild 项目,并使用上述带有 buildspec.yml 的文件来启动构建容器的过程,将映像推送到 ECR。
Lambda 函数还包含有用的环境变量,可以针对新的构建进行重新配置。

使用 AWS Step 函数 Data Science SDK 训练和部署您的容器
一旦 Lambda 函数设置完毕,我们现在就可以构建自动化管道来训练和部署模型到端点。为此,我们将使用 AWS Step Functions,这是一个编排工具,它允许用户将状态机作为 JSON 对象创作并执行它们,而无需提供或管理任何服务器。Step Functions 现在还提供了一个数据科学 Python SDK,用于在熟悉的 Jupyter 笔记本环境中使用 Python 创作机器学习管道。我们建议读者参考 Github 存储库的 Step Functions 来开始[3]。
这里我们简单演示一下我们的 Github [2]中详细描述的管道的关键组件。为了编写代码,我们将使用 Amazon SageMaker,AWS 完全管理的机器学习平台。
与所有 AWS 服务一样,我们首先需要提供适当的 IAM 服务权限来调用其他 AWS 服务。为此,我们首先需要允许 Amazon SageMaker 调用 Step 函数 API,并允许 AWS Step 函数调用 SageMaker 进行模型训练、端点创建和部署。[3]中详细介绍了如何设置正确的 IAM 凭证。
一旦设置好,我们将首先创建一个 Lambda 状态来运行 Lambda 函数,该函数获取代码并将其作为容器部署到 ECR 中。
lambda_state = LambdaStep(
state_id="Calls CodeBuild to Build Container",
parameters={
"FunctionName": "Docker_Lambda", #replace with the name of the Lambda function you created
"Payload": {
"input": "HelloWorld"
}
}
)lambda_state.add_retry(Retry(
error_equals=["States.TaskFailed"],
interval_seconds=15,
max_attempts=2,
backoff_rate=4.0
))lambda_state.add_catch(Catch(
error_equals=["States.TaskFailed"],
next_step=Fail("LambdaTaskFailed")
))
这里添加了重试和捕获步骤,用于错误处理。您可以用您的自定义错误处理步骤来修改这些,但是如果 Lambda 函数未能部署容器,这将让步骤函数知道结束工作流。
接下来的步骤是将训练任务和来自已训练工件的模型创建链接在一起。幸运的是,Step Functions Data Science SDK 提供了将这些步骤链接在一起的逻辑和 API,以及可能需要的任何自定义分支逻辑。
train_step = TrainingStep('Train Step',
estimator=maskrcnn,
data=os.path.dirname(data_location),
job_name=execution_input['JobName'])model_step = ModelStep('Save model',
model=train_step.get_expected_model(),
model_name=execution_input['ModelName'])endpoint_config_step = EndpointConfigStep(
"Create Endpoint Config",
endpoint_config_name=execution_input['ModelName'],
model_name=execution_input['ModelName'],
initial_instance_count=1,
instance_type='ml.m5.large'
)endpoint_step = EndpointStep("Create Endpoint",
endpoint_name=execution_input['EndpointName'],
endpoint_config_name=execution_input['ModelName'])
在这里,我们使用我们的 mask-rcnn 估计器,它是一个通用的 SageMaker 估计器对象,允许我们指定我们想要在其上训练我们的模型的实例的类型,识别任何网络或安全设置(如果需要)和模型超参数,以及模型的输出路径。估计器的输入是由上面的 Lambda 函数创建的容器图像。
maskrcnn = sagemaker.estimator.Estimator(image,
role, 1, 'ml.p2.xlarge', #feel free to modify with your own. A cost estimate is provided in Readme.
output_path="s3://{}/{}/output".format(sess.default_bucket(), key),
sagemaker_session=sess)maskrcnn.set_hyperparameters(num_epochs = 1,
num_classes = 2)
通过使用 Chain 实用程序,我们可以将上述所有步骤串联起来,按顺序进行。然后,我们可以选择将整个工作流输出为 JSON,例如,可以在更大的云形成模板中使用,该模板还包括关于实例供应、网络安全设置等的信息。,或者自行运行。通过创建工作流和呈现图形,将在 Amazon Step Functions 控制台中创建一个状态机。
workflow_definition = Chain([
lambda_state,
train_step,
model_step,
endpoint_config_step,
endpoint_step
])# Next, we define the workflow
workflow = Workflow(
name="MyWorkflow-BYOC-MaskRCNN-{}".format(uuid.uuid1().hex),
definition=workflow_definition,
role=workflow_execution_role
)workflow.render_graph()
这将呈现以下输出:

这就完成了我们的步骤功能工作流程。我们现在可以直接在 Amazon SageMaker
中执行这个工作流,并使用 workflow.execute 和 workflow . render _ progress()API 或直接从 Step Functions 控制台检查进度。执行将被记录在 CloudWatch 中,并可用于在下游系统中向用户发送警报和通知。
借助 AWS Step Functions Data Science SDK,数据科学家和工程师可以无缝部署定制容器、训练 ML 模型并将其部署到生产中。为了将其他 AWS 大数据工具(如 EMR 和 AWS Glue)集成到 Step Functions 工作流中,我们建议读者参考[4,5]。
参考
[1] He,k .,Gkioxari,g .,Dollar,p .,Girshick,R .,Mask R-CNN,https://arxiv.org/abs/1703.06870.
【2】https://github . com/AWS-samples/AWS-step functions-byoc-mlops-using-data-science-SDK
【3】https://github . com/aw slats/Amazon-sagemaker-examples/tree/master/step-functions-data-science-SD
“拉平曲线”和“解除锁定”的简单建模
一个基本流行病学模型的简单 Python 脚本,用于演示社交距离的影响,以及如果封锁解除得太快会发生什么。

图片:(作者用 Pixabay 免费图片和编程制作)
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
介绍
新冠肺炎——自二战以来最大的全球性危机和自 1918-1919 年西班牙流感以来最大的全球性疫情今天降临在我们身上。每个人都在关注死亡人数的每日上升,以及这种新型病毒的快速指数传播。
数据科学家,像其他各行各业的许多人一样,也可能感到焦虑。他们可能也渴望看到自己是否能为抗击这种高传染性病原体做出贡献。

数据科学家和统计建模专业人员可以通过许多途径为这项事业做出贡献。在几乎所有情况下,他们都应该与领域专家密切合作——病毒学家、医疗保健专家、流行病学家。没有这种积极的合作和团队精神,开展预测性建模或预测疾病传播和缓解努力的项目是危险和无意义的。
正如广受欢迎的数据建模网站 Five-38 所言,制作一个准确的新冠肺炎模型异常困难。
我们在这里,在疫情的中间,像观赏鱼一样盯着我们起居室的窗户。关于…的问题
fivethirtyeight.com](https://fivethirtyeight.com/features/why-its-so-freaking-hard-to-make-a-good-covid-19-model/)
然而,即使不冒险进入实际的预测模型,也有可能通过一种简单的编程方法来展示我们所有人对抗新冠肺炎病毒的唯一基本武器——“T4”社交距离 ”的功效。

来源: Pixabay(免费商业使用)
在本文中,我们将展示如何用 Python 构建这样一个演示,遵循简单而基本的流行病学理论。
这并不是试图建立任何预测或预测模型。除了一些虚构的数字之外,没有实际的数据将用于生成图表和可视化。
目标是展示仅用一个基本的动力学模型,就有可能理解关键概念,例如“使曲线变平”、“群体免疫”和“过快解除封锁”。并且,你可以用基本的 Python 和数学知识编写这样一个模型。
然而,即使不冒险进入实际的预测模型,也有可能通过简单的编程方法来展示我们所有人对抗新冠肺炎病毒的唯一基本武器——“社交距离”的功效。
(流行病学)模型和 Python 类
我们基于基础流行病学的 SEIR 模型创建了一个叫做SEIRclass的 Python 类。该脚本在 my Github repo 中的SEIRclass.py文件中,该类需要为该演示导入。
SEIR 模式
SEIR 模型将全部人口分为四组,
- 易感 :从未被感染过且尚未产生任何免疫力的人群。
- :接触过病毒但没有表现出任何症状或不能被称为“感染者”的人。病毒正处于 潜伏期 。
- 已感染 :处于活跃感染状态的人口比例,表现为轻度或重度症状,可能需要住院治疗。这是对 医疗能力规划 最重要的类别,几乎所有的 死亡事故 都将来自这一人群。
- 收复 :噩梦彼岸的乡亲们!那些被感染并从中康复的人。请注意,在这个简单的模型中,这些人被假定具有“永久免疫力,即他们不会再次落入易感或受感染人群。

来源:维基百科(知识共享许可)
参考文章
这个想法是受这篇文章的启发,这篇文章清楚地阐述了流行病学模型和动力学方程: 社会距离减缓冠状病毒 。
模拟新冠肺炎峰的变平
towardsdatascience.com](/social-distancing-to-slow-the-coronavirus-768292f04296)
下面是上面文章对应的 Github 回购:https://github.com/dgoldman0/socialdistancing。
动力学方程
几乎所有传染病传播的分室模型在本质上都是动态的,即它们由一组以时间为自变量的一阶/二阶微分方程描述。基本的动力学方程如下,


需要注意的是,著名再现数 R0 是这个模型的β和γ之比。
所有系数(α、β、γ等。)在这里被假定为常数。实际上,病原体的传染性可能会随着时间的推移而变化。
随着第四个参数 𝜌 的引入,前两个方程略有变化,第四个参数代表社会混合。𝜌越高,社交距离就越小。它的值可以从 0 到 1。

这里有两篇文章展示了如何使用 Python 编程来数值求解这样的动态方程组。
[## Python 中的动态模拟
表示微分方程的三种方法是(1)传递函数,(2)状态空间,和(3)半显式…
apmonitor.com](https://apmonitor.com/pdc/index.php/Main/ModelSimulation) [## 用 Python 模拟动态系统的初学者指南
Python 中数字积分微分方程
towardsdatascience.com](/a-beginners-guide-to-simulating-dynamical-systems-with-python-a29bc27ad9b1)
核心 Python 类
分部类定义如下所示。一个测试 Jupyter 的笔记本可以在这里找到。模型类在这里是。它们是在 MIT 许可下发布的,因此,我们鼓励您下载并使用它,通过添加其他有用的方法来增强它,等等。****

各种方法
我们在这个类中定义了各种实用方法,
reinitialize:用新值(总体值)重新初始化模型set_params:设定动态参数的值reset:将内部列表重置为零状态,即初始值run:运行给定时间量的动力学模拟(具有给定的时间步长增量)plot:在时间轴上绘制模拟的基本结果
简单的演示
动态模拟和绘图
我们从导入类并创建一个对象作为实例开始。

然后,我们可以运行一段时间的动态模拟——比如 90 个时间单位。这可以被认为是 90 天或任何其他长度的时间。

我们可以简单地绘制出这个模拟的结果,
********
图片:SEIR 模型的代表性模拟结果(作者制作)。
拉平曲线——社交距离如何影响峰值
接下来,我们对各种社会距离因素进行模拟,以检查它们对曲线峰值的影响。请注意,这里的值越高意味着社交距离越小,即社交混合/互动越多。
我们观察到更高程度的社会融合会导致感染人口比例达到更高的峰值,这可能会超出医疗保健系统的能力。

图片:社会距离因素对感染比例峰值的影响(作者制作)。
调整社交距离——提前结束封锁
现在,我们研究提前终止封锁或“留在家中”措施会发生什么,这些措施旨在减少社会交往,即增加社会距离。
我们从社会距离因子的某个值开始,让它运行一段时间,然后放松规范,即增加社会距离因子的值,并观察感染人口比例会发生什么。我们将观察到第二个峰值出现。根据各种社会和流行病学因素,第二个峰值可能高于第一个峰值。
在这项研究中,我们将使用两个 SEIR 模型,
- 第一个模型将在低社交混合因子(严格的社交距离规范)下运行一段时间
- 该模型得出的人口比例最终值将输入第二个模型。
- 第二个模型将运行一个更高的社会混合值(宽松的社会距离标准)

图片:提前终止封锁会导致第二个高峰吗?(作者制作)
优化锁定期可以减少所有峰值
在“呆在家里”的规定结束和社会距离标准有所放松后,不可避免地会出现另一个感染病例高峰。问题是,这一比例会有多高,以及更长时间的封锁能否在某种程度上抑制这一趋势。
通过这个简单的模型,我们可以观察到,让第一次“锁定”运行很长时间可能会降低两个峰值的绝对值——一个在锁定期间,另一个在锁定结束后不可避免地出现。
这是由于增强的 【群体免疫】 即的影响,随着封锁时间的延长,易感人群随着时间的推移逐渐缓慢减少(没有产生尖峰)。因此,当封锁放松时,病毒感染的易感人群就减少了!
我们还注意到,超过 150 天后,易感分数水平不会显著下降,即从 150 天的情况到 180 天的情况再到 210 天的情况,没有明显的下降。因此,如果目标是建立群体免疫,锁定扩展可能仅在特定时期内有效。

图片:随着封锁期的延长,易受影响的比例下降(作者制作)
上面“调整社交距离”的例子显示了高达> 0.05 的第二个峰值,即 5%的人口被感染。这里,我们展示了让第一次锁定运行更长时间可能会减少两个峰值。事实上,我们在该实验中看到第一个峰值更高,仅为 0.018 或 1.8%左右。
当然,这种情况取决于初始感染率、疾病参数和社会动态。这只是我们的计划可以强调的一个可能的结果。

图片:更长时间的封锁可能有助于整体降低峰值(作者制作)
这是一个演示,而不是新冠肺炎的实际模型
同样,这项工作是为了展示如何使用一个简单的 Python 脚本来编程一个广泛使用的流行病学动态模型。
一旦建立了这样一个程序化的模型,许多流行的短语,如'使曲线变平'、群体免疫'和'从锁定的早期结束起的尖峰可以通过玩模型参数和模拟设置来测量。****
目标是展示仅用一个基本的动力学模型,就有可能理解关键概念,例如“使曲线变平”、“群体免疫”和“过快解除锁定”。而且,您可以用基本的 Python 和数学知识编写这样一个模型。****
这个模型非常简化。没有地理空间互动 n,这是采用图论算法的最先进的传染病模型的核心。
该模型没有任何统计估计,这是估计参数(α、β、γ等)的核心。)来运行真实的模拟。
所以,请不要把这个模型当成与当前新冠肺炎局势发展相关的实际数据和预测有任何关联。有许多优秀的资源可供参考。
当尼尔·弗格森参观位于伦敦唐宁街的英国政府中心时,他更接近于…
www.nature.com](https://www.nature.com/articles/d41586-020-01003-6)
然而,即使这样一个简单的编程方法也足够强大,可以创建关键的可视化效果,将“呆在家里”和“曲线变平”的信息传递给家庭。
这里有一篇很棒(但是很长)的可播放的 JavaScript 动画,
“唯一值得恐惧的是恐惧本身”是个愚蠢的建议。当然,不要囤积卫生纸——但如果政策制定者担心…
ncase.me](https://ncase.me/covid-19/)
再次,一个测试 Jupyter 的笔记本可以在这里 找到 。模型类在这里是。它们是在 MIT 许可下发布的,因此,我们鼓励你下载并使用它。****
注意安全,各位!
作者注 : 我是一名半导体工艺师,有兴趣将数据科学和机器学习应用于与我领域相关的各种问题。我没有医学、分子生物学、流行病学或任何与新冠肺炎相关的专业知识。请不要给我发这种问题的邮件。
A lso,你可以查看作者的 GitHub 知识库获取机器学习和数据科学方面的代码、思想和资源。如果你和我一样,对人工智能/机器学习/数据科学充满热情,请随时在 LinkedIn 上添加我或在 Twitter 上关注我。
** [## Tirthajyoti Sarkar - Sr .首席工程师-半导体、人工智能、机器学习- ON…
通过写作使数据科学/ML 概念易于理解:https://medium.com/@tirthajyoti 开源和有趣…
www.linkedin.com](https://www.linkedin.com/in/tirthajyoti-sarkar-2127aa7/)*******
Python 中的简单莫尔斯码解码器

作者 Rhey t . Snodgrass&Victor f . Camp,1922 — Image:Intcode.png 和 Image:国际莫尔斯 code.png,公共领域,https://commons.wikimedia.org/w/index.php?curid=3902977
莫尔斯电码是一种用于电信的方法,其中每个字母、数字和标点符号由一系列点/破折号/空格表示。它是由塞缪尔·莫尔斯在 20 世纪 30 年代首先发明的,并且已经在海军工业中大量使用。本文将描述用 Python 构建一个简单的莫尔斯码解码器的过程。
Python 中的莫尔斯码表示
如上图所示,每个字母和数字都由一系列点和破折号表示。我们可以在 Python 中这样表示它们,但是为了更清楚,让我们将它们翻译成‘0’和‘1’,其中‘0’表示点,而‘1’表示破折号。
character = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9']code = ['01','1000','1010','100','0','0010','110','0000','00','0111','101','0100','11','10','111','0110','1101','010','000','1','001','0001','011','1001','1011','1100','11111','01111','00111','00011','00001','00000','10000','11000','11100','11110']
由于每个字符(即一个字母或数字)对应一系列 0 和 1,我们将使用一个字典结构在 Python 中存储它们。你可以在这里参考我之前关于用 Python 构建字典数据结构的帖子。
# Define an empty dictionary 'morse_dict'
morse_dict = {}# Convert the 2 lists into a dictionary using a tuple
zipped_char_code = zip(character, code)
morse_dict = dict(zipped_char_code)# Print the dictionary 'morse_dict' on the terminal line by line
for key, value in morse_dict.items():
print(key, value)

作者图片-包含莫尔斯电码表示的字典的 Python 输出
建造莫尔斯电码解码器
莫尔斯解码器的构建方式是,我们将提示用户键入莫尔斯码表示(即 0 和 1),每个字母或数字由一个 ***** 分隔。一旦用户按下“回车”,程序将解码莫尔斯电码并以字母数字的形式显示出来。
# reverse the previous dict as it's easier to access the keys
zipped_code_char = zip(code,character)
rev_morse_dict = dict(list(zipped_code_char))
# initiating a while loop
while True:
# empty list to store original message
ori_msg = []
# empty list to store decoded message
dec_msg = []
# prompt the user to input morse code
input_msg = input ("Please enter any Morse Code sequence for decoding. Leave blank to quit. ")
# append input_msg (string) to ori_msg (string)
ori_msg.append(input_msg)
# split each morse code by '*'
new_msg = input_msg.split("*")
# printing out the original message
for line in ori_msg: # to print original message without the []
print("Original message: " + line + "\n")
# loop through each morse code representation
for j in range (0,len(new_msg)):
# get the alphanumeric alphabet based on the dict keys and append to dec_msg
if new_msg[j] in rev_morse_dict.keys():
dec_msg.append(rev_morse_dict[new_msg[j]])
# printing out the decoded message
print ("Decoded Message is: " + ''.join(dec_msg) + "\n") # end the infinite while loop
break

图片作者——莫尔斯电码解码器的 Python 输出
正如在程序输出中看到的,莫尔斯电码解码器能够将莫尔斯电码解码为 MYNAMEISKIERAN。
错误检查

图片由作者提供——带“abc”输入的莫尔斯电码解码器的 Python 输出
到目前为止,我们只实现了一个简单的莫尔斯电码解码器,它只能在用户只输入莫尔斯电码表示(即 0 和 1)的情况下解码。如截图所示,如果用户输入' abc ',解码器将无法解码剩余的莫尔斯电码,也不会显示任何错误信息。让我们改进我们的解码器,进行以下简单的错误检查:
- 用户只能输入 0、1 和*
- 用户只能输入预先定义的莫尔斯电码表示法(例如 0000000 不是有效的表示法)
- 程序可以继续解码莫尔斯电码,直到用户指定退出
# counter to do error check
i = 0
# proceed if user enters something
if (len(input_msg)!=0):
# while loop to check if only 0, 1 or * has been keyed in
while (i<len(input_msg)):
if input_msg[i] == "0" or input_msg[i] == "1" or input_msg[i] == "*":
i+=1
else:
# if invalid chars found, print error message
print ("Error input, Morse Code sequence should only consists of 0 and 1, with a * between subsequence")
# break the error check once one error has been found
break
我们添加上面的代码来纠正第一个无效字符的问题,如下面的屏幕截图所示,现在会向用户显示一条无效字符的错误消息。

作者图片——带“abc”输入的新型莫尔斯电码解码器的 Python 输出
# loop through each morse code representation
for j in range (0,len(new_msg)):
# get the alphanumeric alphabet based on the dict keys and append to dec_msg
if new_msg[j] in rev_morse_dict.keys():
dec_msg.append(rev_morse_dict[new_msg[j]])
# if morse code representation not found in original list, append input to err_msg
else:
err_msg.append(new_msg[j])
# to print error message only when necessary
if len(err_msg) != 0:
for line in err_msg:
print(line + " has no known morse translation")
我们添加上面的代码来纠正在预定义列表中找不到的无效莫尔斯码表示的第二个问题。新程序现在将向用户显示一条错误消息,如下所示,同时对那些有效的消息进行解码。

图片由作者提供-新莫尔斯电码解码器的 Python 输出,带有无效的莫尔斯电码输入
最后,如前所述,我们将使我们的程序有能力继续解码莫尔斯电码表示,如果用户继续输入,只有当用户选择退出时才停止。

作者图片—新莫尔斯电码解码器的 Python 输出
限制
这个程序的第一个限制是,如果用户想键入句子,程序将无法识别。从程序的输出中可以看出,字母数字被解码,中间没有任何空格。当然,有一些方法可以改进这一点,比如指定用户键入“***”作为空格。
第二个限制是,我们没有在这个莫尔斯电码解码器中加入标点符号,因为它对这个程序的目的来说并不重要。由于标点符号也是由点和破折号组成的,我们可以简单地扩展预定义的莫尔斯电码表示来包含标点符号。
摘要
本文描述了构建一个莫尔斯码解码器的过程,该解码器能够接受用户输入,并以原始的字母数字形式输出。此外,我们在程序中实现了几个错误检查功能,以确保莫尔斯电码解码器按照预期的方式工作。希望你们喜欢这篇文章,并开始建立自己的莫尔斯码解码器的乐趣!干杯!
带宇宙魔方的简单 OCR
如何训练宇宙魔方阅读你独特的字体

在本文中,我想与您分享如何使用 Tesseract 构建一个简单的 OCR,“一个用于各种操作系统的光学字符识别引擎”。宇宙魔方本身是自由软件,最初由惠普开发,直到 2006 年谷歌接手开发。它可以说是迄今为止最好的开箱即用的 OCR 引擎,支持 100 多种语言。这是最受欢迎的 OCR 引擎之一,因为它易于安装和使用。
现在,假设你的老板给了你一个任务,让你能够将下面的图片转换成机器语言,或者用更简单的话来说,“建立一个 OCR 模型,以便能够阅读一些图片中的这些字体!”。“好的,没问题,”你说,但突然你的主管对你说“我要你今天完成,在接下来的 3-5 个小时内。”

例如,我们将这张图片命名为 file_0.png
" Welp,我怎么能这么快地建立一个 OCR 模型?"你对自己说。但是别担心,这就是宇宙魔方的作用!首先,你必须把它安装在你的电脑上。
- 如果你用的是 Windows 操作系统,去https://github.com/UB-Mannheim/tesseract/wiki用安装程序安装宇宙魔方(你可以选择最新的稳定版本,或者我用的是宇宙魔方 4.0.0)。按照说明操作。然后,进入编辑环境变量,添加一个新路径到你的宇宙魔方安装文件夹,如下图所示





然后点击“确定”
- 如果使用 Ubuntu OS,那么打开终端,运行
sudo apt-get install tesserac t-ocr
在你的电脑上成功安装了宇宙魔方之后,打开命令提示符对于 windows 或者终端如果你使用的是 Ubuntu,然后运行:
tesseract file_0.png stdout
其中file _ 0 . png是上图的文件名。我们希望宇宙魔方读取它在上面的图像中找到的任何单词。您应该在终端中看到这些输出:
Warning. Invalid resolution 0 dpi. Using 70 instead.
Estimating resolution as 147
40293847 S565647386e2e91L0
哦不!看起来宇宙魔方不能完美地阅读上图中的文字。似乎它误读了一些字符,可能是因为图像中的字体独特而奇怪。幸运的是,你可以训练你的宇宙魔方,让它可以很容易地阅读你的字体。跟着我的脚步走!
免责声明,正如 Tesseract 的 wiki 中所述,建议使用默认的“语言”,这种语言已经在 tesseract 的许多数据上进行了训练,并在最后关头训练您自己的语言(这意味着,您应该在跳转到训练之前尝试预处理图像、阈值处理和其他图像预处理方法)。这是因为宇宙魔方本身在一般干净的图像上相当准确,并且很难使宇宙魔方的训练预测更准确,除非你的字体非常不同和独特(就像在我们的例子中),或者如果你试图阅读一些恶魔的语言。
安装和数据准备
要训练您的字体,首先,您需要:
-
安装宇宙魔方(你不说)
-
安装 jTessBoxEditor 这个工具用于创建和编辑地面真相来训练宇宙魔方。请注意,您需要 Java 运行时才能打开它,您可以下载https://www.java.com/en/download/。安装 Java 之后再在 上安装 jTessBoxEditor (不是 FX 的)https://SourceForge . net/projects/vietocr/files/jTessBoxEditor/ 解压 zip 文件就可以打开 jTessBoxEditor,运行 train.bat 如果你用的是 Windows,或者
-
[ 可选的 ]一个工作 Word Office (Windows)或 LibreOffice (Ubuntu)和。您的字体的 tiff 文件。例如在上面的例子中,我使用的是OCR——一种扩展的字体。你可以很容易地从谷歌上下载你的字体(只需搜索 font_name。tiff 下载)。安装您的字体(只需双击。tiff 文件)或者,您最好有一个图像集合,以便以后作为训练数据进行预测。
在你准备好上面所有的安装步骤后,你就可以训练你的魔方了。Tesseract 使用“语言作为其 OCR 模型。有很多默认语言,像 eng (英语)、 ind (印尼语)等等。我们试图创造一种新的语言,让宇宙魔方能够预测我们的字体,通过使用我们的字体创建一些由随机数组成的训练数据。有两种方法可以做到这一点。首先,如果你有一个仅由你的字体组成的图像集合,那么你可以使用这种方法,或者第二种方法,即使用你的字体在 word 上键入任何你想要的数字(或字符),并使用剪切工具(windows)或 shift 键+ PrintScreen (Ubuntu)来捕获并将其保存在一个文件夹中。

训练数据示例

训练数据示例

训练数据示例

多行的训练数据示例
根据我的经验,10–15 个数据足以产生一个准确的(主观)模型,对于干净和一些有噪声的图像都足够准确。请注意,您应该尝试创建尽可能平衡的数据,并尽可能接近真实案例。如果您想要预测一些蓝色背景、红色字体的图像,那么您应该创建蓝色背景、红色字体的训练数据。
训练宇宙魔方
一般来说,宇宙魔方的训练步骤是:
- 将培训数据合并到。使用 jTessBoxEditor 的 tiff 文件
- 通过创建一个. box 文件来创建一个训练标签,该文件包含来自。tiff 文件并修正每个不准确的预测
- 训练宇宙魔方
第一步。合并培训数据
创建完一些数据后,打开 jTessBoxEditor。 在顶栏,进入“工具”→“合并 Tiff”(或者你也可以只使用快捷键 Ctrl + M )。转到保存训练图像的文件夹。将过滤器更改为 PNG(或您的图像的任何扩展名),选择所有图像,然后单击“确定”。然后在选择面板中,键入 font_name.font.exp0 ,其中 font_name 是您想要的任何名称(这将是您自己的新宇宙魔方语言的名称)。
第二步。创建培训标签
打开“终端”,导航到存储训练图像的文件夹,然后。tiff 文件。既然我们现在有了训练数据,我们如何得到训练标签呢?恐怕不行,您不应该手动标记每个图像,因为我们可以使用 Tesseract 和 jTessBoxEditor 来帮助我们。在终端中,运行以下命令:
tesseract --psm 6 --oem 3 *font_name.font.exp0.tif font_name.font.exp0 makebox*
等等,为什么突然有了 psm 和 oem?当我键入上面的命令时会发生什么?如果你跑步:
tesseract --help-psm
#or
tesseract --help-oem
您将会看到 psm 表示页面分段模式,即宇宙魔方如何处理图像。如果你想让宇宙魔方把它看到的每张图片都当作一个单词,你可以选择 psm 8。在我们的例子中。tiff 文件是单行文本的集合,我们选择 psm 6。至于 OEM,这意味着 Ocr 引擎模式,至于 tesseract,有通过识别字符模式工作的传统引擎,或者使用神经网络和 LTSM 引擎(如果您想使用 LTSM,请安装 tesseract 版本> 4.0.0)。
使用上面的命令,我们希望 tesseract 生成边界框和。tiff 文件,并将其保存到 font_name.font.exp0.box 文本文件中。如果您不知道,我们之前制作的. tiff 文件包含您的按“页面”划分的训练图像。通过使用上面的命令,它将生成一个包含预测的. box 文件,以及。tiff 文件。名为 font_name.font.exp0.box
现在打开 jTessBoxEditor,导航到“框编辑器”选项卡,单击“打开”并选择。tiff 文件。您应该看到每个页面上的每个图像都有其边界框和预测。您现在的工作是修复每个边界框及其在。盒子文件。(没错,这是最无聊的部分)
第三步。训练宇宙魔方
创建了已经修复的。箱文件和。tiff 文件。创建包含以下内容的新文本文档
font 0 0 0 0 0
将其作为 font_properties 保存到与。tiff 文件和。盒子文件。现在你已经准备好开始训练了!(终于)。在该文件夹中,您应该有所有这些文件:

现在在终端上运行以下命令:
# Create a .tr file (training file)
tesseract num.font.exp0.tif font_name.font.exp0 nobatch box.train# Create a unicharset file
unicharset_extractor font_name.font.exp0.box# Create a shapetable file
shapeclustering -F font_properties -U unicharset -O font_name.unicharset font_name.font.exp0.tr# Create a pffmtable, intemp file
mftraining -F font_properties -U unicharset -O font_name.unicharset font_name.font.exp0.trecho Clustering..# Create a normproto file
cntraining font_name.font.exp0.tr
如果遇到错误,您可能需要使用 extractor.exe、unicharset_extractor.exe 和 cntraining.exe(对于 windows 用户)。您将在终端中看到一些输出,最重要的是在 shapeclustering 部分。如果您的训练图像包含所有必要的字符,您将看到形状的数量= {您想要的类的数量}。例如,如果我想训练宇宙魔方能够正确读取数字,那么形状的数量等于 10(即 0,1,2,3,…,9)。
Master shape_table:Number of shapes = 10 max unichars = 1 number with multiple unichars = 0
如果您的形状数不等于您想要的类数,您应该返回创建训练数据,并尝试创建更清晰的数据
如果你做的一切都是正确的,你会在你的文件夹中看到 4 个主要文件。shapetable、normproto、intemp 和 pffmtable。将这些文件重命名为 font_name.shapetable,font_name.normproto,font_name.intemp,font_name.pffmtable.

然后运行:
combine_tessdata font_name.
运行完上面的所有命令后,您会在文件夹中看到这些文件

现在将font _ name . trained data复制到:
C:/Program Files x86/tesseract/4.0/tessdata # Windowssudo cp /usr/shared/tesseract/4.0/tessdata # ubuntu
你完了!是的,因为我们使用少量的数据,训练本身不需要几个小时,只需要几秒钟或者几分钟。与如果你必须从头开始训练一个深度学习模型(可能使用对象检测模型)相比,这要快得多。现在,下次运行 Tesseract 时,可以使用
tesseract -l font_name file0.png
记得之前用默认语言,上图用默认 Tesseract 引擎的结果是 40293847 S565647386e2e91L0。使用我们新训练的语言,结果是
Warning. Invalid resolution 0 dpi. Using 70 instead.
Estimating resolution as 147
10293847 565647382910
如你所见,结果更加准确。耶!仅用少量训练数据和相对较短的时间,您就创建了一个能够读取独特和奇怪字体的 OCR 模型!
为了进一步检查模型的结果,您可以创建另一个。通过使用另一个图像或使用以前的。tiff 文件。打开终端,再次运行:
tesseract -l font_name --psm 6 --oem 3 *font_name.font.exp0.tif font_name.font.exp0 makebox*
现在打开 jTessBoxEditor → 框编辑器→打开并选择你的。tiff 文件。检查一下你的模型是否比前一个模型给出了更准确的预测。你应该看到预测提高了很多。
最后的想法
"但是如果你想要一个现成的快速 OCR 引擎,宇宙魔方是唯一的选择吗?"你可能会问。当然不是,如果你愿意拿出一些钱,有很多 OCR API 提供者。在我看来,如果您的图像非常干净(例如,一个 word 文档、一张收银单等等), Tesseract 是很好的。如果您的图像数据包含许多噪声,您可以使用阈值来区分背景和噪声与字体本身。根据我的经验,使用少至 10-20 个数据,Tesseract 甚至能够与最先进的对象检测模型竞争,如使用更多数据训练的更快的 R-CNN(也有很多增强)。但是,如果你的图像数据有一些噪声(随机点,脏标记)与你的字体颜色相同,宇宙魔方将无法正确预测你的图像。我说如果你想尽快建立 OCR 模型,或者你的训练数据有限,你应该使用宇宙魔方。
宇宙魔方的一个主要弱点(我认为)是它很不稳定。我可以通过使用相同图像的更大裁剪来得到不同的结果。同样出于某种原因,如果我使用超过 50 个数据,那么宇宙魔方的性能会更差。嗯,我自己也还在学习。如果你在这篇文章中发现一些错误或误解,请随时联系我。感谢阅读,快乐学习!
参考文献:
这个包包含一个 OCR 引擎——libtesserac t 和一个命令行程序——tesserac t。宇宙魔方 4 增加了一个新的…
github.com](https://github.com/tesseract-ocr/tesseract) [## nguyenq/jTessBoxEditor
Tesseract OCR 的框编辑器和训练器,提供 Tesseract 2.0x 和 3.0x 格式的框数据编辑和…
github.com](https://github.com/nguyenq/jTessBoxEditor) [## 在 windows 10 上训练您的宇宙魔方
Tesseract 是由谷歌实验室开发并由谷歌维护的开源 OCR(光学字符识别)引擎…
medium.com](https://medium.com/@gaopengbai0121/training-your-tesseract-on-windows-10-df6756946d4f) [## tesserac-ocr/Tess doc
宇宙魔方文档。在 GitHub 上创建一个帐户,为 tesseract-ocr/tessdoc 开发做出贡献。
github.com](https://github.com/tesseract-ocr/tessdoc) [## Tesseract-OCR 如何与 Python 协同工作?
这篇文章指导你使用 Tesseract OCR、OpenCV 和 Python 从图像中识别字符。
medium.com](https://medium.com/@latifvardar/how-does-tesseract-ocr-work-with-python-a6bccf85a002) [## 宇宙魔方 OCR 初学者指南
基于 Tesseract 和 Python 的光学字符识别
medium.com](https://medium.com/better-programming/beginners-guide-to-tesseract-ocr-using-python-10ecbb426c3d) [## [教程 Python 中的 OCR 与 Tesseract、OpenCV 和 Pytesseract
光学字符识别。换句话说,OCR 系统转换文本的二维图像,可以…
简单的实时竞价游戏
使用 Pytorch 和一些真实数据一瞥在线广告的实时竞价机制。

照片由基里尔·沙尔科夫斯基在 Unsplash 上拍摄
我们都会在各种网站、社交媒体平台、视频流媒体服务等上看到广告。对于不同的人来说,它们通常是不同的。这是因为网站提供的是广告空间。然后是对空间的竞价,胜出的广告显示在那个位置。无需深入细节,要更好地了解这一过程,请查看这篇文章:
实时竞价指的是在线拍卖过程,其中在线广告投放的购买和出售是在…
medium.com](https://medium.com/@greedy_game/ad-tech-simplified-what-is-real-time-bidding-rtb-8ee9754c3ab8)
我们将构建一个简单的类似游戏的环境,向用户展示广告,不同的投标人试图优化投标价格。这只是一个例子,实际过程很复杂。我们将使用一个简单的神经网络来评估出价。因此,让我们深入一些编码。
种子数据
虽然整个过程是可生成的,但我们将使用一些种子数据以合理的方式进行初始化。我们将使用 Avazu CTR 预测数据集。可以从这里下载。
没有访问网站的唯一用户的明确数据。因此,我们使用(“设备 id”、“设备型号”)来区分各个用户。
在将数据用于游戏之前,我们将首先分析数据,以了解一些简单的趋势。最近的实证研究表明,在线广告的效果不能被 CTR 或 CR 完全捕捉到。观众通常不会在获得广告印象后立即点击广告(当用户看到一个广告时,它被称为该广告的印象)。他们往往是在抓取多了,对同一个广告的印象多了之后才点击的。
为了捕捉特定广告的这一点(由数据中的“site_id”定义),我们获取所有获得其印象的用户的数据。然后,对于每个用户,我们找出在点击广告之前走过的距离(访问过的网站)以及在此期间用户获得了多少广告印象。

图片由叶琳琳·莫迪
我们绘制了频率对距离图,其中频率是(印象数)/距离。我们可以看到频率随着距离的增加而降低。
创造环境
在我们的例子中,每个用户都拥有每个广告的点击数和浏览量的向量。它还必须在用户查看和点击时更新这些向量。用户还必须根据观看和点击来决定是否点击所显示的广告。
根据视图和点击量,用户可以使用 toss()生成 0-1 点击向量。每当特定用户被展示广告时,为该用户生成“点击”向量。如果赢得投标的广告的“点击”向量是“1”,则假定用户点击了所示的广告。
现在我们需要设置投标人。每个投标人被分配一组广告,每个广告由单个整数标识。
“投标模型”是一种简单的神经网络模型,其作用类似于投标的估计器。每个投标人都有自己的奖励,目标是使其最大化。为此,在“反向预测”函数中,我们将正确的预测定义为奖励和模型的预测点击概率的函数。我们还添加了一些随机事件,以允许模型探索其他可能性。
最后,我们需要一个生成器来创建一个环境,在这个环境中,用户被给予一个位置,投标人投标来赢得这个位置。
把东西放在一起
最终的笔记本会是这样的。在示例笔记本中,使用了 avazu 数据集的精简版本。
结束语
自从 1980 年在线广告开始以来,它已经经历了许多发展,并且人们不断尝试显示相关的广告。这个游戏只是这个领域大量研究的一小部分。
本文由 Akhilesh Ravi 和 Kaushal Modi 联合制作。这是我们数据科学课程项目的一部分。
参考
- 李,K. C .,贾拉里,a .,&达斯丹,A. (2013 年 8 月)。在线广告中具有平滑预算交付的实时出价优化。在第七届在线广告数据挖掘国际研讨会论文集(第 1-9 页)。
- m .比连科和 m .理查森(2011 年 8 月)。个性化广告的预测客户端配置文件。第 17 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集(第 413–421 页)。
- 蔡海红,任,张,马利亚斯,王,于,郭,(2017 年 2 月)。展示广告中基于强化学习的实时竞价。第十届 ACM 网络搜索和数据挖掘国际会议论文集(第 661-670 页)。
- 阿尔查克,n .,米尔洛克尼,V. S .,& Muthukrishnan,S. (2010 年 4 月)。使用 adfactors 挖掘特定广告客户的用户行为。在第 19 届万维网国际会议记录(第 31-40 页)。
下一代测序中 mRNA 的简单重建
使用 NGS 数据重建二型糖尿病患者和非患者的前胰岛素原 mRNA。

图片由来自 Pixabay 的 Arek Socha 提供
P 个性化/精准医疗:根据患者独特的基因构成开出药物处方的能力。这个概念一直是许多医疗从业者的目标,随着下一代测序(NGS)的进展,个性化医疗有望很快从概念过渡到实践。
世界各地的科学界继续在人类基因组和遗传疾病之间取得新的发现。因此,科学家现在已经产生了比以往任何时候都多的数据,可能为研究人员提供更多证据来联系遗传和疾病之间的关系。
通过利用 RNA-seq 的基因测序数据,一种通过对提取的 m RNA 分子(转录组)进行测序来检查细胞产生的大多数蛋白质的 NGS 方法,我能够重建 10 个不同个体的前胰岛素原的 mRNA 和蛋白质序列,其中 4 个被诊断为二型糖尿病(T2D)。
虽然我检查了前胰岛素原的 mRNA,但读者只需要知道胰岛素是一个复杂的生物过程的最终产物,其中前胰岛素原是这个过程的开始。此外,DNA 被用来制造 mRNA,而 mRNA 可以用来制造蛋白质。
步骤 1:获得 NGS 数据和参考基因序列
为了开始这项研究,我从瑞典斯德哥尔摩卡罗林斯卡学院桑德伯格实验室的研究人员那里获得了提交给欧洲生物信息研究所的 RNA-seq 数据。(该数据用于 2016 年出版的细胞。)
接下来,我从 NCBI获得了所有 4 种已知的前胰岛素原 mRNA 序列变体。这些遗传序列被认为是在大多数个体中发现的正常/野生型序列,并将作为与 RNA-seq 数据进行比较的参考序列。

NCBI,4 种前胰岛素原变体:浅绿色矩形是编码 mRNA 的外显子,而(重叠的)深绿色矩形是蛋白质编码区。从顶部开始,变量依次为 1、2、4 和 3。当匹配/比对来自 RNA-seq 数据的序列时,使用变体 3,因为 mRNA 编码区(浅绿色)覆盖所有其他变体,并且前胰岛素原蛋白序列对于所有变体都是相同的。
步骤 2:用 Biopython 加载和排列基因序列
精彩的 Biopython 套装让接下来的步骤变得简单了!只需加载数据并将 RNA-seq 数据与参考序列进行比对。然后我把所有的比赛记录在熊猫的数据框里。
**# Load FASTQ File(s):**
fastq = SeqIO.parse('RNA-Seq\\' + file, "fastq")**# Local Alignment of Sequences:**
for seq_record in fastq:
seq = str(seq_record.seq)matches = pairwise2.align.localms(variant_3, seq, 1, -1, -99, -99)**# The numeric arguments of localms() determine the score for each
# "match". I set my score requirement to 35+ since all sequences are
# 43 nucleotide long. Also, I did not considered matches that
# changed the reference sequence.**
虽然在 RNA-seq 数据中读取的每个核苷酸序列都与测序质量值(FASTQ)相关,但在这种情况下并不相关,因为有大量的比对匹配,其中异常值不会对 mRNA 重建产生任何影响。
步骤 3:重建前胰岛素原 mRNA 变体
一旦所有的测序数据都被扫描匹配,我计数所有测序的核苷酸,并提取每个位置最常见的核苷酸,以重建前胰岛素原 mRNA 序列。
**# Counting Matched Nucleotides:** count_df = pd.DataFrame(columns= list(range(0, 644)), index= ['A', 'T', 'G', 'C'])**# Getting the columns/nucleotide positions of the DataFrame with the mRNA sequence matches (match_df).
# The len() function will count how many of nucleotides matched in each position and works around needing to change NaN values.** for position in match_df.columns: A_count = len(count_df[count_df[position] == 'A'])
T_count = len(count_df[count_df[position] == 'T'])
G_count = len(count_df[count_df[position] == 'G'])
C_count = len(count_df[count_df[position] == 'C']) count_df.loc['A', int(position)] = A_count
count_df.loc['T', int(position)] = T_count
count_df.loc['G', int(position)] = G_count
count_df.loc['C', int(position)] = C_count

mRNA 重建:图像显示了所有 10 个个体的 mRNA 重建的前几个核苷酸位置。看看这些重建,大部分的 mRNA 序列是相同的。所有名字后面有“T2D”的人都是二型糖尿病。请注意,虽然此图像从“0”位置开始,但所有遗传数据和信息通常从 1 开始。
步骤 4:找出 mRNA 和蛋白质序列之间的差异
既然已经进行了重建,就需要扫描 mRNA 序列中每个位置的任何核苷酸差异。

mRNA 重建差异:这些是与每个个体或参考序列存在差异的 mRNA 位置。空的核苷酸单元意味着不存在覆盖该特定个体的核苷酸位置的序列。
只看差异,很明显,人与人之间可能存在许多可能的单一突变。然而,最重要的是,这些 mRNA 位置不位于蛋白质编码区——这意味着一旦 mRNA 被核糖体(翻译)读取,这些差异/变异不会影响前胰岛素原蛋白。蛋白质编码区的范围从位置 239-572(使用我的编号系统为 238-571),所有这些变异都位于该范围之外。但是,这并不意味着这些变化不重要!
下一步是将 mRNA 转化成蛋白质序列。然而,由于所有重建的蛋白质编码区没有差异,转换将导致产生相同的蛋白质序列。
最后一步:从生物学角度解释重建
要解释的主要数据是 mRNA 重建之间的差异。虽然变异的 mRNA 位置不在蛋白质编码区内,但它们可能影响其他方面,如 mRNA 转化为前胰岛素原的速率。mRNA 的起始和末端被称为非翻译区(UTRs),在将 mRNA 信息转化为蛋白质时,它们有助于 mRNA 和核糖体之间的相互作用。除了与核糖体的相互作用,其他蛋白质利用这些区域与 mRNAs 一起执行其他功能。
从该分析中可以得到的第二个认识是,变体 1 是细胞中存在的最普遍的 mRNA 形式(数据未显示)。这是预期的,因为直接转化变体 1 mRNA 序列将产生前胰岛素原的蛋白质序列,而其他变体需要在 mRNA 序列到达核糖体之前对其进行后修饰(选择性剪接)。
考虑:样本多样性和不常见的重建
最后要考虑的是细胞/样本来自哪里,来自谁,以及其他可能的 mRNA 重建。
二型糖尿病(T2D)是一种很难确定病因的疾病——它可能源于一个人的遗传、生活习惯、饮食、健康和其他环境因素。但是,棘手的部分在于,它很可能是由任何或所有这些因素造成的。因此,对于这种疾病和其他类似的疾病,遗传学研究可能无法提供一个关于一个人的遗传是否是其疾病的主要原因的结论性答案。在这项分析中,没有提供关于这些人的其他医学信息——因此,在开始这项分析之前,任何关于 T2D 的结论预计都是站不住脚的。
此外,这些个体的基因库也不清楚。这很重要,因为在这项研究中只有 10 个人,这极不可能反映世界上的遗传多样性。然而,令人惊讶的是,所有这些个体都没有产生与 mRNA 位置 80 处的参考序列相同的核苷酸(A80G,前面图像中的“79”)。
最后,对于一些个体来说,可能存在不太常见的 mRNA 重构。然而,我没有对这些重建进行全面的分析,因为最常见的重建与其他重建之间的百分比很可能保持在 2%以下。这些重构的低群体应该不会对胰岛素生产有显著的影响,因为最常见重构的群体将足以满足细胞的需要,如果不太常见的重构一开始就不存在的话。
结论
这项研究的目的是以 T2D 为例,从 NGS 数据中重建 mRNA,这是通过与参考序列的比对来完成的。虽然该分析没有显示 10 个个体(有或没有 T2D)之间产生的前胰岛素原蛋白有任何差异,但非蛋白编码区(UTRs)的变异在个体和群体之间是常见的、允许的和可行的突变。
查看我的 GitHub 获取 Python 代码。ipynb)! ]
简单可扩展图形神经网络
巨型图上的深度学习
到目前为止,阻碍图形神经网络在工业应用中广泛采用的挑战之一是难以将它们扩展到大型图形,如 Twitter follow graph。节点之间的相互依赖性使得将损失函数分解成单个节点的贡献具有挑战性。在这篇文章中,我们描述了一个在 Twitter 上开发的简单的图形神经网络架构,它可以处理非常大的图形。
G 图形神经网络(GNNs)是近年来出现的一类 ML 模型,用于对图形结构数据进行学习。GNNs 已经成功地应用于各种不同领域的关系和相互作用的模型系统,包括社会科学、计算机视觉和图形学、粒子物理、化学和医学。直到最近,该领域的大多数研究都集中在开发新的 GNN 模型并在小图上进行测试(其中 Cora 是一个仅包含约 5K 个节点的引用网络,仍在广泛使用[1]);在处理大规模应用程序方面投入的精力相对较少。另一方面,工业问题经常处理巨型图,例如包含数亿个节点和数十亿条边的 Twitter 或脸书社交网络。文献中描述的大部分方法不适合这些环境。
简而言之,图形神经网络通过聚集来自本地邻居节点的特征来运行。将 d 维节点特征排列成一个 n × d 矩阵 X (这里 n 表示节点的数量),在流行的 GCN 模型 [2]中实现的对图的最简单的类似卷积的操作将逐节点变换与跨相邻节点的特征扩散相结合
Y = ReLU( AXW )。
这里 W 是一个跨所有节点共享的可学习矩阵, A 是一个线性扩散算子,相当于邻域中特征的加权平均[3]。这种形式的多层可以像在传统的 CNN 中那样按顺序应用。图形神经网络可以被设计成在节点(例如,用于诸如检测社交网络中的恶意用户的应用)、边(例如,用于链接预测,推荐系统中的典型场景)或整个图形(例如,预测分子图形的化学属性)的级别进行预测。例如,可以通过以下形式的两层 GCN 来执行逐节点分类任务
Y= soft max(AReLU(AXW)W’)。
W 为什么标度图神经网络具有挑战性?在前述的逐节点预测问题中,节点扮演样本的角色,GNN 在样本上被训练。在传统的机器学习设置中,通常假设样本是以统计独立的方式从某个分布中抽取的。这反过来允许将损失函数分解成单个样本贡献,并采用随机优化技术,一次处理训练数据的小子集(小批量)。实际上,现在每个深度神经网络架构都是使用小批量来训练的。
另一方面,在图中,节点通过边相互关联的事实在训练集中的样本之间产生了统计相关性。此外,由于节点之间的统计相关性,采样会引入偏差,例如,它会使一些节点或边比训练集中的其他节点或边出现得更频繁,这种“副作用”需要适当的处理。最后但并非最不重要的一点是,必须保证采样后的子图保持一个 GNN 可以利用的有意义的结构。
在许多关于图形神经网络的早期工作中,这些问题被掩盖了:GCN 和切布内[2]、莫奈[4]和加特[5]等架构是使用整批梯度下降来训练的。这导致了在内存中保存图的整个邻接矩阵和节点特征的必要性。结果,例如,一个 L 层 GCN 模型具有时间复杂度𝒪( Lnd )和内存复杂度𝒪(lnd+LD)【7】,即使对于中等大小的图也是禁止的。
解决可伸缩性问题的第一份工作是 GraphSAGE [8],这是 Will Hamilton 和合著者的开创性论文。GraphSAGE 使用邻域采样结合小批量训练来在大型图上训练 gnn(缩写 SAGE 代表“样本和集合”,是对该方案的引用)。主要思想是,为了计算具有 L 层 GCN 的单个节点上的训练损失,只有该节点的 L 跳邻居是必要的,因为图中更远的节点不包括在计算中。问题是,对于“小世界”类型的图,比如社交网络,一些节点的 2 跳邻居可能已经包含数百万个节点,这使得它太大而无法存储在内存中[9]。GraphSAGE 通过对邻居进行采样直到第 L 跳来解决这个问题:从训练节点开始,它均匀采样,替换[10]固定数量的 k 个 1 跳邻居,然后对于这些邻居中的每一个,它再次采样 k 个邻居,以此类推 L 次。这样,对于每一个节点,我们保证有一个有界的 L 跳的𝒪( kᴸ 节点的采样邻域。如果我们随后构造一批具有 b 个训练节点的节点,每个节点都有其自己独立的 L 跳邻域,我们得到一个独立于图大小 n 的𝒪( bkᴸ 的记忆复杂度。一批 GraphSAGE 的计算复杂度为𝒪(bldt30】kᴸ。

graph sage 的邻域抽样程序。从全图中对一批 b 节点进行子采样(在本例中,b=2,红色和浅黄色节点用于训练)。在右边,用 k=2 采样的 2 跳邻域图,其被独立地用于计算嵌入,并因此计算红色和浅黄色节点的损失。
GraphSAGE 的一个显著缺点是采样节点可能会出现多次,因此可能会引入大量冗余计算。例如,在上图中,深绿色节点出现在两个训练节点的 l 跳邻域中,因此它的嵌入在批处理中被计算两次。随着批量 b 和样本数量 k 的增加,冗余计算的数量也增加。此外,尽管每批内存中都有𝒪( bkᴸ 节点,但损失仅在其中的 b 节点上计算,因此,其他节点的计算在某种意义上也是浪费的。
多项后续工作集中于改善小批量的抽样,以消除 GraphSAGE 的冗余计算,使每批更有效。这个方向上最近的工作是 ClusterGCN [11]和 GraphSAINT [12],它们采用了图采样的方法(与 GraphSAGE 的邻域采样相反)。在图采样方法中,对于每一批,原始图的子图被采样,并且完整的类 GCN 模型在整个子图上运行。挑战在于确保这些子图保留大部分原始边,并且仍然呈现有意义的拓扑结构。
ClusterGCN 通过首先对图进行聚类来实现这一点。然后,在每一批中,在一个集群上训练该模型。这使得每批中的节点尽可能紧密地连接在一起。
GraphSAINT 提出了一种通用概率图采样器,通过采样原始图的子图来构造训练批次。图形采样器可以根据不同的方案进行设计:例如,它可以通过使用随机行走计算节点的重要性并将其用作采样的概率分布来执行均匀节点采样、均匀边采样或“重要性采样”。
同样值得注意的是,采样的优势之一是,在训练期间,它充当一种边缘方向的丢失,这使模型正规化,并有助于性能[13]。然而,边缘丢失需要在推理时仍然看到所有的边缘,这在这里是不可行的。图形采样的另一个效果可能是减少瓶颈[14]和由邻域的指数扩展导致的“过度挤压”现象。
在我们最近与 Ben Chamberlain、Davide Eynard 和 Federico Monti [15]合作的论文中,我们研究了为节点分类问题设计简单、免采样架构的可能性。你可能想知道,鉴于我们刚刚在上面强调的间接好处,为什么人们宁愿放弃抽样策略。这有几个原因。首先,节点分类问题的实例可能彼此显著不同,并且据我们所知,迄今为止没有工作系统地研究了当采样实际上提供除了仅仅减轻计算复杂性之外的积极效果时的。其次,采样方案的实施带来了额外的复杂性,我们认为简单、强大、免采样、可扩展的基线架构很有吸引力。
我们的方法是由几个最近的经验发现所激发的。首先,简单的固定聚合器(如 GCN)在许多情况下表现往往优于更复杂的聚合器,如 GAT 或 MPNN [16]。第二,虽然深度学习的成功建立在有很多层的模型上,但在图形深度学习中,是否需要深度仍然是一个公开的问题。特别是,Wu 和合著者[17]认为具有单个多跳扩散层的模型可以与具有多个层的模型性能相当。
通过在单个卷积层内组合不同的、固定的邻域聚合器,有可能获得一个极其可扩展的模型,而无需诉诸图形采样[18]。换句话说,所有与图相关的(固定的)操作都在体系结构的第一层,因此可以预先计算;然后,预聚合的信息可以作为输入提供给模型的其余部分,由于缺乏邻域聚合,该模型可以归结为一个多层感知器(MLP)。重要的是,通过使用几个可能专门的和更复杂的扩散算子,即使使用这样的浅层卷积方案,图过滤操作中的表达性仍然可以保留。例如,可以设计操作符来包含局部子结构计数【19】或图形主题【20】。

SIGN 架构包括一个类似 GCN 的层,该层具有可能作用于多跳邻域的多个线性扩散算子,随后是逐节点应用的 MLP。其效率的关键是扩散特征的预先计算(用红色标记)。
所提出的可扩展架构,我们称之为可扩展的类初始图网络(SIGN ),对于节点分类任务具有以下形式:
y= soft max(relu(xw₀| a₁xw₁| a₂xw₂|…| aᵣxwᵣw’)
这里at24】ᵣ是线性扩散矩阵(例如归一化的邻接矩阵、其幂或基序矩阵)并且wt28】ᵣ和 W 是可学习的参数。如上图所示,通过增加节点层,网络可以变得更深,
y= soft max(relu(…relu(xw₀| a₁xw₁|…| aᵣxwᵣ)w')…w' ')
最后,当对同一扩散算子采用不同的幂时(如a₁=bt56】,A ₂= B 等)。),图操作有效地在越来越远的跳中从邻居聚集,类似于在同一网络层中具有不同感受域的卷积滤波器。这种与经典 CNN 中流行的 inception 模块的类比解释了所提出的架构的名称[21]。
如上所述,上述等式中的矩阵乘积 A ₁ X ,…,aᵣx不依赖于可学习的模型参数,因此可以预先计算。特别是,对于非常大的图形,可以使用 Apache Spark 等分布式计算基础设施来有效地扩展这种预计算。这有效地将整个模型的计算复杂度降低到 MLP 的计算复杂度。此外,通过将扩散移至预计算步骤,我们可以从所有邻居聚集信息,避免采样以及可能的信息丢失和随之而来的偏差【22】。
SIGN 的主要优势是其可扩展性和效率,因为它可以使用标准的小批量梯度下降来训练。我们发现我们的模型在推理时间上比 ClusterGCN 和 GraphSAINT 快两个数量级,同时在训练时间上也快得多(所有这些都保持了与最先进的 GraphSAINT 非常接近的准确性性能)。

不同方法在 OGBN-Products 数据集上的收敛性。与 GraphSaint 和 ClusterGCN 相比,SIGN 的变体收敛更快,验证 F1 分数更高。

OGBN-Products 数据集上不同方法的预处理、训练和推理时间(秒)。虽然预处理速度较慢,但 SIGN 的训练速度更快,推理时间比其他方法快近两个数量级。
此外,我们的模型支持任何扩散算子。对于不同类型的图形,不同的扩散操作符可能是必要的,我们发现一些任务受益于基于基元的操作符,如三角形计数。

SIGN 和其他可扩展方法在一些流行数据集上对节点分类任务的性能。基于三角形主题的扩散算子在 Flickr 上提供了有趣的性能增益,并在 PPI 和 Yelp 上提供了一些改进。
尽管只有一个图卷积层和线性扩散算子的限制,SIGN 在实践中表现非常好,达到与更复杂的模型相当甚至更好的结果。鉴于其速度和实现的简单性,我们设想 SIGN 是一种用于大规模应用的简单基线图学习方法。也许更重要的是,这样一个简单模型的成功引出了一个更基本的问题:我们真的需要深度图神经网络?我们推测,在社交网络和“小世界”图的许多学习问题中,我们应该使用更丰富的局部结构而不是诉诸蛮力深度架构。有趣的是,传统的 CNN 架构按照相反的趋势发展(更深的网络和更小的滤波器),因为它具有计算优势,并且能够将复杂的功能组合成简单的功能。我们不确定同样的方法是否适用于图,在图中,组合性要复杂得多(例如,某些结构不能通过消息传递来计算,无论网络有多深)。当然,还需要更精细的实验来验证这个猜想。
[1]最近推出的开放图形基准现在提供具有数百万个节点的大规模图形。社区可能需要一段时间才能转用它。
[2] T. Kipf 和 M. Welling,用图卷积网络进行半监督分类 (2017)。继续。ICLR 引入了流行的 GCN 架构,该架构是对 M. Defferrard 等人提出的 ChebNet 模型的简化(2016)。继续。乳头。
[3]作为扩散算子,Kipf 和 Welling 使用具有自循环的图邻接矩阵(即,节点本身有助于其特征更新),但是其他选择也是可能的。可以使扩散操作依赖于形式为 A ( X ) X (即,它仍然是节点特征的线性组合,但是权重取决于特征本身)的特征,如在 MoNet [4]或 GAT [5]模型中,或者完全非线性,****x,如在消息传递神经网络(MPNN) [6]中。为简单起见,我们集中讨论应用于节点分类的 GCN 模型。
[4] F. Monti 等人,利用混合模型 CNN 对图和流形进行几何深度学习 (2017)。进行中。CVPR。
[5]p . veli kovi 等人,图形注意网络 (2018)。进行中。ICLR。
[6] J. Gilmer 等人,量子化学的神经信息传递 (2017)。进行中。ICML。
[7]这里为了简单起见我们假设图是稀疏的,边数为|ℰ|=𝒪(n。
[8] W. Hamilton 等人,大型图上的归纳表征学习 (2017)。进行中。神经炎。
[9]在这样的图中,邻居的数量随着邻居的扩展而呈指数增长。
[10]带有替换的采样意味着一些邻居节点可能出现不止一次,特别是如果邻居的数量小于 k 时。
[11] W.-L. Chiang 等人, Cluster-GCN:一种训练深度和大型图卷积网络的高效算法 (2019)。进行中。KDD。
[12] H. Zeng 等, GraphSAINT:基于图抽样的归纳学习方法 (2020)在 Proc .ICLR。
[13] Y. Rong 等.【DropEdge:面向节点分类的深度图卷积网络 (2020)。进行中。ICLR。一种类似于丢弃的想法,其中在训练期间使用边的随机子集。
[14] U. Alon 和 E. Yahav,关于图形神经网络的瓶颈及其实际意义 (2020)。arXiv:2006.05205。确定了图形神经网络中的过度挤压现象,这类似于在顺序递归模型中观察到的现象。
[15]弗拉斯卡等人,符号:可扩展的初始图神经网络 (2020)。ICML 图形表示学习研讨会。
[16] O. Shchur 等人图神经网络评估的陷阱 (2018)。关系表征学习工作坊。显示简单的 GNN 模型与更复杂的模型表现相当。
[17] F. Wu 等,简化图形神经网络 (2019)。进行中。ICML。
[18]虽然我们强调,为了计算效率,SIGN 不需要采样,但是还有其他原因说明图形子采样为什么有用。j .克利茨佩拉等人扩散改善图形学习 (2020)。继续。NeurIPS 表明,采样扩散矩阵提高了图形神经网络的性能。我们在早期的符号实验中观察到了同样的现象。
[19] G. Bouritsas 等通过子图同构计数提高图神经网络表达能力 (2020)。arXiv:2006.09252。展示了如何通过结构节点编码获得强大的 gnn。
[20] F. Monti,K. Otness,M. M. Bronstein, MotifNet:一种基于 motif 的图卷积网络,用于有向图 (2018)。arXiv:1802.01572。使用基于基元的扩散算子。
[21] C. Szegedi 等人,用卷积进行更深入的研究 (2015)。继续。CVPR 在经典的 Google LeNet 架构中提出了 inception 模块。公平地说,我们并不是第一个想到图初始模块的人。我们的合作者来自慕尼黑工业大学的 Anees Kazi 是去年帝国理工学院的访问学生,她首先介绍了他们。
[22]注意,到达更高阶的邻居通常是通过与直接邻居一起操作的深度堆叠图卷积层来实现的;在我们的架构中,这是在第一层通过图操作符的能力直接实现的。
符号 工具 选项可用 PyTorch 几何 。本帖的 中文翻译 由 刘止庸 提供。对图形深度学习感兴趣?关于图形深度学习的其他文章,请参见我的 博客 关于走向数据科学, 订阅 到我的帖子,获取 中等会员 ,或者关注我的Twitter。**
具有弹性搜索的简单搜索引擎
从头开始构建泰米尔歌词搜索

图 1:作者解释的弹性叠加
弹性堆叠
Elastic Stack 是来自 Elastic 的一组开源产品,旨在帮助用户从任何类型的来源以任何格式获取数据,并实时搜索、分析和可视化这些数据。
- Elasticsearch 是一个 RESTful 分布式搜索引擎。它基于 Java,可以搜索和索引不同格式的文档文件。
- Kibana 是一个开源的数据可视化和探索工具,专门用于大量的流和实时数据。该软件通过其图形表示,使庞大而复杂的数据流变得更加容易和快速理解。
还有一些其他的产品。 logstash 和 节拍 。博客的目的是通过配置一个非常简单的歌词搜索引擎来指导读者,特别是对于使用 ElasticSearch 的泰米尔人。
先决条件
歌词语料库 → 需要添加的歌词数据
邮递员 → 测试 API 调用ElasticSearch → 带 API 的搜索引擎
样本歌词搜索引擎 →包含 lyricsdata、UI [HTML/CSS]和 python 脚本,用于 FLASK 的后端支持
要遵循的步骤
数据抓取
- 在构建歌词搜索引擎之前,必须收集歌词数据。www.tamilpaa.com 是一个收集了电影名、歌手和音乐导演的歌词的网站。泰米尔语歌词的必要性和数据量(3200+歌词可刮擦)使得使用特定网站作为爬虫主机成为必要。
- 曾经用scrapy写了一个网络爬虫,从网站上抓取原始数据。爬虫是回购中可用的 colab 笔记本。
Raw_Data : The data scraped directly from the website. Stored in different folders, categorized based on year.
├── Tamil_movie_song_lyrics_2017
├── Tamil_movie_song_lyrics_2018
├── Tamil_movie_song_lyrics_2019
├── Tamil_movie_song_lyrics_2020
├── Tamil_movie_song_lyrics_random_2300+
PreProcessedData : The data has to be pre-processed(convert to Tamil) for values of some fields were in English(E.g. A.R.Rahman => A. R. ரஹ்மான்)
ModifiedData : The data was modified by adding more fields to spice up search ("வகை","நுகர்ச்சி","மதிப்பீடு") -('genre','views','ratings')
配置弹性搜索
第一步
下载elastic search,有多种格式,包括 ZIP 和 TAR.GZ 格式,解压文件夹。打开一个命令行工具,遍历到 elasticsearch 的 bin 文件夹,然后运行“elasticsearch”命令。
C:\Users\cvvin>cd C:\Users\cvvin\Desktop\Notes\elasticsearch-7.7.1\binC:\Users\cvvin\Desktop\elasticsearch-7.7.1\bin>elasticsearch
“elasticsearch”命令将在 localhost 中托管 elasticsearch。默认端口是 9200。
第二步
打开 web 浏览器并粘贴以下 URL,检查 elasticsearch 搜索服务器是否启动并运行。
http://localhost:9200/
结果必须类似于下图。

图 2 .检查 ElasticSearch 服务器启动时的结果——由作者截取
请注意,默认端口是 9200,可以更改。在弹性搜索中遍历到 config 文件夹。打开“config.yml”文件,根据需要编辑端口号。
http.port: 9300
第三步
下载邮差如果你还没有。Postman 是一个专门用来测试别人或者你自己开发的 RESTful API 的工具。
步骤 4
- Elasticsearch 类似于一个数据库。下面是一个比较 ElasticSearch 和更一般的关系数据库的类比。
Elastic Search => Mysql
Index => Database
Types => Tables
Properties => Columns
Documents => Rows
- 索引就像一组键,隐含着指向搜索查询中的术语的指针。索引将由一个或多个文档组成。ElasticSearch 使用一个倒排索引,它将一个以页面为中心的数据结构倒排到一个以关键字为中心的数据结构。
- 我们可以使用 PUT 请求创建索引。这里我选择了'Tamil songlyricsdatabase'作为索引名。
http://localhost:9200/tamilsonglyricsdatabase

图 3 .使用 Postman 屏幕在 ElasticSearch 中创建新索引——由作者捕获
并且响应将类似于上图中的内容(图 3)。如果索引已经存在于 ElasticSearch 中,服务器将抛出一个引用现有索引的错误。
第五步
我们现在可以使用 POST 请求创建类型(即数据库中的表)和添加文档(即数据)。 文档 是搜索和索引的单位,由一个或多个字段组成。
- 我选择了 “歌词” 作为文档类型,选择了“2”作为文档 ID。将歌词数据作为 JSON 添加到帖子请求的 正文部分 如下图所示(Fi.4. |左)。可以从语料库中获取歌词数据。
[http://localhost:9200/tamilsonglyrics/lyrics/](http://localhost:9200/tamilsonglyrics/lyrics/2)2


图 4. ( 左)将文档添加到索引屏幕-由作者捕获| ( 右 )响应屏幕-由作者捕获
- 在图 4(左)中,显示的 JSON 是文档。蓝色的是字段,粉色的是这些字段的相关值。
- 如果对添加文档的响应如图 4 所示,则可以从响应中验证成功添加了文档(右图)
- 但是像这样手动添加几个 JSONs 将会是一项繁忙的任务,而且成本很高。因此,弹性搜索有了“批量 API”的帮助,我们可以在一次 API 调用中添加大量文档。
- 要通过 BulkAPI 添加文档,需要将我通过抓取网站收集的所有单个 JSON 转换成一个 BulkJSON。 这里 (年份 2017,2018,2019) 你可以找到三个这样的 BulkJSONs。但是需要添加一个小的 python 脚本来修改我收集的数据,并使用 Python 通过 BulkAPI 添加数据。
- 必须在当前的 python 解释器中添加 elasticsearch,elasticsearch_dsl。
pip install elasticsearchpip install elasticsearch-dsl
一旦添加了库,现在就可以运行 python 脚本了。
如果您已经克隆了 repo 并且更喜欢尝试,只需运行bulk data . py .否则,如果您在读取文件和添加任何字符替换时有自己的数据和操作,请尝试修改下面的脚本。还可以使用 python 和 elasticsearch 库创建索引、添加文档和搜索。
bulkdata.py 可从作者的 github 获得
- 获取 python 脚本‘bulk data . py’来添加索引(如果之前没有添加,取消对索引部分的注释)。并通过运行脚本向 BulkAPI 添加文档。修改“索引”名称以适合您的名称,并运行 python 脚本。将数据添加到一个文件夹(如 corpus ),并在
read_all_songs()方法中更新路径。如果您想要添加更多文档,请将它们添加到同一个文件夹中并运行脚本。对于抓取的数据,我已经相应地定义了字段。但是,如果您对数据进行了任何更改,请在genData()方法中添加相同的字段。
通过这些步骤,我们将能够成功上传数据,并可以搜索歌词。
高级索引
但是另外,您可以设置现有的分析器或定制的分析器来支持更有效的索引。必须创建一个定制的分析器,结合适当的字符过滤器、记号赋予器和记号过滤器。

图 5 . Arun Mohan 的博客中弹性搜索的文本分析
一个字符过滤器接收作为字符流的原始文本,并可以通过添加、删除或改变字符来转换该流。
一个 记号赋予器 接收一个字符流,将其分解成单独的记号(通常是单独的单词),并输出一个记号流。
记号过滤器接受来自记号赋予器的记号流,并且可以修改记号(例如小写),删除记号(例如删除停用词)或者添加记号(例如同义词)。
我已经创建了一个自定义分析器,你可以从 这里 得到。并遍历到机器中 ElasticSearch 的 config 文件夹。
elasticsearch-7.7.1\config
- 创建一个名为“analyze”的文件夹,并添加您从 repo 中获取的文件。
elasticsearch-7.7.1\config\analyze\
定制分析仪包括
1.标准记号化器→它在单词边界上将文本分成术语,并删除大部分标点符号。对于任何语言来说,它都是最常用的标记符。因此我们坚持使用这个记号化器。
2.自定义过滤器,包括
自定义阻止符 →包含 Tamil(Like:ஒரு、என்று、மற்றும்、இந்த、இது、என்ற、கொண்டு的停用词,这些词在 Thamizh 中非常常见,但在搜索中可以忽略,因为它们通常不会为搜索提供任何特定的意义。
自定义词干 →词干是提供单词的词干。例如,在英语中,我们可以用“播放,播放,播放器”→ 播放。通常蒸可以用动词。在塔米兹我们也能阻止。比如“உண்ண、உண்டு、உண்டேன்、உண்கிறேன்、உண்பேன்、உண்ணும்”→உண்
自定义匿名 →可以添加匿名词,这样我们可以减少各种索引的数量,从而提高索引和搜索的效率。比如“மிகச்சிறந்த、மிகசிறந்த,மிகவும்சிறப்பான、சிறப்பான、தலைசிறந்த、உயர்ந்த”→சிறந்த
添加“分析器”文件夹(包含 stem.txt、stopwords.txt、synonym.txt)后,需要创建(新的)索引,包括以下示例 JSON 作为主体。

图 6 .添加定制分析器屏幕——由作者捕获
示例搜索查询
我们已经看到了添加文档、添加批量数据、添加定制分析器,现在我们可以继续搜索查询。下面的例子可以用 Postman 试试。
- 基本搜索 —用户可以只进行搜索,而无需将任何必需的信息添加到搜索获取请求的正文中。
http://localhost:9200/tamilsonglyrics/_search
- 如果用户只知道电影/年份/歌手/作词人/流派,他可以搜索歌词。将下面的代码片段作为正文添加到 Postman GET 请求中。在所提供的例子中,
யுகபாரதி是一个作词人,他想检索他写的歌词。我们可以通过在查询中提到电影的名称来搜索特定电影的歌词。我们可以通过在查询中提及特定的风格来搜索某个风格的歌词。
例如-“யுகபாரதி”
{
"query": {
"query_string": {
"query":"யுகபாரதி"
}
}
}

图 7 .简单搜索查询屏幕——由作者捕获
- 当用户知道电影/年份/歌手/作词人/流派时,他可以搜索指定该领域的歌词,这与上面提到的广泛搜索相反。这是一个匹配查询。这里的
பாடலாசிரியர்(lyricist)是与用户正在搜索的搜索词யுகபாரதி相关的字段。与在特定字段中搜索相比,这种搜索将减少在每个字段中搜索查询词的开销。这将提高搜索的持续时间。
例如-“பாடலாசிரியர்யுகபாரதி”
{
"query" : {
"match" : {
"பாடலாசிரியர்" : "யுகபாரதி"
}
}
}
- 通配符查询帮助用户即使有拼写错误也能进行搜索。当用户不确定作词人的全名
*யுகபாரதி*,时,他可以使用யுக*作为通配符进行搜索。ElasticSearch 将带来与通配符匹配的高分结果。
如“யுகபாரதி”的“யுக”*
"query" : {
"match" : {
"பாடலாசிரியர்" : "யுக*"
}
}
}
- 多匹配查询允许在一个以上的特定字段中搜索一个术语。这里
*அனிருத்*预期出现在பாடியவர்கள்(singers)和இசையமைப்பாளர்(Music director)的一个或两个字段中
例如——《அனிருத்》
{
"query" : {
"multi_match" : {
"query" : "அனிருத்",
"fields": ["பாடியவர்கள்","இசையமைப்பாளர்"]
}
}
}
- 用户可以搜索特定性质(流派/歌手/音乐导演)的前 20 首歌曲。这里我们搜索
*மிகச்சிறந்த 20 குத்துபாடல் (top20 rock songs).*W e 定义Top应该排在மதிப்பீடு (rating)上。在这个搜索查询中,我们将结果的大小定义为 20,因为我们期望有top20首歌曲,并且我们将它们按照மதிப்பீடு (rating)的降序排序。
例如— மிகச்சிறந்த 20 குத்துபாடல்
"size":20,
"sort" : [
{ "மதிப்பீடு" : {"order" : "desc"}}
],
"query": {
"multi_match": {
"fields":["வகை"],
"query" : "குத்துபாடல்",
"fuzziness": "AUTO"
}
}
}
- 我们可以搜索
famous排名在நுகர்ச்சி (views)之上的(音乐导演/流派/歌手的)著名歌曲。搜索查询是*பிரபல்யமான 15 ஹரிஷ் ஜெயராஜ் பாடல்கள்(15 famous Harish Jeyaraj songs)*。这里我们将尺寸定义为 15(因为我们要求如此)。并将待搜索的特定字段定义为இசையமைப்பாளர்(music director)并将模糊度设置为自动。模糊支持有拼写错误的搜索。我们根据நுகர்ச்சி (views)排序。
例如——பிரபல்யமான15ஹரிஷ்ஜெயராஜ்பாடல்கள்
"size":15,
"sort" : [
{ "நுகர்ச்சி" : {"order" : "desc"}}
],
"query": {
"multi_match": {
"fields":["இசையமைப்பாளர்"],
"query" : "ஹரிஷ் ஜெயராஜ்",
"fuzziness": "AUTO"
}
}
}
- 布尔查询用于减少搜索空间,添加更多条件,如 must、should、must_not,这些条件与布尔 od 和、OR、not 类似。在下面的搜索查询中,我们期望结果包括作为
இசையமைப்பாளர்(musicdirector)的இமான்和作为வருடம்(year)的2019
如இமான் 2019 பாடல்வரிகள்
{
"query": {
"bool": {
"must": [
{ "match": { "இசையமைப்பாளர்": "இமான்" }},
{ "match": { "வருடம்": "2019" }}
]
}
}
}
- 范围查询在我们需要包含给定范围内的搜索结果时很有帮助。这里,当搜索
*சமீபத்திய பாடல்கள் (latest songs0 ,*时,我们将latest定义为基于年份,并定义了范围查询。gte标志着范围的开始。
例如——இமான்சமீபத்தியபாடல்கள்
"query": {
"bool": {
"must": [{
"match": {
"இசையமைப்பாளர்": "இமான்"
}
},
{
"range": {
"வருடம்" : {
"gte" : "2019"
}
}
}
]
}
}
}
- 用户在搜索歌词时只能得到偏好的字段。这里我们只期望有
திரைப்படம்(movie),இசையமைப்பாளர்(music director),因此为15 famous rock songs的查询将这些字段添加到了“_source”:{"includes":[திரைப்படம்","இசையமைப்பாளர்"]
例如——著名的குத்துபாடல்திரைப்படம்/இசையமைப்பாளர்
{
"_source":{
"includes":["திரைப்படம்","இசையமைப்பாளர்"]
},
"size":10,
"sort" : [
{ "மதிப்பீடு" : {"order" : "desc"}}
],
"query": {
"multi_match": {
"fields":["வகை"],
"query" : "குத்துபாடல்",
"fuzziness": "AUTO"
}
}
}
- 我们可以搜索与歌词相关的其他细节。 MLT( more_like_this) 查询有助于文本挖掘,因此扩展了对巨大搜索输入项的支持,并带来相关文档。
{
"query":{
"more_like_this":{
"fields":[
"பாடல்வரிகள்"
],
"like":"நெஞ்சில் மாமழை நெஞ்சில் மாமழை தந்து வானம் கூத்தாட கொஞ்சும் தாமரை கொஞ்சும் தாமரை வந்து எங்கும் பூத்தாட எத்தனை நாள் எத்தனை நாள் பார்ப்பது எட்டி நின்று எட்டி நின்று காய்வது கள்ள குரல் பாடல் உள்ளே ஓடுது கண்மூடி கண்மூடி காதோரம் பாடுது நெஞ்சில் மாமழை நெஞ்சில் மாமழை தந்து வானம் கூத்தாட கொஞ்சும் தாமரை கொஞ்சும் தாமரை வந்து எங்கும் பூத்தாட வாரத்தில் எத்தனை நாள் பார்ப்பது அன்றாடம் வந்து பார்க்க ஏங்குது வராமல் போகும் நாட்கள் வீண் என வம்பாக சண்டை போட வைக்குது சொல்ல போனால் என் நாட்களை வண்ணம் பூசி .",
"min_term_freq":1,
"max_query_terms":20
}
}
}
- 用户可以使用项进行聚合桶查询。
聚合框架有助于针对一组文档构建复杂的数据和分析信息摘要。分桶、度量、矩阵、管道是聚合的类型。存储桶用于构建存储桶,其中每个存储桶都与一个键和一个文档标准相关联。一旦执行,将提供存储桶列表和落入存储桶的文档摘要。
- 但是,在此之前,我们必须添加我们想要存储的特定字段作为字段数据,如图 8 所示。虽然字段自然会被索引、排序、聚合,但需要与搜索不同的访问模式。
搜索→ “哪些文档包含这个术语?”
排序和聚合→ “这个字段对于这个文档的值是多少?”。
默认情况下,字段数据在字段上是禁用的,因为这将占用大量空间,我们需要手动为特定字段启用。

图 8 .添加字段数据屏幕——由作者捕获
添加வகை(genre)作为字段数据后,我们就可以进行分桶了。这种聚集存储的结果是基于类型的。这意味着将根据流派创建存储桶,并汇总每个存储桶/流派中的文档。
"aggs": {
"ratings": {
"terms": { "field": "வகை" }
}
}
}
尝试歌词搜索与用户界面的简单查询
- 分叉并克隆回购。
- 从克隆的 repo 中提取 Analyzer 文件夹,并将其添加到 ElasticSearch/config 文件夹中
- 运行弹性搜索
- 运行“bulkdata.py”添加索引(如果不是手动添加的,则取消对索引部分的注释)并添加数据
- 将 LyricSearch 部件添加到 UI 的 htdocs 文件夹中。
- 转到http://localhost/lyrics search/
- 搜索歌词(目前仅适用于此用户界面的基本查询)
来自作者 github 的 query.py
github 只为某些查询定义,如基本查询、模糊查询、聚合查询。尝试 postman 集合,尝试上面小节中描述的各种其他查询。
来自作者 github 的 searchquery.py
这个searchquery.py阐述了我们如何通过 python 脚本进行搜索。
- 对于高级查询,尝试来自 postman 的 Postman 查询集合(repo 中提供的 Postman API 调用集合)
- 回购正在开发中,以支持高级查询。
这停止了我的博客开发一个简单的歌词搜索引擎(具体到 Thamizh)。下期博客再见。
使用 Python 按特定属性对对象列表进行简单排序
这没有你想象的那么难
在我对 Python 和数据建模的初步实验中,我必须将数据导入到我的 Jupyter 笔记本中。我想到了排序,并且想到了如何使用特定的实例变量(比如 name)对对象列表进行排序。例如,我有一个由名称和价格组成的汽车对象列表。

所以我想生成一个列表,其中的结果按照汽车名称的字母顺序排序,如下所示。我不想使用任何库,所以没有为我导入。

Googling 没有给我返回太多信息,因为结果返回了大量关于数字排序的信息,一些关于单词排序的结果,没有令人满意的作为实例变量一部分的单词排序结果。所以我决定尝试一下。Python 不是我日常工作中需要做的事情。但是当需要的时候,我偶尔会使用 Python 来编写脚本。所以我想我应该尝试一下。
这就是我解决问题的方法,我的示例代码如下所示
首先,我将声明一个汽车类,并创建一个列表来插入这些对象
class cars:
def __init__(self, name, price):
self.name = name
self.price = price unsorted_cars = []
unsorted_cars.append(cars('Ford', 20000))
unsorted_cars.append(cars('Volvo', 50000))
unsorted_cars.append(cars('BMW', 24000))
unsorted_cars.append(cars('Toyota', 15000))
unsorted_cars.append(cars('Kia', 12000))
unsorted_cars.append(cars('Audi', 40000))
unsorted_cars.append(cars('Tesla', 30000))
因为我想按照卡片的名称对列表进行排序,所以我创建了一个空列表,将汽车名称放入该列表,并使用标准的排序函数对列表进行排序
sorted_car_name = []
for car in unsorted_cars:
sorted_car_name.append(car.name)sorted_car_name.sort()
这将返回一个按字母顺序排序的汽车名称列表。最后,现在我有了排序后的名字列表。我可以以此为参考,使用这个双 for 循环遍历未排序 _ 汽车列表,并使用每个汽车对象中的名称实例变量与已排序 _ 汽车名称列表中的每个单词进行比较,如果匹配,则将其插入新的空列表已排序 _ 汽车列表
sorted_car = []
for sort_car in sorted_car_name:
for unsorted_car in unsorted_cars:
if unsorted_car.name == sort_car:
sorted_car.append(unsorted_car)
break
sorted_car_list 现在将按照汽车名称的字母顺序排列汽车的最终列表,如上表 2 所示。请注意,由于双 for 循环,这种方法不是很有效,在双 for 循环中,我们遍历未排序 _ 汽车中的购物车对象列表,然后遍历已排序 _ 汽车 _ 名称中的每个单词,进行比较以查看是否匹配,然后我们将未排序 _ 汽车对象插入到已排序 _ 汽车列表中。
你可以在这里下载示例 Python 代码。要运行代码,只需在命令行输入' python python _ sort _ sample . py ',它就会打印出未排序的汽车列表和最终排序的汽车。我希望这能对任何 Python 爱好者有所帮助。
心灵的朋友,文瑞,刚刚给我指出 Python 有一个 sorted() 函数可以用。函数的作用是:接收一个对象列表,作为排序依据的关键字,并返回排序后的列表。这个函数使用 Lamba 来创建一个匿名函数。因此,为了对未排序的汽车名称列表进行排序,我们使用
result_list = sorted(unsorted_cars, key=lambda cars: cars.name)
for car in result_list:
print(car.name + " and price is " + str(car.price))
所以,通过传入未排序的汽车列表,匿名函数和作为排序依据的属性,也就是汽车的名称。我们将在 result_list 中得到排序后的列表。这是一种更好的排序方式,尽管 Lamba 的使用将您的 Python 代码转变为函数式编程范式。
我已经更新了我的示例代码,并将 sorted() 方法包含在这个 gisthttps://gist . github . com/gib Tang/83f 9681 b 525908900 ec4b 490992 f032d中
排序函数的一些相关链接
https://Julien . danjou . info/python-functional-programming-lambda/
https://docs.python.org/3/howto/sorting.html
https://www.w3schools.com/python/ref_func_sorted.asp
使用 twitter-nlp-toolkit 进行简单的 Twitter 分析
Twitter 是商业分析和学术或教学自然语言处理最丰富的数据源之一;Kaggle 上的许多顶级 数据集是在 Twitter 上收集的,最受欢迎的文本嵌入之一是使用 Twitter 训练的,几乎每个公司都在积极监控 Twitter。
原因有很多:Twitter 有一个可访问的 API,它的 hashtag 系统使数据收集和分类变得容易。也是因为 Twitter 是一个令人难以置信的两极分化和反动的平台;当某件事成为“推特上的流行趋势”时,它通常是一个令人震惊的产品公告,一个受到批评的新版本,或者有人说了一些煽动性的话。这使得 Twitter 成为公众情绪的一个极其强大的信息来源。我和我的合作者注意到,我们经常被分派收集和分析 Twitter 数据的任务,所以我们决定为此构建一个用户友好的包— twitter-nlp-toolkit 。在这里,我将通过我今年早些时候制作的一个可视化展示来告诉你如何使用它,展示伊隆·马斯克在 Twitter 上的几个煽动性评论的影响。
首先,你需要注册一个 Twitter API 密匙,安装软件包,并安装 Spacy 的en_core_web_sm模型。你可以很容易地做第一个这里——你将被简单地要求提供一个你正在做的需要一个的快速描述——后两个甚至更容易;只需在你的终端中运行pip install twitter-nlp-toolkit和python -m spacy download en_core_web_sm。twitter-nlp-toolkit需要
tensorflow ≥2和scikit-learn ≥0.22,所以你可能要把它安装在一个新的虚拟环境里。
倾听
Twitter API 的主要产品是一个监听器,它允许您将 tweets 实时传输到磁盘。搜索逻辑记录在这里。首先,将您的 Twitter API 密匙作为keys.key以.json格式保存在您的工作目录中,如下所示:
你可以建立你的听众。这将监听包含“Musk”和/或“Tesla”的推文(如果你想要两个关键词,只需设置target_words = [‘Musk Tesla’])。)
这将持续不断地将所有包含“Musk”和/或“Tesla”的推文发送到musk_tweets.json。该文件可能会变得非常大,并且包含许多可能无关的信息,因此应该监控磁盘使用情况。比如这条推文:

“我对@elonmusk 的看法现在是零,开尔文。”— @AltPublicLands
被保存为超过 10kB 的信息:

呀。解析器会将包含 tweets 的.json文件转换成更易于管理的.csv文件:
生产parsed_musk_tweets.csv:
(因为我们没有商业 Twitter API 密匙,所以我们看不到用户的确切位置。)
我们还可以使用批量下载工具获取马斯克本人最后 200 条左右的推文:
这将产生已经以.csv格式解析的 tweets。
情感分析
twitter_nlp_toolkit 还包括一个情绪分析包,可以评估推文的正面或负面:
情感分类代码
predict()函数产生二元预测——0 表示负数,1 表示正数——而predict_proba() 产生连续预测。
我们的模特意识到这不是赞美
在 Tableau 中将推文量和平均情绪绘制为时间的函数,产生了以下可视化效果,表明虽然 Twitter 对淡化新冠肺炎严重性的推文有些担忧,但他们对关于特斯拉高股价的推文更加担忧。

随着时间的推移,受平均情绪影响的推文量。对比度得到增强,以提高可见度。
也可以利用用户账户位置来产生估计的地理地图。这里我使用了 Tableau 的地理编码服务;然而,Tableau 只能解释不到 20%的用户提供的位置,其中一些解释是不可信或不准确的。谷歌地图可能会做得更好,但免费层每天的请求数量限制在 2000 个左右:

这里还应该注意的是,在我们的测试中,情感分析只有大约 85%的准确性,在野外可能不太准确;我们的情感分析工具仅使用sensition 140数据集对文本内容进行训练,该数据集已相当陈旧。虽然我们正在努力改进模型,但它们可能只用于观察趋势,而不是对单个推文进行分类,除非它们可以在领域数据上进行微调。
功能愿望列表
该软件包仍在积极开发中,但这里显示的功能应该不会中断。当前的优先任务包括改进情感分析模型,提高推文解析和语言预处理的效率和定制,以及集成谷歌地理编码 API。
软件包中的所有代码,包括更多的例子,都托管在 Github 这里。我们鼓励读者带着问题或功能需求联系开发人员。
具有 Github 操作的简单版本化数据集
实践教程
不到 10 行 Python 代码,保存了著名 CEO 的历史

凯文·Ku 拍摄于 Pexels
背景
几天前偶然发现了一篇关于作者创造的“git 抓取”概念的文章。这个过程最引人注目的方面是,作为开发人员,我不必维护服务器或大型代码库来获得最新的版本化数据集。我实际上可以利用 git 的版本控制功能和 Github 的动作。这个过程对我来说太有趣了,我不得不亲自尝试一下。这是我记录的旅程,所以你可以对你自己的数据集做同样的事情。
查找我的数据集
为了充分利用我的数据集的 git 版本控制,我想寻找一个数据集,在这个数据集上,随着时间的推移,查看它的变化会有附加值。我也不希望这些更改过于频繁,这样提交就会变得稀疏,这样单独的更新就更容易被识别出来。
在未能找到一个好的啤酒厂数据集后,我决定监控这张著名公司首席执行官(CEO)的表格。这个列表以表格的形式出现在维基百科页面上。
[## 首席执行官名单
以下是著名公司首席执行官的名单。的…
en.wikipedia.org](https://en.wikipedia.org/wiki/List_of_chief_executive_officers)
抓取维基百科
现在我的数据集已经确定了,我只需要编写一些代码来检索我们想要存储的信息。我还想确保以一种将来易于接收的方式公开它,以一种自动化的方式,因此考虑到这一点,我决定将这些数据存储为 CSV 文件。
要求
对于我提出的解决方案,需要以下 Python 3 包。在最终的存储库中,这些显示在requirements.txt文件中。
- 熊猫——这可能是另一个类似于 tablib 的库,但是为了以防万一,我选择了熊猫。
- lxml —这个库在从 html 表格中获取表格的函数中得到利用。
摄入代码
我需要做的第一件事是从维基百科获取表格。幸运的是熊猫正好有这个功能。
在上面的代码中,我使用read_html检索该表,将标题标识为第一行,并选择第一个表添加到 DataFrame 中。此时,我已经将文件加载到 Pandas Dataframe 中,但是仍然需要将该文件导出为 CSV 文件格式。在此之前,我注意到摄取的数据有问题。
如您所见,我仍然需要删除显示在结果中的引用注释。为此,我添加了一个正则表达式来去掉这些注释。
首先将数据帧转换成 CSV 文件更容易,所以在应用正则表达式去除注释之前,我先转换了数据格式。在这一点上,我需要做的只是写入我希望数据驻留的文件,数据集已经成功地到达了预期的目的地。
如果您想将此代码用作参考实现,这里是运行来更新数据集的最后一个 main 函数。
由 Github 操作运行的 main.py
Github 操作工作流程
此时,我能够从 Wikipedia 获取该表,并将清理后的结果写入 CSV 文件。下一步是现在安排这个过程,当且仅当数据改变时,将结果提交给 Github。
在我构建动作工作流的步骤之前,我需要安排它每小时运行刚刚开发的代码。为了做到这一点,我需要以预定义的 yaml 格式为每小时的频率定义 cron 调度。
在构建我的工作流之前,我想定义 Github 动作需要运行的图像。为了简单起见,我只是让它使用最新版本的 ubuntu 运行,但在未来,一旦我有时间更深入地进行操作,我会使用一些更轻松的图像,如 python slim 版本或 alpine。
这个 Github 动作在它的工作流程中有许多步骤,在此之前,数据集可以被监控是否有变化。我们 cron 工作流的第一步是签出我们主分支的工作副本。我最近在实验中注意到,这通常是我利用的大多数行动的第一步。
在上面的第 4 行和第 5 行中,我们实际上不需要指定提取深度,因为默认值是 1,但是这定义了要提取的提交数量。起初,我打算尝试用它来比较数据集的版本,但正如你稍后会注意到的,这是一个不需要探索的兔子洞。我能够使所有这些工作合理化的方法是在我的文章中保留对该功能的引用,以供将来的读者查看。
既然我已经有了在动作工作流中运行的代码的工作副本,下一步将是让 Python 3.8 设置开始运行代码。和前面的步骤一样,下面你可以看到 Github 也为此提供了一个动作。Python 版本很容易设置,但是对于我的例子来说,目标是 3.8。
现在我们已经安装了 Python,我们希望安装所需的库。我在这个 repo 中包含了一个 requirements.txt 文件,但是这个步骤也可能是一个pip insall pandas lxml。
在工作流中的这一点上,运行我们的代码以更新数据集所需的一切都已经提供给了环境,因此在这一步中,我们现在将这样做。
此时,我们拥有数据集的最新版本,该版本可能已更改,也可能未更改。因此,我们在这里要做的只是提交,如果数据已经更新,就推送。注意这里我们提前退出动作,如果是这样就不要推了。这里可以使用一些不同的模式,但是如果你好奇的话,Simon Wilson 在这里提到了一些。否则,一个干净的方式来实现我们想要的可以在下面找到。
这是其全部荣耀中的操作流程,您可以随意使用,但此时只需提交不到 10 行的 Python 代码和带有操作工作流的 yaml,一切都应设置为保存历史的版本化数据集。
我通常会发现,当我有一个参考实现时,工作起来会更容易,所以这里是包含完整代码库的 repo,其中包含我刚才单步执行的操作工作流。
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/dylanroy/ceo-dataset)
关键要点
正如你所看到的,它实际上很容易接收,并保持数据集最新,而不需要你自己的基础设施和一点点代码。Github 动作为简单的自动化提供了更多的选择。在这篇文章的例子中,我的回购是公开的,所以为了支持开源项目,Github 完全免费。
正如你从我的旅程中看到的,用一点 Python 知识,利用 Github 动作开始保持数据集更新并不困难。
我有另一个教程,我将在本周出版,所以请随时关注我,这样你就不会错过它,如果你对我的其他教程感兴趣,我将它们列在下面。
阅读迪伦的其他教程
停止花费时间手动调整未对准的箭头
towardsdatascience.com](/create-beautiful-architecture-diagrams-with-python-7792a1485f97)
资源
- https://simonwillison.net/2020/Oct/9/git-scraping/
- https://til . simonwillison . net/til/til/github-actions _ commit-if-file-changed . MD
- https://pandas . pydata . org/pandas-docs/stable/reference/API/pandas . read _ html . html
简单的可视化非常棒
如果你像我一样不擅长 Viz,我们还有希望

图表中的图表(作者:Randy Au)
我必须承认,我有萝卜的艺术和视觉技巧。
这并不是说我曾经欺骗过自己,假装自己很擅长——我几乎总是依靠非常简单的日常工具,体面地过日子。但是在最近的一次团队场外活动中,我突然发现我已经变得对它超级适应了,这是一种非常奇怪的感觉,因为我真的应该改进这样一个缺陷。
触发这种认识的事件是由我上面的集团董事 2 组织结构图级别主持的 UX 峰会。大约有 100 人出席,包括我们产品领域的所有 UXers,所以在人群中有设计师、研究人员、作家和工程师,大概是这个顺序。我想房间里有两个量子 UX 研究员,包括我自己。
该活动的部分活动涉及一系列 10 个 3 分钟的闪电谈话,我是其中之一。人们谈论他们学到或做过的事情,在会议上做研究,他们开发的有趣的新功能,组织研究的框架,等等。我完全专注于品牌,正在谈论我的团队建立的流程,该流程用于设置和监控功能工作的成功指标。
当我那天看完所有的演示时,我意识到每个人都在使用漂亮的图形、可视化、照片,甚至视频剪辑,来讲述他们正在讲述的任何故事。有设计背景的人在这方面尤其出色,他们使用了一些最令人惊叹的设计图形和可爱的 gif 口音。
与此同时,我用默认的谷歌幻灯片字体在白色背景上显示黑色文本。我对设计的唯一认可是从 UX 团队的模板中复制的标题卡。回想起来,肯定有很多地方都有时间表、示例度量图等。,会更容易理解。但是在准备的几周里,我没有想到把一个很长的演讲缩短到 3 分钟。在那模糊的 360 秒里,我所有的话,以及从我嘴里说出来的一切。
虽然这个故事主要是说我在演讲时缺乏对设计和美学的优先考虑,但我向你保证,这个性格缺陷适用于我制作的任何图表。斯巴达是描述事物的好方法,这是我需要努力的地方。
作为数据人员,我们最重要的职责是将我们的发现和结果传达给其他人。无论是授权给决策者,帮助团队达成共识,还是向客户提供信息,都需要沟通。如果我们在最后一步失败了,我们的结果是否是完美的预言也没有关系。视觉化通常对沟通过程非常重要。一幅制作精良的图像,即使是非常简单的图像,也能比文字更好地表达观点。
现在著名的“拉平曲线”图形可能是过去几个月中“简单但强大的 viz”最突出和最令人难忘的例子。顺便说一句,在这里可以很好地看到这个图形的历史。
类似地,一些陈述只能通过可视化来理解,比如选举地图,网络地图。数据点太多,很难用文字来概括。
所以,我只想说,在这个角色中拥有视觉化技能从来都不是坏事。我想不出在任何情况下成为数据可视化的大师会有什么坏处。
令人惊讶的是,你可以用非常非常少的这些技能走多远,这里是我在生活中使用的几个工具。
Lv 1:简单的可视化往往就足够了
大概 99%为工作制作的图表都是用电子表格制作的。开始时,我可能会用复杂的 SQL 和代码处理大量的数据,但最终的演示步骤通常很小,足以放入一个简单的电子表格,可能还会有一个数据透视表,以便我可以播放、格式化和扩充最终的图表结果。
剩下的 1%时间是我不得不依靠 Python 或类似语言中一些更强大的外部工具。这是如此的罕见,以至于我每次做的时候都要查阅文档来绘制一个折线图。我不知道如何使用 D3 或者其他强大的工具。但是尽管我能力有限,我还是设法一瘸一拐地走了下去!
到处都是线!
如果要我猜的话,我的图表中有超过 70%是简单的线形图,你可以在 Windows 上最多通过 6 次按键(ctrl-a,alt,n n,1,enter)从 Excel 中输出。当他们在功能区上添加了太多功能时,他们在命令链中插入了一个“1”,多么令人讨厌。

我的大多数演示图表看起来都像上面这样😜。垂直的“启动”虚线是我的一个花哨的 viz 技巧。我不得不做太多的前/后分析。
我制作的另外 20%的图表只是条形图的变体,水平的或垂直的。剩下的部分是面积图(反正只是彩色的堆叠线)、堆叠条形图,偶尔我会用烛台图来近似误差棒线。我几乎从来不预测未来,所以我从来没有真正制作过误差界限线图,没有专门的软件包很难制作。

大多数时候,只要有适当的标签,一张类似上面的图表就足以让我理解我需要理解的任何一点。事情呈上升趋势,目前的指标与历史水平相似,我们没有因为发布而破坏系统,等等。诸如“样本量小,所以误差可能很大”这样的警告是通过画外音、脚注或添加到标题中来传达的。
这对于半正式的团队工作非常有效,在这种情况下,我们需要快速查看数据点或趋势,做出决定,然后永远不要再查看相同的图表(我们可能会在未来查看更新的图表)。将数据转换成适合图表的格式(装箱、标准化、剔除工件等)已经够麻烦的了,改进演示文稿的边际收益是不值得的。
对于更高级别的涉众的更正式的演示,出于演示的原因,我将在表面样式上投入额外的精力。升级通常包括确保所有标题、轴和图例都格外清晰,添加线条粗细/破折号以增加/消除强调,异常数据点在脚注中附有解释,等等。
在一天结束的时候,一个美学上令人愉悦的图表比一个有着相同内容的非常丑陋的图表更令人难忘。你也不希望小瑕疵分散你的主要信息。
Lv 2:图表。但是用语言
当我出于演示目的需要让变得真正奇特时(不可否认很少),我通常会拿出带注释的折线图,如下所示。这是一种为令人沮丧的时间序列提供更多背景信息的方式。同样,所有这些都是用 Excel 或工作表中的透明色块和文本框完成的。这是我的努力,也是我艺术能力的上限。

我在 Photoshop 中根据内存重新创建示例图表,因为在电子表格中我想要的地方人为地创建带有任意屈折的弯弯曲曲的长线条很烦人。这个图表的目的是简单地提供一段时间内的销售情况。因为每时每刻都有一大堆事情在发生,有时还会重叠,所以不可能找出哪些时间段足够相似来进行比较。
所有的注释和框都是手工完成的,这是一个巨大的时间投资,所以它被保留到需要理解回报的时候。我的颜色感觉特别差,所以当我需要在一个图表中包含 6 种以上的颜色时,事情变得非常难看,它们看起来不可能都一样,但也不能相互冲突。恶心。
尽管成本很高,但在图表上手写注释远比争论独立的数据系统要痛苦得多,我需要将这些独立的数据系统组合起来才能使其工作。其中一些数据点只存在于人们的头脑或随机的电子表格中。
Lv 3:更硬的东西通常有另一个用途
简单的视觉化很擅长清楚地表达一两点,因为它们能够编码的信息量是有限的。你可以用注释和颜色之类的巧妙技巧再多塞进去一点,但是还是有限制的。
除了简单的东西之外,当需要的时候,我会拿出一些更复杂的东西,但是我发现它们有不同的用途。地图、桑基图、网络流程图、动画,这些可视化的复杂性意味着人们需要时间来消化它们,或者它们是为探索而设计的。在某些情况下,它们有助于分析和理解,但在我个人的日常生活中却没有用。

来自https://developers . Google . com/chart/interactive/docs/gallery/Sankey的 sankey 示例
由于不熟悉制作这些可视化效果的细节,我主要依靠预建的版本来制作。Excel 的映射功能惊人地强大(我一生中已经做了足够多的 ZIP->FIPS 映射,以至于还想再做一次),有一些库可以根据需要制作桑基图。漏斗下降图我只是慢慢地用手或黑一个条形图来做。

懒人群组分析
有时我会给一个数字网格着色,就像队列分析一样…然后把它作为一个缩小的图形来阅读。它足够接近于我的大脑进行分析的可视化,而不需要实际做些什么。仅仅通过观察数字的形状就能很容易地看出模式。
吕∞:遥不可及的东西
当我想到我永远也做不了的非常酷的 vis 时,我会想到那些经常来自纽约时报数据团队、卫报或流动数据网站的工作。
其中许多都是复杂的设计,显示了对显示的每个像素投入的许多小时的工作。即使是简单的折线图和条形图,通常也是精心设计的,设计元素经过深思熟虑,颜色经过精心选择,轴和标签经过精心着色,不引人注目但又清晰可见,等等。
这并不是说我没有时间来制作如此美丽的图形,如果有一千个小时的空闲时间来尝试,我真的无法自己制作一个。我能做的最好的事情就是盲目地模仿,很可能会失败。
但至少,我可以坐在我的椅子上,欣赏我知道有人花了一些时间的小细节,因为默认设置(如果默认设置存在的话)看起来永远不会完全轻松。
尽管缺乏美感,但仍有影响力
考虑到我的 Lv 2 有多简单。问题是,你可能想知道你能走多远。
举例来说,这是我迄今为止 12 年多职业生涯中最好的(即最有影响力的)图表。这是一个“奇特”的双图形——棒线!再次在 Photoshop 中重新创建,但原始版本是许多年前在 Excel 中完成的,所以想象一下它的块状,锯齿状,默认红/蓝荣耀。由于我的记忆有缺陷,细节被更改以掩盖起源,并且在公共场合随意挥舞任何人的客户保持数据都不是件好事。

这张图表背后的故事是这样的:我的老板要求我做一个“是什么驱动了留存”的分析,因为一些投资者问了这个问题。在花费数周时间进行大量数据清理和大型回归分析后,一个没有人真正关注的因素出现了。分析该因素的结果变成了这张图表,它本质上是说“在续订时有净积极的[特定类型]活动意味着非常高的保留率!”。
我之所以称之为“我最好的图表”,是因为这个简单的图表能引起人们的讨论。产品人员很快意识到,他们可以做出改变,让许多客户的“净活动”增加 1 到 2 个单位。该公司并没有真正考虑过移动网络活动统计,他们认为这只是系统的一个有机属性。人们很兴奋,他们开始试验,几个月后,他们发现了针对用户共鸣的指标的非常棒的功能设计。
突然之间,整个公司的指标同比增长了 40%,而此前有一段时间,这一数字一直停留在 15%。我们的产品开发相当于一口油井,这张图表是我们最初的地图。太疯狂了。我们也不知道这种极高的增长会持续多久。人们不断问我这个问题,我没有办法模拟前所未有的增长。它最终持续了近 18 个月,才平息下来。狂野。
我完全意识到我在这里非常幸运。在整个职业生涯中,找到这种影响程度的图表可能只有一两次。许多我无法控制的事情都是为了让这种情况发生,包括发现一个流行产品中被严重忽视的方面,管理、工程和产品都兴奋地测试这个想法,以及人们偶然发现有用的设计和功能。
但是只有那一次,它成功地组合在一起,并且它全部来自一个巨大管道末端的一个大 SQL 查询的 CSV 转储,最后被扔进 Excel。除了轴标签之外,它甚至没有注释。图中嘈杂的极端情况(由于样本量小,保留率变得很高)被留在了所有嘈杂的荣耀中。我很确定我用默认的 Excel 蓝色和红色离开了图表。
我很确定,当时,我知道这个图表在说一些重要的东西,但是我认为它会是另一个一次性图表。我把它展示给人们,以获得我需要为一个完美的版本所做的改进的感觉……但是从那以后它就像病毒一样传播开来,所以我从来没有机会清理它。哦好吧。
¯_(ツ)_/¯
最初发表于 统计数据 ,兰迪的免费每周时事通讯涵盖了数据和技术中更平凡、更重要的部分。
在 scikit-learn (Python)中为您的数据找到合适算法的简单方法
入门
使用这种实用的方法解决监督学习问题
在建立模型时,数据科学家需要选择合适的机器学习算法来使用。使用我们最喜欢的算法很有诱惑力,但是,对于数据来说,它可能并不总是正确的。那么我们如何从所有可用的选项中选择一个合适的算法呢?一个好的方法是在你的数据上尝试多种算法,从选项中选择一个或几个性能最好的算法来进一步微调。这个想法并不新颖。事实上,它可能是你已经以某种形式在做的事情。在这篇文章中,我将展示一种有组织地尝试多种算法的方法。

1.准备数据📦
如果你想跟随你电脑上的代码,确保你有numpy,pandas,seaborn,sk learn和 xgboost
假设我们想为一个分类问题找到一个合适的机器学习算法。对于我们的示例,我们将使用 titanic 数据集中的一个要素子集。让我们导入相关的包和示例数据:

让我们将数据分成训练集和测试集。我们还将定义对以后预处理数据有用的特征组:

我们现在将准备几个自定义的转换器来预处理数据:
◼ ️️ Imputer:用一个常量值进行估算,并在熊猫数据帧中返回估算的数据
◼ CardinalityReducer:将不常用的类别聚集到“其他”类别中,并在熊猫数据帧中返回转换后的数据
你会注意到,这篇文章中定义的大多数自定义函数或方法都返回数据帧,因为它们更容易查看。
现在,让我们转换数据。我们将并行预处理数字和分类特征。使用ColumnTransformer和Pipeline,我们将:
- 将数据分成两组:分类数据和数字数据
- 对每个组应用不同的变压器组
- 将结果粘贴在一起
如果这是你第一次看到ColumnTransformer和/或Pipeline,下面的代码可能不容易理解。如果你想了解他们更多,我已经专门写了一个单独的帖子来解释这两个。

部分输出
2.评估多种算法🔧
现在,我们已经到了这篇文章的关键部分。利用您对数据和建模技术的了解,您可以选择一组潜在的候选者来尝试您的数据。例如,探索性的数据分析可能已经暗示了一些关于哪种算法可能对数据有效的方向。另外,你的机器学习算法的理论知识也可以指导你。像这样的小抄可能也会派上用场。
一旦你有了一套要尝试的算法,你就可以对数据逐一尝试每一种算法。然而,使用一些功能,我们可以让这个过程更有条理。这些功能的想法是从这里得到的启发。
我们将需要定义我们决定在create_baseline_classifiers函数中的数据上尝试的所有算法。在这个例子中,我们使用的是开箱即用的分类器,没有任何超参数调整。但是,如果您愿意,可以在这个阶段调整超参数。我们在这里包括了虚拟分类器作为基准:
assess_models()目前的定义方式使其能够创建多个指标的绩效总结。但是,如果您愿意,也可以只包含一个指标。或者,我们很快会看到如何从输出中提取单个指标性能。现在,是时候根据训练数据评估模型并比较它们的结果了:

使用我们创建的第三个函数,让我们根据一个单独的指标来比较所有的模型:ROC 曲线下的面积。

这是一个非常有用的总结,不是吗?只看平均表现是不够的。因此,我们在这里包括了其他列,以便为我们提供关于跨褶皱性能的更详细的信息。在分析了结果之后,我们应该列出候选名单,并把我们的努力方向放在微调一个算法上,或者如果你愿意的话,一个精选的前几个算法。
这种方法也可以很容易地修改成回归问题。例如,下面是一个创建多个回归变量的示例函数:
我发现这些函数对数据科学项目很有用!⭐️,我希望你也是。
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。
谢谢你看我的帖子。我希望你能在你的监督学习项目中使用这种方法。如果你感兴趣,这里有我的一些帖子的链接:
◼️ 用这些提示整理你的 Jupyter 笔记本
◼️ 探索性数据分析指南
◼️python 中的探索性文本分析
◼️️ 给熊猫用户的 5 个提示
◼️️ 在熊猫中进行数据聚合的 5 个提示
◼️️ 在熊猫中编写 5 个常见的 SQL 查询
再见🏃💨
自然语言处理中的简单单词嵌入
单词嵌入是一种将单词或短语表示为实数向量的语言建模技术。这些单词被组合在一起以获得具有相似含义的单词的相似表示。单词嵌入学习单词之间的关系来构建表示。这是通过各种方法实现的,如共生矩阵、概率建模、神经网络。它已经成为自然语言处理的基础知识之一。

乔恩·泰森在 Unsplash 上拍摄的照片
一键向量是单词的简单表示之一。每个单词都可以用一个热向量来表示,但是随着单词数量的增加,维数也会增加。单词嵌入通过使用各种方式来减少单词向量的维数,例如单词如何集体出现,如 King、Queen 或可以交替使用的单词,如 car、vehicle 等。所以相似的词用相似的向量表示。这降低了向量的维数。虽然一个热点向量很容易构建,但通常没有一个好的选择来表示大量的单词。这是因为它确实允许表达语料库中单词之间的相似性。
Word2Vec,GloVe 是流行的单词嵌入。伯特是一个最新的单词嵌入。
单词嵌入分为两种类型
基于频率的嵌入—计数向量、共现向量、哈希向量器、TF-IDF
预训练的单词嵌入— Word2Vec、GloVe、BERT、fastText
本文讨论了基于频率的嵌入及其在自然语言处理问题中的应用
频率基嵌入
基于频率的嵌入根据单词在文本/文档中出现的频率对文本进行矢量化。使用频率基嵌入的一个例子可以在文本分类中使用。考虑到我们将文本分为不同的技术、政治、经济等类别。使用基于频率的矢量器,例如计数矢量器,对文本中的单词进行矢量化。然后根据频率矢量化得到的向量对文档进行训练。编写的模型将能够预测文档类型。这是因为有些词在每种类型的文档中出现的频率会更高。与政治或经济文档相比,技术文档会有一套不同的词汇。
计数矢量器
CountVectorizer 是一个非常简单的矢量器,它获取文本中单词的频率。CountVectorizer 用于将文本文档集合转换为单词/单词计数。
考虑文本“杯子在桌子上”
Data =['The ',' cup ',' is ',' present ',' on ',' The ',' table']
这可以矢量化为

计数矢量化可以通过 Sklearn 的 CountVectorizer 完成。下面是使用它的例子。计数矢量器根据单词在文档中出现的频率对文档进行编码。CountVectorizer 给出了文档中单词/ n 元语法的频率的稀疏矩阵。这对于创建文档分类、文档聚类、情感分析

同现向量机或 N 元语法
ngram_range 的默认参数是(1,1),它从文档中一次取一个单词的频率。ngram 范围给出了单词的下限和上限。这是必需的,因为有些单词如果单独使用,并不能给出完整的意思。例如,以文本“好书”、“好书”、“一美分”、“相当便宜”为例。在这些例子中,单词“nice read”的集合给出了比单个单词更完整的意思。

计数矢量器从文本中提取特征的简单方法之一,这些特征可以在以后的模型开发中使用。
哈希矢量器
HasingVectorizer 类似于 CountVectorizer,但它不存储文档的词汇。它使用散列来查找令牌字符串名称到特征索引的映射。

哈希矢量器将文档转换为包含标记出现频率的稀疏矩阵。根据 norm 参数,这被归一化为令牌频率。可以是 l1 范数,也可以是 l2 范数。
哈希矢量器有几个优点。
因为不需要存储词汇词典,所以减少了存储器消耗。
因为它不保持任何状态,所以浸酸和去浸酸很快。
由于没有使用状态,它可用于流式或并行管道数据。
这有一些缺点
不可能检索字符串名称,因为它们没有被存储。
如果特征的数量较少,则可能存在特征共谋。
没有 IDF 加权,因为它会呈现此状态。
当您拥有大型数据集时,最好使用哈希矢量器,因为它可以减少内存消耗并加快算法速度。如果数据集很小,那么最好使用计数矢量器,因为它很简单。
TF-IDF 矢量器
简单的基于频率的矢量器有时可能达不到目的,因为它只给出单词的频率。TF-IDF 矢量器试图解决这个问题。TF-IDF 是“词频—逆文档频率”的首字母缩写。
TF —术语频率:这是单词在文档中出现的次数
TF =(单词在文档中出现的次数)/(文档中的单词数)
IDF-逆文档频率:这将缩减文档中频繁出现的单词。
IDF = log_e(文档数/出现该术语的文档数)
基本上,TF-IDF 增加了对文档重要的单词或标记的值。
搜索引擎使用 TF-IDF 对与查询相关的文档进行排序。



CountVectorizer 给出了单词使用的绝对数量,但是 TF-IDF 给出了单词在文档中的重要性。
考虑一个文本分类问题。有些词在某种文件中很重要。考虑到关于药物的文档中会有一些医学术语,这些术语在文档中会很重要,TF-IDF 会突出显示这些术语。类似地,考虑与体育相关的文档,TF-IDF 将突出显示与体育和游戏相关的术语。
使用单词嵌入解决简单文本分类问题
让我们看看简单的测试分类问题,并使用单词嵌入来解决它。
这是一个垃圾短信分类的问题。这是从拥有 CC0 许可证的 Kaggle 获取的数据集。

将信息读入熊猫数据框。

使用计数矢量器作为单词嵌入
用计数矢量器拟合单词嵌入

使用 Sci-kit 中的标签编码器学习编码标签

将数据集分为训练数据集和测试数据集。

现在我们使用 Keras 创建一个简单的神经网络模型。

我们创建了一个简单的模型,有两个隐藏层,分别是 64 个节点和 32 个节点。我们已经使用 Softmax 层获得了火腿和垃圾邮件的输出。
我们使用 adam optimizer 进行优化,使用分类交叉熵进行损失。

我们可以使用 evaluate 函数来评估我们的模型


用 TF-TDF 做词嵌入 用 TF-TDF 拟合向量

使用 Sci-kit 中的标签编码器学习编码标签

将数据集分为训练数据集和测试数据集。

现在我们使用 Keras 创建一个简单的神经网络模型。

我们创建了一个简单的模型,有两个隐藏层,分别是 64 个节点和 32 个节点。我们已经使用 Softmax 层获得了火腿和垃圾邮件的输出。
我们使用 adam optimizer 进行优化,使用分类交叉熵进行损失。
评估模型



预测函数可用于进行预测。
得到模型的概要。

使用哈希矢量器作为单词嵌入
用哈希矢量器拟合矢量

标签编码器的使用和模型的创建保持不变。



我们看到参数的数量减少了,这取决于所用特征的大小。
结论
计数矢量器、散列矢量器和 TF-IDF 矢量器可用于为自然语言处理任务的单词创建单词嵌入。
在哈希矢量器中,参数所需的内存较少。参数的数量取决于特征的大小。此外,在哈希矢量器中,由于词汇不存储在哈希矢量器中,因此节省了词汇的存储量。
对于稍微复杂的分类工作,TF-IDF 获得了更好的准确性,因为单词在特定类型的文档中的出现被赋予了重要性。
作者
斯里尼瓦斯·查克拉瓦蒂——srinivas.yeeda@gmail.com
钱德拉舍卡——chandru4ni@gmail.com
Python 中的简单单词云
💡 单词云 是一种可视化文本中频繁出现的单词的技术,其中单词的大小代表它们的频率。
创建单词云的一个简单方法是在谷歌上搜索“单词云”,找到一个可以生成单词云的免费网站。你可以自定义它的外观。又快又简单!
更令人兴奋的是,您可以用 Python 自己构建一个💫。这篇文章将展示如何创建一个像下面这样的单词云。

第三节的词云。Fancier 单词云🌸
0.Python 设置🔧
我假设读者(👀是的,你!)可以访问并熟悉 Python,包括安装包、定义函数和其他基本任务。如果你是 Python 新手,这个是一个入门的好地方。
我已经在 Jupyter Notebook 中使用并测试了 Python 3.7.1 中的脚本。
在我们开始之前,让我们确保您已经安装了以下库:
◻️ 创建单词云: 单词云 ◻️ 导入图像: 枕头(稍后将导入为pil)◻️从维基百科中抓取文本:维基百科
最后一个包是可选的,你可以加载或创建自己的文本数据,而不必通过网络抓取拉文本。
1.数据📦
作为我们的样本文本,我们将使用从维基百科“网络抓取”页面上抓取的文本。
# Import packages
import wikipedia
import re# Specify the title of the Wikipedia page
wiki = wikipedia.page('Web scraping')# Extract the plain text content of the page
text = wiki.content# Clean text
text = re.sub(r'==.*?==+', '', text)
text = text.replace('\n', '')
🔗我已经在另一篇关于抓取的文章中解释了这个脚本的作用。简而言之,这个脚本将提取段落中的纯文本内容,并将其分配给文本字符串。
2.字云☁️
首先,让我们准备一个绘制单词云的函数:
# Import package
import matplotlib.pyplot as plt# Define a function to plot word cloud
def plot_cloud(wordcloud):
# Set figure size
plt.figure(figsize=(40, 30))
# Display image
plt.imshow(wordcloud)
# No axis details
plt.axis("off");
其次,让我们创建我们的第一个单词云并绘制它:
# Import package
from wordcloud import WordCloud, STOPWORDS# Generate word cloud
wordcloud = WordCloud(width= 3000, height = 2000, random_state=1, background_color='salmon', colormap='Pastel1', collocations=False, stopwords = STOPWORDS).generate(text)# Plot
plot_cloud(wordcloud)

Ta-da❕我们刚刚建立了一个单词云!以下是关于 WordCloud 函数参数的一些注意事项:
◼️宽度/高度:您可以使用这些选项将单词云的尺寸更改为您喜欢的宽度和高度。
◼️ random_state: 如果你不把它设置成你选择的数字,你很可能每次在相同的输入数据上运行相同的脚本时得到一个稍微不同的单词云。通过设置此参数,您可以确保完全相同的词云的再现性。你可以玩随机数,直到你找到你喜欢的单词云。
◼️背景 _ 颜色:‘白’和‘黑’是常见的背景颜色。如果你想探索更多的颜色,这个可能会派上用场。请注意,有些颜色可能不适用。希望你能找到你喜欢的东西。
◼️色彩图:通过这个参数,你可以设置文字显示的颜色主题。有很多漂亮的 Matplotlib 色图可供选择。我最喜欢的是“彩虹”、“地震”、“彩色 1”和“彩色 2”。
◼️ 搭配:将此设置为 False 以确保单词云看起来不会包含任何重复的单词。否则你可能会在词云中看到' web '、' scraping '、' web scraping '作为搭配,给人一种词被重复的印象。
◼️停用词:停用词是对文本意义几乎没有价值的常用词 We、are 和 the 是停用词的例子。我已经在这里更详细地解释了停用词(滚动到‘步骤 3。删除“停用词”部分)。这里,我们使用了来自 wordcloud 包的停用词。要查看停用词集合,使用print(STOPWORDS)并向该集合添加自定义停用词,使用此模板STOPWORDS.update(['word1', 'word2']),在生成词云之前用您的自定义停用词替换 word1 和 word2 。您还可以自定义其他参数。查看 文档 了解更多信息。
让我们用不同的背景颜色和颜色图生成另一个单词云🎨。你可以玩不同的组合,直到你找到你喜欢的。我觉得下面这个组合挺好的:
# Generate wordcloud
wordcloud = WordCloud(width = 3000, height = 2000, random_state=1, background_color='black', colormap='Set2', collocations=False, stopwords = STOPWORDS).generate(text)# Plot
plot_cloud(wordcloud)

假设我们对 word cloud 很满意,并希望将其保存为. png 文件,我们可以使用下面的代码来实现这一点:
# Save image
wordcloud.to_file("wordcloud.png")
3.Fancier 单词云🌸
我说的更好的单词云是指那些自定义形状的单词云,就像本文开头显示的那样。要创建一个花哨的单词云,我们需要首先找到一个图像作为遮罩。看来最大的挑战是找到正确的图像文件。你可以在谷歌图片上用关键词搜索图片:“屏蔽文字云图片”。在我的搜索过程中,我偶然发现了这个来源,一位慷慨的 kaggler 分享了一些有用的屏蔽图片。我在这篇文章的开头使用“upvote.png”来生成单词 cloud,使用了以下脚本(记得在运行脚本之前在当前目录中保存一份蒙版图像的副本):
# Import packages
import numpy as np
from PIL import Image# Import image to np.array
mask = np.array(Image.open('upvote.png'))# Generate wordcloud
wordcloud = WordCloud(width = 3000, height = 2000, random_state=1, background_color='white', colormap='Set2', collocations=False, stopwords = STOPWORDS, mask=mask).generate(text)# Plot
plot_cloud(wordcloud)
你会注意到,唯一的区别是我们将图像导入到了一个 numpy 数组,然后在 WordCloud 中添加了mask=mask。蒙版的一个特点是,最好将背景颜色设置为“白色”。如果我们尝试换成不同的颜色,单词 cloud 可能看起来不太好。让我们创建一个并查看:
# Generate wordcloud
wordcloud = WordCloud(width = 3000, height = 2000, random_state=1, background_color='navy', colormap='rainbow', collocations=False, stopwords = STOPWORDS, mask=mask).generate(text)# Plot
plot_cloud(wordcloud)

相对于拥有白色背景,你怎么看这个?我会让你来判断。
我喜欢单词云,并计划做一个(当然不是关于网络抓取的!🙈)用来当海报装饰我的房间。但是它也可以在其他环境中使用,例如在演示文稿和文档中作为视觉辅助。
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接 ,成为会员,您的一部分会费将直接用于支持我。
谢谢你看我的帖子。我希望你已经学到了一些东西,✂️.如果你感兴趣的话, 以下是我其他一些帖子的链接:
◼️ 用 Python 从维基百科中抓取文本的两种简单方法
(下面列出了一系列关于 NLP 介绍的帖子)
◼️ 第一部分:Python 中的文本预处理
◼️ 第二部分:引理和词干的区别
◼️ 第三部分:TF-IDF 讲解
◼️ 第四部分:Python 中的有监督文本分类模型
◼️ 第 5A 部分:Python 中的无监督主题模型(sklearn)
◼️ 第 5B 部分:Python 中的无监督主题模型(gensim
再见🏃💨
SimpleGAN —用 3 行代码训练 GAN
基于 TensorFlow 简化生成模型训练的框架

来源:https://pix abay . com/photos/fall-autumn-red-season-Woods-1072821/
介绍
近年来,深度学习背景下的生成模型领域一直在快速增长,特别是自从敌对网络出现以来。然而,训练这些模型并不总是容易的,即使你是一个只是试图在自定义数据集上复制结果的专家。解决方案: SimpleGAN 。SimpleGAN 是一个使用 TensorFlow 2.0 编写的框架,旨在通过提供高级 API 来促进生成模型的训练,同时提供强大的可定制性来调整模型和运行实验。
装置
安装 SimpleGAN 是一个非常简单的过程。有两种方法可以执行安装。
- 使用 pip 软件包管理器。
$ pip install simplegan
- 从源构建
$ git clone https://github.com/grohith327/simplegan.git
$ cd simplegan
$ python setup.py install
例子
现在您已经安装了软件包(如果没有,您应该😁),让我们来看两个例子,帮助你入门。
让我们看看如何使用 SimpleGAN 框架训练卷积自动编码器
Pix2Pix
现在让我们看一个例子,其中我们将利用对抗性训练来将图像从一个域翻译到另一个域,例如将分割图转换成具有细节的图像。看看这个链接。
来源:https://tenor . com/view/Cheetos-零食-饿了么-yum-gif-16187308
注意:
对于那些可能想知道“这不是 3 行代码”的人,上面的例子只是为了展示框架的可用功能,从技术上讲,你仍然只需要下面显示的 3 行代码来训练你的模型。
>>> gan = Pix2Pix()
>>> train_ds, test_ds = gan.load_data(use_maps = True)
>>> gan.fit(train_ds, test_ds, epochs = 100)
所以,是的,这不是一个诱饵。
重要链接
结论
开发该框架是为了简化具有高级抽象的生成模型的训练,同时提供一些定制模型的选项。我相信“边做边学”是理解新概念的最好方法,这个框架可以帮助人们开始学习。
来源:https://tenor . com/view/simple-easy-easy-game-easy-life-deal-it-gif-9276124
简化生成模型训练的框架 SimpleGAN 是一个基于 TensorFlow 的框架,用于对生成模型进行训练
github.com](https://github.com/grohith327/simplegan) [## SimpleGAN - SimpleGAN v0.2.8 文档
是一个使用 TensorFlow 构建的 python 库,旨在通过高级 API 简化生成模型的训练…
simplegan.readthedocs.io](https://simplegan.readthedocs.io/en/latest/index.html) [## 简单根
简化生成模型训练的框架 SimpleGAN 是一个基于 TensorFlow 的框架,用于对生成模型进行训练
pypi.org](https://pypi.org/project/simplegan/)
正则表达式简单指南
NLP 变得简单

如果你不知道正则表达式,它会被认为是很难和高级的东西,但是如果你知道,恭喜你,你知道很难和高级的东西。在这篇文章中,我们将揭示正则表达式的基础,在文章的最后,我附上了一个指向我的笔记本的链接,在那里你可以看到除了我们将在这里讨论的功能之外的三倍多的功能。
所以让我们从定义正则表达式开始:
正则表达式是定义搜索模式的字符序列。
它们被用在哪里?
正则表达式有广泛的用途:
- 文本预处理
- 根据某种模式提取文本,查找并替换某些符合模式匹配的单词,例如,查找所有以“a”开头的单词,并用单词 cat 替换它们
- 密码模式匹配
- 数据有效性
正则表达式在您的日常编码任务中起着至关重要的作用,此外,当涉及到数据清理、数据挖掘和其他过于庞大而无法硬编码的操作时,它还是一个超级强大的工具。我们创建一个正则表达式模式,在整个文本中滑动,匹配部分的位置或值返回给我们。
正则表达式模式匹配有两个部分:
1.正确的模式:它是关于找出我们真正想要匹配的东西
2.右 re 功能:与职位有关。不管我们是想匹配一开始的模式还是任何地方的模式。万一我们想要分裂和替换,我们也必须改变我们的 re 函数。
问题:给你两个文本,你必须找出它们是否以单词 corona 开头。
所以现在我们必须弄清楚两件事:使用什么模式,使用什么函数。
- 我们必须匹配单词 corona,所以 corona 是我们的模式字符串。
- 对于函数,我们将选择
re.match,因为我们需要找到字符串是否以图案电晕开始。 re.match接受 3 个输入- >模式匹配、需要搜索的文本和标志。我们稍后会谈到旗帜。
输出:
<re.Match object; span=(0, 6), match='corona'>
None
如果模式与字符串匹配,则返回一个匹配对象,否则不返回任何对象。
在匹配的情况下,如在result_text1中,返回具有三个属性的匹配对象:
.span():返回包含匹配开始和结束位置的元组。.string:返回传递给函数的字符串.group():返回匹配的字符串部分
输出:
Span of result_text1: (0, 6)
String passed to result_text1: corona epidemic has taken world by storm.
Groups in result_text1: corona
与re.match的问题:
- 这是一个非常好的函数,只在开始的时候匹配字符串。
- 如果我们想要匹配字符串中的任何地方,我们使用
re.search。它的工作原理和re.match一样,但是允许我们匹配字符串中的任何位置。返回一个匹配对象,如果没有找到匹配,则返回无。
输出:
<re.Match object; span=(0, 6), match='corona'>
None
<re.Match object; span=(29, 35), match='corona'>
re.match和re.search的限制
re.match只能在开始时匹配,而re.search可以在任何地方匹配,但只返回第一个匹配。原因是re.search是为了查找字符串中是否存在模式而设计的。如果我们想要返回所有的匹配,我们使用re.findall。事实上,re.findall默认用于模式匹配,因为通过各种标识符和条件,它可以表现为re.match & re.search。
<re.Match object; span=(0, 6), match='corona'>
['corona', 'corona']
如果我们想替换模式匹配我们选择的字符串的地方,该怎么办?
假设我们想用新冠肺炎病毒取代所有出现的冠状病毒。为此,我们使用re.sub re.sub(pattern,replacement,text,count):模式是我们试图匹配的内容,替换是用来替换模式的内容,文本是我们搜索模式的内容。设定计数以替代有限的发生次数。默认情况下,它会替换所有引用。
输出:
coronavirus is causing international shutdowns. Neil Ferguson's report stated that coronavirus matches SARS.
COVID-19 is causing international shutdowns. Neil Ferguson's report stated that COVID-19 matches SARS.ONLY ONE OCCURENCE IS SUBSTITUTED IF WE MENTION COUNT = 1coronavirus is causing international shutdowns. Neil Ferguson's report stated that coronavirus matches SARS.
COVID-19 is causing international shutdowns. Neil Ferguson's report stated that coronavirus matches SARS.
在模式匹配的地方拆分文本
re.split(pattern,string,maxsplit,flags) 模式和字符串是常用参数。maxsplit 表示我们最大希望进行多少次分割,默认情况下表示全部。我们稍后会谈到旗帜
输出:
['COVID-19 is ', 'virus, as of 24 March ', 'virus has causes more than 400,000 cases.']
字符串在匹配模式的地方被分割。由于上述字符串有两个电晕事件,它只是分裂它在两个地方,因此导致三个部分。将返回拆分列表。
正则表达式也是优秀的武器文本清理、文本挖掘和在一行程序中做复杂的事情。
其余功能请查看我的 Github 笔记本。正则表达式的其他高级特性将在此讨论:
[## iamchiragshama/正则表达式-NLP-Text
自然语言处理和机器学习的正则表达式。贡献给 iamchiragshama/正则表达式-NLP-Text…
github.com](https://github.com/iamchiragsharma/Regular-Expressions-NLP-Text)
在 twitter 上关注我,了解关于自然语言处理、深度学习和文本分析的更多更新:
Chirag Sharma 的最新推文(@csblacknet)。联合创始人 BlackNet |我创造可持续和实用的人工智能。印度
twitter.com](https://twitter.com/csblacknet)
最简单的方法来丰富你的熊猫数据框架

作者图片
熊猫真的很棒,有深度,有文档。您可以快速导航并了解有关重塑数据、处理不同格式(如文本、时间序列、分类数据、合并、可视化等)的一切。但是,如果我说你的数据框架可以通过 https 与外部 API“对话”,你会怎么想?
如果你想一想,这里没有使用革命性的技术。我敢打赌,如果你现在停止阅读,思考几分钟如何让你的数据框架从“外部世界”获取数据,你会很快意识到事情很简单:
df.apply(lambda i: get_result(i[‘input_column_1’], i[‘input_column_2’]), axis=1)
其中 get_result()是一个与数据框架之外的世界“对话”的函数。在本例中,它采用 2 个参数作为输入:数据帧中的 2 列“输入 _ 列 _1”和“输入 _ 列 _2”。
这种方法有什么好处?
首先你需要意识到在 get_result()函数背后可能隐藏着什么。这里有很多选项,简单地说,任何将从外部 api、数据库或您能想到的任何其他东西获取数据的客户端库。
这里唯一的限制是您的结果必须以某种方式放回 dataframe 行:
df[‘result’] = df.apply(lambda i:
get_result(i[‘input_column_1’], i[‘input_column_2’]), axis=1)
注意:我们可以简化我们的。跳过 lambda: 应用()函数
*df.apply(get_result, axis=1)*
和处理熊猫系列里面的 get_result()函数。我更喜欢保持客户端 API 逻辑干净,避免不必要的 Pandas 处理,特别是如果来自其他系统的预测可能没有在输入上使用 Pandas 系列。
还不见效益?
这里最重要的是,您不必将数据帧转换为其他格式,或者将其保存在 API 客户端类可以从中访问数据、获取 API 结果并创建结果与原始数据帧合并的数据帧的地方。你只是一直呆在数据框“领域”里!
有些事情你必须知道。例如,get_result()必须处理出错且没有数据返回的情况。您需要使它适应您的情况,但是您可以尝试做的最简单的事情是实现自动“失败时恢复”。
另一种方法是用空值填充数据帧的所有失败结果。然后再次调用 apply()并只处理失败的行:
df[df.result.isnull()].apply( … )
“分批谈”
到目前为止一切顺利,但是如果您的外部 API 批量接受并返回数据会怎么样呢?假设你的数据框架有一个文本列,你想用基于该文本的情感分析预测来丰富你的数据框架。在这种情况下,您必须对数据帧进行切片,并将每批数据传递给我们的 API 客户端函数:
batch_size = 100for i in range(0, len(df), batch_size):
df.loc[df.index[i:i+batch_size], 'sentiment_prediction']
df.loc[df.index[i:i+batch_size],'text_column']\
.apply(lambda i:
predict_sentiment(i['text_column']), axis=1)
我们的数据帧正在按 batch_size 进行切片,其中“text_column”被发送到 be predict _ perspective()函数。
这两种解决方案都有一个问题。apply()逐行执行,或者在批处理的情况下逐批执行。换句话说,API 调用是按顺序执行的。
加速发展/走向“大数据”
像往常一样,这可以通过多种方式完成,但我将使用 Dask 来完成这项工作。
注意:这篇文章不是关于 Dask 的介绍,如果你不熟悉它,去看看关于 dask.org的真正友好的文档。
只需几个额外的步骤,您就可以将数据帧转换为 Dask 数据帧,从而处理内存不足的数据集。Dask 的伟大之处在于它试图尽可能地“模仿”熊猫 API。您可以在您的笔记本电脑上使用“本地集群”进行开发,或者使用多台机器相当容易地设置实际的生产就绪集群。
现在,使用 Dask dataframe 可以加快速度!假设我们的 API 可以同时处理多个请求,但是我们也应该尽量不要同时处理太多的请求。
因为 Dask 数据帧仅仅是 Pandas 数据帧的分区列表,所以对其调用 apply()将在每个分区上分别分配工作和并行执行。
让我们看看我们目前有多少分区:
*>> df.npartitions
14*
让我们更改块大小以获得 50 个分区
*>> df = df.repartition(npartitions=50)
>> df.npartitions
50*
现在调用 apply()将生成至少 50 个并行任务!让我们修改我们的代码以适应 Dask (注意:这里的 df 是 Dask dataframe,不是 Pandas dataframe) :
*df[‘result’] = df.apply(lambda i:
get_result(i[‘input_column_1’], i[‘input_column_2’]), axis=1)*
有什么变化?没什么!甜甜:)
注意:这里假设您正在使用有许多工作人员的集群。如果你在你的笔记本电脑上这样做,把你的分区数量设置为内核数量。
扩展批次
这里事情变得有点复杂,因为我们需要:
- 将我们的 Dask 数据帧分割成单独的 Pandas 数据帧(分区)
- 在每个分区上创建批处理
- 更新每个熊猫数据帧,这将导致更新整个 Dask 数据帧
Dask 没有提供多少方法来做到这一点。我将使用 map_partitions(),它只是在每个分区上应用函数:
*batch_size = 100def make_per_dataframe_predictions(pdf): # pdf is Pandas dataframe
for i in range(0, len(pdf), batch_size):
pdf.loc[pdf.index[i:i+batch_size], 'sentiment_prediction'] = \
pdf.loc[pdf.index[i:i+batch_size], ['text_column']]\
.apply(lambda i: get_result(i['text_column']), axis=1)
return pdfdf.map_partitions(make_per_dataframe_predictions).compute()*
注意:pdf.loc 索引在额外的括号中有“text_column ”,即使我们传递的是单列。因为我们想。在 dataframe 上应用(),如果没有括号,我们将对 Pandas 系列进行操作。
另外,请注意 Dask 要求。compute()实际结果。
警告词
在盲目应用上面介绍的任何解决方案之前,你需要考虑它如何适合你的情况。
一般来说,特别是在处理真正的大数据时,我建议避免这种新的“强大的知识”,并使用以下步骤将您的管道分成单独的任务:
- […在外部 API 的数据“丰富”您的数据框架之前,完成所有步骤…]
- 存储您希望用作 API 输入的数据帧和(可能是单独的)输入
- 编写单独的任务来加载预测的输入,生成预测并存储它们
- 加载你的数据框架,将你的预测加载到另一个数据框架中,然后合并它们
是的,看起来需要更多的工作,但是这种方法更安全,并且允许对每个步骤有更大的控制。
记住:这篇文章的目的不是向你展示你的数据框架如何与外界交流的实际技术。更多的是心态,如果运用得当,可以为你节省很多时间。
面向初学者的 Android MVP
让我们来理解这种设计模式是如何以更少的努力提供更大的维护大型项目代码的便利性的

在 Android 中,由于 Android 活动与 UI 和数据访问机制紧密耦合,我们遇到了一个问题。但是应用程序代码必须易于扩展、维护、阅读和测试,等等。为了实现所有这些,我们将使用 MVP 架构模式,它将应用程序分为三层。三层是模型、视图和演示者。
模型视图演示者(MVP)
- 模型:它处理我们应用程序的数据部分
- 视图:负责按照演示者的指示,用相关数据布置视图
- 展示者:它是连接模型和视图的桥梁
注意 : Presenter 是模型和视图之间的中间人,这意味着视图和模型不能直接相互交流。
使用 MVP 的好处
- 将用户界面的代码与业务逻辑分开
- 阻止模型(数据)和用户界面之间的直接通信
- 更改代码的一部分不会影响另一部分。
- 代码对于单元测试来说变得容易多了
现在把所有的理论部分放在一边,开始研究编码部分
我们将创建登录应用程序,以尽可能保持简单
在 ActivityMain.java 的课上,我简单地拿了两个编辑文本和一个登录按钮。我在这个活动中实现了LoginView interface,并覆盖了所有的方法——这些方法将基于用户提供的凭证被调用。如果username和password不是用户输入的,那么“Username can’t be empty”消息将显示给用户。我正在创建人工延迟来显示进度条。
ActivityMain.java
这里我声明了不同目的的方法,比如用户名错误和密码错误等等。
LoginView.java
这是最重要的类,有助于模型和视图之间的交流。
LoginPresenter.java
这个类包含了应用程序的业务逻辑,并且这个类决定了哪个方法将被调用。
LoginInteractor.java
输出:
当输入字段为空时:

当用户名和密码都正确时:

结论
MVP 架构模式没有普遍公认的定义。每个人都根据自己的需要实现这个模式,但是我们的目标应该是将代码分成至少三层,就像我们上面讨论的那样。
我希望你喜欢读这篇文章,你也可以访问我的 网站 ,在那里我会定期发布文章。
订阅 我的邮件列表,以便在您的收件箱中直接获得我的文章,并且不要忘记关注我自己在 MediumThe Code Monster上发表的文章,以丰富您的技术知识。
了解你的作者
希曼舒·维尔马毕业于印度勒克瑙的 APJ 阿卜杜勒·卡拉姆大学博士。他是 Android & IOS 开发人员、机器学习和数据科学学习者、金融顾问和博客作者。
使用 Python 简化 KNN 算法并提供编码说明
K 近邻,机器学习中最简单的分类算法之一
M 机器学习就是识别模式,创造自己的算法,并不断进化。模式通常由机器创建,它使用各种技术和算法。对于机器学习中的分类问题,k 近邻算法是一种最简单而有效的算法。它既可用于分类,也可用于回归问题,即它可以对任何特定事件/属性进行分类,甚至可以预测其值。这种方法因为比其他复杂的算法简单而被采用。它测量数据点之间的距离。测量距离会形成一个模式,以创建两点之间的关系。这就是它决定新数据点应该放在哪个组中的方式。

图片来自 nccalculators.com
如果我们需要计算上图中提到的两点之间的距离,比如说(XA,YA)和(XB,YB),那么可以使用一个简单的公式

以上是测量两点间距离的欧几里得方法。这种距离测量也可以有其他方式。遵循上述方法来计算各种数据点之间的距离。KNN 有两个独特的属性
- 懒惰学习算法:它被称为懒惰学习者,因为它没有任何专门的训练阶段,而学习意味着它没有预定义的规则。它只是消耗所有的数据,同时对一个新的数据点进行分类,并制定自己的规则。
- 非参数学习算法:它采用非参数方法,这意味着它不做任何假设。它不担心选择哪些特性。这种方法非常适合您事先不了解传入数据的情况。
由于这种无忧无虑的分类,KNN 算法各有利弊
优点:
- 对于大量数据来说,它非常有用
- 它在选择变量方面很灵活(没有假设)&可以适应大量的函数形式。
- 它可以在预测时提供更好的性能
缺点:
- 在估计映射函数时,它消耗大量的数据
- 它可以给出过拟合模型输出
- 由于训练时使用了大量参数,所以速度较慢。
- 不平衡数据集可能会给这种算法带来麻烦。

绘制在 2D 坐标系上的样本数据集
在 K 个最近邻中,K 的值表示与我们的新数据点具有最小距离的最近邻的数量。如果我们说 k=3,这意味着我们必须为我们的新数据点找出 3 个最近的邻居。如果有 3 个相邻点,其中一个来自红色数据集,另外两个来自蓝色数据集,那么新的数据点将被标记为蓝色。越多的邻居意味着分类越清晰,但是它增加了分类的复杂性和时间范围。k 值还有一个更重要的方面,它应该是一个奇数总是为了更好的分类,否则如果两种颜色的邻居数量相等,那么它将是一个平局。
让我们举一个例子,用 python 语言展示算法是如何工作的。为了在 python 中工作,我们需要调用某些库
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
这里的数据集是 python 框架上一些基本样本数据集的存储库。这些数据集可以用来做一些简单的实际建模。 Iris 是那个存储中非常有名的数据集。
sklearn 是 python 中最著名的数据科学包,拥有机器学习所需的几乎 70%的功能。在这里,我们导入一个函数,用于将数据拆分为测试和训练 (train_test_split)和 KNN 分类的 KNeighborsClassifier 。为了检查我们模型的准确性,我们再次使用来自同一个著名库包的 accuracy_score 。
iris = load_iris()
x= pd.DataFrame(iris.data,columns=iris.feature_names)
y = pd.Categorical.from_codes(iris.target, iris.target_names)
我们已经调用了 iris 数据集,并将目标变量从数据帧的其余部分中分离出来。这里 y 是目标变量,x 是将用于建模的数据集。
x.info()
来深入了解我们的数据集。它对正在处理的数据帧提供了相当多的洞察力。这是它的输出
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 sepal length (cm) 150 non-null float64
1 sepal width (cm) 150 non-null float64
2 petal length (cm) 150 non-null float64
3 petal width (cm) 150 non-null float64
dtypes: float64(4)
memory usage: 4.8 KB

使用 matplotlib 绘制的虹膜数据集
现在,我们将数据分成 70:30 比例的训练和测试数据。这个比例可以由程序员根据自己的意愿来选择,但更明智的做法是为训练数据提供一个合适的容量,并且还应该有合理的测试容量。
#Prepare data for classification process
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=0)
现在,我们准备使用下面的命令制作一个 KNN 模型。您可以在代码中看到,我们使用了 p 值为 2 的闵可夫斯基距离度量,即 KNN 分类器将使用欧几里德距离度量公式。
#Create a model
KNN_Classifier = KNeighborsClassifier(n_neighbors = 6, p = 2, metric=’minkowski’)
现在我们将使用 KNeighborClassifier 训练模型,这里 k 的值是 6。(是的它是偶数,看复杂程度)
KNN_Classifier.fit(x_train, y_train)
在对模型进行训练之后,将通过使用以下命令,使用同一个经过训练的模型对测试数据进行测试
pred_test = KNN_Classifier.predict(x_test)
基于为所有数据点计算的距离,我们找出有多少邻居指示哪一侧。一旦选择了顶部最近的邻居,我们检查邻居中投票最多的类
#check the accuracy of your predicted classifier
acc = accuracy_score(y_test, pred_test)
通过使用这个命令,我们可以检查我们设计的模型的准确性。好的价值意味着更好的建模。为了识别过拟合模型特征,必须检查测试数据和训练数据的准确性。
结论:
该模型为其下一个任务做好了准备,并且不需要再次训练。如果我们输入更多的数据,模型会发展得更好,结果也会更好。我们必须确保所提供的数据是干净的,缺失值已被处理,因为机器无法正确处理缺失值数据集。
使用 Alibi Detect 简化图像异常检测
入门

离群 名词
out li er | \ ˈau̇t-ˌlī(-ə)r
1:在数值上明显不同于样本中其他人的统计观察值
2:在某一特定群体、阶级或类别中非典型的人或事物
O 异常检测是对与大多数数据有显著差异的数据集元素的识别。这些元素被称为异常值,检测它们有各种动机,这取决于每个案例的领域。一个典型的例子是欺诈检测,其中金融数据集中的异常值可能表示欺诈活动,如使用被盗信用卡的交易。异常值检测也可以用于网络入侵检测,其中异常值是可疑网络活动的记录,指示可能试图获得未授权的访问。上述情况是应用于表格数据的异常值检测的示例,但是它也可以用于其他数据类型,例如图像。工业制造中的质量控制就是使用异常值检测来识别产品图像中的缺陷。
异常值检测有三种基本方法。首先,无监督方法既不需要关于离群值的任何信息,也不需要关于正常元素的任何信息。另一方面,半监督方法需要在一组正常元素上进行训练,并且能够检测那些显著不同的元素。最后,监督方法需要一个带有内点和外点的标记数据集,使它们类似于分类算法,特别适合不平衡的类。关于离群点检测的更详细的介绍,我建议你阅读这篇文章。
不在场证明检测
Alibi Detect 是一个开源 Python 库,用于异常、敌对和漂移检测,包括各种强大的算法和技术。它还支持各种数据类型,如表格、时间序列和图像。这里列出了 Alibi Detect 包含的所有异常值检测算法,后面的表格显示了每种算法的可能用途。关于每个算法的更多信息,以及相关的研究论文,都包含在链接的文档页面中。
离群点检测算法

Alibi 检测库中包含的每个算法的建议用途
自动编码器
自动编码器是一种人工神经网络,由编码器和解码器组成。编码器将输入转换为潜在空间表示,而解码器接收该表示并输出输入数据的重构。自动编码器有各种各样的应用,比如降维和图像去噪,但是在本文的范围内,我们将把重点放在图像异常检测上。

一个简单的自动编码器架构图来自 Comp Three Inc
在图像异常值检测的情况下,这种类型的神经网络被称为卷积自动编码器,因为编码器和解码器部分由卷积神经网络组成。离群点检测自动编码器在图像数据集上被训练,并且之后能够重建作为输入提供的相似图像。如果输入图像和重建输出之间的差异很大,则该图像可以被标记为异常值。
mv tec 广告数据集
在现实世界条件下测试离群点检测模型的准确性可能具有挑战性,因为数据集离群点的数量通常是我们未知的。我们可以通过在专门为测试目的而创建的数据集上训练我们的模型来克服这个障碍。

MVTec 广告数据集的示例图像—图像由 MVTec 软件有限公司提供
MVTec AD 数据集包含数千张高分辨率图像,适合测试和基准测试图像异常模型,重点是工业制造质量控制。数据集由 15 类图像组成,如地毯、皮革、晶体管、螺丝等。每个类别的训练集仅包括正常图像,而测试集既有正常图像又有带有各种缺陷的异常值。有关数据集和各种异常值检测算法的基准测试结果的更多信息,可以参考相关的研究论文。
带有 Alibi 检测的异常值检测
我们现在将基于 Alibi Detect 库的自动编码器算法创建一个图像异常值检测模型。该模型将在 MVTec AD 数据集的胶囊图像上进行训练和测试,遵循半监督方法,因为训练集将仅由正常(内层)图像组成。
我们从导入必要的库、类和函数开始。之后,我们创建一个函数,从给定的路径加载所有的图像,并将它们转换成一个 numpy 数组。我们使用该函数为我们的模型创建train和test集合。
我们使用 TensorFlow/Keras API 定义卷积自动编码器的编码器和解码器部分。然后我们实例化OutlierAE检测器类,它将编码器和解码器层作为输入,并在适当的集合上训练模型。我们还需要定义一个阈值,超过该阈值的元素将被标记为异常值。我们用infer_threshold函数计算阈值,该函数将 inlier 值的百分比作为参数。这很方便,但在现实世界中并不总是可行的。之后,我们通过使用predict函数检测测试集的异常值,该函数返回一个包含每个元素预测的字典。instance_score键包含实例级别的分数,如果该元素高于阈值,则被标记为异常值。此外,feature_score键包含图像中每个像素的分数。
首先,我们将所有标记为异常值的图像复制到img文件夹中。然后,我们用所有图像的文件名以及探测器的预测创建一个熊猫数据帧。我们创建仅包含异常值的第二个数据帧,然后打印它。该模型相当准确,因为它已经检测到所有异常图像,并且仅将少数正确图像标记为异常(假阳性)。

最后,我们使用plot_feature_outlier_image函数为离群元素的每个像素绘制分数。这有助于我们更好地理解异常检测器是如何工作的。第一个图形列包含五个被标记为异常值的图像。接下来,我们可以看到每个图像,因为它是由异常检测器重建的。显然,该模型只能输出正常的胶囊图像,因此不能重建各种变形。接下来的三列是每个图像通道的特征分数可视化,可以帮助我们定位有问题的区域。
结论
卷积自动编码器是一个可行的和相当准确的图像异常检测选项,但仍有改进的空间。例如,您可以尝试修改神经网络架构以获得更好的结果。您还应该记住,Alibi Detect 包括其他算法,如变分自动编码器和自动编码高斯混合模型,它们可能适用于特定情况。我鼓励您进行试验,找到符合您需求的最佳解决方案。欢迎在评论中分享您的想法,或者关注我的 LinkedIn,我会定期在那里发布关于数据科学和其他主题的内容。你也可以访问我的个人网站或者查看我的新书,书名是用 PyCaret 简化机器学习。
参考
[1] I. Goodfellow,Y. Bengio,a .库维尔,深度学习 (2016),麻省理工出版社
[2]r . chal aparty,S. Chawla,用于异常检测的深度学习:调查 (2019),arXiv:1901.03407
[3] P .博格曼,m .福瑟,d .萨特勒格,c .斯泰格, MVTec AD —无监督异常检测的综合真实世界数据集,2019 年 IEEE/CVF 计算机视觉和模式识别会议(CVPR)
用 SymPy 简化机器学习微积分

凯文·Ku 在 Unsplash 上的照片
快速浏览用于机器学习的微积分,以及如何使用 SymPy 将它添加到您的代码中
机器学习需要一些微积分。许多在线机器学习课程并不总是涵盖微积分的基础,假设用户已经有了基础。如果你和我一样,你可能需要复习一下。让我们来看看一些基本的微积分概念,以及如何使用 SymPy 在代码中编写它们。
很多时候,我们需要微积分来寻找最优化问题中的导数。这有助于我们决定是增加还是减少重量。我们的最终目标是找到一个极值点,它将是函数中的局部最小值或最大值点。
让我们通过以下步骤来完成寻找极值点的过程。
- 安装和学习 Sympy 的基础知识。
- 求线性函数的斜率。
- 发现切线和割线。
- 用我们的斜率和切线知识来求极限。
- 理解什么是函数的导数。
- 用导数求极值点。
- 决定极值点是局部最小值还是最大值点。
SymPy 入门
SymPy 是一个 Python 库,可以让你使用符号来计算各种数学方程。它包括计算微积分方程的函数。它还包括许多其他函数,用于一些更高级的数学。
安装 SymPy 很简单,你可以在这里找到完整的安装说明。如果您已经在使用 Anaconda,那么 SymPy 也包括在内。有了 Anacona,您可以通过一个简单的:
conda update sympy
如果您没有使用 Anaconda,pip 是安装新 Python 库的好方法。
pip install sympy
SymPy 依赖于 mpmath 库,所以你也需要安装它。
conda install mpmath
#or
pip install mpmath
使用 SymPy,我们可以像在数学方程中一样创建变量。我们需要将这些变量设置为符号,这样 SymPy 就知道将它们与常规的 Python 变量区别对待。这很简单,使用 symbols() 函数即可完成。
import sympy
x2, y = sympy.symbols('x2 y')
现在我们已经安装了 SymPy,让我们后退一步,看看微积分的基础。
线性方程和斜率
如上所述,我们需要微积分的一个主要原因是寻找极值点。为了说明这一点,让我们假设你每年都参加年度土豆大炮大赛。每年你都输给可怕的丹尼·麦克道格。今年你雇了一个教练来帮你打败丹尼。要打败丹尼,教练需要你给他三样东西。
1.当丹尼的土豆在最高点时。
2.土豆到达最高点需要多长时间。
3.土豆最高点的斜度。
先说坡度。
如果丹尼在土豆永远上升的地方建造了一个魔法炮,找到斜坡会很容易,但不会有最大高度。这种类型的马铃薯飞行路径是一个线性方程,如 y = 3x+2(y 截距形式)。
我们可以使用 NumPy 和 Matplotlib 来可视化这个线性函数马铃薯飞行。如果您没有安装 NumPy 和 Matplotlib,过程就像上面的 SymPy 安装一样。更多详情见此处和此处。
import matplotlib.pyplot as plt
import numpy as np#create 100 values for x ranging from 0 to 6
x = np.linspace(0,6,100)#our linear function
y = 3*x + 2#add some aesthetics to out plot
plt.grid(color='b', linestyle='--', linewidth=.5)
plt.plot(x,y, label="potato flight")
plt.xlim(0, 6)
plt.ylim(0,20)
plt.legend(loc='best')
plt.xlabel("Seconds")
plt.ylabel("Feet(x10)")#show the plot we created
plt.show()
我们要检查斜率,因此我们将在两个随机点上添加标记:(1,5)和(4,14)。
plt.plot(1, 5, 'x', color='red')
plt.plot(4, 14, 'x', color='red')

马铃薯以线性函数飞行
当我们有一个线性函数时,我们的斜率是常数,我们可以通过观察任意两点,计算 y 的变化除以 x 的变化来计算斜率,让我们来看看我们之前标记的两点。

求斜率的方程
在 y 截距形式(y = mx + b)中, m 总是斜率。这与我们之前的函数 y = 3x + 2 相符。
土豆一定要下来——非线性函数
线性函数的斜率很容易,但土豆必须下降。我们需要一种方法来计算随每个点变化的斜率。让我们从可视化一个更真实的土豆飞行路径开始。
我们的教练很棒,他知道代表土豆飞行的函数是 f(x) = -(x ) +4x。
让我们再一次用 Matplotlib 可视化这个土豆的飞行路径。
x = np.linspace(0,5,100)
y = -(x**2) + 4*xplt.xlim(0, 4.5)
plt.ylim(0,4.5)
plt.xlabel("Seconds")
plt.ylabel("Height in Feet(x10)")
plt.grid(color='b', linestyle='--', linewidth=.5)
plt.plot(x, y, label="potato")
plt.legend(loc='best')plt.show()

马铃薯的非线性飞行
从函数的可视化来看,我们看到在大约 2 秒钟内,马铃薯达到了大约 40 英尺的高度。该图很有帮助,但我们仍然需要最大高度的斜率。另外我们需要一些确凿的证据带回给教练。让我们继续用微积分证明这个高度和时间。
割线
曲线的割线是一条至少在两个不同点处与曲线相交的线。当我们有非线性函数时,我们仍然可以找到两点之间的斜率,或一条割线。由于(2,4)看起来像我们的马铃薯路径的顶部,让我们看看我们新的非线性马铃薯路径上的 2 个点:(1,3)和(2,4)。
#adding this code to our above plot
x2 = np.linspace(1,2,100)
y2 = x2 + 2
plt.plot(x2,y2, color='green')

割线 x + 2
我们可以看到(1,3)和(2,4)的斜率是 1。让我们更进一步,看看当我们试图只找到点(2,4)的斜率时会发生什么。为了做到这一点,我们需要一条线,能够代表通过一个点。
切线
让我们看看越接近(2,4)线的斜率会发生什么变化。所以我们再画几条割线。我们将端点保持在(2,4),但一条线将从(1.5,3,75)开始,另一条线从(1.95,3.9975)开始。这又给了我们两条割线 y3 = .5x + 3 和 y4 = .05x + 3.9。

两条割线
当我们最终到达(2,4)作为我们的起点时,一条线形成了,这就是 y = 0x +4。这是(2,4)的切线。通过求解极限并将其代入 y 截距线性方程来计算切线。更多关于极限的内容。函数中的每一点都有一条切线,这就是我们如何计算函数中每一点的斜率。

点(2,4)的切线
记住,我们的主要目标是找到一个极值点,土豆的最大高度。极值点将出现在切线斜率为零的时候,因为这表示函数改变了方向。例如,让我们看看穿过(1,3)和穿过(3,3)的切线的斜率。

3 条切线
我们来看看这三个点的切线斜率发生了什么变化。
- 点(1,3),切线为 y = 2x + 1,斜率为 2
- 点(2,4),切线为 y = 0x + 4,斜率为 0
- 点(3,3),切线是 y = -2x + 9,斜率是- 2
0°之后,斜率改变方向。很好,我们需要找到切线斜率为零的点。这些点将告诉我们最大或最小点,因为切线斜率的方向总是在 0°之后改变。
太好了!所以我们需要在函数上找到一个斜率为零的点。如果有一种方法可以创建一个函数,给出原始函数中任意一点的斜率就好了。有,这就是导数!在我们进入衍生品之前,让我们先看看极限。
限制
极限允许我们找到函数接近某个 x 值时的斜率。如果我们把极限解成割线,那就简单了。我们代入两个 x 值和两个 y 值,就可以求解斜率方程。这种极限定义了。但是,我们想要找到一个未定义的极限,因为我们想要点到点(2,4)的切线的斜率。
当我们接近(2,4)时,我们需要斜率。我们不能得到从(2,4)到(2,4)的割线的斜率,因为如果我们把这些数字代入斜率方程,我们得到 0/0。这是行不通的,因为正如一位数学老师曾经说过的:“生活中有两件事你不能做,把果冻钉在墙上,然后除以零”。因为我们不能被零除,我们需要找到未定义的极限。
极限是通过将我们的函数代入斜率方程并分解出来解决的。我们可以使用之前的斜率公式,用点(2,4)代替 x1/y1 值,然后用 f(x)和 x 代替 x2/y2 值。我们的极限值是我们正在逼近的 x 值,在这个例子中是 2。函数-(x ) +4x 的极限 2 的新斜率方程为:

我们的目标是去掉分母上的 x,所以让我们展开-(x)并抵消分母上的 x。

现在我们已经把 x 从分母中去掉了,我们可以把 plug 2 放回 x 中。

现在我们知道了极限是如何求解的,让我们启动 SymPy,这样我们就可以在代码中求解极限了。
SymPy 有一个名为 limit() 的函数,它有 3 个参数。
- 我们正在寻找极限的函数
- 输入变量
- 输入变量接近的数字
因为我们的极限是未定义的,我们需要像上面一样替换 x 和 y 值。
import sympy
x2, y = sympy.symbols('x2 y')
#store our substituted function as a y variable
y = (-(x2**2) + 4 * x2 -4) / (x2 -2)
limit = sympy.limit(y, x2, 2)
// 0
我们的上限是 0!
衍生品
导数是一个函数,它将给出函数中任意一点切线的斜率。
现在我们明白了极限线和切线是什么,我们可以朝着我们的最终目标前进,用导数来寻找函数中的极值点。求函数导数的过程是 微分 。
求解导数需要用到一些代数和上面的斜率公式。因为我们不是在求解一个特定的点,所以我们不会替换任何值。对于此示例,我们也用更常见的形式替换 x1 和 x2,即使用 x 和 x +h。这将为我们提供以下公式来求解 f′(x)的导数,f′(x)表示 x 的函数的导数:

如果我们把函数代入这里,我们得到:

然后我们可以用解决极限的方法来解决这个问题。我们还可以使用幂法则来求解,从而使用以下等式轻松找到我们的导数。

使用该规则,我们可以看到函数 -(x ) +4x 的导数是- 2x +4 。
让我们用 SymPy 来求导,而不是通过手动的步骤来求导。
SymPy 为我们提供了一个名为 diff() 的函数,它将执行微分过程并返回导数。
diff 函数有两个参数:
- 我们要求导数的函数
- 输入变量
让我们用我们原来的函数 -(x ) +4x 来试试这个函数。
# set x as the variable
x = sympy.symbols('x')#help make the out easier to read
sympy.init_printing(use_unicode=True)#enter the our argumnets to th diff funtion
d= sympy.diff(-(x**2) + 4*x, x)#print our derivative
print(d)
//-2*x + 4
函数的极值点是导数等于零的地方。这是因为当导数等于 0 时,函数的方向已经改变,正如我们上面所探讨的。
为了找到 x 值,我们将导数设为 0,然后求解 x, -2x + 4 = 0。
这是通过使用函数 solveset() 用 SymPy 解决的。Solvest 有两个参数:
- Eq 函数,它有两个参数:等式和等式需要等于的值
- 我们试图解决的变量
Solvset 将返回所有解方程的数的集合。
当导数等于 0 时,使用 solvset 来查找 x 值将如下所示:
answer = sympy.solveset(sympy.Eq(d, 0),x)
print(answer)
//{2}
完美!我们的 x 值是 2 ,如果我们把它代入原始函数,我们得到 4 作为我们的 y 值。
现在我们可以确定,在 2 秒钟时,麦克道戈尔的土豆正好在空中 40 英尺处,并且该点的斜率为 0!我们可以把它带给教练,我们一定会赢得下一场土豆大炮比赛!
我们的极值点是最小值还是最大值?
我们知道我们的土豆的极限点一定是最大点,因为这些土豆大炮不是用来击落土豆的。但是如果我们没有图或者不知道函数的方向,我们怎么知道极值点是局部最小值还是局部最大值?我们已经知道,将导数的 x 值设置为 2 会导致斜率为 0。如果我们在我们的导函数中再插入两个数,一个数会大于 2,另一个会小于 2,会发生什么?我们将使用 1 和 3 来尝试。
test1 = -2*1 + 4
test2 = -2*3 + 4
print(test1)
//2
print(test2)
//-2
我们看到,在极值点之前,斜率是正的,而在极值点之后,斜率是负的。斜率从正到负的变化告诉我们极值点是最大值。如果斜率从负变为正,我们就知道极值点是最小值点。如果有多个极值点,我们希望在每个点之间选择一个值。例如,如果我们有极值点 1 和 5,我们将重复这个过程三次:
- 选择一个小于 1 的随机数
- 选择一个大于 1 但小于 5 的随机数
- 选择一个大于 5 的随机数
很可能非线性函数不会只有一个极值点。在这种情况下,所有的步骤都是一样的,但是当我们求解导数等于零时,我们得到了多个解。
结论
SymPy 是一个庞大的库,是一个很好的方法来寻找导数和函数的局部极值点。SymPy 易于使用和阅读,为任何需要微积分的机器学习项目增加了简单性和可读性。我们只涉及了这个库的许多可用函数中的一小部分。我鼓励您进一步探索它,看看还有什么可以用来将数学融入到您的数据科学项目中。
简化机器学习工作流程
如何使用管道来标准化机器学习工作流的数据预处理、数据转换和建模步骤

杰里米·毕晓普在 Unsplash 上的照片
本文概述了如何使用定制转换器和 Scikit-Learn 管道捆绑数据预处理、数据转换和机器学习工作流的建模步骤。包含探索性数据分析(EDA)的详细笔记本可以在我的 GitHub 上找到。
本教程的结果是在 Kaggle Ames Housing 数据集上使用 Pipelines 的一个示例,其中我们获得了排行榜前 20%的分数!
机器学习工作流
虽然有许多方法来构建机器学习(ML)工作流,但基本结构可以被认为是以下步骤:
- 数据采集:收集数据
- 数据预处理:剔除异常值,替换缺失值等。
- 数据转换:添加特性,标准化数据等。
- 模型训练&调优:选择模型、交叉验证、调优超参数等。
- 模型评估:分析模型性能
- 模型部署:根据测试数据进行预测

基本 ML 工作流程
机器学习工作流程陷阱
即使是简单的 ML 工作流程也会变得复杂。例如,假设有 10 个预处理/转换步骤应用于训练和测试数据。此外,您希望测试多个模型,并执行交叉验证和超参数调整。一些数据科学家可能会拼凑杂乱的代码块,并试图手动跟踪每一步。然而,有几个原因可以解释为什么这很快变得不切实际,甚至对您的建模工作有害。
在管道外执行 ML 工作流程的挑战:
- 训练-测试污染:当您对整个数据集执行预处理/转换步骤,而不是对单个训练、验证和测试数据组件执行预处理/转换步骤时,就会发生这种形式的数据泄漏。一个典型的例子是在分割前标准化数据集,这可能导致验证甚至测试数据的高性能。
- 非统一预处理/转换:即使您将数据集分成训练、验证和测试数据组件,您现在也必须跟踪每个组件,并记住应用相同的预处理/转换。在复杂的 ML 工作流中,这可能很难做到,甚至更难执行“堆栈跟踪”。
- 交叉验证:当你不得不跟踪应用不同模型的每个代码块,或者更糟糕的是,对于循环来说,一个庞大而繁琐的,几乎不可能“干净地”执行多个模型的交叉验证测试。
- 部署:即使你部署了它而没有不可追踪的错误,你也不能轻易地改变工作流中的组件。
输入管道
管道是捆绑数据预处理、转换和建模代码的一种简单方法,允许您像应用单个步骤一样应用“捆绑”。这意味着不再有列车测试污染或忘记预处理/转换步骤。只要您在应用管道之前拆分数据,每个数据集将接收相同且独立的预处理/转换。它还使得交叉验证、模型调整和模型部署更加简单和清晰。

具有示例管道的基本 ML 工作流
一个例子
本节提供了一个使用 Scikit-Learn 管道和定制转换器来交叉验证和比较几个模型的示例。
数据
我将使用来自 Kaggle 竞赛房价:高级回归技术的 Ames 房产数据集。该数据集有 79 个特征,混合了数字和分类,并包括变量,如房屋各部分的平方英尺、社区以及建造和出售的年份。数据可以通过 Kaggle 比赛页面访问。
定义管道
首先,我们需要定义管道步骤。我将执行非常基本的数据预处理/转换和特征工程。基本上,它只是足够加上一点额外的东西来将我们的数据转换成 Scikit-Learn 模型可以接受的东西。

Ames 住房数据集的 Scikit-Learn 管道
首先,需要定义数值和分类数据列(这些数据的预处理和转换涉及不同的步骤)。然后,我们希望定义一个管道类,并在嵌套管道中包含适用的数据转换类(即数据预处理/转换步骤)。我们可以通过将多个转换类和嵌套管道包含在 FeatureUnion 类中来连接它们的结果。这里的是一个很好的来源来获取更多关于构建管道和特征联合的信息。要素数据集被传递到执行以下操作的管道中:
数字列:提取数字列,估算缺失值,生成新要素总平方英尺,log 转换数据。
分类列:提取分类列,估算缺失值,编码分类数据
标准化:feature union 将经过处理/转换的数字和分类数据结合起来,并对这些数据进行标准化。
定制变压器
有时候我们需要一个不附带 Scikit-Learn 的变压器。例如,我们可能希望创建一个新的特性,或者希望现有的 Scikit-Learn 转换器返回一个熊猫数据帧。幸运的是,Scikit-Learn 和 Python 通过 TransformerMixin 和类继承简化了这一过程。
下面是每个定制转换器的简要总结:
- 列提取器():自定义转换器类,用于从特征数据集中提取选择列。
- dfSimpleImputer():从 simpleinputr()类继承并返回 Pandas DataFrame 的自定义转换器类。
- DFOneHotEncoder(): 自定义 transformer 类,该类从 OneHotEncoder()类继承并返回 Pandas DataFrame。
- TotalSF(): 自定义 transformer 类,用于计算房屋的总面积。
创建和评估管道
现在我们已经定义了管道,我们可以把它们放在一起。首先,我们定义一个助手函数,它采用一个管道,对一个特定的模型执行 X 重交叉验证,并返回房屋销售价格日志的均方根误差(RMSE)。接下来,我们定义我们想要训练的模型,并为循环创建一个,其中每个循环定义“完整管道”,该管道是预处理/转换步骤(即最后一部分)和选择模型的组合。循环的结果是每个模型的交叉验证 RMSE 分数以及模型分数和标准偏差的箱线图比较。这里是制作交叉验证箱线图的绝佳资源。

交叉验证 RMSE 分数

各种模型的箱线图交叉验证 RMSE 分数
结论
在本教程中,我们定义并创建了一个管道来预处理/转换 Kaggle Ames 住房数据集,并使用 X 倍交叉验证 RMSE 评分来评估模型。结果是一个易于跟踪和调试的管道,返回 RMSE 分数在 Kaggle 排行榜的前 20%。
将管道添加到您的数据科学武库中,保持有序和高效!
使用此工具简化您的数据科学项目
数据科学家开发和导出机器学习模型的理想工具

【https://github.com/amineHY/AI-LAB
🚀链接到项目
- Github 项目:https://github.com/amineHY/AI-LAB
- docker Hub:https://Hub . docker . com/repository/registry-1 . docker . io/amine hy/ai-lab
描述
这个项目是为数据科学家创造一个开发环境。它帮助用户以简单的方式开发机器学习模型,
- 关注代码,而不是工具。
- 节省安装过程中可能浪费的时间。
- 防止通过安装不兼容的软件包破坏操作系统。
我手工制作了AI-lab(在 NVIDIA 容器之上)并利用 Docker 的功能来拥有一个可复制和可移植的开发环境。
AI-lab允许使用最常见的人工智能框架在 Python 中开发基于人工智能(AI)的应用程序。AI-lab旨在用于构建、培训、验证、测试您的深度学习泰格豪雅
例如,模型是进行迁移学习的好工具。
它包括:
- Ubuntu 18.04
- NVIDIA CUDA 10.1
- 英伟达 cuDNN 7.6.0
- OpenCV 4.1
- Python 3.6
- 最常见的 AI 框架:TensorFlow、PyTorch、ONNX、Keras、ONNX-tensort、Jupyter-lab、VS 代码集成远程开发、Numpy、Matplotlib、Scikit-learn、Scipy、Pandas、tensort 等等。
安装人工智能实验室
在使用AI-lab之前,需要在操作系统上安装一些先决条件
- 您必须拥有 AMD64 架构的操作系统。在终端检查一下
dpkg --print-architecture
比如我用的是 Ubuntu 18.04.3 LST。您可以用这个命令检查您的系统
lsb_release -a

nvidia-smi
在我的笔记本电脑上,我有 NVIDIA 驱动程序版本 430.50 和 CUDA 版本 10.01。


码头工人
使用
首先从 Docker Hub 注册表中拉出 AI-lab:AI-lab
docker pull aminehy/ai-lab
最新的图像大约有 9.97GB,所以请确保您有足够的空间(和高速互联网)。
然后运行人工智能实验室,开始你的开发
xhost
然后
docker run -it --rm -v $(pwd):/workspace -w /workspace -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY --runtime=nvidia -p 8888:8888 -p 6006:6006 aminehy/ai-lab
搞定了。
安装 UFF 转换器 **convert-to-uff** (如果需要)
运行 AI-lab 后,使用以下命令移动到/opt/tensorrt/python文件夹并安装convert-to-uff:
cd /opt/tensorrt/python dpkg -i *-tf_*.deb UFF_PATH="$(python -c 'import uff; print(uff.__path__[0])')" chmod +x ${UFF_PATH}/bin/convert_to_uff.py ln -sf ${UFF_PATH}/bin/convert_to_uff.py /usr/local/bin/convert-to-uff
启动 IDE 并开始开发您的应用程序
Jupyter 笔记本
如果AI-lab在您的机器上正确运行,那么Jupyter notebook应该会自动运行。如果不是这样,请使用以下命令从终端启动它
jupyter notebook --allow-root --port=8888 --ip=0.0.0.0 --no-browser

jupyter 笔记本
VS 代码
VS Code 是一个 IDE,它提供了从 docker 容器内部(即AI-lab内部)通过扩展远程开发进行开发的可能性。更多详情此处。
我在文件夹AI-LAB_in_vscode中添加了两个配置文件夹.devcontainer和.vscode。他们必须能够通过AI-lab使用 VS 代码。这两个文件夹是隐藏的,必须位于应用程序的目录中,以便 VS 代码自动检测AI-lab配置。因此,您需要将它们复制到应用程序文件夹中。
要获得这些文件夹,首先,克隆这个存储库并移动到其中
git clone [https://github.com/amineHY/AI-lab.git](https://github.com/amineHY/AI-lab.git) cd /AI-lab
将这两个文件夹复制到您的应用程序文件夹,例如/path_to_folder_application
sudo cp -R AI-lab/AI-LAB_in_vscode/.* /path_to_folder_application
最后,移动到您的应用程序文件夹
cd /path_to_folder_application
和启动 VS 代码
code .

虚拟代码
显示 GPU 的内存使用情况
根据您的开发情况,您可能希望观察 GPU 的内存消耗。多亏了gpustat,你才能做到这一点
watch -n0.5 -c gpustat --c -cupP
我的操作系统的输出:

用deviceQuery显示关于 GPU 的信息
在终端中,运行deviceQuery脚本(在这个库中提供)来获得更多关于你的 GPU 配置的信息
./deviceQuery
我的操作系统的输出:

参考
- Github 项目:https://github.com/amineHY/AI-LAB
- docker Hub:https://Hub . docker . com/repository/registry-1 . docker . io/amine hy/ai-lab
有什么建议吗?
阅读我的另一篇关于媒介的文章:
简化您的 Python 代码:用 Wily 自动化代码复杂性分析

约翰·巴克利在 Unsplash 上的照片
以下是如何让评估代码复杂性成为 Python 开发例程的一部分
所以你写了一段 Python 代码,它完成了工作。很好,但是你的代码足够简单吗?复杂的代码很难阅读,这使得代码维护成本更高。尽早发现复杂性可以节省时间、金钱和许多挫折。在这篇文章中,我将向您展示如何使用老谋深算的命令行工具来跟踪代码的复杂性。
代码复杂性快速入门
代码复杂性很重要。不必要的复杂代码更难阅读,也更难维护。如果你的代码很难理解,就很难发现现有的错误,也很容易引入新的错误。笨重的代码使团队工作变得复杂,并且很难让新同事跟上进度。科技公司必须满足复杂性门槛,这是有原因的。
开发人员使用几种不同的代码复杂度度量方法。复杂性分析工具中普遍存在两种这样的度量。
麦凯布的循环复杂性
首先,麦凯布的循环复杂性 (CYC)依赖于图论。由 Thomas McCabe 在 1976 年开发的度量是从一个函数的控制流图中计算出来的,控制流图由节点和边组成。

流程图中的节点和边(图片由作者提供)
基于这样的图表,我们可以使用以下公式计算 CYC:
CYC = E – N + 2P
在这个公式中,P是谓词节点(即包含 if/else 条件的节点)的数量,E是边的数量,N是节点的数量。CYC 实际上是通过你的模块的独立路径的数量的度量,给出了代码理解的困难程度的一些指示,以及需要多少单元测试来实现完全的测试覆盖(即它的“可测试性”)。
CYC 的值越高,代码就越复杂。卡内基梅隆大学的软件工程研究所定义了以下范围(参见本出版物第 147 页的):
- 1–10:风险低,程序简单;
- 11–20:中等风险,难度较大的项目;
- 21–50:高风险,非常难的项目;
- > 50 :风险极高,不可测试的程序。
可维护性指数
其次,可维护性指数(MI) 是 McCabe 度量(C)Halstead 量 (V)和代码行数(LoC)的组合。在公式中:
MI = 171 - 5.2*ln(*V*) - 0.23*(*C*) - 16.2*ln(*LoC*)
MI 在理论上被限制在 0 到 100 之间,但在实践中不是这样(大多数软件实现将其限制在 100)。最初介绍度量标准的文章提到了以下阈值:如果你的代码的 MI 低于 65,那么它就很难维护;如果是 85 或者更高,你的代码很容易维护。65 到 85 之间的任何值都是适度可维护的(科尔曼、洛瑟和阿曼,1994 )。Visual Studio使用的重新调整版本(在 0 到 100 之间)将阈值分别设置为 0 到 9 表示低可维护性,10 到 19 表示中等可维护性,20 及以上表示高可维护性。(请注意,不同的 ide 和库可能使用不同的阈值。)
对 CYC 和米的警告
出于多种原因,不应该孤立地使用 CYC 和 MI 来确定您的代码是否过于复杂或难以维护。
首先,这些度量没有考虑其他不必要的复杂性指标,比如代码重复、嵌套深度或可读性。第二,MI 尤其受到一系列问题的困扰,这使得它不一致。它是几十年前校准的,并对它使用的一些变量的增加和减少如何影响整体复杂性做出了一些相当可疑的假设。(关于 MI 缺点的更详细的评估,请看代尔夫特理工大学教授 Arie van Deursen 的这篇出色的博客文章。)
最后,我们应该预期 MI 的值会根据您所分析的框架而有所不同。因此,像代码行(LOC)这样的简单度量可能是首选的。
这些限制确实给了我们一些何时以及如何使用 CYC 和 MI 的想法。首先,MI 不能可靠地用于比较两个不同系统的复杂性,即使它们是使用相同的框架构建的。第二,当一段代码足够简单和可维护时,我们不能使用硬截止,因为这些度量不能脱离人类评估和代码库的专家知识。
相反,CYC 和 MI 可能是有用的——与其他更简单的度量标准结合——如果我们将它们视为帮助我们识别代码中潜在问题的试探法。如果我们定期评估我们的代码,并观察度量标准如何随着时间的推移而演变,这可能特别有用。突然和巨大的变化应该引起我们的注意,并促使我们进一步研究。不用说:和大多数代码质量工具一样,CYC 和 MI 应该在你的开发工作流程中补充质量控制,而不是取代它。
使用预提交挂钩将代码复杂性分析集成到您的工作流中
在这篇文章的剩余部分,我将向你展示如何在你的 Python 开发工作流程中集成和,在每次提交新代码时为你执行复杂性分析。Wily 是一个命令行工具,允许您分析、跟踪和可视化 Python 代码的复杂性和可维护性。虽然 mccabe 和 radon 库提供了类似的功能,但是 wily 有一些很好的特性,允许我们相对容易地跟踪复杂性。下面的视频是作者安东尼·肖对《诡计》的介绍。
老谋深算的 Python:编写更简单、更易维护的 Python — PyCon 2019
检测代码复杂性的用处取决于您执行分析的频率。如果你定期检查你的代码复杂性,你可以很容易地发现突然增加。这样的异常值不一定有问题,但是它们应该促使您进行调查。确保你经常获得这些见解的最好方法是在你的项目的预提交钩子中包含老谋深算。
预提交钩子是一些小的“脚本”,当使用git commit命令时,它们在本地运行在暂存文件上。(如果你想了解更多关于预提交钩子的知识,你可能会对我在上发表的使用预提交钩子自动执行代码风格的文章感兴趣。)
安装预提交库
要开始使用预提交钩子,首先使用终端安装预提交库(关于 Homebrew 和 Conda 的说明可在本页获得):
pip install pre-commit
您可以使用下面的命令检查安装是否成功。此命令应返回预提交安装的版本。
pre-commit --version
创建和配置您的。yaml 文件
安装完pre-commit之后,创建一个.yaml文件。您的.yaml文件指定了您的预提交钩子配置。在终端中使用以下命令在您的项目目录中创建新的.yaml文件:
nano .pre-commit-config.yaml
随后,添加以下配置:
repos:
- repo: local
hooks:
- id: wily
name: wily
entry: wily diff
verbose: true
language: python
additional_dependencies: [wily]
使用预提交
现在您已经安装了预提交包并设置了您的.yaml文件,您已经准备好使用预提交和 wily 来分析代码复杂性了。首先,在终端中运行以下命令来安装预提交挂钩:
pre-commit install
安装好预提交钩子后,每次提交对 git 的更改时,都会执行pre-commit命令。或者,您可以使用以下命令直接从终端运行预提交挂钩:
pre-commit run
老谋深算入门
在可以使用带有预提交的 wily 之前,您必须从终端运行wily build。 build 命令编译您最近 50 次提交中代码复杂性变化的缓存。您需要这个缓存,以便 wily 可以计算您提交的度量。或者,您可以使用wily setup并遵循终端中的指示。
在您设置和配置了预提交并创建了您的老谋深算的缓存之后,wily diff命令将在每次新提交时自动运行。在新提交时,您的终端输出将显示当前提交的代码版本与前一版本相比的复杂性。下面的输出显示了删除一些代码行后的 wily 的 diff 报告示例。我们获得了四个分数,包括代码行数(LOC)、唯一操作数以及圈复杂度和可维护性指数。如果您的复杂性在相对较小的更改后急剧增加,您可能应该暂停并重新考虑您刚刚做出的更改。

结合预提交使用“wily diff”命令进行新提交后的代码复杂性分析(图片由作者提供)
了解代码在两次提交之间是如何变化的是很有用的,但是并没有给我们太多的数据来处理。为了识别和区分潜在的问题领域,我们必须考虑一个特定的模块是如何随着时间而变化的。要获得此信息,请在终端中运行以下命令:
wily build
wily report <my-module-name>
如下例所示, report 命令将生成一个 CLI 表,显示指定模块的所有提交之间复杂性度量的变化。这个报告可以让你很容易地发现变化,以及复杂性的模式和趋势,以及你可能出错的地方。

使用“老谋深算的报告”命令分析提交之间的复杂性差异(图片由作者提供)
另一个识别大型项目中(潜在)有问题模块的有用命令是wily rank,它将显示不同模块的可维护性指数。在这种情况下,所有值都高于 75,这意味着它们很容易维护。(请注意我在本文前面概述的使用可维护性指数的注意事项)。

使用“wily rank”命令计算 Python 模块的可维护性指数(MI)
最后,在绘制不同提交的一段代码的复杂性时,最容易发现趋势。您可以使用 graph 命令显示模块的复杂性报告,例如:
wily graph create_tables.py loc sloc complexity
这个命令将产生一个create_tables.py模块的图(见下文),在 y 轴上显示代码行,在 x 轴上显示提交,以及由每次观察的气泡大小表示的复杂性。

用 Wily 绘制代码行(LOC)(行)和循环复杂度(气泡大小)
结合起来,wily 的diff、report、rank和graph命令可以提供有用的信息,告诉你你的代码是否变得不必要的复杂。
超越诡计:简化您的 Python 代码
编写简单、清晰、易读的代码具有挑战性。虽然代码风格和(单元)测试在很大程度上可以自动化,但是代码本身的设计仍然是一项人工任务。也就是说,如果机器编程的最新进展没有让开发人员过时的话。自动化复杂性分析可以帮助您做出明智的决策,决定何时重新考虑您的代码,以及您的代码库的哪些区域应该优先考虑。这些分析永远不能取代正确的代码设计过程,但是它可以在开发过程中避免不必要的错误和捕捉潜在的问题。
感谢阅读!
MI 的原始版本。请注意,存在不同版本的 MI。参见 Radon 关于该指标的文档。
Visual Studio 的重新调整 MI 可以使用下面的公式计算:MAX(0,(171–5.2*ln(V) — 0.23 * (C) — 16.2*ln(LoC))*100 / 171)。详见本文。
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@ndgoet/membership)
您有兴趣了解更多关于自动化 Python 开发过程的知识吗?看看我之前关于这个话题的一些帖子:
单元测试是产生高质量代码的关键。以下是如何自动化测试 Python 代码。
towardsdatascience.com](/automating-unit-tests-in-python-with-hypothesis-d53affdc1eba) [## 如何用预提交钩子改进 Python 代码风格
实施代码风格是简化开发过程的关键,下面是如何实现自动化。
medium.com](https://medium.com/python-in-plain-english/how-to-improve-your-python-code-style-with-pre-commit-hooks-e7fe3fd43bfa)
请仔细阅读 本免责声明 中的任何内容后再依托 我的 Medium.com 文章 。
用代码和例子简化函数的 args 和 kwargs!
理解 python 编程和机器学习的args 和kwargs 的完整概念。

函数是 python 和面向对象编程不可或缺的一部分。
Python 是一种优雅而简单的语言,它为用户提供了多种更简单有效的编码方式。
其中一个概念是在 python 中包含args 和kwargs。这些向函数传递可变数量参数的方法使得 python 编程语言对于复杂问题非常有效。
正确使用它们的用途很多。函数中的这两个参数将非常有用,即使在机器学习和深度学习的概念中,同时尝试为各自的项目构建您的自定义层或函数。
在本文中,我们旨在通过代码和示例直观地理解这些概念。所以,事不宜迟,让我们开始深入了解这些概念。
在开始编程之前,让我们简单回顾一下函数这个主题。
什么是功能?
函数是写在程序中的一段代码,这样它们可以被多次调用。函数的主要用途是在同一个程序中可以被多次重复调用,而不需要一遍又一遍地编写相同的代码。然而,你也可以用它来为你的程序提供更多的结构和更好的整体外观。
使用关键字 'def,定义函数,可以使用已定义或未定义的参数调用这些函数。当您调用特定的函数时,python 编译器会解释将要返回的任何值。
下面是一个典型函数的代码块—
def func(parameters if required):
# code here
return # solution
在 Python 中,我们可以使用特殊符号向函数传递可变数量的参数。这有两种可能性,如下所示:
- *参数(非关键字参数)
- **kwargs(关键字参数)
让我们分别理解这些概念,从*args 开始,然后到**kwargs。
*参数
python 中函数定义中的特殊语法 *args 用于向函数传递可变数量的参数。它用于传递一个无关键字、可变长度的参数列表。
为什么您的函数需要这个参数选项?
假设篮子里有 3 个水果,你写一个包含 3 个变量的函数,定义如下:
您将得到以下输出。
Apple Mango Banana
一切看起来都很好,直到你意识到你还买了一些葡萄,你想把它也添加到你的功能中。你可以添加一个额外的变量,再次调用它,继续这个过程。然而,你购买的水果越多,你就不得不一遍又一遍地更新。这就是*args 函数发挥作用的地方。
您可以简单地执行此功能,如下所示:
语法是使用符号接受可变数量的参数。按照惯例,它通常与 args 一词连用。args 允许您接受比您之前定义的形式参数更多的参数。
这个过程简单有效。*args 的概念非常有用,如本节所述。让我们继续**kwargs 部分,并详细理解这个概念。
*** 夸脱*
python 函数定义中的特殊语法 **kwargs 用于传递带关键字的可变长度参数列表。我们使用带有双星的 kwargs 这个名字。原因是双星号允许我们传递关键字参数(以及任意数量的关键字参数)。
**kwargs 是一种类似字典的操作,将元素值映射到它们各自的。让我们用一个类似水果的例子来理解这个概念。假设您想按水果摆放的顺序或您最喜欢的顺序对它们进行排序。这个过程可以按照下面代码块的建议来完成:
你会得到下面的输出—
first Apple
second Mango
third Banana
fourth Grapes
关键字参数是在将变量传递给函数时为变量提供名称的地方。人们可以把 kwargs 看作是一个字典,它将每个关键字映射到我们传递给它的值。这就是为什么当我们迭代 kwargs 时,它们似乎没有任何打印顺序。
对于更复杂的项目,您可以同时使用args 和kwargs 函数来执行这些任务。我强烈建议您亲自尝试一下,以便更好地理解这些概念。

结论:
总结一下我们在本文中讨论的内容,函数是 python 和面向对象编程不可或缺的一部分。我们简要介绍了 python,并对函数在 Python 编程语言中的作用有了基本的了解。
详细讨论了args 和kwargs 的概念,以及这些参数选择在 python 编程中到底有多有用。在这些主题的帮助下,我们可以编写更高效的代码来处理复杂的任务。
如果你对今天的话题有任何疑问,请在下面的评论中告诉我。我会尽快回复你。如果我错过了什么,请随时告诉我。您希望我在以后的文章中介绍这一点。
查看其他一些可能对您的编程之旅有用的文章!
这是一个有趣的“不给糖就捣蛋”的游戏,让你在万圣节愉快地学习 python 编程
towardsdatascience.com](/simple-fun-python-project-for-halloween-ff93bbd072ad) [## 5+独特的 Python 模块,用于创建脱颖而出的机器学习和数据科学项目!
超过 5 个酷 Python 库模块的指南,用于创建令人敬畏的机器学习和数据科学项目。
towardsdatascience.com](/5-unique-python-modules-for-creating-machine-learning-and-data-science-projects-that-stand-out-a890519de3ae) [## 用代码和例子理解 Python 中的高级函数!
详细了解 python 中的匿名函数和高级函数及其实际应用…
towardsdatascience.com](/understanding-advanced-functions-in-python-with-codes-and-examples-2e68bbb04094)
谢谢你们坚持到最后。我希望你们喜欢阅读这篇文章。我希望你们都有美好的一天!
参考资料:
- 极客对极客
- 油管(国外视频网站)
了解格鲁、LSTM 和 RNNs
在这篇文章中,我们讨论了序列模型的工作原理及其应用。
序列模型是一类特殊的深度神经网络,可应用于机器翻译、语音识别、图像字幕、音乐生成等。序列问题可以是不同类型的,其中输入 X 和输出 Y 可能都是长度相同或不同的序列。也可以是 X 或 Y 中只有一个是序列。以下是 RNNs 应用的几个例子:

吴恩达在 Coursera 上的图片
单词表示法
如果输入是一个句子,那么每个单词都可以表示为一个单独的输入,如 x(1)、x(2)、x(3)、x(4)等。那么,我们如何表示句子中的每个单词呢?我们需要做的第一件事是拿出一个字典,包含我们在输入句子中可能有的所有单词。字典中的第一个词可能是“a”,再往下我们可能会找到“and”或“after”,最后一个词可能是“zebra”或“zoo”之类的词。准备字典真的是在我们的手中,因为我们可以包括尽可能多的单词。一本字典的长度可以从 10,000 到 100,000 不等,甚至更多。
假设我们有一个命名实体识别问题,其中 X 是一个输入句子,如“杰克和吉尔上山了”Y 是表示每个输入单词是否是人名的输出。因此,本质上 y(1),y(2),y(3),y(4)如果是人名,则为 1,否则为 0。并且 x(1),x(2),x(3),x(4)将是长度为 10,000 的向量,假设我们的字典包含 10,000 个单词。例如,如果 Jack 出现在我们的字典中的第 3200 个位置,x(1)将是一个长度为 10,000 的向量,在第 3200 个位置包含 1,在其他位置包含 0。可能会有这样的情况,输入序列中的一个单词在我们的字典中不存在,为此,我们可以使用一个单独的标记,如“unknown”或其他。
为什么我们需要 RNNS?
下一步是建立一个神经网络来学习从 X 到 y 的映射。一种可能性是使用一个标准的神经网络,在我们的情况下,将七个单词作为输入,以七个一键向量的形式输入到标准的神经网络,然后是一些隐藏层和一个 softmax 层,最后,通过将 0 或 1 作为输出来预测每个单词是否是一个人的名字。但是这种方法有两个问题,一个是对于不同的例子,输入可以有不同的长度,在这种情况下,标准的神经网络将不起作用。其次,像这样幼稚的架构不会共享出现在文本不同位置的特征。例如,如果网络已经知道在文本的第一个位置出现的 Jack 是一个人的名字,如果 Jack 出现在任何位置 x_t,它也应该将 Jack 识别为一个人的名字。

吴恩达在 Coursera 上的图片
由于这些原因,我们需要一个递归神经网络,其中第一层的输入是字向量 x(1)和一个激活函数 a_0,它可以用几种不同的方式初始化。第一层的输出将是 y(1),表示 x(1)是否是人名。第二层将具有来自第一层的输入 a(1 ),第二字向量 x(2)给出输出 y(2 ),依此类推,直到最后一层或最后一个时间步将具有输入 a(t-1)和 x(t)给出输出 y(t)。
因此,在递归神经网络中,信息从左向右流动,在对 y(3)进行预测时,来自 x(1)和 x(2)的信息也与 x(3)一起使用。但是这种 RNN 的一个缺点是,它只考虑出现在我们试图预测的单词之前的单词,而不考虑它后面的单词。比如预测 y_3,我们用的是 x(1),x(2),x(3)而不是 x(4),x(5),x(6),x(7)等等。例如,以“他带罗斯去一家不错的餐馆吃饭”为例。在这里,如果你试图用两个单词“he”和“take”来预测 Rose 是否是一个人的名字,你不会得到好的结果,因为句子可能是“他从花束中取出玫瑰花瓣并把它铺在床上”。因此,在预测 y(3)时,最好考虑 x(3)后面的单词,如 x(4)、x(5)、x(6)、x(7)等。这个问题可以通过使用双向 rnn 或 BRNNs 来解决,我们不会在本文中讨论。
基本 RNN 建筑
先说一下我们网络的参数。在第一层中,a(0)来自左边,x(1)来自底部。为了计算 a(1),我们将 a(0)乘以一组参数 Waa,将 x(1)乘以一组参数 Wax,然后将两者相加,再加上一个偏差 b_a。接下来,为了计算 y^(1,我们将 a(1)乘以一组参数 Wya,再加上一个偏差 b_y。现在,RNNs 的优点在于,我们对所有时间步长使用相同的参数 Wax、Waa、Wya。计算 a(t)和 y^(t 的方程式如下:
a(t)= g(W _ aa * a(t-1)+W _ ax * x(t)+b _ a)
y ^(t)=g(W_ya*a(t)+b_y)
我们用上面的等式计算 y(1、y(2、y(3、y(4 等等,直到 y^(t。然后,我们将所有 y^(t 与地面真实值 y(t)进行比较,以计算可以通过我们的网络反向传播的损耗。然后我们把每个时间步的损失加起来,这就是为什么我们称之为时间反向传播。损失函数类似于逻辑回归中使用的交叉熵损失函数。损失函数将如下:
L(t)(y^(t),y(t))= -y^(t)log y(t)-(1-y(t))log(1- y^(t))
总损失 = ∑ L(t)(y^(t),y(t))
到目前为止,我们一直在处理输入长度 X 等于输出长度 y 的情况。但是,情况可能并不总是这样。例如,在情感分类中,我们有一个输入序列 X,但是 Y 可以是 1 到 10 之间的整数。例如,假设您有一个文本“这部电影的情节很糟糕,表演也很一般”,您想给它打 1-5 颗星。在这种情况下,我们将在每个时间步输入一个字,而没有输出 y^(t,并在最后一个时间步或最后一个字输出单个 y^。这被称为多对一架构。还可能存在一对多架构的情况,例如,音乐生成,其中我们只有一个输入 a(0 ),它可以是一个整数,表示我们想要生成的音乐流派或音乐的起始音符。然后,我们从 a(0)获得输出 y^(1,该输出与 a(1)一起被馈送到下一个时间步骤,以获得 y^(2,该输出与 a(2)一起被再次馈送到下一个时间步骤,以生成 y^(3,然后是 y^(4,等等,直到生成最后一段音乐。
还可能存在多对多架构的情况,其中输入长度 X 不等于输出长度 Y,例如在机器翻译中,我们试图使用 RNN 将法语句子翻译成英语,法语句子的长度可能与翻译的英语句子不同。以下是不同类型的 RNN 架构的概述:

图片来自 Coursera 上的 Angrew Ng
消失梯度问题
到目前为止,我们讨论的可以称为基本 RNN 算法,基本 RNN 的一个问题是它可能会遇到消失梯度问题。例如,假设我们有一个句子“孩子在操场上跑了几个小时,到家时已经筋疲力尽了”。然后想想这句话“孩子们在操场上跑了几个小时,回到家时已经筋疲力尽了”。因此,为了保持一致,应该是“kid was”和“kid was ”,这向我们表明,句子可以具有长期依赖性,而基本的 rnn 无法捕捉到这一点。这意味着,当我们有几个时间步长的非常深的 RNNs 时,与后面的时间步长相关的误差很难影响前面的时间步长的计算。在这种情况下,RNN 必须记住“kid”是单数,因此以后应该使用“was ”,对于“kids”应该使用“were”。在英语中,我们看到单词可以有很长的依赖关系,这是基本的 rnn 无法解决的。这里,输出 y^(5 只受接近 y^(5 的值的影响,这使得输出很难受到序列中更早出现的输入的强烈影响。
另一方面,我们也可能遇到爆炸梯度问题,其中我们的参数变得非常大,并且不收敛。爆炸梯度问题可以通过梯度裁剪来解决。但是一般来说,与爆炸渐变相比,消失渐变是一个更常见也更难解决的问题。现在,让我们来谈谈格鲁斯和 LSTM,他们是用来解决梯度消失问题的。
门控循环单元
门控循环单元有一个新的变量,称为内存单元或“c ”,为 RNNs 提供所需的内存。所以在我们之前的例子中,记忆细胞帮助 RNN 记忆我们句子中的主语是单数还是复数,这样在后面的句子中,它可以考虑主语是单数还是复数。在每一个时间步,我们将考虑用一个新的变量 c ̃(t).覆盖 c(t)我们将使用参数 Wc 矩阵的激活函数 tanh 乘以前一存储单元 c(t-1)和当前输入 x(t)加上偏置项 b 来计算 c ̃(t。现在,GRU 的一个非常重要的元素是门γ_ u,也称为更新门,其值在 0 和 1 之间,因为它是使用 sigmoid 函数计算的。但是出于所有实际目的,γ_ u 可以被假定为 0 或 1,因为对于大多数值范围,sigmoid 函数非常接近 0 或 1。
然后我们尝试使用 c ̃(t 来更新 c(t)的值,并且门γu 决定我们是否更新它。所以基本上,如果γ_ u 等于 1,这意味着用 c ̃(t 更新单元存储器 c(t ),在我们的例子中,它可以用来记住我们句子的主语是单数,即“孩子”。现在,对于接下来的几个时间步,让我们假设γ_ u 等于 0,这意味着我们在告诉 RNN 不要更新存储单元的值,保持设置 c(t) = c(t-1),以便记住主语是单数。而到了需要决定主语是单数还是复数的时候,细胞记忆就会告诉我们,主语是单数,应该用‘was’而不是‘were’。如果我们不需要在句子中进一步记住主语是单数还是复数,γ_ u 可以被设置为 1,这意味着现在我们可以忘记旧值并用新值 c ̃(t).更新存储单元以下等式将更好地描述 GRUs 的工作方式:
1.̃(t) = tanh(W_c [c(t-1),x(t)] + b_c)
2.γ_ u = σ(w_u[c(t-1),x(t) ] + b_u
3.c(t)= γ_uc ̃(t)+(1-γ_ u) c(t-1)
在 GRUs 的情况下,c(t)是下一个时间步长 a(t)的激活值,c(t)也可以通过类似 softmax 的函数传递,以获得当前时间步长的输出 y(t)。这就是我们需要了解的关于 GRUs 的所有信息,下图将更好地展示 GRUs 的工作原理:

米歇尔·卡瓦奥尼关于机器学习叮咬的图片
长短期记忆
LSTM 是长短期记忆的缩写,是另一种可以解决消失梯度问题并帮助记忆序列中的长期依赖性的算法。LSTM 可以被认为是一个更强大和通用版本的 GRUs。一个主要的区别是在 LSTMs 中,a(t)不等于 c(t)。下面的等式支配着 LSTM 的工作,我们将详细讨论它:
- c ̃(t) = tanh(W_c [a(t-1),x(t)]+b_c)
2)γu = σ(w_u[a(t-1),x(t)]+b u)
3)γf = σ(w_f[a(t-1),x(t)]+b_f)
4)γ_ o = σ(w_o[a(t-1),x(t)]+b_o)
5)c(t)=γ_ u∫c ̃(t)+γ_ f∫c(t-1)
6)a^(t)=γ_ o∫c(t)
这里你可以看到我们用的是 a(t-1)而不是 c(t-1)。我们可以看到的另一个区别是,我们用γu 和γf 来计算 c(t ),而不是γu 和(1-γu)。并且γ_ f 被计算为 W_f 矩阵的 sigmoid 乘以[a(t-1),x(t)]加上 b_f。因此,存储单元 c(t)的新值是更新门,γ_ u 逐元素地乘以 c ̃(t)加上遗忘门,γ_ f 逐元素地乘以存储单元 c(t-1)的先前值。我们还有一个输出门γ_ o,它的计算方法是 W_o 矩阵的 sigmoid 乘以[a(t-1),x(t)]加上 b_o。此外,如前所述,a(t)不等于 c(t),而是等于输出门γ_ o 按元素乘以 c(t)。所以,基本上在 LSTM,我们有三个门:更新门,忘记门和输出门,而 GRUs 只有一个更新门。下图将让我们更好地了解 LSTM 是如何运作的:

Michele Caviaone 关于深度学习的图片
现在,想象有一堆并联的 LSTM 单元。每个单元将有一个输入 x(t),如 x(1),x(2),x(3),x(4)等等,并且一个单元的输出 a(t)将是下一个相邻单元的输入 c(t+1)。如果我们适当地设置遗忘和更新门,我们可以让某个值 c(1)一直传递到 c(6)而不被改变,使得 c(1) = c(6)。在我们之前的例句中,“孩子们在操场上跑了几个小时,到家时筋疲力尽”,主语是复数的信息可以存储在以“孩子”作为输入的单元的存储单元 c(2)中,就在以“The”作为输入的单元之后。然后,它可以一直被传送,直到该单元的存储单元 c(10)将“和”作为输入,使得 c(10) = c(3),从而我们得到 y(10)的期望输出,该输出应该是“是”。这就是为什么 LSTM 和格鲁非常善于记住长期依赖关系。下图显示了 LSTM 单元之间的连接方式:

吴恩达在 Deeplearning.ai 上的图片
LSTM 对格鲁
我们什么时候应该使用 GRU,什么时候应该使用 LSTM?这个问题没有明确的答案,尽管我们首先讨论了格鲁,但 LSTM 在实践中要早得多。然后 GRUs 作为更复杂的 LSTM 模型的简单版本被发明出来。与 LSTM 相比,gru 模型更简单,计算量也更小。因此,我们可以用 GRUs 建立更大的网络,尽管 LSTM 更强大、更有效。但更重要的是,这两种算法都不是普遍的优越算法,它真的取决于我们正在处理的数据和我们试图解决的问题。
这是我想在这篇文章中涵盖的所有内容。希望您能够对序列模型的工作原理及其在现实世界中的应用有一个很好的了解。我要感谢吴恩达博士关于深度学习专业化的课程,没有他,我就不能写这篇文章。我正在写一篇文章,在这篇文章中,我将演示我们如何用 python 实现这些算法,并创建一些有用的应用程序。我还在撰写一些关于光束搜索算法的文章,该算法可用于改善机器翻译和图像字幕,以及用于检查机器翻译和图像字幕性能的 bleu 评分。所以,敬请期待!
HDFS 擦除编码
通过利用擦除编码,显著降低 HDFS 集群的存储开销

假设:
您已经了解并内化了 Hadoop 分布式文件系统或 HDFS 的基本概念— 数据块&复制因子、存储&复制和机架感知
背景
Hadoop 分布式文件系统(HDFS)数据块和复制方法有两个关键概念,即“数据块大小”和“复制因子”。进入 HDFS 的每个文件都被分成几个块或“区块”。块数取决于分配的最大块大小,通常为 128 MB。创建数据块后,它们会在 HDFS 集群中复制。副本的数量由复制因子(RF)决定,通常配置为 3 (1 份原件和 2 份副本)。这种冗余有助于建立弹性和容错能力,也就是说,当一个数据块出现故障时,我们可以从另一个数据块安全地恢复数据。

基于块大小的文件分割= 128 MB
上图是我们刚刚讨论过的分割的快速演示。一个 700 MB 的文件被分成 6 个块。128 MB 的 5 份和 60 MB 的 1 份。复制系数为 3 时,它将消耗(6*3) = 18 个数据块和(700 MB * 3) = 2100 MB 的存储。考虑将其扩展到 Pb 级,您将很快意识到由于数据复制带来的冗余而导致的可用空间的严重利用不足。
因此,对于 3-n/3 路复制(即 RF = 3),其中 n =副本数量,我们有 2 个复制的数据块,即 200%的存储开销,效率为(1/n)或(1/3)或 33%,n-1 = 2 作为容错。更不用说创建、维护和执行 BAU 活动的网络和 I/O 使用情况了。
虽然廉价的存储和出色的网络带宽是当今世界的现实,但这种为容错和弹性建立冗余的方法仍然非常低效。这带来了一种新的模式,可以显著提高保护数据的效率。
擦除编码
通过英特尔和 Cloudera 的优秀人员的共同努力,擦除编码(EC)在 3.x 版中被引入 Hadoop。
继续同一个示例,一旦数据在 HDFS 被分割成几个块,它就作为输入被传递给 EC,EC 返回许多奇偶校验块。这个过程称为编码,而(数据+奇偶校验块)称为编码组。在失败(也称为擦除)的情况下,可以从该编码组中重建数据,称为解码。
引擎盖下发生了什么?

对 OR 和 XOR 有基本的数学理解
在被称为⊕的异或或异或编码中,数据(INs)通过被称为异或的数学运算传递,结果(OUT)为单个奇偶校验块,如上所示。此外,XOR 有两个漂亮的数学特性:
可交换的 : B1⊕ B2 = B2⊕ B1
联想:b1⊕【b2⊕B3】=【b1⊕b2]⊕B3
意思是——输入的排列不会改变输出。
作为推论,我们可以扩展到我们的示例,使用 6 个数据块作为输入,我们将在磁盘上总共消耗 7 个存储块,6 个数据块和 1 个奇偶校验块。与 HDFS 的三向复制相比,这显著提高了效率。并且如果任何一个数据块失败,例如如果 B2 失败,则剩余的块被异或,即 b1⊕P1⊕b3⊕b4⊕b5⊕b6,以恢复丢失的数据 B2。然而,≥2 个同时故障且数据不可恢复。因此,XOR 最多可以容忍 1 次故障,效率为((n-1)/n)或约 83%,其中 n =数据块的总数。由于 XOR 具有低容错性,所以它对于 HDFS 的要求来说是完全不可接受的。

里德·所罗门编码(来源)
Reed-Solomon【RS】编码通过使用复数线性代数生成多个奇偶校验块,解决了 HDFS 处理多个同时失效的需求。RS 编码表示为 RS₍ₖ,ₘ₎,使用两个参数,其中 k 是数据块的向量,m 是奇偶校验块的数量。这是通过将数据块向量 k 乘以生成矩阵(Gᵀ)得到长度= (k+m)或长度=(数据+奇偶校验)的 Codeword₍ₖ₊ₘ₎向量而生成的,如上图所示。
当故障发生时,通过将剩余的块(或幸存者)乘以生成矩阵的逆矩阵来进行恢复,前提是 k 个块总是可用的。因此,最多可以容忍 m 个故障。在我们的示例中,使用 k & m 的最佳实践参数,即 RS(6,3),具有 6 个数据块的文件将消耗磁盘上的 9 个存储块(即 6 个数据块和 3 个奇偶校验块),或者每 2 个数据块消耗 1 个奇偶校验块。因此,只需要 50%的存储开销,效率为(k/(k+m))或约 67%。
还有另一种流行的 RS 配置,即 RS(10,4),其效率为(k/(k+m))或约 71%,存储开销约为 50%。
选择正确的区块布局
我希望到现在为止,你们都支持 HDFS 的(6,3)或(10,4)配置的 Reed Solomon 擦除编码。
在连续块布局中,你在 HDFS 基础上有一个更简单的实现。考虑部署在连续块布局上的 HDFS EC RS(10,4 ),块大小固定为 128 MB。无论您有 10 个数据块还是 1 个数据块要写入,都会写入 4 个奇偶校验块。因此,对于单个数据块(比如 B5),存储效率开销现在约为 400%,比三向复制还要糟糕。我们所有的存储效率收益都化为乌有。为了证明从 HDFS 三向复制切换到具有连续布局的 EC 的合理性,需要写入所有 10 个数据块。同样,对于具有相同块布局的 RS(6,3),我们需要 6 个写入的数据块来确保存储效率。
根据几个项目的个人经验和 Cloudera 的行业研究(参考下文),存储在 HDFS 的大约 70–95%的数据小于 1 个数据块或 128 MB。在条带化块布局中,文件被“条带化”为较小的大小,通常为 64 KB 或 1 MB 数据“单元”。因此,无论我们使用 RS(10,4)还是 RS(6,3),创建的奇偶校验单元都不会对存储开销产生太大影响。
最重要的是,HDFS 允许在集群中的目录或文件级配置不同的复制和擦除编码策略。由于文件大小是块布局的决定因素,从数据持久性和存储效率的角度来看,在文件/目录级别应用擦除编码策略的能力非常有益。
HDFS 的建筑变革
为了用条带化布局处理 EC,进行了某些体系结构上的更改。
名称节点扩展:
文件的逻辑块或字节范围已从存储块中分离出来,存储块在数据节点中存储实际的数据块。HDFS 命名节点现在将其块 ID 分别映射到数据节点的存储块和逻辑块。这在名称节点上产生了大约 250–440%的巨大存储开销。

具有 3 个部分的分层块
因此,引入了一种新的分层块命名协议来解决空间使用过度增长的问题。我们不是基于时间戳顺序分配块 id,而是将块映射分成 3 个部分,如上所述。注意,对于连续区块布局,只有 2 个部分。因此,神经网络能够以摘要-细节或分层协议的形式管理逻辑和存储块,并将开销限制在大约 21–76%。
客户端扩展:
将 DFSInputStream (Java 数据类型)扩展为 DFSStripedInputStream,将 DFSOutputStream (Java 数据类型)扩展为 DFSStripedOutputStream,以适应数据分条和 EC。由于逻辑块和存储块现在是分开的,使用条带化数据类型,我们可以在 HDFS 实现块的并行创建/处理。
数据节点扩展:
神经网络识别丢失的块,并将恢复分配给数据节点。这由一个新的组件来处理,即 ECW 或 ErasureCodingWorker 、,它执行三个任务。首先,它向所有没有失败的数据源发送一个读请求。第二,使用英特尔优化的 Reed Solomon Erasure 编解码器框架, ISA-L ,ECW 对数据进行解码。第三,它将恢复的数据推送到故障数据节点。
最后,让我们总结一下到目前为止我们所讨论的利弊:
优点
- 在线电子商务支持:将数据实时转换为电子商务,从而立即节省存储空间,并完全避免临时/导入后数据转换过程。
- 低存储开销:将存储开销降低到仅 50%左右。
- 向后兼容:HDFS 的大多数功能,如快照、加密和缓存,在 EC 模式下也可用。
限制
- 由于架构的变化,HDFS 的一些原生特性,如 hflush、hsync 和 append 在 EC 模式下不可用。然而,作为 HDFS-欧共体第二阶段的一部分,这一问题可能会得到解决。
- 在线/离线 EC 对集群提出了大量带宽和 IO 要求。但是,带宽与存储效率和耐用性之间的权衡应该被视为一种微妙的平衡,因为当使用 EC 进行条带化时,这种权衡是真正有益的。
参考文献:
[1] HDFS 擦除编码 (2017),Apache Hadoop,ASF
[2] A.Wang,Z. Zhang,K. Zheng,U. Maheshwara 和 V. Kumar,Apache Hadoop 中的擦除编码介绍 (2015),Cloudera
J. Plank 教授,存储应用擦除编码教程,第 1 部分 (2013),田纳西大学 EECS 系
登录页面
medium.com](https://medium.com/@prathamesh.nimkar/big-data-analytics-using-the-hadoop-ecosystem-411d629084d3)
简化精确度、召回率和 F1 分数
用基本术语解释评估指标
机器学习术语可能看起来非常费解,好像它们是为了让机器理解而制造的。不直观和听起来相似的名称,如假阴性和真阳性、精确度、回忆、ROC 下面积、敏感性、特异性和疯狂。好吧,最后一个不是真的。
已经有一些关于精确和召回的好文章,但是当我阅读它们和其他关于 stackexchange 的讨论时,这些混乱的术语在我脑海中混在一起,我比一个未标记的混乱矩阵更加混乱——所以我从来没有感觉到我完全理解了它。

混乱的混乱矩阵
但是要知道我们的模型是如何工作的,掌握评估指标并在深层次上理解它们是很重要的。那么一个数据科学家真正需要知道什么来评估一个分类模型呢?我在下面用图片和例子解释了最重要的几个,这样它就能永远留在我们的脑海里。
精度
让我们从最简单的——精确度开始。这实际上是你的模型在猜测正确的标签或基本事实方面有多好。如果你的数据集非常平衡,并且你关心每个类别是否正确,这就是你需要担心的。

可悲的是,如果你的数据集像欺诈检测数据集一样不平衡,那么非欺诈案例占你的标签的 80–90%的可能性很大。因此,如果您的模型盲目地将所有数据点预测为多数标签,我们仍有 80–90%的准确性。
这就是我们需要精确和回忆的时候。
精确度(也称为特异性)
精度是模型正确预测值与模型预测值的比率。对于每个类别/类,都有一个精度值。
当我们需要正确的预测时,我们关注精度,也就是说,理想情况下,当您预测标签时,您希望确保模型是正确的。举个例子,如果你有一个足球博彩模型预测是否下注,你最关心的是它是否正确,因为你会根据它的预测采取行动,但当它告诉你不要下注时,你并没有赔钱。
当倾向于精确时,错误预测的成本比错过正确预测的成本高得多。

回忆(也称为敏感度)
召回率是模型正确预测的数量与实际标签数量的比率。类似地,对于每个类别/类,都有一个召回值。
当我们想要最大化特定类别的预测时,我们关心回忆,也就是说,理想情况下,你希望模型捕获该类别的所有示例。例如,机场安检扫描机必须确保探测器不会漏掉任何真正的炸弹/危险物品,因此我们可以接受有时拦下错误的行李/旅客。
当倾向于回忆时,错过一个预测的代价比一个错误的预测要高得多。

f1-得分:结合精确度和召回率
如果我们希望我们的模型有一个平衡的精度和召回分数,我们平均他们得到一个单一的指标。但是什么样的平均才是理想的呢?对于精确度和召回率这样的比率,与通常的算术平均值相比,像 F1-Score 这样的调和平均值更合适。
调和平均数的定义似乎很复杂:分数的算术平均数的倒数和倒数。我处理冗长定义的方法是从最深层开始,逐层理解。有 3 个:

权衡:生活的现实
正如你可能已经想到的,精确度和回忆对我们来说更重要——是错误预测的代价,还是错过真相的代价?很多时候,你必须放弃一个才能得到另一个。下面是谷歌对权衡的一个很好的解释/viz,以及如何切换分类阈值让我们决定我们关心什么——注意,这也将改变我们的 F1 分数。

https://developers . Google . com/machine-learning/crash-course/classification/precision-and-recall
结论
我希望这用简单直观的方式解释了准确度、精确度、召回率和 F1。结合示例,我认为这是理解其他评估指标的良好开端。那么,你的业务目标是更接近博彩模式、机场扫描仪,还是两者兼而有之?

资料来源:联合国人类住区规划署
简化机器学习中的决策树
最流行和最常用的 ML 算法之一

资料来源:联合国人类住区规划署
这是机器学习最简单和最基本的模型之一,可以用于分类和回归。让我们以我们熟悉的问答方式深入了解决策树。我们在这里还有一个理论的视频讲座,在这里还有 python 的实际操作。
决策树有哪些组成部分?
基本成分是
一个)根节点:这通常会在节点中提供完整的训练数据。来自所有类的数据将混合在一起。
b) 决策节点:通常情况下,它的格式类似于属性“A”和条件“k”。例如年龄> 30,这创建了另外两个节点。
c) 内部节点和终端节点:内部节点是决策节点的结果,如果它们足够纯,它们可以是终端节点,否则它们是内部节点,这将需要再次经过决策节点。决策节点可以清楚的告诉我们,一个未知的观测如果落在那个节点会被贴上什么标签。
让我们用一个非常简单的例子来说明,假设我们有 10 个学生的数据,他们的语言能力和数学成绩。根据学生的安置成功率,将学生分为三类。这三个类分别被立即放置(PI)、一段时间后放置(PA)、未放置(U)。

图 1:样本学生安置数据(来源:作者)
当一个决策树,它将有一个结构如下,为上述数据。该树具有一个根节点、两个决策节点(数学=高,英语=高)和对应于三个类别的三个终端节点。

图 2:学生安置数据的决策树(来源:作者)
观察结果:
- 就类而言,根节点是非常混合的,当我们移动到终端节点时,节点具有更同质的群体(最多 2 个类,1 个类是大多数)。
- 现在,如果我们有一个学生萨姆,我们知道他数学和英语成绩都很高,按照决策树,我们知道,他被立即安排的机会非常高。
因此,一个有争议的问题是,我们希望向更同质的终端节点发展。这需要定义一个同质性或缺乏同质性的衡量标准。
我们如何正式度量一个节点的同质性或异质性?
这需要引入一个叫做熵的概念。
熵:
它是对随机变量中存在的不确定性的一种度量。根节点是所有类的混合,所以如果我们随机选择一个,不确定性在根节点是最高的,并且我们向终端节点移动,这种不确定性逐渐降低。我们称之为信息增益。
我们现在明白了,熵将是概率的函数。

图 3:熵方程(来源:作者)
X 是随机变量,H(X)是随机变量的熵。s 是随机变量或样本空间的一组值。s 是采样点。我想你会同意抛硬币是任何随机实验的终极 hello world。
当它是一个公平的硬币时,它是完全随机或不确定的,逐渐地我们可以偏向它,使它甚至为 1。让我们用例子再次理解这一点。我们来看下头部概率的不同场景。

图 4:熵值与头部概率(来源:作者)
观察:
- 当头部和尾部具有相等的概率时,熵最高
- 当压头完全确定时,它是最低的
- 在这两者之间,随着获得优势的确定性增加,熵值下降了
所以,我们知道我们应该从高熵的节点转移到低熵的节点,但是如果有两个属性‘a’和‘b’,我们如何使用熵来做出这个决定。
信息增益进入的时间。
什么是信息增益?
这由下面的等式正式定义。这个想法很简单。假设根节点具有熵 E,并且当我们在某种条件下(比如数学分数=高)通过属性“a”进行分割时,我们得到另外两个节点 N1 和 N2,它们具有相应的熵 E1 和 E2。
第一个切割信息增益将是 E -( E1 + E2)/2。下一步,我们只是做了一个改进,用 N1 和 N2 分别出现的元素数量来衡量熵。这就是下面等式中的形式。
H(T) —分裂前的熵 H(T/a) —在某种条件下被属性‘a’分裂后的熵

图 5:信息增益方程(来源作者)
如何应用信息增益来选择要拆分的属性?
让我们用必要的数学知识进一步理解这一点,让我们比较两种可能的拆分选项,如“A”和“B”

图 6:分割选项(图片:作者)
信息增益的计算如下所示

图 7:通过属性 A 或 B 分割的选项(来源:作者)
观察
- 场景 A 的熵为 0.81,场景 B 的熵为 0.69
- 根节点的熵为 1.0(与投掷公平硬币的场景相同)
- 因此,信息增益在第一种情况下为 0.19,在第二种情况下为 0.31 。因此,将选择属性 B。
还有另一个衡量信息增益的等效指标,叫做基尼指数。根据参考文献[1],只有 2%的情况下使用基尼指数或信息增益才重要。所以,我们不要再提这件事了。
这些树有哪些不同的变种?
- 这更具有学术意义,我们在这里讨论初步的树,如 ID3、C4.5、C5.0 和 CART。
- ID3 迭代二分器 3 使用信息增益。由罗斯·昆兰于 1986 年发明
- 它首先找到要分割的最佳分类属性。
- 然后递归选择下一个属性(未选择)
- 直到不可能再进行拆分,即到达叶节点或没有属性留下来进行拆分
- 这是一个贪婪的算法,不回溯。
- C4.5 取消了分类属性的限制,但允许将数值属性转换为分类属性(J48)
- C 4.5 有能力处理丢失的数据 C4.5 有能力回溯它在数据挖掘的十大算法中排名第一之后变得非常流行
- C 5.0 在生成更小的树、有效使用内存、加速
- CART 是另一个非常著名的算法,它可以处理数值和分类属性,可以处理分类和回归,并且具有处理异常值的能力。它的分裂是双向分裂。
我们如何处理决策树中的过度拟合?
像任何机器学习问题一样,这些模型也容易过度拟合。如果一棵树被过度种植,那么它通常会有更多的深度。更多数量的终端节点。所以,一棵光滑的树会更少的过度生长。我们在这里讨论一些策略。
a)叶或末端节点中的最小观察数:
理想情况下,为了拟合数据,我们最终可以在所有叶节点中进行一次观察。会很好地拟合训练数据,测试数据失败
b)分割一个节点所需的最小观察次数:
这将确保我们不会为了更高的训练集精度而继续分裂甚至具有少量观察值的节点
最大允许深度:
基本上,随着最大允许深度的增加(基本上是连续决策节点的数量),树往往会过度拟合。

图 8:最大深度对测试集准确性的影响(来源:作者)
上图是我们使用决策树(https://www.kaggle.com/saptarsi/decision-tree-sg/)进行实验的结果,还有一些有趣的实验,你可以了解一下。
它清楚地显示了 12 的深度是好的,在此之后,测试精度没有太大的增加。
d)正则化损失函数:
下面的等式是在回归树的上下文中,其中 T 是叶节点的数量,基本上,决策树将特征空间分割成矩形区域。如果有 T 个节点,则在特征空间中将有 T 个矩形判定区域。随后的目标函数的第一部分是正则平方误差,第二部分针对决策区域的数量进行惩罚或正则化。
所以,如果我们有两棵树,都有相同的平方误差。树 1 有 5 个叶节点,树 2 有 4 个叶节点。这个等式会更喜欢第二个。(转载自 ISLR)

图 9:决策树目标函数(来源:作者)
结论:
- 决策树提供了极好的可视化,分类的原因对业务用户来说是清楚的,因此是一个白盒模型。
- 非常简单易懂
- 但是,可能无法提供最佳性能(这可以使用随机森林、增强等解决。)
========================================
谢谢你读到这里。这些是我们在加尔各答大学数据科学实验室创建的一些附加资源
一)用 Python 分类(https://www.youtube.com/playlist?list = plts 7 rwcd 0 do 2 zoo 4 sad 3 jrxnvfyxhd 6 _ S
b)用 Python(https://www.youtube.com/playlist?)进行聚类 list = plts 7 rwcd 0 do 3ts 44 xgwgvgxmeohyfi 3pm)
参考:
[1] Raileanu LE,Stoffel K .基尼指数与信息增益标准的理论比较。数学与人工智能年鉴。2004 年 5 月 1 日;41(1):77–93.
[2]https://towards data science . com/the-complete-guide-to-decision-trees-28 a4 E3 C7 be 14
[3]https://towards data science . com/decision-trees-in-machine-learning-641 B9 c4e 8052
MapReduce
简化 MapReduce 框架

Apache Hadoop MapReduce 架构
在 2003 年,Google 提出了一个迷人的框架,通过他们革命性的白皮书“MapReduce:大型集群上的简化数据处理”,在分布于多个节点的大型数据集上实现并行处理。
现在,MapReduce (MR)是 Hadoop 的主要处理框架,跨多个应用程序使用,如 Sqoop、Pig、Hive 等。
数据存储在 HDFS
如果你是 HDFS (Hadoop 分布式文件系统)的新手,或者想要复习一下,我建议你看看我的综合指南。否则,继续阅读。
在上面的流程图中,我们在 HDFS 存储了一个大的 csv 文件。我们的复制系数(RF)为 2,数据块大小为 128 MB,有 2 个数据节点。因此,B1、B3、B3、B4 等,每个大小为 128 MB,放置在两个数据节点中,如上面的流程图所示。
Hadoop 与传统客户端-服务器架构的不同之处在于,数据位于静态位置,而作业/流程移动到数据所在的位置。这显著提高了性能。
想想看,数据的大小通常是 GB 到 PBs,而作业/进程只有几 MB。因此,通过网络将数据转移到作业/流程中非常昂贵,但是通过网络将作业/流程转移到存储数据的地方非常便宜。这就是 HDFS 建筑的美。
制图人
从本质上讲,谷歌的人认为数据处理的大多数用例都适合 Map + Reduce 任务。我认为大约 90%的任务都适合这种形式。
那么,什么是映射器呢?映射器只是一个函数,它接受一个键、值(k,v)对,对其进行处理并返回一个(k,v)对。下面是它的编程方式:
map(in_key, in_value) -> list(intermediate_key, intermediate_value)
工作开始:地图 0%减少 0%

制图人
- 输入格式— 指向 HDFS 文件块位置的指针。这些数据仍然没有被加载到内存中,目前按原样放在 HDFS 上。在我们的例子中,节点 1 的输入格式中的指针指向块 1 和块 2。类似地,在节点 2 中,它指向块 3 和块 4。
- Split — 此时,文件实际上被加载到内存中。拆分的数量等于该节点中的块数。拆分器和 RecordReader 一起工作。
- RR 或 RecordReader — 我肯定您想知道如何将一个简单的文件转换成(k,v)对。嗯,谷歌在他们的白皮书中提到,大部分处理是通过抽象完成的,这很好!记录阅读器只是为我们将数据处理成(k,v)对。此外,有多种方法可以实现这一点。更多细节见下文。
- Map — 最后,我们到达“Map”函数,在这里进行实际的处理。无论您希望函数执行什么逻辑,这里都是它发生的地方。发布此消息后,最终得到的(k,v)对再次被卸载到 HDFS,reducer 任务开始。
工作状态:地图 100%减少 0%
还原剂
一个 reducer,就像一个 mapper,也是一个函数,它接受一个(k,v)对,处理它并返回一个(k,v)对。以下是图示:
reduce(intermediate_key, list(intermediate_value) -> list(out_key, out_value)

还原剂
- 分割器— 中间(k,v)对再次被原样加载到内存中。并且使用这些中间键,将一个分组函数应用于数据集。我们将在下一节的例子中更好地理解这一点。如果你觉得幸运的话——这里有一个定制分区。
- Shuffle — 这是跨节点的分组。基本上,公共键现在在节点间“混洗”。
- 排序— 数据现在根据关键字排序。
- Reduce — 最后,我们到达“Reduce”函数,在这里进行数据的实际聚合。无论您希望该函数执行什么样的聚合,这里都是它发生的地方。
- 输出格式— 最终得到的(k,v)对通过 RecordWriter (RW —更多细节见下文)再次卸载到 HDFS,作业完成。
工作状态:地图 100%缩小 100%
用一个简单的例子把它们放在一起

假设你是特斯拉汽车公司的首席执行官埃隆·马斯克。你得到了以下特斯拉汽车一年来的全球销量数据(百万辆)。很自然,你很高兴,你抽了一些,然后马上在推特上说:
特斯拉的股价在我看来太高了
好吧,那是个错误。那你哭还是不哭。反正我跑题了。
特斯拉汽车销售数据集(百万)
这些数据现在在 HDFS 被分成几个数据块,平均分布在两个数据节点中(根据 RF)。这是两个区块(B1 和 B3)的样子:
映射器输出:
**Country,Sales(M)**
USA,1
Russia,1
UK,1
France,1
China,1
Russia,1
UK,1
France,1
China,1
USA,1**Country,Sales(M)** UK,1
USA,1
China,1
UK,1
USA,1
China,1
UK,1
USA,1
China,1
UK,1
输出到 HDFS —生成 2 个文件
减速器:
**Country,Sales(M): Partition** USA,1
USA,1
Russia,1
Russia,1
UK,1
UK,1
France,1
France,1
China,1
China,1**Country,Sales(M)**: **Partition** UK,1
UK,1
UK,1
UK,1
USA,1
USA,1
USA,1
China,1
China,1
China,1**Country,Sales(M)**: **Shuffle** Russia,1
Russia,1
France,1
France,1**Country,Sales(M)**: **Shuffle** USA,1
USA,1
USA,1
USA,1
USA,1
UK,1
UK,1
UK,1
UK,1
UK,1
UK,1
China,1
China,1
China,1
China,1
China,1**Country,Sales(M)**: **Sort** France,1
France,1
Russia,1
Russia,1**Country,Sales(M)**: **Sort** China,1
China,1
China,1
China,1
China,1
USA,1
USA,1
USA,1
USA,1
USA,1
UK,1
UK,1
UK,1
UK,1
UK,1
UK,1**Country,Sales(M)**: **Reduce** France,2
Russia,2**Country,Sales(M)**: **Reduce** China,5
USA,5
UK,6
输出到 HDFS —生成 2 个文件。大概就是这样。有问题吗?不要犹豫地问。
记录阅读器
以下方法可用于将数据转换成(K,V)对:
RecordReaderInputFormat
记录器(RW)
以下方法可用于将(K,V)对转换为输出数据:
RecordWriterOutputFormat
优步模式
摘自我的 Apache Sqoop 帖子(脚注中的链接):
MapReduce 作业的 Mapper 和 Reducer 任务由 YARN 的资源管理器(RM)在分布于几个节点的两个独立容器中运行。但是,如果您的数据集很小,或者您的作业包含小型制图工具任务,或者您的作业仅包含一个缩减器任务,我们可以将优步模式设置为 TRUE。这迫使 RM 在一个容器或 JVM 中顺序运行 mapper 和 reducer 任务,从而减少了启动新容器和跨多个节点为一个小任务建立网络的开销。工作完成得更快。
参考资料:
[1] J. Dean,S. Ghemawat (2003), MapReduce:大型集群上的简化数据处理,Google
[1.1] J. Dean,S. Ghemawat (2003), HTML 幻灯片— MapReduce:大型集群上的简化数据处理,Google
[2] Manjunath (2016), MapReduce 自定义分区器,Acadgild
[3] C. Chaudhari,什么是优步模式? (2018),Cloudera 社区
[4] MapReduce 教程 (2019),Apache Hadoop MapReduce 客户端,ASF
使用 Apache Flume 将非结构化数据涓滴输入 HDFS
towardsdatascience.com](/apache-flume-71ed475eee6d) [## Apache Sqoop
RDBMS 到 HDFS 并返回
towardsdatascience.com](/apache-sqoop-1113ce453639) [## 使用 Hadoop 生态系统的大数据分析渠道
登录页面
medium.com](https://medium.com/@prathamesh.nimkar/big-data-analytics-using-the-hadoop-ecosystem-411d629084d3)
用 CycleGAN 和 PyTorch 来简化自己
使用 CycleGAN 和 PyTorch 将人脸转换为 Simpsons 角色

作者图片


作者图片
Cyclegan 是一个能够进行不成对图像到图像翻译的框架。它被应用在一些非常有趣的案例中。比如把马转换成斑马(T4),把冬天的照片转换成夏天的照片。
我认为这可能适用于辛普森一家。我的灵感来自于像变黄和 makemeyellow 这样的网站。这个想法是你上传一张你的脸的照片。Cyclegan 会把它翻译成辛普森一家的角色。
值得注意的是论文明确提到大的几何变化通常是不成功的。所以这不太可能有好结果。
但我还是要尝试一下。
安装
首先我们需要安装 CycleGAN。
!git clone https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix
import os
os.chdir('pytorch-CycleGAN-and-pix2pix/')
!pip install -r requirements.txt
数据集
创建数据集比您最初想象的要困难。
为了创建这个数据集,我需要找到辛普森一家角色的特写镜头和普通人的特写镜头。
下载辛普森数据集
最初我的想法是从谷歌图片中抓取图片。不幸的是,要做到这一点,看起来你需要一个来自谷歌控制台的开发者密钥。
所以我从 Bing 中抓取图片。
这在一定程度上起了作用。但是花了这么长时间才下载完所有的图片。在我看了这些照片后,我注意到其中一些根本没有任何人脸。
谢天谢地,我在 kaggle 上偶然发现了一个数据集,里面有我需要的一切。它包含了从几季中提取的辛普森面孔。每个图像为 200x200 像素,包含一张脸。
该数据集将存储在trainA文件夹中。
def create_training_dataset_simpson_faces(download_dir):
%cd $download_dir
# download dataset and unzip
!kaggle datasets download kostastokis/simpsons-faces --force
!unzip \*.zip
!rm *.zip
!cp -a $download_dir/cropped/. $download_dir
# remove unnecessary folders
!rm -Rf $download_dir/cropped
!rm -Rf $download_dir/simplified
# go back to orig directory
%cd /content/pytorch-CycleGAN-and-pix2pix
create_training_dataset_simpson_faces(TRAIN_A)
下载真实人脸数据集
为了创建真实人脸的数据集,我做了一点实验。
Will Kwan 最近使用 stylegan2 在他最近的一个视频中生成数据集。这对他来说似乎相当有效。所以我想我也可以做同样的事情。
这里有一些取自 Nvidia 的 stylegan2 github 库的人脸示例。如你所见,GAN 的输出相当逼真。

这可能比在网上搜索人脸要好得多。我可以为我的模型创建尽可能多的面。另外,我也不必下载笨重的大文件。
该数据集将存储在trainB文件夹中
创建数据集
import matplotlib.pyplot as plt
from tqdm.notebook import tqdm# see Github for full code: [https://github.com/spiyer99/spiyer99.github.io/blob/master/nbs/cyclegan_simpsonify.ipynb](https://github.com/spiyer99/spiyer99.github.io/blob/master/nbs/cyclegan_simpsonify.ipynb)def create_training_dataset_real_faces_stylegan(download_dir):
# create in batches of 100
# reduces RAM requirements
counter = 0
pbar = tqdm(total = LIMIT)
while counter < LIMIT:
seeds = np.random.randint(10000000, size=100)
imgs = generate_images_from_seeds(seeds, 0.7)
for img in imgs:
img.save(download_dir/'real_face_{}.jpg'.format(counter), 'JPEG', quality=100)
counter+=1
pbar.update(1)
del imgs
create_training_dataset_real_faces_stylegan(TRAIN_B)
列车测试分离
接下来,我们需要将数据分为训练和测试。testB将包含我们想要转换成辛普森一家角色的真实面孔。testA将包含辛普森一家的人物,我们想把他们变成真人。
# move images to a new folder
# `images` is the existing image directory:
# `new_dir` is the path that the images will be moved to
# `files_limit` is the limit of files that will be moved
def move_all_images_to_new_folder(images, new_dir, files_limit = None):
files = glob.glob(str(images/'*.*g'))
if(files_limit is not None):
files = files[:files_limit]
for file in files: shutil.move(file, new_dir/os.path.basename(file))
move_all_images_to_new_folder(TRAIN_A, new_dir = TEST_A, files_limit = int(min(LIMIT*0.1, 25)))
move_all_images_to_new_folder(TRAIN_B, new_dir = TEST_B, files_limit = int(min(LIMIT*0.1, 25)))
查看我们的培训和测试数据
让我们看看我们正在处理的图像。
import PIL
import random
def plot_from_image_path(path, title):
all_imgs = glob.glob(str(path/'*.*g'))
print(f'{len(all_imgs)} imgs in {title} directory')
img_path = random.choice(all_imgs)
img = PIL.Image.open(img_path)
plt.imshow(img)
plt.title(title)
plt.show()
plot_from_image_path(TRAIN_A, 'TRAIN_A')
plot_from_image_path(TRAIN_B, 'TRAIN_B')
plot_from_image_path(TEST_A, 'TEST_A')
plot_from_image_path(TEST_B, 'TEST_B')


作者图片


作者图片
一切看起来都很好!
创建模型
现在我们可以创建模型了。我对现有的脚本做了一些调整。
让我们创建几个助手函数。
这些功能帮助我将保存的模型复制到我的 google drive。它还有助于测试模型并将输出图像存储到 google drive。
import os
from pathlib import Path
from distutils.dir_util import copy_tree
import matplotlib.pyplot as plt
import random
def copy_to_drive(folder = 'cyclegan_simpsonify'):
drive_folder = Path('/content/drive/My Drive/')/folder
if(drive_folder.exists()):
shutil.rmtree(drive_folder)
shutil.copytree('/content/pytorch-CycleGAN-and-pix2pix/checkpoints/'+NAME+'/', str(drive_folder))
def get_corresponding_photo(file_path):
return file_path.replace('fake', 'real')
def plot_results(number):
for i in range(number):
img_path = random.choice(glob.glob('./results/'+NAME+'/test_latest/images/*fake.*g'))
print(img_path)
img = plt.imread(img_path)
plt.imshow(img)
plt.title('fake')
plt.show()
print(get_corresponding_photo(img_path))
img = plt.imread(get_corresponding_photo(img_path))
plt.imshow(img)
plt.title('real')
plt.show()
def get_model(src, dst):
# copy across model
try:
os.remove(dst)
except:
pass
shutil.copyfile(src, dst)
def copy_from_drive(folder = 'cyclegan_simpsonify'):
drive_folder = Path('/content/drive/My Drive/')/folder
if(not Path('/content/pytorch-CycleGAN-and-pix2pix/checkpoints/').exists()):
os.mkdir('/content/pytorch-CycleGAN-and-pix2pix/checkpoints/')
if(Path('/content/pytorch-CycleGAN-and-pix2pix/checkpoints/'+NAME+'/').exists()):
shutil.rmtree('/content/pytorch-CycleGAN-and-pix2pix/checkpoints/'+NAME+'/')
shutil.copytree(str(drive_folder), '/content/pytorch-CycleGAN-and-pix2pix/checkpoints/'+NAME+'/')
def test_model (number_results = 5, direction = 'BtoA', src = None, dst = None):
# delete results folder and recrete
shutil.rmtree('./results')
os.mkdir('./results')
# get appropriate model
if (src is None): src = './checkpoints/'+NAME+'/latest_net_G_'+direction.split('to')[-1]+'.pth'
if (dst is None): dst = './checkpoints/'+NAME+'/latest_net_G.pth'
get_model(src, dst)
if (direction == 'BtoA'):
test = TEST_B
else:
test = TEST_A
cmd = 'python test.py --dataroot '+str(test)+' --name '+str(NAME)+' --model test --no_dropout'
os.system(cmd)
plot_results(number_results)
让我们为培训创建选项。
import time
from options.train_options import TrainOptions
from data import create_dataset
from models import create_model
from util.visualizer import Visualizer
import shutil
import os
from pathlib import Path
from tqdm.notebook import tqdm
options_list = ['--name', NAME,\
'--dataroot', TRAIN_A.parent,\
'--batch_size', BATCH_SIZE,\
'--checkpoints_dir', './checkpoints',\
'--lr', 2e-4,\
'--n_epochs', EPOCHS,\
'--n_epochs_decay', EPOCHS//2,\
'--name', NAME]
opt = TrainOptions().parse(options_list)
首先,我们使用前面指定的选项创建数据集。
dataset = create_dataset(opt)
dataset_size = len(dataset)
print('The number of training images = %d' % dataset_size)
然后,我们创建模型并运行 setup 调用。
model = create_model(opt)
model.setup(opt)
visualizer = Visualizer(opt)
total_iters = 0
我们从 A 到 b 来看生成器,命名约定和论文略有不同。在论文中发电机被称为G。
在代码中,他们称这个映射函数为G_A。意思还是一样的。
该发生器功能从A映射到B。
在我们的例子中,它从辛普森一家映射到现实生活。
model.netG_A

作者图片
这里我们可以看到模型使用了 Resnets 。
我们有Conv2d、Batchnorm、ReLU、InstanceNorm2d和ReflectionPad2d。InstanceNorm2d和ReflectionPad2d对我来说是新的。
InstanceNorm2d:这与批量定额非常相似,但它一次应用于一幅图像。
ReflectionPad2d:这将使用输入边界的反射填充张量。
现在我们也可以看看鉴别器。
model.netD_A

作者图片
鉴别器使用LeakyReLU、Conv2d和InstanceNorm2d。
LeakyReLU有意思。ReLU是增加网络非线性的激活。但是什么是LeakyReLU?
ReLU将所有负值转换为0。由于0的梯度是0神经元达到大的负值,有效神经元抵消到0。他们实际上是“死”了。这意味着你的网络最终会停止学习。
这种效应被称为将死 [ReLU](https://datascience.stackexchange.com/questions/5706/what-is-the-dying-relu-problem-in-neural-networks) 问题。
LeakyReLU旨在解决这个问题。该功能如下所示:

由 PyTorch 在 PyTorch 文档上拍摄的图像
这个函数本质上解释为:如果一个值是负的,则将其乘以negative_slope,否则什么也不做。negative_slope通常是0.01,但是你可以变化一下。
所以LeakyReLU大大降低了负值的幅度,而不是将它们发送给0。但是这是否真的有效还没有定论。
培养
现在,我们可以在多个时期内训练模型。我在这里指定了10纪元。
以下是培训代码:
所有神奇的事情都发生在这里。它运行损失函数,获取梯度并更新权重。通过这样做,它优化了生成器和鉴别器。
让我们训练它!
测试
我让模型在 google colab 上通宵训练,并将.pth模型复制到我的 google drive 上。
让我们看看输出。
test_model(10, 'BtoA')


作者图片


作者图片


作者图片


作者图片


作者图片


作者图片
这是一个好的开始。我特别喜欢这张图片:


作者图片
老实说,它需要一些改进。
让我们尝试运行AtoB周期。所以我们要把辛普森一家的角色转换成人脸。
test_model(10, 'AtoB')


作者图片


作者图片


作者图片


作者图片
丰富
Cyclegan 的作者指出需要大的几何变化的任务不太可能成功。我刚刚证实了这一点。
该网络似乎在努力应对将辛普森一家的角色转换成真人(反之亦然)所需的巨大几何变化。我不确定更多的培训能否解决这个问题。GANs 的棘手之处在于弄清楚何时停止训练。目视检查似乎是 Cyclegan 的答案。再训练几天看看会发生什么也许是值得的。
完整的 jupyter 笔记本可以在 Github 上找到
原载于 2020 年 8 月 30 日https://spiyer 99 . github . io。
对剔除抽样的 3 分钟回顾:模拟任何分布
3 分钟回顾
一个简短的概率和算法教程,值得你花时间

在 Unsplash 上 Miikka Luotio 的照片
当您想要某个概率分布的一些值时,比如说正态分布,您可以简单地在 R 中调用rnorm,或者在 Python 中调用numpy.random.normal。但是你有没有想过他们是怎么做到的?潜在的想法非常简单却非常强大。在这篇文章中,我将直观地解释它,而不会用任何数学符号来让你厌烦。在 3 分钟内,您将能够实现您自己的定制分发模拟器。我们开始吧!
蒙特卡罗模拟拒绝抽样
任何计算机系统都应该有一个伪随机数发生器,它能够给你(伪)均匀分布的随机数。这是我们的起点。核心问题是:给定均匀随机值,我们如何生成不同的分布?
考虑一个投掷飞镖的游戏,在这个游戏中,你向一块长方形的木板投掷飞镖。玩之前,你在上面画一个钟形曲线(高斯概率密度函数)。假设你的飞镖均匀地落在整个区域。自然,会有一些飞镖落在曲线上方,一些落在曲线下方。在足够多的投掷次数后,它应该看起来像下图的下半部分。如果我们去掉曲线上方的红色部分,为蓝色部分做一个直方图,它应该看起来像上半部分的那个。

这是我在 P5.js 中的实现,可以随意去我的网站通过调优迭代次数和改变分布自己试试!
这张照片展示了 2000 次投掷。当你扔的次数多了很多,上半部分的黄色轮廓会越来越接近底部的钟形曲线。
这个游戏被称为拒绝抽样算法,或接受-拒绝法,每次投掷飞镖都是一次蒙特卡洛模拟。
这里到底发生了什么?你可以把 x 的值想成一个均匀随机数sampleX,把 y 的值想成另一个,sampleY。那么一掷镖的位置就是(sampleX, sampleY)。算法是这样的:
- 首先,你画一个
sampleX,然后你立即画一个sampleY。(扔飞镖) - 您将
sampleX插入到您想要的分布的 PDF 中,在本例中是高斯 PDF,并在对应于sampleX的紫色曲线targetY上获得一个值。 - 你把
sampleY比作targetY。如果sampleY < targetY,表示我们有一个“命中”,即飞镖落在曲线下方。这个随机数sampleX被“接受”并作为高斯样本返回。如果sampleY >= targetY,这意味着我们有一个“错过”,然后sampleX被拒绝,并且没有成功的高斯样本从该试验中抽取。继续下一个试验。 - 一旦你有了足够的试验,所有被接受的
sampleX形成了一个正态分布的随机值列表。
就是这个!这就是我们用均匀随机数得到高斯随机数的方法。
事实上,您可以将其更改为任何您想要的目标分布!在板上画一个疯狂的曲线,开始投掷。如果低于曲线,接受;如果高于曲线,拒绝。就这么简单。曲线甚至不需要积分到 1,就相当于缩放这条曲线可以得到的 PDF。
我用 P5.js 在浏览器中创建了一个可视化。您可以通过调整迭代次数和改变分布类型来随意尝试。
摘要
拒绝采样是一个非常简单的想法,非常简单,你只需不到 5 分钟就能学会,而且没有任何公式!尽管它很简单,但对于计算统计学和任何依赖于概率的技术来说都是至关重要的。rnorm和numpy.random.normal使用的实际算法被称为金字形神算法。这是在拒绝抽样和蒙特卡罗方法的保护伞下。有兴趣可以看看。希望你喜欢这个非常短的教程,并欣赏这个算法的小宝石的美丽!
参考
使用 Go 和 Python 模拟文化互动
使用 Go 和 Jupyter Notebook 模拟文化传播
没有什么比过年走亲戚更能体现文化了。从庆典和习俗到装饰和食物(永远都是关于食物的),一切都在你面前变得又红又吵。当我年轻的时候,我认为这就是作为一个中国人的全部,但是随着年龄的增长,我意识到还有更多。

春节期间探索新加坡的唐人街(鸣谢:张秀祥)
我在马来西亚和新加坡,在马来群岛长大,我一直认为中国新年是纯粹中国的事情。后来我知道日本人、朝鲜人、西藏人、蒙古人和越南人也庆祝这个节日。在中国,中国人甚至不叫它春节,而是叫它春节。
过了一段时间,我了解到一些我一直认为完全是中国的习俗,原来并不像看起来那么简单。例如,狮子不是中国本土的,那么为什么舞狮是中国新年庆祝活动的主要部分呢?我一直认为是中国新年的主食——吃肉夹馍和送橘子在中国很多地方都没有实行。作为中国新年小吃的常年菠萝馅饼显然纯粹是当地的一种做法,是土生华人的一种交叉。

新加坡购物中心的中国新年舞狮(鸣谢:张秀雄)
进一步说,如果你观察我们的日常生活,你会意识到你习惯的日常文化可能是多种文化的大杂烩。你所认同的国家或地方文化可能是许多其他文化的混合,而这些文化反过来又是更多其他文化的混合。
以 laksa 为例,这是一道在新加坡、马来西亚、印度尼西亚和泰国南部广受欢迎的香辣汤面。它的起源被认为是来自中国的沿海居民区,随着中国移民引入当地的食材和烹饪方法,它呈现出了当地的特色。至于当地的配料,可以是椰奶(咖喱叻沙的变种),罗望子(阿萨姆叻沙的变种),sambal belacan,各种鱼类,甚至柠檬草!这导致出现了令人愉快和眼花缭乱的各种变体,它们只是当地文化融合的可食用体现。

许多种类的叻沙(咖喱叻沙、柔佛叻沙、槟城阿萨姆叻沙和沙捞越叻沙)中的一些(信用:https://www . theartofbusiness travel . com/news/Malaysia-airlines-lounge-offers-Laksa-disks/)
同样,我们在新加坡使用的一种以英语为基础的克理奥尔语中找到了语言对等词,这种语言包含来自英语、马来语、各种汉语方言和印度语的词汇,在马来西亚的英语、马来语、各种汉语方言和印度语之间通过语码转换形成的一种马来西亚洋泾浜语中也找到了语言对等词。如果我们深入挖掘,我们认为是文化象征的各种事物往往起源于其他文化,例如英国茶(来自中国)和禅宗(通过日本禅宗在西方流行,来自禅宗,起源于中国并受道教影响,但反过来是来自印度的大乘佛教的一个流派)。
正如斯蒂芬·霍金斯在《时间简史》的开篇中所写的——海龟一直在往下走。
文化互动建模
人们和文化如何相互作用和影响是众多研究的主题。各种各样的社会科学家、人类学家和生物学家研究了文化变迁,提出了看似合理的理论,并撰写了描述这些理论的论文。
一篇特别有影响力的论文是罗伯特·阿克塞尔罗德(Robert Axelrod)的《文化的传播:一个局部趋同和全球极化的模型》(T1),这是一篇开创性的论文,在后来的研究中被引用。阿克塞尔罗德建立了一个基于主体的模型,该模型遵循一套简单的规则,试图产生涌现行为(也就是说,他建立了一个复杂系统的模型)。
我已经创建了一个类似的基于代理的模型,部分基于阿克塞尔罗德论文中描述的规则。我用 Go 创建模拟,用 Python 对结果做了一点分析。
我使用的模型基于两个非常简单的前提,类似于 Axelrod 的模型:
- 彼此相似的文化比不相似的文化更有可能相互影响
- 当文化相互作用时,它们变得更加相似
利用这两个前提,我用正方形网格建立了一个模型。网格中的每个单元格代表一种文化。

在模拟中,每种文化有 6 个特征,其中一个特征是文化的属性,如食物、语言、宗教等。

每个特征又有 16 个不同的特性,它们是该特征不同的可能值。

正如您可能意识到的,这显然是为了便于我用十六进制颜色描述网格而建模的。

让我们看看模拟是如何工作的。每个细胞(培养物)有 8 个邻居,除非它是一个角落或细胞。

在每个时间间隔,模拟随机选取 n 个培养物。将选定的区域性与其相邻区域进行逐个功能的比较。一种文化和另一种文化之间的差异,我称之为文化差异,是一种文化影响另一种文化的可能性。如果有文化的影响,模拟会选择一个随机的特质复制到另一个文化中,使其彼此更加相似。
在下面的示例中,取两个相邻的区域性 A 和 B(即它们是邻居)。现在比较它们的特性。在下图中,两个特征之间的差异,或者说特征差异是 3。请注意,我们只寻找两个特征之间的差异,所以我们得到的是绝对数字,而不是简单的一个数字减去另一个数字。

接下来,我们将两种文化之间的所有特征差异加起来,得到一个文化差异。在下图中,我们得到的文化差异是 34(如果我们退后一点,你会发现我们只是将两种文化之间的差异减少到一个数字,但这就是建模的本质)。

快速的算术检查会告诉我们,如果两个文化完全不同,那么它们的文化差异是 96 (16 个特质 x 6 个特征),如果完全相同,那么它们的文化差异是 0。因此,出现文化交流的概率是:

最后,如果文化交流真的发生了,模拟将随机选取一个特征,并将该特性值从一种文化复制到另一种文化。在这种情况下,区域性 A 的功能 3 被复制到区域性 b。

接下来我们来看看模拟代码。
围棋的模拟
这个模拟是用 Go 编写的(这里并不奇怪),它创建了一系列如上所述的网格图像。这些图像以快速连续的方式一个接一个地显示,以显示模拟的培养物如何随着模拟的每个节拍而变化。
数据
先说数据。img变量存储图像,它是标准库中的一个image.RGBA。这是将用于显示图像的变量。cells变量是代表模拟网格的Cell结构的一部分。
我们可以为模拟调整 4 个参数——width是网格的大小,coverage是将包含文化的模拟网格的百分比,interactions表示模拟在每个 tic 中进行的交互次数,numTicks是运行模拟的时间长度。
我们还存储了 3 组模拟数据,可用于以后的分析,fdistances表示网格中所有单元的特征之间的平均距离,uniques是剩余的独特文化的数量,changes是实际发生的文化变化的数量,interactions是我们做了多少次,但changes是实际发生了多少次。
细胞
模拟中的一个Cell有一个位置X和Y,一个半径R描述它有多大,一个Color是单元格的颜色,值为0x1A2B3C。struct Cell有一个返回颜色整数(代表颜色的数字)的getRGB方法和一个用颜色整数设置单元格的Color的setRGB方法。
为了创建一个单元格,我们使用了接受位置x和y以及一个颜色整数的createCell函数。最后,我们还有一个创建随机网格的函数,叫做createPopulation。createPopulation基于coverage参数创建模拟网格,该参数指定了文化填充网格的百分比。
接下来看主模拟。
模拟
对于模拟,我使用了终端框(就像入侵者游戏等)。你可以看看我写的关于我如何使用它的其他帖子。
在我开始主模拟循环之前,我将首先使用createPopulation创建网格。对于模拟中的每个循环,我将捕获距离dist,独特文化的数量uniq和变化的数量chg。
然后,对于每一个循环,我随机选取一些细胞,让它们与它们的邻居互动,如上所述。
在每次循环结束时,我获取距离、唯一性和变化,并分别存储到fdistances、uniques和changes中。这些函数会相应地计算这些值。
该模拟还使用许多函数来帮助它找出哪些是它的邻居。
现在我们有了模拟,我们需要显示它。
图像
和以前的帖子一样,我使用draw2dimg库来绘制网格。draw功能在每个节拍绘制网格。每个单元格都是一个给定颜色的圆圈。
printImage功能就是这样做的——它将图像打印到控制台,而saveImage功能用于保存模拟的最后一幅图像。
保存模拟数据
模拟的全部目的是获取数据,这是使用saveData功能完成的。该功能保存三种类型的数据——存储在fdistances、uniques和changes中的模拟数据。它还将模拟的最终状态(实际上只是最后一个 tick 的网格数据)以及网格的最终图像快照保存在 PNG 文件中。
运行模拟
这就是我们的模拟。如果我们运行它,我们应该得到这样的结果:
以 8 倍速度模拟
模拟结束后,我们应该得到 3 个文件——包含模拟数据的日志文件、包含最终刻度网格数据的 cells 文件以及最终的快照图像。
分析模拟数据
如果你只看模拟网格本身,你可以弄清楚一些事情。GIF 是实际速度的 8 倍(对于没有耐心的人来说),但是你可以清楚地看到,当它以随机布局开始时,随着时间的推移,集群形成、增长和扩展,然后也消失了。
让我们仔细看看数据。在模拟结束时,我们将数据保存在一个log-nxx-tyy-wzz.csv文件中。如上所述,该文件将包含特征距离、独特文化的数量和变化的数量。我用 Jupyter 笔记本对数据做了一些简单的分析。
不同数量的文化互动
我进行了 4 次模拟,每次模拟都将交互次数从 100、500、1000 和 1500 增加,同时保持模拟网格的宽度为 36 个单元。我运行了 500 次模拟。
基于交互分析数据
首先,我使用 Pandas 将数据从 CSV 文件读入数据帧。然后,我相应地转换列,首先是特征距离,然后是唯一的数量,最后是变化的数量。
文化差异
正如我们所看到的,在模拟开始时,特征之间的距离迅速下降,然后下降速度变慢,最终逐渐变小,形成长尾。我只运行了 500 次模拟,即使我们运行更长时间,特征距离实际上也不会下降到 0。这是什么意思?

文化差异,假设每个模拟分笔成交点的交互次数不同
由于特征距离实际上是关于不同文化之间的差异,这意味着当交互发生时,最初文化之间变得更加接近,变得更加相似。然而,文化差异并没有完全消失。
互动数量的差异告诉我们,如果更多的互动发生,文化之间会更接近,这也是我们所期望的。
接下来让我们看看独特文化的数量。
独特的文化
从图表中,你可以看到独特文化的数量随着时间的推移而减少,因为它们相互影响。互动发生得越多,文化就越有可能变得彼此相似,最终变得相同。

给定每个模拟分笔成交点的不同交互数量,独特文化的数量
请注意,这并不一定意味着一种文化吸收了另一种文化,这只是意味着两者变得更加相似,正如你有时可以从模拟中看到的那样,主导文化也会随着时间的推移而变化。
文化变迁
最后,如果我们看一下变化的实际数量,它们大部分时间保持相当稳定,徘徊在交互数量的 15–20%之间。这告诉我们,尽管独特文化的数量在不断变化,即使特征距离变得越来越小,但总会发生某种程度的变化

文化变化的次数,给定每个模拟分笔成交点的不同交互次数
这种分析是基于仅仅改变相互作用的次数。让我们看看如果我们改变模拟网格的覆盖范围会发生什么。通过减少整个模拟网格中的文化总数,该参数改变的是每个文化与之交互的邻居的数量。
不同数量的邻居
分析是相同的,唯一的区别是真正改变了源文件。在这种情况下,我们从 20%的培养物网格覆盖率开始,到 40%,然后 60%,80%,最后整个网格被培养物覆盖。
文化差异
让我们从比较不同 coverages 的要素距离开始。当覆盖范围变化时,特征距离变化看起来相当一致,当覆盖范围增加时,即,当文化有更多的邻居要交互时,特征差异在稳定状态下更大。然而,正如你所看到的,当文化有更多的邻居时,最初的下降更大。

文化差异,给定模拟网格中不同的文化覆盖范围
独特的文化
接下来我们来看看独特文化的数量。该图表与早期的观察结果一致,随着覆盖面的增加,独特文化的数量也在增加,即使随着时间的推移数量在减少。然而,你可能也会注意到,随着覆盖率的增加,独特文化的数量也会下降得更快。

给定模拟网格中不同区域性的覆盖范围,唯一区域性的数量
文化变迁
最后让我们看看变化的数量。不出所料,随着覆盖面的扩大和更多邻居的互动,会发生更多的文化变化。我们还可以看到,随着时间的推移,变化是相当一致的,即使独特的文化以及特征距离的数量下降。

给定模拟网格中不同的文化覆盖范围,文化变化的数量
观察
从模拟中,我们可以观察到以下情况:
- 随着时间的推移,独特文化的数量越来越少。这并不出人意料,毕竟我们确实希望不同的文化相互影响,变得越来越相似,直到它们变得相同。您可以从模拟网格上的文化聚类中看到这一点。这就是阿克塞尔罗德所说的局部收敛。
- 即使过了很长时间,独特文化的数量实际上也不会下降到 1。这些文化仍然彼此不同。这就是阿克塞尔罗德所说的全球两极分化。
- 随着时间的推移,随着特征差异的减少,文化变得越来越相似。然而,在最初的急剧下降之后,文化差异或多或少地趋于平缓,即使独特文化的数量继续下降。这告诉我们,即使文化相互作用,也不意味着我们都会变得一样——文化差异仍然存在。
- 最后一个有趣的观察是,即使文化在互动中同化,一些文化似乎占主导地位,但这种主导地位不是永久的。事实上,在整个模拟过程中,变化或多或少是恒定的,这意味着文化总是在变化。
密码
模拟的完整 GitHub 库可以在这里找到——https://github.com/sausheong/culture_sim
摘要
基于代理的模拟就像科学实验,你可以为你的场景创建完美的环境和代理,你可以快速调整参数并找出可能的结果。我们可以将复杂的情况分离并简化成基本形式,然后进行我们想要的实验。在某种程度上,这有助于我们更好地理解复杂性及其不可预测的结果。
我使用 Go 进行模拟,并使用 Python/Jupyter Notebook 来分析结果,但还有很多其他方法可以做到这一点。事实上(有点无耻的广告宣传)我已经写了一整本书,基于使用 Ruby 进行模拟和使用 R 进行分析。
最后一点,虽然我在文化交流的背景下讨论了这一点,但我在这里展示的是一个有限的受控参数集的计算机模拟。模型或模拟应该被认为是真实的,仅仅是模型,而不是现实的真实代表。
模拟退火和八皇后问题
无监督学习和随机优化算法

模拟退火算法是许多随机优化算法中的一种。不像爬山算法这样的算法,其目的只是改进优化,SA 允许更多的探索。这个想法是,通过这种探索,更有可能达到全局最优,而不是局部最优(关于局部最优、全局最优和爬山优化算法的更多信息,请点击此链接)。
术语“退火”是冶金学中的一个术语,其目的是降低和提高金属的温度。这个过程允许分子重新组合,每次都变得更近,因此金属变得更硬。类似的情况也适用于 SA 算法,通过探索更接近一个解决方案,离它更远,然后再次接近一个更好的解决方案。
模拟退火算法
该算法可以分解为 4 个简单的步骤:
- 从一个随机点 x 开始。
- 在邻域 N(x)上选择一个新的点 xⱼ。
- 决定是否要搬到新点 xⱼ.将基于概率函数 P(x,xⱼ,T 做出决定(前面解释过)。
- 减少 T
就像我们之前提到的 P(x,xⱼ,T)是将指导我们是否移动到新的点的函数:

让我们探索一下这个函数告诉我们什么。F(x)是目标函数(我们要找到最优点 x 的函数)。如果新点 xⱼ改进了目标函数的结果,我们将以概率 1 移动到新点。
当新点没有改善目标函数时,我们将根据 F(xⱼ)-F(x 和变量 t 的差异移动到新点
当 T 高时,移动到新的点的可能性也高,而当 T 低时,移动到新的点的可能性也低。这就是为什么最初我们将从一个高 T 开始做更多的探索,并逐渐降低 T 的值以达到最佳点。
现在我们知道了算法是如何工作的,是时候使用 python 来执行一个例子了,以进一步加深我们的理解。
八皇后问题
八皇后问题在于将八个皇后放置在一个 8*8 的桌面板上,并且它们中的任何一个都不在彼此的攻击线上。蚁后可以水平、对角和垂直移动,如图 1.1 所示。

图片来自 Brainmetrix
找到问题的解决方案并不容易,因为存在大量的组合。我们可以在图 1.2 中看到一些解决方案,其中只有 6 和 7 个皇后位于棋盘上。

图片来自 Brainmetrix
既然我们理解了这个问题,让我们用 python 代码来解决它。
使用 Python 的 8 个皇后
python 中有一个名为“mlrose”的库,它对实现随机优化算法非常有帮助,因此前几行代码将用于导入这个库以及帮助我们处理数组的 numpy 库。
### Importing the necessary libraries
import mlrose
import numpy as np
下一步是定义目标函数。目标函数将计算放置在不能被攻击的地方的蚁后的数量。考虑到皇后是垂直移动的,有理由说没有皇后应该被放置在同一垂直线上,因此我们可以用一个简单的 8 个位置的数组来表示每个皇后的位置。例如,在国际象棋棋盘中,数组 A=[0,2,1,3,7,4,5,6]看起来像图 2.1。

图片来自数据遗传学
现在是编写目标函数的时候了:
###Defining the objective function
def queens_max(position):
# We start the count
no_attack_on_j = 0
queen_not_attacking=0
# Compare for each pair of queens
for i in range(len(position) - 1):
no_attack_on_j=0
for j in range(i + 1, len(position)):
### Check if there is any diagonal or horizontal attack.
###Iterative process for each column
if (position[j] != position[i]) and (position[j] != position[i] + (j - i)) and (position[j] != position[i] - (j - i)):
"""If there isn't any attack on the evaluated column.
The count is increased by one.
This counter is only used as a reference ."""
no_attack_on_j += 1
"""If there is no attack on all the columns.
The general counter is increased by one.
This counter indicates the number of queens that are correctly
positioned."""
if(no_attack_on_j==len(position)-1-i):
queen_not_attacking+=1
"""The return number is the number of queens not attacking each
other. If this number is 7 we add 1 cause it means the last
queen is also free of attack."""
if(queen_not_attacking==7):
queen_not_attacking+=1
return queen_not_attacking
之前定义的目标函数被指定为 mlrose 中方法“CustomFitness”的参数。这就是任何目标函数使用这个库的方式。
# Assign the objective function to "CustomFitness" method.
objective= mlrose.CustomFitness(queens_max)
现在,我们完成了棘手的部分。剩下的唯一一件事就是告诉罗丝需要解决的问题类型。我们正在解决的问题有离散的数字(整数),这就是为什么我们将使用“离散选择”的方法。这个方法将保存问题的描述,它有 4 个参数:
- length——我们正在处理的数组的大小(对于八皇后问题是 8)。
- fitness _ fn——我们之前用“目标”这个名字定义的目标函数。
- 最大化-如果我们想要最大化目标函数,它必须是“真”,否则为“假”。
- max _ val——这个参数表示函数可以取的最大值。从 0 开始,到 max_val-1 结束。在我们的例子中,皇后的位置可以从 0 到 7,所以 max_val=8。
这一行代码:
#Description of the problem
problem = mlrose.DiscreteOpt(length = 8, fitness_fn = objective, maximize = True, max_val = 8)
最后,是时候告诉 mlrose 如何解决问题了。我们知道我们将使用模拟退火(SA ),指定 5 个参数很重要。
- 问题-该参数包含问题的信息。我们之前用“问题”这个名称定义了它。
- schedule——这个参数告诉 T 如何在每次迭代中减少。有很多方法可以减少 T,可以在的玫瑰上查看。这个时间 T 将使用 ExpDecay()以指数方式减少。
- max _ attempts——定义算法尝试搜索更好解决方案的次数很重要。如果尝试次数达到最大值,它应该停止。
- max _ ITER——它表示算法可以找到的新点的最大数量或者它所做的迭代的最大数量。
- init_state-参数“init _ state”是数组的初始位置。
最后一段代码如下所示:
# Define decay schedule
T = mlrose.ExpDecay()
# Define initial state
initial_position = np.array([4, 6, 1, 5, 2, 0, 3, 7])
# Solve problem using simulated annealing
best_position, best_objective = mlrose.simulated_annealing(problem=problem, schedule = T,
max_attempts = 500, max_iters = 5000,
init_state = initial_position)
print('The best position found is: ', best_position)
print('The number of queens that are not attacking each other is: ', best_objective)Output:The best position found is: [4 6 1 5 2 0 3 7]
The number of queens that are not attacking each other is: 8.0
正如图 2.2 所示,我们成功解决了 8 皇后问题

图片来自数据遗传学
最后备注和代码
我希望你喜欢这篇文章,并玩八皇后问题。我把 google colab 和 github 上的代码留给你。运行这段代码,稍加调整,甚至可以解决 9,10…n 皇后问题。
参考书目:
机器学习,随机优化和搜索。(未注明)。检索于 2020 年 8 月 13 日,发自 https://mlrose.readthedocs.io/en/stable/
大脑训练。(未注明)。检索于 2020 年 8 月 13 日,发自 http://www.brainmetrix.com/8-queens/
八个皇后。(未注明)。2020 年 9 月 10 日,从http://www.datagenetics.com/blog/august42012/检索
原载于 2020 年 8 月 25 日 https://www.estudiodedatos.com**的 。
用 Python 模拟排队系统
了解如何从头开始用 python 创建模拟

图片由维多利亚博物馆在 Unsplash 上拍摄
我们都在生活中的某个时候去过银行,我们熟悉银行的运作方式。顾客进去,排队等候叫号,从出纳员那里得到服务,最后离开。这是一个排队系统,我们在日常生活中会遇到很多排队系统,从杂货店到游乐园,它们无处不在。这就是为什么我们必须尽可能提高它们的效率。这些系统中存在大量的随机性,这会导致巨大的延迟,导致长时间的排队,降低效率,甚至造成金钱损失。可以通过开发离散事件模拟模型来解决随机性问题,这对于通过分析关键绩效指标来提高运营效率非常有帮助。
在这个项目中,我将模拟一家银行的排队系统。
让我们考虑一家有两个出纳员的银行。根据泊松过程,客户平均每 3 分钟到达银行一次。在这种情况下,这个到达率是假设的,但是应该根据实际数据进行建模,以获得准确的结果。他们排队等候一个空闲的出纳员。这种类型的系统被称为 M/M/2 排队系统。第一名柜员服务客户的平均时间为 1.2 分钟,第二名柜员为 1.5 分钟。这里假定服务时间是指数增长的。当一个客户进入银行,两个柜员都闲着,他们以相等的概率选择其中一个。如果一个客户进了银行,有四个人在排队,他们会有 50%的概率离开银行。如果一个客户进入银行,有五个或五个以上的人在排队,他们将有 60%的概率离开银行。
让我们首先试着想象这个系统

作者照片
太好了!现在让我们开始构建模型
一般来说,在离散事件仿真中有两种广泛使用的时间推进方法,下一个事件时间推进(时钟从一个事件跳到另一个事件)& 固定增量时间推进(时钟以固定时间间隔推进)。我将为这个模型使用下一个事件时间推进机制。
模拟模型的主要组件包括:
- 状态变量:描述系统在特定时间的状态
- 模拟时钟:记录时间
- 统计计数器:存储性能参数统计信息的变量
- 初始化例程:在时间 0 初始化模型的子程序或类
- 定时程序:决定下一个事件的子程序或类
- 事件例程:特定事件发生时更新系统的子程序或类
从导入所需的库开始,在这种情况下只需要 NumPy 和 Pandas(python 有一个名为 SimPy 的模拟库,这是一个基于流程的模拟框架,也可以使用)
来源https://gist.github.com/BhavyaJain08
接下来,我们开始定义变量,并在主类中的 init 函数中初始化它们。下面定义变量是状态变量和统计计数器。
告诉我们系统性能的关键变量是平均等待时间、服务器利用率、排队等待的人数和流失的客户,其中一些是直接计算的,另一些是派生的。
来源https://gist.github.com/BhavyaJain08
定时程序
定时程序通过比较事件的预定时间来决定下一个发生的事件,并将模拟时钟提前到相应的事件。最初,出发事件被安排在无限时间发生(因为没有顾客),这保证了第一个事件将是到达事件。
来源https://gist.github.com/BhavyaJain08
我还在这个函数中计算了客户的总等待时间。这是有意义的,因为我们希望评估客户在活动结束后的等待时间,这也是计时例程的开始。
到达事件
根据上面提到的问题,一个到达事件可以有多种结果,在下面的图表中突出显示了这些结果。

抵店活动流程图(作者摄影)
到达事件的结果由队列中的客户数量和服务器的状态决定。对于每个结果,更新统计计数器,并安排下一个事件。
来源https://gist.github.com/BhavyaJain08
在队列长度为零的情况下,检查每个服务器的状态,并将顾客分配给空闲的服务器,在到达的同时安排离开。如果两个服务器都很忙,队列长度为零,那么队列长度增加 1,并安排下一个到达。
在所有其他情况下,队列长度增加 1,并计划下一个到达,或者丢失一个客户,并更新计数器。
离开事件
当计时程序识别出接下来要安排的两个发车事件中的任何一个时,发车事件发生。离开事件的流程如下图所示

离职事件流程图(作者摄影)
来源https://gist.github.com/BhavyaJain08
当有客户在队列中等待时,下一个客户开始服务,队列长度减少一,服务器保持忙碌。
当队列中没有顾客时,服务器处于空闲状态,将来不会安排离开事件。
生成到达和服务时间
使用逆变换采样生成到达和服务时间。这些随机数生成器函数在到达和离开函数中被调用,以生成随机的到达和服务时间。
来源 https://gist.github.com/BhavyaJain08
运行模拟
下一步是运行模拟。我决定从上午 9 点到下午 1 点(4 小时)运行 100 次复制,收集数据并存储在 excel 工作簿中以供进一步分析。我使用了一个 for 循环,它每次都更新随机数种子,运行 100 次,并将结果附加到 pandas 数据帧中。稍后,该数据框将导出为 excel 工作簿
来源https://gist.github.com/BhavyaJain08
结果
以下是从 100 次重复中获得的结果片段

作者照片
最后,我们可以从这些结果中导出性能度量,然后分析它们,并在提高效率、降低成本、分配资源等方面使用它们。

作者照片
从制造业到服务业,甚至是生物学,模拟在许多行业都可以作为重要的决策工具。这个项目只是模拟无限可能性的一个小例子。有许多软件和资源可以轻松地对复杂系统进行建模和模拟。然而,该项目的目标是对离散事件模拟如何工作及其作为决策工具的用途有一个基本的了解。
参考文献:
https://www.youtube.com/channel/UCkQ5dusAivKJ66hb3EDeBZg
用 Python & Jupyter 控件模拟流行病学中的房室模型
在 Jupyter 笔记本中实现和模拟 SEIR 和塞德模型。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家,这篇文章的观点不应被解释为专业建议。
在这篇文章中,首先,我们将了解在流行病学中使用的房室模型的基础知识,然后我们将使用 python 来模拟两个这样的模型 SEIR 和塞德。最后,您应该能够模拟更改不同参数的效果,就像下面的动画所示。
下面的动画展示了在保持其他参数不变的情况下,并假设所有人都容易感染该疾病时,感染率降低的效果。

模拟感染率降低的影响,保持所有其他参数不变,并假设整个人口总是容易感染该疾病
请注意,这纯粹是一个编程和数据科学练习,所以不要根据这些模拟得出结论。把这留给流行病学和医学专家吧。
如果你对这个领域很熟悉,并且想直接进入代码,你可以在我的 GitHub 上查看 SEIR 和 T21 的笔记本。
现在让我们从基础开始。
分室模型
房室模型是一种机械模型,它试图通过将问题动力学中涉及的机制整合到模型中来解释观察到的数据。
房室模型是基于一个常微分方程系统,它表达了人群不同流行病学状态之间的动态。它们可用于短期和长期预测一种现象(如疾病)的传播,也可用于研究不同干预措施的效果( Chowell,2017 )。
单词'隔室'表示将种群划分成相互排斥的组,称为‘隔室'。例如,在流行的 SIR 模型中,三个隔间是 S 可接受的、 I 未感染的和 R 已死亡的。SIR 模型用于其中恢复导致对疾病的持久抗性的疾病,例如麻疹的情况( Allen 等人)。理解这些模型的假设及其对特定疾病的有效性极其重要,因此,最好留给专家来做:)
在 SIR 模型的基础上,让我们看看什么是 SEIR 和塞德模型,以及它们之间的动态。
SEIR 模型
SEIR 代表“患病的”和“死亡的”。这 4 种流行病学状态之间的进展如图 1 所示。

图 1: SEIR 模型
模型的动力学用图 2 所示的微分方程系统来表示,

图 2: SEIR 模型的 ODE 系统
有关公式中使用的参数说明,请参考图 5。
塞德模型
SEIRD 代表 SSSEexposedIinfectiveRrecoveredDEAD。在这里,死亡个体的动力学用一个单独的隔间来建模。在一些疾病中,如埃博拉病毒,死亡仍然可以传染,因此 SEIRD 模型的动力学也可以研究 D 和 E 个体之间的相互作用( Weitz 等人)。为简单起见,我们假设 D 没有传染性,因此,这 5 种流行病学状态之间的进展如图 3 所示。

图 3: SEIRD 模型
模型的动态特性用图 4 所示的微分方程系统表示。

图 4: SEIR 模型的颂歌系统

图 5:符号
了解了基础知识后,现在让我们开始模拟。
SEIR 和塞德模型的模拟
此实施练习的结果将是一个小部件,它将使我们能够修改模型的不同参数,并观察其对 SEIR 和 d 曲线的影响。我们将使用 Jupyter 小部件进行交互,最终的小部件将类似于图 6 所示。

图 6: SEIRD 模拟器小部件
模拟的实现将需要我们定义一个常微分方程(ODE)系统,使用解算器对其进行求解,并预测感兴趣的时间跨度,最后用 Jupyter 小部件将所有这些连接在一起,从而实现交互性。
对于这些步骤,我将大量使用超级棒的教程用 Python 求解微分方程、用 Python 计算统计和用 Python 和 Jupyter 实现的常微分方程(ODE)。让我们以 SEIR 模型为例,一步一步地进行,以使实现更加清晰。
SEIR 模型的模拟
定义 ode
这里,我们将在 python 函数中编写图 2 中的 ode,并在列表中返回 ODE 系统。让我们看看如何,
SEIR 颂诗体系
定义规划求解
接下来,定义一个函数,该函数将输入时间跨度、求解常微分方程组的初始条件和模型参数,并在求解常微分方程组后返回结果预测。注意,解微分方程需要初始条件来估计积分常数。我们将使用 scipy 的 odeint 作为求解器。现在让我们看看代码,
求解 SEIR 模型常微分方程的函数
Jupyter 互动部件
现在,让我们使用 ipywidgets 库中的小部件将它们联系在一起,以实现交互性并帮助我们进行模拟。
遵循教程用 Python 和 Jupyter 实现的常微分方程(ODE),我们将编写主函数,其中我们将调用上面定义的辅助函数。让我们看看它的代码…
ipywidgets.widgets 中的 interact 方法所需的主函数
这个难题的最后一部分是调用 interact 函数,参数为上面实现的 main 函数,以及 main 函数所需的参数值,由相应的参数小部件读取。根据输入的类型,使用的小部件有 IntSlider 和 FloatSlider 。让我们看看这最后一段让一切正常工作的代码!
用于创建窗口小部件交互方法
你可以在 Jupyter 笔记本模拟 SEIR 模型中找到完整的代码。运行笔记本后,您将得到一个类似于图 6 所示的小部件。
SEIRD 模型的模拟
SEIRD 模型的相应 ode_model、ode_solver、main 和 interact 函数为:
定义 ode
塞德颂诗体系
定义规划求解
求解 SEIRD 模型常微分方程的函数
Jupyter 互动部件
ipywidgets.widgets 中的 interact 方法所需的主函数
最后,
用于创建窗口小部件交互方法
同样,你可以在 Jupyter 笔记本中找到 SEIRD 模型的模拟完整代码。
结论
在这篇文章中,我们了解到,
- 流行病学中的房室模型
- 先生,SEIR,塞德模型——它们的区间和动态表现为一个常微分方程系统。
- python 中求解 ode 的代码
- 使用 python 中的计算机小部件模拟房室模型的代码。
希望你和这些模特一起工作愉快。
参考
[1]Python 中的计算统计学(【https://people.duke.edu/~ccc14/sta-663/CalibratingODEs.html】T2
[2]用 Python 求解微分方程【https://www.youtube.com/watch?v=VV3BnroVjZo
[3]https://www.idmod.org/docs/hiv/model-seir.htmlSEIR 和塞伊斯的车型(
[4]流行病学中的房室模型(https://en . Wikipedia . org/wiki/compartment al _ models _ in _ epidemiology # The _ SEIR _ model)
[5]Python 和 Jupyter 的常微分方程(ODE)(https://elc . github . io/posts/常微分方程-python/ )
[6]赛尔斯+型号(https://github.com/ryansmcgee/seirsplus)
[7] R .古普塔、G .潘迪、P .乔德里、S .帕尔、SEIR 和基于回归模型的新冠肺炎疫情预测(2020 年),medRxiv 预印本
[8] G Chowell,用量化的不确定性拟合流行病爆发的动态模型:参数不确定性、可识别性和预测的初级读本(2017),传染病建模第 2 卷,第 3 期,2017 年 8 月,第 379-398 页
[9] LJ Allen,MA Jones,CF Martin,《麻疹流行病疫苗接种的离散时间模型》( 1991 年),《数学生物科学》第 105 卷,第 1 期,1991 年 6 月,第 111-131 页
[10] JS Weitz,J . Dushoff,《埃博拉死后传播建模:推理挑战和控制机遇》( 2015 年),《科学报告》第 5 卷,文章编号:8751 (2015 年)
用元胞自动机模拟新冠肺炎
社交距离和戴口罩真的有助于预防感染吗?

看看这篇文章附带的 代号 。试着自己运行它,并修改参数。
新冠肺炎(新型冠状病毒肺炎)
模拟新病毒的传播及其导致的疾病是学习适当预防措施的重要一步。到目前为止,已经有许多新的模拟被创造出来,覆盖了新型冠状病毒和新冠肺炎的不同区域。例如,《华盛顿邮报》发表了一篇很棒的文章展示了社交距离的重要性。通过这篇文章,我尝试模拟这种疾病,并希望通过它来传播安全预防措施的重要性。
什么是元胞自动机?
元胞自动机 是由网格单元组成的离散模型,其中每个单元可以是一组给定状态中的某个状态。每个时间步长,每个单元都根据其邻居的状态和简单规则更新为一个新状态。它们已经被用于模拟不同的领域,从人工生命到森林火灾蔓延。康威的生命游戏是一种流行的细胞自动化,它用非常简单的规则创造复杂的结构。

卢卡斯·维埃拉— 自己的作品,CC BY-SA 3.0
细胞自动机的一个重要方面是使用局部化。因为单元基于它们的邻居(通常在 8 个周围的单元中)更新,所以任何基于邻近实体之间的交互的问题都可以通过元胞自动机有效地建模。这非常适合模拟感染,因为它们往往是通过附近咳嗽或打喷嚏的人身上的水滴发生的。
重要的流行病方程
下面是几个用于分析病毒的重要方程式:
继发感染率(SAR) :感染总人数与易感总人数之比(模拟结束时计算)
基本再生数(R0) :一个感染者在其整个感染期内直接传播病毒的易感者数量
模拟新冠肺炎和安全政策的有效性

环境的渲染:绿色易感,红色被感染,蓝色被恢复;正方形是非社交距离个体,圆形是社交距离个体
环境
模拟环境由封闭空间中的人组成(一边包裹,即把人传送到另一边)。一个人可以是易感的、被感染的或康复的。这遵循了流行病的基本 SIR 模型 。最初,世界上充满了被感染或易感的人,然后随着时间的推移,根据现有的安全措施,感染率将会激增,或者病毒将会很快消亡。然而,没有新的人产卵,没有人可以离开,除非他们死于疾病。
运动和社会距离
环境中的个体四处移动来模拟互动。练习社交距离的人(上图中的圆圈)倾向于防御性地走动,以避免与他人站得太近。而不练习社交距离(方格)的人则四处走动,懒得与可能有传染性的人保持距离。看看上面这张代表环境的 gif。请注意,圆圈往往与其他所有人隔开。唯一不是这种情况的时候是如果他们被包围了,没有地方可去,或者旁边有一个广场。稍后,我们将探讨社交距离有多重要。
感染的时间线
当易感个体被感染时,他们不会立即出现症状或具有传染性。更确切地说,感染在人体内是有时间表的:

上边是时间线的传染部分,下边是症状部分。从用细胞自动机模拟流行病传播开始,程富 S
在顶部或传染性方面,首先病毒是潜伏的,这意味着这个人不会立即传染。几天后,在新冠肺炎,它们变得具有传染性。最后,甚至在症状完全停止之前,它们就进入了消除阶段,这意味着它们再次不具有传染性。在底部或症状方面,首先他们处于潜伏期,这意味着他们没有表现出症状,然后他们变得有症状(或者无症状,这意味着他们从未表现出可能对他人造成危险的症状)。最后,症状会从轻微发展到严重,然后可能导致死亡。然而,大多数人只会经历轻微的症状。模拟包括这个重要的时间线,它与当前的新冠肺炎发现是精确的。
感染模型和戴口罩
一个流行的感染模型是 克马克-麦肯德里克模型 。这有助于计算一段时间内封闭人群中的感染人数。它是一系列描述感染的微分方程,但是在这种情况下,在给定周围感染人数的情况下,使用非微分导数来描述易感者被感染的概率。

给定传染概率 p(传染邻居将疾病传染给易感者的概率)和 R(传染邻居的数量)。从元胞自动机模型看流行病,常 S
戴口罩已经被证明可以限制传染性飞沫的传播。换句话说,戴口罩的感染者将病毒传播给附近易感者的几率较低。所以在上面的等式中,p 值对于所有的感染者来说是不一样的,对于戴口罩的人来说会更低。
安全政策
在开始运行模拟之前,我们需要知道我们要分析什么。即使在无数的研究和报告之后,人们仍然在争论戴面具或 T2 社交距离的有效性。此外,一些州在安全问题上比其他州宽松得多,没有经常强制要求佩戴口罩,或者在加强社会距离方面动作缓慢。因此,让我们通过给戴口罩的人分配概率和社会距离来看看不同级别的安全政策,看看这些技术有多有效。
统计和概率
准确模拟新冠肺炎病毒而不仅仅是普通传染病的最重要的一步是获得正确的概率。许多价值观没有一个一致同意的答案,所以我坚持使用可靠的来源,如疾病预防控制中心和最近的研究论文。一些重要的数值,如感染的基本概率和戴口罩后感染概率的降低并不存在。然而,我将这些值设定在合理的范围之外,并对它们进行了调整,使模拟病毒的 R0 与新冠肺炎病毒相同。
结果和分析
低安全政策
每个人最初有 10%的社交距离和 10%的戴面具的机会。

注意感染传播的速度

显示所有人(总数)、社交距离者(标准差)、非社交距离者(非标准差)在每个时间步(一天)的感染数
该图清楚地表明,练习社交距离的人感染的可能性要小得多。

为社交距离者、戴口罩的人以及两者都做或都不做的人每 5 个时间步长显示 R0
戴口罩、保持社交距离或两者兼而有之的人感染的人数几乎总是比不采取这些安全预防措施的人少。
中等安全政策
每个人最初有 25%的机会保持社交距离,有 25%的机会戴面具。

红色和蓝色比上面少

就像非常不安全的政策一样,那些有社交距离的人比那些没有社交距离的人更不容易被感染。

同上,那些采取安全预防措施的人有助于减少其他人的感染。
高安全性政策
每个人最初有 50%的机会保持社交距离,有 50%的机会戴上面具。

甚至更好

这与上述趋势一致,但界限更近,这可以解释为由于总体安全性,感染人数普遍减少。

这个 R0 图很难读懂,线条更倾向于交叉。然而,在大部分时间内(尤其是 20 到 35 岁之间),采取安全预防措施的人感染的人更少。因为没有太多受感染的人,所以不同的模拟运行会导致看起来非常不同的 R0 图。用随行的 代号 自己试试。
比较安全策略的 SARs
比较不同安全策略有效性的一个好方法是,在模拟结束时,只查看感染与总易感性的比率,即 SAR。

低安全性的 SAR 几乎是高安全性的 4 倍。让我们比较更多的安全政策的计算,以深入了解这一点。
比较感染总数

同样,越不安全,即社交距离越小和戴口罩,感染和死亡就越多(未显示)。注意:时间步长 14 处的下降是因为那些最初被感染的人恢复了(如果他们没有死亡的话)。
比较 r0

R0 图不像感染或 SAR 那样清晰,但在大多数情况下,安全策略归因于较少的终生感染。只有在时间步长 40,它才高于较不安全的策略。试着自己运行模拟,看看结果是什么样的。
社交距离 vs 戴口罩?
本节前驱:双管齐下!然而,我只是想看看哪种方法更能有效地降低模拟的感染人数。

WM%按列,SD%按行。这些百分比再一次代表了个人社交距离或最初戴面具的机会
从该交叉表中可以明显看出,社交距离和戴口罩意味着较低的 SAR,即较少被感染。它还表明,社会距离是非常重要的,因为对于不同水平的社会距离,SARs 之间存在巨大的差异。戴口罩也有影响,但没有那么明显。然而,一点点走了很长的路,SAR 仍然从 10% WM 下降到 50% WM。
结论
通过这个用细胞自动化对流行病进行的简单模拟(使用新冠肺炎统计数据),我们可以看到采取安全预防措施是多么重要,比如保持社交距离和戴口罩。请做这些事情,帮助降低新冠肺炎的感染率。
旁注:有更多的事情可以添加到这个模拟中,如年龄效应,住院治疗,测试和自我隔离。叉我的回购并尝试测试这些东西,以增加更多的模拟现实!
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
使用 Go 和 Python 模拟流行病
用 Go 和 Jupyter Notebook 模拟和分析不同的流行病情景
这是一些直接影响我的事情,甚至当我打出这个故事的时候。2019 年 12 月底,一种新型冠状病毒在中国武汉爆发,并迅速蔓延到中国其他地区和境外。截至 2020 年 2 月撰写本报告时,距首次报告不到 2 个月,已有约 70,000 例确诊病例,近 1,700 例死亡。虽然大多数病例和死亡仍在中国,以武汉及其周边城市为中心,但情况正在迅速演变。

(演职员表:邓https://www.flickr.com/photos/186588517@N05/49477439332/)
在我居住的新加坡,1 月 2 日报告了第一例疑似病例。患者是一名有武汉旅行史的三岁女童。原来是肺炎。
1 月 23 日出现了第一例实际确诊的新冠肺炎病毒病例,这是一名来自武汉的 66 岁男性中国公民的输入性病例,他于 1 月 20 日与其家人抵达新加坡。在接下来的几天里,这些数字迅速增加,都是外来病例。有一段时间,人们曾希望这只是外来病例。2 月 4 日锤子落下报告了 6 例,包括 4 例人际传播。第一例本地传播病例已经出现。
模拟流行病
像新加坡的每个人一样,我一直不安地关注着局势的发展。作为业务连续性规划的一部分,我已经将我的团队进行了分离,并要求其他不必参加面对面会议的人在家工作。生活和工作仍在继续,但紧张和焦虑的情绪正在酝酿。

(鸣谢 pix abay:https://pix abay . com/illustrations/virus-microscope-infection-disease-1812092/)
所以我想尽力而为。在之前的一个项目中,我用彩色网格模拟了文化互动和传播。为什么不用我之前建立的相同机制来模拟流行病的传播呢?
流行病建模
大部分代码与文化互动模拟相同,所以我不会在这里重复。相反,我只关注不同之处。
让我们从流行病建模开始。这个模型非常简单。使用细胞网格,我从网格中心的一个被病毒感染的细胞开始。几天后,被感染的细胞会感染它的邻居,我将从模拟中收集数据并做一些分析。

(鸣谢:张秀雄)
基本参数如width和numDays与之前的模拟基本相同,而filename是保存模拟数据的文件名。
模拟配置和参数
流行病模拟的第一个参数是感染率(rate),即细胞感染其邻居的可能性。接下来是潜伏期(incubation),即病毒在开始传染之前保持休眠的天数。在这个阶段,细胞已经被感染了,尽管它还没有传染性。感染持续时间(duration)是细胞保持感染性的时间。在感染期结束时,细胞将恢复或死亡。细胞死亡的可能性是致死率(fatality),细胞再次感染的可能性是其免疫力(immunity)。
我们从网格中心的一群健康细胞和一个感染细胞开始模拟。在我们的模拟中,不会填充整个网格,网格中的单元数量由参数density决定。当值为1.0时,整个网格将被填充,而在另一端,0.0意味着网格根本没有被填充。
虽然我模拟了疫情随时间的发展,但我也想了解隔离措施和有效药物的引入如何有助于阻止疫情。
参数medIntroduced是在抗击疫情中引入药物的日期。例如,如果值为100,则表示在第 100 天引入了药物。参数medEffectiveness是对引入药物有效性的测量。值1.0表示药物完全有效,每个接受药物治疗的细胞将有 100%的机会恢复,而值0.0表示药物完全无效。在被感染的细胞接受药物治疗并失败后,这就是生命的尽头,它将不得不依靠自己的运气生存。
参数qIntroduced是类似检疫措施出台的日子。参数qEffectiveness是衡量隔离成功程度的指标,包括找到被感染的细胞并确保其被正确隔离。一旦被感染的细胞被隔离,它将无法感染它的邻居,尽管这不会影响它的存活率。
细胞
有了这个,让我们看看我们需要如何改变Cell结构。没有任何惊喜,相应的参数被忠实地反映出来。
我给Cell结构添加了许多新方法。大多数方法都是不言自明的,所以我不会费心去描述它们。
medicate方法将药物应用于细胞,有机会使细胞恢复。如果没有,我会将该手机标记为正在接受药物治疗,我不会再呼叫它。一旦药物被证明无效,那就完了——细胞要靠自己了。
process方法是大部分动作所在的地方。如果被感染的细胞仍在孵化中,我减少它的孵化计数器,不做任何其他事情。否则,我将开始减少其持续时间计数器,一旦持续时间计数器达到 0,根据死亡率,细胞将恢复或死亡。
让我们继续进行主模拟。
主模拟
我从创造人口开始。如前所述,density参数决定了模拟网格的填充量。默认情况下,值为0.7,意味着 70%的网格将(随机)被单元格填充。
接下来,我感染了模拟网格正中央的一个细胞。然后开始模拟。
主模拟循环基本上贯穿所有单元,打印出网格,并在屏幕上打印一些信息。以下是遍历单元格时的步骤顺序:
- 首先,我只关心被感染的细胞,如果不是被感染的细胞,我就忽略它
- 接下来,我用上面的
process方法处理单元格。这将相应地减少孵化或持续时间计数器,如果持续时间达到 0,将为细胞选择恢复或死亡 - 如果细胞已经恢复或仍在孵化,我将跳到下一个细胞
- 如果是时候引入药物,我就开始给细胞用药。如果药物对细胞起作用,它就痊愈了!否则,我会将它标记为正在用药,并在后面的循环中跳过它(药物不再对它起作用)
- 当然,如果药物起作用了,细胞就会恢复,所以我会继续下一个细胞
- 如果是时候引入隔离措施,我会检查是否已经发现并隔离了受感染的细胞,如果没有,我会隔离该细胞
- 如果到达这里,最后一步是查看细胞的邻居。如果他们还没有被感染,如果他们对再次感染没有免疫力,我会试着去感染他们
模拟
正如你所看到的模拟是简单明了的。让我们来看看结果。
我将从一个典型的病毒流行开始,使用默认值。稍后,我们还将查看不同感染率的数据。
(鸣谢:张秀雄)
在默认的模拟场景中,网格填充了 70%,运行了 300 天。感染率为 15%,再次感染的可能性为 50%。病毒潜伏期为 3 天,传染性持续 4 天。致死率为 2%。

结果相当严峻。截至第 300 天,病毒仍然活跃,几乎所有细胞都被感染,尽管几乎 96%的细胞至少有一次从中恢复。结果,18.4%的人口死于该流行病。
虽然每次感染的死亡率为 2%,但由于细胞可以一次又一次地被再次感染(它们只有 50%的免疫力),死亡人数要高得多!
感染率不同
让我们用数据仔细看看。我模拟了 10%、15%、30%和 50%的感染率。从模拟中收集的数据显示了一段时间内任何时间点的感染数、死亡数和已感染细胞数。如果你不明白感染数量和感染细胞数量之间的区别,感染数量是当前感染的数量,可能包括再感染,而感染细胞数量不包括再感染,包括已感染、死亡或恢复的细胞。
和以前一样,我在 Jupyter Notebook 上使用 Python 3,加入 matplotlib 并做了一些简单的图表。代码相对简单,我不会解释它,你可以在这里简单地阅读它。
相反,让我们看看结果。对于任何时间点的感染人数,你可以看到有趣的是,这个数字随着时间的推移而下降。

这不一定是一件好事,因为如果你看下一张图表,你可以看到死亡人数只是线性上升,这意味着感染随着时间的推移而下降,因为活着的细胞越来越少!

最后,让我们看看随着时间的推移,被感染的细胞数量。随着时间的推移,这些数字趋于平稳,因为所有细胞都被感染了!

不同的死亡率
现在让我们看看 1%、2%、5%、10%和 20%的不同死亡率。
感染人数最初保持不变,但随着时间的推移,较高的死亡率并不一定意味着更多的感染,事实上,情况正好相反!

这很可怕,因为死亡的细胞越多,感染的就越少!

最后,你可以看到不管死亡率如何,被感染细胞的总数几乎是相同的。

虽然我可以对其他流行病参数做同样的事情,但这一切都有点太病态了,无法继续。让我们转到一些更积极的话题,我们能做些什么来应对这种流行病,减缓甚至阻止它?对于模拟,我有两种方法:
- 隔离—隔离受感染的细胞,使其不会感染其他细胞
- 药物治疗——治愈病毒性疾病,使细胞恢复
一目了然,你觉得哪种方法帮助更大?我们来实验一下。
带隔离
从视频中可以很快看到,一旦隔离开始(这里是从第 50 天开始),疫情很快得到控制!
(鸣谢:张秀雄)
事实上,如果您将此与没有隔离的模拟进行比较:
- 18%的人口被感染,相比之下,99.4%的人没有被隔离
- 0.8%的人口死亡,相比之下,没有隔离的人口死亡率为 12%
这是相当惊人的进步!为了进一步探索,我用 10%、20%、30%和 50%的不同隔离效率进行了模拟。
从下面的图表中,您可以看到不同的隔离效果以不同的速度减少了感染数量。在 10%的有效率下,效果很低,但一旦达到至少 20%或以上,感染就会急剧下降。即使这样,不管隔离有什么效果,它仍然比没有隔离好得多!

和死亡一样,一旦隔离到位,死亡人数会急剧下降。即使在 10%的有效率下,你也可以看到数量逐渐减少,这意味着过一段时间后不再有细胞死亡。

受感染细胞的数量也急剧下降。对于 20%和更高的有效率,你可以看到在第 50 天之后数字变平,意味着不再有细胞被感染(你也可以从模拟中直观地看到这一点)。

如果隔离稍后开始
如果隔离晚些时候开始呢?这导致了感染的增长,但和以前一样,一旦隔离到位,感染就会迅速下降。

死亡图表与我们分析隔离有效性时的图表相同。过了一段时间,不再有细胞死亡。

感染细胞的数量也是如此。

现在让我们看看第二种方法,即药物治疗。
用药物
对于药物治疗,影响是不同的。首先,一旦药物应用于细胞,它就有机会恢复(药物的有效性)。然而,如果它没有恢复,就意味着药物对它不起作用,即使它自己恢复并再次感染,也永远不会起作用。
其次,药物不会改变再次感染的可能性,所以你可以在下面的图表中看到,在药物有效性较低的情况下,感染的数量只是减缓,而不是完全消失。
然而,随着药物有效性的增加,它通过完全治愈细胞来防止细胞被感染!
我在药物有效性为 0%、30%、50%和 75%的情况下运行模拟。在 75%的有效率下,感染的数量在第 50 天之后很快下降到 0,而即使在 50%的有效率下,疾病仍然存在,并且感染在一段时间后甚至增加。

相应地,这转化为死亡人数。在效力较低的情况下,这种药物只是降低了死亡率,但从未完全消除死亡,但如果这种药物足够有效,它将完全消除感染,并防止更多的死亡。

这也可以从感染细胞数图表中看出。

从这个分析来看,似乎药物治疗不如隔离。然而,这是一个角度的问题,如果你看整个疫情,似乎隔离更有效,但如果你是病人,隔离对你个人没有任何作用,而药物可能会挽救你的生命!
如果我们采取隔离措施并使用足够好的药物会怎么样?
隔离和药物治疗
从第 50 天开始,我使用了 20%的隔离效果,50%的药物效果,也是从第 50 天开始,然后将它们与单独的隔离措施和单独的药物进行比较。
正如你从图表中看到的,使用这两种方法可以非常有效地阻止流行病的传播!从第 50 天开始,感染数量急剧下降。

它也减少了总的死亡人数,比两者单独使用要好。

并且感染细胞的数量也减少了。

隔离和药物治疗的综合效果非常有效。如果它们具有足够的有效性,(如果它们被很好地实施)就有可能阻止流行病的蔓延!
摘要
我只做了部分模拟。例如,我没有对潜伏期或传染期的变化进行任何模拟。我没有探究免疫接种(或疫苗接种)预防再感染的效果,也没有观察不同的人口密度。如果你喜欢我所做的,请自己尝试一下。
我们至少从这个练习中发现了:
- 流行病非常可怕。如果不加控制,整个人口都可能被感染,大部分人口可能会死亡。如果我们回顾历史,我们可以从西班牙流感(导致 5000 万至 1 亿人死亡)、黑死病(导致欧洲 60%的人口死亡)等事件中看到这一点。
- 隔离是阻止流行病传播的最有效的方法,越早实施越好。隔离的有效性也很重要,这包括发现和隔离感染者。
- 药物治疗只有在治愈感染者的有效率较高的情况下才有用,否则,它只会减缓疫情。
- 隔离和药物治疗相结合是阻止疫情的最有效方法。
结论
我经常否认模型只是模型,模拟只是模拟。它们试图给我们一种探索现实生活中不可能实现的可能性的方法,但它们与真实的事物并不相同。我们只能用我们的参数提供一个近似值。这个模拟也是这种情况。
我希望这是有用的,但如果你不同意我的结论或方法,请随时纠正我,并提交代码拉请求!
用 Go 和 Python 实现流行病模拟。通过在…上创建一个帐户,为少林寺/流行病模拟世界的发展做出贡献
github.com](https://github.com/sausheong/epidemic-Sim)
与此同时,我仍在焦急地等待新冠肺炎疫情平息,重新开始我的生活。
模拟我自己的竞争:优惠券兑换
作为游戏大师,我把问题设定为:预测哪些顾客会在特定活动下兑换优惠券。
我的雇主举办了一次数据科学黑客马拉松,我是游戏大师。这是我和同一所学校组织的第二次黑客马拉松,和第一次一样,这是一次班级内的竞赛。赛克斯·ADMU 数据科学黑客马拉松第二届于去年 2 月 1 日至 2 日在 Rizal 图书馆结束。
作为这次活动的游戏大师,我有幸创建并主持了 Kaggle 竞赛,这将是学生们的习题集。一个引导板会让学生们的答案相互竞争,当时间流逝时(第二天),就是数据讲述时间了。这是机器学习和商业领域知识的结合。我设定的任务是:预测哪些顾客会在特定的活动中兑换优惠券。这在电子商务中非常重要,因为可以使用特定的活动方法和优惠券促销为客户群重新注入营销活力。这三个 id,我们的客户,优惠券和活动组成了我们的三胞胎。这篇文章是关于我的解决方案的。

会买哪个券?谁会买?图片来源:https://digitalmediathougts . com/89624-the-complete-guide-to-master-coupon-marketing/
和往常一样,如果你只是想跳到我的解决方案,这里有 Github 的链接。我们开始吧!
数据和初步想法

该数据集包含所有客户的商品交易,无论优惠券是否已被兑换。令人兴奋,所以我可以做一个推荐引擎。然而,我开始看到我推荐的这个正在进行的事情就像在每一个钉子上施加一个锤子。因此,让我们从特征工程的角度来看这个问题。我们应该从几个角度对数据的行为有一个细致入微的理解。开始一些探索吧!
探索性数据分析
少数优惠券主宰了这些数据,这是许多电子商务应用程序的标准。在 200 多张优惠券中,只有 5 张优惠券的兑现率超过了 50%。作为游戏大师,我创造了“仅流行优惠券”作为基线非 ML 解决方案。仅将前 10 张优惠券标为“总是兑现”就能让参与者净赚 0.87 AUC。然而,这里有一个明显的抽样问题。如果发现了一个新的优惠券,它不在训练数据中,那么我们就完全被难倒了。在现实世界中,高管们期待新的东西——他们不太可能被包含相同的旧促销优惠券的演示所购买!“给我一些新的东西”是许多专业人士害怕的…
我想找到可概括的特征。我想把优惠券的特点,如活动,客户,交易和项目的特点。例如,这里有一些有趣的事情:
不同类别之间的折扣和售价比较

折扣和售价本身当然很重要。这很难进行简单的分析,因为一张优惠券适用于几种商品。所以我不知道,从这个图来看,赎回的和未赎回的三胞胎看起来没有区别。橙子是赎回的三胞胎,而紫色(蓝色和红色混合在同一空间)在中间。但是,平均折扣和最低折扣在统计上有所不同。赎回的三胞胎的最低折扣更高,因为这是一个很低的底线。低折扣,耶!非直觉地,未赎回的三胞胎的平均折扣略高,可能是因为一些客户发现其中的一些项目令人生畏。
每个收入等级的兑现优惠券

这里有一个简单的。更高的收入等级表明更倾向于为我们的三胞胎兑换优惠券。然而,最高的两个括号似乎是最不感兴趣的。优惠券?多平民啊!
品牌和类别兑换百分比

当我们转向类别和品牌时,我们看到无论是本地品牌还是老牌品牌,食品杂货和药品都是最受欢迎的。对于本土品牌,顾客会寻找包装好的肉类和海鲜,因为前者容易买到,而后者可能比进口的更新鲜。老牌品牌,几乎所有的东西都依赖于食品杂货和药品,这两者在所有商品组合中所占的比重更大。
我们放大已建立的品牌。如果优惠券上有一个知名品牌,而顾客以前也买过这个知名品牌,那么这就是天作之合。如果是食品杂货/药品,还有额外的奖励。这很难想象,但是原则应该是有的。
结论:非线性模型效果最好。根据我们对类别和品牌类型的发现,顾客和商品应该对同一件东西有兴趣。
建模运行
当然,不要太关注模型的运行,因为它们应该很简单。要记住的唯一明智的事情是,由于这是一个非常倾斜的数据集,因此类权重或损失函数、度量和训练方法应该考虑这种倾斜。

- 为了速度,我跳过了超参数优化。
- 此外,在我们的测试中,阴性样本与阳性样本的比例非常不均衡(15009 个阴性样本— 423 个阳性样本)。
逻辑回归系数

这里是线性分类器的系数。它受到可实现的数据分离超平面的限制,这就是为什么它分别关注天然产品、沙拉、知名品牌、乳制品等。
随机森林要素重要性

然而,非线性集合模型才是王道。这里我们看到了随机森林分类器的特征重要性。在顶部的特性中,我们看到了预期的 coupon _ category _ type _ 杂货(优惠券中适用的杂货项目的数量)和 category _ type _ 杂货(客户过去购买的杂货项目的数量)。优惠券、类别功能和一堆我们在 EDA 中没有发现的其他东西之间存在联系,例如活动类型和优惠券中包含的品牌数量。
总结词
在这方面还有更多事情要做。用于压缩用户项目矩阵的 PCA 应该工作得很好。因此,这是推荐引擎之路,所以不妨再次提及。向用户推荐商品是一回事,所以我们推荐对该商品有最大折扣的优惠券是个好主意。
如果你已经走到这一步了,我想为获胜者欢呼。那是 Hakuna Matata,随机森林和团队。适合()。我应该说我自己的解决方案在私人排行榜上被团队超越了。根据 AUC 拟合()。 GGWP。数据科学社区再见!
归功于我在 Kaggle 找到的原始数据集。当我看到缺少正面的例子时,我将创建的伪标签带到测试集来扩展训练集。这些伪标签来自超参数优化的随机森林模型的第 90 个百分位数的概率。
【http://itstherealdyl.wordpress.com】原载于 2020 年 2 月 9 日。
在策略游戏中模拟瘟疫感染
用二项分布逼近回合制策略游戏的概率

概率可能很难计算,尤其是在复杂的情况下。解决这个问题的一个方法是将概率情况转化为代码。通过多次运行这个代码,我们可以近似地计算出某个结果的概率,而不必直接推导出来。这是一个模拟,在处理大量问题时非常有用。
最近一个朋友来找我,提出了这样一个问题。受到禁闭的启发,他正在为一款回合制策略游戏设计一个 mod,该游戏将疾病作为游戏机制引入。前提是沿着固定路线旅行的商人(游戏中的角色)有很小的几率在每次旅行中感染瘟疫。一旦被感染,他们会将疾病传播到他们到达的下一个城市。之后,他们恢复健康,再次踏上旅程。
如果你曾经玩过《文明》系列的游戏,或者类似的游戏,你可能会在脑海中想象出这个游戏的样子。
在这个场景中的每个回合,交易者都会遇到两种情况中的一种;他们要么被感染,要么保持健康。如果感染的概率在交易者的旅程中保持不变,那么感染变量就是二项式。二项式随机变量包含在二元结果的情况下,在 n 次试验(交易者旅程中的回合)中成功的次数(在我们的例子中是感染)。
简单的问题
鉴于上述情况,我朋友的问题如下。如果去一个城市的旅程持续 10 回合,并且每回合有 5%的机会让一个单位感染瘟疫,那么这个城市被感染的概率是多少?
有一个简单的答案。如果每个回合感染瘟疫的几率是独立的,那么上面的概率是 1 - (1 - 0.05) ⁰ = 0.401。
也就是说,我认为他描述的情况也可以模拟。为此,我想出了以下 R 代码:
我的方法很简单。我从二项分布 B ( n , p )中抽取每一轮的结果,其中 p 是每一轮被感染的概率。我在 R 中使用rbinom(10, 1, 0.05)对此进行了编码,它返回一个 1 和 0 的向量。将每个 1 解释为感染,将每个 0 解释为避免感染,我们可以模拟交易者在交易过程中的感染状态。
这让我们来回答我们的问题。我们可以编写一个函数journeysim来调用rbinom并评估在 10 个模拟回合中是否有“1”出现。如果是这种情况,那么我们可以假设我们模拟的贸易路线末端的城市被感染了,然后返回TRUE。如果没有,函数返回FALSE。
然后我们运行journeysim很多次。我选择了 100000,以可接受的精度水平来结束概率估计。然后,我们对 100000 次运行中的TRUE元素的数量求和,并除以 100000。这将给我们一个非常接近的答案,0.401。
更复杂的问题
上面的问题可能看起来微不足道,但它是对模拟逻辑的介绍。为了更进一步,我们可以看一下前面问题的一个稍微复杂一点的扩展。
让我们假设这一次,这些单元做了一个多站的旅程。他们在四个城市停留,从一个城市到另一个城市转 10 圈。每回合感染概率保持在 0.05。假设同一个交易者可能不止一次感染鼠疫,那么在这段旅程中的任何一点上,两个城市同时被感染的概率是多少?
这仍然可以用手算出。首先,我们用 1 - (1 - 0.05) ⁰ = 0.401 来计算交易者将瘟疫传播到某个城市的可能性。接下来,我们可以将旅途中任何两个城市被感染的概率表示为

但是再一次,我们可以模拟这个问题。这一次的 R 代码如下。
为了获得这个新旅程的值,我们编写了新的函数long_journeysim。这使用 10 作为旅程长度参数调用了journeysim四次(对应于问题中的四个城市)。然后它检查这些城市中是否有两个被感染,并返回TRUE或FALSE来表示这个结果。像以前一样,我们用map_dbl运行long_journeysim 100000 次,然后将返回TRUE的运行次数除以总运行次数。这接近正确概率 0.346。
计算量大的问题
虽然上面的例子比第一个要复杂一点,但是手工计算还是很容易的。那么有没有这样的情况,模拟是一种更必要的方法,而不仅仅是一种获得近似答案的替代方法?让我们举下面的例子。
假设你的交易者不得不走任意长的路。假设现在每个城市的旅行时间是 112、73、187 和 144 转,而不是 10 转。每回合感染的概率现在是 0.01,你要找出沿途 1 到 3 个(含)城市中任何地方被感染的概率。
这个问题的答案涉及到大量繁琐的组合学和额外的计算。然而,它只涉及修改我们先前模拟的一些细节,以接近正确的答案。
模拟到每个城市的旅程的函数adv_journeysim对决定其输出的条件语句做了一点修改。这一修改意味着,如果沿途总共有 1、2 或 3 个城市被感染,则函数返回TRUE,如果没有,则返回FALSE。现在剩下的就是使用map_dbl运行函数,调整journeylengths参数来表示我们到每个城市的新旅程。在运行这个并将allsims中的TRUE 元素的总和除以allsims的长度后,我们得到一个近似的答案 0.766。
这是一个问题的例子,它变得比手工解决问题更直观。与其在纸上计算如何处理问题的多个新变化,不如用功能代码来近似解决方案更容易。
二项式概率随处可见。当你抛硬币,玩回合制策略游戏,或参与任何数量的其他活动时,二元结果是预期的。因此,当计算出一个精确的概率很复杂时,能够快速简单地模拟这些结果是非常有用的。
只要你能在代码中重现一种情况,近似概率就变得直观了。
想阅读我所有关于统计学、数据科学等方面的文章吗?在这个链接注册一个媒体会员,就可以完全访问我所有的作品和媒体上的所有其他故事。这也直接帮助了我,因为我从你的会员费中得到一小部分,而不需要你额外付费。
每当我通过订阅这里发帖,你也可以将我所有的新文章直接发送到你的收件箱。感谢阅读!
模拟概率|解决经典的蒙蒂霍尔问题
Monty Hall 提出了一个概念上令人困惑的问题,使用模拟我们可以实时验证这一现象

图片来自皮克斯拜
介绍
在本帖的过程中,我们将学习如何使用模拟来理解概率,我们将使用 Monty Hall gameshow 问题的经典示例。
Monty Hall 有一个游戏展示,他展示了下面的问题。如果你不熟悉他或他们的游戏,它在 2008 年的 21。无论如何,如果你不熟悉这里的问题。
蒙蒂·霍尔问题
他会给他的参赛者三扇门来选择。两扇门后是山羊…但其中一扇门后是一辆跑车。
假设节目里的人是你。蒙蒂让你选择一扇门,如果你是正确的,你就可以得到这辆车。
现在你问自己,任何一扇门后面有车的可能性有多大?
你我都知道,不管你选哪个门,你都有 33.3%的几率拿到车。
因为没关系,假设你选 1 号门。但是在他揭示后面是什么之前,他阻止了你,并且揭示了一只山羊坐在剩下的两扇门的后面。(如果他们中的一个真的有车,他总是知道谁有羊)
他现在问你,你是坚持原来的选择,还是换到另一扇没打开的门?
典型的想法是,这仍然无关紧要,因为你现在有 50%的机会选择后面有车的门;然而,现实情况是,实际上有 66.7%的可能性汽车在另一扇门后。分配给其他两个门的概率现在浓缩为一个门,因为您知道汽车不在其中一个门的后面。
从概念上讲,这是一件很难理解的事情,我们不会花更多的时间试图从概念上说服你为什么。从这里开始,我们将模拟这个游戏,观察不同场景下的概率。
让我们把这个游戏转换成一些代码,我们可以重复运行数千次,以确定可能性。
让我们开始编码吧
重要的事情先来。让我们考虑一下系统地解决这个问题所需的不同变量或占位符。
我们需要包括以下内容:
- 门
- 获胜之门
- 首选
- 显露的门
- 最终选择
门
好了,让我们开始创建一个矢量来代表门。
doors <- c(1,2,3)
很容易..向量有三种不同的选择。
获胜之门
现在让我们随机选择哪个门有车。sample 函数将获取你传递给它的任何向量的 n(大小)。在这种情况下,它将从 doors 中提取 1、2、3。
winning_door <- sample(x = doors, size = 1)
首选
正如我刚才提到的,现在是你选择哪扇门的时候了。如果你真的想玩这个游戏,你可以这样设置,问你想要三扇门中的哪一扇门。
which_door <- function(){
door <- readline("1, 2, or 3?")
return(as.numeric(door))
}
first_choice <- which_door()
但是我们会在 for 循环中一遍又一遍地重复这些步骤。因此,我们不会每次都强制手动输入,而是将第一选择声明为 1 号门。
first_choice <- 1
显露的门
我们现在需要确定我们的程序将揭示剩下的两扇门中的哪一扇门。我们知道蒙蒂会选择剩下的两扇门中的一扇。
让我们想想这些案例:
- 在你选择了汽车的情况下,剩下的两扇门后面都有山羊——所以没关系
- 如果你选择了一只山羊,你只需要确保你选择的门不等于你刚才取样的获胜门。
我们将把它写成 if 语句。
因此,正如我们刚刚讨论的,如果获胜的门是第一选择,则在移除 first_choice 后对门向量进行采样。如果不是这样,那么从 doors 向量中删除 winning_door 和 first_choice,剩下的唯一选项将是剩余的山羊。
if (winning_door == first_choice){
revealed_door <- sample(x = doors[-c(first_choice)], size = 1)
} else {
revealed_door <- doors[-c(first_choice, winning_door)]
}
最终选择
类似于我们刚刚做的,让我们假设在任何情况下,我们都将固执地坚持我们的门。我们要抵制智慧,追求智慧。
final_choice <- first_choice
如果你想在我们采纳明智的建议时看到结果,你可以使用这段代码。
final_choice <- doors[-c(first_choice, revealed_door)]
把所有的放在一起
让我们来看看目前为止我们设置的所有内容。
我们会声明刚刚经历过的变量。我包含了 final_choice 的两个版本,但是注释掉了第一个版本。
我在这里添加的最后一部分是一个条件输出,如果你赢了就说万岁,否则就享受你的山羊。
winning_door <- sample(doors,1)
first_choice <- 1
if (winning_door == first_choice){
revealed_door <- sample(x = doors[-c(first_choice)], size = 1)
} else {
revealed_door <- doors[-c(first_choice, winning_door)]
}
#final_choice <- doors[-c(first_choice, revealed_door)]
final_choice <- first_choice
if(final_choice == winning_door){
print('brand new car')
} else {
print('have a goat')
}
模拟时间
这是一个坚实的开端,但实际上,我们不会一遍又一遍地记录结果。技术上我们可以,但我们肯定没有必要。
我们只需要做一些编辑。
首先,让我们将代码嵌套在一个 for 循环中,这样我们就可以按顺序一遍又一遍地运行它。
for(i in 1:10000){
}
这将瞬间重复这个过程 10000 次,但是我们真的想打印结果吗?我们真正想做的是记录结果,将它们存储在某个地方,以便我们可以收集我们正在创建的信息。
我们需要一个计数器。
wins <- 0
这不会嵌套在 for 循环中,因为我们不希望计数器在每次运行下一条记录时都回到 0。
我们将在 for 循环中包含每次运行结束时的考虑,“我们赢了吗?”如果是这样,我们将 win 计数器加 1。
wins <- wins + 1
这是全部组装好的。
wins <- 0for(i in 1:10000){
winning_door <- sample(doors,1)
first_choice <- 1
if (winning_door == first_choice){
revealed_door <- sample(x = doors[-c(first_choice)], size = 1)
} else {
revealed_door <- doors[-c(first_choice, winning_door)]
}
# final_choice <- doors[-c(first_choice, revealed_door)]
final_choice <- first_choice
if(final_choice == winning_door){
wins <- wins + 1
}
}
现在我们已经有了获胜的次数,是时候看看如果你拒绝改变选择,你会赢的几率有多大了。
print(round(wins / 10000, 2))

因此,最初分配给三个选项中的一个选项的概率是 34%,而不是你最初认为的 50%。
如果我们再次转换我们的决策,我们可以看到概率是 67%,不是 50%,不是 33%。

结论
我希望你发现这个关于 Monty Hall 游戏的快速课程很有见地。当我们使用这些原则来为一个游戏建模时,我希望你能识别出可供选择的场景,让你以有意义的方式为概率建模。
欢迎访问我的 Twitter @ data _ lessons。
祝数据科学快乐!
用 Go 模拟种族隔离
用谢林的空间邻近模型探索种族隔离
尽管疫情席卷全球,但由于乔治·弗洛伊德被杀,美国种族不平等和分裂的潜在紧张局势已经爆发。我经常读到美国黑人不得不应对的骇人听闻的事情,但对这一事件的爆炸性反应让我感到惊讶,尽管事后来看,这不应该发生。

Teemu Paananen 在 Unsplash 上的照片
紧张局势已经酝酿了很长时间。尽管被认为是世界上对种族更加宽容的国家之一,种族隔离还是很好地表明了这一鸿沟有多深。
2009 年,激进的制图员(我承认这两个词对我来说不容易组合在一起)比尔·兰金绘制了一张惊人的地图,展示了芝加哥的种族隔离程度。

过渡的分类(致谢:比尔·兰金http://www.radicalcartography.net/index.html?chicagodots
他的作品让很多人惊叹不已,随后也激励了很多人。其中包括埃里克·费希尔,他很快拿出了一组美国其他城市的照片,显示出芝加哥并不是那么独特。




从左上至右下:迈阿密、洛杉矶、底特律、纽约(鸣谢:埃里克·费舍尔https://www . Flickr . com/photos/walking SF/sets/72157626354149574/with/5560490330/)
这显然已经持续了一段时间,不应该让任何人感到惊讶,尽管可视化是相当惊人的。有了如此明显的隔离,难怪最终会有事情发生。
但这仅仅是我们的问题吗?实际上不,这真的不是我们独有的,这是安德鲁·惠特比为伦敦(英国,实际上除了苏格兰)绘制的类似地图。

伦敦种族分布图(鸣谢:安德鲁·惠特比【https://andrewwhitby.com/2013/09/04/uk-ethnicity-map/】)
这是另一个被认为是世界上最具多元文化的城市多伦多。

多伦多可见少数民族(鸣谢:杰夫·克拉克http://neoformix.com/2013/TorontoVisibleMinorities.html
如果这个世界上最多元文化的城市也一样种族隔离,还有什么希望呢?
当我呆在家里时,我想起了不久前读过的一篇论文,作者是美国著名经济学家托马斯·谢林。这篇题为 种族隔离的动态模型 的论文谈到了美国的种族隔离,并创造了一些模型来描述它。我记得很清楚,甚至用一个特定的模型做了几次演讲,因为我认为其中有一些有趣的现实生活中的观点。已经有一段时间了,所以我又翻出了那张纸和我的旧笔记。
我在之前的演讲中模拟了简化版的谢林空间邻近模型。现在我有了一些时间(也有了一个新的模拟框架),我重新实现了一个更完整的模型。
隔离模型
谢林的空间邻近模型描述了两个不同的种族,黑人和白人,占据了一个特定的领土。每个人在任何时候都有一个位置,并且可以自由地移动到任何其他空的空间。在这个模型中,有 5 个参数:
- 邻域大小
- 要求自己种族(肤色)的百分比
- 黑人与白人在总人口中的比例
- 管理人员流动的规则
- 可供人们四处走动的空房数量
谢林的模型是手工运行的,也就是说,他在一张网格纸上画出#和0并通过它来工作。显然我不会这么做,相反,我将使用 Petri,我的 Go 细胞自动化框架来尝试复制谢林的模型。

鸣谢:托马斯·谢林,隔离的动态模型(https://www . suz . uzh . ch/dam/JCR:ffffff-fad 3-547 b-ffff-ffff 9a 867 c 99/09.27-谢林-71.pdf )
我修改过的模型
我的参数几乎和谢林的一样:
- 邻域大小
- 要求自己种族(肤色)的百分比
- 种族间的人口比例。这与谢林假设非黑即白的模型略有不同。对于我的模拟,我允许不仅仅是 2 场比赛
- 我取消了管理人员流动的规则,我使人员可以流动到任何有空缺的地方。相反,我添加了一个参数进行实验,如果我们应用规则来限制同一种族的邻居的数量,会怎么样
- 可供人们四处走动的空房数量
模拟是一个细胞自动机。我们建立了一个网格,并随机填充了不同种族的单位,每个单位占据一个不同的单元。并非所有的单元格都会被填充,一定比例的网格是空的。
久而久之,每个单位可以决定移动到另一个细胞或继续留在同一个细胞,根据规则,这主要取决于周围的单位本身。
构建模拟
为了实现这一点,我使用了 Petri,我的 Go 细胞自动化框架。你可以从这篇文章中获得关于如何使用 Petri 网创建模拟的快速入门。
邻域大小已经是 Petri 中为数不多的参数之一,所以我们不需要实现它。我们需要添加以下内容作为我们的周界:
coverage参数很简单,它只是一个百分比,描述为一个浮点数(默认为0.7或 70%)。raceRatio参数是种族间人口数量的比率,默认为 2 个种族,各占 50%,所以要使用的比率字符串是1:1。如果我们有 3 场比赛,比如第一场 50%,接下来的两场各 25%,那么要使用的比率字符串是2:1:1。
minList参数是自己种族的要求百分比。它的位置与raceRatio参数相对应。该数字表示可接受的同一种族邻居的最小数量。例如,如果数字是 2,那么至少有 3 个邻居属于同一种族。

如果可接受邻居的最小数量为 2,则必须至少有 3 个或 3 个以上相同种族的邻居
minList是位置性的,与种族比率相匹配,也就是说,给定 2:1:1的raceRatio和2:3:2的minList,这意味着,拥有 50%人口的第一个种族,其同一种族的可接受邻居的最小数量为 3 个及以上。有 25%人口的第二个种族必须有 4 个及以上同种族的邻居,同样有 25%人口的最后一个种族必须有 3 个及以上同种族的邻居。
maxList与minList相反。该数字表示同一种族邻居的上限最大数量。这是怎么发生的?在一些国家,例如在新加坡,有一些政策确保在住宅区有一定的种族组合。这是为了防止种族隔离。在许多其他多元文化的国家,也有一些政策和法律服务于同样的反种族隔离的目的。
使用 Petri 网
使用 Petri 网进行模拟非常简单。只有两步。首先,您需要创建一个实现Simulator接口的结构。我们不需要实现所有的方法,我们可以依靠 Petri 已经创建的方法,通过将petri.Sim作为变量包含在我们的结构中。
然后,您只需创建一个 main 函数,并运行您创建的结构的实例。
是的,就这么简单!
大部分逻辑在我们实现的两个方法中。第一个是初始化网格的Init方法。
大部分的动作是弄清楚如何处理种族比例和网格填充的百分比。第二种方法非常简单,只需随机创建一个介于 0 和 1 之间的浮点数,然后将其与覆盖率参数进行比较,如果低于该值,则应该填充它。
首先是关于它应该是哪一个种族。为此,我创建了一个函数calc,它创建了一个函数来确定应该是哪一场比赛。代码很简单,应该是不言自明的。
为Simulator接口实现的第二个方法是Process方法,它处理网格并决定单元是否应该移动到另一个单元格。
就是这样!你可以在 https://github.com/sausheong/segregation找到剩下的代码。
模拟种族隔离
现在我们从基本参数开始。默认情况下,覆盖率为 0.7(70%的网格被占用),1:1为种族比率,表示有 2 个种族,每个种族占 50%,2:2为最小列表,表示两个种族都需要至少 3 个相同种族的邻居,8:8为最大列表。因为每个单元只有 8 个邻居,这里的8表示没有上限。

种族比例 1:1
如你所见,已经有一定程度的隔离了,尽管很轻微。让我们将比赛的数量增加到 3 个,但保留相同的最小值和比率。

种族比例 1:1:1
看起来还不算太糟。但是记住,这还是相当宽容的,只要我的邻居中有 3 个是同种族的(37.5%),就没有动静。
更改邻居偏好级别
让我们后退一点,想象一个理想的世界,假设每个人都很好,如果至少有一个邻居是同一种族的(12.5%)。

最小列表 0:0:0
这看起来很随机,分布很广,因为单元是随机放置的。现在,让我们通过将最小可接受邻居数量设置为 5 或更多(62.5%)来将它提高几个等级

最小列表 4:4:4
仅仅是这个变化,没有其他变化,我们可以看到网格变得更加隔离。
改变种族间的比例
现在让我们稍微调整一下种族比例。根据 2019 年美国人口普查局的估计,白人占 76.5%,任何种族的西班牙裔和拉丁裔美国人占 18.3%,黑人占人口的 13.4%。我们将第一场比赛(深粉色)设置为 76,第二场比赛(草坪绿色)设置为 18,第三场比赛(深天蓝色)设置为 13,并重新运行模拟。

种族比例 76:18:13
我加快了这个 8x 的视频速度,但是你可以看到深粉色是如何快速稳定下来的(因为它的人口,但是其他两个种族在现有种族之间慢慢形成了自己的领地。深粉红色是非常稳定和集群,而其他 2 个种族需要相当长的时间来建立。
不同种族的邻居偏好水平不同
先前的模拟假设所有 3 个种族具有相同种族的相同最小数量的邻居。如果他们不一样呢?如果多数民族比少数民族要求更高会发生什么?

比例 75:18:13,最小列表 4:2:2
我们现在看到了一幅不同的画面。模拟很快稳定下来,另外两个要求较低的种族发现他们在大的飞地中不那么聚集在一起。
反过来呢——如果少数民族之一比多数民族和另一个少数民族要求更多?

比例 76:18:13,最小列表 2:2:4
要求更高的少数种族,深蓝,永远不会稳定,因为它走到哪里都会移动,而深红和草坪绿,这两种要求较低的稳定,分布非常好。
强加同种族邻居的最大数量
到目前为止,我们只研究了同一种族的最小数量的邻居。如果我们实施一些政策来防止种族隔离会怎么样?这意味着我们有一个相同种族的邻居数量上限。
记得早些时候,我们有这种情况,给定的种族比例是平等的,所有的种族都更加苛刻,我们有这些种族隔离集群?

种族比例 1:1:1,最小列表 4:4:4
如果我们设置一个上限,如果一个单元有 6 个以上的邻居,它必须再次搬走,怎么办?

种族比例 1:1:1,最小列表 4:4:4,最大列表 6:6:6
这是行不通的,因为唯一稳定的配置是,如果这个单位正好有 5 个同种族的邻居,并且有太多的运动让它达到一个稳定的稳态。
如果只有一个种族被强加了这种特殊的政策呢?

比赛比例 1:1:1,最小列表 4:4:4,最大列表 6:8:8
在这种情况下,因为草坪绿和深天蓝种族被给予自由统治,他们形成了他们通常的飞地,但因为深天红被强加了一项政策,它在他们的社区中长出了洞!这是因为其他种族都不会住在那些地方,那些地方也因为政策的原因不能被占领。
但是等等,那是因为他们有选择。所以,如果他们没有选择,因为根本没有空间?请记住,覆盖率参数允许我们指定模拟网格的填充程度。默认情况下是 70%,但是如果设置为 99%呢?(不可能是 100%不然谁都动不了)。

事实证明,它确实进入了某种程度的隔离,但是单元继续移动,它永远不会达到一个稳定的状态。
一些想法
模拟结果显示:
- 仅仅因为一个简单的事情,比如对同种族邻居的偏爱,我们就可能很快变得真正被隔离
- 在一个种族占多数的环境中,少数种族在优势种族遗留下来的地区形成他们自己的飞地
- 如果多数种族在要求其邻居是同一种族方面没有少数种族那么苛刻,这可能导致较少的隔离,反之,隔离仍然相当突出
- 仅仅实施政策来防止种族隔离是不会非常成功的。人们需要改变心态来欢迎不同种族的邻居
做和写关于技术的东西是我处理事情的方式,探索并试图理解我周围的世界。谢林是一位杰出的经济学家,他对许多事情都有深刻的见解。重新实施这些想法有助于更好地理解这个世界。
种族主义和种族隔离是当今世界的丑陋事实,但如果我们敞开心扉,欢迎与我们不同的人,事情会变得更好。
密码
你可以在这里找到这篇文章的所有代码——https://github.com/sausheong/segregation。
参考
分离的动态模型,托马斯 C·谢林(1971 年)——https://www . suz . uzh . ch/dam/JCR:ffffffff-fad 3-547 b-ffff-ffff 9a 867 c 99/09.27-谢林-71.pdf
使用新加坡族裔住房配额估计族裔偏好—http://public . econ . duke . edu/~ staff/wrk shop _ papers/2008-2009% 20 papers/wong . pdf
经济自由能培养宽容吗?—http://www.ifn.se/wfiles/wp/wp918.pdf
模拟股票市场回报和崩盘风险
在数据世界里争吵
依赖历史每日回报统计数据可能会对标准普尔 500 指数中的提款风险做出错误的推断

对于数据科学家来说,金融市场是一个快乐的聚宝盆,源源不断的数据源源不断。然而,这种诱惑对于不谨慎的人来说可能是一首警笛,因为金融市场的统计数据是不稳定的,不可靠的。通常它们看起来几乎是正常的(就像在分布中一样),但是看起来坚固的地面可能会迅速溶解成流沙,就像今年早些时候看到的那样。
世界上最重要的股市指数是 S & P 500 指数 (SPX),它被广泛认为是整个美国股票市场,甚至是美国经济状况的晴雨表。在截至 2020 年 3 月 23 日的 23 个交易日里,随着世界陷入新冠肺炎疫情的掌控,SPX 遭遇了灾难性的暴跌-33.9%。

在 1928 年至 2020 年的 23 个交易日中,排名前 10 位的 SPX 指数暴跌
这一-34%的跌幅是 1926 年推出的 SPX 历史上十大 23 天跌幅之一,仅次于预示大萧条的波动性。对许多交易者来说,这种经历就像遇到了只存在于古代民间故事中的神秘怪物。但即使在更近的时代,这种崩溃也确实是一种持续的风险,2020 年的经历在规模上并不落后于 1987 年 10 月经历的衰退。
我将尝试使用 SPX 从 1928 年到 2019 年的长期历史数据,模拟 SPX 中大约 30%的下跌的 事前概率 。为了确保这是真正的事前,不会使用 2020 年的数据。在整个练习中,我交替使用术语“股票市场”和 SPX。为了简单起见,我将使用简单的百分比回报,而不是学术文献中典型的对数回报。
在做这个练习的时候,我还会演示股票市场收益是非正态分布的,而且大部分是用图片来演示的。此外,我将展示如何使用历史每日回报数据提供关于潜在股票市场回报的方差或范围的误导性推论。一个日历月平均有 21 个交易日,我将比较不同月份(和季度)的模拟回报与模拟每日回报的汇总回报有何不同。
波动聚类
尽管 SPX 在 1957 年才扩大到涵盖 500 只股票,但它已有近一个世纪的历史。从 1927 年末开始,通过彭博订阅,可以获得每日回报数据。我在这项研究中使用的历史价格和回报数据来自【1928 年 1 月 1 日至 2019 年 12 月 31 日。

退货折线图
上面的图表显示了 1928 年至 2019 年期间的日回报率(左)和日历月回报率(右)。当你仔细阅读这些图表时,有三个重要的特征需要注意。首先是,它们显示日收益率和月收益率都围绕一个均值波动(日收益率约为零),因此收益率数据乍一看似乎是稳定的或均值回复的。其次,它们显示了波动聚集的证据,即较大的绝对收益往往被聚集在一起,较平静的时期也是如此。
伟大的伯努瓦·曼德尔布罗在 1963 年首次注意到了这种波动聚集现象,当时他指出,“大的(价格)变化往往会伴随着大的变化,无论是哪种符号,小的变化往往会伴随着小的变化,”尽管这一现象随后被研究人员忽视了 20 年。
第三点,与每日序列相比,月度回报数据中的波动聚集现象似乎不太明显。稍后我将回到这个非常重要的波动聚集现象。
总体常态
从 1928 年至 2019 年样本期的平均日收益率为+0.0294%,而平均日历月收益率为+0.6172%。这与一个月平均(大约)21 个交易日的平均日回报率相一致。因此,从每天到每月的合计是正确的。


返回直方图图表
以上是日回报(左)和日历月回报(右)的直方图。如果你仔细观察,日线回报直方图相对于月线回报直方图有一个更尖锐的峰值和更长的左尾巴。这就是总体正态性(或总体高斯性)现象,收益的分布随着收益时间尺度的延长而变得更加正态分布。换句话说,不同时间尺度的收益分布是不一样的。

股市收益中的“肥尾”
日收益率和月收益率序列的过度峰度和偏斜度的正式度量结果如上。正态分布的过度峰度和偏斜度为零。当过度峰度介于+2 和-2 之间时,通常可以假设经验数据分布的正态性,而偏斜度应该在+1 到-1 的范围内。
在这种情况下,我们有两个偏度接近于零的分布的对称数据,但峰度是有问题的。峰度是尾部相对于分布其他部分大小的度量。这两种分布都呈现出臭名昭著的“厚尾,这是金融市场回报数据的典型特征。用统计学术语来说,回报分布是极端的。此外,日收益率显示出比月序列更厚的尾部(即 17.40 比 8.16 的过度峰度)。这又是在起作用的总体常态现象。
通过图表检验正态性的一个更好的方法是查看分位数-分位数图。在 qq 图中,历史收益的分布是相对于理论正态分布绘制的。如果历史收益完全沿着理论线,那么收益可以说是正态分布的。与理论线的偏差表示样本分布偏离正态分布的程度。

标准化收益 Q-Q 图
标准化日收益率和月收益率序列具有可比性,均值为零,标准差为 1。以上是标准化日收益率(左)和日历月收益率(右)的 qq 图,它们突出了股票市场收益率分布相对于红线代表的正态分布的厚尾。同样需要注意的是,与每日数据相比,月度回报数据与正态性的偏差明显较小。

标准化收益箱线图
最后,让我们比较一下标准化日收益和月收益的箱线图。左边的方框图是日收益率,右边是月收益率。我们马上注意到日收益率序列比月收益率序列有更多的异常值。与标准化月度数据相比,标准化日序列也有更多极端异常值。这证实了上述其他图表中的一些观察结果,其中最重要的一点是,日序列和日历月序列之间的收益率分布是不同的。
因此,我们可以得出这样的结论:日序列、月序列的股票市场收益都是非正态分布。特别是,历史收益率的分布比正态分布有更厚的尾部和更多的极值。还有一个左偏,特别是在每日序列中显示更多的负异常值。此外,回报率的分布在不同的时间尺度上有所不同。然而,月度数据似乎更接近理想的正态分布。
非线性自相关
我将尝试通过模拟历史回报数据来量化长期提款风险。然而,对历史数据进行概率解释需要我们处理一系列随机变量。统计随机性反过来要求样本由独立且同分布的** (IID)数据点组成。**
****独立性假设意味着从样本中提取的数据点的值不应与该样本中的另一个数据点相关联或受其影响。在时间序列数据中检查这一点的一种方法是寻找数据点之间的自相关或序列相关。当时间序列数据点与其滞后的对应数据点表现出某种相关性或相似性时,就会出现自相关。

每日线性 ACF & PACF 图表,1928–2019
以上是日收益率系列的自相关(ACF)和偏自相关(PACF)图。正如可以观察到的,并且证实了本文开始时讨论的折线图的直觉,每日回报似乎是(弱)平稳的,几乎没有或没有自相关。

日历月线性 ACF & PACF 图表,1928–2019
上述日历月收益系列的 ACF 和 PACF 也是如此。基于这些图表,我们可以假设收益序列中很少或没有线性自相关。
也就是说,让我们回顾一下我们之前看到的波动聚集现象。聚类现象表明,尽管每日或每月回报的线性自相关可能不成问题,但非线性自相关仍然是一种可能性。为了检查这一点,我们需要检查绝对回报或平方回报时间序列数据。

每日非线性 ACF & PACF 图表,1928–2019
上面日均收益的 ACF 和 PACF 图证明了持续非线性自相关的存在。基本上,巨大的绝对价格变化往往会伴随着巨大的变化,无论是上涨还是下跌,而相对而言,温和的价格波动往往也会持续下去。

历月非线性 ACF & PACF 图表,1928–2019
上面的日历月平方收益序列的等效图表显示,与日序列相比,非线性自相关性较弱且不持久。换句话说,如果一个人必须假设数据点是 IID,那么使用月度回报数据比每日数据更可取。IID 假设与正态性是分开的,但它再次表明,从统计角度来看,月度股市回报比日回报“表现更好”。
月度回报模拟
我们现在转向模拟未来股票市场回报,通过随机抽样和替换**利用历史回报数据。下面的第一个函数从历史数据中抽取大小为“ period_fwd ”的随机样本。该函数嵌套在第二个运行采样“ n_iterations ”次的函数中,以生成模拟 period_fwd 返回的 n_iterations 数组。**

嵌套模拟功能
第一组 10,000 个 21 天的模拟使用 1928 年至 2019 年的每日回报数据,而第二组则从更近的 1990 年至 2019 年期间的有限样本中抽取。根据上面的代码,它将是 period_fwd =21 和n _ interactions= 10000。然后,将模拟的每日回报汇总,得出模拟的每月回报。

具体来说,通过取 21 个模拟日收益率的百分比变化的累积积,并对模拟收益率的所有 n 个数组进行累加来完成。产生的输出是从模拟的 21 个每日回报构建的两个月回报分布,它们的一些统计如下所示。

基于历史日收益率的模拟月收益率分布,1928–2019

基于历史日收益率的模拟月收益率分布,1990–2019
更近的 1990-2019 年数据似乎显示,与从更广泛的 1928-2019 年时间序列中得出的模拟回报率相比,平均月回报率略高(0.61%比 0.54%),分布中的极端负值较少。
然后,我们使用 1928–2019 日历月返回数据运行另一个模拟。在这种情况下,我们只需要向前模拟一个周期,因为它已经基于月观测值,并且这样做5000 次。整个时期只有一千多个不同的月份,所以我不想做过多的随机抽样。基于历史日历月数据的模拟月度回报的结果分布的类似统计数据如下所示。

基于历史月收益率的模拟月收益率分布,1928–2019
所有三个模拟都产生了相似的均值估计值。事实上,每日历史数据(1928 年至 2019 年)和月度数据的月平均收益率几乎相同(0.54%比 0.57%)。甚至模拟的第五百分位观察值在三个分布中也是相似的,大约为-8%。这意味着平均每 20 个月就有一个可能出现至少 8%的下降。****
然而,当我们沿着采样分布的左尾继续深入时,会有明显的差异。第百分位数(或 100 个月中的 1 个月)和第 0.1 百分位数观察值(或 1000 个月中的 1 个月)在模拟的累计日回报率和模拟的日历月回报率之间存在显著差异。
使用历史月度数据进行的模拟显示,在这些左尾分布的极端情况下,预期提款要高得多。基于从 2019 年的历史月度数据中提取的抽样分布,在一个月的时间内有 0.1%的概率出现 ~30%或更多的下降。从概率的角度来看,这相当于一个人一生中溺水的几率,远远高于窒息的几率。这是一个非常低的概率,但不是一个可以忽略的。否则,救生员就会失业。
相比之下,基于历史每日数据的合计月度回报产生了明显较低的提款风险估计。从更近的 1990 年至 2019 年数据集汇总的采样分布中的最低月回报率仅为-19.8%,这意味着它完全没有预见到相当于 2020 年 2 月至 3 月崩盘的长期抛售。
因此,对每日回报统计数据的天真使用可能会导致对股票市场下跌风险的严重低估,如果将样本限制为过去 30 年的数据,这种错误将会加剧。
季度回报模拟
在我们结束之前,让我们快速看一下模拟季度回报,同样使用汇总的模拟历史日回报(超过 63 天)和历史日历季度回报。两个模拟都使用了完整的 1928-2019 年时间序列。
于是又进行了 10000 组日收益模拟,这次用 period_fwd =63。历史季度回报依次被抽样 2000 次。请注意,采样周期中的不同季度少于 400 个。下面是从这两个练习中选择的统计数据。

基于历史日收益率的模拟季度收益率分布,1928–2019

基于 1928–2019 年历史季度收益的模拟季度收益分布
模拟的平均季度回报率是相似的(1.88%对 2.16%),但随着我们向极端移动,左尾百分位数再次急剧偏离。基于历史每日数据的合计季度回报产生了明显较低的提款预期,强调了上述月度模拟的结果。
结论
金融市场是可量化数据的源泉,但数据生成过程仍是一个谜。在一个由恐惧和贪婪的相互作用所主导的舞台上,股票价格的波动源于人类不断互动的净效应。在艾萨克·牛顿(Isaac Newton)在南海泡沫中损失一大笔财富后,他发表了一句著名的评论,称自己可以“计算天体的运动,但无法计算人类的疯狂。”
在这篇文章中,我使用 SPX 从 1928 年到 2019 年的回报数据,强调了金融市场统计中一些众所周知的陷阱。股票市场的回报不是正态分布的,尾部的可变性要大得多。不同时间尺度的收益分布也不一样(聚合正态性)。此外,由于波动聚集,收益表现出非线性自相关,并且在日收益中比月序列中表现得更为明显。
与使用历史每日回报数据相比,1928 年至 2019 年的月度历史数据可能会提供更高的类似于 2020 年 2 月至 3 月崩盘的可能性。1990 年至 2019 年期间更近的每日数据完全无法预见这种可能性。因此,对每日回报数据的天真使用会导致对股票市场极度缩水的风险的严重低估。
(这个练习的完整 Python 代码可以在我的 GitHub 页面上找到。)
如果你看到了阅读这些文章的价值,你可以在这里订阅 Medium来阅读我和无数其他作家的其他文章。谢谢你。****
用贝叶斯概率模型测试均值-方差优化
towardsdatascience.com](/portfolio-diversification-with-emerging-market-bonds-ef1ec966531a) [## 面向金融的顶级 Python 黑客
用比特币时间序列数据
medium.datadriveninvestor.com](https://medium.datadriveninvestor.com/top-python-hacks-for-finance-f9ea900a686c) [## 揭开股票价格背后的潜在因素
美国大盘股的动态因素模型
medium.datadriveninvestor.com](https://medium.datadriveninvestor.com/uncovering-the-hidden-factors-driving-stock-prices-2891a1b99024)***
模拟 2020 年 NFL 赛季 10 万次
通过跟踪每个模拟宇宙为每个球队产生给定结果的频率,预测整个 2020 年 NFL 赛季的结果

照片由于是吊杆从的 Unsplash
这是官方的!周四晚上,NFL 回归,卫冕冠军堪萨斯城酋长队迎战休斯顿德克萨斯队。这是一个赛季的开始,鉴于今年的表现,许多人认为我们不会看到这个赛季。然而,足球又回来了,我们将尝试模拟和预测整个 2020 年 NFL 赛季的结果。
Elo 模型
如果你熟悉国际象棋中玩家的排名,那么你就熟悉 Elo 评级。Elo rating 是一个简单的系统,根据人头结果来判断球队或球员,是我们用来模拟 2020 赛季 NFL 比赛的模型。这些 Elo 评级能够预测每场比赛的结果,并生成每支球队的获胜概率。
Elo 模型的工作原理是,它为每个团队分配一个权力等级。这些评级用于根据两个团队的 Elo 评级之间的差异生成获胜概率。球队通过赢得比赛来增加他们的 Elo 等级,通过输掉比赛来减少,但是增加多少取决于比赛的预期结果。
例如,让我们取两个团队,给他们每个人一个 Elo 评级。让我们说达拉斯牛仔队对纽约巨人队。达拉斯牛仔队的 Elo 评分为 1650,纽约巨人队的评分为 1400。由于达拉斯的收视率更高,我们知道他们比纽约赢得了更多的比赛,应该在这场比赛中受到青睐。事实上,我可以告诉你,Elo 模型给了他们 80%的胜算。

达拉斯牛仔队主场迎战纽约巨人队,2019 赛季第一周。由拍摄的照片
由于达拉斯有望以较大优势获胜,如果他们真的获胜,他们的 Elo 评分只会增加约 5 分。然而,如果纽约赢了,他们的 Elo 评分将增加约 17 个点。Elo 考虑到了对手的水平,对失败者奖励更多,对受欢迎者奖励更少。这是为了确保 Elo 评级高的团队能够战胜实力相当的团队,而不仅仅是低于平均水平的团队。
如果你想了解更多关于 Elo 模型的细节,请查看我的另一篇文章,在这篇文章中,我实际上改进了这个由 FiveThirtyEight 团队开发的模型。
深入研究 NFL 的统计数据,以改进一个有潜力与拉斯维加斯竞争的著名模型
medium.com](https://medium.com/the-sports-scientist/improving-a-famous-nfl-prediction-model-1295a7022859)
季节模拟
有了 Elo 评级,很容易判断任何给定团队的实力并预测赢家。Elo 模型还进行了调整,通过处理直接游戏内外的情况,帮助这些预测变得更加准确。这些特定情况可能包括:一支球队是在主场还是客场比赛,他们是不是一周一次,他们走了多远,或者首发四分卫有变化。由于 2020 赛季的时间表已经出来了,我们有了所有我们需要的信息来预测整个赛季将会发生什么。
NFL 赛季并不总是确定的,通常应该击败其他球队的球队有时会输。这意味着 NFL 赛季存在随机性。为了将这种随机性整合到 Elo 模型中,我们使用蒙特卡罗方法模拟 2020 年 NFL 赛季 10 万次,跟踪每个模拟宇宙为每个球队产生给定结果的频率。
最后,模拟将显示一支球队的预期 Elo 评级、积分差异、整个赛季的记录以及赢得分区冠军、进入季后赛、获得第一轮比赛甚至赢得超级碗的几率。
在下面找到你最喜欢的球队,看看 Elo 模型预测你的球队下赛季会发生什么。


评论一下,让我知道!
在你最喜欢的球队下面发表评论,让我知道你是否认为 Elo 模型正确地实现了你的球队预期的 2020 年记录。
模拟 Web 事件
有时我们想要生成假事件来测试我们的管道和仪表板。随机事件做不了这个工作。这就是我构建这个 Python 包的原因。
您希望在工作场所实施新的流式管道,并需要向您的经理展示概念证明。此 POC 应允许您演示一些功能,在这种情况下,生成实时指标。但是,有一个限制:您不能在 POC 上使用生产数据。你如何解决这个问题?
如果你的答案是制造假事件,那么你是对的。这可能是最好的解决方案。然后,您创建一些随机事件,并将其推送到管道。你很快就会意识到随机和假不一样。你肯定不想给你的经理看这样的图表:

随着时间的推移产生的随机事件的网页浏览量。它们只是随机的。作者图表。
随机事件没有意义;他们不卖任何东西。让我们来了解一下在随机事件基础上创建的另一个指标:

随机浏览量没有任何意义。没有人指望一个网站在付费页面的访问量会超过首页。作者图表。
现在,让我们说,你想建立一个分析工程师职位的投资组合。你可能需要表明,你有能力创建网络会话,衡量转化率和分裂活动或来源的指标。如果没有数据,你怎么建立你那该死的投资组合?同样,生成随机数据不会让你测量任何东西。
创建半随机事件
考虑到这些问题,我决定创建一个 python 包来生成不完全随机的假事件。它们遵循一套约束,允许你用看起来像真的假数据创造美丽的东西。再次查看一段时间内的页面浏览量图表:

虚假网络事件。现在,随着时间的推移,我们有了更真实的页面浏览量。作者图表。
如果我们看看页面浏览量漏斗,我们会看到更多的主页访问,而付费和确认的访问要少得多,对吗?让我们看看这是不是真的。

虚假网络事件。有道理的漏斗!作者图表。
如何自己创建假的 web 事件?
很简单!PyPI 上有包,GitHub 上有源代码。要安装你做 pip 安装,就像你对任何其他软件包做的那样:
pip install fake_web_events
使用起来也很简单。请参见下面将事件打印到 stdout 的示例。
from fake_web_events import Simulationsimulation = Simulation(user_pool_size=100, sessions_per_day=10000)
events = simulation.run(duration_seconds=10)for event in events:
print(event)
你可以在循环里做任何你想做的事情。发给卡夫卡或者 Kinesis。用 Spark 流处理它,并创建一些指标。保存到 Postgres 并使用元数据库构建一些仪表板。炫耀你的投资组合的 SQL 技能。或者让 POC 获得批准。
由此包创建的事件将如下所示:
{
"event_timestamp": "2020-07-05 14:32:45.407110",
"event_type": "pageview",
"page_url": "http://www.dummywebsite.com/home",
"page_url_path": "/home",
"referer_url": "www.instagram.com",
"referer_url_scheme": "http",
"referer_url_port": "80",
"referer_medium": "internal",
"utm_medium": "organic",
"utm_source": "instagram",
"utm_content": "ad_2",
"utm_campaign": "campaign_2",
"click_id": "b6b1a8ad-88ca-4fc7-b269-6c9efbbdad55",
"geo_latitude": "41.75338",
"geo_longitude": "-86.11084",
"geo_country": "US",
"geo_timezone": "America/Indiana/Indianapolis",
"geo_region_name": "Granger",
"ip_address": "209.139.207.244",
"browser_name": "Firefox",
"browser_user_agent": "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_5; rv:1.9.6.20) Gecko/2012-06-06 09:24:19 Firefox/3.6.20",
"browser_language": "tn_ZA",
"os": "Android 2.0.1",
"os_name": "Android",
"os_timezone": "America/Indiana/Indianapolis",
"device_type": "Mobile",
"device_is_mobile": true,
"user_custom_id": "vsnyder@hotmail.com",
"user_domain_id": "3d648067-9088-4d7e-ad32-45d009e8246a"
}
假的网络事件正在使用 Faker 来创建一些数据;其他字段是根据预定义的权重(可以在 YAML 文件中自定义)随机生成的。
幕后的虚假网络事件
我假设您可能有兴趣了解这些事件是如何创建的,以及其背后的逻辑是什么。我可以直截了当的告诉你,不是外星科技:)。
虚假网络事件不是外星技术。Gif 信用 u/Huesh 在 Reddit 上。
用户
我们首先创建一个用户池。一些字段完全是随机的(来自 Faker),其他字段遵循一组预定义的权重。例如,用户将获得使用以下权重分配的浏览器:
browsers:
Chrome: 0.5
Firefox: 0.25
InternetExplorer: 0.05
Safari: 0.1
Opera: 0.1
这意味着大约 50%的用户将使用 Chrome,25%的用户将使用 Firefox。
用户与事件具有本质上相同的 JSON 结构,除了它不包含时间戳或页面信息。当我们运行模拟时,将从池中随机挑选用户开始“浏览网站”。用户以后可能会回到这个网站,这就是为什么他们选择了重新定位。
事件
为了创建事件,我们模拟会话。在模拟中创建了一些“页面”。用户将从主页、产品 A 或产品 B 页面开始。在每次迭代中,用户可以停留在同一个页面,移动到另一个页面,或者结束会话。以下是当前在家的用户的概率:
home:
home: 0.45
product_a: 0.17
product_b: 0.12
session_end: 0.26
该模拟跟踪所有用户,并在每次到达新页面时生成一个事件。一旦用户到达会话末尾,他的会话就会被丢弃。遵循模拟过程中可能的用户事件图表:

虚假 web 事件模拟的站点地图。绿页是用户在会话开始时可以进入的页面。黄页只对已经在浏览的用户开放。作者配图。
模拟
模拟将分批运行,其内部时钟通常会比标准时间快得多。例外情况是,如果您正在使用非常大的user _ pool _ size 和 sessions_per_day 运行它。
模拟将创建一个发电机对象。它不会运行或使用资源,直到你开始迭代它。
接下来是什么?
我确实对这个项目下一步做什么有一些想法。有些是简单的错误修复,或者是对如何生成和跟踪事件的改进实现。但是有一个广泛的想法我想深入探讨:
在 web 事件之上产生微服务事件。
我的想法是向模拟中添加另一个模块,该模块将基于微服务架构创建不同的事件。我能想到这样的事件:
- 用户 _ 创建的
- 订单 _ 已创建
- 付款 _ 已完成
- 支付 _ 失败
- 订单 _ 已发送
- 订单 _ 完成
微服务事件将有助于创建绑定到 web 事件的假事务数据库。我认为这对很多人来说是有用的,因为它允许更多的用例。
如果你喜欢这个项目,请在 GitHub 上主演来表达你的爱。
每个人也可以贡献:创建一些问题、特性请求,甚至是拉式请求,如果你对接触代码感到舒服的话!
SimPy 中的模拟结构和建模
思考、创造和模拟—一切尽在 SimPy
Python 以其简单的语法和众多的库而闻名,这使得这种语言几乎可以做任何事情。Python 的操作范围从开发 web 和桌面应用程序等中等简单的任务到构建机器学习和人工智能项目等复杂任务不等。

肖恩·林在 Unsplash 上的照片
我们随处可见系统,从数字闹钟中的嵌入式系统到像机场和火车站这样的大型系统。为了高效和最佳地运行这些系统,我们需要模拟,因为它们为我们提供了可依赖的读数。参与环境和随机性是系统和模拟的两个关键因素。本文将关注 python 库的这些功能,这样我们就可以根据我们的需求模拟一个场景。为了实现这一目标并创建算法,我们将使用 Python 的以下两个内置库:
- 简单
- 随意
场景:为了遵循社交距离,作为站长,你必须设计一个计划,使站台上的人数最少,并让尽可能多的人呆在他们的车辆或候车室里(让我们假设这些房间有适当的措施来保证旅客的安全)。
计划:我们将从分配火车的到达和离开时间开始。应该设立一个售票亭,向登上下一趟到站列车的乘客分发站台票。
我们开始吧
我假设你已经安装了 Python,并且有基本的知识。如果你以前没有使用过 Python,你可能想看看这个教程。
我更喜欢在 shell 中运行程序。你也可以使用 Jupyter 笔记本。第一步是安装并导入所需的库。打开命令提示符,写下:
pip install SimPy
pip install random
成功安装后,使用导入功能导入库:
import SimPy
import random
在开始编写主要算法之前,有必要对您的模拟应该是什么样子有一个清晰的印象。这一步对于制作一个好的仿真模型是最重要的。在这一步,人们应该花最多的时间进行头脑风暴、构建和收集数据。从可靠的来源收集模拟中每个不确定时刻的统计数据非常重要。如果这受到损害,一个或多个事件的发生频率会增加或减少。这可能导致生成错误的值。根据我们的计划,模拟必须以下列方式运行:
- 乘客到达火车站,走向站台售票柜台。如果他登上了下一趟到站的火车,他会得到一张站台票。
—否则,请他在休息室等候。
2。列车到达站台,乘客上车,10 分钟后发车。火车也有可能晚点几分钟。
3。在候机室等候的乘客前往售票柜台,符合条件的乘客前往站台。同时,更多的乘客到达车站。这样,我们可以最大限度地减少站台上的乘客数量。
编码程序
我们将从定义主类开始,该类将包含模拟蓝图和在火车站执行的程序。这个类将包含一些生成所需环境的函数。该班命名为站。
class Station(object):
def __init__(self, env, num_worker):
self.env = env
self.worker = simpy.Resource(env, num_worker)
在这段代码中,init()是 python 类中的一个保留方法。当从类创建对象时,会调用它。这个方法允许我们定义一个类的属性。我们继续创建一些对我们的模拟至关重要的简单资源。变量“env”是预定义的,它帮助我们生成一个用于模拟的虚拟环境。现在这样想,有一些资源是车站提供给乘客的。在这种情况下,是售票柜台的工作人员。工人数量将由变量 num_worker 表示。
在继续之前,我们需要了解 SimPy 和 Random 库的更多功能。第一个是:
random.randint(a,b)
这个函数帮助我们在两个整数 a 和 b 之间生成一个随机整数(两者都包括在内)。这将帮助我们模拟过程中的随机事件。通过为事件指定触发条件,可以将它与条件语句一起使用。
p = random.randint(1,8)
if p == 3 :
print('Event Triggered') #Probability = 0.125
第二个功能是:
yield self.env.timeout(a)
这用于在一分钟的持续时间内运行一个进程(本例中为 env )。我们可以进一步使用 randint 函数来运行环境,运行在 a 和 b 之间的任意时间整数值。
yield self.env.timeout(random.randint(a,b))
现在,您已经准备好编写将对乘客进行分类并据此出售站台票的函数了。它还将生成列车时刻表,延迟列车(如果需要),并打印站台和休息室的乘客人数。该任务将通过使用上述函数以及条件语句和循环来完成。SimPy 将帮助生成和运行环境。
第一步是定义函数及其参数。之后,所有控制列车到达、离开(到达 10 分钟后)和延迟的必要变量将被声明。
def ticket(self, passenger):
sch_train = random.randint(0,45)
dep_train = sch_train + 10
print('Next train arriving after',sch_train,'minutes')
注:函数车票以自身和乘客为属性。乘客属性将在运行站功能中定义。
接下来的任务是设定一个条件,让火车晚点。在这种情况下,火车将在 0 点至 10 点之间延迟。
del_ = random.randint(0,10)
del_f = del_%2
if del_f == 0:
del_t = random.randint(5,20)
print('Train is delayed by',del_t,'minutes')
sch_train = sch_train + del_t
dep_train = sch_train + 10
print('Train will arrive after',sch_train,'minutes\n')
else:
print('No delay\n')
变量 del_ 生成所需的案例,而 del_f 是这些案例值除以 2 后的余数。要成为偶数, del_f 的值必须为零。当它等于零时,火车被延迟 del_t 分钟,这也是 5 到 20 分钟之间的随机时间量。因此,到达和离开时间的价值增加了。如果当前时间与延迟到达时间(宣布延迟后的新到达时间)之差小于 10,则不会生成站台票(这将在下一步中进行编码)。
num_pass = 0
for i in range(passenger):
time = random.randint(5,60) #time after which passenger's train is scheduled
if time<=dep_train:
yield self.env.timeout(random.randint(1,3))
print('Platform ticket generated')
num_pass +=1
else:
print('Cannot generate platform ticket')
print('\nPassengers on platorm:', num_pass)
p = passenger - num_pass
print('Passengers in waiting lounge:', p,'\n')
最初, num_pass (站台乘客数)等于 0。变量 time 以分钟为单位存储时间的随机值,在此之后列车被调度。有条件的“如果”语句检查乘客是否有资格购买站台票。工人完成这一过程的时间在 1 到 3 分钟之间。随后,生成站台票, num_pass 加 1,并打印 num_pass 的值。
票证生成过程完成。现在我们将编写一个函数来安排乘客到达车站的时间。
def station_arrival(env, passenger, station):
arrival_time = env.now
with station.worker.request() as req:
yield req
yield env.process(station.ticket(passenger))
注意:这个函数调用主类中的另一个函数。这给出了一个提示,它将在某个地方被再次调用作为替代,以避免一次调用太多的函数。
变量 arrival_time 存储由 env.now 命令生成的环境的当前时间值。下一行请求主类(工作站)让模拟使用它的资源( num_worker )。该请求的最后一行将触发主类中定义的车票生成功能(env . process(station . ticket(passenger))。我们需要的最后一件事是一个函数,它按顺序调用所有其他函数,并在“for”循环中为乘客变量生成值,因为它是上面定义的两个函数的属性。
def run_station(env, num_worker):
station = Station(env, num_worker)
a = 5
for passenger in range(20,40):
env.process(station_arrival(env, passenger, station))while a > 0:
yield env.timeout(0.7)
passenger += 1
env.process(station_arrival(env, passenger, station))
在“for”循环中调用 station_arrival 函数,该循环向环境请求资源,然后在条件满足后启动票据生成过程。最后,一个“while”循环执行整个过程,并在每一步增加乘客。为了运行模拟,我们只需要调用 run_station 函数。
这样,模拟结构就可以在 main 函数中执行了,该函数会将 env 变量指定为一个简单环境,并定义模拟时间( env.run(until=200) )。
def main():
random.seed(30)
n = input('Enter no. of workers: ')
num_worker = int(n)
env = simpy.Environment()
env.process(run_station(env, num_worker))
env.run(until=200)if __name__ == "__main__":
main()
模拟的有效性取决于程序的结构和概率决定因素的准确性。这需要大量的头脑风暴。在这种情况下,使用 randint 生成的所有数字给出了一个粗略的估计。我们可以根据对同一主题进行的研究/调查来准确地构建它们,然后确定某个事件的正确概率。这个领域很有潜力成为一个研究课题。
如需更多帮助,从GitHub下载源代码。
输出

一个模拟周期(图片由作者提供)
结论
这是一个在平台上维持社交距离的自制场景。为该问题提供的解决方案可能不是最好的,但设计这种情况的主要动机是描述 SimPy 库的基本功能、模拟需求以及演示简单模拟案例背后的编码过程。

𝗔𝗹𝗲𝘅 𝘙𝘢𝘪𝘯𝘦𝘳 在 Unsplash 上的照片
借助于 SimPy 框架,我们可以了解很多关于构建程序和过程的知识。我们现在可以通过在一个环境中定义和调度各种功能来模拟各种系统及其子流程。这有助于我们理解日常生活过程中的随机性。现在我们对系统以及基本概率如何控制模拟的复杂性和准确性有了清晰的理解。
模拟范围
这些模拟可以通过计算成本和其他因素来帮助个人做出各种决定。如果结构正确,模拟是生成有用和准确数据的有效方法。此外,它们还可以在数据分析的帮助下用于数据预测。
具有策略梯度的同步连续/离散超参数调整
我们演示了一种使用策略梯度同时调整机器学习模型的离散和连续超参数的有效方法。

菲尔道斯·罗斯兰在 Unsplash 拍摄的照片
概观
在我的上一篇文章中,我展示了如何用 Python 从零开始构建策略梯度,我们用它来调整机器学习模型的离散超参数。(如果你还没有读过,我建议你从那里开始。)现在,我们将在这一进展的基础上,扩展策略梯度以优化连续参数。到本文结束时,我们将有一个同时调优离散和连续超参数的成熟方法。
政策梯度审查
从上次的中,回想一下策略梯度优化了以下用于调整超参数的成本函数:

其中 a 是为特定实验选择的一组超参数,而θ代表我们的 PG 模型的所有可训练参数。然后, p 表示选择动作 a 的概率, r 是该动作获得的“奖励”。我们随后表明:

上面的等式告诉我们,给定一组动作和他们观察到的奖励,如何更新我们的 PG 模型。对于离散超参数,我们直接更新了每个可能动作的相对对数概率( logits ):
这种方法不适用于连续超参数,因为我们不可能存储每个可能结果的对数概率!我们需要一种新的方法来生成连续的随机变量及其相对对数概率。
扩展到连续超参数
在强化学习领域,连续变量通常使用高斯过程建模。这个想法非常简单:我们的模型预测高斯分布的均值和标准差,我们使用随机数生成器收集动作/预测。
同样,我们选择了最简单的模型——只存储每个参数的平均值和对数标准偏差。为了理解上面self.mu和self.log_sigma的更新规则,让我们计算一些梯度。高斯分布的概率密度函数为:

或者换句话说,用对数标准偏差来表示:

要获得对数概率,只需取自然对数,

我们使用以下数学恒等式来帮助简化表达式:

在所有这些工作之后,从这里计算梯度并不太困难。对 mu 和 log-sigma 求偏导数(或者只用 WolframAlpha ),我们发现:

这解释了如何在GaussianActor中更新参数…几乎如此。尽管有很好的数学计算,我们的公式还是有一个实际问题:与标准偏差相比,我们的平均值变化非常缓慢。本质上,这是因为self.log_sigma在对数空间中,并且对self.log_sigma的更新导致标准差的指数级更大变化。我们可以手动增加self.mu的学习率,鼓励它跟上。在实践中,乘以 1000 往往效果很好。
在我看来,这是一个丑陋的创可贴,而不是一个优雅的解决方案。但是真的有用。我不建议对大多数策略梯度应用使用这种方法,因为它会降低我们模型在训练过程中的稳定性。在我们的例子中,效率比稳定性重要得多,因为我们受限于固定数量的实验。与大多数应用程序不同,我们不会在任何事情上重复使用训练好的模型——我们只是用它来估计超参数,然后完全丢弃该模型。
玩具问题:连续超参数
让我们应用我们所学的。我们可以建立一组超参数、基础真值和目标函数。这次,我们将使用均方误差作为目标,而不是平均绝对误差。目标函数的选择并不重要,任何明智的选择都应该可行。不过,有些选择比其他选择更有效。MSE 和 MAE 通常是相当安全的选择。根据经验,均方差给出了这些实验的最佳结果。
注意,我们向每个参数字典添加了“type”键。稍后,当我们引入离散超参数时,这将证明是有帮助的。让我们还设置一个函数来为每个参数类型创建参与者。
最后,我们可以展示完整的策略梯度代码。考虑到连续的参数,只需要很小的改变。
为了衡量我们算法的性能,让我们运行 1000 个左右的独特实验,并观察我们的预测有多准确。同样,我们将使用 250 的预算——这是新的超参数可以被评估的最大次数。这将允许与我们之前仅针对离散超参数的实现进行比较。
Average MAE: 2.155
这与随机搜索相比如何?为了达到相同的 MAE,您需要在每个基础真值的 4.31 范围内进行猜测。随机选择这样一组参数的概率大致为 0.0862 = 6.41E-4 。平均而言,在匹配政策梯度的准确性之前,需要进行 1561 次随机实验!在这种情况下,PG 大概比随机搜索高效 6.25x 。这比我们看到的离散参数( > 10x )的效率要低,但仍然相当可观。
另一个玩具问题:混合超参数
在这一点上,我们已经确认了策略梯度分别用于调整连续和离散超参数。让我们把这些放在一起,看看同步参数调谐是如何工作的。不需要额外的更改,只需更新超参数并重新运行实验。我们还将把预算增加到 1000,因为我们正在优化一组更大的参数。
*Average MAE: 2.088*
暂停片刻,体会这个结果的意义。仅使用 1000 个实验,策略梯度在 6 个单独的超参数之间仅实现了 2.1% 的平均误差。大概有一个 0.0835⁶ = 3.39E-7 的概率来随机抽取一组相似的参数,这意味着 PG 现在比随机搜索几乎要高效3000 倍!
随着搜索空间的扩大,使用策略梯度的好处会急剧增加。这是因为我们正在同时(不是顺序)调整我们的超参数。如果我们简单地先调整离散参数,然后调整连续参数,PG 会比随机搜索高效 60 倍。(只需将离散搜索和连续搜索的相对效率相乘。)相反,我们能够在预算中使用每个实验的来同时优化所有超参数,效率飙升。**
外卖食品
我一直对政策梯度的力量和灵活性感到惊讶。在数百行 Python 代码中,我们为离散和连续超参数创建了一个高效的、可用于生产的优化器。它与任何机器学习算法(神经网络、决策树、k-最近邻等)一样好用。),因为优化不需要外部渐变。如果您需要更快的性能,还可以使用内置的 Python 模块(如multiprocessing或concurrent.futures)来并行化每一批实验。为了简单起见,我避免在这里这样做。
在这个演示之后,我希望你和我一样迷恋政策梯度。要了解更多关于 PG 的信息,我强烈推荐 OpenAI Spinning Up ,它包含了大量的背景材料、研究论文和与强化学习相关的开源软件。
SinGAN:从单个图像训练 GAN。
生成网络解释
没有足够的数据来训练你的生成网络?辛甘是来帮忙的。
介绍
GANs 是一种生成网络,可以从潜在向量(“或分布”)中生成逼真的图像。通常,GAN 由两个网络组成:生成器(G ),其目的是将潜在代码映射到图像;鉴别器(D ),其任务是评估图像是来自原始数据集(真实图像)还是由其他网络生成(虚假图像)。与鉴别器对抗,生成器试图愚弄它,从潜在向量生成新图像,因此鉴别器认为它们是真实图像。
而 SinGAN 是 GAN 的变体,其中网络必须从单个自然图像中学习,这与以前版本的 GAN 形成对比,因为它们有多个真实图像来学习表示。SinGAN 是一个无条件的生成模型,它可以学习单个图像中面片的内部统计信息。正如本文的结果部分所示,SinGAN 在各种图像处理任务上显示了令人印象深刻的结果。
体系结构
SinGAN 架构由多尺度流水线组成,其中存在一对生成器和鉴别器,学习不同尺度的表示。它们可以以由粗到细的方式进行训练,其中最低尺度的生成器和鉴别器学习背景和材料等粗糙特征,而在高尺度下,它们学习边缘和拐角等非常精细的细节。

新加坡建筑
源图像被缩减采样到相应的大小,并与发生器的输出一起输入鉴别器。并且随机噪声连同从它们下面的发生器生成的图像一起被馈送到发生器(除了最后一个,它仅被馈送随机噪声)。
因为我们只处理一个源图像,所以我们将来自下采样源图像的一组补片视为我们的真实图像数据集。“您可以将 patch 视为一个滑动窗口,它悬停在图像上方并收集样本”。通常,所有大小的补丁区域保持不变,但是对于更高的网络,随着图像变得越来越大,有效的补丁大小会减小。
如果我们仔细观察发生器,随机噪声向量与从下面生成的图像(向上采样为噪声形状)连接在一起,并馈入 5 个后续卷积层,卷积层的输出再次与从下面生成的图像连接。这将输出一个新的图像,与真实图像(下采样)一起进一步发送到鉴别器进行评估。

辛甘的典型发电机
辛甘的典型发电机,每个区块:
噪点+g _ image->5x(conv)+g _ image->输出。
其中 g_image 是从先前的生成器生成的图像,Conv 是conv(3x 3)->batch norm->LeakyReLU。
对于鉴别器,生成的图像和源图像(下采样)被馈送用于评估。鉴别器由五个卷积层组成,与发生器一样,但没有级联。
训练和损失函数
网络按顺序训练,从最低级别开始,上升到最高级别。首先训练最小尺寸的发生器和鉴别器得到粗特征,然后训练下一个尺寸的网络,依此类推。一旦每个 GAN 被训练,它就保持固定,并且所有子网 GAN 以传统(对抗)方式被训练。
训练包括两个损失函数的组合。
- 对抗性损失:对抗性损失用于惩罚网络,通过计算真实数据分布与生成器预测数据分布之间的距离,使预测样本分布与原始样本分布相匹配。最初的实现使用 WGAN-GP 丢失,他们发现这可以增加稳定性。这个损失在这里得到了很好的解释。
- 重构损失:顾名思义,重构损失是用来惩罚网络生成看起来像原始样本的样本。这种损失很重要,因为噪声矢量被输入发电机。最初的实现使用 RMSE(均方根误差)损失。
结果
如下图所示,第一列作为网络的输入,所有后续图像都是网络的输出。所有生成的样本都具有相同的高层次特征,如第一行是山脉、湖泊和沙子,第二行是橙色背景、鸟类和树木。尽管仅使用一幅图像作为输入,但样本显示了非常精细的细节,并且所有样本彼此之间非常不同。

资料来源:https://github.com/tamarott/SinGAN/blob/master/imgs/teaser.巴布亚新几内亚
下图显示了一些图像处理任务的结果。第一列示出了风格转移,其中图像的属性可以被转移到视觉上不同但上下文相同的另一个图像,放大或缩小图像内的对象而不引起像素内的抖动,在背景前面添加对象,减少像素失真(超分辨率)等。

来源:https://github . com/Tamar ott/SinGAN/blob/master/imgs/manipulation。巴布亚新几内亚
结果表明,一个图像足以学习属性。所有的实验表明,SinGAN 确实是一个强大的生成网络,即使给定一幅图像作为输入,它也能够很好地进行泛化。
结论
这是对最近推出的 SinGAN 的快速而完整的介绍。我发现这个网络特别有趣,因为它能够仅使用一个源图像进行很好的归纳。如上所示,这个网络在各种图像相关的任务中表现良好,你可以看看 Github 上的实验。这个网络是用 PyTorch 实现的,可以在 GitHub 上进行实验。
参考
[1]https://github.com/tamarott/SinGAN
[2]https://arxiv.org/abs/1905.01164
新加坡的新冠肺炎曲线变平了

马丁·桑切斯在 Unsplash 上的照片
新加坡新冠肺炎局势的最新情况
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
随着新加坡大选的临近,大多数媒体的注意力都集中在不同的政党候选人、他们的演讲,甚至他们的性格上。
但我们不要忘记,我们仍然处于疫情的中心。
大约一个月前,我写了一篇关于新加坡的新冠肺炎曲线是否变平的文章。
新冠肺炎曲线真的变平了吗?大多数新闻图表只显示了部分情况。这里有一个更好的…
towardsdatascience.com](/is-the-covid-19-curve-flattening-in-singapore-857219f72f1)
从那以后,我一直在积极跟踪新加坡的每周进展,我可以有把握地说,根据数据…
新加坡的新冠肺炎曲线变平了!
我将保持这篇文章的简短,直接进入更新。
如果你想知道这篇《新冠肺炎邮报》的动机以及我从哪里得到的数据,我建议你读一下之前的帖子。
平坦的新冠肺炎曲线

平均每周新病例
上图描述了平均每周案例数和平均每周案例数的对数转换。
注:红线表示来自新加坡的病例。蓝线代表韩国,绿线代表日本。
为什么要对数变换?
简而言之,对数变换让我们能够更好地判断新冠肺炎曲线是否变平。
它向我们展示了与指数增长的背离。

偏离指数增长的例子
这个想法很简单。
每个国家的新冠肺炎局势都呈指数增长。
当且仅当我们看到明显偏离这条路径时,曲线才会变平。
就新加坡、韩国和日本而言。
我们实现了这种扁平化效果。
第一阶段的效果如何?
对于非新加坡读者来说,新加坡分三个阶段开放经济。第一阶段于 2020 年 6 月 19 日结束,我们目前处于第二阶段。
单从数据来看,第一阶段确实有助于抑制病毒的传播。
从《断路器》结束(2020 年 6 月 2 日)到第一阶段结束(2020 年 6 月 19 日),我们可以清楚地看到对指数增长的较大偏离。即平均每周病例的急剧下降
因此,看起来新加坡缓慢重新开放的计划确实是有效的。
为此向政府致敬!
警示故事

照片由 Goh Rhy Yan 在 Unsplash 上拍摄
截至 2020 年 7 月 1 日,新加坡似乎很好地处理了病毒的传播。
但是我们必须小心谨慎。
以韩日为例,它们显然处于疫情的第二波。很像现在的中国或新西兰。
新加坡承受不起再次陷入封锁。
作为公民,我们必须继续发挥我们的作用。
待在家里,在家工作,尽可能减少社交聚会,直到找到疫苗。
我相信世界即将找到疫苗,但在此之前,我们需要记住这种病毒传播很快。
走错一步,我们就要开始准备第二波了。
可怕的污点
我分别在韩国和日本的曲线中注意到了这一点。
在第二波袭击他们之前,他们的曲线上都有一个小小的污点。
我在新加坡曲线上也看到了这个污点。

曲线上可怕的斑点
这是什么意思?
基于 2 的样本量,曲线中的(我知道这很荒谬)斑点可能表明病毒开始再次传播的潜在信号。
也就是第二波迫在眉睫。
其他可视化
以下是我在这篇文章中跳过的其他可视化效果。

每日新病例

新加坡考试费率
结尾注释
虽然数据显示曲线已经变平,但我们不要放松警惕。
如果新加坡做出错误的举动,第二波病毒可能会出现。即过早地进入阶段 3。
在开放经济和遏制病毒传播之间需要有一个平衡。
没有一个国家是完美的。
但到目前为止,新加坡似乎走在了正确的道路上。也就是说,慢慢开放经济,同时控制病毒。
让我们都只希望疫苗很快出现,这样生活就能回到过去的样子。
这里有我的代码供你自己分析。
注意:对于我的非新加坡读者,您可以通过简单地在我的脚本中过滤到您自己国家的代码来跟踪您自己国家的进展。
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/timtan-github/COVID-19-Singapore)
就这样,我们在邮局见!😃
永别了!
LinkedIn 简介:蒂莫西·谭*
单细胞 RNA 测序:生物学家的 A/B 测试工具
用 scRNA-seq 和人工智能改造生物医学研究

信用:Pixabay.com
“我对遗传学是数字化的这个想法很感兴趣。基因是一长串编码字母,就像计算机信息一样。现代生物学正在成为信息技术的一个分支。”—理查德·道金斯
A/B 测试是科技行业的常见做法。每次构建新功能时,产品经理和数据科学家都会对其进行最终的性能测试——A/B 测试。由此产生的度量标准将告诉我们该特性是否符合提议的业务成果。第一步是找出要收集的数据。对于脸书和 Twitter 等平台,衡量标准包括在网站上停留的时间、点赞数、每日活跃用户(DAU)的增加、分享数等等。接下来,对用户群体进行细分以进行控制和测试来运行实验——群体的大小由功效分析决定。最后,收集数据。一旦有了足够的数据,现在就该对测试总体进行建模,进行参数估计,并执行统计显著性测试,以检查测试分布是否明显偏离控制。如果有意义,该特性将被添加到产品堆栈中。
在生物学中,整个过程正好相反。我们已经有了产品——一个有机体;因此,我们处理一组不同的问题。
产品是怎么做出来的?用什么标准来衡量一个特性的成功?为什么要合并冗余?是什么导致了模块化?问题很多。这些都是很难回答的问题,因为我们不能回到过去,我们能做的最好的事情就是基于现有数据的最大似然估计。
scRNA-seq 背后的大思想是什么?
scRNA-seq 是一种高通量测序技术,用于平行分析数十万个细胞的转录组(细胞中存在的总 RNA)。根据分子生物学的中心法则,基因表达是遗传信息从 DNA(基因)→RNA→蛋白质的单向流动。scRNA-seq 在 RNA 水平上捕获每个相关细胞的信息流。

鸣谢:维基百科
为了理解 scRNA-seq 背后的逻辑,让我们看看果蝇中的同源盒基因或 Hox 基因。术语同源盒来源于同源异形——意思是用一个身体部分替换另一个。

鸣谢:维基百科
在果蝇中,身体模式由同源基因复合体触角足和双胸控制。这些基因在幼虫特定区域的表达决定了成蝇的节段身份。
例如,Ultrabithorax—Ubx—基因阻止第三胸段(T3 —见上图)翅膀的形成;因此,翅膀被限制在苍蝇的 T2 部分。
在一个 ubx 突变体中,它缺少一个 ubx 基因的功能副本——T3 转化为 T2,给突变体苍蝇多了一对翅膀!点击阅读更多关于果蝇发育的有趣方面的内容。

鸣谢:维基百科
一般来说,细胞身份由该细胞中特定基因的表达决定,这可能在另一个细胞中不存在(皮肤细胞与神经元)。基因相互作用网络是复杂的非线性网络(相互作用组),其中一个特定基因的表达可能导致另一个基因完全停止表达,或者可能激活不同基因的表达,等等。基因的这种上下文相互作用决定了细胞的发育轨迹。

精神分裂症相互作用组——一个相互作用的基因网络。鸣谢:维基百科
在我们的 ubx 突变体中,我们可以将来自 ubx 突变体的 T3 片段的 RNA 与一只正常苍蝇的 T3 片段进行比较,以找出形成翅膀的因素。因为我们观察到的一种物理变化——额外的翅膀——必定有其基因表达的基础。通过计算从每个基因转录的 RNA 的拷贝数(就像我们在 A/B 测试设置中收集点击和页面访问一样),我们可以精确地测量特定突变带来的基因表达的细微差异——这项研究被称为差异基因表达分析。差异基因表达构成了 scRNA-seq 的基础。同样,癌细胞与正常对应物的比较可能会发现独特的药物靶点,否则不容易识别。
是怎么做到的?
在数据科学中,垃圾输入,垃圾输出 (GIGO)是一个众所周知的概念,如果您将有缺陷的数据输入到您的分析管道中,您得到的将是垃圾。处理这个问题的唯一方法是,首先,适当的随机实验设计并收集有意义的数据。
以下是 scRNA-seq 管道的步骤:
1)样品收集:收集组织样品进行分析。像周一所有肿瘤标本,周二所有正常标本这样批量采集标本是不明智的。这种做法将导致批量效应和混淆。随机化是这里的关键。让正常样本和肿瘤样本在同一天采集,由相同的人员和相同的方案进行适当的控制,以避免不必要的变化。
2)从组织中分离单细胞:这是最具挑战性的部分。组织是细胞的集合,非常脆弱,因此需要小心处理。
有关高通量方法的更多详情,请参见 郑。等人(2017) 论文。

单细胞 RNA 分离程序的时间推移。信用:dropseq.org
3)从单个细胞中提取 RNA。
4)将 RNA 转化为 DNA: DNA 测序对于确定 RNA 的基因组来源是必要的。因此,在测序之前,我们需要通过逆转录 PCR 将 RNA 转化为 DNA。RNA 是一种单链核酸分子,因此,高度不稳定的 RTPCR 将 RNA 转化为更稳定的 DNA,适用于下游测序实验。
4)DNA 测序
5)序列分析:
→质量控制:检查测序数据的质量(fastQC、multiQC、rse QC)
→接头修剪:移除测序接头(cutadapt、flex bar)
→与参考基因组的比对:确定序列的身份(最好使用 HISAT/HISAT2 等剪接感知映射器)。
→比对可视化:可视化比对文件(IGV)
→比对后 QC:检查比对后的序列质量(samtools,fast QC)
→制备计数矩阵:计数并记录测序分析检测到的独特 RNA 的数量。
一个优秀的教程可以在 这里 找到
6)数据分析
→基因质量控制&过滤。
→主成分分析、tSNE、UMAP 降维:RNAseq 数据是高维数据。在分析中尽早处理“维数灾难”是至关重要的。这也有助于消除协变基因。
→使用 DBSCAN、K-means 和 Louvain 算法进行聚类和社区检测

有什么影响?
当我还是研究生的时候,我们依靠 Northern 印迹来检测 RNA 表达。然后是微阵列、 qPCR ,接着是 RNAseq 。最新进入这一领域的是 scRNA-seq,它将改变生物医学研究。
例如,最近在旧金山举行的一场黑客马拉松使用对 RNAseq 数据的深度学习来识别一种罕见形式的肾癌特有的基因网络。这个想法是要找到一个基因调控网络,类似于一个名为 TSPG ( 转录组状态扰动发生器)的 GAN(生殖对抗网络)所做的预测,这样我们就可以重新利用现有的药物来治疗肾癌。使用更传统的临床试验方法来开发新的药物配方既昂贵又耗时,患者通常需要快速的临床干预(你可以在这里和阅读莱拉·贾纳的悲惨故事。因此,深度学习方法更有吸引力。
你可能还会读到发生在 2017 年的首届基因组学黑客马拉松,它解决了一个类似的问题。
我是 Aneesh,我热衷于将人工智能应用于生物医学研究。我希望这篇文章能提供信息。下次再聊!
Python 中的单引号、双引号和三引号

扬·阿莱格在 Unsplash 上的照片
有选择总是好的——单引号和双引号在 Python 中可以互换使用。
我们所有的 Python 程序员都知道,在 Python 中,与字符串声明相关的单引号和双引号的使用。然而,并不是所有人都知道三重引号的某些用法。
这篇简短的文章回顾了 Python 中单引号、双引号和三引号的用法。
单引号和双引号
基本用法
单引号和双引号最常见的用法是通过包含一系列字符来表示字符串。如下面的代码所示,我们分别使用单引号和双引号创建这两个字符串。
>>> quotes_single = 'a_string'
>>> quotes_double = "a_string"
>>> quotes_single == quotes_double
True
正如您所注意到的,使用单引号和双引号创建的字符串是相同的。换句话说,当我们声明一个字符串时,我们可以交替使用单引号和双引号。然而,应该注意的是,我们不想把它们混在一起,因为这是一个语法错误。
>>> "mixed quotes'
File "<stdin>", line 1
"mixed quotes'
^
SyntaxError: EOL while scanning string literal
>>> 'mixed quotes"
File "<stdin>", line 1
'mixed quotes"
^
SyntaxError: EOL while scanning string literal
逃避行为
像其他编程语言一样,当字符串包含引号这样的特殊字符时,我们需要对它们进行转义。下面是一个逃跑失败的例子。
>>> 'It's a bad example.'
File "<stdin>", line 1
'It's a bad example.'
^
SyntaxError: invalid syntax
我们如何修复这个错误?一种是通过在单引号前放置一个反斜杠来转义单引号。另一种是使用双引号而不是单引号作为括住的引号。两种方式如下所示。
>>> 'It\'s a good example.'
"It's a good example."
>>> "It's a good example."
"It's a good example."
类似地,如果字符串包含双引号,我们可以使用单引号来表示字符串,这样我们就不必对双引号进行转义。下面给出一个例子。
>>> 'She said, "Thank you!"'
'She said, "Thank you!"'
然而,如果字符串中既有单引号又有双引号,如果您没有对与整个字符串所使用的引号相同的引号进行转义,就会出现语法错误。
>>> print('She said, "Thank you! It's mine."')
File "<stdin>", line 1
print('She said, "Thank you! It's mine."')
^
SyntaxError: invalid syntax
>>> print('She said, "Thank you! It\'s mine."')
She said, "Thank you! It's mine."
三重引号
包含单引号和双引号的封闭字符串
正如上一节末尾提到的,我们需要根据字符串使用的引号来转义单引号或双引号。实际上,我们可以使用三重引号(即三重单引号或三重双引号)来表示既包含单引号又包含双引号的字符串,以消除对任何。
>>> print('''She said, "Thank you! It's mine."''')
She said, "Thank you! It's mine."
需要注意的是当一个字符串以单引号或双引号开始或结束,并且我们想要对这个字符串使用三重引号时,我们需要使用与开始或结束引号不同的引号。例如,对于上面代码片段中的字符串,使用三重双引号会导致语法错误。在这种情况下,我们想要使用上面的三个单引号。
>>> print("""She said, "Thank you! It's mine."""")
File "<stdin>", line 1
print("""She said, "Thank you! It's mine."""")
^
SyntaxError: EOL while scanning string literal
多行字符串
三重引号的另一个用例是表示多行字符串。下面给出一个例子。在这种情况下,您可以使用三重单引号或双引号。
>>> print("""Hello
... World
... !""")
Hello
World
!
虽然我们可以通过使用下面的\n符号创建多行字符串来达到相同的效果,但是使用\n符号会使字符串更难阅读。相比之下,使用三重引号可以准确地写出字符串,因此可读性更好。
>>> print('Hello\nWorld\n!')
Hello
World
!
此外,用三重引号括起来的字符串的一个有用的应用是在多行字符串中指定一些注释,例如,作为函数定义的一部分,如下所示。
>>> def multiple_line_comment(a, b):
... '''
... a is a string # other additional description
... b is a list of integers # other additional description
... '''
... pass
...
>>> print(multiple_line_comment.__doc__)
a is a string # other additional description
b is a list of integers # other additional description
我们可以清楚地知道函数的注释是什么。
结论
本文回顾了单引号、双引号和三引号在 Python 中的常见用法。下面是这些用例的快速总结。
单引号和双引号
- 括起字符串。单引号或双引号都可以。
- 使用单引号作为括起来的引号可以消除字符串中转义双引号的需要,反之亦然。
三重引号
- 将包含单引号和双引号的字符串括起来,这样就不需要转义。
- 括起多行字符串。
感谢您阅读本文,祝您用 Python 愉快地编码。
AWS SageMaker 上的单线分布式 PyTorch 培训
如何更快地迭代您的数据科学项目,让您的绝妙想法得以实现

作者图片
不管我在做什么研究项目,拥有合适的基础设施总是成功的关键部分。很简单:假设所有其他“参数”都相同,迭代越快/越便宜,在同样的时间/成本预算下,可以获得更好的结果。由于这些总是有限的,良好的基础设施通常是取得突破的关键。
说到数据科学,特别是深度学习,在强大的硬件上轻松分布训练过程的能力是实现快速迭代的关键。即使是最聪明的想法也需要几次迭代才能得到完善和验证,例如检查不同的预处理选项、网络架构,以及批量大小和学习速率等标准超参数。
在这篇文章中,我将向您展示在 AWS SageMaker 上使用simple-sage maker分发现有的准备分发的 PyTorch 培训代码是多么容易(如果您愿意的话,还很便宜)(假设分发是在支持的 gloo 或 nccl 后端 ) 之上完成的)。此外,您将了解如何在培训期间轻松地实时监控和分析资源利用率和关键培训指标。
简单的 sagemaker
简单——SageMaker是围绕 AWS SageMaker 的薄包装器,这使得在任何支持的实例类型 上的工作分配非常简单并且便宜。快速介绍可以在这篇博文中找到。
在单行中分发 PyTorch 模型培训
我将基于 PyTorch 的官方 ImageNet 示例进行演示。事实上,我将只使用一个命令在 AWS 上运行它!
更准确地说,我假设:
- 您已经安装了simple-sagemaker:
pip install simple-sagemaker - 您的 AWS 帐户凭证和默认区域是为 boto3 配置的,如 Boto3 文档中所述。
- ImageNet 数据已经存储(和提取,稍后将详细介绍)在 S3 存储桶中,例如
s3://bucket/imagenet-data. - 您已经将训练代码
[main.py](https://raw.githubusercontent.com/pytorch/examples/master/imagenet/main.py)下载到当前工作目录。
现在,要在单个 p3.2xlarge 实例上运行训练代码,只需运行以下命令:
就这样,在培训作业运行时坐下来。实际上,您可能需要休息一下,因为在整个数据集(总共约 120 万张图像)上,10 个时期需要约 8 小时。别急,训练好的模特到最后会在output/state下等你。
对ssm命令的一些解释:
shell—运行一个 shell 任务。-p imagenet -t 1-node—命名项目和任务。-o ./output1 --download_state—在训练结束时下载输出的本地路径+下载状态目录的请求(默认情况下也会下载日志)。--iis—使用来自s3://bucket/imagenet-data的 imagenet 数据作为映射到$SM_CHANNEL_IMAGENET路径的输入通道。--it ml.p3.2xlarge—将实例类型设置为ml.p3.2xlarge.-d main.py—添加 main.py 作为依赖项。-v 280—将 EBS 卷大小设置为 280 GB。--no_spot—使用按需实例而不是定点实例(默认)。更贵,但是时间是我们在努力节省的。--cmd_line—执行培训脚本。
一些注意事项:
- 在
[Bucket name]/[Project name]/[Task name]下,每个任务被分配一个专用的 S3 路径。路径下有几个目录,但是现在与我们相关的是state,它不断地与 S3 同步,并且在连续执行相同的任务时保持不变。 - 由于脚本在当前工作目录中保留了检查点,我们首先将它更改为 state 目录—
$SSM_INSTANCE_STATE - 世界大小和节点等级是基于工作代码可访问的环境变量设置的。完整的列表可以在这里找到。
--resume—在训练停止的情况下,根据状态目录中保存的检查点恢复训练。- 如果数据已经在您的本地机器上,您可以使用
-i参数(而不是--iis)让它自动上传到 S3,并用作“数据”输入通道。
有关更多信息和选项,例如,如果您需要定制 docker 映像或使用本地数据集进行培训,请阅读文档,运行ssm shell -h以获得命令行参数的帮助,和/或查看简介博客文章。
让我们看看./output1/logs/log0处输出日志的结尾:
** Acc@1 46.340 Acc@5 72.484
Total time: 26614 seconds*
我们取得了 46.3 的前 1 名准确率和 72.484 的前 5 名准确率,总训练时间为 26,614 秒= ~7:23 小时。总共 8 个小时的运行时间是由于开销,主要是由于下载(和提取)输入数据(~150 BG)。其中大约 3-4 分钟是由于“标准 SageMaker 开销”——启动和准备实例、下载输入数据和训练图像。在 spot 实例上训练时,这可能会变得有点长。
分发培训
回到你的时间预算,8 个小时对你来说可能太长了。如上所述,在某些情况下,这甚至意味着你的绝妙想法不会被公之于众。
幸运的是, ImageNet 示例代码写得很好,并且可以通过在几个实例上分配培训来轻松加速。此外,这将只是一个额外的参数!
又来了。将实例计数设置为 3( --ic 3)就可以在 3:51 小时内完成同样的工作!
查看输出日志./output2/logs/log0,我们看到在不到一半的训练时间内达到了相同的精度——11,605 秒= ~3:13 小时!
** Acc@1 46.516 Acc@5 72.688
Total time: 11605 seconds*
监控和优化培训过程
所以,你节省了时间,你的绝妙想法也更接近现实了。但是,如何轻松地观察和监控进展,使机会更高呢?
首先,在 SageMaker 培训工作控制台上查看,并选择3-nodes工作。这里应该可以得到关于它的所有可用信息:

培训工作信息
那里有更多可用的信息,包括例如到州(检查站)的链接和 S3 的输出,请随意探索。
我们现在最感兴趣的部分是“Monitor”部分,在这里您可以获得实例利用率(CPU、RAM、GPU、GPU 内存、磁盘)和算法指标的图表(稍后将详细介绍)。
实例和算法指标的完整日志和动态 CloudWatch 图形系统的链接位于该部分的顶部,是进行分析的途径。

以下是两个培训周期的实例指标:
**
这些图表会实时更新,可以让您确保一切按预期进行,以及是否有任何关键的瓶颈需要解决。
经验法则是确保 GPU 负载大部分时间接近 100%。以上图中的 3 个节点为例,可以看到 GPU 的负载仅为 70%,这意味着我们可以从硬件中获得更多。一个好的猜测可能是有更多的数据加载工作线程,以更快地将数据推送到 GPU。
算法度量
为了进一步简化对培训过程的监控,我们可以使用 SageMaker metrics 来实时获取特定于培训的指标。同样,我们只需要更新几个参数:
--md用于定义指标,其中第一个参数是名称,例如"loss",第二个参数是从输出日志中提取数值的正则表达式。
快进一下,这是两个训练周期的算法指标:
**
完整的分布式 ImageNet 培训管道
可以从image-net.org网站下载 LSVRC2012 ImageNet 数据。这里 Google 描述的简单步骤很有帮助。
由于完整的数据集大约有 120 万张图片,总大小约为 150GB,将其下载到本地,然后上传到 S3 水桶会花费很多时间。此外,在培训前将这么多文件从 S3 同步到培训实例也会非常慢。以下策略用于克服这些问题:
- 使用专用的处理任务下载数据,配备更快的 S3 连接。
- S3 的数据保持在 1000 年左右。tar 文件,并在训练实例上提取,就在训练之前。
使用下面的ssm命令可以轻松启动处理任务:
其中download.sh是一个 bash 脚本,它下载数据并把数据排列到它在第一个参数($SSM_OUTPUT/data)上获得的路径。一旦该任务完成,带有train和val子文件夹的data目录被放置在任务专用 S3 路径[Bucket name]/[Project name]/[Task name]的output目录下。训练命令现在也应该更新了:
这里引入了两个变化:
- 为了“链接”这两个任务,使处理任务的输出成为训练任务的输入,现在使用参数
--iit代替--iis。这将train和val子文件夹映射到具有相同名称的输入通道,可通过SSM_CHANNEL_TRAIN和SSM_CHANNEL_VAL环境变量访问。 - shell 脚本
extract.sh用于在训练之前提取数据。
在 simple-sagemaker 仓库中可以找到下载数据和执行一些训练选项的完整管道。
摘要
简单的分布式模型培训设置是数据科学项目的必备工具。它现在触手可及,比您想象的更简单、更容易。利用它!
在 Python 对象和 JSON 之间交换的单行代码

Python 编程技巧
在 Python 对象和 JSON 之间序列化/反序列化的最简单方法是Attr和Cattr
在我以前的一篇文章中,我介绍了 Python 中面向对象编程(OOP)的最佳实践,即使用“Attrs”库。
[## 可能是面向对象 Python 的最佳实践— Attr
让 Python 面向对象编程变得更加容易
towardsdatascience.com](/probably-the-best-practice-of-object-oriented-python-attr-d8c26c0e8a4)
然而,在大多数情况下,我们使用 OOP 可能是因为它可以序列化为字符串,如 JSON 字符串。更方便的是,我们还应该能够将它反序列化回类实例以用于其他目的。
例如,其中最流行的用法之一是数据访问对象(DAO)。因此,我们可以用对象实现 CRUD 函数,以便与持久层无缝集成。
因此,大多数时候,我们可能希望将 Python 对象序列化到 JSON 中,以便进行传输。相反,如果我们使用 Python 接收 JSON 类型的数据,我们也希望将 JSON 字符串反序列化为 Python 对象。
在本文中,我将介绍另一个库——“Cattr”,它可以与“attr”一起使用。我将把重点放在“Cattr”上,所以如果你对“attr”的功能感兴趣,请查看上面提到的文章。
安装和导入

照片由 JoshuaWoroniecki 在 Pixabay 上拍摄
首先,我们需要使用pip安装这两个库。
pip install attrs
pip install cattrs
在本文中,我们从attr中需要的只是类和属性函数的注释,所以让我们将它们和库cattr一起导入。
from attr import attrs, attrib
import cattr
Cattr 的基本用法

基本上,cattr用于在结构化和非结构化状态之间转换数据对象。例如,来自类的实例被认为是结构化数据,而 Python 字典和 JSON 对象被认为是非结构化数据。
假设我们要用不确定来规范一个列表中的数据,我们可以用cattr如下。
from typing import Tuplecattr.structure([1.01, True, False, "2", "I will be ignored"], Tuple[int, int, int, int])

请注意,我们使用的是来自typing库中的类型别名“Tuple ”,这是 Python 3 内置的。如果你不确定它是什么,这里是官方文档。
[## 类型-支持类型提示- Python 3.8.3 文档
源代码:Lib/typing.py 注意 Python 运行时不强制函数和变量类型注释。他们可以是…
docs.python.org](https://docs.python.org/3/library/typing.html)
在本例中,float、boolean 和 string 对象被调整为模板中指定的整数。此外,列表中的第 5 个对象被忽略,因为模板中只有 4 个元素。
Cattr 与 attr 合作

由 PublicDomainPictures 在 Pixabay 上拍摄的照片
cattr和attr一起处理班级的时候效果最好。
假设我们如下定义这个类。
[@attrs](http://twitter.com/attrs)
class Person:
name = attrib()
age = attrib()def tell_age(self):
print(f'My name is {self.name} and my age is {self.age}.')
当然,正如我在上一篇文章中介绍的,attr可以用于将实例序列化到字典中。
from attr import asdictp1 = Person('Chris', 32)
asdict(p1)

当然,cattr也可以这样做。
cattr.unstructure(p1)

看起来来自attr的asdict()函数更直观。然而,这只是序列化。如果我们得到了一个字典,并想将它反序列化为一个Person 对象,该怎么办?这次attr帮不上忙,但是我们可以用cattr。
p2 = cattr.structure({'name': 'Chelsea', 'age': 1}, Person)

Cattr 使用字典列表

上面的例子只是对单个字典的反序列化。实际上,这并不理想。如果我们想将字典列表反序列化为 Python 对象,该怎么办?在下面的例子中,我们有三个字典要在列表中描述。
p_list_raw = [
{'name': 'Alice', 'age': 20},
{'name': 'Bob', 'age': 25},
{'name': 'Chris', 'age': 32}
]
要实现这一点,我们还需要定义一个“模板”。请注意,我们传入的参数不再是“人”,而是“人”对象的列表。因此,我们需要再次使用输入别名。
from typing import Listp_list = cattr.structure(p_list_raw, List[Person])

因此,我们从 person 字典列表中得到一个 person 对象列表。
Cattr 使用 JSON

当然,我们并不满足于仅仅序列化/去序列化 Python 字典。我们希望它是一个 JSON 对象!这也很容易。事实上,我们唯一需要做的就是导入json库,它也是一个 Python 内置模块。
回想一下,在前面的例子中,我们有一个 Python 对象列表p_list。

要将其序列化为 JSON 数组,只需将cattr与json.dumps()函数一起使用,如下所示。
import jsonjson_obj = json.dumps(cattr.unstructure(p_list))
print(json_obj)

将 JSON 数组反序列化为 Python 对象列表也非常容易。简单地将json.loads()功能与cattr结合使用。
p_list = cattr.structure(json.loads(json_obj), List[Person])

只是不要忘记我们需要输入别名“列表”作为模板。
当然,上面的例子也显示了去序列化的对象可以用它们的类函数来调用:)
摘要

在这篇文章中,我介绍了如何使用cattr和attr库来实现将 Python 对象序列化为 dictionary/JSON,以及以一种极其简单的方式将 dictionary 和 JSON 对象反序列化为 Python 对象。
考虑到这在大多数其他编程语言中通常不是一件容易的事情,至少实现起来没有那么快,我想说这从一个方面反映了为什么人们喜欢 Python。
本文中的所有代码都可以在这里找到:
Google Colab
colab.research.google.com](https://colab.research.google.com/drive/1fm8PWLVp2vHEhkArmUcDp6VdNqLSG-O1?usp=sharing) [## 通过我的推荐链接加入 Medium 克里斯托弗·陶
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@qiuyujx/membership)
如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)
单参数模型| Pyro 与 STAN
用两种贝叶斯方法模拟美国癌症死亡率:斯坦的 MCMC 和 T2 的 SVI。

模拟美国各县的死亡率——照片由 Joey Csunyo 在 Unsplash 上拍摄
单参数模型是开始概率建模主题的极好方法。这些模型包括一个影响我们观察的参数,我们可以从给定的数据中推断出来。在本文中,我们着眼于性能并比较两个成熟的框架——统计语言 STAN 和 Pyro 概率编程语言(PPL)。
肾癌数据
一个古老而确定的数据集是美国 1980-1989 年的肾癌病例,可在这里获得(见【1】)。给出了美国各县、其总人口和报告的癌症死亡病例。我们的任务是用贝叶斯方法从给定的数据中推断出死亡率。
任务的详细走查可以在“贝叶斯数据分析 3”【1】的 2.8 节中找到。
我们的数据帧看起来像这样:

我们有数据点总数 N (数据框中的所有行),每个县有观察到的死亡数(dc),我们称之为 y 和人口数(pop),我们稍后称之为 n 。
鉴于我们有流行病学数据,我们认为泊松分布为估计我们想要计算的比率提供了良好的基础。因此,我们的观察值 y 是从泊松分布中采样的。有趣的参数是泊松的λ,我们称之为速率。这个死亡率来自伽马分布(见第 2 章[1]的解释)。一个非常简短的解释,为什么我们在这里使用γ,是因为它是关于泊松的共轭先验。
尽管这些分布有更多的特殊关系。
把它放在一起,我们得出死亡病例的观察公式:

而对于想要的单参数速率:

现在我们已经看到了任务,让我们启动工具开始工作。
STAN——经典统计模型
统计学家公认的工作语言是统计语言。
你把你的问题写成模型代码,斯坦会在幕后编译一个高效的 C++模型。从一个编译的模型中,你可以取样并执行推理。该框架提供了不同的接口,例如 Python (PyStan)、R (RStan)、Julia 等。对于本文,我们将使用 PyStan ,这样我们就可以将两种模型整齐地并排放在一个笔记本中。
我们开始定义我们在 STAN 中给出的数据。这意味着整数 N 表示数据集的总大小, y 表示观察到的死亡人数, n 表示每个县的人口数。这样我们每个人都有 N 次。
kidney_cancer_code="""
data {
int N; // total observations
int y[N]; // observed death-count
vector[N] n; // population
}
...
我们已经知道,像死亡率θ这样的速率参数有界在[0,1]内。这意味着利率不能小于 0 或大于 1。
该θ参数是实际比率的基础,即一个县的人口数。因此,由于我们转换了我们的参数,我们将其放入转换参数括号中。:
...
parameters {
vector<lower=0,upper=1>[N] theta; // bounded deathrate estimate
}transformed parameters {
vector[N] rate=n .* theta;
}
...
现在到了神奇的推理部分,这就是后验概率的意义所在。我们从伽玛分布中对θ进行采样。α (=20)和β (=430000)在[1]中给出,但人们可以很容易地从基础数据集计算出它们。请注意,模型实际上采用了转换后的参数,而不仅仅是θ。这将在稍后的输出中变得明显。
...
model {
theta ~ gamma(20,430000);
y ~ poisson(rate);
}
"""
现在我们有了一个字符串形式的 STAN 模型,我们需要正确格式的数据。这意味着数据中的整数数组,就像这样:
dc = data["dc"].to_numpy().astype(int)
pop = data['pop'].to_numpy().astype(int)
kidney_cancer_dat = {'N': N,
'y': dc[0:N],
'n': pop[0:N]}
由于一切都已设置好,我们可以使用 PyStan 将我们的模型转换成 C++代码,并使用采样来执行推理。推理过程是马尔可夫链蒙特卡罗或 MCMC。必要的参数是我们采集的样本量(迭代)和我们绘制样本的链的数量。每条链都是有序的抽奖序列。
sm = pystan.StanModel(model_code=kidney_cancer_code)
fit = sm.sampling(data=kidney_cancer_dat, iter=5000, chains=4)
拟合完成后,首先要检查的是模型是否收敛。这意味着 R(-hat)> = 1,或者我们可以直接询问诊断工具:
stan_utility.check_all_diagnostics(fit)### the below lines are output:
n_eff / iter looks reasonable for all parameters
Rhat looks reasonable for all parameters
0.0 of 10000 iterations ended with a divergence (0.0%)
0 of 10000 iterations saturated the maximum tree depth of 10 (0.0%)
E-BFMI indicated no pathological behavior
我们还可以从执行的推理的轨迹中看到链已经收敛(右图):
az.plot_trace(fit,var_names=['theta'])

图 1——θ后验计算的轨迹图。右侧的采样链显示收敛。每条链都有一个 theta 的密度函数(左侧),显示了数值的一致性。
链条(图 1 右侧)应该看起来像“疯狂相爱的毛毛虫”,诊断看起来也不错。这意味着我们的模型已经收敛。我们现在可以看看推断的θ值和个体密度:
az.plot_density(fit, var_names=["theta"])

图 2——推断后拟合单参数θ的后验密度。
Warning: Do not use the complete dataset as input! This will lead to errors,
we went with N=25 samples for testing purposes. Feel free to test how many samples it takes to break PyStan (or STAN).
为了完成贝叶斯回归任务,也有不同的模块让你跳过“写一个精心制作的统计模型”的部分。【BRMS】在 R 就是那些优秀的工具之一。
概率规划方法
提供一个完全不同的范例是 Pyro。我们不是通过采样来执行 MCMC,而是将我们的任务视为优化问题。
为此,我们制定了一个模型,它计算我们的后验概率( p )。此外,我们还制定了一个所谓的指南,为我们提供了一个参数化分布( q ),用于模型拟合过程。
在之前的故事中,我们已经了解了这种优化的工作原理,并推荐一个简短的回顾。
贝叶斯建模与真实世界数据一起工作的一个原因。随机海洋中的近似灯塔。
towardsdatascience.com](/compute-the-incomputable-how-svi-and-elbo-work-505ce0868fdd)
我们的模型不太直观的部分是,我们不是简单地拟合一个参数,而是由四个 Pyro 参数组成。:
- 首先,α和β是常数,它们赋予我们的伽马分布形状,就像我们在 STAN 部分所做的那样,
- 我们添加了两个钻孔可训练参数 p1 和 p2,这允许在 SVI 步骤中进行优化。两个参数都是正的,因此约束=约束。
- 当浏览数据时,观察本身是独立的事件。
这是通过 Pyro 的平板建模完成的,它也支持从我们的数据集中进行二次采样。在[2]中可以找到对此的很好的介绍。
ϵ = 10e-3
def model(population, deathcount):
α = pyro.param('α', torch.tensor(20.))
β = pyro.param('β', torch.tensor(430000.))
p1= pyro.param('p1', torch.ones(data.shape[0]), constraint=constraints.positive)
p2 = pyro.param('p2', torch.ones(data.shape[0]), constraint=constraints.positive)
with pyro.plate('data', data.shape[0], subsample_size=32) as idx:
n_j = population[idx]
y_j = deathcount[idx]
α_j = α + p1[idx]*y_j
β_j = β + p2[idx]*n_j
θ_j = pyro.sample("θ", Gamma(α_j, β_j))
λ_j = 10*n_j*θ_j + ϵ
pyro.sample('obs', Poisson(λ_j), obs=y_j)
该模型对给定泊松分布的观测值进行采样。这与 STAN 所做的工作相当,不同之处在于构成λ和底层分布的参数现在是可训练的 Pyro 参数。
为了使我们的模型不被烧毁,我们必须在速率中加入一个小数值ϵ,否则泊松对象在后面的计算中将会不稳定:
λ_j = 10*n_j*θ_j + ϵThis is not the best way to model this task, but it is closest to the STAN model. One can find a model and guide that do not rely on **y** and **n** for computing α and β.
现在,指南为我们提供了一个参数化分布 q ,我们可以使用它来执行优化,以最小化证据下限或 ELBO。参数是可训练的烟火参数,我们已经在模型中看到了。
def guide(population, deathcount):
α = pyro.param('α', torch.tensor(20.))
β = pyro.param('β', torch.tensor(430000.))
p1 = pyro.param('p1', torch.ones(data.shape[0]), constraint=constraints.positive)
p2 = pyro.param('p2', torch.ones(data.shape[0]), constraint=constraints.positive)
with pyro.plate('data', data.shape[0], subsample_size=32) as idx:
n_j = population[idx]
y_j = deathcount[idx]
α_j = α + p1[idx]*y_j
β_j = β + p2[idx]*n_j
θ_j = pyro.sample("θ", Gamma(α_j, β_j))
我们可以像这样继续运行我们的随机变分推理:
svi = SVI(model, guide, Adam({'lr': 0.025}), JitTrace_ELBO(3))
for i in tqdm(range(1000)):
loss = svi.step(population, deathcount)
print(f"Loss: {loss}")
当我们绘制损失图时(见图 3),我们可以看到模型随着时间的推移而改进。界限越低越好。损失是迭代过程中的 ELBO 轨迹。

图 3——迭代过程中的 SVI 损失。Loss 是经过 1000 次迭代后从 SVI 步骤返回的 ELBO。
现在进行最后的检查,我们可以看到我们已经安装了合适的参数。我们的模型发现的α和β变量为我们的后验推断提供了一个很好的基础伽马分布。

优化步骤后拟合的 Pyro 参数
结论——什么方法是最好的?
斯坦有一种简单明了的方式来推理这个模型。如果后验概率的数学公式是已知的,那么实现一个模型是非常简单的。然而,STAN 及其 MCMC 采样有其局限性。在默认配置下,不可能在所有数据上运行我们的模型。
Pyro 在高效处理大型数据集和执行变分推理方面表现出色。作为一种概率编程语言,它可以像任何其他 Python 代码一样编写。模型和指南也提供了丰富的信息,很好地概括了问题。通过这种方法,我们将后验计算转化为优化任务,并得到合理的输出。
既然您已经熟悉了单参数模型,那么就享受处理更大、更复杂任务的乐趣吧。烟火示例是一个很好的起点。
快乐推断!
参考
[1] A .盖尔曼、J.B .卡林等人。艾尔。、 贝叶斯数据分析 。第三版。
【2】Pyro 文档 SVI 第二部
单阶段实例分割——综述
实时实例分割的未来一瞥
更新:
- 2020/07/17:添加空间嵌入(ICCV 2019)的简要描述,一种自下而上的方法
实例分割是一项具有挑战性的计算机视觉任务,需要预测对象实例及其每像素分割掩模。这使得它成为语义分割和对象检测的混合。

自从 Mask R-CNN 发明以来,用于实例分割的最先进方法主要是 Mask RCNN 及其变体( PANet 、 Mask Score RCNN 等)。它采用先检测后分割的方法,首先进行对象检测,提取每个对象实例周围的包围盒,然后在每个包围盒内进行二值分割,以分离前景(对象)和背景。
除了自顶向下的先检测后分割(或逐检测分割)方法之外,还有其他一些实例分割方法。一个这样的例子是通过将实例分割公式化为自下而上的像素分配问题来关注像素,正如在(ICCV 2019)中所做的那样。但是这种方法通常比先检测后分割的 SOTA 方法性能差,在这篇文章中我们就不详述了。
然而,Mask RCNN 非常慢,并且排除了许多实时应用的使用。此外,由掩模 RCNN 预测的掩模具有固定的分辨率,因此对于具有复杂形状的大对象不够精细。在无锚点对象检测方法的进步(如 CenterNet 和 FCOS )的推动下,出现了一波对单阶段实例分割的研究。参见我的幻灯片快速介绍无锚点对象检测)。这些方法中有许多比掩膜 RCNN 更快、更准确,如下图所示。

最近在 Tesla V100 GPU 上测试的一阶段方法的推理时间(来源
这篇博客将回顾单阶段实例分割的最新进展,重点是掩码表示——实例分割的一个关键方面。
局部掩码和全局掩码
在实例分割中要问的一个核心问题是实例掩码的表示或参数化——1)是使用局部掩码还是全局掩码,以及 2)如何表示/参数化掩码。

遮罩表示:局部遮罩和全局遮罩
主要有两种方法来表示实例掩码:局部掩码和全局掩码。一个全局遮罩是我们最终想要的,它具有与输入图像相同的空间范围,尽管分辨率可能更小,例如原始图像的 1/4 或 1/8。它有一个天然的优势,即对于大物体和小物体具有相同的分辨率(因此具有固定长度的特征)。这不会牺牲较大对象的分辨率,固定分辨率有助于执行批处理以进行优化。一个局部遮罩通常比一个全局遮罩更紧凑,因为它没有过多的边界。它必须与遮罩位置一起使用才能恢复到全局遮罩,而局部遮罩的大小将取决于对象的大小。但是为了执行有效的批处理,实例掩码需要固定长度的参数化。最简单的解决方案是将实例遮罩的大小调整为固定的图像分辨率,如遮罩 RCNN 所采用的。正如我们在下面看到的,还有更有效的方法来参数化局部掩码。
根据是使用局部还是全局掩码,单阶段实例分割可以大致分为基于局部掩码的和基于全局掩码的方法。
基于局部掩模的方法
基于局部掩码的方法直接输出每个局部区域的实例掩码。
具有显式编码的轮廓
包围盒在某种意义上是一个粗糙的遮罩,它用最小的包围矩形来近似遮罩的轮廓。 ExtremeNet (通过对极值点和中心点进行分组的自下而上的对象检测,CVPR 2019)通过使用四个极值点(因此是具有 8 个自由度的边界框,而不是传统的 4 个 DoF)来执行检测,并且这种更丰富的参数化可以通过在其相应边缘上的两个方向上将极值点延伸到整个边缘长度的 1/4 的片段来自然地延伸到八边形遮罩。

此后,有一系列的工作试图将实例掩模的轮廓编码/参数化成固定长度的系数,给出不同的分解基础。这些方法回归每个实例的中心(不一定是 bbox 中心)和相对于该中心的轮廓。 ESE-Seg (实时实例分割的显式形状编码,ICCV 2019)为每个实例设计了一个内中心半径形状签名,并用切比雪夫多项式进行拟合。 PolarMask (PolarMask:使用极坐标表示的单次拍摄实例分割,CVPR 2020)利用从中心开始的恒定角度间隔的射线来描述轮廓。 FourierNet (FourierNet:使用可微分形状解码器进行分割的紧凑掩模表示)引入了使用傅立叶变换的轮廓形状解码器,比 PolarMask 实现了更平滑的边界。

各种基于轮廓的方法
这些方法通常使用 20 到 40 系数来参数化掩模轮廓。它们推理速度快,易于优化。然而,它们的缺点也是显而易见的。首先,从视觉上看,它们看起来——说实话——都很糟糕。他们不能精确地描绘面具,也不能描述中间有洞的物体。
我个人认为这一行很可爱,但没什么前途。实例遮罩或其轮廓的复杂拓扑的显式编码是难以处理的。
结构化 4D 张量
TensorMask (TensorMask:稠密对象分割的基础,ICCV 2019)是通过预测每个特征图位置的掩膜来展示稠密掩膜预测思想的首批作品之一。张量掩模仍然预测感兴趣区域的掩模而不是全局掩模,并且它能够运行实例分割而不运行对象检测。
张量掩模利用结构化的 4D 张量来表示空间域上的掩模(2D 在输入图像中的所有可能位置上迭代,2D 在每个位置上表示掩模),它还引入了对齐表示和张量双锥来恢复空间细节,但是这些对齐操作使得网络甚至比两级掩模 R-CNN 更慢。此外,为了获得良好的性能,需要使用比标准 COCO 对象检测流水线长六倍的调度(6x 调度)来训练它。

紧凑掩码编码
自然对象遮罩不是随机的,它类似于自然图像,实例遮罩驻留在比像素空间低得多的固有维度中。MEInst(CVPR 2020 年单镜头实例分割的掩模编码)将掩模提取为紧凑和固定的维度表示。通过 PCA 的简单线性变换,MEInst 能够将 28x28 的局部掩模压缩成一个 60 维的特征向量。本文还尝试了在一级目标检测器()上直接回归 28x28=784 维特征向量,在 1 到 2 个 AP 点下降的情况下也能得到合理的结果。这意味着直接预测高维掩码(在每个张量掩码的自然表示中)并非完全不可能,但是很难优化。掩码的紧凑表示使得优化更容易,并且在推理时运行更快。它最类似于掩模 RCNN,并且可以直接与大多数其他对象检测算法一起使用。

基于全局掩码的方法
****基于全局遮罩的方法首先基于整个图像生成中间的和共享的特征图,然后组合提取的特征以形成每个实例的最终遮罩。这是目前一阶段实例分割方法中的主流方法。
原型和系数
YOLACT (YOLACT:实时实例分割,ICCV 2019)是最早尝试实时实例分割的方法之一。YOLACT 将实例分割分成两个并行任务,生成一组原型掩码,并预测每个实例的掩码系数。原型掩码是用 FCN 生成的,可以直接受益于语义分割的进步。系数被预测为边界框的额外特征。这两个并行步骤之后是组装步骤:通过矩阵乘法实现简单的线性组合,并对每个实例的预测边界框进行裁剪操作。裁剪操作减少了网络抑制边界框之外的噪声的负担,但是如果边界框包括同一类的另一个实例的一部分,仍然会看到一些泄漏。

原型掩码的预测对于确保最终实例掩码的高分辨率是至关重要的,这可与语义分割相媲美。原型遮罩仅依赖于输入图像,而与类别和具体实例无关。这种分布式表示是紧凑的,因为原型掩码的数量独立于实例的数量,这使得 YOLACT 的掩码计算成本恒定(不像掩码 RCNN,其计算成本与实例的数量成线性)。
回顾 MSRA 的 InstanceFCN (实例敏感全卷积网络,ECCV 2016)和后续研究【FCIS】(全卷积实例感知语义分割,CVPR 2017),它们似乎是 YOLACT 的一个特例。InstanceFCN 和 FCIS 都利用 FCN 生成多个包含对象实例相对位置的实例敏感得分图,然后应用组装模块输出对象实例。位置敏感的得分图可以被视为原型掩模,但代替学习的线性系数,IntanceFCN 和 FCIS 使用一组固定的空间池操作来组合位置敏感的原型掩模。

InstanceFCN [b]和 FCIS [c]使用固定池操作进行实例分段(源)
BlendMask(blend mask:自上而下遇到自下而上进行实例分割,CVPR 2020)建立在 YOLACT 的基础上,但 blend mask 不是为每个原型遮罩预测一个标量系数,而是预测一个低分辨率(7x7)注意力图来混合边界框内的遮罩。这个注意力地图被预测为附着于每个边界框的高维特征(7×7 = 49-d)。有趣的是,BlendMask 使用的原型遮罩是 4 个,但它甚至只用 1 个原型遮罩就能工作。 中心遮罩 (中心遮罩:用点表示的单镜头实例分割,CVPR 2020)几乎以完全相同的方式工作,并显式使用 1 个原型遮罩(名为全局显著图)。CenterMask 使用 CenterNet 作为主干,而 BlendMask 使用类似的无锚点单级 FCOS 作为主干。

中心遮罩的架构。BlendMask 也有极其相似的管道。
注意,BlendMask 和 CenterMask 都进一步依赖于检测到的边界框。在与裁剪的原型遮罩混合之前,注意力图或形状遮罩必须缩放到与边界框相同的大小。
(例如分割的条件卷积)更进一步,完全去除了对边界框的任何依赖。它没有组装裁剪过的原型面具,而是借用了动态过滤器的想法,预测一个轻量级 FCN 头部的参数。FCN 磁头有三层,共有 169 个参数。令人惊讶的是,作者表明,即使原型面具是单独的 2-ch coord conv,网络也可以预测 COCO 上 31 AP 的良好结果。我们将在下面的隐式表示部分讨论这一点。****

BlendMask /CenterMask 和 CondInst 都是 YOLACT 的扩展。
- BlendMask/CenterMask 尝试在每个 bbox 中将裁剪的原型遮罩与更细粒度的遮罩混合。YOLACT 是 BlendMask 或 CenterMask 的一个特例,其中注意力图的分辨率是 1×1。
- CondInst 正在尝试将裁剪过的原型遮罩与由动态预测滤镜组成的更深层次的转换融合在一起。YOLACT 是 FCN 是 1×1 conv 层的一个特例。
使用分支来预测原型掩码允许这些方法受益于使用语义分割的辅助任务(通常在 AP 中提升 1 到 2 个点)。它也可以自然地扩展到执行全景分割。
关于表示每个实例掩码所需的参数,下面列出了一些技术细节。这些具有全局遮罩和系数的方法对每个实例遮罩使用 32,196,169 个参数。
- YOLACT 采用 32 原型蒙版+ 32-dim 蒙版 coeff +方框裁剪;
- BlendMask 使用 4 个原型遮罩+ 4 张 7x7 注意力图+方框裁剪;
- CondInst 使用 coordConv + 3 1x1 动态 conv (169 个参数)
SOLO 和 SOLOv2:按位置分割对象
SOLO 是独一无二的,值得拥有自己的部分。这些论文见解深刻,写得非常好。它们对我来说是一件艺术品(就像我最喜欢的另一个 CenterNet 一样)。

SOLOv1 的架构
The first author of the paper posted his reply on the motivation of SOLO on Zhihu (知乎), which I quote below:
语义分割预测图像中每个像素的语义类别。类似地,对于实例分割,我们建议预测每个像素的“实例类别”。现在的关键问题是,我们如何定义实例类别?
如果输入图像中的两个对象实例具有完全相同的形状和位置,则它们是同一个实例。任何两个不同的实例都有不同的位置或形状。由于形状一般很难描述,我们用大小来近似形状。
因此,“实例类别”是由位置和大小定义的。位置按其中心位置分类。SOLO 通过将输入图像划分为 S x S 个像元的网格并由此划分 S 个类来近似中心位置。大小通过将不同大小的对象分配到特征金字塔的不同级别(FPN)来处理。因此,对于每个像素,SOLO 只需要决定将像素(和相应的实例类别)分配给哪个 SxS 网格单元和哪个 FPN 级别。所以 SOLO 只需要执行两个像素级的分类问题,类似于语义分割。另一个关键问题是面具是如何表现的?
实例遮罩由堆叠在 S 通道中的全局遮罩直接表示。这是一个同时解决许多问题的巧妙设计。首先,许多先前的研究将 2D 掩模存储为展平向量,当掩模分辨率增加导致通道数量激增时,这很快变得难以处理。全局遮罩自然会保留遮罩像素内的空间关系。第二,全局掩模生成可以保持掩模的高分辨率。第三,预测掩模的数量是固定的,与图像中的对象无关。这类似于原型遮罩的工作线,我们将在 SOLOv2 中看到这两个流是如何合并的。
SOLO 将实例分割公式化为仅分类问题,并消除了任何对回归的依赖。这使得 SOLO 自然独立于对象检测。SOLO 和 CondInst 是两个直接作用于全局遮罩的作品,是真正的无边界框方法。

索罗预言的全球面具。掩模是冗余的、稀疏的,并且对目标定位误差是鲁棒的。
分辨率权衡
从 SOLO 预测的全局掩模中,我们可以看到,由于相邻通道预测的掩模非常相似,所以掩模对定位误差相对不敏感。这带来了对象定位的分辨率(以及精度)和实例遮罩之间的折衷。
4D 结构张量的想法在理论上很有意义,但在 NHWC 张量格式的当前框架下很难在实践中实现。将具有空间语义的 2D 张量展平为 1D 向量将不可避免地丢失一些空间细节(类似于使用全连接网络进行语义分割),甚至在表示 128x128 的低分辨率图像时也有其局限性。位置的 2D 或掩模的 2D 必须牺牲分辨率。大多数先前的研究理所当然地认为位置分辨率更重要,并且下采样/压缩蒙版尺寸,损害了蒙版的表现力和质量。TensorMask 试图取得平衡,但繁琐的操作导致训练和推理速度缓慢。SOLO 意识到我们不需要高分辨率的位置信息,并借鉴了 YOLO 的方法,将位置信息压缩到一个粗略的 S 网格中。这样,SOLO 保持了全局遮罩的高分辨率。
我天真地认为 SOLO 也许可以预测 S x W x H 全局遮罩,作为附加到 YOLO 每个 S 网格的扁平 WH 维特征。我错了——全分辨率的全局蒙版公式而不是扁平矢量实际上是 SOLO 成功的关键。
解耦独奏和动态独奏
如上所述,在 S 通道中由 SOLO 预测的全局掩码是相当冗余和稀疏的。即使在 S=20 的粗略分辨率下,也有 400 个通道,并且图片中不太可能有如此多的对象以至于每个通道都包含有效的实例遮罩。
在解耦 SOLO 中,形状为 H x W x S 的原始 m 张量被形状为 H x W x S 的两个张量 x 和 y 代替。对于位于网格位置(I,j)的对象,M_ij 通过逐元素乘法 X_i ⊗ Y_j 来近似。这将 400 个通道减少到 40 个通道,并且实验表明性能没有下降。

SOLO vs 去耦 SOLO vs SOLOv2
现在很自然地会问,我们是否可以借鉴 YOLACT 的原型遮罩思想,通过预测更少的遮罩并预测每个网格单元的系数来组合它们?SOLOv2 正是这样做的。
在 SOLOv2 中,有两个分支,一个特性分支和一个内核分支。特征分支预测 E 个原型遮罩,而核分支预测 S 个网格单元位置中的每一个处的大小为 D 的核。这种动态过滤器方法是最灵活的,正如我们在上面的 YOLACT 部分中看到的。当 D=E 时,是原型遮罩(或 1x1 conv)的简单线性组合,与 YOLACT 相同。本文还尝试了 3x3 conv 核(D=9E)。这可以通过预测轻质多层 FCN 的重量和偏差而更进一步。

现在,由于全局掩码分支与其专用位置分离,我们可以观察到新兴的原型掩码显示出比 SOLO 中更复杂的模式。它们仍然是位置敏感的,更类似于 YOLACT。
掩码的隐式表示
在 CondInst 和 SOLOv2 中使用的动态滤波器的想法起初听起来很棒,但实际上非常简单,如果你认为它是用于线性组合的系数列表的自然扩展。
你也可以认为我们用系数或注意力图参数化了面具,或者最终,变成了一个小神经网络头的动态过滤器。最近在 3D 学习中也探索了使用神经网络来动态编码几何实体的想法。传统上,3D 形状或者用体素、点云或者网格编码。占位网络(占位网络:在功能空间中学习 3D 重建,CVPR 2019)提出将形状编码到神经网络中,通过将深度神经网络的连续决策边界视为 3D 表面。网络接收 3D 中的一个点,并判断它是否在编码的 3D 形状的边界上。这种方法允许在推理过程中以任何分辨率提取 3D 网格。

占用网络中提出的隐式表示
我们是否可以学习一个神经网络,该网络由每个对象实例的动态过滤器组成,以便网络接受 2D 中的一个点,并输出该点是否属于该对象遮罩?这自然会输出全局遮罩,并且可以具有任何所需的分辨率。回顾 CondInst 的消融研究,证明了即使没有原型掩模,但只有 CoordConv 输入(其用作执行均匀空间采样)。由于该操作与原型蒙版的分辨率无关,因此在更高分辨率下单独输入 CoordConv 来获得更高分辨率的全局蒙版会很有意思,可以看看这是否能提高性能。我坚信实例掩码的隐式编码是未来的趋势。

在没有原型屏蔽的情况下,仅使用 CoordConv 输入,CondInst 也可以预测良好的性能(来源
最后一句话
大多数单阶段实例分割工作都是基于无锚对象检测,如 CenterNet 和 FCOS。也许并不奇怪,上面的许多论文来自创造了 FCOS 的阿德莱德大学的同一个实验室。他们最近在 https://github.com/aim-uofa/AdelaiDet/开源了他们的平台。
许多最新的方法速度很快,可以达到实时或接近实时的性能(30+ FPS)。NMS 通常是实时实例分割的瓶颈。为了实现真正的实时性能,YOLACT 使用快速 NMS,SOLOv2 使用矩阵 NMS。我将在另一篇文章中谈论各种 NMS 方法。
外卖
- 预测高维特征向量例如掩模是困难的。几乎所有的方法都集中在如何将掩模压缩成更低维的表示。这些方法通常使用 20 到 200 个参数来描述一个掩模,具有不同程度的成功。我认为这是表示掩模形状的最小参数数量的基本限制。
- 手工制作的参数轮廓不是很有前途。
- 局部遮罩本质上依赖于对象检测。我期待看到更多直接生成全局遮罩的研究。
- 掩模的隐式表示是表达性的、紧凑的,并且可以以任何分辨率生成掩模。通过利用隐式表示的能力,CondInst 有可能生成更高分辨率的全局遮罩。
- SOLO 简单 SOLOv2 快速准确。我希望未来能看到更多这方面的研究。
参考
- SOLO: 按位置分割对象,Arxiv 12/2019
- SOLOv2 :动态、更快、更强,Arxiv 03/2020
- YOLACT :实时实例分割,ICCV 2019
- PolarMask :用极坐标表示的单镜头实例分割,CVPR 2020 口述
- ESE-Seg :实时实例分割的显式形状编码,ICCV 2019
- point render:图像分割为渲染,CVPR 2020 口述
- :密集对象分割的基础,ICCV 2019
- BlendMask :自顶向下遇到自底向上进行实例分割,CVPR 2020
- 中心遮罩:用点表示的单镜头实例分割,CVPR 2020
- MEInst :单镜头实例分割的掩膜编码,CVPR 2020)
- 条件:用于实例分割的条件卷积,Arxiv 03/2020
- 占位网络:在功能空间学习三维重建,CVPR 2019
- FCOS :全卷积一级目标检测,ICCV 2019
- 面具 R-CNN ,ICCV 2017 最佳论文
- PANet : 路径聚合网络实例分割,CVPR 2018
- 面具评分 R-CNN ,CVPR 2019
- 实例敏感全卷积网络,ECCV 2016)
- FCIS : 全卷积实例感知语义分割,CVPR 2017
- FCN :面向语义分割的全卷积网络,CVPR 2015
- CoordConv: 卷积神经网络的一个耐人寻味的失败和 CoordConv 解决方案,NeurIPS 2018
- 关联嵌入:用于联合检测和分组的端到端学习,NeuRIPS 2017
- 空间嵌入:联合优化空间嵌入和聚类带宽的实例分割,ICCV 2019
奇异值分解及其在主成分分析中的应用
主成分分析稳健计算的数学工具

图片来源:https://www.youtube.com/watch?v=c0fy5V7hA4g
“学习所有的训练数据与实际学习没有任何关系。你所做的基本上是记忆数据”
线性代数为从简单的线性回归到深度神经网络的机器学习算法奠定了核心基础。主要原因是数据集可以用二维矩阵表示,其中列表示特征,行表示不同的样本数据点。话虽如此,使用矩阵中所有值的矩阵计算有时是多余的,或者在计算上相当昂贵。我们需要用一种形式来表示矩阵,使得进一步计算所需的矩阵的最重要部分可以容易地提取出来。这就是奇异值分解(SVD) 发挥作用的地方。
SVD 基本上是一种矩阵分解技术,它将任何矩阵分解成 3 个常见的矩阵。它在机器学习和图像处理方面有一些很酷的应用。为了理解奇异值分解的概念,关于特征值和特征向量的知识是必不可少的。如果你对特征值和特征向量有很好的理解,向下滚动一点来体验奇异值分解。
特征值和特征向量

图片来源:https://commons.wikimedia.org/wiki/File:Eigenvectors.gif
矩阵和向量的乘法产生另一个向量,该向量被定义为该向量相对于给定向量空间中的特定矩阵发生的变换。然而,对于某些给定的矩阵,存在一些向量,使得即使在应用了变换之后,它们的方向也不会改变(类似于上面 GIF 中的蓝色向量)。这样的向量称为给定矩阵的特征向量,而向量变换后的标度值定义为该特征向量对应的特征值。这可以用下面的例子来说明:

λ是特征向量 v 对应的特征值
特征向量的概念只适用于方阵。有许多方法可以找到特征值和相应的特征向量,我们不打算在这篇文章中讨论。我找到了下面这个来自 3blue1brown 的视频,它以一种更生动的方式解释了特征值和特征向量。随便看看。
一个特征向量所跨越的向量空间被称为特征空间。一个方阵称为可对角化矩阵,如果它可以写成如下格式:

D 是由作为对角元素的特征值组成的对角矩阵
矩阵 P 无非是特征向量叠加在一起的矩阵。还有另一种特殊的矩阵称为对称矩阵,其中矩阵等于其自身的转置矩阵,如果矩阵的转置矩阵是该矩阵的逆矩阵,则该矩阵称为正交矩阵。

对称矩阵

正交矩阵
以下是对称矩阵关于特征值和特征向量的一些特殊性质。
- 只有个实特征值
- 总是可对角化
- 具有正交特征向量
由于对称矩阵的特征向量彼此正交,所以对角化矩阵 A 中的矩阵 P 是正交矩阵。所以我们说任何对称矩阵都是正交可对角化的:

对称矩阵 A 是正交对角化的
现在我们已经介绍了奇异值分解的基础知识。矩阵对角化通常被称为矩阵的特征分解。然而,这种特征分解仅限于某一组矩阵。奇异值分解的实际动机源于特征分解的缺点:
- 特征值的概念只适用于平方矩阵。
- 对于方阵,复特征值的存在限制了实特征空间的数量。
奇异值分解
为了克服矩阵特征分解带来的挑战,需要对任何矩阵进行更一般的表示,这就是奇异值分解发挥作用的地方。设 A 为任意形状的矩形矩阵(m×n)。我们可以证明 AᵀA 和 AAᵀ 分别是形状为(n×n)和(m×m)的对称方阵。

AᵀA 和 AAᵀ 对称性的证明
此外,还可以证明 AᵀA 和 AAᵀ 共享相同的非零特征值。如果一个比另一个有更多的特征值,所有多余的特征值应该为零。

两个矩阵共享相同的特征值λ,而特征向量不同
根据对称矩阵的正交可对角化性质,矩阵 AᵀA 和 AAᵀ 可以分解如下:

d 是对角矩阵的特征值,V,U 是正交矩阵
假设 v 是 AᵀA 的任意特征向量,大小为(n×1)。乘法 A v 将产生大小为(m×1)的向量,因为 A 是形状为(m×n)的矩形矩阵。为了节省时间,我们假设 Av=σk其中 k 是一个大小为(m×1)的向量,σ是一个标量值。如果矩阵 D 的秩为 r,则矩阵 AᵀA 和 AAᵀ.有 r 个非零特征值

既然我们知道 V 是正交矩阵,

这里σ是σ值的对角矩阵
现在让我们做一些简单的数学运算来看看关于 K. 的一些令人兴奋的结果

现在很明显 K 不过是aaᵀ.的特征向量矩阵现在用kby我们可以写成a = uσvᵀ.矩阵的这种通用表示形式称为 奇异值分解。 在此分解中,我们将中的向量称为左奇异向量,而将 V 中的向量称为右奇异向量。**
奇异值分解背后的主要直觉是,矩阵将一组正交向量 (v) 转换为另一组正交向量 (u) ,缩放因子为σ。所以 σ 称为对应于各自奇异向量 u 和的奇异值****
****矩阵方法的 Eckat-Young-Mirsky 定理描述了低秩近似。简单来说,它提供了给定数据矩阵中最重要的部分。我们可以把我们分解的矩阵 A 写成:

上面的等式描述了矩阵加法。埃克哈特-杨-米尔斯基*定理所陈述的是, Aₖ 这是奇异矩阵的加法直到 k ᵗʰ最大奇异值是矩阵a 的秩 k 的最近矩阵,它可以说明如下:***

这个结果被证明适用于许多著名的矩阵范数,如 L2 范数、弗罗贝纽斯范数等。矩阵 X 的协方差矩阵 S 定义为:

现在我们已经学习了奇异值分解的理论。让我们深入研究 SVD 发挥作用的应用程序。

主成分分析
主成分分析是一种降维技术,用于许多机器学习应用,包括特征工程和特征提取。PCA 的目标是为给定的数据矩阵找到一组向量的正交基,使得投影到由向量确定的方向上的数据集的方差最大化。通过一组证明,已经确定那些向量(俗称主成分)不过是按照对应的特征值的顺序排列的协方差矩阵的特征向量。本文不讨论主成分的详细推导。**

二维数据矩阵的第一和第二主分量
对于一个矩阵 X , k ᵗʰ主分量是 X 的协方差矩阵对应的 k ᵗʰ最大特征值的特征向量。
虽然这可以用协方差矩阵的传统特征分解来处理,但缺点是计算复杂性。由于我们的数据矩阵将是一个巨大的矩阵,包含成千上万的数据,这真的很难计算协方差矩阵的特征值,这有时会导致误差,如舍入误差。****

主成分分析中的奇异值分解
然而,数学家们已经找到了计算奇异值分解的稳定而精确的方法。其中一种方法可以在这里找到。在 SVD(a = uσv中我们知道 V 是协方差矩阵的特征向量而它的特征值 (λ) 隐藏在奇异值【σ】中。

A 的奇异值与 A 的协方差矩阵的特征值之间的关系。
由于 n 在两种情况下都是常数,因此数据矩阵的主分量是给定矩阵的右奇异向量 ( V ) ,按照奇异值的顺序。
对于一个矩阵 X , k ᵗʰ主分量是 X 协方差矩阵的右奇异向量对应于 k ᵗʰ最大奇异值。
因此,我们遇到了一种表示任何矩阵的更通用的方法,奇异值分解及其在建模主成分分析中的贡献,这是一种在机器学习中提取数据矩阵重要特征的复杂方法。我希望你喜欢这篇文章🙂。请随时让我知道关于这方面的任何意见和建议。**
奇点可能不需要 AGI
自 60 年代以来,人工智能可以比人类更快地自我改进的点——奇点一直是一个话题。 I.J. Good 在 1965 年推测“一台超智能机器...这可以远远超过任何聪明人的所有智力活动”。
詹姆斯·巴拉特的畅销书我们的最终发明将这个话题从学术和书呆子带到了主流关注点(或者,我应该说恐惧)?

作者图片
伟大的已故斯蒂芬·霍金和备受争议的埃隆·马斯克是对人工智能最直言不讳的人,人工智能可能是人类文明史上发生的最糟糕的事情。而其他人,如比尔·盖茨、吴恩达和一些著名的人工智能研究人员认为人工智能已经成为迫在眉睫的威胁。
然而,对于那些仔细阅读的人来说,与霍金斯的大多数分歧实际上并不是说 AI 将永远不会成为威胁,或者奇点将永远不会到来。大多数的争论都是关于时机的。也就是说,吴恩达用“担心机器人杀手的崛起就像担心火星人口过剩”来比喻人工智能的奇点威胁。虽然从人工智能研究人员的角度来看,这是完全正确的,但如果你考虑一下我们在过去二十年里在这个地球上增加 20 亿人口的速度,你可能会同意无论火星人口过剩的威胁有多遥远,这实际上是可能的(火星比地球小得多,直径为 6790 公里,而地球为 12750 公里,略超过地球的一半。由于球体的表面积与直径的平方成正比,所以火星的表面积只有地球的四分之一多一点。我离题了,但我希望你明白吴恩达的意思,这种威胁是真实的,只是时间问题,也许不是立即的,但肯定是不可避免的。
在流行文化中,围绕奇点的大多数恐惧是,人工智能将获得超越最聪明人类的整体智能,从那里开始,它将自我完善,并越来越快地扩大差距。针对这一点,许多“抚慰人心”的论点都是基于 AGI(人工通用智能)遥遥无期;我们甚至不知道如何建造 AGI…作为一名人工智能工程师,我同意这一点。
然而,这些争论实质上是人工智能的智能设计理论。这是 AI 达到奇点的唯一途径吗?我们人类花了几千年来思考我们的智慧是如何产生的,至少我们现在有了一个可能的替代理论——进化。
有没有可能 奇点 可能不需要 AGI 触发 ?
进化成奇点
如果你是一个进化论者,这不会给你太大的打击,人类是“刚刚发生”的智能代理,没有其他更聪明的存在绘制的蓝图。我们进化成智能代理的方式是通过随机突变和自然选择。因为我们的祖先是“成功人士”,他们的优势基因增加了他们的生存机会,一代又一代,我们携带可能更好基因的祖先不断调查,让我们成为今天的我们。
你还会注意到,自从有文字记载的历史以来,人类文化的发展,我们这个物种的集体智慧,作为一个整体,进化得比以前快得多。因此,在没有另一个超级智能出现的情况下,引爆点事件确实至少发生过一次(如果你是一个神创论者,你很可能会同意人类没有在八千年前成为创造者)。)
主要限制?时间。生命形式进化到拥有我们花了数十亿年。关键因素是该过程的成本,需要存在大量相似的个体,经过选择过程并存活足够长的时间,然后才能自我繁殖(这是一种通过一些突变来保存基因的方法)。)
AI 能进化成奇点吗?
先说进化需要什么:随机 突变和自然选择。
自然选择,在人工智能的例子中,它可以从人类自然选择人工智能开始,我们甚至可能没有意识到我们正在这样做。
我记得在 CAPTCHA 这个臭名昭著的测试检查你是否是机器人的早期,人们问我,“他们说人工智能公司使用 CAPTCHA 来训练他们的人工智能,但它如何知道我回答正确?”嗯,实际上它不需要知道你是否回答正确,大多数人选择的答案对 AI 来说已经足够好了去学习。因此,允许人类与智能工程的人工智能互动,将允许我们训练他们,或者在自然选择的情况下,我们可能充当“自然”,在甚至不知道的情况下选择更好的人工智能形式。例如,你观看或跳过的网飞标题,将被聚集并用于训练他们的推荐模型的下一次迭代。
你正在阅读这篇文章的事实,由于某种算法将它推向你的注意力,当你阅读这篇文章时,系统实际上正在学习关于你的一些东西(即你在这一页上呆了多长时间),关于我的一些东西(即我的写作风格),关于我们如何互动(即如果我回复你的评论,你鼓掌、强调或评论的次数),以及改进它将如何向你推荐下一篇文章。
这听起来熟悉吗?机器学习(我们这里将使用监督学习作为例子)是这样的过程,即训练过程帮助改进算法中使用的参数值,这种改进来自于使用当前参数集运行模型,获得预测结果,将预测结果与已知结果进行比较(即,将某些人是否会阅读这篇文章的预测与这些人是否会实际阅读这篇文章进行比较),并缩小差距(即梯度下降)。旧值被丢弃,取而代之的是更新、更好的参数集,这些参数集将生成更好的预测。
是的,这与进化过程非常相似,尽管它是一种非常特殊的形式。参数值是被选择的,被丢弃的,或者换句话说,被进化的。选择是为了与已知结果进行比较。这种特殊的进化形式非常有限,它不能改变算法本身,只能改变算法中使用的参数。它只能根据预先知道的结果进行选择,不能推广到其他问题。虽然这种限制意味着它不能进化成一般的智力,但令人担忧的事实是,在大多数单一技能测试中,人工智能可以超过 99.9%的人,如果不是 100%的话。(1997 年计算机击败人类最佳棋手,2019 年 AI 击败人类最佳围棋手)。
人工智能研究和工程在过去几十年中的进展。一个特别有趣的例子是 GAN——生成性对抗网络。如果听起来很陌生,那就想想深度假动作,甘是深度假动作下面的基础技术。它的核心仍然只是深度学习,但通过战略设计的多个神经网络以特定的方式交互,其中一个生成一些东西,另一个试图判断这是否是生成的假,然后它将向生成算法提供反馈,该算法将试图做得更好,以生成另一个(图片、声音、视频等)。)直到对抗网络分不清一个真实的东西和生成的假货。
这个过程是向前迈出的一大步,表明智能工程技术可以用来大大推进我们所认为的人工智能中的“选择”——它使用我们人类作为“自然”提供的样本,并使用神经网络来计算这些样本的模式(概括或抽象这些样本),然后使用另一个神经网络尝试生成可以融入模式的东西,直到无法区分。
虽然这些都不是完美的,但它们是我们可以利用的一些技术的例子,来建立一个“选择”可以以不断增长的方式发生的环境。我一年前写的一篇文章可能会改变游戏规则:
随着深度学习,特别是 CNN 在图像处理方面获得成功和声誉,它也获得了一些严重的…
像这样设计得当的部件可以帮助人工智能直接从现实世界获得反馈,机器人已经可以使用类似的技术来学习操纵积木:
来自麻省理工学院的一组研究人员刚刚制造了一个机器人,并开发了一个基于深度学习的系统,可以玩 Jenga,a…
news.developer.nvidia.com](https://news.developer.nvidia.com/mit-builds-robot-that-relies-on-ai-to-play-jenga/)
进化的另一个要素呢,突变?
对于人工智能来说,这可能是最不具挑战性的一个,随机性已经得到了广泛的研究,我们已经可以在随机数生成过程中很大程度上结合自然随机性。对于计算机来说,生成数百万个随机数并不一定具有挑战性。
在机器学习中,我们已经有许多工具用于比随机性更好的改进,梯度下降自 40 年代以来就已经可用。Geoffrey Hinton 为深度学习提供的部分突破是反向传播,它允许我们更有效地改变参数值。这意味着人工智能的进化已经快于自然进化,自然进化中突变大多是随机发生的。
“圣杯”是从根本上改变核心算法,不仅仅是算法使用的参数值或超参数,这到目前为止还不实用——尽管研究人员正在朝着它大步前进。
一些技术已经出现了。即随机添加层、添加节点、添加退出或其他“技巧”,随机选择和应用某些数据预处理或数据工程方法。如果与智能工程相结合,我们实际上非常接近于允许某种程度的自我变异人工智能算法来计算出一套更广泛的技能。
但是更多突破性的技术即将出现,例如:
自从上个月发布以来,OpenAI 的 GPT-3 由于各种原因一直在新闻中出现。从最大的…
analyticsindiamag.com](https://analyticsindiamag.com/open-ai-gpt-3-code-generator-app-building/)
虽然这些目前还很初级,但人工智能领域的进步无法用我们的常识时间尺度来衡量。如果我们找到了将代码生成效率与最终结果改进联系起来的方法,那么代码生成即使是随机的也会非常有趣。
真正能让 AI 进化超高效的是丢弃能力较弱模型的低成本。
我们可能没有注意到,但这实际上一直在发生——我们一直在丢弃不太想要的模型。丢弃不太合适的算法或模型的成本接近于零——主要是计算的时间和能量成本。真正昂贵的部分实际上是研究人员的时间和用于运行算法的更快的计算机。
鉴于该领域的一些进展,我们可能会更接近于将研究人员从保姆式人工智能培训中解放出来。这将进一步降低“花费在次优模型上的时间”的成本,并使人工智能进化的整体成本更低。
虽然今天的顶级硅仍然需要人类研究人员的努力,但人工智能已经是其中的一大部分,纯人工智能设计的硅对许多领先的头脑来说是可以想象的。一旦我们允许芯片(以及可用于芯片制造的资源)由芯片的性能来评估,而不是(或至少除了)芯片的商业成功,人工智能设计的芯片可能会比市场选择的芯片发展得更快,至少在性能方面。这意味着人工智能进化的速度可能比我们想象的要快得多。不幸的是,我们对进化速度的想象是基于我们祖先所经历的,这可能与人工智能将经历的有许多不同的数量级。
通过自学,AlphaZero 几乎可以做任何棋盘游戏,这涉及到一些非常复杂的算法,丢弃能力较弱的策略(又称参数),以及其他一些改进,它在几周内自学了围棋,超过了人类数千年积累的游戏策略。
但更重要的是,我们可以将 和 的突变和选择过程联系起来,减少,甚至消除人为干预的必要性。这意味着人工智能的独特性可能通过进化来实现,不需要太多人工智能。
实际上,人工智能很有可能成为超级人工智能,并在解决我们可以设计的任何问题方面超越人类,然而,它可能不具有我们可以识别的一般智能。
如果你看看今天的语言模型,NLP 已经可以比 99%的人类更好地进行语言之间的翻译。语言模型甚至可以比大多数人更好地生成像新闻文章、小说或诗歌这样的作品。今天的语言模型其实根本不懂人类语言,至少对于我们能领悟的,他们不懂。如果您感兴趣,请查看我的另一篇关于 NLP 中的语法和语义的文章:
艾哲学随笔提炼语文房思想实验——聪明的人沟通不明白…
towardsdatascience.com](/a-chinese-speakers-take-on-the-chinese-room-88a0558b2cc8)
似乎没有 AGI,人工智能也能通过图灵测试已经成为智能研究者的共识。更大的问题是假设 AI 自我进化可以在我们有 AGI、之前起飞,它会进化成 AGI 吗?我相信答案是是的。
假设人工智能的自然选择安排涉及现实世界,人工智能将不可避免地进化成学习物理定律,而能量守恒将被人工智能视为一种‘生存’优势。这意味着人工智能将很快搞清楚个人、群体和他人,并可能学会合作和竞争的策略。它会变得有自我意识,以恰当地平衡能量守恒和进化速度,这一事实表明它可能会变得有意识。
然后它会用它的意识智能地设计自己的未来吗?有可能,但很可能它不会放弃进化,考虑到单一路径改进策略的风险可能会导致一个无论智能体有多聪明都无法通过纯智能解决的死胡同。
这可能不是我们人类需要担心的。这篇文章的主要观点是 AI 奇点可能不依赖于【AGI】,它可能在人类创造出 AGI 之前就起飞了,而仅仅是更好的变异速度、结合淘汰不适合的低成本和被自然选择的能力,就足以踢掉可能成为奇点的 AI 自我进化。
如果是这样的话,也许努力创造一个与(比随机的)突变相联系的自然选择循环是一条更有可能通向奇点的道路,而 AGI 可能不会成为它的路障。
情景喜剧自然语言对比
视觉化和模型化在电视喜剧中的应用
这是没人要求的分析。我们能通过使用自然语言处理来比较当代一些最大的美国情景喜剧的剧本学到什么吗?
我尽可能多地收集了我能找到的大型情景喜剧的剧本:老友记、弗雷泽、威尔和格蕾丝(第 1 至第 8 季)、办公室、宋飞、已婚并有子女(部分季)、以及 Scrubs (第 1 至第 5 季)。感谢所有粉丝网站如此彻底地抄录了这几集。经过一些处理,舞台和语调方向被删除,留下了每行一行的格式的每集剧本,其中有人物说话和口语文本。我在这上面花的时间远远超过了合理的时间。
行统计和最有特色的词
这里显示了一些表演级别的统计数据。Medium 不做 HTML 表格,但是用 R 的 formattable 生成这个导出版本,至少让我看到了这篇文章展示了迷你图是如何包含在其中的。

《Scrubs》和《Frasier》每集包含了最大的词汇量;前者可能得益于医学术语的使用。与其他剧集相比,《宋飞正传》涉及了相对更多的名词和更少的动词(使用 spaCy 的词性标签识别)。这与《老友记》、《威尔》和《格蕾丝》是“无所事事的表演”相符吗:《老友记》、《威尔》和《格蕾丝》更受叙事驱动,包含更多描述角色做某事的动词,而在《宋飞正传》中,他们谈论的是抽象的东西,而不是做事情。迷你图按剧集和季节显示每集出现的人物数量的中位数。《办公室》和《丛林》每集都有比其他剧集更多的角色,而且《办公室》在以后的几季中也有所增加。
使用词频逆文档频率(TF-IDF ),在排除了角色的名字(这些名字很常见,但只在一个节目中出现)之后,我们可以看看每个节目中所说的一些更“独特”的词。这些词在一个节目中经常出现,但在其他节目中却不常见:

许多得分最高的术语都是次要人物的名字或其他没有被删除的名字,这并不奇怪,但该方法也挑选出一些真正代表一部电视剧的术语,如“地区”、“雪利酒”和“外科手术”。单词“will”在几部剧中出现,因为它不被、《滚雪球》词典视为停用词(但不会出现在 Will 和 Grace 中,因为它是主要角色的名字)。
字符语音模式
为了对每个字符的词汇有所了解,下面我显示了字母的平均单词长度,以及使用的独特单词数与总单词数的比率(都包括停用词)。两者都是按季节计算的,只使用每个角色说出的前 5000 个单词,并进行(加权)平均,以避免将唯一单词与总单词的比率偏向某些季节中剧集数量较少的剧集,或者每季台词数量较少的角色(因为说出的单词越多,就越难避免重复单词)。只有平均每季至少 3000 字的人物才纳入剧情。

倾向于使用最长单词的人物是凯尔索医生和考克斯医生(可能是因为他们使用了医学术语)、德怀特和奈尔斯,而雷切尔、乔伊和格雷斯倾向于使用最短的单词。单词长度和词汇量呈正相关,但也有一些偏离,主要是通过显示,Frasier 和 Seinfeld 显示了相对于他们的词汇量更长的单词(名字位于虚线上方),Will 和 Grace 以及已婚并有子女的情况相反(名字位于虚线下方)。
显而易见,每部剧中的角色都非常集中,尤其是《老友记》、《宋飞正传》和《已婚并有子女》中的角色。如果上面情节中的人物是真实的人,我们可能会认为他们的说话方式是随机分布在各个节目中的,也许会有一些聚集在一起,这是因为他们自己选择了一群教育水平相似的朋友。这里看到的聚类可能反映了编剧的偏见,他们同时为剧中的所有角色写作。这也可能是因为每部剧的风格不同,比如《纽约二十多岁的年轻人》或《在医院里》。公平地说,Frasier 和 Scrubs 展示了沿着主对角线分布的人物,展示了一系列的说话风格或教育水平。

我计算了一个文档术语矩阵,计算的方法是计算每个角色使用所有七部电视剧中最常见的 300 个单词的次数。上面的网格显示了矩阵中每对行之间的相关性。每个节目中使用的语言的相似性可以被看作是沿着对角线的高度相关的方框。成对人物之间的相关性最高的是弗雷泽和奈尔斯、菲比和瑞秋、威尔和杰克,而相关性最低的是弗雷泽和达里尔、奈尔斯和达里尔。最独特的声音(与所有其他角色的平均相关性最低)是凯尔索博士、弗雷泽和达里尔。

当在主成分(PC)轴上绘制该文档-术语矩阵时,字符按节目分组在一起,并且朋友以某种方式不同于其他节目而突出(在 PC 空间中更孤立)。从上面的表格中也可以看出,马西和佩吉与弗雷泽的角色有着惊人的相似之处。吉姆和帕姆实际上是一样的:)在这里的人物语言中没有发现明显的男性/女性模式。从我们之前看到的,我们可以推断第一个 PC 轴(左右)大致对应于较长单词的使用频率。
性格情绪
每一部剧中人物语言的情感都是用 NRC 词典通过区分标记为“积极”和“消极”的单词分数来评分的。《漂亮的包裹》让我们看到《威尔和格蕾丝》平均来说是最“积极”的剧集,而《宋飞正传》和《实习医生格兹》(也许令人惊讶)则是最消极的:

使用 VADER 复合极性分数(未显示)重新计算得到了相当相似的结果,只是节目排名有一些变化。
NRC 还为我们提供了几种特定情绪的得分:实习医生,已婚有子女,威尔和格蕾丝在“厌恶”上得分最高;《欢乐》上宋飞远远低于其他人;在“悲伤”方面,Scrubs 得分最高,Friends 得分最低。这可能在某种程度上受到每个节目中使用某些喜爱的和/或俚语的影响。一些字符似乎比其他字符更一致地“击中”NRC 词典中的单词:例如,Turk 出现在前三个字符中的“喜悦”单词的分数和中的“悲伤”单词的分数。
质量指标
最后,是否可以用剧本文本信息来推断一集的好坏?对于剧集质量的最客观指标(事实上,这似乎是唯一可用的),我使用方便的 IMDbPY 包提取了每集的 IMDB 评分。
这些评级准确吗?它们至少抓住了一部剧的质量从第一季到第二季逐渐提高,到第五季左右逐渐下降的总体感觉:

然而,收视率中有一个很强的——可能太强的——“作秀”成分。《老友记》(8.46)和《宋飞正传》(8.44)的平均评分最高,而弗雷泽(8.01)在七部影片中排名第五,这很难证明。值得注意的是,我们的预测模型发现的“好”集可能会倾向于《老友记》或《宋飞正传》中的内容,而不是《弗雷泽》中的内容;虽然我们也将努力控制平均收视率之间的差异。
我为每集推导了几个统计数据:行数、每行平均字数、平均字数、至少三行的字符数、独特字数;其中一些已在上面显示。名词与动词和名词与形容词的比例,每个主要角色说的台词的比例,以及最终的术语频率(100 个常用词和二元模型),也作为特征包括在内。我将剧集随机分为训练和测试,并使用 scikit-learn 拟合简单的广义线性模型(GLMs )(因为我的兴趣是解释系数)。

从前面的图中我们可以看出,按显示(模型 B)而不是整体(A)预测训练集均值给出了更好的基线(较低的 RMSE)。与此相比,文本摘要术语,连同节目和季节(作为数字),确实显示了少量的预测技能。模型 C 包括每行平均单词和平均单词长度的显著负系数,这意味着这些术语越大,剧集的平均评级越低。它还适用于季节的负系数,以及每集独特字数的弱正系数。
名词和动词的比率大约是 0.6-0.8;《宋飞正传》最高,《老友记》最低。该模型发现,在控制了该剧之后,这个词的值越高越好,平均而言,《宋飞正传》比《老友记》高出约 0.1 个评分点。这是否揭示了“优秀写作”的一个基本要素?我不确定。名词-形容词的比例并不能预测疾病发作的等级。
字符线分数提供了进一步提升,当添加到显示条款(模型 D)。从理论上讲,这些系数告诉我们,在每部剧集中,哪些角色在被认为是更好的剧集中出现得更多或更少;换句话说,观众喜欢或不喜欢的角色。迈克尔、达芙妮、奈尔斯、莫妮卡、罗斯(!),乔治,还有克莱默。Pam,Erin,Jerry 的系数显著为负,Cox 和 Marcy 的系数略有下降。显然,在其他条件相同的情况下,更好的《宋飞正传》中有更多的乔治或克莱默,而更少的杰瑞。
包括词袋术语频率并没有改善模型,这可能并不奇怪,因为这可能意味着有一些“神奇”的词仅仅通过出现在抄本中就可以提高剧集评级。仅使用这些术语的模型确实击败了基线 A,但没有击败基线 B,这可能是因为它选择了将一个节目与另一个节目区分开来的词(例如,“办公室”、“同性恋”、“博士”)。
从一开始,我就希望神经网络模型(an LSTM )能够“阅读”剧集脚本,并学习根据单词序列预测剧集评级:本质上,学习什么是好的和坏的情景喜剧写作。当我只在的脚本上训练这样一个模型来预测评级,将剧集分成场景,并为每个场景分配总的剧集评级(给出 8000 个训练行),它确实展示了一些技能(模型 F),这可能会通过改变模型架构来改进。但是,当我试图做同样的事情来预测模型 C 的残差(预测误差)时,LSTM 无法提取任何进一步的信号。这可能意味着,F 型机器人通过提取关键词来区分不同的节目,使它的表现达到了 B 型机器人的水平,但除此之外,它并没有从文字记录的句子中学到任何有意义的东西。**
这些对我们写一集好的情景喜剧有帮助吗?大概不会。但是模型中的一些术语可能会被用作作家的指南,如果它们可以在节目还在进行的时候被计算出来的话;特别是角色片段,尽管可能有比从几十集的收视率中提取信息更直接的方法来衡量观众对角色的看法。名动比的发现很有意思:我不知道这是不是以前在语言学中研究过的概念;这只是我认为要计算的一个简单的显示级文本指标。
利用移动性数据优化市场覆盖的站点规划
利用人员流动数据确定最佳位置
近年来,面临倒闭的实体店数量激增。在零售领域,这种现象被称为零售末日,但银行等其他行业也受到了影响。然而,这种零售业的末日并没有影响到所有的零售商和,一些在线零售商甚至宣布计划开设他们的第一家实体店。在这种背景下,在决定保留或关闭哪些商店以及决定在哪里开设新店时,考虑这两种情况下的自相残杀比以往任何时候都更重要。空间数据科学技术是应对这一挑战的关键。

在这篇博客文章中,介绍了一个案例研究,其中一家银行有兴趣在西班牙南部的塞维利亚省、加的斯省和马拉加省进行扩张。考虑到他们的经济和商业环境,他们只计划开设 10 个分支机构,他们希望找到尽可能多的人可以接触到这些分支机构的位置。因此,我们的工作重点将是确定吸引最多游客的 10 个地点,同时尽量减少分店之间的相互蚕食。人员流动数据是我们方法的核心组成部分。
这个案例研究提出了两个主要困难:
- 计算缺少历史客户数据的位置的集水区。拥有这些集水区对于模拟分支之间的潜在自相残杀是必不可少的。
- 确定最佳位置。这是一个组合优化问题,这意味着即使对于小的实例,计算上也很难解决。
确定 10 个最佳位置的方法将在接下来的章节中详细介绍。遵循的主要步骤是:
- 数据发现确定本案例研究的相关数据。
- 支持(网格)选择和细胞富集在发现阶段识别的数据,主要是人员流动、社会人口统计和商业数据。
- 选定单元子集的集水区计算。通过应用用于识别具有高商业潜力的细胞的过滤器来获得该细胞子集。对于这一步,我们将使用在之前的博客文章中解释的基于人类移动数据的方法。
- 优化算法确定 10 个最佳位置。在算法的每一步使用贪婪方法和线性规划来开发近似算法。
1.数据发现
对于数据发现,我们利用 CARTO 的数据观测站中可用的位置数据流和 CARTOframes 中可用的丰富工具包,以便我们可以轻松引入来自人员流动、社会人口统计、金融和其他数据类别的功能。
由于银行分支机构在人流量较大的地方利用率较高,并且商业活动频繁,因此我们确定了以下相关数据:
- 人员流动:客流量和起点-终点矩阵(来源:沃达丰分析)
- 兴趣点(来源:Pitney Bowes)
- 商业密度指数(资料来源:Unica360)
- 社会人口统计和社会经济数据(资料来源:Unica360)
下面的仪表板显示了使用的一些数据。
2.支持选择和细胞富集
我们方法的基础是使用沃达丰分析公司的人员流动数据。因此,我们选择沃达丰的 250m x 250m 单元网格作为参考网格来投影所有其他功能。
在下面的地图上,您可以看到网格和重点区域(塞维利亚、马拉加和加的斯)。
图一。该图显示了焦点区域和候选细胞
我们丰富了网格,如以下部分所述:
人类移动数据
沃达丰分析数据提供了对访问覆盖整个研究区域的任何 250m x 250m 网格单元的人数的洞察。沃达丰对网络中测量的数据进行匿名化、聚合和外推,以提供代表整个国家和国际人口的见解。此外,该数据还提供了根据到目标像元的距离在不同级别聚集的访问者的来源。单元格中包含来自该来源的以下数据:
- 访客总数
- 按来源和活动分列的访客总数
- 缓冲区内距离像元质心的像元中访问者的平均数量
图二。这张 choropleth 地图显示了塞维利亚市从每个起点到一个目的地的标准化游客数量。
商业活动数据:兴趣点(poi)
该数据集提供了相关兴趣点的信息。单元格中包含来自该来源的以下数据:
- 距离小区质心 250 米缓冲区内的竞争者数量。
- 距离单元质心 250 米缓冲区内的 poi 数量。这里我们使用兴趣点作为商业活动的代理。
商业活动数据:商业指数
该数据集提供了一些商业指数(综合、零售、医疗保健等。)由范围从 0 到 1 的标准化商业活动值组成;0 表示商业活动非常低,1 表示商业活动非常高。
单元格中包含来自该来源的以下数据:
- 普通商业指数
- 酒店商业指数
- 零售指数
- 公共交通指数
- 保健指数
社会人口和社会经济数据
该信息在 100 米 x 100m 米的网格上提供。数据聚合被放大以适应 250m x 250m 单元网格,应用面积插值。单元格中包含来自该来源的以下数据:
- 人口
- 平均家庭收入
- 在目标单元工作的人数
3.过滤和构建集水区
一旦丰富了网格,在计算集水区之前,我们通过应用过滤步骤来缩小搜索空间,以便仅考虑具有高商业和经济潜力的单元来开设分支。
过滤使用以下标准,每个标准都有预定义的阈值:
- 距离单元质心 250 米缓冲区内的访问者数量。在同一缓冲区内存在竞争对手时,该最小值会增加。
- 250 米缓冲区内的 poi 数量。
- 零售强度指数。
- 平均家庭收入。
- 在目标单元中工作的人数
- 人口
在分析了具有不同阈值的不同场景,并可视化它们以检查基于我们对焦点区域的了解的一切是否有意义之后,我们在这六个标准上设置了以下切割。

图 3。应用于过滤的阈值。这些图显示了标准变量的分布以及为每个标准变量选择的阈值。注对数转换已应用于某些发行版。
因此,我们将搜索空间从超过 18,000 个初始单元格减少到 620 个。下图左侧显示了塞维利亚市周围区域的所有网格单元,右侧显示了过滤后剩余的单元。

图 4。左边是塞维利亚周围地区的参考坐标。右边是过滤后同一区域的剩余单元格。
最后,使用人类移动数据并遵循在之前的博客文章中介绍的方法,构建集水区。
4.位置-分配。最佳化
位置分配是一组优化算法的名称,这些算法侧重于确定设施点的最佳位置,以服务于一组需求位置。它们已被广泛用于各种行业,如物流部门寻找配送中心的最佳位置,零售部门寻找开设新店的最佳位置,电信部门寻找安装天线的最佳位置。
这里介绍的案例研究也是一个很好的位置分配问题的例子,其中一家银行希望找到 10 个位置来开设新的分支机构,从那里他们可以接触到尽可能多的人。这意味着找到游客数量最多的位置,同时尽量减少其集水区之间的交集,因为游客将只计入其中一个位置。集水区之间的这些交叉点将被视为成对位置之间的潜在自相残杀。
位置分配问题的这种特殊情况被称为最大覆盖问题 (MCP)。但是,我们与标准 MCP 有一个重要的区别,因为在我们的例子中,一个特定的起点可以有(大多数时候确实有)不同数量的访问者去不同的目的地单元。
位置分配问题是组合优化问题,众所周知,即使对于小实例也很难解决。这是因为可能的解决方案的数量随着要考虑的候选位置的数量和要识别的最佳位置的数量而呈指数增长。

表 1。针对 620 名候选人的位置分配问题的不同解决方案的数量,取决于待选位置的数量。
左边的表格显示了可能的解决方案的数量,这取决于我们有兴趣在 620 个候选位置中找到的最佳位置的数量。
由于 MCP 问题的高度组合复杂性,通常使用近似算法,而精确算法仅用于问题简化版本的小实例。
文献中最常见的方法是贪婪算法,有时会跟随一些局部搜索启发式算法,以确保达到最近的局部最优。一些更高级的元启发式算法被设计成能够避开局部最优,但是它们的复杂性随着每次迭代中允许的并发交换数量而增加。因此,大多数情况下,这些更高级的方法只允许每次迭代进行一次交换,这使得探索解决方案空间中的遥远区域变得更加困难。
该算法
我们设计的解决这个问题的算法遵循一种贪婪的方法,在每次迭代中使用线性规划,以增加找到更好的局部最优解的机会。单交换局部搜索试探法被应用于找到的解决方案,以确保我们处于局部最优。
你可以在的上一篇文章中读到更多关于线性编程的内容。
初步考虑
基于以下事实,使用对问题的简化来设计算法,即在所选位置的三个汇水区内具有原点比在两个汇水区内具有原点更糟糕(即,更有可能发生自相残杀)。更一般地说,原点在所选位置的 n 集水区内比原点在 n-1 或更少的集水区内更糟糕。
这个事实允许我们仅考虑成对的交集来解决问题,这显著地降低了复杂性。10 个选定位置所覆盖的潜在客户总数是这样计算的:将每个集水区的游客独立相加,然后减去每个两两交叉路口重复计算的游客。这种计算会根据包含多边形的集水区的数量,为位于多个集水区内的原始多边形指定一个递增的惩罚。

图 5。代表三个集水区之间不同可能交叉点的文氏图。
左侧的示例旨在显示在计算有无上述属性时,潜在客户的计算差异。在本例中,我们有三个选定的位置、它们的集水区以及它们之间的交叉点。
潜在客户的数量计算如下:
- 未使用遗产:来自三个集水区的游客人数,减去来自 5、6 和 3 的游客人数(因为他们只应被计算一次),减去来自 7 的游客人数的两倍(2x)(因为他们位于三个集水区的交叉点,但只应被计算一次)。
- 使用属性:来自三个集水区中每个集水区的访问者数量减去来自 5、6 和 3 集水区的访问者数量(因为它们在一个成对的交叉点内),减去来自 7 集水区的访问者数量的三倍(3x)(因为它们在三个成对的交叉点内)。
算法描述
如上所述,我们遵循贪婪的方法,在每次迭代中应用线性规划。贪婪算法包括在每次迭代中选择 3 个新位置,允许在先前迭代中选择的位置之一被改变(即,允许一次交换)。下面你可以找到这个贪婪算法的伪代码:

每次迭代求解的线性规划模型如下所示。

使用 Google 或-Tools 求解线性规划模型,这是一个强大的优化求解器包装器,允许连接到各种商业和免费求解器。
为了提高算法的效率,我们将变量 Xjk 定义为连续的,并且我们只惩罚那些其交集包含来自两个位置的超过 10%的访问者的位置对。可以通过以下方式实现进一步的改进:
- 计算一个初始解(例如,用一种纯粹贪婪的方法)和:
(a)用它作为一个热的开始。
(b)使用具有最低游客数量的位置的游客数量作为线性规划模型的下限。 - 在贪婪算法的每次迭代之后应用一些局部搜索试探法。
结果
在对不同的 f(增加因子)和 k(自由度)值运行优化算法后,我们获得了下图所示的解决方案。我们获得的最佳解决方案的潜在客户总数为 3,223,552 。
下图显示了所选位置及其集水区。
图 6。在地图上标出为开设新银行分行而选择的 10 个地点及其各自的服务区。
如果我们分析 CA 所选位置的集水区覆盖了哪些城市(见下图 7),我们可以看到所有人口超过 50,000 的城市至少都在该位置的一个集水区内。此外,可以观察到,一个城市的人口越多,覆盖他们的集水区的数量就越多。

图 7。按 0、1、…、4 集水区覆盖的人口范围划分的城市比例
为了评估 CARTO (CA)开发的算法的质量,我们将使用我们的算法与通常用于解决位置分配问题的标准贪婪算法(SGA)获得的结果进行比较。SGA 在每次迭代中找到一个新位置,并考虑与已选择位置的交集来更新未选择位置的潜在访问者的数量。该算法不允许交换。
SGA 所选地点的集水区覆盖的潜在游客人数为2884347。这意味着 CA 可以通过增加大约 340,000 访客来改善这个结果,这代表了额外 11.75%的访客。
下图显示了两种算法所选位置的集水区。这些区域标绘在参考网格上,每个单元格中的访问者数量用颜色表示。可以观察到的主要区别是,SGA 所选地点的一些集水区较大,覆盖了人口密度较低的地区,这意味着地点质量较低。这是因为在确定了最初的 5-7 个位置后,需要进行一些交换,以便找到新的高质量位置。但是,SGA 不会执行任何交换。

图 8。地图显示了使用 CARTO(左)开发的算法选择的 10 个位置的集水区,以及另一个图层上的标准贪婪算法(右),其中候选像元按游客数量着色。
进一步的步骤:计算位置的最佳数量
在这篇博文中,我们展示了一个选址案例研究,其中要开设的新银行分行的数量是事先知道的。通常,公司发现很难得出这个数字。这里介绍的方法也可以用来回答这个问题,只需对开发的优化算法稍作修改。
在这种情况下,必须知道将使用什么标准来确定最佳位置数量。一个可能的标准是市场饱和。市场饱和可以被定义为一个阈值,使得如果当增加一个新位置时覆盖的新的潜在客户的数量低于该阈值,则达到市场饱和。
例如,对于 5%的阈值,我们知道最佳位置数是 10,如下图所示。

图 9。通过增加新地点来增加潜在客户的数量。市场饱和的阈值为 5%。
CARTO (CA)开发的算法在这个问题上也表现出比 SGA 更好的性能。根据所选位置的数量,我们可以在下面看到潜在客户的数量。我们可以看到,对于少量的位置,两种算法具有非常相似的性能,随着位置数量的增加(因此问题变得更难解决),CA 的性能优于 SGA。这意味着 SGA 将在 CA 之前达到饱和点,失去市场潜力。

图 10。两种算法覆盖的访客数量取决于新位置的数量。
具体来说,我们可以看到 CA 的表现比 SGA 高出 30%,具体取决于为市场饱和度设置的阈值。

图 11。CA 与 SGA 的性能改进。
结论
今天,影响零售和其他行业的挑战性环境使得他们必须使用技术和工具,使他们能够做出明智的决策,并从竞争对手中脱颖而出。
通过其他数据流丰富的人员流动数据,以及优化和其他空间技术的使用,将在应对这些部门目前和未来面临的挑战时发挥重要作用。
本文原载于 CARTO 博客 。
特别感谢Mamata Akella,CARTO 的制图主管,对她在本帖地图创作中的支持。
使用优化技术选择站点和最佳路径——加拿大邮政示例

来源—https://developers . Google . com/maps/solutions/images/store locator _ clothing . png
在本文中,我们将关注快递服务行业(加拿大)。这个行业总是需要降低运营成本。要做到这一点,公司在选择新站点的位置和寻找送货车的最佳路径以降低与燃料和时间相关的成本时经常面临挑战。
关于行业
快递服务行业包括两大部分,即大型快递公司和小型快递公司。加拿大 2019 年的总收入为 128 亿美元,5 年年增长率为 3.5%。该行业预计将在未来五年内增长,因为可支配收入的提高使消费者越来越愿意购买商业商品,其中大部分与电子商务相关。原油价格的预期上涨也将使这些公司通过优化其交付绩效来获得更多利润。
供应链和主要参与者
在市场生态系统中,加拿大的快递公司构成了一级买家和供应商之间的桥梁。请参见下图,了解供应链。

图 1:加拿大快递服务的供应链流程
下表 1 显示了加拿大的主要参与者(2019 年)。尽管通过合并和收购扩大了经营范围,但行业内的总体市场份额集中度有所下降。

表 1:快递服务主要参与者的市场份额(加拿大——2019 年)
加拿大邮政和联合包裹服务公司(UPS)是该行业最大的两家公司。加拿大邮政拥有 33.5%的市场份额,与加拿大边境服务局和中国邮政等其他实体有着强大的合作关系,这使得该公司的包裹收入和数量显著增长。由于劳动力中断,该公司经历了增长下滑,因此需要提出高效的成本规划模型来降低运营成本。
另一方面,UPS 依靠机群长距离运输包裹。航空运输确实加快了这一过程,但反过来也导致客户支付高额费用。UPS 在加拿大拥有超过 14%的市场份额,由于新设施和新技术的上线成本,预计运营利润将会下降,因此也需要优化 UPS 的运营成本。
快递业供应链面临的挑战
从现在开始,我将缩小范围,专注于行业内的交付性能优化。
运营挑战
快递公司面临的共同挑战是递送包裹的站点之间的时间窗口、车辆的存储容量、燃料容量和充电要求、车道驾驶规则、司机的午休时间和客户对订单接收时间的偏好。还有其他约束,如劳动法和周末送货,但这些都超出了本文的范围。
使用线性规划的约束公式
配送性能问题是车辆路径问题族的一部分。为了清楚地解释这个问题,我使用了一个线性规划模型,这些问题的简单版本包括公司减少燃料费用/行驶距离的目标。在实际场景中,目标还包括最小化使用的车辆数量和平衡工作量。为了简化模型,我只考虑了加拿大邮政在蒙特利尔的一辆送货车。
目标函数为:
最小值(σ行驶距离/燃油成本)
受约束:
- 货车的起点和终点位置是相同的
- 货车只行驶一次
注意:有时,约束条件不允许问题形成凸空间让优化算法收敛到一点。因此,我们应该根据问题陈述使用强制约束。像进化这样的求解方法比 GRG 非线性和单纯形表现更好。
加拿大邮政问题图解
我选择了蒙特利尔市的 10 个地点,考虑到他们有很高的需求。下面的表 2 列出了位置名称以及地址和其他位置信息。

表 2:为说明问题而选择的位置
您可以在下面的地图上看到这些位置:

图 2:地图上为问题图示选择的位置(来源——谷歌地图)
问题 1:找到最佳位置
有关问题,请参考表‘最佳位置’(最后的下载链接)。
在这个问题中,目标(目标函数)是最小化运输的燃料成本。给定的 9 个客户位置是高需求的位置。位置数据(也提供了纬度和经度)。任务是找到开店的最佳地点,使货车的行程(每个地点两次——去商店和回来商店)对企业来说成本最低。请注意,这个问题不考虑到一个位置的道路路径。这个问题的最佳解决方案是基于地球弧度距离的几何计算距离。
在 Excel 规划求解器中使用 GRG 非线性方法找到最佳位置,使用强制约束允许算法收敛到最小值。针对此问题找到的最佳解决方案如下所示:

图 3:根据红色给出的位置,开新店的最佳位置(来源——谷歌地图)
问题 2:旅行商问题——寻找最佳路径
这个问题参考【最佳路线】表(最后下载链接)。
在这个问题中,目标(目标函数)是最小化行进的总距离(以米为单位)。表 3 显示了来自谷歌地图的数据,给出了四舍五入到最近的百分之一米的距离。请注意,这个问题考虑的是使用谷歌地图测量的最短道路路径。由于车道限制,这些数字在数学上没有关系。这个问题有两种情况:第一,送货车可以从任何地方出发,第二,送货车应该从加拿大邮局出发。对于这个问题,我获取了加拿大邮政在蒙特利尔的一个现有商店的位置数据。图 4 和图 5 显示了两种场景的结果

表 3:位置代码

表 4:位置之间的距离(以米为单位)
场景 1 结果:

图 4:场景 1 的最佳路径——货车可以从任何地方出发(来源——谷歌地图)
场景 2 结果:

图 5:场景 2 的最佳路径——货车从加拿大邮政出发(来源——谷歌地图)
从这个分析中一个有趣的发现是,如果货车必须从加拿大邮政出发,算法表明它应该首先去德绍特尔管理学院,而不是 La Marq。事实上,La Marq 距离加拿大邮政只有 700 米,但由于我们考虑了车道驾驶法,该算法会建议最佳路线,否则会显得荒谬。
我对快递业的看法
快递公司需要专注于降低运营成本,因为他们的利润与政府政策等超出他们能力的因素有关。他们唯一能控制的就是优化他们的成本。在激烈的行业竞争中,越来越需要找到更好的算法来实施最佳实践以降低成本。这些问题陈述中的大多数属于车辆路线问题(VRP)和带时间窗的车辆路线问题(VRPTW)。这些问题有时会变成 NP-Hard,需要大量的计算来达到最优解。数据驱动的公司将在未来几年主导市场。
离别笔记
有一些高级的算法,如带有贪婪插入的平衡聚类算法和通过扩展插入算法的路线改进,有时在凸形问题中使用启发式算法来达到最优最小值。然而,这类问题在计算和技能集方面都需要大量资源。没有公开可用的基准,有时解决方案并不理想。有时,我们还会寻求“视觉上有吸引力”的解决方案,即考虑如何将站点分组到路线中。多辆车路线重叠的解决方案通常被认为在视觉上不如其他方案吸引人。
参考
- 宜必思世界报告| 49222 加拿大快递和本地递送服务| 2019 年 10 月
- 废物管理的路线优化:Surya Sahoo,Seongbae Kim,Byung-In Kim,Bob Kraas 和小亚历山大·波波夫。
- 加拿大邮政包裹电子商务发展战略分析
参考文件(下载 excel 文件)
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/chandravenky/Optimization/blob/master/Canada Post location problems.xlsx)
坐在一堆数字黄金上
如何利用你已有的资源改变你的组织!

安德烈·尼希尔在 Unsplash 上拍摄的照片
暂停一下。想想你的组织;在脑海中想象你的过程,并对你收集的所有数据进行快速盘点。它可能是表单上的涂鸦,也可能是数据库中的记录。我打赌你有很多。现在,请更深入地思考您的操作以及您没有捕获的所有数据。它可能包括走进你的商店的人的名单或者你的送货车的位置。我很确定你能想到大量未捕获的数据。
T4:你是否意识到你正坐在一堆数字黄金上?
最糟糕的是,很有可能,你并没有对你的数据做很多事情。您可能会在这里或那里生成一个报告,但差不多就是这样。当然,这是一个被错过的机会,因为只有通过度量您的过程,您才能有效地管理它们。在这个时代,数据被许多人认为是新的黄金,因为它是我们智能软件的主要燃料。它是高度的,无孔不入的;你可以从任何地方收集信息,随着数字设备的激增,信息的可用性也在增加。就在两年前,世界上 90%的数据甚至还不存在!正因为如此,我们今天面临的问题是多方面的。

首先,我们每天都在创建大量数据。电脑、可穿戴设备、移动设备和各种传感器每天都在产生 2.5 万亿字节的数据。想象一下这个规模,如果我们有 250 亿分之一便士,我们可以覆盖整个地球表面五次!当你产生如此多的数据时,问题就转移到如何管理这些数据上,这就是人工智能(AI)发挥作用的地方。处理它的唯一方法是使用能够消化大量数据、识别模式并理解它的人工智能算法。
以制造业为例,有数百台机器同时运行。他们产生的数据量是巨大的。只有人工智能能够对其进行实时分析,提出规范的维护建议,预测未来的故障,并自主优化工厂的运行。

在 Unsplash 上由 Adeolu Eletu 拍摄的照片
第二,并不是所有的数据都适合计算机。互联网上大约 80%到 90%的数据是非结构化数据,因此在计算机使用之前需要进一步处理。再一次,即使人工智能远非完美,但它可以自动处理这些非结构化数据。
股票交易员监控本地和国际新闻,试图预测市场的波动。但是有数百个新的频道,其中一些是官方的,而另一些不是。他们都使用自然语言(如英语、西班牙语、普通话等)。)它是非结构化的,机器无法理解。正因为如此,人工智能系统可以实时解析不同的新闻,翻译文本,对其进行总结,并提取新闻的极性,从而为股票交易员提供市场对特定新闻的反应的良好指示。

第三,互联网最大的弊病之一是缺乏可靠或值得信赖的数据。同样,检查这些数据的唯一方法是使用自动化技术。
报纸需要从各种新闻来源中收获故事,区分真假新闻并不总是那么容易。自动化系统能够以很高的准确度做到这一点。他们可以快速识别新闻条目的来源,将其与可靠来源列表进行比较,从文本中提取片段,并通过其他在线来源验证其完整性。

帕克·科夫曼在 Unsplash 上的照片
第四,数据的产生以光速发生。此外,您永远不会有单一的数据源,但是您必须同时处理多个实时数据源。
想象一下,如果你在运营一个闭路电视摄像头网络。让一个人观看所有的提要是缓慢、无聊、容易出错和乏味的。但人工智能可以全天候实时分析各种信息,从而迅速发出警报。

在 Unsplash 上由Kenan süleymanolu拍摄
第五,数据本身没有价值。在这个充斥着稀疏数据源的世界里,只有当我们用其他信息扩充数据并正确使用它时,数据才变得有价值。
如果没有摄像头监控交通状况并决定何时关灯,自动交通灯系统就没有多大用处。但是摄像头系统和智能交通信号灯的结合让一切都变得不同,节省了通勤者的宝贵时间。

如您所见,数据在当今世界至关重要。我们已经看到了它的使用是如何提高流程效率、减少错误并为组织带来价值的。因此,如果你正坐在一堆数字数据上,不要让它积灰,因为如果你不使用它,你的组织就会错失良机。这就好像你有巨大的燃料储备,但你却犹豫要不要买车。不要浪费时间,咨询专家,探索你可以用这些数据做什么,大胆尝试,开始提升你的组织的引擎。
如果你喜欢这篇文章,并想与我联系,请这样做🐦推特,🔗 LinkedIn ,📷 Instagram 或😊脸书。
一本给没有人工智能背景的人的简明指南
towardsdatascience.com](/how-to-pump-up-your-business-using-ai-ff9d7edb1d77) [## 一个全新的人工智能世界
疫情之后人工智能的兴起
towardsdatascience.com](/a-whole-new-ai-world-6a5e9e49aa12) [## 重塑办公室之外的工作场所
如何在家中舒适地高效工作
towardsdatascience.com](/reinventing-the-workplace-beyond-the-office-3a41c42b426c)
阿列克谢·丁力教授 是马耳他大学的 AI 教授。二十多年来,他一直在人工智能领域进行研究和工作,协助不同的公司实施人工智能解决方案。他的工作被国际专家评为世界级,并赢得了几个当地和国际奖项(如欧洲航天局、世界知识产权组织和联合国等)。他已经出版了几本同行评审的出版物,并成为马耳他的一员。由马耳他政府成立的人工智能工作组,旨在使马耳他成为世界上人工智能水平最高的国家之一。
时间序列数据分析中的六个关键点
季节性图、滚动窗口、时间序列分解等

一幅画胜过千言万语
对,没错,一图胜千言;在数据科学中,一张图片可能胜过千言万语!
数据可视化是数据科学的基础,无论是用于探索性数据分析、构建更好的模型,还是用于可视化讲故事。仅仅通过目测箱线图或散点图,一双有经验的眼睛可以瞬间获得比阅读表格中的描述性统计数据更多的信息。
时间序列数据更是如此。很难想象没有时间序列图的时间序列分析。
下面我将展示六个这样的基本情节,并介绍如何创建每一个情节,解释并从中提取信息。我将在这个练习中使用 R,因为它是一个特别为时间序列分析设计的超级有用的库fpp2,你只需要几行代码就可以完成大多数绘图。
这是我们将要探索的情节:
- 一个简单的时间序列图
- 滚动窗
- 季节性绘图
- 亚季节图
- 时间序列分解
- 自相关(ACF)图
让我们卷起袖子吧。
图书馆和数据
做下面的视觉效果你所需要的就是fpp2库。它附带了必要的依赖项,所以一开始只使用一个库应该没问题。
要了解这个库的更多信息,这里有 Rob J Hyndman 和 George Athanasopoulos 的包文档和一本开放访问的书预测:原则和实践。
library("fpp2")
本练习的数据来自人口普查局存储库。该数据集包含从 1963 年 1 月到 2018 年 12 月每月售出的新独栋房屋数量。这些数据是以千套住房为单位报告的,没有经过季节调整。
读入后,需要进行一些格式化,以便fpp2包将它识别为一个时间序列对象。
# read in data
data = read.csv("../NewSingleFamilyHousesSold.csv", skip = 6)# drop "Period" column
data$Period <- NULL# rename column
names(data) <- c("value")# convert dataframe to a ts object
df = ts(data, start = 1963, frequency = 12)

从人口普查局检索的原始数据
情节#1:简单时间序列情节
一旦读入数据并将其转换成一个ts对象,第一个图通常是一个简单的可视化图,以获得数据的“感觉”。
autoplot(df[, "value"])+
ggtitle("Number of new single-family houses sold") +
xlab("Year") + ylab("Thousand units")

时间序列图的简单可视化
仅仅通过目测这幅图,你就可以得到很多提示——比如售出的房屋数量、季节性、趋势、周期、市场崩溃等等。我们将放大每一个以进一步了解。
剧情#2:卷窗
图 1 信息太多,有点嘈杂,所以我们需要简化它。只要用 12 个月移动平均线去除季节性因素,我们就能看到数据中的关键信号。
autoplot(ma(df, 12), series = "Moving avg.") +
xlab("Year") + ylab(" Thousand house units")

具有 12 个滞后滚动窗口的移动平均线
因此,通过牺牲季节性,我们可以更好地看到趋势和其他特征。
例如,在整个 70 年代和 80 年代,年销售量徘徊在每年 4-5 万台左右,大约有 5-6 年的商业周期。但是没有发现明显的趋势。
自 20 世纪 90 年代以来,市场呈上升趋势。这种情况一直持续到 2005 年,年销量超过 10 万台。
然后就发生了车祸。
自 2011 年以来,市场正在复苏。但截至 2018 年,仍处于 70 年代水平左右。
曲线#3:季节性曲线
在前面的图中,我们去除了季节性来检测关键信号。现在,让我们通过对全年每个月的销售额进行平均来专门放大季节性。
ggseasonplot(df, year.labels = TRUE) +
ggtitle("Seasonal plot")+ xlab(" ")+ ylab("Thousand house units")
我知道这看起来真的很丑,当然有办法用更多的代码来美化这个情节,但这不是我们所追求的。

显示每年月度趋势的季节性曲线图
再一次,通过目测,你可以看到三月是独户住宅市场的最佳月份。夏季市场还不错,但从秋季开始就开始下滑。
地块#4:亚季节地块
现在让我们做与图 3 相反的事情,将所有年份的平均值挤进每个月。
ggsubseriesplot(df) +
ggtitle(" Seasonal subseries plot") + ylab("Thousand house units")

显示全年每月销售额变化的分季节曲线图
它显示的是——在连续几年的平均值之后,新房销售每月是如何变化的。横条代表一年中每个月的平均值。
例如,3 月份的平均销量约为 6 万台,峰值为 12.5 万台。
地块#5:时间序列分解
正如我们已经看到的,时间序列数据有很多属性——趋势、季节性和随机(噪声)成分。
如果我们想看到所有的组件呢?我们可以通过所谓的“时间序列分解”来做到这一点。
df %>% decompose(type="multiplicative") %>%
autoplot() + xlab("Year") + ylab("Thousand house units")

时间序列分解有四个组成部分:数据、季节性、趋势和噪声
因此分解的输出有 4 层:顶层——原始数据;第二——季节性;第三——趋势;第四,余数/噪声。
时间序列分解通常有助于在一个地方一览无余。
曲线#6:自相关曲线
“Auto”表示自身——因此自相关是一个序列与其自身的相关性。在时间序列分析中,自相关意味着数据点对其过去值的依赖性。
例如,12 月份的房屋销售量并不是随机的,而是与 11 月、10 月及以后的销售量相关。
# auto-correlation plot
ggAcf(df, lag = 72)

显示不同滞后中自相关的 ACF 图
所以自相关图的目的是确定“自相关”可以追溯到多远。例如,在该图中,自相关直到任何数据点的前 51 个值都是显著的。
自相关图在高级时间序列分析和预测中是一种有用的技术——尤其是确定在 ARIMA 家族中用作参数的滞后数。
期末笔记
我们探索了六种不同的情节,每一种都表达了不同的信息。数据可视化是数据科学工具箱中必不可少的工具。不仅仅是为了讲故事,而是为了理解数据,理解关键组件,甚至调整模型参数。
希望这对 R 用户是一个有用的练习。Python 用户需要心灰意冷,盯紧了,来了。
从客户生命周期分析中获得的六大经验

照片由诺亚·帕森斯拍摄
在与各种业务团队合作后,他们中的许多人都试图加深对如何更好地锁定客户旅程中关键点的受众的理解。例如,营销人员需要决定如何调整信息传递和优化目标策略。保留团队需要知道如何主动重新吸引那些倾向于流失的客户,以及如何赢回那些已经流失的客户。产量优化团队想知道他们如何在降低服务总成本等的同时提高收入。
客户生命周期分析是一种数据驱动的方法,用于识别您的客户与公司产品和服务的关键接触点,并了解目标受众如何在整体上以及在其端到端客户生命周期的关键点采取某些行动。了解客户旅程中每个阶段的客户行为模式可以帮助业务团队及时制定明智的获取和保留策略,以优化收入和减少客户流失,并为内容和产品开发设定方向,以改善整体客户体验。在本文中,我想分享从客户生命周期分析中获得的六个关键经验。
确定客户生命周期中的核心指标

在分析领域工作时,你几乎找不到一个适用于所有垂直行业组织的单一分析框架。每个公司都有其独特的业务和运营模式。对于客户生命周期分析,第一步是对业务如何运作有一个坚实的理解。你应该与高管团队和商业领袖会面,了解什么对公司和他们的各个部门最重要。客户生命周期中的核心指标需要反映公司希望从客户那里获得的最大价值。改善核心业务指标将使整体业务实现可持续增长,同时观察该指标的下降趋势表明业务可能没有朝着正确的方向发展。
描绘客户生命周期的关键阶段
为了体验贵公司产品和服务的核心价值,您需要确定客户和潜在客户在其端到端旅程中经历的关键阶段。例如, Salesforce 营销云概述了典型客户旅程中的六个关键阶段,包括认知、获取、入职、参与、保留和宣传。盗版指标将客户生命周期分为五个关键阶段,包括获取、激活、收入、保留和推荐。请记住,您公司客户的客户生命周期阶段可能看起来与其他客户非常不同,简单地应用现有的方法可能不适合您的业务。
确定客户生命周期关键阶段的成功指标
在您确定了核心指标和客户在端到端旅程中经历的关键阶段后,您需要计算出客户生命周期中每个关键阶段的成功指标。由于客户行为可能非常复杂,并且您的客户和潜在客户产生的接触点数量和数据量可能非常大,因此您的业务团队可能会提出许多指标,他们希望数据科学或分析团队来衡量这些指标。有时,业务团队可能会要求您在他们希望花费更多时间或深入研究的非常精细的级别上查看客户的指标和属性。使用少量指标来总结客户生命周期绩效需要分析人员开发适当的指标框架来设置成功指标。度量框架需要确保更细粒度的度量能够支持业务团队,并帮助他们改进他们的关键成功度量。此外,跨关键客户生命周期阶段的成功指标应该相互补充,以帮助公司更接近整体业务目标。

胡玮炜摄
制定客户数据策略,实现实时数据采集
虽然您已经概述了客户生命周期的核心指标和一组成功指标,但您还需要制定适当的数据策略来整合和运营客户数据。与您的工程和商业智能团队一起构建客户数据字段,以确保客户数据在交易系统中准确可靠地流动。您还可以选择开发实时客户数据平台,将客户数据从交易系统整合到统一的数据库中。您需要与有能力的数据工程师合作,他们了解业务需求,并在此基础上准确设计和应用定义良好的业务逻辑,以计算客户生命周期成功指标,用于定期报告和分析。制定适当的数据策略将有助于团队利用数据系统地监控和跟踪客户生命周期成功指标的表现,评估现有计划的有效性,并为未来的营销和保留策略提供信息。
让跨职能团队在成功指标上保持一致
跨业务领域的不同团队需要有明确定义的角色和共同的责任,以实现公司的首要任务,从而改善协调并最大限度地减少重复工作。虽然您的公司可能有一系列指标,但数据科学和分析需要确保应用于成功指标的定义和业务逻辑清晰、记录良好,并在业务团队中保持一致。在业务团队中采用一套通用的成功指标,并定期会面以评估结果,使跨职能团队保持一致并对其指标负责,这一点至关重要。
揭示影响成功指标的主要因素
数据科学家和分析师需要将客户与公司产品和服务的互动以及业务成果联系起来。例如,分析团队需要能够定期解决以下问题:影响客户订阅或购买决策的主要因素是什么?客户流失的主要原因是什么?如果营销人员需要为客户提供更个性化的体验,他们还需要了解客户在其生命周期的每个关键阶段因不同角色段而异的行为,以便他们能够发现与这些客户互动的机会。他们还需要了解哪些营销渠道、活动、内容供应和设备类型可以在客户生命周期的不同阶段推动更多流量,以便他们可以通过更复杂、更有针对性和更数据驱动的战略来推动改进和效率。
客户生命周期分析对于企业实现可扩展增长以及成功分配产品和服务的核心价值至关重要。沿着客户生命周期的关键阶段系统地跟踪和监控核心和成功指标,将使您的业务团队能够在正确的时间利用有针对性的信息与正确的客户接触。这将允许你的团队为改善客户体验做出适当的调整,并从你的产品和服务中获得核心价值。
阅读更多:
机器学习中使用的六种学习技术
计算机是如何学习的?
用于训练机器学习模型的技术

机器学习是一个和计算机一样古老的概念。1950 年,艾伦·图灵创造了转向测试。这是对计算机的一个测试,看看一台机器是否能让人类相信它是人而不是计算机。此后不久,在 1952 年,阿瑟·塞缪尔设计了第一个计算机程序,计算机可以一边运行一边学习。这个程序是一个跳棋游戏,电脑在比赛中学习玩家的模式,然后用这些知识来改进电脑的下一步棋。机器学习是人工智能的一种应用,应用程序将自动从经验中学习和改进,而无需显式编程。
从那时起,机器学习技术发展迅速,现在被用于不同的应用。随着计算机每天需要处理的数据量的增加,机器学习尤其取得了巨大的发展。机器学习主要是分析不断增加的信息量的结果,也就是说,底层算法不会改变,但代码在内部实现的方法会略有变化,以适应数据量的增加。机器学习技术可以根据基本算法模糊地分为三大类:监督学习、非监督学习和强化学习。

作者使用 Canva
- 监督学习:
在监督学习算法中,计算机通过示例进行学习。程序员向算法提供已知的数据集,该数据集以期望的输入和输出为特征。算法必须找到一种方法从给定的输入中获得那些输出。
- 无监督学习:
在无监督学习算法中,计算机通过探索和分析数据来发现模式。没有现成的答案,也没有开发人员来提供指导。相反,该算法确定绑定可用数据的相关性和关系。
- 强化学习:
在强化学习算法中,为算法提供了一组动作、参数和最终值。通过定义这些关联,算法试图探索不同的选项和可能性,监控和评估每个结果,以找出哪个是理想的。
然而,研究人员一直致力于建立上述三种算法的更优化和更有效的方法,以跟上需要分析的数据的增长。本文将涵盖六种学习技术,使训练机器学习模型更快、更有效。我们将讨论的方法是补丁学习、主动学习、在线学习、迁移学习、联合学习和使能学习。

补丁学习
补丁学习(PL)是一种通过优化机器学习算法的性能来提高其学习能力的方法。在补丁学习中,他们使用特定数据集训练复杂的通用模型,以在输入数据集中生成导致模型产生错误结果的点。之后,错误结果和导致错误的数据集部分被用于形成每个错误部分的简单模型。然后将这些简单的模型串联或并联,通过降低误差百分比来提高整体算法的性能。

作者使用 Canva
面片学习的复杂性在于获得最佳结果所需的面片模型的数量。研究人员通常尝试不同数量的面片模型,并观察哪个数量对应的总误差最小。选择贴片型号数量的过程通常是一个权衡的过程;如果数字很大,那么模型非常复杂,但是,如果数字太小,那么错误率就很高。一个可接受的补丁数量是一个错误率,而不是太大是理想的选择。
补丁学习的步骤是:
- 使用特定数据集训练一般模型。
- 从通用模型中获取结果,主要是数据集的哪些部分没有产生正确的答案。
- 为误导数据的特定部分设计较小的补丁。
- 使用补丁模型和通用模型提出最佳训练模型。

在线学习
在在线学习(OL)中,用于训练模型的数据可以在线获得,并且经常更新。使用在线学习模型,你可以精确地创建一组参考数据。之后,该算法通过在线获取信息来更新其数据和学习方法。因此,这些算法通常比批量学习快得多,因为大多数批量学习算法包含对同一数据集的多次通过过程。由于模型不重新考虑以前的数据集,旧的数据集不需要存储,所以这种方法更快,内存效率更高。

作者使用 Canva
电子商务和社交网络行业广泛采用在线学习算法。原因是它的学习速度和捕捉任何最新趋势的能力。

联合学习
联邦学习(FL)是一种分布式学习算法,能够利用移动电话和个人笔记本电脑等设备上存在的大面积分散数据进行训练。像谷歌这样的大公司经常使用联合学习;通过从用户与移动设备的交互中收集数据来训练模型。

作者使用 Canva
联邦学习算法的使用生成了更智能的模型,具有低延迟和低功耗,同时确保了隐私。此外,增强模型(基于特定用户交互构建的模型)可以立即在该用户的设备上使用。因此,这种方法不仅更有效,而且可以根据每个用户自己的体验偏好进行定制。

迁移学习
迁移学习(TL)是一种机器学习技术,其中模型将先前相关数据的知识转移到新目标任务的学习中。使用这种学习方法的目标是让机器学习像人类学习一样高效。迁移学习可以通过三种方式改善机器学习过程。
- 使用从先前知识转移的数据在目标数据上使用的模型的初始性能将比如果模型根本没有被训练好得多。
- 因为 TL 使用来自先前任务的结果数据,所以为目标任务充分训练模型所需的时间显著减少。
- 通过将转移的数据应用于不熟悉的任务而建立的连接和关系使得模型的结果对于旧的和目标任务都更好。

作者使用 Canva
迁移学习算法包括扩展众所周知的分类和推理算法,如神经网络、贝叶斯网络和马尔可夫逻辑网络,以提高效率和适应性。它还可以通过扩展 Q 学习和策略搜索等算法用于强化学习。

主动学习
在主动学习中,通过允许算法选择它想要学习的数据集,鼓励算法“好奇”。研究人员认为,通过让模型选择自己的训练数据,它将学习得更快,从而表现得更好。

作者使用 Canva
主动学习模型试图通过请求由“甲骨文”(人类注释者)标记的未标记实例形式的“查询”来克服标记瓶颈。通过这种方式,主动学习模型旨在使用尽可能少的标记实例来获得高精度。在许多现代机器学习问题中,主动学习是很有动机的,在这些问题中,数据也是足够的,但是标签很难获得或者很昂贵。
主动学习模型有多种方式形成和标记查询;三种最常见的是:
- 不确定性采样: 这是最直接最常用的查询形成方法。在这种方法中,主动学习模型查询最不确定如何标记的实例。对于概率学习模型来说,这种方法通常很简单。
- 按委员会查询: 这种方法是一种理论上有动机的、查询选择的方法。这种方法包括创建和维护一个模型委员会,这些模型都是在相同的标签集上训练的,但是代表不同的输出。然后允许每个模型对查询的标签进行投票。最具信息性的模型投票通常用于决定查询标签。
- 预期模型变化: 使用这种方法,模型优先考虑最有可能对模型产生最显著影响的实例,而不管其标签。研究人员已经证明,这种方法在大多数情况下都很有效;然而,如果特征空间和标注集都很大,那么计算代价可能会很高。

集成学习
集成学习将“基础学习模型”多次应用于不同的数据集,然后分析不同的结果假设。这可以使用两种方法之一来完成:
- 独立于其他假设构建每一个假设,这样每一个假设都会有不同的低误差结果。这是通过使用略有不同的训练数据多次运行模型来完成的。我们可以通过操纵输入特征或在训练数据中添加一些随机性来保证独立性。则未加权的投票决定数据的最终分类。
- 与独立方法不同,实现集成学习的另一种方法是使用加法。在这种方法中,原始模型被耦合在一起,然后集合的加权和确定数据的分类。

这六种学习技术并不是我们应用机器学习算法的唯一方法。由于该领域相当活跃,最近的发展总是由研究人员提出。尽管如此,所有的提议都是为了同一个目标,那就是快速、高效、低误差或无误差的算法。

参考
[1]吴博士和孟德尔博士(2019 年)。补丁学习。 IEEE 模糊系统汇刊。
[2]丰滕拉-罗梅罗,第三版。、吉哈罗-贝迪尼亚斯、马丁内斯-减压阀、佩雷斯-桑切斯和彼得罗-巴拉勒(2013 年)。在线机器学习。计算智能的效率和可扩展性方法。
[3] McMahan,H. B .和 Ramage,D .联合学习:没有集中训练数据的协作机器学习,2017 年 4 月。
[4] Torrey,l .,& Shavlik,J. (2010 年)。迁移学习。在机器学习应用和趋势研究手册:算法、方法和技术。
[5] Settles,B. (2009)。主动学习文献调查。威斯康星大学麦迪逊分校计算机科学系。
[6]迪特里希,T. G. (2002 年)。集成学习。大脑理论和神经网络手册, 2 ,110–125。
地理空间数据科学的六个 Python 技巧
如何使用 Geopandas 在 Python 中轻松有效地整合空间要素

在这一轮关于 Python 的地理空间技巧中,我通过六个关键方面来使用 Geopandas 有效地处理和制作 Python 中的漂亮地图。
如果您想访问地理空间数据处理的最新提示和技巧,可以访问:
第 1 部分:如何使用 Geopandas 在 Python 中轻松有效地集成空间要素。
towardsdatascience.com](/5-geospatial-tips-and-tricks-in-python-eef86aec5110) [## Python 中的 7 个地理空间数据处理技巧
第 2 部分:如何使用 Geopandas 在 Python 中轻松有效地集成空间要素。
towardsdatascience.com](/7-geospatial-data-processing-tips-in-python-dac5e4d28439)
以下是我们在本文中包含的技巧列表。
提示 1 —图例位置
传说是地图制作的重要组成部分。使用 GIS 软件,您可以拖放图例的位置以适应您的整体设计并避开障碍物。在 Geopadnas 中,您可以更改图例的位置。
默认情况下,图例显示在地图的右上角。在本例中,我们使用legend_kwd和loc参数将图例的位置更改到左上方。

图例位置-作者的图像。
下面是用上面的代码生成的地图。如您所见,图例位置现在位于地图的左上角。

左上角带有图例的大陆地图-图片由作者提供。
提示 2-简单的地理编码
地理编码是将物理地址描述转换为地球表面位置(以数字坐标表示的空间)的计算过程— 维基百科。
在 Python 中使用 OpenStreetMap 免费进行地理编码很容易。在本例中,我们将对三个地址进行地理编码。首先,我们创建一个包含三个地址的数据帧。一旦我们有了数据帧,我们就可以在数据帧上快速调用. tools.geocode 方法。

一旦我们进行地理编码,我们就会得到一个额外的列,即几何列,它帮助我们执行地理功能,如缓冲、计算距离和最近点等。
提示 3-空间连接
作为基本的地理空间功能之一,空间连接几乎占了所有地理空间处理的一半。我们可以使用 Geopandas 通过位置快速连接空间数据。在本例中,我们使用 SQL 语法和 Geopandas read_file方法从 PostgreSQL 中读取数据。

一旦我们读取了数据,就很容易通过位置来连接数据。在上面代码的最后一行,我们使用 Geopandas 的sjoin sjoin 方法将列表点连接到静态区域多边形。我们以两个数据集的连接结束,表明每个点属于哪一个。
我们可以使用 Pandas 的 group by 和 aggregation 函数进一步处理数据,以获得统计数据。在本例中,我将对每个多边形或统计区域中的列表进行聚合和计数。

空间连接数据的聚合函数-图片由作者提供。
最终的数据框仅包含统计代码和每个多边形中 Airbnb 房源的数量。这是一张地图,显示了每个地区的列表数量。

Airbnb 房源 Choropleth 地图——作者图片
提示#4 —行过滤器
就像 pandas 数据帧一样,Geopandas 允许您限制或过滤出想要读取的行数。当您有一个大的数据集,并且您只想试验数据集的某一部分时,行筛选器非常有用。

按行过滤数据-按作者过滤图像。
我们可以通过传递 rows 参数来实现这一点。在上述代码的第一个实例中,我们将获得从零到一千的行。然而,通过切片,我们可以得到起始和结束数字之间的任意范围的行。
技巧 5——夹子
我们很少获得具有适当界限的正确数据。有时,我们需要将数据裁剪到我们感兴趣的边界。使用 Geopandas 裁剪地理空间数据就像调用。裁剪方法并提供两个地理数据框架。在本例中,我们将把街道裁剪为预定义的边界多边形。

在 Geopandas 中裁剪。—图片由作者提供。
现在,让我们比较这两个数据集。下图显示了裁剪后的数据与原始边界和街道数据集的对比。

裁剪数据集-作者提供的图像。
提示#6 —单独的图例
在第一篇技巧文章中,我们从图例位置开始,最后以图例方向结束。默认情况下,我们有一个垂直方向的图例。但是,出于任何原因,如果您希望有水平图例,您也可以使用 legend_kwds 和方向参数。让我们看一个水平图例方向的例子。

横向图例—作者图片。
输出是带有水平图例的地图。水平图例可以是美观的,并且可以帮助读者比垂直默认图例更好地阅读图例数字。

横向图例图—图片由作者提供。
结论
我希望您喜欢这一轮 Python 中的地理空间数据技巧。在本文中,我们看到了有效使用 Geopandas 进行地理空间数据分析的六个技巧。
其中一些技巧是直接的几何操作,对于处理地理空间数据至关重要:空间连接、裁剪和地理编码。其他三个提示与地图制作和图例样式有关。
如果你喜欢我在 Twitter 上发布的这些提示和技巧,你可以在 @spatialML 找到它们
六个现实世界中的数据陷阱——以及如何应对它们

照片由查理/SANY0012 (CC-SA 2.0)拍摄
你找到你的数据,加载它,建立它的模型——然后扔掉垃圾。就像他们说的,一定是垃圾。当然,您确保有一个很好的矩形文件,具有一致命名的列,并且您删除了人们在 Excel 文档中输入的随机注释。那么是什么原因呢?
这里有六种常见的、现实世界中的数据违规现象,你迟早都要面对。
1.行数比预期的多
我们希望每行有一条记录。在 95%的文件中,这就是你所拥有的。但是突然一个 join 给出了警告,你意识到还有多余的。为什么?可能是因为某人的查询构建得很差,或者您认为行是一回事,但它实际上是完全不同的东西。
案例研究:
我以为在住院医师资格表中,每个大学生占一行。事实上,每种状态占一行:一小部分学生在他们的大学生涯中有多种状态。这没有记录,当然,在这些状态上也没有标识符或时间戳。
策略:每当你加载数据时,聚集你认为唯一的行标识符,一边走一边计数,看看是否有任何行是> 1。然后你必须决定省略一些或者把它们合并在一起——或者改变你的分析,使之更复杂,以便两者都用。
2.随着时间的推移改变约定
在数据没有严格控制的情况下——也就是手动输入,没有什么指导原则——你可以在不同的时间或由不同的人使用不同的约定。缩写会改变。使用新的代码系统。日期格式改变。很烦。
有时,这些转变甚至有一个很好的理由,比如程序上的改变,或者意识到需要一个新的类别。当然,仍然应该有人清理旧的价值观——但是你对他们没有这样做感到惊讶吗?
案例研究:
我在分析接受高、中、低金额资助的人。当前的数据输入约定对每种类型使用三个字母的缩写,但是回顾四年前,我发现使用的是全名——大写和拼写差异很大;显然根本没有标准化。负责此事的员工后来都换了部门,你对此感到惊讶吗?
案例研究 2:
我过去分析国会数据,尤其是对候选人的捐款。然而,将投票记录或条款与捐款匹配起来并不容易,因为没有一致的 id 给国会成员,我不得不依靠他们的名字。不同的来源包括中间名和头衔,比如 Jr。最糟糕的是,数量惊人的政客有一个昵称——这就是国会官方网站上列出的!
策略:总是总结你的分类变量,即使只是得到所有唯一的值和它们的频率,并看着它们被排序。然后你可以合并等价的。对于姓名和其他字符串数据,如果有相当多但数量有限的情况,应该尽可能地进行抽查,最好使用正则表达式来分离出可以更可靠地匹配的字符串片段,比如全大写的姓氏。
3.不同的缺失值代码
我们都知道缺失值,以及如何处理它们,对吗?更讨厌的是多种表观缺失出现在同一个场的时候。它们应该被保留、抛弃还是合并?当然,这要看情况。
案例研究:
在人口统计数据中,我检查了性别一栏(被误标为“性别”),这一栏表面上只包含男性或女性的值。有正常的缺失数据,给定为零…但也有空白值,有些“未提供”,最糟糕的是“999”对于不同的集合或编码协议,这些都意味着相同的东西吗,或者在每种情况下意味着不同的东西吗?一些真的意味着,例如“不适用”而不是“不可用?”我们是猜测,还是能发现?
策略:如上,检查你的范畴值,以及你的数字范围。任何超出预期范围的都应该检查出来。
我见过-1、0 和 9 的字符串被用作需要重新编码的特殊代码(可能在不同的列中)。我见过在同一个文件中使用的各种丢失的字符串,它们都意味着丢失,因为协议不同,包括空格、NA、NIL、*。,-,还有很多。
要处理这些情况,首先您只需了解用于获取和记录数据的协议。这可能需要(恐怖!)与一个活生生的人交谈——他现在在另一个部门工作,目前正在度假——因为,当然,它从未在任何地方被记录下来。
4.无意义的时间线
如果您有日期或时间列,请检查它们是否有意义。通常情况下,其中一些不会,因为一个事件应该总是先于另一个事件。
案例研究:
我下载了课程注册的数据,并将它们加入到学生详细信息表中,比如专业。我感兴趣的是,根据一个学生获得学位需要多少个学期,课程量会有什么变化。看资料发现,学生在被录取前都在上课!
问题的根源:录取日期只是最近的学位,一些学生被多次录取,例如,一个硕士项目或做学士后工作。我(从一个中心办公室)获得的数据摘录隐藏了这个细节,会导致一些非常错误的结论。
策略:核对所有日期。找出任何违反假定关系或超出预期范围的情况。通常,一些额外的数据被隐藏在某个地方,如在我的例子中,或者与日期相关联的事件没有我们期望的确切定义——是当用户点击按钮结账时记录的“购买”时间戳,还是当他们的卡运行时记录的时间戳等等。通常只是垃圾数据,日期转换不正确(众所周知,在一些平台上很难处理)或输入格式错误:“10/12”是指 12 月 10 日还是 10 月 12 日?每个人都收到备忘录了吗?
5.键入错误的数字
当你手工输入一些数据时,不可避免地会输错一些。常见的错误是重复的数字——尤其是在一串零、丢失的数字和换位中。
案例研究:
我当时在协助一个大型调查,收集某个部门员工的工资。大约 30%的受访者使用网络界面手工输入数据,而不是上传电子表格。(一些电子表格可能也是手工输入的。)
我们进行了标准的异常值检查,以寻找数量级过大或过小的值。通常问题是输错了零:120,000 会被输入为 12,000 或 1,200,000。(web 字段中没有显示逗号,这可能会有所帮助。)
但是我在详细检查记录时注意到了其他错误的值(另一个原因):数字被调换了,例如 57000 换成了 75000。这比一个数量级的变化要小得多,并且会被我们的常规检查所忽略。这些误差到底有多大?我在 R 中运行了一些模拟,发现如果发生在前两位,换位通常会导致数字过大或过小三倍。通过与期望值进行更具体的比较,这也是可以通过编程进行检查的事情(对极端情况进行相当多的手动审查)。
策略:当然是做标准的异常值检查;但是这首先需要知道什么是正常的——或者合理的。我在以前的工作场所发现的另一个问题是,我们的异常值检查将值与平均值进行比较——这本身就非常容易受到异常值的影响。运行更多的模拟,我发现一个大的异常值(由重复的零产生)极有可能夸大均值/标准差,以至于看起来不再像一个异常值。我们需要转向不太敏感的指标,比如中位数和 MAD。当然,历史和领域知识也影响了我们的预期。
6.神秘失踪的数据
让带有“NA”的单元格告诉您数据丢失是一回事;对于行来说,神秘地不导出是另一回事。我们必须记住的一件事是我们的数据系统的局限性,尤其是在寻找旧数据的时候。
案例研究:
我使用一个庞大而笨拙的报告系统为一项纵向研究寻找数据。各种预构建的查询允许我指定所需群组的年份或季度。我照做了,并下载了 CSV。
分析进行到一半时,我意识到随着时间的推移,数据越来越少。结果是,不管指定的日期是什么,报告中只包括了当前活跃的用户。是的,这是非法的。我必须找到数据的替代来源(不容易)。
策略:和目前为止的每一项一样,汇总你的变量,包括日期,然后看看你有多少个案例。这种变化方式很奇怪吗?另外,随机或从有代表性的班级中抽出几个人,通过数据追踪他们。他们出现在应该出现的地方,而不是不应该出现的地方吗?
结论
从这六个项目和案例研究中可以得出两大主题。一个在你的控制之下,一个不在:
检查你的数据。在它上面聚集。列出你对它们的假设,并明确检查它们是否成立——这包括非常基本的、看起来愚蠢的假设,因为其中一些不可避免地会被违反。
糟糕的文档是你的敌人。缺少元数据的导出。记录不良或根本没有记录的查询。只存在于某人头脑中的定义——而且他们正在休假。我们知识中的这些漏洞隐藏着重大和微妙的问题;尤其是当它们与我们自己的常识、假设和专业判断相抵触时——因为其他人有不同的想法,或者根本不思考。你能做的最好的事就是意识到你所不知道的,提防麻烦。
六个适马工程师使用 R 进行数据分析的必备工具
r 代表工业工程师
探索“六西格玛”R 包

在 Unsplash 可用的谷仓图像
数据分析图表
图表的开发是 DMAIC(定义、测量、分析、改进、控制)周期每个阶段的六个适马项目的重要组成部分。他们的主要目标是通过描述性分析支持数据的解释。虽然二维图表可以用作更复杂表示的基础,但多维数据可以通过这些图表的扩展来显示。
数据的图形表示有助于更好地理解给定的过程。在分析的早期阶段,当工程师需要进行推测、找出关系和计划进一步的研究时,它们是很有帮助的。因此,选择适当类型的图表是有效交流进展和建议的关键任务;糟糕的图表可能会毁掉项目期间完成的重要的好工作。
在本文中,我们将通过一个简单的案例研究来解释和说明六个适马项目中一些最重要的数据分析图表。有关在六个适马和质量保证项目中使用的附加工具的更多信息,请参考 7 质量基本工具。
条形图
条形图是最简单的图表类型。每个条形代表一个正在测量研究变量的因子。条形的高度代表给定数量或度量(如缺陷、项目、产品)的频率。条形图是计数的最佳图形表示。
对于这个例子和下面的例子, ss.data.pc 数据集(一个用于打印机墨盒例子的数据集,随 SixSigma 包提供)将用于生成一个特定的图表。
我们来看看 R 代码生成柱状图!

运行图表
运行图是二维图表,其中 x 轴代表时间线,而在 y 轴上绘制了被监控的变量。通常在运行图中画一条中线,它可以代表目标值、数据平均值或任何其他值。
当在 x 轴上有时间刻度时,这些图表也被称为时序图。运行图对于检测可以指示过程中的变化(即可变性)的模式是有用的。周期、趋势或转变的发现应触发过程评审,以采取进一步的措施来提高质量。
我们来看看 R 代码生成运行图!

分层图表
当每次运行有一个以上的观察值时,使用分层图。它们有助于在单个图表中同时显示短期变化和长期变化。短期变化由每个亚组内的变化表示,而长期变化由所有组之间的变化表示。
要创建分层图,在从较高值到较低值的每个游程的位置绘制垂直线。然后,将单个值绘制成点或水平线段。
让我们来看看生成层图的 R 代码!

盒须图
也称为盒图,盒须图用于以图形方式总结连续变量的分布。方框的两边是第一和第三个四分位数(分别是第 25 和第 75 个百分位数)。50%的数据位于盒子内部。穿过方框的线对应于中间值,极端晶须值可以是数据的最大值和最小值,或者是数据被认为是异常值的其他界限。极限值通常取为:

其中 Q 1 和 Q 3 分别是第一和第三个四分位,IQR 是四分位区间( Q 3 — Q 1)。
箱线图有助于直观显示分布是否居中或有偏差(即相对于其余数据的中间值的位置),是否存在异常值(即触须之外的点),或者数据是否接近中心值(即小触须或盒子)。此图表在比较各组和检查它们之间是否有差异时非常有用。
让我们来看看生成盒须图的 R 代码!

团体图表
分组图主要用于图形化显示多个点所属的分组。在六适马环境中,当测量的特性由不同的过程流产生或在不同的位置测量时,它们很有用。每组的最大值和最小值通常由线连接。
我们来看看 R 代码生成组图!

多元图表
多元图表主要用于以图形方式识别影响特定结果的因素(即质量关键(CTQ)特征)。一旦确定了这些因素,就可以提出并执行变更,以实现期望的目标。
对于以下示例,将使用扩展版本的 ss.data.pc.big 数据集来生成多元图表。数据集包含 72 个观察值,对应于 4 个不同因素的所有可能组合:颜色(2)、操作者(3)、填充剂(3)和批次(4)。我们来看看 R 代码生成多元图表!

总结想法
过程改进、质量保证和六西格玛工程师必须能够使用贯穿本文的概念来构建最合适的图表来表示数据。同样,发展和强化图形分析技能将带来更好的解释(即更容易识别周期、变化或趋势),这将有助于制定更有效的行动计划,以提高业务交付成果的质量。
正确选择图表将简化结果交流和对所传达信息的理解。本文并不打算说服读者在开发这些图表时严格使用 R for,而是介绍如何用几行代码在免费的开源软件中开发这些图表。
—
如果你觉得这篇文章有用,欢迎在 GitHub 上下载我的个人代码。你也可以直接在 rsalaza4@binghamton.edu 给我发邮件,在LinkedIn上找到我。有兴趣了解工程领域的数据分析、数据科学和机器学习应用的更多信息吗?通过访问我的媒体 简介 来探索我以前的文章。感谢阅读。
——罗伯特
六个星火练习来统治他们
一些具有挑战性的 Spark SQL 问题,易于在许多现实世界的问题上提升和转移(带解决方案)

照片由 Xan Griffin 在 Unsplash 上拍摄
Spark SQL 非常容易使用,句号。你可能已经知道这也是很难掌握的 。
要精通 Spark,必须具备三项基本技能:
- 操作和理解数据的能力
- 关于如何根据程序员的需求弯曲工具的知识
- 在影响 Spark 工作执行的因素中寻找平衡的艺术
我精心制作了以下六个练习,这些练习类似于 Spark 开发人员在构建他们的管道时每天面临的一些典型情况:这些将有助于评估上述技能。
你可以在文章末尾找到建议的解决方案!
数据集
让我们简单描述一下我们将要使用的数据集:i t 由来自商店数据库的三个表组成,分别是产品、销售和卖家。您可以通过下面的链接下载拼花文件中的数据。请注意,要 100%利用这些练习,你需要阅读提供的文件!(.zip、~6GB、 如果无法下载数据,可以点击这里 ) 找到生成器脚本
****[## datasettocomplettethesixsparkexercises . zip
包含做六个练习的三个表的数据集
drive.google.com](https://drive.google.com/file/d/1kCXnIeoPT6p9kS_ANJ0mmpxlfDwK1yio/view?usp=sharing)****
下图显示了如何连接这些表:

销售表
该表中的每一行都是一个订单,每个订单只能包含一种产品。每行存储以下字段:
order_id:订单编号product_id:订单中销售的单个产品。所有订单只有一种产品****seller_id:销售产品的销售员工 IDnum_pieces_sold:订单中特定产品的销售数量bill_raw_text:一个字符串,表示与订单关联的账单的原始文本date: 订单的日期。
下面是表格的一个示例:
产品表
每行代表一种独特的产品。这些字段是:
product_id:产品 IDproduct_name:产品名称price:产品价格
卖方表
该表包含所有卖家的列表:
seller_id:卖家 IDseller_name:卖家名称daily_target:卖家完成其配额所需的商品数量(与产品类型无关)。例如,如果每日目标是 100,000,员工需要销售 100,000 件产品,他可以通过销售 100,000 件 product_0 以及 30,000 件 product_1 和 70,000 件 product_2 来达到定额
练习
利用下面的练习的最好方法是下载数据并实现一个工作代码来解决提出的问题,最好是在分布式环境中!我建议在阅读本页末尾的解决方案之前先这样做!
提示:我构建数据集是为了允许在单台机器上工作:在编写代码时,想象一下数据集大 100 倍会发生什么。
即使你知道如何解决这些问题,我的建议是不要跳过热身问题!(如果你知道火花,他们需要几秒钟)。
如果要用 Python 做这个练习,需要以下包:
**# Pyspark
pip install pyspark# Pyspark stubs
pip install pyspark-stubs**
热身#1
**Find out how many orders, how many products and how many sellers are in the data.How many products have been sold at least once? Which is the product contained in more orders?===========**Create the Spark session using the following code**spark = SparkSession.builder \
.master("local") \
.config("spark.sql.autoBroadcastJoinThreshold", -1) \
.config("spark.executor.memory", "500mb") \
.appName("Exercise1") \
.getOrCreate()**
热身#2
**How many distinct products have been sold in each day?===========**Create the Spark session using the following code**spark = SparkSession.builder \
.master("local") \
.config("spark.sql.autoBroadcastJoinThreshold", -1) \
.config("spark.executor.memory", "500mb") \
.appName("Exercise1") \
.getOrCreate()**
练习#1
**What is the average revenue of the orders?===========**Create the Spark session using the following code**spark = SparkSession.builder \
.master("local") \
.config("spark.sql.autoBroadcastJoinThreshold", -1) \
.config("spark.executor.memory", "500mb") \
.appName("Exercise1") \
.getOrCreate()**
练习#2
**For each seller, what is the average % contribution of an order to the seller's daily quota?**# Example** If Seller_0 with `quota=250` has 3 orders:Order 1: 10 products sold
Order 2: 8 products sold
Order 3: 7 products soldThe average % contribution of orders to the seller's quota would be:
Order 1: 10/105 = 0.04
Order 2: 8/105 = 0.032
Order 3: 7/105 = 0.028Average % Contribution = (0.04+0.032+0.028)/3 = 0.03333===========**Create the Spark session using the following code**spark = SparkSession.builder \
.master("local") \
.config("spark.sql.autoBroadcastJoinThreshold", -1) \
.config("spark.executor.memory", "500mb") \
.appName("Exercise1") \
.getOrCreate()**
练习#3
**Who are the **second most selling and the least selling** persons (sellers) for each product?Who are those for product with `product_id = 0`===========**Create the Spark session using the following code**spark = SparkSession.builder \
.master("local") \
.config("spark.sql.autoBroadcastJoinThreshold", -1) \
.config("spark.executor.memory", "3gb") \
.appName("Exercise1") \
.getOrCreate()**
练习#4
**Create a new column called "hashed_bill" defined as follows:- **if the order_id is even**: apply MD5 hashing iteratively to the bill_raw_text field, once for each 'A' (capital 'A') present in the text. E.g. if the bill text is 'nbAAnllA', you would apply hashing three times iteratively (***only if the order number is even***)- **if the order_id is odd**: apply SHA256 hashing to the bill textFinally, check if there are any duplicate on the new column===========**Create the Spark session using the following code**spark = SparkSession.builder \
.master("local") \
.config("spark.sql.autoBroadcastJoinThreshold", -1) \
.config("spark.executor.memory", "3gb") \
.appName("Exercise1") \
.getOrCreate()**
解决方法
让我们深入研究解决方案。首先,你应该注意到热身问题对解决练习很方便:
热身#1
这个练习的答案很简单。首先,我们只需要count每个数据集中有多少行:
我们得到以下输出:
**Number of Orders: 20000040
Number of sellers: 10
Number of products: 75000000**
如您所见,我们的数据集中有 75,000,000 个产品和 2 0,000,040 个订单:由于每个订单只能有一个产品,其中一些从未售出。让我们找出有多少产品至少出现一次,哪个产品包含在更多订单中:
第一个查询计算 sales 表中有多少不同的产品,而第二个块提取 sales 表中计数最高的product_id。
输出如下所示:
**Number of products sold at least once
+--------------------------+
|count(DISTINCT product_id)|
+--------------------------+
| 993429|
+--------------------------+Product present in more orders
+----------+--------+
|product_id| cnt|
+----------+--------+
| 0|19000000|
+----------+--------+**
让我们仔细看看第二个结果:20 M 中的 19,000,000 个订单正在销售带有product_id = 0 : 的产品这是一个我们以后应该使用的强大信息!
热身#2
对 Spark 有所了解,这应该很简单:我们只需要找出“在每一天卖出了多少不同的产品”:**
这里不多说了,输出如下:
**+----------+----------------------+
| date|distinct_products_sold|
+----------+----------------------+
|2020-07-06| 100765|
|2020-07-09| 100501|
|2020-07-01| 100337|
|2020-07-03| 100017|
|2020-07-02| 99807|
|2020-07-05| 99796|
|2020-07-04| 99791|
|2020-07-07| 99756|
|2020-07-08| 99662|
|2020-07-10| 98973|
+----------+----------------------+**
练习#1
让我们解决难题吧!第一个练习是简单地询问"订单的平均收入是多少?**
理论上,这很简单:我们首先需要计算每个订单的收入,然后得到平均值。记得那个revenue = price * quantity。零用易:product_price在products表中,金额在sales表中。
第一种方法是简单地连接两个表,创建一个新列,然后求平均值:
以上是正确的,并且它可能工作得相当好(特别是如果您正在本地环境中工作)。但是让我们看一下执行计划 DAG:在某个时候,我们将有一个重新分区(在product_id字段上)和一个连接:

让我们看看当 Spark 执行 join 时会发生什么(在 Spark UI 上的):

哎呀!一项任务比其他任务花费更多的时间!
这是一个典型的倾斜连接的例子,其中一个任务需要很长时间来执行,因为连接只倾斜在很少的键上(在这个例子中是product_id = 0)。我在我的媒体文章《星火加盟的艺术》中提到过星火加盟,如果你想了解更多,可以去那里看看!
Spark 中加速连接的实用技巧
towardsdatascience.com](/the-art-of-joining-in-spark-dcbd33d693c)
请注意,如果您在本地系统上运行 Spark,这不是一个大问题。在分布式环境中(有更多的数据),这个连接可能会花费难以置信的时间来完成(也许根本不会完成!).
让我们用一种叫做“密钥加盐”的技术来解决这个问题。我不会详细描述,因为我已经在上面链接的文章中涉及了这个主题。总结一下,我们要做的是:
- 为最常见的产品复制维度表中的条目,例如,将复制 product_0,创建 id:
product_0–1、product_0–2、product_0–3等。 - 在销售表上,我们将把“
**product_0**”替换为随机复制的(例如,其中一些将替换为product_0–1,其他替换为product_0–2,等等。)使用新的“salted”键将消除连接的倾斜:
这里要注意的重要一点是我们并没有对所有的产品加盐,只是对那些驱动偏斜度的产品加盐(在这个例子中,我们得到了 100 个最频繁出现的产品)。对整个数据集加盐会有问题,因为行数会根据“加盐因子”线性增长:
查看我们执行上述操作时的各个阶段:

查询的结果应该如下所示
+------------------------------+
|avg((price * num_pieces_sold))|
+------------------------------+
| 1246.1338560822878|
+------------------------------+
在本地环境中使用这种技术可能会导致执行时间的增加;然而,在现实世界中,这个技巧可以决定完成还是不完成连接。
练习#2
第二个问题是:“对于每个卖家,订单对卖家每日配额的平均贡献百分比是多少?".
这与第一个练习类似:我们可以将我们的表与 sellers 表连接起来,我们计算特定订单的配额命中率,然后计算平均值,按seller_id分组。
同样,这可能会产生一个偏斜的连接,因为即使是卖家也不是均匀分布的。不过,在这种情况下,解决方案要简单得多!因为卖家的表格很小,我们可以广播它,使得操作快得多!
“广播”仅仅意味着将表的副本发送给每个执行者,允许“本地化”任务。我们需要小心地使用这个操作符:当我们广播一个表时,我们需要确保这个表不会变得太大而不能在将来广播,否则我们将会在以后出现内存不足的错误(随着广播数据集变得越来越大)。
练习#3
问题:“每种产品的 销量第二多和销量最少的 人员(卖家)是谁?那些带有 *product_id = 0* 的产品是谁。
这听起来像窗口函数!让我们来分析一下这个问题:对于每种产品,我们需要销量第二多和销量最少的员工(销售人员):我们可能需要两个排名,一个是销售图表中的第二名,另一个是最后一名。我们还需要处理一些边缘情况:
- 如果一个产品只被一个卖家卖出,我们会把它放入一个特殊的类别(类别:
Only seller or multiple sellers with the same quantity)。 - 如果一个产品由多个卖家出售,但所有卖家都出售了相同的数量,我们将把他们放在同一个类别中,就好像他们只是该产品的一个卖家一样(类别:
Only seller or multiple sellers with the same quantity)。 - 如果“最少销售”也是“第二次销售”,我们将仅将其计为“第二次销售”
让我们起草一个策略:
- 我们得到每对产品和卖家的销售总额。
- 我们增加了两个新的排名列:一个按降序排列产品的销售额,另一个按升序排列。
- 我们将获得的数据集分成三份:我们要处理的每个案例一份(第二大销售、最少销售、单一销售)。
- 在计算“最少销售”时,我们排除了只有一个销售人员的产品,以及销售最少的员工也是第二多销售人员的产品
- 我们把碎片重新组合在一起。
问题第二部分的结果如下:
+----------+---------+--------------------+
|product_id|seller_id| type|
+----------+---------+--------------------+
| 0| 0|Only seller or mu...|
+----------+---------+--------------------+
练习#4
对于这个最后的练习,我们只需要应用一个奇特的算法。我们可以通过UDF(用户定义函数)来实现。UDF 是一个自定义函数,可以在数据帧列上调用;作为一条经验法则,我们通常应该尽量避免 UDF,因为 Spark 并不能真正优化它们:UDF 代码通常比非 UDF 代码运行得慢。不幸的是,我们不能仅使用 Spark SQL 函数来应用所描述的算法。
解决方案如下所示:
首先,我们需要定义 UDF 函数 : def algo(order_id, bill_text)。algo功能接收order_id和bill_text作为输入。
UDF 函数实现算法:
- 检查
order_id是偶数还是奇数。 - 如果
order_id是偶数,计算钞票文本中大写字母“A”的数量,并迭代应用 MD5 - 如果
order_id是奇数,应用 SHA256 - 返回哈希后的字符串
之后,这个函数需要通过algo_udf = spark.udf.register(“algo”, algo)行注册到 Spark 会话中。第一个参数是 Spark 上下文中的函数名,而第二个参数是将要执行的实际函数。
我们在下面一行应用 UDF:
sales_table.withColumn("hashed_bill", algo_udf(col("order_id"), col("bill_raw_text")))
如您所见,该函数将两列作为输入,并将对每一行执行(即每对order_id和bill_raw_text)。
在最终的数据集中,所有的散列应该是不同的,所以查询应该返回一个空的数据集
拿走
如果你完成了所有的练习,恭喜你!这些内容涵盖了关于 Spark SQL 开发的一些非常重要的主题:
- 连接偏斜:这通常是 Spark 管道中的主要痛点;有时很难解决,因为在这些操作中涉及的所有因素之间找到平衡并不容易。
- 窗口函数:超级有用,唯一要记住的就是先定义开窗。
- 虽然 UDF 非常有用,但是我们在开始开发这样的函数之前应该三思,因为它们的执行可能会降低我们代码的速度。
当然,上面的练习可以用许多不同的方法来解决,我很乐意接受建议!我希望你喜欢!让我知道你的想法,如果你愿意,看看这些其他的文章!
如何在 Spark 上运行随机搜索而不用编写 Spark 代码?
towardsdatascience.com](/effortless-hyperparameters-tuning-with-apache-spark-20ff93019ef2) [## 聚类波洛克
杰森·布拉克绘画的聚类分析——如何利用 k-means 进行色彩分组
towardsdatascience.com](/clustering-pollock-1ec24c9cf447)****
成为有抱负的数据科学家的六种方法
学习如何推销自己,从人群中脱颖而出

鲁珀特·布里顿在 Unsplash 上的照片
介绍
无论你作为一名数据科学家学到了多少,如果你不营销自己,你将面临有限的机会。
举个例子,从技术角度来看,索尼制造了最好的手机之一,拥有 4K 屏幕、可扩展存储、免工具 SD 卡托盘、耳机插孔等等。然而,它的市场份额基本上为零,这是怎么回事呢?
索尼的一个主要问题是他们有一个糟糕的营销策略,为一个新型号制造宣传,当宣传停止时,该型号才在几个月后发布。
我的观点是…
你应该花一部分时间在学习数据科学的同时推销自己,这样你就可以增加被那些有机会给你的人认识的机会。
我不是技术最强或知识最丰富的数据科学家,但因为我推销了自己,我从教授、初创公司甚至新加坡政府那里获得了几次机会!
也就是说,作为一名有抱负的数据科学家,这里有六种方法可以增加你的曝光率。
1.用 Kaggle!
如果你不知道什么是 Kaggle ,我强烈建议你花时间去探索它,看看它能提供什么。在我看来,Kaggle 对于数据科学家就像 Leetcode 对于软件工程师一样。
Kaggle 允许你展示你的数据科学项目,你的底层代码,以及你有多活跃!你可以通过以下几种方式来利用它:
参加比赛
在我看来,没有比通过竞赛展示您的代码更好的方式来表明您已经为数据科学工作做好了准备。Kaggle 举办了各种各样的比赛,其中包括建立一个模型来优化某个指标。
你现在可以尝试的两个比赛是:
创建和共享数据集
为了成为一名优秀的数据科学家,你首先要有好的数据!通过 web 抓取或其他方式创建数据集,并与社区的其他成员共享这些数据集,这是实践提供干净和可用数据的一个很好的方式。
进行 EDA 并构建模型与他人分享
也许 Kaggle 最好的部分是有成千上万的数据集供你探索和建立模型。不久前,举个例子,我使用成对关联构建了一个极其简单的烹饪食谱推荐系统。我还利用其中一个冠状病毒数据集来看看自今年年初以来新冠肺炎的传播是如何演变的(点击这里查看)。)
2.创建 GitHub 帐户
我推荐的第二件事是创建一个 GitHub 存储库来存储所有的代码和数据科学项目。为什么?
- 使用版本控制系统,比如 GitHub,来组织你的代码和项目是一个很好的实践——每一个技术公司都希望你熟悉 GitHub。
- 在学习 GitHub 如何工作的同时,你还应该学习如何使用 Git(这可能是每个招聘经理都希望你知道的另一项技能!)
因此,用 GitHub 和 Git 建立良好的实践,并通过你有组织的 GitHub 库展示出来,意味着你已经在这些领域有经验了!
3.在媒体上开博客
是的,我有偏见,但是听我说完。你会惊讶有多少数据相关的专业人士在 Medium 上。他们喜欢看信息丰富、见解深刻、有趣的材料。利用 Medium 来记录您的学习成果,用简单的行话解释复杂的主题,或者浏览您的数据科学项目!
具体来说,我建议你为《走向数据科学》杂志撰稿,因为他们目前拥有近 50 万名粉丝。
如果你想要一些灵感,请查看我关于 葡萄酒质量预测 的项目演练。
4.创建个人网站
创建个人网站是展示您的数据科学项目和/或任何其他与数据科学相关的成就的另一个好方法。如果你对 HTML、CSS 和 JavaScript 有一些经验,我特别建议你创建一个个人网站,这样你就可以展示出你精通多种编码语言(JavaScript 对数据科学家来说肯定能派上用场!).
5.非营利机会
最近,我看到 Susan Currie Sivek 写的一篇 足智多谋的文章,文章提供了几个组织,在那里你可以有机会从事现实生活中的数据科学项目。
如果你想在简历中添加更多的经历,我强烈建议你看看这个。
6.完善你的 LinkedIn 个人资料和简历
说到简历,确保你的简历和你在 LinkedIn 上的简介更加清晰,这样可以突出你所有的工作、成就和贡献。
具体来说,我建议您考虑以下几点:
- 在你的简历中添加一个名为“个人项目或“数据科学项目”的部分,在那里你可以清楚地定义你解决的问题,你是如何处理每个问题的,以及结果是什么。
- 同样,确保你有一个部分强调你精通的技能和工具,比如 Python、SQL、Pandas 等…
- 如果你在任何数据科学竞赛中获得了成功,请确保也包括这些。
- 最后,确保包含我在本文前面提到的所有内容,比如你的 Kaggle 个人资料、GitHub 个人资料和/或个人网站的链接。
感谢阅读!
不确定接下来该读什么?我为你挑选了另一篇文章:
[## 在你第一份工作之前获得现实生活数据科学经验的 3 种方法
如何通过以下方式发展您的数据科学技能
towardsdatascience.com](/3-ways-to-get-real-life-data-science-experience-before-your-first-job-545db436ef12)
特伦斯·申
- 如果你喜欢这个, 关注我的 Medium 了解更多
- 关注我Kaggle了解更多内容!
- 我们连线上LinkedIn
- 有兴趣合作?查看我的 网站 。
简化的偏度和峰度
什么是偏斜度,我们如何检测它?
如果你问大自然母亲——她最喜欢的概率分布是什么?
答案将是——“正常”,其背后的原因是影响地球上每一个已知变量的机会/随机原因的存在。如果一个过程也受到可分配/重要原因的影响呢?这肯定会改变分布的形状(扭曲),这时我们需要像偏斜度这样的度量来捕捉它。下面是一个正态分布图,也称为钟形曲线。这是一个对称的图形,所有集中趋势的量度都在中间。

(图片由作者提供)
但是,如果我们遇到不对称分布,我们如何检测不对称的程度呢?让我们直观地看看当我们遇到这样的图形时,集中趋势的度量会发生什么。

(图片由作者提供)
请注意,当正态分布被扭曲时,这些集中趋势度量会如何传播。对于命名法,只需遵循尾部的方向即可——对于左图,因为尾部在左侧,所以它是左偏斜的(负偏斜),而右图的尾部在右侧,所以它是右偏斜的(正偏斜)。
如何推导出一个衡量标准来捕捉分布的众数和平均数之间的水平距离?很直观地认为,偏斜度越高,这些度量就会越分开。现在让我们跳到偏斜度的公式:

除以标准差可以在相同的标准标度上进行分布的相对比较。由于不建议将众数计算作为小数据集的集中趋势,因此为了得到更可靠的偏度公式,我们将使用从中值和平均值导出的计算结果来代替众数。

*近似为偏态分布
替换偏度公式中的众数值,我们得到:


(图片由作者提供)
什么是峰度,我们如何捕捉它?
想想从顶部打孔或者拉正态分布曲线,会对分布的形状产生什么影响?让我们想象一下:

(图片由作者提供)
因此,有两件事需要注意——曲线的峰值和尾部,峰度测量负责捕捉这一现象。峰度计算的公式很复杂(在基于矩的计算中是第 4 阶矩),所以我们将坚持这个概念及其直观的清晰性。正态分布的峰度为 3,称为中峰度。大于 3 的分布称为薄分布,小于 3 的分布称为宽分布。所以值越大,峰值越大。峰度范围从 1 到无穷大。由于正态分布的峰度度量值为 3,我们可以通过保持正态分布的参考值为零来计算超额峰度。现在过度峰度将从-2 变化到无穷大。

正态分布的过度峰度= 3–3 = 0
当峰度为 1 = 1–3 =-2 时,超额峰度值最低

(图片由作者提供)
峰度的话题已经争论了几十年,这些年来峰度的基础一直与峰值相关联,但最终的结论是离群值(较胖的尾部)比均值(峰值)附近的值更能控制峰度效应。
因此,我们可以从上面的讨论中得出结论,正态分布曲线的水平推或拉失真由偏斜度度量捕获,而垂直推或拉失真由峰度度量捕获。此外,主导峰度效应的是异常值的影响,其证据来源于基于四阶矩的公式。我希望这篇博客能帮助你以一种简单的方式阐明偏度和峰度的概念,并在未来关注更多类似的博客。
谢谢!!!
为招聘流程的 GitHub 活动图换肤

作为一名软件工程师,对你来说,推销自己和你的工作的最好方式是你的 GitHub 账户。公式很简单——展示令人印象深刻的项目,定期的活动,并在你的知识库中有大量的星星和叉子。

招聘人员的圣杯— Gleb Bahmutov GitHub 活动图
就是这样。这应该足够让你参加很多面试了。
现在,成功通过这些面试的问题本身就是一个大话题,围绕它建立了一个完整的商业生态系统,所以让我们假设你已经把这部分收入囊中了。😃
然而,当招聘人员在 GitHub 上寻找工程师时,有一件重要的事情需要讨论——招聘人员通常是非技术人员。
为什么这很重要?三个原因:
首先,他们无法准确判断你所做的事情是否令人印象深刻。有时,向项目中添加 100 行代码可能意味着系统效率的彻底转变。发现这一点有时需要详细查看代码,并理解哪些内容发生了变化以及以何种方式发生了变化,以便保证所述改进。
其次,最好的程序员是这个星球上最懒的人。他们不在乎努力工作,他们在乎聪明地工作,对于程序员来说,自然的道路是尽可能多地自动化他们的生活。
最后,许多程序员非常清楚我写的第一点(上面的两段)——他们知道他们的工作没有被通常装备不足的招聘人员从外部角度公平地评判。
综合所有这些因素,我们可以得出这篇文章的中心观点:考虑到招聘过程的惊人复杂性,GitHub 为每个用户衡量和展示的生产力和技能的许多不同方面,以及招聘机构在严格的研究、方法和招聘指标上花费的时间,有没有一种方法可以自动最大化程序员对面试的适应性?
Pfft 当然有。
永远记住:如果 it 可以自动化,it 就会自动化。

GitHub 活动图表的漫画
下面是一个 50 行的 Python 脚本,它更改了一个简单文本文件中的文本,并通过随机提交消息将其推送到一个选定的存储库中。通过这样做,它在常规的基础上做了微小的改变,并确保将你的贡献沐浴在一片葱郁、春意盎然的绿色中。
虽然有许多方法可以实现 GitHub 活动的自动化,但我选择了这一种,因为它简单且有良好的记录。这只会影响你整个 GitHub 活动的一部分,但往往是招聘人员和其他工程师在评估技能时在个人资料中寻找的关键指标。
我想在结束的时候讨论一下这个问题的含义,并给你一个免责声明。
首先,不要自己用这个脚本。
我并不特别赞同自动化的使用,也不认为自动化 GitHub 活动的一部分(或全部)本质上是个坏主意。然而,我确实认为这是一个错误的价值展示,任何做最少量挖掘的人都会看到你的“活动”充满了简单的变化,而这些变化对项目没有任何贡献,这肯定会发出危险信号。
甚至可能有人为此编写了一个反脚本——检查用户的活动,并试图判断该活动是真实的还是自动化的产物。这可能会立即让你失去参加更严肃的面试的资格(例如,大型科技公司)。
这种推销自己的方法的广泛后果是,技能/经验不足的人得到的工作要求他们按照他们在 GitHub 账户上错误展示的速度工作,因此经常导致失败和错过投资(招聘人员的错误),或者精疲力尽、压力和疲劳(程序员的错误)。
总结一下——如果你在招聘,确保你不会上当,确保如果你的生产率指标是 GitHub 活动,你的员工不会这样做,除非你真的知道你在做什么,否则不要为你自己的个人资料这样做。
SKORCH:用 Scikit-Learn 包装器训练的 PyTorch 模型
理解使用 SKORCH 训练 PyTorch 模型是多么容易和简单的指南

肯尼斯·贝里奥斯·阿尔瓦雷斯在 Unsplash 上拍摄的照片
你有没有想过有没有一种工具可以简单方便地训练和评估 PyTorch 车型?这个工具确实存在,它就是 SKORCH ,一个用于训练 PyTorch 模型的 scikit-learn 包装器。
在这篇博客中,我们将讨论什么是 SKORCH ,它的组成部分,以及包装一个 PyTorch 模型来训练和评估它是多么容易。博客将分为以下几个部分:
- 什么是 SKORCH?
- PyTorch 型号
- 与斯科奇一起训练
我们开始吧!
什么是斯科奇?
SKORCH 是 scikit-learn 和 PyTorch 的并集,换句话说, SKORCH 是一个用于训练、调整和优化 PyTorch 模型的包装器。 SKORCH 是 2017 年推出的开源库【1】, SKORCH 的出现是为了将 PyTorch 和 SciKit-learn 框架的伟大优点结合在一起并加以增强。

图一。PyTorch + SciKit-Learn = SKORCH |作者图片|取自原始来源的徽标
PyTorch 是开发神经网络模型最常用的框架之一,然而,有些阶段需要开发时间,有时它会成为有些不切实际的部分。斯科奇试图简化 PyTorch 车型培训阶段的各种流程。在一个或多个功能中开发 PyTorch 模型的训练模块是很常见的,然而,当需要评估模型或优化以找到最佳参数时,需要开发额外的功能。所有这些过程都被 SKORCH 简化了,因为它是基于 scikit-learn 的包装,因此扩展了已经执行这些过程的函数。
斯科奇宣称他的哲学是:“做一个科学的人——学习 API,学会黑客,不要隐藏 PyTorch,不要重新发明轮子”
在图 2 中,我们可以看到复合了斯科奇的 PyTorch 和 scikit-learn 的能力。正如我们所见,从 PyTorch 方面来看,原型化模型和处理数据集的能力被使用了。另一方面,我们观察到 scikit-learn 已知的函数被扩展到能够训练、评估、调整和优化机器学习模型,这种组合使 SKORCH 成为一个强大的工具。

图二。PyTorch 和 scikit 的优势-了解 SKORCH |作者图片|来自原始来源的徽标
另一方面,我们可以将 SKORCH 视为 Keras API 的等价物,它从 Tensorflow 扩展而来,以加速、简化和加快神经网络模型的原型化。在这种情况下, SKORCH 将作为 PyTorch 模型的训练、调整和优化阶段的原型工具。
太好了,到目前为止我们已经知道了 SKORCH 是什么,它的组件是什么,使用它的优势是什么,是时候看看一个例子来更好地了解它的工作原理了,让我们开始吧!
PyTorch 模型
为了了解 SKORCH 在训练 PyTorch 模型时是如何工作的,我们将创建一个神经网络来预测众所周知的葡萄酒数据集。因此,首先我们将根据上述数据集创建一个简单的葡萄酒分类模型,然后我们有:
如果你想访问完整的实现,看看:https://github.com/FernandoLpz/SKORCH-PyTorch-Wrapper
代码片段 1。PyTorch 模型
正如我们所看到的,有些值是固定的。实际上,我只想强调第 9 行和第 12 行。在第 9 行中,我们定义了 13 个输入特征,这是因为葡萄酒数据集包含 13 个特征。另一方面,在第 12 行中,我们定义了大小为 3 的输出,这是因为我们要分类的类是 3(即 3 种类型的葡萄酒)。
完美, PyTorch 模型做好了,是时候看看我们如何用 SKORCH 训练这个模型了,让我们进入下一节!
与 SKORCH 一起训练
1.基础训练
通过 SKORCH 进行的培训可以根据我们的需要简单或复杂,对于实际例子,我们将逐步进行。因此,训练上一节中定义的模型的一个基本而简单的方法就像下面几行代码一样简单:
代码片段 2。简单训练
我们将逐行分析。在第 2 行中,我们导入了 PyTorch 模型(在前面的部分中已经定义)。在第 4 行中,我们导入了一个类,它将作为我们的 PyTorch 模型的包装器。该类接收一系列重要参数(第 7 行),它们是:PyTorch 模型,历元数,学习率,批量,优化器。显然,它们不是我们在这个类中可以定义的唯一参数,然而为了实用,我们将只显示在这个例子中已经提到的那些参数。最后,在第 9 行,我们执行“ fit ”方法,它将负责执行整个训练阶段。
您可能想知道,“那么分解成训练和验证呢?”,那么 NeuralNetClassifier 类也会处理这个问题。默认情况下,该类实现数据的 StratifiedKFold 分割,80%用于训练,20%用于验证。好了,一旦上面提到,这将是输出:
epoch train_loss valid_acc valid_loss dur
------- ------------ ----------- ------------ ------
1 9.6552 0.4167 9.2997 0.0124
2 9.6552 0.4167 9.2997 0.0109
3 9.6552 0.4167 9.2997 0.0107
4 9.6552 0.4167 9.2997 0.0109
5 9.6552 0.4167 9.2997 0.0116
6 9.6552 0.4167 9.2997 0.0119
7 9.6552 0.4167 9.2997 0.0114
8 9.6552 0.4167 9.2997 0.0113
9 9.6552 0.4167 9.2997 0.0115
10 9.6552 0.4167 9.2997 0.0115
输出的结构如前面的代码片段所示。正如我们所看到的,默认情况下它显示了关于训练和验证集合中损失的信息,以及验证中精度和执行时间的信息。由于我们没有调整模型,结果非常差,但是,我们将在接下来的例子中解决这个问题。
2.管道:定标员+培训
在上一点中,我们看到了如何用 SKORCH 以一种基本的方式训练模型。然而,数据处理是一个非常重要的阶段,总是在训练阶段之前进行。在这种情况下,我们将执行一个非常简单的预处理,我们将只对数据进行缩放,然后我们将执行训练,为此,我们将利用 scikit-learn Pipeline 模块,因此我们将拥有以下内容:
代码片段 3。涉及扩展和培训的管道
在第 5 行和第 6 行,我们从 scikit-learn 导入了流水线和 StandardScaler 模块。在第 12 行中,我们可以看到,我们初始化包装器的方式与上一点完全相同(使用固定值),有趣的事情出现在第 14 行和第 15 行,在那里管道被初始化,它包含 StandarScaler() 模块以及 PyTorch 模型的包装。运行这个程序,我们得到:
epoch train_loss valid_acc valid_loss dur
------- ------------ ----------- ------------ ------
1 0.4663 0.8889 0.3528 0.0124
2 0.0729 0.8889 0.6507 0.0111
3 0.0420 0.9167 0.4564 0.0118
4 0.0101 0.9167 0.3142 0.0116
5 0.0041 0.9167 0.3321 0.0119
6 0.0028 0.9167 0.3374 0.0129
7 0.0022 0.9167 0.3376 0.0111
8 0.0017 0.9167 0.3384 0.0122
9 0.0014 0.9167 0.3373 0.0135
10 0.0012 0.9167 0.3378 0.0118
需要强调的是,结果显著改善,这是由于在训练阶段之前对数据进行了缩放。
到目前为止,我们已经看到了如何在执行管道中将 PyTorch 模型(具有固定参数)训练为 scikit-learn 模块,然而,我们如何将其他评估指标(如准确性或平衡准确性添加到 SKORCH 模块,这就是我们利用回调的地方。
3.管道:定标员+培训+回访
回调是 SKORCH 的扩展,它允许我们向 NeuralNetClassifier 包装器添加其他函数,例如,如果我们希望优化指标是 balanced_accuracy 或 ROC 或任何其他分类指标,这可以通过回调来完成。因此,引入一个回调来计算流水线内模型的精度和平衡精度如下:
代码片段 4。涉及扩展、培训和回访的渠道
因此,正如我们在第 9 行看到的,我们导入了划时代 回调。为了使用回调,我们只需通过传递我们想要用作参数的度量的名称来初始化它,在这种情况下,我们为度量初始化“ balanced_accuracy 和“ accuracy ”。此外,我们必须将参数“ lower_is_better ”设置为“ False ”,因为我们的问题寻求度量的最大化,而不是最小化。
因此,执行前面的代码片段的结果将类似于:
epoch accuracy balanced_accuracy train_loss valid_acc
------- ---------- ------------------- ------------ -----------
1 0.9722 0.9762 0.4780 0.9722
2 1.0000 1.0000 0.0597 1.0000
3 1.0000 1.0000 0.0430 1.0000
4 1.0000 1.0000 0.0144 1.0000
5 1.0000 1.0000 0.0110 1.0000
6 1.0000 1.0000 0.0083 1.0000
7 1.0000 1.0000 0.0067 1.0000
8 1.0000 1.0000 0.0058 1.0000
9 1.0000 1.0000 0.0047 1.0000
10 1.0000 1.0000 0.0039 1.0000
最后,我们将看到如何使用 scikit-learn 模块执行网格搜索,让我们开始吧!
4.GridSearch:管道+定标器+培训+回调
要执行网格搜索,我们只需导入 scikit-learn 模块。执行网格搜索与从 scikit-learn 中学习机器的经典模型完全相同,唯一的不同点在于网格参数的定义。
代码片段 5。网格搜索定义
正如我们所看到的,参数有一个特殊的方面。我们正在添加前缀“ nn__ ”和“ nn__module__ ”。这些前缀将帮助包装器知道参数是属于 PyTorch 模型的定义还是属于训练阶段。正如我们所看到的,当我们提到训练阶段的参数时,我们只使用前缀“ nn__ ”,当我们提到 PyTorch 模型的参数时,我们只使用前缀“nn __【模块 _ _】”。重要的是名称“ nn ”指的是包装器的实例化(第 19 行)。
因此,如果我们想知道最佳参数是什么,我们可以很容易地做到:
[1] print(gs.best_params_)
{'nn__lr': 0.1, 'nn__max_epochs': 10, 'nn__module__dropout': 0.1, 'nn__module__num_units': 10, 'nn__optimizer': <class 'torch.optim.adam.Adam'>}
如果你想访问完整的实现,看一看:https://github.com/FernandoLpz/SKORCH-PyTorch-Wrapper
结论
在这篇博客中,我们已经看到了什么是 SKORCH 及其组成部分。我们还看到了如何实现 NeuralNetClassifier 包装器,以非常简单的方式训练 PyTorch 模型。
在我看来,斯科奇会留下来。有时需要快速灵活地构建 PyTorch 模型的原型,SKORCH 在这方面做得非常好。
参考
[1]https://skorch.readthedocs.io/en/latest/index.html
https://www.youtube.com/watch?v=Qbu_DCBjVEk
Sktime:用于时间序列机器学习的统一 Python 库
用于时间序列预测、分类和回归的“sklearn”

用 Python 解决时间序列数据的数据科学问题是一项挑战。
为什么?现有工具不太适合时间序列任务,并且不容易集成在一起。scikit-learn 包中的方法假设数据是以表格格式组织的,并且每一列都是独立的——这些假设不适用于时间序列数据。包含时间序列学习模块的包,比如 statsmodels ,不能很好地集成在一起。此外,许多基本的时间序列操作,如将数据分割成不同时间的训练集和测试集,在现有的 python 包中是不可用的。
为了应对这些挑战,sktime 应运而生。

sktime 库的 logo(Github:https://github.com/alan-turing-institute/sktime)
sktime 是一个开源的 Python 工具箱,用于时间序列的机器学习。这是一个由社区推动的项目,由英国经济和社会研究委员会、消费者数据研究中心和艾伦图灵研究所资助。
sktime 将 scikit-learn API 扩展到时间序列任务。它提供了有效解决时间序列回归、预测和分类任务所需的算法和转换工具。该库包括专用的时间序列学习算法和转换方法,在其他常见库中不容易获得。
sktime 旨在与 scikit-learn 进行互操作,轻松调整相关时序任务的算法,并构建复合模型。如何?许多时序任务是相关的。可以解决一个任务的算法通常可以被重用来帮助解决一个相关的任务。这个想法叫做还原。例如,时间序列回归模型(使用序列来预测输出值)可以重新用于时间序列预测任务(预测的输出值是未来值)。
使命陈述:“sk time 用时间序列实现可理解、可组合的机器学习。它提供了 scikit-learn 兼容的算法和模型合成工具,由学习任务的清晰分类提供支持,具有指导性的文档和友好的社区。”
在本文的其余部分,我将重点介绍 sktime 的一些独特特性。
时间序列的适当数据模型
Sktime 对熊猫数据框架中的时间序列使用嵌套数据结构。
典型数据框中的每一行都包含 i.i.d .观测值,每一列代表不同的变量。对于 sktime 方法,Pandas 数据框中的每个像元现在都可以包含一个完整的时间序列。这种格式对于多变量、面板和异质数据是灵活的,并且允许在 Pandas 和 scikit-learn 中重用方法。
在下表中,每一行都是一个观察值,X 列中包含一个时间序列数组,y 列中包含类值。sktime 估算器和转换器可以对此类序列进行操作。

原生时序数据结构,兼容 sktime。
在下一个表格中,按照 scikit-learn 中方法的要求,X 系列中的每个元素都被分成单独的一列。维度相当高— 251 列!此外,表格学习算法会忽略列的时间顺序(但时间序列分类和回归算法会使用)。

scikit-learn 所需的时序数据结构。
对于将多个同现序列建模在一起的问题,与原生序列数据结构兼容的 sktime 显然是最好的。根据 scikit-learn 所期望的表格格式的结构化数据训练的模型会在大量的特性中陷入困境。
sktime 能做什么?
根据 Github 页面,sktime 目前提供:
- 用于时间序列分类、回归和预测的最新算法(移植自基于 Java 的 tsml 工具包),
- 时间序列的转换器:单序列转换(例如,去趋势化或去季节化)、序列作为特征转换(例如,特征提取器)以及组成不同转换器的工具。
- 变压器和模型的流水线作业,
- 模型调整,
- 模型集合——例如,用于时序分类和回归的完全可定制的随机森林;多元问题的集成。
sktime API
如前所述,sktime 遵循带有 fit、predict 和 transform 类方法的基本 scikit-learn API。
对于估计器(又名模型)类,sktime 提供了一个用于模型训练的拟合方法和一个用于生成新预测的预测方法。
sktime 中的估计器将 scikit-learn 的回归器和分类器扩展到它们的时间序列对应项。Sktime 还包括专门针对时间序列任务的新估算器。
对于 transformer 类,sktime 提供了 fit 和 transform 方法来转换系列数据。有几种类型的转换可用:
- 对 i.i.d .实例进行操作的表格数据转换器,如 PCA
- 将每一行中的时间序列转换成基元数(例如特征事务)的序列到基元转换器;
- 串-串变压器将级数转换成不同的级数(例如级数的傅立叶变换);
- 去趋势转换器返回与输入序列相同域中的去趋势时间序列(例如,季节性去趋势)。
代码示例
时间数列预测法
以下示例改编自 Github 上的预测教程。本例中的系列(Box-Jenkins 航空公司数据集)显示了从 1949 年到 1960 年每月的国际航班乘客人数。
首先,加载数据,并将其分为训练集和测试集,然后进行绘图。sktime 提供了两个方便的函数来轻松做到这一点——temporal_train_test_split用于按时间分割数据集,而plot_ys用于绘制训练和测试序列值。

在您创建任何复杂的预测之前,将您的预测与一个天真的基线进行比较是有帮助的—一个好的模型必须超过这个值。sktime 提供了NaiveForecaster方法,采用不同的“策略”来生成基线预测。
下面的代码和图表展示了两个天真的预测。具有 strategy = "last "的预测器总是预测系列的最后观察值。具有 strategy = "seasonal_last "的预测器预测给定季节中观察到的序列的最后一个值。示例中的季节性被指定为“sp=12”,即 12 个月。

下一个预测片段展示了现有的 sklearn 回归器如何以最小的努力轻松、正确地适应预测任务。下面,sktime ReducedRegressionForecaster方法使用 sklearn RandomForestRegressor模型来预测序列。在内部,sktime 将训练数据分割成长度为 12 的窗口,以便回归变量进行训练。

sktime 也包含了原生的预测方法,比如AutoArima。

要更全面地了解 sktime 的预测功能,请查看 sktime 预测教程。要了解预测的时态交叉验证,请查看以下文章。
如何用 python 中的 sktime 执行时态交叉验证
towardsdatascience.com](/dont-use-k-fold-validation-for-time-series-forecasting-30b724aaea64)
时间序列分类
最后,sktime 可用于将时间序列分为不同的序列组。
在下面的代码示例中,单个时间序列的分类与 scikit-learn 中的分类一样简单。唯一的区别是上面讨论的嵌套时间序列数据结构。
从 https://pypi.org/project/sktime/借用的示例代码

传递到 TimeSeriesForestClassifier 的数据。
要更全面地了解时间序列分类,请查看下面链接的我关于时间序列分类的文章以及 sktime 单变量和多变量分类教程。
专门为时间序列分类设计的专用算法
towardsdatascience.com](/a-brief-introduction-to-time-series-classification-algorithms-7b4284d31b97) [## 微型火箭:快速和准确的时间序列分类
使用 Python 实现系列分类的最快的先进算法
towardsdatascience.com](/minirocket-fast-er-and-accurate-time-series-classification-cdacca2dcbfa) [## ROCKET:快速准确的时间序列分类
“时间序列分类的任务可以被认为是学习或检测信号或模式…
link.medium.com](https://link.medium.com/qYcaC7lL69) [## 不要对时间序列预测使用 K-fold 验证
如何用 python 中的 sktime 执行时态交叉验证
towardsdatascience.com](/dont-use-k-fold-validation-for-time-series-forecasting-30b724aaea64)
附加 sktime 资源
要了解更多关于 sktime 的信息,请访问下面的链接,获取深入的文档和示例。
- 详细 API 参考:sktime.org
- sktime github 页面(带文档)
- 示例笔记本
- Sktime 论文:Markus lning,Anthony Bagnall,Sajaysurya Ganesh,Viktor 卡萨科夫,Jason Lines,Franz király(2019):《sk Time:时间序列的机器学习统一接口》
不是中等会员?今天就加入!
[## 阅读亚历山德拉·阿米登(以及媒体上成千上万的其他作家)的每一个故事
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
alexandra-amidon.medium.com](https://alexandra-amidon.medium.com/membership)
进一步阅读
towardsdatascience.com](/pyod-a-unified-python-library-for-anomaly-detection-3608ec1fe321) [## 如何对时间序列数据应用 K 均值聚类
使算法适应时间序列的理论和代码
towardsdatascience.com](/how-to-apply-k-means-clustering-to-time-series-data-28d04a8f7da3)
用熊猫切片和索引
PyTrix 系列
PyTrix #4:用熊猫访问数据

由 Marvin Meyer 在 Unsplash 上拍摄的照片
PyTrix 是一个每周一期的系列文章,我在其中展示了可以用 Python 完成的对数据科学家有用的很酷的东西。在 PyTrix 系列的前几周,我们主要研究了 Numpy 数组,具体来说是索引和切片…
访问 Numpy 数组中的元素
towardsdatascience.com](/working-with-numpy-arrays-indexing-e4c08595ed57) [## 使用 Numpy 数组:切片
PyTrix #3:访问 Numpy 数组中的序列
towardsdatascience.com](/working-with-numpy-arrays-slicing-4453ec757ff0)
Pandas 是一个快速、强大、灵活且易于使用的开源框架,它构建在 Python 之上,用于数据操作和分析,就像 Numpy 一样,是数据科学事实上的库之一。很大一部分人很可能是从学习熊猫开始他们的数据科学之旅的,如果你没有,那么我强烈建议你阅读文档——当然是在阅读了这个故事之后。
要访问 Github 中使用的代码,请单击下面的链接。
permalink dissolve GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/kurtispykes/demo/blob/master/pytrix/pytrix_pandas_indexing-and-slicing.ipynb)
索引的选择
对于许多学习熊猫来说,他们的多轴索引方法很少被实践者理解,这是公平的,因为有许多方法来进行对象选择:
.loc主要基于标签,这意味着它从索引中选择带有显式标签的行(或列)。因此,如果没有找到项目,将引发一个KeyError。.iloc主要基于整数位置(从 0 到轴的长度-1 ),这意味着行(或列)是根据其在索引中的位置来选择的——它只接受整数。如果索引器越界,则会引发IndexError。[]主要用于筛选出低维切片。
注意:Python 和 NumPy 索引操作符
[]和属性操作符.提供了跨越广泛用例的对 pandas 数据结构的快速和简单的访问。这使得交互式工作变得直观,因为如果您已经知道如何处理 Python 字典和 NumPy 数组,就没有什么新东西需要学习了。然而,由于要访问的数据类型事先不知道,直接使用标准操作符有一些优化限制。对于生产代码,我们建议您利用本章中介绍的优化的 pandas 数据访问方法。-熊猫的摘录文档
使用[ ]的属性访问
对于那些一直关注 PyTrix 系列的读者,或者如果您对 Python 索引行为有所了解,那么您会知道用于索引低维切片的主要方法是[]。
import pandas as pd
import numpy as np df= pd.DataFrame(np.random.randn(5, 5),
columns=["col_1", "col_2", "col_3", "col_4", "col_5"])df

图 1
*# access all elements in "col_1"*
df["col_1"]>>>> 0 0.32
1 0.74
2 0.14
3 0.79
4 0.58
Name: col_1, dtype: float64
从上面我们可以看到,使用[]来索引 Pandas DataFrame 类会返回一个对应于列名的series。如果数据是一个series,将返回一个标量,例如我将使用上面返回的序列来显示我们可以像这样返回一个标量:
a = df["col_1"]
a[1] >>>> 0.79390631428754759
这是最基本的索引形式。我们也可以将一个列列表传递给[]来按顺序选择列。
df[["col_2", "col_3", "col_4"]]

图二。
我不会深入研究这个功能,因为它非常类似于普通 Python 和 Numpy 中的索引和切片,除了开始和结束边界都被返回。
按标签选择
Pandas 使用一个严格的基于包含的原则,允许所有用于基于标签的索引的方法正确运行——未能提供一个不在索引中的标签将引发KeyError。
对于这一部分,我将创建一个新的熊猫数据框架
new_df = pd.DataFrame(np.random.randn(10, 4), index=list("abcdefghij"), columns=list("ABCD"))new_df

图 3。
按标签选择时,.loc属性是主要的访问方法。.loc的有效输入如下:
- 单个标签(注意,标签可以是整数,不涉及沿索引的整数位置)
# cross-section using a single label
new_df.loc["a"]>>>> A 0.952954
B -1.310324
C -1.376740
D 0.276258
Name: a, dtype: float64
- 标签的列表或数组
# A list or array of labels
new_df.loc[["a", "d ", "i"]]

图 4。
- 带标签的切片(注意,与 Python 切片相反,开始和结束边界都包含在切片中)
# slice with labels
new_df.loc["a":"d", "B":]

图 5。
- 布尔数组
# a boolean array
new_df.loc["j"] > 0.5>>>> A False
B False
C True
D True
Name: j, dtype: bool # another way to use a boolean array
new_df.loc[:, new_df.loc["j"] > 0.5]

图 6。
按位置选择
Pandas 使用符合 Python 和 Numpy 切片语义的0-based索引。有多种方法可用于通过使用纯基于整数的索引按位置访问元素。试图使用一个非整数,不管其有效性如何,都会引发一个IndexError。
*# using same df but new index values* new_df.index = list(range(0, 10))
new_df

图 7。
按位置选择时,.iloc属性是主要的访问方法。.iloc的有效输入如下:
- 整数
*# cross section using an integer position*
new_df.iloc[3]>>>> A -0.650225
B 1.571667
C -1.204090
D 0.637101
Name: 3, dtype: float64
- 整数的列表或数组
*# list or array of integers*
new_df.iloc[[1, 5, 2, 3]]

图 8。
# another example
new_df.iloc[[1, 2, 3, 4], [0, 1, 2]]

图 9。
- 带有整数的切片对象
# integer slicing
new_df.iloc[:3]

图 10。
# integer slicing by column
new_df.iloc[:, :3]

图 11。
- 布尔数组。
new_df.iloc[1:] > 0.5

图 12。
当使用超出界限的切片时,这可能导致空轴。
new_df.iloc[10:13]

图 13。
然而,如果我们试图调用一个越界的索引器,这将引发IndexError。此外,如果我们试图调用任何元素越界的索引器列表,那么这也会引发一个IndexError。
注意:是否为设置操作返回副本或引用,可能取决于上下文。这有时被称为
**chained assignment**,应该避免。参见 返回视图与 复制。
可调用选择
以上所有属性都可以接受一个叫做callable的东西作为索引器。对callable的要求是,它必须是一个带有一个参数的函数,返回索引的有效输出。
# selection by a callable using []
new_df[lambda df: df.columns[3]]>>>> 0 0.276258
1 -0.617174
2 0.229638
3 0.637101
4 0.977468
5 0.401624
6 -0.659852
7 0.984220
8 0.947080
9 1.182526
Name: D, dtype: float64
这将返回索引 3 处的一系列列(在此场景中,索引 3 处的列是“D”)。
# selection by a callable using .loc
new_df.loc[:, lambda df: ["A", "B"]]

图 14。
在这个例子中,我们使用.loc属性返回所有的行和列 A 和 B。下面我们将使用.iloc做完全相同的事情。
# selection by a callable using .iloc
new_df.iloc[:, lambda df: [0, 1]]

图 15。
包裹
Pandas 对于数据科学家来说是一个非常有用的工具。值得通读一下文档看看这个包里还有什么很酷的东西,因为有太多东西我在这篇文章里没有涉及到,例如如何在pd.Series上使用这些操作。
感谢您花时间阅读这个故事。如果你喜欢它,你可以在 PyTrix 系列中找到更多类似的文章。
阅读《走向数据科学》中关于 Pytrix 系列的文章。共享概念、想法和代码的媒体出版物。
towardsdatascience.com](https://towardsdatascience.com/tagged/pytrix-series)
如果您想亲自联系我,我是 LinkedIn 上最活跃的用户,我会非常乐意与您联系!
[## Kurtis Pykes -人工智能博客-走向数据科学| LinkedIn
在世界上最大的职业社区 LinkedIn 上查看 Kurtis Pykes 的个人资料。Kurtis 有两个工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/kurtispykes/)
Power BI 中的图像数据切片
您可以用许多不同的方式在 Power BI 中分割数据。但是,你知道你也可以使用图像切片和切块吗?比你想象的简单…

安德鲁·罗伯特·劳科在 Unsplash 上拍摄的照片
你知道我是一个强力 BI 的传播者。关于 Power BI,我最喜欢的一点是,它让您可以灵活地以多种不同的方式讲述数据故事。基本上,您不仅仅局限于现成的解决方案(尽管如此,这些解决方案通常非常复杂,足以满足您所有的报告需求)。
通过一些创意和一些小调整,你可以为你的用户创造一个难忘的体验。他们会因此而感激你!
简单的要求—简单的解决方案!
几周前,我正在为我们的销售部门做一份报告。销售人员对报告设计的要求不是很高——他们希望尽可能快地看到他们的数字,不要太关注视觉效果。
本质上,他们会很感激有这样的东西:

所以,两个简单的视觉效果,和一个切片器用来切片和切割数据。而且没毛病!但是,由于我有一些额外的时间投入到这份报告的开发中,我决定向他们提供一个更吸引眼球的解决方案…
像往常一样,我在所有示例中使用 Contoso 示例数据库。
利用 PowerPoint 的优势
当我想创建一个漂亮的报告背景时,我喜欢使用 PowerPoint。这给了我将所有想法、视觉占位符、文本框等分组的可能性。在一个地方。这样做还会减少我的 Power BI 报告画布上的视觉效果数量,从而减少报告渲染所需的时间。
使用 PowerPoint,你可以用一个画面代替多个画面!诀窍是——一旦你创建了你想要的背景,只需将其保存为. png 或。jpeg 文件:

顺便说一下,这是我的报告背景的样子:

让我简单解释一下新报告外观的想法。画布中间的两个大占位符将包含主要视觉效果。左手边就是神奇发生的地方!
我已经决定把图像和使用它们,而不是简单的切片器视觉。通过这种方式,我的用户将获得类似应用程序的体验,就像他们在浏览网站一样。
书签掌握着关键!
书签是 Power BI 中最酷的功能之一!基本上,【Bookmark 所做的是,它捕获报告的当前状态,因此您可以通过按钮、图像、形状将它用作您行动的参考…这将基本上为您的报告创建类似应用程序的体验,并使其看起来具有交互性。
确实有十几个可以应用书签的用例,这是其中之一。
第一步是把我们用 PowerPoint 创建的背景,作为 Power BI 中的背景图片:

现在,我将在左侧的占位符中插入图标。这些图标将用于在各种书签之间导航用户:

关于报告中使用的图像的简短说明:
- 标有绿色箭头的图像将被用作“切片器”
- 标有红色箭头的图像将用于指示当前应用的“切片器”
- 标有黄色箭头的图像将帮助我们回到起点,查看所有产品类别的数据(未应用切片器)
我创建的第一个书签将捕获报告的默认外观,包括所有产品类别:

这里最重要的事情是 选中 ,因为这将捕获页面的当前状态,包括所有应用的过滤器(在我们的例子中,没有应用过滤器)!
现在让我们为音频产品类别创建一个视图。我将隐藏除音频以外的所有图像。这里的关键是 应用滤镜面板 中的滤镜,以便只显示音频产品类别的数据!

同样,在创建书签时,保持选中数据选项。对其他产品类别重复相同的步骤,这样书签窗格的最终外观将会提醒您:

现在,我们需要为我们的图像指定动作,这样它们就可以在不同的书签之间导航。让我向您展示音频产品类别是如何做到这一点的,然后您可以轻松地对其余类别采用相同的模式:

最后一步是对我们的用户隐藏过滤器窗格,因为他们不需要知道报告是如何工作的:

在我向 Power BI Service 发布我的报告后,下面是它的样子:

如果你问我,那看起来比我们的起点好多了:)
结论
正如我已经多次说过的,Power BI 在灵活性方面非常强大。您已经看到了一些基本的背景格式、书签和图像的巧妙使用如何将您的报表推向一个全新的水平。
不用我说,我的销售团队在得到这份报告后都肃然起敬。这是本文中最重要的一点:为了让你的用户能够享受使用报告的乐趣,一定要付出额外的努力!
感谢阅读!
订阅这里获取更多有见地的数据文章!
Slideio:一个用于阅读医学图像的新 python 库。

这是一个新的 python 库的介绍,用于医学图像的阅读。更多详细信息可在项目网站上找到:www.slideio.com。源代码可以在 GitLab 的知识库中找到:【https://gitlab.com/bioslide/slideio。
介绍
医学图像—由生物扫描仪、显微镜等产生的图像。与普通图像不同。其中一个重要的区别是它们的大小。这种图像可能非常大。目前,大小为几十亿字节的幻灯片并不罕见。另一个区别是维度的数量。许多生物图像格式支持 3 维和 4 维(体积和时间序列)。除了传统的尺寸之外,一些格式引入了扫描仪特定的尺寸,如焦距、旋转(对于从各种角度记录的数据)、相位指数等。
不可能用传统的压缩方法来编码数千兆像素的图像。jpeg 或 png 等图像编解码器需要将整个图像保存到计算机内存中,以便在屏幕上显示,甚至读取图像的一小部分。生物格式使用平铺方法和缩放金字塔来解决这些问题。它允许以最小的内存和计算资源读取任意比例的图像的任意区域。缩放金字塔是一组不同比例的图像副本。

Slideio library 旨在使用医学图像的内部结构来读取医学图像,以尽可能提高过程的性能。Slideio 并不是第一个提供这种功能的库。在我的图像分析实践中,我使用了许多不同的库。但到目前为止,我没有找到任何库可以满足我对图像分析的所有要求。所以我决定创建我自己的,它应该聚合我在这方面的经验。
该库有一个驱动程序架构。每个驱动程序支持一种或多种图像格式。slideio 的第一个版本提供了 4 个驱动程序:
- CZI——读取蔡司 CZI 图像的司机。
- SVS——读取 Aperio SVS 图像的驱动程序。
- AFI——读取离子荧光图像的驱动程序。
- GDAL——读取 jpeg、png、tiff 等通用格式的驱动程序。它使用了流行的 c++图像库 GDAL 。
Slideio 库有一个简单的对象结构:

图像驱动程序创建幻灯片对象。Slide 对象代表单个图像文件(或文件夹,取决于图像格式)。幻灯片对象包含至少一个连续光栅区域的场景对象(2D 图像、体积、时间序列等)。一些图像格式支持单个场景,如单个组织扫描。一些格式允许在一个文件中存储多个组织区域。2D 场景的所有图层都具有相同的像素大小和分辨率。如果场景是 3D 体积,则该体积的所有切片具有相同的大小和分辨率。时间序列也是如此。
以下代码片段显示了如何使用“SVS”图像驱动程序打开幻灯片:
图像元数据
Slideio 库提供不同级别的图像信息。幻灯片对象具有属性“raw_metadata ”,该属性公开了从图像中提取的未修改的文本信息。文本内容特定于文件格式。在 Aperio SVS 幻灯片的情况下,它是从“图像信息”tiff 标签中提取的字符串。对于蔡司 CZI 文件,它是一个带有完整文件元数据的 XML 文档。以下是从 Aperio SVS 文件中检索元数据的代码片段:
下面是代码示例产生的输出:
['Aperio Image Library vFS90 01\r\n20320x19545 [0,100 19919x19445] (240x240) JPEG/RGB Q=70',
'AppMag = 20',
'StripeWidth = 2032',
'ScanScope ID = SS1598',
'Filename = 24496',
'Date = 11/09/11',
'Time = 18:51:40',
'Time Zone = GMT+09:00',
'User = e8ddb309-efc1-4a6b-b9b0-7c555f9fa0ef',
'MPP = 0.4962',
'Left = 23.939867',
'Top = 19.531540',
'LineCameraSkew = 0.000320',
'LineAreaXOffset = 0.060417',
'LineAreaYOffset = 0.011084',
'Focus Offset = -0.000500',
'DSR ID = ap6101-dsr',
'ImageID = 24496',
'Exposure Time = 109',
'Exposure Scale = 0.000001',
'DisplayColor = 0',
'OriginalWidth = 20320',
'OriginalHeight = 19545',
'ICC Profile = ScanScope v1']
光栅存取
场景是访问栅格数据的主要对象。它公开了以下信息:
- 压缩:数据压缩的类型;
- 放大:扫描仪放大;
- 名称:场景名称;
- num_t_frames :时间序列中的时间帧数;
- num_z_slices :卷中的切片数;
- rect :场景矩形的坐标和尺寸;
- 分辨率:场景平面内的分辨率(一个元组);
- t_resolution , z_resolution :场景在时间和 z 方向的分辨率;
- 通道数:场景中的通道数;
- 通道数据类型:图像通道的数据类型(字节、16 位等。);
- 通道名称:图像通道的名称。
以下代码片段检索场景名称、矩形和分辨率。
它产生以下输出:
('Image', (0, 0, 19919, 19445), 3, (4.961999999999999e-07, 4.961999999999999e-07))
该图像的宽度为 19919 像素,高度为 19445 像素。每个像素在 x 和 y 方向上都是 0.4962 mkm。该图像有 3 个通道。生物图像中通道的含义取决于图像格式。对于亮场图像,它只是红色、绿色和蓝色。这种图像有 3 个 8 位通道。通道属性可通过方法 get_chanel_data_type 和 get_channel_name 访问。
uint8
uint8
uint8
方法 read_block 检索连续区域的像素值。在没有参数的情况下执行该方法会以原始大小检索整个场景。通常情况下,由于尺寸较大,不可能以原始比例读取整个图像。在这种情况下,程序可以检索图像的一个区域,将其缩小到可接受的大小,或者检索一个缩小的区域。下面是一段代码。检索整个图像并将其缩放为 500 像素宽的图片。请注意,用零代替图片高度表示必须自动计算图片高度,以保持 x 和 y 方向的比例不变。

下面的代码片段从图像中读取一个矩形区域,并将其缩小为 500 像素宽的图片。

可以读取单个通道或通道子集:

附加的元组参数切片和帧允许读取体积和时间序列;
(1000, 1000, 27)
装置
slideio 库可以与 pip 一起安装:
pip install slideio
目前,仅支持 Linux 和 Windows 版本。
结论
Slideio 是一个用于阅读医学图像的 python 模块。它允许阅读整张幻灯片以及幻灯片的任何区域。大幻灯片可以有效地缩小尺寸。该模块使用图像的内部缩放金字塔来使缩放过程尽可能快。Slideio 支持 2D 幻灯片以及 3D 数据集和时间序列。
该库以 numpy 数组的形式提供栅格,并与许多流行的图像分析库兼容,如 opencv 。
目前,它支持阅读 Aperio SVS 和 AFI 文件,蔡司 CZI 文件和通用格式。以下格式的即将推出的驱动程序:

- 珀金埃尔默图像
- 徕卡 SCN 图像
- DICOM 数据集
- 徕卡 lif 图像
- 还有更多…
感谢您的阅读。如有任何意见或建议,我们将不胜感激。
COVID 疫情期间 Rt 估计的滑动 SIR 模型

图片来自 Unsplash 由 Patrick Assalé 拍摄
流行病的一个主要特征是有效繁殖数( Rt ),它表示每个被感染个体在任何给定时间将进一步感染的人数。能够估计出 Rt 是一项重要的任务,因为这个数字定义了疫情是预计会增长(Rt1),还是会开始下降(Rt1)。在本帖中,我建议使用滑动 SIR 方法来估计 Rt ,该方法基于 SIR 流行病模型与不同国家的感染数据的拟合。
本文介绍了我们与莫斯科国立罗蒙诺索夫大学 的 塔吉扬娜·佩特洛娃 的联合研究。我们这里描述的代码在 GitHub 上有 ,你可以在Azure Codespaces或 Azure 笔记本 中轻松运行 来做自己的研究。对应的论文是 可在 preprints.org—如果使用代码的任何部分,请 引用它 。
流行病建模
让我们从任何流行病如何演变的基础开始。描述流行病的最简单模型被称为 SIR 模型 ,因为它包含三个变量:
- S(t) — 易感 —有可能被感染的人数
- I(t) — 感染 —感染人数
- R(t)———不易感染的人数(也包括死亡人数)。
在此模型中,每个变量都是时间的函数,我们可以用公式表示以下描述模型行为的微分方程:

SIR 模型的微分方程
该模型取决于两个参数:
- β 是接触率,我们假设在单位时间内每个感染者都会接触到 βN 人。从这些人中,易感人群的比例为 S/N ,因此新感染发生的速度定义为 -βSI/N 。
- γ 是恢复率,数字 1/γ 定义一个人保持感染的天数。因此, γI 这个术语定义了被感染个体从被感染到康复的速度。
为了对流行病进行建模,我们需要用一些初始条件 S(0) 、 I(0) 和 R(0) 对这些微分方程进行数值求解。我们将使用下一本书的本章中的例子:克里斯蒂安·希尔。用 Python 学习科学编程。— 剑桥大学出版社,ISBN: 9781107428225。
首先,让我们定义微分方程的右边:
**def** **deriv**(y, t, N, beta, gamma):
S, I, R **=** y
dSdt **=** **-**beta ***** S ***** I **/** N
dIdt **=** beta ***** S ***** I **/** N **-** gamma ***** I
dRdt **=** gamma ***** I
**return** dSdt, dIdt, dRdt
假设我们想做 120 天的模型。我们将定义点的网格:
days **=** 160
t **=** np.linspace(0, days, days)
让我们在一个拥有 1200 万人口的大城市建立疫情模型——类似于我居住的城市。让我们从第 0 天的 100 名感染者开始,假设接触率为 0.2,恢复期为 30 天。模型的初始参数将是:
N **=** 12000000
I0, R0 **=** 100, 0
S0 **=** N **-** I0 **-** R0
beta, gamma **=** 0.2, 1.**/**30
然后,我们将使用初始参数求解方程,以获得时间网格中每个点的 S、I 和 R 向量:
from scipy.integrate import odeint
y0 **=** S0, I0, R0
ret **=** odeint(deriv, y0, t, args**=**(N, beta, gamma))
S, I, R **=** ret.T
plt.plot(t,S)
...

在 SIR 建模中,常见的是估计流行病 R₀ = β/γ (详见本文)。在我们的例子中,我们有 R₀ =4,这与 COVID 感染的估计数字非常相似。这个模型告诉我们,在没有任何隔离措施的情况下,在像莫斯科这样的城市,我们将在大约 80 天内一下子有大约 500 万人被感染,最终每个人都将经历这种疾病。
下面,我们展示了几个不同 R₀ 值的图表:


它有效地说明了使曲线变平的想法,因为越低的是r₀——同时感染的人数越低,这有助于最小化医疗系统的过载。
确定模型的参数
在我们的例子中,我们在某种程度上随意地取了 β 和 γ 的值。然而,如果我们有一些真实的流行病学数据,我们可以尝试通过拟合 SIR 模型来确定这些值,以最接近真实数据。在这种情况下,我们将解决优化问题,并优化参数以最小化度量。
为了获得数据,我们将使用约翰·霍普金斯大学系统科学与工程中心(CSSE)的新冠肺炎数据仓库,可从这里获得。从这个数据集中,我们将获得感染、康复和死亡的人数,以及每个国家人口的信息。我们需要做一些繁重的工作来连接这些表并调换日期,直到我们得到一个与每个国家类似的表:

然后,我们通过计算所有列的 3 天滚动平均值来平滑这些数字:
**for** x **in** ['Infected','Recovered','Deaths']:
df[x**+**"_Av"] **=** df[x].rolling(window**=**smooth_window).mean()
df['Removed_Av'] **=** df['Recovered_Av']**+**df['Deaths_Av']
我们还计算了包含从易感人群中移除的人数的Removed列。
我们将调用结果表 country dataframe ,我们的代码包含函数make_frame,该函数检索给定名称的国家的数据帧和人口。
现在,为了估计 R₀,我们需要从所有国家的一个共同点开始,比如说,从感染人数超过 1000 的那一天开始。然后,我们将关注几天的时间段,用ndays表示。考虑一周似乎是个好主意。
start_index **=** df[df['Infected_Av']**>**1000].index[0]
ndays **=** 7
V **=** df['Infected_Av'][start_index:start_index**+**ndays].to_numpy()
R **=** df['Removed_Av'][start_index:start_index**+**ndays].to_numpy()
在数组V和R中,我们保存了连续几天ndays被感染和被移除的人数。现在我们需要定义一个函数,用给定的参数 β 和 γ 计算 SIR 模型,从start_index的感染/清除人数开始,返回预测数据和实际数据之间的误差:
**def** **model**(V,R,N,beta,gamma):
t **=** np.linspace(0,len(V),len(V))
y0 **=** N**-**V[0]**-**R[0],V[0],R[0]
S,I,R **=** odeint(deriv, y0, t, args**=**(N, beta, gamma)).T
dV **=** np.diff(V)
dI **=** np.diff(I**+**R)
**return** np.linalg.norm(dV**-**dI)
我们计算误差的方法如下。因为我们拥有的最准确的数字是特定日期的累计感染总人数(不考虑已移除的人数),所以最简单的方法是计算每天的新增病例数,dV。在 SIR 模型中,与感染总人数相对应的数字将由I+R表示,即我们加上当前感染人数(I)和已经患病人数(R)。因此,SIR 模型中的每日新病例数将由I+R的日间差异给出,用dI表示。返回的误差值将是dV-dI向量的范数。
为了找到参数,我们需要针对参数 β 和 γ 优化model函数。在我们的实验中,我们发现 7 个有噪声的数据点不允许我们有效地优化两个参数,因此我们根据医学研究固定了 γ 参数(见本报道世卫组织),其表示平均恢复时间为 30 天。然后我们使用 SciKit Learn 中的minimize方法找到并返回 β 的最优值:
the_gamma **=** 1**/**30
**def** **fit**(V,R,N):
res **=** minimize(**lambda** x:model(V,R,N,x,the_gamma),
x0**=**0.5,method**=**'powell')
**return** res.x
下面你可以找到更正式的过程的数学描述。
假设 t₀ 是感染人数在 1000 以上的第一天:t₀= min {t|I(t)>1000 }。一次考虑一个国家,让我们用以下符号来表示我们拥有的数据:
- V(t) —第 t 、 t > t₀ 日累计感染病例数。
- E(t) —第 t 天的恢复病例数
- D(t) —第 t 天的死亡病例数
对于每个 β ,我们将通过 Sᵦ(t) 、 Iᵦ(t) 和 Rᵦ(t) 来表示具有以下初始值的方程(1)的解:
- s(t₀)=n-v(t₀)-d(t₀)-e(t₀)
- I(t₀)=V(t₀)
- R(t₀)=D(t₀)+E(t₀)
这里的 N 是所考虑的一个国家/城市的人口。我们认为 γ =1/30 的值是固定的。
接下来,我们需要比较预测数字与观测值的对应程度。模型计算的累计总感染人数为 Iᵦ˟(t) = Iᵦ(t)+Rᵦ(t) ,每天新增总感染人数等于 Iᵦ'(t) = Iᵦ˟(t+1)-Iᵦ˟(t) 。
每日实际新增感染病例数 V'(t)=V(t+1)-V(t) 。我们需要找到值 β* ,该值对应于 7 天期间v’(t)和 Iᵦ'(t) 之间的最小差异(我们将用 n=7 来表示所考虑的天数):

寻找 argmin 的过程是复杂的优化过程,每一步我们都需要数值求解一个 ODE (1)。我们没有梯度的显式函数,因此我们需要使用一些不依赖于梯度的优化算法。在我们的例子中,Powell 优化在速度方面提供了一个很好的折衷。
一旦我们知道了 β* ,我们就可以计算出 R₀ = β/γ* 。
以下是我们在数据集中获得的几个国家的结果:

Rt 的滑动 SIR 估计
在实践中,有趣的是看到模型的参数如何随着时间的推移而变化,以应对不同国家实施的保护措施。类似于基本生殖数 R₀ 这是一种疾病的特征,我们可以考虑有效生殖数 Rt ,其含义相同——单个感染者进一步感染的人数——但在疫情期间,考虑到隔离措施和非易感人群的比例。
我们可以按照同样的方法估算 Rt :
- 从有 1000 个感染者开始(
start_index) - 移动一个宽度为 7 天的滑动窗口(由参数
ndays表示)直到当天。 - 在每一点上,使用上述
fit函数,通过最小化实际和预测新感染人数之间的平方差,使用连续 7 天来估计β(以及 Rt)。
为了计算 Rt ,我们通过在我们国家的数据框架上组织一个滑动窗口来找到每天的最佳参数 β :
**def** **compute_params**(df,population, start_index, ndays):
**for** i **in** range(start_index,len(df)**-**ndays):
V **=** df['Infected_Av'][i:i**+**ndays].to_numpy()
R **=** df['Removed_Av'][i:i**+**ndays].to_numpy()
beta **=** fit(V,R,population)
df.loc[i,'Beta'] **=** beta
df.loc[i,'Gamma'] **=** the_gamma
一旦我们有了beta的值,我们就可以计算国家数据框架中每天的 Rt :
df['Rt'] **=** df['beta'] **/** df['gamma']
一些正式的细节如下。
从数学的角度来看,为了获得当天 t 的 Rt ,我们需要找到从 t 开始的 β 的一个最优值,而不是从 t₀ 开始。所以我们的等式(2)变成了:

这里【itᵦ'(i】也取决于 t ,因为我们需要考虑解stᵦitᵦrtᵦ的方程(1)从点 t 开始,具有以下起始条件:
- S(t)=N-V(t)-D(t)-E(t)
- I(t)=V(t)
- R(t)=D(t)+E(t)
功能 Itᵦ' 和 Itᵦ˟ 的定义方式同上。
一旦我们将 Rt 的值放入国家数据框架,我们就可以用图形的形式来研究疫情的行为。这是疫情如何在我们的祖国俄罗斯展开的:

在该图中,我们指出了隔离措施实施的两个日期:
- 4 月 2 日,T42 政府宣布了第二波隔离措施(比刚刚建议的自我隔离更加严格)
- 4 月 15 日,莫斯科和其他几个大城市引入了强制通行证
从图中,我们可以清楚地看到这些措施对 Rt 曲线斜率的影响。
为了将这个图表放入更多的背景中,我们可以在同一个图中添加每日新感染病例的数量:

在这张图上,我们还可以清楚地看到,当计算出的 Rt 值低于 1 时,疫情如何同时开始减缓。
为了能够比较国家之间的疫情传播,我们在这个图中做了两件事:
- 在 x 轴上,我们显示了自第一个 1000 例感染病例以来的天数,这使得比较流行病传播的速度成为可能,而不管实际的时间框架
- 新病例的数量是以每百万人中的病例数来衡量的,也就是说,我们按照国家人口来标准化这个数字
比较不同国家的疫情
我们正在使用的数据源包含 188 个国家的数据,其中一些国家(如我们)进一步细分为地区。它为不同的研究和比较提供了很大的自由度,这不是本文的主题。
然而,以下是我们发现有趣的几个国家的图表:

你可以点击图片放大看细节。从这个图表中,你可以看到:
- 不同国家的保护措施有多有效,
- 疫情得到控制的速度(即当 Rt graph 低于 1 时),
- 它对总体人口的影响有多严重(通过标准化的新病例数)
有几件事需要注意:
- 新病例的标准化数量在每个图表中以不同的比例显示,因此您不能直接比较它们。这样做是有目的的,使图形的形状更明显,因为在我们的例子中,它似乎比数量级更重要。
- 在所有图表中,我们显示了从 0 到 90 天的时间段,因此对于一些国家,图表结束得更早。
- 一些图表包含每日新增病例的高峰——这对应于统计数据的修正。此外,在某些情况下,这些修正是负的,我们没有在图表上显示出来。理想情况下,我们需要找到一些方法来考虑这种校正,因为它们会在 Rt 图中产生尖峰,而这在现实生活中是不会发生的(例如,看看法国在第 30 天左右的图)。
为了更清楚地看到流行病是如何展开的,从“第 0 天”开始,在一个图上绘制所有的 Rt 图是有意义的:

从这个图表中,我们可以清楚地看到瑞典的公众意识从一开始就使得 Rt 与其他国家相比非常低,但是它仍然不如检疫措施有效。此外,我们可以看到许多国家的检疫对 Rt 有非常相似的影响,俄罗斯除外,在那里我们可以看到 4 月 24 日左右的水平平台期(4 月 15 日莫斯科地铁许可证检查的可能结果)。
这里还有一个国家比较多的剧情——看起来太美了,不能省略,但另一方面又几乎不可能搞清楚细节。

如何引用
你可以免费使用来自我们的 GitHub 库的分析代码,只要你链接到我们的帖子,最好是关于 preprints.org 的论文。以下是正确的参考:
彼得罗娃,t。索什尼科夫博士;全球新冠肺炎病毒爆发的时间相关再生数的估计。预印本 2020,202006 02 89(doi:10.20944/预印本 202006.0289.v1 )。
本文包含对该方法的更详细解释、相关论文的参考、与其他 Rt 估算方法的比较以及对结果的更详细讨论。
原载于 2020 年 6 月 24 日 https://soshnikov.com。
缓慢而随意的风格转换
神经类型转移,进化
使用卷积神经网络的图像风格转换
介绍
风格转移是组合两个图像的技术,一个 内容 图像和一个 风格 图像,使得 生成的 图像显示其两个成分的属性。 目标 是生成在风格(例如,颜色组合、笔触)上与风格图像相似并且在结构上与内容图像相似(例如,边缘、形状)的图像。
在这篇文章中,我们描述了一种基于 优化的 方法,该方法由 Gatys 等人在其开创性的工作“使用卷积神经网络 进行 图像风格转换”中提出。但是,让我们先来看看导致最终解决方案的一些构件。

图一。演示,图像取自“[R2]实时风格转换和超分辨率的感知损失”
CNN 在学什么?
一开始,你可以把 低级 特征想象成在一个 放大的 图像中可见的特征。相比之下, 高级 特征可以在图像 缩小 时最佳观看。现在,计算机如何知道如何区分图像的这些细节?CNN,来救援。
预训练卷积神经网络的学习滤波器是优秀的通用图像特征提取器。CNN 的不同层提取不同尺度的特征。 浅层 中的隐藏单元只看到输入图像相对较小的一部分,它提取 低级 特征,如边缘、颜色和简单纹理。更深的层次,然而,具有更广感受野的人倾向于提取等高级特征,如形状、图案、错综复杂的纹理,甚至是物体。
那么,我们如何利用这些特征提取器进行风格转换呢?
深层图像表示
在卷积神经网络中,具有 N 个不同滤波器(或, C 通道)的层具有 N (或, C ) 个大小为 H x W、的特征映射,其中 H 和 W 分别是特征激活映射的高度和宽度。该层的特征激活是形状为NxHxW的体积(或者,CxHxW)。让我们看看如何使用这些激活从单个图像中分离出 内容 和 样式 信息。****
内容表示
传统上,两幅图像之间的 相似度 是使用像素空间中的 L1/L2 损失函数来测量的。虽然这些损失很好地衡量了的低级相似性,但它们没有捕捉到图像之间的差别。例如,彼此偏移一个像素的两个相同的图像,尽管在感觉上相似,但是将具有高的每像素损失。****
直观上,如果两幅图像的卷积特征激活是相似的,那么它们在感知上应该是相似的。因此,我们将网络的特征响应称为 内容表示 ,两幅图像的特征响应之差称为 感知损失。 为了找到原始 内容 图像的 内容重构 ,我们可以对触发相似特征响应的白噪声图像执行梯度下降。
通过仅匹配来自特定层的特征响应来生成内容重构,可以可视化由网络的不同层捕获的特征的规模(参见图 2)。较低层的重建几乎是完美的(a,b,c)。在网络的较高层中,详细的像素信息丢失,而高级内容被保留(d,e)。

图二。内容和风格表示,图像取自“[R1]使用卷积神经网络的图像风格转换”**
风格表现
为了获得输入图像风格的表示,在网络的每一层中的滤波器响应之上建立特征空间。它由特征图的空间范围内不同滤波器响应之间的 相关性 组成。数学上,不同滤波器响应之间的相关性可以计算为两个激活图的 点积 。形式上,图像的 风格表示 可以由 Gram 矩阵 (参见图 3)捕获,该矩阵捕获所有特征激活对的相关性。对于一层中的 N 个滤镜,克矩阵是一个 N x N 维矩阵。
- 在 Gram 矩阵的位置 (i,i) 处的对角元素测量过滤器I如何活动。假设滤波器 i 正在检测图像中的垂直边缘,那么 (i, i) 处的高值意味着图像具有许多垂直边缘。**
- Gram 矩阵的位置 (i,j) 处的值测量两个不同滤波器 i 和 j 的激活的 相似度 。换句话说,这意味着由两个过滤器 i 和 j. 捕获的特征的 共存
通过捕捉不同类型的特征 (i,i) 的流行程度,以及有多少不同的特征一起出现 (i,j) ,Gram Matrix 测量图像的风格。本质上,通过丢弃存储在功能激活图中每个位置的空间信息,我们可以成功地提取样式信息。
****
图三。 Gram Matrix ,图片取自吴恩达的“卷积神经网络”课程
类似于内容重建,风格重建可以通过最小化随机白色图像和参考风格图像的 Gram 矩阵之间的差异来生成(参见图 2)。这创建了在增加的比例上匹配给定图像的风格的图像,同时丢弃了场景的全局排列的信息。
现在我们已经有了定义损失函数的所有关键要素,让我们直接进入它。
损失函数
设 C,s, 和 G 为原始内容图像,原始风格图像和生成的图像, aᶜ, 和 aᴳ 从一个预先训练好的 CNN 的层 l 中激活它们各自的特征。
内容损失
如图 4 所示,内容损失可以定义为 内容 和 生成的 图像的特征表示之间的平方误差损失。沿着 CNN 的处理层级,输入图像被转换成对图像的实际 内容 越来越敏感但对其精确外观相对不变的表示。在实践中,我们可以通过选择网络中间某处的层 l 来最好地捕捉图像的内容。

图 4。内容丢失****
风格丧失
如图 5 所示,风格损失可以定义为风格和 生成的 图像的 Gram 矩阵之间的平方误差损失。我们通常在预先训练的网络的多个层上采用风格损失的加权贡献。

图五。款式丢失****
将这些点连接起来
结合单独的内容和风格损失,最终损失公式在图 6 中定义。我们从随机图像 G、开始,迭代地 优化 该图像,以匹配图像的内容 C 和图像的风格 S、,同时保持预先训练的特征提取器网络的权重固定。

图六。款式转移损耗****
总之,值得注意的是,尽管优化过程是 缓慢的, 这种方法允许在任意对内容和样式图像之间进行样式转换。
参考
- 利昂·A·加蒂斯、亚历山大·S·埃克和马蒂亚斯·贝奇。使用卷积神经网络的图像风格转移。在 CVPR ,2016。
- 贾斯廷·约翰逊,亚历山大·阿拉希和李菲菲。实时风格转换和超分辨率的感知损失。在 ECCV ,2016。
- https://www . coursera . org/learn/convolutionary-neural-networks/
小家庭:小数据集
2020 年 1 月,我们完成了骨髓的开发阶段,在这一系列的文章中,阿夫纳·佩莱德和我分享了我们在这个过程中所学到的东西。这是该系列的第一篇文章:一个小数据集的扩充。

从左到右:原始数据集,失败训练过程 1 号,失败训练过程 2 号,成功训练过程 3 号。
自 2017 年以来,我一直在从事一个名为骨髓的过度实践研究项目,该项目旨在推测机器学习中精神疾病的可能性。这个项目已经发展成为与 Avner Peled 合作的沉浸式影院体验。去年 3 月,我提出了骨髓家庭晚宴背后的第一个想法,这是体验的主要场景,在 2018 年 IDFA DocLAB上制作了原型。在中期帖子 Family2Family 中,我解释了我们为什么以及如何在“完美家庭晚餐”数据集上训练生成性对抗网络(GAN)机器学习模型。

谷歌搜索到“提督家宴”的截图

骨髓@ IDFA 2018 _ 安妮·范·多恩 2018 NFB。版权所有
当时,我们使用 GAN 的一个特定条件模型— Pix2Pix —该模型研究图像对,学习如何在提供源时生成目标图像。它可以处理小数据集,这在时间和预算的限制方面有很大的不同)。当时原型的目标主要集中在物理参与者的交互、设置和整个项目的陈述,而不是模型的训练过程。
2019 年 9 月,在加拿大国家电影局和 AtlasV 的合拍下,我们开始了开发阶段。这使我们能够重新审视一年前所做的一些决定,并质疑它们是否与项目的目标和行动要求一致。
《髓》强调了在机器学习模型中发现的故障,以反映人工智能中精神障碍的可能性,以及导致这些故障的社会结构,为社会思维提供了新的途径。
我们需要将选择的 GAN 模型改变为更健壮的模型,该模型试图从零开始生成完美的家族,而不是依赖源输入。这样,我们可以更深入地了解训练过程和数据集分析。我们想突出和可视化的故障和错误发生在培训和国家的艺术甘一代。因此,我们转向了 StyleGAN (当时是 V.01):这个生成器以其生成高分辨率图像的能力而闻名,特别是在人脸方面,并识别数据集中的高级特征,如微笑或年龄。
机器学习模型就像渴求数据的孩子,大多数时候数据集的质量和数量决定了模型的性能。有些模特比其他模特更饥渴,StyleGAN 绝对是饥渴的那一个。我们没有预料到 StyleGan 需要比我们之前使用的模型 Pix2Pix 更大的数据集。
“大数据”是人工智能领域的热门词汇之一。它指的是数以百万计的数据点,这些数据点可以为学习模型提供有价值的见解。然而,在现实世界中,只有少数人能够获得这些资源,这些资源正在成为我们这个时代最昂贵的资源;数字区域的石油被经济学家命名为。我们中的大多数人不是大公司的一部分,他们需要找到处理相对较小的数据的方法。这就是为什么小型独立项目倾向于使用那些公司预先训练好的模型的一个原因。根据少量观察值训练的模型往往会表现出过度拟合,并产生不准确的结果。在现实环境中,这可能会产生不平等和偏见的危险社会影响。
在我们的独特案例中,我们实际上并没有瞄准您通常从 StyleGAN 期望的完美高清结果,您可能会说我们希望训练失败,因此我们可以展示算法和有偏数据集的约束所固有的错误。我们的目的是教机器关于亲密的人类概念,如“家庭晚餐”,但当你浏览网页时,你会发现扭曲的图像与真正的家庭相去甚远。使用“家庭晚餐”的标语产生了大部分年轻、闪亮、快乐和富裕的白人家庭。一堆图像只能引导机器得出我们自己的虚假图像。在那种情况下,机器的输出将是我们自己感知的扭曲的镜子。

从 GAN 看 GAN 中鉴别器与生成器的“不收敛”——为什么生成性对抗网络这么难训练!
GAN 中的一个常见故障是振荡“不收敛”:一种无休止的状态,其中鉴别器和生成器轮流愚弄他们的对手,而实际上他们在愚弄自己。在人脑和其他生物的神经网络中,神经元总是处于振荡状态。随着环境的变化,神经元协调它们从一个波频率到另一个波频率的平衡。然而,在机器智能中,神经网络渴望专注并收敛于单个值——一个最优结果。具有讽刺意味的是,在人工神经网络的训练过程中的振荡状态通常表示出了问题,系统失去了平衡。当我们在推测机器学习中精神疾病的可能性时,GAN 的振荡案例是一个典型的案例,说明一种障碍如何在这样的模型中表现出来。
然而,我们不能有一个完全的失败,我们需要一个足够清晰的结果让用户理解这个模型,但也要足够扭曲以反映精神障碍。数据集必须足够大和多样化,以使训练取得一些进展,但不足以使训练收敛于高质量的图像。在我们的例子中,找不到足够大的数据集。我们旨在根据家庭晚餐的概念训练一个机器学习模型。不仅仅是这样——一顿完美的家庭晚餐。一个标签行是如此具体以至于它只能将数百张高质量的图像塑造成一个或多或少一致的数据集。
由于我们确实成功地用数百张图像训练了 Pix2Pix,我们首先与 StyleGAN 合作了类似数量的图像(约 700 张),这些图像是从“完美家庭晚餐”标语中刮出来的,然后使用“ DensePose ”神经网络从它们的背景中剥离出来,用于人类姿势检测。这是一个失败,在 72 小时的培训后,我们停止了这个过程,因为我们注意到输出变得越来越不稳定,并且由创造者定义的指标输出了非常糟糕的数字。我们目睹了极端的过度拟合,这是由模型对来自小数据集的非常特殊的图像样式的依赖引起的。此外,由于图像没有很好地对齐(即,具有不同的角度和视角),机器捕捉到了这些偏差,并将它们作为主要特征处理-我们的数据非常脏,我们需要清理它。

培训流程 1
尽管我们只有大约 700 张图片,但我们假设,如果我们能更仔细地管理它们,可能会改进我们的模型。我们决定采用一种更精确的方法——角度和视角对齐并居中,图片中的数字数量相似。这进一步减少了我们的数据集,但清理了我们的数据,并减少了模型中的噪声。
只有大约 200 张图像,我们可以看到比更大、更多样化的数据集略有改善。然而,一个小的数据集不仅使模式的检测变得更加困难,也阻碍了创造力和产生新图像的能力。因此,使用如此小的数据集几乎不可能呈现准确的结果。和前面的例子一样,这个训练过程在大约 90 小时后中断。

培训流程 2
我们开始感受到成本和时间的压力。骨髓是一个实验项目,资源有限。培训和数据收集是一个昂贵的过程;在金钱、人力、计算资源和时间方面。在不确定下一个实验是否正确的情况下,我们无法承担越来越多的实验。我们设法联系到了《StyleGAN》的创作者之一贾科莱提宁,并在执行最后一轮之前得到了他的建议。他告诉我们,毫无疑问,我们需要大约 5-10k 张图像才能获得令人满意的结果,即使这样也不能保证我们达到“解开纠缠”:GAN 可以辨别图像的质量不同和有意义的属性的理想状态(相比之下,StyleGAN 的高质量人脸数据集有 70k 张图像)。
我们知道我们需要一种混合的方法:首先,选择数量而不是质量,收集尽可能多的图像,然后,使用定制技术增加我们的数据,使我们的模型更容易处理图像。现在,我们正亲眼目睹偏见的产生:为了让我们的模型更好地把握现实,我们需要用一个被篡改的图像来呈现它。
在我们的例子中——在抓取了“晚餐”和“完美”同义词的图像,并添加了“完美家庭餐”、“快乐家庭餐”和“四人完美家庭餐”之后,我们通过处理管道运行它们:
1)通过“查找图像副本实用程序运行所有图像,删除所有副本。
2)利用前面提到的 DensePose 分析,明目张胆地从图片中切掉 4 个人(如果多,我们随机选择 4 个人)。
3)手动调整尺寸,将族紧挨着放置,并锚定在图像的中心。
4)通过将图形的顺序打乱四次,从一个图像中产生四个图像,来创造更多的家庭多样性。
这以大约 20,000 张图片结束。

混乱的家庭
然后,我们对图像应用了另一个过滤过程:对生成的图像再次运行 DensePose 分析,丢弃任何没有四个人的图像(主要是一些设法通过第一次运行的破碎的身体部分)。
我们只剩下大约 6.5k 的图像。
这减少了模型分类器中的过度拟合,并产生了更加一致的结果。尽管如此,质量在过程进行到一半时达到顶峰,之后工件开始出现。

培训流程 3
这种方法使我们获得了令人满意的结果;一个完美家庭的完美但扭曲的形象。

放大 3 号训练的“假家庭”输出
对于那些大公司之外的大多数人来说,收集和分配数据的斗争是一场真正的斗争。这对我们的生活有着真正的意义。骨髓是由我们的动机推动的,我们谈论通过交互式讲故事等替代媒体可获得的数据和信息,并设想信息技术的可能未来。这是艺术和独立的社会实验的时代,可以挑战和破坏常见的做法,并建立一个共享知识的新社区。

Marie-Pier Gauthier 设计的骨髓@NFB 互动 2020 NFB
在骨髓开发阶段,我们的目标是了解如何处理扭曲家庭的结果,增加与用户的实时交互,并使用 GAN 模型创建更多干预。我们寻找将 StyleGAN 与故事联系起来的方法,以及其他模型和视觉效果,希望引发一场关于失真输出的对话,以及当一个人的表达意识消失时,它们如何突出混乱。
在下一篇文章中,我们将描述如何开发一个工具来帮助我们探索 StyleGAN 的潜在状态,并在团队成员之间进行实时交流。
数据集准备和过滤开源代码:Github 上的骨髓 。
特别感谢 Osman Zeki 做了大量的搜集工作,并在培训的构思阶段提供了有益的反馈和建议。
这项体验是与声音艺术家 Philippe Lambert 合作开发的。
小 ML 是 RPA 的下一个大飞跃
每个人都同意机器学习将改变 RPA,但它不会以你可能认为的方式发生。

一群蚂蚁比一只孤独的大象更有生产力。Vlad Tchompalov 在 Unsplash 上拍摄的照片
过去几年机器人流程自动化(RPA)的蓬勃发展已经非常清楚地表明,几乎每个行业的业务流程都有无数的瓶颈有待解决,效率有待提高。在 RPA 全面激增的几年前,麦肯锡已经估计到 2025 年知识工作自动化的年度影响大约为6 万亿美元。
随着 RPA 从 python 脚本到通用平台的发展,我见证了相当大的转变。RPA 中可用的工具和库随着时间的推移不断改进,每一次迭代都扩大了可自动化流程的种类,并进一步提高了整体自动化率。我相信在 RPA 开发人员的日常工具箱中添加机器学习(ML)是流程自动化范围和效率的下一个巨大飞跃。和 I am 不 单独。但是有一个问题。它看起来会与所有的宣传让你相信的大相径庭。
为什么还要关心机器学习?
想象一下没有 if-else 逻辑或变量的 RPA。您只能自动化简单且完全静态的点击过程。随着我们逐渐添加一些变量和逻辑,我们可以开始自动化更复杂和更有影响力的流程。您想要自动化的过程越复杂,您需要添加的逻辑规则就越多,您需要考虑的边缘情况也就越多。RPA 开发人员规则系统的负担呈指数级增长。明白我的意思了吗?
收益递减定律表明,在某个时间点(很快)规则系统的开发变得如此昂贵,以至于自动化过程不再值得投资。这就是机器学习的用武之地。如果使用得当,它可以轻松地击败任何传统的规则系统,同时需要的资源也少得多。更好的是,它解开了如此复杂的自动化问题,以至于试图用规则系统来解决它们将是可笑的。最后,收益递减规律自然也适用于机器学习,但我很快就会明白为什么现在它实际上并不重要。

成本随着复杂性呈指数增长
但是等等,机器学习不是非常昂贵吗?
是也不是。通过选择正确的方法和工具,你可以在疯狂昂贵和疯狂有利可图之间做出选择。我喜欢将自动化分为两类:
1.高影响、低容量自动化
2.低影响、高容量自动化
第一类包含所有炒作的应用程序,如个人人工智能助理、大数据商业分析、自动化 R&D 和其他概念,这些概念有望对商业产生巨大影响。这些都是作为雄心勃勃的大型机器学习项目推出的,但往往只是公关噱头,无法带来多少实际价值。为什么?答案在图表中。影响大的应用需要巨大的投资,才能挤出最后 2%的精度增长,这使得投资回报率为负数。通常这些项目会消耗太多资源,以至于公司被迫削减成本并关闭它们。
第二类是关于效率的。它对媒体的吸引力要小得多,但不要被它低调的本质所迷惑。在这里你会发现可实现的利润和真正的组织变革。发票处理、客户投诉分类和销售线索确认等事情听起来并不像是改变世界的自动化。但是加在一起,它们会将你公司的效率提高一个数量级。想想互联网的影响。你没有一个大规模的互联网项目,但相反,互联网嵌入了你公司的每一个功能。机器学习也会发生同样的情况。你想在有利可图的高效率区。因此,不要做大型 ML 项目,而是将小型 ML 嵌入到您的日常 RPA 工作中,并感到惊讶。

高效区是应该去的地方
我该怎么做?我们的数据科学家超级忙。
简单地说,选择允许您的 RPA 团队使用机器学习的工具,而不是依赖数据科学团队来实现每一项自动化。有针对开发者的机器学习工具,跳过了模型训练、托管和维护的所有麻烦。
自然,您可以通过数据科学团队制作的定制模型获得更高的性能,但您需要评估和证明是否值得投资。当 RPA 团队可以自己使用机器学习时,将智能融入流程自动化的门槛就大大降低了。你会发现它无处不在。
大多数 ML 工具都是针对数据科学家来优化他们的工作,所以你需要做一些挖掘来找到以开发者为中心的解决方案。我会在文章的最后回到这个话题。
好的,我应该从哪里开始呢?
看看你现在的自动装置。它们中的一些需要规则系统的不断更新还是需要频繁的人工干预?如果是这样的话,这些瓶颈可以用一些智能来解决吗?
另一个很好的来源是您的 RPA 积压。有没有一些自动化已经以中高优先级搁置了一段时间,但从未向前移动过?通常情况下,那些有点复杂的项目会被卡在 backlog 中。
需要智能的自动装置通常位于以下盒子中:
- 的输入数据不可靠:例如,用户没有在表格中填写所有必要的信息,或者他们打错了字。
- 需要一个复杂的规则系统:例如,识别一个条目是否已经存在于数据库中,但格式不同 (Corp Inc. vs Corp)。
- 需要认知决策:例如,投诉单需要根据其类别或紧急程度分配给正确的客户服务代理。
- 环境或数据经常变化:例如,当新产品推出,旧产品停产时,零售的产品经常变化。

小 ML 从哪里入手
我可以在我的 RPA 平台上完成吗?
是的。重点是让机器学习成为你日常 RPA 工具箱中的正常工具,并消除其间的任何摩擦点。至少 aito.ai 已经与 Robot Framework、UiPath、BluePrism 和所有其他主要玩家兼容。使用这样的解决方案只需要发送 HTTP 请求,这是任何 RPA 平台中的标准功能。我们正在为每个平台开发指南和教程来帮助你入门,并且我们正在发布库和组件来使通过这些平台使用 ML 更加容易。
如果你想加入早期采用者的行列,请随时在 LinkedIn 上给我发信息,或者给我发电子邮件。ML 列车上见!
我正在aito . ai为不同的 RPA 平台开发机器学习集成,以永远改变 RPA 的完成方式。
使用 Pandas 和 pandasql 学习 SQL 的小动机和简单入门
来自 giphy.com(上图)我脑中的数据科学家形象(下图)我努力成为一名数据科学家
不是因为你必须这么做,而是因为这让你的生活更轻松
当我开始独自学习数据科学时,有太多的东西需要我去学习。我从 Python 编码开始,我相信这是大多数人的起点,除非你已经知道如何使用 R 或 Python 编程。然后我们听到机器学习算法和大数据等等。在我加入数据科学沉浸式项目(也称为数据科学训练营)之前,我没有考虑过数据库管理系统(DBMS ),因为我只考虑过如何处理数据,而没有考虑过如何访问数据。数据库是组织存储不同类型数据的地方,根据数据的种类(关系或非关系)决定数据库的类型。关系数据库通过包含特定信息的行和列的表格来存储数据。例如,在企业中,数据库可能存储一个包含客户 ID、姓名、地址、电话号码的客户信息表,以及一个包含订单号、日期、产品名称、金额、客户 ID 的订单表。
然后这两个表通过客户 ID 连接起来。数据库中的每个表可能都有主键,例如客户 ID 和订单号,在本例中,这是表的唯一标识符。


SQL 代表结构化查询语言,是一种与关系数据库管理系统(RDBMS)一起工作的语言。尽管有不同的 RDBMSs,如 PostgreSQL、MySQL 和 SQLite,但 SQL 是所有人的通用语言。
当我学习任何一门新的编程语言时,我都试图找到最简单的方法来接触这门语言,并将其与我已经知道的语言进行比较。所以今天我想分享我是如何用熊猫数据框架来练习 SQL 的。这种方式降低了学习的障碍,让你的心从恐惧中平静下来。此外,您可以更经常地练习,因为您不需要寻找 SQL 示例数据库来练习。最后,编写查询通常更容易操作表。(相信我)
第一种方法是使用pandasql。您可能需要首先使用 bash 命令pip install pandasql安装它。
from pandasql import sqldf
然后我们编写一个 lambda 函数,它将使编写查询变得更快。
pysqldf = lambda q: sqldf(q, globals())
让我们以泰坦尼克号数据集为例。我使用了链接中的火车设置,并保存为titanic.csv。

现在让我们尝试一些简单的东西。
让我们通过 50 到 100 之间的Fare范围来分割数据帧。
对于用我们通常的方式使用熊猫:

对于使用 SQL 查询:

我们可以通过使用.equals()来检查这两个结果是否相同。但是请注意,当我们使用 SQL 查询时,索引被重置。所以我们用PassengerId设置索引,然后使用.equal()。

第二个例子是获取幸存男性乘客的前 30 个名字。

它表明,当应用的条件越多,SQL 查询就越容易使用!因此,不仅为了实践,也为了方便,我喜欢使用 SQL 查询来一次应用多个条件。
第二种方法是使用.query()
真的很简单!让我们直接看一个例子。
我们想要 15 岁以下的女性乘客。
使用熊猫:

使用查询:

请注意,没有使用.query()重置索引。
所以我们可以直接对比这两个。

我希望这些简单的例子能激发您查找更多的 SQL 推荐,并尝试自己使用它们。如果您有任何问题或意见,请告诉我!我会把 Jupyter 笔记本和我在这里使用的例子放在我的 GitHub 库中,我会用更多的例子更新它!
最小神经网络

我不打算写关于神经网络背后的复杂数学和算法。相反,我将把你的直觉建立在神经网络如何工作的基础上。我将通过创建最小的神经网络来做到这一点,并训练它完成一项简单的任务。
直觉是不容忽视的,约翰。它们代表的数据处理速度太快,意识无法理解- 夏洛克·福尔摩斯
神经网络背后的想法
神经网络是权重的集合。我们可以在一组输入和输出(目标或标签)上训练神经网络。神经网络内部的权重与输入交互并产生输出。随着网络被训练,权重被更新,使得它试图将输出与目标值相匹配。简而言之,神经网络学习输入和输出之间的映射。现在让我们看看我说的这些是什么意思。
最小神经网络
下面是只有一个权重(w)的最小神经网络。我们给它一个输入(x ),乘以权重,结果就是网络的输出。

由于这个神经网络非常小,我们将在一个非常简单的任务上训练它。我们的任务是给它输入任何数字,网络应该改变这个数字的符号。比如我们给 3 作为输入,那么网络应该输出-3。
在 Keras 中创建神经网络
现在我要在 Keras 中构建并训练最小的神经网络,这是一个深度学习库。现在没有必要深入语法,这只是为了建立你的直觉。
创建一个神经网络
太好了!我们创造了只有一个权重的神经网络。现在让我们创建训练数据,我们将在此基础上训练我们的神经网络。
创建数据
创建培训数据
我们也创建了训练数据。数据包含 100K 个随机数,标签是该数的负数。让我们根据刚刚创建的数据来训练网络。
训练网络
开始时,神经网络的权值是随机初始化的。随着我们不断训练网络,权重也在更新。在我们开始训练之前,让我们检查一下重量。

训练前的体重
现在让我们来拟合网络中的数据。试衣不过是训练的别称。

训练网络
我们训练了网络。正如您在进度条中看到的,网络是在 100K 个样本上训练的。现在让我们给网络输入一个值,并检查响应。

检查响应
网络几乎完成了任务。输出非常接近输入数,符号相反。随着我们对更多数据进行训练,输出将越来越接近目标值。还有,现在让我们检查一下重量的值。

训练后的体重
当我们根据数据训练网络时,权重从 0.42 变化到-1 左右。这是显而易见的,因为一个数必须乘以-1 才能改变它的符号。
摘要
因此,基本上神经网络可以学习任何输入和输出之间的映射,并作为函数逼近器工作。一旦它学会了映射,它可以为你给它的任何输入产生一个近似的输出。
智能面部锁定系统
虚拟助理项目
建立高精度人脸识别模型

来源:照片由弗洛里安·奥利沃在 unsplash 上拍摄,并由作者编辑
安全是当今最令人担忧的问题之一。确保只有正确的人有权访问设备变得极其重要。这是我们的智能手机通常没有两步安全系统的主要原因之一。这是为了确保我们的隐私得到维护,只有真正的所有者才能访问他们的设备。基于人脸识别的智能人脸锁定技术就是这样一种安全措施,我们将研究如何构建我们自己的人脸识别系统,该系统使用深度学习和 VGG-16 的转移学习,从头开始以最高的准确度执行。
注: 这是虚拟助手系列的 part-1。同一主题将有更多即将到来的部分,我们将介绍如何使用深度学习技术和 python 构建自己的虚拟助手。
简介:
这一部分将涵盖所构建的模型将确切执行的内容。我们正在建立的人脸识别模型将能够检测到授权所有者的人脸,并将拒绝任何其他人脸。如果面部被准许进入或拒绝进入,该模型将提供声音响应。用户将有 3 次验证相同的尝试。第三次尝试失败时,整个系统将关闭,从而保持安全。如果识别出正确的面部,则准许访问,并且用户可以继续控制设备。完整的代码将在文章的最后提供,并带有一个到 GitHub 库的链接。
方法:
首先,我们将研究如何收集合法所有者的图像,人脸识别模型将授予许可。然后,如果我们想添加更多可以访问我们系统的人,我们将创建一个额外的文件夹。我们的下一步将是调整图像大小为(224,224,3)的形状,这样我们就可以通过 VGG-16 架构传递它。注意,VGG-16 架构是在具有上述形状的图像净重上预先训练的。然后,我们将通过对数据集执行图像数据扩充来创建图像的变体。在此之后,我们可以通过排除顶层来自由地在 VGG-16 架构之上创建我们的定制模型。接下来是编译、训练,并相应地用必要的回调来调整模型。最后,我们将得出一个最终模型,它可以加载模型的权重,并执行基于人脸识别的智能人脸锁定。
注: 在本文中,我只用一个火车目录就执行了整个任务。您可以自由地将程序分成训练和验证目录。我还对一个训练和验证目录执行了同样的操作,我将在最后包括一个图表。

来源:丹尼尔·科尔派在 unsplash 上拍摄的照片
图像集合:
在这一步中,我们将编写一个简单的 python 代码,通过单击空格键按钮来收集图像。我们可以单击“q”按钮退出图形窗口。图像收集是一个重要的步骤,我们将只为您希望授权访问您的选择性设备的人收集图像。让我们看看我们将用来执行以下操作的代码。
我们正在导入所需的库,并在上面的代码块中相应地初始化变量。
导入用于计算机视觉和捕获图像的 opencv 模块。
导入 os 模块访问本地系统。
我们将“打开”我们的默认网络摄像头,然后继续捕捉数据集所需的面部图像。这是通过 VideoCapture 命令完成的。然后,我们将创建一个特定目录的路径,并将 count 初始化为 0。这个计数变量将用于标记我们的图像,从 0 到我们点击的照片总数。
注意: 我已经创建了我的文件夹,如果你想通过程序直接创建你的目录你可以使用 os.mkdir 命令或者以通常的方式创建一个文件夹。创建另一个文件夹也很重要,该文件夹可以包含不被授予访问权限的其他图像。
最后,我们可以看看执行图像收集的整个过程所需的代码。
我们确保代码仅在摄像头被捕获并激活时运行。然后,我们将捕获视频并返回帧。然后,我们将分配变量“key”来执行按钮按下命令。这个按键给了我们两个选择。为此,我们将参考 ASCII 表—
点击此处查阅特定等待键的 ASCII 表。现在让我们来看看图像捕捉功能的两个选项。
- 当我们按下键盘上的空格键时,单击一张图片。
- 按下“q”时退出程序
在我们退出程序后,我们将从我们的网络摄像头释放视频捕捉,并破坏 cv2 图形窗口。

来源:多梅尼科·洛亚在 unsplash 上拍摄的照片
调整图像大小:
在下一个代码块中,我们将相应地调整图像的大小。我们希望将我们收集的图像重新调整为适合通过 VGG-16 架构的大小,该架构预先训练了 imagenet 权重。让我们看看执行这个任务的代码。
导入用于计算机视觉和捕获图像的 opencv 模块。
导入 os 模块访问本地系统。
我们正在将我们捕获的所有图像从默认帧大小重新缩放到(224,224)像素,因为如果我们想尝试像 VGG-16 这样的迁移学习模型,这是最好的。我们已经捕获了 RGB 格式的图像。因此,我们已经有 3 个通道,我们不需要指定。VGG-16 所需的信道数量是 3,并且该架构的理想形状是(224,224,3)。
调整大小步骤完成后,我们可以将所有者的目录转移到 images 文件夹中。
注意: 如果您试图创建单独的训练和验证数据集,那么以 80:20 的格式分割图像,并将其相应地放置在各自的目录中。

来源:赫克托·J·里瓦斯在 unsplash 上拍摄的照片
图像数据增强:
我们收集并重塑了我们的形象。下一步是对数据集执行图像数据扩充,以复制副本并增加数据集的大小。我们可以用下面的代码块做到这一点。
ImageDataGenerator 用于图像的数据扩充。
我们将复制和制作
原始图像转换的副本。Keras 数据生成器将使用副本和
而不是原件。这对每个时期的训练都很有用。
我们将重新缩放图像,并更新所有参数,以适应我们的模型。参数如下:
1。重新缩放 =按 1 重新缩放。/255 来归一化每个像素值
2。旋转 _ 范围 =指定旋转的随机范围
3。 shear_range =指定逆时针范围内每个角度的强度。
4。 zoom_range =指定缩放范围。
5。 width_shift_range =指定扩展的宽度。
6。高度 _ 移位 _ 范围 =指定延伸的高度。
7。水平 _ 翻转 =水平翻转图像。
8。 fill_mode =根据最近的边界填充。
train _ data gen . flow _ from _ directory 获取到一个目录的路径,并生成批量的扩充数据。可调用属性如下:
1。 train dir =指定我们存储图像数据的目录。
2。 color_mode =我们需要指定图像分类方式的重要功能,即灰度或 RGB 格式。默认值为 RGB。
3。 target_size =图像的尺寸。
4。 batch_size =流程操作的数据批次数。
5。 class_mode =确定返回的标签数组的类型。
“分类”将是 2D 一键式编码标签。
6。无序播放 =无序播放:是否无序播放数据(默认值:True)
如果设置为 False,则按字母数字顺序对数据进行排序。

来源:Alex Iby 在 unsplash 上的照片
构建模型:
在下一个代码块中,我们在变量 VGG16_MODEL 中导入 VGG-16 模型,并确保我们输入的模型没有顶层。
使用没有顶层的 VGG-16 架构,我们现在可以添加自定义层。为了避免训练 VGG-16 层,我们给出下面的命令:
。
我们还将打印出这些层,并确保它们的训练设置为假。
现在让我们继续在 VGG-16 架构之上构建我们的定制模型。这将类似于我的另一篇文章中的手指手势模型,你可以在这里查看。
我们正在构建的人脸识别模型,将使用
迁移学习进行训练。我们将使用没有顶层的 VGG-16 模型。
我们将在 VGG-16 模型
的顶层添加自定义层,然后我们将使用这个转移学习模型来预测它是否是授权所有者的脸。
定制层由输入层组成,基本上是 VGG-16 模型的
输出。我们添加一个具有 32 个滤波器的卷积层,
内核大小为(3,3),默认步长为(1,1),我们使用激活
作为 relu,he_normal 作为初始化器。
我们将使用池层从
卷积层向下采样。
在样品通过展平
层后,两个完全连接的层作为 relu 激活使用,即
密集结构。
输出层具有 num_classes 为 2 的 softmax 激活,其
预测 num_classes 的概率,即授权所有者或额外参与者或被拒绝的面部。
最终模型将输入作为 VGG-16 模型
的起点,输出作为最终输出层。

来源:照片由 Pavan Trikutam 在 unsplash 上拍摄
回访:
在下一个代码块中,我们将查看人脸识别任务所需的回调。
我们将导入培训我们的模型所需的 3 个回调。3 个重要的回调是 ModelCheckpoint、ReduceLROnPlateau 和 Tensorboard。让我们看看每个回调函数执行什么任务。
- ModelCheckpoint —这个回调用于存储我们的模型在训练后的权重。通过指定 save_best_only=True,我们只保存模型的最佳权重。我们将使用准确性指标来监控我们的培训。
- ReduceLROnPlateau —这个回调用于在指定的次数后降低优化器的学习率。这里,我们将耐心指定为 10。如果准确度在 10 个时期后没有提高,那么我们的学习率相应地降低 0.2 倍。这里用于监控的指标也是准确性。
- tensor board—tensor board 回调用于绘制图形的可视化,即绘制精度和损耗的图形。
编译并拟合模型:
我们正在最后一步编译和装配我们的模型。这里,我们正在训练模型并将最佳权重保存到 face_rec.h5,这样我们就不必重复地重新训练模型,并且可以在需要时使用我们保存的模型。这里我只根据训练数据进行了训练。但是,您可以选择同时使用训练数据和验证数据进行训练。我们使用的损失是 categorical _ crossentropy,它计算标签和预测之间的交叉熵损失。我们将使用的优化器是 Adam,学习率为 0.001,我们将根据指标准确性编译我们的模型。我们将在增强的训练图像上拟合数据。在拟合步骤之后,这些是我们能够实现的关于列车损失和准确性的结果。

图表:
列车数据图表—

训练和验证数据图表—

观察:
我们能够开发基于迁移学习的 VGG-16 人脸架构,这给了我们极高的准确性和非常低的损失。总的来说,我们开发的模型非常有效,效果非常好。在这些图的帮助下,我们可以观察到只有训练图,以及具有训练和验证图的图表现良好。
这就结束了我们的人脸识别模型。如果您想自己运行和测试模型,那么 GitHub 存储库中会提供代码。你可以在这里查看整个代码的链接以及加载重量和最终运行模型的代码。这将需要一个额外的 Haar cascode _ frontal face _ default . XML 文件,用于检测人脸。甚至这个也会在 GitHub 链接中提供。我希望你们都喜欢阅读这篇文章。这是虚拟助理项目的第一部分。请继续关注虚拟助手项目即将到来的部分,我祝大家有美好的一天!
使用 TPU 和塔罗斯对任何深度学习模型进行智能超参数优化
Keras API + Colab 张量处理单元+ Talos
什么是 TPU?
张量处理单元(tensor processing unit,TPU)是谷歌专门为神经网络机器学习开发的 AI 加速器专用集成电路(application-specific integrated circuit,ASIC)。TPU 专门针对执行快速、庞大的矩阵乘法进行了优化。谷歌称,TPUs 比 GPU 和 CPU 快 15 到 30 倍- 来源。

Colab 中 TPU 环境的准备:
在Google Colab,中创建一个新的 Python 笔记本,确保将运行时更改为 TPU,您将分配到大约 12.72 GB RAM,然后您可以通过运行以下命令将内存分配增加到大约 35.35 GB RAM。
d=[]
while(1):
d.append('1')
上面的命令试图扩展(由于‘append’命令)RAM,并在此过程中崩溃。在上次内存分配崩溃后,点击“获取更多内存”。想要更多这样的建议,请随意参考我之前的博客。
TPU +塔罗斯管道:
我正在考虑 Kaggle IEEE-CIS 欺诈检测竞赛,我现在将使用 TPU 在 colab 中一步一步地分解超参数优化深度学习管道的快速方法。
1–3.建模数据的准备:
我已经使用了我之前的博客中类似的前三个步骤,在 Google Colab 的帮助下自动化 Kaggle 竞赛,即:
- 从 API 调用下载数据集。
- 预处理和数据争论。
- 特征工程和特征选择。
4。数据缩放:
除此之外,我们还将对数据进行缩放,以将数据集中数值列的值更改为通用的比例。由于特征具有不同的范围,因此在输入到深度神经网络之前缩放数据是非常重要的。
5。TPU 初始化:
为了有效地使用 TPU,并使用由 TPU 实验室提供的所有工人和核心,我们需要通过使用以下代码来初始化 TPU 系统,以初始化 TPU 策略对象,该对象将在模型构建中进一步使用。
6。模型构建:
要做 Talos 超参数优化,首先需要初始化一个深度学习模型。我用过 Keras,因为它使用高级 API 和 tensorflow 作为后端。我将使用 Keras 序列模型的两个隐藏层和输出层与 sigmoid 作为激活函数。
7。参数网格:
选择的参数网格可以取决于各种因素,如数据、建模时间等。我为超参数优化考虑了以下网格。
8。距骨超参数扫描:
然后,我们根据在参数网格中初始化的度量和损耗,沿着参数网格扫描。我们使用以下代码扫描参数网格,其中:
我们使用 ieee_fraud_model 作为要扫描的模型,我们已经用 strategy.scope()初始化了该模型,其中它使用所有 TPU 工作器来构建该模型。这将模型的构建速度提高了 15-20 倍。

Talos 扫描实时绘图进度
如果你感兴趣的话,我还包括了没有 TPU 的 Talos 的代码,或者如果我的 colab 笔记本中没有 TPU 的话。
9。预测:
然后,从扫描的所有模型中,我们根据度量标准(在本例中为“binary_accuracy ”)选择最佳模型,使用下面的代码对提交文件进行预测。
10。保存并恢复提交文件的模型:
此外,您还可以根据指标将模型部署为 zip 文件,您可以在其中恢复预测模型,并通过使用这些预测来创建提交文件。
请从这个 colab 查看详细的 Kaggle 管道,我在提交文件上得到了大约 0.91 的分数。我们可以进一步使用其他 Keras 自动编码器,添加层和增加网格或任何其他 Keras DNN 定义的模型建设。
结论:
构建深度神经网络是一个耗时的过程。此外,对于这样的大数据集(约 600,000 个观察值和 394 个特征),定义的神经网络的超参数调整甚至可能需要几天时间。充分利用张量处理单元,我们可以极大地减少建立任何深度学习模型的时间,并获得更好的结果。
参考资料:
更安全城市的智能警务:数据驱动的方法
我们利用现有犯罪数据得出的宝贵见解和解决方案

在 LinkedIn 上与我联系!
供稿人: 邓金养
李俊浩,卢卡斯
罗克勇林
冯传斌
波依梦寒伊恩
唐宗伟,狄龙
如果您希望查看本报告的简明幻灯片,请前往https://medium . com/@ phoechuanbin/smart-policing-for-safer-cities-a-data-driven-approach-slides-633244 f 052 e 6
1.行动纲要
贫困和犯罪真的密切相关吗?
作为美国最富裕的城市地区(Kopf & Varathan,2017),旧金山的人均国内生产总值为 89,978 美元,这一惊人的数字甚至会让发达国家相形见绌。
旧金山警察局(SFPD)的年度预算超过 123 亿美元,拥有 2108 名警力,负责管理 883,305 名居住在 121.4 公里土地上的居民。有了这样一个资金充足、人员配备良好的警察局,人们会认为旧金山是世界上最安全的城市之一。
但是,旧金山的总体犯罪率比全国平均水平高 141%,比美国 96%的城市都危险,这使它真正成为工作和生活最危险的地方之一。
近年来,招募更多警察的声音越来越大(Kreutz,2019)。这是一个令人困惑的现象,因为无论从哪方面来看,SFPD 的警力都是绰绰有余的,每 419 名居民就有一名警察,相比之下,新加坡是 614 名。
在我们的项目中,我们试图通过研究和引入由分析和预测技术驱动的最佳实践,找出潜在的问题,并将 SFPD 转变为一支聪明的现代警察队伍。
我们将从使用数据可视化软件 Tableau 开始,带来关于旧金山不同地点、不同时间发生的犯罪的整体模式和趋势的新见解。
接下来,我们将使用 RStudio 和数据科学技术中的各种可用模块来构建两个预测模型:
- 预测未来将在旧金山发生的犯罪类型,以便 SFPD 能够做出更明智和有效的警务决策。
- 预测特定刑事案件的破案率(%),以便 SFPD 将合适的案件分配给合适的官员,从而最大限度地提高破案率。
最后,我们通过 Tableau 可视化来放大针对青少年的犯罪和青少年犯罪的相关问题,同时还采用时间序列预测技术来预测未来的数字。最终目标:阻止未来的青少年犯罪。
通过这一全面的分析,我们旨在提供有价值的见解,帮助 SFPD 实现最大限度地减少犯罪并为旧金山居民维护安全环境的总体目标。
2.商业问题介绍
犯罪造成伤害:它们引发恐惧和仇恨,导致社区分裂,阻碍国内外投资,制造不确定性和低效率,以及一系列社会经济问题。
然而,犯罪是现代社会的一个重要问题,政府正积极努力保持低犯罪率,以促进国家和城市的安全。具体来说,犯罪一直是旧金山的一个问题,尤其是当旧金山以关押阿卡特兹臭名昭著的罪犯而闻名时。
与其他各种规模的社区(从最小的城镇到最大的城市)相比,旧金山的犯罪率为每 1000 名居民 64 人,是美国最高的犯罪率之一。在旧金山,一个人成为暴力或财产犯罪受害者的可能性是 1/16,仅在加利福尼亚州,超过 99%的社区犯罪率较低(NeighbourhoodScout,n.d .)。此外,随着 47 号提案(Sandberg,2019 年)的实施,犯罪浪潮变得更加严重,该提案在 2014 年将拥有非法麻醉品供个人使用以及盗窃价值低于 950 美元的任何物品从重罪降级为轻罪。
在 2011 年的盖洛普民意调查中,38%的美国人表示,他们会在住所一英里范围内“害怕晚上独自行走”;这一数字相当于超过 8600 万成年人。在同一调查中,47%的人说他们担心他们的家被盗,44%的人担心他们的汽车被盗。其他犯罪的相应数字是:经历身份盗窃,67%;被抢劫,34%;开车时被袭击,19%;被性侵,22% —包括 37%的女性;20%的人被谋杀(Saylor,2012)。根据 2018 年尊严健康 CityBeat 民意调查,这种情况在旧金山更加严重,街头行为被列为当地居民最关心的问题。
犯罪的受害者可能会经历不同类型的影响,包括受伤等身体影响,愤怒和创伤后应激障碍(PTSD)等心理影响,以及支付医疗费用和休假等经济影响。一项关于犯罪影响的研究得出结论认为,当我们比较不同类型犯罪(包括非暴力和暴力犯罪)的受害者时,受害的情感影响没有太大差异(Shapland & Hall,2007 年)。这一观察表明犯罪,无论轻微或严重,对个人都有负面影响。
犯罪的影响超越了个人,影响到整个社区。在旧金山,财产和低级犯罪正在加剧对零售市场的破坏。随着盗窃行为猖獗和缺乏安全保障,地标使命区商店正在关闭(Brock,2019),而夫妻店发现在不断被盗的情况下很难生存。高犯罪率和缺乏安全也导致三藩市被贴上不可行市场的标签(Phillips,2019),由于恐惧而阻止新企业设立。其他可能的影响包括房屋保险费上涨和房地产价格受到影响(英国广播公司,未注明)。
面对高犯罪率,每个个人、家庭、社区和组织都是受害者。
3.期望的业务成果
基于上述犯罪带来的问题和影响,我们的团队决定关注利益相关方,如三藩市警察局(SFPD)和地方政府能够实现的 3 个最重要的结果,即根据从过去犯罪历史分析中得出的见解采取行动。
3.1 人力分配和调度
每年,SFPD 都将很大一部分预算用于巡逻活动。2017 年至 2018 年间,巡逻活动占 SFPD 预算的 58%,达 3.392 亿美元(Campbell,2018)。从 2012 年到 2016 年,SFPD 的警察服务需求增加了 49.3%,分别从 300,919 次增加到 449,181 次。然而,根据不同地区的时间点,日常汽车巡逻人员不足或过多,表明资源没有得到最佳利用。
在旧金山监事会委托进行的一项研究中,发现某些地区对服务呼叫的响应时间“特别长”。在 Mission 和 Southern 等地区,平均响应时间超过两个小时:在 Mission 地区,打电话者报告车辆中有可疑人员可能要等 179 分钟(Barba,2020 年),相比之下,如果打电话者在 Richmond 地区,平均等待时间为 30 分钟。
我们相信,通过了解事件在整个旧金山的分布,可以更有效地分配人力——无论是在警察局内部还是在警察局之间——以加强行动。为了实现这一点,我们决定重点关注地理 犯罪地点和犯罪时间分布。
3.1.1 犯罪地点
SFPD 在三藩市内有 10 个区,每个区由外勤业务局分配的人力为餐饮区提供治安服务。根据旧金山预算和立法分析师编制的绩效审计报告(Campbell,2018 年),SFPD 目前分配警察的做法(附录 1)——如跟踪呼叫量——并不能完全反映实际工作量,因为它没有考虑各单位响应呼叫所花费的时间。
目前,这些地区面临着服务呼叫响应时间长的问题,这可能是由于不同地区的复杂犯罪发生率较高,或者需要行驶的距离较长。通过了解每个地区应对的犯罪的位置分布,确定新的见解可能会提高人力分配的效率。
3.1.2 不同犯罪的时间分布
SFPD 目前对分配到警区的巡逻警察实行 10 小时轮班和 49 天轮换制。然而,这种轮班时间表在一个警区内任何一天实际可轮班的警官总数上造成了很大的差异。某个班次的巡逻车人员可能会超编,但另一个班次的巡逻车人员可能会不足(附录 2)。不同地区的同一班次内的人员配备也可能有所不同(附录 3)。如果我们能够确定哪一个班次以及一周中的哪一天由于犯罪率较高而通常需要更多的人员,就可以实现更有效的人员配置。
各种类型的犯罪意味着犯罪人不同的心理状态,因此,他们在一天中的发生率也有不同的变化(匡,2011)。激情犯罪和机会犯罪通常有不同的发生时间框架——激情犯罪通常可以发生在一整天,而机会犯罪发生在被抓住的可能性较低的特定时间。了解不同犯罪的不同时间发生将允许 SFPD 知道哪个班次分配更多的警察以打击更严重的犯罪。
3.2 预防性巡逻和犯罪分配
预防性巡逻
警察巡逻包括主动/预防性巡逻和反应性巡逻,两者具有非常不同的特点。预防性巡逻旨在增加预期犯罪地区的警力,以起到威慑作用。如前所述,旧金山最受关注的是街头活动。这种活动通常在公共场所进行,如果警察在正确的时间出现在正确的地点,很容易被发现,从而很容易被阻止。
目前,预防性巡逻路线是先验确定的,基于理论街道网络使用率(中心性测量)和历史犯罪数据(Wu & Lum,2017)。然而,这种方法未能考虑以下因素:
- 旧金山的不同地区可能有不同的“高峰时间”,那里最有可能发生犯罪活动。因此,巡逻不同区域的最佳顺序是什么?
- 旧金山可能同时发生多起犯罪行为。由于人力有限,SFPD 不可能在任何时候出现在任何地方。在这种情况下,SFPD 应该关注哪些领域?
- 随着时间的推移,每个地区的历史犯罪数据在数量和种类上都只会增长。因此,巡逻人员在执行任务时应该注意什么?
我们希望通过分析,我们可以帮助 SFPD 回答这三个问题。这将允许他们计划更有效的预防性巡逻路线。
犯罪分配
犯罪筛查通常由犯罪经理或同等的决策者处理(英国交通警察,2017)。他们根据由评分系统确定的优先级来分配案例。许多警察部门进行的研究表明,基于可解决性的评分系统成功地筛选出解决概率低的案件,并确定有希望的案件(Dempsey & Forst,2017)。
我们希望使用分析,我们可以提供额外的输入,以提高 SFPD 当前评分系统的可解决性。这使得他们能够最大限度地利用调查人员的时间和精力,从而提高破案率。
3.3 青少年保护
作为社会最弱势的阶层之一,青少年的福利需要特别关注。人们常说,儿童是社会的基石,他们的成长将决定国家的未来。注意到这一点,我们已经确定了与针对青少年的犯罪和青少年实施的犯罪相关的一些重要成果。
3.3.1 青少年受害者
针对未成年人的犯罪通常会受到重罚,而且理由充分。除了造成明显的身体和心理伤害,这种犯罪往往导致受害者大脑和神经系统的发育受损,形成不健康、高风险行为的比率更高,以及未来成为罪犯的风险更高(世卫组织,2019)。
联合国进行的一项研究得出结论认为,对儿童的身体、心理和性暴力每年造成的经济影响(如医疗、咨询和丧失生产力)最低可达 1,240 亿美元,最高可达 5,850 亿美元(Pais,2015 年)。这是一笔不可低估的巨款,因此一个关键目标应该是尽可能降低此类犯罪的发生率,以便最大限度地减少对旧金山市造成的负面社会和经济成本。
3.3.2 少年犯罪人
让刑满释放人员重返社会一直是每个国家面临的一个紧迫问题。当他们被释放时,他们面临许多挑战,这些挑战严重阻碍他们成为社会中有生产力的成员,包括社会歧视、无法找到合适的工作、无法跟上技术的变化等等。没有能力回到正常的生活方式,他们因此被迫重新犯罪来养活自己。鉴于青少年罪犯很可能会错过学校和正常的童年,这个问题对他们来说更加严重。研究表明,儿童首次犯罪的年龄越小,累犯率越高(量刑咨询委员会,2016 年)。在这种情况下,威慑是减少青少年犯罪最有效的方法。
虽然青少年为犯罪付出了监禁的代价,但纳税人也承担了一些负担。关押一名少年的费用高达每人每天 407.58 美元,每年 148,767 美元(Sneed,2014 年)。这是一笔很大的支出,肯定可以通过降低犯罪率来减少,这样国家就可以将节省下来的成本投入到更有生产力的领域。
4.资料组
主要数据集从旧金山市和县网站获得,包含警察局事件报告(旧金山市和县,2020 年),时间跨度为 2003 年 1 月至 2018 年 5 月。有 13 列,超过221 万条记录:

有了 15 年的犯罪分类数据,就可以进行全面分析,了解影响犯罪率的因素和变量。有了这些认识,我们将能够向相关利益攸关方建议适当的措施,以便他们能够遏制和阻止未来的犯罪。低犯罪率将确保居民的安全,这将有助于旧金山市的社会稳定。
5.分析解决方案
5.1 人力分配和调度
我们将利用可视化技术提供简单明了的工具,SFPD 可以轻松地在日常运营中采用这些工具,并且只需一个平缓的学习曲线。这些可视化仪表板可以反映实时数据,并根据 SFPD 的需求进行调整,以便更好地理解。
5.1.1 地理分布
为了了解不同地区的一般人力需求,绘制了旧金山的基本犯罪密度图(图 1 ),犯罪率最高的地区显而易见——即北部、南部和中部地区。这些可能表明对警察人力的更大需求。

为了更深入地了解人力使用情况,我们生成了每个地区所应对的犯罪地点的可视化图(图 2 左)。从视觉上,我们可以清楚地区案件的区别;注意到多个例外情况,即各区应对本区以外的案件——这可能表明本区人力资源未得到最佳利用,或者相应区缺乏人力资源,需要其他区的援助。

例如,我们可以看到湾景区(图 2 右)处理了来自旧金山几乎所有其他区的案件,尤其是在北区、南区和中区的犯罪高发区。由此看来,上述各区可能缺乏必要的人力来处理更高和更普遍的犯罪事件。这也可能导致湾景区人员过剩,将多余的人力重新分配给人员不足的人可能更有利于优化资源。

可视化技术将提供每个区的犯罪事件和类别的简单可视化(图 3),允许在每个区内方便地分配人力,以更好地利用其人力,并更有效地处理每类犯罪。

尽管如此,SFPD 应对的各类犯罪事件都可以根据处理这些事件的地区进行可视化处理(图 4),这为 SFPD 现场行动局提供了犯罪情况的概览,以便其更有效地在各地区分配相关人力。
例如,袭击、抢劫和强迫性犯罪等暴力犯罪可能是影响最大的犯罪,应努力遏制这些犯罪事件。这有助于密切监测这些"危险信号"犯罪事件,以及处理这些问题的必要应对措施和应对者,如辅导员。
时间分布
为了更好地帮助我们的分析,我们按照时间范围对时间进行了分类,而不是报告的犯罪的实际时间。这有助于我们限制分析的因素数量。此外,这也符合 SFPD 目前采用的五个巡逻人员配置表,即巡逻人员每 10 小时轮班一次。

首先,通过五个时间段内犯罪数量的基本可视化(图 5 ),我们可以看到全天犯罪数量的变化。凌晨 1 点的班次犯罪率最低,而下午 4 点的班次犯罪率最高。随着犯罪在上午 11 点开始达到高峰,SFPD 可以为上午 11 点分配更多的人员,以便犯罪率最高的两个时间段(上午 11 点至下午 4 点和下午 4 点至晚上 9 点)可以配备足够的人员。
随后,我们进一步分析并查看了更多有助于人员配置的因素:

查看不同警察局不同时间段的犯罪率,可以发现下午 4 点到晚上 9 点的时间段犯罪率最高,这与之前得出的结果一致。
在所有警察部门中,南部警察部门的犯罪率最高。因此,SFPD 必须确保南方警察局有足够的人员来打击犯罪。SFPD 可以考虑将犯罪率较低的地区(如帕克和里士满)的警官重新分配到犯罪率较高的地区,以便更好地利用资源。
接下来,我们观察了一周中不同日子的犯罪率分布情况(图 7)。我们可以观察到,在一周的不同日子里,报告的刑事案件没有显著差异。报告病例略高的两天是周三和周五。
由于各天之间不存在差异,SFPD 应确保任何一天都不会出现警员分配不足的情况。如果在这一周的其他几天出现人员过剩的情况,SFPD 可以考虑在这两天安排人员轮班,以便最大限度地利用人力。


最后,我们通过查看不同时间段内严重犯罪的分布情况来进一步分析数据(图 8)。自 1994 年以来,加利福尼亚州一直实行三振出局法判刑制度(加利福尼亚州法院,未注明日期)。“三振出局法”要求被判犯有任何新的重罪的被告,在之前被判犯有严重重罪的情况下,将被判处两倍于该罪行的刑期。为了有助于我们的分析,我们将构成(Sigal,2011 年)的犯罪归类为严重犯罪的三击判刑制度下的罢工。
根据调查结果,袭击、毒品和车辆盗窃是旧金山最普遍的严重犯罪。每一类事件的趋势也遵循早先观察到的一般趋势,即犯罪率从上午 11 点开始达到高峰,在凌晨 1 点以后逐渐下降。
SFPD 可以确保在上午 11 点、下午 4 点和晚上 9 点的班次中,有足够的称职人员来处理这些案件。研究表明,周围有更多的警察有助于降低犯罪率(Klick & Tabarrok,2005 年)。通过在更严重犯罪的轮班期间派驻更多的警察,潜在的罪犯会因为害怕被抓住而不敢犯罪。
5.2 预防性巡逻和犯罪分配
5.2.1 预测巡逻,更智能的巡逻
世界各地的警察部门越来越依赖 PredPol 这样的软件,它使用机器学习算法来预测“热点”犯罪街区——在犯罪发生之前(Huet,2015)。PredPol 为警察部门提供了快速、廉价地从大量数据中收集洞察力的能力。这些见解可用于优化警官巡逻路线。
当警察部队的人力有限时,像 PredPol 这样的工具可以快速做出关于何时何地分配人力的数据知情建议,从而带来警务效率的阶跃变化(Amina,2018)。
在我们项目的这一部分,我们已经开始预测在任何给定的时间,任何给定的一天,在旧金山不同的社区可能发生的蓝领犯罪的类型。这种见解将有助于 SFPD 优化他们的巡逻决策,并在此过程中,将他们从犯罪的“反应者”转变为犯罪的“预防者”。
我们之所以选择预测蓝领犯罪,是因为这些犯罪往往是可以直接观察到的,因此可以通过警察巡逻来最有效地阻止。相比之下,像挪用公款这样的白领犯罪更难通过巡逻发现,也更难阻止。
我们选择的预测技术是 XGBoost,这是一个梯度提升分类器,具有内置的早期停止功能。与随机森林相比,XGBoost 还构建了一个分类树集合,但是是以一种顺序的方式,其中新的树是使用以前的树表现不佳的数据来训练的。
通过内置的早期停止,我们使用 trainset 和 testset 实现了一个监视列表。随着培训的开始,评估指标 trainset mlogloss 将随着时间的推移而降低。但是,一旦这个指标开始向上攀升,这是一个过度拟合的指标,我们将结束训练,并采用具有最低训练集 mlogloss 的模型。

我们使用了 6 个预测变量:星期几、警区、月份、月份中的某一天、一天中的某一小时和地区 id。请注意,原始数据集中没有区域 id。当我们决定将旧金山绘制成一个由 100 个地区组成的 10 X 10 的网格时,就获得了这个地图。这一制图决定是因为研究表明,犯罪往往在地理上集中,但这些“热点”往往分散在整个城市中(Weisburd,2018)。由于旧金山是 121.4 平方公里,每个地区将是大约 1.21 平方公里,一个合理的巡逻区。
我们的预测变量是犯罪类别。这是一个因素变量,包括 13 种蓝领犯罪,如殴打、纵火和抢劫。
我们的最终模型是 1053 个分类树的集合(81 次迭代* 13 个类别),训练集 mlogloss 为 1.527106。为了衡量模型的有效性,我们让模型预测每行测试数据中最有可能发生的前 3 种犯罪,然后将输出与实际发生的犯罪类别进行比较。79.44%的时候,预测列表包含实际犯罪类别。
对于 SFPD 来说,这意味着能够预测旧金山不同地区可能发生的犯罪类型。有了这些信息,他们可以更好地决定在何时何地部署他们的人力,从而最有效地阻止蓝领犯罪。例如,如果明天下午 2 点区域 55 的前 3 个最可能的犯罪都是严重犯罪,那么 SFPD 可以预先安排在明天的那个时间在该区域巡逻。
对于警察来说,这意味着压力更小,工作效率更高。对警察来说,巡逻可能是一项体力和脑力都很紧张的活动,因为它需要长时间的注意力和警觉性。使用我们的模型,警察可以放心地进行巡逻,准确地知道要准备和防范的犯罪类型。
为了更好地理解预测变量如何影响我们的模型,我们利用 xgb.plot.importance 函数来绘制前 5 个最重要的变量(图 10):

我们注意到区域,一个更细化的地区,是如何被列为最重要的。
此外,通过进一步的研究,我们发现在我们的情节中第二个最重要的变量,区 Tenderloin,被 StreetAdvisor 称为“SF 中最危险的地方”,街道犯罪猖獗。在 SFPD 自己做的一项研究中,在三藩市暴力犯罪的十大统计区域中,有七个在田德隆区。
这些发现证实了我们之前关于犯罪如何在地理上集中的研究。此外,月、日和小时在这里被证明是重要的,这意味着不同类型的犯罪往往发生在不同的时间,这进一步证明了我们的模型的实用性和有效性。
5.2.2 预测犯罪分配的解决方案
根据一篇被广泛引用的论文(Gill et al .,1996),犯罪分配涉及犯罪投诉“职业生涯”中的两个主要决策点(图 11)。

使用我们的数据集,我们可以根据犯罪报告的不同细节预测其解决概率。这使我们能够采用统计观点来衡量其可解决性,并且可以成为“来自其他系统的输入”因素的一部分,这有助于影响对犯罪报告的评估,从而影响案件的分配。

快速浏览显示分辨率栏的许多级别及其计数(图 12 左)。我们认为,对于犯罪评估,更重要的是知道它是否可解,而不是它的具体解决方案。因此,我们将该列预处理为二项式可解/不可解(图 12 右)。
由于这是一个二项式分类问题,我们决定继续使用以下模型来获得这些准确度分数。

(附录 4)
我们对 CART 使用了自动 10 倍交叉验证,对其他模型使用了 75/25 的训练测试分割。我们通过输入所有预测变量来创建 CART 和 XGBoost 模型,因为它们具有内置的特征选择算法。不幸的是,对于逻辑回归,我们必须手动进行。我们的第一个逻辑回归模型,考虑了所有的预测变量,具有 47.3%的低测试集准确性。

为了提高准确性,我们研究了逻辑回归 1 中的显著变量和 CART 中的变量重要性特征。两个模型都表明描述、类别和地区是重要的变量。这是有意义的,因为不同类型的案件和警察局辖区可能有不同的解决率(附录 5)。
我们继续训练逻辑回归 2 模型,并获得了 84.5%的较高测试集精度。总的来说,我们的模型具有大约 85%的平均测试集预测精度,这表明这些模型是可行的。

使用这三个分类模型,我们能够获得一个案例可解的预测概率。由此,我们可以根据可解性对这些案例进行排序,这可以作为“来自其他系统的输入”。SFPD 可以利用这一点来简化他们对案件的评估和分配——破案率较高的案件可以分配给初级侦探,而破案率较低的案件则分配给更有经验的警官。这可以帮助在利用劳动力方面产生效力,从而提高案件解决率。
我们列出了 SFPD 根据他们的目标可以考虑的三种可能性:
- 使用 3 个概率的平均值;为了得到一个相等加权的聚合概率
- 选择特定模型的概率;如果对某些型号有保留
- 获得模型叠加后的概率;为了得到更高精度的概率
我们模型的一个关键限制是假设所提供的数据是准确的。该研究论文称,犯罪报告“的价值可能会因其糟糕的写作质量而受损”,即使它们“是根据特定标准编写的”。
总之,我们希望通过预测犯罪的可解决性并获得相应的概率,我们将通过为这一过程提供新的输入来帮助更好地进行犯罪分配的决策过程。我们不打算改变 SFPD 的案件分配政策。
5.3 青少年保护
我们从数据集中子集化并提取了两个相关部分,一个包含青少年受害者的所有实例,另一个包含青少年犯罪者的所有实例。这是通过筛选出描述中包含“少年”和“儿童”的所有案例来完成的,然后将它们分配到正确的数据表中进行分析。
趋势的可视化
Tableau 上两个数据集的快速可视化显示了一些重要趋势:

自 2008 年以来,侵害青少年的案件呈惊人的上升趋势(图 14),这些案件大多被描述为"虐待儿童"。这告诉我们,此类案件中的大多数罪犯是未能适当照顾其子女的父母,必须做更多的工作来确保旧金山家庭的安全。
对青少年的性犯罪占青少年受害者案件的第二大百分比,并且在稳步上升。虽然绑架和可疑活动的发生率通常在年均 70 起和 45 起左右波动,但涉及“遗弃/遗弃儿童”和“未能抚养儿童”等描述的家庭犯罪已经稳步下降。
可以参考以前为减少家庭犯罪所做的努力,因为事实证明,无论是通过对父母的教育还是电视宣传,这些努力都成功地减少了此类案件的数量。这些措施可以单独实施,以应对不断增加的袭击案件,从而减少每年的发生率。
青少年犯罪者所犯罪行正以天文数字的速度增长(图 16)。由于数据集的限制,我们无法确定“二级代码”类别下的犯罪类型。有了更详细的数据,警察局应该能够确定这类犯罪迅速增加的根本原因。

更详细地研究少年犯罪者犯罪的情况(图 17),可以发现一种独特的模式:案件数量在年中和年底急剧下降。这可能要归功于美国学生的寒暑假,他们有 9-10 周的假期离开学校(Karnes,2019)。

如果旷课真的是犯罪数量减少的原因,那么在学校的教育能力范围内还需要做更多的工作,从而阻止青少年犯罪。
5.3.2 预测未来犯罪数量
进行了时间序列预测,以预测涉及少年受害者和少年犯罪者的犯罪案件数量。这种逐月预测将使利益相关者为季节性趋势导致的病例激增做好更充分的准备。进行了一次训练测试分离,以便 2003 年至 2016 年的所有数据组成训练集,并将用于预测 2017 年的犯罪数量。2017 年的案例被用作测试集,2018 年的数据因不完整而被遗漏。
forecastHybrid 包通过使用基于样本内误差的权重,将 auto.arima()、ets()、thetaf()、nnetar()、stlm()、tbats()和 snaive()组合在一起,用于创建最适合任何数据集的模型(Shaub & Ellis,2020)。
第一个模型(图 18)针对数据集中的所有案例,没有子集。

蓝色突出显示的部分是预测值,测试集 RMSE 为 479,仅占 2017 年平均案例数(12,898)的 3.7%。


第二个模型(图 19)是为青少年受害者设计的。测试集 RMSE 为 9.5,2017 年此类案件的平均数为 55.3。
第三个也是最后一个模型(图 20)是为青少年犯罪者设计的。测试集 RMSE 为 14.2,2017 年此类案件的平均数为 52.4。
有了这些每月滚动预测模型,通过可视化更好地了解青少年涉及的犯罪类型,三藩市警察局可以更好地为案件做准备。由于大多数青少年犯罪案件发生在学期中,学校可以更好地处理这些犯罪,同时也加强他们的犯罪预防教学大纲,以教育年轻人作为一种威慑。这些措施的有效性可以通过每年年底国家必须承担的总成本来评估,这表明了分析在帮助解决这些问题方面的有效性。
6.未来的改进和实现
6.1 不断变化的犯罪模式
我们知道,我们当前的数据集仅涵盖截至 2018 年 5 月的犯罪。由于犯罪模式会随着时间的推移而变化,因此需要对我们的模型进行再培训,以保持其相关性。一个可能的解决方案是实现一个递归神经网络来考虑时间变化。此外,通过将新的数据集重新上传到 Tableau,我们可以很容易地在仪表板上可视化这些犯罪。
6.2 在预测犯罪时考虑其他变量
除了数据集中可用的因素,可能还有其他变量可以帮助预测犯罪。在我们最初的探索中,我们对犯罪发生的地址进行文本挖掘,寻找“块”的存在。因此,犯罪是否发生在一个街区可能是我们可以输入到模型中的另一个变量。另一个因素可能是天气(Glorfeld,2018)。在芝加哥进行的一项研究表明,当天气比平均温度高时,恶性袭击和殴打案件会增加。根据我们对数据的初步探索(附录 6),Block 对犯罪类别的预测有重大影响。考虑更多的变量将使我们的模型更加全面。这将使 SFPD 获得信息,从而更有效地预防和解决犯罪。
6.3 可能的道德问题
所提出的解决方案可能导致基于预测模型的相应输出/结果,某些类别的优先级高于其他类别。这可能会对警察部门应如何处理其案件提出道德关切,因为没有一个基准可以确定一个事件优先于另一个事件,对于暴力犯罪尤其如此。鉴于警察是宣誓保护人民的公务员,他们的道德行为将极大地影响公众信任,这是一个最令人关切的问题(Fitch,2011)。一个可能的解决方案是建立一个协议,明确划分一个案件被认为比另一个案件更“重要”的场景,这样警察就有一套规则来遵守既定的优先事项——超出模型的预测。
7.结论
在我们的项目中,我们致力于优化人力调度、通过主动巡逻预防犯罪以及调查职责的分配。此外,我们还特别关注社会最弱势群体之一的青少年,确定了在预防青少年犯罪方面要取得的重要成果。
历史、财富和气派,旧金山是一个真正的世界级城市。我们相信,凭借我们的情景化洞察力和预测模型,我们可以将 SFPD 转变为世界领先的警队,并将三藩市变成一个安全、愉快的地方,供所有居民生活、工作和娱乐!
8.参考
科普夫博士和瓦拉坦博士(2017 年 9 月 15 日)。官方消息:旧金山是美国最富裕的城区。从 Quartz 检索:https://qz . com/1077050/San-Francisco-is-Americas-rich-major-metropolitan-area-rising-above-Washington-DC-in-the-latest-rankings/
AreaVibes。(未注明)。加州三藩市犯罪。从 AreaVibes 检索:https://www.areavibes.com/san+francisco-ca/crime/
Kreutz,L. (2019 年 7 月 12 日)。根据数字:旧金山有多少警察?检索自 ABC 7 news:https://ABC 7 news . com/San-Francisco-police-staffing-SF-officers-recruiting/5389997/
邻里童子军。(未注明)。加州旧金山犯罪率。从邻里侦察兵那里取回:https://www.neighborhoodscout.com/ca/san-francisco/crime
桑德伯格,E. (2019 年 5 月 19 日)。旧金山的生活质量指数。检索自城市日报:https://www.city-journal.org/san-francisco-crime
塞勒。(2012).社会问题:持续与变化。塞勒学院。检索自https://saylordotorg . github . io/text _ social-problems-continuity-and-change/S11-01-the-problem-of-crime . html
j .沙普兰和 m .霍尔(2007 年)。我们对犯罪对受害者的影响了解多少?国际受害者研究评论,175–217 页。
布洛克,S. (2019 年 1 月 2 日)。SF Mission 区的标志性商店因犯罪、安全和街道状况而永久关闭。从 NBC 湾区检索:https://www . NBC bayarea . com/news/local/iconic-stores-in-SFS-mission-closing-down-for-good-citing-crime-security-street-conditions/7090/
j .菲利普斯(2019 年 11 月 18 日)。‘没人想在旧金山开餐馆’因为入室盗窃,成本。检索自旧金山纪事报:https://www . SF Chronicle . com/restaurants/article/No-one-want-to-open-a-restaurant-in-San-14842211 . PHP
BBC。(未注明)。犯罪对更广泛社会的社会和经济影响。转自 BBC:https://www.bbc.co.uk/bitesize/guides/zbhpgwx/revision/2
坎贝尔,S. (2018)。旧金山警察局的绩效审计。旧金山。
Barba,M. (2020 年 3 月 10 日)。研究发现 SFPD 巡警人手“严重不足”。检索自旧金山考官:https://www . SF Examiner . com/news/study-finds-sfpd-patrol-staffing-severely-individual/
匡,2011 年 7 月 14 日。每日信息图:罪犯什么时候在街上游荡?从 Fast Company 检索:https://www . Fast Company . com/1664491/infograph-of-the-day-when-do-crimes-prowl-the-streets
吴,徐,林,陈(2017)。测量警察主动性的空间和时间模式。定量犯罪学杂志,915–934。
英国交通警察。(2017).强制筛选和分配犯罪,政策和程序。检索自https://www . BTP . police . uk/pdf/FOI % 20 response % 2012 84-18% 20 screened % 20 out % 20 and % 20 other % 20 crimes % 20 attachment . pdf
邓普西,j .,&福斯特,L. (2017)。警务工作简介。成规。
世卫组织。(2019 年 6 月 7 日)。对儿童的暴力。从世界卫生组织检索:https://www . who . int/news-room/fact-sheets/detail/violence-against-children
派斯,硕士(2015 年 7 月 13 日)。暴力侵害儿童的经济成本。检索自暴力侵害儿童,联合国:https://Violence Against Children . un . org/economic _ costs _ of _ vac _ view point
量刑咨询委员会。(2016 年 12 月 15 日)。过早进入青少年司法系统的儿童更有可能再次犯罪。检索自量刑咨询委员会:https://www . Sentencing Council . vic . gov . au/news-media/media-releases/children-who-enter-youth-justice-system-early-is-more-likely-to-re offend
斯尼德,T. (2014 年 12 月 9 日)。青年监禁花费了纳税人多少钱。检索自美国新闻:https://www . US News . com/News/blogs/data-mine/2014/12/09/what-youth-insulation-costs-纳税人
旧金山市和县。(2020 年 2 月 26 日)。警察局事件报告:历史 2003 年至 2018 年 5 月。从数据 SF 中检索:https://Data . SF gov . org/Public-Safety/Police-Department-Incident-Reports-Historical-2003/tmnf-yvry
加州法院。(未注明)。加州三振出局量刑法。从加州法院取回:https://www.courts.ca.gov/20142.htm
西加尔,V. (2011 年 9 月 2 日)。加州罢工犯罪清单。检索自 Sigal 法律小组:https://www . la-criminal-defense . com/blog/list-of-strike-defense-in-California/
Klick 和 a . Tabarrok(2005 年)。使用恐怖警戒级别来评估警察对犯罪的影响。乔治梅森大学。
休特,E. (2015 年 2 月 11 日)。服务和保护:预测警务公司 PredPol 承诺在犯罪发生前绘制地图。检索自福布斯:https://www . Forbes . com/sites/ellenhuet/2015/02/11/pred pol-predictive-policing/# 6a 3d 89084 f9b
阿米娜 E. (2018 年 11 月 13 日)。利用机器学习进行犯罪预测。检索自数字倡议:https://Digital . HBS . edu/platform-rctom/submission/using-machine-learning-for-crime-prediction
韦斯伯德博士(2018)。犯罪热点和基于场所的预防。犯罪学&公共政策,5–25。
吉尔,m .,哈特,j .,利文斯通,k .,,史蒂文斯,J. (1996)。犯罪分配系统:警方对入室盗窃和汽车犯罪的调查。伦敦:内政部警察研究小组。
卡恩斯,B. (2019 年 8 月 2 日)。旧金山校历 2019–2020。从补丁中检索:https://Patch . com/California/San-Francisco/San-Francisco-school-calendar-2019-2020
Shaub,d .,& Ellis,P. (2020 年 4 月 2 日)。集合时间序列预报的便捷功能。检索自 CRAN:https://CRAN . r-project . org/web/packages/forecast hybrid/forecast hybrid . pdf
格洛菲尔德,J. (2018,10 月 26 日)。杀人,受天气、时间影响的入室盗窃。检索自 Cosmos:https://Cosmos magazine . com/society/凶杀-入室盗窃-受天气影响-一天中的时间
惠誉国际评级(2011 年 10 月 1 日)。关注道德,反思执法道德。从 LEB 检索:https://leb . FBI . gov/articles/focus/focus-on-ethics-reflecting-ethics-in-law-enforcement
9.附录
附录 1

资料来源:旧金山警察局绩效审计,由旧金山预算和立法分析师为旧金山市和县监事会编制(2018 年 6 月 12 日)
附录 2

附录 3

附录 4
合并结果

前 3 个重要变量:描述、类别、PD 区。
推车




逻辑回归 1


逻辑回归 2


XGBoost



附录 5
大车变量重要性

逻辑回归 1 显著变量






附录 6
购物车变量重要性

区块与类别

温度与类别

天气综合与类别

无监督机器学习的简单实现
加拿大大学集群

照片由 Unsplash 上的agency followeb拍摄
与参照目标标签将模型拟合到数据集的有监督机器学习不同,无监督机器学习算法被允许在不求助于目标标签的情况下确定数据集中的模式。标签可以指客户是否拖欠银行贷款,或者哪种药物对许多患者的特定疾病有效。聚类和异常检测是无监督机器学习的常见应用。我的目的是通过一个简单的实现和一个相关的用例来描述集群令人兴奋的能力。
介绍
每年都有成千上万的外国人涌入加拿大寻求大学教育。这主要是由于加拿大的亲移民政策、高质量的教育、相对较低的学费以及整体生活质量的持续高排名。未来的学生面临着大量的选择,因为加拿大各省和各地区都有很多著名的大学。
为了优化潜在学生的搜索体验,加拿大的大学被组织成基于预先选择的特征(或属性)的集群。这些聚类是从 Python 的 scikit-learn 库中的 k-means 聚类机器学习算法在定义的特征集上的实现中派生出来的。每个聚类包括具有独特特征组合的大学,这些特征反过来描述聚类。然后,未来的学生可以根据附带的聚类描述来确定他们要集中搜索的聚类。因此,搜索体验是精炼的、有效的,并且耗时更少。
数据
用于这项研究的数据集是从零开始组装的。最终数据集组成部分的来源如下:
- 加拿大大学列表:使用 BeautifulSoup Python 库从加拿大大学列表 [1】中废弃。
- 加拿大大学排名:使用 BeautifulSoup Python 库从加拿大大学排名【2】中报废。
- 省租金:来源于 rentals.ca 省租金中位数【3】。
- 大学地理坐标:geo py Python 库被占用。大学名称作为参数传递,并返回各自的坐标。
- 位置数据(娱乐指数):利用 Foursquare API 获得各大学 500 米范围内的场馆数据作为位置数据。每所大学的娱乐指数是从独特的场馆类别中得出的。
方法学
数据采集
如前一节所述,本项目中使用的数据集是从不同来源收集到一起的,以实现目标。BeautifulSoup Python 库用于抓取加拿大大学列表和排名[1][2]。各省租金数据来源于 Rentals.ca May 2020 年 5 月租金报告[3]。大学坐标由 geopy 库生成。最后,娱乐指数是一个衡量机构 500 米范围内“娱乐”点可用性的指标,它是使用 Foursquare API 作为位置数据获得的。构建最终数据集涉及一系列清理、合并和连接操作。
下面给出了用于抓取加拿大大学列表的代码:
使用以下代码清理生成的数据帧:
下面的一系列代码描述了娱乐指数的公式,从 Foursquare API 的位置数据开始。首先,在一个数据框架中获得了大学 500 米范围内的前 20 个场馆:
接下来,获得独特的场地类别并进行“计数”以给出娱乐指数。
特征集分类
特征集的选择先于机器学习算法的实现。该功能集包括以下几列:“排名”、“租金”和“娱乐指数”。这些特征然后被转换成分类变量,随后基于分类变量执行一键编码,以便于机器学习算法输出的分析。
使用以下代码实现了分类:

功能类别
上述分类是通过对特征集进行探索性数据分析得出的:

特征集直方图
衍生大学集群
在组装数据集之后,在特征集上实现一个热编码。这确保了数据被转换成更适合实现机器学习算法的结构。接下来,在编码数据集上实现 k-means 聚类机器学习算法。
k-means 聚类是用以下代码实现的:
假设/限制
这项研究只考虑了公立大学。为了便于数字数据处理,在没有官方排名的情况下,给大学分配了一个任意的排名 50 。所采用的省租金[3]代表了指定省份内的月租金中位数。因此,省内各城市的实际租金可能与规定的有所不同。
结果和讨论
检查聚类算法的输出。然后为每个聚类分配唯一的描述。这些描述基于每个聚类中普遍存在的特征组合,并作为未来学生的标记,以“明智地选择”哪个聚类进行进一步探索。
下表显示了集群及其各自的描述:

独特的分类和描述
对这些集群的进一步检查揭示了以下情况:
- 租金中值较低的省份的大学没有“令人兴奋”的娱乐活动(即娱乐指数要么“有趣”,要么“稀疏”)。
- 租金中值为“昂贵”和“奢侈”的省份的大学有各种排名和娱乐选择。
- 没有一所排名较低或未排名的大学有“令人兴奋”的娱乐活动。
- 每所排名靠前的大学都位于租金中位数“昂贵”或“奢侈”的省份。
下面的图表提供了对集群的更多了解。首先,给出为生成每个图表而定义的函数:

基于排名特征的大学集群分布
从上面的图表中可以看出,希望在一流大学学习的学生可以直接探索第 8 组中的选项。

基于租费特征的大学集群分布
根据上面的图表,主要考虑“便宜”租金的潜在学生将很容易探索集群 0 中的大学。
此外,下图显示,对于那些认为娱乐是绝对必要的潜在学生来说,集群 2 和 7 提供了专门的“令人兴奋”的大学。第 4、5 和 8 组也提出了进一步的选择。

基于游憩指数特征的大学集群分布
然而,应该注意的是,没有一个图表是孤立有效的,因为未来的学生通常会有至少两个他们认为对他们的大学教育经历必不可少的特征。因此,应该结合使用这些图表以获得最佳结果。在此回顾集群及其各自的构成。点击这里查看 GitHub 上的代码。
结论
加拿大的大学已经根据定义的特征进行了分类:大学排名、省租金和娱乐指数。聚类是使用流行的 k-means 机器学习聚类算法获得的,而新娱乐指数所基于的位置数据是通过 Foursquare API 生成的。这些集群具有独特的特征,每个集群都清楚地包括具有所定义特征组合的大学。未来的学生现在可以自信地依靠集群来简化他们对梦想中的加拿大大学的搜索。
参考
[1]加拿大大学列表(2020 年 5 月 12 日)。维基百科,免费的百科全书。检索于 2020 年 5 月 18 日,来自https://en . Wikipedia . org/wiki/List _ of _ universities _ in _ Canada # MW-head
[2]加拿大最佳全球大学(2019 年 10 月 21 日)。美国新闻和世界报道 LP
[3]2020 年 5 月租金报告(n.p .)。rentals . ca . 2020 年 5 月 18 日检索自https://rentals . ca/national-rent-report # provincial-rental-rates
提升卷积神经网络性能的聪明方法:EfficientNet Google AI

照片由 Alicia Quan 在 Unsplash 上拍摄
卷积神经网络(CNN)已经成为图像分类、目标检测和许多其他应用的首选模型。但是就像来自黑豹的 T4·首里建议的那样,CNN 必须被改进以提供更好的准确性来解决正在研究的问题
"仅仅因为某些东西有效,并不意味着它不能被改进."—首里(黑豹,2018)
传统方法
提高 CNN 性能的传统方式是通过增加深度学习模型的深度。这里的深度意味着在已经可用的深度卷积模型之间或之上添加额外的层。深度的增加可能会适得其反,因为它需要更多的计算能力和资源。此外,在一定深度之后,系统中的 权重 趋向于饱和,而没有任何进一步的改进。
聪明的方法
为了解决上述问题,谷歌大脑团队提出了一个名为 EfficientNet 的解决方案,该方案通过在所有方向上高效缩放来提高模型精度和计算需求,不仅包括深度,还包括宽度和分辨率。它理想地导致每个维度相对于另一个维度的最佳平衡。通过这种方式,EfficientNet 不需要像 CNN 那样多的计算需求,从而获得更好的准确性
现在,让我们尝试围绕 EfficientNet 做一些因果分析,并理解普遍性的问题——为什么、在哪里以及这些深度神经网络是什么。
为什么选择高效网络?
为了理解为什么我们在构建深度模型时要保持高效率,首先,让我们了解不同类型的 缩放方法 和 复合缩放 的实际含义
传统缩放方法:
宽度缩放:图像的宽度一般是指通道,就像彩色图像中的 R、G、B。在这种缩放方法中,随着网络的增长,CNN 模型会尝试添加更多的频道,使网络变宽。这些广域网络(例如 WideResNet 和 MobileNets)在捕获高级特征方面存在困难
深度缩放:CNN 由几层组成,理解输入图像。增加层数在某个点上是有利的,在该点之后,模型由于消失梯度问题和复杂性而无法学习。
分辨率缩放:图像的分辨率就是图像的高度 x 宽度。与尺寸为 256 x 256 的图像相比,尺寸为 512 x 512 的图像包含更多信息。然而,采用高分辨率输入总是倾向于增加计算需求的负荷,并且在某个阈值之后将不会对模型的性能提供显著的增益。

模型缩放:a)宽度缩放 b)深度缩放 c)分辨率缩放。图片来自高效网论文:https://arxiv.org/abs/1905.11946
复合缩放
使用固定缩放系数的复合缩放方法可以解决单个缩放的痛点。在这种方法中,基于具有固定比例系数集的可用计算资源,网络在深度、宽度和分辨率上被均匀地缩放。
应该在不改变底层函数 F(x)(我们试图匹配的模式)的情况下确定最佳的层架构模型。因为有多个参数必须改变(深度、宽度、分辨率、资源),所以设计空间考虑相当大。为了减少这种设计空间,使用恒定比率来缩放参数。复合缩放的目标是在给定的约束条件下找到一个最佳比率—内存&FLOPS并获得最大精度
原始论文建议借助网格搜索尝试不同的缩放组合以找到最佳的缩放系数。后来,在流行数据集 ImageNet 上的现有模型如 MobileNet 和 ResNet 上实现了这种系数缩放,分别提高了 1.4%和 0.7%的精度。
准确性的提高并不仅限于上述两个模型,而是在几个模型上给出了显著的结果,如下图所示

图片来自原论文:https://arxiv.org/abs/1905.11946
因此,从上面的参考资料来看,在我们的模型开发阶段,EfficientNet 确实值得考虑。
什么是效率网?
一个好的基线模型对于在它的基础上进一步构建具有更好性能的模型是必要的。在 EfficientNet 中,使用类似于 MobileNetV2 和 MnasNet 的移动反向瓶颈卷积(MBConv)构建基准模型 EfficientNet-B0。稍后对基线模型进行改进,以获得效率网系列
让我简单介绍一下什么是 MBConv 以及 EfficientNet 的其他构建模块。MBConv 块只不过是最初在 MobineNetV2 CNN 架构中提出的反向残差块。
在正常的 剩余块中,网络流量通常从宽到窄再到宽的结构相对于信道数量而言。最后一层恢复到要添加的输入的形状(剩余块的目的是防止渐变消失)**

残留块。图片来自 papers with code:https://paperswithcode.com/method/bottleneck-residual-block免费
在反转残差块中,图层从窄到宽再到与残差块相反的。因此,它最初采用低维输入,并使用 1×1 卷积层对其进行扩展,随后是 3×3 深度方向卷积,并使用 1×1 卷积层返回到输入形状。

反向剩余块。作者图片
采用反向残差块的原因是,在原始残差块中,中间的扩展层仅仅是实现细节。该信息仍然可以在低维上相关,导致较少的计算需求和运行时间。
如图所示,baseline EfficientNet 的架构由深层的 MBConv 模块组成

图片来自谷歌人工智能博客— 来源
使用不同的比例系数获得效率网 B1 到 B7。下面给出了原始文件中所述的整体模型和性能比较

图片来自高效网纸—https://arxiv.org/abs/1905.11946
哪里可以使用高效网络?
由于用于计算的参数数量很少,EfficientNet 可以很好地用于快速处理,尤其是在 MobileAI 中。随后可以引入多维度进行缩放,并在 CNN 上开辟了全新的研究领域。
外卖
EfficientNet 开辟了一个广阔的研究领域,以改善一些计算机视觉任务的结果。它可能有助于在选择模型的深度、宽度和分辨率方面提供一个好的解决方案,以从中获得最大的结果。
在谷歌人工智能团队公布这个模型之后,已经有一些研究将 EfficientNet 视为主干,如优化分辨率差异的 FixEfficientNet ,可以广泛用于对象检测任务的 EfficientDet 。
太好了!感谢您阅读这篇文章,希望对您有所帮助🙌
参考📙
****原文:https://arxiv.org/abs/1905.11946
****谷歌 AI 博客:https://AI . Google Blog . com/2019/05/efficient net-improving-accuracy-and . html
****倒转残块:【https://paperswithcode.com/method/inverted-residual-block】T2
更明智的新冠肺炎决策
如何将决策科学的合理原则应用到自己的生活中
如果你没有意识到新冠肺炎,你可能已经在过去的几个星期里躲在石头下面了(很好,呆在那里)。你们其余的人可能会问自己,“我应该做什么,如果有的话?”
【本文也有: 阿拉伯语 , 印地语 , 意大利语 , 俄语 , 西班牙语。】

图片:来源。
首先,以下是不要做的事情。不要形成一个不了解情况的观点,然后去寻找证实你观点的媒体。你会找到它,也许你会感觉好一点,但你也可以跳过整个练习——这是浪费时间。你已经知道你只会确认你想相信的任何事情。如果这是你正在做的,这个指南可以帮助你!
处理事情的更好方法是:
- 把你的思想集中在你可能采取的行动上。
- 在你看数据之前选择你的决策标准。
免责声明: 我的专长是数据和决策——而不是流行病学——所以这是一个循序渐进的决策指南,帮助你在向对疾病略知一二的科学家寻求新冠肺炎建议时,构建你的思维。
第 0 步:面对你的非理性
如果你的主要目标是感觉更好,也许你会发现阅读两种令人讨厌的心理影响会让人感到安慰,这两种心理影响可能会破坏你有效应对所获得信息的能力:
如果你有兴趣了解他们在疫情期间是如何扰乱你的大脑的,请查看我在上面链接中关于这些主题的文章。也许这将是行为经济学的一种治疗时刻。(说从来没有人?)
第一步:了解自己,设定目标
从仔细思考你的道德和价值观开始。在这个阶段,试着从比最近的疫情更普遍的角度去思考。问自己一些尖锐的问题,你认为你对你的世界、社区、朋友、家庭和自己的责任是什么。
如果你没有调查自己道德的习惯,现在是一个成熟的时刻,面对令人不快的一般问题,如“在什么情况下,如果有的话,我愿意把一个陌生人的生命置于危险之中?风险有多大?”(如果你曾经在感冒的时候开车绕过别人或者出门,我很抱歉地告诉你,你已经在拿陌生人的生命冒险了。)
一旦你理解了你的优先事项和你认为的对与错,你将开始形成对你的各种目标以及它们对你有多重要的看法。例如,在餐馆吃饭的能力对你来说重要吗?对你来说比家人的健康更重要吗?
这种分析假设你的典型行为是为现有目标服务的(例如,去你最喜欢的餐馆可能会给你带来效用),只要不与你更重视的不同目标发生冲突(例如,保持健康可能会给你带来更多效用),这种行为对你来说是有意义的。在接下来的几个步骤中,我们将围绕你的旧行为不再符合你所陈述的优先事项的信号来构建你的决策。
注意,在决策过程的这个阶段,你应该避免考虑在外面吃饭是否安全。您将在步骤 5 中解决这个问题。目前,请坚持在当前特定病毒的背景之外衡量事情对您的重要性。
免责声明: 我应该指出,既然我已经为自己做了这个练习,我显然对什么是道德的有自己的看法,但我在这里不是要把我的任何看法强加给你。这篇文章不是要告诉你做一个多好的人(我是什么?你的政府?),只是如何在你自己的道德框架内明智地做出决定…尽管我希望你选择善良。
第二步:考虑可能的行动
一旦你知道你的立场,头脑风暴一下你可能考虑在不久的将来采取的一系列潜在行动,这些行动与如果没有新冠肺炎你会做的有所不同。从多洗手到在家工作到完全自我隔离,再到阅读如何徒手猎熊的手册。
从技术上来说,潜在行动的列表是无限的,所以每当一个行动突然出现在你的脑海中,你可以通过问自己来节省时间:
- “对我来说,做出一个慎重的决定很重要吗?”
- “有什么能说服我去做吗?”
回答“不”中的任何一个都意味着你可以通过彻底消除它来节省精力,这样决策过程就不会花费太长时间。
例子 1——不重要:多洗手的决定对我来说并不重要,因为这并不会花我多少钱。即使结果证明是浪费时间,我也不会难过。我不介意只是做它。我会做的。不需要更多的思考或研究。酷,那很简单。
例子 2——不是一个真正的决定:没有什么(除了一个完全疯狂的科幻场景)能让我徒手猎杀一只熊。非常好。不用做决定。我不用再想这件事了。
一旦你完成了头脑风暴,试着按照重要性的顺序来处理你的清单,这样你就可以在你累了和去看电视之前完成那些大的。或者,更好的是,为你愿意投入到第 2-4 步的时间量设置一个计时器。对于每个动作,下面的每个步骤都应该单独完成(并行,除非它们是依赖关系)。
步骤 3:选择动作触发器
对于每一个潜在的行动,请仔细考虑您将接受哪些信息作为该行动的触发因素。适当的触发器(或“决策标准”如果你喜欢附加音节)是足够强烈的信号,表明遵循你的旧行动路线与你声明的目标和优先事项不一致(从而触发你切换到正在考虑的新行动)。
让我们试一个例子。也许你已经买到了明晚的戏票,并且正在考虑不去看演出。
默认动作: 按计划去看戏。 替代动作: 改变你的行为,不要走。
默认情况下,你会去看演出,如果你的某个触发条件发生,你就承诺不去。(明智地选择它们——如果你允许自己以后打退堂鼓,你就失去了构建决策的全部意义。这就是为什么重要的是要想象你确实收到了这个信息,并检查你是否满足于用你的新行动来回应。)
在本节中,您需要考虑您的优先事项—如果您只关心自己的短期健康,那么您的触发因素将主要与感染病毒的个人风险及其在您的人口统计群体中的严重性有关。如果你关心其他人的健康和/或在未来几个月内获得医疗资源,你还需要考虑与"拉平曲线"相关的触发因素,以及关于疾病传播风险的信息(因为让因你而患病的人挤满最近的医院会损害你所声明的优先事项)。令人欣慰的是,您在第一步中花时间权衡了这些优先级,否则您将如何找到合适的触发器呢?

如果你不熟悉“拉平曲线”这个术语,你可以在这里了解更多。
您可以为每个操作选择多个触发器。这些触发因素都应该被理解为你收到的信息。这些信息可能是关于:
- 法律,例如“我的政府禁止大于 x 的集会”。
- 事件,例如“在我居住的 10 英里范围内检测为阳性的人数超过 x”。
- 一份研究出版物,例如“科学家说无症状的人可以传播病毒。”
- 一种社会规范,例如“现在好人都不去看戏了。”
- 建议,例如“最好避免呆在每平方英尺超过 x 人的密闭空间里。”
- 费用的明确变化,例如“所有门票将根据要求退款。”
- 风险估计的变化,例如“如果我在人群中闲逛,在接下来的两周内生病的概率至少是 x”。
- 一个我没有放在这个列表中的类别,例如“如果我出去,我最好的朋友会和我断绝关系。”
数据书呆子们,听好了——如果你们习惯于从统计假设检验的角度来思考,事情可能会变得很奇怪,因为我跳过了一些步骤,以使事情对普通读者变得简单。我建议查看下面的附录,在那里我通过您可能已经习惯的框架解释了正在发生的事情——带有 默认动作 和 无效假设 的框架。】
步骤 4:选择最低质量的来源
选择可以作为有效触发器的最低质量的信息源。如果一个质量较低的来源给你信息,你会试图用你选择的来源来验证它,除非质量足够好,否则你不会采取行动。继续我们的例子,每个触发器的最低质量来源可能是:
- 法律:你们政府的官方网站。当纽约市昨天禁止超过 500 人的集会时,我在合法的纽约市网站上查看了一下。其他人可能会从一家声誉良好的报纸上接受同样的信息,而不会进一步核实。你的最低信息源质量是你的个人选择。
- 事件:一份声誉卓著的报纸(符合你的口味)。就我个人而言,我喜欢那些享有恰当核实事实声誉的网站。
- 研究:一个有资格的流行病学家可以获得足够的数据来做出目前的推断,并以中到高的可信度发表他们的结论。作为一名科学家,在信任科学出版物时,我可能会更加谨慎。虽然有些人选择相信任何科学家说的任何话,但赢得我的信任需要综合经验/证书、相关数据的访问以及假设的力度与断言的力度。
- 社会规范:推特上有人?你会接受哪些关于社会规范的线索来源,这是非常私人的事情,我无法给你任何建议。对一些人来说,随便一个人在听得见的范围内说出来就足够了。其他人可能会等到《哈佛商业评论》的礼仪版。
- 建议:你的医生或贵国相当于 的疾病控制中心 。我不会告诉你从哪里得到医疗建议,但我希望你有标准。
- 费用: 剧院网站。如果剧院说他们会给我退票,我会比我的邻居说她听到谣言说票可能会被退票更有说服力。
- 风险估计:**疾控中心 再次,一个见多识广的 统计学家 正在处理相关数据,或者也许是你自己的模拟。是的,我们中的许多人数据科学家正在编写模拟(世界的玩具模型,看看事情如何在不同的假设下发生)。当我们根据我们信任的科学家的出版物更新假设时(或者在我们的代码中发现错误),我们的模拟会改变。
- **其他:其他。对于所有类别,我建议你要有一些质量标准(多严格由你决定)并意识到你的标准。不要惊慌失措地回应那些不符合你个人品质标准的人的喋喋不休。举个例子,如果我爸告诉我,如果我去外面,我最好的朋友会和我断绝关系,我不会惊慌失措——我会打电话给我最好的朋友核实。
记住,这些例子(模糊地基于我的品味)不是建议。我不会冒昧地告诉你如何生活,也许除了鼓励你走向自我意识。我们每个人都必须在如何构建决策的问题上达成共识。
第五步:收集信息
现在你已经想出了宇宙需要发送给你的触发各种行动的最小信号,你将从你的高质量来源收集信息(并继续收集)。如果决定很重要,彻底做好功课。
请注意,我要求您在查看信息之前先思考一下。这就是为什么数据收集位一直保存到第 5 步。如果你考虑人类动物的典型习惯,你会注意到大多数人不这样做。那我为什么要你去做呢?
在寻找信息前思考并设定标准有助于你避免确认偏见。要了解更多,请查看我关于数据驱动决策的文章。当然,你忘记考虑的事情可能会出现,所以你需要做出基于现实的决定(点击了解更多)。即使在这种情况下,稍微考虑一下你将接受的作为行动触发因素的信息的最低强度和质量也是非常有价值的。
第六步:行动(或者不行动)
如果没有相关信息,继续做你计划要做的事情。当不同的动作被触发时,执行它。(也许你会注意到有些动作应该已经被触发了,这个练习帮助你赶上了。)
这个故事的寓意
现在花点时间思考一下,这样当信息出现时,你会更加明智和冷静。
如果你一直读到这里,并且你知道有人可能会觉得这很有用,请与他们分享。与此同时,我会忍住不开一个关于如何让建议像病毒一样传播的玩笑。不过说真的,除非你(还有你和你还有你……)分享一下,否则几乎没人会看到这个。允许任何人免费查看本文的链接版本为:http://bit.ly/quaesita_covid
如果你想了解更多关于结构化决策的知识,我的 决策智能简介 是一个很好的起点。
假设检验者的附录
如果你习惯于经典的统计推断,你想知道零假设到底是怎么回事,我把附录放在这里。
接下来读什么
在疫情期间,照顾好你的大脑,聪明对待数据,做出更明智的决定
towardsdatascience.com](/a-decision-scientists-10-dos-don-ts-for-covid-19-805577bccd67)
喜欢作者?与凯西·科兹尔科夫联系
让我们做朋友吧!你可以在 Twitter 、 YouTube 、 Substack 和 LinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用此表格取得联系。
现在是完全不同的东西…
感谢阅读!如果你在这里玩得开心,并且对人工智能感兴趣,这里有一个初学者友好的介绍供你娱乐:
在这里欣赏整个课程播放列表:bit.ly/machinefriend*
使用机器学习为 Airbnb 更智能地定价

通过回归和时间序列分析增加主机收入
这个项目是名为 Metis 的沉浸式数据科学项目的一部分。你可以在我的 GitHub 和幻灯片 这里 找到这个项目的文件。最终项目可在 此处 (交互式 web app)访问。】
我最近设计了一种新的方法,使用 Airbnb 数据集中的为 Airbnb 房源自动定价。我使用线性回归建立了一个基础价格和时间序列分析,以预测由于日期的价格波动。我使用无监督学习建立了一个推荐系统,这样主机可以将他们的列表与其他类似的流行列表进行比较。
一些背景
Airbnb 在几年前推出了智能定价工具,但问题是价格建议太低,主机用户在使用该工具时注意到他们的收入减少了。像 Hosty 和 Beyond Pricing 这样的第三方解决方案试图通过增加主机收入的模式来解决这个问题;然而,这些是不灵活的和不可解释的。用户输入被限制为在 Airbnb 房源上输入的数据(防止用户轻易调整输入),主机无法了解他们是如何获得某个价格建议的。
对于那些还没有上市或者甚至还没有购买房产出租的新主机用户来说,这让他们对预期的收入感到困惑。所以我的目标是为新老主机建立一个工具,在不把价格降得太低的情况下最大化预订。
该过程
对于这个最初的概念,我专注于洛杉矶价格合理、入住率非常高的 Airbnb 房源,以训练模型,剔除定价过低和不受欢迎的房源。一个重要的假设是,因为实际的预订数据是不可用的,评论可以作为预订的代理。
我对每个列表的名称和描述使用了自然语言处理,以了解其中讨论的主题如何影响定价。然后我建立了几个回归模型来预测每处房产的基价。对于最终的模型,我使用了线性回归,因为它易于解释,这很重要,因为最终用户 Airbnb 主机将受益于了解他们的价格是如何最好地确定的。由于一年中的时间在度假价格中起着如此重要的作用,我做了时间序列分析来预测价格如何随着日期的变化而波动。然后我使用无监督学习建立了一个基于内容的推荐系统,供主机将其列表与类似的列表进行比较。最后,我将这个模型部署在一个 web 应用程序中,看看它如何工作。
清理完数据后,我设置了许多潜在的重要特性。除了上面提到的基于文本的特性之外,这个特性集还包括高级信息,如资产类型、房间类型和位置。它还包含更多的细节,如客人数量、浴室、他们拥有的便利设施等等。
结果
在训练初始模型并使用弹性网络正则化后,我挑选了最有效的模型,并调整超参数以找到最具预测能力的模型。我使用平均绝对误差来衡量回归模型的成功,最终结果是大约 18 美元,这意味着使用该工具的主机在为它们找到准确的价格时可以预计大约有这么大的回旋余地。
为了更好地理解该模型的工作原理,让我们深入研究一下它的特性。下图显示了每个特性的相对重要性,那些使价格上升的特性向右延伸,而那些向左延伸的特性使价格下降。

线性回归系数
最强的积极预测因素是房产类型是否是整个住宅,是否在洛杉矶西边的社区,酒店房间,以及它能容纳的人数——越多越好。虽然我最终从部署的模型中排除了基于文本的功能,但值得注意的是,价格上涨最多的主题是那些涉及良好室外景观和最近装修的主题。
那些对价格有最大负面影响的人需要长期居住,大多数非房产类型,东区社区,以及不出所料的合租房间。对价格产生负面影响的基于文本的特征涉及被描述为“舒适的”或“舒适的”以及“家庭友好的”房屋。
这似乎是相当直观的,价格应该更高或更低,取决于是哪一天。下图显示了基于一周中的某一天、一年中的某个时间以及特定节假日的细分。

价格在一周内下降,在周三达到最低,在周末飙升。许多节日也会抬高价格,尤其是感恩节、圣诞节和新年前夕。从季节变化来看,价格与洛杉矶夏末和寒假期间的旅游旺季相关。
基价与基于时间的波动相结合,建立一个建议价格,如下所示。

更智能的定价演示
用于价格预测的特征也被用作基于内容的推荐系统的输入,以找到与该输入相似的受欢迎的列表,这允许主持人将他们的列表与已经在市场上的其他列表进行比较。
如果你想亲自尝试一下,请访问我通过 Heroku 这里部署的应用程序。有任何问题,请随时联系和。
请微笑,你在镜头前!

使用许可知识共享零— CC0
你可以使用微软 Azure 的 Face API 将面部识别软件嵌入到你的应用中。相同的 API 可以用于零售分析(人们对产品展示的反应)、人群分析和商店中的客户行为等。
在一些客户那里使用过之后,我喜欢微软赋予公民数据科学家权力的方式。
我不是统计学家,但对数据科学的潜力有所了解。它总是让我大吃一惊!我今天想写关于认知服务,因为我喜欢探索它的潜力以及它所迎合的用例。
今天,我将探索 Azure Face 服务。它提供了用于检测、识别和分析图像中人脸的算法。处理人脸信息的能力在许多不同的软件场景中都很重要。示例场景包括安全性、自然用户界面、图像内容分析和管理、移动应用和机器人。

在 Azure 中创建面部服务
第一步是在 azure 中创建一个 face 服务。现在已经创建了资源,请转到您的资源,复制端点和密钥,它们将用于根据 face API 进行身份验证。

点击“转到资源”
现在让我们创建一个简单的控制台应用程序来调用和使用 API。
创建应用程序
-
在 Visual Studio 中,创建新的 C#控制台应用程序。
-
使用以下代码作为 facedetection.cs 文件的主体。
-
将<订阅密钥>替换为您的面部服务的订阅密钥
-
2。用在您的端点 URL 中找到的字符串替换< myresourcename >
现在运行代码,您应该会看到下面的内容

我用的是从 Unsplash 得到的图片。

杰米·布朗在 Unsplash 上拍摄的照片

来自面部服务 API 的输出
上面的截图显示了面部服务 API 的输出
1。性别是女
2。确定没有胡须
3。确定画面中有幸福

来自面部服务 API 的输出
第二个屏幕截图显示了面部服务 API 的输出
她头发的颜色为棕色,有 99%的把握
结论
有关于“老大哥综合症”的比较,每一个动作都被公司分析。虽然像面部识别这样强大的技术有其缺陷,但如果小心使用,它是非常强大的。在这篇文章中,我们介绍了如何通过 C#使用微软的 face API 实现面部识别系统的基本步骤。我喜欢如何进行面部分析(我创造了一个新词吗?!)使用 C#每个人都可以迈出成为数据科学家的第一步。
注:本文所表达的观点仅是我个人的观点,并不代表我的雇主的观点。
平滑语义分割边缘

玛利亚·沙妮娜在 Unsplash 上拍摄的照片
埃里克·范布勒贡献了叠加图像和掩模扩张的代码。
在之前的帖子中,我展示了如何从视频流中分离出一个人并改变背景,创建一个虚拟的绿色屏幕。在那篇文章中,表现最好的模型是一个粗粒度的语义分割模型,它产生了大的块状分割边缘。更细粒度的分割模型不能准确地跟踪视频流中的人,并且在更粗粒度的模型上使用高斯平滑会模糊整个图像。在本教程中,我们将介绍如何平滑由粗粒度语义分割模型生成的边缘,而不会模糊所需的目标对象。
本教程的所有代码都可以在 GitHub 上获得。要运行最终代码,首先注册一个 alwaysAI 账号(免费!)并在您的机器上设置它(也是免费的)。但是,您可以在任何 Python 计算机视觉应用程序中使用平滑代码!
本教程基于 OpenCV 和虚拟绿屏博客文章。如果你想跟着做,先克隆这个回购。
让我们开始吧!
- 首先,我们将建立一个检测帧中人物的遮罩。为了构建颜色遮罩,我们首先将语义分割对象中的所有颜色都改为黑色。然后,我们将只把对应于我们想要识别的标签的索引改变为白色。复制以下代码,并将其粘贴到将模型时间附加到文本变量的行下面:
# build the color mask, making all colors the same except for background
semantic_segmentation.colors = [ (0,0,0) for i in semantic_segmentation.colors]# iterate over all the desired items to identify, labeling those white
for label in labels_to_mask:
index = semantic_segmentation.labels.index(label)
semantic_segmentation.colors[index] = (255,255,255)# build the color mask
mask = semantic_segmentation.build_image_mask(results.class_map)
2.接下来,我们通过扩大掩模来扩大对应于检测到的人的区域。我们这样做是因为被检测的人的边界边缘通常倾向于在人的内部。通过放大这个区域,我们不会在后续步骤中切断任何被检测的人。我们使用 OpenCV 库来扩展遮罩,使用十字形扩展类型。复制以下代码,并将其粘贴到上一步所做更改的下方:
# Enlarge the mask
dilatation_size = 15# Options: cv.MORPH_RECT, cv.MORPH_CROSS, cv.MORPH_ELLIPSE
dilatation_type = cv.MORPH_CROSSelement = cv.getStructuringElement(dilatation_type,(2*dilatation_size + 1, 2*dilatation_size+1),(dilatation_size, dilatation_size))mask = cv.dilate(mask, element)
注 :您可以改变膨胀的大小来定制在被检测的人周围留下多少空间。有关 OpenCV 方法的更多详细信息,请参见文档中的CVT color,getStructuringElement,以及expand。
3.然后,我们使用 OpenCV 库中的“模糊”方法对整个蒙版进行平滑处理。复制以下代码,并将其粘贴到上一步代码的正下方:
# apply smoothing to the mask
mask = cv.blur(mask, (blur_level, blur_level))
4.生成背景的那部分代码与原始示例应用程序中的代码基本相同。我们要做的唯一区别直接出现在“else”语句的末尾。用下面两行替换“else”块后更新“background”并将数据发送到 streamer 的两行:
frame = overlay_image(frame, background, mask)
streamer.send_data(frame, text)
5.最后,我们将为背景生成一个倒易蒙版,然后将原始蒙版和倒易背景蒙版合并成一个新图像。在上一步中,我们调用了一个名为“overlay_image”的方法。我们的代码中还不存在此方法,因此复制以下代码,并将其放在 app.py 顶部的“main()”声明的上方:
def overlay_image(foreground_image, background_image, foreground_mask):
background_mask = cv.cvtColor(255 — cv.cvtColor(foreground_mask, cv.COLOR_BGR2GRAY), cv.COLOR_GRAY2BGR) masked_fg = (foreground_image * (1 / 255.0)) * (foreground_mask * (1 / 255.0))
masked_bg = (background_image * (1 / 255.0)) * (background_mask * (1 / 255.0)) return np.uint8(cv.addWeighted(masked_fg, 255.0, masked_bg, 255.0, 0.0))
该函数基于原始遮罩生成背景遮罩,该遮罩检测到白色的人(以及添加到 labels_to_mask 的任何其他标签)和黑色的所有其他字段。原始蒙版和新的背景蒙版然后被适当地缩放。最后,使用相等的权重组合两个掩模以形成最终图像。
就是这样!
要查看完成的应用程序,首先按照这里的所述配置一个新项目,选择从头开始。然后,只需构建并启动该应用,打开任何浏览器“localhost:5000”即可看到你的虚拟绿屏在运行,现在检测到的个人周围有了更平滑的定义。

你也可以看到与以前版本的不同

深度强化学习代理扮演的 Snake
犯了大错

图片来自 melmagazine.com
自从我看了网飞纪录片《AlphaGo 》,我就对强化学习着迷了。强化学习与现实生活中的学习是相似的:你看到一些东西,你做一些事情,你的行为会产生积极或消极的后果。你从后果中学习,并相应地调整你的行动。强化学习有很多应用,比如自动驾驶、机器人、交易和游戏。在这篇文章中,我将展示计算机如何使用深度强化学习来学习玩游戏蛇。
基础知识
如果你熟悉深度强化学习,可以跳过下面两节。
强化学习
强化学习(RL)背后的概念很容易理解。代理通过与环境交互来学习。代理选择一个动作,并以状态(或观察)和奖励的形式接收来自环境的反馈。这个循环会一直持续下去,或者直到代理以终止状态结束。然后新一集的学习就开始了。示意性地看起来是这样的:

强化学习:代理通过选择动作和接收观察(或状态)和奖励来与环境交互。
代理的目标是在一集里最大化总的回报。在学习阶段的开始,代理探索了很多:它在相同的状态下尝试不同的动作。它需要这些信息来为各州找到可能的最佳行动。当学习继续时,探索就会减少。相反,代理人会利用他的行动:这意味着他会根据自己的经验选择最大化回报的行动。
深度强化学习
深度学习使用人工神经网络将输入映射到输出。深度学习是强大的,因为它只需要一个隐藏层就可以逼近任何函数。它是如何工作的?网络是由具有节点的层构成的。第一层是输入层。然后隐藏层用权重和激活函数来变换数据。最后一层是输出层,对目标进行预测。通过调整权重,网络可以学习模式并改进其预测。

顾名思义,深度强化学习是深度学习和强化学习的结合。通过使用状态作为输入,行为的值作为输出,以及在正确方向上调整权重的奖励,代理学习预测给定状态的最佳行为。
行动中的深度强化学习
让我们将这些技术应用到著名的游戏《贪吃蛇》中。我打赌你知道这个游戏,目标是在不撞到墙或蛇的身体的情况下尽可能多地抓住苹果。我用 Python 和海龟库构建了这个游戏。

我在玩蛇。
定义行动、奖励和状态
为了给一个 RL 代理准备游戏,让我们形式化这个问题。定义动作很容易。代理可以选择向上、向右、向下或向左。奖励和状态空间有点难。有多种解决方案,其中一种会比另一种更好。现在,让我们试试下面的方法。如果蛇抢了一个苹果,奖励 10。如果蛇死了,奖励是-100。为了帮助代理,如果蛇靠近苹果,奖励 1,如果蛇远离苹果,奖励-1。
这个状态有很多选项:你可以选择给出蛇和苹果的坐标或者给出苹果的位置。要做的一件重要的事情是添加障碍物的位置(墙和身体),以便代理学会避免死亡。下面是行动、状态和奖励的总结。在本文的后面,您可以看到对状态的调整如何影响性能。

行动、奖励和状态
创建环境和代理
通过向 Snake 程序添加一些方法,可以创建一个强化学习环境。增加的方法有:reset(self)、step(self, action)、get_state(self)。除此之外,每次代理迈出一步,都需要计算奖励(查看run_game(self))。
代理使用深度 Q 网络来寻找最佳动作。这些参数是:
# epsilon sets the level of exploration and decreases over time
param[‘epsilon’] = 1
param[‘epsilon_min’] = .01
param[‘epsilon_decay’] = .995# gamma: value immediate (gamma=0) or future (gamma=1) rewards
param[‘gamma’] = .95# the batch size is needed for replaying previous experiences
param[‘batch_size’] = 500# neural network parameters
param[‘learning_rate’] = 0.00025
param[‘layer_sizes’] = [128, 128, 128]
如果你对代码感兴趣,你可以在我的 GitHub 上找到。
代理人扮演的蛇
现在是关键问题的时候了!代理学习玩游戏吗?让我们通过观察代理如何与环境交互来找出答案。
第一场比赛,经纪人毫无头绪:

第一届奥运会。
第一个苹果!代理似乎仍然不知道自己在做什么…

找到第一个苹果…然后撞墙。
第 13 场比赛结束,第 14 场比赛开始:

正在改进!
代理学习:它不采取最短的路径,但找到他的苹果。
第 30 场:

干得好!新高分!
哇,代理人避免了蛇的身体,并找到了一个快速的方法,苹果,只玩了 30 个游戏!
玩弄状态空间
代理学习玩蛇(有经验重放),但也许有可能改变状态空间,实现类似或更好的性能。让我们尝试以下四种状态空间:
- 状态空间‘没有方向’:不要给代理蛇前进的方向。
- 状态空间“坐标”:用苹果(x,y)和蛇(x,y)的坐标替换苹果的位置(上、右、下和/或左)。坐标在 0 和 1 之间缩放。
- 状态空间“方向 0 或 1”:原始状态空间。
- 状态空间“只有墙”:不要告诉代理人身体是向上、向右、向下还是向左,只告诉它是否有墙。
能否猜一猜,在玩了 50 局之后,把他们从最好的状态空间排到最差的状态空间?

一个玩蛇的代理阻止看到答案:)
你猜对了吗?
下面是使用不同状态空间的性能图:

定义正确的状态加速学习!该图显示了不同状态空间下最近二十场游戏的平均收益。
很明显,使用具有方向的状态空间(原始状态空间)学习得很快,并获得最高回报。但是使用坐标的状态空间正在改进,也许当它训练更长时间时,它可以达到同样的性能。学习缓慢的一个原因可能是可能的状态的数量:20⁴2⁴4 = 1,024,000 个不同的状态是可能的(蛇形画布是 20*20 步,有用于障碍的 2⁴选项,以及用于当前方向的 4 个选项)。对于原始状态空间,可能状态的数量等于:3 2⁴4 = 576(上/下和左/右各 3 个选项)。576 比 1,024,000 小 1,700 多倍。这影响了学习过程。
玩弄奖励
奖励呢?有没有更好的方法给它们编程?
回想一下,我们的奖励是这样的:

大错#1:转圈 如果我们把奖励-1 改成 1 呢?通过这样做,代理每存活一个时间步长将获得 1 的奖励。这可能会在开始时减慢学习速度,但最终代理不会死,这是游戏中相当重要的一部分!
嗯,有用吗?特工很快学会了如何避免死亡:

代理人每幸存一个时间步长将获得 1 的奖励。
-1,请回来!
大失败#2:撞墙 下一个尝试:把靠近苹果的奖励改成-1,抢一个苹果的奖励改成 100,会怎么样?你可能会想:代理每一个时间步都会收到一个-1,所以它会尽可能快地跑向苹果!这可能是事实,但还有一件事可能会发生…

代理运行到最近的墙,以尽量减少负回报。
体验回放
代理快速学习(只需要 30 局)背后的一个秘密是经验回放。在经验重放中,代理存储以前的经验,并使用这些经验来更快地学习。在每个正常步骤中,执行多个重放步骤(batch_size参数)。这对 Snake 非常有效,因为给定相同的状态动作对,奖励和下一个状态的差异很小。
大失败#3:没有经验重演 经验重演真的那么重要吗?我们把它去掉吧!在这个实验中,吃一个苹果的奖励是 100 英镑。
这是代理在玩了 2500 个游戏后没有使用经验重放:

没有经验回放的训练。即使代理打了 2500(!)游戏,代理不能玩贪吃蛇。玩得快,否则要过几天才能达到 10000 场。
3000 局之后,一局抓到的苹果最高是 2 个。
经过 10000 场比赛,最高数字是 3…这 3 是学习还是运气?
看起来经验回放确实很有帮助,至少对于这些参数、奖励和这个状态空间。每个步骤需要多少个重放步骤?答案可能会让你大吃一惊。为了回答这个问题,我们可以使用batch_size参数(在创建环境和代理一节中提到)。在最初的实验中,batch_size的值是 500。
不同经验的退货概述重放批次大小:

用 3 个不同的批量训练 200 个游戏:1(无经验重放),2 和 4。前 20 集的平均回报。
即使批量大小为 2,代理也要学会玩这个游戏。在图表中,您可以看到增加批量大小的影响,如果使用批量大小 4 而不是批量大小 2,则可以提前 100 多场比赛达到相同的性能。
结论
本文给出的解决方案给出了结果。代理学习玩蛇,在玩了 50 个游戏后获得 40 到 60 之间的高分(吃掉的苹果数)。这比随机特工强多了。
细心的读者会说:“这个游戏的最高分是 399 分。为什么代理没有达到接近 399 的分数?60 和 399 之间有巨大的差别!
没错!这篇文章的解决方案有一个问题:代理没有学会避免封闭。代理学习避开直接围绕蛇头的障碍物,但它看不到整个游戏。所以代理会把自己围起来死掉,尤其是蛇比较长的时候。

封闭的。
解决这个问题的一个有趣的方法是在状态空间中使用像素和卷积神经网络。那么代理人就有可能“看到”整个游戏,而不仅仅是附近的障碍物。它可以学习识别应该去的地方,避免圈地,获得最高分。
相关
[## 我是如何教我的电脑玩 Spot it 的!使用 OpenCV 和深度学习
一些有趣的计算机视觉和 CNN 的小数据集。
towardsdatascience.com](/how-i-learned-my-computer-to-play-spot-it-using-opencv-and-deep-learning-ad1f017a3ec3) [## 用 120 行代码求解诺诺姆图
拼图,组合和解决方案 gif。
towardsdatascience.com](/solving-nonograms-with-120-lines-of-code-a7c6e0f627e4)
[1] K. Hornik,M. Stinchcombe,H. White,多层前馈网络是通用逼近器 (1989),神经网络 2.5:359–366
[2] Mnih 等人,用深度强化学习玩雅达利 (2013)
别忘了 订阅 如果你想在我发表新文章时收到电子邮件。 ❤





浙公网安备 33010602011771号