用计算机视觉理解新冠肺炎对交通的影响
实践教程
用 Python 和 OpenCV 分析新加坡的交通
ovid-19 深刻影响了我们生活的方方面面,从全球供应链到我们的工作方式。在疫情期间,大多数国家都在不同程度的限制下实施了某种形式的封锁。这些封锁的一个有趣的方面是对世界不同地区日常生活的影响,最常见的预防措施之一是留在家中的命令。新加坡作为一个人口密集的城市国家和岛屿,为观察这些影响提供了一个有趣的测试案例。这两个因素,加上强有力的政府干预,应该为这些影响提供了充分的证据。通过使用政府的交通摄像头数据库和计算机视觉,我们将试图了解城市中心附近的交通如何受到并仍然受到整个疫情的影响。
这篇文章的重点是回答以下问题:
新冠肺炎对新加坡的交通有影响吗?如果是,影响是什么,是什么造成的?
本文中的代码是用于解释目的的补充工具,已经从原始代码中进行了缩写和略微修改;这不是一次演练,而是如何解决问题的一个可能的脚手架。如果您只是对数据感兴趣,请随意跳到结果部分。
数据收集
ingapore 拥有一个令人难以置信的公共数据库,涵盖了城市及其功能的方方面面。你可以去参观:https://data.gov.sg/。该项目利用由陆路运输管理局管理的交通摄像头部分。该 API 允许用户指定时间戳,并返回城市中每个摄像机的所有数据。我们可以使用 python 中的请求库来指定时间戳,并接收一个 JSON 对象,该对象包含所有摄像机的位置和视频帧。
返回的 JSON 对象是每台摄像机和各种数据的列表,包括位置、视频帧的链接和一些关于图像的元数据。我们对三个方面最感兴趣:
- camera_id —嵌套在相机键内的相机数组中
- image:一个 URL,包含摄像机当时看到的图像
- 位置:相机的 GPS 线,嵌套在相机对象中
为此,需要对 JSON 响应进行规范化和解析。这可以通过熊猫图书馆来完成,它将用于管理我们的数据。
这将给我们留下一个 87 行 8 列的熊猫数据帧。
前十行
这个数据帧是对于给定的时间戳,城市周围的所有 摄像机的 。为了减少收集的数据量并控制范围,我们将把摄像机的数量限制为 1702 和 1711。它们位于璧山区和实龙岗区之间的 CTE 高速公路上。在主干道上,交通的任何显著变化都应该很容易被发现。下面是每个摄像机看到的一个例子。
照相机 1702 例子
照相机 1711 的例子
下一步是建立一个测量流量模式的时间框架。选择了 2019、2020 和 2021 年从 3 月 1 日到 5 月 1 日的两个月时间,以每三分钟为增量。选择这一点有三个主要原因:
- 包含三年的时间框架可以实现 COVID 之前、之中和之后的评估,其中 2019 年作为正常流量模式的示例。
- 这个时间框架在封锁方面也很重要-因为最严格的措施是在 2020 年 4 月推出的,限制将在 2021 年取消。
- 将时间范围限制为每三分钟,可以更好地管理要标记的图像数据集。
使用 pandas,可以建立批量请求的框架。首先,用 date_range 函数制作时间戳的数据帧:
其次,将时间戳格式化成可以传递给 API 的格式。
现在我们有了要循环的日期,我们可以利用并发库使用 futures 函数进行并发请求。未来的库通过创建不同的工人,使批量请求数据变得容易得多,这些工人可以彼此并行地进行请求。关于如何使用期货的一个很好的指南可以在这里找到。
下面是将要使用的功能的基本概要。Fair wairing:每个电话仍然需要大约 2 个小时才能完成。
这将产生一个包含所有响应的庞大列表。下一步是按 camera_id 列对响应进行排序,并将它们保存为各自的. csv 文件。我还建议将原始列表保存为 DataFrame,以便以后需要时可以引用。(因此,如果我们想在未来研究其他相机,我们不必重复 2019 年的 API 调用。)
2020 年和 2021 年重复这些步骤,总共留下 6 个单独的文件,每个相机 3 个。请求部分的总运行时间约为 6 小时。我们现在有了图像的链接,可以继续从数据库中抓取图像了。为了获取图像,我们将使用与之前相同的结构来进行并发调用,但是首先,加载上一步中创建的数据帧。
加载数据帧后,我们可以编写新的请求函数和并发请求框架。
关于上面的代码块及其输出,有几点需要注意。首先,我们正在抓取大量图像;所以要确保有足够的空间来存放它们。第二,每个呼叫大约需要 1.5 到 2 个小时,具体取决于定义的工作人员数量。
收集完图像后,我们就可以开始生成数据了。我们将使用 OpenCV 并利用 google 提供给 Colab 用户的 GPU 能力。为了做到这一点,我建议按照这个教程来设置 OpenCV,以便在 colab 环境中使用 GPU 来加速图像的标记。
设置完成后,多亏了 OpenCV,标记图像变得相当简单。
OpenCV_example.py 的输出
关于如何设置 detect_common_objects 函数,有一些重要的注意事项:
- 你可能已经注意到,它既没有标记图像前面的模糊汽车,也没有标记旁边的汽车。这是因为默认过滤级别为 0.5。置信度值低于 0.5 的任何对象都不会被认为可以防止误报。通过在函数调用中定义 nms_thershold,可以将该级别调整为所需的任何级别。更多信息可以在这里找到。
- 您可以使用 model 关键字修改在其中对模型进行训练的标记数据集。然而,YOLOv4 非常适合这项任务。如果你有兴趣了解更多,这里有一个 YOLOv4 结构和设计的链接。
我们的基本工作流现在已经设置好了,我们可以编写函数来处理 2019 年数据集中的所有图像,并建立一种方法来跟踪标签并将它们添加回数据帧。
接下来,我们可以使用该函数遍历收集的所有数据,并生成可用于分析的标签数据帧。下面是摄像头 1702 的 2019 年图像的通话情况。
然后,我们对每一年和每一台相机重复这一步。最后,我们准备开始做一些分析!如果您已经完成了数据采集过程,我想澄清几个可能出现的问题。
- 数据集仅限于调用 api_imageRequest 函数返回的内容。我使用了一个 try-expect 块,这样即使调用失败,它也不会抛出错误,并且不是所有的时间戳都有有效的图像可以提取。因此,您的数据集可能与我生成的数据集有所不同,但流量数据的总体趋势应该仍然相对相似。此外,抓取 2021 年的图像导致图像减少了约 35%,这很可能是在数据库方面。
- 为什么我们没有在 get_label_count 块中定义要计数的标签?我们想跟踪摩托车、卡车和任何可能在路上行驶的车辆。虽然人或其他物体有可能被计算在内,但由于每个数据集包含数以千计的图像,因此它对流量的整体趋势只会产生极小的影响。
- 下载图片时,3 月 17 日和 18 日 1711 相机的 2019 都不完整。严重缺乏白天的图像导致那些日子的数据不准确。经过调查,在此期间进行了定期维护,这可以解释异常现象。我们通过替换在数据分析部分对此进行了说明。
数据分析
在进行探索性数据分析时,记住我们在项目开始时提出的“全局”问题并使用这些问题来指导过程是很重要的。
【COVID 对新加坡的交通有影响吗?如果是,影响是什么,是什么造成的?
第一步是加载所有以前收集的数据,并开始将其聚合成我们可以使用的东西。
关于编码示例的注意事项:我们将查看相机 1711,因为它提供了一些有趣的挑战(如上所述),然而,相同的步骤应用于相机 1702 以生成本文中的图形。
在数据被加载之后,我们可以通过添加一个名为“num_cars”的新列来将标签 DataFrame 与原始数据合并,该列表示生成的标签。
我们还可以继续修改“时间戳”列,这对以后的重采样很重要。
通过运行。在我们的每个数据帧上描述(),我们可以了解我们正在处理的数据。
从该输出中得出的最重要的细节之一是 2020 年到 2021 年的计数差异。虽然大约 13k 的数据点仍然为这种分析提供了典型的流量模式,但实际上不可能比较总计数。
下一步是了解我们数据的形状,我们可以通过观察标签的频率来做到这一点。这使我们对交通模式的分布有了一个大致的了解。我们将使用 pandas 的 count_values()函数来生成这些数据。
我们使用 normalized 关键字来获得标签的比例,而不是精确的计数,然后将它们四舍五入到最接近的百分之一,以使绘制它们更容易!
一定数量汽车的车架比例
我们可以从图表中看到,2020 年和 2021 年,较大流量急剧下降,空帧或稀疏帧大幅增加。这些图表提供了一个很好的概览,并显示了很大的差异。然而,为了得出有意义的结论,处理当前数据集的一些问题是很重要的。
每年之间数据点数量的差异和偏斜分布使得很难知道到底发生了什么。我们可以对数据进行重新采样,以更好地了解整个人口,并进行时间序列分析。由于我们的数据是有时间戳的,panda 内置的重采样工具是获取时间序列的有效方法。为了处理年份之间的计数差异,我们将避免任何依赖于总计数的度量,而是使用描述数据的度量,如平均值、最大值和中值。
如上所述,2019 年的数据集存在问题。3 月 17 日和 18 日显示异常低值。我们可以使用列索引将其与数据集中的其他日期进行比较。
确定异常值是否是真实数据点的一个重要部分是查看生成它们的元素——在这种情况下,是图像。在对图像进行了一些检查之后,很明显,在那些日子里,大量的图像丢失了,而 serval 实际上是维护消息。
从数据库返回的维护消息
因为我们已经确定这两个数据点很可能不具有代表性,所以可以用几种不同的方法来解决这个缺失的数据。一种方法是尝试只在那几天再次请求映像,但是如果维护是他们捣乱的原因,这将不起作用。另一种方法是使用数据集中的其他星期日和星期一来生成值。这种方法将给出一个合适的近似值来代替缺失的数据,并且可以通过将这些天的平均值作为每个测量值的替代来实现。
准备好数据集后,下一步是可视化数据。如上所述,我们应该对数据的形状有一个概念,因为它将指导未来的步骤和统计测试。我们将使用箱线图来理解数据的形状,并使用 pyplot 的 subplot 函数来为两台摄像机生成信息丰富的紧凑视图。生成可视化后,将上下文应用到数据中以真正理解每个图表所表达的内容是很重要的。
- 中位数——这是一个很好的指标,可以衡量在任何给定的时间你在路上会看到多少辆车。
- 均值-也是在任何给定时间你期望在路上看到的东西的度量,但它更容易受到异常值的影响。
- max——当天一帧中的最大汽车数量,这是衡量交通高峰的一个很好的指标。
我们可以收集到一些东西(新冠肺炎)在 2020 年引起了巨大的变化,展开数据:每个指标都有总体下降的趋势。平均值的线形图可用于观察这一趋势。
理解数据
很明显,这两个地点在 4 月 7 日左右显示出 2020 年的急剧下降,这与总理的“电路中断”相吻合,该中断大大限制了旅行,并呼吁所有个人限制在公共场所聚集。每个摄像头都显示,除了 4 月 27 日星期一之外,本月剩余时间的平均流量大幅减少了 50%。虽然当天没有重大新闻或事件,但数据与其他周一一致。这一减少证明了疫情及其相关政策极大地减少了交通流量。
交通流量似乎还没有恢复到 2021 年疫情之前的水平。这个假设可以用单侧韦尔奇 T 检验来检验。这个统计测试将有助于了解每年的流量水平是否实际上在变化,并且不在变化范围内。我们将测试数据集的平均值(道路上汽车的平均数量)和最大值(高峰业务),以了解全貌。Scipy 库的。ttest_ind() 函数提供了一种简洁的方法。
运行 T-test 函数会给出两个输出:T-stat 和 P-value。T-stat 表示两个样本组差异的方向和水平,P 值表示确定性水平。在这种背景下,负 T-stat 意味着 2021 组小于 2019 组。确定性是 P 值减 1,或我们确定存在差异的程度。确定性值> 95%被认为是显著的。将所有这些放在一起,对于每个测量,两组在每帧的平均汽车数量以及最大数量方面显示出统计上的显著差异。
在该项目中,两个交通摄像头与 OpenCV 结合使用,以了解新冠肺炎疫情对新加坡交通的影响,包括 2020 年 4 月交通流量减少 50%,以及统计测试,以提供新加坡交通仍未恢复到疫情之前水平的证据。虽然不可能把一切都归咎于疫情,但有强有力的证据表明,疫情周围的政策和公众反应已经改变了新加坡最繁忙道路之一的交通状况。
提及和最终注释
这个项目的灵感来自于一个探索更有限的日期和时间范围的高级编码项目。这些项目是有指导的,但不会给用户任何代码,这使得它成为一种很好的实践方式,同时仍然提供了一个体面的挑战。我还想说,如果你自己做这个项目,你的数据集将很可能与我的不同,只是由于调用的数量和最终用户与数据库之间的通信。也就是说,数据的总体趋势和分布应该是相似的,因为我试图摆脱依赖于计数的测量。另外,对于那些对使用新加坡数据库感兴趣的人,你可以在这里找到条款和服务的链接!最后,感谢您花时间阅读这篇文章,我希望它能激励其他人。
理解面试官的心态
如何进入面试官的思维并在数据科学工作面试中表现得更好
作者在 Canva 上创建的图片
对于求职者来说,工作面试可能看起来像是单方面的相遇。他们问,我答。我说,他们听。他们很强大,我无能为力。他们有选择,我没有。
嗯,那通常是真的。采访者处于有利地位。他们隐藏在组织的背后,你自己去面对他们。除了你的知识,你的经验,你的个性,你一无所有。你只有你自己。他们有工作。你不知道。犯一点小错误,你的命运就掌握在他们的手中。
虽然在某种程度上这是对的,但也不完全对。尽管他们通常比你占优势,但这并不是说你完全无能为力。当他们试图理解你是如何做的时候,没有人说你不被允许去理解是什么让他们做的。
一旦你明白了这一点,你会发现你可以很容易地扭转局面。你就能把面试变成双方平等的对话。这样双方都可以得到他们想要的,而没有他们不得不翻身的感觉。那比妥协好多了。毕竟,妥协被定义为让双方都不开心的解决方案。
为了避免这种情况,我在这里来看看一些让面试官更人性化的事情。在理解了他们的不安全感之后,我会深入了解他们在面试中想要什么。最后,我会给你一些关于如何准备这种数据科学面试的建议。
是什么让面试官更有人情味?
这里有一个简短的汇总表,让你有个感觉。一会儿我会详细阐述这四点。
作者创造的形象
面试官也不喜欢面试。
在那里,你们至少有一个共同点。事实是,面试官和你一样讨厌面试。因为一些其他的原因,但尽管如此,感觉是一样的。
他们不喜欢面试,因为面试会让他们脱离工作。
然而,他们知道他们不应该让他们的时间表超过他们的专业水平。你应该能理解。你压力太大,没有工作,或者离开办公室去参加面试。如果你尊重面试官的时间,你可以让他们不那么讨厌这段经历。准时参加面试。做好准备,这样你对你的工作经历、公司等的回答。,更切题,也更省时。遵循面试结构,坚持面试官引导你进入的话题。这是你应该做的。但是如果面试官忽略了这三点,那么这三点也可能成为你的危险信号。
采访者通常也没有接受过进行采访的培训。他们中的大多数人在见到你之前,只会凭借他们的经验和纯粹的责任心去谷歌“如何进行面试”。就像你会利用你以前面试的经验和阅读大量关于如何在面试中表现出色的文章一样。甚至可能是一篇关于理解面试官心态的文章。
他们和你一样,害怕自己出丑。
他们不是在寻找最优秀的人。
我的意思是,他们试图找到理想的候选人。但是现实是理想最大的敌人。事实是,在给定的环境和限制条件下,他们试图找到最佳候选人。基本上,考虑到招聘的时间和预算,他们会寻找相当优秀的人。他们会将候选人的素质与获得他们所需的时间和金钱进行比较。如果他们有一个几乎拥有他们需要的一切的人,和一个稍微好一点但需要多几倍时间和金钱投入的人,公司可能会满足于第一个候选人。
当你认为你的经验、教育和知识不够时,你应该意识到这一点。你唯一应该做的就是突出你作为候选人的所有优点。你不需要完美,只要够好就行。完美是好的敌人。
他们不知道自己想要什么。
这些公司通常不知道他们在寻找什么,确切地说他们需要什么资格等等。
例如,公司可能认为他们需要擅长数据分析的人。但并不能保证他们知道自己需要哪些技能,数据分析会用到哪些工具等等。你知道当他们问你“你认为自己五年后会怎样”时,你有多纠结吗?对他们想要的候选人没有明确的想法表明他们也在这个问题上挣扎。
当你明白这一点时,你就更容易与面试官进行双向对话。他们没有必要试图在你的知识中寻找漏洞。不,他们通常想以专家的身份和你谈谈,看看你对你申请的工作理解如何。他们希望你帮助他们更清楚地了解他们需要什么,他们需要谁。例如,他们可能会询问您使用 PostgreSQL 的体验。也许他们会问这个问题,因为他们正在考虑过渡到这个数据库。在与他们的交谈中,您可以问一些关于数据量、他们想用这些数据做什么、数据库现在看起来如何的问题。从这一点出发,你可以谈论为什么 PostgreSQL 是一个好的选择。或者为什么其他数据库可能更适合他们的需求。也许是您更熟悉的 SQL Server。在这里,你是在帮助他们创造需求,而不是回应他们的需求。你在帮助他们找到最好的候选人:希望是你自己。
找到一个好员工并不容易。
不要以为你申请的所有工作都有比你优秀的候选人。不一定是这样。公司经常很难找到一名好员工,尤其是当他们经常与一些大型科技公司争夺候选人时。这意味着你并不像你想象的那样可以随意处置。当然,你不应该在面试时大喊,“你需要我,我知道你需要我!你,现在就雇用我!”。但重要的是要记住,很有可能公司需要你,就像你需要他们一样。
在某种程度上,所有这四点都显示了一些面试官和公司的不安全感了解某人的不安全感会让他们更有人情味。这让他们更像你。
现在你知道面试官(可能)的不安全感,他们不喜欢什么,不知道什么。我想我们该谈谈他们知道些什么的话题了。因为可以肯定的是,大多数面试官都在他们的候选人身上寻找一些特质。
面试官想要什么?
图片来自 Canva
无风险雇佣
理想情况下,他们寻找的是没有风险的人。当然,没有这样的候选人。但可以肯定的是,面试官的工作是雇佣风险尽可能低的人。
无风险雇佣意味着找到一个有值得尊敬的相关经验的人。面试官希望这种经历尽可能贴近公司的需求。如果他们找到了这样的候选人,很有可能这个候选人在新工作上的过渡会很顺利。这是合乎逻辑的;如果你正在处理你以前已经处理过的情况,机会是你学到了一些东西,你知道如何处理这些情况(更好)。再说一遍,如果有时间和金钱,无风险的候选人是他们能得到的最好人选。
他们也在寻找对工作环境有积极贡献的人。愉快共事的人。那些不把别人的成就归功于自己的人,那些在压力下不崩溃的人,那些在离开时不推卸责任的人变得强硬起来。
当然,他们在寻找一个对公司满意的人。一个会尽可能长时间贡献的人。如果他们发现你对和他们呆在一起不感兴趣,他们会犹豫是否在你身上投资时间和金钱。
即时贡献
说到贡献,这些公司真的希望找到一个能立即做出贡献的人。即插即用型员工。这通常发生在急需雇人的情况下。对于这种情况,找到一个可以立即做出贡献的人是一个理想的解决方案。
然而,有时不可能找到这样的候选人。或者公司有意雇用某人是因为他或她的潜力,而不是当前的知识或以前的经验。毕竟,即使是即插即用的员工也需要花一些时间来适应新的环境。也许学习使用一个新的核心系统,理解数据结构,业务的一些细节,或者公司本身。当然,如果你有经验,花的时间会少一些。但有时,公司希望建立在一个长期的时间尺度上,开发员工未来利益的潜力,并在某种程度上,从零开始按照员工的需求塑造他们。他们寻找的是学习的能力,而不是当前的知识。毕竟,大多数工作并没有那么复杂,因此,一些相当聪明的人,或者可能受过相关教育的人,无法学到所需的技能。当然,其中一些需要很多时间,但是公司有时愿意投资这些时间。
进步和良好的品牌
你如何选择你想去的公司?我相信你在考虑公司的形象和其他事情。同等条件下,在一家拥有某种声望和形象的公司工作总是更好。
求职者也是如此。面试官希望让他们的公司变得更好。在实践中以及在他人眼中也是如此。要做到这一点,他们会关注你曾经就读的学校和/或学院。通常,最受重视的大学是有原因的。在某种程度上,大学为他们做了最初的选择。虽然名牌大学不能保证一个好员工,但它至少(在某种程度上)保证了某人的知识和学习能力。
但是,总有但是!大学一般只有在你没有任何(或很少)经验的情况下才重要。在比较这样的候选人时,面试官必须根据你上的大学和你的成绩来评估你。在几乎所有其他情况下,经验胜过任何教育。雇主看的是你在实践中的能力。如果你以前在一些知名公司工作过,这看起来会稍微好一点。同样,和名牌大学一样,如果你不够优秀,你就不可能为这样的大公司工作。
不仅如此,它可能会给他们的公司带来一个有价值和有知识的员工。当公司可以吹嘘他们的数据科学团队如何如何时,这看起来也不错,比如说,FAANG 背景。
除了良好的品牌效应,雇主还希望在你的简历或数据科学求职信中看到一些进展。它可以是同一家公司内部的层级结构,也可以是更换公司。也有可能是你没有往上爬,但是隔几年就去了一家技术更先进、更有挑战性的公司。所有这些都表明你没有停滞不前。你表现出了变得更好和承担更多责任的意愿。这肯定是你的面试官会喜欢的。
匹配文化
已经有很多关于公司文化的文章。每个公司都认为自己是独一无二的,与其他公司相比,有着完全不同的公司文化。老实说,当谈到公司文化时,我们更多的时候是在谈论一些模糊的、通用的概念,这些概念是公司试图呈现给他们的独特概念。
他们不是。就像你对面试官说这样的话,你不会是独一无二的:
“我是一个优秀的团队合作者,但也非常独立。”
每个人都这么说。他们这样说是因为他们不知道面试官想听什么,所以他们试图涵盖一切。
如果你真的想引起面试官的共鸣并脱颖而出,你必须冒一点风险。不是某种盲目的冒险。如果你为面试做好了准备,并倾听面试官的暗示,你就能了解面试官在寻找什么样的合群。如我所说,没有那么多变化。所以,举例来说,如果你在面试过程中发现团队合作是至关重要的,那就专注于此。不要说你如何擅长团队合作,但也很独立。不,只关注团队合作。告诉他们你是一个优秀团队成员的故事。没有人会认为,由于你出色的团队合作,你完全依赖他人,而自己什么也做不成。
反过来也一样。如果公司刚刚起步,你必须自己解决很多问题,那么重点给出几个例子,让你看起来像一个高度独立的专业人士。这也并不意味着你是一个不想和任何人在一起并吓跑同事的隐士。
简单的语言
我知道这很诱人。你如此渴望向面试官展示你有多优秀,以至于尽可能地使用行话、流行语和性感的缩写。通常情况下,你无法完全避免。使用某些特定工作和/或行业的术语是很自然的。
然而,面试官通常不喜欢这样,因为这听起来像是在吹牛。甚至可能就像你在用时髦的词语来掩盖对这个话题缺乏实质性的了解。即使你不是因为这个原因才这么做的,也不要给面试官怀疑的理由。
能够用简单的语言解释你的工作和你所做的事情通常是一个人真正理解他们在谈论什么的标志。这不仅显示了他们透彻的理解,也显示了他们能够想出自己的解释,而不仅仅是使用其他人都使用的普通短语。
面试官喜欢听到简单的语言还有一个重要的原因。如今,对于数据科学家和所有其他从事数据工作的人来说,与背景、经历和知识大相径庭的各种股东交流变得越来越重要。跨部门协作是你无法避免的事情,而且越来越需要。这意味着你必须能够用一种不太专业的方式向那些甚至不熟悉你的基本工作的人解释一些事情。让他们加入的唯一方法是让他们理解你。如果你知道自己在做什么,如果你能解释清楚,他们就能做到——没有比求职面试更好的地方来展示这些特质了。毫不奇怪,面试官会问你类似的问题:“你会如何向一个 6 岁的孩子解释云技术?”。
如何准备这些面试
图片来自 Canva
研究你的雇主和面试官
你应该为面试做好准备。你不能总是为你会被问到的问题做好准备。但你必须做的是研究你的雇主。了解他们的产品、历史、行业、组织结构等等。
对你的面试官也这样做。如果你知道他或她的名字,试着对他们做一点研究。找到关于他们背景的信息:他们在哪里上学/大学,他们在哪里工作,他们的专业领域是什么。
这会显示出你对这家公司的兴趣,而且一旦你了解了这家公司的基本情况,谈论你未来的工作会更容易。熟悉面试官也有助于和他们建立联系,尤其是如果你们有共同点的话。
了解公司文化
这是你只有在他们的网站上阅读文化才能大致理解的事情。正如我所说的,这通常包括可能意味着任何事情和没有任何事情的一般性陈述。更重要(也更难)的是,试着从你参加面试时看到的和从面试官那里学到的东西中“感受”公司文化。你没有太多时间去做那件事,但是你可以得到一些线索。办公室看起来是空的还是挤满了人?人们是独立工作还是团队工作;有时,这是可能的,尤其是如果它是一个开放空间的办公室。办公室是不是显得很安静,还是充满了人们的喋喋不休?交流是显得冷淡专业,还是很轻松?
这些只是一些建议。但是最重要的一点是,当你参加面试的时候,要睁大你的眼睛,竖起你的耳朵,倾听你所听到的和看到的。尤其是面试官发出了什么样的信号。适应他们。
了解工作类型
这是你事先只能部分知道的事情。你可以试着从职位描述、做互联网调研等方面去了解工作类型。但你不可能什么都懂。这就是为什么为面试准备一些关于工作类型的问题是很重要的。例如,我是在团队中工作还是独自工作?这-和-这必须从头开始设置还是仅仅改进?你使用什么技术?你打算使用什么技术?
作为一名数据科学家,了解你在工作中必须做的工作类型的最佳方式是通过我们为你准备的一些非编码和编码问题。
当然,在面试过程中你会想到一些其他的问题。这些问题的意义不仅仅在于表明你有问题要问。这是为了更清楚地表明对你的期望。作为一个(非常令人向往的)副作用,你会表现出你理解这份工作和这个行业(可能)存在的问题。此外,有了这些问题,你就有了一个框架,来回答那些你无法准备、只能在与面试官交谈时提出的问题。
准备好个人故事
不,我不是说你第一次看《小王子》的时候是怎么哭的。尽管这也不应该被排除在外。尤其是如果面试官问你最喜欢的书是什么。
我想更多的是展示面试官想要的技能的个人故事。也许是一个关于你如何在项目中途被任命为项目负责人以及你如何处理此事的故事?或者,即使你是一名经济学家,你是如何从事数据科学的?或者你是如何成为某个初创公司的第一名员工的,当时的 job 和现在公司雇佣 30 人的 job 有什么区别?
看,这些故事都很有用。它们会告诉你很多关于你的事情。只有一个这样的故事可以概括你的个性,你如何处理逆境,你的数据科学技术技能,软技能,你的沉着,机智,幽默,口才,甚至对生活的整体看法。通过讲述个人故事,你会以一种非直接的方式做到这一切,而不是吹嘘和无聊地提供你擅长的事情的清单。讲一个故事,让面试官总结他们是否喜欢听到的内容。
在面试之前,想出 4-5 个有趣的故事,突出你做得好的事情。
做你自己
我承认,对此毫无准备。你要么是你自己,要么不是。即使你不是你自己,那也是你自己。但是我们不要太哲学化了。我想说的是:要真实。是的,做好准备。试着读懂面试官的暗示。但是不要刻意去让他们喜欢你。不管你怎么想,人们通常会看穿这一点。很有可能,你会完全弄错。即使你在面试中骗过了他们,当你开始工作的时候,你会被发现,很快,你就会失业。
那没有意义。做你自己总是更好,诚实地回答,用你的方式说话,用你的方式思考。你应该努力展现自己最好的一面。不是别人的最佳版本。
摘要
理解面试官想法的第一步是接受面试官也是人。他们比你想象的更像你。他们不喜欢面试;他们可能缺乏安全感,不确定自己在寻找什么。当然,他们不是在寻找一个完美的员工。通过理解这一点,你将帮助自己打破带着恐惧或某种理想化接近面试官的习惯。一旦你意识到他们并不完美,就更容易与他们建立双向的融洽关系。
其次,你需要明白他们在找什么。他们正在寻找一个风险尽可能低的人。他们也希望有人能立即做出贡献。或者,如果没有,愿意学习的人。最重要的是,他们想要一个能与其他人和谐相处的人,一个能让工作场所尽可能愉快的人。最后,拥有令人尊敬的教育和/或工作背景对公司形象总是有好处的。
最后,明白这一点后,你需要有一定的策略来引起面试官的共鸣。这基本上可以归结为面试时的准备和警觉。你应该研究公司和面试官。确保研究公司的文化,并就地吸收。对某一类型的工作做研究,准备一些问题,并准备好在面试中根据你对这份工作的了解来提问。准备几个展示你的技术和软技能的故事。一旦你做好了所有的准备,放松,做你自己。如果做自己就是不放松,那也没关系。
最初发表于【https://www.stratascratch.com】。
了解 n_jobs 参数以加速 scikit-learn 分类
数据分析
一个现成的代码,演示了如何使用 n_jobs 参数来减少训练时间
作者图片
在本教程中,我说明了由scikit-learn
库的一些类提供的n_jobs
参数的重要性。根据官方的scikit-learn
库,n_jobs
参数描述如下:
为邻居搜索运行的并行作业的数量。除非在 joblib.parallel_backend 上下文中,否则 None 表示 1。-1 表示使用所有处理器。
这意味着n_jobs
参数可以用来分配和利用本地计算机中所有可用的 CPU。
在本教程中,我通过将n_jobs
参数从 1 变化到 CPU 的最大数量,来评估适应 scikit-learn 库提供的所有默认分类数据集所需的时间。作为例子,我将尝试一个带有交叉验证的网格搜索的 K-Neighbors 分类器。
定义辅助变量
首先,我定义了所有分类数据集名称的列表,包含在 sklearn.datasets 包中。
datasets_list = ['iris', 'digits', 'wine', 'breast_cancer','diabetes']
然后,我计算系统中可用的 CPU 数量。我利用了os
包提供的cpu_count()
函数。
import os
n_cpu = os.cpu_count()
print("Number of CPUs in the system:", n_cpu)
就我而言。CPU 的数量是 4 ( 一台相当旧的电脑,唉…我应该决定造一台更新的… )
我还定义了网格搜索的所有参数。
import numpy as np
parameters = { 'n_neighbors' : np.arange(2, 25),
'weights' : ['uniform', 'distance'],
'metric' : ['euclidean', 'manhattan',
'chebyshev', 'minkowski'],
'algorithm' : ['ball_tree', 'kd_tree']
}
定义主要功能
现在,我准备定义 main 函数,它将用于测试训练所用的时间。我导入所有需要的函数和类:
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import *
import time
我定义了load_and_train()
函数,它接收数据集名称作为输入。为了加载相应的 dataaset,我利用了globals()
函数,它包含一个包含所有导入函数的表。因为我已经导入了 scikit-learn 提供的所有数据集,所以我可以将函数名传递给globals()
函数。语法是:globals()[<function_name>]()
。
def load_and_train(name):
dataset = globals()['load_' + name]()
X = dataset.data
y = dataset.target
一旦加载了数据集,我就可以构建一个循环,通过改变 CPU 的数量来遍历 CPU 的数量并计算训练所用的时间。我构建了一个包含所有运行时间的列表,最终由函数返回。
tdelta_list = []
for i in range(1, n_cpu+1):
s = time.time()
model = KNeighborsClassifier(n_jobs=i)
clf = GridSearchCV(model, parameters, cv = 10)
model.fit(X_train, y_train)
e = time.time()
tdelta = e - s
tdelta_list.append({'time' : tdelta, 'bin' : i})
return tdelta_list
绘图结果
最后,我为所有数据集名称调用load_and_train()
函数,并绘制结果。
import matplotlib.pyplot as plt
import pandas as pdfor d in datasets_list:
tdelta_list = load_and_train(d)
df = pd.DataFrame(tdelta_list)
plt.plot(df['bin'], df['time'], label=d)
plt.grid()
plt.legend()
plt.xlabel('N Jobs')
plt.ylabel('Time for fit (sec.)')
plt.title('Time for fit VS number of CPUs')
plt.show()
作者图片
对于所有数据集,通过增加作业数量来减少对 K 近邻分类器执行具有交叉验证的网格搜索所花费的时间。为此,我强烈建议您使用n_jobs
参数。
具体来说,我建议设置n_jobs=n_cpus-1
,以免机器卡死。
摘要
在本教程中,我演示了如何使用n_jobs
参数来加速训练过程。
本教程的完整代码可以从我的 Github 库下载。
现在 Medium 提供了一个新特性,即它允许构建列表。如果您喜欢这篇文章,您可以将其添加到您的收藏列表,只需点击按钮,放在文章右上角的按钮:
作者图片
如果你想了解我的研究和其他活动的最新情况,你可以在 Twitter 、 Youtube 和 Github 上关注我。
相关文章
透过数据的镜头理解疫情
多伦多当前新冠肺炎病例的探索性数据分析
介绍
2019 年 12 月,中国武汉发现首例新型病毒。世卫组织和中国当局确认了人际传播。不久之后,它被宣布为全球疫情。这当然是新冠肺炎,一种由新型冠状病毒引起的高传染性疾病。自那以来,我们已经取得了长足的进步,目前已有超过 1 . 05 亿人受到感染(截至 2021 年 2 月)。全球病例仍在增加,一些国家采取了一些限制措施。
为了更好地了解正在进行的疫情,一些研究人员开始分析现有的数据,以提取有价值的见解。在这篇文章中,我将分析多伦多 Covid 病例的公开数据。目标是结合新闻报道来理解这些数据所提供的信息。
数据源
多伦多市的开放数据门户是一个伟大的倡议,它提供了大量的数据集来探索和了解多伦多市是如何工作的。特别是在这个项目中,我接手了新冠肺炎病例,它包含了向多伦多公共卫生部门报告的所有病例的人口统计和地理信息。该数据每周更新,当前分析包含截至 2021 年 2 月 1 日的数据。
探索性分析
数据集由 83474 个点和 18 个要素组成,其示例如下所示。截至 2021 年 2 月 1 日,我们有 80,775 例确诊病例和 2699 例疑似病例。
前五点来自于数据中的一些特征
自 2020 年 1 月起每月报告的病例数
自 2020 年 1 月起每月报告的死亡病例数
上图显示了自疫情开始以来每月报告的病例总数和死亡病例数。我们可以清楚地看到两波,第二波仍在进行中。8 月份结束的第一波高潮出现在 4 月份。第二波似乎感染了更多的人群,但导致死亡病例减少。这表明,从第一波开始,我们已经学会更好地应对疫情。自疫情开始以来的每日案例如下所示。
自疫情开始以来的每日病例
现在让我们了解一下各年龄组的病例分布情况。
:考虑的年龄组有 0-19 岁、20-29 岁、30-39 岁、40-49 岁、50-59 岁、60-69 岁、70-79 岁、80-89 岁、≥90 岁。
不同年龄组的新冠肺炎病例
以上显示了不同年龄组的 Covid 病例(以千计)。我们可以看到,年轻一代的病例数要高得多,这可能仅仅是因为多伦多的青年人口较多。因此,了解每个年龄组的人口统计是很重要的。这些人口统计数据来自 StatCan 。这是 2016 年的人口普查数据,我假设到 2021 年增长 5%,略高于 2011 年到 2016 年的增长(4.3%)。
多伦多人口和 Covid 病例与年龄组
正如预期的那样,由于人口较多,较年轻年龄组的病例数明显较高。从绝对数字来看,20 至 29 岁年龄组的病例数量最多。这是有道理的,因为 20 至 29 岁年龄段的人往往相互接触最多,流动性也很高。就感染人数而言,这是受影响最严重的年龄组吗?为了找出答案,让我们画出不同年龄组的病例数与人口数的比率。
每个人口的病例数
令人惊讶的是,竟然是 90 岁以上的年龄段!病例与人口的比率(10)明显高于其他年龄组(3)。虽然 90 岁以上年龄组的人口是最小的,但他们中的许多人居住在观察到严重疫情的长期护理院。稍后将详细介绍。现在,让我们看看这些确诊病例的结果。
结果 :活动(仍在进行中的病例)、已解决(患者已康复的病例)、致命(导致死亡的病例)
在多伦多的所有病例中,约 70000 例已得到解决,约 3%的病例(2265 例)是致命的。
基于结果的病例计数
不同年龄组的病例结果
上表显示了不同年龄组的结果。我们可以看到死亡率随着年龄的增长而增加。
各年龄组的死亡率和病例数
这个情节很恐怖!我们可以看到,随着年龄的增长,感染人数明显减少,而致命病例却急剧增加。各年龄组的死亡率百分比如下所示。
各年龄组的死亡率百分比
随着年龄的增长,死亡率急剧增加,90 岁及以上的约占 30%。我们的中和抗体越多,我们对 Covid 的免疫力就越好。不幸的是,这些抗体随着时间的推移而减少,因此老年人群更容易因 Covid 而死亡。更多关于这个的讨论可以在这里找到。
传染源:
旅行(安大略省外旅行)密切接触(与确诊或疑似病例有密切接触)机构(长期护理院、特殊护理医院、急症护理医院等。)、医疗保健(家庭医生、牙医等。)、社区(杂货店、健身房等。)、不明(感染源不明)、暴发(与长期护理、无家可归者收容所等暴发有关的病例。)
病例与传染源
大多数病例的传染源不明,这有点令人担忧,甚至令人害怕。由此可见接触者追踪有多难。我建议人们开始使用 Covid Alert app 来帮助追踪联系人的来源。
密切接触、暴发和社区是下一个最常见的传染源。
年龄组较年轻一侧的大多数病例对应于密切接触和社区传播。而与疾病爆发相关的感染是 80 岁及以上人群的主要感染源。这与自疫情开始以来我们一直在新闻中听到的长期护理单位爆发疫情相一致,这令人深感沮丧。
与死亡病例相对应的传染源
特别是在长期护理单位中的爆发可被视为死亡病例的主要原因。如果安大略省更好地处理长期护理单位,死亡人数本来可以大大减少!对加拿大养老院危机的详细分析可以在这里找到。
最后,让我们看看案件在多伦多各地区的分布情况。这个城市被分为 96 个前分拣区(FSA)。每个 FSA 对应一个以字母 m 开头的唯一的 3 位邮政编码。
多伦多地图,显示每个 FSA 的死亡病例数
多伦多地图,显示每个 FSA 中的活动案例数
在多伦多推广疫苗时,最好针对上面显示的活跃病例数量最多的地方。这对应的是怡陶碧谷(M9V),北约克(M3N,M2R),斯卡伯勒(M1B),约克(M6M)。理想的情况是开始给长期护理院的人接种疫苗,同时在上述地点进行大规模接种。
结论
- 与第一波相比,8 月开始的第二波感染人数明显更多,但导致的死亡病例相对较少。这表明,做好应对疫情的准备有助于拯救许多生命,这是一个特别重要的教训,值得在未来发扬光大。
- 由于流动性大和相互接触,20 至 29 岁年龄组的感染人数最多。另一方面,大多数死亡病例发生在 80 岁及以上。这是由于中和抗体随着时间的推移而减少。
- 在超过 40%的病例中,感染传播的来源不明,这表明追踪接触者的困难。在已知病例中,密切接触是头号传染源。这也是安大略省总理实施严格的居家隔离令的原因。
- 在多伦多的所有新冠肺炎病例中,最致命的病例是由于爆发引起的,特别是在长期护理院和养老院。正如在此所讨论的,这些护理院的条件必须得到显著改善,这些护理院过度拥挤的问题必须得到解决,并且应该雇用更多合格的工作人员。
- 多伦多没有疫苗接种的时间表,但根据现有的数据,理想的策略是尽快为长期护理院和养老院的人接种疫苗,并在受影响最严重的地区开始大规模接种疫苗。
- 50 岁及以下年龄组的死亡率几乎为零,20 至 29 岁年龄组的感染人数最多。在给 50 岁以上的人和所有年龄组的脆弱人群接种疫苗后,给 20 至 29 岁年龄组的人接种疫苗似乎可以遏制病毒的传播。
通过数据我们可以看出,感染传播的主要原因是密切接触。隔离和留在家中是遏制病毒传播的有效策略。我明白并不是很多人有我这样的特权,与世隔绝,呆在家里。但是我强烈要求你尽可能地遵守这些命令。虽然不是强制性的,但我也强烈建议您接种疫苗,建立群体免疫,共同抗击疫情病毒!
所有的分析都是用 Python 完成的,相关代码可以在我的 GitHub repo 中找到。请在这里分享你的想法,或者在 LinkedIn 上与我联系。
感谢阅读!
*编者注:*towardsdatascience.com是一家以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
参考
- https://open.toronto.ca/dataset/covid-19-cases-in-toronto/
- https://www12 . stat can . GC . ca
- https://www . the lancet . com/journals/lancet/article/piis 0140-6736(21)00083-0/full text
- https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7288963/
了解为真实世界场景构建机器学习模型的过程
构建线性回归模型以根据天气历史数据预测表观温度的实用分步指南
本文的重点是找出特定要素之间的关系,并在经历了所有必要的步骤后使用天气历史数据集进行预测,
- 数据清理
- 数据转换
- 特征编码
- 特征缩放
- 特征离散化
- 降维
- 线性回归模型
- 模型评估
这里的目标是发现,湿度和温度之间是否存在关系,湿度和表观温度之间是否存在关系?并且还发现在给定的湿度下是否可以预测表观温度。****
这里使用的数据集是 Kaggle 的天气历史数据集。点击这里可以找到。
首先,导入所需的 python 库。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
import seaborn as sns
from sklearn import preprocessing
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import KBinsDiscretizer
from sklearn import linear_model
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from math import sqrt
from sklearn.model_selection import cross_val_score, cross_val_predict
from sklearn import metrics
然后将数据集导入 Colab 并读取。
from google.colab import drive
drive.mount("/content/gdrive")data_set = pd.read_csv('/content/gdrive/My Drive /data /weatherHistory.csv')
data_set.tail(10)
数据集中的最后 10 行可以用下面的*data_set.tail(10)*
进行检查。
输出:
资料组
那么原始数据集的副本被创建为 x。
X = data_set.copy()
1.数据清理—处理缺失值、异常值和异常值
应该检查数据集是否有缺失值,下面的代码将返回 True 如果有任何缺失值,否则返回 False 。
X.isnull().values.any()
上面的代码输出 True ,表示数据集中有缺失的值。因此需要识别出缺少值的列。
X.isnull().any()
输出:
这意味着,只有 Precip 类型列有缺失值,所有其他列没有任何缺失值。
缺失值的百分比可按如下方式检查。
print(X.isnull().sum() * 100 / len(X))
输出:
我们可以看到百分比非常低,所以我们可以用下面的代码删除数据集中所有缺失的值。
X = X.dropna()
既然缺失值问题已经解决,接下来,我们应该检查异常值或异常值。
X.boxplot(figsize=(18,8))
输出:
所有特征的箱线图
我们可以看到压力特征的数据分布是异常的,因为压力已经为 0。我们可以检查有多少数据显示异常。
X[X['Pressure (millibars)'] == 0].shape[0]
产量:1288
所以这些都不是离群值。这些值可能是一些人为错误或系统故障的结果。因此,我们不能简单地接受它们,也不能放弃它们,因为那样我们会错过其他功能数据。所以我们可以利用 IQR。
IQR 或四分位数范围是基于将数据集划分为不同分位数的变异性度量。
我们可以用分位数来计算下限和上限。然后我们用下限代替小于下限的值,用上限代替大于上限的值。这也适用于左偏或右偏的数据。
fig, axes = plt.subplots(1,2)
plt.tight_layout(0.2)
print("Previous Shape With Outlier: ",X.shape)
sns.boxplot(X['Pressure (millibars)'],orient='v',ax=axes[0])
axes[0].title.set_text("Before")Q1 = X["Pressure (millibars)"].quantile(0.25)
Q3 = X["Pressure (millibars)"].quantile(0.75)print(Q1,Q3)
IQR = Q3-Q1
print(IQR)lower_limit = Q1 - 1.5*IQR
upper_limit = Q3 + 1.5*IQR
print(lower_limit,upper_limit)X2 = XX2['Pressure (millibars)'] = np.where(X2['Pressure (millibars)']>upper_limit,upper_limit,X2['Pressure (millibars)'])X2['Pressure (millibars)'] = np.where(X2['Pressure (millibars)'] <lower_limit,lower_limit,X2['Pressure (millibars)'])print("Shape After Removing Outliers:", X2.shape)
sns.boxplot(X2['Pressure (millibars)'],orient='v',ax=axes[1])
axes[1].title.set_text("After")
plt.show()
输出:
施加 IQR 压力前后的箱线图
然后,我们需要通过绘制箱线图来检查湿度中的异常值或异常值。
humidity_df = pd.DataFrame(X2["Humidity"])
humidity_df.boxplot()
输出:
湿度箱线图
我们可以看到湿度为 0.0。所以我们要检查有多少数据值是 0.0。
X2[X2['Humidity'] == 0].shape[0]
产量:22
鉴于地球的气候和天气条件,湿度不可能为零。出现这种异常的数据点数量也非常少,因此我们可以简单地删除它们。
X2 = X2.drop(X2[X2['Humidity'] == 0].index)
现在,我们完成了数据清理。
通常,在数据清理之后,您可以继续进行数据转换。但在这里,我在分割数据之前进行了特征编码,因为这将消除为训练和测试数据单独进行特征编码的需要。稍后将解释在应用任何变换之前拆分数据集的原因。
2.特征编码-处理分类特征
分类特征是可以分组到类别中的数据。举个例子,我们可以拿性别、肤色等。我们需要将那些非数值转换成数值,以便训练机器学习模型。有两种处理分类数据的传统技术。
- 一键编码
- 标签(整数)编码
我将用天气历史数据集中的例子来解释这两点。我们的数据集中有两个分类列,Precip Type 和 Summary。让我们以“Precip 类型”为例。
X2['Precip Type'].value_counts()
输出:
我们可以看到‘Precip Type’中的数据值不是雨就是雪。所以 Precip 类型’是一个分类特征。
一键编码
在这种方法中,分类特征被值为 0 或 1 的新特征所取代。Precip 类型被新的特征雨和雪所取代,如下图所示。
标签编码
在这种技术中,每个分类值都被转换成一个数值。如下图所示。
对于线性模型,一键编码更合适。如果我们对这种情况应用标签编码,那么模型将试图识别顺序,因为特征值类似于 0、1、2、3 等。但是如果是二进制类别,我们可以使用标签编码。
这里,因为 Precip 类型只有 2 个值,所以我可以使用标签编码。
X2['Precip Type']=X2['Precip Type'].astype('category')
X2['Precip Type']=X2['Precip Type'].cat.codes
但是如下图所示,summary 有许多类别。
final['Summary'].value_counts()
输出:
所以我们需要对汇总列进行一次性编码。*pd.get_dummies*
将根据每个类别创建新的特性列,然后我们需要合并新的特性列并删除摘要列,如下面的代码所示。
dummies_summary = pd.get_dummies(X2['Summary'])
merged_summary = pd.concat([X2,dummies_summary],axis='columns')
X2 = merged_summary.drop(['Summary'], axis='columns')
X2
输出:
应用要素编码后的数据集
3.分割数据集
数据泄漏是指机器学习模型的创建者犯下的错误,其中他们意外地在测试和训练数据集之间共享信息。
当我们对训练和测试数据集一起(对整个数据集)应用变换、离散化和缩放等时,可能会导致数据泄漏。为了缓解这个问题,我在转换之前分割数据集,以避免模型过度拟合。
表观温度是目标特征。因此,我们需要将其从要素数据集中分离并移除。这里,数据集分为 80%用于训练,20%用于测试。
target_column = pd.DataFrame(final_summary['Apparent Temperature (C)'])final_summary = final_summary.drop(['Apparent Temperature (C)'], axis='columns')X_train, X_test, y_train, y_test = train_test_split(final_summary, target_column, test_size=0.2)
拆分数据集后,需要重置索引。
X_train=X_train.reset_index(drop=True)
X_test=X_test.reset_index(drop=True)
y_train=y_train.reset_index(drop=True)
y_test=y_test.reset_index(drop=True)
现在,我们可以分别对训练和测试数据集应用转换。
4.数据转换
真实数据集中的变量将遵循更偏态的分布。但是如果数据来自正态分布,那么机器学习模型可以学习得很好。因此,我们应该使用直方图和 Q-Q 图来检查这些变量是如何分布的。这里我只解释训练数据集的转换。同样的过程也应该应用于测试数据集。
X3 = X_train.copy() #copy of the training dataset
Y3 = X_test.copy() #copy of the testing dataset stats.probplot(X3["Temperature (C)"], dist="norm", plot=plt)plt.show()
输出:
温度的 Q-Q 图
同样,对于所有特性,我们可以使用 Q-Q 图分析数据分布,以查看数据是否偏离了预期分布(红线)。这里我们可以看到温度呈正态分布。
但是当我们看到风速的 Q-Q 图时,我们可以看到数据是倾斜的。
风速的 Q-Q 图
然后我们也可以绘制直方图。
X3.hist(figsize=(15,10))
输出:
训练数据的直方图
我们可以看到湿度是左偏的,风速是右偏的。可见性也显示了一些左偏,但是在应用变换之后,它没有显示正态分布。所以我没有应用可见性的转换。
对于右偏的数据,我们应用对数变换,对于左偏的数据,我们可以应用指数变换。
logarithm_transformer = FunctionTransformer(np.log1p)
data_new1 = logarithm_transformer.transform(X3['Wind Speed (km/h)'])
X3['Wind Speed (km/h)']=data_new1
X3['Wind Speed (km/h)'].hist()
这里我使用了*np.log1p*
,因为风速值为 0.0,而 np.log 仅用于正数。
输出:
应用对数变换后的风速直方图
现在我们可以看到风速呈正态分布。
由于湿度是左偏的,我们应用指数变换。
exp_transformer = FunctionTransformer(np.exp)
data_new2 = exp_transformer.transform(X3['Humidity'])
X3['Humidity']=data_new2
X3['Humidity'].hist()
输出:
应用指数变换后的湿度直方图
在这里,我展示了直方图在转换后是如何变化的。
风速:
湿度:
我们可以从 Q-Q 图和直方图中看到,大声覆盖始终为 0.0。因此,由于它没有影响,我们需要在训练和测试数据中消除噪声。
X3 = X3.drop(['Loud Cover'], axis='columns')
Y3 = Y3.drop(['Loud Cover'], axis='columns')
由于格式化日期是一个唯一的值,而每日摘要不是一个数值,它有如此多的不同值,我们可以将它们都删除。
X3 = X3.drop(columns=['Daily Summary','Formatted Date'])
Y3 = Y3.drop(columns=['Daily Summary','Formatted Date'])
5.特征缩放—标准化
特征缩放指的是用于归一化独立变量的值的范围的方法。
这里我使用了标准化来进行缩放。标准化将数据转换为平均值 0 和单位标准差。这一步至关重要,因为它避免了模型受到大幅度变量显著影响的机会。
标准化不适用于分类变量。因此,在对数字特征进行标准化之前,应该将它们放在一边。标准化也应该分别应用于训练和测试数据。
这里,请注意,我仅将*scaler.fit()*
用于训练数据,因为我们需要将用于训练数据集的相同参数(平均值和标准偏差)应用于训练数据集。
X4 = X3.copy()
Y4 = Y3.copy()to_std_train = X4[['Temperature (C)', 'Humidity','Wind Speed (km/h)', 'Wind Bearing (degrees)', 'Visibility (km)','Pressure (millibars)']].copy()
to_std_test = Y4[['Temperature (C)', 'Humidity','Wind Speed (km/h)', 'Wind Bearing (degrees)', 'Visibility (km)','Pressure (millibars)']].copy()scaler = StandardScaler()
scaler.fit(to_std_train)train_scaled = scaler.transform(to_std_train)
test_scaled = scaler.transform(to_std_test)std_df_train = pd.DataFrame(train_scaled, columns = to_std_train.columns)
std_df_test = pd.DataFrame(test_scaled, columns = to_std_test.columns)X4[['Temperature (C)', 'Humidity','Wind Speed (km/h)','Wind Bearing (degrees)','Visibility (km)','Pressure (millibars)']]=std_df_train
Y4[['Temperature (C)', 'Humidity','Wind Speed (km/h)','Wind Bearing (degrees)','Visibility (km)','Pressure (millibars)']]=std_df_test
标准化数据后,我们可以使用相关矩阵进行相关分析。
sns.heatmap(std_df_train.corr(),annot=True);
相关矩阵
我们可以知道湿度和温度之间有负相关关系。所以要回答这个问题湿度和温度之间有和的关系吗?是的。湿度和温度呈负相关。
6.[数]离散化
离散化用于将连续变量转换为离散变量。这里我们可以看到,当绘制风向直方图时,它不符合正态分布。当具有非标准概率分布的数值变量被离散化时,机器学习模型可以表现得更好。我已经用 K-means 离散化了风向。
X5 = X4.copy()
Y5 = Y4.copy()data1 = pd.DataFrame(X5, columns=['Wind Bearing (degrees)'])
data1 = data1.dropna()
data2 = pd.DataFrame(Y5, columns=['Wind Bearing (degrees)'])
data2 = data2.dropna()discretizer = KBinsDiscretizer(n_bins=8, encode='ordinal', strategy='uniform')discretizer.fit(data1)
_discretize1 = discretizer.transform(data1)
_discretize2 = discretizer.transform(data2)
X_dis = pd.DataFrame(_discretize1)
Y_dis = pd.DataFrame(_discretize2)
X_dis.hist()
输出:
离散化后的风向直方图
我们可以绘制一个相关矩阵,以确定目标列(表观温度)的特征的重要性。
相关性是一种统计度量,表示两个或多个变量一起波动的程度。
X5['Wind Bearing (degrees)'] = X_disd_data = X5[['Temperature (C)', 'Humidity','Wind Speed (km/h)','Wind Bearing (degrees)','Visibility (km)','Pressure (millibars)']].copy()d_data['Apparent Temperature (C)'] = y_train
d_data.head(10)
print(d_data.corr())
sns.heatmap(d_data.corr(),annot=True)
相关矩阵
我们可以看到,湿度和目标变量表观温度有着显著的高度相关性。所以回答问题湿度和表观温度之间有 关系吗?是的。湿度和表观温度呈负相关。
7.降维—主成分分析
降维的重要性在于,我们可以通过去除冗余,只保留有用的信息来压缩数据集。太多的输入变量可能会导致维数灾难,然后模型将无法很好地执行,因为模型还会从训练数据集中的噪声中学习并过度拟合。
主成分分析是一种用于降维的强大技术,增加了可解释性,但同时最小化了信息损失。
pca = PCA(n_components=12)
pca.fit(X5)
X_train_pca = pca.transform(X5)
X_test_pca = pca.transform(Y5)
principalDf = pd.DataFrame(data = X_train_pca)
principalDf.head(20)
输出:
参数*n_components*
的值通过分析下面的*explained_component_ratio_*
来决定。
pca.explained_variance_ratio_
输出:
PCA 解释的方差比
当决定使用主成分的数量时,我们应该考虑上述值。数组的第一个元素是高方差维数,我们应该认为高方差维数的总和约为 0.95。这里我用了 12 个主要成分。
8.线性回归模型
完成所有上述步骤后,将线性回归模型应用于数据集。
lm = linear_model.LinearRegression()
model = lm.fit(X_train_pca,y_train)
9.模型评估
当我们评估我们的模型时,可以看到精度为 0.990223。
accuracy = model.score(X_test_pca, y_test)
print("Accuracy:", accuracy)
输出:
为了进一步评估模型,我们使用均方差(MSE)。
predictions = lm.predict(X_test_pca)
y_hat = pd.DataFrame(predictions, columns=["predicted"])
mse = mean_squared_error(y_test, y_hat)
print('Test MSE: %.3f' % mse)
输出:
我们也使用了计算的均方根误差(RMSE)。
rmse = sqrt(mean_squared_error(y_test, y_hat))
print('Test RMSE: %.3f' % rmse)
输出:
我们可以进行 6 重交叉验证。
scores = cross_val_score(model, X_test_pca, y_test, cv=6)
print("Cross-validated scores:", scores)
输出:
用下面的代码,我计算了交叉预测的准确性。
predictions = cross_val_predict(model, X_test_pca, y_test, cv=6)
accuracy = metrics.r2_score(y_test, predictions)
print("Cross-Predicted Accuracy:", accuracy)
模型的精度是好的。但是检查重量参数也很重要。
权重参数是模型在新数据下表现良好的一个重要指标。如果权重参数较小,则意味着您的模型非常好,在没有数据的情况下会表现得更好。
#W parameters of the model
print(lm.coef_)
输出:
在这里,权重参数不是很低。但是我们可以通过识别和改变我们在预处理、转换等过程中所做的一些步骤来进一步减少它们。
我们可以将模型的预测可视化如下。这里我只绘制了 100 个数据点的图表。
plt.figure(figsize=(15, 7))
plt.plot(y_hat[:100], label = "Predicted")
plt.plot(y_test[:100], label = "Actual")
plt.title('Predictions Vs Actual')
plt.legend()
plt.show()
输出:
预测与实际数据图
10.结论
在本文中,我向您提供了如何通过应用数据清理、数据转换、特征编码、特征缩放、离散化、维度缩减来构建机器学习模型的分步指南,并且我还评估了线性回归模型。
我希望这篇文章能帮助你很好地理解我们应该遵循的重要步骤以及它们背后的主要概念,以建立一个好的机器学习模型。
编码快乐!
11.Colab 代码
https://colab.research.google.com/drive/1C4GlUeLKhiC-1aX0D63M88_Rw-K7nCTc?usp=sharing
理解数据库管理系统(RDBMS)的关系模型
以及为什么它在整个行业如此受欢迎
在流行媒体对机器学习的大肆宣传和荣耀背后,一个有点被忽视的极其重要的组件是数据库管理系统(DBMS)的作用。当然,并不是每个人都需要知道数据库管理的细节。但是,如果你以任何身份使用机器学习,在你的职业生涯中,很大程度上,理解一定程度的机器学习可能会有所帮助。
大约在 60 年代,开发人员仍然使用硬编码软件来管理数据。每当这些数据不适合非常严格的预定义架构时,软件每次都需要进行重构,以适应存储的数据类型和用于检索和操作数据的方法类型。如果开发人员使用哈希表来定义数据结构,随着数据库的增长和需求的发展,系统将需要重新编写。这是一个重复发生的事件。
在 IBM 工作的一位名叫 Edgar F. Codd 的数学家看到了这种对通用架构的需求,这种架构可以真正绕过硬编码的僵化,以适应不断发展的需求。进入关系数据库管理系统(RDBMS)。1970 年,他发表了一篇描述这种架构的论文,其中系统本身可以找出存储、检索和操作数据的最佳可能表示和过程。
大型共享数据库的数据关系模型。美国计算机学会通讯26.1(1983):64–69。ACM 的通信。Web 。
Codd 建议我们使用简单、原始的数据结构,如标量、整数、浮点和字符串来存储数据。数据会以元组的形式形成关系。也许用更简单和更容易理解的术语;想象一个数据表(也称为关系),其中每个单元格都是简单的标量数据类型之一,在每一行中作为元组连接起来,形成它们自己的关系。每个实体(或行)都有一个唯一的 ID,称为主键。表也可以通过这些键相互对话,这些键现在被称为外键,使用七个基本操作形成自定义关系。下面列出了基本操作及其相应的标准 SQL 语法:
i) Select: 选择并返回一个新的关系,它是满足某些条件谓词的元组的子集:SELECT * FROM Shop_A 其中 author _ id = 102
**ii)投影:**返回只包含指定属性的元组的新关系,可以重新排列属性顺序,可以操作值:SELECT author_id-100,book _ id FROM Shop _ A WHERE author _ id>102;
iii) Union: 将两个输入关系中的所有元组作为一个新关系返回,但仅当两者中的输入数据类型和属性相同时才有效:(SELECT * FROM Shop _ A)Union ALL(SELECT * FROM Shop _ B);
iv) Intersection: 返回两个输入关系中的元组的新关系,但仅当两者中的输入数据类型和属性相同时才有效:(SELECT * FROM Shop _ A)INTERSECT(SELECT * FROM Shop _ B);
v) Difference: 返回元组在第一个输入中但不在第二个输入中的新关系,但仅当两者的输入数据类型和属性相同时才有效:(SELECT * FROM Shop _ A)EXCEPT(SELECT * FROM Shop _ B);
vi) Product: 返回一个新的关系,即两个输入的点积,aka。所有可能的组合,一般用于测试:SELECT * FROM Shop _ A CROSS JOIN Shop _ B;或者,选择* FROM Shop_A,Shop _ B;
vii) Join: 返回两个输入关系中都有的元组的新关系,但与 Union 不同,数据和属性类型不需要相同,只要元组内至少有一个匹配即可:SELECT * FROM Shop _ A NATURAL Join Shop _ B;
此后,又增加了更多高级操作,如除法、聚合、排序等等。
这些较低级的操作被用来用一种叫做关系代数的技术来评估关系。RDBMS 使用这些原始的关系代数表达式来确定最有效的如何这就是关系演算。系统中一个非常复杂的组件叫做查询优化器 来完成这项工作。
假设您想在表 A 和表 B 之间创建一个新的关系,每个表都包含 50 亿行,您希望所有主键小于 500 的元组都同时出现在表 A 和表 B 中,并且具有相同的属性。一种方法是首先自然连接所有 100 亿行,然后过滤少于 500 的选择键。另一个过程可以是首先从 A 和 B 中过滤选择少于 500 个键,然后自然连接 1000 个(最多)条目。根据数据库的实际大小,第二个过程的性能因素将比第一个过程有效得多。
这就是关系模型的优势所在。用户只需要说出他们想要做什么,RDBMS 就会计算出 T2 如何以最有效的方式做这件事。这就是像 SQL 这样的查询语言被称为“非过程化”的原因。系统内置了明确的步骤(或程序)。与 Python 或 C/C++等编程语言不同,在这些语言中,用户需要显式声明对数据进行多次迭代,寻找这一特性,如果 n 大于某个数字,请选择另一种方法,yada yada,SQL 只需被告知所需的最终结果。
RDBMS 主要基于三大支柱:
**i)结构(模式)😗*关系及其内容,如属性、类型、数据内和数据间的关系。
**ii)完整性:**确保数据库的内容满足约束条件(也就是一些预定义的本地结构,比如内存分配),以在给定这些约束条件的情况下验证数据库的实例,没有冗余。
**iii)操作:**如何通过运行查询来访问或修改数据。
因为该系统可以随着不断发展的数据和需求而发展,所以它非常通用,适合大多数数据库的业务需求。RDBMS 由于其智能化设计,可以说是数据库管理系统的人工智能。
💔-reasons-why-your-machine-learning-model-is-garbage-d643e6f0661> </5-stages-of-learning-data-science-40bca61f11b1>
参考文献:
- 帕夫洛 A,2019,数据库系统介绍,讲义,15-445/645,卡内基梅隆大学
- 大型共享数据库的数据关系模型。美国计算机学会 26.1 (1983 年)通讯:64-69。ACM 的通信。网络。
附言:要获得更多关于数据科学、编程以及生物学家如何在数据革命中导航的简明扼要的文章,可以考虑关注我的博客。
由于每分钟都有成千上万的视频被上传,所以过滤掉它们是很重要的,这样你就可以只使用高质量的数据。我亲自挑选的,我会把你感兴趣的主题的教育视频发邮件给你。报名这里。
感谢您的阅读!
了解萨里玛模型的季节顺序
了解 Python statsmodels 库的 SARIMA 模型的(D,P,Q,M)季节顺序的快速概述和现成代码。
几个月前,我写了一篇文章,描述了为时间序列预测构建 SARIMA 模型的全过程。在那篇文章中,我解释了如何调整 SARIMA 模型的 p、d 和 q 阶,并根据 NRMSE 评估了训练模型的性能。
关于文章的一个评论是,提议的模型基本上是 ARIMA 模型,因为没有考虑季节顺序。我感谢评论的作者,我调查了这方面。
现在我在这里向你们解释我发现的一个有趣的方面,不幸的是,我在网上找到的文章中没有很好地解释它。
萨里玛模型订单
SARIMA 模型可通过两种订单进行调整:
- (p,d,q)顺序,是指时间序列的顺序。这个顺序也用于 ARIMA 模型(不考虑季节性);
- (P,D,Q,M)季节顺序,是指时间序列的季节成分的顺序。
在本文中,我将重点介绍季节性订单的重要性。
加载数据集
首先,我导入了 1990 年至 2019 年意大利入境游客的相关数据集作为一个pandas
数据框架。数据摘自欧洲统计:旅游业年度数据。
import pandas as pddf = pd.read_csv('source/tourist_arrivals.csv')
df.head()
作者图片
现在我把数据集转换成时间序列。这可以分三步完成:
- 我将
date
列转换为日期时间类型 - 我将
date
列设置为数据帧的索引 - 我将数据帧的
value
列赋给一个新变量,名为ts
。
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
ts = df['value']
我通过绘制时间序列来探索它。我开发了matplotlib
库。
from matplotlib import pyplot as pltplt.plot(ts, label='prediction seasonal')
plt.grid()
plt.xticks(rotation=90)
plt.show()
作者图片
我注意到时间序列呈现季节性,因此 SARIMA 模型是合适的。此外,时间序列也呈现增长趋势。
(p,d,q)顺序
现在我将时间序列分成两部分:训练集和测试集。训练集将用于拟合模型,而测试集将用于评估模型。
ts_train = ts[:'2019-03-01']
ts_test = ts['2019-04-01':]
在另一个笔记本中,我已经解释了如何计算 SARIMA 模型的(p,d,q)阶,因此我将其手动设置为发现的值:
d = 1
p = 10
q = 7
(P,D,Q,M)顺序
(P,D,Q,M)阶是指自回归参数、差异、移动平均参数和周期的模型的季节性组件:
- d 表示季节性过程的积分顺序(使时间序列稳定所需的转换次数)
- p 表示季节成分的自回归顺序
- q 表示季节性成分的移动平均顺序
- m 表示周期性,即一个季节中的周期数,例如每月数据为 12。
为了评估季节顺序,我们必须从时间序列中提取季节成分。出于这个原因,我们利用了由statsmodels
库提供的seasonal_decompose()
函数。在输入参数中,我们可以指定分解模型(加法或乘法)以及我们是否想要推断趋势。该函数返回趋势、季节和剩余部分。
from statsmodels.tsa.seasonal import seasonal_decomposeresult = seasonal_decompose(ts, model='additive',extrapolate_trend='freq')
result.plot()
plt.show()
作者图片
订单
为了提取 D,我们必须检查季节成分是否是平稳的。我们定义一个函数,利用 Adfuller 测试来检查平稳性。
from statsmodels.tsa.stattools import adfuller
import numpy as npdef check_stationarity(ts):
dftest = adfuller(ts)
adf = dftest[0]
pvalue = dftest[1]
critical_value = dftest[4]['5%']
if (pvalue < 0.05) and (adf < critical_value):
print('The series is stationary')
else:
print('The series is NOT stationary')
然后,我们对时间序列的季节性部分调用check_stationarity()
函数:
seasonal = result.seasonal
check_stationarity(seasonal)
级数是平稳的,因此我们不需要任何额外的变换来使它平稳。我们可以设置 D = 0。
采购订单
P 的值可以通过查看季节分量的偏自相关(PACF)图来提取。在排除中间滞后的贡献后,PACF 可以被想象为序列和它的滞后之间的相关性。
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
plot_pacf(seasonal, lags =12)
plt.show()
作者图片
在 PACF 图中,值超出置信区间(浅蓝色)的最大滞后是 12,因此我们可以设置 P = 12。
q 顺序
Q 阶可以通过自相关(ACF)图计算。自相关是单个时间序列与其自身滞后副本的相关性。
plot_acf(seasonal, lags =12)
plt.show()
作者图片
从上图中,我们注意到,值超出置信区间的最大滞后是 8,因此 Q = 8。
火车模型
为了显示调整和不调整(P,D,Q,M)顺序的 SARIMA 模型之间的差异,我们拟合了两个模型,第一个模型没有季节性顺序,第二个模型有季节性顺序。
不按(P,D,Q,M)顺序拟合
我们利用了statsmodels
包的SARIMAX()
类,并将其配置为只处理(p,d,q)顺序。
from statsmodels.tools.eval_measures import rmse
nrmse = rmse(ts_pred, ts_test)/(np.max(ts_test)-np.min(ts_test))
nrmse
它给出了以下输出:
0.0602505102281063
符合(P,D,Q,M)顺序
我们通过传递seasonal_order
参数来拟合模型。此操作比上一个操作要求更多。
model_seasonal = SARIMAX(ts_train, order=(p,d,q), seasonal_order=(P,D,Q,12))
model_fit_seasonal = model_seasonal.fit()
我们计算预测和 NRMSE:
ts_pred_seasonal = model_fit_seasonal.forecast(steps=n_test)
nrmse_seasonal = rmse(ts_pred_seasonal, ts_test)/(np.max(ts_test)-np.min(ts_test))
nrmse_seasonal
它给出了以下输出:
0.08154124683514104
考虑
我们注意到,就 NRMSE 而言,没有季节性订单的模型优于另一个模型。
(P,D,Q,M)顺序没用吗?的确不是。对于短期预测,这两个模型的行为方式几乎相同。然而,对于长期预测,具有(P,D,Q,M)阶的模型更现实,因为它反映了增长趋势。
为了解释这个概念,我们可以在两种情况下计算一个长期预测:
N = 300
ts_pred = model_fit.forecast(steps=n_test+N)
ts_pred_seasonal = model_fit_seasonal.forecast(steps=n_test+N)
我们可以画出结果。我们注意到这两个模型之间有很大的不同。虽然没有(P,D,Q,M)阶的模型倾向于随时间减少,但是另一个模型反映了增加的趋势。
plt.figure(figsize=(10,5))
plt.plot(ts_pred_seasonal, label='prediction with P,D,Q')
plt.plot(ts_pred, label='prediction without P,D,Q')
#plt.plot(ts_test, label='actual')
plt.title('Multi-step Forecasting (manual parameters)')
plt.legend()
plt.grid()
plt.xticks(rotation=90)
plt.show()
作者图片
摘要
在本教程中,我解释了 SARIMA 模型中季节顺序对于长期预测的重要性。
本文解释的所有代码都可以作为 Jupyter 笔记本从我的 Github 库下载。
如果你想了解我的研究和其他活动的最新情况,你可以在 Twitter 、 Youtube 和 Github 上关注我。
相关文章
</4-different-approaches-for-time-series-analysis-7e2364fadcb9> [## 4 种不同的时间序列分析方法
towardsdatascience.com](/4-different-approaches-for-time-series-analysis-7e2364fadcb9) https://alod83.medium.com/june-articles-a-summary-of-my-june-articles-in-case-you-have-missed-them-8bc370375419
理解计算机视觉中的转换;
克里斯多夫·伯恩斯在 Unsplash 上拍摄的照片
入门指南
仿射变换和单应性概述
内容
- 仿射变换
- 单应性
—齐次坐标
—针孔摄像机型号
—单应性方程
- 参考
变换是计算机视觉的重要组成部分,理解它们如何工作为更高级的技术奠定了基础。
在这里,我将主要介绍仿射变换和单应性。
仿射变换:
仿射变换是最简单的变换形式。这些变换在满足以下特性的意义上也是线性的:
- 线条映射到线条
- 点映射到点
- 平行线保持平行
仿射变换的一些常见例子是平移、扩展、旋转、剪切和反射。此外,这些变换的任何组合(如膨胀后的旋转)都是另一种仿射变换。
基本仿射变换的示例(图片由作者提供)
与其将仿射变换分解成不同的情况,不如有一个统一的定义。因此,我们转向使用矩阵作为线性变换来定义仿射变换。如果你不熟悉将矩阵解释为空间的线性变换,3Blue1Brown 有一个关于这个主题的精彩视频:
为了将矩阵理解为线性变换
本质上,我们可以把仿射变换看作是首先用矩阵进行某种线性变换,然后用某种平移进行组合。
在 2D 的情况下,仿射变换的等式由下式给出:
2D 仿射变换的方程式(图片由作者提供)
这里,矩阵用条目( x 1 和 x 2)表示向量上的一些线性变换,例如反射、剪切、旋转、膨胀或所有四者的组合。需要注意的是,由于变换是线性的,所以它也一定是可逆的,所以矩阵的行列式是非零的。转换的最后一步是向量[ t 1, t 2]的平移,完成到向量[ y 1, y 2]的转换。
2D 仿射变换的例子(图片由作者提供)
仿射变换也可以用下面的等式推广到 n 维的维:
n 维仿射变换方程
这个变换通过应用线性变换 A (其中 A 是一个 *n×n,*可逆矩阵),然后应用向量 b ( b 具有维度 n ×1)的平移,将向量 x 映射到向量 y 。
总之,仿射变换可以表示为由一些平移组成的线性变换,并且它们在为计算机视觉修改图像方面极其有效。事实上,图像预处理很大程度上依赖于仿射变换来进行缩放、旋转、移位等。
单应性:
单应是一种投影变换,因为我们利用投影来关联两个图像。同形异义词最初被引入来研究视角的变化,它们使人们能够更好地理解当我们从不同的角度看图像时,图像是如何变化的。
使用单应变换视角(鸣谢:马里兰大学
单应性的研究是通过检查相机根据其位置和方向拾取不同图像的事实来进行的。本质上,单应是同一场景的两个图像之间的变换,但是从不同的角度。只有两种情况适用单应性(这两种情况都假设世界视图可以用平面来建模):
- 图像是由同一个相机从不同的角度拍摄的(世界现在基本上是一个平面)
- 两台摄像机从不同的位置观察同一平面
鸟瞰单应性的两个案例(图片由作者提供)
然而,为了使用单应性,我们必须首先设计工具来描述一幅图像在相机上的表现。更具体地说,如果给我们一个摄像机和一个图像平面(图像出现的地方,也是摄像机的属性),我们必须找到世界上的一个点(称为世界点)出现在图像平面上的位置。
找到图像上的点的坐标是单应性的关键
因为光是直线传播的,所以我们知道在图像平面上出现了一个笛卡尔坐标的世界点( X,Y,Z ),它位于图像平面与经过相机中心和世界点的直线(这条线就是光到达相机的路径)的交点处。
然而,为了正确地定义这个公式,我们必须绕道到射影几何中一个叫做齐次坐标的概念。
齐次坐标:
齐次坐标(或射影坐标)是另一种坐标系,其优点是齐次坐标的公式往往比笛卡尔坐标(x-y 平面上的点)中的公式简单得多。相比之下,齐次坐标使用 3 个坐标( x ', y ', z ')来表示空间中的点(一般来说,它们比笛卡尔坐标多使用一个坐标)。另外,将齐次坐标转换为笛卡尔坐标相对简单:
将齐次坐标转换为笛卡尔坐标
注意,当 z’ =1 时,齐次坐标很好地映射到笛卡尔坐标。再者,当z’= 0 时,我们把对应的笛卡尔坐标解释为无穷远处的一点。记住这一点,让我们研究齐次坐标的一些应用。
首先,齐次坐标中的直线,只用 3 个点就可以表示出来。具体来说,你可以把一条线 l 在齐次坐标下表示为( l 1, l 2, l 3)。那么,这条线就是所有点的集合 p= ( x , y , z ),使得 l 与 p 的点积为 0。
用齐次坐标表示的线(图片由作者提供)
注意的第二个性质是,给定两点 p 1=( a , b , c )和 p 2 = ( d , e , f ),直线 l 经过 p 1 和p
齐次坐标中两点之间的线(图片由作者提供)
注意的最后一个性质是:两条直线 l 1 和 l 2 的交点(齐次坐标中)是两条直线的叉积给出的点 p 。
齐次坐标中两条线的交点(图片由作者提供)
有了这些性质,我们现在就能很好地理解单应性背后的公式。
针孔摄像机型号:
我们现在回到我们的问题,在给定所述摄像机的位置和方向的情况下,找到一个世界点 ( X 、 Y 、Z)——这是在笛卡尔坐标中——位于所述摄像机的图像平面的位置。
特别地,我们发现世界点( X , Y , Z ,1)位于图像平面的点(X’,Y’,Z’)上,其中两个点在齐次坐标中,并且通过以下等式相关( f 是描述相机焦距的常数):
世界点齐次坐标与像平面齐次坐标的关系方程
从这里我们可以把( x ', y ', z ')转换成前面所说的图像平面上的笛卡尔坐标( x , y )。
事实证明,将世界点转换为图像平面上的点的矩阵可以很好地分解,为我们提供了一种直观的方式来理解矩阵的作用:
矩阵可以理解为两个动作:(1)缩放,(2)压缩到更低维度
但是,由于图像上的坐标系不同于笛卡尔坐标系(左上角是像素坐标中的(0,0)),我们必须执行一次最终转换,以从同质图像平面坐标(x’、y’、z’)转换为同质像素坐标(u’、v’、w’)。
像素坐标的表示(图片由作者提供)
因此,我们首先通过除以像素的大小来缩放我们的图像平面坐标(以便将它们转换成像素),像素的大小在 u 方向上是 ρu 并且在 v 方向上是 ρv 。你可以认为这是把米这样的单位转换成像素。接下来,我们必须通过一些 u 0 和 v 0 来平移坐标,这样像素坐标的原点就在适当的位置。把这两个变换放在一起,我们得到下面的公式:
将图像平面坐标转换成像素坐标。
最后,将所有东西放在一起,我们可以通过将世界点( X , Y , Z ,1)转换为像素坐标(u’,v’,w’),来完成我们的相机模型,其中两者都以齐次坐标给出:
相机模型的方程式
外部参数可以被认为是一个术语,它为我们提供了关于摄像机的方向(存储在旋转矩阵 R 中)和位置(存储在向量 t 中)的信息。
在实际中,我们并不经常知道所有的参数,所以我们可以近似相机矩阵来代替,它只是一些 3×4 的矩阵(通过矩阵乘法性质);这是通过校准摄像机来实现的。
此外,相机矩阵的一个重要属性是缩放 C 的条目给出了描述同一相机的新相机矩阵。这是因为如果我们将 C 乘以某个常数 λ ,那么同质像素坐标的所有条目也会被 λ 缩放。然而,当我们从齐次坐标转换到笛卡尔坐标时(如前所示), λ 被抵消,留下与缩放前相同的笛卡尔坐标。因此,因为比例因子是任意的,所以让相机矩阵的右下角的条目为 1 已经成为惯例。
相机矩阵的标准形式
有了这些定义的方程,我们就非常接近获得单应性的公式。
单应方程;
让我们再一次检查针孔摄像机的设置。在这个设置中,我们的摄像机将拍摄位于一个平面上的点 P =( X , Y , Z ),其中点 P 在图像平面上的同质像素坐标中显示为(u’,v’,w’)。现在,我们可以用一个聪明的技巧来选择坐标系。也就是说,我们让 X 和 Y 轴位于平面内,使得 Z 轴指向平面外。因此,平面上所有点的 Z 坐标为 0,意味着 P 的形式为 P =( X , Y ,0)。
方便选择坐标系(坐标显示为 齐次)(图片由作者提供)
现在,将其代入我们的相机方程,并使用 Z =0,我们得到以下简化:
利用照相机等式中的 Z=0
这个新的相机矩阵被称为单应矩阵 矩阵 H ,有 8 个未知条目(因为右下角的 1 是固定的)。通常,平面单应矩阵的条目用 H 而不是 C 表示,如下所示:
平面单应性方程
我们现在最后的任务是估计 H 的条目。由于单应矩阵中有 8 个未知数,并且平面上的每个世界点有 2 个坐标,我们将需要在 4 个世界点上校准摄像机,以便估计 H 的所有条目。
概括地说,单应性是一种变换,当两个图像是同一平面的图片,但从不同的角度看,我们可以使用它将一个图像转换为另一个图像。在数学上,这种变换由单应矩阵执行,该单应矩阵是具有 8 个未知数的 3×3 矩阵,并且可以通过用 4 个对应点校准图像来估计(使用更多点获得更好的近似,但是 4 是所需的最小值)。
带有黄色校准点的单应性示例(图片由作者提供)
总而言之,homgraphies 是一个强大的工具,可应用于像增强现实(将某些图像投影到环境中)和图像拼接(将多幅图像组合起来创建一个更大的全景图)等领域。
参考
*【https://en.wikipedia.org/wiki/Homogeneous_coordinates *
https://medium . com/swlh/image-processing-with-python-image-warping-using-单应矩阵-22096734f09a
https://www.youtube.com/watch?v=l_qjO4cM74o
https://www.youtube.com/watch?v=fVJeJMWZcq8
使用 Doccano 了解文本数据
文本标注工具不仅仅用于创建数据集。
图 1: Doccano
每个研究人员应该做的第一件事就是了解他们的数据和领域。有许多方法可以做到这一点,从手动检查列和行,打印统计数据,使用 pandas_summary,使用特征选择方法,使用通气管,可视化数据,解释您的模型等。
我认为当你遇到新数据需要被标记成几个类的时候,你需要做的第一件事就是自己注释它。
坐在房间里,在屏幕前,对你的数据做几个小时的注释,可以让你深入理解它。设置完成后,大多数注释工具允许您进入工厂思维模式,您可以在每个屏幕上获得一个注释,通过使用快捷键,您可以简化并适应快速标记程序。
问题是
然而,您可能需要考虑另一个场景,想象一个专家团队,每个人对所讨论的领域都有自己的观点。
你认为每个人都同意他们的同事吗?
你觉得大家都一致吗?
当然不是!
7 个注释神话
这些神话是人们不能就任何事情达成一致的一些最常见的原因,也是为什么你的带注释的数据集充满了噪音。全文请看人群真相和人类注释的七大神话。
- 一个事实大多数数据收集工作都假设每个输入示例都有一个正确的解释。
- 不一致是不好的为了提高注释数据的质量,应该避免或减少注释者之间的不一致。
- 详细的指导方针有助于当具体案例持续引起分歧时,增加更多说明以限制解释。
- 一个就够了大多数带注释的例子都是一个人评估的。
- 拥有领域知识的专家是更好的人类注释者提供更好的注释数据。如图 2 所示。
- 所有的例子都是平等的,运用基础真理的数学对每个例子都一视同仁;你要么匹配正确的结果,要么不匹配。
- 一旦完成,永远有效一旦为一项任务收集了人工注释的数据,这些数据就会被反复使用而不会更新。新的批注数据与以前的数据不一致。
图 2: 神话 5 —专家是更好的人类注释者,拥有领域知识,可以提供更好的注释数据。不是 **真的!**以下是专家和众包的对比。我们可以看到,专家收敛得更快,但结果质量相似。
解决方案
是使用多用户注释工具,并在对每个样本进行强制多数投票后,创建一个可以与之前的假设进行比较的数据集,这可以暂时作为您的基本事实(参见误区 7)。此外,我们希望验证我们的团队在多大程度上彼此一致,以及他们是否彼此一致,即评分者间可靠性和评分者内可靠性** 。**
这是我建议你每次进入一个新的领域都要做的事情。如果你想知道你可以使用哪些工具,这几天有很多文本注释工具,如 Doccano (用于本文)、 Prodigy 、 LightTag 等。
如果你好奇的话,我写了一篇关于如何创建带有行业要求和约束的学术级数据集的指南。
多卡诺
Doccano 是一款面向机器学习从业者的开源注释工具。它为文本分类、序列标记和序列到序列任务提供了注释功能。使用 Doccano,您可以为情感分析、命名实体识别、文本摘要等创建标记数据。你可以在几个小时内建立一个数据集。它具有协作注释、多语言支持、移动支持、表情符号支持和 RESTful API。”如果你好奇,你可以试试他们的注释演示这里。
装置
如果您想自己添加注释,安装非常简单
pip install doccanodoccanonavigate to [http://localhost:8000/](http://0.0.0.0:8000/)
但是,如果您想将 Doccano 放在远程机器上,以便允许协作注释,即多用户、持久性和健壮性。您将需要使用 Docker 安装过程。
docker 安装有其独特之处。目前,它允许您将数据保存到 docker 内的一个目录中,但如果发生一些事情,数据将会消失。为了在外部保存您的数据,您需要将 -v data:/data 参数添加到 docker create 命令中。这个命令允许你将你的本地目录指向一个外部目录,因此如果发生什么事情,不会丢失你的 doccano.db 文件。
1\. Install Docker.
2\. docker pull doccano/doccano
3\. mount a persistent drive onto /data.
4\. docker container create --name doccano_db -v /data:/data -e “ADMIN_USERNAME=admin” -e “ADMIN_EMAIL=admin@example.com” -e “ADMIN_PASSWORD=password” -p 8000:8000 doccano_db
5\. docker container start doccano_db
设置
Doccano 允许您轻松地导入和导出数据。我推荐使用 JSONL(图 3a)。Doccano 还允许您轻松地设置类标签及其快捷键,如图 3b 所示。
图 3a:导入用户界面。
图 3b:标签创建 UI。
注释
Doccano 可以开箱即用,用于多类任务,例如,情感分析、命名实体识别和翻译任务,如图 4a、4b 和 4c 所示。
图 4a: Doccano 情感分析任务
图 4b: Doccano 命名实体任务
图 4c: Doccano 翻译任务
管理模式
作为项目的管理员,您可以检查一些统计数据,比如标签分发、项目完成、用户进度,如图 5 所示。这些工具非常方便,尤其是当你在做这个单调乏味而且非常无聊的注释任务的时候,如果你需要游戏化并且给团队成员注入一些激情的话。
图 5:管理仪表板。
指标
在导出多用户注释数据集后,有多种方法可以测量一致性。我推荐使用来自 Github 和 Scikit-learn 的 Oliver 的 Disagree 包。
- Cohen 的 Kappa(0–1,两个注释者,根据概率进行了修正)
- fleiss Kappa(0–1,多个注释者,根据概率进行了修正)
- krippendorff alpha(0–1,多个标注器,随机修正,允许缺少值)
- 精确度/召回/ F1
正如我们在图 6 中看到的,即使是专家也不会完全同意彼此的观点。
图 6:一个一致矩阵,X 和 Y 轴是专家,在对角线上我们可以看到他们同意自己,但不出所料专家之间的一致度不高。
好处
我们从这个过程中得到了一些有价值的东西:
- 我们对数据有了更深入的了解。
- 我们可以让专家讨论分歧和未标记的样本,并进一步了解领域内的困难
- 我们有一个基于多数的基础事实数据集,我们可以计算一段时间。
结论
在本文中,我想说服您为什么注释主要对于理解您的领域很重要,而不仅仅是对于创建数据集以及如何使用 Doccano 来实现这个目标。
我恳求你在进入一个新的领域时练习自我注释,同时制定你的类标签,甚至在考虑寻找算法解决方案之前。
我要感谢塞缪尔·杰弗罗金的宝贵见解,感谢他在许多个月前为我指明了道路。
Ori Cohen 博士拥有计算机科学博士学位,主要研究机器学习和脑机接口(BCI)。他在一家智能城市初创公司领导了一个数据科学团队,主要利用机器和深度学习进行自然语言处理(NLP)和理解(NLU)研究。目前,他是 TLV 新遗迹公司在 AIOps 领域的首席数据科学家。他定期在 Medium.com 的上撰写关于管理、流程和所有数据科学的文章。
理解零射击学习——让 ML 更人性化
一个模型如何识别它没见过的东西的直观概述。
简介——什么是零起点学习?
Z ero-shot 学习允许一个模型识别它以前没有见过的东西。
想象一下,你的任务是设计最新最棒的机器学习模型,可以对所有动物进行分类。是的,所有的动物。
使用您的机器学习知识,您会立即理解我们需要一个带标签的数据集,每个动物至少有一个例子。世界上有 1,899,587 种已描述的物种,所以你需要一个包含大约 200 万个不同类别的数据集。
呀。
你的模型要分类的动物。Unsplash 上的照片。
你可能已经注意到了,获取大量高质量的标签数据是很困难的。非常辛苦。
当你的模型需要学习大量不同的种类(比如动物种类)时,这并没有什么帮助。
那么我们如何解决这个问题呢?
一种方法是减少我们的模型对标记数据的依赖。这就是零触发学习背后的动机,在这个过程中,你的模型学习如何对以前没有见过的类进行分类。
在动物物种分类示例中,您的模型可能能够预测右下角的图像是一只“熊猫”,即使它在训练期间没有明确看到一只“熊猫”的标记示例。
很疯狂吧。!
在下一节中,我们将通过一些采用零拍摄设置的模型示例来了解这种看似神奇的方法是如何工作的。
零拍学习是如何运作的?
虽然在文献中有多种零镜头学习的方法,但本文主要关注 OpenAI 最近提出的一种称为对比语言-图像预训练(CLIP)的方法,该方法在零镜头设置中表现良好【2】。
CLIP 的目标是学习如何在没有任何明确标签的情况下对图像进行分类。
直觉
就像传统的监督模型一样,CLIP 有两个阶段:训练阶段(学习)和推理阶段(做出预测)。
在训练阶段,CLIP 通过“阅读”每个图像对应的辅助文本(即句子)来学习图像,如下例所示。
CLIP 架构的可能输入示例。幸运的猫在 Unsplash 上的照片
作为一个人类(假设你以前从未见过猫),你可以阅读这篇文字,并可能破译图像中的三个的东西是“猫”。如果你看到了足够多的配有“猫”字说明的猫的图片,很有可能你会非常擅长判断一张图片中是否有猫。
类似地,通过查看不同对象的 4 亿个图像-文本配对,该模型能够理解特定短语和单词如何对应图像中的特定模式。一旦有了这种理解,模型就可以使用这种积累的知识来推断其他分类任务。
但是等一下。
你可能会疑惑,这种“辅助文本”在技术上不就是一种标签吗,从而渲染这个过程而不是我一开始承诺的无标签学习?
虽然辅助信息(即标题)是一种监督形式,但它们不是标签!通过这些辅助信息,我们能够使用信息丰富的 非结构化数据,而不是必须自己解析非结构化数据来手工制作单个标签(即“这是我的三只可爱的猫……”→“猫”)。
设计一个标签需要时间,并删除潜在有用的信息。通过使用 CLIP 的方法,我们可以绕过这个瓶颈,最大化模型可以访问的信息量。
潜水更深——零射击训练
模型究竟如何能够从这些辅助文本中学习?
正如该架构的名字所暗示的那样,CLIP 使用了一种叫做对比学习的技术来理解图像和文本配对之间的关系。如果你不熟悉对比学习,我建议在继续之前先看看这篇关于对比学习的文章。
剪辑方法概述。图来自[2]。
本质上,CLIP 的目标是*最小化图像编码和相应文本之间的差异。*换句话说,模型应该学会使图像的编码和相应文本的编码尽可能相似。
让我们进一步分析这个想法。
**什么是编码?**编码只是数据的低维表示(上图中的绿色和紫色方框)。理想情况下,图像或文本的编码应该分别代表该图像或文本最重要的、可区分的信息。
例如,所有猫的图像应该有相似的编码,因为它们都有猫在里面,而它们应该有不同于狗的编码。
请注意,在这个理想世界中,相似对象的编码也是相似的,不同对象的编码也是不同的,对图像进行分类变得非常容易。如果我们给模型输入一个图像,编码与模型见过的其他一些“猫”编码相似,它就可以说是一只“猫”!
看起来好的图像分类的关键是学习理想的图像编码。这实际上是 CLIP(和大部分深度学习)背后的整个前提!我们从糟糕的编码开始(即每个图像的随机编码),我们希望模型学习理想的编码(即猫图像有相似的编码)。
为了更直观地了解这种学习数据表示的想法,我推荐下面的文章:
**为什么图像编码应该与其对应的文本编码尽可能相似?**现在我们知道了什么是编码,以及为什么学习好的编码很重要,我们可以探索为什么我们要强制模型使图像和文本编码相似。
回想一下,我们的最终目标是学习如何对图像和图像进行分类,因此我们需要学习好的图像表示(编码)。当我们有标签时,我们能够通过最小化模型输出和预期输出(标签)之间的差异来学习好的编码。
但是在 CLIP 的情况下,我们没有单一的模型输出,也没有单一的期望输出。相反,我们可以将训练图像的图像编码视为模型输出,将相应标题的文本编码视为预期输出。
事实上,我们可以想象**模型正在学习如何为我们创造好的标签。**由于文本编码器也在这个过程中更新,随着时间的推移,模型学习如何从文本中提取更重要的信息,从而给我们一个更好的文本编码(预期输出)。
考虑到这一点,我们应该尽量减少图像和文本编码之间的差异。*这是因为我们知道相似的图像可能会有相似的文本编码,*就像在标签设置中相似的图像会有相同的标签。因此,模型将学习为相似的图像生成相似的编码。
潜得更深——零射击推断
一旦该模型在足够多的图像-文本配对上得到训练,它就可以用于*推理(使用该模型对看不见的数据进行预测)。*这是设置变得非常聪明的地方。
在推理阶段,我们通过首先获得所有可能标签的列表来设置典型的分类任务。因此,如果我们要预测动物物种,我们将需要一个所有动物物种的列表(例如,企鹅、熊猫、刺螈等。)(图中步骤 2)。
Polina Razorilova 在 Unsplash 上拍摄的照片。作者图改编自[2]中的图。
然后,每个标签将由步骤 1 中预先训练的文本编码器进行编码。
现在我们有了标签编码,从 T₁到 Tₙ,我们可以把我们想要分类的图像,通过预训练的图像编码器,并使用一个叫做 余弦相似度 的距离度量来计算图像编码与每个文本标签编码的相似度。
我们现在将图像分类为与图像具有最大相似性的标签*。我们可以这样做,因为我们知道模型已经学会了为图像生成尽可能与其文本副本相似的编码,其中大多数可能包含我们试图分类的标签。*
瞧啊。我们已经实现了零射击能力!
有趣的是, CLIP 是一种相对较新的方法,与更传统的零镜头学习方法相比,它具有独特的简单性。这些概念中的一些,包括基于嵌入的方法和生成方法将在下面的文章中直观地解释。
https://www.kdnuggets.com/2021/04/zero-shot-learning.html
无论使用哪种方法,零射击学习的一个共同主题是,我们可以使用一些不是明确标签的**辅助信息(即文本描述)**作为监督的弱形式。
零射击学习的潜在应用
一般来说,零触发学习在需要大型标注数据集但不容易获得的情况下最有用。
下面,我们来看看【3】中概述的一些潜在的现实应用。
新冠肺炎胸部 x 光诊断
新冠肺炎胸部 x 射线诊断是一个完美的(如果你在 2021 年阅读这篇文章,这是一个热门话题)例子,说明零射击学习如何应用于医学相关和低标签设置。
由于在疫情的初始阶段很少有新冠肺炎阳性的胸部 x 射线,因此很难创建一个高性能的模型来区分 COVID 与非 COVID,或 COVID 与更常见的呼吸系统疾病,如肺炎。
胸部 x 光的例子。照片由疾控中心在 Unsplash 上拍摄
为了解决这个标签很少的问题,我们需要一个模型,它可以了解新冠肺炎只看过其他疾病的图像和新冠肺炎胸部 x 光片的一些辅助信息——没有 COVID 的显式标签。
在这种情况下,我们可以使用新冠肺炎胸部 x 光片的文本描述作为一种辅助信息。下面是一个例子。
“可见双侧多灶斑片状 GGOs 和实变.”—【3】
据我所知,还没有正式发表的作品证明零炮适用于 COVID 分类。然而,辅助文本信息的可用性突出了零射击学习应用于这样一个医学上重要任务的潜力。
自动驾驶汽车
特斯拉的图像。亚历山大·赞恩在 Unsplash 上拍摄的照片
人工智能几乎肯定会看到它以前没有看到的东西的另一个关键例子是自动驾驶汽车的感知系统。
事实上,即使是人类在路上看到新的物体,他们也不知道如何做出反应。如果我们想设计安全、坚固的自动驾驶汽车,我们需要让它们具备适应未知环境的能力。
同样,据我所知,很少有作品将零射击方法应用于自动驾驶感知系统。然而,一些有趣的想法包括使用概念车的文本描述来教一个模型区分普通汽车[3],并以零射击的方式将模拟中学习的政策转移到一个城市[1]。
关键要点
- 零镜头学习是一种设置,在这种设置中,模型可以学习识别以前在训练中没有明确看到的东西。
- 有不同的零射击学习方法,但一个共同点是在训练过程中使用或编码辅助信息,如文本描述,而不是显式标签。
- 零射击学习在现实世界中有几个潜在的应用——从新冠肺炎病诊断到无人驾驶汽车。
本文讲解的作品只是冰山一角!随着该领域的发展,我们稳步朝着我们许多人设想的人工智能前进:一个不受标记数据结构严格限制的人工智能,一个可以理解以前从未见过的东西的人工智能,一个更像人类的人工智能。
参考
【3】雷扎伊,m .&沙希迪,M. (2020)。零触发学习及其在自主车辆新冠肺炎诊断中的应用:综述。智能医学,100005。
笔记
- 是的,“带刺的笨蛋”是真实存在的。请参见https://www . tree hugger . com/animals-with-completely-almony-names-4864307
- 这是对 CLIP 的简化解释。建议看一下 OpenAI 的论文。
- 根据[维基百科](https://en.wikipedia.org/wiki/Concept_car#:~:text=A%20concept%20car%20(also%20known,may%20not%20be%20mass%2Dproduced.)的说法,概念车是“展示新款式和/或新技术的汽车”。换句话说,它们看起来很古怪,足以与普通汽车区分开来。
如何撤销 Git 中的最后一次本地提交
了解如何在 Git 中撤销最近的本地提交
由 Roman Synkevych 在 Unsplash 上拍摄的照片
介绍
Git 是帮助开发人员、数据科学家和工程师编写代码版本的最强大的工具之一。使用 Git 时,一个非常常见的场景是当您意外提交文件时,您需要撤销最近的提交,以避免将这些文件中所做的更改推送到远程主机。
在今天的文章中,假设您没有将最后一次提交推送到远程主机,我们将讨论几个可能的选项。具体来说,我们将探索如何
- 撤消最近的提交,并清除对提交的文件所做的所有更改
- 撤销最后一次提交,并保留修改文件中的更改
- 撤销最近的提交并且保留文件和索引中的更改
撤消上次提交并放弃对文件所做的所有更改
有时,除了撤销最近的提交,您可能还想放弃对该特定提交中包含的文件所做的所有更改。在这种情况下,你需要做一个硬复位。
**git reset** **--hard HEAD~1**
--hard
标志表示git reset
命令将重置机头、索引和工作树。这意味着提交将被撤销,此外,对文件所做的更改也将被丢弃。HEAD~1
翻译为“使用第一个父代从HEAD
返回 1 次提交”。通常一个提交只有一个父级,所以在大多数情况下这应该可以解决问题。注意HEAD~1
相当于HEAD~
。
撤消上次提交,但保留对文件所做的更改
或者,您可能仍然希望进行最近的提交,但同时在本地保留对文件所做的更改。在这种情况下,您只需在运行git reset
命令时指定HEAD~1
:
**git reset HEAD~1**
该命令将指示 Git 将指针HEAD
向后移动一次。但是,对文件所做的更改不会受到影响。现在,如果您运行git status
,您应该仍然能够在本地看到对文件所做的更改。
撤消上次提交并保留索引和本地文件更改
最后,您可能想要撤销最后一次提交,保留对文件的更改,同时**保留索引,**也是如此。
索引(也称为暂存区)是准备新提交的地方,它包含新提交中要包含的所有内容。例如,每次你运行git add <filename>
的时候,一个文件被从工作的三个文件中添加(或更新)到索引中。实际上,索引是一个存储在<repo>/.git/index
下的二进制文件,包含。
**git reset --soft HEAD~1**
--soft
标志表示git reset
命令只会重置机头,而索引和工作树保持不变。
现在,如果你运行git status
,你应该能够看到相同的文件仍然在索引中。
最后的想法
在今天的简短指南中,我们探索了几种不同的方法来撤销 Git 中最近的本地提交。有时,您可能想要撤消最近的提交,并放弃对已修改文件所做的所有更改,而在其他情况下,您可能只想撤消最近的提交,但同时保留更改。
但是请注意,只有当您尚未将提交推送到远程主机时,我们在本文中讨论的选项才适用。关于git reset
命令的更多细节,您可以在命令行中运行git reset -h
来显示使用说明。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
https://betterprogramming.pub/how-to-merge-other-git-branches-into-your-own-2fe69f70a2b4 https://betterprogramming.pub/11-python-one-liners-for-everyday-programming-f346a0a73f39
歧视性人工智能举例说明
歧视性人工智能以实例和视觉效果展示
右边的照片由 Unsplash 上的 Divya Agrawal 拍摄,左边的图片由作者拍摄
人工智能越来越多地用于做出直接影响我们的决定,例如工作申请、我们的信用评级、约会网站上的配对。因此,人工智能是非歧视性的,决策不会偏向某些种族、性别和肤色,这一点很重要。
歧视性人工智能是一个非常广泛的主题,超出了纯粹的技术方面。然而,为了让它更容易理解,我将使用例子和视觉效果来展示歧视性的人工智能。这将会给你一个发现歧视性人工智能的方法。
语境
让我首先建立这个例子的背景。业务环境与银行业务中的信用贷款流程相关。让我们假设银行已经建立了一个人工智能,它将查看贷款申请数据,并决定是否批准或拒绝它。
业务内容的图示(作者提供的图片)
贷款申请数据包含以下信息:收入、性别、职业、子女数量、个人是否拥有房屋或汽车等资产。
先看歧视艾
人工智能接受训练的数据也具有关于先前贷款是否被接受的决策的历史信息。
训练数据快照(图片由作者提供)
让我们假设人工智能已经在决策树算法上接受了训练,如下所示。决策树中的每个节点代表数据列和一个阈值。
基于决策树的贷款审批 AI 模型(图片由作者提供)
该决策树的输出是“是”或“否”,指示信用贷款是被接受还是被拒绝。现在,当你看到性别 _ 女性或性别 _ 男性等节点时,这已经表明人工智能模型正在区分男性和女性,以做出贷款批准的决定。这是一个可能的迹象,表明这个人工智能是歧视性的。
确认大赦国际的歧视性质
现在让我们举一些例子来证实人工智能是否具有歧视性。让我们看看这两个应用程序。一封来自职业为护士的女性,另一封来自职业为销售经理的男性。
证实 AI 歧视行为的例子。仅显示示例字段(图片由作者提供)
工资水平大致相等,女性的工资略高于男性申请人。两位申请人都拥有一辆车和一栋房子。
现在让我们为两个申请人做贷款批准预测。女性申请人的决策途径如下所示。决定是不批准贷款。你可以看到路径中的一个决策节点是性别是女性。
女性候选人的决策路径(图片由作者提供)
现在让我们预测一下男性申请人。下面显示的是决策路径。令人惊讶的是,人工智能的决定是批准,并给出了一个大大的是。
男性候选人的决策路径(图片由作者提供)
尽管两位申请人的收入水平相似,拥有的资产也相似,但女性申请人被拒绝了,而男性申请人获得了批准。
这是一个明显的迹象,表明这是一个歧视性的人工智能。
理解为什么这个人工智能是歧视性的
让我们使用 SHAP(Shapely Additive Explanation)分析来深入理解为什么 AI 会做出如此歧视性的决定。这是女申请人的 SHAP 分析。
女性申请人的 SHAP 分析
蓝色条表示对信贷批准有积极贡献的因素,红色条表示对信贷批准有消极贡献的因素。收入和拥有房子是积极的贡献,但身为女性有负面影响。
这是 SHAP 对男性求职者的分析。
男性申请人的 SHAP 分析
对于男性求职者来说,收入和住房是积极因素,但身为男性也是积极因素。所以很明显,身为女性对女性申请者没有帮助。
歧视行为的根源
现在让我们看看歧视行为背后的根源。这是人工智能训练数据的柱状图。X 轴是性别,Y 轴是 AI 的训练数据中的信用贷款批准数。
训练数据中的偏差
培训数据中获得批准的男性申请者人数几乎比女性申请者多 3 倍。这被称为“偏见”,这导致了歧视性的人工智能。
无性别模式——一种可能的解决方案?
我们可以尝试创造一个没有性别的模型。让我们看看是否有帮助。这是没有性别的决策树模型。它在决策过程中没有性别特征。
没有性别的决策树模型(图片由作者提供)
以下是女性候选人的决策路径(不考虑性别领域)。决定仍然是不批准信用贷款。
女性候选人在无性别模型上的决策路径(图片由作者提供)
以下是男性候选人的决策路径(不考虑性别字段)。决定是批准信贷贷款。
无性别模型中男性候选人的决策路径(图片由作者提供)
所以即使我们去掉了性别,也没有什么变化。为什么会这样?现在让我们再一次使用这里显示的热图来分析 AI 被训练的历史数据。
培训数据中批准数量的热图
热图的 X 轴是性别,Y 轴是职业。我们看到人工智能被训练的数据有更多的女性是护士,更多的男性是销售人员。
由于女候选人是护士,申请被 AI 拒绝。同样,由于男性候选人是一名销售人员,申请被 AI 接受。
因此,即使我们去除了性别领域,职业仍然是性别的替代品。
因此,无论有无性别,这两种模式都会导致相同的歧视性结果。
数据中性别的平等代表性
歧视性人工智能的解决方案是在用于训练人工智能的数据中男女具有平等的代表性。
性别平等原则也需要适用于数据。
额外资源
网站(全球资讯网的主机站)
你可以访问我的网站进行零编码分析。https://experiencedatascience.com
每当我发布一个新的故事,请订阅保持通知。
https://pranay-dave9.medium.com/subscribe
你也可以通过我的推荐链接加入 Medium
https://pranay-dave9.medium.com/membership
Youtube 频道
这是我在 https://www.youtube.com/c/DataScienceDemonstrated 的 YouTube 频道
T5 的链接
SQL 中的 UNION:一个必须知道的子句
分析多个表的结果
来源:图片来自 Pixabay
我们在 SQL 中学习的许多常见查询(如 GROUP BY)通常用于孤立地分析一个表。在将两个表连接在一起并将它们视为一个表时,也经常使用 JOIN 子句。
但是,经常会有需要跨多个表分析结果的情况。使用 UNION 子句可以做到这一点,本文将举例说明该子句如何工作。
UNION vs UNION ALL vs INTERSECT
考虑以下两个表:
houses=# select * from onebedroom;
city | price
----------+-------
Paris | 1000
Munich | 850
Rome | 930
Helsinki | 1200
(4 rows)houses=# select * from onebedroom_v2;
city | price
-----------+-------
Helsinki | 1200
Berlin | 750
Prague | 500
Amsterdam | 1400
(4 rows)
这两个表格显示了欧洲主要城市一居室公寓的价格(数值是假设的,由作者虚构)。
UNION、UNION ALL 和 INTERSECT 如何组合这两个表的结果?
在这两个表中,我们可以看到城市赫尔辛基有一个重复的值(价格为€每月 1200)。让我们看看这个值在三个子句中是如何处理的。
联盟
当用 UNION 组合这两个表时,我们可以看到只保留了 Helsinki 条目的一个实例——删除了重复的条目。
houses=# select * from onebedroom union select * from onebedroom_v2;
city | price
-----------+-------
Paris | 1000
Prague | 500
Helsinki | 1200
Berlin | 750
Amsterdam | 1400
Rome | 930
Munich | 850
(7 rows)
UNION ALL 怎么样?
联合所有
当使用 UNION ALL 子句时,我们可以看到赫尔辛基的两个条目保留在表中,没有删除重复的条目。
houses=# select * from onebedroom union all select * from onebedroom_v2;
city | price
-----------+-------
Paris | 1000
Munich | 850
Rome | 930
Helsinki | 1200
Helsinki | 1200
Berlin | 750
Prague | 500
Amsterdam | 1400
(8 rows)
横断
INTERSECT 子句与 UNION 子句的工作方式不同,因为该子句只标识两个表共有的条目,并维护该条目—所有其他条目都被删除。
在这个例子中,我们可以看到赫尔辛基条目被返回,因为这个条目对两个表都是公共的——所有其他条目都不存在。
houses=# select * from onebedroom intersect select * from onebedroom_v2;
city | price
----------+-------
Helsinki | 1200
(1 row)
对表格中的值求和并求平均值
现在,让我们考虑下面的表(同样,值是假设的,由作者编造)。
houses=# select * from onebedroom;
city | price
--------+-------
Paris | 1000
Munich | 850
Rome | 930
(3 rows)houses=# select * from twobedroom;
city | price
--------+-------
Paris | 1400
Munich | 1300
Rome | 1500
(3 rows)houses=# select * from threebedroom;
city | price
--------+-------
Paris | 2800
Munich | 2200
Rome | 2000
(3 rows)
在巴黎、慕尼黑和罗马,我们希望:
- 对每个城市的值求和
- 平均每个城市的值
让我们看看如何在第一个实例中对值求和。我们将从前两个表开始。
houses=# select city,sum(price) total
houses-# from
houses-# (
houses(# select city,price
houses(# from onebedroom
houses(# union all
houses(# select city,price
houses(# from twobedroom
houses(# ) t
houses-# group by city;
city | total
--------+-------
Rome | 2430
Paris | 2400
Munich | 2150
(3 rows)
在上面的脚本中,我们可以看到 UNION ALL 子句被用来组合两个表的结果,并且价格的总和( sum(price) )被定义为一个总值。
要对三个表中的值求和,只需使用两个 UNION ALL 子句:
houses=# select city,sum(price) total
houses-# from
houses-# (
houses(# select city,price
houses(# from onebedroom
houses(# union all
houses(# select city,price
houses(# from twobedroom
houses(# union all
houses(# select city,price
houses(# from threebedroom
houses(# ) t
houses-# group by city;
city | total
--------+-------
Rome | 4430
Paris | 5200
Munich | 4350
(3 rows)
对于平均值,该条款实际上保持不变。这一次,我们只是要求价格的平均值,而不是总和。
houses=# select city,avg(price) total
houses-# from
houses-# (
houses(# select city,price
houses(# from onebedroom
houses(# union all
houses(# select city,price
houses(# from twobedroom
houses(# union all
houses(# select city,price
houses(# from threebedroom
houses(# ) t
houses-# group by city;
city | total
----------+-----------------------
Rome | 1476.6666666666666667
Helsinki | 1200.0000000000000000
Paris | 1733.3333333333333333
Munich | 1450.0000000000000000
(4 rows)
在上述子句中还可以使用其他聚合函数,如 MIN、MAX 等。
结论
在本文中,您已经看到:
- 工会条款如何运作
- UNION、UNION ALL 和 INTERSECT 之间的区别
- 如何计算多个表格中数值的总和及平均值
非常感谢您的宝贵时间,非常感谢您的任何问题或反馈。
参考
- 堆栈溢出- SQL:如何对不同表中的两个值求和
- 斯蒂芬斯、琼斯、普勒(2016)。24 小时内 SamsTeachYourself SQL
免责声明:本文是在“原样”的基础上编写的,没有担保。它旨在提供数据科学概念的概述,不应被解释为专业建议。本文中的发现和解释是作者的发现和解释,不被本文中提到的任何第三方认可或隶属于任何第三方。作者与本文提及的任何第三方无任何关系。