数学如何帮助控制流行病
分室模型
来源:Fusion Medical Animation 的 Unplash
这总是一个不确定性。我们总是在传染病轮盘赌桌上(威廉·沙夫纳博士)
有了现在的 Covid 19 疫情,我们可以看到沙夫纳博士的上述引用是多么准确。不确定我们什么时候会处于疫情。自古以来,人们就知道传染病会使人虚弱和死亡。霍乱、麻疹、疟疾、埃博拉、登革热和当前的 Covid 19 只是几个例子。
虽然一些疾病可以通过药物、疫苗、减少病媒数量或行为改变来治疗,但找到正确的控制策略来控制问题同样至关重要。当科学家不知疲倦地努力寻找治疗方法时,数学可以在各种情况下提供帮助。了解疾病的传播并控制它是这些领域之一。
本文的重点将放在一个非常基本的模型上,它被称为 SIR。SIR 模型是一种描述传染病动力学的房室模型。
背景
根据维基百科,对房室模型的研究始于二十世纪初,Ross 和 Hudson(1916-17)、Kermack 和 McKendrik (1927)以及 Kendall (1956)在该领域做了大量的关键工作。
与任何其他数学模型一样,在开发基础模型时使用了假设和限制。看到如何从数学上描述这种差异,并用来理解面临约束时的差异,这很有意思。正如我之前所说,这是一个基本模型,许多其他科学家和研究人员在 SIR 的基础上创建了复杂的架构模型,使限制更接近现实。然而,要理解其他模型,需要对这种范式有一个基本的理解。
数学建模
整个种群首先被分成三个部分,称为“可接受的”、“不传染的”、“不传染的”、“被发现的”,这也是这个模型名字的由来。假设该人口规模稳定,没有出生、死亡或移民等事件。
资料来源:作者- SIR 模型
- 所有可能被这种疾病感染的人。通常在开始的时候,每个人都会受到影响。
- I 易感染者:
所有被疾病感染并有能力感染易感者的人。这些人会在特定的时期内康复 - 发现:
这些人对疾病产生了免疫力,不再易感。免疫力是由康复的人获得的,他们没有再次脆弱的前景。
我们先定义一些变量。
- s,I,R :
分别在易感、感染和恢复隔室中的个体数量 - a : a > 0
一个参数,表示一种疾病可以通过一个感染者传播到什么程度。这可以使用诸如接触的可能性、疾病传播的可能性等因素来计算。 - b : b >0
一个参数,表明个人在给定的时间范围内,从给定的疾病中恢复的程度。
因为人口在任何给定的时间都是固定的,我们可以说三个隔间里的总人数等于时间 t 时的人口数量。
S(t) + I(t) +R(t) = N
为了更好地了解疾病的动态,正在检查每个房室的变化速度。三个简单的微分方程可以用来表达这一点。
- dS/dt = -aSI 因此,我们将 S 乘以 I ,然后乘以上述反映感染率的正常数 a。这个术语变成了负面的,因为随着时间的推移,人们会被感染,S 区会缩小。
- dI/dt = aSI — bI 这里增加了从易感人群中以 a 的比率转移出来的新感染者,当他们康复后,由于不能再传染他人而离开感染区。受感染人数越多,离开隔离室的人就越多,所以我们用常数 b 乘以 I,该常数描述了恢复率。当它们离开感染区室时,第二项为阴性。
- dR/dt = bI
来源:作者图片:疾病动态图解
如果我们用图表来检验,我们可以观察到,在开始时,每个人都属于易感群体。然后,当他们被感染时,黄色图形开始变淡,红色图形表示受感染人数开始增加。随着人们从感染进展到康复,随着易感人数的减少,感染人数曲线开始下降。
如上所述,疾病传播的动力学可以用数学方法解释和描述。现在让我们来看看在了解动力学之后我们可以推导出的一些信息。
新出现的感染会在人群中传播吗?
答案在第二个等式中,
dI/dt = aSI — bI
为了阻止扩散,第二隔间中的人数应该随着时间的推移而减少。这意味着随着时间的推移,离开第二隔间的人数应该高于进入第二隔间的人数,这意味着即使新的一群人被感染,他们也应该很快离开系统。
来源:作者——传染性是会增强还是减弱
如图所示,如果传染性要降低,ℛ0 应该小于 1。如果不这样,感染将会在人群中传播,人们将不会很快康复。
此外,如果随着时间的推移,易感人群的人数没有减少,疾病就有可能爆发。让我们将易感人群的数量定义为常数 S0。然后,
来源:作者
当微分方程如上求解时,将显示感染计数随着时间呈指数增长。那么这种疾病爆发的可能性很大。
基本复制号
我们上面讨论过的ℛ0,实际上被称为基本再生产数。
**ℛ0 = as/b;**其中 a —传输速率,b —恢复速率
在易感人群中,它被定义为受一个感染者影响的预期人数。因此,如果 R0 小于 1,疾病将不复存在;否则,可能会爆发疾病或流行病。R0 越低越好。
根据 ℛ0 如何采取行动控制疫情
根据上述方程,ℛ0 与传播率和人群中易感个体的数量成正比,但与恢复率成反比。因此,为了保持ℛ0 <1 either a or S should be reduced or b should be increased.
- Reducing the transmission rate (a)
,假设某种疾病的传播是通过与感染者的密切接触而发生的,并且没有适当的消毒方法。因此,为了控制ℛ0,易感人群必须与其他人保持安全距离,进行适当的消毒活动,或者当局必须隔离感染者或封锁城市以限制传播率。 - 减少易感个体的数量
如果一种药物或疫苗能够产生免疫力,通过增加这些和减少易感人群,就可以减少ℛ0。 - 提高采收率(b)
这是一个较难调整的参数,但通过适当的措施,如果人们继续活着,采收率提高,ℛ0 也可以降低。
拉平曲线
理解疾病动态的另一个关键好处是,如果监控正确,它将防止医疗系统负担过重。如果作出适当的努力来限制感染室的增加,医院床位和 ICU 可以得到有效的控制。如果操作不当,回收率(b)可能会降低,ℛ0 可能会增加。
来源:作者-拉平曲线
当传播率降低时,如通过封锁或任何其他适当的干预,人群中的感染者数量减少,如上图所示。因此,卫生保健行业随时都有资源来应对这一问题。它还将高峰期推迟,让医疗服务提供者有更多的时间做准备。
群体免疫
如果通过适当的干预可以减少 s 室,并且足够多的人对这种疾病免疫,ℛ0 将得到控制,对这种疾病将有抵抗力。当高比例的人口获得免疫时,群体免疫就实现了,使得疾病在人与人之间的传播极其罕见,因此保护了整个人口。
摘要
如上所述,房室模型可用于更好地理解疾病动态,并且当适当建模和改进时,可用于采取适当的行动。在某些情况下,假设群体是封闭的,或所有成员都是易感的,或当恢复时,不会是易感的,可能是不现实的。除了文献中的微分方程之外,还有许多基于此的模型,以及许多其他用于建模疾病的方法。
最重要的是,在将每种方法应用于特定案例或将其用作更全面分析的合适起点之前,要了解每种方法的优势和局限性。
参考
- https://www . mayo clinic . org/diseases-conditions/coronavirus/in-depth/herd-immunity-and-coronavirus/art-20486808
- https://scipython . com/book/chapter-8-scipy/additional-examples/the-sir-epidemic-model/
- https://en . Wikipedia . org/wiki/compartment al _ models _ in _ epidemiology
- https://intermountainhealthcare . org/blogs/topics/live-well/2020/04/what-the-difference-a-a-疫情-an-epidemic-地方病-an-outbreak/
微学习如何帮助您在每天不到 10 分钟的时间内提高数据科学技能
这种电子学习趋势可用于高效满足您的数据科学目标
斯里兰卡在 Unsplash 拍摄的照片
现在,赞美某人的注意力像金鱼一样集中是合理的。
人类曾被认为是注意力持续时间为 12 秒的优等种族,过去 15 年的研究显示人类的平均注意力持续时间下降到了 8.25 秒。
金鱼的注意力持续时间是 9 秒。
人类平均每小时查看收件箱 30 次,每周拿起手机超过 1500 次(每天使用 3 小时 16 分钟),平均只阅读网页上 28%的单词,可以肯定地说,作为一个物种,我们很容易分心。
这种容易分心的性质很难转化为对复杂主题的研究,例如与数据科学相关的主题。
传统的学习方式不再是一种选择。进入小额学习。
什么是微学习?
微学习是一种电子学习和教学设计趋势,指的是一种教育方法,它使用小型学习单元来提供学习者实现目标所需的适量信息。
微学习是一种有效的转变,它远离了整天的课程和枯燥的 PowerPoint 演示,这些课程和演示会让参与者在头两分钟就打瞌睡。相反,我们的目标是提供小型课程,仅涵盖 1-2 个主题,可在 10 分钟内完成。
根据发表在《应用心理学杂志》上的一项研究,微学习比传统学习方法效率高 17%。这种提高的效率来自于学习者只需要消化小块的信息,这提高了主题的记忆和理解。
由软件咨询进行的一项研究发现,微学习还创造了 50%以上的学习参与度。这种参与度的提高来自于与人类注意力持续时间相匹配的学习课程的实施。
微学习的使用对数据科学学习体验有何益处?
简而言之,数据科学的研究是一个漫长而艰巨的过程。再加上需要成为一个拥有编程、数学、机器学习、人工智能、商业头脑等技能的全面发展的个人,通往数据科学的旅程往往没有被看透。
数据科学就像高尔夫。你可以花一生的时间去掌握它,但你只会触及皮毛。
因此,学习过程必须尽可能地快速和有效。不,这并不意味着走捷径,在你的知识中留下基础漏洞,以便更快地找到“好”的东西。这意味着将复杂的主题分解成小的课程,在这一天结束时,你已经学习了 1-2 个主题,产生了 4-5 个收获。
小额学习适合谁,不适合谁。
对于使用微学习来研究数据科学,有一点需要注意。
对于那些已经具备数据科学技能基础的人来说,微学习是一种有益的学习工具。为什么?因为使用微学习方法学习数据科学的基础需要几十年的时间。那些希望过渡到数据科学的人通常会在给定的时间内这样做(通常是在他们的安全网耗尽之前)。因此,每天只花 10 分钟学习概念会让你在 6 个月的学习后只知道数据科学的基本框架。
**这种学习方法适用于:**已经具备数据科学基础知识,并且希望通过学习更复杂的主题来提高技能的人。这些人已经可以进行基本的数据分析,可以编写代码,并可以应用他们的发现来解决业务问题。对于专业人士来说,这种学习方法是一种很好的方式,可以在不中断日常工作的情况下,每天抽出 10 分钟来提高他们在特定主题上的技能。
**这种学习方法不适合:**完全是数据科学新手的人。这种学习方法可以与更传统的学习方法一起使用,以补充更复杂的主题。
如何利用微学习提高数据科学技能?
为自己建立微学习模块可能比登录 MOOC 或观看 Youtube 视频需要更多的时间,但结果可以在更短的时间内产生巨大的改善。
如何设置您的个性化小额学习模块:
- 留出专门的时间来计划你的内容:要想成功地制定一个小额学习计划,你需要在这个过程中投入时间。几个小时就能决定你想学什么,以及你打算怎么学。
- **列出你想学的概念:**这个列表将为你的模块设定框架。例如,如果你想学习 NLP,列出所有与 NLP 相关的概念。将它们分解成单独的部分,或者将它们组合成小的逻辑模块。
- **确保微学习过程适合每个概念:**有时,微学习不足以学习深入的概念。例如,通过微学习无法学习完整的基本统计数据,因为需要更深入和长期的研究。测试一个概念是否适合小额学习的一个好方法是确定你认为学习这个概念需要多长时间。如果花费的时间超过 1 小时,可能不是为了小额学习。
- 削减脂肪:微学习就是在短时间内学习少量的信息。这意味着你必须把内容精简到最低限度。包括你需要的一切,没有你不需要的。
- 确保每个模块或课程都有一些要点,并且只涵盖 1-2 个目标。想要把所有东西都加入到课程中会变得很容易,尤其是当它涉及到你感兴趣的话题时。然而,这些必须保持微经验,以确保你得到微学习的全部效果。如果你的课回答了 1-2 个问题,那太好了!如果它回答更多,尝试进一步分解内容。
- **如果没有效果,不要把自己局限在 10 分钟的课程中:**有时候,不管你减掉多少脂肪,一个概念不会浓缩成 10 分钟的课程。在这种情况下,不要限制自己。如果课程长度少于 20 分钟,请按原样完成,或者考虑分成两节课。
- **利用多媒体让事情变得有趣:**看课本很无聊。看个视频就不是了。选择有趣的媒体,让你参与其中,增加学习体验。
- **使用微评估来评估你的进步:**小测试和小测验是评估你在学习这些主题方面的进步的好方法。简单测试的例子包括但不限于在 HackerRank 或 Kaggle 上完成一个编码挑战,或者花 10 分钟写下你对某个主题的所有了解,并将你写的内容与你对该主题的笔记进行比较。
微观学习之后是微观实践。
没有微观实践,微观学习就什么都不是。
采用新技能需要实践,而不是简单的死记硬背。使用微学习来学习数据科学概念也不例外。
诀窍是将微学习模块与微实践课程配对,微实践课程使用在更实际的情况下学到的确切技能。例如,如果您刚刚完成了 NLP 中关于标记化的微学习模块,那么您应该完成一个微练习,在该练习中,您获取一个运行文本的数据集,并将其分割成句子和单词,也称为标记。
微实践可以简单到在 HackerRank 或 Kaggle 上完成一个编码挑战,也可以复杂到在你自己的个人项目中实现你的新技能。
无论是哪种类型的实践,10 分钟的微观实践会议应该在完成微观学习模块后进行,以巩固你的新知识。
最后的想法。
当谈到学习数据科学时,必须使用书中的每一个技巧才能取得成功。这意味着利用一切可能的学习形式,确保你充分利用时间,学习必要的概念,以便在这个以结果为导向的行业中变得更加有效和有影响力。
通过探索不同的学习方法,你会有最好的机会掌握一个无法掌握的知识领域。
对于一个注意力跨度比金鱼还小的物种来说,我们需要所有我们能得到的帮助。
《扫雷》如何让我们以不同的方式思考数据
我们生活在一个不确定和信息不完善的世界
资料来源:矿业(LTS Ubuntu 18.04)
业余时间经常喜欢下棋扫雷(对,别笑)。
这两款游戏中,我一直觉得扫雷比较难懂,游戏规则一直显得很不透明。
然而,后一个游戏更类似于现实世界中的情形。这就是它与数据科学相关的原因。
完美信息与不完美信息
相比之下,在国际象棋中,不管一个人的游戏能力如何,所有的玩家在任何时候都有完美信息。
一个人总是可以看到棋盘上的每一个棋子,而且任何一方都不拥有相对于另一方的任何信息优势(除了从玩游戏的经验中获得的潜在知识)。
出于这个原因,人工智能被广泛用于训练计算机在国际象棋中获胜。这在 1997 年被证明是成功的,当时一台 IBM 超级计算机被训练击败特级大师加里·卡斯帕罗夫。
从这个例子很容易推断出,人工智能模型可以被训练来潜在地解决这个世界上呈现给我们的任何给定问题。然而,事实并非如此——因为人们总是在一个信息不完全的世界里工作。
当一个人考虑扫雷游戏时,不完善的信息总是围绕着我们。总的来说,在某些方格中有一系列的地雷。点击地雷意味着玩家自动输掉游戏。当开始游戏时,没有办法知道哪些方块是可疑的,哪些不是。一个人必须简单地点击一个给定的方块,然后期待最好的结果。
假设一个人继续玩游戏,某些方格会给出一个指示,指出哪里可能有地雷**。例如,一个数字为 1 的方块表示在原来的方块周围有一个有地雷的方块。然而,没有人知道这是哪一个方块。**
在这方面,《扫雷》是一款比国际象棋等游戏更能反映真实世界的游戏。
无论收集了多少数据,都不可能收集到 100%的数据来解释结果变量的变化。
即使这是可能的,解释这种变化的参数在未来也总是会改变的。就这一点而言,昨天非常有效的模式明天可能就不那么有效了。
所以,当面对不完美的信息时,每个决定都归结为一个概率。我们无法确切知道在决定一个特定的结果时会发生什么,但我们可以给它分配一个概率。****
例如,围绕数字 1 的方块比围绕数字 3 的方块风险小——现在后一个方块周围有三个地雷。最好避免点击那些方块!
强化学习
有趣的是,强化学习在过去曾被用来试图训练人工智能在扫雷中获胜。sdlee94 的一个例子在这里。
虽然我不太熟悉算法如何工作的细节,但作者确实指出,任何被归类为猜测的举动都会得到负面奖励,因为目标是训练计算机通过逻辑和概率揭示安全方块。
也就是说,根据结果,神经网络仍然需要超过 60,000 场训练才能达到 10%以上的胜率。
当涉及到不确定性时,即使深度神经网络在做出正确预测的能力上似乎也是有限的。即使负面结果(在这种情况下,落在一个正方形上)发生的概率很低——只要尝试足够多,它仍然会发生。
概率的重要性
在这点上,我怀疑数据科学将逐渐发展,更少依赖准确性**,更多依赖**概率。****
例如,训练模型的经典方法包括训练-测试分离,即首先使用训练数据训练和验证模型,然后通过测试集来测量准确性。
但是,较高的验证和测试分数仅表明该模型在这两个数据集上显示出较高的预测准确性。即使使用了交叉验证——该模型在能够表明它与新信息的配合程度方面仍然是有限的。
模拟分析
由于这个原因,我预见更多的重点将放在模拟分析上。例如,假设有人试图预测一家公司一段时间内的收入。正在讨论的时间序列有一个固定的均值和标准差。
我们对这个时间序列进行 10,000 次模拟,同时人为增加标准差,怎么样?在这种情况下,先验模型有多准确?
从这个角度来看,人们将会更好地了解模型在什么情况下可以表现良好,在什么情况下表现不佳。
事实上,人们可以进一步发展这一想法,用不同的参数通过模拟数据训练几个模型。根据企业可能面临的潜在情况,可以在概率基础上配置不同的模型,以便在不同的环境中进行预测。
事实上,这正是贝叶斯分析的基础,我怀疑这一领域会越来越受欢迎。
结论
尽管可以访问的数据比以往任何时候都多,但重要的是要记住现实世界是不确定的、易变的和不完美的。
当面对不完美的信息时,我们唯一能做的就是利用我们仅有的一点点信息来给不同的结果分配概率。
不仅在扫雷游戏中如此,在我们面临的几乎所有复杂的现实世界场景中也是如此。
ML 与 AI 的关系
迈克尔·泽兹奇在 Unsplash 上的照片
机器学习(ML)如何融入人工智能(AI)的奇妙世界?
人工智能
让我们从陈述 AI 到底是什么的简单定义开始:
表现 的计算机智能地 和 自主地 ,与计算机做它们被告知的事情
几十年来,软件工程师一直在构建专家系统:严格约束的、基于规则的软件解决方案,能够很好地完成单一任务。
这没什么不好!在许多情况下,这是正确的答案。考虑更新电视的固件。你可以通过设置菜单按需寻找它,或者让电视偶尔寻找它,但这是一个最好用传统技术解决的问题。它不需要智力。
现在想想开着车在大城市转悠:那个需要智能!在人工智能兴起之前,我们在无人驾驶汽车方面进展缓慢。
人工智能的类型
那么 AI 的类型有哪些呢?有三个。
第一种是 窄 AI :思考高度集中。苹果 iPhone 上的 Siri 对与电话相关的任务很有帮助,但你可以试着问它“为什么我的伴侣今天对我很生气?”。不会有太大帮助。
垃圾邮件与垃圾邮件过滤器:你上一次设置垃圾邮件规则是什么时候?你没有,AI 本质上已经解决了那个问题。
脸书的人脸识别——非常专注,非常准确——但如果你试图用它来驾驶无人机,底层的 ML 实现将毫无用处。
这就是 狭义 的意义所在:在有限的环境中提供极具性能的人工智能解决方案。
下一个类型是 一般 AI——想想那种可以媲美人类能力的智能。现在还不存在。
人类适应眼前挑战的能力强调了我们智力的敏捷性和灵活性。如果你和我需要学开叉车,我们可以。如果我们需要掌握驾驶无人驾驶飞机,我们可以。这种可以针对各种各样任务的广义智能在 AI 中还没有实现。
最后一类 AI 是 超级 AI——现在我们说的是那种我们只能推测的智能,既然超过了我们自己。
一般的人工智能必须首先在这种类型之前实现——对这可能需要什么的猜测导致了许多激动人心的科幻书籍和电影。
底线:我们没有或想法。我们不会创造它——一般的人工智能计算机会。
机器学习适合在哪里?
作者图片
因此,如果我们有 3 种类型的人工智能,机器学习在哪里?
机器学习是一种类型的 狭义的AI:它是专门打造的*,专注于相对小范围的任务。*
记住: 狭义AI是目前仅存的类型的 AI,我们沉浸其中的所有技术奇迹都是机器学习带给我们的。**
为什么是机器学习?
因为它解决了传统方法无法解决的问题
正如我们已经讨论过的,传统的软件技术已经无法破解某些难题。这些往往是机器学习大放异彩的领域。
ML 不是所有问题的解决方案——但它经常是以前的技术失败或不足的解决方案。
记住这句格言:“对拿着锤子的人来说,每个问题看起来都像钉子”。不要选择 ML——在很多领域,传统技术是正确的答案——并且将继续是正确的答案。
什么是机器学习?
大数据+算法=模型
通过筛选堆积如山的数据进行学习并让更智能完成任务的功能是机器学习模型*。这个训练过的模型然后可以被部署,并在它暴露给新的数据时发挥作用。***
传统软件不是这样的——它不会随着暴露给更多数据而进化——它只是盲目地遵循设计时的规则。
例如,在机器学习中,你可以向神经网络(这是一种类型的算法)提供大量的狗和猫的图像,然后获取该模型并将其部署到云**(如微软 Azure、谷歌云平台 GCP 或亚马逊网络服务 AWS)——然后向该模型呈现一张新的图片,并询问它是否看到了一只狗或猫。使用以前的技术,这种功能本质上是无法解决的。**
机器学习擅长什么?
替换需要大量微调或涉及一长串规则的现有系统
如果你有一个现有的软件系统,它需要不断的调整或者涉及到一系列的规则——你可能会有一个好的候选人。当维护系统的持续成本很高时,这可能是 ML 可能更适合的良好指示。
复杂的问题(想语音识别、缺陷识别等。)传统解决方案已经失败
有许多传统技术无法解决的现实世界问题。机器学习填补了这些缺口,为我们正在经历的惊人进步提供了动力。**
动态、波动的环境需要不断适应新数据
根据定义,处于高度变化状态的问题(想想不断发布的需要分类的新图片)通常最适合 ML 解决方案。
从大量数据中洞察复杂关系
当数据很小时,数据模式很明显(想象一个有 100 行的电子表格)。随着数据量的增长(想象一下有一百万行的电子表格),很快就不可能发现模式或趋势。ML 技术在这个领域表现出色。
ML 的三个主要分支
作者图片
回到我们关于狗和猫图像的例子——这将是一个属于 监督 学习的 ML 模型:算法是用数据训练的*,数据被给出正确的答案(因此得名监督)。*
无监督 学习涉及算法筛选没有答案的数据。网飞使用的推荐系统是这种 ML 实现的一个很好的例子——算法正在查看观众的流媒体习惯,并识别相似性,通过这些相似性他们可以做出未来的推荐。因此,他们将用户聚集在一起,并根据历史流媒体习惯提出明智的建议。
强化 学习在游戏界众所周知:一个在环境中运行的软件代理**进行观察*,采取动作,并接收反馈(可能是正面的或负面的)。目标是随着时间的推移,通过反复试验学会最大化正向反馈。现实世界中的应用比比皆是:游戏(当然)、机器人、智能家居设备(比如 Nest 恒温器)和自动股票交易——这只是其中的几个例子。*
结论
到目前为止,您应该对以下主题的电梯演讲感到满意了:
- 什么是 ML?
- 你为什么要在乎?
- 它和人工智能有什么关系?
您的 Google Analytics 仪表盘中丢失了多少数据?
利用自托管分析平台发现缺失数据。
米利安·耶西耶在 Unsplash 上拍摄的照片
随着许多网站采用更智能的广告方法,广告拦截器变得越来越突出。2020 年 Q2 的一项研究表明各年龄段超过 40%的互联网用户使用某种形式的广告拦截器。
广告拦截器不仅可以拦截广告,还可以通过拦截脸书和谷歌分析等跟踪标签来保护用户的隐私。uBlock Origin 等应用程序默认情况下会启用跟踪保护,而 AdBlock Plus 等其他应用程序可以轻松打开该设置。这给希望分析和理解用户数据的开发人员带来了一个潜在的问题,因为他们可能没有看到全貌。
测量缺失数据
我目前维护着两个基于网络的应用程序,每个都有超过 5000 个月的用户,我将用它们来测试丢失的数据。在这个实验中,我用一个名为 Umami 的自托管分析解决方案建立了一个并发分析服务。这是一个私有的、开源的 Google Analytics 的替代品,你可以在这里了解更多。由于鲜味是自托管的,广告拦截器不会阻止收集分析。这将为我们提供数据的完整视图。我用一些最流行的广告拦截软件测试了这一点,并确认它们都没有阻止鲜味记录数据。
在 Vercel 和 Digital Ocean 上设置了我的鲜味实例并离开网站一个月后,我比较了这两个服务报告的数据。
比较结果
在查看报告的数字之前,了解这两个网站的流量背景会有所帮助,因为广告拦截软件的受欢迎程度因人群而异。
网站#1
要分析的第一个网站是一个基于 web 的 Reddit 客户端,它使用了媒体接口。根据谷歌分析,该网站大约 95%的流量来自有机搜索。这可能是因为用户想要浏览 Reddit,但更喜欢不同的界面。
图片作者。第一个网站 Reddium 的每周页面浏览量和用户数据
从页面浏览量、用户和跳出率来看,我们发现这两种服务之间存在差异。Umami 的每周用户数增加了 19%,每周页面浏览量增加了 23%。这是一个明显的差异,不能仅仅归因于不同的方法,导致开发人员对他们看到的分析体验到不同的流量负载。
为了证实这种差异,我们可以尝试比较两种服务的人口统计数据。由于桌面广告拦截器的流行和 Firefox 上增强的跟踪保护,我们可以预期在 Google Analytics 上看到更少的桌面和 Firefox 用户。
图片作者。第一网站的用户设备数据
从设备数据来看,很明显,桌面用户是我们的谷歌分析数据中缺失的用户。数字也显示了这一趋势,移动用户的数量在这两种服务中保持不变,而桌面用户的数量则高出 40%。
图片作者。第一个网站的 Umami(左)和 Google Analytics(右)用户浏览器数据
在浏览器数据中,我们可以看到,在谷歌分析和 Umami 之间,Firefox 用户几乎增加了两倍,而其他浏览器略有增加。这证实了这两种服务之间的数量差异可能归因于广告拦截器。
网站#2
第二个网站是一个与你的 Spotify 账户相关的音乐测验。根据 Google Analytics,流量获取在直接、推荐、有机搜索和社交之间平分秋色,每个来源各占 20-25%
图片作者。第一个网站:Whisperify 的每周页面浏览量和用户数据
用户和页面浏览量数据显示了与第一网站相同的趋势,Umami 记录的页面浏览量和用户数多了约 30%。页面浏览量的差异遵循类似的模式,我们可以看到设备和浏览器数据进一步证实了这一点。
图片作者。Umami(左)和 Google Analytics(右)的用户设备和浏览器数据
观察
我们的比较表明,谷歌分析丢失了 15%到 25%的有价值的用户数据。随着越来越多的人熟悉跟踪保护,这一比例在未来可能会增加,但在收集用户数据时,这是一个需要记住的好数字。
当然,这只是一小部分有特定目标受众的网站。这两个网站都与社交应用相关,如 Reddit,其目标人群可能会使用广告拦截器,因此针对普通公众的网站的缺失数据可能比我们观察到的要少。
针对不同平台的网站也会影响谷歌分析中丢失的数据量。如果你的目标人群是移动用户,那么与针对使用 Firefox 的桌面用户的网站相比,你可能只丢失了少量的数据。
摘要
在这篇文章中,我们:
- 找到了谷歌分析的自主替代方案
- 比较两个网站的两个分析服务之间的分析数据
- 已确定的用户群更有可能从 Google Analytics 中消失(桌面和 Firefox 用户)
- 查看了观察中的潜在偏差,以及谷歌分析可能拥有更完整数据的情况
结果提供了相当多的信息。在大多数情况下,谷歌分析应该能够报告大约 80%用户的趋势。但是,在某些情况下,可能会收集更多或更少的数据。随着广告拦截器越来越受欢迎,像 Umami 这样的自托管替代产品可能是一条出路,因为它可以收集所有可用的数据,并让您更好地控制自己的数据。
资源
奥运会要花多少钱?
迄今为止最昂贵的奥运会是 2014 年索契奥运会。东京 2020 将改变这一点
亚历山大·布齐尔和丹尼尔·伦恩
下表 1 显示了 1960-2016 年奥运会的实际体育相关费用,以及每届奥运会的赛事数量和运动员人数。在 1960 年至 2016 年的 30 届奥运会中,有 25 届获得了产出成本数据。应当提及的是,在编制表格时,2016 年里约夏季奥运会尚未举行。因此,这些比赛使用了初步数据。*
来源:作者,https://bit.ly/2ZBaQSI
迄今为止最昂贵的夏季奥运会是 2012 年伦敦奥运会,耗资 150 亿美元。最昂贵的冬季奥运会,2014 年索契冬奥会耗资 219 亿美元
迄今为止最昂贵的夏季奥运会是 2012 年伦敦奥运会,耗资 150 亿美元,1992 年巴塞罗那奥运会耗资 97 亿美元。对于冬奥会来说,索契 2014 年冬奥会耗资最大,为 219 亿美元;2006 年都灵冬奥会耗资 44 亿美元,位居第二。成本最低的夏季奥运会是 1964 年东京奥运会,耗资 2.82 亿美元;最便宜的冬季奥运会,1964 年因斯布鲁克冬奥会,2200 万美元。必须提及的是,这些数字中不包括城市和交通基础设施的更广泛的资本成本,而这些成本通常是巨大的。
1960 年至 2016 年夏季奥运会的平均成本为 60 亿美元。同期冬奥会的平均成本为 31 亿美元。冬奥会平均成本和中值成本之间的巨大差异主要是由索契 2014 年冬奥会 219 亿美元的异常值造成的。事实上,即使与夏季奥运会相比,2014 年索契冬季奥运会也是有史以来最昂贵的奥运会。这是非同寻常的,因为冬季奥运会的成本通常比夏季奥运会低得多,冬季奥运会的平均成本不到夏季奥运会平均成本的一半。
冬季奥运会的成本通常比夏季奥运会低得多,冬季奥运会的平均成本不到夏季奥运会平均成本的一半
图 1 显示了 1960 年至 2016 年成本的发展情况。趋势线表明,游戏的成本随着时间的推移而增加。然而,这种明显的增加在统计上并不显著。因此,从统计角度来看,我们可以说成本不会随着时间的推移而增加或减少,这可能会随着东京 2020 年奥运会成为有史以来最昂贵的奥运会而改变…
图 1:1960 年至 2016 年的奥运成本时间序列
来源:作者,【https://bit.ly/2ZBaQSI
表 2 显示了 1960 年至 2016 年的每项赛事成本和每位运动员的成本(以 2015 年美元计)。这些数据适用于 1960 年至 2016 年的 30 场比赛中的 25 场。夏季奥运会每项赛事的平均成本为 2240 万美元(中位数为 1970 万美元)。冬季奥运会为 3920 万美元(中位数为 2950 万美元)。—2012 年伦敦奥运会的每项赛事费用最高,为 4950 万美元,其次是巴塞罗那,为 3770 万美元。对于冬季奥运会,索契的每项费用最高,为 2.234 亿美元,其次是 2006 年都灵冬奥会,为 5200 万美元。我们再次看到 2014 年索契冬奥会是一个异数。最低的单项成本是 1964 年东京夏季奥运会的 170 万美元和 1964 年因斯布鲁克冬季奥运会的 60 万美元。
来源:作者,【https://bit.ly/2ZBaQSI】T4
就每位运动员的成本而言,我们发现冬季奥运会的成本大约是夏季奥运会的两倍。夏季奥运会每位运动员的平均费用为 70 万美元(中位数为 60 万美元),冬季奥运会为 130 万美元(中位数为 100 万美元)。然而,这种差异在统计学上并不显著。夏季奥运会每位运动员的最高花费是 2012 年伦敦奥运会的 140 万美元,其次是 1980 年莫斯科奥运会的 120 万美元。冬奥会每位运动员的最高费用是索契 2014 年冬奥会的 790 万美元和都灵 2006 年冬奥会的 170 万美元。1964 年东京夏季奥运会的运动员人均费用最低,为 55,000 美元,1964 年因斯布鲁克冬季奥运会为 20,000 美元。
夏季奥运会运动员人均花费最高的是 2012 年伦敦奥运会,为 140 万美元。冬奥会是 2014 年索契冬奥会,每位运动员 790 万美元
图 2 显示了每个运动员的花费与时间的关系。我们看到了一个趋势的转变,从夏季运动员的人均成本通常高于冬季奥运会,直到 20 世纪 80 年代中期,冬季奥运会在人均成本方面变得比夏季奥运会更昂贵。我们还看到,从 20 世纪 80 年代中期到 21 世纪初,夏季奥运会每位运动员的成本普遍下降,此后,夏季和冬季奥运会每位运动员的成本一直在上升,主要受 2012 年伦敦奥运会和 2014 年索契奥运会的推动。然而,总的来说,无论是夏季奥运会、冬季奥运会还是所有的奥运会,随着时间的变化在统计上都是不显著的。
图 2:1960 年至 2016 年奥运会运动员人均体育相关成本的时间序列,包括和不包括索契 2014 年奥运会
来源:作者,https://bit.ly/2ZBaQSI
— — — —
*)有关完整的故事,包括参考资料和注释,请参见 Flyvbjerg、Bent、Alexander Budzier 和 Daniel Lunn,2021 年,“回归尾部:为什么奥运会吹了”,环境与规划 A:经济与空间,第 53 卷,第 2 期,第 233-260 页。免费 pdf 在这里:【https://bit.ly/2ZBaQSI
你在咖啡上真正花了多少钱?
这是我的故事,关于使用数据分析和可视化来证明我丈夫是错的
自从我们结婚以来,我丈夫和我就一直在为他在菲尔茨咖啡的开销争论不休。不要误解我,菲尔茨咖啡非常棒,但我们正在进行的辩论需要解决。为了解决这场争论,我求助于数据。
作者图片
首先,我必须通过菲尔兹咖啡应用获取我丈夫的菲尔兹咖啡应用使用数据(当然要经过他的允许!).根据《加州消费者隐私法》,加州人可以在使用移动应用程序时要求收集数据。请求数据后,大约需要 30 天才能返回带有数据集的请求。返回的数据集包含 2018 年 5 月至 2021 年 10 月的用户数据。
然后,我将数据集加载到 R-studio 中,看看当用户通过应用程序点咖啡时,应用程序会收集什么样的信息。通过应用程序收集的信息类型包括商店位置、订单时间/日期、提货时间/日期和总交易金额。数据集还包括两个单独的税和小费列,但这些列返回 0,并且税和小费值已经包含在总交易金额中。
原始数据集格式和列标题
我还想使用订单时间/日期和提货时间/日期列,按商店位置分析我丈夫等待咖啡的平均时间。然而,这被证明是困难的,因为该应用程序允许将提货时间设置为未来更晚的时间。例如,可以在上午 8:00 下订单,在上午 10:00 提货。这将显示为订单时间和提货时间之间的两小时“等待时间”,并不一定反映订单的准确“等待时间”。因此,我决定从这个分析中排除这些列。
我首先通过安装几个包来执行数据清理,包括’ tidyr ‘,’ dyplr ‘和’ tidyverse '。
### INSTALL PACKAGES AND LOAD LIBRARIES
install.packages("readr")
library(readr)
install.packages("tidyverse")
library(tidyverse)
install.packages("dplyr")
library(dplyr)
install.packages("tidyr")
library(tidyr)
我删除了与分析计划无关或为空的行,重命名了列标题以更好地描述列中的内容,并删除了任何包含缺失值的行。我还将包含数值的字符列重新格式化为数字列。
# Drop row 1 through 6 and 116
df <- (df %>% slice(-c(0:6,121)))# Rename column headers
colnames(df) <- (c("Store", "OrderCreationDate", "ReservedPickUpTime","Status","Subtotal", "Tip", "Taxes"))# Drop first row with column names and relabel column headers with column names
df <- (df %>% slice(-c(1))) # Remove rows with missing values
df <- na.omit(df) # Change variable from character to numeric
df$Subtotal <- as.numeric(df$Subtotal)
出于这个项目的目的,我非常依赖于商店位置列、总支出列和订单日期列。在原始数据集中,日期和时间信息存储在一个单元格中。我将这些数据分成两个单独的列,一列是日期,另一列是时间戳。我这样做是因为出于前面提到的原因,我不会依赖时间信息来进行分析。
# Split date and time into two columns
df$OrderCreationDate <- data.frame(do.call("rbind", strsplit(as.character(df$OrderCreationDate),' ', 2)))
我还创建了一个新列,将每个商店位置与其各自的邮政编码关联起来。这个额外的列将有助于在地理上映射商店位置,以便在地图上可视化数据。
最后,我将清理后的数据集放入 Google Data Studio,创建一个仪表板来可视化数据。该控制面板具有向下钻取功能,允许用户按位置或日期对数据进行切片和切块。完整的交互式仪表盘可在这里找到。
点击此处通过 Google Data Studio 访问完整的交互式仪表盘。Dashboard 是实时的,可能不会反映这篇静态博客文章中的内容。
这个项目的一个关键发现是,从 2021 年 1 月 1 日到 2021 年 10 月 26 日,我丈夫在菲尔茨咖啡消费了 523.95 美元。数据证实,菲尔茨库比蒂诺大街是和菲尔茨一起放松的首选地点。
这开始于一场关于我丈夫的 Philz 支出和我证明他是错的动机的辩论。而是变成了一个有趣的数据分析和可视化项目。由于他将继续成为菲尔茨的常客,我希望收集足够的数据点来建立对他未来行为的预测模型。那段未完待续…
要查看我的原始数据集、Rstudio 代码和清理后的数据集,请查看我在 GitHub 上的 Philz Coffee 数据报告。
语言模型的参数中可以包含多少知识?—摘要
理解“存储”在语言模型中的隐性知识
TL;博士;医生
语言模型已经显示出从用于预训练的数据中隐含地记住信息的能力。Roberts 等人(2020)的这篇论文试图对其进行量化,并展示了隐性知识的规模如何随模型大小和训练时间而变化。
非常感谢 Sundeep Teki 的反馈,以及帮助我写这篇博客!
介绍
Patroni 等人(2019)最近的工作显示了语言模型如何从用于预训练的数据中构建内部知识库。在 Roberts 等人(2020)的论文中,作者试图通过“*闭卷问答”来理解这一现象。*与最近在问答(QA)领域的工作不同,作者没有向模型共享任何上下文或外部知识源来回答问题(因此得名——闭卷问答)。在本文中,作者着重于使模型查找它们的参数,以获得预训练时存储的信息。此外,作者还探索了这种行为在缩放模型大小(参数数量)或训练数据(这两者都已被证明可以提高下游任务的性能)时如何变化。
T5 模型和预训练/微调阶段。在这里,本文作者让 T5 从其知识中回答问题*!(* 来源 )
背景
**问题回答:**通常为模型提供外部信息源,以查找与问题相关的细节。这些问题可以是历史事实、可以从外部来源解释的信息等。这种问答被称为“开卷问答”。在这个过程中,期望模型输出文本的跨度(范围/坐标)或文本本身。
这个任务的一个更简单的版本是,代替一个完整的“外部知识源”,模型也提供有一个特定的上下文输入。这里,模型可以学习从输入的上下文中“查找”答案,而不是在庞大的外部语料库中搜索。这个版本的问答被称为阅读理解。
在这篇论文中,作者针对一组他们称为*闭卷问答的更具挑战性的问题。*在这里,模型应该学会在自身内部寻找答案的记忆内容,而不是作为上下文或大型外部语料库的甲骨文文本。
**迁移学习:**大规模语言模型在大型无标签数据语料库的预训练帮助下,表现有所提高。这种预训练步骤被认为是以无人监管的方式为模型提供语言信息或某些“世界知识”。最近流行的迁移学习模型是从 Transformers (Vaswani 等人,2017 年)衍生而来的,一种特殊的仅编码器的 Transformers(类似于 BERT (Devlin 等人,2018 年))在问答系统中很受欢迎。这是由于这样一个事实,即通常使用上下文输入或外部知识库来尝试问题回答,其中编码器模型被期望预测将具有答案的单个标记。
虽然,这对于闭卷问答来说是不可能的,因此作者使用了一个称为 T5(文本到文本转换转换器)的框架,该框架将每个问题建模为文本到文本的问题(Raffel 等人,2019)。也就是说,模型不是提取信息,而是生成信息。
实验
**数据集:**该研究着眼于 3 个数据集,即——自然问题(科维亚特科夫斯基等,2019);网络提问(Berant 等人,2013 年);TriviaQA (Joshi 等人,2017 年)。论文只利用了数据集中的问题,而*忽略了附带的匹配文档。*此外,TriviaQA(拥有私有测试集)的所有结果都是通过提交给排行榜获得的。
**训练:**作者利用 T5 模型(Raffel et al .,2019);T5 没有在问答数据集上进行预训练。此外,性能是作为模型大小的一个因素来衡量的——基础模型、大型模型、3B 模型和 11B 模型。此外,还基于 T5.1.1 检查点报告了结果,这些检查点仅根据未标记的数据进行了预训练。验证是在数据集的预留 10%上完成的,其中使用了从 90%的训练中获得的最佳性能检查点。通过在每个时间步选择最可能的标记来选择模型的预测。
**显著跨度掩蔽(SSM)😗*Guu 等人(2020)提出的掩蔽较长短语(包括命名实体、日期等)的方法已证明可在基于 BERT 的模型中实现更好的性能。在本文中,作者以类似的方式用 100k 个额外步骤微调 T5 模型。
**结果:**这项研究的主要收获是
- 随着型号尺寸从基本型号增加到 11B 型号,性能也随之提高。
- SSM 战略大大提升了业绩。
- 内存和计算成本显著降低,因为与查找大型知识语料库的典型开放领域问答模型不同,本文描述的模型只查看自身“内部”。
- 该模型也击败了多答案任务中的最佳基线,尽管与 SOTA 模型相比,在召回率上落后。
**人工评估:**由于模型使用自由形式的答案生成,评估中有多个假阴性。这是因为,如果在基本事实和输出之间没有精确的匹配,尽管它们在语义上是相同的,这将被认为是错误的输出预测。作者查看了 150 个随机抽样的例子进行评估,他们可以注意到 20 个被错误分类为错误,20 个被标注为错误,17 个无法回答。忽略评估中无法回答的问题,该模型给出了 57.8 分。
通过微调 T5 在开放领域自然问题(NQ)、网络问题(WQ)和 TriviaQA (TQA)任务上获得分数。除了 Ling 等人(2020 年)和 Févry 等人(2020 年)之外,所有模型都使用昂贵的数据查找。此外,我们可以看到 T5 型号的性能随着规模的扩大而提高。(来源)
结论
在本文中,作者展示了在非结构化数据上预先训练的大型语言模型在“封闭领域”问答中可以获得显著的结果。这需要许多有趣的工作,以及制定资源约束(较小的模型)以模拟较大模型的性能,查看模型可解释性的“知识”,更重要的是,了解模型是否“学习”事实作为基于最大似然损失的预训练的结果。
你的 ML 代码消耗了多少内存?
了解如何通过一行命令快速检查机器学习功能/模块的内存占用。生成一个好的报告。
图片来源: Pixabay
为什么要分析内存使用情况?
假设你已经编写了一个很酷的机器学习(ML)应用程序,或者创建了一个闪亮的神经网络模型。现在,您希望在某个 web 服务或 REST API 上部署这个模型。
或者,您可能已经基于来自制造工厂的工业传感器的数据流开发了该模型,现在您必须将该模型部署在一台工业控制电脑上,以便根据持续输入的数据做出决策。
“很高兴开发出闪亮的 ML 模型”。图片来源: Pixabay
作为一名数据科学家,你可能期望工程/平台团队提出的一个极其常见的问题是“ ”你的模型/代码有多少内存占用? 或 在给定的数据负载下运行时,您的代码的内存使用峰值是多少?
这是很自然的,因为硬件资源可能是有限的并且一个单独的 ML 模块不应该占用系统的所有内存。对于边缘计算场景来说,这一点尤其正确,即 ML 应用可能在边缘上运行,例如在工业 PC 上的虚拟化容器内。
此外,您的型号可能是运行在该硬件上的数百种型号中的一种,您必须对内存使用峰值有所了解,因为如果大量型号同时出现内存使用峰值,可能会导致系统崩溃。
这让你很好奇,不是吗?
图片来源: Pixabay
…硬件资源可能是有限的,单个 ML 模块不应该占用系统的所有内存。对于边缘计算场景来说,尤其如此……
不要犯这个根本性的错误
注意,我们讨论的是整个代码的运行时内存配置文件(一个动态量)。这与您的 ML 模型的大小或压缩无关(您可能已经将它作为特殊对象保存在磁盘上,例如 Scikit-learn Joblib dump ,一个简单的 Python Pickle dump,一个 TensorFlow HFD5 ,等等)。
Scalene:一个小巧的内存/CPU/GPU 分析器
这里有一篇文章介绍了一些与 Python 一起使用的旧内存分析器。
在本文中,我们将讨论Scalene——您可以一站式回答工程团队提出的这些问题。
根据其 GitHub 页面 , " Scalene 是一个用于 Python 的高性能 CPU、GPU 和内存分析器,它可以做许多其他 Python 分析器不能做的事情。它的运行速度比其他分析器快几个数量级,同时提供更详细的信息。”
它是由马萨诸塞大学开发的。查看此视频,了解全面的介绍。
安装
毕竟是 Python 包。所以,通常安装,
**pip install scalene**
目前,仅适用于 Linux 操作系统。我没有在 Windows 10 上测试它。
在 CLI 或 Jupyter 笔记本中使用
不等边三角形的使用非常直接,
**scalene <yourapp.py>**
或者,您可以在 Jupyter 笔记本中使用这个神奇的命令,
**%load_ext scalene**
示例输出
下面是一个输出示例。我们将很快对此进行更深入的研究。
特征
以下是 Scalene 的一些很酷的特性。大多数都是不言自明的,可以从上面的截图中判断出来,
- 行或函数:报告整个函数和每个独立代码行的信息
- 线程:支持 Python 线程。
- 多重处理:支持使用
multiprocessing
库 - Python 与 C 的时间对比 : Scalene 显示了 Python 与本机代码(如库)的时间对比
- 系统时间:区分系统时间(如睡眠或执行 I/O 操作)
- GPU :它还可以报告花费在 NVIDIA GPU 上的时间(如果有的话)
- 复制量:报告每秒复制的数据量
- 检测泄漏 : Scalene 可以自动查明可能导致内存泄漏的线路!
一个具体的机器学习代码示例
让我们言归正传,将 Scalene 用于内存分析标准机器学习代码。我们将研究两种不同类型的 ML 模型——原因将很快阐明。我们将对所有三个模型使用 Scikit-learn 库,并利用其合成数据生成功能来创建我们的数据集。
- 多元线性回归模型
- 具有相同数据集的深度神经网络模型
所有三个模型的建模代码都遵循完全相同的结构。下图中还显示了外部 I/O 操作,因为我们将看到,根据型号的类型,它们可能会也可能不会主导内存配置文件。
图片来源:作者出品(拥有版权)
线性回归模型
代码文件在我的 GitHub repo 中的。
我们使用标准导入和两个变量NUM_FEATURES
和NUM_SMPLES
来做一些实验。
我们没有展示数据生成和模型拟合代码。它们相当标准,可以在这里看到。我们将拟合的模型保存为一个 pickled dump,并加载它和一个用于推理的测试 CSV 文件。
为了清晰起见,我们在一个main
循环下运行所有东西,执行和报告都是不规则的(你很快就会明白)。
当我们运行该命令时,
$ scalene linearmodel.py --html >> linearmodel-scalene.html
我们得到这些结果作为输出。注意,这里我使用了 **--html**
标志,并将输出传输到一个 HTML 文件中,以便于报告。
那么,这个结果有什么惊人之处呢?
内存占用几乎完全由外部 I/O(如 Pandas 和 Scikit-learn estimator 加载)控制,少量内存用于将测试数据写入磁盘上的 CSV 文件。
实际的 ML 建模、Numpy 或 Pandas 操作以及推理根本不会影响内存!
当模型和数据缩放时会发生什么?
我们可以调整数据集大小(行数)和模型复杂性(要素数),并运行相同的内存分析来记录各种操作在内存消耗方面的表现。结果如下所示。
这里的 X 轴表示一对的特征数量/数据点数量。请注意,此图描绘的是百分比而非绝对值,以展示各种类型操作的相对重要性。
图片来源:作者出品(拥有版权)
所以,对于线性回归模型…
从这些实验中,我们得出结论,Scikit-learn 线性回归估计器非常有效,并且不会为实际的模型拟合或推断消耗太多内存。
然而,就代码而言,它确实有一个固定的内存足迹,并且在加载时会消耗那么多内存。然而,随着数据大小和模型复杂性的增加,代码占用的百分比总体上是下降的。
因此,如果您正在使用这样一个小型线性模型,那么您可能想要关注数据文件 I/O 来优化您的代码以获得更好的内存性能。
深度神经网络会发生什么?
如果我们用一个 2 隐藏层的神经网络(每个隐藏层有 50 个神经元)运行类似的实验,那么结果看起来如下。代码文件在这里。
图片来源:作者出品(拥有版权)
显然,神经网络模型在训练/拟合步骤消耗大量内存,不像线性回归模型。但是,对于少量要素和大数据量,拟合占用的内存量很少。
您还可以试验各种架构和超参数,并记录内存使用情况,以获得适合您的情况的设置。
遵循实验方法
如果您使用相同的代码文件重复实验,结果将会根据您的硬件、磁盘/ CPU/ GPU/内存类型而有很大差异。本文的目的不是关注实际值,甚至不是关注趋势。我想让你拿走为你自己的代码做内存分析实验的方法。
一些重要的建议
- 最好在你的代码中编写专注于一个单一任务的小函数
- 保留一些自由变量,比如特性的数量和数据点的数量,这样当数据/模型扩展时,您可以运行相同的代码文件进行最小的修改来检查内存配置文件
- 如果你正在比较一个 ML 算法和另一个,试着保持结构和整个代码的流程尽可能的一致以减少混乱。更好的是,只需更改估计器类并比较内存配置文件。
- 根据您的建模场景,数据和模型 I/O (导入语句,模型在磁盘上的持久性)在内存占用方面可能令人惊讶地占主导地位。做优化的时候千万不要忽略它们。
- 出于上述同样的原因,考虑比较来自多个实现/包的 same 算法的内存配置文件(例如 Keras vs. PyTorch vs. Scikit-learn)。如果内存优化是您的主要目标,那么您可能需要寻找一种内存占用最少但能够令人满意地完成工作的实现,即使它在功能或性能方面不是绝对最好的。
- 如果数据 I/O 成为瓶颈,探索更快的选项或其他存储类型,例如用拼花文件和 Apache Arrow 存储替换 Pandas CSV。查看这篇文章,
使用 Scalene 可以做的其他事情
在本文中,我们刚刚讨论了最低限度的内存分析,重点是规范的 ML 建模代码。您可以利用 Scalene CLI 的其他选项,
- 仅分析 CPU 时间,不分析内存
- 仅使用非零内存占用量减少分析
- 指定 CPU 和内存分配最小阈值
- 设置 CPU 采样率
- 多线程并检查差异
最终验证有时是必要的
对于资源不足的情况,托管一个验证环境/服务器将是一个好主意,它将接受给定的建模代码(当开发时)并通过这样的内存分析器运行它以创建运行时统计信息。如果它通过了预先确定的内存占用标准,那么只有建模代码才会被接受用于进一步的部署。
图片来源:作者出品(拥有版权)
如果内存优化是您的主要目标,那么您可能需要寻找一种具有最小内存占用量但又能令人满意地完成工作的实现。
摘要
在本文中,我们讨论了对 ML 代码进行内存分析的重要性,以便与将代码部署到服务/机器上的平台/工程团队进行顺畅、轻松的交互。剖析内存还可以向您展示基于您正在处理的特定数据和算法优化代码的惊人方法。
我们展示了一个典型的 ML 建模代码示例,它是用一个强大而轻量级的 Python 库 Scalene 进行剖析的。我们用线性回归和神经网络模型展示了一些有代表性的结果,并提供了一些一般性的建议。
希望您在使用这些工具和技术将您的 ML 代码实现和部署到产品中时获得更多的成功。
L 喜欢这篇文章?成为 中等成员 继续 无限制学习 。如果你使用下面的链接,我会收到你的一部分会员费, 而不需要你额外付费 。
https://medium.com/@tirthajyoti/membership
用 R 的简化处理缺失值
我们数据集中的漏洞可以通过在线性模型中进行智能推理来解决
休伊·费恩·泰
和格雷格·佩奇一起
上图:一个游乐园; 图片来自 Pixabay 吉姆·威灵顿
推断是在证据和推理的基础上得出结论。
在文学中,这是通过上下文线索来完成的。像“…你有一张二月的脸,充满了霜、风暴和多云…”这样的比喻告诉我们,一个人是阴郁的,因为二月在北半球仍然是一年中寒冷的时候。
同样,在数据科学中,智能猜测可以基于我们的领域知识、线性建模或仅仅是常识来做出。
为了说明这一点,我将使用缅因州一个名为龙虾王国的虚构游乐园作为例子。
假设您在 Lobster Land 担任常驻数据分析师。一天,老板发现电子表格中缺少一些条目,要求你“解决问题”。如果手头只有一个数据转储,并且不知道上下文,您会从哪里开始呢?
第一步:确定数据缺失问题的严重程度。
我们首先在 r 中安装 visdat() 包。对原始数据应用 vis_miss() 函数使您能够可视化数据集中的漏洞。
下图显示了两类洞:降水和黄金地带。降水变量表示特定一天的降雨量,单位为英寸。以美元计算的 GoldZoneRev 变量表示龙虾王国的室内博彩区产生的收入,人们在这里赢得可以用来兑换礼物的黄金券。
幸运的是, GoldZoneRev 中的缺口只影响了该变量数据的 5.66%。此外,下面的图表告诉我们,*“降水”*列中有 3.77%的数据丢失。
第二步:确定哪些因素影响黄金区域的收入
正如我在以前的文章中所写的,最后一次观察结转 (LOCF)是我们可以用来处理缺失值的一种方法。在先前的观察可能提供关于缺失值的重要线索的情况下(如在一个气候季节性变化的地方的每日天气数据),它可以很好地工作。然而,在这种情况下,LOCF 并不适合应对眼前的挑战,因为游乐园景点的收入会受到多种因素的影响。一周中的某一天可能很重要,就像某一天公园游客的总量一样。我们没有理由假设我们可以通过简单地使用前一天的总数来对这个变量进行合理的估算。
相关矩阵将告诉我们数据集中的其他变量之间是否存在关系,以及这些关系的强度。
为了创建矩阵,我们使用了 cor() 函数。同时,我们告诉 R 只使用归类为“数值”的数据,而忽略缺失的值。这些是防止命令失败的必要说明。最后,我们将结果四舍五入到两位小数。
在下面显示的矩阵中,圆圈的大小对应于相关性的强度。较暗的蓝色表示正相关,而较暗的红色表示负相关。在这种情况下,售出的一日通票数量、小吃店的收入以及龙虾馆员工的工作时间是影响黄金区一天收入的三个最重要的因素。
第三步:根据黄金区与一个或多个变量的关系,估算黄金区当天的收入
为了简单起见,在这个例子中,我们将尝试基于一个因素来估计黄金区域在那些丢失的日子中的收入——售出的日通票的数量。
相关矩阵告诉我们,在龙虾之乡卖出的一日游越多,我们在黄金区赚的钱就越多。换句话说,这两个因素之间有一种强烈的、积极的、线性的关系(见下图)。
因为我们缺少的 GoldZoneRev 的值在我们现有数据的范围内,所以我们可以通过查看当天卖出了多少张一日通票来推断当天的收入。为此,我们使用 R 的 simputation 包中的 impute_lm() 函数。
为了根据售出的一日通票数量对一天的收入进行智能猜测,我们可以运行以下代码:
在上面的代码中,我们首先告诉 R 在“rawdata”数据集中查找。然后我们添加一个名为 is_missing 的列来跟踪最初为空的单元格。接下来,我们调用 impute_lm() 函数。在该函数中,我们将 GoldZoneRev 表示为 DayPass 的函数。
第四步:验证结果
第 13 天是黄金区每日总收入缺失的第一个实例。
我们的线性模型告诉我们,当卖出 4151 张一日通票时,当天的收入是 30914 美元。这一估计是合理的,因为它仅略低于我们在第 7 天的收入,当时售出了 4412 张一日通票,黄金区产生了 33163 美元。
所以留给我们两个问题。我们可以根据多个因素预测黄金地带收入的减少吗?是的,但这违反了简约原则——因为 DayPass 和 GoldZoneRev 之间的线性关系非常强,没有必要通过添加其他输入变量来引入额外的复杂性。
最后,我们是否可以使用类似的线性模型来预测’*降水’*列中的缺失值?答案是否定的。Rain 不依赖于一周中的某一天、售出的龙虾卷的数量或我们数据集中存在的任何其他变量,因此没有任何合适的方法使用 impute_lm() 来填充我们数据集中的这些漏洞。
NumPy 为您节省了多少时间?
洞察 NumPy 函数的速度优势
NumPy 是一个非常著名的用 python 进行数学计算的库。它尤其适用于数据科学和机器学习领域。
NumPy 给了你很多数学函数和算法。这为您节省了大量的开发时间,因为您不必自己实现它们,但是使用这个库是否也节省了计算时间呢?这篇文章包括一些小的算法实验,可以帮助我们回答这个问题。
让我们开始吧!
NumPy 数组与列表
让我们从研究 NumPy 数组开始,并将它们与普通 python 列表进行比较。
列表和 NumPy 数组都可以用来表示向量。
import numpy as np
list_a = [1, 2, 3, 4]
array_a = np.array([1, 2, 3, 4])
然而,这两种不同的数据结构具有非常不同的行为。例如,当对它们应用函数时。
list_a + list_a
>> [1, 2, 3, 4, 1, 2, 3, 4]array_a + array_a
>> array([2, 4, 6, 8])
两个普通列表加在一起会产生一个新列表,它是两个列表的串联。而将两个数组相加在一起会应用加法元素。
这在下面的例子中也很明显:
list_a + 5
>> TypeError: can only concatenate list (not "int") to listarray_a + 5
>> array([6, 7, 8, 9])
其中,试图向列表中添加 5 会引发一个TypeError
,因为它试图将一个整数连接到列表中。另一方面,当向数组中添加 5 时,它适用于每个元素,从而返回一个新数组,其中前一个数组的所有元素都增加了 5。
这些是列表和 NumPy 数组之间的一些基本区别,当决定在您的用例中使用什么时,了解这些区别很重要。
速度比较
点积计算
接下来,让我们更深入地了解在阵列上使用 NumPy 函数而不是使用手动实现的函数时可以获得的速度优势。
使用 NumPy 的randn
函数,我们可以用 100 个随机数快速填充一个数组。
使用datetime.now()
,我们可以在运行手动实现的函数 100,000 次之前和之后获得当前时间。
在使用 NumPy 的dot()
函数时,我们使用相同的方法。
最后,我们将两个时间之间的差异打印为一个比率,我们可以看到手动实现的函数比 NumPy 慢 65 倍。
我已经运行了这个代码片段几次,结果在 55 和 65 之间略有不同。如果你喜欢,我鼓励你自己尝试一下。
矩阵乘法 再来看看另一个速度对比。这次我们将分析矩阵乘法。
在下面的代码片段中,您会发现我实现了一个矩阵乘法算法,就像前面的例子一样,它将与 NumPy 中内置的dot
函数进行比较。
代码遍历
单元格 1: 导入必要的库。
单元格 2: 创建 3 个不同的矩阵。a 是一个 3x2,B 是一个 2x3,C 是一个 5x2 的矩阵。
单元格 3: 定义矩阵乘法函数。
单元格 4: 检查手动实现的函数是否返回与 NumPy 相同的结果。
单元格 5: 对一个 2×3 矩阵与一个 3×2 矩阵点 100,000 次时的函数进行计时,求它们之间的比值。
单元格 6: 用一个 2×3 矩阵点一个 5×2 矩阵 100,000 次时的函数计时,求它们之间的比值。
结果
用A
点缀的C
使用 NumPy 函数大约快 49 倍。这个观察还表明,当矩阵的大小增加时,使用 NumPy 节省的时间也增加了一个很大的系数。
正如这些结果所揭示的,使用 NumPy 有相当大的时间优势。你可能正在使用它。如果你和我一样是一个好奇的人,那么你可能很享受这个小实验,并且了解到你最喜欢的 python 数学库甚至比你想象的还要好。
功劳归于懒惰的程序员,因为正是通过他的材料,我意识到了这一点。
感谢阅读!
音乐如何让我成为更好的数据科学家
办公时间
我的音乐和数据科学之旅告诉我,个人成长源于对更大图景的更好理解。
我仍然记得 11 年前在德克萨斯州一个炎热的夏天,我挑选了我的第一把电吉他。这是一个不起眼的乳白色挡泥板压扁器,有轻微生锈的字符串,但我迫不及待地把它带回家。当我这么做的时候,我向成为一个粉碎领主迈出了第一步。我学会了我的音阶,调高了失真,并训练我的手指越来越快地移动。我被 70-80 年代摇滚令人敬畏的吉他独奏深深吸引,以至于我不太想学其他东西。节奏、和弦或音调的空间很小;我只想玩得又快又炫。
一两年后,我可以结结巴巴地演奏出相当数量的著名吉他独奏,所以我觉得自己已经准备好加入乐队了。我开始和我高中的一些朋友一起即兴演奏,我们尝试创作原创音乐。我认为这是一个机会来写吉他部分,尽可能展示我的吉他技巧。在一次灾难性的即兴演奏中,我的朋友们开始演奏一段即兴重复片段,让人想起 21 世纪初绿日(Green Day)或眨眼 182(Blink 182)等乐队的摇滚,他们让我加入一段主吉他部分。回想起来,这首曲子需要一首简单、充满活力、旋律优美的吉他独奏。相反,我漫无目的地放大缩小五声音阶。音乐一停,我的朋友温和地告诉我,虽然我的独奏令人印象深刻,但与乐队演奏的内容“不相符”。这个反馈无疑让我措手不及——在我看来,令人印象深刻的吉他部分就是好的吉他部分。
在那次事件之后的几年里,我开始向更有经验的吉他手和老师学习。这些导师一次又一次地强调“为歌曲服务”的重要性这意味着音乐家的主要精力应该放在创作与听众产生共鸣的音乐上,而乐器只是辅助这一努力的工具。有时演奏这首歌需要精湛的独奏,有时需要演奏一些简单的曲子,有时则完全不需要演奏。这种范式的转变从根本上改变了我的惯例。最近几年,我更加注重培养自己的时间感、音高感以及和声感——所有这些都让我更加意识到自己的角色在大局中的位置。服务歌曲也鼓励合作,因为音乐家必须协调编写有效互动的部分。
那么这和数据科学有什么关系呢?嗯,我在数据科学方面的旅程在很多方面反映了我在音乐方面的旅程。当我开始学习数据科学时,我迷恋上了复杂的机器学习算法,并将它们视为一名成功的数据科学家的核心能力。现在我有了更多的经验,我比以前更加重视其他技能——比如编写产品质量的代码、商业意识和沟通。换句话说,我知道了作为一名数据科学家为歌曲服务的价值。在专业数据科学项目中,“歌曲”通常是一个产品或一个决策,数据科学家必须学会根据他们对这些努力的贡献来量化他们的成功。这种心态极大地提高了数据科学家的就业能力。作为一名招聘人员,我更希望看到一份简历上写着“建立了一个降低 10%维护成本的模型”,而不是“建立了一个准确率达 95%的模型”。
明确一点,很多快速吉他独奏是为歌曲服务的,很多前沿的机器学习模型是为产品改进的。最重要的是,要理解什么能提供价值,什么不能。我欣赏的吉他手会在适当的时候演奏精湛的独奏,但当歌曲需要时,他们会随意弹奏和弦。当我面试数据科学申请者时,我通常会问一个开放式的问题,关于为基本的二元分类问题选择初始模型。我发现,建议从简单的逻辑回归模型开始的候选人能够详细解释更复杂的模型是如何操作的。具有讽刺意味的是,一些建议从更复杂的模型开始的候选人无法清楚地解释这些模型是如何操作的。在音乐和数据科学中,技术上最熟练的从业者通常认识到,许多情况并没有从他们工具包中最先进的技术中受益。
回想起来,作为一名吉他手,我对快速演奏的过分强调来自于玩电子游戏《吉他英雄》。在这个游戏中,玩家每弹奏一个正确的音符就可以获得分数,因此有很多音符的快歌是获得高分的理想选择。虽然我仍然喜欢《吉他英雄》,并认为它让我对吉他产生了最初的热情,但它的激励让我忽略了与他人一起演奏实际乐器的重要方面。我想知道 Kaggle 竞赛对一些有抱负的数据科学家是否有类似的影响。这些竞赛当然推进了这个领域,并且对学习很有帮助,但是我担心它们会导致一些人过分强调构建性能模型,而不强调产生商业价值。
有时候,在模型的性能和它的价值之间实际上有一个折衷。这种权衡通常是由于时间限制。在一些项目中,我面临着这样的决定:是把时间花在制作更有性能的模型上,还是花在制作更有 T2 影响力的模型上。使模型更具性能包括诸如特征工程、评估不同模型和构建集合模型的任务。另一方面,使模型更有影响力包括在生产环境中部署它、配置它以发送自动通知以及改进它的文档等任务。性能和影响之间的权衡有时也会出现在模型选择中。线性回归等简单模型比深度神经网络或随机森林更容易向非技术风险承担者解释。利益相关者更有可能相信并最终根据他们理解的模型结果采取行动。因此,在某些情况下,为了实现价值最大化,牺牲一些性能是可取的。一个成熟的数据科学家的一个标志是能够从那些需要更严格方法的情况中辨别出这些情况。
最终,我的音乐和数据科学之旅告诉我,个人成长源于对个人贡献如何融入大局的更好理解。在这两种努力中,我曾经相信卓越仅仅包括掌握困难和复杂的技能。虽然这些技能很有用,但我现在认识到优秀是“为歌曲服务”的能力
成为数据科学家后,我的学习道路发生了怎样的变化
我一直在学习,但方式不同
我对数据科学的热情始于大约两年半前。我在做一份与数据科学无关的工作。转行对我来说是一个很大的挑战,因为我有很多东西要学。
经过两年的学习和奉献,我终于找到了第一份工作,成为一名数据科学家。当然,我的学习之旅并没有停止。作为一名数据科学家,我在工作期间学到了很多新东西。
学习部分不变。然而,我学习的内容和方式发生了巨大的变化。在这篇文章中,我将详细阐述这些变化。如果你正在努力成为一名数据科学家,你可能会有同样的经历。
需要强调的是,成为一名数据科学家需要不断学习。数据科学仍在发展,你需要时刻保持新鲜感。我认为数据科学还不是一个成熟的领域,所以新的技术和概念正在被频繁引入。
数据的大小
1000 万行对于现实生活中的问题来说并不算多。
对我来说,最显著的变化是数据的大小。当我独自学习时,我用最多有 10 万行的数据集进行练习。我现在认为它是一个小数据集。数据的大小取决于您正在处理的领域和问题。一般来说,1000 万行对于现实生活中的问题来说并不算多。
处理大型数据集有其自身的挑战。首先,我需要学习新的工具来处理这样的数据集。在我开始做数据科学家之前,熊猫对我来说已经足够了。但是,对于大规模数据,它不是一个高效的工具。
允许分布式计算的工具更受欢迎。Spark 是最受欢迎的一款。它是一个用于大规模数据处理的分析引擎。Spark 允许您将数据和计算分布在集群上,以实现显著的性能提升。
幸运的是,可以在 Python 代码中使用 Spark。PySpark 是 Spark 的 Python API。它结合了 Python 的简单性和 Spark 的高效性。
云计算
另一个重大变化是从本地环境转向云环境。当我在学习的时候,我在我的电脑里做所有的事情(即在本地工作)。这足够练习和学习了。
然而,一家公司在当地经营的可能性极小。大多数公司都在云中工作。数据存储在云中,计算在云中完成,等等。
为了高效地完成工作,全面了解云工具和服务非常重要。有各种各样的云提供商,但主要是 AWS、Azure 和谷歌云平台。我必须学会如何使用他们的服务和管理存储在云中的数据。
饭桶
作为数据科学家,我经常使用的另一个工具是 git 。我在学习的时候学习了基本的 git 命令。但是,在生产环境中工作时就不同了。Git 是一个版本控制系统。它维护对代码所做的所有更改的历史记录。
Git 允许协同工作。你可能会作为一个团队参与项目。因此,即使你在一家小公司工作,git 也是一项必备技能。项目是用 git 开发和维护的。
Git 比外表看起来要复杂一些。然而,在做了几个项目之后,你就习惯了。
不仅仅是工具!
在我的学习旅程中,工具不是唯一改变的东西。我处理数据的方式也发生了变化。当您处理一个现成的数据集时,在清理和处理数据方面您能做的不多。例如,在机器学习任务的情况下,您可以在几个简单的步骤后应用模型。
在你的工作中情况会有所不同。项目的很大一部分花费在准备数据上。我的意思不仅仅是清理原始数据。这也是重要的一步。然而,探索数据中的底层结构并理解特征之间的关系是至关重要的。
如果您正在处理一个新问题,那么定义数据需求也是您的工作。这是另一个需要特殊技能的挑战。领域知识是其中重要的一部分。
特征工程比机器学习模型的超参数调整重要得多。超参数调整所能达到的效果是有限的,因此您可以在一定程度上提高性能。另一方面,一个信息丰富的特征有可能极大地改进模型。
在我开始作为数据科学家工作之前,我专注于理解机器学习算法以及如何调整模型。我现在大部分时间都在准备数据。
我所说的就绪包括许多步骤,例如
- 清理和处理数据
- 重新格式化数据
- 探索和理解数据
统计知识对这些步骤非常重要。因此,我强烈建议提高你在这方面的知识。对你的数据科学生涯会有很大帮助。
结论
学习数据科学有大量的资源。您可以使用它们来提高您在任何数据科学领域的技能。然而,这些资源不能提供真实的工作经历。没毛病。当你找到第一份工作时,你要做好准备学习一套不同的材料。
感谢您的阅读。如果您有任何反馈,请告诉我。
我母亲是如何开始用 CNN 来报道她的植物的
她的植物状况不佳;Python、Streamlit 和机器学习拯救了我们
禁闭激发了人们的许多技能;一些人转向烹饪,一些人转向乐器,还有一些人尝试种植植物。我们家属于最后一批。在成长过程中,我们在花盆中种植了常见的圣罗勒、芦荟和偶尔生长的金盏花,但现在是时候扩大品种了。于是开始在亚马逊和当地苗圃寻找盆栽土、花盆和其他用具。
我的国家幅员辽阔,不仅在文化、人民和食物方面,而且在动植物和土壤类型方面都是多样化的。根据产品运输的地点,可能会有差异,尤其是当产品是土壤时。有冲积,粘土,红色,红土,黑色,泥炭和更多类型的土壤在该国。不用说,不同土壤的化学和物理性质是不同的,只有某些种类的植物适合每种土壤。
问题陈述
长话短说,我的母亲在每种类型的土壤中种植一切,并补充一些厨房垃圾肥料,但树苗的生长要么很慢,要么植物会在它们身上留下一些下垂的叶子。此外,鸽子——会飞的老鼠——在任何大城市都是威胁。我母亲可以做三件事:
1.确定土壤类型,只在其中种植相关的种子。
2.尽早发现任何疾病并采取纠正措施。
3.照顾鸽子(邪恶的笑声)😈
她花了几个小时在 YouTube 上,试图找到照顾某些植物的方法,说实话,在互联网上寻找信息可能会很难。我想过帮助她,但我的植物学知识很可笑,所以我决定召唤机器学习。
识别土壤类型
资料组
第一个问题是找到土壤的数据。正如我提到的,由于这个国家不同的气候和地理环境,土壤的种类太多了。就在我考虑转向基于土壤特性的更多数值分析时,我发现了一个土壤数据集。它有冲积土、粘土、红色和黑色土壤的图像。看起来足够好了。
完美!让我们开始分析。
系统模型化
在构建了一些卷积网之后,我创建了一个模板,用来为模型设置基线。很多时候,我们需要对超参数做一点小小的调整,就能得到不错的结果。
我使用 split-folders 包将数据(包含子文件夹)分成训练集、测试集和验证集。在定义了训练、测试和验证数据之后,我形成了一个简单的 CNN 模型,其中有一系列卷积层和最大池层,中间有漏失。模型的后几层由激活 softmax 的“展平”和“致密”组成。
我可以看到,在这些纪元中,我获得了令人尊敬的验证准确性。让我们绘制各个时期的准确度和损失。
跨时代的模型准确性和模型损失。验证集和训练集的模型损失迅速下降(图片由作者提供)
看起来不错!现在,我将评估测试数据上的模型,并绘制一个混淆矩阵来检查错误分类。对于一个好的模型,大部分的观察值应该位于对角线上。
对于测试数据的混淆矩阵,大多数观察值是沿着对角线的(图片由作者提供)
看起来我们对问题的第一部分很满意。
识别疾病
资料组
像往常一样,我没有数据集,所以我求助于互联网,快速搜索将我带到了植物村疾病分类挑战,它有 38 个不同类别的图像数据集。诚然,数据集中的许多植物都不在我家生长,但至少有总比没有好。
数据集有大约 100k 张图像,在我简陋的机器上运行它会有些过分,所以我决定使用 Kaggle 的 GPU 功能。此外,数据出现在 Kaggle 上,因此将其导入模型会简单得多。这种数据有许多内核,但我发现有些奇怪的是,大多数人使用训练和验证数据来训练模型,为了测试的目的,他们使用“已经消费”的验证数据。我在这里看到了一个根本性的问题,决定建立自己的模型。
在开始之前,我将训练数据分成训练集和验证集;已经有了一个测试集,所以我设置了三个必需的数据集——训练、测试和验证
系统模型化
在开始建模之前,我记得我的母亲将不得不在现实生活中使用这些模型,而且大多数时候 Keras 的模型都很重~300 MB,这增加了 Heroku 应用程序的 slug 大小。这是一个应该在建模过程中缓解的问题。
我决定使用 MobileNet,经过编译和训练后,它的体积会非常小。
跨时代的准确性和损失看起来很有希望。
植物病害的模型精度和模型损失。(图片由作者提供)
我有一点信心,测试集上的预测不会真的很差,我是对的。
我不能在 Matplotlib 中打印混淆矩阵,因为这里的类的数量是 38,因此这将是一个巨大的矩阵(图片由作者提供)
你可以看到矩阵的对角线由很多数字组成,F1 分数(精确度和召回率的调和平均值)在大多数类别中接近 0.9,我认为这是一个足够好的模型。
现在怎么办?
该模型的主要用户是我的母亲,我不希望她使用笔记本电脑来使用该模型,所以我必须让事情变得简单一些。
进入细流!
在开发 UI 之前,我知道我有两个模型——一个用于土壤分类,另一个用于植物病害。第二个非常小(12 MB ),但前者(300 MB)需要转换以兼容物联网设备。谢天谢地,TensorFlow 让我们这样做。
现在,我们已经准备好在 Streamlit 上部署应用程序。
部署
Streamlit 应用程序非常容易构建,我所要做的就是在一个文件夹中创建 app.py、setup.sh、requirements.txt、Procfile、models 和其他我正在使用的东西。请看这里的 GitHub 回购。
如果你的 GitHub repo 中有所有文件,那么你可以轻松地使用 Streamlit 共享服务(免费),指定你的 app.py,如果一切顺利,你将拥有一个你可以在任何地方从访问的应用(不知道专制国家)。
请查看这里部署的 app—https://share . streamlit . io/prashantmdgl 9/soil-analysis/main/app . py
或者在https://soil-analyser.herokuapp.com/
资源
编辑资源列表以便于访问。
- 土壤数据集出现在这里。
- 患病叶片数据集出现在这里。
- 部署的应用程序可以在这里 (Streamlit)和这里 (Heroku)访问。
- 部署的应用程序的 GitHub 是这里的(Streamlit)和这里的(Heroku)。
- 训练土壤模型的代码在这里 (GitHub)。
- 训练叶子模型的代码出现在这里 (Kaggle)。
我母亲的反馈
- 她的手机拍摄高分辨率照片,每当她拍摄照片并上传到应用程序时,应用程序就会崩溃。我错过了它,因为测试图像的尺寸非常小。我可以通过设置更高的递归限制来缓解这个问题。
sys.setrecursionlimit(10000)
2.她喜欢这个应用程序提供建议,告诉她应该在土壤中种植什么类型的植物。
其中一个分类结果的快照(图片由作者提供)
3.她对植物疾病模型的结果并不感到兴奋,因为根据它,几乎所有她的植物都需要手术室,我完全理解这一点。
我错误地认为病叶可能看起来有些相似。这种假设似乎很牵强,因为叶子上可能有特征斑点。
迫切需要用她种植的植物来更新这个数据集。目前,她可以在这个应用程序的帮助下照顾小番茄植物。如果叶子是绿色的,它将被分类为健康的,并且在许多情况下,很少有黑星病、锈病、枯萎病、霉变将被正确分类。对于那些身上有自然斑点、黄线、棕色斑点的物种,我需要随时更新数据。
就目前而言,如果因为这种努力,甚至有一些植物得到了正确的治疗,那就“不错”了!
资料来源:Giphy
网飞元流如何帮助我们建立真实世界的机器学习服务
基于真实世界用例的元流快速介绍。
斯塔基·贾在 Unsplash 上的照片
这篇文章生活在:
简介:
两年前,我作为一名软件工程师加入了 future demand,去年我和我的团队一直在使用 Metaflow,在这篇文章中,我想总结一下我们使用它的经验。
该框架最初是在网飞开发的,它有一个活跃的社区。由于这个框架仍然相对较新,我决定写一篇文章来描述什么是元流,以及它如何适应产品开发过程的全貌。
尽管 Metaflow 有非常好的文档,但我认为基于真实世界的用例来编写我们的经验会有所帮助,并且更容易掌握。
为了快速了解未来需求,我们与活动组织者(体育、音乐和娱乐活动)合作,通过从他们已有的数据中提取知识来提高他们的门票销售。我们根据人们的真实兴趣,而不是社会和人口统计特征,使用味觉群集的概念来定位人们。例如,基于音乐品味的定位基本上是推动古典音乐领域销售的因素,而不是其他任何特征。
什么是元流?
Metaflow 是一个框架,帮助数据科学家在生产环境中管理、部署和运行他们的代码。它通过跟踪数据科学家所做的实验来加速开发过程。
前置元流:
在我加入公司时,数据科学团队已经开发了他们的模型。他们的代码是 python 脚本,在本地机器上运行以交付最终结果。
回到过去,这段代码最初是在 Jupyter 的笔记本上写的。然后,我们的团队对其进行提取和重构,使其作为自动化的纯 python 脚本运行。
作为工程师,对我们来说,重点是部署和管理这些代码,如何实现自动化,以及将这些脚本投入生产。
元流开始发挥作用:
那时,我们的机器学习代码可以被描述为 DAG(有向无环图)。
简而言之,DAG 是工作流的数学表示,它描述了处理和转换数据的步骤,基本上,它是数据管道的抽象
线性非循环图—图片由 Metaflow 官方文档提供— Apache License 2.0
分支无环图—图片由 Metaflow 官方文档提供— Apache License 2.0
我们自己管理工作流没有任何优势,所以我们决定使用一个框架来为我们运行和管理代码。使用框架可以在很多方面帮助我们。例如自动化、并行化、编排、故障转移(在特定步骤失败后恢复)等。
在做一些研究时,我们发现了许多选项,如(Luigi,Airflow,Metaflow,MLflow),由于 Metaflow 和 AWS 之间的高度集成给我们留下了深刻的印象,我们决定使用 Metaflow。
元流术语:
元流流量:
流是 Metaflow 中的主要概念,它是一段描述要执行的步骤以及这些步骤的执行顺序的代码。
让我们考虑下图中提供的 DAG:
Metaflow 官方文档提供的图片— Apache 许可证 2.0
基本上,这个流程可以使用 python 来实现:
并且该流程可以如下容易地执行:
在本地运行元流-按作者分类的图像
元流运行:
元流运行的概念——至少对我来说——是一个新的和聪明的东西。
基本上,每次您或任何其他团队成员在本地或 AWS 上运行流程时,所有连接到流程的元数据都会自动存储在中央数据库或 S3 上,以备后用。
例如:
- 你分配给 自身 的任何东西都会被保存。
- 行刑的时间。
- 已执行的代码版本。
- 元数据(输入参数、状态、执行流程的用户)。
- 数据科学工件(模型、特征集、训练数据快照)
元流服务:
正如我在上一节中提到的,Metaflow 的每次运行都会被跟踪,但是这是怎么发生的呢?
简而言之,有一个客户端 API 服务器在运行(在 AWS 上)。
我们称之为元流元服务,每次流被执行时(本地或 AWS 上),所有关于您运行的元数据都将被传输到一个中央数据库——使用元服务。
元流用例:
我将提到一些我们可以从 Metaflow 中受益的用例,以及它如何使我们的开发和部署过程变得更加容易:
跟踪和版本控制:
在开发模型时,我们的数据科学家必须进行实验,并选择能够提供最佳模型的最佳特性集。基本上,他们使用 excel 文件来存储哪个特性集给出哪个结果。
应该有更好的方法来做这件事, 对吗?
答案是肯定的,Metaflow 将存储您或任何其他团队成员所做实验的所有数据,您可以轻松检查所有历史运行,以比较和选择您的模型的最佳结果。
检查您的历史运行非常简单,可以使用下面的代码片段来解释:
检查历史运行
在这个代码片段中,我们对一个流的所有历史运行进行迭代,并从每次运行中读取一些数据。除了做实验,我们的模型还在不断变化的训练数据上接受训练。迭代历史运行帮助我们理解这是如何影响我们的模型的,这是我们可以使用 Metaflow 轻松跟踪的。
扩展和云集成:
我们的另一个用例是,我们希望在本地训练我们的模型,但是有些步骤需要太多的时间和资源来执行。
我们发现,即使我们在本地运行流程,我们也可以很容易地将特定步骤切换为在 AWS 上作为批处理作业执行——这可以使用 batch decorator 来完成:
使用 AWS 批处理作业扩展我们的资源
在最后一个代码片段中,通过对步骤 a 使用批处理装饰器,我们使用请求的内存和 CPU 资源在 AWS 上强制执行这个步骤,同时仍然使用我们的 ide 来运行代码。
在本地运行元流,并强制一些步骤作为批处理作业在 AWS 上运行——图片由作者提供
部署:
部署是元流的另一个有用的方面。我们第一次讨论如何部署和自动化重新训练我们的模型的过程时,我们考虑了将我们的代码归档,以及选择哪个服务最适合运行代码,等等…
后来我们发现使用 Metaflow 部署过程再简单不过了。
基本上,通过执行一个命令,我们可以将本地流反映为 AWS 上的阶跃函数状态机,我们可以使用 lambda 函数或手动触发它。
这是一个例子:
将元流部署为 AWS 上的阶跃函数状态机—图片由作者提供
这个流程在 AWS 上反映为一个阶跃函数状态机:
AWS 上的阶跃函数状态机—图片由作者提供
我们习惯于在 AWS 上手动触发它们,并使用 lambda 函数安排日常运行。
这是我们的流的阶跃函数在 AWS 上的样子:
触发 AWS 上的流量—图片由作者提供
后来,我们构建了一个简单的部署管道,并将其附加到我们的代码库中。每当有人将新的变更推送到特定的分支时,所有的变更都会直接反映在相关的 step 函数上。
机器学习的持续交付:
在其中一个用例中,我们在 rest API 后面使用了一个数据科学模型,以服务于前端并给出事件建议,正因为如此,我们的模型需要每天进行训练,以包含新的事件。我们使用 Metaflow 在后端加载模型的最新版本,步骤如下:
- 从 Metaflow 的最近一次成功运行中在后端加载模型。
- 使用加载的模型对服务进行健全性测试,只有当它通过测试时,我们才使用新的模型。
- 如果健全性测试失败,我们返回到更早的元流运行,从模型中加载一个可以通过我们测试的旧版本。
这完全可以在没有 Metaflow 的情况下完成,但对我们来说,使用 Metaflow 来为我们版本化和存储所有数据科学工件要简单得多。
调试和恢复失败的流程:
另一个有用的用例是恢复失败步骤的能力。
有时,计划在 AWS 上每天运行的步进功能会失败。由于数据不断变化,重现错误变得更加困难,因此,我们希望能够使用相同的数据集恢复失败的步骤。
通过使用 Metaflow,我们可以轻松地检查我们机器上的流,查看导致错误的数据,从失败的步骤恢复流执行,并调试哪里出错了。
最后…
总之,在某些方面,使用 Metaflow 对我们来说和使用 Git 对代码本身一样重要。它让我们的数据科学家有可能在代码的整个生命周期中对其进行管理。同时,这也给了我们(工程师)更多的时间去关注系统的其他部分。
在你走之前…
感谢 的阅读!我希望你喜欢这篇文章……如果你想与我取得联系,请随时通过 ahmad.hori@gmail.com 联系我,或者通过我的 LinkedIn 个人资料也可以通过 关注我的媒体 了解更多故事。
神经网络如何学习
反向传播的数学指南
本文的目的是通过开发一个框架来分析权重和偏差的变化如何影响成本函数,从而提供对神经网络的 学习 过程的数学理解。一旦理解了这一点,我们将能够确定如何使用像 Adam 这样的优化算法,使非常小 改变这些变量中的,可以降低成本函数。
神经网络,或者具体地说是人工神经网络,是一系列模仿动物神经系统的节点,产生类似于大脑的信息处理能力。这些节点之间的连接由在训练过程中学习的权重指定。这些网络背后的基本思想可以追溯到艾伦·图灵在 1948 年发表的题为智能机器的论文中,他将它们称为 B 型无组织机器,即从初始组成来看相当无组织,但能够学习如何执行特定任务的机器。今天,这些神经网络构成了深度学习算法不可或缺的组成部分,本文旨在阐明它们到底是如何学习的。
让我们从想象一个相当简单的神经网络开始。让我们想象一个由 L 层组成的网络,但是每一层只有一个神经元,如下图所示。
现在,让我们将我们的分析限制在最后一层和倒数第二层之间的连接,下面显示了这两层的关联权重()和偏差( b )。
激活的神经元 L 和 L-1 分别是 a^(L) 和 a^(L−1) 。如果最后一层的期望输出为 y ,则误差或代价函数变为c _ o =(a^(l)−y)。这也称为均方误差,可能是所有可用选项中最简单也是最广泛使用的。成本函数中的下标表示这是第一个训练图像/数据点的成本,并且整个训练过程将需要对训练数据集中的所有 N 个图像进行训练。这里的层 L 的激活可以表示为:
其中**【b^(l】是层 L 和 σ 是上面讨论的激活函数。学习包括使用合适的优化算法(通常是梯度下降的某种变体)来达到最小化【C20】***【ω(l】和***【b(l】**的最优值。我们通过检查成本函数对偏差和权重的小扰动的敏感度来做到这一点,即通过使用链式法则计算以下偏导数:
上述等式右侧的偏导数可以计算如下:
将上面导出的偏导数代入等式 1 和 2
这两个偏导数有助于量化重量和偏差的变化如何影响成本。
现在让我们添加另一层到我们的神经网络,如下所示。
除了我们刚刚计算的两个偏导数之外,为了充分研究权重和偏差变化对成本函数的影响,对于该网络,我们还必须计算倒数第二层的以下两个偏导数
上述两个方程所需的偏导数可以计算如下:
代入这些值,我们得到与层 L-1 相关的权重和偏差变化的成本函数变化率的以下表达式
*这应该能让我们了解反向传播是如何工作的。首先,我们根据层 L 和 L-1 的激活情况,确定成本相对于层 L 的重量和偏差的偏导数。然后,我们推导出该相同成本函数相对于层 (L-1) 的权重和偏差的导数,作为层 **L、L-1、**和 **L-2 的激活的函数。*这些激活又被表达为各自权重和偏差的函数。我们可以遵循相同的过程,直到整个网络的第一个神经元,以确定所有的权重和偏差如何影响成本函数。
在我们的分析中,到目前为止,我们还没有解决单层中有一个以上神经元的情况。事实证明,向一层中添加更多的神经元只需要一些额外的指标来跟踪。下面显示的是一个两层的神经网络,但每层都有许多神经元。这里,我们引入两个新的指数来跟踪每一层上的神经元,k 用于层 L-1,j 用于层 L。
这种情况下的成本函数将是输出层 L 中每个神经元的成本之和
层 L 中每个神经元的激活将是层 L-1 中所有神经元的激活的加权和
成本相对于层 L 的重量和偏差的偏导数可以如前所述
上述方程所需的偏导数可以像以前一样计算。
将这些代入等式(1)和(2)
上面的等式是用于具有两层但每层有许多神经元的神经网络。我们可以类似地计算具有许多层和每层许多神经元的神经网络的偏导数。我不包括这个方程,因为它们本质上涉及与上面讨论的相同的逻辑。
如何不成为数据科学家
什么“不要做”也很重要
由 Unsplash 上的 Karsten Winegeart 拍摄
数据科学是近年来最受欢迎的工作之一,吸引了各行各业的无数人。这些人,包括我自己,花费大量的时间成为一名数据科学家。
在河的另一边,有人帮助或指导那些试图成为数据科学家的人。书籍、个人博客、Youtube 视频、MOOC 课程是帮助有抱负的数据科学家过河的一些工具。
由于这种受欢迎程度和需求,有大量关于“如何成为数据科学家”的资源。我还写了几篇文章,试图让数据科学学习之旅更加实用和高效。
在这篇文章中,我打算从一个不同的角度来看这个话题。这里的重点是“如何不成为数据科学家”,所以我将尝试解释在学习数据科学时应该避免或不应该做什么。
我花了大约两年时间找到了我的第一份工作,成为一名数据科学家。在这漫长的旅途中,我做了一些我不该做的事情。因此,我对“不要做”很有经验。
读,看,读,看,…
大多数资源以书面材料或视频的形式出现。总的来说,学习一项新技能,观察比阅读更受欢迎,因为这样更省力。
当我读一些东西时,我觉得我的大脑比看同一主题的视频更关注这个主题。
然而,就所需的主动学习而言,阅读和观看都是不够的。尤其是在学习软件工具或编程语言的时候。
当我阅读或观看时,我觉得我学得很好。然而,真正发生的是我理解了题目,而不是学会了。
正如尼克·达姆在这篇文章中所说,“对于大脑中发生的学习来说至关重要的神经连接的变化,在学习经历不活跃时似乎不会发生。许多研究表明,积极参与是大脑变化的先决条件。毫不奇怪,仅仅听一场演示或讲座不会带来学习。”
在 Youtube 上看视频类似于听讲座。如果没有实践或实践经验的支持,你很可能会失败。
不要做:不要只是阅读和观看。尽量多练。实践经验在学习数据科学中至关重要,尤其是在学习软件工具或编程语言时。
学这个学那个
数据科学的范围是巨大的。金融、零售、图像识别、自然语言处理只是你可能作为数据科学家工作的一些领域。
虽然基本原理是相同的,但每个领域都有特殊的技术和概念需要学习。
除此之外,数据科学中还有丰富的工具可供选择。你将有许多编程语言、库、软件工具的选择来学习和执行典型的任务。
让我说清楚。如果你试图全部学会,你会失败的。
你应该做的是缩小你的关注范围。例如,一种编程语言和几个库就足够了。与其把很多东西学到一定程度,不如试着掌握一门。这肯定也会增加你找到工作的机会。
让我们关注一个更具体的例子。Matplotlib,Seaborn,Altair 是 3 个流行的 Python 数据可视化库。所有的都学没有意义。每一个都有一些优点和缺点,但这不是你在学习过程中应该关心的事情。
同样,你应该试着决定你想在哪个领域工作。例如,如果你决定从事金融工作,你应该掌握时间序列分析,这不是自然语言处理的要求。
一旦你真正开始作为一名数据科学家工作,你就可以转换领域。然而,最好是选择一个特定的领域,并努力掌握所需的技能。这会让你的简历或作品集脱颖而出,增加你找到工作的机会。
不要做:不要试图学习每一个主题和工具。一开始尽量用最少的。
承诺过多和兑现不足
我碰到过很多帖子,标题都是“x 个月学会数据科学”。“x”通常为 3 或更小。这绝对是一个过度承诺。这需要 3 个多月的时间。事实上,学习数据科学是一个持续的过程,所以即使在你开始作为数据科学家工作后,你也会继续学习。
当然,设定目标是件好事,但你不应该从这种过度承诺开始。3 个月的时间结束后,这将是一个动力断路器。你会意识到有更多的东西需要学习,这可能会让你认为自己不适合成为一名数据科学家。
学习数据科学,我们需要的是一个有现实里程碑的结构良好的计划。需要多长时间取决于你的技能和知识,以前的工作经验,以及你目前的计划。请记住,我们不是在进行短跑比赛。
不要做:不要过度承诺。你可以设定你的目标,但要现实一点。学习数据科学不是几个月就能完成的任务。它需要时间、奉献和更长时间的努力。
结论
我花了将近两年时间找到了我的第一份工作,成为一名数据科学家,我很高兴我做到了。这是一次有趣但富有挑战性的旅程。
如果你有决心和时间,你将会实现成为一名数据科学家的目标。避免我刚刚在这篇文章中提到的情况,将有助于你的学习之旅更加高效和顺利。
感谢您的阅读。如果您有任何反馈,请告诉我。
如何(不)在数据科学项目中失败
行业笔记,商业科学
可能破坏投资回报和影响的 4 个设计选择
自新冠肺炎疫情开始一年多以来,数据科学家仍在努力让他们的模型恢复原状。大约每周,我都会看到另一篇文章哀叹过去一年的混乱对机器学习模型产生了负面影响。许多组织已经不再试图适应,只是希望等待,直到我们“恢复正常”。
当他们最终意识到不存在正常这种东西时,他们将会大吃一惊。
我们所有在数据科学领域工作的人都需要认识到导致这些模型崩溃的失败,并以新的方式处理我们的算法设计。我们不必继续犯同样的错误。
数据科学中这 4 个常见的项目设计选择让你很容易失败。这是你实现模型漂移、最小影响和低投资回报率的路线图(或者,更好的是,4 件让你走向成功的事情)。
1.隔离您的项目
回想一下您最近的几个数据科学项目。希望它们不要太相似,这样你就可以挑战自己并保持有趣。但是,即使它们是具有相反目标的非常不同的项目,代码和机器学习基础仍然非常相似。现实情况是数据科学家有一个特殊的工具箱并且经常重复方法来实现不同的目标。
尽管如此,数据科学家倾向于创建与其他数据科学家和其他项目隔离的项目孤岛。我们最终会浪费大量时间重复自己的话,做类似的分析。甚至在同一家公司的团队也是如此!
整个数据世界是一个集成的全球系统;打破这些联系只会限制你的回报。
所有数据、见解和中间结果应在整个分析中共享,以最大化其影响。由于您的大多数项目处理相似的操作,隔离只是浪费时间。
当你在一个 项目孤岛 上时,你往往会为了收益而错过关键领域。你看到了所有的水,却忽略了底下的东西。将您的项目与其他数据科学项目隔离会让您面临失败,因为您必须重新学习过去的所有经验教训,并从头开始重新创建所有最好的代码。孤立的数据、方法和代码让你容易犯错。与其重新创建代码,不如将时间和精力用于设计您的分析。你会得到更好的结果。
**资料荒岛。**图像演职员表:兰道尔·门罗、xkcd 。
2.从工具出发,而不是从目标出发
作为一名数据科学爱好者,我和其他人一样对使用新工具和新类型的分析来改进我的结果感到兴奋。很难抗拒全新战略的吸引力,尤其是因为数据科学的最新进展通常会提供大量增长机会。
这是一个普遍的问题。在最近一期的麻省理工学院斯隆管理评论中,他们讨论了一名技术娴熟的数据科学家受聘改进印度一家大型金融公司的投资定位算法的案例。他迷上了 k-最近邻算法,并投入大量时间和精力将其应用到分析中。
收获甚微。事实上,该算法的建议并不比任何专业人士在没有任何正式统计分析的情况下通过查看数据给出的建议更好: 所有开发该工具的努力,却一无所获。
K-最近邻 算法。 图片演职员表: E. M. Mirkes,维基媒体 。
为什么?如果你知道关于 k-最近邻算法的任何事情,它看起来会有很大的潜力。您可以使用健壮的聚类快速对数据进行聚类,以找到看似噪声的模式和相似性。它应该工作,对不对?
这个问题要追溯到最开始。我们的目标是看看一个特定的算法能做什么,而不是改进 KPI。确切的项目设计是有缺陷的。在有效的数据科学项目中(我喜欢称之为商业科学),必须有一个精确的目标,以获得想要的结果。
太多时候,数据科学家带着“让我们应用这个方法,看看我们有什么发现”的心态来建立项目。有时这能带来令人印象深刻的结果,但通常表现不佳。
成功的数据科学项目只回答一个问题:我如何改进这个 KPI?
实验可能有它的位置,尤其是在大学里,但一旦你试图实现可预测的增长和最大化的结果,方法必须是不同的。从工具出发,而不是从目标出发,将永远无法实现投资回报最大化。最佳实践是从业务需求出发,找到实现目标的最佳统计方法 —即使它并不花哨,也不是数据科学领域的最新趋势。
如果你专注于方法或工具,而没有深入到为什么,你会让自己失败。
3.优先考虑错误的 KPI
当然,即使你把目标放在第一位,只有当目标是正确目标时,你才能获得最佳结果。
你的努力的影响主要取决于你选择优先考虑的 KPI。例如,在零售业,我们经常看到人们以牺牲更有价值的洞察力为代价来提高需求预测的准确性。如果你花费数周时间开发完美的工具,将预测准确度提高 2 个百分点,如果数据科学家忽略供应链或定价中的突出问题,这可能不会产生太大影响。优化这些关键绩效指标带来的收益将更加显著。
KPI 优先顺序 至关重要,也极具挑战性。没有一个硬性的规则告诉你你的目标应该是什么,但是两个简单的准则可以使决策过程更容易管理:
1。 你的 KPI 应该对底线有重大影响。
2。 你的 KPI 应该有增长的潜力。
第一条规则很简单。你的目标应该带来切实的回报。例如,一家连锁杂货店将从只能优化牛奶价格的算法中获得最小的好处。它将从能够最大化整体收入的算法中获得更大的好处。这通常要复杂一点,但原理是一样的。
一个简单的测试?在您选择的 KPI 中添加“等等……”:即,我们正在优化额外的利润增长,等等,这将使我们能够在短时间内大幅提高底线收入。这个练习把你带出经常导致这个设计缺陷的技术思维模式。你可以交付具有更大影响力的业务可消化的产出。
**了解正确的 KPI 并非易事。**图片致谢: Evo 定价 (CC 带归属)
第二条准则更难实现。有时,很难从表面上评估特定 KPI 的改进潜力。然而,你通常可以通过识别关键痛点、资源消耗或浪费领域来找出最大潜力所在。消除这一点大有帮助。
您的目标成果最终决定了您的数据科学项目的成败。所以要慎重选择。
4.选择错误的分析深度
设计数据科学项目的最后一个致命缺陷?选择错误的分析级别。
作为数据科学家,我们可以利用四个基本的分析级别:描述性、诊断性、预测性和规范性。所有这些都有其目的,但对于大多数大规模数据科学项目来说,只有规定性分析才会产生最大的影响。
**价值与分析难度。**图片来源: Evo 定价 (CC 带归属)
只有规定性分析才能推动,而不是分析或预测结果。它提供了最佳的预见性,并且是优化您选择的 KPI 的最佳设计。通过规范性分析实现的灵活性使您能够实现您的目标,而不管前进道路上的干扰或障碍。
在建立新项目时,很容易默认使用预测分析。毕竟,预测是大多数非数据科学家要求从他们的数据中学习的东西。另外,指令性的方法更难!但作为专家,我们应该更清楚。优化几乎总是我们的真正目的。这要求我们站出来拥抱更艰难但更有回报的成功之路。
在过去的一年里,在新冠肺炎危机面前,导致人工智能模型崩溃的干扰是普遍存在的——但不是规范模型中的。他们在处理模式变化时更加敏捷,并且能够调整。
如果您想在自己的项目中避免这种失败,请仔细考虑一种规范的方法。
明确地说,描述性、诊断性和预测性分析仍有价值。但是他们永远不会让你的数据价值最大化。除非您的项目范围仅限于事后诸葛亮,仅仅是为了及时捕捉快照或以其他方式限制规模,否则您将在说明性分析方面取得更大的成功。项目难度会增加,但影响也会增加。
为数据科学的成功干杯!
Guille 阿尔瓦雷斯在 Unsplash 上拍摄的照片
这可能看起来过于简单,但是简单地从你的项目设计中消除这些错误将会显著增加你在数据科学中的成功率。这是我们这个领域迫切需要的。根据 Gartner 2017 年的一项研究, 85%的数据科学项目都失败了。我认为这一数字在过去 5 年中有所改善,部分原因是人工智能和机器学习的巨大进步,但几乎没有变化的迹象。
就我们所知,为什么?
这可以归结为我们设计这些项目的核心缺陷。
最终,有缺陷的不是技术;它是实现—和我们。幸运的是,这意味着我们有能力为此做些什么。有了集成、规范的方法和正确的目标来指导您的设计,建立一个失败的数据科学计划将会困难得多。
我不能保证这四个考虑会消除你未来的所有失败,但它们会避免最持久的缺陷。这是朝着正确方向迈出的一大步。
PS 更多商业科学来自我的写作:
Monthly Business Science in your inbox, new software, and University-level learning:[**Free access**](https://evouser.com/register)Questions? Please reach out on [Linkedin](https://www.linkedin.com/in/fabrizio-fantini/)
如何不使用 Python 列表
理解 Python 中的可变对象。
由 Sarah Kilian 在 Unsplash 上拍摄的照片
我记得几年前当我从使用 R 转换到使用 Python 时,我必须习惯的一件事是可变对象——这在 R 中并不算什么。
可变对象是创建后可以修改的对象。Python 中可变对象的一些例子是列表、字典和集合。在下面的例子中,我们在创建之后扩展了y
。
y = [1, 2, 3]
id(y)
Out[7]: 4831904704y.extend([4, 5, 6])
y
Out[10]: [1, 2, 3, 4, 5, 6]
id(y)
Out[11]: 4831904704
我们可以看到它保持了其唯一的标识号(由id
函数给出)——这意味着我们仍然在使用同一个对象。
另一方面,不可变对象不能被修改。一些例子是元组、字符串、整数、布尔等。正如你在下面的例子中看到的,一旦我们改变了x
的值,它的身份就改变了——我们已经将x
重新分配给了2
。
x = 1
id(x)
Out[3]: 4564694112x = 2
id(x)
Out[5]: 4564694144
如果您不习惯可变对象,那么编写具有…的代码是相当容易的。意想不到的后果。
让我们来看几个例子(在大多数情况下,不要做什么)。
列表作为默认参数?
假设您正在编写一个类来帮助跟踪每个人的朋友。所以你要做以下事情。
*class* FriendBook:
*def __init__*(self, *name*, *friends*=[]):
self.name = *name* self.friends = *friends
def* add_new_friend(self, *friend*):
*if friend not in* self.friends:
self.friends.append(*friend*)
然后你开始为不同的人创建友谊书。
person_a_friendbook = FriendBook(name='Person A')
person_b_friendbook = FriendBook(name='Person B')person_c_friendbook = FriendBook(
name='Person C',
friends=['Person E'],
)person_a_friendbook.add_new_friend('Person D')
现在,我们希望 B 在这一点上没有朋友。但是,事实并非如此。
person_a_friendbook.friends
Out[3]: ['Person D']person_b_friendbook.friends
Out[5]: ['Person D']person_c_friendbook.friends
Out[7]: ['Person E']
这是因为我们的默认参数friends=[]
只被创建一次,在我们创建类的时候。我们可以通过使用比较它们的身份的is
操作符来验证这一点。
person_a_friendbook.friends is person_b_friendbook.friends
Out[8]: True
我们可以看到person_a_friendbook.friends
和person_b_friendbook.friends
的身份是一样的。任何时候你回过头来使用friends
的缺省值,你都将使用同一个列表——这意味着这个列表将被所有使用缺省参数实例化的对象共享。这很少(很可能永远不会)是我们想要的。大多数 ide 会警告你。
PyCharm 试图将我们从可变的默认参数中拯救出来。图片由作者提供。
解决办法很简单。
*class* FriendBook:
*def __init__*(self, *name*, ***friends*=None**):
self.name = *name* **self.friends = friends or []** *def* add_new_friend(self, *friend*):
*if friend not in* self.friends:
self.friends.append(*friend*)
这样,我们为每个对象都获得了一个新的空列表。
但我只是修改了函数内部的列表?
继续下一个我们可能会搞砸的方式。
x = [1, 2, *None*, 4, 5, *None*]
*def* fill_none(*data*, *fill_value*):
n = len(*data*)
*for* i *in* range(n):
*if data*[i] *is None*:
*data*[i] = *fill_value
return data* y = fill_none(data=x, fill_value=100)
上面的函数越过data
并用fill_value
替换None
值。
y
Out[1]: [1, 2, 100, 4, 5, 100]
y
的值是我们所期望的。你能猜出x
现在是什么吗?如果你认为它和y
一样,那么你是正确的。
x
Out[2]: [1, 2, 100, 4, 5, 100]
当我们将一个可变对象作为参数传递给一个函数时,我们给了这个函数修改它的权力。现在,我们可以用两种方法来解决这个问题。第一个是清楚地表明,如果我们真的想这样的话,函数会修改列表。在我看来,我们可以通过删除return
语句并添加一个 docstring 来实现。
x = [1, 2, *None*, 4, 5, *None*]
*def* fill_none(*data*, *fill_value*):
'''
Replace None values with the fill_value. Modifies data in-place.
'''
n = len(*data*)
*for* i *in* range(n):
*if data*[i] *is None*:
*data*[i] = *fill_value* fill_none(data=x, fill_value=100)
第二种选择是在函数中使用列表的副本。
x = [1, 2, *None*, 4, 5, *None*]
*def* fill_none(*data*, *fill_value*):
data = data[:] # make a copy of data
n = len(*data*)
*for* i *in* range(n):
*if data*[i] *is None*:
*data*[i] = *fill_value* *return data*y = fill_none(data=x, fill_value=100)
现在x
和y
不一样了。
y
Out[13]: [1, 2, 100, 4, 5, 100]
x
Out[14]: [1, 2, None, 4, 5, None]
你确定元组是不可变的吗?
如果你记得,在这篇文章的开始,我们说过元组是不可变的,它们是不可变的,它们没有允许我们改变它们的方法。你可能想知道的一件事是“我能在里面放一个列表吗?”然后“我能改变元组内部的列表吗?”。答案是“是”和“是”。
my_list = [1, 2, 3]
my_tuple = ('a', 'b', my_list)my_tuple
Out[1]: ('a', 'b', [1, 2, 3])my_list.append('surprise')my_tuple
Out[2]: ('a', 'b', [1, 2, 3, 'surprise'])
为什么会这样?嗯,tuple 是不可变的意味着我们在创建它之后不能改变它包含的对象(但是如果它们是可变的,我们可以修改其中的对象)。事实上,即使在我们修改了列表之后,my_tuple
仍然包含相同的三个元素,它们在我们创建它的时候都有相同的身份。这不一定是“搞砸了”或你想做的事情,但如果你没有意识到这一点,可能会令人困惑。
结论
在这篇文章中,我们讨论了 Python 中的可变和不可变对象。我们关注了可变对象,更具体地说是列表,如果不知道它们是如何工作的,会导致意想不到的后果。
更多来自同一作者。
https://medium.com/analytics-vidhya/calculating-using-monte-carlo-simulations-337cff638ac5
你撞头的频率取决于你离北极有多近
詹尼弗·拉特珀里萨-安德森在 Unsplash 上拍摄的照片
此外,还有一堂关于 Altair python 可视化的课
这是一种古老的技术。这叫权力姿态。你拥有宇宙,所以举起你的岩石酒杯;为摇滚的人干杯。现在微笑点头,让我看看你的眼珠子,好像有什么不对劲。
你听起来熟悉吗?
在一个过去 15 年来小心存放的外置硬盘中,我发现了电影、连续剧、照片、视频和其他随身物品。它有我过去常听的歌曲的 mp3 快速一瞥,我看到了范·海伦,金属乐队,梅加迪思,以及其他艺术家。我打开了其中的几个文件,但大多数都无法播放,或者比特率太低,我甚至无法欣赏它们。这就是时间对你的影响!
说实话,我从来都不是一个狂热的金属追随者,但硬摇滚亚流派正好符合我的兴趣。我原以为我的 Spotify 的大部分播放列表会被《摇滚但男人》占据。我还能错得更离谱吗?我还是会定期听很多经典,还是会点点头。检查完硬盘后,我花了几个小时听老音乐,后来在网上搜索相关数据集,看看摇滚学校发生了什么;很快,我找到了一个,但它是为金属乐队而不是摇滚。
哦好吧!这不是关于敲打头部,而是关于猛烈地摇晃它。
我们走吧!🤘
寻找重金属
我在 Kaggle 上找到了一个数据集,你也可以在这里访问它。它包含了从这个摇滚子类开始(即 1964 年)的金属乐队的信息。你也可以使用从金属档案里刮来的关于死亡金属的这里。
在丢弃了复制品和那些没有任何原产国的乐队后,我前进到观想。放心吧!所有那些掉下来的都不流行,因为他们只有很少的粉丝(变量之一)。
没心情用 matplotlib,plotly,bokeh,seaborn,就用 Altair 吧。
谁最摇滚?
我知道的许多著名乐队来自美国和英国,但北欧和斯堪的纳维亚也不甘落后。我们来调查一下。
使用 Altair 相当容易;我推荐看杰克·范德普拉斯(Jake VanderPlas)的前 40 分钟视频。
你提到你的数据框架作为“源”,并使用其中的属性来构建你的图。您可以在字段中使用诸如“排序”之类的选项,并且可以获得想要的效果。无需专门更改数据集。
作者图片
不出所料,美国和英国有很多金属乐队,斯堪的纳维亚国家也名列前茅。
但这是清晰的画面吗?美国、英国和德国人口众多,所以也许我们需要找出人均金属乐队的数量。
人均摇滚现场
该图表很容易制定,我需要创建一个临时数据框架,将国家的人口作为一个属性,可用于进行更准确的分析。
作者图片
法罗群岛?他们在黑色安息日和金属乐队是不是用药过量了?嗯,他们有 5 个频段,代表 5 万人口,所以每 1 万人就有一个频段,如图所示。此外,法罗岛紧挨着丹麦和瑞典,所以它得到了感应效应。
如果梵蒂冈城只有一个乐队,它会让所有其他国家感到羞愧(梵蒂冈人口约 800 人)。
那么,是什么亚类让它们滴答作响呢?
金属世界中最受欢迎的分支是什么?我猜这将是重金属,鞭打,黑色。
作者图片
请注意,我们到目前为止所做的所有图表都是条形图,所以上面的代码只做了微小的改动。
要在笔记本、VSCode 或 Atom 中呈现这些图形,请使用:
我又对了!
黑色、死亡和沉重的统治。黑暗之神一定很高兴。
金属正在消亡吗?
每年有多少个金属乐队成立?
作者图片
这些年来,乐队的数量似乎在减少。这是否意味着金属正在消亡?
仅仅因为你没在听它,并不意味着它遇到了它的创造者。找到每年形成和分裂的波段,以找到每年活跃波段的数量,这是公平的。
作者图片
金属是摇滚的一个分支,它比硬摇滚更刺耳,硬摇滚在大众和广播中都有听众。你不会在收音机里听到金属歌曲,你必须自己去寻找。如果你不去尝试,你永远也找不到它,并且会认为它是一种正在消亡的文化。
给那些让我们头大的人
每个国家最受欢迎的金属乐队有哪些?
作者图片
这是一个有趣的图表,因为条形标有。你可以选择任何颜色,你只需要指定十六进制代码,并不限于特定库的样式表。通过使用(图表+文本)来查看单个图表中的效果,您可以制定图形的单个元素,并可以像上面一样绑定它们。
词源学视角
我最终将我的数据框架与金属档案中的数据合并,因为它很好地包含了乐队的主题信息。一个简单的词云就能说明很多:)
作者图片
哦好吧!你在期待什么?
世界观
作者图片
这是一个使用 leav 创建的图表,只是条形图的另一种表示。
裁决是明确的。
格陵兰岛、冰岛、瑞典、挪威和芬兰似乎摇摆得很厉害;离北极越近,头撞得越厉害!😃
你可以在我的 GitHub 上找到创建图表的代码。和往常一样,你可以在 Twitter (@prashantmdgl9)上找到我,或者在 LinkedIn 上大喊一声。我很想知道你会用这些数据创造出什么样的视觉效果。
后来添加的东西
摇滚、硬摇滚、金属都经历了时间的考验;那些不认为它们是真正的音乐的人并不喜欢它们,即使是现在,人们也经常拿它们与老派的古典音乐相比较,这是不公平的。但是只要你喜欢,谁会在乎呢!
还有,我不明白为什么一个人要把自己的音乐品味限制在这样或那样的形式上?我可以像喜欢罗伯特·普兰特的音乐一样喜欢卡切里(古典卡纳蒂克音乐家的集会)。
那么为什么要选择呢?
毕竟,这都是音乐,始于大约 45000 年前有人将两块石头撞在一起。
我从这篇文章中学到的是付了我将近一年的房租
如果你有自己的观点,大胆地说出来
在我攻读理学硕士期间,我的一位教授说了一句话,完全改变了我对自己表达思想方式的看法:“你必须让自己与众不同;你得是个异教徒。”
以人工智能领域的研究规范在过去十年中的变化为例:多年来,人工神经网络被认为是一个失败的事业,一个死胡同。涉及神经网络(NN)的文章受到了怀疑,它们的作者试图隐瞒他们的论文研究 NN 相关属性的事实。
然后,Geoffrey Hinton、Yann LeCun 和 Yoshua Bengio 为我们带来了深度学习,这是一场现在主导该领域的革命,为他们赢得了 2018 年的图灵奖,并为应用程序开发者和用户开辟了新的可能性。深度学习是几十年来坚持反对人工智能研究范式的结果。
"未来取决于某个对我所说的一切深感怀疑的研究生。"杰弗里·辛顿。
因此,我决定听从这个建议,触及我所在领域的一个几乎是禁忌的话题。我有我的想法,我需要把它表达出来。文章的主题其实并不重要,也不是本文的重点。这不是一篇关于如何写故事在媒体上传播的文章。我没有那个食谱。但是,如果你好奇的话,它是关于微软和 Linux、公司和开源世界之间的“激烈战争”,以及如何在一个系统下统一一切以完成工作。
当我完成这篇文章并把它提交给一家媒体时,没有任何东西能预测接下来会发生什么。这篇文章是在早上发布的,直到下午晚些时候,它似乎没有什么特别之处。它有几百个浏览量,我没有在任何社交媒体或相关论坛上发布链接;没有自我推销。
然后,发生了一些事情,每次我刷新 Medium stats 页面时,这篇文章都会获得数百次浏览。直到今天,我不确定是谁推动了它,但它以超过七千的浏览量结束了这一天。第二天又拿了 16 万,第三天又加了 10 万。
我继续在你能想象到的每个论坛或脸书小组中发现这篇文章。一开始,如果辩论不是用英语进行的,我不得不通过谷歌翻译来搜索评论,以获得讨论的要点。最终,这是不可维护的或者没有效率的,所以我就让它这样吧。
最终,这篇文章获得了超过 50 万的浏览量,7.5K 的掌声,超过 1000 小时的会员阅读时间,以及 60 多条评论,其中大多数都指责我贿赂;我告诉过你这个话题在我的领域几乎是一个禁忌,所以如果你表达了一个不受欢迎的观点,那是要付出代价的。然而,我认为 7.5K 的掌声远远补偿了那些没有根据的评论。另外,这是我第一篇被翻译成多种语言的文章。
余波
差不多一年过去了,我仍然收到这篇七分钟长的文章的评论、掌声、提及和关注。但是我得到的不仅仅是中等收入。更多:
- 我找到了今天的工作
- 图书代理商的兴趣
- 这个平台和其他平台上的关注者继续支持我的工作
- 我的时事通讯越来越多的订户
- Twitter 上有影响力的追随者,他们欣赏强烈的观点
我以前写过一两篇像病毒一样传播的文章,之后也写过几篇,但都没有达到那个规模。简而言之,在过去的一年里,单是这篇文章就已经支付了我很大一部分费用。但这不是你应该从这个故事中隐瞒的。
如果你有意见,就需要表达出来
在我开始在 Medium 上写作之前,我没有写博客的经验。去年二月我发表了我的第一篇文章。这是一篇展示我开发的编程库的教程文章。
从那天起,我决定发表我对所阅读的东西的笔记。我研究一些新的东西,做笔记,把它们转化成一篇文章,发表在媒体上。
那篇被广泛传播的文章正是如此。我关于如何统一 Windows 和 Ubuntu 的笔记。这是我遇到的一个实际问题的解决方案。但是还有更多:这也是一篇固执己见的文章。
我没有试图卖任何东西。我没有承诺改变任何人的生活,我没有撒谎,当然,微软也没有资助我。我表达了我的观点,并有证据支持,而这个观点碰巧不受欢迎。我是个异教徒。我睡着了,醒来,成千上万的人在争论这件事。这就是未知因素。这篇文章让人反应过来,支持我的观点,反推,甚至留下可恨的评论。
这篇文章的目的不是给你提供一个写文章的清单,也不是告诉你如何在媒体上致富。然而,你永远不知道谁会读你记下的东西。你永远不知道你会影响谁,谁会参考你的作品。在这个互联的世界里,只需要一个人。
所以,如果你有自己的观点,就要与众不同。人们不需要另一篇文章来宣扬一种已经很流行的观点。你不需要被所有人喜欢,你当然也不需要认同所有人。如果你有自己的观点,大声说出来,大胆提出,拿出证据,做一个异端。
Learning Rate 是为那些对 AI 和 MLOps 世界好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
关于作者
我叫 Dimitris Poulopoulos ,我是一名为 Arrikto 工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。你可以在 Medium 、 LinkedIn ,或者@ james2plTwitter 上关注我。
PagerDuty 如何应用 DevOps 最佳实践来实现更可靠的大规模数据
数据可观察性 101
以下是这家开创事件管理先河的公司如何防止数据停机
图片由 Shutterstock 上的 Michael V 提供,可供拥有标准许可的作者使用。
page duty帮助 90 个国家的 16,800 多家企业通过其数字运营管理平台实现正常运行时间 SLA,支持随叫随到管理、事件智能、分析和事件响应。
那么,PagerDuty 是如何在自己的组织内处理特定于数据的事件管理的呢?最近,我与数据平台和分析高级总监 Manu Raj (被恰当地命名为 DataDuty 团队)进行了交谈,以了解他的团队在防止“数据宕机”和相关消防演习方面的更多信息。
PagerDuty 的数据前景
PagerDuty 的业务数据平台团队有一个明确的任务:随时随地为客户提供可信的数据,这些数据易于理解,并能实现高效的决策。
“其中最关键的部分是数据治理、数据质量、安全性和基础设施运营,”Manu 说。该团队的客户包括“几乎所有的部门,包括财务、行政、客户成功、工程、销售和营销。”
就他们的平台本身而言,DataDuty 团队用的是 page duty——“我们绝对要吃自己的狗粮”——还有数据仓储用的雪花,数据科学用的 Fivetran,Segment,Mulesoft,AWS,Databricks。
该团队最近还将他们的堆栈与 ML 驱动的 数据可观察性 集成在一起,使他们能够通过监控、跟踪和排除管道每个阶段的数据事件,全面了解数据系统的健康状况。
寻呼机工作中的数据挑战
像大多数 SaaS 公司一样,PagerDuty 使用大量 SaaS 云应用程序(想想 Salesforce、Marketo 和 Netsuite ),并吸收大量内部和第三方数据。结构化数据、非结构化数据、不同节奏的数据以及不同粒度的实时批处理数据都是 PagerDuty 整体数据生态系统的一部分。
DataDuty 团队的主要挑战是确保数据质量满足最终用户的期望,使他们能够基于准确的数据做出更快的决策。
Manu 表示:“业务的动态本质是推动数据挑战的原因。“业务数据需求每个季度都在不断变化,必须快速做出准确的决策。一切都是数据驱动的,所以我们必须保持敏捷。”
使用 DevOps 最佳实践来扩展数据事件管理
为了完成他们雄心勃勃的任务,DataDuty 团队对其数据管道实施了大量的 DevOps 事件管理最佳实践。
最佳实践#1:确保您的事件管理涵盖整个数据生命周期。
图片由 PagerDuty 提供。
在 PagerDuty,数据工程师的事件管理属于他们所谓的数据操作,这是 DevOps 的扩展。它包括对数据和管道问题的跟踪、响应和分类。
一旦数据进入仓库,一直到出现在面向客户的报告中,都有可能出现各种类型的数据宕机,从丢失数据到错误模型。DataDuty 团队监控数据质量问题,包括异常、新鲜度、模式更改、指标趋势等。
数据可观察性 对于监控和确保数据仓库中的数据质量尤为重要。您可以通过 ETL 工具进行定制的数据质量检查,在数据管道级别进行干预,但是随着时间的推移,管理逻辑、脚本和数据生态系统的其他元素会变得很麻烦。此外,正如 Manu 指出的,数据趋势的问题无法通过管道质量检查来识别。
最佳实践#2:事故管理应包括噪音抑制
图片由 PagerDuty 提供。
在实施数据监控和异常检测时,数据噪音是一个主要问题,在企业范围内,您每天都会收到各种各样的“警报”,其中许多警报表明您的数据发生了变化,但不一定是全新的“问题”数据团队需要能够在客户、企业所有者之间进行分类,并及时响应这些警报,同时对数据产品本身委派明确的所有权。
Manu 的 DataDuty 团队使用 PagerDuty 事件智能来识别类似的数据事件警报,抑制包含多个数据问题的一个事件的多个警报。这样,他的团队成员就不会被警报淹没,可以专注于修复手头数据问题 的 根本原因。
最佳实践#3:对数据资产和事件进行分组,以智能地发送警报
图片由作者提供。
Manu 表示,数据可观察性是任何数据事件管理步骤(包括事件响应和上报)发生之前的第一步。毕竟,与异常趋势或指标相比,“我的数据没有刷新”是一个完全不同的问题。团队需要能够识别这种数据问题随着时间的推移而存在。
当 DataDuty 团队开始在他们自己的数据平台上集成数据可观察性和 page duty时,他们遵循了 DataOps 的最佳实践,包括将数据问题分组在一起,以便基于 360 度视图实现更轻松的路由和警报,包括:
- 将类似的数据管道问题与数据可观察性组合在一起,并在此工作流之上实施 page duty,确保这些警报被正确发送给 DataDuty 团队。由于他们使用气流进行调度,团队也通过 PagerDuty 接收气流警报。
- 识别公司最关键的数据资产,包括管理层报告和财务报告层面的数据。现在,与这些资产相关的警报通过带有升级策略的 PagerDuty 发出,并自动发送给其他利益相关者和商业智能团队。
- 利用事件警报和可观察性来监控 BI 指标的运行状况,如客户数量、客户流失率、账户数量和数据事件数量。然后,这些警报被发送给商业智能团队,以便他们能够进行监控并根据需要采取措施。
凭借这些最佳实践,PagerDuty 的平台团队通过从 DevOps 的角度来处理数据事件管理,实现了他们的使命,这与数据可观察性的 原则 完全一致。
作为集成合作伙伴,我们的平台协同工作,帮助企业识别和解决数据事件,使领导者能够快速自信地做出数据驱动的决策。
好奇一些最优秀的团队是如何开创数据可观测性的?RSVP for IMPACT 2021!
百分比近似值的工作原理(以及为什么它比平均值更有用)
实践教程
初步了解百分位数近似值,为什么它们对分析大型时间序列数据集有用,以及我们如何创建百分位数近似值超函数来提高计算效率、可并行化,并与连续聚合和其他高级时标 DB 功能一起使用。
在我最近发表的关于时间加权平均的文章中,我描述了我早期的电化学职业生涯如何让我认识到时间加权平均的重要性,这塑造了我们如何将它们构建成时标超函数。几年前,在我开始学习更多关于 PostgreSQL 内部的知识后不久(查看我的聚合和两步聚合帖子来亲自了解它们!),我在一家广告分析公司做后端工作,在那里我开始使用 TimescaleDB。
像大多数公司一样,我们非常关心确保我们的网站和 API 调用在合理的时间内为用户返回结果;我们的分析数据库中有数十亿行数据,但我们仍然希望确保网站响应迅速且有用。
网站性能和商业结果之间有直接的关联:如果用户不得不等待太长时间才能得到结果,他们会感到厌烦,从商业和客户忠诚度的角度来看,这显然是不理想的。为了了解我们网站的表现并找到改进的方法,我们跟踪了 API 调用的时间,并将 API 调用响应时间作为一个关键指标。
监控 API 是一个常见的场景,通常属于应用程序性能监控(APM)的范畴,但是在其他领域也有很多类似的场景,包括:
- 工业机器的预测性维护
- 航运公司的船队监控
- 能源和水使用监控和异常检测
当然,分析原始(通常是时间序列)数据只能帮到你这么多。您希望分析趋势,了解您的系统相对于您和您的用户的期望表现如何,并在问题影响生产用户之前捕捉和修复问题,等等。我们构建了 TimescaleDB hyperfunctions 来帮助解决这个问题,并简化开发人员处理时序数据的方式。
作为参考,hyperfunctions 是一系列 SQL 函数,可以用更少的代码行更容易地操作和分析 PostgreSQL 中的时序数据。您可以使用超函数来计算数据的百分比近似值,计算时间加权平均值,缩减采样和平滑数据,并使用近似值执行更快的COUNT DISTINCT
查询。此外,超函数“易于”使用:您可以使用您熟悉和喜爱的相同 SQL 语法来调用超函数。
我们与社区成员交谈以了解他们的需求,我们的初始版本包括一些最常被请求的功能,包括百分点近似值(参见 GitHub 功能请求和讨论)。它们对于处理大型时间序列数据集非常有用,因为它们提供了使用百分位数(而不是平均值或其他计数统计数据)的好处,同时计算速度快、空间效率高、可并行化,并且对于连续聚合和其他高级 TimescaleDB 功能非常有用。
我从七年级数学中忘记的事情:百分位数与平均值
我可能在七年级的数学课上学到了平均值、中间值和众数,但是如果你和我一样,它们可能会周期性地迷失在“我曾经学过并认为我知道的东西,但实际上,我并不像我想象的那样记得很清楚。”
在我研究这篇文章的时候,我发现了一些很好的博客帖子(参见来自 Dynatrace 、 Elastic 、 AppSignal 和 Optimizely 的人们的例子),关于平均值对于理解应用程序性能或其他类似的事情来说并不太好,以及为什么使用百分位数更好。
我不会在这上面花太多时间,但我认为提供一点背景知识是很重要的,这是关于为什么和百分位数如何帮助我们更好地理解我们的数据。
首先,让我们考虑百分位数和平均值是如何定义的。为了理解这一点,我们先来看一个 正态分布 :
正态分布(或称高斯分布)描述了落在给定值附近的许多真实世界的过程,其中找到远离中心的值的概率降低。对于正态分布,中值、平均值和众数都是相同的,它们落在中心的虚线上。作者图片
正态分布是我们在思考统计时经常想到的;这是入门课程中最常用的方法之一。在正态分布中,中值、平均值(也称为均值)和众数都是相同的,尽管它们的定义不同。
中值是中间值,一半数据在上面,一半在下面。均值(又名平均值)定义为总和(值)/计数(值),而模式定义为最常见或最频繁出现的值。
当我们看到这样的曲线时,x 轴代表值,而 y 轴代表我们看到给定值的频率(即,y 轴上“较高”的值出现的频率更高)。
在正态分布中,我们看到一条以最频繁值为中心的曲线(虚线),随着距离最频繁值越远,看到值的概率越小(最频繁值是众数)。请注意,正态分布是对称的,这意味着中心左侧和右侧的值出现的概率相同。
中位数或中间值也称为第 50 个百分位数(100 个百分位数中的中间百分位数)。这是 50%的数据小于该值,50%大于该值(或等于该值)时的值。
在下图中,一半的数据在左边(蓝色阴影),另一半在右边(黄色阴影),第 50 个百分位直接在中间。
描述了中位数/第 50 百分位的正态分布。作者图片
这就引出了百分位数:百分位数被定义为 x %的数据低于该值的值。
例如,如果我们称之为“第 10 个百分位数”,我们的意思是 10%的数据小于该值,90%的数据大于(或等于)该值。
描述了第 10 百分位的正态分布。作者图片
第 90 个百分位数是 90%的数据小于数值,10%大于数值:
描绘了具有第 90 百分位的正态分布。作者图片
为了计算第 10 个百分位数,假设我们有 10,000 个值。我们取所有的值,从最小到最大排序,并确定第 1001 个值(其中 1000 或 10%的值低于它),这将是我们的第 10 个百分位数。
我们之前注意到,在正态分布中,中位数和平均数是相同的。这是因为正态分布是对称的。因此,值大于中值的点的大小和数量是完全平衡的(在大小和小于中值的点的数量上)。
换句话说,在中间值的两边总是有相同数量的点,但是平均值考虑了点的实际值。
为了使中值和平均值相等,小于中值的点和大于中值的点必须具有相同的分布(即,必须有相同数量的点稍微大一些、稍微小一些、大得多和小得多)。(**更正:**正如在黑客新闻中向我们指出的那样,从技术上来说,这仅适用于对称分布,不对称分布可能适用,也可能不适用,你可能会遇到不对称分布相等的奇怪情况,尽管可能性较小!)
**为什么这很重要?**正态分布中中位数和平均数相同的事实会造成一些混淆。因为正态分布通常是我们首先学习的东西之一,所以我们(包括我自己!)可以认为它适用于比实际更多的情况。
人们很容易忘记或没有意识到,只有中值保证 50%的值会在上面,50%在下面——而平均值保证 50%的加权值会在上面,50%在下面(即,平均值是质心,而中值是中心)。
在正态分布中,平均值和中值是相同的,它们将图形精确地分成两半。但是它们的计算方式不同,表示的内容也不同,在其他分布中也不一定相同。作者图片
🙏向在 Desmos 的人们大声欢呼,感谢他们伟大的图形计算器,它帮助制作了这些图形,甚至允许我制作这些概念的互动演示!
但是,为了脱离理论,让我们考虑一些现实世界中更常见的东西,比如我在广告分析公司工作时遇到的 API 响应时间场景。
长尾、异常值和真实效应:为什么百分位数比平均值更好地理解你的数据
我们看了平均值和百分位数的不同之处,现在,我们将使用一个真实的场景来演示使用平均值而不是百分位数是如何导致错误警报或错失机会的。
为什么?平均值并不总是给你足够的信息来区分真实的影响和异常值或噪音,而百分位数可以做得更好。
简而言之,使用平均值会对数值的报告方式产生巨大的(和负面的)影响,而百分位数可以帮助你更接近“真相”
如果您在查看类似 API 响应时间的东西,您可能会看到一个类似于下面这样的频率分布曲线:
API 响应时间的频率分布,峰值为 250 毫秒(所有图表未按比例绘制,仅用于演示目的)。作者图片
我以前在广告分析公司工作时,我们的目标是让大多数 API 响应调用在半秒内完成,很多比这短得多。当我们监控我们的 API 响应时间时,我们试图理解的最重要的事情之一是用户如何受到代码变化的影响。
我们的大多数 API 调用在半秒钟内完成,但是有些人使用系统在很长的时间内获得数据,或者有奇怪的配置,这意味着他们的仪表板响应速度有点慢(尽管我们试图确保这些情况很少发生!).
由此产生的曲线类型被描述为长尾分布,其中我们在 250 ms 处有一个相对较大的峰值,我们的许多值都在该峰值之下,然后响应时间以指数方式减少。
我们之前讨论过如何在对称曲线中(像正态分布),但是长尾分布是一个不对称曲线。
这意味着最大值比中间值大得多,而最小值与中间值相差不远。(在 API 监控的情况下,您永远也不会有响应时间少于 0 秒的 API 调用,但是它们可以花费的时间是没有限制的,所以您会得到较长 API 调用的长尾效应)。
因此,长尾分布的平均值和中值开始偏离:
标有中值和平均值的 API 响应时间频率曲线。图表未按比例绘制,仅用于演示目的。作者图片
在这种情况下,平均值明显大于中值,因为长尾理论中有足够多的“大”值使平均值更大。相反,在其他一些情况下,平均值可能小于中值。
但是在广告分析公司,我们发现平均值没有给我们足够的信息来区分我们的 API 如何响应软件变化的重要变化和只影响少数人的噪音/异常值。
在一个案例中,我们对有新查询的代码进行了修改。该查询在暂存中运行良好,但是在生产系统中有更多的数据。
一旦数据“热了”(在内存中),它就会运行得很快,但第一次运行时非常慢。当查询投入生产时,大约 10%的调用的响应时间超过了一秒。
在我们的频率曲线中,大约 10%的呼叫的响应时间超过 1 秒(但不到 10 秒),导致我们的频率曲线出现第二个较小的峰,如下所示:
频率曲线显示了当 10%的呼叫花费 1 到 10 秒之间的适度时间时发生的偏移和额外峰(图表仍未按比例绘制)。作者图片
在这种情况下,平均值变化很大,而中位数略有变化,但影响较小。
您可能认为这使得平均值比中值更好,因为它帮助我们识别问题(太长的 API 响应时间),并且我们可以设置我们的警报,以便在平均值变化时发出通知。
让我们想象一下,我们已经做到了这一点,当平均值超过 1 秒时,人们就会采取行动。
但是现在,我们有一些用户开始从我们的用户界面请求 15 年的数据…这些 API 调用需要很长时间。这是因为 API 并不是真正为处理这种“标签外”使用而构建的。
这些用户打来的几个电话就轻松地让平均时间超过了我们的 1s 阈值。
为什么?平均值(作为一个值)可能会受到像这样的异常值的显著影响,即使它们只影响一小部分用户。平均值使用数据的总和,因此异常值的大小会产生巨大的影响,而中位数和其他百分位数则基于数据的排序。
我们的曲线有一些异常值,其中不到 1%的 API 调用响应超过 100 秒(响应时间有一个断点,表示异常值会偏右,否则,该图仍未按比例绘制)。作者图片
关键是,平均值并没有给我们一个区分异常值和真实影响的好方法,当我们有长尾或非对称分布时,它会给出奇怪的结果。
为什么理解这一点很重要?
好吧,在第一个案例中,我们有一个问题影响了 10%的 API 调用,这可能是 10%或更多的用户(它怎么可能影响超过 10%的用户呢?嗯,如果一个用户平均进行 10 次调用,10%的 API 调用受到影响,那么,平均来说,所有用户都会受到影响…或者至少大部分用户会受到影响。
我们希望对这种影响大量用户的紧急问题做出快速响应。我们建立了警报,甚至可能让我们的工程师在半夜起床和/或回复一个更改。
但是在第二种情况下,“标签外”用户行为或小错误对一些 API 调用有很大影响,这种情况要好得多。因为受这些异常值影响的用户相对较少,所以我们不想让我们的工程师在半夜起床或者恢复一个更改。(识别和理解离群值仍然很重要,无论是对于理解用户需求还是代码中的潜在错误,但是它们通常不是紧急事件。
除了使用平均值,我们可以使用多个百分点来理解这种类型的行为。请记住,与平均值不同,百分位数依赖于数据的排序,而不是受数据的大小的影响。如果我们使用第 90 百分位,我们知道10%的用户的值(在我们的例子中是 API 响应时间)大于它。
让我们看看原始图表中的第 90 个百分位数;它很好地捕捉了一些长尾行为:
我们最初的 API 响应时间图显示了第 90 个百分点、中间值和平均值。图未按比例绘制。作者图片
当我们有一些由运行超长查询的少数用户或影响一小组查询的 bug 引起的异常值时,平均值会发生变化,但第 90 个百分点几乎不受影响。
异常值影响平均值,但不影响第 90 百分位或中位数。(图未按比例绘制。)作者图片
但是,当尾部由于影响 10%用户的问题而增加时,我们看到第 90 个百分位非常显著地向外移动——这使得我们的团队能够得到通知并做出适当的响应:
但是,当有“真正的”影响超过 10%用户的响应时,第 90 个百分位会发生显著变化(图未按比例绘制。)图片由作者提供。
这(希望)让您更好地了解百分位数如何以及为什么可以帮助您识别大量用户受到影响的情况——但不会给您带来误报的负担,误报可能会唤醒工程师并让他们感到疲劳!
那么,现在我们知道了为什么我们可能想要使用百分位数而不是平均值,让我们来谈谈我们是如何计算它们的。
PostgreSQL 中百分点的工作原理
为了计算任何一种精确的百分位数,你取所有你的值,对它们进行排序,然后根据你试图计算的百分位数找到第 n 个值。
为了了解这在 PostgreSQL 中是如何工作的,我们将展示我们广告分析公司的 API 跟踪的一个简化案例。
我们将从这样一个表格开始:
CREATE TABLE responses(
ts timestamptz,
response_time DOUBLE PRECISION);
在 PostgreSQL 中,我们可以使用[percentile_disc](https://www.postgresql.org/docs/current/functions-aggregate.html#FUNCTIONS-ORDEREDSET-TABLE)
聚合来计算列response_time
的百分比:
SELECT
percentile_disc(0.5) WITHIN GROUP (ORDER BY response_time) as median
FROM responses;
这看起来和普通的聚合不一样;WITHIN GROUP (ORDER BY ...)
是一种不同的语法,它作用于称为有序集聚合的特殊聚合。
在这里,我们将我们想要的百分位数(0.5 或中位数的第 50 个百分位数)传递给percentile_disc
函数,我们要评估的列(response_time
)放在 order by 子句中。
当我们了解了引擎盖下发生的事情后,就会更清楚为什么会发生这种情况。百分位数保证 x %的数据将低于它们返回的值。为了计算这个值,我们需要对一个列表中的所有数据进行排序,然后挑选出 50%的数据低于这个值,50%的数据高于这个值。
对于那些读过我们上一篇文章中关于 PostgreSQL 聚合如何工作的部分的人来说,我们讨论了像 T5 这样的聚合是如何工作的。
当它扫描每一行时,转换函数更新一些内部状态(对于avg
,它是sum
和count
,然后一个最终函数处理内部状态以产生一个结果(对于avg
,将sum
除以count
)。
一个 GIF 展示了如何在 PostgreSQL 中计算 avg,其中 sum 和 count 是处理行时的部分状态,而 final 函数在我们完成后将它们相除。作者 GIF。
有序集合聚合,如percentile_disc
,工作方式有些类似,但有一点例外:状态不是一个相对较小的固定大小的数据结构(如sum
和count
代表avg
,它必须保留所有已处理的值,以便对它们进行排序并在以后计算百分位数。
通常,PostgreSQL 通过将值放入一个名为[tuplestore](https://github.com/postgres/postgres/blob/c30f54ad732ca5c8762bb68bbe0f51de9137dd72/src/backend/utils/sort/tuplestore.c)
的数据结构中来实现这一点,该数据结构很容易存储和排序值。
然后,当调用最后一个函数时,tuplestore
将首先对数据进行排序。然后,根据输入到percentile_disc
中的值,它将遍历排序数据中的正确点(中值数据的 0.5 倍)并输出结果。
使用“percentile_disc”有序集合聚合,PostgreSQL 必须将它看到的每个值存储在一个“tuplestore”中,然后当它处理完所有行时,对它们进行排序,然后转到排序列表中的正确位置提取我们需要的百分位数。
许多人发现,近似百分位数计算可以提供“足够接近”的近似值,而不需要在非常大的数据集上执行这些昂贵的计算**…这就是我们引入百分位数近似超函数的原因。**
百分位数近似值:它是什么以及为什么我们在时标超函数中使用它
根据我的经验,人们经常使用平均值和其他汇总统计数据,而不是百分位数,因为它们在大型数据集上的计算在计算资源和时间上都明显“便宜”。
正如我们上面提到的,在 PostgreSQL 中计算平均值有一个简单的二值聚合状态。即使我们计算一些额外的相关函数,如标准差,我们仍然只需要少量固定的值来计算函数。
相反,为了计算百分比,我们需要一个排序列表中的所有输入值。
这导致了一些问题:
- 内存占用:算法必须将这些值保存在某个地方,这意味着将值保存在内存中,直到它们需要将一些数据写入磁盘,以避免使用过多的内存(这就是所谓的“溢出到磁盘”)。这会产生很大的内存负担和/或大大降低操作速度,因为磁盘访问比内存慢几个数量级。
- 并行化带来的有限好处:即使算法可以并行排序列表,并行化带来的好处也是有限的,因为它仍然需要将所有排序列表合并成一个单独的排序列表,以便计算百分位数。
- **高网络成本:**在分布式系统中(比如 TimescaleDB 多节点),所有的值都必须通过网络传递到一个节点,才能做成一个单一的排序列表,速度慢,成本高。
- 没有真正的部分状态:部分状态的具体化(例如,对于连续的聚集)是没有用的,因为部分状态仅仅是它下面的所有值。这可以节省列表排序的时间,但是存储负担会很高,回报会很低。
- 无流式算法:对于流式数据,这是完全不可行的。您仍然需要维护完整的值列表(类似于上面的部分状态具体化问题),这意味着算法本质上需要存储整个流!
当您处理相对较小的数据集时,所有这些都是可以管理的,而对于大容量、时序工作负载,它们开始变得更成问题。
但是,如果您想要 精确的 百分位,您只需要完整的值列表来计算百分位。对于相对较大的数据集,您通常可以接受一些准确性折衷,以避免遇到这些问题。
上述问题,以及对权衡是使用平均值还是百分位数的权衡的认识,导致了多种算法的发展,以在大容量系统中近似百分位数。大多数百分位数近似方法涉及某种修改的直方图以更紧凑地表示数据的整体形状,同时仍然捕捉分布的大部分形状。
在设计超功能时,我们考虑了如何获得百分位数的好处(例如,对异常值的稳健性,与现实世界影响的更好对应性),同时避免计算精确百分位数带来的一些缺陷(如上)。
百分位数近似值似乎非常适合处理大型时间序列数据集。
结果是一整个家族的百分位近似超函数,内置于时标 DB 中。调用它们最简单的方法是使用[percentile_agg](https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/percentile_agg/)
集合和 https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/approx_percentile/ [approx_percentile](https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/approx_percentile/)
访问器。
此查询计算大约第 10、50 和 90 个百分点:
SELECT
approx_percentile(0.1, percentile_agg(response_time)) as p10,
approx_percentile(0.5, percentile_agg(response_time)) as p50,
approx_percentile(0.9, percentile_agg(response_time)) as p90
FROM responses;
(如果您想了解更多关于聚合、访问器和两步聚合设计模式的信息,请查看我们的 PostgreSQL 两步聚合入门书。)
与正常的 PostgreSQL 精确百分位数相比,这些百分位数近似值有许多好处,尤其是在用于大型数据集时。
内存占用
当计算大型数据集的百分位数时,我们的百分位数近似值限制了内存占用(或者需要溢出到磁盘,如上所述)。
标准百分位数会产生内存压力,因为它们会在内存中建立尽可能多的数据集…然后在被迫溢出到磁盘时会变慢。
相反,超函数的百分位数近似值基于其修改后的直方图中的存储桶数量具有固定的大小表示,因此它们限制了计算它们所需的内存量。
单节点和多节点时标并行化 b
我们所有的百分位数近似算法都是可并行化的,因此它们可以在单个节点中使用多个工人来计算;这可以提供显著的加速,因为像percentile_disc
这样的有序集合聚合在 PostgreSQL 中是不可并行化的。
并行性为单节点时标数据库设置提供了加速——这在多节点时标数据库设置中更加明显。
为什么?要使用percentile_disc
有序集聚合计算多节点 TimescaleDB 中的百分比(不使用近似超函数的标准方法),必须将每个值从数据节点发送回访问节点,对数据进行排序,然后提供输出。
在 TimescaleDB 多节点中计算精确的百分比时,每个数据节点必须将所有数据发送回访问节点。接入节点然后排序并计算百分位数。图片作者。
“标准”方式的成本非常非常高,因为所有的数据都需要通过网络从每个数据节点发送到接入节点,这又慢又贵。
即使在访问节点获得数据之后,它仍然需要在将结果返回给用户之前对所有数据进行排序和计算百分比。(注意:有可能每个数据节点可以单独排序,而访问节点只执行合并排序。但是,这不会否定通过网络发送所有数据的需要,这是最昂贵的步骤。)
通过近似百分位超函数,更多的工作可以下推到数据节点。可以在每个数据节点上计算部分近似百分位数,并通过网络返回固定大小的数据结构。
一旦每个数据节点计算了它的部分数据结构,访问节点就组合这些结构,计算近似百分位数,并将结果返回给用户。
这意味着可以在数据节点上完成更多的工作,最重要的是,通过网络传输的数据要少得多。对于大型数据集,这可以大大减少在这些计算上花费的时间。
使用我们的百分位数近似超函数,数据节点不再需要将所有数据发送回接入节点。取而代之的是,它们计算一个部分近似值,并将其发送回接入节点,然后接入节点将部分近似值合并,并产生一个结果。这节省了大量网络调用时间,因为它在数据节点上并行执行计算,而不是在访问节点上执行大量工作。图片作者。
连续集合体的物化
TimescaleDB 包括一个名为连续聚合的特性,旨在使大型数据集上的查询运行得更快。
TimescaleDB continuous 聚合在后台连续并增量地存储聚合查询的结果,因此当您运行该查询时,只需要计算已更改的数据,而不是整个数据集。
不幸的是,使用percentile_disc
的精确百分位数不能存储在连续的聚合中,因为它们不能分解成部分形式,而是需要在聚合中存储整个数据集。
我们设计的百分位数近似算法可用于连续聚合。它们具有固定大小的部分表示,可以在连续聚合中存储和重新聚合。
与精确百分位数相比,这是一个巨大的优势,因为现在您可以在更长的时间内进行基线和警报等操作,而不必每次都从头开始重新计算。
让我们回到 API 响应时间的例子,假设我们想要识别最近的异常值来调查潜在的问题。
一种方法是查看前一小时高于 99%的所有数据。
提醒一下,我们有一张表:
CREATE TABLE responses(
ts timestamptz,
response_time DOUBLE PRECISION);
SELECT create_hypertable('responses', 'ts'); -- make it a hypertable so we can make continuous aggs
首先,我们将创建一个一小时的聚合:
CREATE MATERIALIZED VIEW responses_1h_agg
WITH (timescaledb.continuous)
AS SELECT
time_bucket('1 hour'::interval, ts) as bucket,
percentile_agg(response_time)
FROM responses
GROUP BY time_bucket('1 hour'::interval, ts);
注意,我们不在连续聚合中执行访问器函数;我们只是执行聚合功能。
现在,我们可以找到最近 30 秒内大于第 99 百分位的数据,如下所示:
SELECT * FROM responses
WHERE ts >= now()-'30s'::interval
AND response_time > (
SELECT approx_percentile(0.99, percentile_agg)
FROM responses_1h_agg
WHERE bucket = time_bucket('1 hour'::interval, now()-'1 hour'::interval)
);
在广告分析公司,我们有很多用户,所以我们每小时会有成千上万的 API 调用。
默认情况下,我们的表示中有 200 个桶,因此通过使用连续聚合,我们可以大大减少存储和处理的数据量。这意味着它将大大加快响应时间。如果没有足够多的数据,您会希望增加存储桶的大小或降低近似的保真度,以大幅减少我们必须处理的数据。
我们提到,我们只在连续聚合视图定义中执行了聚合步骤;我们没有在视图中直接使用我们的approx_percentile
访问函数。我们这样做是因为我们希望能够使用其他访问器函数和/或[rollup](https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/rollup-percentile/)
函数,您可能还记得这是我们选择两步聚合方法的主要原因之一。
让我们来看看这是如何工作的,我们可以创建一个每日汇总,并得到第 99 个百分位数,如下所示:
SELECT
time_bucket('1 day', bucket),
approx_percentile(0.99, rollup(percentile_agg)) as p_99_daily
FROM responses_1h_agg
GROUP BY 1;
我们甚至可以使用[approx_percentile_rank](https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/approx_percentile_rank/)
访问函数,它会告诉您一个值将落入哪个百分点。
百分位数排名是百分位数函数的倒数;换句话说,如果你问,第 n 百分位的值是多少?答案是一个值。
对于百分位等级,您会问这个值会在哪个百分位?答案是百分位数。
因此,使用approx_percentile_rank
可以让我们看到最近 5 分钟到达的值与前一天的值相比排名如何:
WITH last_day as (SELECT time_bucket('1 day', bucket),
rollup(percentile_agg) as pct_daily
FROM foo_1h_agg
WHERE bucket >= time_bucket('1 day', now()-'1 day'::interval)
GROUP BY 1)
SELECT approx_percentile_rank(response_time, pct_daily) as pct_rank_in_day
FROM responses, last_day
WHERE foo.ts >= now()-'5 minutes'::interval;
这是连续聚合有价值的另一种方式。
我们在一天内执行了一次rollup
,它只是结合了 24 个部分状态,而不是对 24 小时的数据和数百万个数据点执行完整的计算。
然后,我们使用rollup
来查看它如何影响最后几分钟的数据,让我们了解最后几分钟与过去 24 小时相比的情况。这些只是一些例子,说明百分位数近似超函数如何给我们一些漂亮的结果,让我们相对简单地进行复杂的分析。
百分位数逼近深度探讨:逼近方法,它们如何工作,以及如何选择
你们中的一些人可能想知道 TimescaleDB hyperfunctions 的底层算法是如何工作的,所以让我们开始吧!(对于那些不想进入杂草中的人,可以跳过这一点。)
近似方法及其工作原理
我们实现了两种不同的百分位数近似算法作为时标 DB 超函数: UDDSketch 和 T-Digest 。每一个在不同的场景中都是有用的,但是首先,让我们了解它们是如何工作的一些基础知识。
两者都使用修正的直方图来近似分布的形状。直方图将附近的值分成一组,并跟踪它们的频率。
您经常会看到这样绘制的直方图:
直方图表示与上面的响应时间频率曲线相同的数据,您可以看到图形的形状与频率曲线是如何相似的。不按比例。图片作者。
如果您将它与我们上面展示的频率曲线进行比较,您可以看到它如何提供 API 响应时间与频率响应的合理近似值。从本质上来说,直方图有一系列的存储桶边界和落入每个存储桶的值的数量。
要计算大约百分位数,比如说第 20 个百分位数,首先要考虑代表它的总数据的分数。对于我们的第 20 百分位,这将是 0.2 * total_points
。
一旦有了这个值,就可以从左到右对每个桶中的频率进行求和,找出哪个桶的值最接近 0.2 * total_points
。
当存储桶跨越感兴趣的百分比时,您甚至可以在存储桶之间进行插值,以获得更精确的近似值。
当您想到直方图时,您可能会想到类似上面的直方图,其中所有的桶都是相同的宽度。
但是选择存储桶宽度,特别是对于变化很大的数据,会变得非常困难,或者会导致存储大量额外的数据。
在我们的 API 响应时间示例中,我们可以拥有从几十毫秒到十秒或数百秒的数据。
这意味着第 1 百分位的良好近似(例如 2 毫秒)的正确桶大小将比第 99 百分位的良好近似所需的小得多。
这就是为什么大多数百分点近似算法使用带有可变桶宽的修正直方图。
例如,UDDSketch 算法使用对数大小的桶,可能如下所示:
修改后的直方图显示了像 UDDSketch 算法使用的对数存储桶仍然可以表示数据。(注意:我们需要修改图来绘制频率/桶宽,以便比例保持相似;然而,这仅用于演示目的,并未按比例绘制)。图片作者。
UDDSketch 的设计者使用了这样的对数桶大小,因为他们关心的是相对误差。
作为参考,绝对误差定义为实际值与近似值之差:
图片作者。
要获得相对误差,将绝对误差除以以下值:
图片作者。
如果我们有一个恒定的绝对误差,我们可能会遇到如下情况:
我们要求第 99 百分位,算法告诉我们是 10 秒+/-100 毫秒。然后,我们要求第 1 个百分位数,算法告诉我们是 10ms +/- 100ms。
第一百分位的误差太高了!
如果我们有一个恒定的相对误差,那么我们会得到 10ms +/- 100 微秒。
这要有用得多。(10s +/- 100 微秒可能太紧了,如果我们已经达到 10s,我们可能真的不在乎 100 微秒。)
这就是 UDDSketch 算法使用对数大小的桶的原因,其中桶的宽度与底层数据的大小成比例。这允许算法在整个百分点范围内提供恒定的相对误差。
因此,您总是知道百分位数的真实值将落在某个范围[v_approx *(1-err), v_approx * (1+err)]
内。
另一方面,T-Digest 使用大小可变的存储桶,这取决于它们在分布中的位置。具体来说,它在分布的两端使用较小的桶,在中间使用较大的桶。
因此,它可能看起来像这样:
修改后的直方图显示了在极端情况下较小的可变大小存储桶(如 TDigest 算法所使用的存储桶)仍然可以表示数据(注意:出于说明目的,未按比例绘制。)图片由作者提供。
这种具有可变大小桶的直方图结构针对不同于 UDDSketch 的东西进行了优化。具体来说,它利用了这样一个想法:当你试图理解分布时,你可能更关心极值之间的细微差别,而不是范围的中间值。
例如,我通常非常关心区分第 5 百分位和第 1 百分位或者第 95 百分位和第 99 百分位,而我不太关心区分第 50 百分位和第 55 百分位。
中间的区别不如极端的区别有意义和有趣。(注意:TDigest 算法比这个要复杂一点,它没有完全捕捉到它的行为,但是我们试图给出一个大概的要点。如果你想了解更多信息,我们推荐这篇论文。
在时标超函数中使用高级近似方法
到目前为止,在这篇文章中,我们只使用了通用的percentile_agg
集合。它使用 UDDSketch 算法,对于大多数用户来说是一个很好的起点。
我们还提供了单独的[uddsketch](https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/percentile-aggregation-methods/uddsketch/)
和[tdigest](https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/percentile-aggregation-methods/tdigest/)
以及聚合,以实现更多的可定制性。
每个都将桶的数量作为它们的第一个参数(这决定了内部数据结构的大小),并且uddsketch
也有一个关于目标最大相对误差的参数。
我们可以使用正常的approx_percentile
访问函数,就像我们使用percentile_agg
一样,因此,我们可以像这样比较中值估计:
SELECT
approx_percentile(0.5, uddsketch(200, 0.001, response_time)) as median_udd,
approx_percentile(0.5, tdigest(200, response_time)) as median_tdig
FROM responses;
他们两个也和我们上面讨论的approx_percentile_rank
机能亢进一起工作。
如果我们想知道 1000 在我们的分布中会落在哪里,我们可以这样做:
SELECT
approx_percentile_rank(1000, uddsketch(200, 0.001, response_time)) as rnk_udd,
approx_percentile_rank(1000, tdigest(200, response_time)) as rnk_tdig
FROM responses;
此外,每个近似都有一些访问器,这些访问器只对基于近似结构的项起作用。
例如,uddsketch
提供了一个error
访问器函数。这将告诉您基于uddsketch
看到的值的实际保证最大相对误差。
UDDSketch 算法保证最大相对误差,而 T-Digest 算法不保证,所以error
只和uddsketch
一起工作(和percentile_agg
因为它在引擎盖下使用了uddsketch
算法)。
这个误差保证是我们选择它作为缺省值的主要原因之一,因为误差保证对于确定你是否得到一个好的近似是有用的。
另一方面,Tdigest
提供了min_val
& max_val
访问器函数,因为它将其存储桶偏向极端,并且可以提供精确的最小值和最大值,而不需要额外的成本。Uddsketch
无法提供。
您可以像这样调用这些其他的访问器:
SELECT
approx_percentile(0.5, uddsketch(200, 0.001, response_time)) as median_udd,
error(uddsketch(200, 0.001, response_time)) as error_udd,
approx_percentile(0.5, tdigest(200, response_time)) as median_tdig,
min_val(tdigest(200, response_time)) as min,
max_val(tdigest(200, response_time)) as max
FROM responses;
正如我们在上一篇关于两步聚合的帖子中所讨论的,对所有这些聚合的调用都会被 PostgreSQL 自动删除重复数据并进行优化,因此您可以用最少的额外成本调用多个访问器。
它们都有为它们定义的[rollup](https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/rollup-percentile/)
函数,所以当它们用于连续聚合或常规查询时,您可以重新聚合。
(注意:tdigest
rollup 与直接在底层数据上调用tdigest
相比,会引入一些额外的错误或差异。在大多数情况下,这可以忽略不计,通常相当于更改底层数据的接收顺序。)
我们在这里提供了算法之间的一些权衡和差异,但是我们在文档中有一个更长的讨论,可以帮助你选择。您也可以从默认的percentile_agg
开始,然后在您的数据上试验不同的算法和参数,看看什么最适合您的应用。
包装它
我们简要概述了百分位数,它们如何比更常见的统计总量(如平均值)提供更多信息,为什么存在百分位数近似值,以及它们通常如何工作以及在时间范围内如何超函数。
如果您想立即开始使用https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/?utm_source=tds&utm_medium=blog&utm_campaign=hyperfunctions-1-0-2021&utm_content=docs-percentile-approx****—以及更多功能,请创建一个完全托管的时标服务**:创建一个账户免费试用 30 天。(Hyperfunctions 预装在每个新的数据库服务中,所以在你创建一个新的服务后,你就可以使用它们了)。**
如果您喜欢管理自己的数据库实例,您可以 下载并在 GitHub 上安装 [**timescaledb_toolkit**](https://github.com/timescale/timescaledb-toolkit)
扩展 ,之后您将能够使用百分点近似值和其他超函数。
我们相信时间序列数据无处不在,理解它对于各种技术问题都至关重要。我们构建了超函数,让开发人员更容易利用时序数据的力量。
我们一直在寻找关于下一步构建什么的反馈,并且很想知道您如何使用超函数、您想要解决的问题,或者您认为应该或者可以简化的事情,以便更好地分析 SQL 中的时序数据。(要提供反馈,请在 GitHub 的未决问题或讨论主题中发表评论。)
原载于 2021 年 9 月 14 日https://blog.timescale.com。**