成为机器学习工程师的不为人知的真相
从事人工通用智能研究?自动驾驶汽车?不…组成训练集并在基础设施上工作?更有可能。
照片由 Unsplash 上的 Gwendal Cottin 拍摄
我最近参与了 Reddit 上一个有趣的讨论,我的一些回答得到了高度评价。它的要点是作为一名机器学习工程师的不为人知的真相。我以策划的方式分享关键要点,因为我是更积极的参与者之一。
作为一名 ML 工程师有哪些不为人知的真相?关于 Reddit
这里有几个你可能会感兴趣的链接:
- [Labeling and Data Engineering for Conversational AI and Analytics](https://www.humanfirst.ai/)- [Data Science for Business Leaders](https://imp.i115008.net/c/2402645/880006/11298) [Course]- [Intro to Machine Learning with PyTorch](https://imp.i115008.net/c/2402645/788201/11298) [Course]- [Become a Growth Product Manager](https://imp.i115008.net/c/2402645/803127/11298) [Course]- [Deep Learning (Adaptive Computation and ML series)](https://amzn.to/3ncTG7D) [Ebook]- [Free skill tests for Data Scientists & Machine Learning Engineers](https://aigents.co/skills)
上面的一些链接是附属链接,如果你通过它们购买,我会赚取佣金。请记住,我链接课程是因为它们的质量,而不是因为我从你的购买中获得的佣金。
1.使用深度学习
许多机器学习爱好者认为他们会玩花哨的深度学习模型,调整神经网络架构和超参数。别误会,有些人会,但不多。
事实是,ML 工程师将大部分时间花在“如何恰当地提取类似真实世界问题分布的训练集”上。一旦你有了这些,你就可以在大多数情况下训练一个经典的机器学习模型,它会工作得足够好。
出于好奇,这些算法中最难解决的问题是什么?又是用哪一个来解决的呢?
由 Caleb George 在 Unsplash 上拍摄的照片
深度学习最近在计算机视觉(例如,自动驾驶汽车)和自然语言处理(GPT-3 等)方面取得了最大的成功。).因此,在这些领域工作的研究人员和从业者最有可能使用深度学习。
IMO 有史以来最大的成就就是 DeepMind 的 AlphaGo Zero。自动驾驶汽车可能是对社会影响最大的汽车。自然语言处理的最新成果是 GPT-3。
深度学习模型与经典的 ML 模型相比是否很难解释?
OP 说得好:
我看不出解释卷积神经网络会比解释基于支持向量机、随机森林或梯度推进的整个分类框架更难。
我觉得随着 NNs 对可解释性的研究越来越多,这种说法越来越不真实了。
当将 NNs 与 GLMs 或朴素贝叶斯等优秀的传统统计学进行比较时,它显然仍然成立。但是一旦你转向基于 CART 的方法或者任何使用内核技巧的方法,这种虚构的可解释性就不复存在了。
自动驾驶汽车领域将在未来四年内增长 42%,顶级工程师的薪水…
medium.com](https://medium.com/@romanorac/autonomous-systems-dcf6af4f88c5)
2.学习机器学习
在学习的时候,你倾向于浏览很多关于 arxiv-sanity 的论文,里面有一些非常酷的算法。然后你进入这个行业,你看到的都是相对基础的东西,如逻辑回归、前馈神经网络、随机森林(决策树)、单词袋而不是嵌入,你觉得这些模型可以由普通大学生甚至聪明的高中生实现。也许如果你幸运的话,你会看到 SVM。
基础设施和数据管道是所有真正的工程工作发生的地方。
职业生涯刚开始的时候感觉和上面的 OP 差不多。但是为什么在没有必要的情况下,你会使用一个更复杂的工具来完成任务呢?许多现实世界的问题不需要最先进的神经网络架构来解决。有时一个简单的逻辑回归就能完成任务。
评论的第二部分适用于较小的初创公司,在这些公司中,你通常必须自己处理数据管道。在较大的公司中,有专门的部门处理基础设施。但是没有捷径——数据科学家仍然需要充分了解数据基础设施是如何工作的。
3.学习理论
想学多少理论就学多少,但最终,你的工作将是 99%的数据清理和基础设施工作。
99%有点夸张了。换句话说:机器学习工程师不只是玩花哨的模型。有时他们需要通过清理和标记数据来弄脏自己的手。
为什么不用软件和服务给数据贴标签?
这是非常正确的。以至于我以为只有我一个人。我主要在 NLP 工作,99%的工作是用 Java 标记数据和制作一些基础设施。
对于实践中使用的大数据集来说,数据标注服务通常过于昂贵。有些数据集的标注并不简单。我有过一次在发票分类上工作的经历,你需要专业的会计师来标记这些数据。
机器学习在现实世界中是怎样的?
用 imgflip 创建的迷因
我越来越注意到,在理解数据科学家做什么方面存在差距。当期望与现实不符时,许多有抱负的数据科学家会感到失望。数据科学不仅仅是调整你最喜欢的模型的参数,并在 Kaggle 排行榜上获得更高的排名- 如果我告诉你现实世界中没有排行榜会怎么样?!?
这就是为什么我写了你的第一本云中的机器学习模型电子书来展示如何从头到尾处理一个实际的数据科学项目。这本电子书的目标是数据科学爱好者和软件工程师,他们正在考虑从事数据科学职业。
一步一步的指导,将告诉你如何训练一个机器学习模型,建立一个网络应用程序,并部署到…
medium.com](https://medium.com/@romanorac/hands-on-data-science-course-e764853f516b)
在你走之前
在 Twitter 上关注我,在那里我定期发布关于数据科学和机器学习的消息。
照片由Courtney hedge在 Unsplash 拍摄
揭示“民主化”数据科学/机器学习的常见误解
意见
你的志向是成为数据科学家还是机器学习专家?那么,请允许我戳穿炒作,澄清一些你可能已经被扼杀的误解。
尼克·舒利亚欣在 Unsplash 上的照片
大约 4 年前,正是 YouTube 上这个特定的视频——MarI/O——视频游戏的机器学习激起了我对人工智能&机器学习的兴趣。作为一个狂热的游戏玩家,同时也有经济学的学术背景,我对自己说,“哦,我已经有了让马里奥自己做这些事情所需的一半技能了”。
你看,这是我对机器学习(或一般的数据科学)的第一个误解。我一点也不知道什么是强化学习,在哪里&如何使用。但我在乎吗?没有。我所想的就是创造我自己的 ML 模型。
这里的教训是?误解的产生是由于一知半解&缺乏深入探究兔子洞的好奇心。[1]
不管怎样,我自学了编码&现在我向我的客户提供我在计算机视觉和 ML 方面的专业知识。
你能从这篇文章中期待什么
看最近的趋势,AI 肯定是上升的。对任何人来说,错过目前大量的就业机会都是不明智的。幸运的是,现在比以往任何时候都更容易进入机器学习或数据科学领域。现在有成千上万的在线资源,自学 ML 变得更加容易。
但是,随着学习资源的容易获取,一个主要的警告也随之而来。
你学会了编码,你只是弄清楚了什么是SVM&如何调整它的超参数以达到很好的效果。一切都很好,但是现在问问你自己。你对如何将新学到的知识和技能运用到现实世界的问题中有什么线索吗?
如果你对这个问题没有答案感到惊讶,那么,快速阅读文章的其余部分。
通过这篇文章,我希望在你进入机器学习领域之前澄清你可能有的一些误解。
观看&向卑微的巨人学习
吴恩达他们这样做的动机是什么?通过帮助社区繁荣,让他们在不久的将来更容易被雇佣,让世界变得更美好。
几年前,当我在 Python 上写下我的第一个 print(“Hello World”) 语句时,他们的资源对我来说是无价的,为我现在的抱负奠定了基础。但是,这就足以让你在这个行业真正就业吗?
一点也不。
像训练营、MOOC、视频教程等在线学习资源的本质是,它们被推销为“自学编码”。正如他们所说,这正是你投入时间和金钱的地方。你学习编码,而不是以非常具体的方式或风格理解为什么编码。
这本身就产生了一个问题;
学习上述课程的学生希望这足以在现实生活中找到一份工作。但如果是这样的话,仅参加 Udemy 课程的 300 多万学生就足以填补该行业的 ML 职位空缺。
因此,很明显,MOOC 或其他自定进度的在线课程不会帮你切断线索。
原因如下。
机器学习教育资源大众化的陷阱
一般来说,机器学习或数据科学领域主要由院士主导。由于某些学者愿意为社区贡献他们的知识,这种趋势似乎正在逐渐变好。
个人的这种慈善方式使全球成千上万的个人能够在这一领域寻找就业机会。此外,我们还可以看到该领域发展的速度有多快,因为他们决定与世界其他地方分享他们的知识。
简而言之,民主化对整个社区都有好处。
但是“让数据科学民主化&机器学习”无论如何现在都是一个热门话题。每个人都想为社区创建一两个教程。你可能会想,为什么我会特别指出来呢?
因为我不想让社区被误导。
为了重申这句话,让我给你一个另一位作家 Rahul Agarwal 描述的真实事件的例子。
Rahul Agarwal 在他的文章— 不要让数据科学 民主化,陈述了一个面试的例子,其中候选人是有经验的&可能也是自学的。[2]
引用他的文章;
“……他很好地解释了更高层次的概念,我决定更深入地挖掘他对他在项目中应用的技术的数学理解。这就是事情发生变化的地方……”
他对采访的描述是一个典型的例子,说明一个人仅仅依靠浏览教程,一个接一个地创建项目&建立一个可靠的投资组合。可以说,仅仅学习如何编写代码是不够的。
我们能从这个背景中学到什么?
你可能是一名全明星程序员,但如果你不能理解基本的基本概念,你就不会进步到足以被雇用的程度。
为什么会这样呢?
你知道,大多数企业经常以小本经营。此外,生产环境是不稳定的,不仅易受市场竞争的影响,也易受消费者的突发奇想的影响。这使得企业处于不利地位&被迫关注产品中最微小的细节。
从加快数据管道到在几毫秒内做出推论,这可能是一个获取巨额利润或破产的问题。拉胡尔试图通过他的文章传达的就是拥有如此精确的鹰眼。
但你不必总是有一双鹰眼
与 Rahul 的观点相反,机器学习领域的另一位专家&企业家是 Caleb Kaiser。他提倡将 ML 软件提供给那些迫切需要它的人,尤其是那些不是数据科学家的开发者。他的文章— 深度学习不再难 是一篇关于生产能力 ML 软件领域的精彩报告。
在这篇文章的上下文中,引用了他文章的一段摘录;
“……社区内的人们开发库和项目,抽象出公共的实用程序,直到工具能够足够稳定地用于生产。
在这个阶段,使用它来构建软件的工程师不关心发送 HTTP 请求或连接到数据库——所有这些都被抽象掉了——而只专注于构建他们的产品。"[3]
这里的关键词——“所有这些都被抽象掉了”。
现在,作为一名企业家,他不仅有义务向他的员工,也有义务向他的财务支持者解释产品。他认为,试图找出产品内部运作的基本概念可能是浪费时间。此外,考虑到他在公司的职位,他花时间学习与业务无关的新东西对公司来说是金钱损失。相反,他可以雇佣其他人,一个这方面的专家来做这件事。
我的观点是,如果你缺乏机器学习的基本概念的知识也没关系,如果你的优先事项是,比如说经营一家公司。但是如果你想找一份机器学习专家的工作,那么你必须做你应该做的事情。
AutoML 不是邪恶的天才,准备夺走你的工作
我真的不明白反对自动化背后的逻辑。当工作可以自动化时,为什么要弄脏自己的手呢?自动化不仅高效,还能为你节省时间去做其他事情!不管怎样,我想抗议自动化的历史可以追溯到人类刚刚开始创新技术的时候。
仔细阅读由一个名为勒德分子的组织发起的新勒德主义运动。见鬼,我们在经济学中也用一个术语来指代对技术失业的恐惧,这种恐惧被称为勒德谬误。
更多地谈论卢德主义就脱离了文章的内容,所以这是另外一个话题。
不管怎样,让我再一次把你的注意力引向 Rahul 的文章,这里有一些我不能同意的他提到的东西。
“……此类软件包的可用性让许多人认为数据科学可以完全自动化,从而完全消除对数据科学家的需求。或者,如果流程不能自动化,这些工具将允许任何人成为数据科学家。”[1]
我相信他担心像 MindsDB 这样完全没有根据的 AutoML 软件的出现。
MindsDB 是一款令人惊叹的开源 AutoML 软件,请查看它们。
在桑德尔·皮帅向全球观众宣布谷歌的新发明后,出现了任何人都可以使用 AutoML 软件创建神经网络的误解。在他的推介中,他表示 AutoML 将使我们的社区能够创建和设计神经网络,这在以前是只有少数拥有博士学位的人才拥有的技能
我引用他的话。
今天,设计神经网络是非常耗时的,并且需要专业知识,这限制了它在较小的科学家和工程师群体中的使用。这就是为什么我们创造了一种叫做 AutoML 的方法,表明神经网络设计神经网络是可能的。我们希望 AutoML 将利用今天一些博士拥有的能力,并在三到五年内使成千上万的开发人员为他们的特殊需求设计新的神经网络成为可能。【5】
你读过他在哪里提到 AutoML 是为开发者准备的吗?明白这意味着什么。
打个比方,假设我拥有一家公司&我们的应用程序可以使用生成对抗网络(GANs) 让你的照片看起来更老。有一个职位可以进一步开发我的应用程序。我可以雇佣一个拥有博士学位或者有经验的软件开发人员。当然,拥有博士学位的人会更好地理解 GAN 到底是如何工作的。虽然开发者更喜欢使用像 Keras 这样的框架来抽象构建 GAN &更关注于完善应用程序的工作方式。
如果我想让我的公司持续盈利,我应该雇佣一个有博士学位的人还是一个开发人员?
毫无疑问,考虑到我所受到的限制,我会把赌注压在开发者身上,让他按时交付给我一个可生产的产品。
抛开个人观点,技术上的抽象是不可避免的。在某个时间点,重复的任务,如数据扩充、数据清理等需要进行抽象,以节省开发人员的时间。
最后,结束
数据科学& ML 的领域极其广泛,即使在其子领域内也有特定的需求!一个人不可能在一生中成为真正的数据科学大师。但幸运的是,在数据科学领域成为一名万事通&而非大师也是一件好事。你只需要在正确的情况下运用正确的技能。
我们生活在一个惊人的时间点上。
毫无疑问,人工智能和人工智能领域的进步有时是势不可挡的。我们很多人都渴望从经济上充分利用这个机会。你可能对一份全职工作很满意,而你的朋友可能想开始自己的 ML 事业。正如我之前提到的,你的每一种方法肯定是不同的。
所以,知道你未来想做什么&为你的理想找到正确的方法。
此外,我们应该时常提醒自己,这种快节奏的发展给我们作为一个社区带来了好处。变化是好的,我们只需要知道如何根据不断变化的技术环境塑造自己。
参考文献:
[1] Imarticus Nirmal,关于机器学习的 10 个常见误解,数据科学协会(2018)
[2] Rahul Agarwal ,不要让数据科学民主化,走向数据科学 (2020)
[3] Caleb Kaiser ,深度学习不再困难,走向数据科学 (2020)
卢德派的领袖。手绘蚀刻,勒德—维基百科 (1812)
[5]雷切尔·托马斯,谷歌的 AutoML:打破炒作, fast.ai (2018)
揭示网络中的重要节点
揭示数据中隐藏层次的概率方法
编剧基尔弗·j·坎波斯,尼古拉斯·波扎·莫雷诺,亚历杭德罗·阿尔瓦雷斯,托马斯·维拉。
图数据库(或网络数据集)中最重要节点的检测是各种科学学科,尤其是数据科学中广泛关注的问题。近年来,由于现代计算机存储和计算能力的进步[1],以及 21 世纪初网络理论的爆炸式繁荣[2,3,4],其相关性一直在增加。
基本上,可以通过一组节点或实体以及一组描述这些实体之间如何交互或相关的链接来描述的任何数据集。这些类型的系统(或数据库)的一些例子是:
- 社交网络:人们用节点来表示,链接表示他们之间不同的社会联系(友谊、合作、共同爱好等)。).这些类型的网络出现在科技产品中,如脸书、推特、LinkedIn、Instagram、抖音等。在后者中,最重要的节点与高影响力的人“影响者”相关,这些人对现代营销部门越来越感兴趣[5]。
- 生物有机体:有机体的代谢可以用网络(代谢组学)来表示,其中的节点是生物分子(代谢物或酶),如果代谢物是酶介导的酶促反应的离析物或产物,则代谢物与酶相连。我们还可以通过蛋白质相互作用网络(蛋白质组学)将生物体内物理相互作用的所有蛋白质联系起来。最重要的节点与可能的药物靶标相关,这对于新治疗方法的设计非常重要,例如在寄生虫病中[6]。
- 运输网络:在这个场景中,节点代表地理位置(城市、机场、港口等。)并且如果存在连接两个节点的路由,则这两个节点是连接的。例如,在机场网络的情况下,如果从一个机场到另一个机场有直飞航班,则两个机场是连接的。最重要的节点/机场与大多数人流动通过的机场有关,如果我们假设标准的商业航班,因此避免或最大限度地减少流行病的传播,在这样的机场放置控制点和疫苗接种活动是非常重要的[7]。
- 计算机和物联网设备网络:这里的节点由物联网生态系统的所有设备(智能手机、基于 Arduino 的传感器、树莓、平板电脑、智能设备、计算机等)组成。)并且连接可以是有线的和/或抽象的,例如 wifi、3G、4G、5G、蓝牙等。
- 地震活动和气候:网络的多功能性也通过表现时间性质的数据来显示,如地震活动或气候,按时间来衡量。在这种情况下,节点是地理区域,如果两个节点之间存在高度的相关性或因果关系,则这两个节点是连接的[8]。
- 在线商店:我们可以将电子商店的产品表示为一个网络,在这个网络中,如果两个产品都是由同一个用户搜索或购买的,那么这两个产品就是相连的。另一种联系是由这些产品之间的关系(元数据)提供的。例如,网球拍和袜子可以共享属性:运动、户外、爱好。因此,球拍和袜子可以连接,但球拍和床不能连接。
- 互联网:在这种情况下,路由器是节点,链路是允许它们通信的有线或无线连接[9]。
- WWW(或万维网):允许我们通过节点来描述网页的世界,并且如果有从一个网页到另一个网页的超链接,这些网页中的两个是连接的。在这种情况下,WWW 是一个有向网络(因为它可能是从 A 页到 B 页的超链接,但不一定是从 B 到 A)。如果大量页面“指向”一个网页,我们可以说这个网页是相关的。网页的相关性或重要性的概念被用于像 Google 这样的搜索引擎的设计中。
前面所有的例子都允许我们从不同的角度来看数据,例如,作为组成系统(数据集)的元素之间的交互图。因此,使我们能够利用现有的数据挖掘和人工智能工具来揭示层次结构、模式、漏洞、重要元素等。这对于由记录列表组成的传统数据库模式来说是极其困难的。
具体来说,网络分析能为我们提供什么?
我们通过一个例子来回答这个问题。让我们想象一下,我们正试图在货物运输领域创建一家初创公司,例如像联邦快递、DHL、UPS 这样的企业。降低成本同样重要,对宏观公司和初创公司都是如此。我们需要问的第一个问题是主仓库放在哪里?尽管这个问题起源于被称为运筹学的数学学科。另一方面,网络理论允许我们从新的角度来处理这个问题,例如,通过计算中心性指数。特别是,计算在统计上最接近网络中任何点的节点(或站点)(紧密度中心性指数),或更容易从任何起点流向任何目的地的节点(或站点)(中间中心性指数)。这是寻找最中心的节点对一个公司有价值的几个例子之一。
“在下面的论文中,我们将感兴趣的是检测最重要的、相关的、有影响的或中心的节点。”
根据所研究的系统,重要性、相关性或影响的概念可能会有所不同。然而,对于大多数系统来说,一个重要的节点是
- 最连通(度中心性[10])。
- 最接近其余节点(接近中心性[11])。
- 通过它传递更多的信息(中间中心性[12])。
- 一个连接到其他重要节点(特征向量中心性[13])。
- 在许多其他人当中[14]。
这里我们将对基于信息流的方法感兴趣。
典型地,出租车司机不通过最短路线从 A 点到 B 点,因为城市交通网络中两点之间的最短路径可能遭受瓶颈效应(即可能饱和)。相反,出租车司机会选择比最短路线更省时的路线。同样的情况也发生在信息环境中,信息并不总是以最短的路径传播。因此,传统的中介度量(中间性)并没有利用网络中两点之间存在的路径多样性所提供的所有信息。
受 Mark Newman 的论文[15]的启发,下面我们从一个更简单的方法来探索他的方法,即通过吸收性均匀随机行走对网络中的信息包流进行建模。我们在下文中将这种方法称为纽曼方法。
随机漫步的方法论
我们从以下启发性的原则开始。信息网络中最相关的节点通过信息包与最常访问的节点相关,即大多数信息通过的那些节点。为了进一步阐明这个想法,想象从灰色节点集合开始的三次随机行走。为了到达蓝色节点,它们必须不可避免地经过红色和绿色节点,这样后者将比其他节点拥有更多的信息流。
图 1 两组节点(灰色和蓝色)之间的随机游走。
数学上,我们可以通过其转移矩阵 P_ij 描述随机游走,由下式给出:
等式 1
其中,邻接矩阵 A 是图的代数表示,如果节点 I 和 j 相连,则其输入 A_ij 等于 1,否则为 0(见图)
图 2 图或网络及其邻接矩阵。
k_i 是一个节点拥有的连接数。它被称为节点的度。例如,在图 2 中,节点 A 具有度 2,而节点 B 具有度 3。
对比结果
表 1 显示了应用于维克多·雨果的小说《悲惨世界》中的人物之间的同现网络的不同方法之间的比较[10]。根据每个度量显示前 10 个最重要的字符。应当指出,几乎所有的措施都把主角“冉阿让”以及反面角色沙威视为最重要的因素。顶部的其他主要人物是伽弗洛什和马吕斯。只有亲近也包括珂赛特在内。
表 1。不同中心性度量的比较分析
请注意,排名与小说的主要人物非常一致,即使只考虑了互动(没有权重),忽略了其频率。
随机漫步中间方法的实现
我们首先引入实现基于随机行走的纽曼方法所必需的一组库。
使用的 Python 包
(i) Networkx 能够通过适当的方法进行图形处理和基本分析。
(ii) Numpy 为我们提供了一套代数运算的工具。
(iii) Matplotlib 用于可视化结果。
我们还实现了一个函数来读取 sif 文件(简单交互文件)
这个函数允许我们读取 sif 格式的数据集,并构建一个 networkx 图。然后,使用nx.to_numpy_matrix(G)
我们创建其相应的邻接矩阵。
“转移”函数允许我们计算从节点 I 到节点 j 的概率。注意,这与等式(1)中的写法相同。然后,我们通过使图上的随机行走进化更大数量的步骤来模拟网络中的信息流。这是通过允许 walker 根据其转移概率从一个节点移动到一个邻居节点来实现的。
对于随机行走执行的每一步,我们将访问过的节点存储在一个名为 Orbit 的列表中。然后,我们计算随机漫步在图 G 的每个节点 I 上的访问频率,以这种方式获得每个节点的中心性。为了可视化的目的,我们从一个特定的色标中心值。
使用 nx.draw 函数绘制网络,使用 Kamada Kawai 布局计算节点的位置,这提供了网络的良好表示。色标用红色调表示最中心的节点,用蓝色调表示最不中心和最外围的节点。
最后,下面的代码块旨在导出使用该方法获得的排名的前 10 名,并将其存储在 pandas 数据帧中,以供表 1 中所示的后续分析和比较。
将中心性值标准化,并设计条形图来比较这里研究的每个中心性测量的重要性的规模和分布。
各种数据集中的应用
悲惨世界网络图。
冉阿让突出显示为最中心的节点,以红色显示。接下来,我们将看到从所研究的不同方法获得的图,其轴是所涉及的节点及其在网络中相对于从轨道列表的 H 直方图获得的密度的影响或中心性(从 0 到 1)。由节点除以轨道的最大值产生。
特征向量中心性:认为伽弗洛什是最有影响力的节点,其次是冉阿让。
度中心性:冉阿让被认为是网络中最有影响力的节点,其次是伽弗洛什。比预期的要近。
接近中心性:显示冉阿让为最中心节点,然后显示随后的 4 个形成具有大致相同重要性值的平台。沙威(与冉阿让对立的人物)、马吕斯和伽弗洛什脱颖而出。
中间中心性:它将冉阿让显示为最有影响力的节点,并且由于其试探法中使用的测地线概念的限制性,以下中心性值与冉阿让相比呈现相当低的值。
纽曼基于随机游走的中心性:给我们一个与小说中最有代表性的人物很符合的排名:冉阿让、伽弗洛什、马吕斯、沙威。包括更多的信息,例如转移矩阵中的共现频率,肯定会改善这个结果。
文艺复兴时期的佛罗伦萨家族网络。
这个网络取自帕吉特等人的作品,并根据描述不同家庭间婚姻网络的历史文献构建而成。从[17,18]我们有证据表明,美第奇家族是 15 世纪佛罗伦萨最强大的。
扎卡里空手道俱乐部网
这个网络取自 Wayne Zachary 关于小型社会团体裂变的研究[19]。节点是大学空手道俱乐部的成员,它们之间的链接表示它们之间在俱乐部之外的社交互动。扎卡里的工作表明,最重要的节点是 33,32,和 0,分别是俱乐部的主席,副主席,和唤醒。了解了这一点,我们注意到,通过应用纽曼的算法,发现俱乐部主席和老师是这个网络中最有影响力的节点。
结论
- 在基于随机游走的网络型数据库中实现了一种重要节点分析方法。
- 在几个测试网络中,其性能与文献中报道的其他中心性方法进行了比较,在这些测试网络中,存在关于节点的层次或重要性的部分或全部信息,显示纽曼方法具有更好的结果。
- 鉴于其性质,它可以并行化,采取许多轨道,而不是只有一个。
- 更实际的方法是考虑转移矩阵的渐近分析(稳态),这相当于进行无限长的随机行走。然而,关于暂时统计状态的信息却丢失了,而这些信息是人们非常感兴趣的。
代码
所有代码都可以在存储库中找到:
【https://github.com/vtomasv/uiNin
参考文献。
- Grochowski,EG,Hoyt,RF & Heath,JS 磁硬盘驱动器外形尺寸演变。IEEE 磁学汇刊 29,4065–4067(1993)。
- A.博纳博·巴拉巴斯(2003 年)。“无标度网络”。科学美国人:50–59。
- 施·斯特罗加兹,DJ·瓦茨(1998 年)。“小世界网络的集体动力”。大自然。393 (6684): 440–442.
- Amaral,LAN,Scala,a .,Barthélémy,M. & Stanley,何类小世界网络。美国国家科学院学报 97,11149–11152(2000)。
- https://medium . com/swlh/what-is-influencer-marketing-the-complete-guide-2ef 95 a 6 EB 4a 3
- Herrera-Almarza G .,等从网络理论的角度看大肠杆菌蛋白质相互作用网络中必需基因的性质,科学与工程计算方法杂志 17 (1),209–216(2017)。
- 复杂网络中的流行病过程。现代物理学评论 87,(2015)。
- Yook,SH,Jeong,h .和 Barabási,AL 模拟互联网的大规模拓扑结构。美国国家科学院院刊 99 **,**13382–13386(2002)。
- Bottinelli,a .,Perna,a .,Ward,A. & Sumpter,2012 年欧洲复杂系统会议录。2012 年欧洲复杂系统会议论文集 591–606(2013)。doi:10.1007/978–3–319–00395–5
- 社会网络分析方法与应用。(剑桥大学出版社,1944 年)。
- 图的中心性指数。心理测量学。31, 4, 581–603 (1996).
- 一个更快的中间中心性算法。今天。数学。搭档。25, 163–177 (2001).
- 《权力与中心性:一系列衡量标准》。我是。你好。社会主义者 92, 1170 (1987).
- 复杂网络中的重要节点识别。物理报告 650,1–63(2016). 650,
- 纽曼,MEJ (2005)。“基于随机游走的中介中心性的度量”。社交网络 27:39–54。
- 斯坦福图表库:组合计算的平台。(艾迪生-卫斯理,雷丁,马,1993)。
- 帕吉特、JF 和安塞尔、CK《强力行动和美第奇家族的崛起,1400-1434》。我是。你好。社会主义者 98, 1259 (1993).
- 社会和经济网络。(普林斯顿大学出版社,2010 年)。
- Zachary WW --小团体中冲突和分裂的信息流模型。你好。安东尼。第 33,452-473 号决议(1977 年)。
在一个文件夹中解压缩、更新和再压缩 XML
使用 python 自动化办公程序
作者图片
日常办公中,经常要带着一堆文件做一些事情。解压,移动,重命名,更新,再次压缩,发送或加载到 FTP。所有这些事情做起来都很简单,但是非常耗时,你必须手动地在数十或数百个文件上重复它们。
幸运的是,您可以使用编程语言来自动化这些重复的任务。Python 是一个理想的选择,因为它很容易在计算机上安装,几乎不用试错,即使是计算机新手也能创建程序。Python 是一种通用的编程语言,基本上你可以用它解决任何问题。
让我们来探讨一个在许多行业中相当常见的任务。我们将:
- 解压缩一组文件
- 更新它们的内容—在我们的示例中,我们将更改 XML 节点的内容
- 使用
zipfile
和shutil
库再次压缩结果
你可以在 github 笔记本-Unzip _ Update _ Zip _ full . ipynb中跟进这个练习。
安装 Python
在 Jupyter 笔记本中执行的示例 python 代码
有几种方法可以在你的电脑上设置 python。我个人很喜欢使用 Anaconda 和 Jupyter 笔记本。您下载并安装 conda 包,该包旨在通过所有可能的增强使 python 环境易于管理,并运行笔记本,这是包的重要部分。
在笔记本中,您可以运行包含一行或多行代码的单独单元格,并立即看到结果。这种方法非常适合原型开发。在 google、 stackoverflow、和教程的帮助下,例如在 medium 上,你可以快速组合你需要做的事情所需的代码片段。
解压缩
让我们探索一下如何在 python 中处理解压文件的任务。只要去谷歌输入“解压 python”就可以了。它会快速列出结果,你可以选择,比如说最大的编码问答网站之一——stack overflow 的 Python 解压文件。在 3 行代码中,您将了解如何做到这一点:
import zipfile
with zipfile.ZipFile(path_to_zip_file, 'r') as zip_ref:
zip_ref.extractall(directory_to_extract_to)
你在import
图书馆工作所需的.zip
文件— zipfile
。这允许您使用它的函数和方法来解包归档文件并再次压缩它们。
首先,使用zipfile.ZipFile(path_to_zip_file, 'r')
打开归档文件进行读取,然后将包的内容提取到目录zip_ref.extractall(directory_to_extract_to)
中。
我使用了with
符号来确保打开归档文件,执行一个操作,然后关闭归档文件,以便从内存中释放其内容。它可以防止在处理成百上千个文件时出现内存泄漏。
解压缩包含许多文件的文件夹
在 python 中解压缩一个文件需要使用三行代码。要解压缩一堆文件,您只需再添加几行。您必须识别文件夹中的 zip 文件,并将它们传递给我们上面描述的过程。
os
库让你既可以获得文件夹os.listdir()
的内容,又可以使用os.path.join(folder,file)
将文件夹和文件名组合起来。Listdir 返回文件和子文件夹。您可以添加file.endswith(".zip")
来仅识别档案。
或者你可以使用
os.path.splitext()
。它的第二个输出是文件扩展名。
知道了文件夹中的所有文件,就可以应用前面的代码来解压缩它们。同样,您可以遍历文件并解压缩每个文件,或者将解压缩打包到一个函数中,该函数在一行综合符号中调用。
def unzip(folder: str, file: str, folder_to_extract: str) -> list:
"""unzips a file in a folder into folder_to_extract
returns a list of files in the zip archive"""
with zipfile.ZipFile(os.path.join(folder,file), 'r') as zip_ref:
zip_ref.extractall(folder_to_extract)
return zip_ref.namelist()# applying a function to the output can be squeezed into the list comprehension
[unzip(folder, f, "temp") for f in os.listdir(folder) if f.endswith(".zip")]
更新提取的 XML
一旦我们将 XML 提取到temp
文件夹中,我们就可以使用它了。Python 包含 xml.etree 库来处理 xml 文件。在我们的例子中,我们知道 zip 存档包含一个 XML 文件a.xml
,尽管您可以使用zip_ref.namelist()
列出存档中的所有文件。
要更新 XML 文件,您必须导入树库并加载 XML 文档。
from xml.etree import ElementTree as ET# parse the XML document into a variable
tree = ET.parse(path)# get the root emelement containing all the XML nodes
root = tree.getroot()
请记住,从
tree
派生的任何变量都是一个引用。当您更新这些变量的内容时,您也更新了tree
。
假设我们想要更新 XML 中的<id>...</id>
节点。我们必须首先找到它。etree 库中有几种定位 XML 节点的方法。
.find()
找到 XML 元素的第一次出现.findall()
列出子元素的所有外观
这两种方法都接受元素的名称,或者您可以使用xpath
找到它。Xpath 是一种在 XML 中定位所需元素的地址。一旦找到使用的节点,就用.text
参数来获取写在标签之间的值。
# in the <data> find the <id>...</id> node and show its content (.text)
id = root.find("id").text
我们的 Id 由下划线“_”分隔成三部分:
- 前缀
- 版本
- 日期
其中一个 XML 的 id 是test_001_20201026
。.text
返回字符串形式的值,您可以应用.split("_")
函数将文本分解成细节。
[In]:
split_id = id.split("_")
print(split_id)[Out]: ["test","001","20201026"]
输出是一个 python 列表,可以很容易地按元素更新。首先我们改变前缀split_id[0] = new_prefix
。然后我们更新版本。
split_id[0] = new_prefix
split_id[1] = "{:03d}".format(new_version)
如果需要将1
转换为001
,我们已经使用"{:03d}".format(new_version)
添加了最多 3 个字符的前导零。
更新的值可以通过.join("_")
组合成一个字符串,原始的 XML 组件可以用它来更新:
root.find("id").text = "_".join(split_id)
正如我提到的,对从tree
派生的变量的任何更新也会更新tree
。我们已经实现了我们想要的 XML 更新,我们只需要使用tree.write(output_path)
将其导出。
让我们看看 XML 更新的完整代码:
压缩更新的 XML
现在更新后的a.xml
位于temp
文件夹中。我们只需要压缩它,并将这个归档文件放到processed
文件夹中。让我们首先创建输出文件夹,如果它不存在的话。我们将使用pathlib
库中的Path
。
# create the output folder if it doesn't exists
Path(output_folder).mkdir(parents=True, exist_ok=True)
然后,我们使用zipfile
lib 将 XML 打包到 zip 存档中。现在我们必须打开归档文件进行写入'w'
。然后我们使用这个档案和.write(path_to_file, name_of_this_file)
的引用。
如果不指定第二个参数
name_of_the_zipped_file
,那么包括文件夹和子文件夹在内的整个路径都会被压缩。
如果你不知道文件名,os
库可以用它的os.path.basename()
功能帮你。
with zipfile.ZipFile(output_path, 'w') as myzip:
myzip.write(path_to_processed_xml, os.path.basename(path_to_processed_xml))
压缩时,指定压缩文件的名称,以避免压缩包含的文件夹。作者图片
尽管有时你也需要打包文件夹和文件。在我们的例子中Folder_001_20201101.zip
包含一个文件和另一个文件夹中的文件。
- folder_A/a.xml
- efg.txt
在这种情况下,使用 zipfile 会有点太完整,但是在[shutil.make_archive](https://docs.python.org/3/library/shutil.html)(output_folder, format, folder_to_pack)
中有一个替代方法。这个方法只将folder_to_pack
的内容存档,并将结果放在output_folder
中。您可以选择zip
、tar
、gztar
、bztar
、xztar
格式。
把它们放在一起
现在我们知道了该过程的所有组成部分:
- 将一个文件夹中的多个归档文件解压缩到一个临时文件夹中
- 更新了每个解压后的文件
- 并将更新后的文件再次压缩到归档文件中
在这个最后的练习中,我们必须做一些小小的调整。我们将使用原始存档的名称,更新它,同时更新所有包含的 XML 的内容。原因是归档中可能有两个或更多的 XML,每个都有不同的 id,我们将它们全部压缩回更新的 zip 归档(不能有两个不同的名称)。
完整的代码,可以在这个笔记本中找到—Unzip _ Update _ Zip _ full . ipynb
结论
在这个简单的教程中,您已经看到了 python(或任何其他编程语言)的威力。在几行代码中,您可以自动执行任务,如果手动执行,将会花费大量时间。当决定是否值得花时间编码时,我使用这个原则:
如果你做一次小事情,手动做。如果它很大,你在许多项目上重复同样的操作,或者你认为你将来不得不这样做——用编程语言自动化。
这个例子中的操作可以有许多变化。您可能希望更新不同的 XML 节点。zip 可能包含 CSV 文件。您宁愿更新日期,而不是前缀和版本。您可能需要修改输入—例如,将版本增加 1 或在日期上添加一周。
只要对代码稍加修改,所有这些都是可能的。您也可以在 Github上的 jupyter 笔记本中查看完整的示例。
我希望你喜欢这篇关于压缩和 XML 处理的教程,也希望你喜欢用 python 可以实现的东西。可能性是无限的。
Other articles:* [Plotly Express complete tutorial](/visualization-with-plotly-express-comprehensive-guide-eb5ee4b50b57)
* [Very illustrative highlighted line chart](/highlighted-line-chart-with-plotly-express-e69e2a27fea8)
* [Plotly Histogram - Complete Guide](/histograms-with-plotly-express-complete-guide-d483656c5ad7)
* [Everything you wanted to know about Kfold train-test split](/complete-guide-to-pythons-cross-validation-with-examples-a9676b5cac12)
* [How to turn a list of addreses into a map](/pythons-geocoding-convert-a-list-of-addresses-into-a-map-f522ef513fd6)
与 Milvus 一起运行
向量相似性搜索引擎。构建推荐并搜索图像/视频、音频或非结构化文本。
马库斯·温克勒在 Unsplash 上的照片
什么是 Milvus?
一个矢量相似性搜索引擎,看起来已经可以生产了。据网站:
- 它提供了多种相似性度量和索引类型。
- 水平缩放。
- 读写几乎是实时进行的,这意味着我们可以在引擎在线时插入记录。
- 公开一个 REST 接口。
听起来很酷!
对于那些还不知道的人来说,像这样的技术有很多用例。在机器学习的帮助下,我们可以搜索图像、视频和音频。
假设我们训练了一个对图像进行分类的 CNN。如果我们在最终输出之前查看任何层的输出,我们可能会发现描述输入的 N 维特征向量。随着我们在网络中移动,这些特征变得更加具体。开始时,我们可以识别纹理、形状等。接近尾声时,我们辨认出像猫耳朵和狗尾巴这样的物体。我们可以获取这些层的输出,通过某种方法将其展平,并在搜索引擎中对其进行索引!瞧啊。所选择的层将对什么被认为是“相似的”产生影响。这将因使用情形而异。这个例子是基于内容的图像检索(CBIR)的一个应用。
我们在建造什么?
一个非常简单的在 Dockerized 环境中使用 Milvus 的 CBIR 实现。这是完整的回购协议和我们将使用的技术列表。如果你想下载回购,只是乱搞,它已经准备好了。
在 GitHub 上创建一个帐户,为 dshvimer/milvus 的启动和运行开发做出贡献。
github.com](https://github.com/dshvimer/milvus-up-and-running)
- python——因为
- Docker —这样每个人都有一个标准的环境
- py torch——因为我总是跳 Keras,想学点新东西。
- Jupyter 笔记本—与 Milvus 互动的简单方式
设置项目
在一个新的目录中,让我们创建更多的空目录。
-project
-notebook
-milvus
-conf
在顶层目录中,创建一个名为docker-compose.yml
的文件,内容如下:
version: '2.0'
services:
notebook:
build:
context: ./notebook
ports:
- '8888:8888'
volumes:
- ./notebook:/home/jovyan
links:
- milvus
milvus:
image: milvusdb/milvus:0.9.1-cpu-d052920-e04ed5
ports:
- '19530:19530'
- '19121:19121'
volumes:
- ./milvus/db:/var/lib/milvus/db
- ./milvus/conf:/var/lib/milvus/conf
- ./milvus/logs:/var/lib/milvus/logs
- ./milvus/wal:/var/lib/milvus/wal
我们定义了两个 docker 容器,一个用于 Milvus,另一个用于 jupyter 笔记本。Milvus 容器通过links
属性对笔记本可见。我们声明的卷是为了让 Milvus 文件系统与我们的操作系统共享一些文件夹。这让我们可以轻松地配置和监控 Milvus。因为我们给了笔记本容器一个上下文来构建,所以我们需要在notebook
目录中创建一个名为Dockerfile
的文件,其内容如下:
FROM jupyter/scipy-notebookRUN pip install pymilvus==0.2.12RUN conda install --quiet --yes pytorch torchvision -c pytorch
这不是声明依赖关系的最佳方式,但可以在以后进行优化。我们还应该下载一些图片来玩。随意下载我用的这里的:把它们放入notebook/images
。
最后一步,下载启动器 Milvus 配置文件并放入milvus/conf/
中。现在只要 Docker 安装并运行,我们运行docker-compose up
,我们就活了!
如果您在控制台输出中看到以下行:
milvus_1 | Milvus server exit...milvus_1 | Config check fail: Invalid cpu cache capacity: 1\. Possible reason: sum of cache_config.cpu_cache_capacity and cache_config.insert_buffer_size exceeds system memory.milvus_1 | ERROR: Milvus server fail to load config file
这意味着 Docker 没有足够的内存来运行 Milvus。如果我们打开配置文件并搜索“cpu_cache_capacity ”,我们会看到一些有用的文档。“T11’插入缓冲区大小’和’ cpu 缓存容量’之和必须小于系统内存大小。”
将两个值都设置为 1,然后打开 Docker 的设置,确保将其配置为任何大于 2GB 的值(必须大于)。确保应用设置并重启 Docker。然后再试试docker-compose up
。如果有其他问题,请在评论中告诉我。
PyTorch 特征向量
有趣的东西,开始了。一旦一切都运行了,我们应该有一个 URL 来访问我们的 jupyter 实例。让我们创建一个新的笔记本并开始编码。一次一个细胞。
首先是进口:
import torch
import torch.nn as nn
import torchvision.models as models
import torchvision.transforms as transforms
from torch.autograd import Variable
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
现在让我们定义一个助手类来提取特征向量:
我为什么选 ResNet18?因为它有一个输出长度为 512 的平面向量的层。学习新事物时,方便和容易是合理的。这个类有很大的扩展空间。我们可以一次从多个层提取特征,并一次输入多个图像。就目前而言,这已经足够好了。
现在,我们可以加载我们的图像,并开始查看相似性:
feat_vec = FeatureVector()
dog1 = Image.open('./images/dog1.jpg')
dog2 = Image.open('./images/dog2.jpg')
dog3 = Image.open('./images/dog3.jpg')
cat1 = Image.open('./images/cat1.jpg')
cat2 = Image.open('./images/cat2.jpg')
person1 = Image.open('./images/person1.jpg')
person2 = Image.open('./images/person2.jpg')def compare(a, b):
plt.figure()
plt.subplot(1, 2, 1)
plt.imshow(a)
plt.subplot(1, 2, 2)
plt.imshow(b)
a_v = feat_vec.get_vector(a)
b_v = feat_vec.get_vector(b)
print('Similarity: {}'.format(feat_vec.similarity(a_v, b_v)))compare(dog1, dog2)
在第一个例子中,小狗和成年金毛猎犬图像的相似性得分约为 0.79。当我们比较一只小狗金毛寻回犬和一只哈巴狗时,我们得到的相似性分数约为 0.58。
使用 Milvus:连接、插入、查询
让我们做我们来这里要做的事。我们从连接 Milvus 开始,创建一个集合
from milvus import Milvus, IndexType, MetricType, Status# Milvus server IP address and port.
# Because the link to milvus in docker-compose
# was named `milvus`, thats what the hostname will be
_HOST = 'milvus'
_PORT = '19530' # default value# Vector parameters
_DIM = 512 # dimension of vector_INDEX_FILE_SIZE = 32 # max file size of stored indexmilvus = Milvus(_HOST, _PORT, pool_size=10)# Create collection demo_collection if it dosen't exist.
collection_name = 'resnet18_simple'status, ok = milvus.has_collection(collection_name)
if not ok:
param = {
'collection_name': collection_name,
'dimension': _DIM,
'index_file_size': _INDEX_FILE_SIZE, # optional
'metric_type': MetricType.L2 # optional
}print(milvus.create_collection(param))# Milvus expo
_, collection = milvus.get_collection_info(collection_name)
print(collection)
现在我们可以插入图像的特征向量。我们需要将向量转换成 python 列表:
images = [
dog1,
dog2,
dog3,
cat1,
cat2,
person1,
person2
]# 10000 vectors with 128 dimension
# element per dimension is float32 type
# vectors should be a 2-D array
vectors = [feat_vec.get_vector(i).tolist() for i in images]# Insert vectors into demo_collection, return status and vectors id list
status, ids = milvus.insert(collection_name=collection_name, records=vectors)
if not status.OK():
print("Insert failed: {}".format(status))
else: print(ids)
如果成功了,我们应该会看到 Milvus 用来识别图像的 ID 列表。它们的顺序与我们的图像列表相同,因此让我们创建一个快速查找表,以便在给定一些 ID 的情况下轻松访问图像:
lookup = {}
for ID, img in zip(ids, images):
lookup[ID] = imgfor k in lookup:
print(k, lookup[k])
我们可以将新项目刷新到磁盘上,并为收藏获取一些信息:
# Flush collection inserted data to disk.
milvus.flush([collection_name])# Get demo_collection row count
status, result = milvus.count_entities(collection_name)
print(result)
# present collection statistics info
_, info = milvus.get_collection_stats(collection_name)
print(info)
让我们搜索!
# execute vector similarity search
search_param = {
"nprobe": 16
}print("Searching ... ")param = {
'collection_name': collection_name,
'query_records': [vectors[0]],
'top_k': 10,
'params': search_param,
}status, results = milvus.search(**param)
if status.OK():
print(results)
else:
print("Search failed. ", status)
如果我们看到结果列表,这意味着一切都很好。我们可以用下面的代码片段将它们可视化
for neighbors in results:
for n in neighbors:
plt.figure()
plt.subplot(1, 2, 1)
plt.imshow(images[0])
plt.subplot(1, 2, 2)
plt.imshow(lookup[n.id])
print('Distance: {}'.format(n.distance))
要删除收藏:
milvus.drop_collection(collection_name)
结论
启动并运行起来非常容易。这里大部分与 Milvus 相关的代码来自网站上的入门示例。我们的一个向量大小约为 1KB,因此我们可以将一百万个特征向量放入 1GB 的内存中。我们在这里没有使用索引,这会增加成本,但这仍然是一种非常有效的图像索引方式。网站文档很棒,但是我认为通读配置文件是理解这个东西能做什么的好方法。在这篇文章中,我们把它保持得非常简单,但是对于那些想更进一步的人来说,这里有一些想法:
- 预处理特征向量。(即标准化)
- 尝试不同的层,如果它们不平坦,尝试最大池化或平均池化,然后平坦化
- 应用降维技术:tNSE、PCA、LDA
- 使用自动编码器进行预处理
这是我的第一篇文章。所以如果你喜欢,请告诉我。如果有什么不工作或格式被关闭,也让我知道!在外面保持优雅。
升级代码
从注册建筑师的角度看建筑规范符合性的未来:UpCodes Web & UpCodes AI
作为一名注册建筑师和数据科学家,我对通过数据科学和机器学习简化建筑实践中的工作流感兴趣。我作为一名建筑师已经工作了 4 年,我知道建筑师、工程师和承包商在建筑法规合规性方面面临的挫折。需要有一种更好的方法来设计符合规范的建筑——多亏了一家名为 UpCodes 的初创公司,这种方法确实存在。
什么是建筑规范?
简要概述— **建筑规范是确保建筑用户安全和无障碍的标准。**例如,建筑法规限制火灾时出口的距离,要求容纳更多人的房间有更多的门,并强制规定楼梯台阶的最大高度。
虽然建筑规范并不意味着抑制建筑师和设计师的创造力,但它往往会成为设计问题创造性解决方案的障碍。架构师经常会看到代码符合性的图表——并且只是想准确地提供所显示的内容以确保符合性。可以说,构建代码可能是一个令人沮丧和痛苦的需求,它经常抑制设计过程的创造性流动。
左图:符合美国残疾人协会指南的无障碍浴室的三维示意图。右图:剖面图显示了符合 ADA 指南的间隙和安装高度。来源。
我使用哪种建筑规范?
更复杂的是,强制执行的建筑法规在不同的司法管辖区可能会有所不同。不同的建筑规范可能会在地方一级或国家一级采用,这可能会变得非常混乱!有地图和其他文档显示各州的代码采用情况。
例如,在不涉及太多细节的情况下,佛罗里达州迈阿密的一栋新公寓楼与加利福尼亚州旧金山的同一栋楼相比,将有不同的建筑规范要求。在迈阿密——建筑规范坚持设计要求,以应对飓风和风暴潮的可能性,而在旧金山——建筑规范假定需要更坚固的建筑来抵御地震。
建筑规范因管辖范围和面临的独特挑战而异。左:佛罗里达。来源。右图:旧金山。出处。
我引用哪个代码段?
一旦我们弄清楚了管辖区使用的建筑规范,我们必须确保我们引用了规范的正确的部分。有不同的章节涉及建筑设计的各个方面。有关于占用,建筑高度&面积,建筑结构类型,出口,内部装修等章节。
因此,当我们设计建筑时,我们必须在物理代码簿(或者 PDF 文档,如果你幸运的话)的页面中搜寻,找到我们需要参考的正确部分,以确保合规性。仅 IBC 2018(一个通用的建筑标准)就有 726 页——这可能是你的项目必须遵守的许多建筑规范之一。所以你可能需要为你的项目引用成千上万的页面。
国际代码委员会(ICC)开发的代码集。他们是开发建筑规范的几个主要实体之一。有很多要记录的!来源。
作为一名建筑师,可能需要数年的时间来积累足够的经验和专业知识,以便对建筑规范足够熟悉,从而培养对符合规范的设计的敏感性。我注意到的是这样的:年轻的设计师通常不确定一个特定的设计决策是否符合代码,直到更高级的架构师检查他们的工作。这导致对设计安全和无障碍空间缺乏信心,不得不返工,而成功取决于对更年长、更有经验的员工的依赖。
一定有更好的方法…
所以现在你明白了构建代码的头痛之处,一定有更好的方法,对吗?自从计算机出现以来,科技公司彻底改变了建筑师设计建筑的方式。 Autodesk 改变了建筑师通过 AutoCAD 和 Revit 绘制图纸的方式。 Adobe 改变了建筑师通过 Photoshop、Illustrator 和 InDesign 制作图表、渲染和演示的方式。那么,技术如何解决建筑法规合规性的问题呢?
升级代码
输入: UpCodes 。这家初创公司利用数据和软件开发的力量为架构师创造了两种工具。第一个工具是UpCodes Web——这是一个搜索引擎,(想想谷歌)增强了机器学习和分析,唯一的目的是找到你需要的建筑代码,超级快。第二个工具是 UpCodes AI —这是 Revit 的一个插件,允许我们实时查看代码错误!这些工具有可能每年为 AEC 专业人员节省数千小时的辛苦时间。
UpCodes 网站
Upcodes Web 是一个查找建筑规范的一站式商店,而不是在多个代码簿、网站或 pdf 中查找。通过提供“项目输入”,如我们的建筑类型、建筑类型、喷水灭火系统和建筑占用等级,UpCodes 可以过滤以仅显示与我们的项目唯一相关的建筑代码。这有助于所有年龄段的架构师和工程师更快速、更自信地浏览代码。
通过提供“项目输入”,UpCodes 将与我们的项目无关的代码变灰,只突出显示我们关心的代码。资料来源:UpCodes
有时,司法管辖区会对通用建筑规范进行修改,如国际建筑规范(IBC)——UpCodes 帮助我们识别这些变化。UpCodes 随时更新 UpCodes 网络工具,更新我们管辖区最近可能实施的任何修订,因此我们始终关注最新的指南。
例如,通过选择“California”作为我们的辖区,我们可以快速突出显示并了解加州与典型基础建筑规范的独特差异,如 IBC。资料来源:UpCodes
在设计的早期阶段,建筑师需要确定支持建筑规模的建筑类型。一般来说,建筑物越大和/或越高,建筑系统就必须越坚固。存在与建筑面积、楼层数和建筑高度相关的限制,这些限制会随着建筑占用、建筑类型和其他因素的变化而变化。为了解决这个问题,UpCodes Web 工具有一个计算器功能,在提供您的“项目输入”后,允许我们检查我们没有超出允许的建筑面积、建筑高度或楼层数。
计算器功能一瞥。在提供我们的项目输入之后,一个绿色的“检查”意味着我们的项目是代码兼容的。红色的“X”表示我们不符合规范。资料来源:UpCodes
UpCodes Web 将代码研究变成了一项更友好、更有吸引力的社交活动!通过在 UpCodes Web 中创建一个项目,团队成员可以评论、标记和共享可能需要进一步审查或可能引发项目设计变更的代码摘录。我们可以边看建筑规范边聊建筑规范。
您可以在 UpCodes web 应用程序中与您的项目团队一起对代码摘录进行评论。资料来源:UpCodes
UpCodes AI
UpCodes AI 是 Autodesk Revit 的一个插件。对于那些使用 Revit 的人来说,你们是否有过这样的想法:
“如果 Revit 能告诉我这些(楼梯、走廊、门、ADA 卫生间等)是否符合规范,那就太好了。”
你猜怎么着:这正是 UpCodes AI 所做的!目前,该项目只关注构建代码的两个方面:egress 和 ADA。将来,有望支持更多的构建代码方面,使该工具更加全面和健壮。
**要使用该工具,您只需下载并安装插件,它就会与您现有的 Revit 模型集成,自动分析模型的构件和几何图形。该工具可以标记建筑规范错误,并按类别对其进行分类,无论是 ADA、浴室还是门。我们可以单击这些类别来突出显示模型中的单个问题。从这里开始,我们可以进行必要的设计更改以符合代码。这个工具有可能改变我们使用建筑规范的方式,集成到我们用来建模和记录建筑设计的主要软件中。我们不再需要等待更有经验的高级架构师(或者外部顾问)的代码审查。有了这个工具,每个人都可以随时检查他们的工作是否符合代码。 **UpCodes AI 允许我们在设计时检查我们的工作,而不是在设计之后。查看下面 UpCodes AI 的视频演示。
UpCodes AI 的视频演示。来源:UpCodes
当我们在 UpCodes AI 中查看问题时,该工具会显示与错误相关的特定代码信息。首先,它向我们简要概述了这个问题。第二,它将建筑规范中通常隐晦的语言解释成“外行人的术语”,以便每个人都能理解问题。第三,它提供了原始代码摘录以供参考,只需单击一下就可以带您到 UpCodes Web 应用程序,如果需要,可以查看更多的构建代码。最后,它列举了我们模型中的每一个代码违规实例——我们可以使用“Inspect”按钮直观地研究每一个违规。见下图。
UpCodes AI 如何引起我们对代码违规的注意。资料来源:UpCodes
随着时间的推移,UpCodes 会自动更新新功能。来自 UpCodes AI 用户的反馈决定了该工具如何开发和进化。他们优先考虑用户反馈中最受欢迎的请求。你可以在这里给升级代码 AI 更新日志留下反馈。
后续步骤
了解更多关于 UpCodes AI 工具如何在幕后工作,以及如何改进它将会很有趣。是否只是访问指导建模图元尺寸的 Revit 参数来确定合规性?
UpCodes AI 还能如何使用机器学习算法来预测问题区域?它可以使用自然语言处理来提取房间名称的含义,然后预测并分配这些房间的入住等级吗?还是必须依赖建筑师在 Revit 模型中手动输入的占用等级参数?这个工具可能有很多方法可以通过数据科学和机器学习/人工智能努力来改进。
来源:作者。
结论
UpCodes 试图以一种更加包容和用户友好的方式来打破建筑师设计建筑的方式。从本质上来说,建筑规范是建筑师和工程师必须遵守的规则的集合,以创造安全和无障碍的空间供人们使用。到目前为止,作为一个职业,我们总是在几个不同的资源中手动检查这些规则的合规性。
UpCodes Web 将建筑代码集中到一个 Web 应用程序中,并利用项目数据使代码合规性更容易、更直观。UpCodes AI 更进一步,允许我们在架构师习惯的软件环境中进行代码检查。建筑的未来取决于数据以及我们如何利用数据来更高效地设计我们的建筑环境。UpCodes 可能是这个未来的一大部分。
预测 NFL 几乎是不可能的…是吗?
采用新开发的色谱柱选择技术的综合测试系统
图片来源:perfectduluthday.com
作者:Matthew Littman 商业分析硕士
加州大学欧文分校
介绍
我以前的文章“超级碗预测模型”讨论了预测超级碗冠军的整个建模过程,重点是缺失值的数据插补方法。该过程如下:
- 从多个来源收集数据(3 个网站)
- 连接数据(1579 行,242 列)
- 清理数据
- 估算缺失值-通过链式方程进行多重估算(MICE)
- 对数据进行采样-对少数进行综合过采样(SMOTE)
- 选择重要列—递归特征消除(RFE)
- 拆分数据(80%培训,20%验证)
- 通过逻辑回归运行数据
- 当前年份(2019 年)的测试数据
利用 ROC 曲线,该前一种方法的曲线下面积为 95%。ROC 曲线是通过并列真阳性率(TP/P)和假阳性率(FP/N)来可视化不同分类模型之间的比较的标准方式。当对错是唯一重要的结果时,这种方法很有效。从 32 支球队的常规赛数据预测超级碗不是一件容易的事;因此,测试系统应该反映这种可变性,并为接近的预测加分,即使它们不是真阳性。结论是 ROC 曲线不是有效的测量工具。
正如我在上一篇文章中提到的,有一些地方我想深入研究,也就是第六到第九点。本文重点介绍了一个全新的健壮测试系统、两种列选择技术(随机森林和一种新颖的“RFE 循环”方法),以及一个附加的算法/模型(神经网络)。我之前的文章包括了本赛季前 13 周的数据,但随着常规赛的结束,这篇文章包括了我对 2019-2020 NFL 赛季超级碗冠军的最终预测。
数据源
提醒一下,图 1 显示了所使用的数据源。
**图一。**数据来源
清洁
每个团队的统计数据都是特定年份中与该团队相关的独立事件。这意味着,所有的计算或比较都是在按年份分组并进行范围标准化之后进行的,以便在该年的每个统计中清楚地对每个团队进行排名。
超级碗预测的改进测试系统
新的测试系统反映了每年预测的累积总数,以确保对“接近”但不一定正确的预测进行无偏见的评分和奖励。评分规则如表 1 所示。
**表 1。**评估/比较模型和技术变化的新评分系统
新系统计算包含超级碗的每一年的分数,最高年分数为 30 分。这一过程在所有年份都重复进行,在超级碗时代的 53 年中,最高得分为 1590。对于每一年,该年的数据用于测试,而其余的用于训练。
评分系统背后的基本原理是,“赢得会议的分数”和“输掉会议的分数”代表该模型是否能够准确预测超级碗的竞争者。预测正确的超级碗冠军赢得 10 分,以便测试系统支持超级碗冠军预测。有 12 支球队进入了季后赛,6 支来自亚足联,6 支来自 NFC。由于这种季后赛结构,任何球队的最大可行距离将是距离联盟第一名 5 个位置。如果一支球队超过了这个距离,这个模型将会预测这支球队没有进入季后赛,从而导致负分。
评分系统示例:
为了进一步理解评分系统,我将通过一个对 2018 年超级碗的预测进行评分的示例(出于说明目的,使用了假数字)。2018 年超级碗的获胜者是新英格兰爱国者队,而失败者是洛杉矶公羊队。图 2 给出了预测示例。
**图二。**示范 2018 赛季评分系统的预测示例。
在两场会议一起进行的预测中,爱国者队排名第二,公羊队排名第四。这两个队被分成各自的小组,因为最终,亚足联的冠军将对阵 NFC 的冠军。一旦分开,爱国者现在是第一,公羊是第二。
**表二。**示例年得分计算明细:2018 年
列选择技术
有了新的测试系统,我们尝试了几种色谱柱选择技术来改进模型。广泛使用的随机森林和新建立的“RFE 环”(下面详细描述)都被添加到测试方法列表中,该列表先前包括 RFE 方法和“初始列”。上一篇文章中的最初专栏是通过 RFE 和信息增益的结合发现的。
随机森林
随机森林算法可用于特征选择以及分类。决策树的思想是,所有的观察结果都可以根据对或错的陈述(例如,触地得分> 30)被任何属性分割。随机森林是决策树的组合(在我们的例子中是 1000 棵)。该算法随机选择一个色谱柱,然后使用杂质平均减少量(MDI)或基尼系数最大化分离 (Breiman 2001) 。“它被定义为在集合的所有树上平均的节点杂质的总减少量(由到达该节点的概率加权(由到达该节点的样本的比例近似))(李 2017) 。从本质上讲,该算法寻找最能分割数据的特征。
RFE 环线
利用递归特征消除方法,我开发了一种在数据集中选择重要列的新方法。RFE 从所有列中随机选择一个子集,并使用一个决策函数来决定该子集中的哪些列是最重要的列。它重复这个过程,直到剩下的列数等于用户指定的数目。
为了选择数据集的重要列,我开发了一种使用 RFE 的新方法,我称之为 RFE 循环。在 RFE 循环中,一个字典记录了被测试的每一年的重要列的数量。一旦所有年份都经过测试,字典就会被检查,计数最高的列(用户指定的列数)将被选为最重要的列。当与 K-fold 或 hold one out 测试方法配对时,这种技术工作得非常好,因为算法已经在重复运行。
伪代码:
**表 3。**RFE 循环算法的伪代码
建模
除了两种新的色谱柱选择技术之外,还使用 TensorFlow 的 Keras 构建了一个神经网络,尝试与逻辑回归模型竞争。神经网络通常适用于高维数据以及大量数值数据。我搜集的 NFL 数据集没有大量的数据(1579 个观察值),但它确实有很高的维数(137 列)。该模型使用不同数量的隐藏层和参数创建了多次:
**表 4。**用 Keras 建立的神经网络的参数
测试系统的结果
**图 3。**模型选择、数据插补和列选择方法的综合测试结果比较
如图 3 所示,技术/方法的最佳组合是逻辑回归,缺失值由先前的 MICE 计算文件处理,初始列在我的第一篇文章 Super Bowl 预测模型中。这种组合对于正确预测的超级碗的数量和总得分都是最好的。图 3 包括:
- 两种建模方法(逻辑回归和神经网络)
- 五种列选择技术(RFE 循环、RFE、随机森林、初始列和所有列)
- 三种数据插补方法(先前计算的 MICE 值、MICE 和平均值)
RFE 循环法的总分略低于初始列的总分。此外,初始列正确地预测了另外两个超级碗。基线模型是包含所有列和缺失值平均值的逻辑回归。当涉及到正确的超级碗预测时,该基线比其他一些组合稍好,但在总分上它输给了几乎所有其他模型。唯一的例外是包含所有列和先前计算的 MICE 值的神经网络。图 3 显示了模型的不同组合以及它们的表现,而图 4 根据总分对不同方法进行了分类。
**图四。**类别预测方法比较:模型选择、列选择、数据插补
图 4 阐明了相互比较时,每项技术对总分的贡献程度。对于模型选择,平均而言,逻辑回归得分比神经网络高约 2.7%。对于列选择,RFE 循环的性能比使用所有列时高 20%,比第二高的初始列方法高 3.3%,比仅使用 RFE 高 10.9%。随机森林技术的性能比普通 RFE 方法稍好。值得一提的是,RFE 方法每年大约需要 45 秒(总共 53 年),而随机森林方法每年大约需要 5 分钟。这点时间差,不值总分的些微增益。
继续进行数据插补,之前计算的 MICE 值比仅使用平均值高 6.2%。为了强调每个 MICE 计算之间的细微差异,先前计算的 MICE 值和新计算的 MICE 值之间的差异大约为 3%。这表明,如果不使用之前计算的值,结果可能会略有不同。
总的来说,考虑到所用的不同方法可能得到的总分范围很广,很明显色谱柱选择的影响最大。当谈到模型选择时,导致最终算法的步骤远比选择的“模型”重要。根据这个项目,建模过程的每个部分都会极大地影响预测能力的结果,但是最重要的部分是列的选择。由于 NFL 捕获的统计数据的数量,列选择很可能是建模过程中最重要的部分。辨别哪些统计数据最有意义的能力是这个项目的缩影。
通过 RFE 环技术选择的 20 根柱子如下表 5 所示。
**表 5。**根据 RFE 循环技术最重要的列
在所有 12 个模型都经过测试后,我很好奇是否有哪个年份的大多数模型预测正确。结果显示,12 个模型都预测正确的 6 年(1972 年、1979 年、1985 年、1991 年、1996 年和 2003 年)表现突出。
**图五。**显示每年正确预测超级碗的模型数量
1972 年:不败的迈阿密海豚队
1979 年:12-4 匹茨堡钢人队与圣地亚哥充电器队平了最佳记录
1985 年,芝加哥熊队以 15 比 1 领先(最佳记录)
1991 年:14-2 华盛顿红人队(最佳记录)
1996 年:13-3 绿湾包装工队,进攻得分比防守允许的得分多 37 次触地得分。第二高的是 49 岁的人,只有 18 人。
2003 年:14–2 名新英格兰爱国者(最佳记录)
记录显然对预测有很大的影响,因为有好记录的球队往往有其他好的统计数据。在选择了之前讨论过的最佳方法(逻辑回归、RFE 循环和之前计算的小鼠值)之后,整个测试过程的可视化可以在下面的图 6 中看到。
**图 6。**整体模型评估,显示模型对预测赢家的选择及其机会百分比(根据预测是否正确以红色/绿色显示),以及实际赢家和模型给予实际赢家的机会百分比(黑色)。
图 6 显示了所有年份的预测赢家、实际赢家和超级碗竞争者。这表明,即使模型是不正确的,它也可能只是预测超级碗的输家是赢家。例如,2015 年,卡罗莱纳黑豹队在超级碗比赛中对阵丹佛野马队。该模型预测了卡罗莱纳黑豹队,而实际的赢家是野马队。因此,虽然模型不正确,但它仍然预测了一支参加超级碗的球队。
结论
总之,新的测试系统允许以前不可能的模型比较。该系统允许在神经网络和以前的逻辑回归之间进行比较。此外,测试了两种新的列选择技术,其中“RFE 循环”获得了最佳平均总得分的第一名。图 7 中橙色部分显示了整个模型的变化。
**图 7。**对以前方法的流程变更进行建模。
使用这种改进的预测模型,截至分区赛,2019 年超级碗的预测赢家是旧金山 49 人队,胜率为 36%,如图 8 所示。
**图 8。**2019-2020 NFL 赛季超级碗预测,截至通配符回合
相关作品/参考文献
随机森林列选择
布雷曼,狮子座。2001.“机器学习。”https://doi.org/10.1023/a:1010933404324。
李,瑟辛。2017.“树木模型的特征重要性测量—第一部分”中等。名副其实。2017 年 10 月 28 日。https://medium . com/the-artificial-impostor/feature-importance-measures-for-tree-models-part-I-47f 187 C1 a2 C3。
Github
一个全自动的模型版本发布在我在 https://github.com/kelandrin/Superbowl-Prediction-Model/的 Github 上
请随意下载并体验不同的功能!
只要确保下载了适当的包(列在主文件的顶部),然后运行主文件,你就可以开始了!
可能的网络应用即将推出!
使用 Python API 更新 Quip 电子表格
什么是妙语,你为什么要在意?
Quip 是一个用于移动和网络的协作生产力软件套件。它允许多组人员作为一个组来创建和编辑文档和电子表格,通常用于商业目的。(维基百科)
Quip 和 Google Docs/Sheets 的一个主要区别是 Quip 有一个原生的桌面应用程序。
Quip 电子表格截图(Lynn Zheng)
在这篇文章中,我将向您展示如何使用其 Python API 客户端来自动化创建、插入和更新 Quip 电子表格的过程。为了增强 API 的功能,我对它的官方 GitHub 库做了一个分支,并加入了一些有用的 pull 请求,这些请求还没有合并到主分支中。从我的库下载quip.py
继续本教程。
Quip API 基础
官方 API 文档位于本网站。您将需要一个访问令牌来与 Quip 的 API 进行交互。访问页面https://quip.com/dev/token生成个人访问令牌。
要打开 Python 客户端:
import quip
ACCESS_TOKEN = "" # your access token
client = quip.QuipClient(access_token=ACCESS_TOKEN)
Quip API 的一个基本实体是线程。
Quip 将文档和消息集成到一个单元中,我们称之为线程。Quip Automation API 中的大多数操作都是在线程上进行的。线索可以简单地是消息列表,即聊天线索,或者除了消息列表之外,它们还可以具有文档。(装备 API 文件
在 Quip 中创建电子表格
向new_document
传递一个空字符串作为第一个参数,告诉 Quip 使用它的默认 HTML 模板。
jso = client.new_document("", title="My Spreadsheet", type="spreadsheet")
您还可以指定一个 HTML 字符串作为第二个代码段中的模板。如下创建一个名为template.html的文件。这个电子表格模板只包含两列。
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>with open("template.html", "rt") as f:
template = f.read()
jso = client.new_document(template, title="My Spreadsheet", type="spreadsheet")
抓住thread_id
发来的服务器响应。我们将需要它作为我们创建的电子表格的参考,以插入/更新记录。
thread_id = jso["thread"]["id"]
让我们将标题(默认为 A 和 B)更新为更具描述性的内容。
client.update_spreadsheet_headers(thread_id, "Name", "Email")
检查标题设置是否正确:
spreadsheet = client.get_first_spreadsheet(thread_id)
headers = client.get_spreadsheet_header_items(spreadsheet)
print(headers) # prints ['Name', 'Email']
按标题检索电子表格
title = "My Spreadsheet"
jso = client.get_matching_threads(title, only_match_titles=True)
# get the id of the first thread
thread_id = jso[0]["thread"]["id"]
将记录插入电子表格
client.add_to_spreadsheet(thread_id, ["John Doe", "jdoe@gmail.com"])
client.add_to_spreadsheet(thread_id, ["Jane Doe", "jane@gmail.com"])
更新电子表格中的记录
假设简将她的电子邮件地址更新为 jd12@gmail.com,让我们更新电子表格来反映这一变化。
client.update_spreadsheet_row(thread_id, "Name", "Jane Doe", {"Email": "jd12@gmail.com"})
一个警告:Quip 的 API 实现了严格的速率限制,默认为每分钟 50 个请求,这意味着每分钟最多只能插入/更新 50 条记录。在文档中阅读更多关于自定义标题X-Ratelimit-Limit
的信息。
与您组织中的其他 Quip 用户共享电子表格
假设您想与电子邮件地址为 smith@gmail.com 的同事共享该电子表格。
email = "smith@gmail.com"
jso = client.get_user(email)
member_id = jso["id"]
client.add_thread_members(thread_id, [member_id])
这些是 Quip 的电子表格 API 的基础。感谢阅读!
更新 BigQuery 中的已分区表
BigQuery 已经取得了很大的进步,但是一些重要的方面(比如通配符搜索)仍然缺少一些在 SQLServer 中相对简单的功能。其中一个功能是更新分区表的能力。更新一个分区很容易,但是,如果您有 100 个分区,单独更新它们会很麻烦。
下面是一个更系统化的尝试。请记住你的 GCP 成本,因为这可能不是最具成本效益的方式。如果您确实找到了更高效或更经济的方法,请将您的解决方案添加到回复部分。
为了更新一个分区表,我们将首先创建一个包含所有需要更新的分区的表,然后为每个分区创建一个 update 语句。最后,我们将遍历每个 update 语句来完成更新。
create table `myResource.Dataset.tablePartitions` AS
with parts as (
select distinct _table_suffix as dates from `myResource.Dataset.prefix_*`
)
select
concat('update ','`myResource.Dataset.prefix_',dates,'` set columnUpdate = "abc" where columnB = "xyz"') as tab
,row_number() Over() as rn
from parts;
要创建一个表,只需查询您要分区的表的每个不同分区。本例中为 Dataset.prefix_* 。表分区,或 *myResource。Dataset.tablePartitions,*是一个新表,将被创建和引用以创建 update 语句。如果不需要保存每个分区的记录,也可以在这里创建一个临时表。如果您选择这样做,请确保一次性运行上面和下面的代码。
declare num_partitions int64;
declare query string;
set num_partitions = (select count(distinct _table_suffix) from `myResource.Dataset.prefix_*`);while num_partitions > 0 Do
set query = (select tab from `myResource.Dataset.tablePartitions` where rn = num_partitions);
Execute Immediate query;
set num_partitions = num_partitions-1;
END While;
后一部分将引用在步骤 1 中创建的 update 语句,并遍历它们。根据分区的大小、GCP 成本结构和分区的数量,您可能希望分批完成工作,而不是像这里一样遍历每个分区。要批量执行,调整 num_partitions 变量和 while 语句条件。
这是一个快速的解决方案,可以改进。如果你发现了一种更新 BQ 中的分区表的更好的方法,我很想听听。希望这是有帮助的,并为您节省一些时间。
使用 Python 更新 Github 存储库
使用 GitPython 自动从远程目录中提取
照片由 Richy Great 在 Unsplash 上拍摄
我每天至少运行两次以下命令:
>>>git fetch upstream master
>>>git merge upstream/master -m 'Here we go again...again'
>>>git push
每次 10 个单词,在我为期 15 周的训练营中每天跑两次,总共 1500 个单词。客观地说,这相当于我为你写的三篇高质量的博客。真的,必须做点什么。
GitPython
Git python 创建了一个 repo 对象,它允许你与你自己的库或者你的代码所依赖的公共库进行交互。
安装
>>>pip3 install GitPython
安装过程会仔细检查库的依赖关系。但是,您应该将您的用户名和密码添加到您的 git 配置中。
设置
您可以简单地将下面两个代码片段中的任何一个放在脚本的顶部,以编程方式更新您的本地存储库。
如果您想从远程源更新您的代码本地存储库,代码很简单:
但是,如果您想从远程上游存储库进行更新,代码会稍有不同:
申请
我以前的文章概述了如何使用 python 制作一个命令行工具。让我们使用该教程来构建一个“自动更新程序”。
>>>mv autoupdate.py autoupdate
>>>chmod +x autoupdate
>>>cp autoupdate ~/.local/bin/autoupdate
>>>source ~/.zshrc
>>>autoupdate
就这样,简单多了!新讲座?没问题。《纽约时报》更新了他们的知识库?我的地图会在下次打印时更新。
编码快乐!
升级您的 Nvidia GPU 驱动程序以获得更好的性能🚀
你的训练不稳定?考虑将 Cuda 升级到最新版本
我有一个运行在 Ubuntu 16.04 发行版和 Nvidia 1080 TI 上的 GPU 服务器。2018 年买的,到今天还在用 Cuda 9.0,驱动版本 384.130。
我的设置
我决定升级到 Cuda 10.2,用最新版本的驱动(440.33.01)。出于几个原因,我很早就想这么做了:
- 我偶尔会注意到我当前设置的不稳定训练和 GPU 故障
- 一些最新版本的通用深度学习框架(主要是 PyTorch)只能在 Cuda 10+上运行
所以这是做这件事的最佳时机。我在这篇文章中记录了不同的步骤。我们走吧!
- 头顶https://developer.nvidia.com/cuda-downloads
- 选择您的
-操作系统(Linux)
-架构(x86_64)
-发行版(Ubuntu)
-版本(16.04)
-安装程序类型(runfile (local)) - 一旦您选择了元素,您将会得到以下两个命令的提示。处决他们
**wget** [**http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_440.33.01_linux.run**](http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_440.33.01_linux.run)**sudo sh cuda_10.2.89_440.33.01_linux.run**
4.重启你的机器
**sudo reboot now**
你现在应该没事了。但是,如果您在运行nvidia-smi
时遇到此错误消息
未能初始化 NVML:驱动程序/库版本不匹配
这意味着您以前的驱动程序太旧,无法被**cuda_10.2.89_440.33.01_linux.run**
脚本检测和删除。
这就是为什么你需要清除 Nvidia 旧的依赖:
**sudo apt-get update
sudo apt-get --purge remove cuda
sudo apt-get autoremove
dpkg --list |grep "^rc" | cut -d " " -f 3 | xargs sudo dpkg --purge
sudo apt-get purge nvidia*
sudo apt-get update
sudo reboot now**
5.创建指向 Cuda 最新版本的符号链接
**sudo ln -s /usr/local/cuda-10.2 /usr/local/cuda**
6.更新您的。bashrc
旧行: 导出路径=/usr/local/cuda-9.0/bin:$ PATH
导出 LD _ LIBRARY _ PATH =/usr/local/cuda-9.0/lib 64:$ LD _ LIBRARY _ PATH
新行: 导出路径=/usr/local/cuda/bin: P A T H 导出 L D L I B R A R Y P A T H = / u s r / l o c a l / c u d a / l i b 64 : PATH 导出 LD _ LIBRARY _ PATH =/usr/local/cuda/lib 64: PATH导出LDLIBRARYPATH=/usr/local/cuda/lib64: LD _ LIBRARY _ PATH
然后重启以保存更改。
7.安装 Cudnn
在这里创建一个 Nvidia 开发者账号。然后,点开这个链接,下载 Cudnn。
下载该文件后,运行以下命令:
**sudo cp cuda/include/cudnn.h /usr/local/cuda/include** **sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64** **sudo chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn***
8.检查您的安装
我用支持 Cuda 10.2 的最新 PyTorch 版本创建了一个新的 conda 环境。安装后,我运行以下命令:
**import torch****torch.cuda.is_available()
# True****torch.version.cuda
# '10.2'****torch.backends.cudnn.version()
# 7605**
但是您也可以使用您最喜欢的框架进行检查。
感谢阅读,我希望这是有用的!
干杯!
升级 Python 列表
向 Python 列表添加有用的功能
图片来源:JoeyBLS 摄影
介绍
Python 列表很好。但他们并不伟大。有如此多的功能,可以很容易地添加到他们,但仍然缺乏。用布尔进行索引,轻松地用它们创建字典,一次追加多个元素,等等。嗯,不再是了。
Fastai 已经拿出了自己的数据结构叫做L
。它能做 Python 列表能做的一切,甚至更多。
本文的目的是向您展示自己编写这样有用的功能是多么容易。尤其是如果你是一个初学者,试着创建一个迷你版本的库。试着写一些你希望存在的功能。这将是一次很好的学习经历。
现在,让我们来了解一下 L 。这是 Colab 的链接。在您的 Colab ( 文件- >驱动器中保存一份副本)上制作一份副本,并且只运行第一个单元格一次。你的笔记本会崩溃。但是你马上就可以使用图书馆了。
我是什么?
就像我之前提到的,它类似于 Python 列表,但是可以实现更多。让我们从导入库并创建L.
的实例开始
我们看到它打印了列表的长度,然后是内容。再也不用一直单独打印长度了。
如果你和我一样,不喜欢用方括号。移除它们。
编写.append()
来追加元素又是如此乏味。此外,一次只能追加一个元素。咩。移除移除。
请注意,这些东西非常容易编码。我们只是在幕后定义了一个__add__
魔法方法来决定+
操作员将做什么。如果你想学习更多关于魔法方法的知识,你可以阅读我的文章如何在 Python 中熟练使用 OOP。
我们来考察一下__add__
的方法。
它用当前元素和新元素创建 L 的新实例。很简单,对吧?
我们也试试__mul__
吧。
它将列表复制两次。另外,请注意,它只打印前 10 个元素,然后显示...
这比显示所有元素的 Python 列表要干净得多。
你可以在 l 中找到独特的元素。
你可以很容易地把它转换成一本字典。
然而,L 的真正强大之处在于它的索引功能。
- 使用索引列表进行索引
2.使用布尔进行索引
3.多重赋值
4.处理无问题的连接
很多时候,我们用 Python 返回一系列列表。我们需要 if 语句来检查其中是否有一个是空的,否则它们会抛出一个错误。不是和 l。
结论:
总而言之,这是一个很好的数据结构,可以很容易地用来代替列表。试试笔记本。探索它。这就是本文的全部内容。
~快乐学习
参考资料:
https://github . com/fastai/fastai _ dev/blob/master/dev/01 _ core _ foundation . ipynb
直接从终端上传文件到 Google Drive(使用 Curl)
将数据从计算机推送到云的另一种方法。
在许多情况下,从一台新机器向另一台机器发送数据可能很困难。这方面的例子包括隐藏在登录门户后面但不允许 ssh 隧道的 HPC 设施,或者只安装了几个核心程序的简单无头机器。在本文中,我们将使用 cURL(一个用于传输数据的命令行程序)将一个压缩文件(包含日志文件)推送到我们的 google drive 帐户上,以便进行进一步的分析。
照片由 Element5 数码在 Unsplash 上拍摄
装置
大多数机器都会安装 cURL(试着输入which curl
)。如果不是这样,我们可以安装它
sudo apt install curl # Linux Debian/Ubuntu
或者
brew install curl # Mac
现在我们已经安装了它,我们可以看看如何创建发送文件所需的凭证。
创建您的项目凭据
由于我们允许访问我们的谷歌驱动器,我们希望能够管理这一点。这是通过创建一个具有用户定义权限的项目来实现的,该项目充当我们的用户(在本例中,我们在不同的机器上)和我们的帐户之间的代理。我们首先转到下面的页面(下面的链接)并创建一个新项目。
Google 云平台让您可以在同一基础设施上构建、部署和扩展应用程序、网站和服务…
console.developers.google.com](https://console.developers.google.com/apis/credentials?pli=1)
完成后,我们选择“凭据”选项卡(在左侧),然后从顶部选择“创建凭据”。
当询问应用程序类型时,我们选择电视和其他。
最后,这会生成一个client id
和一个client seacret
。
这是您的用户名和密码,请将其复制到安全的地方。
现在我们需要验证设备
为此,我们ssh
进入我们希望上传的机器,并运行以下命令:
curl -d "client_id=**<client_id>**&scope=https://www.googleapis.com/auth/drive.file" https://oauth2.googleapis.com/device/code
这样,我们会得到以下格式的响应
{"**device_code**": "<long string>",
"**user_code**": "xxx-xxx-xxx",
"expires_in": 1800,
"interval": 5,
"**verification_url**": "https://www.google.com/device"}
这里我们需要访问 URL(https://www.google.com/device)并提供用户代码来完成我们的验证。我们现在继续选择我们的 google 帐户并授予相关权限。进行此操作时,确保记下设备代码用于下一步。
获取不记名代码
当我们开始上传时,这是我们需要用来识别我们的帐户的代码。我们通过使用以下内容获得它:
curl -d client_id=**<client id>** -d client_secret=**<client secret>** -d device_code=**<device code>** -d grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code https://accounts.google.com/o/oauth2/token
客户端 id 和密码保存在第一步中,设备代码保存在上一节中。输出应采用以下格式:
{
"access_token": ".....",
"expires_in": 3599,
"refresh_token": "....",
"scope": "https://www.googleapis.com/auth/drive.file",
"token_type": "Bearer"
}
记下访问令牌,因为上传阶段会用到它。
上传文件
下面给出了我们用来上传文件的命令
curl -X POST -L \
-H "Authorization: Bearer **<enter** **access token here****>**" \
-F "metadata={name :'**<our.zip>'**};type=application/json;charset=UTF-8" \
-F "file=@**<our.zip>**;type=application/zip" \
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart"
在允许上传数据之前,您可能需要启用应用程序 API。如果是这种情况,错误消息中会给出执行此操作的链接。
这里的多部分文件预计只有几 MB 大小。然而,如果你正在考虑移动更大的文件可恢复的可能更适合(见https://developers.google.com/drive/api/v3/manage-uploads
用一个脚本把它包起来
现在我们知道我们的命令工作,我们可以创建一个可执行脚本来为我们做所有的工作。在这里,我们可以提供一组文件,它将它们压缩,然后发送到 google drive。
我们首先用nano curlgoogle;
创建一个新文件,并输入以下代码——记得添加您自己的个人身份验证令牌!选择 Python 2.7 是因为这仍然是旧系统上的默认 Python 版本,但是下面的脚本也应该适用于 python 3。
如果 curl 已经存在于系统中,它应该不需要新的依赖关系。
#!/usr/bin/python'''
A quick python script to automate curl->googledrive interfacing
This should require nothing more than the system python version and curl. Written for python2.7 (with 3 in mind).Dan Ellis 2020
'''import os,sys,jsonif sys.version[0]=='3':
raw_input = lambda(x): input(x)##############################
#Owner information goes here!#
##############################
name = 'curldata'
client_id= '**<enter your client id>**'
client_secret='**<enter your client secret>**'############################## cmd1 = json.loads(os.popen('curl -d "client_id=%s&scope=[https://www.googleapis.com/auth/drive.file](https://www.googleapis.com/auth/drive.file)" https://oauth2.googleapis.com/device/code'%client_id).read())str(raw_input('\n Enter %(user_code)s\n\n at %(verification_url)s \n\n Then hit Enter to continue.'%cmd1))str(raw_input('(twice)'))cmd2 = json.loads(os.popen(('curl -d client_id=%s -d client_secret=%s -d device_code=%s -d grant_type=urn~~3Aietf~~3Aparams~~3Aoauth~~3Agrant-type~~3Adevice_code https://accounts.google.com/o/oauth2/token'%(client_id,client_secret,cmd1['device_code'])).replace('~~','%')).read())
print(cmd2)# zip files
cmd3 = os.popen('zip -r %s.zip %s'%(name,' '.join(sys.argv[1:]))).read
print(cmd3)cmd4 = os.popen('''
curl -X POST -L \
-H "Authorization: Bearer %s" \
-F "metadata={name :\'%s\'};type=application/json;charset=UTF-8" \
-F "file=@%s.zip;type=application/zip" \
"[https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart](https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart)"
'''%(cmd2["access_token"],name,name)).read()print(cmd4)
print('end')
然后我们使它可执行chmod a+x curlgoogle
,允许我们以可执行的方式使用它:
**./curlgoogle** file1 file2.txt file3.jpg etc...
结论
现在我们有了一个简单的方法,可以将多个日志文件从一台无头机器发送到一个 google drive 存储库中,供多人访问以进行分析。
如果你需要更多的信息,由 Tanaike 和 HAKS (以及其他人)提供的堆栈溢出回答对创建这篇文章特别有帮助。
SARS-新冠肺炎感染人数的上限和检验偏差
我看着新冠肺炎
估计目前该疾病在各国传播的最大可能程度
在之前的一篇文章中,我提出了不同国家可能被当前的 SARS-新冠肺炎疫情感染的人数的上限和下限——无论他们是否表现出症状——以及提供一个接近实际数字的中心估计值。总的来说,这些界限和核心估计数表明,该疾病并没有像一些人声称的那样广泛传播,而且所有国家离群体免疫的可能性还很远。我在那篇文章中的结论和主要观点已经被最近发表的几项研究所证实。然而,我的朋友兼语言学家同事博班·阿尔塞尼耶维奇在对那篇文章的私人回复中注意到我的上限有一个错误。在这篇文章中,我进一步完善了疾病传播的上限,以回应博班的批评。我表明,尽管有这个错误,前一篇文章的主要结论仍然成立,甚至得到了最近数据的支持。在这里,我还考虑了额外的重要细节,比如测试的准确性,为了简单起见,在之前的帖子中有意忽略了这些细节。使用这些新的改进,我使用更近的数据提供了更精细的疫情扩散范围,并且我研究了这些告诉我们不同国家遵循的测试政策。
更可靠的上限
人们在有限的时间内测试呈阳性
在我的上一篇文章中,我使用了人群中检测结果呈阳性的比例——阳性检测率*——作为感染该疾病人数的上限——终生患病率。这种关系成立的原因是*检测偏差:当已经有迹象表明他们可能已经被感染时,人们更有可能接受检测,无论是通过明确的症状,还是通过与其他已知被感染的人的密切接触。由于这个原因,在任何一天,被检测者中的阳性比例都会高于普通人群。
上述关系在任何一天都成立,但是——正如博班·阿塞尼耶维奇友好地向我指出的——它不需要在更长的时间内成立。问题是,人们从感染中康复后,只能在一定时间内保持检测阳性。例如,如果我们有一百个人,在五天的时间里,我们每天测试其中的十个人,每天获得两个阳性结果,我们可以推断在任何一天,被感染的人不超过百分之二十,这是正确的。然而,如果我们假设在第一天测试为阳性的人在第五天也测试为阳性,那么这一估计只能延伸到整个五天。如果不是这种情况,我们就需要把在非重叠日感染的人口比例加起来。请注意,这个问题的解决方案并不像将不同日期的积极因素相加那么简单。如果我们这样做的话,我们将会把一些受感染的人计算几次,直到他们检测呈阳性。简而言之,如果人们在很长一段时间内测试呈阳性,那么我上一篇文章的上限或多或少是正确的。然而,如果人们在更短的时间内测试呈阳性,我会严重低估上限。
为了解决这个问题,我们需要知道人们在被感染后,甚至在康复后,多久会继续检测为阳性。在最近发表的一项研究中,杜和他的同事们调查了人们在 SARS-新冠肺炎检测中呈阳性的时间长度。他们发现,这一持续时间取决于某人被感染的病毒载量(即初始感染的严重程度),以及患者的年龄(老年人比年轻人保持阳性的时间更长)。在他们研究的 161 人中,他们发现一名患者在被感染 50 天后仍呈阳性。更普遍的是,他们发现 25%的人在不到 17 天内保持阳性,50%的人在最多 21 天内测试呈阳性,75%的人在 28 天或更短时间内测试呈阳性(在技术术语中,这三个数字被称为分布的四分位数)。
图 1:在确认患有该疾病后,CoV-19 检测为阴性的概率。使用杜等人(2020)报告的四分位数(由图中的点表示)拟合到威布尔分布(参数 k=2.88,λ=25.68)。
杜等人报告的数字很好地符合威布尔概率分布(绘制在图 1 之外)。这是一个两参数的等待时间分布,通常用于可靠性分析(例如,估计设备故障前的预期时间)和生存分析(例如,估计治疗对病人预期未来寿命的影响)。有趣的是,拟合分布的形状参数反映了统计学术语中所谓的“老化过程”( k > 1 ):在我们的情况下,这意味着一个人测试阳性的时间越长,我们就越不可能发现这个人测试阳性的时间更长;换句话说,检测阴性的概率随着时间的推移而增加。
如何累积阳性检测率
在一段时间内累计阳性检测率的关键在于,每天只累加与前一天已经检测为阳性且仍为阳性的那部分人群不对应的阳性检测。换句话说,每天只有的新阳性应该被累加。累积一段时间内的新阳性结果将为我们提供一个真实的患病率上限。实际上,这意味着重复应用图 1 中的曲线:在疫情的第一天,我们增加了整个阳性检测率。在接下来的几天里,我们只累计前一天低于图 1 曲线的阳性检测率案例部分。这种累积过程避免了遗漏那些过去测试为阳性,但此后变成阴性的患者,并且通过重复应用曲线来确保不重叠防止了对那些仍然为阳性的患者进行两次计数。我将这一措施称为部分累积阳性检测率。
请注意,上面概述的累积过程需要足够详细的每日测试数据,而我在上一篇文章中使用的度量可以仅使用累积的测试数量和相应的累积案例来计算。不幸的是,对于不报告每日进行的检测数量,而是报告多日累计批次的国家,如德国(目前报告了 8 个批次)或西班牙(目前报告了 4 个批次),这使得很难获得可靠的上限估计值。
没有测试是完美的:敏感性和特异性
需要考虑的另一个因素是,尽管测试可能很准确,但没有一个测试是完美的。CoV-2 测试有多个提供者,所提供的不同测试在多个属性上有所不同。根据约翰·霍普金斯大学彭博公共卫生学院的一份报告,在不同的测试中,现有测试的 T2 敏感度,即“真实阳性率”,即测试呈阳性的感染者的比例,在 87%到 93%之间。同一消息来源称,测试的特异性——即“真实阴性率”,即未被感染的人测试呈阴性的概率——在 95%到 100%之间。尽管这些数字看起来很高,但事实上它们可以改变测试结果。例如,假设我们测试了 100 个人,我们得到了 80 个肯定的结果。我们可能会得出结论,有 80 人被感染,20 人未被感染。然而,如果我们把自己放在测试准确性最差的情况下——87%的灵敏度和 95%的特异性——我们实际上应该预期:
- 在测试呈阳性的 80 人中,79.57 人实际上对应于被感染的人(即真阳性)。剩余的 0.43 人预计是假阳性——由于测试的局限性,未感染的人测试为阳性。
- 在测试为阴性的 20 人中,只有 8.11 人对应于未被感染的人(即真阴性)。剩下的 11.89 人极有可能是假阴性——测试未能检测到的感染者。
考虑检测灵敏度和特异性,对阳性检测率进行校正。
考虑到上述情况,在阳性检测率为 80%的情况下,测试的灵敏度和特异性告诉我们,我们应该预计 79.57+11.89=91.46%的人被感染,8.11+0.43=8.54%的人未被感染。换句话说,如果我们直接使用测试数据,我们的估计会有超过百分之十的误差。即使我们不容易知道谁是假阳性或假阴性,我们也可以合理确定地知道有多少错误归因。一般来说,你可以用旁边的公式直接修正正比率。
不同国家的上限
修正的上限
图 2:一些代表性国家的每日阳性检测率、累计阳性检测率(我在上一篇文章中使用的上限)和此处建议的校正估计最大流行率的比较。
我使用了从数据中的我们的世界获得的检测数据来计算新的上限测量,结合了部分累积法和上述检测准确度校正(假设最差精度情况为 87%的灵敏度和 95%的特异性),适用于所有报告了一系列至少 45 天的每日阳性检测率的国家。
图 2 显示了部分累积的度量如何随着时间的推移产生恒定的累积。最重要的是,将其与累积阳性检测率(我在上一篇文章中提出的患病率上限)进行比较,后一种方法在该疾病在一个国家最流行的时候达到峰值,此后持续下降。这种下降反映了累积阳性检测率未能解释许多已解决的疾病病例,即,我们不应指望终生患病率指标会下降。相比之下,新的上限指标的表现与人们预期的一样:它快速增长,直到疾病达到峰值,然后稳定下来,进入较慢的增长。唯一的下降(使用七天运行平均值衰减)出现在每日测试速率的噪音振荡中。
图 3:至少 45 天的每日测试序列可用的国家的计算上限(红色三角形)。蓝色和黄色圆点分别表示情景 1 和情景 2 中提出的偏差的结果。
图 3(上图)中的红色三角形显示了超过 45 天的每日测试结果可用的国家的计算上限。只有三个国家——按降序排列为英国、塞内加尔、巴拿马和比利时——的 SARS-新冠肺炎终生患病率可能超过 60%,绝大多数国家远低于 30%。然而,正如我下面所讨论的,上限实际上是非常宽松的。一旦将测试偏差考虑在内,这些数字会大幅降低。
缺少日常测试数据时回归上限
图 4:逻辑回归预测中位数累积阳性率的上限。使用红点拟合回归,并用于预测蓝点。
不幸的是,许多国家没有报告每日测试数据,例如西班牙或德国,而其他国家只是在最近才开始提供这种每日报告,以便能够在一定程度上可靠地重建上限,例如智利或法国。然而,我们仍然可以根据其与累积阳性检测率的相关性来估算这些国家的上限。图 4(除此之外)绘制了累积率中值与那些有足够数据的国家(红点)的上限度量之间的关系。这里要注意是,使用平均值累积速率*,回归会更加准确。*然而,我使用了中间值,因为它对于数据点很少的国家更稳健(如西班牙只有四批数据)。我使用虚线绘制的回归线来插入其余国家的上限值(图 4 中的蓝点)。请注意,与我在的上一篇文章中使用的外推法相比,这仍然是回归训练范围内的插值,因此更加可靠。
图 5。回归-对于至少 45 天的每日测试序列可用的国家,插值上限(红色三角形)。蓝色和黄色圆点分别表示情景 1 和情景 2 中提出的偏差的结果。
图 5 中的红点标出了那些无法直接计算的国家通过回归插值得出的上限。和以前一样,在绝对最坏的情况下,只有三个国家(伊朗、西班牙和荷兰)的患病率可能超过 50%,而绝大多数国家的患病率远低于 30%。
缩小界限
偏倚和患病率之间的数学关系
现在,我将简短地——但也是必要地——谈谈数学符号,因为这对于理清测试偏差与流行度指标之间的关系至关重要。
根据概率论,我们可以将测试偏差定义为测试感染了疾病的人的概率与测试未感染的人的概率之间的比率。理想情况下,当两个方向都不存在实际偏差时,偏差的测量值应该正好为零,也就是说,感染者和非感染者接受检测的可能性完全相同。这是通过以对数标度定义等式 1(上面)中的测量值 B 来实现的。等式 2 是通过应用贝叶斯定理(概率的基本规则之一)从等式 1 得出的,该定理指出,对于任何事件 A 和 B ,它们的条件概率与*P(A | B)= P(B | A)×P(A)/P(B)*相关,并且抵消了所得的 P( 测试 ) 项。最后,应用概率的另一个基本规则——P(不是 A)= 1-P(A)——我们得出了至关重要的等式 3。这最后一个等式确定了——对于给定的一天——偏差是上限的对数比值比(即,博彩赔率)和真实患病率之间的差异。
[……]等式 3[……]必然意味着每日阳性检测率是每日流行率的严格上限
BB的正值代表偏向于检测患病人群,这是所有国家都存在的情况。正如我在之前的帖子中所讨论的,所有人都自然而然地优先检测有暴露于病毒迹象的人(例如参见美国疾病控制中心关于新冠肺炎检测的标准)。因此,我们可以相当肯定地说,对所有国家来说。请注意,相反的情况意味着非感染者比感染者更有可能接受检测,这在任何可能的情况下都没有意义——除非检测机构有意避免找到 SARS-CoVID 病例,这多少有些令人惊讶。
反过来,根据等式 3,这必然意味着每日阳性检测率是每日患病率的严格上限。通过将阳性检测率项替换为上述部分累积的阳性检测率,以及感染终生流行率的日流行率,等式 3 可以扩展到比特定一天更长的时间段。
“基于统计的常识”
从上面的等式 3 中,我们还可以推断出真实患病率的对数优势比正好是上限减去偏差。因此,为了限制真实患病率,限制偏差值 B 就足够了。我们可以将现有的数据与一些常识性的假设结合起来——我称之为基于统计的常识——以更好地了解各国的流行情况。
首先,现在众所周知的是,大部分感染 CoV-2 的人从未出现任何明显的症状,尽管这些无症状患者的确切比例仍在调查中(参见此处的了解不同研究报告的不同比例的概述)。据报道,无症状感染的最高比例约为 70%(来自对意大利北部 Vo '的 3000 名居民的测试)。
现在假设 60%的人口——专家估计达到群体免疫所需的最低水平——在某个时候已经被 CoV-2 感染。在评估患病率的最坏情况下,让我们假设只有 30%的感染者表现出任何症状——就像 Vo '的情况一样。我有意将这个非常高的无症状百分比作为偏倚的下限(因此也是患病率的上限)。采用任何较低的无症状百分比都会导致更大的测试偏差。要达到 60%,我们需要观察患病率的上限值是多少?
让我们假设两种可能的情况:
- 情景 1 :假设每 20 个没有真正感染 CoV-2 的人中就有一个显示出被感染的迹象——或者是通过与 SARS-新冠肺炎一致的症状,或者是通过与已知感染者的密切接触。与大多数国家正在做的事情相似,我们选择只检测表现出疾病症状的人。因此,我们有 P( 测试|感染 )= 30%和 P( 测试|未感染 )= 5%。这意味着感染者接受检测的可能性是未感染者的六倍。然后,根据等式 1,我们的偏差将是 B = log .3 /.05 = 1.79,这反映出感染者接受检测的可能性是非感染者的六倍。我们可以使用测试偏倚的值来查看真实的终生患病率为 60%时需要的上限值。从等式 3 我们知道上限的对数比值比等于真实患病率的对数比值比加上偏差值:log .6 / .4 + 1.79 = 2.2。将对数优势比转换为简单的概率值,这意味着要获得 60%或更高的真实患病率,需要找到 90%以上的上限。
- 情景 2 :在实践中,许多国家不仅仅要求测试症状或 CoV-2 暴露的迹象;他们实际上将测试限制在那些有严重症状需要住院治疗的人,或者属于非常特殊的关键或高风险人群(例如,医务人员、老年人……)。例如,许多国家都有报告称,即使人们表现出明显的非典-新冠肺炎症状,他们也很难接受检测。在这种情况下,情景 1 中描述的偏差实际上是一个很大的低估。我们可以预期测试偏差会大得多。本着这种精神,如果我们假设一个受感染的人比一个未受感染的人被检测的可能性高 20 倍,我们将得到 B= 3.00。重复上面的计算,在这种情况下,60%的真实患病率需要观察不小于 97%的上限值。
图 6:在两种偏倚情况下,可能的估计流行率上限和达到此上限所需的相应真实流行率值之间的关系。
如图 6 所示,这些情景可用于猜测观察某个上限值所需的真实流行率。在这两种情况下,除了接近 100%的上限值,真实流行率必须大大低于上限值,通常是 4 或 5 倍。
在图 3(对于直接计算的上限)和图 5(对于通过回归内插的上限)中,应用来自两种情况的猜测偏差的结果由蓝色(情况 1)和黄色(情况 2)点绘制。重要的是,除了英国、塞内加尔和巴拿马——拥有可靠的每日序列的国家——以及伊朗和西班牙——通过回归估计的国家——预计绝大多数国家的患病率低于 20%,即使在非常低的偏倚情景 1 中也是如此。在情景 2 更现实的偏差下,只有英国、伊朗和塞内加尔的终生患病率超过 10%。
结论
这些场景有多真实?西班牙、法国和爱沙尼亚
上述两种情况结合了对偏差可能有多大的粗略常识性猜测,以及统计上合理的上限测量。人们当然会怀疑这些估算中的常识成分。然而,请注意,常识推理是概率论的核心。正如皮埃尔·西蒙·拉普拉斯所说,
[…] 概率的理论不是建立在基础上的,而是建立在计算基础上的。 *——*皮埃尔·西蒙·拉普拉斯《概率哲学随笔》 1814 年
概率论只不过是简化成微积分的常识。这个想法后来在 Richard T. Cox 的一个著名定理( Cox 的定理)中得到更正式的证明,表明常识和直觉知识可以被编纂,然后概率论的规则提供了对这些知识进行推理的最合理的方式——事实上是唯一的方式。我提出的常识性情景只是对我们先前知识的简单公开量化,即在大多数国家,CoV-2 检测偏向于感染者。这里使用的方法能够——如果有人有理由相信偏差应该更高或更低——只需插入一个新的先前猜测,并获得与这些假设最一致的结果。我们现在可以使用来自我们对其真实流行率有可靠估计的国家的数据来调查各国之间真正的阳性检测偏倚。
[……]在西班牙,感染者接受检测的可能性是未感染者的 127 倍。
最近,西班牙的卡洛斯三世健康研究所发布了其在 T2 的第一轮 ENE-COVID19 研究的初步结果(链接是西班牙语的,点击此处查看路透社的英语摘要)。这是一项大规模的血清流行病学研究,旨在从 4 月 27 日至 5 月 11 日期间随机抽样的 6 万多名西班牙居民的血液样本中寻找 CoV-2 抗体,这些样本经过精心选择,以提供西班牙人口的准确代表性。他们报告说,大约 5%的西班牙居民会被病毒感染,95%的置信区间在 4.7%到 5.4%之间。这非常接近西班牙在情景 2 下的估计,即 4.64%。然而,看起来西班牙的测试偏差实际上比设想 2 所猜测的还要高。考虑到西班牙患病率的估计上限(49.32%),加上 5%的真实患病率,使用等式 3,我们将得到测试偏差 B= 3.00,与第二位小数的情形 2 相同。这意味着,在西班牙,感染者接受检测的可能性是非感染者的 20 倍。然而,请注意,根据 ENE-COVID19 研究,不是我故意采取的 70%的最坏情况,只有 2.5%的 CoV-2 抗体携带者没有表现出任何症状,另有 4.6%的人表现出两种或更少的症状(怀疑一个人可能被感染的最低要求是三种症状)。这本身就可以解释从情景 1 到情景 2 的转变。
从 ENE-COVID2 研究报告的数据中可以推断出更多关于西班牙检测偏倚情况的详细事实。该研究报告从 60,640 名以前没有接受过 CoV-2 检测的人和 247 名已经接受过检测的人身上采集了样本。在这些人中,只有 4.7%未检测的人有 CoV-2 抗体,而之前检测过的人有 87%。有了这些数字,通过应用贝叶斯定理,我们可以直接使用等式 1,计算出西班牙的真实偏差为 B=4.85 。换句话说,在西班牙,感染者接受检测的可能性几乎是未感染者的 127 倍。测试偏差中一个完整对数单位的增加表明西班牙的上限(通过回归插值)实际上被低估了,应该在 87%左右,而不是回归插值的 49.32%。
上述不匹配的部分原因可归因于回归的使用。然而,这背后还有另一个更令人担忧的原因。不同国家报告的测试数据差异很大(参见此处的了解每个国家的详细信息)。一些国家报告了进行检测的次数,一些国家报告了采集样本的次数,另一些国家报告了接受检测的人数,一些国家报告了其中几项措施,还有一些国家根本没有说明。在西班牙的具体案例中,报告的是进行测试的次数— ,但是请注意,通常会对一个人进行几项测试。累计阳性检测率计算为确诊病例与检测次数的比率。截至今日,西班牙的这一比例为 11.95%。然而,87%的上限与 ENE-COVID19 研究中报告的人数的阳性检测率完全一致。换句话说,在所有只报告检测次数而没有提及实际检测人数的国家中,上限很可能被严重低估。
关于西班牙测试策略的说明应该在这里给出。87%接受检测的人实际上是阳性的——注意这个数字可能更高,因为许多在检测后不久死亡的人不能参加血清阳性反应研究——揭示了一个相当有问题的检测策略。这种偏差如此之大,以至于只能用来确认我们已经几乎可以肯定是谁被感染了。请注意,阳性检测率实际上接近实际检测的灵敏度——这很可能是一个灵敏度为 87%,特异性为 95.3%的检测。换句话说,在西班牙,接受疾病检测的事实本身就构成了对疾病的检测,几乎和检测本身一样可靠!我不认为这是一个非常有用的测试应用。
[……]在爱沙尼亚,感染者接受检测的可能性是未感染者的 68 倍
同样,5 月 6 日,爱沙尼亚塔尔图大学发布了第一波全国新冠肺炎血清学研究的结果。他们在 4 月 24 日开始的七天时间里测试了爱沙尼亚的 2007 名成年居民,他们发现了三例 CoV-2 抗体。这表明截至 5 月 1 日,爱沙尼亚人口的患病率约为 0.15%(95%置信区间[0%–0.32%])。这非常接近爱沙尼亚在情景 2 下的估计值,即 0.51%。如前所述,将抗体数据与爱沙尼亚上限(9.32%)相结合,爱沙尼亚的偏倚估计值为 B =4.23。这相当于说,在爱沙尼亚,感染者接受检测的可能性是非感染者的 68 倍。这确实与爱沙尼亚政府的新冠肺炎检测指南相一致,该指南通常建议仅对有症状的患者进行检测,特别是当他们被认为有风险时(除了进行单独批次的随机检测以评估疾病在全国的传播程度)。与西班牙的回归上限不同,爱沙尼亚的估计值是直接从日常测试数据中计算出来的,但它仍然基于所进行的测试数量——而不是测试的人数——所以它可能被低估了。这意味着测试偏差实际上可能比这更高,也许和西班牙一样高。
此外,由于计算样本数量相对较少,爱沙尼亚的血清阳性率估计值可能不那么准确。我怀疑这个比率的原因是双重的:首先,它的 95%置信区间将包括 0%和两倍以上的比率。第二,爱沙尼亚目前的确诊病例数实际上相当于其人口的 0.13%,而且——正如我在上一篇文章中所主张的——这是终生患病率的绝对最小值。只有 0.15%的流行率非常接近于最小值,这表明爱沙尼亚是相当独特的,因为它发现了几乎所有的 SARS-新冠肺炎病例。
[……]法国的感染者接受检测的可能性“仅仅”是非感染者的 7.79 倍。
最近,来自法国巴斯德研究所的研究人员在科学杂志上发表了一项关于 T2 的详细研究,使用非常详细的人口数据模拟了 CoV-2 在法国人口中的流行情况。这比全国患病率研究低了一步,但仍然是一个非常可靠的估计。他们得出结论,到 5 月 11 日,大约 4.4%的法国人口——95%的置信区间在 2.8%和 7.2%之间——在某个时候感染了 CoV-2。这仅略低于法国在情景 1 下的估计值(5.64%)。使用法国的插值上限(26.39%),将意味着法国实际上具有相当低的测试偏差 B = 2.05 法国的感染者接受检测的可能性“仅仅”是非感染者的 7.79 倍。然而,我们应该对这种偏差估计持保留态度,因为法国的上限(和西班牙的上限一样)是通过对大量测试进行回归而获得的,我们从西班牙的数据中知道这导致了严重的低估。
英国正在发生什么?
在 2020 年 5 月 15 日完成这篇文章时,英国在可以直接从每日测试率计算上限的国家中脱颖而出。其上限是惊人的 77.8%的最大可能终生流行率。英国报告的是每天接受测试的人数,而不是进行的测试,因此上限很可能没有被低估。虽然,正如我已经表明的,即使引入非常小的检测偏倚也会显著降低这一数字——例如,情景 1 下的 36.87%,已经与群体免疫的任何希望相去甚远——即使是高偏倚情景 2 也使英国的估计患病率为 14.91%。我怀疑英国的真实流行率实际上远低于这个数字,可能更接近西班牙的 5%(因为它有非常相似的死亡数字)。这将使英国的检测偏差为B= 4.25——几乎与爱沙尼亚相同,表明一个感染者被检测的可能性是一个非感染者的大约 70 倍。
带回家的信息
在修正上限测量值并更详细地研究阳性检测偏倚的明确测量值时,我必须重申我在 4 月 29 日提出的主要观点——如上所述,这一点已经得到了开始可用的真实流行率研究结果的证实:群体免疫非常遥远,需要很长时间才能达到,直到疫苗可用。因此,重要的是,各国——即使它们已设法控制住了疫情高峰——仍要非常小心,以避免今后再次出现感染。显然,在大多数国家,解除一些限制将成为经济和公共卫生当务之急——正如我在之前的帖子中提到的,**深度经济危机也会导致许多人死亡。然而,在疫苗问世之前,试图完全恢复到疫情之前的常态是鲁莽的。这有可能重演——或者更糟——发生在米兰、马德里、伦敦或纽约医院的悲剧。
“无论如何,最终每个人都会得这种病,所以试图阻止它是没有意义的”这种观点本身就是鲁莽的——尤其是在公共卫生官员的嘴里。它忽略了一个证据,即经历病例的逐渐泄漏是不一样的——在许多国家,这可以通过卫生服务得到很好的控制——因为它将经历突然的压倒性病例雪崩,正如我们已经在意大利、西班牙和其他几个国家看到的那样。在第二种情况下,生命的代价肯定会高得多。
这里进行的计算也强调了拥有可用的每日测试数据的重要性。这是一些国家目前没有做的事情,但这是监测各国疫情进展的一个关键部分。反过来,这对于评估用于控制疫情的不同政策选择的效力至关重要。此外,正如西班牙发布的 ENE-COVID19 研究所表明的那样,各国报告已接受检测的人数和已进行检测的人数至关重要。只有这样,我们才能计算出可靠的跨国数据。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
根除在线用户行为中的异常现象
实践教程
用于识别异常在线活动根本原因的比较马尔可夫链分析
作为一名训练有素的认知神经科学家,我有理解人类行为和信息如何引导决策的经验。现在,随着我转变为一名数据科学家,部分由于我在 Insight 的数据科学奖学金,我开始了解到许多其他在更大范围内跟踪和理解行为的媒介和方法。
在我的研究员生涯中,我为一家软件公司 Lazy Lantern 做顾问,该公司协助其他公司监控客户如何与他们的在线平台互动。更具体地说,Lazy Lantern 为其客户公司提供对其网站和 iOS/Android 应用程序的自动监控和分析,从而了解这些平台上的客户流量、互动和整体行为。
问题
为了理解 Lazy Lantern 如何跟踪客户行为,让我们考虑一个典型零售网站的用户旅程,如下图所示。
**图一。**这些是反复出现的链接或事件,客户通常会点击这些链接或事件在零售网站上购物。[图片由作者提供]
在主页上,客户可以点击产品列表,然后锁定感兴趣的产品,将该产品添加到购物车中,最后结账。考虑到在给定的时间内,网站上会有许多这样的客户交互,Lazy Lantern 使用时间序列模型 Prophet 来预测给定链接或事件(如产品列表、产品等)的交互率。)在给定时间段内。Prophet 模型每小时评估一次这些事件的预期点击数,并得出给定时间段的预期正常点击数范围。要了解更多关于 Prophet 模型如何在 Lazy Lantern 中使用以及提高其检测效率的方法,请查看我的 Insight 同事 Yeonjoo Smith 的博客这里 。
如果客户与这些链接的交互次数高于或低于模型预测的范围,算法将触发 异常 ,并向客户公司发出警报。虽然该模型能够检测出这些事件中每一个单独的用户交互率的异常,但它无法确定触发的异常是否实际上是平台上事件的连锁反应的一部分。
例如,让我们考虑与以前相同的用户旅程,但这次它被中断了,如下图所示。
图二。有时零售网站上的链接可能会断开,这导致在一系列事件中点击后续链接的用户数量下降。[图片由作者提供]
在这里,客户再次从主页进入,单击产品列表,单击感兴趣的产品,但是由于一些故障,他们无法将产品添加到购物车中。在这种情况下,该算法将对“添加到购物车”和“结账”事件发出异常警报;然而,除此之外,它无法向客户提供任何信息。
在本例中(图 2 ),可能是“添加到购物车”按钮被破坏,这导致了级联效应,导致“结账”按钮也被破坏。然而,该算法只是将这些识别为独立的异常,而不一定是事件之间的重叠和关系。**因此,提出了这个项目的中心问题:我们如何识别哪个事件是这些重叠触发异常的潜在根本原因?**查明这些连锁异常效应的根本原因将为客户公司提供关于其平台上潜在问题的更细致的反馈,然后他们可以快速解决这些问题,以确保未来的客户满意度,避免不必要的收入损失。
数据
虽然在上面的例子中很容易理解什么事件是问题的根本原因,但实际上,答案是…不那么简单。在调查实际公司平台的客户行为时,会发生多个用户和用户交互,但并非所有用户和用户交互都清晰、整齐地对应于触发的异常。为了建立一个可扩展的、通用的模型来封装跨不同平台和用例的潜在用户交互的复杂性,我必须首先收集相关的数据。
对于给定的客户公司,发生的每个事件异常都存储在 InfluxDB 数据库中,带有相应的事件标签、违规的开始和结束时间以及发生异常的平台(即 web、iOS 或 Android)。累积这些异常计算的原始用户交互存储在 MongoDB 数据库中,按公司和平台划分;其中包含事件标签、用户身份和用户与事件交互的时间戳。
**图 3。**这里描述的解决方案使用的数据分布在 InfluxDB 和 MongoDB 上。异常事件通过 Prophet 算法聚合,原始事件对应于这些异常事件,是单独的交互。[图片由作者提供]
首先,我评估了异常事件列表,并评估了哪些异常在时间上相互重叠。这些是连锁异常,在真实数据中,它们通常在 2 到 15 个异常事件之间。我们可以将异常之间的时间重叠称为 异常周期 。考虑到我们最初的例子,“添加到购物车”和“结帐”这两个异常事件发生的时间段将导致一个这样的异常时间段,因为它们的警报在时间上重叠。
在生成那些重叠的、连锁的异常的列表之后,我通过在异常时段和原始事件之间进行时间匹配,提取了在结果异常时段内发生的 原始事件 。现在有了这些原始事件,我们可以尝试查明哪个事件是级联异常的起因或根本原因。
解决方案
有了对应于异常时期的原始事件列表,我现在必须找出异常时期的根本原因是什么。异常时期的原始事件数以千计,当然与时期的长度直接相关。因此,当务之急是找到解决根本原因问题的解决方案,即:
- 快速 由于在给定的异常时段内需要解析的事件数量庞大,因此需要部署的解决方案必须省时且易于实施。
- 灵活 因为 Lazy Lantern 有超过 160 家客户公司,每家公司都有多个平台,所以解决方案必须与数据无关,并且不需要过度定制。
考虑到这些限定条件,我的解决方案是利用马尔可夫链模型并进行一些比较分析。马尔可夫链是一个“根据某些概率规则经历从一种状态到另一种状态的转换的数学系统…其中转换到任何特定状态的概率仅取决于当前状态。”为了将这个定义与手头的问题直接联系起来,马尔可夫链模型将能够告诉你在给定的时间段内用户从一个事件转移到另一个事件的可能性。
对于异常时间段,我决定用户如何遍历相关事件,跟踪哪个事件紧跟在前一个事件之后。然后,在对给定事件的所有用户的交互进行平均后,我通过创建逐个事件的马尔可夫矩阵(即矩阵中的所有列总和为 1),生成了用户将从一个事件转移到另一个事件的*。*
这个转换矩阵在 x 轴和 y 轴上向我们展示了用户在这个异常的时间段内经历的所有原始事件。为了公司数据的匿名性,这些事件在图 4 中用数字表示,但是这些数字本质上对应于初始示例中的事件,例如“将产品添加到购物车”、“结账”等。矩阵中每个单元的值对应于从一个事件(x 轴上编号的事件)遍历到下一个事件(y 轴上编号的事件)的用户比例。
图 4。为了查明异常的潜在根本原因,我进行了比较马尔可夫链分析。在这个分析中,我从一个正常的时间段减去了事件转换,从异常的时间段回溯到正好一周之前。这产生了一个差异得分矩阵,它展示了两个时间段之间的概率变化。该矩阵允许人们看到哪个事件转换(x 轴上的事件到 y 轴上的事件)导致两个时间匹配的时间段之间用户之间的事件转换的最大变化。[图片由作者提供]
既然我已经生成了异常时期的马尔可夫链转移矩阵,我需要某种基线来与之比较。该基线是通过提取在相同的确切时间段内发生的原始事件而获得的,但是回溯到异常时段之前的一周,其中没有检测到异常。我认为这将是一个很好的代理,说明在没有任何站点问题的类似“正常”时间段内,用户的事件遍历是如何发生的。对于这个正常的时间段,我再次以完全相同的方式生成了一个转移矩阵。
现在有了异常时段的转移矩阵和相似时间匹配的非异常时段的转移矩阵,我决定用 比较 它们之间的概率:从异常矩阵中减去正常矩阵。得到的矩阵将由两个时间段的两个概率的增量变化组成(图 4 )。
这个概率差异得分矩阵告诉我们,在两个时间段之间的相同事件之间,用户的转换可能性有多大差异。回到我们最初的例子,如果我们跟踪正常日子里与我们的零售网站互动的客户的转变(图 1 ),然后将其与零售网站行为不当的时间(图 2 )进行比较,从差异得分矩阵中,我们会看到在这两个时间段内转变的比例差异在事件“将产品添加到购物车”和“结账”之间这表明,与网站上的这些事件相对应的最终行动应该得到解决,以便纠正这种异常现象。
这种解决方案是理想的,因为无论客户及其不同的业务类型和事件如何,它都能很好地执行。具体来说,马尔可夫链矩阵只跟踪客户正在交互的事件,因此不知道具体的数据类型。借助该解决方案,我可以明确指出给定客户端平台上的哪些事件或操作导致了通常的流量行为,从而找到异常的根本原因。凭借这种洞察力,Lazy Lantern 可以将客户平台的具体痛点传递给客户,然后客户可以在他们的网站或应用程序上有效地解决这些问题。
产品
为了使解决方案可扩展,我决定创建并部署一个 Streamlit 仪表板。有了这个仪表板,Lazy Lantern 可以在一个地方轻松检查所有客户的消费行为。通过下拉菜单,用户可以选择他们感兴趣的客户端,选择该客户端的特定平台(即 web、iOS 或 Android),然后从 InfluxDB 链接列表中选择该特定客户端和平台的相关异常。在选择了特定的异常之后,从 MongoDB 中提取与该异常及其时间匹配的非异常相对应的原始事件,并部署上述矩阵解决方案。
***图 5。*Streamlit 仪表盘允许用户专门关注公司、平台和异常情况。结果输出允许判断哪些事件转变导致异常和非异常时间段之间用户行为的最大变化。了解事件转换中的这些变化有助于了解哪些事件可能是异常的根本原因。[图片由作者提供]
仪表板输出结果矩阵,如图 4 所示;Lazy Lantern 可以直观地检查差异矩阵,以发现哪些事件导致了两个时间段之间的变化。此外,仪表板还输出一个摘要图(图 5 ),该图突出显示了导致两个时间段之间最大概率变化(正和负)的前五个事件转换。有了这个摘要,Lazy Lantern 可以快速评估客户平台上的哪些事件转换对客户行为的变化影响最大,并相应地提醒他们的客户。
该仪表板是该解决方案的理想产品,因为人们可以轻松、相对快速地在客户端和异常之间切换,而不必修改内部代码来访问数据并将其与相应的解决方案匹配。
未来考虑
这个项目从构思到实施,历时约三周。虽然这里详细描述的解决方案快速灵活,但有了更多的时间和数据,我的解决方案还可以改进,为用户提供更多定制的反馈。在当前的解决方案中,我只研究了给定平台上事件之间的单步转换。其他需要考虑的是多个步骤的事件链,不仅仅是上一次或下一次点击。这将有助于洞察客户采取的多种类型的“典型”活动路线,例如购买商品的路线,阅读更多关于公司的信息并找到其社交媒体平台的另一条路线。这些高阶马尔可夫链将允许向客户提供更多关于异常用户流量的定制反馈。
补充该解决方案的另一个考虑可能是为每个客户公司训练定制的隐马尔可夫模型,以获得存在于他们平台中的事件状态的表示。这将为我们提供比我们从当前解决方案中得到的快照分布更稳定的事件转移概率分布。然而,这种方法的一个警告是,它不仅需要大量数据来生成模型,而且它不会如此容易或快速地适应客户可能在平台中做出的更改,并且必须不断更新和重新训练。
我要感谢 Lazy Lantern,特别是 Bastien Beurier,给我机会研究这个问题。这是我第一次提供以业务为中心的解决方案,我非常感谢我得到的支持和反馈。这对您刚刚阅读完的数据解决方案和产品至关重要!你可以在我的 GitHub 上找到代码和一些样本数据。
熊猫的样本高于平均值
入门
为您的机器学习对齐不一致的报告数据
图片作者(许可)
许多模型输入累积变量,如几小时内的降雨量或几个月内的公司收入。不幸的是,数据源通常在时间上不一致。一个传感器每隔奇数小时提供数据,另一个在偶数小时提供数据。一家公司在五月提供信息,另一家在六月。
如果您不想等待所有数据源都收集输入数据,或者当不适合向模型提供来自不同时间段的数据时,您必须将测量结果分散到相同的时间段。熊猫本身可以完成部分工作,但在本文中,我们将探索如何用平均值进行上采样,这需要一点额外的编码。
您可以通过 Github 上共享的笔记本运行本教程中的所有示例—up sample _ to _ average . ipynb
重采样
向下采样
python 的 Pandas 中的重采样允许您将频率较高的值转换为频率较低的值— **downsample**
,例如,将每小时的数据转换为每天的总和、计数和平均值,或者将每天的值转换为每月的值。
# downsample:
CAT|DATE|VALUE
abc|0101|10
abc|0102|20
abc|0103|15# downsample
**[IN]:** df.groupby("CAT").resample("W", on="DATE").agg({"VALUE":["sum","count","mean","first","last"]})**[OUT]:** CAT|DATE|SUM|COUNT|MEAN|MIN|MAX|FIRST|LAST
abc|0107|45 | 3 | 15 | 10| 20| 10 | 15
它被称为downsample
,因为数据行的数量减少了。可以申请sum
、count
、mean
(平均)、median
、min
、max
、first
或last
。基于每日输入,您可以重采样到周、月、季度、年,也可以重采样到半月——参见 pandas 文档中重采样选项的完整列表。您还可以对乘法进行重新采样,例如5H
以 5 小时为一组。
向上采样
重新采样到更频繁的时间戳被称为**upsampling**
。你可以把几天变成几小时,或者几个月变成几天。进行上采样时,必须首先将日期时间列设置为数据框的索引(.set_index
),然后才能进行上采样。
# error in case you try upsample using .resample("D", on="col")
**ValueError**: Upsampling from level= or on= selection is not supported, use .set_index(...) to explicitly set index to datetime-like
除上述功能外,上采样还支持backfill/bfill
、ffill/pad
和nearest
。但是如果你认为应用mean
会把每天的值分割成每小时的平均值,那你就错了。所有加起来的样本都用NaN
填充。
为什么我们要向上采样到平均值
假设你有一个商店组合,试着估算一下销售额。您输入Jan-1
、Jan-2
和Jan-3
的收入,并执行回归以猜测Jan-4
的目标值。你对你所有的商店进行训练,并使用模型来预测未来的销售。
但是如果有些商店只提供Jan-2
和Jan-3
的数据呢?其他仅在Jan-1
和Jan-3
上。您可以使用这 3 天中的sum
或average
进行缩减采样和建模,但在这种情况下,您会丢失有价值的输入信息,如周五的收入或周一的收入。
与普遍看法相反,这种情况很典型。当分析公司的基本数据以预测未来的股票价格时,一些公司每季度报告一次,而另一些公司每年报告两次。有些在 11 月,有些在 8 月。如果你等到每个人都提供了他们的数据,你可能会得出一个精确的预测,但那时所有有利可图的股票都会被卖出。
图片作者(许可)
通常 80%的输入保持相同的模式,20%包括一些重要的场景具有不寻常的结构,你必须重新计算。
要解决这些数据泄漏,您可以向上采样到平均值。
用平均值向上采样
我说的是平滑不一致的报告数据的选项,这样您就可以
**[IN]:**
data="""
**CAT|DATE|VALUE**
abc|0101|10
abc|0103|20
abc|0105|15
efg|0102|40
efg|0105|30"""**[OUT]:**
**CAT|DATE|VALUE**
abc|0102|10
abc|0103|10 # 20 on 0103 covers interval 0102-0103 (2 days)
abc|0104|7.5
abc|0105|7.5 # 15 on 0105 covers interval 0104-0105 (2 days)
efg|0103|10
efg|0104|10
efg|0105|10 # 30 on 0105 covers interval 0103-0105 (3 days)
上面的例子很简单,但是想象一下你有几千个类别。有些是每天报告,有些是单双日报告,其余的是每三天或不定期报告。
如何做一般的魔术
为了计算平均值,你需要两个东西——sum
除以count
。您知道总数,因为它已被报告,但从最后一个值算起的天数(月数、周数……)未知。幸运的是,熊猫重采样包含一个参数.group
,它显示了上采样时创建了多少个群组。
不幸的是,它本身不能与groupby
一起工作,所以我们将首先查看单个类别。
data="""
CAT|DATE|VALUE
abc|**0101**|10
abc|**0103**|20
abc|**0106**|15"""
重采样方法有两个属性:
indices
—显示输入数据出现的位置groups
—用组索引对每个日期时间值进行索引。
# indices
[In]: df.set_index("DATE").resample("D").**indices**
[Out]:
defaultdict(list,
{Timestamp('1900-01-**01** 00:00:00', freq='D'): [0],
Timestamp('1900-01-**03** 00:00:00', freq='D'): [1],
Timestamp('1900-01-**06** 00:00:00', freq='D'): [2]})# groups
[In]: df.set_index("DATE").resample("D").**groups**
[Out]:
{Timestamp('1900-01-01 00:00:00', freq='D'): 1,
Timestamp('1900-01-02 00:00:00', freq='D'): 1,
Timestamp('1900-01-03 00:00:00', freq='D'): 2,
Timestamp('1900-01-04 00:00:00', freq='D'): 2,
Timestamp('1900-01-05 00:00:00', freq='D'): 2,
Timestamp('1900-01-06 00:00:00', freq='D'): 3}
1 月 1 日和 2 日形成第一组,3 日至 5 日是第二组,最后一个数据样本属于最后一组。大多数情况下,报告的数据包含报告日期的值—1 月 3 日报告的 20 个数据涵盖 1 月 2 日和 1 月 3 日。在这种情况下,您使用label
参数并将其设置为right
。
# groups
[In]: df.set_index("DATE").resample("D", label="right).**groups**
[Out]:
{
Timestamp('1900-01-02 00:00:00', freq='D'): 1,
Timestamp('1900-01-03 00:00:00', freq='D'): 1,
Timestamp('1900-01-04 00:00:00', freq='D'): 2,
Timestamp('1900-01-05 00:00:00', freq='D'): 2,
Timestamp('1900-01-06 00:00:00', freq='D'): 2,
Timestamp('1900-01-07 00:00:00', freq='D'): 3,}
或者,您可以将组转换成数据帧,并移动值
df_groups = pd.DataFrame(df.set_index("DATE").resample("D").groups, index=["group"]).T.shift(1)
然后你计算每组中出现的次数。
s = df_groups.groupby("group").size()
s.name = "count"
并将计数与日期和回填值连接起来。它会生成一个数据帧,其中包含该时间段的总和以及该时间段内的发生次数,这就是计算平均值所需的全部内容。
如果你现在兴奋地大叫,坚持住,我们还没有到达终点。我们已经计算了单个组的平均值,但是如果我们想要groupby
多个类别,例如,当我们有许多商店、公司或传感器要处理时,我们必须分别计算每个组的平均值。
这并不复杂,但如果您有许多输入,这可能会很耗时。参见下面的代码:
您已经将数据平滑到平均值,但通常您不需要每个月的平均值。您只需要涵盖不同的报告期。例如,在审查上市公司业绩的财务分析中,大多数公司在季度末报告数据。但是有些是在不同的月份,甚至不是每季度。如果你想对一大堆公司的行为建模,你首先要对那些没有季度报告的公司进行平滑平均,然后使用rolling
函数将输入限制为仅季度。
更多的输入意味着更多的模型参数和更长的计算时间
让我们看一下股票市场分析的例子:
编码再次让我们感到惊讶。当您对天应用.resample("D", label="right")
重采样时,结果与.resample("D", label="right", **closed="left"**)
相同。如果在重新采样到月时做同样的操作,label="right"
与label="right", **closed="right"**
相匹配。因此,您必须为每月计算指定label="right", closed="left"
,或者使用上述带有shift
的变通方法。
结论
我希望你不仅学到了关于重采样的知识,还学到了在输入机器学习模型时如何使用替代方法来对齐不一致的数据。
The images were with [canva.com](https://partner.canva.com/vdek) (affiliate link, when you click on it and purchase a product, you won't pay more, but I can receive a small reward; you can always write canva.com to your browser to avoid this). Canva offer some free templates and graphics too.
Other articles:
* [Everything you wanted to know about Kfold train-test split](/complete-guide-to-pythons-cross-validation-with-examples-a9676b5cac12)
* [Why it's worth considering another file types than csv](/stop-persisting-pandas-data-frames-in-csvs-f369a6440af5)
* [How to turn a list of addreses into a map](/pythons-geocoding-convert-a-list-of-addresses-into-a-map-f522ef513fd6)Great thanks to [Towards data science](https://towardsdatascience.com/)
Github 上的完整代码—up sample _ to _ average . ipynb。
镦粗是自维恩图以来最伟大的可视化设置
一个新的 R 包,用于查看复杂数据中的交叉点
作者图片,灵感来自一张来自原始论文的图片
我坚信翻转器是我见过的最漂亮、最直观的大型复杂集合交集可视化。
维恩图让我微笑,但冷门让我感到强大。冷镦机可以可视化维恩图只能梦想的数据。
但首先,让我们回顾一下文氏图。
维恩图综述
维恩图在我们今天的文化中无处不在。它们易于阅读,能有效地传递信息,而且玩起来也很有趣。但是如果你想形象化三个以上的类别,你会怎么做?
让我们看一个简单的例子。
假设我们有一个关于世界各国的数据集,我们有每个国家的一些信息。
这是一个愚蠢的例子,但信息是准确的
将不同国家之间的相似性和差异可视化的维恩图可能如下所示:
作者图片
这张图看起来很漂亮,但我不能代表太多,它会很快变得杂乱无章。
如果我想比较另一个国家呢?嗯,我运气不好。你真的想尝试破译类似这种的东西吗?这个呢?
“史蒂夫·米勒·维恩图:你是一个采摘者、一个微笑者、一个情人、一个罪人、一个小丑、一个吸烟者还是一个午夜吸烟者? dullhunk 的(艺术家未知)由 2.0 在 CC 下授权
是啊,我不这么认为。
介绍:冷镦机
UpSet 是一种非常新的可视化技术,它通过用条形图以表格形式呈现信息来解决这个问题。你可以在每一个类别中拥有你想要的任意多的东西,并且很容易找到它们之间的交集。UpSetR 是实现它的一个 R 包。
有一个来自 IMDB 的数据集,看看有多少部电影有相同的演员,他们是谁?没问题!想看看癌症患者的基因中是否有相同的一组突变,它们是什么?颠覆者为你而来!
UpSetR 最适合在包含大量要素的复杂数据集中查找模式。这是通过将不同要素中具有许多相同值的数据点分组来实现的。也就是说,冷镦机寻找最大的相交集。
对于已经是二进制的变量(这意味着两个类别),或者可以转换成二进制的变量,这是最好的。需要注意的是,一键编码可以将任何分类特征转换为二进制特征。事实上,目前的实现只适用于二进制变量。
例如:心理健康数据
我正在为这个 Kaggle 数据集开发一个分类模型,我试图理解不同的列是如何相互关联的。
数据集包含了科技公司对心理健康的态度,以及员工心理健康的信息。调查数据包含了从雇主是否提供心理健康福利到员工自己是否接受过心理健康治疗的所有问题的答案。
在这一点上,还不清楚这些特性是如何相互关联的,我想知道发生了什么。
之前,我已经清理了一些数据,所以现在我将把它输入到 R 中。然而,在我创建颠覆可视化之前,我想一次性编码我的数据,因为它大部分是分类数据。
一键编码
one-hot encoding 是一种通过创建新列将分类变量转化为二进制变量的方法。例如,我们的 work_interfere 栏有 3 个选项:经常、有时、从不。在我们一次性编码我们的数据后,我们将有 3 列:*work _ interfere _ occurly,work _ interfere _ sometimes,work_interfere_never,*如果该值适用,则每一列包含 1,如果不适用,则包含 0。如果你想了解更多,网上有很多很棒的教程。
下面是 R 代码:
data = read.csv('survey_data.csv', na.strings="Not Applicable")#install packages (can skip if already installed)
install.packages("mltools")
install.packages("data.table")
install.packages("UpSetR")#one-hot encode
library(mltools)
library(data.table)
newdata <- one_hot(as.data.table(data))#create the visualization
library(UpSetR)
upset(newdata, order.by=”freq”, main.bar.color = “#995ee1”, sets.bar.color = “#995ee1”, group.by = ‘degree’)
您可以在此下载调查数据。
你会得到这个可爱的东西:
作者图片
如何解读
左侧栏
在左侧,有代表每个集合的总大小的条。在性别 _ 男性的案例中,我们可以看到大约有 950 名调查受访者认为自己的性别是男性。这些集合是不分离的——也就是说, mental_interview_No 包括所有对“你会在面试中向潜在雇主提出精神健康问题吗?”这个问题回答“不”的人,无论性别如何
顶栏
在顶部,我们可以看到每个交叉集合的大小。如果黑点被填充,则该类别包含在集合中。如果圆点是灰色的,则该类别不在集合中。注意集合是不相交的,这意味着它们是不重叠的。你可以在顶部的横条中看到每个数据点,不像左边的横条。
示例 1: 由于左起第一个条上的所有点都已填写,该条代表对由性别变量表示的问题回答为男性的所有 475 人,对心理 _ 健康 _ 面试、观察 _ 结果和自雇者,以及对技术 _ 公司回答为“是”。
示例 2: 然而,右边第二组代表一名单身男子( Gender_Male ),他没有听说过或观察到患有精神健康疾病的同事在其工作场所造成的负面后果(OBS _ result),但是一家科技公司的自营职业者,并将在采访中提及精神健康问题。我们知道这位工人是个体经营者,并且会在采访中提到精神健康,这是基于可视化中某些点没有被选中的事实以及我们对其他可能选项的了解。
在这个可视化中,考虑在可视化中没有出现的信息非常重要,就像第二个例子一样。在某些情况下,这是最有趣的部分。
心烦意乱的形象告诉我们
我们来看左起第一列(例 1 )。
我知道我有大约 1200 个数据点,其中 988 个是男性。有 475 名男性表示,他们不会在面试中向潜在雇主提出心理健康问题mental _ health _ interview _ No,他们目前在一家科技公司工作 tech_company_Yes ,他们没有听说或观察到工作场所有心理健康问题的同事会带来负面后果OBS _ result _ No,他们也不是自由职业者自由职业者 _No ,这一事实意义重大,因为显示,近一半的男性(48
如果你把对这四个问题做出相同回答的 132 名非男性加入进来,就像我们在左起第二列看到的那样,那么你会发现整个数据集中有将近一半的人对这四个问题做出了完全相同的回答(48%)。
释义
这些结果告诉我,人们,尤其是男性,不会在工作场所公开谈论心理健康。这是一个有趣的初步发现。
潜在的改进
如果我想改进我的分析,我可以将序数变量(具有顺序感的变量,如从 1 到 5 的范围,或“没有、一些、很多”)转换成二元变量,通过宁滨(将相关值分成两个复合类别)保留一些层次感。这将允许他们更强烈地考虑到 upser 的分析中,因为 upser 可以考虑的选项更少。
总结想法
我很喜欢 UpSetR 软件包,认为这是进行探索性数据分析的一种很好的方式。它的文档很不错,并且有一个可用的 Python 版本。
如果您有任何问题或意见,请联系我们!我希望你能像我一样喜欢这种想象。
城市无人机:设施定位问题
当成群的无人机涌入我们的城市时会发生什么,为什么城市规划者应该关心?
城市需要无人机吗?
根据美国联邦航空局的一份报告,到 2021 年,预计将有 447 万架小型无人机在美国运营,高于今天的 275 万架。自 2017 年以来,已经有超过 100 万无人机所有者在美国联邦航空管理局(FAA)注册。到目前为止,正如预期的,商业无人机购买量快速增长的主要驱动力是它们的高机动性和在计算机视觉中的应用:在危险区域拍照,建筑物检查,交通监控,摄影测量等。
然而,这仅仅是开始。预计无人机将在未来的城市中执行重要任务:如果一座桥梁即将倒塌,一场火灾正在蔓延或一个人陷入困境,它们将立即提供从天空鸟瞰的报告。它们将补充我们的运输系统,把东西搬来搬去,或者把人快速送到某个地方。事实上,亚马逊的 Prime Air 无人机送货服务已经处于开始运营前的最后开发阶段。无人机也将是长着翅膀的机器人,执行诸如修桥或救火等任务。
在本帖中,我们将讨论无人机将如何影响城市,以及城市规划者将如何扩展他们的专业知识范围,以便能够处理城市空域、城市空中交通及其与传统城市空间的相互作用。我们将通过解决无人机站在一个城市中的高效放置问题,并查看不同的城市空中交通配置如何导致不同的操作区和城市机动性来实现这一点。
为什么城市规划者应该关注?
到目前为止,我们大多数人只是偶尔见过无人机。但是,当成群的无人机涌入我们的城市时,会发生什么?我们可以充满信心地预计,无人机的大规模部署将给规划、管理和设计可持续城市带来一些重大挑战。无人机技术的大规模扩散将对我们城市的本质产生影响。某些类型的无人机应用将需要新的物理基础设施。
无人机系统可能会影响建筑物的设计和建造方式。例如,如果无人机对接站将被放置在建筑物的屋顶上,那么屋顶将必须易于人类接近,同时也便于运输货物进出。新建筑的设计必须考虑到这一点(例如,增加内部或外部电梯井)。改造旧建筑以适应新环境也是一个严峻的挑战。还需要解决对建筑环境的视觉影响。
将出现新型基础设施,如形成无人机移动网络的客运和物流枢纽,以及配备有雷达、 信号干扰机 和 无人机捕捉技术 的地面反无人机系统,用于打击具有流氓或危险行为的无人机。必须通过地理围栏指定并强制执行关键基础设施和建筑物(如政府大楼、机场或监狱)上空的禁飞区。将所有这些与现有的建筑环境相结合,并为其运作创建必要的监管框架,将对建筑师、城市规划者和决策者的日常实践产生重大影响。
高度自动化的无人机操作将需要固定的起降坞站,集成充电或加油系统。这可能是一个放置在建筑物顶部的移动或永久车站,与现有的交通基础设施或其他类型的基础设施(如小型车站的灯柱)相结合。这些扩展坞很可能会集成电池充电功能。鉴于大多数发达国家的能源政策,必须考虑和认真规划飙升的电力需求对电网和相关排放的影响。
例如,私人拥有无人机的成本可能比租赁无人机的成本要高得多,尤其是对于那些可能只需要无人机执行单一任务的公司。然而,随着全市租赁系统的到位,城市、公司和用户将不需要购买无人机,有效地在他们之间分配成本。因此,基于遍布城市的无人机港口(或站)系统规划无人机租赁服务是必要的。通过提供在无人机站等待的分布式自主无人机的公共无人机租赁服务,这可以减少空中无人机的总数以及利用无人机完成城市服务、公民和其他用户请求的任务的总成本。这意味着有必要解决许多其他问题中的下列问题:
- 在哪里放置扩展坞?
- 他们有多少人?
- 凭什么能力?
设施选址问题
上述问题可以在数学优化的帮助下得到解答,特别是用线性规划如果公式化为容量受限设施选址问题。
后者是为工厂、仓库、发电站或其他基础设施选址的经典优化问题。一个典型的设施选址问题涉及在潜在可用的地点中确定最佳地点,服从特定的约束,该约束要求在几个地点的需求由开放的设施服务。与此类计划相关的成本包括通常与从设施到需求地点的距离总和成比例的部分,以及与设施的开放和维护成本成比例的部分。该问题的目标是选择设施位置,以最小化总成本。设施的服务能力可能有限,也可能有限,这将问题分为有能力和无能力两种情况。
给点上下文吧!
想象一下这样一种情况,我们的任务是为在埃里温市放置无人机停靠站草拟一份概念计划。具有城市中每日(每小时、每周或每月)名义需求的空间分布(出于演示目的,出租车需求被用作替代):
以及许多安装无人机站的潜在地点(在我们的示例中有 30 个):
我们如何确定放置扩展坞的最佳位置?嗯,这显然取决于成本。
第一类成本是购买和安装扩展坞。为了简化问题,让我们假设 Alonso 的单中心城市模型,根据该模型,房地产价格随着与中央商务区的距离增加而按照某种指数或幂衰减规律下降:
这显然是一种权衡:虽然大部分需求在空间上集中在中心位置(见需求图),因此在中心位置安装扩展坞以降低传输成本是有意义的,但相反,我们会因选择中心位置而产生更高的成本(虽然价格是根据一些常识选择的,但它们仅用于演示目的)。
第二类成本是操作无人机的成本,可以安全地假设这与飞行距离成比例。然而,这里事情变得有趣了,**这些距离将取决于底层(实际上是上层所在)的城市空中交通路径方式!**在下图中,我们可以看到空中交通简单配置的两个例子,笛卡尔网格( A )和迷宫式布局( B ):
让我们再看两个例子:上面网格的最小生成树,通常用于在通信网络中建立物理线路以减少总线路长度,以及实际的埃里温街道网络,因为现实场景之一是无人机将直接在现有街道网络上方运行,以减少视觉污染并出于安全原因( D )。
由于四个空中交通路径系统如此不同,我们可以直观地预期无人机站选址问题的解决方案也会产生差异。
数学公式
为了验证这一点是否正确,解决方案之间的比较,以及这对未来的城市规划者和交通工程师意味着什么,我们需要解决一个线性优化问题。考虑 n 个客户 i = 1,2,…,n 和 m 个地点放置无人机对接站 j = 1,2,…,m 。将连续变量 Xij ≥ 0 定义为从无人机站 j 到客户 i 的服务量,如果无人机站安装在位置 j 处,则定义为二进制变量 Yj = 1 ,否则定义为 Yj = 0 。容量受限的设施位置问题的整数优化模型现在可以公式化如下:
该问题的目标是最小化无人机站安装成本和无人机运行成本的总和。第一组约束要求严格满足每个客户的需求。每个无人机站 j 的能力受到第二组约束的限制:如果安装了无人机站 j ,则考虑其能力限制;如果没有安装, j 满足的需求为零。第三组约束强加了可变的上限。尽管它们是多余的,但它们产生了比等价的较弱公式更严格的线性规划松弛(线性规划的很好的介绍可以在这里找到)。为了直观地了解这些问题是如何解决的,这篇维基百科文章提供了一个相当好的初步概述。幸运的是,有许多优秀的数学优化求解器。让我们看看如何用 Python 自己编码:
from pulp import *
COSTUMERS = positive_flow_inds # the demand vector
potential_stations = np.random.choice(COSTUMERS,30) #choose 30 potential sites
STATION = ['STATION {}'.format(x) for x in potential_stations]
demand = dict(polyflows[polyflows.inflow>0]['inflow']) #setting up the demand dictionary
STATION_dict = dict(zip(STATION, potential_stations))
#installation cost decay from center (given a vector of distances from a central location)
costs_from_cen = 150000 - 1.5*dists_from_cen**1.22
install_cost = {key: costs_from_cen[val] for key, val in STATION_dict.items()} #installation costs
max_capacity = {key: 100000 for key in FACILITY} #maximum capacity
#setting up the transportation costs given a distance cost matrix (computed as pairwise shortest paths in the underlying air
#traffic network)
transp = {}
for loc in potential_stations:
cost_dict = dict(zip(COSTUMERS, costmat_full[loc][COSTUMERS]))
transp['STATION {}'.format(loc)] = cost_dict
# SET PROBLEM VARIABLE
prob = LpProblem("STATIONLocation", LpMinimize)
# DECISION VARIABLES
serv_vars = LpVariable.dicts("Service",
[
(i,j) for i in COSTUMERS for j in STATION
], 0)
use_vars = LpVariable.dicts("Uselocation", STATION, 0,1, LpBinary)
# OBJECTIVE FUNCTION
prob += lpSum(actcost[j]*use_vars[j] for j in STATION) + lpSum(transp[j][i]*serv_vars[(i,j)]
for j in STATION for i in COSTUMERS)
# CONSTRAINTS
for i in COSTUMERS:
prob += lpSum(serv_vars[(i,j)] for j in STATION) == demand[i] #CONSTRAINT 1
for j in STATION:
prob += lpSum(serv_vars[(i,j)] for i in COSTUMERS) <= maxam[j]*use_vars[j]
for i in COSTUMERS:
for j in STATION:
prob += serv_vars[(i,j)] <= demand[i]*use_vars[j]
# SOLUTION
prob.solve()
print("Status: ", LpStatus[prob.status])
# PRINT DECISION VARIABLES
TOL = .0001 #tolerance for identifying which locations the algorithm has chosen
for i in STATION:
if use_vars[i].varValue > TOL:
print("Establish drone station at site ", i)
for v in prob.variables():
print(v.name, " = ", v.varValue)
# PRINT OPTIMAL SOLUTION
print("The total cost of installing and operating drones = ", value(prob.objective))
四个解决方案
解决上述优化问题产生了配置 A 和 B 的以下解决方案:
对于 C 和 D :
现有街道网络配置的小动画,用于说明系统动态:
我们从图中看到,尽管所有四种布局都有一个共同的优化模式,无人机站的最佳数量大致相似(从 8 到 11),大型供应商站的空间聚类也相似(较大的圆圈表示较大的供应量),但最佳位置和需求覆盖区域(以颜色显示)有很大不同!
这意味着空中交通路径设计的微小变化会对无人机站的最佳位置、每个站覆盖的地理区域以及不同区域的空中交通量产生巨大影响。我们也可以看看每个航空系统的最佳总成本。特别是,我们发现最好的路径系统是笛卡尔网格(~ 250 万美元),然后是现有的街道网络(~ 410 万美元),然后是迷宫系统(~ 450 万美元),最差的是其最小生成树(~ 600 万美元)。我们看到结果暗示了未来规划者将不得不面对的权衡:成本对安全对美观对实用性。
结论
在这篇文章中,我们试图提高建筑师、城市规划者和政策制定者对无人机技术即将给我们的城市带来的巨大变化的认识和警觉。我们研究了埃里温的案例,并解决了一个简单的数学优化问题,以找到无人机停靠站的最佳位置来满足需求(包括商业和城市运营,如紧急服务)。我们看到了城市空间规划的差异如何对上述问题的解决产生巨大影响。与城市街道空间不同,城市街道空间的大部分存在都是逐渐演变的,城市空气空间必须在相对较短的时间框架内进行规划、设计和部署。
在现实环境中解决设施选址问题时,显然会有更多的变量需要考虑,这使得优化问题更难解决。例如,在我们的例子中,我们假设了一次性需求结构,而在大多数现实世界的设置中,需求是不稳定的,需要随机优化。
然而,这篇文章的目的不是提供解决无人机站选址问题的手册(让我们把它留给运筹学专业人士),而是展示它对城市空间和移动性的影响,并指出扩展城市规划者和其他城市爱好者兴趣范围的必要性。
附注:你可以在这里找到更多关于主题的信息。
基于 Python 的城市物流网络仿真
使用 SimPy、OSMnx 和 fleet . js 构建 Anylogic 的 GIS 功能
Anylogic 可能是目前最流行的物流应用模拟软件包之一。一个非常好而且非常独特的特性是可以将 GIS 地图包含到模拟模型中。它允许在地图上放置模拟元素,并根据真实的空间信息沿现有路线移动它们。这很酷,因为它可以用来模拟整个供应链,包括为复杂的问题提供一个伟大的,有形的可视化的手段。例如,项目使用 Anylogic 评估法国格勒诺布尔市中心更可持续的城市物流网络的不同设计和交付方案。数据驱动的模拟模型允许计算多层供应链网络中各种转运节点位置和不同类型运输设备的 KPI。
随着该功能的成功,Anylogic 的家伙们甚至构建了anylistix,将预先构建的&可定制模拟模型与商业求解器相结合,用于集成供应链规划&优化。
显然,那些商业特性是有代价的,所以我们来看看这种模式是否也可以用不同的手段来实现。
场景和范围
这个职位的模拟模型将基于一个小型的案例研究。
面对人类越来越习惯于甚至是日常必需品的送货上门这一事实,汉堡阿尔托纳的法国面包店 Die Patisserie 想要为附近的顾客提供甜点。
确定了 3 个主要购买者:失物招领处中央基金会、猴子音乐俱乐部和出版社卡尔森出版社。
不同位置的坐标(纬度、经度):
- 法式蛋糕店(53.55668,9.92815)
- 中央公园(53.55817,9.92829)
- 猴子音乐俱乐部(53.55706,9.93161)
- 卡尔森出版社(53.55703,9.92684)
为了简单起见,假设访问节点的顺序是固定的。旅游的起点和终点都在蛋糕店(1。):
作为旅程的一部分要访问的节点
仿真模型
简单场景的模拟模型是通过以下方式创建的:
- 用于检索地理信息和计算最短路径的 OS mnx/networkx(Python)
- SimPy/Casymda 用于模拟游览(Python)
- 基于浏览器的动画(JavaScript)的传单. js
1.OSMnx
令人惊叹的 OS mnx T1 包提供了从 OpenStreetMap 获取街道网络的 T2 网络图 T3 的可能性。通过指定要包括的 OSM 节点的中心和距离,可以获得我们场景的相关部分:
CENTER = (53.55668, 9.92815)
DISTANCE = 300
G = ox.graph_from_point(CENTER, distance=DISTANCE, network_type='drive')
OSMnx 让我们为旅游的 4 个地点中的每一个选择最近的 OSM 节点,并且还提供了绘制网络的方便方法。蓝点代表由边连接的 OSM 节点。4 个相关位置以红色显示:
提取的街道网络的 OSMnx 图
为了准备仿真模型所需的所有信息,现在使用 networkx 计算网络中 4 个相关节点之间的所有最短路径,并且包括每条路线的所有分段线性段的详细信息。结果被保存到磁盘上,以避免每次运行模型时进行提取和重新计算(当然,这也是为了尽可能降低 OSM 服务器的负载)。
上述方法可以被改进,例如,通过从给定的相关位置自动确定要加载的区域。不是为每个相关位置选择最近的 OSM 节点,而是首先寻找网络中最近的边会更精确。随着网络规模的增长,从 OSM 服务器直接查询相关节点之间的最短路径可能是一个更好的主意,而不是获取整个网络(Anylogic 似乎就是这样做的)。
2.Casymda/SimPy
Casymda 在 SimPy 之上提供了基于块的离散事件模拟模型建模。
我们的模型可以用一个简单的流程来描述:
模拟的流程模型
卡车实体在参数化的Source
中创建,然后在自定义的DriveTour
模块中处理,该模块包含根据路线长度和卡车移动速度计算时间的逻辑。它还提供了为动画计算中间实体位置的选项(时间间隔取决于模拟运行的实时因子)。模拟模型也可以在不调度任何动画相关行为的情况下运行,以最小化执行时间。要访问的节点及其顺序通过文本注释stops=["ZFB", "MMC", "CAV"]
指定。
动画是通过 flask 暴露信息和资源实现的(类似于本帖中描述的基于 tile-map 的动画)。
3.传单. js
为了可视化地图上节点和实体的位置,传单只需要几行。为了设置旋转角度,有一个旋转。标记插件满足我们的需求。
marker = L.marker(element.coords, { icon: new L.Icon({iconUrl: element.icon_path}) }).addTo(map);
marker.bindPopup(element.text);
marker.setRotationAngle(element.direction);
结果
从克隆的存储库中通过 http://localhost:5000 运行模拟:
docker-compose up geo-web-animation
下面的截屏显示了一辆卡车按照定义的顺序( Patisserie —失物招领—Monkey ’ s—Carlsen Publishing—Patisserie)访问所有节点的完整旅程。单行道被正确地考虑在内,例如当从猴子音乐俱乐部 (3。,最右边的节点)到卡尔森出版社 (4。最左边的节点)沿着线。
基于浏览器的动画的屏幕截图