TowardsDataScience-博客中文翻译-2022-五十-

TowardsDataScience 博客中文翻译 2022(五十)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

初创公司创始人的现代数据堆栈指南

原文:https://towardsdatascience.com/the-startup-founders-guide-to-the-modern-data-stack-e972c8d89023

需要 分析 虽然像谷歌分析这样的无代码解决方案会让你走得很远,但在你的首轮投资中,你会意识到有太多的问题你无法回答,你会开始谷歌“如何正确设置分析”来偷工减料解决方案。你将游过企业、全方位承诺的海洋,差点被拉进去。但是在这次搜索中,你可能会听到希望之乡的低语:现代数据堆栈。

不幸的是,栈是什么是模糊的,你可能会遇到更多的思想领导而不是解决方案。因为尽管现代数据堆栈兜售的东西令人信服——为你的组织建立分析的正确方式——但工具很少被列举,主要是因为形势仍在变化,没有人真正知道。

但在这种不确定性中,你仍然有工作要做,你需要明确的方向。

这篇文章是来帮助你的。接下来,我会告诉你:

  1. 对现代数据堆栈的温和介绍,让您可以尽情享受
  2. 工具建议,帮助您快速设置可扩展分析。

在我们开始之前,声明:在这场比赛中,我确实有一匹 ,所以如果你在寻找偏见,它将被定位到 Hyperquery 的提及。但除此之外,这是我在花了一年时间设置和使用下面列出的每一个工具后测量的空间。

什么是现代数据堆栈,为什么要关注它?

在过去十年中,数据空间经历了大规模的重构。特别是,云数据仓库彻底改变了企业数据的处理方式,降低了存储成本,加快了访问速度,实现了云优先。他们改写了数据的经济学,在此过程中,他们也改写了行为——我们如何看待存储、基础设施和数据访问,产生了许多利用这些变化的工具,不仅改变了数据的存储方式,也改变了随后收购使用的方式。

从本质上来说,“现代数据堆栈”是一个模糊的名称,指的是在数据空间中实现这种重构的工具类别。你为什么要在乎?因为这些工具使得获取和使用高质量数据变得比以往更容易、更便宜、更快捷。它们也倾向于可组合,这意味着您将能够比坚持使用完整的端到端捆绑解决方案更容易地更换供应商。

这在实践中是什么样子

虽然术语“现代数据堆栈”经常被用来(在我看来是错误的)笼统地指代所有现代数据工具,但在我看来,有 4 个关键过程已经成为现代数据堆栈中不可改变的原子元素:获取数据、存储数据、转换数据和分析数据

现代数据堆栈的核心组件。(图片由作者提供)

让我们来讨论一下这些步骤和工具,我个人认为它们在这些领域最有前途,特别是对于初创公司和扩大规模的公司:

🪓正在获取数据

用于 ETL 的 Airbyte 或 Hevo 两者都不会花费你任何成本。如果您正在寻找一个托管解决方案, Hevo 非常棒,您将能够在一个地方完成 ETL、业务前逻辑转换和反向 ETL。如果你相信自己能做一些基本的基础设施设置,Airbyte 是一个很好的开源解决方案。因为它管理的是管道而不是存储,这里的中断在最坏的情况下会导致管道中断,但可能不会丢失数据——这是早期阶段可以接受的风险。如果你在寻找一些晦涩难懂的东西(但仍然保养良好),那么 便携 就太棒了。

为事件跟踪也弄点东西。我们选择了细分市场,但我的主要问题是广告拦截器太容易识别细分市场事件跟踪,所以你可能会错过一半用户的事件。不知道鲜为人知的工具有多好,但可能值得一试。或者,您可以通过 API 调用来跟踪事件,但我不是工程师,所以这可能是一个可怕的长期想法。这里可能有更好的解决方案,所以我不会给出任何真正的建议。

📦存储数据(仓库)

如果你想以低廉的价格起步,那就去 BigQuery 吧(尤其是如果你是一家初创公司,你可以获得大量的 GCP 积分)。如果你想以后成本透明,去雪花。不要红移,否则你会讨厌管理基础架构,只有当你真的需要东西变得如此无结构而不是因为你懒惰时,才使用数据湖。您也可以只读取您的实时 Postgres 实例的副本,但要知道您必须稍后迁移所有内容,并且您可能会遇到 Postgres 兼容性的红移 b/c。我也听说过微软堆栈的伟大之处,但是我没有尝试过。

🪚转换数据

您是否曾经编写一个 SQL 转换来回答一个问题,然后一遍又一遍地编写它?然后你制造一个你总是忘记的观点。dbt 是在普通 SQL 中对这些转换进行版本控制和调度的地方,因此您可以更好地https://en.wikipedia.org/wiki/Don't_repeat_yourself。在这个阶段,不要担心研究其他选择——实际上没有任何选择。dbt 拥有最活跃的社区,最活跃的开发,并且是开源的(完全免费)。不要搞砸了,而是做一些事情,如建立一百万个漂亮的 PDT。

📕分析数据

  • ❤️超查询 ,可注释,深注释,十六进制,模式(数据工作区)
  • 元数据库、超集、Tableau、Google Data Studio、Power BI(仪表板)

在早期阶段,您不需要单独的工具来执行仪表板、SQL munging、您的报告构建和文档编制:您需要一个单一的工作空间来分析+可视化 SQL 中的数据,然后随后记录、共享和集中调查结果—Hyperquery非常适合于此。这是一个支持查询的文档工作区,您可以在其中完成所有基本的问题回答和探索,而不必处理数百万个无上下文的仪表板或 IDE 选项卡。你也不应该用 Python 做事情,直到你在 SQL 中做了你能做的一切,因为过早地将 Python 设定为标准将会为你的组织树立一个 的糟糕先例

对于所有这些工具,我要说的是,实际上现在不要去自托管开源解决方案。你不希望红外线坏了,丢失你所有的工作。

🪜[可选]操作化数据(反向 ETL)

  • 人口普查小组

你可能不需要马上使用它,但是反向 ETL 允许你将你的仓库数据传输到其他工具,比如 Salesforce、Intercom,甚至是 conception,所以它可以增强操作工作。high touch在这个空间有更多的连接器。人口普查也很可靠。或者如果你是混乱邪恶的话两者都用。**

最终意见

批评者可能会感叹,我对现代数据堆栈的范围限制得太多了,但这一切背后的粗体星号是,这是为了让您开始,而不是为您的所有数据问题提供一些最简单的解决方案。当然,考虑一下度量 监控,特别是当事情扩展和中断时。但是你需要有数据,它才可能是错的。从上面开始——它会让你完成 95%的工作,一个人可以在几天内完成所有工作。

我是 Robert,我是 Hyperquery 的首席产品官,我们正在打造一种新的文档,将笔记、查询和数据整合到一个统一、有序的空间中。我们最近进入公测,直接在hyperquery . ai报名吧。(如果你有兴趣帮助我们建设,我们正在招聘——查看我们的 空缺职位 。)

推文@ imrobertyi/@ hyperquery来问好。👋
关注我们LinkedIn。🙂

自助背后的统计魔法

原文:https://towardsdatascience.com/the-statistical-magic-behind-the-bootstrap-2188ee147423

如何使用 bootstrap 进行测试或置信区间,以及它为什么有效

Artem Maltsev 在 Unsplash 上拍摄的照片

经常有人声称,人工智能、数据科学和机器学习都只是美化了的统计学。虽然这可能走得太远了,但数据科学家无疑从统计学中借鉴了许多有用的工具。但是有一个非常有用的工具被广泛忽视了——T4 自举。Bootstrap 是一种算法,允许您在不做任何理论的情况下确定测试统计的分布。

统计推断提供了描述从数据中可以合理得出哪些结论的数学理论。

在数据科学中,统计推断通常出现在 A/B 测试中,或者当模型用于分析时。非统计学家在测试和推断时经常会遇到困难。公平地说,我(作为一名统计学家)有时也很纠结。

当我们在实践中必须做一个测试时,我们定义我们想要测试的假设,并且很可能开始搜索以找出正确的测试统计和分布来使用。如果我们有很多数据,这通常不是问题——特别是如果我们想测试一些简单的东西,如关于 A/B 测试结果均值的假设或线性回归模型中的系数。然后一个好的老 t-test 就可以了。

但是如果数据集很小,根本不是正态分布呢?各个测试的所有假设都实现了吗?如果我们要测试的假设是模型中特征的非线性函数,该怎么办?或者如果我们要检验一个关于测试中测得的两个 KPI 之比的假设?统计很快变得非常复杂。这就是引导程序发挥作用的地方。

Left :我们要测试期望值是否为零的样本的直方图。右侧:从与左侧样本相同的分布模拟的样本的 t 统计量的模拟分布,叠加了正常密度。图片作者。

在上图中,我们可以看到一个普通 t 检验达到极限的例子。左侧样本中的 50 个观察值来自指数分布,平方后居中。在右边,我们可以看到,如果我们想对样本来自零均值分布的(真)零假设使用 t 检验,会发生什么。直方图显示了如果对以相同方式构建的 5000 个模拟实例实际计算测试统计量时所获得的分布。叠加密度是 t 检验的渐近正态分布的密度。

显然,在这种情况下,正态分布是对真实分布的一个非常糟糕的近似。因此,如果我们在这种情况下使用正常的 t 检验,我们得出的结论将是不正确的。

引导程序如何工作

Bootstrap 允许确定统计数据 T 的分布——例如 A/B 测试中的点击率(CTR)——通过类似于模拟的过程非常容易。该过程如下:

  1. 从您的数据中抽取一个与您的数据大小相同的样本。使用替换进行绘制,这样一些原始数据点可能会丢失,一些数据点可能会多次出现在样本中。这个样本被称为引导样本
  2. 根据 bootstrap 样本计算您感兴趣的数量 T* 并保存结果。
  3. 重复前面两步 m 次。
  4. 使用前面步骤中保存的值 T₁,…,T 来计算您感兴趣的分布的属性,无论是 p 值还是置信区间的分位数。

就这些了。它的效果出奇的好——通常在相对较小的样本中也是如此。这可能需要一些计算,但在许多应用程序中,这不是一个障碍,因为数据集足够小。这是统计魔术!

顶部:叠加经验累积分布函数的原始样本。底部:引导样本的两个例子。图片由作者提供。

为了计算抽样统计数据的置信区间,可以简单地利用观察到的 T₁,…,T 分布的相应分位数。

对于假设检验,必须要小心一点,因为 bootstrap 统计数据 T* 是以原始样本的统计数据 T 为中心的,而不是以检验统计数据的期望值为中心的。数学上,我们写 E[T*ₘ]=T ≠ E[T] 。因此,如果我们想要测试 T 是否显著不同于零,临界值或 p 值必须从 T*ₘ-T 的分布中导出。

上例中 t 统计量的分布与渐近正态分布和 bootstrap 分布的比较。图片由作者提供。

上图比较了使用 Bootstrap 获得的检验统计分布与实际模拟分布和正态分布。很明显,自举分布更接近真实分布。

理解 Bootstrap 需要知道什么

当我第一次了解 Bootstrap 时,我学习了如何执行上述步骤。但是我真的很困扰,我不知道为什么这个魔法会起作用。从一个样本中提取新样本对我来说似乎很可笑。有什么统计数据可以证明这一点呢?

事实证明,理解 Bootstrap 起作用的统计学原因实际上非常简单。你只需要清楚地了解两件事:

1.统计测试

理解 Bootstrap 的第一件事是清楚地理解统计测试。当我们做测试时,我们有一个样本和一些假设。在我们的样本 x₁,…,xₙ 中的数据来自一些通常未知的分布。然后我们计算一些测试统计数据t(x₁,…,xₙ】这只是我们数据的一些函数。既然我们不知道我们样本的分布,我们也不可能知道 T 的分布 Fₙ
统计学家所做的就是克服这一点,以这样一种方式构建 T ,他们知道如果我们有无限量的数据并且零假设为真,它会有什么分布。如果零假设为假, T 必须发散到一个在渐近分布 F 下极不可能的值。
然后我们计算 T 并将其与 F 进行比较——忽略实际样本是有限的这一事实。如果样本足够大,这是一个合理的近似值。如果它很小,结果可能会非常错误。
在上面的 t 检验示例中,渐近分布 F 是正态分布,但是右侧直方图中显示的有限数量数据的检验统计量的分布 Fₙ 非常不同。

2.经验累积分布函数

理解 Bootstrap 的第二件事是了解经验累积分布函数。如果你觉得你的统计学基础有点生疏,让我给你一个快速的提醒。

当我们想到统计分布时,我们通常倾向于想到密度函数 f(x) —例如正态分布中著名的钟形曲线。描述分布的另一种方式是通过它的累积分布函数。

f(x)= p(x≤x)=e[𝟙(x≤x)】

对于每个值 x ,它给出了从该分布中抽取的随机变量 X 小于或等于该值 x 的概率。对于连续分布 F(x) 就是从负无穷大到 x 的密度积分,所以累积分布函数只是描述概率分布的另一种方式。

标准正态分布的分布函数和密度函数。图片由作者提供。

在实践中,我们通常不知道我们正在处理的数据的累积分布函数,但我们可以通过它的经验对应物来估计,经验累积分布函数或 ECDF 由下式给出

从公式中可以看出,点 x 的 ECDF 就是小于或等于值 x 的数据比例。本质上,ECDF 是一个阶跃函数,在样本中实际观察到的数据点之间保持不变。随着数据集大小 n 的增加, F̂(x) 变得越来越接近真实的累积分布函数 F(x)

经验累积分布函数和理论累积分布函数。图片由作者提供。

关键洞察力

对于 Bootstrap 来说,最重要的是任何 ECDF 本身都是一个有效的分布函数。这种分布是离散的,随机变量可能取的值是在原始样本中观察到的值。ECDF 给这些可能的结果分配了相同的概率。

自举的工作原理

那么,为什么这个自举魔法会起作用呢?回想一下,我们的测试统计数据 T(x₁,…,xₙ) 遵循未知分布 Fₙ ,我们想知道 Fₙ 来计算置信区间、临界值或 p 值。
我们根据从原始样本中抽取的 bootstrap 样本计算 m 检验统计量 T* ,然后利用这些检验统计量的经验分布 F*ₙ 代替未知分布 Fₙ

为什么这样做有意义的关键在于,从原始样本中进行替换绘制意味着从样本的 ECDF 指定的分布中进行绘制。正如我们刚刚讨论的,ECDF 是将概率 1/n 分配给原始样本中每个数据点的分布。替换绘制意味着以概率 1/n 绘制这些点中的每一个。因此,如果我们从样本中抽取——我们从 ECDF 抽取。

因此,如果样本量 n 足够大,检验统计量 T* 的分布 F*ₙ 将是 Fₙ 的一个好估计,因为 F̂(x) 将是 F(x) 的一个好估计。

为什么叫自举?

这种靴带的发明者如今已经 80 多岁了。他的名字叫布拉德利·埃夫隆,事实证明他是一个非常幽默的人。他接受的几次采访充满了尖锐的引用、笑话和有趣的轶事。作为一名学生,他实际上被斯坦福停学 6 个月。他成为了斯坦福幽默杂志的编辑,并在 花花公子 上发表了一期恶搞的文章。对于 1961 年来说,这种模仿可能有点过火了。

格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片

为他的手术选择“Bootstrap”这个名字的灵感来自一个故事,这个故事在德国和英国比在世界其他地方更广为人知。Baron Munchausen 是一个虚构的 18 世纪的德国贵族,喜欢讲述他的冒险故事。在其中一个故事中,他和他的马被困在了一个沼泽里,他抓住自己的头发——或者在某些版本中——他的鞋带,设法把自己和马拉了出来。

你可以看到,为什么 Efron 认为这是一个很好的从样本中重新采样的类比!

何时何地使用引导程序

bootstrap 可用于测试、置信区间等。每当真实分布未知或难以确定时。

bootstrap 工作的逻辑是基于渐近近似的。bootstrap 分布将与真实分布相差很远,因为 ECDF 不同于真实的累积分布函数。因此,不清楚自举是否优于基于渐近正态分布的检验。然而,bootstrap 通常在相对较小的样本中表现得非常好。

自举的一个主要缺点是所需的计算量。如果底层数据集非常大,或者相对于数据而言,生成 T(x₁,…,xₙ) 所需的计算量很大,这可能会是一个问题。然而,在您可能希望应用引导的大多数领域,计算并不是一个限制因素。

最终,一切都取决于用例。对于希望快速得出可靠结果的数据科学家来说,Bootstrap 是一个很好的工具,他们无需担心理论。但是请注意,Bootstrap 工作的原因是渐近近似,并且不能保证它在有限样本中的性能。

如果你喜欢这篇文章,请在 Linkedin 上关注我,我经常在那里发布关于统计学、数据科学和机器学习的帖子。另外,看看我在 Medium 上的其他一些帖子:

* https://pub.towardsai.net/how-to-choose-your-loss-function-where-i-disagree-with-cassie-kozyrkov-2038d19b5e0a *

随机森林背后的统计数据

原文:https://towardsdatascience.com/the-statistics-behind-random-forests-2bfe2e8116f9

窥探随机组合的内部运作

随机森林。(照片由迭戈·伯奇皮克斯拜拍摄)

随机森林有一点非常独特。

我们通常的方差减少技术——比如限制决策树的深度,或者给逻辑回归增加范数惩罚——通过惩罚单个假设的复杂性来工作。然而,随机森林中的方差减少来自于同时探索多个竞争假设

注意这里的“竞争”二字。个体预测者之间的多样性是集合模型(如随机森林)性能的关键。而在统计学的语言中,“多样性”对应的是单个模型预测的不相关/反相关

让我们做一些很少机器学习类做的事情,深入研究随机森林的统计数据。为了做到这一点,我们将以一种读者友好的方式从开创性的 Breiman 论文中推导出一些结果,并最终回答这个有意义的问题: 那么什么是

定义我们的指标

回想一下,随机森林分类器的输出来自于为不同类别投票的单棵树的比例,并挑选相应比例最大的类别。因此,正确分类一个点的随机森林将使其最大比例(介于 0 和 1 之间的数量)属于正确的类。

让我们给我们的随机森林附加一个叫做边缘函数的函数;该函数从我们的数据集分布中提取单个(X,Y)对,并输出林中正确的Y 类的投票比例与林中所有不正确的类的最大比例之间的差异。

关于 margin 函数,你只需要知道,在一个点上较大的正 margin 意味着在森林的“正确性”上有更大的缓冲空间;然而,低于的边距值意味着森林直接向上错误分类该点(越大的负边距越差)。)

示例:点(X,Y)处的 0.5 的差值意味着森林正确地选择了类别 Y,在 Y 处的总票数比任何其他不正确的类别多 50%。相反,差值为-0.3 意味着森林错误地对该点进行了分类,错误选择的类别的总票数比正确的类别 y 多 30%

注意:在本文的其余部分,我们将使用拥有大量树的随机森林,即在限制内的随机森林,这样一旦您修复了您的训练数据集,它们的输出实际上就而不是随机的。这并没有改变我们的任何结论,因为即使是中等大小的森林也会很快收敛到它们的极限,但这确实简化了我们的分析。

现在,让我们定义我们的分类度量:对点 D 的训练数据集进行采样的概率,以及从相同分布中对单个评估点(X,Y)进行独立采样的概率,使得拟合在 D 上的森林在该(X,Y)点上具有正余量:

图 1:“mg”是从训练数据集 D 生成的森林的边缘函数,在点(X,Y)上评估。(图片作者提供)

同样,一个点上的正裕度意味着森林正确地分类了该点,因此上面的概率完全等同于我们的森林生成过程的人口%准确度。(如果你很难看出这一点,可以尝试这种更明确的重构:如果你从总体分布中抽取一个验证集,并且在任何随机抽样点上正确分类的概率是 Q,那么验证集的%准确度大约是 Q。)

现在出现了一个你可能很久没听过的短语:切比雪夫不等式。

统计能力移动#1:你可以(二次)只使用它的期望和方差来限制任何随机变量的尾部概率。

利用切比雪夫不等式,我们可以仅利用边际函数的期望和方差来计算对零下边际进行采样的概率的具体下界。直观地说,方差低、正均值大的边际很少会取负值,切比雪夫只是让这一点变得严谨。现在,只要知道我们可以调整和权衡均值和方差,以获得上面概率表达式的更大下限(我们的总体精确度。)

高水平的偏差与方差

由于边际函数的期望和方差是我们精度权衡的关键,因此我们应该对这两者有一个直观的理解。

让我们看看这些术语,从期望开始:

图 2 (图片由作者提供)

更大的期望值意味着我们生成的任何森林通常都是正确的,其误差比不正确的要大。根据我们对概率和切比雪夫不等式的了解,较大的期望值意味着负值概率的较大下限,即总体精确度的较大下限。

通过使用诸如自举抽样或特征二次抽样的方法对单个树进行随机化,可以稍微降低上述期望。这是森林做出的权衡之一:略微增加“偏差”。但是我们通过增加偏置获得了什么呢?

这就是差异出现的原因:

图 3 (图片由作者提供)

对于固定的正平均值,较小的方差意味着我们生成的森林在任何采样点都不太可能有低于零的边际。与较大的期望值一样,较小的方差增加了采样低于零的裕量的概率的下限。

请注意,我们不能构建无限多的树来将方差缩小到零;如果我们所有的树都是相同的,那么我们的随机森林与一棵单独的决策树是无法区分的,不管它有多大。显然,树与树之间的差异很重要。这里代表“树与树之间的差异”的严谨量是什么?

事实证明,树误差之间的协方差就是我们所需要的。(注意协方差只是一个比例相关。)但是怎么做?而这个协方差项从何而来?我们需要分解方差项来找出答案。

分解差异

我们可以使用方差的矩定义来如下展开边际函数的方差:

图 4 (图片作者提供)

让我们放大右边的第一个期望项。

记住,( X,Y)处的边际函数是正确类别 Y 的树投票比例与其在所有不正确类别中的最大投票比例之差。我们真的可以将投票给某个类别的所有树的比例表示为投票给该类别的随机选择的树的概率。(回想一下,一个森林是从一个特定的数据集通过独立的、相同分布的单棵树的绘制而生长出来的。)

森林投票比例和抽样概率之间的这种联系让我们想到了第二个统计学上的优势:

统计学威力大招#2:所有的比例——或者说概率——都可以改写为二元/指标/伯努利随机变量的均值。

重申一下,我们可以将森林对给定 C 类的投票比例写成每棵树对 C 类的二元投票的平均值——其中,如果树投票给 C,投票为 1,如果树不投票,投票为 0。在极限情况下(即有无限多的随机生成的树),这个“树的平均值”变成了一个期望值,从我们随机抽样的单个树的分布中取值。

让我们使用这种树形分布和我们的频率特性来重写我们的边际函数:

****图 5:“K”是错误的类别,在我们的树分布中平均票数最高。(图片作者提供)

请快速注意,我已经将期望值设定在训练数据集 D 和固定评估点(X,Y)上,因为左边的边际函数是在固定的D 和固定的T7(X,Y)上评估的。**

在这种替换中,我们将产生 Y 类或 K 类的树的比例的差异用于输入 X(这是我们对 X 处评估的边际函数的原始定义),并将其转换为随机采样的树对 Y 类或 K 类的二元投票的平均值的差异(上图是差异的平均值,相当于平均值的差异)。)为了使表达式更简洁,让我们将上述期望内的二进制投票的差异称为与单个树相关联的“原始”边际函数,或“rmg”。****

我们可以通过首先对两边求平方,然后对 D 和(X,Y)应用期望,最后用更紧凑的原始边距函数代替二进制投票的差,来写出下面的新恒等式:

****图 6:“RMG”是单个样本树的原始边缘函数(图片由作者提供)

我们为什么要这么做?如果你还记得,左边的期望是图 4 中方差公式的第二阶矩。我们正在重写方差项。

现在我们要从上面右边的项中取出一个协方差表达式 兴奋起来!

刚刚有人说“协变”吗?(图片由加布里埃拉·克莱尔·马里诺 转自Unsplash)****

在我们这样做之前,我们需要使用三个简短而巧妙的技巧。第一个技巧是通过引入两个独立的、同分布的树分布来重写上面表达式中右边的期望:“Trees”和“Trees-prime”。因为这些分布都是同分布的,它们的期望是相同的,所以我们可以用“Trees”和“Trees-prime”上的两个(同值)期望的乘积来代替右边项中的平方期望。然后,我们得到右手项的如下重写:

图 7 (图片作者提供)

请注意,原始边际函数是特定树的唯一属性(就像边际函数是特定森林的唯一属性一样),因此我将从“Trees”采样的树的原始边际函数描述为“rmg”,将从“Trees-prime”采样的树的原始边际函数描述为“rmg-prime”。

第二个技巧利用了这样一个事实:两个独立随机变量的期望乘积等于乘积的期望。由于分布“Trees”和它的孪生“Trees-prime”在构造上是独立的,所以在上面的表达式中被评估的“rmg”和“rmg-prime”函数本身独立于树的绘制(在固定评估点(X,Y)和数据集 D 生成我们的树时)。)然后,我们可以使用第二个技巧,用两个原始边际函数的乘积的联合期望来代替期望的乘积。因此,我们可以将表达式重写为:**

图 8 (图片作者提供)

最后,第三个技巧是“置换”期望,这样您在外部对训练数据集 D 和树分布有一个期望,在内部对评估点(X,Y)有一个期望。要了解这是如何工作的,首先巩固一些术语是有帮助的。使用迭代期望定律,我们可以将上面的迭代期望重写为总期望:

图 9 (图片作者提供)

现在,我们将利用(X,Y)独立于“树”、“树素”和 D 上的联合分布这一事实,将上述期望分解为新的迭代期望:

图 10 (图片作者提供)

我们非常接近于在这里抽出一个协方差 (它也只是一个换算 相关性!)注意,里面的项是两个随机变量乘积的期望,是协方差的教科书公式之一中的组成项: Cov(X,Y) = E[XY]- E[X]E[Y] 。让我们根据协方差重写期望中的项,以获得新的整体表达式(为下图中的字体大小道歉;我答应这一点,只要表情会得到):

图 11 (图片作者提供)

回想一下图 6,我们一直在计算边际函数的二阶矩。然后,我们可以将上述表达式代入图 4 中方差的矩定义中的二阶矩。我会在这里保存几页重复的数学;只需知道我们可以将上述期望中的第二项与图 4 中右侧的第二项合并。进行这种替换和合并会得到以下关于边际函数方差的表达式,该表达式仅涉及上述协方差项(包含在预期中)和一个附加方差项:

图 12 (作者图片)

这是构成我们的森林的边际函数在 D 和(X,Y)上的方差的两个分量。让我们直观地理解每个术语:

  1. 左边的术语:粗略地说,这个术语表示任意两个随机采样的树的“误差”在点的总体分布上“共变”的程度,其中这个协方差是在树和产生这些树的训练数据集的所有可能组合上平均的。注意,让一棵树的逐点误差与另一棵树的误差不相关,甚至相反,会降低表达式的整体值。****
  2. 右边的术语:这个术语不太重要,因为对于大型训练数据集 D,不同训练数据集 D 上的森林的预期裕度函数的方差很小(换句话说,两个大型随机森林适合两个 i.i.d .大型数据集将做出非常相似的预测。)然后我们可以合理地假设右边的项比左边的项小得多。

让我们去掉右边的项,只使用左边的项重写边际函数的方差:

图 13 (图片由作者提供)

太神奇了!**我们森林的偏差-方差权衡实际上是偏差-协方差权衡**,所讨论的协方差是单棵树的误差。**

偷偷摸摸的读者可能已经注意到一些更令人兴奋的事情:**这个数学没有任何部分是专属于棵树的。你听到我在任何地方提到“叶子”、“节点”或“分裂”了吗?****

没错;您可以随机选择任何分类器,然后将它们平均在一起,以实现最佳的偏差-协方差权衡——这可能比单独使用任何一个分类器都更准确!狂野。

投资类比

(照片由谢尔盖·托克马科夫皮克斯拜拍摄)

在传统的投资组合理论中,投资的一个目标是在固定的平均回报下最小化投资回报的方差。

假设你的投资组合包括对不同公司的投资:谷歌、可口可乐、Reddit 等。那么,你投资的累积回报就是个人回报的总和。我们可以把你的累积收益的方差写成:

图 14:让你退休的数学方程式(图片由作者提供)

让我们看一下右边的两个总数。

右边的第一个总和由每只股票收益的方差总和组成。某种股票的回报波动越大,整个投资组合的回报也波动越大,这是有道理的。你可以把收益的方差看作是一项投资的风险的粗略度量。

右边的第二个和稍微有趣一点,包含协方差项(你能看出我在说什么吗?)如果两只股票共同负变,实际上降低了投资组合收益的总体方差。**

这就是为什么分析师总是告诉个人投资者分散投资。如果你只持有 Gamestop 的股票,那么你的财富会像 Gamestop 的财富一样剧烈波动。但是如果你持有不同行业的不同公司的股票,那么个人的涨跌会在一定程度上抵消,你面临的唯一风险是整个市场下跌的风险(所谓的“系统性”风险)。分散投资相当于不把所有的鸡蛋放在一个篮子里。

回到随机森林——我们的单个树(股票)有时可能过于投机,以泛化为代价追求训练的准确性。然而,通过随机化这些树,我们正在探索(投资)问题中不同的、相关性较低的“部门”,通过取平均值,我们正在使产出(我们的投资组合)较少依赖于任何一棵树。通过这样做,我们创建了一个健壮而强大的模型。

结论

让我们总结一下我们的两条主要经验:

  • 随机森林采用了一种独特的方差减少方法:集合相关误差较小的单个模型
  • 基于树的系综没有什么独特之处。你可以构建任何机器学习模型的随机集合,调整随机性以达到最佳精度

需要注意的一点是,梯度推进可能会做一些类似于第一个项目符号的事情。对于每个新的 boosting 迭代,我们有效地对当前迭代的“错误”进行上采样,并训练新的模型;最后,我们将新模型添加到现有的集合中。因为我们对前一次迭代的误差进行了上采样,所以增量模型往往在这些点上具有相对较低的误差,而在前一次迭代表现良好的点上具有相对较高的误差。这是反相关性在起作用!然而,注意,这里没有给出严格的证明;我将把关于增强和随机集合的讨论留给真正的专家。

第二点实际上很有趣。它表明,现有的每一个模型都可以简单地通过随机化和并行训练许多类似的模型来改进——这在更便宜的云计算中越来越容易做到。

谁知道呢?也许下一场大型 Kaggle 比赛将归结为一种巧妙的随机技术。

参考

[1] L .布雷曼,随机森林 (2001),机器学习 45 5–32**

在欧洲医疗保健和制药行业推进人工智能(AI)的斗争:挑战和策略

原文:https://towardsdatascience.com/the-struggle-to-advance-artificial-intelligence-ai-in-the-european-healthcare-and-pharmaceutics-7869574e0bdf

意见

国家癌症研究所Unsplash 上拍摄的照片

人工智能(AI)有可能彻底改变医疗保健和制药行业,提供一系列好处,如改善患者疗效、提高效率和降低成本。然而,在这些部门采用和实施人工智能也面临着许多挑战,特别是在欧洲背景下。在本文中,我们将探讨欧盟医疗保健和制药行业人工智能解决方案面临的一些主要挑战,以及缓解这些挑战并在该领域取得进展的潜在方法。

1。有限的数据集可用性和机器学习模型中的偏差

人工智能模型在医疗保健和制药领域面临的主要挑战之一是高质量数据集的可用性有限。为了训练和验证人工智能模型,需要大量的数据,这在医疗保健领域尤为重要,因为这里的风险很高,错误的后果可能很严重。然而,获取大型、多样化和准确的数据集可能很困难,尤其是在数据隐私法规严格且医疗保健系统复杂多样的欧洲环境中。

例如,《通用数据保护条例》( GDPR)等数据隐私法规会使收集、共享和使用医疗保健数据变得困难,即使是出于研发目的。此外,欧盟内不同国家的医疗保健系统可能会有很大差异,因此很难建立一个具有代表性且适用于整个地区的数据集。最后,收集和注释大型数据集所需的成本和时间可能令人望而却步,尤其是对于较小的组织或初创公司。

数据的有限可用性也影响了数据的质量,造成了潜在的偏差威胁。机器学习(ML)模型只和它们被训练的数据一样好,如果数据有偏差,模型也会有偏差。这可能导致不公平和不准确的预测和建议,特别是对于边缘化或代表性不足的群体。例如,如果一个人工智能模型是在一个主要由来自一个特定种族或族裔群体的数据组成的数据集上训练的,那么该模型可能会偏向于该群体,而可能不会对其他群体表现良好。类似地,如果在不包括具有某些条件或特征的患者的代表性样本的数据集上训练 AI 模型,则该模型可能偏向或反对这些患者。然而,这个问题可以通过确保用于训练和验证人工智能模型的数据具有代表性和多样性,并定期评估和解决模型中的任何潜在偏差来解决。

2.医疗专家对人工智能系统缺乏了解和信任

在欧洲,医疗保健专家对人工智能系统也缺乏了解和信任。许多医疗保健专业人员可能不熟悉人工智能,可能不理解它如何工作或它能够做什么,从而导致对其采用的怀疑和抵制。

例如,以我目前的经验来看,许多医疗专业人士害怕采用技术,因为他们认为系统可能会取代他们。就人工智能的潜在优势和局限性对医疗保健专业人员进行教育和参与,并让他们参与开发和实施过程以帮助建立对该技术的信任和信心是非常重要的。

3.严格的欧盟法规在顶部添加樱桃

人工智能模型在欧洲医疗保健和制药行业面临的另一个挑战是监管环境。欧盟对医疗设备和药物的批准有严格的规定,人工智能模型和设备获得批准的过程可能是缓慢而复杂的。这可能成为这些部门采用和实施人工智能的障碍,也可能扼杀该领域的创新和进步。

例如,欧盟有一个复杂的监管机构系统,负责审批流程的不同方面,包括欧洲药品管理局(EMA)和欧洲医疗器械管理局(MDA)。根据产品的类型和复杂程度,医疗器械或药品获得批准的过程可能涉及多个阶段,可能需要数年时间。

在人工智能模型和设备的情况下,监管格局可能特别具有挑战性,因为这些技术仍然相对较新,监管框架并不总是定义良好。这使得公司和组织很难通过审批程序,也很难将其产品推向市场。

除了监管挑战,人们还担心人工智能模型和设备的可靠性和安全性,以及对患者结果的潜在意外后果或负面影响。在医疗保健行业,这些担忧更加突出,因为风险很高,出错的后果可能很严重。由于这些监管挑战,与美国等其他地区相比,ML 模型在欧洲医疗保健领域取得的进展相对有限。尽管欧洲有一个庞大而先进的医疗保健系统,并且有明确的需求和需要创新的解决方案来应对该行业面临的挑战,如人口老龄化和医疗保健成本上升。

为了缓解这些挑战并在欧洲医疗保健和制药行业的人工智能领域取得进展,探索简化人工智能模型和设备监管流程的方法可能会有所帮助,包括通过建立明确的监管框架以及让监管机构参与开发和批准流程。这可能需要努力澄清人工智能模型和设备的要求和标准,并创建一个更有效和透明的批准过程。它还可能涉及确保监管机构拥有必要的专业知识和资源来审查和评估人工智能模型和设备的努力。例如,虽然人工智能在医疗保健领域的使用在美国出现了爆炸式增长,许多初创公司和大型科技公司进入了市场,但人工智能在欧洲医疗保健领域的采用却较为缓慢和谨慎。这部分是由于监管障碍和医疗保健领域缺乏明确的人工智能监管框架,以及高质量数据集的可用性有限和与偏见和信任有关的挑战。

减轻人工智能在欧洲医疗保健和制药行业面临的挑战

为了缓解这些挑战并加快欧洲医疗保健和制药行业人工智能领域的进展,可以采取几个步骤。

首先,应该努力提高高质量数据集的可用性,包括与医疗服务提供商和研究人员合作建立伙伴关系和协作,以及开发数据共享平台和计划。同样重要的是,通过确保用于训练和验证模型的数据具有代表性和多样性,以及通过定期评估和解决任何潜在的偏差,来解决和减轻 ML 模型中的偏差。

其次,应该努力教育和吸引医疗保健专业人员了解人工智能的潜在优势和局限性,并让他们参与开发和实施过程,以帮助建立对该技术的信任和信心。

最后,探索简化医疗保健和制药行业人工智能模型和设备监管流程的方法可能会有所帮助,包括通过建立明确的监管框架和让监管机构参与开发和批准流程。

结论

AI 在欧洲医疗保健和制药行业面临的挑战是巨大的,但并非不可克服。通过应对这些挑战并为人工智能的开发和实施营造一个支持性的环境,有可能在该领域取得进展并实现这一变革性技术的全部潜力。

用于手写数字识别的个人宠物项目的第三次生命

原文:https://towardsdatascience.com/the-third-life-of-a-personal-pet-project-for-handwritten-digit-recognition-fd908dc8e7a1

使用 Streamlit 在定制数据集上从头开始部署 YOLOv3 的旅程

五年前,当我得到第一份数据科学家的工作时,我想尽快获得更多的经验。我做的其中一件事是做一个个人项目:一个 Flask 应用程序,允许用户画一个数字,并让它被 ML 模型识别。我花了几个月的时间来开发它,但是从提高我的技能和帮助找工作的角度来看,这是值得的。

两年后,我出版了一个有各种改进的新版本;比如我用 OpenCV 识别单独的数字,模型扩展到 11 类,预测非数字。如果你有兴趣,你可以在这里阅读关于这两个版本的更多细节

这两个应用程序是使用免费计划部署在 Heroku 上的,但前一段时间,免费计划停止了。我想保持这个项目的活力,所以我决定做一个新版本。简单地重新部署一个项目并不有趣,所以我在 12 个类上从头开始训练了一个 YOLOv3 模型。虽然这看起来像是一个小型的个人项目,但它实际上提出了许多与真实项目相同的挑战。在这篇博文中,我想分享我在这个项目上的工作经历,从数据收集到部署。

这是应用程序本身的链接

作者制作的截图

数据收集和处理

获得良好的数据和注释是任何项目的重要组成部分。由于这个应用程序的早期版本,我有一个大约 19k 张图片的数据集,存储在亚马逊 S3 桶中。虽然这些图像的标签最初是由我的模型生成的,但我知道存在一定程度的误差。事实上,我估计错误率在 10%左右,这意味着大约 2k 的图像有不正确的标签。

作者制作的截图

除了标记过程中的错误之外,我还遇到了图像中令人困惑的案例带来的困难。例如,人们有时绘制数字的方式很难确定描绘的是什么,或者在一幅图像中绘制多个数字,这又增加了一层复杂性。此外,我在以前的模型中实现了一个“other”类来识别非数字对象,但是我仍然需要验证所有的标签。

作者制作的截图

因此,我花了几个小时手动检查和纠正图像的标签,甚至删除了一些我不确定的标签。在开发我的项目时,确保数据和注释准确可靠是至关重要的。

图像分类模型

当我开始着手我最新的数字识别项目时,我在我的 MacBook 上用 Pytorch 训练了一个 CNN 模型。我还用这个教程训练了一个 ViT 模型。这两种模型都使用 Pytorch 的 MPS 进行训练,允许使用 Metal 编程框架在 macOS 设备上进行高性能 GPU 训练。与使用 CPU 相比,这大大加快了训练时间。

我之前使用 PyTorch-lightning 和 Hydra 开发了一个培训管道,我可以很容易地为这个项目修改它。你可以在这里看到这条管道的代码。

一旦模型被训练,我就检查他们做出不正确预测的情况,并试图纠正它们。不幸的是,在某些情况下,我自己无法确定正确的标签,所以我通常会删除此类图像。

值得注意的是,在这一点上,我有 12 个类供模型识别:10 个用于数字,一个用于“其他”,最后一个类,我称之为“审查”。我惊讶地发现,模型能够很好地识别这个类。

虽然这些实验工作起来很愉快,但它们最终是我为项目训练对象检测模型的最终目标的垫脚石。

为对象检测注释图像

正如我前面提到的,我这个项目的目标是训练一个对象检测模型,它需要每个图像中每个对象的边界框。首先,我使用 OpenCV 库中的 cv2.findContourscv2.boundingRect 在图像中的对象周围绘制边界框。为了使这个过程更有效,我最初只处理包含单个对象的图像。

如果 OpenCV 在一个图像中识别出多个边界框,我会手动验证并修改标签,将这些图像移动到一个单独的文件夹中,以便以后处理。

接下来,我需要为包含多个对象的图像获取标签。我最初试图自动提取边界框,但发现了太多错误,因为人们经常用多个不相连的笔画来绘制数字。

作者制作的截图

经过一些研究,我发现https://www.makesense.ai/是标记其余数据的有用工具。花了几个小时浏览所有图像,但最终,我有了 16.5k 图像的边界框注释。

我在标注数据时遇到的一个挑战是决定标注什么和不标注什么。例如,在一些图像中,很难确定是否所有描绘的对象实际上都是数字,或者一些对象是否应该被标记为“其他”。

作者制作的截图

为对象检测训练 YOLOv3

当我开始研究我的对象检测模型时,我最初只使用带有单个对象的图像进行训练,以确保一切都按预期进行。我以这个教程为起点,看到了一个不错的表现,错误率相对较低。

作者制作的截图

然而,当我开始在所有图像上训练模型时,事情出错了。该模型的性能受到影响,有时梯度甚至爆炸。预测的边界框也是不正确的。

作者制作的截图

为了尝试并找出这些问题的根源,我仔细调试了流程的每一步。我遇到的一个问题是关于增强的:Albumentations 库中的一些增强导致了边界框的扭曲。这里有一个关于这个问题的旧 GitHub 问题。因此,我开始使用 imgaug 进行增强,并且只在标准化和调整图像大小的最后一步使用 albumentations。

我发现的另一个问题是边界框的格式:我使用了 coco 格式,而模型的代码期望它们是 yolo 格式。修复这个问题有所帮助,但模型的性能仍然不够好。

经过进一步的实验,我发现了最终的问题:当我在训练图像分类模型时,我使用 OpenCV 提取了绘制的数字,并将图像的大小调整为 32x32 或 64x64。这意味着数字占据了图像中的所有空间。然而,当我开始训练对象检测模型时,我将带有图像的整个画布调整为 64x64。结果,许多物体变得太小和扭曲,不能有效地被识别。将图像大小增加到 192x192 有助于提高模型的性能。

我正在分享一个链接到一个带有训练图和更多细节的权重和偏见报告。

之前我提到过我在 MacBook 上用 Pytorch MPS 训练过图像分类模型。然而,当我试图以同样的方式训练一个对象检测模型时,我遇到了 Pytorch MPS 的一些问题。一个内部操作失败了,所以我被迫切换到使用 CPU。GitHub 上有一个特殊的问题,人们可以在那里分享这类案例。

虽然这在对 64x64 大小的图像进行训练时是可行的(尽管要花 15 分钟),但是将图像大小增加到 192x192 会使训练极其缓慢。结果我决定用 Google Colab 代替。不幸的是,免费版本是不够的,所以我不得不购买 100 个信用点。Colab 上的一个纪元只用了 3 分钟。运行几个实验就足以获得良好的性能。

作者制作的截图

部署

训练模型是开发过程中的一个重要步骤,但不是最后一步。训练模型后,下一步是创建和部署应用程序。

细流

为了创建这个项目的应用程序,我决定使用 streamlit ,因为我以前有过使用它的经验,并且发现它比使用 flask 进行应用程序开发要快得多。虽然这款应用的视觉效果可能不如一个精心设计的网站,但它的开发速度足以弥补这一点。

我用这个画布工具让用户画出模型可以识别的数字。应用程序开发过程相对较快,只需几个小时就能完成。一旦应用程序准备就绪,我就可以进入部署阶段了。

部署

最初,我计划在 streamlit cloud 上部署应用,因为这是一个快速部署和共享小应用的优秀平台。我在 streamlit cloud 上成功部署了该应用程序,但当我在聊天中分享它时,它很快就达到了资源限制。这意味着我需要找到一个替代的部署解决方案。

作者制作的截图

我考虑过像以前一样在 Heroku 上部署这个应用,但意识到对这个项目来说太贵了,因为它比以前的版本需要更多的内存。

这时我想起了拥抱面部空间,一个专门为部署 ML 应用程序而设计的平台。我能够在一个小时内轻松地将我的应用程序部署到拥抱脸空间上,并且它工作起来没有任何问题。总的来说,我发现这个平台是部署小型 ML 模型的优秀解决方案。

CI/CD

当处理已经存在的项目时,我们并不总是能够自由地按照我们的意愿设置管道,但是在我的情况下,我可以做我想做的任何事情,所以我实现了大量的检查来最小化错误出现的机会。

我安装了带有各种检查的预提交钩子。

作者制作的截图

I .限制对主要分支机构的推送—所有变更应仅通过 PRs 完成。

作者制作的截图

创建 PR 时,它会触发 deepsource 检查以及带有检查的 github 操作。

作者制作的截图

当一个 PR 成功合并到主分支时,github 会触发一个动作来更新 Hugging Face Spaces 上的 repo。

作者制作的截图

失败的样式转移

最初,我计划给应用程序添加一个额外的功能:使用样式转移来显示与用户绘制的样式相同的所有 9 个其他数字的能力。然而,我发现这个功能并没有我希望的那么好。我认为,在白色画布上绘制的黑色数字缺乏上下文和风格,这使得很难有效地应用风格转移。因此,我决定在最终版本的应用程序中不包含这一功能。

作者制作的截图

结论

总的来说,我对这个项目的结果很满意。虽然该模型的预测并不完美,但对于该应用程序的目的来说,它们仍然足够准确。但是,我确实计划在未来使用新数据重新训练该模型,以进一步提高其性能。

这个项目对我来说是一次宝贵而愉快的学习经历,我希望你也觉得有趣。

更多资源的链接:

数据科学的三大基石

原文:https://towardsdatascience.com/the-three-building-blocks-of-data-science-2923dc8c2d78

数据科学本质上是一个跨学科的领域,我们应该提醒自己这一点。

作者图片

在我本科第一次上数据科学课的第一堂课,教授展示了上面的维恩图。我找不到确切的演示文稿,所以我尽力复制了一份图表,同时保留了关键点。

回过头来看,我怀疑她在一开始就给我们留下了这样的印象,因为她希望我们记住数据科学的基础,因为这个世界越来越被硅谷闪亮迷人的产品分散了注意力。

这些天,每个人似乎都专注于数据科学的一些热门新话题或技术,无论是 PyTorch、TensorFlow、最新的 Tableau 更新,还是谷歌最先进的自然语言处理模型。所有这些话题有什么共同点?不可否认,他们是技术型的

不要误解我。技术专长当然是有效数据科学工作的重要组成部分,但它不是唯一的组成部分。就其本质而言,数据科学是一个跨学科领域。要想在这方面出类拔萃,从它的所有基本学科中汲取营养是很重要的。

在本文中,我将介绍数据科学的三个组成部分——统计学、计算机科学和领域专业知识——并讨论每一个部分对该领域的重要性,以及探索如果忽略一个或多个部分会出现什么问题。

统计数字

我们中的大多数人可能会用统计学这个词来支持我们的任何随机论点,但是我们真的能定义它吗?根据牛津语言,统计学是“收集和分析大量数字数据的实践或科学,特别是为了从代表性样本中推断整体比例”[1]。

更简单地说,统计学着眼于一堆数字,并试图从中找到有意义的模式。它通常分为两个分支:1) 描述性统计,试图描述现有数据中的模式;2)推断性统计,试图对未来数据做出预测。

在最初的定义中有两个重要方面需要注意:

  1. 传统上,统计学——作为数学的一个分支——专注于严格的数字数据。正如我们将看到的,数据科学不一定是这种情况。
  2. 准确的统计依赖于具有代表性的样本。这与第一点有关,因为盲目地关注数字可能会与这个目标背道而驰。

在数据科学出现之前,统计学就是数据科学。几个世纪以来,人们一直在分析数据以获得洞察力,但正式的数据科学是一个相对较新的领域。为什么?在过去,数据是手工收集的,数量相对较少,这意味着也可以手工分析。然而,随着计算机的出现,可供我们使用的数据量呈指数增长,单靠统计学已不足以处理和研究这些数据。

这将我们引向现代数据科学的下一个组成部分。

计算机科学

回到我们的好朋友牛津语言,我们可以将计算机科学定义为“对计算机原理和使用的研究”

嗯。不是超级信息量。可以说甚至有点误导。

许多人默认认为计算机科学等同于编程或软件工程。事实上,计算机科学涉及一系列不同的学科,包括但不限于图形学、理论计算机科学、操作系统、计算机体系结构、算法设计和编程语言。

将所有这些领域联系起来——并因此定义了整个计算机科学——的是使用计算机程序来执行一步一步的逻辑运算以解决某个问题。事实上,这就是“计算机”的全部——一台执行一系列逻辑步骤的机器。计算机科学包括在追求特定目标的过程中对这些步骤的主动操作。

计算机最大的优势是它们的运算速度比人快得多。这是计算机科学成为数据科学主要组成部分的主要原因。

理论上,数据科学可以在没有计算机的情况下存在。计算机不提供分析数据的数学基础——这是统计学的作用。在一个人类可以以光速思考和写作的世界里,统计数据可能就足够了。

但是实际上,有如此多的数据以至于不可能全部用手工来收集、研究、处理和分析。进入计算机科学,这是促进大数据洞察力的现代工具。

Max DuzijUnsplash 上拍摄的照片

至此,我们可以看到统计学为数据科学提供了数学基础,计算机科学为数据科学提供了现实世界的处理能力。

然而,如果没有第三个同样重要的因素,两者都失败了。

领域专业知识

这一次,没有牛津语言的定义可以借鉴,因为领域专长实际上不是一个单独的领域;这更像是一个总括性的术语,最好通过以下方式来理解。

让我们问自己一个问题:在谈论数据科学时,数据实际上来自哪里?是某个统计方程的数学余项吗?还是隐藏在计算机硬件某处的难以捉摸的结构?

这些问题可能看起来很愚蠢,但当我们考虑到这么多自称的数据科学家是如何痴迷于数字和代码,以至于忘记这两者的成功从根本上依赖于数据本身时,它们就不那么愚蠢了。

数据来自哪里?域名。

没有正确理解数据的背景,数据是没有价值的——背景只能由领域专家获得:理解数据来源领域的人,因此可以提供正确解释数据所需的视角。

让我们考虑一个玩具例子来说明这一点。想象一下,我们从 PGA 巡回赛最近几年的不同高尔夫比赛中收集数据。我们获得所有的数据,我们处理和组织它,我们分析它,我们自信地发表我们的发现,三次检查我们所有的公式和计算。

然后,我们就成了媒体的笑柄。为什么?嗯,因为我们都没有真正打过高尔夫球,所以我们没有意识到低分数对应着好成绩。因此,我们所有的分析都是基于相反的情况,因此是不正确的。

这显然是夸大其词,但它表达了这一点。数据只有在上下文中才有意义,因此在试图得出任何结论之前咨询领域专家是至关重要的。

在实践中,未能说明领域和持续依赖纯粹的定量方法会导致(在许多情况下,已经导致)不道德的、限制性的数据科学实践。

一些最后的想法

半年前,当我开始我的人机交互和以人为中心的数据科学博士项目时,我与我所在部门的一位教授分享了一次奇怪的交流。就背景而言,他有社会学背景。

几个同学和他一起喝咖啡,讨论交叉的研究兴趣;我偶然遇到他们,他问我我的是什么。我回答说,我学的是以人为中心的数据科学、计算机科学教育和可视化。

他专注于我的第一点,并继续简要讨论了他的研究项目如何围绕技术的历史和社会学。他描述了他如何检查信息技术的基本基础设施,并对通过提供数据和计算工具来支持科学活动的组织感兴趣(听起来熟悉吗?).

他以半开玩笑的方式结束,笑着说,“所以,我自己也算是一个以人为中心的数据科学家。”

当时,我并没有多想,但在过去的六个月里,我开始明白他的意思了。他的角色是为领域专家提供便利和支持,以便人们可以在上下文中正确理解和解释他们的数据——这项工作的重要性怎么强调都不为过。

关于这一点,让我们回顾一下:

  1. 统计学提供了从数据中得出数学见解所需的工具。没有它,我们可能会得出不科学的结论。
  2. 计算机科学提供了大规模收集、处理和分析数据所需的工具。没有它,我们就无法理解现代世界中的海量数据。
  3. 领域专业知识提供了将数据融入上下文和理解数据所需的工具。没有它,我们可能会依靠数学和计算技术得出不准确的结论,而这些技术忽略了只有领域专家才能看到的数据的复杂性。

将这三者结合在一起,我们就得到了数据科学。

想擅长 Python? 获取独家、免费获取我简单易懂的指南点击 。想在介质上无限阅读故事?用我下面的推荐链接注册!

https://murtaza5152-ali.medium.com/?source=entity_driven_subscription-607fa603b7ce---------------------------------------

我叫 Murtaza,是华盛顿大学研究人机交互的博士生。我喜欢写关于教育、编程、生活以及偶尔的随想。

参考

[1]https://languages.oup.com/google-dictionary-en/

系统需要的三种可观察性

原文:https://towardsdatascience.com/the-three-types-of-observability-your-system-needs-a3e7f6ae4803

作者图片

本文是与凯尔·柯文合作撰写的,他是 Bigeye 的联合创始人兼首席执行官

什么是可观测性?

1969 年,人类首次登上月球,这要归功于大量巧妙的工程和 15 万行代码。除此之外,这种代码使任务控制中心的工程师能够全面了解任务,并做出近乎实时的决策。代码量如此之少,以至于工程师们能够彻底地调试该软件,并且其性能近乎完美。另一方面,今天的搜索引擎执行数十亿行代码,这使得工程师更有可能犯错误或在系统的某个地方出现异常情况。最重要的是,数据和机器学习模型(计算机本质上为自己编写的代码)都有自己的挑战。简而言之,几乎不可能保证一个现代的软件系统总是如你所期望的那样运行。这就是为什么可观察性对所有生产系统都是至关重要的。

幸运的是,我们可以自动化复杂软件系统的可观测性,这样你就可以获得关于你的软件的及时的和可操作的信息,就像 NASA 工程师对阿波罗任务所做的那样。可观察性是快速发现问题所在并找到根本原因的实践。大多数现代软件系统包括基础设施、数据和机器学习模型。这三者都需要可观察性,但是每一个都有不同的需求、工作流和角色。让我们仔细看看!

作者图片

当然,可观察性并不是开发人员、数据工程师和 MLOps 工程师等技术人员所独有的。这与跟踪业务度量和行业特定需求的规程是一样的,但是在这篇文章中,我们将关注可观察性对这三个更具技术性的角色的人意味着什么。

这三种类型的工程师使用可观察性来解决不同工作流的不同问题。在最高级别,基础设施可观察性与软件问题有关,这些问题通常围绕延迟、故障和资源利用。另一方面,数据可观察性更关心应用程序正在使用的数据的变化,无论是数据库中的静态数据还是进入数据存储系统的任何步骤中的数据。机器学习的可观察性是一门较新的学科;它关注于你的模型的性能,衡量它们预测值的好坏,无论是在某些数据片段的总体上,还是使用像 SHAP 分析这样的技术在单个预测的水平上。

分解三种类型的可观察性:作者的图像

基础设施可观测性

人物角色

软件/DevOps 工程师负责软件基础设施的开发和运营。他们的代码是将现代软件系统的所有砖块粘合在一起的灰泥。

问题

许多现代应用程序都依赖于几个系统的协同工作,一个系统中的小问题可能会导致整个应用程序的速度显著下降。

新版本的代码可能会有意想不到的错误。配置更改、密码和闰秒等罕见事件都可能在这一层引起问题。此外,DevOps 工程师通常要对他们没有设计的软件系统负责。运行其代码的虚拟机或 Kubernetes 集群可能会失败。

工作流程

根据问题出现的位置,可以在这一层采用几种工作流。我们来看其中一个。

假设你是一个大型电子商务网站的 DevOps 工程师——姑且称之为 Nile。突然之间,页面加载时间开始变长了。众所周知,此类应用程序 1%的速度下降会导致 15%的客户满意度下降,这意味着巨大的收入损失。

不费吹灰之力—您已经将您的应用与市场领先的可观察性解决方案相集成。您会立即收到有关问题的通知,并可以开始故障排除。

首先,因为您记录了页面加载时间以及页面上每个查询的单独查询时间,所以您可以确定哪些页面加载得比其他页面慢。然后,您可以查看单个查询时间,并根据哪个查询时间最长对它们进行排序。

在系统的更深处,您可以识别出降低您速度的子查询。通过分析这些子轨迹周围的时序,像您这样的 DevOps 工程师能够很容易地看到指向问题根本原因的模式。在这种情况下,最近的代码更改为去年购买超过 300 次的客户在历史查找中引入了更多延迟,由于尾部延迟放大,所有客户都为此付出了代价。您退出变更,直到您的团队能够找出如何在不产生此类成本的情况下部署它。

问题解决了。

作者图片

数据可观察性

人物角色

数据工程师和分析工程师负责构建和运营数据管道。它们确保您的应用程序接收的数据的及时性、完整性和其他质量特征。

问题

当数据源发生变化时,它可能会改变模式、内容或数据到达数据湖或数据仓库的时间。例如,假设您的数据供应商从美国邮政编码(数字)转换为全球邮政编码(字符串)。突然,您的管道中的一个步骤出现故障,因为它依赖于邮政编码是一个数字或者正好是 5 位数字,并且您得到了所有加拿大客户的部分或空邮政编码。

其他问题可能包括陈旧数据(来自未按时运行的管道)、数量(意外丢失或重复的记录)和分布(个人年龄的负值或新的分类值)。这些问题可能是由数据原始来源的变化、数据基础结构的问题或者数据在管道中传输时所经历的各种转换步骤中的代码变化引起的。

全天候识别所有数据管道中的这些问题对于防止数据中断到达模型用于培训和服务的数据是至关重要的,并且可以快速超越抽查等手动方法,甚至数据管道测试等半自动方法。

工作流程

现在,假设你是一家快速发展的分析公司的数据工程师。你获得了第一个大客户,他们刚刚发起了一场关键的营销活动,这取决于你公司的客户细分模型。您的模型在未来 24 小时内提供的建议将对他们的业务和您的业务产生巨大影响。这种模式依赖于新的观众数据。

您从数据可观察性工具得到一个警告:一个应该每 60 分钟更新一次的表已经有 75 分钟没有更新了。单击警报中的链接,您将看到第三方数据提供商的 SLA。您会发现数据已经过时,几个月前也发生过类似的问题。阅读您的队友上次修复时留下的事件记录,您会看到这些数据来自哪个提供商,以及他们的电话号码。你拿起电话给他们打电话。你猜怎么着?在你打电话之前,他们甚至不知道有问题。他们的 SSL 证书过期了,他们用来更新证书的 cron 作业卡住了。他们手动重新运行脚本,您的数据可观察性工具确认一切恢复正常。探测时间:15 分钟。修复时间:十分钟。客户影响:可忽略不计。没人知道你刚刚挽救了公司迄今为止最大的一笔交易。

作者图片

机器学习可观察性

人物角色

机器学习工程师负责开发、生产和操作机器学习模型。

问题

越来越多的软件系统依赖于机器学习模型。越来越多的经济价值依赖于机器学习模型。表现不佳的模型可能会导致糟糕的决策,甚至更糟,让许多客户名誉扫地,收入减少。

然而,与传统软件不同,机器学习模型不是静态的。性能通常会随着时间的推移而下降。事实上,一项调查显示,平均而言,模型在投入生产后的 10 天内就会退化。拥有尽快检测问题、确定根本原因和改进模型的工具是至关重要的。

工作流程

对于这个例子,假设你是一个机器学习工程师,为一家大银行维护一个欺诈模型。您的模型将交易标记为欺诈(或不欺诈)。有一天,你的 ML 可观测性系统向你发送一个警报。您登录后,可以很快找到似乎会产生意外输出分布的输入片段。在这些输入中,您可以识别出一个新的骗子。也许这种新的骗子展示了模型以前没有见过的行为,但你可以用这些新数据重新训练它,并抓住他们和任何其他未来尝试这种方案的人。

收集有用的信息再次成为关键。在这种情况下,您正在寻找一段时间内的模型输入和输出。一旦您获得了所需的数据,对基线性能有所了解是非常有用的。

当模型性能超出基线界限时,您可以放大出现问题的时间范围。接下来,您将按切片对数据进行排序,并评估有问题的数据。

图片作者(来源:模特绩效管理论文)

结论

随着软件在整个世界,尤其是在你的公司中变得越来越不可或缺,对可观察性的需求也在增长。今天,复杂软件系统所需的可观察性水平需要自动化工具。你需要哪些工具取决于你正在解决什么问题。通常,软件和 DevOps 工程师将主要依赖系统和基础设施可观察性工具。数据工程师面临特定的挑战,需要针对数据可观察性定制解决方案。机器学习工程师需要一套完全不同的工具来解决模型性能下降的问题。随着你的团队和公司规模的扩大,你可能会发现自己需要这三样东西。

联系我们

如果这个博客引起了你的注意,并且你渴望了解更多关于机器学习可观察性模型监控,请查看我们其他的博客ML 监控上的资源!如果您有兴趣加入一个有趣的 rockstar 工程团队来帮助模型成功生产,请随时联系我们,注册一个免费帐户,或者在这里找到我们的空缺职位

现在是开始量子计算的时候了

原文:https://towardsdatascience.com/the-time-to-get-started-in-quantum-computing-is-now-9157d0e606e1

现在轮到我们这些领域专家来学习如何使用这项新技术了

量子机器学习要不要入门?看看 动手量子机器学习用 Python

量子计算最近经常出现在媒体上。当然有!我们都非常兴奋,因为它是新的,闪闪发光。

2017 年,量子计算进入了 Gartner 炒作周期。所以,让我们为它欢呼吧,只要我们还在创新的扳机上,它还没有过渡到幻灭的低谷。

改编自 Gartner 2017 年新兴技术宣传周期

但是量子计算将会影响我们所有人。有一个合理的理由相信,这项利用量子力学作为资源的技术在 21 世纪可能会像 19 世纪的电一样具有变革性。

我们最初是如何学会获取和使用电的,以及我们今天是如何用量子力学做同样的事情的,这两者有很深的相似之处。

英国物理学家罗伯特·威廉·博伊尔在 1675 年发表了他关于电的机械起源或产生的笔记。从那以后,对电的探索又上了一个台阶。另一位英国科学家弗朗西斯·豪克斯比(Francis Hauksbee)在做电的吸引和排斥的实验时,第一个制作了一个摩擦时会发光的玻璃球。然而,又过了一个世纪,托马斯·爱迪生才在 1878 年看到电灯的市场。治理电力的起点。

在看量子计算之前,我们先走一个中间步骤。让我们看看数字计算时代是如何开始的。它始于 Eniac——电子数字积分器和计算机。

改编自美国陆军照片,公共领域

这是第一台数字电子计算机,其运算方式与今天的微处理器大致相同。建于宾夕法尼亚大学,美军于 1946 年实施。当时,它唯一的应用是计算炮弹的弹道。

然而,战争结束了,它再也没有什么实际用途了。然而,科学家和工程师对随之而来的可能性感到兴奋。毫无疑问,他们被证明是正确的。但是,在 1946 年,没有人想到个人电脑、笔记本电脑、手机和互联网。这项新技术的深远影响是最没有预料到的。相反,它们完全来源于对这种计算技术的接触。顺便说一下,它们都是电力驱动的。

今天,我们正在见证另一种计算技术的出现。又一次,一个全新的计算能力世界开启了。

然而,量子力学的基本理论并不新鲜。它出现在 20 世纪初。几十年的量子物理学基础研究让我们走到了今天——在驾驭它的边缘。

当然,我们会在大众媒体上读到精彩的东西。有时候,当他们报告量子叠加和纠缠时,这听起来很夸张。当然,大众媒体说明性地解释了叠加——一个粒子同时处于多种状态。当然,当我们听到纠缠时,我们会想到《星际迷航》中的隐形传送——当有人在宇宙的另一端看到另一个粒子时,一个粒子会瞬间改变其状态。但是当然,这些观念从过于简单到错误都有。

作者图片

然后,还有科学。即使是最伟大的头脑也嘲笑量子力学暗示的概念。就连爱因斯坦也在挣扎。他对量子纠缠不屑一顾,认为它是一种幽灵般的超距作用,因为他认为这很荒谬。他当然不是唯一一个试图将量子物理学预测的奇怪事物归入数学好奇心垃圾箱的人。

在这个特殊的例子中,爱因斯坦错了。过去三十年的发现表明,量子力学预言的每一件怪异的事情,尽管可能与直觉相反,却是正确的。没有其他理论能准确预测量子力学没有预测到的东西。

作者图片

假设这一切都太多了。假设这一切都太不可思议而不真实。然后,看看我们自己周围是有帮助的。

我们周围已经有了量子技术。我们利用量子力学建造的第一件东西绝对改变了世界。这是全球定位系统——GPS。它的工作原理是原子计时,使用量子叠加来访问原子内部非常稳定的滴答。它能让我们在厘米范围内进行地理定位。它为我们提供基于位置的服务。

那么,量子计算是怎么回事呢?

量子计算是一种完全不同的信息处理方式。它不仅能让我们解决当今超级计算机难以解决的问题。但在某些情况下,量子计算使我们能够解决我们能够建造的任何可以想象的超级计算机无法解决的问题。

但是有一个条件——当然有。

问题是,利用这种新的计算能力很难做任何有用的事情。找到一台量子计算机可以做的事情并不困难。它们可以做经典计算机能做的几乎所有事情。然而,如果经典计算机能够解决这个问题,那么让经典计算机来做可能会更便宜,甚至更快。

所以,挑战是找到你应该用量子计算机做的事情,因为没有其他合理的方法来解决这个问题。所以,本质上,我们必须去一个组织问:

“有什么非常重要的事情是你不可能做到的,但是如果你不去做,你的组织将会处于危险之中?”

答案可能是不存在这样的问题。如果一个组织有这样的问题,他们会阻止他们建立组织。

因此,相反,我们需要组织内部的人拓展和思考那些在计算上不可能的事情,这些事情可能真的有价值。

我们不需要另一个物理学家在实验室里思考一个组织的问题。他们不会提出这些见解。

这些见解将来自拥有这种新型计算能力的从业者。因此,我们需要知道如何利用这些特殊量子设备的领域专家。

现在是成为这些专家之一的时候了!

IBM 刚刚推出了名为 Eagle 的 127 量子位芯片。因此,解决经典计算机无法解决的任务的技术今天已经存在。然而,物理学家在实验室里想出的最好的东西是模拟量子力学系统。

谷歌在 2019 年宣称量子至上——他们的 Sycamore 量子设备解决了一项经典计算机无法完成的任务。但是,他们承认这个问题没有实际用途。本质上,他们证明了量子计算机能做的事情,量子计算机也能做得很好。就像 1946 年一样。唯一的区别是,今天的 Eniac 的被称为 Sycamore 和 Falcon。

现在轮到我们这些领域专家来学习如何使用这项新技术了。让我们不要等待一些聪明的物理学家重新发明我们的企业,让我们灭绝。相反,让我们走在这场运动的最前沿,塑造我们的未来。

量子机器学习要不要入门?看看 动手量子机器学习用 Python

在这里免费获得前三章。

作为数据科学家,您使用的前 20%的工具和活动会产生 80%的结果

原文:https://towardsdatascience.com/the-top-20-percent-of-tools-and-activities-you-use-as-a-data-scientist-produce-80-percent-of-the-93b15e5fa659

意见

80:20 法则告诉我们,作为一名数据科学家,这些工具和活动会给你带来最高的投资回报。

Unsplash 上的 Venti Views 拍摄的照片

作为一名数据科学家,您总是在寻找使您的工作更简单、更有效的方法。

无论是自动化每周一早上困扰你的单调任务,还是寻找最有效的方法来执行一个过程,以便你可以得到好东西,总有一些事情你试图简化和加快。

数据科学家最大的抱怨之一是他们的工作可能很单调。这是因为像数据清理这样的任务虽然对分析的成功至关重要,但通常花费的时间最多,并且重复性最高。

这种现象可以归结为帕累托原理:给定情况或系统的 80%输出是 20%输入的结果,反之,20%输出归因于 80%输入。

知道了这一点,如果我们能够将精力集中在为我们的工作提供最大投资回报的工具、活动和技能上,难道不是有益的吗?来自各种教育和职业背景的数据科学家在 r/datascience 上的一个鼓舞人心的帖子中共同回答了这个问题,您可以在这里找到,下面总结了他们的最佳答案。

领域知识

虽然这似乎是任何数据科学家的既定投资回报,但我们中有多少人已经开始(或正在开始)并开始申请任何可以想象的领域的工作,无论领域知识资格是什么?

作为一名数据科学家,当主要目标是击败数百名其他合格候选人时,很难评估领域知识的价值。

然而,作为一名数据科学家,领域知识将为你提供 80%的成果。

领域知识使您能够理解您的利益相关者在追求什么,该领域如何决定数据的外观,以及您的分析应该回答的问题类型。

作为一名数据科学家,该工具还能为您节省大量时间。

有多少次你因为刚进入这个领域是一个新的数据科学家,而一直在研究一个你无法理解的问题?可能比你愿意承认的次数还要多。然而,随着时间的推移,你会发现解决问题的过程变得更加简化,你会给你的利益相关者带来更大的影响。

因此,领域知识是为数不多的工具之一,可以保证您节省时间,并在数据分析中获得更大的投资回报。

结构化查询语言

在过去几年的某个时候,数据科学家使用 SQL 变得不酷了。

如果你是一个使用 SQL 的数据科学家,你会被称为老古董和不食人间烟火。更糟糕的是,如果你是一名数据科学家,工作围绕着使用 SQL 和 Tableau,那么你很难被业内其他人认为是一名数据科学家。

然而一次又一次,SQL 证明自己仍然是数据科学家工具箱中最有价值的工具之一。

SQL 不仅灵活、强大、快速,而且简单易学、价格合理。最重要的是,它产生结果

SQL 使数据科学家可以轻松地即时生成业务问题的答案,并通过几个快速查询来了解公司、项目或领域的状态。

不仅如此,配合 Tableau 这样的数据可视化工具,SQL 可以让您立即向利益相关者展示自己的见解。当谈到理解此时此地的数据时,SQL 是任何其他工具都无法比拟的。

只要数据需要被理解为数据科学家日常职责的一部分,SQL 将仍然是一个相关且强大的工具。

线性回归

正如大多数数据科学家所知,大多数统计测试都是某种形式的回归,而且大多数实际上都是线性回归。

那么,尽管这个简单的数学过程产生了影响,为什么它却被如此忽视呢?

事实是,大多数企业和利益相关者都在寻找能够创造奇迹的数据科学家。因此,虽然数据科学家可能只是完成简单的线性回归来解决业务问题,但他们会用烟雾和镜子掩盖它,使工作看起来比实际复杂得多。

利益相关者和 C 级高管往往只对最新算法能够告诉他们的关于他们公司或组织的信息感兴趣。对他们来说,低级的线性回归已经是过去的事情了(如果他们明白它到底是做什么的话)。

这促使数据科学家重新发明轮子,并制定详细的分析计划,以产生预期的结果。

然而,当使用简单的线性回归(产生大部分结果)时,可以节省多少时间呢?

线性回归计算速度快,结果易于解释。这两个因素使得它成为处理大部分数据分析需求的显而易见的选择。

直方图、散点图和热图

一个简单、中肯、美观的数据可视化是物有所值的。

它不仅准确地告诉利益相关者他们需要知道什么,而且还讲述了一个有助于塑造组织动力的故事。

当谈到数据可视化时,直方图、散点图和热图能够通过以一种易于理解的方式呈现事实来为您完成 80%的工作,几乎没有留给您在解释和呈现部分做什么。

将这些可视化放在一起既简单又快速,如果做得正确,可以提供一个了解数据的窗口,即使是最困难的利益相关者也可以了解情况的真相。

关键要点

  • 作为一名数据科学家,您可能每天都要使用 5 到 10 种工具。作为一名数据科学家,为什么不将你的精力集中在你使用的 20%的工具上,以产生 80%的影响力呢?
  • 许多数据科学家都知道,领域知识、SQL、线性回归、直方图、散点图和热图可以在一个小软件包中产生最大的影响。
  • 最有影响力的工具不一定是最花哨或最复杂的——如果有什么不同的话,对你产生最大影响的工具是最简单的,只是碰巧能提供大的结果。

订阅将我的故事直接发送到您的收件箱:故事订阅

请成为会员,使用我的推荐链接获得无限制的媒体访问权限(我将收取少量佣金,无需额外费用):媒体会员

通过捐赠来支持我的写作,以资助更多像这样的故事的创作:捐赠

最高云评估,这样你就不需要重复我们的错误

原文:https://towardsdatascience.com/the-top-clouds-evaluated-such-that-you-dont-need-to-repeat-our-mistakes-6797720992b

一位 ML 工程师对热门云服务提供商的看法

您是否正在努力理解不同的云服务提供商?您的云成本正在激增吗?你害怕在转换供应商时犯战略性错误吗?在这篇文章中,我们收集了所有的知识和经验来帮助你。

多年来,云一直在增长和扩展,从那时起,它们已经成为许多软件系统的重要组成部分。LinkedIn 上有超过 1.7 万个德国云工程师的空缺职位。对于许多公司来说,他们是否应该使用云是毫无疑问的。例如,我在一家初创公司工作,对我们来说,使用现有的强大和可扩展的基础设施以及服务器和分析软件的可能性大大超过了成本,并使我们能够更专注于软件的创意方面,而不是技术服务器问题。对我们来说,一个更相关的问题是选择哪种云,在这里我想分享一下我对此的想法。

在本文中,我将简要分析三种主要的云——AWS、Azure 和 GCP。除了一些客观特征,我还将分享我与他们每个人一起工作的个人经历,包括我面临的问题以及我是如何解决这些问题的。

https://pixabay.com/images/id-3843352/

我们需要从云中得到什么

现代云提供了数百种服务,当然,我们无法分析所有的服务。不过,其中一些比另一些用得更频繁。例如,在我们的项目中,我们通常需要从云中获得以下内容:

基于 SQL 或文件的数据存储。

基于 HTTP 请求或时间触发器运行 ETL 流程的批处理服务。

一个轻量级的 API 服务来处理对模型的快速请求。

由于我们专注于开发轻量级机器学习模型,所以我们不考虑高性能机器的可用性。我们通常需要的是廉价的虚拟机或可抢占的经济高效的集群。

1。GCP。妥协还是后起之秀?

Google 云平台是我遇到的第一个云,先从它说起吧。

在三大巨头中,GCP 是最不受欢迎的选择。然而,它的受欢迎程度增长相对较快。在过去的两年里,它获得了将近 2%的市场份额,从 7.2%增长到 9.1% [1]。其较低的市场份额可以解释为 GCP 在不久前才推出(其核心服务之一——应用引擎——在 2011 年才普遍推出)[2]。

2020-2022 年云市场份额。图片由作者提供,数据来自 [1]

云服务商年轻意味着什么?就 GCP 而言,这导致可获得的服务数量减少。AWS 和 Azure 提供 200 多种服务,而 GCP 只有 100 多种。例如,你现在在 GCP 找不到区块链开发、量子计算和图形数据库的专用服务。虽然如果你的业务是围绕这些技术建立的,这对 GCP 来说可能是一个破坏交易的缺点,但在更传统的情况下,这甚至可能是一个优势——你的团队不会迷失在无限的配置和服务列表中。

历史上,人们一直批评 GCP 的可用数据中心数量较少。的确,这是一件需要考虑的重要事情。AWS 和 Azure 的数据中心似乎离你或你的客户更近,而 GCP 的数据中心更远,这可能会增加延迟。幸运的是,这个缺点不再相关,因为谷歌开放了多个新的地区和区域,并不断增加新的。就区域和专区的数量而言,谷歌超过了 AWS——AWS 是这方面的前领导者。

作为云计算市场上相对年轻的竞争对手,GCP 也可以在价格上提供更好的交易。例如,GCP 提供了最便宜的虚拟机“E2-micro-preemptive ”,具有 2 个 vCPU 和 1 GB 内存。它的价格比 AWS 的“t4g.nano”低 48%,比 Azure 的“A0”低 5 倍。如果你需要一个便宜的专用 PostgreSQL 服务器,GCP 也可以提供一个比竞争对手低 25%的价格[2]。总的来说,GCP 在低端水平上更便宜。更高性能的实例的成本通常与其他云提供商的同类产品大致相同。重要的是要知道 GCP 没有廉价的内存优化实例——只有 40 个 vCPUs 的高性能和极其昂贵的实例。

GCP 的个人经历

我真正喜欢 GCP 的是它的 web 界面和文档,它们以非常简洁和用户友好的方式实现。就个人而言,我认为这是直接影响您的团队实现解决方案所需时间的主要优势之一。

GCP 似乎比 Azure 更稳定,但仍不如 AWS 稳定。例如,我们在 App Engine 中遇到了一个恼人的 bug。从 App Engine 执行对第三方服务的每个请求至少需要 2 分钟,而在我的本地环境中最多需要 100 毫秒。我们需要做的就是从“标准”环境切换到“灵活”环境。有趣的是,Java 组件在“标准”环境下工作得很好,所以这个问题只与用于 Python 的 Google Cloud SDK 有关。

App Engine 又一次让我们大吃一惊。一天,我们查看了成本预测,发现 App Engine 产生的成本比我们的预期高出五倍。出于某种原因,五个应用引擎实例被分配给了一些过时的版本,这些版本在重新部署后仍保留在那里,尽管处于非活动状态,但它们仍在产生成本。

总之,廉价机器的较低价格、较少的配置选项和服务选择使 GCP 成为小公司的完美选择。有些人可能会考虑谷歌宣传的另一个优势,但这很难核实。他们宣称,谷歌云数据中心运行的能源是典型数据中心的一半,并且在可用的情况下 100%使用可再生能源[3]。

GCP 提示

GCP 适合你,如果:

  • 你是一家刚起步的公司。
  • 你不可能投入太多时间去学习 AWS 和处理 Azure bugs。
  • 您不需要太多来自云的灵活性和配置工具。
  • 你已经准备好接受平台规定的方法。
  • 您需要通用或计算优化的解决方案,但不需要内存优化的解决方案。

如果你决定选择 GCP,以下是我对开发者的建议:

  • 不要使用 App Engine 标准环境——G 大哥希望你使用更灵活的环境,否则,他们会惩罚你。
  • 定期检查成本分析,确保没有意外成本。
  • 一定要清理掉多余的 App Engine 应用版本,防止 G 抢你。

2。AWS。当金钱不再重要

目前,AWS 是云服务的市场领导者,拥有 49.2%的市场份额,尽管慢慢地将它的地位输给了 Azure 和 GCP [1]。自 2002 年成立以来,它也是我们三个竞争对手中历史最悠久的云服务提供商。老实说,除了运行简单的 EC2 实例,我从未与 AWS 深入合作过,但我们一直认为 AWS 是我们项目的替代云服务提供商。

AWS 作为大型企业项目的行业标准而闻名。出于这个原因,AWS 提供了最大的机器选择,包括具有 448 个 CPU、12 TB 内存和 100 千兆网络的高性能机器,每小时 132 美元。除了出租虚拟机,AWS 还提供 200 多种服务来满足不同的需求。AWS、Azure 和 GCP 之间特定服务的比较是另一篇文章的主题,但总体而言,AWS 的定价平均较高,尽管就最便宜的配置而言,AWS 的价格介于 GCP 和 Azure 之间[4]。

AWS 的一个明显优势是它的成熟。AWS 变化不大。在最流行的服务中你几乎找不到任何错误,文档是广泛的和写得很好的。它的高受欢迎程度意味着你有更大的机会找到熟悉 AWS 的新员工以及也使用 AWS 的客户。

AWS 的另一个优势是它的灵活性。事实上,就云配置而言,您可以满足任何项目需求,但是可能需要的配置数量自然会增加配置的复杂性和时间。如果你的团队没有 AWS 方面的专家,复杂性有时会让人不知所措。

AWS 的个人体验

AWS 并没有带来什么惊喜,但是有两件事在我看来很不方便。第一个—如果您创建了一个标记策略,它仅在当前区域内可用。当我切换区域时,我必须重新创建策略,尽管可以选择将策略设为全局策略。

第二个不便之处也与标签政策有关。当我创建一个强制标签策略时,AWS 不允许我创建没有这些标签的 EC2 实例(这正是我想要的),但是我仍然必须键入标签名称并在下拉列表中找到它们。我希望看到已经分配了空值的标签,并在实例创建之前提示填充值。似乎我需要在 AWS 组织工具下实现一个服务控制策略来支持这样的行为。我发现这个过程对于这样一个简单的任务来说相当复杂。

AWS 提示

AWS 适合您,如果:

  • 你很富有。
  • 您的团队中有 AWS 专家。
  • 你建立一个企业级的长期项目。
  • 或者你只是想租一个便宜的虚拟机,其他的设施都不在乎。

如果你决定使用 AWS,以下是我对开发者的建议:

  • 从一些外部资料中初步学习主要概念。我强烈推荐 Coursera 上的“AWS 基础专业化”——并不是 AWS 上的所有东西都凭直觉就能弄清楚。
  • 花一些时间浏览文档并理解文档是如何组织的。

3。蔚蓝色。微软有时做得很好

出于多种原因,我们的一些客户更喜欢微软 Azure 作为云服务提供商。我注意到它在德国特别受欢迎。其中一个原因可能是由于微软团队或微软 Outlook 的流行,它们在微软 365 账户下运营,并提供对包括 Azure 在内的所有其他微软工具和服务的访问。在市场上,Azure 介于 GCP 和 AWS 之间,市场份额为 33.1%,数据显示其受欢迎程度增长[1]。说到服务数量,Azure 也被认为是 AWS 和 GCP 之间的折中选择。除此之外,微软宣传 Azure 与其他微软产品的深度集成。

虽然 Azure 在价格上被认为是一个折中的解决方案,但在低端它超级贵。他们最便宜的通用虚拟机“A0”的价格是 GCP 同类产品的 5 倍,内存却更少。它也比 AWS 的模拟产品贵 3.5 倍。最便宜的 PostgreSQL 实例“B1MS”也比 GCP 和 AWS 的同类产品贵,尽管这里的差别不是很大[5]。对于更高性能的配置类型,Azure 服务器的成本与 AWS 相同或略低。还有一点需要考虑的是,Windows 机器在 Azure 上通常比在 AWS 或 GCP 上便宜。[6]

人们经常报告 Azure 文档的问题,包括不一致、错误和缺失部分。Python SDK 也是如此。你可能会说,这只是谣言,但这是我在 Azure 上的经历。

Azure 的个人体验

Azure 在用户体验方面给我的印象最差。例如,当您选择数据库配置时,您认为“没有可用的配置,您的区域正在维护中”错误意味着什么?你能决定等一会儿维护结束吗?哈,你会永远等下去的!在 Azure 中,此错误意味着订阅设置中缺少相应的资源提供者注册。

如果你是 Azure 门户的开发者,你会首先向打开“成本分析”面板的用户展示什么?如果你的答案是“下个月的预计成本”,那么你就远远落后了。微软正在显示一个“错误请求”错误,其中有很多细节,让你有机会思考——你希望看到哪种类型的预测——做好道德准备,同时学习一些关于 Azure 内部的知识。

Azure 案例 2 演示,作者图片

你发现 Azure 机器学习了吗?这是一个非常好的平台!如果您正在创建实时端点,您知道您的源代码将被有意地交付给您的服务,并且您可以在您的评分函数中使用您的模块。这样很方便。该平台还允许您创建批处理端点。为什么你会期望你的源代码被交付呢?如果您是一个独特的人,在批处理过程中需要他们的模块,请考虑您自己独特的方式来交付代码!你是不是很绝望,想在 Azure 文档里找到答案?有一天我们都还年轻天真。啊是的,你甚至不能使用 Azure ML SDK for Python 部署批处理端点。要么创建一个发布的管道,要么使用 Azure CLI,要么使用 Azure ML Portal,因为方便的部署只是实时端点的特权。

你还可以使用 Azure 机器学习来惩罚初级开发人员或降低公司中受访者的薪资预期。例如,只需将 Flask 模块添加到 conda 依赖列表中,并要求他们部署此服务。他们会很高兴地调查一个非常有趣的错误。Azure 还保证他们不会在文档中找到任何提示。

Azure 机器学习是一个不错的平台。如果你经历了所有的不一致,那么它工作得很好。

3.2。Azure —提示

在以下情况下,Microsoft Azure 适合您:

  • 您使用 Microsoft Office 堆栈(Word、Teams、OneDrive、SharePoint 等。)和/或 C#编程语言。
  • 你既不会选择最便宜的服务器,也不会选择最贵的——你需要中间的东西。
  • 您需要内存优化的解决方案,而不是通用或计算优化的解决方案。
  • 你读到了 Azure 当前的错误和不一致,但这并没有吓到你。

如果你决定使用微软 Azure,以下是我对开发者的建议:

  • 如果因为 Azure 服务器处于维护状态超过几分钟而无法创建服务,请在“资源提供者”面板下检查您的权限和注册。
  • 如果你在 Azure 门户上看到任何奇怪的错误——只需改变过滤器的值。
  • 如果您使用 Azure 机器学习,并且您的评分函数无法定位您的源代码,请将代码作为模型交付,并将其显式添加到 init 函数中的 sys.path。
  • 如果你使用 Azure 机器学习,不要使用批处理端点——看起来它们还没有准备好——只需使用常规发布的管道。事实上,“批处理端点”只是一个已发布管道的包装器。
  • 不要在你的 Azure conda 环境规范中包含 flask。

画廊

AWS,作者图片

蔚蓝,作者图片

GCP,作者图片

结论

我提到了可以帮助您选择正确的云服务的多种差异。同时,我必须承认,所有提到的公司都以大致相同的价格提供大致相同的服务。在这种情况下,我宁愿依赖我团队的专业知识,而不是某个云服务提供商的特定功能。从我的经验来看,开发人员花费的时间比你选择更好的云服务节省的时间要多。因此,如果我的团队由 Azure 专家组成,我会坚持使用 Azure,尽管有过不好的体验。

我很惊讶这些云服务提供商通过接管如此多的事情来简化工作。可悲的事实是,这种简化不仅要花费金钱,还要花费我们的时间来更深入地了解它们并应对所有即将到来的挑战。然而,我很高兴我的云之旅还在继续,我在云方面的专业知识也与日俱增。

参考文献

[1]韦尔舍里,L. S. (2022 年 2 月 16 日)。超大规模云市场市场份额:2022 年。Statista。2022 年 5 月 6 日检索,来自https://www . statista . com/statistics/1202770/hyperscaler-iaas-PAAs-market-share

[2]谷歌云定价计算器。(未注明)。谷歌云。2022 年 5 月 6 日检索,来自https://cloud . Google . com/products/calculator/# id = 1 abd7a 80-bf53-4f 77-8006-db48d 924 dd9c

【3】谷歌云平台的与众不同之处?(未注明)。谷歌云。https://cloud . Google . com/free/docs/what-makes-Google-cloud-platform-different

[4]“AWS 定价计算器”,Calculator . AWS .https://calculator.aws/#/estimate?id = 171 ef 16 e 56 c 643 CB 303 BD 94 f 950 af0 c 0343058 ad(2022 年 5 月 6 日访问)。‌

[5]云计算服务|微软 Azure。(未注明)。Azure.microsoft.com。2022 年 5 月 6 日从https://azure.com/e/749b0305ecd74af280c0ab84ad998d8e检索

[6]森蒂斯峰,P. (2021 年 8 月 26 日)。终极云定价对比:2021 年 AWS vs Azure vs Google Cloud。投 AI。https://cast . ai/blog/ultimate-cloud-pricing-comparison-AWS-vs-azure-vs-Google-cloud-in-2021/

获得数据科学工作的曲折过程

原文:https://towardsdatascience.com/the-twists-and-turns-of-landing-a-data-science-job-ea3bf45b05be

无论你是一名刚出道的数据科学家,还是一名正在寻找新机会的经验丰富的从业者,开始求职都不是一件轻松的事情。再加上疫情、全球经济的不确定性,以及不断变化的招聘方式,事情看起来比以往更加令人生畏。

我们在这里提供帮助:TDS 作者经常写他们自己的职业轨迹,并分享在广泛的以数据为中心的领域寻找工作的见解。我们选择了几个最近的杰出人物,他们提供了具体的信息,同样重要的是!—对那些准备开始新冒险的人的启发。

  • 了解流程 。在 2021 年自己成为一名求职者后,拉希·德赛现在在她目前的工作场所参与招聘数据分析师。这个有利位置让 Rashi 清楚地了解了公司正在寻找的技能,他们如何筛选申请人,以及数据专业人员如何才能在当前的招聘环境中取得成功。
  • 重在基本面 。作为一名“经历了足够长的时间,还记得条形图上霓虹灯的颜色和渐变有多酷”的分析师,乔希·贝里(Josh Berry)非常了解变化。他还了解到,从长远来看,核心技能最重要;虽然他的建议是为那些渴望升职的人量身定制的,但它同样适用于任何寻找新职位的人。
  • 先入为主 。你可能会认为,到 21 世纪的第三个十年,简历和求职信将会成为过去。唉,他们仍然在这里——正如麦迪逊·亨特指出的,他们仍然很重要。如果你想完善你的数据科学简历,以更好地突出你最相关的技能和成就,麦迪逊的帖子是一个方便的资源。

克里斯汀在 Unsplash 上的照片

  • 如何接近面试问题 。经过多年的咨询和招聘, Brian Perron 博士已经掌握了面试数据密集型职位候选人的艺术。他利用自己的专业知识来帮助求职者理解坐在桌子另一边的人在寻找什么,以及他们应该如何设计对自己有利的答案。
  • 学会如何从挫折中反弹 。所以你参加了一个面试,觉得很顺利,然后…你没有得到那份工作。接下来呢?莎兰·库马尔·拉文德兰最近的一篇文章是对失败的诚实反思,对于那些想把一次不成功的经历转化为帮助你提高面试技巧的学习机会的人来说,这是一个有用的指南。

如果你没有在找工作,但仍然想读一些很棒的文章(或者:你正在找工作,但迫切需要考虑其他事情),你很幸运。我们本周的阅读推荐涵盖了机器学习、国际象棋等等:

  • 莉迪亚·内梅克的精彩新帖中探索噪声和数据集大小对高斯过程回归的影响。
  • 马克西姆·霍万斯基的第一篇 TDS 文章深入探讨了 AlphaZero 的内部运作,“这是一台前所未见的革命性象棋机器。”
  • 对于一个有耐心、容易理解的回归树解释者来说,读一读 T2·伊沃·伯纳多的最新作品,它展示了如何构建回归树,并展示了它们的优点和缺点。
  • 强大的数据平台满足不同利益相关方的需求;玫瑰日解释了你如何为你的内部客户提供工具,使他们能够做出基于数据的决策。
  • 我们希望你没有错过我们最近与谷歌 Cassie Kozyrkov 的问答,但如果你错过了:这里有很多关于选择正确职业道路的深刻见解以及数据分析师带来的价值和其他主题。

我们感谢您支持我们出版作品的所有方式——无论是通过阅读、与您的网络分享,还是成为媒体成员。感谢您成为我们社区的一员!

直到下一个变量,

TDS 编辑

每个程序员都应该知道的类型系统

原文:https://towardsdatascience.com/the-type-system-every-programmer-should-know-c3134a1b9bde

这可能是你最不能错过的编程知识

作者图片

本文将介绍各种编程语言中不可忽视的那些部分——类型系统。

什么是类型系统?

在学习一门编程语言时,入门课程的前几节通常会介绍该语言的各种数据类型,它们与后续的编程开发密不可分。这足以说明类型对于一门编程语言的重要性。

编程语言中的类型分类广泛,可以分为以intfloat为代表的内置类型,以及以classfunction为代表的抽象类型。区分这些类型最显著的特征是,我们只能在特定类型上使用它的特定操作。

但是什么是类型系统呢?

它实际上是一个专注于管理类型的系统,它是一个由一组规则组成的逻辑系统,这些规则将称为类型的属性分配给计算机程序的各种结构,如变量、表达式、函数或模块。

类型系统能做什么?

  1. 定义程序类型以确保程序的安全性。
  2. 可以提高代码的可读性,提高代码的抽象层次,而不是低级低效的实现。
  3. 有利于编译器优化。指定类型后,编译器可以将其与相应的字节对齐,从而生成高效的机器指令。

等等。

从以上几点可以看出,一个变量的类型可以决定一个具体的意义和用途,这对我们的编程是极为有利的。

程序中类型的本质是什么?

类型系统可以说是一个工具,我为什么这么说?

因为程序最终运行的是机器码。在机器代码的世界里,没有类型,那些指令只是处理即时数据或内存。

所以类型本质上是内存的抽象,不同的类型对应不同的内存布局和内存分配策略。

有关内存管理的更多信息,请查看我以前的文章:

静态与动态类型

我们经常听到这个问题,但是在类型检查发生的时候,两者的区别是

静态类型系统在编译时确定所有变量的类型,并在不正确使用的情况下抛出异常。

动态类型系统在运行时确定变量类型,如果有错误就抛出异常,如果处理不当可能会使程序崩溃。

静态类型系统的早期类型错误报告保证了大型应用开发的安全性,而动态类型系统的缺点是编译时没有类型检查,程序不够安全。只有大量的单元测试才能保证代码的健壮性。但是使用动态类型系统的程序很容易编写,并且不需要花费很多时间来确保类型是正确的。

作者图片

强类型与弱类型

强类型和弱类型的区别没有权威的定义。早期关于强分型和弱分型的讨论,大多可以概括为静态分型和动态分型的区别。

但流行的说法是,强类型往往不容忍隐式类型转换,而弱类型往往容忍隐式类型转换。这样,强类型语言通常是类型安全的,也就是说,它只能以允许的方式访问它有权访问的内存。

作者图片

常见编程语言

我总结一个常见编程语言类型的分类图,注意拆分的四个区域都是分区,比如 PHP 和 JS 都是动态弱类型。

作者图片

今天就到这里。我是 Zachary,我会继续输出与 web 开发相关的故事,如果你喜欢这样的故事并想支持我,请考虑成为 中级会员 。每月 5 美元,你可以无限制地访问媒体内容。如果你通过 我的链接 报名,我会得到一点佣金。

你的支持对我来说非常重要——谢谢。

地理空间栅格数据入门指南

原文:https://towardsdatascience.com/the-ultimate-beginners-guide-to-geospatial-raster-data-feb7673f6db0

关于栅格文件、地理配准、元数据和栅格 Python 库,您需要了解的一切

丹尼尔·科鲁奇在 Unsplash 上的照片

大多数航空照片和卫星图像都是光栅文件。
这种格式常用来表示现实世界的现象。如果您正在处理地理数据,那么您很有可能必须处理它。

要在 Python 中使用地理栅格文件,需要不同的理论概念。在进入编程部分之前,我强烈建议您阅读介绍性部分。

目录

  1. 简介:第一概念。
  2. 应用:栅格用在哪里?
  3. 色彩映射表:离散和连续色彩映射表,用于可视化栅格。
  4. 地理参考: CRS 和仿射变换。
  5. 栅格的元数据:与栅格相关的所有数据。
  6. Rasterio: 在 Python 中读取、保存、地理配准和可视化栅格文件。

介绍

栅格由按行和列组织的像元(或像素)矩阵组成,其中每个像元包含一个表示信息的值

光栅结构。图片由作者提供。

地理栅格中的每个像素都与特定的地理位置相关联。这意味着如果栅格的分辨率为 1 m/px ,每个像素覆盖 1m 的区域。有关这方面的更多详细信息,请参见地理配准部分。

此外,

栅格包含一个或多个大小相同的图层,称为波段

三波段栅格。图片由作者提供。

任何类型的数值都可能存储在一个单元格中。根据上下文,单元格可能包含不同范围内的整数或浮点值。

jpg、png 和位图都是光栅文件,但是本指南不考虑它们,因为它们是非地理文件。地理栅格通常以 TIFF 格式保存。

应用程序

照片由 NASAUnsplash 上拍摄

由于栅格的应用方式多种多样,以下是最常见的应用:

  • 卫星图像
  • 专题地图
  • 数字高程模型(DEM)

卫星图像

来自卫星的影像通常保存在多波段栅格中。电磁波谱被分成多个部分,可以被卫星探测到。并不是所有的都属于可见光谱,但通常有些是在红外波段,人眼是看不见的。

栅格文件非常适合这种类型的影像,因为卫星感测到的每个电磁波谱部分都可以存储在波段中。

Sentinel-2 是最受欢迎的卫星之一,它使用 13 个光谱带拍摄照片,一部分来自可见光谱,另一部分来自红外光谱。因此,每个输出文件都是一个包含 13 个波段的栅格(其中 3 个波段为红色、绿色和蓝色)。

以下是从 Sentinel-2 拍摄的照片(仅显示 RGB 波段):

明斯克市(白俄罗斯),哨兵-2 卫星图像。包含修改后的哥白尼哨兵数据 2019CC BY-SA 3.0 IGO ,via Wikimedia Commons。

专题地图

专题地图用于对地理区域进行分类。每个区域都与共享某些特征的特定类别相关联。例如,我们可以根据种植园的类型对农业区进行分类。栅格非常适合此任务,因为每个像元都可以存储表示像素关联区域所属类的整数值。

以下是意大利伦巴第大区的专题地图示例。根据类别,每个像素存储 0 到 6 之间的值:

伦巴第(意大利),专题地图。图像来自 Sentinel-2 图像时间序列,用于作物制图

数字高程模型(DEM)

数字高程模型用于表示地表起伏。DEM 是一种栅格,其像素包含浮点值:表面的高程值。

这里显示的是火星表面区域的 DEM:

火星表面的一个陨石坑。图片来自 UAHiRISE (已编辑)。

为了使第一个文件可视化,只显示了可见的波段,但是第二个和第三个文件不能直接可视化,因为保存在每个单元格中的值不是一种颜色,而是一条信息。

在下一节中,将重点介绍可视化这种栅格文件所需的解决方法。

彩色地图

亚历山大·格雷在 Unsplash 上拍摄的照片

由于栅格对可存储的数值类型和范围没有限制,因此并不总是能够直观地显示它们。例如,我上面显示的最后一幅图像是两个单波段光栅:在前者中,每个像素是一个介于 0 和 6 之间的整数,而在后者中,是一个介于 -4611 和- 3871 之间的浮点数。他们的信息不代表一种颜色

为了直观显示这些类型的栅格,我们使用色彩映射表,即

将单元格值映射到颜色的函数

因此,当通过色彩映射表可视化栅格时,其值将被颜色替换。

彩色地图主要有两种类型:连续非连续

非连续彩色地图

它们是通过使用值-颜色对定义分段函数来实现的。

在专题地图示例中,我定义了 7 个值-颜色对:<0, black>、<1, red>、❤️, orange>、<4, yellow>、<5, blue>、<6, gray>、<2, green>。

不连续的色彩映射表。图片由作者提供。

当栅格包含一小组值时,通常使用这种方法。

连续彩色地图

它们是通过使用连续函数将栅格值的间隔与颜色的间隔相关联而得到的。

通常,在应用此类色彩映射表之前,会使用以下公式在范围[0,1]内缩放所有栅格值:

最小-最大比例公式。使用编码生成的图像

在灰度色图中,使用线性函数将[0,1]范围内的值与[0,255]范围内的灰度值相关联:

灰度色图。图片由作者提供。

彩条以适当的方式显示结果:

灰度色图。图片由作者提供。

在这种情况下,0 值用黑色表示,1 值用白色表示,它们之间的所有值用不同形状的灰色表示。

为了更好地可视化栅格,我们还可以定义一个 RGB 色彩映射表,其中每个栅格值都与一个红色、绿色和蓝色值相关联。

以下是文献中称为 Turbo 的流行色彩映射表:

Turbo 色彩映射表。图片由作者和查表从这里

该色图以蓝色阴影开始表示最低值,以红色阴影结束表示最高值:

Turbo 色彩映射表。图片由作者提供。

在 DEM 示例中,我使用这种颜色图将高程信息转换成颜色。这是将一系列值映射到颜色时使用的颜色映射表(而不是像非连续颜色映射表中的小集合)。

地理参考

Unsplash 上的 GeoJango Maps 拍摄

地理栅格中的每个像元覆盖一个特定的地理区域,其坐标(由行和列表示)可以转换为现实世界的地理坐标。翻译过程使用两个组件:T4 坐标参考系统(CRS)T5 和仿射变换 T7。

在继续之前,重要的是要知道地球的形状是通过一个几何图形来近似的,称为旋转椭球椭球。由于这个数字是一个近似值,多年来已经使用不同大小的轴定义了多个球状体。

球体。 Ag2gaehCC BY-SA 4.0 ,via Wikimedia Commons(已编辑)。

坐标参考系统

CRS 是一种用于精确测量地球表面坐标位置的框架

每个 CRS 都基于特定的椭球体,因此,如果两个 CRS 使用不同的椭球体,则相同的坐标表示两个不同的位置。

CRS 可以分为:

  • 地理坐标系,利用角度单位(度)。角距离从定义的原点开始测量。
  • 基于地理坐标系的投影坐标系。它使用空间投影来投影椭球体,空间投影是一组用于将 3D 数据展平到 2D 平面上的数学计算。它使用线性单位(英尺、米等)。)来测量该位置距离平面原点的距离(在两个轴上)。

最流行的地理坐标系之一是 WGS84T3【也称 EPSG:4326 。它基于一个椭球体,其半短轴(称为赤道半径)等于 6378137 米,半长轴(称为极地半径)等于 6356752 米。WGS84 使用纬度来找出一个地方距离赤道多远,使用经度来找出一个地方距离本初子午线多远。两者都以度为单位。

地球的纬度和经度。Djexplo ,CC0,通过维基共享。

例如40° 43 ' 50.1960 ' ' N,73° 56 ' 6.8712 ' ' W是使用经纬度的纽约市位置。

而最流行的投影坐标系之一是 UTM / WGS84 ,也称为 EPSG:32632 。它将 WGS84 球体投影到一个平面上,然后使用(x,y)以米为单位定义坐标。

栅格文件中使用的 CRS 取决于多种因素,例如数据的采集时间、数据的地理范围和数据的用途。请记住,您可以将 CRS 的坐标转换为另一个坐标。也有用于地球外表面地理参考的 CRS,如月球和火星。

仿射变换

地理配准栅格使用仿射变换从影像坐标映射到真实坐标(采用 CRS 定义的格式)。

仿射变换用于将像素位置映射到所选的 CRS 坐标中

仿射变换是保持共线性(如果三个或三个以上的点都位于同一条直线上,则称它们共线)和直线上各点之间的距离比的任何变换。

这些都是仿射变换:

仿射变换。图片由作者提供。

在地理配准中,大多数情况下,只需要进行缩放和平移变换。将它们与正确的系数一起应用,可以将栅格像元坐标转换为真实坐标。读取地理栅格时,这些系数已经在元数据中定义。

用于转换的关系是:

光栅坐标和 CRS 坐标之间的关系。使用编码生成的图像。

如果 scale_xscale_y 是 CRS 单位(度、米、英尺等)中的 pixel_widthpixel_height 。), r 是图像在现实世界中的旋转x_originy_origin 是光栅左上角像素的坐标,参数为:

  • a = scale _ x cos(r)
  • b = scale _ y sin(r)
  • c = x _ origin∙cos(r)+y _ origin∙sin(r)
  • d = scale _ x sin(r)
  • e = scale _ y cos(r)
  • f = x _ origin∙sin(r)+y _ origin∙cos(r)

请记住,根据所使用的 CRS,scale_x、scale_y、x_origin 和 y_origin 中的一个或多个可以是负值。

由于大多数图像都是朝北,因此 r = 0 ,参数可以简化为:

  • A =标度 x
  • B = 0
  • C = x _ 原点
  • E =比例 y
  • D = 0
  • F = y _ 原点

地理参考示例。图片由作者提供。

a 和 E 定义缩放比例,而 C 和 F 定义从原点的平移。

[计]元数据

每个地理栅格都有关联的元数据。以下是最重要的字段:

元数据字段。图片由作者提供。

深部热疗

此字段存储坐标参考系统的信息,例如名称、测量单位、椭球体轴和原点坐标。

转变

它存储用于将光栅像素坐标映射到 CRS 坐标的系数 A、B、C、D、E、F。

数据类型

通常被称为数据类型。它定义了存储在栅格中的数据类型,如 Float32、Float64、Int32 等。

NoData 值

栅格的每个像元都必须包含一个值,并且栅格不支持空值。如果生成栅格的源无法为某些像元提供值,则使用 nodata 值填充这些像元。如果 nodata 值设置为 0,这意味着当读取 0 时,它不是一个要考虑的值,因为它表明源不能提供正确的值。通常,栅格数据类型为 Float32,将 nodata 值设置为-3.4028235 10 ⁸.

宽度、高度和带数

它们分别是每个波段的宽度、每个波段的高度和栅格的波段数。

驾驶员

驱动程序为光栅文件提供了更多功能。大多数情况下,地理栅格使用 GTiff 驱动程序,该驱动程序允许将地理配准信息集成到文件中。

拉斯特里奥

第一个用于访问地理栅格文件的库是[地理空间数据抽象库,GDAL](http://GT(1) × GT(5) = 10m × 10m) 。它最初是用 C 开发的,后来扩展到 Python。这样,Python 版本只提供了对 C 版本的少量抽象。基于 GDAL 的 Rasterio 试图通过提供一个更简单、更高级的接口来解决这个问题。

要从 PyPI 安装最新版本的 Rasterio,请使用:

pip install rasterio

这些是必需的导入:

import rasterio
from rasterio.crs import CRS
from rasterio.enums import Resampling
from matplotlib import pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
from pprint import pprint

读取栅格

要打开光栅文件,请使用:

raster = rasterio.open('raster.tiff')

要打印波段数,请使用:

print(raster.count)

要将所有栅格作为 NumPy 数组读取,请使用:

raster_array = raster.read()  # shape = (n_bands x H x W)

或者,要仅读取特定波段,请使用:

first_band = raster.read(1)  # shape = (H x W)

请记住,波段索引从 1 开始。

要读取与栅格相关联的所有元数据,请使用:

metadata = dataset.meta
pprint(metadata)

输出:

{'count': 1,
 'crs': CRS.from_epsg(32632),
 'driver': 'GTiff',
 'dtype': 'uint8',
 'height': 2496,
 'nodata': 255.0,
 'transform': Affine(10.0, 0.0, 604410.0,
       0.0, -10.0, 5016150.0),
 'width': 3072}

读取栅格时,可能没有数据值,建议用 NaN 值替换它们。为此,请使用:

first_band[first_band == metadata['nodata']] = np.nan

要按给定因子调整栅格的大小,首先定义输出形状:

out_shape = (raster.count, int(raster.height * 1.5), int(raster.width * 1.5))

然后使用:

scaled_raster = raster.read(out_shape=out_shape,
                resampling=Resampling.bilinear)

请记住,缩放栅格后,仿射变换的 A 和 F 系数必须更改为新的像素分辨率,否则,地理配准将给出错误的坐标。

形象化

要使用色彩映射表和色彩条显示栅格波段,请使用:

fig, ax = plt.subplots()
im = ax.imshow(raster.read(1), cmap='viridis')
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.10)
fig.colorbar(im, cax=cax, orientation='vertical')
plt.savefig('cmap_viz')

输出:

光栅可视化示例。图片由作者提供。

对于多波段卫星栅格,要显示前 3 个可见波段,请使用:

rgb_bands = raster.read()[:3]  # shape = (3, H, W)
plt.imshow(rgb_bands)

通常,卫星影像在前三个波段存储 RGB。如果不是这种情况,则必须根据波段的顺序来改变索引。

地理参考

通过以下方法获得的坐标将被返回,并且必须使用当前的 CRS 单位提供。

要查找像素(I,j)的实际坐标,其中 I 是行,j 是列,请使用:

x, y = raster.xy(i, j)

做相反的用法:

i, j = raster.index(x, y)

要显示数据的界限:

print(raster.bounds)

输出:

BoundingBox(left=604410.0, bottom=4991190.0, right=635130.0, top=5016150.0)

本例中的栅格是使用 ESPG:32632 作为 CRS 进行地理配准的,因此输出坐标以米为单位。

保存栅格

步骤 1 —找到所需 CRS 的 EPSG 代码,然后检索其信息:

crs = CRS.from_epsg(32632)

在此示例中,使用了 EPSG:32632,这在本指南的第四部分中有所提及。

步骤 2-定义仿射变换:

transformation = Affine(10.0, 0.0, 604410.0, 0.0, -10.0, 5016150.0)

系数 A、B、C、D、E、F 的用途已在本指南的第四部分进行了解释。

步骤 3-保存栅格:

# a NumPy array representing a 13-band raster
array = np.random.rand(13,3000,2000)
with rasterio.open(
    'output.tiff',
    'w',
    driver='GTiff',
    count=array.shape[0],  # number of bands
    height=array.shape[1],
    width=array.shape[2],
    dtype=array.dtype,
    crs=crs,
    transform=transform
) as dst:
    dst.write(array)

如果不需要地理参考,设置crs = Nonetransform = None

write 方法还有另一种语法:

dst.write(array_1, 1)
# ...
dst.write(array_13, 13)

但是在大多数情况下,编写一个单独的 3d 数组更容易。

结论

本指南展示了在栅格(由一个或多个相同大小的矩阵组成的集合,称为波段)中,每个像元包含一条信息。这些信息根据任务而变化,例如卫星图像、专题地图和数字高程模型。此外,根据应用程序的不同,您可能需要色彩映射表来将其可视化。此外,您发现使用坐标参考系统和仿射变换,可以将每个细胞位置映射到真实世界的坐标。最后,您会看到 Rasterio 使读取、写入、可视化和地理参考操作变得非常容易。如果您需要一个程序来打开栅格, QGISArcGIS 是不错的选择。

附加资源

感谢阅读,我希望你发现这是有用的。

终极指南:机器学习模型部署的挑战

原文:https://towardsdatascience.com/the-ultimate-guide-challenges-of-machine-learning-model-deployment-e81b2f6bd83b

动机

“机器学习模型部署很容易”

这是一个我听过很多次的神话。作为一个有工程背景的数据科学家,我也有这个观点,直到实际开发了一个机器学习部署(或 MLOps )项目。从技术上讲,部署机器学习(ML)模型可能非常简单:启动一台服务器,创建一个 ML 推理 API,并将该 API 应用于一个现有的应用程序。不幸的是,这个工作流程太容易出现了,以至于人们往往低估了它的复杂性。事实上,我的一些 ML 工程师朋友抱怨说,他们的工作不被这么多人理解,例如来自不同团队的工程师、产品经理、执行团队,甚至客户。

不要根据提示来判断 MLOps 项目的复杂性。西蒙·李在 Unsplash 上的照片

通过这个故事,我希望更多的人能够理解 MLOps 背后的困难。我想穿上工程师裤,与你分享 ML 模型部署挑战的终极指南。

背景:ML 工程师与数据科学家紧密合作。例如,数据科学家构建 ML 模型,ML 工程师实现模型。

第一阶段:当一个模型刚刚交给 ML 工程师时

照片由 ETA+Unsplash 拍摄

“该模型实际上无法在生产服务器上运行”

当数据科学家将他们的模型传递给 ML 工程师时,该模型可能无法在不同的机器上工作。这个问题通常是由软件 环境变化或者代码质量差造成的。

DockerK8s 这样的容器能够通过跨机器调整软件环境来解决大部分的复制问题。然而,模型容器化并不是每个数据科学家(DS)都具备的技能。如果这种情况发生,DS 和 ML 工程师将需要额外的时间来交流知识。

另一方面,服务器和 ML 框架之间的编译也会导致系统错误。例如,尽管 Flask + Tensorflow 是许多教程中使用的组合,但有一段时间我们发现,随着环境变得越来越复杂,Flask 服务器环境对 Tensorflow 2 并不友好。我们花了一段时间才找到解决办法。

数据科学家不是程序员。写代码时遵循 PEP 8 指南对于数据科学来说并不是必须的。一个 ML 工程师声称的“糟糕的代码质量”可能来自于科学家和工程师之间不同的编码习惯。Jupyter Notebook 取代了 VS Code 等传统 IDE,是一款更受数据科学家欢迎的代码编辑工具。笔记本中的编程逻辑与普通的软件开发非常不同。因此,当代码模型从 Jupyter Notebook 迁移出来时,它可能会出错。

如果生产服务器使用与开发服务器不同规格(例如,操作系统、CPU 类型、GPU)的机器,那么 MLOps 项目将会上升到更高的复杂性水平。

阶段 2:当团队开始合作时

假设来自数据科学团队的 ML 模型现在可以在生产环境中成功运行,那么是时候将它迁移到现有的应用程序中了。然而,在哪里以及如何在应用中使用模型来解决实际的业务问题是一个新的课题,需要跨团队的协作。

杰森·古德曼Unsplash 上的照片

“我们为什么要关心……”

由于分散的责任和优先权,跨团队的沟通面临许多挑战。工程师们关心软件的效率、系统的稳定性和易维护性。然而,大多数决策支持系统更关心 ML 模型的性能和严密性。为了最大化模型性能,他们总是利用各种数据科学工具。我见过 DS 的同事用 SQL 预处理数据,用 R 启动模型管道,然后是 Sklearn,最后是 Pytorch。当然,这种结构是不会被工程师欣赏的。

当 DS 和 ML 工程师争论什么应该更优先时,产品经理(pm)进入舞台并要求两个团队关注路线图,因为pm 的责任是确保产品交付按时发布

“有意思,部署 ML 车型的门票正在引发团队辩论……”

没有固定的解决方案来避免这种纠结。软件效率,ML 模型性能,路线图,哪个更有意义?答案是企业与企业之间的转移,而且永远不会完美。

阶段 3:当模型即将发布时

团队最终为了彼此的需要而妥协。工程团队还成功地将模型推理功能添加到应用程序中。一切看起来都很好,不是吗?

“等一下,模型托管服务器应该支持多少流量?”

压倒性的系统日志。由 Markus SpiskeUnsplash 上拍摄的照片

当涉及到用户吞吐量问题时,如果一家公司资源丰富,最值得推荐的解决方案是购买一组功能强大的服务器,即使在高峰时也足以处理所有流量负载。然而,用于容纳 ML 模型的机器是稀缺和昂贵的。8 个 V100 核心的按需 p 3.16 x 大型 AWS 服务器的定价为每小时 24.48 美元,每月 17625.6 美元。

可悲的是,上述解决方案只有少数公司负担得起。对于其他公司来说,根据需要扩展计算能力更实际,但即使对于高级 ML 工程师来说也很有挑战性。数据搜索、并发、一致性和速度是伸缩系统中的四个常见问题。更糟糕的是,由于服务器容量的不足,ML 的可扩展性更加困难:假设你的项目中最常用的云服务器叫做服务器 A,在传统的扩展系统中,你只需要考虑你应该扩展到的服务器 A 的数量。但是在机器学习中,即使在 AWS 这样的大型云平台中,服务器 A 也并不总是具备容量,因为它是稀缺的。您的扩展策略还应该包括具有更高容量的其他类型的服务器。负载测试需要对所有种类的组合进行。还可以添加新的云平台,这样,如果服务器 A 在一个平台上不可用,您仍然有机会通过查找其他平台来获得一个。因此,很少有 ML 项目最终开发出成熟的缩放系统。

阶段 4:当模型被部署时

恭喜你!您最终部署了模型,但现在还不是离开的时候。

“什么?挑战还没结束?”

即使你是一个在这个行业工作了 10 年的有经验的 ML 工程师,你的 ML 基础设施也不会一直在运转。其实如果你是有经验的,你应该比我更担心 ML 系统变质。

不稳定堆积的石头。照片由科尔顿鲟鱼Unsplash 上拍摄

恶化来自两个方面:工程方面和数据科学方面。

在工程方面,内部软件迭代可能是关闭机器的主要原因,特别是当模型部署模块与应用程序的其余部分高度集成时。当一个软件更新时,它可能会破坏其他的连接部分。隔离模块可能是一个解决方案,但是缺点是开发速度变慢,因为重用的工作减少了。同样,引入和升级外部软件包也会对系统稳定性产生负面影响。例如,当版本升级时,R 包以破坏模型脚本而闻名。

在最坏的情况下,工程师可能会犯错误。曾经有一段时间 Google Photo 工程师不小心部署了一个性能很差的模型,它把黑人朋友认成了“大猩猩”。

在数据科学方面,随着时间的推移,数据转移是模型性能的一大杀手。数据偏移被定义为来自 ML 模型的输入和输出数据之间的潜在关系的改变。如果发生数据转移,数据科学家将需要重新训练旧模型。反馈回路是克服数据偏移的解决方案之一。它检测性能变化,并通过新收集的数据重新训练部署的模型。是的,你是对的。这种解决方案也有不利的一面。模型可能存在严重偏差,偏差问题难以识别。

“假设一家杂货店使用 ML 模型来预测下个月的库存变化。该模型预测瓶装水是下个月最受欢迎的商品,因此店主采纳了它的建议,储备了更多的瓶装水。因为有更多的瓶装水,下个月最畅销的商品确实是瓶装水,这个数据作为新收集的数据被再次输入到 ML 模型中。结果,反馈回路使模型非常偏向瓶装水,总是要求所有者获得更多的瓶装水……当然,这种预测是不恰当的。”

为了检测退化,监控系统在模型部署中是必不可少的,这也是最后一个挑战点。监视器需要是实时的,检测异常事件,发送警报,收集 ML 度量,跟踪模型性能,等等。

结束了

这篇博客描述了工程团队在部署 ML 模型时可能面临的挑战。我描述了时间序列中的挑战。总结一下:

  1. 阶段 1 中的挑战:当从开发环境迁移到生产环境时,模型可能会有不同的行为。
  2. 阶段 2 中的挑战:当在生产中将 ML 模型添加到现有的应用程序中时,很难满足所有团队的需求。
  3. 第 3 阶段的挑战:构建可扩展的计算能力来服务模型是必要的,但也是艰难的。
  4. 第四阶段的挑战:ML 系统总是随着时间而恶化;应该建立一个监测系统。

一个常见的团队配置是每个数据科学家有 2-3 名数据工程师,在一些具有更复杂数据工程任务的组织中,这个数字可能会超过 5 名。这种说法与我的经验相关,即 ML 模型部署总是比模型开发花费更长的时间(除了由学术界领导的旨在给整个 ML 世界带来翻天覆地变化的研究)。为了保持故事的简洁,我在解释一些挑战时仍然保持高水平。如果你有兴趣了解更多的细节,请加入我的不和谐社区来 DM 我:【https://discord.gg/vUzAUj7V。

关于我们

我们来自 Aipaca 团队,构建一个无服务器的 MLOps 工具 Aibro,帮助数据科学家训练&在 2 分钟内在云平台上部署 AI 模型。与此同时,Aibro 采用了专为机器学习打造的成本节约战略,将云成本降低了 85%。

AIpaca Inc .图片作者

摄影测量三维重建终极指南

原文:https://towardsdatascience.com/the-ultimate-guide-to-3d-reconstruction-with-photogrammetry-56155516ddc4

三维重建

使用 3D 摄影测量、现实捕捉、网格空间和 Blender 的完整动手 3D 重建教程。

如何通过简单的工作流程将 3D 图像转化为 3D 资产。弗洛伦特·普克斯

我们生活的时代是超级令人兴奋的,如果你对 3D 感兴趣,那就更令人兴奋了。我们有能力使用任何相机,从感兴趣的对象捕捉一些图像数据,并在眨眼之间将它们转化为 3D 资产!这种通过简单的数据采集阶段实现的 3D 重建过程对于许多行业来说都是一个改变游戏规则的过程。你喜欢电子游戏吗?很好!电影?甚至更好!映射?没错!机器人技术?医学?3D 打印?我会就此打住;你抓住了重点。我会开始腐蚀你,让你追求无限的 3D 力量!

随着新的尖端 3D 重建方法的兴起,如神经辐射场(又名 NeRF ),回到某种程度上“基础”而不是“基本”是必不可少的,这应该有助于减轻宣传(除其他外😄).

从图像进行三维重建是一个广泛研究的领域,有一个超级激动人心的故事,它通过三个研究“振动”得到了历史性的解决:具有立体视觉和运动结构的计算机视觉(SFM),具有各种同步定位和绘图(SLAM)迭代的机器人技术,以及具有摄影测量视角的地理信息学。这些术语主要针对传感器相对于其周围环境的同步定位(位置和方向),同时构建这些周围环境的 3D 地图。

今天,我们对 metric 方法感兴趣,它可以建立在一组非结构化的重叠图像上,并将它们转化为 3D 对象。还有什么比我们自己做更好的理解方式呢?

本指南详细介绍了 3D 摄影测量工作流程。它包括现实捕捉,网络空间和搅拌机软件的直接使用。F. Poux

让我们开始吧!

Introduction

1\. The Small Scale Object (The Hands-on basics)
  Step 1\. Data Acquisition
  Step 2\. Data Processing
    Option A. Reality Capture
    Option B. Meshroom

2\. The Large Scale Project (Advanced Photogrammetry)
  Step 1\. 3D Data Acquisition
  Step 2\. 3D Data Processing
    Option A. Reality Capture
    Option B. Meshroom

Conclusion

介绍

在这本终极 3D 重建指南中,我们将详细探索的两个摄影测量项目,并解释导致最终美丽结果的所有步骤。我们将研究一个小规模项目(通过摄影测量重建一个简单的对象)和一个大规模项目(使用地面激光扫描仪和摄影测量重建一个废弃的羊毛工厂)。

对于每个项目,我们将经历采集设置和处理步骤,展示带有付费选项(现实捕捉)和开源软件(网络空间)的工作流程。

为了便于复制,我有意给出了最大限度的细节和插图。因此,这种语气比通常的要浓一点,但是希望,当你日常活动中的事情变得模糊时,它可以作为一个精确的配方😁。

我正在 3D 扫描羊毛工厂。然后,产生的点云充当主干来注册各种图像视角。图片由 R. Robroek 提供

如果你有时间的话,现在就按照这个过程,准备好创建感兴趣的物体和场景的数字复制品。

小尺度物体

让我们首先研究一个简单的项目,你可以在家里用一台基本的相机和一台电脑轻松复制。这个项目旨在获得一个简单物体的三维重建(更准确地说,是一个迷你矿井装饰)。物体的大小大致为 151010 厘米。这个物体是灰色和棕色的,表面粗糙。

要重建的对象。

第一步。数据采集

正如承诺的那样,必需的装备很容易得到。只需要一个摄像头(你的智能手机可以工作),如果需要更多的稳定性和控制,可以使用三脚架,但没有它也有可能工作。使用的相机是佳能 EOS 50D,配有佳能超声波镜头。照片以 JPG 格式保存,尺寸为 4752*3168 像素。在开始采集之前,我们拍几张照片来确定应该使用什么设置。在我们的实验中,我们将相机参数设置如下:

  • 焦距:28 mm 的固定焦距,在到主体的距离和可工作区域之间给出了良好的平衡;
  • ISO: 400,这是一个很好的开始值,但是如果你的场景看起来太暗,你可以把这个值提高到 1600(风险自负😁);
  • 光圈开口:F/3.5,允许以有限的景深为代价获得足够的光线。在我们的例子中,由于我们只关注一个微小的物体,我们在这里很好。
  • 快门速度:125 毫秒(1/8 秒),由于更稳定,我们的三脚架允许这一速度。没有三脚架,1/200s 以下超级棘手;
  • 白平衡:4000 K。这适应我们场景的环境照明。

上述参数在整个采集过程中保持不变。

相机设置。

收购战略本身很简单。我们将相机放在三脚架上,调整高度和角度,使物体完全适合视野。在这种情况下,由于物体相对较低,我们可以给相机一个向下的角度,这样我们也可以拍摄顶部。我们使用自动对焦来确保照片不会模糊,然后切换到手动模式

采集设置。

然后,我们沿着围绕物体的圆形轨迹移动三脚架。我们需要与物体保持恒定的距离,这样焦点才能保持正确。我们边走边检查照片。一旦我们完成了物体周围的第一圈,我们就缩小三脚架的腿,降低相机向下的角度。我们调整焦距,然后再次切换到手动模式。我们在主题周围多拍几张照片。

最后,我们将相机从三脚架上取下,拍摄完整物体的垂直照片。为此,我们再次调整焦点。然后,我们拍摄详细的照片,以确保物体所有部分的纹理都完好无损。这个想法基本上是拍摄足够多的照片,以允许完整和详细的重建,同时记住不必要的大量输入只会减慢和复杂化这个过程。理想情况下,对于这样一个物体,你有 25 张图片(8 个水平位置乘以三层高度,再加上最上面的一张)。

单一物体摄影测量的 3D 采集设置图。F. Poux

现在,我们可以把照片复制到电脑上,然后开始处理!👌

第二步。摄影测量处理

首先对照片进行分类,剔除那些只会干扰后续步骤的劣质图像(模糊、不在画面内、曝光错误)。从 50 张照片中,我们剔除了两张稍微失焦的照片。为了进行处理,我不得不找一台旧的笔记本电脑,配备相当标准的组件来证明可复制性😁:笔记本电脑是宏碁 Aspire,Windows 10 64 位;英特尔酷睿 i5 第七代处理器;12 Gb 内存,和一个 NVIDIA GeForce 940 MX GPU。相对于下一个将要评审的项目,并且考虑到输入的数量较少,使用高性能的计算机比可选的多!

现在,所有的测试平台都清楚了,让我们通过一个带有现实捕捉和网格空间的工作流程来深入了解 3D 摄影测量处理细节。

选项 A:现实捕捉。

现实捕捉的选择非常简单:你可以免费做任何事情…只要不输出任何东西。所以,没有什么比展示最先进的专业软件更好的了。

🦚 注意 : 我对植入式广告很谨慎,我真心相信客观测试。我不希望认可解决方案,而是提供明确的信息和知识来指导用户做出明智的决策。因此,我想说的是,在所有的摄影测量解决方案中,现实捕捉对某些事情来说是非常好的,但其他解决方案对其他事情来说更好。经典的候选软件包括 Metashape (Agisoft)、ContextCapture (Bentley Systems)、3D 泽法、Pix4D、…

你可以用这个提供的链接直接下载 Reality capture。一旦程序安装完毕,你就可以通过“匿名”注册,以 PPI 模式(按输入付费)免费试用许多在线教程和讨论有助于开始现实捕捉。第一步是创建一个新项目并导入我们的 48 张图片。这可以通过拖放或点击“输入”图标来完成。

数据导入。

然后,我们从“校准”选项卡中的第一个图标开始校准。对于这个项目,我们保留默认参数。

对齐。

考虑到输入数量少,校准只需 30 秒即可完成。在这一步之后,我们有一个组件,它由一个点云和摄像机的估计位置组成。呜哇!🎉

点云和相机位置。俯视图(左);侧视图(右)。

我们可以检查所有输入是否对齐,并看到 48 个摄像机中的 48 个摄像机的位置是估计的。我们还检查了校准报告。该报告提供了校准持续时间、校准输入的数量、点数以及平均和最大重新投影误差(以像素为单位)。也可以检索使用过的校准设置。

比对报告。

💡提示 : 最好将最大投影误差设定为 2 个像素,平均投影误差低于 0.5 个像素。当然越低越好。有趣的是,你可以看到我们回答了这两个标准。最重要的是,我们获得了平均轨迹长度信息,可以清楚地了解相机到物体的距离。

最后,对点云进行视觉检查。如果一切正常,我们可以进行下一步,重建。我们保留默认参数,除了“图像缩小”因子被设置为 2。

💡提示 : 缩小系数是图像在使用前缩小的系数。可以将缩小比例保持在 1(这意味着图像以其原始大小使用),但重建可能需要更多时间。当使用较高的缩减系数时,结果可能会更嘈杂或更不详细。然而,这种差异有时非常微妙。使用一个能给出令人满意的结果和可接受的处理时间的缩减因子确实很重要(在这种情况下,它不是关键的,但对于更重要的项目是必不可少的)。

点击“重建”选项卡中的“普通细节重建”图标,启动重建。这一步只需要五分钟,就能生成大约一百万个三角形面的网格。与地球上的国家数量(2023 年为 195 个)相比,这是一个很大的数字,但与我们通常的工作相比,这是非常小的数字。用“高级”选择工具,我们选择边缘和大三角形,然后过滤选择。我们还调整了重建框,以消除属于放置对象的家具的部分(“框”选择工具)

重建按钮(左)、滤镜选择工具(中)和可能的滤镜选项(右)

我们现在可以看看我们的过滤模型。在这一步,分析你得到的质量是很重要的,因为在这种模式下,很容易发现应该修复的几何问题。就我所见,我对这一步的结果很满意。你呢?你的实验进展如何?

生成的三维网格

最后一步是纹理网格。为此,我们保留默认参数,并单击“重建”选项卡中的“纹理”按钮。默认情况下,纹理使用的缩减系数为 2。

纹理菜单

又过了两分钟,我们终于得到了这个物体的数字复制品。

纹理网格。

不到一个小时(包括采集和处理时间)的时间里,我们设法获得了一个完整的物体的 3D 模型,并且与实物高度逼真。最大重投影误差被设置为低于 2 个像素,并且我们获得了 0.46 个像素的平均误差。模型的某些区域比其他区域具有更好的纹理。在这种情况下,由于我们手头有物体,采集设置也准备好了,通过拍摄缺少信息的零件的照片,纹理问题可以很容易地解决。这表明,具有现实捕捉的 3D 摄影测量可以非常有效,并且即使不是专家也相对容易操作。我们保留了默认的参数,得到了令人满意的结果。显然,对于更广泛或复杂的项目,理解并调整每个任务的设置以获得最佳结果是至关重要的。这就是我们将在第二章检查的内容。😉

🦚 : 如果你想导出模型,要么必须购买许可证,要么免费使用 PPI 模式下的程序,只为最终结果付费。

选项 B:网络空间。

Meshroom 是一个开源程序,可以在这个地址下载:https://alicevision.org/。在线提供用户手册。

通过拖放或点击“文件”顶部菜单中的“导入图像”将图像导入到 Meshroom 中。在 Meshroom 中,您可以轻松地可视化管道以及为获得最终结果而执行的不同任务(图 15 )。可以通过添加或修改节点的参数来适应用户的需求。

网格管道的数据导入和提取及其相应的任务监控。

我们可以看到执行的连续任务是特征提取、图像匹配、特征匹配、运动结构、深度图的创建、网格化和纹理化(关于这些步骤的详细解释,请参见第二章第 2 节)。对于这个项目,我们保留默认的管道,这通常会给出好的结果,只需单击屏幕顶部的“开始”按钮。2 小时后,处理完成,我们可以研究 3D 视图中的稀疏点云结果,以及摄像机的估计位置。

网格计算后的稀疏点云和相机位置。

如果我们点击管道节点,我们有一个关于每个任务的简短的报告。例如,我们可以看到所有 48 个摄像机的位置都是估计的。我们还可以检查网格任务的报告,它告诉我们重建几乎是由 2M 三角形组成的。

运动结构报告和有关网格化结果的信息

在文件资源管理器中,我们现在可以寻找" Meshroom Cache "文件夹,它已经包含了所有的处理结果(没有必要显式地导出模型)。在“网格化”文件夹中,我们可以发现我们的模型是一个 OBJ 文件。在“纹理文件夹中,我们找到了纹理模型的 OBJ 文件。

图 21网络空间缓存文件夹的内容。

💡提示 : 在 Windows 10+中,OBJ 模型可以直接用 3D Viewer app 打开,否则我们会在第二章看到如何用 Blender 或 MeshLab 处理这些文件。

使用 Meshroom 标准管道及其纹理对应物生成的 3D 网格。

有了 Meshroom,加工时间要长得多。三角形的数量也是现实捕捉的两倍,这并不奇怪,因为我们在重建中使用了缩小因子,这与这里不同。然而,模型的外观(纹理)可能看起来更好,即使在这种情况下,使用的缩小因子是相同的(2)。可以用 Meshroom 对模型进行后处理,或者改变节点的参数(而不是保持默认值)以获得更好的结果。该模型也可能被导入到另一个软件(如 Blender)中,以清洁放置物体的家具的部件。与现实捕捉不同,使用 Meshroom,我们可以直接获得模型作为 OBJ,没有隐藏成本。我们甚至可以把它 3D 打印出来(但那是以后的事了😉)!

2.大型项目

现在让我们来看一个大规模的项目,更详细地了解处理工作流程。这个项目发生在比利时的韦尔维耶市,特别是一个废弃的羊毛工厂。工作环境由几栋组成。这些建筑的室内和室外部分都要考虑。

大型 3D 项目的最终 3D 网格。F. Poux

因为这个地方被废弃了,所以这条路不对公众开放。这个地方的建模是一个项目的一部分,该项目旨在捕捉像这样不寻常的地方,使人们可以(虚拟地)和我的朋友 Roman Robroek 一起参观它们。

第一步。三维数据采集

整个收购过程由两个人在 2 小时内完成。一个人拍照。本项目中使用了两台摄像机:

  • 焦距为 16 至 36 毫米的索尼相机;
  • 焦距为 24 毫米的佳能相机。

393 张照片由索尼相机拍摄,384 张由佳能相机拍摄。照片拍摄于 HDR(高动态范围)。格式是 JPEG。所以,我们总共有 777 张照片。

在战略要地,一个三脚架在一个圆上以短角度间隔拍摄照片。更多的照片是徒手拍摄,完全覆盖工作环境。

第二个人负责激光扫描部分,并使用 BLK 360 激光扫描仪,这种扫描仪体积小,因此可以在狭窄区域进行扫描。因此,该项目是一个混合项目。来自 156 次激光扫描的数据被收集并添加到处理中,以完成来自照片的信息。

BLK 中的原始文件是. e57 格式。黑白目标用于将扫描链接在一起。

第二步。三维数据处理

这一次,为了进行处理,我们使用了一台高端计算机:这是一台配备了英特尔酷睿 i9–10900 x 处理器、256 Gb 内存和 NVIDIA GeForce RTX 3090(我知道这很酷😊).

选项 a .现实捕捉

在现实捕捉中,我们首先导入我们的 156 次激光扫描(从. e57 转换成。lsp 文件)。对准可以在所有输入上进行,也可以逐个零件进行。在最后一种情况下,我们对齐组件(“合并组件”工具)。

对准也可以在扫描上单独进行,然后在图像上进行。如果扫描是地理配准的,则对准只是元素的定位信息的视图,因此是即时的。我们可以使用“匹配地理配准组件”选项来仅获取一个组件,即使我们的环境中有未链接但地理配准的零件。另一个有用的选项是“强制组件重匹配”随着更多的摄像机被对准,在已经匹配的摄像机之间执行重新对准以增强结果。但是,如果我们有想要链接的组件,这个选项不应该设置为" Yes ":这将修改每个组件已经很好的对齐,并可能引入错误。

首先,我们对准激光扫描。由于它们是地理配准的(因此已经链接在一起),只需几秒钟。我们有 156 次扫描中的 156 次在组件中对齐。我们导入我们的 777 图像,并在开始之前更改校准设置。我们将“每张图像检测到的特征数量”和“每 mpx 检测到的特征数量”(百万像素)参数设置为 100k,并将“图像重叠”设置为“高”。

💡提示:更高的最大检测特征数有助于获得更少的组件,但是对更多特征的研究可能会减慢这个过程。必须根据数据集定义图像重叠。如果设置为“低”,处理速度较慢,我们可能会获得几个单独的组件

在高质量数据集的复杂情况下工作良好的对齐设置。

经过 36 分钟的处理后,我们得到了主成分,其中 933 个元素中有 897 个是对齐的。我们还有六个小组件,包含 3 到 6 个对齐的图像。当然,我们感兴趣的是更重要的组件,但是为了完整起见,让我向您展示我们如何链接回其他组件(如果它们包含所需的信息,这将非常有用)。我们将添加控制点来对齐尽可能多的图像。控制点是位置位于不同图像中的点。添加控制点的目的是添加使对齐更容易的约束。我们可以浏览在每个小组件中对齐的图像,决定在哪里添加控制点,然后尝试在主组件中对齐的图像中找到相同的点,以确保当我们进行新的对齐时,一切都将被链接在一起。

通过打开 2D 视图,然后进入“场景”选项卡,我们可以选择只查看未注册的图像(即根本没有对齐的图像)。这向我们展示了其他哪些领域需要控制点。

未注册的图像。

在现实捕捉中,我们可以通过点击“对齐”选项卡中的“控制点”按钮来添加控制点。

添加控制点。

然后,通过按住鼠标左键,我们可以调整图像中的位置。我们也可以使用鼠标滚轮来缩放。释放鼠标左键时,会添加控制点。可以添加另一个控制点,或者通过预先选择所讨论的控制点,可以在另一个图像中定位相同的控制点。

(左)图像 1 中的控制点;图 2 中的(中间)控制点;(右)控制点列表。

本项目使用了 18 个控制点。每个控制点位于 3 到 18 幅图像中。新的校准以与之前相同的设置开始。11 分钟后,校准完成。现在我们已经对齐了 98%的输入(933 张图像中的 918 张),让我们检查一下定量结果。这首先通过查看校准报告来完成。平均重投影误差为 0.57 像素。通过对齐另外 21 幅图像,点数从 1280 万增加到了 1350 万。

对齐报告。

然后,我们还可以通过观察点云来直观地检查对齐的结果。我们在寻找放置怪异的元素,双层墙,或者比例不够大的部分。

对齐。全局视图(左);详细视图(右)。

我们注意到三台摄像机排列不整齐(它们的位置没有意义)。当这种情况发生时,我们可以尝试将这些相机与新的控制点对齐,或者禁用它们以进行进一步处理。当我们在这些照片所覆盖的区域中已经有足够的信息时,选择最后一个选项,因此使用它们并不重要。

💡提示 : 输入可通过选择输入并按 CTRL+R 同时禁用所有任务的。这些输入将被交叉输入到输入列表中,并以红色显示。

我们现在可以开始网格化。我们用默认参数开始一个正常细节的重建,除了“按部件的最大顶点计数”,它被设置在 3M 上。在“正常细节”中,“图像缩小”的值默认为 2。

重建设置。

经过 5 小时 30 分钟的处理,我们得到了一个由 616.6 米三角形组成的模型。

复杂场景实景捕捉重建的三维网格

模型太大,无法完全以“实体”模式显示,所以我们剪切一小部分来检查结果。通过调整感兴趣区域周围的重建框,选择框外的三角形(使用“框”选择工具),并过滤选择来完成剪辑。结果是一个新的模型,可以显示在“固体”模式

***

框选择(左)和现实捕捉中选择的 3D 网格视觉结果。*

剪裁还有助于在模型的小部分上执行测试,而不是同时对整个模型应用更改,这可能会导致较长的处理时间。例如,我们可以测试“图像缩小”值的影响我们禁用重建框外的输入,并连续开始三次重建,每次使用不同的“图像缩小”参数值。

下表给出了处理时间和用每个值获得的三角形计数。

加工时间、三角形计数和零件计数取决于“图像缩小”的值。

“图像缩小”增加得越多(即图像缩小得越多),处理时间就越短。但是,随着“图像缩小”的增加,某些区域的细节会丢失。

*

用不同的“图像缩小”值创建的模型的详细视图。(左)2;(中)6;(右)10。*

在很大程度上,差异非常微妙,如下图所示。

*

用不同的“图像缩小”值创建的模型的详细视图。(左)2;(中)6;(右)10。*

另一个有用的测试是研究支持三角测量的合格点的数量。如果使用 0.01 米而不是 0.002 米的“两个顶点之间的最小距离”等约束,该值会低得多。这导致模型中包含的三角形更少(2 m 之前有 27.4 米)

表二加工时间、三角形计数和零件计数取决于“两个顶点之间的最小距离”。**

这还会导致模型中出现较大尺寸的三角形,从而可能会丢失非平面区域的清晰几何图形。

***

增加“两个顶点之间的最小距离”的效果。(a)最小距离为 0.002 米;最小距离为 0.01 米*

我们还可以尝试减少“按部件计算的最大顶点数”参数的值。三角形数量没有变化,但我们现在有 61 个零件,而不是 20 个。好处是处理时间要短得多(2 分钟对 13 分钟)。

表 3加工时间、三角形计数和零件计数取决于“零件的最大顶点计数”。**

💡提示 : 根据已经使用的 激光扫描 可以设置三个重建参数。这些参数是“两点之间的最小距离”、“点云裁剪半径”(距离激光扫描范围较远的点被认为是不可靠的,不用于计算),以及“点的最小强度”(强度较低的点不用于计算)。要找到应该使用的设置,我们可以参考激光扫描用户手册。

现在,让我们做一些清理,用本章前面提到的【高级】选择工具选择边缘和大三角形。此功能需要 1 分钟来推送结果。我们还平滑模型以去除噪声。要调整的设置有“平滑类型”(“去噪”或“强”),“平滑样式”(平滑边界顶点、曲面顶点曲面或两者),以及算法的“平滑权重”和“迭代次数”。权重越大,平滑程度越高(因此,可能会删除更多细节)。我们在模型的一小部分上执行一些测试,如下所示和解释。

*

取决于迭代次数的平滑结果。(左)0.5 和 5 次迭代的平滑权重;(中)0.5 和 50 次迭代的平滑权重;(右)0.5 和 100 次迭代的平滑权重。*

我们可以观察到一些变化,但它们并不明显,因为这个模型一开始并不是很吵。

*

取决于平滑权重的平滑结果。(左)0.1 和 100 次迭代的平滑权重;(中)0.5 和 100 次迭代的平滑权重;(右)1 和 100 次迭代的平滑权重。*

如果我们看一个更嘈杂的数据集,我们可以更好地看到平滑的效果。平滑是在曲面上完成的,而不是在边上,执行 100 次算法迭代,权重设置为 0.5。平滑在 10 分钟内完成。

平滑工具的设置。

这些参数可确保高效平滑,而不会丢失太多细节。

***

“平滑工具”对另一个数据集的影响。(a)原始网格;(b)平滑网格。*

在这一点上可以使用的另一个工具是“简化工具”可以简化模型以达到固定的三角形数量(类型:“绝对”)或保留一定百分比的三角形。

简化工具设置。

在这个项目中,我们不使用这个工具,因为我们不打算导出并继续处理模型。否则,简化对于减轻 3D 模型的重量以将其导入其他软件非常有用。例如,我们的模型可以简化到 2000 万个三角形(“目标三角形数”),同时保持令人满意的质量。我们应用颜色校正来标准化图像的外观。为此,我们禁用扫描,因为颜色不自然,会干扰正常化。扫描也不用于纹理化。色彩校正在 3 分钟后完成。

校正颜色工具。

最后,我们进行纹理。这一次,我们也保留默认的“图像缩小”因子,设置为 2。我们使用 16k 的纹理分辨率和 1 mm 的纹理尺寸,这在我们的案例研究中给出了极好的结果。

纹理设置。

纹理是在 1h30 中执行的,我们通过裁剪来显示它,就像我们对重建所做的那样。

***

3D 纹理网格(左)和放大剪辑视图的结果,用于评估真实捕捉的质量。*

现在,为了科学起见,让我们测试其中一个纹理参数对模型一小部分的影响。定义的重建框外的摄像机被禁用,所有激光扫描也被禁用。如果图像缩小比例增加,处理时间会有所不同,但我们可以看到结果可能会更好。如下所示。

*

图像缩小对纹理的影响。(左)图像缩小 2 倍,处理时间为 3 分 11 秒;(左)图像缩小 6 倍,处理时间 3 分 4 秒;(左)图像缩小 10 倍,处理时间为 3 分 8 秒。*

在开始纹理化之前,还可以完成一个步骤:展开。默认情况下,展开是在纹理化开始时执行的,但也可以显式执行,以获得更好的结果并使纹理化更快。在展开选项中,可以设置“最大纹理分辨率”,以及展开“样式”

展开工具。

展开样式是用于创建 UV 贴图的策略。可以设置“最大纹理尺寸”,以便计算满足该约束所需的纹理元素尺寸。反之,可以固定纹理元素大小。程序会计算出一个最佳的纹理尺寸。使用此纹理元素大小进行纹理处理会产生 100%的纹理质量,而使用较小的纹理元素大小会产生大于 100%的纹理质量。因此,使用较大的纹理元素大小会导致纹理质量低于 100%。纹理质量并不是纹理质量的良好指标,而仅仅是最佳纹理元素大小和已用纹理元素大小之间的比率。

表 7“纹理元素大小”对“纹理质量”的影响。

纹理质量可以在下面的纹理报告中找到。我们可以看到,我们的纹理元素等于 0.001 毫米每纹理元素,这就是我们想要的。最后,如果我们有许可证,我们可以将我们的模型导出为 OBJ 文件。可以在项目设置中设置坐标系,并检索以进行输出。我们可以选择是否导出纹理,也可以选择它们的文件格式

纹理报告(左)和导出参数(右)

在总共 8 小时的时间里,我们获得了一个几何精确的纹理模型,它很好地代表了物理环境。这一次,我们没有系统地保留默认参数,而是对它们进行了调整以获得最佳结果。虽然我们没有测试每个参数,但我们已经检查了最关键的参数,并看到它们的影响相对容易理解。我们还回顾了一些工具,这些工具允许获得一个干净的模型。

最后,这里有几张我们用现实捕捉制作的重建效果图。

***

通过现实捕捉获得的模型的 3D 渲染图。F. Poux***

选项 b .网络空间

哈哈,如果你需要强烈的咖啡因,现在是时候了🤣。我们现在将研究相同的过程,并评估使用 Meshroom 可以做什么。在 Meshroom,我们只能导入我们的 777 张图像(而不是 156 张激光扫描)。因此,仅由激光扫描覆盖的部分不会被建模。由于本节仅旨在说明更大规模的项目也可以在不需要付费软件(如 Reality Capture)的情况下进行,因此这不是问题。然而,采集方法应适应为处理选择的软件,反之亦然。换句话说,如果你没有可以处理激光扫描的软件,你就必须用摄影测量学仔细收集所有数据。导入数据后,我们就可以开始处理了。这一次,我们也保留默认管道。**

在网络空间中使用的连续任务。

超过 13 个小时后,处理完成,我们可以看看结果。首先,我们可以从视觉上检查运动结构节点的结果。**

稀疏点云和相机位置。(左)俯视图;(右)透视图。

在报告中,我们看到 777 个摄像机位置中只有 554 个被估计(71%的摄像机)。这对应于场景的主要建筑。

运动结构报告

接下来,我们可以检查网格。我们在“Meshroom Cache”文件夹内的“ Meshing ”文件夹中找到 OBJ 文件,并使用 3D Viewer 应用程序打开它。这比小比例模型花费的时间多一点。

***

三维网格。(左)全局观;(右)详细视图。***

该报告指出,网格由 6.8 米三角形的几乎 3.5 米顶点组成。

啮合报告

最后,我们可以看看我们在“纹理”文件夹中找到的纹理网格。**

***

用 Meshroom 得到的三维纹理网格。(左)全局观;(右)详细视图。***

可以在管道中添加节点来进行后处理或测试不同的参数,然后在最终的工作流程中保留最优的参数,这非常方便!不过这一集我会给大家展示如何使用另一个软件进行后期处理,这个软件非常强大: Blender

🎵注意* : Blender 也可以用来对用 Reality Capture 或任何导出 3D 网格的软件制作的模型进行后处理。Blender 可以在这里免费下载:https://www.blender.org/***

安装程序后,我们导入纹理网格。**

搅拌机中的 3D 网格导入

模型需要清理:重建边缘的三角形必须移除(就像我们用现实捕捉过滤边缘和大三角形一样)。**

型号导入搅拌机。

要修改几何图形,我们切换到编辑模式。首先,我们使用“删除”工具,顾名思义,该工具用于删除选定的顶点、边或面。**

***

Blender 的编辑模式(左)及其删除工具(右)。***

我们使用它来消除网格边界的伪像和三角形,使它更干净。

***

清洗模型。(左)之前;(右图)使用工具后。***

删除松散的”工具删除断开的顶点、边或面。该工具位于“网格”选项卡的“清理”部分。我们可以应用的另一个工具是“填孔”。基于周围的几何图形和纹理来填充孔洞。我们选择“边缘选择”模式来选择我们想要填充孔洞的模型部分。**

***

删除搅拌机中的松散工具和边缘选择模式***

选择完成后,我们按 ALT+F。所选零件中的孔将被填充。

***

孔洞填充。(左)之前;(右图)使用工具后。***

其他有趣的工具有“溶解”和“抽取”工具(图 62* )。溶解允许将小平面合并为一个小平面,以便保留原始几何体。抽取可以将三角形的数量减少到特定的比例,同时保持形状尽可能接近原始形状。***

***

(左)溶解工具;(右)抽取工具。***

我们可以打开纹理绘制标签来查看我们的纹理模型并修改纹理贴图。**

mesh room 中的纹理贴图和纹理模型。F. Poux

Meshroom 和 Blender 允许我们在超过 15 个小时的加工后获得一个有纹理的网格。使用 Blender,我们解决了 Meshroom 使用默认参数生成的模型的一些问题,并获得了一个干净的模型,而不必对管道的每个步骤进行参数化。然而,根据最终的应用,使用 Meshroom 进行后处理可能会更有效,并且会产生更好的结果,尽管这需要事先熟悉程序。

结论

真诚地,如果你读到这里,恭喜你!这是一个超级密集的 3D 实践指南,当然可以作为你未来项目的参考!如果我必须用 4 个要点来总结这两个软件上展示的 3D 摄影测量过程:

  • 您需要调整采集策略,这在很大程度上取决于感兴趣对象的规模、范围和材料,以及应用所需的细节和精度水平。
  • 对于大型项目,激光扫描是对通过摄影测量收集的信息的极好补充,并允许避免精度的大漂移。然而,并不是所有的软件都允许处理这些信息。
  • 摄像机、计算机和软件应适应输入和期望的输出。现在,您已经很好地了解了依赖于所有这些参数的加工时间和约束条件。
  • 各种处理步骤和参数允许根据项目的最终目标灵活调整。对于经常性项目,对它们进行分类以建立整个自动工作流程的预设是很有趣的。

如果你像我一样渴望知识,你可以查看下面的各种资源来加深你的专业知识或探索新的 3D 主题,包括 3D GeoAI3D 点云处理3D 机器学习等等。

🎆喜欢阅读这篇文章吗?

✅可以随时关注,或者订阅我的简讯

🎆新手到中等,考虑全面使用?****

✅可以使用我原来的独家推荐链接注册成为一名媒体会员。(个人超级强烈推荐!)

🎆你想专攻某一领域成为专家?

✅查看了我其他关于 3D 点云处理3D 机器学习3D 体素建模的文章。

✅在 3D 学院查看在线课程,尤其是 3D 摄影测量课程

***https://learngeodata.eu/

所有图片均为作者所有,如需重用,请联系f . Poux**

用 Python 进行 A/B 测试的终极指南

原文:https://towardsdatascience.com/the-ultimate-guide-to-a-b-testing-with-python-b2c560b7ab26

使用概率规划测试假设

Freepik 上的宏向量设计的向量

在我们今天生活的网络世界中,企业非常依赖于通过网站、移动应用程序或广告等在线渠道发展客户群。那么,你如何增加访问你的人数呢?你如何把他们变成你生意的潜在消费者?答案很简单,你问用户他们想要什么。这正是 A/B 测试寻求实现的目标。企业观察人们更倾向于什么,因此他们可以以最大化增长的方式设计他们在线存在的特征。

A/B 测试,在最基本的层面上,是一种比较一个产品的两个版本的方法,试图了解哪个版本的性能更好。

为潜在的产品改进进行假设检验的一个常见策略是 A/B 检验。我们将在下面的章节中探讨这个策略,以理解 A/B 测试和假设测试在现实世界的设计问题中是如何执行的。

置信区间和假设检验

在执行和理解 A/B 测试的结果之前,我们需要做一些统计基础工作。这些概念将有助于培养在各种不同条件下进行这些测试的直觉。

置信区间

置信区间是一个数值范围,它可能代表具有一定置信度的总体平均值。最常见的置信水平是 95%,它由一个下限和一个上限松散地限定。这基本上意味着,如果多次重复相同的抽样技术,您可以 95%确信总体平均值将位于上限和下限之间。

这里的信心,在于抽样的方法而不在于区间本身。对于不同的样本,样本均值(置信区间的中心)仍会变化。但是,如果同样的抽样方法一遍又一遍地重复,我们就有信心在给定的区间内得到总体均值。

假设检验

假设可以被看作是对世界上某些事物的有根据的猜测,可以通过实验或观察来检验。在一般的语言世界中,假设语句应该是这样的:

如果我对一个自变量做 X ,那么 Y 就会发生在 因变量上。

赢得假设检验通常会遭到拒绝。这个想法是从给定的数据中建立一个零假设陈述,并在提出新的证据时得出结论,最初建立的假设是错误的。无效假设通常看起来像一个陈述。例如,一名研究人员指出,如果膝盖手术患者每周进行两次理疗(而不是四次),他们的恢复会更快。为了拒绝这一点,我们需要新的证据和测试来证明,每周两次的物理治疗不会导致更快的愈合。

在上面的例子中,我已经非常简要地解释了假设和置信区间。如果你是统计学新手,这些解释可能没什么意义。因此,我建议您按照我在下面参考资料部分提到的特定链接来更好地理解这些统计概念。

个案研究

为了理解我上面讨论的所有理论信息,让我们采取案例研究的方法,并尝试通过使用 Python 在网站上进行的 A/B 测试来编写我们的程序。确保这个代码库在故事旁边打开,以便理解理论和代码。

问题陈述

网站的登陆页面是一个新用户的介绍点,通常是业务流量的来源。简而言之,订阅您网站的用户将通过登录页面完成他们各自的购买(如果他们觉得足够吸引人,也许?).这里的问题是设计一个登陆页面,引导更多的消费者浏览网站。我们得到了现有的设计和一些新的功能,可以在现有的设计上实现,以形成一个新的设计。目标是从两个设计中选择一个作为网站的最终登录页面。

解决方法

这是一个经典的 A/B 测试题。我在这里解释的方法是计算两个登录页面的转换率(用户访问登录页面并完成购买)。 从统计上来说,既然问题只是想增加顾客的数量,我们就用单尾假设检验。 衡量标准是转换率,此外,我们将使用 z 测试建立一个置信区间,在此区间内,我们的测试不会产生任何错误(类型 II)

为了理解解决 A/B 测试的方法,我将我的分析(以及包含代码的笔记本)分成三个不同的部分,这将有助于简明地理解和构建假设测试。

  1. 定义成功的标准 在我们正在探索的例子中,我们的想法是设计一个增加网站订阅的登陆页面。对于这个分析,我将使用转换率作为成功的衡量标准。这被定义为看到新页面并加入订阅的用户数量,与旧页面的比率相同。
  2. 制定零备假设 定义假设对于能够从中得出结论很重要。在这种情况下,零假设表示,“新设计并不决定用户加入网站的概率是否成功”。由于我们只关心新页面的用户数量是否增加,我们将使用一个单尾假设检验来尝试并拒绝零假设。
  3. 定义一个测试指标来衡量分析的成功 理解任何分析的一个重要部分是能够自信地断定它是正确的。为了测量这种正确性,我们需要执行一些测试来证明我们的分析确实是正确的。在这种情况下,我将执行一个 z 测试来判断是否可以忽略零假设。此外,我还将执行功率分析来预测提交错误的概率。

理解测试策略

在一个典型的假设检验中,我们看到 t 检验z 检验具有一定的显著性水平,帮助我们决定拒绝零假设。

何时使用 t,z 测试。|作者图片

计算 Z 值

我们在分析的输出中观察到 z 测试的 alpha 值是 1.64,基于这个 alpha 值和 95%的置信度,我们只能拒绝该组(是,否)。通过下面的权力分析也可以得出同样的结论。

执行功率分析

通常,0.8 的功率水平被认为是一个好值。该组(是,否)是上面功率分析中唯一一个值大于 0.8 的组。至于样本的大小,理想情况下,样本越大,得分越准确,因此我们使用了样本中所有可用的条目。

了解结果

从我们的假设、z 分数检验和功效分析中,我们可以得出结论,相对于对照组(否,否),只有一个实验组(是,否)具有成功拒绝零假设的影响。以下是我们可以从这一分析中得出的结论。

  1. 在 95%的置信度下,我们可以说,与对照组相比,设计的改进(是,否)是 0.56%。
  2. 对于(1)为真,在得出上述结论时犯 I 型错误的概率约为 5%。
  3. 对于(1)为真,在得出上述结论时犯第二类错误的概率约为 10%。

代码库

虽然我已经包含了在这个故事中执行 A/B 测试的关键代码结构,但是浏览整个笔记本还是有好处的。我宁愿建议你在阅读这个故事的过程中,让它在后台保持打开状态。

**https://github.com/rjrahul24/statistics_with_python/tree/main/A:B Testing

结论

这个故事讲述了假设检验、置信区间、z 分数和 A/B 检验。这些是统计世界中的重要概念,经常在围绕数据的实验中使用,特别是当组织希望更新他们的产品时。在我上面解释的实验中,该组织希望修改他们的登录页面以增加流量,随后提高他们的订阅量。通过我们的 A/B 测试,我们以 95%的信心得出结论,在看到带有旧图片的新版本登录页面时,与旧设计相比,他们加入订阅的机会至少提高了 0.56%(可能更多)。我们还考虑了 I 型和 II 型错误,以消除错误分析的可能性。

设计选择(“A”和“B”)|照片由 Greg Jeanneau 拍摄🗾 on Unsplash

测试任何假设的一般工作流程都遵循相同的步骤和说明。我们从零假设开始,引入证据来比较零假设和另一个假设。然后,我们得出结论,如果新的证据可以肯定地推翻零假设。无论在哪种情况下,我们都应该注意测试分析中可能存在的错误。

如果你喜欢这个故事,我经常写关于数据科学、统计学、机器学习和气候变化的文章。这里有一些阅读材料可以帮助你前进。

https://medium.com/geekculture/probability-has-nothing-to-do-with-the-likelihood-of-an-events-occurrence-a9475a365ac0

关于我

我是纽约哥伦比亚大学的一名软件工程师兼数据科学研究员,目前正在研究如何减少气候变化对世界贫困人口的影响。这些人受我们砍伐树木和在地球表面推混凝土的行为影响最大。如果你的研究或工作抱负也与我一致,请务必与我联系到 TwitterLinkedIn ,我们可以一起努力建设 负责任的人工智能。

参考

  1. https://www.investopedia.com/terms/h/hypothesistesting.asp
  2. https://en . Wikipedia . org/wiki/Statistical _ hypothesis _ testing
  3. https://www . aha journals . org/doi/full/10.1161/circulation ha . 105 . 586461
  4. https://www . optimize ly . com/optimization-glossary/a b-testing/
  5. https://hbr.org/2017/06/a-refresher-on-ab-testing
  6. https://vwo.com/ab-testing/**

PDP 和 ICE 绘图的最终指南

原文:https://towardsdatascience.com/the-ultimate-guide-to-pdps-and-ice-plots-4182885662aa

部分依赖图和个体条件期望图背后的直觉、数学和代码(R 和 Python)

(来源:作者)

PDP 和 ICE 图都可以帮助我们理解我们的模型如何做出预测。

使用PDP,我们可以可视化模型特征和目标变量之间的关系。他们能告诉我们一段关系是线性的、非线性的还是没有关系。

类似地, ICE Plots 可以在特征之间存在交互时使用。我们将深入研究这两种方法。

我们从PDP开始。我们将带您一步步了解 PDP 是如何创建的。你会发现它们是一种直观的方法。即便如此,我们也要解释一下 PDP 背后的数学。然后我们继续前进到冰原。您将会看到,如果对 PDP 有很好的了解,这些都很容易理解。在此过程中,我们讨论了这些方法的不同应用和变体,包括:

  • 连续和分类特征的 PDP 和 ICE 图
  • 二元目标变量的 PDP
  • 2 个型号特性的 PDP
  • 衍生 PDP
  • 基于 PDP 和 ICE 图的特征重要性

我们一定要讨论这两种方法的优点局限性。这些是重要的部分。它们帮助我们理解什么时候方法是最合适的。它们还告诉我们在某些情况下它们会导致不正确的结论。

最后,我们将带您浏览这些方法的 R 和 Python 代码。对于 R,我们应用 冰箱iml 包来创建可视化。我们还使用 vip 来计算特征重要性。对于 Python,我们将使用 scikit-learn 的实现,partialdependicedisplays。您可以在这些部分找到带有代码的 GitHub repos 的链接。

部分相关图

我们从 PDP 的逐步演示开始。为了解释这种方法,我们随机生成了一个包含 1000 行的数据集。它包含了二手车销售的细节。你可以在表 1 中看到这些特性。我们希望使用前 5 个特征来预测汽车的价格。你可以在 Kaggle 上找到这个数据集。

表 1:二手车销售数据集概述(来源:作者)(数据集: kaggle )(牌照:CC0)

为了预测价格,我们首先需要使用该数据集训练一个模型。在我们的例子中,我们用 100 棵树训练了一个随机的森林。确切的模型并不重要,因为 PDP 是一种模型不可知的方法。我们现在将看到它们是使用模型预测构建的。我们不考虑模型的内部运作。这意味着我们探索的可视化将类似于随机森林、XGBoost、神经网络等…

表 2 中,我们的数据集中有一个观察值用于训练模型。在最后一列中,我们可以看到这辆车的预测价格。为了创建 PDP,我们改变其中一个特性的值,并记录结果预测。例如,如果我们改变汽车年龄,我们将得到不同的预测。我们这样做的同时保持其他特性的真实值不变。例如,车主 _ 年龄将保持在 19, km_drive 将保持在 27544。

表 2:训练数据和预测示例(来源:作者)

图 1 ,可以看到这个过程的结果。这显示了针对该特定观察的预测价格(部分 yhat)和车龄之间的关系。你可以看到,随着车龄的增加,预测价格下降。黑点给出原预测价格( 4,654 )和 car_age ( 4.03 )。

图 1:观察 1 中不同车龄的预测价格(来源:作者)

然后,我们对数据集中的每个观察值或观察值子集重复这个过程。在图 2 中,可以看到 100 次观测的预测线。为了清楚起见,对于每个观察,我们只改变了车龄。我们将剩余的特征保持在它们的原始值不变。这些值与我们在表 2 中看到的值不同。这就解释了为什么每一行的起点都不同。

图 2:100 次观察的预测线(来源:作者)

要创建 PDP,最后一步是计算汽车年龄的每个值的平均预测值。这给了我们图 3 中的粗黄线。这条线是 PDP。通过保持其他特征不变并对观察值进行平均,我们能够分离出与 car_age 的关系。我们可以看到,预测价格会随着车龄的增长而下降。

图 3:汽车时代的部分依赖图(来源:作者)

你可能已经注意到了 x 轴上的短线。这些是汽车时代的四分位数。也就是说,10%的 car_age 值小于第一行,90%小于最后一行。这就是所谓的地毯阴谋。它向我们展示了特征的分布。在这种情况下,car_age 的值在其范围内相当均匀地分布。当我们讨论 PDP 的局限性时,我们将理解为什么这是有用的。

您可能还注意到,并非所有的预测线都遵循 PDP 趋势。一些较高的线似乎增加了。这表明,对于这些观察,价格与车龄有相反的关系。也就是说,预测的价格会随着车龄的增加而增加。请记住这一点。当我们讨论冰的情节时,我们将会回来。

PDP 背后的数学

对于更注重数学的人来说,PDP 也有一个正式的定义。让我们从刚刚创建的 PDP 函数开始。这由等式 1 给出。集合 C 将包含除 car_age 之外的所有特征。对于给定的 car_age 值和观察值 I,我们使用 c 中特性的原始值找到预测价格。我们对所有 100 个观察值都这样做,并找到平均值。这个等式将给出我们在图 3 中看到的粗黄线。

等式 car _ age 的 PD 函数(来源:作者)

等式 2 中,我们对上述等式进行了推广。这是一组特征的 PD 函数。S. C 将包含除 s 中的特征之外的所有特征。我们现在还对 n 次观察进行平均。这可以达到数据集中的观察总数(即 1000)。

等式 2:特征集 S 的近似 PD 函数(来源:作者)

到目前为止,我们只讨论了 S 由一个特征组成的情况。在上一节中,我们有 S = {car_age}。稍后,我们将向您展示包含 2 项功能的 PDP。我们通常不会在 s 中包含超过 2 个特征,否则,将很难可视化 PD 功能。

上述等式实际上只是 PD 函数的近似。真正的数学定义在等式 3 中给出。对于集合 S 中的给定值,我们找到了集合 c 中的预期预测值。为此,我们需要将模型函数 w.r.t .与观察到集合 c 中的值的概率进行积分。要完全理解此方程,您需要一些随机微积分方面的经验。

等式 3:特征集 S 的 PD 函数(来源:作者)

使用 PDP 时,对近似值的理解就足够了。真正的 PD 功能实现起来并不实际。首先,与近似法相比,它的实现在计算上更加昂贵。其次,考虑到我们有限的观测数据,我们只能估算出大概的概率。也就是说,我们无法找到每个观察值的真实概率。最后,许多模型不是连续的函数,这使得它们很难集成。

连续功能的 PDP

了解我们如何创建 PDP 后,我们将继续使用它们。使用这些图我们可以理解模型特征和目标变量之间关系的本质。比如我们已经在图 4 中看到了 car_age PDP。预测价格以相当稳定的速度下降。这表明 car_age 与价格有一个线性关系。

图 4:汽车时代 PDP(来源:作者)

图 5 中,我们可以看到另一个特性的 PDP,修复。这是汽车接受维修/服务的次数。最初,预测价格往往会随着维修次数的增加而增加。我们希望一辆可靠的汽车接受一些定期保养。然后在 6/7 修左右,价格趋于降低。过度维修可能说明车有问题。由此我们可以看出,价格与维修之间存在非线性关系

图 5:维修 PDP(来源:作者)

从上面,我们可以看到 PDP 在可视化非线性关系时是有用的。我们将在下面的文章中更深入地探讨这个话题。在处理许多功能时,查看所有 PDP 可能不切实际。所以我们也讨论使用互信息和特征重要性来帮助找到非线性关系。

图 6 中,我们可以看到一个特性与目标变量没有关系时的 PDP 示例。对于车主年龄,PDP 保持不变。这告诉我们,当我们改变所有者年龄时,预测价格不会改变。稍后,我们将看到如何使用 PDP 变化的思想来创建特性重要性分数。

图 6: owner_age PDP(来源:作者)

分类特征的 PDP

我们上面讨论的特征都是连续的。我们还可以为分类特征创建 PDP。例如,参见图 7 中car_type 的绘图。这里我们计算每种汽车的平均预测值——普通型(0)或经典型(1)。我们用柱状图来代替直线。我们可以看到,老爷车往往售价更高。

图 7: car_type PDP(来源:作者)

二元目标变量的 PDP

二元目标变量的 PDP 与连续目标的 PDP 相似。假设我们想预测汽车价格是高于(1)平均值还是低于(0)平均值。我们构建了一个随机森林,使用相同的特征来预测这个二进制变量。我们可以使用与之前相同的流程为此模型创建 PDP。只不过现在我们的预测是一种可能性。

比如在图 8 中,可以看到 car_age 的 PDP。我们现在在 y 轴上有一个预测的概率。这是汽车高于二手车平均价格的概率。我们可以看到,随着车龄的增长,概率有降低的趋势。

图 8:二元目标变量的 PDP(来源:作者)

两个功能的 PDP

回到我们的连续目标变量。我们还可以看到两个特性的 PDP。在图 9 中,我们可以看到 km_drivencar_age 不同组合下的平均预测值。该图表的创建方式与一个特性的 PDP 相同。也就是说,保持其余特征的原始值。

图 9: 2 专题 PDP(来源:作者)

这些 PDP 对于可视化功能之间的交互非常有用。上图显示了行驶里程和车龄之间可能的相互作用。也就是说,当两个特性的值都较大时,预测价格往往会较低。在得出这些类型的结论时,你应该谨慎。

这是因为如果两个特征相关,我们可以得到相似的结果。稍后,当我们讨论 PDP 的局限性时,将会看到事实确实如此。即行驶里程与车龄相关。车越老,行驶里程越多。这就是为什么当两种特性都较高时,我们会看到较低的预测价格。

衍生 PDP

衍生 PDP 是 PDP 的变体。它显示了 PDP 的斜率/导数。它可用于更好地理解原始 PDP。然而,在大多数情况下,我们从这些情节中获得的洞察力是有限的。它们通常对非线性关系更有用。

例如,以图 10 中的维修衍生 PDP 为例。这是我们之前在图 5 中看到的线的导数。我们可以看到,在大约 6 次修复时,导数为 0。此时,导数由正变负。换句话说,最初的 PDP 从增加到减少 w.r.t .维修。这告诉我们,经过 6 次修理后,汽车的价格将会下降。

图 10:维修衍生 PDP(来源:作者)

PDP 功能重要性

在结束这一部分时,我们有一个基于 PDP 的功能重要性分数。这是通过确定每个特性的 PDP 的“平坦度”来实现的。具体来说,对于连续变量,我们计算绘图值的标准偏差。对于分类变量,我们通过首先取范围来估计标准差。即最大值减去最小 PDP 值。然后我们将范围除以 4。这个计算来自一个叫做范围规则的概念。

您可以在图 11 中看到基于 PDP 的功能对我们功能的重要性。请注意,owner_age 的分数相对较低。如果我们回想一下图 6 中的 PDP,这是有意义的。我们看到 PDP 相对稳定。换句话说,y 轴值总是接近它们的平均值。它们的标准差很低。

图 11:基于 PDP 的特性重要性(来源:作者)

有更广为人知的特征重要性分数,例如排列特征重要性。您可能更喜欢使用这种基于 PDP 的评分,因为它可以提供一定的一致性。如果您正在分析要素趋势,现在可以使用通过类似逻辑计算的要素重要性分数。你也可以避免解释两种不同方法的逻辑。

个体条件期望(ICE)图

随着 PDP 的方式,让我们继续到冰图。您会很高兴地知道,我们已经讨论了创建它们的过程。取图 12 下图。这是我们在图 3 中的 car_age PDP 之前创建的图。这是一个汽车时代的冰图。冰图由每个单独观测的预测线组成。

图 12:汽车时代的冰图(来源:作者)

当模型中存在交互时,冰图非常有用。也就是说,一个特征与目标变量的关系取决于另一个特征的值。在上图中可能很难看出这一点。为了使事情更清楚,我们可以把我们的冰图放在中间。在图 13 中,我们通过让所有预测线从 0 开始来实现这一点。现在很清楚,根据一些观察,预测的价格会随着车龄的增加而增加。

图 13:中心冰图(来源:作者)

为了理解是什么导致了这种行为,我们可以改变冰图的颜色。在图 14 中,我们根据汽车类型改变了颜色。我们把老爷车的线弄成蓝色,普通车的线弄成红色。我们现在可以看到,这种关系来自于 car_age 和 car_type 之间的交互。凭直觉,一辆老爷车随着年龄的增长会升值是有道理的。

图 14:彩色冰图(来源:作者)

最后一项添加是将 PDP 线添加到图中。这样,我们就可以将 ICE 图和 PDP 结合起来。这可以强调一些观察结果如何偏离平均趋势。我们可以看到,如果我们只依赖 PDP,我们将会错过这种互动。也就是说,当使用图 3 中的 PDP 时,我们得出的结论是,所有汽车的价格都会随着车龄的增长而下降。

图 15:PDP 和 ICE 的组合图(来源:作者)

与 PDP 一样,ICE 图可以帮助我们可视化数据中的重要关系。为了找到这些关系,我们可能需要使用像特性重要性这样的指标。另一种专门用于突出模型中交互作用的度量是弗里德曼的 H-统计量。我们将在下面的文章中讨论使用所有这些方法。

分类特征的冰图

我们可以用箱线图来显示分类特征的冰图。例如,我们在图 16 中有 car_type 的 ICE 图。方框中间的粗线给出了平均预测值。换句话说,他们就是 PDP。我们可以看到普通汽车的预测价格更低(0)。

图 16: car_type ICE 情节(来源:作者)

基于 ICE 图的特征重要性

我们还可以计算基于 ICE 图的特征重要性分数。这类似于基于 PDP 的评分,只是我们不再考虑平均预测线。我们现在使用单独的预测线来计算分数。这意味着分数将考虑特征之间的相互作用。

在图 17 中,我们有我们的模型的基于 ICE 图的分数。我们可以将这些与图 11 中基于 PDP 的分数进行比较。最大的不同是汽车时代的分数现在更大了。从 300 增加到 345。根据我们上面的分析,这是有意义的。我们看到了影响车龄和价格之间关系的交互作用。基于 PDP 的特征重要性不考虑这种相互作用。

图 17:基于 ICE 图的特征重要性(来源:作者)

PDP 和 ICE 图的优势

到目前为止,希望我们已经很好地理解了 PDP 和 ICE 图,以及我们可以从中获得的见解。我们将继续讨论这些方法的优势。然后在下一节中,我们将讨论其局限性。理解这些是至关重要的,这样你就不会从图中得出不正确的结论。

隔离功能趋势

我们可以使用散点图来可视化数据中的关系,但数据是杂乱的。例如,我们可以在图 18 中看到 car_age 和 car_type 之间的交互作用。这些点围绕真正的潜在趋势而变化。这是因为统计噪声和价格与其他特征也有关系的事实。在真实的数据集中,这个问题可能会更严重。最终,很难看出数据的趋势。

图 18:汽车年龄和汽车类型交互的散点图(来源:作者)

使用 PDP 和 ICE 图时,我们不再使用原始数据值。我们正在研究模型预测。如果构建正确,模型将捕捉数据中的潜在关系,并忽略统计噪声。然后,我们可以分离出特定特征的趋势。这是通过保持其他特征值不变并对观察值进行平均来实现的。

这就是 PDP 和 ICE 图如此有用的原因。它们允许我们去除噪声和其他特征的影响。这使得我们更容易看到数据中的潜在关系。在这个意义上,这些方法可以用于数据探索,而不仅仅是理解我们的模型。

开门见山地解释

希望通过向您介绍构建 PDP 的过程,您会很容易理解。这样,你就可以获得对该方法的直观理解,而不需要一个数学定义。这也意味着这些方法很容易向非技术人员解释。这在工业环境中很有用。

易于实施

这些方法也很容易实现。我们只需要改变特征值并记录结果预测。我们甚至不需要考虑模型的内部运作。这意味着相同的实现可以用于任何模型。当我们讨论 R 和 Python 代码时,你会看到这些方法已经有了很好的实现。

PDP 和 ICE 图的局限性

假设特征独立

继续讨论局限性,我们将从这些方法的主要问题开始。这是因为他们假设特征是独立的。这并不总是如此,因为特征可以是相互关联的。例如,以图 19 中的 km_driven 和 car_age 散点图为例。有明显的相关性。直觉上,这是有道理的。老式汽车往往行驶更长的距离。

图 19:行驶里程与车龄的散点图(来源:作者)

问题是,当我们为观测值构建预测线时,我们将对某个要素的所有可能值进行采样。例如,假设我们想为 km_driven 构建一个 PDP。以图 20 中红色给出的观察结果为例。它的车龄是 10 年。为了建立预测线,我们将改变虚线椭圆中所有值的 km_driven。然而,在现实中,这种车龄的观测只能在实心椭圆内行驶一段距离。

图 20:随机抽样的问题(来源:作者)

我们的模型不是在实心椭圆之外的观察上训练出来的。尽管如此,我们仍在根据这些观察结果的预测创建 PDP。结果是,预测线是建立在模型以前没有“看到”的观察结果上的。这可能会产生不直观的结果,并导致关于特征趋势的错误结论。

同等关注所有特征值

即使特征是不相关的,我们仍然会得出不正确的结论。对于每个观察值,我们对所有可能的特征值进行采样。这给予所有值同等的权重。实际上,该特性的一些值不太常见。例如在特征分布的极端。这些数值的趋势将会有更多的不确定性。

考虑到这一点,通常包括地毯情节。这些有助于我们理解特征的分布。在我们看到地毯图的分位数版本之前。图 21 ,给出了替代版本。在这里,我们为每个观察值设置了单独的行。我们可以看到,km_driven 值越高,观测值越少。因此,我们应该更加小心地解释这些值的趋势。

图 21:km _ driven 的替代 PDP(来源:作者)

结论取决于你的模型

正如优势中提到的,使用模型预测可以帮助我们更清楚地看到关系。问题是模型可能做出不正确的预测。一个不合适的模型可能会错过重要的关系。通过对噪声建模,过度拟合的模型可以呈现实际上并不存在的关系。最终,我们得出的结论将取决于我们的模型。考虑模型的性能很重要。

即使有了一个精确的模型,我们仍然会有问题。一个模型可以忽略一些关系而支持其他关系。我们会得出错误的结论,即被忽略的特征与目标变量没有关系。这意味着,在进行数据探索时,您可能希望将要素限制在您有兴趣探索的子集内。

PDP 忽略交互

如前所述,通过使用平均值,PDP 可能会错过交互。因此,基于 PDP 的特征重要性也将错过这些交互。这意味着,如果存在交互,分数可能会低估某个特征的重要性。我们在 car_age 特写中看到了这一点。一个解决方案是使用 ICE 图或坚持排列特征重要性。

实施的局限性

在接下来的部分中,我们将带您浏览用于实现这些方法的代码。我们将看到每种实现都有其优缺点。有些包没有我们讨论的所有情节的实现。例如,如果您正在使用 Python,那么就我所知,对于派生 PDP 或特性重要性,没有实现。

PDP 和 ICE 图的 r 代码

在本节中,我们将带您浏览用于创建 PDP 和 ICE 图的 R 代码。我们将研究使用三种不同的包。我们使用冰箱iml 来创建情节。结合这些允许我们创建我们上面讨论的所有情节。对于特征重要性分数,我们使用 vip 。你可以在 GitHub 上找到我们讨论的所有代码。

我们从加载数据集开始(第 1 行)。这与我们在本文开头的表 1 中讨论的是同一个问题。我们还将 car_type 设置为分类特征(第 2 行)。

造型

在我们创建 PDP 和 ICE 图之前,我们需要一个模型。我们使用 randomForest 包来做这件事(第 1 行)。我们使用价格和 6 个特征建立一个模型(第 4-6 行)。具体来说,我们使用了一个有 100 棵树的随机森林(第 6 行)。

对于下面的大多数图,我们将使用模型 rf 。这已经在连续目标变量上进行了训练。我们还想在二进制目标变量上建立一个模型, rf_binary,。这是为了向您展示不同类型的目标的代码和输出是如何不同的。

首先,我们创建二进制目标变量。如果原始汽车价格高于平均值,则该值为 1,如果低于平均值,则该值为 0(第 2-4 行)。然后,我们像前面一样构建一个随机森林(第 7–9 行)。有了这些模型,我们现在可以继续使用 PDP 和 ICE 图来了解它们是如何工作的。随着我们的深入,输出将显示在相关代码的下方。

包装—冰箱

我们将从冰箱包开始(第 1 行)。我们将使用它为 car_age 创建一个 PDP。我们使用 ice 函数为 car_age 创建一个 iceplot 对象(第 4–7 行)。我们传递我们的模型、特性和目标变量(第 4-6 行)。该对象将包含 car_age 的所有单个预测行。它还将包含平均预测线(即 PDP)。

然后我们使用 plot 函数显示 iceplot 对象(第 9–11 行)。默认情况下,此包将始终显示冰图。要创建 PDP,我们需要隐藏各个预测线。我们通过将它们全部变成白色来做到这一点(第 11 行)。我们还隐藏了给出原始 car_age 值的点(第 10 行)。

(来源:作者)

要创建冰图,我们可以使用相同的冰图对象。现在,我们不再隐藏单独的线条,而是根据它们的汽车类型给它们着色(第 5 行)。经典车和普通车的区别在于它们的线条分别是蓝色和红色。我们也进入了冰情节(3 线)。我们通过仅绘制 10%的单独线条(第 2 行)将绘图限制为 100 个观察值。

(来源:作者)

我们也可以使用 ICEBox 包来绘制衍生 PDP。我们以与之前相同的方式创建一个 iceplot 对象进行修复(第 1–4 行)。然后我们用它来创建一个骰子对象(第 5 行)。最后,我们绘制骰子对象(第 7–10 行)。我们已经设置了 plot_sd = F(第 10 行)。这隐藏了各个预测线的标准偏差。

(来源:作者)

我们用这个包创建的最后一个图是二进制目标变量的 PDP。代码类似于之前。除了使用 rf_binary 之外,唯一的区别是传递了一个预测函数(第 4–6 行)。这让 ice 函数知道我们的预测是根据概率给出的。

(来源:作者)

冰箱包装有一些优点。通过用另一个特征给冰图着色,它允许我们清楚地看到相互作用。它也是唯一一个实现了衍生 PDP 的包。就局限性而言,它不处理分类特征。这意味着我们不能为 car_type 特征创建图。它也没有为 2 个功能实施 PDP。

包装— iml

下一个包 iml 可以解决这些限制。首先,我们将使用它为 car_age 创建一个 PDP。我们使用随机森林和数据集创建一个预测器对象(第 4 行)。使用它,我们创建一个特征效果对象(第 7 -9 行)。我们使用“pdp”作为功能效果方法(第 9 行)。最后,我们绘制这个特征效果对象(第 10 行)。

(来源:作者)

我们使用类似的代码为 car_age 创建一个 ICE 图。我们使用与之前相同的预测器对象(第 1 行)。我们现在将方法设置为“pdp+ice”(第 3 行)。这将给我们一个组合的 PDP 和 ICE 图。我们还将图居中,因此所有预测线都从 0 开始(第 4 行)。将方法设置为“ice”将删除黄色 PDP。

(来源:作者)

iml 包也可以处理分类特征。下面我们为 car_type 创建 PDP(第 2-5 行)。这给了我们下面的直方图。类似地,我们为 car_type 创建一个 ICE 图(第 8–11 行)。这给了我们箱线图。

(来源:作者)

iml 的另一个优势是它为 2 个特性实现了 PDP。下面我们为汽车年龄和公里驾驶创建一个 PDP。代码类似于之前。唯一的区别是我们传递了一个带有两个特性名称的向量(第 2 行)。

(来源:作者)

最后,我们为二元目标变量创建一个 PDP。我们用 rf_binary (第 1 行)创建预测器对象,但是代码的其余部分和以前一样。你可以看到我们现在有两个图。请注意,它们是彼此相反的。这是因为第一个图给出了汽车低于平均值(0)的概率。第二个图给出了高于平均值(1)的概率。当目标变量有两个以上的值时,为每个值绘制图表非常有用。

(来源:作者)

套餐— vip

以上两个包都没有实现特性重要性分数。为了计算这些,我们使用 vip 包(第 1 行)。创建基于 PDP 的分数(第 4 行)和基于 ICE 的分数(第 7 行)非常简单。我们已经将方法设置为“固定”。这代表特征重要性排序度量。

(来源:作者)

用于 PDP 和 ICE 图的 Python 代码

在本节中,我们将带您浏览用于创建 PDP 和 ICE 图的 Python 代码。你也可以在 GitHub 上找到这个。我们将使用 scikit-learn 的实现, PartialDependenceDisplay 。另一个我们不会讨论的包是 PDPbox

我们从导入 Python 包开始。我们导入了一些用于处理和可视化数据的通用包(第 2–4 行)。我们有两个不同的建模软件包— RandomFrorestRegressor (第 6 行)和 xgboost (第 7 行)。最后,我们有用于创建 PDP 和 ICE 图的包(第 9–10 行)。第一个包用于可视化绘图。第二个包用于获得用于创建图的预测。这在我们以后探索分类特征时会很方便。

PDP 包由 scikit-learn 提供。您仍然可以将它们用于不是用 scikit-learn 包创建的模型。稍后当我们用 xgb 包建模二进制目标变量时,您将会看到这一点。

连续目标变量

我们将从连续目标变量开始。我们加载数据集(第 2 行)。这与我们在本文开头的表 1 中讨论的是同一个问题。我们得到了目标变量(第 5 行)和特征(第 6 行)。我们用这些来训练一个随机的森林(第 9-10 行)。具体来说,随机森林由 100 棵树组成。每棵树的最大深度为 4。

我们现在可以使用 PartialDependenceDisplay 包来理解这个模型是如何工作的。首先,我们将为 car_age 创建一个 PDP。为此,我们使用 from_estimator 函数。我们传入模型、X 特征矩阵和特征名称。您可以在代码下面看到输出。

(来源:作者)

为了创建一个 ICE 图,我们需要将种类参数设置为‘individual’(第 4 行)。我们还将情节居中(第 6 行)。默认情况下,这些函数只显示特征的 5%到 95%的百分位数。如果你想显示汽车年龄的全部范围,你需要改变它。也就是 0 到 40 岁。我们在第 5 行做这个。

(来源:作者)

我们在下面探索一些其他的选择。将种类特性设置为“两者”将显示 PDP 和 ICE 图(第 4 行)。我们还可以使用 ice_lines_kw (第 4 行)和 pd_line_kw (第 5 行)参数分别更改 ice 图和 PDP 线的样式。

(来源:作者)

创建包含两个功能的 PDP 与之前类似。我们所需要做的就是传递一个特性名称的数组,而不是一个单独的特性名称。你可以在下面看到我们是如何为车龄和公里数做这些的。

(来源:作者)

scikit-learn 包的缺点是它将分类特征视为连续特征。你可以在下面看到这样做的结果。PDP 和 ICE 图由线条给出。直方图和箱线图会给出更好的解释。

(来源:作者)

我们可以通过创造自己的情节来解决这个问题。我们使用partial _ dependency函数来实现这一点(第 3 行)。我们使用该函数的方式与使用 for_estimator 函数的方式相同。不同的是,它不显示一个情节。它仅返回用于创建图的数据。 pd_ice 将包含 car_type 的 PDP 和 ice 图的数据。

您可以在下面看到我们如何使用它来创建 PDP。我们从从 pd_ice (第 2 行)获取平均值开始。这将是普通车和老爷车的平均预测。使用这些,我们绘制一个条形图(第 5-14 行)。

[分手]

(来源:作者)

对于冰图,我们可以创建一个箱线图。我们从 pd_ice (第 2 行)中得到单独的预测。然后,我们将这些分为普通车和经典车预测(第 4-6 行)。最后,我们绘制箱线图(第 9-14 行)。

(来源:作者)

二元目标变量

最后,我们将创建一个二元目标变量的 ICE 图。首先,我们创建变量(第 2–3 行)。如果原始汽车价格高于平均值,则其值为 1,如果低于平均值,则其值为 0。我们使用这个二元变量训练一个模型(第 6–7 行)。这一次我们使用了一个最大深度为 2 的 XBGClassifier 和 100 棵树。

我们像以前一样为汽车时代画一个冰图。你会注意到 y 轴现在给出的是概率而不是价格。您还可以看到,将 scikit-learn 包与其他建模包一起使用非常简单。

(来源:作者)

使用 Python 的缺点是没有衍生 PDP 和特性重要性分数的实现(据我所知)。虽然,对于大多数问题,上面的图表是你所需要的。如果您需要其他方法,您可以使用partial _ dependency函数自己实现它们。

我希望这篇文章对你有用!我真的希望它成为 PDP 和 ICE 情节的终极指南。如果你认为我错过了什么,请在评论中提出。另外,如果有什么不清楚的地方,请告诉我。我很乐意更新文章:)

PDP 和 ICE 图是可解释的机器学习方法。它们被用来理解我们的模型是如何做出预测的。另一种流行的方法是 SHAP。SHAP 值的一个优点是它们可以用来理解个人预测是如何做出的。还可以将它们聚合起来,以了解模型作为一个整体是如何工作的。在下面的文章中,我们将探索如何在 Python 中应用这种方法。

我希望这篇文章对你有帮助!你可以成为我的 推荐会员 来支持我。你可以访问 medium 上的所有文章,我可以得到你的部分费用。

https://conorosullyds.medium.com/membership

你可以在|Twitter|YouTube|时事通讯上找到我——注册免费参加 Python SHAP 课程

参考

C.莫尔纳尔、可解释机器学习 (2021)、https://christophm.github.io/interpretable-ml-book/

南用 Python 进行可解释的机器学习 (2021)

格伦威尔,B.M .,博姆克,B.C .和麦卡锡,a . j .(2018)。一种简单有效的基于模型的可变重要性度量https://arxiv.org/abs/1805.04755

Power BI 中行级和对象级安全性的终极指南

原文:https://towardsdatascience.com/the-ultimate-guide-to-row-level-and-object-level-security-in-power-bi-3a98f5422bad

“谁能看到报告中的内容?”是 Power BI 中的关键安全问题之一。了解实现访问控制的两种可能方式

作者图片

恭喜你!在之前的文章中,您已经了解了如何设计和构建大格式数据集聚合如何加速您的 Power BI 报告,以及如何利用复合模型特性在设计企业级表格模型时获得最大的灵活性。不仅如此,您还发现了【DirectQuery 如何在 Power BI 中工作,什么是外部工具,以及如何通过创建计算组来扩展您的数据建模技能。不要忘记一些关于变量、虚拟关系和迭代器的 DAX 小技巧

现在,我们来总结一下如何保护您的数据,或者更好地说,如何控制对 Power BI 解决方案某些部分的访问。您可以在行级安全性(RLS)和对象级安全性(OLS)之间进行选择。需要说明的是,这并不是说选择一个就排除了使用另一个的可能性——您可以在同一个解决方案中同时使用 RLS 和 OLS。

让我们快速区分这两者,以及在哪些场景中使用 RLS、OLS 或两者都使用是有意义的。我们将从“更老”的表亲——RLS 开始,它是 Power BI 中一个长期可用的特性。

行级安全性简而言之

RLS 的思想是在行级别上限制指定用户对数据的访问。然而,在我看来,RLS 的这个定义——它可以在行级别上限制特定用户对数据的访问——可能有点令人困惑。让我解释一下为什么…

作者图片

假设我有一个显示每个产品和国家的总销售额的矩阵。国家是我们矩阵中的,假设我们想限制特定用户组的访问权限,使其只能看到加拿大的数字。

我们将转到“建模”选项卡,管理角色并创建角色加拿大,这将仅过滤加拿大的数据:

作者图片

如果我选择“查看”角色“加拿大”,您会发现报告中只留下了加拿大号码:

作者图片

现在,如果您认为行级安全性是严格应用于行的,那么,在这种情况下,它是一个列:)

因此, 我喜欢将行级安全性理解为限制对特定属性的访问—例如,国家(仅像加拿大)、产品类别(即经济、常规等)。)、客户的位置等等。无论它们是否在报表中显示为行!

另一方面,我更倾向于将对象级安全性理解为限制对数字(度量)的访问,例如单位成本、公司开支或完整的数据对象——例如,整个表或表的整个列!

但是,回过头来更详细地解释 RLS…首先,RLS 对导入模式和 DirectQuery 都有效,但它在与 Analysis Services 或 Azure Analysis Services 数据源的实时连接模式下不可用。或者,最好这样说:RLS 实际上在实时连接模式下可用,但必须在源端定义(在 as 或 AAS 中),而不是在 Power BI Desktop 中!

首先定义角色(就像我在上面的例子中所做的那样),并使用 DAX 设置特定的过滤器——在我们的例子中,我设置的过滤器是:只显示国家等于“加拿大”的那些行。如果您来自 SQL 世界,您可以将这些条件视为 SQL 语句中的 WHERE 子句。

Power BI 中有两种主要类型的 RLS:

  • 静态 RLS
  • 在基本场景中很有用,当用户不多、没有复杂的限制要求、访问规则不经常改变时(根据我们前面的例子来考虑:来自加拿大的所有用户总是只能看到加拿大的数字)
  • 静态 RLS 的规则在 PBIX 文件中维护
  • 通常设置简单明了
  • 一些缺点:维护开销,大量手工工作,不可重用
  • 动态 RLS
  • 设置稍微复杂一点,但是您可以在更精细的级别上控制访问
  • 访问控制是通过表和关系在数据模型中定义的
  • 可重复使用,需要较少的维护
  • 一些缺点:增加了模型的复杂性

网上有很多很棒的文章,一步一步地解释了如何创建和管理静态和动态的 RLS,比如来自 Reza Rad 的这篇文章。本质上,您可以利用 DAX 中的 USERPRINCIPALNAME() 函数来捕获当前浏览报表的用户的登录信息。而且,根据您在数据模型中指定的规则,具有特定登录凭证的用户将只能看到数据的特定部分。

虽然设置静态 RLS 是一个简单明了的过程,但动态 RLS 提供了各种实现选项—基于您的业务场景,您可能希望将用户和角色拆分到不同的维度表中。此外,您应该评估过滤器的性能,因为您必须在启用双向交叉过滤或编写 DAX 来处理过滤器之间做出选择。

RLS 注意事项

  • 一个用户扮演多个角色 — RLS 滤波器以累加方式工作。这意味着,如果用户是限制访问属性“薪金”的角色“雇员”的成员,如果同一用户也是有权访问属性“薪金”的角色“财务”的成员,他们将能够看到数据
  • 性能影响 — RLS 是一个非常强大的功能,但像任何其他强大的功能一样,它也有代价。由于 RLS 将对每个 DAX 查询应用额外的过滤器,因此可能会发生 RLS 对性能降级负责的情况。尝试遵循 Power BI 数据建模的一般建议(世卫组织说,星型模式和 1:M 单向关系),并确保在维度表而不是事实表上实施 RLS 过滤器
  • 尝试为定义的数据集角色分配 AAD 组,而不是单个用户帐户(减少维护开销)
  • 查看来自微软的官方 RLS 指南,了解更多推荐实践

简而言之,对象级安全性

在 Power BI 中引入 OLS 之前,我使用了一个简单的 RLS 技巧对特定用户隐藏整个表。假设我想在我的数据模型中限制对整个 DimGeography 表的访问。我可以去做这样的事情:

作者图片

我已经创建了一个名为 Hide Geography 的角色,选择了 DimGeography 表,并将 FALSE()作为 DAX 表达式!

作者图片

嘣!矩阵现在完全空了!这很好,但是如果我只想隐藏特定的度量,例如,总销售额(我的意思是,实际上,您可能会限制对比销售额更敏感的度量的访问,但是让我们假设只有选定的一组人可以在我们的报表中看到总销售额)。

OLS 特写来拯救世界了!

等等…我怎样才能在力量 BI 中控制 OLS?!

对,这是第一个……姑且称之为限制吧!你不能直接从 Power BI Desktop 指定 OLS——相反,你需要一个叫做表格编辑器的外部工具

我们已经研究了表格编辑器提供的一些特性(例如,创建计算组,无论是否适用于 OLS,您都应该使用它。一旦你从这里下载了表格编辑器,你应该能够直接从 Power BI 桌面访问它。只需转到 External Tools 选项卡,您将看到所有可用的外部工具(您已经安装在 Power BI 桌面所在的同一台计算机上的工具)。

问题 2——不是每个表格编辑器版本都适合 OLS!

在这个例子中,我使用的是 2.11.6 版本的表格编辑器,我没有定义 OLS 的选项!

作者图片

一旦安装了最新版本,我就可以看到特定列的一整套新选项,其中之一是对象级安全性:

作者图片

现在,对于“销售额”列,我将设置“无”值来隐藏地理位置角色,而不是默认的 OLS:

作者图片

然后,我将保存在表格编辑器中所做的更改,并返回到 Power BI Desktop,检查当我作为隐藏地理位置角色成员开始查看报表时会发生什么:

作者图片

等等,什么??!!我的报告中有错误!但是,为什么,我做错了什么?我刚刚限制了对销售额指标的访问…

如果我是一个试图了解哪里出了问题的用户…好吧,假设我会发现这条消息非常尴尬:

作者图片

第三个问题——不要试图“理解”错误信息!

这个奇怪的结果来自于这样一个事实:当您将 OLS 应用到某个列 时,它的行为就像您从数据模型中删除了它一样! 并且,下图证实了:

作者图片

RLS 和 OLS 的主要区别在于,当您使用 DAX 过滤器应用 RLS 时,数据将不会显示在报告中,但基础元数据对象仍然存在于模型中!


此外,引用受限列的所有度量也将从数据模型中“消失”!

看看这个:

Sales Amt = SUM(FactInternetSales[SalesAmount])

这是一个超级简单的显式度量,显示销售额的总和。并且,当角色有权访问列 Sales Amount 时,这将按预期工作:

作者图片

但是,当我作为 Hide Geography 角色的成员开始浏览报表时,我会(再次)看到这个“直观的”错误:

作者图片

结论

Power BI 中的 RLS 和 OLS 都是强大的功能,为您提供了全方位的能力来控制 Power BI 解决方案中“谁能看到什么”。

但是,不要急于下结论,认为两者之间的唯一区别是应用规则的“方向”——水平与垂直。RLS 和 OLS 的工作方式完全不同——不仅因为您不能从 Power BI 本身配置 OLS(不像 RLS)——更因为它们对用户“隐藏”数据的方式:使用 RLS,对象仍然存在于模型中,而使用 OLS,它们完全被省略了!

感谢阅读!

成为会员,阅读 Medium 上的每一个故事!

清洁熊猫代码的最终参考

原文:https://towardsdatascience.com/the-ultimate-reference-for-clean-pandas-code-413df676e63c

一种清理数据的干净方法

Precious Plastic MelbourneUnsplash 拍摄的照片

熊猫可以将最混乱的数据转化为原始的机器学习数据集。不过,这个过程本身可能会相当混乱。

熊猫的代码很难读懂,原因有很多。首先,熊猫有许多不同的方式来完成同样的基本任务。子集化数据、添加新列、删除列、删除空值和许多其他过程可以通过许多不同的方式完成,这导致了不一致和混乱的代码。

对熊猫来说,管理数据清理步骤的顺序也是一个挑战。我职业生涯早期的大部分数据清理代码如下所示:

# Import data
df_raw = pd.read_csv("path/to/data/file.csv")

# Clean data
df_raw["id"] = df_raw["id"].astype(str)
df_merged = df_raw.merge(df2, on="id")
df_final = df_merged.drop(columns=["col_5", "col_6", "col_7"])

# Investigate data
df_agg = df_final.groupby("id").size()

“意大利面条式代码”,就像上面的例子,很难解释和调试。此外,命名空间中有如此多的数据框会耗尽内存,并且在处理大型数据集时可能会特别成问题。

最后,熊猫代码可能会变得混乱,因为很多时候它是在匆忙中编写的。无论您是渴望构建模型并需要提前快速清理数据集,还是有一批新的输出数据需要分析,作为一名数据科学家,熊猫通常是达到目的的一种手段。

那么,一劳永逸地编写干净的熊猫代码的秘诀是什么呢?两个字:方法链接

在这篇文章中,我与您分享了一组精选的 clean Pandas 方法,我用它们来预处理、调查、聚集和分析 Twitter 数据,在一个单独的项目中,我用它们来训练一个 Transformer 模型。利用这些例子将扩展您对方法链的理解,并作为您编写自己干净的 Pandas 代码的参考指南。

清洁熊猫的基本知识

Pandas 库附带了大量的内置方法。回想一下,在 Python 中,方法是属于一个特定类的对象的函数,并且被附加到对象本身上,就像df.to_csv()一样。方法也可以被链接,这意味着您可以一次对一个对象应用几个方法。

new_df = (                          # Wrap everything in ()'s
    original_df                     # Name of data frame to modify
    .query("text_length > 140")     # Subset based on text length
    .sort_values(by="text_length")  # Sort entire df by text length
    .reset_index()                  # Reset index of subsetted df
)

强迫自己使用 Pandas 方法而不是操作符一开始可能会令人沮丧,因为在大多数情况下,您正在重新学习您已经知道的东西。但是这就是为什么您应该坚持使用方法链的原因:

  • 它使代码更具可读性。
  • 它消除了对多个中间数据帧的需要,从而节省了内存。
  • 更容易调试。只需一行一行地注释掉数据帧操作,看看哪种方法给你带来了问题。

数据清理

我有一个由美国参议员制作的原始推文的数据框架,我通过具有提升访问凭证的 Twitter API v2 获取。以下是一些数据:

现在让我们做一些链接来清理这一点。在这一次调用中,我们将选择并删除列,格式化日期列,清理 tweet 的原始文本,计算文本长度,合并两个数据框,删除重复的行,重命名列,重新排序列名,按日期排序,并删除 tweet 长度为零的所有行。

你可能对这些方法中的大部分都很熟悉。也许这里最重要的方法是.assign(),它允许您创建新列或覆盖旧列。我主要出于两个目的使用assign()方法。

  1. 更改现有列的数据类型:
.assign(column_name=original_df["column_name"].astype(str)

2.将函数应用于整列:

.assign(new_column=original_df["column_name"].apply(function_name)

请注意,您也可以将多个函数按顺序应用于一个列。

数据调查

在对原始 Twitter 数据实现了这个庞大的链之后,我们有了一个整洁的、可读的数据框架,我们想要检查它。

简单的方法.info()为您提供了关于数据框的大量信息,包括:

  • 行数(和索引范围)
  • 列数
  • 列名
  • 列的数据类型
  • 每列非空值的数量
  • 内存使用

这个方便的一行程序可以获得每列的空值数量:

.describe()方法为您提供了每个列中数据的实际值和分布的概述。根据列的数据类型将.describe()应用于列,以获得更清晰的输出,如下所示:

dtype="object"上调用.describe()的结果不是特别有洞察力,因为列idusernametext包含字符串值而不是分类数据。然而,party列的行值可能会显示一个潜在的模式。

数据汇总和分析

分类变量的数据聚合通常是我为 NLP 项目进行的任何分析的第一部分。tweet 数据集中最明显的聚合变量是party

接下来,让我们转到一些更高级的聚合。像这样按顺序链接.groupby().agg()函数可以更容易地从整体上理解聚合:

应用聚合后,生成的索引难以阅读。.pipe()方法是将一个函数应用于整个数据帧的干净熊猫方法。

结论

编写干净的熊猫代码的关键是强迫自己使用方法链接。这样做最终会使您的代码更具可读性和可解释性,更易于调试,甚至节省内存。正如本文所展示的,您可以在数据生命周期的每个部分使用方法链,包括清理、调查、聚集和分析数据。有关方法链接的更多信息,请查看下面的参考资料。

如果您想了解最新的数据科学趋势、技术和软件包,请考虑成为中级会员。你将可以无限制地访问像《走向数据科学》这样的文章和博客,并且你会支持我的写作。(每个会员我赚一小笔佣金)。

https://medium.com/@mary.newhauser/membership

想要连接吗?

  • 📖跟着我上
  • 🔗查看我的其他项目

资源

参考

(1) M. Newhauser, DistilBERT 参议员推文 (2022)。

(2) T. Augspurger,现代熊猫(上) (2016)。

(3) M. Harrison & T. Petrou, Pandas 1.x cookbook:使用 Python 进行科学计算、时间序列分析和探索性数据分析的实用食谱(第二版) (2020)。

(4) Python 软件基础, 9。类别 (2022)。

(5) Twitter, Twitter API 文档 (2022)。

Jupyter 笔记本的终极替代品

原文:https://towardsdatascience.com/the-ultimate-replacements-to-jupyter-notebooks-51da534b559f

讨论 Jupyter 笔记本电脑的最佳替代方案,用于解释数据科学项目

照片由星球卷上的 Unsplash

有多种工具可供数据科学爱好者探索这一主题。在代码编辑器和集成开发环境的几个选项中,开发人员可以选择来构建他们的项目,其中一个更受欢迎的选项是 Jupyter 笔记本。

Jupyter 笔记本通常是大多数初级数据科学家深入研究该主题的推荐方式。它们提供了一种快速、简洁、基于单元的执行方式,来有效地解释基础主题的项目。

在每个单元的执行过程中跟踪您的进度的能力允许用户跟上他们特定任务所需的步伐。Jupyter 笔记本无疑是执行探索性数据分析的最佳选择,以便相应地可视化和解释您的数据。

虽然 Jupyter 笔记本是初学数据科学家的绝佳选择,但大多数专家为了更好的体验而远离它们。在这篇文章中,我们将讨论 Jupyter 笔记本的一些缺点,以及这些笔记本在 Deepnote 中令人难以置信的替代品。

如果观众不完全熟悉 Jupyter 笔记本是什么,以及它们对数据科学有多有用,我建议通过下面提供的链接查看我以前的一篇文章。它涵盖了初级数据科学爱好者从头开始使用 Jupyter 笔记本所需了解的几乎所有内容。

Jupyter 笔记本的缺点:

照片由 Tim GouwUnsplash 上拍摄

Jupyter 笔记本是向初学数据科学家推荐的开始学习机器学习和数据科学的最佳选择。尽管这些 Jupyter 笔记本对于初学者来说是一个出色的入门工具,但过渡到开发人员可用的一些更好的选择变得至关重要。在文章的这一部分,我们将看看本地 Jupyter 笔记本的三个主要缺陷。

1.缺少 IDE 功能:

Jupyter 笔记本被归类为基于网络的交互式计算平台。然而,它们缺乏大多数其他代码编辑器和 ide 所具备的一些基本特性。其中一些特性包括语法突出显示、代码辅助工具、调试器和其他类似的附加特性。因此,初学者可能倾向于其他选择,如 Visual Studio Code 或 Pycharm,以获得更好的开发环境。

还有一个新的选项,允许开发人员在 Visual Studio 代码环境中计算 Jupyter 笔记本。然而,在运行这些笔记本电脑时,仍然存在明显的限制。超出文件大小的输出需要在文本编辑器中打开,整体执行机制可能会给一些人带来不便。

2.协作团队效率较低:

一旦你作为一名数据科学家取得了足够的进步,你就会意识到数据科学最重要的一个方面就是团队合作。数据科学领域的大多数复杂项目都需要有效的协作团队。虽然您可以与您的团队共享 Jupyter 笔记本,但缺少允许您在同一台笔记本上同时工作的功能是一个很大的缺陷。

共享功能没有太大价值,因为即使简单的 Python 文件也可以与个人共享。Jupyter 笔记本的其他访问权限需要远程托管,这本身就有潜在的风险。因此,我们可以得出结论,这些 Jupyter 笔记本电脑,尽管对开发人员来说是一个很容易分享的选择,但缺乏一个重要的功能,使用户能够与他们的团队合作,有效地解决更复杂的项目。

3.内核崩溃和安装问题:

在本节中,我们将触及 Jupyter 笔记本中存在的两个主要问题,以及初学数据科学家面临的一个关键问题。有多少数据科学爱好者第一次安装 Jupyter 笔记本就认为可以立刻上手一些编程?

在经历了安装 Jupyter 笔记本(通过 anaconda 或本地虚拟环境)的繁琐过程后,您意识到要解释项目,您需要在开始之前再安装几个库。除了安装之外,您还会浪费一些宝贵的时间来管理数据库、跟踪您的实验,或者耗尽内存,导致内核崩溃。

deep note:Jupyter 的协作式云托管替代方案:

虽然 Jupyter 笔记本有一些缺点,但大多数数据科学家更喜欢基于单元的 Jupyter 笔记本风格的环境来执行他们的大多数机器学习和数据科学项目。如果前面提到的问题都解决了,但你仍然有一个类似 Jupyter 的界面,那不是很酷吗?

解决前面提到的所有问题并提供详细解决方案的最佳平台之一是 DeepnoteDeepnote 为与您的数据科学团队进行高效协作提供了解决方案。它的大部分主要服务都是免费的,允许几乎任何用户直接投入到他们项目的开发中。

Deepnote 的工作环境中内置了一些最好的特性。它为用户提供了下图中显示的自动完成属性。访问这些特性允许开发人员以更快的速度更有效地解释他们的代码。

作者截图

它还有一个奇妙的嵌入功能,允许数据科学家将他们的代码单元嵌入到代码片段中,以便轻松共享。在每个代码单元中,您可以选择嵌入和共享代码选项,通过该选项,用户可以共享各自的代码块。下面是一个用 Deepnote 嵌入代码块的例子。这段代码代表了我以前的一篇文章中提到的条形图的可视化。

虽然 Deepnote 允许团队协作是首屈一指的,但它也解决了 Jupyter 笔记本中持续存在的大多数安装和内核问题。大多数先决条件库,包括像 TensorFlow 这样的深度学习框架,都已经安装在工作环境中,允许数据科学爱好者直接投入到他们的研究中。

笔记本电脑在云环境中运行,可以更好地跟踪您的项目进度。Deepnote 引入的历史特性解决了大部分内核问题。该功能允许用户在发生事故或崩溃的情况下回溯并恢复到之前的工作。

作者截图

最后,Deepnote 通过集成几个生产工具解决了数据管理和实验跟踪的问题。这些工具包括 Google Drive 和 Google Cloud Storage、Amazon-s3、My SQL 和 Postgre SQL、Redshift、Big Query 和大量其他选项,进一步增强了 Deepnote 的功能。

与 Google Colab 的比较:

我们已经讨论了 Deepnote 如何为初学者和专业数据科学家提供一些最好的实用工具,以有效地与他们的团队合作,顺利地构建他们的项目。在本节中,让我们将 Deepnote 与另一个免费服务(如 Google Colab)进行直接比较,以了解一些关键的复杂性。

1.共享笔记本的不便之处:

Google Colab(协作实验室)运行在云环境中,允许用户访问 Jupyter 笔记本来执行和记录他们的代码。

虽然该平台提供了预装库的免费笔记本,但代码共享的问题仍然存在。虽然用户可以共享一个帐户或各自的笔记本,但与 Google Colab 进行有效的团队合作是复杂的。

另一方面,Deepnote 允许您将数据科学小组添加到工作空间,以便您可以立即开始工作。

2.乏善可陈的功能和集成:

之前提到的 Jupyter 笔记本的问题对于 Google Colab 仍然存在。它缺少一些关键的 IDE 特性,比如代码辅助和有效调试的帮助。

与 Deepnote 相比,Google Colab 的集成选项较少。Google Colab 可以有效地链接到 Google Colab 或 Google Cloud 环境,但在其他一些关键集成方面存在困难。虽然您可以将 Google Colab 与其他一些流行的工具联系起来,但它们更复杂,并且无法无缝执行。

3.有限使用问题:

Google Colab 主要与 Google Drive 集成,后者只有 15GB 的活动空闲空间,对于大数据和复杂的机器学习项目来说几乎不够用。运行时间也是有限的,有时可能会因为较长的空闲时间而导致服务器意外关闭。

Google Colab 的内核问题更加明显,因为有时它们可能会在一段时间后自动关闭,导致一些数据丢失。与 Deepnote 相比,缺乏有效的历史跟踪系统也是一个关键问题。

因此,Deepnote 是一个很好的选择。我建议初学者和高级数据科学家都来看看并构建他们独特的项目!

结论:

乔安娜·科辛斯卡在 Unsplash 上的照片

“从文明诞生到 2003 年,总共有 5eb 的信息,但现在每两天就有这么多信息产生。”
埃里克·施密特

在本文中,我们探讨了 Jupyter 笔记本的一些缺点,这些缺点伤害了大多数初学数据科学爱好者的体验。Deepnote 是一款 Jupyter 兼容的数据笔记本,无缝运行在云环境中,并与 GitHub 和亚马逊 S3 等一些最好的工具相集成。

除了所有生活质量的增加,Deepnote 还提供了高效的团队合作机会和项目协作。我们对 Deepnote 和另一个流行的平台 Google Colab 进行了简单的比较。我们研究了 Deepnote 相对于后者的一些优势,以及为什么它是初学数据科学的爱好者必须了解的免费服务。

我强烈建议您亲自尝试该平台,并与您的团队合作构建创新项目!在接下来的文章中,我将使用 Deepnote 进行一些很酷的机器学习和可视化项目。

如果你想在我的文章发表后第一时间得到通知,请点击下面的链接订阅邮件推荐。如果你希望支持其他作者和我,请订阅下面的链接。

https://bharath-k1297.medium.com/membership

如果你对这篇文章中提到的各点有任何疑问,请在下面的评论中告诉我。我会尽快给你回复。

看看我的一些与本文主题相关的文章,你可能也会喜欢阅读!

</7-best-research-papers-to-read-to-get-started-with-deep-learning-projects-59e11f7b9c32>

谢谢你们坚持到最后。我希望你们都喜欢这篇文章。祝大家有美好的一天!

州-县-FIPS 的终极工具

原文:https://towardsdatascience.com/the-ultimate-state-county-fips-tool-1e4c54dc9dff

唯一的工具,你需要映射美国 FIPS 代码到国家,县,缩写,反之亦然

KOBU 机构Unsplash 上拍摄的照片

问题是

当使用地理位置进行数据科学研究时,经常会篡改美国 FIPS 代码、州名、县名、缩写等。互联网上有各种各样的信息表,但我找到的每一个都在某些方面有所欠缺。缺少州名缩写,或者县名格式不一致,或者表是可视化的,不容易下载用于编程,或者其他一些问题。

解决方案

本文用一个通用的美国 FIPS-州-县表解决了所有这些问题。您可以轻松地将其导入任何电子表格、数据准备层或编程语言。如果你想检查我工作的正确性或者添加一个特性,用于创建表格的 Python/pandas 代码可供检查或修改。

可下载表格允许您:

  • 通过 FIPS 代码查找州和县,反之亦然。
  • 查找州名的官方缩写,反之亦然。
  • 将 FIPS 代码转换成可读的州-县字符串,反之亦然。
  • 将两位数的 FIPS 州代码转换为州名或缩写,反之亦然。

该表如下所示:

作者图片

请注意,完整的 FIPS 县代码由一个 2 位数的州代码加上一个 3 位数的州内县代码组成。

要使用该表,只需将其导入您喜欢的数据软件或编码语言。对于 Python/pandas:

path = "~/Desktop/fips2county.tsv"FipsDF = pd.read_csv(path, sep='\t', header='infer', dtype=str, encoding='latin-1')

然后翻译州,县和代码的任何方式你想要的。假设您有一个名为 MyDF 的数据帧,其中包含 5 位 FIPS 县代码,如下所示:

PLACE         FIPSManhattan     36061
Bedford MA    25017
Yosemite      06043

并且您想要可读的州和县名。编写类似这样的代码:

StateCountyDF = FipsDF[["CountyFIPS", "CountyName", "StateName"]]MyDF = MyDF.merge(StateCountyDF, how='left', left_on="FIPS", right_on="CountyFIPS")MyDF = MyDF.drop(columns=["FIPS"])   # get rid of duplicate column

这产生了:

PLACE        CountyFIPS   CountyName      StateNameManhattan    36061        New York        New York
Bedford MA   25017        Middlesex       Massachusetts
Yosemite     06043        Mariposa        California

如果要添加州缩写:

StateAbbrDF = FipsDF[["StateAbbr", "StateName"]].drop_duplicates()MyDF = MyDF.merge(StateAbbrDF, how='left', on="StateName")

这产生了:

PLACE        CountyFIPS   CountyName    StateName       StateAbbr
Manhattan    36061        New York      New York        NY
Bedford MA   25017        Middlesex     Massachusetts   MA
Yosemite     06043        Mariposa      California      CA

我是如何做桌子的

这个项目的真实来源来自美国人口普查。我用 MacOS 工作表手动打开了那里的 XLSX 文件,并将它们导出到 TSV 文件,做了一些小的编辑,以便更容易导入到熊猫文件中。那些 TSV 文件代表州 FIPS 代码县 FIPS 代码,它们必须组合在一起才能使用。

使用 Python/pandas,我将原始代码处理成最终的单个表格,其中包含了上面列出的所有特性。请随意修改或扩展此代码,遵守麻省理工学院的许可证,该许可证要求对我的作品进行署名。

欲了解更多信息

2022 年及以后的终极 TensorFlow-GPU 安装指南

原文:https://towardsdatascience.com/the-ultimate-tensorflow-gpu-installation-guide-for-2022-and-beyond-27a88f5e6c6e

无论如何,始终在您的 PC 上安装最新 GPU 版本的 TensorFlow 的终极指南

本工程照片拍摄于un plash

过去十年,深度学习的崛起令人瞩目。它凭借其创新和突破性的技术在几乎每一场比赛中占据主导地位,同时也带来了几种新型的研究和训练方法。处理深度学习模型以解决复杂计算问题的最流行的方法之一是借助深度框架。

TensorFlow 就是这样一个流行的深度学习库,用于构建和构造模型,以找到众多任务的解决方案。TensorFlow 被认为是解决几乎任何与神经网络和深度学习相关的问题的最佳库之一。虽然这个库可以有效地处理大多数更小更简单的数据集,以在 CPU 上完成任务,但它真正的强大之处在于对图形处理单元(GPU)的利用。

GPU 即兴发挥这种深度学习框架的性能,以达到新的高度和峰值。然而,深度学习程序员、开发人员和爱好者面临的最令人烦恼的问题之一是 CUDA 错误的困扰。对于大多数个人来说,这种经历相当令人沮丧,因为这是在处理深度学习模型时经常发生的事情。

在本文中,我们将探讨如何获得 TensorFlow 的最新版本,并与现代技术保持同步。在你深入研究之前,你可以访问我以前的一个博客,并通过下面提供的链接了解你是否真的需要一个 GPU 来开始深度学习。

如果读者不想在本地安装 TensorFlow 的麻烦,并希望在 GPU 支持下在云上免费使用它,请查看 Saturn Cloud ,这是一个面向团队的协作、可扩展的数据科学平台。

对安装问题的理解:

如果您总是希望使用 GPU 运行 TensorFlow 的最新版本,那么 Anaconda 环境中的以下命令将不起作用。

conda install -c anaconda tensorflow-gpu

虽然上面的命令仍然会安装 TensorFlow 的 GPU 版本,但如果您有可用的版本,它最终会安装 TensorFlow 的早期版本,如 TF 2.3、TF 2.4 或 TF 2.5,而不是最新版本。您可能需要等待相当长的时间才能收到 TensorFlow 最新版本的支持更新,在撰写本文时,该版本是 TensorFlow 2.7。

在本文中,我们将分解完整的步骤,以便无论如何都能收到 TensorFlow 的最新 GPU 版本。请坚持阅读这篇文章,并跟随阅读 TensorFlow-GPU 最新版本安装过程的完整指南。

要遵循的步骤:

让我们来看看我们必须严格遵循的所有步骤,以便始终能够下载更现代版本的 TensorFlow。

1.官方版本来源:

第一步是访问官方 TensorFlow 网站,查看目前可用的 TensorFlow 最新版本。一旦你弄清楚并成功确定了你的操作系统的 TensorFlow 的最新版本,看看最新 GPU 版本的安装的基本要求。

相应地检查 CUDA 版本和 cuDNN 版本的精确列表,以获得要下载的精确元素的清晰图片。在撰写本文时,TensorFlow 的最新版本是 2.7。该版本需要额外下载 CuDNN 版本 8.1 和 CUDA 版本 11.2。查看适合您的最新版本,并下载具体内容。

此外,请确保检查您正在安装的 TensorFlow 变体所提供的 Python 支持版本。您不希望最终拥有一个当前版本的 TensorFlow 不支持的旧 Python 版本。

2.下载 Microsoft Visual Studio:

下一个关键的安装是微软 Visual Studio 框架,这是在 Windows 平台上继续进一步安装过程所必需的。点击上面的链接,您将进入下载网站,在那里您可以按照简单的说明成功完成下载。目前,除非用户愿意,否则不需要安装任何额外的工作负载。

这个自由软件 IDE 帮助我们集成了众多编程语言的组件,如 Python、C、C++等等,使我们能够更好地执行一些特定的操作。成功下载该软件后,您可以关闭它,并进入下一个必要的安装。Visual Studio 代码也是我最喜欢的 Python ide 之一。查看下面的文章,了解更多不同类型的 ide。

3.安装 CUDA 工具包:

下一个关键步骤是下载下面的 CUDA 工具包。选择与最新 TensorFlow 版本相匹配的正确版本。下载带有最新更新的 CUDA 工具包,并选择合适的参数作为您的系统设置。查看以下网站,了解如何填写您的下载信息。

我选择了 64 位架构的 Windows 操作系统平台。我会做一个本地的。但是查看者可以相应地选择他们偏好的参数。一旦所有正确的目标平台被选中,网站会给你一个下载链接,你可以点击。下载成功完成后,接下来是简单的快速安装。

4.安装 CuDNN:

现在是倒数第二步,也是稍微长一点的一步,去 CuDNN 安装网站。继续点击屏幕上的下载 CuDNN 选项。要继续这一过程,您需要一个可以轻松免费使用的帐户,并登录以访问必要的内容。登录您的帐户后,下载 CuDNN 组件。

作者截图

在下载的文件夹中,复制文件夹内容并将其放在位于以下目的地的 CUDA 文件夹中。

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0

替换下载文件夹的内容,并继续添加环境变量的最后一步。选择 bin 文件夹路径和 libnvvp 位置,并将其复制粘贴到环境变量的路径中。

作者截图

5.最终命令安装:

在最后一步,我们将首先重启我们的电脑。在 Anaconda 发行版中创建一个虚拟环境。如果您还没有下载它,那么安装相当简单,我强烈推荐您使用它。一旦您准备好了所有的需求,输入下面的命令。

conda create --name tf_2.7 python==3.9

现在开始激活新创建的环境,如下所示。

conda activate tf_2.7

在最后一步,您可以继续执行简单的 pip 安装,如下所示。

pip install tensorflow

上述命令将在给定的虚拟环境中,在您的系统上成功安装 CPU 和 GPU 版本。如果你对这个安装过程的书面版本有任何问题,我强烈推荐看看这个令人惊叹的 YouTube 视频,它启发了这篇文章并经历了所有的步骤。

结论:

Fotis FotopoulosUnsplash 上拍摄的照片

“人工智能、深度学习、机器学习——不管你在做什么,如果你不懂,就去学吧。因为否则你会在三年内变成恐龙。”
——马克·库班。

在数据科学领域保持更新总是至关重要的,尤其是在深度学习方面。对于最新版本,您将收到最新的更新、各自的修复程序和最新功能。即使是最小的变化,你也会获得更好的整体体验。这个事实对于 TensorFlow 也是成立的。

随着 TensorFlow 在每个开发版本中的不断更新,它们添加了所有用户都可以受益和利用的新功能和开发。因此,强烈建议您始终尝试获取 TensorFlow 的最新 GPU 版本。在深度学习的世界里,保持更新是至关重要的,因为你永远不知道一项新技术或新发现什么时候会在眨眼之间取代现有的方法。

与在本地安装 TensorFlow 相反,一个奇妙的替代方案是利用土星云上提供的免费 GPU 支持。它为开发人员提供了一个绝佳的机会,让他们可以切换到云环境进行深度学习项目。

如果你想在我的文章发表后第一时间得到通知,请点击下面的链接订阅邮件推荐。如果你希望支持其他作者和我,请订阅下面的链接。

https://bharath-k1297.medium.com/membership

如果你对这篇文章中提到的各点有任何疑问,请在下面的评论中告诉我。我会尽快给你回复。

看看我的一些与本文主题相关的文章,你可能也会喜欢阅读!

谢谢你们坚持到最后。我希望你们都喜欢这篇文章。祝大家有美好的一天!

大批量训练计划背后的潜在危险

原文:https://towardsdatascience.com/the-underlying-dangers-behind-large-batch-training-schemes-6cdc0e511ef1

Julian Hochgesang 在 Unsplash 上拍摄的照片

一般化差距背后的方法和原因,以及如何将其最小化

近年来,深度学习以其多功能性、广泛的应用范围和并行化训练能力,席卷了机器学习领域。深度学习算法通常使用基于梯度的方法进行优化,在神经网络中称为“优化器”。优化器使用损失函数的梯度来确定对网络参数值的最佳调整。大多数现代优化器偏离了原始的梯度下降算法,并采用它来计算从整个数据集提取的一批样本中的梯度的近似值。

神经网络的本质及其优化技术允许并行化或批量训练。当允许计算能力显著加快具有多达数百万个参数的神经网络的训练时,通常采用大批量。直观上,批量越大,每次梯度更新的“有效性”就越高,因为数据集的相对重要部分被考虑在内。另一方面,具有较小的批量意味着基于从数据集的较小部分估计的梯度来更新模型参数。从逻辑上讲,数据集的较小“块”不太能代表要素和标注之间的整体关系。这可能导致一个结论,即大批量总是有利于训练。

大批量与小批量。图片由作者提供。

然而,上述假设是在没有考虑模型推广到看不见的数据点的能力和现代神经网络的非凸优化性质的情况下推导出来的。具体而言,各种研究已经通过经验证明并观察到,无论神经网络的类型如何,增加模型的批量大小通常会降低其推广到未知数据集的能力。“泛化差距”这个术语就是为这种现象创造的。

在凸优化方案中,访问数据集更重要的部分将直接转化为更好的结果(如上图所示)。相反,访问更少的数据或更小的批量会降低训练速度,但仍然可以获得不错的结果。在非凸优化的情况下,这是大多数神经网络的情况,损失图的确切形状是未知的,因此问题变得更加复杂。具体来说,两项研究试图调查和模拟由批量大小差异引起的“泛化差距”。

泛化差距的方式和原因

在 Keskar 等人(2017)的研究论文“ 关于深度学习的大批量训练:泛化差距和尖锐极小值 ”中,作者围绕大批量训练制度进行了几项观察:

  1. 与用较小批量训练的相同网络相比,大批量训练方法倾向于过度适应。
  2. 大批量训练方法容易陷入甚至被亏损前景中的潜在鞍点所吸引。
  3. 大批量训练方法倾向于放大它找到的最接近的相对最小值,而用较小批量训练的网络倾向于在确定有希望的最小值之前“探索”损失情况。
  4. 与用较小批量训练的网络相比,大批量训练方法倾向于收敛到完全“不同”的极小点。

此外,作者从神经网络如何在训练期间导航损失景观的角度解决了泛化差距。相对较大批量的训练往往会收敛到尖锐的极小值,而减少批量通常会导致陷入平坦的极小值。一个尖锐的极小值可以被认为是一个狭窄而陡峭的峡谷,而一个平坦的极小值类似于一个低而温和的丘陵地形的广阔景观中的山谷。用更严谨的术语来表述:

锐极小元的特征在于 f(x)*的 Hessian 矩阵的大量正特征值,而平极小元的特征在于f(x) 的 Hessian 矩阵的大量较小正特征值。*

“落入”尖锐的极小值可能会比平坦的极小值产生看似更好的损失,但它更容易对看不见的数据集进行较差的概化。下图显示了 Keskar 等人的一个简单的二维损失图。

与平坦最小值相比的急剧最小值。来自凯斯卡等人。

我们假设看不见的数据点的特征和标签之间的关系类似于我们用于训练的数据点,但不完全相同。如上例所示,训练和测试之间的“差异”可能是轻微的水平偏移。当应用于看不见的数据点时,由于其对最小值的狭窄适应,导致尖锐最小值的参数值变成相对最大值。不过,如上图所示,在平坦最小值的情况下,“测试函数”的轻微变化仍会将模型置于损失格局中相对最小的点。

通常,与使用较大批量相比,采用小批量会增加训练的噪音。由于梯度是用较少数量的样本进行估计的,因此相对于整个数据集的“损失景观”,每次批量更新时的估计将相当“嘈杂”。早期阶段的嘈杂训练有助于模型,因为它鼓励探索损失情况。Keskar 等人还指出…

“我们已经观察到,深度神经网络的损失函数景观是这样的,大批量方法被吸引到具有尖锐极小值的区域,并且与小批量方法不同,不能逃脱这些极小值的吸引盆地。

虽然较大的批量被认为给训练带来更多的稳定性,但是小批量训练提供的噪音实际上有利于探索和避免急剧最小化。我们可以有效地利用这一事实来设计一个“批量调度程序”,从小批量开始,以允许探索损失情况。一旦确定了大方向,我们就专注于(希望是)平坦的最小值,并增加批量大小以稳定训练。如何在训练中增加批量以获得更快更好的结果的细节将在下面的文章中描述。

* *

在 Hoffer 等人(2018 年)在他们的论文“ 训练更长,推广更好:在神经网络 的大批量训练中缩小推广差距”中的一项更近期的研究中,作者扩展了 Keskar 等人先前探索的想法,并提出了一种简单而优雅的解决方案来缩小推广差距。与 Keskar 等人不同,Hoffer 等人从不同的角度攻击泛化差距:权重更新的次数及其与网络损耗的相关性。

Hoffer 等人对泛化能力缺口现象提出了一个有些不同的解释。请注意,批量大小与重量更新次数成反比;也就是说,批量越大,更新就越少。基于经验和理论分析,随着权重/参数更新次数的减少,模型接近最小值的机会大大减少。

首先,需要理解通过基于批次的梯度下降的神经网络优化过程本质上是随机的。从技术上来说,术语“损失景观”指的是高维度表面,其中所有可能的参数值相对于由这些参数值产生的所有可能的数据点的损失值绘制。请注意,损失值是跨所有可能的数据样本计算的,不仅仅是定型数据集中可用的数据样本,而是针对该方案的所有可能的数据样本。每次从数据集中对一个批次进行采样并计算梯度时,都会进行更新。从整体损失情况来看,这种更新被认为是“随机的”。

一个可能亏损的例子。这里,z 轴是损耗值,而 x 和 y 轴是可能的参数值。图片由作者提供。

Hoffer 等人进行了类比,即通过基于随机梯度的方法优化神经网络是一个粒子在随机位势上进行随机行走。你可以把这个粒子想象成一个“步行者”,盲目地探索一个有着山丘和山谷的未知高维表面。在整个表面的尺度上,粒子的每个移动都是随机的,它可以向任何方向移动,无论是朝向局部最小值、鞍点还是平坦区域。基于先前对随机电位上的随机行走的研究,行走者从其起始位置行进的距离与其行走的步数成指数关系。例如,要翻过一座高度为 d 的山,需要粒子 eᵈ 随机行走才能到达山顶。

说明“行走”次数和行走距离之间的指数关系。

在随机高维表面上行走的粒子可以被解释为权重矩阵,每个“随机”步骤或每次更新都可以被视为“粒子”采取的一个随机步骤。然后,从我们上面建立的移动粒子直觉出发,在每个更新步骤 t ,权重矩阵到其初始值的距离可以建模为

其中 w 是权重矩阵。在随机电位上行走的“粒子”的渐近行为被称为“超慢扩散”。从这种统计分析并基于 Keskar 等人的结论,平坦极小值通常比尖锐极小值更好地“收敛”,可以得出以下结论:

在初始训练期间,为了搜索具有“宽度” d 的平坦最小值,权重向量,或者在我们的类比中的粒子,必须行进距离 d ,从而至少花费 eᵈ 迭代为了实现这一点,需要高扩散率,这保持了数值稳定性和总的高迭代次数。

“随机电位上的随机行走”中描述的行为可以在 Hoffer 等人进行的实验中得到经验证明。下图绘制了不同批次大小的迭代次数与权重矩阵的欧几里德距离的关系。可以看出明显的对数(至少是渐近)关系。

根据权重矩阵与初始化的距离绘制的迭代次数。来自霍弗等人。

缩小推广差距的方法

在神经网络训练中不存在固有的“泛化差距”,可以对学习速率、批量大小和训练方法进行调整以(理论上)完全消除泛化差距。基于 Hoffer 等人做出的结论,为了在训练的初始步骤期间增加扩散率,可以将学习率设置为相对较高的数。这允许模型采取相当“大胆”和“大”的步骤来探索更多的损失领域,这有利于模型最终达到平坦的极小值。

Hoffer 等人还提出了一种算法来降低泛化差距的影响,同时能够保持相对较大的批量。他们检查了批处理规范化,并提出了一个修改,幽灵批处理规范化。批量标准化减少了过度拟合,提高了泛化能力,并通过标准化前一个网络层的输出加快了收敛过程,实质上是将值“放在同一尺度上”以供下一层处理。统计数据是在整个批次上计算的,在标准化之后,学习一种转换来适应每一层的特定需求。典型的批处理规范化算法如下所示:

其中 γβ 代表学习到的变换, X 为一批训练样本的前一层输出。在推断过程中,批处理规范化使用预先计算的统计数据和从训练阶段学习到的转换。在大多数标准实现中,平均值和方差在整个训练过程中存储为指数移动平均值,动量项控制每次新的更新对当前移动平均值的改变程度。

Hoffer 等人提出,通过使用“幽灵批次”来计算统计数据并执行批次标准化,可以减少泛化差距。通过使用“幽灵批次”,从整个批次中提取小块样本,并通过这些小“幽灵批次”计算统计数据。通过这样做,我们将增加权重更新次数的概念应用于批量标准化,这不会像整体上减少批量大小那样修改整个训练方案。但是,在推断过程中,会使用整个批次的统计数据。

幻影批处理规范化算法。来自霍弗等人。

在 Tensorflow/Keras 中,可以通过将 Batch Normalization 层中的virtual_batch_size参数设置为 ghost 批处理的大小来使用 Ghost 批处理规范化。

结论

在现实世界的实践中,泛化差距是一个相当容易被忽视的话题,但它在深度学习中的重要性不容忽视。有一些简单的技巧可以减少甚至消除这种差距,例如

  • Ghost 批处理规范化
  • 在训练的初始阶段使用相对较大的学习率
  • 从小批量开始,随着训练的进展增加批量

随着研究的进展和神经网络可解释性的提高,泛化差距有望完全成为过去。

ML 动力产品令人不安的最佳点

原文:https://towardsdatascience.com/the-unnerving-sweet-spot-for-ml-powered-products-c34b54e17179

维护一个推理服务器是痛苦的,但也是必要的。

瓦迪姆·博古洛夫在 Unsplash 上的照片

这篇文章是解决生产 ML 世界中最可怕的想法的系列文章的继续:把该死的东西投入生产。

在以前的故事中,我们看到了两种不同的方法来设计机器学习(ML)驱动的应用程序。首先,我们研究了为什么您希望将模型保存在 web 服务器中,以及为什么您不应该这样做。

将您的模型与您的核心业务逻辑放在一起是必须的,因为您尝试不同的想法,并且希望从一个信任的测试人员圈子中获得快速反馈,但是当在生产中部署时,这是不够的。

我们讨论的第一个解决方案是一个非常简单的技术,它允许我们将模型从 web 服务器中分离出来。我们仔细研究了数据库中的模型解决方案,适合这种方法的用例,以及它的优缺点。

数据库中的模型方法实现起来很简单,但是它的范围有限。它也导致陈旧的模型,并不总是为我们的用户提供有价值的服务。

那么,我们如何解决前面两种方法所面临的问题呢?这个故事研究了最常见的架构设计:如何将您的模型放在它自己的推理服务器中。

推理服务架构——作者图片

为我们的模型创建和维护一个单独的 web 服务增加了基础设施的复杂性,但是,正如我们将看到的,这是大多数 ML 支持的产品的最佳选择。

Learning Rate 是一份时事通讯,面向那些对 AI 和 MLOps 世界感到好奇的人。你会在每个月的第一个星期六收到我关于最新人工智能新闻和文章的更新和想法。订阅这里

模型即服务方法

模型即服务(MaaS)架构范式允许我们在自己的推理服务中在线运行模型。这个推理服务就像其他后端一样,是专门为运行 ML 模型而设计的。这意味着它有适当的基础设施支持;一台或多台能够保持一个或一系列 ML 模型性能的机器。

我们的后端(即我们的 web 服务器)通过扮演客户机的角色进行交互:它发出请求并接收响应。例如,当它从客户端(例如,我们的用户)接收到识别图像中存在的对象的请求时,它将请求转发到推理服务器,模型进行预测,发回响应,最后,web 服务器将响应转发回客户端。

正如我们在介绍中所说的,这种方法似乎是大多数 ML 支持的应用程序的最佳选择。但这是为什么呢?让我们深入研究一下这种方法,什么时候应该使用它,并讨论一下它的优缺点。

赞成者

可以说,MaaS 方法是服务于 ML 模型的最常见的方法。这是大多数用例推荐的方法,这是有充分理由的。

首先,ML 模型代码中的一个错误不会导致整个应用程序崩溃。您将有机会优雅地处理错误,并仍然设法为您的用户提供可靠的服务。

然后,正如我们之前所说的,运行单独的推理服务允许我们为 ML 模型选择最佳的硬件,并适当地扩展它。需要 GPU 加速器吗?您需要垂直或水平扩展服务器吗?使用这种方法,您可以根据需要任意扩展服务,而不会影响应用程序的其他部分。

最后,这种方法提供了灵活性。您的模型现在已经成为一个独特的 web 服务。因此,您可以在多个应用程序、部分应用程序中重用它,甚至向公众开放它。你可以围绕它建立一个 API,并将其商业化,就像 OpenAPI 一样。

黑暗面

MaaS 方法最突出的缺点是它给系统增加了更多的延迟。当您的服务器与您的模型交互时,它必须通过网络发出请求。这会增加延迟,您应该衡量它对应用程序的影响。

最后,这种方法增加了基础设施的复杂性,因为您现在必须设计、运行和维护不同的服务。

马丁·鲍登在 Unsplash 上拍摄的照片

结论

这个故事考察了第三种架构范式,它可以帮助我们设计和实现一个 ML 应用程序。模型即服务方法是大多数 ML 支持的产品的最佳选择,这是有充分理由的。

其他方法的缺点太明显了。您需要能够独立地扩展您的模型,并且您需要它们足够灵活来处理请求中的任何类型的数据。

在下面的故事中,我们将看到如何使用 KServe 在 Kubernetes 集群上运行真正的、生产就绪的推理服务。

关于作者

我叫迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。

如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请关注我的 MediumLinkedIn 或 Twitter 上的 @james2pl

所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。

非官方 PyTorch 优化循环歌曲

原文:https://towardsdatascience.com/the-unofficial-pytorch-optimization-loop-song-89657dd3a434

一首有趣的顺口溜,帮助你记住 PyTorch 训练循环中的步骤

每个教程都需要一首歌。

我一直在学 PyTorch。

如果您也在学习 PyTorch,但来自 Scikit-Learn 或 TensorFlow 等框架,编写自己的训练和测试循环可能是一个陌生的概念(这两个框架都有一个漂亮的model.fit()系统)。

为了帮助自己学习,我写了一首顺口溜。

所以我永远不会忘记 T2。

你可以在 YouTube 上看到我唱这首歌的视频版本。

托奇,放音乐!

什么是优化循环?

在说歌词之前,先定义一下我说的优化循环(或者训练循环)是什么意思。

在 PyTorch 或一般的机器学习中,优化循环遍历数据集,目标是训练模型(通常是神经网络)学习数据集中的模式。

该模型通过结合前向传播(前向传递,数据通过模型)、后向传播(后向传递,通过模型返回)和梯度下降来更新其内部数字(权重),从而进行学习(请参阅参考资料一节中关于这两者的更多信息)。

测试循环的目标是评估模型在训练循环中学习的模式。

抒情诗

我们训练吧!

对于一个范围内的一个时期

呼叫模型点火车

向前传球

计算损失

优化零梯度

向后丢失

优化器步骤步骤步骤

考试时间!

调用模型点评估

在火炬推断模式下,

向前传球

计算损失

打印出发生了什么

让我们再做一次‘增益’增益

另一个时代

呼叫模型点火车

向前传球

计算损失

优化零梯度

向后丢失

优化器步骤步骤步骤

考试时间!

调用模型点评估

在火炬推断模式下,

向前传球

计算损失

打印出发生了什么

如果你想的话,继续走

但是不要忘记拯救拯救拯救

解释歌词

歌词描述了训练循环中发生的事情(向前传递训练数据,损失计算,将优化器梯度归零,通过步进优化器执行反向传播和梯度下降)。

PyTorch 训练循环的步骤。来源:学习 PyTorch 用于深度学习的书第 01 章

以及测试循环中发生的情况(正向传递,对测试数据的损失计算——模型从未见过的数据)。

PyTorch 测试循环中的步骤(注意没有通过loss.backward()的反向传播,也没有通过optimizer.step()的梯度下降,这是因为评估/测试/做出推断不需要这两个步骤)。来源:学习深度学习 PyTorch 书籍第 01 章

它们被称为循环,因为它们遍历数据中的各种样本(训练集和测试集)。

因为这是机器学习模型的全部思想,查看数据样本并执行数值计算以找到数据中的模式。

就订单而言,在计算损失之前,您需要执行正向传递。

在进入优化器(optimizer.step())和执行梯度下降之前,您可能想要执行反向传播(loss.backward())。

损失衡量模型的错误程度,越低越好。

优化器告诉模型如何更新其学习的模式,以改善损失。

制作培训和测试功能

当然,您可以将上面的代码函数化。

你应该这么做。

它可以防止你发疯和学这样的顺口溜。

但是你只需要学一次。

然后将上面的代码函数化。

并利用它再次‘增益’增益。

不需要记住所有的步骤,您可以将训练和测试循环步骤函数化(在编码一两次之后),这样您就可以在不同的项目和数据集上重用它们。

材料和资源

这首歌来自于寻找一种记忆和教授 PyTorch 优化循环中的步骤的方法。

许多学习 PyTorch 的资源从未真正讨论过每一步或步骤的顺序。

所以我自己做了。

使神经网络能够学习的两个主要算法是反向传播和梯度下降。

PyTorch 实现了幕后人员的机制。

但是如果你想了解每一个,我推荐以下内容:

PS 你可能已经猜到了,这首歌并没有得到 PyTorch 的认可,我只是为了好玩才创作的,因此是非官方的。

Python 中理解的不合理有效性

原文:https://towardsdatascience.com/the-unreasonable-effectiveness-of-comprehensions-in-python-2a0dcc585153

Python 中有哪些理解,为什么它们如此有用

(图片由 Pixabay 上的 altoff 提供)

介绍

在语法方面,ython 是一种众所周知的妙招百出的语言。其中一个例子是 decorators,它完全改变了 Python 在不同实例中的行为方式。另一个很好的例子是理解,由于它们非常有用和多才多艺,它已经被带到了各种其他语言中。如果你不知道如何使用理解来表示 Python 中的不同类型,那么你就真的错过了 Python 编程语言的一个巨大特性。

此外,理解尤其热衷于数据科学。当然,总会有一些软件工程场景,在这些场景中,理解变得唾手可得,并且使用了列表,但是在数据科学领域,更常见的是在整个数据范围内应用操作。我们可以认为理解很像正常的断言。如果我们将一个值设置为正常意义上的某个值,那么数据不会发生任何变化,但是如果我们添加了一个操作,那么在我们创建它之前,我们会使数据等于其他值。理解也有类似的应用,它们可以在断言之前改变或生成数据。这是数据结构所特有的。不用说,因为我们经常在 Julia 中处理列表或熊猫系列,所以对于 Python 中的数据科学和软件工程来说,理解是一个非常强大的工具。

笔记本

不同类型的理解

在 Python 中有许多不同类型的理解。尽管本文的主要焦点是列表理解,考虑到它们在数据科学和其他领域的应用,也可以理解 Python 中的字典、集合甚至生成器。在许多情况下也非常有用,并为处理数据结构的传统方法提供了显著的性能优势。

列出理解

首先要谈的理解仍然是列表的理解。Python 中的列表理解在大多数情况下本质上是一个迭代循环。然而,这些循环的一个优点是,它们通常比 Python 中的标准迭代循环要快得多。考虑下面的例子,其中理解可以非常有效地使用,但不是。

def define_list(x : int):
    lst = []
    for i in range(1, 50):
        lst.append(x * i)
    return(lst)

在这种情况下,仅仅因为我们没有使用理解,就需要做更多的工作。首先,如果我们希望我们的最终值对函数是公共的,那么我们必须在 for 循环开始之前定义它。这是因为每个迭代循环都在函数内部建立了一个新的私有作用域,这也是我们一旦退出 for 循环就不能访问" I "的原因。除了使用 append()方法而不是仅仅使用列表理解来降低算法速度之外,我们还浪费了各种各样的代码行。我们可以将整个函数缩减为一行,在这里使用简单的列表理解来排除 return 和 definition 语句。我们通过使用标准的数组分隔符、[和],并在其中加入某种公式化的或迭代的逻辑,来进行列表理解。在前面的例子中,它们是这样的:

def def_list2(x: int):
    return([x * i for i in range(1, 50)])

不用说,这要简洁得多。即使这样,代码也获得了性能增强,所以没有什么好的理由不使用理解。理解也提供了一个回报,意味着我们可以设置一些与它相等的东西,这个值将成为我们写理解所要创建的列表。

字典理解

虽然我肯定在列表中使用理解最多,但它们也适用于其他类型。其中之一是字典类型。这种理解语法与 list 示例中的方式大致相同。通常,这些都是用迭代循环规范来完成的,然而这次当然是用键和花括号来完成的。

input = [5, 10, 15, 20]
{x:x ** 3 for x in input if x % 2 != 0}

数据科学中的理解应用

当涉及到通用软件工程时,这种不合理的有效性很容易理解为什么这种有效性会延伸到数据科学领域。经常使用理解的一个很好的例子是条件掩蔽技术。条件屏蔽允许我们创建一个位数组,然后用它从给定的数据帧、列表或你所拥有的东西中过滤出值。它首先创建掩码,然后用位数组索引数据帧。

import pandas as pd
df = pd.DataFrame({"A" : [5, 10, 15, 20], "B" : [5, 10, 15, 20]})mask = df["A"] > 5
masknewdf = df[mask]

做数据科学的时候,这其实是相当常见的操作。一个很好的例子是,如果我们想进行测试。测试时,我们需要根据某个字段来分离数据。例如,假设我们有以下数据:

df = pd.DataFrame({"height (cm)" : [182, 125, 102, 190, 140, 150], "sex" : ['m', 'f', 'f', 'm', 'f', 'm']})

我们想进行一项学生 t 检验,以确定一个人的性别对其身高的影响是否有统计学意义。我们可以用一种理解来区分男性和女性,并将他们与人口进行比较。

from scipy.stats import ttest_indmale_mask = df["sex"] == 'm'
female_mask = df["sex"] == 'f'male_df = df[male_mask]
female_df = df[female_mask]ttest_ind(df["height (cm)"], female_df["height (cm)"])
Ttest_indResult(statistic=1.2115133507714908, pvalue=0.26500459971996915)

理解的另一个重要应用是特征工程。通常在数据科学中,特性并不完全是我们想要的样子。有时,我们希望预测数据中没有的东西,但可以使用数据来创建。对于这一点,理解非常适合,因为它们提供了足够的回报,并且可以非常容易地从其他列表中构建,例如数据帧中的其他特性。我们将通过在我们的其他数据帧上设计一个新的特性来尝试这一点。虽然这个特性没有用,但它很好地展示了如何将同样的技术应用到更有用的实例中。

df["height (in)"] = [x * 0.393701 for x in df["height (cm)"]]

这将为我们的 dataframe 添加一个新的高度列(英寸)。不用说,与其他设计特征的技术相比,这种技术非常有效。理解在数据科学世界中扮演着大胆而重要的角色。

结论

所以…理解是很棒的。它们不仅使您的代码更加简洁,而且还提高了 Python 代码的性能。当然,考虑到我们是在用 Python 做数据科学,可以节省的每一点性能都应该被节省下来。也就是说,这些理解也被引入到其他语言中,如 Julia,它们的实现在某种程度上已经成为科学计算高级语言中的主要内容,很容易理解为什么会这样。

虽然理解在一般的软件工程应用中肯定有恰当的应用,但我相信这些理解真正开始发光是在数据科学中。感谢您阅读我的文章,我希望这些理解对您今后的 Python 代码有重大的改进!

无名的数据英雄

原文:https://towardsdatascience.com/the-unsung-data-heroes-ac51bef6ed2c

几个数据英雄如何推动高增长公司的发展,为什么你不能失去他们

许多最优秀的数据人员希望在高增长的技术公司工作,这是有充分理由的。学习曲线很陡,你可以进步很快,公司的使命令人兴奋,你可以用最新的技术工作。

但是在高增长公司工作也意味着每时每刻都在变化。业务的不断变化意味着数据预期也必须改变。初创公司的平均任期是两年,而且总是有很多新员工加入。

这为数据英雄创造了完美的环境。

数据英雄通常是数据团队中最年长的成员之一。这个人仍然理解有 500 个上游依赖项的 fct_orders.sql 表,也是唯一一个有足够勇气做出改变的人。

来源:Unsplash.com(作者修改)

如果你管理一个数据团队,你就会知道,当事情变得非常糟糕时,你总是可以依靠这些人来挽救局面。他们解决问题的速度比其他任何人都快,如果他们不知道什么,他们总能想出办法,如果数据是错误的,他们会对业务发生的后果承担个人责任。

数据英雄的问题在于,他们隐藏了团队中的问题,否则这些问题就会暴露出来,如果他们离开,很难找到替代者。

不幸的是,经理们依赖数据英雄来完成太多的日常工作,比如解决紧急问题,因为他们知道这些工作会完成。这份工作并不光彩,在两年左右的时间里,数据英雄们往往会厌倦,开始在其他地方寻找工作。

数据英雄们提前离开给公司带来的机会是巨大的。

作者图片

适应新的数据角色需要一段时间。你必须了解业务,理解现有的数据模型,并与合适的人建立关系。我预计平均数据雇员在第二年的生产力会翻一番。尽管如此,初创公司的平均任期只有两年。

如果你能让你最优秀的员工呆上四年而不是两年,你就能以同样的价格获得两倍的生产率。

那么,如何留住你的数据英雄呢?让我们从做什么开始

  • 不要因为他们知道如何做,就把所有琐碎的工作都交给他们。不要让他们在你的“model _ with _ 500 _ dependencies _ that _ nobody _ knows . SQL”每次失败时都去修复它。
  • 不要让他们总是在周末登录,因为他们非常关心数据出错给业务带来的后果。

相反,在你的数据文化中建立正确的行为。

创造一种留住数据英雄的文化

通过设计让关心重要数据成为每个人的责任。建立一个机制,将他们应该关心的数据问题通知给合适的人,这样就不会每次都落在相同的几个人身上。

奖励数据英雄分享最佳实践或分离最大数据模型的行为,以便更多人可以做出贡献。

确保为个人贡献者(ICs)提供一条晋升路径,让你的优秀员工在不进入管理层的情况下有发展空间。我们开始看到员工数据角色的出现,但与工程相比,他们仍然不常见。

作者图片

在上面的例子中,如果你选择了快乐的道路,你将拥有一个两倍生产力的数据团队。

照顾好您的数据英雄,不要忘记为新的数据英雄腾出空间。

对这个话题有什么想法或反馈吗?让我知道

科技多元化的价值

原文:https://towardsdatascience.com/the-value-of-diversity-in-tech-c37d3b0d60c7

为什么不同的团队会提升你的组织的共同智慧潜力

照片由 Unsplash 上的 sharonmccutcheon 拍摄

介绍

信息技术是一个协作部门,为分散在全球各地的数十亿不同客户提供服务。然而,这个部门创造的产品和服务是由相对同质的团队构思的。这尤其适用于软件开发、软件工程和数据科学领域。

数十项研究表明,多样化的团队比同质的团队集体更聪明、更高效、更具创新性,总体上更成功。然而,尽管有这些发现,除了少数几个例外,大多数技术公司在多样性方面表现出非常缓慢的增长。事实上,这些数字是惊人的。

根据 TruelistZippia 收集的 2022 年统计数据,女性仅占全球软件工程师的 27.5%,显示出巨大的性别差距。在美国,这一差距甚至更大,只有 21%的软件专家认为自己是女性,低于 2010 年的 29%。此外,西班牙裔和美国黑人在这一部门的代表性严重不足。虽然 19%的美国人口是西班牙裔,13%是黑人,但他们在软件开发中的比例分别只有 7%和 5%[1,2]。这些数字在很大程度上也反映在数据科学领域。

本文将探讨多样性带来的各种好处及其在产品开发、客户同理心和组织成功中的重要性。虽然重点将放在科技行业,但无论是哪个行业,工作中的多样性总体来说都是一个重要方面。因此,这篇文章也旨在鼓励读者在他们各自的领域里为更多的多样性而奋斗和倡导。

生产力

多元化和包容性的工作环境让每个人都感到受欢迎,这通常会提高员工的参与度和满意度。此外,多元化团队带来的广泛的专业知识、经验、观点和工作风格极大地提高了他们解决问题的能力。它还创造了一种健康竞争的氛围,这往往会鼓励员工超越自己的潜力,从而提高生产力。因此,所有这些因素的融合可以导致众多公司流程的优化,从而显著提高其效率[3]。

决策

多元化的团队拥有独特的能力,能够更彻底地审查新想法,并从各种不同的角度调查问题,最终使他们能够达成更明智的决策。根据 Cloverpop 的研究,拥有多元化团队的组织在 87%的情况下都能做出更好的商业决策[4]。多元化不仅能改善决策过程,还能加速决策过程。新的思维方式、新的视角和多种技能自然有助于团队更快地做出决策。

创造力和创新

不足为奇的是,由具有各种不同背景的员工组成的团队开发出了比同类团队更具创造性和创新性的解决方案。这是团队成员分享他们的不同意见的结果,这促使整个团队从各种角度和视角看待问题,找出他们思维中的错误,并集体达成更明智的解决方案。换句话说,多元化极大地丰富了学习曲线,并推动员工跳出框框思考——当涉及到为广泛的客户提供餐饮产品和服务以及不断适应市场需求变化时,这一技能至关重要。

照片由jasongoodman _ youxventuresUnsplash 上拍摄

在《创新》上发表的一项研究中,研究人员调查了西班牙 4277 家公司研发团队中的性别多样性水平。在应用统计模型后,他们发现拥有更多女性的公司更有可能在两年时间内将激进的新创新引入市场[5]。另一项发表在《经济地理》上的研究表明,文化多样性极大地促进了创新。作者汇集了参与伦敦年度商业调查的 7615 家公司的数据,这是一项针对英国首都高管进行的关于公司业绩的问卷调查。该研究表明,由文化多元的领导团队经营的企业比由同质领导团队经营的企业更有可能开发和发布新产品[6,7]。

客户体验

具有不同背景的团队将更容易适应客户的需求和要求。无论团队是在开发一个应用程序、一个平台还是一项服务,他们都必须以一种提供最佳用户体验的方式来设计和构建它。在大多数情况下,软件产品和服务的客户并不来自一个单一的同质群体。因此,拥有一个由来自不同背景的人组成的团队,能够产生各种各样的想法,并通过各种视角对它们进行评估,这对于预测和整合最终用户的需求是非常有益的。

表演

由于工作场所的多元化已经被证明可以提高生产力、决策能力、创造力、创新能力和客户体验,因此它也能提高组织绩效也就不足为奇了。2019 年,麦肯锡分析了 366 家上市公司,发现管理层中族裔和种族多样性排名前四分之一的公司实现高于行业平均水平的财务回报的可能性高出 36%。同样,性别多样性排名前四分之一的人获得高于行业平均水平的回报的可能性要高 25%[8]。

结论

本文表明,努力建立更加多样化和包容的工作环境会带来巨大的组织效益,包括提高生产力、决策、创新和绩效,以及为公司产品或服务的最终用户提供更准确的目标客户体验。

在技术领域建立多元化团队尤为重要,因为该行业的产品最终可能会拥有数十亿用户,在整个开发过程中必须考虑他们的不同需求。因此,拥有一个由来自各种不同背景的代表组成的丰富的员工库是至关重要的,这样才能确保新产品的创造融入了代表这一庞大而多样化的客户群需求的想法和反馈。

参考

[1] Truelist,软件开发统计https://truelist.co/blog/software-development-statistics

[2] Zippia,美国软件工程师人口统计与统计https://www . zippia . com/software-engineer-jobs/demographics/?src=sp-popout-timed

[3] Saxena,A. (2014)。劳动力多样性:提高生产率的关键。Procedia 经济学和金融,76-85。

[4] Cloverpop,利用包容性决策制定实现多样性。https://www . clover pop . com/hacking-diversity-with-inclusive-decision-decision-paper?UTM _ campaign = Forbes&UTM _ source = Forbes&UTM _ medium = Forbes % 20 hacking % 20 diversity % 20 white % 20 paper

[5]迪亚斯-加西亚等人(2013 年)。研发团队中的性别多样性:对创新激进性的影响。创新,15:2,149–160。

[6]内森和李(2015 年)。文化多样性、创新和企业家精神:来自伦敦的企业层面的证据。经济地理,89:4,367–394。

[7]洛克&格兰特(2016)。为什么多元化的团队更聪明。哈佛商业评论:多样性&包容。

[8]麦肯锡公司(2020)。多元化赢了:包容是多么重要。

构建数据策略的来龙去脉

原文:https://towardsdatascience.com/the-variable-2582e88f1906

我们通常专注于如何处理和提取我们所拥有的数据的价值,而对保持数据组织平稳运行的基础架构和工作流投入较少的脑力。嗯,这周不行!这里有四篇关于数据策略不同方面的优秀文章。(其他话题的帖子,向下滚动!)

照片由EJ·斯特拉特Unsplash 上拍摄

我们本周最喜欢的其他读物涵盖了丰富而广泛的主题——如果你已经厌倦了数据策略的讨论,不妨试试这些:

所有在阅读了 TDS 的文章后受到启发成为媒体成员的人:感谢你们对我们作者工作的支持。我们真的很感激。

直到下一个变量,

TDS 编辑

面向社会公益社区的 Viz 使用 Python 和 Tableau 进行分析

原文:https://towardsdatascience.com/the-viz-for-social-good-community-an-analysis-using-python-tableau-63d19ed8376d

了解面向社会公益志愿者的 Viz,为您的下一次可视化获取有用的提示,并了解如何参与其中

作者图片:Viz 代表世界各地的社会公益志愿者

最近,我通过 Viz for Social Good (VFSG) 参与了一个项目,这是一家帮助使命驱动型组织利用数据可视化的力量来促进社会变革的社会企业。你可能听说过他们之前与一些组织合作的项目,如无国界学者通向繁荣的桥梁女孩+数据

VFSG 的最新项目 Visualize our Community ,让志愿者分析来自 VFSG 社区民意调查的数据,以帮助他们更好地了解他们当前的志愿者基础,确定招募工作,并帮助确定他们应该与哪些非营利组织合作。

在这篇文章中,我将提供一个项目的概述,有趣的见解,和有用的提示,你可以应用到你的下一个仪表板!

项目概述

对于 Visualize our Community 项目,VFSG 志愿者获得了一个数据集,以帮助 VFSG 了解他们当前的志愿者,并确定未来的合作组织。

数据集由 19 个字段组成,每个字段代表一个来自 VFSG 社区匿名投票的问题。调查中的问题涵盖了广泛的人口统计信息,如年龄、教育水平和原籍国。其中两个问题是自由文本回答,而其他几个问题允许受访者从多个选项中进行选择。数据集的性质促使我决定使用 Python 和 Tableau Public 来分析数据——Python 用于快速清理和操作数据,Tableau Public 用于设计有效的可视化。

使用 Python,我从现有字段中创建了一些新字段,包括程序数量,它反映了志愿者用于数据可视化的不同技术的数量,以及志愿者使用的每种技术的单独布尔列(即 Tableau、Excel、Cognos、Alteryx 等)。).

这个 Python 脚本随后被用来生成一个新的数据集,该数据集被上传到 Tableau Public 以开发可视化。完整的 Python 脚本和最终数据集可以在这里找到。

洞察力

一旦我创建了一个干净的数据集,我就开始在 Tableau 中开发可视化工具,最终用于 VFSG 的仪表板。

从这个数据集中获得了一些有趣的见解,我在下面强调了其中的一些。

洞察 1 : Tableau 和 Excel 是 VFSG 志愿者使用最多的两个工具。

下图显示了 VFSG 志愿者在项目中使用的 7 大工具,包括许多市场领先的开源、商业智能和数据混合工具。Tableau 和 Excel 是当今市场上众多工具中 VFSG 志愿者的最爱。

作者图片:VFSG 志愿者使用的 7 大程序

洞察力 2:大多数 VFSG 志愿者在美国或加拿大。

虽然大多数 VFSG 志愿者位于美国和加拿大,但也有一些志愿者遍布全球。如下文所述,一些志愿者也在欧洲和亚洲工作,特别是在英国和印度。

作者图片:全球 VFSG 志愿者

洞察 3:大多数志愿者是通过推特找到 VFSG 的。

下图显示了志愿者发现 VFSG 的前 7 个渠道。Twitter、Tableau 用户群和 LinkedIn 占据了前 3 名。有趣的是,大量的流量来自 Tableau 用户群,正如我们之前看到的,大量的 VFSG 志愿者使用 Tableau 来创建数据可视化。

作者图片:志愿者发现 VFSG 的 7 大途径

要了解更多信息,请查看 Tableau Public 上的整个仪表盘。

有用的提示

在为 VFSG 创建可视化和仪表板时,我使用了几种技术——下面我重点介绍了几个关键技术,您可以在下一个可视化或仪表板中实现它们!

技巧 1:利用 Tableau 的双轴特性将多个度量值合并到一个图表中

双轴是两个相互层叠的独立轴。它们允许您在单个可视化中比较多个度量。

VFSG 的数据集中有一栏列出了每个人自愿使用的技术。在 Python 中,我将这个列分成多个布尔列,每个产品一个。如果一名志愿者使用了特定的技术来创建可视化效果,那么这个值就被设置为 1,如果没有,那么这个值就被设置为 0。

为了在一个可视化视图中查看所有这些产品专栏,我利用了 Tableau 中的双轴特性。

为了创建可视化,如上面的洞察#1 所示,我执行了以下步骤:

  1. 在新的工作表中,将两个度量放在架上(例如 Alteryx 和 Tableau)
  2. 选择下拉菜单选择行 s helf 上的一个测量
  3. 从下拉选项中选择双轴
  4. 演示选项卡中选择水平条形图
  5. 滤镜卡上,选择编辑滤镜
  6. 选择您希望包含在可视化中的所有度量,然后选择确定(在此可视化中,我选择了产品特定的度量。)
  7. 添加完所有度量后,对可视化进行格式化和排序

注意:在第 6 步中,从过滤器卡中选择度量可以更快地将每个度量添加到图表中,而不是将每个度量单独添加到行架中

技巧 2:给工具提示添加可视化效果

在 Tableau 中,工具提示是当您将鼠标悬停在可视化标记上时显示的细节。工具提示是一种很好的方式,可以在可视化中添加额外的上下文和信息,同时充分利用您的仪表板空间。

对于 VFSG 仪表板,我在一些工具提示中添加了可视化效果,包括显示志愿者年龄分布的条形图。

作者图片:来自“你的年龄是多少?”条形图

通过在的工具提示中添加可视化效果,“你的年龄是多少?”条形图,我能够为用户提供另一个视图来进一步深入数据。在上面的例子中,我们可以看到 18-25 岁年龄组的性别细分。

向工具提示添加可视化效果:

  1. 导航到包含要添加工具提示的可视化的工作表(在上面的示例中,这将是“你的年龄是多少?”条形图)
  2. 从左侧的标志卡中选择工具提示
  3. 在随后的屏幕上,从菜单选项中选择插入
  4. 选择包含要添加到工具提示中的可视化效果的工作表(在上面的示例中,这是包含性别身份细分饼图的工作表)
  5. 选择确定,然后悬停在可视化上的标记上,查看更新的工具提示!

提示 3:使用容器在你的仪表板中放置可视化效果

在 Tableau 中创建仪表板时,有几个对象可以利用,比如水平和垂直容器!

按作者分类的图像:Tableau 仪表板的可用对象

容器是在仪表板中组织对象的好方法。水平容器允许您将可视化效果并排放置在一行中,而垂直容器允许您将可视化效果堆叠在一列中。使用容器,您还可以选择在容器内均匀分布可视化效果。

对于 VFSG 仪表板,我使用了一个垂直容器来保存 VFSG 徽标和仪表板描述,如下图所示。这个垂直容器包含一个 VFSG 徽标的图像对象和一个仪表板描述的文本对象。

作者图片:VFSG 仪表板中的垂直容器

我还使用了几个水平容器。在关于志愿者部分的条形图中使用了一个水平容器。

作者图片:VFSG 仪表板中的水平容器

这个水平容器由 3 个条形图组成,均匀分布在容器中。

要平均分配容器中的内容物:

  1. 选择容器中的一个可视化效果或对象
  2. 选择对象的下拉菜单
  3. 从下拉菜单选项中选择选择容器:水平
  4. 选择容器的下拉菜单
  5. 最后,选择平均分配内容

使用容器可能有点棘手,所以就我个人而言,在我创建仪表板之前,我喜欢勾画出一个布局来作为指南。在处理多个容器时,有一个草图是有帮助的——仅仅因为你画出了一些东西,并不意味着以后不能调整它!

额外提示:水平&垂直容器可以互相使用!我为 VFSG 仪表板这样做了,当您想在一个仪表板中使用多个对象和可视化时,我强烈推荐这样做!

看看我为 VFSG 仪表板画的草图,看看我是如何使用水平和垂直容器的。

作者图片:VFSG 仪表板草图

Tableau Public 上查看最终仪表板,在 GitHub 上查看代码/数据集。

即社会公益运动有几名积极分子。如果你对志愿服务感兴趣,注册 VFSG 时事通讯,随时了解你可以参与的新项目。

Payal 是 IBM 的一名数据科学家。在业余时间,她喜欢阅读、旅游和写作。如果你喜欢她的作品, 在这里订阅 她的列表,不要错过任何一个故事!

以上文章是个人观点,不代表 IBM 的立场、策略或观点。

参考文献

[1]:即社会公益。(2022 年 1 月 12 日)。 Viz for Social Good- Visualize 我们的社区数据集https://drive . Google . com/drive/folders/1-YFp _ 09 yx 9 ui 2 lr m3 cnpzee 9 AOR 7 pj-

第三波 CDO 事业成功的蓝图

原文:https://towardsdatascience.com/the-wave-3-cdo-blueprint-for-career-success-bd76574dbabb

阿曼德·库利在 Unsplash 上拍摄的照片

现代 CDO 如何应对当今数据环境的复杂挑战

成为首席数据官从未如此艰难。一方面,对 CDO 的需求比以往任何时候都高,超过三分之二的企业任命了 CDO,而 2012 年这一比例还不到八分之一。另一方面,工作缺乏保障,CDO 平均持续时间仅为 2.5 年。这比所有其他高管都要短,是高管层 5 年平均任期的一半。

这部分是由于过去十年 CDO 关税的迅速扩大。第一波 CDO,专注于数据管理,特别是建立数据集市和数据仓库。他们还向这些数据仓库添加了数据治理。他们创建并实施了一些流程,以确保数据得到高效、安全的使用,免受网络盗窃、隐私风险、降级和其他任务的影响。换句话说,他们主要扮演坏警察的角色,监督员工如何使用数据。

然而,纯粹的防御角色让工人和 CDO 都士气低落,这催生了第二波 CDO 浪潮。而 CDO 比谁都懂数据。他们了解应用分析和创建数据管道和数据应用程序的力量。因此,第二波 CDO 成为了内部创新的领导者,倡导他们的公司如何看待和使用数据的转型,从一个被动的档案库,如布满灰尘的图书馆中的书籍,转变为数字企业的命脉。

如今,我们看到了第三波 CDO 的出现。我会解释的。

第三波 CDO 负责监督技术、运营和可靠性。(图片由作者提供)

第三波 CDO 的作用

‍Convinced 的价值分析,第三波 CDO 正在寻求纳入更多的数据源,如实时事件流。Wave 3 CDOs 希望构建运营仪表板,并定期向其业务提供数据。他们正在寻求机器学习生成的预测分析,以更好地做出决策。他们迫切需要基于人工智能的工作流来自动化流程,以提高效率、灵活性和成本节约。第三波 CDO 不仅仅被要求构思、计划和支持。他们被要求执行这些转换。为了做到这一点,他们被赋予了专门的数据运营团队、对数据技术和领域的监督,以及对整体数据可靠性和数据交付的责任。

对现代 CDO 的期望

如果 CDO 如此重要,那么为什么他们被解雇得如此之快、如此之频繁?

‍One 的理由是,对业务风险不了解的 CDO 往往试图在削减错误成本的同时实现数据基础设施的现代化。今天的第三波 CDO 部分或全部负责多样化的多云设置,包括 ERP 系统、Salesforce 实例、传统数据库、数据湖和其他大数据部署,以及云原生数据仓库。

‍To 从他们的数据管道和数据仓库中提供了更多的价值,他们不断修补和升级他们的基础设施。将数据带入云中是最常见的升级。由于云中易于切换和扩展,这种迁移看起来似乎很容易。

‍But:我们不要低估成功迁移所涉及的复杂性和工作。将数据从本地数据仓库迁移到云实例,无论是简单的提升和转移还是整体重构,都需要密切监控和认证数据迁移时所有数据集、模式和依赖项都保持不变。验证和协调数据迁移前和迁移后是劳动密集型工作,时间紧迫的 CDO 和他的团队可能觉得他们没有足够的带宽来完成这项工作。‍

我们看到太多的 CDO 满足于让他们的运营团队快速查看迁移的数据以发现任何数据错误或数据可靠性受损。这样做对任何公司来说都是一个很大的风险,但对那些以支持销售、业务运营或任何其他关键任务的方式使用数据的公司来说则是一个巨大的风险。在这种情况下,不可避免地会出现数据错误和损坏的数据管道。最糟糕的是,如果在实际迁移过程中没有强有力的监督,这些问题将会在很长一段时间内持续出现,甚至在最糟糕的时候出现。数据迁移失败是 CDO 失业的一个重要原因。

业务需要更多数据

‍Reason 的第二个问题是无法支持企业对新数据工作流的巨大需求。即使他们没有主动将数据从集群迁移到云中,大多数 CDO 仍在不断添加新的数据源。其中包括实时客户点击流、来自内部存储库和第三方数据集市的变更数据捕获(CDC)同步、首先由您的 ERP 系统获取的物联网传感器数据,然后共享给更广泛的分析,等等。‍

该数据不符合单一结构。此外,处理数据的现代方式不再是写模式,而是读模式。这是一种更加灵活的策略,使得在大型数据湖中存储各种非结构化和半结构化数据类型变得更加容易。但是到了机器学习和分析的时候——特别是微妙、难以检测的异常和数据科学家为而生的大胆的大趋势——来自不同来源的数十亿字节的数据必须经过协调才能被处理和查询。‍

所有这些都是繁重而复杂的工作,数据科学家完全无法处理。如果缺乏必要的工具,这给 CDO 和训练有素的数据工程师带来了大量潜在的苦差事。但是,由于当今许多 ML/AI 项目被赋予了高优先级,无法快速构建这些数据管道的 CDO 面临着被视为业务障碍的风险。

‍In 除了他们在进攻方面的职责之外,第三波 CDO 还负责防御数据——数据治理、安全和访问控制。然而,已经发生的巨大转变是,所有这些领域现在实际上都是可操作的,并且必须实时进行。数据治理不再是一次性的年度审计,而是必须持续执行并达到完美。

导航现代数据环境

CDO 们忙于平衡长期优化项目和消防演习。有些是常见的日常任务,有些对长期业务成功至关重要。担任这些角色的人需要始终评估他们应该评估的数据。他们必须知道数据是否可用。必须意识到计算系统是否在工作,业务流程是否管理良好?当 CDO 从这些问题开始并愿意回答这些问题时,他们就能更好地理解企业数据投资的内在可能性。

根据我领导数据团队的经验,运营成功的基础显然是数据的可靠性和有效性。在你的数据能够产生很大影响之前,你必须知道你可以信任它,并且它是最高质量的。CDO 需要一定程度的可见性,这不仅能让他们洞察问题所在,还能让他们理解数据活动。

随着时间的推移,我清楚地认识到,作为一名数据主管,为了确保我能够对我的组织产生有意义的影响,我必须知道的不仅仅是如何处理警报。我的价值来自于能够就支出预测、扩展和性能问题以及构成数据环境的无数其他问题做出明智的决策。当我寻求对数据操作智能的持续感知,使我能够解释数据供应链的状态时,我对数据操作的状态有了更好的处理。

这就是我如何想到第三代 CDO 的。他从数据管道/平台和数据应用程序的角度考虑内部数据环境。不仅仅是作为环境要素的那些,而是作为整体组成部分的它们之间的相互作用。意识到这些活动和行为是 CDO 成功的基础。最终,凭借可见性和战略地图,CDO 可以成功驾驭新的数据格局,并在未来几年蓬勃发展。

数据的权重

原文:https://towardsdatascience.com/the-weight-of-data-cfbb0032dec0

我们应该如何以及为什么评估我们数据的权重

马库斯·克里斯蒂亚在 Unsplash 上的照片

探索性数据分析是数据分析和数据科学的重要组成部分;也许,是最重要的部分,因为这是我们在进行真正的分析之前试图弄清楚我们的数据发生了什么的时候。
然后,我认为在数据科学和数据分析中需要理解的一件重要事情是,我们必须评估数据的权重。

数据有权重是什么意思?我想用一个例子来解释我的意思。

假设你是一名教练,你必须选择运动员参加奥运会的 100 米比赛;假设你不知道运动员,你只能根据数据选择他们;当然,你有一个记录每个运动员跑 100 米的时间的数据集。

为了简化这项研究(和本文),我将创建一个数据集,其中只包含与四名运动员相关的数据(但在本文结束时,我们将概括为数千人)。让我们创建数据集:

import pandas as pd# initializing
data = {'Name':['Tom', 'Jack', 'Nick', 'John',
                'Tom', 'Jack', 'Nick', 'John',
                'Tom', 'Jack', 'Nick', 'John',],
        'Time':[20, 21, 19, 18,
                20, 100, 19, 18,
                21, 22, 21, 20]}#dataframing the data
df = pd.DataFrame(data)

现在,我们通常首先做的一件事是计算平均值。让我们开始吧:

#calculating mean values and sorting
b = df.sort_values('Name').groupby('Name').mean()b---------Name       Time
------------------
Jack       47.7                 
John       18.7                 
Nick       19.7                 
Tom        20.3

正如我们所看到的,杰克的平均值比其他运动员高得多。这意味着杰克似乎比其他人慢,不让他参加奥运会的诱惑可能很大。
但由于我们是“数据爱好者教练”,我们想更深入一点,不要只看平均时间就结束分析。例如,我们可以计算某个值在我们的数据集中“出现”了多少次。我们可以这样做:

#counting single values and sorting for index
c = df['Time'].value_counts().sort_index()
c------------18     2
19     2
20     3
21     3
22     1
100    1
Name: Time, dtype: int64

正如我们所看到的,我们有一个值 100,它只出现一次,如果我们深入一点,我们可以看到它与我们的朋友 Jack 相关联。现在,我们可能决定删除这个 100 值,它只出现一次,看看杰克是否还能被选中参加游戏。也许,如果我们可以获得更多的数据,我们可以发现杰克跑了一段腿受伤的路程,并有强烈的意愿结束这段路程(他结束了!),因为如果他决定退出,他将失去一些资格分。

当然,除了散点图之外,还可以使用“value_counts()”代码来图形化地查看异常值,我认为这样做确实是个好主意。但是使用“value_counts()”确实有助于我们理解如何衡量我们的数据:例如,在这种情况下,这个 100 值(对我们的朋友 Jack 来说是唯一的值)可以被丢弃,我们可以在没有它的情况下执行即将到来的数据分析。

概括和结论

当然,这只是一个简单的例子——正如我在本文开头所解释的。但是让我们把数字增加一点。你有 100 个或者 1000 个运动员的数据怎么样?在这种情况下,仅仅用散点图来可视化数据可能不会帮助你理解 100 的值仅仅是与仅仅一个运动员相关联的唯一值;这意味着,在我看来,离群值必须用图形来处理,但也要用分析来处理。当然,最后,有时时间是唯一重要的东西:进行深入的分析研究需要时间;所以,尽量花时间分析数据。

我们一起连线吧!

https://federicotrotta.medium.com/

LINKEDIN(向我发送连接请求)**

如果你愿意,你可以 订阅我的邮件列表这样你就可以一直保持更新了!**

考虑成为会员:你可以免费支持我和其他像我一样的作家。点击 这里成为会员。****

生成流网络是什么,为什么和如何

原文:https://towardsdatascience.com/the-what-why-and-how-of-generative-flow-networks-4fb3cd309af0

在 TensorFlow 2 中构建第一个 GFlowNet 的指南

组合对象是由积木组成的。(照片由鲁本·汉森Unsplash 上拍摄)

生成流网络(GFlowNets)是一种机器学习技术,用于以与其相关联的回报成比例的频率生成合成对象。

在本文中,我们将解释所有这些词的含义,概述 GFlowNets 为什么有用,讨论它们是如何被训练的,然后我们将剖析 TensorFlow 2 的实现。

建立你的直觉

2021 年,Emmanuel Bengio 和合著者在 NeurIPS 推出了 GFlowNets。GFlowNets 是一种深度学习技术,用于以与环境中这些对象的预期回报成比例的频率“构建对象”。

他们第一篇论文中令人振奋的例子是新化学结构的发现(或者我也将它们称为“分子”)。化学结构或分子是“组成的”,因为它们是由离散的构件(原子)组成的。可以测试化学结构的感兴趣的性质,例如抗生素活性。一些分子是强效抗生素——当在实验室中对细菌进行测试时,大多数细菌都会死亡,并获得一个我们可以认为是巨大“奖励”的测量值。大多数分子不会杀死细菌,因此,从实验室测试中返回一个小的“奖励”值。

分子是由原子构成的。一些分子具有抗生素特性,但大多数没有。(照片由特里·维利迪斯Unsplash 上拍摄)

GFlowNet 是构建对象的概率模型。一般来说,GFlowNet 的使用方式如下:

  1. 从起点开始,它输出可能的构建块的概率分布。
  2. 它根据预测的分布随机选择一个构造块。请注意,这一步是随机的。有些行动会更有可能,有些会更少。
  3. 添加完第一个构建块后,它接受到这一点的构建对象作为输入,并在可能的构建块上生成一个新的概率分布,然后添加下一个。
  4. 它以这种方式进行,直到选择一个终止动作。
  5. 终止操作完成生成的对象,然后可以根据环境查询该对象以获得相关的奖励值。

需要了解的一些关键事项:

  • 施工被视为一个马尔可夫过程。也就是说,当选择下一个构建块时,唯一的输入是正在构建的对象的当前状态。
  • 我们一直使用“积木”的形象,但“行动”可能是更合适的术语。当构建一个分子时,你不仅要选择一个碳原子,还要选择它的位置。将每一步都看作是选择一个动作,这样更容易想象 GFlowNets 的其他应用。在下面的代码示例中,我们通过在网格中移动来构建路径。每个动作都是对相邻单元的一步。
  • 学习可能行动的概率分布(我们将很快讨论如何完成)。预测的分布被称为“策略”。
  • 该模型最直观的部分是“远期政策”。这是建设性的部分,输出了下一步行动的概率分布。该模型还包括一个“向后策略”,它描述了可以导致当前状态的动作的分布。
  • 从开始到结束的一系列完整的动作称为“轨迹”。

现在你知道了 GFlowNets 是构造对象的概率模型。GFlowNets 的关键特征是,它们以与回报成比例的频率构建对象

如果你多次重复这个随机的构建过程,你会在高回报区域得到更多的物体,在低回报区域得到更少的物体。以我们的抗生素分子为例,该模型将生成更多类似于强抗生素的分子,但也会生成一些类似于弱抗生素的分子。输出概率将与回报成正比。

Emmanuel Bengio 写了一篇博文和附带的教程,值得研究。

物流网的应用

现在你明白 GFlowNet 是做什么的了。你为什么想要一个?它们是用来做什么的?

它们用于从非常大的环境中进行智能采样。

例如,坚持化学结构的例子,假设你有一些训练数据开始(一堆化学结构和它们相关的抗生素活性)。你首先训练一个模型(独立于你的 GFlowNet ),它可以预测给定化学结构的抗生素活性。我们姑且称之为代理奖励函数,因为它是目前化学结构和抗生素“奖励”之间关系的最佳表征。现在你想用你的代理模型来挑选新的、未经测试的化学结构,在实验室里进行试验。

那么,你的下一步是什么?一种继续进行的方法是使用你的训练数据作为起点,详尽地生成每一种可能的化学结构。困难在于空间呈指数增长。即使从仅仅 10 或 20 个可能的“积木”开始,你也可以在每个分子上有许多可能的位置,导致数百个可能的动作。如果你详尽地列举这种行为的每一种组合,仅仅经过几个步骤,你就会有数十亿种可能性,你很快就会淹没你的计算资源,甚至没有开始探索可能的化学空间。

另一种方法是随机选择行动,这将让你更深入地探索,但不是穷尽。这种方法的问题是均匀随机性。由于大多数分子不是抗生素,很可能绝大多数取样结构的回报很低。

这就是 GFlowNets 的切入点。首先训练一个 GFlowNet 来反映代理模型学习到的奖励函数。然后,使用 GFlowNet 生成许多结构,并使用代理模型对它们进行优先级排序。这样,你已经从可能的化学空间中取样,但是以一种丰富有希望的候选者的方式,同时也允许对不太有希望的结构进行一些探索。

换句话说,GFlowNets 用于从非常非常大的环境中进行智能采样。

如何训练 GFlowNets

现在你知道什么是 GFlowNets,以及它们是如何使用的了。你如何训练一个模型来展示你想要的行为?你如何训练一个模型来生成与奖励成比例的对象?

关于这个主题的深入讨论,我将向您推荐这篇论文,它讨论了可用于训练 GFlowNets 的各种目标函数。出于本文的目的,我们将坚持轨迹平衡。

现在我们到了 GFlowNets 的“流”部分。作者让我们把环境中所有可能的轨迹想象成一个有水流过的管道网络。每个“管道”都是从一个状态到另一个状态的动作。水从原点(所有轨迹的起点)流过所有的动作,在已知“回报”的终点状态流出。目标是通过管道分配水,使流出的水量与回报成比例。

弹道平衡损失函数是实现这一目标的一种方法。对于每条轨迹,概率的前向流动(从起点到终点状态)应该与从终点状态到起点的回报流动成比例。也就是说,沿着轨迹的前向政策概率的乘积应该与沿着相同轨迹的后向政策概率和回报的乘积成比例。写成一个损失函数,看起来像这样:

来自马尔金等人的方程 14。

其中:

  • z 是一个单一的学习值,表示从原点通过整个网络的总流量。
  • P_F 是前向策略,P_B 是后向策略。注意,对于每一条轨迹,你沿着轨迹取每一个动作的概率的乘积。
  • r 是与特定轨迹相关的报酬。也就是说,它是轨迹产生的物体的回报。
  • θ代表将被改变以最小化该函数的模型参数。
  • n 是计算损失值的轨迹长度。

直观来看,内部分是前向流(从起点到终点)与后向流(从回报到起点)的比值。理想情况下,该比率将收敛到 1。取该比值的对数意味着如果向前的流量较大,对数将大于零。如果回流较大,对数将小于零。取整件事的平方,最小值将为零(即 log 内部的比值将为 1)。

这种安排的另一个好处是,当把许多概率相乘时,我们避免了下溢的问题。乘法变成对数下的和。

为训练集中的每个样本计算该轨迹平衡损失函数。很关键的一点是,奖励和终态在你的训练数据中是固定值,但是轨迹是学习到的。在每一个学习时期,向前和向后的政策都将改变,模型将决定平衡概率的行动顺序,以便正确地反映回报。

在 TensorFlow 2 中构建一个 GFlowNet

现在,您已经理解了什么是 GFlowNets,为什么它们有用,以及它们是如何被训练的,您已经准备好构建一个 GFlowNets 了。作者在 github 上提供了他们所有的代码,你绝对应该研究一下。虽然本吉奥实验室使用 PyTorch 实现了他们的 GFlowNets,但我们将使用 TensorFlow 2

本教程的所有代码可以在:https://github.com/mbi2gs/gflownet_tf2/找到

环境

首先,在最初的 GFlowNet 出版物中描述的环境是一个 n 维立方体,其边长为 H ,奖励函数在角上最高。对于这个例子,我们将使用一个 2 维的 8x8 网格,因为它很容易绘制和观察发生了什么。文件` env.py '定义了re warden environment类。奖励环境的核心是一个基于输入坐标计算奖励的函数:

def reward_fn(self, coord):
   """Calculate reward function according to section 4.1 in
   [https://arxiv.org/abs/2106.04399.](https://arxiv.org/abs/2106.04399.)
   :param x_coord: (array-like) Coordinates
   :return: (float) Reward value at coordinates
   """
   assert len(coord) >= 1
   assert len(coord) == self.dim
   r1_term = 1
   r2_term = 1
   reward = self.r0
   for i in range(len(coord)):
      r1_term *= int(0.25<np.abs(coord[i]/(self.length-1)-0.5))
      r2_term *= int(
                 0.3 < np.abs(coord[i]/(self.length-1)-0.5)<= 0.4)
      reward += self.r1*r1_term + self.r2*r2_term
   return reward

最终的环境看起来是这样的,较低的奖励用紫色,最高的奖励用黄色。

电池 3 输出

向前和向后采样

GFNAgent 类在 gfn.py. 中定义,从转发策略采样需要:

  • 从原点(0,0)开始。
  • 使用该模型生成可能动作(向上、向右或终止)的概率分布。
  • 根据概率选择行动。
  • 应用终止或移动到新位置的动作。
  • 继续,直到终止操作。

理解采样过程是理解 GFlowNet 实际工作的最佳方式。在 python 中,前向采样函数如下:

def sample_trajectories(self, batch_size=3, explore=False):
   """Sample `batch_size` trajectories using the current policy.
   :param batch_size: (int) Number of trajectories to sample
   :param explore: (bool) If True, mix policy with uniform
                   distribution to encourage exploration.
   :return: (tuple of nd.array) (trajectories, one_hot_actions,
            rewards)
   """
   # Start at the origin
   still_sampling = [True]*batch_size
   positions = np.zeros((batch_size, self.dim), dtype='int32')
   trajectories = [positions.copy()]
   one_hot_actions = []
   batch_rewards = np.zeros((batch_size,))
   for step in range(self.max_trajectory_len-1):
      # Convert positions to one-hot encoding
      one_hot_position = tf.one_hot(
                           positions, self.env_len, axis=-1)
      # Use forward policy to get log probabilities over actions
      model_fwrd_logits = self.model.predict(one_hot_position)[0]
      model_fwrd_probs = tf.math.exp(model_fwrd_logits)
      if explore:
         # Mix with uniform distribution to encourage exploration
         unif = self.unif.sample(
                   sample_shape=model_fwrd_probs.shape[0])
         model_fwrd_probs = self.gamma*unif + \
                           (1-self.gamma)*model_fwrd_probs
      # Don’t select impossible actions (like moving out of
      # the environment)
      normalized_actions = self.mask_and_norm_forward_actions(
                                   positions, model_fwrd_probs)
      # Select actions randomly, proportionally to input
      # probabilities
      actions = tfd.Categorical(probs=normalized_actions).sample()
      actions_one_hot = tf.one_hot(
                          actions, self.action_space).numpy()
      # Update positions based on selected actions
      for i, act_i in enumerate(actions):
         if act_i == (self.action_space — 1) and still_sampling[i]:
            still_sampling[i] = False
            batch_rewards[i] = self.env.get_reward(positions[i,:])
         elif not still_sampling[i]:
            positions[i,:] = -1
            actions_one_hot[i,:] = 0
         else:
            positions[i, act_i] += 1
      trajectories.append(positions.copy())
      one_hot_actions.append(actions_one_hot)
   return np.stack(trajectories, axis=1), \
          np.stack(one_hot_actions, axis=1), \
          batch_rewards

一些需要强调的细节:

  • 在提供给模型之前,位置坐标被转换成一个热点矢量。
  • 有一个“探索”的选项,将统一分布与模型策略混合起来,作为一种鼓励非策略决策的方式。Gamma 是控制探索程度的参数(通过控制策略和统一的混合比例)。
  • 有些动作是不可能的,但是模型一开始并不知道(比如将模型带出环境的动作)。我们执行一个屏蔽步骤来迫使不可能的动作的概率为零。同时,你稍后会看到,我们也在训练模型识别那些不可能的步骤。
  • 上面的函数一次采样多个轨迹。对于每个终止的轨迹,添加一个填充符号(-1),而其余的完成采样。

采样反向轨迹非常相似(参考" back_sample_trajectory() "函数),但是使用向后策略而不是向前策略。落后的政策可能感觉没有必要,但它是实现工作模式的关键。在训练过程中,每次一对(位置,奖励)被输入到模型中,它就从反向策略中采样,将奖励流回原点,然后将正向策略与反向采样的轨迹匹配,一个动作接一个动作。我们将在下一节中看到它是如何在代码中工作的,但是要知道向后策略是必要的!

训练循环

训练过程从采样轨迹开始,并通过查询环境来确定奖励。可以反复采样,然后训练,然后采样,然后训练。每次迭代,模型都会更好地逼近环境,如果 GFlowNet 可以学习任何奖励结构,它将通过从未知区域智能采样来加速探索过程。也可以从独立于 GFlowNet 策略收集的训练数据集开始(这被称为“离线”训练)。对于本教程,我们将使用离线培训。

训练过程从混洗和分批训练数据开始。在这个演示中,我们使用一个生成器函数" train_gen() "来生成 10 个(位置,回报)对的混洗批次,每个时期遍历整个数据集。

train() ”函数遍历预设数量的历元。在每个时期内,它为每个训练样本计算一个损失值,并由此对模型权重进行梯度更新。如果历元期间的平均损失低于任何先前的损失,则保存模型权重。这样,最后可以加载最佳的一组砝码。

def train(self, verbose=True):
   """Run a training loop of `length self.epochs`.
   At the end of each epoch, save weights if loss is better
   than any previous epoch.
   At the end of training, read in the best weights.
   :param verbose: (bool) Print additional messages while training              
   :return: (None) Updated model parameters
   """
   if verbose:
      print('Start training...')
   # Keep track of loss during training
   train_loss_results = []
   best_epoch_loss = 10**10
   model_weights_path = './checkpoints/gfn_checkpoint'
   for epoch in range(self.epochs):
      epoch_loss_avg = tf.keras.metrics.Mean()
      sampler = self.train_gen()
      # Iterate through shuffled batches of deduplicated data            
      for batch in sampler:
         loss_values, gradients = self.grad(batch)                
         self.optimizer.apply_gradients(                    
          zip(gradients, self.model.trainable_variables + [self.z0])                
         )
         losses = []
         for sample in loss_values:
            losses.append(sample.numpy())
         epoch_loss_avg(np.mean(losses))
      # If current loss is better than any previous, save weights                     
      if epoch_loss_avg.result() < best_epoch_loss:                      
         self.model.save_weights(model_weights_path)                    
         best_epoch_loss = epoch_loss_avg.result()
      train_loss_results.append(epoch_loss_avg.result())            
      if verbose and epoch % 9 == 0:
         print(f'Epoch: {epoch} Loss: {epoch_loss_avg.result()}')       
      # Load best weights              
      self.model.load_weights(model_weights_path)

使用“ grad() 函数计算渐变。这个函数使用 tf。GradientTape()对象来计算每个模型参数相对于损失的梯度。请注意,参数“z0”被添加到正在更新的参数列表中。

损失函数

训练过程的核心是轨迹平衡损失函数。回想一下,还有其他损失函数可以使用,但是轨迹平衡往往优于以前的方法(见脚注 3)。

def trajectory_balance_loss(self, batch):
   """Calculate Trajectory Balance Loss function as described in
   [https://arxiv.org/abs/2201.13259.](https://arxiv.org/abs/2201.13259.)
   I added an additional piece to the loss function to penalize
   actions that would extend outside the environment.
   :param batch: (tuple of ndarrays) Output from self.train_gen()    
                 (positions, rewards)
   :return: (list) Loss function as tensor for each value in batch
   """
   positions, rewards = batch
   losses = []
   for i, position in enumerate(positions):
      reward = rewards[i]
      # Sample a trajectory for the given position using
      # backward policy
      trajectory, back_actions = self.back_sample_trajectory(
                                                    position)
      # Generate policy predictions for each position in trajectory
      tf_traj = tf.convert_to_tensor(
                   trajectory[:,…], dtype=’float32')
      forward_policy, back_policy = self.model(tf_traj)
      # Use “back_actions” to select corresponding forward
      # probabilities
      forward_probs = tf.reduce_sum(
          tf.multiply(forward_policy, back_actions),
          axis=1)
      # Get backward probabilities for the sampled trajectory
      # (ignore origin)
      backward_probs = tf.reduce_sum(
         tf.multiply(back_policy[1:,:],
         back_actions[:-1,:self.dim]),
         axis=1)
      # Add a constant backward probability for transitioning 
      # from the termination state
      backward_probs = tf.concat([backward_probs, [0]], axis=0)
      # take log of product of probabilities (i.e. sum of log 
      # probabilities)
      sum_forward = tf.reduce_sum(forward_probs)
      sum_backward = tf.reduce_sum(backward_probs)
      # Calculate trajectory balance loss function and add to 
      # batch loss
      numerator = self.z0 + sum_forward
      denominator = tf.math.log(reward) + sum_backward
      tb_loss = tf.math.pow(numerator — denominator, 2)

损失分别应用于每个(位置,奖励)对。注意,给定一个训练位置,第一步是使用向后策略对返回原点的轨迹进行采样。然后,为该采样轨迹中的每个位置计算相应的前向概率。z0乘以向前概率与回报乘以向后概率的比例形成了最终的损失值,但是我们应用了对数,所以乘法变成了加法。

请注意,本演示中的向后策略不包括终止可能性。相反,第一个向后动作总是被假定为终止动作,所以我们只在第一个向后步骤中包括一个恒定的可能性。从那里一直回到原点,我们只采样转移概率。请注意,从原点的转移概率没有定义,并被排除在后向轨迹之外。

最后,我们增加了一些额外的损失条款来惩罚不可能的行为,比如离开环境。我们通过识别环境边缘的位置,合计从该边缘到环境之外的概率,并将这些错误的总和加到损失中。我们对向前和向后策略都这样做。

 # Penalize any probabilities that extend beyond the 
      # environment
      fwrd_edges = tf.cast(
         np.argmax(trajectory, axis=2) == (self.env_len-1),
         dtype=’float32')
      back_edges = tf.cast(
         np.argmax(trajectory, axis=2) == 0,
         dtype=’float32')
      fedge_probs = tf.math.multiply(
         tf.math.exp(forward_policy[:,:self.dim]),
         fwrd_edges)
      bedge_probs = tf.math.multiply(
         tf.math.exp(back_policy[:,:self.dim]),
         back_edges)[1:,:] # Ignore backward policy for the origin
      fedge_loss = tf.reduce_sum(fedge_probs)
      bedge_loss = tf.reduce_sum(bedge_probs)
      combined_loss = tf.math.add(
         tb_loss, tf.math.add(fedge_loss, bedge_loss))
      losses.append(combined_loss)
   return losses

示范

笔记本“ gflownet_demo.ipynb ”将所有的片段放在一起,组成一个离线培训工作流程。

我们首先初始化一个 GFlowNet 代理(它也初始化一个奖励环境)。

from gfn import GFNAgent
agent = GFNAgent()

调用agent.model.summary()向我们展示了模型结构,默认情况下,它由两个密集层组成,每层 32 个单元,一个密集的向前策略和一个密集的向后策略。共有 1765 个可训练参数,另外还有一个用于z0

未经过训练的策略,在初始化之后看起来非常一致。垂直或横向转变(箭头)或终止(红色八边形)的可能性在每一点上基本一致。

agent.plot_policy_2d()

电池 8 输出

我们可以通过对许多轨迹进行采样,并估计在环境中每个位置结束的可能性,来可视化这种未经训练的策略的结果。

l1_error_before = agent.compare_env_to_model_policy()

电池 9 输出

请注意,大多数轨迹都在原点附近结束。鉴于每个职位都有很高的终止可能性,这是意料之中的。训练的目标是让这个情节看起来更像奖励景观(每个角落的模式)。记住,一个训练有素的 GFlowNet 生成对象的概率与回报成正比。

出于演示的目的,我们从环境中深入取样,直到大多数职位及其相关报酬都在数据集中。请注意,训练数据是重复的,因此只表示唯一的(位置,奖励)对。在这种情况下,在对 5000 个轨迹进行采样后,我们最终得到了所有四种模式(每个角中的最大值)和几乎所有的 64 个(8×8)位置。采样数据显示在下图中,x 的大小与该点的回报成比例。

agent.sample(5000)
agent.plot_sampled_data_2d()

电池 6 输出

现在我们训练模型!

agent.train()

训练进行 200 个时期,在停止之前,损失大约减少两个数量级。

Start training…
Epoch: 0 Loss: 5.823361873626709
Epoch: 9 Loss: 1.9640847444534302
Epoch: 18 Loss: 1.6309585571289062
Epoch: 27 Loss: 1.0532681941986084
… … … …
Epoch: 171 Loss: 0.03023693338036537
Epoch: 180 Loss: 0.050495393574237823
Epoch: 189 Loss: 0.046723444014787674
Epoch: 198 Loss: 0.06047442555427551

经过训练,我们可以再次可视化策略,看起来有了很大的改善。

agent.plot_policy_2d()

电池 11 输出

最后,我们通过使用学习到的向前策略对 2000 个轨迹进行采样,来可视化环境中每个位置的结束概率。

l1_error_after = agent.compare_env_to_model_policy()

电池 12 输出

这看起来更像他们奖励景观!当然,它并不完美,你可以花很多时间调整超参数来完善模型。但是,这无疑是在学习一个明智的政策。

我们还可以使用 L1 误差(每个位置差异的绝对值)来比较学习的概率分布(根据学习的策略绘制许多轨迹来估计)和目标(归一化奖励环境)。

在训练之前,L1 误差是 1.5,而在训练之后,它减小到 0.2。

结论

现在你知道什么是 GFlowNet,它们为什么有用,以及它们是如何被训练的。您已经完成了演示,可以研究 TensorFlow 2 中的实现。您已经准备好构建自己的应用程序并将其应用到自己的工作中。祝学习优秀政策好运!

Word2vec 分类器

原文:https://towardsdatascience.com/the-word2vec-classifier-5656b04143da

单词嵌入入门

如何训练单词嵌入

穆库尔·瓦德瓦Unsplash 上拍摄的照片

本文是 4ᵗʰ系列文章中关于单词嵌入的入门: 1。word 2 vec 后面有什么 | 2。单词成向量 |
3。统计学习理论 | 4。word 2 vec 分类器 |
5。word 2 vec 超参数 | 6。单词嵌入的特征

上一篇文章 统计学习理论 回顾了逻辑回归的概念和数学,以及如何使用浅层神经网络确定回归系数。在本文中,我们将扩展这些知识,学习 Word2vec 用来导出单词嵌入的分类算法的概念和数学。

基于预测的嵌入

在本系列第二篇文章讨论的向量空间模型中, 单词到向量 ,向量是从全局语料库统计创建的。向量可以被修改、重新加权,甚至降维,但它们的来源是一种基于计数的方法。

适用于基于计数的方法的相同思想也包含在我们将在这里探讨的用于创建单词嵌入的神经网络方法中。

当使用机器学习来创建单词向量时,该算法使用关于单词的邻近关系的信息来训练其权重。使用 Word2vec,上下文信息是基于教导单词向量来预测单词所在的上下文。这就是为什么神经网络学习的单词向量,如 Word2vec 中的那些,据说使用了基于预测的方法(Almeida and Xexéo,2019;Voita,2020)。

此外,术语嵌入用于单词向量,因为从神经网络训练的角度来看,单词向量的值被“嵌入”在较低维度的空间中。

Word2vec 的模型:CBOW 和 Skip-gram

Mikolov 等人的第一篇介绍 Word2vec 的论文(Mikolov 等人,2013a)描述了两种对数线性模型,可用于使用 Word2vec 导出单词嵌入:连续单词包 (CBOW)和连续跳格,他们使用下图对其进行了对比:

Word2vec 模型架构 (Mikolov 等人,2013a)

在其基本形式中,CBOW 和 Skip-gram 使用多项式逻辑回归执行分类任务,这在本系列的前一篇文章 统计学习理论 中有所描述。对于分类,不是二元响应(用 0 或 1 表示的肯定或否定结果),而是有多个结果(或类别),其中每个单词是一个类别。多项式逻辑回归使用 softmax 函数作为其激活函数,而不是为逻辑回归引入的 sigmoid 函数。

与 CBOW 相比,Skip-gram 在每个语料库中执行更多的训练示例,并且对于小语料库和罕见单词产生更好的单词嵌入,但是 Skip-gram 在计算上更加密集。

Mikolov 等人的第二篇论文介绍了 Word2vec (Mikolov 等人,2013b),详细介绍了采用 Skip-gram 模型时减少计算要求的两种方法:分层 Softmax 和负采样。

分层 Softmax 使用语料库词汇上霍夫曼编码的二叉树,在进行多项逻辑回归时,将 Softmax 的训练计算从 O ( v )减少到 O (log₂ v )。

另一方面,负采样将算法从多项式逻辑回归简化为更简单的逻辑回归,其中一个单词是匹配的(阳性),而其他单词的子集(样本)不是匹配的。这种方法是噪声对比估计(NCE)的简化,它使用了前一篇文章中描述的二进制分类数学(包括 sigmoid 激活函数)。

在下一节中,我们将详细研究使用负抽样的跳格模型。

负采样跳跃图

让我们重温一下本系列第二篇文章中的共现矩阵示例, 单词成向量 。它包括出现在语料库中每个文档中的成对单词的计数。

同现矩阵示例
(图片由作者提供,灵感来自 Potts 和 MacCartney,2019)

不包括文档级别的计数,现在让我们考虑当文档被读取时,每个单词之前的 l 个单词和之后的 l 个单词的窗口;也就是说,我们将在彼此的 l 单词距离内创建一个单词的连续单词对计数。我们将被评估的单词定义为目标单词 t 和围绕它的上下文单词 c

这种计数方法的结果是一个 v × v 矩阵(其中 v 是词汇表中的字数)。然而,当我们创建词对时,我们将通过机器学习技术来处理它们,将词向量长度限制在更少的维度,通常为 50-1000,最典型的是 300(Jurafsky 和 Martin,2019;曼宁,2021)。

这种机器学习技术是 Word2vec 的基础。该技术最大化了成对单词之间的点积,它将点积用作单词相似度的近似值。回想一下本系列的第二篇文章, 单词成向量 ,那个余弦相似度,也就是归一化的点积,是最典型的比较单词向量的方式。

在每个训练步骤,我们将训练一个分类器,使用逻辑回归的概念,通过降维近似。对于每个目标单词,我们将最大化与其周围上下文单词的点积,同时最小化所有其他非上下文单词的点积。这种方法是 Word2vec 中 Skip-gram 算法的核心,它形成单词嵌入来预测每个目标单词周围的 2 个 l 上下文单词。

Skip-gram 负采样(SGNS)中的负采样通过允许算法仅处理上下文窗口中不存在的单词子集来简化训练。它还允许将训练算法的复杂性从多项式逻辑回归降低到二元逻辑回归。

作为题外话,回想一下 Word2vec 也可以以相反的方式训练。也就是说,Word2vec 可以通过让上下文单词预测最可能的目标单词来进行训练。这个版本的 Word2vec 被称为连续单词包(CBOW)。

在接下来的部分中,我们将开发 Word2vec SGNS 的数学,但是首先让我们回顾一些 Word2vec SGNS 的高级概念:

  • 研究人员根据他们对最适合其应用的理解,在 Word2vec 之外对单词进行预处理(参见本系列第二篇文章中的“实验设计考虑”部分, 单词到矢量 )。Word2vec 并不是简单地将原始文本作为数据。Word2vec 作者甚至提供了一种额外的预处理技术来查找文本中的短语,以便这些短语可以作为训练中的一个单元(Mikolov 等人,2013b)。
  • 目标单词的“窗口”由目标单词之后的之前的单词组成,不像一些早期的ngram 语言模型通过仅在目标单词之前查找来建立单词向量。
  • Word2vec 最大化由窗口大小定义的文本中彼此靠近的单词的向量的点积,同时最小化没有出现在窗口中的随机单词的点积。点积被用作余弦相似性的代理,余弦相似性在概念上也接近皮尔逊相关系数。
  • Word2vec 使用机器学习逻辑回归技术来训练分类器(对数线性),该分类器区分正面和负面(真和假)示例。训练的回归权重被用作单词嵌入。
  • Word2vec 在训练时使用了多种重新加权技术,包括下面这些,将在本系列的下一篇文章中详细讨论,word 2 vec 超参数 :

P P 修剪生僻字

S 年代 子采样常用词

D D 根据与目标单词的距离,动态加权上下文窗口中的单词

S S 选择否定样词

  • 需要优化培训的一组参数,并且需要完成充分的培训。

请注意,Word2vec 算法的某些方面没有公布或没有得到很好的定义(Goldberg 和 Levy,2014)。研究人员不得不通过阅读代码并从 Mikolov 等人的论文(Mikolov 等人,2013aMikolov 等人,2013 年 b)。

Word2vec 具有微妙性和复杂性,它的一些成功即使在今天也没有得到很好的理解(Goldberg 和 Levy,2014;Jurafsky 和 Martin,2019 年),但这里有一个从 Goldberg 和 Levy 那里获得的有趣信息,为了与本文中使用的术语保持一致,对其进行了重新措辞:

SGNS 没有建模 P ( c|t ) 而是一个与目标词 t 及其每个上下文 c 的联合概率相关的量。联合学习 tc 的表示,使模型非凸。如果固定目标单词并仅在上下文表示上训练,或者固定上下文表示并仅学习目标表示,则该模型简化为逻辑回归,并且是凸的。(戈德堡和利维,2014)

对于统计师来说,Word2vec 值得强调的几点包括:

  • Word2vec 并不是从独立同分布(iid)的随机变量的原始数据开始的。我们处于机器学习领域,寻找最有效的方法,并应用统计学原理来帮助获得最成功的结果。
  • Word2vec 做了一个简化的假设,即语境词是独立的,这是不成立的(Jurafsky 和 Martin,2019)。
  • Word2vec SGNS 算法使用概率分类器,该分类器使用逻辑回归机器学习技术(如 softmax 或 sigmoid 函数进行归一化)的各个方面来分配概率,但结果并不完全是概率性的。
  • 最后,尺寸受到设计的限制,使得 Word2vec 的结果只是一个近似值。

在高层次上,上面概述的几点是 Word2vec 如此重要的原因。Manning 是 GloVe (Pennington 等人,2014 年)的合著者,GloVe 是一种在 Word2vec 一年后推出的性能稍好的单词嵌入算法,他在自然语言处理与深度学习中对 Word2vec 这样说:

“从某种意义上说,对将 NLP 世界转向神经网络方向产生最大影响的是托马斯·米科洛夫在 2013 年提出的一种算法,称为 Word2vec 算法。这是一种非常简单、非常可扩展的学习单词矢量表示的方式,它真正打开了闸门。”(曼宁,2019)

现在,让我们回顾一下 SGNS 的数学。

SGNS 分类器

当在他们关于 Word2vec 的第二篇论文中定义负采样与 Skip-gram 一起使用时,Mikolov 等人从他们在第一篇论文中使用的 softmax 转向引用 sigmoid 函数的使用(Mikolov 等人,2013bMikolov 等人,2013a)。

在统计学中,sigmoid(或逻辑函数)在进行逻辑回归(即二元分类)时创建概率分布;然而,对于名义多项式模型,softmax 函数定义了概率分布。

SGNS 执行二元分类任务。给定两个词,来自上下文窗口内的目标词 t 和潜在上下文词 c ,SGNS 应该返回上下文词确实是来自语料库的上下文词的概率。

为了更好地说明这种二元分类是如何工作的,让我们来看一个句子中的短语:

(图片由作者提供,短语灵感来自 Chia,2018)

使用窗口 l =2,当单词‘处理’是目标单词 t 时,有 2=4 个上下文单词: c ₁、 c ₂、 c ₃、 c ₄.

对于每个目标词 t 和上下文词 c ,让我们创建一个二元分类器,预测 ct 的真实( y =1 其中 y ∈{0,1})上下文词的概率(Jurafsky 和 Martin,2019;戈德堡和利维,2014):

因此, ct 的假上下文词的概率,即不真实情况( y =0),是 1 减去真实情况:

Word2vec 算法使用向量 tc 的点积,通过近似公式计算这些概率:

您可能还记得本系列的第二篇文章,余弦相似性的等式(通常用于测量单词向量相似性)是归一化的点积:

其中 ab 是两个大小为 n 的向量。

因为 t c 的点积不产生从 0 到 1 的实际概率值,所以在 SGNS 模型中使用了逻辑或 sigmoid 函数 σ ( z ):

使用 sigmoid 转换为概率来源于本系列上一篇文章讨论的逻辑回归, 统计学习理论 。在逻辑回归中,z =XβXβ为模型提供了线性回归中的最优直线,但在本例中 z = t c 所以,根据点积的相似度公式, ct、的真实上下文词的近似概率为(Jurafsky and Martin,2019;戈德堡和利维,2014):

c 为假上下文词,即 y =0,对于 t 的近似概率为:

接下来,我们来回顾一下 Word2vec 的神经网络模型对 SGNS 使用的学习过程。

SGNS 损失函数

SGNS 通过抽取否定情况的样本(即,是错误上下文单词的单词)来简化处理。因此,如果我们取一个目标/上下文单词对( t,c )并将其与 k 负样本单词 s…sₖ 相结合,则学习目标是最大化 tc 匹配且负样本不匹配的概率。

为了做到这一点,SGNS 做出了不正确但数学上简化的假设,即所有上下文词和负样本都是独立的,这允许它们的概率被相乘(Jurafsky 和 Martin,2019)。因此,我们需要找到这个似然函数的最大值:

为了进一步简化数学,我们可以像将最大似然法应用于逻辑回归时一样使用对数。自然对数不会影响结果,因为函数是单调递增的。如前一节所示,Word2vec 使用一个近似公式计算相似度,使用单词向量的点积。因此,学习目标 L 是(Jurafsky 和 Martin,2019):

这里,θ被认为是目标和上下文词向量的串联,即它们的权重矩阵(Kim,2019)。

在机器学习中,损失函数(也称为目标函数或成本函数) J ( θ ),是将最小化的函数,因此是上述对数似然方程的负数(Kim,2019;Voita,2020):

SGNS 训练和随机梯度下降

为了在数学上找到损失函数中的最小值,我们取其导数,然后将其设置为零。在机器学习中,人们估计每一步向最小值的方向,并向它迈出一小步(Voita,2020):

在这里,𝛼就是那一小步,也就是学习速率。朝着最小值前进被称为随机梯度下降

在 SGNS 中,相对于c 、以及负样本、 s ,使用上面所示的 J ( θ )的偏导数来确定朝向最小值的方向。因此,对于每个第 m 个训练实例,单词向量值更新如下(Jurafsky 和 Martin,2021):

其中 σ ( z )是上面定义的 sigmoid 函数。

我们通过在目标单词向量矩阵 T 和上下文单词向量矩阵 C (权重矩阵)中为每个单词建立随机向量来进行学习过程。有时初始值采用 1 和 1 之间的均匀分布。然而,2017 年科奇米和 Ondřej 证明,使用以零为中心的低方差随机正态分布(例如,𝒩(𝜇=0,𝜎 =0.01),会导致更快的优化。

注意,对于负采样,我们可以通过选择取多少负样本来调整计算量。然而,Skip-gram 的训练时间与窗口大小 l 成比例。

SGNS 权重矩阵

训练完成后,每个单词有两个嵌入, t c 。通常在实践中, C 矩阵被忽略,而 T 将每个单词嵌入定义为向量 t 。然而,也可以将两个嵌入相加或平均,或者连接两个嵌入,以创建两倍长的向量(Jurafsky 和 Martin,2019;曼宁,2019)。

下图显示了训练过程中的一个更新,其中目标单词“processing”与上下文单词“language”配对,单词“aardvark”被随机选为负样本。

**

用一个否定样本更新目标/上下文单词对
的权重矩阵 T 和 C(图片由作者提供,灵感来自 Jurafsky 和 Martin,2019)

重要的是要理解,在训练期间,矩阵、矩阵、矩阵和矩阵和矩阵中的单词嵌入都会更新。更具体地说,在本例中, T 中的“处理”被更新为 C 中“语言”的目标词,而不是中“土豚”的目标词,并且 C 中的“语言”被更新为 T 中“处理”的上下文词,而 C 中的“土豚”被更新为同样,训练使用点积作为相似性的度量。**

这也是进行二元分类的前馈神经网络的框架:

二元分类器的神经网络框架
(图片由作者提供,灵感来自 Raschka,2020)

在这个简单的浅层神经网络中,向量 w 中的权重代表预测系数,它们可以用于对一组新的输入 x 进行预测。然而,在 Word2vec 中,“权重”是单词嵌入本身,有两组。 T 中的行是单词嵌入,每个都被优化以预测它们在 C 中的上下文单词,并且 C 中的列是单词嵌入,每个都被优化为用于 T 中的每个目标单词的那些上下文单词。

虽然 TC 都包含词汇表的所有单词,但是 TC 针对不同的条件进行了优化,因此包含不同的信息。然而,正如 Jurafsky 和 Martin (2019 年)和 Manning (2019 年)指出的,通常会忽略 C 矩阵。

一个有趣的问题是,当* C 矩阵被忽略时会丢失什么?*

Word2vec SGNS 不是典型的神经网络。Word2vec SGNS 算法训练速度很快,并且具有使其成为研究对象的品质。例如,Levy 和 Goldberg (2014b)证明了 SGNS 分解移位的 PMI 矩阵,Aggarwal (2018)补充说,SGNS 执行一种逻辑矩阵分解,即一种自动编码。

摘要

在本文中,我们了解到 Word2vec 使用两个基本模型,一个是对上下文单词集进行平均来预测目标单词(CBOW),另一个是目标单词预测上下文单词(Skip-gram)。这些模型使用执行多项式回归的浅层神经网络。我们还看到了如何使用负采样减少 Skip-gram 的计算需求,负采样将算法转换为二进制分类器。

然后,我们从概念上和数学上研究了负采样跳过图(SGNS)是如何工作的。

在下一篇文章中,Word2vec 超参数我们将了解 word 2 vec 用来优化训练其单词嵌入的一组附加技术。

这篇文章是 4ᵗʰ系列文章中关于单词嵌入的初级读本: 1。word 2 vec 背后有什么 | 2。单词成向量 |
3。统计学习理论 | 4。Word2vec 分类器|
5。word 2 vec 超参数 | 6。单词嵌入的特征

关于这个主题的更多信息:与其他单词嵌入技术相比,我推荐学习 Word2vec 的一个资源是斯坦福大学的这个在线计算机科学课程:Manning,C. (2021), CS224N 自然语言处理与深度学习

参考

阿加瓦尔,C. (2018)。神经网络和深度学习:一本教科书。瑞士查姆:施普林格国际出版公司。

阿尔梅达,f .和 Xexéo,G. (2019)。词汇嵌入:一个综述。可从 arXiv:1901.09069v1 获得。

Goldberg 和 o . Levy(2014 年)。word2vec 解释:推导 Mikolov 等人的负采样单词嵌入法。可从 arXiv:1402.3722v1 获得。

Chia,D. (2018)。使用 NumPy 和 Google Sheets 的 Word2Vec 实现指南。走向数据科学。**

jurafsky d .和 Martin j .(2019 年)。语音和语言处理:自然语言处理、计算语言学和语音识别导论。徒弟堂,第三版,2019 稿

jurafsky d .和 Martin j .(2021)。语音和语言处理:自然语言处理、计算语言学和语音识别的介绍。徒弟堂,第三版,2021 稿

金,E. (2019)。揭秘 Skip-Gram 语言建模中的神经网络Github

t .科奇米和 b . ondřej(2017 年)。深度学习任务中单词嵌入初始化的探索。P 第十四届国际自然语言处理会议论文集(ICON-2017)第 56–64 页。P DF。

Levy 和 y . Goldberg(2014 年 b)。神经单词嵌入作为隐式矩阵分解。第 27 届国际神经信息处理系统会议录,2:2177–2185。 PDF

Manning,c .(2019)cs 224n 自然语言处理与深度学习 。在线计算机科学课程。加州斯坦福:斯坦福大学。

Manning,c .(2021)cs 224n 自然语言处理与深度学习 。在线计算机科学课程。加州斯坦福:斯坦福大学。

Mikolov、Corrado、G . Chen、k .和 j . Dean(2013 年 a)。向量空间中单词表示的有效估计。可从 arXiv:1301:3781v3 获得。

Mikolov、Corrado、G . Chen、k . Sutskever 和 j . Dean(2013 年 b)。词和短语的分布式表示及其组合性。可在 arXiv:1310.4546v1 获得。

Pennington、r . Socher 和 c . Manning(2014 年)。GloVe:单词表示的全局向量。2014 年自然语言处理经验方法会议论文集,第 1532–1543 页。 PDF

Potts c .和 MacCartney b .(2019)。 CS224U 自然语言理解 ,在线计算机科学课程。加州斯坦福:斯坦福大学。

沃伊塔湖(2020)。自然语言处理课程:单词嵌入Github

*除非另有说明,数字和图像均由作者提供。

Word2vec 超参数

原文:https://towardsdatascience.com/the-word2vec-hyperparameters-e7b3be0d0c74

单词嵌入入门

一组创造性的重新加权

阿迪·戈尔茨坦Unsplash 上拍摄的照片

本文是 5ᵗʰ系列文章中关于单词嵌入的入门: 1。word 2 vec 后面有什么 | 2。单词成向量 |
3。统计学习理论 | 4。word 2 vec 分类器 |
5。word 2 vec 超参数 | 6。单词嵌入的特征

在上一篇文章Word2vec 分类器中,我们学习了 word 2 vec 算法的概念和数学,重点是负采样的跳格模型(SGNS)。

然而,并不仅仅是 SGNS 的算法使它有效。2015 年,Levy 等人将来自传统的基于计数的方法(如 PPMI 矩阵和 SVD 降维向量)的最新单词向量与当时可用的基于预测的方法(包括 Word2vec SGNS 和 GloVe)进行了比较。他们发现,Word2vec 的大部分性能提升来自其系统设计选择和“超参数”,而不仅仅来自神经网络启发的训练。

在本文中,我们将回顾 Word2vec 的性能改进预处理建议和算法优化参数。

短语识别

Mikolov 等人强调了预处理原始文本的重要性,提出了一种识别语料库中出现频率足够高的短语的方法,为短语创建嵌入比单独为单词创建嵌入效果更好(Mikolov 等人,2013b)。在 NLP 中识别短语通常与命名实体识别相关联,这允许像‘Bush’(植物)和‘Bush’(总统)这样的词可以单独嵌入。Mikolov 等人定义的短语识别公式是:

其中分数是选定的值,高于该值的短语被识别。这里, δ折现系数。Mikolov 等人解释说,他们更喜欢对数据运行得分方程 2 到 4 次,每次减少 δ 的值。

词频阈值

Word2vec 不是简单地根据单词在原始文本中的外观来训练单词。首先,根据训练前设定的阈值从语料库中去除生僻字。罕见的单词被删除,因为语言模型不太可能需要它们,并且正确训练它们的上下文更少。

Mikolov 等人定义了以下公式,其中可以根据参数𝜏(通常在 10⁻⁵附近)设置阈值(Mikolov 等人,2013b):

其中 f ( wᵢ )是由单词 wᵢ 表示的语料库的分数。但是,请注意,根据 Levy 等人(2015 年)的说法,Mikolov 等人的代码的 C 编程语言实现使用了以下稍加修改的等式:

子采样率

此外,为了减少训练时间,根据 Mikolov 等人的代码(McCormick,2019)的 C 编程语言实现中的以下子采样函数,Word2vec 训练更频繁的单词的频率低于它们在语料库中的出现频率:

这里再次说明, f ( wᵢ )是由单词 wᵢ 表示的语料库的分数,参数𝜅控制进行多少次子采样。当𝜅设置为默认值 0.001 时,最常见的英语单词“the”的 80%的实例可能会被跳过,但当单词的频率 f ( wᵢ )小于 0.0026 时,不会发生跳过。

上下文位置加权

当对目标单词周围的窗口 l 中的上下文单词进行训练时,Word2vec 不会像最初出现在文本中一样使用这些单词。首先,根据前两节中解释的公式,在训练开始之前删除不常用的单词,跳过常用单词的实例。移除这些单词后,上下文窗口实际上比保留这些单词时要宽。

接下来,Word2vec 对距离目标单词 t 较近的上下文单词的线性加权比距离较远的上下文单词大。例如,如果窗口大小为 l =5,则位于最远位置的单词有/₅机会被包括在训练中,而恰好在目标单词之前或之后的单词总是被包括在内,如下图所示:

上下文位置加权示例(麦考密克,2019,经许可转载)

根据 Levy 和 Goldberg 在 2014 年发表的一篇论文(Levy 和 Goldberg,2014 年),对于广泛的主题嵌入,窗口大小通常为 5。

负样本的加权

在 SGNS 中,第 k 个否定样本词不是根据它们在文本中的出现频率来选择的(unigram);也不是同等(统一)选择的。相反,Word2vec 使用加权单字频率 P 𝛼( w ,其中 wᵢ 是单词, f ( wᵢ )是该单词在语料库中的总单词数, v 是词汇表中的单词数,𝛼 是米科洛夫等人定义的权重(米科洛夫等人,2013b 麦考密克,2019):

当𝛼=1 时,根据单词在语料库中的出现频率来选择单词。对于 SGNS,Mikolov 等人发现𝛼=0.75 效果最好:

“我们调查了许多关于p【𝛼](w】的选择,发现在我们尝试的每个任务中,一元分布 U ( w )的 3/4rd 次方(即u(w)/⁴/z)明显优于一元分布和均匀分布……(米科洛夫等人,2013 年 b)

当𝛼=0 75,训练生僻字的概率增加,训练频繁字的概率减少(McCormick,2019),反映了本系列第二篇文章 字成向量 中讨论的重新加权方法的一个客观。

根据 McCormick (2019)的说法,“这种单词选择在[Mikolov 等人的] C 代码中实现的方式很有趣。麦考密克解释说,米科洛夫等人创建了一个包含 1 亿个元素的大数组,并根据等式 P 𝛼( w 用词汇表中每个单词的索引填充它。在训练过程中,他们通过选择 0 到 1 亿之间的随机数来随机选择表中的一个词索引值,从而选择负样本。

摘要

在本文中,我们学习了一些建议用于创建单词向量的文本预处理技术,以及一些基于训练的重新加权“技巧”,这些技巧用于在使用 Word2vec 创建单词嵌入时优化结果并减少训练时间。

在下一篇文章 单词嵌入的特点 中,我们将看看 Word2vec 单词嵌入的优缺点。

这篇文章是 5ᵗʰ系列文章中关于单词嵌入的初级读本: 1。word 2 vec 背后有什么 | 2。单词成向量 |
3。统计学习理论 | 4。word 2 vec 分类器 |
5。Word2vec 超参数| 6。单词嵌入的特征

关于这个话题的更多内容:我推荐的一个了解 Word2vec 算法更多内容的资源是:McCormick,C. (2019)。word 2 vec的内部运作方式(电子书)。

参考

Levy 和 y . Goldberg(2014 年)。基于依存关系的单词嵌入。在计算语言学协会第 52 届年会会议录(第 2 卷:短文)(第 302–308 页)。可在 doi10.3115/v1/P14–2050处获得。

Levy、y . Goldberg 和 I . Dagan(2015 年)。利用从单词嵌入中获得的经验改进分布相似性。计算语言学协会汇刊,3:211–225。可在 doi10.1162/tacl _ a _ 00134处获得。

麦考密克,C. (2019)。word 2 vec 的内部工作原理 (Pro 版,第一版)。电子书。McCormickml.com

Mikolov、Corrado、G . Chen、k . Sutskever 和 j . Dean(2013 年 b)。词和短语的分布式表示及其组合性。可从 arXiv:1310.4546v1 获得。

*除非另有说明,数字和图像均由作者提供。

我在伦敦大学学院的第一个研究项目中犯的最严重的 4 个错误

原文:https://towardsdatascience.com/the-worst-3-mistakes-i-made-in-my-first-research-project-at-university-college-london-1b973acbb5ab

从我的错误中吸取教训,在你自己的研究项目中脱颖而出

Unsplash 上的窗口拍摄

大约两年前,我在伦敦大学学院从事我的第一个严肃的机器学习和数据科学项目。这个项目对我来说非常困难和可怕,因为我以前对机器学习和数据科学一无所知,而且我试图在医疗领域解决的问题是非常特定的。

该项目是关于使用无监督学习来区分 8 种不同类型的组织。这听起来可能不太难,但在组织病理学领域,组织和载玻片之间的差异有时甚至对于专业病理学家来说也很难区分。你可以在这里找到更多关于我的项目的信息:

无论如何,本文的主要目的是强调我作为一名数据科学家初学者在实验过程中所犯的错误。在阅读了几个博客并与其他初级数据科学家交谈后,我开始注意到一个很容易避免的模式,我认为这非常值得分享。请注意,这是一个成熟的项目,需要 400 多个小时的工作,所以我犯了很多错误,也学到了很多东西!我也注意到很多人在 Kaggle 比赛中重复这些错误。事不宜迟,让我们开始吧:

1.总是从最简单的模型开始,建立坚如磐石的基线

当我第一次开始学习机器学习时,我想象大多数人一样,对深度学习非常热衷。我在项目开始时的主要思路是:

如果神经网络是最新和最好的进步,那么我将不得不在自己的项目中使用它们才是有意义的。因此,我一开始就试图直接去找他们。

这是我在许多初学数据的科学家身上看到的一个非常大的误解。神经网络并不总是最好的方法。即使它们是,从神经网络模型开始也不会有任何进展。简单地说,对于初学者来说,在他们的项目中成功地实现一个高性能的神经网络是非常困难的,因为:

  1. 他们没有花足够的时间检查和分析数据
  2. 他们将无法为他们的神经网络进行有效的数据和特征工程,除非他们已经为更多可解释的模型如 K-Means 或决策树(当然取决于任务)进行了数据和特征工程。

这在开始时导致了很多挫折,因此我意识到从最简单的模型(因为我正在做一个无人监督的项目,所以它是 K-Means)开始更有意义,建立一个可靠的指标,我可以根据它来衡量性能,了解更多的数据,并以我的方式向上发展。

实际上,即使在我的项目结束时,神经网络最终胜过了其他模型,我仍然有非常简单和更容易解释的模型实现了非常相似的性能。我想在医学领域,高度可解释性可能比 1%-2%的性能提升更有利!

2.你的实验要非常准确、描述性和系统性

我犯的一个非常大的错误是我的实验非常混乱。我从一个模型跳到另一个模型,从一个超参数跳到另一个超参数,而没有完全检查和记录结果。这使得写期末论文和分析我接下来的步骤变得非常困难。而且最糟糕的是,我看过很多关于资深数据科学家犯这种错误的博文。

对于您执行的每个实验,请确保记录:

  1. 您执行的任何数据/特征选择/提取
  2. 具有所有超参数的模型
  3. 评估指标
  4. 交叉验证策略
  5. 集合策略(如果有)

确保一次只改变一个参数,并观察结果。看完结果后,总是问自己为什么结果会有改善或下降?我对尝试新模型感到非常兴奋,因此每次实验后,我都直接跳到下一个最先进的模型,根本没有检查我实现的模型为什么会这样!

我的超参数实验也相当混乱,我已经忘记了很多实验,我不得不在最后重做。我也发现自己在最后写论文的时候,在实际思考那些实验的时候,缺乏很多分析。

3.不要只关注建模

也许这只是我的想法,但我急着尽可能多地尝试各种型号。我最初认为,最重要的是你在数据上拟合的模型的容量和复杂性。这实际上是不正确的。我认为在做研究项目时需要优化的不同领域的一个很好的总结是:

  1. 数据清理和加载
  2. 功能选择和工程
  3. 建模
  4. 交叉验证策略
  5. 集成策略

建模只是等式的一部分。我没有意识到这一点,结果花了大约 50-60%的时间在建模上,而我应该花更少的时间(在我看来)。在参加了几次 Kaggle 竞赛后,我了解到,在构建高质量的机器学习系统时,特征选择和工程很可能是等式中最有效的部分。有效的交叉验证策略也非常重要。否则,您最终会得到一个您认为性能很好的模型,但实际上是一个简单地过度拟合数据的模型。

4.特定领域的知识&简单可解释的模型是你的秘密成分

我认为我可以在不太了解这个领域的情况下获得一个高性能的模型。虽然有些人可能试图向你兜售这样的想法:

机器学习是一个神奇的黑匣子,只需把你的数据放进去,你就会得到好的结果

事实根本不是这样。当然,你不一定要成为该领域的专家才能做出一个好的模型,但是你需要有一个像样的理解。你总是这样做,但你需要的数量取决于手头的问题。我建议至少阅读 5-10 篇关于该领域和同一问题的好模型的高质量论文。在我的项目中,与数周的新模型试验相比,简单的特定领域技巧产生了最高的性能提升。

另外,确保从一个简单的可解释的模型开始,而不是复杂的模型!

结论

我希望这篇文章对你有所帮助。作为一个初学者,最好的事情是避免非常简单的事情,比如我上面提到的那些,通常会给你的结果带来非常显著的改善。一旦你成为中级/专家(我不是说我是),我想你会发现改进你的实验要困难得多。这利用了数据科学中知识相对于经验的重要性。

在你的项目中编码和实现模型是重要的,但是从别人的错误中学习和做课程肯定会极大地推动你前进。

如果您想定期收到关于人工智能和机器学习的最新论文的论文评论、高质量的 ML 教程等,请添加您的电子邮件此处 &订阅!

精确召回曲线下面积近似的正确与错误

原文:https://towardsdatascience.com/the-wrong-and-right-way-to-approximate-area-under-precision-recall-curve-auprc-8fd9ca409064

总结 AUPRC 的方法有很多,但并不是所有的方法都有相同的优点

雷蒙·克拉文斯Unsplash 上拍摄的照片

精确召回(PR)曲线下的面积(AUPRC)是一个总结 PR 曲线信息的单一数字。有许多方法可以估算它的封闭面积,但并不是所有的方法都有同样的优点。本文试图分析近似 AUPRC 的两种常见方法:使用梯形规则或使用平均精度分数,以及为什么一种方法比另一种方法更正确。

通过 PR 曲线的梯形近似获得的 AUC 与平均精密度分数不同:例如

我看到人们经常犯的一个错误是,假设通过 PR 曲线的梯形插值获得的 AUC(在 scikit-learn 中用auc(precision, recall)表示)与平均精度分数(在 scikit-learn 中用average_precision_score(y_true, y_score)表示)完全相同。虽然这两种度量在许多情况下产生非常相似的估计,但它们是根本不同的。梯形方法使用了过于乐观的线性插值。当数据高度偏斜时,更有可能观察到这种不正确插值的影响(,这正是 PR 曲线优于 ROC 曲线的情况)。

为了说明这一点,我在从 UPenn 机器学习基准(PMLB)套件中选择的不平衡数据集上训练了一个虚拟分类器。这个名为“spambase”的数据集有 4,601 个观察值,57 个特征,以及 0.04 个阳性率的二进制目标。虚拟分类器根据 80%的训练数据进行训练,并根据 20%的排除数据进行评估。当比较梯形规则产生的 AUPRC 估计值与平均精度得分时,前者明显更高(0.53 比 0.41)。下面提供了您自己实验的代码片段——由于虚拟分类器和训练/测试分割的随机性,您可能看不到完全相同的估计值。然而,与平均精度分数相比,梯形规则计算的 AUPRC 过于乐观,这一观点应该是明确和一致的。

https://replit.com/@TamTran26/AUPRC-different-estimations#main.py [## AUPRC 不同估计

与平均精度分数相比,使用梯形规则获得的 AUPRC 过于乐观。使用 repl.it 生成的交互式代码。](https://replit.com/@TamTran26/AUPRC-different-estimations#main.py)

为什么梯形近似适用于 ROC 空间…

给定 ROC 空间中的一组点,其 x 坐标表示假阳性率(FPR),y 坐标表示真阳性率(TPR),梯形近似使用线性插值来连接相邻的点以形成 ROC 曲线。简单来说,我们画一条连接两点的直线。该曲线下的面积(AUC)是所有梯形面积的总和。

连接 4 个 ROC 点的 ROC 曲线。曲线下面积(AUC)分数可以通过梯形规则计算,该规则将曲线下的所有梯形 1、2 和 3 相加。图片作者。

已经证明,通过投掷加权硬币来决定两个端点所代表的分类器,可以在连接两个现有 ROC 点的这条线上实现任何级别的性能。假设点 a(在上图中)代表模型 a,它在 fₐ的 FPR 下实现了 tₐ的 TPR,而模型 b(由点 b 代表)同样在 fᵦ.实现了 tᵦ的 TPR 在分类器 a 和分类器 b 之间,通过以概率 pᵦ = (f-fₐ)/(fᵦ-fₐ)选择 b 的输出和以概率 pₐ=1-pᵦ.选择 a 的输出,可以产生具有 FPR f 的新分类器

线性插值实际上是 ROC 空间中凸包的关键思想所要求的主要标准之一。

…但不是在公关领域?

在 ROC 空间中,TPR(或召回)相对于 FPR 绘制,而在 PR 空间中,召回相对于精确度绘制。随着召回水平的变化,精确度不一定线性变化。召回被定义为 TP/(TP+FN),其中 TP+FN =实际阳性的数量不依赖于分类器阈值。这意味着降低分类器阈值可以通过增加真阳性结果的数量来提高召回率。也有可能降低阈值会使召回率保持不变,而精确度会波动。另一方面,Precision=TP/(TP+FP)的定义表明,通过增加返回的肯定预测结果的数量,降低分类器的阈值可以增加分母。如果阈值先前设置得太高,新的结果可能都是真阳性,这将提高精确度。如果先前的阈值大约合适或太低,进一步降低阈值将引入假阳性,降低精度。例如,PR 空间中的基线曲线是一条水平线,其高度等于正类的流行度,这意味着对于每个召回值,对应的精度值保持不变,并且等于流行度。

所以在 PR 空间中,点与点之间的线性插值是不正确的。线性插值是一个错误,它对 PR 空间的性能估计过于乐观。当要插值的点之间的距离非常大时,不正确插值的影响尤其明显。

考虑从具有 433 个阳性和 56,164 个阴性的数据集由单个点(0.02,1)构建并延伸到端点(0,1)和(1,0.008)的曲线。正确的插值将产生 0.031 的 AUPRC,而线性插值将严重高估 0.50 的 AUPRC。图片来自 Davis 和 Goadrich (2006)的论文“精确召回和 ROC 曲线的关系”。

对于 AUPRC,什么是更好的近似?

希望到现在为止,我们都同意非线性插值是 PR 空间的发展方向。有多种不同的方法和变体可用于构建该 PR 曲线。Davis 和 Goadrich (2006)根据对应于每个 PR 点的真阳性(TP)和假阳性(FP)的数量来检查插值。假设我们有一个包含 20 个阳性和 2000 个阴性的数据集。让 TPₐ=5、FPₐ=5、TPᵦ=10 和 FBᵦ=30.为了找到一些中间值,Davis 和 Goadrich (2006)建议首先找出多少个负数等于一个正数,或者局部偏差,由(FBᵦ-FPₐ)/(TPᵦ-TPₐ).)定义在本例中,局部偏斜=(30–5)/(10–5)= 5,这意味着每 5 个负值就有 1 个正值。现在,我们可以为 x 的所有整数值创建新点 TPₐ+x,使得 1≤x≤TPᵦ-TPₐ,并通过由局部偏斜线性增加每个新点的假阳性来计算相应的 FP。具体来说:

+-------+----+----+--------+-----------+
| Point | TP | FP | Recall | Precision |
+-------+----+----+--------+-----------+
| A     | 5  | 5  | 0.25   | 0.5       |
| .     | 6  | 10 | 0.30   | 0.375     |
| .     | 7  | 15 | 0.35   | 0.318     |
| .     | 8  | 20 | 0.40   | 0.286     |
| .     | 9  | 25 | 0.45   | 0.265     |
| B     | 10 | 30 | 0.5    | 0.25      |
+-------+----+----+--------+-----------+

请注意,结果精度插值在 0.5 和 0.25 之间不是线性的。

另一个较好的估计是平均精度(AP)。AP 方法完全避免了经验曲线的构建,这意味着我们不需要担心使用什么插值方法。AP 计算为每个阈值达到的精度的加权平均值,其中权重是从上一个阈值开始的召回增加:

ap=σ(rₙ-rₙ₋₁)pₙ

其中 Pₙ和 Rₙ是第 n 个阈值的精度和召回率。

AP 和工作点下的梯形面积都是概括精度-召回曲线的常用方法。但是,它们可能会导致不同的结果,尤其是当数据高度倾斜时。在这些情况下,AP 是更合适的估计值。

参考文献

[1] J.Davis 和 M.Goadrich,(2006),ICML 2006 年第 23 届机器学习国际会议论文集

如果你喜欢这篇文章,你可能也会喜欢:

数据科学不仅仅是软件开发

原文:https://towardsdatascience.com/theres-more-to-data-science-than-software-development-eb8c2fd5ac0c

意见

不是软件的四种技能

与数据科学家交谈时,我发现最令人不快的事情之一是对软件开发的高度关注。“你用 R 还是 Python 编码?熊猫有了新功能!你对图书馆‘x’有多少年的经验?”

沿着这些思路,我最近看到一条推文,称数据科学的准入门槛极低。该推文建议,你所要做的就是在网上参加一些软件开发课程,你就可以开始了!它让我的胃翻腾。它混淆了整个数据科学领域和软件开发。

数据科学家为什么要冒充软件开发人员?数据科学远不止于此。看到数据科学家独力推动该领域的软件开发,令人大失所望。

詹姆斯·希利Unsplash 上拍摄的照片

软件对数据科学家来说重要吗?当然了。熟练编码是工作的一大部分吗?是的。数据科学家能从软件开发人员那里学到很多东西吗?绝对的。软件开发技能是数据科学家最重要的属性吗?号码

当我们推动软件开发成为数据科学中最重要的一块时,我们冒着将我们的团队和领域变成另一个 IT 部门的风险。这并不是要批评它的工作。我与许多大型企业合作过,我无法告诉你我在 IT 部门遇到了多少非常聪明、有才华的人。但是这些团队在他们的组织中扮演着明确的角色。总的来说,他们没有推动整体商业战略。然而,我看到许多进入该领域的数据科学家希望影响商业中的重大决策,然后完全专注于最大化软件开发技能。

软件开发是你的重要工具。但它不是唯一的工具。我们不能做出支持业务关键决策的崇高承诺,然后回到只谈论软件开发。

我在这里 写过数据科学家需要的更多态度工具 。然而,即使在技术方面,也不仅仅是软件。

这是软件开发之外的四项关键技能,是许多数据科学家所缺乏的。

基本统计背景

除非你知道代码背后的基本统计数据,否则你不会真正理解你的代码在做什么。我遇到过许多数据科学家,他们可以很快编写出复杂的深度学习模型,但他们几乎没有掌握正态分布的含义。

熟练的数据科学家知道他们工具的基础。迈克·泰森说得好,“每个人都有一个计划,直到他们被打脸。”好吧,当你的数据科学模型行为不当,给你当头一棒时,通常是对基本面的理解让你能够纠正方向。

波格丹一世·尤克姆丘克Unsplash 上的照片

你必须有扎实的数学和统计学基础。你熟悉常客统计的核心概念吗?贝叶斯统计呢?如果你必须为你正在利用的模型写第一原理伪代码,你能吗?你错过了哪些差距,如何弥补?

此外,我认为数据科学中的最佳解决方案往往比许多人愿意承认的更为基础。最成功的数据科学家反复向我展示了简单、基本解决方案的优雅。

批判性思维

最优秀的数据科学家善于理解争论,质疑他人,并梳理出某人在对话中带来的真相。数据科学不是一行一行地重复信息;它比那有更多的艺术。源于能够破译你接收到的信息质量的艺术。

我在数据科学项目中见过的一些最大的失误,都是从有人认为错误的信息或无力的论点是理所当然的,而不去质疑它开始的。如果你正在着手一个项目,你的工作就是从一开始就提出正确的问题并分析情况。说你接受了订单或得到了错误的信息是一种逃避,不会让你走得太远。

我发现批判性思维是一个人能否在数据科学领域取得成功的最重要的决定因素之一。商业中的任何职位都需要批判性思维,但在数据科学中尤其重要。所提的问题太模糊,不经过适当的检查就无法解决。为什么?因为在商业环境中,你将成为大量信息、理论和观点的接收端。有些是有根据的,有些就没那么有根据了。作为一名数据科学家,你试图将这些信息和想法转化为统计模型。如果你不能破译你收到的信息的质量,你将迷失在大海里。

Anastasia Taioglou 在 Unsplash 上拍摄的照片

为了锻炼这些辩论数据的肌肉,科学家需要哲学的基础知识。网上有免费的课程可以帮助你达到这个目标。最好的不是专门针对数据科学的。对于许多数据科学家来说,这些课程会让人感到沮丧——正确的答案不会非黑即白。这才是重点。

沟通

很不幸,但我见过高质量的模型因为沟通不畅而失败。数据科学家无法清楚地解释他们的模型在做什么,或者结果意味着什么。由于没有人能理解他们的工作,这个项目被认为是失败的。事实上,结果可能会非常有见地。然而,如果你不能以一种清晰、有意义、可联系的方式为你的客户和团队成员提供这些见解,那么你将永远不会获得你想要的巨大影响。

我甚至可以说,无论一个数据科学项目执行得多么好,如果没有适当的沟通,它都不会被认为是成功的。如果你不知道你的项目会是什么样子,那么你所有的努力都有可能很快被放弃。

活动创建者Unsplash 上拍摄的照片

一些良好的沟通来自于良好的统计背景,一些来自于强大的批判性思维能力。但是沟通,就其本身而言,是一项关键技能。这就是为什么你经常发现非常聪明的人被征服到办公室某个黑暗、孤立的角落。他们只是不知道如何沟通,结果是失去了他们工作的大部分影响。

具体练习沟通,有话说。再说一遍,网上有很多课程可以让你达到你需要的水平。再说一次,这些课程中最好的并不是特定于数据科学的。

领域专长

我最近无意中听到数据科学家之间关于定价分析的讨论,这是一个我有一些经验的领域。我可以看出对这个问题的商业方面缺乏了解。数据科学家直接进入了关于模型选择的问题,但他们几乎没有掌握他们将面临的实际数据限制。如果没有领域专业知识,他们会走向失败。

仅仅因为你可以种植室内植物,并不意味着你可以经营葡萄园。细微差别很重要。了解你计划解决的问题的细节是至关重要的。

Jaime Casap 在 Unsplash 上拍摄的照片

有时候,我看着学术界,对数据科学的现状感到困惑。在学术界,你从领域专业知识开始,然后应用统计模型。统计建模相对于理论理解是次要的。然而,在数据科学中,我们从统计建模开始,经常忽略理论理解,领域专业知识,这是提出问题的基础。

我认为学术模式是完美的吗?远非如此。我不建议所有的数据科学家都是领域专家。但是,数据科学家确实需要找到一种方法,将领域专业知识融入到他们的工作中。无论是通过在特定的行业领域工作,还是通过寻找能够为项目提供背景知识的商业伙伴。

T 这是我认为数据科学家在软件开发之外的四大障碍。我鼓励所有数据科学家花尽可能多的时间来锻炼这些肌肉,就像他们锻炼编码肌肉一样。其中每一个都蕴含着一生的潜在学习。此外,数据科学实现我们真正抱负的能力取决于其中的每一项。

数据科学从来不意味着成为另一个 IT 部门,被征服到办公室的黑暗角落,很少有人和它说话。数据科学有着远大的抱负。我们希望影响重要的商业决策。我们希望将商业领袖所寻求的所有衡量标准和洞察力展现在世人面前。测量不仅仅是简单的数据库查询。

所以,我们不要像 IT 部门那样说话和行动。让我们把话题拉回到软件开发之外的所有技能上,这些技能对数据科学的成功至关重要。

这 5 个技巧将帮助你在没有经验的情况下获得第一份数据科学实习

原文:https://towardsdatascience.com/these-5-tips-will-help-you-get-your-first-data-science-internship-with-no-previous-experience-a8b225a0bb46

在 2022 年,获得数据科学领域的实习机会变得越来越难,但这 5 个简单的提示将帮助你在任何地方迈出第一步

照片由 Shridhar GuptaUnsplash 拍摄

年复一年,在科技行业找工作似乎越来越难,2022 年也不例外。

数据科学领域也不例外,有如此多年轻、有才华的人被吸引到这个诱人的领域。对于少数实习来说,竞争是激烈的,这意味着做好充分准备进入这个领域变得越来越重要。

幸运的是,这 5 个经过测试且值得信赖的技巧将帮助你击败竞争对手,获得你的第一份没有经验的数据科学实习。你所需要的只是一点耐心、坚持和动力。

1.诚实面对你拥有的技能和你没有的技能。

很自然地,每个人和他们雇用数据科学实习生的狗都在寻找一个可以做所有事情的候选人:他们可以编写干净的代码,他们可以解决现实世界的问题,他们会长时间工作而工资很低,他们会完全熟练并准备好投入工作。

事实上,只有很小一部分候选人能够满足所有这些标准,即使这样,候选人身上的某些东西也不会让他们成为这份工作的合适人选。

信不信由你,人人都有实习机会。

制作一份有吸引力的申请并结束面试的关键是让招聘人员清楚地知道你能做什么和不能做什么。招聘人员的时间有限,他们必须审查申请,安排面试,并希望通过所有这些,招聘到合适的人。通过坦率地说出你拥有和不拥有的技能,你既节省了自己的时间,也节省了招聘人员的时间。没有什么比得到实习机会,然后因为你在面试中不诚实而无法完成要求你做的工作更糟糕的了。

那么,当你没有任何工作经验时,突出你所拥有的技能的最好方法是什么呢?

谈论你参加过的编码挑战,强调你在大学时对项目的贡献,或者描述你自学数据科学的计划。从这些故事中,招聘人员可以了解(或者可以要求你进一步阐述)你使用了什么技术,解决了什么问题,你如何在压力下工作,以及你对学习新技能的感受。试着让这些故事与你申请的公司相关,并解释你在这些场景中的经历如何能很好地转化为你成为团队中有效的一员。

2.准备好为花生工作吧。

你的第一份实习不会带来六位数的薪水和一间可以看到风景的办公室。你的第二次和第三次也不会。

当我毕业后开始第一份工作时,我告诉招聘人员我愿意以低于他们最初给我的工资工作,这让我很震惊。有些人可能会说我做这种事是疯了。然而,我建议降薪,因为我意识到这家公司对一个新的、未经考验的毕业生抱有极大的信心。这种善意的行为得到了回报,因为在过去的一年里,我赢得了他们的信任,并证明了我可以做得很好,值得他们的钱。现在,如果我要求加薪,就不会有冲突或过多的考虑。

这里的关键要点是,记住每个人都必须从某个地方开始,这一点很重要。所有的工作经历都是好的工作经历,不管你的工资是每小时 15 美元还是 100 美元。因此,不要为你在大学之外的第一份有报酬的工作经历而坚持高薪,相反,你应该感激这样一个事实:你得到报酬是为了学到一大堆东西。

3.通过学习一项新的高需求技能来增加你被选中的机会。

申请数据科学实习的每个人都将知道如何使用 Python 编码,将能够使用 Plotly 创建数据可视化,并将能够运行简单的机器学习分析。数据科学实习的竞争越来越激烈,你需要找到一种方法让自己与众不同。

这里的关键是弄清楚你实习的目标是哪个行业,以及哪些技术或技能与该行业相关并为其所需要。

例如,企业部门将寻找能够用数据讲述故事的数据科学家。这意味着能够从不同类型的报告中得出有意义的结论,并将它们结合成一个故事,使用引人注目的可视化方式进行描述。或者,在科学或研发部门,招聘人员将寻找能够运行机器学习模型以从实验数据中发现见解的实习生。

通过选择一个行业并了解他们具体需要什么技能,你可以立即开始调整你的技能组合和简历,以成为他们的完美候选人。

在开始你的第一份简历之前,花几个星期的时间,确保你可以做一些该领域的数据科学家可能每天都会做的常规任务。

4.毕业后与同学和老师保持联系。

关于公开实习机会,你最好的信息来源是毕业后一直保持联系的同学和老师。

如果你和这些类型的人有良好的关系,他们很可能会为你打开不同雇主的大门,甚至可能是你感兴趣的领域。如果你还没有毕业,这是一个关键的提醒,让你和同学建立一些联系,在导师面前为自己树立一个好榜样。如果你在申请实习时需要推荐信,这些人也是很好的候选人。

不幸的是,在寻找实习机会时,人际关系网是必不可少的,但如果只是简单地与老同学或老师联系,就可以变得容易得多。

5.在你第一次申请之前,学会解决现实生活中的问题。

科技行业招聘人员抱怨最多的一个问题是,申请工作的应届毕业生无法解决现实世界中的问题。

这种现象并不是数据科学领域独有的。

虽然大多数训练营或大学会尽最大努力让你解决现实世界的问题,但在高压力的环境中复制这种体验可能很难,因为在这种环境中,当你陷入困境时,你可能没有一只指导手可以给你正确的答案。

因此,在你第一次参加面试之前,你应该学会如何解决现实生活中的问题。这种简单的技能不仅会让你从其他候选人中脱颖而出,而且如果你真的得到了实习机会,它还会让你马上进入状态。

这些现实世界的问题可以和你创造的一样有创意。许多常见的组合项目包括假新闻检测器、气候变化可视化器和面部识别应用程序。或者,许多公司在 Github 或其他数据共享平台上提供对他们一些数据的访问,在那里他们可能会描述他们正在寻找社区数据科学家解决的问题,或者他们可能会让用户发现他们自己的发现。此外,一些公司将举办竞赛,向参与者发布数据,并描述他们希望解决的问题。

无论你决定用什么方法来展示你的现实世界解决问题的技能,确保你的数据科学作品集至少有三个不同类型的问题被解决的例子。这向招聘人员展示了你的能力范围,不怕尝试解决不同类型的问题。

关键要点。

要在没有经验的情况下获得第一份数据科学实习,您需要:

  1. 诚实面对你拥有和没有的技能。
  2. 准备好为低于你理想工资的工作。
  3. 学习一门你的目标行业非常需要的新技能。
  4. 毕业后与同学和老师保持联系。
  5. 在你递交第一份申请之前,先学会解决现实世界中的问题。

随着越来越多的人对这个快节奏、诱人的技术领域感兴趣,数据科学领域的竞争越来越激烈。幸运的是,有一些简单的方法可以帮助你在 2022 年获得第一份数据科学实习。你所需要的只是一点耐心、坚持和动力。

这些是你应该知道的 10 个最好的鲜为人知的 Python 库

原文:https://towardsdatascience.com/these-are-the-10-best-lesser-known-python-libraries-you-should-know-about-9c551842fc39

大蟒

这些是你应该知道和尝试的一些最好的 Python 库

来自 Pexels 的 Andrea Piacquadio 的照片

数据科学的变化比以往任何时候都快,在学习如何提高我们的生产力时,我们需要创建一些捷径,Python 库非常适合这一点。如果你不熟悉我的博客,有一件事你应该知道:我喜欢测试 Python 库,并写关于它们的文章。我尝试了几十个图书馆,有些我比其他人更喜欢。

所以今天,我决定收集我最喜欢的 10 个鲜为人知的图书馆,你可能不知道,但应该知道。所以不多说了,让我们开始吧!

懒惰预测

先说我最喜欢的 Python 库:懒预测。Lazy Predict 是一个低代码的机器学习构建器,允许您用两行代码运行多达 40 个机器学习模型。

您需要准备好数据集,在训练和测试中拆分数据,并运行 Lazy Predict。就是这样。几秒钟后,它将返回几十个模型及其基线结果的列表。

import lazypredict
from lazypredict.Supervised import LazyClassifierclf = LazyClassifier(verbose=0,ignore_warnings=True)
models, predictions = clf.fit(X_train, X_test, y_train, y_test)
models

作者图片

如果你像我一样,你可能会认为这太好了,不像是真的,所以我不得不做一些测试来确认。我决定使用 Scikit-Learn 并测试随机模型,比如 Random Forest,结果非常相似。

我还尝试了逻辑回归,同样,结果非常相似。太神奇了!

作者图片

我写了两篇关于 Lazy Predict 的博客——一篇是关于分类模型的,另一篇是关于回归模型的,其中包括了我对它的想法和代码,这样你就可以自己测试了。

勒克斯

Lux 是另一个你绝对应该尝试的黄金图书馆。它允许您进行探索性的数据分析,并通过一次点击构建数据可视化。你正在学习 Python,想学习更多关于数据探索和数据分析的知识吗?那莱克丝就是你的了。你是一个为你的项目寻找快速见解的专业人士吗?莱克丝也是给你的。

下面是 Lux 的开发商 T1 对此的看法:

“Lux 是一个 Python 库,它通过自动化数据探索过程的某些方面来简化数据科学。Lux 旨在促进更快的数据实验,即使用户不清楚他们在寻找什么。Lux 集成了一个交互式 Jupyter 小工具,允许用户直接在 Jupyter 笔记本上快速浏览大量数据。”

作者图片

如果你想进一步了解莱克丝,我还为此写了一篇博客。

黑色

这里说一些道理吧。你可以成为世界上最好的 Python 程序员,但是如果人们不能理解你写的东西,他们会认为你没有那么好。在 Python 中使用适当的间距受到许多 Python 用户的监督,借口是代码将以相同的方式运行。尽管如此,足够的间距有助于其他人(甚至是编写代码的人)更好地理解代码中发生的事情,而黑色有助于这一点。Black 是一个扩展,它在代码中添加了空格,使代码更加全面。

你安装扩展,把它添加到你的笔记本上,每次你运行一个单元,它就会固定间距。就这么简单!看下图,你会看到间距是如何自动固定的。

作者图片

QuickDA

QuickDA 是一个 Python 库,可以帮我们节省很多时间。它使数据探索和数据可视化变得容易。您可以用很少的代码完成数据探索、数据分析、数据清理和数据可视化。

它将其他超级酷的库,如 Pandas Profiling、Matplotlib、Plotly 等放在同一个库中。如果你正在做一个项目或者只是学习 Python,QuickDA 是你可以尝试的最好的库之一。

作者 GIF

QuickDA 太棒了,我在两个博客中写了关于它的内容。一个侧重于数据清理、数据探索和数据分析,您可以在此找到:

[## 用几行代码完成一个完整的 EDA,节省大量时间

towardsdatascience.com](/save-hours-of-work-doing-a-complete-eda-with-a-few-lines-of-code-45de2e60f257)

另一个关注数据可视化,你可以在这里找到:

[## 如何用一行代码在 Python 中创建数据可视化

towardsdatascience.com](/how-to-create-data-visualizations-in-python-with-one-line-of-code-8cda1044fe69)

PyForest

PyForest 是我写的第一批 Python 库之一。我发现 PyForest 时,我正在用多个笔记本进行一个大型项目,我总是忘记导入我必须使用的许多库。PyForest 在这方面有所帮助。您可以用一行代码将 40 个库“导入”到您的项目中。请注意,我在引号中使用 import,因为 PyForest 只会在您使用它时导入库。否则,它不会被添加到您的 Jupyter 笔记本中。

你需要做的就是导入 PyForest,并在你的笔记本中调用它。嘣!如果你需要的话,所有最流行的库都可以使用。请参见下面可供使用的 Python 库列表。

作者图片

你可以在这里找到我的博客:

Bamboolib,米托和 D-Tale

Bamboolib、米托和 D-Tale 不是一个图书馆。它们实际上是三个不同的库。我将它们放在一起的原因是它们有一个相似的概念:通过一个看起来更像电子表格的图形用户界面,帮助人们完成诸如数据清理、数据探索、数据可视化等任务。

对于学习者来说,它们非常棒,因为除了允许人们通过一两次点击来完成需要多行代码的任务之外,它们还会给你代码,这样你就可以看到每个任务是如何完成的。

哪一个是我最喜欢的?我看不出来!虽然他们有相似的概念,但他们也有独特的功能。他们中的一些人比其他人拥有更多。还有,我觉得有些比较好用,所以我推荐你自己试试,自己下结论。我可以补充一点说明,Bamboolib 有免费版和付费版。我只测试了免费版。

如果你想了解更多,我为这三个图书馆写了博客。

Bamboolib

这里有一个小 GIF 展示了 Bamboolib 的样子。有免费版和付费版;我只测试了免费版本,因为我们有其他类似的选择,我不认为我会为此付费。

作者 GIF

这是我关于 Bamboolib 的博客

米托

在这三个博客中,我关于米托的博客可能是我最喜欢的,但它并不是一成不变的。我认为他们的 GUI 是这三个库中最好的,但是缺少 Bamboolib 的一些功能。我听说他们总是包括更多的功能,所以这可能会改变。

作者 GIF

这是我关于米托的博客:

数字童话

与米托和 Bamboolib 相比,D-Tale 具有更复杂的特性,但它不像它的兄弟姐妹那样直观。开发人员做了出色的工作,但有时会令人困惑,而且在 Jupyter Notebook 中使用时有点慢。幸运的是,您可以在浏览器中打开另一个标签,继续您的工作。

作者 GIF

PyCaret

PyCaret 是一个用 Python 编写的开源、低代码的机器学习库,可以自动化机器学习工作流。你需要有一个数据集来预测,PyCaret 会做探索性数据分析、数据预处理、模型训练、模型可解释性、MLOps 等任务。与 LazyPredict 类似,它也可以用很少的几行代码运行多个机器学习模型。

作者 GIF

如果你想在测试之前看一下,他们还有一个漂亮的网站

几个月前我写过这个。是时候写一篇关于它的新博客了,因为他们增加了更多的功能,但是你可以在这里了解 PyCaret:

SweetViz

最后但同样重要的是,我们有超级酷的 SweetViz。SweetViz 创建了一个 HTML 文件,您可以通过两行代码获得完整的探索性数据分析报告。我在工作环境中用过,所有同事都印象深刻。

以下是它的开发者对此的评论:

“Sweetviz 是一个开源 Python 库,只需两行代码即可为 kickstart EDA(探索性数据分析)生成漂亮的高密度可视化效果。输出是一个完全独立的 HTML 应用程序。

该系统围绕快速可视化目标值和比较数据集而构建。它的目标是帮助快速分析目标特征、训练与测试数据以及其他类似的数据表征任务。"

我在这篇博客中已经谈到了 Lux,那么为什么还要测试 SweetViz 呢?因为 SweetViz 有很多 Lux 没有的功能,反之亦然。他们之间我没有最喜欢的,因为他们完成相似但不同的任务。

作者 GIF

几个月前我写了一篇关于它的博客,如果你想了解更多的话:

</5-python-libraries-that-you-dont-know-but-you-should-fd6f810773a7> [## 5 个你不知道但应该知道的 Python 库

towardsdatascience.com](/5-python-libraries-that-you-dont-know-but-you-should-fd6f810773a7)

最后的想法

今天我浏览了一些我一直最喜欢的 Python 库。我真诚地相信每个人都应该了解它们,即使我们不会每天都使用它们。我每周都收到无数的消息,人们谈论这些图书馆如何帮助他们学习和提高工作效率,所以我决定把它们都放在同一个博客里。

数据科学在不断变化,我们每天都需要学习如何提高工作环境中的效率。了解一些可以节省您的编码时间的库是提高您的生产力并使我们更具竞争力的一个很好的方法。我建议你自己尝试一下,然后得出你的结论。如果你有,让我知道你的想法。编码快乐!

这些是您创建一个好的数据科学产品需要采取的步骤

原文:https://towardsdatascience.com/these-are-the-steps-you-need-to-take-to-create-a-good-data-science-product-697b22d335c5

夏嫣·米克尔森在 Unsplash 上拍摄的照片

意见

从问题到生产

几年前,我为一家公司开发了一个机器学习应用程序。它有预测,对预测的解释,一个结合了许多数据源的仪表板等等。然后工具上线了。而且……几乎没怎么用。哪里出了问题?我对此一无所知:我每周都与业务部门联系,该工具与现有系统紧密集成,并且我仔细倾听用户的意愿。

事后看来,我认为我本应该以不同的方式做很多事情。这个工具相当复杂,而且不直观。我认为我们等了太久才上线,应该让更多的商业人士参与进来。这让我想到一个重要的问题:应用机器学习解决商业问题的正确方式是什么?本文将指导您完成基本步骤。你一开始就需要回答的问题,数据问题,建模和操作模型的技巧。我希望这能防止你犯和我一样的错误!

哎呀。照片由莎拉·基利安Unsplash 上拍摄

以下是我将在本文中解释的步骤概述:

  • 第一步。抓住问题的核心
  • 第二步。理解并了解数据
  • 第三步。数据处理和特征工程
  • 第四步。对数据建模
  • 第五步。操作模型
  • 第六步。改进和更新

并不总是从第一步开始,到第六步结束。有时候需要迭代。在步骤 4、5 或 6 中,您可以发现改进模型的方法,例如在执行错误分析之后。您可以返回到上一步,例如创建新要素(步骤 3)或收集更多数据(步骤 2)。

第一步。抓住问题的核心

第一步可能是最重要的一步。如果你真的想开发一个好的产品,你应该抓住问题的核心。你应该深入材料,与利益相关者交谈,问正确的问题,思考技术需求。这可能需要一些时间,但最终您会节省时间,因为问题的范围变小了。你预先知道哪里可能会出现障碍。

你可以系统地处理这一步。为了简单起见,我把这个步骤分成了六个子部分。这些部分是价值和目的、可能的解决方案、人员、技术方面、过程和立法。让我们穿过它们。

价值和目的

产品的目标是什么?它解决什么问题?有时候实际问题并不是问题背后的真正问题。为了回答真正的问题,试着理解商业动机并测试你的假设。如何衡量成功?对最终用户有什么好处?深入当前流程(如果存在)可能会有所帮助。这可以给你一个基准性能,并有助于理解背景。

谈到性能,现在是建立性能指标的时候了。如果可能的话,使用单一的度量标准,因为这样可以更容易地根据性能对模型进行排序。尝试找到一个简单的、可观察的度量标准,它易于向不太懂技术的人解释,并且涵盖了问题的目标。

另一个有趣的问题是:还有其他人可以从产品中受益吗?这有助于说服人们,使产品更加有趣。

可能的解决方案

定义了产品的价值和用途之后,你就可以开始思考可能的解决方案了。你可以做一些研究:阅读处理类似问题的文献,或者和团队组织一次头脑风暴会议。

这一部分并不意味着完全解决问题,但它将在实际解决阶段提供指导。也许你会发现机器学习不是必要的,但是基于规则的方法也可能有效。

相关人员包括用户、利益相关者、赞助商和开发团队。开发团队是否涵盖了所有需要的方面?你有足够的技术专长来成功完成这个项目吗?如果出现障碍,你应该去哪里?

与用户讨论他们如何测试产品。让他们参与进来,越快越好。在早期阶段,改变和调整更容易:如果你很早就收到反馈,你可以马上实施。确保您定期与所有相关人员交谈,这将引导我们进入流程。

过程

流程是如何管理的?定期更新用户和利益相关者是最佳实践。当你按照敏捷原则工作时,例如使用 scrum,很容易将标准会议(起立,回顾,回顾)固定在特定的时间段。有可能流程不固定,比如因为你在一家小公司工作。至少每隔一周向相关人员提供一次更新。尝试快速交付产品的第一个版本,以便您的最终用户可以测试产品并提供反馈。

技术方面

该说数据了!数据从哪里来?它对开发团队来说是可访问的和可用的吗?什么时候更新?除了数据之外,还要考虑其他技术方面,比如部署、架构、基础设施、维护以及将要使用的工具。

如果解决方案将与其他系统集成,不要有过于乐观的规划。构建一个独立的产品更容易,但风险是它会被更少地使用。延迟和吞吐量也是需要考虑的事情。

法规

没那么有趣,但同样重要。你应该考虑法律或道德方面的问题吗?考虑监管问题以及如何安排安全措施。您可能还想确定错误预测的影响。你如何防止人们因为你的模型的预测而受到伤害?

“抓住问题的核心”的六个部分。图片作者。

问正确的问题,使问题的范围变小,会节省你以后的时间!如果你对上述所有问题都没有一个(深入的)答案,那就不是问题。问题的范围和复杂程度各不相同。完成这一步最简单的方法是与相关人员协商,填写机器学习用例画布。网上有许多可用的用例画布,你可以根据上面描述的部分,尝试找到一个符合你需要的或者为你自己创建一个。

第二步。理解并了解数据

下一步就是数据了。数据源、理解数据和数据探索。

数据源

您使用的数据源很重要,因为数据质量越好,模型的表现就越好。你有足够的数据吗?还是有必要通过网络搜集、数据扩充或购买数据来获取更多信息?

有时没有可用的数据模式或数据描述。如果是这样的话,你应该找个人问问题。没有任何解释或描述,很难(或不可能)理解表格和列的含义。

探索性数据分析

现在是时候动手了,从探索性的数据分析开始。创建汇总统计数据并绘制分布图、直方图、条形图和计数图。尝试找出变量和目标之间的第一个关系,发现具有预测价值的特征,例如相关矩阵。没有差异或有许多空值的要素可以标记为在下一步中移除。

年龄(特性)和功能(目标)之间有明确关系的简易条形图。图片作者。

第三步。数据处理和特征工程

来自探索性数据分析的见解被输入到下一步:数据处理和特征工程。

数据处理

在数据处理步骤中,您丢弃不相关的数据,清除丢失的值,删除重复的行,并且检测处理异常值。数据中的错误也需要解决。

特征工程

然后,您可以开始创建特征。这取决于什么样的功能最有效。量化变量的一些基本建议是变换或宁滨。如果数据集有大量的维度,像 UMAP 或主成分分析这样的降维可能是有效的。对于分类变量,您可以尝试一种热编码或散列。

当您处理非结构化数据时,这一步会稍微复杂一些。对于文本数据,你需要注意词干、词汇化、过滤、词袋、n 元语法和单词嵌入。对于图像,您需要处理噪声、色阶、增强图像或检测形状。

图像处理可能很耗时。图片作者。

第四步。对数据建模

对处理后的数据尝试不同的模型。模型的类型取决于多种因素,如训练和预测速度、数据的数量和类型以及要素的类型。一些项目需要一个可解释的模型,而对于其他项目,性能更重要。如果你想使用一个很难解释但可解释性很重要的模型,这里有一些你可以使用的方法。

在模型评估阶段,您可以使用训练、验证和测试分割和/或交叉验证。调整超参数并比较不同的模型。发现不同功能的重要性,并检查(如有必要,与业务部门一起)这些功能是否有意义。调整模型以避免过度拟合,并确保处理数据不平衡。在完整数据集上训练最终模型。

与团队和利益相关者分享您的结果和绩效。在此步骤中,您可以决定继续操作模型,或者返回到数据处理步骤提取新要素。

排列特征重要性,解释机器学习模型的方法之一。图片作者。

第五步。操作模型

部署过程称为 MLOps。您可以使用不同的工具,如 MLflowAirflow 或基于云的解决方案。决定你是否可以批量预测或者是否有必要实时预测。这决定了您是否需要分别关注高吞吐量或延迟。混合方法也是可能的。

当性能下降时,应该有一个用新数据自动重新训练模型的过程。注意数据漂移,如果模型真的很重要,了解数据如何变化也很有趣,那么数据漂移过程可能是一个很好的补充。

用机器学习检测协变量漂移的方法。点击放大。图片作者。

第六步。改进和更新

如果你能说:‘我的模型是活的,让我们从新的开始吧!’不幸的是,在现实生活中,大多数时候事情并不是这样的。您应该跟踪模型和业务目标,以确保您的模型保持其应有的性能。您可以执行误差分析来分析错误的预测。

误差分析。照片由Cookie PomUnsplash 上拍摄

摘要

创造一个好的数据科学产品可能很难。除了建模,你还必须处理许多事情,比如用户和利益相关者、数据、部署和维护。本文通过解释机器学习生命周期各阶段的最佳实践来帮助您。

首先,抓住问题的核心。现在还不需要解决它,但是要确保你得到了所有你需要的信息来说服自己可以解决它,并且这个案子是值得的。这一步包括聚集合适的人员,建立产品目标和成功的度量,基线性能,以及技术方面的概述,如数据源和部署。

当你真正理解了问题,你就可以钻研数据了。从探索性的数据分析开始,然后是数据处理和特征工程。然后,是时候对数据建模了。你可能会在数据源、特征工程和建模之间来回切换。例如当模型的性能不够好时。

如果模型的结果令人满意,您就可以部署您的模型了。记录绩效,确保你有一个再培训的过程。如有必要,继续改进模型,例如通过误差分析。

相关文章

https://medium.com/bigdatarepublic/detecting-data-drift-with-machine-learning-adb177544312

时间序列预测的 Theta 模型

原文:https://towardsdatascience.com/theta-model-for-time-series-forecasting-642ad1d00358

关于如何在 Python 中应用 Theta 模型进行时间序列预测的实践教程

汉斯·雷尼尔斯在 Unsplash 拍摄的照片

当谈到时间序列预测时,我们通常会将注意力转向 SARIMAX 系列或指数平滑中的模型。然而,有一种预测技术很少被提及:Theta 模型。

尽管简单,Theta 模型可以产生精确的预测。它在最大的学术时间序列预测竞赛 M-3 竞赛中表现如此出色,以至于在随后的几年中成为一个基准。

在这篇文章中,我们首先从理论的角度探索模型的内部工作原理。然后,我们将 Theta 模型应用于预测实践,并将其性能与 SARIMA 模型和指数平滑模型进行比较。当然,所有的代码都是 Python 的。

我们开始吧!

用 Python 中我的 免费时间序列小抄 学习最新的时间序列分析技术!获得统计和深度学习技术的实现,全部在 Python 和 TensorFlow 中!

Theta 模型是如何工作的

Theta 模型基本上依赖于分解。我们知道时间序列可以分解成三个部分:趋势部分、季节部分和残差部分。

因此,合理的方法是将一个序列分解成它的每个组成部分,预测每个组成部分的未来,然后组合每个组成部分的预测来创建您的最终预测。

不幸的是,这在实践中行不通,特别是因为很难分离残差并预测它们。

所以 Theta 模型是这个想法的一个发展,但是它依赖于将序列分解成一个长期部分和一个短期部分。

在形式上,Theta 模型基于修改时间序列的局部曲率的概念。这个修改由一个名为 theta 的参数管理(因此得名 theta 模型)。这种修改应用于系列的第二个差异,这意味着它是差异两次。

θ在 0 和 1 之间时,系列“放气”。这意味着短期波动较小,我们强调长期影响。当θ达到 0 时,数列转换为线性回归线。这种行为如下图所示。

当θ在 0 和 1 之间时级数的收缩。注意,当它等于 0 时,我们得到一条线性回归线。图片由 V. Assimakopoulos,K. Nikolopoulos 从theta 模型:预测的分解方法

或者,当θ大于 1 时,则短期波动被放大,因此我们强调短期效应。在那种情况下,我们也说这个系列是“膨胀”的。这种行为如下图所示。

当θ大于 1 时级数的膨胀。注意短期波动是如何被放大的。来自的 V. Assimakopoulos,K. Nikolopoulos 的图片 theta 模型:预测的分解方法

对于每一个θ值,我们说我们创建了一条“θ线”。理论上,我们可以生成尽可能多的θ线,预测每一条线的未来,然后将它们组合起来进行最终预测。

在实践中,我们经常只使用两条θ线:一条是θ为 0,一条是θ为 2。第一条 theta 线( theta = 0)给出了数列的趋势信息,而第二条 theta 线( theta = 2)放大了短期波动。然后,我们预测每一行,并结合预测。

季节性呢?

Theta 模型的程序适用于非季节性数据。但是,它仍然可以用于季节性数据,因为季节性可以很容易地被删除,并在结束时再次添加。

因此,Theta 模型的实现遵循以下步骤:

  1. 去除季节性:进行季节性测试。如果检测到季节性,则通过分解去除。
  2. 分解成两条θ线:我们生成两条θ线;一个是θ= 0,表示为 Z(0),一个是θ= 2,表示为 Z(2)。
  3. 外推:我们将两条θ线外推至未来。Z(0)是使用线性回归外推的,因为它本身是线性回归线。使用简单的指数平滑外推 Z(2)。
  4. 组合:我们组合两条θ线的外推,以获得一条预测线。
  5. 把季节性加回来:如果季节性在第一步中被移除,我们在最后把它加回来。

现在我们了解了 Theta 模型的工作原理,让我们在预测练习中应用它!

使用 Theta 模型进行预测

在这个练习中,我们将预测从 1958 年 3 月到 2001 年 12 月在莫纳罗亚天文台记录的二氧化碳浓度。数据每周都被记录下来。

在任何时候,都可以在 GitHub 上随意查阅源代码。

第一步当然是导入必要的库并加载数据。

import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt# Load the data
df = sm.datasets.co2.load_pandas().data
df.head()

然后我们可以可视化我们的数据集。结果如下图所示。

fig, ax = plt.subplots()ax.plot(df['co2'])
ax.set_xlabel('Time')
ax.set_ylabel('CO2 concentration (ppmw)')fig.autofmt_xdate()
plt.tight_layout()

从 1958 年 3 月到 2001 年 12 月的每周 CO2 浓度。请注意,我们在数据集的开头有一些缺失的值。图片由作者提供。

查看上图,我们注意到三个重要元素:

  1. 我们的系列有一个积极的趋势,因为二氧化碳浓度随着时间的推移而增加。
  2. 我们的系列具有年度季节性,因为冬季的二氧化碳含量高于夏季。
  3. 我们在数据集的开头有一些缺失的值。

所以,让我们去掉缺失的值。这里,我们简单地使用两个已知点来插值缺失值。

df = df.interpolate()

这就解决了任何缺失的值,我们准备好继续进行预测了。

预测

对于这种情况,我们为测试集保留最近两年的观察结果。由于我们有周数据,并且一年有 52 周,这意味着最后 104 个点是用于测试集的,其余的是用于训练的。

train = df[:-104]
test = df[-104:]

然后,我们必须设定一个预测范围。在这里,我们将其设置为 52 周,或一年。这意味着我们想要建立一个模型来预测未来 52 周的二氧化碳浓度。

由于我们的测试集有 104 周的数据,我们将执行滚动预测。这意味着我们在训练集上训练模型,预测未来 52 周,然后在更新的训练集上重新训练模型,该训练集包括另外 52 周的数据,以预测未来 52 周。

用文字描述滚动预测是相当混乱的,所以这里有一个图表来形象化整个过程。

可视化滚动预测。在第一遍中,我们预测了测试集的前 52 周。在第二遍中,我们预测了测试集的最后 52 周,但是使用了更新的训练集。图片由作者提供。

从上图中,我们可以看到我们预测了 104 周的整个测试集,但是一次预测了 52 周。这样,我们就可以在做出新的预测之前模拟收集新数据并添加到训练集的过程。

在继续之前,我们还需要选择一个基线模型。在这里,由于我们有季节性数据,一个合理的基线将是简单地预测已知的最后一个季节。因为我们有每年的季节性,并且每年有 52 次观察,这相当于在未来重复最后的 52 个数据点。

有了所有这些设置,我们现在可以构建我们的函数来进行滚动预测。

from statsmodels.tsa.forecasting.theta import ThetaModeldef rolling_forecast(df: pd.DataFrame, train_len: int, horizon: int, window: int, method: str) -> list:

    total_len = train_len + horizon
    end_idx = train_lenif method == 'last_season':
        pred_last_season = []

        for i in range(train_len, total_len, window):
            last_season = df[:i].iloc[-window:].values
            pred_last_season.extend(last_season)

        return pred_last_season

    elif method == 'theta':
        pred_theta = []

        for i in range(train_len, total_len, window):
            tm = ThetaModel(endog=df[:i], period=52)
            res = tm.fit()
            predictions = res.forecast(window)
            pred_theta.extend(predictions)

        print(res.summary()) #Optionalreturn pred_theta

从上面可以看出,我们的函数需要一个时间序列数据集、训练集的初始长度、测试集的长度以及一个窗口或一个范围。

训练集和测试集的长度很容易从我们之前进行的划分中恢复,我们的窗口将是 52 周,如前所述。

TRAIN_LEN = len(train)
HORIZON = len(test)
WINDOW = 52

我们现在准备预测我们的时间序列,使用基线模型和 Theta 模型。

test = test.copy()test.loc[:, 'pred_last_season'] = pred_last_season
test.loc[:, 'pred_theta'] = pred_thetatest.head()

添加三重指数平滑

为了便于比较,让我们在这种情况下也应用三重指数平滑法。这样,我们可以将 Theta 模型的性能与基线和另一个相对简单的模型进行比较。

为此,我们必须更新我们的 rolling_forecast 函数来实现三重指数平滑。

from statsmodels.tsa.holtwinters import ExponentialSmoothingdef rolling_forecast(df: pd.DataFrame, train_len: int, horizon: int, window: int, method: str) -> list:

    total_len = train_len + horizon
    end_idx = train_lenif method == 'last_season':
        pred_last_season = []

        for i in range(train_len, total_len, window):
            last_season = df[:i].iloc[-window:].values
            pred_last_season.extend(last_season)

        return pred_last_season

    elif method == 'theta':
        pred_theta = []

        for i in range(train_len, total_len, window):
            tm = ThetaModel(endog=df[:i], period=52)
            res = tm.fit()
            predictions = res.forecast(window)
            pred_theta.extend(predictions)return pred_theta

    elif method == 'tes':
        pred_tes = []

        for i in range(train_len, total_len, window):
            tes = ExponentialSmoothing(
                df[:i],
                trend='add',
                seasonal='add',
                seasonal_periods=52,
                initialization_method='estimated'
            ).fit()

            predictions = tes.forecast(window)
            pred_tes.extend(predictions)return pred_tes

然后,我们简单地运行它来添加来自三重指数平滑的预测。

pred_tes = rolling_forecast(df, TRAIN_LEN, HORIZON, WINDOW, 'tes')test.loc[:, 'pred_tes'] = pred_testest.head()

估价

现在,我们已经有了来自基线、Theta 模型和三重指数平滑的预测,让我们评估每一个并确定冠军模型。

这里,我们使用平均绝对百分比误差,或 MAPE,来评估我们的模型。

在实际测量性能之前,让我们首先将模型的预测与实际值进行对比。结果如下图所示。

fig, ax = plt.subplots()ax.plot(df['co2'])
ax.plot(test['co2'], 'b-', label='actual')
ax.plot(test['pred_last_season'], 'r:', label='baseline')
ax.plot(test['pred_theta'], 'g-.', label='Theta')
ax.plot(test['pred_tes'], 'k--', label='TES')ax.set_xlabel('Time')
ax.set_ylabel('CO2 concentration (ppmv)')
ax.axvspan('2000-01-08', '2001-12-29', color='#808080', alpha=0.2)ax.legend(loc='best')ax.set_xlim('1998-03-07', '2001-12-29')fig.autofmt_xdate()
plt.tight_layout()

我们可以看到,从基线得到的预测值与实际值相差最远。否则,三重指数平滑似乎更接近实际值。图片由作者提供。

看上面的图,我们可以看到基线的预测值与实际值相差最远。我们还看到来自三重指数平滑的线(黑色虚线)似乎最接近实际值。

让我们通过实际计算 MAPE 来验证一下。

def mape(y_true, y_pred):
    return round(np.mean(np.abs((y_true - y_pred) / y_true)) * 100, 2)mape_baseline = mape(test['co2'], test['pred_last_season'])
mape_theta = mape(test['co2'], test['pred_theta'])
mape_tes = mape(test['co2'], test['pred_tes'])

注意,在写这篇文章的时候,MAPE 还没有在 scikit-learn 的稳定版本中实现,但是它很快就要实现了!

最后,让我们用柱状图直观地展示每个模型的 MAPE。

fig, ax = plt.subplots()x = ['Baseline', 'Theta', 'TES']
y = [mape_baseline, mape_theta, mape_tes]ax.bar(x, y, width=0.4)
ax.set_xlabel('Exponential smoothing models')
ax.set_ylabel('MAPE (%)')
ax.set_ylim(0, 1)for index, value in enumerate(y):
    plt.text(x=index, y=value + 0.05, s=str(value), ha='center')

plt.tight_layout()

在这里,三重指数平滑显然是赢家,因为它实现了最低的 MAPE。图片由作者提供。

看上面的图,我们可以看到我们的冠军模型是三重指数平滑,因为它实现了 0.12%的 MAPE。

至于 Theta 模型,它优于基线,但不如三重指数平滑。

结论

虽然 Theta 模型在这种特定情况下不是冠军模型,但它仍然是一个很好的预测方法,可以放在您的工具箱中。

它的分解方法使它成为预测时间序列的一种灵活而快速的方法。至少,它可以作为比较其他更复杂模型的坚实基准。

本文到此为止!祝贺你坚持到最后,我希望你喜欢它并且学到了新的东西!

一定要下载我用 Python 写的免费时间序列预测小抄,涵盖统计和深度学习模型!

干杯🍺

资源

Grzegorz Dudek — 使用 Theta 方法的短期负荷预测

罗布·j·海德曼,叶鬼·比拉— 揭开西塔方法的面纱

动词 (verb 的缩写)Assimakopoulos,k . Nikolopoulos—theta 模型:预测的分解方法

K.Nikolopoulos,V. Assimakopoulos,N. Bougioukos,a . Litsa—Theta 模型:供应链规划的重要预测工具

我希望在组建数据团队时就知道的事情

原文:https://towardsdatascience.com/things-i-wish-i-knew-when-i-was-building-a-data-team-efcb43591204

如何根据您公司的数据成熟度阶段为成功的数据实践奠定正确的基础

资料来源:Randy Fath ,Unsplash

在之前的一次经历中,我被要求建立一个数据团队。这项任务对我来说是全新的,所以我做了任何人在我的情况下都会做的事情:我谷歌了一下。我找到了许多关于这个主题的资源,但是大多数的博客和文章主要集中在更技术性的方面。虽然有些信息很有帮助,但我仍然不知道从哪里开始。

这种挫败感是我写这篇文章的动机。这里的目的是就关注什么、如何确定优先级以及其他考虑事项提供指导,这些将有助于组织的现代领导者向数据成熟度迈出第一步。

一、设定正确的目标

数据团队的目标应该在实施之前设定。它们应该包括来自不同业务部门(工程、产品、营销、财务等)的关键利益相关者。),因为许多人最终将成为数据产品的消费者。

数据团队的目标反映公司的数据素养水平也至关重要。考虑到您正在从零开始建立数据团队,您的公司可能正处于数据成熟的早期阶段。稍后将详细介绍。

数据团队的目标通常可以分为以下几类:

  • 试探性:公司有一些数据,但你不知道如何利用这些数据,因为你不知道去哪里找,也不知道是否应该信任这些数据。
  • 分析:你的领导层确信,数据驱动是做出更好商业决策的关键。可能已经有人尝试在 Microsoft Excel 或其他工具中进行分析,但是您希望将数据使用提升到一个新的水平。
  • 创新:当你已经有了做决策的必要洞察,你认为 AI/ML 会帮你创造下一个差异化优势;所以,你要开始往那个方向投资。

二。定义组织结构

现在您已经定义了业务目标,您应该从公司组织的角度决定数据团队的位置。这一步至关重要,因为它将为避免各自为政和所有权不明奠定适当的基础。一些流行的设置:

  • 在工程部门:在一些像 LinkedIn 这样的组织中,数据团队是工程部门的一部分。在过去看到过类似的设置,我认为数据和工程团队应该作为合作伙伴,因此,有单独的报告线。在两者之间创建报告动态可能会危及协作的效率,并使数据团队远离业务。
  • 在产品内:当产品与数据紧密相关,并且组织主要依赖数据进行特性测试和其他产品分析用例时,这是有意义的。
  • 在业务实体中:财务或营销,例如,这通常是小型数据团队的情况,其范围和目标仅与该特定团队相关(不建议大型公司使用)。
  • 作为独立实体:直接向首席执行官或首席财务官报告。这对于一个组织来说是有意义的,该组织已经:a .达到了良好的数据成熟度和公司范围的数据素养水平,b .跨不同业务功能的各种定义良好的用例,并且正在考虑迎合各种业务领域的“数据作为产品”类型的方法。

三世。选择合适的数据堆栈和数据平台。

有了为您的数据团队定义的目标和组织报告,您现在需要考虑几个方面:公司的数据成熟度阶段、数据堆栈和数据平台。

1。数据成熟度阶段

  • 基础:这适用于任何刚开始接触数据并希望通过分析工具从数据源中获取洞察力的组织。团队的规模可以从 1 人(通常是创始人之一或数据工程雇员)到 1-5 人的小型数据团队不等。
  • 中间:数据用于各种用例:产品、增长、业务监控等。您已经有了数据堆栈的初始版本,并且您的数据团队正在成长。
  • 高级:数据是贵公司战略和决策的核心。每个部门在日常运营中都依赖于数据;用例多种多样,从运营分析到在产品差异化和目标设定中对人工智能和人工智能的高级利用。

2。数据栈 现代数据栈(MDS)是一个工具和技术的集合,帮助企业收集、转换、存储和利用数据进行分析和 ML 用例。现代数据堆栈基于云、模块化,通常包括以下几层:

  • 集成,ETL/ELT: 数据从源传输(在某些情况下,进行规范化和转换)到存储的地方。想想像 Fivetran、Stitch 和 Airbyte 这样的工具。
  • 存储:数据存储的地方,一般是云数据仓库或者数据湖。想想像雪花、数据块和 BigQuery 这样的工具。
  • 转换&建模:将原始数据转换成便于运营分析访问的格式、形状和结构。想想像 Dbt 和 Dataform 这样的工具。
  • 商业智能/数据可视化:数据被消费的地方,通常是在仪表板、图表或表格中,并可供业务用户访问。想想像 Tableau、Looker 和 Mode 这样的工具。
  • 工作流程编排:通过允许用户创建、调度和监控数据管道,将所有这些组件结合在一起的“粘合剂”。
  • 反向 ETL: a 反向 ETL 是将数据从数据仓库转移到其他基于云的业务应用程序(CRM、营销、财务工具等)。)因此它可以用于分析目的。想想像 Hightouch 和 Census 这样的工具。
  • 数据可观察性 : 这是“栈顶”层,确保数据在整个栈中可靠可信。作为首席执行官和 Sifflet 的联合创始人,我对此有偏见。

3。
数据平台
一般来说,数据平台可以是:

  • 集中化:这可以说是最容易实现的团队结构,也是那些开始向数据驱动转变的公司的必经之路。团队和架构都集中在这里。
  • 混合:该公司正处于一个成长阶段,多个团队每天都利用数据来做出决策。数据被视为一种产品,虽然数据团队是集中的,但在组织内进一步民主化数据的努力已经完成。在这种情况下,可能存在“专家”,通常是每个业务职能部门内的数据分析师或分析工程师,他们拥有足够的技术技能来与数据团队沟通和自主工作,同时还具有业务背景。
  • 完全去中心化:该公司在其数据平台中完全采用去中心化,利用来自数据网格等概念的原则。数据团队(尽管在这种情况下,传统团队的概念不太相关)反映了数据无处不在的本质。每个业务领域都可以利用数据平台的模块化和面向自助服务的特性来开启最先进的数据驱动案例。想想微服务,但对于数据平台来说,领域专业知识符合数据及其基础设施的民主化。

资料来源:Salma Bakouk

四世。招聘部分

现在让我们把重点放在人力资源方面。数据团队有三种核心技术能力:数据工程、数据分析和数据科学。这些角色的其他变化或组合导致了分析工程师、ML 工程师、MLOps、BI 开发人员等角色的出现。在数据更成熟的组织中,类似 DataOps、MLOps、DataSecOps 等职位。,经常受到追捧。

让我们详细介绍一下这三个突出的角色。

  • 数据工程师:负责创建、扩展和维护支持和产生数据的基础设施。需要的技能:云技术、数据库、ETL、Java、Python。由 Cord 提供更多信息。co
    Maxime Beauchemin 写了一系列关于数据工程作为职业道路的伟大文章,值得一读:数据工程师的崛起数据工程师的衰落
  • 数据科学家:负责使用高级统计学、数据建模和 ML 技术创建、维护和扩展数据科学模型。找的技能:统计分析&计算,编程(Python,SQL,R),机器学习,数据扯皮。拉希·德赛对此有更多报道。
  • 数据分析师:负责将数据转化为洞察。数据分析师可以将最终业务需求与源数据联系起来,同时评估所需的转换和争论。要寻找的技能:SQL,商业理解(通常是低调的,但却是必不可少的),商业智能知识,创造力。WINC 的分析工程师 Madison Schott 发表了一系列关于适用于数据分析的分析工程最佳实践的文章

你应该先雇佣谁?

如果你刚刚开始,我建议你遵循“少即是多”的原则。从小处着手,支持“完整数据堆栈”功能,并牢记您的数据团队的目标;随着需求的发展,你可以一次增加一名成员。

在早期阶段,数据团队倾向于专注于实验和初始概念验证,而不是将一个大项目投入生产。在这种情况下,数据分析师或具有分析技能(Python、SQL 等)的数据工程师。)作为第一次雇佣会更有价值。这个人可以在第一次 POC 中与软件工程师一起工作,这将有助于确定第一个管道需求。这为第二次雇用铺平了道路,第二次雇用应该是具有更多数据和架构工程技能的人,以继续构建平台并做出适当的基础架构选择。此后,应根据正在进行的项目进行进一步的招聘。

有哪些需要寻找的软技能?

评估数据专业人员时,软技能至关重要。默认情况下,数据实践是跨职能的;数据团队的核心任务是帮助企业从数据中获取最大价值,并成为数据驱动型企业。因此,靠近商业是必不可少的。另一方面,尤其是在数据成熟的早期阶段,数据团队还与 IT 和软件工程密切合作,以确保数据基础设施的稳定性和可持续性。一名优秀的数据员工应具备以下技能:

  • 沟通:候选人需要是一个清晰高效的沟通者,有能力适应技术和非技术受众。
  • 业务知识:这对于确保顺利采用数据计划、帮助数据消费者将数据转化为可操作的见解,以及知道优先处理什么和何时处理至关重要。
  • 道德和安全第一的心态:在早期阶段,您的流程可能仍然很脆弱,缺乏数据隐私和安全性。合适的员工将确保研究和实施最佳实践,从而为数据保护和遵守数据法规(即使是在早期阶段)奠定适当的基础。
  • 灵活性和适应性:数据团队需要能够适应贵公司的发展和可能由此产生的业务考虑,同时还要适应数据基础设施和工具行业的快节奏。

V .需要牢记的事情

  • 专注于业务:大多数公司的业务不是为了分析而分析,他们通过其他方式增长,而分析是为了增长服务的。
  • 不要低估内部宣传 —您的组织需要强有力的管理层认同和数据领导力来培育数据文化。
  • 数据领导至关重要避免数据组织分裂,业务部门无法从数据团队获得所需的帮助,因此不得不雇佣其他分析师。
  • 传达数据团队的期望。业务部门领导会对与数据团队合作感到非常兴奋。然而,由于资源在一开始是有限的,所以从一开始就设定正确的期望值是至关重要的。
  • 品牌是关键。创建数据团队的一致形象将影响组织的其他部分如何看待数据团队并与之交互。
  • 不要低估技术上的缺陷:了解团队存在之前的过去。许多内部快捷方式(非常长的 SQL 查询、电子表格等。)是作为一种临时解决方案来完成的。通过展示有价值的例子和案例研究来证明改变组织内现有数据实践的重要性是至关重要的。如果团队内部需要恢复信任,这一点尤为重要。
  • 定义清晰的成功 KPI:一般来说,这些 KPI 需要支持 ROI,而不是直接影响它。

结论

建立数据实践不仅仅是做出技术选择;您可能必须从第一次迭代开始,并期望它随着您的业务增长而发展。虽然没有放之四海而皆准的方法,但我从自己的经验以及与数据领导者围绕该主题的多次对话中收集了一些最佳实践。从“为什么”开始,通过评估您组织的数据成熟度为您的现代数据团队设定正确的目标至关重要。处于不同数据成熟度阶段的公司有不同的需求,这应该会推动您在创建团队时做出选择。此外,您需要为组织内的数据团队定义一个明确的角色,以避免孤岛和不明确的所有权。除此之外,您需要为您的组织选择最佳的数据堆栈和数据平台。虽然它可能无法满足所有的考虑,但本博客旨在为您提供最佳实践的概述和建议的非详尽列表,以克服在构建现代数据团队时可能出现的一些非技术性挑战。考虑到组织在团队创建阶段面临的非技术挑战,技术方面也值得详细关注。我将在另一篇博客中详细讨论这些。

为数据科学思考快与慢

原文:https://towardsdatascience.com/thinking-fast-and-slow-for-data-science-e739513becbf

知道何时使用实验和何时使用 MLOps 的重要性

云层上的日落。作者图片

这些天来,几乎每一个与数据科学和机器学习工程相关的内容似乎都是关于 MLOps 的。自从《机器学习系统中隐藏的技术债务》(Sculley 等人)在 2015 年末出版以来,学习和教授 MLOps 概念的人数急剧增加。这篇论文中的这张著名图片在几乎所有 MLOps 文章和书籍(包括我自己的一些演练)中作为学习 MLOps 的前提#1 被分享。

机器学习系统中隐藏的技术债务,斯卡利等人

通常,前提#2 是关于有多少机器学习模型最终进入生产的一些统计,作为从大量机器学习模型中获得最小价值的启发。

MLOps 的谷歌搜索趋势。作者图片

MLOps 是实验的对立面,数据科学家的成功依赖于能够高度敏锐地利用这两种心智能力。

MLOps 已经(并将继续)席卷数据科学界,以至于它被视为数据科学专业人员发展的自然进程。即使作为一个对这个领域非常着迷并参与过多个与 MLOps 相关的项目的人,我也想澄清一下,这种主导地位对该领域的整体寿命是有害的。MLOps 是实验的对立面,数据科学家的成功依赖于能够高度敏锐地利用这两种心智能力。过度关注其中一个范例会降低另一个范例的重要性,但是两者都是最大化所产生价值的关键。

丹尼尔·卡内曼的《思考的快慢》是我最喜欢的书之一,这位诺贝尔奖获得者在书中强调了你大脑中的两个主导系统——系统 1 和系统 2。系统 1 是自动和冲动的能力,而系统 2 是有意识和方法的能力。虽然我不会在这里深入研究这本书,但我会对书中讨论的概念进行类比,因为我认为它非常适用于数据世界。无论如何,我鼓励阅读这本书——它很吸引人,而且有科学依据。

在我们的案例中,数据科学家在使用 MLOps 概念和原则构建系统时,需要非常小心谨慎。他们需要锻炼他们的系统 2 心智模型,让他们能够慢慢设计出远远超越他们的东西。由于工艺的技术严谨,这种类型的思维被吹捧为最重要的。为了让数据科学家取得巨大成功,他们需要利用自己的直觉和好奇心来寻找创造性的解决方案。这套系统 1 心智模型允许他们提出各种各样的智能问题,并进行足够的实验,以确定继续前进的正确问题。

对于数据科学家来说,系统 1 和系统 2 思维的差异不在于你是否在进行机器学习,而在于你在指导有效决策方面的目标。数据科学家必须在每个项目中微妙地平衡速度和规模。从运行专家分析到工程统计方法,两个系统顽强地相互平衡着。就像系统 1 和系统 2 在我们的大脑中从心理上起作用一样,这些系统在工作时会一致地一起工作,看到它们各自的价值和缺陷对我们有利。这两者之间有明显的区别:

系统 1:在好奇心的引导下,提出更好的问题。

系统 2:严谨领导下的方法和缓慢的专业知识,以提供更好的答案。

谷歌首席数据科学家凯西·科兹尔科夫(Cassie Kozyrkov)开创了决策科学作为一个领域的重要性。她写道卓越的分析完全是关于速度以真实地展示数据分析师、机器学习/人工智能工程师和数据科学家的重要性以及他们各自的闪光点。虽然我同意他们都应该学习自己的专业知识,但我经常看到高级+分析师、mle 和数据科学家执行以上所有的一点点。他们必须是某些方面的大师,至少也是所有方面的大师。行业需要这种多方面的数据专业人员,这使得每个人都发展了这两种主要的思维系统。

系统 1 包括对数据的快速实验,以获得对它包含什么、极限在哪里、可能存在什么样的选择偏差、它可以合理地产生什么样的答案等等的有力把握。

系统 2 包括精心构建系统,利用系统中的数据,通过能够归纳出具有可再现性、透明性和抗脆弱性的新数据的模型进行有效扩展。

最后,为了简洁起见,我将称“数据科学家”为任何从事企业机器学习工作的人的简称。这对于机器学习工程师或其他数据从业者也同样重要。

MLOps 困扰的根源

任何参与 Twitter 机器学习社区的人几乎每隔一周就会看到一张新的 MLOps 图。一个架构的一些新的“需要的”组件声称使机器学习项目更加系统化。

最简单的图增加了开发和生产区域的二分法,最复杂的看起来像整个 IT 组织。

Twitter 公共域,tweet 作者@suzatweet。作者图片

不同组织在构建机器学习系统方面的差异也催生了过多的工具和技术,试图解决一些或所有 MLOps 的不满。

生产机器学习工具的精选列表由伦理人工智能研究所维护。图片来源

因此,这使得数据科学家争相成为各种工具的大师,努力建立这些“鲁棒和可扩展的”机器学习系统。这一点和执行方向的驱动原因似乎源于这样一种想法,即最小的机器学习模型最终会进入生产,因此从这些大规模项目中检索到的价值最小。

尽管关于有多少机器学习模型进入生产的这些指标的准确性还没有定论,但我主要想首先质疑这个前提的必要性。让每一个机器学习模型投入生产的需求是什么?从什么时候开始,这个行业盲目地接受了这样一种观点,即除非一个模型进入生产阶段(因此需要所有这些周围的基础设施),否则价值很难达到?

Lak Lakshmanan 写了一篇很棒的文章“不,你不需要 MLOps”在那里他阐明了大规模构建机器学习系统的过度复杂性。存在更简单的解决方案来“执行 MLOps”并遵循适当的准则,而不需要过度设计架构,这将导致比 2015 年更大的技术债务。

在继续我的观点之前,我想非常清楚地表明,我确实相信构建高效、健壮和可扩展的机器学习系统的价值,不管有没有简单的解决方案。我相信数据科学家学习如何思考和构建超越 Jupyter 笔记本,但这并不意味着他们的角色应该仅仅局限于这一功能。

当目标是构建超越 Jupyter 笔记本时,最好从版本控制、特性存储、模型注册以及帮助 MLOps 的数百种工具或技术方面开始考虑。这个深得吓人的兔子洞会很快欺骗你,让你认为这是需要优化的“首要”技能。实验和系统 1 思维的价值是人们雇佣数据科学家的原因,因为他们有能力建立大规模的数据系统,但这在 Kubernetes、Docker、Terraform 等的噪音中变得相形见绌。尽管 MLOps 确实可以非常好地服务于某些项目,但它并不是每个数据项目的最佳答案。

可悲的是,实验被低估了

我说的“实验”并不是指 A/B 测试和贝叶斯推断方法;我指的是最广义的实验。通常,它可以被认为是“R&D 工作”,但从根本上说,它是能够在您的数据项目中从 0 到 1 的技能。

当你设计一个大规模的系统时,你需要可重复的步骤,在这些步骤中你可以选择一个随机的系统,并使它尽可能的可理解和可控制。但是除非你知道该问什么样的问题以及去哪里寻找答案,否则你很可能会建立一个没有人会使用或从中发现价值的系统。我们可以衡量预测的价值,当它们失败时会发生什么,并设置 okr 以确保我们可以定量地“成功”。这与测量实验的价值截然不同,后者的目标是从零到一。实验是帮助你确定要解决的正确问题的方法,它要求你以数据为导向,以产品为导向,并对领域有很强的理解。这可以涉及 ML,也可以不涉及;它更多的是关于开发一个你的数据集想要表现的世界的强大模型。

如果不能在头脑中模拟超出现有数据集的数据集模型,您就无法很好地理解如何构建一个系统来推广现实世界中部署的新数据。

在实践中,实验通常是分析师和/或产品经理所期望的,但我经常看到数据科学家/mle 在他们变得更高级时不得不自己做这项工作。你越进步,似乎你就越被期望在两个系统中思考,并拥有更多你构建的整个数据产品。你也开始对你可能遇到的陷阱的领域有了具体的直觉,这极大地提高了你捕捉随后可能出现的错误的能力。这种直觉真的只来自于强大的实验。如果不能在头脑中模拟超出现有数据集的数据集模型,您就无法很好地理解如何构建一个系统来推广现实世界中部署的新数据。

问题在于给这项工作分配一个数值。这是艰难的,模糊的,不可预测的。理解一个领域和组成该领域的人,对为什么会出现某些空值、缺少什么混杂因素(以及为什么)以推断因果关系、总体打算采用什么分布等有一个具体的想法,这可能是一个学习和探索的随机过程,需要系统 1 比系统 2 思考更多。很多工作几乎不可能有效地重复。它处理数据的上下文性质,这在很大程度上受您对领域的看法和在领域中花费的时间的影响。

尽管这项工作可能会很慢并且需要深思熟虑,但是在进行大规模数据科学项目时,您通常会面临紧迫的截止日期,并且您很少有“足够”的时间来完成所有工作。这实质上意味着这种实验工作几乎总是会得到快速跟踪,因此行业需要深入了解某个领域并建立强大数据系统的专家——他们的直觉很深刻,并在谨慎的假设下得到明智的引导。这被认为是有价值的,但这通常没有转化为在这项工作上花费的时间。

建立有效的系统需要聪明的好奇心

过度关注 MLOps 最大的遗憾是,我们给人的印象是,它位于数据科学这座大山的顶端,其他一切都是前进道路上的垫脚石。现实是,MLOps 只是两座大山中的一座,另一座是实验。这两座山都值得攀登,也富有挑战性,而且都有潜力产生难以置信的价值。一名经验丰富的数据专业人员受雇能够翻越任何一座山,这意味着了解:何时翻越哪座山,翻越每座山时的常见陷阱/如何导航,到达山顶的最有效方法,以及如何开辟一条其他人也可能遵循的道路。

几乎总是,攀登实验山使攀登姆罗普斯山变得更好。这通常不是因为你可以在任何关于“如何进行机器学习”的普通博客帖子中读到的公式化原因。这是因为精确的领域知识让您能够洞察数据,并帮助您为不断变化的真实世界数据集创建可概括的模型。

攀登实验之山的有效方法是保持好奇心和探索精神。相关领域材料的异步阅读,对数据集上下文研究的定性查询,用度量和直觉驱动的想法分析数据,等等都是驱动这种系统 1 思维模式的因素。

攀登 MLOps 之山的有效方法是战略和方法。规划所需的系统和工具,协调监督某些方面的人员,制定策略来平衡系统的触发和启发,等等都是驱动系统 2 思维的因素。

专家们在紧张的时间期限下平衡两者,而不会精疲力竭。这才是我们应该放在数据科学这座大山的顶峰的东西。正因为如此,它不同于真正的软件工程角色,我认为我们通过认识和教授另外 50%的角色,为这个领域做出了巨大的贡献。

非常感谢你给我时间来读这个故事。我休了很长一段时间的假,因为我度过了一个多事之秋(搬到了一个新的城市,结婚了,开始了一份新的工作),不幸的是,这个夏天把我的一些爱好搁置了。我很兴奋能重新开始写作,尤其是这首曲子开启了写作的序幕。和我所有的故事一样,我欢迎辩论,所以请不要盲目地同意我的观点——找出它们的漏洞,让我们聊聊吧!

通过我的推荐链接成为中级会员

Medium 是我日常阅读的大型存储库,如果你在数据领域,这个平台就是一座金矿。如果你想订阅,这是我的推荐链接。完全披露:如果您使用此链接订阅 Medium,您的订阅费的一部分将直接交给我。希望你能成为我们社区的一员。

https://animadurkar.medium.com/membership

想成为一名数据分析师?你已经是一个了!

原文:https://towardsdatascience.com/thinking-of-becoming-a-data-analyst-youre-already-one-5773b63ae83b

是的,你。

你觉得自己“不是数据人”吗?或者,也许你渴望成为一名数据分析师,但你担心你需要参加一门课程,或者更糟,一个完整的博士学位,只是为了开始?我想借此机会向你证明你已经是一名数据分析师了。(对,就是你。)

先从一起分析一些数据开始吧!

这一桶数字——呃,我是说,矩阵——看起来枯燥无味,难以理解。而这只是整个事情的极小一部分,它重复了十万次类似的主题。

如果你出了一身冷汗,那是因为你有一种完全正常的人类反应:厌倦感。你猜怎么着,你是对的!

这个矩阵很无聊。

上下文使数据变得有趣

无论是谁告诉你数据会自动令人兴奋,他要么是在撒谎,要么是有古怪的癖好。为了让这个矩阵更有趣,你需要 上下文 。两大类:

  1. 使这些数字有用的上下文
  2. 让这些数字变得熟悉的背景。

第一类将数据与您的需求联系起来——如果您有特定的问题,如果我告诉您这个矩阵包含解决方案,您会很感兴趣。当谈到数学动机时,疼痛的减轻是一个游戏规则的改变者。

第一类是关于增加与数据交互的收益,第二类是关于降低成本

换句话说,也许我们可以找到一种方法,让这些数据背后的意义轻松地从屏幕跳到你的大脑。即使结果很无聊,也许也不会比我们开始时那么无聊。让我们试试用一些超级机密的博士专用图像处理软件来绘制它…

哒哒!在 MS Paint 的帮助下,我们了解到这个数据集只是我的(无聊的*)木地板的一张照片。通过使用软件,我们降低了与该数据集交互的成本——现在理解它就像看照片一样简单。更重要的是,我们知道你已经是分析师了。

你在那里做的事情被称为 数据可视化 ,它是分析师核心技能的一部分,另外还有 数据转换 (例如,删除你的前任)和 数据汇总 (例如,抱怨 1722 张自拍中只有 3 张对你的状态)。

你已经是数据分析师了

如果有人试图恐吓你,让你相信你没有资格分析数据,这里有一些提醒,让你免受他们的不良影响。

如果你曾经看过照片,你已经是一名数据分析师了。(如果你正在看这个屏幕,欢迎!此时此刻,你正在用软件从数据中提取意义。)

(我用照片来证明我的观点是不是作弊了?我会不认罪。数码照片是合法的数据集——它们以一种对你的大脑不友好的形式存储,但如果用正确的工具分析,它们可能充满意义。还有许多其他的数据类型数据源,但是相同的核心原则适用于所有领域。)

如果你曾经 进行过网上搜索 ,你已经是一名数据分析师了。

如果你曾经跳过一个. mp3 文件,你已经是一个数据分析师了。

如果你曾经使用过地图来找路,你已经是一名数据分析师了。

如果你曾经查看过世界另一端的天气,你已经是一名数据分析师了。

如果你曾经打开过电子表格,你已经是一名数据分析师了。

我从未见过真正“不是数据人”的人——花一点时间将你的计算机增强的存储、处理和传输信息的能力与典型的古希腊人进行比较。对他们来说你基本上就是雅典娜。

照片由赫特尼克Unsplash 上拍摄

你认为所有这些都是理所当然的原因是你已经学会了如何使用数据处理工具。从 Microsoft Paint 到 Google Maps 再到 Spotify,一切都是作为日常必需品的分析软件。这些工具的制造者知道不应该这样称呼它们,但它们就是这样。现代世界充满了奇迹,你已经是其中的一部分了。

这是否意味着你准备好成为一名专业分析师?

不完全是。业余分析师和专业分析师之间有一些很大的区别。如果你很想知道它们是什么,看看我的下一篇文章 …但是好消息是它们都是关于实践和经验的。如果你梦想从事分析职业,停止梦想,开始行动吧。简单地挑战自己,尽可能多地查看新的数据格式,并在此过程中,尝试学习有望加速这一过程的工具。没有什么能阻止你!玩得开心!

如果你渴望用一些分析职业概念来补充你的实践课程,请前往我的分析迷你课程

http://bit.ly/quaesita_sminianalytics

*脚注:我无聊的木地板

我用了一张我所在楼层的无聊照片来提醒我们,我们对数据的探索并不总能带来惊天动地的发现。有时候会,但大多数时候不会。这是工作的一部分。

这些数据很无聊,对你来说也不是特别有用,但是以一种熟悉的格式查看它们会让你更容易理解其中的含义(并继续前进)。这是分析师工作的一半——把数字转化成你能理解的东西。另一半是关于最大化每分钟的灵感,但那是另一篇文章

我用 MS Paint 来表达我的观点,你生气了吗?好吧,这是 Python!同样的想法。

附言:你有没有试过在 Medium 上不止一次地点击拍手按钮,看看会发生什么? ❤️

喜欢作者?与凯西·科兹尔科夫联系

让我们做朋友吧!你可以在 TwitterYouTubeSubstackLinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用表格取得联系。

浓缩咖啡的第三波水与过滤水

原文:https://towardsdatascience.com/third-wave-water-vs-filtered-water-for-espresso-955f9588693

咖啡数据科学

我更喜欢我习惯的水还是更好的水?

第一次用第三波水(TWW) 的时候,用的是一般的配方,不是浓缩咖啡专用的那种。我决定尝试混合浓缩咖啡,来自 TWW 的泰勒送来了样品。我查看了一组多次烘烤的成对照片,我发现味道有所下降,但对提取没有明显影响。

所有图片由作者提供

TWW 背后的想法是,你拿起蒸馏水,加入他们的矿物质包。无论当地水质如何,这都能让你获得适合喝咖啡或浓缩咖啡的稳定水源。

我住在加州的圣克拉拉县,我用的是冰箱里的过滤水。这个实验的警告是,自从八年前我来到加州,我就一直是这种浓缩咖啡的过滤水。所以很有可能我是有偏见的,我鼓励有兴趣的人自己做研究,更好地了解他们的口味。

另一个警告是,我比大多数人更喜欢食物中含盐量高的食物。当某种东西对我来说咸得恰到好处时,对其他人来说却似乎咸得过头了。所以每个人的味蕾都不一样。

设备/技术

意式咖啡机 : 像样的意式咖啡机

咖啡研磨机 : 小生零位

咖啡:家庭烘焙咖啡,中杯(第一口+ 1 分钟)

镜头准备:断奏夯实断奏

预灌注:长,约 25 秒

输液:压力脉动

过滤篮 : 20g VST

其他设备: Atago TDS 计Acaia Pyxis 秤

绩效指标

我使用两组指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和余味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

使用折射仪测量总溶解固体量(TDS),这个数字结合咖啡的输出重量和输入重量用于确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

【IR】强度半径定义为 TDS vs EY 控制图上原点的半径,所以 IR = sqrt( TDS + EY)。这一指标有助于标准化产量或酿造比的击球性能。****

数据

我有两组使用完整数据包(TWW 100%)和 89%数据包(TWW 89%)的数据。在之前的品尝实验中,我用四种浓度的水杯装了一杯咖啡,其中 89%是剩余的水。

总的来说,在 12 次咖啡烘烤中,我有 19 个镜头对。

在这两种浓度下,TWW 并不比我的过滤水好。最好的情况是,已经很接近了。我也没有看到从 89%到 100%的趋势,这表明我应该考虑增加 TWW 矿物的浓度。

在查看 TDS、EY 和 IR 时,我没有看到任何趋势。所有的镜头都非常相似。

所以我根据个人口味指标将它们分类,除了酸味和苦味,大多数都有差异。

我把两组数据汇总起来看差距,但这并没有改变任何结论。

我用一些统计数据完善了这个数据。除了酸味和苦味之外,味道的差异在统计学上是显著的。TDS、EY 和 IR 没有统计学上的显著差异,这让我怀疑水对味道的影响来自水,而不是它能够从咖啡中提取的东西。

对于 TWW 89%来说,味道的差异没有统计学意义,所以我可以尝试更低的浓度,但我没有兴趣进一步研究。

在这项研究中,我使用第三波水和过滤自来水收集配对数据。我发现过滤后的自来水味道更好,但提取咖啡的能力没有区别。目前,我坚持使用过滤水,除非数据显示并非如此。

当我们的味蕾如此不同时,水似乎是一个棘手的变量。

如果你愿意,可以在推特、 YouTubeInstagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在订阅

我的进一步阅读:

我未来的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

这篇文章写在朱庇特的笔记本上

原文:https://towardsdatascience.com/this-article-was-written-on-jupyter-notebook-767ca864cb48

jupyter-book 和 jupyter_to_medium 简介

图片来自 Unsplash 感谢 Erik

很长一段时间,我都把笔记保存在本地的苹果页面上。为此,我毫无怨言。Pages 是一款令人惊叹的软件,它可以让您快速制作高质量的文档(带有非常棒的图表),所用时间仅为 Overleaf、Word 或 Google Docs 的一小部分。

然而,有几件事一直让我很恼火:

  • 不可能进行版本控制
  • 这些文档不容易共享
  • 记录代码真的很难

这些也不是页面独有的。Word、Docs 和 Overleaf 在很大程度上都存在同样的问题。这些工具都不适合持续更新共享笔记、创建文档或合并代码。

好消息是,我最近学会了如何使用两个新的 Python 库,它们将帮助我大大加快记笔记和写文章的速度。这些是jupyter-bookjupyter_to_medium

在这篇文章中(我碰巧写在 Jupyter 笔记本上!)我将解释如何使用这两种工具来加快记笔记和写文章的速度。

这些引文是我通过*jupyter_to_medium*转换后在媒体上添加的。我很高兴它正确地格式化了副标题!切片(例如……)是在培养基上手动完成的。此外,Unsplash 分钟是在发表之前添加到介质上的,因为我忘记了 XD

什么是jupyter_to_medium

jupyter_to_medium是一个 Python 包,可以让你直接把你的 Jupyter 笔记本文章部署到 Medium。如果你的大部分文章都是基于 Jupyter 笔记本上的内容,这是很有用的。我对这个包已经好奇了一段时间,但我只是刚刚开始尝试它...让我们看看它能做什么!如果一切顺利,我可能会强烈考虑把它作为我文章的主要来源。

装置

%%capture

# install jupyter_to_medium
!pip install jupyter_to_medium

对于大多数人来说,这样做应该可以让你访问 Jupyter 笔记本中的“文件”下的“部署”按钮。

如果不是(像我这样),那么您需要运行jupyter bundlerextension enable --py jupyter_to_medium._bundler --sys-prefix

图像似乎像一个魔咒一样传入!

现在,您可以使用它将您的笔记本电脑部署到中型。有一些关于如何压缩图像的选项,以及你是否希望你的代码转换成 gists。对于本文,我只是使用默认选项来看看结果是什么样的。

Jupyter 到 Medium 的测试

  1. 我想看看数学公式压缩后是什么样子…

$ $ \ frac { \ partial } { \ partial t }(\ rho \ underline { u })+\ nab la \ cdot(\ rho \ underline { u } \ otimes \ underline { u })=-\ nab la p+\ nab la \ cdot \ underline { \ underline { \ tau } }+\ rho g $ $

为方程式感到羞耻!

  1. Numpy 数组
import numpy as np
np.array([1,2,3,4])array([1, 2, 3, 4])

代码块及其输出被视为一个整体

  1. 命令行日志
!echo "TESTING"TESTING 

与介质一致,您无法继续编号!

什么是jupyter-book

这个标题必须手动放大,即使它在减价时更大

jupyter-book是一个软件包,允许您使用 markdown 文件和 jupyter 笔记本文件轻松制作类似书籍的文档。因此,它们非常灵活,可以让您在很短的时间内快速生成丰富的文档。更重要的是,它们可以与 GitHub 动作集成以支持 CI/CD 行为。如果您正在寻找没有任何 CI/CD 特性的jupyter-book的快速安装,只需运行:

%%capture

# install jupyter-book
!pip install jupyter-book

# create a book
!jupyter-book create your_book_name

如果您当前的工作目录,这会创建一个名为your_book_name的书。目录结构如下所示:

your_book_name:
    - _config.yml
    - _toc.yml
    - intro.md
    - logo.png
    - markdown.md
    - notebooks.ipynb
    - references.bib
    - requirements.txt

现在,您可以通过编辑。md 或者。ipynb 文件!你甚至可以添加自己的文件。记住,_toc.yml文件包含了你的书的结构,所以要确保任何添加到那里的书都被正确引用。

更多信息,请访问 jupyter-book 官方文档这里

请注意,添加了%%capture魔术命令,以防止打印安装输出。

使用 cookiecutter 安装

我更喜欢通过cookiecutter安装jupyter-book。这个方法附带了额外的文件,这些文件与 GitHub 动作接口,以在项目上启用 CI/CD。要使用此方法安装,首先确保您已经安装了cookiecutter:

%%capture

# install cookiecutter
!pip install -U cookiecutter

然后,使用以下 cookiecutter 命令下载最新的 jupyter-book 配置:

%%capture

!cookiecutter git@github.com:executablebooks/cookiecutter-jupyter-book.git

这允许你添加一些关于你的项目的元数据,比如标题、作者姓名、许可证等等。我特别想让大家注意一下book_slugselect include_ci_files。对于前者,它是用于下载目的的项目名称,例如,如果你想运行pip install project。我还没有使用过这个特性,但是我提到它是为了让你有兴趣了解更多。关于cookiecutter中什么是鼻涕虫的帖子,请参见 GitHub 问题。

更有趣的标签是select include_ci_files。选择 1 将下载 GitHub 的 CI/CD 配置(而选择 2 将下载 GitLab 的 CI/CD 配置)。我将经历这为 GitHub 做了什么。

CI/CD 文件

Cookiecutter 会自动添加一个名为.github的隐藏文件夹,其中包含一个. yml 文件workflows/deploy.yml。当您对项目进行更改时,GitHub 使用它的内容来触发测试和部署。默认情况下,它被配置为在 GitHub 上寻找主分支的变化。如果检测到了变化,那么它会在一个 ubuntu 环境中用指定版本的 Python 运行一些测试。这些包括依赖项安装(例如从requirements.txt开始)以及监视哪个文件夹中的项目新版本。

# test import pandas
try:
    import pandas
    print('Pandas import successful.')
except:
    print('Pandas import failed.')Pandas import failed.

因为我在本地运行,所以我看到“熊猫导入失败”以上,因为我所处的环境不是用熊猫。然而,该项目的需求文件中确实有熊猫。这意味着该页面的发布版本(参见此处的)。实际上应该输出不同的消息。

推送至 GitHub

为了将您的笔记本发布到 GitHub,首先按照此处的说明激活 GitHub 页面。一旦完成,您将拥有一个指向同名网页的存储库{your_github_username}.github.io。现在,您创建的任何新项目都可以在{your_github_username}.github.io/project_name有一个与之关联的网页。

因此,你可以将你的书放在 GitHub 的一个项目下。因此,为您的项目创建一个新的存储库,然后将your_book_name中的所有文件(注意:不是之前创建的那个,而是使用 cookiecutter 创建的那个)推送到其中。在 GitHub repo 上,确保您创建了一个空的gh-pages分支(这是 GitHub actions 将图书内容推送到的分支),并将您的项目 GitHub 页面的位置指向该分支(这可以通过进入您的项目 repo 设置,然后进入 pages,然后启用该功能并将目录指向 gh-pages 根目录来完成)。

做出改变

一旦您的项目链接到 GitHub,任何对项目的新提交都将触发 GitHub 动作。这将自动在 GitHub 上运行一些测试。

在您最近的提交中,您将能够看到一个橙色的点,表明测试正在运行。完成后,你会得到一个叉号或一个勾号。

这表明测试是否成功。如果没有,您需要查看测试日志。记住测试运行的细节可以在.github/workflows/deploy.yml找到,所以从那里开始总是好的。

如果成功,那么你的项目将被部署在 GitHub 页面上!您可以在存储库的侧面看到最新的构建,并从那里访问它:

想法和要点

Jupyter 到 Medium

就我个人而言,我通常不会在 Jupyter 笔记本上写文章。我真的很喜欢在 Jupyter(或者通常只是 Python)上运行实验,然后在头脑中写一篇清晰的叙事文章以吸引读者的清晰划分。因此,我认为我不会经常使用jupyter_to_medium。我发现在媒体上上传图片和给图片加标题要简单得多,而且可能会继续这样下去。

不过总的来说,我认为这是一个很棒的软件包,对很多作家都有帮助。确实可以加速文章的写作进程。

朱庇特书

jupyter-book似乎极有希望。到目前为止,我非常喜欢它,我想我会开始在那里记笔记,而不是在本地,同时慢慢开始迁移我的旧内容。还有很多要学的...还有许多功能我需要探索,如引用,图形和标题的正确使用,与代码的正确集成。

尤其是因为我还没有弄清楚为什么这些图片会导致 GitHub 上的构建失败,而在本地却成功了…

所有图片均由作者提供,除非另有说明。

这个装饰器将使 Python 速度提高 30 倍

原文:https://towardsdatascience.com/this-decorator-will-make-python-30-times-faster-715ca5a66d5f

以熊猫为例

撰写人:阿玛尔·哈斯尼 & 迪亚·赫米拉

人工智能生成的图像(稳定扩散)

您可能知道,python 是一种解释型语言。这意味着 python 代码不是直接编译成机器代码,而是由另一个名为解释器(大多数情况下为 cpython)的程序实时解释。

这也是为什么与编译语言相比,python 有如此大的灵活性(动态类型,到处运行等等)的原因之一。然而,这也是 python 非常慢的原因。

缓慢 python 的解决方案

python 速度慢实际上有多种解决方案:

  • 使用cython:python 的超集编程语言
  • 使用 C/C++语言结合 ctypespybind11CFFI编写 python 绑定
  • 用 C/C++扩展 Python
  • 使用其他编译语言,如 rust

如您所见,所有这些方法都需要使用 python 之外的另一种语言,并编译代码以便与 python 一起工作。

尽管这些都是有效的选择,但它们并不是让 python 变得更快的对初学者最友好的方法,并且不一定容易设置。

Numba 和 JIT 编译

来认识一下 numba一个 python 包,它将使您的代码运行速度大大加快,而无需放弃 python 的便利性:

Numba 是一个开源的 JIT 编译器,它将 Python 和 NumPy 代码的子集翻译成快速的机器代码。

numba使用实时(JIT)编译(这意味着它是在 python 代码执行期间的运行时编译的,而不是之前),在你问之前,不,你甚至不需要安装 C/C++编译器。你所需要做的就是用 pip/conda 安装它:

pip install numba

我们已经说得够多了,让我们试一个例子(来自 numba的文档)。我们希望使用蒙特卡罗模拟来计算 π 的估计值:

注意如何使用numba,只需要我们导入一个装饰器( njit),它将完成所有的工作。

运行这段代码,对两个版本进行计时,显示出 numba 比普通 python 快 30 倍:

一些警告

如此呈现,听起来好得令人难以置信。但是它确实有它的缺点:

  • 有一个开销,第一次运行一个numba修饰函数。这是因为numba会在函数第一次执行的时候试图找出参数的类型并编译它。所以第一次运行时会慢一点。
  • 并不是所有的 python 代码都会用 numba编译,例如,如果你对同一个变量或者列表元素使用混合类型,你会得到一个错误。

立体公园里的熊猫

numba是专为 numpy设计的,对 numpy 数组非常友好。你知道 numpy上还建了什么吗?
你猜对了: pandas。当使用用户定义的函数或者甚至执行不同的数据帧操作时,这会导致疯狂的优化。

让我们看一些例子,从这个数据框架开始:

用户定义的函数

numba 的另一个方法是 vectorize,这使得创建 numpy 通用函数( ufuncs )变得轻而易举。

一个简单的例子是计算数据集中高度列的平方:

基本操作

另一个例子(使用 njit)是使用以下代码计算身体质量指数(身体质量指数):

你可以看到,即使是基本操作,numba 仍然比原始熊猫花费更少的时间(6.77 毫秒对 8.63 毫秒)

最后的想法

使用 numba是一种非常简单的方法,可以让你的代码运行得更快。有时,在你的代码被成功编译之前,可能需要一些尝试,但是一般来说,它可以开箱即用。

如果你对让熊猫跑得更快的更多方法感兴趣,看看我们关于 eval & query的文章:

https://python.plainenglish.io/these-methods-will-change-how-you-use-pandas-921e4669271f

谢谢你坚持到现在。注意安全,在接下来的故事中再见😊!

更多文章阅读

</8-tips-to-write-cleaner-code-376f7232652c>

这就是我如何使用我的编码技能来构建免费的 Pdf 提取器

原文:https://towardsdatascience.com/this-is-how-i-used-my-coding-skills-to-build-free-pdf-extractor-51f87ce68cc3

使用 Python

Canva 中的 T.AI 创建

简介-故事:

我总是想用我的编码技能为我自己或我的朋友做点什么。让我告诉你一些关于我父亲的事情,他是一个自学成才的技术员,在没有得到教育或机构的太多帮助的情况下,他成功地在我们的小镇上经营了一家修理店,为任何电气和电子设备提供服务。他总是非常有兴趣自己做点什么,猜猜看,在我的童年,我们有两台电视,一台收音机和一台录音机,它们都是由我父亲用各种二手零件组装而成的,并且都运转得非常好,超过了 10 年。

每当他做出这样的东西时,我总是为他的技术感到高兴和感动。如果你真的观察到到处都在发生这种事,木匠喜欢为自己做东西,画家喜欢为自己画东西。但不幸的是,这不是我们在软件或数据科学领域经常看到的趋势。

一张由布鲁纳·阿劳霍Unsplash 拍摄的旧电视照片

查看您在笔记本电脑或手机上使用的应用程序或服务中有多少可以由您或您的朋友完成?至少要有一个。虽然它涉及到一些财务储蓄,但你不能低估它给你的信心和满足感。

因此,尝试使用 python 制作 pdf 提取器是让自己开心的想法之一。

我为什么做 PDF 提取器的技术方面-

如果你在网上搜索 pdf 提取器,你会得到一堆免费的资源,而且它们还不错。他们在将 PDF 转换为 CSV 方面做得非常好。

在我的特殊情况下,我需要 JSON 格式的 PDF 中的表格,这样我就可以将数据插入或更新到数据库中。为此,我需要正确可行格式的数据,因为这往往是一个重复的过程。我想要一个将 PDF 格式的表格转换成 JSON 格式的 API,当然也不想掏空我的口袋去使用这项服务。

因此,在本文结束时,您可以了解到

  1. 如何使用 Python 将 PDF 转换成 JSON 和
  2. 如何为其编写 API

选择

Python 的好处是它有很多库,几乎可以满足您想要运行的每个作业。对于 Pdf 的提取,有很多如下的库

  • PyPDF2
  • Textract
  • 阿帕奇蒂卡
  • pdf 木材
  • pdfMiner
  • 白板
  • 卡梅洛特

我不打算在这里涵盖所有库之间的差异,但有一个很好的如何从 PDF 中提取文本,你可以检查。

底线是不是所有的库都是好的,对我有用的不一定对你有用。这完全取决于您的场景和 pdf 格式。

哪个图书馆最好?

建议-如果执行时间对你来说不成问题,那么卡梅洛特就是完美的选择。

我想根据三件事来选择库

  1. 输出的准确性
  2. 执行时间
  3. 易于在云中部署

带着这三点,我总结了我对卡梅洛特和塔布拉的选择。

卡梅洛特的参数非常丰富,提供了很多选项。

但是我最终没有在这个项目中使用卡米洛特。

你可能会想为什么🤔?

因为正如我所说的,我希望以后能够灵活地将代码部署为 API。在本地这可能行得通,但是随着执行时间的增加,在部署期间或部署之后处理云配置确实是一件令人头疼的事情。

卡梅洛特耗时约 36 秒

白板花费的时间约为 8 秒

卡梅洛特用了 36 秒,塔布拉尔用了 8 秒。

所以要回答他们中最好的一个是什么?由于执行时间,我说 Tabula 为我。

卡梅洛特确实提供了很多选择,但执行起来需要很多时间。

最后,我和塔巴鲁一起去了

怎么做?

我已经使用 pycharm 和 Jupyter 笔记本来编写和测试我的代码。您可以使用自己选择的任何 IDE。

如果你想看完整的代码请参考— Github 链接

密码

我们来看看主函数pdf_to_df()

主要功能

正如您可能已经预料到的,我们在函数中所做的是获取 URL,然后使用 PyPDF2 读取它

PyPDF2.PdfFileReader(remote_file_bytes)

神奇的是,从 pdf 文件中提取数据只用了一行代码,如下图所示read_pdf()是从tabula library导入的

read_pdf(url_path, pages=[1,2], lattice=True, pandas_options={'header': None})

这里的重要参数是latticepandas_options

让我们来看看在使用和不使用lattice的情况下,我所使用的示例 pdf 的输出有何不同

示例 PDF(由 T.AI 创建)

晶格-对还是错

您可以看到,当 lattice 等于 True 时,代码如预期的那样生成了 12 列,而当它被设置为 False 时,它只生成了 3 列。这是因为 lattice 使用 pdf 表格中的线条来分隔列。您可以在此文档链接中找到更多信息。

当我从函数pdf_to_df()中获取数据帧时,很容易使用jsonify()将其转换为 JSON

Falsk 应用程序- API

我想生成 API,这样我就可以提供 pdf 的 Url 并获得 JSON 输出。为此,我使用了一个简单的 flask 应用程序结构和“post”方法。

您可以使用python run <flask app.py>在本地运行 flask 应用程序

我已经用 postman 在本地测试了这个应用,你可以在下面看到结果

Flask API 成功输出

结束了吗?

虽然写的代码为我做了工作。你能告诉我有什么问题吗?

我知道你们中的一些人肯定猜对了。这是我们在部署代码时面临的问题。在我写了这段代码之后,我意识到没有多少服务提供 PDF 给 JSON API,那么商业化怎么样呢?

为此,我需要部署 API,当我尝试使用tabula-py时遇到了困难,因为这个库是 tabula-java 的包装器。如果你有兴趣了解更多,并想知道我最终是如何部署它的,请留下评论,让我知道。

资源

要点链接-

  1. https://gist . github . com/tejeshb/96203007 c 6 CFF 7 f 141 f 67 f 89208 dcb 7 e

2.https://gist . github . com/tejeshb/cf2f 10207959 b 57b 6 b 267155 e 070 f 185

这就是有效的工程管理的样子

原文:https://towardsdatascience.com/this-is-what-effective-engineering-management-looks-like-7c1e5e0877

如何在工程领导角色中取得成功的 50 个洞见

作者图片

在转变为工程经理和总监之前,我已经担任技术主管多年,我编制了这个列表,以提醒我必须不断发展和展示的所有技能和行为,以帮助我实现飞跃,以及我在担任该角色时获得的认识,希望它也能鼓励我的读者。

拥有扎实的工程基础是必须的,但要成为一名成功的工程领导者,还需要许多其他技能。

这绝不是一个详尽的列表,也没有按照任何特定的顺序排序,但它确实描绘了一个经理的技能组合:

  1. 成为经理不是升职,而是一份完全不同的工作,事实上,这份工作会让你离你的专业领域更远。
  2. 适应连续会议,即使感觉你在一天结束时没有完成多少。
  3. 接受不断的上下文切换和被打断,但也要保证白天(或晚上)的一些思考时间。
  4. 转变你的心态,成为一个推动者(甚至是乘数),而不是执行者。
  5. 创建路线图(短期与长期)并定义您的战略愿景。
  6. 发布状态报告——掌握 KPI、突袭、实际与计划基线、预测里程碑、衡量项目的 ROI 等。
  7. 管理工作组并为 SteerCo 会议做出贡献。
  8. 知道何时构建内部软件,何时采用现成的软件。
  9. 培养创新文化。
  10. 让技术债务成为计划会议中反复出现的话题,同时不要失去对实际可交付成果的关注。
  11. 交付一个有特定目标的项目,但是要考虑到企业的全局。
  12. 帮助您的工程团队看到他们在这个大局中的目标。
  13. 向另一个团队宣传你的框架/应用程序/解决方案,这样他们就不会重新发明轮子。
  14. 与跨职能同事合作交付项目。
  15. 放下你的项目,继续前进。
  16. 理解“指挥链”,即权力在组织中的分配方式(又称组织结构图),尤其是这些棘手的虚线…
  17. 确定谁是真正的影响者,以及如何将他们添加到你的网络中。
  18. 认识到什么在你的控制之内,什么在你的控制之外。
  19. 把办公室政治抛在脑后,同时又不幼稚!
  20. 认识到你的职业发展不仅依赖于你的经理或团队成员,也依赖于你的同事。
  21. 建立你的权威,但也促进你的团队的授权和自主权。
  22. 定期进行自我评估。
  23. 把合适的人放在合适的岗位上。
  24. 志愿参加有益于组织的项目,但在绩效评估和职业发展方面不一定有魅力、有挑战性或可提升性。
  25. 向可能比你级别高的非技术观众解释技术观点,以获得支持或项目赞助。
  26. 被叫去现场做报告。
  27. 引导白板会议。
  28. 掌握谷歌搜索的艺术!
  29. 吸收不确定性和压力,这样你的团队才能把事情做好。
  30. 反思负反馈。
  31. 传递负面反馈。
  32. 向你的上司传递负面反馈!
  33. 接受不是每个人都喜欢你,这没关系!
  34. 能够量化和测量几乎所有的东西。
  35. 理解领导本地团队和领导全球团队是非常不同的(必读:Erin Meyer 的文化地图
  36. 帮助你的团队成长,因为你管理的人是你的直接反映。
  37. 管理一个比你聪明的工程师团队!
  38. 无论成功是小是大,都要认可你的工程师。
  39. 在信息共享方面对你的团队保持透明。
  40. 提供技术指导和训练,但不是填鸭式的解决方案。
  41. 确定目标,而不是规定过程。
  42. 执行产能规划并建立招聘策略以雇佣高性能的工程师。
  43. 新成员的入职、定向、指导和评估,以及离职,如果需要的话。
  44. 在授权方面变得越来越有效。
  45. 坚持到底——无论是给你的直接下属发一篇你读过的文章,还是给你的老板发他们要的材料。
  46. 情绪成熟,能够领导一个由意志坚强(可能很难相处)的人组成的团队。
  47. 首先解决冲突并防止其发生。
  48. 评估现状(在开发实践、团队动态等方面)并设定新的优秀标准。
  49. 鼓励你的团队参与决策过程。
  50. 在问题出现之前,克服不愿意寻求帮助的心理。

现在是软件工程管理的大好时机!在大多数组织中,这些技能融合了多种角色,但无论你的级别如何,你都需要不断进化和发展。我希望我的观察和学到的教训对任何未来的工程领导者都有帮助。

感谢阅读!

我经常在媒体上写关于领导力、技术&的数据——如果你想阅读我未来的帖子,请‘关注’我

https://semika.medium.com/subscribe

这就是为什么你会收到这么多特别的请求

原文:https://towardsdatascience.com/this-is-why-you-are-getting-so-many-ad-hoc-requests-edf3370484b8

行业笔记

这就是为什么你会收到这么多特别的请求

我们分享分析工作的方式很糟糕。让我们来谈谈我们能做些什么来使它变得更好,并减少您的临时过载。

“嘿,问个小问题,我知道你很忙,但是你能在有空的时候重新运行一下这个分析吗?如果你也能帮助我们挖掘对这些旧决策的查询,那就太好了。”(图片由作者提供)

你是一台分析机器。你喝咖啡,输出可操作的见解。但是你有一个致命弱点:臭名昭著的临时请求。

“嘿,你能再快速调出这些数字吗……”
“嘿,你做的那个分析在哪里……”
“嘿,你对这个有疑问吗?”“嘿,这是你 4 个月前用过的那张桌子吗?”
“嘿,这个查询又能做什么?”

我们经常感叹,这种利益相关者管理的味道是工作中不幸的一部分。但是我不同意。

当我在 Airbnb 担任数据科学家时,我整理了一份我收到的请求列表。有些确实是全新且必要的:例如,你能帮我做一个查询吗,你能为 X 创建一个新的度量标准吗,等等。但是大多数人觉得是可以避免的:例如,对我以前已经做过的工作的要求,对我应该更好地记录的工作的一长串后续问题,或者我知道别人以前做过的工作。令人沮丧的是,在这些情况下,我本没有必要参与进来。不知何故,我无意中让自己成了自己工作的看门人,忘记了包括上下文或用于洞察的查询。在其他情况下,因为工作不是集中的,我只是作为一个机构知识的人类仓库来运作。

在这篇文章中,我认为这类问题很大程度上可以通过改变我们如何分享工作来解决,这可以导致你收到的临时请求数量的急剧减少。在接下来的内容中,我将考虑两个罪魁祸首:糟糕的实践和延续它们的工具。

我们的工具天生不擅长分析协作

让我们从讨论我们用来与利益相关者共享工作的工具的缺点开始。考虑以下我们作为分析师经常抱怨的问题:

  • 您抱怨您的仪表板没有被使用(但是它缺乏上下文,并且在其他无上下文仪表板的海洋中游泳)。
  • 您抱怨说您与大量文档共享了您的笔记本,但是您的利益相关者仍然有许多问题(但是……您在 Jupyter 笔记本而不是 SQL 中编写了您的工作,使得非技术人员无法访问您的结果)。
  • 您的利益相关者催促您刷新您的工作(但是您忽略了在您的结果旁边提供 SQL 查询,因为它位于您的 IDE 的某个选项卡中)。
  • 你对一个第 100 次问你“你做的那个分析”的利益相关者发出嘘声(但是你最好把你的工作保存在 Google docs 中,最坏的情况是 SQL 查询被转储到 Slack 中,那里的可见性和可发现性很差——见鬼,你甚至不能自己找到它)。

我们喜欢的工具——仪表盘、笔记本、ide、谷歌文档——在我们需要围绕分析进行协作的方式上天生就不擅长协作(这就是为什么我们建立了 Hyperquery )。是的,当你在 Slack 中匆忙删除你的工作链接时,利益相关者会得到他们问题的答案,但这些现有的交付模式往往会剥夺他们对独立性和能力的任何希望,这意味着与工作相关的每个后续请求都必须通过你。如果是某人找到、理解和修改你的作品的唯一途径,你将会得到很多问题。

如何解决这些缺点:背景、透明度、可发现性

通过对如何交付工作采用更严格的标准,我们的工具中的缺点可以大大减少。面对问题时,作为分析师,我们的本能是正面解决问题,并尽可能快地给出答案。但是我们需要提供更多的答案,而不仅仅是以我们获得答案的形式,否则我们就有被超越的风险,因为我们无法超越我们松弛的反应速度。是的,我们需要快速响应,并与我们的利益相关方紧密合作,但是如果我们的工作能够带来正确的元素,这些对话将会进行得更顺利:

  1. ****📒上下文:解释什么、为什么和如何
    没有生成查询的上下文,查询是没有用的。虽然在没有业务上下文的情况下转储查询、仪表板和数据通常很有诱惑力,但这将不可避免地导致后续问题、误解,并且通常会使双方都感到沮丧。当上下文、假设和结论清晰时,对话总是进行得更顺利。
  2. 👀透明度:**分享你的疑问透明度是围绕分析进行对话的必要条件。没有人想要一个不知道为什么的问题的答案。如果没有用于生成图和数据的查询,就不应该交付图和数据。并且工作 应该在 SQL 中完成,以确保无摩擦、无状态的可再现性。没有透明度,利益相关者将没有能力回答后续问题,这意味着这些问题将会慢慢反馈给你,更糟糕的是,他们将会失去信任,这意味着你的工作的影响将会减少。SQL 很容易学习,但是如果给你一个查询来引导你的工作,就更容易操作了——我还没有遇到一个利益相关者不渴望做后者。
  3. 🔍可发现性:**把你的工作放在别人能找到的地方工作需要被发现。我们之所以得到这么多重复的请求,是因为没有人(包括我们!)可以在我们的作品第一次交付后找到它。虽然这不会直接帮助任何单个分析, 将发布工作集中到一个中心位置 将减少冗余,并在未来打开自助服务的通道。分析工作最痛苦的部分不是工作本身。因为你第一次没有组织和记录,所以下周又要做这项工作。

也许您已经接过了火炬,但是我知道我个人已经不止一次地放弃了这些标准——足以保证明确地陈述这些需求,并且将它们作为组织范围的标准。背景、透明度和可发现性是协作分析的缺失支柱。没有它们,利益相关者(和其他分析师)就无法了解你做了什么,为什么要这么做。没有它们,断头情节和 SQL 代码转储将不可避免地在 Slack 中泛滥成灾,而您将不得不将它们保存在一起。

如果我们想要建立更强大、协作友好、值得信赖的分析组织,我们需要以不妨碍我们努力的方式工作。让我们拥抱更好的标准,以能够与我们的利益相关者对话的方式工作(而不是单方面的移交),并提升我们的专业水平。

推文@ imrobertyi/@ hyperquery来问好。👋或者关注我们LinkedIn。🙂
如果你感受过分析协作的痛苦,你会爱上
Hyperquery。Hyperquery 是一个文档工作区,您可以在其中执行+可视化查询,为您提供即时可用的上下文、透明度和可发现性。**

这个小 Python 练习教会了我很多

原文:https://towardsdatascience.com/this-little-python-exercise-taught-me-a-lot-65a60e1100bf

如果你想成为一名优秀的程序员,不要满足于你想到的第一个解决方案

约翰·施诺布里奇在 Unsplash 上的照片

解决编程挑战是提高技能和学习新工具的好方法,即使是用你已经知道的语言。这就是为什么我觉得这个小问题很吸引人:

给定一个包含重复字母的字符串 s ,例如“hhhhhhhaaaaaaaaabbbbbbbvvvvvaaaahhhh”,输出一个摘要列表,显示每个相同字符序列的起始位置和字符

对于上面的字符串,输出将是:

[(0, 'h'), (7, 'a'), (15, 'b'), (22, 'v'), (27, 'a'), (31, 'h')]

解决方案 1

第一种解决方法是根据每个字符在字符串中各自的位置,这可以通过

enumerate(s)

然而,这还不够,因为我们需要扫描“变化”——当前角色与其前任不同的位置。让我们迭代字符串的两个副本,移动一个字符,如下所示:

enumerate(zip(s[1:],s),1)

枚举现在从 1 开始,因为我们从相对于前一个字符的索引 1 开始查找字符。

为了完成这个解决方案,我们需要只保留代表一个新字符的元组。我们还需要确保在输出中包含第一个字符(第 0 个索引处的字符)。空字符串的情况需要单独处理,以避免异常。

这是我们的功能:

def summarize_string1(s):
    if not s:
        return []
    return [(0,s[0])] + \
[(i, c) for (i, (c, pc)) in enumerate(zip(s[1:],s),1) if c != pc]

i 代表索引, c 代表字符, pc 代表前一个字符。

itertools.groupby

事实证明,Python 的 itertools 模块可以帮助我们让这段代码更加优雅。

该模块中的 groupby 函数将一个序列作为输入,并将其分解成子序列,其中每个子序列中的项目共享同一个键。这听起来有点抽象,所以让我们分解一下,看看在这种情况下如何让它工作。

我们再看看

enumerate(s)

它根据单个字符及其位置生成一个项目序列,例如(0,' h ')、(1,' h')…等等。

现在,我们希望将这个序列中字母相同的项目组合在一起,因此我们编写这个 lambda 函数来提取字符作为键:

lambda x: x[1]

现在我们准备编写如下代码:

from itertools import groupby
def summarize_string2(s):
    result = []
    for key, group in groupby(enumerate(s),lambda x: x[1]):
        result.append(next(group))
    return result

理解这段代码的关键是理解 groupby 函数在这里是如何工作的。它检查我们的字符串 s 的枚举字符,并将 lambda 函数应用于元组(0,' h ')、(1,' h ')等。当它意识到它到达了一个键不同的项时,它“打包”到目前为止它处理过的所有项,并把它们放入一个 iterable(我们在变量组中接收到它)和它们相关的公共键中。因为是一个生成器而不是一个合适的列表,访问它的第一个元素的最简单的方法是使用 Python 的内置 next,以上面代码中描述的方式。下一个(组)的可能替代项是

list(group)[0]

提取第一个元素。

这是我们对这个问题的第二个解决方案。我认为代码更好,但是在性能方面,它比解决方案 1 慢 50%。

使用 numpy

numpy 用于数值计算,通常不用于处理字符串。但是它有一个 diff 函数,我们可以在这里利用它。

下面是我们使用 numpy 的代码:

import numpy as npdef summarize_string3(s):
    str_arr = np.array(list(s.encode('ascii')))
    loc = np.diff(str_arr,prepend=0).nonzero()[0]
    return [(i, s[i]) for i in loc]

str_arr 是字符串到整数数组的转换。每个整数代表字符串中的一个字母,通过它的 ASCII 码(如果字符串包含 ASCII 子集中没有的 unicode 字符,它就不起作用)。

np.diff 是什么?它查找 numpy 数组中连续条目之间的差异。无论相同的字符在哪里,显然相同的 ASCII 码将填充数组,差异将为零。非零元素只会出现在字符序列的开头。预先添加一个任意的零条目允许我们自动捕获第一个元素,因为没有一个字母或可打印字符的 ASCII 码是 0。

虽然 numpy 被认为非常快,但对于我在本文中使用的特定示例数组,我们的解决方案的 numpy 版本大约比前面的解决方案慢 4 倍。转换成数组一定消耗了大量的处理器时间。

一锤定音

这个有趣的编码小挑战让我们看到了解决同一个问题的不同方法。当选择工具来解决特定的编码问题时,每个工具所提供的效用应该与最终解决方案的可读性及其解决特定问题的效率相权衡。

资源

这个快速简单的 7 步清单将帮助你为数据科学编写更好的 Python 代码

原文:https://towardsdatascience.com/this-quick-and-easy-7-step-checklist-will-help-you-write-better-python-code-for-data-science-62f1a1f4b20c

这个清单将帮助您编写干净且易于管理的 Python 代码

奥斯汀·洛曼在 Unsplash 上的照片

直到我开始阅读其他数据科学家写的代码,我才真正理解为什么来自计算机科学背景的软件工程师或数据科学家会抱怨数据科学家写的代码。

然后,我发现了数据科学家的氪石。

“数据科学不是一个自然源自计算机科学的领域”,这反映在数据科学家拥有的各种背景中。数据科学家通常来自不相关的领域,如医学、工程、艺术、商业等,他们很少拥有基于计算的背景来支持他们编写代码的知识。

通常情况下,数据科学家编写的第一个代码是通过在线课程,这将为他们进入该领域提供动力。不仅如此,大多数数据科学家都是从学习 Python 开始的,Python 是一种能让新的程序员轻松完成大量工作的语言。

因此,数据科学家在编写代码时往往处于劣势,而这些代码在提交给生产环境时会变得很明显。

当你去一家没有预算来雇佣数据科学家和软件工程师的公司工作时,写好代码的重要性就变得很明显。在这些场景中,数据科学家负责创建生产就绪代码。因此,您必须开发一个系统来帮助您编写干净、易于管理的代码。

无论您是一名刚刚起步的新数据科学家(尽早养成好习惯总是一个好主意!)或者是一个睡觉时也能做到这一点的老手(偶尔敲掉锈迹从来都不是一个坏主意),这个清单将帮助您为数据科学编写更好的 Python 代码。

1.你的语法遵循 Python 惯例吗?

如果你有计算机科学或软件工程的背景,你可能会带着口音编码。

就像说一门新的语言或第二语言一样,你说话的口音会让听者清楚地知道这不是你的母语。

当你用一种刚学会的语言写代码时,同样的事情也会发生。

然而,如果你开始用一种你很熟悉的不同编程语言的口音和惯例来写代码,你的代码可能不一定理解你要求它做什么,或者它会以一种非常低效的方式做你要求的事情

简而言之,按照预期的方式使用 Python,并使用适当的约定和模式进行编码。

作为使用正确的 Python 语法和约定的扩展,您需要确保您使用的是预先存在的库。诸如 NumPy、Pandas、Matplotlib、TensorFlow、Seaborn、SciPy、Scikit-Learn 等库已经调试完毕,可以投入生产。此外,它们正在成为许多公司工作的标准,这意味着如果您开始使用他们的首选库,您的团队将会受益匪浅。

2.代码设计得好吗?

作为数据科学家的最初几年,你的主要目标可能是编写能够正常工作的代码。当你的主要目标是生产一些运行且不破坏公司系统的东西时,规划和设计可能不是你脑海中闪过的概念。

在某一点上,当您开始扩展代码的范围并开始为生产环境做准备时,设计将变得对您很重要。

在这一点上,您将希望关注它的规划和设计,它将如何与现有代码一起工作,以及它是否按照其组件的位置进行了组织。

当你听到较少的来自工程部门的咒骂时,或者当你知道这些咒骂不适合你时,你就会知道你已经编写了设计良好的代码。

在准备代码时,一些设计参数可以让你集中注意力于迭代器和生成器(它们被很好地内置到 Python 中),责任链(每段代码必须做一件事,而且只能做一件事,以及命令模式。

3.你的代码可读吗?

你的代码组织得好吗?

是否清晰简洁?

变量和函数的名字是否有意义并且符合风格指南?

这些是你在发布代码之前需要问自己的问题。

Python 因允许用户灵活地编写混乱的代码而臭名昭著,这些代码很少或根本没有清晰性、简洁性或组织性。

尽管它很灵活,但必须遵循严格的风格约定,以确保您可以在周末休假后理解您的代码,并且新员工可以在五年后看到您的代码并成功地重构它。

风格指南是你最好的朋友。使用它,偶尔刷新一下它的内容。

4.你写过代码文档吗?

您的代码文档应该包含两部分:

  1. 使用适当的 Python 注释约定在代码中添加注释。
  2. 详细说明意见的支持文件。

每个新代码提交应该至少包括这三种类型的注释:

  1. 新提交的代码顶部的注释,简要描述了代码的目标及其功能。
  2. 每个函数顶部的注释描述了它的输入、输出和它执行的逻辑。
  3. 在不容易理解的任何逻辑或实用的一行程序的顶部添加一个注释,以便从外部查看您的代码的人可以组织并更好地理解您作为作者的想法。

支持代码文档应该在您编写大量代码的任何时候编写,这些代码一旦添加到产品代码中就会产生重大影响。该外来文件应包括:

  • 代码的目标和功能。
  • 关于如何集成代码的说明(如有必要)。
  • 对代码中棘手或难以理解的部分进行长时间的解释,你需要花时间逐行准确地描述代码做了什么,也许还需要简要地描述为什么你选择以这种方式编写代码。
  • 屏幕截图有助于调试和故障排除。
  • 外部支持文档的有用链接。
  • 如果需要其他信息或帮助,请提供您的联系信息。

5.您的代码是否针对生产环境进行了优化?

数据科学家越来越负责让他们的代码生产就绪。

这意味着在提交代码之前,您需要问自己这些问题:

  1. 您的代码是否根据需要进行扩展?
  2. 您的代码包含用于报告指标的分析器吗?
  3. 你的代码已经被优化到最高效率了吗?

这些问题都可以通过牢记一些 Python 原则来回答:

  • 使用一个分析器,它提供关于代码失败和代码性能的持续的统计信息和信息流——这就消除了判断代码是否被优化的猜测。
  • 通过仅分配和声明使代码工作所需的变量和函数来保持代码简洁——滥用变量和函数需要不必要的内存和 CPU 资源。
  • 尽可能避免循环,以减轻服务器的负担。
  • 通过使用提供改进性能的替代函数来编写高效的代码,例如xrange()join(),避免全局变量,记住使用多重赋值,以及使用集合和联合。

6.你保持简单了吗,笨蛋?

如果你想给你的朋友留下深刻印象,或者如果你想在媒体上发表一篇病毒式的文章,写一行解决问题的方法是的一个很棒的聚会技巧

然而,当需要调试和重构代码时,你正在将自己暴露在一个充满伤害的世界中。

这里的关键是要记住您在第一次学习如何编码时可能使用的旧缩写:

KeepItSimpleStupid。

这个缩写是一个很好的提醒,无论你的预测股市的一行解决方案多么令人印象深刻,它都不是最简单或最实用的解决方案。

不必要的复杂性不应该出现在你的代码中,尤其是当它涉及到一门已经很容易保持简单的语言时。不要被 Python 给你的灵活性所吸引。相反,保持你的代码简单,易读,最重要的是,易于调试。

7.你的提交信息写得好吗?

不可否认,随着项目的拖延,你的提交信息会越来越少。

每个人都曾在某个时候掉进过这个陷阱,这一天过得很长,代码流动缓慢,提交消息开始看起来越来越像一个蹒跚学步的孩子抓住了你的键盘。

然后第二天,你发现自己有一堆难以辨认的提交消息,当你最终发现一个需要修复的 bug 时,你必须对这些消息进行分类。

这里的技巧是在提交提交之前问自己这两个问题:

  1. 在远离工作的一个长周末后的第二天,你能理解提交信息吗?
  2. 您的提交消息是否遵循格式标准?

这就是写好提交消息的全部内容!

专业提示: 使用一种提交消息格式,可以让你立刻明白提交涉及到什么。例如,使用前缀标签或表情符号(使用 gitmoji )来表示提交的类型,例如:

  • [功能]或✨This 提交正在向代码中添加新功能。
  • [BUG]或者🐛该提交通知/修复了一个错误。

关键要点

  • 编写优秀的 Python 代码将增加您作为数据科学家的影响力,因为您将能够编写可以无缝集成到现有系统中的生产就绪代码,而不会受到工程部门的干扰。
  • 好的 Python 代码保持简单易读,特别注意围绕组织原则规划其设计。组织良好的代码自然会针对生产环境进行优化。
  • 您的代码应该始终伴随着您的思维过程的长形式版本,通过注释、文档和提交消息,以确保您的代码始终能够被您自己和外部用户理解。

订阅将我的故事直接发送到您的收件箱:故事订阅

请成为会员,使用我的推荐链接获得无限制的媒体访问权限(我会收到一小笔佣金,不收取额外费用):媒体会员

通过捐赠来支持我的写作,以资助更多像这样的故事的创作:捐赠

线性回归中偏差和方差的彻底检验

原文:https://towardsdatascience.com/thorough-examination-of-bias-and-variance-in-the-linear-regression-4b08bc2bb8da

概率定义和机器学习解释之间的联系

估计量的方差和偏差的数学定义和机器学习的解释是一致的吗?来源:rawpixel.com-www.freepik.com 创作的机器人手照片

为什么一个新的偏见差异职位?

在我的概率课程中,我很难清楚地理解估计量的方差偏差的定义之间的联系,以及我随后参加的机器学习课程的解释。在第一种情况下,数学定义是明确的,没有留下任何含糊不清的余地。相反,从机器学习课程的角度来看,偏差和方差通常使用视觉解释来解释,如 Scott Fortmann-Roe 的文章[2]中众所周知的解释。

受[2]启发的偏差-方差权衡。来源:[1]

它们也可以用一般规则来解释,如下面的摘录:“偏差和方差都与模型的复杂性有关。低复杂度意味着高偏差和低方差。增加复杂性意味着低偏差和高方差”[3]或“偏差-方差权衡是复杂和简单模型之间的权衡,其中中等复杂性可能是最好的”[4]。简而言之,我在下图中描述了我的担忧。

估计量的方差和偏差的数学定义和机器学习的解释是一致的吗?来源:[1]

为了调和这两种方法(数学定义和机器学习解释),我对线性回归进行了深入分析。

我看了什么?

在这篇文章中,我分析了在为线性回归模型添加解释变量(也称为特征)时,在频率主义方法和 L2 正则化贝叶斯方法中偏差和方差的变化。后者假设“β是具有指定的先验分布【5】、均值为 0 的多元正态分布和与单位矩阵成比例的协方差矩阵的随机变量。从机器学习的一般解释来看,我预计偏差会减少,方差会增加。然而,当估计量不是单个标量时,改善或恶化偏差和方差意味着什么?我们能比较两个向量估计量的偏差和协方差吗?为此,我研究了向量估计量和单个估计量的偏差和方差。

如何比较估计量?

估计器的均方误差(MSE)允许比较估计器。当估计量是标量时,定义是清楚的。然而,当估计量是多维的时,我发现了以下两个定义:

第一个[6]是矩阵,第二个[7][8]是标量。因为,在这一点上,我没有选择两个定义中的一个,我考虑了两个,首先是矩阵定义,其次是标量定义。当考虑 MSE 矩阵时,可以通过分析两个 MSE 矩阵之差的符号来比较两个估计量。如果结果矩阵是:

  • 正,那么第二向量估计量更好,
  • 负的,那么第一向量估计器更好,
  • 既不肯定也不否定,什么都下不了结论。

当在两个 MSE 定义中插入线性回归解时,结果可以分成两部分,偏差相关项和方差相关项。

矩阵均方误差定义的均方误差分解

标量 MSE 定义的 MSE 分解

分析

所有的数学证明都在一个笔记本上那里【1】,都有一个可重复的例子,其中 8 个独立解释变量 X 中的 7 个已经从正态和伽玛分布中产生(第 8 个是常数)。因变量 Y 是解释变量与系数β和随机多元正态噪声ε的线性组合:Y = Xβ+ε。一些系数被设置为 0,以考虑线性回归中无效解释变量的增加。在线性回归中考虑越来越多的解释变量时,分析了指标的偏差和方差项。例如,第一个模型只考虑一个解释变量,常数。对于所有的观测值,估计值都是相同的。

我欢迎任何反馈,更正,进一步的信息…

多维估计量

当考虑矩阵 MSE 时,我注意到,在没有正则化的线性回归中添加新变量时,方差项会增加。不幸的是,我没有观察到其他任何东西。如果矩阵 MSE 是比较估计量的合适度量,那么当增加变量时,偏差项不会系统地减少。

当考虑标量 MSE 时,我注意到更多值得注意的行为。在 Frequentist 方法中,当添加新变量时,偏差项增加,无论它是有用的变量(相关系数非空)还是无用的变量(相关系数为空),与增加的方差相反。贝叶斯方法中的偏差项大于频率项,与方差相反,贝叶斯方法中的偏差项小于频率项。根据可重现示例,所有结论如下图所示。第 2、第 3、第 7 和第 8 个变量是无用的变量,即相关的系数都是零。我特意加入了这样的变量,来说明加入无效变量时偏倚和方差的变化。正如所证明的,当增加新的变量时,Frequentist 方法中的偏差项减少。贝叶斯偏差总是大于频率主义者的偏差。类似地,当增加新变量时,频繁项中的方差项增加,贝叶斯方差总是低于频繁项方差。正如所料,当考虑所有解释变量时,Frequentist 方法中的偏差项在第 6 个变量后为零。

根据解释变量的数量,贝叶斯和频率主义方法中的标量 MSE、偏差和方差项。来源:[1]

一维估计量

当考虑线性回归模型的单个标量估计量时,对于估计量的偏差不能得出任何结论。估计量的方差在频率主义方法中增加,并且大于贝叶斯方法中的方差,如下文根据相同的可再现示例所示。

根据解释变量的数量,贝叶斯和频率主义方法中线性回归的单个估计量的偏差和方差。来源:[1]

我只显示单个估计量的偏差和方差。如果你对可视化单个预测的分布形状感兴趣,我建议你看看这篇文章“线性模型中的偏差和方差”。

结论

为了更好地理解估计量的偏差和方差与机器学习模型的偏差和方差之间的联系,我分析了频率主义者和贝叶斯(L2 正则化)方法中的线性回归。

首先,我使用了两个指标来评估线性回归的偏差和方差:整个训练估计量(在所有训练点上)的矩阵和标量 MSE,这允许在偏差和方差方面比较两个估计量。在 Frequentist 方法中,对于标量 MSE,我得到了预期的结果:当增加新的变量时,偏差项减少,方差项增加。此外,正则化减少了方差,不利于偏差。

其次,我已经使用了标量估计量的偏差和方差来评估模型的单个预测的偏差和方差。即使结果与之前的方差相似,增加一个变量也不能保证减少单个估计量的偏差。

我所有的观察总结在下表中。我观察到两个我无法证明的行为,在表格中用问号标出。

添加解释变量时偏差和方差项的变化。来源:[1]

估计量的方差和偏差数学定义和机器学习解释的协调。来源:rawpixel.com-www.freepik.com 创作的机器人手照片

参考

[1] Arnaud Capitaine,深入分析线性回归中的偏差和方差,github
【2】Scott fort Mann-Roe,了解偏差-方差权衡(2012)
【3】Ismael Araujo,偏差和方差如何影响机器学习模型(2020)
【4】Anthony Schams,线性回归中的偏差、方差和正则化:套索、岭和弹性网——差异和 概率和统计计算导论 (2010),Les Presses de l 'ENSTA,VIII.4 第 205 页
【7】Guy Lebanon,估计值的偏差、方差和均方误差(2010)
【8】Gersende Fort,Matthieu Lerasle,Eric Moulines,统计和研究 (2020),I-4

威胁建模人工智能和机器学习系统

原文:https://towardsdatascience.com/threat-modeling-a-i-and-machine-learning-systems-8c1c6b86eb21

使用威胁建模来识别 AI 和 ML 风险

UnsplashCharlesDeluvio 拍摄的照片

答人工智能和机器学习系统正在改变世界,并将成为当代最具颠覆性的技术。企业广泛采用这种系统以获得行业竞争优势,对于不习惯这种系统带来的独特风险的网络安全团队来说是一个巨大的挑战。

数据中毒、模型提取和成员推断 攻击都是网络安全团队需要及早识别和缓解的新风险。最好的方法之一是将威胁建模的概念应用到这些应用程序中。

威胁建模

威胁建模是指一种识别系统安全威胁的结构化方法,通常包括以下内容:

●系统的高层次图表

●攻击者及其动机的简介

●系统面临的威胁以及这些威胁可能如何实现的列表

威胁建模类似于风险评估,但是您采用攻击者的视角,看看他们能造成多大的损害。有许多方法和工具可用于威胁建模,我们不必在此介绍,但老实说,如果您理解核心概念,您可以使用纸笔创建威胁模型!

威胁建模人工智能应用

最简单的形式是,你为你的 AI 应用程序创建一个高层次的图表,并设想威胁将会实现的场景。

让我们以一个简单的人工智能系统为例,我们为其创建了以下高级抽象:

来源:作者

即使这是一个非常基本的概念化,你仍然可以使用它来分解 AI 系统,并列出可能成为攻击者目标的关键资产。

一些关键资产是:

●培训数据

●面向公众的 API

●机器学习模型

●托管模型的服务器

●基础管理员访问密钥或凭证

现在假设一个攻击者的观点,试着想象他们会攻击哪些区域。你不必独自完成这项工作,应该让人工智能团队中的数据科学家和技术人员一起帮助你。集思广益威胁是一个伟大的方式来确定您的技术生态系统的薄弱领域与众多的方法。

STRIDE 是微软的一种流行的威胁建模方法,我更喜欢它,它将威胁分为以下几类:

  1. 冒充 : 冒充某物或某人。
  2. 篡改 : 修改数据或代码
  3. 否认 : 声称没有执行某个动作。
  4. 信息泄露 : 将信息暴露给未被授权查看的人
  5. 拒绝服务 : 拒绝或降低对用户的服务
  6. 特权提升 : 未经适当授权获得能力

试着将你所有的威胁分成这些类别,并设想每一类至少有一个。让我们通过一些示例威胁及其缓解措施来详细了解这些类别。

电子欺骗

🚨威胁场景:攻击者可以恶意使用人工智能系统进行身份欺诈。例如,在远程采访中使用 Deepfakes 假扮成其他人的身份

🔒缓解:对敏感职位的面试进行“真实性检查”。确保人力资源经过培训,能够发现深度造假

T

🚨威胁场景:攻击者毒害数据科学家使用的第三方工具的供应链;

🔒缓解:使用前扫描软件库。确保完整性检查存在

否认

🚨威胁场景:基于欺骗威胁,攻击者可以使用 deepfakes 实施身份威胁,并将这些行为归因于另一个人。

🔒缓解措施:确保认证建立在相互独立的多个级别的系统中。

一、信息披露

🚨威胁场景:攻击者获得模型的访问权并试图复制它

🔒缓解:限制暴露的 API 上存在的限制,以限制可以发出的请求的数量。异常呼叫数量警报。输出请求中的信息有限

服务期限

🚨威胁场景:攻击者通过删除训练数据引发拒绝服务攻击

🔒缓解:定期备份镜像。限制对培训数据的访问

特权的取消

🚨威胁场景:攻击者获得管理员凭证或密钥的访问权

🔒缓解:管理员使用多重身份认证通过强化的端点访问服务器。

结论

如你所见,威胁建模与其说是一门精确的科学,不如说是一门艺术,你做得越多,就会做得越好。你使用的具体方法并不重要,但重要的是你要坚持不懈地去做,并跟踪这些风险直到结束。这项工作应与技术和业务团队合作完成,他们将定期参与人工智能系统的培训/创建。

我希望这有助于你看到威胁建模如何以一种清晰易懂的方式帮助设想人工智能的风险和威胁。从本质上来说,威胁建模就是提出“什么会出错”的问题,并在像攻击者一样思考的同时回答这个问题。在人工智能的整个生命周期中执行这个过程,每当有重大变化时,你会看到你的人工智能安全状况的切实改善

我希望你喜欢阅读这篇文章。如果你觉得这个话题很有趣,那就去看看我的书《人工智能治理与网络安全》https://www.amazon.com/gp/product/B09YHK8L2T/或者我的 教程 。请考虑使用此 链接 成为中等会员来支持我

时间序列特征工程的三种方法

原文:https://towardsdatascience.com/three-approaches-to-feature-engineering-for-time-series-2123069567be

托马斯·博尔曼斯在 Unsplash 上的照片

使用虚拟变量、循环编码和径向基函数

假设您刚刚开始了一个新的数据科学项目。目标是建立一个预测目标变量 Y 的模型。你已经从利益相关者/数据工程师那里收到了一些数据,做了一个彻底的 EDA,并选择了一些你认为与手头问题相关的变量。然后你终于造出了你的第一个模型。分数可以接受,但是你相信你可以做得更好。你是做什么的?

有很多方法可以让你跟进。一种可能性是增加你使用的机器学习模型的复杂性。或者,你可以尝试提出一些更有意义的特性,继续使用当前的模型(至少暂时是这样)。

对于许多项目,企业数据科学家和 Kaggle 等数据科学竞赛的参与者都同意,后者——从数据中识别更有意义的特征——通常可以以最少的努力对模型准确性做出最大的改进。

您有效地将复杂性从模型转移到了特性上。这些特征不必非常复杂。但是,理想情况下,我们会找到与目标变量有着紧密而简单关系的特征。

许多数据科学项目包含一些关于时间流逝的信息。这并不局限于时间序列预测问题。例如,您经常可以在传统的回归或分类任务中找到这样的特征。本文研究如何使用与日期相关的信息创建有意义的特性。我们提出了三种方法,但我们首先需要做一些准备。

设置和数据

对于本文,我们主要使用非常著名的 Python 包,同时依赖一个相对不知名的包,scikit-lego,它是一个包含许多有用功能的库,扩展了scikit-learn’s的功能。我们导入所需的库,如下所示:

为了简单起见,我们自己生成数据。在这个例子中,我们使用一个人工时间序列。我们首先创建一个空的数据框架,其索引跨越四个日历年(我们使用pd.date_range)。然后,我们创建两列:

  • day_nr–代表时间流逝的数字指数
  • day_of_year–一年的第几天

最后,我们必须创建时间序列本身。为此,我们将两条变换后的正弦曲线和一些随机噪声结合起来。用于生成数据的代码基于scikit-lego文档中包含的代码。

图 1

然后,我们创建一个新的数据帧,在其中存储生成的时间序列。该数据框架将用于比较采用不同特征工程方法的模型性能。

results_df = y.to_frame()
results_df.columns = ["actuals"]

创建与时间相关的要素

在本节中,我们描述了生成时间相关要素的三种方法。

在我们开始之前,我们应该定义一个评估框架。我们的模拟数据包含了四年的观察结果。我们将使用前 3 年生成的数据作为训练集,并在第四年进行评估。我们将使用平均绝对误差(MAE)作为评估指标。

下面我们定义一个变量,它将为我们提供服务,用于切断这两个集合:

TRAIN_END = 3 * 365

方法 1:虚拟变量

我们从你最可能已经熟悉的东西开始,至少在某种程度上。对时间相关信息进行编码的最简单方法是使用虚拟变量(也称为一键编码)。让我们看一个例子。

下面,你可以看到我们操作的输出。

首先,我们从DatetimeIndex中提取关于月份的信息(编码为 1 到 12 范围内的整数)。然后,我们使用pd.get_dummies函数来创建虚拟变量。每一列都包含观察值(行)是否来自给定月份的信息。

你可能已经注意到了,我们已经降了一级,现在只有 11 列。我们这样做是为了避免臭名昭著的虚拟变量陷阱(完美多重共线性),这在处理线性模型时可能是一个问题。

在我们的例子中,我们使用虚拟变量方法来获取记录观察的月份。然而,同样的方法也可用于指示来自DatetimeIndex的一系列其他信息。例如,一年中的某一天/某一周/某一季度,某一天是否是周末的标志,某一时期的第一天/最后一天,等等。你可以在pandas.pydata.org找到一个列表,其中包含了我们可以从pandas文档索引中提取的所有可能的特性。

额外提示:这超出了这个简单练习的范围,但是在现实生活场景中,我们也可以使用关于特殊日子的信息(比如国庆节、圣诞节、黑色星期五等等)来创建特性。是一个不错的 Python 库,包含了每个国家特殊日子的过去和未来信息。

如引言中所述,特征工程的目标是将复杂性从模型方面转移到特征方面。这就是为什么我们将使用最简单的最大似然模型之一——线性回归——来看看仅使用创建的虚拟模型我们能多好地拟合时间序列。

图 2

我们可以看到,拟合线已经很好地遵循了时间序列,尽管它有点参差不齐(台阶状),这是由虚拟特征的不连续性造成的。这就是我们接下来两种方法要解决的问题。

但是在继续之前,可能值得一提的是,当使用非线性模型如决策树(或其集合)时,我们并不明确地将特征如月数或一年中的某一天编码为哑元。这些模型能够学习有序输入特征和目标之间的非单调关系。

方法#2:使用正弦/余弦变换的循环编码

正如我们前面看到的,拟合线类似于台阶。这是因为每个虚拟对象都被单独处理,没有连续性。然而,时间等变量存在明显的循环连续性。那是什么意思?

想象一下,我们正在处理能源消耗数据。当我们包括观察到的消费月份的信息时,连续两个月之间有更强的联系是有意义的。使用这种逻辑,12 月和 1 月以及 1 月和 2 月之间的联系很强。相比之下,一月和七月之间的联系没有那么强。这同样适用于其他与时间相关的信息。

那么我们如何将这些知识融入到特征工程中呢?三角函数来拯救。我们可以使用以下正弦/余弦变换将循环时间特征编码成两个特征。

在下面的代码片段中,我们复制了初始数据帧,添加了带有月份数字的列,然后使用正弦/余弦转换对monthday_of_year列进行编码。然后,我们绘制两对曲线。

图 3

我们可以从转换后的数据中得出两个结论,如图 3 所示。首先,我们可以很容易地看到,当使用月份进行编码时,曲线是步进式的,但当使用日频率时,曲线要平滑得多;其次,我们也可以看到为什么我们必须使用两条曲线而不是一条。由于曲线的重复性,如果你在一年的时间里在图上画一条水平直线,你会在两个地方穿过曲线。这不足以让模型理解观察的时间点。但是有了两条曲线,就不存在这样的问题,用户可以识别每一个时间点。当我们在散点图上绘制正弦/余弦函数值时,这一点非常明显。在图 4 中,我们可以看到圆形图案,没有重叠的值。

图 4

让我们仅使用来自每日频率的新创建的特征来拟合相同的线性回归模型。

图 5

图 5 显示该模型能够获得数据的总体趋势,识别具有较高和较低值的时期。然而,预测的幅度似乎不太准确,乍一看,这种拟合似乎比使用虚拟变量实现的拟合更差(图 2)。

在我们讨论第三个特征工程技术之前,值得一提的是,这种方法有一个严重的缺点,当使用基于树的模型时,这一点很明显。根据设计,基于树的模型基于当时的单个特征进行分割。正如我们之前提到的,为了正确识别一个周期内的时间点,应该同时考虑正弦/余弦特性。

方法 3:径向基函数

最后一种方法使用径向基函数。我们不会详细讨论它们到底是什么,但是你可以在这里读到更多。本质上,我们再次希望解决我们在第一种方法中遇到的问题,也就是说,我们的时间特征具有连续性。

我们使用方便的scikit-lego库,它提供了RepeatingBasisFunction类,并指定以下参数:

  • 我们想要创建的基函数的数量(我们选择了 12)。
  • 用于索引 RBF 的列。在我们的例子中,这是包含给定观察值来自一年中哪一天的信息的列。
  • 输入的范围-在我们的例子中,范围是从 1 到 365。
  • 如何处理我们将用于拟合估计量的数据帧的剩余列。”drop”将只保留创建的 RBF 特征,”passthrough”将同时保留新旧特征。

图 6

图 6 显示了我们使用天数作为输入创建的 12 个径向基函数。每条曲线都包含了我们离一年中的某一天有多近的信息(因为我们选择了那一列)。例如,第一条曲线测量从 1 月 1 日开始的距离,因此它在每年的第一天达到峰值,并随着我们远离该日期而对称地减小。

根据设计,基函数在输入范围内等距分布。我们选择 12,因为我们希望 RBF 类似于月。这样,每个函数大约显示(由于月份长度不等)到一个月第一天的距离。

与前面的方法类似,让我们使用 12 个 RBF 特征来拟合线性回归模型。

图 7

图 7 显示,当使用 RBF 特征时,该模型能够准确地捕捉真实数据。

使用径向基函数时,我们可以调整两个关键参数:

  • 径向基函数的数量,
  • 钟形曲线的形状——可以用RepeatingBasisFunctionwidth参数修改。

调整这些参数值的一种方法是使用网格搜索来确定给定数据集的最佳值。

最终比较

我们可以执行下面的代码片段,对编码时间相关信息的不同方法进行数值比较。

图 8

图 8 说明了径向基函数从所考虑的方法中产生最接近的拟合。正弦/余弦特征允许模型拾取主要模式,但不足以完全捕捉系列的动态。

使用下面的代码片段,我们计算了每个模型在训练集和测试集上的平均绝对误差。我们预计训练集和测试集之间的分数非常相似,因为生成的序列几乎完全是循环的——年份之间的唯一差异是随机成分。

自然,在现实生活中不会这样,在现实生活中,随着时间的推移,我们会遇到更多的相同时期之间的可变性。但是,在这种情况下,我们还会使用许多其他特征(例如,一些趋势或时间流逝的度量)来解释这些变化。

如前所述,我们可以看到使用 RBF 特征的模型得到了最佳拟合,而正弦/余弦特征表现最差。我们关于训练集和测试集之间分数相似性的假设也得到了证实。

外卖食品

  • 我们展示了三种将时间相关信息编码为机器学习模型特征的方法。
  • 除了最流行的虚拟编码,还有更适合编码时间循环特性的方法。
  • 使用这些方法时,时间间隔的粒度对于新创建的要素的形状非常重要。
  • 使用径向基函数,我们可以决定想要使用的函数的数量,以及钟形曲线的宽度。

您可以在我的 GitHub 上找到本文使用的代码。一如既往,我们非常欢迎任何建设性的反馈。你可以在推特或评论中联系我。

喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用 这个链接 成为会员,你就支持我,不需要你额外付费。提前感谢,再见!

您可能还会对以下内容感兴趣:

https://medium.com/geekculture/investigating-the-effects-of-resampling-imbalanced-datasets-with-data-validation-techniques-f4ca3c8b2b94

参考

所有图片,除非特别注明,均为作者所有。

最初发表于 NVIDIA 的开发者博客2022 年 2 月 17 日

揭示用户旅程的三种方法

原文:https://towardsdatascience.com/three-approaches-to-uncover-user-journey-98071e98e7eb

通过构建能够产生强大洞察力的数据系统,更好地了解全局

公司投资数据科学只是因为它服务于他们的关键路径,即创造收入或节省成本。数据科学的独特之处在于它能够通过分析历史自动发现可行的方法。这种能力增强了获取客户的能力,这是关键路径中的一个关键部分。公司可以通过扩大已被证明有效的产品和削减无效的产品来更有效地获得客户。具体来说,公司关心他们的客户来自哪里,他们何时转换或放弃,以及为什么。

在“连接数据战略中的点”一文中,我讨论了构建一个数据系统作为用户旅程的“数字双胞胎”如何帮助一家公司理解大图并回答上述基本问题。本文将深入探讨构建这种数字双胞胎的三种实用方法。

图片来自 Unsplash

用桑基图描绘高级用户旅程

作者图片

桑基图是最流行的图解顾客旅程的图。它显示了不同的用户组如何从一个点移动到另一个点,哪些用户路径最受欢迎,以及人们在哪里下车。由于 Sankey 图在可视化方面的优势,它是许多数据分析软件的关键特性。

桑基图最适合于高层商业决策。例如,如果图表显示一个特定的渠道驱动了大部分的流量,并且对一个企业来说具有高转换率,那么它将从加倍投资该渠道中获益。另一方面,如果用户经常在与网站进行特定的交互后离开,那么就有必要调查一下这个接触点出了什么问题。

然而,Sankey 图需要仔细的用户旅程映射才能正确工作。对于公司来说,试图通过为每个可能的接触点建立跟踪机制来映射网站上或应用程序中的用户交互是一个难以置信的挑战。这变成了一个悖论:需要了解用户旅程的公司往往没有对它的完整见解,因此无法绘制出旅程中所有重要的接触点。然而,只有在绘制了接触点并为其建立了跟踪机制时,桑基图才是准确的。

此外,桑基图没有讲述用户旅程背后的故事——为什么用户选择一条路径而不是另一条路径或放弃。幸运的是,第二种和第三种方法可以弥补桑基图的缺陷。

用户交互深入了解会话重放

会话重放是一种通过会话记录和回放历史用户交互的技术。由于它会自动记录每一次用户交互,因此不需要事先绘制用户旅程地图。因此,它大大降低了公司开始使用数据科学的门槛。

作者图片

会话重放记录用户屏幕或点击流数据以及每次点击或移动之间的时间。它为产品经理、设计师和工程师解释用户行为提供了丰富的细节,例如用户是否在特定屏幕上遇到问题或困惑,以及什么可能导致这些问题。

热图提供了更多方向

对于一些网页,公司不需要对每个接触点进行粒度跟踪,但对页面级用户交互的洞察仍然是有益的。例如,许多公司在有机营销上花费了大量资源,如在网站上放置创意和博客,他们需要了解用户是否查看或点击了内容。

测绘和跟踪所有的创意和博客将需要大量的工作,特别是考虑到这些经常更新和改变立场。公司也没有必要使用会话重放来了解所有用户交互细节。在这种情况下,热图是一个很好的选择。

作者图片

热图显示网页上的哪些部分更受关注。它帮助公司将关键内容转移到最受关注的地方,并可能重新设计网站或应用程序,将内容呈现在用户面前。

选择正确的解决方案

虽然每个例子都有优点和缺点,但结合一个或多个例子有助于公司获得用户旅程的必要细节。

在接下来的文章中,我将继续深入研究获取客户的数据科学技术。如果你想聊聊他们,请随时在 Linkedin 上联系我。

在 Python Pandas 数据帧中解析 JSON 文档的三种情况

原文:https://towardsdatascience.com/three-cases-when-parsing-json-documents-in-a-python-pandas-dataframe-9c9dfea9ec34

图片由 Flore W 来自 Pixabay

如果你知道这些技巧,在 Pandas 中标准化 JSON 对象并不困难

我们在做一些数据科学工作时,不得不处理 JSON 文档这样的半结构化数据是相当常见的。作为 Python 中最流行的数据处理框架,Pandas 提供了内置的 JSON 规范化特性“json_normalize()”。

当然,这篇文章的目的不仅仅是介绍如何在 Pandas 中使用 JSON 规范化方法。在现实世界中,数据并不完美。例如,当我们使用 JSON normalize 方法时,JSON 对象中可能会有丢失的数据,这可能会导致错误。

在本文中,我将描述三种情况,当我们试图用 Pandas 中丢失的数据来规范化 JSON 文档时。

0.熊猫 JSON 标准化方法

图片来自 Pixabay

在我们讨论特殊情况之前,让我们先看看json_normalize()方法在正常情况下的用法。假设我们有这样一个 JSON 文档。我们可以从 JSON 对象创建一个熊猫数据帧,如下所示。

import pandas as pddf = pd.DataFrame({
    'student_id': [1, 2, 3],
    'student_name': ['Alice', 'Bob', 'Chris'],
    'student_info': [
        {'gender': 'F', 'age': 20},
        {'gender': 'M', 'age': 22},
        {'gender': 'M', 'age': 33}
    ]
})

好的。现在,student_info字段嵌套在 JSON 对象中。是时候使用json_normalise()方法从 JSON 对象中解码它了。

pd.json_normalize(df['student_info'])

该方法非常方便。它聪明地计算出所有 JSON 对象的属性,并将它们用作列名。然后,提取它们的值并将它们转换成表格格式。

如果想把它放回原来的数据帧,可以用熊猫里的concat()方法。

df = pd.concat([
    df.drop('student_info', axis=1), 
    pd.json_normalize(df['student_info'])], 
    axis=1
)

案例 1 — JSON 作为字典

图片由 Liselle VDPixabay 获得

现在,让我们看看 JSON 对象中丢失数据的一些情况。在第一种情况下,假设我们已经有了 Python 字典格式的 JSON。

df = pd.DataFrame({
    'student_id': [1, 2, 3],
    'student_name': ['Alice', 'Bob', 'Chris'],
    'student_info': [
        {'gender': 'F', 'age': 20},
        {'gender': 'M', 'age': 22},
        None
    ]
})

在这种情况下,所有的student_info类型都是 Python 字典。

本案例模拟学生“Chris”的缺失数据。对他来说没有student_info。如果我们试图使用json_normalize()方法,将会抛出一个错误。

然而,我们不想使用dropna()来删除这些行,因为还有其他有用的字段。在这种情况下,我们需要用一个空字典来填充【无】student_info

到目前为止,我相信没有问题。难的是我们可以很容易的使用fillna()方法如下。

df['student_info'].fillna({})

这根本行不通。

这是因为fillna()方法需要一个标量/文字值或者一个字典、序列,甚至是数据帧。换句话说,如果它是一个标量或文字值,它将用于填充所有缺失的单元格。否则,它必须是一个集合类型,可以告诉哪个单元格将填充什么。

显然,空字典{}dict()不是标量,但不能用来告诉程序哪些字段应该填充什么值。因此,我们必须使用数据帧的索引来组成字典。

用于填补漏洞的值(例如 0),或者是值的字典/系列/数据框架,指定每个索引(对于系列)或列(对于数据框架)使用哪个值。不在字典/系列/数据框架中的值将不会被填充。该值不能是列表。

df['student_info'].fillna({i: {} for i in df.index})

现在,我们可以使用json_normalize()方法。

熊猫的重要更新

在此添加本节是为了澄清上述问题已在 Pandas 更新版本 1.3.0 中涵盖。换句话说,上面的错误只会出现在 1.2.5 或更低版本中。

案例 2 —字符串形式的 JSON

图片来自茱莉亚·罗曼来自 Pixabay

在这种情况下,让我们假设我们得到的 JSON 文档是字符串格式的。这在实践中很常见。想象一下,我们从一些 CSV 文件中读取数据,这些文件是从 NoSQL 数据库中转储的(有人可能会这样做,不要惊讶)。

样本数据如下。

df = pd.DataFrame({
    'student_id': [1, 2, 3],
    'student_name': ['Alice', 'Bob', 'Chris'],
    'student_info': [
        '{"gender": "F", "age": 20}',
        '{"gender": "M", "age": 22}',
        None
    ]
})

在这种情况下,我们需要使用一些魔法将 JSON 字符串转换成 Python 字典。我们可以使用内置的 JSON 库来加载它们,并将json.loads()方法放入pands.apply()方法中。然而,有更简单的方法。那就是使用 AST(抽象语法树)中的literal_eval()方法,这也是一个内置的库。

顺便说一句,避免使用eval()方法是很好的方式,因为它会立即评估一切,而不需要任何安全检查。不管我们之后会对数据做什么,我们都应该使用literal_eval()。简单来说,后者只会对字符串、字节、数字、元组、列表、字典、集合、布尔、None 求值。

from ast import literal_evalmy_dict = literal_eval('{"gender": "F", "age": 20}')type(my_dict)

现在,我们可以使用literal_eval()方法将 JSON 字符串转换成 Python 字典吗?它将完成工作,但是不要忘记我们仍然没有价值。

df['student_info'].apply(literal_eval)

解决方案并不复杂,只需用一个空字典填充None值,但采用字符串格式'{}'。所以,它将被literal_eval()方法转换成一个空字典。

df['student_info'] = df['student_info'].fillna('{}')df = pd.concat([
    df.drop('student_info', axis=1), 
    pd.json_normalize(df['student_info'].apply(literal_eval))], axis=1)
df

案例 3 —字符串形式的 JSON 数组

来自 PixabayKAVOWO 的图像

最后,源数据中有大量 JSON 数组对象并不少见。如果能把它们读入 Python list,我们消费起来就容易多了。然而,有时它们也可能是字符串。

让我们这样来考虑这个案例。

df = pd.DataFrame({
    'student_id': [1, 2, 3],
    'student_name': ['Alice', 'Bob', 'Chris'],
    'student_exam': [
        '[{"math": 90, "english": 85}]',
        '[{"math": 85}]',
        None
    ]
})

出于某种原因,这就是我们拥有的数据。我们没有别的选择,就改造吧。

由于它们也是字符串,我们可以再次使用literal_eval()方法将它们转换成真正的 Python 列表。这一次,我们需要分别用'[]'填充 None 值。

df['student_info'] = df['student_info'].fillna('[]').apply(literal_eval)

然后,重要的部分是我们需要使用 Pandas 中的explode()方法从列表中提取值。如果一个列表中有多个项目,那么这个特定的行将被重复几次,这样每个项目都在一行中。

此外,使用explode()方法不会产生数据帧的新索引。如果有任何包含多项的列表,数据帧索引也将重复。因此,我们可以添加reset_index()方法来重置索引,然后删除旧的。

下一步,我们可以毫无问题地使用json_normalize()方法。

df = pd.concat([
    df.drop('student_info', axis=1), 
    pd.json_normalize(df['student_info'])], 
    axis=1
)

摘要

图片由Seth OS来自 Pixabay

在这篇文章中,我介绍了 Pandas 框架中最方便的方法之一json_normalise()。它很容易使用,可以节省大量的时间和精力,虽然有时它不能处理一些特殊情况。本文展示了 JSON 文档中有空值的 3 种情况以及如何处理它。

https://medium.com/@qiuyujx/membership

如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)

数据预处理的三个关键要素—第 1 部分

原文:https://towardsdatascience.com/three-critical-elements-of-data-preprocessing-part-1-3c16f46f8ced

数据科学中建模的主干。

沙拉碗,就像一个混合数据集。安娜·佩尔泽在 Unsplash 上的照片

在本文中,我将分享数据科学项目生命周期中数据预处理步骤的主要组件,并提供一些有价值的资源来有效地执行这一步骤。

作者图片

数据预处理是将不同来源的原始数据转换成可用于获得可操作见解的精炼形式的关键步骤。它需要整合、清理和改造。

作者图片

此外,数据预处理确保机器学习模型可以获得高质量的数据,从而实现出色的预测性能。事实上,建模中的“垃圾进垃圾出”在很大程度上依赖于提供给模型的数据质量。

因此,数据预处理可以被描述为建模的主干。

用于数据预处理的工具选择是 Pandas 和 Numpy,但是,也可以使用其他语言的等效库,并且从数据库中提取数据主要是通过 SQL 查询来完成的。

本系列的每一部分都将详细介绍数据预处理的一个关键要素,从数据集成开始。

数据集成

数据预处理的这一部分包括利用不同数据集之间的关系,通过使用相似的特征作为连接点来组合它们。

数据集成技能可以帮助数据科学家利用孤岛中可用的信息数据,从而从现有资源中创造更多的商业价值。

数据集成可以通过使用 SQL 查询直接连接到不同的数据源并返回由数据源的属性组成的单个数据集来执行。

或者,可以编写单独的查询来从不同的源提取数据,并且可以使用 Pandas 和 Numpy 等 python 库来组合数据以产生所需的数据集。

根据我的工作经验和 Python 编程知识,上面的选项 2 是我的首选方法。

数据集成期间执行的关键操作包括:

加入

该操作会导致列数的增加,而主数据的行数会根据联接的类型发生变化或不发生变化。例如,该动作可用于通过向现有训练数据添加新特征(列)来丰富机器学习模型的输入数据。

在 Python 中,Pandas 的 Concat、Merge 和 Numpy 的 Concatenate 模块可用于执行连接操作。

下图显示了不同类型的连接:

图片由 Arbeck 提供,CC 由 3.0 提供,来自维基媒体

资源:

SQL 连接:https://www.w3schools.com/sql/sql_join.asp

熊猫 Concat:https://pandas . pydata . org/docs/reference/API/pandas . Concat . html

熊猫合并:【https://pandas.pydata.org/docs/reference/api/pandas. DataFrame.merge.html

numpy Concatenate:https://numpy . org/doc/stable/reference/generated/numpy . Concatenate . html

工会

此操作增加了主数据集的行数,而不改变列数。例如,该动作可用于增加可用于训练机器学习模型的示例数量,以减少过度拟合。要联合的所有数据集必须具有相同的要素,返回的数据集才可用。

执行工会操作时,必须小心避免重复数据。如果允许,UNION ALL 操作允许在返回的数据中表示两个数据集的所有数据,而不考虑重复的示例。

Pandas Concat 也可以用于执行 union 操作。

联合对联合所有(图片由作者提供)

资源:

SQL 联合:

  1. https://www.w3schools.com/sql/sql_union.asp
  2. https://www.tutorialspoint.com/sql/sql-unions-clause.htm

结论

在本文中,我们探讨了数据集成,这是数据科学项目生命周期中数据预处理步骤的关键组成部分。它包括组合不同来源的数据,以获得包含所有可用相关特征和示例的数据集。

在下一篇文章中,我们将讨论数据清理,这是数据预处理的另一个关键部分。

我希望你喜欢阅读这篇文章,直到下次。干杯!

什么更有趣?你可以通过下面我的推荐链接订阅 Medium 来获得更多我和其他作者的启发性文章,这也支持我的写作。

https://aolaoye.medium.com/membership

数据预处理的三个关键要素—第 2 部分

原文:https://towardsdatascience.com/three-critical-elements-of-data-preprocessing-part-2-2078110ae8e7

数据科学中建模的支柱

Unsplash 上由Towfiqu barb huya拍摄的照片

数据预处理是数据科学项目生命周期中的主要步骤之一,包括将原始数据转换为适合数据分析的精确形式。

作者图片

在本系列的第一篇文章中,我介绍了数据预处理的数据集成组件,它涉及到组合来自不同来源的数据,以获得包含所有可用相关特性和示例的数据集。该文章的链接可在此处找到:

在本文中,我将讨论数据预处理的下一个组成部分,也可能是建模目的中最关键的部分,即数据清洗。此外,我将分享处理数据清理过程不同部分的资源。

作者图片

数据清理

这是从收集的数据集中识别并移除或纠正重复、损坏和缺失数据的过程。

作者图片

数据清理提高了输入机器学习算法的数据质量,可以成就或破坏一个数据科学项目。尽管通常是一个耗时的过程,但数据清理会产生巨大的好处,尤其是在提高模型性能方面,因为模型的好坏取决于它接收到的数据。

因此,生成更清晰的数据比花费更多的计算能力和时间调整复杂的算法要好。

数据清理过程包括以下任务:

纠正结构性错误

这包括识别和修复数据中的不一致。例如,分类特征可能被标注为不同的大写字母(男性与男性),或者目标变量可能被分配到错误的类别。后者很难检测,可能需要领域专家的知识才能发现。

Pandas DataFrame 中的 value_counts 方法可用于调查数据集中每一列的唯一标签。此外,独特标签计数的条形图可用于直观检查数据中的不一致性。

资源:

数据清理—https://www . tableau . com/learn/articles/what-is-Data-cleaning #:~:text = Data % 20 cleaning % 20 is % 20 进程,to % 20be % 20duplicated % 20or 或%20mislabeled

熊猫值计数—https://pandas . pydata . org/pandas-docs/stable/reference/API/pandas。DataFrame.value_counts.html

处理缺失值

根据正在处理的缺失值的普遍程度和类型,可以估计缺失值或删除受影响的观察值(示例)。

根据经验,当缺失值的百分比“非常小”时,我会建议放弃观察值(比如< 5%) compared with overall available data. Similarly, features with more than 95% of the data missing may be dropped although these are hard not thresholds and can be changed based on domain knowledge.

Missing values occur in several forms including:

(1) 完全随机缺失(MCAR): 在这种情况下,缺失数据与观察到的或未观察到的样本无关,不会引入偏差。因此,它们可以被删除。但是,可以分析的总人口比例减少了。

(2) 随机缺失(MAR): 这里的缺失数据依赖于观测数据。例如,受观察数据属性(如年龄或性别)影响的缺失值可能会随机出现,但可能会也可能不会在数据集中引入偏差。这些值可以使用内插法或其他基于观察数据的统计估计来估算。

(3) 非随机缺失(MNAR): 在这种情况下,缺失数据依赖于未观察到的数据,来自这类数据集的洞察更有可能出现偏差。这些缺失值通常是不可忽略的,不能用标准方法估算,因此很难分析。另一方面,有一类 MNAR 称为可分析的结构性缺失数据。

资源:

https://www.ncbi.nlm.nih.gov/books/NBK493614/

处理异常值

异常值是存在于给定变量的预期值范围之外的数据点。根据定义,预期范围是主观的,取决于调查领域。

但是,有一些处理异常值的方法,包括彻底消除受影响的数据点,根据数据分布将值剪切到某个阈值,以及估计数据点的实际值(将该点视为缺失值)。

并非所有的异常值都是平等的。有些只是干扰你的机器学习模型的噪音,而另一些则是你的数据的真实属性的表示。

消除“好的”异常值可能会危及数据清理过程,并导致不具代表性的数据模型。

领域知识和专家咨询是发现差异的好方法。

你如何发现异常值?以下是检测异常值的方法列表:

(1) 数据可视化:箱线图和直方图对于快速识别数据中的异常值很有用。许多绘图工具,如 Seaborn、Tableau 和 Power BI,都具有创建这些图形的功能。

原始照片由罗伯斯布(语言由鲁迪格 85 更改), CC-BY-SA-3.0 ,通过维基媒体

(2) 标准差阈值:对于近似正态分布的数据,离群值可以定义为距离均值+/-x 标准差的数据点。其中取决于应用领域,x 的值通常在 1 至 3 的范围内。

(3) 四分位数范围阈值:异常值可以定义为在正负方向上位于四分位数范围 1.5 倍(1.5IQR)之外的数据点。其中四分位数间距是第三(上)四分位数和第一(下)四分位数之间的距离。阈值可以增加到 3IQR 以检测极端的异常值。

(4) 假设检验:根据数据分布,统计检验可用于检测数据集中异常值的存在。一些例子包括 Grubb 检验、Dixon 的 Q 检验和卡方检验。在这种方法中,零假设表明数据中没有异常值,而替代假设表明至少有一个异常值。在显著性水平为α(比如 0.05)的情况下,如果测试的 P 值小于α,则拒绝零假设,并推断存在异常值。

(5) 异常检测模型:可以构建监督和非监督机器学习模型,以基于数据集中的其他预测特征来学习变量的典型值。然而,这种方法在计算上是昂贵的,甚至是过度的。

资源:

识别异常值的方法—https://statisticsbyjim.com/basics/outliers/

异常值检测的假设检验—https://www . dummies . com/article/technology/information-technology/data-science/big-data/hypothesis-tests-for-data-outliers-141226/

去除错误的观察值

在数据整合过程中,一些观察结果可能会重复或损坏。消除受影响的数据点有助于避免数据模式的错误表述或建模过程中的过度拟合等问题。因此,清除错误的数据点可以显著提高模型性能。

结论

在本文中,我介绍了数据清理,这是数据预处理的一个关键元素。正如我们所看到的,这个过程非常复杂,但是它在模型性能改进方面有很大的好处。

在本系列的下一篇也是最后一篇文章中,我将讨论数据转换,其中也包括数据缩减策略。

我希望你喜欢这个系列,直到下次。干杯!

什么更有趣?你可以通过下面我的推荐链接订阅 Medium 来获得更多我和其他作者的启发性文章,这也支持我的写作。

https://aolaoye.medium.com/membership

数据预处理的三个关键要素—第 3 部分

原文:https://towardsdatascience.com/three-critical-elements-of-data-preprocessing-part-3-6a7da681ae16

数据科学中建模的主干。

克里斯·劳顿在 Unsplash 上的照片

在本文中,我将讨论数据转换,这是数据科学项目生命周期中数据预处理步骤的一个关键元素。

作者图片

数据预处理是将来自不同来源的原始数据转换成可用于获得可操作见解的精炼形式的过程。它需要整合、清理和改造。

在本系列的第 1 部分中,我们讨论了数据集成,将不同来源的数据组合起来,获得一个包含所有可用相关特性和示例(如沙拉碗)的数据集😊。详情如下:

随后,我们探讨了数据清理,即在收集的数据集中查找和修复重复、损坏和丢失的数据的过程。详情可在此处找到:

在这里,我将从数据科学中建模的角度介绍数据预处理难题的最后一部分,即数据转换。

数据转换

在机器学习的上下文中,数据转换是将数据转换成最能代表数据模式并适合模型拟合的适当格式或结构的过程。

如果我们在建模之前恰当地应用转换,我们可以从数据中挤出更多的汁液。

机器学习算法接受不同的数据格式和类型,尽管数字数据是最可接受的格式。其中,数字数据是可以是小数或整数的数字,其值的范围从-无穷大到+无穷大。

相比之下,分类数据是表示为字符串的定性特征(例如,状态特征可以将“开”或“关”作为唯一的类别)。数据集还可能包含具有“真”或“假”特征值的布尔数据类型。

以下数据转换通常适用于数据科学建模,并且非常有价值。

特征编码

这是将分类数据转换成数字数据的过程。存在两种主要的方法,即顺序编码和独热编码。

序数编码:在这种情况下,分类数据中的层次结构在转换后保持不变。例如,风险级别特征可以转换如下:低风险-0,中风险-1,高风险-2。熊猫图书馆的顺序编码器可用于此操作。

One-hot 编码:这种方法在分类特征中没有顺序,并且很少有唯一的类别(低基数)时使用。因为为每个类别创建了一个新列,所以当将这种方法应用于具有高基数的特性时,数据大小会显著增长。在这种情况下,可以应用基数编码,如这里的所述

离散化

通过创建离散化数据的类区间可以更好地将连续数据呈现给算法。例如,一组年龄范围(0-12:0,13-19:1,20-35:2,35+:4)可以从连续年龄数据中创建,转换后的数据具有更好的预测能力。用于离散化的有用的熊猫方法包括切割q 切割

此外,二进制化是一种特殊类型的离散化,它涉及将特征值分配给两组中的任何一组,即 0 或 1。Scikit-learn 预处理模块中的二进制化工具可用于该操作。

分布映射

当输入数据具有特定分布(例如正态分布)时,一些机器学习算法表现更好。绘制分布图的著名方法包括:

均匀映射:这涉及到将数据映射到具有同等可能性结果的均匀分布。更多详情可点击查看。此外,Scikit-learn 中的分位数转换器工具可用于此操作。

高斯映射:这里,数据被映射成尽可能接近正态分布,平均值、中值和众数大致相同。更多细节可以在这里找到。此外,Scikit-learn 中的电源变压器工具可用于此操作。

可以说,变换数据分布并不总是一个好主意,因为会产生意想不到的影响,例如掩盖残差的真实行为。更多解释可以在这里找到。

数据缩放

此过程可确保将具有不同单位和量值范围的要素转换为相同的比例,以避免将数据误报给模型。存在几种数据缩放方法,但为了简洁起见,我在这里只简要描述几种,如果有兴趣,还提供了进一步研究的链接。

标准化:这包括减去平均值并除以标准差。它确保数据以零为中心,并根据标准偏差进行调整。更多详情可在这里找到。

标准化:该方法确保每个观察值或每个特征的数据值都有一个单位标准。更多细节可以在这里找到。此外,可以使用 Scikit-learn 预处理模块中的 normalize 方法。

缩放到一个范围:这里,给定特征的数据值被映射到一个特定的范围。它通常包括减去平均值,然后除以要素的最小值和最大值之间的差值。更多详情可点击查看

其他缩放方法包括使用最小和最大阈值的对数缩放和限幅值。这个免费的 Google 课程对数据缩放(规范化)进行了更深入的解释。不同的缩放方法对有异常值的数据的影响可以此处

数据还原

在数据转换过程中,可能会出于很好的理由创建许多新功能。然而,随着特征数量的增加,计算成本和时间也会增加。此外,过多的特征可能会导致过度拟合等问题。这个问题通常被称为维数灾难。

因此,我们可能需要减少特征的数量,以有效地建立机器学习模型,同时提高预测性能。

多重共线性(两个或多个独立要素高度相关)是可能修剪要素的另一个原因。它会影响模型性能和可解释性,尤其是非基于树的算法,如线性回归。更多关于多重共线性的细节可以在这里找到。

数据简化的一些方法包括:

主成分分析:这是一种非常有用的方法,可以将数据特征映射到一个较低的正交维度空间,同时尽可能多地保留数据中的信息。然而,变换后的特征不像原始特征那样可解释。因此,它们在某些应用中可能不被使用。更多细节可以在这里找到。另外,Scikit-learn 中的分解模块有一个 PCA 工具可以用于这个动作。

特征消除:在这种情况下,最不相关的特征被去除,同时保留最具预测能力的特征。使用直观且大多可解释的原始特征,这避免了 PCA 遇到的可解释性问题。该方法可以递归执行,如这里的所述

结论

在本文中,我们讨论了数据转换,即将数据转换成适合模型的格式的过程。此过程还可能包括一些讨论过的数据简化策略。

这里探讨的数据转换与大多数数据科学建模应用程序相关,但并不详尽。应该注意的是,还有其他特定于不同领域的转换,例如用于自然语言编程的符号化和用于时间序列分析的滞后特征的特征创建。

这就把我们带到了数据预处理系列的结尾。耶!!我希望你喜欢这些文章,直到下次。干杯!

什么更有趣?你可以通过下面我的推荐链接订阅 Medium 来获得更多我和其他作者的启发性文章,这也支持我的写作。

https://aolaoye.medium.com/membership

实用数据科学家的三项基本软技能

原文:https://towardsdatascience.com/three-essential-soft-skills-for-practical-data-scientists-e73ce99f7018

克里斯·长滨在 Unsplash 上的照片

为什么技术知识不是你应该关注的唯一事情。

数据科学家倾向于关注硬技能。他们喜欢学习新的主题,并希望发现该领域的最新发展。当然,玩 DALL-E 2 比花时间做演示更有趣。有时很容易忘记软技能,尽管它们是成为优秀数据科学家的重要组成部分。

这篇文章解释了数据科学家的三个基本软技能。如果你练习它们,它们会帮助你,节省时间,让你脱颖而出。我们开始吧。

注意:我喜欢区分专注于人工智能研究的研究数据科学家和为公司开发人工智能应用的实用数据科学家。这三种技能对这两种类型的数据科学家都有用,尽管本文是以实用的数据科学家为中心撰写的。

管理期望

许多利益相关者期待数据科学项目带来革命性的变化。我们不是都认识一个过分热情的管理者,想用 AI 代替完整的流程吗?还是承诺给公司增加几十亿人工智能的首席执行官?在雇佣了一群数据科学家并等待数月(或数年)后,这些人会感到失望。为什么不彻底改变公司或流程?他们以为 AI 会给他们金山,但它没有。这很难实现,每个人都继续做着和以前一样的事情(在最坏的情况下)。

“人工智能在短期内被高估,但在长期内被低估。”—阿马拉定律(编辑)

为了防止失望的发生,你可以做几件事。除了开始设计良好的概念证明,其中的问题是明确的,你需要管理你的利益相关者的期望。你需要解释人工智能不是魔法,不能改变杂乱的数据或糟糕的基础设施。您可以解释使解决方案在生产中更难工作的依赖关系。每一两周组织一次与利益相关者的会议,在会上解释进展并谈论挫折。如果你不能解决问题,就寻求帮助。当你认为人工智能不是解决某个问题的最佳方式时,说不,并解释原因。保持过程的透明和清晰将有助于你和公司。

也有相反的一面,人们对人工智能持批评态度。他们可能会想:‘人工智能将来会取代我吗?’或者“我不明白,这很危险。”。在这种情况下,管理预期也很重要。在大多数情况下,人工智能不会取代它们,但它会取代重复、枯燥的任务。他们有更多的时间发挥创造力,为公司发现机会。这条信息可以改变你与这些人合作的方式。

说不是管理期望的一个重要部分。照片由杰玛·埃文斯Unsplash 上拍摄

解释难懂的概念和讲故事

有很多原因让你需要有表达技巧。例如,你想让人们相信你的人工智能解决方案的一个用例。当你用简单明了的语言解释为什么需要开发你的解决方案时,更容易说服他们。或者,如果你开发了一个成功的人工智能应用,人们会要求你解释它是如何工作的,并展示出来。申请工作时,表达能力也会派上用场。

如果你没有演讲经验,也不喜欢成为关注的焦点,一开始可能会很难。让难懂的概念变得简单也很困难。没有金科玉律,但是你应该记住的一件重要的事情是:我的观众需要知道什么,他们的能力水平如何?如果你需要在整个公司面前讲话,很多人没有数据科学背景,保持简单,让它变得有趣(添加实际例子,删除文本和公式,添加图像或动画)。如果你有一小部分特定的观众,多解释一些他们感兴趣的东西(不要用数学让销售人员厌烦)。如果人们想知道更多,他们可以随时提问。或者你可以和一个更小的小组安排一次深入的会议。

应该从哪里开始学习这项技能?如果你想用一种简单的方式解释难懂的概念,你可以在 YouTube 或 Google 上搜索,看看别人是如何解释的。或者你可以从实践中举一个大家都能理解的简单例子。很多情况下,直观的理解就足够了。如果你想创建简单易懂的图表,我可以推荐《T4 用数据讲故事》这本书。

"尽可能让你的听众感到轻松."

不要把数学公式扔给不需要知道或使用它的人。丹·克里斯蒂安·pădureț在 Unsplash 上拍摄的照片

好奇心

这个技能是双重的。一方面,好奇心很重要,这样你才能了解人工智能的最新发展,并不断提高自己。另一方面,好奇心对于获得启动一个项目(或在项目期间)所需的所有信息很重要。本节重点讨论后者。

如果你有点像我,爱解决问题。当有人来问你:‘你能帮我吗?’你跳进去开始解决它。几个星期后,你和那个人联系,展示你的解决方案。他说:“这不是我真正需要的!你回去后需要重做很多项目。太早开始是一个陷阱,因此错过了重要的信息。你需要有好奇心才能触及问题的核心。

这种技能是必不可少的,因为数据科学家必须处理大型和困难的问题。作业的潜在问题是什么?项目什么时候成功?基线是什么?过去做了什么来解决问题,那些实验的结果在哪里?你是执行这个项目的合适人选吗?不正确的预测会产生什么影响?我们如何使项目在生产中发挥作用?该解决方案如何连接到现有系统?问好问题会对你有帮助,会节省你很多时间。你不会面临意想不到的惊喜,并且能够检查你的假设。问题和限制将被阐明,您将理解业务动机和技术需求。

如果你发现很难提出正确的问题,不要担心。有工具可以帮助你做到这一点。例如,您可以填写一个用例画布,它允许您监控问题的所有方面。这里的和这里的就是一些例子。

"启动一个好的项目就是要问正确的问题."

框架外还有更多。照片由派恩瓦特Unsplash 上拍摄

从哪里开始?

这些技能有一个共同点:都是关于沟通的。一些幸运者可以给出漂亮的演示,当场提问并以每个人都能理解的方式解释,但大多数人需要在现场练习和学习这些技能。如果你想参加课程,产品负责人课程可以帮助你管理期望。还有很多展示课程。但是最好的学习方法是开始做:下次有人让你做演示的时候,不要犹豫!

祝您好运,如果您有任何问题、补充或其他问题,请联系我们!

别忘了 订阅 如果你想在我发表新文章时收到电子邮件。

在选择 Apache Airflow 作为工作流管理平台之前,需要了解三个有用的技巧

原文:https://towardsdatascience.com/three-helpful-things-to-know-on-choosing-apache-airflow-workflow-management-platform-42dc4073ae11

帮助您决定选择 Apache Airflow 的建议

Unsplash 上的 Yaakov Winiarz 拍摄的照片

Apache Airflow 是工作流管理平台的绝佳选择。然而,这并不意味着气流可以成为盲目的选择。在 StackOverflow 中有许多讨论,工程师提出了超出气流设计用途的问题。总的来说,气流对所有用例来说都更好。在决定最终采用气流之前,需要评估一些注意事项。本文将深入探讨在选择 Apache Airflow 工作流管理平台时需要了解的三件有用的事情。即使 Airflow 已经在您的项目中作为工作流管理工具被采用,这篇文章仍然可以帮助改进用例,以进行下一步工作或者提供一个替代的解决方案。

气流不是拖拽工具,气流需要编码

传统上,工作流管理工具不要求人们具有深入的编程知识。SQL 通常足以在 2000 年(2000-2010 年)的这些角色中取得成功。像微软(SSIS)和 Informatica 这样的公司提供拖放工具来满足市场这样的需求。

拖放式工作流管理工具非常易于安装。拖放工具的开发通常包括提供给用户的 ETL(提取、转换和加载)功能组件列表。

功能组件是 ETL 步骤的抽象,底层执行仍然由代码完成,但是用户不需要知道详细的实现。例如,我想将列类型从字符串转换为整数。我们将“Type Convert”组件拖放到画布上,然后将上游数据源移到这个组件框中。一旦打开“Type Convert”组件的配置窗口,我们就提供列名和数据类型,以便进行数据类型转换。然后,用户通过在功能元素之间画线来定义工作流。

在使用这个工作流管理工具时,用户通常会戴上一顶“设计师的帽子。拖拽工具类似于一个流程图绘制 app,不可避免的会给用户留下设计的印象。

Airflow 采用了另一种方法,这种方法需要比拖放工具更好的编码

  • 代码更加灵活。Airflow 也有由 Airflow 社区或第三方供应商完成的类似功能组件。然而,更强大的是,您可以编写自定义 Python 代码作为操作符/传感器,以更灵活地完成缺失的任务。虽然拖放工具允许您在一定程度上做到这一点,但它限制了您能做的事情。由于最初可以与代码中的整个管道进行交互,因此可以在气流中实现更多。
  • 代码更容易共享和协作。代码天生就易于共享和阅读,开源的代码共享库使它比以往任何时候都不那么痛苦。然而,共享真正的可编辑拖放项目是一个不同的故事。它需要你有一个兼容的版本来打开,在适当的级别放大/缩小,有时它需要用其他工程师最初设计的工作流程的优秀布局来修复。
  • 代码不那么含糊。阅读 Python 代码的行与观看画布上连接的多个盒子是不同的。我们可以将清晰的模式、表达性的注释和易于理解的抽象放到代码中,以减少歧义。一旦涉及到视觉效果,就变得更加困难;还有更多类似哈佛商业的例子在“糟糕的数据可视化:误导数据的 5 个例子”一个人工设计的工作流可以更加模糊和误导。

如果代码完美,我们是否应该立即跳入气流?

图片由 giphy 提供

看你需要什么,看你团队的技术。拖放工具已经有几十年的历史了,它被广泛采用是有充分理由的。拥有一个能用 Python 读写有效代码的人需要软件工程师技能,这不同于一个精通 SQL 的人。使用拖放工具开发中小型工作流的工作量与 Airflow 相同,但是更复杂的工作流将更容易构建和调试代码。

替代方案:现在市面上还有很多拖拽工具。如果你使用微软,SQL Server Integration Services(SSIS)仍然是一个很好的选择。对于开源软件来说, Apache Hop 是另一个很好的选择。它从 Pentaho 数据集成开始,并成为 Apache 基金会的数据项目之一。Talend 和 Pentaho 也是基于 GUI 的 ETL 解决方案的早期参与者。它们都为复杂的数据管道提供了丰富的特性。

气流不是用来流动的

Airflow 不是数据流解决方案”(此处在《地平线之外》一节)从一开始就出现在 Airflow 官方文档的首页。需要用关于气流文档的两个简短段落来澄清这意味着什么,除非你已经在气流方面工作了一段时间,并且理解气流是如何工作的。

什么是数据流解决方案? Tyler Akidau 在他著名的 Streaming 101 博客文章中提到了流媒体系统的如下定义:

“一种数据处理引擎,设计时考虑了无限数据集。仅此而已。(为了完整性,也许值得指出的是,这个定义包括真正的流和微批处理实现。)."

为什么气流不适合串流?提到气流的一个原因是任务不会将数据从一个移动到另一个(虽然收费可以交换元数据!).为了将数据从一个作业转移到另一个作业,Airflow 不会存储这些数据,而是依赖 S3 和 GCS 等外部存储来支持这种操作。与气流不同,数据可以从一个任务中流出,而无需像 Flink、Storm 和 Spark Streaming 这样的现代流包中的强制暂存区。

另一个较少讨论的原因是 Airflow 的气流调度器的设计。airflow scheduler 最初是按照以 ETL 为中心的思想设计的,该架构侧重于触发一个数据窗口(通常是一天,但也可能是一个小时)。气流的最小单位是 1 分钟,因为它使用 cron。然而,每 1 分钟执行一次工作流会给气流调度器带来很大压力。它需要 Airflow 用新的状态持续更新其后端数据库,并触发新的作业。在生产环境中,如果您的工作流需要在不到 1 分钟的时间内启动一个小批量,这就成了一个问题。在这种情况下,气流表现不佳;工作可以快速排队,需要赶上。

Airflow 更适合批处理风格的任务,需要一个预定的间隔,不一定要 24/7 运行。如果一个工作流项目的 SLA 被限制为小规模,那么一个替代的流解决方案可能更适合这里。

替代解决方案:如果您正在寻找作为流式解决方案处理的数据。最好能看看阿帕奇 Flink阿帕奇 Spark 结构化流阿帕奇光束,或者卡夫卡流。这些是从一开始就以流为核心概念设计的框架,适合 24/7 流用例。如果你有兴趣了解更多关于流媒体系统的工作原理,我推荐泰勒·阿基多的博客文章。

气流需要定期维护

虽然 Airflow 中的工作流不是流式的,但 Airflow 调度程序和 web 服务器是全天候运行的。Airflow scheduler 是一个守护进程,它不断检查新作业是否需要触发或更新。Airflow web 服务器确保 Airflow 正常运行,以允许用户查看作业状态。更值得关注的是调度器,因为它与作业调度相关。如果 Airflow 调度程序终止或停滞,将不会调度新的作业,并且已启动的作业不会更新最新状态。如果 Airflow web 服务器不正常,所有工作流仍将由 air flow 调度程序运行。唯一的缺点是用户从 UI 中看不到任何东西。这意味着你需要一个随叫随到的时间表,让某人看看为什么气流调度器和网络服务器在半夜不健康。

此外,将开源气流部署到生产中是一项复杂的任务。这与在数据基础设施端部署其他工具需要付出同样的努力。作为第一步,适当的资源规划对于长期健康的气流是必要的。

一旦您部署了 Airflow,Airflow 就应该包括在随叫随到的调度堆栈中,以避免用户的调度停机。随着更多的工作在船上,气流后端数据库也在增长。任务状态的一行不会花费一分钱,但是当长期累加所有行时,后端数据库可能会是指数级的。由于许多查询不是很有效,例如,在 Xcoms 中的include_prior_dates,我在另一篇文章“关于气流 Xcoms 你应该知道的 5 件事”中更详细地提到了它通过清除旧状态并在后端数据库中保留更少的记录来进行定期维护,可以帮助减少查询开销,使气流调度器更少被烧毁。

替代解决方案:如果你没有资源来维护团队内部的气流基础设施,领先的云提供商有一些托管解决方案:谷歌提供 Cloud ComposerAWS 为 Apache Airflow(MWAA) 提供亚马逊托管工作流,以及公司支持的 Airflow 天文学家. io 。因此,您可以更多地关注 ETL 管道和业务逻辑,而不是担心整个流程的停机时间。

最后的想法

如果您希望使用 Airflow 作为您的工作流管理平台,上面提到的关于 Apache Airflow 工作流管理平台的三个有用的东西已经通过 Airflow 为您预览了数据工程堆栈。本文将帮助您做出决定,并帮助您了解气流以及如何使用它。

请在下面评论您认为应该添加到 Airflow 上的项目,或者对该工作流管理平台有更多了解的项目。

希望这个故事对你有帮助。本文是我的工程&数据科学系列的部分,目前包括以下内容:

Chengzhi Zhao

赵承志

数据工程和数据科学故事

View list47 stories

你也可以 订阅我的新文章 或者成为 推荐媒体会员 也可以获得媒体上的所有报道。

如果有问题/评论,请不要犹豫,写下这个故事的评论或者通过 LinkedinTwitter 直接联系我。

开发机器学习模型时要考虑的三种可解释性方法

原文:https://towardsdatascience.com/three-interpretability-methods-to-consider-when-developing-your-machine-learning-model-5bf368b47fac

照片由米切尔罗Unsplash

F 继我的上一篇文章了解机器学习可解释性之后,这篇文章介绍了机器学习可解释性分类、驱动力和重要性的介绍性概述——这篇文章介绍了在开发机器学习模型时可能需要考虑的 3 种可解释性技术。这些方法是 SHAP(沙普利加法解释),石灰(局部可解释模型不可知的解释),和锚。除了为每种方法提供例子之外,我们比较和对比这三种方法,讨论它们的限制并且为进一步的阅读提供论文和参考。

注意事项:

  1. 本文不是关于这些方法的理论细节或者它们是如何精确工作的,而是我将提供一个关于每种方法的简短的直觉,并集中于如何使用它。
  2. 这篇文章中的很多内容都是基于 Christoph Molnar 的这本书:可解释的机器学习:使黑盒模型可解释的指南。强烈推荐阅读。

内容

  1. 短暂的直觉
  2. 例子
  3. 比较
  4. 进一步阅读
  5. 结论
  6. 参考文献和参考书目

1.短暂的直觉

1.1 SHAP

SHAP 通过确定每个特征对最终预测的贡献来解释实例的预测。

这种方法是一种基于 Shapley 值的博弈论方法,每个特征值被视为游戏中的一个“玩家”,Shapley 值决定了如何在不同的特征之间公平地分配这笔支出。[1]

1.2 石灰

LIME 通过用本质上可解释的模型(如决策树)来近似模型,来解释模型对实例的预测。大致来说,LIME 所做的是,它获取模型并多次调用(探测)它,以了解模型如何或为什么做出预测,通过比较模型如何对数据的不同变化做出反应,通过这种探测,我们将有一个新的数据集,LIME 然后训练一个新的可解释模型,就像决策树一样,每个实例都根据它与新生成的数据集的样本实例的接近程度进行加权。[2]

1.3 锚

像 SHAP 和莱姆一样,主播们也采用了类似的策略来生成本地解释。但是,与 LIME 采用的可解释模型不同,这些解释被表达为简单、易于理解的 IF-THEN 规则,称为锚。“锚”的概念是不在锚规则中的其他特征值的变化不会影响或改变预测,因此该规则被称为“锚定”预测。[3]

2.例子

问题描述

为了说明如何利用这些方法,这里有一个贷款审批的例子,我们将使用来自 GitHub 的数据集,下图中提供了数据的 5 个最上面的行,以了解数据的样子。

这个数据集表示一个贷款批准数据集,由 13 列组成(12 个特性和 1 个目标变量 loan_status)。

出于本文的目的,我开发了一个简单的 XGBoost 分类器,准确率为 86.67%。这些可解释性方法所做的是,它接受黑盒模型变量“模型”并尝试解释它。这里我们需要理解的是,我们已经构建了一个 XGBoost 分类器模型,我们将我们的可解释性技术应用到这个模型中。【注意,本文所有代码都是在 Google Colab 平台上进行的】

请从 GitHub 下载数据集,并将其保存为 loan_approval.csv。构建模型的代码如下:

模型构建和培训

让我们安装并导入我们的 3 个库

2.1 口译

首先,我们需要提取预测中使用的数据集的特征(列)

下一个单元将为测试集中的第一个实例初始化、应用和显示 SHAP 解释。我们通过模型和 X_test(测试集)。

电池输出

上图中的红色表示对预测有积极影响的特征,即贷款获得批准,而蓝色的特征对贷款未获批准有消极影响。

在显示了单个实例的解释之后,下一个单元可用于绘制模型的总体特征重要性的摘要

输出如下,该图总结了每个特性的总体重要性,x 轴表示 SHAP 值,正值表示贷款批准,反之亦然,y 轴表示每个特性,红色表示该特性的高值,蓝色表示低值,那么如何理解该图呢?

例如,我们可以注意到,申请人的已婚状态(已婚=1)一直是积极的,而贷款金额高几乎对贷款批准产生消极影响,等等,查看每个特征,查看颜色指示并相应地读取 SHAP 值。

电池输出

2.2 用石灰解释

对于 LIME,类似的过程也适用,我们启动一个表格解释器,LIME 为每种类型的数据(如文本、表格、图像等)都有一个特定的解释器。LIME explainer 接受 4 个参数:训练数据、特性名、类名和模式(在我们的例子中是分类)

下一个单元格将显示 LIME 对测试集的第一个实例的解释

电池输出

电池输出

2.3 用锚点解释

与 SHAP 和莱姆类似,Anchors 接受一些参数,如类名、特征名和训练数据,此外还有一个参数是分类名。对于处理分类特征的锚点,您需要创建一个字典,将每个分类特征映射到其对应的类别,字典中的每个键都是训练数据中特征(列)的索引,每个字典中的值都是表示每个类别的字符串。例如,如果在训练数据中有一个分类特征作为第三列,并且它的值为:employees,Student-那么您的分类映射将类似于{ 2:[" employees "," Student"]}

如果您使用的是独热编码,您可以将其写入下一个单元格{2:["0 "," 1"]}。(确保将 0 和 1 写成字符串,否则会引发错误)

下一个单元格将打印测试集的第一个实例的预测

Output:
Prediction: Approved

下一个单元格将打印测试集的第一个实例的锚

Output:
Anchor: ApplicantIncome > 0.67 AND Married = 1 AND LoanAmount <= 0.63 AND Property_Area_Urban = 1
Precision: 0.99
Coverage: 0.01

不要看完整的锚,你可以只看锚的一部分(前 2 或 3 个从句)

Output:
Partial anchor: ApplicantIncome > 0.67 AND Married = 1Partial precision: 0.82Partial coverage: 0.11

最后,下面的单元格将输出锚点解释的可视化效果

电池输出

电池输出

电池输出

3.比较

3.1 相似性

  1. 所有这三种方法:SHAP、LIME 和 Anchors,都提供了本地的、与模型无关的可解释性方法。局部意味着它解释了个别实例,SHAP 可以通过将个别预测的绝对 SHAP 值相加来提供全局可解释性。模型不可知意味着它是模型独立的,即它可以解释任何黑盒机器学习模型。
  2. 这三种方法可以应用于不同的数据类型(表格数据、文本和图像)

3.2 利弊

SHAP

赞成的意见

  1. “SHAP 在博弈论方面有坚实的理论基础”[1]
  2. 这些解释是对比性的,因为预测在特征值中是公平分布的[1]。

骗局

  1. 一般来说,SHAP 在计算上是昂贵的,除非是基于树的机器学习模型,如决策树、随机森林和 XGBoost,SHAP 有一个快速的实现[1]
  2. 人们可以创造误导性的解释(SHAP 可以隐藏偏见)[15]

石灰

赞成的意见

  1. “LIME has fidelity measure 给出了一个好主意,说明可解释模型在解释黑盒预测时的可靠性”[2]
  2. LIME 易于使用,在 Python 和 R[2]中都可以实现

骗局

  1. “一个大问题是解释的不稳定性”[2]。在一篇文章[14]中,“作者表明,在模拟环境中,两个非常接近的点的解释差异很大,这种不稳定性意味着很难相信这些解释”[2]
  2. 与 SHAP 相似,“数据科学家可以操纵石灰解释来隐藏偏见”[2][参考第 15 条]

赞成的意见

  1. 该算法的输出很容易理解,因为它是以 IF-THEN 规则的形式编写的。
  2. 它效率很高

骗局

  1. “算法受到高度可配置设置的影响”3
  2. 构造锚点需要多次调用 ML 模型,算法运行时间则取决于模型的性能。[3]

4.进一步阅读

对于那些有兴趣详细阅读机器学习可解释性的人,我发现这些参考资料对我很有用:

书籍:

  1. 可解释的机器学习:使黑盒模型可解释的指南
  2. 使用 Python 的可解释机器学习:学习使用 Serg Masís 的实际例子构建可解释的高性能模型[5]
  3. 可解释的人工智能,构建可解释的机器学习系统

论文:

  1. 可解释的人工智能:机器学习可解释性方法综述[7]
  2. 机器学习的可解释性:方法和度量的调查[8]
  3. 解释解释:机器学习的可解释性概述[9]
  4. 可解释的人工智能:机器学习可解释性方法综述[10]
  5. 解释模型预测的统一方法(SHAP 原始论文)[11]
  6. “我为什么要相信你?”解释任何分类器的预测(LIME 原始论文)[12]
  7. Anchors:高精度模型不可知解释(Anchors 原始论文)[13]

5.结论

本文介绍了 3 种可解释性技术,在开发机器学习模型时考虑这些技术很有帮助:SHAP、莱姆和锚点。我们给出了每种方法的简短直觉,以及如何应用它们的例子。我们比较并简要讨论了它们之间的相似之处,每种方法的优缺点,通过参考一些有用的参考资料和论文进行进一步阅读,我们完成了这篇文章。

在接下来的文章中,我们将探索更多最新的可解释性技术,并讨论这些方法的理论基础。

如果您有任何意见、建议或其他任何事情,请随时在下面留下您的评论或通过 LinkedIn 联系我们

非常感谢您的阅读,希望您觉得有用:)

6.参考文献和参考书目

[1]克里斯托弗·莫尔纳尔。可解释的机器学习。露露。com,2022。第 9.6 节,https://christophm . github . io/interpretable-ml-book/shap . html

[2]克里斯托弗·莫尔纳尔。可解释的机器学习。露露。com,2022。第 9.2 节,https://christophm . github . io/interpretable-ml-book/lime . html

[3]克里斯托弗·莫尔纳尔。可解释的机器学习。露露。com,2022。第 9.4 节,https://christophm . github . io/interpretable-ml-book/anchors . html

[4]克里斯托弗·莫尔纳尔。可解释的机器学习。露露。com,2022。,https://christophm.github.io/interpretable-ml-book/

[5]塞尔吉·马西什。使用 Python 的可解释机器学习:学习使用实际例子构建可解释的高性能模型。帕克特出版有限公司,2021 年。,https://learning . oreilly . com/library/view/interpretable-machine-learning/9781800203907/

[6]Ajay Thampi,可解释的 AI,构建可解释的机器学习系统,作者 Ajay tham pi https(2021)😕/live book . manning . com/book/Interpretable-AI/

[7]Linardatos、Pantelis、Vasilis Papastefanopoulos 和 Sotiris Kotsiantis。"可解释的人工智能:机器学习可解释性方法综述."熵 23.1 (2021): 18。,https://www.mdpi.com/1099-4300/23/1/18

[8]卡瓦略、迪奥戈、爱德华多·佩雷拉和海梅·卡多佐。"机器学习的可解释性:方法和度量的调查."电子 8.8 (2019): 832。,https://www.mdpi.com/2079-9292/8/8/832

[9]Gilpin,Leilani H .等人,“解释说明:机器学习的可解释性概述”2018 IEEE 第五届数据科学与高级分析国际会议(DSAA)。IEEE,2018。,https://ieeexplore.ieee.org/abstract/document/8631448

[10]Linardatos、Pantelis、Vasilis Papastefanopoulos 和 Sotiris Kotsiantis。"可解释的人工智能:机器学习可解释性方法综述."熵 23.1 (2021): 18。,https://www.mdpi.com/1099-4300/23/1/18

[11]Lundberg,Scott M .,和 Su-In Lee。"解释模型预测的统一方法."神经信息处理系统进展 30 (2017)。,https://proceedings . neur IPS . cc/paper/2017/hash/8 a20 a 8621978632d 76 c 43 DFD 28 b 67767-abstract . html

[12]里贝罗、马尔科·图利奥、萨梅尔·辛格和卡洛斯·盖斯特林。”“我为什么要相信你?"解释任何分类器的预测."第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集。2016.,【https://dl.acm.org/doi/abs/10.1145/2939672.2939778

[13]里贝罗、马尔科·图利奥、萨梅尔·辛格和卡洛斯·盖斯特林。"锚:高精度模型不可知的解释."AAAI 人工智能会议录。第 32 卷。№1.2018.,【https://ojs.aaai.org/index.php/AAAI/article/view/11491】T4

[14]Alvarez-Melis,David 和 Tommi S. Jaakkola。"论可解释性方法的稳健性."arXiv 预印本 arXiv:1806.08049 (2018)。,https://arxiv.org/abs/1806.08049

[15]Slack,Dylan 等人,“愚弄莱姆和夏普:对事后解释方法的对抗性攻击。”AAAI/美国计算机学会人工智能、伦理和社会会议录。2020.,https://dl.acm.org/doi/abs/10.1145/3375627.3375830

我在亚马逊 SDE 实习时学到的三课

原文:https://towardsdatascience.com/three-lessons-i-learnt-as-an-sde-intern-at-amazon-19e78c8cc608

以及它们如何让你成为更好的开发人员和数据科学家…

照片由 Unsplash 上的 Fotis Fotopoulos 拍摄

上个月,我作为一名软件开发工程师结束了在伦敦亚马逊为期 3 个月的实习。在实习期间,我学到了很多东西,成功地参与了一些令人惊叹的项目,并与一些才华横溢的人一起工作。我知道在编程方面我还有很多要学,但实习也教会了我,编码并不是成为软件工程师或数据科学家的全部。为此,以下是我在亚马逊工作期间学到的三条主要经验,以及它们为什么/如何让我在未来成为更好的软件工程师或数据科学家。

反馈很重要

如果你想成为一名优秀的软件开发人员/工程师,反馈非常重要。这不仅包括通过代码评审等过程对代码的反馈,还包括一对一、团队会议和文档评审。为了提高你作为一名软件工程师的能力,你必须能够接受这些反馈,从中学习,然后确保你在前进中使用这些反馈。

在编写任何代码之前,我收到反馈的第一个地方是与我的经理、导师、入职伙伴和其他团队成员的一对一会议。这些反馈包括我的进展如何,我应该注意什么,以及我如何适应团队的其他成员。这意味着我可以快速适应,提出问题,并确保我一直朝着正确的方向前进,也意味着我可以更快地加入团队并成为有用的成员。加入一个新团队通常是一个很大的问题,需要吸收大量的信息;在关注什么的指导下,我能够确保尽可能快地做出贡献。这种情况在整个实习期间都在持续,之后的反馈是关于我的进步,或者关于我如何解决问题,我是否有什么可以改进的地方。

我能够通过文档审查过程在团队环境中获得反馈。由于亚马逊是一家以客户为导向和关注焦点的公司,我必须确保我的任何想法或想法对客户都是有用的。在我的例子中,由于我正在构建一个内部工具,这意味着我必须构建一些我的团队能够使用的东西。在这一阶段,所有团队都根据我整理的文档对项目的特性、外观和实现进行了评论,这一阶段的反馈有助于确保最终项目与他们相关。如果没有这个反馈,这个项目就不会满足客户的需求,而且在我离开后,它很可能会被丢弃!不过现在,我被放在了正确的轨道上,以确保团队可以在未来使用。

最后,在代码评审的过程中,我也收到了对我的代码的反馈。这是第一次有人对我的代码、结构、实现以及我是如何写的给出直接反馈。这当然是一个非常伤脑筋的过程,但它设法极大地改善了最终的实现。我挑选了一些东西,并尽我所能在下一个版本和将来的提交中实现,同时也为将来提供了一些有用的提示。这直接有助于提高我的代码质量,虽然我还有很多需要改进的地方,但我希望这将为我未来的成功做好准备。

我将继续寻找反馈,只要它是可用的和合适的。虽然我可以自己学到很多东西,并构建一些伟大的项目,但最终其他人可能会有不同的观点或经验,最终为客户带来更好的代码、更好的过程和更好的产品。

干净的代码

这一课是上一课的继续,因为代码和文档审查的过程表明,干净的代码对于为客户创建持久和健壮的产品是非常重要的。这意味着代码应该简单实现,高效,可读/可理解。干净的代码应该以一种合乎逻辑的方式流动,以至于不熟悉基础知识的人应该能够相对容易地理解一段代码的内容和目的,而不需要太多的预先理解或文档。

我不是说文档或注释不重要,但是代码应该能够自己说话。在这方面,我还有很多要学的,但我从这一课中学到的要点包括:

  • 变量和函数的名字应该说明它们在做什么或者有什么用。它们应该清晰易懂。如果不是这样,那么你的代码可能很难阅读和调试,当你有一个大的代码库时,这可能会使生活困难 10 倍。这包括确保命名约定在整个代码中保持一致,否则事情会变得混乱和不清楚。
  • 一个函数应该只做一件事。如果它做的不止一件事,它应该被分解,以便更容易理解和测试,最终确保更健壮的代码。同样,当您有一个非常大的代码库时,这也很有用,因为这意味着您可以很容易地隔离错误出现的地方并修复它,而不必深入代码本身。
  • 文件结构和命名很重要。这与变量和函数的命名点密切相关,但是确保很容易找到代码并且类似的代码被捆绑在一起对于调试和理解代码库的功能是很重要的。对于一个大的代码库来说,这可能会变得更加复杂,但这使得它在浏览各种文件时变得更加重要。
  • 最后,虽然不是代码本身,但是提交应该是为了特定的目的并且很小。一个涵盖对代码库的多个更改的大提交将很难看到哪里引入了 bug,以及如果需要,如何回滚更改。分离提交,并清楚地说明它们的目的,可以帮助代码的长期可维护性。

所有这些都应该符合你写作的语言或目的的公认惯例。这包括在整个代码库中保持一致性,这样就不会出现混乱,尤其是当您在一个有多人参与的项目中工作时。所有这些最终将有助于代码的可维护性和可改进性,不仅对您自己,而且对您的整个团队都是如此。

虽然在实习前我就知道很多,因为没有人检查我的代码,我不知道我是否遗漏了什么,或者我所做的是否正确。在漫长的一天编码之后,通常很难对自己进行管理,并且您也不完全确定自己在寻找什么。虽然这并不意味着你不应该坚持高标准,或者你应该依赖他人来解决你的代码,但这意味着一个好的团队可以确保高标准得到保持,并且你们可以不断地互相学习。代码审查过程帮助我学到了很多东西,希望能提高我的代码可读性和目的性,希望能为我自己和团队改进未来的编码承诺。

知道去哪里寻找答案

我学到的最后一课是知道去哪里寻找答案。就其本身而言,这可能意味着许多不同的事情。这可能意味着知道如何搜索您需要的代码片段,在哪里可以找到关于已知框架或库的文档,在特定任务中向谁寻求帮助,或者在哪里和什么时候花时间自己解决项目,而不是依赖他人。这对于确保您以高效的方式工作很重要,这样您就可以解决为您设定的任务,同时也意味着您作为一名软件工程师正在发展和学习。

任何软件工程师的工具箱的一个重要部分是能够有效地谷歌找到我们需要的相关代码。无论是修复一个 bug 还是引入一个新特性,技巧通常是相同的。其中一部分还包括知道什么时候简单地复制和粘贴一段代码,以及什么时候深入了解解决方案的工作原理。在某些情况下,谷歌代码仅仅是为了提醒你如何用给定的语言做一些简单的事情,比如循环,或者因为你忘记了一个函数或模块的名字。在这种情况下,从互联网上获取代码应该不成问题,因为这只是复习。然而,在后一种情况下,当查看新代码时,理解它在做什么以及如何做通常是很重要的。这不仅是出于安全原因(您不希望代码库中有不稳定的代码),也是为了确保下次遇到类似的问题或错误时,您可以更快地修复它,并有更好的理解。否则,我们将花费所有的时间在谷歌上搜索,而不是自己编写代码。

第二部分是知道什么时候尝试自己解决问题,什么时候寻求帮助。第一部分的意思是,在某些情况下,为你做一点点工作可以让你相当快地、不费吹灰之力地找到解决方案。这意味着你不必阻止其他人做他们自己的生产性工作,同时也确保你作为一个软件工程师在成长和学习。这可以确保你将来能够解决类似的问题,成为团队中更有价值的一员。即使你没有找到解决方案,当你需要向别人寻求帮助时,拥有一些潜在的代码会有所帮助,因为你可以向别人展示你至少尝试过解决问题。这可以帮助他们快速上手,并确保他们不必浪费时间想出和你一样的解决方案。当你在与一项新技术互动时,你也可以找一个更有经验的人,确保他们可以为你提供资源,帮助你快速入门并走上正确的方向。

最后一部分是知道去找谁来有效地解决问题。在某些情况下,这可能是团队成员,甚至是团队之外的人,他们以前使用过类似的技术。在其他情况下,它包括知道你可以问谁可能认识某人来帮助,无论是你的经理,你的入职伙伴还是你的导师。这意味着你需要有一个强大而良好的人际网络,你可以依靠他们,但这也意味着你不需要认识每个人。否则,如果你不知道该去找谁,你可能会被困很长时间,这对你的进步没有帮助。你也不应该害怕寻求这种帮助,因为大多数软件工程师都应该理解被困在一个问题上而不知道去哪里是什么感觉。

因此,知道去哪里寻找答案可能意味着不同的事情,无论是知道如何正确地谷歌,知道什么时候花时间自己解决问题,或者什么时候该举手说你卡住了。通常团队会有一个机制来促进这类事情,无论是日常站立或定期团队会议,这将有助于你发展这种技能。这也是一项需要很长时间才能掌握的技能,当我完成更多的任务并理解不同的界限时,我当然还在学习。

结论

我了解到反馈对于成为一名软件工程师的各个方面都很重要,干净的代码对于创建和生产健壮且可持续的产品很重要,知道去哪里寻找答案可以极大地加快你的开发过程。在大多数情况下,我仍然有很多东西要学习和掌握,但它们肯定是我未来将继续学习的课程,并且肯定会帮助我成为一名更好的软件工程师或数据科学家。我希望这些也是其他人可以学习的经验,并且这些方面中的每一个对于继续成为更好的开发人员都是重要的。我希望这对我的职业生涯和我最终加入的任何团队都有好处。

如果你喜欢你所读的,并且还不是 medium 会员,请使用下面我的推荐链接注册 Medium,来支持我和这个平台上其他了不起的作家!提前感谢。

https://philip-wilkinson.medium.com/membership

或者随意查看我在 Medium 上的其他文章:

机器学习建模的三个主要组成部分

原文:https://towardsdatascience.com/three-main-components-of-machine-learning-modeling-c9186658f7fe

通过数据学习的艺术

马库斯·温克勒在 Unsplash 上的照片

介绍

本文涵盖了作为数据科学家或机器学习工程师应该掌握的机器学习(ML)建模的三个主要单元。ML 建模,通过数据学习的艺术,是数据科学项目生命周期中的重要一步,可能也是数据从业者最感兴趣的一步。

作者图片

我们每天都通过感知、视觉检查和听觉来学习。此外,我们根据以前的经历对明天做出决定。机器学习是人工智能的一个分支,它通过揭示数据模式(即特征和目标变量之间的关系)来模仿人类的学习能力。

特征是描述给定观察值或数据点的独立变量,而目标变量是我们感兴趣的因变量,通常用于建模以进行预测。

此外,机器学习的三种主要类型强调如下:

  1. 监督学习:这里用例子中提供的目标变量来训练算法。更多细节可以在这里找到
  2. 无监督学习:在这种情况下,算法只在没有例子中提供的目标的特征上进行训练。更多细节可以在这里找到。
  3. 强化学习:在这里,学习是通过与环境交互,同时根据需要向算法提供消极和积极的奖励来完成的。更多详情可在这里找到。

从发现创新的蛋白质结构到预测天气和能源需求,ML 建模的应用在学术领域和行业中各不相同。此外,ML 在欺诈检测、销售预测和客户细分领域为企业提供了巨大的价值。

机器学习建模的三个主要组成部分

ML 建模的主要组件(图片由作者提供)

现在,让我们深入研究 ML 建模的三个主要单元。

数据

这可能是 ML 建模最重要的组成部分。在用于建模之前,根据要解决的业务问题收集数据,对数据进行预处理和探索。数据质量很大程度上取决于勘探和预处理步骤。此外,在建模之前,可以进一步丰富原始数据。

数据质量是最大似然建模中影响预测性能的最重要因素。

在以前的文章中,我介绍了数据预处理的关键组件,即数据集成、清理和转换。此外,我还讨论了在数据探索过程中要避免的陷阱。这些链接可以在下面找到:

数据整合:

</three-critical-elements-of-data-preprocessing-part-1-3c16f46f8ced?sk=f383e05e79c640216fdb820cc74d6ed2>

数据清洗:

数据转换:

数据探索:

算法

这是 ML 建模的组成部分,它用数据拟合以学习特征和目标变量之间的模式和关系。存在几种基于它们如何从数据中学习的 ML 算法。一些例子包括决策树随机森林KMeansDBSCAN神经网络

在数据科学实践中,当解决给定问题时,会考虑不同的算法。这个过程是实验性的,高度依赖于问题。

此外,Scikit-learn 是用于实现不同 ML 算法的最广泛使用的 Python 库。其他流行的用于 ML 建模的 Python 库还有 LightGBMXGBoostTensorflowKerasPytorchLightning

拟合方法是每个算法中的主要特征函数。

型号

ML 模型是通过将算法与数据相匹配而得到的对象。它已经过训练,可以识别数据模式,并在必要时做出预测。

在实践中,使用算法的超参数的不同值进行实验,以创建使用不同度量评估的几个模型。选择“最佳”模型并部署到生产中。

创建 ML 模型所涉及的过程超出了本文的讨论范围,将在另一篇文章中讨论。

预测方法是许多 ML 模型中的主要特征函数。

结论

在本文中,我们讨论了机器学习建模的主要组件:数据、算法和模型。我们还强调了不同类型的机器学习和一些应用领域。

我希望你喜欢这篇文章,直到下次。干杯!

你可以通过下面我的推荐链接订阅 Medium 来获得更多我和其他作者的启发性文章,这也支持我的写作。谢谢大家!

https://aolaoye.medium.com/membership

三百万条 Wordle 推文之后

原文:https://towardsdatascience.com/three-million-wordle-tweets-later-3d3af23bd5c7

对 tweets 的分析揭示了什么关于 Wordle,它的单词和它的玩家。

Twitter 上分享的几千个 Wordle 游戏。图片作者。

在这篇文章中,我分析了 2021 年 12 月 23 日至 2022 年 1 月 27 日期间发布的超过 300 万条 tweets,以展示以下内容

  • Wordle 在 Twitter 上仍然很受欢迎,但每天的增长很大程度上是因为回归的玩家发布了他们的最新成果;首次发布的每日新玩家数量似乎保持稳定。
  • 有些单词比其他单词更有挑战性,这些难词大约每周出现一次。它们通常是不常见的单词,或者是字母组合不常见的单词,但它们也更有可能有重复的字母,这可能会让一些玩家出局。
  • 熟能生巧:单词玩家确实会随着练习而提高,当我们控制单词难度时,平均游戏时间会随着经验的增加而减少。

推特上的沃尔多

Wordle 是一个在过去一个月左右的时间里迅速传播的单词查找游戏,当时,被《纽约时报》收购,成为其越来越多的单词游戏和谜题之一。简而言之,玩家每天有 6 次机会猜测一个新的 5 个字母的目标单词;每个人得到的单词都一样,而且每天只有一个单词。

一个 Wordle 游戏的例子和每次猜测后提供的提示。请注意,即使玩家第一次猜对了“L”(及其位置),Wordle 也不会帮助他们识别“L”是目标单词中的重复字母。这就是为什么' KNOLL '被证明是一月份发现的最棘手的单词之一,以及它很少被使用和' KN '的使用不寻常的事实。图片作者。

每次猜中后,玩家会收到多达 3 个颜色编码的反馈,如上所示,可用于指导下一次猜中。Wordle 的病毒式成功与玩家分享他们游戏的完形的能力相关联——他们游戏的抽象图像——如下图所示,毫无疑问,这些推文的日益流行帮助推动了 Wordle 的成功。

Twitter 上分享的一个 Wordle 游戏示例。重要的是,共享游戏不公开使用的单词或目标单词,只公开收到的反馈。图片作者。

有如此多的人分享他们的努力,Twitter 成为现实世界数据的一个非常有用的来源,尽管它偏向于社交媒体和 Twitter 用户,并且可能认为用户更有可能分享他们更成功的努力;显然,没有未解决的单词被共享。

我可以通过申请 Twitter 学术许可证来获取这些数据,这允许我收集多达 1000 万条推文。为了收集这项研究中使用的数据集,我搜索了包含关键短语“ Wordle n,r/6 ”的推文,其中 n 是有效的游戏号码(例如上面的 n =202 ),而 r 是猜测的次数(例如上面的 r=3 )。经过一些数据争论,以消除无效或被操纵的游戏,这给我留下了 12 月 23 日至 1 月 27 日(含)的 3,014,306 条推文。

Wordle(在 Twitter 上)有多受欢迎

关于 Wordle 的惊人崛起,已经有很多报道,它从一月初的 30 万玩家激增到月底超过 2M。当我们在下面的条形图中看到每天在 Twitter 上分享游戏的玩家总数时,这一点就很明显了。本月初,每天的分享量不到 2 万,现在每天的分享量超过 20 万,总的来说,超过 80 万的独立玩家在此期间至少在 Twitter 上分享了一次他们的努力。

每天在 twitter 上分享 Wordle 成果的独特玩家(新老玩家)的数量。还显示了每个玩家分享的平均游戏次数。作者配图。

上面的柱状图区分了新玩家和回归玩家,虽然分享他们努力的新玩家数量有所稳定,但回归玩家的数量一直在稳步增长。因此,每个玩家平均分享的游戏数量也在增加。例如,到 1 月底,普通玩家在 Twitter 上分享了大约 7 个游戏,而在月初只有 2 到 3 个游戏;大多数玩家不会每天分享他们的努力,但他们会定期分享。

到目前为止,最难和最容易的目标词是什么?

回顾 Wordle 的第一个病毒月,找出那些特别难解决的单词是很有趣的。我们如何衡量一个词的挑战性?我们可以使用平均游戏时长。更多的猜测意味着一个更难的单词。另一种方法是查看游戏(需要不超过 3 次猜测的游戏)和游戏(需要最多 6 次猜测的游戏)的比例。

注意,沃尔多大约一周选一次难词。

在下面的图表中,我们看到了自 12 月 23 日以来对每个目标词的所有 3 种测量方法。目标词按日期顺序显示——因为它们在这个阶段是'旧新闻'。我们可以看到平均游戏时长在 3.5 到 4.7 回合之间变化,整体平均每场游戏 4.12 回合。正如所料,短游戏往往与高比例的短游戏和低比例的长游戏相关联。例如,‘点’是最简单的单词之一,因为它的游戏有 52%是短的,只有 3%是长的。相比之下,最难找到的词是“代理”:只有 23%的游戏是短的,超过 13%的游戏是长的。

短游戏(≤3 轮,蓝色)长游戏(6 轮,橙色)的比例,以及按日期顺序排列的每个最近 Wordle 目标单词的平均游戏长度(虚线)。

一种将这些措施结合成一个简单的难度比率的方法是将长游戏的分数除以短游戏的分数;我们从结果中减去 1,这样,对于一个给定的单词,难度比> 0 意味着长游戏比短游戏多,反之亦然。该难度比(和平均游戏时长)如下所示,根据最难(红色)和最容易(蓝色)单词的难度比是正还是负,分别突出显示这些单词;这些条也是用颜色编码的,所以颜色的强度反映了实际难度比的大小。

难(难度比> 0,红色)和易(难度比< 0, blue) words: every week or so Wordle uses a word that is much more challenging than usual (the red bars). Such challenging words are associated with much more long games than short games. Graph by author.

To date there have been 7 单词,长游戏比短游戏所占分数大的单词。这些词是渡口、围城、峡谷、修道院、恩惠(原文如此)、代理、山丘;虽然,围攻青睐只是在难度比略高于 0 的情况下勉强存在,因为他们的长游戏比短游戏略多。

是什么让难词具有挑战性?

为什么有些单词比其他单词更难解决?这里有三个值得验证的假设:

  1. 单词级频率:更罕见的单词(也就是说,使用频率更低的单词)会更难,因为它们可能不为我们所熟悉,或者至少在我们搜索新的猜测时不是首选
  2. 字母级频率:以类似的方式,具有不寻常字母组合的单词也将更加困难,因为可能更难想到使用这种字母组合的单词,即使单词本身相当常见。
  3. 重复字母:包含重复字母的单词也可能更难识别,因为 Wordle 的反馈不会标记重复字母,并且因为玩家很自然地会避免重复字母,以试图最大化他们找到新目标字母的机会。

为了评估一个单词的单词级频率,我使用了一个英语单词及其频率的数据集,相对于平均 5 个字母的单词频率进行了标准化。对于字母级频率,我计算了 5 个字母单词中单个字母的频率。然后,给定单词的字母频率是其字母的平均频率;与单词级频率一样,该字母级频率得分相对于 5 个字母单词的平均字母级频率被标准化。

这两个指标的结果显示在下面的前两个图表中,即简单单词和困难单词的平均单词级和字母级频率;在每种情况下,1 分对应于 5 个字母单词的平均单词级/字母级频率。很明显,简单的单词比困难的单词更常见,它们的字母也更频繁。例如,平均而言,简单单词比 Wordle 中典型的 5 个字母的单词更常见(标准化的单词级频率为 1.16),但困难单词则不太常见(单词级频率为 0.28);换句话说,容易的单词比难的单词常见 4 倍;如果我们使用字母频率,情况类似。这表明单词级别和字母级别的频率是区分易词和难词的一种方式。

标准化的单词级和字母级频率分数,以及简单和困难游戏中重复字母的标准化可能性。作者图表。

与简单的单词相比,困难的单词也更可能包含重复的字母。超过 70%的难词(7 个中的 5 个)包含重复字母,但只有 16%(29 个中的 5 个)的易词包含重复字母。平均来说,大约 27%的 5 个字母的单词有重复字母,所以简单的单词比预期的不太可能有重复字母,而困难的单词更可能有重复字母。毫不奇怪,重复字母的出现带来了挑战。首先,沃尔多的提示不能帮助我们找到重复的字母。第二,大多数玩家会尽量避免猜测重复的字母,因为这限制了目标词匹配的机会,尤其是因为我们凭直觉认为重复的字母相对较少。

如果你在单词上没有进步,那么不要忘记考虑重复字母的可能性!

论经验的益处

玩家是不是玩的游戏越多越好?风险总是存在的,人们只是在发布他们最大的努力,所以经验的价值可能不会在我们的 Twitter 数据中体现出来。此外,由于人们发帖的频率不同——有些人每天都发,有些人没那么频繁——有必要根据他们分享的游戏数量来衡量体验,另外,根据他们第一次发帖以来已经过去的天数来衡量体验。

下图显示平均游戏时长随着两项经验指标的增加而下降,表明玩家确实随着经验的增加而提高。显示的所谓的 r 平方值表示游戏长度和每个经验测量之间的关系强度。游戏时长和自第一次游戏以来的天数(r 平方= 0.86)之间的关系比游戏时长和所玩游戏的数量(r 平方= 0.58)之间的关系更强,这确实表明依赖自玩家第一次发帖以来已经过去的天数作为他们经验的衡量标准更好。

在 Twitter 上分享的每场游戏的平均回合数,由玩家迄今发布的游戏数或自其第一场游戏发布以来的天数来表示。作者配图。

然而,比较游戏的平均长度没有考虑到单词的不同难度水平,我们知道这是不同的;例如,难单词的 5 轮游戏可能比简单单词的 4 轮游戏更好。为了控制这一重要因素,我们可以相对于每个单词的平均游戏长度来标准化游戏长度。更准确地说,我们计算给定游戏的游戏长度的 z 分数——简而言之,这是给定游戏长度高于或低于单词的平均游戏长度的标准偏差的数量——因此 z 分数-0.1 表示特定游戏比该单词的平均游戏短 10%的标准偏差,而 z 分数+0.05 表示游戏长度长 5%。**

这些 z 分数是根据以下两种体验绘制的。我们可以再次看到,经验似乎确实有助于玩家提高——游戏长度的 z 分数下降——但当使用这些标准化的游戏长度时,这种关系甚至更强;r 的平方值为 0.98,表明 98%的标准化游戏时长变化可以用玩家在 Twitter 上发布第一个游戏的天数来解释。和以前一样,自第一个游戏发布以来的天数与游戏长度(z 分数)的关系比共享游戏的数量更密切,这表明它是一个更好的衡量玩家体验的指标。

在 Twitter 上分享的每场游戏的回合数(按平均游戏长度标准化)的平均 z 值,由玩家迄今发布的游戏数或自第一场游戏发布以来的天数决定。作者配图。

结论

在这篇文章中,我们分析了 80 万玩家的 300 多万条 Wordle 推文。Wordle 在 Twitter 上仍然很受欢迎,但目前的日常增长很大程度上是由重复发布新游戏的玩家推动的;自 1 月初至 1 月中旬以来,每天在 twitter 上发帖的新玩家数量基本保持稳定。

对于不同的目标单词,游戏长度的分布有很大程度的变化。大多数单词与短游戏的关联比长游戏多,但大约每周一个单词,Wordle 的目标单词更具挑战性,导致更多长游戏和更少短游戏。毫不奇怪,这些更具挑战性的单词往往是不太常见的单词,或者有更多不寻常的字母组合,但它们也更有可能有重复的字母,这可能会让玩家出局。

对于经常玩 Wordle 的玩家来说,好消息是熟能生巧。经验和游戏时长之间有很大的关系:随着玩家经验的增加,他们往往会以更少的猜测成功,特别是当我们控制不同的经验和单词难度时。

祝你明天的单词玩得开心,但要小心那些重复的字母!

如果你想知道更多关于 Wordle 的数据能告诉我们如何有效地打球,那么看看我最近的帖子:

快速进入数据科学职业生涯的三件必做之事

原文:https://towardsdatascience.com/three-must-dos-for-a-successful-data-science-career-915dc3396d5c

意见

加快数据科学职业发展的关键事项

约书亚·厄尔在 Unsplash 上的照片

数据科学被认为是 21 世纪最性感的工作。随着人们对人工智能的兴奋,以及科学获得的宣传数据,每年都有越来越多的人进入这个领域。面对如此激烈的竞争,似乎很难在数据科学领域脱颖而出并取得成功。这篇文章涵盖了一些经过验证和测试的行动,以快速跟踪您的数据科学职业生涯,而且不,它不是另一个技术培训或认证。

创造高价值

照片由 Riccardo AnnandaleUnsplash 上拍摄

数据科学家的任务是为客户创造价值。你能创造的价值越多,你对你的公司就越有价值。你可以创造三个不同层次的价值。

低层次的价值创造:在这个层次,业务涉众陈述了他们想要解决的问题。您团队中的一名高级数据科学家已经确定了如何解决这个问题,确定了所需的数据,并与利益相关方一起确定了如何评估解决方案。剩下的唯一事情就是实现这个解决方案。听起来很熟悉?这是大多数入门级数据科学家的工作。构建模型/改进现有模型,其中消除了大多数解决问题的模糊性。唯一留下的模糊性是实现模糊性,它为价值创造留下了最小的空间。

中级价值创造:在这一级,业务利益相关者陈述了他们想要解决的问题,作为数据科学家的你与他们一起解决问题。您确定需要什么数据,需要开发什么解决方案,以及从业务角度评估模型的什么度量标准是有意义的。然后你着手实现一个最小可行的解决方案,并迭代地改进它,为业务涉众创造价值。

高层次的价值创造:在这一层次,由于您对数据和业务领域的熟悉,您可以带着创造价值的建议接近业务利益相关者。在这个层面上,你本质上是在改变商业运作的方式。如果你的提议被采纳,你就继续发展它(如前所述)。这是创造价值的最高层次,也是你希望快速提升职业生涯的理想层次。

行动项目— 那么,您是如何做到的呢?使用 80-20 法则。花 80%的时间在你的任务上。剩下的 20%用来了解你的业务领域和你可以访问的数据。这意味着与业务利益相关者建立一对一的关系,以了解他们在做什么,花时间了解可用的数据,阅读你的业务领域的趋势以激发想法。

证明文件

Vadim BozhkoUnsplash 上拍摄的照片

记录一切,我是说一切。数据科学是一个多阶段的过程,每个阶段都需要维护特定的文档。

提议阶段:在这个阶段,科学家致力于阐明业务问题,为什么这是一个需要解决的重要问题,以及解决该问题可能带来的定量/定性收益的估计。这记录在与业务利益相关方合作创建的研究提案中。该提案还可以包含对最小可行解决方案的描述,该解决方案具有明确定义的范围、将如何评估该解决方案以及对工作量的估计。

开发阶段:在这个阶段,科学家致力于确定解决问题所需的数据,并研究如何开发解决方案。因此,科学家必须与数据工程师合作开发数据数据文档,描述从哪里提取了什么数据,如何存储/保护数据,以及如何更新数据。此外,科学家将撰写一份文献综述,记录解决他所负责的问题的现有方法,确定什么是基线解决方案,并列出可以改进基线的有前途的方法。根据文献综述,科学家将试验不同的方法,并开发一个或多个最低可行的解决方案,以供企业审查。

产品化阶段:一旦确定了最低可行解决方案,科学家与工程团队一起决定培训/部署和服务最低可行解决方案的架构。整个过程记录在设计文件中。

公开阶段:一旦解决方案准备好发布,最好用公开可访问的文档(比如 Wiki 页面)来支持解决方案。文档应该用通俗易懂的语言列出问题是什么,为什么解决它很重要,开发了什么,以及它带来了什么好处。如果可能的话,创建一个视频记录并上传。

建立关系网并寻求反馈

charlesdeluvioUnsplash 上拍摄的照片

“[你的]重要职业决策是在你不在房间的时候做出的”——卡罗琳·多德-希金斯

让熟悉你的工作的人成为那个房间的一部分,是提高你做出这样的决定的机会的最好方法。因此,你需要谈谈你的工作。

从在公司内部的时事通讯/博客/视频渠道宣传你的工作开始。请你的经理在团队/领导会议上强调这一点。

接下来,确定你所在领域中可能对你的工作感兴趣的关键产品所有者。召开会议寻求反馈。这在两个方面有所帮助。一,产品负责人熟悉了你的工作,会和别人讨论。第二,你得到了关于你的工作的有价值的反馈,以及它可以增加额外价值的可能方式。

最后,和你团队中的资深科学家开个会,征求反馈。这在前面讨论的两个方面都有帮助。第一,你的资深科学家知道你的工作。第二,您可以获得关于如何改进模型的技术反馈,以及您的技能组合!

关键要点

总结来说,你必须做的三件事来加速你的职业生涯。

  • 为您的公司创造高价值
  • 记录你所做的工作
  • 谈论你的工作并寻求反馈

听起来很简单?最好的东西通常是!

如果你喜欢这篇文章,一定要看看我页面上的其他文章!

https://medium.com/codex/how-do-i-land-a-data-science-internship-in-the-us-82997d59f18d https://medium.com/@selfStarter/4-ways-to-get-the-most-out-of-graduate-school-from-a-cmu-grad-7f3d70e51e37

机器学习监控的三个必备

原文:https://towardsdatascience.com/three-must-haves-for-machine-learning-monitoring-8f43cb8751be

数据科学家评估解决方案指南

监控对于生产系统中部署的机器学习模型的成功至关重要。因为 ML 模型不是静态的代码片段,而是依赖于数据、超参数、评估指标和许多其他变量的动态预测器,所以深入了解训练、验证、部署和推理过程以防止模型漂移和预测停滞以及许多其他问题是至关重要的。然而,并非所有监控解决方案都是一样的。在这篇文章中,我强调了机器学习监控的三个必备条件,无论你是决定建立还是购买一个解决方案,它们都有望很好地服务于你。

来源:莫娜

完整的流程可见性

首先,模型必须在它们旨在服务的业务功能的上下文中进行评估。这种功能通常在模型下游的多个步骤中实现。在实验室之外,许多人工智能驱动的应用程序涉及多个协同工作的模型。此外,模型的行为可能依赖于上游多个步骤的数据转换。因此,关注单个模型行为的监控解决方案将不会捕捉到模型性能的全貌,因为它与全球业务环境相关,并且将无法发现在模型之外开始或结束的许多问题。对 ML 模型可行性的正确评估只能来自完整的流程可见性——洞察整个数据流、元数据、上下文和建模所依据的总体业务流程。

例如,作为信贷审批应用程序的一部分,银行可以部署一套模型来评估信用价值,筛选潜在的欺诈,并动态分配趋势优惠和促销。一个简单的监控系统可能能够单独评估这些模型中的任何一个,但是解决整个业务问题需要理解它们之间的对话。虽然它们可能有不同的建模目标,但是每个模型都依赖于训练数据、上下文和业务元数据的共享基础。因此,有效的监控解决方案将考虑所有这些不同的部分,并生成利用这些共享信息的统一见解。这些可能包括识别培训数据分布中的利基和未充分利用的客户群,标记概念和数据漂移的潜在实例,了解对业务 KPI 的聚合模型影响,等等。

最好的监控解决方案能够扩展到所有过程阶段,包括不涉及模型组件的阶段。

来源:蒙娜丽莎

自动化的精细洞察

一个常见的误解是,监控解决方案应该简单地实现与生产中的 ML 模型相关的常见指标的可视化和故障排除。虽然这很有帮助,但可视化和故障排除意味着您已经处于“调查模式”中。更糟糕的是,在企业抱怨某个 KPI 下降后,您可能正在“救火”(并询问“模型有什么问题?”).

那么,更主动一点怎么样?

如何在整体性能下降前几周甚至更长时间发现问题?

您应该期望您的监控解决方案能够在问题还很小的时候,在数据的粒度片段中自动检测到问题。让你有足够的时间采取纠正或先发制人的行动。“自动”的含义值得在这里进一步阐述。一些监控工具将提供仪表板,允许您手动调查数据的子部分,以查看哪些表现良好,哪些表现不佳。然而,这种肤浅的内省需要艰苦的人工干预,并且忽略了更重要的一点,即真正的监控解决方案将能够通过其自身的机制从本质上检测异常,而不需要外部依赖个人来提供他们自己的假设。

越是粒度大,越要注意降噪。预计单个异常会在多个地方传播问题。只有通过检测问题的根本原因,监控才能真正成功,而不仅仅是通过标记表面数据差异等。

来源:莫娜

总体可配置性

不同的 ML 系统有不同的数据和流程,不同的业务周期,不同的成功指标,以及不同类型的模型。你应该严重怀疑“即插即用”监听解决方案

一个完整的 ML 监控解决方案必须能够针对任何问题并跨其所有组件进行配置。它应该能够接受任何模型指标、任何非结构化日志以及任何表格数据,并使其易于:

  • 构建并持续更新单个性能数据库
  • 创建和定制动态可视化和报告
  • 设置和调整自动、精细的洞察和通知

可配置性需求的一个简单例子是系统之间的对比,在系统中,您可以获得模型保真度的(接近)实时反馈(例如,消费者推荐系统),而在系统中,反馈循环需要人工干预和更多时间(例如,欺诈检测、信用评分等)。

大多数企业 ML 团队都在从事各种 ML 项目,解决非常不同的业务问题。因此,监测要求是广泛的,需要细微差别和灵活性,以适应差异。如果您是这些团队中的一员,您可能已经建立了强大的数据科学标准,这是一个用于数据准备、模型开发和部署的统一堆栈。现在,您能够使用统一标准和单一解决方案来监控和管理您的系统吗?你绝对应该期待这样做。

结论

鉴于围绕机器学习的不断增长的宣传,存在许多解决方案,这些解决方案将采用 ML 模型,并提供对其特征行为、输出分布和基本性能指标的肤浅见解。然而,展现出完整流程可见性、前瞻性、智能洞察力和总体可配置性的解决方案非常罕见。然而,正是这三个属性是从 ML 模型中挤出最高性能和下游业务影响的关键。因此,通过这三个必备条件来评估任何监控解决方案至关重要,并确保它不仅提供模型可见性,还提供对业务环境的更全面、更完整的理解。

原载于https://www . monalabs . io

三个最被低估的数据科学概念

原文:https://towardsdatascience.com/three-of-the-most-underrated-data-science-concepts-47d58ef7187d

理解这些概念来提高你的影响力

照片由 Unsplash 上的延斯·勒列拍摄

你熟悉随机森林、偏差-方差权衡和 k 倍交叉验证吗?如果你是一名专业的数据科学家,你可能就是。

您可能已经花了无数时间来学习各种构建高性能预测模型的技术。这并不奇怪,因为有大量的在线内容致力于我们用来解决问题的工具。

更少的内容探索我们需要识别正确的问题来解决的概念。本文概述了其中的三个概念。

3.说服力与逼真度

从根本上说,模型的目标是什么?在大多数数据科学应用中,目标是提供支持决策的信息。当一个模型擅长于这个目标时,它表现出的说服力。问题是,我们在追求逼真性的过程中常常忽略了说服力,逼真性是一个模型详细描述现实的属性。让我们考虑一个例子。

想象一下,一家企业面临一个重要的决定,这个决定取决于下个月的用户购买总数,因此他们要求两位数据科学家提供预测。

第一位数据科学家 Jim 构建了一个相对简单的时间序列预测模型,该模型关注历史月度购买计数。他的模型考虑了最近的趋势、季节性和几个宏观层面的变量,这些变量推动了每月购买数量的变化。

第二位数据科学家 Dwight 希望建立一个比 Jim 更好的模型。他认为 Jim 的模型过于粗糙,没有考虑到详细的用户级动态。Dwight 花了两周时间建立了一个复杂的模型,预测每个用户是否会购买下个月可以买到的每个产品。一旦 Dwight 完成了他的模型,他就将用户级别的预测汇总成一个最终数字——下个月的估计购买总数。

Dwight 的模型比 Jim 的更详细,但是它更好吗?

大概不会。

问题是,德怀特在努力描绘现实的详细画面时,忽略了手头的决定。

吉姆的模型优于德怀特的模型有几个原因:

  1. 吉姆的模型建造和维护成本要低得多。
  2. 德怀特的模型更难向决策者解释,因此不太可能有影响力。
  3. Jim 的模型可能会更准确,因为它经过优化,可以直接预测感兴趣的数量。Dwight 的用户级预测中的错误可以累积成宏观级别的重大错误。

吉姆的模型侧重于的相关性,而德怀特的模型侧重于的逼真性。

中肯和逼真之间的区别来自罗纳德·霍华德的书,“决策分析的基础重温[1]。”在这篇文章中,他写道:

逼真是决策模型的标准吗?包含“特拉华州销售税”的决策模型比不包含的要好吗?答案是否定的,除非这个因素对决策至关重要。决策模型的标准是相关性:模型是否为决策者带来清晰的行动。您应该消除任何对这个目标没有帮助的特性。

更详细的模型不一定是更好的模型。如果你正试图决定是否要打包一件毛衣,你不用担心大气中的分子间动力学。

我们应该在模型中包含多少细节?下面两个概念有助于回答这个问题。

2.不确定度传播中的“四分之一法则”

太多时候,我们担心减少实际上无关紧要的不确定性。它们无关紧要,因为更大的不确定性主导着决策。

让我们考虑一个例子。数据科学家的任务是预测平台上新用户的平均支出。他们很快建立了一个简单的线性回归模型,预测精度为+/- 5%。

这个模型是一个不错的起点,但是数据科学家相信他们可以做得更好。他们在接下来的一周投入不同模型和超参数的实验。他们最终选定了一套制作精良的模型,精确度高达+/- 1%。

数据科学家将模型交给利益相关者,对话是这样的:

利益相关者:“哇,你能够将预测误差从 5%降低到 1%,真是不可思议。这就减少了 80%的误差!”

数据科学家:“谢谢。出于好奇,模型会用来做什么?”

利益相关者:“我们将使用你的模型来预测新用户的总收入。我们对安装数量进行了预测。你的模型预测了新用户的平均消费。如果我们用你的模型的预测乘以我们的预计安装数,我们将估算出新用户的总收入。”

数据科学家:“安装数量预测的不确定性是什么”

利益相关者:“大约+/- 20%”

在这种情况下,利益相关者实际上关心来自新用户的总收入:

总收入=(平均每次安装收入)x(安装数量)

感兴趣数量的不确定性由两个不确定性因素造成,即数据科学家模型中的不确定性因素和安装数量预测中的不确定性因素。

在这种特殊情况下(两个不确定量的乘积),相对不确定性贡献等于单个相对不确定性。因此,来自数据科学家模型的不确定性贡献为 1%,来自安装数量预测的不确定性贡献为 20%。换句话说,如果模型中只有不确定性,那么总的不确定性将是 1%。如果安装数量预测中只有不确定性,那么总体不确定性将为 20%。

不确定性贡献的结合方式有些令人惊讶。直觉上,人们可能认为不确定性的贡献增加了。这不是真的。数学更类似于勾股定理;不确定性贡献的平方相加。这是因为方差是相加的,而不是标准差。请查看维基百科关于不确定性传播的页面,了解更多数学细节。

不确定性传播的数学方法放大了大的不确定性相对于小的不确定性的影响。

如果我们假设模型的误差与预测的误差不相关,那么总收入的不确定性实际上是 sqrt(0.01 + 0.2 ) = 20.0%(四舍五入)。

如果数据科学家使用不确定性为 5%的简单回归模型,总不确定性将为 sqrt(0.05 + 0.2 ) = 20.6%。他们还可以节省一周的时间。

数据科学家花费时间将总体不确定性从 20.6%降低到 20%是否值得?大概不会。

在这种情况下,主要的不确定性贡献仅比较小的不确定性贡献大四倍。

在进行项目时,问自己以下问题:

  1. 决策时我们关心的量是多少?
  2. 我们关心的量的不确定性的主要来源是什么?

根据经验,避免投入过多的时间和资源对不确定性贡献小于主要不确定性贡献的四分之一的组件进行建模。

即使你神奇地以完美的精度对组件建模,你也只会减少不到 3%的总体不确定性。通常情况下,改进对你所支持的决策来说是完全无关紧要的。

如果可能的话,数据科学家应该关注主要的不确定性。想象一下,如果数据科学家将他们的时间集中在改进安装计数预测上。如果他们将不确定性从 20%降低到 18%,总的不确定性将是 sqrt(0.05 + 0.18 ) =18.7%。将不确定性从 20%降低到 18%听起来不如将不确定性从 5%降低到 1%那么令人印象深刻,但在这种情况下影响更大。

1.信息的价值

在我看来,这是数据科学中最被低估的一个概念。

根据维基百科,信息的价值 (VoI)是“决策者在做出决策前愿意为信息支付的金额”

对于专业的数据科学家来说,决策者通常是公司或客户。

VoI 非常重要,因为它向数据科学家展示了如何量化他们所做工作的价值。事实上,VoI 是我们在建模时关心的实际品质因数。在大多数情况下,诸如均方误差和分类器准确度之类的性能度量是 VoI 的替代。我们通常认为更高性能的模型更有价值。如果性能的提高可能导致不同的行为,那么这个假设是有效的。

要理解 VoI,我们必须考虑有信息和无信息情况下的价值差异。我们经常听到无处不在的流行语“数据驱动的决策”你有没有想过数据驱动的决策和“普通”决策在价值上的区别?这就是 VoI 的意义所在。

让我们再次考虑一个例子。一家公司有一个成功的披萨外卖网站。他们正在考虑扩展他们的网站,增加一个汉堡配送功能。该公司已经对这项功能是否会成功进行了初步的市场研究,但他们认为数据科学家可能会发现更多的见解来澄清决策。

在聘用数据科学家之前,该公司对汉堡配送功能将取得成功持乐观态度。为了简单起见,让我们假设一个具有两种结果的简单分布很好地描述了他们先前的信念:

  1. 新功能有 75%的机会成功并赚到 800 万美元。
  2. 新功能有 25%的可能性会失败,并损失 200 万美元。

公司可以在不雇佣数据科学家的情况下做出这个决定。在这种情况下,决策情况用下面的树来描述:

图片作者。基于先前的信念显示公司决策情况的决策树。黄色方块代表决定,蓝色圆圈代表不确定。绿色箭头表示使预期利润最大化的行动。

如果公司是风险中性的,它将推出该功能。该特性的期望值为(0.75 x 800 万美元)-(0.25 x 200 万美元)= 550 万美元,大于 0 美元。

尽管如此,该公司认为聘请一名数据科学家可能是值得的。方便的是,一位名叫克莱尔的申请人向公司提交了她的简历。克莱尔精通一种新的机器学习算法,该算法通过撕裂时空连续体来发布预测,从而直接看到未来。克莱尔有一种独特的能力,用一个价格创造出一个完全准确的模型。公司应该给克莱尔多少钱买她的礼物?

要回答这个问题,请考虑 Claire 的模型将如何改变决策树:

图片作者。用一个完美的模型显示决策情况的决策树。黄色方块代表决策,蓝色圆圈代表不确定性。绿色箭头代表最大化预期利润的行动。

关键的修改是,该公司现在将知道该功能是成功还是失败之前他们决定推出它。存在不确定性,因为公司不知道克莱尔会预测什么。

然而,一旦克莱尔提供了她的预测,就不再有不确定性。她有 75%的可能性预测这部电影会成功。在这种情况下,该公司将推出产品,并获得 800 万美元。

她有 25%的可能性预测到这个特性的失败。在这种情况下,该公司不会推出产品,产生 0 美元。将这种情况与前一种情况进行比较,在前一种情况下,公司将无条件地推出该功能,并可能因失败而导致 200 万美元的成本。

Claire 的模型有价值,因为它可能会预测功能的失败。该公司可能会取消该功能的推出,以回应她的预测。她的模型预测是可操作

为了使信息有价值,它必须具有改变行动的潜力。

为了计算 VoI,我们必须确定具有自由信息的决策情况的价值(忽略 Claire 的服务成本)。这个值就是(0.75 x 800 万美元)-(0.25 x 0 万美元)= 600 万美元。Claire 的完美模型将决策情况的价值提高了 500,000 美元,因此其 VoI 为 500,000 美元。

现实中,我们都没有克莱尔那么熟练;我们的模型有误差。完美模型的 VoI 被称为千里眼的 (VoC)。VoC 很有帮助,因为它为数据科学工作的价值建立了上限。

一个数据科学家永远不应该在解决问题上投入超过千里眼的价值。

计算 VoI 比计算 VoC 更难,因为它必须考虑到我们模型的不完美性。考虑建模误差的 VoI 计算的细节超出了本文的范围。我强烈推荐埃里克·比克尔关于主题的网络研讨会,以了解更多信息。关于计算 A/B 测试 VoI 的讨论,我推荐这篇博文

为了理解一个问题的影响,数据科学家应该意识到千里眼的价值。如果你的企业可以付钱给一个透视者,让他 100%肯定地回答你试图回答的问题,你会付多少钱?

结束语

感谢你花时间阅读这篇文章。我希望这些概念对您的数据科学之旅有所帮助。

参考

  1. 霍华德,R.A .,2007。决策分析基础再探。载于:Edwards,w .,Ralph,j .,Miles,f .和 Winterfeldt,D.v .(编辑),《决策分析进展》。纽约剑桥大学出版社,第 32-56 页

地面实况标签不可用时聚类的三个性能评估指标

原文:https://towardsdatascience.com/three-performance-evaluation-metrics-of-clustering-when-ground-truth-labels-are-not-available-ee08cb3ff4fb

无监督学习

如果基础事实标签不可用,应该使用哪个度量来评估聚类结果?在这篇文章中,我将介绍其中的三种。

西蒙·穆格在 Unsplash 上的照片

模型评估始终是机器学习管道中的一个重要步骤,因为它告诉我们模型在描述数据方面有多好。

当谈到模型评估时,我们更多地是指监督学习模型,其中数据的真实标签是可用的。监督学习中的性能度量可以基于来自模型的真实标签和预测标签之间的差异/一致来开发。

虽然不太直接,但对无监督学习模型的性能评估也很重要。在这篇文章中,我将谈论如何评估聚类模型的性能,这是无监督学习中的一项主要任务,如果地面真相标签不可用的话。

因此,我将要谈到的每种方法都需要完成聚类步骤,这意味着每个数据点都有一个聚类标签以及用于进行聚类的那些特征。

聚类评估的主要思想

聚类评估的思路很简单。它比较类内(自身类)距离和类间(相邻类)距离,以决定类的分离程度。

一个好的聚类应该具有较小的类内距离和较大的类间距离,如下图所示。

良好聚类结果中的类间距离和类内距离的示例。用三种颜色突出显示的分类标签。(图片由作者提供)

但是,如果聚类不好,则簇间距离和簇内距离没有那么明显,如下所示。

不良聚类结果中的类间距离和类内距离的示例。用三种颜色突出显示的分类标签。(图片由作者提供)

要注意的是,当我们谈论聚类是好是坏时,聚类实际上是指数据点和聚类标签之间的分配。对于同一个数据集,用一种方法聚类可能很好,但用另一种方法聚类可能很差。上述所有距离定义都必须基于已经聚类(标记)的数据集。

好的,在理解了聚类评估的主要思想之后,你会发现下面三个指标非常简单。

轮廓系数

作为最常用的聚类评估指标之一,轮廓系数将类内/类间距离比较总结为-1 到 1 之间的分数。

接近 1 的值指示超好的聚类结果,其中聚类间距离远大于聚类内距离;而接近-1 的值意味着完全错误的聚类分配,其中聚类间距离甚至不能与聚类内距离相比。

接下来我们来看看-1 比 1 之间的分数是如何构造的。

首先,我们需要知道如何计算特定点的平均类内/类间距离。

至于类内距离,对于类 C 内的任何数据点 I, a 被定义为 I 和 C 内所有其他数据点之间的平均距离

组内距离定义。(图片由作者提供)

其中| C_I |是属于簇 i 的点数, d(i,j) 是簇 C_I 中数据点 ij 之间的距离。

因此,对于任何给定点 I,小的分数a(I)表示点 I 的好的聚类分配,因为它接近相同聚类内的点。相反,大的分数 a(i) 表示点 I 的差的聚类,因为它远离它自己的聚类中的点。

关于类间距离,对于类 C 内的任何数据点 I, b 被定义为 I 到任何其他类中所有点的最小平均距离,I 不是该类的成员。换句话说, bi 到其最近邻簇所有点之间的平均距离。

聚类间距离定义。(图片由作者提供)

在获得数据集中每个点的聚类内和聚类间平均距离之后,轮廓分数被如此定义,

轮廓分数定义。(图片由作者提供)

对于 C_I = 1 的罕见情况(聚类 C 中只有一个数据点 I),轮廓得分被定义为 0。

我们可以从上面的公式中看到,分数完全由-1 和 1 限定,并且较大的分数表示较好的聚类分离。剪影乐谱的一个最重要的优点是它易于理解和界定。

轮廓分数的最大缺点是计算量大。在相对较大的数据集上超长的运行时间使得它在现实应用中用处不大。

为了用简单的解释换取更快的计算,人们通常求助于以下两个指标,卡林斯基-哈拉巴斯指数和 T2 指数。

卡林斯基-哈拉巴斯指数

Calinski-Harabasz 指数(也称为方差比标准)被定义为所有聚类的类间距离平方和与类内距离平方和的比值。距离的平方和由自由度修正。

这里,基于从聚类中的数据点到其自己的聚类质心的距离来估计聚类内,并且基于聚类质心到全局质心的距离来估计聚类间。

数据集 D 上 K 个聚类的卡林斯基-哈拉巴斯指数(CH)被定义为,

其中, d_i 是数据点 I 的特征向量, n_k 是第k簇的大小, c_k 是第k簇的质心的特征向量, c 是整个数据集的全局质心的特征向量, N 是数据点的总数。

我们可以看到,分子是从单个聚类质心到全局质心的距离平方的加权和(按聚类大小 n_k )除以自由度。分母是从每个单独的数据点到它自己的聚类质心的距离的平方和除以自由度。自由度用于将两个部分调整到相同的比例。

我们可以从上面的等式中看到, CH 越高,聚类彼此分离得越好,并且 CH 没有像剪影分数那样的上限。

让我们考虑一个基于 CH 指数的理想聚类结果。可能有几个“球状”集群,其中集群质心彼此远离,而集群成员靠近各自的质心(如下所示)。

获得 Calinski-Harabasz 指数奖励的良好聚类结果示例(图片由作者提供)

然而,如果聚类不具有这样的形状,基于质心的距离将不能提供足够的信息来判断聚类算法的质量。因此,CH 指数是而不是推荐用于基于密度的方法,如均值漂移聚类、 DBSCAN光学等..

戴维斯-波尔丁指数

Davies-Bouldin 指数类似于 CH 指数,但是组间/组内距离比的计算与 CH 指数相反。在 Davies-Bouldin 指数的计算中,有一个概念,即相似性得分,它衡量两个集群彼此相似的程度,其定义为:

戴维斯-波尔丁指数中的相似性计算。(图片由作者提供)

其中 R_ij 是相似性得分,S_i 和 S_j 分别是从点到聚类 I 和 j 内的质心的平均距离;并且 M_ij 是簇 I 和簇 j 的质心之间的距离

从等式中我们可以看出,较小的相似性分数表示较好的聚类分离,因为小分子意味着聚类内距离小,而大分母意味着聚类间距离大。

Davies-Bouldin 指数被定义为所有聚类与其最近邻聚类的平均相似性得分,

戴维斯-波尔丁指数计算(图片由作者提供)

其中 D_i 是第聚类在所有其他聚类中的最差(最大)相似性得分,最终 DB 索引是 N 个聚类的平均D _ Ia。

我们可以看到,DB 指数越小,聚类分离越好。它具有与 ch 指数相似的缺点,CH 指数在处理没有特定形状假设的聚类方法(如基于密度的聚类)时表现不佳。但是 CH 和 DB 索引都比轮廓分数计算快得多。

用 Python 实现

多亏了 scikit-learn 包,这三个指标在 Python 中非常容易计算。

让我们使用 kmeans 作为示例聚类算法。以下是计算剪影得分、Calinski-Harabasz 指数和 Davies-Bouldin 指数的示例代码。

**from** sklearn **import** datasets
**from** sklearn.cluster **import** KMeans
**from** sklearn **import** metricsX, y **=** datasets.load_iris(return_X_y**=**True)
kmeans **=** KMeans(n_clusters**=**3, random_state**=**1).fit(X)
labels **=** kmeans.labels_Sil = metrics.silhouette_score(X, labels)
CH = metrics.calinski_harabasz_score(X, labels)
DB = metrics.davies_bouldin_score(X, labels)

就是这样!希望文章对你有帮助。

如果你喜欢阅读这些文章,请订阅我的账号

参考资料:

https://scikit-learn.org/stable/modules/generated/sklearn.metrics.silhouette_score.html https://scikit-learn.org/stable/modules/generated/sklearn.metrics.davies_bouldin_score.html https://scikit-learn.org/stable/modules/generated/sklearn.metrics.calinski_harabasz_score.html

Artem Kniaz 在 Unsplash 上拍摄的照片

嵌入要避免的三个陷阱

原文:https://towardsdatascience.com/three-pitfalls-to-avoid-with-embeddings-ec0c6ed07234

作者图片

与 Arize AI 的数据科学家Francisco Castillo carr ASCO合作撰写。

介绍

假设你读了一篇非常有帮助的文章,揭开了嵌入的神秘面纱,你真的很兴奋。你的社交媒体公司当然可以使用它们,所以你打开笔记本开始打字。随着时间的流逝,兴奋变成了沮丧,你会想:人们是怎么做到的?

有几个关于嵌入的问题。没有一篇帖子能够涵盖所有场景,但是这篇帖子将尝试在三个方面给你一些实用的建议:

  1. 如何版本化您的项目,
  2. 一旦上线,如何监控您的嵌入,以及
  3. 如何对你的嵌入质量有一个直观的感觉?

但是首先,让我们看看如何创建一个嵌入。这里有一个示例代码,告诉你如何用几行代码组装一个简单的 Bert 嵌入到拥抱脸。

按作者

嵌入版本控制

迭代是这种努力的基础,迭代要求您能够跟踪您所做的事情。保持组织性可以节省你很多时间和麻烦,所以版本控制是关键。

在之前关于嵌入基础的文章中,您可以看到嵌入是如何实现跨团队协作的。现在,把你自己放在一个在自动驾驶汽车初创公司工作的工程师的位置上,培训停止标志的嵌入。假设您的前几个模型没有产生有趣的结果,但是在第五次尝试时,您得到了一些有趣的结果。您用更多的数据训练了嵌入,调整了一些参数,事情似乎进展顺利。您的同事推荐了一种有前途的新技术,您在下一次迭代中小规模地尝试了它。效果很好,所以你用更大的数据集来训练它。。。结果比你昨天吃的更糟。现在你想回到你最好的版本。你要找的是 untitled 5 _ 1 _ final . ipynb——还是 Untitled5_finalfinal.ipynb?

你的麻烦不会就此结束。你的老板说公司正在迅速向欧洲扩张,你必须用新的欧洲数据集重新培训嵌入。版本控制是嵌入式的永恒主题。你需要一个系统。

如何比较数据的两个矢量表示版本?这与一维的性能比较不同,它更复杂。对于这个问题还没有很多好的答案,但是有一些常见的原因可以解释为什么你要改变你的嵌入版本。嵌入会因为各种各样的原因而改变,但是这里有三个主要的原因,从大到小排列如下:

  1. 模型架构的变化:这是比以前更大的变化。改变模型的架构可以改变嵌入向量的维度。如果图层变大/变小,你的矢量也会变大/变小。
  2. 使用另一种提取方法:在模型不变的情况下,您仍然可以尝试几种嵌入提取方法并进行比较。
  3. 重新训练你的模型:一旦你重新训练了提取嵌入的模型,定义它的参数将会改变。因此,向量的分量值也将改变。

与语义版本化相比,您可以将模型架构的变更视为主要的版本变更。嵌入可以具有非常不同的维度,使用不同的提取技术,并且需要重新训练。即使提取技术保持不变,尺寸的意义也完全改变了。这种改变必然会破坏向后兼容性。

第二个变化可以被视为较小的版本变化,因为维度的维度和含义可能会改变,但不需要重新训练。最好也将这些视为破坏兼容性。

第三个变化可以认为是补丁版本的变化。您并没有改变嵌入本身或它的提取方法,您只是用新数据重新训练了模型。下游团队在现有系统中使用新的嵌入应该不会有任何问题。

一个更现实的例子是吸收不同类型输入的模型。您可以将这种情况视为一种嵌入,它是其他嵌入的组合。您处理这些输入的方式的任何改变都会导致您的最终嵌入向量的改变。向量应该表示输入的组合,以便您的模型可以使用尽可能多的相关信息进行决策。现在你的版本问题开始变得非常复杂。

UMAP:作者的形象

使用嵌入了解您的数据

如果你能形象化你的嵌入,你就能理解它。机器学习工程师非常擅长理解二维甚至三维的数据表示。人类通常凭直觉进行聚类。直观地看到嵌入对帮助您理解它在做什么大有帮助。这应该是可能的,因为嵌入是一种向量表示,向量很容易绘制。如果你能看到点的集群,你通常至少能对每个维度的含义有所了解。唉,在数百个维度中可视化事物是非常具有挑战性的。

幸运的是,有大量关于降维的文献。出于几个原因,最成功的嵌入表示方法是邻图,特别是 UMAP(一致流形逼近和投影降维)。要了解更多关于可视化你的嵌入的信息,包括对 UMAP vs t-SNE 的剖析,请查看我的同事 Francisco Castillo Carrasco 最近的这篇文章。

监控嵌入

嵌入不是静态的。想想也有道理——现实世界无时无刻不在出现新概念,人类也在不断更新旧范式。

现在你的嵌入已经出来了,你需要一种方法来监控它。最重要的是,什么时候失去意义?这是一个不小的问题,但幸运的是有一个正确的答案。

假设你的社交媒体公司现在有一个很棒的文本嵌入产品中。作为一名出色的工程师,您已经为您的模型设置了监控。当单词出现时,您会对其进行监控,并跟踪簇形心之间的平均距离。这个数字有一些随机波动,但这个水平通常是可预测的,所以您可以设置一个合理的阈值,超过这个阈值您将收到警报。这在一定程度上是可能的,因为当您第一次发布它时,您有了一个与您新训练的嵌入进行比较的点。

作者图片

结论

嵌入是一个强大的工具,但是像所有的电动工具一样,一些知识对于正确使用它们是必不可少的。知道如何正确地版本嵌入会让你在迭代代码的时候省去很多麻烦。一旦你的嵌入被训练好了,你就可以开始了解它在使用降维和图形化方面做得有多好。一旦投入生产,适当的嵌入监控技术将确保为您的客户提供一致的价值。

想了解更多?阅读关于监控非结构化数据的内容,了解为什么开始使用嵌入式技术比你想象的要容易。

联系我们

如果这个博客引起了你的注意,并且你渴望了解更多关于机器学习可观察性模型监控,请查看我们的其他博客资源!如果您有兴趣加入一个有趣的 rockstar 工程团队来帮助制作成功的模型,请随时联系我们,或者注册一个免费账户,或者在这里找到我们的空缺职位

处理不完美实验设计的三条规则

原文:https://towardsdatascience.com/three-rules-to-deal-with-imperfect-experimental-designs-830c92f60590

一个现实生活中的咨询例子

Irene B .的照片:https://www . pexels . com/photo/sand-dirty-breaked-ground-12496974/

在现实世界中,在学习了数据科学或/和统计学之后,这可能是最重要的:如何处理不完美的现实生活数据?作为活体实验室研究人员的统计顾问和统计教师,我经常需要处理收集的数据。事实是,在统计学家设计的理想的纸上实验和人们已经做的或能够做的之间存在差距。

本文将首先介绍主要观点(三个规则),然后用我最近实践中的一个真实例子来说明这个观点。

我处理不完美实验设计的三条规则

从 A/B 测试的企业到科学研究:

1.接受不完美:定义最佳研究设计,并尽可能接近它。通常,我们无法实现我们在纸上定义的理想实验。然而,将您实际做的与您最初的理想实验设计进行比较可以帮助您识别和评估潜在的限制。

2.现实一点:客观地评估你所拥有的可能是最困难的任务之一,但它也能为你节省最多的时间。试图得到一个不存在的东西往往代价很高。无论如何,你以后可能会放弃,你可能会得出错误的结论/建议,或者其他人可能会发现(你甚至可能会对其他工作失去信誉)。对我来说,我和我的合作者已经放弃了五年的研究。然后,我们不得不从不同的角度从头开始。我仍然相信这是最好的决定,我们这样做节省了很多时间。另一方面,正如我们将在下面的例子中看到的,客户认为他们有完美的体验,并且确实有一个非常有前途的想法。然而,一个重大缺陷使得这项研究的一个关键特征过时了,从而降低了研究计划的等级。尽管在我们的缩放交流中,客户几次试图恢复最初的想法,但我建议采取另一种(不那么“性感”)的方法,并客观地评估其局限性。

3.保守一点:统计模型依赖于假设,如果机理是基于理论模型,在得出结果之前还要做更多的假设。因此,即使结果在统计上是显著的,现实和模型估计之间也可能有差距。评估局限性通常不会取消作者的资格,反而会增强他或她的可信度。我举两个例子。首先,我看到学术报告中作者从“声称”因果关系开始。通常在这个早期的断言之后,听众会在接下来的演讲中用(有时非常不现实的)故事和例子来攻击演讲者,说明为什么在这种情况下因果关系可能无法实现。在这种情况下,一种更保守的方法是解释你如何解决阻止因果关系被测量的问题,同时让读者/观众自己来判断这是否足够。其次,想一想在任何问题上都过于自信的人。如果你已经在统计领域工作了一段时间,你就会知道一切都是复杂的,很少有简单的无条件的答案。

最近的一个咨询问题说明:

一个客户联系我,问了我一个简单的统计问题,是关于他们最近做的一个实验。为了保护隐私,我不会透露姓名或问题的确切内容。

研究问题:衡量绩效的方法 B 会产生与方法 A 相似的结果吗?(方法 A 是目前最先进的方法,但非常昂贵,而方法 B 要便宜得多。)

要检验的统计假设:方法 B 与方法 A 相关吗?(有几种方法可以回答这个问题,我将集中讨论一种简约的方法)。

设置:客户用每种方法进行了八次绩效评估,历时八天,共有 27 名参与者。这个想法是进行成对比较(不是比较个体,而是比较每个个体内部的度量)。

关键特征:该设计的主要目的之一是观察新的性能测试是否足够灵敏,以捕捉个体差异。这些是身体测试。因此,如果你将一名运动员和一名普通跑步者进行比较,这两种测试可能很容易发现差异,但测试的主要目的是测量恢复时间(以及其他)。所以更小的差异(个体内部而不是个体之间)应该被捕捉。

客户提问:客户问我,在这种情况下,他们应该执行什么测试。我建议用重复观测值进行两两相关检验(c.f. Bakdash 和 Marusich (2017))。于是那个人递给我数据,在做测试之前,我用我通常的方法看了看(在这篇 TDS 文章中有完整的描述)。

我通常的方法遵循 5 个步骤(变量选择、样本选择、单变量分析、双变量分析和结论)。我将跳过第 4 部分——双变量分析——直奔主题。不过,如果你也对第一步感兴趣,你可以在这里公开访问我的 Deepnote 文件包括所有的步骤(笔记本末尾的第一步)。

4.双变量分析:

我们对两个变量之间的关系感兴趣。最初的想法是使用重复的配对相关性测试。相关系数是线性关系的量度。因此,我想先看看数据,看看线性假设是否可信。

观察:有正相关。总体关系似乎可以用线性趋势很好地近似。个体之间的关系是明确的(使用方法 A 得分较高的人倾向于使用方法 B 得分较高),而在个体内部则不明确(每组相同颜色的点没有明确的趋势)。

免责声明:这是我将在几分钟内完成的第一个快速分析。当然,我可以探索不同的函数形式,对极值进行适当的测试,等等。

由于线性假设是合理的,并且两个变量是连续的,我确实会遵循我最初的建议:匹配测量的相关性。

观察:正如预期的那样,相关性与统计意义上的显著性相差甚远(p 值=0.52),甚至为负(相关性=-0.048)。

问题的早期迹象:看着这个散点图,我认为与受试者之间的差异相比,个体内部的差异确实很低。这让我想到了一个潜在的问题。

找出问题:所以在与客户的下一次通话中,我问我们是否真的期望个人之间的表现有所不同(即使使用相同的方法)。基本上,如果你衡量自己在一周内每天都习惯做的一项任务的能力,你会期待一个显著的自发变化吗?我们的结论是事实并非如此。如果发生了重大的事情(例如,作为训练的结果),就会观察到一个人的变化。事实上,在关于方法 A 的文献中,当实际存在治疗(例如,训练、比赛等)时,这种性能测试捕捉(内部)差异。).所以,设计漏掉了一个很重要的东西:一种治疗。这将允许对同一个人进行治疗前和治疗后观察,从而验证两种表现测试是否能够捕捉到差异。

5.结论:

应用上述三个规则:

1.理想与现实:在理想的设置中,个人将接受允许前后测量的治疗。考虑到这一点,让我们看看下面的 2 条规则。

2.现实一点:在当前的体制下,利用个人之间的差异是行不通的。如果你去掉个体间的差异,剩下的就是噪音。所以……那真令人失望。然而,仍然有可能利用个体间的差异。客户已经可以看到两种测试是否捕捉到受试者之间的差异。客户提出的问题还没有在文献中探讨过,因此,尽管它有一些缺陷,还是值得发表这些结果。如果这是关于这个主题的第二十篇论文,就更难“推销”了。此外,客户有一组重要的控制变量(性别、年龄、身高、体重)。因此,我建议采用包含控制变量的线性回归(以及由于重复值而聚集在个体水平上的误差)。线性回归是一种非常直观和简单的方法,可以根据控制变量捕捉两种方法之间的关联。

3。最后,我的建议是清楚地解释研究的局限性以及如何改进研究。

每个博士生免费获得的三项软技能

原文:https://towardsdatascience.com/three-soft-skills-every-phd-student-gets-for-free-f63f4b1d3f2d

我在攻读机器学习博士期间学到的关于研究、交流和团队工作的技巧和诀窍的综合列表

图片由作者提供。

这篇文章的动机是在一个播客上关于从博士项目过渡到行业的特殊性的对话,这个播客叫做机器学习的冒险,我是其中的特邀嘉宾。从经验丰富的机器学习团队领导那里听到工程师和科学家由于缺乏基本的软技能,可能会减慢甚至破坏项目,这令人担忧。因此,对于技术职位来说,软技能的价值不亚于核心的数学和解决问题的技能。

下面,我总结了博士生可以无意识地获得的软技能,然而,在工作环境或早期教育阶段,这些软技能很难培养——研究、沟通和团队合作。由于我的博士学位是机器学习,所以大多数例子都集中在研究和交流以及管理机器学习项目上,然而,这些技巧也适用于任何创业或领导科技项目的人。

不多说了,我们开始吧!

研究

听到 PhD 大概在“苦”之后想到的第一个词就是“研究”。

高效执行研究的能力在行业中尤其有价值,因为许多商业机器学习产品都是基于最近的出版物。

研究的两个关键方面是搜索和分析。

搜索

对于任何研究问题,你首先需要确定工作的范围,以及工作在更广泛领域中的位置。这同样适用于启动一个新的应用程序——您想要了解市场、主要竞争对手及其解决方案。

因此,你需要从论文、博客、文章、专利或会议讨论中找到尽可能多的关于相同或相似问题的信息。那么你从哪里开始呢?

  • 简单的谷歌请求将是一个很好的起点,然而也有像门德利这样的专业工具,在寻找科学研究时是一个很大的帮助。
  • 在搜索相关作品时,谷歌学者也是一个非常强大的工具。你可以通过关键词或作者姓名进行搜索。一旦你找到一篇相关的论文,你可以浏览引用这篇论文的作品,或者看看谷歌学者认为相关的文章。
  • 另一个信息来源是会议记录或期刊——例如,在 IEEE 网站上搜索关键词“图像质量评估”进行图像处理交易。
  • IEEE 网站也很有帮助,因为它可以让你浏览给定论文引用的论文
  • 许多作者有专门介绍他们研究的网页——通常有大量有用的链接。与拥有数十名合作者的知名学者相比,博士生(大多数计算机科学论文的第一作者)的研究范围更窄。
  • 与出版物相关的 GitHub 库也是一个非常有用的信息资源——通常你会找到基准和数据集的链接。有时,您还会查看使用存储库和提出问题的人员列表。
  • 关键是要有条不紊,始终如一,坚持不懈。

现在,你有一吨的信息,你需要通过噪音削减..

分析

提取相关信息的挑战之一是从噪音中剔除。学术界以其“不发表就灭亡”的态度著称,经常迫使研究人员在没有足够时间进行深入研究的情况下发表论文。那么,如何让不相关的工作离开你的盘子呢?基于以下因素确定优先级:

  • 作者名单和所属机构——作者是否在该领域知名,是否来自可信的机构。
  • 引用数量,虽然不总是一个好的指标(特别是对于新发表的作品),但高引用数表明该作品在该领域得到了应用和认可。
  • 发表作品的会议或期刊;大型和小型会议都很重要——专注于一个特定领域的小型会议和有很多主题的大型会议一样有价值。重要的是,提交的材料必须通过低接受系数的同行评审。
  • 论文的格式——能够使用漂亮的图形包和熟悉 latex (脚本语言和广泛用于 STEM 编写和编辑论文的框架)通常是一个很好的指标,表明读者为使作品易于理解付出了努力。
  • 如果方法论部分有臃肿的数学,需要一个单独的表格来保存使用过的符号,很可能论文写得不好。你将花费大量的时间来记住希腊字母。

一旦初步扫描完成,文件堆至少减少了一半,深入挖掘也不失为一个好主意:

  • 阅读摘要有助于确定作品是否符合方向。
  • 录制的会议演讲(youtube 上有很多)是快速鸟瞰作品的好方法。
  • 为了对作品有更深的理解,我大声朗读论文,用不同的颜色突出不同的观点。
  • 好的论文将使用多个数据集上的多个指标报告结果,并确保公平比较,将重新运行基准方法(而不是直接从原始论文中获取结果)。

沟通

大多数成功的研究人员也是伟大的沟通者!虽然有新的发现很重要,但确保你的同事、评论家和更广泛的观众明白这一点也同样重要。如果你不能表达你的想法,它们就毫无价值。

写作技巧

博士生有望发表论文,最好是在顶级场所发表。然而,这些都很难通过。例如,我所在地区的顶级会议之一— AAAI 在 2022 年的录取率不到 15%。当竞争如此激烈时,写作技巧往往是让作品被接受的关键。

因此,剑桥大学计算机科学博士生第一年的必修课之一是写作课。由于新生的文化差异很大,并不是所有的学生都习惯西方风格的学术写作——实际上东西方写作风格在有着明显的差异。那么,一篇写得好的论文有什么特点呢?

  • 简明扼要。会议有非常严格的格式要求和页数限制——你没有冗长的奢侈。写作课上的一个练习是将 300 个单词的段落缩短为 20 个单词的句子。一般来说,句子长度不应该超过 1.5 行。
  • 精确——出于以上同样的原因,避免空洞的陈述和明显的事实,你需要在前 1-2 句话中抓住读者的注意力。如果你想让你的论文被人阅读,你需要从噪音中脱颖而出。
  • 如果这个想法需要解释两次或者是含糊不清的,这个段落必须重写。一个明确的指示哪里需要改变的是一个以“换句话说……”开头的结构。
  • 图像是传达信息的强大工具。当处理图像时,首先考虑数字,然后考虑文本,确保情节和标题本身足够信息丰富——不要链接到论文的核心文本。
  • 有数十亿种不同的工具可以用来制作漂亮的图片。我大量使用免费的软件——draw . ioInkscape (特别是 textext 包,它允许你将乳胶配方嵌入图像)。
  • 还有几篇关于制作格式良好图形的文章。我喜欢这个。也许一个好的情节最重要的特征就是字体大小。当一个图形嵌入到纸张中时,字体大小应该与文章本身的字体大小相匹配。
  • 遵循“什么、为什么、如何”模式。什么?每一部分(段落)的前 1-2 句话应该概述它将要讲述的内容。为什么?概述结束后(或同时),激励为什么这个话题很重要。当读者知道为什么它们是相关的时,他们会更热衷于学习细节。如何?结果是如何取得的,问题是如何解决的。
  • 在符号和术语上保持一致。确保图上的符号和文本中的符号匹配。
  • 即使你的母语是英语,也要在语法上使用
  • 校对时,大声朗读。这将帮助你保持专注。
  • 总是让别人也来读。

写作不仅仅涉及论文——写电子邮件也要精确和考虑周到,如果你需要寻求帮助,确保你缩小了需要帮助的确切范围,要具体——做好你的功课。网上有无数关于学术写作的课程,我推荐 Coursera 的科技写作课程。

呈现

博士生们不断地练习他们的演讲技巧,从五分钟的电梯演讲到酒吧里的新朋友,再到会议上长达一小时的谈话。一般来说,演示文稿有两个主要部分——文本和幻灯片。

首先是文本,可以在编辑幻灯片时对其进行修改,但你应该先决定你要讲什么,然后再创建演示文稿。

  • 演示可以有多种目的,从问题的鸟瞰,到解释每一个整洁的细节。然而,如果没有倒带的选项,用耳朵来感知信息是非常困难的,所以文本越简单越好。让听众有时间跟上——不要一个接一个地用复杂的想法轰炸。
  • 为了理解演示文稿的要点,一个非常好的练习是用一分钟时间总结内容,类似于电梯推销。

幻灯片是为了帮助你形象化,而不是逐字重复你的脚本,因此:

  • 每张幻灯片应该有大约一分钟的演示时间。这使得观众有足够的时间阅读和理解幻灯片上的文本,同时提示演示者不要使幻灯片过于复杂。
  • 演示是关于视觉内容的,它的要点是视觉化,而不是过多的文字。清晰的图表,没有效果,只有相关的图像。每张幻灯片不要超过五个简短的要点。
  • 第一张幻灯片是开场幻灯片,包含关键信息、作者、演示名称、资助机构的附属机构和徽标。第二张幻灯片总结了演示者(您)的信息。第三张幻灯片描述了演示的内容,并列出了关键部分。
  • 最后一张幻灯片,你通常会问观众是否有任何问题,这可能是展示中最长的一张——明智地使用它,总结演示或放入有用的链接。
  • 有用链接的二维码是一个新领域,可以帮助观众快速找到你所指的信息。
  • 如果观众想在问答环节返回,不要忘记幻灯片编号。
  • 准备的时候,录下自己的声音,几个小时后再看一遍,这不失为一个好主意——总是有助于提高速度。
  • 当创建海报而不是演示文稿时,请记住,在海报会议期间,您的观众将首先检查海报(它应该有足够的信息来理解论文)。当一个人看完海报后,他们可以提问。在这里,图像将服务于他们的目的。有人建议我把 30%/70%的文本/图像分开。

顶级会议演讲总感觉流畅随意,就好像主讲人在现场演讲一样。没有窍门——演示是一遍又一遍地排练的,重复十几次后,你就会自然流畅了。

录制演示文稿时,最好在你面前准备好文本,这会节省你大量的时间。PowerPoint 是一个非常强大的演示记录工具。确保你有一个好的麦克风——声音很重要。

最后,你的声音很重要,参加声音课程是个不错的主意。我拍了这张

作为一个团队工作

大学做了大量工作来确保 STEM 学生在本科或硕士项目期间获得足够的合作经验。尽管这些都是进入现实世界项目的很好的速成课程,但是交互通常是短暂的,不需要日常交互。

协同工作

博士需要合作,每个博士生必然要建立的长期关系之一是与他们的导师和研究小组的其他成员的关系,这意味着你不可避免地会发展其中的一些特质:

  • 拥有你的作品——对你写的每一行代码和每一段文字负责。你可能不是专家,甚至不知道答案,承认吧,做好你的功课,认真对待它。
  • 如果出了问题,不要找借口。“那不是我的工作”是你永远不应该大声说出来的话。
  • 解释时,确保使用观众容易理解的术语和例子。
  • 如果有必要的话,忽略边界来完成你的项目。如果你发现了一个问题,而这个问题不在你的范围内,提出来并提供帮助来解决它。
  • 思考你的决定对其他团队成员的影响,尤其是随着时间的推移。一个简单的例子是记录你的代码,确保其他人可以很容易地使用它。
  • 考虑项目的未来结果—您的解决方案是否可扩展?它容易与项目的其余部分集成吗?
  • 学会接受批评。最好的学习方法是培养一种成长的心态,就像马尔科姆·格拉德威尔的《局外人:成功的故事》
  • 尽早提出问题——这可能是我得到的最好的工作建议。你越早养它们,你就能越早修复它们。人们讨厌你在最后一刻带着问题来找他们——但是你很快就知道了。

这里提到的许多方面都可以很好地概括为亚马逊在员工身上寻找的品质

团队合作从来都不是一帆风顺的过程,要在职业关系的风暴中航行,我从博士学位中学到了两个教训,第一个是诚实地回答这个问题:“你想正确还是快乐?”另一个我从经验中学到的是:“私下批评,公开表扬。”我在克里斯·沃斯的《永远不要分割差异:谈判就像你的生活取决于它一样》一书中找到了很多有用的建议。

领导和项目管理

我的一个朋友指出,博士学位是学习项目管理核心原则的绝佳场所——你会得到大量实践,每一份出版物都是一个新项目,在一份入门级工作中,你很少被委以如此高的责任——管理从研究到交付的整个流程。

  • 总是分配比你预期的项目需要更多的时间。《T2》中的卡尼曼从自己的经历中给出了一个很好的例子。一群学者想写一本书,在开始之前,每个成员都要预测一下这项工作需要多长时间。或许不足为奇,大家都低估了。
  • 第二,构建一个简单的解决方案,然后增加复杂性。确保定期问自己:“你目前正在做的事情对当时的项目至关重要吗?”首先关注关键部分。
  • 设定明确的目标——据说科洛列夫(伟大的俄罗斯工程师)说过:“80%的项目成功在于明确的任务和目标”。
  • 委派。你很容易一头扎进问题中,然而,对于一个应该领导他人的人来说,理清思路,能够预见未来更为重要。
  • 确保每一次谈话都被记录在电子邮件中或稍后发送的会议记录中——这允许团队作为一个整体成为过程的一部分,也有助于回顾未完成的任务,甚至有助于解决冲突。

结论

也许发展软技能的主要困难在于,如果你缺少了一项,很难发现。同样,注意到你已经获得了一个也是困难的。我发现,只有在重读了第一年的报告(一份总结你博士第一年成就的评估报告)后,我的写作技能才有所提高。这并不可怕,但是有很大的改进空间。然而,在写作的时候,我觉得我不可能写出比这更好的东西了…

大多数技能都是通过重复获得的——通常没有诀窍。这也是为什么一些软技能在博士期间很容易被开发的原因。在三年(在英国)到五年(在美国)的时间里,候选人要经历重复的出版周期,包括研究、项目管理、论文撰写、答辩和陈述。一次又一次,在这些领域获得的技能得到完善和净化。

我在本文中提到了一些工具、书籍、课程和文章,您可能会发现这些工具、书籍、课程和文章对提高您的软技能很有用:

如果你喜欢这篇文章,请与朋友分享!要阅读更多关于机器学习和图像处理的主题,请点击订阅!

喜欢作者?保持联系!

我错过了什么吗?不要犹豫,直接在 LinkedInTwitter 上给我留言、评论或发信息吧!

扩展我的表格模型的三个步骤

原文:https://towardsdatascience.com/three-steps-for-expanding-my-tabular-model-9e2d939378d7

在 Power BI 中扩展数据模型是一项日常任务。我们定期这么做。但是,大多数时候,我们没有考虑我们需要采取的三个必要步骤。让我们深入研究一下。

林赛·亨伍德Unsplash 上拍摄

介绍

每当我们必须改变我们的数据模型时,我们必须首先理解需求。

一旦我们知道需要什么,我们就必须:

  1. 定义目标数据模型
  2. 获取和准备数据
  3. 完成数据模型并计算和测试结果

大多数时候,我们是凭直觉做到这一点的。

但有时,我们需要重新考虑我们必须做什么以及如何去做。

虽然下面解释的需求是相对具体的,但是我将使用标准方法来满足这些需求。正如你将看到的,我会遇到一些不寻常的挑战,我会告诉你如何解决它们。

要求

我的一个客户问我,他如何根据年销售额对客户进行分类,并在 Power BI 的切片器中使用这些分类。

因此,我需要创建一个计算列来计算每个客户每年的销售额,并将分类分配给客户。

让我们来完成这些步骤。我们会在前进的道路上发现一些绊脚石。

步骤 1 —数据建模

下图显示了原始数据模型:

图 1 —原始数据模型(作者绘制)

从逻辑的角度来看,我们需要创建一个结合所有客户和所有年份的表。然后,我们可以计算每个客户每年的销售额,对每个客户进行分类。

下面您会看到带有附加表的数据模型:

图 2 —数据模型(起点)(作者绘制)

新的每年客户分类表与客户表中的客户 Id 和日期表中的年份相关联。从而创建了一个与数据表的 m:n 关系。

因为我想用客户类别的选择来过滤日期客户表,所以我需要将关系设置为双向过滤:

图 3 —双向过滤的数据模型(作者绘制)

但是,这种配置给数据模型带来了不确定性:

图 4 —不明确的数据模型(由作者绘制)

如您所见,Sales 表可以通过多条路径到达。表格模型不允许这样的配置。

当我试图将第二个关系设置为交叉筛选时,我得到一条错误消息:

图 5 —不明确的错误消息(作者提供的图片)

这个特性确保了我的数据模型不会有歧义。

由于这种方法行不通,我们需要将逻辑视图转移到技术视图来解决这个问题。

在继续之前,花点时间尝试自己找到解决方案:

.

.

.

.

在 Power BI 或 Analysis Services (SSAS)的表格模型中建模数据的一个原则是避免雪花模式,如上所示。重温一段感情需要时间。这同样适用于使用雪花来过滤数据。

参加 SQLBI 关于数据建模的免费在线课程可以获得关于这个主题的很好的解释。

或者观看以下来自 SQLBI 的关于模糊性问题的视频:

好吧,有什么解决办法?

我们需要改变模型,在新的每年客户分类表和销售表之间建立联系:

图 6 —目标数据模型(由作者绘制)

为了实现这一点,我们需要在两个表中添加一个额外的列,将 CustomerKey 和订单年份结合起来

下一步,我们将准备数据来满足这些要求。

步骤 2 —数据准备

首先,我们必须决定在哪里准备数据。

当我们有一个关系数据库作为数据源时,我们可以在数据库中创建一个视图,或者添加一个新表并定期刷新数据。

如果这是不可能的,我们可以使用数据库查询或使用 Power Query 来准备数据。

在我的例子中,不允许我更改源上的数据库。

但是在将数据导入 Power BI 时,我可以通过查询添加新表。

但是,我们有两种方法来准备新表:

  1. 从所有客户与所有年份的组合来看
  2. 来自销售表中客户和订单日期的组合

这两种变体之间的区别如下:

  • 使用 Customer 表时,每个客户和年份都有一行,不管该客户在该年是否下了订单
  • 使用 Sales 表时,您将只获得每年下订单的客户的行
  • 使用销售表时,您将得到一个更短的表

您需要根据自己的需求来决定哪种变体最适合您:

  • 如果您只对某一年有订单的客户感兴趣,那么可以使用销售表
  • 当您对所有客户都感兴趣时,不管订单如何,请使用客户表

根据源系统的不同,加载时间会有所不同。您必须用您的源系统测试这一点。查询折叠可以在这个场景中产生显著的不同。

通过查询获取数据

从数据库中,我们可以使用以下查询从 Customer 表中获取数据:

WITH [Years]
AS
    (SELECT DISTINCT [Year]
        FROM [dbo].[Date])
    SELECT [CustomerKey]
        ,[Year]
        ,CONVERT(nvarchar(50)
              , [CustomerKey]) + ‘_’ + CONVERT(nvarchar(50), [Year]) AS [CustomerPerYear]
      FROM [dbo].[DimCustomer]
           CROSS JOIN [Years];

或者类似下面的查询,当从 Sales 表中获取数据时:

SELECT DISTINCT CONVERT(nvarchar(30), [CustomerKey]) + ‘_’ + CONVERT(nvarchar(30), YEAR([OrderDate]) )
    FROM [dbo].[V_FactOnlineSales];

但是有时候,你必须使用 Power Query 来准备你的数据。

例如,当源数据不是来自关系数据库,或者您不具备所需的技能时。

使用 Power Query 获取数据

让我们看看如何使用 Customers 表作为源为新表准备数据:

  1. 打开 Power Query 并从 Customer 表中创建一个引用:

图 7 —创建客户表的引用(作者提供的图片)

2.删除除客户密钥之外的所有其他列:

图 8 —删除所有列,除了自定义键(图片由作者提供)

3.从日期表中添加自定义列:

图 9 —从日期表中添加一个定制列(作者提供的图片)

4.展开日期表,仅使用年份列:

图 10 —展开数据表(作者提供的图片)

这一步对应于上面 SQL 语句中的交叉连接。它将 Customer 表的每一行与 date 表的 Year 列中的每个值相乘。

5.选择剩余的列并删除所有重复的列:

图 11 —删除所有重复项(图片由作者提供)

现在你看到结果了:

图 12 —日期表中所有年份所有客户的结果(作者提供的图片)

当使用 Sales 表作为新表的源时,过程是不同的。

首先,您必须在 Sales 表中创建键列,结合 CustomerKey 和 Year:

图 13 —添加新的键列(作者提供的图片)

对新表使用以下表达式:

Text.From ( [CustomerKey] ) & “_” & Text.From ( [OrderYear] ))

在 sales 表中,可以使用下列表达式之一:

当您有一个数字日期键列时,可以使用下面的表达式,如 20220322:

Text-From ( [CustomerKey] )
    & “_”
    & Text.From ( OrderDateKey / 10000 )

或者这个表达式,当 OrderDate 作为日期列时:

Text.From ( [CustomerKey] )
    & “_”
    & Text.From ( Date.Year ( [OrderDate] ) )

接下来,创建一个被引用的表,删除除新的 CustomerPerYear 列之外的所有列,并删除重复的列。

现在,您已经准备好将数据加载到数据模型中,并完成解决方案。

步骤 3 —完成数据模型并计算和测试结果

下一步是在新的每年客户分类表和销售表之间添加一个关系:

图 14 —带有新表的数据模型(作者提供的图片)

下一步是使用上下文转换来计算每个客户每年的销售额。

如果您不了解这种机制,可以阅读我关于上下文转换的文章:

首先,我们创建一个调用现有销售度量值的计算列:

Sales per Year = [Online Sales (By Order Date)]

下一步是验证结果。

我在我的报告中添加了一个矩阵,包括客户、年份和基本度量,比如销售额。现在,我可以使用矩阵中的结果与新表中的结果进行比较。

图 15 —结果的验证(作者提供的图片)

下一步是添加计算分类的条件:

Category by Sales =SWITCH( TRUE()
    ,ISBLANK([Online Sales (By Order Date)]), “No Sales”
        ,[Online Sales (By Order Date)] < 10000, “Small Sales”
        ,[Online Sales (By Order Date)] >= 10000
           && [Online Sales (By Order Date)] < 25000, “Medium Sales”
        ,”Large Sales”
        )

现在可以创建一个度量来计算新的客户每年分类表中的行数(Counter = count rows(‘客户每年’)),从而创建一个如下所示的报告:

图 16 —包含每个类别的销售和客户(包括没有销售的客户)的报告(图片由作者提供)

要获得这个报告,您必须使用新表中的 Year 列。日期表中的年份列将不起作用。

有一个解决方案可以解决无法使用日期表的问题。

我邀请你思考这个问题,并写下你的解决方案作为回应。

结论

如您所见,逻辑或业务视图和技术解决方案之间可能存在差异。

它有助于为您的模型创建计划更改的绘图。这样的绘图将有助于看到和理解计划中的变化的含义。

这些要求对数据的准备有重大影响。您需要了解预期,以便根据需要准备数据。

完成数据模型的最后一步很简单,因为绘图已经包含了数据模型的定义。

计算结果的 DAX 代码是最后一步,可能非常简单也可能非常复杂。计算也是由需求定义的。

如您所见,对需求的理解对于解决方案的定义至关重要。理解需求所花的每一分钟都将节省您在实施解决方案过程中的时间。

不要小看这个。

达伦·劳伦斯Unsplash 上拍摄的照片

参考

我使用 Contoso 样本数据集,就像我以前的文章一样。你可以从微软这里免费下载 ContosoRetailDW 数据集。

Contoso 数据可以在 MIT 许可下自由使用,如这里的所述

https://medium.com/@salvatorecagliari/membership

用于机器学习的缩放特征的三种技术

原文:https://towardsdatascience.com/three-techniques-for-scaling-features-for-machine-learning-a7bc063ecd69

现代数据堆栈的扩展功能

照片由 Julentto 摄影Unsplash 上拍摄

虽然数字特征的缩放并不总是需要像 Praveen Thenraj 在他关于基于树的机器学习技术的帖子中解释的那样进行,但它确实有利于线性和逻辑回归、支持向量机和神经网络。许多数据科学家已经创建了建模脚本,用于自动构建和测试许多不同类型的建模算法。这些脚本允许数据科学家为该数据选择性能最佳的模型。特征的缩放通常在这些脚本中执行。

使用了两种主要的缩放技术。第一种是标准缩放(或 z 缩放),计算方法是减去平均值并除以标准差。第二个是最小-最大缩放,计算方法是减去最小值,再除以最大值和最小值之差。

sci kit-基于学习的缩放

通过从预处理模块导入StandardScaler并将其应用于数据帧,标准缩放器可用于缩放列scale_columns的列表

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df[scale_columns] = scaler.fit_transform(df[scale_columns])

类似地,最小-最大缩放器可以应用于与

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
df[scale_columns] = scaler.fit_transform(df[scale_columns])

仅基于熊猫的缩放

由于 scikit-learn 模块相当大,如果它仅用于缩放特征,那么使用 pandas 进行缩放会更容易。要按平均值和标准差缩放每个要素,请调用

df[scale_columns] = (df[scale_columns] - df[scale_columns].mean()) /
                     df[scale_columns].std()

请注意,这并不重复来自StandardScaler的结果。这是因为 scikit-learn 使用了 numpy 的std函数。默认情况下,该函数使用 0 个自由度。另一方面,熊猫的std是默认的无偏估计量。要获得相同的值,请运行

df[scale_columns] = (df[scale_columns] - df[scale_columns].mean()) /
                     df[scale_columns].std(ddof=1)

类似地,要获得最小-最大缩放器,运行

df[scale_columns] = (df[scale_columns] - df[scale_columns].min()) /
                 (df[scale_columns].max() - df[scale_columns].min())

数据仓库中的 RasgoQL 伸缩

开源 Python 包 RasgoQL 可以直接在数据仓库中创建缩放变量,而不是从数据仓库中提取数据。首先,这将节省提取数据并在缩放后将其推回数据仓库的时间。其次,通过利用仓库的能力,可以一次转换大得多的数据集。

标准定标器可用作

scaledset = dataset.standard_scaler(
                       columns_to_scale=['DS_DAILY_HIGH_TEMP', 
                                         'DS_DAILY_LOW_TEMP',
                                         'DS_DAILY_TEMP_VARIATION',
                                         'DS_DAILY_TOTAL_RAINFALL'])scaledset.save(table_name='DS_STANDARD_SCALED')

类似地,最小-最大缩放器可以应用为

scaledset = dataset.min_max_scaler(
                       columns_to_scale=['DS_DAILY_HIGH_TEMP', 
                                         'DS_DAILY_LOW_TEMP',
                                         'DS_DAILY_TEMP_VARIATION',
                                         'DS_DAILY_TOTAL_RAINFALL'])scaledset.save(table_name='DS_MIN_MAX_SCALED')

这些缩放后的要素现在可以通过连接到原始数据或任何其他数据来使用。它们还可以用于管道建模、数据可视化和生产管道预测。可以通过调用to_df将缩放后的数据下载到 pandas 中用于建模

df = scaledset.to_df()

如果您想检查 RasgoQL 用来创建这个表或视图的 SQL,运行sql:

print(scaledset.sql())

最后,如果您在生产中使用 dbt,并且希望将这项工作导出为 dbt 模型,供您的数据工程团队使用,请致电to_dbt:

scaledset.to_dbt(project_directory='<path to dbt project>'

当在单台机器上处理少量数据时,scikit-learn 和 pandas 方法将很好地用于在建模之前缩放特征。但是,如果数据很大或者已经存储在数据库中,在数据库中执行缩放(使用 RasgoQL 或 SQL)可以在数据准备期间节省大量时间。更重要的是,用于缩放数据的代码可以很容易地放入生产工作流中,潜在地节省了将模型投入生产的数周时间。

如果您想查看 RasgoQL,可以在这里找到文档,在这里找到存储库

了解二分搜索法的三件事

原文:https://towardsdatascience.com/three-things-to-know-about-binary-search-cf3b00971c2c

彻底揭开二分搜索法的神秘面纱

二分搜索法将列表分为两部分,然后只关注其中的一部分。照片由克鲁索Unsplash 上拍摄

从概念上讲,二分搜索法是一种非常容易理解的算法。然而,实现它是非常困难的,尤其是当你试图实现它的许多变种时。我的目标是让你明白如何很好地实施二分搜索法,这将是你需要的关于二分搜索法的最后一本指南。

几点:第一,这篇文章是长文。有时候,当我们解释事情的时候,我们倾向于跳过对每个人来说不明显的事情。其次,我使用 Python 编写代码。在 Python 中,数组中的第一个元素的索引是0,数组中的最后一个元素的索引是len(array)-1。阅读本指南后,你将能够适应 1 索引语言。另外,Python 是一种动态类型语言。如果你使用像 C++这样的静态语言,为lohi使用合适的数据类型。

感恩:我从拉布拉东二分搜索法教程中学到了区间和退出条件的概念。这是我读过的关于面试算法的最好的公开指南。你在这里读到的一些东西是他思想的延伸。我认为他对寻找左右边界的解释太快了,所以我在本指南中花了相当大的篇幅来解释这个问题。

概念审查

二分搜索法是一种分治算法。目标是在排序后的数组中找到一个目标值。它只能处理已排序的数据,通常是按升序排序的。该算法通过选择数组中的中间点,然后将数组分为三部分:小于中间点的部分、中间点和大于中间点的部分。有关解释,请参见图 1。

图一。二分搜索法算法的概念概述。假设所有元素都是唯一的。作者图。

人们为什么与二分搜索法斗争?

从个人经验和阅读 StackOverflow 来看,实施二分搜索法的大部分问题似乎来自:

  • 越界->错误的间隔考虑
  • 目标存在但未找到->间隔之间的间隙
  • 返回了错误的元素->没有考虑退出条件
  • 第一个或最后一个元素的边界情况
  • 整数溢出(在 C++ 等静态类型语言中发现)

如果你需要精通二分搜索法的实现,你需要理解为什么会发生这一切。理解有三个步骤:(1)区间,(2)分区,(3)退出条件。

一:音程

首先,我们来复习一下音程的概念。结束间隔包括结束值,而开始间隔不包括。

  • 间隔[1,5]具有以下元素:1 2 3 4 5
  • 间隔[1,5)具有以下元素:1 2 3 4
  • 间隔(1,5)具有以下元素:2 3 4

考虑以下打印一组整数的函数。

循环的退出条件是lo > hi。当我们增加lo直到lo = hi+1时,它退出。这意味着该功能将打印出闭合区间[lo, hi]内的所有值,包括 lo 和 hi。

现在,考虑下面的函数。

该功能的退出条件是lo >= hi。当我们增加lo直到lo == hi的点时,它退出。这意味着该功能不会打印hi。该功能打印出左开区间[lo, hi)的所有值

Take away 1。如果我们想要一个两端封闭的区间[lo, hi],那么我们使用lo <= hi作为我们的循环条件。另一方面,如果我们想要一个左端开放区间[lo, hi),我们必须在循环条件中使用lo < hi

现在,让我们将它应用于遍历一个列表。在我们的封闭区间中,我们想要遍历范围[0, length(array) — 1]中的所有元素,因此我们的遍历循环如下:

如果我们想遍历一个左开区间,那么最后一个元素(不包括)应该是 length(array),我们的区间应该是[lo, length(array))

我的建议是,从现在开始,无论你什么时候实现二分搜索法,你都要使用封闭区间。不仅闭区间更容易理解,而且它还具有开区间所没有的对称性质。下面的函数说明了这一点,这些函数通过递减 hi 来向后遍历间隔。对称性使得封闭区间的反向版本成为可能,但开放区间版本则不可能。第一个功能覆盖[lo, hi],但是第二个功能覆盖(lo, hi]而不是[lo, hi)

第二:隔板

如果列表有不止一个元素,我们可以把它分成三个子列表。[lo, middle — 1]是左边的子列表,[middle, middle]是一个元素列表,[middle + 1, hi]是右边的子列表。

Take away 2。三个区间[lo, middle — 1] [middle, middle][middle + 1, hi]不重叠,并且覆盖了整个闭合区间[lo, hi]。这确保了列表中的所有元素都被考虑在内。

区间的选择是很多人犯错的地方:

  • 为什么左音程在middle-1结束?因为记住这些都是闭区间(含闭区间)。[lo, middle-1]表示该区间也有元素middle-1。如果我们使用区间[lo, middle],那么我们的区间将与[middle, middle]元素重叠,这是我们不想要的。[middle+1, hi]的逻辑相同。

我使用我选择的三个封闭区间来实现。

最后,我们退出 while 循环,因为lo > hi,这表明我们在数组中找不到目标。它返回None

Take away 3。使用mid = lo + (hi — lo)//2。当你用其他语言实现二分搜索法时,用这个代替mid = (hi+lo)//2。这是因为hi+lo可以溢出(斯基亚纳的书是我第一次了解到这个的地方)。

如果我们想在区间[lo, hi)上搜索,而不是在封闭区间[lo, hi]上搜索呢?我们仍然可以对数组进行分区,但是我们的所有分区(除了中间的分区)都必须有右开区间。这是因为我们已经使二分搜索法适应右开音程,所以它接收的应该是右开的。回想一下,我们的起始条件应该是[0, length(array)),因为length(array)不包含在区间内。

我们想要的分区是[lo, mid)[mid+1, hi)

  • 为什么左音程在mid结束?因为这个区间是[lo, mid)所以它不包括mid元素。因此它不与[mid, mid]区间重叠。自己确认它们没有重叠,并且仍然覆盖整个右开区间[lo, hi)

三:退出条件

在我们的封闭区间例子中,如果目标不在数组中,那么最终lo > hi和 while 循环退出。但是在这些情况下lohi指针在哪里呢?

考虑下面的排序数组[0 1 2 3 4 5]和三种情况的target:

  • 目标= -2
  • 目标= 10
  • 目标= 3.5

一旦我们退出循环,这里就是lohi指针所在的位置(注意在所有这些情况下都是lo > hi)。

图二。作者图

Take away 4。如果targetarray中不存在,那么lo显示的是目标在数组中的索引。对此的解释相当简单:

  • 在第一种情况下,我们只更新hi的值,因为nums[mid] > target在 while 循环的每次迭代中。这意味着lo停留在0直到我们退出。因为新元素比所有其他元素都小,所以我们将它插入位置0
  • 在第二种情况下,我们只更新lo的值,因为在 while 循环的每次迭代中nums[mid] < target。当lo > hilo == hi + 1时,回路存在。因为hi指针不改变值,我们在lo == length(array)时退出循环。因为新元素比其他所有元素都大,所以我们将它插入到位置length(array)。(array指原数组)
  • 在第三种情况下,由于 target 不存在,我们将列表分成两部分:小于target的列表和大于target的列表。当循环退出时,lo标志着第二部分的开始。当我们插入目标元素时,它将获取lo所指向的索引。

如果你不熟悉,这可能很难得到,所以一步一步地自己看几个例子。调试工具可以帮助您在循环的不同迭代中查看lohi的值。另一种思考方式是lo指针索引显示有多少元素严格小于目标。在第一个例子中,有一个比-2小的0元素。在第二个例子中,有比10小的6元素。在第三个例子中,有比3.5小的4元素。

我们为什么要做这些?因为我想告诉你如何修改二分搜索法算法来完成许多其他任务,每个任务都建立在前一个任务的基础上。相信我,一切都是值得的。

二分搜索法的变体

任务 1。找出比目标值小的元素数

我们之前的观察是一个很好的起点。当我们退出循环时,我们返回lo而不是None。但是,当我们在数组中找到target时,我们该怎么办呢?我们知道,如果目标不存在于数组中,那么函数将退出,并且lo指向解。换句话说,如果array[mid] == target没有被调用,那么函数将退出,并且lo指向解决方案。我们可以修改前面的函数,这样当array[mid] == target不返回mid时,我们更新lo或者hi指针。

那么,我们更新哪个指针呢?这取决于我们想在哪里搜索。如果我们找到一个等于target的值,并且我们想知道有多少个元素更小,那么专门在较低的分区中搜索是有意义的。因此,我们希望更新 hi 指针,将搜索区间缩小到[lo, mid-1]

这是我们的解决方案。注意第 8 行是我们修改的地方。

任务 2。找到目标的第一次出现

想象一下,如果我们的排序列表没有唯一的元素。我们的任务是找到第一次出现的target。我们不能使用常规的二分搜索法,因为它不能保证我们将返回正确的索引。

这个任务和任务 1 很像(原因就看你自己了)。事实上,任务 1 的解决方案在大多数情况下都适用。唯一的问题是当元素在数组的边缘或者target不在数组中的时候。请记住,任务 1 的解决方案返回数组中小于目标的元素数,因此结果可以是从0length(array)的任意值。

  • 如果当lo == len(array)时 while 循环存在,那么我们知道所有元素都小于 target。我们可以返回-1,因为目标不存在
  • 否则,lo指向大于或等于 target 的第一个元素(仔细阅读)。该元素可以是lo或大于lo。我们简单地检查一下array[lo] == target

任务三。找到目标的最后一次出现

我们能反过来吗?是的,我们可以感谢闭区间的对称性(这是我在编码二分搜索法时推荐闭区间的另一个原因)。我们需要修改以下内容:

  • array[mid] == target时,我们现在更新 lo 指针,这样我们就可以专注于闭合区间[mid+1, hi]
  • 我们返回hi的值。该值的范围从-1length(array)-1(返回图 2 查看hi的范围)。如果hi == -1,那么所有元素都大于目标,所以我们返回None

任务 4。第一缺陷元素

给定两个数组,一个充满缺陷元素(表示为“F”),一个充满正常元素(表示为“T”)。不知道两个数组是否都非空。我们将两个数组连接在一起,这样得到的数组如下所示:

[T T T T T T F F F F F F F F F F F]

我们的任务是找出正常元素的数量。要了解二分搜索法如何提供帮助,请考虑一个只有两个唯一数字 1 和 2 的数组:

[1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]

显而易见,我们可以使用函数elements_less_than来查找数组中 1 的数量。现在,假设我们所有的输入都是由数字 1 和 2 以这种方式排列而成的。我们可以通过删除不必要的代码来修改函数:

请注意两个变化:

  • 我们删除array[mid] > target分支条件。之所以不需要,是因为数组只有 1 和 2,所以我们没有大于 2 的元素。
  • 我们将array[mid] < target改为array[mid] == 1。这是因为元素小于 2 的唯一方式是它等于 1。

简单地用 T 和 F 代替 1 和 2 就得到我们的解。另一种思考方式是,当我们找到 T 时,我们需要更新对上层分区的搜索,反之亦然。

外卖食品

  1. 这是我推荐的二分搜索法框架。它使用封闭区间[0, length(array) — 1]。记住三个分区[lo, mid-1][mid, mid][mid+1, hi]。如果要使用 open interval [0, length(array)),记得正确分区即可。

2.现在,您可以通过考虑以下四点来调试任何二分搜索法代码:

  • 间隔是多少?
  • 分区重叠并覆盖整个阵列吗?
  • 当循环退出时,lohi的位置在哪里?
  • 如果目标位于边缘会发生什么?

编码快乐!

以下是一些训练问题:

https://leetcode.com/problems/find-smallest-letter-greater-than-target/ https://leetcode.com/problems/sqrtx/ https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/

在 DAX 中使用变量时,你需要知道三件事

原文:https://towardsdatascience.com/three-things-you-need-to-know-when-using-variables-in-dax-c67724862b57

在 DAX 中,变量可以被长期使用来简化代码,有时还可以提高性能。以下是你需要知道的关于 DAX 变量的内容。

机器人神童Unsplash 上拍摄的照片

DAX 中的变量是什么

如果您已经知道如何在 DAX 代码中使用变量,请继续学习。这部分是给初学者的。

变量可以在任何 DAX 代码中长期用于 Power BI 和 SQL Server Analysis Services。

我们可以使用变量来存储中间结果。

使用以下语法定义变量:

VAR VarName = <Value>

您不需要在 DAX 中指定数据类型,因为数据类型是自动分配的。

你甚至不需要事先声明一个变量。当你要给一个变量赋值的时候,你就已经创建了一个变量。

一旦创建了变量,就必须将 RETURN 子句添加到 DAX 代码中以返回值。

例如,我想用名为 Var1 的变量执行一个查询,将它的值设置为 100 并返回这个值:

EVALUATE
 VAR Var1 = 100

RETURN
 {Var1}

我需要添加花括号来将变量转换成一个一列一行的表格。

那么,我们能对变量做些什么呢?

我们可以分配比标量值更多的值

我们可以像任何其他编程语言一样,在 DAX 中为变量赋值一个标量值。

变量的创建看起来像这样:

VAR Var1 = 100

这一行创建了一个名为 Var1 的变量,并将值 100 赋给它。

此外,我们可以调用 DAX 测量,并将测量结果赋给变量:

VAR SalesAmount = [Sum of Sales Amount

然后在度量的筛选器上下文中评估该度量。

但是我们可以做得更多。

我们可以将整个表添加到一个变量中,并在下面的表达式中使用该变量。

例如,我想创建一个过去 45 天的日期列表,并计算这些天的销售额:

DEFINE MEASURE ‘All Measures’[SalesLast45Days] =
 VAR Last45Days = DATESINPERIOD(‘Date’[Date], MIN(‘Date’[Date]), -45, DAY)

 RETURN
     CALCULATE([Online Sales (By Order Date)]
               ,Last45Days
               )

 EVALUATE
    ADDCOLUMNS(
        SUMMARIZE(‘Date’
               ,’Date’[EnglishYearMonthShortName])
               ,”Sales”, [Online Sales (By Order Date)]
               ,”SalesLast45Days”, ‘All Measures’[SalesLast45Days]
               )

我在 DAX Studio 的查询中动态地创建了一个度量“All Measures”[sales last 45 days]。

使用 DATESINPERIOD(),我生成一个日期列表,从查询的过滤器上下文中的第一天开始,到 45 天之前。然后将这个列表赋给变量 Last45Days。

在返回之后,我在 CALCULATE()函数中使用这个表作为过滤器。

结果如下图所示:

图 1 —查询过去 45 天的销售额和结果(图由作者提供)

听起来很酷?

一个变量只计算一次

使用变量时,变量只计算一次,变量中的值可以在表达式中多次使用。

查看以下代码,以百分比形式计算年销售额(YoY)的变化:

[YoY %] =
 VAR Sales = [Online Sales (By Order Date)]

 VAR SalesPY = CALCULATE([Online Sales (By Order Date)]
 ,SAMEPERIODLASTYEAR(‘Date’[Date])
 )

RETURN
    DIVIDE(Sales — SalesPY, Sales)

如您所见,Sales 变量可以在 DIVIDE()函数中重用两次。

这意味着分配给 Sales 变量的度量结果只计算一次。

这项措施的结果如下:

图 2 —用 YoY %度量值进行查询(作者提供的数据)

度量中变量的这种可重用性可以显著提高性能。

一个变量只计算一次(又一次?)

您可能已经注意到了上面代码中的一个小细节。

当我可以重用一个变量时,为什么我不这样写这个度量呢?

[YoY %] =
VAR Sales = [Online Sales (By Order Date)]

VAR SalesPY = CALCULATE(Sales
 ,SAMEPERIODLASTYEAR(‘Date’[Date])
 )

RETURN
    DIVIDE(Sales — SalesPY, Sales)

这一次,我在 CALCULATE()函数中使用了 Sales 变量。

可惜这不管用。

以上带有变体的查询结果如下所示:

图 3 —使用错误的年同比百分比度量进行查询(由作者提供)

当我更改度量的代码以返回 CALCULATE()函数的结果时,我们可以找到原因:

图 4——销售变量可以在计算中重用的原因(由作者提供)

您可以看到 CALCULATE()函数的结果与原始销售度量值相同。

原因是分配给变量的值已经被评估,并且过滤器上下文丢失。所以,计算并不影响结果。

当使用变量来理解 DAX 代码的结果时,您必须始终考虑过滤器上下文。如果你不去做,你会得到意想不到的结果。

结论

变量是 DAX 工具箱的重要组成部分,我建议使用它们来简化 DAX 代码。

当我在 DAX 中开发复杂的计算时,我总是使用变量来获得中间结果。使用这种方法,我可以交叉检查每一步并验证结果。

在 DAX 中使用变量的另一个好处是,您可以避免创建中间度量,因为您可以在一个度量中完成所有这些。

谢谢你一直读到最后。

山姆·克拉克在 Unsplash上的照片

参考

我使用 Contoso 样本数据集,就像我以前的文章一样。你可以从微软这里免费下载 ContosoRetailDW 数据集。

Contoso 数据可以在 MIT 许可下自由使用,如这里的所述

https://medium.com/@salvatorecagliari/membership

解析 Python 代码中参数的三种方法

原文:https://towardsdatascience.com/three-ways-to-parse-arguments-in-your-python-code-aba092e8ad73

通过使用 Python 中的命令行和配置文件来提高代码的效率

里卡多·安南达尔在 Unsplash 上的照片

如果你在机器学习和深度学习模型方面做了很多工作,你可能会在 Jupyter 笔记本或 python 脚本上尝试改变超参数一百万次,以提高数据集的性能。如果每次编辑时都要检查代码,这可能会很耗时。

在从事数据科学项目时,我发现了不同的方法来加速这种持续的变化。第一个选项是使用argparse,这是一个流行的 Python 模块,专门用于命令行解析。另一种方法是读取 JSON 文件,在那里可以放置所有的超参数。第三种也是不太为人所知的方法是使用 YAML 文件!你好奇吗?开始教程吧!

先决条件

在本教程中,我将使用 Visual Studio 代码,这是一个非常高效的 Python 集成开发环境。这个程序的美妙之处在于,它通过安装扩展支持每一种编程语言,集成了终端,并允许同时处理大量的 python 脚本和 Jupyter 笔记本。如果您从未使用过它,请查看本指南这里的开始使用

为了展示这些命令行策略的效率,自行车共享数据集 [1]正被用于根据温度、风速和湿度等特征来预测每小时租赁自行车的数量。这个数据集可以在 UCI 的机器学习库Kaggle 上找到。

目录:

  1. 使用 argparse
  2. 使用 JSON 文件
  3. 使用 YAML 文件

1.使用 argparse

使用 argparse 的项目结构。作者插图

在我们的迷你项目中,我们有一个标准的结构来组织我们的工作:

  • 名为data的文件夹包含我们的数据集
  • train.py文件
  • 用于指定超参数的options.py文件

首先,我们可以创建一个文件train.py,其中包含导入数据、根据训练数据训练模型以及在测试集上评估模型的基本过程:

在代码中,我们还导入了 train_options 函数,它包含在options.py文件中。后一个文件是一个 python 文件,从中我们可以更改 train.py 中考虑的超参数:

在这个例子中,我们使用了argparse库,这是一个非常流行的解析命令行参数的库。首先,我们初始化解析器,然后,我们可以添加我们想要访问的参数。

这是一个运行代码的示例:

python train.py

要更改超参数的默认值,有两种方法。第一个选项是在options.py文件中设置不同的默认值。另一种方法是从命令行传递超参数值:

python train.py --n_estimators 200

我们需要指定想要更改的超参数的名称以及相应的值。

python train.py --n_estimators 200 --max_depth 7

2.使用 JSON 文件

使用 JSON 文件的项目结构。作者插图

像以前一样,我们可以维护一个类似的文件结构。在本例中,我们用一个 JSON 文件替换了options.py文件。换句话说,我们希望在 JSON 文件中指定超参数的值,并将它们传递给train.py文件。与 argparse 库相比, JSON 文件可能是一个快速而直观的替代方案。它利用键值对来存储数据。下面,我们创建了一个options.json文件,其中包含了我们稍后需要传递给其他代码的数据。

{
"normalize":true,
"n_estimators":100,
"max_features":6,
"max_depth":5 
}

如您所见,它非常类似于 python 字典。与字典不同,它包含文本/字符串格式的数据。此外,还有一些语法略有不同的常见数据类型。比如一个布尔值是 / ,而 python 识别的是 / 。JSON 中其他可能的值是数组,用方括号表示为 python 列表。如果您想深入理解 JSON 文件所要求的语法,请在这里查看其他案例。

在 python 中使用 JSON 数据的好处在于,它可以通过load方法转换成 python 字典:

f = open("options.json", "rb")
parameters = json.load(f)

要访问一个特定的项目,我们只需要引用它在方括号中的键名:

if parameters["normalize"] == True:
    scaler = StandardScaler()
    X = scaler.fit_transform(X)rf=RandomForestRegressor(n_estimators=parameters["n_estimators"],max_features=parameters["max_features"],max_depth=parameters["max_depth"],random_state=42)
model = rf.fit(X_train,y_train)
y_pred = model.predict(X_test)

3.使用 YAML 文件

使用 YAML 文件的项目结构。作者插图

最后一个选择是挖掘 YAML 的潜力。像 JSON 文件一样,我们将 python 代码中的 YAML 文件作为字典来读取,以访问超参数的值。YAML 是一种人类可读的数据表示语言,其中层次结构用双空格字符表示,而不是像 JSON 文件中那样用括号表示。下面我们展示了options.yaml文件将包含的内容:

normalize: True 
n_estimators: 100
max_features: 6
max_depth: 5

train.py中,我们打开options.yaml文件,该文件将始终使用load方法转换成 Python 字典,这次是从 yaml 库导入的:

import yaml
f = open('options.yaml','rb')
parameters = yaml.load(f, Loader=yaml.FullLoader)

和以前一样,我们可以使用字典所需的语法来访问超参数的值。

最后的想法

如果你在这里,你终于到了文章的结尾。恭喜你!本文的目标是展示三种优雅而有效的方法来解析 python 代码中的参数。

  • 配置文件编译起来非常快,而 argparse 需要为每个想要添加的参数编写一行代码。
  • 根据您的目的,这些方法中的一种可能是您的正确选择。
  • 例如,如果您需要为参数添加注释,JSON 并不合适,因为它不允许注释,而 YAML 和 argparse 可能是一个很好的选择。

感谢阅读。祝您愉快!

参考资料:

[1]https://www.capitalbikeshare.com/data-license-agreement

你喜欢我的文章吗? 成为会员 每天无限获取数据科学新帖!这是一种间接的支持我的方式,不会给你带来任何额外的费用。如果您已经是会员, 订阅 每当我发布新的数据科学和 python 指南时,您都会收到电子邮件!

使用人工智能生成令人惊叹的图像的三种方法

原文:https://towardsdatascience.com/three-ways-to-use-ai-to-generate-stunning-images-44c667c89a28

“照片/表现性油画/像素艺术,一名宇航员躺在沙漠中的躺椅上,喝着鸡尾酒。”—用 DALL-E2 使用各自的提示创建的图像。

最近,互联网上充斥着人工智能生成的惊人图像。也就是说,用户提供文本提示,AI 系统基于所述提示生成图像。有趣的是,它不仅产生了——坦率地说——非凡的图像,而且人们可以将有趣的想法和风格结合起来。这可能意味着你将一名宇航员放在沙漠中,并将其作为照片级真实感图像、富有表现力的油画或像素艺术。在这里,我们将提供三种方法,让你可以用不同的技术专业知识水平探索这些技术:在线版本的 DALL-E 2 ,谷歌 Colab,以及本地版本的稳定扩散。

背景

让我们首先简要了解一下不同技术的一些基本信息。DALL-E 2是一个拥有 35 亿参数的 AI 模型,由 OpenAI创成式预训练变压器(GPT) 模型的基础上构建而成。针对选定用户的测试阶段于 2022 年 7 月开始,并于 9 月 28 日由 OpenAI 向公众推出,源代码尚未公开。

与此相反,稳定扩散的代码和模型权重对公众可用。这是一个潜在的扩散模型,于 2022 年 8 月 22 日由 Ludwig Maximilian 大学(LMU)的 CompVIS 集团、stability ai——一家视觉艺术初创公司和 Runway 合作发布。稳定扩散模型是用大规模人工智能开放网络( LAION )的数据训练的,这是一家德国非营利组织,从网络上搜集图像。模型本身有 8.9 亿个参数,可以在消费级显卡上运行。

除了 DALL-E,还有 Midjourney ,它也只能通过云服务访问,并于 2022 年 7 月 12 日开始公开测试。

从商业角度来看,人工智能生成的艺术似乎非常有前途。StabilityAI 刚刚从筹集了 1.01 亿美元,Midjourney 声称已经盈利。

达尔-E 2

截至 2022 年 10 月的 DALL-E 登录后截图。

DALL-E 2 的用法简单明了:进入 OpenAI 的 DALL-E 2 页面注册。他们将需要一个手机号码来注册您的帐户。就是这样。你最终会看到一个类似谷歌的文本提示;输入你的想法,几秒钟内就能生成四幅示例图像。你可以点击单个图像,得到它们的变化。每要求 花费 你一个信用点;第一个月你将获得 50 个学分,随后的每个月会增加 15 个学分。此外,你可以花 15 美元购买 115 个积分。

稳定扩散

如果你更喜欢开源的替代稳定扩散,我们首先需要设置东西。

谷歌可乐。如果你没有合适的硬件,我推荐使用 Google Colab,它可以访问适合该任务的 GPU。作为起点,我们从这个笔记本开始。它需要一个拥抱脸令牌来访问模型权重。你可以通过创建一个拥抱脸帐户,前往稳定扩散模型,并接受共享模型的条款来获得令牌。

要生成图像,请执行所有单元格,直到需要输入令牌,然后继续执行,直到到达可以输入图像生成提示的单元格。这需要几分钟的时间,生成一幅图像需要几秒钟的时间。

Google Colab 和 Stable Diffusion:“一幅富有表现力的油画,描绘了一名宇航员躺在阳光躺椅上,在沙漠中喝着鸡尾酒。”

如果您想将图像保存到您的 Google Drive,例如保存在文件夹 exported-images 中,您可以这样做:

安装驱动器:

*from google.colab import drive
drive.mount(‘/content/gdrive’)*

保存图片(注意主目录是我的驱动为谷歌驱动)

*image.save(f"/content/gdrive/My Drive/exported-images/image.png")*

Google Colab 方法的一个局限性是,如果失去了与内核的连接,您需要重新设置环境。

本地安装。如果你有一台为深度学习任务而设置的 GPU 机器正在运行;您可以在本地安装并运行稳定的扩散。更准确地说,你应该有一个 Python 环境(比如 Anaconda 或者 Miniconda ), Git ,并且正确安装了 GPU,也就是 CUDA 驱动)。实事求是地说,对于一台装有 NVIDIA 卡的 Windows 机器,如果你运行

*nvidia-smi*

在命令行中,您应该会看到 CUDA 版本。对于安装,您可以遵循 GitHub 指令,但是本质上,您通过 Git 克隆存储库并创建和安装环境。

*conda env create -f environment.yaml
conda activate ldm*

接下来,你需要从稳定扩散的拥抱脸页面下载重量。我用的是最新的SD-v1–4 . ckpt。在 Linux 上,可以像 GitHub 存储库上描述的那样链接文件;在 Windows 系统上,您可以下载该文件并将其重命名为 model.ckpt,然后将其复制到稳定扩散模型的文件夹中,如下所示:

*models/ldm/stable-diffusion-v1/model.ckpt*

然后,您可以(在激活的环境中)通过命令行提示符创建图像(注意,您需要位于 GitHub 存储库的文件夹中):

*python scripts/txt2img.py --prompt "Expressive oil painting of an astronaut laying in a sun lounger with a cocktail in the desert" --plms*

“一幅富有表现力的油画,描绘了一名宇航员躺在太阳躺椅上,喝着沙漠中的鸡尾酒”——由稳定扩散的本地装置生成。请注意,我尝试了五种不同的种子,才在照片中找到一名穿着太空服的宇航员。

生成的图像将位于 outputs/txt2img-samples 中。

这里的是一个更详细的安装指南,也展示了如何使用网络界面。

我用 12 GB 内存的 Titan V 进行了测试,确实经常遇到内存问题。在这里,通过传递-H 或-W 参数或者用-n_samples 减少样本数来减小大小是有帮助的。

结论

今天,生成带有文本提示的 AI 图像出奇的容易。使用 DALL-E 2 这样的工具,甚至不需要昂贵的硬件或编码技能。虽然图像质量令人惊叹,但仍可能存在伪像,这些伪像会泄露图像是人造的,例如,当查看来自稳定扩散的本地安装的最后一个示例图像的阴影时。最终,我相信这将彻底改变创意部门,因为它从未如此容易地将想法可视化。

写下你作为数据科学家的工作对你的职业生涯有好处的三种方式

原文:https://towardsdatascience.com/three-ways-writing-about-your-work-as-a-data-scientist-can-benefit-your-career-fb8c390c06df

一年多来,我一直在媒体上写关于数据科学的文章。以下是我注意到这样做的所有好处。

照片由王思然·哈德森Unsplash 上拍摄

雇主喜欢它。

几个月前,我参加了一个极其漫长的职位面试过程——最终我决定不参加(浪费了 20 多个小时的面试)。这是一种会有无数候选人的工作,所有候选人的素质都差不多。因此,你必须站出来。每个人的简历上都有[Python,Pandas,TensorFlow,R,JavaScript]。在这个阶段,这些是先决条件,而不是工作保证。我面试的那家公司声称我脱颖而出的原因是因为我的写作。每个人都可以说自己懂 Python,但真正能证明的又有几个。是的,每个人都有 GitHub,但是你怎么知道有人真的理解他们页面上的代码呢?

为了解释和教导或解释某事,你必须去理解它。至少达到足够的工作水平。写一篇关于某事的文章表明了两件事,你在学习某事上投入了时间,并且这种投入得到了回报。雇主可以看到这一点,他们真的喜欢它。除此之外,这表明你对你所做的事情充满热情,表明在你正常的朝九晚五之外,你仍然在思考有趣的问题以及如何解决它们。对雇主来说又是一笔巨大的奖金。

我最近也站在了招聘台的另一边,你会注意到个人简历是多么的千篇一律。我意识到我们并不总是雇佣绝对最好的技术人员。

我们从技术水平最低的团队中雇佣最优秀的

谁是最好的人?成为一名有效的数据科学家的很大一部分是你如何交流你的想法和想法。这是你如何向高级人员推销你的想法,这是你如何向没有技术知识的人解释你的代码。这几乎和能够工作一样重要。技术能力是必备的,但如果你真的想出类拔萃,帮助你扬帆起航的是个人技能。

写作证明了这种能力。

写作学习——费曼技巧

我说,要教或解释某事,你必须理解它。这是第二个原因,你可以通过教授或写作来更好地理解事物。

我们大多数从事科学研究的人都会听说过理查德·费曼,所以我不会详细解释他的想法。但是基本上,他说如果你不能教(一个孩子)它,你就不理解某些东西。没有比写一篇关于某事的文章更好的方法来确保你理解了它。

费曼技术有四个关键步骤:

  1. 选择一个你想了解的概念
  2. 向一个 12 岁的孩子解释
  3. 反思、提炼和简化
  4. 组织和审查

当你写一篇技术文章时,这和你要经历的过程完全一样。

首先,代码必须工作,其次,解释必须有意义。写文章是确保你真正理解某事的一种万无一失的方法。相信我,你可以认为你知道一些事情是如何运作的,直到你尝试在这里解释它。你当然不会有信心把一个东西发布给全世界,如果你觉得你没有完全理解这个东西的话。

我还觉得写文章鼓励你清理代码——没有人愿意和全世界分享丑陋的代码。

你做笔记是有报酬的。

就这么简单,你拿工资——记笔记。反正我就是这么看的。参考前面两点,无论如何这样做是有益的——所以为什么不为此获得报酬呢?我绝对没有从《灵媒》赚到足够的钱来生存(感谢伦敦),但它确实有帮助。将它们发布在媒体上也让你(以及任何朋友、同事或陌生人)可以随时看到它们。如果你想的话,你可以在你的工作电脑、私人手机或者奶奶的 kindle 上下载。

拥有自己的笔记是非常宝贵的,这些笔记(如果你遵循了我之前的建议)被很好地构建、审阅和简化了。你可以理解自己的笔记,只需要你消化 Stackoverflow 中其他人答案的一小部分时间。我甚至不打算讨论花在寻找正确答案上的时间。

我们中的许多人每天都会消化如此多的代码和信息,以至于有时我们会忘记上周刚写的代码。拥有自己的个人演练是回到最佳状态的最快方法。当你在 medium 上写作时,最好的方法是在你的文章中包含 GitHub Gists ,这也迫使你保持你的 GitHub 更新。通过写你的工作,你创建了你自己的小代码存储生态系统,在那里一切都是容易访问和理解的。你甚至可以把你的文章添加到你自己的个人博客/网站来增加流量。你有 Github 作为代码,有 Medium(或另一个平台)作为笔记。它们之间只有一次点击的距离。

我有没有说过,你做这个是有报酬的?

有没有什么时候我不应该写我做过的事情?

有几个原因让你不应该写你正在做的事情,其中大部分都与你工作的公司有关。永远不要分享他们不想让你分享的东西。绝对没有数据,没有公司特定的代码。你应该把重点放在对非特定问题的具体解决方案上,这些解决方案可以被归纳并在许多地方使用。

我也不建议分享你任何天才想法的代码。

请私下寄给我。

If I’ve inspired you to join medium I would be really grateful if you did it through this [link](https://jamesasher4994.medium.com/membership) — it will help to support me to write better content in the future.If you want to learn more about data science, become a certified data scientist, or land a job in data science, then checkout [365 data science](https://365datascience.pxf.io/c/3458822/791349/11148) through my [affiliate link.](https://365datascience.pxf.io/c/3458822/791349/11148)

这是我写的其他一些东西。

干杯,

詹姆斯

门限自回归模型——超越 ARIMA + R 码

原文:https://towardsdatascience.com/threshold-autoregressive-models-beyond-arima-r-code-6af3331e2755

满足 TAR——自回归模型的非线性扩展。

3844328

介绍

当谈到时间序列分析时,在学术上你最有可能从自回归模型开始,然后扩展到自回归移动平均模型,然后扩展到积分使其成为 ARIMA。接下来的步骤通常是季节性分析类型,包含额外的内生和外生变量(ARDL,VAR)最终面临协整。从这一刻开始,事情变得越来越有趣

这是因为这是严格而美好的程序的终结,例如在 Box-Jenkins 方法中。如前所述,时间序列中非线性排列的可能数量几乎是无限的——因此通用程序不再适用。是不是意味着游戏结束了?见鬼不要。如今,处理非线性时间序列最流行的方法是使用机器学习和深度学习技术——由于我们不知道时刻 t-1t 之间的真实关系,我们将使用一种不假设依赖类型的算法。

在机器学习之前,计量经济学家是如何管理这个问题的?这就是 TAR 模型的用武之地。

阈值自回归模型

让我们从简单的 AR 模型开始。其公式确定为:

一切都只存在于一个等式中——美丽。在我们继续讨论焦油的分析公式之前,我需要告诉你它实际上是如何工作的。首先,在 TAR 模型中,我们称之为机制。它们是什么?它们是由阈值分隔的区域,根据这些阈值我们切换 AR 方程。我们交换,什么?为简单起见,让我们考虑最简单的双机制 TAR 模型:

阈值自回归的一般方程,作者的图形。

其中:

p1,p2——自回归子方程的阶数,

r —已知的阈值,

z _ t——取决于状态的力矩 t 中的已知值

现在让我们来读一下这个公式,以便更好地理解它:

时间序列在时刻 t 的值等于满足条件的自回归模型的输出:Z≤r Z > r.

听起来有点抽象,对吧?难怪 TAR 模型是阈值转换模型的概括。这意味着在建立政权转换发生的条件模型时,你是最灵活的。我建议你读完整篇文章后再读一遍这一部分——我保证到时会更清楚。现在,让我们来看一个更实际的例子。

如果我们用时间序列的前一个值代替 Z_t 值,TAR 模型就变成了一个自激门限自回归模型— SETAR(k,p1,…,pn),其中k是模型中的状态数,【T10]p 是每个自回归分量的连续阶数。两种状态的 SETAR(2,p1,p2)模型可以描述为:

两种状态下的一般方程。

现在它看起来更贴近地面了,对吗?让我们用散点图来形象化它,这样你就有了直觉:

生成的 SETAR(2,1,1)的散点图,其上绘制了黄土线和标记阈值的垂直红线,由作者绘制。(由 tsDyn 生成)

在这种情况下,k = 2r = 0p1 = p2 = 1d = 1你可以清楚地看到状态转换发生的阈值。但是在实际的时间序列上看起来如何呢?

生成的 SETAR(2,1,1)及其累积和,由作者绘制。

正如你所看到的,仅仅从外观上很难说我们正在处理一个阈值时间序列。那我们能做什么?让我们解决一个没有生成的例子,这样你就可以重复整个过程。

建模程序

让我们开始编码吧,我会一路解释这个过程。我们将使用 Lynx 数据集,并将其分为训练集和测试集(我们将进行预测):

library("quantmod")
library("tsDyn")
library("stats")
library("nonlinearTseries")
library("datasets")
library("NTS")

data <- log10(datasets::lynx)

train <- data[1:80]
test <- data[81:114]

我记录了整个数据集,因此我们可以获得整个数据集的更好的统计属性。现在,让我们检查自相关和偏自相关:

{par(mfrow=c(2,1))
acf(train)
pacf(train)}

按作者

看起来这个系列有可能以 ARIMA 为模型——也将在路上尝试一下。然而,让我们来看看滞后图:

{par(mfrow=c(2,2))
  scatter.smooth(Lag(train, 1), train, span = 2/3, degree = 1,
                 family = c("symmetric", "gaussian"), evaluation = 50, 
  xlab = "t-1", ylab = "t")
  scatter.smooth(Lag(train, 2), train, span = 2/3, degree = 1,
                 family = c("symmetric", "gaussian"), evaluation = 50, 
  xlab = "t-2", ylab = "t")
  scatter.smooth(Lag(train, 3), train, span = 2/3, degree = 1,
                 family = c("symmetric", "gaussian"), evaluation = 50, 
  xlab = "t-3", ylab = "t")
  scatter.smooth(Lag(train, 4), train, span = 2/3, degree = 1,
                 family = c("symmetric", "gaussian"), evaluation = 50, 
  xlab = "t-4", ylab = "t")
}

黄土线打开时训练集的滞后散点图,作者

在第一个滞后中,这种关系似乎确实适合 ARIMA,但从第二个滞后上看,非线性关系是显而易见的。然而,有时事情就是这样发生的,要决定这种类型的非线性是否存在并不那么简单。在这种情况下,我们必须进行统计测试——这种方法是汉森和 Tsay 最推荐的方法。然而,为了做到这一点,最好首先建立我们或多或少在谈论的滞后次序。为此,我们将使用平均互信息,并将订单限制为其第一个本地最小值:

*mutualInformation(train)*

作者为训练集创建的 AMI

因此,嵌入维度被设置为*m=3*。当然,这只是一种方法,你可以用不同的方法。请注意,我们可以再次看到强烈的季节性。现在,我们已经建立了最大滞后,让我们执行统计测试。我们将使用似然比检验来检验阈值非线性。它的假设是:

H0:这个过程是一个 AR(p)

H1:这个过程是一个集合

这意味着我们想要拒绝关于过程是 AR(p)的零假设——但是记住过程应该是自相关的——否则,H0 可能没有多大意义。

*for (d in 1:3){
  for (p in 1:3){
    cat("p = ", p, " d = ", d, " P-value = ", thr.test(train, p=p, d=d), "\n")
  }
}*
*SETAR model is entertained 
Threshold nonlinearity test for (p,d):  1 1 
F-ratio and p-value:  0.5212731 0.59806 

SETAR model is entertained 
Threshold nonlinearity test for (p,d):  2 1 
F-ratio and p-value:  2.240426 0.1007763 

SETAR model is entertained 
Threshold nonlinearity test for (p,d):  3 1 
F-ratio and p-value:  1.978699 0.1207424 

SETAR model is entertained 
Threshold nonlinearity test for (p,d):  1 2 
F-ratio and p-value:  37.44167 1.606391e-09 

SETAR model is entertained 
Threshold nonlinearity test for (p,d):  2 2 
F-ratio and p-value:  8.234537 0.0002808383 

SETAR model is entertained 
Threshold nonlinearity test for (p,d):  3 2 
F-ratio and p-value:  7.063951 0.0003181314 

SETAR model is entertained 
Threshold nonlinearity test for (p,d):  1 3 
F-ratio and p-value:  30.72234 1.978433e-08 

SETAR model is entertained 
Threshold nonlinearity test for (p,d):  2 3 
F-ratio and p-value:  3.369506 0.02961576 

SETAR model is entertained 
Threshold nonlinearity test for (p,d):  3 3 
F-ratio and p-value:  3.842919 0.01135399* 

正如你所看到的,在alpha = 0.05 我们不能拒绝只有参数d = 1的零假设,但是如果你回头看看滞后曲线,你就会明白为什么会发生这种情况。

另一个可以进行的测试是汉森线性测试。它的假设是:

H0:时间序列遵循一些 AR 过程

H1:时间序列遵循某种特定的过程

然而,这一次,假设被指定得更好一点——我们可以测试 AR 与 SETAR(2)、AR 与 SETAR(3)甚至 SETAR(2)与 SETAR(3)!让我们测试我们的数据集:

*setarTest(train, m=3, nboot=400)
setarTest(train, m=3, nboot=400, test='2vs3')*
*Test of linearity against setar(2) and setar(3)

         Test   Pval
1vs2 25.98480 0.0175
1vs3 46.31897 0.0150

Test of setar(2) against  setar(3)

         Test   Pval
2vs3 15.20351 0.2425*

这个测试基于 bootstrap 分布,因此计算可能会变得有点慢——不要放弃,你的计算机没有死,它需要时间:)在第一种情况下,我们可以拒绝两个空值——时间序列遵循 SETAR(2)或 SETAR(3)。从第二个测试中,我们发现我们不能拒绝 SETAR(2)的空值,因此没有理由怀疑 SETAR(3)的存在。因此,SETAR(2,p1,p2)是要估计的模型。

到目前为止,我们已经估计了 mdk的值的可能范围,仍然需要的是阈值 r 。不幸的是,它的估计是最棘手的,几十年来一直是计量经济学家的一大难题。我不知道任何计算它的分析方法(如果你知道,请在评论中告诉我!),而是通常执行网格搜索。

背后的直觉有点类似于决策树中的递归二进制分裂——我们用增加的阈值连续地估计模型。幸运的是,我们不必从 0 开始编写代码,这个特性在 r 中是可用的。

对于给定的阈值,我们希望实现最小的可能信息标准值。尽管如此,这种方法总会给你一些输出!你要找的是一个清晰的最小值。这看起来不错:**

对 tsDyn 生成的数据集进行网格搜索

有一个明确最低一点点低于 2.6。图表越呈 V 形越好——但这并不意味着你总能得到漂亮的结果,因此解释和滞后图对你的推断至关重要。这就是好看的地方:

生成数据集的网格搜索

虽然这个也有一些局部最小值,但不像以前那么明显——让 SETAR 来取这个阈值,你就有过度拟合的风险。实际上,虽然它看起来从来没有这么好——你在寻找许多组合,因此会有许多像这样的线。让我们回到我们的例子:

*selectSETAR(train, m=3, thDelay=1:2)*
*Using maximum autoregressive order for low regime: mL = 3 
Using maximum autoregressive order for high regime: mH = 3 
Searching on 50 possible threshold values within regimes with sufficient ( 15% ) number of observations
Searching on  900  combinations of thresholds ( 50 ), thDelay ( 2 ), mL ( 3 ) and MM ( 3 ) 
Results of the grid search for 1 threshold
   thDelay mL mH       th pooled-AIC
1        2  3  3 2.940018  -26.88059
2        2  3  3 2.980912  -26.44335
3        2  3  2 2.940018  -24.66521
4        2  3  2 2.980912  -24.43568
5        2  3  3 2.894316  -24.20612
6        2  3  3 3.399847  -22.98202
7        2  3  2 2.894316  -22.89391
8        2  2  3 2.940018  -22.15513
9        2  3  2 3.399847  -21.34704
10       2  1  3 2.940018  -20.52942*

训练集的网格搜索

因此,首选系数为:

*thDelay mL mH       th pooled-AIC
2        3  3 2.940018  -26.88059*

太好了!是时候进行最终的模型估算了:

*model <- setar(train, m=3, thDelay = 2, th=2.940018)
summary(model)*
*Non linear autoregressive model

SETAR model ( 2 regimes)
Coefficients:
Low regime:
   const.L     phiL.1     phiL.2     phiL.3 
 0.8765919  0.9752136  0.0209953 -0.2520500 

High regime:
   const.H     phiH.1     phiH.2     phiH.3 
 0.3115240  1.6467881 -1.3961317  0.5914694 

Threshold:
-Variable: Z(t) = + (0) X(t)+ (0)X(t-1)+ (1)X(t-2)
-Value: 2.94 (fixed)
Proportion of points in low regime: 55.84%   High regime: 44.16% 

Residuals:
       Min         1Q     Median         3Q        Max 
-0.5291117 -0.1243479 -0.0062972  0.1211793  0.4866163 

Fit:
residuals variance = 0.03438,  AIC = -254, MAPE = 5.724%

Coefficient(s):

         Estimate  Std. Error  t value  Pr(>|t|)    
const.L  0.876592    0.227234   3.8577 0.0002469 ***
phiL.1   0.975214    0.142437   6.8466 2.117e-09 ***
phiL.2   0.020995    0.196830   0.1067 0.9153498    
phiL.3  -0.252050    0.121473  -2.0749 0.0415656 *  
const.H  0.311524    0.685169   0.4547 0.6507163    
phiH.1   1.646788    0.172511   9.5460 2.027e-14 ***
phiH.2  -1.396132    0.277983  -5.0224 3.576e-06 ***
phiH.3   0.591469    0.272729   2.1687 0.0334088 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Threshold
Variable: Z(t) = + (0) X(t) + (0) X(t-1)+ (1) X(t-2)

Value: 2.94 (fixed)*

SETAR 模型已安装。现在,由于我们正在进行预测,让我们将其与 ARIMA 模型(通过 auto-arima 拟合)进行比较:

*ARIMA(4,0,1) with non-zero mean 

Coefficients:
         ar1     ar2      ar3      ar4     ma1    mean
      0.3636  0.4636  -0.4436  -0.2812  0.9334  2.8461
s.e.  0.1147  0.1290   0.1197   0.1081  0.0596  0.0515

sigma^2 = 0.0484:  log likelihood = 8.97
AIC=-3.93   AICc=-2.38   BIC=12.74

Training set error measures:
                        ME      RMSE       MAE        MPE     MAPE      MASE
Training set -0.0002735047 0.2115859 0.1732282 -0.6736612 6.513606 0.5642003
                     ACF1
Training set -0.002296863*

SETAR 似乎更适合训练。现在让我们比较测试集的 MSE 和 RMSE 的结果:

作者对塞塔和 ARIMA 的样本外预测

*SETAR MSE: 0.04988592
SETAR RMSE: 0.2233516

ARIMA MSE: 0.06146426
ARIMA RMSE: 0.2479199*

如您所见,SETAR 能够为训练集和测试集提供更好的结果。

最终注释

  1. TAR 的平稳性——这是一个非常复杂的话题,我强烈建议您从科学资源中寻找相关信息。然而,你可以应用一个不完整的规则:如果在任何一个机制中有一个单位根,那么整个过程是非平稳的
  2. 第一个生成的模型是平稳的,但在某些条件下,TAR 也可以模拟非平稳的时间序列。当它的状态都是稳定的时候,这样做是安全的。在这种情况下,你很可能会处理结构性变化。
  3. 制度的数量——理论上,制度的数量是不受限制的,但是根据我的经验,我可以告诉你,如果制度的数量超过 2,通常最好使用机器学习。
  4. SETAR 模型经常与 TAR 混淆——如果您在统计包中看到一个实际上是 SETAR 的 TAR 模型,请不要惊讶。每个星都是星,但不是每个星都是星。
  5. 为了适应模型,我使用了 AIC 和 pooled-AIC(SETAR)。如果您的案例需要不同的衡量标准,您可以轻松地更改信息标准。

摘要

阈值自回归模型曾经是过去最流行的非线性模型,但今天主要被机器学习算法取代。尽管如此,多年来它们已经被证明是有用的,而且因为你总是为任务选择工具,我希望你会发现它有用。

当然,SETAR 是一个可以扩展的基本模型。如果你对获得更好的结果感兴趣,请确保关注我的个人资料

你也可以在 LinkedIn 上找到我。

链接到数据(GNU)。

* *

用 PyThresh 设定异常检测分数的阈值

原文:https://towardsdatascience.com/thresholding-outlier-detection-scores-with-pythresh-f26299d14fa

附身摄影Unsplash 上拍照

异常值检测中取代污染水平必要性的方法

现实生活往往是混乱的,不可预测的。它似乎喜欢把隐喻的“扳手”扔进工作中,使数据通常显得令人困惑和随机。记录或提取的大多数数据通常需要在应用建模等进一步方法之前进行某种形式的清理。然而,通常很难或几乎不可能从视觉上区分哪些数据是真实的,哪些是噪音,哪些是异常。有时,异常甚至可能是必要的,这使得区分使用什么数据的行为更加复杂。这就是离群点检测技术的用武之地。

异常值检测方法可以有多种形式。但是他们检测异常值能力的关键通常是通过一组统计条件。有些方法很严格,有些方法很简单,但所有这些方法对于数据科学家在寻找与众不同的数据时都很重要。

PyOD 是众多 python 库中的一个,它包含了用于离群点检测的有用方法集合。它使用简单,比大多数其他库有更多的异常检测方法。因此,它是大多数数据科学家的最爱。然而,当试图使用大多数方法来发现异常值时,存在一个讨厌但必要的参数…污染水平。大多数方法在应用于数据集时会返回异常值置信度得分。这个分数本身是有用的,但是就像回归对于分类一样,它缺少标签。因此,需要一个污染水平来设置边界,通过设定置信分值的阈值来区分内点和外点。

PyOD 和许多其他库中,通常在异常值检测之前设置污染水平。然而,这个输入参数提出了一个问题:在测试异常值之前,如何知道数据集的污染程度?这是一个很好的问题!这个问题的答案通常意味着在异常值检测之前必须进行某种形式的统计测试,以获得污染水平。流行的方法包括使用 z 得分或四分位数区域。虽然这些都是正确污染水平的一个很好的近似值,但它们也有自己的缺点。更好的方法是对离群值检测分数本身应用统计测试,以便从离群值中阈值化内联者。

下面的例子将实现py thresh库…这是一个用于阈值离群点检测分数的库,我参与并正在积极开发。PyThresh由一组统计方法组成,这些方法试图设定异常值检测分数的阈值,而无需在拟合数据之前设置污染水平。这些统计方法从经典的阈值方法如 k-均值聚类和概率距离,到涉及拓扑和图论的更模糊的方法。总而言之,当涉及到异常值检测时,他们试图将污染水平的猜测(尽管他们可能受过教育)排除在等式之外。**

让我们看看如何在无监督的异常值检测分数上实现阈值处理。对于下面的示例,将使用来自 异常值检测数据集( 赔率 )心血管开源数据集。这个数据集是由石溪大学免费提供的,代表了真实世界的数据。

心脏 ( 心脏分娩图)数据集[2][3]包含由产科专家分类的心脏分娩图上的胎儿心率和子宫收缩特征的测量值。测量结果分为正常(内值)或病理性(异常值)。

首先,让我们加载 cardio 数据集,并标准化将由异常值检测方法评分的变量。

如果我们快速看一下数据,我们可以看到我们将有 21 个解释变量,每个变量有 1831 个唯一的条目。在这些条目中,1655 个(~90%)属于响应变量中的内点,176 个(~10%)属于外点。

为了正确识别这两个类别,选择正确的异常值检测和异常值阈值方法是很重要的。对于这个数据集,由于探索变量的数量,选择了主成分分析 ( PCA )无监督离群点检测方法。这种方法通过构造由特征向量生成的子空间来降低数据的维数,所述特征向量表示仍然能够解释数据的最高方差。离群值在这种维数减少过程中会变得更加明显,离群值分数是样本在所有特征向量上的投影距离的总和。对于这个数据集,我们将组件的数量从 21 个减少到 5 个。

异常值和阈值方法之间的协同作用通常提供更好的结果。这是由于离群值检测方法生成的分数随后被阈值方法处理的方式。这两种方法表现得越相似,出现不合理阈值的可能性就越小。然而,情况并非总是如此,选择正确的异常值检测和阈值方法可能需要在应用前后进行稳健的统计测试。

对于该数据集以及异常值检测方法,一个良好的对应阈值方法将是从正常 ( DSN )阈值的距离偏移。该阈值的工作方式是将异常值的概率分布与正态分布进行比较,并测量两者之间的差异。使用统计距离时,选择将用于测量的度量非常重要。 Bhattacharyya 距离是两个概率分布之间相似性的度量,并返回它们之间存在的重叠量。从技术上来说,它不是一个指标,但是它将用于设置数据集的阈值。Bhattacharyya 距离被定义为,

其中 pq 表示同一域上的两个概率分布 X ,连续概率分布的 Bhattacharyya 系数( BC )可以表示为:

最终设置异常值检测分数的阈值,使得任何大于 1 减去 Bhattacharyya 距离的分数都被标记为异常值。

现在有了更好的理解,我们可以将这些方法应用于数据集:

从 thresholder 返回的标签由一个二进制数组组成,其中内点用 0 表示,外点用 1 表示。在揭示这些方法的最终表现之前,让我们先来看看真实标签和预测标签的对比图。我们将再次使用 PCA ,但是现在通过减少维度来可视化 2D 的数据。当处理没有响应变量的真实世界数据时,这一步以及其他步骤是必不可少的,因为它提供了阈值的可视化表示。注意, PCA 是一个正交线性变换,因此具有非线性关系的异常值在视觉上可能不总是表现为明显的异常值。此外,将数据减少到 2 维也可以去除区分内部值和外部值所需的维度。然而,即使有这些缺点 PCA 可视化是一个强大的确认测试工具。

从图中我们可以看出, DSN 阈值和 PCA 异常值检测器分数能够非常准确地将异常值与内部值分开!这个例子的准确度是 99%,只有两个异常值被归类为内部值,没有内部值被归类为外部值。但是,根据数据集、应用的异常值检测器和阈值,预测精度会有所不同。尽管污染水平已被移除,以采用更具统计性的方法来确定阈值异常值,但最终,如果预测结果正确,则由数据科学家做出最终决定。

最后,异常值检测分数的阈值化并不是一门新的科学,并且已经有了许多成熟的实现。这些统计和数学方法增加了数据科学家的工具包,并有助于在信息和数据的奇妙世界中导航。

[1] Shebuti Rayana (2016)。ODDS 库[http://ODDS . cs . stony brook . edu]。纽约州石溪市:石溪大学计算机科学系。

[2] C. C. Aggarwal 和 S. Sathe,“异常值系综的理论基础和算法。《美国计算机学会 SIGKDD 探索通讯》,第 17 卷,第 1 期,第 24–47 页,2015 年。

[3] Saket Sathe 和 Charu C. Aggarwal。矿脉:局部密度符合光谱异常值检测。2016 年 SIAM 数据挖掘大会。

在这个问题上投入更多的计算

原文:https://towardsdatascience.com/throwing-more-compute-at-the-problem-1ceec0cb178a

奥利维尔·科莱在 Unsplash 上拍摄的照片

为什么这不是一个长期或短期的好策略

背景

是的,如果可能的话,这是查询编写人员在面对他们编写了一个糟糕的查询这一事实时通常采取的第一种方法。有时,他们有能力获得更多的计算来解决问题。大多数时候,不是的。在过去的十年里,我已经为多个产品和公司设计和扩展了数据库和数据仓库,我已经非常详细地理解了这个问题。在这篇文章中,我将分享我的观察,并提出一些解决这个问题的好策略。

在我们深入研究解决方案之前,我想从我自己的工作中给你一些例子,你可能会很容易联系到。这会帮助你更好地理解这个问题。考虑以下场景:

😕MySQL 混合使用本地和第三方复制器,具有复杂的复制拓扑。数据库托管在 EC2 实例上(这不是最近的;RDS 当时还不流行)。对于您所拥有的负载,这些实例是过度调配的。尽管如此,当有人查询终端从属数据库实例时,他们有时会由于负载峰值而停止复制。由于各种各样的锁,它们还会阻止其他想要查询数据库的用户。这直接影响了业务。

😞你刚刚加入了一个团队。该团队已经建立了一个红移“数据仓库”。他们实际上从关系数据库、第三方集成 API 和应用程序流中转储所有数据。将数据转储到 Redshift 中的过程非常有效,但是当分析师在这些数据上编写查询,连接所有数据源时,这一过程似乎不起作用。为什么?嗯,将所有数据转储到一个允许数据仓库的平台上并不会自动使转储成为一个数据仓库。一半的表没有正确的分布和排序键。他们中的一些有巨大的倾斜。了解为了什么目的使用什么工具也是非常重要的。

😭你有很多数据。其中大部分来自结构化来源。您希望通过 Spark 利用并行处理。你给你的团队一个 Spark EMR 集群。集群被设置为自动扩展,但这是有上限的。您的数据在从中提取数据的对象存储中被正确分区,但是仍然有一点倾斜。您使用 Python 和 SQL 的组合来到达您想要的地方,但是您注意到您在执行查询上比在小得多的关系数据库上花费更多的时间。这怎么可能呢?

让我们一个接一个地看看这些例子。

识别问题

乍一看,基础架构似乎配置不足,但仔细观察,您可以清楚地从这些示例中发现几个问题:

  • 对于第一个例子,有一个查询优化问题需要尽快解决。
  • 在第二个例子中,有一个术语“数据仓库”的误用和对查询性能成功的错误期望。
  • 在第三个例子中,还有一个查询优化问题需要解决。

这只是三个例子。我相信你们中的许多人已经看到了更多。

一些问题和建议

通过询问以下问题,您可以做一些简单的事情来解决这个问题:

  • 查询数量/强度的激增是否导致了该问题?如果是,并且您的系统大部分时间都没有得到充分利用,那么最好转移到无服务器基础设施。
  • 你真的需要数据仓库吗?如果是的话,如果您构建一个而不是将红移垃圾站称为数据仓库不是更好吗?那是不诚实的工程。
  • 通过查看执行计划来分析查询有帮助吗?是的,可以,而且确实如此。不管您使用什么样的数据库技术,您都可以选择查看查询优化器,看看数据库是如何执行查询的;这将告诉你什么需要修理。

上投多算

对上述问题投入更多的计算不会有多大帮助。有时候会,但是不会值这个钱。如果您的查询很糟糕,或者您使用了错误的数据库来解决问题,数据库系统甚至不会记录计算(资源)的增加。它们会吃掉任何它们遇到的东西。

你可能会问,什么时候投入更多计算是好的?答案并不简单,但也不复杂。您需要同时考虑几个因素,比如数据库配置、计算和内存利用率、数据量、并发用户、数据访问模式(尤其是读取模式)、索引(和/或分区)等等。在某种程度上,即使在短期内,投入更多的计算可能是最糟糕的解决方案,因为它也可能无法解决糟糕的查询问题。

利用可观察性了解更多信息

市场上的许多工具可以让你了解这些事情。一个例子是 NewRelic 和 Percona 工具包的组合。据我所知,这将是应用程序可观察性和数据库性能管理工具的结合,它将为您提供数据库发生情况的完整视图。如果您将数据库托管在 AWS 这样的云平台上,那么您可以使用 RDS Performance Insights 这样的工具来查看数据库。这就是为什么使用云数据库进行扩展更容易一些,因为它们从一开始就打包了一些支持工具。

结论

一旦您对数据库性能有了更全面的了解,您就能更好地判断是否需要为数据库提供更多的功能!

如果你觉得我的文章有用,请订阅并查看我的文章🌲 Linktree 。你也可以考虑用我的推荐链接购买一个中级会员来支持我。

https://kovidrathee.medium.com/membership

与汉密尔顿一起整理生产熊猫

原文:https://towardsdatascience.com/tidy-production-pandas-with-hamilton-3b759a2bf562

与汉密尔顿一起编写生产级熊猫代码。

你的熊猫与汉密尔顿代码。图片来自 Pixabay。

&熊猫 ”这两个词通常不会被联系在一起,更不用说与单词“生产”联系在一起了。在这篇文章中,我会说如果你在生产中使用 Pandas,你应该使用开源微框架 Hamilton ,因为它可以让你在默认情况下编写整洁的生产级代码。

你可能会想?这篇文章是关于熊猫的吗?是的,从整洁的代码的精神来看,但从如何实现的角度来看却不是。

此外,在我们开始之前,先说明一下我们的术语:

****生产:我们所说的生产是指为了使业务流程正常运行,需要运行这段代码。例如,为机器学习模型创建特征,或者将数据转换为仪表板工具。

整洁:整洁意味着代码是可读的、可维护的和可测试的。我们过分强调了你的代码长时间存活的能力;您的产品代码通常比您预期的寿命更长,所以让我们让它更容易维护。另一种思考方式是,我们希望您的熊猫代码能够方便地促进软件工程最佳实践。

熊猫生产问题

关于熊猫代码是否应该在产品中运行,业界有很多不同意见。虽然这对于快速的原型和研究来说显然是很棒的,但是熊猫繁重的代码库经常会被自己绊倒;软件工程最佳实践很难遵循。

这下一节应该是所有的头点头;在生产中使用熊猫时感觉到的常见油漆点。

集成测试和单元测试是一个挑战

熊猫代码通常被写成线性 python 脚本。这很可能是因为它最初是从一个 Jupyterhub 笔记本的不同单元中的代码开始的,这些单元本身是线性执行的。这种方法使得长时间测试变得困难。当然,当你开发脚本时,你也在“测试”它。但是一旦投入生产,时间可能会流逝,数据的背景可能会改变。例如,如果您需要调整正在运行的生产熊猫代码,您如何确信您所做的更改不会产生负面影响?单元测试很可能不存在,或者测试覆盖率参差不齐;编写内联 Pandas 操作很容易做到,但很难进行编程测试。而集成测试通常涉及到运行整个脚本。如果它进行大量的计算,这意味着测试所有东西的迭代周期很慢,或者可能完全跳过测试。

文档不存在

文档对于协作和代码维护至关重要。如果您习惯于编写内联创建一堆列的 Pandas 代码(因为这很容易做到),那么您总是会牺牲文档。文档应该容易呈现,并与代码同步。一旦你开始把文档放在代码之外,它就很容易过时…

代码很难重用

通常会看到一个 python 文件包含所有的熊猫代码:提取数据的逻辑、执行转换的逻辑和保存输出的逻辑。这意味着这个脚本中的转换函数不容易访问或重用。有些人反驳说“我就重构”,但这种情况会发生几次呢?人们最终会剪切和粘贴代码,或者一遍又一遍地重新实现相同的逻辑。

除了你,没人懂你的熊猫密码

作为一名前数据科学家,我切身体会到继承他人代码的可怕之处。熊猫是一个强大的工具,但每个人使用它的方式不同。考虑到上面提到的测试、文档和可重用性,至少可以说,拥有别人的 Pandas 代码是令人生畏的。

哈密尔顿

Hamilton 就是为了解决上面引出的问题而建造的——把一个杂乱的熊猫代码库变成一个整洁的。不,与你可能知道和喜爱的 R tidyverse 不完全相同,但在精神上是相同的…

什么是汉密尔顿?

Hamilton 是用于指定数据流的声明性范例。这只是学术上的说法:

  1. 通过在函数定义中直接编码,您可以编写 python 函数来声明它们输出什么以及它们依赖什么。
  2. 您编写这些 python 函数来指定数据和计算应该如何流动,即数据流(也称为管道/工作流)。

在代码中,这意味着:

df['age_mean'] = df['age'].mean()
df['age_zero_mean'] = df['age'] - df['age_mean']

你写作

# a_function_module.py
def age_mean(age: pd.Series) -> float:
    *"""Average of age"""* return age.mean()

def age_zero_mean(age: pd.Series**,** age_mean: float) -> pd.Series:
    *"""Zero mean of age"""* return age - age_mean

然后,您必须编写一些“驱动程序”代码来实际执行计算。“驱动程序”代码的职责是实例化什么函数可以并且应该被计算,以及如何计算。

import pandas as pd
from hamilton import driver
import a_function_module # where your transforms liveconfig_and_inputs = {'age': pd.Series([...])}
dr = driver.Driver(config_and_inputs**,** a_function_module)# here we're constructing a data frame with only two columns
df = dr.execute(['age', 'age_zero_mean'])

在这里,我们将跳过对汉密尔顿的详细介绍,而是链接到以前的介绍:

否则你只需要pip install sf-hamilton就可以开始了。

为什么使用 Hamilton 会产生整洁的熊猫代码?

以下是四个主要原因:

  1. 可测试代码,总是
  2. 文档友好代码,总是
  3. 可重用逻辑,总是
  4. 运行时数据质量检查,总是

让我们用下面的函数来讨论这几点:

示例哈密尔顿函数

可测试的代码,总是

Hamilton 迫使您编写与指定数据如何到达函数无关的函数。这意味着总是为单元测试提供输入是很简单的。在上面的函数中,提供height_zero_meanheight_std_dev只是为每一个拿出一个有代表性的熊猫系列来测试这个函数;在定义函数时,我们没有指定如何提供输入。

类似地,人们可以很容易地用 Hamilton 端到端地测试上述函数。你只需要将计算height_zero_mean_unit_variance指定给“驱动”代码,它就会执行产生height_zero_mean_unit_variance.所需的功能,这样即使是集成测试周期也会相对较快。您不需要运行整个脚本并计算一切来测试单个更改。即:

df = dr.execute(['height_zero_mean_unit_variance'])

文档友好的代码,总是这样。

Hamilton 有四个有助于文档的功能:

  1. ****功能。通过使用函数作为抽象,人们可以自然地通过函数的 docstring 插入文档。然后,这可以与工具连接,如 sphinx 来更广泛地展示这些。
  2. 命名**。汉密尔顿强迫命名成为你脑海中的焦点。由于驱动程序.execute() 函数请求的列名与您(或同事)编写的函数相对应,描述性的、简洁的名称逐渐成为规范。此外,从函数名到函数参数,代码读起来自然而直观;使用 Hamilton 时,很难命名任何重要的东西[*foobar*](https://en.wikipedia.org/wiki/Foobar)
  3. ****可视化。Hamilton 可以生成一个 graphviz 文件图像,该图像可以生成函数如何联系在一起的图形表示。这是帮助人们了解全局的重要工具。例如,请参见下面的可视化示例。
  4. ****标签。Hamilton 使人们能够通过注释函数来分配标签(键值对)。如上例所示,@tag(owner='Data-Science', pii='False')提供了额外的元数据来帮助代码读者理解,例如,谁拥有代码,它是否包含个人识别信息。

汉密尔顿可以生成的示例渲染。经https://outer bounds . com/blog/developing-scalable-feature-engineering-DAGs许可拍摄。

可重用逻辑,永远如此。

为了有用,上面的函数需要在 python 模块中管理。因为该模块没有耦合到“驱动程序”代码,所以很容易在各种上下文中引用该函数:

  1. 多个驱动程序可以使用同一个功能。这些驱动器可以不同地构造 DAG,例如通过从不同的位置加载数据。所以从第一天起就有代码重用。
  2. 如果你有一个 Python REPL ,导入函数并运行它就很容易了。
  3. 您可以发布该函数的模块并对其进行版本化,以实现重用和可重用性。

此外,由于 Hamilton 强制所有核心逻辑位于与“驱动程序代码”分离的功能中,因此 Hamilton 很容易提供开箱即用的方法来扩展计算。像 RayDask 这样的框架很容易打开和集成。你所需要做的就是在你的“驱动程序”代码中修改几行代码。更多信息参见汉密尔顿的 & 达斯克例子。

运行时数据质量检查,总是。

单元测试是有价值的,但是它不能代替在生产中验证假设。而不是使用单独的任务(甚至单独的函数)来检查数据。Hamilton 支持使用简单的装饰器在运行时对函数的输出进行验证:

@check_output(data_type=np.float64, range=(-5.0, 5.0), allow_nans=False)

这使得不了解代码上下文的人很容易理解输出的一些基本属性。因为装饰器与转换函数定义相邻,所以维护起来要简单得多。没有单独的系统需要更新—您可以在一个拉取请求中完成所有工作!

当函数被执行并且验证失败时,当前的选项是记录一个警告或者抛出一个异常。这是一种非常快速简单的方法,可以确保生产中运行的内容符合您的期望。

那些更喜欢潘德拉的力量的人,欢呼吧!Hamilton 中的数据验证是完全集成的,您可以将一个 Pandera 模式传递给 decorator

额外好处

除了使你的熊猫代码库整洁之外,Hamilton 还在你的熊猫开发工作流程的这些更宏观的方面提供帮助。

更快的迭代周期。

一旦 Hamilton 启动并运行,添加、更改和调整代码的灵活性就很简单了。您可以:

  • 测试驱动的方式开发
  • 通过仅请求计算所需的内容,轻松测试您的更改
  • 通过跟踪计算数据谱系有条不紊地进行调试。您从函数开始,调试逻辑,如果问题出在其他地方,您可以通过函数的输入迭代递归。
  • 利用您预先定义的功能,非常容易地为多个上下文创建驱动程序。

更快的入职。

由于编写了带有各种文档挂钩的函数,增加新员工变得简单多了。探索代码库可以用图形化的方式来完成,运行和测试代码也很容易解释。

花在代码维护和保养上的时间更少

通过设计,Hamilton 使得遵循软件工程最佳实践变得容易。这意味着维护、继承甚至移交代码是非常容易管理的。这也意味着很容易使您的所有转换逻辑看起来统一和美观(例如参见下一节中的链接),并保持这种方式。

现实的例子

我吹嘘了它的好处,但是代码实际上是什么样子的呢?以下是一些例子:

>将 Hamilton 与 Metaflow 结合:

>汉密尔顿知识库中的一个示例:

  • 数据质量(基于上述示例,但包括@check_output注释)。有关 Pandera 的示例,请参见本示例

最后

代码的寿命比你通常预期的要长得多。确保它易于编写、维护,并能被您之后的人访问,这是使熊猫在生产环境中工作的一个关键因素。汉密尔顿熊猫帮你做到这一切。将汉密尔顿与 Pandas 一起使用会产生整洁的产品代码,无论是谁编写的,都可以在计算上(例如 RayDask )和组织上进行维护和扩展。

我们希望您能够:

  • 💪如果你还没试过,试试汉密尔顿 T2。刚刚pip install sf-hamilton开始。
  • github 上的⭐️美国,
  • 📝如果你发现了什么,给我们留个问题,
  • 📣加入我们的 slack 社区 —我们非常乐意帮助回答您可能有的问题或帮助您起步。

您可能感兴趣的其他汉密尔顿帖子:

冲泡和饮用浓缩咖啡之间的时间

原文:https://towardsdatascience.com/time-between-brewing-and-drinking-espresso-ffbeea7bcf95

咖啡数据科学

了解饮料温度的简单测试

我曾经听说过一个咖啡师,他坚持认为一杯浓缩咖啡如果不在冲泡后一分钟内喝掉就是死的。我不相信这种推理,两年前,我开始注意浓缩咖啡的时间和温度,因为这关系到我如何体验拍摄。

我用两张照片做了一个快速测试,来探究这种差异。我之前做了一些测试,我确定 4 到 6 分钟是正确的时间,或者是饮料温度达到 47 摄氏度的时候。

所有图片由作者提供

每个杯子都不一样。对于我的海盗杯,这发生在拍摄后 4 分钟左右。对于 Kruve EQ cup,大约在拍摄后 6 分钟。

设备/技术

意式咖啡机:金快线(不是 DE,但画面很酷)

咖啡研磨机:韩国

咖啡:家常烘焙咖啡,中杯(第一口+ 1 分钟)

镜头准备:断奏夯实

预灌注:长,约 25 秒

输液:压力脉动

过滤篮 : 20g VST

其他设备: Atago TDS 计Acaia Pyxis 秤

绩效指标

我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是记分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和回味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

用折射仪测量总溶解固体量(TDS),这个数字结合弹丸的输出重量和咖啡的输入重量用来确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

两杯,四种口味

我喝了两杯,第一杯是基线,5 分钟后喝,第二杯在几分钟内尝了几次。挑战在于品尝一杯酒会影响舌头,很难隔离变量。这将是一个更好的测试,通过多次注射和喝咖啡来完成,但这里的意图是建议在不同的休息时间尝试注射。

这两个镜头有相似的 TDS 和 EY。他们的品味完全不同。

****

随着时间的推移,味道变好了,我没有超过 5 分钟。这种味道没有任何特别之处,比其他味道特征变化更大。很难说我是如何感知味道的,但舌头是一个传感器,它有正常工作的条件。

这个简短测试的主要目的是倡导个人实验。很容易指望有经验的人告诉你如何享受浓咖啡或咖啡,但你可以让自己的感觉成为你的向导。

如果你提前花些时间去尝试,你将为一生享受更好的咖啡做好准备。

如果你愿意,可以在 TwitterYouTubeInstagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。也可以在 LinkedIn 上找到我。也可以在关注我,在订阅

我的进一步阅读:

我未来的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

时间序列中的时间和季节性特征

原文:https://towardsdatascience.com/time-seasonality-features-in-time-series-7e8236f7b04a

在数据世界里争吵

以数据为中心,并在模型校准过程中包括季节性选项

来自 Unsplash 的杰克·亨特制作的布拉格天文钟

T ime 和季节性特征 s 在时间序列分析中经常被假设,忽略了它们在模型校准中作为输入的重要作用。最近,周期性季节性变量在数据科学中变得非常流行。然而,寻找季节性效应的最佳形式应该是建模过程的一部分,而不是简单地想当然。

通过三角正弦和余弦变换的周期性季节性特征长期用于生物医学和生态学研究。他们背后的直觉是时间是循环的。一天的 24 小时或一年的 12 个月确实形成了一个无限的循环。小时的三角变换图如下所示。它描绘了一个看似直观的令人愉快的循环模式。

这种直觉往往是不正确的。首先,重要的是考虑目标变量是否随时间以起伏的正弦型波移动。另一个相关要求是,当在机器学习模型中使用这些循环变量时,目标变量必须是固定的。非平稳时间序列需要在正弦和余弦变量之上估计一个趋势变量,因此增加了使用这种时间/季节性处理的复杂性。

自然世界之外的现象或事件如电力消耗或商店访问或媒体流活动可能会明显偏离正弦模式前提,即使它们可能是静止的。在时间序列分析中,这就是周期性季节性模式假设开始失效的地方。从我的经验来看,当然我的重点是在非自然现象上,周期性季节性特征通常不是最好的选择,因为时间本身通常不是所研究现象的预测器。

通过正弦和余弦变量的组合捕捉季节性也可能产生另一个问题,因为每个季节性特征(如小时或月)现在同时在两个变量中捕捉。基于树的算法一次根据一个特征分割样本数据。因此,一个特征同时编码在两个变量中可能对这种模型没有帮助,或者至少这是人们普遍认为的。

时间变量的用途

让我们回到基本原则。为什么我们要加入时间或季节性特征?是因为时间还是季节本身就是目标的预测因素?或者是因为时间或季节表明一些未观察到的或潜在的变量解释了目标?当试图模拟非自然现象时,感兴趣的几乎总是潜在影响*。*

例如,没有人会认为电力需求在一天中仅仅因为小时而上下波动。这是因为一天中的某个时刻捕捉到了社会经济行为的某些重要方面。比方说,在午夜和凌晨 5 点之间,任何城市的社会和商业活动都会大大减少,这就是导致电力需求在这些时间达到最低点的原因。因此,不是时间本身解释了用电量,而是时间对人类行为意味着什么。

再举一个例子,在大城市,交通高峰往往出现在上午 8:00-9:30 和下午 4:30-6:00,但这是因为这些时间神奇地诱导了更多的驾驶吗?当早上 8 点钟声敲响的时候,人们会下意识地被提醒上车开车吗?当然不是!交通高峰期在那些时间,因为这是典型的现代人类社会的工作时间表。现代工作时间表是原因,而不是工作时间本身。

因此,当涉及到模拟非自然季节性时,关键问题是:潜在的驱动因素是周期性的吗?还是更加飘忽不定或者零星?问题是潜在的行为没有被观察到,否则我们应该直接建模。由于未被观察到,我们通常对如何最好地建模没有很高的信念,尽管广泛的领域知识可能是有帮助的。这意味着时间和季节性变量的最优形式受到不确定性的影响,并且是我们可以校准模型性能的另一种方式。

有三种常见的方法来模拟时间和季节性效应。我已经讨论过流行的循环正弦和余弦方法。下面是用于生成此类特性的一段 Python-NumPy 代码:

还有传统的虚拟变量方法,我们为每个时间或季节创建一个虚拟变量,或者用现在的行话来说就是“一次性编码”。最后,我们也可以在数字变量中捕捉季节性(例如,在单个变量中从 1 到 12 的月份)。从现有数据帧的日期时间指数中生成数字季节性特征非常简单:

数字季节性特征将提供最少数量的季节性特征,因此在这方面将产生最节约的方法。三角季节性特征将总是两倍于数值变量的数量,因为每个季节性值同时被两个变量捕获。最后,虚拟季节性变量将生成迄今为止数量最大的季节性特征。

当我们使用这些方法中的每一种时,我们有效地做出了关于特定时间或季节如何影响目标变量的不同假设,同时考虑了不同的机器学习算法如何处理信息。没有一种方法是先验的建模时间或季节的最佳方式,除非我们在深厚的领域知识的指导下有非常高的信念。这通常取决于数据、手头的其他特征、算法。

数据和模型

在本文中,我查看了在小时和月使用周期正弦和余弦季节性特征与使用季节性虚拟变量数字变量比较性能。我还使用两个不同的时间序列数据集进行评估,但两个目标变量都表现出平稳性,没有任何转换,因此可以对不同的季节性工程处理进行公平的比较。

第一个数据集是空气污染数据集,其中目标变量是 2010 年 1 月至 2014 年 12 月期间北京市空气中每小时 2.5 微米颗粒物(“PM 2.5”)的浓度【1】。原始数据可以从这个 UCI 免费获得。**

[1]梁,邹,郭,李,张,黄,陈。《评估北京的 PM2.5 污染:严重性、天气影响、APEC 和冬季供暖》,英国皇家学会学报471(2015 年 10 月)。

第二个数据集来自对美国各城市用电量的研究。我使用 2015 年 7 月至 2019 年 12 月之间的小时用电量为千兆瓦(“GW”)的纽约市电力数据子集作为*前一时期的目标变量[2]。原始数据可从研究的 GitHub 资源库中获得。*****

[2] Z. Wang、T.Z. Hong、H. Li 和 M.A. Piette。“使用数据驱动模型预测城市规模的日用电量”,应用能源进展,第 2 卷(2021 年 5 月)

因此,我们有两种不同的现象——空气污染和用电。两个目标变量自然都是稳定的,通过增强的 Dickey-Fuller 测试得到证实。在数据工程之后,包括缺失数据插补,北京污染数据集产生 43,799 个观察值,而纽约电力数据集有 39,455 个

为了简洁起见,我将不讨论所涉及的数据工程,但是感兴趣的读者可以仔细阅读我的 GitHub 库中相关的 Jupyter Notebook 文件,链接在文章底部。北京 PM2.5 数据的小时图和月图如下,显示出明显的季节性影响。****

****

下面的每小时和每月纽约电力需求图表也显示了相当大的季节性影响。然而,正如我们所观察到的,两个数据集中的季节性模式都不像平滑的正弦波。

****

我没有包括任何季节性变量。从我的经验来看,人类活动的大部分日常季节性(一旦你控制了每小时的季节性)可以通过工作日-周末和工作日-假日的区别来解释。所以我在两种情况下都包括了一个周末假人。

当查看按月份分组的观察值的箱线图时,显而易见的是,纽约电力目标值以更平滑的方式分布,因为与北京污染数据相比,其数据点分布更少。两个标准化目标变量的箱线图显示如下,其中平均值为 0,标准差为 1 ,以便直接相互比较:****

****

我们马上注意到,北京的污染数据中除了方框中的“胡须”之外,还有更多的观察数据。因此,北京的数据比纽约电力公司的数据更不稳定,更不平滑,有更多的“异常”值。

****六个流行的机器学习模型被评估为练习的一部分:

  • 套索回归 n(线性)
  • 岭回归 n(线性)
  • ****随机森林(基于树)
  • ****极限渐变增强(基于树)
  • 支持向量机
  • ****多层感知器神经网络

这些模型的任务是根据各种时间/季节性特征来预测目标,并相应地进行评分。

季节性治疗

这将是一个多变量时间序列建模练习,目标是提前一个周期,因此还涉及到其他非季节性特征,包括两种情况下目标的滞后变量。为了长话短说,我将不讨论其他特性,但是感兴趣的读者可以研究我的 GitHub 库中的文件以获得完整的细节。

两个数据集的每一个都被给予不同的季节性处理,覆盖小时,导致在每种情况下三个数据集的集合:

  • 一个“循环特征”数据集,具有正弦和余弦小时月特征;
  • 带有小时和月虚拟变量的“虚拟特征”数据集;和
  • 带有小时和月数字变量的“数字特征”数据集,即小时在单个变量中呈现为 0 到 23,月在单个变量中呈现为 1 到 12。

所有其他非季节性变量在这些季节性特征的每个集合中都完全相同。然后我们总共有六个数据集,分别为北京和纽约数据集收集了三个不同的小时季节性特征。****

让我重复这一点,这样就不会有误解。在每种情况下(北京污染和纽约电力),“循环数据集”、“虚拟数据集”和“数值数据集”之间唯一的差异是季节性特征的形式。

对比评分程序

评估程序很简单,但由于数据集的数量而有些复杂。所有六个数据集都经过训练测试分割,按照时间顺序保留的最新的 20% 数据作为测试集。因此,在季节性处理的每个集合中,测试集具有相同的长度。在最小最大缩放之后,在每个训练集上运行随机搜索 CV ,为上面列出的六个机器学习算法中的每一个找到最佳参数设置。****

每个原始数据集的评估过程图

然后使用训练数据对最优模型进行三重交叉验证时间序列分割,并根据平均误差** (MAE)进行评分。根据 MAE 和均方根误差(RMSE)度量,测试集也最终被评分。换句话说,每个模型在每个季节性数据集上的表现被评分两次,第一次通过训练集交叉验证,最后在测试集上****

概括地说,采用以下评分程序:

  • 训练测试分割,然后对六个数据集的每一个进行最小最大缩放(分别针对北京和纽约数据集的三个不同的季节性特征);**
  • 然后对评估中六个模型的所有六个数据集**进行随机搜索;****
  • 训练集的时间序列片段三重交叉验证 与六个模型所有六个数据集的MAE 评分;和**
  • 六个模型的所有六个数据集的测试集的 MAE 和 RMSE 指标上的得分。

比较分数

我将把重点放在 MAE 分数上,尽量缩短文章的长度。来自纽约州电力数据集的发现似乎证实了一个假设,即虚拟季节性变量最适合线性模型(拉索&山脊)。线性模型对数字变量的表现最差,这也证实了另一个假设。这个结果在训练集和测试集中是一致的。

然而,基于树的模型 (RF & XGB)在具有周期性季节性特征的训练集交叉验证中取得了他们的最佳成绩,但最终在具有数字特征的测试集中表现最佳。该结果证明了基于树的算法可能不适用于循环正弦和余弦特征的假设。尽管如此,最终的测试集结果似乎证实了通常的前提,即基于树的变量在数字季节性特征中表现最佳。

SVM 在这种情况下表现相当差,尽管它的最佳得分是通过使用循环特征。在使用虚拟季节性变量的测试集中,MLP 在所有六个模型中获得了最高分,尽管它在训练集交叉验证中的得分没有那么令人印象深刻。顺便提一下,各种模型的不同季节性特征的 MAE 分数的显著差异也突出了前者在模型校准过程中的关键作用。

训练集平均绝对误差分数

测试集平均绝对误差分数

评估模型性能的一种图形方式是观察预测值与测试集中实际目标值的映射程度。如果预测 100%正确,那么我们应该在预测值与真实值的散点图中观察到一条 45 度线。下面的图表显示了岭回归模型的预测值与实际目标值的对比,很明显,利用虚拟季节性变量提高了模型的预测能力(中图)。与其他两种季节性处理相比,预测值更接近“完美模型”线。

这种影响在 MLP 模型的预测中更加明显。带有虚拟季节性变量的 MLP 模型无疑是三种季节性处理中表现最好的。

然而,来自北京空气污染数据集的结果在某些方面令人惊讶。在这种情况下,线性模型的最高分分散在各种季节性处理中,没有明确的赢家。另一方面,基于树的模型数字季节性变量 s 上得分最高,唯一的例外是在列车组交叉验证中具有循环特征的 XGB。****

在这种情况下, SVM 算法做得更好,事实上通过虚拟季节性变量在测试集中获得了最高 MAE 分数。 MLP 模型显示出对北京数据集中数字变量的明显偏好,而不像它对纽约数据集中虚拟变量的偏好,因此显示出缺乏一致性

训练集平均绝对误差分数

测试集平均绝对误差分数

我们之前注意到,北京 PM 2.5 的目标值充满了“异常值”,这表明获得准确的预测将更具挑战性。下面的北京数据集测试集中的XGB 预测值与真实值的散点图确实揭示了这一挑战。尽管如此,在这种情况下,我们还是可以通过数字季节性特征看出一些更好的表现,特别是在极端目标值下。例如,对于 PM 2.5 读数超过 400 的情况,数字特征的预测通常更接近“完美模型”线。

至于 MLP 模型,使用数字季节性特征同样会在目标值高于 400 时产生更好的预测性能。也就是说,在最极端的目标值 600 以上时,循环变量似乎确实具有性能优势,但在这些水平上的观察数量非常少。

我们还没有考虑在小时和月之间改变季节性特征的可能性,但那是以后的事了。如果要从这个练习中得出任何一个结论,那就是在分析自然世界之外的时间序列现象时,我们不应该假设任何时间/季节性处理总是最佳的

尽管如此,如果需要进行快速的初步分析,还是有一些经验法则的。基于树的模型往往表现良好,具有数字季节性特征同时,线性模型往往对虚拟季节性变量表现良好

结论

时间和季节性特征经常被选择,而没有理解它们在时间序列模型校准中的关键作用。在自然世界之外的现象中,时间很少是直接的因果因素,但通常是未观察到的潜在变量的代理,这些潜在变量在解释变量中没有得到明确控制。因此,季节性特征的最佳形式受到相当大的不确定性的影响。

本研究针对两个时间序列数据集中的小时和月的虚拟和数字季节性变量,评估了周期正弦和余弦季节性特征的性能。其中一个数据集是关于北京的空气污染,另一个是关于纽约的用电量。作为评估的一部分,六个流行的机器学习模型接受了测试,它们的预测在各种季节性处理中得分。**

基于树的模型被发现在周期性季节性特征方面表现良好,但它们的最佳测试集分数最终是通过使用数字季节性特征获得的。线性模型似乎对虚拟季节性特征表现更好,但并不一致。****

多层感知器神经网络在一个数据集中使用虚拟季节性变量,而在另一个数据集中使用数字变量,从而取得了最好的成绩。支持向量机算法确实显示出对周期性季节性特征的偏好,但同样不一致。****

该研究表明,对于任何特定的数据集,尤其是非自然现象,季节性特征的最佳形式是校准机器学习模型性能的另一种方式。因此,我们应该以数据为中心,而不是假设任何特定的时间/季节性特征选择对于每个机器学习算法都是最优的,除非有固体领域知识指示特定的选择。

(这个练习的完整 Python 代码和数据可以在我的GitHub资源库中找到。如果直接渲染 GitHub 笔记本文件有问题,使用 nbviewer 。)**

如果你在阅读这样的文章中看到了价值,你可以在这里订阅 Mediumhttps://at-tan.medium.com/membership来阅读我和无数其他作家的其他文章。谢谢你。

**** ****

时间序列分析导论 ARMA、ARIMA、SARIMA 模型的比较

原文:https://towardsdatascience.com/time-series-analysis-introduction-a-comparison-of-arma-arima-sarima-models-eea5cbf43c73

这些模型之间的差异,以及您应该如何使用它们

时间序列分析图(图片由作者

什么是时间序列?

时间序列是机器学习中的一种独特类型的问题,其中时间组件在模型预测中起着关键作用。由于观察依赖于相邻的观察,这违反了大多数传统机器学习模型所遵循的观察彼此独立的假设。时间序列分析的常见用例是预测未来数值,例如股票定价、收入、温度,这属于回归模型的范畴。然而,时间序列模型也可以应用于分类问题,例如,脑电波监测中的模式识别,或生产过程中的故障识别是时间序列分类器的常见应用。

在本文中,我们将主要关注三个时间序列模型——ARMA、ARIMA 和 SARIMA,用于预测数值的回归问题。时间序列回归不同于其他回归模型,因为它假设数据在一段时间内是相关的,并且前期的结果可用于预测后续期间的结果。

如何描述时间序列数据?

首先,我们可以使用sns.lineplot通过折线图可视化来描述时间序列数据。如下图所示,“发电量 [1]”时间序列数据的可视化描绘了一个具有一些重复模式的上升趋势。

df = pd.read_csv("../input/time-series-datasets/Electric_Production.csv")
sns.lineplot(data=df,x='DATE', y='IPG2211A2N')py

时间序列可视化(图片由作者提供)

为了更好地解释时间序列数据的特征,我们可以将其分解为三个部分:

  • 趋势–T(T):平均值长期向上或向下的变化。
  • 季节性–S(t):价值遵循可识别模式的周期性变化。
  • 残差–R(t):时间序列数据中不遵循任何模式的随机波动。

它们通常可以通过加法或乘法来组合:

  • 加法时间序列:O(t) = T(t) + S(t) + R(t)
  • 乘法时间序列:O(t) = T(t) * S(t) * R(t)

在 Python 中,我们通过seasonal_decompose,decomposition.plot()从时间序列数据中分解出三个部分,为我们提供趋势、季节性和残差的可视化分解。在这段代码中,我们将模型指定为加法模型,并将 period = 12 指定为季节性模式。

(要访问完整的代码片段,请看看 我的网站 )

from statsmodels.tsa.seasonal import seasonal_decompose
decomposition = seasonal_decompose(x=df['IPG2211A2N'], model='additive', period = 12) 
decomposition.plot()

平稳性

时间序列数据可以分为平稳数据和非平稳数据。平稳性是一个重要的属性,因为一些模型依赖于数据是平稳的假设。然而,时间序列数据往往具有非平稳性。因此,我们需要了解如何识别非平稳时间序列,以及如何通过各种技术(如差分)对其进行转换。

平稳数据被定义为不依赖于时间成分,具有以下特征:均值恒定、方差随时间恒定、自相关结构恒定(即自相关模式不随时间变化)无周期性或季节性成分。

识别平稳性的技术

最直接的方法是目视检查数据。例如,上面的时间序列可视化表明,时间序列呈上升趋势,其平均值随着时间的推移而增加,这表明数据是不稳定的。要量化它的平稳性,我们可以用以下两种方法。

首先,ADF(Augmented Dickey Fuller)****测试基于数据非平稳的零假设和数据平稳的替代假设来检验平稳性。如果 ADF 测试产生的 p 值小于 0.05,它提供了更强的证据来拒绝数据是非平稳的。

我们可以使用来自statsmodels.tsa.stattools模块的adfuller来执行 ADF 测试,并生成 ADF 值和 p 值。在本例中,p 值 0.29 大于 0.05,因此该数据集是不稳定的。

其次, ACF(自相关函数)总结了当前观测值与过去观测值之间的双向相关性。例如,当滞后=1 (x 轴)时,ACF 值(y 轴)大致为 0.85,这意味着所有观察值与其之前的观察值之间的平均相关性为 0.85。在后面的部分中,我们还将讨论使用 ACF 来确定移动平均参数。

下面的代码片段使用sm.graphics.tsa.plot_acf生成 ACF 图,显示了 40 个滞后。

import statsmodels.api as sm
sns.lineplot(x=df['DATE'], y=df['IPG2211A2N'], ax=subplot1)
sm.graphics.tsa.plot_acf(df['IPG2211A2N'], lags=40, ax=subplot2) 
fig.show()

对于非平稳数据,ACF 下降到 0 的速度相对较慢,因为非平稳数据仍然可能出现与之前观测值高度相关的情况,说明时间成分仍然起着重要作用。上图显示了原始时间序列数据的 ACF,它缓慢下降,因此很可能是非平稳的。

平稳性和差分

差分通过计算一个观测值与其后续观测值之间的差异来消除趋势和季节性,差分可以将一些非平稳数据转换为平稳数据。

  1. 移除趋势

我们使用shift(1)将原始时间序列数据(显示在左侧)向下移动一行(显示在右侧),并取差值以移除趋势成分。dropna是在减去 NaN 时去掉空行。

# remove trend component
diff = df['IPG2211A2N'] – df['IPG2211A2N'].shift(1)
diff = diff.dropna(inplace=False)

应用趋势差分后,我们可以绘制时间序列图以及 ACF 图。如下所示,趋势已从数据中移除,数据似乎具有恒定的平均值。下一步是解决季节性因素。

# ACF after trend differencing
fig = plt.figure(figsize=(20, 10))
subplot1 = fig.add_subplot(211)
subplot2 = fig.add_subplot(212)
sns.lineplot(x=df['DATE'], y=diff, ax=subplot1)
sm.graphics.tsa.plot_acf(diff, lags=40, ax=subplot2) 
fig.show()

趋势差异(作者图片)

2。去除季节性

从上面的 ACF 图中,我们可以看到,当滞后为 12、24、36 等时,观测值更相关,因此它可能遵循滞后 12 的季节模式。让我们应用 shift(12)来消除季节性,并使用 ADF 重新测试平稳性,ADF 的 p 值约为 2.31e-12。

# remove seasonal component
diff = df['IPG2211A2N'] – df['IPG2211A2N'].shift(1)
seasonal_diff = diff – diff.shift(12)
seasonal_diff = seasonal_diff.dropna(inplace=False)

去除季节模式后,下面的时间序列数据变得更加随机,ACF 值迅速下降到一个稳定的范围。

季节性差异(图片由作者提供)

模特——阿玛、ARIMA、萨里玛

在本节中,我们将介绍三种不同的时间序列预测模型——ARMA、ARIMA 和 SARIMA。一般来说,这些模型的功能可以总结如下:

  • ARMA:自回归+移动平均
  • ARIMA:自回归+移动平均线+趋势差分
  • SARIMA:自回归+移动平均+趋势差异+季节差异

ARMA–基线模型

ARMA 代表自回归移动平均线。顾名思义,它是两部分的组合——自回归和移动平均。

自回归模型–AR(p)

自回归模型根据以前观察到的值进行预测,可以用 AR(p)表示,其中 p 指定要查看的以前数据点的数量。如下所述,其中 X 代表来自先前时间点的观测值,而 φ 代表权重。

例如,如果 p = 3,则当前时间点取决于前三个时间点的值。

如何确定 p 值?

PACF(偏自相关函数)通常用于确定 p 值。对于时间序列 Xt 中的给定观测值,它可能与滞后观测值 Xt-3 相关,后者也受其滞后值的影响(例如 Xt-2、Xt-1)。PACF 将过去的观察对现在的观察的直接贡献形象化。例如,下面的 PACF 当滞后= 3 时 PACF 大致为-0.60,这反映了滞后 3 对原始数据点的影响,而滞后 1 和滞后 2 对滞后 3 的复合因子在 PACF 值中没有解释。然后,AR(p)模型的 p 值由 PACF 第一次落入显著阈值(蓝色区域)的时间来确定,即在下面的示例中 p = 4。

PACF(作者图片)

移动平均模型–MR(q)

移动平均模型,MR(q)基于来自先前的 q 观察的平均预测误差来调整模型,其可以陈述如下,其中 e 表示误差项,并且 θ 表示权重。 q 值决定移动平均窗口中包含的误差项的数量。

如何确定 q 值?

ACF 可用于确定 q 值。它通常被选作 ACF 第一次下降到接近 0 的第一个滞后值。例如,根据下面的 ACF 图,我们可以选择 q=4。

ACF(图片由作者提供)

为了建立 ARMA 模型,我们可以使用statsmodels.tsa.arima.model中的 ARIMA 函数(将在下一节解释)并指定超参数-阶(p,d,q)。当 d = 0 时,它作为 ARMA 模型运行。这里我们将 ARIMA(p=3 和 q=4)模型与时间序列数据df“IPG2211A2N”进行拟合。

from statsmodels.tsa.arima.model import ARIMA
ARMA_model = ARIMA(df['IPG2211A2N'], order=(3, 0, 4)).fit()

模型评估

在为时间序列建模选择合适的超参数时,模型评估变得尤为重要。我们将介绍三种评估时间序列模型的方法。为了估计模型对未观察数据的预测,我使用原始数据集中的前 300 条记录进行训练,剩余的(从索引 300 到 396)进行测试。

df_test = df[['DATE', 'IPG2211A2N']].loc[300:]
df = df[['DATE', 'IPG2211A2N']].loc[:299]
  1. 可视化

第一种方法是在同一图表中绘制实际时间序列数据和预测,并直观地检查模型性能。此示例代码首先使用 ARMA 模型生成从索引 300 到 396(与 df_test 大小相同)的预测,然后可视化实际数据与预测数据。如下图所示,由于 ARMA 模型未能捕捉到时间序列中的趋势,因此随着时间的推移,预测值会偏离实际值。

# generate predictions
df_pred = ARMA_model.predict(start=300, end=396)
# plot actual vs. predicted
fig = plt.figure(figsize=(20, 10))
plt.title('ARMA Predictions', fontsize=20)
plt.plot(df_test['IPG2211A2N'], label='actual', color='#ABD1DC')
plt.plot(df_pred, label='predicted', color='#C6A477')
plt.legend(fontsize =20, loc='upper left')

ARMA 预测(图片由作者提供)

2。均方根误差(RMSE)

对于时间序列回归,我们可以应用一般的回归模型评估方法,如 RMSE 或 MSE。更多详情,请看我的文章《机器学习中的 4 大线性回归变量》。

RMSE 越大,表明实际值和预测值之间的差异越大。我们可以使用下面的代码来计算 ARMA 模型的 RMSE——大约是 6.56。

from sklearn.metrics import mean_squared_error
from math import sqrt
rmse = sqrt(mean_squared_error(df['IPG2211A2N'][1:], pred_df[1:]))
print("RMSE:", round(rmse,2))

3。赤池信息标准(AIC)

第三种方法是使用 AIC,表述为AIC = 2k–2ln(L),来解释模型性能,它是基于对数似然( L )和参数个数( k )来计算的。我们希望对模型进行优化,以降低 AIC,这意味着:

  • 对数似然性需要很高,因此具有高预测性的模型将是首选。
  • 参数的数量很少,因此模型预测由更少的因素决定,因此它不太可能过拟合并且具有更高的可解释性。

我们可以通过summary()函数得到 AIC 值,下面的汇总结果告诉我们,ARMA 模型有 AIC = 1547.26。

ARMA_model.summary()

ARMA 摘要(图片由作者提供)

ARIMA:地址趋势

ARIMA 代表自回归综合移动平均,它从 ARMA 模型扩展而来,并结合了综合成分(差分的逆)。

ARIMA 在自回归模型(AR)和移动平均模型(MA)的基础上,通过引入差异成分的程度(指定为参数 d)–ARIMA(p,d,q) 。这是为了解决在时间序列数据中观察到明显趋势时的问题。如 ARMA 示例所示,该模型未能捕捉到数据中的趋势,这使得预测值偏离实际值。

在“平稳性和差异”一节中,我们解释了如何应用差异来消除趋势。现在让我们探索一下它是如何使预测更加准确的。

如何确定 d 值?

由于 ARIMA 在其模型构建过程中引入了差分,因此它并不严格要求训练数据是静态的。为了保证 ARIMA 模型能够很好地工作,应该选择合适的差分程度,使时间序列在去趋势化后转化为平稳数据。

我们可以首先使用 ADF 测试来确定数据是否已经是稳定的,如果数据是稳定的,则不需要差分,因此 d = 0。如前所述,差分前的 ADF 测试给出的 p 值为 0.29。

在应用趋势差分diff = df[‘IPG2211A2N’] – df[‘IPG2211A2N’].shift(1) 并使用 ADF 检验后,我们发现 p 值远低于 0.05。因此,这表明转换后的时间序列数据很可能是平稳的。

然而,如果数据仍然是不稳定的,第二级差分可能是必要的,这意味着对 diff 应用另一级差分(例如diff2 = diff – diff.shift(1))。

为了建立 ARIMA 模型,我们使用了 ARMA 模型中提到的相同函数,并添加了 d 参数,在本例中,d = 1。

# ARIMA (p, d, q)
from statsmodels.tsa.arima.model import ARIMA
ARIMA_model = ARIMA(df['IPG2211A2N'], order=(3, 1, 4)).fit()
ARIMA_model.summary()

ARIMA 摘要(图片由作者提供)

从总结结果可以看出,与 ARMA 模型相比,对数似然增加,AIC 减小,表明它具有更好的性能。

可视化还表明,预测趋势与测试数据更加一致,RMSE 降至 4.35。

ARIMA 预言(图片由作者提供)

萨里玛:解决季节性问题

SARIMA 代表季节性 ARIMA ,它处理时间序列中观察到的周期性模式。之前我们已经介绍了如何使用季节差异来消除季节影响。SARIMA 结合了这一功能来预测季节性变化的时间序列,我们可以使用 SARIMAX(p,D,q) x (P,D,Q,s) 来实现它。第一项(P,D,Q)表示 ARIMA 模型的阶数,( P,D,Q,s)表示季节分量。 P,D,Q 分别是季节顺序的自回归项、差分项和移动平均项。 s 是每个周期的观察次数。

如何确定 s 值?

ACF 图为季节性提供了一些证据。如下所示,每 12 个滞后似乎与原始观察值具有更高的相关性(与 6 个滞后相比)。

我们之前也测试过,在移动 12 个滞后的数据后,在可视化中没有观察到季节性。因此,在本例中我们指定 s=12。

#SARIMAX(p, d, q) x (P, D, Q, s)
SARIMA_model = sm.tsa.statespace.SARIMAX(df['IPG2211A2N'], order=(3, 1, 4),seasonal_order=(1, 1, 1, 12)).fit()
SARIMA_model.summary()

萨里玛摘要(图片由作者提供)

从汇总结果中,我们可以看到 AIC 从 ARIMA 的 1528.48 进一步下降到萨里玛的 1277.41。

萨里玛预言(图片由作者提供)

预测现在说明了季节性模式,RMSE 进一步下降到 4.04。

感谢您到目前为止,如果您想阅读更多来自 Medium 的文章并支持我的工作,我真的很感谢您使用这个附属链接注册 Medium 会员。

带回家的信息

这种时间序列模型介绍解释了 ARMA,ARIMA 和萨里玛模型在一个渐进的顺序。

  • ARMA:自回归+移动平均
  • ARIMA:自回归+移动平均线+趋势差分
  • SARIMA:自回归+移动平均+趋势差异+季节差异

此外,我们探索与时间序列数据相关的概念和技术,如平稳性,ADF 测试,ACF/PACF 图和 AIC。

更多相关文章

Destin Gong

德斯坦贡

EDA 和特征工程技术

View list9 storiesDestin Gong

德斯坦贡

机器学习实用指南

View list10 storiesPrincipal Component Analysis for MLTime Series Analysisdeep learning cheatsheet for beginner

参考

[1]原始数据集参考:美联储系统(美国)理事会,工业生产:公用事业:电力和燃气公用事业(NAICS = 2211,2) [IPUTIL],检索自圣路易斯美联储银行弗雷德;【https://fred.stlouisfed.org/series/IPUTIL,】T42022 年 11 月 17 日。[公共领域:请求引用]。

原载于 2022 年 11 月 17 日 https://www.visual-design.net**

地理空间数据的时间序列分析

原文:https://towardsdatascience.com/time-series-analysis-of-geospatial-data-bee45f156ba

从地理空间信息到用于时间序列分析的熊猫数据框架

照片由凯蒂·哈普Unsplash 拍摄

地理空间数据的时间序列分析允许我们分析和理解一个地方的事件和属性如何随时间而变化。它的使用案例非常广泛,特别是在社会、人口、环境和气象/气候研究方面。例如,在环境科学中,时间序列分析有助于分析一个地区的土地覆盖/土地利用如何随时间变化及其潜在驱动因素。它在理解天气模式的时空变化的气象研究中也是有用的(我将很快使用降雨数据演示一个这样的案例研究)。社会和经济科学极大地受益于这种分析,了解时间和空间现象的动态,如人口,经济和政治模式。

数据的空间表示非常强大。然而,分析地理空间数据并提取有趣的见解可能是一项具有挑战性的任务,尤其是对于没有接受过地理信息科学培训的数据科学家/分析师而言。幸运的是,有工具可以简化这个过程,这就是我在这篇文章中尝试的。我写了一篇关于地理空间数据争论的基础的文章——请随意查看:

在本文中,我将介绍一系列过程——从下载栅格数据开始,然后将数据传输到 pandas 数据框架中,并设置传统的时间序列分析任务。

案例研究:日本北海道的日降雨模式

数据源

在这个案例研究中,我使用的是日本北海道地区2020 年 1 月 1 日至 12 月 31 日期间的降雨量空间分布,相当于一年中的 366 天。我从一个开放的空间数据平台 ClimateServe 下载了数据——这是 NASA/USAID 合作的产物。任何能上网的人都可以很容易地下载数据。我已经把它们和代码上传到了 GitHub 上,如果你想继续的话。以下是我的本地目录中的一些光栅图像的快照:

本地目录中一些光栅文件的快照(来源:作者)

设置

首先,我设置了一个存储栅格数据集的文件夹,以便以后可以循环访问它们。

# specify folder path for raster dataset
tsFolderPath = './data/hokkaido/'

接下来,我将导入几个库,其中大部分是数据科学家熟悉的。为了处理栅格数据,我使用了rasterio库。

# import libraries
import os
import rasterio 
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

可视化数据

让我们看看光栅图像在绘图中的样子。我将首先使用rasterio加载一个随机图像,然后使用matplotlib功能绘制它。

# load in raster data
rf = rasterio.open('./data/hokkaido/20201101.tif')

fig, ax = plt.subplots(figsize=(15,5))

_ = ax.imshow(rf.read()[0], cmap = 'inferno')
fig.colorbar(_, ax=ax)
plt.axis('off')
plt.title('Daily rainfall Jan-Dec 2020, Hokkaido, Japan');

2020 年 11 月 1 日日本北海道的降雨量分布(单位:毫米)

正如你所看到的,这个图像是像素的组合,每个像素的值代表了特定位置的降雨量。较亮的像素雨量值高。在下一节中,我将提取这些值,并将它们传输到一个pandas数据帧中。

从光栅文件中提取数据

现在进入关键步骤——为 366 幅光栅图像中的每一幅提取像素值。这个过程很简单:我们将遍历每幅图像,读取像素值并将它们存储在一个列表中。

我们将在另一个列表中单独记录日期。我们从哪里得到日期信息?如果你仔细看看文件名,你会注意到它们是以各自的日期命名的。

# create empty lists to store data
date = []
rainfall_mm = []

# loop through each raster
for file in os.listdir(tsFolderPath):

    # read the files
    rf = rasterio.open(tsFolderPath + file)

    # convert raster data to an array
    array = rf.read(1)

    # store data in the list
    date.append(file[:-4])
    rainfall_mm.append(array[array>=0].mean())

请注意,由于图像分辨率较低(即像素较大),遍历 366 个栅格并不需要很长时间。但是,对于高分辨率数据集来说,这可能是计算密集型的。

所以我们刚刚创建了两个列表,一个存储文件名中的日期,另一个存储降雨量数据。以下是两个列表的前五项:

print(date[:5])
print(rainfall_mm[:5])

>> ['20200904', '20200910', '20200723', '20200509', '20200521']
>> [4.4631577, 6.95278, 3.4205956, 1.7203209, 0.45923564]

接下来将列表转移到一个pandas数据帧中。我们将从这里采取额外的步骤,将 dataframe 更改为一个时间序列对象。

转换为时间序列数据帧

pandas中,将列表转换为数据帧格式是一项简单的任务:

# convert lists to a dataframe
df = pd.DataFrame(zip(date, rainfall_mm), columns = ['date', 'rainfall_mm']) 
df.head()

从列表中生成的数据帧的前几行(来源:作者)

我们现在有了一个pandas dataframe,但是注意‘date’列保存字符串中的值,pandas还不知道它表示日期。所以我们需要稍微调整一下:

# Convert dataframe to datetime object
df['date'] = pd.to_datetime(df['date'])
df.head()

日期列现在转换为日期时间对象(来源:作者)

df['date'].info()

这确认了该列是一个日期时间对象(来源:作者)

现在数据帧是一个日期时间对象。

将日期列设置为索引也是一个好主意。这有助于按不同的日期和日期范围分割和过滤数据,并使绘图任务变得容易。我们将首先按照正确的顺序对日期进行排序,然后将该列设置为索引。

df = df.sort_values('date')
df.set_index('date', inplace=True)

好了,所有的处理都完成了。现在,您可以随意使用这些时间序列数据了。我就把数据画出来看看怎么样。

# plot
df.plot(figsize=(12,3), grid =True);

2020 年 1 月至 12 月日本北海道降雨量数据的时间序列图(来源:作者)

剧情很美!我过去写过几篇关于如何分析时间序列数据的文章,这里有一篇:

一锤定音

从地理空间时间序列数据中提取有趣且可操作的见解非常有用,因为它在空间和时间维度上显示数据。然而,对于没有受过地理空间信息培训的数据科学家来说,这可能是一项艰巨的任务。在本文中,我通过一个案例研究演示了如何以最小的努力轻松完成这项困难的任务。如果你想复制这个练习或者把它带到下一个水平,可以在我的 GitHub 上找到数据和代码。

感谢阅读。请随意订阅以获得我即将在媒体上发表的文章的通知,或者通过 LinkedInTwitter 与我联系。下次见!

基于 PyFBAD 的时间序列异常检测

原文:https://towardsdatascience.com/time-series-anomaly-detection-with-pyfbad-d37e5462c6c3

一种端到端的无监督离群点检测

取自 Unsplash

机器学习项目的典型流程从读取数据开始,然后是一些预处理、训练、测试、可视化以及与通知系统共享结果。当然,所有的步骤都可以在各种开源库的帮助下轻松完成。然而,在一些特定于任务的情况下,比如时间序列数据中的异常检测,减少库和硬编码步骤的数量将更有利于可解释性。pyfbad 库就是为此而开发的。

https://github.com/Teknasyon-Teknoloji/pyfbad

pyfbad 库是一个端到端的无监督异常检测包。这个包提供了前面提到的所有 ml-flow 步骤的源代码。例如,可以使用 pyfbad 通过特殊的过滤器从文件、MongoDB 或 MySQL 中读取数据。这些读取的数据可以通过预处理方法为模型做好准备。该模型可以使用不同的机器学习模型进行训练,例如 Prophet 或 Isolation Forest。异常检测结果可以通过电子邮件或 slack 报告。换句话说,项目的整个周期可以在 pyfbad 下提供的源代码的帮助下完成,而不需要使用任何其他库。

事实上,阅读 这篇内容丰富的文章 将有助于理解我们为什么需要开发这个包,以及如何从总体上设计一个无监督的异常检测项目。然而,我们仍然简单地将异常检测描述为一种识别技术,用于发现导致给定数据集中突然峰值或谷值的异常观察。

图一。基于 pyfbad 的时间序列数据无监督异常检测流水线。作者图片

如图 1 所示,pyfbad 有 4 个主要模块:数据库、特性、模型和通知。在 CookiecutterDrivendata 的帮助下,这种结构在数据科学项目中几乎是标准化的。项目组织如图 2 所示。

数据库:

这个模块有从各种数据库或文件中读取数据的脚本。MySQL 和 MongoDB 是目前为止添加的数据库支持。特别是在 MongoDB 中,通过 Pyfbad 使用过滤步骤变得更加用户友好。下面的代码片段可能会让您了解如何使用 pyfbad 进行数据库操作。

功能:

变量时间序列异常检测的概念需要两类数据。其中一个是连续时间数据,另一个是我们想要检测异常的主数据。这两个数据应该从原始数据中提取出来作为模型数据。Pyfbad 提供了从原始数据帧中检索模型数据的可选过滤功能。下面的代码片段显示了如何使用 pyfbad 来执行此操作。

型号:

该模块能够用各种算法训练模型数据。可以理解,Pyfbad 旨在检测时间序列数据上的异常。从这个意义上来说,它提供了使用模型的机会,这些模型可以被快速而稳健地应用。脸书先知和隔离福里斯特是模型支持添加到目前为止。作为一个例子,从下面的代码片段可以看出 Prophet 是如何在 pyfbad 的帮助下实现的。

通知:

我们使用的所有技术的成功程度与它们如何利用其产出有关。如果产品能很好地传达给用户,并能解释如何使用它,产品就会变得可见。pyfbad 提供了各种通知系统来共享项目的结果,比如电子邮件和 slack。电子邮件选项可以用作下面的代码片段。请注意,电子邮件帐户不应该有授权的高安全性设置。

实现!

让我们快速实现一下,以便更好地理解如何使用 Pyfbad。完整的笔记本可以在 Kaggle 上从这里找到。这里我们只看每一步的结果。

将数据集模块导入 pyfbad 库之后,可以从 CSV 格式的文件中读取原始数据。原始数据如图 3 所示。

图 3。原始时间序列数据值。作者图片

在这个数据集中,实际上不需要预处理步骤来从原始数据集中提取准备训练的数据集。然而,在图 4 中,可以看出初始数据帧和最终数据帧之间的差异。

图 4。原始数据集在左侧,准备好训练的数据集在右侧。作者图片

在此实现中,使用 Prophet 算法来训练模型。在训练步骤之后,检测到的异常可以显示在图 5 中。

图 5。异常检测结果。作者图片

结论

Pyfbad 可以很好地与大多数流行的数据库一起工作,比如 MongoDB 和 MySQL,但是仍然可以添加不同种类的数据库支持。它目前使用最知名的模型,如 FB Prophet 和 Isolation Forrest,但仍需要更多的机器学习算法。项目背后的团队渴望学习,对研发充满热情,对学习新技术非常有抱负。因此,我们可以有把握地说,这是 Pyfbad 的第一个版本。正在进行研究,以弥补上述不足,并使 Pyfbad 成为一个非常全面的无监督异常检测库。

包创建者

参考

基于 LightGBM 的时间序列分类

原文:https://towardsdatascience.com/time-series-classification-with-lightgbm-d79d2d81bfd0

使用 LazyProphet 的示例

Unsplash 上的隐形力量拍摄的照片

处理时间序列数据时,分类是一项常见的任务。类似于时间序列回归,趋势和季节性的存在使这项任务变得困难。幸运的是,使用 LightGBM 进行回归所得到的相同特性也可以用于分类。通过使用 LazyProphet ,这个任务就变得简单了。

介绍

这篇文章是我之前对 LazyProphet 的评论的后续:

在那篇文章中,我们解决了标准时间序列回归问题,并在 M4 数据集上实现了单变量时间序列树的最先进(我认为)的结果。关键在于利用线性分段基函数。虽然并不都是独一无二的,但我们添加了一个扭曲——函数被加权以更好地适应数据。这使得树实现了显著更好的性能。如果你不知道这些是什么,一定要看看之前的文章!

此外,LazyProphet 还提供了“递归”预测功能,即使用以前的目标值进行预测。这要求我们在过程中的某个时刻使用未来预测,这对于从头开始编码和处理来说有点烦人。

最后,我们也有一些独特的方式来思考树木的趋势,这也有助于改进,你可以在这里查看一篇文章:

幸运的是,这些相同的技术也可以用来解决分类问题。在本文中,我们将快速浏览一下用 LazyProphet 解决这样一个问题。

但是首先,如果您还没有安装这个包,那么只需要一点点:

pip install LazyProphet

现在,让我们来看数据。

例子

对于这个例子,我们将使用 Scikit-Learn 开放数据集的一个例子:自行车共享需求数据集。

from sklearn.datasets import fetch_openml
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('darkgrid')bike_sharing = fetch_openml("Bike_Sharing_Demand", version=2, as_frame=True)
y = bike_sharing.frame['count']
y = y[-800:].values
plt.plot(y)
plt.show()

作者图片

显然,这些数据不是为二进制分类创建的,所以让我们来解决这个问题。

y_class = y > 70
y_class = y_class * 1
plt.plot(y_class)
plt.show()

作者图片

在这里,我们简单地将任何超过 70 的值标记为 1,将所有低于 0 的值标记为 0。显然存在一些季节性,以及 600 到 700 小时之间的一些“冲击”。

接下来,我们简单地构建模型:

from LazyProphet import LazyProphet as lplp_model = lp.LazyProphet(seasonal_period=[24],
                          n_basis=10,
                          objective='classification',
                          fourier_order=5,
                          decay=.99,
                          ar=3,
                          return_proba=True)
  • seasonal_period —数据的季节性。我们可以传递一个 intfloat 以及一个 list 。如果我们传递一个列表,我们可以为复杂的季节性传递多个值,比如[7, 365.25]
  • n_basis —要使用的分段基函数的数量。这是用来衡量“趋势”以及允许季节性随时间变化。
  • objective'classification''regression'。如果我们通过了classification,那么 LazyProphet 使用一个二元交叉熵目标函数。如果我们通过regression,那么 LazyProphet 将使用 RMSE。
  • fourier_order —用于近似季节性脉冲的正弦和余弦分量的数量。数字越大,它就越适合摆动!
  • decay —趋势基函数的“衰减”或惩罚权重。如果你不知道这是什么,那么看看前面提到的文章。
  • ar —用于预测的过去值的数量。如果我们在这里传递一个 int,那么 LazyProphet 会自动进行一步预测,并将该预测用于整个预测范围的下一步。
  • return_proba —布尔标志,如果设置为True,则 LazyProphet 返回概率,如果设置为False,则仅返回[1,0]分类。

现在我们只需要将模型与我们的数据相匹配,并预测 100 步:

fitted = lp_model.fit(y_class)
predicted_class = lp_model.predict(100)
plt.plot(y_class)
plt.plot(np.append(fitted, predicted_class), alpha=.5)
plt.axvline(800)
plt.show()

作者图片

瞧!

我们对概率有一个合理的预测。当然,树模型与训练数据不合理地拟合得很好,所以我们应该小心评估我们的拟合度。可以用不同的超参数进行进一步的迭代。

有时(比如在这个例子中),我们的标签是由一个实数而不是二进制数的时间序列派生出来的,或者与这个时间序列密切相关。如果是这种情况,我们只需要在构建模型对象时传递该系列。看起来会像这样:

lp_model = lp.LazyProphet(seasonal_period=[24],
                          n_basis=3,
                          objective='classification',
                          fourier_order=5,
                          decay=.99,
                          #ar=3, ar should be turned off here
                          return_proba=True,
                          series_features=y,
                          )

其中“y”是我们处理成二元分类标签的原始系列。注意 需要禁用 ar。从这里开始,其余的程序是相同的!

结论

在本文中,我们尝试用 LazyProphet 进行时间序列分类。因为核心是用 LightGBM 构建的,所以从回归问题转换到分类问题非常容易。但是,我们看到的真正性能提升来自加权基函数。

请务必查看 github 并公开您遇到的任何问题!

如果你喜欢这篇文章,你可能会喜欢我写的其他几篇:

时间序列分解

原文:https://towardsdatascience.com/time-series-decomposition-8f39432f78f9

将时间序列分解成基本的构建块

奥斯曼·拉纳在 Unsplash 上拍摄的照片

介绍

当试图获得洞察力并找到产生未来预测的最佳模型时,理解你的 时间序列 是最基本的。大多数时间序列可以被分解成不同的 成分 来帮助以结构化的方式对其进行诊断,提供了一个强大的分析工具。

在这篇文章中,我想讨论这些不同的组件是什么,如何获得它们,以及我们如何使用 Python 进行时间序列分解。

时间序列组件

时间序列是(主要)三个部分的组合:趋势季节性残差/余数。让我们逐一分析。

趋势 : 这是系列的整体运动。它可能持续增加加班时间、减少加班时间或两者兼而有之。

季节性 : 序列中任何有规律的季节性模式。例如,冰淇淋的销量在夏季通常高于冬季。要了解更多关于季节性的知识,请查看我的上一篇文章:

残差/余数 : 这是我们考虑了趋势和季节性之后剩下的那一点。也可以认为只是 统计噪声

有时也有一个单独的 周期 成分,但它经常被归入趋势成分。

加法与乘法模型

这些组件的组合方式取决于您的系列的性质。对于一个 加法 模型我们有:

作者用 LaTeX 写的方程式。

而对于一个 乘性 系列:

作者用 LaTeX 写的方程式。

其中 Y 为数列, T 为趋势, S 为季节性, R 为残差分量。

当序列变化的大小在一致的绝对数值范围内时,加法模型是最合适的。另一方面,乘法模型是当系列的波动是在一个相对的和成比例的规模。

例如,如果每年夏天的冰淇淋销售额高出 1000,那么该模型就是可加性的。如果每年夏天销售额持续增长 20%,但是绝对销售额在变化,那么这个模型就是乘法模型。我们将在后面讨论一个例子,这个例子将使这个理论更加具体。

可以通过简单的对数变换或 Box-Cox 变换 将乘法模型转换为加法模型:

作者用 LaTeX 写的方程式。

要了解关于 Box-Cox 变换的更多信息,您可以阅读我以前的一篇文章:

分解是怎么做的?

有多种算法和方法可以将时间序列分解为三个部分。我想回顾一下经典的https://www.openforecast.org/adam/classical-seasonal-decomposition.html方法,因为这种方法经常使用并且非常直观。

  • 使用移动/滚动平均值计算趋势分量T、
  • 去趋势系列, Y-T 为加法模型, Y/T 为乘法模型。
  • 计算季节性成分 S ,取每个季节去趋势序列的平均值。
  • 剩余分量 R 计算如下: R = Y-T-R 对于加法模型, R = Y/(TR) 对于乘法模型。

还有其他几种分解方法,如 STLX11席位 。这些都是先进的方法,补充了传统方法的基本方法,并改进了其缺点。****

Python 中的分解

让我们再次回顾一下 1948 年至 1961 年间美国航空公司的经典客运量数据:

数据来自拥有 CC0 许可证的 Kaggle

作者代码要点。

作者用 Python 制作的情节。

从该图中,我们观察到一个增长趋势和一个年度季节性。请注意,波动的大小随着时间的推移而增加,因此我们有一个乘法模型。

我们可以使用 statsmodels 函数seasonal _ decompose分解时间序列,并在调用该函数时指定我们有一个“乘法”模型:**

作者代码要点。

作者用 Python 制作的情节。

从上面的图中我们可以看到,该函数确实成功地捕获了三个组件。

我们可以通过应用 boxcox Scipy 函数,使用 Box-Cox 变换来稳定方差,从而将我们的序列转换为加法模型:

作者代码要点。

作者用 Python 制作的情节。

同样,该函数似乎很好地捕捉到了这三个组件。有趣的是,我们看到残差在早些年和晚些年有更高的波动性。在为此系列构建预测模型时,这可能是需要考虑的因素。

结论

在这篇文章中,我们展示了如何将一个时间序列分解成三个基本部分:趋势、季节性和残差。这三个部分的组合产生了你观察到的时间序列,根据它的性质,它可以是加法的,也可以是乘法的。有几种技术来进行分解,如 STL,海豹突击队和 X11,但是我更喜欢经典的方法,因为它非常直观。能够分解时间序列有助于加深对数据的理解,从而更容易做出未来预测。

这篇文章中使用的完整代码可以在我的 GitHub 中找到:

*****https://github.com/egorhowell/Medium-Articles/blob/main/Time Series/Time Series Tools/decomposition.py

参考资料和进一步阅读

和我联系!

(所有表情符号由 OpenMoji 设计——开源表情符号和图标项目。许可证: CC BY-SA 4.0*****

时间序列 DIY:季节分解

原文:https://towardsdatascience.com/time-series-diy-seasonal-decomposition-f0b469afed44

克里斯·劳顿在 Unsplash 上的照片

了解在statsmodel’ s seasonal_decompose的引擎盖下发生了什么

如果你处理过时间序列,你可能已经使用过statsmodel中的seasonal_decompose(或者 R 的等价物)。长话短说,它将时间序列分成三个部分:趋势、季节性和残差。运行该命令后,您会看到类似下图的内容。

作者图片

组件的解释也非常直观:

  • 趋势——一个系列在很长一段时间内的总体方向
  • 季节性——由于各种季节性因素,定期观察到的独特的重复模式。可以是每月、每周等。
  • 残差——去除之前的成分后,由时间序列波动组成的不规则成分

这应该足够了。我也不会详细讨论季节分解的目标(理解数据、预测、异常值检测)。相反,我想探索一个不太受欢迎的角度——当你调用seasonal_decompose 函数时会发生什么。在这篇动手文章中,我们将回答这个问题:这些组件是如何估算的?如果你好奇,请继续阅读!

理论

让我们假设我们处理的是加性模型,即由一个线性趋势和具有相同频率(宽度)和振幅(高度)的季节性周期组成。对于乘法模型,你只需要用乘法代替加法,用除法代替减法。

趋势分量

使用时间序列的居中移动平均值计算趋势。使用对应于时间序列频率的窗口长度来计算移动平均值。例如,我们将对月度数据使用长度为 12 的窗口。

使用这种移动平均线来平滑序列也有一些缺点。首先,我们正在“丢失”系列的第一个和最后几个观察值。第二,移动平均线会使数列变得过于平滑,这使得它对趋势的突然变化或跳跃反应迟钝。

季节性成分

为了计算季节性成分,我们首先需要对时间序列进行去趋势分析。我们通过从原始时间序列中减去趋势分量来实现(记住,我们除以乘法变量)。

完成后,我们计算每个季节周期的去趋势序列的平均值。对于月份,我们将计算每个月的平均去趋势值。

季节性成分是简单地从整个序列的长度重复的季节性平均值构建的,这也是反对使用简单季节性分解的理由之一-季节性成分不允许随着时间的推移而变化,这对于较长的时间序列来说可能是一个非常严格且通常不切实际的假设。

另一方面,在加法分解中,去趋势序列以零为中心,因为加零不会改变趋势。相同的逻辑应用于乘法方法,不同之处在于它以 1 为中心。这是因为趋势乘以 1 也不会对其产生影响。

残差

最后一个部分就是从原始时间序列中去除(减去或除以)趋势和季节成分后剩下的部分。

理论到此为止,让我们编码吧!

循序渐进的教程

设置

和往常一样,我们从导入库开始。

数据

我们将使用可能是时间序列分析中最流行的数据集——澳大利亚航空乘客时间序列。我们从一个 CSV 文件中加载它(此处可用,但是您也可以从其他来源获取它,例如,从seaborn库(此处)。

作者图片

仅仅通过目测图表,乘法分解似乎是一个更好的选择(特别是当看到季节成分随着时间的推移而增加时)。但是我们将保持我们在介绍中的假设,并进行加法分解。我们把乘法作为一个可选的练习。

来自 statsmodels 的基准

在我们自己分解时间序列之前,可以用statsmodels得到基准。

作者图片

在图中,我们可以看到另一个提示,即加性模型在这里不是正确的选择-随着时间的推移,残差中有明显的模式。在拟合较好的情况下,我们希望残差表现随机,没有任何模式。

作为参考,我们可以很容易地从DecomposeResult对象中提取组件。它们存放在trendseasonalresid下。

人工分解

对于手工分解,我们将使用一个pandas数据框架来存储原始序列、提取的组件和所有中间结果。

我们已经在上面的理论部分写出了作战计划,所以让我们在一个代码片段中执行所有步骤(你可以在 GitHub 上按照笔记本中的一个单元一个单元的流程)。

运行该代码片段会生成下表:

作者图片

关于计算,有几件事值得一提:

  • 我们使用了长度为 13 的滚动窗口(12 个月+ 1 使其成为居中平均值的奇数)。
  • 我们使用了一种叫做transform的非常简便的方法来计算每组的平均值。我们使用它来避免创建一个单独的带有聚合值的数据帧,然后将它连接回原始的 DF。你可以在这里阅读更多关于它的内容(以及其他一些有用的pandas功能】
  • 我们显示了前 15 行,这样我们就可以看到所有月份(包括那些在去趋势序列中缺少值的月份)的合计季节性成分都计算正确。

最后,我们绘制分解图。

作者图片

结果看起来和我们用statsmodels得到的非常相似。我们没有将残差绘制成点(而不是默认的线),但是,我们应该仍然能够很容易地看到重叠的模式。

结果比较

为了比较我们是否精确匹配,我们可以查看用seasonal_decompose提取的组件,并将它们与我们手动计算的组件进行比较。剧透:它们非常相似,但又不相同。

我们选择了另一种方法,即直观地比较两种分解。首先,我们将手动分解的结果存储在DecomposeResult对象中。然后,我们借用了一个很棒的助手函数,将一个分解的结果添加到一个现有的分解图中(函数的源)。

作者图片

在上图中,我们看到结果非常接近。这些差异可归因于组件的计算方式——一如既往,细节决定成败。在statsmodels中,使用一维卷积滤波器计算用于提取趋势分量的移动平均值(使用convolution_filter函数计算)。如您所见,结果非常相似,但还是有点不同。这然后传播到季节性成分。

外卖食品

  • 季节分解的基本方法是将时间序列分成三个部分:趋势、季节和残差,
  • 趋势分量被计算为原始序列的居中移动平均值,
  • 季节性因素是按去趋势数列的每期平均值计算的,
  • 残差分量是在从时间序列中去除趋势和季节分量之后获得的。

您可以在我的 GitHub 上找到本文使用的代码。此外,欢迎任何建设性的反馈。你可以在推特或评论中联系我。

喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用 这个链接 成为会员,你就支持我,不需要你额外付费。提前感谢,再见!

您可能还会对以下内容感兴趣:

参考

  • Box,G. E. P .,Jenkins,G. M .和 Reinsel,G. C. (1976) 时间序列分析、预测和控制。第三版。霍尔登日。g 系列。

R 中的时间序列预测

原文:https://towardsdatascience.com/time-series-forecast-in-r-70d51a21d6c8

如何在 R 中执行时间序列预测的分步指南

您已经获得了大量的时间序列数据,您想知道如何使用这些数据来预测未来?

如果你的答案是肯定的,那么你来对地方了…

亨特·哈里特Unsplash 上拍摄的照片

在这个故事中,让我向您介绍一种易于实现的方法,使用季节性 ARIMA 模型对时间序列数据集进行预测。出于演示的目的,我们将使用麻省理工学院许可下的一个鱼类销售数据集和一个雅虎财经股票价格数据集(直接在 R 中下载)…

探索性数据分析

在开始任何数据科学或人工智能相关的任务之前,执行探索性数据分析(EDA)是一个好的做法。在整个 EDA 过程中,你将获得有价值的见解,这些见解可能会极大地影响你即将到来的建模策略。如果你不熟悉 EDA,我推荐你看一看我的另一个故事,我在其中执行了一个示例 EDA。

让我们开始吧…

作为第一步,我们导入时间序列预测所需的库并读取数据…

下面是我们的鱼销售数据集的‘头’‘尾’的样子…

作者图片

从上面的片段中,可以注意到数据比需要的多很多。我们将为“销售”值创建时间序列预测。相应地,我们开始处理数据,去掉所有变量,除了' start'sales'

测井回报在变量' logr '下计算。它们被添加到一个单独的列中,现在数据头看起来像…

作者图片

然后数据被格式化成变量' test_ts '下的' ts '变量。

让我们在时间域中绘制数据,以便对我们正在处理的内容有一个大致的了解…

作者图片

然后将数据分解为“原始数据”、“季节性”、“趋势”和“残差”,在下一张图中从上到下绘制

作者图片

然后对自相关部分自相关函数进行评估…

作者图片

通过上面的图表,可以区分良好的季节性以及数据中合理的相关性,但是增强的 Dickey-Fuller 测试可以证实这一假设。获得的 p 值<为 0.05,因此可以安全地假设数据集是静态的

作者图片

基于这一发现,选择季节性 ARIMA 模型来创建预测。季节性 ARIMA 的系数是基于数据集显示出很强的季节性这一事实进行估计的(季节性=真 )…

…并获得结果摘要

作者图片

作者图片

基于平稳性假设,该模型表现相当好。让我们看看另一个数据集上的示例…

雅虎财务数据的时间序列预测

在第二个示例中,再次验证了数据的平稳性,数据看起来足够平稳,可以使用季节性 ARIMA 进行时间序列预测。执行与上述相同的过程…

输入数据是…

作者图片

…以及下面提供的输出和摘要。

作者图片

作者图片

讨论

总的来说,我们使用了一个 ARIMA 模型来拟合两个不同的(稳定的)时间序列数据集进行预测。然而,通过查看结果,您可以注意到第二个示例(在 Yahoo Financial 数据集上)比第一个示例(在 Fish Sales 数据集上)有更大的错误。

你认为为什么会这样?你有什么看法?

为了回答这个问题,您可能需要自己运行 Yahoo Financial Dataset 的代码(两个示例的完整代码都在我的 repo 中提供)。

如果你愿意进一步尝试时间序列预测,并探索 Python 中的 SARIMAX 和 Prophet 等其他算法,那么你可以看看下面的故事。

如果你喜欢我的故事,并想跳到代码和完整的数据集,我已经在我个人的 git 上的 repo 中发布了它。

回购一颗星,在 linkedin 上联系我!
干杯:)

基于趋势和季节成分的时间序列预测

原文:https://towardsdatascience.com/time-series-forecasting-based-on-the-trend-and-seasonal-components-26b92866e548

分析时间序列的趋势和季节性,以分解时间序列并实现预测模型

照片由卢卡斯像素上拍摄

时间序列预测是基于带有时间戳的历史数据进行预测的任务。它包括建立模型以进行观察,并在天气、工程、经济、金融或商业预测等应用中推动未来的决策。

本文旨在介绍时间序列预测。结构展开如下。首先,描述任何时间序列的两个主要模式(趋势和季节性)。其次,根据这些模式对时间序列进行分解。最后,实现了一种称为 Holt-Winters 季节性方法的预测模型,适用于具有趋势和/或季节性成分的时间序列数据。

为了涵盖所有这些内容,我创建了一个数据集来模拟 2010 年至 2020 年间北半球城市(如塞维利亚)的温度。任何感兴趣的人都可以免费获得合成数据集和用于创建它的方法。代码可以在下面的 GitHub 库中找到。

1.导入库和数据

首先,导入运行代码所需的以下库。除了最典型的库之外,代码基于由 statsmodels 库提供的函数,该库提供了用于估计许多不同统计模型的类和函数,例如统计测试和预测模型。

下面是创建数据集的代码。该数据由两列组成,一列是日期,另一列是 2010 年到 2020 年之间的温度。

2.可视化数据集

在我们开始分析时间序列的模式之前,让我们将数据可视化,其中每条垂直虚线对应于一年的开始。

图 1 。温度时间序列。参考:作者图片

在进入下一部分之前,让我们花点时间看看数据。有趣的是,这些数据似乎有季节性变化,因为冬季气温升高,夏季气温下降(南半球)。此外,温度似乎不会随着时间的推移而显著升高,因为无论哪一年,平均温度都几乎相同。

3.时间序列模式

时间序列预测模型使用数学方程来寻找一系列历史数据中的模式。然后,这些等式被用于将数据中的历史时间模式投射到未来[1]。

有四种类型的时间序列模式:

  • 趋势:数据的长期增减。趋势可以是任何函数,例如线性或指数函数,并且可以随时间改变方向。
  • 季节性:以固定频率(一天中的小时、一周、一月、一年等)在序列中重复循环。).季节性模式存在于一个固定的已知时期。
  • 周期性:当数据上升和下降时出现,但没有固定的频率和持续时间,例如由经济条件造成的。
  • 噪声:序列中的随机变化。

大多数时间序列数据将包含一个或多个模式,但可能不是全部。这里有一些例子,我们可以确定其中的一些时间序列模式:

  1. 维基百科年度受众(左图):在该图中,我们可以发现一个增长趋势,因为受众每年都在线性增长。
  2. 美国用电量的季节性曲线图(中间图):每条线对应一年,因此我们可以观察到年度季节性,因为消耗每年重复一次。
  3. IBEX 35 日收盘(右图):这个时间序列随着时间的推移有一个增加的趋势,以及一个周期模式,因为有一些时期 IBEX 35 由于经济原因而下降。

图 2 。从左到右,维基百科的年度观众,美国用电量的季节性图,IBEX 35 日收盘。参考:从左到右依次为【3】、【4】、【5】

如果我们假设这些模式的加法分解,我们可以写为:

Y[t] = T[t] + S[t] + e[t]

其中 Y[t]是数据,T[t]是趋势周期分量,S[t]是季节分量,e[t]是噪声,都在周期 T 内。

另一方面,乘法分解可以写成:

Y[t] = T[t] *S[t] *e[t]

当季节波动不随时间序列水平变化时,加法分解是最合适的。相反,当季节性成分的变化似乎与时间序列的水平成比例时,则乘法分解更合适[2]。

4.分解数据

平稳时间序列被定义为其性质不依赖于观察时间的时间序列。因此,具有趋势或季节性的时间序列不是平稳的,而白噪声序列是平稳的[6]。从更数学的意义上来说,如果一个时间序列有一个恒定的均值和方差,并且协方差与时间无关,则称该时间序列是平稳的。在[ 6 ]中,你有不同的说明性例子来比较平稳和非平稳时间序列。一般来说,一个平稳的时间序列不会有长期可预测的模式。

但是,为什么平稳性很重要呢?

嗯,平稳性已经成为时间序列分析中许多实践和工具的共同假设。其中包括趋势估计、预测和因果推断等。因此,在许多情况下,您需要确定数据是否是由平稳过程生成的,并将其转换为由该过程生成的样本的属性[7]。

但是,如何检验时间序列的平稳性呢?

我们可以用两种方法检查静止的。一方面,我们可以通过检查时间序列的均值和方差来手动检查它。另一方面,我们可以使用测试函数来评估平稳性[8]。

有些情况可能会令人困惑。例如,没有趋势和季节性但具有周期行为的时间序列是稳定的,因为周期不是固定长度的。

4.1。检查趋势

为了分析时间序列的趋势和季节性,我们首先使用 30 天和 365 天窗口的滚动平均法分析一段时间内的平均值。

图三。滚动平均值和标准差。 Ref :图片作者。

在图中,我们可以看到由于数据的季节性模式,使用 30 天窗口时的滚动平均值是如何随时间振荡的。此外,使用 365 天窗口时的滚动平均值随着时间的推移而增加,表明随着时间的推移略有增加的趋势。

这也可以使用几个测试进行评估,如迪基-富勒(ADF)和科维亚特科夫斯基、菲利普、施密特和申(KPSS):

  • ADF 测试的结果(p 值低于 0.05)表明,单位根存在的零假设可以在 95%的置信水平上被拒绝。因此,如果 p 值低于 0.05,时间序列是稳定的。
  • KPSS 检验的结果(p 值大于 0.05)表明,不存在单位根和存在单位根的零假设不能在 95%的置信水平下被拒绝。因此,如果 p 值低于 0.05,时间序列就不是稳定的。

虽然这些测试似乎是为了检查数据的平稳性,但它们对于分析时间序列的趋势而非季节性是有用的,如[9]所示。

Results of Dickey-Fuller Test:
Test Statistic                  -3.69171446
p-value                          0.00423122
Lags Used                       30.00000000
Number of Observations Used   3621.00000000
Critical Value (1%)             -3.43215722
Critical Value (5%)             -2.86233853
Critical Value (10%)            -2.56719507
dtype: float64
Results of KPSS Test:
Test Statistic           1.04843270
p-value                  0.01000000
Lags Used               37.00000000
Critical Value (10%)     0.34700000
Critical Value (5%)      0.46300000
Critical Value (2.5%)    0.57400000
Critical Value (1%)      0.73900000
dtype: float64

有趣的是,统计结果揭示了时间序列平稳性的影响。然而,两种检验的零假设是相反的。ADF 检验表明时间序列是平稳的(p 值> 0.05),而 KPSS 检验表明它不是平稳的(p 值> 0.05)。该数据集是以轻微趋势创建的,因此结果表明 KPSS 检验对于分析该数据集更为准确。

为了降低数据集的趋势,我们可以实现以下去趋势方法:

图 4 。去除时间序列趋势后的滚动平均值和标准差。参考号:图片由作者提供。

4.2。检查季节性

正如之前从滚动 std 中观察到的,我们的时间序列中有一个季节性模式。因此,我们应该采用差分方法来消除时间序列中潜在的季节性或周期性模式。由于样本数据集有 12 个月的季节性,我使用了 365-滞后差异的差异:

图 5 。时间序列差分后的滚动平均值和标准差。 Ref :图片作者。

现在,滚动平均值和标准差在一段时间内基本保持不变,所以我们有一个稳定的时间序列。

去趋势和差分方法的组合实现如下:

图 6 。时间序列去趋势和差分后的滚动平均值和标准差。参考:图片由作者提供。

4.3。分解

基于上述模式的分解可以通过【stats models】包 中的一个有用的 Python 函数seasonal _ decompose来实现:

图 7 。时间序列分解。参考:图片由作者提供。

在查看了分解图的四个部分后,我们可以说,在我们的时间序列中有一个很强的年度季节性成分,以及一个随时间推移而增加的趋势模式。

5.建模

时间序列数据的合适模型将取决于数据的特定特征,例如,数据集是否具有总体趋势或季节性。请务必选择最适合您的数据的模型。

时间序列数据的合适模型将取决于数据的特定特征,如趋势和季节性[10]。请确保选择最适合您的数据的模型:

  1. 自回归(AR)
  2. 移动平均线
  3. 自回归移动平均(ARMA)
  4. 自回归综合移动平均(ARIMA)
  5. 季节性自回归综合移动平均(SARIMA)
  6. 带有外生回归量的季节性自回归综合移动平均(SARIMAX)
  7. 向量自回归(VAR)
  8. 向量自回归移动平均(VARMA)
  9. 带外生回归量的向量自回归移动平均(VARMAX)
  10. 简单指数平滑(SES)
  11. 霍尔特·温特的指数平滑法

由于我们的数据中存在季节性,实施的模型是霍尔特-温特斯指数平滑法,因为它适用于具有趋势和/或季节性成分的时间序列数据。

这种方法使用指数平滑对过去的大量值进行编码,并使用它们来预测现在和未来的“典型”值。指数平滑是指使用指数加权移动平均(EWMA)来“平滑”时间序列[11]。

在实施之前,让我们创建培训和测试数据集:

下面是使用均方根误差(RMSE)作为度量来评估模型误差的实现。

The Root Mean Squared Error of additive trend, additive seasonal of period season_length=365 and a Box-Cox transformation 6.27

图 8 。霍尔特-温特斯指数平滑法的结果。参考号:图片由作者提供。

从图中,我们可以观察到模型是如何捕捉时间序列的季节性和趋势的,在异常值的预测中有一个错误。

6.结论

了解主要的时间序列模式并学习如何实现时间序列预测模型是至关重要的,因为它们有许多应用。

在整篇文章中,我们通过一个基于温度数据集的实际例子介绍了趋势和季节性。除了检查趋势和季节性,我们还看到了如何减少它,以及如何创建一个基本模型,使用这些模式来推断未来几天的温度。

从这里开始,接下来的步骤是理解其他预测模型,如第 5 节中列出的模型。在这里,我留下了两个链接[ 1012 ],链接到其他可以被认为是这篇文章的延伸的文章。

如果你喜欢这篇文章,请考虑 订阅 。你将获得我所有的内容+所有其他来自牛逼创作者的文章!

参考

[1] Science Direct,智慧餐厅:顾客需求调查及销售预测

[2] Otexts,时序组件

[3]维基媒体,维基百科的年度受众

[4]维基媒体,美国用电量的季节性图表

[5]维基媒体,【1986 年 12 月至 2012 年 9 月的 IBEX 35(每日收盘)

[6] Otexts,平稳性和差分性

[7]中等,时间序列分析中的平稳性

[8] Medium,为什么增强的 Dickey-Fuller 检验(ADF 检验)在时间序列分析中如此重要

[9]堆栈交换,被 ADF 和 KPSS 检验视为平稳的季节性数据

[10]boundous,使用 Python 进行时间序列模型预测:第二部分

[11] Orangematter,霍尔特-温特斯预测和指数平滑简化

[12]中等,找到 ARIMA 车型的订单

其他:

时间序列预测:集成学习

原文:https://towardsdatascience.com/time-series-forecasting-ensemble-learning-df5fcbb48581

用决策树和 ARIMA 模型展示集成学习的威力

仪表图像——作者多丽丝·摩根

在这篇文章中,我将展示集成学习对于时间序列预测的预测能力。集成学习导致模型具有更高的预测准确性、更低的过拟合可能性和不同的预测集。

我将使用 ASHRAE(美国供暖、制冷和空调工程师协会)提供的数据集,该数据集包含各种建筑的电力、冷冻水、蒸汽和热水的每小时计量数据。这个数据集可以在这里 (CC0:公共领域)找到。在下一节中,我们将导入必要的 python 包,并加载计量和建筑数据。

加载数据

建筑行业—按作者

在上面的图像中,我们可以看到有大约 1400 个独特的建筑分布在不同的区域。并非所有建筑物都有干净的数据,一些建筑物的计量数据比其他建筑物包含更多缺失值。让我们设想一个缺失数据点最少的建筑样本。

建筑样本—按作者

我们可以看到大部分的情节都大相径庭。例如,即使对于办公楼,我们也可以看到每栋建筑的用水量差异很大。这表明建筑物的区域对于每次预测可能不是很有用。

在本文的剩余部分,我们将使用 1266 号建筑的热水用量数据。这似乎很少有错误或长时间没有使用。使用各种特征和外部数据集,我们将有望创建一个具有高预测准确性的模型。在下面的单元格中,我们隔离了这个建筑样本,将样本拆分为一个训练集和一个验证集,并绘制出结果。橄榄色数据是训练数据,紫色部分是验证集。

1266 号楼热水使用情况—作者

一年中热水使用量似乎有 8-10 次高峰。这可能是由于低温、特殊事件或其他完全不同的原因。还有 10–20 分的建筑热水使用量,这可能表示假期、周末或错误。这些初步的想法不能仅用可视化来证实或否认,我们将需要在开发模型时进行进一步的探索。

我们现在将使用数据中基于时间的特征来查看潜在的季节性。我们可以在 Matplotlib 中创建支线图,并获取每个可能特征值的平均计量热水用量。

潜在季节性—按作者

与下午时段(PM)相比,上午时段(AM)似乎使用了更多的热水。有趣的是,周日的热水用量似乎比一周中的任何一天都要高。星期几、星期几和其他特征可能是重要的,或者它们可能只是噪声,但是我们不能仅从可视化中确定这一点。

基线 LGBM 模型

通过单独使用这些特征,我们可以生成一个基线 LGBM 模型。LGBM 是一个基于决策树算法的梯度推进框架。这个框架不同于 XGB,因为它的树模型是逐叶增长的,而不是逐层增长的。这导致更快的训练时间和相当的准确性。欲了解更多关于这些模型之间的差异,请查看本文。

然后,我们可以使用训练好的模型来预测验证集中每个小时的热水用量,并用真实标签绘制预测结果。图标题还显示了预测的 RMSE(均方根误差)。这将为我们提供一个具体的度量标准,用于度量模型的准确性。请注意,我们还没有进行 n 步预测,我们纯粹是使用从时间戳特性设计而来的特性。

基线 LGBM RMSE:~ 59.9——作者

假期数据

在下一节中,我们将使用美国假日数据的外部数据源(CC0:公共域)。这可能是解释热水需求低谷的有用特征,并可能提高模型的准确性。将这些数据合并到训练集中后,我们将更新模型并进行新的预测。

LGBM w/ Holiday RMSE:约 59.9 英镑——作者

这个模型比以前的 RMSE 提高了 0.0041。这是一个相当不起眼的改进,但是我们现在将保留这个特性,以防它与我们在下一节中添加的其他特性结合起来很有价值。

气象资料

我要添加的第二个数据源是来自 ASHRAE 数据集(CC0:公共领域)的天气数据。这提供了离数据集中的建筑物最近的塔的实时历史天气测量值。

我们必须小心,因为我们的数据来自实时测量,而不是 10 小时的预测。如果我们只是简单地使用这种天气信息作为一个功能,我们将犯数据泄漏!因此,我们将通过向每一列添加少量高斯噪声来模拟天气数据中的误差。这将使模型更少依赖于天气数据,更不容易过度拟合。

然后,我们可以用添加的特征来拟合 LGBM 模型,对新预测的 RMSE 进行评分,并根据其真实值绘制预测。

LGBM w/ Weather RMSE:约 41.8 英镑——作者

哇!与上一次迭代相比,RMSE 显著增加了约 20 个点。因为我们在这个模型的迭代中增加了 7 个特征,所以不容易看出哪个特征对准确性的提高贡献最大。幸运的是,LGBM 模型本身就具有特性重要性。在下面的图中,我们将每个特征的重要性形象化。我们可以看到,所有 7 个特征对模型都很重要,但海平面气压、气温和风向的影响最大。

要素重要性图-按作者

ARIMA 模型

最后,我们将在预测中加入一个 ARIMA 模型。在现实世界中,在单一时间点对未来 750 小时进行预测是没有意义的。你更有可能提前 n 小时预测一个数据点。你做的预测越靠前,它就可能越不准确。

进行 n 步预测的一个好处是,您可以将更多的本地化信息合并到您的模型中。我们将通过集成 LGBM 模型和 SARIMA(季节性自回归综合移动平均)模型来实现这一点。萨里玛是基于 ARIMA 模型架构,但它纳入了季节性的组成部分。基于 ARIMA 的模型是时间序列预测的黄金标准,可以产生准确的预测。

在下一个单元格中,我们迭代地对整个验证数据集进行 10 步预测,然后观察 SARIMA 本身的表现。

萨里玛模型 RMSE: ~38.7 英镑——作者

时间序列预测的黄金标准再次来袭!该模型的 RMSE 约为 38,比 LGBM 模型高出近 3 个百分点。

有人可能会认为放弃 LGBM 模型是正确的,但是我们可以通过组合这两个模型来获得更好的模型精度。集成是指将多个模型的平均预测值进行组合,得出最终预测值。这通常会提高模型精度并减少过度拟合。

RMSE LGBM-SARIMA 合奏:~ 32.3——作者

哇!我们将 SARIMA 模型的 RMSE 提高了约 7 个点,将 LGBM 模型的提高了约 9 个点。这是一个重大的改进,展示了集成学习的力量。

最后的想法

集成学习在 AI/ML 中与在现实世界中一样强大。在现实世界中,当你和一群不同的人一起解决一个问题时,你可能会创造出更有效的解决方案。这是由于每个小组成员的独特经验和不同的技能组合。这和集成学习没什么区别。通过组合不同的模型架构和特性组合,您可以创建一组不同的预测。

如果你想了解更多信息,我在下面提供了一些额外的资源。这篇文章的代码可以在这里找到。

资源

  1. 集成学习维基
  2. 时间序列预测 w/ ARIMA、SARIMA 和 SARIMAX
  3. LGBM 文件
  4. StatsModels 文档

基于 SQL 的雪花时序预测

原文:https://towardsdatascience.com/time-series-forecasting-in-snowflake-using-sql-6ce7cedce862

需求预测、供应链和库存管理、财务规划对企业运营非常重要。Modelstar 让您在雪花中做到这一点,只需一行 SQL。

博客输出概述。图片作者。

什么是时间序列预测及其用例?

时间序列预测是一种基于历史时间采样数据预测值的技术。

预测是企业管理的基础https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#sales-forecasting-is-rudimentary-for-business-management

预测可以帮助公司在供应链管理、库存管理(关于补货数量和时间)、财务规划、产品路线图和招聘策略等方面做出正确的商业决策。有了准确及时的预测结果,企业管理层可以更好地了解如何分配资源或利用顺风。

预测的技术挑战

预测是时间序列分析的一种应用。有几个组件需要考虑:

  • 季节性:随时间的周期性变化。例如:寒暑假是每年一次,或者每天早上喝更多的咖啡。
  • 趋势:持续的非周期性变化。例如:过去 5 年公司销售额的增长。
  • 破坏性事件:突然的变化。它可能由可预测的因素(如假期或服务维护)和不可预测的问题(如随机错误或缺陷)共同驱动。

一个好的预测算法应该捕获大部分成分,并在统计上以一定的置信度做出预测。

实施的技术挑战

Python 有丰富的生态系统来实现机器学习和预测算法。雪花的新 Snowpark 功能将 Python 引入您的数据仓库,使用 UDF 在 SQL 中运行 Python,这是您可以对数据执行的转换的游戏规则改变者。但是,如果您想要实施一个端到端的解决方案来执行预测,这可能会令人望而生畏并且非常耗时。 Modelstar 通过提供一个简化的解决方案将 Python 的强大功能引入 SQL,解决了这个问题。

Modelstar 是一个开源项目,建立在最近推出的雪花功能上,比如 Snowpark。它在雪花计算中自动处理依赖关系、模型人工制品和文件 I/O。

用于预测的 SQL 1-liner

Modelstar 让您可以发送和管理预测模型,并在雪花中用一行 SQL 可视化建模结果。在幕后,Modelstar 提供了预构建的预测算法,并将它们作为 SQL 存储过程公开在您的数据库中。在这个例子中,我们将使用univariate_time_series_forecast ( API 文档)。这个 API 基于一个开源库 Prophet ,这是业界使用最广泛的预测算法之一。

本教程提供了建立时间序列预测模型和报告的步骤。它包括:

  • 基本概念:关于销售预测用例及技术。
  • Modelstar CLI 工具:Modelstar 安装指南
  • univariate_time_series_forecast SQL 语法:进行预测的 SQL 1-liner
  • 预测报告:可供业务团队使用的预测结果

在本示例结束时,您将知道如何在雪花内部训练预测模型,并生成显示模型性能的报告,如下所示:

我们的产出报告。图片作者。

SQL ML 之旅的准备https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#preparation-for-the-sql-ml-journey

如果您是第一次使用 Modelstar,这是一个安装 Modelstar 的快速入门指南。

第一步:安装型号之星https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#step-1-install-modelstar

$ pip install modelstar

提示:我们建议使用虚拟环境来管理依赖关系。下面是如何开始的快速概述: Python 环境

通过快速版本检查来验证安装:

$ modelstar --version

这应该会在您的终端中显示版本号。

步骤 2:初始化一个模型星项目https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#step-2-initialize-a-modelstar-project

$ modelstar init forecast_project

提示: modelstar init <project_name> 是基本命令,其中<project_name>可以替换为您选择的名称。

现在你会看到一个forecast_project文件夹创建在你的工作目录中。

步骤#3:配置雪花会话https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#step-3-config-snowflake-session

forecast_project文件夹中,找到文件modelstar.config.yaml,用你最喜欢的编辑器打开它。向其中添加您的雪花帐户信息和凭据。随意用任何名称命名会话。在这个例子中,我们使用snowflake-test。该文件中的凭证用于连接到您的雪花数据仓库。(注意:不要将 modelstar.config.yaml 文件提交到您的 CI/CD 版本控制中。)

# ./modelstar.config.yaml
# MODELSTAR CONFIGURATION FILE
---
sessions:
    - name: snowflake-test
      connector: snowflake
      config:
          account: WQA*****
          username: <username>
          password: <password>
          database: MODELSTAR_TEST
          schema: PUBLIC
          stage: test
          warehouse: COMPUTE_WH

注意:请在您的雪花仓库数据库中创建阶段,并在配置中指定它。

第四步:Ping 雪花https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#step-4-ping-snowflake

我们现在可以从您的终端启动 Modelstar 会话。在新生成的 Modelstar 项目的目录中(在我们的示例中,它是./forecast_project/),运行以下命令:

$ modelstar use snowflake-test

提示: modelstar use <session name>是命令,如果你给了另一个会话名,用那个来代替<session name>

一次成功的 ping 应该会导致如下结果:

控制台输出。图片作者。

第五步:将预测算法注册到雪花https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#step-5-register-the-forecast-algorithm-to-snowflake

Modelstar 提供了现成的预测算法,并管理该算法的依赖关系,因此您不必这样做。要使其在您的雪花仓库中可用,请运行以下命令:

$ modelstar register forecast:univariate_time_series_forecast

成功消息如下所示:

控制台输出。图片作者。

步骤#6:将样本销售数据上传到雪花(可选,如果您使用自己的数据集)https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#step-6-upload-sample-sales-data-to-snowflake

如果您想在示例销售数据集上尝试预测算法,请运行此命令在您的数据仓库中创建一个数据表。如果您想使用自己的数据,可以跳过这一步。

$ modelstar create table sample_data/time_series_data.csv:TS_DATA_TABLE

该命令将time_series_data.csv文件上传到雪花并创建一个名为‘TS_DATA_TABLE’的表。在这里找到更多关于这个 API 的信息。

使用 SQL 1-linear https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#build-a-forecast-model-using-a-sql-1-linear构建预测模型

在雪花工作表 https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#run-this-script-in-a-snowflake-worksheet 中运行该脚本

在 Snowflake 中使用以下命令来构建预测模型(下面的示例使用了在步骤#6 中上传的样本数据):

CALL UNIVARIATE_TIME_SERIES_FORECAST('TS_DATA_TABLE', 'DS', 'Y', 40, 'M');

意思是:根据TS_DATA_TABLE表中的历史数据预测Y值的下一个40 M(月),其中DS为时间列。

雪花雪景。图片作者。

对您自己的数据运行预测算法https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#to-run-the-forecasting-algorithm-on-your-own-data

在幕后,预测算法作为存储过程在雪花内部运行。它采用以下参数:

要配置您自己的预测周期,请查看该 API 文档以获取设备别名的完整列表。

检查结果https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#check-the-result

模型训练完成后,在雪花结果窗口中,一次成功的运行应该会输出如下所示的 json 字符串:

{
    "return_table": "RESULT_UNIVARIATE_TIME_SERIES_FORECAST",
    "run_id": "3NvQXnHQqUdYG4Fu"
}

表示已经创建了一个名为“RESULT _ UNIVARIATE _ TIME _ SERIES _ FORECAST”的表来物化预测数据,运行 id(“3 nvqxnhqkudyg 4 fu”)可以帮助您拉取预测报告。

查看预测数据表

让我们使用以下命令检查运行的结果表:

SELECT * FROM RESULT_UNIVARIATE_TIME_SERIES_FORECAST;

表格中有 4 列:

  • DS ( datetime):日期时间
  • Y_FORECASTYHAT_LOWERYHAT_UPPER (float):预测值的均值、下键和上键(其含义参见术语表部分的Uncertainty Intervals)。

雪花雪景。图片作者。

检查预测报告

使用 Modelstar 自动生成一份报告,其中记录了有关运行的信息,以及机器学习工件。要检查报告,只需在本地计算机上运行以下命令:

$ modelstar check <run_id>

您的终端应该会显示以下消息:

如前所述,一份报告将出现在您的浏览器中:

模特之星报道。图片作者。

报告里有什么https://modelstar.io/docs/tutorials/sales-forecasting-inside-snowflake/#whats-in-the-report

该报告包括 3 个部分:

  • 本次运行的元信息

  • 预测图:检查建模质量和预测结果。

模特之星报道。图片作者。

  • 组件分析:为了说明趋势和季节性,您的模型已经“学习”了,包括总体趋势,以及每年和每周的季节性(超过 1 年/周的周期模式)。

模特之星报道。图片作者。

词汇

样本内和样本外预测: 通过样本内预测,可以检查预测模型与实际数据的拟合程度。样本外预测显示对未来的预测。

不确定区间: 上下界之间的区间。这意味着真实值有 80%的概率落在该区间内。更高的确定性要求导致更宽的频带(参见 巴托兹的文章 )。不确定性也随着我们走向更远的未来而增长,导致作为时间函数的带宽变宽。

结论

预测是商业管理的基础。我们的目标是为雪花提供预测功能,以训练机器学习模型并使用它进行预测。我们只用一行 SQL 就实现了所有这些。与此同时,还会生成一个运行报告,其中包含运行的详细信息以及预测分析。这是由 Modelstar 实现的。

查看 Modelstar 的 GitHub 库:这里 ,star 它将会在最新更新。如果您的用例出现了 bug、问题或功能请求,请联系Github或在Github上打开问题。

飞镖使时间序列预测变得简单

原文:https://towardsdatascience.com/time-series-forecasting-made-easy-with-darts-3be0b8ba02f4

一个用于时间序列预处理和预测的开源包,具有统一和用户友好的 API

科林·伯伦斯来自的图片

时间序列预测涉及基于历史时间戳数据的模型构建,以进行科学预测并推动未来的战略决策。时间序列预测在各个领域都有很多用途,包括:

  • 预测消费者对每种产品的需求
  • 医疗保健中疫情传播、诊断、药物和规划的预测
  • 异常检测、网络安全和预测性维护
  • 预测当前的基础设施能否处理近期和远期的流量

还有很多。

时间序列预测与传统的机器学习用例略有不同,因为它涉及到在特征工程和建模过程中必须考虑的数据的时间顺序。

动机:

为了训练一个时间序列预测模型,您最终会遇到这样的情况:使用熊猫进行预处理,使用 statsmodel 进行季节性和统计测试,使用 scikit-learn脸书先知进行预测,并使用定制代码来实现回溯测试和模型选择。

由于不同的库有不同的 API 和数据类型,端到端的时间序列预测对数据科学家来说是一项单调乏味的任务。对于传统的机器学习用例,我们有 scikit-learn 包,它为端到端的机器学习建模提供了一致的 API。

Darts 试图成为时间序列的 scikit-learn,其主要目标是简化整个时间序列预测方法。在本文中,我们将讨论 darts 包及其实现。

飞镖:

Darts 是一个 Python 库,可以轻松操作和预测时间序列。它提供了各种模型的实现,从 ARIMA 等经典模型到深度神经网络,这些模型的实现方式与 scikit-learn 模型相同(使用 fit 和 predict APIs)。

Darts 包的一些特点是:

  • 它是围绕不可变的 TimeSeries 类构建的
  • 它有一个统一且用户友好的类似 scikit-learn 的 API 接口,如 fit()和 predict()
  • 它提供了从经典模型到最先进的 ML/DL 方法的各种模型
  • 它为端到端时间序列预测用例提供 API,包括数据发现、数据预处理、预测以及模型选择和评估。

(来源),Dart 包概述

用飞镖预测:

此外,让我们讨论、探索和实现从 1949 年到 1960 年每月航空乘客数据集的航空乘客数据集 ( 开源)的 Darts 包的基本功能。

读取时间序列:

读取航空乘客数据集,将其拆分为训练和验证数据,并进一步可视化。

(图片由作者提供),可视化培训和验证数据

预测:

Darts 提供了各种经典和先进的时间序列建模技术的实施,包括 ARIMA,西塔,指数平滑,N-Beats,脸书先知等。

跟随 darts.models 文档来了解每个实现的更多信息。

(图片由作者提供),可视化训练、验证和预测数据

评估和调整:

Darts 提供了计算模型性能的实现,并调整估计器的超参数以获得优化的模型。

高级功能:

  • 除了经典的时间序列模型,Darts 还提供最先进的现代 ML/DL 功能。
  • 概率预测
  • 针对多个系列和大型数据集的培训
  • 支持多维系列。可以对多维时间序列数据执行 n 拍建模。
  • 包括外部过去和未来数据。过去和未来的协变量数据可以在模型训练期间传递,以提高模型性能。

结论:

Darts 是一个方便的包,它提供了用户友好的现代 ML 实现,专门针对时序用例。

Darts 包的局限性可能是静态协变量、AutoML 实现、异常检测和预训练模型的不可用性。

参考资料:

[1]飞镖文档:https://unit8co.github.io/darts/#

[2]航空客运数据(开源许可):https://www.kaggle.com/datasets/rakannimer/air-passengers

感谢您的阅读

电力消费的时间序列预测

原文:https://towardsdatascience.com/time-series-forecasting-on-power-consumption-273d56768b99

本文旨在利用时间序列分析来预测摩洛哥泰图安市的电力消耗

马太·亨利Unsplash 上拍照

介绍

该项目的目标是利用时间序列分析来预测摩洛哥 Tétouan 市 10 分钟内的能源消耗。

语境

根据 2014 年的人口普查,泰图安是摩洛哥的一个城市,人口 38 万,面积11570km。这座城市位于该国的北部,面向地中海。夏天的天气特别湿热。

根据国有 ONEE “国家电力和饮用水办公室”的数据,摩洛哥 2019 年的能源生产主要来自煤炭(38%),其次是水电(16%)、燃油(8%)、天然气(18%)、风能(11%)、太阳能(7%)和其他(2%) [1]。

鉴于对不可再生资源的高度依赖(64%),预测能源消耗可以帮助利益相关者更好地管理采购和库存。最重要的是,摩洛哥的计划是通过增加可再生能源的产量来减少能源进口。众所周知,像风能和太阳能这样的能源存在一年到头都不可用的风险。从一个中等城市开始,了解该国的能源需求,可能是规划这些资源的进一步举措。

数据

公共服务运营商 Amendis 的监控和数据采集系统( SCADA )负责收集和提供项目用电数据。配电网由 3 个区域站供电,即:Quads、Smir 和 Boussafou。三个区域电站为城市的三个不同区域供电,这就是为什么我们有三个潜在的目标变量。

你可以在这个链接【2】【3】找到的数据,有从 2017 年 1 月 1 日开始,一直到同年 12 月 30 日(不是 31 日)的 10 分钟窗口中的 52,416 能耗观测。一些功能包括:

  1. Date Time:十分钟的时间窗口。
  2. Temperature:天气温度,单位为摄氏度
  3. Humidity:天气湿度百分比
  4. Wind Speed:风速单位为千米/小时
  5. Zone 1 Power Consumption单位为千瓦(KW)
  6. Zone 2 Power Consumption单位为千瓦
  7. Zone 3 Power Consumption单位为千瓦

代码部署

导入数据集

几乎每个数据科学项目的第一步都是导入我们将使用的数据集以及第一部分所需的库。

项目的数据导入和 EDA 部分需要的库当然是PandasNumPy,以及MatplotlibSeaborn

#Importing libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

我们可以使用下面的链接直接从 UCI 机器学习库加载数据。如果您在浏览器上搜索相同的链接,它会启动文件的下载。

# Load data from URL using pandas read_csv method
df = pd.read_csv('[https://archive.ics.uci.edu/ml/machine-learning-databases/00616/Tetuan%20City%20power%20consumption.csv'](https://archive.ics.uci.edu/ml/machine-learning-databases/00616/Tetuan%20City%20power%20consumption.csv'))df.head()

使用命令df.head(),我们可以可视化数据集所有列的前 5 行。我对它们进行了重新命名,以便在下面的章节中能够容纳它们。

|    | DateTime      |   Temp |   Hum |   Wind |
|---:|:--------------|-------:|------:|-------:|
|  0 | 1/1/2017 0:00 |  6.559 |  73.8 |  0.083 |
|  1 | 1/1/2017 0:10 |  6.414 |  74.5 |  0.083 |
|  2 | 1/1/2017 0:20 |  6.313 |  74.5 |  0.08  |
|  3 | 1/1/2017 0:30 |  6.121 |  75   |  0.083 |
|  4 | 1/1/2017 0:40 |  5.921 |  75.7 |  0.081 |

我们注意到每个特征只呈现出数值,因此我们可以假设一个潜在的预测任务将需要回归技术而不是分类。

|    |   Diff Fl |   Zone 1 PC |   Zone 2 PC |   Zone 3 PC |
|---:|----------:|------------:|------------:|------------:|
|  0 |     0.119 |     34055.7 |     16128.9 |     20241   |
|  1 |     0.085 |     29814.7 |     19375.1 |     20131.1 |
|  2 |     0.1   |     29128.1 |     19006.7 |     19668.4 |
|  3 |     0.096 |     28228.9 |     18361.1 |     18899.3 |
|  4 |     0.085 |     27335.7 |     17872.3 |     18442.4 |

由于数据集的索引是数字形式的,我可以使用DateTime列作为我的索引,这对于图表绘制来说会更容易。

#transforming DateTime column into index
df = df.set_index('DateTime')
df.index = pd.to_datetime(df.index)

命令df.set_index()允许我们用DateTime列替换当前索引,命令pd.to_datetime()将新索引的格式变为可读格式。

探索性数据分析

我们现在可以专注于数据探索可视化。

让我们从使用 seaborn 绘制一个相关矩阵开始。相关矩阵向我们展示了数据集中每个要素与其他要素之间的单一相关性。一般来说,相关性可以是:

  • <0.3 and therefore 虚弱
  • 介于 0.3 和 0.6 之间,因此适中
  • 介于 0.6 和 0.9 之间,因此
  • 0.9 极强

另一方面,符号表示两个因子是同向增长还是反向增长。相关性-0.9 表示随着一个变量增加,另一个变量减少。但是,根据环境的不确定性,范围可能会发生变化。在定量金融中,0.3 或 0.4 的相关性可以被认为是强相关性。

特征相关矩阵-按作者分类的图片

我们来分析一下与功耗相比,这些因素的总体趋势:

  • Temperature与所有用电区域正相关。更多地使用空调可能是对此的一种解释。
  • 另一方面,Humidity显示了与所有三个区域的功耗的轻微负相关
  • Power Z1Power Z2Power Z3相互之间呈现出高相关性。这表明所有地区的消费模式略有不同,但它们都趋向于同时增加和减少。

特征创建

从这一点开始,我从由 Kaggle 的大师 Rob Mulla 出版的 Kaggle 笔记本中获取了大部分代码,并根据我的情况进行了修改。我绝对推荐看一看他的伟大作品。

如标题所示,结合 EDA 的特征创建代表第三步。在时间序列分析和预测中,“时间”可能是你可以支配的唯一特征,所以最好从中提取尽可能多的信息。下面的函数从DateTime索引中创建列。

例如,在时间1/1/2017 0:10,命令df.index.hour将提取值 0,因为现在是午夜。df.index.dayofweek将显示 6 为 2017 年 1 月 1 日是星期天(从 0 开始计数),以此类推。

通过在我们的df上运行函数create_features,我们立即创建了函数中定义的所有特性

def create_features(df):
    """
    Create time series features based on time series index.
    """
    df = df.copy()
    df['hour'] = df.index.hour
    df['dayofweek'] = df.index.dayofweek
    df['quarter'] = df.index.quarter
    df['month'] = df.index.month
    df['year'] = df.index.year
    df['dayofyear'] = df.index.dayofyear
    df['dayofmonth'] = df.index.day
    df['weekofyear'] = df.index.isocalendar().week
    return dfdf = create_features(df)

此时,我们可以用方框图表示每个特性,以查看特定时间段内的最小、第 25 个百分点、平均、第 75 个百分点和最大消耗。

如果我们按小时绘制图表,我们可以看到1 区的平均消耗量比 2 区和 3 区高得多。最重要的是,所有三个地区的平均消耗量在晚上都会增加。****

2017 年全年每小时功耗(千瓦)的箱线图—图片由作者提供

不出所料,温度在白天中部时段呈上升趋势,然后在晚上下降。这就是为什么只有 50%的时间消耗和温度一起变化。随着晚上头几个小时气温开始下降,耗电量突然飙升。

2017 年全年以摄氏度为单位的小时温度箱线图-图片由作者提供

另一方面,湿度在一天中较冷的时候增加,在最热的时候减少。

2017 年全年每小时湿度百分比箱线图-图片由作者提供

简单移动平均线( SMA )是平滑我们预测的基本信息。移动平均计算时间序列中所有数据点的平均值,以便为预测算法提取有价值的信息。****

#Calculating moving averagedf['SMA30'] = df['Zone 1 Power Consumption'].rolling(30).mean()
df['SMA15'] = df['Zone 1 Power Consumption'].rolling(15).mean()

用户可以使用命令rolling(n_days).mean()指示 SMA 中包含的天数。

列车测试分离

在这个阶段,数据集可以在训练测试之间分割。在正常情况下,我们会随机选择新的记录来训练算法,并在剩下的记录上进行测试。在这种情况下,在训练和测试记录之间保留一个时序是很重要的。

70%的可用数据是从 1 月 1 日的到 10 月 10 日的,因此这将是我们的训练集,而从 10 月 2 日的到 12 月 30 日的(可用的最后一个数据点)将是我们的测试集。

您会注意到TemperaturedayofyearhourdayofweekSMA30SMA15列已经被选择作为模型的输入。在启动最终训练阶段之前,我计算了每一列的特性重要性,并排除了返回值为 0 的特性。如果你想看我应用这种技术的项目,请看一下这篇文章中更深入的解释。

我最初只选择Zone 1 Power Consumption作为目标变量,因为在这种情况下逐区域进行更有意义,因为每个区域都有其特定的电力需求。另一个解决问题的方法是创建第四列合计三个区域的能源需求。

#defining input and target variableX_train = df.loc[:'10-01-2017',['Temperature','dayofyear', 'hour', 'dayofweek', 'SMA30', 'SMA15']]y_train = df.loc[:'10-01-2017', ['Zone 1 Power Consumption']]X_test = df.loc['10-01-2017':,['Temperature','dayofyear', 'hour', 'dayofweek', 'SMA30', 'SMA15']]y_test = df.loc['10-01-2017':, ['Zone 1 Power Consumption']]

训练和测试数据集分割-按作者分类的图像

从图表中,你可以看到用电量在八月底达到峰值,并在一月份达到最低点,我再次看到温度趋势在这里发挥了重要作用。这确实是我们在模型中包含的特性之一。

预言

为了预测我们测试集中的记录,我决定使用的算法是梯度提升,我在我以前的文章中简要解释了它是如何工作的以及它做得最好。

在以下代码部分中设置的超参数中,我认为最相关的是:

  • n_estimators:XGBoost算法将尝试从训练数据中学习的学习轮数****
  • max_depth:一棵树可以拥有的最大深度,越深的树越容易造成过度拟合
  • learning_rate:或收缩因子,当创建新的树来纠正残差时,学习率(< 1.0)“减慢”模型拟合数据的能力,因此随着树的数量增加而学习
  • verbose:模型在控制台上打印结果的频率,我们在这里设置 100 为n_estimators相当高。默认值为 1。
import xgboost as xgb
from sklearn.metrics import mean_squared_error reg = xgb.XGBRegressor(base_score=0.5, booster='gbtree',    
                       n_estimators=1500,
                       early_stopping_rounds=50,
                       objective='reg:linear',
                       max_depth=6,
                       learning_rate=0.03, 
                       random_state = 48)reg.fit(X_train, y_train,         
        eval_set=[(X_train, y_train), (X_test, y_test)],
        verbose=100)

我们感兴趣的列是右边的一列,因为 RMSE 值与测试集相关联,而左边的一列与训练集相关联。您可以清楚地看到均方根误差在每次迭代中快速下降,直到在 600 个估计器阈值后达到最小值。

[0]    validation_0-rmse:32788.2     validation_1-rmse:30041.3
[100]  validation_0-rmse:1909.16     validation_1-rmse:2153.27
[200]  validation_0-rmse:902.714     validation_1-rmse:2118.83
[300]  validation_0-rmse:833.652     validation_1-rmse:2061.93
[400]  validation_0-rmse:789.513     validation_1-rmse:1952.1
[500]  validation_0-rmse:761.867     validation_1-rmse:1928.96
[600]  validation_0-rmse:737.458     validation_1-rmse:1920.88
[700]  validation_0-rmse:712.632     validation_1-rmse:1921.39
[800]  validation_0-rmse:694.613     validation_1-rmse:1920.75
[900]  validation_0-rmse:676.772     validation_1-rmse:1917.38
[1000] validation_0-rmse:662.595     validation_1-rmse:1920.73
[1100] validation_0-rmse:647.64      validation_1-rmse:1925.71
[1200] validation_0-rmse:634.896     validation_1-rmse:1927.89
[1300] validation_0-rmse:620.82      validation_1-rmse:1932.68
[1400] validation_0-rmse:609.903     validation_1-rmse:1937.36
[1499] validation_0-rmse:599.637     validation_1-rmse:1935.59XGBRegressor(early_stopping_rounds=50, learning_rate=0.03, max_depth=6,n_estimators=1500, random_state=48)

通过绘制出重要性每个特征在预测正确结果中的作用,我们可以清楚地注意到一些相关的模式。

fi = pd.DataFrame(data=reg.feature_importances_,
             index=X_train.columns,
             columns=['importance'])

两个最重要的因素是特定测量的 15 天 SMA小时。不出所料,温度预测能源消耗相对重要的唯一外部因素。正如预期的那样,初始数据集中的所有其他因素在项目的预测部分几乎不起作用,它们的重要性实际上是 0。

特征重要性 XGBoost 回归器-按作者分类的图片

一旦我将它与初始数据集合并,我们最终可以看到模型的整体性能。

y_test = pd.DataFrame(y_test)
y_test['prediction'] = reg.predict(X_test)
df = df.merge(y_test[['prediction']], how='left', left_index=True, right_index=True)

总体而言,预测遵循了冷季典型下降趋势,尽管该模型在识别 11 月和 12 月的峰值时有些困难。

实际记录与预测的全面比较—作者提供的图片

如果我们放大到 10 月的前 15 天,我们可以清楚地看到预测与该月的测试数据有多接近。

10 月 15 日的实际记录与预测对比——图片由作者提供

但是在12 月,峰值预测与实际记录相差很远。这可以在未来的模型中通过调整超参数或改进特征工程以及许多其他选项来改进。

12 月 15 天的实际记录与预测对比—作者图片

准确性度量突出了回归器的良好但不优秀的性能。 R 表示由回归模型解释的目标变量中观察到的可变性的百分比。在这种情况下, 91% 的观测数据可以用模型来解释,这是一个很好的结果。

平均绝对误差(MAE)简单计算为绝对误差的平均值。分数告诉我们,模型从实际记录中平均偏离 1354.63 KWs ,这样不好吗?就电力支出而言,每 10 分钟提供大约比所需多(或少)1300 千瓦的电力需要多少钱?下面是你如何评价它的好坏。****

均方误差 (MSE)的计算类似于 MAE,但它将平方与实际 vs 预测差相加。平均来说,我们的模型是好的,MAE 告诉我们,但是 MSE 表明这个模型可能有很大的误差。事实上,平方差倾向于通过增加加权因子来放大模型所犯的更大错误。****

最后,均方根误差 (RMSE)就是 MSE 的平方根。你会注意到 3746515.40 的平方根是 1935.59。在这种情况下,RMSE 比 MSE 有用得多。我们知道,1935 年的比 1354.63 年的 MAE 略高,这表明我们的模型平均预测得很好,但在具体记录上往往“错误”得有点多,实际值与预测值相差太远。

理想的情况是让 MAE、MSE 和 RMSE尽可能接近 0,但不是精确的 0,我们仍然希望避免过度拟合。

**r2:                      0.9101
MAE:                  1354.6314
MSE:               3746515.4004
RMSE:                 1935.5917**

结论

我希望你喜欢这个项目,并希望它对你需要做的任何时间序列分析都有用!

超参数调整特征工程是未来项目的两个主要改进领域。除此之外,部署一个简单回归器并因此将准确度分数与基准进行比较通常是一个很好的实践。****

未来任务包括收集 2018 年途安电力消耗的实际数据,并预测这些记录。

如果你想更深入地挖掘代码,这里有一个链接到一个 Kaggle 笔记本,上面有该项目的从头到尾的版本。为这个伟大的建议大声喊出来!

最后一点,如果您喜欢该内容,请考虑添加一个关注,以便在新文章发布时得到通知。如果你对这篇文章有什么要考虑的,写在评论里吧!我很想读读它们:)谢谢你的阅读!

PS:如果你喜欢我写的东西,如果你能通过 这个链接 订阅一个中等会员,那对我来说就是全世界。有了会员资格,你就获得了媒体文章提供的惊人价值,这是支持我的内容的一种间接方式!

[1] (2019).摩洛哥——能源。2022 年 9 月 25 日检索,来自国际贸易管理局 www.trade.gov 网站:https://www . Trade . gov/country-commercial-guides/Morocco-energy #:~:text = Per % 20 the % 20 state % 2d owned % 20 power,%2C%20others%20(2%20percent)。

[2] Salam,a .,& El Hibaoui,A. (2018 年 12 月)。http://archive.ics.uci.edu/ml 的 UCI 机器学习知识库。加州欧文:加州大学信息与计算机科学学院。‌

[3]萨拉姆,a .,&埃尔希巴乌伊,A. (2018 年 12 月)。电力消耗预测的机器学习算法比较:铁头市案例研究。在 2018 第六届国际可再生与可持续能源大会(IRSEC) (第 1–5 页)。IEEE。

[4] robikscube。(2022 年 7 月 5 日)。用机器学习进行时间序列预测。2022 年 9 月 29 日检索,来自 kaggle.com 网站:https://www . ka ggle . com/code/robikscube/time-series-forecasting-with-machine-learning-yt

时间序列预测:预测间隔

原文:https://towardsdatascience.com/time-series-forecasting-prediction-intervals-360b1bf4b085

满怀信心地估计未来观测的范围

目标图像—由 Afif Kusuma

在现实世界中预测是一项重要的任务。考虑预测能源需求、温度、食物供应和健康指标等等。在这些情况下获得不准确的预测会对人们的生活产生重大影响。

这就是预测间隔的用处。预测区间用于提供一个范围,在该范围内,预测可能具有特定的置信度。例如,如果您以 95%的置信度进行了 100 次预测,那么 100 次预测中会有 95 次落在预测区间内。通过使用预测间隔,您可以考虑预测中的不确定性和数据的随机变化。

加载温度数据

在本文中,我们将预测巴西圣保罗的月平均气温。数据集由 NCEI⁶和 NASA⁷.收集和策划感谢所有参与分享这个数据集的人!(许可证:CC0 —公共领域)

圣保罗皮涅罗斯——作者威尔肯·卡多萨

不幸的是,在现实世界中,数据从来都不是您想要的格式。在下面的单元格中,我们使用 Pandas 将其转换为两列。日期和温度。使用 Matplotlib 将结果数据可视化。

未清除的温度数据—按作者

在上图中,我们可以看到数据集有缺失值和错误。这些点充满了 999.9 的温度。我们可以简单地对大约 1980 年到大约 2015 年之间的 372 个数据点进行采样,其中不包含错误。在本文的其余部分,我们将使用这个数据样本。

温度数据的干净样本—作者

创建模型

我曾与许多时间序列模型,但我总是回来 ARIMA 模型。这些模型是可靠的,并且通常优于竞争模型类型(NeuralProphet、指数平滑、最后值)。

我们将使用 ARIMA 的修改版,名为萨里玛。萨里玛为 ARIMA 增加了一个滞后项,用于跟踪数据中的季节性。使用名为 pmdarima⁹的软件包,我们可以自动调整模型参数。关于 ARIMA 车型更详细的解释,请点击这里查看这篇精彩的文章

最佳 ARIMA 参数—作者

上面的单元格给出了适合我们的 ARIMA 模型的最佳订单和季节性订单。在下面的单元格中,我们就是这样做的,并在验证数据集上迭代地进行一步预测。

预测区间

方法 1: RMSFE

我们可以使用的第一种方法称为 RMSFE(均方根预测误差)。RMSFE 与 RMSE 非常相似。唯一的区别是 RMSFE 必须根据对未知数据(即验证或测试集)。

需要注意的是,只有假设验证预测的残差呈正态分布,我们才能使用这种方法。为了验证这一点,我们将使用 PP 图,并用 Anderson-Darling、Kolmogorov-Smirnov 和 D'Agostino K 平方检验来检验其正态性。

PP 图(概率对概率)根据正态分布图绘制数据样本,如果正态分布,数据点将形成一条直线。

三个正态性检验使用 p 值确定数据样本来自正态分布总体的可能性。每个检验的零假设是“样本来自正态分布的总体”。这意味着,如果得到的 p 值低于选定的α值,则拒绝零假设。因此,有证据表明数据来自非正态分布。对于本文,我们将使用 0.01 的 Alpha 值。

PP 图和正态性检验——作者

太好了!所有三个测试都返回了大于 alpha 值 0.01 的 p 值。这意味着不能拒绝零假设,并且数据点很可能来自正态分布。我们现在可以使用 RMSFE 在我们的预测中生成预测间隔。

这里的第一步是选择我们想要提供的置信度。我们希望我们的预测落在 75%、95%或 99%的预测区间内吗?我们将使用 95%的预测区间。在正态分布中,95%的数据点落在平均值的 1.96 个标准偏差内,因此我们用 RMSFE 乘以 1.96 来获得预测区间大小。如下图所示。

RMSFE 预测区间-按作者

这种方法的缺点是预测区间高度依赖于验证预测的残差。这并不是世界末日,但是预测区间很可能过度适应验证集中的变化。

方法 2: BCVR(自举交叉验证残差)

注意:BCVR 是我提出的一种理论方法!

我们姑且称这种方法为 BCVR(自举交叉验证残差)。BCVR 试图获得交叉验证和引导的好处。自举残差是一种生成预测区间的常用方法,通常与具有正态分布残差的 RMSFE 方法产生相似的结果,但在非正态残差上的表现略好于 RMSFE。此外,通过使用交叉验证,BCVR 应该生成更能代表整个数据集的残差分布。

我们可以从执行交叉验证来生成残差开始。我们随机选择一个长度在 250 到 372 点之间的训练样本,进行一步预测。然后,我们计算该预测的残差,并重复该过程 1000 次。

然后,我们可以检验残差分布的正态性。

PP-Plot BCVR 方法—作者

哦不!我们的 p 值远低于 Alpha 阈值,因此应该拒绝零假设?不用担心,我们可以使用一种叫做 bootstrapping 的技术来获得剩余方差的度量。为了做到这一点,我们采取交叉验证的残差,并执行随机抽样替换。然后,我们计算重采样集的标准偏差,并将其存储在一个数组中。我们重复这个过程几次,然后取存储的自举标准偏差的平均值/中值。

关于应该引导多少次,数学家们并没有达成共识,但是我在这个实现中使用了提前停止来减少计算需求。在下面的单元格中,我们每 200 次迭代检查一次自举样本的平均标准差。如果平均标准偏差与先前测量值的偏差不超过 0.001%,则我们终止循环。在我们的例子中,早期停止发生在第 7500 次迭代。

BCVR 预测间隔-按作者

BCVR 方法的缺点是对于一台机器来说计算量很大。幸运的是,这种方法非常适合集群计算。这意味着可以在多台机器之间分配工作负载。例如,如果我们有一个包含 10 个节点的集群,并且想要执行 1000 个引导样本,我们可以让每个节点同时执行 100 个样本。这将大大减少计算时间,并允许我们增加自举样本的数量。

RMSFE 与 BCVR

这两种方法如何比较?

BCVR 与 RMSFE 预测区间对比——作者

在这两种情况下,所有 75 个点都落在预测区间内。虽然不太可能(各有 2%的机会),但有些点非常接近边界。这两种方法的区间范围略有不同。BCVR 方法产生的预测区间范围比 RMSFE 方法稍窄(见上面 BCVR 预测区间周围的淡蓝色线)。

最后的想法

该示例表明,所提出的 BCVR 实现可用于生成更能代表整个群体的预测区间。看到它应用于不同的场景会很有趣。

这篇文章的代码可以在这里找到。

参考文献

  1. 预测:原则与实践——罗布·J·海曼和乔治·阿萨纳索普洛斯
  2. 预测值的置信区间和预测区间— Charles Zaiontz
  3. 将预测区间添加到您的预测模型中— Marco Cerliani
  4. 引导预测区间—丹·萨图普·尼尔森
  5. 常态测试的温和介绍——杰森·布朗利
  6. NCEI(国家环境信息中心
  7. 美国宇航局 GISS(戈达德太空研究所)
  8. 夏皮罗-维尔克测试—维基百科
  9. Pmdarina

用 ARIMA、萨里玛和萨里马克斯进行时间序列预测

原文:https://towardsdatascience.com/time-series-forecasting-with-arima-sarima-and-sarimax-ee61099e78f6

深入探讨时间序列预测的黄金标准

时间序列图——作者艾萨克·史密斯

时间序列预测是一个没有简单答案的难题。有数不清的统计模型声称优于彼此,但从来不清楚哪个模型是最好的。

也就是说,基于 ARMA 的模型通常是一个很好的开始模型。他们可以在大多数时间序列问题上获得不错的分数,并且非常适合作为任何时间序列问题的基线模型。

这篇文章是一个全面的、初学者友好的指南,帮助您理解基于 ARIMA 的模型。

介绍

ARIMA 模型的首字母缩写代表“自回归综合移动平均线”,在本文中,我们将把它分解为 AR、I 和 MA。

自回归分量— AR(p)

ARIMA 模型的自回归部分用 AR(p)表示,p 参数决定了我们使用的滞后序列的数量。

AR 公式-按作者

AR(0):白噪声

如果我们将 p 参数设置为零(AR(0)),没有自回归项。这个时间序列只是白噪音。每个数据点都是从平均值为 0 且方差为σ-平方的分布中采样的。这会产生一系列无法预测的随机数。这真的很有用,因为它可以作为一个零假设,保护我们的分析不接受假阳性模式。

AR(1):随机游走和振荡

在 p 参数设置为 1 的情况下,我们考虑由乘数调整的前一个时间戳,然后添加白噪声。如果乘数为 0,我们得到白噪声,如果乘数为 1,我们得到随机游走。如果乘数在 0 < α₁ < 1, then the time series will exhibit mean reversion. This means that the values tend to hover around 0 and revert to the mean after regressing from it.

AR(p)之间:高阶项

进一步增加 p 参数只是意味着进一步返回并添加更多由它们自己的乘数调整的时间戳。我们可以追溯到我们想要的那么远,但是当我们追溯到更远的时候,我们更可能应该使用额外的参数,例如移动平均线(MA(q))。

移动平均线— MA(q)

"这个分量不是滚动平均值,而是白噪声中的滞后."—马特·索斯纳

马(q)

MA(q)是移动平均模型,q 是预测中滞后预测误差项的数量。在 MA(1)模型中,我们的预测是一个常数项加上前一个白噪声项乘以一个乘数,再加上当前的白噪声项。这只是简单的概率+统计,因为我们正在根据以前的白噪声条件调整我们的预测。

ARMA 和 ARIMA 模型

ARMA 和 ARIMA 架构只是 AR(自回归)和 MA(移动平均)组件的组合。

ARMA

ARMA 模型是一个常数加上 AR 滞后及其乘数之和,再加上 MA 滞后及其乘数之和加上白噪声。这个等式是接下来所有模型的基础,也是跨不同领域的许多预测模型的框架。

ARIMA

ARIMA 公式—作者

ARIMA 模型是一个 ARMA 模型,但在我们用 I(d)表示的模型中包含了一个预处理步骤。I(d)是差序,它是使数据稳定所需的转换次数。因此,ARIMA 模型就是差分时间序列的 ARMA 模型。

SARIMA、ARIMAX、SARIMAX 型号

ARIMA 模型是伟大的,但在模型中包括季节性和外生变量可能会非常强大。由于 ARIMA 模型假设时间序列是平稳的,我们需要使用不同的模型。

萨里玛

萨里玛公式—作者

输入萨里玛(季节性 ARIMA)。这个模型非常类似于 ARIMA 模型,除了有一个额外的自回归和移动平均组件。额外的滞后被季节性的频率抵消(例如每月 12 天,每小时 24 天)。

SARIMA 模型允许按季节频率进行数据差异分析,也允许按非季节差异分析。通过自动参数搜索框架,例如 pmdarina ,可以更容易地知道哪些参数是最好的。

ARIMAX 和 SARIMAX

Sarimax 公式——作者

以上是 SARIMAX 模型的。这个模型考虑了外生变量,换句话说,在我们的预测中使用外部数据。一些外生变量的真实例子包括黄金价格、石油价格、室外温度、汇率。

有趣的是,在历史模型预测中,所有外生因素仍然在技术上被间接建模。也就是说,如果我们包括外部数据,模型对其影响的反应会比我们依赖滞后项的影响快得多。

代码示例

让我们通过一个简单的 Python 代码示例来看看这些模型的运行情况。

加载数据

对于这个例子,我们将使用航空乘客数据集。该数据集包含从 1949 年初到 1960 年底的航空旅行乘客人数。

该数据集具有积极的趋势和年度季节性。

一旦数据集被读取,索引就被设置为日期。这是在 Pandas 中处理时间序列数据时的标准做法,并使实现 ARIMA、萨里玛和萨里玛更容易。

单元格输出-按作者

趋势

数据随时间变化的大致方向。例如,如果我们正在观察一个新生婴儿的身高,他们的身高会随着上升趋势进入青少年时期。另一方面,减肥计划成功的人会发现他们的体重随着时间的推移呈下降趋势。

季节性+周期

任何具有固定频率的季节性或重复模式。可以是每小时、每月、每天、每年等。这方面的一个例子是,冬季夹克的销量在冬季月份增加,在夏季月份减少。另一个例子是你的银行账户余额。在每个月初的 10 天里,随着你支付每月的租金、水电费和其他账单,你的余额呈下降趋势。

不规则+噪音

这是数据中任何大的峰值或谷值。一个例子是你跑 400 米时的心率。当您开始比赛时,您的心率与一整天的心率相似,但在比赛过程中,它会在一小段时间内达到一个更高的水平,然后恢复到正常水平。

在下面的航空公司乘客数据的可视化中,我们可以找到这些组件。乍一看,数据集中似乎有积极的趋势和某种季节性或周期性。数据中似乎没有任何重大异常或噪声。

航线乘客图—作者

滚动统计

滚动平均是直观显示数据集趋势的好方法。由于数据集按月提供计数,窗口大小为 12 将为我们提供年度滚动平均值。

我们还将包括滚动标准差,以查看数据与滚动平均值的差异。

滚动统计图-按作者

增强迪基-富勒试验

扩展的 Dickey-Fuller 检验用于确定时间序列数据是否是平稳的。与 t 检验类似,我们在检验前设置显著性水平,并根据所得的 p 值对假设做出结论。

零假设:数据不是平稳的。

备选假设:数据是平稳的。

对于静止的数据(即拒绝零假设),ADF 测试应该具有:

  • p 值< =显著性水平(0.01,0.05,0.10 等。)

如果 p 值大于显著性水平,那么我们可以说数据很可能不是稳定的。

我们可以在下面的 ADF 测试中看到,p 值为 0.991880,这意味着数据很可能不是平稳的。

ADF 测试输出—按作者

ARIMA 车型选择,带自动 ARIMA

虽然我们的数据几乎肯定不是稳定的(p 值= 0.991),但让我们看看标准 ARIMA 模型在时间序列上的表现如何

使用pmdarima包中的 auto_arima()函数,我们可以对模型的最优值进行参数搜索。

模型诊断

plot_diagnostics 函数产生四个图。标准化残差、直方图加 KDE 估计、正态 q-q 和相关图。

基于以下条件,我们可以将该模型解释为非常适合。

标准化残差

残差中没有明显的模式,值的均值为零,方差一致。

直方图加上 KDE 估计

KDE 曲线应该非常类似于正态分布(在图中标为 N(0,1))

普通 Q-Q

大多数数据点应该位于直线上

相关图(ACF 图)

大于零的滞后的 95%的相关性应该是不显著的。灰色区域是置信带,如果数值超出此范围,则它们在统计上是显著的。在我们的例子中,有一些值在这个区域之外,因此我们可能需要添加更多的预测值以使模型更加准确

Arima Diagnostics —作者

然后,我们可以使用该模型预测未来 24 个月的航空乘客数量。

从下面的图中我们可以看到,这似乎不是一个非常准确的预测。也许我们需要改变模型结构,以便它考虑到季节性?

ARIMA 预测—作者

萨里玛模型

现在,让我们尝试与上面相同的策略,只是让我们使用一个 SARIMA 模型,以便我们可以考虑季节性。

看一下模型诊断,我们可以看到与标准 ARIMA 模型相比的一些显著差异。

标准化残差

标准化残差在整个图表中更加一致,这意味着数据更接近稳定。

直方图加上 KDE 估计值

KDE 曲线类似于正态分布(这里没有太大变化)。

正常 Q-Q

与 ARIMA 诊断图相比,数据点更靠近直线聚集。

相关图(ACF 图)

灰色区域是置信带,如果数值超出此范围,则它们在统计上是显著的。我们需要这个区域内的所有值。加上季节性因素就做到了这一点!所有点现在都在 95%的置信区间内。

萨里玛诊断公司

然后,我们可以像以前一样,使用该模型预测未来 24 个月的航空乘客数量。

从下面的图中我们可以看到,这似乎比标准的 ARIMA 模型要精确得多!

萨里玛预测-作者

SARIMAX 型号选择

现在让我们练习加入一个外生变量。在这个例子中,我将简单地添加月份数作为外生变量,但这并不是非常有用,因为这已经通过季节性传递了。

请注意,我们在传递到 SARIMAX 模型的数据周围添加了额外的方括号。

我们可以从下面的预测中看到,我们得到了一些非常好看的预测,并且预测置信区间的宽度已经减小。这意味着该模型对其预测更有把握。

SARIMAX 预测-按作者

结束语

请在这里找到这篇文章的代码。

用我自己的话来表达想法并实践 ARIMA 模型是最好的学习方式。希望这篇文章能激励其他人也这样做。

ARIMA 模型架构比 RNN 模型架构提供了更多的可解释性,然而 RNN 模型架构被认为能产生更准确的预测。现在我已经很好地掌握了 ARIMA 模型架构,我需要研究 LSTM 和 RNN 深度学习模型来预测时间序列数据!

延伸阅读

在整个笔记本中,我实现并改写了以下来源的想法。谢谢大家的分享!

深入探究 Arima 模型——马特·索斯纳←必读!

初学 ARIMA 的时间序列 —作者 @Arindam Chatterjee

时间序列预测的 Arima 模型 —作者 @Prashant Banerjee

StatsModels ADF 文档

去除趋势和季节性文章 —作者杰森·布朗利

贾森·布朗利温和地介绍了萨里玛

具有保形预测区间的时间序列预测:Scikit-Learn 是您所需要的

原文:https://towardsdatascience.com/time-series-forecasting-with-conformal-prediction-intervals-scikit-learn-is-all-you-need-4b68143a027a

使用 MAPIE 和 TSPIRAL 进行精确的不确定性量化

卢卡斯·乔治·温迪特在 Unsplash 上的照片

当执行时间序列预测任务时,我们习惯于开发对未来观测值进行逐点估计的解决方案。这是正确的,如果经过适当的验证,它们可能会对业务结果产生积极的影响。有可能做得更好吗?我们能通过简单地添加更多信息来提供更详细的预测吗?

用预测区间丰富我们的预测是关键。实际上,一个预测区间由几个数字表示。这些值分别是未来观测可能发生的下限和上限。未来值落在给定范围内的可能性由 0 和 1 之间的浮点数( alpha )表示。其中α接近 1 意味着我们更有信心这种情况会发生。

很容易理解在我们的预测中附加一个预测区间的附加价值。提供不确定性评估是一项古老的需求,可以通过多种方式解决。如果采用得当,所有方法都很棒,但有些方法更好。我们试着细说一下。

每个人都知道自举是一种重采样技术。常见的是将自举应用于预测残差,以获得未来预测的不确定性度量。尽管当第一次接近不确定性量化时,残差自举可能是一个很好的起点,但它可能会导致较差的性能,因为它只关注数据不确定性。不确定性的另一个来源存在。我们指的是建模不确定性。建模不确定性考虑了在训练阶段可能遇到的知识缺乏,这可能会影响预测。一个好的预测不确定性度量应该包括数据和建模不确定性

在这篇文章中,我们介绍保形预测作为一种技术来估计不确定性。具体来说,我们演示了如何在时间序列预测场景中产生预测区间。使用 tspiral ( 一个使用 scikit-learn 估计器进行时间序列预测的 python 包)结合 MAPIE ( 一个用于估计预测间隔的 scikit-learn 兼容模块),我们展示了如何解决一个时间预测任务,提供精确的不确定性估计,而不移动到 scikit-learn 生态系统之外。

设置预测

生成预测区间的第一步是选择要使用的预测模型。这似乎不太合理,但这是保形预测的主要好处之一,因为它是一种基于模型的技术(即,它可以用在任何预测算法的任何环境中)。

在这篇文章中,我们关注机器学习生态系统中采用的两种最著名的预测技术。我们指的是递归和直接预测。它们都是已知的方法,各有优缺点,可以使用 tspiral 以 scikit-learn 格式访问(要了解关于这个主题的更多信息,我建议使用我以前的一篇文章)。

模拟正弦系列分为训练、验证和测试[图片由作者提供]

让我们想象使用模拟的正弦序列生成了下面描述的预测。如何给我们的预测增加可靠的预测区间?

在测试中比较递归(蓝色)和直接(橙色)预测[图片由作者提供]

生成保形预测区间

为了解决这个问题,我们可以使用保形预测。通过研究残差的分布建立保形预测区间。没有任何秘密收据或任何魔法。

alpha = 0.95

conformity_scores = np.abs(np.subtract(y_val, y_pred_val))
estimated_distributions = np.add(y_pred_test[:, None], conformity_scores)

lower_q, upper_q = np.quantile(
    estimated_distributions, 
    [(1-alpha)/2, 1-(1-alpha)/2], axis=1
)

给定验证集上的预测值和真值,我们必须:

  • 计算绝对残差(一致性分数)。
  • 将一致性分数添加到测试预测中。这将为每个逐点测试预测生成分布(估计分布)。
  • 计算每个逐点预测分布的上限和下限分位数,以获得预测区间。

逐点递归一致性分数分布(上图)。递归一致性分数分布的分位数(较低)。[图片由作者提供]

尽管很简单,但是可以使用https://github.com/scikit-learn-contrib/MAPIE自动计算保形预测间隔。让我们看看它在递归和直接预测中的作用。

递归预测的共形区间

forecaster = ForecastingCascade(
    Ridge(), 
    lags=range(1,24+1),
    use_exog=False,
)

forecaster.fit(None, y_train)
model = MapieRegressor(
    forecaster, cv="prefit",
).fit(X_val, y_val)

forecaster.fit(None, y_train_val)
model.single_estimator_ = forecaster

forecasts = model.predict(X_test, alpha=0.05)

递归预测加上保形预测区间。[图片由作者提供]

直接预测的共形区间

forecaster = ForecastingChain(
    Ridge(),
    n_estimators=len(y_test),
    lags=range(1,24+1),
    use_exog=False,
)

forecaster.fit(None, y_train)
model = MapieRegressor(
    forecaster, cv="prefit",
).fit(X_val, y_val)

forecaster.fit(None, y_train_val)
model.single_estimator_ = forecaster

forecasts = model.predict(X_test, alpha=0.05)

在这种简单的形式中, MAPIE 可以简单地给定一个验证集和一个拟合模型(如上所述)来估计预测区间。为了提高稳健性,可以使用交叉验证的方法或更复杂的技术进行不确定性估计。

直接预报加上保形预报间隔。[图片由作者提供]

递归预测加交叉验证的共形区间

forecaster = ForecastingCascade(
    Ridge(),
    lags=range(1,24+1),
    use_exog=False,
)

model = MapieRegressor(
    forecaster, 
    cv=TemporalSplit(20, test_size=len(y_test)),
    method='base', agg_function=None, n_jobs=-1,
).fit(X_train_val, y_train_val)

forecasts = model.predict(X_test, alpha=0.05, ensemble=False)

使用交叉验证的递归预报加上保形预报间隔。[图片由作者提供]

直接预测加交叉验证的共形区间

forecaster = ForecastingChain(
    Ridge(),
    n_estimators=len(y_test),
    lags=range(1,24+1),
    use_exog=False,
)

model = MapieRegressor(
    forecaster, 
    cv=TemporalSplit(20, test_size=len(y_test)),
    method='base', agg_function=None, n_jobs=-1,
).fit(X_train_val, y_train_val)

forecasts = model.predict(X_test, alpha=0.05, ensemble=False)

使用交叉验证的直接预报加共形预报区间。[图片由作者提供]

****保形预测生成可信的预测区间,因为已经证明在估计过程中考虑了数据和建模不确定性。其他方法显示出对理清不确定性来源的良好反应(线性模型的一个例子在我以前的文章的中有报道)。然而,共形预测的适应性及其通过 MAPIE 的可达性使得该技术在接近不确定性量化时是必须的。

摘要

在这篇文章中,我们发现了保形预测在估计预测区间方面的强大功能。我们将重点放在时间序列预测任务上,为我们的预测增加预测间隔。将可信的保形预测区间添加到通过递归或直接预测生成的预测中是可行且简单的。得益于 tspiralMAPIE 的组合使用,只需使用 scikit-learn 就可以一次性完成时间序列预测和不确定性量化。

查看我的 GITHUB 回购

保持联系: Linkedin

用动力系统方法进行时间序列预测

原文:https://towardsdatascience.com/time-series-forecasting-with-dynamical-systems-methods-fa4afdf16fd0

如何使用动态系统通过标准的经典机器学习算法来预测时间序列数据

照片由约尔戈斯·恩特拉哈斯Unsplash 拍摄

时间序列预测是数据科学家在日常工作中面临的另一种任务。正因为如此,将这种工具添加到我们的工具箱中非常重要。这将是今天帖子的重点。

有很多方法可以解决这个问题,在这篇文章中,我将重点讨论一些我们可以用来将标准学习算法(如 SVM 或梯度推进)应用于时间序列数据的动力系统方法。进行这种预测的其他可能性有:

  • 预测的统计方法,如 ARIMA
  • 深度学习方法论,如 LSTM 和 RNN

首先,让我们理解为什么获取我们的时间序列数据并将其直接应用于回归变量不是一个好主意。

在我的 GitHubKaggle 中可以找到用于生成这篇文章(以及更多)结果的代码。

为什么默认算法通常不尽如人意

统计学习理论是从数学上证明我们的机器学习模型实际上具有学习能力的基础。为了让这些保证成立,必须对我们试图建模的数据进行一些假设[1],其中之一是:

  • 样品必须以 i.i.d .的方式取样

当我们处理一个时间序列时,我们的数据集的例子是相互独立的(如果是,那么你的序列可能是一个随机序列)。

因此,动力系统理论有一些方法可以用来打破我们数据点之间的时间依赖性,这样我们就可以使用标准的机器学习算法来进行预测。我们现在来谈谈多恩嵌入定理。

多恩嵌入定理

这个定理是由 Takens [2]在 80 年代提出的,它讨论了如何将我们的时间序列嵌入(从一个空间到另一个空间)其时间滞后的空间,我们称之为相位空间,消除序列实例之间的时间依赖性。

级数越确定,我们就会越清楚地看到相空间上形成的吸引子。吸引子可以被看作是时间序列在相空间上产生的“画”。例如,如果我们有一个随时间变化的周期函数,这个周期依赖将被视为相空间上的一个椭圆。请看下面的例子,当我们嵌入正弦函数时会发生什么:

正弦函数相空间表示。由作者开发。

当然,并不是所有的时间序列都是确定的,因此相空间中的吸引子不会被很好地定义。

好了,现在我们知道我们可以把我们的级数嵌入到相空间中,以消除时间依赖性,但是怎么做呢?为此,我们必须定义两个参数:

  • m ->称为嵌入维数,这个参数将告诉我们相空间的维数
  • d ->称为时间延迟,这将告诉我们相空间的每个轴将代表多少时间滞后

听起来有点抽象,对吧?让我们以方程式的形式来看,让事情变得清楚明白。

设 f(t)为我们的时间序列。给定 md ,我们的相空间嵌入将是如下矩阵:

这意味着我们空间的每一个 m 轴都将被表示为我们定义的时滞的倍数。

实现镜头的嵌入

让我们实现一些代码来将时间序列转换到我们的相空间。首先,让我们导入所需的库:

import numpy as np
import pandas as pd
import matplotlib.pyplot as pltfrom nolitsa import dimension, delayimport plotly.express as px
import plotly.graph_objects as gofrom sktime.datasets import load_airline, load_shampoo_sales, load_lynxfrom sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score, mean_squared_error
from sklearn.model_selection import train_test_splitfrom gtda.time_series import SingleTakensEmbedding, takens_embedding_optimal_parameters
from openml.datasets.functions import get_dataset

对于 Taken 的实现,我们只能使用 numpy:

def takens(data, m=2, d=1):
    emb = np.array([data[0:len(data) - d*m]])
    for i in range(1, m):
        emb = np.append(emb, [data[i*d:len(data) - d*(m - i)]], axis=0)

    return emb.T

让我们从乔托-TDA 包中得到一个洛伦兹函数:

lorenz = get_dataset(42182).get_data(dataset_format='array')[0][0:, 0]
t = [i for i in range(len(lorenz))]emb = takens(lorenz, m=3, d=5)fig = go.Figure()
fig.add_trace(go.Scatter3d(
    x=emb[:, 0], y=emb[:,1], z=emb[:, 2], mode='lines'
))
fig.show()

代码生成了以下图形:

洛伦兹函数相空间表示。由作者开发。

正如我们所看到的,我们有一个定义非常明确的吸引子,许多人称之为蝴蝶吸引子。

当然,你可能会奇怪,我怎么知道我应该为 md 使用哪些参数?洛伦兹函数已经被很好的研究过了,这些值是很多年前发现的。

然而,如果你有一个新的时间序列,你如何找到这些值?我们有一些试探法,可以用来尝试找到好的候选人。

查找 md

为了找到这些参数,我们将使用 python 的 NoLiTSA 包中的一些实现。这个软件包实现了几个非线性时间序列分析的函数和算法。如果您尚未安装此软件包,您可以使用以下软件进行安装:

pip install git+https://github.com/manu-mannattil/nolitsa.git

我们必须首先找到我们的时间延迟。为此,通常使用互信息图。该图表示时间序列中两个实例的相关程度。换句话说,它可以被看作是通过观察其他实例而获得的关于一个实例的信息量。

以下代码片段将生成正弦的互信息并绘制出来:

t = [i for i in np.arange(0, 20, 0.1)]
y = [np.sin(i) for i in t]plt.figure(figsize=(9,4))
plt.xlabel('Time delay (d)')
plt.ylabel('Mutual Information')
plt.plot(delay.dmi(y, maxtau=20))

给了我们情节:

正弦函数的互信息。由作者开发

启发式方法是选择互信息的第一个局部最小值作为时间延迟。我们可以通过使用以下代码来实现这一点:

def find_optimal_delay(x, maxtau=50):
    mi = delay.dmi(x, maxtau=maxtau)
    diffmi = np.diff(mi)return np.where(diffmi > 0)[0][0]

既然我们已经定义了时间延迟,我们可以继续研究给定时间延迟的嵌入维数。为此,我们将使用伪最近邻。

这个度量告诉我们,给定一个维度,我们的点的邻居中有多少是“假邻居”。伪邻居是在给定维度上的给定点附近的点,但是当我们将空间展开到另一个维度后,它就不再存在了。

我们可以使用以下公式绘制假最近邻的比例:

dim = np.arange(1, 10)
f1, f2, f3 = dimension.fnn(y, tau=4, dim=dim)plt.figure(figsize=(9,4))
plt.xlabel('Dimension (m)')
plt.ylabel('False Nearest Neighbors')
plt.plot(f1)

情节是:

正弦函数的假最近邻比例

在这种情况下,启发是,任何 FNN 结果小于 20%的维度都是好的候选。所以我们可以创建函数来找到它:

def find_optional_dimension(x, tau, max_dim=10):
    dim = np.arange(1, max_dim)
    f1, f2, f3 = dimension.fnn(x, tau=tau, dim=dim)return np.where(f1 < 0.2)[0][0] + 1

请注意,这些都是经验试探法,因此不能保证找到最佳值。此外,如果使用乔托-TDA 包(已经实现了 Taken)中的自动搜索,也不能保证值会匹配。

现在让我们看看如何使用所有这些来预测我们的时间序列。

用嵌入法预测时间序列

好的,这里的想法是,在嵌入完成后,我们有一个 X 矩阵,把时间序列的延迟放入一个新的空间。我们可以使用这个矩阵上的前 m-1 个条目作为我们的回归函数的特征来预测最后一列。

让我们看看这在代码中是怎样的,我们将使用一个维持集:

def forecast_on_phase_space(y, m, d, forecast_horizon):
    emb = takens(y, m, d)

    # Divide into train and test
    X = emb[:, :m-1]
    y = emb[:, m-1]

    X_train = X[:len(X)-forecast_horizon, :]
    y_train = y[:len(y)-forecast_horizon]
    X_test = X[len(X)-forecast_horizon:, :]
    y_test = y[len(y)-forecast_horizon:]

    # Fit the regressor on the training data
    rf = RandomForestRegressor()
    rf.fit(X_train, y_train)

    # Predict the test data
    preds = rf.predict(X_test)

    print(f'R²: {r2_score(y_test, preds)}')
    print(f'RMSE: {mean_squared_error(y_test, preds, squared=False)}')

    # Plot the result
    preds_ = [np.nan for i in range(len(y)-forecast_horizon)] + list(preds)
    t = [i for i in range(len(y))] fig = go.Figure()
    fig.add_trace(go.Scatter(
        x=t, y=y, mode='lines'
    ))
    fig.add_trace(go.Scatter(
        x=t, y=preds_, mode='lines', line=dict(color='red')))
    fig.show()

以下代码将生成以下预测:

洛伦兹函数预测。由作者生成。

看起来不错,对吧?让我们看看,如果我们使用一个不那么确定的真实数据集,会发生什么。为此,让我们安装 sktime 库,并使用库中免费提供的航空公司数据:

!pip install sktimeairline = load_airline()
forecast_on_phase_space(airline, 3, 1, 50)

这会产生:

航线数据集预测。由作者生成

不太好吧?嗯,我们没有对这个系列做任何类型的预处理,我们可以做很多事情来进一步改进它,但是,这将在随后的情节中探索。

现在,有人可能会问:好吧,但是如果我想从一个未知的序列中预测几个新的值,而没有延迟呢?在您的示例中,您使用了一个保持,但是在真实的场景中,我现在将有 X 来支持回归变量。预测()。

这是正确的。在真实的场景中,您需要使用您拥有的数据来预测下一个点,然后反馈它以生成新的延迟来预测下一个点。请注意,您将在每个后续预测中传播错误。这是处理时间序列的一个很大的缺点。

结论

这篇文章旨在介绍图森的嵌入定理,它可以作为一种工具来帮助时间序列预测任务。像其他方法一样,它也有一些缺点,可以改进。

我希望写更多关于我们如何对未来做出更好预测的帖子。现在,我希望这对你有用。

这里使用的每一个数据集都来自公共领域,可以在 post 上使用的开源包中免费获得。

感谢

我必须在这里感谢圣保罗大学的前教授 Rodrigo Mello,他在 2019 年的一次大学课堂上首次向我介绍了这些概念。

[1] Pagliosa,Lucas & Mello,Rodrigo .(2016).对依赖于时间的数据应用核函数以提供监督学习保证。专家系统及其应用。71.10.1016/j.eswa

[2] Takens F. (1981)在紊流中检测奇怪的吸引子。在:兰德 d,年轻的 LS。动力系统和紊流,沃里克,1980 年。数学讲义,第 898 卷。斯普林格,柏林,海德堡。https://doi.org/10.1007/BFb0091924

[3] Box,G. E. P .,Jenkins,G. M .和 Reinsel,G. C. (1976 年)时间序列分析、预测和控制。第三版。霍尔登日。g 系列。

具有特征选择的时间序列预测:为什么你可能需要它

原文:https://towardsdatascience.com/time-series-forecasting-with-feature-selection-why-you-may-need-it-696b23ecc329

在保持性能的同时加快预测速度

照片由你好我是尼克Unsplash

当第一次处理预测任务时,开始采用标准和基线解决方案是一个好的做法。在项目的第一部分,我们必须花时间了解业务需求并进行充分的探索性分析。如果我们迫不及待地要建立一个预测模型,最好的选择就是拟合天真的模型。这听起来也不错,因为它可能有助于理解数据、采用适当的验证策略或引入新奇的想法。

在这个初步阶段之后,当我们对取得的结果更有信心时,我们可以更加关注工程选择来开发最合适的解决方案。我们可以优化许多活动。从数据处理到模型推断,我们必须考虑许多方面,以使我们的解决方案发挥最佳作用。

有时,以快速有效的方式提供预测可能是一种需要。在这种情况下,我们必须配置管道,以最快的方式提供预测,同时保持足够的性能水平。从头开始重新训练模型是重要的,但不是强制性的。因为它可能不会提高性能/稳定性,所以每次我们必须进行预测时,我们都有浪费宝贵时间进行再培训的风险。重用模型和进行预测而无需强制拟合的可能性这是加速预测的第一个优势

同时,我们可以用一些简单而有效的技巧来提高预测的速度。例如,每个人都知道特征选择是一种减少预测模型输入的特征维数的技术。特征选择是大多数机器学习流水线中的重要步骤,主要用于提高性能。排出特征时,我们降低了模型的复杂性,从而减少了推理时间

在本帖中,我们展示了特征选择在减少预测推理时间的同时避免性能显著下降的有效性。为了促进和规范每个机器学习模型的预测,我开发了 tspiraltspiral 是一个 python 包,它超越了经典的递归预测,提供了各种预测技术。它与 scikit-learn 的完美集成使得基于 scikit-learn 构建的丰富生态系统也可以应用于时间序列领域。

实验设置

我们以每小时一次的频率和双重季节性(每天和每周)来模拟多个时间序列。我们还添加了一个从平滑随机游走中获得的趋势,以引入随机行为。

模拟时间序列(图片由作者提供)

该系列的最后部分用作测试集,我们在其中测量预测误差和做出预测所需的推断时间。在我们的实验中,我们模拟了 100 个独立的时间序列。我们说“独立”是因为尽管所有的系列表现出非常相似的行为,但它们并不相互关联。通过这种方式,我们对它们进行单独建模。

递归和直接预测策略都进行了测试。这些方法使用目标的滞后值作为输入来预测时间序列。换句话说,为了预测下一个小时的值,我们使用以前可用的每小时观察值,以更友好的表格格式重新排列。为时间序列预测进行特征选择与标准表格监督任务一样简单。选择算法简单地对滞后的目标特征进行操作。下面是一个使用递归预测进行特征选择的示例。

from sklearn.linear_model import Ridge
from sklearn.pipeline import make_pipeline
from sklearn.feature_selection import SelectFromModel
from tsprial.forecasting import **ForecastingCascade**max_lags = 72
recursive_model = **ForecastingCascade**(
    make_pipeline(
        SelectFromModel(
            Ridge(), threshold='median',
            max_features=max_lags,
        ), 
        Ridge()
    ),
    lags=range(1,169),
    use_exog=False
)recursive_model.fit(None, y)**selected_lags** = recursive_model.estimator_['selectfrommodel'].get_support(indices=True)

我们使用元估计量的重要性权重(线性模型情况下的系数)从训练数据中选择重要特征。这是一种简单而快速的选择特征的方法,但是时间序列的特征选择可以使用通常应用于表格回归任务的相同技术进行。

在直接预测的情况下,我们必须为每一个预测步骤安装一个单独的估计器,其过程是完全相同的。我们为每个预测步骤做出选择。每个估计器选择重要滞后的不同子集。为了汇总结果并只产生一组独特的有意义的滞后,我们选择那些更频繁选择的。

from sklearn.linear_model import Ridge
from sklearn.pipeline import make_pipeline
from sklearn.feature_selection import SelectFromModel
from tsprial.forecasting import **ForecastingChain**max_lags = 72
direct_model = **ForecastingChain**(
    make_pipeline(
        SelectFromModel(
            Ridge(), threshold='median',
        ), 
        Ridge()
    ),
    n_estimators=168,
    lags=range(1,169),
    use_exog=False,
    n_jobs=-1
)direct_model.fit(None, y)**selected_lags** = np.argsort(np.asarray([
     est.estimator_['selectfrommodel'].get_support() 
     for est in direct_model.estimators_
]).sum(0))[-max_lags:]

结果

滞后的选择与模型性能密切相关。在纯自回归背景下,如果没有额外的外生变量,滞后目标值是提供良好预测的唯一有价值的信息。使用特征选择来期望误差度量的显著改善可能过于乐观。让我们检查结果。

以表格形式预测业绩。时间以秒计算(图片由作者提供)

我们适合递归和直接方法的三种变体。首先,我们考虑过去 168 小时内的所有滞后()。然后,我们只使用周期性滞后(哑元)。最后,我们拟合我们的模型,仅考虑在训练数据上选择的有意义的滞后(过滤)

直接方法是最准确的方法。正如所料,完全方法比虚拟过滤方法更有性能。然而,差异并不明显。完全过滤方法的行为方式几乎相同。考虑到推理时间,同样的差异也存在吗?

以图形格式预测误差指标。橙色:递归预测。蓝色:直接预测(图片由作者提供)

虚拟方法是最快的方法,因为它考虑的特征数量很少。出于同样的原因,过滤方法比完全方法更快。令人惊讶的是过滤接近的速度是一个的一半。这可能是一个很好的结果,因为我们可以通过简单的特征选择以更快的方式得到好的预测。

以图形格式预测推理时间。橙色:递归预测。蓝色:直接预测(图片由作者提供)

摘要

在这篇文章中,我们利用了 tspiral 的能力,简单地使用 scikit-learn 来处理时间序列。这简化了有意义的自回归滞后的识别,并给予时间序列操作特征选择的可能性。最后,我们发现如何通过简单地应用适当的滞后选择来减少预测的推断时间。

查看我的 GITHUB 回购

保持联系: Linkedin

霍尔特·温特斯的时间序列预测

原文:https://towardsdatascience.com/time-series-forecasting-with-holt-winters-b78ffc322f24

最强大和最有用的指数平滑模型的讨论和实现

丹尼斯·德吉奥安尼在 Unsplash 上拍摄的照片

背景

在我最近的帖子中,我们一直在讨论一个非常著名的预测模型家族,指数平滑。指数平滑法的基本原理是,作为预测时间序列的一种手段,更重视最近的观测值,而不重视历史观测值。

最基本的指数平滑模型是(有趣的是)简单指数平滑也被称为单一指数平滑。该模型只是预测时间序列的水平,没有考虑趋势季节性。要了解这个模型的更多信息,请查看我之前的帖子:

这个简单模型的下一步是霍尔特的线性趋势方法,也称为双指数平滑。顾名思义,这款车型融合了潮流和水平。如果你想了解更多关于霍尔特的方法,请参考这里:

最后,霍尔特方法的下一步是找到一种将季节性纳入指数平滑模型的方法。这就是 霍尔特·温特斯 (三重指数平滑)的用武之地!

在本帖中,我们将回顾指数平滑的理论,深入研究 Holt Winters 的模型如何包含季节性的数学,最后通过 Python 中的一个真实例子。

霍尔特·温特斯模型理论

简单指数平滑重述

让我们快速回顾一下简单的指数平滑是如何工作的:

关于简单指数平滑的完整解释,请参考我以前的文章这里

作者在 LaTeX 中生成的方程。

其中【ŷ_{t+1}】是我们要预测的值, y_t 是最近的观测值, ŷ_{t-1} 是我们之前的预测, α 是平滑因子(0≤α≤1【t19)****

该组件形式的模型是:

作者在 LaTeX 中生成的方程。

这里 h 是我们预测的时间步长l _ t=【ŷ_{t+1}】明确说明这是模型的水平分量。

霍尔特线性趋势法概述

霍尔特的线性趋势模型在预测中加入了趋势成分:

作者在 LaTeX 中生成的方程。

这里 b_t 是预测的趋势,b _ { t-1 }是之前预测的趋势, β 是趋势平滑因子( 0 ≤ β ≤ 1 )。

关于霍尔特的线性趋势方法的完整解释,请参考我以前的文章这里

霍尔特·温特斯

如上所述,霍尔特温特斯模型通过在预测中加入季节性因素,进一步扩展了霍尔特的线性趋势方法。季节性的加入产生了两种不同的霍尔特温特斯模型,加法乘法

两个模型的区别在于季节性波动的大小。对于加性模型,季节性波动通常是恒定的。然而,对于乘法模型,波动与给定时间的时间序列值成比例。要了解更多关于加法和乘法时间序列模型的信息,请查看我之前的博文:

*

现在让我们回顾一下霍尔特·温特斯两个模型的方程:

添加剂:

作者在 LaTeX 中生成的方程。

其中 m 为时间序列的季节性, s_t 为季节性预测分量, s_{t-m} 为上一季度的预测, γ 为季节性分量平滑因子(0≤γ≤1α)。

如果你想了解更多关于季节性的知识,请点击这里查看我之前的博文:

乘法:

作者在 LaTeX 中生成的方程。

不去研究这些方程的麻烦,他们试图做的是计算时间序列的趋势线,并用季节变化加权趋势线上的值。

请注意,还有其他形式的包含阻尼参数的方程。我们不会在本文中涉及这些,但是感兴趣的读者可以在这里了解关于这个的更多信息。

厌倦了这些无聊的数学,让我们用 Python 实现这个模型吧!

Python 示例

我们将一如既往地使用美国航空数据集,并使用 statsmodel 库中的 指数平滑 类来拟合霍尔特温特斯预测模型。

数据来自拥有 CC0 许可证的 Kaggle

作者 GitHub 要点。

作者用 Python 生成的图。

从上面的图中我们可以看出,Holt Winters 的预测是迄今为止最好的,因为它捕捉到了时间序列的趋势和季节性。

当调用模型时,我们将参数seasonal_periodstrendseasonal传递给模型 obejct。从上面的图来看,很明显有一个年度季节性,所以我们设置seasonal_periods=12。此外,趋势并不完全是直线,所以它是乘法,因此trend='multi'。最后,季节性波动不是某个设定的一致值,而是与时间序列成正比,因此季节性是倍增的seasonal='multi'

霍尔特温特斯模型可通过制定总结方法进一步诊断:

print(model_holt_winters.summary())

由作者用 Python 生成的图片。

smoothing_levelαsmoothing_seasonalγ参数相对较高,说明季节性和水平分量变化频繁。然而,smoothing_trendβ、值非常小,意味着趋势变化不大。

总结和进一步的思考

通过讨论可能是最有用的模型,霍尔特·温特斯的模型,这将我们带到指数平滑系列的末尾。该模型同时考虑了趋势和季节性因素,因此可以有效地用于大多数时间序列的建模。如我们的 Python 示例所示,它很好地捕捉了季节性和趋势性成分。

本文中使用的全部代码可以从我的 GitHub 获得,网址是:

https://github.com/egorhowell/Medium-Articles/blob/main/Time Series/Exponential Smoothing/holt_winters.py

参考资料和进一步阅读

和我联系!

(所有表情符号都是由 OpenMoji 设计的——开源的表情符号和图标项目。执照: CC BY-SA 4.0*

基于监督机器学习的时间序列预测

原文:https://towardsdatascience.com/time-series-forecasting-with-machine-learning-b3072a5b44ba

使用监督机器学习模型的时间序列分析和预测

Unsplash 上由 Aron 视觉拍摄的照片

当我第一次看到时间序列预测问题时,我非常困惑。在那之前,我只是对表格数据做了一些监督学习预测,所以如果没有目标值,我不知道如何做预测。你们中的许多人可能都面临这个问题,所以在这篇文章中,我想介绍一种非常强大的方法来解决时间序列预测问题,使用监督机器学习模型,而不是统计模型,如 ARIMA,ARMA,MA,AR…

我决定写关于解决时间序列问题的机器学习方法,因为我相信这些模型非常通用和强大,并且它们比其他统计方法对初学者更友好。

代码可从以下链接获得:

https://github.com/unaiLopez/towards-data-science-posts-notebooks/blob/master/time series/Bike Sharing Demand Prediction.ipynb

资料组

我们将使用 Kaggle 的自行车共享需求竞争数据集,因为它非常适合本教程。您可以下载并阅读以下链接中的数据:

https://www.kaggle.com/c/bike-sharing-demand/data

时间序列分析

在使用任何模型之前,做一些时间序列分析来理解数据是很重要的。在这一步,我们将检查所有变量类型、季节性、序列是否自回归等。

首先,让我们将数据可视化:

自行车共享需求熊猫数据框架

如果我们看上面的截图,我们可以看到 dataframe 长 10886 行,宽 12 列。时间序列有一个小时周期,我们的目标变量将是计数列。该列是临时列和注册列的总和,但是为了本教程的简单起见,我们稍后将删除临时列和注册列,并且我们将只预测计数列。如果你想更好地理解数据的不同变量,你可以查看上面 kaggle 的链接,并阅读一些关于自行车共享需求竞争数据集的信息。

现在让我们检查 dataframe 的变量类型:

自行车共享需求的可变类型熊猫数据框架

除了日期时间列之外,dataframe 的所有变量都是正确的。这个变量的类型应该是 pandas 的 datetime 而不是 object。我们以后再改。

让我们来看一些关于数据框架各列的统计数据:

关于自行车共享需求的统计数据熊猫数据框架的列

截图中显示的数据对于从我们的数据中提取一些见解可能很有意思。让我们继续我们的数据分析,寻找季节性和趋势。

我们可以使用 statsmodels 的 seasonal_decompose 函数轻松地寻找季节性。该函数将我们的时间序列分解为趋势、季节性和噪声:

用于时间序列分解的自定义函数

现在,我们将使用上面的自定义函数来分解 1000 个小时的时间序列,其中包含每日季节性(周期=24 小时):

使用我们的自定义函数和 statsmodels 包进行时间序列分解

我们走吧!我们可以从上面的图表中获得很多见解。如果我们仔细观察,我们可以看到一个清晰的每日季节性模式,有两个高峰,中间有一个山谷。尽管存在这种模式,但仍有许多噪音无法用我们的日常季节性来解释,因此我们将尝试使用数据集中的其他变量和一些特征工程来对此噪音进行建模。但在此之前,让我们看看我们的数据是否是自回归的:

滞后 48 小时的时间序列的自相关图

在绘制了这个自相关图之后,我们可以非常自信地说,我们的数据是自回归的,并且我们可以使用 lags 来改善我们模型的性能。换句话说,自行车共享需求可以用前一小时和前一天的值来解释。

时间数列预测法

在了解数据并获得一些见解后,我们准备开始建模和预测每小时的自行车共享需求。在本帖中,我们将预测 1 周的自行车共享需求。这意味着,如果一周有 7 天,每天有 24 小时,我们将预测未来 168 小时的自行车共享需求。

我们将使用微软的光梯度增强机器模型。这个模型是由微软开发的,它在训练速度和准确性方面击败了标准的极端梯度增强(XGBoost)。即使我使用这个机器学习模型,你也可以在 scikit-learn 回归器或更远的地方使用任何你想要的模型。

在这种方法中,我们将从时间戳中提取新特征,并使用这些新特征来执行多输出回归:

执行特征工程

让我们看看这一特性工程流程的结果:

包含从日期中提取的新要素的数据集

一旦我们有了包含我们要使用的回归量的数据集,让我们构建一个自定义函数来预测我们的范围:

自定义训练函数和预测图

没有滞后

一旦我们定义了自定义函数,我们将使用它并检查模型的结果:

没有滞后的模型预测

在没有使用任何滞后变量的情况下,我们得到了 53 的 MAE。那一点也不差!

无滞后的模型变量重要性

如果我们根据我们的模型检查变量的重要性,小时和日期似乎非常重要,因此我们可以说我们的特征工程过程创建的特征非常有用。

但是,我们能创造更多的功能并进一步提高我们的性能吗?

有滞后

正如我们之前所说,数据似乎非常自相关,因此让我们尝试添加滞后,看看这一新功能是否能提高模型的性能:

创建新的滞后特征

如果我们看看上面的代码,我们可以看到 panda 的 shift 函数是如何帮助创建滞后功能的。让我们看看这项新功能是否能帮助我们提高模型的性能:

滞后 1 周(168 小时)的模型预测

哇!仅仅增加了一个新的滞后特征,模型精度就提高了很多。平均绝对误差从 53 降到了 32。与没有滞后功能的模型相比,这大约提高了 40%!

具有滞后的模型变量重要性

如果我们仔细观察变量重要性,滞后特征(count_prev_week_same_hour)似乎对预测我们的目标非常有用。特色工程太棒了!

结论

正如我们在这篇文章中看到的,监督机器学习模型可以非常通用,甚至在某些情况下比其他时间序列预测的统计方法更好。也就是说,我们可以得出结论,这些模型对于时间序列预测是非常强大的。尽管它们很强大,但它们需要一些功能工程才能工作,否则,它们的性能会很差。

如果你喜欢我的内容,你也可以看看我的其他帖子:

参考

https://www.geeksforgeeks.org/python-pandas-dataframe-shift/ https://www.kaggle.com/

用 Salesforce 的 Merlion 进行时间序列预测

原文:https://towardsdatascience.com/time-series-forecasting-with-salesforces-merlion-9fffd7c80ff4

用于时间序列预测的 ML 库 Merlion 简介

照片由作者拍摄。

扩展您的时序解决方案可能是一项具有挑战性的任务。幸运的是,像优步或 LinkedIn 这样的公司让他们的解决方案像 OrbitGreykite 开源。我发现的一个相对较新的是 Merlion,由 Salesforce 的研发团队开发。

它是用 Python 编写的,为时间序列预测异常检测提供了一个端到端的 ML 框架。鱼尾狮声称包括数据加载转换构建训练 模型后处理模型输出,以及评估你的预测。

鱼尾狮支持单变量多变量时间序列。该框架旨在提供一站式解决方案快速开发时序需求模型,并在多个时序数据集上对其进行基准测试。

你将从这篇文章中学到什么

这篇文章向你展示了 Merlion 为时间序列预测提供的关键特性。您将了解它的架构,并理解它的不同部分如何协同工作。

如果您对进一步的技术信息感兴趣,您可以查看鱼尾狮的最新📘文档和📑白皮书

装置

鱼尾狮配备了一系列不同的时间序列预测模型。当我安装它的时候,我面临着一些模型依赖的小挑战(见下文)。

基本上你只需要运行下面的命令 pip install salesforce-merlion

使用命令pip install "salesforce-merlion[all]"安装它所有的模型,如 lightgbm 或脸书的 Prophet

如果您是 mac 用户或遇到任何错误,请参阅📘此处了解更多详情。

请注意:我和 Prophet 和 Arima 之间有些矛盾。有所帮助的是降低了《预言家》中 pystan 和《ARIMA》中 scipy 的等级。

鱼尾狮的建筑

在深入研究代码之前,我们先来看看鱼尾狮的架构。图 1 按时间顺序展示了不同的模型,以及它们是如何协同工作的。

图一。鱼尾狮的建筑(Bhatnagar 等人,2021 年)。

在本文中,我们涵盖了除后处理块之外的所有部分,因为这一部分仅用于异常检测。

数据加载

Merlion 自带的数据结构叫做TimeSeries。该结构或类支持多变量单变量时间序列。从技术上来说,它充当了UnivariateTimeSeries系列包装

为了将数据放入所需的数据结构中,我们使用了 TimeSeries 的方法.from_pd()。这个方法需要一个带有日期时间索引的 pandas 数据帧。默认情况下,它检查每个索引是否唯一,以及是否设置了频率 freq (默认 1h )。

以下示例显示了如何从 pandas 数据框架中加载单变量时间序列。

如果我们处理一个单变量时间序列,并且面临缺失或 nan 值,Merlion 会自动删除它们和它们的相关指数。这意味着在我们将数据帧转换成鱼尾狮的数据结构之前,我们必须考虑插补

然而,当处理多元时间序列时,情况就不同了。在这种情况下,鱼尾狮带来了一个叫做对准的概念。鱼尾狮检查我们的多元时间序列是否包含任何缺失值或者每个变量的指数是否没有对齐

为了检查对齐,我们可以调用TimeSeries对象的.is_aligned属性。万一我们得到False,我们可以调用.align()方法来修复它。

默认情况下,该方法将获取任何单个变量中存在的所有时间戳的联合,并使用线性插值来估算缺失值。

切片和分割

除了方法之外,鱼尾狮还有另外两种简便的方法。

.window(t0, tf)允许在范围t0tf之间切出一个子集。这些参数可以是任何合理的日期时间格式,也可以是 Unix 时间戳。

.bisect(t)类似于.window()。它将时间序列分成左右两部分。

预处理

Merlion 提供常见的数据预处理转换技术,如最小-最大归一化、幂转换(box-cox)或指数移动平均。可以找到完整的列表📘此处

以下示例向您展示了如何在建模步骤之前使用最小-最大归一化。

请注意,也可以在模型初始化步骤中设置一个转换器。点击📘此处了解更多详情。

模型

鱼尾狮提供了一系列不同的模型:

  • ARIMA (自回归综合移动平均)
  • 萨里玛 (ARIMA,具有用户指定的季节性)
  • ETS (误差、趋势、季节性)
  • 先知(脸书先知的包装)
  • 平滑器(用于单变量时间序列预测的多尺度指数平滑器)
  • 向量自回归模型用于多元时间序列预测
  • 套袋(随机林)助推树(lightgbm)
  • LSTM

然而,也可以定义或包含您的自己的型号。你可以找到更多关于它的信息📘此处

以下示例显示了如何使用航空乘客 数据集 用 LGBM 模型进行训练和预测。

但是在我们开始建模之前,我们必须加载航空公司乘客的数据,并以正确的形状和格式将其带入。我建议确保日期时间索引频率设置正确(lines 6-9)。

将数据转换成正确的 DataFrame 格式后,我们将其转换成 Merlion 的数据结构(line 12)。在line 13中,我们简短地检查数据集是否对齐(例如,没有遗漏索引)。最后,我们可以将数据分成一个训练集和测试集(line 17)。

有了正确的数据结构,我们准备配置(lines 3-5)和初始化(line 7)我们的 lgbm 模型。在这一步之后,我们准备好拟合或训练我们的模型(line 9)并预测接下来的 6 个月(line 11)。

.forecast()方法需要时间戳来表示要做出的预测数量。因此,我们通过使用训练集.time_stamps属性来提供所需的时间戳。

为了可视化我们的预测,鱼尾狮的模型为我们提供了两种方法:.plot_forecast().plot_forecast_plotly()。下面的例子显示了如何绘制我们的预测和地面真相。

可视化应该看起来像这样(图 2)。

图二。plot_forecast 方法的结果。

坦率地说,这不是最佳性能,进一步的调整(例如,不同的参数或变换)将是必要的。然而,其目的是展示如何使用内置的可视化方法。

AutoML

谈到尝试不同的参数,鱼尾狮还附带了一个 AutoML 包。它支持:

  • SARIMA 的自动超参数选择
  • 自动季节性检测
  • 脸书先知的自动(多)季节性检测
  • ETS 的自动季节性检测

下面的例子使用了与上面相同的数据集,并展示了如何对 SARIMA 模型使用 AutoML。

类似于现有的例子,我们必须首先配置我们的 AutoML 模型(lines 3-5)。随后,我们训练我们的模型并预测未来 6 个月。与 lgbm 示例不同,我们还在lines 9-10中定义了一个train_config来加强我们的 SARIMA 模型的稳定性和可逆性。

系综和型号选择

鱼尾狮提供了两种常用的合奏技术。首先,它支持传统的系综,报告所有模型在每个时间戳预测的均值中值 。其次,它还支持自动型号选择

基于上面的数据,下面的例子展示了如何使用这些技术。下面介绍第一个传统合奏团。

我们首先配置和初始化我们的两个模型(lines 13-21)。然后我们在lines 25-27中定义系综。这里我们描述我们想要如何组合不同模型(combiner=Mean())的结果,以及哪些模型将在集合中“扮演”([lgbm,sarima])。

由于我们使用 autosarima,我们还提供了关于如何训练模型 ( lines 30-34)的集合信息。per_model_train_configs接受每个型号的字典列表。如果我们想使用默认配置,我们只需为相应的单一型号提供None。默认情况下,集合采用训练数据集的 20% ( valid_frac=0.2)进行验证。

下面的第二个例子展示了如何利用自动模型选择。与上面的例子类似,我们必须首先配置我们的两个模型(lines 13-21)。

然后我们配置模型选择器(lines 24-28)。作为一个选择标准,我们在这里设置了 sMAPE

除了 sMAPE 之外,Merlion 还支持许多其他误差指标,如 MAE 或 RMSE。完整的列表可以在📘此处

如果您需要关于时间序列误差度量的更多信息,请查看我的文章📑你应该知道的时间序列预测误差指标

存储和加载模型

如果你想存储你训练过的模型或者加载现有的模型,Merlion 的所有模型都有一个.save().load()类方法。您还可以在 modelFactory 包的帮助下加载模型,该包适用于任意模型。.save()方法在给定的路径下创建一个新的目录,其中存储了模型的配置(json)和状态(二进制)。

下面的例子显示了我们如何从上面的集合例子中保存和加载模型。

默认情况下,.save()方法会将所有已定义的模型存储在我们的集合中。在这个例子中,我们设置了save_only_used_models=True(第7行),所以我们只存储具有最佳 sMAPE 值的模型。然而,创建的配置文件包含了所有集合模型的元信息。

评估管道

最后但同样重要的是,Merlion 提供了一个非常酷的特性来模拟实时模型部署。这允许我们根据(多个)评估标准来评估我们开发的预测器的质量。模拟了以下场景:

  • 根据过去的数据训练模型
  • 以固定的间隔节奏(cadence)获取模型对某个范围(horizon)的预测
  • 定期重新训练模型(retrain_freq)
  • 可选:指定一个train_window来根据最大数据量重新训练模型

这种模拟或评估与滚动交叉验证非常相似,在时间序列建模中非常推荐使用滚动交叉验证。

下面的示例向您展示了如何使用我们在上面的示例中开发的 lgbm 模型来模拟部署场景。

由于评估器使用了to_timedelta函数,我们可以使用周、天、小时、分钟和(毫/微/毫微)秒作为单位。在本例中,我们将频率设置为90d,表示每 3 个月将使用该模型预测接下来的 6 个月(horizon = 180d)。此外,该模型每 3 个月重新训练一次(retrain_freq 90d),并使用 12 个月(train_window=360)的训练数据。

最后我们计算 RMSE 来评价我们模型的性能。

结论

试用鱼尾狮一段时间后,我对它的架构和可能性印象深刻。它评估管道是一个很好的工具,可以模拟您的模型在部署场景中的表现。此外,autoML 功能也非常支持。

在这篇文章中,我只触及了表面。我们没有深入研究如何在建模过程中使用变压器,或者如何用多元时间序列进行预测。然而,现在您应该对鱼尾狮的架构以及如何使用它有了很好的理解。请随意查看他们的文档白皮书

来源

Merlion:时间序列的机器学习库 ( GitHub )

鱼尾狮的文档 ( 链接)

巴特纳加尔公司;卡西亚尼克,p。刘;兰;杨;卡修斯河;Sahoo,d;Arpit,d;萨勃拉曼尼亚;吴;萨哈,A 杰戈塔,又名:戈帕拉克里希南;辛格,m;K. C .克里蒂卡;Maddineni,s。Cho,d;宗;周;熊;萨瓦雷塞;Hoi,s;王,H. 2021。 Merlion:时间序列的机器学习库。arXiv:2109.09265。http://arxiv.org/abs/2109.09265

使用轨道 101 进行时间序列建模

原文:https://towardsdatascience.com/time-series-modeling-with-orbit-101-f6a262c1eaf6

轨道入门教程(面向对象 - O r 面向BayesIanTime 序列预测)

图片来自 unsplash.com艾萨克·史密斯

目录

  • 什么是轨道?
  • 有哪些用例?
  • 弄脏你的手!
    -轨道模型的区别(DLT vs LGT)
    -数据
    • EDA
      -用轨道建立模型
      -更多关于回溯测试
      -进入未知——预测未来
  • 数据来源
  • 参考文献

特别感谢 Orbit 的首席开发者和建筑师 Edwin Ng 回顾了这个故事并提供了宝贵的建议。

什么是轨道?

轨道是面向对象对象对象对象对象对象对象对象对象对象对象对象对象对象对象对象对象对象对象对象对象对象对象【时间】对象对象【】对象对象【时间】对象它是一个开源的 python 包,具有面向对象的设计,使用结构化贝叶斯时间序列模型来产生时间序列推理和预测。在后端,Orbit 利用概率编程语言(PPL)如 StanPyro 进行后验近似。

Orbit Github 首页(作者截图)

与具有类似目的的其他包/接口(如 Prophet by Meta、pyro、pymc3 等)相比,Orbit 更容易实现,使用更灵活,功能更多,同时还能产生准确的估计。Orbit 提供了一个端到端的建模解决方案,包括 EDA 功能、多种类型的模型、各种后验估计方法(MAP、MCMC、SVI)、基于核的时变回归、高级特征选择方法、回溯测试功能、模型诊断和验证功能以及可视化、Orbit 主题绘图风格和调色板,并且它正在扩展。

此外,在优步内部数据和 M4 M3 的竞争数据上,Orbit 都优于流行的时间序列模型,如萨里玛先知。(关于所用模型、测试指标和数据的更多细节可以在这篇文章中找到。)这是一个高性能的软件包,将严格的统计方法和具有挑战性的业务问题联系起来。

有哪些用例?

Orbit 由优步营销数据科学团队开发,是优步营销组合模型背后的核心引擎。在优步,它主要用于对推动业务 KPI 的营销渠道的增量和效率进行公正的测量。Orbit 还可以帮助预测未来的 KPI,这是规划未来营销预算和优化不同地区和渠道的预算分配的重要组成部分。借助贝叶斯模型和动态系数,Orbit 可以优先吸收不同时间的实验结果,将提升测试与真实世界的数据相结合,并提供数据驱动的见解,帮助提高优步营销活动的投资回报率。如果你有兴趣了解更多关于营销组合模型(MMM)的知识,请查看我的另一个故事这里是关于 MMM 的非技术性介绍。

示例 MMM 结果—营销支出和贡献(图片由作者提供)

优步的其他使用案例包括支付欺诈检测和基础设施容量规划。优步的风险团队利用 Orbit 从早期检测和预防支付欺诈。优步的容量规划团队已经利用 Orbit 为工程团队规划了未来几年的计算和存储容量。

在外部,Orbit 团队还与包括 Meta、Spotify、Pinterest 在内的企业合作,解决 Orbit 具有挑战性的预测问题。

把手弄脏!

在深入研究代码之前,让我们看一下 Orbit 支持的两个主要模型:阻尼局部趋势模型(DLT)和局部全球趋势模型(LGT)。两种模型都使用指数平滑法,并将时间序列分解成不同的部分:趋势、季节性、回归和误差项。这两个模型之间的主要区别是,DLT 使用阻尼趋势因子,而不是 LGT 的混合趋势因子,DLT 引入了回归分量,这在外生回归变量已知时很有帮助。哪种模型结构在预测中表现更好取决于数据和使用情况。虽然数学不是本文的重点,但以下函数可能有助于您理解。更多细节可以在这篇文章中找到。

轨道模型的数学(表格由作者使用优步营销数据科学团队发表的论文中的信息制作)

现在让我们真的把手弄脏吧!在本教程中,我将只使用 DLT。本文中的数据和分析仅用于演示如何使用 Orbit,我并不追求学术严谨性或帮助任何数据驱动的决策。

1.数据

经济与我们所做的一切都息息相关,所以我想预测一下未来几年美国的经济会是什么样子。国内生产总值被认为是经济整体表现的良好指标。国内生产总值也是一个周期性和流行的指标,很容易从公共数据来源获得,是时间序列分析的良好候选对象。我将尝试使用 Orbit 来预测美国的实际 GDP 和其他一些被认为是经济指标的特征,包括 CPI(消费者价格指数)、失业率、短期利率(3 个月到期的国债的市场收益率)和长期利率(10 年到期的国债的市场收益率)。在数据集中,所有变量都汇总到季度级别,并进行对数转换。我从 1982 年到 2021 年总共有 160 个数据点。

数据来源 :本文中我使用的所有数据均来自经济数据聚合平台 FRED 。请看这个故事结尾的详细数据来源和引用。

2.电子设计自动化(Electronic Design Automation)

首先,让我们导入分析所需的所有模块和函数。

我从 orbit 导入了一些方便的绘图功能来做 ed a、模型诊断和 Orbit 自己的主题风格和调色板。我还导入了 DLT,我将使用的模型,以及一些用于回溯测试和计算评估所需度量的辅助函数。

导入模块的要点(作者的要点)

我们来看看数据。我的目标是真实 GDP real_gdp_log的日志版本,特征是下面变量的日志版本。

# Target
# ‘real_gdp’: real GDP# Features
# ‘dgs_3m’: short term interest rate 
# ‘gs_10y’: long term interest rate
# ‘unemp_rate’: unemployment rate
# ‘cpi’: Consumer Price Index

我的数据一览(按作者排列的表格)

Orbit 有一些方便的 EDA 功能来帮助可视化数据和检查数据模式。eda_plot模块中的warp_plot_ts可以方便地在一行代码中绘制所有变量的时间序列图。

eda_plot.wrap_plot_ts(df, 
                      date_col = 'quarter', 
                      var_list=['quarter', 'real_gdp', 
                                'cpi', 'dgs_3m', 'gs_10y', 
                                'unemp_rate']
)

变量的数据模式(按作者分类的图表)

另一个有用的 EDA 图表在同一图表中以不同的比例绘制了两个变量,这使我们能够直观地显示两个变量之间的关系,即使变量的值处于非常不同的比例,例如 GDP(非常大的数字)与失业率(范围为 0-1)。

for i in ['cpi_log','dgs_3m_log','gs_10m_log','unemp_rate_log']:
    eda_plot.dual_axis_ts_plot(df=df, 
                               var1='real_gdp_log', var2=i, 
                               fig_width=10, fig_height=3, 
                               date_col='quarter')

功能与目标(按作者分类的图表)

从图表中我们可以看到,该目标有明显的上升趋势,在 20 世纪 90 年代初、互联网泡沫破裂、2008 年大衰退和 2020 年 COVID 爆发前后有一些较大的下降。所有其他变量也有一些明显的趋势,并根据简单的相关性分析与目标高度相关。还有其他类型的 EDA 可以用于时间序列分析。为了这个故事的目的,我不会深究它们。

3.用轨道建立模型

我将我的数据分为两部分:训练和测试,测试规模为 16(我的总数据集的 10%,因为它是季度数据,所以是 4 年),并实例化了一个 DLT 模型。主要有两种估计量可供选择:‘stan-mcmc’(马尔可夫链蒙特卡罗)和‘stan-map’(最大后验概率),以及四种 global_trend_option to 可供选择:‘linear’, ‘loglinear’, ‘flat’, ‘logistic’。在对所有 8 个组合进行回溯测试后,趋势为‘linear’‘stan-mcmc’在该数据集上表现最佳。Seasonality设为 4 是因为我认为应该有年度季节性,而且我有季度数据。

使用regressor_col参数,我指定了我想要添加到模型中的所有回归量,并使用regressor_sign参数以与regressor_col相同的顺序指定了预期符号。我不确定 CPI 是否应该正面影响 GDP,因为通货膨胀可能会提振经济,所以我将其设置为‘=’,这意味着模型和数据将决定后续迹象。我设置了seed以便结果是可重复的。

实例化、拟合和预测 DLT 模型(作者要点)

拟合和预测功能与 sklearn 和其他流行的统计软件包非常相似。我将我的 test_df 传递到预测中,并将decompose指定为True,这样在预测结果中,我会将趋势、季节性和回归量组件与预测结果一起分解。

正如您在下面的预测数据框中所看到的,对于每个组件,我们也获得了平均值、95%和 5%的百分比。与许多其他软件包不同,Orbit 还提供完整的参数分布。要获得参数分布,请对训练好的模型对象使用.get_posterior_samples()。(dlt_model.get_posterior_samples())

predicted_df 的前 5 行(按作者排列的表格)

我用.get_regressor_coefs()检查了回归变量的系数。看起来这些迹象是意料之中的,失业率正在发挥更大的作用。

特征系数(作者列表)

我喜欢的两个方便的模型结果绘图函数是用于绘制分解序列的plot_predicted_components()和用于检查预测与实际的plot_predicted_data()

plot_predicted_components(predicted_df, ‘quarter’)产生以下分解系列。我们可以看到一个上升趋势,第三季度的年度季节性高于其他季度,以及 covid 导致的回归下降。

分解趋势、季节性和回归(按作者绘制)

在下面的函数中,我指定了 train_df 来提供训练期间的实际目标,predicted_df 用于预测目标,test_actual 用于测试期间的实际目标,以及 target 列和 date 列。基于这个回溯测试样本,我的预测看起来很棒,MAPE 小于 1%(平均绝对百分比误差)。

MAPE 公式(作者图片)

plot_predicted_data(training_actual_df=train_df, 
                    predicted_df=predicted_df,
                    date_col='quarter', 
                    actual_col='real_gdp_log',
                    test_actual_df=test_df)

培训和测试期间的预测与实际(由作者绘制)

具有信息先验的回归

Orbit 还支持贝叶斯时间序列建模,并允许用户使用外部信息作为回归变量的先验。例如,用户可以使用基于以前的研究、实验结果、类似产品的信息或以前模型的结果的行业基准。当与观测数据一起工作时,先验非常强大,尤其是当数据稀疏或质量低时。我们可以设置 sigma 来控制从先验到后验的变化水平。这样,模型可以利用以前从观测数据中获得的知识和信息,并且模型结果将保持在合理的范围内。

使用 regressor_beta_prior 和 regressor_sigma_prior 参数,可以很容易地将先前的 beta 和 sigma 传递给 DLT。两个参数都接受一个长度和顺序与 regressor_col 和 regressor_sign 相同的数值列表,如下例所示。我计划用一个模拟数据集写另一个关于未来使用轨道先验的故事。

使用先验知识实例化、拟合和预测 DLT 模型(作者要点)

4。关于回溯测试的更多信息

如果您想要多个回测样本或使用回测来调整超参数,来自 Orbit 的BackTester非常有用。

为了创建一个BackTester,我需要之前实例化的模型对象和完整的数据框作为输入。min_train_len定义了训练时间段的最小长度。incremental_len定义每个回溯测试样本的增量步骤。forecast_len定义回溯测试的预测长度。
window_type‘expanding’‘rolling’两个选项。'expanding’扩展窗口并为每个训练样本增加更多的训练时间,‘rolling’创建滑动窗口,训练样本保持相同大小。

# create a backtester based on the model we instantiated earlier 
backtest = BackTester(model = dlt_model, 
                      df = df, 
                      min_train_len = 100, 
                      incremental_len = 12, 
                      forecast_len=12, 
                      window_type = 'expanding')ts_splitter = backtest.get_splitter()
_ = ts_splitter.plot()

在我的例子中,第一个训练样本是我的数据中的前 100 个数据点,接下来的 12 个数据点是我的第一个回溯测试样本。然后,窗口将扩展 12 个数据点,这使我的第二个训练样本成为数据中的前 112 个数据点,然后接下来的 12 个数据点将成为我的第二个回溯测试样本,依此类推。对于我的数据长度,我有 5 个回测样本。.get_splitter()功能有助于可视化训练和回测样本分割。在下图中,蓝色表示训练样本,橙色表示测试样本。

在我们拆分数据之后,我们可以使用.fit_predict()来拟合和预测,并使用.score()来检查跨回溯测试样本平均的不同评估指标。对于不同的回测样本,该模型也表现良好。

backtest.fit_predict()
bt_predicted_df = backtest.get_predicted_df()
backtest.score()

回溯测试平均分数(按作者列出的表格)

另一个有趣的可视化多重回溯测试性能的功能是 gif maker。(这需要安装imageio包。)它生成一个很酷的 gif 图,依次展示所有样本的性能。
看起来在某些时间段,我的模型确实倾向于过度预测。作为一个潜在的下一步,我可以做一些其他的测试,如其他趋势选项,但现在我对整体结果还满意。

plot_bt_predictions2(bt_pred_df=bt_predicted_df, metrics=wmape, 
                     figsize=(16, 8), is_visible=False,
                     fig_dir='result/', export_gif=True,
                     markersize=80, imageio_args={'fps': 2.5})

使用不同回测样本的预测(图片由作者提供)

您可以使用BackTester和轨道网格搜索功能.grid_search_orbit()来调整超参数。我对默认设置的模型很满意,我不想让这篇文章太冗长,所以我没有包括这一部分。这里可以找到一个的例子。

5.走向未知——预测未来

最后,我用自己有限的知识和乐观的经济前景为这些特征创建了一个未来输入数据框架。我假设 CPI 会略有上升,因为我们一直面临着高通胀,失业率会相当平稳,因为 COVID 后,人们应该回到工作岗位,利率将在未来 4 年内增长更高。

使用相同的 DLT 函数,但拟合全部历史数据,并使用我编造的 forecast_input_df 进行预测,对未来 4 年美国实际 GDP 的预测看起来很有希望。

实例化、拟合和预测 DLT 模型(作者要点)

预测(由作者绘制)

谢谢你,并关注我更多!

感谢您阅读到目前为止,并了解轨道。我计划为 Orbit 编写更多教程,深入演示其他用例及功能。敬请关注,关注我,并订阅电子邮件以获取更多关于数据科学和其他有趣主题的故事!

数据源

参考

[1]Orbit:Orbit 开发团队使用指数平滑法进行概率预测
【2】Orbitgithub
介绍 Orbit,Orbit 开发团队在优步工程博客
【4】
上发布的用于时间序列推断和预测的开源包Bayesian 时变系数模型及其在营销组合建模中的应用Orbit 开发团队发布的
【5】Orbit 文档中心

时间序列的可预测性——协整是统计上的侥幸吗?

原文:https://towardsdatascience.com/time-series-predictability-is-cointegration-a-statistical-fluke-9aa6b9f9076e

Python 中蒙特卡罗模拟的盒条正则分解λ统计量

图片作者。

在这个故事中,我们将揭示一些关于时间序列整合的令人不安的事情,即模型过度拟合。通常,我们会将过度拟合与其他类型的模型联系在一起,但不会与整合联系在一起,毕竟,如果我们找到一个平稳的线性组合,这还不够吗?事实证明并非如此。

当我们增加用于寻找协整关系的时间序列数量时,在大多数情况下,我们看到得到的时间序列不断得到更低的 Dickey-Fuller 检验值,因此这样的时间序列越来越有可能是平稳的。

例如,如果我们使用几个布朗运动(AR(1)单位根过程),很容易得到大约-10 的 Dickey-Fuller 结果。我们无法拒绝这样一个时间序列是平稳的假设。但是 AR(1)单位根过程的非平凡线性组合也是 AR(1)单位根过程,其定义是非平稳的但不是趋势性的。

我们大多数人可能得出的逻辑是这样的,输入到模型中的序列越多,就意味着产生的时间序列是平稳的可能性越大;那么,如果我们用整个 S&P500 作为这样一个模型,会发生什么呢?我们会变得富有吗?答案大概是不会;除了试图交易如此大的投资组合的一些实际问题,我们可能会过度适应噪音。即使我们得到的投资组合在大多数平稳性测试中是平稳的,这个投资组合在样本外也很可能表现不佳。免责声明,这不是交易建议,只是举例说明一个观点。

如果你还在这里,而上述简陋的现实并没有让你对这样的模型失去所有的兴趣,那就让我们继续吧。

我们寻找协整向量所用的方法是典型分解,由 G. Box 和 G. Tiao(简称 BTCD)进行;但这里的核心论点可以代表任何一种为时间序列的线性组合寻找系数的方法,这种方法会产生一个平稳的时间序列。看看这个 BTCD 的故事,其中详细介绍了该方法以及实现它所需的所有代码。我们将使用这里概述的核心功能。

BTCD 的酷之处在于,我们还可以获得潜在的趋势关系,而不仅仅是静态关系。

目录

  • 问题设置(正式讨论)。
  • BTCD 中λ的含义(均值回复参数)。
  • 多重单位根 AR(1)过程。
  • BTCD 的蒙特卡罗模拟。
  • 累积分布函数。
  • λ的概率。
  • 把所有的放在一起
  • 结束语。

问题设置

我们想找到一个权重向量 w 来形成一个线性组合 N 时间序列的 S ,即

使得 S 是静止的(或者在 BTCD 的情况下是趋向的)。BTCD 通过建立一个模型 q 来实现这一点,该模型用于 N 维时间序列 p 使用高达 k 的先前时间滞后到 t:

其中ε是 i.i.d。

Box 和 Tiao 定义了一个他们称之为可预测性的量λ,可预测性较高意味着 S 更可能是一个趋势时间序列,而可预测性较低的 a S 更可能是一个平稳时间序列。

其中 T 上标表示矩阵转置和

我们可以通过解决一个特征值问题找到λ的最小值和最大值,更多细节请查看概述 BTCD 的主要故事全文。

λ在 BTCD 中的意义

λ量化了时间序列中均值回复的水平,它类似于奥恩斯坦-乌伦贝克过程方程中均值回复参数的倒数。

在这种情况下,较小的λ意味着更倾向于均值回复(更有可能是稳定的),而较大的λ意味着均值回复较少(更有可能是趋势性的)。

λ的问题在于它是依赖于模型的,当我们改变 N (时间序列的数量)、样本大小( T )、模型中包含的最大滞后( k )时,实际数字会改变,并且还会根据我们用来建立模型的回归方法而改变。因此,λ仅适用于相同的模型、相同的回归、相同的设置;比较不同的模型是没有用的。

那我们怎么知道λ的什么值是可接受的呢?

这就是我们在接下来的部分要做的,我们将做一些蒙特卡罗模拟,并使用结果来做一个λ统计。

多重单位根 AR(1)过程

对于我们的蒙特卡罗模拟,我们将使用 N 个布朗运动(维纳过程),因为我们知道我们不应该从这些过程的线性组合中找到除了噪声之外的任何东西。

多个单位根 AR(1)过程不能有稳定关系(协整)也不能有趋势关系,即考虑单位根过程:

其中,ε是 i.i.d .,平均值为零。这个过程是非平稳的,非趋势性的;此外,让我们假设ε的分布是标准正态分布,在这一点上,没有理由假设该分布不是标准正态分布。然后

以便

很明显, S 又是一个单位根 AR(1)过程,因为

S 的增量是独立的,它们的分布是正态分布。线性组合简单地重新调整了 S 的方差。

为了生成样本量为 T (观察次数)的 N 布朗运动:

例如:

图片作者。离散采样的多重布朗运动

BTCD 的蒙特卡罗模拟

在本节中,我们将使用主要 BTCD 故事中所示的代码,该模块公开公开一个函数、一个包含结果的数据类和一个回归模型接口(协议):

为了跟踪本节中的结果,在尝试重现下面的示例之前,将主要 BTCD 故事中的代码作为 btcd.py 保存在运行该代码的文件夹中(如果保存在其他地方,则必须更改 import 语句)。

我们的蒙特卡罗模拟包括将“n_MC”试验的 BTCD 应用于不同的随机集合的 N 布朗运动,对于每个试验,我们存储最小λ和最大λ的结果(我们丢弃所有其他λ解,因为我们只对极端平稳和趋势解感兴趣)。我们还应用 Dickey-Fuller 检验来确定除λ之外的模型之间的一些可比数量。

我们将结果存储在“LambdaSimResult”数据类的实例中,然后将该数据模型分别存储在 min λ和 max λ的“BTCDMonteCarloResult”(我们主要的面向公众的结果对象)的实例中。

让我们进行模拟。注意,如果你输入一个大的“n_MC”、大的 T 和大的 N 可能需要一段时间。

图片作者。两种 BTCD 模型设置的蒙特卡罗模拟结果直方图。

查看 Dickey-Fuller 结果,趋势关系(max λ)的结果看起来一点也不令人印象深刻。然而,静态关系(最小λ)看起来很有希望,N = 5 时约为-3.5,N = 30 时约为-10.5,T=1000。Dickey-Fuller 的结果-3.5 已经是平稳性的 99%置信度,-10.5 是 S 是平稳的实际确定性。

但是等等,我们不应该能够建立一个稳定的线性组合,记住单位根过程的线性组合也是一个单位根过程,它是不稳定的。

此外,请注意λ的范围因型号而异。我们现在要做的是将这些结果用于λ,并获得 CDF(累积分布函数),这样我们就可以根据我们的模型将概率分配给λ的值。

简而言之,如果我们观察到布朗运动的λ结果不应该是稳定的/趋势的,那么当我们将 BTCD 应用于真实数据时,使用用于运行蒙特卡罗模拟的相同模型,我们应该观察到更小/更大的λ以认真对待我们的结果,否则,我们会过度拟合噪声。CDF 会告诉我们λ应该有多大/多小,这样我们就不会拒绝这个结果。

累积分布函数(Cumulative Distribution Function 的缩写)

CDF(累积分布函数)是这样的,如果我们为λ输入一个值,它将返回一个与之相关的概率,它是一个递增函数,因此根据 CDF,更大的λ意味着更大的概率。

Statsmodels 很好地实现了经验累积分布函数(ECDF)。它是一个带有 call 方法的类,所以一旦类被实例化,它的行为就像一个函数。我们将使用 ECDF 作为蒙特卡罗数据的λ。

这就是我们蒙特卡洛模拟中试验次数“n_MC”发挥作用的地方,试验次数越多,越接近真实的 CDF。

实现这一点的代码非常简单,我们只需返回两个 ECDFs 的元组,一个用于最小λ模拟值,另一个用于最大λ模拟值。

λ的概率

在实践中,给定一些模型设置,我们将需要计算得到的“S”是稳定的或趋势的概率。

为了做到这一点,我们将把蒙特卡罗模拟和上一节的 CDF 封装在一个类中,这样我们就可以很好地简单地存储结果并重用它们。

正如我们在上一节中讨论的,CDF 是一个递增函数,这有时会导致一些令人困惑的概率。对于一些统计测试,低 p 值实际上是您正在寻找的,但对于其他测试,大 p 值是您需要寻找的。

我们将对此进行简化,使其更加直观,为概率计算分配两种类型,“稳定”和“趋势”。

对于“平稳”概率,较低的λ值实际上会导致序列平稳的概率较高。

对于“趋势”概率,较高的λ值意味着更高的趋势概率。

在任何情况下,我们得到的概率要么是稳定的,要么是趋势的,我们不必记住低 p 值是好事还是坏事。

注意,为了计算“稳定”概率,我们使用最小λ模拟结果,而对于“趋势”概率,我们使用最大λ模拟结果。

因此,使用我们到目前为止编写的所有代码,并将其包装在“BTCDProbTable”类中:

这是低代码部分,在这里我们使用我们已经建立的工具。工作流程是这样的,用你需要的模型设置实例化一些 BTCDProbTable,调用“run_simulation”方法,在你等待的时候去喝杯咖啡(或茶)(注意“n_MC”的大值,它可能需要一段时间):

然后使用“get_prob”方法计算给定模型设置的概率,例如

图片作者。OLS 和弹性网络的概率与λ、平稳和趋势。

把所有的放在一起

为了完整起见,让我们把前面几节的所有代码放在一起,这样您就可以复制、粘贴、保存它,并结合 BTCD 算法使用它:

结束语

正如单位根检验(平稳性检验)所检验的那样,我们已经看到协整方法可以产生具有高度确定性的平稳时间序列。然而,这可能会误导我们认为我们已经找到了一个真正稳定的(或趋势)关系,而事实上我们只是过度拟合了纯噪声。

在可能的情况下,对你肯定找不到任何有意义的结果的数据进行一些蒙特卡洛模拟,并用它们来比较和对比从真实数据中获得的结果。

参考

[1] G. E. P. Box 和 G. C. Tiao, (1977),Biometrika 64,2,第 355-65 页

我希望这个故事对你有用。如果我错过了什么,请让我知道。如果你想知道更多这样的故事,请关注我的媒体

https://medium.com/subscribe/@diego-barba

喜欢这个故事吗?通过我的推荐链接成为媒体会员,可以无限制地访问我的故事和许多其他内容。

https://medium.com/@diego-barba/membership

张量流中的 LSTM 时间序列预测

原文:https://towardsdatascience.com/time-series-prediction-with-lstm-in-tensorflow-42104db39340

了解如何创建基于 LSTM 的神经网络来预测单变量时间序列

阿格巴洛斯Unsplash 上的照片

在本文中,您将学习如何使用 Python 中的 Tensorflow 和 Keras 对时间序列进行预测。

我们将使用基于双向 LSTM 层在 Tensorflow 中创建的序列神经网络来捕获我们将输入到模型中的单变量序列中的模式。

特别是我们将看到如何

  • 生成合成数据模拟具有不同特征的时间序列
  • 处理训练和验证集中的数据并基于时间窗口创建数据集
  • 使用 LSTM (长短期记忆)为我们的神经网络定义一个架构
  • 训练和评估模型

本教程的目标是在给定一系列数据的情况下预测未来的某一点。不包括多步情况,即预测了前一个点,而该点又被模型预测了。

这个指南的灵感来自于 Coursera 的 DeepLearning。AI TensorFlow 开发者专精,我强烈建议任何感兴趣的读者去看看。

我们开始吧。

生成数据

我们将使用允许我们为我们的情况生成合成时间序列的函数,而不是从网上下载数据集。我们还将使用 dataclasses 将我们的时间序列参数存储在一个类中,这样我们就可以使用它们而不用考虑范围。数据类名称将为 G ,代表“全局”。

我决定使用这种方法,而不是使用真实的数据集,因为这种方法允许我们测试多个时间序列,并在项目的创作过程中具有灵活性。

让我们用这段代码生成一个合成时间序列

这是获得的系列

通过我们的功能创造的合成系列。图片作者。

现在我们有了可用的时间序列,让我们继续进行预处理

深度学习时间序列的预处理

时间序列的特点是,它们必须分为训练集和验证集,而训练集和验证集又必须分为长度由我们的配置定义的序列。这些序列被称为窗口,模型将使用这些序列生成预测。

让我们再看两个助手函数来实现这一点。

这里需要一些解释。 train_val_split 函数只是根据之前在 G 数据类中定义的 G.SPLIT_TIME 值来划分我们的序列。此外,我们将传递给它 G.TIME 和 G.SERIES 参数。

让我们回忆一下 G 数据类的定义。

用于存储和维护数据的全局数据类。图片作者。

通过调用 generate_time_series,我们得到

时间=范围(0,1439)

SERIES = array([ 0.81884814,0.82252744,0.77998762,…, -0.44389692,-0.42693424,-0.39230758])

长度都是 1439。

train_val_split 的分割将等于

time_train = range(0,1100)

time_val = range(1100,1439)

如何将时间序列分为 X 和 y。图片由作者提供。

分成训练集和验证集后,我们将使用一些 Tensorflow 函数来创建一个数据集对象,它将允许我们创建 X 要素和 y 目标。回想一下,X 是模型将用来预测下一个值(即 y)的 n 个值。

让我们看看如何实现这些功能

我们会用 Tensorflow 的。window() 方法在 dataset 对象上对我们的点应用 1 的移位。这里可以看到一个应用逻辑的例子:

如何制作窗口数据集。图片作者。

在示例中,我们使用 Tensorflow 创建了一个从 0 到 10 的范围,并应用了一个 5 的窗口。然后,我们将总共创建 5 列。传递 shift = 1 每一列将从顶部开始减少一个值,并且 drop_remainder = True 将确保您总是有一个相同大小的矩阵。

让我们应用这两个函数。

现在数据已经准备好了,我们可以继续构建我们的神经网络。

神经网络体系结构

正如文章开头提到的,我们的神经网络将主要基于 LSTM(长短期记忆)层。LSTM 之所以适合这种任务,是因为它的内部结构能够通过长序列传播信息。

这使得它们在自然语言处理(NLP)和时间序列中非常有用,因为这两种类型的任务可能需要在整个序列中传递信息。

在下面的代码中,我们将看到 LSTM 层是如何包含在一个双向层中的。该层允许 LSTM 考虑两个方向上的数据序列,因此不仅具有过去的上下文,还具有未来的上下文。它将帮助我们建立一个比单向网络更精确的网络。

除了 LSTMs,还有 gru(门控递归单元)可用于时间序列预测任务。

我们还将使用 Lambda 层,这将允许我们根据网络正确调整输入数据格式,最后使用密集层来计算最终输出。

让我们看看如何在 Keras 和 Tensorflow 中依次实现这一切。

Lambda 层允许我们在一个层中使用自定义函数。我们使用它来确保输入的维数对于 LSTM 是足够的。因为我们的数据集由二维时间窗口组成,其中第一个是 batch_size ,另一个是时间步长

然而,LSTM 接受第三维,这表明我们输入的维数。通过使用 Lambda 函数和input _ shape =【None】,我们有效地告诉 Tensorflow 接受任何类型的输入维度。这很方便,因为我们不必编写额外的代码来确保维度是正确的。

为了阅读更多关于 LSTM 和图层如何工作的信息,我邀请读者在这里查阅官方的张量流指南。

所有 LSTM 层都包含在一个双向层中,每个层都通过 return_sequences = True 将处理后的序列传递给下一层。

如果该参数为假,Tensorflow 将会给出一个错误,因为下一个 LSTM 将不会找到要处理的序列。唯一不能返回序列的层是最后的 LSTM,因为最后的密集层是负责提供最终预测的层,而不是另一个序列。

提前停止回调

正如您在文章中看到的,在 Tensorflow 中使用回调控制您的神经网络的训练,当我们的性能指标达到指定级别时,我们将使用回调来停止训练。我们将使用平均绝对误差(MAE)来衡量我们的网络正确预测系列中下一个点的能力。

事实上,这是一个类似于回归任务的任务,因此将使用类似的性能指标

让我们看看实现提前停止的代码。

模特培训

我们准备训练我们的 LSTM 模型。我们定义一个调用create _ un compiled _ model的函数,并为模型提供一个损失函数和一个优化器。

Huber 损失函数可用于平衡平均绝对误差(MAE)和均方误差(MSE)。因此,当您有各种数据或只有几个异常值时,这是一个很好的损失函数,就像在这种情况下。

Adam 优化器通常是一个有效的选择—让我们将任意的 learning_rate 设置为 0.001。

让我们开始训练吧

训练神经网络。图片作者。

我们看到,在第 20 个时期,达到了目标 MAE,训练停止。

模型评估

让我们画出损失和 MAE 的曲线。

MAE 和 loss 绘制了。图片作者。

曲线显示了网的改善,直到在第 5 个时期后稳定。还是一个不错的结果。

让我们写一个 helper 函数,方便访问 MAE 和 MSE。此外,我们还定义了一个函数来创建预测。

现在让我们看看模型的表现如何!让我们对整个系列和验证集进行预测。

让我们看看验证集的结果

对验证集的预测。图片作者。

在整个系列中

对整个系列的预测。图片作者。

结果似乎不错。也许我们有办法通过增加训练周期或调整学习速率来提高模型的性能。

mse: 30.91,mae: 3.32 预测。

预测未来新的一点

现在让我们看看,给定序列中的最后一个序列,如何预测未来的某一点。

下面是结果(修改后——图片显示 200 分)。

对未来 a 点的预测。图片作者。

结论

总之,我们已经了解了如何

  • 生成合成时间序列
  • 将系列适当地分成 X 和 y
  • 基于双向 LSTMs 在 Keras 和 Tensorflow 中构造神经网络
  • 提前停止训练并评估表现
  • 对培训系列、验证和未来进行预测

如果你有任何关于如何改善这种流程的建议,请写在评论中并分享你的方法。希望文章能对你的项目有所帮助。

推荐阅读

对于感兴趣的人来说,这里有一个我为每个与 ML 相关的主题推荐的书籍列表。在我看来,有一些必不可少的书籍对我的职业生涯产生了巨大影响。
免责声明:这些是亚马逊会员链接。我会收到亚马逊为你推荐这些项目的一小笔佣金。你的体验不会改变,你也不会被收取更多费用,但它将帮助我扩大业务规模,围绕人工智能制作更多内容。

有用的链接(我写的)

如果你想支持我的内容创作活动,欢迎点击我下面的推荐链接,加入 Medium 的会员计划

我将收到你投资的一部分,你将能够以无缝的方式访问 Medium 的大量数据科学文章。

https://medium.com/@theDrewDag/membership

感谢您的关注,很快再见!👋

简单解释为快餐套餐的时间序列问题

原文:https://towardsdatascience.com/time-series-problems-simply-explained-as-fast-food-combo-meals-70c6eb9bdef

单变量与多变量、单步与多步以及滑动与扩展窗口时间序列问题之间的区别

作者用来自平面图标的图标创建的图像

开始时间序列预测可能是势不可挡的,因为有许多变化。时间序列问题可能因输入和输出序列的数量、预测的步骤数量以及输入序列长度是静态还是可变而异。

开始时间序列预测可能是势不可挡的,因为有许多变化。

例如,您可能有一个巧克力棒的销售数据,您正试图根据过去 12 个月来预测其未来 6 个月的销售。

或者,你可以根据过去所有可用的温度和降雨量数据来预测第二天的降雪量。

在本文中,我们将复习一下不同类型的时间序列预测问题。由于时间序列问题可能是不同变化的组合,我们将使用快餐套餐的例子来展示这些变化。

所以,欢迎来到“时间系列小酒馆”!

请看看菜单,从以下类别中各选一个:

电源:输入和输出序列的数量

首先,我们将看看输入和输出时间序列的数量。这意味着您可以将单个时间序列或多个时间序列作为输入。预测输出也是如此。

我们区分单变量和多变量时间序列问题。对于多元问题公式,我们还区分了相同和不同的输入和输出序列

照片由 Pille R. PriskeUnsplash 上拍摄

单变量的

在单变量时间序列问题中,您只有一个时间序列,它既用作输入序列,也用作输出序列。

input_cols = ["chocolate_bar_sales"]
output_cols = input_cols

如果您尝试预测的时间序列与其他时间序列没有任何相关性,则可以使用此选项。

单变量时间序列问题公式化(图片由作者提供)

用例示例:根据巧克力棒的过去销售额预测其未来销售额。

投入和产出相等的多元变量

在多元时间序列问题中,可以有多个时间序列,既可以用作输入序列,也可以用作输出序列。

input_cols = ["stock_1", ..., "stock_n"]
output_cols = input_cols

当多个时间序列之间存在相关性时,通常会使用这个问题公式。

输入输出相等的多元时序问题时序问题公式化(图片由作者提供)

用例示例:根据股票市场指数中所有股票的过去价格预测其未来价格。

具有不同输入和输出的多元变量

与上述输入和输出相等的多变量时间序列问题相反,您也可以有不同的输入和输出序列。

input_cols = ["precipitation", "temperature"]
output_cols = ["snowfall"]

如果您需要来自另一个时间序列的额外信息来预测目标序列,您通常会使用这个问题公式。例如,您可以通过向模型提供模数或正弦波信号来提供一些时间意识)。

具有不同输入和输出时间序列问题公式的多元时间序列问题(图片由作者提供)

用例示例:根据之前的降水和温度预测降雪量。

边:输出序列的长度

接下来,我们将看看输出序列(边)的长度。这意味着您可以预测未来的单个时间步长或多个时间步长。

我们区分单步和多步时间序列问题。对于多步问题公式,我们还区分了单次预测和递归预测

照片由 Pauline LoroyUnsplash 上拍摄

单步输出序列

单步时间序列问题可能是最简单的,因为你只需要预测未来的一个时间步。

单步时序问题公式化(图片由作者提供)

用例示例:预测第二天要烘焙的商品数量。

单次多步输出序列

与单步时间序列问题相比,多步时间序列问题稍微困难一些,因为您必须预测未来的多个时间步。我们试图立刻预测的未来越远,我们的预测就越不可靠。

单发多步时间序列问题公式化(图片由作者提供)

用例示例:预测下周学校午餐的数量,以购买适量的食品。

递归多步输出序列

您可以多次预测单个时间步长,而不是一次预测多个时间步长。虽然我们提到预测一个时间步长比一次预测多个时间步长更可靠,但是您必须记住,在这种方法中,您将会从之前的预测中带走误差。

递归多步时间序列问题公式化(图片由作者提供)

饮料:输入序列的类型

最后,我们将看看输入序列的类型(饮料)。这意味着您可以使用固定长度的输入序列,也可以使用可变长度的输入序列。

我们区分滑动窗口和扩展窗口时间序列问题。

另一个要考虑的因素是步长。虽然您可以一次移动或扩展序列窗口一个时间步长,但也可以一次移动几个时间步长。步长越小,可用的训练样本数量就越多。

照片由 IamninoslavUnsplash 拍摄

推拉窗

滑动窗口意味着您的输入序列总是有一个指定的固定长度,例如一小时、一天、一周、六个月、一年、五年等等。

滑动窗口时间序列问题公式化(图片由作者提供)

用例示例:根据上一年预测下一年的学校午餐需求。

扩展窗口

顾名思义,对于扩展窗口时间序列问题,输入序列的长度会增加。

扩展窗口时间序列问题公式化(图片由作者提供)

用例示例:基于所有历史数据预测下个月某平台的新用户数量。

结论

你现在是不是对一些时间序列问题如饥似渴?

基于我们的组合菜单,你可以看到至少有 18 个(3 * 3 * 2)不同类型的时间序列问题。难怪感觉力不从心。

通过套餐类比,时间序列问题有三个主要组成部分变得很清楚:

  1. 输入和输出时间序列数量的变化
  2. 预测未来的方式和程度的变化
  3. 训练样本长度的弹性变化

喜欢这个故事吗?

这里是我其他时间序列文章的合集:

Leonie Monigatti

莉奥妮·莫尼加蒂

时间序列分析和预测

View list6 storiesHierarchical time series forecastingGIF created with Matplotlib and imageioA time series with lines indicating trend and variance for time series analysis. The last three data points are in a contrast color to indicate that they are predicted values from the time series forecasting model

如果你想把我的新故事直接发到你的收件箱里,请务必 订阅

成为媒介会员,阅读更多来自我和其他作家的故事。报名时可以用我的 推荐链接 支持我。我将收取佣金,不需要你额外付费。

https://medium.com/@iamleonie/membership

TwitterLinkedIn,以及ka ggle!**

时间序列平稳性的简单解释

原文:https://towardsdatascience.com/time-series-stationarity-simply-explained-125269968154

时间序列建模中平稳性需求的简单而直观的解释。

m.Unsplash 上拍照

介绍

当试图预测天气、股票市场或产品销售时,我们必须考虑一些时间因素。例如,当预测英国明天是否会下雪时,我们知道冬天的概率会比夏天高很多。

使用 时间序列 可以最好地表示这种类型的时间相关数据。这是每个数据点在时间上向前排序或索引的地方。预测时间序列中的下一个数据点非常有价值,称为 预测

准确预测下一个数据点的一个要求是保证时间序列是 平稳 。在本文中,我们将讨论:

  • 什么是平稳时间序列
  • 如何使时间序列平稳
  • 如何检验一个时间序列确实是平稳的
  • 为什么我们需要平稳的时间序列

如果你想了解更多关于时间序列和预测的知识,可以参考我在参考资料部分链接的书:预测原理和实践。

什么是平稳性?

一般来说,如果一个时间序列没有表现出任何长期趋势或明显的季节性,它就是平稳的。数学上我们有:

  • 恒定的T21 方差穿越时间
  • 不变表示穿越时间
  • 时间序列的统计特性不会改变

例如,考虑作为时间函数的航班乘客数量,使用简单的 Python 脚本绘制如下:

数据来自拥有 CC0 许可证的 Kaggle

作者代码 GitHub 要点。

作者用 Python 生成的图。

这个时间序列是平稳的吗?号码

很明显,随着时间的推移,航空乘客的数量有增加的趋势。此外,差异和波动也随着时间的推移而增加。我们现在将研究产生平稳时间序列的方法。

使时间序列平稳

为了使时间序列稳定,我们可以对数据进行变换。

差分变换

最常见的变换是将 差分 的时间序列。这是计算每个连续数据点之间的数值变化。从数学上来说,这可以写成:

作者在 LaTeX 中创建的方程。

其中 d(t) 是数据点【y(t)【y(t-1)在时间的差值。

我们可以通过使用diff()pandas 方法来绘制差异数据,从而简单地将差异数据计算为我们的数据框的一列:

作者代码 GitHub 要点。

作者用 Python 生成的图。

数据现在是静止的吗?号码

平均值现在是常数,并在零附近振荡。然而,我们可以清楚地看到,随着时间的推移,方差仍在增加。

对数变换

为了稳定方差,我们对原始数据应用自然对数变换:

作者代码 GitHub 要点。

作者用 Python 生成的图。

现在波动的规模是一致的,但仍然有一个趋势。因此,我们现在必须再次应用差分变换。

对数和差分变换

应用对数变换和差分变换:

作者代码 GitHub 要点。

作者用 Python 生成的图。

数据现在是静止的吗?是啊!

正如我们所见,均值和方差现在是常数,没有长期趋势。

平稳性测试

从视觉上看,数据现在是静止的。然而,有更多的定量技术来确定数据是否确实是平稳的。

一种这样的方法是增强的 Dickey-Fuller (ADF)测试。这是一种统计假设检验,其中零假设是序列是非平稳的(也称为 单位根检验 )。

statsmodels 包为执行 ADF 测试提供了一个简单易用的功能:

作者代码 GitHub 要点。

运行这个函数,我们得到以下输出:

ADF Statistic: -2.717131
P-Value: 0.071121
Critical Values:
        1%: -3.48
        5%: -2.88
        10%: -2.58

我们的 ADF P 值(7.1%)介于 5%和 10%之间,因此根据您设置的显著性水平,我们拒绝或未能拒绝零假设。

如果我们愿意的话,我们也许可以进行进一步的差分,使它更加稳定。

如果您有兴趣深入了解 ADF 测试的数学原理,请参考我在参考资料部分提供的链接。

ADF 测试不是唯一可用于平稳性的测试,还有 科维亚特科夫斯基-菲利普斯-施密特-申(KPSS)测试 。然而,在这个测试中,零假设是趋势是稳定的。

要了解有关假设检验过程的更多信息,请参阅参考资料部分。

为什么我们需要平稳性?

问题仍然在于为什么我们需要确保我们的时间序列是平稳的?

嗯,有几个原因:

  • 大多数预测模型都假设数据是平稳的
  • 平稳性有助于使每个数据点独立
  • 总的来说,使数据更容易分析

结论

在本文中,我们描述了什么是平稳时间序列,以及如何应用各种变换使数据平稳。对数变换有助于稳定方差,差分变换有助于稳定均值。然后,我们可以使用 ADF 测试来测试平稳性。平稳性的主要重要性在于,大多数预测模型都假设数据具有这种性质。在我的下一篇文章中,我们将讨论其中一个预测模型。

本文中生成数据、图表和 ADF 测试的完整代码可在此处查看:

**https://github.com/egorhowell/Medium-Articles/blob/main/Time Series/Time Series Tools/stationary.py

参考资料和进一步阅读

和我联系!

(所有表情符号都是由 OpenMoji 设计的——开源的表情符号和图标项目。执照: CC BY-SA 4.0**

Google Data Studio 中的时间序列可视化

原文:https://towardsdatascience.com/time-series-visualizations-in-google-data-studio-e8fff21e86d3

包括带有累计和缺失数据的可视化。

珍妮·罗亚尔在 Unsplash 上的照片

当人们需要使用文字处理器或电子表格,但不想为微软 word 或 Excel 付费时,他们通常会转向谷歌文档和谷歌表单。同样,如果你需要制作数据可视化的仪表板,但不想注册 Power BI 或 Tableau,你可以使用已经拥有的谷歌账户使用谷歌数据工作室

在这篇文章中,我将使用 Google Data Studio 创建一些时间序列可视化,包括带有运行总数和缺失数据的可视化。

跟踪财产检查

数据

假设我在一家物业管理公司工作,我的部门需要在 2022 年 1 月至 2 月 15 日的第一个工作日检查 134 处物业。该公司已经雇佣了四个团队在全市范围内开展这项工作。

在电子表格中,每个属性占一行;每一行都包括地址、平方英尺以及其他财产信息,一旦检查完成,还有空的单元格需要填写。这些空白单元格将包含检查日期、进行检查的团队名称,以及关于评估的单元格。

目标

假设此时此刻,我们正在进行项目的一部分,我们的目标是跟踪项目整体和团队的进展。假设今天是 1 月 31 日,从 1 月 3 日到今天,检查记录在电子表格中。

这是顶部,两个与此目标相关的列按检查日期排序。(所有值都是随机生成的。)

作者图片

启动仪表板

理想情况下,这个电子表格应该放在 Google Drive 上的 Google Sheets 中,因为 Google 产品通常与其他 Google 产品配合得最好。但是,您可以上传文件。

前往 datastudio.google.com 的,打开空白报告开始。系统将提示您添加数据源。然后,您可以导航到 Google Sheets 文件。

可视化 1:跟踪整体项目进度

工具栏上有一个按钮可以添加一个图表 。点击它,你会看到各种图表选项。我选择第一个时间序列图表。

作者图片

图表是自动创建的。

每当您添加图表并选中它时,右侧会打开一个属性面板,其中有两个选项卡:数据样式。在这种情况下,默认指标是记录计数,它累加了每天的检查总数。

作者图片

但是我不想要一个日线图的起伏。我想要一张记录项目迄今进展的图表。

我点击【T2 指标】、下的记录计数,它会打开一个新窗口,我可以在这里定制东西。我更改了的运行计算,在那里它有,并将其更改为运行总和,我还将指标重命名为“运行总和”。现在我得到了这张图表:

作者图片

这个图表看起来更像我想要的,但是因为团队周末不工作,所以在没有完成任何事情的日子里,这条线下降到零。这看起来很奇怪。

我可以在面板的样式标签中修复这个问题。在通用下,默认线归零被选择为缺失数据

作者图片

这可以更改为线性插补。我做了改变,瞧:

作者图片

我差不多到了我想去的地方,但是记住,我用这个图表来跟踪项目的整体进展。同样,该项目将于 2 月 15 日结束,届时团队必须完成 134 项检查。

我还需要做两件事:

  1. 数据选项卡中,我将默认日期范围从自动更改为自定义。打开一个日历,我选择现有的开始日期和结束日期为 2 月 15 日。
  2. 样式标签中,有一个叫做参考线的部分。我选择加一条参考线,赋一个常数值 134,标签改为“Goal-134”。

作者图片

这些团队似乎正朝着我们的目标前进。

可视化 2:跟踪每日团队活动

之前的可视化关注的是整个项目的进展,但是现在我想看看团队有多忙。

我在 Google 工作表的另一个选项卡中创建了一个数据透视表,其中包含参数行:检查日期列:团队名称值:检查日期计数。这给了我一张这样的表格:

作者图片

Data Studio 将工作表文件中的每个选项卡或工作表视为自己的数据源。为了在 Data Studio 中使用这个新表,我必须使用工具栏中的 添加数据 按钮来添加它。

Data Studio 可以很容易地识别标题行,但是因为数据透视表在实际数据之上有两个标题行,所以可能会有点混乱。以下是解决任何问题的几种方法:

  • 添加数据时,您可以找到一个选项,在该选项中您可以手动选择要使用的单元格区域。(对于我在这篇文章中创建的可视化效果,我不会选择总计行。)
  • 您可以在另一个选项卡中引用所需的单元格,并在添加数据时选择该选项卡。

对于这个可视化,我使用四个指标,每个团队一个:

作者图片

我得到了下面的图表:

作者图片

在这个截图中,我将鼠标悬停在 1 月 10 日,图表弹出了当天的团队细分。

可视化 3:跟踪每个团队的进展

我知道有些时候团队可能会很忙,但其他时候不会那么忙。总的来说,这四支车队相比之下表现如何?

我复制了之前的可视化效果,并将其粘贴到仪表板上的另一个位置。然后,在数据选项卡中,我可以通过单击显示总和的位置来编辑每个指标。注意它是如何变成铅笔符号的。

作者图片

打开那个窗口,我现在转到运行计算下拉菜单并选择运行总和:

作者图片

正如我在上面的第一个可视化中所做的,我在样式选项卡中选择线性插值来解决周末数据的缺乏。我对所有四个团队重复这个过程,我得到这个图表来直观地了解所有团队在一段时间内的表现:

作者图片

在这篇文章中,我主要关注时序图,但是自然地,我也可以制作条形图、饼图、地图、仪表和其他类型的可视化。

修补美国农业部的食品数据库

原文:https://towardsdatascience.com/tinkering-with-the-usda-food-database-5db92f7f044f

为机器学习算法和进一步的统计分析准备美国农业部食品数据中心数据库。

Unsplash 上由 Bruno Scramgnon 拍摄的照片

我们大多数人都熟悉食品上的营养标签。即使我们没有真正读它们,我们也知道它们在那里。情况并不总是如此。直到 20 世纪 70 年代初,大多数食品中都没有营养标签。直到 20 世纪 90 年代初,它们才成为强制性的。今天,一些食物甚至在营养标签上标明了必需氨基酸的含量。现在有一种明显的趋势,那就是对我们放进嘴里的食物的成分和化学成分有更多的了解。

如果你想知道,这个故事不是关于营养建议的。我不会告诉你什么该吃,什么不该吃。如果你正在寻找这样的建议,这个故事不适合你,抱歉。

营养标签在一定程度上是有帮助的,但是如果我们想了解更多呢?作为数据科学家,如果我们想更深入地挖掘营养数据会怎样?嗯,我们首先需要数据。 美国农业部食品数据中心 数据库是一个很好的选择。

数据科学家和开发人员为制造分析工具以使消费者更容易获得营养信息所做的一切努力都会产生重大影响。

在这个故事中,我与你分享我在不得不修补这个数据库的几天中构建的工具。我希望这些工具可以帮助你分析食物数据库,如果运气好的话,还可以在营养领域创建你自己的模型和工具。故事的主要范围是数据构造成简单的平面数据帧,以用于使用机器学习和优化算法的进一步分析。****

故事结构

  • 数据库版本和文档
  • 数据库许可
  • 形成原始营养数据
  • 营养细节数据
  • 营养 id vs. 营养 _ 编号
  • 搜索营养名称
  • 搜索食物名称
  • 活力
  • 大量要素
  • 质量守恒
  • 阿特沃特通用因子系统
  • 最大无 NaN 数据框架
  • 结构化数据创建
  • 最后的话

数据库版本和文档

可通过以下链接查阅美国农业部食品数据中心数据库:

https://fdc.nal.usda.gov

并可在此下载:

https://fdc.nal.usda.gov/download-datasets.html

这个故事中使用的数据库是 2021 年 10 月的 CSV 版本,所有数据类型的完整下载

在下载的目录(FoodData_Central_csv_2021–10–28)中,有一个文件:

Download & API Field Descriptions October 2021.pdf

…它描述了每个表以及表之间的关系。我们在下文中将该文件称为文档,并将下载的目录称为数据库目录

数据库许可

该数据库是在公共领域,因此它是没有版权。然而,

如果开发者将 FoodData Central 列为数据来源,美国农业部将不胜感激。而且,如果可能的话,美国农业部希望看到使用这些数据的产品,或者被告知它们的用途

美国农业部食品数据中心许可

格式化原始营养数据

这个故事的主要目标是为数据挖掘和机器学习算法创建食物营养结构化数据。换句话说,我们希望生成以食物项目为索引的平面数据框架,以营养成分为特征(列)。

数据库目录中有一个名为food_nutrient.csv的文件。该文件包含对我们很重要的三列:

  • fdc_id:数据库中每种食品的唯一通用 id。
  • nutrient_id:营养素相关表中每种营养素的 id。
  • amount:每 100 克食物的营养素含量。营养素的单位在另一个表中,可以使用nutrient_id查阅。我们将在后面的故事中这样做。

让我们加载表:

在此定义您的目录路径。

这个表有重复的 fdc _ ids,因为一种食物有很多营养成分。所以我们用fdc_idnutrient_id对营养成分进行分组:

这是一个pandas MultiIndex,所以现在我们拆分MultiIndex,在多索引的第二层创建营养列:

这个数据帧是我们想要的原始数据,大概是我们想要的格式。索引是每种食物的 id——fdc_id,每一列是一个nutrient_id。我们必须理解它,并开发工具来使用它。

如你所见,有很多NaN价值观。因此出现了第一个问题:

NaN值是指零营养测量值还是简单的缺失测量值?

让我们检查数据帧中是否有实际的零:

真实的

我们可以断定零测量值被报告为 0**NaN** 值为缺失测量值。我可能已经猜到了,但这是很好的彻底。

营养详细数据

我们需要理解上一节的df_nutrients中的列 id。为此,我们将加载描述每种营养素的表格。该表在nutrient.csv下的数据库目录中:

我们将这个数据帧命名为df_nutrients_details。该数据框包含营养物的name,用于测量的单位(unit_name)两个不同的标识符idnutrient_nbr

营养 id vs. 营养 _ 编号

根据文件,food_nutrient.csv表中的nutrient_id应为df_nutrient_details中的id。但是还有其他的可能性。df_nutrient_details中还有一个nutrienr_nbr,这个有点混乱。

nutrient_id有三种可能,可能是:

  1. 来自df_nutrients_detailsid索引。
  2. nutrient_nbr出自df_nutrients_details
  3. idnutrient_nbr都有。

我们需要在进一步行动前搞清楚这一点。

在得出结论之前,我们需要解决一些问题。

首先,营养素 _ ids 的范围是什么?

(203, 2063)

df_nutrients_detailsid的范围是什么?

(1001, 2064)

nutrient_nbr的范围是什么?

(200, 958)

看来nutrient_id既是id又是nutrient_nbr。让我们进一步调查一下。

df_nutrients列中的所有假设 id 都在实际 id 中吗?

真实的

df_nutrients栏中所有假设的营养素参考值都在实际营养素参考值中吗?

真实的

我们假设,其实idnutrient_nbr可以互换使用。如果是这种情况,对于给定的食物,假定的 id 列和假定的 nutrient_nbr 列之间不能有重叠。换句话说,一个单一的营养测量要么通过它的id要么通过它的nutrient_nbr来说明,但不能同时通过两者来说明。

所以,问题来了:营养素 _nbrs 和 id 有重叠吗:

错误的

因此,我们可以假设idnutrient_nbr是可以互换的。因此,我们将把nutrient_nbr列转换成 id,并在下文中将这些 id 称为nutrient_id:

我们还会将df_nutrients列转换为整数类型,并删除任何没有营养测量的食物:

搜索营养素名称

现在是时候写一些真正的代码了。我们想开始理解营养数据框架。到目前为止,nutrient_id专栏并没有对我们说太多。我们需要能够通过名称搜索营养物质,然后获得它们的nutrient_id

我们可以使用复杂的pandas链式方法来搜索和过滤df_nutrients_details中的数据,从而搜索营养名称。然而,最好编写一个类来以简单的方式处理它,并避免每次我们想要执行搜索时编写熊猫链。一开始,编写我们自己的类可能看起来比较长,但是相信我,它会简化以后的事情。

下面是NutrientSearch类:

让我们来看看它是做什么的,它是如何做到的,以及为什么。

该类用df_nutrients_detailsdf_nutrients初始化。这就是我们需要的全部信息。只有两个公共方法,search_nutrient,它允许我们按名称搜索养分:

还有get_all_nutrients法,列出了所有营养成分:

这两种方法都有两个可选的布尔夸尔:

  • valid_nutrient:如果True,我们检查营养素是否在df_nutrients栏中。毕竟,对于一种数据中不存在的营养物质,我们没有多大用处。
  • n_foods:如果True,则在返回的数据帧中添加一列,列出每种营养没有NaN测量的食物数量。

返回的数据帧由id索引,这是上一节描述的nutrient_id。它有一个营养物栏name和描述测量单位的unit_name。记住,所有的测量都是以每 100 克食物为单位的。最后,前面讨论过的可选n_foods列。

类中的其他方法只是帮助处理实际的搜索、验证和计算n_foods

搜索食物名称

我们需要执行的下一个搜索是关于食物名称的。到目前为止,我们知道了df_nutrients的每一行的 fdc_id,但是这并不是很有用,除非我们给每个 fdc_id 分配一个食品名称。

也就是说,我们导入包含每种食物描述的food.csv表:

我们必须注意此后的食品描述或食品名称,因为有重复的:

真实的

让我们找出每个data_type的计数:

大部分食物来自branded_food。因此,我们将导入branded_food.csv表以了解更多信息:

现在我们需要编写另一个类来搜索食物名称。同样,我们会经常搜索食物名称,所以最好编写一次工具代码,简化我们的生活。

下面是FoodNameSearch类:

让我们来看看它是做什么的,它是如何做到的,以及为什么。

首先用df_foodsdf_branded_foodsdf_nutrients初始化该类。它有三个公共方法。search_by_name,它允许我们输入一个字符串(或正则表达式)并返回一个pandas Series:

search_single_fdc_id将 fdc_id 映射到 food_name,它返回一个字符串:

愚蠢的山羊和切达山羊奶酪通心粉和山羊奶酪,比萨饼和冰淇淋形状的意大利面,愚蠢的山羊和切达奶酪|纳什芬奇公司

最后,search_fdc_ids接受 fdc_ids 的 iterable 并返回一个pandas Series:

除了位置参数之外,所有方法都有一个可选的布尔参数:valid_nutrients。此标志控制是否仅包括无NaN营养测量的 fdc _ ids。毕竟,没有营养测量的食物对我们来说没有更多的用处。

其他方法,私有方法,是助手。他们验证 fdc _ ids 并将brand_owner数据添加到branded_food名称中。对于品牌食品,在食品名称和品牌所有者之间插入一个“|”。这样做是为了帮助消除歧义,但仍然不能保证产生不重复的食品名称。

能量

事不宜迟,让我们开始数据清理的第一步。在本节中,我们将了解能量测量的意义。目标是通过由fdc_id索引的Series产生食物的单一能量测量。

我们将使用我们闪亮的新NutrientSearch类来寻找能量营养素:

数据库中有四个能量测量值。普通能量千卡,这是大多数食物使用的热量。另一个能量以 kJ(千焦)为单位。最后,两份阿特沃特能量,很少的食物。

也就是说,让我们创建一个只有能量测量值的数据框架:

并将千焦能量转化为千卡能量:

多少千焦能量测量值与千卡测量值重叠?

7934

因此,几乎所有以 kJ 为单位的测量都是多余的。

现在,我们希望放弃过高的能量测量值。根据阿特沃特通用因子系统,每克能量最大的营养素是脂肪,9 千卡/克,这些能量是针对 100 克食物测得的;因此,任何比 900 千卡大得多的测量值都可能是错误的,应该丢弃:

我们将选择使用nutrient_id 1008 的能量测量作为能量的基础:

宏量营养素

提供能量的三种最著名的常量营养素是:

  • 碳水化合物
  • 脂肪
  • 蛋白质

酒精在技术上被认为是提供能量的宏量营养素,但目前,我们将忽略它。

在本节中,我们希望为这三种宏量营养素生成三个Series地面实况。

我们先搜索一下脂肪:

显然,nutrient_id 1004 正是我们想要的,因为它存在于大多数食物中:

那么,蛋白质呢:

这里没有太多选择:

最后,让我们搜索碳水化合物:

大多数食物中都含有 1005,所以我们将使用它:

质量守恒

为了进一步清理数据,我们希望找出大于 100 克的质量测量值。记住,所有的测量都是以每 100 克食物为单位的。因此任何测量的报告质量都不能超过这个值。

食物质量由上一节讨论的三种常量营养素的质量加上下列物质的质量组成:

  • 酒精
  • 纤维

寻找这些营养物质:

我们生产他们的Series:

请注意,所有这些系列的测量单位都是克。

我们将假设这些序列的‘T2’值实际上为零。这样做没有害处,因为如果未测量的值大于零,这将增加质量,而不是减少质量。

我们将连接上一节的碳水化合物、脂肪和蛋白质系列,然后将酒精、纤维、水和酒精的质量设置为零,除非它们不是NaN:

让我们对每行的质量求和:

显然,有些质量差得很远。

让我们删除所有质量大于 100 的 fdc _ ids:

下面是总质量的分布情况:

总质量直方图[图片由作者提供]。

还有很多质量不是 100。这可能有许多原因:

  • 也许有一些质量营养素被我们忽略了,或者我们使用了不同的质量术语
  • 也许一些质量测量是错误的。

我们将假设前者并继续下去。如果我们假设是后者,我们最终会放弃很多食物。

为了清理数据,我们需要从先前生成的数据中删除任何没有通过质量守恒过滤器的 fdc _ ids:

阿特沃特通用因子系统

食物中能量的计算方法有很多。最简单的,也许是最常用的,是阿特沃特通用因子系统。该系统为每克碳水化合物、脂肪、蛋白质和酒精分配固定的能量值,并认为总能量是这些能量的总和。这些因素如下:

  • 碳水化合物:4 千卡/克
  • 脂肪:9 千卡/克
  • 蛋白质:4 千卡/克
  • 酒精:7 千卡/克(大约。)

其他系统包括作为能量项的纤维;其他人使用特定的因素。然而,为了简单起见,我们坚持使用通用因子系统。

考虑到这些营养成分,让我们创建一个包括它们的数据框架,以及报告的能量:

让我们使用阿特沃特通用因子系统来估算能量:

这些是能量、报告能量和估计能量的描述性统计数据:

能源的描述性统计。

使用阿特沃特通用因子进行能量估算的描述性统计。

这是两种能量的直方图和另一种能量差的直方图:

报告的能量直方图,使用阿特沃特通用因子系统估算的能量直方图,以及它们之间的差异直方图[图片由作者提供]。

我们可以看到,大多数报道的能量倾向于与阿特沃特估计的能量一致,但不完全一致。

为了使进一步的宏量营养素计算更容易,我们将放弃报告的能量,而使用阿特沃特能量。

我们制作了一个名为df_emacros的数据框架,包含能量和常量营养素(能量常量营养素)的基本事实。

所有食物都必须有能量和常量营养素的测量值。因此,我们将删除所有先前生成的数据中不在df_emacros中的所有 fdc _ ids:

最后,我们从df_nutrients中删除能量、碳水化合物、脂肪、蛋白质和酒精的所有营养标识。因为我们现在在df_emacros中已经有了这些测量值

在这一节和上一节中,我们已经对数据做了许多更改,所以现在应该重新实例化我们的搜索类,以包含最新的数据:

最大无 NaN 数据帧

当试图从“df_nutrients”中去除 NaN 值时,我们将面临一个问题。问题是,我们可以很容易地在数据帧的所有行和列中找到由任何给定的营养成分创建的 nan。

让我们稍微偏离一下数据,使用简单的数据框架来关注这个问题。考虑这个数据框架:

如果我们对列或行使用dropna方法,我们将得到一个空的数据帧。相反,我们想要一种算法,以这样一种方式删除列,即保持列最大化非NaN行的数量。

在这个例子中,如果我们删除B列,我们将得到一个 2x2 的数据帧。

我们提出了一种贪婪算法来实现这一点:

函数get_maximal_no_nan_df实现算法。其他函数只是助手。get_maximal_no_nan_df服用

  • 作为位置参数的数据帧。
  • min_data_size夸尔格。它控制我们想要保留的最小行数。如果我们试图保留大多数行,该算法将丢弃许多列。相反,如果我们将其设置为较低的值,它将保留许多列。该值可以是大于或等于 1 的整数,也可以是小于 1 的浮点数。在前一种情况下,它被认为是行的字面数量;在后者中,它被视为总行数的一部分。

事不宜迟,我们来测试一下算法:

它像预期的那样工作。

结构化数据创建

最后,我们拥有了创建适合进一步分析的结构化数据的所有元素。

让我们获取所有的营养,只保留那些存在于一百多种食物中的营养:

出现次数最多的营养素、大量营养素和能量不包括在内[图片由作者提供]。

我们需要再编写一个类来创建我们想要的数据帧,也就是说,具有选定营养成分的数据帧。我保证这是我们编写的最后一个类。这个类将使用上一节中的最大 no NaN算法:

这个类用df_emacrosNutrientSearch类的一个实例和FoodNameSearch类的一个实例初始化。所以它几乎使用了我们迄今为止开发的所有东西。

它只有一个公共方法,create_data。这个方法只有一个位置参数,一个可迭代的营养标识(任一列表,熊猫索引元组)。有许多夸尔格:

  • no_nans:如果设置为True,则使用最大编号NaN算法来保留尽可能多的列。否则,它会保留所有列以及所有的NaN值。
  • with_nutrient_names:是否将营养素 id 更改为实际营养素名称的列名。
  • include_food_name:是否包含食品名称列。在这两种情况下,生成的数据帧都由 fdc_id 进行索引。
  • shallow_valid_mass:如果True,将验证以克为单位测量的位置参数 iterable 中没有任何营养素大于 100 克。如果一些食物含有这种无效的营养成分,它将从结果数据框中被丢弃。
  • min_data_size:与上一节get_maximal_no_nan_df功能相同。

所有的私有方法都是帮助者。

最后,我们可以创建我们想要的格式的数据。让我们实例化该类并使用来自df_all_nutrient"的所有索引(nutrient _ ids);即大多数营养物质,至少是一百多种食物中的营养物质:

这个数据帧没有Na,我们设法保留了 114 行 84 列。减少营养元素的数量可能会创建具有更多行(食物项目)的数据帧。

最后的话

我们停止了对实际食物营养成分的进一步分析。那是故意的。首先,这个故事的想法不是告诉你什么该吃,什么不该吃。此外,这个故事太长了。

我希望这里开发的工具可以帮助您在第一次清理和结构化数据时节省大量时间。从这里开始的路线图是生成含有选定营养成分的数据帧,以进一步分析食物成分。食物集群、食谱的食物元素推荐器和每日营养摄入优化器只是我头脑中的一些想法

注: 故事通篇所有数据帧和系列图像均为作者原创图像。

我希望这个故事对你有用。 订阅 到我的邮件列表如果你想知道更多这样的故事。

喜欢这个故事吗?通过我下面的推荐链接成为一个媒体成员来支持我的写作。无限制地访问我的故事和许多其他内容。

https://medium.com/@diego-barba/membership

TinyML:用 Arduino Pro 实现机器人的坡度控制

原文:https://towardsdatascience.com/tinyml-slope-control-for-robots-with-arduino-pro-b2bca81e939e

用 Arduino Nicla Sense ME 和内乌顿 TinyML 构建倾角估算系统

“追随一个人的爱好是件好事,只要它能把人引上坡路。”——a·纪德

真空吸尘器机器人是过去十年中最有用的发明之一,任何有不同看法的人都意味着他没有!这个神奇的家用电器是技术的集中:一个复杂的嵌入式系统,由一些微控制器、许多传感器和许多…软件组成!

我的吸尘器机器人。图片作者。

但是有多少次你会觉得你的机器人很蠢?
特别是,当你的小帮手挡住了家里地毯、晾衣架等障碍物时。如何在为时已晚之前认识到这一点?

避免这种恼人情况的一种方法是实时计算机器人相对于地板的路径,并根据其当前位置执行决策。例如,如果坡度超过 4 度,机器人会自动停止并返回。

我的真空吸尘器机器人卡在地毯上了。图片作者。

在本教程中,我将使用基于数据的技术机器学习来解决这个问题,并展示如何在 Arduino Pro 板上使用 ML 模型来实现基于加速度计倾斜度估计器系统。为了在微控制器上训练和部署这个模型,我将使用 内乌顿 ,这是一个 TinyML 框架,允许在没有任何机器学习经验的情况下自动构建神经网络,并将它们嵌入到小型计算设备中。

微控制器:Nicla Sense ME

ML 模型将部署在 Arduino Nicla Sense ME 板上,这是一种微型低功耗的 Arduino 板,具有强大的计算能力。它基于一个带有 4 个传感器32 位微控制器:运动、磁力计、压力和气体传感器。它适用于需要在一个小设备上结合传感器测量和 AI 任务的项目。这个实验的完美匹配!

Arduino Nicla 感觉我。图片作者。

NiclaArduino Pro 平台的一部分。要开始使用 Nicla ,只需使用 Arduino IDE 并从板管理器下载"Arduino Mbed OS NIC la Boards "包。

电路板管理器中的 Arduino Mbed OS Nicla 电路板包。图片作者。

使用 USB 电缆将 Arduino 板连接到您的计算机,然后…完成!您的主板已准备好与 IDE 通信。

在用机器学习“弄脏你的手”之前,检查一下 Nicla 是否正常工作:打开“ Nicla_Blink “里面的草图” Nicla_Sense_System" 示例并上传。安装在 Nicla 上的 LED 将开始闪烁绿色。

Nicla_Sense_System 示例。图片作者。

Blink_Nicla sketch 在 Arduino Nicla Sense ME 上运行。图片作者。

加速计测量将由博世 BHI260AP 执行:一个安装在 Nicla 上的 6 轴 IMU 传感器。
为了验证所有 Nicla 传感器是否正常工作,从库管理器下载“Arduino _ BH y2”库,并打开“独立示例。

Arduino_BHY2 库。图片作者。

Arduino_BHY2 示例。图片作者。

将此示例上传到 Arduino 板上,并在串行绘图仪上查看结果。该草图配置并读取所有传感器数据(加速度、温度、气体等……)。

Arduino_BHY2 —独立示例。图片作者。

现在, Nicla 真的准备好了!

模型结构

该系统被设计为仅沿一个轴估计倾斜度,斜率值以度表示,在[0;5 ]范围。
该模型将由在 1- 第二时间窗(采样时间:20ms — 50Hz )内采样的 50 个加速度和 50 个陀螺仪测量值组成的数据集作为输入。

在机器学习环境中,这项任务可以通过两种方式完成:

  • 回归:是预测一个连续数值的问题。
    模型将倾斜度计算为 0 到 5 之间的连续值(例如 2.54 )。
  • 多类分类:将输入分类到三个或更多离散类中的问题。
    该模型识别 6 个类别:0、1、2、3、4 和 5。

我们将使用这两种方法并对它们进行比较。

实验包括三个阶段:

  1. 捕获训练数据集
  2. 使用内乌顿训练模型
  3. Nicla 上部署模型

实验流程。图片作者。

1.捕获训练数据集

第一阶段是创建用于训练神经网络的训练数据集
对于每个倾斜度, 10 个测量值将被捕获并存储在 CSV 文件中。每次测量将由 50 个加速计和 50 个陀螺仪读数组成。

一个 Arduino 草图被设计用来根据 内乌顿需求创建数据集。该程序将获取每个倾斜度的测量值,并将传感器数据打印在串行端口控制台上。用户将通过输入串行端口插入要采集的每个度数值。

为了创建精确的数据集,有必要通过将 Nicla 板放置在代理(在本例中为真空吸尘器机器人)上方,并使用精确的仪器来测量真实的坡度,例如数字测斜仪。如果你没有它,你可以使用你的智能手机和 AndroidiOS 商店中的众多测斜仪应用中的一个。在这个项目中,我使用了测量 iPhone app。

下面, Arduino 程序:

  • 包括标题,定义项目参数和变量
#**include** “Arduino.h”
#**include** “Arduino_BHY2.h”#**define** NUM_SAMPLES 50
#**define** SAMPLE_TIME_MS 20*// IMU sensor handlers*
SensorXYZ **acc**(SENSOR_ID_ACC);
SensorXYZ **gyro**(SENSOR_ID_GYRO);
  • 设置串行端口、IMU 传感器和 CSV 接头
void **setup**() {
 *// init serial port*
 **Serial**.begin(115200);
 while (!Serial) {
    delay(10);
 } *// init IMU sensor*
 **BHY2**.begin();
 **acc**.begin();
 **gyro**.begin(); *// print the CSV header (ax0,ay0,az0,…,gx49,gy49,gz49,target)*
 for (int i=0; i<NUM_SAMPLES; i++) {
    Serial.print(“aX”);
    Serial.print(i);
    Serial.print(“,aY”);
    Serial.print(i);
    Serial.print(“,aZ”);
    Serial.print(i);
    Serial.print(“,gX”);
    Serial.print(i);
    Serial.print(“,gY”);
    Serial.print(i);
    Serial.print(“,gZ”);
    Serial.print(i);
    Serial.print(“,”);
  }
 Serial.println(“target”);
}
  • 等待用户输入以执行测量
void **loop**() {
 static int    samplesRead = 0;
 static String target; *// wait for user input (degree target value)*
 while(Serial.**available**() == 0) {}
 target = Serial.**readStringUntil**(‘\n’);
 samplesRead = 0; *// read samples of the requested input orientation*
 while (samplesRead < NUM_SAMPLES) {
    *// read the acceleration and gyroscope data*
    **BHY2**.update(); samplesRead++; *// print the sensor data in CSV format*
    Serial.print(acc.x());
    Serial.print(‘,’);
    Serial.print(acc.y());
    Serial.print(‘,’);
    Serial.print(acc.z());
    Serial.print(‘,’);
    Serial.print(gyro.x());
    Serial.print(‘,’);
    Serial.print(gyro.y());
    Serial.print(‘,’);
    Serial.print(gyro.z());
    Serial.print(‘,’); *// print target at the end of samples acquisition*
    if (samplesRead == NUM_SAMPLES) {
       Serial.println(**target**);
    }

    **delay**(SAMPLE_TIME_MS);
 }
}

上传并运行草图,打开串行监视器,在目标位置倾斜 Nicla (用倾斜仪或 app 验证)。然后,在串行接口的输入字段中输入度数值,并按 enter 键:程序将执行测量…在此期间不要移动您的板!
每度重复此步骤进行测量。在这个实验中,我以 1 度(0、1、2、3、4 和 5)为步长从 0 到 5 进行测量。

Nicla Sense ME 和 iOS Measure app。图片作者。

将串口输出复制到一个名为" trainingdata "的文件中。 csv ”。

2.用内乌顿训练模型

在此阶段,您将使用相同的数据集训练两个不同的模型:一个使用回归任务类型,另一个使用多类类型。

2a。上传数据集

  • 创建两个新的解决方案,名称分别为:“倾斜度估计器 Reg 和“倾斜度估计器 Mul ”。

内乌顿:添加一个新的解决方案。图片作者。

对于每个解决方案:

  • 上传训练数据集文件,并验证是否满足内乌顿要求(文件名旁边会出现一个绿色复选标记)。然后,点击确定
  • 在目标变量部分,选择包含度数值的列名(如目标,点击下一个

内乌顿:经过验证的数据集和目标变量。图片作者。

2b。我们训练吧!

  • 一旦数据集被成功验证,内乌顿自动提供可用的 ML 任务类型。在第一个解决方案中选择“回归”,在第二个解决方案中选择“多分类”。

内乌顿:任务类型选择。图片作者。

  • 由于模型将在微控制器上运行,因此在两种解决方案中启用 TinyML 选项。

内乌顿:TinyML 选项。图片作者。

  • 打开高级模式,进入高级设置,在位深下拉菜单中选择 32。通过这样做,您将充分利用 32 位 Nicla 微控制器的强大功能。

内乌顿:TinyML 高级设置。图片作者。

  • 现在…按下“开始训练”:训练程序开始,进度逐步显示。

内乌顿:培训过程。图片作者。

  • 当“状态变为“训练完成时,表示训练结束,模型达到最佳预测能力。

2c。模型准备好了

“预测”选项卡显示训练阶段的结果。

回归解已达到 0.29RMSE 。RMSE 代表均方根误差,它是测量模型误差的标准方法。
低值表示模型预测数据准确。一个好的值在 0.20.5 之间。

内乌顿:回归解决方案的预测选项卡。图片作者。

多类解决方案已经达到 88%精度。这意味着从 100 个预测记录中,有 88 个被分配到正确的类别。较高的值表示模型拟合较好。

内乌顿:多类解决方案的“预测”选项卡。图片作者。

在这两种方案中,用于嵌入的模型的大小小于 3 KB 微控制器的 ( )北欧 nRF52832 )内存大小 512 KB 相比,这是一个非常小的尺寸。

内乌顿:预测选项卡的度量部分。图片作者。

3.在 Nicla 上部署模型

要生成两个模型的 C 库,点击每个解决方案的“下载按钮。

内乌顿:C 库下载。图片作者。

内乌顿 C 库包括:

  • / 模型:神经网络模型
  • / 预处理:用于执行预处理操作的一组函数:数据操作、数据过滤等。
  • neuton . cneuton . h:应用逻辑用来执行模型和读取预测结果的一组函数。

库集成很简单,由 3 个步骤组成:

1.包括内乌顿图书馆

**#include** "neuton.h"

2.声明输入变量并设置输入值

float **inputs**[300] = {
    *aX0*,
    *aY0*,
    // ...
    *gZ49*
};**neuton_model_set_inputs**(inputs);

3.运行预测

**neuton_model_run_inference**(*…*);

两个模型的主要应用程序是相同的,但是每个解决方案都包含各自的库文件。开发了应用程序来计算每 1 秒的倾斜度值(单位为度)。

#**define** REGRESSION 0
#**define** MULTICLASS 1
#**define** TASK_TYPE /* Choose task type: REGRESSION or MULTICLASS */#**include** "Arduino.h"
#**include** "Arduino_BHY2.h"#if (TASK_TYPE == **REGRESSION**)
   #include "src/**regression**/neuton.h"
#elif (TASK_TYPE == **MULTICLASS**)
   #include "src/**multiclass**/neuton.h"
#endif*[...]*

下面是倾斜度估算系统的 Arduino 程序:

float **inputs**[NUM_SAMPLES*6] = { 0 };void **setup**() {
  *// init serial port*
  *[...]* *// init IMU sensor*
  *[...]* Serial.println(“Neuton ANN model: Inclination estimator system”);
}void **loop**() {
  int samplesRead = 0; *// perform IMU measurement*
  while (samplesRead < **NUM_SAMPLES**) {
     *// read the acceleration and gyroscope data*
     **BHY2**.update(); *// fill sensor data array (model input)*
     **inputs**[0+samplesRead*6] = (float) **acc.x**();
     **inputs**[1+samplesRead*6] = (float) **acc.y**();
     **inputs**[2+samplesRead*6] = (float) **acc.z**();
     **inputs**[3+samplesRead*6] = (float) **gyro.x**();
     **inputs**[4+samplesRead*6] = (float) **gyro.y**();
     **inputs**[5+samplesRead*6] = (float) **gyro.z**(); samplesRead++;

     delay(**SAMPLE_TIME_MS**);
  } *// provide inputs to Neuton neural network model*
  if (**neuton_model_set_inputs**(inputs) == 0) {
     uint16_t  **predictedClass**;
     float*    **probabilities**; *// run model inference*
     if (**neuton_model_run_inference**
                           (&predictedClass, &probabilities) == 0) {
        Serial.print("Estimated slope: ");
        #if (TASK_TYPE == **MULTICLASS**) 
          Serial.print(predictedClass);
          Serial.print("°");
          *// show class probabilities*
          Serial.print(" - Probabilities [ ");
          for (int i=0; i<**neuton_model_outputs_count**(); i++) {
             Serial.print(**probabilities**[i]);
             Serial.print(" ");
          }
          Serial.println("]");   
        #elif (TASK_TYPE == **REGRESSION**) 
          Serial.print(**probabilities**[**0**]);
          Serial.println("°");
        #endif
     }
     *[...]* }
  *[...]*
}

我们来预测一下!

…是时候在 Nicla 上运行推理了!
让我们在板上验证并上传应用程序,倾斜系统并在串行监视器中查看估计的倾斜度值。它将每 1 秒钟实时计算和打印一次。

回归解

#**define** TASK_TYPE **REGRESSION**

对于回归任务,度值将在概率数组的 0 位置作为连续值输出。

以下是回归解决方案串行输出的示例:

内乌顿倾斜估计器的串行输出—回归任务。图片作者。

多类解决方案

#**define** TASK_TYPE **MULTICLASS**

对于多类任务, predictedClass 变量将包含估计度值的类索引。
概率数组将包含 6 个类别的概率。预测类的精度将存储在数组的位置 predictedClass 处。

以下是多类别解决方案串行输出的示例:

内乌顿倾斜估计器的串行输出—多类任务。图片作者。

让我们行动起来吧!

为了显示倾斜度估计的实际效果,我将由小电池供电的 Nicla 放在真空机器人上。
Nicla 用 led 颜色指示斜率值:

  • 绿色:如果倾斜度小于小于 4
  • 红色:如果是超过 4

镍镉和电池安装在我的真空吸尘器机器人。图片作者。

倾斜度评估正在进行中。作者视频。

这里,你可以找到本文所描述的 Arduino 草图!

将 Excel 电子表格加载到 Pandas 数据框架中的技巧和诀窍

原文:https://towardsdatascience.com/tips-and-tricks-for-loading-excel-spreadsheets-into-pandas-dataframes-c486ac1ed16f

了解如何正确地将工作表加载到 Pandas 数据框架中

鲁拜图·阿扎德在 Unsplash 上的照片

在大多数数据分析项目中,您通常会遇到的最常见和最流行的数据文件格式之一是 CSV。然而,来自金融部门的人经常处理另一种格式——Excel 电子表格。

虽然很多关于 Pandas DataFrame 的文章都侧重于使用 CSV 文件加载,但在本文中,我将重点讨论 Excel。我将向您展示如何将工作表从 Excel 加载到您的数据框架中,以及一些将工作表的一部分加载到数据框架中的技巧和诀窍。

对于本文,我将使用两个示例 Excel 电子表格。

:本文所有图片和截图均由作者创作

相关阅读

将大型 CSV 文件加载到 Pandas DataFrames 的提示和技巧第 2 部分(https://towards data science . com/Tips-and-Tricks-for-load-Large-CSV-Files-into-Pandas-data frames-Part-2-5fc 02 fc 4 E3 ab)

将大型 CSV 文件加载到 Pandas DataFrames 的提示和技巧—第 1 部分(https://towards data science . com/Tips-and-Tricks-for-load-Large-CSV-Files-into-Pandas-data frames-Part-1-fac 6 e 351 Fe 79)

样本 Excel 电子表格#1

我的第一个 Excel 电子表格样本(my data . xls);自行创建)包含两个工作表:

  • 机场
  • 航空公司

两个工作表中的数据来自航班延误数据集—https://www.kaggle.com/datasets/usdot/flight-delays许可 : CC0:公共领域

以下是机场工作表的样子:

以下是航空公司的工作表:

请注意,airlines 工作表不包含标题。

安装 xlrd 包

加载旧的。xls 格式的 Excel 文件,需要安装 xlrd 包:

xlrd 是一个库,用于从历史记录中的 Excel 文件读取数据和格式化信息。xls 格式。

pip install xlrd

导入 Excel 电子表格

让我们尝试使用 Pandas 中的read_excel()函数加载 Excel 电子表格中的数据:

import pandas as pd

df = pd.read_excel('mydata.xls')
df

以下是数据帧的内容:

请注意,虽然我们的 Excel 电子表格有两个工作表,但只加载了第一个工作表。

加载所有工作表

要加载 Excel 电子表格中的所有工作表,请将sheet_name参数设置为None:

df = pd.read_excel('mydata.xls', 
                   sheet_name=None)
print(df)

结果不再是熊猫的数据框架;相反,它是一个数据框架的字典:

{'**airports**':     IATA_CODE                              AIRPORT  \
0         ABE  Lehigh Valley International Airport   
1         ABI             Abilene Regional Airport   
2         ABQ    Albuquerque International Sunport   
3         ABR            Aberdeen Regional Airport   
4         ABY   Southwest Georgia Regional Airport   
..        ...                                  ...   
317       WRG                     Wrangell Airport   
318       WYS               Westerly State Airport   
319       XNA  Northwest Arkansas Regional Airport   
320       YAK                      Yakutat Airport   
321       YUM           Yuma International Airport   

                               CITY STATE COUNTRY  LATITUDE  LONGITUDE  
0                         Allentown    PA     USA  40.65236  -75.44040  
1                           Abilene    TX     USA  32.41132  -99.68190  
2                       Albuquerque    NM     USA  35.04022 -106.60919  
3                          Aberdeen    SD     USA  45.44906  -98.42183  
4                            Albany    GA     USA  31.53552  -84.19447  
..                              ...   ...     ...       ...        ...  
317                        Wrangell    AK     USA  56.48433 -132.36982  
318                West Yellowstone    MT     USA  44.68840 -111.11764  
319  Fayetteville/Springdale/Rogers    AR     USA  36.28187  -94.30681  
320                         Yakutat    AK     USA  59.50336 -139.66023  
321                            Yuma    AZ     USA  32.65658 -114.60597  

[322 rows x 7 columns], '**airlines**':     UA         United Air Lines Inc.
0   AA        American Airlines Inc.
1   US               US Airways Inc.
2   F9        Frontier Airlines Inc.
3   B6               JetBlue Airways
4   OO         Skywest Airlines Inc.
5   AS          Alaska Airlines Inc.
6   NK              Spirit Air Lines
7   WN        Southwest Airlines Co.
8   DL          Delta Air Lines Inc.
9   EV   Atlantic Southeast Airlines
10  HA        Hawaiian Airlines Inc.
11  MQ  American Eagle Airlines Inc.
12  VX                Virgin America}

结果中的关键字是工作表的名称。以下语句显示为机场工作表加载的数据帧:

display(df['airports'])

同样,以下语句显示为 airlines 工作表加载的数据帧:

display(df['airlines'])

不要担心标题;我会尽快修好它。

加载特定工作表

如果您想要加载特定的工作表,将您想要加载的工作表的名称存储为一个列表,并将其传递给sheet_name属性:

df = pd.read_excel('mydata.xls', 
                   sheet_name=['airports','airlines'])
print(df)

上面的语句加载了机场航空公司工作表,结果是一个数据帧字典。

转换列的类型

您可以使用dtypes属性检查加载到机场数据框架中的每一列的数据类型:

df['airports'].dtypes

观察熊猫将根据工作表中每一列的值的类型来加载它们:

IATA_CODE     object
AIRPORT       object
CITY          object
**STATE         object
COUNTRY       object** LATITUDE     float64
LONGITUDE    float64
dtype: object

特别是对于机场数据帧,最好将国家列表示为category类型,而不是object类型。这是为了减少数据帧的内存占用。您可以使用dtype参数在加载期间执行类型转换:

import numpy as np

df = pd.read_excel('mydata.xls', 
                   sheet_name='airports',
                   dtype= {
                       'STATE': 'category',
                       'COUNTRY':'category'
                   })
df.dtypes

在上面的语句中,我加载了机场工作表,并指示使用category数据类型加载国家列。您可以在加载数据帧后验证这一点:

IATA_CODE      object
AIRPORT        object
CITY           object
**STATE        category
COUNTRY      category** LATITUDE      float64
LONGITUDE     float64
dtype: object

转换列的值

除了加载特定类型的列,您还可以在加载期间使用converters参数执行值转换。例如,假设我想将所有的纬度和经度值转换成度、分和秒格式。

我首先定义了进行转换的函数:

# convert from decimal degrees to degrees, minutes, seconds
def deg_to_dms(deg):
    deg = float(deg)
    m, s = divmod(abs(deg)*3600, 60)
    d, m = divmod(m, 60)
    return int(-d if deg < 0 else d), int(m), s

然后,使用converters参数指定您想要转换的列:

df = pd.read_excel('mydata.xls', 
                   sheet_name='airports',
                   dtype= {
                       'STATE': 'category',
                       'COUNTRY':'category'
                   },
                   converters={
                       'LATITUDE': deg_to_dms,
                       'LONGITUDE': deg_to_dms,
                   })
df

这是转换的结果:

检查列的数据类型:

df.dtypes

您会看到纬度经度列都是object类型:

IATA_CODE      object
AIRPORT        object
CITY           object
STATE        category
COUNTRY      category
**LATITUDE       object
LONGITUDE      object** dtype: object

如果您尝试提取第一行的纬度值:

lat_first_row = df.iloc[0,5]
type(lat_first_row)

您将看到该值的类型为tuple:

tuple

使用列标题加载

前面我提到过航空公司工作表没有标题。所以如果你把它载入一个数据帧:

df = pd.read_excel('mydata.xls', 
                   sheet_name='airlines')
df

结果是第一行的内容将被用作标题:

显然这是不可接受的。要修复它,使用header参数并将其设置为None:

df = pd.read_excel('mydata.xls', 
                   sheet_name='airlines', 
                   header=None)
df

现在将使用默认的标题 01 :

您可以使用names参数更改标题:

df = pd.read_excel('mydata.xls', 
                   sheet_name='airlines', 
                   header=None,
                   names=['IATA_CODE','AIRLINE'])
df

现在已经设置了列名:

加载特定列

如果您只想加载工作表中的特定列,您可以使用usecols参数:

df = pd.read_excel('mydata.xls', 
                   sheet_name='airports', 
                   usecols=['IATA_CODE','AIRPORT','CITY','STATE','COUNTRY'])
df

在上面的语句中,我只想加载' IATA_CODE '、机场'、城市'、'和'国家'列:

实际上,您省略了纬度列和经度列和经度列。在这种情况下,使用 lambda 函数指定省略可能会更容易:

df = pd.read_excel('mydata.xls', 
                   sheet_name='airports', 
                   usecols=lambda column: column not in ['LATITUDE','LONGITUDE'])
df

另一种方法是指定要加载到 Excel 电子表格中的列名。嘿,还记得我们正在使用 Excel 电子表格吗?以下语句显示了如何使用 Excel-way 加载列 F ( 纬度)到 G ( 经度):

df = pd.read_excel('mydata.xls', 
                   sheet_name='airports', 
                   usecols='F:G')
df

结果如下:

如果你还想要 IATA_CODE机场栏目,可以轻松搞定,像这样!

df = pd.read_excel('mydata.xls', 
                   sheet_name='airports', 
                   usecols='A,B,F:G')
df

结果现在包含四列:

示例 Excel 电子表格#2

到目前为止,第一个 Excel spreahsheet 相当简单(我想说它对于现实世界来说太干净了)。我将使用的第二个数据集更加真实,它可以从https://data.world/davelaff/restaurant-inventory-log下载。

这是一个餐厅库存工作簿。这些数据是真实的,但远远不是最新的。列出的价格不是实际价格。许可:公共领域

该 Excel 电子表格包含两个工作表:

  • 库存工作表
  • 子类别库存值

下面是库存工作表的样子:

这里是子类别库存值工作表:

安装 xlrd 包

加载更新的。xlsx Excel 文件格式,需要安装 openpyxl 包:

pip install openpyxl

openpyxl 是一个 Python 库,用于读取/写入 Excel 2010 xlsx/xlsm 文件。

加载数据集

让我们加载第一个工作表:

df = pd.read_excel('RESTAURANT INVENTORY LOG.xlsx', 
                   sheet_name='Inventory Worksheets')

df

以下是输出结果:

注意到未命名:0 列了吗?此外,请注意最下面几行包含 NaN s?

如果您检查 Excel 电子表格,您会注意到实际数据从 B 列开始,并且在工作表的底部有一些空单元格:

为了让 Pandas 正确加载数据帧,您需要指定想要加载的列以及要加载的行数。这里,我将使用usecolsnrows参数来实现:

df = pd.read_excel('RESTAURANT INVENTORY LOG.xlsx', 
                   sheet_name='Inventory Worksheets',
                   usecols="B:Q", 
                   nrows=797)
df

结果现在看起来好多了:

对于第二个工作表,假设我要加载的实际数据在工作表的中间(我用红色突出显示)。为了帮助您直观地看到要加载的行,如果您想要加载以红色突出显示的数据,我已经指出了需要跳过加载的行:

要加载 FOOD 部分下的所有行,首先创建一个列表来存储要跳过的行:

rows_to_skip = list(range(0,5))
rows_to_skip.append(6)

上面将生成一个值列表— [0,1,2,3,4,6]。然后,使用skiprowsusecolsnrows参数从工作表中的准确位置加载数据:

df = pd.read_excel('RESTAURANT INVENTORY LOG.xlsx', 
                   sheet_name='Subcategory Inventory Value',
                   skiprows=rows_to_skip,
                   usecols="B:AA", 
                   nrows=8)
df

下图显示了包含食物部分下的行和列的数据帧:

如果你喜欢阅读我的文章,并且认为它对你的职业/学习有所帮助,请考虑注册成为一名灵媒会员。每月 5 美元,你可以无限制地访问 Medium 上的所有文章(包括我的)。如果你使用下面的链接注册,我会赚一小笔佣金(不需要你额外付费)。你的支持意味着我将能够投入更多的时间来写这样的文章。

https://weimenglee.medium.com/membership

摘要

从 Excel 文件加载 Pandas 数据帧与从 CSV 文件加载非常相似。主要区别在于:

  • 一个 Excel 文件可能包含多个工作表,您需要指明要加载哪个工作表。
  • 从 Excel 加载提供了通过 Excel 列名指定列的灵活性。这使您可以轻松识别要从中加载数据的列。
  • 由于 Excel 工作表中的数据可能不会以严格的表格格式填充,因此通常需要指定要加载的行数,以及加载时要跳过的行数。

一般来说,从 Excel 文件加载时,需要特别注意工作表中数据的格式。玩得开心!

将大型 CSV 文件加载到 Pandas 数据帧的提示和技巧—第 1 部分

原文:https://towardsdatascience.com/tips-and-tricks-for-loading-large-csv-files-into-pandas-dataframes-part-1-fac6e351fe79

了解如何读取大型 CSV 文件,以最大限度地减少内存使用和加载时间

照片由乔丹·哈里森Unsplash 拍摄

您在现实世界中使用的大多数数据集通常非常庞大,它们以千兆字节为单位,包含数百万行。在本文中,我将讨论一些在处理大型 CSV 数据集时可以使用的技术。

处理大型 CSV 文件时,有两个主要问题:

  • 加载大型 CSV 文件时使用的内存量。
  • 加载大型 CSV 文件所花费的时间。

理想情况下,您希望最小化数据帧的内存占用以及加载时间。在本文中,我将使用一个样本数据集向您展示。

我们的数据集

对于本文,我将使用来自https://www . ka ggle . com/datasets/4 e 614 EC 846 ab 778 f 6 a2 ff 166232 D5 a 65 f 5 e 6786 B4 f 5781690588 BD 2 CCD 71 CB 6 的日本贸易统计数据?资源=下载

许可证类型: CC BY-SA 4.0

该数据集包含 1988 年至 2020 年的贸易数据。它包含超过 1 亿行,CSV 文件占据了 4.5 Gb 的巨大空间。因此它是阐释本文中概念的理想数据集。

将 CSV 文件加载到熊猫数据帧中

让我们首先加载超过 1 亿行的整个 CSV 文件。我很想知道加载数据帧需要多长时间,以及它的内存占用量:

import time
import pandas as pd

start = time.time()

df = pd.read_csv("custom_1988_2020.csv")

print(time.time() - start, ' seconds')
display(df)
display(df.info())

输出如下所示:

总内存占用量高达 6.8 GB。)我花了 30 秒把它载入熊猫的数据框。

作为参考,我用的是 32GB 内存的 Mac Studio。

检查列

让我们检查数据框中的列:

df.columns

您现在应该意识到这个 CSV 文件没有标题,因此 Pandas 将假定 CSV 文件中的第一行包含标题:

Index(['198801', '1', '103', '100', '000000190', '0', '35843', '34353'], dtype='object')

使用标题加载

由于 CSV 文件没有标题,您至少可以使用header参数告诉 Pandas 在 CSV 文件中没有标题:

# loading with no headers specified
df = pd.read_csv("custom_1988_2020.csv", header=None)
display(df)

Pandas 现在将自动从 0 开始命名列,然后是 1,依此类推。

https://www . ka ggle . com/datasets/4 e 614 EC 846 ab 778 f 6 a2 ff 166232 D5 a 65 f 5 e 6786 B4 f 5781690588 BD 2 CCD 71 CB 6 上对数据集的描述?resource=download ,我们知道各个栏目的含义:

  • ym(年+月)
  • exp_imp(导出:1,导入:2)
  • hs9(协调制度编码)
  • 海关
  • 国家
  • 雌三醇环戊醚
  • Q2(数量)
  • 价值(以千日元计)

让我们使用names参数来命名列:

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'])
display(df)

DataFrame 现在有以下列名:' YearMonth' ,' ExportImport' ,' HSCode ,'海关,'国家,' Q1' ,'Q2 _ 数量','值'

加载特定列

由于 CSV 文件如此之大,您想问自己的下一个问题是—您真的需要所有的列吗?要加载特定的列,您可以使用usecols参数来指定您想要加载的列:

start = time.time()

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 usecols = ["YearMonth", "Value"])

print(time.time() - start, ' seconds')
display(df)
display(df.info())

正如您从上面的输出中看到的,内存占用已经减少到 1.7GB,加载时间现在减少到 17 秒。

usecols参数也支持列位置索引。上面的内容也可以用列号 0 和 7 重写:

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 usecols = [0, 7])

print(time.time() - start, ' seconds')
display(df)

请注意,不能使用-1 来表示最后一列,如下所示:

usecols = [0, -1])   # -1 is not supported

usecols参数也支持 lambda 函数。例如,如果要检索除国家列之外的所有列,可以使用下面的 lambda 表达式:

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 usecols = lambda column: column not in ['Country'])
display(df)

国家列现在将从结果中排除。

usecols参数中使用 lambda 函数可以让你做一些有趣的事情,比如加载名称中包含“Q”的列,例如:

usecols = lambda column: "Q" in column

或者列名长度超过七个字符:

usecols = lambda column: len(column) > 7

加载前 n 行

在许多情况下,您不需要整个 CSV 文件中的所有行。也许前 100 行就足够了。为此,您可以使用nrows参数来指定想要加载的前 n 行:

start = time.time()

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 nrows=100)

print(time.time() - start, ' seconds')
display(df[:15])
display(df.info())

从上面的结果中,您可以看到加载前 100 行只需要 0.1 秒,生成的数据帧只占用 6.4 KB。

跳过行

有时,您可能希望跳过 CSV 文件中的某些行。为此,使用skiprows参数:

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 skiprows=2,
                 nrows=100
)
display(df[:15])

上面的结果显示 CSV 文件的前两行被跳过:

您也可以跳过特定的行:

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 skiprows=[0,2,4],
                 nrows=100
)
display(df[:15])

上面的结果显示第 0、2 和 4 行被跳过:

您也可以使用一个range对象来指定要跳过的行的范围:

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 skiprows=range(5,10),
                 nrows=100
)
display(df[:15])

上面的结果显示第 5 行到第 9 行被跳过。skiprows参数的值也可以使用 lambda 函数编写,如下所示:

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 skiprows=lambda x: 5 <= x < 10,
                 nrows=100
)

使用 lambda 函数,您可以跳过所有偶数行:

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 skiprows=lambda x: x % 2 == 0,
                 nrows=100
)

print(time.time() - start, ' seconds')
display(df[:15])

上述结果显示所有偶数行都被跳过:

加载特定行

到目前为止,您已经学习了如何加载前 n 行,以及跳过 CSV 文件中的特定行。如何在 CSV 文件中加载特定的行?没有允许你这样做的参数,但是你可以利用skiprows参数得到你想要的。

使用skiprows参数中的 lambda 函数,您可以指定跳过哪些行而不是(这实际上意味着您希望加载哪些行):

start = time.time()

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 skiprows=lambda x: x not in [1,3],
                 nrows=100
)

print(time.time() - start, ' seconds')
display(df[:15])
display(df.info())

上面的结果显示保留了编号为 1 和 3 的行:

这种方法的缺点是必须扫描整个 CSV 文件,因此仅加载两行就需要 20 秒。

正在加载最后 n 行

我想讨论的最后一个挑战是如何从 CSV 文件中加载最后 n 行。虽然加载前 n 行很容易,但加载后 n 行就不那么简单了。但是你可以利用你到目前为止所学的知识来解决这个问题。

首先,计算 CSV 文件中有多少行:

# read the last n rows
start = time.time()

row_count = sum(1 for l in open('custom_1988_2020.csv')) 

print(time.time() - start, ' seconds')
row_count

由于 CSV 文件中有超过 1 亿行,所以计算行数大约需要 10 秒钟。另外,记住这个 CSV 文件没有头文件。所以 113607322 是记录的实际行数。

然后,要加载最后 20 行,使用skiprows参数并传递给它一个 lambda 函数来跳过除最后 20 行之外的所有行:

# read the last n rows
start = time.time()

df = pd.read_csv("custom_1988_2020.csv", 
                 header=None, 
                 names=['YearMonth', 'ExportImport', 'HSCode', 'Customs', 
                        'Country', 'Q1', 'Q2_Quantity', 'Value'],                 
                 skiprows=lambda x: 0 <= x < row_count - 20,
                 nrows=100)

print(time.time() - start, ' seconds')
display(df)
display(df.info())

结果显示了加载到 Pandas 数据帧中的最后 20 行。

与上一节一样,缺点是在加载过程中必须扫描整个 CSV 文件(因此加载数据帧需要 22 秒)。

如果你喜欢阅读我的文章,并且认为它对你的职业/学习有所帮助,请考虑注册成为一名灵媒会员。每月 5 美元,你可以无限制地访问 Medium 上的所有文章(包括我的)。如果你使用下面的链接注册,我会赚一小笔佣金(不需要你额外付费)。你的支持意味着我将能够投入更多的时间来写这样的文章。

https://weimenglee.medium.com/membership

摘要

在本文中,我介绍了从 CSV 文件中加载熊猫数据帧的多种技术。通常,不需要将整个 CSV 文件加载到数据帧中。通过只加载您需要的内容,您不仅节省了时间,还节省了在内存中保存数据帧所需的内存。在下一篇文章中,我将向您展示减少数据帧内存占用的技术。敬请期待!

将大型 CSV 文件加载到 Pandas 数据帧的提示和技巧—第 2 部分

原文:https://towardsdatascience.com/tips-and-tricks-for-loading-large-csv-files-into-pandas-dataframes-part-2-5fc02fc4e3ab

了解如何有选择地将 CSV 文件的一部分加载到数据帧中,同时减少其内存占用

Unsplash 上的 Shubham Dhage 拍摄的照片

在我的上一篇文章——将大型 csv 文件加载到 Pandas DataFrames 的提示和技巧——第 1 部分(https://towards data science . com/Tips-and-Tricks-for-load-Large-CSV-Files-into-Pandas-data frames-Part-1-fac 6 e 351 Fe 79)中,我分享了一些如何将大型 CSV 文件中的特定列和行加载到 Pandas DataFrames 中的技巧。在本文中,我想继续叙述,但这一次我想把重点放在非常大的数据集上,这些数据集要么太大,无法一次性加载所有内容,要么加载时间太长,以至于无法实际处理这些数据集。一旦您成功加载了数据集,我还将向您展示如何优化数据帧的内存占用,从而使您更容易执行数据分析。

我们的数据集

对于本文中的例子,我使用的是来自 https://www.kaggle.com/datasets/dilwong/flightprices航班价格数据集。数据集中的每一行都是 2022 年 4 月 16 日至 2022 年 10 月 5 日之间 Expedia 上的可购买机票,往返于以下机场:ATL、DFW、DEN、ORD、LAX、CLT、MIA、JFK、EWR、SFO、DTW、BOS、PHL、LGA、IAD、OAK。

许可证类型:归属 4.0 国际版(CC BY 4.0)

选择这个数据集的主要原因是它非常大——31GB,包含 8200 多万行和 27 列。因此,对于那些机器内存有限的人来说,这应该是一个很好的现实挑战。

将整个 CSV 文件加载到数据帧中

我想尝试的第一件事是将 CSV 文件正常加载到数据帧中。我想对加载过程计时,看看加载这样一个文件需要多长时间:

import time
import pandas as pd

start = time.time()

df = pd.read_csv('itineraries.csv')

print(time.time() - start, 'seconds')

所以我等了又等。最终,将整个 CSV 文件加载到 Pandas 数据帧需要 1164 秒(接近 20 分钟)。

作为参考,我的机器是 32GB 内存的 Mac Studio。上面的代码片段甚至无法在我的 8GB 内存的老式 M1 Mac Mini 上运行(内核在试图加载 CSV 文件时死亡)。

让我们看看数据框:

display(df)

数据帧有 82,138,753 (> 8,200 万)行和 27 列。要查看数据帧使用了多少内存,使用info()函数并将memory_usage参数设置为deep:

display(df.info(memory_usage='deep'))

从下面的结果中,您可以看到 dataframe 的内存占用为 110.5 GB!

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 82138753 entries, 0 to 82138752
Data columns (total 27 columns):
 #   Column                             Dtype  
---  ------                             -----  
 0   legId                              object 
 1   searchDate                         object 
 2   flightDate                         object 
 3   startingAirport                    object 
 4   destinationAirport                 object 
 5   fareBasisCode                      object 
 6   travelDuration                     object 
 7   elapsedDays                        int64  
 8   isBasicEconomy                     bool   
 9   isRefundable                       bool   
 10  isNonStop                          bool   
 11  baseFare                           float64
 12  totalFare                          float64
 13  seatsRemaining                     int64  
 14  totalTravelDistance                float64
 15  segmentsDepartureTimeEpochSeconds  object 
 16  segmentsDepartureTimeRaw           object 
 17  segmentsArrivalTimeEpochSeconds    object 
 18  segmentsArrivalTimeRaw             object 
 19  segmentsArrivalAirportCode         object 
 20  segmentsDepartureAirportCode       object 
 21  segmentsAirlineName                object 
 22  segmentsAirlineCode                object 
 23  segmentsEquipmentDescription       object 
 24  segmentsDurationInSeconds          object 
 25  segmentsDistance                   object 
 26  segmentsCabinCode                  object 
dtypes: bool(3), float64(3), int64(2), object(19)
**memory usage: 110.5 GB**

按块加载数据帧

显然,加载如此大的 CSV 文件是一件费时费力的事情(如果一开始就有可能的话)。因此,必须有更好的方法来优化流程。

问自己的第一个问题是:您真的需要 CSV 文件中的所有行和列吗?例如,您可能只需要起始机场为 ATL 的所有行,而忽略其余的行。但是,将整个 CSV 文件加载到一个数据帧中,只删除所有不需要的行,这种做法是不可取的,因为您的计算机可能甚至没有足够的内存来容纳整个数据帧。这就是分块有用的地方。

分块允许您以较小的块(因此得名)加载数据帧,而不是一次性加载所有数据帧。每个块都是您正在加载的整个数据帧的子集,每个块的大小可以根据您的需要进行定制。当加载每个块时,您有机会过滤数据帧中的行或列,并仅保留那些您需要进行进一步分析的行或列。

要对数据帧进行分块,使用read_csv()函数中的chunksize参数:

import time
import pandas as pd

start = time.time()
chunks = pd.read_csv('itineraries.csv', chunksize=100000)
print(time.time() - start, ' seconds')

# result is a TextFileReader object
chunks

在上面的代码中,当您运行它时,控件几乎立即返回,输出显示chunks变量的类型是pandas.io.parsers.readers.TextFileReader

chunks想象成一个指向 CSV 文件中第一行的文件指针,它准备开始读取前 100,000 行(如chunksize参数中所指定的)。

事实上,chunks是一个 iterable ,您可以遍历它将 CSV 文件中的所有行加载到一个 dataframe 中,一次 100,000 行。

为了查看如何遍历chunks变量,让我们定义一个名为process_chunk()的函数,其中我将只获取startingAirport列的值为“ ATL ”的所有行:

def process_chunk(df):
    df = df.query('startingAirport == "ATL"') 
    print(df.shape)
    return df

如果您愿意,也可以在此函数中过滤列。

以下代码片段显示了如何使用chunks iterable 加载整个 CSV 文件:

chunk_list = []                # used for storing dataframes
for chunk in chunks:           # each chunk is a dataframe    
    # perform data filtering 
    filtered_chunk = process_chunk(chunk)

    # Once the data filtering is done, append the filtered chunk to list
    chunk_list.append(filtered_chunk)

对于chunks变量的每次迭代,chunk迭代器将包含一个包含 100,000 行的数据帧。然后数据帧被传入process_chunk(),在那里进行过滤。当过滤后的数据帧返回时,它被附加到一个名为chunk_list的列表中。

要组合列表中的所有数据帧,使用concat()函数:

# concat all the dfs in the list into a single dataframe 
df_concat = pd.concat(chunk_list)

让我们打印出加载的最终数据帧:

display(df_concat)

您将看到最终的数据帧包含 5,312,028 行。

通过使用分块,您现在可以有选择地将 CSV 的一部分加载到数据帧中,而不是尝试从整个 CSV 文件中加载所有内容。

检查数据帧的内存占用

我们的数据帧现在有 500 万行,而不是原来的 8200 万行,这是一个更易于管理的大小。让我们看看它使用了多少内存:

df_concat.info()

注意输出的最后一行:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 5312028 entries, 0 to 82137143
Data columns (total 27 columns):
 #   Column                             Dtype  
---  ------                             -----  
 0   legId                              object 
 1   searchDate                         object 
 2   flightDate                         object 
 3   startingAirport                    object 
 4   destinationAirport                 object 
 5   fareBasisCode                      object 
 6   travelDuration                     object 
 7   elapsedDays                        int64  
 8   isBasicEconomy                     bool   
 9   isRefundable                       bool   
 10  isNonStop                          bool   
 11  baseFare                           float64
 12  totalFare                          float64
 13  seatsRemaining                     int64  
 14  totalTravelDistance                float64
 15  segmentsDepartureTimeEpochSeconds  object 
 16  segmentsDepartureTimeRaw           object 
 17  segmentsArrivalTimeEpochSeconds    object 
 18  segmentsArrivalTimeRaw             object 
 19  segmentsArrivalAirportCode         object 
 20  segmentsDepartureAirportCode       object 
 21  segmentsAirlineName                object 
 22  segmentsAirlineCode                object 
 23  segmentsEquipmentDescription       object 
 24  segmentsDurationInSeconds          object 
 25  segmentsDistance                   object 
 26  segmentsCabinCode                  object 
dtypes: bool(3), float64(3), int64(2), object(19)
**memory usage: 1.0+ GB**

1+ GB 的内存使用量只是一个估计。要查看完整的内存使用情况,您需要将memory_usage参数设置为deep:

df_concat.info(memory_usage='deep')

结果现在显示实际内存占用为 7.1 GB:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 5312028 entries, 0 to 82137143
Data columns (total 27 columns):
 #   Column                             Dtype  
---  ------                             -----  
 0   legId                              object 
 1   searchDate                         object 
 2   flightDate                         object 
 3   startingAirport                    object 
 4   destinationAirport                 object 
 5   fareBasisCode                      object 
 6   travelDuration                     object 
 7   elapsedDays                        int64  
 8   isBasicEconomy                     bool   
 9   isRefundable                       bool   
 10  isNonStop                          bool   
 11  baseFare                           float64
 12  totalFare                          float64
 13  seatsRemaining                     int64  
 14  totalTravelDistance                float64
 15  segmentsDepartureTimeEpochSeconds  object 
 16  segmentsDepartureTimeRaw           object 
 17  segmentsArrivalTimeEpochSeconds    object 
 18  segmentsArrivalTimeRaw             object 
 19  segmentsArrivalAirportCode         object 
 20  segmentsDepartureAirportCode       object 
 21  segmentsAirlineName                object 
 22  segmentsAirlineCode                object 
 23  segmentsEquipmentDescription       object 
 24  segmentsDurationInSeconds          object 
 25  segmentsDistance                   object 
 26  segmentsCabinCode                  object 
dtypes: bool(3), float64(3), int64(2), object(19)
**memory usage: 7.1 GB**

为什么会有巨大的差异?为了理解为什么,让我们使用memory_usage()函数来看看每一列使用了多少内存:

df_concat.memory_usage()

有趣的是,似乎所有的列(除了三个bool列——是基础经济是可归还的是不停止的)都使用相同数量的内存:

Index                                42496224
legId                                42496224
searchDate                           42496224
flightDate                           42496224
startingAirport                      42496224
destinationAirport                   42496224
fareBasisCode                        42496224
travelDuration                       42496224
elapsedDays                          42496224
isBasicEconomy                        5312028
isRefundable                          5312028
isNonStop                             5312028
baseFare                             42496224
totalFare                            42496224
seatsRemaining                       42496224
totalTravelDistance                  42496224
segmentsDepartureTimeEpochSeconds    42496224
segmentsDepartureTimeRaw             42496224
segmentsArrivalTimeEpochSeconds      42496224
segmentsArrivalTimeRaw               42496224
segmentsArrivalAirportCode           42496224
segmentsDepartureAirportCode         42496224
segmentsAirlineName                  42496224
segmentsAirlineCode                  42496224
segmentsEquipmentDescription         42496224
segmentsDurationInSeconds            42496224
segmentsDistance                     42496224
segmentsCabinCode                    42496224
dtype: int64

通过一些简单的计算,可以看到所有这些列(除了三个bool列)中的每一行都使用了 8 个字节(42496224 字节/ 5312028 行)。为什么会这样呢?对于类型为int64float64的列,这是合理的,因为 64 位等于 8 个字节。例如,elapseday列的每个值将占用 8 个字节(int64):

那些object栏目怎么样?在内部,对象列将它们的值分别存储在其他内存位置。所以为一个object列存储的实际值实际上是存储object值的位置的内存地址。下面是一个搜索日期列的示例,它属于object类型:

为了准确地找出一个object列使用了多少存储,您需要将memory_usage()函数中的deep参数设置为True:

df_concat.memory_usage(deep=True)

输出现在更准确地显示了每一列使用了多少内存:

Index                                 42496224
legId                                472770492
searchDate                           355905876
flightDate                           355905876
startingAirport                      318721680
destinationAirport                   318721680
fareBasisCode                        343071603
travelDuration                       339818490
elapsedDays                           42496224
isBasicEconomy                         5312028
isRefundable                           5312028
isNonStop                              5312028
baseFare                              42496224
totalFare                             42496224
seatsRemaining                        42496224
totalTravelDistance                   42496224
segmentsDepartureTimeEpochSeconds    403417584
segmentsDepartureTimeRaw             579572987
segmentsArrivalTimeEpochSeconds      403417584
segmentsArrivalTimeRaw               579572987
segmentsArrivalAirportCode           338518225
segmentsDepartureAirportCode         338518225
segmentsAirlineName                  410952127
segmentsAirlineCode                  329246888
segmentsEquipmentDescription         438243766
segmentsDurationInSeconds            350013948
segmentsDistance                     341426543
segmentsCabinCode                    357085873
dtype: int64

例如, searchDate 列中的每个值使用 67 字节(355905876 字节/ 5312028 行), startingAirport 列中的每个值使用 60 字节(318721680 字节/ 5312028 行)。

转换类型

从上一节可以看出,两列使用的内存— searchDateflightDate ,每个值(这是一个日期)在存储为object类型时占用 67 个字节。由于这些列包含日期,将它们存储为object类型是低效的,因为以后操作它们会很困难。与其这样,不如把它们转换成datetime64型。这样做还可以节省内存,因为它们现在每个只占用 8 个字节。

现在让我们将这些列转换成datetime64类型:

df_concat["searchDate"] = df_concat["searchDate"].astype('datetime64')
df_concat["flightDate"] = df_concat["flightDate"].astype('datetime64')

现在,您可以检查每一列的内存使用情况:

df_concat.memory_usage(deep=True)

您现在可以看到两列的内存使用都减少到了 42496224 字节。每个值按预期占用 8 个字节(42496224 个字节/ 5312028 行):

Index                                 42496224
legId                                472770492
**searchDate                            42496224
flightDate                            42496224** startingAirport                      318721680
destinationAirport                   318721680
fareBasisCode                        343071603
travelDuration                       339818490
elapsedDays                           42496224
isBasicEconomy                         5312028
isRefundable                           5312028
isNonStop                              5312028
baseFare                              42496224
totalFare                             42496224
seatsRemaining                        42496224
totalTravelDistance                   42496224
segmentsDepartureTimeEpochSeconds    403417584
segmentsDepartureTimeRaw             579572987
segmentsArrivalTimeEpochSeconds      403417584
segmentsArrivalTimeRaw               579572987
segmentsArrivalAirportCode           338518225
segmentsDepartureAirportCode         338518225
segmentsAirlineName                  410952127
segmentsAirlineCode                  329246888
segmentsEquipmentDescription         438243766
segmentsDurationInSeconds            350013948
segmentsDistance                     341426543
segmentsCabinCode                    357085873
dtype: int64

我们现在想知道数据帧的内存占用量:

df_concat.info(memory_usage='deep')

它现在已从 7.1 GB 减少到 6.5 GB:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 5312028 entries, 0 to 82137143
Data columns (total 27 columns):
 #   Column                             Dtype         
---  ------                             -----         
 0   legId                              object        
 **1   searchDate                         datetime64[ns]
 2   flightDate                         datetime64[ns]**
 3   startingAirport                    object        
 4   destinationAirport                 object        
 5   fareBasisCode                      object        
 6   travelDuration                     object        
 7   elapsedDays                        int64         
 8   isBasicEconomy                     bool          
 9   isRefundable                       bool          
 10  isNonStop                          bool          
 11  baseFare                           float64       
 12  totalFare                          float64       
 13  seatsRemaining                     int64         
 14  totalTravelDistance                float64       
 15  segmentsDepartureTimeEpochSeconds  object        
 16  segmentsDepartureTimeRaw           object        
 17  segmentsArrivalTimeEpochSeconds    object        
 18  segmentsArrivalTimeRaw             object        
 19  segmentsArrivalAirportCode         object        
 20  segmentsDepartureAirportCode       object        
 21  segmentsAirlineName                object        
 22  segmentsAirlineCode                object        
 23  segmentsEquipmentDescription       object        
 24  segmentsDurationInSeconds          object        
 25  segmentsDistance                   object        
 26  segmentsCabinCode                  object        
dtypes: bool(3), datetime64[ns](2), float64(3), int64(2), object(17)
**memory usage: 6.5 GB**

将与日期相关的列转换为datetime64类型不仅可以节省内存,还可以更容易地执行数据分析。

向下浇铸的柱子

我们可以对 dateframe 进行的下一个改进是向下转换所有的数字字段。考虑一下座位保留栏。如果您检查该列中的值范围(最小和最大),您将看到最小值为 0,最大值为 10:

df_concat['seatsRemaining'].min() # 0 
df_concat['seatsRemaining'].max() # 10

然而,一个int64类型被用来存储这个列。一个int64列可以存储从-(2⁶-1)到 2⁶的值。显然,这种数据类型对于该列来说是一种大材小用,因为它只存储非负值,并且最大值不超过 10。这同样适用于其他列,例如基本费用总费用,以及总行程距离。为了减少这种内存浪费,我们需要将这种列使用的类型向下转换为仅足以保存它们的值的类型。例如, seatsRemaining 列可以很好地处理uint8数据类型,它可以保存从 0 到(2⁸-1)或 0 到 255 的值。

现在让我们尝试向下转换所有的数字列(整数和浮点)。

首先,定义一个名为memory_usage()的函数来接收 Pandas 数据帧或序列,并返回其总内存使用量:

def mem_usage(obj):
    if isinstance(obj, pd.DataFrame):
        usage_b = obj.memory_usage(deep=True).sum()
    else: # we assume if not a df then it's a series
        usage_b = obj.memory_usage(deep=True)

    usage_mb = usage_b / 1024 ** 2     # bytes to megabytes    
    return "{:03.2f} MB".format(usage_mb)

接下来,定义一个名为downcast_type()的函数来接收一个数据帧,并将一种类型的列转换为一种新的类型:

def downcast_type(df, old_type, new_type):
    # get all the columns with the specified type – old_type
    df_oldtype = df.select_dtypes(include=[old_type])

    # convert all the columns from old_type to new_type
    df_newtype = df_oldtype.apply(pd.to_numeric, downcast=new_type)

    # print out the memory usage of old_type and new_type
    print(f'{old_type} memory usage: {mem_usage(df_oldtype)}')
    print(f'{new_type} memory usage: {mem_usage(df_newtype)}')

    return df_newtype

apply()函数中的downcast参数根据以下规则将结果数据向下转换为可能的最小数字数据类型:

  • integersigned’:最小有符号整数类型(min。:np.int8)
  • unsigned':最小的无符号整型数据类型(min。:np.uint8)
  • float':最小浮点数据类型(min。:np.float32)

来源:https://pandas . pydata . org/docs/reference/API/pandas . to _ numeric . html

让我们尝试将所有整数列向下转换为无符号的:

df_converted_int = downcast_type(df_concat, "int", "unsigned")

对于 Windows,将上述语句中的“int”替换为“int64

您将看到以下输出:

int memory usage: 121.58 MB
unsigned memory usage: 50.66 MB

这意味着数据帧中所有整数列的内存已从 121.58 MB 减少到 50.66 MB。

让我们也向下转换所有浮点列:

df_converted_float = downcast_type(df_concat, "float", "float")

输出显示了这些浮点列的内存使用量的减少:

float memory usage: 162.11 MB
float memory usage: 101.32 MB

我现在将在df_concat中创建一个 dataframe 的副本,然后替换所有已经向下转换的列:

# make a copy of the dataframe and replace the columns with the downcasted types
optimized_df = df_concat.copy()
optimized_df[df_converted_int.columns] = df_converted_int
optimized_df[df_converted_float.columns] = df_converted_float

您可以检查类型已向下转换的各种列:

optimized_df.info(memory_usage='deep')

以下粗体输出显示了已向下转换的列:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 5312028 entries, 0 to 82137143
Data columns (total 27 columns):
 #   Column                             Dtype         
---  ------                             -----         
 0   legId                              object        
 1   searchDate                         datetime64[ns]
 2   flightDate                         datetime64[ns]
 3   startingAirport                    object        
 4   destinationAirport                 object        
 5   fareBasisCode                      object        
 6   travelDuration                     object        
 **7   elapsedDays                        uint8** 
 8   isBasicEconomy                     bool          
 9   isRefundable                       bool          
 10  isNonStop                          bool          
 **11  baseFare                           float32       
 12  totalFare                          float32       
 13  seatsRemaining                     uint8**      
 **14  totalTravelDistance                float32** 
 15  segmentsDepartureTimeEpochSeconds  object        
 16  segmentsDepartureTimeRaw           object        
 17  segmentsArrivalTimeEpochSeconds    object        
 18  segmentsArrivalTimeRaw             object        
 19  segmentsArrivalAirportCode         object        
 20  segmentsDepartureAirportCode       object        
 21  segmentsAirlineName                object        
 22  segmentsAirlineCode                object        
 23  segmentsEquipmentDescription       object        
 24  segmentsDurationInSeconds          object        
 25  segmentsDistance                   object        
 26  segmentsCabinCode                  object        
dtypes: bool(3), datetime64[ns](2), float32(3), object(17), uint8(2)
**memory usage: 6.4 GB**

内存占用进一步减少到 6.4 GB。

向下转换通过自动检查每一列中的值的范围并将该列转换为足以容纳现有值的数据类型来帮助您节省内存。

将对象类型转换为类别

数据帧的内存占用仍然相对较大。真正的罪魁祸首是我们前面看到的那些类型为object的列。

让我们找到所有这些object列,并更详细地检查它们:

# get all the columns with the Object type
df_obj = optimized_df.select_dtypes(include=['object']).copy()
df_unique_objs = df_obj.describe()

print(df_unique_objs)

以下是输出结果:

 legId startingAirport destinationAirport  \
count                            5312028         **5312028**            **5312028**   
unique                            362460               **1**                 **15**   
top     3c18dd8a485f8f15b31e68982f53db00             ATL                LAX   
freq                                  60         5312028             709809   

       fareBasisCode travelDuration segmentsDepartureTimeEpochSeconds  \
count        5312028        5312028                           5312028   
unique          6035           1480                            320710   
top         KAUOA0MQ        PT2H15M                        1663672500   
freq          107336          79204                               377   

             segmentsDepartureTimeRaw segmentsArrivalTimeEpochSeconds  \
count                         5312028                         5312028   
unique                         321658                          344387   
top     2022-09-20T07:15:00.000-04:00                      1661900340   
freq                              377                             237   

               segmentsArrivalTimeRaw segmentsArrivalAirportCode  \
count                         5312028                    5312028   
unique                         348155                       1439   
top     2022-08-30T18:59:00.000-04:00                        LGA   
freq                              237                     192573   

       segmentsDepartureAirportCode segmentsAirlineName segmentsAirlineCode  \
count                       5312028             5312028             5312028   
unique                          637                  59                  59   
top                             ATL               Delta                  DL   
freq                        1754883             1031841             1031841   

       segmentsEquipmentDescription segmentsDurationInSeconds  \
count                       5155578                   5312028   
unique                         2514                     24456   
top                     Airbus A321                      8100   
freq                         427699                     79204   

       segmentsDistance segmentsCabinCode  
count           5312028           5312028  
unique             1352                34  
top          None||None      coach||coach  
freq             556848           3168404 

这样做是为了查看每个object列中唯一值的数量。例如,考虑只有 1 个唯一值的 startingAirport 列(这是 ATL)。

你甚至可能会争辩说,我们可以完全删除这个开始机场专栏!但是为了清楚起见,我将保留这个专栏。

在这种情况下,在 dataframe 中存储字符串" ATL" 5312028 次并不是一个非常明智的选择。同样,对于 destinationAirport 列,只有 15 个唯一值,因此该列中存储了大量重复值。

与其存储所有这些重复值,不如将像 startingAirportdestinationAirport 这样的列转换为category数据类型。在category数据类型中,列中的唯一值存储在单独的引用表中,值的索引存储在该列中。下图说明了这一概念:

通过将object列转换为category类型,可以节省大量的内存。然而,有一个警告。如果一个列包含许多唯一值,那么将它转换成一个category字段不会节省任何内存——事实上它会使用更多的内存。因此,我想计算每个object列的唯一值的百分比:

df_unique_objs.iloc[1,:] / df_unique_objs.iloc[0,:] * 100

如果一列中超过 50%的值是唯一的,继续使用object类型比将它们转换为category类型更可行。以下输出显示没有一个object列具有超过 50%的唯一性:

legId                                6.823383
startingAirport                      0.000019
destinationAirport                   0.000282
fareBasisCode                         0.11361
travelDuration                       0.027861
segmentsDepartureTimeEpochSeconds    6.037431
segmentsDepartureTimeRaw             6.055277
segmentsArrivalTimeEpochSeconds      6.483155
segmentsArrivalTimeRaw               6.554088
segmentsArrivalAirportCode           0.027089
segmentsDepartureAirportCode         0.011992
segmentsAirlineName                  0.001111
segmentsAirlineCode                  0.001111
segmentsEquipmentDescription         0.048763
segmentsDurationInSeconds            0.460389
segmentsDistance                     0.025452
segmentsCabinCode                     0.00064
dtype: object

我们现在可以将object列转换为category数据类型:

df_obj_cat = df_obj.astype('category')

一旦列被转换,将其分配回optimized_df数据帧:

optimized_df[df_obj_cat.columns] = df_obj_cat

我们现在可以检查每一列的内存使用情况:

optimized_df.memory_usage(deep=True)

我们可以直接看到,以前的各种- object列现在使用的内存要少得多:

Index                                42496224
legId                                61961236
searchDate                           42496224
flightDate                           42496224
**startingAirport                       5312196
destinationAirport                    5313484
fareBasisCode                        11147023
travelDuration                       10752574**
elapsedDays                           5312028
isBasicEconomy                        5312028
isRefundable                          5312028
isNonStop                             5312028
baseFare                             21248112
totalFare                            21248112
seatsRemaining                        5312028
totalTravelDistance                  21248112
**segmentsDepartureTimeEpochSeconds    55265918
segmentsDepartureTimeRaw             67923918
segmentsArrivalTimeEpochSeconds      57071505
segmentsArrivalTimeRaw               70785925
segmentsArrivalAirportCode           10755425
segmentsDepartureAirportCode         10684758
segmentsAirlineName                   5319331
segmentsAirlineCode                   5318025
segmentsEquipmentDescription         10949169
segmentsDurationInSeconds            12869511
segmentsDistance                     10750114
segmentsCabinCode                     5315719**
dtype: int64

例如, startingAirport 列的每个值现在平均使用大约 1 个字节(5312196 字节/ 5312028 行)。

让我们检查一下优化数据帧的最终占用空间:

optimized_df.info(memory_usage='deep')

我们的数据帧的最终内存占用是 605.9 MB,而它的初始大小是 7.1 GB!

<class 'pandas.core.frame.DataFrame'>
Int64Index: 5312028 entries, 0 to 82137143
Data columns (total 27 columns):
 #   Column                             Dtype         
---  ------                             -----         
 0   legId                              category      
 1   searchDate                         datetime64[ns]
 2   flightDate                         datetime64[ns]
 3   startingAirport                    category      
 4   destinationAirport                 category      
 5   fareBasisCode                      category      
 6   travelDuration                     category      
 7   elapsedDays                        uint8         
 8   isBasicEconomy                     bool          
 9   isRefundable                       bool          
 10  isNonStop                          bool          
 11  baseFare                           float32       
 12  totalFare                          float32       
 13  seatsRemaining                     uint8         
 14  totalTravelDistance                float32       
 15  segmentsDepartureTimeEpochSeconds  category      
 16  segmentsDepartureTimeRaw           category      
 17  segmentsArrivalTimeEpochSeconds    category      
 18  segmentsArrivalTimeRaw             category      
 19  segmentsArrivalAirportCode         category      
 20  segmentsDepartureAirportCode       category      
 21  segmentsAirlineName                category      
 22  segmentsAirlineCode                category      
 23  segmentsEquipmentDescription       category      
 24  segmentsDurationInSeconds          category      
 25  segmentsDistance                   category      
 26  segmentsCabinCode                  category      
dtypes: bool(3), category(17), datetime64[ns](2), float32(3), uint8(2)
**memory usage: 605.9 MB**

随着数据帧的内存占用大大减少,现在对数据帧执行数据分析应该会更加容易和快速。

将对象列转换为类别类型通常会节省大量内存。

持久化优化的数据帧

如果您费尽心思过滤数据帧并优化其内存占用,那么您最不想做的事情就是使用 CSV 格式将数据帧保存回存储器!如果您这样做,下次您将 CSV 加载回数据帧时,您辛苦执行的所有优化都将付诸东流。更聪明的方法是通过to_pickle()函数使用 Pickle 保存它:

optimized_df.to_pickle('optimized_df.pkl')

Pickle 使用二进制模式将您的数据帧序列化到存储中,不像另存为 CSV 那样将数据保存为纯文本。

要验证所有优化都没有浪费,请加载回 pickle 文件,并验证新加载的数据帧的数据类型:

df = pd.read_pickle('optimized_df.pkl')
df.info(memory_usage='deep')

您将意识到,现在产生的内存占用比以前更小(605.9 MB):

<class 'pandas.core.frame.DataFrame'>
Int64Index: 5312028 entries, 0 to 82137143
Data columns (total 27 columns):
 #   Column                             Dtype         
---  ------                             -----         
 0   legId                              category      
 1   searchDate                         datetime64[ns]
 2   flightDate                         datetime64[ns]
 3   startingAirport                    category      
 4   destinationAirport                 category      
 5   fareBasisCode                      category      
 6   travelDuration                     category      
 7   elapsedDays                        uint8         
 8   isBasicEconomy                     bool          
 9   isRefundable                       bool          
 10  isNonStop                          bool          
 11  baseFare                           float32       
 12  totalFare                          float32       
 13  seatsRemaining                     uint8         
 14  totalTravelDistance                float32       
 15  segmentsDepartureTimeEpochSeconds  category      
 16  segmentsDepartureTimeRaw           category      
 17  segmentsArrivalTimeEpochSeconds    category      
 18  segmentsArrivalTimeRaw             category      
 19  segmentsArrivalAirportCode         category      
 20  segmentsDepartureAirportCode       category      
 21  segmentsAirlineName                category      
 22  segmentsAirlineCode                category      
 23  segmentsEquipmentDescription       category      
 24  segmentsDurationInSeconds          category      
 25  segmentsDistance                   category      
 26  segmentsCabinCode                  category      
dtypes: bool(3), category(17), datetime64[ns](2), float32(3), uint8(2)
**memory usage: 564.7 MB**

如果您比较每一列的内存使用情况(见下文),请注意所有的category列现在使用的内存(从 pickle 文件重新加载后)比以前少得多。这很可能是由于 category 列从 pickle 文件直接加载时在内存中的加载和组织方式。

如果你喜欢阅读我的文章,并且认为它对你的职业/学习有所帮助,请考虑注册成为一名灵媒会员。每月 5 美元,你可以无限制地访问 Medium 上的所有文章(包括我的)。如果你使用下面的链接注册,我会赚一小笔佣金(不需要你额外付费)。你的支持意味着我将能够投入更多的时间来写这样的文章。

https://weimenglee.medium.com/membership

总结

在本文中,我介绍了一些技术,您可以在处理非常大的 CSV 数据文件时使用这些技术。具体来说,您了解到可以使用分块来按部分加载数据帧,而不是将整个 CSV 文件加载到数据帧中。这使您可以灵活地有选择地加载分析所需的行和列。此外,有几种技术可以用来减少数据帧的内存占用。通常,使用以下步骤来减少内存使用:

  • 将与日期相关的列转换为datetime64类型
  • 将所有数值类型向下转换为宽度足以容纳这些列中的值的类型
  • 如果可行,将所有的object列转换为category类型

使用这三个简单的技巧将会大大节省数据帧的内存使用。在自己的数据集上尝试一下,你会大吃一惊的!

有效解决 Wordle 的提示和技巧

原文:https://towardsdatascience.com/tips-and-tricks-for-solving-wordle-efficiently-28ab67a52dbf

使用 Wolfram 语言

随机选择的单词(图片由作者提供)

每次我玩 Wordle 的时候,我都会想起亚瑟·柯南·道尔笔下的夏洛克·福尔摩斯在解决另一个神秘难题时所说的话:

我跟你说过多少次了,当你排除了不可能,剩下的,不管多么不可思议,一定是事实。—夏洛克·福尔摩斯

Wordle 是一个新的日常文字游戏,挑战你在六轮或更少的回合中猜出一个五个字母的单词。输入一个猜测后,游戏会告诉你哪些字母是正确的,并且用绿色高亮显示在正确的位置。正确但不在正确位置的字母用黄色表示。使用这些信息,您可以消除大量的单词,并在每一轮中做出更好的猜测来解决游戏。和夏洛克·福尔摩斯一样,你也在和时间赛跑,因为你必须在六个回合中解决这个游戏。

在这篇文章中,我将使用计算方法来探索有效解决这个游戏的方法。虽然我自己不直接使用这些方法来解决日常的 Wordle 游戏(那有什么乐趣呢?!),做这个分析让我对游戏如何在“幕后”运作有了深入的了解。因此,我觉得这些见解帮助我更好地玩游戏,并给我更好的结果。

每一轮 Wordle 都会对你的猜测给出反馈,所以你将能够推断出越来越多的关于解决方案的信息。具体来说,您将了解以下信息:

  • 溶液中的字母
  • 不在溶液中的字母
  • 某些字母出现的地方
  • 某些字母没有出现的地方
  • 一个字母在解决方案中出现的次数

解释这个列表上的最后一项:如果你猜单词“RADAR ”,而 Wordle 用一个标有绿色或黄色的“A”来回答,那么你就知道这个解决方案中只有一个“A”。用一个有五个不同字母的单词开始你的第一次猜测是一个很好的策略,可以覆盖尽可能多的范围。但是解决单词经常包含重复的字母,所以在游戏的某个时候,你需要切换到猜测一个可能重复的字母。

解决 Wordle 的方法有很多。我认识的大多数人都是从一个随机的词开始,然后根据你得到的线索继续下去。其他人使用相同的两个初始猜测,例如“RAISE”和“CLOUD”包含许多在英语中很常见的字母。

从包含英语中常见字母的单词开始,依赖于字母频率表。例如,单词“RATES”比单词“EPOXY”包含更多的普通字母。从一个有共同字母的单词开始是一个好方法,因为它可以让你快速消除许多单词:

如果你用最常见的字母来选一个单词,而这些字母中有一个或多个不在答案中,那么你已经确定了大量不可能的答案。这大大减少了可能的解决方案的数量,这使得在下一轮中更有可能选择正确的解决方案。

所以关注字母频率应该是获胜策略的一部分。

英语(或任何其他语言)中的任意单词都有字母频率表,但这里我们只需要考虑英语词典中一个非常特殊的子集:Wordle 接受的五个字母单词。

Wordle 有自己独特的五个字母的单词字典,包含 12,972 个单词。通过从下面的数据仓库对象加载数据,您可以方便地获得这个用 Wolfram 语言编写的单词列表:

words = ResourceData[
  ResourceObject["Wordle Word List"]
]

我们可以检查这个列表中有哪些单词:

RandomSample[words,10] Out[] = {
  "mawns", "alary", "maare", 
  "lower", "cesta", "muggy", 
  "mayed", "broth", "taler", 
  "brags"
}

有一些显而易见的英语单词,如“lower”、“muggy”、“broth”和“brags”,但这个单词列表还包括一些非常模糊的单词,如“maare”和“alary”。我不知道这个 Wordle 单词列表的来源,所以我们只从表面上看这个列表,并用它来玩游戏。我应该指出,这个列表中有一个子集包含了未来几年的实际解决方法。在这篇文章中,我选择忽略解决词的子集,因为我认为这太“欺骗”了。

使用 Wolfram 语言,我们可以通过将所有单词连接成一个非常长的 64,860 个字母的字符串(12,972 个单词,每个单词有 5 个字母)并使用 CharacterCounts 函数查看每个字母出现的频率来获得单词的整体字母分布:

KeySort[CharacterCounts[StringJoin[words]]] Out[] = <|
  "a" -> 5990, "b" -> 1627, "c" -> 2028, "d" -> 2453, 
  "e" -> 6662,  "f" -> 1115, "g" -> 1644, "h" -> 1760, 
  "i" -> 3759, "j" -> 291,  "k" -> 1505, "l" -> 3371, 
  "m" -> 1976, "n" -> 2952, "o" -> 4438,  "p" -> 2019, 
  "q" -> 112, "r" -> 4158, "s" -> 6665, "t" -> 3295,  
  "u" -> 2511, "v" -> 694, "w" -> 1039, "x" -> 288, 
  "y" -> 2074,  "z" -> 434
|>

因此:string joins 将所有 12,972 个单词放在一个字符串中,然后characters counts计算每个字母出现的次数。然后键排序函数将结果按字母顺序排序。

我们可以看到,字母 Q 并不常见(在所有单词中只出现了 112 次),字母 E 非常常见(出现了 6662 次)。这里有一个条形图显示所有的字母计数:

(图片由作者提供)

我们可以更进一步,看看在一个五个字母的单词中,每个字母在特定的位置上有多常见。比如第三个位置的字母“E”有多常见?下面是实现这一点的 Wolfram 语言代码:

Dataset[
  Map[  
    Join[
      AssociationThread[CharacterRange["a", "z"] -> 0], 
      Counts[#]
    ] &,   
    Transpose[Map[Characters, words]]
  ], 
  Alignment -> Right,  
  MaxItems -> {All, All}
]

这段代码看起来有点复杂,但它只是计算了每个字母在一个五个字母的单词中的特定位置出现的次数。它在笔记本中给出以下输出:

(图片由作者提供)

例如,给定单词列表,字母“E”出现在第三个位置的次数是 882 次。这是该表的一个视觉上更吸引人的版本:

(图片由作者提供)

现在我们有了这个值表,我们可以根据每个字母在特定位置的常见程度给每个五个字母的单词打分。例如,单词“RAISE”的得分为 628+2263+1051+516+1522=5980。这是通过在表格的相应行中查找字母来计算的。例如,单词 S 中的第四个字母在表的第四行中的值为 516。

给每个单词分配一个分数给你一个排列单词的方法。得分高的单词在它们出现最多的地方有普通字母。

我们可以对任何五个字母的单词列表中的每个单词进行这种“得分”计算,下面的 Wolfram 语言代码就是这样做的。它看起来有点复杂,但它所做的只是查看列表中的每个单词,并计算其分数:

wordScores[words_] := Module[{letters, a, e},  
  letters = CharacterRange["a", "z"];  
  a = Map[    
    Values[      
      Join[
        AssociationThread[CharacterRange["a", "z"] -> 0],
        KeySort[Counts[#]]]] &, 
    Transpose[Map[Characters, words]]
  ];  
  Echo[Grid[a]];  
  Map[   
    Function[{word},    
      e = Transpose[{
        Range[5],        
        Flatten[Position[letters, #] & /@ Characters[word]]
      }];    
      word -> Total[Extract[a, e]]    
    ],   
    words
  ]  
]

当我们用初始单词列表调用这个“wordScores”函数时,我们得到如下结果:

wordleScores = wordScores[words];
Take[ReverseSortBy[wordleScores, Last], 25] Out[] = {
  "sores" -> 11144, "sanes" -> 11077, "sales" -> 10961,  
   "sones" -> 10910, "soles" -> 10794, "sates" -> 10729,  
   "seres" -> 10676, "cares" -> 10668, "bares" -> 10655,  
   "sames" -> 10624, "pares" -> 10605, "tares" -> 10561,  
   "sades" -> 10503, "cores" -> 10501, "bores" -> 10488,  
   "sages" -> 10477, "sabes" -> 10448, "senes" -> 10442,  
   "mares" -> 10439, "pores" -> 10438, "canes" -> 10434,  
   "sires" -> 10431, "dares" -> 10431, "banes" -> 10421,  
   "tores" -> 10394
}

得分最高的单词是“疮”,这是有意义的,因为所有的字母都非常常见,并且出现在非常常见的地方(例如,许多单词都以字母 S 结尾)。在这篇文章中,我没有过滤掉重复字母的单词,比如“疮”。有些人在最初的猜测中更喜欢五个不同的字母,这只是我在这里采用的方法的一个微小的变化。没有重复字母的得分最高的词是“关心”。

好的开头词,字母得分高,没有重复的字母(图片由作者提供)

所以现在我们可以用“疼痛”作为一个实际的单词游戏的起点:

(图片由作者拍摄)

我们从游戏反馈中可以得出的结论是,单词中没有出现字母 S、R、E,但是字母 O 确实出现了,而且出现在第二个位置。我们可以编写一小段代码来删除所有不可能的解决方案,并得到一个 520 个单词的列表,它仍然可以是一个解决方案:

words2 = Select[words,    
  And[
    Not[StringContainsQ[#, "s" | "r" | "e"]],      
    StringTake[#, {2}] == "o"
  ] &
]; 
Length[words2] Out[]= 520

我们可以再次计算得分最高的单词,但现在基于剩余的 520 个单词:

scores2 = wordScores[words2]; 
Take[ReverseSortBy[scores2, Last], 25] Out[] = {
  "cooly" -> 882, "booay" -> 862, "colly" -> 856,  
  "cooky" -> 853, "mooly" -> 850, "dooly" -> 849, 
  "conky" -> 848,  "copay" -> 845, "gooly" -> 844, 
  "coomy" -> 844, "ponty" -> 842,  "hooly" -> 841, 
  "booty" -> 839, "moony" -> 836, "monty" -> 834,  
  "polly" -> 832, "coaly" -> 831, "bonny" -> 831, 
  "loony" -> 830,  "hooty" -> 830, "goony" -> 830, 
  "donny" -> 830, "pongy" -> 829,  "poncy" -> 829, 
  "wooly" -> 827
}

这将产生以下结果:

(图片由作者拍摄)

没有新的“好”字母,但现在我们可以另外删除字母 C、L 和 y。我们现在还知道单词中只有一个 O:

words3 = Select[words2, 
  And[
    Not[StringContainsQ[#, "c" | "l" | "y"]], 
    StringCount[#, "o"] == 1
  ] &
]; 
Length[words3] Out[]= 117

因此,我们进一步将可能的单词列表减少到 117 个。现在最佳得分猜测是:

scores3 = wordScores[words3]; 
Take[ReverseSortBy[scores3, Last], 25] Out[]= {
  "gonna" -> 210, "donna" -> 208, "gonia" -> 201,  
  "ponga" -> 199, "donga" -> 196, "tonga" -> 195, 
  "honan" -> 194,  "honda" -> 193, "gonad" -> 192, 
  "downa" -> 191, "wonga" -> 190,  "tonka" -> 189, 
  "pound" -> 189, "monad" -> 189, "hound" -> 189,  
  "bonza" -> 187, "podia" -> 186, "fonda" -> 186, 
  "mound" -> 185,  "bound" -> 185, "donah" -> 184, 
  "douma" -> 183, "zonda" -> 182,  "tomia" -> 182, 
  "found" -> 182
}

我们选择得分最高的单词“goto”,这给了我们以下反馈:

(图片由作者拍摄)

附加信息是字母 G 和 A 没有出现在单词中。字母 N 出现在第四个位置,也是单词中唯一的字母 N。这给我们留下了 13 个可能的单词:

words4 = Select[words3,   
  And[
    Not[StringContainsQ[#, "g" | "a"]], 
    StringTake[#, {4}] == "n",     
    StringCount[#, "n"] == 1
  ] &
] Out[] = {
  "boink", "bound", "found", "fount", 
  "hound", "joint", "mound", "mount", 
  "poind", "point", "pound", "pownd", 
  "wound"} Length[words4] Out[] = 13

得分最高的词是:

scores4 = wordScores[words4]; 
ReverseSortBy[scores4, Last] Out[]= {
  "pound" -> 46, "mound" -> 44, "found" -> 44, 
  "bound" -> 44,  "wound" -> 43, "hound" -> 43, 
  "poind" -> 42, "mount" -> 40,  "fount" -> 40, 
  "pownd" -> 39, "point" -> 38, "joint" -> 35,  
  "boink" -> 33
}

所以让我们用“英镑”作为下一个猜测:

(图片由作者拍摄)

我们现在有三个已知的字母(OUN)和两个可以排除的字母(P 和 D)。这就把可能性归结为两个词:

words5 = Select[words4,    
  And[
    Not[StringContainsQ[#, "p" | "d"]],      
    StringTake[#, 2 ;; 4] == "oun"
  ] &
] Out[]= {"fount", "mount"}

两个单词的得分都是 9,所以我们可以选择其中一个:

scores5 = wordScores[words5]; 
ReverseSortBy[scores5, Last] Out[]= {"mount" -> 9, "fount" -> 9}

通过“安装”,我们得到了最终的解决方案:

(图片由作者拍摄)

如果“山”是错的,我们将只剩下“泉”作为最后的可能性,所以无论哪种方式,我们都将在六个回合内解决这个游戏!

就是这样!

“太棒了!我哭了。”初级,”他说。—华生医生和夏洛克·福尔摩斯

总结一下这个策略:我们将允许的 Wordle 单词列表加载到 Wolfram 语言中。然后我们计算了一个数值表,它代表了一个特定的字母在一个五个字母单词的特定位置出现的频率。使用这个表格,我们计算出一个高分数单词的列表,希望优化我们猜测这个单词的机会(或者确定尽可能多的字母)。

在每一轮游戏中,我们根据游戏的反馈机制删除“不可能”的单词,然后根据剩余的单词列表生成一个新的“最有可能”的单词。使用这种方法,我们系统地将可能性从 12972 减少到 520、117、13,最后减少到 2 个得分相等的单词。看看第一次猜测有多重要,很有意思。它排除了 95%以上的可能性。即使你的第一次猜测令人失望(根本没有匹配的字母),你仍然在排除很多很多单词。

虽然不能保证这种方法在六轮游戏中总能成功,但它确实在每轮系统地去除大量单词方面做得很好。

来自 Pexelscottonbro 摄影

节省数据分析师时间的技巧

原文:https://towardsdatascience.com/tips-for-saving-time-as-a-data-analyst-be4c2491068e

以下是我如何最大限度地提高效率的方法

一天中根本没有足够的时间。这是个问题。如果你和数据打交道,你就会知道当你在调试或解决问题时,8 小时的工作日会变成 9 小时或 10 小时。

已经 6 点多了??(米切尔·霍兰德在 Unsplash 上的照片)

为了节省时间,我将使这篇文章简明扼要——这里是我在处理数据时做的一些事情,以帮助自己变得更有效率(和更少压力)。

首先测试查询和检查记录计数

我在等待数据下载的项目上浪费了太多时间,只是为了意识到它不正确或者不是我需要的数据。如果使用大型数据集,那么必须检查表中的记录数,并在数据子集上测试查询。

以下是我开始使用新数据源时采取的典型步骤:

  1. 运行一个查询来查看前 10 条记录,以确认这看起来像是我需要的数据
  2. 运行查询来计算表中的记录数。然后与数据来自的源系统进行比较(如果可能的话)
  3. 如果我的查询很复杂——比如只选择具有最大装载日期的记录,其中交易日期是每月的第一天——我通过将结果限制在前 10 条左右的记录来测试查询逻辑。然后,我可能会根据某些值或我需要的任何其他值进行分组,以确保我设计查询的方式是正确的

此外,根据您用于分析的工具,将业务逻辑嵌入到数据库查询中可以使您的分析更有效。

利用并行处理

当我说“利用并行处理”时,我指的是更广泛的方式,而不仅仅是在机器学习建模的意义上。我“并行处理”的方式通常是在云(我使用 AWS)和本地机器上运行工作流。这样,如果我有一个需要长时间运行的工作流,我可以在云上设置它,然后在我的计算机上执行其他任务。

更好的方法是尽可能地实现自动化,这样,当您甚至没有登录到您的计算机时,流程就可以在服务器上运行,但是这并不总是可行的,并且在您仍然在开发您的数据清理/分析代码时,它不会有所帮助。

Max DuzijUnsplash 上拍摄的照片

此外,如果您同时使用本地和云环境,拥有多个屏幕是一个救命稻草。

全程组织和优化

我仍然在做一份工作——有时我会回到以前的工作,思考“我在这里到底在想什么?”所以,我一直在为自己开发一个文档系统(只是为了以后想参考的小项目或者工作)。对于较大的项目,您的团队可能已经有了一个组织标准或系统,您可以从中学习。

以下是一些帮助我保持条理的事情:

  • 总是给文件起描述性的名字
  • 为您可能仍想参考的旧文件创建一个归档文件夹。如果你知道你不需要它们,不要害怕删除它们!
  • 用文件夹来组织你工作的每个项目或主题的电子邮件,使交流参考更容易
  • 在代码本身内部记录注释,解释复杂的步骤并创建逻辑部分

我知道这些建议很简单,但是当我很忙,没有花时间来组织和记录我的工作时,我给自己制造的混乱令人惊讶。

至于优化,我通常会在项目接近尾声时然后考虑“我如何才能让数据处理得更快?”我的理论是,如果我在过程的每一步都考虑效率,而不是留到最后,这会让我的生活更轻松。再说一次,这是我正在做的事情。

自行调试后咨询团队成员

拉拉·阿兹利Unsplash 上的照片

当我独自努力解决工作中的一个问题几个小时,然后最终解决它的时候,我确实学到了很多。但是,如果我面临一个截止日期,我不想浪费时间。

有时候,只需要和同事打个电话,解释一下我的流程——当我大声说出来或者展示我的屏幕时,错误就出现在我面前,他们什么都不用说。其他时候,那些没有经常查看工作的人可能会通过问几个问题或者通读代码来发现问题。

无论如何,你的团队成员是宝贵的资源,可以帮助你更快地学习和改正错误。

我的希望是,至少我在这篇文章中概述的一个策略可以帮助你在工作日中获得更多的时间——并帮助你按时完成项目。

照片由 Unsplash 上的 Prateek Katyal 拍摄

如果你有节省时间的数据分析技巧,请在评论中留下,这样我们就可以互相学习了!感谢阅读。

如何有效学习深度强化学习的小技巧

原文:https://towardsdatascience.com/tips-on-how-to-learn-deep-reinforcement-learning-effectively-8578813ff23

可能会帮你节省时间的多年经验总结

帕特里克·托马索在 Unsplash 上的照片

不要只是学习,要体验。不要只是阅读,要吸收。

罗伊·t·贝内特《心中之光》

介绍

首先,免责声明:对一些人有用的,不一定对其他人有用。在这篇文章中,我揭示了在我花了几年时间阅读与强化学习相关的学术论文、书籍和源代码之后,什么对我有效。
一些读者可能会发现它,有用的其他人可能不会,但重要的是,通过分享,我相信我可能会帮助一些或一些很难进入 RL 的人。

这篇文章不能保证你会去理解每一本书或每一篇关于 RL 的论文,但是它会给你一个方法论,可能(就像我的情况)减轻学习的过程。

文章从一些基本的行为开始,这些行为是我们过去在学校经常做的,但是随着在线学习的普及,它已经越来越不像是一种条件反射了。

基本反射:记笔记

如果你不记得你过去在学校做了什么,那么,现在是时候做了:记笔记。

虽然在学校这是一件非常明显和自然的事情,然而在网络和视频学习的时代,这一基本行为经常被忽视!

在你旁边放一张纸,写下你在阅读或观看时遇到的所有定义或重要公式。相信我,你不会想通过上下滚动来记住那个符号是什么或者这个术语是什么意思。

除非你有过目不忘的记忆力,否则你肯定不会记得几页后的定义。更糟糕的是,你可能没有完全理解这个定义,所以你后来看到的可能与你自己的理解相矛盾,你需要再次检查以确保你得到了想要的意思。因此,把这份文件放在身边会节省你太多的时间。

你应该拿一支笔和一张纸,写下你所理解的内容,不要简单地抄袭。

最重要的是,不要将它们复制粘贴到另一个文档中,因为这对你自己没有任何好处。

此外,当您想要快速刷新关于算法的记忆,而不是从头到尾阅读几十页时,本文将作为一个备忘单供以后使用。

另一个基本条件反射:练习

还有一件在学校很常见,在网络学习的时代不知何故丢失了的事情,就是练习。

练习的方法有很多,但是效果较差的一种就是采用“假到做出来”的策略!我这么说的意思是“不知所云地”复制代码(或从 Github 下载)并运行它,而不试图理解它背后的概念,也不理解代码本身。如果你不知道自己在做什么,这种方法是行不通的。更不用说,如果你试图根据这种策略推销你的技能,一旦人们发现你并不真正了解自己的解决方案,就会适得其反!这会削弱他们对你的信心。记住方法或算法是不够的,需要的是能够理解它们是什么,以及为什么。

如果有时你不得不修改实现,你将需要理解其中的含义,当然,要能够解释结果并知道算法的边界。

所以实践包括理解算法的每个组成部分,理解代码,然后广泛地测试和调试它。

从普通强化学习开始

Deep RL 很吸引人,你可能会忍不住直接跳进水里开始游泳。通常,这是由于一些在线课程向你出售梦想。但这不是正确的方法(当然是在我看来)。

从表格方法开始,坚持做下去,直到它们成为你思维的有机组成部分。因为如果你不明白 Q-Learning 是什么,它代表了什么,再往前走就没有意义了。

q-学习:非策略 TD 控制(摘自萨顿和巴尔托的书:强化学习,介绍)

关于这个问题,可以去看看 DeepMind 或者大卫·西尔弗的 Youtube 课程。然后,先做所有的列表,必要时重复。

处理“深度”增加的复杂性

将神经网络添加到 RL 算法增加了它们的复杂性,因为有新的组件要馈送和训练。然而,抛开它们的技术特性,它们被插入来完成两个主要任务。因此,降低复杂性的一个方法是抽象地思考。

将神经网络想象成具有两个特征的黑匣子:

  • 如果给定输入,它产生的输出不像你希望的那样精确,这就引出了下一点。
  • 它可以更新其内部参数,以便“有希望”对相同的输入产生更好(更准确)的输出。

换句话说,借用表格方法,表的概念,但是一个非常大的概念,需要非常大的内存。有了这样的虚拟内存,您可以适应所有可能的(数百万或数十亿)状态和动作,以便为每个状态映射状态值和动作值。

但是既然你已经知道这在现实中是不可能的,那么就用占用内存少得多但结果不太准确的东西来代替它,例如,你得到的不是期望值 1,而是 0.85,0.90,1.10 或 1.20

在上面的例子中,近似值仍然是可以接受的,但这种情况很少发生。近似开始时非常不准确,然后随着迭代,野生随机数变得越来越准确。

因此,当你在科学论文中遇到神经网络时,不要陷入细节,只需将它想象为一个黑盒,它可以提供近似(理论上),随着时间的推移,通过学习过程会变得更好。

考虑这个深度反事实后悔最小化算法。你可能会直接对与神经网络相关的神秘符号和表达感到不安。

深度反事实后悔最小化论文,作者:n .布朗、a .勒尔、S .格罗斯、t .桑德霍尔姆(【https://arxiv.org/pdf/1811.00164.pdf】T4)

但是你可以这样读它们:

NN 短语的解释(图片由作者提供)

这样的解释使你更容易理解和减轻嵌入算法中的复杂性。你现在谈论的是黑盒的更新(很多人,尤其是开发者很容易理解)。
一旦你很好地理解了算法,你就可以实现它,并把黑盒看作是对做神经网络的特殊函数(单独编码)的调用。

创建图表

从算法中制作图形和草图是降低复杂性和识别其组件及其相互关系的一种方法。你可以单独想象每个组件,以及将它与其他组件联系起来的活动流或信息流,而不是记住一大堆行。
有了这种精神(或具体)的表示,就很容易推导出算法的代码。

下面是深度 Q 网络算法的图表,比起一堆代码或伪代码,你会更容易理解和记忆它。

DQN 工作流程(图片由作者提供)

请注意,每个组件都非常清晰,并且与其他组件分离开来,这使您很容易进行推理。您甚至可以尝试取出一个组件,用一个不同的、可能更好的组件来替换它,以测量性能。

橡皮鸭法

照片由 S. TsuchiyaUnsplash 上拍摄

最后,当你认为你准备好了,找个人告诉/教他们你学到了什么,最好是和你分享那种激情的朋友。

在那一刻,你可以接受测试,如果你真的掌握了材料或没有。你的朋友会问你问题,挑战你的知识,这会让你更多地思考你知道什么,你理解什么。

另一种方法是告诉你的橡皮鸭。这个方法来自橡皮鸭调试,我可以向你保证它有效。当你告诉其他人,包括一只橡皮鸭,一个问题被解决了多少次,你可能会感到惊讶,因为你强迫自己听你在说什么。因此,如果你没有人向你解释算法,就用大嗓门向你自己或你的鸭子解释,这样你就能清楚地听到自己的声音。

最后,关于它的博客或 vlog(视频日志)。别人在你之前做过多少次并不重要。把你的知识放在那里,试着获得反馈和问题,你可以反思和提高你的理解。事实上,你是在自己身上练习 RL,通过你得到的反馈来精炼和增强你对主题的理解。

博客/vlog 的另一个原因是不同的人对同一主题有不同的理解方式。所以你可能用一种吸引一些读者的方式解释了它。

编码和共享

在这个学习旅程的最后,最好是实现算法并展示给某人看。只为自己做没有任何好处,因为(很可能)你不会付出额外的长度和努力来使它工作或完善它。

不要只是从 GitHub 下载代码并运行它,这是没有道理的。就代码行而言,RL 算法并不庞大,所以花点时间来编写、测试和调试它,这样你就能发现与之相关的所有问题。

自己编写代码会让你想到每一个很可能让你的算法失败的实现细节,以防你没有恰当地处理它们。许多例子之一是忘记标准化神经网络的输入数据。

不要期望这个阶段会很顺利,即使你认为你掌握了算法,可能会有很多事情出错,你需要一个接一个地跟踪和修复它们。像 DQN 这样的小算法可能要花上好几天才能完成。所以保持动力,不要绝望。

共享代码或实现会无意识地促使你格外小心,并尽最大努力使其工作。即使没有人给你负面的反馈,但是如果你的代码做得很好,人们会开始使用它并在他们之间分享,最终,你会有一些人会因为你的工作而称赞你,因为它解决了他们的问题,这本身就是值得的。更不用说可能会有招聘人员在那边寻找像你这样的人,谁可以提供。

查看RL-lab.com关于如何与他人分享你的工作的例子。

结论

深度强化学习是一个艰难的课题,接近它具有挑战性,需要大量的耐心、投入和学习的动力。有效获取知识的方法之一是简化和隔离复杂的部分,然后通过实现和发布你的工作来保持动力。

关于熊猫、正则表达式和集合的提示

原文:https://towardsdatascience.com/tips-on-pandas-regex-collections-f2e8096d12d2

附有示例的实用指南

在之前关于数据清理和特征工程的文章中,我们经历了一些操作(应用、映射等)。)示例及其模拟运行时。

图片由 Taras ShypkaUnsplash 上拍摄

在本文中,我将分享对我的工作有帮助的其他例子,希望也能对你的工作有帮助。我们将会看一些例子…

  • 熊猫显示设置
  • 功能模式
  • 编译正则表达式
  • 词典理解
  • 默认字典

…使用相同的 iaito 数据集。这些例子并不全面,但是它们应该有助于您开始探索它们的应用。

关于数据集的简短概述;该数据集始于 2012 年,当时帮助 iaidoka 成员翻译 iaito 订单细节。每个记录包含每个所有者的 iaito 零件规格。出于隐私考虑,诸如所有者的全名和地址等敏感信息永远不会在数据集中捕获。数据集可以从我的 GitHub repo 中访问。

熊猫显示设置

熊猫有很多选择。我们可能遇到和使用的比较常见的应该是max_rows或者max_columns。当读取可能很长的表时,某些列可能会被截断为“…”。为了减轻这种情况,我们可以设置它显示所有的列(即pd.set_option('display.max_columns', None))。

import pandas as pd
pd.set_option('display.max_columns', None)

df = pd.read_excel('project_nanato2022_Part1.xlsx',)

要查看数据帧的前 n 行或后 n 行,可以使用headtail

display(df.head()) # take a look at first default = 5 rows
df.tail() # take a look at last 5 rows

作者图片

不要误解我的意思,我完全支持使用head()tail(),并且我仍然使用它们作为检查导出的数据帧副本是否正确的首选方法。但是通过上面的设置,我们压缩了数据框显示以显示第一行和最后“n”行——用更少的代码实现了相同的结果。

pd.set_option('display.max_rows', 10) # set display to 10 rowsdf = pd.read_excel('project_nanato2022_Part1.xlsx')
df

作者图片

处理多个文件时,另一个值得考虑的方面是检查这些文件的过程,以及潜在的文件大小。如果数据是干净的,但我们希望更好地感知数据特征,那么限制行数(即记录数)对于管理大文件更好。

# limit to 5 rows
df_limited = pd.read_excel('project_nanato2022_Part1.xlsx',nrows=5) 
df_limited

作者图片

  • 另一个容易被忽略的小问题是为了方便而重复调用函数。我知道——我倾向于随意使用这个。一个例子是df.shape。摆脱这种情况的第一步是记住输出的特征(在本例中是行和列计数的元组)。我们可以调用它一次,并在将结果赋给变量后访问它们。
print(f'df rows: {df.shape[0]}, df columns: {df.shape[1]}')
print('.shape returns a tuple of rows and cols as a result, \nconsider using as assigned to a variable.')
res_shape = df.shape
print(f'df rows: {res_shape[0]}, df columns: {res_shape[1]}')

作者图片

功能模式

在函数模式中安排代码增强了灵活性和易用性,我们可以用它来修改代码以进行下游的数据清理或转换。考虑到数据清理中有时存在的不确定性,我最初并不总是这样做,而是尝试在重构时实现它们以增强可重用性。我们将以清理列名为例。

# initial column names
ini_cols = df.columns
ini_cols

作者图片

关于这些列标题,我们需要

  • 删除逗号(即标点符号)
  • 用下划线替换空格
  • 小写字母

让我们看看上一篇文章中的实现。为简洁起见,显示的行数调整为一。在这个例子中,重命名不是就地完成的。

pd.set_option('display.max_rows', 1) # 1 row for easier reading
# lowercase, drop commas, replace newline & spaces with underscores
col_names = []
for old in df.columns:
    new = re.sub( r"[,]" ,'',old.strip()) 
    new = re.sub( r"[\n\s/]" ,'_',new) 
    col_names.append(new.lower()) 
df.rename(columns=dict(zip(df.columns, col_names)), ) 

作者图片

  • 现在,让我们把它分成几个方面,我们可以提高它。首先,我们可以使用compile派生可重用的正则表达式对象。下面是一个编译正则表达式的例子,然后手动调用模式的替换。
comma_ = re.compile( r"[,]" ) # compile the regular expressiontest_string_ = ini_cols[29]
print(f'input:\n\t{test_string_}')res_string_ = comma_.sub('', test_string_.strip())
print(f'comma removed:\n\t{res_string_}')

作者图片

然后,我们可以通过将操作序列作为一个 iterable 来实现这一点。我们会…

  • 编译所有的正则表达式;
  • 创建操作列表;
  • 最后,作为一种功能来应用
# compile regular expressions
comma_ = re.compile( r"[,]" )
whitespaces_ = re.compile( r"[\n\s/]" )# functions 
def remove_comma(val):
    return comma_.sub('', val)def replace_whitespaces(val):
    return whitespaces_.sub('_', val)def clean_headers(headers, op_seq):
    cleaned_cols = []
    for val in headers:
        for op in op_seq:
            val = op(val)
        cleaned_cols.append(val)
    return cleaned_cols# sequence of operations as a list
op_seq = [str.strip, remove_comma, replace_whitespaces, str.lower]
# implement on df column headers
res = clean_headers(df.columns, op_seq)
df.rename(columns=dict(zip(df.columns, res)), inplace=True) 
df

作者图片

词典理解

与列表理解类似,语法如下:

作者图片

对于 if-else 条件,应该是:

作者图片

我们会得到一部分数据。假设我们想要创建一个带有从所有者的性别推断出的称呼的列(即,如果性别是' M ',则添加' Mr . ';如果性别是' F ',则使用 5 行数据以保持简洁)。

pd.set_option('display.max_rows', 10) # set display to 10 rows
df_subset = df.iloc[:5][['owner', 'gender']].copy()

一种实现是:

name = {}
for i in range(len(df_subset)):
    if df_subset['gender'][i] == 'M':
        name[i] = 'Mr. ' + df_subset['owner'][i]
    else:
        name[i] = 'Ms. ' + df_subset['owner'][i]

df_dict = pd.DataFrame.from_dict(name, orient='index',columns=['name'])
df_dict

作者图片

用字典理解:

name2 = {i:'Mr. ' + df_subset['owner'][i]  
         if df_subset['gender'][i] == 'M' 
         else 'Ms. ' + df_subset['owner'][i]
         for i in range(len(df_subset)) 
        }

df_dict2 = pd.DataFrame.from_dict(name2, orient='index',columns=['name2'])
df_dict2

作者图片

默认字典

在字典中设置值通常涉及到从另一个集合中引用它们。典型的逻辑包括:如果值不在字典中,则设置一个键-值对;如果键已经存在,则添加到值序列中。如果默认值不在此实例的字典中,则认为它设置了一个键值对。使用来自collectionsdefaultdict可以方便地获得字典中的默认值。一个假设的用例可以回答:“生成每个模型的 tsuba 选择列表。”

# prep the data to work with
tsuba_codes = df['tsuba'].apply(lambda x: x.split(' ')[0])
model_series = df['model']print(tsuba_codes.unique())
print(model_series.unique())

可处理的潜在数据范围|按作者分类的图片

使用 for 循环:

model_tsuba = {}
for model, code in list(zip(model_list, tsuba_codes)):
    if model not in model_tsuba:
        model_tsuba[ model ] = [code]
    if code not in model_tsuba[model]: # avoids duplicate tsuba code
        model_tsuba[ model ].append(code)for k, v in model_tsuba.items():
    v.sort()
    print(f'{k}: {", ".join(ele for ele in v)}')

作者图片

from collections import defaultdictmodel_tsuba2 = defaultdict(list)
for model, code in list(zip(model_list, tsuba_codes)):
    model_tsuba2[model] = list(set(model_tsuba2[model] + [code]))for k, v in model_tsuba2.items():
    v.sort()
    print(f"{k}: {', '.join(ele for ele in v)}")

作者图片

本文只介绍了一些函数和例子,但是它们应该是您会遇到的最常见的函数和例子。

我希望这篇文章是一篇信息丰富的读物。感谢您的阅读,直到那时保持安全!

posted @ 2024-10-18 09:37  绝不原创的飞龙  阅读(345)  评论(0)    收藏  举报