TowardsDataScience-博客中文翻译-2021-三十九-
TowardsDataScience 博客中文翻译 2021(三十九)
线性回归面临的五大障碍
当您在数据集上训练线性回归模型时,可能会出现这五个障碍。

让我们从黄色、危险的颜色到黄色、阳光和幸福的颜色。(照片由凯西·蒂博在 Unsplash 上拍摄)
线性回归是最简单的机器算法之一。可解释性和易于训练的特点使这种算法成为机器学习的第一步。线性回归不太复杂,是理解更高级和复杂算法的基本概念之一。
要知道什么是线性回归?我们如何训练它?我们如何获得最佳拟合线?我们如何解读它?以及我们如何评估拟合的准确性,您可以访问以下文章。
在了解了线性回归的基本直觉之后,某些概念让它变得更加迷人,更加有趣。这些还提供了对算法缺陷、其影响和补救措施的深入理解。并且,我们将在文章中探讨这些概念。
我们都知道,线性回归涉及一些假设。这些假设使得该算法的结构非常简单。然而,这就是为什么它有许多缺陷,为什么我们需要研究和理解这些缺陷的原因。
本文讨论了训练线性模型时可能出现的问题,以及处理这些问题的一些方法。
本文范围内的五个问题是:
- 反应-预测值关系的非线性
- 误差项的相关性
- 误差项的非常数方差【异方差】
- 共线性
- 异常值和高杠杆点
响应-预测值关系的非线性
来源:
这个问题的原因是线性回归中涉及的一个假设。线性的假设,表明预测值和响应之间的关系是线性的。
如果反应和预测值之间的实际关系不是线性的,那么我们得出的所有结论都是无效的。此外,模型的准确性可能会显著下降。
那么,我们该如何处理这个问题呢?
补救措施:
解决上述问题的方法是绘制残差图。
残差图是残差(实际值和预测值之间的差值)和预测值之间的图。
一旦我们绘制了剩余图,我们将寻找一个模式。如果一些模式是可见的,那么在反应和预测之间存在非线性关系。而且,如果图显示随机性,那么我们就在正确的道路上!
在分析了模式的类型之后,我们可以使用非线性变换,比如平方根、立方根或对数函数。这在一定程度上消除了非线性,并且我们的线性模型表现良好。
示例:
让我们试着用一条直线来拟合一个二次函数。我们将使用 NumPy 生成一些随机点,并将它们的平方作为响应。
import numpy as np
x = np.random.rand(100)
y = x*x
sns.scatterplot(x,y)
让我们看看 x 和 y 之间的散点图(图 1)。

图一
现在,让我们尝试用一个线性模型来拟合这个数据,看看残差和预测值之间的关系。
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(x.reshape(-1,1),y.reshape(-1,1))
predictions = model.predict(x.reshape(-1,1))
residual = y.reshape(-1,1) - predictions

图 2
我们可以在残差图中看到二次趋势。这种趋势有助于我们识别数据中的非线性。此外,我们可以应用平方根变换来使数据更适合线性模型。
如果数据是线性的,那么你会得到随机的点。残差的性质将被随机化。在这种情况下,我们可以继续这个模型。
误差项的相关性
来源:
线性模型的一个主要假设是误差项不相关。“不相关项表示一个观测值的误差符号与其他观测值无关。
误差项之间的相关性可能由于几个因素而出现。例如,如果我们观察人的体重和身高。错误的相关性可能是由于他们所吃的食物、他们所做的运动、环境因素或者他们是同一家庭的成员而发生的。
当误差相关时,模型会发生什么变化?如果误差项相关,则模型系数中的标准误差会被低估。因此,置信区间和预测区间将比它们应有的范围更窄。
要了解更多信息,请参考下面的例子。
补救措施:
解决方法与上述问题相同,残差图。如果在残差图中可以看到一些趋势,这些趋势可以表示为一些函数。因此,它们是相关的!
示例:
为了理解相关性对置信区间的影响,我们应该注意两点。
- 当我们估计模型参数时,会涉及到一些误差(标准误差:SE)。这种误差是由于对样本总体特征的估计而产生的。该误差与观察次数的平方根成反比。
- 置信度为 95%的模型参数的置信区间相差两个标准误差。(请参考图 3)

图 3 模型参数的置信区间。
现在,假设我们有 n 个数据点。我们计算标准误差(SE)和置信区间。现在,我们的数据翻倍了。因此,我们将有成对的观测值和误差项。
如果我们现在重新计算 SE,那么我们将计算它对应于 2n 的观测值。这样一来,标准误差就会低一个因子根 √2 (SE 与观测次数成反比)。并且,我们将获得更窄的置信区间。
误差项的非常数方差【Heteroscedasticity】
来源:
这个问题的来源也是一个假设。假设误差项具有恒定方差,也称为同质性。
一般来说,情况并非如此。我们通常可以从残差图中漏斗形状的存在来识别误差中的非恒定方差,或异方差。在图 2 中,漏斗表示误差项具有非恒定方差。
补救措施:
一种可能的解决方案是使用对数和平方根等凹函数来转换响应。这种转换导致响应变量的收缩,从而减少异方差。
示例:
让我们尝试将对数变换应用于问题 1 中生成的点。

图 4 凹面转换
我们可以观察到一个转化后的线性趋势。因此,我们可以通过应用凹函数来消除非线性。
共线性
共线性指两个或多个预测变量相互关联的情况。例如,我们可以发现身高和体重、房子面积和房间数量、经历和收入之间的一些关系,以及许多其他关系。
来源:
在线性回归中,我们假设所有的预测因子都是独立的。但通常情况恰恰相反。预测值是相互关联的。因此,有必要研究这个问题并找到可行的解决方案。
当独立性假设被忽略时,会出现以下问题:
- 我们无法推断预测因素对反应的个别影响。因为它们是相互关联的,一个变量的变化会影响另一个变量的变化。因此,模型参数的精度显著下降。
- 当模型参数的精度下降时,我们所有的结论都变得无效。我们不能说出响应和预测值之间的实际关系,因此,模型精度也会降低。
补救措施:
这个问题有两种可能的解决方法。
- 删除变量:我们可以从回归中删除有问题的变量。直觉是,共线性意味着该变量提供的信息在其他变量存在的情况下是多余的。因此,我们可以不做太多的妥协就放弃这个变量。
- 组合变量:我们可以将两个变量组合成一个新变量。这些技术是特征工程。例如,将体重和身高合并得到身体质量指数(身体质量指数)。

图 5 组合相关变量
离群值和高杠杆点
异常值和杠杆点的存在极大地影响了线性回归。它们的发生可能有多种原因。它们的存在极大地影响了模型的性能。这也是线性回归的局限性之一。
异常值:对于某个给定的预测因子 x,异常值是对响应 y 的异常观察
高杠杆点:与异常值相反,高杠杆点被定义为对预测值 x 的异常观察。

图 6 散点图中的异常值和高杠杆点
有几种技术可用于识别异常值。这包括四分位距、散点图、残差图、四分位-四分位图、箱线图等。
由于这是线性回归的一个局限性,因此采取必要的措施至关重要。一种方法是剔除异常值。但是,这可能会导致一些信息丢失。我们还可以使用特征工程来处理异常值。
摘要
在本文中,我们看到了使用线性回归时的五个问题。我们已经看到了每个问题的来源、影响和解决方案。
虽然线性回归是最基本的机器学习算法,但它在学习新事物方面有着广阔的空间。对我来说,这些问题为线性回归提供了不同的观点。
希望了解这些问题,能在你解决任何问题的时候,给你提供新颖的见解。
你也可以检查线性回归的完整播放列表。
快乐学习!
2021 年的五个最佳数据科学项目
2021 年最佳 Kaggle 笔记本精选列表

图多尔·巴休在 Unsplash 上的照片
介绍
我爱卡格尔。
当我开始学习数据科学时,Kaggle 是加速我学习的主要资源之一。Kaggle 不仅有很棒的初学者教程,还有很棒的代码可供你学习!
通过观察专业人士的比赛,你可以在一项运动中取得更好的成绩,同样,通过查看其他数据科学家的分析和代码,你也可以显著提高自己的数据科学技能。
为什么你应该利用 Kaggle
阅读他人的代码有很多好处:
- 您可以了解以前不知道的新包、方法和技术
- 你可以了解比你目前知道的更好的方法,比如强大的机器学习模型或更快的迭代数百万行的方法。
- 你可以学习如何处理特定的问题,无论是处理高维数据、图像处理,还是进行时间序列分析。
信不信由你,当我面对一个我没有 100%把握如何解决的新问题时,Kaggle 是我首先检查的地方之一。这就是为什么我强烈建议你花时间浏览一下这个 Kaggle 笔记本的精选列表。
话不多说,以下是我在 2021 年见过的五款最好的 Kaggle 笔记本:
1.举办奥运会能提高成绩吗?

https://www.kaggle.com/joshuaswords/does-hosting-the-olympics-improve-performance
这项分析(上面的链接)是由 AWS 的数据科学家 Josh 进行的。他想知道当一个国家主办奥运会和不主办奥运会时,奖牌数是否有统计学上的显著差异。
这份分析之所以排在首位是有原因的。事实上,有两个原因:
第一,我发现这个问题本身很好奇。在我的内心深处,我一直有一种感觉,答案是“是”,但我从来没有确切地知道。看到有人主动发现这一点是令人鼓舞的!
第二,这个分析本身很精彩。虽然这仍然是一项正在进行的工作,方法是合理的,过程是有意义的,可视化是美丽的。
在本分析中,您将看到 Josh 回答了几个问题,包括:
- 哪些国家在奥运会上获得了最多的奖牌?
- 主办奥运会和不主办奥运会的国家表现如何?两者有统计学上的显著差异吗?
- 奖牌的分布是什么样的?
2.网飞数据可视化和趋势

照片由 Thibault Penin 在 Unsplash 上拍摄
https://www.kaggle.com/joshuaswords/netflix-data-visualization
接下来的分析也是由乔希进行的——我能说什么呢,他的分析令人难以置信!这个分析有几个与网飞内容相关的独特的数据可视化,我要说他们很有见地!
他回答的一些问题包括:
- 哪个国家最喜欢看网飞?
- 电影和电视剧的比例是多少?
- 每年有多少内容被添加到网飞?
- 网飞的目标人群是什么年龄组?
3.数据科学和 STEM 工资

https://www.kaggle.com/jackogozaly/salary-data-eda
这项分析是由杰克·奥格扎利进行的,它着眼于数据科学家和其他 STEM 相关职业的工资数据。用于此分析的数据来自 levels.fyi。
我喜欢任何与 STEM 工资相关的分析,因为我觉得知道你的工作(或理想工作)的现行工资总是好的。此外,这项分析特别包括了你通常不会在其他网站上看到的信息,比如按种族划分的平均工资。
您可能希望得到回答的一些问题包括:
- 根据多年的经验,薪酬会有怎样的变化?
- 最常见的 STEM 工作有哪些?
- 大多数数据科学家的教育水平如何?
- 哪些公司为数据科学家职位支付的薪水最高?
4.Reddit EDA 和文本分析

https://www.kaggle.com/khsamaha/reddit-vaccine-myths-eda-and-text-analysis
这项分析是由 Kheirallah Samaha 进行的,他使用 NLP 技术进行了文本分析,以确定过去几年 Reddit 帖子中关于疫苗的平均情绪。他还以一些关于为什么许多人对接种疫苗犹豫不决的最终原因结束了分析。
我真的很喜欢这个分析,因为它很好地利用了网络图和 NLP 技术。你可以期待他回答的一些问题包括:
- 哪些词用得最多,彼此关联度最大?
- 随着时间的推移,积极或消极情绪的水平如何变化?它在新冠肺炎期间和之后有显著变化吗?
5.2021 幸福与人口分析

https://www.kaggle.com/joshuaswords/awesome-eda-2021-happiness-population
最后,这最后的分析也是由乔希进行的。特别是,这是一个探索性的数据分析,以确定什么因素使一个国家幸福或不幸福。他使用的数据来自 2021 年世界幸福报告。
您可能已经回答了一些问题,包括:
- 哪些国家最幸福?最不开心?
- 国家分数如何随时间变化?它们相对一致吗?
- 什么因素与一个国家的幸福指数直接相关?
感谢阅读!
如果您喜欢这篇文章,请务必点击 订阅此处 或至我的 独家快讯 千万不要错过另一篇关于数据科学指南、技巧和提示、生活经验等的文章!
我希望你觉得这有用!不仅要花时间浏览这些见解,还要了解这些见解是如何编码的。我真诚地相信这是加速你学习的最好方法之一。
我一如既往地祝你学习一切顺利!😃
不确定接下来要读什么?我为你挑选了另一篇文章:
还有一个:
特伦斯·申
- 如果你喜欢这个,就 订阅我的媒介 获取内容!
- 同样,您也可以订阅我的独家简讯
- 跟我上LinkedIn其他内容
五个值得一试的开源机器学习库
五个库的旋风之旅,这可能是对您的数据科学堆栈的一个很好的补充

开源是机器学习的支柱。它们携手并进。没有开源兄弟会的贡献,这个领域的快速发展是不可能的。机器学习社区中许多广泛使用的工具都是开源的。每年都有越来越多的图书馆加入这个生态系统。在本文中,我快速浏览了我最近遇到的一些库,它们可能是对您的机器学习堆栈的一个很好的补充。
1️⃣.蜂鸟
Humminbird 是一个用于将训练好的传统机器学习模型编译成张量计算的库。这意味着你可以利用 GPU 和 TPU 等硬件加速,即使是传统的机器学习模型。这在几个层面上都是有益的。
- 用户可以受益于在神经网络框架中实现的当前和未来的优化;
- 用户可以从本机硬件加速中受益;
- 用户可以从拥有支持传统和神经网络模型的独特平台中受益;
- 用户不必重新设计他们的模型。

蜂鸟库高层架构|来源:[官方论文](http://Compiling Classical ML Pipelines into Tensor Computations for One-size-fits-all Prediction Serving)
此外,Hummingbird 还在 Sklearn API 之后提供了一个方便的统一“推理”API。这允许用 Hummingbird 生成的模型交换 Sklearn 模型,而不必更改推理代码。

Hummingbird 根据作者转换您训练过的传统 ML |图像
🛠 Github
🔬论文:
- 为服务的统一机器学习预测的张量编译器。
- 将经典的 ML 管线编译成张量计算,以实现“一刀切”的预测服务。
📋博客
使用 Hummingbird 将传统机器学习管道标准化为张量计算
💻演示
蜂鸟的语法非常直观和简洁。要在 DNN 框架上运行您的传统 ML 模型,您只需要import hummingbird.ml并将convert(model, 'dnn_framework')添加到您的代码中。下面是一个使用 scikit-learn 随机森林模型和 PyTorch 作为目标框架的例子。

使用一个 scikit-learn 随机森林模型和 PyTorch 作为目标框架使用 Hummingbird |图片由作者提供
2️⃣.Top2Vec
文本文档包含大量信息。手动筛选很难。主题建模是工业中广泛使用的一种技术,用于在大量文档中自动发现主题。一些传统的和最常用的方法是潜在狄利克雷分配 (LDA)和概率潜在语义分析(PLSA)。然而,这些方法都有缺点,比如没有考虑单词的语义或顺序。Top2vec 是一种利用联合文档和单词语义嵌入来寻找主题向量的算法。以下是作者要说的话:
这种模型不需要停用词表、词干或词汇化,它可以自动找到主题的数量。得到的主题向量与文档和单词向量一起嵌入,它们之间的距离表示语义相似度。我们的实验表明,top2vec 找到的主题比概率生成模型更具信息量和代表性。甚至,预先训练的通用语句编码器和 BERT 语句转换器也可以用于编码。
一旦训练了 Top2Vec 模型,我们可以执行以下操作:

Top2Vec |作者图片的功能
🛠 Github
https://github.com/ddangelov/Top2Vec
🔬纸
📜文档:
https://top2vec.readthedocs.io/en/latest/index.html
💻演示
这里有一个在20 个新闻组数据集上训练 Top2Vec 模型的演示。这个例子取自他们的官方 Github 回购。

在20 个新闻组数据集 |作者图片上训练 Top2Vec 模型的演示
3️⃣.贝尔托皮奇
BERTopic是另一种主题建模技术,它利用 BERT 嵌入和基于类的 TF-IDF 来创建密集的集群,允许轻松解释主题,同时保留主题描述中的重要单词。它还支持类似于 LDAvis 的可视化。这里是对 BERTopic 功能的一个快速总结。

BERTopic |作者图片的功能
🛠 Github
https://github.com/MaartenGr/BERTopic
🔬证明文件
https://maartengr.github.io/BERTopic/
📋博客
💻演示
在20 个新闻组数据集上训练BERTopic模型后生成的主题的可视化

用 BERTopic |作者图片可视化主题
4️⃣.Captum
Captum 是为 PyTorch 设计的模型可解释性和理解库。Captum 在拉丁语中的意思是理解,它包含了 PyTorch 模型的集成渐变、显著图、smoothgrad、vargrad 和其他的通用实现。此外,它可以快速集成用特定领域库构建的模型,如 torchvision、torch text 等。Captum 还提供了一个名为 Insights 的网络界面,便于可视化和访问我们的许多可解释性算法。

解释文本模型:使用 Captum 的 IMDB 情感分析| 图片来自文档
Captum 目前处于测试阶段,正在积极开发中!
🛠 Github
https://github.com/pytorch/captum
🔬证明文件
🎤幻灯片
- 他们来自 NeurIPS 2019 的幻灯片可以在这里找到
- 他们来自 KDD 2020 指南的幻灯片可以在这里找到。
💻演示
以下是我们如何通过 Captum Insights 在 CIFAR10 上分析样本模型:

通过 Captum Insights 分析 CIFAR10 上的样本模型|作者图片
5️⃣.烦恼
骚扰代表近似最近邻居。它是用 C++构建的,但是附带了 Python、Java、Scala、R 和 Ruby 的绑定。Annoy 用于在高维空间中进行(近似)最近邻查询。尽管许多其他库也执行同样的操作,但 airy 附带了一些很棒的插件。它创建基于文件的大型只读数据结构,这些数据结构被映射到内存中,这样许多进程可以共享相同的数据。由埃里克·伯恩哈德森开发的 Annoy 被用于 Spotify 的音乐推荐,并被用于搜索相似的用户/商品。
我们在高维空间中有数百万首歌曲,所以内存使用是首要考虑的问题
🛠 Github
https://github.com/spotify/annoy
🎤幻灯片
- 来自纽约机器学习会议的演讲关于骚扰
💻演示
下面是我们如何使用 Annoy 来查找 100 个最近的邻居。

使用作者的图片寻找 100 个最近的邻居
包裹
这些是我觉得有趣、有用、值得分享的库。我相信您会想探索它们,看看如何在您的工作领域中使用它们。尽管我们已经有数不清的库需要修补,探索新的库总是有趣和有见识的。
👉有兴趣看我写的其他文章。这个 回购 包含了我分类写的所有文章。
不要再用“数据工程师”这个术语了,有更好的说法
年度最热门工作的 5 个被滥用的定义

站立时的餐叉——图片由作者提供
数据工程师范围从来没有这么大,这么混乱。一些新的角色定义已经出现在特定的领域,但是它们仍然没有被充分利用。如果你看数据工程师的工作机会,你可能会感到困惑,因为内容和工作本身可能会因公司而异。在本文中,我们将提醒自己数据工程师角色的近亲是什么,以便能够发现用词不当。
📕数据工程师又名数据库管理员(DBA)
随着大多数分析用例基于 OLAP 系统,这一角色已经淡出。一些公司仍然严重依赖 OLTP 数据库(如 MySQL、Postgres)进行分析。原因有很多:
- 他们没有任何发布/订阅系统来实时获取数据,并且具有低延迟查询要求(毫秒级响应时间)
- 他们仍然没有在数据平台上投资,只是依靠现有的软件工程师来做分析工作
- 他们可能需要一名数据库管理员来维护他们的生产数据库:性能调优、监控、迁移、备份等。
如何发现 DBA 数据工程师的角色?你可能会有一个工作机会,专注于对 SQL 和数据库/查询/存储过程优化有很高要求的特定数据库。
📗数据工程师又名数据分析师
数据分析师更关注业务价值,而不是内部 SQL 性能。他们通常使用仪表板工具,并提供 KPI,业务可直接使用的洞察力。
这里的陷阱是,数据分析师可能会做一些数据管道,因为缺乏数据工程师的可用性,但这并不使其成为数据工程师;这是一个不同的野兽。
软件工程不是数据分析师的强项。如果你在工作机会中错过了以下内容:CI/CD、编程知识(测试、Python/Java/Scala)、基础主题(Terraform、Docker 等。)—你可能正在寻找一份数据分析师的工作,而不是数据工程师。
📘数据工程师又名分析工程师
分析工程师是一个相当新的命名角色。随着云数据仓库的出现(雪花、BigQuery、Firebolt),一个全新的数据工程师时代诞生了。这些工程师是超能力的“数据分析师”。
他们应用软件工程师最佳实践(版本控制、测试、CICD ),通常关注 SQL 管道和优化,同时使用云数据仓库技术。
他们通常负责企业直接使用的数据资产(经过清理和转换的数据)(与只提供“原始”数据相反)。
Dbt 通常是他们主要工具带的一部分。
🔗Fishtown Analytics 对数据分析师、分析工程师和数据工程师做了一个很好的比较。
📙数据工程师又名机器学习工程师
数据成熟度不断增长,机器学习越来越大众化。因此,我们需要有奉献精神的人来迎接挑战!
这个角色将他的时间集中在机器学习生命周期上:部署模型(由数据科学家开发),并将它们转化为实际的生产系统。他们通常有很强的软件工程背景。
他们使用的一些(特定)工具的示例:
- ML 平台:AWS SageMaker,GCP 云 ML
- ML Libs : Tensorflows,scikit-learn,Spark ML,Keras,Pytorch
- 编排:MLflow、Kubeflow、Airflow
📔数据工程师又名数据平台工程师
随着数据网格概念的发展,我们倾向于采用更多的自助式方法,在这种方法中,集中式数据团队将主要专注于提供数据平台和工具,以使其他数据公民能够在数据管道方面实现自治。
数据平台工程师的一些工作:
- 管理数据基础设施(Kafka、数据编排器、数据目录)
- 提供 ETL 工具(dbt)或框架来合理化和简化数据管道
- 创建一些提供数据的微服务/API。
那么谁是真正的数据工程师呢?🕵
今天的大挑战是,公司中的数据工程师角色通常不仅仅涉及上述中的一个定义,而是混合了 2 个或更多的定义。然而,公平地说,如果你的工作主要属于 1 个领域,那么就不要使用数据工程师头衔!
当你申请一个职位时,一定要问一下你在这些话题上的预期工作时间,这可以让你更好地了解你的预期。
一个数据工程师可以隐藏另一个,你的角色定义可能因公司而异,所以要小心!👀
迈赫迪·瓦扎又名迈赫迪欧·🧢
感谢阅读!🤗 🙌如果你喜欢这个,跟随我上🎥 Youtube ,✍️ 中型 ,或者🔗 LinkedIn 了解更多数据/代码内容!
支持我写作 ✍️通过加入媒介通过这个链接
可能会让你困惑的五个悖论
还是能智胜他们?

来自 Pexels 的 Andrea Piacquadio 的照片
在我们的日常生活中,我们不断处理不确定的情况。因此,至少在潜意识里,我们一直面临着概率。此外,似乎我们对概率有很好的直觉。或者我们真的有吗?
我们知道,将一枚硬币抛 100 次,结果大约是 50 个正面和 50 个反面。此外,我们很清楚,在国外度假时偶遇朋友的概率非常低,尽管不是零。然而,有些情况下,从概率论中得出的正确预测完全违背直觉。
让我们深入探讨概率论和统计学中的五个悖论,它们产生的结果看似荒谬,但却是真实的。
1.生日悖论

图片来自 Unsplash
你在一个朋友的聚会上,有 30 个人出席。两个人同一天过生日的概率有多大?你的直觉是什么?我的第一个猜测是有一些机会,但应该有点低。
现在,生日悖论是关于以下问题的:
多少人需要参加聚会,这样我们至少有 50%的机会两个人一起过生日。
这个悖论假设一年中的每一天都同样可能是一个随机的人的生日。
令人惊讶的答案是 23!只需要有 23 个人在场,就有至少 50 %的机会让两个人分享他们的生日。对于你朋友的 30 人生日聚会,其中两人生日相同的概率实际上超过 70 %!
2.辛普森悖论
假设我们是生意伙伴。我们在全市拥有五家不同的咖啡店。作为一种营销策略,我们向最忠诚的顾客发放代金券,希望他们会回报我们,买更多的咖啡。
然而,我们在代金券应该值多少钱的问题上意见不一。为了找出什么是最好的选择,我们发放不同价值的代金券。我们收集了在接下来的一个月里我们从每一位忠实顾客那里获得了多少利润的数据。
一个月后,一切似乎都清楚了:对于我们的五家咖啡店中的每一家,我们都可以看到这样的趋势:优惠券价值越高,我们从相应的客户那里获得的利润就越多。
然而,当综合所有五家商店的数据时,趋势似乎完全相反:优惠券价值越高,我们从客户那里获得的利润就越少。怎么会这样呢?

辛普森悖论的直观解释。图片来自维基百科。
这正是辛普森悖论:
当数据被组合时,出现在不同数据组中的趋势可能消失。
3.伯特兰盒子悖论
如果你熟悉 Montey Hall 问题,这个悖论还是挺像的。在我们面前有三个盒子:

来自 Good Ware 的图标
一个盒子里有两枚银币,一个盒子里有两枚金币,一个盒子里有一枚金币和一枚银币。我们不知道哪些硬币在哪个盒子里。现在,我们随机挑选一个盒子,然后从盒子里盲目地抽出一枚硬币。是金币!
现在,问题是:
我们盒子里的第二枚硬币也是金币的概率有多大?
我第一次遇到问题时天真的(而且错了)回答是。我想,因为我们抽到了一枚金币,所以我们的盒子要么是装有两枚金币的盒子,要么是装有混合金币的盒子。在第一种情况下,我们会抽取另一枚金币,而在第二种情况下,我们不会。因此,我推测概率应该是。
真正的可能性是⅔.
原因是,我们抽取的第一枚金币可能是混合盒子中的唯一一枚金币,也可能是纯金色盒子中的第一枚金币,或者是纯金色盒子中的第二枚金币。而在这三种可能性中的两种,我们会抽取另一枚金币。

伯特兰盒子悖论的直观解释。图片来自维基百科。
4.领带悖论
圣诞节假期后,你回到办公室,戴着你作为礼物得到的新领带。你的同事鲍勃也在圣诞节得到了一条领带。你们都不知道领带的价格。你们开始争论谁得到了更贵的礼物。
鲍勃和你同意打赌:你要去看看领带的价格。得到较贵领带的人必须把领带给较便宜的人。

两条领带——哪一条更贵?来自 Freepik 的图标
鲍勃认为赌注对他有利:他赢/输的几率是 50/50。如果他输了,他就失去了领带的价值。然而,如果他赢了,他赢的比他领带的价值还多。
但从你的角度来看,你可以做完全相同的推理,得出赌约对你有利的结论。
但是,这个赌注不可能对你和鲍勃都有利。那么错在哪里呢?
为了解决领带悖论,我们必须将领带的价格纳入计算:假设一条领带价值 100 €,另一条价值 50 €。如果鲍勃赢了,他就赢了一条价值 100 €的领带。如果他输了,这意味着他拥有更昂贵的领带,只是失去了 100 €。所以可能的得失抵消了,赌注实际上对谁都没有好处。
5.随机漫步
这最后一个事实通常不被列为悖论,但我认为它是如此迷人和令人困惑,以至于它必须被列入这个列表。
想象一只蚂蚁在一张无限长的纸上。每过一秒钟,蚂蚁就会随机走进四个可能方向中的一个(向前、向后、向左或向右)。每个方向的可能性都是一样的。这种情况就是所谓的对称 2D 随机漫步。2D,因为纸是二维的。
我们也可以想象蚂蚁不在一张纸上,而是在一串织物上。在这种情况下,蚂蚁只能向前或向后移动,我们将面临一个 1D 随机漫步。
类似地,我们可以想象一个 3D 随机行走,其中我们的“行走者”是一只无人机或一只鸟,它随机地向六个方向移动(向前/向后、向左/向右、向上/向下)。

2D 随机漫步(左)和三维随机漫步(右)的可视化。Vipul Lugade 的图片【1】【2】。
现在的问题是:
一个步行者回到起始位置的概率是多少?
令人惊讶的答案是,对于布料上的蚂蚁(1D)和纸张上的蚂蚁(2D)来说,概率是 1。但是对于这只鸟来说,它有可能永远离开而不再回来。这也适用于第 4、5、6 维度……
令我难以置信的是,步行者总是在第 1 和第 2 维返回,但这种模式从第 3 维开始就被打破了。我可以看数学,但不得不承认,在直觉层面上,我仍然没有完全理解它。数学家左师·卡库塔尼对此笑着评论道:
喝醉的人会找到回家的路,但喝醉的鸟可能会永远迷路。
——左师·角谷
觉得这个故事有趣?你可以在这里成为媒介会员来支持我的写作:medium.com/@mmsbrggr/membership。你将获得所有媒体的访问权,你的部分会员费将直接支持我的写作。
欢迎在 LinkedIn 上向我提出私人问题和评论。如果你喜欢这篇文章,让我告诉你我的时事通讯:marcelmoos.com/newsletter。
五个问题将帮助你更好地为整数线性规划建模
一种将现实世界问题公式化为数学模型的结构化方法,如背包问题

你可能听说过经典的数学问题,比如旅行推销员问题或者 0/1 背包问题。解决这类优化问题有几种选择,但最基本的一种是试图找到精确解。为此,大多数数学家应用整数线性规划,简称 ILP。当我在一门大学课程中被介绍到这一点时,我感到非常困惑。通常教授会给我们一个详细的问题陈述,这个问题陈述可以归结为少于十行的 ILP。诀窍是将这种现实生活中的问题转换成数学模型。和我的同学一起,我发现这样做很有挑战性。幸运的是,在这个过程中,我们开发了一个包含五个问题的列表,这使得我们能够以结构化的方式分析问题。更重要的是:它使得写下实际的模型变得更加容易。在本文中,我将详细解释这种方法,以便帮助您建模下一个 ILP。这将通过将它直接应用到现实生活中的一个问题来实现:0/1 背包问题。首先,这里有五个问题:
- 有哪些套?
- 参数有哪些?
- 什么是决策变量?
- 优化的目标是什么?
- 我应该记住哪些约束?
问题陈述
一位投资者正在考虑七项投资。在下图中,你可以找到每项投资所需的现金和净现值。

投资机会,来源: R. Roberti 来自 VU 阿姆斯特丹。
投资者有 15,000€可用,并希望以这样一种方式投资,即总净现值最大化,而不超过可用现金。投资可以接受,也可以不接受,但不能部分接受。给你的问题是:应该买哪些投资?
设置
本质上,集合是元素的集合。元素可以是任何东西:城市,病人,卡车,你能想到的。通常,当阅读问题陈述时,集合是什么就变得很清楚了。在本例中,表格显示了一组投资,因此这将是我们的集合。我们将用字母 I 来指代这一组。
因素
一个参数也可以被称为一个变量,并且包含一个特定的值,通常连接到其中一个集合。这可以是任何东西。在我们的例子中,它是每项投资所需的现金和净现值,分别记为 cᵢ 和npvᵢ**。注意下标 i 表示 c 和 npv 的投资。最后,有一个参数与其中一组无关,但却非常重要:投资预算 b 。
决策变量
顾名思义,决策变量是一个可以被决策者改变的变量。在 ILPs 中,这样做是为了最大化(或最小化)目标函数。因此,根据问题陈述,你应该寻找应该由你做出的选择。在我们的例子中,问题的最后一句话指出:应该购买哪些投资?数学上,我们用二元变量 xᵢ 来表示投资 i 是买(1)还是不买(0)。
目标
数学模型的目标通常用目标函数量化。最大化这个函数是常见的,但是最小化归结为相同的想法。我们示例的目标是最大化投资者投资组合的 NPV。对于每一笔投资,都要确定是买还是不买,如果是,就要把相应的 NPV 加到我们的总收益里。这在下图的 1a 行中完成:它对所有投资求和,并将决策变量 xᵢ 与参数 npvᵢ 相乘。毕竟,如果 xᵢ 等于 0,什么都不会增加,但是当 xᵢ 等于1 时就会增加。注意 max 写在目标函数之前,明确目标是最大化。
限制
如果没有限制,只有线(1a)的 ILP 将决定进行所有投资。然而事实并非如此:有一个现金预算 b 不能超过。所以,所有投资所需的现金不能大于这个 b 。类似于第(1a)行,通过对所有投资求和并乘以决策变量 xᵢ 和参数 cᵢ.来计算所需的总现金
在数学符号中…

ILP 的数学符号,来源: R. Roberti 来自 VU 阿姆斯特丹。
最后一行(1c)称为完整性约束,告诉我们决策变量可以得到什么样的值。在这种情况下,它是一个二元变量,因为我们正在解决 0/1 背包问题。
但是投资者呢?
将问题陈述转换成实际的 ILP 后,您可能想知道背包问题的解决方案是什么。理想情况下,你会选择投资 1、2 和 5,它们需要€14,500 英镑(剩下€500 英镑),€的总净现值为 46,000 英镑。
下次……
所以,我想让你带回家的是我们遵循的结构化方法。每次阅读问题陈述时,试着问自己这五个问题。如果你已经这样做了几次,对更复杂的 ILP 建模和分析就会变得容易得多。所以下次当你遇到旅行推销员问题、背包问题或布景问题时,你知道该怎么做!
你可能不知道的五个降价技巧
这五个简单的技巧开启了你用 R Markdown 做什么的可能性

经常阅读我的文章的许多人会知道我是一个多么狂热的 R Markdown 迷。它无疑是最好的数据科学出版软件,而且完全免费,还在不断改进,变得更好、更灵活。
随着时间的推移,我不断学习新的技巧,让我的生活变得更轻松,或者从 R Markdown 中获得最大收益。我在这里与你分享最近的五个。希望你觉得有用。
1.新的内嵌块选项
你们中的许多人可能知道 R Markdown 中的 chunk 选项。当你写一个代码块的时候,你可以添加许多选项来指示你想用这个代码块做什么。例如:
```{r, echo = FALSE}
# some R code
这将显示代码块的结果,但不会显示代码本身。或者:
# some python code
这将显示代码,但不会运行它。事实上,有非常多的块选项可用,如果你不得不把它们放在 curly`{}`中,有时会变得混乱和难以理解。
如果你安装了 1.35+版本的`knitr`,你现在可以使用一个新的块选项特殊注释`#|`在块中逐行输入你的块选项,例如:
#| echo = FALSE, out.width = "80%"
#| fig.cap = "My caption"my_plot
## 2.有条件地评估代码块
你知道你可以在你的块选项中加入条件吗?这非常有用,可以让你只在满足某些条件的情况下运行程序块。例如,只有当对象`my_data`超过三行时,才会评估这个块:
#| eval = nrow(my_data) > 3my_data
您还可以使用条件块来显示不同的内容,这取决于您是要渲染为 PDF 还是 HTML——这意味着您只需保留一个与您的预期输出无关的`Rmd`文件。例如:
#| eval = knitr::is_html_output()# code for html output (eg interactive graphic)
``````{r}
#| eval = knitr::is_latex_output()# code for pdf output (eg static graphic)
您也可以在 if 语句中使用这些`knitr`输出函数,因此另一种方法是:
if (knitr::is_html_output()) {
# code for html output
} else {
# code for latex output
}
## 3.直接使用 Javascript 定制你闪亮的应用程序
你们中的一些人可能会使用两个独立的`ui.R`和`server.R`文件来编写自己的应用程序,但是你也可以在一个 R Markdown 文件中编写完整的应用程序。这样做的一个好处是,你可以使用 Javascript 定制你的应用程序,只需在`js`块中直接输入 Javascript。
让我们看一个简单的例子。在 Shiny 中,目前没有直接选项来限制文本区域输入框中的字符数。所以如果我使用这个标准的界面函数:
shiny::textAreaInput(
"comment",
"Enter your comment:"
)
这将创建一个 ID 为`comment`的`textarea`框。然而,如果我想将所有的评论限制在 1000 个字符以内,我在`textAreaInput()`函数中没有简单的方法。
不过,不要担心——如果你懂一点 Javascript/jQuery,你可以添加一个`js`块来给`textarea`框添加一个`maxlength`属性,就像这样:
$('[id="comment"]').attr('maxlength', 1000)
## 4.使用块选项来简化/模块化你的文档/应用
如果您的文档或应用程序变得很长,并且块中有很多代码,那么跟踪起来会很麻烦,并且很难维护。相反,您可以从 chunk 中取出代码并保存在 R 文件中,然后使用`code` chunk 选项从 R 或 Python 文件中读取代码。例如:
#| code = readLines("my_setup_code.py")# python code for setup
## 5.使用 CSS 块定制你的文档
如果你想定制你的文档或应用程序的风格,你可以使用 CSS 代码块很容易地做到这一点。您可能必须呈现文档,然后在 Google Chrome 中检查它,以识别您想要定制的特定元素的类或 ID,但是作为一个简单的示例,如果您想要将文档主体的背景颜色更改为漂亮的浅蓝色,您可以简单地插入以下内容:
body {
background-color: #d0e3f1;
}
希望这些简洁的小技巧对你有用。如果你有任何其他的建议,请在评论中提出。
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在[*LinkedIn*](https://www.linkedin.com/in/keith-mcnulty/)*或*[*Twitter*](https://twitter.com/dr_keithmcnulty)*上找我。也可以看看我在 drkeithmcnulty.com 的***上的博客。**
# 不创办数据科学或数据工程咨询公司的五个理由
> 原文:<https://towardsdatascience.com/five-reasons-why-not-to-start-a-data-science-or-data-engineering-consulting-firm-d669d7d61047?source=collection_archive---------12----------------------->
## 这比建立一个网站需要更多的东西

在 [Unsplash](https://unsplash.com/s/photos/consulting?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上由 [Austin Distel](https://unsplash.com/@austindistel?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 拍摄的照片
在今天的“即时创业”文化中,看起来你所要做的就是建立一个有限责任公司,并推出一个网站,瞧!—你是顾问。不幸的是,这与现实相去甚远。
互联网网站可能会描绘出一幅看似简单的自由职业数据科学咨询的画面,但实际上这是一个很难进入的领域,并且在最初几年,可能需要不断的工作和奉献才能建立起足够的客户名单。
你将花费数百个小时写没人会读的提案,并在任何邀请你的会议上发表演讲。
最重要的是,当你在一家大型科技公司工作时,你可以获得 15 万至 30 万美元的固定收入,创办自己的咨询公司可能没有意义。
事实上,这个建议对任何顾问都适用。然而,尤其是在技术领域机会成本如此之高的情况下。不创办自己的咨询公司的理由甚至更多。
如果你仍然没有被这个想法吓跑,那么让我们来看看为什么创办数据科学或大数据咨询公司可能不是一个好主意的五个原因。
*免责声明——我个人喜欢拥有一家私人咨询公司。然而,这并不适合所有人,而且我有一份全职工作。我只是想陈述一些你将面临的挑战。*
## 加入我们的时事通讯!
在继续滚动之前,为什么不加入我们团队的时事通讯,了解数据科学、数据工程和技术的最新动态。
# 1.你希望职业生涯稳定——而自由咨询远非稳定
作为一名独立顾问,你的客户可以随时决定让你离开。这可能有很多原因——例如,客户可能想缩减开支,或者甚至决定不再需要专业建议。
不管是什么原因,如果你最大的客户决定离开,你可能会留下一个巨大的财务漏洞需要填补。独立工作就是这个意思。你将独自一人,没有经济保障可以依靠。
如果你想养家或者有债务要还,这可能是毁灭性的。独立咨询没有确定性。
相反,如果你在一家咨询公司工作,即使客户决定放弃公司的服务,你仍然会得到报酬——你仍然会有一份工作。
# 2.你可能认为你将成为自己的老板——但实际上你将为比以前更多的人工作
作为一个独立的承包商,你将同时面对多个客户;从某种意义上说,这些客户在合同期间都是你的老板。
每个客户都有自己的一套期望和管理风格。对于每一个新的客户关系,你永远不知道会发生什么;当然,有些客户比其他人要求更高,也更宽容。并不是所有的客户都很容易相处,有些客户可能不可理喻,甚至表现出有害的、不专业的行为。如果你有压力倾向,这种过山车式的场景可能不适合你。
在咨询公司工作,你唯一真正的老板是你的直接上司或公司经理。另外,你们经常一起工作,所以你很清楚他们会给你带来什么。如果任何专业协议被违反,作为一名公司员工,你可以得到公司人力资源部门的全面保护。
还有一点需要考虑:客户通常会为特定项目雇佣自由职业顾问,而不是提供一整套咨询服务。虽然你可能会设想获得无数机会来改革和拯救一家公司的技术部门,但实际上你可能只会被要求处理一个特定的项目或部门问题,因此你使用大数据咨询技能的机会以及你的影响范围将受到严格限制。
# 3.你将不得不经常面对拒绝
让我们面对现实吧:作为一名自由职业者,你一半的时间将花在向潜在客户发送推销和建议上;而其中的很多,因为种种原因,都会被拒绝。
客户可能认为另一家供应商更便宜,或者他们可能会将合同交给朋友或亲戚推荐的人。不管拒绝的原因是什么,你都要学会不要把它当成私人恩怨。
还记得你第一份工作是什么样的吗?当时你没有工作经验,也没有行业记录。想象一下当你第一次开始做自由职业者时会是什么样子。你会试图把自己推销成一名经验丰富的顾问,但你没有客户名单或任何已完成的项目来支持这一点。本质上,潜在的客户不会看你的作品,因为没有任何作品可以看。然而,如果你在为一家公司工作,你总是会得到工作表现记录的支持,再加上你公司已完成项目的跟踪记录。
还有一点需要考虑:如果你已经在一家知名的咨询公司工作了很长时间,你可能会有一个多年来建立起来的客户名单;但满意的客户往往会对他们的咨询公司保持忠诚,所以如果你自己创业,你不能指望这些客户会追随你。
# 4.如果你不喜欢自我推销,你可能不应该开始自己的咨询业务
您可以提供业内最好的数据科学咨询服务;但是如果你不能营销自己,就没有人会知道这件事。
你能想象自己每天都试图让人们相信你是这份工作的最佳人选吗?如果你想做顾问,那就是你必须做的。你必须学会如何适应自我推销,这包括创建网页内容、分发营销材料,以及从本质上采取销售你的个性和服务的方式。
如果你担心过于“销售”,那么这样想吧:通过提供你恰好擅长的急需的服务,你正在帮助其他人在他们自己的业务上取得成功。
# 5.你必须是一个善于交际的人
作为一名数据顾问,您向客户提供各种技术专业知识和经验;但你也提供了一种信任的伙伴关系,在这种关系中,他们可以依靠你来帮助他们完成业务的一个重要部分。你将不得不花大量时间与人会面,讨论(通常猜测)他们的业务需求是什么,以及你如何能帮助他们。如果你很难共事,你的客户可能不会再雇佣你。
你可以提供这个星球上最好的数据科学咨询服务;但是如果人们觉得他们不能相信你能提供他们想要的个性化客户服务,他们就会雇佣其他人。同样,您的许多客户可能并不精通技术,他们依赖您来解释他们的需求并提供可靠的解决方案。如果你的沟通技巧不好,随之而来的沟通失误会导致客户不满。
# 你认为数据科学咨询适合你吗?
驾驭、利用和存储数据正迅速成为任何成功企业的关键组成部分;通过拥有自己的数据科学咨询公司,你可以利用这种数据繁荣进入一个高回报的职业生涯。但是,您必须为大数据咨询所需的一切做好准备,从日常的头痛和压力到成功所需的主要要求(如营销和自我推销)。本质上,作为一名自由职业的数据顾问,除了成为一名专业的数据技术人员,你还必须成为一名销售人员、心理学家和外交官。但是通过现实地看待全局并接受这些挑战,你会有更好的成功机会。
# 每个数据科学家都必须知道的五个回归 Python 模块
> 原文:<https://towardsdatascience.com/five-regression-python-modules-that-every-data-scientist-must-know-a4e03a886853?source=collection_archive---------1----------------------->
## [入门](https://towardsdatascience.com/tagged/getting-started)

图一。使用 **seaborn** python 库(图由作者出于教育目的创建)绘制的生活满意度值与人均 GDP 的曲线图,如第 5 节所示。彩色区域代表线性回归线的 95%置信区域。
# 介绍
R 回归是统计建模、数据科学和机器学习中一个非常重要的概念,它有助于通过使用特定的数学最小化标准,在自变量(或预测值) ***x*** 、因变量(或简单输出)*y(****x****)*之间建立一种可能的关系。有几种类型的回归用于不同的情况,其中最常见的是线性回归。其他类型的回归包括逻辑回归、非线性回归等。
在 Python 中,有几个库和相应的模块可用于执行回归,具体取决于遇到的具体问题及其复杂性。在本文中,我将总结 Python 中可以用来执行回归的五个最重要的模块和库,并讨论它们的一些局限性。这里我假设读者了解 Python 和它的一些最重要的库。
# 1.NumPy 的 polyfit
NumPy 代表 *Numerical Python* 可能是涉及数组的数值计算中最重要和最有效的 Python 库。除了一些数值计算的操作,NumPy 还有一个模块可以执行简单的线性回归和多项式回归。为了使事情更清楚,最好给出一个涉及 NumPy 数组的具体示例,这些数组表示如下的真实数据:
import numpy as npx = np.array([ 56755.72171242, 44178.04737774, 40991.80813814, 8814.00098681, 43585.51198178, 13574.17183072, 6175.8760297 , 17829.69832237, 53254.85637009, 17522.23018625, 42784.69836164, 36638.18492916, 41086.72967373, 18167.77372717, 12706.89121489, 52564.42917946, 61995.42280258, 35776.79516181, 30230.22630213, 34524.46986093, 13774.60527391, 14258.22933451, 101376.49657434, 9616.64500569, 45175.23189338, 38615.99518491, 74355.51585756, 12578.49547344, 19242.3664711 , 16310.988409 , 20881.76692993, 5734.63362915, 25732.01836475, 51545.48360953, 82081.59716162, 11006.2497364 , 44974.83187718, 56839.38177423])y = np.array([7.3, 7.1, 6.9, 6.4, 7.4, 6.5, 6.3, 6.7, 7.6, 5.7, 7.6, 6.5, 7.0, 5.4, 5.6, 7.5, 7.0, 7.2, 6.0, 5.9, 5.9, 5.9, 6.9, 6.5, 7.4, 7.3, 7.6, 6.1, 5.4, 6.2, 5.9, 4.7, 6.3, 7.3, 7.5, 5.5, 6.8, 6.9])
NumPy 数组 x 表示给定国家的人均 GDP(美元),数组 y 表示给定国家人民的生活满意度值。生活满意度值在[0,10]的范围内,其中值 10 对应于最大满意度,而值 0 表示完全没有满意度。几个国家的生活满意度和人均 GDP 之间的关系的细节可以在[我的 GitHub 页面](https://github.com/DamianEjlli)上找到。
如上所述,NumPy 库提供了一个选项,允许用户通过使用最小二乘法作为最小化标准来执行线性回归(简单和多项式)。做这个回归的模块是 polyfit: [**np.polyfit(x,y,deg,rcond=None,full=False,w=None,cov=False)**](https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html) **。**x 数组的形状是(M,),而 y 数组的形状是(M,K),其中 M 和 K 是正自然数。此外, **np.polyfit()** 可以使用“ **deg = n** ”指定多项式回归的次数,还可以计算*协方差矩阵*,该矩阵提供了关于多项式回归系数的重要信息。 **polyfit** ,使用最小二乘法拟合数据,并在内部存储拟合过程中发现的线性回归系数。为了绘制线性回归函数,需要通过函数 **np.poly1d()将已经找到的多项式系数转换成多项式函数。**
例如,现在我使用 **np.polyfit()** 函数对上面的 x 和 y 数组执行简单的线性回归( *n = 1* )并绘制结果。我使用以下 Python 代码:
[In]: import matplotlib.pyplot as plt
[In]: p = np.poly1d(np.polyfit(x, y, 1))
[In]: x_line = np.linspace(np.amin(x), np.amax(x), 200)
[In]: plt.scatter(x, y)
[In]: plt.plot(x_line, p(x_line))
[In]: plt.show()
您可以在您的计算机上运行上面的 Python 代码来显示简单线性回归的曲线图,但是,为了清楚起见,这里我没有显示曲线图。此外, **polyfit** 为用户提供了了解线性回归系数的可能性。事实上,如果您在上面的代码中显示变量 p,您将得到下面的线性回归线,公式如下:
[In]: print(p)[Out]: 2.4e-05 x + 5.742
因此,用 **np.polyfit()** 进行线性回归的结果是一条线性回归线( *y(x) = a + bx* ),截距为 *a* =5.741(精确值),斜率为 *b* =2.39e-05(精确值)。print(p)命令给出一个近似值显示。
**polyfit** 模块对于拟合简单线性回归和 n 次多项式回归非常有用。但是,它不允许用户使用带有多个预测变量的线性回归,即多元回归。因此, **np.polyfit()** 不能用于混合相互作用项,只能用于自相互作用项。此外,它没有给用户直接*计算的可能性:确定系数 *R* 以评估拟合优度,皮尔逊相关系数 *r,*假设检验的 *p* 值,以及与回归系数相关的样本误差。*
# 2.科学回归
SciPy 是一个 Python 库,代表科学 Python。它是学术界和科学工业中使用的最重要的科学计算库。该库包含几个用于特定目的的模块。在这些模块中,[**scipy . stats()**](https://docs.scipy.org/doc/scipy/reference/stats.html)**模块是关于统计建模最重要的一个模块。[**scipy . stats()**](https://docs.scipy.org/doc/scipy/reference/stats.html)**模块有一个完全专用于线性回归的子模块,它符合语法:[**scipy . stats . linregresse()**](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html)**并使用最小二乘法作为最小化标准。******
******现在来看看**Lin regressive**的运行情况,我再次使用上面的数组 x 和 y,并使用下面的 Python 代码:******
[In]: import scipy as sp
[In]: regr_results = sp.stats.linregress(x, y)
[In]: print(regr_results)[Out]: LinregressResult(slope=2.3996299825729513e-05, intercept=5.741754353755326, rvalue=0.720287195322656, pvalue=3.4265564700646986e-07, stderr=3.851624914535862e-06, intercept_stderr=0.15853194959552008)
****从上面的 Python 代码中可以看出,**Lin regressive**模块给出线性回归的结果作为输出,其中截距值为, *a* = 5.741,斜率值为 *b* = 2.39e-05。 *a* 和 *b* 的这些值与前面章节中使用 NumPy 的 **polyfit** 模块得到的值相同。另外,**Lin regressive**计算皮尔逊相关系数 *r* (值为 rvalue = 0.72)、p 值(pvalue = 3.42e-06)、斜率的标准差 *b* (stderr = 3.85e-06)、截距项的标准差*a*(intercept _ stderr = 0.15)。显式计算和 Python 代码可以在[我的 GitHub 页面](https://github.com/DamianEjlli)找到。****
****如上所示,**Lin regressive**模块向 **polyfit** 模块提供线性回归的附加结果。linregress 的唯一缺点是不支持多元回归。它只支持简单的线性回归。此外,它没有为用户提供直接*预测未在最小二乘法中使用的特性的新值的选项,如下面第 5 节中的 scikit-learn 库。*****
# ****3.统计模型的 OLS 和最小二乘法****
****[**stats model**](https://www.statsmodels.org/stable/index.html)**s**库/模块是 **scipy.stats** 模块的扩展,主要用于将模型拟合到给定的数据集。这个模块可能是关于一般回归,特别是线性回归的最完整的模块。该模块非常灵活,它为用户提供了几个选项来执行特定的统计计算。****
****正如我在第 2 节和第 3 节中所做的那样,我使用 **statsmodel** 来执行简单的线性回归,方法是使用上述 x 和 y 数组,并使用最小二乘法作为最小化标准,使用 [**OLS**](https://www.statsmodels.org/stable/examples/notebooks/generated/ols.html) 模块。我使用以下 Python 代码:****
[In]: import statsmodels.api as sm
[In]: x = sm.add_constant(x) # Adds an intercept term to the simple linear regression formula
[In]: lin_model = sm.OLS(y, x)
[In]: regr_results = lin_model.fit()
[In]: print(regr_results.results)[Out]: [5.74175435e+00 2.39962998e-05]
****用上面的代码打印结果后,我得到了 x 和 y 数组上简单线性回归的截距 *a* = 5.741 和斜率 *b* = 2.39e-05 的值。 **OLS** 模块隐式使用最小平方最小化方法来计算回归系数。人们可以注意到, *a* 和 *b* 的值与之前用其他方法在第 1 节和第 2 节中发现的值一致。****
****使用 python 命令**print(regr _ results . summary())**可以获得回归结果的更详细描述,其中结果表如图 2 所示。如您所见,汇总表给出了线性回归结果的详细信息,包括:决定系数 *R* ,截距值 *a* 及其标准差,斜率值 *b* 及其标准差, *t* 得分值,p 值,置信区间等。****
********
****图二。使用 **statsmodel** 库的 **OLS** 模块进行简单线性回归的结果表。****
******OLS** 模块和它的等价模块[**ols**](https://www.statsmodels.org/stable/generated/statsmodels.formula.api.ols.html)**(在本文中我没有明确讨论 **ols** 模块)比**Lin regressive**模块有优势,因为它们可以执行多元线性回归。另一方面,模块 **ols,**的缺点是它没有选项*直接*预测新值 *y* 对于预测器**x _ I的新值(至少我不知道)。此外, **OLS** 模块的另一个缺点是,必须使用命令 **sm.add_constant()** 为线性回归显式添加一个常数项。 [**线性 _ 模型。另一方面,OLS**](https://www.statsmodels.org/stable/generated/statsmodels.regression.linear_model.OLS.html) 模块为用户提供了在给定设计矩阵的情况下预测新值的可能性,类似于 scikit-learn 的**线性回归**模块。********
# **4.scikit-learn 的线性回归**
**scikit-learn 是统计/机器学习的最佳 Python 库之一,它适用于拟合和进行预测。它为用户提供了不同的数值计算和统计建模选项。其最重要的线性回归子模块是 [**线性回归**](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html) **。**它使用最小二乘法作为最小化标准来寻找线性回归的参数。**
**正如我在前面几节中所做的那样,我使用数组 x 和 y 进行简单的线性回归。我使用以下 Python 代码:**
[In]: from sklearn import linear_model
[In]: linmodel = linear_model.LinearRegression(fit_intercept=True)
[In]: linmodel.fit(x.reshape(-1, 1), y)
[Out]: LinearRegression()
**上面的 Python 代码使用线性回归来拟合 x 和 y 数组中包含的数据。如果现在需要从 fit 中获取一些参数,就需要编写额外的代码。例如,我想看看拟合过程的截距 *a* 和斜率 *b* 的值。为此,我运行以下 Python 代码:**
[In]: (slope, intercept) = (linmodel.coef_[0], linmodel.intercept_)
[In]: print(slope, intercept)
[Out]: 2.3996299825729496e-05 5.741754353755327
**如您所见,**线性回归**模块给出了与之前使用其他方法得到的截距 *a* 和斜率 *b* 相同的值。此外,还可以使用 Python 命令*:***print(linmodel . score(x . shape(-1,1),y))** 计算确定系数 *R* ,其给出的值 *R* = 0.518 与使用图 2 的 **OLS** 模块结果给出的值相同。**
****LinearRegression** 模块的优势在于,它为用户提供了使用 **linmodel.predict()** 命令直接*预测新数据的新值的可能性。这个函数使得**线性回归**模块对于统计/机器学习非常有吸引力。与 **OLS** 模块一样,**线性回归**模块也可以根据需要进行多元线性回归。**线性回归**模块的缺点是,它没有像 **OLS** 模块那样的回归结果汇总表,并且它迫使用户显式地编写新命令来获得重要的统计信息。此外,使用**线性回归**模块进行多项式回归可能相当麻烦,因为在获得回归结果之前需要计算设计矩阵 ***X*** 。在我之前的[文章](https://medium.com/geekculture/understanding-the-bias-variance-error-with-specific-python-examples-145bd3255cfd)中可以清楚地看到这一点。***
# ***5.seaborn 的 regplot***
***s [eaborn](https://seaborn.pydata.org) Python 库是一个非常重要的统计结果可视化库。从技术上讲,它不是一个可以用来计算回归参数的库,正如我在前面几节中所展示的,但是它可以用来图形化地显示一个图中的回归线和置信区域。例如,如果我想绘制在前面部分获得的简单线性回归线,我需要运行以下 Python 代码:***
[In]: import matplotlib.pyplot as plt[In]: fig, ax = plt.subplots(figsize=(10, 6))
sns.regplot(x = x, y = y, ci=95, order=1,line_kws={'label': 'Linear regression line: \(Y(X)=5.74+2.39\cdot 10^{-5} X\)', 'color': 'm'}, seed=1,truncate=False, label="Original data")
ax.set_xlabel("GDP per capita 2015 (USD)")
ax.set_ylabel("Life Satisfaction Value")
ax.set_xticks([1000, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000, 100000])
ax.set_yticks(np.arange(3.0, 10.5, 0.5))
ax.legend(loc="upper left")*
***上述代码的结果与图 1 完全一致,如本文顶部所示。seaborn 的 **regplot** 模块在内部计算线性回归参数的值,并绘制线性回归参数的 95%置信区间(我在上述代码中设置了参数“ci=95 ”)的线性回归直线。此外, **regplot** 模块可以执行多元线性回归和逻辑回归的图形可视化,因为该模块强烈基于 **statsmodel** 库。总的来说,seaborn 的唯一缺点是它没有给用户提供直接*查看使用特定 Python 命令的回归结果的可能性。****
# ***结论***
***在本文中,我总结了最重要的 python 库及其回归模块,并给出了线性回归的具体例子。一个模块相对于另一个模块的优势取决于用户面临的特定问题。对于简单的线性回归和多项式回归, **polyfit** 和**Lin regresse**模块最容易使用,非常方便。另一方面,对于线性回归的详细统计结果来说, **OLS** 和 **ols** 模块可能是最好的,因为它们不难使用,并且在汇总表中给出了大量的回归结果。此外,**线性模型**的 **OLS** 子模块为用户提供了在[线性模型**的帮助下进行预测的可能性。OLS**](https://www.statsmodels.org/stable/generated/statsmodels.regression.linear_model.OLS.html) 模块**。**对于统计/机器学习,scikit-learn Python 库的 **LinearRegression** 模块是最好的模块之一,因为它可以用于进行预测,这是上面提到的大多数其他模块都不具备的功能。如果希望在没有拟合参数值信息的情况下直接绘制统计程序的结果,那么 seaborn 的 **regplot** 模块是最好的选择之一。***
***在我对用于回归的最佳 Python 模块的总结中,我没有包括 Pandas 库,尽管它可以显式地计算线性回归的一些参数,例如皮尔逊系数 *r* 等。,详见[我的 GitHub 页面](https://github.com/DamianEjlli/Data-Science-Project-GDP-and-life-satisfaction)。此外,NumPy 的 [**lsqt**](https://numpy.org/doc/stable/reference/generated/numpy.linalg.lstsq.html) 模块提供了进行一些回归的可能性,但是与上面提到的模块相比,Pandas 库和 **lsqt** 模块都处于较低的级别。***
## ***如果你喜欢我的文章,请与你可能对这个话题感兴趣的朋友分享,并在你的研究中引用/参考我的文章。不要忘记订阅将来会发布的其他相关主题。***
# 设计表格的五条规则
> 原文:<https://towardsdatascience.com/five-rules-for-designing-tables-a953a16e50f3?source=collection_archive---------20----------------------->
## 简单的设计元素让您的电子表格流行起来

设计表格的 5 条规则。作者:Alana Pirrone
让人们对表格或 Excel 电子表格感到兴奋不是一件容易的事情。通常,它们被一排排的数字填满,当人们看到一个数字时,他们的眼睛似乎变得呆滞。您可以将一些简单的设计元素合并到 Excel 表格中,使其更易于读者浏览。
我最近在一份大学报告中看到了这张表,它从几个指标看了他们在过去五年中的表现。虽然这个表格比标准的 Excel 电子表格要好,但我认为我可以更进一步,创造出一些值得兴奋的东西。

之前。在一份大学报告中发现的表格设计。

之后。使用迷你图重新设计表格。
让我们来看看设计表格的五条规则。
# **文本层次**
在你制作的任何设计作品中,创造层次都是至关重要的。我们需要为我们的观众提供一个清晰有序的导航方式。通常最大最粗的部分会最先吸引我们的注意力,也是最重要的,最小最轻的部分最不重要。
在我们的表格设计中,我们可以通过将标题设置为大而粗的字体并放置在左上角来建立文本层次结构。那是我们希望我们的观众开始阅读的地方。我们的下一级文本层次是行标题和列标题。我设计了比标题略小的字体,但仍然是粗体和彩色的。使用颜色有助于将它们与其他数据区分开来,并有助于创建不同的部分。第三层是行副标题。它们的大小和颜色与正文相同,但以粗体显示。表中的其余数据是我们的第四级结构,称为正文。
# 空格
> **“空白用于将属于一起的数据对象与其他数据对象分开,从而对它们进行分组”** —斯蒂芬·诺,给我看看数字。
白色空间充当呼吸空间。仅仅确保 Excel 电子表格中的列之间有空白是不够的,还要考虑行与行之间的空白。这有助于你的读者更有效地阅读这些行。如果数据行靠得太近,我们就很难在不与其他行混淆的情况下跟踪整行数据。在《给我看数字》一书中,Stephen worth 建议将单元格内的行高增加一倍。例如,如果我使用 10 磅的字体,我的单元格高度应该是 20 磅。

行高应该是字体大小的两倍。
# 对齐
作为一个快速的经验法则,所有的文本应该左对齐,所有的数字应该右对齐。显然,这条规则也有例外,但在大多数情况下,这是最有效的。避免使用居中对齐的列,尤其是对于文本,因为我们的眼睛很难浏览带有锯齿状边缘的数据。
列标题应该与其列共享相同的对齐方式,不管是文本还是数字。

列标题应该与其列共享相同的对齐方式,不管是文本还是数字。
# 迷你图
迷你图是由爱德华·塔夫特创造的,被描述为**“小而强烈、简单、只有一个字大小的图形。”对于显示数据趋势的大量数字表格来说,它们是一个完美的补充。在上表中,我使用了折线图和柱形图两种迷你图。我使用迷你图的目的是让读者能够快速浏览内容,找到他们需要的内容,或者在这种情况下,找到我想告诉他们的内容。我在每个迷你图中突出显示了“高点”,以查看它们在过去五年中每个指标的比较情况,以及哪一年最成功。当迷你图的其余部分为灰色时,此高亮颜色效果最佳。**
请注意,迷你图的 Y 轴是由该特定行中数据的最高点和最低点测量的。因此,在迷你图之间进行比较可能不准确。如果您想要始终保持一致的轴,可以在迷你图选项卡下进行更改,方法是单击轴>垂直>并在最小值和最大值下为所有迷你图选择相同。
# 需要考虑的其他几点
* 使用深灰色文本而不是黑色,尤其是当你使用动作或高亮颜色时。它失去了数字和纸张之间的鲜明对比,让我们突出的颜色更具视觉冲击力。
* 只使用一种字体,最好是无衬线字体。读起来简单多了。
* 如果你使用日期,要保持一致。例如,如果你写 2021 年 4 月 1 日,写 01/04/2021 而不是 1/4/2021。这将使您的列中的数字排列得更好。
快乐设计!
*Alana Pirrone 是澳大利亚墨尔本大学的设计和数据可视化顾问、设计和沟通协调员。在 alanapirrone.com.au*<https://www.alanapirrone.com.au/>*了解更多关于 Alana 的信息*
# 99%的初级 Python 开发人员都会陷入五个微妙的陷阱
> 原文:<https://towardsdatascience.com/five-subtle-pitfalls-99-of-junior-python-developers-fall-into-721727a73c55?source=collection_archive---------2----------------------->
## 我曾经是那 99%中的一员。

照片由作者用 Python 编辑的[若热·热苏斯](https://www.pexels.com/@jorge-jesus-137537?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels)来自[像素](https://www.pexels.com/photo/computer-program-language-text-614117/?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels)
如果说数据科学是“21 世纪最性感的工作”,那么 Python 无疑是“21 世纪最性感的编程语言”
Python 出色地降低了计算机科学的入门门槛。当你听到有人说“如果你懂英语,你就可以用 Python 编程”,期待各行各业的人都选择数据科学和编程职业。主要是因为有利可图的工作前景;部分原因是社区中流传的数据科学术语——这些术语让人觉得他们在建造火箭船。
Python 无非就是一个工具。编写代码的工具。然而,我必须警告你,亲爱的皮托尼斯塔,你的工作并没有以一个功能代码结束。相反,这只是开始。开始一段艰苦的旅程,制作一件艺术品,希望能让你与一般的 Python 程序员有所不同。
为了帮助您,我整理了大多数初级(和一些中级)Python 开发人员容易陷入的五个陷阱。我将要向您展示的陷阱,无论看起来多么微妙,都有助于获得一段干净、设计良好的代码。最重要的是,他们可能会让你的技术领导说“这个人知道他们在做什么。”
放心吧,我不会说教理论的。相反,我会用代码来支持我的声明,以彻底消除任何一丝疑虑。
## #1.盲目使用集合
集合是不同元素的无序集合。集合检查成员资格的能力非常强大。更正式地说,与复杂度为 O(n)的列表相比,集合的复杂度为 O(1),这使得它们非常快。除了充当重复过滤器之外,速度可以说是使用集合而不是其他数据结构的主要原因。
一般来说,在使用条件句时,你应该区分集合的优先级。然而,你不应该做的是迭代它们。
类似于下面的例子:
from time import timemy_set = {i for i in range(1000000)}start = time()
def even(sample):
even_list = []
for num in sample:
if num % 2 == 0:
even_list.append(num)
return even_listeven(my_set)
end = time()
print(f"runtime : {end - start}")
输出:
runtime : 0.16255903244018555
当我遍历一个列表时,我得到了下面的结果:
runtime : 0.11905360221862793
你可以清楚地看到性能方面的差异。布景很快。但它们并不总是如此。列表得到了很好的优化,可以在循环时以最高的性能运行。
因此,你不应该总是遵循集合更快的假设。有时候事情还是顺其自然。任何其他的调整都会耗费你思考和运行的时间。
## #2.无限循环
当你想听一个事件时,无限循环是你最好的选择。我相信你已经学会使用`**while** True`进行无限循环。至少我一直是。我被告知,在正当理由下,`**while** True`是整洁的、明确的和 Pythonic 式的,这是真的。然而,`**while** True`并不是最有效的无限循环媒体。
`**while** 1`确实是比`**while** True`高效一点。与布尔值 True 相反,1 是一个数字布尔值。因此,性能有所提高。
## #3.用+和 join()连接字符串
如果你没有跟上 Python 的发展趋势,我怀疑你还在使用`+`和`join()`来格式化你的字符串。如果是这样的话,那你就走运了,因为你将摆脱一些旧的坏习惯,接受一种新的更好的字符串操作语法。
看看下面的脚本:
from time import timeLINKING_WORD = 'and'start1 = time()
for x in range (1000000):
friends1 = LINKING_WORD.join(['Jake ', ' Peter'])end1 = time()
print("runtime join():", end1 - start1, "seconds")start2 = time()
for x in range (1000000):
friends2 = 'Jake '+ LINKING_WORD +' Peter'end2 = time()
print("runtime +: ", end2 - start2, "seconds")start3 = time()
for x in range (1000000):
friends3 = f"Jake {LINKING_WORD} Peter'"end3 = time()
print("runtime f-: ", end3 - start3, "seconds")
结果是:
runtime join(): 0.5975692272186279 seconds
runtime +: 0.3718130588531494 seconds
runtime f-: 0.28975749015808105 seconds
上面的代码显示了`f-string`与`join()`和`+`相比效率有多高。`f-string`是一种 pythonic 式的、高效的字符串操作语法。
事实上,`f-string`是相当新的。它是在 Python 3.6 中引入的。目前,它是字符串格式化的可靠选择之一。最棒的是,它清晰易用。
## #4.冗长的 If-else 语句
在编程中,没有什么比非结构化、冗长的条件分支更糟糕的了,尤其是当您使用像 Python 这样简洁明了的语言时。
写得不好的语句不仅难以跟踪,而且还会减慢你的程序。
为了让您为难,让我们比较下面的两段代码。
代码 1:
from time import time
start = time()for _ in range(1000000):
a = 10
b = 5
if a == 10 and (b == 1 or b == 2 or b == 3 or b == 4 or b == 5 or b == 6):
pass
elif (a == 5 or a == 9) and b == 4:
pass
else:
passend = time()print(f"runtime: {end - start}")
结果是:
runtime: 0.49709439277648926
代码 2:
from time import time
start = time()for _ in range(1000000):
a = 10
b = 5
if a == 10 and 1 <= b <= 6:
pass
elif a in [5, 9] and b == 4:
pass
else:
passend = time()print(f"runtime: {end - start}")
结果是:
runtime: 0.3018171787261963
如您所见,干净的`if-else`语句除了对读者友好之外,还非常有效。
现在让我们分解代码的细节,以找到性能的来源。
首先要考虑的是`in`的使用。和 pythonic 一样快。其次,比较运算符`<= value <=`提供了额外的性能。
现在,您可以看到 Python 如何通过弥合效率和风格之间的差距来杀死它。
## #5.遗忘工具
听说过 Python 的 [gem](https://more-itertools.readthedocs.io/en/latest/index.html) 库吗?如果没有,就见`itertools`。
`itertools`是一个强大的 Python 库。然而,奇怪的是被许多人低估了。`itertools`在概率、线性代数和高效编码方面崛起并大放异彩。
现在,让我们放大一下`itertools`能提供什么。
from time import time
import itertoolsLIST = [i for i in range(10000000)]start1 = time()
standard slicing with lists
LIST[:5000000]
end1 = time()
print(f"runtime lists: {end1 - start1}")start2 = time()
slicing with itertools
itertools.islice(LIST, 5000000)
end2 = time()
print(f"runtime itertools: {end2 - start2}")
结果是:
runtime lists: 0.10329008102416992
runtime itertools: 0.0
如你所见`itertools`速度很快。这仅仅是因为`itertools`库受到了 Haskell、SML、APL 的启发,它们都非常高效。
请注意,这个例子只是你能从`itertools`中挤出的沧海一粟。
## 结束语
到目前为止,您可能已经注意到了上述缺陷中的一种模式:它们都与性能相关。这正是它们微妙的原因。
众所周知,一般初级开发人员都专注于拥有一个无 bug 的代码。聪明的人倾向于同时考虑代码的正确性和美观性。然而,独特的初级程序员通过将效率放在其他考虑因素之上而使自己与众不同。
这么说,这个岗位注定是论资排辈的捷径。这是因为学长喜欢做事与众不同的人。据我所知,没有多少初级开发人员知道这篇文章中提到的实践。
> “加入人群不需要什么。独立需要一切”——汉斯·汉森
祝你编码好运。
# 部署机器学习模型的五种技术
> 原文:<https://towardsdatascience.com/five-technologies-to-deploy-your-machine-learning-models-bddaad69e0d4?source=collection_archive---------12----------------------->
## 深入现代 ML 部署工具

SpaceX 在 [Unsplash](/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上拍摄的
与构建 ML 模型不同,模型部署一直是数据科学中最大的痛点之一,因为它更倾向于软件工程方面,并且对于初学者来说有着陡峭的学习曲线。
然而,近年来,已经开发了一些工具来简化模型部署。在本文中,我们将介绍五种可以用来部署机器学习模型的技术。
*如果你不完全确定什么是模型部署…*
模型部署意味着将机器学习模型集成到现有的生产环境中,该环境接受输入并返回输出,以根据数据做出实际的商业决策。
也就是说,这里有五种技术可以用来部署你的机器学习模型:
# 1.码头工人
Docker 是一个允许你在容器中创建、部署和运行应用程序的平台。您可以将容器视为软件的标准单元,它将应用程序的代码捆绑在一起,以便从一个计算环境快速可靠地运行到另一个计算环境。Docker 还加速了容器化和实现过程,因此它可以用于将 ML 模型部署到其他环境中。我们也可以说它是将代码和依赖项打包到一个称为“容器”的封闭盒子中的过程。
## 赞成的意见
1. Docker 减轻了调试环境的痛苦。
2. Docker 有助于加快供应过程。
3. Docker 社区庞大,资源丰富。
## 骗局
1. Docker 在非本机环境中存在性能问题。
2. Docker 在文档方面有一些空白。
3. Docker 是平台相关的。Windows 容器只能在 Windows 上运行。Linux 容器只能在 Linux 上运行。等等。
# 2.格拉迪欧

[图片由 Gradio 拍摄(经许可)](https://www.gradio.app/hub/aliabid94/hub-titanic)
Gradio 是一个开源的 python 库,它允许我们只需几行代码就可以为我们的机器学习模型、API 或任意函数快速创建易于使用、可定制的 UI 组件。
Gradio 是一个适应性很强的 UI,与 Tensorflow 或 Pytorch 模型结合在一起。它是免费的,而且一个开源框架使任何人都可以迅速获得它。
## 赞成的意见
1. Gradio 提供了几个可定制的 UI 组件,针对机器学习模型进行了优化。例如,Gradio 提供了易于使用的拖放式图像分类,该分类针对用户进行了高度优化。
2. 设置 Gradio 非常简单快捷。可以通过 pip 直接安装。此外,在 Gradio 中创建接口只需要几行代码。
3. Gradio 创建了可共享的链接,这可能是在用户面前部署机器学习的最快方式
4. 与其他包不同,Gradio 可以在 Jupyter/Colab 笔记本或独立的 Python 脚本中的任何地方运行。
## 骗局
1. 虽然 Gradio 在官方网站上有很好的文档,但很难找到关于它提供的具体功能的信息和足够的例子。
2. Gradio 的社区比其他一些软件包要小,所以很难找到关于它的资源。
# 3.库伯内特斯
Kubernetes 是一个用于监督容器化责任和管理的开源平台。我们可以将 Kubernetes 部署定义为 Kubernetes 中的一个资源对象,它向应用程序提供声明性更新。部署允许我们描述应用程序的生命周期,例如,应用程序使用哪些图片,以及应该以何种方式更新这些图片。
## 赞成的意见
1. Kubernetes 有助于使应用程序运行更加稳定。
2. 利用 Kubernetes 及其庞大的生态系统可以帮助提高效率和生产力。
3. Kubernetes 可能比它的替代品便宜。
## 骗局
1. Kubernetes 对于基本的应用程序来说可能是多余的,因为它非常复杂。
2. 向 Kubernetes 的过渡可能是陡峭而繁琐的。
# 4.SageMaker
SageMaker 是一项完全受监管的服务,它使开发人员和数据科学家能够快速有效地构建、训练机器学习模型,并将其部署到任何规模的生产就绪托管环境中。Amazon SageMaker 整合了可以一起使用或自由使用的模块,以构建、训练和部署 ML 模型。
它提供了一个集成的 Jupyter writing notebook 实例,可以简单方便地访问用于调查和分析的数据源,因此您不需要监管任何服务器。此外,它还提供了常见的机器学习算法,这些算法经过改进和优化,可以在分布式环境中针对大量数据有效运行。
## 赞成的意见
1. SageMaker 从外表上看机器学习模型的发展是不可思议的。这个循环是在一个合乎逻辑的逐步过程中建立起来的。
2. SageMaker 使训练数据模型变得简单。构建训练和测试样本非常简单。
3. SageMaker 使机器学习模型的部署比其他开源工具简单得多。
## 骗局
1. 由于 SageMaker 专注于机器学习模型,因此数据科学家可能使用的不同模型可能需要更多的努力才能合并。
2. SageMaker 在更大的数据集上运行可能需要很长时间。在这种情况下,SageMaker 似乎没有其他工具那么快。
# 5.MLFlow
MLflow 是一个处理 ML 生命周期的开源平台,包括实验、再现和部署。它旨在与任何 ML 库、计算、算法、语言和部署工具一起工作。
## 赞成的意见
1. 它旨在用于任何云环境。
2. MLflow 与各种开源机器学习框架相结合,包括 Apache Spark、TensorFlow 和 SciKit-Learn。
3. 它跟踪试验和实验,记录和比较参数和结果。
4. 它将 ML 代码捆绑并打包成一个可重用、可复制的结构,以便传授给其他数据科学家或转移到生产中
5. 它监督和部署从各种 ML 库到各种模型服务和推理平台的模型。
## 骗局
1. MLFlow 不太灵活,因为它不能自动包含风格——风格本质上是 MLflow 可以支持的库/工具。
# 感谢阅读!
不确定接下来要读什么?我为你挑选了另一篇文章:
</introducing-dbt-the-etl-elt-disrupter-4351adc34123>
**又一个!**
</a-complete-52-week-curriculum-to-become-a-data-scientist-in-2021-2b5fc77bd160>
# 特伦斯·申
* ***如果你喜欢这个,*** [***跟我上媒***](https://medium.com/@terenceshin) ***了解更多***
* ***有兴趣合作吗?让我们连线上***[***LinkedIn***](https://www.linkedin.com/in/terenceshin/)
* ***报名我的邮箱列表*** [***这里***](https://forms.gle/tprRyQxDC5UjhXpN6) ***!***
# 解决 500 个 Leetcode 问题后我学到的五件事
> 原文:<https://towardsdatascience.com/five-things-i-have-learned-after-solving-500-leetcode-questions-b794c152f7a1?source=collection_archive---------0----------------------->
## 为什么研磨 Leetcode 没那么糟糕

在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄的 [ThisisEngineering RAEng](https://unsplash.com/@thisisengineering?utm_source=medium&utm_medium=referral)
任何寻找软件开发职位的人都可能非常了解 Leetcode,该网站收集了一些最受欢迎的公司如谷歌、脸书和微软的技术面试中出现的问题和解决方案。
这种涉及数据结构和算法的面试问题甚至在小公司中越来越受欢迎,这是许多人感到沮丧的原因,他们认为自己的“电子编码”技能不能反映他们的工作能力。
虽然我同意不了解 Leetcode 并不会让你成为一个糟糕的开发人员,而且在你工作期间你可能永远不需要[反转二叉树](https://twitter.com/mxcl/status/608682016205344768)这可能是真的,但是打磨 Leetcode 可以教会你很多事情,这将证明对你的职业生涯是有益的。
## 1)数据结构和算法的重要性
Leetcode 不是 DSA 课程,如果你之前没有这方面的准备,你肯定应该参加一门旨在教你能够有效使用该平台的基础知识的课程,但它在帮助你深入了解它们如何工作以及它们最擅长什么方面非常突出。
老实说,坚实的数据结构基础对于每个开发人员来说都是必不可少的,我最近看到一个简单的[算法改进如何能够为 GTA V](https://screenrant.com/gta-online-5-loading-time-fix-mod-update/) 减少 70%的加载屏幕时间的故事,我从经验中知道高效的实现如何能够让应用程序即使在压力下也能平稳运行。
## 2)总有人比你更有见识
在达成解决方案后,我通常会对自己的代码感到非常自豪,但当我阅读评论部分时,这种自豪通常会消失,在评论部分,您有时可以找到甚至优于官方解决方案的实现。
老实说,我在编写 Leetcode 时学到的知识中,大约有一半来自于仔细阅读他人的代码,并尝试自己实现他们的建议。
总是有更多东西需要学习的想法在我的工作中更加有效,我很幸运有非常有经验的前辈帮助我提高,这种向他人学习的心态让我尽可能多地吸收他们的知识。
## 3)边缘案例会毁了你的一天
在我开始工作之前,如果我在代码中犯了一个错误,并没有真正的利害关系,一个情境 bug 永远不会出现并被忽略。现在情况完全不同了,我在生产代码库上工作,有成千上万的人与我的工作互动,任何 bug,即使是影响到一个小的边缘案例,都可能出现,给我们的客户带来不便甚至损害。
谢天谢地,Leetcode 是一个很棒的训练场,每个问题都有数百个测试案例,通常包括每个边缘案例,如果不加以考虑,就会破坏代码。
当我最近不得不处理一个没有适当约束且在许多行中包含意外值的数据库时,我意识到这是多么重要,谢天谢地,我能够在这些问题成为生产中的问题之前在我的代码中解决它们。
## 4)努力战胜天赋……
…天赋不努力的时候。我很喜欢 Tim Notke 的这句话,从我的个人经验来看,这句话非常适用于 Leetcode,我知道许多出色的、非常有才华的开发人员不能解决大多数中型问题,因为他们不知道模式和要使用的正确工具,也没有开发出解决这类问题的适当结构。
当我开始的时候,我甚至比那更糟糕,我几乎挣扎于任何简单的问题,但是在做了几个关于 DS&As 的课程和磨了许多容易的问题之后,我能够进步到在合理的时间框架内解决大多数中等的问题,甚至一半的时间解决困难。
当我最近从 Python 转到 Java 来解决问题时,我又一次确认了实践的重要性,虽然我每天在工作中使用 Java,但在这种情况下感觉一点也不直观,如果不像初学者那样搜索实现细节,我就无法解决大多数问题。
这并没有让我气馁,现在我知道只要有足够的练习,我会像精通 Python 一样精通 Java。
## 5)规划是软件开发的重要部分
在实践和真正的面试中解决许多问题,我很快意识到编码只是过程的一部分,阅读提示后立即编写解决方案可能是一个人可能犯的最大错误。
软件开发充满了模棱两可和意想不到的结果,编码面试经常试图通过提供模棱两可或不完整的问题来复制它,这取决于你与面试官沟通,并要求澄清和可能的限制。
不仅如此,在编写实际代码之前,你应该提出一个解决方案,分析它的优点和缺点,只有当所有人都同意你提出的方案是可以接受的时候,才开始编码;如果你开始编码一些不满足时间和空间需求的东西,在你意识到之前就太晚了,你将没有时间去实现更好的东西。
这在实际工作中同样重要,如果你在没有分析需求和仔细考虑可能性的情况下就开始编写代码,你很可能最终需要重构你的大部分工作。
## 结论
就我个人而言,我很幸运喜欢 Leetcode,我不介意在不找工作的时候练习它,但我知道许多人非常不喜欢它,认为它没有教授任何适用于实际工作的知识。我希望通过我的文章,我至少让你们中的一些人相信事实并非如此,如果你被迫用它来准备面试,至少试着从中获得一些有价值的东西,嘿,如果你真的不喜欢它,有许多工作不会问你 Leetcode 问题。
感谢您的阅读,请随时通过 Linkedin 与我联系,如果您想支持我,您可以通过我的链接注册一个中等合作伙伴关系。
<https://medium.com/@federicomannucci_31459/membership>
# 商业环境中强化学习需要考虑的五件事
> 原文:<https://towardsdatascience.com/five-things-to-consider-for-reinforcement-learning-in-business-environments-23647a32f01f?source=collection_archive---------23----------------------->
## 强化学习不仅仅可以用于走迷宫和玩棋盘游戏。然而,现实生活中的实现本身就很混乱。

这是一家企业,通过促进合作的开放式办公空间、配有平板电视的舒适休息区和蛇类植物得到认可。在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上由 [Austin Distel](https://unsplash.com/@austindistel?utm_source=medium&utm_medium=referral) 拍摄的照片
即使是那些完全不熟悉强化学习(RL)的人,也可能知道 DeepMind 的 AlphaGo 是如何在古代棋盘游戏 Go 中击败世界冠军 Lee Sedol 的。对许多人来说,RL 已经成为玩游戏的代名词,无论是国际象棋、超级马里奥,还是简单地穿越冰冻的湖泊。游戏有趣、直观、定义明确,并且通常包含独特的属性,这使得它们对学习算法具有挑战性。毫不奇怪,它们被作为新 RL 技术开发的基准问题。然而,这并不意味着 RL 仅限于*人工智能健身房*。
公司通常关心以最大化利润的方式分配资源。这不是一次性的决定,而是一系列长期的决定,今天做出的决定会影响明天的表现。在这种混合中加入相当多的不确定性,决策往往变得令人烦恼,超出了人类的认知极限。在这种环境下做出明智的决策会让你比竞争对手更有优势,而 RL 在这方面可以有所贡献。然而,在深入研究现实世界的业务问题之前,有一些重要的方面值得考虑。
# 一.成果、成果、成果
是的,三次,因为这可能是第一点、第二点和第三点。诚然,这不仅仅是一点陈词滥调,但这是有原因的。对于企业来说,部署强化学习的目的是为了解决问题。一种算法应该使企业能够**做出更好地定位未来**的决策。如果 RL 不能产生直接的、可衡量的影响,它就没有什么价值。
为了具有实用价值,源自 RL 的(自动化)决策支持也应该**集成到现有的工作流中**。在许多情况下,这意味着使用已经存在的系统。例如,如果确定性规划算法已经存在,简单地添加一些前瞻特征通常比从头开始设计 RL 算法更易于管理。
计算时间自然也是一个相关点。对于战略和战术层面的决策,更长的运行时间是可以原谅的。然而,如果 RL 支持日常运营决策,则必须限制在线运行时间。
# 二。未来必须是可预测和可影响的
> “预测很难,尤其是关于未来的!”—尼尔斯·玻尔
为了能够预测一个过程,它实际上应该是可预测的。当然,每个人都想拥有一个预测股价走势的 RL 算法——至少我想——并告诉你何时买入何时卖出。工厂经理想知道机器零件什么时候坏,以便及时更换。至于任何机器学习算法,**数据实际上应该包含一个可以辨别的模式**。
不用说,应该有足够的高质量数据。正如任何数据科学家所知,'*垃圾输入=垃圾输出【T3]'—RL 算法也不例外。需要大量高质量的数据才能学到有用的东西。一个大型的神经网络可能需要数百万次的观察来正确训练;历史记录可能不足以达到这样的目的。如果一个基本的线性回归实际上会产生更好的结果,不要感到惊讶。*
到目前为止,没有什么新的,但 RL 有一些自己的挑战,没有监督学习的经验。那些曾经试验过重放缓冲区的人很快意识到**一旦确定了更好的政策,许多观察就会变得过时**。一家卡车运输公司可能有大量来自东海岸的数据,但如果政策告诉您探索西部边境,该怎么办?有时候效果很好——例如,你可以根据历史价格数据对许多投资策略进行回溯测试。其他时候,你可能会随意模拟新的结果。尽管有时,一旦偏离当前的实际政策,正确的数据可能就不存在了。
RL 环境通常是[部分确定和部分随机的](/what-are-post-decision-states-and-what-do-they-want-from-us-9e02105b7f40)。如果你能比别人更好地预测或模拟随机过程,你应该能胜过竞争对手。如果你能通过当前的行动更好地为未来做准备,这同样适用。如果你不能预测太多,今天的决定几乎不会影响明天的表现,或者你根本没有数据,RL 可能是错误的方法。
# 三。问题表述是关键
对于棋盘和电脑游戏,问题的定义从一开始就是已知的。相比之下,实践并不能决定问题到底是什么,更不用说如何度量性能了。**定义适当的 KPI**可能是一门艺术。可能有多个重要的绩效指标和利益相关方,需要对它们进行权衡或排序。许多实际问题可以形式化为一个受一组约束的目标函数。我们希望利润最大化,但也要考虑我们的环境足迹。我们希望最大限度地降低成本,但必须保持合同服务水平。对于子流程,定义良好的性能指标可能并不容易。空列车的重新定位似乎对年度利润没有什么影响,但与业务目标的一致性应该存在。RL 算法将努力最大化你定义的目标:小心你想要的。
在与利益相关者交谈,抽象出问题的属性,并定义一个一致同意的目标之后,从数学上表述问题是非常重要的。马尔可夫决策过程和数学规划是这一步的重要框架。
一个**马尔可夫决策过程** (MDP)模型描述了不确定环境中的连续决策。本质上,它定义了*问题状态*(做出决策所需的信息)*动作*(允许的决策)*奖励函数*(决策的贡献或成本)*转换函数*(状态间转换的模型,受决策和随机波动的影响),以及*目标函数*(我们寻求优化的累积奖励函数)。尤其是对管理环境的分布和决策所需的信息所做的假设在业务环境中是必不可少的。
以**数学程序**的形式表达行动空间通常是方便的(即使没有求解到最优),因为它非常谨慎地定义了*目标函数*——显然应该与 MDP 中的目标函数一致——以及相应的一组*约束*。如果我们想降低成本,最低服务水平是什么,我们能保持多少订单量,什么样的卡车路线是可行的?现实世界问题的简化是不可避免的,然而[数学编程](/using-linear-programming-to-boost-your-reinforcement-learning-algorithms-994977665902)使得这些简化非常明显。

数学问题形成片段。这里,动作空间被公式化为线性程序[图片由作者提供] [1]
人们可能不同意你对现实的抽象,但是他们不应该有误解这种抽象的空间。
# 四。选择合适的解决方法
在解决方法的选择上,可以发现研究和工业之间的显著差距。学者和研究人员倾向于重视设计努力和数学优雅,而实践者相对更依赖于**蛮力和利用问题结构**。例如,确定性航线调度算法可以用松弛参数来扩展,松弛参数的值通过 RL 来确定。另一个例子是将今天的卡车路线问题求解到最优,并用一个简单的试探法估计本周剩余时间的路线成本。公司通常对问题结构有相当好的想法——这些结构可以在解决方法中加以利用。
尽管鲍威尔的四个政策类别过于简单化[2],我还是试图在这里做一个粗略的区分:

强化学习的四个策略类的简化[图片由作者提供]
固有的权衡是在设计努力和计算努力之间。尽管存在一些有用的指导方针[3],但是对于一个给定的问题,不一定有一个“最佳”的政策类别,更不用说一个*通用的*解决方案。不过这是另一个时间的讨论——现在,在构思现实世界 RL 问题的解决方案时,推荐一种开放的思维就足够了。
</the-four-policy-classes-of-reinforcement-learning-38185daa6c8a> [## 强化学习的四个策略类别
towardsdatascience.com](/the-four-policy-classes-of-reinforcement-learning-38185daa6c8a)
# 动词 (verb 的缩写)行动空间通常很大

照片由 [Graham Holtshausen](https://unsplash.com/@freedomstudios?utm_source=medium&utm_medium=referral) 在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 拍摄
在许多基准 RL 问题中,动作空间通常没有那么糟糕。穿越迷宫只需要一次评估四步棋。一个超级马里奥游戏有更多的按钮组合需要考虑,但仍然是易于管理的。一个国际象棋棋盘有令人眼花缭乱的状态,但在一个单一的棋盘组合中可行的走法数量很少超过 100。简而言之,对于大多数基准问题,动作完全在枚举的限制内,例如,作为行动者或深度 Q 网络的输出。
如前所述,商业决策通常可以归结为资源分配的问题——什么样的资产分配能产生最好的回报?这经常转化为基于向量的决策,其中许多资源同时被分配。如果你有 100 万美元,你如何最好地分配给所有纳斯达克股票?如果您的仓库中有 10,000 件产品,那么下个月您会为每种产品再订购多少件?如果你拥有一个由 1000 辆卡车组成的车队,你如何在全美范围内分配它们?
即使对于这些问题的确定性变体,动作枚举通常也是非常不可行的——**组合优化问题**可能会产生数百万、数十亿或数万亿个可行的动作。尽管有一线希望;很多现实生活中的问题是凸的,甚至是(近似)线性的。这是一个非常强大的属性,通常会使问题的解决变得相当容易。商业解算器可以在有限的时间内解决大量的问题——一个包含数百万个动作的线性程序可能在几秒钟内就可以解决。
尽管如此,即使数学编程也不能总是拯救我们。在几秒钟内做出决定听起来很棒,但如果我们需要数百万次训练观察,这些“几秒钟”真的会累加起来。通常需要(元)试探法和简化假设来处理动作空间。毕竟现实生活很乱。
# 行动纲要
* RL 解决方案需要**集成到现有的工作流程**中。最终,该算法应该能够改善现实世界中的决策。实际可用性、计算工作量、数据可用性、决策支持中的角色——所有这些因素都需要在一开始就加以考虑。
* 强化学习在部分可控的环境中有意义,并允许预测未来事件。**今天做出的决定应该会对未来产生一定的影响**,而且环境在一定程度上应该是可预测的。如果你不能真正影响或预测未来(或者只是没有数据),你可能会更喜欢短视的政策或确定性优化。
* 在考虑任何解决方案之前,首先要明确地对问题建模。对于每个利益相关者来说,目标(性能度量)和约束应该非常清楚。马尔可夫决策过程和数学规划是问题公式化的有用框架。
* 花点时间**挑选最合适的解决方法**(策略类)。这需要对手头的问题进行反思。问题结构可以被利用吗?额外的设计工作值得减少计算工作量吗?解决方案是否应该嵌入到现有算法中?
* 准备好**处理大量的行动空间**。资源分配通常需要组合优化。基于向量的问题通常非常大,需要数学规划和启发式归约等技术来保持其可管理性。
# 参考
[1] Van Heeswijk,W.J.A .,Mes,M.R.K .,& Schutten,J.M.J. (2019)。城市合并中心带时间窗的配送调度问题。*交通运输科学*, *53* (1),203–221。
[2]鲍威尔,W. B. (2019)。随机优化的统一框架。*欧洲运筹学杂志*, *275* (3),795–821。
[3]鲍威尔(即将露面)。强化学习和随机优化:顺序决策的统一框架。新泽西州霍博肯的约翰·威利父子公司。第 522-525 页。
# 作为一名有抱负的数据科学家需要关注的五件事
> 原文:<https://towardsdatascience.com/five-things-to-focus-on-as-an-aspiring-data-scientist-a52ce1d9ce89?source=collection_archive---------20----------------------->

开始学习数据科学可能会令人望而生畏。数据科学家被期望在一个人身上融合几种难以获得的技能,即:统计学、软件工程和分析。当你刚进入这个领域或者想一头扎进去的时候,知道从哪里开始或者关注什么真的很难(相信我,我记得很清楚!).
也就是说,很容易陷入不知所措的困境,以至于你完全推迟或停止了学习之旅。尽管这对你来说是一个可怕的结果。数据科学仍在快速发展,并作为一种技能和一门学科不断进化。
我给你的建议是专注于五项基本技能。剔除新语言、框架和算法的噪音,专注于核心技能,这些技能将加速您作为数据科学家的学习和成长能力。把这些做好,你就能在学习过程中轻松扩展你的技能和知识。
## 1)真正精通 SQL
有这么多有趣的机器学习模型要学习,有这么多问题要解决,很容易忘记成为一名有效的数据科学家实际上需要的核心技能之一。绝大多数数据科学家将拥有自己的数据管道和自己的数据来源,并承担端到端的责任。此外,你永远不应该依赖别人为你提取数据。这可能不是与工作相关的“性感”技能之一,但它是必不可少的(相信我这一点,在 FAANG 公司,你可能会在面试时被测试 SQL,作为最初的筛选任务)。您应该知道如何做的事情:
a)运行基本的选择查询,选择列、分组、过滤和应用聚合函数
b)与其他表连接—知道何时以及为什么使用左连接、内连接和右连接
c)编写子查询/使用临时表
d)使用窗口函数(滞后、超前、优先)。挑战自己,用 SQL 编写一个累积和函数。
## 2)同时学习 R 和 Python
这可能更有争议。很多建议倾向于建议你选择其中一个,或者除了 Python 之外学习一些新的东西,比如 Julia。我的建议是**同时学习 R 和 Python** 。了解其中一种语言是必要的,但是了解这两种语言不仅能帮助你更加突出,还能让你利用每种语言的相对优势更好地解决问题。我不一定建议不要学习像朱莉娅这样的新人,但这不是你在职业生涯开始/早期应该关注的事情。学习每种语言的推荐资源如下。
**R**
r 是一种流行的开源编程语言,广泛应用于工业界和学术界。对于应用统计学、数据分析和数据可视化来说,它是一门伟大的语言。
**在这里下载 R**:【http://cran.us.r-project.org/
在这里下载 R studio—R 开发的 IDE:[https://www.rstudio.com/products/rstudio/download/](https://www.rstudio.com/products/rstudio/download/)
RStudio 是一个 R 的集成开发环境,这将使你第一次用 R 编写代码的体验更加愉快和富有成效。当你打开 RStudio 时,它会自动找到你机器上的 R 发行版。
了解一下**潮汐**——[https://www.tidyverse.org/](https://www.tidyverse.org/)
tidyverse 是一个 R 包的集合,它使得许多常见的数据分析/科学任务变得更加简单和直观(操作数据,创建可视化等等)。).这个 DataCamp 教程是一个很好的起点[https://www . data camp . com/community/tutorials/tidy verse-tutorial-r](https://www.datacamp.com/community/tutorials/tidyverse-tutorial-r)你应该从这本书[http://r4ds.had.co.nz/](http://r4ds.had.co.nz/)开始。
**Python**
Python 是一种开源的通用编程语言,近年来变得非常流行,尤其是在机器学习和数据科学领域。它是一种高级语言,意味着你可以编写可读性很高的代码。这使得它非常适合初学者,也相对容易学习。
**在这里下载 Python**:[https://www.continuum.io/downloads](https://www.continuum.io/downloads)
这是 Python 的 anaconda 发行版。它包括该语言的最新版本+许多预装的好东西,如用于数据操作、机器学习、web 抓取和开发的有用的外部包,以及 Jupyter notebook,这是编写 Python 代码的好地方。一旦你下载并安装了它,你就可以通过搜索“Anaconda Navigator”并启动一个 Jupyter 笔记本来开始编写 Python 代码。
以下是学习 python 的一些有用资源:
***用 Python 自动化枯燥的东西:***
这本书可以在网上免费获得,这里:[https://automatetheboringstuff.com/](https://automatetheboringstuff.com/)。它是为完全的初学者准备的,但是可以让你很快上手并运行有趣且有用的任务。
***谷歌的 Python 课程:***
谷歌为新开发人员提供了自己的内部 Python 课程,他们在这里免费提供了所有内容:[https://developers.google.com/edu/python](https://developers.google.com/edu/python)
***Codeacademy 免费在线课程***
这是一个免费的互动课程,教授基础知识:[https://www.codecademy.com/learn/python](https://www.codecademy.com/learn/python)
对于 python 中的数据分析/科学任务,您将需要熟悉 pandas 包——参见下面的 *Python 数据分析书籍推荐。*
## 3)提高你的综合分析技能
探索性数据分析*仍然*是数据科学家增加价值的主要方式之一。不要误解我的意思,构建预测模型非常有价值,但通常情况下,您会通过发现数据中隐藏的模式并将这些见解传达给业务部门来产生最大的影响。考虑如何在分析数据时增加价值的一种方法是通过考虑**指标和杠杆**来接近数据。
通过关注**指标**,你将有一个分析指南,防止你掉进兔子洞和浪费时间。例如,如果你在一家订阅企业工作,在进行分析时,通常应该首先考虑的两个指标是 ***订阅和流失。***
杠杆是企业实际上可以用来推动或改变用户行为的东西。例如,这可能是优惠、促销、内容选择或开放时间。我猜这里的重点是通过 ***控制可控*** *来增加价值。*因此,在分析数据时,你应该思考企业已经或正在做的事情如何影响低层次和高层次的指标。
一旦你采用了**指标和杠杆心态**,它将帮助你更快地专注于执行增值分析。你还需要将这种心态与**强大的分析技能组合**。通过分解数据集来练习——过滤、分组、聚合、排序和应用各种方式或任意转换应该成为你的第二天性。同样,这应该与提高数据可视化技能相结合。就我个人而言,我真的很喜欢 R 和 tidyverse 来做这类工作——在这里可以看到一个快速而整洁的数据分析的例子[。](https://conrmcdonald.medium.com/a-quick-and-tidy-data-analysis-2cf0d42909b3)
## 4)熟悉线性模型

作者图片
随着学习旅程的进行,你将有足够的时间来学习神经网络和基于树的模型,但是如果你刚开始(或者即使你没有!)你应该对线性模型非常熟悉。你应该知道:
1. 如何用自己选择的语言实现它们
2. 如何解释只有一个回归变量的模型中的截距和斜率
3. 如何解释具有多个连续预测值的模型中的截距和斜率
4. 难以解释具有混合连续和分类(虚拟)预测值的模型中的截距和斜率
5. 如何以及何时标准化输入,以及这如何影响解释。
老实说,你应该购买并通过 Gelman 的书[开始工作。](https://www.amazon.co.uk/Analysis-Regression-Multilevel-Hierarchical-Analytical/dp/052168689X/ref=sr_1_4?dchild=1&keywords=gelman+and+hill&qid=1617523487&sr=8-4)
只要真正关注线性模型如何工作,你就可以增加很多价值,解决很多问题,并非常熟悉统计学和机器学习。相信我,这将是你时间的一项非常好的投资。
## **5)学会成为更好的问题解决者**
对于数据科学家来说,善于解决结果不确定的模糊复杂问题是成功的关键。幸运的是,解决问题是一项非常容易学习的技能,作为一名数据科学家,你可以自然而然地发展这项技能。也就是说,这是一项你应该投入时间并寻找机会发展和提高你技能的技能。我发现克劳德·香农的建议在这方面非常有价值。香农建议,要解决问题,你应该:
1. 从不同的角度着手(我可以用哪些不同的方式来想象或描述这个问题)
2. 尝试将其分解为更小的子问题(为了解决问题/开发解决方案,系统中需要工作的组成部分是什么),以及;
3. 从解决方案到问题逆向工作(例如,这个问题的解决方案看起来像什么或做什么)
为了不断提高你的技能,我建议在你解决了一个棘手的问题之后做一个快速回顾。自我批评。哪些*做错了,哪些做对了*,你将从下一个面临的难题中吸取哪些教训。这个回顾会占用你 5-10 分钟的时间,但是在未来会有巨大的回报。
## 摘要
成为一名数据科学家是一项具有挑战性但值得努力的工作。试着不要让自己对每一个出现的新趋势/算法/编程语言或框架感到不知所措。专注于这里概述的五个基本原则将是一项非常值得的投资,会让你处于一个更好的位置来快速增值,这反过来会让你致力于更大、更有趣的问题。
感谢阅读!如果您有任何想法、问题或评论,请告诉我。
# 你从不知道可以用 dplyr 做的五件事
> 原文:<https://towardsdatascience.com/five-things-you-never-knew-you-could-do-with-dplyr-1b634c0ea745?source=collection_archive---------10----------------------->
## 将 dplyr 插入到基本上任何东西中,在一个命令中执行批处理任务
自从去年发布 dplyr 1.0.0 以来,我非常喜欢尝试这个开创性的 R 包,最近我一直在考虑如何使用 dplyr 对来自数据框的输入运行任何类型的函数。这意味着您可以使用 dplyr 在一个命令(通常非常简单)中执行与数据帧中的行数一样多的操作。
在本文中,我将向您展示如何使用这个概念,在 dplyr 中使用一个管道命令来完成以下任务:
1. 运行许多不同的模型来评估哪一个最适合
2. 创建一批图表
3. 编写任意数量的 csv 文件
4. 用任意数量的工作表编写一个 excel 文件
5. 生成一批 pdf 报告
我想强调的是,这些只是一个更广泛的想法的例子——您可以将 dplyr 与其他包和函数集成,以执行比您最初可能想到的更广泛的任务。希望你能利用这里的例子想出一些其他的用途,让你将来的生活更轻松。
## 0.开始之前
在本文中,我们将使用几个 dplyr 1.0.0+中新增的或大幅改进的关键函数。首先是`rowwise()`。这是在数据帧的各个行上执行操作的一个重要功能。你可以把它想象成按单行分组。
让我们看一个`mtcars`的例子来说明我的意思。如果我们想在`mtcars`的每个观察中取`gear`和`carb`的最小值,你自然可以尝试:
library(dplyr)mtcars %>%
dplyr::mutate(min = min(gear, carb))
然而你得到了这个,这可能不是你想要的:

这是因为默认情况下,dplyr 是按列工作的,所以您的代码正在计算整个两列`gear`和`carb`中的最小值。要跨行工作,您需要使用`rowwise()`:
mtcars %>%
dplyr::rowwise() %>%
dplyr::mutate(min = min(gear, carb))
现在我们看到,在返回最小值之前,数据已经按行分组,这正是我们实际想要的。

我想强调的第二个功能是`nest_by()`。这是一个创建嵌套数据行的快捷函数。例如:
mtcars %>%
dplyr::nest_by(cyl)
您将看到这创建了一个名为`data`的*列表列*,根据`cyl`的三个不同值,它包含了`mtcars`的三个子集:

当我们现在进入五个例子时,您将看到这两个函数是多么有用。
## 1.**运行许多不同的模型来测试适合度**
R 中的`broom`包包含了一些很棒的函数,可以产生整洁的模型输出。例如,`glance()`函数允许您在一个整洁的表格中轻松查看模型的总体统计数据。例如,这段代码:
library(broom)broom::glance(
lm("mpg ~ cyl + gear", mtcars)
)
将为指定的模型生成以下统计数据行。

因此,如果我们想要测试一大堆模型组合的适合度,我们需要做的就是用我们感兴趣的模型组合写一列,并对 broom 进行行方向的变异,以便在一个管道命令中获得它们的所有适合度统计数据:
create a column with model formulas to test
models <- data.frame(
formula = c(
"mpg ~ cyl",
"mpg ~ cyl + disp",
"mpg ~ cyl + disp + hp",
"mpg ~ cyl + disp + hp + drat"
)
)# run them all and get fit statistics
models %>%
dplyr::rowwise() %>%
dplyr::mutate(
broom::glance(lm(formula, mtcars))
)
瞧,你所有的模型都符合统计数据:

## 2.创建一批图表
您可能已经注意到前面的列表列概念。List columns 允许我们将任何类型的对象放入我们使用 dplyr 变异或总结的列中。假设我们想要生成一个图表,显示不同的`cyl`值下`mpg`与`wt`的散点图。我们可以使用嵌套数据将每个图表转换成一个新列:
library(ggplot2)scatters <- mtcars %>%
dplyr::nest_by(cyl) %>%
dplyr::mutate(
charts = list(
ggplot(data, aes(x = wt, y = mpg)) +
geom_point()
)
)
这给了我们以下结果:

您可以看到`ggplot2`对象存储在我们新的`charts`列中。如果你想看到一个,你可以简单地调用它:
scatters$charts[[1]]

## 3.编写一批 csv 文件
你也许能看到我现在要去的地方。假设我们想将不同的嵌套数据帧写入不同的 csv 文件。同样,我们可以改变一个函数,将每个嵌套的数据帧写入一个适当命名的 csv 文件:
mtcars %>%
dplyr::nest_by(cyl) %>%
dplyr::mutate(
write.csv(data, paste0("cyl", cyl, ".csv"))
)
这将产生以下不起眼的输出:

但是看看你的项目文件夹,你会发现你的三个 csv 文件就在那里等着你。
## 4.用任意数量的工作表编写一个 Excel 文件
扩展我们正在做的事情,让我们编写一个函数,使用`openxlsx`包将三个嵌套的数据帧放入 Excel 工作簿的不同工作表中:
library(openxlsx)write_worksheet <- function(wb, sheet, data) {
addWorksheet(wb, sheetName = sheet)
openxlsx::writeData(wb, sheet, data)
}
现在我们可以开始一个工作簿,使用`dplyr`将所有内容写入不同的工作表,然后保存它。
wb <- createWorkbook()mtcars %>%
dplyr::nest_by(cyl) %>%
dplyr::mutate(
write_worksheet(wb, paste("cyl", cyl), data)
)saveWorkbook(wb, "test.xlsx")
虽然这个命令的终端输出并不起眼,但是请查看您新编写的`test.xlsx`文件,打开它,您应该会看到:

## 5.生成一批 pdf 报告
现在让我们把几件事情放在一起,用`rmarkdown`批量生成一堆使用`dplyr`的 pdf 报告。首先,我们可以保存一个`template.Rmd`文件,该文件期望接收我们的一个嵌套数据帧(`data`)和一个`cyl`值,计算一些平均值,并在一个基本报告中显示数据和我们的 ggplot 图表。这里是我们的`template.Rmd`文件的内容:
title: "Report on your data"
author: "Keith McNulty"
date: "15/03/2021"
output: pdf_document
---{r setup, echo = FALSE} library(ggplot2) knitr::opts_chunk$set(echo = FALSE) Here is the data for the cyl value r cyl.## Your averagesYour average mpg value is r mean(data$mpg).
Your average wt value is r mean(data$wt).## Your chartHere is your scatter plot:{r, fig.height = 3} ggplot(data, aes(x = wt, y = mpg)) + geom_point() ## Your raw dataHere is your raw data:```{r}
knitr::kable(data)
现在,我们编写一个简单的函数来呈现我们的 R Markdown 报告,用于特定的值cyl:
library(rmarkdown)# function to write a pdf based on an Rmd template
write_markdown <- function(data, cyl_value) {
data <- data
cyl <- cyl_value
rmarkdown::render("template.Rmd",
output_file = paste0(cyl, "_report.pdf"))
}
然后我们让dplyr再次施展它的魔法:
mtcars %>%
dplyr::nest_by(cyl) %>%
dplyr::mutate(write_markdown(data, cyl))
您将看到一些神奇的事情发生,然后您的项目目录中会有三个 pdf 报告,如下所示:

这些显然是使用简单数据集的一般示例,但这里的目的是展示如何将dplyr与 R 中的其他函数集成,从而在一个简单的命令中轻松执行大量任务的非常广泛的可能性。我真的鼓励你去探索和玩这个,如果你发现了它的其他有趣的用途,请给这篇文章添加评论,让大家都知道。
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在LinkedIn或Twitter上找我。也可以看看我在drkeithmcnulty.com上的博客。

unsplash.com 的好意
自动化 Python 文档的五个技巧
用这五个自动化步骤和预提交 Git 挂钩在 MkDocs & Material 中创建漂亮的 Python 文档

MkDocs 中自动生成的带有 Google 风格 docstring 的函数文档
在这个故事中,您将学习如何通过我们的定制函数、包mkgendocs、预提交 Git 钩子和 MkDocs 中的一点魔法从 Python 模块自动生成文档。我们将涉及以下内容
- MkDocs &材料安装
- 将类型提示自动化到文档字符串
- 使用
mkgendocs将文档字符串自动转换为 MkDocs - 自动记录新的 Python 函数
- 在预提交 Git 钩子中将所有东西绑在一起
MkDocs &材料安装
MkDocs 是一个用于构建项目文档的静态站点生成器,加上 Material 框架,它看起来非常漂亮。首先,我们需要安装一堆包来使用 MkDocs 的所有功能。所有这些包都是 pip 可安装的。
MkDocs 使用一个配置文件mkdocs.yml,在这里你可以启用上面安装的所有功能和软件包。请在这里找到我的。它包括对主题的/docs和/docs_assets文件夹的引用。
将类型提示自动化到文档字符串
以前,我写过关于编写 docstrings 的重要性的文章,重点是 Sphinx 文档。
https://betterprogramming.pub/the-guide-to-python-docstrings-3d40340e824b
文档字符串是记录函数的重要工具。Python 3.5+引入了类型提示,这是一种直接在函数参数中将静态类型赋给变量的方法。
几个 ide 如 Pycharm 、 Visual Studio 和 Sublime Text 都支持自动生成 docstring。然而,它们还不能从类型提示中推断变量类型,这意味着您必须在文档字符串中填写变量类型和描述。

Pycharm(几乎)自动生成文档字符串
上面显示的是 Pycharm 中使用 Google 风格的文档字符串的实现。您可以自由使用其他样式(例如 reStructuredText/Sphinx 或 NumPy),但是我发现了一个专门用于 Google 样式的 docstrings 的包,用于我们接下来的自动化步骤。
对自动化文档字符串的类型提示感兴趣吗?阅读下面的故事👇
将文档字符串自动转换为 MkDocs

从函数 docstring 自动推断出的 MkDocs 页面
包mkgendocs自动将 Google 风格的 docstrings 翻译成带有 Python 函数描述的页面。它使用一个配置文件mkgendocs.yml。配置文件如下所示
sources_dir: docs
templates_dir: docs/templates
repo: [https://github.com/LouisdeBruijn/Medium](https://github.com/LouisdeBruijn/Medium)
version: masterpages:
- page: "scripts/base/base.md"
source: "Python tips/base.py"
functions:
- parse_arguments
- print_df
- unescape_html
- equal_array_items
使用该软件包的两个手动步骤是
- 将需要记录的页面、源代码和函数添加到这个
mkgendocs.yml文件中。 - 运行
**$** gendocs --config mkgendocs.yml用这些函数的文档创建静态 MkDocs 页面。
接下来,我们将自动化这两个步骤,首先创建一个脚本来预填充我们的配置文件,然后将这两个步骤附加到一个预提交 Git 挂钩中。
自动记录新功能

从文档字符串填充 mkgendocs 配置的函数
首先,我编写了一个带有函数automate_mkdocs_from_docstring()的模块[automate.py](https://github.com/LouisdeBruijn/Medium/blob/master/Python%20tips/automate.py),用存储库中模块(脚本)中的所有 Python 函数填充mkgendocs.yml配置文件。
automate_mkdocs_from_docstring()使用 Pathlib 读取目录中的 Python 脚本并提取函数名。它将模块名和函数名保存在一个字典中,并用它来覆盖mkgendocs.yml。这样我们可以自动填充mkgendocs包的配置文件。

从 docstrings 到 MkDocs 的自定义自动化步骤
其次,我们将在预提交 Git 挂钩中包含automate.py和**$** gendocs --config mkgendocs.yml的执行。
在预提交 Git 钩子中将所有东西绑在一起
我们的最后一步是将每个自动化步骤添加到pre-commit-config.yaml中的 Git 挂钩中。关于预提交 Git 钩子的更多信息,请见下面的文章👇
https://betterprogramming.pub/4-tips-to-automate-clean-code-in-python-527f59b5fe4e
我们将自动生成 MkDocs 页面的两个强制步骤与预提交 Git 挂钩中的mkgendocs包一起添加。这些钩子允许我们用一个entry bash 命令执行一个 Python 脚本。
这样,当我们在存储库中的任何地方创建或删除 Python 函数时,它们将被自动添加到mkgendocs配置文件中,自动创建静态 MkDocs 页面并构建文档网站。

预提交 Git 挂钩中的自动文档
剩下唯一要做的就是用**$** mkdocs serve运行我们的 MkDocs 站点,并在 http://127.0.0.1:8000/找到我们的文档。
结论
通过本文中介绍的自动化步骤,您可以在 MkDocs 中自动创建漂亮的 Python 文档。如果你有任何问题,随时联系我。编码快乐!

包含 MkDocs 和材料的文档站点,图片由作者提供。
寻找更多 Python 干净的编码技巧?在这里找到他们👇
https://medium.com/analytics-vidhya/seven-tips-to-clean-code-with-python-24930d35927f
在数据科学领域克服冒名顶替综合症的五个技巧

就在 18 个月前,我的视角已经从一个非技术性的、面向商业的角色转向了
你好,朋友们!我想我应该从典型的以教程为导向的帖子中稍微休息一下,来涵盖一个不同的主题,这个主题仍然是以数据科学为导向的,并且在我看来是被低估了的。当然,我说的是冒名顶替综合症。如果你对这个概念不熟悉,冒名顶替综合症是指你觉得自己不够好,不能胜任某个特定的职位。这不是一个只局限于数据科学界的概念,但在我看来,我认为数据科学家和机器学习工程师受到冒名顶替综合症的打击最大。
简单分享一下我的个人背景,我已经在一家财富 50 强公司做了 18 个月的机器学习工程师。在担任这个职位之前,我从未担任过任何技术职务。我的本科是工商管理,硕士是组织领导。我之前的角色包括 scrum master、业务架构师和一般业务分析师。
关于我如何步入机器学习的世界,这是一个很长的故事,但我的教育道路完全围绕着替代学习平台。虽然我没有任何与计算机科学或机器学习相关的正式大学学位,但我通过纳米学位、MOOCs 和行业认证了解到了我目前的技能。在建立了工作组合并展示了我在该领域的能力后,我真的很惊讶地收到了一份工作邀请,将于 2020 年 1 月开始我的工作。
但是如果我完全诚实的话…当我第一次开始我的角色时,我觉得完全不合适。请记住,这不仅仅是我在机器学习领域的第一份工作;这是我在计算机科学领域的第一份工作。句号。在最初的几个月里,我觉得自己很沮丧,认为自己永远也不可能胜任这个角色。我经常想,“我到底在这里做什么?”有很多次,我都认真考虑过回归商业导向的角色。老实说,只是因为害怕尴尬,我才没有那样做。
不过,我很高兴自己坚持了下来,因为尽管我不认为自己是任何方面的“专家”,但我在我的角色中已经看到了很多非常出色的成功。我现在领导着一个由其他机器学习工程师组成的小组,最近我被提升为“高级机器学习工程师”。如果你在 2020 年 2 月骗子综合症最严重的时候告诉我这些,我真的不认为我当时会相信。
作为一个真心希望看到其他人在这个领域取得成功的人,我想花些时间来谈谈这个话题,因为闭门造车之后,我知道事实上我不是唯一一个经历过这个的人。在指导了机器学习和数据科学领域的许多人之后,他们中的许多人都表达了同样的担忧。我希望通过这篇文章来分享一些可以帮助你克服自己的冒名顶替综合症的事情。因此,让我们来思考一下关于冒名顶替综合症的五件事。
1.由于领域知识和专业技能,每个人在任何数据科学角色中都是新的。
无论你是编写基本的逻辑回归模型还是花哨的深度学习算法,现实情况是,即使你理解引擎盖下的数学,领域知识也绝对是任何数据科学工作成功的关键。从这个意义上说,每个人在加入数据科学领域的新工作时,都必须从头开始。即使一个人只是在同一家公司内从一个部门转到另一个部门,这个人也可能不得不学习一套新的领域知识,这显然使他们在一开始就处于不利地位。即使是经验最丰富的数据科学从业者也无法回避这一点,因此无论这是你的第一份还是第十份数据科学工作,每个人都必须重新开始一套新的领域知识。
2.许多数据科学的招聘信息写得很差。
作为一名 Lambda 学校的导师,我和我的一些学员坐下来回顾了他们感兴趣的一些职位,难怪我的学员在看到空缺职位后会感到非常沮丧。我在数据科学职位发布中经常看到两个一般性问题。首先,一份招聘启事显然是由一名没有任何数据科学工作经验的人力资源招聘人员撰写的,其次,这份招聘启事将要求大量的技能。我看到一些帖子会要求候选人精通 Python、Java、Scala、R、C++、Kubernetes、AWS 等等。我和一群非常聪明的人一起工作,让我这么说吧:没有人——包括我自己——会仔细检查每一项想要的技能。而且大多数雇主也不希望看到全部。不要让一系列技能阻碍你申请你感兴趣的职位。
3.请记住技术发展的速度有多快。
技术,尤其是在数据科学领域,发展如此之快,以至于即使是经验丰富的从业者也很可能需要随着时间的推移不断磨练他们的技能。想到像 Docker 和 Kubernetes 这样我每天都在使用的东西还没有出现那么久,这有点不可思议。自从大约 18 个月前我开始担任这个角色以来,亚马逊网络服务(AWS)已经为 SageMaker 服务添加了大量新功能,特别是以 SageMaker Studio 的形式。我个人还没有机会学习 SageMaker 工作室的那些东西,但我知道如果我不努力跟上,我就会落后。进化的步伐不会很快放缓,所以请记住,如果你觉得自己很难跟上,那么即使是经验丰富的从业者也很难跟上。
4.不要害怕照顾你的心理健康。
这是一件被严重低估的事情,尤其是当你同时应对工作场所之外的压力时。对我个人来说,新冠肺炎进入我的角色仅仅三个月,就在我自己的冒名顶替综合症的顶峰。虽然我并不害怕死于病毒,但我对病毒的潜在连锁反应有很大的压力。这将如何影响经济?这对我未来的就业状况意味着什么?这种病毒会彻底改变人类的未来吗?这是一个糟糕的时机,说实话,我寻求了专业的帮助。我觉得这是我们作为男人特别难以做到的事情,因为这感觉像是示弱。坦率地说,即使在这里输入这些单词也感觉非常脆弱和不舒服,但我认为如果我能帮助影响你获得你需要的帮助,对你说实话是重要的。我知道寻求和接受专业人士对你精神健康的帮助有多难,但这是一个我一点也不后悔的决定,我很高兴我这样做了。
5.请记住,所有的专业知识都是一种幻觉。
我必须说,当我打开像《走向数据科学的 T0》这样的出版物时,我自己仍然会经历一种自然的冒名顶替综合症。我知道这有多讽刺,因为我自己也是该出版物的定期撰稿人,但人们为数据科学社区做出的贡献给我留下了深刻的印象。我必须提醒自己的是,知道我自己是社区的贡献者,但不可否认在数据科学的几个方面教育不足,我必须想象大多数人都是这样。这根本不是对任何人居高临下。现实就是要学的东西太多了,我认为一个人不可能学会所有的东西。我们都可能在世界上的某个狭小领域拥有专业知识,但我非常怀疑任何人都是万能的。
伙计们,这篇文章到此结束。我希望在您继续您的数据科学之旅时,它会让您感到鼓舞。记住,我们都必须从某个地方开始;没有人一开始是专家。感谢查看这篇文章,我们可能会在下一篇文章中继续讨论更多的 Terraform + SageMaker 系列。
数据科学家生存分析的五个技巧
如何在商业中利用生存分析的指南

吉尔·海尔在 Unsplash 上的照片
生存分析预测事件发生的时间
许多分析问题需要预测事件发生的时间。例如,互联网提供商需要知道客户何时会终止合同,以便及时采取行动并防止客户流失。像这样的挑战可以通过生存分析来解决。
生存分析的目标是预测事件发生的时间,并估计“生存概率”。生存分析起源于医学研究,在医学研究中,对患者进行长期随访,直到某一事件发生,例如死亡,这是它被称为“生存分析”的原因。它用于具有右删失的数据集,其中对于样本的子集,事件的发生在研究时是未知的。例如,一名患者仅在 2 个月前进入研究,在研究时,我们不知道他是否会存活 5 个月或 10 年。仅次于存活时间预测,可以描述单个因素对存活的影响。例如,治疗对某种癌症类型的无病生存的影响经常用这种方法来研究。
由于 medium 本身提供了大量关于生存分析理论背景的博客,如果你不熟悉这种技术,我建议你去看看这些博客。在本文中,我将分享我作为数据科学家的经验中关于生存分析的额外技巧。
经典回归或分类不适用于右删失数据
选择生存分析的最重要原因是数据集中存在右删失样本。重要的是,右删失数据不使用回归或分类技术进行分析,因为此类分析不考虑删失或事件发生时间[4]。这可能导致得出不正确的结论。这里有一个(过于简化的)例子,说明事情是如何出错的:
假设你在一家 X 医院工作,你想描述影响癌症患者生存的特征。您拥有 2005 年至 2015 年间诊断的患者数据,并跟踪他们的生存情况,直到 2020 年,包括标准的患者特征,如年龄、性别等。然而,在 2010 年,X 医院引入了 DNA 测序,根据患者的 DNA 图谱对其患者进行个性化癌症治疗(参见图 1 的说明性研究概述)。你进行回归分析,得出如下结论:“有 DNA 测序的患者比没有的患者生存率差”。那是因为你的 DNA 测试病人的存活率最高。10 年(2010 年至 2020 年),而在您的研究中,没有进行 DNA 测试的患者可以存活长达 15 年(2005 年至 2020 年),这对每组的平均存活率有影响。鉴于几种 DNA 引导的癌症疗法的已知成功,这一结论是出乎意料和不正确的,而且可能传播错误信息。如果忽略了权利审查,这就是可能发生的事情。

作者图片
超越考克斯回归揭示了额外的机会
多变量生存分析的首选模型是 Cox 回归。它常用于医学研究,易于解释。它是用编程语言甚至像 SPSS 这样的统计分析软件包来实现的,SPSS 仍然是许多临床医生的最爱。然而,对于回归或分类问题,您可能不会将自己局限于线性或逻辑回归,对于生存分析,您还应该考虑 Cox 回归之外的方法。Cox 回归最重要的局限性在于,它是一种需要几个假设的线性建模技术[5]。如果您的目标是通过使用可能包含非线性关系的复杂数据集来获得高预测性能,则存在更合适的方法。
替代算法的一个例子是随机森林生存分析。随机森林仍然是许多数据科学家的最爱,因为与经典回归相比,它有许多最高级。随机森林建模有许多最高级,包括下面列出的这些:
- 它识别变量之间的非线性关系
- 与受假设限制的方法(如线性、逻辑或 Cox 回归)相比,它需要较少的数据转换
- 它说明了特征之间的相互作用
- 它性能良好,具有大量的功能
- 在有限的时间内,这是一个可行的解决方案
在生存分析中使用随机森林与用于分类或回归的随机森林模型非常相似,即许多树是基于数据集的子样本进行训练的,而预测是基于树的投票进行聚合的。生存特异性部分是模型基于例如对数秩检验,而不是基尼杂质,根据每个子节点中观察到的和预期的事件数之间的差异来评估每个分裂[6]。

作者图片
其他有趣的替代算法是基于例如惩罚 Cox 模型、梯度推进、支持向量机、使用贝叶斯统计的模型等的生存模型(见下一段中的细节)。
选择正确的编程语言为分析提供了更多的灵活性
使用 Python 或 R 是数据科学领域正在进行的讨论,每种语言都有其相对于其他语言的特定优势[7–9]。
Python 是一种通用编程语言,因为它提供了更好的稳定性、模块化和代码可读性。由于其深度学习库和更适合生产环境中的模型部署,它在行业中是首选的。
使用 Python 进行生存分析不如在 R 中普遍,因此 Python 在生存模型的选择上提供的自由度更小。然而,尽管数量有限,Python 中仍有很好的生存分析包:
- 生命线 是一个参数模型包,包括单变量模型的实现以及 Cox 回归。
- sklearn-survival 包括更复杂或非线性的模型,如可能具有 L1 或 L2 正则化的 Cox 回归、随机森林、梯度推进或支持向量机。
- pysurvival 用非常有用的模型评估可视化实现了 10 多个模型,不幸的是,它目前只在 Linux 上可用。
另一方面,R 擅长于统计计算和图形,因此它目前在学术界非常受欢迎。由于生存分析来源于医学研究(学术环境)并经常在其中进行,因此大多数创新都是由该领域发起的。因此,R 提供了各种各样的 CRAN 包,其中包含大量的生存模型实现,包括替代算法(例如使用随机森林的生存模型的 randomForestSRC 或梯度推进算法的 mboost )、Cox 回归的扩展(例如使用正则化的 Cox 模型的 glmnet 或 Cox 回归模型的贝叶斯模型平均的 BMA )或模型评估包(例如time AUC如果需要集成到工业化的生产环境中,可以使用像 Azure Databricks 这样的解决方案大规模运行 R。****
因此,在选择用于分析的编程语言之前,要考虑业务问题、数据和需要交付的最终产品。
生存分析可以应用于不同的行业
在数据科学中,回归和分类是“必须知道的”数据分析技术。不幸的是,生存分析不是,也不清楚为什么。个人认为部分原因在名字上,“生存分析”。这表明该分析仅可用于生存预测,因此仅在医学研究中有用。
事实并非如此,因为生存分析实际上是一种非常通用和强大的分析技术。除了大量的健康分析案例,生存分析可以在许多行业中使用。在我们的团队中,我们在几个不同的项目中进行了生存分析:
我们开展了一个关于癌症患者生存预测的健康分析项目。与许多癌症生存研究相比,这个项目涉及生存分析与自然语言处理的整合。我们分析了医疗患者记录中的自由文本,以提取有价值的信息,例如使用正则表达式的特定放射学得分,以及估计填写文档的医生的总体情绪。将这些变量与标准临床数据结合在一起,使得最终模型具有很强的预测性能。
过去,我们也将生存分析应用于客户终身价值(CLV)的计算。CLV 估计在留住客户之前,企业可以从客户那里获得多少收入,它可以用来调整营销活动,在正确的时间瞄准正确的客户。在这个项目中,我们将 CLV 计算为每个客户每个时期的收入,并预测该时期的客户保留率,后者使用生存分析进行建模。这使得企业能够专注于留住他们最有价值的客户,这些客户在未来有流失的风险。
在另一个项目中,我们使用生存分析来预测二手车的受欢迎程度。使用汽车的品牌和车龄,我们对其受欢迎程度进行建模,受欢迎程度被定义为购买汽车前的库存天数。了解品牌和车龄对汽车受欢迎程度的影响有助于企业确定每辆车的最佳售价。
在健康分析之外应用生存分析的其他例子有:
- 类似于客户终身价值计算,有一个关于电信公司客户流失预测的著名案例[10],其中生存时间对应于客户任期,事件是流失。同样,生存分析可以用来预测雇员终止合同的时间。
- 在金融学中,生存分析可以用于信用风险中违约概率的计算。
- 在工业企业中,生存分析可用于预测机器寿命。
结束语
总之,这是数据科学家应该知道的关于生存分析的五件事:
- 这是一种预测事件发生时间的技术。
- 对右删失数据使用其他数据建模技术,如回归或分类,会导致有偏见的结果。
- 除了 Cox 回归,还有多种多样的模型可用于生存分析,具体取决于你的数据集和业务问题。
- 目前,R 在分析中比 Python 提供了更多的灵活性。
- 生存分析非常有用,也在健康分析之外。
最后,需要提及的是,本文为主观观点。在实践中,当我拿到我的第一个右删失数据集时,这是我想知道的关于生存分析的五个技巧。希望这些小技巧可以帮助到其他数据科学家的工作。
参考
[1] S. Dhamodharan,生存分析|安介绍 (2020),https://medium . com/analytics-vid hya/Survival-Analysis-An-Introduction-87 a94c 98061
[2] T. Zahid,生存分析—A 部分 (2019),https://towards data science . com/Survival-Analysis-Part-A-70213 df 21 c2e
[3] E. Lewinson,生存分析导论 (2020),https://towardsdatascience . com/Introduction-to-Survival-Analysis-6f 7 e 19 c 31d 96
[4] K. Sawarkar,生存分析——是什么?* (2019),https://medium . com/inside-machine-learning/survival-analysis-CB 5832 ffcd 78*
[5] A .卡桑巴拉,考克斯模型假设,http://www.sthda.com/english/wiki/cox-model-assumptions
[6] H. Ishwaran,U.B. Kogalur,E.H. Blackstone 和 M.S. Lauer,随机生存森林* (2008),《应用统计年鉴》 2008 年,第 2 卷,№3,841–860*
[7] R. Cotton, Python vs. R for Data Science:有什么区别?(2020)https://www . data camp . com/community/blog/when-to-use-python-or-r
[8]数据驱动的科学, Python 对 R 的数据科学:赢家是.. (2018),https://medium . com/@ datadrivenscience/python-vs-r-for-data-science-and-the-winner-is-3 ebb1a 968197
[9] B. Karakan,Python vs R for Data Science(2020),https://towards Data Science . com/Python-vs-R-for-Data-Science-6a 83 e 4541000
[10] A. Pandey,生存分析:直觉&在 Python 中的实现* (2019),https://towardsdatascience . com/Survival-Analysis-Intuition-Implementation-in-Python-504 FDE 4 fcf 8 e*
从头开始构建分析和数据科学时要避免的五个陷阱
使用早期创业案例的实践指南
每个数据驱动的初创公司最终都会达到创始团队无法满足其不断增长的分析和数据科学需求的阶段。在这个阶段,通常会雇佣一名数据专家来构建和领导这些功能。在过去的 2.5 年里,我有幸在 SaaS 初创公司 virtualQ 建立了数据团队和分析基础设施,其使命是通过智能处理来电来改善客户服务。
虽然我相信我们公司的发展以及数据团队和基础设施的现状证明我们做了很多正确的事情,但并非一切都是一帆风顺的。由于习惯在大公司工作,我有一个陡峭的学习曲线,同时要适应资源有限、员工数量、产品复杂性和用户快速增长的环境。
本文旨在通过描述从零开始设置数据分析和数据科学功能时最常见的陷阱,帮助您避免熬夜和沮丧,无论是在初创公司还是成熟公司。当然,根据数据团队的规模、成熟阶段和业务模式,您面临的具体挑战会有所不同。
陷阱#1:在脏数据产生后修复它

公元前 1300 年,被艰巨的数据清理工作打破。照片由萨法克·阿塔莱在 Unsplash 上拍摄
上图是希腊神话人物赫拉克勒斯。他的第五项任务是清理奥革阿斯的马厩,这些马厩已经三十多年没有打扫过了,里面有 3000 头牛。从那以后,它就成了执行一项长期以来需要关注的大型且令人不快的任务的同义词,就像数据清理在创始人雇佣你之前对他们的意义一样。当您从头开始设置数据函数时,整理和清理所有现有的数据会感觉像是一项非常艰巨的任务。
为什么脏数据不好的争论超出了本文的范围,但是 GIGO (垃圾输入,垃圾输出)的概念很好地总结了这一点。当你接近你公司的数据生产者(团队、产品所有者)来“清理马厩”时,许多人会理解你的计划的价值并愉快地合作。然而,您也可能会遇到一些阻力,因为您的利益相关者并不认为干净的数据是优先事项。此外,清理数据涉及到您的利益相关者的一些努力,因为他们需要帮助您理解现有的数据,并且必须适应新的过程以保持数据的整洁。毕竟,人为错误是脏数据的主要来源。
当面临从源头清理数据的阻力时,危险的陷阱是使用复杂的数据工程来代替。在这种情况下,人或应用程序继续产生脏数据,但您在稍后阶段通过执行大量数据争论将它恢复到干净的状态。不幸的是,这种方法为您的数据管道增加了很多额外的复杂性和维护工作,因此应该尽可能避免。一个非常简单的例子是通过 Regex 将自由格式条目与类匹配,而不是首先定义一个下拉列表。
相反,你应该教育所有的数据生产者在早期阶段拥有干净的数据和适当的过程的重要性。向他们解释不作为的未来成本,让他们相信,在马厩变得丑陋之前,从你的清理工作开始。
主要建议:从源头清理脏数据,并建立流程保持其整洁。坚持不懈,即使你最初会遇到来自其他职能部门的阻力。
延伸阅读:
陷阱 2:在没有数据的情况下启动特性

这是您向董事会报告这些绩效指标的事件日志。凯利·西克玛在 Unsplash 上拍摄的照片
数据专业人员的噩梦由两件事组成:脏数据(我们之前讨论过)和根本没有数据。想象一下,你的团队被要求帮助决定一个新特性的命运:它应该得到更多的投资还是应该被关闭?为此,您需要挖掘您的数据并进行分析,以回答关键问题,例如:“哪些客户查看了新功能”和“谁经常使用该功能”。如果你在第一次考虑分析所需的数据时就被要求支持决策,那么你实际上是梦游进入了陷阱 2:在没有数据的情况下启动特性。这将是非常棘手的把你所期望的洞察力放在一起。
为了防止这种情况,请确保所有重要事件都在数据库中生成、保存、清理和存储,这一过程称为数据规范。在使用您的特性时有一个权衡:作为一个数据用户,您获得的数据越多,您的工作就越容易。另一方面,增加仪器总是伴随着额外的开发工作和复杂性。
当计划一个特性时,您的工作是将您的数据需求传达给产品管理和开发部门。我建议通过以下 4 个步骤:
- 询问你的利益相关者成功的首次展示对他们意味着什么(例如:你希望在 3 个月后看到什么样的功能采用率?)
- 就关键 KPI 及其确切定义达成一致(例如:功能采用由每周至少使用一次该功能的客户数量来衡量)
- 确定计算 KPI 所需的事件日志(例如:获取跟踪每个功能使用、时间戳和客户端 id 的日志)
- 沟通你的需求,最好是在待办事项整理会议期间。
不要仅仅依靠你的开发者来处理好的工具,因为他们通常只使用他们应用程序产生的一小部分数据。他们有不同的优先级,如核心性能,并且不能直觉地知道你将需要什么数据来回答业务问题。
最后,如果您一开始就没有正确地检测您的特性,就不要试图修补。通过广泛的数据工程,你也许能够重现一些丢失的数据。例如,您可能想通过从第三方提供商的 API 中获取数据来弥补缺少正确的使用日志的情况,该 API 存储了一些用户的接触点。我希望你不要这样做,因为你最终治愈的是劣质仪器的症状,而不是潜在的问题。除此之外,您还会遇到非常复杂的数据管道和维护工作。
主要要点:在你发布一个特性之前,与你的利益相关者就关键绩效指标达成一致,并与你的产品经理和开发人员密切合作,以确保你有计算它们的数据。
延伸阅读:
- 10 个产品仪表错误以及我们从中吸取的教训——Sergio schüler
- 可持续分析仪器的 5 步指南——Jessica Chiu 的振幅
- 如何为你的企业选择正确的关键绩效指标——杰西·马嵬尼为 Hubspot
陷阱 3:从解决方案开始,而不是从问题开始

您的团队正在寻找一个地方来实现他们的卷积神经网络,照片由 ThisisEngineering RAEng 在 Unsplash 上发布
这听起来似乎是显而易见的,但在实践中很难做到。对于许多员工来说,加入创业公司的动机是创造下一件大事,并应用令人着迷的新技术。一个初级数据团队可以带来大量的动力和热情,但工作经验有限。假设你的团队是聪明的和自我激励的,你应该提供一些创新和实验的空间来释放他们的全部潜力。然而,通过给予这种自由,一个项目可能会逐渐偏离你想要解决的最初的客户问题,因为你被神奇地吸引到了流行的技术堆栈中。
例如,您的团队可能会选择开发基于神经网络的解决方案,即使基于规则的算法可以在更短的时间内以更低的复杂性为您的客户的问题提供一个完全可接受的解决方案。坚持下去的一个好方法是寻求与你的产品经理和客户关系团队的定期交流:他们与客户交谈,知道他们的痛点是什么。如果你正在构建一个内部工具,与你的利益相关者建立定期更新,讨论你所设想的最终产品将会是什么样子和如何工作——使用模型和初步结果对这个目的非常有帮助。
主要收获:不断提醒自己和你的团队你想解决的尖锐的客户问题。然后,逆向工作,找到为您提供最佳解决方案的技术。
延伸阅读:
陷阱 4:将数据科学局限于产品 R&D

你的数据团队正常工作的一天,正如人力资源部所想象的,照片由this engineering RAEng在 Unsplash 上拍摄
初创公司也将数据素养和技术理解程度差异很大的人聚集在一起。根据年龄和背景,数据科学家的角色可能与其他职能部门的领导非常疏远。这会让他们不太愿意向你的团队谈论他们的痛点和挑战。反过来,你对他们的问题的了解和理解将会受到限制,降低了你为他们创造有价值的解决方案的能力(记住陷阱 3)。
然而,几乎每个公司职能部门都可以受益于数据团队中可用的技能组合和技术:通过自动化、刮擦、预测建模和经由 A/B 测试的迭代改进,可以实现效率和性能的巨大改进。然而,你的利益相关者可能只观察你的团队在核心产品上的(非常技术性的)工作,而没有意识到他们有能力提供帮助。
作为数据主管,您的任务是积极主动地寻求与各职能部门的定期对话。努力提高关键利益相关者的数据素养。根据合作的程度,让你的团队成员中的一个“支持”某个特定的职能,增加双方的所有权和参与度也是有意义的。
主要要点:如果您希望利用团队技能成为高效的数据驱动型组织,您需要以积极主动的方式与所有业务职能部门合作,并对关键利益相关方进行数据素养教育。
延伸阅读:
陷阱 5:过度设计你的报告

他们说,这只是我在以前的工作中得到的一份简单的报告,照片由卢克·切瑟在 Unsplash 上拍摄
资深员工经常被雇佣来从大公司引进有价值的技术。他们也习惯了企业生活的福利,包括人力和资金充足的后台办公室、免费午餐券和养老金计划。另一方面,您正在用有限的资源管理您的数据团队,严重地划分任务的优先级,并带来不新鲜的三明治。
当高级员工要求他们在以前的角色中习惯的相同的报告/分析标准时,这两个世界发生了冲突。他们可能不知道这些报告是由一个指定的数据团队多年来构建的。如果您按照要求实现这些项目,它们将占用您团队的宝贵资源的很大一部分。问题是你的涉众太关注解决方案,而不是问题(就像你的团队在陷阱 3 中一样)。因此,当他们向您描述所需的布局、表格和过滤器时,通过询问他们希望能够回答的问题来做出回应。确定真正重要的元素,解释你的情况(有限的资源),删掉所有“有就好”的部分。
这甚至更重要,因为您可能会发现新的报告很少使用,即使它完全按照要求执行。这是因为你的利益相关者感受到了和你一样的压力:他们需要在许多任务上明智地分配时间,因为他们现在的资源更少了,所以处理数字的时间是有限的。
为了让你的利益相关者负起责任,让他们参与你的路线图规划。询问他们认为使用新报告/工具的频率,并向他们解释您需要权衡每个请求与另一个请求的影响。提醒他们你会检查他们会用多少他们要求的东西。
要点:改变对利益相关者问题的关注,而不是一个预先定义的解决方案,并讨论报告中哪些元素是真正不可或缺的。让他们参与到您的路线图规划中来,确定优先级并让他们负起责任。
延伸阅读:
谢谢你阅读这篇文章
我希望你在描述的五种情况中的一种中找到安慰或建议,并且它可能帮助你犯不同的错误,而不是相同的错误。正如奥托·冯·俾斯麦(1871 年至 1890 年任德国总理)所说:
只有傻瓜才会从自己的错误中吸取教训。聪明人从别人的错误中吸取教训。”
90%的人失败的五个棘手的统计和概率谜语
有趣的脑筋急转弯会让你想学统计学

由故事创造的人矢——【www.freepik.com】T2
介绍
随着新年的临近,我认为分享一些统计谜语将是开始 2022 年学习之旅的一种有趣方式。
这些谜语不仅发人深省,还能帮助你学习基本的统计学和概率知识。如果你读过我以前的文章,你会知道我是学习统计和概率的巨大倡导者,因为大多数数据科学概念都建立在它的基础上。
因此,我还将介绍一些对您的数据科学职业生涯有所帮助的关键统计概念,包括以下内容:
- 概率的基本性质
- 通用集合和样本空间
- 组合和排列
- 条件概率
- 预期值
也就是说,这里有四个棘手的统计难题,90%的人第一次都会失败!
注:带解释的答案在底部。
请务必点击 订阅此处 千万不要错过另一篇关于数据科学指南、技巧和提示、生活经验等的文章!
1.生日问题
谜语:有多少个随机的人需要在同一个房间里,两个人有 99.95%的可能性在同一天生日?
a:75
B:183
C:365
D:500
2.两个问题儿童
谜语:假设一个家庭有两个孩子,我们知道其中一个是男孩。家里有两个男孩的概率有多大?
3.蒙蒂·霍尔问题
谜语:假设你在一个游戏展上,有三扇关着的门。其中一个后面是一辆汽车,另外两个后面是山羊。考虑以下场景:
- 你选 1 号门。
- 游戏节目主持人看着 2 号门和 3 号门,打开了有一只山羊的门。如果他们都有一只山羊,他会随机选择一只。
- 在用山羊打开一扇门后,游戏节目主持人会让你选择切换到另一扇门或坚持你最初的猜测。
到底该不该换门?
4.最大化弹珠的赔率
谜语:假设你被判死刑,但国王给你一条生路,前提是你在下面的游戏中打败他:
- 假设给你 50 颗红色弹珠、50 颗蓝色弹珠和 2 个空碗。
- 你的目标是把 100 个弹珠分成两个碗,只要你用光所有的弹珠,你可以选择任何方式。
- 然后,将随机选择一个碗,然后从选择的碗中随机选择一个弹球。如果弹珠是蓝色的,你活着,但是如果弹珠是红色的,你就死了。
你应该如何划分弹珠,这样你有最大的概率选择一个蓝色的弹珠?
5.多色卡片组
谜语:假设你有 40 张四种不同颜色的卡片。具体来说,有 10 张挑卡,10 张橙色卡,10 张绿色卡和 10 张紫色卡。每种颜色的卡片都从一到十编号。随机抽取两张牌。所选的两张牌不是同一个号码或同一个颜色的概率是多少?
请务必点击 订阅此处 千万不要错过另一篇关于数据科学指南、技巧和提示、生活经验等的文章!
答案
1)答:75
为了理解为什么答案是 A: 75,你首先需要理解两个基本的统计学原理:
组合
组合被定义为你可以从 n 个对象中选择 r 的不同方式的数量,其中顺序并不重要。这很重要,因为我们想知道给定数量的人的唯一配对(组合)的可能数量。这可以通过下式计算:

作者创建的图像
概率的基本性质
概率有几个性质,但是对于这个问题,我们对其中一个特别感兴趣,补充规则:

作者创建的图像
如果 A 是集合中的一个事件,那么 A 不发生的概率等于 1 减去 A 发生的概率。
为什么答案是 A: 75
现在你已经理解了这两个概念,我们可以开始寻找答案了。
两个人生日不同的概率是 364/365。这是有道理的,因为第二个人和第一个人有 1/365 的机会过同一天生日。我们可以把这个重新措辞,说一对人同一天生日的概率是 364/365。
75 个人,有 2775 对独特的人(组合)。这是使用前面讨论的公式计算的:

作者创建的图像
现在我们知道了一对人生日相同的概率,并且我们知道 75 个人创造的独特对的数量是 2775,我们可以计算所有 2775 对生日不同的概率:

作者创建的图像
上面的等式告诉我们,所有对生日不同的概率是 0.05%。
使用互补法则,这相当于说有 1–0.05%的几率,或 99.95%的几率,至少有一对是同一天生日。
因此,答案是 75 人。
2) 1/3
为了理解为什么答案是 1/3,你首先需要理解几个概念:泛集和样本空间。
通用集
通用集合表示在给定场景中可能发生的所有可能事件(或结果)的集合。例如,滚动单一染料的通用集合为= {1,2,3,4,5,6}。
样本空间
样本空间是在给定一组约束的情况下考虑所有可能结果的通用集合的子集。
条件概率
条件概率简单地表示一个事件(A)在另一个事件(B)已经发生的情况下发生的概率。它被表示为 P(A|B)。
回到问题上,通用集合由以下四种可能的性别组合组成:
- 男孩和男孩
- 女孩和女孩
- 男孩和女孩
- 女孩和男孩
既然我们知道其中一个是男孩,那么我们的样本空间由三种可能性组成:
- 男孩和男孩
- 男孩和女孩
- 女孩和男孩
现在我们可以计算第二个孩子是男孩的条件概率假设其中一个已经是男孩。因为这里只有一种可能性,两个孩子都是男孩,概率是 1/3。
3)是的,你应该经常换门。
这可以通过观察所有可能性的集合来解释,也就是宇宙集合:

作者创建的图像
这张表显示了在每种可能的情况下会发生什么,基于你选择哪扇门,哪扇门是奖励门,以及你是否切换门。
请注意,当您切换门时,您赢得了 9 个可能场景中的 6 个,相当于 2/3。
因此,你应该经常换门。
4)将 1 个蓝色弹珠放在一个碗里,将其他 99 个弹珠放在另一个碗里。
因为有几种可能性我们必须考虑,我们的目标是最大化选择蓝色弹珠的期望值。期望值被定义为所有可能值的总和乘以它发生的概率。
选择蓝色弹球的期望值可以写成以下等式:
选择碗 1 的可能性选择碗 1 中的蓝色弹珠的可能性+
选择碗 2 的可能性选择碗 2 中的蓝色弹珠的可能性
我们的目标是最大化上面的等式。由于选择给定碗的概率为 50%,因此简化为:
0.5 *在碗 1 中选择蓝色弹珠的概率+
0.5 *在碗 2 中选择蓝色弹珠的概率
通过在一个碗里放 1 个蓝色的弹珠,在另一个碗里放另外 99 个弹珠,你获得了 74.75%的最高概率。您可以测试任何其他可能的组合,但不会达到如此高的预期概率。

作者创建的图像
5. 69.2%
假设你从 40 张牌中抽出了第一张牌。它有一些颜色和一些数字。
我们现在有 39 张卡片,其中 9 张与第一张卡片颜色相同,另外 3 张与第一张卡片号码相同。这意味着第二张牌有相同颜色或相同号码的概率等于(9+3)/39 = 4/13。
根据互补规则,这意味着第二张卡与不具有相同颜色或相同号码的概率等于 1–4/13 = 0.692 或 69.2%
感谢阅读!
务必 订阅此处 千万不要错过另一篇关于数据科学的指南、诀窍和技巧、生活经验等文章!
不确定接下来要读什么?我为你挑选了另一篇文章:
</50-statistics-interview-questions-and-answers-for-data-scientists-for-2021-24f886221271>
还有一个:
-特伦斯·申
高绩效数据科学家的五种思维
思考思考(上)
从心智模型到计算思维

来源:作者制作
复杂性弥漫于当今社会——无论我们审视经济、在经济中运营的企业、在社会中扮演不同角色的个人,还是我们的物理、社会、政治和工业综合体如何相互作用,我们都不能忽视它的复杂性。没有一个单一或简单的解释可以概括这一切的复杂性。作为数据科学家,我们必须理解这种复杂性,并磨练我们的思维,以隔离重要的东西,忽略不重要的东西,并继续回答向我们提出的关键问题。
在这篇和随后的博客中,我计划详述一些关键的“思考”范例,这些范例帮助我将向我提出的抽象问题概念化,以及我如何能够解决这些问题以产生洞察力。虽然元认知或“思考思考”是一个丰富的讨论话题——我认为这对人工智能的努力至关重要——但我将在本系列中限制我对数据科学家有用的思维范式的关注。
模型思维
作为数据科学家,我们需要的首要技能是根据模型进行思考。在最抽象的形式中,模型是对象、属性或过程的任何物理、数学或逻辑表示。比方说,我们想制造一种能够提升重物的飞机引擎。在我们建造完整的飞机发动机之前,我们可能会建造一个微型模型来测试发动机在不同条件下(例如,顶风、物体撞击)的各种属性(例如,燃料消耗、功率)。甚至在我们建造微缩模型之前,我们可能会建造一个三维数字模型,它可以预测用不同材料建造的微缩模型会发生什么。
在每种情况下,都有两个不同的实体——一个模型和被建模的对象。在第一种情况下,微型模型发动机是整个飞机发动机的模型。在第二种情况下,发动机的数字模型是微型模型发动机的模型。数字模型本身必须模拟飞行物理的不同方面(如推力)。所以模型不需要总是一个对象,它也可以是一个属性。例如,引力模型考虑了两个物体的相对质量以及它们质心之间的距离。在这种特殊情况下,模型是一个方程或数学表示。在微型模型发动机的情况下,模型是物理模型。
模型也可以是关于一个过程的。例如,一个相当常见的消费者购买过程模型是从认知、考虑、购买和重复购买开始的。这里的模型是一步一步过程的逻辑表示。相同的逻辑表示可以用等式表示,也可以编程为代码。
因此,模型是现实的抽象或值得研究的东西。它们也是我们解释和理解世界的方式。伯克希尔·哈撒韦公司副主席查理·芒格是这种思维方式的最大支持者之一
“我认为不可否认的事实是,人类的大脑必须在模型中工作。诀窍是让你的大脑比其他人的大脑工作得更好,因为它理解最基本的模型:每单位做最多工作的模型。”“如果你养成了将你正在阅读的内容与正在论证的基本观点联系起来的思维习惯,你就会逐渐积累一些智慧。”
查理·芒格已经充分证明了这种模型思维在商业世界中的价值。这项技能不仅对投资至关重要,也是理解世界的更好方式。这种模型思维对于数据科学家和人工智能研究人员来说也是必不可少的。我们经常需要对人类决策的某些方面进行建模(例如,预测、优化、分类——更多详细信息请参见[2])或对某个过程或现象进行理解(例如,异常行为)。许多不同领域的领域专家——商业、科学(物理、化学、生物)、工程、经济或社会科学——经常要求我们构建模型来理解世界、获得洞察力、做出决策或采取行动。
如果数据科学家能够理解这些领域的心理模型,我们就可以更容易地将它们建模为数学公式、逻辑表示或代码。事实上,有许多关于心智模型的书籍[2-4 ],并且有数百种心智模型被分类。心智模型网站[6]列出了 10 个不同类别下的 339 个模型,包括经济和战略、人性和判断、系统、生物世界、物理世界等。Scott Page 在他的文章[7]中解释了为什么“多模型思考者”做出更好的决策。多模型思考者不仅是更好的决策者,能够思考并基于数百个心智模型构建模型集合的数据科学家也是更好的数据科学家。基本上,拥有一套模型对人类和机器都有好处!!
在这篇文章和随后的文章中,我将挑选一些我发现在商业世界建模中非常有用的心智模型。
图 1:什么是模型思维?(来源:作者出品)
系统思维
在我三十年的商业和技术生涯中,我广泛使用的最有用、最实用、最深刻的心智模型是系统思维。它帮助我看到了更大的图景和看似不相关的领域之间的相互关系。我觉得对数据科学家来说,很好地理解系统思维并实践它是至关重要的。彼得·圣吉清晰地总结了什么是系统思维:
“系统思维是一门学科,用于观察复杂情况下的‘结构’,以及识别高杠杆和低杠杆的变化。也就是说,通过观察整体,我们学会了如何促进健康。为此,系统思维提供了一种语言,它从重构我们的思维方式开始。”
有许多书籍[10-12]甚至多个系列的博客[8,9]描述系统思考。在我自己的作品中,巴里·里士满[12–13]和约翰·斯特曼[11]的作品对我影响最大。我将利用他们的工作来说明它是什么以及为什么它与数据科学家相关。
我们传统的教育课程强调分析性思维——解决问题、将其分解成组成部分、为这些部分开发解决方案并将它们组合在一起的能力。作为顾问,你被不断地敦促在你的思维中要有 MECE(互斥的和集体穷尽的),清晰地提出你的假设,并开发出一套 MECE 选项来解决任何问题。虽然分析和 MECE 思维在理解问题时确实有特定的作用,但我们经常被它蒙蔽,很少质疑它。另一方面,系统思维是 MECE 思维的完美反例。让我们回顾一下系统方法需要的一些关键思维模式。
动态思维——根据问题如何随时间演变来强化问题框架的思维模式。静态思维关注的是具体事件,而动态思维关注的是物理或人类系统的行为如何随着时间的推移而变化。思考输入如何随时间变化以及它对输出行为的影响的能力至关重要。
数据科学家通常使用某个时间点的横截面数据来处理问题,以进行预测或推断。不幸的是,考虑到大多数问题周围不断变化的环境,很少有东西可以进行静态分析。静态思维强化了“一劳永逸”的建模方法,这种方法往好了说是误导,往坏了说是灾难性的。即使是简单的推荐引擎和基于历史数据训练的聊天机器人也需要定期更新。理解变化的动态本质对于构建稳健的数据科学模型至关重要。
系统因思维——一种思维模式,决定我们系统的边界(即广泛边界)内包括什么,以及要包括什么的粒度级别(即密集边界)。广度和深度的界限取决于我们分析系统的环境,以及什么在决策者的控制之下,什么在他们的控制之外。
数据科学家通常使用提供给他们的任何数据。虽然这是一个很好的起点,但我们还需要了解更广泛的背景,即如何使用模型,以及决策者可以控制或影响什么。例如,在构建机器人建议工具时,我们可以包括许多不同的方面,从宏观经济指标、资产类别表现、公司投资策略、个人风险偏好、个人的生命阶段、投资者的健康状况等。要包含的因素的广度和深度取决于我们是在为个人消费者、顾问、财富管理客户,甚至是政府的政策制定者打造一个工具。更全面地了解不同因素以及它们如何与用户和用户环境相互影响,将有助于我们建立有针对性的模型,并适当地确定它们的范围。
森林思维——这种思维模式让我们能够看到“更大的图景”并在必要时进行汇总,同时又不会丢失必要的细节。通常,数据科学家在查看数据的单个元素(例如,单个客户数据)时,会被迫进行逐树思维,而看不到解决所提出的问题需要哪些数据的更大图景。我经常看到这转化为“使用可用数据建立我们可以建立的最佳模型”,而不是探究“可能需要收集什么数据来解决我们的问题”。
运营思维 —一种专注于行为在系统中如何表现的运营过程或“因果关系”的思维模式。运营思维的对立面是我之前提到的因素思维或基于列表的思维或 MECE 思维。依赖机器学习作为数据科学的主要或唯一方法很容易导致我们所有人进入因子思维,专注于预测输出变量,而不考虑过程或因果关系。虽然这在许多应用中可能是合适的,但是它们不是普遍适用的。最近对可解释的人工智能的研究是试图重现一些答案是如何得出的过程和基本原理。
闭环思维——一种寻求识别系统中反馈回路的思维模式,通过反馈回路某些结果成为原因。占主导地位的“时间如箭一般”是一种强大的思维模式,它限制了我们对商业和科学的思考。数据科学家也未能幸免于这一趋势。系统动力学社区广泛使用的因果循环图和股票流图以及因果推断是数据科学家可以用来脱离直线思维的一些工具。
这些只是系统思考的几个关键模式。Barry Richmond [12,13]还谈到了 定量思维科学思维非线性思维 和 万计思维 。此外,他还分享了值得研究的沟通和学习原则。
我发现系统思考方法特别有吸引力,原因有几个。首先,它提供了一种可供选择的思维方式,更重要的是,这种思维方式可以将不同的部分联系起来,并且通常会带来解决问题的独特视角。第二,它更加开放,提供多种观点和权衡来进行分析,而不是要求一个唯一正确的答案。这通常会导致更明智的人类决策,而不是脆弱和无法解释的机器决策。第三,它提供了一种更好的解释和交流决策的方式。在后续的文章中,我将举一些具体的例子来说明这些好处。
图 2:什么是系统思维?(来源:作者制作)
基于主体的思维
如果你在网上搜索基于主体的思维,你可能在基于主体的思维上找不到多少;取而代之的是,你会看到许多关于 基于代理的建模 (ABM)的引用。虽然 ABM 是我将在以后的文章中探讨的这种思想的具体实现,但我想把重点放在构建这种基于代理的模型之前的思想上。
基于主体的思维——一种思维模式,其中我们关注更简单的(或原子的)实体或概念,以及这些实体之间相对简单的交互如何导致涌现的系统行为。与系统思维类似,我们对系统层面的行为感兴趣,但是我们不是从自顶向下的角度观察关系,而是从自底向上的角度分析系统行为。这种思维是以个人为中心的——个人的状态(身体或精神)是什么,个人如何与其环境和其他个人互动,以及这如何改变其状态。这种以个人为中心或基于代理的思想可以应用于物理资产(例如,恒温器可以被认为是代理)、个人消费者(例如,在营销环境中对做出购买决定的个人消费者进行建模)、公司实体(例如,按照自身利益行事以使市场有效的公司),或者甚至国家政府(例如,基于其比较优势彼此进行贸易的国家)。
系统思维和基于主体的思维可以应用于同一组问题,并产生类似的结果,但从不同的思维模式或心理模型来处理它。例如,众所周知的疾病进展流行病学模型——SEIR(易感、暴露、传染、康复),可以从系统角度或个体角度进行分析。当我们观察整个易感人群、暴露人群等时,我们是在系统水平上工作,如果我们观察每个人的状态,如他们是否已经感染、康复等。我们在基于代理的水平上操作。
当我们想从疾病进展的总体行为转向个体行为时,基于主体的思维成为一种更自然的思维方式。例如,如果我们不仅对总体感染水平感兴趣,而且希望了解哪些人容易感染疾病或特定人的行为(例如,社交距离或戴口罩),以及它们如何促进疾病发展,基于代理的思维是一种更自然的方法。
基于主体的思维是基于主体的建模(也称为基于主体的模拟或微观模拟系统)、多主体系统和强化学习的基础。因此,数据科学家需要善于从个体代理的角度分析问题,其中个体代理可能是物联网设备或物理资产(更普遍的说法是“数字双胞胎”)或个体决策实体,如消费者、企业等。
我发现基于代理的思维在某些情况下特别有吸引力。首先,当实体或代理的集合是可识别的和异质的时,它提供了一种研究它们行为的直观方式。第二,当实体之间的交互更加本地化时,用基于主体的思维来研究它们就更容易了。第三,当个体行为(或群体行为)比系统行为更重要时,基于主体的思想提供了一种更好的方法。第四,当个体实体以不同的方式适应和改变时,我们最好在个体层面建模,而不是在系统层面。在后续的文章中,我将使用具体的例子来探讨系统和基于代理的思维之间的更多相似之处和不同之处。
图 3:什么是基于主体的思维?(来源:作者出品)
行为(经济学)思维
围绕人性和判断的心智模型集合[6],通常被称为行为经济学,在我的咨询和人工智能之旅中对我产生了重大影响。有趣的是,人工智能和行为经济学有着共同的祖先。希尔伯特·西蒙的有限理性概念质疑了“人类是理想的理性决策者”的主流观点,相反,他认为我们做出的决定受到我们的思维能力、可用信息和时间的限制[14]。这是行为经济学领域[15-17]的基础,该领域自 20 世纪后期以来一直处于优势地位。西蒙也被认为是人工智能的创始人之一,他在开发启发式程序和人类问题解决方面的工作为未来的符号人工智能系统奠定了基础。用他的话说[14],
有限理性的原则是,与问题的规模相比,人类思维制定和解决复杂问题的能力非常小,而这些问题的解决方案是现实世界中客观理性行为所需要的,甚至是这种客观理性的合理近似。
在过去的几十年里,行为经济学对学术界和商业界产生了深远的影响,包括人类如何做出决策[15],做出决策的基本过程[16],他们如何偏离理想的效用最大化经济观点,以及如何引导他们做出符合自身利益的决策[17]。
行为(经济)思维 (或简称 行为思维 )是一种思维模式,关注人类如何真正做出决策,而不是他们应该如何做出决策。当我们使用基于主体的思维时,我们通常需要理解人类如何做出决策(例如,关于购买什么商品、投资多少等的决策)。锚定、违约、跟风效应、损失厌恶、双曲线贴现和大量其他启发法等行为经济学原理试图解释我们在不同情景下如何做出决策。我将在接下来的文章中更详细地探讨这些。
作为一名数据科学家,我发现行为思维在两个具体方面很有用。首先,它帮助我们了解人类如何做出决策,以便我们可以了解数据科学家建立的模型将如何被他们使用,以及更好地采用这些模型所需的解释。第二,它有助于我们在代理内模拟人类决策,以模拟或观察整体行为。这第二个方面可以看作是基于主体的思维的进一步专门化。
图 4:什么是行为思维?(来源:作者出品)
计算思维
计算思维这个术语是由西蒙·派珀特[18]在 1980 年首次提出的。然而,计算思维作为计算机科学教育的一个关键组成部分的重要性是在 Jeannette Wing 的一篇论文[10]之后出现的。随着算法思维、科学、工程和商业各个方面的计算方法的出现,计算思维的基础在上个世纪的后半个世纪已经日趋成熟。
计算思维 是一种强调结构化问题求解、问题分解、模式识别、概括和抽象,并能被计算机编码和执行的思维模式。计算思维对工业革命之后的一系列革命产生了深远的影响——计算革命、互联网和智能手机革命,以及现在的大数据、分析和人工智能革命。
虽然我之前讨论的所有思维模式都可以用于理解人类和机器,但计算思维是创建智能系统的核心。或者,我们也可以将计算思维视为编码和实现其他类型思维的机制。因此,作为一名数据科学家,我们必须经常进行计算性思考,并对我们提供的指令保持精确。
图 5:什么是计算思维?(来源:作者出品)
在这篇介绍性文章中,我解释了五种关键的思维模式——每一种都是对前一种的提炼。在接下来的几篇文章中,我们将深入研究这些思维模式的细节,并举例说明如何应用它们来解决商业和科学问题。
参考文献
[1]特伦斯格里芬。我从查理·芒格那里学到了很多关于心智模式和人情世故的东西。2015 年 8 月 22 日。
[2]阿南德·拉奥。开发以人为中心的 AI 的十种人类能力和四种智能。中—启动,2020 年 10 月 10 日。
[3]沙恩·帕里什和里扬农·博比恩。伟大的心智模型第 1 卷:一般思维概念。格子出版公司 2019。
[4]沙恩·帕里什和里扬农·博比恩。伟大的心智模型第 2 卷:物理、化学和生物。格子出版公司 2020。
[5]加布里埃尔·温伯格和劳伦·麦肯。超级思维:心智模型大全。作品集,2019。
用心智模型来理解世界:339 种模型被解释为随身携带在你的头脑中。
[7]斯科特·E·佩奇。为什么“多模型思考者”做出更好的决策《哈佛商业评论》,2018 年 11 月 19 日。
[8]莱拉·阿卡罗格鲁。系统思考者的工具:系统思考的六个基本概念。中等——颠覆性设计。2017 年 9 月 7 日。
[9]安德鲁·亨宁。系统思考第 1 部分——要素、相互联系和目标。中等—更好的系统。2018 年 8 月 1 日。
10 多内拉·梅多斯。系统思维:初级读本。切尔西格林出版社。2008.
[11]约翰·斯特曼。商业动态:复杂世界的系统思考和建模。麦格劳-希尔教育公司。2000.
12 巴里·里士满。与 Stella 一起介绍系统思维。ISEE 系统公司,2004。
13 巴里·里士满。系统思维中的“思维”。怎么才能让它更容易掌握?。系统思考者。
[14]希尔伯特·西蒙。有限理性模型第 1 卷:经济分析与公共政策。麻省理工学院出版社。1984.
[15]丹·艾瑞里。可预测的非理性,修订和扩展版:塑造我们决定的隐藏力量。哈珀·柯林斯,2009 年。
[16]丹尼尔·卡内曼。思考,忽快忽慢。法勒、斯特劳斯和吉鲁,2013 年。
17 理查德·塞勒和卡斯·桑斯坦。推动:改善关于健康、财富和幸福的决定。企鹅图书,2009 年。
[18]西蒙·派珀特。头脑风暴:儿童、计算机和强有力的想法。基础图书公司,1980 年。
[19]珍妮特·温。计算思维。《化学文摘》第四十九届会议的信息通报(3):第 33- 35 页。2006.
Python 的五个意想不到的行为可能会令人惊讶

图片由 chriszwettler 来自 Pixabay
一些你需要知道的关于 Python 的冷知识
每种编程语言都可能有一些有趣的事实或神秘的行为,Python 也是如此。事实上,作为一种动态编程语言,Python 中有更多有趣的行为。
我敢打赌,大多数开发人员可能从未经历过这些场景,因为我们大多数人会编写“常规”代码。但是,从别人那里知道这些事情,提醒自己避免一些陷阱,还是有好处的。此外,我们可以从这些例子中学习,以更深入地了解 Python。
在本文中,我将演示其中五个有趣的场景。如果你想了解更多,这里还有另外三个:)
1.“+=”不是原子操作

很不幸,此时此地的图片结束了我在 Pixabay 上的旅程
我们知道 Python 中的 tuple 是一个不可变的对象,所以一旦它被创建,我们就不能改变它的元素。
my_tuple = (1,2,3)
my_tuple[0] = 11

嗯,这是意料之中的。然而,Python 中的列表是可变的。因此,我们可以向列表中添加更多的元素,即使它是元组中的一个元素。毫不奇怪,如果我们用列表作为条目定义一个元组,我们可以用更多的条目扩展其中一个列表。
my_tuple = ([1],[2],[3])
my_tuple[2].extend([4,5])

我们使用了extend()方法,将一个列表附加到另一个列表。但是,如果我们尝试使用“+=”操作符来扩展列表呢?
my_tuple[2] += [6,7]

由于元组是不可变的,它不允许我们用新的列表[3,4,5,6,7]替换原来的列表[3,4,5]。然而,如果我们试图打印元组,我们会发现列表被改变了!
这是因为运算符“+=”不是原子操作。基本逻辑如下。
- 由于我们使用了“+=”,Python 会将列表
[6,7]追加到元组中的原始列表。它将在处发生,因为我们使用了“+=”。 - 它将尝试将新列表分配回元组。
好的。该操作不是原子的,它由两个步骤组成:扩展和分配。第二步赋值将失败,因为元组是不可变的。但是,第一步在适当的位置修改了列表,因此列表已经被更改。
这就是为什么我们看到错误消息,但是元组中的列表已经被更改。
2.类属性存储在字典中

图片来自 Pixabay
我们知道可以在 Python 类中定义类属性。因为它是一个类属性(在某种程度上类似于其他编程语言中的静态属性),所以我们可以在没有实例化对象的情况下访问它。
让我们定义一个父类和两个子类。
class Parent:
class_attr = 'parent'class Child1(Parent):
passclass Child2(Parent):
pass
因为这两个子类是从父类继承的,所以它们也将继承 class 属性。所以,这三者的属性值都是一样的。
print(Parent.class_attr, Child1.class_attr, Child2.class_attr)

现在,如果我们显式地给子类中的 class 属性赋值,就会显示出区别。
Child1.class_attr = 'child1'

但是,如果我们更改了父类的值,所有其他从未覆盖该类属性的子类也会反映这一更改。
Parent.class_attr = 'parent_new'

这是因为所有这些类属性都将存储在该类的专用字典中。我们可以使用__dict__来访问这本字典。
Parent.__dict__
Child1.__dict__
Child2.__dict__

如果我们不覆盖属性,子类的字典中就不会有这样的键值对。然后,它将试图在它的父类中找到它。如果我们给 class 属性分配了一个子类的值,它将在字典中维护它。
3.消失的错误信息

图片来自 Pixabay 的Steve buiss NNE
与大多数其他编程语言不同,Python maximum 扩展了变量的范围。例如,如果我们在 if-else 条件中定义了一个变量,就可以从它的外部作用域访问它。
if True:
a = 1print(a)

然而,对于一个 try-except 块来说,这是不正确的。
try:
1/0
except ZeroDivisionError as e:
a = 1print('a =', a)
print('The exception was:', e)
在上面的代码中,我们有意触发了一个异常,并在 except 块中捕获了它。然而,消息e不再可访问,而普通变量a仍然可以访问。

如官方文件所述:
当使用
as target指定一个异常时,它在 except 子句的末尾被清除。异常之所以被清除,是因为有了对它们的回溯,它们与堆栈帧形成了一个引用循环,使该帧中的所有局部变量保持活动状态,直到下一次垃圾回收发生。
ref:https://docs . python . org/3/reference/compound _ stmts . html #除了
如果我们真的想保留那个错误消息,我们仍然可以通过将它赋给另一个变量来实现,如下所示。
err_msg = Nonetry:
1/0
except ZeroDivisionError as e:
print('The exception is:', e)
err_msg = eprint('The exception was:', err_msg)

4.不可靠的价值转移

NumPy 是 Python 中使用最广泛的库之一。它擅长模拟多维数组。现在,让我们写一个函数来定义一个 NumPy 数组,但不返回它。
import numpy as npdef make_array(num):
np.array([num])
我知道,写这样一个函数没有任何意义,但我只是想展示有趣的行为。
现在,让我们使用这个函数创建一个 NumPy 数组,然后使用np.empty()函数创建一个只有 1 个值的空数组。同样,让我们显式地指定我们想要空数组中的整数。
make_array(12345)
np.empty((), dtype=np.int)

为什么我们能获得这个函数创造的价值?
事实上,NumPy 数组是在函数中创建的。然而,它没有被函数返回,所以这个数组的值变成了“垃圾”。这个垃圾值的内存地址将被释放。换句话说,这个内存地址现在可以用于其他目的。
然后,np.empty()函数将创建一个空数组,其中的值占位符指向内存。在这种情况下,将使用最近释放的内存。这就是为什么我们可以在新的空数组中看到值。
5.不可见的迭代条件

请注意,这个例子中的代码是完全错误的!这仅用于演示目的!
让我们定义一个简单的字典,然后循环它。对于这个字典的每个循环,我们希望删除一个键值对并创建一个新的键值对。代码如下(还是那句话,这种代码的写法不对!)。
my_dict = {1: 1}for key in my_dict.keys():
del my_dict[key]
my_dict[key+1] = key+1
print(key)
print(my_dict)

最初的直觉猜测是什么?这会是一个无限循环吗?不,结果相当令人惊讶。
我们认为我们写了一个 bug,它应该是一个无限循环。不过每次都停在 6(Python 3.7)。
对于 Python 字典,通常创建的最小长度是 8。当它达到长度的 2/3 时,词典将自动调整大小。是调整大小导致了迭代的失败。8 * (2/3) = 5.33,正好是我们停下来的数字。
当在第 6 个项目处触发调整大小时,这导致“下一个”键现在位于“更早的”槽中。
摘要

在本文中,我展示了 Python 中五个有趣而神秘的行为,包括类属性、非原子的“+=”操作、在外部作用域中访问 except 错误消息、NumPy 空函数和字典。希望这些例子能引起你的兴趣,尽管从编程的角度来看,有些例子是完全错误的。
如果你觉得这篇文章中的例子很有趣,我会在以后找到更多这样的例子和技巧!
https://medium.com/@qiuyujx/membership
如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)
在数据科学团队中培养健康文化的五种方法

帮助您在数据科学团队中培养强大文化的战略方法
大家好!我们今天发布了一个新帖子,将学习新的硬技能放在一边,专注于数据科学领域的一些重要软技能。不言而喻,健康的工作文化对任何工作都很重要,对数据科学家和机器学习工程师来说也是如此。健康的工作文化有助于提高生产力,留住优秀员工,并让你的队友开心。
虽然我现在的日常工作是一名实践机器学习工程师,但你可能不知道的是,我的大部分教育和工作根源都是在商业和领导力方面。简单介绍一下我的背景:几年前,我从面向业务的角色转向了数据科学领域。因此,我实际上没有任何数据或计算机科学领域的正式学位。实际上,我有一个组织领导力的硕士学位,并持有几个以领导力为导向的认证,比如项目管理专家(PMP)、认证 Scrum Master (CSM)等等。
好了,别再自吹自擂了!我分享这一点的唯一原因是,当我进入目前的机器学习工程师角色时,我将许多相同的原则带到了这里,几乎两年后,我真的为我的工作团队感到自豪。他们是一群合作愉快的人,每个人都在教学和互相鼓励方面做得很好。我的团队的生产能力也同样高!
当然,我希望看到每个人都茁壮成长并取得成功,所以我想分享五个策略来帮助培养您自己的数据科学团队的文化。坦率地说,所有这些策略的基本原则对于任何非数据科学的工作都同样重要,但在可能的情况下,我会特别针对数据科学角色对这些策略进行一些战术上的调整。
事不宜迟,让我们开始我们的战略吧!
1.优雅地接受所有的想法。
这是名单上的第一名。尽管统计的严谨性等许多事情是该角色的关键要素,但数据科学家通常必须在他们做许多事情的方式上具有创造性。请记住,数据科学家的预测模型与解决业务问题有直接关系,请记住,即使没有数据科学,解决业务问题的方法也往往不止一种。因此,将有不同的选项来协调不同目的的不同模型,不同的建模方法(例如,标准监督学习与深度学习),等等。
当然,有些想法比其他的更好,但重要的是以同样的优雅程度尊重所有的想法。当你告诉一个人他的想法很愚蠢时,没有什么比这更能让他闭嘴了。这是极其贬低身份的,一个人在未来远不太倾向于分享新的想法。这个人可能对未来的项目有很棒的想法,但他们可能不会分享,因为害怕再次被嘲笑。
这是多层面的损失。这显然是企业的损失,因为他们错过了潜在的好主意,但这也是整个团队的损失。如果团队在分享新想法方面变得僵化,快乐水平肯定会下降,个人完全离开公司的可能性很大。
如果你想在你的团队中培养一种开放的优雅精神,那就从你自己开始吧。即使你不同意某个想法,也要感谢这个人的想法,并展开对话,引导团队提出更好的想法。谁知道呢,也许当初“坏主意”的一部分还能影响更好的方向呢?但是恩典必须从某处开始,没有比和你一起开始更好的地方了。
2.考虑定期举行展示新技能的会议。
在上面的策略中,我提到没有什么比贬低一个人更能让他闭嘴。我会说 下一件让人很快闭嘴的事是对某个话题缺乏了解。实话实说:没有人喜欢看起来像个哑巴。我们倾向于过度补偿我们知识的缺乏,要么加倍我们舒适的东西,要么退缩到角落里。总的来说,我注意到数据分析领域的一个最大问题是,许多数据科学家会加倍研究传统的统计建模,因为像深度学习这样的新策略可能是一个学习挑战。
解决这个问题的一个非常有策略的方法是定期召开会议,为团队的其他成员分享学到的新技能。今天,我的团队每隔一周就这样做一个小时,老实说,这是我最喜欢的例会之一。学习一项新技能不仅很棒,而且经常会有关于如何在不同的项目中以不同的方式应用新技能的精彩对话。
关于对话的最后一点,我认为如果小组规模小得多,效果会好得多。我知道邀请你部门的每个人去学习新的东西是很诱人的,但是一旦你开始超过十个人,进行合理的对话就有点过时了。人太多就太难用了。对于更多的观众来说,可能会有不同类型的技能会议的空间,但为了获得最佳效果,我会鼓励从较小的人群开始。
3.确保团队最佳实践的清晰性。
在最后一个策略中,我们提到,当人们缺乏某方面的知识时,他们会感到厌烦,虽然一般的数据科学技能是一回事,但团队最佳实践和策略是另一回事。组织和标准可以帮助团队茁壮成长,但是如果每个人都不清楚这些实践是如何体现的,它们就没有用了。数据科学也不例外。我确信您的团队可能有组织 Git 存储库、从一个中心源获取数据等等的方法。
这里我将推荐两件具体的事情:一件显而易见,另一件不那么显而易见。第一个明显的例子:在某个地方记录你团队的所有最佳实践。即使这些都在一个 Git 项目的自述文件中,或者保存在每个人都知道可以访问的地方的 Word 文档中,这也比什么都不写要好。
第二点也是更重要的一点是确保你的团队的实践在概念层面上不会复杂和简单到难以记忆。即使你把它们都写下来,如果过程太复杂或者太麻烦,没有人会愿意去遵循它们。句号。文档应该被看作是一个参考指南,具体地做一些你已经有了大致概念的事情。
例如,您可能很清楚您的数据存储在一个中心源中。文档应该作为所有本质细节的参考,没有人应该在访问中央数据源时记住这些细节。请记住,即使一件复杂的事情如果做对了会变得很酷,但是如果没有人愿意持续地做这件事,它也是无用的。
4.推广结对编程的概念。
现代数据科学显然与现代计算机科学密切相关,因为我们使用 Python 或 R 等技术来构建预测模型。普通的软件开发人员经常不得不努力让代码工作,数据科学家在代码中实现数据科学工作时同样面临许多相同的挑战。作为一名机器学习工程师,我可以向你保证,我花在调试我认为应该工作的代码上的时间比一开始写代码要多得多!
如果你不知道,结对编程是一种让两个或更多的人同时处理相同代码的策略。通常会有一个人接手打字工作,并与他们的队友分享他们的屏幕,他们会就如何编码进行反复的对话。这通常会带来更好的编码方式的新想法,我个人将结对编程作为调试不工作的东西的绝佳时机。因为计算机科学需要如此精确的语法,一个简单的输入错误就可能对代码的功能造成严重破坏。第二双眼睛通常可以很快发现那些语法错误!
5.寻求小机会找乐子!
商业世界的诱惑是声明任何与促进商业没有直接关系的事情都是浪费时间。虽然我当然同意一个团队花费大量时间偷懒对公司的底线是有害的,但我认为重要的是要记住快乐的员工=高效的员工。尤其是在这个“大迁移”的时代,许多数据科学家都去了其他地方工作,快乐因素对于留住这些优秀人才极其重要。
除了是机器学习工程师,我还担任我团队的 scrum master。我知道一些 scrum 大师可能会把谈话引回到手边的业务上,如果它开始偏离到一个私人的、有趣的话题,但是我个人偶尔会允许这样做。是的,公司不在乎我的队友对我们玩的电子游戏或看的电影的看法,但如果我能保持团队的高昂士气,我可以保证公司的底线将通过更高的生产率和留住优质员工而得到实质性的提高。
伙计们,这又是一篇文章了!我希望这些策略有助于在您的数据科学团队中培养强大的工作文化。你还有什么要补充的吗?我总是渴望听到新的策略,所以请在评论中分享你的想法。感谢阅读,下期再见!
即使你没有经验,也可以通过五种方式获得现实生活中的数据科学经验
发展你的技能,获得宝贵的经验

照片由维达尔·诺德里-马西森在 Unsplash 拍摄
介绍
我相信你经历过可怕的循环,
“我找不到工作因为我没有经验因为我找不到工作因为我没有经验…”
最重要的是,疫情只会让就业市场的竞争更加激烈。那么,如何获得任何与数据相关的经验,并从中脱颖而出呢?
在本文中,我将通过五种高效且有价值的方式让您获得真正的数据科学体验。我特别选择了这五个,因为它们将帮助你获得实践经验,还能让你充实简历(是的,我们生活在一个这很重要的世界里)。
说了这么多,让我们开始吧!
1.利用非营利机会
直到最近,我才发现有许多非营利组织招募志愿者来支持社会事业的数据科学项目。
以下是我推荐的几个组织:
- 统计无国界 组织并连接统计学家和数据科学家与国际非营利组织。他们合作过的一些著名组织有联合国儿童基金会和联合国。
- Catchafire 是另一个知名的组织,它为那些愿意贡献时间的专业人士和需要他们技能的非营利组织牵线搭桥。他们有大量的数据和分析机会,如果你搜索“数据”就能找到。
- 我想分享的最后一个是 Solve for Good ,这是一个专门为数据科学发布项目的非营利组织平台!你所需要做的就是注册并申请你感兴趣的项目。
正如我一开始说的,这些都是很好的机会,因为它们会给你实际的现实世界的经验,而且它们也会丰富你的简历!
2.SQL 案例研究
如果你想成为一名数据科学家,你必须有很强的 SQL 技能。Mode 提供了三个模拟真实业务问题的实用 SQL 案例研究,以及一个在线 SQL 编辑器,您可以在其中编写和运行查询。
要打开模式的 SQL 编辑器,请转到 此链接 并点击显示“打开另一个模式窗口”的超链接。
学习 SQL
如果您是 SQL 新手,我会首先从 Mode 的 SQL 教程开始,在那里您可以学习基本、中级和高级 SQL 技术。如果您已经对 SQL 有了很好的理解,可以跳过这一步。
案例研究 1:调查用户参与度的下降
链接到案例 。
本案例的目的是确定 Yammer 项目用户参与度下降的原因。在深入研究这些数据之前,您应该先阅读一下 Yammer 的概述这里的。您应该使用 4 张表。
到案例的链接将为您提供关于问题、数据和应该回答的问题的更多细节。
如果你需要指导,请点击查看我是如何完成这个案例研究的。
案例研究 2:了解搜索功能
链接到案例 。
这个案例更侧重于产品分析。在这里,您需要深入研究数据,确定用户体验是好是坏。这个案例的有趣之处在于,由你来决定“好”和“坏”是什么意思,以及如何评估用户体验。
案例研究 3:验证 A/B 测试结果
链接到案例 。
最实际的数据科学应用之一是执行 A/B 测试。在本案例研究中,您将深入研究 A/B 测试的结果,其中对照组和治疗组之间存在 50%的差异。在这种情况下,您的任务是在彻底分析后验证或否定结果。
3.个人数据科学项目
获得数据科学经验的最佳方式之一是创建自己的机器学习模型。这意味着找到一个公共数据集,定义一个问题,用机器学习解决问题。
Kaggle 是世界上最大的数据科学社区之一,有数百个数据集可供选择。以下是一些你可以用来开始的想法。
世界大学排名
链接到数据集这里。

你认为你的国家有世界上最好的大学吗?成为“最好的”大学意味着什么?该数据集包含三个全球大学排名。使用这些数据,看看你能否回答以下问题:
- 顶尖大学在哪些国家?
- 决定一个人世界排名的主要因素是什么?
检测信用卡欺诈
在此链接到数据集。

照片由rupixen.com在 Unsplash 上拍摄
该数据集显示了两天内发生的交易,284,807 笔交易中有 492 笔欺诈。数据集高度不平衡,正类(欺诈)占所有交易的 0.172%。了解如何处理不平衡数据集并构建信用卡欺诈检测模型。
贷款预测
在此链接到数据集。

德米特里·德米德科在 Unsplash 上拍摄的照片
该数据集取自 Analytics Vidhya,包含 615 行和 13 列过去已批准和未批准的贷款。看看你能否创建一个模型来预测贷款是否会被批准。
4.熊猫练习题
当我第一次开始开发机器学习模型时,我发现我缺乏熊猫技能是我所能做的一个很大的限制。不幸的是,互联网上没有多少资源可以让你练习熊猫技能,不像 Python 和 SQL…
然而几周前,我偶然发现了 这个资源——这是一个专门为熊猫准备的充满练习题的资源库。通过完成这些练习题,您将知道如何:
- 过滤和排序您的数据
- 分组和聚合数据
- 使用。apply()操作数据
- 合并数据集
- 还有更多。
如果你能完成这些练习题,你应该可以自信地说,你知道如何使用熊猫进行数据科学项目。这也将对你下一节有很大的帮助。
5.成为一名卡格尔大师
如果你不知道什么是 Kaggle ,我强烈建议你花时间去探索它,看看它能提供什么。在我看来,Kaggle 对于数据科学家就像 Leetcode 对于软件工程师一样。
Kaggle 允许你展示你的数据科学项目,你的底层代码,以及你有多活跃!有三种方法可以让你成为一名卡格尔大师:
a)参加比赛
在我看来,没有比通过竞赛展示您的代码更好的方式来表明您已经为数据科学工作做好了准备。Kaggle 举办了各种各样的比赛,包括建立一个模型来优化某个指标。
你现在可以尝试的两个比赛是:
b)创建和共享数据集
为了成为一名优秀的数据科学家,你首先要有好的数据!通过 web 抓取或其他方式创建数据集,并与社区的其他成员共享这些数据集,这是实践提供干净和可用数据的一个很好的方式。
c)进行 EDA 并构建模型与他人分享
也许 Kaggle 最好的部分是有成千上万的数据集供你探索和建立模型。不久前,举个例子,我使用成对关联构建了一个极其简单的烹饪食谱推荐系统。我还利用其中一个冠状病毒数据集来看看自今年年初以来新冠肺炎的传播是如何演变的(点击这里查看)。)
感谢阅读!
我希望这些资源和想法对您的数据科学之旅有所帮助!
不确定接下来该读什么?我为你挑选了另一篇文章:
**
又一个!
特伦斯·申
在同一个项目中实现 R 和 Python 无缝协作的五种方式
现在很容易同时使用两种语言来获得最佳效果
最近我发现自己同时使用 R 和 Python 做了更多的项目。对我来说,在工作中使用最好的工具,不受单一语言的限制变得越来越重要。有些事情 Python 做得最好,有些事情 R 做得最好,所以如果我们能在需要的时候使用这两者,我们就能做到最好。在最近的一个例子中,我想创建一个闪亮的应用程序来生成参数化的 Powerpoint 文档,并想用 R 编写我的数据处理代码以利用 tidyverse,但使用 Python 编写 Powerpoint 编辑代码,这在python-pptx包中很容易。
现在,在 RStudio IDE 中使用这两种语言非常容易。要做到这一点,您需要在 r 中安装并加载reticulate包。以下是您可以做的五件事,让您在同一个项目中使用两种语言进行无缝编码:
1.在项目启动时定义 Python 环境
为了避免与使用错误的 Python 解释器相关的任何问题,您可以在项目启动时通过创建一个.Rprofile文件并将其保存在项目目录中来定义您的 Python 环境。您的.Rprofile包含每当您的项目启动时将被执行的代码。我的.Rprofile里通常有这两行代码:
Sys.setenv(RETICULATE_PYTHON = "<path>")print(paste("Python environment forced to", Sys.getenv("RETICULATE_PYTHON")))
其中<path>是您希望使用的 Python 环境中的 Python 可执行文件的路径。第一个命令将其设置为 python 可执行文件。第二个命令打印一个确认信息,每次启动项目时都会显示在您的终端上。当我开始一个项目时,我的终端看起来是这样的:

作者生成的剪切屏幕
2.使用repl_python()在 Python 中实时编码
在构建项目时,您需要测试 Python 代码和 R 代码。reticulate包中的repl_python()函数将您的 R 终端切换到 Python 终端,这样您就可以用 Python 实时编码了。您可以使用exit命令退出,然后用 R 编写更多的代码,然后如果您返回到 Python 终端,它仍然会记住上次会话的所有对象,这意味着可以很容易地在语言之间无缝切换。这里有一个简单的例子:

作者生成的剪切屏幕
3.在 Python 和 R 之间交换对象
任何相当标准的数据对象,比如值、列表和数据帧,都可以在 Python 和 R 之间交换。要在 R 中使用名为my_python_object的 Python 对象,可以使用py$my_python_object来调用它。下面是另一个例子,我将来自 R 的mtcars数据集引入 Python:

作者生成的剪切屏幕
数据对象将被翻译成不同语言的等价结构。例如,R 中的列表将被翻译成 Python 中的 dict:

作者生成的剪切屏幕
4.将 Python 函数转换成 R 函数
当您同时使用这两种语言时,您最终需要将 Python 代码作为 R 中的一个函数来执行。如果您将 Python 函数编写到一个文件中,然后使用source_python()将该文件转换为 R 中的源代码,那么您的 Python 函数就变成了一个 R 函数,供您在需要时使用。下面是一个简单的例子,我编写了一个 Python 函数将两个数字相加并保存在文件sumof.py中:
def sumof(a, b):
return a+b
现在我可以对sumof.py进行 source,它变成了 and R 函数:

作者生成的剪切屏幕
5.编写介于 R 和 Python 之间的 R Markdown 文档
通过适当地设置您的.Rprofile,您可以创建具有两种语言的代码块的文档,并且您可以在代码块之间交换对象。下面是一些简单的 R Markdown 代码来演示这一点:

作者生成的剪切屏幕
这会产生以下输出:

作者生成的剪切屏幕
同样,您可以用一种语言编写函数,并在另一种语言中轻松使用它们:

作者生成的剪切屏幕
对我来说,这个功能让我的工作变得可能。我希望这些技巧能帮助你开始探索 Python 和 R 所能提供的最好的东西。
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在LinkedIn或Twitter上找我。也可以看看我在drkeithmcnulty.com上的博客。

unsplash.com 的好意
Python 中“f 字符串”的五种奇妙用法

Paul Volkmer 在 Unsplash 上拍摄的照片
在 PEP 498 推出之前,Python 主要有三种格式化字符串的方式,即[%-formatting](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting)、[str.format](https://docs.python.org/3/library/string.html#formatstrings)和[string.Template](https://docs.python.org/3/library/string.html#template-strings)。2015 年, Eric V. Smith 提出了一种新的字符串格式化机制,称为文字字符串插值,为格式化字符串提供了一种更简单有效的方式。这些字符串被称为格式化字符串或 f 字符串,因为它们以'f'或'F'为前缀。
首先,我们将快速了解 Python 中不同的字符串格式样式,以及 f-strings 是如何超越其他格式的。假设我们有三个人的姓名和年龄,我们希望以下面给出的格式打印他们:
The manager is [NAME] and his age is [AGE].
现在让我们来看一下 Python 中不同字符串格式样式之间的比较。我们将看到相同的输出,但是使用了不同的格式。
1.使用%运算符

2。使用字符串。格式
使用string.format的确在一定程度上简化了格式。

3.使用 f 弦
f 字符串进一步简化了格式。

如上所述,f 字符串在格式化字符串时非常方便。不再需要计算%s 和格式关键字。它们直截了当,不那么模棱两可,容易理解。既然我们现在知道了 f 弦的用处,是时候看看它们的其他功能了。
1.用 f 字符串格式化表达式
F-strings 允许您将表达式放在括号之间。括号内的表达式被计算并显示为结果。

这里,距离是在表达式中计算的,这为用户节省了一个额外的步骤。
2.格式化日期时间对象
在 Python 中,我们使用strftime() 方法,该方法使用 date 、 time 或 datetime 对象返回表示日期和时间的字符串。让我们看下面一个打印当前日期的例子。

嗯,仅仅用 f 弦也能得到同样的结果。这样就不需要使用srftime。

3.添加分隔符:逗号、下划线和空格
f 字符串也可以派上用场的情况下,你想包括分隔符在长的数字,即分隔数字在千位。您可以添加逗号、下划线,或者简单地用空格分隔数字。

4.对齐和居中字符串
默认情况下,字符串靠左对齐。但是,可以通过使用>或<字符后跟一个表示填充的数字来将它们右对齐。

类似地,你也可以通过在需要居中的字符串后使用^N来使字符串居中。同样,N 表示字符的数量。

5.在 F 字符串中使用if-else条件
最后,f-strings能够评估 if-else 条件。您可以在花括号中指定条件,它会输出结果。下面是一个打印两个给定数字中较大的一个的例子。

结论
我们已经看到 f 字符串在格式化字符串时非常有用。我们也看到了它们的一些使用方法。f 弦还有其他一些很好的用途,如果你想深入了解,官方文档是一个很好的起点。如果这篇文章激起了你对字符串数据类型的兴趣,这里还有一篇你可能会喜欢的文章,它是关于 Python 中的字符串方法及其用途的。
用 fixthejet 修复不均匀的色彩映射表
为什么(以及如何)避免感知上不一致的色彩映射表

Pawel Czerwinski 在 Unsplash 上的照片
信息是而不是知识。
如果信息背后的模式被很好地理解,信息可以被转化为知识。在当今这个科技飞速发展的时代,数据是一个重要的信息来源。因此,我们产生大量的数据也就不足为奇了——每天大约有 2.5 万亿字节。
理解科学数据(并因此将其转化为知识)的最有力的方法之一是绘制它。
想知道人的体重和身高有关系吗?剧情吧!
想知道宇宙膨胀是否在加速?剧情吧!
想知道离赤道越远越热吗?剧情 …小心出错!
尽管可视化对于快速消费数据和获得洞察力非常有效,但如果处理不当,它们也可能是有害的。
在这篇文章中,我们将学习:
- 为什么要小心选择色彩映射表?
- 为什么不使用“喷射”和所有其他感知不一致的色彩映射表?
- 如何使用一个新的 python 包来改变制作拙劣的图形的色彩映射表
非均匀色彩映射表的问题是

平均海面温度(来源: GrADS-aholic
看上面的海面温度(SST)图,试着用一句话概括。当我把上面的图表给我的 10 个朋友看时,他们中的 7 个人给出了某种版本的回答:“随着我们远离赤道,温度下降,在大约北纬 30 度或南纬 30 度处突然转变(斜体是我的)。我的朋友认为温度突然变化的原因是高亮度的颜色(如黄色)在我们的眼中很突出。换句话说,上面使用的色彩映射表在不存在对比的地方制造了人为的对比。在更好的色图中的相同数据(下面显示了具有“绿色”的例子)显示没有这样的突然转变。

如果这是一次性的,我们可以原谅。不幸的是,科学文献中充斥着使用糟糕的、感觉不一致的彩色地图的地图,比如“喷射”、“彩虹”、“光谱”、“要点”等等。雪上加霜的是,许多彩色地图对色盲人群也不友好。
2015 年,很多人注意到了这个现象,并在 R、Python、Matlab 等中轻推各自的社区。以改变它们的默认色图,使其在感觉上一致,从而不会在亮度上引入任何人为的梯度。关于更新的更多信息,查看 Python 中 matplotlib 的新默认颜色图的发布。我鼓励每个人使用他们可以得到的感觉上统一的颜色图(他们可以在这里找到 Python 和 R )。
但这仍然给我们留下了 2015 年前的劣质地图。如果不固定,它们可能很难在海报或演示中引用。迄今为止,它们继续出现在顶级会议、期刊和报告中。我们如何继续使用“喷气机”时代的知识,但避免与解释它们相关的陷阱?
输入 fixthejet
fixthejet 是一个 python 包,可以将图像(jpg/。png)从“jet”色彩映射表转换为基于用户输入的任何其他色彩映射表。该脚本仅选择性地更改喷射颜色。图像中的所有其他颜色保持不变。因此,图像的背景和文本保持不变(假设它们与“jet”中的颜色明显不同)。由于包只需要一个图像文件,因此避免了获取图像的原始数据所需的时间和精力。
现在,更改他人制作的劣质图像的色彩映射表就像在终端中输入以下内容一样简单:
python fixthejet.py —-input <input file> —-output <output file>
这里有两个例子,展示了该软件包如何将图像从“喷射”色图转换为感知均匀的色图。
示例 1
python fixthejet.py —-input .\images\cube.png —-output .\images\cube_plasma.png —-colormap plasma
输入文件:

输出文件:

示例 2
python fixthejet.py —-input .\images\cone.jpg —-output .\images\cone_inferno.jpg —-colormap inferno
输入文件:

输出文件:

传递颜色图参数来控制 outfile 的颜色图。默认为“viridis”。仅支持 Matplotlib 颜色映射。
--colormap <output colormap>
对使用 fixthejet python 包感兴趣? 下面是下载说明 。
概述
使用像“jet”这样的糟糕的色彩映射表会导致人为的渐变,在某些情况下,这会导致错误的推断。善待你的观众,避免不一致的色彩,如“喷射”、“彩虹”、“光谱”等。
总而言之,
- 如果你正在制作你自己的地图,不要使用“喷射”或者其他感觉上不一致的颜色。
- 如果你想在你的演示中使用别人制作得很差的图形,使用 fixthejet python 包来改变色彩映射表并删除任何人工创建的图案。
本文的一个版本最初出现在 斯坦福数据科学博客 。
如何修复 pandas.parser.CParserError:标记数据时出错
了解在 pandas 中读取 CSV 文件时出现错误的原因以及如何处理该错误

介绍
从 csv 文件导入数据可能是实例化 pandas 数据帧最常用的方式。然而,很多时候这可能有点棘手,尤其是当文件中包含的数据不是预期的形式时。在这些情况下,pandas parser 可能会引发类似下面报告的错误:
pandas.errors.ParserError: Error tokenizing data. C error: Expected 5 fields in line 2, saw 6
在今天的简短指南中,我们将首先讨论为什么会出现这个错误,此外,我们还将讨论一些最终可以帮助您处理它的方法。
重现错误
首先,让我们使用我在本教程中准备的一个小数据集来重现这个错误。
包含不一致格式数据的示例文件— 来源:作者
现在,如果我们尝试使用read_csv读取文件:
import pandas as pddf = pd.read_csv('test.txt')
我们将得到下面的错误
pandas.errors.ParserError: Error tokenizing data. C error: Expected 4 fields in line 4, saw 6
这个错误非常明显,因为它表明在第 4 行而不是 4 行,观察到了 6 个字段(顺便说一下,同样的问题也出现在最后一行)。
默认情况下,read_csv使用逗号(,)作为分隔符,但是很明显,文件中两行的分隔符比预期的多。在这种情况下,预期的数字实际上是 4,因为我们的头(即文件的第一行)包含 4 个用逗号分隔的字段。
手动修复文件
这个问题最明显的解决方案,是通过删除行中给我们带来麻烦的额外分隔符来手动修复数据文件。这实际上是最佳解决方案(假设您已经指定了正确的分隔符、标题等)。调用read_csv函数时)。然而,当您需要处理包含数千行的大文件时,这可能是相当棘手和痛苦的。
指定行结束符
此错误的另一个原因可能与数据中的某些回车符(即'\r’)有关。在某些场合这实际上是通过pandas.to_csv()方法引入的。将 pandas 数据帧写入 CSV 文件时,会在列名中添加一个回车,然后该方法会将后续的列名写入 pandas 数据帧的第一列。因此我们将在第一行中得到不同数量的列。
如果是这种情况,那么您可以在调用read_csv()时使用相应的参数显式地指定'\n' 的行结束符:
import pandas as pd df = pd.read_csv('test.csv', **lineterminator='\n'**)
指定正确的分隔符和标题
该错误也可能与调用read_csv时指定的分隔符和/或头(非)有关。确保传递正确的分隔符和标题。
例如,下面的参数指定;是用于分隔列的分隔符(默认情况下逗号用作分隔符),并且文件不包含任何标题。
import pandas as pddf = pd.read_csv('test.csv', sep=';', header=None)
跳过行
跳过导致错误的行应该是您最后的手段,我个人不鼓励您这样做,但是我想在某些用例中这是可以接受的。
如果是这种情况,那么在调用read_csv函数时,可以通过将error_bad_lines设置为False来实现:
import pandas as pd df = pd.read_csv('test.txt', **error_bad_lines=False**)print(df)
*colA colB colC colD
0 1 A 100 1.0
1 2 B 121 2.1
2 4 D 164 3.1
3 5 E 55 4.5*
正如您从上面的输出中看到的,导致错误的行实际上被跳过了,现在我们可以继续处理我们的 pandas 数据帧了。
最后的想法
在今天的简短指南中,我们讨论了在将 csv 文件读入 pandas 数据帧时,pandas 解析器引发pandas.errors.ParserError: Error tokenizing data的几种情况。
此外,我们展示了如何通过修复数据文件本身的错误或打字错误,或者通过指定适当的行结束符来处理错误。最后,我们还讨论了如何跳过导致错误的行,但是请记住,在大多数情况下,这是应该避免的。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
如何修复值错误:熊猫系列的真值不明确
了解如何处理熊猫最棘手和最常见的错误之一

马特·阿特兹在 Unsplash 上拍摄的照片
介绍
熊猫最常报告的错误之一是
**ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all()**
而且有时处理起来可能相当棘手,尤其是如果你是熊猫库(甚至 Python)的新手。
在今天的文章中,我们将首先了解这个错误出现的原因和时间,并展示如何消除它。具体来说,我们将讨论如何通过使用
- Python 的按位运算符,或
- NumPy 的逻辑运算符方法
理解错误
在进入细节之前,让我们用一个例子重现这个错误,我们也将在本文中引用这个例子来演示一些概念,这些概念将最终帮助我们理解实际的错误以及如何消除它。
让我们开始在 pandas 中创建一个示例数据框架。
import pandas as pddf = pd.DataFrame(
[
(1, 531, True, 12.8),
(2, 126, False, 74.2),
(3, 175, False, 1.1),
(4, 127, True, 45.8),
(5, 543, True, 21.1),
(6, 254, False, 98.1),
],
columns=['colA', 'colB', 'colC', 'colD']
)print(df)
*colA colB colC colD
0 1 531 True 12.8
1 2 126 False 74.2
2 3 175 False 1.1
3 4 127 True 45.8
4 5 543 True 21.1
5 6 254 False 98.1*
现在让我们假设我们想要使用几个逻辑条件来过滤我们的熊猫数据帧。假设我们希望只保留列colB中的值大于200且列colD中的值小于或等于50的行。
df = df[(df['colB'] > 200) and (df['colD'] <= 50)]
上述表达式将失败,并出现以下错误:
File "/usr/local/lib/python3.7/site-packages/pandas/core/generic.py", line 1555, in __nonzero__ self.__class__.__name__ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
出现该错误是因为您使用逻辑运算符(如and、or、not)将多个条件链接在一起,导致了不明确的逻辑,因为对于每个指定的单独条件,返回的结果是基于列的。
换句话说,该错误告诉您,您正试图获取熊猫系列对象的布尔值。为了将它放入一个更简单的上下文中,考虑下面的表达式,它将再次引发这个特定的错误:
>>> import pandas as pd>>> s = pd.Series([1, 2, 3])
>>> s
0 1
1 2
2 3
dtype: int64>>> bool(s)
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-5-68e48e81da14>", line 1, in <module>
bool(s)
File "/usr/local/lib/python3.7/site-packages/pandas/core/generic.py", line 1555, in __nonzero__
self.__class__.__name__
**ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().**
当多个条件被指定并使用逻辑操作符链接在一起时,每个单独的操作数被隐式地转换成一个bool对象,从而导致问题中的错误。
使用按位运算符
现在为了修复这个错误,你的第一个选择是使用 Python 位操作符。
**Operator** | **Meaning**
----------------------
& | Bitwise AND
| | Bitwise OR
~ | Bitwise NOT
^ | Bitwise XOR
现在,表达式应该像预期的那样工作,不会出现ValueError:
**df = df[(df['colB'] > 200) & (df['colD'] <= 50)]**print(df)
*colA colB colC colD
0 1 531 True 12.8
4 5 543 True 21.1*
使用 NumPy 的逻辑运算符
或者,您可以使用 NumPy 的逻辑运算符方法,即按元素计算真值,这样真值就不会有歧义。
Operator | Method
-----------------
AND | [numpy.logical_and](https://numpy.org/doc/stable/reference/generated/numpy.logical_and.html)
OR | [numpy.logical_or](https://numpy.org/doc/stable/reference/generated/numpy.logical_or.html)
NOT | [numpy.logical_not](https://numpy.org/doc/stable/reference/generated/numpy.logical_not.html)
XOR | [numpy.logical_xor](https://numpy.org/doc/stable/reference/generated/numpy.logical_xor.html)
在我们的例子中,numpy.logical_and方法应该可以达到目的:
import numpy as np**df = df[np.logical_and(df['colB'] > 200, df['colD'] <= 50)]**print(df)
colA colB colC colD
*0 1 531 True 12.8
4 5 543 True 21.1*
最后的想法
在今天的指南中,我们讨论了 pandas 和 Python 中最常报告的错误之一,即ValueError: The truth value of a Series is ambiguous。
我们重现了这个错误,试图更好地理解为什么首先会出现这个错误,此外,我们还讨论了如何使用 Python 的按位运算符或 NumPy 的逻辑运算符方法来处理它。
成为会员 阅读媒介上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
你可能也会喜欢
聚焦分割第 1 部分:如何用 Python 进行图像分割
在我的上一篇文章中,我们学习了如何基于斑点检测和连接组件来识别感兴趣的对象。然而,有时我们必须从图像中分离出感兴趣的特定对象。让我们来看看人类制造的最多彩的物品之一:魔方

作者图片
对于这个故事,我们将讨论两个主题,关于如何隔离这个立方体感兴趣的特定对象:阈值和彩色图像分割
阈值处理
第一种方法需要大量的试验和错误步骤,以确定您希望从图像中分离的对象的完美值。对于这种类型的方法,最容易分割的元素之一是灰度图像。让我们用魔方试试吧
#library imports
from skimage.io import imread, imshow
from skimage.color import rgb2graycube = imread('medium/source.jpg')
cube_gray = rgb2gray(cube)
imshow(cube_gray)

作者图片
现在让我们尝试几个阈值,看看我们是否能把立方体从背景中分离出来
import matplotlib.pyplot as plt
thresh_list = [0.2, 0.3, 0.4, 0.5]
fig, ax = plt.subplots(1,4, figsize=(10,10))
for i in range(4):
im = ax[i].imshow(cube_gray < thresh_list[i], cmap='gray')
ax[i].set_title(thresh_list[i])
plt.show()

作者图片
然而,试错是非常麻烦的。自动找到阈值的一种方法是使用 Otsu 的方法。这种方法非常适合我们的魔方图片,因为 Otsu 的方法假设图像有前景和背景。
让我们用下面的代码来试试我们的魔方吧
from skimage.filters import threshold_otsuthresh = threshold_otsu(cube_gray)
cube_binary_otsu2 = cube_gray < thresh
imshow(cube_binary_otsu2)

作者图片
彩色图像分割
由于魔方中有多种颜色,如果我们想要分割图像的特定区域,我们也可以考虑每种颜色。按照这种思路,我们可以通过不同的颜色通道对图像进行分割。让我们首先尝试使用 RGB 颜色空间,并分割红色、绿色和蓝色。
#red
red = cube[:, :, 0] - cube_gray*255
red2 = np.where(red > 0, red, 0)
thresh = threshold_otsu(red2)
red_binary_otsu = red2 > thresh#green
green = cube[:, :, 1] - cube_gray*255
green2 = np.where(green > 0, green, 0)
thresh = threshold_otsu(green2)
green_binary_otsu = green2 > thresh#blue
blue = cube[:, :, 2] - cube_gray*255
blue2 = np.where(blue > 0, blue, 0)
thresh = threshold_otsu(blue2)
blue_binary_otsu = blue2 > threshfig,ax = plt.subplots(1,3,figsize=(10,10))
ax[0].imshow(red_binary_otsu,cmap='gray')
ax[0].set_title('Reds')
ax[1].imshow(green_binary_otsu,cmap='gray')
ax[1].set_title('Greens')
ax[2].imshow(blue_binary_otsu,cmap='gray')
ax[2].set_title('Blues')

作者图片
请注意,还有其他颜色空间可以分割魔方的每种颜色。另一个我们将尝试的是 HSV 颜色空间。HSV 代表色调、饱和度和值,与 RGB 相比,该空间的优势在于,有时不同的色调和色调看起来会更加相似。这使得 HSV 更适合根据颜色隔离图像的特定部分。
我们将使用以下代码隔离绿色
from skimage.color import rgb2hsv
cube_hsv = rgb2hsv(cube)#green mask
lower_mask = cube_hsv[:,:,0] > 0.30
upper_mask = cube_hsv[:,:,0] < 0.40
mask = upper_mask*lower_mask
plt.imshow(mask)

作者图片
正如你从上图中看到的,绿色的色调范围在 30 到 40 之间。通过使用这个值,我们可以生成一个遮罩来标识绿色在图像中的位置。然后,我们可以使用这个遮罩来引用原始图像中的绿色色调,并最终在图像中只显示绿色
red = cube[:,:,0]*mask
green = cube[:,:,1]*mask
blue = cube[:,:,2]*mask
cube_masked = np.dstack((red,green,blue))
imshow(cube_masked)

作者图片
现在你知道了。用几行代码完成的图像分割
对我的工作感兴趣?你可以在我的个人资料中看到更多的故事
https://nico-aguila.medium.com/
关注分割第 2 部分:如何用 Python 进行图像分割


作者图片
嗨!如果你还没有阅读这个关于图像分割的简短系列的第一部分,请在这里阅读。
我们已经讨论了阈值和颜色分割,所以我们的第 2 部分将集中在色度分割,以及图像差异。
色度分割
尽管 HSV 比 RGB 有优势,但仍然会有一些颜色需要我们的眼睛更仔细地观察才能发现明显的差异。其中一个例子就是我们的肤色,不同深浅的棕色可能看起来相同或不同,这取决于个人如何解释颜色差异。对于这种情况,我们可以查看 RG 色度空间,为感兴趣的对象生成遮罩。
在这种情况下,我们将使用这幅画作为参考,并使用以下代码确定 RG 色度

作者图片
#library imports
from skimage.io import imread, imshow
import matplotlib.pyplot as plt
import numpy as nppaint = imread('medium/painting.jpg')paint_R = paint[:,:,0]*1.0/paint.sum(axis=2)
paint_G = paint[:,:,1]*1.0/paint.sum(axis=2)plt.figure(figsize=(5,5))
plt.scatter(paint_R.flatten(),paint_G.flatten())
plt.xlim(0,1)
plt.ylim(0,1)
上面的代码将通过散点图显示红色和绿色空间的分布,如下所示

作者图片
在查看了数据的分布后,我们可以得到颜色值的 2D 直方图
plt.figure(figsize=(5,5))
plt.hist2d(paint_R.flatten(), paint_G.flatten(), bins=100,cmap='binary')
plt.xlim(0,1)
plt.ylim(0,1)

作者图片
从直方图中,我们可以确定哪些颜色构成了我们的绘画。为了确定颜色及其在直方图上的具体位置,我们需要从图像中获取一个参考色块,并获取其相应的 RG 色度。
让我们试着把水体作为补丁
patch = paint[150:200,400:450,:]
imshow(patch)

作者图片
使用以下代码获取 RG 色度
#scatterplot
patch_R = patch[:,:,0]*1.0/patch.sum(axis=2)
patch_G = patch[:,:,1]*1.0/patch.sum(axis=2)plt.figure(figsize=(5,5))
plt.scatter(patch_R.flatten(),patch_G.flatten())
plt.xlim(0,1)
plt.ylim(0,1)#histogram
plt.figure(figsize=(5,5))
plt.hist2d(patch_R.flatten(), patch_G.flatten(), bins=100,cmap='binary')
plt.xlim(0,1)
plt.ylim(0,1)


作者图片
现在我们有了水体的数据分布,让我们使用 RG 色度来尝试两种类型的分割:参数和非参数分割。
- 参数分割
参数分割需要根据参考面片和图像参数变换每个元素。为了在我们的绘画图像中做到这一点,我们将首先使用前面生成的遮罩来拟合高斯概率分布
#Parametric Magic
std_patch_R = np.std(patch_R.flatten())
mean_patch_R = np.mean(patch_R.flatten())std_patch_G = np.std(patch_G.flatten())
mean_patch_G = np.mean(patch_G.flatten())#Making the gaussian work
def gaussian(p,mean,std):
return np.exp(-(p-mean)**2/(2*std**2))*(1/(std*((2*np.pi)**0.5)))
现在让我们检查一下我们用上面的代码制作的补丁的分布情况
x = np.linspace(0,1)
y = gaussian(x,mean_patch_R,std_patch_R)
plt.plot(x,y)

作者图片
让我们在 RG 色度空间中测试我们的数据
#Visualization of R space and G space#R space
r_test = np.tile(np.linspace(0,1,64),(64,1))
plt.imshow(r_test)#G space
g_test = r_test.transpose()
plt.imshow(g_test)


作者图片
#Test sample R and G space into the gaussian distribution with the generated patch#R space with patch
test_R = gaussian(r_test,mean_patch_R,std_patch_R)
plt.title('R Space and patch')
plt.imshow(test_R)#G space with patch
test_G = gaussian(g_test,mean_patch_G,std_patch_G)
plt.title('G Space and patch')
plt.imshow(test_G)


作者图片
prob_test=test_R * test_G
plt.imshow(prob_test)

作者图片
上面的图像显示,通过仅使用 R 坐标,补丁的颜色有可能是绘画的一部分。让我们试着只用 R 色度空间来遮盖我们的画
prob_R = gaussian(paint_R,mean_patch_R,std_patch_R)
plt.imshow(prob_R)

作者图片
现在让我们使用 G 色度空间来尝试一下
prob_G = gaussian(paint_G,mean_patch_G,std_patch_G)
plt.imshow(prob_G)

作者图片
将 R 和 G 空间相乘得到以下输出
prob=prob_R * prob_G
plt.imshow(prob)

作者图片
组合图像现在表明,所拍摄的颜色实际上有可能是我们之前拍摄的参考色块的一部分。我们现在可以通过用一组给定的概率值生成一个新的掩模来正确地分割图像
prob_list = [0.2, 0.4, 0.6, 0.8]
fig, ax = plt.subplots(1,4, figsize=(10,10))
for i in range(4):
ax[i].imshow(prob > prob_list[i], cmap='gray')
ax[i].set_title(prob_list[i])
plt.show()

作者图片
在我们的原始 RGB 图片上整合蒙版可以隔离水体。对于本例,我们将使用 0.8 作为阈值
mask = prob > 0.8
red = paint[:,:,0]*mask
green = paint[:,:,1]*mask
blue = paint[:,:,2]*mask
paint_masked = np.dstack((red,green,blue))
imshow(paint_masked)

作者图片
2。非参数分割
对于感兴趣区域不容易被我们生成的 2D 高斯函数近似的情况,可以用非参数方法来代替。其工作原理是使用绘画中的 2D 直方图,并使用直方图反投影,用参考面片的计算直方图来掩盖图像。
既然已经说了,我们可以简单地用 cv2 做所有这些!这里有几行代码可以实现这一点。然而对于这个例子,我们将只使用一维直方图,考虑来自 HSV 颜色空间的色调
import cv2 as cv#histogram and backprojection
def Hist_and_Backproj(val):
bins = val
histSize = max(bins, 2)
ranges = [0, 180] # hue_range
hist = cv.calcHist([hue], [0], None, [histSize], ranges, accumulate=False)
cv.normalize(hist, hist, alpha=0, beta=255, norm_type=cv.NORM_MINMAX)
backproj = cv.calcBackProject([hue], [0], hist, ranges, scale=1)
cv.imshow('BackProj', backproj)
w = 400
h = 400
bin_w = int(round(w / histSize))
histImg = np.zeros((h, w, 3), dtype=np.uint8)
for i in range(bins):
cv.rectangle(histImg, (i*bin_w, h), ( (i+1)*bin_w, h - int(np.round( hist[i]*h/255.0 )) ), (0, 0, 255), cv.FILLED)
cv.imshow('Histogram', histImg)#getting image and transforming to hsv
src = cv.imread('medium/painting.jpg')
hsv = cv.cvtColor(src, cv.COLOR_BGR2HSV)
ch = (0, 0)
hue = np.empty(hsv.shape, hsv.dtype)#using only 1-D histogram (Hue)
cv.mixChannels([hsv], [hue], ch)#creating trackbar to change bin values
window_image = 'Source image'
cv.namedWindow(window_image)
bins = 25
cv.createTrackbar('* Hue bins: ', window_image, bins, 180, Hist_and_Backproj )
Hist_and_Backproj(bins)#show image and allow user to close the program
cv.imshow(window_image, src)
cv.waitKey()

值设置为 25。作者图片

值设置为 100。作者图片
图像差分
这是一个有趣的话题,尤其是对孩子们来说。图像差异是指当我们不看色彩空间时,我们想要确定我们的视频或图像中的变化或运动,这很像孩子们在看两张几乎相同的图片时玩的“找出差异”游戏。
image1 = imread('medium/19a.jpg')
image2 = imread('medium/19b.jpg')fig, ax = plt.subplots(1,2,dpi=100)
ax[0].imshow(image1)
ax[1].imshow(image2)

你能看出区别吗?作者图片
进行图像差分的一种方法是简单地将两幅图像转换成灰度,并从字面上减去两幅图像。结果输出给出了两幅图像之间的变化
#grayscale
from skimage.color import rgb2grayimage1_gray = rgb2gray(image1)
image2_gray = rgb2gray(image2)fig, ax = plt.subplots(1,2,dpi=100)
ax[0].imshow(image1_gray,cmap='gray')
ax[1].imshow(image2_gray,cmap='gray')

作者图片
现在让我们spot the difference
diff = image1_gray - image2_gray
imshow(diff)

作者图片
现在你知道了!色度分割和图像差分
对我的工作感兴趣?你可以在我的个人资料中看到更多的故事
https://nico-aguila.medium.com/
固定效应回归—简单解释
为什么我们在测量因果效应时需要固定效应回归的直观观点。

我目前正在学习因果推理和相应的建模技术。本着边解释边学习的精神,我决定写一篇博客来解释固定效应回归模型及其在 Python 中的实现。该博客将包含三个部分:
- 什么是固定效应模型,我们为什么要使用它?
- 固定效应模型是如何工作的
- 在 python 中使用固定效果模型的示例
与试图做出预测不同,经济学家更感兴趣的是回答一个不同的问题——一个特定变量(感兴趣的变量,添加或不添加功能)和结果变量(销售额)之间的因果关系是什么。
什么是“因果关系”,它与“相关性”有什么不同虽然我听说了很多关于“相关性并不意味着因果关系”,但直到最近我才真正注意到这一点。
为了解释什么是“因果关系/结果”,我认为最好参考一下达纳·麦肯齐(Dana Mackenzie)和朱迪亚·珀尔(Judea Pearl)所著的《原因之书》中的“因果关系阶梯”。
在书中,作者描述了 因果关系的三个层次 :
- 联想:如果我看到了什么会怎么样。在数学中, P(观察 Y |观察 X)
- 干预:如果我做了某事会发生什么。数学上, P(观察 Y |做 X)
- 反事实:如果我做了/没做某事会发生什么。 P(观察 Y|如果我没有做 X 会怎样)
因此,因果效应是我们做了某件事和我们没有做某件事(反事实)的结果差异
我们为什么关心这个?这是我第一次遇到这个问题时的疑问之一。嗯,事实证明我们确实关心它,因为当我们试图在现实世界中做出决策(例如,为应用程序添加新功能)时,企业不仅知道明天会发生什么(预测或预报),他们还想知道如果我们今天添加一个新功能,我们是否会增加下周、下个月和明年的参与度。
回答这个问题的直观方法是运行 A/B 测试(看到该功能的人的收入(治疗组)和没有看到该功能的人的收入(对照组))。不幸的是,实验有时成本太高,或者不道德/不合法。
你可能也会想,为什么我不能在训练完我的模型之后,直接使用我感兴趣的变量的估计量/系数。如果你这样做,你可能会遇到遗漏变量偏差,这是我们的估计量的偏差(例如,看不看特征的系数),当一些重要的和未观察到的变量(例如,用户特征)在我们的模型中未被控制时。
这些变量很重要,因为它们既与我们的兴趣变量(更有可能看到新功能)相关,也与我们的结果变量(花费更多)相关。所以忽略它们会给我们的估计量带来偏差。
在我们开始解释固定效应模型如何工作之前,让我们先介绍两个术语。
固定效应回归,顾名思义,暗示某事物是固定不变的。当我们假设一些特征(例如,用户特征,这里我们先假设)在一些变量(例如,时间或地理位置)上是恒定的。我们可以使用固定效应模型来避免遗漏变量偏差。
面板数据:也称为纵向数据,用于跨多个时间段(如年或月)的多个实体(如地理位置、州)。这是固定效应回归的关键因素。
它是如何工作的?
让我们戴上数学帽子,写一些公式。

贬低固定效应回归
对于上面的公式(3),我们可以在数据中丢弃虚拟变量,然后运行 OLS 回归来得到结果。但是当实体列表变得很大时(例如,产品名称(SKU/阿辛),在这种情况下可能有数千个实体),回归可能变得不可能或非常乏味。
为了解决这个问题,我们可以使用一种叫做“实体贬低 OLS”的东西。这里的实体贬低实际上就是从每个观察值中减去其实体平均值,以从我们的结果变量中去掉那些不可观察的实体独特但时间不变的变量影响。

在 python 中使用固定效果模型的示例
我将使用著名的啤酒税数据来说明 python 中的步骤,如下所示:

结果表明,啤酒税系数为负,具有统计学意义。我们可以解读为,啤酒税增加 1 美元将导致每万人减少 0.66,这个数字是巨大的!这可能是由于其他被忽略的变量随着时间的推移而变化,从而引入了偏差。
这篇博客通过我们为什么需要它,我们如何制定它,以及一个玩具例子,介绍了通过固定效应避免遗漏变量偏差来测量因果效应的通用建模技术。我希望你喜欢阅读。
面向数据科学家的定点 DSP
了解如何使用 C/C++和 Arm 的 CMSIS-DSP 库在 Python 中创建 DSP 管道,并将其转换为在基于 Arm Cortex-M 的 MCU 上运行。
作者 : 桑德普·米斯特里,亨利·伍德库克代表 Arm 软件开发团队
介绍
当在音频系统中应用机器学习(ML)时,通常使用数字信号处理(DSP)技术将输入音频信号转换成 2D“图像”,从而可以使用计算机视觉技术对音频进行分类。现实世界中的例子包括音频或语音识别,以及关键词识别。
本指南将使用 Python 和 NumPy 代码示例向您介绍这些系统中使用的 DSP 技术。一旦您熟悉了这些 DSP 技术,我们将介绍如何使用 Python 中的 Arm 的 CMSIS-DSP 库来使用定点数学执行相同的操作。
最后,我们将演示如何用 C 语言创建一个等效的流水线,以便将其部署到基于 Arm Cortex-M 的微控制器(MCU)上。在基于 Arm Cortex-M 的系统上使用定点数学可以大幅减少内存使用,同时提高运行时性能!
本指南的 Jupyter 笔记本版本也可以在 GitHub 上找到,也可以使用 Google Colab 访问。
目录:
音频频谱图
在这本笔记本中,我们将在 NumPy 和 CMSIS-DSP 中开发一个音频声谱图管道。这是用于音频数据的常见预处理管道。原始音频样本被转换成音频信号的可视表示,其显示频率随时间的变化。它通常被描绘成 2D 的形象。
关于 spectrograms 更深入的解释,可以看看关于音频识别的 TensorFlow 教程。
为了将音频信号转换到频域,使用了快速傅立叶变换(FFT)。这将按时间将幅度表示的音频信号转换到频域,因此您可以了解信号中包含的频率。然而,当对整个音频信号执行 FFT 时,您将丢失该音频信号的时域信息,为了抵消这一点,我们将音频分解为单独的片段。
光谱图步骤
创建光谱图可分为以下步骤:
- 音频信号被分解成称为“窗口”的更短的片段。这意味着当我们稍后应用 FFT 时,我们仍然保留一些时间信息,因为我们知道每个窗口出现的时间点。将音频信号分割成多个窗口时,窗口之间通常会有一些重叠,以帮助保持输出更加连续。
- 然后将窗口函数应用于每个窗口。将我们的信号分解成重叠的窗口会给我们留下音频信号的不连续性,这将不能准确地表示真实世界的音频信号。为了减少这种影响,窗口函数将通过将窗口乘以 0 和 1 之间的平滑对称曲线来平滑每个窗口的幅度边缘。
- 然后用 FFT 将每个窗口转换到频域。因为 FFT 产生复数输出,所以从该输出中取出绝对值以保留幅度信息,但移除复数。
- 最后,创建一个称为频谱图的 2D 阵列,其大小为(窗口数、FFT 仓)。
我们选择了一些示例音频输入及其音频频谱图,如下所示:

Python 中的音频频谱图
现在你已经对什么是音频声谱图有了一个大概的了解,我们将通过 Python 和 Numpy 从一个预先录制的 wave 文件中创建一个声谱图。
安装 Python 模块
您需要使用pip安装 NumPy 、 Matplotlib 、 SciPy 和 requests Python 模块:
pip install numpy scipy matplotlib requests
下载样本音频文件
我们将使用来自“ESC-50:环境声音分类数据集”GitHub repo 的“敲门”.wav文件作为笔记本中 DSP 管道的输入信号。您可以使用 Python 的requests库从 GitHub 下载.wav文件:
从样本音频文件中读取数据
SciPy 的[scipy.io.wavfile.read(...)](https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.wavfile.read.html) API 现在可以用来从.wav文件中读取音频样本。
.wav文件的采样率为 44.1 kHz,这意味着每 1 秒钟的音频由 44100 个样本表示。由于 44.1 kHz 采样率包含的分辨率超过了我们的需求,我们将使用 SciPy 的[scipy.signal.resample(...)](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.resample.html) API 将音频数据的采样率从 44.1 kHz 降低到 16 kHz,以减少分析中使用的样本数量。
现在我们已经从.wav文件中读取了音频样本,让我们使用 Matplotlib 绘制一段时间内的音频信号:

您也可以在您的电脑上下载并收听 1–103995-A-30 . wav 文件。
根据整个音频信号的图表,播放声音,我们知道开始时有大约 1 秒钟的声音,然后是寂静。让我们放大并使用 Matplotlib 仅绘制前 1 秒的音频信号,以便更仔细地观察:

开窗术
现在我们可以将音频样本分割成重叠的窗口。通常选择 2 的幂,例如 16、32、64、128、256、512、1024 或 2048 作为窗口大小。我们将使用大小为 256 的窗口,并在此时跨过音频信号 128 个样本。

当前窗口在整个蓝色信号之上以绿色突出显示。你可以看到第一个窗口是从 0 到 256,第二个窗口是从 128 到 384 (128 + 256),第三个窗口是从 256 到 512,第四个窗口是从 384 到 640。
的窗口总数。wav 文件可以计算如下:
number_of_windows = (len(audio_samples) - window_size) // step_size
窗口函数和汉宁窗口
当处理连续信号(如音频)时,在应用 FFT 变换之前会应用一个窗口函数,以便音频片段的边缘更平滑。窗口函数是(通常)范围在(0–1)之间的函数,可应用于窗口,如下所示:
𝑦 = 𝑤𝑖𝑛𝑑𝑜𝑤_𝑓𝑢𝑛𝑐𝑡𝑖𝑜𝑛 × 𝑤𝑖𝑛𝑑𝑜𝑤
Hanning 窗口是最常见的窗口函数之一(也是本例中使用的函数)。 NumPy 有一个内置的方法来计算任意窗口长度的汉宁窗口:
**import** numpy **as** nphanning_window = np.hanning(window_size)
让我们使用 Matplotlib 绘制汉宁窗口:

现在,汉宁窗口可以应用于第一音频信号窗口,使用:
window_1 **=** audio_samples[0:window_size]processed_window_1 **=** hanning_window ***** window_1
然后,我们可以使用 Matplotlib 绘制第一个窗口和已处理的窗口

可以看到,在整个窗口周期内,经过处理的窗口幅度从未超过汉宁窗口的值。
让我们扩展我们的图表,通过前几个窗口进行循环。

快速傅里叶转换(同 fast Fourier transform)
对于每个已处理的窗口,可以使用 NumPy 的[np.fft.rfft(...)](https://numpy.org/doc/stable/reference/generated/numpy.fft.rfft.html) API 计算 FFT,并使用[np.absolute(...)](https://numpy.org/doc/stable/reference/generated/numpy.absolute.html)获取 FFT 的绝对值:
*# Calculate the FFT.* fft_1 **=** np.fft.rfft(processed_window_1)*# Take the absolute value.* fft_bins_1 **=** np.absolute(fft_1)
然后,我们可以使用 Matplotlib 绘制 FFT 频段。

让我们绘制前 4 个窗口随时间变化的 FFT 图,以便了解音频信号的频率成分如何随时间变化:

光谱图
我们可以创建一个单独的音频信号频域 2D 图,作为热图,也称为频谱图,而不是每个窗口周期随时间变化的单独 FFT 图。该频谱图在 x 轴上显示时间,在 y 轴上显示频率,最后用颜色显示振幅。
让我们以重叠的步长和窗口大小遍历所有样本,计算信号随时间变化的频率,以显示为频谱图。这里我们计算 1 秒钟音频中的窗口数量。
现在我们已经计算了音频信号的频谱图,让我们绘制它:

从频谱图中,我们可以清楚地看到每个爆震的 5 个感兴趣的区域,频率低于 4000 Hz 的更普遍。
让我们放大声谱图的下半部分,仔细看看:

我们再画一张图,但在声谱图上方加上时域中的信号。这样,我们可以看到信号幅度和频率计数与时间的相关性。

概述
让我们回顾一下迄今为止我们所取得的成就:
- 使用请求库从 GitHub 下载了一个敲门声音的. wav 文件。
- 使用 SciPy 库从 44.1 kHz 的. wav 文件中读入音频样本,并对它们进行重新采样,以获得 16 kHz 的采样速率。
- 理解什么是窗口,为什么需要窗口函数,比如汉宁窗口。
- 学习了如何在特定窗口周期内创建音频信号的 FFT。
- 通过在一段时间内跨越音频信号、应用汉宁窗口并对每个窗口周期使用 FFT 函数来创建音频信号的频谱图表示。
CMSIS-DSP 音频频谱图
现在您已经了解了如何使用 NumPy 创建音频频谱图,我们可以使用带有定点数学的 CMSIS-DSP Python 包装器做同样的事情。
定点数学和 CMSIS-DSP 简介
与浮点运算不同,定点数学数字以较低的精度表示实数,因为它们有固定的位数来表示小数点前后的数字。比如我们有一个 1.15 定点格式的 16 位数,这个 16 位的值可以代表-1 到 1 之间的一个值,固定精度为1 / 2^15 = 0.000030517578125。
Arm Cortex-M 处理器在基于整数的计算方面比浮点运算更快。Arm Cortex-M4、Cortex-M7 和更高版本的处理器支持单指令多数据(SIMD)指令,允许它们一次对多个值执行相同的指令。CMSIS-DSP 库利用这些 SIMD 指令实现更高性能的 DSP 处理。
Arm 的 CMSIS-DSP 库包含针对 Arm Cortex-M 处理器常见 DSP 操作的高度优化实现。
CMSIS-DSP Python 包装器
一般来说,在 Arm Cortex-M 设备上使用 C 或 C++来使用 CMSIS-DSP 库。然而, CMSIS-DSP 团队已经创建了一个 Python 包装器来利用 Python 中的这些 DSP 功能。
该库包含针对 Arm Cortex-M 处理器的高度优化的 DSP 功能实现和针对非 Arm 处理器的通用 C 实现。如果您在 PC(可能基于 x86)上使用 Arm CMSIS-DSP Python 包装器,则从输入和输出角度来看,这些函数的行为将与它们在 Arm 处理器上的行为相同,但是您可能看不到运行时性能的提高。
让我们继续安装 CMSIS-DSP Python 包装器:
pip install git+[https://github.com/ARM-software/CMSIS_5.git@5.8.0#egg=CMSISDSP\&subdirectory=CMSIS/DSP/PythonWrapper](https://github.com/ARM-software/CMSIS_5.git@5.8.0-rc#egg=CMSISDSP\&subdirectory=CMSIS/DSP/PythonWrapper)
量化输入信号
我们可以使用 CMSIS-DSP 的[arm_float_to_q15(..,)](https://arm-software.github.io/CMSIS_5/DSP/html/group__float__to__x.html#gac7696e64963e5051ebb950c88c6ba186)函数将浮点值转换为 16 位定点(Q15)值:
**from** cmsisdsp **import** arm_float_to_q15audio_samples_q15 = arm_float_to_q15(audio_samples)
现在,让我们将定点值与原始数值一起绘制成图表:

您可以看到信号的形状与使用 NumPy 创建的信号相似,但是 Y 轴上的值的范围是从-32768 到 32767,而不是从 0 到 1。
CMSIS-DSP 中的汉宁窗口
CMSIS-DSP 没有为特定窗口大小创建汉宁窗口的内置功能。然而,我们可以利用内置的[arm_cos_f32(...)](https://arm-software.github.io/CMSIS_5/DSP/html/group__cos.html#gace15287f9c64b9b4084d1c797d4c49d8)和arm_float_to_q15(...) API 来创建一个定点汉宁窗口。让我们用汉恩函数的公式来做这个:

现在让我们使用 Matplotlib 绘制 Q15 Hanning 窗口和 NumPy Hanning 窗口:

您可以看到它的形状与使用 NumPy 创建的形状相似,但是值的范围是从 0 到 32767,而不是从 0 到 1。
要像在 NumPy 中那样应用汉宁窗口,我们可以使用[arm_mult_q15(...)](https://arm-software.github.io/CMSIS_5/DSP/html/group__BasicMult.html#gaeeda8cdc2c7e79c8a26e905342a0bb17)乘法函数将两个长度相等的向量相乘。
现在让我们来看看在 q15 格式中应用 Hanning 窗口后的第一个窗口:

让我们将它与 NumPy 值并排绘制成图表:

采用 CMSIS-DSP 的 FFT
CMSIS-DSP 为各种数据类型提供了许多 FFT 功能:q15、q31 和 f32。在本例中,我们将使用实数 FFT 函数。要使用 CMSIS-DSP 的 Q15 RFFT 函数,我们首先需要创建一个[arm_rfft_instance_q15](https://arm-software.github.io/CMSIS_5/DSP/html/structarm__rfft__instance__q15.html)实例,并用[arm_rfft_init_q15(...)](https://arm-software.github.io/CMSIS_5/DSP/html/group__RealFFT.html#ga053450cc600a55410ba5b5605e96245d)函数初始化它。之后,过程类似于 NumPy,你可以使用[arm_rfft_q15(...)](https://arm-software.github.io/CMSIS_5/DSP/html/group__RealFFT.html#ga00e615f5db21736ad5b27fb6146f3fc5)函数来计算 FFT 和[arm_cmplx_mag_q15(...)](https://arm-software.github.io/CMSIS_5/DSP/html/group__cmplx__mag.html#ga0488e185f4631ac029b02f1759b287cf)来计算 FFT 的幅度。
我们现在可以用 Matplotlib 绘制 Q15 定点值的图形:

现在让我们将fft_bins_1_q15 Q15 的值转换为浮点值,这样我们就可以将该值与 NumPy 计算的值进行比较。
当使用 256 的 RFFT 长度时,arm_rfft_q15(...)功能的输出格式将是9.7(而不是1.15)。[arm_cmplx_mag_q15(...)](https://arm-software.github.io/CMSIS_5/DSP/html/group__cmplx__mag.html#ga0488e185f4631ac029b02f1759b287cf)功能的文档说明输入值为1.15格式,输出为2.14格式。因此,如果我们将一个9.7格式的数字传递给arm_cmplx_mag_q15(...),输出将会有一个10.6的格式——这意味着它的值的范围将会从-512到511。
我们可以通过使用[arm_q15_to_float(...)](https://arm-software.github.io/CMSIS_5/DSP/html/group__q15__to__x.html#ga5a75381e7d63ea3a3a315344615281cf)函数将其从 Q15 转换为浮点数并乘以512 ( 2^9)来将10.6数转换为浮点值:
**from** cmsisdsp **import** arm_q15_to_float# Let's rescale them and compare the two
fft_bins_1_q15_scaled = arm_q15_to_float(fft_bins_1_q15) * 512
我们可以叠加它们,看看它们有多接近:

正如我们从上面看到的,两条管道产生了视觉上非常相似的特征。
虽然使用定点函数会丢失一些信息,但我们设法计算出了类似的形状,并在相同的频率下显示出峰值。定点函数未能计算出的频率(在 2000 年的右侧),都具有非常低的振幅,表明信息损失最小。
CMSIS-DSP 谱图
最后,我们需要像处理 NumPy 一样将所有这些放在一起。
现在让我们用 Matplotlib 绘制输入信号和 Q15 频谱图:

最后将 Q15 谱图与 NumPy 版本进行比较:

概述
正如我们所见,CMSIS-DSP 管道类似于 NumPy 管道。让我们回顾一下我们为创建它所做的工作:
- 使用
arm_float_to_q15功能将音频样本转换为 Q15 格式。 - 使用汉恩函数公式通过
arm_cos_f32和arm_float_to_q15函数计算汉宁窗口。 - 学习了如何使用
arm_mult_q15函数乘以相同长度的向量。 - 了解如何使用
arm_rfft_instance_q15、arm_rfft_init_q15和arm_rfft_q15函数在 CMSIS-DSP 中计算 Q15 FFT。 - 通过在一段时间内跨越音频信号、应用汉宁窗口并对每个窗口周期使用 FFT 函数来创建音频信号的频谱图表示。
不同音频声音的频谱图示例
现在让我们来看看 ESC-50 存储库中不同音频文件的一些不同频谱图。

将 CMSIS-DSP 代码从 Python 移植到 C
现在,我们已经从上一节中对如何使用 Python 中的各种 CMSIS-DSP API 有了一个大致的了解,我们可以开始将这些 API 映射到 C 语言,以便在基于 Cortex-M 的系统上运行。
包含
第一步是在.c文件的顶部添加一个#include <arm_math.h>:
#include <arm_math.h>
常数
然后我们可以为窗口和步长定义一些常量变量:
const int WINDOW_SIZE **=** 256;
const int STEP_SIZE **=** 128;
输入信号
可以声明一个全局数组变量来存储输入信号:
q15_t input_q15[WINDOW_SIZE];
创建光谱的输入信号可存储在input_q15变量中。
出于测试目的,我们将其设为频率为 440 Hz、采样频率为 16 kHz 的固定正弦波。
for (int i = 0; i < WINDOW_SIZE; i++) {
float32_t f = sin((2 * PI * 440) / 16000 * i);
arm_float_to_q15(&f, &input_q15[i], 1);
}
汉宁窗户
对于 Hanning 窗口函数,必须声明一个全局数组变量来存储窗口函数值:
q15_t hanning_window_q15[WINDOW_SIZE];
然后我们可以创建一个 C 函数,在运行时初始化hanning_window_q15数组:
void hanning_window_init_q15(q15_t* hanning_window_q15, size_t size) {
for (size_t i = 0; i < size; i++) {
*// calculate the Hanning Window value for i as a float32_t*
float32_t f = 0.5 * (1.0 - arm_cos_f32(2 * PI * i / size ));
*// convert value for index i from float32_t to q15_t and
// store in window at position i*
arm_float_to_q15(&f, &hanning_window_q15[i], 1);
}
}
我们将需要另一个变量来存储输入信号上应用的汉宁窗口的值:
q15_t processed_window_q15[WINDOW_SIZE];
现在,我们可以对输入信号应用汉宁窗口:
*// equivalent to:
// processed_window_q15 = input_q15 * hanning_window_q15*arm_mult_q15(input_q15, hanning_window_q15, processed_window_q15,
WINDOW_SIZE);
快速傅里叶转换(同 fast Fourier transform)
变量
我们需要 FFT 实例和输出的全局变量:
arm_rfft_instance_q15 S_q15;*// this is twice the size because each FFT output has a real and
// imaginary part*
q15_t fft_q15[WINDOW_SIZE ***** 2];*// this is half the size of WINDOW_SIZE becase we just need the
// magnitude from the first half of the FFT output*
q15_t fft_mag_q15[WINDOW_SIZE **/** 2];
初始化
我们需要调用arm_rfft_init_q15来初始化 Q15 RFFT 实例:
arm_rfft_init_q15(&S_q15, WINDOW_SIZE, 0, 1);
执行 FFT
执行 FFT 并计算 FFT 的输出幅度现在可以通过下式完成:
arm_rfft_q15(&S_q15, processed_window_q15, fft_q15);arm_cmplx_mag_q15(fft_q15, fft_mag_q15, WINDOW_SIZE / 2);
将所有东西连接在一起,就像一幅 Arduino 草图
性能基准
现在,让我们在以下 Arduino 或 Arduino 兼容板上对上面的 Arduino 草图进行基准测试:
我们已经创建了一个等效的草图,它使用 32 位浮点而不是定点来与上面的定点草图进行比较。这两张草图都可以在 GitHub 上找到:
RAM 使用情况
当我们使用 16 位 Q15 而不是 32 位浮点时,我们应该会看到 DSP 运算所需的缓冲器占用一半的空间。
我们目前的缓冲包括:
因此,对于WINDOW_SIZE = 256,我们预计:
- F32: 22 x 256 = 5632 字节
- Q15: 11 x 256 = 2816 字节
这说明与 F32 使用浮点相比,Q15 使用定点需要一半的 RAM。
如果我们编译我们的草图,我们会得到下面的“全局变量使用”度量。
来自 Arduino 的值与我们期望节省的内存量完全匹配。
运行时速度
现在,让我们将两张基准测试草图上传到评估板上,看看计算单个输入窗口的 FFT 仓需要多长时间:
Arduino Nano 33 物联网板基于 Arm Cortex-M0+ CPU,未配备 FPU(浮点单元),使用 16 位定点 DSP 流水线完成流水线的速度比 32 位浮点版本快 11 倍。基于 Arm Cortex-M4F CPU 并配备 FPU 的 Arduino Nano 33 BLE 性能提升了 37%。最后,基于配备 FPU 的 Arm Cortex-M7 CPU 的 Teensy 4.0 的性能提高了 26%。
结论
本指南概述了将音频信号转换为声谱图的 DSP 流水线,声谱图可以与计算机视觉技术相结合,对音频信号进行分类。我们已经解释了什么是声谱图,以及如何使用以下 DSP 操作用 Python 和 NumPy 从. wav 文件创建声谱图:开窗、汉宁窗和 FFT。之后,您了解了定点数学,以及如何利用 CMSIS-DSP Python 包装器通过 16 位定点运算创建等效频谱图,同时精度损失最小。然后,我们介绍了如何将 CMSIS-DSP 管道从 Python 移植到 C,以便在基于 Arm Cortex-M 的设备上运行。
在我们的基准测试中,当使用定点 16 位操作而不是 32 位浮点操作时,DSP 流水线所需的全局缓冲区需要的内存减少了 50%。当使用定点 16 位操作而不是浮点操作时,Cortex-M0+(无 FPU)的速度提高了 11 倍。当使用定点 16 位运算而不是浮点运算时,具有内置 FPU 的 Cortex-M4F 和 Cortex-M7F 系统的速度分别提高了 37%和 26%。这些进步令人印象深刻。使用定点还可以节省一个转换步骤,当从模拟麦克风(使用 ADC)或数字麦克风读取音频输入值时,这些值(通常)会存储为 16 位值。
欲了解更多来自 Arm 软件开发团队的博客、指南、资源、视频和笔记本,请访问:
了解更多信息
在即将到来的 Arm 开发峰会上提升使用 tinyML 的技能并获得实践经验,这是一个在 10 月 19 日至 21 日之间举行的为期 3 天的虚拟活动。该活动包括针对真实嵌入式设备的 tinyML 计算机视觉研讨会,以及利用基于 Arm Cortex-M 的 MCU 构建大词汇量语音控制。我们希望在那里见到你!
人工智能系统中的固定偏差
元学习和创建人工智能伦理框架的反直觉方法如何对抗偏见蔓延

鸣谢:Zapp2Photo/Shutterstock
人工智能模型与它们接受训练的算法和数据一样好。当一个 AI 系统失败时,通常是由于三个因素;1)算法被错误地训练,2)系统的训练数据中存在偏差,或者 3)在模型建立过程中存在开发者偏差。本文的重点是训练数据中的偏差和模型开发人员直接编码到 AI 系统中的偏差。

作者图片
开发者偏见
“我认为今天,人工智能社区总体上有一种自我选择的偏见,因为建造这种系统的人仍然主要是白人、年轻人和男性。我认为,人们已经认识到,我们需要超越它,但现实是,我们还没有做到这一点。”——格雷迪·布奇,IBM 首席沃森科学官
开发人员偏见是数据团队缺乏多样性的产物。有社会责任感的组织认识到需要改变这种动态,并持续努力让代表性不足的群体参与进来,以增加其数据团队的多样性。这一努力需要时间。与此同时,解决人工智能系统继承的默认价值系统的另一种方法是,技术行业为人工智能采用一个通用的道德框架。
一个人工智能伦理模型框架
人工智能尚未建立道德模型框架的一个重要原因是,对于应该使用谁的价值观和道德体系来建立一个道德模型框架,还没有达成共识。
那么为什么不让模型建立自己的伦理框架呢?这种反直觉的想法正是 IBM 的 Murray Campbell 通过使用逆向强化学习提出的。逆向强化学习涉及让系统学习人们在各种情况下的行为,以便它可以找出人们重视什么,让模型做出符合我们基本道德原则的决定。这个解决方案是违反直觉的,但是它也给了模型和我们一起更新信念系统的能力。在一个不断变化的世界里,这应该是所有人工智能系统的特征。
偏见是如何潜入人工智能模型构建的
监督学习算法依靠人类来做标记,这是模型建立过程中的一个步骤,可能会将人类偏见引入系统。还可能有一个主题专家沿途通知学习系统。该主题专家在提供意见时也在输入他们自己的偏见。
一种可以从人工智能系统构建过程中消除这些偏见注入步骤的技术是无监督学习。无监督学习使用未标记的数据来训练系统,几乎没有人工干预,通过与环境交互来学习环境。这大大减少了偏见渗入模型的机会。
我们离开发纯无监督学习还很远,但有更新的学习方法,即混合模型,位于无监督和有监督学习之间的某个位置。这些模型需要的数据量较少,有助于解决代表性数据集较少的问题。此外,这些模型需要更少的标记和人工干预,从而降低了数据预处理阶段出现偏差的可能性。无监督学习的一种方法是元学习。
修复有偏数据集的元学习
元学习是机器学习的一个子领域,深度学习模型可以用较少的数据进行有效的训练。这样做的方式是让机器学习一项复杂的任务,使用它用来学习一项任务的相同原则,并将它应用于其他任务。这种形式的泛化允许学习模型更快地获得新技能。
一次性元学习技术是这种建模方法的一个很好的例子。一次性学习可以应用于像人脸识别这样的任务,我们有很多类,但每个类的样本很少。许多人脸识别数据集都是如此,在这些数据集里,白人的数量过多。在这一步中,设计了一个深度神经网络,它能够从训练数据集推广到看不见的数据集。一次性分类类似于普通分类,但它不使用数据样本,而是使用整个数据集。该模型在不同的学习任务/数据集上进行训练,然后在一系列训练任务和未知数据上进行优化,以获得最佳性能。

作者图片
展望未来
修正无意的偏见需要提高认识和数据收集技术。为了实现更好的数据完整性,组织必须自己手动收集数据,以确保机器接收的数据集确实是多样化和包容性的。收集更多的数据可能是不可行的,而且成本高昂。组织还必须继续努力,为他们的数据科学团队带来更多的多样性和代表性。
无监督学习和元学习是两种可以解决在数据收集、特征标记和模型开发阶段悄悄进入人工智能系统的偏见的技术。此外,一个通用的人工智能伦理框架是重要的一步,可以确保指导人工智能系统建设的价值观是保护和促进整个社会的价值观。
在新冠肺炎疫情的生活告诉我们,偏见是一个我们需要毫无疑问和迫切解决的问题。我们的优先事项已经改变。生命、时间和环境重塑了我们的伦理和价值观,我们的人工智能系统应该得到发展,以便它们能够根据我们不断变化的社会价值观更新信仰系统。
格雷迪·布奇在他的 Ted 演讲、不要害怕超级智能 AI 中呼应了这一观点:
“我们正处在与机器共同进化的不可思议的旅程中。我们今天的人类不是那时的人类。”
多么美好的未来等待着我们。
使用正则表达式修复常见 CSV 错误
实践教程
一个强大的、未被充分利用的工具,可以修复许多常见的数据问题。

正则表达式是一个经常被忽视的强大工具。
在这篇文章中,我将介绍 CSV 文件的几个常见问题,并使用正则表达式来修复它们。
作为一名数据科学家,您通常会处理自己没有生成的大型数据集。因此,从外部数据提供程序接收数据的情况很容易出错。您无法直接控制传输前的数据导出。当这些错误发生时,有几个选项可用—其中一个是使用正则表达式。
有一个关于在软件开发中使用正则表达式的笑话是这样的:
你有一个可以从正则表达式中获益的问题,现在你有两个问题。
但是正则表达式并没有想象的那么复杂。本质上,你试图完成的是描述一个模式。Regex 包在许多语言中都有很好的定义,语法也相对一致。
然而,在这篇文章中,我不会展示具体的代码块。相反,我将展示在 Notepad++中使用正则表达式。Notepad++是一个非常轻量级的编辑器。因此,在编辑器中而不是直接在代码中试验正则表达式,可以快速测试所创建的表达式。
Notepad++可以很好地处理 CSV 文件,最多可以处理一百万条记录。但是,当文件较大时,更好的选择是联系数据提供商,从源头解决问题。
许多在线正则表达式工具可以帮助构建表达式,但是来自编辑器的直接反馈可能更有益。此外,对于文件中的某些实例,您创建的模式经常会中断,如果不上传整个文件,您可能在在线正则表达式工具中看不到这一点。
编码

文件编码(作者照片)
CSV 文件的第一个问题是文件中的奇怪字符或奇怪的换行符。虽然由于有许多不同的格式,这些问题没有万能的解决方案,但一个常见的解决方案是在 UTF-8 中打开所有内容。虽然这并不总能解决你的问题,但如果你坚持这样做,那么你就能逐渐理解你的 UTF-8 解决方案。
可视化
谈论可视化 CSV 文件似乎有点奇怪。然而,仅仅看一下数据通常就能清楚地显示出你所面临的问题。然而,默认情况下,许多编辑器会忽略 GUI 中的一些字符。有时候,像额外空间这样的小事也可能是问题的根源。因此,在处理文件错误时,确保您可以看到文件中的每个符号,并确认您所看到的是您所期望的。
要在 Notepad++中显示所有文件符号,请转到视图>显示符号>显示所有字符。

显示所有文件符号(作者照片)
改变日期格式
大多数文件读取函数都有解析日期的选项。然而,这些通常假设日期遵循相同的格式。当日期是相同的格式时,确定该格式是一个相对简单的过程。
但是,如果你曾经在现实世界中工作过,你就会知道每个人写日期的方式都不一样。每个人都有自己的理由,这些理由对他们来说是有意义的。争论通常是打一场失败的仗。
但是,如果您的文件有多种日期时间格式,您可以用正则表达式更新这些格式。

多种日期时间格式(图片由作者提供)
这里需要注意一些事情:
- 使用括号捕获组。
- 正则表达式的替换部分中的引用组。第一组使用\1,第二组使用\2,依此类推。
目的是将日期部分作为一个组来捕获,并将这些组重新排列成与其余日期一致的单一格式。
我知道没人问,但最好的日期格式是' yyyy-mm-dd ',如果你需要时间,那么' yyyy-mm-dd hh:mm:ss '。这种格式的 DateTime 的小数位数正在严格减少。每个元素都是分开的,使用前导零,时间与日期分开。易于机读且逻辑清晰。最好的格式。
如果你在日期字段中添加月份作为缩写文本,你就是一个怪物,停止。
文本限定词
文本是最灵活的数据格式之一。也正因为这种灵活性,才成为很多问题的源头。文本通常可以包含文件中使用的列分隔符。
由于这个问题,添加了文本限定符。文本限定符(通常是引号之类的字符)指定要跟随的文本。文件读取器将忽略任何列分隔符,直到遇到第二个文本限定符。当这些限定符不存在时,很难在以后有效地添加文本限定符。
最好的选择是尝试获取文本限定符。也许您可以要求用文本限定符提取另一个数据。
这是我提到的第一个选项的原因是文本太灵活了。下面的替换表达式要求相邻的列具有一致的、结构良好的模式。如果没有一致的模式,就无法保证剩余的字符不是文本的一部分。文字是一场噩梦。请求文本限定符。
如果获取文本限定符不是一个选项,并且数据的其余部分有一些结构,那么有一些选项。示例显示文本中多了一个逗号,这是这种类型中最常见的问题。
下面的模式利用了文本和相邻列的几个方面。
- 在文本中,逗号后面通常有一个空格。因此,无论其他文本如何,该模式都很容易被捕获。
- 可能有多个逗号。带逗号的文本模式与*字符匹配零次或多次。
- 相邻的列以一致的模式匹配。
- 括号内捕获的组用\1 指定。对于多个组,使用\2、\3 等。

文本中的文件分隔符(作者图片)
中线断开
当发生多个数据导出时,行中间有换行符的 CSV 可能是一个常见问题。例如,这种错误经常发生在没有文本限定词的数据导出过程中,以及在允许文本内换行的初始数据插补系统中。
最简单的情况是当这个换行符只在一行中时。虽然通常更容易确定断行的原因(开发人员通常会添加检查来计算一行中的分隔符数量以找到行),但自动修复这些问题要困难得多。

带有换行符的文本(作者提供图片)
当由于文本的原因一行中只有一个断点时,可以用负的前瞻自动处理。本质上否定的前视是匹配模式的正则表达式,但仅当后面没有另一个模式时。
第一部分在 regex 中很容易识别。匹配换行符。
第二部分,消极的前瞻,更为复杂。要寻找的模式是您在下一个换行符开始时所期望的。例如,如果每一行都以日期“yyyy-mm-dd”开头,后跟一个数字,则您要捕获的负数模式是\r\n(?!\d\d\d\d-\d\d-\d\d,),并替换为第一组\1 的内容。
这里需要注意的几件事:
- 前瞻是用字符“?”指定的后跟“!”字符(对于负前视)或=字符(对于正前视)
- 指定了整个日期格式模式。捕捉任何日期都需要这种模式,并且必须加以推广。
- 括号内捕获的组用\1 指定。对于多个组,使用\2、\3 等。
- 替换操作会删除用“\n”捕获的换行符。然而,在 UTF 8 中,换行符既是换行符又是回车符' \r '。在记事本文件中显示为 CRLF。
特别敏锐的读者会注意到匹配模式中的额外逗号。匹配第一个组后,添加一个逗号来强制第一列只有这种格式。匹配前几列将显著提高这种模式匹配的可靠性,但这是有代价的。如果问题文本字段位于 CSV 的第一列,那么这种模式就不再可行。但是假设前几列有一个清晰、一致的模式。在这种情况下,您应该匹配其中的每一项,因为文本中的分隔符不可能在多列中具有相同的模式。
当第一列是文件的问题列时,替换更易于管理。

带有换行符的文本(作者提供图片)
这种模式的基础是 CSV 中的一些列具有格式良好的设计。确保 CSV 中至少有适当格式的一种方法是在第一列中要求 ID 或日期。这个 ID 确保有一些模式作为模式匹配的基础。
对于文本字段中的多个换行符,最简单的解决方案是重复该模式,直到找不到匹配为止。虽然这不是最优雅的解决方案,但当中断次数未知时,会有一个问题。使用未知数量的分隔符,需要未知数量的组来成功地将文本组合成一行。因此,最简单的解决方法是用替换重复该模式。
未转义字符
另一个常见的问题是带有特殊字符的文本没有被转义。当非转义字符是文本限定符时,这个问题就更成问题了。
下面的正则表达式看起来相当复杂,但是每个组件都相对简单。首先,目标是捕获引号,引号是未转义的,而不是文本限定符。这里的第二个方面意味着忽略前面的分隔符和后面的分隔符。

未转义字符(作者照片)
这里的模式使用了一些不同的正则表达式组件。
- 后面的否定眼神,用‘指定?
- The second group uses exceptions to handle the valid text qualifiers with the trailing separator. This group captures the quote to be escaped then the following character.
- The replacement places the literal escape character (specified with the double escape) and the content of the second group.
- For the stand-alone double quotes, this pattern will need to be run twice since the unescaped second quote is placed back in the first replacement.
结论
正则表达式是一个经常被忽视的强大工具。然而,它可以在几乎所有的编辑器和编程语言中使用。由于大多数数据科学工作都是数据争论,正则表达式成为数据科学家武器库中的一个重要工具。
尽管有奇怪的语法和挑战性的学习曲线,正则表达式只是一个模式匹配工具。如果你很难找到正确的表达方式,大声说出你想要捕捉的模式,包括例外和条件,这是一个很好的开始。
此外,数据清理和结构问题通常可以用一个正则表达式来解决。当您不仅考虑畸形模式,而且考虑围绕畸形模式的正确模式时,这些表达式变得越来越强大。不幸的是,人们通常不使用文件中存在的已知模式,而只关注畸形。这就是为什么表达式不能捕捉所有的情况,或者更糟;他们抓住你不想要的案子。
最终理解正则表达式是值得投入时间的。
如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。
如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。
https://zjwarnes.medium.com/membership
修复你的机器学习模型的故障点
一步一步的指导你发现和理解你的机器学习模型中的问题,并修复它们!
机器学习模型可以用来构建很酷的应用程序和演示。但是在现实世界中可靠地部署机器学习系统仍然是一个挑战,因为当意想不到的数据出现时,它们经常以意想不到的方式失败。
例如,对 MNIST 手写数据集中的数字进行分类是最基本的机器学习任务之一,经常被用作机器学习入门课程中“已解决问题”的示例。然而,当数字以不寻常的方式旋转时,即使达到 99%准确率的机器学习分类器也可能做出不正确的预测:

一个在 MNIST 数据集上训练到 99%以上准确率的卷积神经网络仍然预测“1”,当它遇到来自测试集的异常旋转的“2”时(试试 www.gradio.app
这篇博客的目的是帮助你发现这些数据点(我们将称之为“硬数据”),这些数据点在训练过程中导致机器学习失败,这样你就不会让你的模型出现各种各样的裂缝,这些裂缝可能会变成更大的裂缝,因为在你的模型部署后,数据分布会继续变化。我们将介绍修复模型故障点的三个重要步骤:
- 识别硬数据
- 可视化硬数据&理解它破坏模型的原因
- 固定模型
所以让我们开始吧!
0.设置:加载您的模型
我们将首先在 TensorFlow 中加载一个简单的 MNIST 模型,我们将在本文的其余部分使用它。在我们的例子中,我们将从一个 S3 桶中加载一个预先训练好的模型,当然,您可以很容易地自己训练一个 MNIST 模型或者使用一个完全不同的模型。
1.识别硬数据
训练完模型后,神经网络通常会在训练数据集上达到非常高的精度,因此,要确定潜在的故障点,您需要使用模型以前没有见过的数据。在我们的例子中,我们将使用 MNIST 测试集来识别硬数据。
为了以一种有用的方式识别硬数据,我们应该考虑两个因素:
- 难度:模型最不准确的数据点是什么?我们将研究神经网络的可信度,以此作为代理。
- 多样性:我们如何挑选一组多样化的硬数据点,以便我们检查一组有代表性的硬数据?有许多方法可以使用它,但是我们将着眼于最简单的:确保我们收集的样本包括来自 10 个标签类的一些例子
下面的代码执行这些步骤,首先对测试数据运行模型,然后识别 20 个硬数据点,即每个数字中最难的 2 个。你会注意到,我们将这些例子都保存为图片,这在下一步中很重要。
2.可视化硬数据&理解为什么它打破了模型
在您识别出硬数据之后,现在是时候动手了,并真正理解为什么这些数据点会破坏您的模型。为此,使用像Gradio(https://github.com/gradio-app/gradio)这样的可视化库是有帮助的,它可以帮助你“看到”你的硬数据点以及它们根据模型的预测。
要使用 Gradio 库,我们必须编写一个包装模型的函数。在下面的代码中,那就是recognize_digit()。我们还定义了我们想要创建什么样的 UI(画板 → 标签),然后我们可以传入一个examples列表,这是上一步中的文件名列表。下面是完整的代码:
这将产生以下 GUI,它加载了示例,并使我能够理解为什么不同的示例会破坏模型:

3.固定模型
现在,进入最重要的部分!修复模型需要您彻底理解为什么不同的硬数据点会破坏模型。根据原因,可能需要不同的步骤来使模型更加健壮。让我们将此应用到我们为 MNIST 模型确定的硬数据中,并集体讨论我们需要做些什么来修正这个模型。
3A。添加数据增强和
您的模型可能损坏的第一个原因是,如果它看到输入数据以不寻常的方式转换,如下面的旋转“2”示例。这通常可以通过数据扩充(在训练期间综合转换你的输入数据)很容易地解决。这里有一个数据扩充的指南。

边注:可以使用 Gradio 库的内置特性旋转样本,观察预测的差异。通过使用一个图像→标签接口,我们能够在我们的样本上尝试许多不同的转换(更多细节参见 colab 笔记本)。以下是我们将样品旋转 30°回到正确方向时的结果,证实旋转可能是罪魁祸首:

3B。获取更多的稀有样本
您的模型可能失败的第二个原因是因为它在训练期间不常看到的稀有数据。考虑下面的“5 ”,在形成“5”顶部的水平杆和弯曲钻头的顶部之间只有很小的空间。因为像这样的训练例子不多,所以 MNIST 模型没有意识到它是一个“5”。这种问题很难通过数据扩充来解决——解决方案是获取更多像这样的样本。

3C。平衡等级和
我注意到仔细阅读硬数据的一件事是,不管数字实际上是什么,模型很少预测“5”。例如,下面的数字是模糊的——它可能是“5”或“0”或“9”,但是模型确信它是“0”而不是“5”(真正的标签)。这可能反映了训练数据的不平等分布,也许该模型在训练期间遇到“5”的频率比其他数字低。事实上,尽管在训练数据中有很多“5 ”,但它们是训练数据中最不常见的类别。这使得模型通常不太可能预测“5”要解决这个问题,你可以尝试平衡你的训练设置。

3D。删除坏数据
有时,硬数据被错误分类仅仅是因为它是一个坏数据点。数据集通常由人来注释,人会犯错误。如果您确定一个数据点被贴错了标签(就像我相信下面的数据点一样,根据其分配的标签,据称是“0”),并且不代表您的部署数据,那么您应该将它从您的测试集中删除,以便您的评估指标更符合实际。

在这篇文章中,我概述了一个捕捉模型故障点并尽早修复它们的过程。尽管具体细节会根据您拥有的模型类型而有所不同,但这种识别、理解和修复 硬点的一般方法将会改进您的数据集,并生成一个健壮的模型,它不仅具有更高的测试准确性,而且在现实世界中部署时可能会更加可靠。祝你好运!
注:你可以在这个 Colab 笔记本上一次性运行以上所有代码:https://Colab . research . Google . com/drive/1 orsrgccovzxcdxf 8 GL 3 XM 8 j2yzngr 0y?usp =分享
生产中的 Flask:最小的 Web APIs
将 API 投入生产可能是一个令人困惑的前景。这篇文章给你在生产中使用 Flask 的技巧和模板。

蒂姆·福斯特在 Unsplash 上的照片
烧瓶是什么?
如果你在云软件领域(或与之相邻的领域)工作,并且熟悉 Python,你很可能会遇到Flask——这是一个优秀的、最小化的“micro”web 框架,十年来一直是 Python web 社区的核心。据报道,它已经进入了大量的应用程序,包括 LinkedIn 和 Pinterest 平台,以及无数其他商业、私人和研究项目。这种受欢迎程度确保了它有一个充满活力的扩展、文档和教程生态系统。
那么为什么又发了一篇 Flask 的博文呢?在过去八年左右的时间里,我已经使用 Flask 进行了几十个个人和专业项目,我学到了很多东西。然而,很难找到简单、高质量的指南来指导如何开始使用“生产就绪”的 Flask 应用程序。我想我已经把我对一个简单、最小的 Flask“生产就绪”应用程序可能是什么样子的一些想法放在一起了——一个(不全面的)列表,列出了我希望这些年来已经知道的一些事情。如果你对这篇文章中的建议有什么改进的建议,一定要联系我,让我知道。
此外,在这篇文章中,我特别关注为提供 API 作为 web 服务而开发的 Flask 应用程序。这是许多软件专业人员的基本用例,也越来越与许多机器学习实践者相关。另外,对于软件世界的新来者来说,这可能有点令人困惑。因此,这篇文章的目的是给你一个简单但可靠的“生产就绪”的 Flask 服务模板,并分享我提供的结构的一些基本原理。我也给出了几个基本步骤来将模板项目部署到 Google Cloud Run。让我们开始吧。
一点术语…
和技术领域一样,很容易被 API 语言绊倒。在我们研究模板项目本身之前,有必要快速回顾一下几个更重要的术语,以便有所了解。
如果你想直接跳到代码,那就这样吧:
https://github.com/markdouthwaite/minimal-flask-api
我们所说的“生产就绪”是什么意思?
软件社区使用“生产就绪”这个词作为一个近乎护身符的不言自明的术语。然而,有一点不清楚特别是是什么使得一个软件产品化,特别是对于这个领域的新来者,或许也包括技术水平较低的团队。那么当我们说一个软件是“生产就绪”的时候,意味着什么(对于一个软件专业人员来说)?这有点主观,但我认为这些是关键因素:
- 软件满足其需求。你的软件做了它应该做的事情,并且它做得足够好来产生商业价值。
- 该软件已经过充分测试。有一个(最好是)自动测试套件可以有效地测试你的代码。
- 软件有充分的文档记录。有足够的文档让另一个从业者拿起软件并开始使用它。
- 该软件“架构良好”。它是可扩展的、可维护的和可伸缩的。这包括确保软件包含优雅的错误处理。
- 该软件已经过同行评审。您的代码已经得到了同行的评审和签署。
显然,我不能帮助你解决其中的一些问题:我不能确定你的软件是否满足你的需求,我不能检查你的测试套件是否合理,你的应用程序是否架构良好,你的文档是否足够。但是,我可以让您从一个项目模板开始,该模板指示您可能如何着手构建您的工作以满足其中的每一项,相关代码和信息可以/应该位于何处,并且模板代码为您提供了一个初始的脚手架,您可以使用它来使您的项目达到该标准。这就是我这篇文章的目的。
“API”和“服务”之间有什么区别?
您可能只听说过 web 服务上下文中使用的术语“API ”,在这种情况下,您可能认为它们是同义词。这种观点不太准确。
- API—API 是一个“应用程序编程接口”,定义了一组其他应用程序可以访问和利用的功能。这可以通过不同的媒介公开,例如,包括通过 web 和作为语言、包和库的公共接口。
- 服务 —服务是通过 web 公开的资源。换句话说,它是一个可以通过网络互动的实体。这个实体可以是函数的集合,或者只是一个静态文件。实际上,这意味着 web 服务也是API,但它不是唯一的API。
换句话说,web 服务公开了一个 API,但并不是所有的 API 都通过 web 公开。如果你写了一个 Python 包,可以说这个包也提供了一个 API。
路由和端点有什么区别?
这是另一个微妙的技术区别。如果你过去浏览过 Flask 应用程序,毫无疑问你会看到route 装饰器,也许会听到一般的“路线”的说法。如果你读过很多关于 web APIs 的书,你可能也听说过“端点”的说法。有时这些术语看起来几乎是同义的。那么它们是什么意思呢?
- 路由 —路由就是 URL。这是定位资源的一种方式(例如,资源是某种功能或信息)。例如,这可能是
localhost:8080/users。 - 端点 —端点是通信信道的一个特定端。重要的是,一条路由可能有多个端点。例如,
GET localhost:8080/users和DELETE localhost:8080/users将是单条路线localhost:8080/users的两个不同端点。这对于你如何选择设计你的 API 有着重要的影响。
术语到此为止。让我们来看看代码!
输入模板
在这篇文章的其余部分,我将参考 GitHub 模板库,我把它放在一起展示我认为是一个最小生产就绪 Flask API 的一些基本元素。您可以在这里找到存储库:
https://github.com/markdouthwaite/minimal-flask-api
要进行设置,您可以直接从这个模板创建一个新的存储库,或者您可以将存储库分支到您自己的帐户,然后从那里克隆它——任何适合您的方式!最后,如果你想用 Google Cloud Run 部署你的 API,一定要检查一下google-cloud-run分支。都准备好了吗?太好了!
项目结构
下一个问题:你刚刚拉下了什么?以下是您正在查看的项目结构的几个最重要方面的概要:
bin-正如您可能期望的,这个目录是项目的任何直接可执行文件的存储位置。默认情况下,这里有一个名为run.sh的文件。该文件包含 bash 命令,该命令将初始化 Gunicorn 服务器并显示您的 Flask 应用程序。如果这还不太有意义,不要担心,我们稍后会介绍它!docs-这个目录应该存储任何关于你的 API 的文档。你会在这个目录中看到一个名为swagger.yaml的文件。它存储了 API 的标准规范。实际上,这可以让其他团队和服务更容易地使用你的 API,并且你应该考虑为你构建的每个API制作一个。在本文中,我们不会深入探讨 Swagger 或 OpenAPI 标准,但是你可以在 Swagger 网站上找到更多信息。requirements-这个目录存储你的经典 Pythonrequirements.txt类型的文件。注意,这里实际上有两个文件:common.txt和develop.txt。这有助于将部署 API 时需要的依赖项(基本的依赖项存储在common.txt中)与开发 API 时需要的依赖项(这些存储在develop.txt中,通常是测试工具和样式 / 林挺实用程序)分开。换句话说,当开发你的 API 时,你需要安装common.txt和develop.txt,但是当部署你的 API 时,你可以只安装common.txt。**- 这个目录存储了你的 API 的源代码。文件
app.py设置你的 Flask 应用程序并创建你的应用程序的‘路线’。我们稍后将更详细地讨论这个问题。您还会看到errors.py文件。它存储了一个 Flask Blueprint ,用于处理 API 代码中的错误。我们很快会看一下蓝图。最后,handlers目录应该存储您的模型处理程序。换句话说,这是您提供加载和查询模型的函数的地方。同样,我们很快会再看一遍。 Dockerfile-该文件包含特定 Docker 图像的定义。换句话说,它包含构建 Docker 的命令,Docker 可以作为一个独立的。如果这对您来说没有多大意义,您可以简单地将其视为定义您希望代码运行的特定环境的一种方式。我不打算在这里介绍 Docker 的基础知识,所以如果您对 Docker 和容器技术不熟悉,请务必查看 Docker 文档,另外,如果您感兴趣,YouTube 上还有一些很棒的入门教程。如果您遵循本文末尾的部署步骤,对 Docker 的理解将会派上用场。Makefile-这个文件提供了一个简单的机制来为你的项目运行有用的命令。我们将在这篇文章的后面触及其中的一些。tests——这个目录存储了你的测试套件的文件,包括一个展示如何使用来测试你的 Flask 应用的基本例子,以及一个最小的[locustfile](https://locust.io/),你也可以使用它来加载测试你的 API。wsgi.py——这个文件是你的 API 的 WSGI 入口点。稍后会有更多的介绍。
有道理吗?太好了!让我们再深入一点。
了解 Flask
虽然 Flask 是一个紧凑的框架,但仍然有一些重要的概念可以真正帮助您构建更干净、更具可伸缩性的应用程序,因此非常值得更好地理解其中的一些概念。这样做可能是拥有一个整洁的、高性能的 API 和一个杂乱无章、杂乱无章的 API 之间的区别。我还想强调的是,这远远不是 Flask 的全部内容,但是我认为这是您可能会发现对基本 API 特别有用的几个领域。
申请途径
值得从头开始。Flask(以及一般的 web 服务)中最基本的概念之一是 Flask 中的一个route的概念。这些被设计用作装饰符,指示当调用给定的route时应该执行的特定函数。我不打算在这里深入装饰者的技术细节,但是如果你不熟悉他们,很值得阅读一下那里的一些资料更详细地解释他们做什么。
看看下面的例子:
**import flask
app = flask.Flask(__name__) @app.route("/")
def home():
return "You are home"**
这段代码创建了一个只有一个route的 Flask 应用程序。该路线告诉应用程序在调用/路线时执行home功能。Flask route decorator 可以用来指示和解包 URL 参数。例如,下面是如何定义一个新的路由来从 URL 中提取一个name参数:
**@app.route("/users/<name>")
def user(name):
return f"Hey, {name}!"**
如果您要调用路由/user/Jane,这个处理程序将返回Hey, Jane!。正如您可能看到的,这些是任何 web 服务的构建块,通过扩展,理解route decorator 的功能将使您在构建 API 的道路上走得更好。
应用蓝图
Flask 框架中的另一个关键概念是 蓝图 的想法。蓝图很棒。它们可以用来划分你的 API。例如,假设您想要创建一个 API 来管理您的在线商店。你需要一些关键的功能。三组明显的功能是处理用户、产品和结账过程的功能。如上所述,您可以使用上述route装饰器提供的功能轻松捕捉这种行为。您可以在app.py中为以下内容创建单独的路线:

图 1:您可能期望在购物 API 上看到的示例路线。在你的 Flask 应用程序中,这些将是单独的“标准”路线。作者图片
然而——虽然是一个虚构的例子——这个 API 中显然有一些定义良好的功能子集。您可以将这些子集捕获为独立的 Python 模块,每个模块为该子集定义一个不同的蓝图。将此功能划分到蓝图中的一种方法如下:

图 2:一个购物 API 的路径示例,其中颜色表示功能被分组到一个单独的蓝图中,并注入到 Flask 应用程序中。图片作者。
然后你可以在你的“核心”应用程序中注册这些蓝图。注册蓝图会立即将蓝图中定义的所有路线添加到“父”Flask 应用程序中。这样做的好处是,你可以快速添加和删除 Flask 应用程序功能的全部子集,并独立开发子集。正如您可能想象的那样,当您开发更复杂的 API 时,这非常有用。
要查看蓝图的实际例子,请看模板库中的api/error.py文件。这是蓝图的一个超级实用的用例。在这种情况下,这个蓝图定义了一个简单的模式来优雅地处理 API 中未被捕获的错误。它定义了一种特殊类型的装饰器,error_handler,它将有效地处理应用程序中的错误。同样,我不打算详细说明装饰器是如何工作的,但只要说这个特殊的装饰器可以捕捉你的应用程序中未处理的Exception就够了。在这种情况下,它返回一个股票字符串响应和一个错误代码(500) 。
该蓝图已注册在主应用程序中,代码行为:
**app.register_blueprint(errors)**
这将在您的蓝图中定义的错误处理行为注入到您的应用程序中。换句话说,你的整个应用现在可以利用这个蓝图来捕捉和处理任何地方可能出现的未被捕捉的错误。这将适用于您应用程序中的所有路线。酷吧。
为什么要用 Gunicorn?
有一件事有时会让初入 Flask 世界的人感到困惑,那就是需要使用符合 WSGI 的 web 服务器来包装 Flask 应用程序。你不应该使用捆绑的 Flask 开发服务器部署 Flask 应用。在实践中,这个开发服务器可以方便地快速测试您的应用程序,但是它不是为高要求的应用程序设计的,因此当您将它推到生产环境中时,它不太可能很好地发挥作用。
相反,Flask 是设计的用于其他符合 WSGI 的 web 服务器。对于这篇文章,(在模板中)我使用了 Gunicorn 。这是一个坚实的工具。然而,这不是唯一的选择,例如,还有twisted和uWSGI。如果您想了解关于您的部署选项的更多信息,Flask 提供了一些关于如何准备这些选项的极好的提示:
在模板存储库中,Gunicorn 与 Flask 的配置由两个文件处理。第一个是bin/run.sh bash 脚本。如果您检查这个文件,您将看到一个命令。该命令将 Gunicorn 服务器指向您的 Flask 应用程序,在0.0.0.0:8080(即在您的本地主机上的端口 8080)公开应用程序,将您的应用程序设置为在debug级别登录(即记录所有内容),并使用 4 个工作进程初始化服务器(即,将被初始化以处理对您的 API 的请求的工作进程的数量,以及因此可以并行处理的请求的数量)。后一个参数(workers)通常最好设置为运行 API 的服务器上可用内核的数量。
第二个感兴趣的文件是wsgi.py Python 模块,那是关于什么的?
WSGI 和 WSGI 入口点
wsgi.py通常被称为 WSGI 入口点。你会问,WSGI 是什么?它代表“web 服务器网关接口”,简而言之,它是定义 Web 服务器如何与 Python 应用程序交互的规范。
在这个示例项目中,它只是一个让您的 web 服务器(在这个示例中是:Gunicorn)挂钩到您的应用程序的文件。每当您发现自己在使用常见的 Python web 框架(例如,包括 Django )时,您将会看到并且可能需要提供类似的 WSGI 入口点。
在这个例子中,我遵循了一个相对标准的惯例,将这个文件与“核心”Flask 应用程序的定义分开。然而,如果你愿意的话,你可以把你所有的代码放在一个文件中(例如在 T8 中)。
获取设置
此时,您可能已经准备好启动服务器了。很公平。首先,您需要安装这个项目的开发需求。为此,在项目目录的顶层,您应该运行:
**make develop**
这将安装测试和样式工具,以及运行应用程序所需的核心 Python 包。安装这些程序后,您可以通过运行以下命令来启动服务器:
这将启动你的 Gunicorn 服务器(暴露你的 Flask 应用)。在继续之前,确保您已经安装了[curl](https://curl.se/)(一个用于与您的 API 交互的命令行工具)您可以通过运行(可能在一个单独的终端窗口中)来检查您的服务器是否已经成功启动:
**curl localhost:8080/health**
你应该得到回应OK。这个/health路径提供了一个简单的方法来检查你的 API 是否仍然响应。一些云服务要求这些路由存在,一般来说,设置它们是一个好主意,以便您自己监控(和保持理智!).显然,示例项目附带了一个。您现在可以拨打:
**curl localhost:8080**
您应该会看到带有默认处理程序的响应Hello, world!。您有一个运行在本地机器上的最小 Flask API。很好。现在,如果你想做一些更复杂的事情呢?
修改您的 API
如你所料,许多“真实世界”的 web APIs 至少会比这复杂一点点。那么,如何着手扩展您的应用程序呢?有几种方法,但这里有一些基本的建议。
创建新的路线和处理程序
显而易见的选择是简单地创建更多的route。例如,看看下面的片段:
**from flask import request # ... existing routes and handlers @app.route("/custom", methods=["POST"])
def custom():
"""A handler that receives a POST request with a JSON payload, and may or may not return a friendly JSON-formatted response!""" payload = request.get_json() if payload.get("say_hello"):
output = jsonify({"message": "Hello!"})
else:
output = jsonify({"message": "..."}) return output**
这个代码片段将/custom路由添加到您的应用程序中,并将其设置为只接受使用[POST](https://en.wikipedia.org/wiki/POST_(HTTP)) 方法发出的请求。在这种情况下,custom函数试图从发送给服务器的request中提取 JSON 数据。这意味着它也期望在请求中发送 JSON 格式的主体。最后,它也返回 JSON 格式的响应。
如果添加上面的代码片段(记住附加的 import 语句!)添加到您的api/app.py文件中,并重新启动您的服务器,然后您可以使用:
**curl -X POST 'localhost:8080/custom' --data-raw '{"say_hello": true}' --header 'Content-Type: application/json'**
您应该会看到这样的回应:
**{ "message": "Hello!" }**
正如您所看到的,通过这一小小的添加,您已经向 API 添加了一个稍微复杂一些的功能。您还可以想象如何通过添加更多的路由和相关功能来构建越来越复杂的 API。然而,对于一个大型应用程序(即 API),以这种方式添加大量的路由会变得很麻烦。幸运的是,这就是 Flask 的蓝图(前面讨论过的)出现的地方。
划分您的应用程序
是时候让 API 变得更复杂一些了。假设您想要添加一大堆与操作用户数据相关的功能。正如前面所讨论的,您可以创建一个单独的蓝图来捕获这个功能。
要了解如何操作,在api目录中创建一个名为users.py的新 Python 文件。在此文件中,复制以下代码片段:
**from flask import Blueprint, Response users = Blueprint("users", __name__, url_prefix="/users") @users.route("/list")
def index():
return Response(f"Looks like there are no registered users!") @users.route("/purchases")
def history():
return Response(f"Looks like there are no purchases!")**
在这个蓝图中,您将向您的蓝图中添加两条新路线(/list和/purchases)。重要的是,Blueprint初始化中的url_prefix参数表示该蓝图的路线应安装到前缀。具体来说,这意味着蓝图注册后调用应用程序时,路线/list和/purchases将在/users/list和/users/purchases可用。要注册蓝图,您可以在您的api/app.py文件中包含以下代码:
**# ... existing imports
from .users import users app = Flask(__name__) # you don't need this twice.
# ... register other blueprints
app.register_blueprint(users) # ... 'core' handlers**
当您现在重新启动 Gunicorn 服务器时,您将能够调用:
**curl localhost:8080/users/list**
并查看这种情况下的响应Looks like there are no registered users!。实际上,users模块中定义的所有路线现在都已经添加到您的 API 中了。希望您能看到如何将这种模式应用于 API 中的每个主要功能子集,这反过来会帮助您开发一个良好划分的、可维护的 web 服务。
更新您的测试套件
正如您前面看到的,tests目录包含了您的 API 的测试代码。我已经草拟了一个用和构建的超级基本测试套件。前者是一个很好的测试框架,你可以用它来测试你的 API 的功能性属性(比如你的 API 实现了所需的功能),而后者用于测试你的 API 的非功能性属性(比如你的 API 可以处理预期的流量)。
在以后的文章中,我将深入探讨 web APIs 的locust和pytest,所以我将厚着脸皮跳过它们。然而,如果你想启动locust并同时使用基于网络的用户界面,你可以运行:
**make load-test**
类似地,您可以使用以下代码运行模板pytest测试套件:
**make test**
当然,如果您像在 API 的前面部分中那样更新路由,您需要确保更新测试套件以捕捉这些变化。事实上,如果你做得很好,并且遵循一个测试驱动开发(TDD) 工作流程,你应该在编写任何核心 API 代码的扩展之前,将测试添加到tests/test_api.py(以及你添加的任何其他文件)。建立tests/test_api.py文件是为了(希望)让你的 API 编写测试变得更容易一些。
部署到 Google 云运行
至此,我们已经触及了项目中的大多数关键文件和相关概念,让我们进行最后一步,将最小的 API 部署为一个活动的 web 服务。如果你想继续这最后一步,确保你已经检查了模板的google-cloud-run分支,并且(如果你还没有)在 Google Cloud 注册一个免费的账户。在写这篇文章的时候,你可以获得 300 美元的注册费用,这比你在这里做任何事情的费用都要多。如果你不打算在 Google Cloud 上做更多的工作,请记住禁用你的帐户。
**https://cloud.google.com/free
还要注意,在继续之前,您需要确保您的 API 在本地运行,因此,如果您在继续操作时对模板项目中的文件进行了任何更改,请确保在继续操作之前检查这些更改是否有效。
准备好了吗?开始部署吧。
了解你的Dockerfile
在部署到 Cloud Run 之前,您需要构建和推送一个 Docker 映像到 Google Cloud。这意味着理解你将在项目中看到的神秘Dockerfile中发生的事情是有用的。当您试图部署服务时,熟悉容器技术肯定会对您有所帮助。
然而,这篇文章不是关于 Docker 的,我不会在这里详述。我将假定您对 Docker 和Dockerfile s 有一些基本的了解。如果您不熟悉 Docker,我鼓励您去看看网上有很多很棒的资源。不言而喻:在继续之前,确保你已经为你的系统下载了 Docker。
https://docs.docker.com/get-started/overview/
现在,回到你的Dockerfile本身。首先,您需要指定构建映像的基础映像。这体现在下面一行中:
FROM python:3.7.8-slim
这告诉 Docker 您希望使用官方的 Python 3.7.8 映像作为新映像的基础。换句话说,这建立了一个标准的 Python 3.7.8 环境。-slim后缀告诉 Docker 使用该图像的‘slimline’版本。这消除了“完整的”Python 3.7.8 映像中包含的一些“混乱”。实际上,这有助于保持较小的图像大小,当 API 投入使用时,这有助于降低成本和提高性能。
值得注意的是,如果你正在创建一个依赖非常少(包括系统依赖)的 API,你应该考虑使用alpine基础映像。这是额外的。然而,基于alpine的图像可能会让新用户有点头疼:alpine图像通常不会随通用编译器和其他工具一起发布。如果你不需要它们,这很好,但是如果你不确定如何将这些工具添加到图像中,这可能会很麻烦。例如,许多数字库依赖于特定的编译器和没有在alpine映像中发布的专用库。
接下来,是时候安装依赖项了。这由以下代码行处理:
COPY requirements/common.txt requirements/common.txt RUN pip install -U pip && pip install -r requirements/common.txt
这个代码片段将系统环境中的requirements/common.txt文件复制到映像中。然后我们升级 pip 并在requirements/common.txt文件中安装需求。这意味着我们只安装运行服务所需的依赖项,而不安装仅用于开发的依赖项(例如测试工具)。
你可以在其他地方看到一些使用COPY . .的例子。这会将当前工作目录中的所有内容(实际上是:Docker 上下文)复制到映像中。这是一个坏主意,因为 Docker 尽最大努力避免重新运行不必要的步骤,它是通过在映像构建时在每个'层'中查找文件的变化来做到这一点的。如果您使用COPY . .命令后接RUN pip install -r requirements.txt,每当您对当前工作目录中的任何文件进行更改时,Docker 将被迫在每次编译时重新安装您的所有需求。通过孤立地复制您的需求,Docker 只会在您更新文件本身时重新安装这个(或这些)文件中的依赖项。这可以为你节省很多时间。
然后,映像将所有相关的 API 代码和 WSGI 入口点复制到不在给定操作系统“顶层”的目录中的容器中,并将该目录设置为其工作目录。这确保了您的代码在远离重要系统文件的地方执行。此外,通过添加用户并承担该用户的角色,该用户具有:
RUN useradd demo USER demo
您限制了您的应用程序代码对系统的访问。出于各种安全性和可用性原因,这可能是有用的,并且被认为是良好的实践。
最后,映像公开端口 8080(Cloud Run 需要的),并运行上面讨论的bash脚本来启动 Gunicorn 服务器。这样,你就有了一个容器化的 API。您可以通过执行以下命令来检查您的 API 是否运行良好:
docker build . -t flask-demo docker run -t -p 8080:8080 flask-demo
这将在本地机器的端口 8080 上构建并运行您的容器化 web 服务。然后,您应该能够再次运行:
curl localhost:8080/health
确认您的 API 在 Docker 容器中运行正常。完成后,您就可以推进云运行了。
推动云运行
在推动之前,你需要确保你已经安装了 GCP 工具。完成后,导航到模板的顶层目录(在google-cloud-run分支上带有cloudbuild.yaml的目录)。你可能需要从命令行登录到你的 GCP 账户,所以在继续之前确保你已经这样做了。你还需要确保环境变量 PROJECT_ID也已经设置好了。如果您不确定在哪里可以找到这个变量的值,看看 Google 的帮助文档。接下来,运行:
gcloud builds submit
这将触发 Google Cloud Build 工具,该工具首先将您的项目文件推送到 Google 云存储,然后使用 Cloud Build 在云中构建您的映像。然后,它会在 Cloud Run 中将您的 API 作为一个容器化的 web 服务从这个映像中启动。关于 Cloud Run 的伟大之处在于,它为你管理了许多复杂的网络设置和路由,为你节省了许多潜在的复杂工作。几分钟后,您应该会看到成功消息。
现在,您应该能够拨打:
curl {your-cloud-run-url}/health
当您的部署完成时,{your-cloud-run-url}将显示在哪里。又一次看到了OK的回应。就这样,你的 API 已经上线,可以接受公众的请求了!不算太寒酸。
后续步骤
不言而喻,这个模板远不是故事的结尾。与任何生产系统一样,构建一个“黄金时间”网络服务可能涉及许多其他工具、技术和过程。然而,根据您打算如何部署 API,有几个明显的后续步骤您可能需要考虑。这些是:
- 如果你没有使用管理服务,比如 Google Cloud Run T1 或 T2 AWS Fargate T3,你应该考虑为你的 API 建立某种形式的反向代理。例如,这可能是一个 NGINX (发音为引擎 x )服务器。 DigitalOcean 有一个很好的指南来解释这如何能为你工作(在他们的平台上!).
- 我强烈推荐给这个项目增加一些持续集成/持续交付(CI/CD) 功能。对于大多数小项目来说,GitHub 为其 GitHub 操作提供的免费津贴可能足以满足您的需求,并且是一个很好的起点。
- 如果你想用 Flask 构建一个 REST API,你应该看看 Flask RESTful 。虽然 Flask 本身可以用来构建 REST APIs,但是 Flask RESTful 提供了一些有用的零碎东西,可以让您更快地开始。Miguel Grinberg 的博客上有一个关于构建 RESTful API 的很棒的教程。
- 我在这里没有讨论身份验证,但是很明显,向 API 添加身份验证层是一个好主意——至少在大多数应用程序中是这样。如果你正在使用云运行,在这方面有几个选项。
如果你想让你的 Flask-in-production 技能更上一层楼,一定要看看我的另一篇关于 ML 模型 API 负载测试 Flask 应用的文章:
这个帖子到此为止!和往常一样,反馈是非常受欢迎的,所以请随时在 LinkedIn 或 Twitter 上给我留言。
原载于 2021 年 1 月 28 日https://mark . douthwaite . io。**
使用 PySpark 展平 JSON 记录
使用 Apache PySpark 通过嵌套模式结构扁平化 JSON 数据

介绍
JavaScript Object Notation (JSON)是一种基于文本的、灵活的、轻量级的数据交换格式,用于半结构化数据。它大量用于在服务器、web 应用程序和联网设备之间传输数据。
通常,由服务或产品生成的事件都是 JSON 格式的。这些 JSON 记录可以有多层嵌套、数组类型的字段,这些字段又有自己的模式。此外,这些字段中有些是必填的,有些是可选的。因此,检索模式并只提取所需的列变成了一项单调乏味的任务。
本文介绍了一种方法,可以最大限度地减少检索 JSON 记录的模式以提取特定列的工作量,并展平作为输入传递的整个 JSON 数据。
履行
假设两个人从一个在线交付平台订购了商品,生成的事件作为 ORC 文件被转储到 S3 的一个位置,这里是s3://mybucket/orders/。要读取这些记录,请执行这段代码:
df = spark.read.orc('s3://mybucket/orders/')
当您执行df.show(5, False)时,它最多显示 5 条记录,而不会截断每一列的输出。

JSON 记录
让我们打印 JSON 的模式并可视化它。为此,执行这段代码:
json_df = spark.read.json(df.rdd.map(lambda row: row.json))
json_df.printSchema()

JSON 模式
注意:从一个路径中读取一个文件集合可以确保在那些文件中存储的所有记录上捕获一个全局模式。
JSON 模式可以被视为一棵树,其中每个字段都可以被视为一个节点。如果一个字段包含子字段,那么该节点可以被认为具有多个子节点。该模式的树如下所示:

JSON 模式的树形可视化
JSON 数据中的第一条记录属于一个名叫John的人,他订购了 2 件商品。第二条记录属于订购了 3 件商品的Chris。我们算法的期望是提取所有字段并生成总共 5 条记录,每条记录对应一个项目。
展平这些 JSON 记录的关键是获得:
- 每个 叶节点 的路径(这些节点可以是 string、bigint 或 timestamp 等。类型,但不是结构类型或数组类型)
- 展开顺序 (数组类型时,提供列展开的顺序)。
- 打开顺序 (如果 struct-type 是 array-type 的父级,则提供打开列的顺序)。
代码实现
使用火花配置至关重要:
--conf spark.sql.caseSensitive=True
由于可能有不同的字段,考虑到 spark 的默认不区分大小写,具有相同的叶名称(例如产品& Product)是本质上不同的字段,但由于 spark 的默认不区分大小写属性,被认为是相同的。
首先导入必要的库:
import json
接下来,定义类变量:
类别变量
其中get_fields_in_json函数定义为:
get _ fields _ in _ json
下面给出了每个类变量的简要说明:
fields_in_json:该变量包含模式中字段的元数据。all_fields:该变量包含叶字段的路径和将出现在扁平数据帧中的列名之间的 1-1 映射。cols_to_explode:该变量是包含数组类型字段路径的集合。structure:该变量是一个字典,用于逐步节点遍历到cols_to_explode中的数组类型字段。order:这是一个包含数组类型字段展开顺序的列表。如果数组类型在结构类型内部,则结构类型必须首先打开,因此必须出现在数组类型之前。bottom_to_top:这包含一个字典,其中每个键映射到每个数组类型/结构类型字段的互斥叶字段列表(如果结构类型字段是数组类型字段的父字段)。rest:包含可直接访问的字段,无论有无点符号。
然后,所有这些类变量都用于执行字段的分解/打开。但是这些类变量是如何计算的呢?让我们逐步分析一下。
步骤 1: 当从AutoFlatten类的对象调用compute函数时,类变量得到更新,其中 compute 函数定义如下:
计算
每个类变量看起来都像这样:

类别变量(图像)
步骤 2:unnest_dict函数递归地解除json_schema 中字典的嵌套,每当遇到叶节点时,将字段的层次路径映射到all_fields字典中的列名(在 *is_leaf* 函数中完成检查)。此外,它还存储了cols_to_explode集合中数组类型字段的路径。
是叶子
unnest_dict
步骤 3: 接下来,通过检查all_fields的元素是否以cols_to_explode中的任何元素开始来获得所有的叶字段,并将其存储在all_cols_in_explode_cols中。
步骤 4: 使用all_cols_in_explode_cols,rest被计算,其包含使用或不使用点符号可直接访问的字段,使用简单的集合差运算。
步骤 5: 现在,使用cols_to_explode来计算structure,该cols_to_explode用于逐步遍历节点以到达数组类型字段。
获取 _ 结构
步骤 6: 接下来,对structure执行 BFS 遍历,以获得数组分解必须发生的顺序,该顺序存储在order类变量中。
提取 _ 订单
第 7 步:最后用order和all_cols_in_explode_cols获取order中每个元素的所有 互斥字段 。为此,使用自下而上的方法,即order列表被反转,并且order中每个字段内的叶字段被映射并存储在bottom_to_top中。注意 *'.order_details'* 键在 *bottom_to_top* 中没有元素它。如果它下面有叶节点,这些节点将可以直接访问并出现在 *rest* 中。
结合所有的函数,这个类看起来像这样:
AutoFlatten 类
为了利用类变量来打开/分解,执行以下代码块:
这里,从 S3 路径读取 JSON 记录,并计算全局模式。然后,在创建初始化所有类变量的AutoFlatten类的对象时,传递这个模式。当从AutoFlatten类的对象调用compute函数时,类变量被更新。
打开/分解时,所有第一级列被选中,并且rest中的列尚未出现。目标名称上有一个计数器,它对重复的目标列名称进行计数。任何计数大于 1 的目标列名都被重命名为<path_to_target_field>,每个级别用一个>隔开。这些字段的所有路径都被添加到visited路径集中。
然后检查order是否为空。空的order列表意味着模式中没有数组类型的字段,反之亦然。如果order列表不为空,则遍历order中的每个元素,并基于其类型数组/结构(仅当数组类型字段是结构类型字段的子字段时出现),分别展开/打开列,并且仅选择那些尚未出现的列。此外,重复的目标列名由<path_to_target_field>替换,每个级别由>分隔,这些字段的路径被添加到visited路径集中。
我们来看看final_df里出现了哪些栏目。
>>> final_df.columns
['city', 'country', 'house_number', 'street', 'pincode', 'state', 'email', 'id', 'name', 'discount', 'order_details>id', 'price', 'product_name', 'quantity', 'ordered_time']
由于order_details字段中的id是重复的,因此将其重命名为order_details>id。
查看初始数据帧df和final_df数据帧的计数,我们知道阵列爆炸已经正确发生。

数据帧计数
现在让我们通过查看属于final_df数据帧的记录来进行验证。

最终 _ 测向数据帧
如您所见,购买的每件商品都有一条记录,并且该算法按预期工作。
注意事项
使用这种方法时,需要记住一些事情。
- 所有的目标列名都是通过使用 JSON 模式的元数据中的叶节点名来检索的。
- 如果您在受约束的环境中工作,则在执行拼合后,必须根据合规标准更改列名。
- 合并
regexp_replace、epoch to timestamp conversion、string to timestamp conversion等被视为对从每一列提取的原始数据的定制转换。因此,它必须在执行自动展平操作后由开发者定义。 - 注意不要暴露个人身份信息(PII)列,因为此机制会暴露所有列。您必须对这些列执行定制操作,比如散列。
就是这样!我希望这能帮助那些希望简化 JSON 数据而不需要定义和传递模式来提取所需字段的人,以及那些希望学习新知识的人。
感谢 Sandesh 在这件事上与我合作!
干杯!
更新:大家好,上面描述的操作是开始了解核心 autoflatten 机制的好方法。我已经为这里的设计了一个优化的方法(其关键或多或少是相同的),与文章中描述的方法相比,它避免了占用大量内存。您可以通过调用返回展平数据帧的execute函数开始。如果您有任何问题,请随时联系我!
用 multipledispatch 实现 Python 中完美的参数多态性
使用 Python 的多重调度模块使我的生活多样化

(图片由 Pixabay 上的 Blickpixel 拍摄)
介绍
在我对编程、数据科学和一般基于互联网的软件工程的探索中,我遇到了很多我喜欢的编程概念。我遇到了很多 API,很多很棒的工具,很多插件,还有很多我非常喜欢的应用程序。然而,每当我第一次熟悉它时,有一个泛型编程概念真的让我大吃一惊,那就是多重分派。
也就是说,虽然我以前使用过单一调度,当然也在几乎所有的范例中使用过,但是我以前真的从来没有在我的代码中使用过像多态性这样的想法。虽然世界上对多分派的介绍可能来自 ML 编程语言,但我对多态性的介绍是以一种叫做 Julia 的编程语言的形式出现的。本文还提供了一个笔记本,您可以使用它来查看 Python 中的多个调度会话的示例。以下是所用笔记本的链接:
朱莉娅
Julia 是一种编程语言,由 Viral B. Shaw 先生、Stephen Karpinski、Alan Edelman 和 Jeff Bezanson 领导,他们都是我认为的天才。这种语言很棒,因为它从类型到构造都很灵活且可伸缩。它主要是自己编写的,并且是 JIT 编译的。所有这些结合起来,使朱莉娅成为许多不同用途的强大选择。
这种新的编程语言让我印象深刻的是类型系统。Julia 下面的类型系统工作得非常好,在超严格和动态之间达到了很好的平衡,同时也表现得非常好,实际上允许你操作和转换类型。这真的是两全其美,这还是在我们开始深入研究 Julia 的主要特征之前,
多重分派范例。
不使用 Julia 的人不会意识到多重分派范例意味着什么,但是对于那些广泛使用过 Julia 的人来说,可以理解,使用多重分派,只需改变输入和输出,就可以完全定制类型。我有一篇关于我有多爱茱莉亚的文章,你可以在这里读到:
关于构造函数如何使用多重分派来改变 Julia 的范式,我有另外一个故事,附带一个视频,您可以在这里观看,它涵盖了多重分派 paraidgm 中的面向对象编程,以及另一篇深入研究构造函数的文章:
https://medium.com/chifi-media/constructing-with-unknown-types-and-oop-in-julia-f3decc46d49 [## 在 Julia 中用未知类型和 OOP 来构造
medium.com](https://medium.com/chifi-media/constructing-with-unknown-types-and-oop-in-julia-f3decc46d49)
朱莉娅的多重调度模式是多么令人惊讶,不谈恋爱是非常困难的。话虽如此,
我恋爱了。
朱莉娅有趣的位置
既然我已经永久地融入了这种令人惊叹的编程语言,我当然会跟踪它的进展。因此,我也对语言的不同方面、它的生态系统以及数据科学和软件世界的其他方面形成了自己的观点。我发现 Julia 现在处于一个非常有趣的位置——在这个领域介于 Python、R 和 Scala 之间。
朱莉娅现在似乎处于一个尴尬的阶段。编程语言仍然相当小众,那些使用它的人要么永远拿起它并爱上它,要么很快放下它。Julia 面临的最大问题是,该生态系统要赶上像 Python 这样的竞争生态系统还有很多工作要做。当然,Julia 的目标不是接管 Python,但是这种语言到底是如何在它旁边工作的呢?
鉴于 Julia 场景的不确定性,考虑到我编写了几种语言,而 Julia 和 Python 只是其中的两种,我想看看 Python 的一个模块可能会很酷,它采用了 Julia 的核心思想——多重调度,并将其实现到 Python 中。也许有些人会考虑使用这个包,因为它对某些用户来说肯定是有价值的。
该模块
我们将要学习的模块是 multipledispatch。这个模块的特别之处在于它的易用性。就像我们在 func-tools 中观察到的单一分派模型一样,这个模块允许使用一个简单的装饰器来改变类型与函数交互的方式。
此外,如果你想学习更多关于装饰者的知识,并学习一些很酷的知识,我有另一篇文章是关于这个的:
</10-fabulous-python-decorators-ab674a732871> [## 10 个神话般的 Python 装饰者
towardsdatascience.com](/10-fabulous-python-decorators-ab674a732871)
我真的很高兴我有足够多的文章向我的读者介绍更多我知道存在的知识,快乐学习!
使用多重分派
正如我上面简单提到的,使用这个模块非常简单。一旦模块被导入,我们可以简单地用我们想要分派到函数中的类型调用上面的函数。也就是说,解释如何实际使用该模块相对简单,只需导入该模块,然后在给定函数上方的装饰器中使用以下语法。另外,另一个旁注——我发现获得该文档的最好地方是 Github。当然,还有星选和叉选等。对于那些想要的人,这里有一个 Github 页面的链接:
https://github.com/mrocklin/multipledispatch
每当我们导入这个模块时,我们不希望调用整个模块,这将破坏我们的修饰语法,只导入我们不需要的东西。这个库本质上提供了这一个模块和函数,所以我们真的没有必要或目的不直接导入它。
from multipledispatch import dispatch
既然已经导入了,让我们编写一个函数的快速示例集,以便在。我们的函数当然会有一个简单的指令,在这种情况下,它只会做一些基本的事情,比如按维度打印给定的类型。我们考虑一个一维数组,或者像我们 Pythonistas 所说的…
列表。
让我们写一个函数来打印出一个数组:
def printout(x : list):
print(x)
x = [5, 10, 15, 20]
我们定义了一个新的函数 printout,它将简单地打印这个值。虽然我确定可能会有某种警方的指纹。DataFrame,接下来我们要做一个打印函数。然而,由于一个数据帧可以保存一个给定观察的多个维度,我们需要以不同于处理典型数组的方式来处理这种类型。
import pandas as pd
这是我想出的连续打印每个系列的小函数。
def printout(x : pd.DataFrame):
for col in x:
print(df[col])
现在,通过添加我们很酷的小 dispatch decorator,我们可以对这两种类型使用相同的打印输出调用。这将把我们的论点的类型,按照顺序和位置。
[@dispatch](http://twitter.com/dispatch)(list)
def printout(x : list):
print(x)
我们为我们的熊猫数据框架做了同样的事情:
[@dispatch](http://twitter.com/dispatch)(pd.DataFrame)
def printout(x : pd.DataFrame):
for col in x:
print(df[col])
现在终于,同一个调用可以用于两者,并且将基于它们的类型调用不同的函数。
printout(df)
printout(x)

(图片由作者提供)
结论
参数多态真的很酷!—是我在 2019 年末写的一篇文章。准确地说,是 12 月 22 日,这意味着差不多两年前我在重复我今天重复的同一句话——
参数多态真的很酷!
另外,如果你想读那篇旧文章,你可以在这里读:
到目前为止,参数多态性无疑是我最喜欢的编程概念之一。我认为能够以这种方式处理类型和函数真的很酷,因为它在代码中创造了很多流动性。当涉及到多重分派时,对方法的描述要详细得多,这鼓励了一种新的思维方式。多重分派通过别名和类型来定义方法,而不是通过别名定义方法。这给 Julia 带来了很多强大的能力,但也有一些非常激进的 Python 应用。
正如我在我的关于装饰者的文章中所说的,我喜欢装饰者是因为
- 有很多很棒的。
- 它们很容易使用。
- 它们会严重改变 Python 代码。
我希望这篇文章深入探讨了装饰者的可能性,甚至有可能启发一些未来装饰者的使用。我发现函数参数的类型转换在很大程度上除了文档之外一无是处,所以能够看到像这样操作方法以使 Python 适用于这种范式是非常好的。非常感谢您的阅读,我希望这篇文章能够启发大量新的 Pythonic 知识!
疫情期间的船队管理:一个优化问题
行业笔记
航空公司机队的理想配置是什么,才能实现利润最大化?

梁杰森在 Unsplash 上
新冠肺炎的经济影响正被广泛地感受到,尤其是在航空业。航空公司已采取严厉措施,尽可能多地保留流动性,以便在中短期内盈利。这个项目的目标是使用航空公司的机队和目的地信息创建一个程序,以最大限度地提高其航班的效益。这意味着该模型试图找到既能增加收入又能降低成本的飞机和航线的最佳组合。对于这个项目,使用了美联航的机队数据和国内目的地。
目录
∘ 目录
∘ 问题描述及表述
∘ 数值实现
∘ 结果
∘ 问题延伸:不确定需求
∘ 结论
∘ 项目代码
∘ 参考文献
问题描述和表述

为了使这个问题变得现实,重要的是要考虑到其他因素,这些因素也被称为约束。
第一个约束很简单,但对模型的正常运行很重要。简而言之,这种约束确保飞机不会服务于从给定机场到同一机场的航线。例如,一架飞机不能从丹佛飞往丹佛,因为这不会给公司带来任何价值。

- 其中 I 和 j 是机场(这里 i=j)
关于客户需求,覆盖两个机场的所有航班的座位总数必须高于或等于该航线的需求。

- 其中 X 是某一类型的平面总数
- s 是座位的供应量
假设一架飞机每天总共只能在空中飞行 20 个小时(其余时间是周转时间),那么该航线上所有飞机的所有这些小时的总和必须大于或等于两个目的地之间的飞行时间乘以两个机场之间每天需要的航班总数。每天 20 小时的限制可以解释为需要给机场员工时间给飞机加油,安排乘客登机并为下一次飞行做准备。

- 其中 F 是所需的每日航班频率
航班频率是一个需要添加到模型中的重要约束条件,也就是说,在两个目的地之间,每条航线都必须由机群覆盖一定的次数。例如,联合航空公司提供的所有航班中需求最高的芝加哥-纽瓦克航班。一些乘客对早上的航班感兴趣,而其他人可能对晚上的航班感兴趣。这个约束确保了当飞机被调度到目的地时,所有这些选项都被覆盖。

最后,这最后一个约束可能看起来微不足道,但如果不添加到模型中,很容易打乱航空公司的调度流程。这限制了公司可以使用的每种类型飞机的总数。简单地说,如果联合航空公司拥有 48 架波音 787,他们不能有超过 48 架飞机被分配到不同的航线。

数值实现
为了简化问题,本文只关注最大化 7 个枢纽城市的收入,这意味着优化总共 42 条航线上的飞机分布,因为客户可以从这 7 个地方中的一个出发,前往其他 6 个枢纽。7 个集线器如图 1 所示。

图 1:unitedaviate.com的联合航空枢纽(CLE 和口香糖被移除)
关于飞机的分配,截至 2020 年 10 月,联合航空公司的机队由 806 架飞机组成,全部由波音或空客制造。国内,美联航只用 5 架。表 1 包括每架飞机的座位容量、运营成本(美元/小时)以及联合航空公司为其国内航班预留的每种类型飞机的数量。
注:本项目中使用的所有数据都是虚构的,仅代表近似值。

表 1: 联合国产飞机描述
这是 代码 (GitHub)上的纸浆(Python)和结果。
结果
在 Jupyter 上运行该程序后,我们得到了总平面分布和它们的路线。单个飞机类型分布的 20 个最大值如表 2 所示。最终值列描述了利润最大化所需的飞机总数。此外,通过降低成本一栏,可以解释为纽瓦克至旧金山的航班(使用波音 737)每次旅行的总收入为 18,812.50 美元,这使其成为该模型中利润最高的航线。另一方面,使用同样的飞机,每趟纽瓦克到丹佛的航班只能带来 3762.50 美元的利润,这是我们覆盖的所有航线中利润最少的一条。最后,表 3 显示了总需求和航线方案的可用和指定机队。

表 2: 美国联合航空公司飞行的前 20 条航线

表 3:可用和分配的飞机
问题延伸:需求不确定
今天,航空业是世界上竞争最激烈的行业之一,每年创造数十亿美元的收入,累计利润率不到 1%。该行业的低利润率可能是由于公司获得的利润在很大程度上受到各种因素的不确定性的影响。价格和路线需求在短时间内变化很大,这迫使企业不断发展,并根据不断变化的趋势改变其战略。在新冠肺炎之后,事情变得更糟,因为世界各地实施的各种旅行限制导致需求骤降。
在这个项目中,历史数据被用来估计每条航线的平均需求以及与飞行相关的成本。但是,该模型没有考虑上述不确定性。为了使项目更能代表现实世界,我们开发了一个随机模型,作为解决方案的扩展,以考虑影响价格和需求可变性的因素。在这个模型中,我们假设每条路线的价格和需求以正态分布的方式变化,围绕我们在原始模型中设置的真实平均值。我们模拟了每架飞机每次飞行的需求和成本,正态分布,每条航线的成本和需求的标准偏差分别为 1000 和 100。在前疫情时代,我们可以将这些不确定的需求归因于工资膨胀和工会罢工等各种因素。根据美国运输局的数据,从 2007 年到 2017 年,航空旅行的需求稳步增长,增幅约为 15%。因此,劳动力需求上升,员工要求获得更高的服务报酬。这对联合航空公司的业务产生了重大影响,增加了极其多变的规划范围。这一点,再加上来自其他航空公司的竞争,使得每条航线的需求大相径庭,从而导致低利润率和脆弱性。
价格是另一个因经济影响而彻底改变的因素。石油、燃料、着陆费、餐饮和机组人员费用的价格是不可预测的,如果忽视它们的可变性,可能会给公司带来灾难。这里我们可以注意到的一点是,一个航班在空中运行得越多,公司支付的可变成本就越少。因此,像航班取消或不利的天气条件等情况可能会增加可变费用,并对利润产生影响。此外,不同的航班每海里的费用也不同。举例来说,一架喷气式飞机在海里方面会更贵,但是它可以飞得更快,从而减少飞行时间。
具备上述条件后,我们可以进行 14 次试验的模拟,每次对不同飞机的每条航线都有不同的需求和价格(见图 2)。从这次试验中,我们注意到,随着每架飞机每次试验的最佳飞行组合数的变化,最佳条件下的总利润在 200 万美元到 400 万美元之间。

图 2:14 个不同模拟的指定航班数量和产生的收入
这一模型让我们更好地理解经营航空公司业务所涉及的不确定性和风险,因为我们经常被迫预测最佳航班时刻表、乘客需求和每条航线可能产生的可变成本。这是优化和运筹学在航空领域至关重要的主要原因之一,各公司都在积极投资,以增强其分析能力,从而领先于竞争对手。
这是随机模型的 代码 (GitHub)。
结论
除了按照我们之前的分析建立每条航线所需的不同机队,我们对该航空公司的建议是暂时停飞波音 777,使用更高效的飞机,如波音 737 和空客 A320。我们相信,使用适当的时间安排和运营管理技术,美联航在困难时期仍能获得正利润。
尽管这个实验充满了真知灼见,但它并不完全适合现实世界,因为它并不完全代表联合航空公司开展业务的程度(例如,货运部门、飞机租赁合同、旅游套餐、忠诚计划和公司联盟)。有数百个二级机场和外部因素没有包括在这个模型中。

Unsplash 上的 DOMA goj OSI
项目代码
github:https://github.com/arguz95/United
参考
[1] Garrow,l .,Lurkin,v .新冠肺炎如何影响和重塑航空业。j 收入定价管理 20,3–9(2021)。https://doi.org/10.1057/s41272-020-00271-1(https://link . springer . com/article/10.1057/s 41272-020-00271-1 # citea)
[2]https://www . BCG . com/publications/2020/seven-trends-shape-airline-industry
[3]https://to70 . com/how-to-use-uncertainty-to-make-better-plans/
[4]http://www . OECD . org/coronavirus/policy-responses/新冠肺炎和航空业影响和政策反应-26d521c1/
随时联系我们!
https://www.linkedin.com/in/arnaud-guzman-annès/ https://www.linkedin.com/in/ramprakash-babu/ https://www.linkedin.com/in/alfonso-cabello/ https://www.linkedin.com/in/jules-zielinski/
Python 中的量子计算机抛硬币纯粹是一种乐趣
用一个有趣的自己动手的初学者实验产生真正的随机性。

图片作者(marcelmoos.com),图标作者 mynamepong 和 Freepik
普通计算机可以产生真正的随机数。这是传统计算机在不依赖外部资源的情况下无法做到的。传统计算机只能产生看似随机但实际上是根据固定规则计算出来的数字。这些数字被称为伪随机。如果我们生成足够多的伪随机数,我们会注意到它们最终会重复出现。

为了生成真正的随机数,传统计算机会测量外部事件,如大气噪音或你按键的准确时间。
相比之下,量子计算机天生随机这既是祸也是福。一方面,很难理解量子计算机是如何得出特定结果的。另一方面,随机量子现象是这些强大的计算机运行的原因。
那么为什么不使用量子计算机来做一次真正随机的硬币投掷呢?
用量子计算机来做抛硬币是不是有点矫枉过正?最肯定!
但这也很有趣吗?哦耶!
所以让我们开始吧。你所需要的只是一个互联网连接和 python。下面是我们要做的事情:IBM 为每个人免费提供真正的量子计算机。
如果你想跟进,只需在 quantum-computing.ibm.com 创建一个账户,并获得你的 API 令牌与 IBM 的量子计算机进行交互。
我们将使用 python 库 qiskit 构建一个简单的量子电路,在 IBM 的量子计算机上执行。我们的量子电路将只由一个代表硬币的量子位组成。我们将操纵量子位处于 0(头)和 1(尾)的叠加状态。
就像薛定谔的猫同时又死又活一样,我们的硬币将同时是正面和反面。
当我们测量硬币时,当我们看一看,硬币将真正随机地以概率结束正面或反面。

首先,我们安装 python 库 qiskit :
pip install **qiskit**
然后我们用 qiskit 来构造我们的量子电路:
在第 4 行中,我们用一个量子位(我们的硬币)和一个经典位来创建量子电路,以存储测量结果。下一行将 阿达玛门 应用到我们的硬币上,将硬币的正面和反面叠加在一起。最后一行测量我们的硬币,并将结果存储在经典位中。
代码不执行操作,只是定义我们的量子电路应该是什么样子。
我们可以用下面的代码在 IBM 的量子计算机上执行这个电路:
代码首先用给定的密钥建立一个到 IBM Quantum API 的认证连接。然后,我们指定希望在名为“ibmq_armonk”的量子计算机上执行我们的电路。
参数“shots”指定我们只想执行一次循环——我们只想掷一次硬币。之后,代码从结果对象中提取硬币投掷的结果并打印出来。

量子硬币翻转的结果
我们在量子计算机“ibmq_armonk”上执行了我们的代码。IBM 提供多台量子计算机。在 IBM Quantum 平台上的仪表板中,我们可以看到哪些机器可用,它们有多少量子位,等等。取决于所选择的量子计算机有多忙,我们的掷硬币迟早会完成。

quantum-computing.ibm.com的免费量子机器
在继续我们的日常工作之前,我们必须反思我们刚刚到底做了什么。只需运行 python 代码,获得结果,然后忘记我们刚刚通过一次击键激活了哪些令人惊叹的技术,这太容易了。
100 年前,量子力学刚刚发展起来,并困扰着这个星球上有史以来最聪明的头脑。今天,按下回车键,我们发出指令,绕地球运行一个量子回路。发送到一台量子计算机,其工作温度刚好高于绝对零度(-273.15°C 或 459.67°F),比外层空间冷几个数量级。
我们向这样一台机器发送指令,以精确操纵单个孤立量子系统的状态,使其测量值与真正随机的硬币投掷相对应。如果这还不能让你起鸡皮疙瘩,我不知道还有什么可以。
觉得这个故事有趣?你可以在这里成为灵媒会员来支持我的写作:medium.com/@mmsbrggr/membership。你将获得所有媒体的访问权,你的部分会员费将直接支持我的写作。
欢迎在 LinkedIn 上向我提出私人问题和评论。我不是以任何方式隶属于 IBM 的。如果你喜欢这篇文章,让我告诉你我的简讯:【marcelmoos.com/newsletter。
翻转 USB 连接器
实践教程
贝叶斯决策分析显示为什么你必须翻转 USB 连接器两次
艾伦·唐尼
我不是第一个观察到有时需要尝试几次才能插入 USB 连接器(特别是矩形的A 型连接器,不可逆)。有关于它的迷因,有关于它的漫画,而且在 Quora 这样的网站上,人 有 问 关于 它不止一次。

杰斯·贝利在 Unsplash 上拍摄的照片
但我可能是第一个使用贝叶斯决策分析来找出插入 USB 连接器的最佳策略的人。具体来说,我算出了你翻第一面要试多久,再翻第二面要试多久,第三面要试多久,等等。
当然,我的分析是基于一些建模决策:
- 让我们假设连接器处于正确方向的初始概率是 0.5;
- 如果是,成功所需的时间遵循平均为 1.1 秒的指数分布;
- 翻转连接器需要 0.1 秒。
有了这些假设,我们就可以开始了。
贝叶斯定理
第一步是计算出连接器处于正确方向的概率,作为你尝试了多长时间的函数。
例如,假设连接器方向正确的先验概率为 0.5,而您已经尝试了 0.9 秒。你可能会开始怀疑自己是否做对了。
为了计算后验概率,我们将从 0.9 秒内无法连接的可能性开始,给定方向:
- 如果你站在错误的一边,你失败的可能性是 100%。
- 如果你在右边,可能性由指数分布的生存函数给出,即 exp(—λt,其中 λ 是速率参数, t 是时间。
因此,对于连接器方向正确的假设,似然比是 exp(λt):1。
现在可以方便地使用对数比形式的贝叶斯定理:
logO(H| D)= logO(H)+logLR(D)
在哪里
- log O ( H )是假设的先验 log odds,在我们看到数据之前,
- log O ( H |D)是假设的后验对数赔率,我们看到数据后,和
- log LR(D) 是两种假设下数据的对数似然比。
由于似然比是 exp(–λt),对数似然比是 λt ,因此我们可以写为:
logO(H| D)= logO(H)λt
给定后验对数概率,我们可以计算出你站在正确一边的概率,作为你尝试了多久的函数。下图显示了结果:

经过几秒钟的摆弄,你应该有理由相信连接器的方向是错误的。
我们可以从两个方向阅读这个图表:考虑到你已经摆弄了多长时间,你可以查找你在正确一边的概率。或者,给定一个目标概率,你可以查一下到达那里需要多长时间。这对下一步很有用。
战略
现在让我们来思考如何将信念转化为行动。我将从一个猜想开始:我怀疑最佳策略是在第一面尝试,直到正确定向的概率下降到某个阈值以下,我将它称为 r ,然后在第二面尝试,直到概率再次下降到该阈值以下,并根据需要重复。
为了实现这个策略,我们可以使用上一节的结果来计算在给定先验概率的情况下,后验概率降到阈值以下需要多长时间,我称之为 p 。
我编写了一个 Python 函数来模拟这个过程,同时跟踪总时间和翻转次数。以下是步骤:
- 基于 p 和 r ,计算翻转前的最大尝试时间。
- 如果我们站在错误的一边,我们就不会成功,所以将最大时间加到总数上,翻转连接器,然后转到步骤 1。
- 否则,从指数分布中随机抽取一个连接时间。
- 如果连接时间小于最大时间,则表示我们成功了,所以将连接时间加到总数上,然后返回总时间和翻转次数。
- 否则,将最大时间加到总数上,翻转连接器,转到步骤 1。
模拟的细节在一个 Jupyter 笔记本里,你可以在 Think Bayes 网站或者在 Colab 上运行阅读。
对于 r 的一系列值,我多次运行模拟,50%的时间从正确的方向开始,并计算连接的平均时间。结果如下:

圆点示出了不同阈值概率的模拟结果。该线显示了结果的局部回归。
当 r 接近 0.3 时,平均连接时间最小。这意味着我们应该继续尝试第一面,直到我们认为有 30%的机会方向是正确的——这需要大约 0.9 秒——然后尝试第二面。
在翻转之后,我们认为有 70%的机会方向是正确的。我们应该继续尝试,直到它再次下降到 30%——这需要大约 1.8 秒——然后再次翻转,重复直到我们连接上。
几个空翻?
现在我们用 r 的最优值来看看连接需要多长时间,要翻转多少次。
我从两个方向开始进行模拟,记录了总时间和翻转次数。下图显示了每个方向的总时间分布,以累积分布函数(CDF)表示。

如果我们从右边开始,平均时间是 2.2 秒,如果我们从错误的尺寸开始,平均时间是 2.6 秒。但有时需要两倍或更多的时间:如果我们从右边开始,第 90 百分位大约是 4.6 秒,否则是 5.6 秒。
这是翻转总数的分布。

第一次尝试连接的概率只有 28%,这意味着当我们以正确的方向开始时,我们几乎有一半的时间会翻转(50 次中有 22 次)。
最常见的结果是,我们翻转一次,大约 40%的时间。而臭名昭著的双翻的概率大概是 18%。
幸运的是,翻转三次或三次以上的情况很少见。
摘要
至此,我想我们已经解决了 USB 连接器的问题。
- 我们使用贝叶斯定理(对数比数形式)来计算连接器方向正确的后验概率,这取决于您拨弄的时间。
- 我们基于我的推测定义了一个策略,你应该继续摆弄,直到后验概率低于一个给定的阈值。
- 给定连接(在正确方向上)的平均时间和翻转所需的时间,我们找到了最小化总连接时间的阈值概率。
- 给定这个最优值,我们估计了总时间和翻转次数的分布。
这些结果解释了为什么翻转 USB 连接器不止一次是如此普遍,即使你从正确的方向开始。
可悲的是,我们的乐趣被越来越流行的 USB-C 连接器破坏了,这种连接器可以在两个方向上工作。
这个例子是根据新二版中的方法 想贝叶斯 。关于贝叶斯决策分析的其他例子,参见 第九章 和 第十章 。
艾伦·唐尼(Allen Downey)是奥林学院的教授,著有《Think Python**、 Think Stats 以及其他关于软件和数据科学的书籍——所有这些都可以从 绿茶出版社 获得。他的博客 可能想多了 ,以关于贝叶斯统计和数据科学的文章为特色。
版权所有 2021 艾伦·唐尼。
许可: 归属-非商业性-共享 4.0 国际(CC BY-NC-SA 4.0)
洪水:现代海岸线面临的新威胁
气候变化如何影响房地产价值以及对现有投资组合的影响


图 0.1:作者提供的图片-洪水保险索赔支出如何因县而异,以及美国人口变化(净移民)如何因县而异。佛罗里达州和阿拉巴马州的申请人数最多,那里的人口也在增长。

图 0.2:作者图片:衡量 2010-2018 年房地产价值变化的指数;-3 表示数值下降幅度最大的区域;+3 表示值增加最多的区域。东海岸几乎所有的房产都在升值。
在本帖中,我们将进行一项案例研究,分析洪水对美国东海岸的社会和经济影响。极端洪水事件主要是由暴雨引起的,在最严重的情况下,会导致非常严重的财产损失。2012 年飓风桑迪造成了 700 亿美元的损失,并导致数百万人断电;哈维飓风造成了 1250 亿美元的损失;美国损失最大的飓风(截至 2021 年 2 月)是 2005 年的卡特里娜飓风,造成了 1610 亿美元的损失。
联邦紧急事务管理局(FEMA)是负责帮助社区从自然灾害的影响中恢复的联邦机构。作为帮助社区了解其当前和未来洪水事件风险的努力的一部分,他们开发了一种洪水风险制图工具,可生成如下图像:


(图片公开提供,由联邦应急管理局提供)图 0.3: 联邦应急管理局洪水风险区位于罗德岛州普罗维登斯(左)和迈阿密-戴德郡(右)。AE 区代表 1%的年洪水概率和 26%的 30 年期抵押贷款洪水概率。
似乎我们每天都发现新的信息来支持我们正在接近一个高潮临界点的论点,当生活将在这个国家的大部分地区变得难以维持。然而,科学和气候分析被如此成功地嘲笑、挑战和否认,以至于许多美国人仍然认为政府投入了太多的资源 来解决这个问题。
我今天想研究的问题是:
美国那些特别容易遭受可怕洪水的地区的房地产价值是如何变化的?
从直觉上看,在洪水造成财产损失的概率为 1/4 的地区(超过 30 年),财产价值应该会下降。或者也许不是——也许人们对洪水保险政策感到欣慰,这些政策承诺涵盖与洪水相关的损失,尽管长期以来保险公司在灾难发生时让其保单持有人束手无策,没有履行他们在 T2 的承诺。
如果你是一个有兴趣了解更多可用数据的读者,以了解洪水风险;或者,如果你是一个关心的公民,有兴趣了解更多关于气候变化的影响,并了解我们未来的世界可能是什么样子,这篇文章是给你的!
一.数据收集
最终,这项工作涉及汇总包含洪水损失、人口迁移、收入和房地产价值信息的多个数据集,同时考虑外部变量,如通货膨胀、人口密度以及各种地理位置的沿海与非沿海性质。总共收集和处理了 7 个数据集:
- 洪灾损失:(来源于 FEMA)
- 房地产价值(来源于 Zillow)
- 人口数据(来源于美国 Fact Finder 从“地理位置”中选择“县”;然后从“主题”中选择人员,然后选择“基本计数/评估”)
- 通货膨胀数据(来源于 BLS)
- 人口密度数据(来源于 CDC)
- 沿海指标(来源于美国人口普查;点击图书馆故事 2018/08 海岸线-县)
- 收入数据集(来源于数据世界)
设计了三个变量来执行这一分析。它们是:
- 人口变化指数:使用 2010 年至 2018 年的数据,计算出 3 年间总人口的变化百分比。人口是在美国县一级汇总的。每年的人口增量按人口密度分组,并按 z 值缩放(与蒙大拿州丹尼尔斯县相比,洛杉矶人口增加 1%意味着不同的事情)
- 房地产价值指数:计算为 Zillow 房产价值指数(ZHVI)在 3 年内的百分比变化。这些变化百分比按人口密度分组,并转换为 z 值(有了 z 值,我们可以对农村地区的房产价值变化与大城市的房产价值变化进行比较,农村地区往往更便宜)
- 洪水保险索赔指数:使用通货膨胀数据将历史洪水索赔支出调整为 2020 年初的美元。然后,对计算移民/ ZHVI 流量的相同 3 年期的调整后年度索赔进行汇总。这些县级索赔按县级人口进行划分,以标准化人口密度的影响。
为什么通量是以 3 年为周期计算的?只是因为每年人口和财产价值的变化往往是嘈杂的;与时间序列中的一年变化相比,从 n 年到 n+3 年的变化揭示了更强的正或负信号。
一个缺点是:理赔并不是洪水风险的最佳代理,因为,如前所述,保险公司通常会欺骗他们的客户,并编造理由来避免支付欠款。他们经常侥幸逃脱,因为大多数灾难受害者没有资源对保险巨头提起诉讼。如果任何人有兴趣进一步阅读这个主题,我强烈推荐纽约时报的文章自然的赌场,它讲述了保险公司如何在“无灾难”的情况下赌博,并最终出售远远超过他们在另一种情况下“灾难”的保单与此同时,保险公司严重低估了巨灾风险。当安德鲁飓风登陆时,人们一致认为损失不可能超过 60 亿美元。当灾难风险分析师卡伦·克拉克估计损失为 130 亿美元时,她被嘲笑为傻瓜。损失最终总计 155 亿美元。
因此,更好的洪水风险替代方法是收集实际的洪水数据,并围绕一段时间内测得的洪水水位设计一个指数。如果有人知道访问这些数据的好地方,我很乐意听听!
二。方法
理解财产价值如何改变(或不改变)以响应洪水事件的一般方法如下:
- 使用通货膨胀数据将历史洪水索赔支出标准化到一个通用等级
- 使用人口数据计算各县的移民趋势-某些县是否在稳步增长,或者是否存在导致人口下降的周期性“冲击”。这些“冲击”与洪水事件一致吗?
- 使用 Zillow 的 ZHVI 数据来追踪一段时间内的房地产价值
利用这些信息,我们可以想象哪里的洪水特别严重。迁移数据将告诉我们,人们总体上是离开这些地区还是向这些地区迁移。最后,财产价值数据将告诉我们,洪水热点地区的财产是增值还是贬值。
基础 EDA
在我们开始任何实际的分析之前,执行数据验证步骤来说服我们自己我们收集的数据是高质量的是很重要的。糟糕的数据+模糊的模型=无意义的见解。
验证迁移数据
为了验证我们的迁移数据,我们可以查看直方图。我们知道美国的人口一直在增长,所以我们预计这个直方图会偏于 0 以上。但是,由于我们跟踪的是县与县之间的变化,从技术上来说,一个县的发展不可能没有另一个县的衰落。所以我们预计会有一定程度的负迁移。一般来说,这个直方图通过了这些检查。

图 1 作者图片:移民的分布大致呈正态分布,略呈正态分布(表明总体人口增长;尽管一些县出现了人口下降的迹象)

图 2 作者图片:这是最终训练数据集的一个例子

图 3 作者图片:这是零膨胀数据集的极端情况,其中绝大多数保单的总理赔额为 0 美元。50 亿美元的数据点
验证索赔数据
为了验证我们的洪水索赔数据,我们可以看一个箱线图(图 3)。我们期望这里有一个零膨胀的情节:大多数保险单最终根本不会支付任何索赔。
此外,图 3 中最右边的数据点代表近 50 亿美元的索赔。这里需要注意的一个细微差别是,这并不代表一个特定的索赔,而是代表跨越 3 年期的总索赔数(经通胀调整)(在上面的数据集中表示为“时间组”))
如果我们仔细看看原始数据,它看起来像这样:其中 time_group 2018 包含 2016 年至 2018 年。我们可以看到,2017 年期间发生了重大损失;特别是在 2017 年 8 月 27 日(毁灭性的飓风哈维)


图 4 作者提供的图片:可视化图 3 中异常点背后的数据(了解 48 亿美元的索赔总额来自哪里)
在这一点上,我没有一个很好的方法来快速验证 ZHVI 数据,所以我将假设原始的财产价值数据是值得信赖的,足以继续进行。
三。分析
既然我们已经讨论了数据收集的基础知识,我们应该再次提醒自己我们进行这种分析的最终目标。
我们的主要目标是了解洪水事件是否对 a)人们选择居住地或 b)房产价值有任何影响
属性值
我通常喜欢在进行分析时建立一个简单的基线。首先,我们可以看一个简单的图表,比较当我们将县分为两组时,总索赔额是怎样的:财产贬值的县和财产升值的县:

图 5 作者图片:不清楚这两个群体实际上是否非常不同。洪水索赔对财产的价值是增加还是减少有影响吗?
对我来说,这两种分布看起来很相似…我看不出这里有什么明显的迹象表明仅仅基于洪水索赔的财产价值是否有显著的不同。为了更严格地测试这一点,我们可以使用一个排列测试。
对于任何不熟悉排列测试概念的读者来说,它本质上是一种通常应用于假设检验场景的方法。排列测试是 t 测试的一个很好的替代方法,因为它们不依赖于任何分布假设(t 测试假设您的数据是正态分布的)。你可以在这里了解更多关于排列测试。排列测试是检验假设的好方法(有区别吗?)并且可以很好地与 bootstrapping 配对来估计该差异周围的置信区间。
无需深入测试背后的细节,下面你可以看到我们的模拟测试统计数据的分布。假设索赔对迁移模式没有影响的零假设,我们可以观察我们的初始测试统计值在这个分布中的位置,我们获得了测试的最后一部分:神奇的 p 值。r 有

图 6 作者图片:模拟测试统计分布(黑色)与实际测试统计分布(蓝色)
我们如何解读这个情节?首先,我将数据分成两组:
- A 组:报告高额索赔(重大损害)的国家
- B 组:报告低索赔(微不足道的损害)的国家
如果我们假设索赔对财产价值没有影响,那么我们期望看到 A 组和 B 组之间的差异落在黑色轮廓的分布中。实际差异(我们观察到的测试统计)用蓝色显示。我们可以计算观察我们的测试统计的概率,假设我们的可能差异的隐含分布为 0.011。(也称为 p 值)。
底线是什么?看起来洪水索赔对财产价值有显著的统计影响:更多的索赔导致更多的价值贬值。这种影响是否“实际上意义重大”完全是另一个问题。但是我们可以说,在洪灾损失严重的地区,房产往往价值较低。量化“到底少了多少”的置信区间需要差异的自举分布,我可能会在这篇文章的后续文章中讨论这一点。
移民
我想回答的第二个问题是:
在遭受洪水严重破坏的地方,人口在减少吗?

图 7 按作者分类的图像:人口发生正负变化的地区的人均人口要求的可视化
与上面的例子类似,不清楚声明是否会影响迁移。如我们所获得的那样重复排列测试,产生以下分布:

图 8 作者图片:我们可以拒绝声明对迁移模式没有影响的假设。
迁移信号比房地产信号强一些,但这里的底线与我们在上面的发现相似:
人们的迁移模式受到洪水模式的影响——更多的索赔导致更多的人口下降。
四。结论
我们最初的目标是了解在洪水保险赔付最高的地方,财产价值是否已经下降。这项工作的动机有两个方面:移民通过直接影响税收来影响各县。如果某些地区正在经历人口下降,从而失去税收,那么这些城市可能会面临未偿市政债券违约的风险(他们可能会在 30 年内偿还)。
对这个问题的快速总结是这样的:考虑三个参与者:“市政债券”、“市政当局”和“投资者”。你可以把市政债券想象成贷款,把市政当局想象成购房者,把投资者想象成银行。市政当局是一个城市或城镇,它总是需要贷款来建造桥梁、维修道路,并使他们的社区更加安全和健康。这些贷款的规模高达数百万(如果不是数十亿的话)美元,比一般银行通常发放贷款的资本要多得多。市政当局不是从银行贷款,而是从“投资者”——查尔斯·施瓦布和世界忠诚者——那里获得贷款。市政当局向投资者出售债券,与城市从大型金融服务机构获得贷款是一样的。
这些债券有助于城镇获得短期现金储备,也有助于投资者获得传统上低风险的资金保证回报。平均投资组合包括某种形式的市政债券:

图 9 作者图片:平均投资组合中的市政债券
细节可能很复杂,但简单来说,只要城镇人口保持不变(或理想情况下增长),这对地方政府和债券发行人来说都很好。当社区从这些债券中欠下大量余额,并随后观察到人口下降时,问题就出现了。违约的风险增加了,不幸的是,这种风险由普通的美国投资组合来承担,他们大量持有这些看似低风险的债券。
那么我学到了什么?
- 在极易遭受洪水灾害的地区,税收收入面临风险——人们似乎正在离开这些地区。
- 在遭受严重洪灾的地区,房地产价值正在下降
- 尽管如此,似乎仍然存在差距。例如,东海岸的房地产价值图显示价值几乎全面上涨。尽管存在明显的风险,佛罗里达州的门罗县(东海岸索赔最多的县)似乎仍在适度升值。


图 10:作者图片;房地产价值指数与东海岸人均索赔。请注意,佛罗里达州门罗县拥有全国最高的人均索赔率。
为了应对佛罗里达州门罗县明显的洪水风险,人口自 2016 年以来一直在下降。然而,尽管人口减少和极端的洪水风险,房地产价值一直在稳步上升。
门罗县是一个典型的例子,在那里,当前的房地产价值错误地代表了气候变化将如何影响未来居民生活的现实。


图 11 作者提供的图片:门罗县的房产价值与预期相反,该县的人口在减少,总索赔额在上升
你觉得这个分析怎么样?任何关于如何改进的建议,或者任何可以进一步澄清的问题,都欢迎并鼓励在评论区发表!
多杯浓缩咖啡的咖啡流量分析
咖啡数据科学
充斥着咖啡数据
几个月前我得到了一个 Acaia Pyxis 标尺,我开始记录照片。我想要一个有两个原因:更准确地测量输出重量和检查流量。我的 Kim Express 没有足够的空间放秤,所以我需要一些小的东西。
在用这种尺度拍摄了 200 多张照片(准确地说是 232 张)之后,我收集了一些数据来帮助理解浓缩咖啡。然而,我没有从流量或连续重量数据中找到任何可以很好预测性能的指标。我希望我能找到一些可测量的东西来帮助改善拍摄,但我没有。
原始数据
对于每条测井曲线,我应用了一个中值滤波器,因为数据可能有点嘈杂,然后我使用 1 秒的时间间隔连续计算流量。
下面是两张对比照片:


所有图片由作者提供
您可以在这些图表中看到一个指示预输注结束(PI)的弯头。输液时流量大是由压力脉动引起的。我们在这里只能看到平滑的流量记录:

我收集了很多数据。我主要是用音阶在合适的时候结束投篮。这是一个图表中的一组日志样本。

寻找线索
我以前没见过有人钻研流量曲线,所以我不得不编造一堆指标。我不知道什么会好,所以我把预输注(PI)和输注分开。我没有看脉动,而是看平滑的流动。
对于预注入,我将其减半,因为通常 PI 开始缓慢,然后加速。对于输液,我看着向上和向下的趋势,如下图所示,至于我的杠杆机器,我在整个拍摄过程中积极调整流量。

此外,我还查看了喝 1 克咖啡以及 2、3、4、5、6、7 和 8 克咖啡的时间。
覆盖过滤器的时间(TCF)和 T10(达到 10 毫升的时间)这两个变量我已经用了将近一年,以帮助在更高水平上跟踪流量的差异。它们和一杯好的浓缩咖啡有很好的相关性。
我的主要兴趣是看看是否有任何流量预测值与良好的口味或更高的提取率(即我的性能指标)有很好的关联。
绩效指标
我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。
最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和回味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。
使用折射仪测量总溶解固体量(TDS),该数值与咖啡的输出重量和输入重量相结合,用于确定提取到杯中的咖啡的百分比。
分析
我首先研究了相关性。
相关性是衡量两个变量彼此相似程度的指标。高相关性并不意味着一个变量会引起另一个变量,而是当情况发生变化时,两个变量的涨跌幅度相同。相关性可以是正的(趋势相同)或负的(趋势相反)。0 表示没有相关性。
这是所有的数据,我把它们分解成可消化的块。

我们可以首先只看预输注和输注指标,很少混合。有许多强相关性,但就第一个 X 克的时间而言,EY 之间似乎有更强的负相关性。我怀疑这是因为 TCF 发生得更早。
****
我还对所有变量进行了排名,并根据 EY 和最终得分将它们分开。相关性最强的变量与 TCF 有关。似乎上坡的速度也对味道有影响,但比 TCF 少一点。
****
我观察了散点图中的一些变量,如 TCF、PI/TCF、第一个 8g 的时间和最大流速的时间。
****
TCF 有非常明显的趋势,但第一个 8g 的时间和最大流量的时间的趋势有一些有趣的趋势。
****
预输注期间抽取 TDS 样本
在其中一些镜头中,我还在大约 5g 输出的预输注期间对镜头进行了采样。因为有了秤,我能够测量输出重量,然后我计算 TDS 和πEY。我研究了这些与其他变量的相关性。

最终 TDS 被 PI TDS 预测得相当好,同样,最终 EY 被 PI EY 预测得很好。

最终分数与皮氏 TDS 有很强的相关性,但与皮氏 EY 的相关性没有那么强。

然而,对于最终的 TDS 和 EY,这种差异有所减少。

虽然我对找到更好的度量标准抱有很高的期望,但是这些测试仍然是对我在 TCF 和圆周率上已经经历过的事情的再确认。我一直在收集这些数据,因为无论如何我都在测量输出重量,也许这对于区分不同的射击时间是有用的。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中。
我的进一步阅读:
关注数据驱动的特性,推动数据科学项目向前发展
数据驱动并不意味着数据驱动本身

Julian Hochgesang 在 Unsplash 上拍摄的照片
介绍
对于围绕数据和数据连字符术语(如“数据驱动”)的所有宣传,重要的是要记住,数据是一种原始资源,在集成到使用所述数据生成有意义的输出的产品之前,它没有实际价值。虽然数据科学家的具体角色和职责因组织而异(甚至在组织内部),但数据科学家通常负责将数据从原始资源实际转换为对产品用户有价值的东西。事实上,与其说数据科学是对数据本身的科学研究,不如说它是创造事物的实践,这些事物使用数据来产生推论和/或预测,以满足未满足的需求或希望[3,4]。因此,一个组织在数据科学方面的投资通常旨在创建我所称的“数据驱动的产品功能”,即在输入和输出之间的实际过程中,在最少或没有人为干预的情况下,将数据输入转化为有价值的输出的产品功能。然而,要使数据科学项目成功且高效地运行,仅仅拥有大量数据并期望数据科学能够提供相关的数据驱动特性是不够的。相反,在任何技术工作(例如,数据争论和建模)发生之前,需要对期望的数据驱动特性有一个清楚的理解。
产品、功能和优势,天啊!
在继续之前,让我们建立一些定义。产品是一种旨在满足顾客需求的物品或服务[1,2]。产品的定义很宽泛,可以包括从电视和汽车等实物到信贷监控和金融建议等客户服务。在产品的上下文中,特征是产品的特定功能部分,旨在产生特定的收益,其中收益是用户通过使用产品获得的某种价值【7】。一个数据驱动的特性,特别是,我用这个术语来描述一个由数据驱动的产品特性,如果没有数据输入,这个特性将毫无用处。数据驱动功能的例子包括电子商务网站/应用程序上的推荐引擎,语音助理设备中的语音识别模型,可以区分热狗和非热狗的图像分类器,信用卡客户服务中的欺诈检测模型。
我之所以如此强调产品功能,而不是产品本身,是因为一个产品的创造,甚至可以被称为“数据产品”[4–6],是具有互补技能的多个团队的结果,而不仅仅是数据科学家。然而,当焦点转移到产品的特定数据驱动功能时,我相信数据科学的责任会变得更加清晰,组织数据科学项目会变得更加简单。
从想法到执行
如果数据科学要产生任何效益,方向是必要的。为数据驱动的特性建立一个清晰的概念提供了这样的方向。为什么?当对数据驱动的特性有了清晰的想法后,数据科学项目的下一步可能会变得更加清晰。
我可以想到至少三种方式来理解需要创建的特性,这有助于指导项目中的其他步骤(如果您有其他方式,请留下评论)。首先,在确定了数据驱动特性的想法后,就更容易确定需要的数据,同样重要的是,确定不需要的数据。现在,这并不意味着所需的数据将立即可用或准备好在机器学习模型中使用(大多数情况下不会),但能够表达数据需求是朝着正确方向迈出的一大步。其次,理解所需的特征也有助于确定需要对数据应用哪种方法。例如,如果正在讨论的特性旨在预测某种事件是否已经发生(比如欺诈行为),那么您现在有一种很好的预感,您将需要一个分类模型。此外,通过评估预测生成过程是否有必要具有高度的可解释性,您现在可以进一步细化您的建模策略了?如果是这样的话,那么就需要使用某种可解释的方法或机制来理解模型的决策过程。第三,了解推动数据科学项目的产品特性有助于评估性能指标。例如,如果该功能是一个受监督的机器学习模型,了解该功能对产品的用途有助于确定误报或漏报是否会给产品用户带来更大的代价[8]。
结论
如今,许多组织都在投资数据科学。这种努力通常应该受到欢迎(假设这些努力建立在道德和负责任的数据实践的基础上)。然而,我写这篇文章是为了强调,对数据科学的投资假定或者应该假定,一个组织对数据驱动的功能有很强的想法,或者正在积极开发由数据驱动的功能的想法。请记住,数据科学家可以将任何数据放入模型并获得一些结果。然而,有意义的结果是由一个清晰的想法驱动的,这个想法指导数据科学家努力使用数据为产品用户带来某种好处。
1.https://courses . lumen learning . com/unlimited-marketing/chapter/what-a-product/
2.https://www . aha . io/road mapping/guide/product-management/what-a-a-product
3.Kozyrkov C .数据科学到底是什么?in:hacker noon[互联网]。2018 年 8 月 10 日【引用于 2020 年 9 月 7 日】。可用:https://hackernoon . com/what-the-earth-is-data-science-EB 1237 D8 CB 37
4.做数据科学:来自前线的直话直说。“奥莱利媒体公司”;2013.
5.https://www . district data labs . com/the-age-of-the-data-product
6.O'Regan S.《设计数据产品——走向数据科学》。In:走向数据科学[互联网]。2018 年 8 月 16 日【引用于 2021 年 2 月 8 日】。可用:https://towards data science . com/designing-data-products-b 6 b 93 EDF 3d 23
7.https://www . aha . io/road mapping/guide/requirements-management/what-is-product-features
8.Koehrsen W.《超越准确性:精确性和召回——走向数据科学》。In:走向数据科学[互联网]。2018 年 3 月 3 日[引用于 2021 年 2 月 20 日]。可用:https://towards data science . com/beyond-accuracy-precision-and-recall-3da 06 bea 9 f6c
树叶地图:如何用 HTML 代码创建一个表格样式的弹出窗口
逐步提高地理空间数据可视化技能的指南

介绍
yellow 是一个非常流行的 Python 可视化库,它是专门为创建地图和可视化地理空间数据而开发的。在叶子的官方文档页面上写着:
*folium*使用 Python 处理的数据在交互式活页地图上可视化变得容易。它既可以将数据绑定到地图上用于*choropleth*可视化,也可以将丰富的矢量/光栅/HTML 可视化作为标记传递到地图上。
互联网上有很多关于叶子的基础知识的文章和教程,比如如何创建叶子地图对象,如何显示各种地图样式,如何添加标记等等。很多时候,我们需要超越这些基础,并使用额外的技术或技巧,使可视化更引人注目,对讲故事更有用。
在这篇文章中,我想与你分享我最近完成的一个 python 项目,在这个项目中,我使用 HTML 代码在叶子地图中创建了一个定制的、表格样式的弹出窗口。我用叶子和HTML 代码在互动地图上标出了美国大城市的主要大学。当用户点击地图上的一个标记时,会出现一个小窗口,用户可以在一个格式良好的表格样式的弹出窗口中查看关于该机构的附加信息。
带有表格样式弹出窗口的交互式地图如下所示:

带有自定义表格样式弹出窗口的交互式树叶地图
关于数据
这种可视化背后的数据是从一个原始的开放数据集创建的,该数据集可以从DATA.ED.GOV下载。原始原始数据集包含 6000 多所高等教育机构的机构级数据以及填充美国教育部创建的大学记分卡仪表板的各种指标。
在本教程中,为了便于演示,我只选择了一小部分机构样本和一些常用指标。样本数据集如下所示:

可视化数据集(图片由作者提供)

df.info()和数据字典—按作者分类的图像
创建一个基本的树叶地图
首先,让我们通过创建一个基本的叶子地图来稍微热身并刷新我们的叶子知识。我们首先创建一个空的地图对象。然后,我们添加标记,将机构的位置叠加到地图上。最后,我们向每个标记添加一个简单的弹出窗口,当点击时显示机构的名称。
请注意,在第 10–17 行中,我们创建了一个颜色字段,公共和私人机构分别用蓝色和棕色表示。我们还创建了一个机构名称的标签,并将其分配给第 21 行的弹出菜单参数。当叶子为每个机构添加一个标记时,它将使用 for 循环遍历数据集,并对每个标记进行颜色编码以及在弹出窗口中添加每个机构的名称。
关于叶子的一个很好的小事情是你可以为标记选择定制的图标。例如,在第 22 行,我们可以指定 icon='university' 为每个标记指定一个好看的大学图标。

一张基本的树叶地图(图片由作者提供)
使用 HTML 创建带有表格样式弹出窗口的树叶地图
现在,我们想超越基础,尝试使用定制的表格格式使弹出窗口更漂亮一些,就像我们在前面的介绍中展示的那样。为此,我们将需要使用 HTML 代码来创建表格格式,然后将其传递给leav . popup()。
下面的代码定义了一个函数 popup_html ,它将使用 html 代码创建一个包含两列和一个表头的表格。表头显示机构名称。表格的左栏显示了我们希望包含在弹出窗口中的信息/指标;右栏显示了每个指标的实际值。我们还可以通过指定 HTML 颜色代码来选择任何列的颜色。
这一长段代码看起来很吓人,但实际上并没有那么复杂。对于每个指标(机构 url、机构类型、录取比率等)。)显示在弹出的表格中,HTML 代码结构总是一样的;只有指标名称和指标值需要在代码中相应地更改。

作者图片
现在让我们将 HTML 代码传递给follow并通过向标记添加表格样式的弹出窗口来重新创建地图。这是通过下面的代码实现的。具体来说,第 15–19 行使用 for 循环和 popup_html 函数创建 HTML 表格,然后使用leav 将表格添加到地图上的标记中。标记()。同样的概念和过程也可以用于创建定制的工具提示(对于工具提示,用户只需将鼠标悬停在标记上,工具提示就会出现,而不是单击标记)。
这就对了。现在,您已经使用flour和 HTML 代码创建了一个交互式地图,带有一个格式良好的弹出窗口。感谢您的阅读,希望您喜欢这篇文章。快乐学习!

带有自定义弹出窗口的交互式树叶地图
如果您对 HTML 完全陌生,并且在理解代码方面有困难,请阅读我最近发表的关于 HTML 基础知识以及如何使用它将动态图像、链接和表格添加到 read 地图弹出窗口的文章,其中有对代码的详细解释!
参考列表和数据源:
- Github 中的官方文档页面:http://python-visualization.github.io/folium/
- 大卫·贝克的《奇妙的叶子:https://www.kaggle.com/dabaker/fancy-folium
- 数据来源:美国教育部大学记分卡开放数据(https://data . ed . gov/dataset/College-score card-all-data-files-through-6-2020)
你可以通过这个推荐链接报名 Medium 来支持我。通过这个链接注册,我将收到你的会员介绍费的一部分。谢谢大家!
使用食谱嵌入的食品搜索:一个简单的基于嵌入的搜索引擎,使用 gensim,fastText 和 ElasticSearch
这是构建搜索 ML 产品的介绍性课程。我们将使用一个工具(genSim)来训练一个语言模型(fastText),然后将数据索引到一个可扩展的搜索基础设施(ElasticSearch)上,并编写一个自定义的搜索功能来尝试基于嵌入的搜索。

斯蒂芬·c·阿萨夫蒂在 Unsplash 上拍摄的照片
目的在本教程中,我们将学习如何为某个用例创建一个简单的搜索应用程序。搜索无处不在,每个应用程序都有多个搜索栏和算法,都服务于不同的目的。想象一下,你正在创建一个送餐应用程序,或者更具体地说是一个烹饪应用程序,你想让你的用户发布食谱并实时搜索你的库存,因此你希望在主页上有一个搜索栏,作为用户来到你的平台时遇到的第一个搜索栏。
我们将此作为教程来学习。代码在我的 Github 里。
https://github.com/arnab64/food-search-recipe-embeddings
笔记本:https://github . com/arnab 64/food-search-recipe-embeddings/tree/main/src
目标显示一个食品列表,给出一个查询,从库存中按相似性降序排列。
- 工程:学习如何训练定制语言模型(Gensim),并将其快速部署在可扩展的搜索基础设施(ElasticSearch)中。
- 数据:学习处理这种文本数据的复杂性,我指的是食品餐馆领域的数据,否则就是所有数据
- 产品/科学:了解如何评估解决方案的优劣,以及我们可以生成哪种架构或哪些额外的改进嵌入来在指标上表现得更好。[即将发布-教程]
数据数据来源:数据集是来源于 Kaggle 的公共领域数据集。 6000 份印度食物食谱数据集
数据探索和预处理:为了训练嵌入和使用它们,已经按照文本字段的要求完成了所有必要的预处理。笔记本上有更多的细节。我主要使用了两栏配料和配方,以便能够在它们上面训练单词向量。使用的堆栈 Gensim,ElasticSearch,Pandas

烹饪直方图
recipeEmbeddings:使用 Gensim 建立一个关于食物食谱的快速文本语言模型由于这个数据集是一个食谱数据集,我们可以训练一个关于食谱的语言模型。菜肴是用特定的配料经过一系列特定步骤后的结果。事实上,食谱是由连续的结构组成的,这有利于对食物进行连续的处理。
在这里,我们试图构建一个食物/菜肴建议应用程序,我们希望嵌入可以做到这一点。我们正在试着推荐菜肴,我们有每一道菜的菜谱。因此,输入字段的性质已经是有序的,我们想要的输出将是一个相似性递减的菜肴列表。我们可以使用在菜肴食谱上训练的嵌入,然后使用其组成成分或食谱的嵌入来表示每个食品/菜肴。我们称之为食物嵌入。
因为,所有的食物项目将由供应商只上传到网站一次,并且由于上下文不变,每道菜的这些嵌入可以预先计算一次,并且每次我们都有一个新的语言模型,并且索引以便更快地检索。
出于我们的目的,我们在 recipe 列上训练一个快速文本模型。有关训练语言模型的更多细节,以及了解更多关于 word2vec 和 fastText 嵌入的信息,请查看这篇文章。
关于我实现这里提到的所有东西的细节,请查看我的知识库:arnab 64/food-search-recipe-embedding

与经过培训的 LM 中的“paneer”(农家干酪)最相似的术语
现在,我们的任务是什么?
- 暗示一道菜? : 没有明确的查询,我们可以根据他们过去的订单使用用户嵌入
- 寻找一道菜? : 提供显式查询,基于距离创建查询嵌入和建议
在这个报告中,我已经执行了提到的第二个任务,即在运行时给定一个显式查询,我想使用嵌入来建议食品。
类似食物的一些结果,或者我们这里所说的菜,可以在下面看到。快速文本模型的训练非常简单,在 gensim 中完成。


基于训练嵌入的相似菜肴 1) Homemade Easy Gulab Jamun 2) Kashmiri Style Chicken Pulao
我们如何从单词向量中得到食物项目嵌入?菜谱是说明书的集合,说明书是文字的集合(食材、动作等)。现在,我们已经训练我们的语言模型能够学习单词的 n 维表示。
菜谱向量:简单的平均菜谱中的单词向量,因为我没有花太多时间。
你可以只在食物的标题上做同样的事情,但是标题提供的食物信息不如食谱多。因此,它可能没那么有用。尽管如此,我也尝试了其他方法,但为了简短起见,这里不做赘述。
在现有数据的基础上添加了基于重复嵌入的食物向量在 pandas 中,根据食谱和配料为每种食物新计算的向量已被添加为附加列。对于像食物这样的非用户文本特征,最好存储预先计算的嵌入,并随着数据的变化而更新。
在数据集中有了向量之后,我们可以使用这些向量+其他现有特征来执行分类任务,就像这里我们可以尝试预测给定名称的菜肴类型,从而评估嵌入的好坏。但是预测烹饪似乎不是一个值得花时间去研究的有趣问题。
使用 fastText 时,我们只使用上下文信息,而不使用顺序信息,也就是说,如果您在番茄后添加洋葱,这些嵌入很可能无法区分,反之亦然。我们可以使用基于注意力的方法来训练我们的定制语言模型,以捕捉食谱的顺序信息。然后,我们必须在 torch 或 tensorflow 中训练定制语言模型,然后使用该模型添加基于矢量的嵌入。fastText 用于在不浪费时间的情况下训练单词向量,或者我们可以使用在数十亿参数上训练的预训练单词嵌入,并找出一种方法来直接使用它们来驱动应用程序,从而节省工程工作并获得类似的结果。

照片由 Unsplash 上的 Umesh Soni 拍摄
在 ElasticSearch 上使用新的密集向量索引食品数据集我们将数据索引到 ElasticSearch 中,并探索其中的功能,最重要的是,我们希望建立一个搜索引擎,ElasticSearch 使它变得非常简单,并且可扩展,通过基于密集向量的操作,可以构建许多非常快速的智能应用程序。elasticSearch 可以处理几乎所有类型的数据,它是大规模可扩展的和快速的,很容易将你的搜索模型部署到产品中,并进行实验。
在这里,我使用 Python 中的 ElasticSearch 客户端 API 将数据从 pandas 索引到 ElasticSearch。用 python 定义模式,并为索引中需要的所有列编写了从 pandas 到 JSON 的定制数据摄取函数。
Elastic Search 上基于密集向量的搜索 Elastic search 使数据一旦编入索引就可以通过 API 进行搜索。搜索查询的嵌入是以与我们对带有 recipe 的项目相同的方式导出的。我们读取预先训练的食谱单词模型,并获得单词在处理后的搜索查询中的嵌入,并取平均值。
观察结果下面的结果很有趣,它证明了配方数据的基本效用,并且它可以与其他数据集相结合,以使嵌入和模型更好。食谱遵循一种全球通用的格式,在印度食谱遵循一种结构。这也是一个多语言问题,因为相同的食谱可能存在于网络上的不同语言中,这些基于嵌入的方法使得能够构建适用于任何语言的应用程序变得更加容易,这对于像印度这样的多元文化市场中的应用程序来说无疑是有帮助的。

Elasticsearch 上的搜索执行—示例 1
我的见解:这是一个非常小的数据集,嵌入是在这个数据集上训练的(大约 6000 个实例),我们可能有庞大的真实数据,因此更好,或者训练更智能的嵌入。然而,尽管使用这个,我们可以建立一个可行的搜索应用程序,它看起来并不太糟糕。
由于我们直接使用基于食谱的向量来搜索每一个食品,我相信当我们提供本质上是配料的搜索查询时,我们的应用程序会工作得很好。像:“面粉油烤番茄奶酪橄榄牛至”-比萨饼或面包条与番茄沙拉等。
对于食品名称搜索,我们可能需要训练另一个将查询映射到食谱的模型。“披萨”——“四块奶酪和蘑菇披萨,鸡肉香蒜酱披萨,芝士松饼”


查询建议示例。
在这里(例-3)我们看到,我们已经检索了许多多种菜系的汤菜。
用户不会列出正在查询的食材,他们更可能会搜索菜名。这种方法也适用于这种情况,但是我们的嵌入并不是为这种情况而设计的。
例如,搜索结果为“”的烤鸡看起来像这样。
【辣椒粉烤鸡串】,
‘烤盼儿玉米串’,
‘鸡丁卡玉米卷配奶酪蒜味蛋黄酱’,
‘烤鱼脆片(烤箱中煎鱼)’,
‘甜菜根鸡排’,
‘鸡马莱 Kabab’,
‘土豆卷’,
‘迷迭香和百里香鸡’,
‘辣味猕猴桃酱配羊乳酪’,
‘脆皮蔬菜天妇罗’]
结果还不错,实际上相当多样,但很相似。
因此,为了能够使用基于食物名称的搜索,我们只需添加另一个从搜索查询映射到唯一“食物食谱”的模型,甚至可能使用一种连续的训练。
评估和后续步骤到目前为止,我还没有办法评估这些向量的优劣。我在这一点上放下了工作。但这是一次很好的入门学习经历,让我们了解处理食品的应用程序中的数据科学问题。我很确定实际问题要复杂得多,规模也更大。
至于下一步,我将尝试结合其他数据集,找出更好的嵌入信息的方法,并解决另一个任务。请随意贡献或联系令人兴奋的东西。
谢谢大家!
基于博弈论的食物选择
用博弈论解决两个朋友之间的餐馆选择冲突。
虽然 2020 年没有像过去那样给我们很多出去吃饭的机会,但无论何时,我们都花了很长时间来决定去哪里吃饭!这是一个众所周知的百万美元问题。我的这两个朋友相当挑剔(虽然比我少一点,但我的目标是让他们看起来很糟糕,😄),在过去的 8 年里,我很少和他们一起吃饭,但根据我的经验,我们必须额外花半个小时来讨论食物大战。

我决定通过理解底层模式并找到一种快速达成妥协的方法来结束这一切。
假设:给定我的朋友在某一天的食物偏好,我们能很快找到选择什么菜来最大化满足感吗?
一点博弈论的背景知识
我不会在这里长篇大论地谈论这个理论,我会尽量简洁明了。
博弈论是研究描述理性决策者( 【我的两个朋友】 )之间互动( 食物选择 )的数学模型。很公平!
游戏的结果——预测游戏结果的一种方法是确定每个玩家的优势策略。优势策略是对给定玩家来说最好的策略,而不管其他玩家的选择如何( 无论什么菜都能满足我朋友们当前的渴望)——所以不管朋友#2 做什么,朋友#1 的优势策略就是朋友#1 的最优策略。
玩家(朋友)选择的一套优势策略(美食)被称为纳什均衡。这被称为均衡,因为任何一方都不会因为改变他/她的选择而获得额外的利益。
简而言之,纳什均衡是一条法律,即使没有警察,也没有人想打破这条法律。违法对个人没有任何好处,他们不会获得任何额外的东西。人们观察交通信号并根据灯的颜色停车/前行就是这样一种现象。
好了,理论到此为止,让我们进入应用程序。
你可以点击这里查看 GitHub 中的代码。
我不打算使用 Nashpy,而是使用基本的 python 功能来看看是否可以实现一个结果。
让我们创建我们的收益矩阵。在这种情况下,这将是两个朋友对他们想吃的各种美食的评级。

上周五测量的各种美食的支付矩阵
任务是找到给定收益矩阵的优势策略,结束食物战争。
让我们在散点图上画出收益矩阵:

作者图片
上面的曲线描述了一个人在品尝各种美食时的满足感。属于曲线最高部分的坐标属于两个朋友的最高收益。如果 x 代表瓦伦的收益,y 代表柯蒂的收益,那么我们必须最大化 xy。
为此,我们需要找到通过点(1,4)和(3,2)的直线的方程。线的斜率由下式给出:

斜率为-1。
该直线的方程可以很容易地由下式求出:

方程式是 y = -x + 5
xy = x(-x + 5) = -x + 5x
取 xy 相对于 x 的一阶导数:

因此,在 x = 5/2 时,xy 最大(等于上述导数,-2x + 5 等于 0)。x = 5/2 时 y 的值也是 5/2。

上面线上的绿点是折中点。它位于中国和意大利支付的坐标线上,离意大利食物更近。
但这到底意味着什么呢?我们应该吃中国菜和意大利菜的混合体吗?比萨饼上的面条听起来很奇怪,但我吃过非常奇怪的比萨饼,茄子、山羊奶酪和土豆怎么样?是的,我吃了,因为那是我唯一的素食选择。
解释
上面的解决方案是混合的,所以我们要么找一家既供应中餐又供应意大利餐的餐馆,要么如果我们想从中意混合食物的冲击中拯救自己,让我们找到获得纯解决方案的可能性。

对他们两个来说,占优点都是 5/2。
对于 Kirti,5/2 = p(2) + (1-p)(4)
解决这个问题,我们得到 p = 3/4
如果我们解出凡荣,就会得到同样的解。
结论
p = 3/4 意味着每 4 次我们对中国和意大利食物有这样的偏好,我们就会去意大利餐馆 3 次,去中国餐馆 1 次。
最后,我相信我们有办法解决他们之间的冲突。:)我要做的就是随身带着笔记本电脑,或者创建一个可以运行这个程序的小 app。
顺便说一句……在我完成这个分析后,已经过了午夜,现在没有食品配送服务在运行。所以,今晚我不吃中国菜或意大利菜。
又是拉面!顺便说一下,对于那些不知道拉面是日本的人来说,它被认为是上个世纪日本最伟大的发明。
火影忍者和他最喜欢的拉面(图片来源:Giphy)
被标准差愚弄
直觉价值和不确定性的替代测量

罗伯特·鲁杰罗在 Unsplash 上的照片
上次,我看了英国收入分布的统计平均值,以说明平均值的潜在弱点。概括一下,你可以在这里看到https://medium.com/@rohan.tangri/fooled-by-the-average-f254ff9bc08c。这一次,我们将看看标准差和一个可以根据情况使用的替代方法,即平均绝对偏差。
一个常见的误解
当被问及标准差描述了什么时,许多人会说它给出了样本与平均值的平均距离。让我们考虑一个简单的例子。假设我们有 5 个人,他们的年收入是:{$15k,$27k,$34k,$50k,$90k}。现在,直观地说,我们如何测量收入与平均值的平均偏差?首先,我们需要计算样本均值:

作者图片
接下来,我们需要从上面的样本平均值中获得每个样本点的平均距离:

图片由作者提供:注意括号中的术语始终为正数!
看起来不错!实际上,我们这里刚刚计算的是平均绝对偏差,它清楚地描述了最初的定义。样本统计公式如下:

作者图片:由 x_i 和 mean hat{x} 定义的 N 个样本的样本平均绝对偏差
现在让我们来看看样本标准差公式:

作者图片:由 x_i 和均值 hat{x} 定义的 N 样本的样本标准差
马上,我们可以看到这看起来不像平均绝对偏差计算。还应该注意的是,为了简单起见,我们通过除以 N 而不是 N-1 来使用有偏估计量:

作者图片
我们得到的结果是一个非常不同的数字,我们高出 20%以上!发生了什么事?不同之处在于两种计算都主张正偏差。对于标准差,我们求差的平方使其为正,然后求平方根,而不是只求差的绝对值。然而,这造成了离群值的偏差,因为大数平方本身变得更大,使得厚尾分布的标准偏差根本不能反映平均值的平均偏差。另一方面,当处理细尾分布时,偏差很小,标准偏差确实更符合样本远离平均值的平均距离的近似值,但它仍然不完全符合(例如高斯分布)。
重新定义标准差
到目前为止,我们已经看到,如果您想要一个度量来告诉您样本与平均值的平均距离,您应该使用平均绝对偏差。那么,标准差告诉我们什么?嗯,它给出了一个直观的值,为分布的扩散作为一个整体。你可能认为这听起来和平均距离平均值一样,但是有细微的差别。现在,我们可以辨别样本在一组样本中的排列,以及它们之间的差异。让我们考虑另一个例子。假设有两组数字,{1,1,7}和{0,2,7}。这两组的平均值为 3,平均绝对偏差为 2.67。然而,第一组具有 2.83 的标准偏差,而第二组具有 2.94 的标准偏差。直观地说,第二组有更广泛的价值观。这被标准偏差捕获,但是随着平均绝对偏差丢失。
通过平方算子,标准差还具有非常有用的数学性质,它构成了许多统计学和概率论的基础。一个很好的例子是我们如何简化随机变量的方差:

图片作者:方差的简化,注意标准差就是简单的方差的平方根!
最后,对于完美的高斯分布,标准偏差实际上比平均绝对偏差更有效。然而,一旦离群值和厚尾值开始出现,这种情况很快就会消失,可以说在现实场景中,平均绝对偏差实际上更有效。
同样,在使用指标和统计数据得出结论之前,理解它们是如何得出的非常重要。在引用偏差统计数据之前,一定要理解数据的分布,并准确地理解你要传达的信息。
如果您觉得这篇文章有用,请考虑:
推广的方式,我希望这篇文章是一个有趣的阅读,并让我知道你的想法!!
简单指南:如何在你的树莓 Pi 中安装 Ubuntu
借助广泛的应用和软件包生态系统,释放您的 Raspberry Pi 的威力

加里·罗基特在 Unsplash 上的照片
有很多原因让你想把 Ubuntu 放到你的 Raspberry Pi 中,而不是官方的 Raspbian 操作系统。在我的情况下,我通常使用 Raspberry Pi 作为小型机器人和人工智能项目的低功率便携式计算机。许多驱动程序、包和依赖项只有在 Ubuntu(如 ROS2🤖或者 OpenCV👀)但在拉斯边不是。
在这篇文章中,我想通过不同的常见步骤来成功地为 ARM 64 位架构设置带有最新版本 Ubuntu 的 Raspberry Pi 4 或 Raspberry Pi 3,目前是 Ubuntu 20.10 Groovy Gorilla 和 Ubuntu 20.04 Focal Fossa 。
第一步:刻录你的 Ubuntu 操作系统镜像
首先你需要选择你的 Ubuntu 版本。根据您的需求,您可能想要一个完整的桌面版,或者只是命令行登录。为了获得完整的桌面体验,我推荐你至少有一个 4Gb 内存的 Raspberry Pi 4 和 Ubuntu 20.10 桌面 版。对于 Raspberry Pi 3,我可能会继续使用 Ubuntu Server 20.04 LTS 和没有图形界面的控制台访问。
选择最新的兼容操作系统并将图像刻录到 SD 卡中的最简单方法是使用官方的 Raspberry Pi Imager 应用程序。它包括一个更新的兼容操作系统的集合,适用于所有型号的 Raspberry Pi。你可以去 Ubuntu 版块选择你需要的版本。确保您始终为桌面版或服务器版选择 64 位版本。

树莓 Pi 的 Ubuntu 图片列表。作者图片
要刻录图像,请使用至少 16GB 的 SD。因为 Raspberry Pi 不仅会使用 SD 卡进行存储,还会使用 SD 卡中的交换内存来扩展可用内存,所以使用快速 SD 卡非常重要(级别越高越好)。 Raspberry Pi Imager 应用程序将为您处理所有刻录步骤:格式化、写入和验证图像。
启动新的操作系统,第一次登录,检查一切正常。在 Ubuntu 中默认登录的用户是 ubuntu 密码是 ubuntu 。
第二步:设置 WiFi
第一项任务是通过 WiFi 设置互联网接入。假设您目前离线,最直接的方法是直接编辑网络计划配置文件:
$ sudo nano /etc/netplan/50-cloud-init.yaml
我们需要添加 wifi 适配器配置。在后键入这几行以太网:配置和配置并以同样的缩进:
wifis:
wlan0:
optional: true
access-points:
“SSID-NAME-HERE”:
password: “PASSWORD-HERE”
dhcp4: true
现在您可以应用来自网络计划的新配置,并检查是否有任何错误:
$ sudo netplan generate
$ sudo netplan apply
检查 wlan0 接口是否已成功连接并已分配 IP:
$ ip addr show
# or just `ip a` or just `hostname -I` for a minimalistic approach
当 Ubuntu OS 第一次连接到互联网时,需要一些时间在后台运行更新。如果 apt 或 apt-get 命令被锁定几分钟,不要感到惊讶。
步骤 3:设置本地主机名访问
在一个 wifi 网络中有几台具有不断变化的动态 IP 的机器,使得每次都很难连接到它们。我们希望能够访问每台带有本地主机名地址的机器。这在 Linux 和 Mac 系统中工作得很好,对于 Windows 你需要额外的工作,比如安装 Bonjour for Windows 。首先,我们需要修改您机器的主机名:
# Set host name to `ubuntu` (this is the default anyway)
$ sudo hostnamectl set-hostname ubuntu
然后,我们安装 avahi 守护程序并启用自动发现服务:
# install avahi and enable daemon
$ sudo apt install -y avahi-daemon
现在你可以使用 ubuntu.local 访问你的 Ubuntu 机器,而不是使用你网络内部的动态 IP。
步骤 4:设置 SSH
启用本地主机名和连接后,我们希望能够远程登录到机器。根据你的 Ubuntu 版本,SSH 服务可以默认激活。但为了以防万一,我们尝试安装 SSH 服务器包,并允许它的流量集成 Ubuntu 防火墙:
$ sudo apt install openssh-server
# Allow Ubuntu firewall to accept ssh connections
$ sudo ufw allow ssh
如果 SSH 启动,您应该能够使用默认用户名和主机名从远程机器登录:
$ ssh ubuntu@ubuntu.local
步骤 5:设置交换内存大小
交换内存允许操作系统使用 SD 卡中的存储空间作为运行进程的额外内存。这对于在 Raspberry Pi 系统中激活是非常重要的,因为电量非常有限,我们会很快耗尽内存!首先我们需要安装配置管理器包(根据你的 Ubuntu 版本可能已经安装了):
$ sudo apt-get install zram-config
现在我们可以编辑交换内存设置文件了。
$ sudo nano /usr/bin/init-zram-swapping
你应该在定义了 mem 变量的地方找一行,然后把这个值乘以你想要分配给内存交换的 SD 卡中的千兆字节。通常 5GB 是个好数字:
# Inside /usr/bin/init-zram-swapping
# Multiply the available swap memory size. 5Gb should be good enough
mem=$(((totalmem / 2 / ${NRDEVICES}) * 1024 * 5))
重启 Raspberry Pi 并使用htop命令检查新的可用交换内存:
*$ sudo reboot
. . .
$ htop*
步骤 7:启用树莓相机(可选)
你可能想激活你的官方树莓皮相机。通常在 Raspbian 中你可以使用 raspi-config 来编辑一些固件配置。但是在 Ubuntu 中,我们可以直接编辑固件配置文件:
*$ sudo nano /boot/firmware/config.txt*
要激活相机并增加 GPU 内存大小,请在 【所有】 下添加这些行:
*start_x=1
gpu_mem=128*
在 Raspberry Pi 4 中,您可能不需要修改 GPU 内存大小。重新启动并尝试保存相机中的图片:
*$ raspistill -o cam.jpg*
步骤 8:启用 i2c(可选)
同样,对于相机,您可能希望激活 i2c 通信,例如,如果您正在使用扩展帽。在 Ubuntu 中,i2c 通常是默认激活的,但只对根用户有效。您只需将您的用户添加到 i2c 组:
*$ sudo usermod -aG i2c ubuntu*
注销并再次登录,并根据 i2c 组检查您的新权限:
*$ i2cdetect -y 1*
如果您有权限运行它,I2C已经为您的用户成功启用。
一如既往地让我知道你是否有任何问题或意见,以提高这篇文章的质量。享受你的新 Ubuntu 系统!
基于机器学习的足球比赛视频分析
使用 ML 和传统 CV 技术从视频馈送中理解足球比赛的场景。

19 年前的足球日。照片来自 Unsplash 的 @jesusance 。
足球是世界上最受欢迎的运动之一,它能够在最高级别的联赛中的一场比赛中吸引数百万爱好者的注意:数百万(x2)的眼睛注视着同样的图像,显示 22 名球员争夺一个球的所有权。
嗯,这并不是观看一场足球比赛的全部,如果我们分析一场比赛中我们能够处理的数据量,我们可能会得到一个提示。
足球分析正是这样做的,在这篇文章中,我想分享我自己在解决该领域的一个子问题方面的经验:从单个类似广播的摄像机记录的足球比赛视频流中提取尽可能多的知识。
此外,一定要看看我朋友的作品 @matteoronchetti ,我和他一起完成了这个有趣而富有挑战性的项目!
问题是
这个问题本身已经非常不适定了,因为从前景突然变化的单个移动摄像机中提取位置和语义信息肯定不是一个简单的方法,因为你可能通过在场地周围放置多个固定摄像机来解决一个更简单的问题。但是,考虑到明显的预算和许可限制,你可能不会被允许在一个真实的体育场里做这些。
尽管如此,有多种方法可以在预算范围内处理(至少大致如此)这样的视频数据,而且不用离开你舒适的椅子。
方法
我们像任何教科书(优秀的)软件工程师一样处理任务:我们将问题分解成更小、更易管理和更具体的问题。
我们提出了如下的划分:
- 参考系统和单应性估计(如何将玩家位置从摄像机视角投影到 2D 平面)。
- 物体检测(又名球员/球/裁判是什么,在哪里)。
- 物体跟踪(又名如何跨帧跟踪实体)。
- 玩家识别(也就是我如何跨帧识别玩家)。
- 团队认可度(我怎么弄清楚一个球员为哪个团队效力)。
因此,让我们按照“位置到语义”的顺序,在进入每个任务的细节之前,从系统的整体架构开始。
我们在输入中得到一系列的帧,我们使用对象检测(字段和实体)依次处理每一帧;一旦我们有了一系列近乎连续的探测,我们就可以开始追踪每个实体。与此同时,我们用摄像机估算场地的位置,我们将每个实体的位置从框架投影到俯仰坐标。此外,我们可以通过识别和将分配到一个团队来跟踪每个玩家。

系统的整体架构。图片作者。
然后我们一帧一帧地重复,直到视频结束。在这一点上,我们有一个阶段,我们称之为平滑,在这个阶段中,我们基本上允许自己回顾到目前为止我们一帧一帧提取的所有知识,我们“进行向后调整”,以便使轨迹和检测在整个序列中更加连贯。
现在让我们试着一步一步地跟踪从一个框架被送入系统的那一刻起,系统内部发生了什么。
目标检测
当从 ML 的角度处理这样的问题时,你可能注意到的第一件事是很难找到质量不错的可用标记数据。因此,是时候抛出一个最著名的反对探测器了: YoloV3 。

YOLO 网被喂了一帧游戏用滑动窗口的方法。图片作者。
你很快就会发现,简单地裁剪框架,并期望预先训练的网络提供良好的结果是行不通的。因为我们在这里高度优先考虑准确性而不是速度,所以我们使用滑动窗口向 YOLO 提供原始分辨率图像,以使网络在整个帧上一点一点地工作。你用这种方法得到的结果会更好,让你可以持续地发现球员/裁判和球。
是的,如果你想知道的话,COCO 数据集(YOLO 接受训练的数据集)有一个足球类。
作为一个简短的考虑,我们假设几乎整个系统都有(相当)可靠的检测,因此准确性是重中之重。足够幸运的是,这可能是一个让你有更多自由的任务,因为你有很大的可能性来获得一个超级可靠和高效的探测器,这里没有限制。你可能想从头开始训练你自己的超光探测器,提取预先训练好的网络,利用空间邻接,最大化并行化...我们的时间非常紧张,所以我们几乎没有触及这些选项的表面。
参照系
这可能是最具挑战性的任务,因为它需要估计单应性,这种单应性是将球员的位置从相对于球场的框架绝对坐标系投影出来所需要的。

球场的预遮罩图像。图片作者。
为了做到这一点,我们屏蔽了图片中描述的帧,删除了在前面步骤中检测到的所有对象,并且将球场的当前帧与一组预先计算的球场图像进行匹配,这些图像来自于球场的简单模型,从不同的旋转和平移角度拍摄。为了有效地匹配,我们利用了一个索引,并将输入视为一个“查询”。

使用一个简单的 Flask 服务器,将图片中的玩家投影到 2D 渲染的区域。图片作者。
为场地找到正确的匹配可以让你建立单应矩阵,它可以把你从 YOLO 得到的检测框投射到球场上。为了构建矩阵 tho,你还需要知道和 在哪里你正在看图片,也就是相机的 3D 坐标。这很难实时估计,但幸运的是,每个体育场都有一个或多或少固定的位置来转播比赛(注意,摄像机几乎可以自由地平行于场地移动)。
目标跟踪
到目前为止,我们只是对每一帧应用了相同的步骤,没有时间上的联系,但如果我们想随着时间的推移保持当前的检测状态,以便能够识别每个玩家的轨迹,并实际理解涉及同一实体的后续检测,同时仍然对检测器不时出现的故障具有鲁棒性,会怎么样呢?
为此,我们需要一个跟踪器,准确地说是一个多跟踪器,并选择将其实现为卡尔曼滤波器。

二分图中的最小权重匹配,将观察分配给预测。图片作者。
跟踪器完全基于位置(实际上不见帧),并接收来自 YOLO 的一系列探测位置作为观测值,通过将分配问题公式化为二分图中的最小权重匹配,将这些位置与被跟踪的对象进行匹配(卡尔曼预测)。

用位置信息跟踪玩家。作者 GIF。
之后,一个简单的跟踪逻辑定义被跟踪对象的生命周期(活动/不活动),并确保用观测值更新卡尔曼状态。
玩家识别
这实际上是这样一种情况,一个简单但出色的从头实现被证明比您可能尝试的任何现成解决方案都要有效得多。

从门牌号码到球衣号码,都可以做得十分相似。图片作者。
我们训练了一个 CNN 来识别你在球衣背面看到的数字,通过增加流行的街景房屋号码(SVHN)数据集,具有相当好的准确性和偏斜容限。正如我们上面提到的,找到像样的和可访问的足球比赛的标签图像被证明是太难了。这就是为什么我们必须变得有创造性,我们相信这是一个应用领域适应的很好的例子。
一旦你能够检测到一个玩家的号码,你就能够给他们分配一个 id,并且你可以利用上述相同的跟踪逻辑来使 id 的分配更有弹性(前面提到的平滑)。
此外,请记住,一旦你知道了玩家的队伍(下一个)或者有了额外的外部信息(比如队伍阵容和烘烤师),可能的数字的分布可以被进一步限制。
团队认可
你有两个由在球场上穿着相同球衣的球员(加上裁判)组成的球队:在我看来,这是利用古老的 K-means 算法的完美设置。
你可能会在这里做一些更奇特的事情,把所有东西都转换到光谱域,但是你仍然可以在 HSV 颜色空间上使用球员边界框聚类两个队,并且用一个 tf-idf 加权从每个边界框中过滤出场地的绿色来完成所有事情,从而获得良好的结果。

团队识别算法的结果。图片作者。
页(page 的缩写)s:应用任何异常值检测技术,裁判都可以被检测为两个团队集群之一中的特殊“异常值”。例如,DBSCAN 产生了良好的结果。
结果呢
我们用一些可视化的结果来结束这篇文章,这些结果有望总结我们在这里描述的所有步骤。不幸的是,我们无法真正深入地涵盖每一个细节,但我们仍然希望您能够跟随并对该方法有一个直觉,并可能享受这个过程。
对于任何建议、问题或只是聊天,不要犹豫,联系我在 nicolo.lucchesi@gmail.com 或@nick_lucche 在 Twitter 上。
感谢阅读,祝你在球场上好运!
足球桌面艺术

足球表中名字的第一个字母拼出的最长的单词是什么?
如果给它无限的时间,一只猴子随机打字几乎可以肯定写出莎士比亚的全部作品。
在我们的问题设置中,我们没有无限的时间,也没有无限的猴子,但是我们有足球桌,而且很多。
如果还是不清楚,那么换个更冗长的问题,我们想知道在联赛排名表中球队名字的连续首字母中最长的英文单词是什么?这里有一个例子:

就像问题陈述一样,2016/17 赛季结束表的缩写拼写为“跛脚”
数据
我从维护良好的 Github 存储库中下载了所有的数据。利用这些数据,我用每一组比赛日的结果反复构建了比赛日结束表。这项分析涵盖了 28 个国家的多个联赛。数据集中最早的赛季是 1963/64 年的德甲。
总而言之,我收集了 54,095 个比赛日结束时的排行榜。
方法学
对于每张表,我生成了长度超过 5 个字母的团队名称的每组连续首字母。
对于一个比赛日表的每一组连续字母,我将它们与英语单词的 nltk 语料库进行交叉比较。
这在整个英语单词语料库中产生了超过 1400 万次查找。
结果
有很多 6 个字符的单词是有效的,我们要找的是 7 个字符的单词。那些是传说中的干草垛中的针。总之,我们发现了 4 个有效实例(和一个无效实例……)。
注意,除了搜索连续的离合点之外,我还扩展了搜索空间,包括反向离合点、两跳离合点和反向两跳离合点。
整齐
从上到下按顺序出现的字符串。例如:

有序离合拼读" TMESIS "
7 个字母的离合字符
🄼🄰🄻🄻🄰🄲🄰 [France Ligue 2] [2013-09-21]
🄿🄾🄰🄻🄸🄺🄴 [Greece League 1] [2008-02-20] ❌
^^^ I can't find a well sourced definition - scrubbed.
6 个字母的离合符号
🅂🄲🄰🅁🄲🄴 [Spain Segunda División 2019-20][2020-02-29]
🅂🄴🄰🅂🄾🄽 [Superliga 2016-2017] [2016-09-24]
🅂🄺🄰🅃🄴🅁 [Turkey League 1] [2013-09-23
以相反的顺序
从下到上按顺序出现的字符串。例如:

逆序离合符咒“软化
7 个字母的离合音
🄲🄷🄰🄽🄲🄴🄻 [Premier League 2015-2016] [2015-10-17]
6 个字母的离合字符
🅁🄴🄰🅂🄾🄽 [Superliga 2018-2019] [2018-10-08]
🅅🄰🄲🄰🄽🅃 [Italy League 2] [2018-05-18]
🄲🄻🄰🅄🅂🄴 [Italy League 1] [2007-03-17]
按顺序,每隔一个字母
每两个小组中从上到下依次出现的字符串。例如:

每隔一个字母,依次拼成“ MANNESS ”。注意团队位置在 2 中上升。
7 个字母的离合字符
🄼🄰🄽🄽🄴🅂🅂 [Premier League 2011-12] [2012-02-26]
🄻🄰🄿🅂🄰🄽🄰 [France Ligue 2] [2018-04-05]
6 个字母的离合字符
🅂🄰🄻🅃🄴🄳 [Premier League 2000-01] [2001-04-11]
🄻🄰🄶🄶🄴🅁 [Superliga 2018-2019] [2019-09-02]
以相反的顺序,每隔一个字母
每两个小组按从下到上的顺序出现的字符串。例如:

每隔一个字母,按字母顺序拼成“ SWAIRD ”(一个延伸,真的)
6 个字母的离合字符
不幸的是,没有找到这种格式的 7 个字母的离合字符。最有趣的 6 个字母组合是哀叹和赞同。
🄱🄴🄼🄾🄰🄽 [Superliga 2012-2013] [2012-11-23]
🄰🅂🅂🄴🄽🅃 [Superliga 2018-2019] [2019-02-25]
词典
7 个字母
马六甲 : /məˈlakə/ ( 名词)——一种用于手杖和伞柄的棕色手杖。🌂
:/ˈmannəs/(名词)——:人与众不同的或与众不同的特征。👨🏻🦰**
lap Sana:/lapsənə/(名词)——lap Sana 是向日葵科开花植物的一个属。它原产于欧洲和亚洲北部。尼普勒草是这一属植物的通用名。🌻**
圣坛 : /ˈtʃɑːns(ə)l/(名词)——教堂靠近圣坛的部分,为神职人员和唱诗班保留,通常用台阶或屏风与中殿隔开。 ⛪️
*注意,虽然它在 nltk 语料库中,但我删除了“poalike ”,因为我找不到合理的定义。
所以你走吧。4 14,000,000 次查找中的 7 个字母的字母缩写!我挑战任何人去战胜它!
感谢阅读。
我们应该教数据科学家更像开发者一样思考吗?(第二部分)

由 pressfoto 制作的科技照片—www.freepik.com
在这份关于如何编排机器学习操作化(MLOps)的混乱芭蕾的两部分报告的第一部分中,我们谈到了在企业中编纂数据科学的“科学”部分的可能性,认为这样做肯定会扼杀其发现的核心使命。在第二部分中,我们将尝试通过简短讨论一个极其相关的编程范例来至少部分推翻这一概念,数据科学家现在可以使用该范例来帮助他们自己以及他们现在和未来的同事。这个范例就是函数式编程。
函数式编程的一个非常简短的历史可以追溯到 20 世纪 30 年代,当时数学家阿隆佐·邱奇发明了 lambda 演算,这是一个使用函数来表达计算的数学逻辑的正式系统。二十多年后,这种抽象的数学理论进入了列表处理器(Lisp)编程语言。作为目前使用的第二古老的语言(比 Fortran 年轻一岁),Lisp 仍然是一种有影响力的、几乎令人尊敬的语言,尤其是在人工智能研究社区中。
从那时起,Lisp 极大地影响了数据科学中使用的许多流行语言,特别是 Python、R 和 Scala,所有这些语言都借鉴了 Lisp 的函数性质。这些语言(当然还有许多其他语言)向 Lisp 的列表友好语法致敬,这可以从几乎普遍采用列表理解中看出,其中列表可以使用其他列表作为起点来构建。Lisp 本身继续在许多流行的方言(如 Common Lisp)中茁壮成长,或者以许多衍生语言(如 Haskell 和 Clojure)的形式发展,所有这些都可以在现代数据中心架构中愉快地运行。
但是到目前为止,这些语言最重要的共同点可以直接追溯到 lambda 演算,表现为开发人员能够编写由离散函数组成的程序,这些函数不会改变或依赖于程序的更广泛状态。简而言之,像 Python、R、Scala 和 Haskell 这样的语言(甚至 JavaScript 和最近的 C++)都鼓励开发人员编写高度模块化的代码。这使得调试、维护、重构和重用更加容易。最重要的是,函数式编程产生的代码可以随时适应代码、数据和环境的变化,而不会产生无法预料的后果——这是高度实验性和协作性的数据科学领域中最受欢迎的属性。
(非)函数式编程的危险
在企业中的任何一天,数据科学家可能会打开一个 Jupyter 笔记本,用 Python 编写一组复杂的数据准备例程,这些例程采用一些全局变量,如在几个笔记本单元中乘坐过山车的熊猫数据帧,将数据、逻辑和变量交织在一起,形成一个高度可延展的相互依赖的过程语句和函数的汤。
对于特定的用户和特定的任务集,最终的笔记本电脑可能在那一天工作得非常好,但随着时间的推移,它能否成为企业日复一日依赖的强化数据管道?其他团队成员能理解代码吗?它能在其他项目中重用吗?更糟糕的是,笔记本是否返回了预期的结果?它可以干净地执行,但是如果一个或多个变量从一个函数或单元意外地改变到另一个函数或单元,则产生的数据集可能包含计算不正确的条目,例如,迫使数据科学家回溯他/她的步骤,以找出隐藏在可塑汤内的意外结果。
上面的场景听起来可能有些极端,但是它在企业中经常发生,即使该企业正在工具和平台上投资 MLOps。最终,由个人数据分析师、ML 工程师、数据科学家和其他同事编写的代码成为所有企业人工智能项目的命脉。如果代码难以理解、调试或重用,或者如果其输出不可再现或不可解释,那么没有任何 MLOps 工具可以挽回在根除代码级问题时所损失的时间,也不能挽回损失的收入或暴露的安全、隐私和治理风险。
实践中的函数编程
通过采用函数式编程范式,从事数据科学项目的开发人员可以通过更好地划分每个函数来回避这些问题。基本的想法是根据要做什么而不是要执行的任务来思考。传统上,程序员可以编写一个函数,如下例所示(见图 1)。
图 1:传统结构化函数

资料来源:Omdia
此任务将函数与外部定义的变量联系起来。对“num”变量的更改可能会以意想不到的方式改变该函数的工作方式。相比之下,一个更具功能性的方法应该类似于下面的例子(参见图 2)。
图 2:编写函数的更实用的方法

资料来源:Omdia
在这里,该函数简单地定义了通过将传递的值转换为返回值来完成什么。现在和将来都不需要担心依赖关系。该函数只是将数字 1 加到传递的变量上,而不是直接修改变量。
因为函数是 Python 中的一级对象,所以该语言本身包括许多高阶函数,开发人员可以使用这些函数来创建不修改或不依赖于程序整体状态的非过程化代码。这些函数包括“filter()”、“map()”和“reduce()”函数,这些函数对于那些沉浸在 Hadoop 大数据世界中的人来说是很熟悉的。有了这些函数,而不是像本例中那样在几行代码中遍历一个列表(参见图 3)。
图 Python 中的传统迭代

资料来源:Omdia
开发人员可以编写与下例相同的迭代(参见图 4)。
图 Python 中的高级迭代函数

资料来源:Omdia
这个函数基本上将 do_function 映射到列表“y”。尽管与列表理解相比,这些内置函数不被认为是 Pythonic 迭代器,但是它们非常有效。在幕后,“map()”简化了数据科学家寻求遍历非常大的列表或数据帧时有时会非常耗费资源的过程。通过 Apache Spark 这样的并行化架构运行“map()”函数,性能优势将呈指数级增长。相比之下,功能性较差的基于循环的迭代替代方案会带来本地 RAM 不足的风险,并且会在一次非常大的数据转换中丢失所有数据。
企业的下一步
企业是否需要严格执行函数式编程,就像他们可能采用敏捷开发这样的软件方法一样,在敏捷开发中,开发人员的参与是一件要么全有要么全无的事情?对于每个开发者来说,函数式编程本身是一种做还是不做的练习?谢天谢地,没有。函数式编程是一种可以一行一行、一个任务一个任务、一个项目一个项目地采用的思维模式。
开发人员可以挑选如何以及何时更具功能性的编码方法是最合适的。如果对于一个给定的任务,“map()”比列表理解更有意义,那也没关系。如果一个 Jupyter 笔记本包含一些纯粹的功能性代码和一些不那么纯粹的功能性代码,那也没关系。数据工程师、ML 工程师、数据科学家和许多其他专家能够并且应该总是拥有为手边的过程选择正确的工具和正确的方法的优势。
旨在服务于长期流程(如数据管道)的代码、需要经得起同事们仔细检查的代码以及必须经受严格单元测试的代码肯定可以从函数式编程中受益。同样的道理也适用于任何使代码更易读、更易调试、更易复制、更易于重用的东西。
这样,我认为函数式编程应该在人工智能驱动的企业中被视为一种哲学,而不是一种实践。像斯多葛主义和柏拉图主义等希腊哲学一样,函数式编程应该被视为一套基本原则,可以全部或部分地遵循,作为提高一个人生活质量的手段——或者在数据科学的情况下,提高一个人的软件质量。
正如正确的代码文档和变量/函数命名约定一样,毫无疑问,不同的开发人员会有不同的风格,一般来说,遵守公司的指导方针也是如此。最重要的是,开发人员在编写代码时开始采用“做什么”的哲学,而不是“T2 如何做”。通过这种方式,函数式编程的整体价值主张可以交付增量价值,即随着时间的推移而积累的价值。
如果对函数式编程的投资导致一个人工智能项目更短的上市时间,或者如果它允许一家公司在生产中只维持一个人工智能项目,那么这项投资将是值得的。正如第一部分中提到的,尽管最初数据科学家和其他人工智能实践者需要做更多的工作,但这一简单的开发实践可以为希望将人工智能作为核心竞争力的公司带来巨大的变化,不仅仅是在一两个部门,而是在整个公司。
注:这篇文章摘自一篇最初出现在 Omdia VisionAIres 社区 的文章。
对于新的数据科学家来说,领域知识有时比技术技能更重要
作者聚焦
索菲亚·杨谈到持续学习和寻找优秀同事和导师的重要性。
在 Author Spotlight 系列中,TDS 编辑与我们社区的成员谈论他们在数据科学领域的职业道路、他们的写作以及他们的灵感来源。今天,我们很高兴与大家分享 杨 与本https://medium.com/u/e6ad8abedec9?source=post_page-----90e103a8c4da--------------------------------的对话。

照片由索菲亚·杨提供
Sophia 是 Anaconda,Inc .的高级数据科学家,负责管理关键指标、数据管道和模型,并使用数据科学来帮助公司各部门制定决策。她还是多个开源库的作者,如 condastats、cranlogs、PyPowerUp、intake-stripe 和 intake-salesforce。她拥有德克萨斯大学奥斯汀分校的统计学硕士学位和教育心理学博士学位。
首先:你是如何决定进入数据科学领域的?
我的背景是统计学和心理学。我在研究生院接受了很多因果推断、实验设计和统计建模方面的培训。我使用实验、调查数据和纵向历史数据来建立统计模型,并产生关于人类行为的见解。我喜欢和数据打交道,毕业后我想继续和数据打交道。因此,对我来说,过渡到数据科学是非常自然的。
回顾过去,开始数据科学职业生涯时,最困难的方面是什么?
当我第一次开始我的数据科学工作时,我在技术和业务领域都遇到了一些挑战。但我没有把它们视为挑战,而是把它们视为成长的机会。
从技术上讲,我受过统计学的训练,但没受过多少计算机科学的训练。所以,说到 GPU,并行编程,大数据处理等等,我都没有准备,不知道怎么做。幸运的是,我在公司有很好的导师,我非常渴望学习所有我以前没有的技术技能。我也上了一些相关的网络课程,帮助我学习和成长。
从商业角度来看,从学术界到商界的心态转变可能具有挑战性。行业项目可能与研究项目非常不同。发表论文不再是目标。您经常处于紧张的时间表中,并且您的工作经常与收入和财务后果相关联。不得不说,我喜欢改变,拥抱改变。能够看到我的项目的直接影响比发表学术论文更有意义。
根据你自己的经验,你会给正在该领域迈出第一步的有抱负的数据科学家什么建议?
我认为领域知识有时比技术技能更重要。因此,我会鼓励人们首先尝试在自己的领域做数据科学。提出一个有意义的数据科学问题,你有兴趣在你的领域甚至日常工作中解决,建立假设,收集你需要的数据,并从那里开始。
另一件事是永远不要停止学习。数据科学领域有太多东西需要学习。幸运的是,还有许多学习资源、聚会和会议可以帮助人们学习。还有,我认为找到榜样很重要,和你想成为的人在一起,向他们学习。每天都在学习和成长。随着时间的推移,你会越来越像你想成为的那个人。
你最喜欢现在这个职位的什么?
我有很好的导师和同事。是人们让工作环境变得愉快。
就项目而言,作为我们公司仅有的两名数据科学家之一,我与各种各样的利益相关者一起参与各种项目。我与产品、销售和营销部门密切合作,了解用户趋势、产品特性,并发现商机。我真的很喜欢端到端地处理我的项目。我定义项目的范围,编写 ETL 管道,创建可视化,构建模型,部署仪表板和模型,然后将结果转化为业务。
你的公开写作和你的其他专业活动有什么关系?是什么激励你开始的?
起初,我只是想记录我所学到的或做的事情,作为给自己的笔记。然后,当我将来需要做类似的事情时,我可以回到我的笔记,并确切地知道该怎么做。
写了几篇文章后,我意识到写作是一种很好的学习方式。人们总是说教学是最好的学习方式。我认为写作也是最好的学习方法。即使是我认为自己非常了解的话题,在研究和写作的过程中,我也能学到很多东西。
最后,展望未来,您希望在未来几年内看到数据科学社区发生什么变化?
我们的首席执行官王蒙杰总是说“数据科学是素养,而不是工作。”我认为越来越多的人将成为数据科学素养。Python 和 R 是新的 excel。每个人都将能够在自己的领域中谈论数据科学和使用数据科学工具。
好奇想了解 Sophia 的工作和项目吗?在媒体、推特、 LinkedIn 上关注她。以下是 Sophia 收集的关于数据科学的帖子中的一些我们最喜欢的,这些帖子从面向行业的教程到清晰、初学者友好的讲解。**
- " 从零开始的多类逻辑回归"(2021 年 4 月, TDS )
"很多人一直在使用多类逻辑回归,但并不真正知道它是如何工作的,"因此 Sophia 编写了一个全面的演练,并用 Python 实现完成。 - " 数据科学家的测试"(2021 年 1 月, TDS )
软件测试对开发者来说是家常便饭,但在数据科学家中却是不太常见的做法。在这篇文章中,Sophia 介绍了两个工具——Pytest 和 Hypothesis——它们使得单元测试变得容易。 - "(2020 年 8 月, TDS )
在这里,索菲亚利用她的行业经验,解释了商业世界中最重要的指标之一:客户终身价值(LTV)。她包括了一个数学和 Python 实现。 - " Jupyter 面向数据科学家的工作流程"(2020 年 12 月, TDS )
Jupyter 笔记本在数据科学世界里随处可见,但相当一部分从业者不喜欢使用;Sophia 分享了一个实用的工作流程,帮助她从设置到部署利用该工具的强大功能。
请继续关注我们即将推出的下一位专题作者。如果你对你想在这个空间看到的人有建议,请在评论中给我们留言!
对于成功的人工智能项目,庆祝你的墓地
如何在人工智能项目中快速失败

图片来源: Unsplash
人工智能团队在定义新的项目指南时投入了大量的严谨性。但对于扼杀现有项目来说,情况就不一样了。在没有明确指导方针的情况下,团队让不可行的项目拖上几个月。
他们在项目评审会议上大肆炫耀,以免成为坏消息的传播者。通过简化过程来快速失败不可行的项目,团队可以显著提高他们在人工智能计划中的整体成功。
AI 项目不同于传统的软件项目。他们有更多的未知:正确数据集的可用性,满足所需精度阈值的模型训练,生产中建议的公平性和健壮性,等等。
为了快速失败,人工智能计划应该作为类似于营销和销售漏斗的转换漏斗来管理。项目从五阶段漏斗的顶部开始,可以在任何阶段落下,要么被暂时搁置,要么被永久暂停并添加到 AI 墓地。人工智能漏斗的每个阶段都定义了一组清晰的未知因素,并通过一系列有时限的成功标准进行验证。
AI 项目漏斗有五个阶段:

作者图片
1.问题定义:“如果我们建了,他们会来吗?”
这是漏斗的顶端。人工智能项目不仅在初始开发阶段,而且在持续的监控和改进阶段都需要大量的投资。这使得验证正在解决的问题相对于潜在的商业价值是否真正值得解决变得非常重要。即使问题值得解决,也不一定需要 AI。可能有更简单的人类编码的启发式方法来解决这个问题。
开发人工智能解决方案只是成功的一半。另一半是如何实际使用和集成解决方案。例如,在开发预测客户流失的人工智能解决方案时,需要清楚地了解如何将流失预测纳入客户支持团队的工作流程。如果没有这种级别的集成清晰度,一个完美强大的人工智能项目将无法交付商业价值。
要成功退出这个阶段,以下断言需要为真:
- 如果成功交付,人工智能项目将产生切实的商业价值。
- 没有更便宜的替代方案可以解决具有所需精度阈值的问题。
- 有一条清晰的路径可以将人工智能建议整合到现有流程中以产生影响。
以我的经验来看,项目的早期阶段有着比现实更高的期望值。杀死一个形式不良的项目可以避免团队构建“寻找问题的解决方案”
2.数据可用性:“我们拥有构建它的数据。”
在漏斗的这个阶段,我们已经验证了问题值得解决。我们现在需要确认数据的可用性,以建立人工智能项目所需的感知、学习和推理能力。数据需求因人工智能项目的类型而异——项目构建分类智能的要求将不同于提供建议或排名的要求。
数据可用性广义上解释为具有正确的质量、数量和特性。正确的质量是指数据样本是我们试图建模的现象的准确反映,并满足诸如独立和同分布的属性。常见的质量检查包括发现数据收集错误、不一致的语义和标记样本中的错误。正确的数量是指需要可用的数据量。一个常见的误解是训练 ML 模型需要大量的数据。这并不总是正确的。使用预先构建的迁移学习模型,可以从很少的数据开始。此外,更多的数据并不总是意味着有用的数据。例如,10 年的历史数据可能不能真实反映当前的客户行为。最后,需要有正确的特性来构建模型。这是典型的涉及 ML 模型设计的迭代。
要成功退出此阶段,以下断言需要为真:
- 所需要素的数据集可用
- 相应的数据集满足质量要求
- 这些数据集中有足够的历史数据样本
根据我的经验,项目经常在这个阶段被搁置。缺少所需的功能,应用程序团队可能需要几个月的时间来收集数据集。
3。模型培训—“项目符合准确性阈值”
在这个阶段,我们已经确认了数据是可用的,并且已经迭代了 ML 模型特征。现在,是时候验证一个模型是否真的能够满足所需的精度阈值了。训练是一个迭代过程,其中 ML 算法、模型配置、数据集、输入要素的不同组合被反复尝试,目标是满足精度阈值。培训是资源密集型的,在给定大数据集的情况下,基础设施容量可能成为限制因素。此阶段验证使用现有基础架构资源或在可行的云预算内构建模型是否可行。
在训练阶段,当团队已经获得高得令人难以置信的精确数字时,就有可能出现“假警报”!在兴奋之前,仔细检查训练和验证数据集是否有重复样本是很重要的。此外,有时初始测试可能是有希望的,但可能不会推广到整个数据集。在训练之前对数据集进行随机化有助于避免准确性变化的过山车。
为了成功退出这一阶段,人工智能项目在训练后能够达到要求的精度阈值。
4。结果公平性——“生成的结果不是垃圾输入,垃圾输出。”
我们已经确认该项目可以满足精度阈值。现在,是时候验证生成的结果实际上是公平的 w.r.t .偏见,可解释性,以及对隐私和数据权利法规的遵从性。
确保人工智能推荐的公平性是一个重要的研究课题。大多数数据集天生就有偏见,可能无法捕捉所有可用的属性。理解数据集的原始目的和假设非常重要。另一种常见的偏见形式是代表性不足,例如,贷款承销应用程序没有针对特定类别的用户或收入范围场景进行培训。评估模型性能很重要,不仅是为了整体准确性,也是为了各种数据切片。
人工智能解决方案仅仅精确是不够的——它们需要可解释,即算法如何得出结论。一些使用自动化决策工具的受监管行业需要向其客户提供有关生成结果的有意义的信息。可解释性可以以不同的形式支持:结果可视化、特征相关性、假设分析、模型因果可解释性。
要成功退出这个阶段,以下断言需要为真:
5。运营健康—“已准备好投入生产—不是一个科学项目”
最后一个阶段是确认操作适应性。并非所有的项目都需要同样的操作严谨性。我根据训练和推理是在线还是离线,将项目分成一个 2x2 的矩阵。离线训练和推理是最容易的,而在线训练需要强大的数据管道和监控。
运营适应性有三个核心维度:模型复杂性、数据管道稳健性和再培训治理。复杂的模型在生产中很难维护和调试。关键是在简单性和准确性之间找到恰当的平衡。与更精确的复杂模型相比,不太精确的简单模型,但由于过度拟合,可能无法推广到新的数据样本。类似地,由于不断变化的数据模式、质量问题和非标准的业务度量,数据管道的管理也很复杂。最后,重新训练需要考虑由于数据分布和特征语义的变化而导致的准确性变化(称为概念漂移)。
要成功退出此阶段,以下断言需要为真:
- 模型已经过优化,在复杂性和准确性之间取得了恰当的平衡
- 数据管道是健壮的,具有所需的监控级别
- 为模型再训练实施正确水平的数据和概念漂移监控
总而言之,要在人工智能项目中取得成功,团队需要快速失败!5 阶段转换漏斗为人工智能团队提供了一个词汇表,用于向业务团队传达项目的状态,用一系列已知的未知因素取代他们对这些项目的黑箱认知。该漏斗还有助于识别项目中的常见下降阶段,这些阶段是潜在的改进领域。在一个快速失败的文化中,人工智能的墓地因其学到的可以应用于未来项目的经验而闻名。
关注 获取我即将发布的关于 Data+AI 的博客通知。管理数据+人工智能在生产中的策略,勾选 解开数据
文章原载于TechCrunch
大鲸迁徙路线中觅食点的检测
变更数据
大鲸追踪记录中的停止检测与移动的熊猫

图片由作者提供。中纬度大鲸觅食点探测
在这个演示中,我将解释如何在北大西洋大鲸的迁徙路线中发现觅食点。在由 席尔瓦等人(2013) 撰写的论文中,作者解释说,巨头鲸长时间保持在中纬度觅食[1]。在这里,我们将预设参数,可以找到这些提到的中纬度地区的点,这是指相对更接近亚速尔群岛。在第一篇评论中,我发表了 " 大鲸迁徙路线的时间过滤器 " ,你可以根据 2009 年这一年的过滤器来可视化大鲸的移动模式。
在 Silva 等人(2013 年)的出版物中,作者使用状态空间模型(SSSM)来识别动物行为。在这篇综述中,我将测试 python 库中开发的一种不同的方法,该方法使用时间和搜索电台参数来移动熊猫。事实上,分析结果正如预期的那样,它检测到了动物在中纬度地区的行为。请注意!动物行为的参数很关键,必须由生物专家提供。在我的演示中,由于我的生物和生态研究背景,我表达了我对动物行为的常识,但考虑到我是地理空间方法论方面的专家,而不是生物学方面的。
在 800 米的搜索范围内,用于觅食点检测分析的参数在 5 分钟和 110 分钟之间。如果您想查看不同参数的更多分析,您可以参考文章 蓝鲸 GPS 跟踪中的觅食点 和 鸟类迁徙 GPS 轨迹中的停止检测—移动熊猫& KeplerGl 。
“这个演示是北大西洋大鲸洄游路线运动分析的第二部分。还有更多的观点需要审查,如停止分段。在第三篇综述中,我将发布一个带有停止分割分析的演示,以证实大鲸的觅食行为”
在下一张地图中,你将看到参数是如何(根据我的常识)显示中纬度大鲸鱼的觅食行为的。研究提到,为了节省迁徙的能量,巨头鲸更喜欢在亚速尔群岛附近的觅食【1】。

图片由作者提供。在大鲸迁徙路线的中纬度发现觅食点
目前,很高兴知道算法正在工作,并且确实代表了大鲸鱼专家对它们迁徙路线的看法。但从科学的角度来看,不断质疑和批评这些结果,而不是把它们作为基本真理,总是好的。这就是为什么我将在第三个与觅食点分割相关的演示中继续分析大鲸鱼的迁徙路线,以更批判性和可视化的方式确认鲸鱼的觅食行为。
“如果你对动物行为分析感兴趣,有一种软件正在开发中,可以帮助动物跟踪研究。看看野生动物追踪器”
动物行为分析是保护区管理决策的重要手段。它有助于回答以下问题:保护区的适当界限是什么?为什么我们必须保护指定的范围?在保护区内,我们必须对渔业进行哪些监管?
数据
本演示中使用的数据集对应于亚速尔群岛大鲸卫星遥测程序。它可以在 Movebank 中找到,并且是在非商业性知识共享许可下使用。
练习
请注意,这个分析对应于已经发表的 巨鲸迁徙路线 时间过滤器的第二部分。因此,您可能需要引用相同的名称,但无论哪种方式,您都可以遵循以下文本。
首先,我们导入库
import pandas as pd
import geopandas as gpd
import movingpandas as mpd
from shapely.geometry import Point
from datetime import datetime, timedelta
from keplergl import KeplerGl
然后,我们读取数据集
fp = r’data/azores_great_whales.geojson’
geodata = gpd.read_file(fp, driver=’GeoJSON’)
我们准备geodata桌
# preparing data
geodata[‘t’] = pd.to_datetime(geodata[‘timestamp’])
geodata = geodata.set_index(‘t’)# setting individuals
geodata[‘id_whale’] = [‘w’+str(idwhale) for idwhale in geodata[‘ind_ident’].to_list()]# time attributes
geodata[‘year’] = geodata.index.year
geodata[‘month’] = geodata.index.month
我们准备一个geostops表,包含我们想要的 2019 年的子集
# prepare tables for visualization
geostops = geodata[[‘timestamp’, ‘long’, ‘lat’,’id_whale’, ‘year’, ‘geometry’]]subset = [2009]geostops = geostops.loc[geostops[‘year’].isin(subset)]geostops[‘year_id’] = [‘Year ‘+str(year) for year in geostops[‘year’].to_list()]
在这一部分中,我们定义了基于参数分钟和以公里为单位的搜索电台返回觅食站的函数
def get_stop_point_traj_collection(moving_df, traject_id_column, Minutes, searchradio):
all_stop_points = gpd.GeoDataFrame()
# create a traj collection with movingpandas
traj_collection = mpd.TrajectoryCollection(moving_df, traject_id_column)
for i in range(len(traj_collection)):
# create a stop detector
detector = mpd.TrajectoryStopDetector(traj_collection.trajectories[i])
# stop points
stop_points = detector.get_stop_points(min_duration=timedelta(minutes=Minutes), max_diameter=searchradio)
# add ID
stop_points[‘tag_id’] = [tag.split(‘_’)[0] for tag in stop_points.index.to_list()]
all_stop_points= all_stop_points.append(stop_points)
return all_stop_points
现在我们用geostops表应用该函数
whale_stops = get_stop_point_traj_collection(geostops, ‘id_whale’, 5, 800)
然后,我们计算在觅食点停留的时间
# Duration of stops
whale_stops[‘duration_m’] = (whale_stops[‘end_time’]-whale_stops[‘start_time’]).dt.total_seconds()/60# Between 5 and 110
whale_stops = whale_stops.loc[whale_stops[‘duration_m’]<=110]# remove datetime format for whale stops
whale_stops[[‘start_time’, ‘end_time’]] = whale_stops[[‘start_time’, ‘end_time’]].astype(str)
可视化
为了可视化,我们使用开普勒格尔。我们继续创建一个实例并添加数据。
# Create KeplerGl instance
m = KeplerGl(height=600)m.add_data(whale_stops, ‘Whale stops’)
最后,你保存地图并像我一样使用在觅食点花费的时间来配置它。栏目是duration_m
m.save_to_html(file_name=’index.html’)

图片由作者提供。中纬度地区的觅食点
结论
正如演示所展示的,该算法正在检测中纬度的觅食点,考虑到参数表征了大鲸鱼的觅食行为。这不是一个基本事实,它可能真的需要由海洋生物学领域的专家来分析。这只是一个演示如何使用该算法的练习。
建议
当你使用这种算法时,进行测试。参数的变化会在不同的位置产生不同的结果,因此您可能需要通过 critic view 真正观察和定义适当的参数。正如我之前建议的,与海洋生物学领域的专家一起测试这种算法是合适的。然而,通过观察轨迹中的移动,你已经可以知道巨型哺乳动物是在四处寻找食物还是在直线移动,所以这是很好的指导。
如果你有更多的问题,或者在你的分析或项目中需要帮助,你可以在我的个人简介中找到我。
参考
[1]席尔瓦·马、彼尔托·R、琼森·I、鲍姆加特纳·MF、桑多斯·RS(2013 年)。北大西洋的蓝鲸和长须鲸暂停春季迁徙,前往中纬度地区觅食:为旅途积蓄能量? PLoS ONE 8(10): e76507。https://doi.org/10.1371/journal.pone.0076507
生存分析:浴盆形寿命中死亡率的力量
Python 中的参数生存分析简介

墨西哥万圣节亡灵节 Pixabay 上的免费照片
本教程将介绍生存分析及其广泛的范围。生存分析适用于处理时间相关数据的所有领域:医学、生物学、工程学、市场营销、金融和许多其他领域。数据科学家作为生存分析师的角色,会涉及到与临床试验、客户流失、罗马皇帝暴死前的时间、产品或系统的故障率以及无数其他情况相关的问题:“什么时候会发生,失败的风险或成功的机会有多大?”在第一章的介绍之后,我们将在第二章探索一些例子——然后用浴缸形状的寿命来完成教程。
- 什么是生存分析?
- 死亡率和危险率的力量
- —系统故障
- 通过实例进行参数生存分析
- —示例:指数寿命模型
- —示例:威布尔寿命模型
- —浴缸形状的寿命
1.什么是生存分析?
1.1 事件时间分析——概念
首先:什么是死亡之力?它是生存到某一时刻后,在该时刻死亡的条件概率。在精算学中也称为死亡强度或瞬时死亡率。在不太关心预测向来世过渡的领域,它更好地被称为风险率 。
这听起来好像我们将要讨论的数据科学方法只涉及一种类型的问题:从保险公司的角度看,生物退出的时间。
远非如此。我们希望从中提取分析洞见的事件类别出现在不同的领域,如医学治疗和临床试验、社会学、产品开发、人寿保险、生物学和生态学、工程学、刑事累犯、信用风险、政治学(例如:独裁统治的生存时间)和历史(例如,罗马皇帝暴力死亡的平均时间是多项研究的主题:“最危险的职业”;以及罗马帝国:生存分析|皇家学会)。

朱利叶斯·凯撒遇刺,戈登·约翰逊 Pixabay 上的免费矢量图作者 GDJ
换句话说,生存分析的方法可以处理任何可以想象的情况。生存分析是对时间序列分析的补充。
生存分析的重点是关注目标事件发生前的时间——故障时间、生存时间或事件时间 — 及其相关风险。
它超越了死亡或系统故障的预测,也可以指不太确定的事件类型。感兴趣的事件可以是沿时间轴的任何现象:
- 第一次和第二次分娩的时间间隔
- 离婚前的时间:结婚和离婚的生存分析 (researchgate)
- 再次犯罪的时间:返回监狱的人
- 故障前时间:设备在其目标使用寿命或保修期内发生故障的风险
- 药物治疗或临床试验:药物的代谢吸收率;癌症治疗或移植后的 5 年存活率;任何疾病痊愈前的时间;接种疫苗后达到最大抗体计数的时间;抗体计数降至阈值以下的时间
- 输水管道的生存分析(awa.asn.au)
- 生物或生态事件发生的时间:昆虫种群发展的统一生存分析方法(nature.com);猎物的隐藏时间;捕食者的等待时间
- 客户流失或员工流失率:一定比例的客户或员工将离开企业或不再续订的时间
- 公司债务违约的时间
- 直到一半的单身女性候选人没有收到玫瑰,必须回家
在工程中,生存分析通常被称为可靠性分析。在经济学中,久期建模。在社会学中,事件历史分析。
表达生存分析通用范围的更全面的同义词是时间-事件分析。感兴趣的事件可以是任何依赖于时间的事件。
生存分析的方法有三种基本类型:
- 非参数:例如,Kaplan-Meier 估计量——它不假设风险函数的形状,也不假设协变量或外生回归变量的影响
- 半参数:例如,Cox 模型——它对风险函数的形状没有任何假设;但它确实对协变量以及它们如何影响风险函数做出了假设
- 参数:关于风险函数的假设由概率分布表示,如指数、威布尔、对数逻辑、Gompertz、极值、瑞利或对数正态模型
在今天的教程中,我们将重点放在参数生存分析上。从概率分布的其他应用中,我们已经知道了它的相当多的工具。

1.2 参数生存分析的要素
在我们计算具体的例子之前,我们需要学习一些将成为我们焦点的技术术语:我们希望从数据中提取的分析描述符。
以下一些术语是由可靠性分析和精算学创造的。请记住,这两个字段所称的故障也可以表示其他字段中任何感兴趣的中立事件。对于精算师和可靠性工程师来说,感兴趣的事件恰好是系统的故障:机械的、电子的或生物的。你可能需要调整你的思维过程,将这些传统词汇翻译成更适合你要研究的事件的词汇。但是功能工具将适用于所有类型的时间相关事件。
- CDF(t):累积分布函数 =寿命分布函数=表示到时间 t 将失效的所有单元的分数;相反,表示一个随机抽取的单元在时间 t 前失败的概率。我们也可以读为“事件”,而不是“失败”:在时间 t 前将受到感兴趣的事件影响的单元。
- pdf(t):概率密度函数 =事件密度=单位时间内的故障率
- SF(t)或 R(t):生存、幸存或可靠性函数= CDF = 1 的简单补数— CDF(t) =所有幸存机组的分数(保持运行;或者不受感兴趣的事件影响)至少 t 小时=事件将在时间 t 之后发生的概率
- 直到时间 t 的故障或事件:
- —如果 N 是样本数,则 CDF(t) * N 是直到时间 t 的故障(事件)数;
- —而 SF(t) * N 是幸存者的数量:在时间 t 时仍在运行的单位。
- AFR (t1,t2):时间间隔【T1,t2】内的平均故障率,简单来说就是间隔内统计的故障次数除以以月或天为单位测量的时间跨度
- h(t):风险函数,瞬时失效率,或死亡率。这是我们将要研究的生命周期模型的核心因素。
- —也简称为危险率或故障率。我们需要意识到,风险函数不一定是像平均故障率 AFR 那样的常数。危险函数是一条曲线,可以根据其潜在“危险过程”的行为随时变化,因此其瞬时故障率绰号。
- —它测量在时间 t 之前仍然存在,但在下一个时刻 t*将失效的单元的故障率
- —危险率表示系统达到一定年龄时发生故障的倾向。它是一个条件故障率:在 t 时刻的故障,假设一个单元已经存活到 t
- —注意,危险函数不能解释为概率——它在区间[0;∞)是无限的。h(t)是故障分布的概率密度函数。
- —它可以计算为概率密度函数 pdf(t)和生存函数 SF(t)的商:

作者图片
- H(t):累积危险函数。类似于概率密度函数和累积概率函数之间的关系,可以对危险率 h(t)进行积分以获得 H(t)。
- 在可靠性分析中,故障率通常用特定的技术术语来表示:
- —1.0%/K = %每“千小时”的故障率= 1000 小时内 1%的故障率
- — 1.0 PPM/K =每千小时每百万的部件数(故障数)= 1000 小时内一百万个部件中有一个故障
- — 1.0 拟合=故障时间=每 10 亿小时 1 次故障
- 平均无故障时间 MTTF :整个群体无故障前所有时间跨度的平均值
- 一个单元存活 t 小时后的平均剩余寿命
2.通过实例进行参数生存分析
在这一章中,我们将通过几个例子,提取我们在第一章中讨论过的描述符,并解释它们。
2.1 故障率的形状
一个生存模型区别于其他模型的核心属性是其失败率的形状。我们区分:
- 恒定故障率
- 单调递增速率
- 单调递减率
- 不稳定的故障率,其中包括所谓的浴缸形状
我们将计算每种情况的例子。
2.2 系统故障:乘法法则

让我们以一个由 N 个组成元素组成的系统为例,例如控制第一艘前往火星的宇宙飞船中的火箭发动机的 12 个电子电路。每个电路在不同的升压阶段执行不同的任务。但是如果 12 个中的任何一个失灵,整个推进系统将会失灵。
假设任何电路在其操作使用的目标时间窗口内具有 0.999 的生存概率。他们最终的失败是不相关的,他们会独立地失败。单个组件的生存函数返回 SF(t) = 0.999。推进系统发生灾难的概率有多大?独立事件的乘法法则告诉我们,整个系统到时间 t 的生存概率是 S(t) = (0.999) = 98.8%。如果系统依赖于 100 而不是 12 个组件,其生存函数值将减少到(0.999) ⁰⁰ = 90.4%。
一艘宇宙飞船依赖成千上万的关键任务部件。因此,冗余成为一个不可避免的防护栏:我们的简化示例意味着,一个只有 100 个关键组件的系统将需要至少 9.6%的备份,前提是它们是独立的。但是,如果第一个组件的缺陷会触发相邻组件的级联,那么冗余储备就必须更高。
2.2 指数分布
指数分布是参数失效时间模型中最基本的变量。它假设一个常数失效率,λ>0。

为了在 SciPy 中实例化指数分布,我们需要将 SciPy 的标度参数定义为故障率λ的倒数。 SciPy 对其所有分布使用比例参数;指数分布也不例外。然而,一个更典型的指数分布的定义,如维基百科所示,会用失败率和来参数化它(也称为的倒数)。
- SciPy: expon(loc,scale),其中 scale = (1 /故障率λ)
比例参数代表平均故障间隔时间。
为了获得危险函数 h(t ),我们应用我们在第 1.2 章中看到的定义:
- h(t) = pdf(t) / (1 — CDF(t))
如果你看一下上面显示公式的截图,你会看到这个商将简化为 h(t) = lambda。
指数分布是具有非时变失效率的寿命分布的唯一情况。这种恒定性就是指数随机过程的定义。在任何时间 t,新的缺陷出现在相同的水平λ。指数分布是无记忆的。
这当然是一个大胆的假设。但是,如果分析集中在一个足够窄的时间窗口,以排除磨损效应,它可以与现实相一致;也排除了所谓的婴儿死亡阶段——一个新过程启动后,但在通过消除其早期缺陷而稳定下来之前的时间窗口。因此,指数分布可以应用于我们将在下面进一步讨论的所谓浴盆曲线模型的中心部分。
我们飞往火星的宇宙飞船的一种电路板将在发射后几个小时打开。它们将在升空过程中免受机械应力的影响。这次旅行,包括返回地球,将需要 36 个月。制造商知道这段时间太短,不会因化学或机械老化而导致磨损。但在航行过程中,宇宙辐射会随机击中一些电路。实验室中的辐射测试让我们预计电路将以 0.06%/K 的速率烧毁。该速率将是恒定的,因为在第一天之后,当宇宙飞船离开距离地球 58,000 公里的范艾伦辐射带时,辐射暴露量将仅发生最小量的变化。
翻译:每“千小时”0.06% = 0.06/(100 * 1000)。这是我们可以插入到模型中的故障率λ。在 SciPy 的符号中,我们使用它的倒数 1/lambda 作为比例参数:1,666,667。同样的 1.67 米小时也代表任何电路的平均无故障时间。
在第 6 行,我们将我们想要分析的时间范围制成表格。
第 7 行实例化了 SciPy 的指数分布。位置参数被设置为零:电路可以在它们被接通时立即烧断,在时间零之后没有等待期。比例参数设置为速率λ的倒数。
在第 8 行中,我们通过在累积分布函数中插入时间 T 的范围来评估累积分布函数。我们在第 9 行的字典中收集时间 T 和 cdf 结果。然后,第 10 行中的列表“理解”打印词典。
第 15 行根据指数分布计算平均失效时间,并确认它等于 1/λ。

作者图片
在运行 20,000 小时后,即航行 833 天后,1.19%的电路将遭受高能粒子的击倒。这表明,低于 2%的储备将能够抵消辐射风险。

作者图片
不出所料,我们观察到 cdf 曲线中的累积故障呈线性上升;和恒定危险函数。
这证实了指数分布以恒定的失效率运行。

我们的下一个评估计算分位数。多少小时后,1.0%的电路会显示蓝屏错误?在第 2 行到第 5 行,我们准备了一个概率范围,我们将把它提供给第 6 行的百分点函数。第 6 到 8 行收集字典中的分位数和相关概率,第 9 行的 list comprehension 逐行打印。
该表报告了 16,751 小时的 1%分位数。

作者图片
系统故障
在第 2.2 章中,我提到了乘法法则:如果一个系统的 N 个组件中只有一个失效,那么这个系统的生存概率等于特定组件生存函数的乘积。如果 N 个组件在时间 T 时仍以概率 S 起作用,那么系统在时间 T 时的生存概率 S 将是个体生存概率的乘积。

作者图片
而系统的失效率是各个失效率的之和。如果所有 N 个部件的故障率都相同,那么系统(我们的宇宙飞船)的故障率将为 N λ,也遵循指数分布。其平均无故障时间 MTTF 将是 1/(N λ)的倒数。这被称为指数闭包性质。
让我们把这转化为我们的例子。如果宇宙飞船运行 100 个独立的、相同的电路板,每个电路板的 lambda 比率报告为 0.06%/K,并且当第一个到期时系统将会崩溃,那么飞船在运行 T 小时内在太空中倾覆的风险会有多大?

作者图片
系统的故障率 LL 仅仅是单个故障率 l 的 N 倍。在运行 5000 小时后,飞行 7 个月后,太空沉船的风险已经达到近 26%——除非备份电路可以在第一个火花开始飞起来时立即启动。
分配拟合
在演习开始时,我们报告说,实验室的辐射测试提供了一个失败率。具有单一参数的指数分布是从观测数据中最容易得到的模型。我们通过将失败次数除以观察小时数来获得参数估计值。
审查
当我们考虑截尾时,失效率的计算变得更加复杂。
当电路被测试 T 个小时后,其中一些电路将被记录下它们失效的准确时间 T。幸存者将在稍后的某个时间耗尽精力。但我们无法确定它们何时到期。这种源数据问题被称为类型 I 的右删失:测试时间 T 是固定的,但是一些单元将存活超过 T 的未知时间。
另一个不同的测试——一个在时间上开放的测试,但是当第 k 个缺陷被观察到时就会结束,无论它何时出现——报告II 型截尾结果。
在这两种情况下,我们都必须调整估计的故障率,以获得对所有电路总数的更准确的估计。审查是我将在下一篇文章中讨论的一个方面。
2.3 威布尔分布
指数模型基于这样的假设,即没有磨损机制会随着时间的推移而提高故障率。这是一个应该仔细推敲的假设。在我们的宇宙飞船例子中,我们有理由假设这将是一个碰运气的游戏:一个电路可能会也可能不会被单个高能粒子的碰撞所破坏。
但是,较小的辐射损伤的积累可能会成为一个磨损过程,需要我们的生命周期模型中不断增加的终止率。

火星红色星球,由 WikiImages 拍摄 Pixabay 上的免费照片
到达火星后,我们的设备将暴露在沙尘暴和陡峭的温差中。这些肯定会导致缺陷的增加。
1951 年,瑞典工程师恩斯特·威布尔发展了现在以他的名字命名的分布。这是对各行各业需要一个能够描述真实世界流程的模型的响应,而真实世界的流程通常不会表现出恒定的故障率。威布尔分布可以反映
- 剔除有缺陷的部件时,加工速度降低(形状参数< 1);
- and also wear-out or aging processes with increasing rates (shape parameter > 1)。
- 如果威布尔形状参数设置为 1,则分布简化为一种特殊情况:指数分布。
- 如果形状设置为 2,它还包括瑞利分布作为另一种特殊情况,这将产生线性增加的危险率。

SciPy . stats . Weibull _ min—SciPy v 1 . 7 . 1 手册
SciPy 提供名为 weibull_min 的 Weibull 模型。维基百科用形状和比例参数来定义它。在 SciPy 中,您可以通过在形状和比例之间插入一个位置参数,将其转换为一个三参数威布尔分布。形状和比例必须是正数。
- 该位置设置 x 轴上观测开始的最小时间。
- 标度是最大值和最小值之差;换句话说,最大时间 tmax =位置+规模。标度参数也被称为特征寿命:最小和最大时间之间的跨度。
与指数情况下的λ不同,威布尔风险函数不能从单个参数中读出。它依赖于时间,并受形状和比例的影响:

作者图片
最初,我们将假设我们已经确定我们将在火星表面上使用的电路板的寿命将遵循威布尔分布。寿命显示出增加的故障率。稍后,我们将研究分布拟合来证实最初的假设。
估计特征寿命为 50,000 小时。形状参数为 1.5。我们将位置参数设置为 0——没有等待时间:一旦电路所在的设备暴露在恶劣环境中,电路就可能停止工作。

作者图片

作者图片
在磨损阶段,危险函数的斜率变得更陡。
形状
威布尔形状参数控制曲线的上升或下降。
- 0 < shape < 1 : decreasing hazard rate
- shape = 1 : constant failure rate
- shape > 1:增加危险率
- 形状= 2:瑞利分布:风险率线性增加
- 3 ≤形状≤4:CDF 曲线开始类似于正态分布的钟形曲线,尽管具有不同的偏斜度和峰度
特征寿命
缩放参数充当一种锚点:

作者图片
我们知道,68%遵循正态分布的观察值位于其平均值的 1 个标准差以内。在任何威布尔分布的情况下,不管形状参数如何,63.2%的观测值低于其特征寿命。
系统故障
如果一个系统由 N 个可以用相同的威布尔形状参数建模的独立元件组成,并且当第一个元件损坏时系统将崩溃,那么系统的危险率也遵循具有该形状参数的威布尔分布。
系统的特征寿命是一个更复杂的表达式:

作者图片
我们的任务如下:

wiki images 拍摄的火星漫游太空旅行 Pixabay 上的免费照片
我们的火星探测器依靠四块电路板来控制仪器。它们的寿命曲线可以用威布尔形状参数来建模,制造商在测试期间将所有四块板的威布尔形状参数固定为 1.5。这些主板都有不同的典型寿命,有 8,000、10,000、11,000 和 14,000 小时,因为它们包含不同数量的处理器。数字越大,棋盘越早到达临界点。
我们可以期待火星车具有哪些耐力?

作者图片
列表 comprehension Chars 通过实现上面所示的公式来计算漫游者的特征寿命:4058 小时。
描述火星车的威布尔模型告诉我们,它预测的平均到期时间只有 3664 小时。

作者图片
拟合威布尔分布
在本章开始时,我们假设制造商已经为我们确定了形状和特征寿命。现在让我们快速了解一下分布拟合。制造商的工程团队已经向我们提供了他们测试的原始数据,将由我们来确定与他们的数据相匹配的寿命分布。
在这个练习中,我创建了一个由 100 个观察值组成的合成集合:威布尔分布的变量,夹杂着一些随机抖动。然后我会演示 SciPy 的分布钳工法。
我之前的一篇文章(概率分布和用 Python 的 SciPy |走向数据科学的分布拟合)讨论了一个自动拟合脚本,它针对源数据测试了 60 种不同的候选分布。今天,我们把任务限制在寻找一个分布的参数,威布尔模型。
观察数据的数组在脚本中被称为 randWW。
- 在应用 SciPy 的拟合函数之前,我计算了概率为 0.632 的分位数。记住,这个分位数对应于威布尔分布的特征寿命。我将把它作为初步猜测提供给装配工。
- 在拟合函数中,我们将位置参数设置为零。 floc 中的前缀 f 告诉装配工保持用户定义值不变。根据经验,我建议尽可能修正位置值。你可能已经预先知道,失效过程将从零开始,就像我们的例子一样。如果不是,将观察值的最小值设置为位置参数。否则,装配工可能很难得出一个合理的结果。

作者图片
拟合函数将返回最小化预测误差的参数元组。在这种情况下,形状为 1.45 小时,特征寿命为 48,578 小时。
我们称之为 SciPy 的 Kolmogorov-Smirnov 拟合优度测试。

作者图片
其结果,0.401 的高 p 值,证实了观测数据与装配员发现的威布尔参数化密切相关。拟合是中等质量的(尽管它远远超过通常的 0.05 的显著性水平),而不是完美的,因为 100 的样本量很小,因此容易出现异常值。

作者图片
从单调到浴缸
威布尔过程模拟单调增加、减少或恒定的失效率。在其通常的参数化中,它没有反映最典型的失效过程:所谓的浴盆曲线。让我们试试看。
2.4 浴盆形寿命

Go Game,Alexas _ Fotos—pix abay 上的免费图片
许多过程和系统呈现出类似浴缸轮廓的寿命曲线。
- 它们早期的特点是废弃和浪费率下降。新产品或新生产流程在其初始阶段会经历一个高报废率的磨合或学习阶段。
- 随着时间的推移,质量控制措施会剔除薄弱环节或易出故障的流程步骤。更坚固的部件将决定下一阶段更低的故障率。
- 随后,末期将呈现出递增的终止率,该终止率沿浴缸形状的右壁上升。这是磨合期。组件或系统——机械的、电子的或生物的——在老化过程中会继续加速退化。

by tubath _ curve . jpg:wyatts 衍生作品:MC sush(talk)—tubath _ curve . jpg,公共领域,【https://commons.wikimedia.org/w/index.php?curid=7458336
- 中心阶段的特点是相对平坦的故障率。磨损导致的退化和系统初期解决的初始结构问题都不会对所谓的稳定故障期产生太大影响。失败确实会发生,但却是随机的。
2.4.1 指数化威布尔分布
指数化威布尔分布是少数几种足够灵活的分布之一,可以画出浴缸形状的风险函数。它将第二个形状参数,即指数因子,添加到威布尔-最小分布中。附加参数扩展了 is 曲线的灵活性,可以模拟恒定、递增、递减或浴缸形状。
方便的是,SciPy 通过它的子类 exponweib 使它可用。如果它的指数参数设置为 1,那么指数化威布尔就简化为它的特殊情况,威布尔最小分布。

SciPy . stats . expon weib—SciPy v 1 . 7 . 1 手册

作者图片
然而,出于实际目的,我发现很难找到一个参数组合,使蓝色危险函数的尖肘进一步向右移动。开始时故障率的急剧下降很难通过调整参数来克服,并且不太适合下降阶段持续更长时间的许多现实情况。
2.4.3 霍尔特分布
Hjorth 分布提供了一个适应性更强的浴缸曲线。
由于它在 SciPy 的目录中不可用,我们将其实现为一个新的发行版子类,该子类继承自 SciPy 的 rv_continuous 类。我们需要六行代码来完成它。
第 1 行显示的继承提供了很大的便利:我们只需要定义概率密度函数 pdf 或者累积分布函数 cdf(第 7 到 11 行)。然后,SciPy 的父类可以接管并通过数值积分或微分计算所有其他属性,如矩、百分点函数和生存函数。
Hjorth 分布取位置参数 m > 0,尺度 s > 0,形状参数 f ≥ 0。
如果形状参数被设置为零,则 Hjorth 分布被简化为 Rayleigh 分布。如果威布尔形状设置为 2,瑞利分布是威布尔分布的特殊情况。因此,Weibull 和 Hjorth 分布是一种表兄弟,两次删除。

作者图片
我们的重点是危险函数,为此我们正在寻找一个产生浴缸形状的设置。我们从位置 m = 20,比例 s = 1,形状 f = 0.1 开始

作者图片
在第 11 行代码中,我们将风险函数计算为概率密度函数和生存函数的商,这两个函数都来自我们的新子类 hjorth_gen 。

作者图片
我们有浴缸了。参数元组(m,s,f) = (20,1,0.1)为我们提供了风险率的蓝色曲线。
类似地,参数 tuple (3,1,3)会产生一个形状,它的右尾部有一个更适度的增加(左边是红色)。

作者图片
元组(2,47,0.33)将描绘浴盆曲线的更陡峭的增加。
现在我们可以开始评估 Hjorth 分布,其方式与我们评估其他具有恒定或单调失效率特征的分布的方式相同。
3.结论
我们已经知道,我们现有的概率分布知识可以转移到我们在参数生存分析中遇到的任务。
我们还没有触及可能影响我们的源数据的复杂性:删截和截断,这是生存分析中的两个核心问题,但我们在其他数据科学领域不太经常遇到。这将是未来文章中的一个主题。
Jupyter 笔记本可以在 GitHub 上下载:h3ik0th/param survival:SciPy 参数生存分析教程(github.com)
浓缩咖啡的强制双峰咖啡分布
咖啡数据科学
如果你试着打一个坏球会发生什么?
当讨论咖啡磨粒时,存在双峰分布或分布中的两个主峰的问题。这意味着你有很多不同大小的粒子。更高端的研磨机减少了分布,以适应更高斯的曲线,这种增加的均匀性被视为一件好事,正如在浓缩咖啡拍摄中所经历的那样。

假分布显示理想化的双峰分布。并不总是这么干净。
所以我很好奇,如果我强迫一个双峰分布,会如何影响口味?
这种兴趣部分源于想知道你是否能把一个糟糕的磨工变得体面。劣质研磨机的一个问题是,它们磨得太细或太粗——它们没有更好的调整。然而,如果你以不均匀的比率组合两个研磨级别,你能近似一个更好的研磨设置吗?
理论的
我开始考虑利用利基市场将两种截然不同的研磨粒度结合起来。所以我查看了这些设置的一些已知粒子分布(S0 和 S30S0 和 S20),以了解如果我在 mix 的两个设置下研磨,或者只是在两者之间的设置下研磨,分布会有什么不同?

组合 S0 和 S30 看起来是更好的选择,因为它给出了比组合 S0 和 S20 更双峰的分布。而且,S0+S30 比 S15 更双峰。我们可以在这里仔细看看:

在实践中
所以我在 S0,S15,S30 磨了一些豆子。然后我混合了 S0 和 S30。结果略有不同。S15 仍然具有与 S30 相似的分布。

绩效指标
我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。
最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和回味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。
拉镜头
我拍了些照片。我还拉了一个 S12 的镜头作为参考,因为 S12 通常是一个很好的设置,我已经在多次漫游中拨入。在这种情况下,比 S15 更好。S15 和 S0+S30 在味道上表现相似,但是 S0+S30 能够具有更高的 EY。


就拍摄时间而言,他们都有相似的时间。

我很感兴趣为什么 S0+S30 的 TDS 比 S15 高。假设研磨分布随着研磨设置线性变化,这并不完全正确。我感到惊讶的是,味道与 S15 相似,因为我预计味道会因 S30 的粗糙而不同。正如涡轮增压所经历的那样,较粗的研磨可能导致较高的提取率。
至于接下来的步骤,我认为用筛子筛出研磨分布中两个峰之间的音符并真正形成双峰分布会很有趣。
如果你愿意,请在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在媒和订阅关注我。
我的进一步阅读:
个人故事和关注点
预测 KPI:如何评估产品组合的准确性
MAPE、MAE 和 RMSE 等预测 KPI 不适合评估产品组合的准确性。让我们来看看几个新的指标:MASE、RMSSE、WMASE 和 WRMSSE。
作为预测者,我们的工具箱中有许多指标来评估预测的质量。每个指标(偏差、平均误差和 RMSE)都有利弊。但总的来说,当比较同一产品的两个模型时,我们知道实现较低偏差、MAE 和 RMSE 的模型是最好的。

实际上,供应链对逐个比较 SKU达到的精确度不感兴趣。因此,问题不在于逐个评估每个 SKU 获得的精度;但是如何评估整个产品组合的预测模型(或过程)的整体质量。在跟踪预测附加值时,预测模型和需求预测流程整体上也是如此(FVA,如(吉利兰,2010 年)所述)。
简而言之,由于我们只能改进我们可以衡量的东西,我们必须有一个衡量标准来评估产品组合预测的质量。
评估产品组合的准确性时的准确性幻象
让我们用一个例子来说明在看产品组合时,三个通常的度量标准(偏差、MAE 和 RMSE)的不相关性。
假设你负责预测六种产品。它们不可互换,同等重要(有价值),没有季节性,需要不同的供应资源。(测量偏差只对一组可互换的项目有意义;或者如果他们都使用相同的受限资源——作为共同的供应商或生产流程。)你要根据他们预测第 6 期需求的历史表现,选择你最喜欢的预测模型(A、B、C 或 D)(为简明起见,我们只看一期)。在表 1 中,A、B、C 和 D 之间的差异用蓝色突出显示。

表 1 预测比较。
在表 2 中可以看到在第 6 阶段达到的常用指标(偏差、平均误差和 RMSE)。

表 2
与任何其他预测相比,预测 C 以相当大的优势胜出(它具有最低的 MAE 和 RMSE,其偏差最接近于零)。此外,预测 A 在所有指标上都是最差的。
根据我的咨询经验,大多数供应链经理会通过查看 MAE 和 Bias 来评估预测质量。根据这两个指标,他们应该选择预测 C 作为第 6 阶段的最佳预测。
这是最明智的选择吗?
让我们比较一下预测 A 和其他三个挑战者。
- 预测 B 在产品#4 上犯了一个巨大的错误(这甚至可能导致对供应商的一些牛鞭效应),在产品#6 上犯了一个较小的错误。这对 MAE 没有影响,因为总绝对误差仍然相同(A 和 B 表现相同)。看看 RMSE,预测 A 更糟,因为它在第 6 项上犯了一个巨大的错误(这是因为 RMSE 对更重大的错误很敏感)。尽管如此,作为一名供应链从业者,我认为预测 A 比预测 b 更好。后者在第 4 项上有很大的误差(第 6 项上较小的误差没有补偿它)。
- 与观察到的通常需求范围相比,预测 C 在项目#1、#3 和#5 上产生相对较大的误差。它仅改进了项目#6 的预测,但是考虑到观察到的需求变化和项目#6 的平均值,这不是这样的改进。同样,在实践中,大多数供应链计划者通常更喜欢 A 而不是 c。
- 预测 D 对产品#3 做出了更差的预测,其误差已经很大了(绝对误差已经是 14)。更大的误差可能会导致更多的销售损失。另一方面,D 对产品#4 做出了更好的预测,但它已经是准确的了(对于每期销售约 13 个单位的产品,误差为 2 个单位)。这种额外的准确性可能不会导致更少的过时成本,只是略微节省了持有成本。我认为 A 和 D 很接近,但 A 应该是首选。
简而言之,我们看到通常的度量三重奏(Bias、MAE 和 RMSE)不适于区分产品组合中好的和坏的预测。更糟糕的是,在某些情况下,这三人组会建议我们选择最糟糕的预测(我称之为准确性幻影)。
机器学习弱点
这种准确性幻影尤其糟糕,因为我们通常使用 MAE 或 RMSE 来训练机器学习算法。随着机器学习算法优化整个数据集的误差,它们将更喜欢预测 C 而不是预测 A(因为 C 具有较低的 MAE 和 RMSE)。【1】另一方面,统计模型通常独立地优化每个时间序列,从此完全避免了准确性的幻影。机器学习从业者应该特别关注选择正确的度量标准,避免这种准确性幻觉。**
【1】我这里假设我们训练的是全局机器学习算法。也就是说,一次对所有产品训练一个算法(与为每个时间序列训练一个单独的模型相反)。
对完美投资组合度量的不可能的追求
我们需要找到一个新的(一组)指标来充分评估产品组合预测的质量。
**完美的指标应该是:
- 可操作的。供应链是一个不断做出决策的生命体。为了做出适当的决策,供应链需要得到可靠的预测流程的支持。从今以后,预测指标应该使预测者(和计划者)能够提高供应链的计划能力。通常,计划者会查看最大的预测违规者,以执行纠正措施。可操作的指标是指向有意义的违规者的指标。
- (容易)解释的。你希望使用计划者和管理层都能理解的简单指标。简单来说,你想通过查看一个简单的 KPI 来知道预测是好是坏。
- 不是线性的。小的预测误差会导致库存过多或消耗少量安全库存。重大预测误差会导致库存积压或销售损失。从数学上来说,我们说供应链成本不是线性的:错 50 个单位比错 5 个单位要糟糕十倍以上。由于供应链成本不是线性的,因此错误惩罚也应该是线性的。
- 对异常值不敏感。供应链需求数据集通常充满异常值:我们不希望我们的指标对这些数据反应过度。
异常值敏感度与惩罚重大错误 我们需要在抵制异常值的指标(通常是基于绝对误差的指标)和惩罚更重大错误的指标(通常是基于平方误差的指标)之间进行权衡。一个解决办法是使用多个指标的平均值。
- 不偏不倚。任何非对称指标(即,不会对超出和低于预测的指标进行同等惩罚)都会导致有偏差的需求估计。有偏见的预测会损害其他计划者和供应链职能部门对你的预测的信任(并最终损害其依从性)。简而言之,如果你持续超出预测 5%,很快生产计划员将生产 95%的计划,供应计划员将订购 95%的所需原材料,等等。这将助长不信任的恶性循环。我经常听到这样一个问题,“我们是否应该高估需求,因为丢失一件商品的成本要高于多买一件商品的成本?”库存政策、服务水平目标和生产目标应考虑供应可变性、预测误差、交付周期、各种成本和盈利能力,而不仅仅是(vande put,2020)中解释的需求预测。你的需求预测应该是对未来需求的无偏估计。然后你可以根据其他众多因素或多或少地生产。简而言之,正确的服务水平目标应该适当地保护您免于缺货,而不是有偏见的预测。
- 加权。并非所有产品都同等重要。有些价值更高,有些带来更多利润或承担更多风险。这些关键产品应该得到更多的关注(无论是来自规划者还是机器学习算法)。简而言之,关键产品上的错误应该比无关紧要的 SKU 上的错误受到更多的惩罚。不知何故,我们希望在指标中整合优先化理念,这是许多计划者使用的 ABC 分析的核心。
加权指标
我们可以很容易地对任何指标进行加权,将每个误差乘以所需的权重,如(Vandeput,2021)中所述。数学上,我们有:加权误差= w x 误差其中 w 是产品的重量。为了表示加权度量的使用,我们在其名称前添加字母 W(例如,WMAE 或 WRMSE)。
- 按比例缩放。我们应该惩罚与在每个时间序列中观察到的通常需求相比大的预测误差。如果预期需求为每期 10 件的时间序列比通常需求为每期 100 件的时间序列出现 50 件的偏差,则应受到更多惩罚。请注意,我们可以对每件物品进行称重。权重与产品的重要性有关,而比例则与每种产品的需求量有关。
我们将在下一部分讨论衡量指标。** - 不可破解。最后,预测者不应该人为地做出错误的预测,从而得出更好的指标。除此之外,我们应该注意没有一个项目得到负的权重(如上所述)。如果您将每种产品的权重设置为其单位利润,您可能会遇到这样的情况:某些项目在总准确性指标中的权重为负。这意味着对该项目的预测越差,指标就越好。**
缩放指标:MAPE、sMAE、MASE 和 RMSSE
将预测误差换算成“正常需求”非常简单。让我们讨论一下如何衡量每种产品的预测误差的三个想法。
想法 1:根据预测范围内的需求进行扩展(MAPE)
我们可以通过将每个产品的预测误差除以其观察到的需求(在预测范围内观察到的)来进行简单的缩放。这是 MAPE 背后的(坏)想法。我们将 MAPE 定义为:

其中预测范围从时段 n+1 开始,直到 n+h.
局限性
- 如(Vandeput,2021)所述,使用 MAPE 会导致选择有偏差和扭曲的预测。
- 在预测范围内,我们有零需求的风险,导致不确定的预测误差。
- 由于 MAPE 使用未来需求来衡量预测误差——从而揭示未来的一些情况——这一指标不能用于训练机器学习算法。
想法 2:基于历史需求的扩展(sMAE)
另一个想法是根据每个项目的历史平均需求来调整。我们将获得一个度量,如缩放平均绝对误差(sMAE),如(彼得罗保罗斯等人,2015 年)中所述:

sMAE 已经比 MAPE 好了,因为我们避免了除以 0 的风险和(大规模)有偏见的预测的风险。因为我们只使用历史信息来衡量误差,所以我们可以在机器学习算法中使用 sMAE。
限制
- 正如(Svetunkov,2019 年)和(Hyndman 等人,2006 年)所解释的那样,如果你有需求趋势(供应链中几乎总是如此),基于每个项目的历史平均值来衡量每个项目的误差可能会造成扭曲。
- 对于季节性产品,为了避免在计算历史平均值时偏离比例,您必须始终密切注意包括整个季节性周期。
想法 3:基于历史(原始)误差(MASE 和 RMSSE)的缩放
我们可以将预测误差换算成历史需求平均值,而不是历史水平的原始误差。简而言之,我们将根据每一项的可预测性来衡量每一项。为此,我们将使用(Hyndman 等人,2006 年)中介绍的平均绝对对称误差(MASE)和(MOFC,2020 年)中介绍的均方根对称误差(RMSSE)。
**
历史的地平线一直延伸到时期n*;并且预测范围从时段 n+1 开始,直到 n+h.*
解读。 MASE 和 RMSSE 可以解释为预测误差与每个项目可预测性之间的比值(任何小于 1 的值都意味着模型在增值)。我们可以将 1 — MASE(或 1 — RMSSE)解读为与原始基准相比误差减少的百分比(任何负值都意味着模型比基准差)。RMSSE 和 MASE 应被解释为模型相对于原始预测的加权预测增加值(用%表示,越低越好)。
正如(Vandeput,2021)中所建议的,RMSSE 的降低可以解释为最大误差的降低。MASE 的减少可以表示为总误差的减少。**
加权。在一个数据集上平均一个缩放指标(MAPE、sMAE、sRMSE、MASE 或 RMSSE)将而不是*产生一个有意义的指标。你可能会比较等级的苹果和等级的梨:每一种产品都被认为同等重要,每一个销量都被标准化了。这是没有意义的:在大批量、高价值的产品上实现低规模的指标比在小批量、低价值的产品上实现良好的准确性更重要。因此,我们应该权衡衡量标准,将产品的重要性和总销量考虑在内。不幸的是,对于如何衡量销售量的衡量指标,没有什么灵丹妙药。一种方法是根据每个 SKU 的(最近)历史需求量对其进行加权。这是在(财政部,2020 年)中所做的,其中每个 SKU 根据其最后 4 周的收入进行加权。*

限制
- RMSSE 和 MASE 不适合季节性产品。由于与非季节性产品相比,历史需求期间的天真误差会被任意夸大,因此季节性产品在 RMSSE/MASE 中的权重较低。(Hyndman 等人,2006 年)提出的一个可能的解决方案是使用季节性的简单基准,而不是常规的简单基准。
- 由于比例是基于历史可变性的,任何具有历史异常值的项目都将被认为是(非常)不重要的。一个可能的解决方案是计算相似项目的平均可预测性,并将其用于每个项目。
- 在实践中,实现 MASE 和 RMSSE 并不简单,因为您需要计算历史上天真的 MAE 和 RMSE(如果您的所有时间序列不在同一时间点开始,这可能会变得更加棘手)。
- 此外,它们都缺乏可解释性和绝对的复杂性——尤其是考虑到权重时——这使得它们不适合一般的供应链会议。
实践中的 MASE 和 RMSSE

表 3 有原始误差的历史需求
我们获得了表 4 中所示的指标,其中预测 D 实现了最少的 MASE 和 RMSSE。为了简明起见,没有报告 MAPE、sMAE 和 sRMSE,因为基于前面讨论的限制,它们不应该被使用。

表 4 使用加权比例指标预测 KPI
结论

表 5 指标比较
我们看到通常的度量三人组(Bias、MAE 和 RMSE)不适合评估产品组合的预测质量。这对于机器学习模型来说是一个重要的问题,因为它们优化了整个数据集的指标。在讨论了完美指标的特征后,我们看到加权、缩放的指标(WMASE 或 WRMSSE)可能会对产品组合预测的质量产生新的影响。但是,这两个新指标还不是我们追求的完美指标。研究仍在继续。
与此同时,我会建议公司依赖一套加权指标(如偏差、WMAE 和 WRMSSE ),而不是通常的 MAE/偏差组合。使用一套不同的指标也将使计划者能够关注更有意义的违规者,从而使供应链能够做出更好的决策。
文献学
吉利兰迈克尔商业预测交易:揭露神话,消除不良做法,提供切实可行的解决方案:约翰威利& Sons,2010。
Hyndman Rob J .和 Koehler Anne B. 对预测准确性的另一种衡量。国际预测杂志,2006 年,第 679-688 页。
商务部 M5 申办 2020 年奥运会。https://mofc.unic.ac.cy/m5-competition/.
彼得罗保罗斯·福蒂斯和考伦茨·尼古拉奥斯间歇性需求的预测组合:运筹学学会杂志,2015 年,第 66 卷。
你确定你是精确的吗?测量点预测的准确性,2009 年。https://forecasting . svetunkov . ru/en/2019/08/25/are-you-sure-you-precision-measuring-accuracy-of-point-forecasts/。
Vandeput Nicolas 供应链预测的数据科学。柏林,波士顿:德·格鲁埃特,2021。
库存优化:模型和模拟。柏林,波士顿:德·格鲁埃特,2020。
👉让我们在 LinkedIn 上联系吧!
关于作者
icolas Vandeput 是一名供应链数据科学家,擅长需求预测和库存优化。他在 2016 年创立了自己的咨询公司 SupChains ,并在 2018 年共同创立了 SKU 科学——一个快速、简单、实惠的需求预测平台。尼古拉斯对教育充满热情,他既是一个狂热的学习者,也喜欢在大学教学:自 2014 年以来,他一直在比利时布鲁塞尔为硕士学生教授预测和库存优化。自 2020 年以来,他还在法国巴黎的 CentraleSupelec 教授这两门课程。他于 2018 年出版了 供应链预测的数据科学(2021 年第 2 版)和 2020 年出版了 库存优化:模型与模拟 。

预测不同的水平:介绍 Scalecast Pt。3
直接比较基于静态和非静态数据运行的模型

欢迎回到 scalecast 系列的最后部分。第 1 部分介绍了对一个系列的预测。第 2 部分将该方法扩展到许多系列。这一部分展示了如何在不同的层次上对相同的序列进行建模,并公平而容易地比较结果。
https://github.com/mikekeith52/scalecast
注意:这篇文章最初是为了展示 scalecast 早期版本的差异和均衡特性而写的。此后,自动化和更复杂的系列转换被引入。参见 scalecast 入门笔记本。这里写的大部分内容在 scalecast 的当前版本中仍然是可能的。
为什么要在意等级?
在预测任何给定的时间序列之前,必须对其进行一些考虑,以确保它是平稳的,这意味着它的均值和方差不会随时间随机变化。否则,您将尝试建模的大部分内容将是随机的。像 Prophet 和 Silverkite 这样的模型通过使用分段函数来处理非平稳数据——Prophet 使用贝叶斯回归方法,而 Silverkite 使用带正则化的线性模型。ARIMA 代表自回归综合移动平均线;在这种情况下,“集成”指的是 ARIMA 内部处理非平稳性的机制。指数平滑法对近期观测值的权重大于早期观测值。通过以上所有方式,可以处理非平稳趋势,以便评估准确的预测。
其他常用于预测的机器学习模型,如决策树、非分段线性回归函数、k 近邻、支持向量机和神经网络,都没有考虑非平稳数据。无论如何,如果您试图向他们提供这样的数据,随机趋势变化会严重影响模型,导致噪声被解释为信号和虚假结果。你可能很幸运,仍然获得看似不错的预测,但你的模型可能无法推广到未来的许多阶段。
为了补救这一点,我们可以在将一个系列的一阶或二阶差输入到特定的模型中之前获取它;时间序列中的每一次观察都变成了前一次观察和它本身的差异。因此,大部分噪声被从序列中剥离出来,留下可以建模的周期性信号,如季节性、滞后效应和/或特定协变量。这种策略的唯一缺点是失去了可解释性,并且需要更多的后端工作来使预测对其他人有用。
确定你的数据是否稳定的一个好的统计测试是增强的 Dickey Fuller。它的零假设是,你给它的数据不是平稳的,如果你想安全,这也应该是你处理时间序列时的默认假设。当你的数据不是稳定的时候,假设你的数据是稳定的比反之更严重,至少这是我的经济学老师总是告诉我的。
在不同级别上运行模型
当您想要比较考虑平稳性的模型和不考虑平稳性的模型的预测结果时,您会怎么做?为了安全起见,一个答案是用静态数据运行所有模型,但更动态的方法是对水平数据运行一些序列,对差异数据运行其他序列。然后,可以根据每个模型在级别数据上的表现来比较误差和准确性指标。
执行这个策略可能很有挑战性,但是使用 scalecast 时很容易(参见示例中使用的完整脚本这里)。首先,安装软件包并满足其他需求:
pip install scalecast
pip install pandas-datareader
pip install lightgbm
pip install fbprophet
pip install greykite
接下来,导入库并加载数据:
我们在第一部分中很好地检验了这些数据。这一次我们使用相同的预处理步骤——对序列求差分,使其稳定;规定测试和验证周期;并添加季节回归、自回归项、时间趋势和一些其他变量。
让我们将四种模型应用于差异数据——K-最近邻、支持向量机、光梯度增强机和多层感知器。我们还可以选择四个模型,无论数据是否平稳,它们都应该工作良好:ARIMA、霍尔特-温特斯指数平滑、脸书先知和 LinkedIn SilverKite。我们将后四个应用于原始级别的数据。我们还为这两种模型类型中的每一种添加了两个组合模型,总共剩下四个组合模型。
为了调整这些模型,我们在工作目录中放置了一个 Grids.py 文件。一种简单的方法是使用:
from scalecast import GridGenerator
GridGenerator.get_example_grids()
当运行您自己的应用程序时,我们鼓励您在您认为合适的时候手动修改这个文件中的网格。
直观比较结果
当比较结果时,分析的有趣部分就来了。首先,为了简洁起见,让我们选择一个可以信任的错误/准确性指标(比较几个指标可能更有趣,但这超出了本文的范围)。由于预测是在不同的水平上进行的,我们应该选择一个对所有序列都有意义的预测。我喜欢 LevelTestSetMape。当向组织中的高级决策者交付预测时,人们通常最关心的是预期结果与实际结果之间的差距。当你能快速说出一个百分点的时候,这是很受欢迎的——这样,就不会对比例或统计数据产生混淆。平均绝对百分比误差(MAPE)允许我们这样做,LevelTestSetMAPE 通常对您可能预测的任何系列进行公正的评估。让我们来看看绘制的预测,根据这个指标从最好到最差排序:

作者图片
k-最近邻返回了最好的结果(0.07 MAPE),其次是多级感知器(0.08 MAPE),两者都在差异数据上运行,但在这里直观地显示在级别数据上。在水平数据上运行的最佳模型是简单平均组合模型(0.08 MAPE),然而,从视觉上看,该模型的评估比直观的要低很多。让我们仔细看看这些测试集的结果:

作者图片
看起来对avg_lvl有利的测试集指标是由于 ARIMA 模型对该特定数据段的评估远远高于其他级别的模型(注意——实际上是由于 scalecast 版本 0.9.1 中解决的代码错误)。对于我的最终预测,我既不相信 ARIMA 模型,也不相信组合模型——它们的表现不可靠,也不总是超出样本。有时候你会看到这样奇怪的东西;一些模型在相反的方向上相差甚远,这使得组合模型乍一看似乎是合理的。但在做最后决定时,你必须运用常识。
有趣的是,在水平数据上运行的模型比其他模型表现得更差。银雀回报了 0.17 的 MAPE 和 0.23 的先知。也许更重要的是,他们的结果看起来不可信。尽管这些模型有处理非平稳性的机制,但在平稳数据上运行它们仍然是一个好主意。如果我们那样做了,我们可能会取得更好的结果。另一种选择是花更多的时间处理它们的变点参数(分段函数在序列中变化的点),看看是否有办法让它们更有效地捕捉序列趋势的变化。当观察拟合值(样本内预测)时,我们可以看到在水平数据上运行的模型可能出错的地方:

作者图片
我们看到,先知没有能够在系列中找到任何变化点,始终遵循一个趋势。它不够动态,无法可靠地预测这些数据。SilverKite 也始终遵循一个趋势,并且无法获得该系列的任何季节性,可能是过度正规化了。另外两个看起来可能装得太多了。
虽然不是所有基于差异数据评估的模型都比那些没有差异的模型好,但差异被证明是该过程的一个重要部分。我们简单地利用平稳数据,很容易地得出了两个非常可信的预测(KNN 和 MLP)。
最后,我认为探索最佳表现模型的选定超参数是很有趣的:
knn HyperParams: {'n_neighbors': 11, 'weights': 'uniform'}
mlp HyperParams: {'activation': 'relu', 'hidden_layer_sizes': (25, 25), 'solver': 'adam', 'random_state': 20}
了解这些信息是在未来的预测迭代中获得更好结果的起点。
结论
在探索这些结果的过程中,我们看到了一个在不同级别进行预测的例子,并对尝试这样做时可能面临的潜在挑战有了更好的了解。scalecast 软件包简化了这一过程。
感谢您的关注。scalecast 系列到此结束。这个包可以做很多事情,希望你可以更容易地访问它的一些功能。自从最初的系列文章结束以来,我已经写了很多关于这个包的文章。关注我,获取更多预测和数据科学文章。
脸书预言家的尺度预报——一个关于其优点和局限性的案例研究
领域知识仍然是机器学习应用中的决定性因素
背景
时间序列预测通常是一项复杂的任务,因为单变量数据的结构通常包含许多未观察到的因素。标准模型,如 ARIMA 或滤波器,如卡尔曼滤波器是复杂的模型,经常需要调整,这需要对基础理论有严格的理解。
具有良好领域知识但缺乏统计知识的从业者希望利用机器学习和预测方法来为他们的业务决策提供信息。因此,许多软件包和库试图通过提供自动化解决方案来弥合这一差距。
这篇文章的目的是调查脸书的一个很有前途的图书馆,叫做先知。Prophet 的承诺是大规模自动生成预测。
结果
不幸的是,即使是在实验室环境下,人们对一台引擎能够在没有任何交互作用的情况下进行大规模可靠预测的希望也太高了。然而,经过一些调整后,这个库运行良好,并能识别测试数据中的所有元素。因此,只要对这个领域有一点了解,这个库就会产生有用的结果
情况
为了进行设置,加载预测库、漂亮图形的 ggplot 和一些时间序列魔术的 zoo。
现在生成数据。我们将使用 5 年的数据,包括三种不同的季节模式和前半段时间后的变化趋势。
通过识别 sin (2π/b) 的周期长度为 b,三角函数可用于生成季节模式。换句话说,每个 b 周期,模式都会重复。我们将使用年度模式 (b=360) 、月周期 (b=30) 和周周期 (b=7) 。
该趋势将在半个观察周期后被提升,以测试 FB Prophet 是否能够发现这种结构变化。我们会看到,它确实在这个挑战中做得很好。
先知可以捕捉的其他特征是趋势饱和度和特殊事件,如假期。但是这里不讨论这些。
该模型将根据前四年的数据进行训练。第五年的数据用于评估模型的性能。
首先,我们在没有进一步信息的情况下运行 Prophet:
要从中创建预测,需要调用保存预测的数据框:

数据和预测的吻合度(图片由作者提供)
从这个情节中,很容易理解拟合度是可以提高的。季节的高峰没有被很好地捕捉。为了更好地理解发生了什么,让我们看看残差:

剩余剧情(图片由作者提供)
残差的范围相当宽,并且可以看到清晰的结构。所以模型里少了一个成分。让我们试着明确地说明每年的季节性:

数据和预测的吻合度(图片由作者提供)
看起来更好,但仍不完美。请记住,模型数据是在没有噪声的情况下生成的,因此模型应该能够以几乎 100%的准确度拟合数据。
然而,这次残差显示了一个不同的问题:

剩余剧情(图片由作者提供)
这是为什么领域知识很重要的主要例子。因为我们知道底层数据的频率,所以我们可以用参数 period 来指定它。
为此,我们设置了不带季节组件的模型,并手动添加它们:

剩余剧情(图片由作者提供)
这看起来更好,除了围绕趋势变化发生的突破。但是,残差中还是有结构的。这里的问题是过拟合,这是由参数傅立叶级数引起的。该参数的标准值为 10 。
Prophet 使用傅立叶变换来估计季节性成分。基本思想是任何任意信号都可以用足够数量的正弦曲线来近似。傅立叶阶参数指定了这里应该使用多少个。因为我们只使用一条 sin 曲线创建了每个组件,所以真正的顺序是 1。
所以让我们看看当我们告诉先知这个模型的这个方面时会发生什么:

残差图
残差现在看起来好多了,除了趋势变化时的干扰,但这并不奇怪,因为它突然打破了数据的良好规则模式。
现在让我们看看样本外预测,看看训练数据集的良好拟合是否转化为良好的预测:

真实数据(灰色)和拟合(蓝色)//(图片由作者提供)
预测现在完全符合真实数据!
外卖
自动预测对于大规模商业应用来说是一个方便的特性。然而,这些方法并不总是现成的。我们必须从数据生成过程中编织大量的知识,以创建一个良好的模型拟合。
如果没有这些见解,模型仍然是有用的,但仍然不精确,尽管数据生成过程遵循与数据探索方法完全相同的逻辑。
使用 Prophet 用 Python 预测业务 KPIs 第 2 部分
预测 | 巨蟒 | 办公时间
了解如何通过使用 Prophet 预测未来绩效来为您的企业增值

更新:你们中的许多人联系我,要求提供有价值的资源,以了解更多关于使用 Python进行时间序列预测的信息。下面我分享两个我亲自参加的课程,强烈建议你扩展这方面的知识:
希望你也会发现它们有用!现在欣赏:D 的文章
介绍
在本教程的第一部分( 使用 Prophet 用 Python 预测业务 KPI-第一部分 ),我们使用脸书的 Prophet 库构建了一个简单的预测模型,来预测未来 426 天的两个每日 KPI(销售数字 & 销售值 GBP) 。最终预测被分配给原始数据帧中的空未来日期,以获得以下结果( GitHub ):
df.loc[(df['observation_date'] > cutoff_date )].head()
df.loc[(df[‘observation_date’] > cutoff_date )].tail()

原 DF 负责人

原始 DF 的尾部:两个空字段被预测替换
我们还试图评估模型性能,获得 6.73%的 MAPE 。尽管这对于我们的第一个模型来说是一个公平的结果,但是通过重叠预测值和实际值,我们注意到我们的预测仍然没有很好地响应观察到的销售量的突然峰值和下降:

图表 1:重叠的实际值与预测值
因为模型不能很好地拟合许多过去观察到的值,所以有理由认为未来的值也是如此。为此,在本文中,我们将改进原始拟合,引入假日和定制的季节成分,并调整另外三个参数( 傅立叶顺序、 变点先验比例 和 变点范围 )。
添加假日
在 Prophet 中,术语 【假日】 不应从字面上理解,因为它更广泛地表示产生明显偏离其模式的趋势的不寻常事件,一旦事件结束,这些事件就会回到正轨。从该描述中可以看出,将假日添加到模型中相当于包括额外的回归量(通过 Prophet.add_regressor() 方法实现的),然而,这两个类别之间的主要区别在于:
- 当我们希望对限定在特定日期的意外事件建模时,应使用额外的回归变量****;
- ****假期应在趋势偏离是周期性的,并且可能在事件日期之前开始并在事件日期之后继续时使用。这意味着当添加假日时,我们将被允许指定一个 下部窗口 和一个 上部窗口 来模拟围绕事件本身的潜在异常。
使用我们的领域知识,我们确定了六个我们希望作为假日传递给模型的事件:
- 当月第一个工作日 :由二进制字段
fl_first_working_day表示; - 当月最后一个工作日 :用二进制字段
fl_last_working_day表示; - 本月最后一个星期五的:用二进制字段
fl_last_friday_day表示; - 元旦 :由二进制字段
fl_new_year表示; - 窗口中的复活节[-4,+2] :这些日期将被手动估算;
- 窗口中的圣诞节[-3,+3] :这些日期也将手动输入;
为了在模型中使用这些事件,我们首先需要创建一个holidays数据帧,如下所示:
创建假日数据框架
上面的代码中发生了什么?
首先,我们创建了四个列表(最初的df中每面旗一个),包括日期为flag = 1。然后,这些列表被用来构建尽可能多的单个数据框架,其数量与我们希望建模的事件数量一样多。每个数据帧应包括四列,即holiday、ds、lower_window和upper_window。
特别要注意的是,在标记的情况下,ds列是通过自动传递步骤一中的日期列表创建的,而对于Easter和Christmas来说,日期是手动估算的。在这两种情况下, Prophet 要求每个假日不仅要包含过去的数据,还要包含要预测的日期范围的数据。最终,holidays DF 应该如下图所示:

假日总监

假日的尾巴
通过在我们的原始模型中包括holidays DF,我们得到:
如果我们现在重新运行同一时期的预测,并为sales_num KPI 计算 MAPE ,结果是 5.28% 。这意味着通过考虑影响业务的周期性事件,我们能够将平均绝对百分比误差降低近 22%****
*Output: 5.2806026397*
当实际值和预测值重叠时,模型拟合df_train数据集的方式的改进变得很明显,如图 1 所示:

图表 2:重叠的实际值与预测值(使用节假日)
在结束本节之前,值得强调的是,如果我们要预测某个特定国家的 KPI,我们可能还想添加该市场的国家节日(允许的国家代码的完整列表 此处 ):**
*model.add_country_holidays(country_name = 'GB')*
此外,如果我们希望显示holidays DF 的样子,我们可以使用组件图轻松实现:
*model.plot_components(forecast)*

图表 3:节假日中的周期性事件
添加季节性
我们模型的性能有所改善,但在季节性方面仍有一些工作要做。例如,我们的领域知识也告诉我们,企业经历了一个明显的 月季节性 ,但是当前的模型没有考虑到这个信息。
幸运的是,Prophet 允许我们关闭标准的weekly_seasonality和yearly_seasonality,添加我们定制的季节。这种方法给了我们更多的控制,因为我们可以为每个季节设定一个精确的period以及fourier_order:
实际上,为了模拟多时期的季节性,fbprophet依赖于标准的傅立叶级数(如 中所述的本文** ):

傅立叶级数数学表示
其中,P 是一个季节的正常时间段(,例如,当数据集粒度以天为单位时,P = 365.25 表示年度数据,P = 7 表示周数据)。在公式中,N 参数代表需要选择的fourier_order,以适应季节性。一般来说,通过增加 N,可以提高我们拟合快速变化的季节模式的能力,以及过度拟合训练数据集的风险。**
出于这个原因,在区间[5,20]中选择一个fourier_order通常是一个好的实践,这个选择过程可以采用一个模型选择程序自动进行,如 AIC(第二部分广泛讨论的一个主题)。对于我们的模型,我发现[5, 14, 10]是每周、每月和每年季节性的最佳值。这意味着该模型将更具反应性,以适应每月和每年级别的重复变化,而在每周级别的反应性较低。
使用这些参数运行model,导致 MAPE 为 3.6% ,与第一部分中介绍的初始模型相比,减少了 46.5% 。我们所要做的就是添加定制的季节性并找到正确的组合参数。
添加“先前比例”参数
在这一点上,我们应该对我们的模型相当满意,但在结束本教程之前,我想再介绍三个参数,它们可以帮助我们进一步降低 MAPE:
- 季节性先验比例(默认为 10) :该参数用于调整季节性成分的强度,意味着较高的值允许模型适应较大的季节性波动,较小的值抑制季节性。它可以作为通用参数添加,也可以作为
add_seasonality()( 如下图所示)的一部分为个别季节指定。在我们的例子中,值 15 适用于所有季节,将 MAPE 略微降低到 3.59% 。 - 节假日优先比例(默认为 10): 此参数调整模型中节假日组件的强度,确定节假日对预测的影响。对于我们的模型,默认值是导致最低 MAPE 的值。
- 变点优先比例(默认值= 0.05): 该参数调节自动变点选择的灵活性,意味着较高的值将允许更多的变点,较低的值将减少允许的变点数量。我发现,在某些情况下,将默认值增加一倍(从 0.05 增加到 0.1* ,可以提高模型的精确度,进而降低 MAPE。然而,对于我们的模型来说,情况并非如此,默认值会产生最佳结果。***
结论
在本教程的第二部分,我们学习了如何使用节假日、定制季节性和更多的高级参数来提高我们模型的预测准确性。这些调整导致最终 MAPE 为 3.59%* 从最初的 6.73%下降了 46.5%。用于得出该结果的最终模型如下所示:***
在本指南关于预测业务 KPI 的最后一部分(第三部分)中,我们将学习如何实施更高级的技术来执行模型评估,以及如何使用 AIC 作为基准来自动选择最佳的可能参数组合。**
我希望这篇文章对你有用&继续学习!
给我的读者一个提示:这篇文章包括附属链接,如果你购买的话,我可以免费给你一点佣金。
你可能也喜欢
***</10-algorithms-to-solve-before-your-python-coding-interview-feb74fb9bc27> 💔-ways-to-compute-a-weighted-average-in-python-4e066de7a719> </8-popular-sql-window-functions-replicated-in-python-e17e6b34d5d7> ***
基于时间序列的象棋 Elo 预测
使用 Glicko 评级系统对您未来的象棋评级进行预测。

哈桑·帕夏在 Unsplash 上的照片
不久前,我偶然看到了这个视频【1】由 1littlecoder 制作,展示了如何使用 berserk,Lichess API 的 Python 客户端,来提取关于你的象棋游戏的信息。作为 Lichess 的常客,我想建立一个预测模型,根据以前玩过的游戏对我的象棋评分进行预测。如果你也是 Lichess 的普通用户,你可以模仿我的方法,看看是否能提取出一些有趣的东西。
第一步,安装 berserk,导入。然后,你想从 Lichess 那里得到你的个人信物。为此,点击右上角的 Lichess 配置文件,进入首选项,然后点击左下角的 API 访问令牌。获得 API 令牌后,只需使用最后两行进行身份验证。关于 berserk 包的完整文档,你也可以看看这个。
!pip install berserk
import berserk
token = "YOUR_PERSONAL_TOKEN"
session = berserk.TokenSession(token)
client = berserk.Client(session=session)
现在,我已经导入了一些有用的库,如 NumPy、Matplotlib 和 datetime。然后,我使用类用户的 get_rating_history 方法提取我对子弹棋的评分。接下来,我使用 create_bullet_list 将它们存储在一个列表中。
import numpy as np
import matplotlib.pyplot as plt
import datetime
%matplotlib inlineentries_of_bullet_ratings = \ client.users.get_rating_history("bibimbap123")[0]["points"]def create_bullet_list(bullet_ratings):
lst = []
for entry in bullet_ratings:
lst.append(entry[3])
return lstratings = create_bullet_list(entries_of_bullet_ratings)
下面的代码将创建一个日期时间列表,首先提取所玩游戏的日期(times_list),将它们存储为元组列表(tuple_to_str),然后将它们转换为日期时间数据类型(str_to_datetime)。
import calendar
from dateutil import parserdef times_list(bullet_ratings):
tl = []
for entry in bullet_ratings:
tl.append((str(entry[0]), calendar.month_name[entry[1]+1], \
str(entry[2])))
return tl
times = times_list(entries_of_bullet_ratings) def tuple_to_str(time):
l = []
for entry in time:
l.append(', '.join(entry))
return lstr_times = tuple_to_str(times) def str_to_datetime(time):
l = []
for entry in time:
l.append(parser.parse(entry))
return ldtime = str_to_datetime(str_times)
接下来,让我们绘制时间序列,以了解从 2021 年 2 月(我创建账户的那一天)到 2021 年 12 月,我的评级进展的大致情况。
fig, ax = plt.subplots()
fig.autofmt_xdate()
plt.plot(dtime, ratings)
plt.show()

从 2021 年 2 月到 2021 年 12 月的评级进展。图片作者。
好了,现在,为了建立模型,我使用了这张纸【2】,它展示了评级计算背后的数学原理。第一件事是检索我的最新评级和我的最新评级偏差。本文解释说,评级偏差本质上是对评级不确定性的一种度量。
# Latest rating
old_rating = ratings[-1]# Latest rating deviation
rating_deviation_old = \
client.users.get_public_data("bibimbap123")["perfs"]["bullet"]["rd"]
现在,我进行了以下计算来计算新的评级偏差。

来源:http://www.glicko.net/glicko/glicko.pdf
然而,我需要使用下面的等式来求解 c 。

来源:http://www.glicko.net/glicko/glicko.pdf
这里 t 代表我的等级变得像新玩家一样不可靠所需的时间(以等级周期为单位)。评级期被定义为所有游戏被视为同时进行的一段时间。对于这个项目,我决定使用每月评级周期,并设置 t = 60。这表明,在我的评级变得像新手一样不可靠之前,需要 60 个月(5 年)的时间。
rating_period = 1# Calculate c
c = np.sqrt((350**2-rating_deviation_old**2)/(rating_period * 60)) # Calculate RDrating_deviation_current = \
min(np.sqrt(rating_deviation_old**2+c**2), 350)
现在,这是后期评级和后期评级偏差的大计算。后期评级将是我们的预测。

来源:http://www.glicko.net/glicko/glicko.pdf
我要处理的第一件事是r’中的求和。这里, m 代表我在一个特定时间段(1 个月)内面对的对手数量。首先,我需要计算四件事:
- 每月平均游戏次数( m )
- 对手平均评级
- 平均对手评分偏差
- 平均结果
为了计算 1),我将做如下假设:我在一年内玩的对手的平均数量除以 12 反映了我每个月玩的对手的数量。
对于 2),我只是在我的 Lichess 个人资料中查找;我没有找到通过 API 提取的方法。
对于 3),我假设 RD 是 50,因为这是活跃玩家的常见 RD。
对于 4),我用总胜率除以总游戏数来计算我的胜率。在这里,get_public_data 方法允许我提取玩的游戏总数和赢的游戏总数。
# 1) Take total amount of games played in one year and divide them by 12entries_of_bullet_ratings = \
client.users.get_rating_history("bibimbap123")[0]["points"]
d = {1: 0, 2:0, 3:0,4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0}
for key in d:
for time in dtime:
if time.month == key:
d[key] += 1
#Round up
average_number_of_games = int(sum(d)/12) + 1# 2) Their average rating
opponent_average_rating = 2145# 3) Their average rating deviation
opponent_average_RD = 50# 4) Calculate the average win_rate
win_rate = client.users.get_public_data("bibimbap123")["count"]["win"]/\
client.users.get_public_data("bibimbap123")["count"]["all"]
请注意,这些计算意味着我基本上是在和相同数量、相同评分和评分偏差的对手比赛。因此,求和可以用乘以对手数量来代替。
除此之外,我们还要计算另外四个值: q,d,g(RD_j),E(s|r)。文中没有明确解释这些的含义。然而,幸运的是,公式已经给了我们,所以我们只需要插上塞子,咕嘟咕嘟地喝。

来源:http://www.glicko.net/glicko/glicko.pdf

来源:http://www.glicko.net/glicko/glicko.pdf
我的代码显示如下:
q = 0.0057565g_RD = 1/(np.sqrt(1+3*q**2*(rating_deviation_current**2)/np.pi**2))E_sr = 1/(1+10**(-g_RD*(old_rating - opponent_average_rating)/400))d_squared = 1/(average_number_of_games * q **2 * \
(g_RD ** 2) * E_sr * (1- E_sr))new_rating = old_rating + average_number_of_games * \ q/(((1/rating_deviation_current**2) + 1/d_squared)) * g_RD * \(win_rate - E_sr)new_RD = np.sqrt(1/(1/rating_deviation_current ** 2 + 1/d_squared))
最后一步是绘制预测图。因为我将一个评级周期视为一个月,所以这个预测评级将正好是我玩最后一个游戏后的一个月。在这里,我想确保如果我的最后一场比赛是在第 12 个月(12 月),那么预测将在第 1 个月(1 月)而不是第 13 个月,因为那不存在。
last_game_time = dtime[-1]prediction_month = last_game_time.month+1prediction_time = last_game_timeif prediction_month == 13:
prediction_time = \
prediction_time.replace(year = last_game_time.year + 1)
prediction_time = prediction_time.replace(month = 1)else:
prediction_time = \
prediction_time.replace(month = last_game_time.month + 1)
预测评级和预测时间显示如下。我们可以从这张图推断出我最后一局是在 2021 年 12 月 17 日。

预测时间和预测评级。图片作者。

时间序列图上 1 月 17 日的预测评分(红点)。图片作者。
随着我玩的游戏越来越多,这个程序将对我未来的评分做出越来越新的预测,这使得看到我的实际评分和预测评分相差多少变得很有趣。在未来,看看我们如何能最小化这种差异是值得的。
参考
[1]1littlecoder,用 Python 从 Lichess API 中提取象棋数据(2020),https://www.youtube.com/watch?v=OnCQ3J6ZKL4
[2]M. E .格利克曼,格利克体系 (1995),http://www.glicko.net/glicko/glicko.pdf
用长短期记忆网络预测意大利的气候变化
变更数据
用于预测温度趋势的深度学习

恩里克·费雷拉在 Unsplash 上拍摄的照片
简介
我们生活在一个对人类充满挑战的时代,其中最大的挑战之一就是气候变化。那么,在这个充满变化和困难的时代,数据科学在气候变化中的作用有多重要呢?从我个人的角度来看,在不久的将来,数据科学在气候变化中的作用会越来越大。但是让我解释一下为什么。
例如,考虑组织如何通过使用监测碳排放的传感器来减少碳足迹,或者数据科学家如何使用卫星数据和跟踪实时天气变化,并使用机器学习模型来防止灾难性事件。
再想想机器学习在电力消耗或农业方面的应用。通过考虑当地天气、气候模式或家庭行为的算法,数据科学家可以实时预测我们长期需要多少能源。
在农业领域,使用能够感知土壤湿度和养分的物联网设备,结合天气数据,农民可以更好地控制灌溉和施肥系统。
还有许多其他可能性,如使用算法来改善电动汽车的电池能量管理,采用卫星图像和计算机视觉技术来防止大规模的树木覆盖损失。
然后,正如你所看到的,数据科学在气候变化问题中发挥了重要作用,在这篇文章中,我将向你展示我如何使用深度学习模型来预测我所居住的国家意大利的气温趋势。
在本文中,我将向您展示:
- 我做的数据可视化是为了理解温度数据
- 长短期记忆网络的直观介绍
- 如何建立 LSTM 网络
你可以在我的谷歌实验室或者我的 GitHub 上找到完整的代码。
所以,让我们开始吧!
第一部分:数据可视化

作者图片
在上图中,您可以看到数据集中所有国家的全球平均温度。我用下面的代码构建了这个地图。
然后,为了对这些年的气温变化有一个时间线的概述,我写了这段代码,以建立一个从 1743 年到 2013 年各国气温变化的地图。
出局:

作者图片
为了追踪意大利逐月和逐年的平均气温,我构建了如下图表:
出局:

作者图片
这一部分以图表的形式展示了我的主要发现,如果你想看到构建这个图表的整个过程,我建议你看看我的 Google Colabo 这里或者我的 GitHub 简介这里。
第二部分:对 LSTM 的直观解读
在开始解释什么是长短期记忆网络之前,让我用几句话来给你一个传统神经网络和递归神经网络的局限性的概述。
在传统的神经网络中,如果我们在不同的时间将输入输入到模型中,我们将获得独立的输出。事实上,第二个输出(t)没有关于前一个输出(t-1)的信息,这意味着第一个输出对第二个输出没有影响。如果我们需要建立一个能够从过去的输出中学习的模型,以便做出更准确的预测,这是一个很大的限制。这个问题的解决方案是递归神经网络。
为了直观地理解什么是 RNN,当你看你最喜欢的网飞电视剧时想想。每次看新一集的时候,你都需要记住前几集才能理解后面几集。RNN 以同样的方式工作,它记住过去的输出,并使用它们来更好地理解后面将要发生的事情。因此,过去的产出和未来的产出之间存在相关性。
您还需要知道,rnn 使用反向传播算法进行训练,该算法适用于每个时间戳。在反向传播期间,RNNs 尝试计算误差,该误差由实际输出和模型输出之间的差给出,并将其提高到 2 的幂。但是,当 RNNs 通过递归神经网络的所有多层传播误差时,我们会发现 RNNs 的性能在训练期间会非常差,因为我们的梯度变得越来越小。
为了解决这个问题,我们需要梯度值,当它们向后时保持不变。为此,我们需要一个长短期记忆网络。
LSTM 网络可以控制何时让输入进入神经元,以及何时记住前一个时间戳中计算的内容。此外,LSTM 网络还可以控制何时让输出传递下一个时间戳。
因此,LSTM 神经元与 RNN 普通神经元的区别在于,它有可能自己决定电流输入。正如你所观察到的,整个过程都是受我们大脑工作方式的启发,这太神奇了。
如果你想更深入地了解 LSTM,我建议你读一读克里斯托弗·奥拉写的这篇文章 了解 LSTM 网络 。这篇文章对我理解 LSTM 网络帮助很大。
第三部分:用 LSTM 网络建立模型
在这一部分中,我将向您展示如何准备和构建模型来预测意大利的气温趋势。我将重点介绍如何构建模型,而不是准备过程。如果你想看完整的代码,你可以去我的 GitHub 档案。
为了构建模型,我们将使用 Keras API。如您所见,第一个变量是训练集的输入。然后我们有我们的网络层,其中第一层被输入,包含 50 个单元。然后,我们有辍学层,允许网络概括,而不是记忆。接下来,我们有另一层 LSTM,和另一个辍学层。
之后,我们有输出变量,该变量增加了具有一个神经元的密集全连接人工神经网络,并且激活函数将是线性的。
在函数的最后,我构建了模型,并用 adam optimizer 和均方误差对模型进行了编译。
现在,我们可以用训练数据训练我们的模型,并查看摘要
出局:

作者图片
正如你在上面的总结中看到的,有 LSTM 层、下降层和密集层。
最后,我们可以用训练数据(train_x,train_y)拟合模型,并传递验证数据(test_x,test_y)
出局:

作者图片
输出向我们展示了整个培训过程中损失和错误的进展。在下图中,您可以看到训练和测试集中的损失趋势。

作者图片
相反,在下图中,您可以看到原始数据集与预测值的对比。因此,该模型能够捕捉趋势,但它需要一些改进,以捕捉发生的细节。

作者图片
结论
我希望这篇文章能帮助你对气候变化问题产生更多的兴趣,并理解数据科学在解决气候变化问题方面的潜力。
我用于这个模型的数据集可以在 Kaggle 中找到,你可以在我的 G oogle Colab 或 GitHub 中找到完整的代码。所以,你可以试着建立你的模型,了解气候如何随时间变化。
无论如何,对于那些有兴趣深入了解大数据在气候变化中的应用的人,我建议阅读 NASA 发表的文章气候科学中的大数据挑战你可以在这里找到。这篇文章很有见地,可以为您详细解释气候数据分析的基础设施。
感谢你阅读这篇文章。您还可以通过其他方式与我保持联系并关注我的工作:
预测短生命周期产品的需求
你应该如何预测保质期短的产品?让我们回顾一下最佳实践。
最近在 LinkedIn 上收到以下问题。
“我们每年在短期内(比如 20-40 天)销售一次某些产品。第二年,同样的升级产品或全新的产品将被出售。你对那些短生命周期的产品有什么建议吗?”
预测生命周期短的产品非常困难:你不能依赖任何历史需求。那么,我们该如何面对这个挑战呢?
这里有一些想法。
🛍️ 如果产品正在替换旧版本
如果你每年发布一个新的产品版本,确保你的(产品生命周期)主数据是正确的。您将需要映射一个产品版本到另一个产品版本之间的链接(映射链接,如“2020 年的 A”->“2021 年的 B”)。然后,您将使用清理后的历史需求来创建预测基线(使用您常用的预测模型)。
如果您冒着新旧版本之间互相蚕食的风险,那么在做预测时要跟踪任何剩余的旧产品。我喜欢同时预测新旧版本的需求。然后由计划工具/软件/团队根据剩余库存(或通过应用分割因子)将预测分配给旧/新版本。
👜如果产品是全新的
一些新产品没有任何历史前辈,但仍然与其他当前产品相似。然后你可以依靠历史类比来预测新产品的需求。也就是说,根据观察到的其他类似项目的需求模式来预测新产品的需求。例如,要预测一种新的早餐谷物的上市,你可以基于一种相似类型的谷物的历史销售模式。
如果这个历史类比不起作用,你可以尝试其他技巧:
- 判断性预测(注意认知偏差!) [1]
- 在更高的层次结构层预测需求:您可以在较高的汇总层(如每个类别/系列/品牌)预测需求,然后将其传回 SKU。例如,您可以分析年度趋势来预测新产品的需求。
- 为了进一步改善你的预测,不要犹豫使用协作预测(与你的客户、供应商、一线员工讨论)。
📦关注库存优化
你应该考虑库存优化,而不是关注点预测。记住,预测只是达到目的的一种手段:它只帮助你购买/生产正确数量的商品。简而言之,重要的是在货架上获得正确的产品数量。没有得到最佳点估计预测。
你也可以和生产方合作,减少最小批量,提高灵活性等。这将有助于你轻松应对不断变化的需求。
📰报童模型
您可以使用报童模型来优化购买/生产的商品数量。为此,您需要:
- 概率预测。
- 对错过一笔销售的成本的估计(称为超额成本, Co )。这应该是盈利能力加上一些商誉损失。
- 赛季末剩下一个人的成本(称为未成年成本, Cu )。该成本应包括生产/采购成本减去折扣价。
产品的最佳服务水平应该是 Cu / (Cu + Co)。[2]
结论
与供应链一样,没有一种方法可以解决所有行业和上市模式的所有问题。历史上行之有效的方法在未来可能行不通(尤其是在出现 COVID 这样的中断时)。你需要了解历史上成功和失败的关键因素,以评估未来赛季的正确策略。记住,预测只是达到目的的一种手段:做出正确的供应链决策。了解你的极限,并据此制定计划。
来源
[1]范德普特,尼古拉(2021)。供应链预测数据科学第二版。柏林的胡家。
[2]尼古拉斯·范德普特(2020)。库存优化:模型和模拟。柏林的胡家。
👉我们在 LinkedIn 上连线吧!
感谢
这篇文章是我在 LinkedIn 的一篇帖子的摘要。如果你对这样的辩论感兴趣,那就连线吧!感谢以下人士在原讨论中的真知灼见: Tatiana Usuga 、Bruno vini cius gon alves、 Chris Mousley 、 Zachary MacLean 和 Levent Ozsahin 。
关于作者
https://www.linkedin.com/in/vandeputnicolas/
icolas Vandeput 是一名供应链数据科学家,擅长需求预测和库存优化。他在 2016 年创立了自己的咨询公司 SupChains ,并在 2018 年共同创立了 SKU 科学——一个快速、简单、实惠的需求预测平台。尼古拉斯对教育充满热情,他既是一个狂热的学习者,也喜欢在大学教学:自 2014 年以来,他一直在比利时布鲁塞尔为硕士学生教授预测和库存优化。自 2020 年以来,他还在法国巴黎的 CentraleSupelec 教授这两个科目。他于 2018 年出版了 供应链预测的数据科学(2021 年第 2 版)和 2020 年出版了 库存优化:模型与模拟 。

用人工神经网络预测电价——第一部分

马克西姆·霍普曼在 Unsplash 上的照片
介绍基于人工神经网络预测电价的新“Python-How-to”系列。
介绍
2019 年,我写了关于借助人工神经元网络(“ann”)预测电价的硕士论文。我的论文的想法是由 Lago,De Ridder,Vrancx 和 De Schutter 写的一篇研究论文激发的。这篇论文发表于一年前,提出如果人工神经网络不是预测一个市场而是同时预测两个相互连接的市场,那么用人工神经网络预测电价的准确性可以提高。由于他们的方法仅基于法国和比利时的电力市场,我构建了一个实验来测试他们关于北欧和德国电力市场的论文。
它失败得很惨。我设法建立并训练了各自的人工神经网络,但我无法衡量预测单一市场和多个市场价格的网络之间的任何性能提高。事实证明,这两个市场之间没有显著的电力交易。因此,人工神经网络无法做出更好的预测,因为两个市场的互联对整体价格的影响非常小。糟糕,这是我应该早点检查的。

2018 年 Nord Pool 价格预测与实际对比——单一预测者。图片由作者提供。
然而,尽管我失败了,我还是取得了一些有趣的结果。我的最后一个单一市场预测者获得了略低于 10.00 的 MAPE 分数,这意味着平均而言,预测的价格只相差 10%。网络的标准偏差为每预测兆瓦时 5.57 欧元。尽管所达到的精度还没有高到商业上有用的程度,但我仍然认为结果令人惊讶——尤其是考虑到所使用的人工神经网络结构非常简单,并且是在我过时的游戏笔记本电脑上训练的。
我的实验是基于 2018 年的价格。北欧电力市场 Nord Pool 的平均价格为每兆瓦时 33.43 欧元。三年后的今天,2021 年的平均价格为每兆瓦时 58.64 欧元,增长了近 100%。然而,Nord Pool 并不是唯一有这种现象的公司。整个欧洲的能源价格持续上涨。波兰等一些州受到的冲击尤其严重,仅在 2021 年一年,价格就上涨了 90%。⁴有些人可能会说欧洲正处于能源危机之中。
由于当前的发展,我很好奇我的人工神经网络在当前环境下是否会有类似的表现。因此,我决定开始一个“如何”系列,探索人们如何基于人工神经网络预测电价的可能性。
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
系列内容
该系列将涵盖电力市场的必要理论,并包括用于数据分析和人工神经网络建模的 Python 编码指令。人工神经网络的必要理论知识将不包括在内。然而,如果你想刷新你的记忆,我会在此过程中发表更多的文章,你可以在那里阅读。
本系列的目的是为您提供一个关于如何进行基于人工神经网络的电价预测的全面指南,以便您可以在自己的场景中使用它。以下大纲将为您提供后续部分的更详细概述。我将随着每一个新零件的发布更新大纲:
第二部分:欧洲电力市场简介
每个数据科学项目都基于真实的用例。在预测任何电价之前,我们需要了解欧洲电力市场是如何运作的。读完这一部分,你将有足够的知识来进行有意义的数据分析,并建立一个工作预测模型。
第 3 部分:探索性数据分析
在构建我们的 ANN 之前,我们将讨论数据及其使用权,并在 Python 和相关库的帮助下进行探索性数据分析。我们将可视化我们的结果,并讨论它们对我们实验的潜在影响。
第 4 部分:我们的人工神经网络预测器的部署
在这一步中,我们将设计和训练我们的人工神经元网络。我们将使用 Keras 用 Python 编写我们的 ANN 并进行预测。
第五部分:结果讨论
是时候看结果了。我们将尽可能中立地描述和验证它们,看看我们的结果是否可靠。
第 6 部分:评论和进一步讨论
每个项目都需要严格的审查。在这里,我们将采取不同的观点,并试图撕裂我们的结果。我们将以一些关于如何改进我们的设置的建议来结束这个系列。
下一步是什么?
如果您有兴趣阅读更多内容,请随时查看该系列的第 2 部分。这篇文章深入解释了欧洲电力市场的价格形成过程。
来源
- 拉戈,德·里德,弗兰克斯和德·舒特。2018.预测欧洲日前电价:考虑市场一体化的重要性。阿姆斯特丹:爱思唯尔。
- 诺德泳池。2021.“Elspot 价格 2021 每日欧元”。最后修改时间 2021 年 12 月 16 日。https://www . nordpoolgroup . com/4a f83 f/global assets/market data-excel-files/els pot-prices _ 2021 _ daily _ EUR . xls
- 彭博。2021.“欧洲能源危机将持续,因为电力价格创纪录”。最后更改 2021 年 12 月 8 日。https://www . Bloomberg . com/news/articles/2021-12-08/energy-crunch-sends-benchmark-European-power-prices-to-record
- notes 复合材料。2021.“波兰的电价一年内几乎翻了一番”。最后修改时间 2021 年 10 月 7 日。https://notes fropland . com/2021/10/07/波兰的电力价格几乎一年翻了一番/
用人工神经网络预测电价——第二部分

安德烈·梅特列夫在 Unsplash 上拍摄的照片。
对欧洲电力市场以及如何从中赚钱的温和介绍。
我最近开始了一个“Python-How-to”系列,讲述在人工神经元的帮助下预测电价。顾名思义,本系列的目标是构建一个成功预测电价的人工神经网络(ANN)。然而,在我们开始编码之前,我们有一些跨学科的研究要做。
每个数据科学项目都需要一个商业案例
这与电力市场无关,但我怎么强调这一点都不为过。数据需要产生价值。如果不是这样,数据只会增加成本,让利益相关者感到沮丧。同样的原则也需要应用于数据科学。如果操作得当,数据科学项目将消耗大量内部和外部资源。你需要确保你的实验结果会为你的业务或研究领域带来价值。否则,你只是在浪费自己的时间,并可能在 AWS 计算能力上花费数千美元。如果你想有几个可能发生的例子,如果你没有做适当的研究,我可以向你推荐这篇文章。
因此,本系列的这一部分将只专注于向我们介绍欧洲电力市场。最后,我们希望了解市场如何运作,以及我们的商业案例会是什么样子。所以…我们走吧!
快速历史课
1980 年代初,由于基础设施在现代社会中日益重要,大多数发达国家和一些新兴市场开始放开其基础设施部门。结果,能源变成了像粮食或石油一样的商品,并分别形成了市场。今天,这些市场通常被称为能源市场。能源市场通常是指单个国家或地区,包括电力或天然气等一般形式的能源交易。电力市场仅描述国家或地区内的电力交易。它们通常由电力交易所运营,电力交易所是通过买卖竞价实现电力交易的系统。
今天,欧洲能源市场分为 19 个主要的电力交易所。欧洲最大的电力交易所是 EEX 集团,该集团包括 EEX 和 PXE 的金融电力合同平台,以及日前电力市场 EPEX Spot 和天然气平台 Powernext。第二大电力交易所是 Nord Pool,它经营现货和日内电力市场。Nord Pool 报告称,2018 年的交易量为 524 万亿瓦时。Nord Pool 目前服务于北欧以及德国、英国、荷兰、比利时、法国和波兰市场。下图显示了电流分布和交换机的互连。

2018 年欧洲日前市场耦合。图片由作者提供。
欧洲电力市场的结构
欧洲电力市场理论上分为金融市场、日前市场(以下简称现货市场)、日内市场和监管市场。

欧洲电力市场的理论分割。图片由作者提供。
金融市场
金融市场由各自的交易所经营,这些交易所通常与电力交易所分开。在这方面,金融市场主要用于价格对冲和风险管理。交易最频繁的产品是所谓的“期货”,例如每日、每周、每月或每年的期货。下面的例子说明了电力期货合约的原理。
德国的一家零售商和一家生产商签订了一份 4 兆瓦时的期货合同,套期保值价格为 65 欧元/兆瓦时。给出了交货的具体月份。双方有相互保险和相互义务。假设约定月份的平均系统价格为 66 欧元/兆瓦时。德国现货市场的高价对零售商不利。然而,由于生产商同意以 65 欧元/兆瓦时的价格出售电力,零售商将节省 4 欧元(1 欧元/兆瓦时* 4 兆瓦时= 4 欧元)。
然而,假设本月的平均系统价格为 63 欧元/兆瓦时。现货市场的低价将对生产商不利。在这种情况下,零售商补偿生产商。他付给他 8 欧元(2 欧元/兆瓦时 4 兆瓦时= 8 欧元)。*
期货合约通过比较特定时期的套期保值价格和平均系统价格来结算。差价乘以合同量。在这一点上需要注意的是,期货合同只管理货币的交换。没有电力供应。
现货市场
第二天交付的电力在现货市场交易(也称为“日前市场”)。市场参与者在交割日期的前一天中午之前以电子方式发送他们的投标。现货市场没有中间交易。第二天的每个小时都有人出价。下面的例子说明了这个过程。
如果一家德国零售商假设他的顾客在一个特定的小时内消费了 50 兆瓦时,他会在相应的时间段和数量下订单。如果零售商拥有他的发电厂,他有几个选择:
- 他从现货市场购买 50 兆瓦时的电力,自己不生产
- 他买了一些电,其余的自己生产
- 他自己正好生产 50 兆瓦时
- 他生产超过 50 兆瓦时的电力,并将多余的电力出售给现货市场
- 他从现货市场购买所有电力,并在现货市场出售生产的 50 兆瓦时电力
在本例中,零售商向德国现货市场下了以下订单。如果每小时的价格为 20 欧元/兆瓦时或更低,他购买 50 兆瓦时。如果价格为 40 欧元/兆瓦时,零售商购买 10 兆瓦时,自己生产剩余的 40 兆瓦时。如果价格为 50 欧元兆瓦时,零售商将出售 10 兆瓦时。如果价格在 50 到 60 欧元/兆瓦时之间,他将根据他的边际成本下降曲线出售电力。如果价格为 60 欧元/兆瓦时或以上,他将出售 30 兆瓦时。

德国现货市场上特定小时的示例性买价/卖价。图片由作者提供。
在现货市场上,所有的买卖订单被汇总,形成相应的供需曲线(见下图)。两条曲线的交点对应于各自小时的系统价格。现货市场计算每小时的价格。这种价格形成方式也被称为“双重拍卖”,因为买方和卖方都必须投标。因此,现货市场也被称为“日前拍卖市场”。

示例性总供给和需求曲线。图片由作者提供。
提交投标后,各交易所计算并公布日前价格。同时,交易所通知市场参与者他们在第二天的各个小时购买和/或出售了多少电力。这些报告被转发给传输系统运营商(“TSOs”)。tso 使用这些信息来计算平衡功率。
当天的市场
除了现货市场,电力也在日内市场交易。日内市场是连续的,电力可以在交割前 5 分钟进行交易。然而,这个时间窗口取决于交换。⁴
日内市场是现货市场的补充。尽管现货市场的供需平衡在很大程度上得到了保证,但在收盘和第二天交割之间可能会发生一些事件。例如,这种事件可能是法国的核电厂可能不得不关闭,或者德国的强风可能导致欧洲风能产量显著增加。在日内市场上,市场参与者可以交易电量来再次平衡市场。
为了做到这一点,欧洲中部时间下午 2 点到 3 点将公布当天市场的自由容量。价格是根据“先到先得”的原则确定的。在这里,最佳价格(最高买价和最低卖价)受到青睐。
平衡市场
平衡市场由 TSOs 管理,通过向不同的市场参与者购买和出售电力来平衡供需,从而确保输电系统的频率稳定。平衡市场上的价格通常在交货前 15 分钟确定。然而,这个时间可能因国家而异,因为它取决于现有的基础设施。平衡市场位于日内市场之后。⁴
欧洲电网具有 50Hz 的交流电,需要维持该交流电以确保电网的稳定性。可能发生的情况是,在现货市场上交易的电能在交付时不能满足实际生产或需求。如果生产者的发电量少于或购买者的用电量超过了现货市场上约定的量(超额需求),电网的交流电就会降到 50Hz 以下。TSOs 必须确保生产商向电网输送更多的电力。在这种情况下,没有达到目标的供应商必须为所谓的监管权力买单,才能履行他们的协议。其他发电商通过提供短缺的电力获得报酬,或者一些买家通过减少电力需求获得报酬。⁵
如果现货市场上约定的电量供应过多或使用过少(过量供应),那么交流电就会升至 50Hz 以上。为了防止这种情况发生,使用下调权力来保持市场的平衡。多余的供应卖给想要增加购买量的买家,或者卖给购买多余供应以减少产量的生产商。⁵
向上调节力和向下调节力也被称为“调节力”或“平衡力”。监管电力的价格不同于电力的现货价格。“调控价格”由优序形成。如果需要上调电力,即电力供应过剩的生产商可以向 TSO 提供电力。TSO 然后开始激活具有最低价格的订单,直到达到所需的电力水平。最后一个向上的订单设定调节价。低于上调价格的订单获利,这是最终调整价格与现货价格之间的差异造成的。下调价格遵循同样的方法。⁶
下图说明了这一过程。绿色矩形显示上调订单,如具有可用产能的生产商。黄色矩形显示下调订单,例如可以减少消费的零售商。所有订单都按价格递增排序。假设需要 400 MW 的上调。所有上调指令从最低价格开始激活,直到达到 400 MW。最后一笔订单的价格决定了调控价格。所有低于规定价格的订单的利润等于规定价格和现货价格之间的差额。⁶

平衡市场中的说明性定价。图片由作者提供。
假设关于上面的例子,一个零售商在现货市场上购买了 100 兆瓦时,但是他的顾客只消费了 85 兆瓦时。在这种情况下,零售商将把剩余的 15 兆瓦时出售给 TSO。如果 TSO 必须在这一小时购买上调电力,零售商将获得上调价格(与例如..向 TSO 出售过剩电力的生产商)。由于调节价格高于现货价格,零售商将从他的过剩能量中获得更高的利润。⁵
然而,如果 TSO 必须购买下调电力,他将根据下调价格(与生产商从 TSO 购买超额电力的价格相同)向零售商付款。在这种情况下,零售商将会亏损,因为调节价格低于现货价格。⁵
当 tso 出售管制权时,价格的确定方式与他们购买管制权时相同。如果在相应的小时内有上调,tso 将开具上调价格的发票。如果存在下调,tso 将开具下调价格的发票。这是另一个 example:⁶
假设零售商的一个供应商是一个生产商,他的太阳能发电场就在交货前坏了。由于现货市场和盘中市场已经关闭,生产商无法从其他供应商那里购买电力。然而,零售商仍然必须向生产商付款,即使生产商没有产生一个 MWh。在这种情况下,TSO 将监管权出售给生产商,生产商将监管权转售给零售商。⁶
如果生产商未能按照计划发电,他们必须与 tso 解决监管权问题。然而,生产商的价格是不同的。在上调监管的情况下,发电量过多的生产商只能获得现货价格。在上调电价的一个小时内,发电量过少的生产商将被收取上调电价的费用。在下调时段,发电量过多的生产商将获得下调价格。生产量过少的生产商将按照市场价开具发票。⁶
额外收获:拥堵管理和市场耦合
除了计算日前价格之外,现货市场也被用于阻塞管理。当输电线路的容量不足以根据市场需求传输电力时,电力系统就会发生拥塞。需要阻塞管理来确保电网的稳定性和区域或市场之间的电能供应。实现阻塞管理的方法有很多,然而,在欧洲最常用的方法是所谓的“隐式拍卖”。在隐性拍卖中,输电容量包含在电力拍卖中。⁷
现货市场可以由几个区域组成(例如在北欧地区,现货市场由 15 个单独的投标区域组成)。一些地区可能能源过剩,而另一些地区能源不足。在这种情况下,逆差地区依赖于来自顺差地区的进口。如果两个地区之间没有足够的传输能力,就会出现瓶颈和价格差异。因此,过剩地区的价格低于短缺地区,因为可用的能源多于消耗的能源。由于区域差异,这些价格也被称为“区域价格”。如果竞价区域之间的功率流动在 TSOs 设定的容量限制内,则这些不同竞价系统中的区域价格是相同的。以下示例说明了通过隐式拍卖形成区域价格的过程:

从挪威向瑞典出口 50 MW 的示例。图片由作者提供。
假设挪威是盈余地区,瑞典是赤字地区,供给和需求曲线是任意选择的。如果两个地区之间没有输电能力,价格就会不同。在这个假设的例子中,挪威的价格是 15 欧元/兆瓦时,瑞典的价格是 20 欧元/兆瓦时。

从挪威向瑞典进口 50 MW 的示例。图片由作者提供。
假设挪威和瑞典之间的输电容量为 50 MW。随着产能的增加,瑞典的价格将降至约 17.50 欧元/兆瓦时。随着消费量的增加,挪威的价格将升至约 17.50 欧元/兆瓦时。
因此,地区价格包括电力成本和输电成本。因此,阻塞管理以这样一种方式使用可用的传输容量,使得投标区域之间的价格差异尽可能地平衡。
此外,另一种形式的阻塞管理被整合到现货价格的形成中。所谓的“市场耦合”使用隐性拍卖,即市场参与者不直接分配跨境容量,而是通过在其交易所提交电力投标。然后,交易所利用边界点的可用容量来最小化两个或更多市场之间的价格差异。⁸
在市场耦合中,通过使用“EUPHEMIA”算法的隐式拍卖,各个交易所的所有出价被聚集和协调。EUPHEMIA 计算每个投标区域的市场出清价格,并确定各个区域之间的电力流量。该电流然后被用作各个交易所的本地价格计算的输入。
因此,相应的系统价格由它们的竞价区域的隐含拍卖以及连接的电力交易所的隐含拍卖形成。因此,计算系统价格的复杂性随着耦合市场数量的增加而增加。根据跨境交易电量对系统价格的影响,潜在因素的影响也会增加。因此,在电价预测中很难正确考虑市场耦合的影响。
我们的商业案例
欧洲电力市场的价格形成非常复杂,并且因市场而异。每个市场都带来了商机。例如,如果我们能够预测长期价格并击败期货市场,我们就可以创造收入。
然而,在我们的案例中,我们将关注欧洲最大的电力市场——现货市场。具体来说,我们将构建一个 ANN 来预测 Nord Pool 现货市场第二天每小时的价格。如果成功,我们的人工神经网络的输出数据可以出售给市场参与者,反过来,可以使用这些信息来提出更有效的购买/出售出价。
不幸的是,在这一点上我不得不发出警告。虽然这可能是一个真实的场景,但是请注意,这仅仅是本教程系列中的一个虚构的例子。在完成本系列文章时,您可能不会期望得到一个成熟的 ETL 数据服务,它会让您变得富有。我们的商业案例的经济成功取决于本系列中未涉及的许多不同的变量。
下一步是什么?
在本系列的下一部分,我们将对 Nord Pool 现货市场进行探索性的数据分析。我们将更详细地了解市场机制、不同的投标领域、电力组合和数据来源。在第三部分结束时,我们将确定用于训练人工神经网络的时间序列数据。
一旦下一部分完成,我将更新这一部分。然而,这将花费更长的时间,因为我已经计划了更多的文章。
来源
- 施耐德和耶格尔。2003.国家理论中的基础设施私有化:经验综述和对竞争性理论解释的讨论,101–137。康斯坦茨:康斯坦茨大学。
- 卡明斯基。2012.能源市场,20–47 和 199–253。伦敦:敏锐的媒体
- 诺德泳池。2017.北欧电力交易所和自由化电力市场的北欧模式。北池 AS
- 下一个 Kraftwerke。2019.“日内交易”维森。最后修改时间 2019 年 7 月 10 日。https://www.next-kraftwerke.de/wissen/intraday-handel
- 丝凯特。1999.北欧电力交易所 Nord Pool 的监管电力市场:计量经济学分析,295–308。阿姆斯特丹:爱思唯尔。
- 昂格尔。2018.可再生能源和常规能源,跨国界的相互作用,以及北部电力市场的电价,1–22。雷克雅未克:冰岛大学
- 莫泽。2018.单一欧洲电力市场——我们站在哪里,5–17。亚琛:亚琛大学。
- EPEX 斑点。2019.“新的日前价格耦合:问题与答案”文档。最后修改时间 2019 年 3 月 28 日。http://static.epexspot.com/document/22770/NWE -% 20 个问题% 20 和% 20 个答案
- 恩特索。2019.“物理能量和能量流”能量统计。最后修改时间 2019 年 06 月 03 日。【https://www.entsoe.eu/data/power-stats/
城市长期日需水量预测

加拿大伦敦泰晤士河。图片由妮可·奥斯本拍摄。
使用 Prophet 进行可解释、准确、快速的预测
Blake VanBerlo 是一名数据科学家,支持加拿大伦敦市的市政人工智能应用实验室。该实验室由信息技术服务部管理。布莱克关于我们开源人工智能项目的帖子。有关其他主要城市利益相关方的联系方式,请参见下面的“联系方式”部分。
摘要
加拿大伦敦市政府完成了一个应用机器学习项目,重点是获取全市长期水需求的每日预测(参见源代码)。本文叙述了该项目的生命周期,从研究到部署。最终的系统将一个 Prophet 模型与全市用水量的每日估计值相匹配,从而对未来四年做出可解释的预测。
介绍
预测是市政府的一项普通工作。其中一项任务是预测长期(即未来数年)的总需水量。合理可信的预测有助于城市进行水收入预测,从而实现可靠的预算。它们还可用于确定和规划对水基础设施能力的重大投资。此外,对这种预测的分析可以表征对消费模式的丰富见解(例如季节变化)。比较对各种费率类别的客户(例如,住宅、商业、工业等)的预测还可以有助于更好地理解不同人群的不断变化的需求,甚至更准确地预测收入。
伦敦金融城的市政人工智能应用实验室和水需求团队寻求调查是否可以为长期水需求预测任务开发更准确的预测模型。
本文将描述(1)预测问题,(2)使用的数据集,(3)搜索有效预测模型的过程,(4)如何部署模型以供未来重用,(5)可能的后续步骤,以及(6)市政当局如何轻松复制这种方法。

地点在加拿大伦敦。图片由妮可·奥斯本拍摄。
问题
在文献中,需水量预测通常分为两类:短期和长期。前者通常发生在几小时到几天的范围内。短期预测的一些努力已经被记录在案,通常使用历史用水量和天气数据等特征(见[1-5]中的例子)。长期预测是指确定几年(甚至几十年)内的大致消耗量的预测。这些方法可能使用各种特征,如历史消费、气候模式、国内模式和经济因素(见[1,6–8])。
水需求管理团队最感兴趣的是对未来至少 4 年进行预测,这与该市 4 年的多年预算规划周期相对应。具体来说,该问题被定义为:
预测至少未来 4 年内任何日期的日用水量(单位:立方米)。
我们非常灵活地处理这个问题,随着调查的深入,我们缩小了解决方案的范围。
资料组
我们能够获得 2009 年年中和 2020 年年中之间所有客户的账单数据。总的来说,我们只剩下 10 年多一点的账单数据。不幸的是,我们缺少两个日期范围的数据:2014 年 3 月 1 日至 2014 年 9 月 30 日,2017 年 3 月 25 日至 2017 年 5 月 31 日。稍后我们将讨论缺失数据是如何成为我们选择模型的一个因素的。
数据以一系列 CSV 文件的形式提供给我们,每个季度一次(或多或少)。每一行都包含一个客户在一个计费周期内的总用水量,以及其他相关属性。也就是说,每个账单周期每个地址有 1 条记录。每个计费周期都有一个开始日期和一个结束日期。账单周期约为一个月,但在数据集中差异很大。使情况更加复杂的是,客户之间的计费周期相互抵消。计费周期的差异与以下事实有关:该信息来自于在城市中行驶的车辆的数字仪表读数,被动地收集数据,这意味着对任何一个客户的收集不一定以一个月的确切间隔进行。我们留下了一个需要解决的逻辑问题:我们如何准确地表示特定时间段内全市的用水量?
回想一下,我们的目标是为特定日期的全市用水量生成一个预测。也就是说,我们的目标是将消耗数据从提供的格式转换为一系列全市用水量的每日估计值。我们将时间步长选择为 1 天,以最大化数据集的粒度,并将训练数据量增加约 30 倍。为了估计特定历史日期的每日消耗量,我们设计了以下方法:
- 在数据集中找到包含日期 d. 的账单周期集
- 将集合中每个计费周期的消耗量除以其天数。
- 对步骤 2 的结果求和。
最终结果是现有历史范围内每日估计消费量的时间序列数据集。鉴于业务成果是提供系统范围内消耗的长期预测,我们有信心使用上述程序来估计日常消耗。上述过程中固有的假设是,在整个计费周期内,每个客户的日消耗量是恒定的。请注意,这种假设将消除任何模型在短时间尺度上捕捉变化的能力(例如工作日和假日影响)。

根据水费数据计算出的全市日用水量估计值(立方米)。图片作者。
我们还转换了所有非消耗特征(例如,水表类型、土地面积、建筑分类等),以创建每个日期的每个特征值的综合度量。对于数字特征,我们为账单周期超过日期 d. 的所有客户创建了平均值和标准差特征,我们还为日期 d. 的数据集中分类特征的值的出现次数创建了特征
候选模型
对于我们的预测任务,我们考虑了四种可供选择的建模技术。在这项工作之前,水需求团队一直在使用基于使用类别、临时模型和最近的线性回归的外推组合来产生用水量预测;因此,线性回归被列为基线。这些技术列举如下:
- 普通最小二乘线性回归(缩写 OLS
- 一种递归神经网络,具有一个 LSTM 层,后面是两个完全连接的层(缩写为 LSTM-RNN )
- 一个卷积神经网络,有一个 1 维卷积层,后面是两个完全连接的层(缩写为 1D-CNN )
- 先知,有每年的季节性
我们向任何不熟悉先知的读者推荐它的创造者的论文【1】。简而言之,Prophet 是分段线性趋势函数、周期函数和特定于假日的函数的组合。
初步实验表明,非消费特征对该模型产生的预测几乎没有影响。我们的理论是,这可能是因为它们在数据集中相当长的时间内处于停滞状态。考虑总仪表类型比率或土地面积的平均值和标准偏差不会每天发生显著变化。此外,水需求团队对单变量消耗模型最感兴趣。因此,我们放弃了非消费特征,而专注于使用消费数据的单变量预测。
评估方法
为了达到模型性能的公平表示,所有的训练实验都使用类似于 Tashman 和 Leonard [10]提出的滚动原点交叉验证策略进行。由于我们在 2017 年有缺失数据,而神经网络不能很好地处理缺失数据,我们从 2017 年 6 月 1 日起,在连续数据的子集上评估了四个模型。在此阶段,对数据集的 4 个最新六等分进行滚动原点交叉验证。

作者对折叠 k .图像的训练/验证/测试分割。
对每个候选模型进行贝叶斯超参数优化,以使它们有最好的机会进行最终评估。通过运行交叉验证,并使用测试集的平均绝对百分比误差(MAPE)作为目标,对研究的每个特定超参数组合进行评估。对于每个模型,我们检查了目标上每个参数的部分依赖图,并相应地选择了最佳超参数。请参见下面的 Prophet 示例。

Prophet 的部分相关图(PDP ),根据贝叶斯超参数优化的结果创建。较亮的区域对应于较低的物镜值。黑点对应于优化的每次迭代的超参数值,红星表示最佳迭代。对角线上的图形是一维 PDP。红线表示最佳迭代。图片作者。
表演
然后,我们使用最佳超参数对每个模型进行交叉验证。性能指标列表包括平均绝对误差(MAE)、MAPE、均方误差(MSE)和均方根误差(RMSE)。下表总结了每个候选模型的结果。

每个候选模型的测试集性能指标,在所有交叉验证试验中取平均值。粗体表示每个指标的最佳值。图片作者。
总的来说,Prophet 拥有最好的性能指标。然而,LSTM-RNN 紧随其后。Prophet 最小化了对利益相关者最重要的指标,即 MAPE。Prophet 还具有最低的 MSE,这可能表明它能更好地处理高方差。
可解释性
由于预测将用于辅助决策,可能会影响市政预算、政策制定和费率等级定义,因此水务经理需要了解模型做出预测的原因。在四个候选模型中,有一半是内在不可解释的。LSTM-RNN 和 1D-CNN 都是神经网络模型,被认为是黑盒模型。如果要选择这些模型中的一个,可能需要使用可解释性算法来为每个预测产生解释,这将需要额外的工作并增加生产中的计算成本。
OLS 和先知,另一方面,是天生的解释。线性回归模型很容易理解,因为它们的系数直接对应于每个特征对最终预测的相对影响。如前所述,拟合的先知模型是简单函数的组合。在这个项目中,拟合的 Prophet 模型是线性分段趋势、年度傅立叶级数函数、周傅立叶级数函数和假日的参数化映射函数的总和。可以获得并保存每个功能的参数。这四个组成部分可以分开并绘制如下:

最终 Prophet 模型的组件根据所有可用数据进行训练。顶部的两个图中显示了训练集中所有日期的趋势和假日部分(在 x 轴上标记为“ds”)。底部的两个图形显示了拟合的年度和周周期函数的一个周期。图片作者。
上图也揭示了一些关于伦敦用水模式的有趣见解。水需求的总体趋势一直在稳步增长,这与该地区不断增长的居住人口相对应。请注意,在温暖的夏季会出现使用高峰,而在寒冷的冬季会有所下降。我们对消费量每周明显变化的真实性持谨慎态度。首先,请注意图表的比例非常小。人们认为,一周内的消费量确实存在显著的周变化。该模型没有考虑到这一点并不奇怪,因为如上所述,每日估计值是在不相交的计费周期内平均的,这可能会消除任何重大的工作日变化。节假日也有类似的影响,因为在预处理过程中对计费周期进行平均会消除大部分节假日影响。
最终型号选择
除了性能稍差之外,神经网络模型缺乏可解释性也是它们被选为最终模型的主要障碍。Prophet 的另一个好处是它的训练速度(我们的数据集需要几分钟)。此外,在拟合 Prophet 时,可以使用整个数据集,而不管缺失消费数据的间隔。Prophet 卓越的性能指标、低计算成本和固有的可解释性使其成为自然选择。
下图展示了 Prophet 在由最新数据组成的测试集上表现良好的能力。

左上: Prophet 对训练集的预测与地面真实日消耗量(即“gt”)进行对比。右上: Prophet 对 6 个月测试集的预测与来自测试集的地面真实消耗的比较。左下:残差(训练集 MAE)和测试集误差(MAE)。右下:残差和测试误差的分布。消耗量以立方米表示。图片作者。
由于这项调查是在 2020 年底进行的,测试集恰好完全落在新冠肺炎疫情的头几个月。在此期间,水消费模式异常(见 2020 年的显著峰值)。
预言家预测
为了进行预测,Prophet 推断未来的最新线性趋势,添加了年度周期函数、周周期函数和假日函数。不确定性区间是基于趋势在未来发生变化的可能性而创建的。由于拟合模型在训练集上包括非常少的趋势变点,不确定性区间相当窄。
我们根据所有可用数据(未使用测试集)对 Prophet 进行了训练,并得出了以下 4 年预测:

预测表明,伦敦的水需求将在未来几年继续增加。预测中的波峰和波谷分别对应夏季和冬季需求的增加和减少。原则上,这种预测可以无限期延长,但依赖对未来太远年份的预测是不明智的,因为不知道未来的重大事件是否会导致趋势的重大变化。
部署和支持
水盲管理团队的目标是,只要有新的原始数据可用,就继续生成新的预测。每季度将计费数据下载到数据库中。因此,将通过对所有可用数据(包括新季度的数据)拟合 Prophet 模型来生成新的 4 年预测。
云架构
该模型是使用微软 Azure 云计算服务部署的。部署场景分为两个任务。首先,模型将在所有可用数据的前 90%上进行训练,并在剩余的 10%上进行测试,保存模型性能记录以供业务批准。第二,根据所有可用的训练数据对模型进行训练,并生成 4 年预测,以及模型的每个功能组件的数字(即趋势、年度、周、假期)。开发了一个 Azure 机器学习管道来执行这些任务。所有数据都存储在 Azure Blob 存储器中。
该管道由以下步骤组成:
- 预处理最近一个季度的数据,并将其附加到所有历史日期的每日消耗量估计值中。
- 针对前 90%的单变量消耗数据训练 Prophet 模型,并在测试集上保存性能指标。然后对所有消耗数据训练一个 Prophet 模型,保存该模型的功能组件,并使用该模型创建一个 4 年预测。
一个 PowerBI 仪表盘消耗汇总的原始数据和模型做出的预测。每当最新的季度消费数据被上传到原始数据的 Azure blob 容器时,管道就会被 Azure Logic 应用程序自动触发。

加拿大伦敦童话花园被水淹没的溜冰场上的溜冰者。图片由妮可·奥斯本拍摄。
后续步骤
未来的一个潜在任务是分析为按费率等级分层的客户子集产生的预测。该市根据不同的收费等级向用户收取不同的水费。费率等级目前包括:住宅、商业、工业、公共机构和消防线。比较每个等级的预言家预测将是一个有趣的研究问题,并可能有助于城市的等级政策制定。这种预测还将提供更详细的市政供水收入的长期估计。
如前所述,气候经常被用作获取长期需水量预测的一个特征。未来的研究可能包括气候特征,并描述气候变化对城市水需求的影响及其对未来水需求的影响。
我的城市如何使用这个?
如果你有城市用水的历史记录,你的城市可以采用这种方法。这里我们提供一些开始的建议。
首先,您所在的城市需要一个由以下专业人员组成的团队:
- IT 经理:管理和支持参与项目的所有员工;最好熟悉数据科学基础知识
- 数据科学家:领导研发工作;应具备数据科学专业知识和经验;如果云服务是您生产模型的最终部署路径,最好有云服务方面的经验
- 水需求经理/团队:确定项目需求,充当应用领域专家,并评估由数据科学成员产生的性能/可解释性工件
- 数据工程师:导航对消费数据的访问。在我们的案例中,我们的水需求经理和伦敦水电的团队履行了这一职能。
要获得我们的代码,您可以克隆我们的公共 GitHub 库。存储库的首页包括详细的代码文档。请注意,我们的原始消费数据可能与您的数据格式不同,因此您可能需要努力将原始数据转换为时间序列消费数据集。
我们已经提交了一份详细说明我们方法的论文,正在等待发表的决定。如果论文被接受,我们将更新这篇文章以提供论文的链接。
接触
马特·罗斯
人工智能经理
信息技术服务
伦敦金融城
maross@london.ca
Blake van berlo数据科学家
伦敦金融城市政人工智能应用实验室
vanberloblake@gmail.com
夏伟
水需求经理
水务工程
伦敦金融城
dhsia@london.ca

图片来自 Pixabay 的 Renee Gaudet
参考
[1] H. Liu,用 ANN 和 SD 模型进行城市短期和长期需水量预测 (2020),阿尔伯塔大学
[2] J. Adamowski,H. Fung Chan,S. O. Prasher,B. Ozga-Zielinski 和 A. Sliusarieva,加拿大蒙特利尔城市需水量预测的多元线性和非线性回归、自回归综合移动平均、人工神经网络和小波人工神经网络方法的比较 (2012),水资源研究
[3] S. Shah,M. Hosseini,Z. B. Miled,R. Shafer 和 S. Berube,印第安纳州中部需水量预测模型 (2018),第 32 届 AAAI 人工智能会议
[4] L. Shvartser,U. Shamir 和 M. Feldman,用模式识别方法预测每小时需水量 (1993),水资源规划与管理杂志
[5]杜,赵,薛,:M: 基于自回归滑动平均模型和马尔可夫链误差修正的日用水量预测新模型 (2020),水(瑞)
[6] C. Qi 和 N. Chang,不确定经济影响下城市区域市政需水量估算的系统动力学建模 (2011),环境管理杂志。
[7] K. Wang 和 e . r . Davies,基于终端用户模拟模型的市政水规划和管理 (2018)环境建模&软件
[8] M. Shrestha,S. Manandhar 和 S. Shrestha,利用人工神经网络预测气候变化下的需水量:尼泊尔加德满都河谷的案例研究 (2020),水科学与技术:供水
[9] S .泰勒和 b .勒森,大规模预测 (2018),美国统计学家
[10] L. J. Tashman,预测准确性的样本外检验:分析和评论 (2000 年),《国际预测杂志》。
用 NumPyro 预测曼哈顿山谷公寓的销售
使用贝叶斯方法生成基于概率的预测

来源:图片来自 Pixabay
NumPyro 是一个日益流行的概率编程工具,用于贝叶斯分析。与其他贝叶斯库相比,使用 NumPyro 的一个主要优势是速度。NumPyro 由 JAX 提供支持,这允许使用自动签名来区分原生 Python 和 NumPy 函数。更重要的是,XLA 可以用于在 GPU 和 TPU 上运行 NumPy 程序,这使得性能特别快。
NumPyro 本身构建于 PyTorch 之上,而 PyMC3(另一个特别流行的贝叶斯库)构建于 Theano 之上。
除了使用 NumPyro 的速度优势之外,该库还提供了大量的概率编程工具——在这个例子中,我们将研究时间序列预测的用例。
在这个例子中,NumPyro 将用于预测曼哈顿山谷每季度的总公寓销售量。
数据
数据来源于纽约公开数据,曼哈顿山谷的公寓——电梯公寓——的销售价格是从 2003 年到 2015 年按季度汇总的。
在处理时间序列时,一个很好的经验法则是时间序列越长,数据就越有意义。
让我们以房地产销售为背景来考虑这个问题。
在曼哈顿谷——有时会发生非常昂贵的房产销售,这可能会极大地扭曲该时期的总销售额。例如,2004 年公寓的平均价格为 825,983 美元,但最贵的公寓售价超过 45,388,000 美元!
在这方面,在这种情况下,使用每月时间序列会导致 2004 年 7 月出现异常大的峰值(当时出售了价值 4500 万美元的房产)。使用季度数据有助于在一定程度上消除这些异常。
当按季度合并销售数据时,我们会发现,在某些季度,总体销售会出现明显的高峰。

来源:Jupyter 笔记本输出
时间序列
当使用传统的时间序列模型(如 ARIMA 模型)时,一个特别重要的考虑因素是特定序列的季节性趋势。如果一个时间序列以一定的时间间隔显示出重复的模式(不同于这些重复模式随机发生的循环时间序列),那么这使得该序列更容易预测。
我们可以看到,严格地说,在这种情况下,时间序列不遵循季节模式,或者至少不是一个重要的模式。自相关滞后低于证明的 95%置信区间(蓝色阴影)。

来源:Jupyter 笔记本输出
也就是说,使用贝叶斯分析的目的是提供一个概率预测。换句话说,虽然我们无法确切知道一个时间序列是否遵循特定的模式,但我们可以对它是否遵循特定模式进行概率评估。
在上面的自相关函数中,我们可以看到相关性大约在每 9 个滞后时达到峰值。
从图表本身来看,我们看到销售似乎在大约每 8-10 个季度达到峰值。

来源:Jupyter 笔记本输出
从这个角度来看,让我们假设一个季节性因素为 10 来进行预测。请注意,在运行模型时,确实可以尝试不同的季节因素来确定哪些因素提供了最佳预测。
使用季节性全球趋势(SGT)模型进行预测
在这个例子中,使用了由 num.pyro.ai 网站提供的模板——它复制了最初在 r
SGT 模型使用学生的 t 分布代替正态分布来表示可能性,因为前者的尾部更重。
该模型由趋势和季节组件组成,并且该模型使用所谓的级别和 s 组件来更新趋势值。
例如,如在 SGT 模型的函数下定义的,level_sm 和 s_sm 都定义如下:
level_sm = numpyro.sample("level_sm", dist.Beta(1, 2))
s_sm = numpyro.sample("s_sm", dist.Uniform(0, 1))
本质上,这只是表示贝塔分布和均匀分布都作为连续概率分布,模型的随机成分根据计算的概率随时间更新。
这是该模型的主要优势之一。例如,我们在自相关函数中看到,模型中可能存在某种季节性模式——但还没有显示出具有统计显著性。可能的情况是,在更长的一段时间内,我们可能会观察到一个显著的季节性模式——但只是没有足够的数据来调查是否是这样。但是,该模型可用于定义在特定时期观察季节模式的概率,并相应地生成基于概率的预测。
该模型还可以更擅长处理不确定性——我们可能无法肯定地说公寓销售何时会出现大幅增长——但我们可以尝试给出一个概率。
假设我们在设计的数据集上总共有 52 个季度,前 40 个季度将用于训练目的,其余 12 个季度用于测试目的。
y_train, y_test = jnp.array(data[:40], dtype=jnp.float32), data[40:]
在定义函数、训练和测试集时,可以生成 5000 个 MCMC(马尔可夫链蒙特卡罗)样本。 NUTS (或 No-U-Turn 采样器)是一种加速采样过程的方法,它避免了通过随机游走方法生成样本,而是选择识别可能的候选点,从而更快地生成目标分布。
该模型运行如下:
%%time
kernel = NUTS(sgt)
mcmc = MCMC(kernel, num_warmup=5000, num_samples=5000, num_chains=4)
mcmc.run(random.PRNGKey(0), y_train, seasonality=10)
mcmc.print_summary()
samples = mcmc.get_samples()
该模型生成以下结果:

来源:Jupyter 笔记本输出
现在,可以进行预测,并且可以估计预测的准确性。
>>> predictive = Predictive(sgt, samples, return_sites=["y_forecast"])
>>> forecast_marginal = predictive(random.PRNGKey(1), y_train, seasonality=10, future=12)[
>>> "y_forecast"
>>> ]>>> y_pred = jnp.mean(forecast_marginal, axis=0)
>>> sMAPE = jnp.mean(jnp.abs(y_pred - y_test) / (y_pred + y_test)) * 200
>>> msqrt = jnp.sqrt(jnp.mean((y_pred - y_test) ** 2))
>>> print("sMAPE: {:.2f}, rmse: {:.2f}".format(sMAPE, msqrt))sMAPE: 38.90, rmse: 22167788.00
让我们看一下预测图,试图更好地理解这些数字。

来源:Jupyter 笔记本输出
我们可以看到,该模型总体上捕捉到了整体趋势,即测试集中前几个季度的销售额下降,随后出现显著上升趋势。虽然主要预测(橙色线)没有捕捉到某个特定季度的公寓销售大幅飙升,但概率区(浅蓝色)大致表明,未来可能会出现大幅飙升。
在 RMSE(均方根误差)的基础上,22,167,788 的 RMSE 与通过测试集计算的 37,448,102 的总平均销售额相比是显著的。
然而,由于 RMSE 受到异常值的显著影响,我们可以预计在这种情况下这个数字会很大。当查看原始示例中所示的 lynx 数据集分析时,计算出的 RMSE 1249.29 与测试集中计算出的平均值 1978.41 相比也非常显著。
在这方面,贝叶斯主导的时间序列模型具有价值,因为它可以帮助提供一系列情景的预测,并消除处理较小数据集时固有的不确定性。在这种特殊情况下,该模型非常有用,因为虽然我们无法确定地定义季节性因素,但我们可以使用基于概率的方法来估计趋势和季节性因素的波动。
结论
总之,在这个例子中,您已经看到了 NumPyro 如何用于:
- 定义 SGT(季节性、全球趋势)模型
- 使用这样的模型来随着时间更新概率估计
- 利用不掉头采样器生成 MCMC 样本
- 生成概率导向的预测并确定其准确性
非常感谢您的时间,任何问题或反馈都非常欢迎。你可以在 michael-grogan.com 找到更多我的内容。
免责声明:本文是在“原样”的基础上编写的,没有担保。它旨在提供数据科学概念的概述,不应被解释为专业建议。本文中的发现和解释是作者的发现和解释,不被本文中提到的任何第三方认可或隶属于任何第三方。
使用高斯过程预测葡萄牙新的新冠肺炎病例
实践教程
使用 Python 和贝叶斯统计预测 30 天的新病例
1.介绍
我更喜欢在不同的主题和不同的背景下做这个分析。今天,葡萄牙是每百万人中新增新冠肺炎病例绝对数量最多的国家【1】。我不想让这成为一篇政治文章,但是遏制病毒的传播是非常必要的。这需要更多的政治勇气来采取必要的措施,另一方面,需要普通民众更加严格的行为,尊重既定的封锁规则。
既然我已经把这些想法抛开了,让我们把注意力集中在科学工作上。新冠肺炎数据集可能是有史以来分析最多的,各种模型都被用来预测它的行为。疫情的扩散有一个已知的动态,通常很好地符合房室模型。然而,在这种情况下,我们有一个前所未有的全球传播,有许多因素影响它。例如,各国正在采取不同的措施来阻止传播,其中一些措施对新病例的数量产生了较大的影响,而另一些措施则影响不大。这是一个边做边学的过程,尽可能利用科学来帮助政治决策。
本文的范围是对葡萄牙新病例数量的预测。我们将试着展望未来 30 天,看看会有什么不同的情况摆在我们面前。为了克服手头的困难模式,我们将使用高斯过程,这是众所周知的非常灵活。
这篇文章是科学练习;请不要根据其结果采取任何行动。
像往常一样,你可以在我的 GitHub 上找到所有代码。
2.高斯过程
本节给出高斯过程背后的理论的一些背景。如果您对该应用程序更感兴趣,请随意跳过它。
高斯过程是一种贝叶斯非参数方法。通常,在贝叶斯框架中,我们感兴趣的是推断用于拟合数据(可能性)的第二个分布的参数分布。在这种情况下,我们直接推断函数的分布。
更实际地说,高斯过程是一种随机过程,其中我们将随机变量(或函数)f 分配给有限数量的离散训练点,即我们的 x。这些变量的联合分布也是高斯分布:

其中μ=(m(x_1),…,m(x_N))是均值函数,K_ij=k(x_i,x_j)是定义协方差矩阵的核函数,f=(f(x_1),…,f(x_N)是函数值的实现。例如,如果内核认为 x_i 和 x_j 是相似的,则在这些点 f(x_i)和 f(x_j)处的函数值可以预期具有相似的值。
2.1 多元高斯分布
高斯过程的基础是多元高斯分布,多元高斯分布是高斯分布的多维推广(参见【2】进行交互解释)。在多元情况下,分布由平均向量μ和对称正定协方差矩阵σ定义。前者代表每个随机变量的期望值,而后者描述了两种现象:它的对角线表示每个维度的方差,非对角线表示所有随机变量之间的协方差。它基本上衡量随机变量如何一起变化。
多元高斯分布具有以下联合概率密度:

其中 x 是大小为 d 的随机向量,而|σ|是 dxd 矩阵σ的行列式。
为了更好地理解这些参数如何改变分布,让我们在二维高斯分布上画两个简单的例子。在第一个例子中,变量是独立的,在第二个例子中,变量是协变的(参见非对角线值)。

这可以概括为:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.gridspec as gridspec
import pandas as pd
import pymc3 as pm
import theano.tensor as tt
import arviz as az
from numpy.linalg import inv
from numpy.linalg import det
from scipy.optimize import minimize
pd.options.mode.chained_assignment = Nonedef multivariate_normal(x, d, mean, covariance):
return (1\. / (np.sqrt((2*np.pi)**d * np.linalg.det(covariance)))
* np.exp(-(np.linalg.solve(covariance, x-mean).T.dot(x-mean))/2))def calculate_pdf(mean, covariance, d):
x_ = 100
xs = np.linspace(-5, 5, x_)
ys = np.linspace(-5, 5, x_)
x, y = np.meshgrid(xs, ys)
pdf = np.zeros((x_, x_))
for i in range(x_):
for j in range(x_):
pdf[i,j] = multivariate_normal(
np.matrix([[x[i,j]], [y[i,j]]]),
d, mean, covariance)
return x, y, pdffig, ax = plt.subplots(nrows=1, ncols=2, figsize=(8,4), sharey=True)
d = 2
mean_ind = np.matrix([[0.], [0.]])
covariance_ind = np.matrix([
[1., 0.],
[0., 1.]])
x, y, p = calculate_pdf(
mean_ind, covariance_ind, d)
ax[0].contourf(x, y, p, 100)
ax[0].set_xlabel('$X$', fontsize=13)
ax[0].set_ylabel('$Y$', fontsize=13)
ax[0].axis([-2.5, 2.5, -2.5, 2.5])
mean_corr = np.matrix([[0.], [0.]])
covariance_corr = np.matrix([
[1., 0.8],
[0.8, 1.]])
x, y, p = calculate_pdf(
mean_corr, covariance_corr, d)
con = ax[1].contourf(x, y, p, 100)
ax[1].set_xlabel('$X$', fontsize=13)
ax[1].set_ylabel('$Y$', fontsize=13)
ax[1].axis([-2.5, 2.5, -2.5, 2.5])
ax[0].set_title('Independent variables', fontsize=12)
ax[1].set_title('Correlated variables', fontsize=12)
fig.subplots_adjust(right=0.8)
cbar_ax = fig.add_axes([0.85, 0.15, 0.02, 0.7])
cbar = fig.colorbar(con, cax=cbar_ax)
cbar.ax.set_ylabel('$p(x, y)$', fontsize=13)
plt.show()

多元高斯是如此有用,由于它的代数性质,确保我们也得到高斯分布时边缘化和条件。
边缘化意味着从原始变量集中整合出变量。结果是变量子集的分布,而不参考我们整合出来的变量。所以如果我们只对 X 的概率密度感兴趣:

如前所述,这也会导致高斯分布:

def univariate_normal(x, mean, variance):
return ((1\. / np.sqrt(2 * np.pi * variance)) *
np.exp(-(x - mean)**2 / (2 * variance)))fig = plt.figure(figsize=(7, 7))
gs = gridspec.GridSpec(
2, 1, height_ratios=[2, 1])
plt.suptitle('Marginal distributions', y=0.93)
ax1 = plt.subplot(gs[0])
x, y, p = calculate_pdf(mean_corr, covariance_corr, d)
con = ax1.contourf(x, y, p, 100)
ax1.set_xlabel('$x$', fontsize=13)
ax1.set_ylabel('$y$', fontsize=13)
ax1.axis([-2.5, 2.5, -2.5, 2.5])
ax2 = plt.subplot(gs[1])
x = np.linspace(-5, 5, 100)
px = univariate_normal(x, mean_corr[0,0], covariance_corr[0, 0])
ax2.plot(x, px, '--', label=f'$p(x)$')
ax2.legend(loc=0)
ax2.set_ylabel('density', fontsize=13)
ax2.yaxis.set_label_position('right')
ax2.set_xlim(-2.5, 2.5);

条件反射时也是如此,条件反射是一个变量依赖于另一个变量的概率。

让我们为我们的例子计算 p(X|y=1 ):
y_cond = 1.
mean_x_cond_y = mean_corr[0,0] + (covariance_corr[0, 1]*(1/covariance_corr[1, 1])*(1 - mean_corr[1, 0]))
cov_x_cond_y = covariance_corr[0,0] - covariance_corr[0,1]*(1/covariance_corr[1,0]) * covariance_corr[0,1]fig = plt.figure(figsize=(7, 7))
gs = gridspec.GridSpec(
2, 1, height_ratios=[2, 1])
plt.suptitle('Conditional distributions', y=0.93)
ax1 = plt.subplot(gs[0])
x, y, p = calculate_pdf(mean_corr, covariance_corr, d)
con = ax1.contourf(x, y, p, 100)
ax1.set_xlabel('$x$', fontsize=13)
ax1.set_ylabel('$y$', fontsize=13)
ax1.axis([-2.5, 2.5, -2.5, 2.5])
ax1.plot([-2.5, 2.5], [y_cond, y_cond], color='lightblue', linestyle='dashed')
ax2 = plt.subplot(gs[1])
x = np.linspace(-5, 5, num=100)
px = univariate_normal(x, mean_x_cond_y, cov_x_cond_y)
ax2.plot(x, px, '--', label=f'$p(x|y=1)$')
ax2.legend(loc=0)
ax2.set_ylabel('density', fontsize=13)
ax2.yaxis.set_label_position('right')
ax2.set_xlim(-2.5, 2.5);

2.2 高斯过程回归
现在我们已经了解了多元高斯性质,是时候将它们结合起来解决回归问题了。首先,我们需要介绍一些概念。
执行高斯过程回归的基本思想是,我们的高斯过程会将概率分配给可能符合我们数据的无限函数。这种概率表达了模型的不确定性,这为我们提供了一个强有力的指示,表明我们应该在多大程度上信任点预测,即所得概率分布的平均值。
2.3 内核
内核定义了我们能够从函数分布中抽取的函数类型。虽然高斯过程是非参数方法,但核函数有参数,允许我们控制特定类型函数的形状。让我们做一个例子来理解这意味着什么。
最常用的核之一是平方指数核:

其中长度 l 控制函数的平滑度,η控制函数的振幅。
az.style.use('arviz-darkgrid')
def sq_e_kernel(x1, x2, l=1.0, η=1.0):
sqdist = np.sum(x1**2,1).reshape(-1,1) + np.sum(x2**2, 1) - 2 * np.dot(x1, x2.T)
return η**2 * np.exp(-0.5 / l**2 * sqdist)# Finite number of points
X = np.arange(0, 100).reshape(-1, 1)
cov = sq_e_kernel(X, X, l=5)
m = plt.imshow(cov, cmap="inferno", interpolation='none')
plt.colorbar(m);

如果我们绘制协方差函数的第一条线,我们可以看到基于该函数产生的点之间距离的指数衰减。
plt.plot(cov[:,0]);

2.4 先前
我们上面定义的是多元分布的协方差矩阵。这意味着我们终于可以访问我们功能的实现了;我们需要从多元高斯分布中取样。我们可以在不实际观察任何训练点的情况下进行采样。这在进行预先预测检查时非常有用——我们将使用这一贝叶斯特性来分析新冠肺炎数据。
让我们为高斯过程定义μ=0。我们将看到,我们可以通过不同的核或核的组合,仅使用协方差矩阵来模拟各种行为。让μ=0 是一种标准的做法。
samples = np.random.multivariate_normal(np.zeros(100), cov, size=3)
plt.plot(samples.T);

我们可以控制核的参数或核的组合来重塑结果函数。下面,您可以使用平方指数内核找到 3 种不同的参数组合。
_, ax = plt.subplots(3, 2)
ax = ax.ravel()
l_p = [0.1, 2, 10]
η_p = [10, 2, 2]
for i in range(6):
cov = sq_e_kernel(X, X, η=η_p[i//2], l=l_p[i//2])
if not i%2:
ax[i].imshow(cov, cmap="inferno", interpolation='none')
samples = np.random.multivariate_normal(np.zeros(100), cov, size=3)
else:
ax[i].plot(samples.T)

2.5 后部
为了完成理论介绍,我们需要插入我们的测试点,也就是我们想要估计新函数的新点。这就是我们使用多元高斯的条件属性的地方,正如我们在上面看到的,它也产生高斯分布。

在上面的表达式中,我们假设训练数据和预测中都没有噪声。在我们的训练数据中包括噪声是通过独立地将噪声添加到每个观察值中来实现的,

为了考虑预测中的噪声,我们将其添加到 K_**的对角线上。
如果在第一种情况下不考虑误差项,则调节的函数集合将精确地通过每个训练点。在后一种情况下,包含噪声可以被视为在我们当前的核中添加一个白噪声核,这有助于在我们的预测中建模小的不规则性。
def posterior(X_s, X_train, Y_train, l=1.0, η=1.0, noise_train=1e-8, noise_predict=1e-8):
K = sq_e_kernel(X_train, X_train, l, η) + noise_train**2 * np.eye(len(X_train))
K_s = sq_e_kernel(X_train, X_s, l, η)
K_ss = sq_e_kernel(X_s, X_s, l, η) + noise_predict**2 * np.eye(len(X_s))
K_inv = inv(K)
mu_s = K_s.T.dot(K_inv).dot(Y_train)
cov_s = K_ss - K_s.T.dot(K_inv).dot(K_s)
return mu_s, cov_s
让我们用后验函数来决定新点 X_*上的先验。首先,我们在没有任何噪声的情况下定义我们的训练数据,并且在不考虑任何噪声的情况下拟合预测。
X_train = np.arange(0,16).reshape(-1,1)
Y_train = np.sin(X_train)
X = np.linspace(0, 20, 100).reshape(-1, 1)
mu_new, cov_new = posterior(X, X_train, Y_train, noise_train=0, noise_predict=0)
samples = np.random.multivariate_normal(mu_new.ravel(), cov_new, 3)
uncertainty = 1.96 * np.sqrt(np.diag(cov_new))
plt.plot(X.ravel(),samples.T)
plt.fill_between(X.ravel(), mu_new.ravel() + uncertainty, mu_new.ravel() - uncertainty, alpha=0.1);

当我们向我们的训练数据添加噪声,但不向我们的模型添加任何噪声时,我们可以看到我们完全过度拟合了数据的不规则行为。
另一方面,当我们对噪声建模时(在第二个图中),我们可以看到我们可以相对更好地恢复数据中存在的潜在模式。
noise_train = 0.8
X_train = np.arange(0,16).reshape(-1,1)
Y_train = np.sin(X_train) + noise_train * np.random.randn(*Y_train.shape)
_, ax = plt.subplots(2, 1)
X = np.linspace(0, 20, 100).reshape(-1, 1)
mu_new, cov_new = posterior(X, X_train, Y_train, noise_train=0, noise_predict=0)
samples = np.random.multivariate_normal(mu_new.ravel(), cov_new, 3)
uncertainty = 1.96 * np.sqrt(np.diag(cov_new))
ax[0].plot(X.ravel(),samples.T)
ax[0].fill_between(X.ravel(), mu_new.ravel() + uncertainty, mu_new.ravel() - uncertainty, alpha=0.1);
mu_new, cov_new = posterior(X, X_train, Y_train, noise_train=0.2)
samples = np.random.multivariate_normal(mu_new.ravel(), cov_new, 3)
uncertainty = 1.96 * np.sqrt(np.diag(cov_new))
ax[1].plot(X.ravel(),samples.T)
ax[1].fill_between(X.ravel(), mu_new.ravel() + uncertainty, mu_new.ravel() - uncertainty, alpha=0.1);

2.6 最大后验概率
估计我们的参数的一种方法是最大化对数边际可能性(要理解这个表达式是如何导出的,参见【3】),

这相当于最小化负对数边际可能性,这通常是首选的(参见【4】对这些想法的扩展)。
def l_fn(X_train, Y_train):
"""Partially adapted from http://krasserm.github.io/2018/03/19/gaussian-processes/"""
Y_train = Y_train.ravel()
def negative_log_like(theta):
K = sq_e_kernel(X_train, X_train, l=theta[0]) + theta[1]**2 * np.eye(len(X_train))
return (0.5 * np.log(det(K))
+ 0.5 * Y_train.dot(inv(K).dot(Y_train))
+ 0.5 * len(X_train) * np.log(2*np.pi))
return negative_log_like
res = minimize(l_fn(X_train, Y_train),
[1.,1.],
method='L-BFGS-B')
l_opt, noise_train_opt = res.x
print('l_opt:' + str(np.round(l_opt, 2)))
print('noise_train_opt:' + str(np.round(noise_train_opt, 2)))
mu_s, cov_s = posterior(X, X_train, Y_train, l=l_opt, noise_train=noise_train_opt)
plt.plot(X.ravel(), np.random.multivariate_normal(mu_s.ravel(), cov_s, 3).T)
plt.fill_between(X.ravel(), mu_s.ravel() + uncertainty, mu_s.ravel() - uncertainty, alpha=0.1);l_opt:1.94
noise_train_opt:0.71

3.模型
3.1 数据
covid19 = pd.read_csv('./data/owid-covid-data20210120.csv')
covid = covid19[['location', 'continent', 'date', 'new_cases']]
covid.columns = ['Country', 'Continent', 'Date', 'Count']
covid['Date'] = covid['Date'].astype('datetime64[ns]')
covid_pt = covid.loc[covid['Country']=='Portugal'].set_index('Date')
covid_pt = covid_pt.dropna()dates = covid_pt.index
c_pt = covid_pt['Count'].fillna(0).reset_index().set_index('Date')['Count'].values
c_pt = np.abs(c_pt)
X = np.arange(c_pt.shape[0]).reshape(-1,1)
下面我们可以看到葡萄牙新病例的演变。正如我前面所说,疫情的传播有一个已知的动力。尽管如此,在这种情况下,我们可以看到,随着时间的推移,采取的行动产生了不同的结果。在病毒传播的第一波中,葡萄牙被认为是遏制病毒的一个很好的例子。这既是由于政治措施,也是由于普通民众的行为。在第二次浪潮中没有发生同样的情况,缺乏规划导致我们面临挑战。现在,在分析数据时,我们被列为世界上最糟糕的国家之一。我们正面临着病例数量前所未有的增加,几乎导致我们的卫生系统崩溃。
该数据包含从 2020 年 2 月 3 日到 2021 年 1 月 19 日的值。请记住,这些值总是指前一天,因此数据集中的最后一天实际上是 1 月 18 日。
n = c_pt.shape[0]
plt.plot(np.arange(n), c_pt, label='data')
plt.legend();

3.2 模型实施
内核
内核可以分为静态和非静态(参见我的另一篇文章以了解更多这些概念【5】)。在远离观察点的区域中,稳定核将总是返回到高斯过程的均值。发生这种情况是因为在点之间建模的协方差只取决于它们的相对位置,而不取决于它们的绝对距离。一个例子可以是指数二次核或周期核。另一方面,线性核是不稳定的核。我们的模型是信号的三个 GP 和噪声的一个 GP 的总和:
- 模拟中期不规则性(不同波)的指数二次核
- 每周季节性的周期性术语。
- 说明趋势的线性核(在本例中为指数)
- 噪声被建模为白噪声核。
作为时间函数的 y 的先验是,

平均函数
如果我们在模型中没有指定均值函数,我们假设 GP 的均值为零。如果我们只使用稳定的内核,这将意味着函数最终会回到零,正如我们对未来的预测。这是一个合理的假设吗?对于这个疫情来说,情况可能并非如此——未来我们将不得不忍受它。所采取的措施的主要目标是控制传播速度,而不是完全让它从地球上消失。我们可以定义一个不同于零的均值函数,我在下面添加了代码来实现。然而,我们模型中使用的方法将使用线性核来代替。
from pymc3.gp.mean import Mean
class Linear(Mean):
def __init__(self, b, a=0):
Mean.__init__(self)
self.a = a
self.b = b
def __call__(self, X):
return tt.squeeze(tt.dot(X, self.b) + self.a)
可能性
在我们的例子中,我们正在处理计数数据。因此,我们希望使用一个或多个 GPs 作为潜在过程来估计泊松均值(和标准差,因为它们是相同的)。

当我们使用一个分布作为泊松分布时,我们需要确保我们为该分布估计的参数被限制为正实数。这可以通过使用传统的对数连接函数来保证——这样,exp(f_i)总是正的。
3.3.4 使用重新参数化来加速
我添加这一小部分是为了让你了解PyMC3的默认参数化。它使用了我们多元常态的非中心参数化。我们已经知道,来自高斯过程的样本是具有参数化协方差矩阵的多元正态的实现。将 f 上的多元正态密度添加到对数后验密度的最佳方法是使用乔莱斯基分解得到因子 L,并将其乘以一个单变量正态随机变量的向量。

因此,f 的密度对其超参数(核参数)的先验依赖性被消除。
超参数分布
良好的做法是始终执行一些预先的预测检查,从而确保所有参数的预先分布都得到很好的定义。由于高斯过程的灵活性,我认为这样做更为重要。他们很容易过度拟合数据,给你意想不到的结果。如果你使用信息丰富的前科会有所帮助(见一篇关于这个主题的优秀文章【6】)。
X_ = np.linspace(0, 350,1000)[:, None]
with pm.Model() as model_prior:
l_t = pm.InverseGamma('l_t', 4, c_pt.shape[0]/4)
l_p = pm.InverseGamma('l_p', 4, c_pt.shape[0])
c = pm.Normal('c', 0, 0.05)
η_trend = pm.HalfNormal('η_trend',0.1)
η_ts = pm.HalfNormal('η_ts', 0.01)
η_per = pm.HalfNormal('η_per', 0.2)
σ = pm.HalfNormal("σ", sigma=0.02)
cov = (η_trend**2 * pm.gp.cov.ExpQuad(input_dim=1, ls=l_t)
+ η_ts**2 * pm.gp.cov.Linear(input_dim=1, c=c)
+ η_per**2 * pm.gp.cov.Periodic(1, period=7, ls=l_p)
+ pm.gp.cov.WhiteNoise(σ))
gp = pm.gp.Latent(mean_func = pm.gp.mean.Zero(), cov_func = cov)
f = gp.prior("f", X=X_)
f_ = pm.Deterministic('f_', tt.exp(f))
prior_checks = pm.sample_prior_predictive(samples=1000)
plt.plot(c_pt, color='darkorange')
plt.plot(X_, prior_checks['f_'].T, color='b', alpha=0.1)
plt.ylim(0, 15000)
plt.title('Draws from GP');

我们可以看到,我们以前的样本多少包含在我们的数据范围内。
3.3.6 现在一起
下面你可以找到我们用来适应葡萄牙新冠肺炎新病例的模型,因为疫情已经到达葡萄牙。
with pm.Model() as model:
l_t = pm.InverseGamma('l_t', 4, c_pt.shape[0]/4)
l_p = pm.InverseGamma('l_p', 4, c_pt.shape[0])
c = pm.Normal('c', 0, 0.05)
η_trend = pm.HalfNormal('η_trend',0.1)
η_ts = pm.HalfNormal('η_ts', 0.01)
η_per = pm.HalfNormal('η_per', 0.2)
σ = pm.HalfNormal("σ", sigma=0.02)
cov = (η_trend**2 * pm.gp.cov.ExpQuad(input_dim=1, ls=l_t)
+ η_ts**2 * pm.gp.cov.Linear(input_dim=1, c=c)
+ η_per**2 * pm.gp.cov.Periodic(1, period=7, ls=l_p)
+ pm.gp.cov.WhiteNoise(σ))
gp = pm.gp.Latent(mean_func = pm.gp.mean.Zero(), cov_func = cov)
f = gp.prior('f', X=X, reparameterize=True)
y_pred = pm.Poisson('y_pred', mu=tt.exp(f), observed=c_pt)
mp = pm.find_MAP(maxeval=20000, progressbar = True)
现在,是时候根据新数据(即我们想要预测的 30 个新时间点)来调整我们的模型了。
X_new = np.arange(c_pt.shape[0]+30).reshape(-1,1)
with pm.Model() as model:
f_n = gp.conditional('f_n', Xnew=X_new)
y_pred_new = pm.Poisson("y_pred_new",
mu=tt.exp(f_n),
shape=X_new.shape[0])
pred_samples = pm.sample_posterior_predictive([mp],
vars=[y_pred_new],
samples=200,
progressbar = False)
4.结果和讨论
最后,让我们画出我们的结果。
from pymc3.gp.util import plot_gp_dist
fig = plt.figure(figsize=(12,5)); ax = fig.gca()
plot_gp_dist(ax, pred_samples['y_pred_new'], X_new, palette="Blues", fill_alpha=0.1, samples_alpha=0.1);
plt.plot(np.arange(c_pt.shape[0]),c_pt, label='data', color='darkorange')
plt.ylim(0,max(c_pt)*4)
plt.legend();

n_new = X_new.shape[0]
放大我们预测的未来 30 天的消息并不好。该模型估计平均病例数在 2 月 18 日达到 24.047 例。但更重要的是,它还告诉我们,在锁定等措施碰巧非常有效的情况下,24.047 的峰值可能低至 8.753(50%区间的底部)或高达 29.939(50%区间的顶部)。您还可以看到关于 90%可信区间的更极端的情况。
当我写完这篇文章的时候,今天新病例的数量被公布了——我把它作为一个红叉加了进去。不幸的是,我们可以看到它在我们区间的顶端,在 50%和 90%之间。可能只是一个不规律(比如更多测试的结果,数据注册,前几天的累积效应等。)或者表示行为的改变。我们需要分析接下来几天的数据来理解它。
mean_values = pd.DataFrame({'x':np.arange(n, n_new), 'y':np.mean(pred_samples['y_pred_new'], axis=0)[-30:]})
top_mean_values = pd.DataFrame(columns=['x', 'y'])
top_mean_values['x'] = [mean_values[(i)*6:(i+1)*6].sort_values(by='y', ascending=False)[:1].values[0][0] for i in range(5)]
top_mean_values['y'] = [mean_values[(i)*6:(i+1)*6].sort_values(by='y', ascending=False)[:1].values[0][1] for i in range(5)]
low_q25_values = pd.DataFrame({'x':np.arange(n, n_new), 'y':np.percentile(pred_samples['y_pred_new'], axis=0, q=[25]).ravel()[-30:]})
low_q25_values = low_q25_values.loc[low_q25_values.x.isin(top_mean_values.x)]
high_q25_values = pd.DataFrame({'x':np.arange(n, n_new), 'y':np.percentile(pred_samples['y_pred_new'], axis=0, q=[75]).ravel()[-30:]})
high_q25_values = high_q25_values.loc[high_q25_values.x.isin(top_mean_values.x)]
low_q10_values = pd.DataFrame({'x':np.arange(n, n_new), 'y':np.percentile(pred_samples['y_pred_new'], axis=0, q=[10]).ravel()[-30:]})
low_q10_values = low_q10_values.loc[low_q10_values.x.isin(top_mean_values.x)]
high_q10_values = pd.DataFrame({'x':np.arange(n, n_new), 'y':np.percentile(pred_samples['y_pred_new'], axis=0, q=[90]).ravel()[-30:]})
high_q10_values = high_q10_values.loc[high_q10_values.x.isin(top_mean_values.x)]plt.fill_between(np.arange(n, n_new), np.percentile(pred_samples['y_pred_new'], axis=0, q=[10]).ravel()[-30:],
np.percentile(pred_samples['y_pred_new'], axis=0, q=[90]).ravel()[-30:], alpha = 0.1, color='b', label='90% CI');
plt.fill_between(np.arange(n, n_new), np.percentile(pred_samples['y_pred_new'], axis=0, q=[25]).ravel()[-30:],
np.percentile(pred_samples['y_pred_new'], axis=0, q=[75]).ravel()[-30:], alpha = 0.25, color='b', label='50% CI');
plt.plot(np.arange(n, n_new), np.mean(pred_samples['y_pred_new'], axis=0)[-30:], label='mean')
for i, j in zip(top_mean_values.x, top_mean_values.y):
plt.annotate(str(int(j)), xy=(i,j))
for i, j in zip(low_q25_values.x, low_q25_values.y):
plt.annotate(str(int(j)), xy=(i,j))
for i, j in zip(low_q10_values.x, low_q10_values.y):
plt.annotate(str(int(j)), xy=(i,j))
for i, j in zip(high_q25_values.x, high_q25_values.y):
plt.annotate(str(int(j)), xy=(i,j))
for i, j in zip(high_q10_values.x, high_q10_values.y):
plt.annotate(str(int(j)), xy=(i,j))
plt.plot(324, 14647, 'rx', label='New cases Jan-19')
plt.legend();

5.结论
本文旨在展示高斯过程在处理难以适应的模式时的优势和灵活性。伴随这种力量而来的是巨大的责任,尤其是在过度配合的时候。当我们花时间明智地选择我们的核,并根据它们的参数定义信息先验时,我们几乎可以用它们来拟合任何类型的数据。我们发现,我们的模型相对较好地描述了像葡萄牙每天新增新冠肺炎病例这样不规则的模式。我说相对较好,是因为我们应该用误差指标评估我们的预测,与基线模型进行比较,并将我们的模型应用于不同的场景(其他国家,其他指标如死亡人数等)。).使用高斯过程时要考虑的另一个重要方面是,它们并不具有很好的可伸缩性(O(n)),尽管有一些有趣的方法可以提高它们的可伸缩性(例如【7】)。
这篇文章是科学练习;请不要根据其结果采取任何行动。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
保持联系: LinkedIn
参考
[2]—https://distilt . pub/2019/visual-exploration-Gaussian-processes/
[3]—https://towards data science . com/first-Bayesian-state-space-model-with-pymc 3-51 cbb 06 ef 8 BD
[4]—http://krasserm.github.io/2018/03/19/gaussian-processes/
[5]—https://towards data science . com/5-难易度-贝叶斯-高斯-随机漫步-pymc 3-and-the ano-34343911 c7d 2
[6]—https://betanalpha . github . io/assets/case _ studies/Gaussian _ processes . html
[7]—https://arxiv.org/abs/1411.2005
用最大似然法预测周期性事件
根据先前事件的日期预测周期性发生的事件。

例如,如果您是数据聚合者,定期事件预测就非常有用。数据聚合者或数据提供者是从不同来源收集统计、财务或任何其他数据,对其进行转换,然后提供给进一步分析和探索的组织(数据即服务)。
数据即服务(DaaS)
对于这样的组织来说,监控发布日期非常重要,这样可以在发布后立即收集数据,并规划容量来处理即将到来的大量数据。
有时发布数据的权威机构有未来发布的时间表,有时没有。在某些情况下,他们只宣布未来一两个月的时间表,因此,您可能希望自己制定出版时间表并预测发行日期。
对于大多数统计数据发布,您可能会发现一种模式,如一周或一个月中的某一天。例如,可以发布统计数据
- 每月的最后一个工作日,
- 每个月的第三个星期二,
- 每月最后第二个工作日,等等。
考虑到这一点和以前的发布日期历史,我们希望预测下一次数据发布可能发生的潜在日期或日期范围。
个案研究
作为案例研究,让我们以美国会议委员会(CB)消费者信心指数为例。这是衡量经济活动中消费者信心水平的领先指标。通过使用它,我们可以预测在整体经济活动中起主要作用的消费者支出。
官方数据提供商没有提供该系列的时间表,但许多数据聚合者,如Investing.com已经收集了一段时间的数据,该系列的发布历史也在那里。
目标:我们需要预测下一次发布的日期。
数据准备
我们从导入所有用于数据操作、构建机器学习模型和其他数据转换的包开始。
# Data manipulation
import pandas as pd# Manipulation with dates
from datetime import date
from dateutil.relativedelta import relativedelta# Machine learning
import xgboost as xgb
from sklearn import metrics
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
下一步是获取发布历史日期的列表。您可能有一个数据库,其中包含您可以使用的发布日期的所有数据和历史记录。为了使这变得简单并专注于发布日期预测,我将手动向 DataFrame 添加历史记录。
data = pd.DataFrame({'Date': ['2021-01-26','2020-12-22',
'2020-11-24','2020-10-27','2020-09-29',
'2020-08-25','2020-07-28','2020-06-30',
'2020-05-26','2020-04-28','2020-03-31',
'2020-02-25','2020-01-28','2019-12-31',
'2019-11-26','2019-10-29','2019-09-24',
'2019-08-27','2019-07-30','2019-06-25',
'2019-05-28']})
我们还应该添加一个包含 0 和 1 值的列来指定发布是否发生在这个日期。现在,我们只有发布日期,所以我们创建一个用 1 值填充的列。
data['Date'] = pd.to_datetime(data['Date'])
data['Release'] = 1
之后,您需要在 DataFrame 中为发布之间的日期创建所有行,并用零填充发布列。
r = pd.date_range(start=data['Date'].min(), end=data['Date'].max())
data = data.set_index('Date').reindex(r).fillna(0.0)
.rename_axis('Date').reset_index()
现在,数据集已准备好进行进一步的操作。
特征工程
对下一个发布日期的预测很大程度上依赖于特性工程,因为实际上,除了发布日期本身,我们没有任何特性。因此,我们将创建以下功能:
- 月
- 一个月中的某一天
- 工作日编号
- 星期几
- 月份中的周数
- 每月工作日(每月的第二个星期三)
data['Month'] = data['Date'].dt.month
data['Day'] = data['Date'].dt.day
data['Workday_N'] = np.busday_count(
data['Date'].values.astype('datetime64[M]'),
data['Date'].values.astype('datetime64[D]'))
data['Week_day'] = data['Date'].dt.weekday
data['Week_of_month'] = (data['Date'].dt.day
- data['Date'].dt.weekday - 2) // 7 + 2
data['Weekday_order'] = (data['Date'].dt.day + 6) // 7
data = data.set_index('Date')
训练机器学习模型
默认情况下,我们需要将数据集分成两部分:训练和测试。不要忘记将 shuffle 参数设置为 False,因为我们的目标是基于过去的事件创建预测。
x_train, x_test, y_train, y_test = train_test_split(data.drop(['Release'], axis=1), data['Release'],
test_size=0.3, random_state=1, shuffle=False)
一般来说,shuffle 通过选择不同的训练观察值来帮助摆脱过度拟合。但这不是我们的情况,每次我们都应该出版所有历史事件。
为了选择最佳预测模型,我们将测试以下模型:
- XGBoost
- k-最近邻(KNN)
- 随机森林
XGBoost
我们将使用 XGBoost 与树基学习器和网格搜索方法来选择最佳参数。它搜索所有可能的参数组合,并基于交叉验证评估选择最佳组合。
这种方法的缺点是计算时间长。
或者,可以使用随机搜索。它在给定次数的给定范围内迭代,随机选择值。经过一定次数的迭代后,它会选择最佳模型。
但是,当您有大量参数时,随机搜索会测试相对较少的组合。这使得找到一个真正的 T2 最优组合变得几乎不可能。
要使用网格搜索,您需要为每个参数指定可能值的列表。
DM_train = xgb.DMatrix(data=x_train, label=y_train)
grid_param = {"learning_rate": [0.01, 0.1],
"n_estimators": [100, 150, 200],
"alpha": [0.1, 0.5, 1],
"max_depth": [2, 3, 4]}
model = xgb.XGBRegressor()
grid_mse = GridSearchCV(estimator=model, param_grid=grid_param,
scoring="neg_mean_squared_error",
cv=4, verbose=1)
grid_mse.fit(x_train, y_train)
print("Best parameters found: ", grid_mse.best_params_)
print("Lowest RMSE found: ", np.sqrt(np.abs(grid_mse.best_score_)))
如您所见,我们的 XGBoost 模型的最佳参数是:alpha = 0.5, n_estimators = 200, max_depth = 4, learning_rate = 0.1。
让我们用获得的参数来训练模型。
xgb_model = xgb.XGBClassifier(objective ='reg:squarederror',
colsample_bytree = 1,
learning_rate = 0.1,
max_depth = 4,
alpha = 0.5,
n_estimators = 200)
xgb_model.fit(x_train, y_train)
xgb_prediction = xgb_model.predict(x_test)
k-最近邻(KNN)
k-最近邻模型是在试图寻找观察值之间的相似性时使用的。这正是我们的情况,因为我们试图在过去的发布日期中找到模式。
KNN 算法需要调整的参数更少,因此对于以前没有使用过它的人来说更简单。
knn = KNeighborsClassifier(n_neighbors = 3, algorithm = 'auto',
weights = 'distance')
knn.fit(x_train, y_train)
knn_prediction = knn.predict(x_test)
随机森林
随机森林基本模型参数调整通常不会花费很多时间。您只需迭代估计器的可能数量和树的最大深度,并使用肘方法选择最佳值。
random_forest = RandomForestClassifier(n_estimators=50,
max_depth=10, random_state=1)
random_forest.fit(x_train, y_train)
rf_prediction = random_forest.predict(x_test)
比较结果
我们将使用混淆矩阵来评估训练模型的性能。它帮助我们并排比较模型,并了解我们的参数是否应该进一步调整。
xgb_matrix = metrics.confusion_matrix(xgb_prediction, y_test)
print(f"""
Confusion matrix for XGBoost model:
TN:{xgb_matrix[0][0]} FN:{xgb_matrix[0][1]}
FP:{xgb_matrix[1][0]} TP:{xgb_matrix[1][1]}""")knn_matrix = metrics.confusion_matrix(knn_prediction, y_test)
print(f"""
Confusion matrix for KNN model:
TN:{knn_matrix[0][0]} FN:{knn_matrix[0][1]}
FP:{knn_matrix[1][0]} TP:{knn_matrix[1][1]}""")rf_matrix = metrics.confusion_matrix(rf_prediction, y_test)
print(f"""
Confusion matrix for Random Forest model:
TN:{rf_matrix[0][0]} FN:{rf_matrix[0][1]}
FP:{rf_matrix[1][0]} TP:{rf_matrix[1][1]}""")
如你所见,XGBoost 和 RandomForest 都表现出了不错的性能。在大多数情况下,他们都能捕捉到模式并正确预测日期。然而,这两个模型都在 2020 年 12 月发布时犯了一个错误,因为它打破了发布模式。
KNN 不如前两者准确。它未能正确预测三个日期,错过了 5 次发布。在这一点上,我们不继续讨论 KNN。一般来说,如果数据是规范化的,效果会更好,所以如果您愿意,可以尝试对其进行调优。
关于其余两个,对于初始目标,XGBoost 模型被认为在超参数调整方面过于复杂,因此 RandomForest 应该是我们的选择。
现在,我们需要创建预测未来日期的数据框架,并使用训练好的 RandomForest 模型来预测未来一年的未来释放量。
x_predict = pd.DataFrame(pd.date_range(date.today(), (date.today() +
relativedelta(years=1)),freq='d'), columns=['Date'])
x_predict['Day'] = x_predict['Date'].dt.day
x_predict['Workday_N'] = np.busday_count(
x_predict['Date'].values.astype('datetime64[M]'),
x_predict['Date'].values.astype('datetime64[D]'))
x_predict['Week_day'] = x_predict['Date'].dt.weekday
x_predict['Week_of_month'] = (x_predict['Date'].dt.day -
x_predict['Date'].dt.weekday - 2)//7+2
x_predict['Weekday_order'] = (x_predict['Date'].dt.day + 6) // 7
x_predict['Month'] = x_predict['Date'].dt.month
x_predict = x_predict.set_index('Date')prediction = xgb_model.predict(x_predict)
就是这样——我们预测了未来一年美国 CB 消费者信心系列的发布日期。
结论
如果您想要预测周期性事件的未来日期,您应该考虑创建有意义的要素。它们应该包括你能在历史中找到的关于模式的所有信息。正如你所看到的,我们没有在模型的调整上花太多时间——如果你使用正确的特性,即使简单的模型也能给出好的结果。
谢谢你一直读到最后。我真的希望它是有帮助的,如果你在评论中发现任何错误,请让我知道。
通过优化 Python 中的特征选择来预测商店流量
该分析最初是在一些数据科学角色的评估中激发和提供的。然而,数据集被修改后发表。

照片由 Aditya Rao 在 Unsplash 上拍摄
介绍
我的发现将涵盖日本各地餐馆/商店客流量波动的原因。这些信息将有利于 F&B 行业的公司管理层优化品类管理、商店选择和相关资源分配,从而提高商店访问量、增加收入,并通过更好的客户服务获得更好的声誉。考虑到其他当地因素,如假期、天气和季节性,所探讨的因素也将显示日本市场在顾客口味方面的更好图景。
数据理解
我们有如下三个主要数据集。由于原始数据非常庞大和复杂,这三个数据集已经是预处理过程的结果。
-2016 年店铺访问数据(train _ restaurant _ visitors . CSV):按日期提供访问日期、餐厅/店铺类型、店铺经纬度、各店铺访问人数等数据。
- 日本的假日信息(holidays _ data . CSV):按日期提供日本不同的假日名称。
-2016 年天气数据(new _ Weather _ data 2 . CSV):提供每一天的各种天气属性,以关键类别表示:温度、湿度、雨、阳光、雪、风。
数据准备和探索
数据清理
在检查了三组数据后,我承认有许多值丢失了。在为每个类别提供解决方案之前,我将缺失值的级别分为三类:> 60%缺失,< 20%缺失,100%缺失。对于第一个解决方案,我决定删除所有缺失值超过 60%的变量。为了处理缺失值低于 20%的要素,我对数值天气属性值使用了中值方法:Temp、Sun、Rain_avg_year、Sun_avg_year Total_precip。就假日信息而言,我用 Normal_day 替换了缺失值,因为带有假日信息的数据在一年中只占很小的百分比。
由于三个清理过的数据集没有任何缺失值,下一步应该是数据合并。使用来自每个数据集的相同日期列(主键)进行连接,最终得到一个主数据集。该数据集包括按日期排列的每个商店的商店访问量信息、按日期排列的假日信息(如果是)和天气信息。
最后,在清理和合并过程中,我从我们的主数据集中删除了其他不相关的数据特征,从而产生了用于转换、EDA 和建模部分的最终数据集。最终数据集具有以下变量:1 .日期,2。月份,3。访问者的数量,4。键入,5。假日名称,6。温度 7 度。Total_Precip,8。雨 _ 平均 _ 年,9。孙,10 岁。太阳平均年。
数据转换
查看我们的因变量 number of visitors 的分布,我得出的结论是,我们的数据不是正态分布的,而是略有偏斜。运行 QQ 图后,我们需要将数据转换为正态分布。新的 QQ 图表明,我们的 log(number_of_visitors)值更符合正态分布,使我们能够继续分析。

访客数量分布-按作者分类的图片
我做的另一个转换是将所有的字符串列转换成因子/分类变量:Type、Holiday_Name 和 Month。
数据探索性
转到 EDA,首先,我想确定 2016 年期间的任何趋势或季节性模式。从访客数量来看,我们发现 3 月至 5 月期间,每家商店的平均访客数量较高,12 月再次增加。与此同时,8 月至 11 月期间的平均访问量最低。

一段时间内的访客数量-按作者分类的图片
然而,假设每家商店的平均访问量受到 2016 年期间开设的商店数量的影响,我使用了两种可视化方法来证实我的假设。因此,下半年有大量商店开业,增加了商店的总访问量。

一段时间内访客和商店的总数-按作者分类的图片
在时间分析中考虑餐厅/商店类型,我们还看到 2016 年下半年开业的一些新店提供了平均访客数量更高的新类别。

一段时间内按类别划分的访客数量—按作者划分的图片
为了深入研究访问者数量的其他统计数据,比如方差,我还使用了如下的箱线图。我们看到,甚至每个商店的平均访问量也没有太大差异;由于新店的扩张,自 6 月以来,差异有所增加。

一段时间内的访客数量-按作者分类的图片
使用月周期的箱线图,我还研究了其他数值自变量的模式,其中大部分是天气特征。没有新的发现表明夏季温度较高,雨季发生在六月和九月。最冷的月份是一月,温度最低,而最热的月份是八月。

一段时间内的天气数据-按作者分类的图片
为了理解不同感兴趣变量的特征和相互作用,我还使用直方图来了解其他独立变量的频率。
接下来,我构建了二维箱线图来可视化访问者数量和独立变量之间的关系。考虑到假期日期,有趣的是,人们在新年那天最少去商店或餐馆。与此同时,其他场合如天皇生日或昭和日也吸引了很多人来逛商店。就商店/餐馆类别而言,我们看到了亚洲食品的主导地位,这可能在日本这样的亚洲国家最容易获得。相反,同期去酒吧/鸡尾酒会等其他高端场所的人并不多。

访客数量和分类数据—按作者分类的图片
在与访客数量的关系分析中,我还考虑了其他数值自变量。以月份作为第三个属性构建三维散点图,我们可能会同意,唯一值得一提的模式是总 precip 的平均值,这意味着一种负相关关系:Precip 越低,商店的访客数量越多。除了谈论游客的数量,我们还知道 12 月的晴天和雨天更少,这部分解释了为什么人们在同一时期外出最频繁。

一段时间内的访客数量和天气数据-按作者分类的图片
相关性分析
为了了解哪些变量可能会影响访客数量,我对所有选定的自变量和因变量进行了相关性分析。在此之前,我将所有分类变量转换为虚拟变量来计算相关性。一旦完成,我选择任何与访客数量相关度超过 10%的变量。这组变量被称为最感兴趣的 13 个变量。

相关矩阵-作者图片
最后,我使用另一个相关矩阵考虑了当前前 13 个变量的数据中是否存在共线性问题:

前 13 个变量的相关矩阵—作者图片
在下一个建模部分,我们将利用 LASSO 等正则化技术来处理其他高度相关的变量。
特征选择和建模
对于特征选择和建模部分,我决定使用三种不同的方法。在后面的分析中,我将深入研究每一个问题。
方法一:过滤方法
顾名思义,在这种方法中,我使用了 filter 并只提取相关特性的子集。模型是在选择特征之后构建的。这里的过滤是使用相关矩阵完成的,最常见的是使用皮尔逊相关。
我们知道,访问者的数量与许多变量高度相关(我们的“前 13 个”)。我们采用多元线性回归建立了一个最佳的游客数量预测模型。我称之为“模型 1”,它包括了我们的“前 13 个”解释变量(与访问者数量高度相关的变量)。使用训练-测试分割方法,我们得到如下模型 1 摘要:

模型 1 摘要—作者提供的图片
在模型 1 中,所有确定的变量都与我们的目标变量——访问者数量——高度相关。所有变量都与目标变量有正相关关系。Type_Asian 对目标变量的边际影响最大。
方法二:包装器方法
包装器方法需要一个机器学习算法,并使用其性能作为评估标准。这意味着您将这些特征输入到所选的机器学习算法中,并根据模型性能添加/删除这些特征。尽管这是一个迭代且计算量大的过程,但它比滤波方法更精确。在这个分析中,我将讨论两种包装方法:逆向淘汰和 RFE。
模型 2.1: 逆向淘汰
首先,我会将所有可能的特征放入模型中。在检查模型的性能之后,它将迭代地逐个移除性能最差的特征,直到模型的整体性能达到可接受的范围(使用高于 0.05 的 p 值)。我称之为“模型 2.1”,它包括了所有重要的解释变量。使用训练-测试分割方法,我们得到模型 2.1 摘要如下:

模型 2.1。摘要—按作者分类的图像
在模型 2.1 中,我们发现一些变量与目标变量——访问者数量——存在负相关关系。最显著的是 type_Bar/Cocktail,暗示人们最少去这个地方。像模型 1 一样,Type_Asian 对目标变量具有最积极的实质性边际影响。
模型 2.2: RFE(递归特征消除)
该方法递归地删除属性,并在保留的属性上构建模型。它考虑准确性度量,根据特征的重要性对其进行排序。RFE 方法将使用的模型和所需特征的数量作为输入。然后,它对所有变量进行排序,1 是最重要的。它也给出了它的支持,True 作为相关特征,False 作为不相关特征。
在找出 12 个特征的最佳数量后,我拟合了这 12 个变量,称之为“模型 2.2”。使用训练-测试分割方法,我们得到模型 2.2 摘要如下:

模型 2.2。摘要—按作者分类的图像
在模型 2.2 中,我们看到所有变量都与目标变量——访问者数量——成负相关。和模型 2.1 一样,最显著的是 type_Bar/Cocktail,暗示人们最少去这个地方。
方法三:嵌入式方法
正则化方法是最常用的嵌入式方法,其在给定系数阈值的情况下惩罚特征。我将使用套索进行特征选择。如果变量是不相关的,拉索惩罚系数,使其为 0。因此,系数= 0 的特征被移除,而其余的被采用。
使用套索回归方法,我们提出了“模型 3 ”,它执行变量选择和正则化。深入研究变量选择,我们有对模型最重要的前 30 个预测因子。这是通过使用 MDI(基尼系数重要性或杂质平均减少量)来完成的,MDI 将每个特征的重要性计算为包括该特征的分裂数(跨所有树)的总和,与它分裂的样本数成比例。

模型 3 变量的重要性—作者图片
模型 3 总结如下:

模型 3 摘要—作者提供的图片
与模型 1、模型 2.1 和模型 2.2 相比,我们对月份变量组有了更多的了解。但是,我们可以再次确认 Type_Asian(正)和 Type_Bar/Cocktail(负)对目标变量的反向影响。
估价
在运行了我们的四个模型之后,我使用了四个指标:R 平方、MAE、MSE 和 RMSE 来评估我们的模型预测性能。正如我们从下表中所预期的那样,就所有指标而言,使用反向消除的模型 2.1 是最好的。另一个性能非常接近的模型是使用 LASSO 正则化的模型 3。
预计过滤方法(模型 1)不太准确,包装和嵌入方法(模型 2.1 和模型 3)提供更准确的结果。然而,当处理大量特征时,这两个后面的模型在实践中在计算上将是昂贵的。

4 个模型的比较—作者提供的图片
部署
通过分析一组与商场客流量相关的数据集,我创建了一个模型,可以帮助高层管理团队、资源规划人员,尤其是 F&B 行业的商场经理预测商场/餐厅的客流量,并更好地了解日本市场的顾客偏好。我发现使用反向消除的模型 2.1 比其他模型表现得更好。我还从使用套索正则化的模型 3 中看到了令人印象深刻的预测准确性。总的来说,我发现一些变量与访客数量成正相关,而另一些变量与目标变量成负相关。冷季(8、9、10、11 月)去商店/餐厅的人比较少,Type_Bar/Cocktail 是最不受欢迎的地方。然而,客流量在 12 月再次增加,并在天气更适合购物活动的夏季达到高峰。同样清楚的是,Type_Asian 对访问者数量具有最积极的实质性边际影响。另一个值得一提的发现是假期变量组,因为它不会对日本顾客的购物或用餐决策产生很大影响。
然而,这种分析有一些局限性。首先,数据集的一些属性中有许多缺失值,这会降低我们预测的准确性。解决方案是通过与数据提供者合作进行挖掘和清理步骤来包含更多合格的数据。第二,基于与数据提供商的协议,我无法使用关于商店/餐馆位置的变量,而这些变量可能是商店客流量的良好预测指标。另一个限制是缺乏与商店/餐厅相关的数据特征,如商店容量、商店评级和客户服务。这些因素会影响吸引人们访问的能力。我们可以通过向数据提供者要求更多的内部数据来处理这个问题。最后是关于数据时间段。在这个分析中,我们只有 2016 年的店铺流量数据,这可能无法反映业务和市场的现状。应考虑通过纳入更多更新数据,向数据提供者提议进一步扩展这一分析。在未来,我们还可以尝试其他性能指标和其他机器学习技术,以获得更好的性能和结果比较。
用后分层多水平回归预测 2020 年美国大选

图片来源:Pixabay
总统选举,特朗普,政治民调,PYMC3,Python
如何评估美国的公众舆论
估计州一级意见最常用的方法叫做 分解 。这个过程很简单,也很容易实现:在合并了一组全国性的民意调查后,您可以计算出按州分列的意见百分比。
分解 的问题在于,它需要收集超过 10 年或更长时间的大量全国性调查,以在每个州内创建足够的样本量。此外, 分解 不能纠正抽样问题,可能会模糊州意见中的时间动态。
为了克服这些缺点, 带后分层的多水平回归(MRP)被开发出来从全国民调中估计美国各州层面的意见。
什么是 后分层多水平回归 (MRP)?
MRP 首先使用多级回归将个人调查响应建模为人口统计和地理预测的函数,在数据确定的范围内部分汇集各州的受访者。最后一步是后分层,其中每种人口地理应答类型的估计值按每种类型在实际州人口中的百分比进行加权(后分层)。
假设我们进行了一项调查,询问人们是否支持同性婚姻。我们有一个 1000 人的调查,其中 700 人为男性,300 人为女性。我们可以利用调查结果来计算支持同性婚姻的人的比例。但是,我们知道男女之间的人口分布大致是 50%/50%,而不是我们调查所暗示的 70%/30%。因此,仅从我们的调查中得出的原始结果就过度代表了男性的观点。
鉴于我们知道更广泛人群的性别分布,我们可以重新加权(分层后)我们的结果:所以在这个例子中,支持同性婚姻的人的比例估计为:
0.5×男性比例+0.5×女性比例
这种技术被称为后分层。我们需要调查数据和可靠的人口普查数据,以获得人口权重。数据可以根据许多不同的类别重新加权,如年龄、教育、性别、种族等。
预测 2020 年美国大选
在本帖中,我们将按照示例这里和这里使用分解技术& MRP 和两个数据集(一个民调数据集和一个人口普查数据集)预测 2020 年美国大选。我们走吧!
选举民调数据
我不能分享数据集,但是,下面是如何获取数据的说明:
- 转到网站:【https://www.voterstudygroup.org 。
- 点击“国家景观”。
- 点击“获取最新的国家景观数据”。
- 填写您的姓名和电子邮件地址,然后点击“提交请求”。
- 您将收到一封带有下载链接的电子邮件,单击此链接。
- 我们会下载。dta 文件。
- 解压下载的“nation scape-data release _ weekly materials _ DTA _ 200910 _ 161918”,然后打开文件夹“phase_2_v20200814”。
- 有很多 dta.files,我用的是“ns20200625.dta”,指的是 2020 年 6 月 25 日。
poll_data.py

表 1
数据中有许多特征,这个分析将需要七个:“投票 _2020”,“种族 _ 民族”,“教育”,“州”,“性别”,“年龄”,“人口普查 _ 地区”。
电子设计自动化(Electronic Design Automation)
df.vote_2020.value_counts(normalize=True)

图 1
在数据中,大约 42%的人说他们会投票给拜登,38%的人说他们会投票给特朗普,10%的人不确定,以此类推。
各州的民意测验答卷人数量
respondents _ by _ state.py

图 2
很明显,越大的州,越多的受访者。值得注意的是,每个州都有回答者。
按州和种族分列的受访者
- 我们将种族简化为四类:“白人”、“黑人”、“亚裔”和“其他”。
- 因为我们对特朗普的选民感兴趣,所以会重新编码“vote_2020”变量。
状态 _ 种族. py

图 3
所有的州都有白人受访者,几个州没有黑人和/或亚裔受访者,甚至更多的州只有很少的黑人和/或亚裔受访者。
按州和性别分列的受访者
state_gender.py

图 4
一个州(WY)没有女性答卷人,所有其他州都有男性和女性答卷人。
估计对特朗普的支持
disa_trump.py

图 5
阿肯色州的支持度最高,佛蒙特州对特朗普的支持度最低。
按年龄和性别给特朗普投票
年龄 _ 性别. py

图 6
在这次民意调查中,大约 35-45 岁的男性是特朗普最大的投票群体。
简化教育和年龄变量
sim_edu_age.py
我们将通过结合性别(2 类)、种族(4 类)、年龄(4 类)和教育(4 类)的所有可能组合来探索特朗普的选民。
按性别给特朗普投票
gender_group.py

表 2
在表示将投票给特朗普的选民中,大约 43%是女性,57%是男性。
按年龄类别投票给特朗普
age_cat.py

表 3
30-44 岁是最大的投票群体,其次是 60 岁及以上。
按年龄和性别给特朗普投票
ageCat_genderCat.py

表 4
按种族给川普投票
race.py

表 5
按种族和性别给特朗普投票
race_gender.py

表 6
按种族和年龄给特朗普投票
race_age.py

表 7
教育投票给川普
edu _ 猫. py

表 8
按教育和性别给特朗普投票
edu_gender.py

表 9
按教育和种族给特朗普投票
edu_race.py

表 10
按教育和年龄给特朗普投票
edu _ 时代. py

表 11
多层模式
我们的多级投票模型将包括州、种族、性别、教育、年龄和投票等因素。为了加速推断,我们计算了这些因素的独特组合的数量,以及每个组合有多少受访者会投票给特朗普。
encode_uniq.py
这种减少将数据集中的行数减少了近 70%。
uniq_dt_df.shape[0] / dt_df.shape[0]

多级. py
现在我们准备好用 PyMC3 指定模型,从在theano.shared中包装预测器开始。
shared.py
我们指定α_state 的多级(分层)模型。
hierarchical_normal.py
我们指定参数如下:
参数. py
最后,我们使用 NUTS 指定模型的可能性和样本。
样本. py
我们可以使用 Gelman Rubin 测试来正式验证链的收敛性。接近 1.0 的值表示收敛。
赫尔曼·鲁宾

图 6
分层后数据
我们将使用 IPUMS 美国人口普查和美国社区调查数据。同样,我无法分享数据集,以下是获取数据集的步骤:
- 进入 https://ipums.org IPUMS 网站:,然后点击“美国 IPUMS”上的“访问网站”。
- 点击“获取数据”。
- 如果你以前没有做过,你需要创建一个帐户,然后等待确认。
- 一旦您有了一个帐户,请转到“选择样品”并取消选择除 2019 年 ACS 之外的所有产品。
- 我们需要得到我们感兴趣的变量。在家庭中,我们想要“STATEICP”,而在个人中,我们想要“性别”、“年龄”、“教育程度”和“种族”。
- 选择所有内容后,“查看购物车”,我们要将数据格式更改为”。dta”。它应该小于 300MB,然后提交请求。
- 你应该会收到一封邮件,说你的数据可以在几分钟内下载。
- 我下载了“usa_00002.dta”并保存在我的数据文件夹中。
我们现在可以开始清理数据,包括重新组织年龄类别、教育类别、种族类别,并将州名改为两个字母的州缩写,这与我们之前分析的调查数据一致。
census_df = pd.read_stata('data/usa_00002.dta')
census_df.head()

表 12
post_stra.py
创建每个子单元的计数和各州的比例后,与之前的州数据合并。现在我们终于有了分层后的数据:

表 13
同样,我们将类别变量编码为数字,并以与之前相同的方式对组合数据进行编码。
ps_encode.py
现在,我们将 PyMC3 模型中的theano.shared变量的值设置为后分层数据,并从后验预测分布中取样。
ps_mean.py
我们通过对每个州内的人口统计单元进行加权求和来完成后分层步骤,以从州级投票分布中产生后验预测样本。州级民意测验的最简单概括是后验期望均值。
下图显示了 MRP 对各州特朗普支持率的估计。
mrp_trump.py

图 7
我们可以看一下我们的估计值,比较每个状态的估计值在分解和 MRP 之间的差异。
mrp_disa.py

图 8
特朗普是如何得到黑人支持的?
我们试着用两个估计来回答这个问题。
首先,我们绘制了黑人男性对特朗普支持率的分解估计。我们意识到,在许多州,民意测验专家很少或根本没有调查黑人。因此,这些州的黑人男性对特朗普的支持度不能用分解法来衡量。
黑人 _ 男人 _disa.py

图 9
在使用 MRP 时,我们能够估计所有州的黑人男性对特朗普的支持度。
黑人 _ 男人 _mrp.py

图 10
Jupyter 笔记本可以在 Github 上找到。祝你周末愉快。
参考资料:
https://scholar . Princeton . edu/sites/default/files/jkstellec/files/MRP _ primer . pdf
https://www . tellingstorieswithdata . com/MRP . html # ref-Wang 2015 预测
用 SEIR 模型预测新冠肺炎趋势
编写一个 Java 程序来分析新冠肺炎数据并预测趋势。

图片作者。泰国 2021 年 4 月 1 日至 2021 年 10 月 2 日每日新冠肺炎死亡人数和 7 天平均值图
泰国在 2020 年非常好地应对了新冠肺炎。与其他国家相比,病例和死亡人数相对较低。自 2021 年 4 月左右开始的最新一波疫情以来,情况已经发生了变化。死亡人数迅速上升。虽然,最近几个月,这个数字有所下降。
我们将讨论:
- SEIR 模式
- 用代码模拟 SEIR
- 检索公共 COVID 数据
- 搜索模型参数
- 利用模型进行预测
- 可视化结果
- 将繁殖率的变化可视化
SEIR 模式
SEIR 模型是描述包括新冠肺炎在内的各种疾病的流行模型。一些文章已经讨论了 SEIR 模式。比如这里的和这里的。我们将简单介绍一下,以便快速进入主题。
该模型将人群分为以下几组:
- 易感者。这组人还没有被感染。
- 暴露(E)。该组中的个体被感染但还没有传染性
- 传染性(一)。这个群体会传染给其他人。
- 已恢复。组里的人都康复了。
五个微分方程描述了这些群体中的人数如何随时间变化。我们只考虑简化版本而不是严格版本,因为我们忽略了出生率和其他原因的死亡率。

图片作者。由代码生成。这些是 SEIR 微分方程。
SEIR 模型参数是:
- Alpha(𝛼)是由疾病引起的平均死亡率。
- Beta(𝜷)是每次接触传播疾病的概率乘以单位时间内的接触次数。
- Epsilon(𝜺)是从接触到传染性疾病的进展速度。它是潜伏期的倒数。
- Gamma(𝜸)是回收率。这是传染期的倒数。
要使用模型进行预测,我们需要在开始时知道上述参数以及以下值:
- 暴露计数
- 传染性计数
- 恢复计数
- 死亡人数
我们还需要知道初始易感人数。然而,我们可以从总体和上面的初始值中计算出来。易感人数等于总人数减去暴露人数、感染人数、康复人数和死亡人数。这里我们将 SEIR 微分方程转化为差分方程。

图片作者。由 CODECOGS 生成。这些是 SEIR 差分方程。
这样更容易用代码实现。
有两个指标与新冠肺炎相关。繁殖率(R0)是由感染个体产生的继发性病例的平均数。如果我们忽略自然出生率和其他原因造成的死亡,下面的等式描述了繁殖率:

图片作者。由代码生成。这是繁殖率方程式。
如果 R0 小于 1,则疾病停止。如果 R0 大于 1,疾病继续传播。
另一个是感染和病死率(IFR)。以下等式描述了 IFR:

图片作者。由 CODECOGS 生成。这是感染率和病死率的等式。
用代码对 SEIR 建模
首先,我们在一个类中模拟 SEIR 参数。然后,我们用另一种方法表示微分方程。
模型参数类
这里我们封装了 SEIR 参数和初始条件。成员变量是α、β、ε、γ、初始暴露、传染性、恢复和死亡计数。
我们将人口存储在这个类中,因为我们用它来计算易感性。人口值是不变的。因此,在代码中,它是静态的,我们只能设置它一次。
SEIR 模特班
SEIR 模型类有一个将模型参数作为参数的构造函数。
run 方法接受一个参数,即我们希望模型预测的天数。run 方法通过计算来预测未来所有组中的个体数量。run 方法有一个嵌套循环。外环处理一天。我们把每天分成小的时间间隔,在我们的例子中是 10 个时间间隔。内部 for 循环将计算每组中个体数量的增量。我们使用 SEIR 差分方程来进行计算。我们将结果放入 SEIRResult 对象中。
检索公共 COVID 数据
我们的 COVID 数据来自这个站点。感谢迪伦杰伊和其他贡献者。
我们使用 Tablesaw 库来处理表和列数据。该库可以处理统计分析以及一些数据可视化。有关 Tablesaw 的更多详情,请点击查看。
人口
泰国人口数据来自 excel 文件这里。尽管文件提供了更多的信息,我们只需要这个国家的总人口。下面是代码。
代码很简单。我们从 excel 文件创建一个表格。然后,我们获取 Total 列的第一行。就是人口值。最后,我们将其设置为模型参数对象。
案例简报
每日新信息可在 CSV 格式这里获得。以下是样本内容。
案例简报 CSV 文件的样本内容
虽然我们只对这些列感兴趣,但是有很多数据:
- 案例
- 死亡
- 恢复
以下是代码:
- 首先,我们通过读取在线 CSV 文件来创建一个表。
- 这个表格有很多栏。我们删除了除日期、病例、恢复和死亡之外的所有列。
- 我们计算死亡列的 7 天滚动平均值,并将其存储在一个新列中。我们不会在 SEIR 模型中使用新列。只是想象。
- 接下来,我们过滤表格。仅获取特定日期当天或之后的数据。该日期是该国最新一波 COVID 浪潮的开始。
- 我们从“病例”列减去“已恢复”列,创建一个新的“传染性”列。
- 每天都有感染、康复和死亡病例。对于每一个,我们创建一个累积值列。
- 最后,我们绘制图表。
这是三张图表:
- 死亡人数和 7 天平均死亡人数。这张图是本文的第一张图片。
- 累积病例、感染和恢复计数
- 每日病例、传染性和恢复计数

图片作者。泰国 2021 年 4 月 1 日至 2021 年 10 月 2 日累计病例数、感染数和痊愈数图表

图片作者。泰国 2021 年 4 月 1 日至 2021 年 10 月 2 日每日病例数、感染数和痊愈数图表
搜索模型参数
为了使用 SEIR 模型进行预测,我们需要 SEIR 参数和初始条件。以下是我们将要做的事情:
- 识别未知的独立模型参数和初始条件。
- 确定每个未知参数的可能值。
- 实施通用网格搜索
- 实施 SEIR 参数网格搜索
识别未知独立参数
这些是:
- 希腊字母的第一个字母
- 贝塔
- 埃普西隆
- 微克
- 初始暴露计数。不得而知。
- 初始感染计数。虽然有官方的数值,但可能太低了,因为权威机构可能没有足够的 COVID 测试。我们将视其为未知。
- 初始恢复计数。出于与上述相同的原因,来自数据的值可能太低。我们将视其为未知。
最初的死亡人数可以从我们得到的数据中得到。应该够靠谱了。
总之,我们有七个未知的独立参数要寻找。
识别每个未知参数的可能值
对于每个模型参数,我们确定或列出可能的值。
- Alpha 的范围从 0.000005 到 0.0001。
- 贝塔系数的范围从 0.05 到 1.0。
- ε是潜伏期的倒数。平均潜伏期为 5.2 天。我们把它做成一个从 1/5.6 到 1/4.8 的值列表。
- γ是传染期的倒数。据信,这一时期是一个星期或更少。我们把它做成一个从 1/9 到 1/4 的值列表。
- 初始暴露计数。我们没有确切的数字。我们猜测它将从 2 倍官方感染开始到 20 倍官方感染计数。
- 初始感染计数。我们估计它会从官方最初的传染数上升到 10 倍的数值。
- 初始恢复计数。我们有官方的数字。然而,正确的数字可能更高。我们猜测它将从官方恢复的计数开始到官方恢复的计数的 10 倍。
GridSearch 类
GridSearch 类将 run 方法作为唯一的方法。请注意,它是一个泛型类,以便将来可以重用。在我们的例子中,类型参数是 ModelParameter 类。
方法参数包括:
- 参数网格。
- ModelParameter 对象的约束。
- 一个我们需要最小化的目标函数。我们通常在模型输出和实际数据之间提供一个误差函数。
- 我们希望函数返回的结果集大小。
该方法将使用网格中所有可能的值来评估目标函数。然后,返回一组排序后的 ModelParameter 对象,这些对象具有目标函数值最低的值。
为此,我们使用生产者-消费者设计模式。我们有一个生产者来创建许多参数,并把它们放在一个绑定的队列中。我们有多个消费者来获取队列的参数并计算目标函数值。
下面是代码的一些解释
- 首先,该方法计算要创建的消费者任务的数量。它是可用处理器的数量减 2。
- 接下来,它构造一个阻塞队列。Deque 是一个队列,一个元素可以从前面或后面添加或删除。德克族是被束缚的。这意味着我们可以加入一定量的元素。如果达到限制,生产者任务将被阻止。
- 该方法创建并提交生产者任务。
- 生成器任务测试网格中每个 ModelParameter 对象的约束,然后将其放入队列。
- 对于每个消费者来说,生产者任务就像一颗毒丸。消费者会知道何时停止。
- run 方法创建并提交消费者任务。
- 每个消费者任务创建一个绑定树集。我们根据目标函数值对树集进行排序。此外,它只保留最低指定数量的元素。树集源代码这里是这里是。
- 每个消费者从队列中获取一个 ModelParameter 对象。如果不是毒丸,则评估目标函数,并将一对 ModelParameter 和函数值添加到集合中。当消费者任务发现毒丸时,它会停止。
- 一旦所有的使用者都完成了,run 方法就组合所有使用者的结果,并将其返回给被调用者。
SEIRParameterGridSearch 类
这个类使用案例简报中的数据表来搜索模型参数。
- 它使用表中的第一行作为初始条件的开始猜测。
- 接下来,我们创建一个参数网格。它计算所有参数的笛卡尔乘积。对于每个组合,它都会构建一个模型参数对象,然后调用一个使用者。
- 然后,我们定义一个目标函数,它是我们希望最小化的模型参数的函数。我们使用误差函数来比较模型输出和观察值。我们用来比较的数值是每日死亡数,因为它比传染数或恢复数更可靠。
- 最后,我们称之为网格搜索。
网格搜索和结果
上面的代码执行参数搜索。稍后,我们将结果转换成表格。然后,将表格保存为 CSV 文件,如下所示。
- 我们使用 61 天的数据:从 8 月 3 日开始。2021 年至 2021 年 10 月 2 日。
- 最低的 RMSE 值是 29.9。考虑到数据是有噪声的,我们认为这个值是有意义的。
- 繁殖率为 1.6。
- IFR 为 0.032%。好像太低了。但是根据这个站点,死亡率最低在 0.07%左右。
想象结果
让我们看看这个模型是如何在图表中拟合观察到的数据的。下面是代码。
- 第一张图是来自实际数据和我们的模型的每日死亡人数。我们可以看到模型与数据非常吻合。此外,所有模型结果都非常接近。
- 第二张图与此类似,只是我们展望了未来 60 天。我们可以看到预测的死亡人数逐渐减少。然而,还不完全是零。
- 第三张图绘制了来自观察数据和 SEIR 模型的感染计数。在这里,我们看到模型值远远高于官方的感染计数。

图片作者。泰国 2021 年 4 月 1 日至 2021 年 10 月 2 日每日观察死亡数和模型结果图

图片作者。泰国 2021 年 4 月 1 日至 2021 年 10 月 2 日观察到的每日死亡数和模型结果的图表。此外,我们预测未来 60 天

图片作者。泰国 2021 年 4 月 1 日至 2021 年 10 月 2 日观察到的感染数和模型结果的图表。此外,我们预测未来 60 天
我们可以看到形势似乎对国家更有利。
将复制率的变化可视化
让我们看看繁殖率是如何逐月变化的。我们将这样做:
- 按月划分案例数据。
- 使用月度数据运行参数网格搜索。
- 计算每月的复制率并绘制数据。
以下是代码:
图表如下。

图片作者。2021 年 4 月至 2021 年 9 月的繁殖率变化
- 4 月份,繁殖率小于 1。
- 然后,R0 一直增加到 7 月。
- 8 月份,R0 略有下降,但仍大于 1。
- 9 月份 R0 下降很多。现在这个值又小于 1 了。
有了这种出生率的变化,我们更加相信疫情的情况正在好转。
结论
我们使用 SEIR 模型和公共在线每日数据来分析和预测新冠肺炎趋势。结果看起来很有希望。模型输出与观测数据非常吻合。
我们可以做一些事情来改进这个模型:
- 我们可以包括自然出生率和其他原因的死亡率。
- 我们本可以在方程式中加入移民工人的数量。
所有的源代码文件都可以在 GitHub 这里获得。
引用:迪伦杰伦。泰国新冠肺炎数据。从 https://github.com/djay/covidthailand取回。它是在知识共享署名 4.0 国际许可下授权的
利用 LSTM(RNN)和 DNN 预测德国未来的电力消费
利用 LSTM(RNN)和 DNN 对过去 5 年的电力消耗进行探索性数据分析,并预测未来的电力消耗
人类生活在时间轴上,并据此设计自己的日常生活。他们通常在晚上睡觉,其他活动通常在特定的时间进行(例如早餐——在早上)。当我们考虑语言时,众所周知,所说或所写的保持并遵循某种意义的完整性。当我们谈论机器学习时,这种序列数据集中的模型训练是通过使用统计方法(如 ARIMA、SARIMAX)以及使用神经网络来进行的。基本思想是时间 t 的数据是几个先前数据点的结果。本文解释了 RNN-LSTM 的理论部分,并包括一个关于时间序列数据集的快速探索性数据分析和使用 LSTM 和 DNN 预测德国未来功耗的教程。
***Table of Contents* 1\. Theory
1.1\. Recurrent Neural Networks
1.1.1\. Under the Hood
1.1.2\. Vanishing Gradient Descent
1.2\. Long-Short Term Memory
2\. Tutorial
3\. Conclusion
4\. References**

丹尼·米勒在 Unsplash 上的照片
递归神经网络
在按顺序流动的数据集中,时间 t 的每个数据都与历史数据相关。比如我们考虑 NLP,一个段落的延续是按照它前面的关键词来塑造的,也就是按照意思的完整性来塑造的。阅读小说时,平均每秒钟可以看到 3-4 个单词,并且可以流畅地继续阅读。虽然在 1 个小时的阅读结束时,已经看到并阅读了几千个单词,但很难背下来。然而,阅读的部分可以很容易理解和解释。在机器学习中,递归神经网络可以用来从这样的序列数据集中提取基本含义和模式。让我们继续不同的例子;电影由画面组成,根据电影的主题和内容,这些画面具有一定的完整性。我们在理解了电影之后,可以很容易地预测电影中的下一个瞬间或者下一帧。递归神经网络可用于通过检测序列数据中的流动模式来预测未来。在另一个例子中,它提供时间序列,即在随时间变化的图形(股票市场,冠状病毒随时间的传播)中,来检测流量并进行预测。那么,如何用数字从数学上解释是什么提供了这些可能性呢?
在后台
下图显示了递归神经网络过程如何在 4 秒钟内处理 4 个数据的顺序数据集中工作。其基本工作原理类似于前馈神经网络。整个系统可以简要概括如下:
分配给输入的权重值在图层后变成输出,并与实际输出进行比较,以确定损失值,即与应有位置的距离。根据该损失值,更新权重值,并重复相同的过程。更新权重的目的是最小化损失值并确定最佳权重值。
另一方面,RNN 是顺序设计的,即,在反向连接中检测时间t与(t-1)的数据连接。当然,除了仅仅t和(t-1),也许它在时间 t 的值是根据最后 10 个值计算的,这要归功于它的后向连接结构。现在让我们详细研究一下图 1。

图一。递归神经网络,作者图片
让我们考虑 4 个数据点(x1、x2、x3 和 x4)。黄色结构代表层。每个输出的等式如上所述。正如所看到的,每一层的输出被顺序地呈现为下一层的附加输入。最终输出结果基于选定的激活函数。然后,计算所得结果的偏差,根据损失输出导出权重,并通过反向传播过程进行更新。RNN 的结构基本上遵循这种模式。如果我们看看这个 RNN 结构的缺点,消失梯度的问题就迎刃而解了。
消失梯度下降
当很难收敛到全局极小点时,这种情况称为消失梯度下降。
在 RNN,当有太多层并且权重用 Sigmoid 函数更新时,这个过程发生。用 Sigmoid 函数获得的值应该在 0 和 1 之间。然而,在反向传播过程中,第一输入(NLP 的前几个字,时间序列的前几次)在连续序列的学习中对系统的影响被最小化,因为权重更新处于如此低的水平,以至于当到达第一层时。这会导致这些输入及其权重被忽略,从而将顺序学习集中在最后的输入上。
如果用另一个激活函数代替 Sigmoid 函数,比如 ReLu ,由于 ReLu 的结构,会出现与消失梯度下降相反的情况,即权重变化太大以至于无法安全到达全局极小点。
长短期记忆
LSTM 设计用于防止在更新权重期间忽略顺序序列中第一个输入的影响。图 2 显示了 LSTM 模型如何避免在权重调整中不考虑不重要的先前数据(先前数据的权重)的问题。

图二。长短期记忆(LSTM),[来源](http://A. Géron, Hands-on Machine Learning with Scikit-Learn, Keras, and TensorFlow (2019, O’reilly). O’Reilly Media, 2017.)
逻辑(Sigmoid)激活功能输出 0-1 之间的数据。这样,数据的显著性水平被评估为 0-1。0 变得不重要,并在乘法运算中反映为 0。1 表示它很重要。
双曲正切激活函数通过输出(-1)和(+1)之间的值来承担调节任务。
步伐
- 先前单元输出
(h(t-1))和当前输入(x(t))通过逻辑(sigmoid)函数传递。长期状态(c(t-1))乘以结果值(f(t))。在这个阶段(忘记门),从长期状态中数学推断出哪些数据是重要的,重要到什么程度。 - 在第一步中获得的 sigmoid 值也在这里用相同的输入(先前单元输出
(h(t-1))和当前输入(x(t)))获得(i(t))。此外,这些输入也通过tanh激活功能并与 sigmoid 输出(g(t))相乘。在这个阶段,(输入门)i(t)从数学上表达了 g(t)值有多重要。 - 将前两种情况下获得的数学表达式(遗忘门和输入门)相加,形成新的单元状态
(c(t))。此外,该结果通过传递 tanh 并乘以前两个阶段的两个输入(前一个单元输出(h(t-1))和当前输入(x(t)))的逻辑(sigmoid)函数结果(o(t))而被规则化。返回短期状态(h(t))。在这个阶段(输出门),长期状态的重要性转移到系统。
LSTM 及其配置版本适用于许多基于时间的数据集,尤其是股票市场价格预测。
辅导的
在本教程中,使用 2015 年 1 月 1 日至 2020 年 9 月 1 日之间德国数据集的每小时能耗,对 LSTM 和 DNN 的模型进行了训练。数据集可以从链接下载。
数据集的许可:CC0:公共域
[1]
首先,导入必要的库,由于时间 t 的数据与之前的数据相关,因此从 2015 年 1 月 1 日到 2019 年 5 月 31 日保留为训练集,2019 年 5 月 31 日–2020 年 9 月 1 日保留为测试集。数据集由每 15 分钟的功耗值组成。通过将 4 个值(0-15 分钟、15 分钟-30 分钟、30 分钟-45 分钟、45 分钟-60 分钟)相加,数据集被转换为基于小时的值。然后如图 3 所示。

图 3。德国 2005 年 1 月 1 日至 2020 年 9 月 1 日的电力消耗,图片由作者提供
[2]
添加年份和月份列后,根据年份和月份的盒状图分别如图 4 和图 5 所示。

图 4。按年份排列的方框图,按作者排列的图像

图 5。按月份排列的方框图,按作者排列的图像
[3]
在本节中,使用以下策略根据神经网络模型对数据集进行重新调整和重新设计:
将 24 个数据(1 天= 24 小时)按顺序用last_n = 24设计为输入,25。数据被输出。例如,在索引的基础上,输入 0–24,而输入 24。数据输出;25.输入 1–25 时的数据输出;26.输入 2–26 时的数据输出,等等。
当设计 LSTM 模型时,return sequence=True被设置直到最后一个 LSTM 层,并且模型被训练。在训练结束时,模型分别预测更新的权重以及训练和测试数据集。
图 6 显示了在创建输入-输出时,通过重新排列由所选数字引起的移位,测试数据集的随机部分的可视化结果。

图 6。LSTM 预测与真实值的比较,作者图片
[4]
在这一部分中,使用密集层来构建模型,以使用深度神经网络来训练模型。在数据集中使用相同的缩放器方法,并在制作适合模型的形状后对其进行训练。LSTM 使用的流程经过配置,适合 DNN 模型,测试数据集随机部分的预测如图 7 所示。

图 7。DNN 预测与真实值的比较,作者图片
结论
顾名思义,长短期记忆(LSTM)是基于通过更新权重来训练模型,同时考虑到长期历史数据的重要性。使用上述密集层创建的 DNN 模型是在神经网络的基础上根据输入和输出之间的激活函数来更新权重。当我们粗略对比上面的结果(图 6 和图 7)时,可以说两种结果都接近现实。然而,当仔细观察时,可以看出 LSTM 在较低和较高的峰值处,尤其是在较低的峰值点处绘制了更成功的图形。尽管 DNN 结果中几乎所有较低的峰值都低于它们应有的水平,但 LSTM 绘制了一个更成功、更恰当的图表,尽管存在小幅的上下偏差。
由于 LSTM 的设计考虑了先前数据的重要性,因此它可以更有效地执行学习过程。因此,当模型被训练时,DNN 可以使错误模式成为学习过程的一部分,而 LSTM 在这一点上更灵活地呈现模型。由于这个数据集结构大致遵循一定的顺序(见图 3),只有仔细研究才能看出这两个模型之间的区别。然而,对于具有较高随机性(难以检测模式)的数据集和时变数据集,可以更清楚地看到 LSTM 的差异。
参考
http://colah.github.io/posts/2015-08-Understanding-LSTMs/
https://ibrahimkovan.medium.com/machine-learning-guideline-959da5c6f73d
预测滑雪板的销售
从零开始的时间序列练习

作者拍摄的照片
如果你了解基本知识,时间序列预测可以是一个简单的练习,就像滑雪一样。有很多时间序列预测的例子,但是,如果我对这个例子感兴趣,我会学到更多。所以,我决定创造一个我自己的例子,关于我最喜欢的运动之一——单板滑雪!
这篇文章的结构如下:
- 查看您可以拥有的不同类型的数据。
2.了解时间序列数据的特征。
3.探索可应用于数据和不可应用于数据的模型类型。
4.滑雪板使用案例——请随意使用您自己的数据集。
正确掌握基础知识
你在处理什么样的数据?
横截面数据
没有时间维度的数据—这可能是某个时间点的许多特征和度量,例如,年龄、性别、平均收入、学校教育……都在某个时间点。
时序数据
具有时间维度的数据—一段时间内的观察结果,例如过去 5 年的平均家庭收入(HHI)。如果你想预测下一年的 HHI,这将被称为单变量时间序列预测,因为你预测的是单个变量。
*我们将关注用例中的单变量时间序列预测。
汇集的数据
这是横截面和时间序列数据的组合,例如,观察一段时间内的销售情况,以及客户满意度和实际可支配收入(RDI)。如果您想预测下一年的销售额,以及外部因素(例如,客户满意度和 RDI),那么这被称为多元时间序列预测,因为您是在预测一段时间内的多个变量。
时间序列预测可以简单地通过观察历史模式来完成,或者可以使用机器学习模型(例如,神经网络或随机森林回归等)。).然而,历史模式并不总是未来行为的良好指标,机器学习模型有时会使分析过于复杂,人们需要考虑如何向利益相关者解释这些模型。
了解时间序列数据的特征

来源:作者
趋势:
这是你长期观察的大致方向。它是向上的、向下的还是水平的(通常称为静止的)?

来源:作者
季节性:
如果有一个模式以相等的时间间隔重复,则您的数据包含季节性:

来源:作者
不规则变化:
除了季节性和趋势性之外,您的数据中还可能存在峰值,例如假期峰值或趋势的任何变化:

来源:作者
使用哪种预测模型?
以下指南根据您的数据特征推荐使用的模型(若宫,C (2020) ):
无季节性+疲软趋势:
●简单的指数平滑
● ARIMA
季节性和趋势:
你会得到加法和乘法季节性:

来源:作者
根据 [Pegels,C.C (1969)](http://Pegels, C.C. (1969) Exponential Forecasting: Some New Variations. Management Science, 15, 311-315. http://dx.doi.org/10.1287/mnsc.15.5.311) 所做的工作,在预测时有许多时间序列模式:

来源:作者
●三重指数平滑法(Holt Winters) —您可以定义加法和乘法的季节性类型。
●SARIMA——是 ARIMA 款的季节性延伸。
复杂模型:
这将在最后讨论。
用例
在本例中,我们将:
- 了解您拥有的数据类型。
- 了解哪些预测模型最适合您的数据,以及为什么其他模型不适合。
- 知道如何评价自己选择的模式。
- 如何让你的模式更进一步?
数据
根据 360 研究报告最近的一份报告:
“2020 年,全球滑雪板设备市场价值为 5.0348 亿美元,并将从 2020 年到 2027 年以 6.71%的 CAGR 增长。”——360 研究报告(2021 年)
我创建了一个虚拟的数据集,你可以在这里下载。它显示了从 2009 年 1 月到 2020 年 12 月售出的滑雪板数量。
#Import packagesimport pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
plt.rcParams.update({'figure.figsize':(20,18), 'figure.dpi':500})
from numpy import log
import warnings
import itertools
import numpy as np
plt.style.use('fivethirtyeight')#Load dataset
data = pd.read_excel('Snowboard_Data.xlsx',
index_col ='Date',
parse_dates = True)# Print the 1st 5 rows of the dataset
data.head()

来源:作者
#We need to ensure the date is a date type and is indexed
data.info()

来源:作者
让我们绘制数据,看看它看起来像什么:
#Plot data#import matplotlib.pyplot as plt
#import seaborn as sns
#import pandas as pdsns.set(font_scale=2)
plt.figure(figsize = (12,10))#choose a grid style out of darkgrid, whitegrid, dark, white, ticks
sns.set_style("ticks", {"axes.facecolor": "white"})
sns.lineplot(x = "Date", y = "Quantity", data = data, color='blue', linewidth=3.5)
plt.show()

来源:作者
查看线图
我们不仅看到了一个线性上升的趋势,而且我们看到周期的幅度在有规律地增加。这表明我们的数据具有倍增的季节性。
ETS 分解
我们现在将使用 ETS 分解在单独的图表上绘制误差、趋势和季节性:
# ETS Decomposition --> our data is multiplicativeresult = seasonal_decompose(data['Quantity'],
model ='multiplicative')
# ETS plot
result.plot()

来源:作者
第一张图简单地描绘了原始数据。以下三幅图分别显示了趋势、季节性和误差(残差)成分。这三个图结合在一起给出了第一个图中的原始数据。我们看到的是:
- 这种趋势随着时间的推移而增强,并且每隔一段时间就会出现季节性(峰值)。
2.残差在早些年和晚些年显示出高度可变性。
我们有一个强劲的上升趋势和季节性,我们证实这是倍增的。
模拟倍增季节性+趋势
如果我们忽略了季节性或者我们对它不感兴趣呢?那么可以使用简单移动平均(SMA)/简单指数平滑。然而,这往往会过度平滑数据的急剧增加或减少,并假设季节性年复一年地重复(回想一下,这并不总是正确的)。
SMA 是最基本的预测技术。取最后 N 个值的平均值,这个平均值就是下一个周期的预测值。让我们将 SMA 应用于我们的数据,看看如果我们忽略季节性会发生什么(回想一下,SMA 用于没有季节性和趋势疲软的情况)。注意不规则性是如何被消除的。
# Take the moving average of last 6 observations
rolling = data.rolling(window=6)
rolling_mean = rolling.mean()
# plot the two series (original data and the rolling average)
plt.plot(data)
plt.plot(rolling_mean, color='red')
plt.show()

来源:作者
但是我们已经知道 SMA 不是为我们的数据设计的,所以我们转向指数移动平均线(EMA)/指数平滑(ES)。EMA 对旧的观察值应用指数递减的权重,因为旧的数据不太重要。我们对最近的观察更感兴趣,因此对更相关的数据赋予更高的权重。这消除了数据中的一些噪声,并改进了预测。这种方法只有在用于短期预测时才是可靠的。
3 种 es 预测方法
1.单一(简单)指数平滑法
SES 使用指数递减权重的加权移动平均,这很简单,因为没有特定的结构。这不处理趋势或季节性,适用于单变量数据。
2.双指数平滑
Holt 的趋势修正双指数平滑法是 SES 的扩展。这确实处理趋势(加法和乘法),并应用于单变量数据,即
- 加性趋势:线性趋势的双指数平滑。
- 倍增趋势:双指数平滑带指数趋势。
3.三重指数平滑
三重指数平滑/乘法霍尔特-温特斯/霍尔特-温特斯指数平滑-是双重指数平滑的扩展,您可能已经猜到了,它可以处理单变量时间序列的趋势和季节性。
- 加性季节性:线性季节性的三重指数平滑。
- 倍增季节性:三重指数平滑,具有指数季节性。
现在,我们将对数据应用双重和三重 ES。
双 e 和三 e
#import numpy as np
#import pandas as pd
#import matplotlib.pyplot as plt
#from statsmodels.tsa.api import ExponentialSmoothing# Split data into train / test sets
train = data.iloc[:len(data)-12]
test = data.iloc[len(data)-12:]# Set one year(12 months) for testing
fit1 = ExponentialSmoothing(np.asarray(train['Quantity']) ,seasonal_periods=12 ,trend='multiplicative', seasonal='multiplicative',).fit()# Create class
# Apply the box-cox power transformation - this that takes the original (non-normally distributed) data as input and returns the fitted data (normally distributed)
# See Source: (GeekksforGeeks , 2021) - [https://www.geeksforgeeks.org/box-cox-transformation-using-python/](https://www.geeksforgeeks.org/box-cox-transformation-using-python/)EMA_fit = ExponentialSmoothing(train['Quantity'], seasonal_periods=12, trend='multiplicative', seasonal='multiplicative').fit(use_boxcox=True)# fit model and make prediciton
fcast = EMA_fit.forecast(len(test))#or can be len(12)
# if the series was monthly data and the seasonal period repeated each year, then the Period=12.y_hat_avg = test.copy()
y_hat_avg['Holt_Winter'] = fit1.forecast(len(test))#holt winter is ES and can be additive or multiplicative and we know we have multiplicative seasonality
ax = train.plot(figsize=(10,6), marker='o', color='black', title="Forecasts from Exponential Smoothing" )
ax.set_ylabel("Quantity Snowboards Sold")
ax.set_xlabel("Index")
EMA_fit.forecast(12).rename('Train').plot(ax=ax, marker='o', color='blue', legend=True)
y_hat_avg.Holt_Winter.rename('Holt_Winter - Test').plot(ax=ax, style='--', marker='o', color='red', legend=True)

来源:作者
forecast = fcast
forecast = pd.DataFrame(forecast)
forecast
forecast_es = forecast.rename(columns={0: "ES_Forecast"})
forecast_es

来源:作者
# Load specific evaluation tools
# We will now calculate RMSE to check to accuracy of our modelfrom sklearn.metrics import mean_squared_error
from statsmodels.tools.eval_measures import rmse
from math import sqrtrms = sqrt(mean_squared_error( forecast_es.ES_Forecast, test.Quantity))
print(rms)#The value we get is: 34.69362278646293
这个 34.69 是什么意思?这就是均方根误差(RMSE) ,这是衡量预测模型性能的方法之一。
我们看到了为什么 SMA 不适用于包含趋势和季节性的时间序列。为了完整起见,让我们看看为什么 ARIMA 不起作用。
ARIMA 失败的原因
ARIMA 不支持季节性。我们通过对我们的数据进行差分并没有消除增加的幅度这一事实来看到这一点。即使对数据进行两次差分,序列仍然是非平稳的。这意味着我们的数据有很强的季节性,我们不能忽视。
#Original Series
fig, axes = plt.subplots(3, 2, sharex=False)
axes[0, 0].plot(data.Quantity); axes[0, 0].set_title('Original Series')
plot_acf(data.Quantity, ax=axes[0, 1]) #autocorrelation plot#1st Differencing
axes[1, 0].plot(data.Quantity.diff()); axes[1, 0].set_title('1st Order Differencing')
plot_acf(data.Quantity.diff().dropna(), ax=axes[1, 1]) #autocorrelation plot#2nd Differencing
axes[2, 0].plot(data.Quantity.diff().diff()); axes[2, 0].set_title('2nd Order Differencing')
plot_acf(data.Quantity.diff().diff().dropna(), ax=axes[2, 1]) #autocorrelation plotplt.show()

来源:作者
萨里玛/萨里马克斯

来源:作者
萨里玛利用季节差异。
我们将对我们的数据应用 auto_arima() 函数。该功能可选择使用逐步方法搜索模型中使用的 p,d,q 参数的多种组合。为了识别 p、d 和 q 的最佳组合,选择具有最低 AIC 的模型。
只是澄清一下阿凯克信息标准 ( AIC )的含义:
我们正在利用一个统计模型(SARIMA)来表示生成我们的滑雪板销售数据的过程。因为这只是一个模型而不是真实的过程,所以信息会丢失。AIC 越低,模型丢失的信息就越少,我们的模型就越能更好地描述过程。AIC 还考虑到模型的简单性,以确保模型不会过度拟合或欠拟合数据。
每当逐步方法找到具有较低 AIC 的模型时,该模型就成为新的最佳模型,直到该过程不能找到接近当前最佳模型的模型。
下面是分步结果的代码:
# Import library
from pmdarima import auto_arima
# Supress warnings that are not important
import warnings
warnings.filterwarnings("ignore")
# Apply auto_arima to data
sw_fit = auto_arima(data['Quantity'], start_p = 1, start_q = 1,
max_p = 3, max_q = 3, m = 12,
start_P = 0, seasonal = True,
d = None, D = 1, trace = True,
error_action ='ignore',
suppress_warnings = True,
stepwise = True)#We are using the stepwise approach
# Summarise the stepwise results
sw_fit.summary()

来源:作者
最好的模型是 SARIMAX(0,1,1)x(2,1,1,12)。现在,我们将数据分为训练集和测试集,并将此模型应用于训练集:
# Split data into train and test setstrain = data.iloc[:len(data)-12]
test = data.iloc[len(data)-12:] # set one year(12 months) for testing
# Fit a SARIMAX(0, 1, 1)x(2, 1, 1, 12) on the training setfrom statsmodels.tsa.statespace.sarimax import SARIMAX
model = SARIMAX(train['Quantity'],
order = (0, 1, 1),
seasonal_order =(2, 1, 1, 12))
result = model.fit()
result.summary()

来源:作者
现在,我们将模型的一年预测与我们的测试集进行比较:
start = len(train)
end = len(train) + len(test) - 1
# Predictions for one-year against the test set
pred = result.predict(start, end,
typ = 'levels').rename("Predictions")
# plot predictions and actual values
pred.plot(figsize = (12, 5), legend = True)
Quantity =test['Quantity']
Quantity.plot(legend = True)

来源:作者
# Load specific evaluation tools
from sklearn.metrics import mean_squared_error
from statsmodels.tools.eval_measures import rmse
# Calculate root mean squared error
#RMSE is always greater than 0, where 0 indicates that our model has a perfect fit(theoretically possible, but hardly achieved in practice)rmse(test["Quantity"], pred)#The value we get: 25.715869516322755#This is a much lower RMSE as our previous model
现在,我们在完整的数据集上拟合模型:
# Train the model on the full dataset
model = SARIMAX(data['Quantity'],
order = (0, 1, 1),
seasonal_order =(2, 1, 1, 12))
result = model.fit()
# Forecast for the next 2 years
fcast_sarima = result.predict(start = len(data),
end = (len(data)-1) + 3 * 12,
typ = 'levels').rename('Forecast')
# Plot the forecast values
data['Quantity'].plot(figsize = (12, 5), legend = True)
fcast_sarima.plot(legend = True)

来源:作者
这一预测与融 360 研究报告中的发现一致。
让我们来看一些诊断:
sns.set(font_scale=1)
result.plot_diagnostics(figsize=(13 , 10))
plt.show()

来源:作者
快速分析我们的诊断图表:
- 标准化残差(左上):这显示了一段时间内的残差。这里必须没有模式,残差越不一致越好。我们已经确定了季节性和趋势。如果这里有一个模式,那么这意味着我们还没有确定趋势或季节性。
- KDE 图(右上角):如果橙色密度线(KDE)紧跟绿线,那么残差的分布是正态分布。
- 正态 qq 图(左下角):这是一个直观的检查,看看我们的因变量是否正态分布。如果蓝点紧跟红线,那么我们的因变量遵循正态分布。这是我们做的一个隐含的假设,但是我们的统计分析必须有效。
- 相关图(右下):如果大多数蓝点落在蓝色阴影区域,那么这表明我们的残差与它们自身的滞后版本几乎没有相关性。
诊断图表明,我们已经找到了适合我们数据集的模型。最后,回忆一下我们发现的 RMSEs:
欧洲标准:34.693
萨里玛:25.72
其中 SARIMA 是 ES 的改进,因为它产生了较低的 RMSE。
复杂模型
您可能已经遇到了各种预测库和算法,它们可以进一步改进 SARIMA 模型。因此,有必要提及一些后续步骤。
LinkedIn 发布了一个名为 Greykite 的时间序列预测库,其中包含 Silverkite,这是一种自动预测的预测算法。同样,脸书发布了 Prophet,这是一种预测算法,有助于处理数据中的峰值和变化趋势。
先知 vs 银雀:
更详细的对比可以在[这里](http://A high-level comparison can be found here)找到。
先知模型
●由脸书创作。
●它可以处理缺失数据、异常值、季节性影响和时间序列数据的突然变化,如产品促销或世界杯等。
●是开源的,Python 和 r 都可以用。
银风筝模型
●由 LinkedIn 创建。
●允许定制回归变量,以说明季节性、数据点变化、增长、交互项和自回归。
●如果快速部署很重要,这是首选。
●增加可解释性的各种可视化选项。
●预测分位数,而不是平均值。
●自带内置模板。
结论
回头看看我们的虚拟数据集,滑雪板的销售显示出季节性是有道理的,因为这是一项冬季运动。我们还研究了滑雪板的销售预计在未来几年将会增加。
我们看到,过度简化您的模型并不能捕捉数据中的所有细微差别。更进一步(SARIMA)展示了增加一个额外的复杂性层如何能够极大地改善结果。然而,我们能更进一步吗?这就是建模艺术的用武之地,因为正如一个人可以过度简化一个模型,他也可以过度复杂它。
然而,我很想听听你对如何模拟这些数据的反馈。
可能的扩展和注意事项:
●典型的冬季分为淡季、旺季和旺季。
●由于 COVID 期间,度假村意外关闭。
●向数据添加额外的解释变量,使其成为多元变量。

当准确性不再是目标时的预测:一个充满可能性的新世界
行业笔记
业务预测需要面向业务的指标,而准确性指标则不需要。弥合这一差距开启了公司和从业者长期以来期待的多个用例。

在这个系列的文章[1]中,我们已经展示了现有的预测准确性指标为什么以及如何阻止需求计划者提供更多的商业价值。
更准确地说,使用来自 M5 竞赛的数据,我们根据经验建立了准确性指标和成本效益之间的弱相关性。
换句话说:现有指标没有考虑预测的预期用途和相关成本…在这种情况下,通过改进预测来最小化成本(或最大化盈利能力)与其说是科学,不如说是运气!
对于公司和从业者来说,浪费时间和资源努力工作却发现并不总是增加预期的价值(更糟糕的是,经常降低盈利能力)是多么令人沮丧!
但好消息是,任何需求规划者都可以通过简单地从“准确性”转换到“成本”指标来创造更多的商业价值。
关注“成本”为需求规划打开了一个全新的可能性世界,并允许半打独家用例!
在这篇文章中,我将举例说明其中的一些。但是首先,让我们快速看一下什么是“决策影响”指标。
什么是“决策影响”指标?
本系列的第一篇文章[2]提醒我们,预测本身并不是目的,而是为了支持决策者做出更好的决策。
预测的目的不是也从来不是提供有史以来最好的预测!其目的是做出最佳决策。
因此,最好的预测并不是完美的预测,而是能够做出最佳决策的预测。因此,预测者的使命不应是最小化预测与现实之间的误差,而是最小化决策误差。
这意味着从侧重于预测内在质量的“预测准确性”(FA)转向侧重于基于预测的最终决策及其相关性/成本和影响的“决策影响”(DI)。
通用成本函数
提议的度量标准要求创建一个“成本函数”,该函数可以针对任何预测输入,评估业务决策并评估其质量。
虽然决策的质量可以用许多方式来表达,但在本研究中,我们选择了财务成本。

作者图片
这种“成本函数”的创建在本系列的第一篇文章中也有详细介绍[2]。让我们假设定义了这样一个“成本函数”。然后,它允许我们计算与任何输入预测相关的成本。

成本指标#1:实际成本(直径)
通过将成本函数应用于我们的“实际”预测,我们获得了由我们的预测引起的成本。让我们用直径来表示。
成本指标#2:原始成本(DIn)
通过将成本函数应用于“原始”预测(例如,移动平均预测),我们可以获得由我们可以实现的最简单的预测过程引起的成本。让我们用晚餐来表示它。
成本指标#3: Oracle 成本(DIo)
通过将成本函数应用于“预言”预测(即实际销售),我们获得后验对未来的完全了解会导致的成本。让我们用 DIo 来表示它。
组合 DIa/DIn/DIo 构建模块
这三项成本是基本的构建模块,可以很容易地组合在一起创建三个有洞察力的指标。
衡量挣值
预测流程的性能如何?它产生价值了吗?多少钱?
在衡量他们给公司增加的价值时,需求计划者经常做不到。由于他们的关键角色通常以交付定性预测而告终,因此他们唯一的资产就是 f a。他们几乎没有评估商业价值的方法。
然而,有人试图评估他们的表现。
其中之一是将 FA 与行业基准进行比较。但是 Nicolas Vandeput 最近在一篇文章[3]中提醒我们,有许多原因可以说明为什么要不惜一切代价避免基准测试!
这些原因包括业务战略的多样性(投资组合的规模、产品和品牌定位)、预测准确性的衡量水平,甚至指标本身的定义(尤其是价值加权公式)也可能不同,等等。
另一种方法是应用 FVA(预测增加值)。大多数情况下,它包括将实际 FA 与简单预测的 FA 进行比较,以评估预测是否得到了改进。
这听起来很棒,的确如此!但它的应用方式仍有重要的局限性:
- FA 不是关键经营业绩指标(KPI)
我们已经说过,FA 与经营业绩相关性不大。所以提高 FA 并不意味着你在创造价值。随着精度的变化,成本可能增加、减少或保持不变。 - FA 指标互相矛盾
FA 指标有几十种,它们并不都一样。更糟糕的是,它们经常互相矛盾:一个改善,另一个恶化。因此,从一个 FA 指标到另一个 FA 指标的简单转换可以深刻地改变你的 FVA 结果。 - 应用于 FA 的 FVA 不是 FVA,而是 FAA
正如 Paul Goodwin 在最近的一次聊天中总结的那样,“预测增加值(FVA),正如它经常被应用的那样,实际上是预测准确度增加值(FAA),这可能会产生误导。”事实上,只要 FA 在 FVA 被使用,它的真正价值就无法实现...
不要误解我。我是 FVA 和迈克·吉利兰作品(《FVA 教父》)的忠实粉丝。他的工作是这一系列文章的灵感来源。
但是,只要 FA 在 FVA 被使用,FVA 与商业价值的相关性就和 FA 一样小。
有趣的是,FVA 的方法本身并没有真正的问题!在 2019 年 ISF 演讲中[5],迈克·吉利兰给出了 FVA 的定义:
预测绩效指标 的变化 可归因于预测流程中的特定步骤或参与者。
因此,很明显,FVA 可以应用于任何指标。因此,用 DI 代替 FA 不仅尊重 FVA 的定义,而且只要以评估商业价值为目的,就更加自然。
然后让我们计算 DIna,即 DIn(原始成本)和 DIa(实际成本)之间的差值。

迪娜衡量的是什么?不亚于 FVA:从商业角度看预测过程的附加值。
衡量尚未实现的价值
你应该对自己目前的迪娜表现满意吗?创造价值是好的…但是你已经抓住了它的全部,还是仅仅抓住了它的表面?
有趣的是,根据 FA 指标,你能梦想到的最好的表现是 100%的准确率!这对每个 SKU 都是一样的。这是需求规划的圣杯!
但是 100%准确的附加商业价值是什么?一百万美元还是 1 美元?嗯…我们又一次不知所措了!
DI 指标如何帮助我们?
我们还是按照之前的逻辑,介绍一下 DIao:DIa(实际成本)和 DIo (oracle 成本)的区别。

刁衡量的是什么?不亚于不劳而获的价值:通过改进预测仍然可以获得的价值。
当然,不可能获得每个 SKU 的 100%的 DIna 值,因为这需要对未来有一个完美的了解。然而,刁提供了我们所能想到的最有趣的见解之一…因为它有助于确定真正的价值所在。下面描述的用例将告诉你更多这方面的信息。
测量可获利价值
到目前为止,我们已经介绍了迪娜和刁?我们来评价一下迪诺。它会测量什么?
遵循和之前一样的逻辑,DIno 就是 DIn(朴素成本)和 DIo(甲骨文成本)的区别。因此,它也可以定义为 DIna(挣值)和 DIao(未挣值)的总和。


因此,DIno 是对整个竞争领域的一种衡量:总的可赚取价值。
总结一下

- DIn:天真预测的成本
- 直径:实际预测的成本
- DIo:Oracle 预测的成本
- 迪诺衡量总的可用价值
- DIna 衡量挣值
- 刁衡量的是尚未获得的价值
- DIna/DIno 衡量挣值的比例
- DIao/DIno 衡量尚未获得的价值的比例
七个用例最终解锁
分享预测绩效
“预测总是错的!”、“预测太这个”、“预测不够那个”、“70% FA 是什么意思?”,“这是好是坏?”
需求计划员通常需要以客观、易于理解且不矛盾的方式与各种各样的受众分享和维护他们的绩效。
到目前为止,FA 通信是规则。但是说实话,
- 大多数(如果不是全部)FA 指标对于非从业者来说很难理解。
- 一个给定的 FA 水平是一个事实,并不能说明它是好是坏
- FA 指标相互矛盾:一个指标得到改善,而另一个指标恶化。
在这种情况下,通过 FA 指标进行有效沟通几乎是不可能的。在每家公司,这往往会让人产生怀疑,更不用说批评了。
DI 指标是表示财务成本、收益或损失的指标。这使得他们很容易理解,无论谁读这些数字。
有了 DIna 指标,需求计划者现在可以证明,即使预测并不完美,它仍然节省了一定数量的资金。相反,他们可以准确评估绩效不佳的成本,并主动启动必要的工作。
建立预测的投资回报率
需求规划部门的季度、季度或年度投资回报率是多少?
所有重大的商业决策都需要了解投资回报。如果你不知道你的努力是否正在产生结果,你如何才能恰当地实现盈利最大化?然而,在需求计划中,我们在玩猜谜游戏。
但是现在,DIna 指标为公司的附加值提供了一个深刻的视角。然后,确定预测的投资回报率是非常实际的。
为了说明这一点,让我们回顾一下 M5 竞赛的一些教训[6]。如果沃尔玛应用“F_ADIDA”方法生成其预测,DIna 指标确定,在竞争范围内(10 家商店,3049 件商品,1 个月),该预测将节省 2,345 美元(与简单的“移动平均”方法相比)。通过减去一些内部预测成本(人员、工具等。),那么预测的 ROI 就很容易计算出来了。
推广最佳实践,消除不良实践
判断性预测会让事情变得更好还是更糟?这些 X 或 Y 数据是否改善了预测?哪种预测模型增加的价值最大?
当这些问题被提出时,通常的答案是“FVA”。这才是正确的答案……只要附加值确实是衡量出来的。这正是迪娜的切入点。
如果你还不熟悉 FVA,那么我强烈推荐你观看兰开斯特大学 CMAF 的“CMAF 周五预测讲座”系列中的这个精彩的网络研讨会。
公平评估预测员工绩效
在评估个人表现时,你能识别出表现最好和最差的人吗?
当然,仅从业务附加值的角度来评估一个人的表现有太多的限制。人类不是纸上的数字。
然而,丢弃这些信息并且不能识别最佳和最差的表现者也是不公平的。
很多时候,业绩是用 FVA(基于准确性)来评估的,通常用投资组合收入、数量或项目数来加权。但是这种方法并不能公平对待每个人的工作。有些周界比其他周界更容易或更难预测,有些更大,有些更关键,等等。
但现在,demand planner 计算的“增值”(DIna)或“增值比例”(DIna/DIno)提供了一个清晰、真实的衡量标准,可以衡量每个人对公司的贡献,从而更好地评估所做的工作和每个投资组合的特点。
为投资建立强有力的商业案例
我们应该投资先进的解决方案吗?值得吗?哪个供应商的解决方案最适合我的特定环境?
投资新的需求计划解决方案通常需要三个步骤:
- 调整管理团队以获得批准并启动项目
- 确定最能满足您需求的解决方案
- 部署后,确保解决方案提供预期的价值。
在需求计划中,FA 在这三个步骤中都起着核心作用。因此,拥有最好 FA 的供应商拥有最好的卡!
但是提高 FA 不是一个商业案例。因此,它不是证明改进需求的正确 KPI,也不是选择正确的解决方案或评估其提供的价值的正确 KPI。
相比之下,DI 指标是自然支持这种投资过程的成本指标。刁从商业角度展示了改进潜力。反过来,DIna 评估每个供应商的实际附加值,以确定为预期用途提供正确解决方案的供应商。最后,随着时间的推移,对 DIna 的监控确保了项目已经交付(并继续交付)了长期的预期价值。
再一次,为了说明这一点,让我们回顾一下 M5 竞赛的一些教训[6]:
- 如前所述,如果沃尔玛应用“F_ADIDA”方法生成其预测,DIna 指标确定该预测在竞争范围内(10 家商店,3049 件商品,1 个月)将节省 2,345 美元(与简单的“移动平均”方法相比)。
- DIao 指标确定改进潜力为 21,946 美元(在相同的小范围内)。因此,总可寻址值的约 10%已通过当前方法得到保护。这样的潜力值得启动一个项目吗?大概吧。
- 为了提高业绩,沃尔玛可能有兴趣采用赢得 M5 竞赛的“YJ _ 斯图”方法。通过这样做,它将节省 2,981 美元(与简单的“移动平均”方法相比)。因此,与现行方法相比,这种方法的增加值为 636 美元。
- 让我们想象一下,沃尔玛也向另一个“供应商”,即“Hiromitsu Kigure”,要求提供概念证明。这种方法在比赛中排名第 45 位,这意味着根据应用的预测准确性指标,这种方法不如“YJ _ 斯图”。然而,该方法的 DIao 显示,沃尔玛可以节省 5000 美元(与简单的“移动平均”方法相比)。因此,与现行方法相比,这种方法的增加值为 2 655 美元,高出 4 倍多。
- 当然,项目成本(人员、工具等。)仍然需要考虑,以便对这两家供应商进行公平的比较,并决定哪种解决方案最适合沃尔玛的具体情况。
确定工作优先级
我应该对自己目前的表现感到满意吗?我应该继续改进吗?我应该停止吗?应该先关注哪里?好的表现到底有多好?
并非所有的 SKU 都是平等的!有些很难预测,有些则不然。有些是高风险,有些不是。有些是战略性的,有些不是。有些有很强的供给约束,有些没有。诸如此类。
在这种情况下,期望相同的性能,或者为每个 SKU 投入相同的精力是不合理的。
你如何定义优先检查的范围?FA 最低的物品是否优先?许多从业者应用 ABC/XYZ 分类,这有助于集中在正确的范围吗?
不幸的是没有。
我们不要过多讨论 FA,因为我们已经讨论了它对业务的价值。
关于 ABC/XYZ 的局限性,我推荐你阅读 Nicolas VanDePut 的这篇文章:“ ABC 分析不是一个好主意。改为这样做。【⑧】。本文清楚地陈述了局限性,并提供了一些关于如何关注正确范围的想法。指导方针包括关注价值、保质期、持有成本、供应提前期、季末和关键程度。
有趣的是,这些要素中的大部分(如果不是全部的话)都与触发决策的成本有关。因此,它们正确地反映在 DI 指标中。
换句话说,DI 指标自然会对项目进行排名,并优先考虑那些影响最大的项目(即,可以获得较高的 DIao 值)。
利用概率预测
当从确定性预测转向概率性预测时,从业者需要用概率性预测来取代他们旧的确定性准确性指标。
第一个好消息是,这不适用于 DI 指标!因为它们关注决策和成本,而不是预测本身,所以 DI 指标在设计上与任何类型的预测都兼容。
第二个好消息是,将 DI 与概率预测结合使用提供了额外的见解!
这里有一个。概率预测准确地描述了未来可能发生的事件及其发生的概率。这是识别有风险的外围环境和确定决策评审优先级的一个很好的方法。
例如,假设我们关注 5%到 95%的百分比范围,该范围涵盖了 90%的需求值。预测的不确定性越高,范围就越大。因此,这一范围的宽度可以被视为优先审查具有高度不确定性的周界的一种有趣方式。
太好了。然而,高度不确定性并不一定意味着企业面临风险。真正重要的是这种不确定性的经济风险!
我们如何衡量不确定性的经济风险?为此,我们可以利用 DI 指标!
让我们用 1)“最小直径”表示与 5%百分比的预测相关的成本,用 2)“最大直径”表示与 95%百分比的预测相关的成本。“最小直径”和“最大直径”之间的绝对差值定义了不确定性带来的额外成本的实际风险。

然后应该首先审查哪些项目?正如你已经猜到的,那些具有最高经济风险的不确定性代表了真正的风险区域。
结论
业务预测需要面向业务的指标。这似乎是显而易见的,但不言而喻的是,说出来会更好。
FA 指标不是以业务为导向的,经验表明它们不能作为这类指标的代理。
向您的“预测指标名人堂”中引入成本指标(如提议的 DI 指标)并不像听起来那么困难,而且它打开了新的视角和独家用例!
这篇文章旨在阐明预测性能测量的当前实践、局限性和可能的改进。它肯定不是完美的,并且受到限制。
如果你觉得这很有见地,请分享和评论…但是,也请随时挑战和批评。如果你想进一步讨论这个问题,请联系我!
在所有情况下,敬请关注下一篇文章!同时,请访问我们的网站www . vekia . fr了解更多我们在为供应链提供高价值方面的专业知识和经验。
Linkedin:www.linkedin.com/in/johann-robette/
Web:www . vekia . fr
参考
[1]韦基亚,j .罗贝特, 《决策影响度量》文章-目录 ,2021
[2] Vekia,J. Robette,“决策影响”:实施新一代面向业务的指标 的 10 个理由,2021
[3] Nicolas Vandeput,评估产品的可预测性:预测基准与 COV,2021
[4]麦克·吉利兰,《商业预测交易,2010 年
[5] ISF,Mike Gilliland,“ 预测增加值分析 ”,2019
[6] Vekia,J. Robette,““最后的将是第一,第一个是最后的”……来自 M5 竞赛的见解,2021 年
[7] CMAF、罗伯特·菲尔德斯、迈克·吉利兰,关于预测附加值,我们需要知道什么?2020 年
[8] Nicolas Vandeput,ABC 分析不是一个好主意。改为这样做。,2021
Python 中贝叶斯动态广义线性模型的预测
对多元时间序列数据比较贝叶斯和频率主义方法的案例研究

图片由原作者提供。
当规划收入目标、库存管理、员工人数和其他对管理成功企业至关重要的经济因素时,预测对几乎所有企业都至关重要。高度准确的预测通常很难实现,但对于企业在动态市场中规划转变和变化至关重要。通常,预测模型可以(也应该)利用额外的输入或变量,这些输入或变量可能有助于解释目标或从属序列中的可变性。例如,根据网站访问量预测销售量,或根据每月营销支出预测每月收入。通常情况下,可用数据往往有限或不完整,这使得使用标准算法生成准确预测的能力变得复杂。
在这篇文章中,我将介绍多元时间序列的贝叶斯方法,并提供与传统的频率方法,如 ARIMA 的对比。时间序列是回归的一个特例,其中独立变量是一个规则的间隔时间度量(即周、月、年等)。),以及可能有助于解释序列残差变异的潜在外生特征。ARIMA(自回归,综合,移动平均)已成为时间序列预测的标准方法之一;这是一个强大的算法,广泛应用于许多行业。然而,有许多复杂的考虑因素:数据应该是平稳的,可能有多个趋势,独立变量往往是滞后的,存在季节性——有时同一数据中有多个季节,必须有相当数量的可用数据等。由于这些原因,时间序列是一种难以掌握的统计技术,并且生成准确的预测是相当具有挑战性的。
贝叶斯方法为时间序列提供了一种概率方法,以减少不确定性并纳入“先验”信息。这些模型被称为动态线性模型或结构时间序列(状态空间模型)。它们通过动态拟合时间序列中的结构变化来工作,换句话说,随着时间的推移,随着新信息的增加,模型参数不断发展和更新。相比之下,ARIMA 估计序列的参数,这些参数保持固定,然后使用最大似然估计来确定时间序列的预测。贝叶斯方法使用 MCMC(蒙特卡罗马尔可夫链)从分布中生成估计值。在这个案例研究中,我将使用py bats——Python 的贝叶斯预测包。对于那些感兴趣的人来说,关于时间序列贝叶斯方法的统计力学的深入文章可以在这里找到。
案例分析
在本案例研究中,我们评估了两个独立时间序列(协变量)对因变量的影响:特定汽车制造商每月汽车购买总量。因为这是计数数据,所以我们看到的是泊松过程,它假设了与高斯分布不同的基础分布。泊松模型基于计数,因此最低可能值为 0。这两个协变量包括:营销支出,按月汇总,以及给定品牌的消费者情绪指标,标准化为 0-100 分。
数据
我们的数据由 2017 年 1 月至 2020 年 12 月间的 48 次观测组成。没有丢失的值。这些数据代表了每月的汽车销量、平均营销支出(以万计)和平均消费者情绪——一个专有指标。由于我们使用的是 Python,我将提供一些代码片段来演示分析步骤。
# Import the necessary libraries
import pandas as pd
import numpy as np
from scipy import stats
import pmdarima as pmd
import matplotlib.pyplot as plt
import pybats
from pybats.loss_functions import MAPE
from pybats.analysis import analysis
from pybats.point_forecast import median
# import the data
dfv = pd.read_csv("vechicle_data.csv")

我们上面的数据集显示了我们将用于此分析的三个变量:交易是因变量,营销支出和消费者情绪是动态回归模型中的两个自变量(或协变量)。我们本质上要说的是:营销支出和消费者情绪对交易数量有随时间变化的影响吗?我们能否对它们的影响进行建模,并利用我们对这些变量的了解,对超出我们当前数据集的交易做出合理的预测?
让我们来看看目前为止的 3 个独立的时间序列:
DV:售出车辆数量
简单的视觉检查揭示了在这个系列中发生的几件重要的事情:1)数据不是静止的,2)似乎有可能的季节效应,3)方差随时间增加。对 ARIMA 来说,这将是有问题的,我们的系列将受到多重“调整”,如差异和季节分解,以达到平稳的要求。

IV 1:营销支出
下图显示了同一时期平均营销支出的变化。这个系列就不太清楚了。可能有季节性,可能有趋势的变化;这个系列看起来并不稳定。然而,如前所述,这些考虑与时间序列的贝叶斯方法无关。

IV 2:消费者情绪
我们的消费者情绪指标与营销支出指标密切相关,考虑到营销努力会对消费者情绪产生影响,我们可能会预计到这一点。

模型构建
为了构建模型,我们将在 Python 中构建一个函数来使事情变得简单一些。在模型本身中有许多参数需要调整,包括学习和衰减率、季节性、前期应该有多长(以学习前期方差)等。我不会在这里深入讨论,因为 Pybats 教程提供了描述和指南。
def bayes_forecast(iv,dv):
'''
This functions runs the Pybats algorithm by taking two parameters: an independent variable matrix and a dependent variable.
Both elements must be sequential time series.
'''
# first check if the iv = None, indicating this would be a univariate series
if iv is None:
x = None
else:
x = iv.values
y = dv.values
# set the one-step-ahead value; by default we want 1
k = 1
forecast_start = 0
forecast_end = len(y)-1 mod, samples = analysis(Y=y, X=x, family='poisson',
forecast_start=forecast_start,
forecast_end=forecast_end,
k=k,
ntrend=1,
nsamps=5000,
seasPeriods=[12],
seasHarmComponents=[[1,2]],
prior_length=4,
deltrend=0.94,
delregn=0.90,
delVar=0.98,
delSeas=0.98,
rho=.6,
) forecast = median(samples)
# set confidence interval for in-sample forecast
credible_interval=95
alpha = (100-credible_interval)/2
upper=np.percentile(samples, [100-alpha], axis=0).reshape(-1)
lower=np.percentile(samples, [alpha], axis=0).reshape(-1)
print("MAPE:", MAPE(y[-18:], forecast[-18:]).round(2))
#Generate the Bayesian Future Forecast
return mod, forecast, samples, ymv_mod, mv_for, mv_samp, mv_y = bayes_forecast(dfv.iloc[:,2:4], dfv.Transactions)
我们将使用上面的 Python 函数来运行没有协变量的等效模型,即标准的单变量时间序列。我们这样做是为了确定在模型中包含独立变量是否具有减少模型中整体残差的预期效果。换句话说,包含变量是否提高了我们对数据的理解;值得将它们包含在模型中吗?
# Calculate Bayesian estimate for the univariate model
uv_mod, uv_for, uv_samp, uv_y = bayes_forecast(None, dfv.Transactions)
结果
下图显示了我们的分析结果。我们有许多观察结果。首先,该模型在学习序列的开始结构时经历了一段困难的时间,正如序列开始时的宽可信区间所证明的那样。最终,“学习”的模型参数和多变量模型的单步超前预测开始更紧密地遵循原始序列。这是我们所期望的。然而,请注意,单变量序列在捕捉原始序列的移动和值方面做得相当差。虽然它似乎了解趋势,但它的预测基本上始终偏离原始的相关值,尤其是在序列的后期。这告诉我们一些关于模型中额外协变量的功效——我们将在下一步讨论。

提前一步预测
上面的图显示了贝叶斯预测的输出。它显示了一步到位的预测,可信区间为 95%。这与产生样本内预测的 ARIMA 不同。
样本内 ARIMA 预测和 Pybats 预测的一个重要区别是:在 ARIMA,样本内预测实际上是没有用的。它们反映了估计的参数与数据的拟合程度,为此,你可以很容易地通过过度参数化你的模型来过度拟合数据;它没有告诉我们参数在看不见的数据上表现如何(更不用说参数是固定的)。对于 Pybats,这不是一个真正的“样本内”预测。这是一种一步到位的预测,从序列的开头开始,并在序列中移动时更新每个参数。因此,每一步实际上都是一个真正的“样本外预测”,因此预测误差反映了基于后验概率的真实样本外估计。为了让 ARIMA 做到这一点,您需要在序列的末尾指定一个保留样本,然后实现一个 For 循环,迭代保留样本中的每个数据点,更新模型,移动到下一个点,更新模型,等等。
贝叶斯:比较单变量和多变量
我们的多变量贝叶斯模型比单变量模型表现得更好吗?通过比较多变量和单变量预测中的累积绝对误差,我们可以更容易地观察到这种差异。下图比较了两个模型(单变量和多变量)之间的累积误差。它表明,随着时间的推移,协变量开始解释时间序列模型中更多的可变性——这是我们在模型根据以前的值学习和调整参数时所期望的。

比较单变量和多变量贝叶斯时间序列模型之间累积误差的图形
此外,我们可以检查每个模型的 MAPE(平均绝对百分比误差),并确定哪个模型在一步预测中更准确。在这种情况下,我们检查了前 12 个月的预测,并比较了 MAPE。对于多变量模型,我们实现了约 20%的 MAPE,而单变量模型实现了 54%的 MAPE。20%留下了很大的提升空间,但肯定比 54 强多了!多变量模型的 MAD(平均绝对偏差)约为 3,300,这意味着我们的汽车交易量估计值每月约有 3,300 辆的误差。
ARIMA
让我们看看 ARIMA 是如何处理我们的数据的。首先,我们需要在数据中创建一个训练/测试分割;在这里,我们将使用该系列的最后 12 个月作为一个坚持样本。
dfv_train = dfv[:-12]
dfv_test = dfv[-12:]
dfv_test
我们使用的是 pmdarima ,它是一个方便的包,围绕 SARIMAX 的 Statsmodels 实现构建了一个包装器。
mod = pmd.auto_arima(y=dfv_train.Transactions, exogenous=dfv_train.iloc[:,2:4], stepwise=True, m=12, seasonal=True)
y_pred = mod.predict_in_sample(exogenous=dfv_train.iloc[:,2:4], return_conf_int=True, alpha=0.05)
a_low = y_pred[1][:,0]
a_high = y_pred[1][:,1]
mod.summary()
我们的 SARIMX 输出(因为它是季节性的,有两个外生协变量)如下所示。这里有很多复杂性。首先,模型是不同的,我们在两个主要序列中观察到一个移动平均分量,并且在季节分量中,季节效应也是不同的。显然,数据不是静止的。我们的协变量都没有发现在模型中有统计学意义;根据 ARIMA 的说法,它们没有任何效果。这与贝叶斯模型观察到的结果不同。

在坚持 12 个月的样本中,ARIMA 模型的表现如何?不算太坏。我们观察到 MAPE 为 22%,贝叶斯模型在同样的 12 个月时间内 MAPE 为 20%。

未来预测
下一步是使用我们创建的模型预测未来。因为我们引入了额外的协变量,我们还需要预测(或以某种方式知道)这些协变量的未来值。实际上,从业者将需要使用他们领域的专业知识来生成对未来预测的可靠估计。在某些情况下,最好的方法可能是使用另一个模型来预测这些变量的未来值。然而,注意:从预测中产生预测是一个潜在的危险领域!出于本例的目的,我们使用单变量 BTS 模型(Pybats 仅使用单个变量)估计了每个协变量的 12 个月预测,并在预测目标系列时使用这些预测作为输入——与我们的更好判断相反。
下图显示了模型对未来 12 个月的预测。我也用同样的数据提供了可比较的 ARIMA 预测。请注意,ARIMA 预测明显高于贝叶斯模型的预测。随着每个月数据的到来,我们需要跟踪这些数据。考虑到交易的历史模式,如果 ARIMA 模型经常出错,而贝叶斯模型更准确,我不会感到惊讶。

结论
本文简要介绍了使用 Pybats 进行多元贝叶斯预测。这个工具非常强大,值得那些需要利用动态线性回归模型的能力进行准确预测的人去研究。贝叶斯方法大大弥补了 ARIMA 的不足,特别是在数据不足、存在多个变量以及需要理解模型中变量的相对重要性的情况下——这种方式比 ARIMA 提供的方式更加透明。
使用基于群组的模型进行预测
行业笔记
预测付费订阅时时间序列模型的替代方法

TLDR
提供订阅服务的公司(如 Wix、Spotify、Dropbox、Grammarly)可以使用时间序列模型预测其未来的付费订阅,如 ARIMA 或先知。这些模型针对包含按日期排序的订阅的时间序列数据进行训练。
一个有趣的替代方法是重新格式化数据,按照用户的注册日期和购买日期进行订阅,基本上将时间序列数据转换成表格数据。这使得应用回归模型成为可能,如 GLM 或 GBM,这通常会产生更好的预测,并提供关于用户群未来订阅归属的更多见解。这些模型被称为基于群组的模型。
什么是队列?
根据字典的定义,一群人是一群具有共同特征的人,通常年龄为。在我们的例子中,在给定日期注册的用户代表一个群体。例如,“2019–01–01群组”由 2019–01–01 注册的所有用户组成。同样,“2019 年的队列”包括 2019 年期间注册的所有用户。
在我们深入讨论之前,还有几个定义:
- 注册日期:用户注册的日期;
- 升级日期(购买日期):用户购买高级订阅的日期;
- 队列/用户的年龄 : 自注册之日起的天数;
- 溢价:付费订阅。用户首先注册,然后购买订阅,有时是在同一天,有时是在免费使用产品一段时间后。Wix、Spotify、Dropbox 等许多公司都有一种“免费增值”的商业模式,或者为他们的产品提供免费试用期。
下图显示了 2019 年 1 月 1 日登记的一个假设队列在登记后的前 30 天产生的保费数量。

图一。2019-01-01 登记日期群组按升级日期和年龄划分的保费。(图片作者)
群体行为(几乎)相似
通常,群体的行为是相似的。当按升级日期绘制不同注册日期的多个队列的保费时,我们可以观察到它们具有相似的形状。

图二。按升级日期 —前 30 天划分的不同注册日期的群组。(图片由作者提供)
当我们用年龄而不是日期来划分相同的人群时,这种相似性就更加明显了。

图 3。按年龄 —前 30 天划分的不同注册日期的队列。(图片由作者提供)
同样,如果我们按年龄划分相同的队列,但现在是注册后的 365 天,我们可以观察到一些长尾,这意味着队列在注册后很久才产生保费。

图 4。按年龄——前 365 天划分的不同注册日期的队列。(图片由作者提供)
在上图中可以观察到一些重要的特征:
- 注册后的头几天会产生更多的保费;
- 随着新用户“变老”,他们购买保费的速度正在迅速下降。这种下降以非常非线性的方式出现,类似于幂律关系;
- 大量订阅是在用户注册后很久才被购买的——“长尾”。
按群组预测保费
假设今天是 2020 年 1 月 1 日,我们想预测未来 90 天的新保费。最终,保费将来自现有的群组(到今天为止注册的用户)和未来的群组(从明天开始的季度中注册的用户)。****
最近的队列
首先,让我们将过去 365 天内注册的所有现有群组称为最近的。
这里 365 天的门槛是任意选择的。对于一些公司来说,根据尾部的不同,最近一批是在过去 90 天内注册的,对于其他公司来说,可能是 2 年。这个想法是将现有的组群分为新的和旧的,并应用不同的预测模型。我们稍后将回到这一点。
绘制最近的群组时,它们可能如下图所示。我们的任务是预测今天以后的日期,用红色标记。红色标记右边的线条对我们来说是未知的。这就是我们想要预测的。

图 5。最近的一群人。(图片由作者提供)
预测最近几个群体产生的保费意味着将这些群体的“尾部”外推至未来。例如,正如您在下图中看到的,对于 2019 年 12 月 15 日登记的现有群组,我们必须用红色虚线来猜测真正的灰色线,这是我们未知的,但希望可以从旧群组中了解到。现有的近期组群也是最容易预测的,因为我们对它们了解更多,最重要的是,我们知道它们的规模,我们知道它们的初始动态。

图 6。最近一批人截至今天的实际保费,然后是实际保费和之后的预测保费。(图片由作者提供)
未来的队列
我们还必须对今天之后出生的未来人群进行估计。这些在下图中用蓝色标出。我们不太了解未来的群体,也许除了在接下来的 90 天里我们每天都会有一个新的群体。明天出生的群体将有 90 天产生保费,而在预测期最后一天登记的群体将只有一天产生保费。希望这些群体与过去的群体具有相同的特征,绘制蓝色形状更接近于数据科学,而不是绘画。

图 7。近期和未来的队列。(图片由作者提供)
老同学
除非我们的产品(或公司)还不到一年(我们为最近选择的阈值),否则我们最终也会拥有的老团队。这些是现有的组群,在最近的组群之前和预测期开始之前很久就登记了。让我们将它们也添加到情节中,并用橙色标记它们。它们表现为许多略高于零的重叠线条。可以有很多。例如,如果产品的历史从 2010 年开始,将有大约 3,285 个队列行(9 年* 365 个注册日期)。尽管数量很少,但老团队产生的总保费可能占总收入的很大一部分。

图 8。旧的、最近的和未来的队列。(图片由作者提供)
现在,让我们按升级日期汇总所有群组,并绘制它们的总数。如下图所示,这是一些看起来不错的时间序列。这里要做一些观察:
- 最近一批人的保费随着时间而下降(记住幂律随年龄衰减)。
- 未来群体在未来保费总额中所占比例更大。
- 老年群体可能占总数的很大一部分。

图 9。按旧的、最近的和未来的群组划分的总保费。(图片由作者提供)
让我们更进一步,总结所有三个部分:旧的、最近的和未来的。这将得到我们的目标总保费的时间序列。也就是下图中的黑色粗线。

图 10。按旧的、最近的和未来的群组列出的保险费总额。(图片由作者提供)
上述技术正是我们用来预测保费的。我们将群组分为旧群组、新群组和未来群组。对于每一部分,我们应用一个独立的回归模型。我们这样做是因为这些模型在分布和可用特性方面是不同的。这些模型中的每一个都预测了许多队列(注册日期)的保费。对于每个群组,它预测未来许多升级日期的保费。然后,我们按升级日期汇总每个模型的预测,以获得每个部分的时间序列:旧的、最近的和未来的。最后,我们将所有三部分加在一起,得出升级日期的总保费。这实际上是时间序列模型将带给我们的——未来日期的溢价。基于群组的方法以更复杂的方式做到了这一点。就预测的准确性和对用户的额外了解而言,这有其优势。
总之,我们刚刚证明,使用基于群组的方法,我们将预测的时间序列任务转化为回归任务。
预测目标的时间序列属性
总计的时间序列有一些有趣的属性需要我们建模:
- 季节性(每周、每年)
- 节假日(如圣诞节、独立日、复活节)
- 特殊活动期间的销售高峰(如黑色星期五,网络星期一)

图 11。时间序列属性:季节性,节假日。(图片由作者提供)
当然,当缩小一点时,我们可能会发现我们的模型中也需要包含趋势(见下图)。

图 12。时间序列属性:趋势。(图片由作者提供)
基于群组预测的回归模型
在我们进一步讨论之前,让我们回忆一下通常的时间序列方法。我们有一个目标,我们希望以时间序列的形式按日期进行预测。时间序列是日期-值对的序列。我们也可以将外生变量添加到模型中。数据可能如下表所示。

表 1。时间序列数据。(图片由作者提供)
通常使用的候选模型有 Prophet、Holt-Winters、SARIMAX、LSTM、X11、SEATS 等。
相比之下,群组模型的数据具有双重关键,因为我们通过注册日期和升级日期来表示目标。每个群组(注册日期)有许多升级日期。这是注册日期和升级日期之间的笛卡尔乘积。对于这些关键字,我们可以加入各种特征,如年龄、事件、假期、季节性条款等。一些将通过升级日期(例如假期)连接,其他将通过注册日期(例如群组的大小)连接,或者甚至通过两个关键字连接,例如,年龄特征被计算为升级和注册之间的差异。最终,这个表格数据比时间序列数据有更多的列和更多的行。

表二。队列数据。(图片由作者提供)
美妙的是,对于这种类型的数据,我们可以应用任何回归模型。我们来考虑几个。
广义线性模型(GLM)
优点:可解释性&简单性;2)当包括时间作为特征时趋势的外推;3)支持来自指数族的非正态分布(泊松、伽马、特威迪)。
缺点 : 1)手动特征工程(好用:非线性的样条,交互的张量积);2)很少有 python 包具备所有的分布和正则化;3)对分布和链接功能的选择敏感。
广义线性模型是一种线性模型,允许目标具有非正态误差分布。GLM 允许通过连接函数对特征和目标之间的非线性关系进行建模。例如,我们可以假设目标的条件均值遵循泊松分布,并使用对数函数。该公式可能如下所示:

(图片由作者提供)
在 Python 中,至少有两个好的 GLMs 库:[statsmodels](https://www.statsmodels.org/stable/generated/statsmodels.genmod.generalized_linear_model.GLM.html)和[scikit-learn](https://scikit-learn.org/stable/modules/linear_model.html#generalized-linear-regression)。在 R 中有著名的[mgcv](https://cran.r-project.org/web/packages/mgcv/index.html)包和来自 stats 的[glm](https://stat.ethz.ch/R-manual/R-devel/library/stats/html/glm.html)方法。参见下面一个使用statsmodels的代码存根。
GLM 的代码示例(来源:作者的 Github
梯度增压机(GBM)
优点: 1) 通过设计处理非线性和交互;2)不需要或很少需要特征工程;3)支持来自指数族的非正态分布(泊松、伽马、特威迪);4)对分布的选择不太敏感;5)许多好的库可供选择(例如 LightGBM、XGBoost、CatBoost);
缺点 : 1)不能根据看不见的数据进行推断,例如不能推断趋势;
梯度增强机器是强大的模型,在我们的情况下表现良好,特别是如果数据没有趋势或只有微弱的趋势。在我们的例子中,这是 GBM 的唯一缺点:它不能根据看不见的数据进行推断,这意味着它也不能推断趋势。预测时间越长,最终误差越大。
GBM 有几个不错的库: LightGBM , XGBoost , CatBoost 。请参见下面的lightgbm代码存根。
GBM 的代码示例(来源:作者的 Github
几条重要建议
选择正确的发行版
这在 GLMs 的情况下尤其重要。目标通常非常不正常,有严重的右倾斜。该分布通常属于指数族。它可以是泊松、伽马或更一般的 Tweedie(方差幂在 1 和 2 之间)。通过验证来尝试它们中的每一个。作为证明,在下图中,即使在对数变换之后,目标仍然高度倾斜。仅仅用对数变换或 Box-Cox 对目标进行归一化并假设正态性是不够的。

图 13。目标的分布:原始的和转化的。(图片由作者提供)
随年龄非线性衰减的工程特征
通常,“年龄”是最重要的特征,因为它描述了保费的非线性衰减——变异的主要来源。如下图所示,在 log(保费)和 log(年龄)之间有一个近似线性的关系,暗示了原始值之间的幂律关系。

图 14。log(保费)和 log(年龄)之间几乎呈线性关系,证实了原始值之间的幂律关系。(图片由作者提供)
这种非线性只能通过“年龄”这一原始特征的转换引入到线性模型中。这对于 GLMs 也是特别重要的。GBMs 将自动处理这种非线性,年龄的转换不一定有帮助。
在 GLMs 的情况下,如果对数变换是不够的(通常是不够的),我会推荐使用 B 样条。有时甚至更好,如果你考虑一个通用加法模型 (GAM)模型(因为样条是算法的一部分)。在下图中,我们有一组彩色的 B 样条曲线,它们加在一起形成红色的粗线,并适当地近似非线性衰减。

图 15。用 B 样条对非线性衰减建模。(图片由作者提供)
有几个 Python 库提供了 B 样条:statsmodels、scikit-learn、patsy、pygam。样条作为一组替换原始年龄的要素添加到线性模型中。每个样条特征都有一个系数,因此它们的总和形成了一个好看的形状,就像上图中的红线一样。应该通过在拟合时施加惩罚来控制摆动。在 GAM 模型中,也有可能对衍生品施加惩罚。看看下面我们如何用statsmodels构造一组 B 样条曲线。
B 样条的代码示例(来源:作者的 Github
在旧群体和新群体之间选择正确的界限
在本文中,我们选择旧队列和新队列之间的截止年龄为 365 天。该阈值应被视为需要校准的超参数。一个很好的经验法则是从按年龄划分多个现有群组开始。你会得到一个类似下图的图片。

图 16。在旧年龄和最近年龄之间选择截止年龄。(图片由作者提供)
我们希望找到保费对年龄的依赖性消失并变得恒定的点。从该值开始,然后通过网格搜索向左和向右移动,找到确保旧群组和最近群组之间最佳分离的阈值。最佳分离是确保聚合模型(旧模型+最近模型+未来模型)的最低 MAPE 的分离。这很重要,因为我们将不同的模型应用于新的和旧的队列。较高的截止年龄将指定更多的组群为近期组群,较少的组群为老年组群。换句话说,当我们增加阈值时,最近模型在聚集模型中的权重将增加。
使用时间序列模型预测旧队列
继续前面的建议,有些情况下最好使用时间序列模型来预测旧群组。发生这种情况有两个原因:
- 通过注册日期加入的与群组相关的特征对于模型变得无关紧要。例如,年龄变得无关紧要(记住平坦的尾部),群组大小(注册用户的数量)等其他特征也变得不必要,可以在不损失预测精度的情况下删除。
- 旧群组有很长的历史,数据量变得太大而无法处理。假设我们有 10 年的历史。最近的队列需要一年的时间,而旧的模型需要 9 年。最终,旧表将有大约 5,397,255 行(9 年* 365 个注册日期,每个日期平均有 1,643 个升级日期,算术和—第一个注册日期有 9*365 个升级日期,而最后一个注册日期只有一个升级日期)。
使用滚动向前验证
即使我们处理表格数据,我们也必须尊重数据的时序性质。我们必须避免前瞻偏见,这意味着我们必须始终根据过去进行训练,并预测未来。一个好的验证方法是在升级日期之前执行滚动的前推验证。下图说明了这种技术。

图 17。按升级日期滚动向前验证。(图片由作者提供)
综合数据
通常情况下,你不会发现一个特定公司的高级订阅的历史数据。这是财务数据,意味着它是敏感的,不会公开。这也是为什么你不会找到太多关于如何预测高级订阅的文章的原因。对于本文中的所有数据,我都使用了我自己生成的合成数据,这些数据模拟了我在Wix.com处理公司数据时观察到的主要特性。你可以用这个 Python 脚本生成同样的合成数据。
特别感谢我的同事Nicolas Marcille,他最初在Wix.com开始群组模型的工作。
使用机器学习模型进行预测
行业笔记
mlforecast 通过机器学习快速轻松地进行预测
乘尼克斯队 。 费德·加尔萨·拉米雷斯 ,马克斯·梅根塔尔
TL;博士:我们介绍了 mlforecast,这是一个来自 Nixtla 的开源框架,它使得在时间序列预测任务中使用机器学习模型变得快速而简单。它允许您关注模型和特性,而不是实现细节。使用 mlforecast,您可以以更轻松的方式进行实验,它具有内置的回溯测试功能,可以帮助您找到性能最佳的模型。
您可以在自己的基础设施中使用 mlforecast,或者使用我们的完全托管解决方案。只需给我们发邮件到 federico@nixtla.io 来测试私有测试版。
虽然这个例子只包含了一个时间序列,但是这个框架能够处理成千上万的时间序列,并且在时间和内存上都非常有效。
介绍
我们在 Nixtla,正试图让时间序列预测更容易被每个人接受。在本帖中,我们将讨论在预测任务中使用机器学习模型。我们将用一个例子来说明主要挑战是什么,然后我们将介绍 mlforecast ,这是一个有助于在预测中使用机器学习模型的框架。 mlforecast 为您进行特性工程并负责更新,用户只需提供一个遵循 scikit-learn API(实现拟合和预测)的回归变量,并指定她想要使用的特性。这些功能可以是滞后、基于滞后的转换和日期功能。(如需进一步创建功能或自动预测管道,请检查 nixtla 。)
动机
许多年来,像 ARIMA 和 ETS 这样的经典方法统治了预测领域。其中一个原因是,大多数用例涉及以月、季度或年为粒度预测低频序列。此外,没有很多时间序列数据集,因此为每个数据集拟合一个模型并从中获得预测是很简单的。
然而,近年来,对更大数据集、更高频率的预测需求有所上升。更大和更高频率的时间序列对传统的预测方法提出了挑战。这些方法并不意味着对许多时间序列一起建模,它们的实现是次优的和缓慢的(你必须训练许多模型),此外,序列之间可能有一些共同或共享的模式,可以通过对它们一起建模来学习。
为了解决这个问题,已经有各种努力来提出不同的方法,这些方法可以在许多时间序列上训练单个模型。一些有趣的深度学习架构已经被设计出来,可以准确地预测许多时间序列,如 ESRNN,DeepAR,NBEATS 等。(检查 nixtlats 和为我们的 WIP 复制 ESRNN 结果。)
像梯度提升树这样的传统机器学习模型也已经被使用,并且已经表明它们也可以实现非常好的性能。但是,将这些模型与基于滞后的要素结合使用并不简单,因为您必须在每个时间步长中更新要素才能计算预测。此外,根据您的预测范围和您使用的滞后时间,在某个时间点,您会用完系列的实际值来更新您的要素,因此您必须采取措施来填补这些缺口。一种可能的方法是使用您的预测作为序列的值,并使用它们更新您的要素。这正是 mlforecast 为你做的。
例子
在下一节中,我们将展示一个非常简单的单序列示例,以强调在预测任务中使用机器学习模型的困难。这将在以后激发对 mlforecast 的使用,这是一个使整个过程更加容易和快速的库。
图书馆
数据

作者图片
我们的数据具有每日季节性,正如您在创建中看到的,它基本上只是 dayofweek + Uniform({-1,0,1})。
培养
假设我们想要未来 14 天的预测,第一步将是决定使用哪个模型和特性,因此我们将创建一个包含数据中最后 14 天的验证集。
作为起点,我们将尝试滞后 7 和滞后 14。

作者图片
我们可以看到滞后和目标之间的预期关系。例如,当 lag-7 为 2 时, y 可以是 0、1、2、3 或 4。这是因为一周中的每一天都可以有值[day-1,day,day + 1],所以当我们处于一周中的第 2 天时,我们可以得到值 1、2 或 3。然而,值 2 可以来自第 1 周的某一天,其最小值为 0,也可以来自第 3 周的某一天,其最大值为 4。
计算滞后值会使一些行为空。

作者图片
我们会在训练前放下这些。
为了简单起见,我们将训练一个没有截距的线性回归。因为最好的模型是取一周中每一天的平均值,我们期望得到接近 0.5 的系数。

作者图片
这个模型取的是 0.51 * lag_7 + 0.45 * lag_14。
预测
太好了。我们有训练有素的模特。我们如何计算未来 14 天的天气预报?机器学习对特征矩阵 X 建模,输出预测值 y 。因此,我们需要为接下来的 14 天创建特征矩阵 X ,并将其交给我们的模型。
如果我们想得到第二天的 lag-7 ,按照训练集,我们可以得到从末尾开始的第 7 个位置的值。训练集结束后两天的 lag-7 将是从末尾开始的第 6 个位置的值,依此类推。对于 lag-14 也是如此。

作者图片

作者图片
您可能已经注意到,我们只能从历史记录中获得 7 个 lag-7 值,而我们可以获得所有 14 个 lag-14 值。有了这些信息,我们只能预测接下来的 7 天,所以我们只取滞后-14 的前 7 个值。

作者图片
有了这些功能,我们可以计算未来 7 天的天气预报。

作者图片
这些值可以解释为最后一次训练日期后接下来 7 天的系列值。为了计算该日期之后的预测,我们可以使用这些值,就像它们是我们系列的值一样,并将它们用作后续期间的 lag-7 。
换句话说,我们可以用这些值和 lag-14 的真实值填充特征矩阵的其余部分。

作者图片
如你所见,我们仍在使用 lag-14 的真实值,并且我们插入了我们的预测值作为 lag-7 的值。我们现在可以使用这些特征来预测剩余的 7 天。

作者图片
现在我们有了未来 14 天的预测!这并不痛苦,但也不漂亮或容易。我们刚刚使用了滞后,这是我们可以拥有的最简单的功能。
如果我们使用了 lag-1 会怎么样?我们需要做这个预测更新步骤 14 次!
如果我们有更精细的特征,比如在一段时间内的滚动平均值,会怎么样呢?正如你可以想象的那样,它会变得相当混乱,而且很容易出错。
ml 预测
带着这些问题,我们创建了 mlforecast ,这是一个帮助你使用机器学习模型预测时间序列的框架。它为你处理所有这些混乱的细节。你只需要给它一个模型,并定义你想要使用的功能,让 mlforecast 做剩下的事情。
mlforecast 在 PyPI ( pip install mlforecast)以及 conda-forge ( conda install -c conda-forge mlforecast)中均有。
使用 mlforecast 和以下代码可以解决之前描述的问题。
首先,我们必须按照要求的格式设置数据。

作者图片
这是必需的输入格式。
- 一个名为 unique_id 的索引,用于标识每个时间序列。在这种情况下,我们只有一个,但是你想要多少就有多少。
- 带有日期的 ds 栏。
- 带有值的 y 列。
现在我们将导入时间序列转换器,在这里我们定义我们想要使用的特性。我们还将导入预测类,它将保存我们的转换器和模型,并将为我们运行预测管道。
我们初始化我们的转换器,指定我们想要使用的滞后。

作者图片
如你所见,该变压器将使用滞后-7 和滞后-14 作为特征。现在我们定义我们的模型。
我们用模型和时序转换器创建一个预测对象,并使其适合我们的数据。
现在,我们只需调用我们想要的预测范围的预测。

作者图片
这要容易得多,在内部,这与我们以前做的一样。让我们快速验证一下。
检查我们是否得到了相同的预测:
检查我们是否有相同的型号:
实验变得更容易
有了这种高层次的抽象,我们就可以专注于定义最好的特性和模型,而不是担心实现细节。例如,我们可以通过编写一个利用 mlforecast 的简单函数来非常容易地尝试不同的滞后:

作者图片

作者图片

作者图片
回溯测试
在前面的例子中,我们手动分割数据。预测对象也有一个回溯测试方法可以为我们做到这一点。
我们将首先把所有的数据转换成所需的格式。

作者图片
现在我们像以前一样实例化一个Forecast对象,并调用backtest方法。
这将返回一个生成器,其中包含每个窗口的结果。

作者图片

作者图片

作者图片
result2这里和我们手动做的评估一样。
我们可以使用几个窗口为不同的滞后定义一个验证方案。

作者图片

作者图片

作者图片

作者图片

作者图片

作者图片
滞后转换
我们可以指定滞后上的转换,也可以只指定滞后。 window_ops 库有一些不同窗口函数的实现。您也可以定义自己的转换。
让我们试试季节性滚动平均值,这是过去n个季节的平均值,在这种情况下,它将是过去n周一、周二等的平均值。计算这个特性的更新可能会有点烦人,但是,使用这个框架,我们可以把它传递给 lag_transforms 。如果转换需要额外的参数(除了序列的值之外),我们指定一个类似于(transform_function, arg1, arg2)的元组,在本例中是season_length和window_size。
help(seasonal_rolling_mean)Help on CPUDispatcher in module window_ops.rolling:
seasonal_rolling_mean(input_array: numpy.ndarray, season_length: int, window_size: int, min_samples: Union[int, NoneType] = None) -> numpy.ndarray
Compute the seasonal_rolling_mean over the last non-na window_size samples of the
input array starting at min_samples.
lag_transforms 获取一个字典,其中键是我们想要应用转换的 lag,值是转换本身。

作者图片

作者图片
日期功能
您还可以指定要计算的日期特性,这些特性是 ds 列的属性,并且也在每个时间步长中更新。在本例中,最好的模型是取一周中每一天的平均值,这可以通过对一周中的某一天列进行一次性编码并拟合线性模型来实现。

作者图片

作者图片
后续步骤
mlforecast 拥有更多类似分布式训练和 CLI 的特性。如果您感兴趣,可以从以下资源中了解更多信息:
- GitHub 回购:https://github.com/Nixtla/mlforecast
- 文档:https://nixtla.github.io/mlforecast/
- 在 https://www.kaggle.com/lemuz90/m5-mlforecast 的 M5 竞赛中使用 mlforecast 的示例:
雪花中的预测:用 SQL 运行云上的脸书预言家
通过创建一个雪花外部函数,我们可以得到脸书预言家对任何时间序列的预测。了解如何轻松地将这些预测集成到您的 SQL 管道中 Snowflake 连接到在 Google Cloud Run 内的 Docker 容器上运行的 Prophet。

图片: Pixabay
2022–09 更新
脸书先知现在运行在雪花内部,不需要外部函数。
https://hoffa.medium.com/facebook-prophet-forecasts-running-in-snowflake-with-snowpark-14fc870b56ae
目标
这篇文章的目标是构建一个可以在 Snowflake 中用来预测时间序列的函数。一个很棒的开源工具是脸书先知,我们只需要一种在我们的雪花环境中使用它的方法。这很容易,因为雪花能够运行外部函数——因此我们只需要托管 Prophet 的一个实例,并添加必要的管道,以在雪花中完成prophetize(timeseries)函数。
先来个演示,雪花里任何时间序列都行:比如纽瓦克机场 2018 年以来纽约市周边的气温:
select date, temp
from noaa_gsod
where country_fips='US'
and station = 'NEWARK LIBERTY INTERNATIONAL AP';-- TODO: Show how to get NOAA GSOD from Knoema in a future post.

纽瓦克机场的每日温度
然后我们可以调用我们的函数prophetize()(见下面如何创建它),将之前的时间序列聚合到一个包含日期和值的数组中:
select prophetize(array_construct(
array_agg(temp::float)
within group(order by date)
, array_agg(date::date)
within group(order by date))::string) str
from table(result_scan(last_query_id(-1)));
仅此而已。我们得到的是一个带有预测的数组。可视化这些结果的一个简单方法是将前面两个查询的值结合起来:
select date, temp::float avg_temp
, 0 forecast, 0 fore_min, 0 fore_max
from table(result_scan(last_query_id(-2)))
union all
select x.value[0]::date, 0, x.value[1]::int forecast, x.value[2]::int fore_min, x.value[3]::int fore_max
from table(result_scan(last_query_id(-1))) a, table(flatten(a.$1)) x;

纽瓦克机场的每日温度,加上未来 365 天的预报波段。
上面有趣的笔记:
- Prophet 能够轻松检测季节模式并预测未来值。
- Prophet 的许多工作方式都是可调的,但是开箱即用也是可行的。
- 在雪花上,我使用了
last_query_id(-1)和last_query_id(-2)来组合前面两个查询的结果。这是一个很棒的功能。
现在让我们检查一下如何将雪花 SQL 世界prophetize()中的一个函数连接到运行在 Cloud Run 上的脸书先知的细节。
如何
将 Prophet 部署到云运行的容器上
构建这个容器的requirements.txt非常简单:
flask==1.1.4
requests==2.25.1
gunicorn==20.1.0
pandas==1.2.4
pystan==2.19.1.1 # <3.0
fbprophet==0.7.1
正如Dockerfile:
FROM python:3.8# Allow statements and log messages to immediately appear in the Cloud Run logs
ENV PYTHONUNBUFFERED TrueCOPY requirements.txt .
RUN pip install -r requirements.txtENV APP_HOME /app
WORKDIR $APP_HOME
COPY main.py ./CMD exec gunicorn --bind :$PORT --workers 1 --threads 1 --timeout 0 main:app
这是main.py,一个基本的 web 服务器,它将传入的数组解析成一个数据帧,Prophet 用它来预测任意数量的周期。然后,它返回一个序列化数组,其中包含雪花将收到的预测和不确定性间隔:
import json
import logging
import osfrom fbprophet import Prophet
from flask import Flask, request
import pandas as pdlog = logging.getLogger()
app = Flask(__name__)def forecast(df: pd.DataFrame, periods=365) -> pd.DataFrame:
df["ds"] = pd.to_datetime(df["ds"]) model = Prophet()
model.fit(df) future_df = model.make_future_dataframe(
periods=periods, include_history=False) return model.predict(future_df)[["ds", "yhat", "yhat_lower", "yhat_upper"]][@app](http://twitter.com/app).route("/", methods=["POST"])
def index():
payload = request.get_json()
logging.info(payload)
# [https://docs.snowflake.com/en/sql-reference/external-functions-data-format.html](https://docs.snowflake.com/en/sql-reference/external-functions-data-format.html) rows = payload["data"]
return_value = []
for row in rows:
row_number = row[0]
function_input = json.loads(row[1])
df = pd.DataFrame({'ds': function_input[1], 'y': function_input[0]})
fc = forecast(df)
fc['ds'] = fc['ds'].dt.strftime('%Y-%m-%d')
row_to_return = [row_number, fc.to_numpy().tolist()]
return_value.append(row_to_return) json_compatible_string_to_return = json.dumps({"data": return_value})
return (json_compatible_string_to_return)if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
如果我们想在 Google Cloud run 上构建和运行这个容器,我们需要运行:
gcloud builds submit --config cloudbuild.yaml;
gcloud run deploy --image gcr.io/fhoffa/prophetize --platform managed
第一次在云构建上构建映像很慢,因为编译 Prophet 需要时间——但这个cloudbuild.yaml在以后的构建中使用映像缓存使它变得很快:
steps:
- name: 'gcr.io/cloud-builders/docker'
entrypoint: 'bash'
args:
- '-c'
- |
docker pull gcr.io/fhoffa/prophetize:latest || exit 0- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'--cache-from', 'gcr.io/fhoffa/prophetize:latest',
'-t', 'gcr.io/fhoffa/prophetize:latest',
'.'
]images: ['gcr.io/fhoffa/prophetize:latest']
云运行在 Google API 网关之后
我在这个项目背后的主要目标之一是庆祝 Snowflake 现在支持 GCP 的外部功能。因此我选择部署在云上运行。
现在,要通过 GCP 运行外部函数,我们需要建立一个从 Snowflake 到 Google API Gateway,以及从 API Gateway 到 Cloud Run 的连接。
首先,我们需要一个用于 API Gateway 的gateway.yaml,让它知道它将充当我们在 Cloud Run 上部署的服务的代理:
swagger: '2.0'
info:
title: API Gateway config for Snowflake external function.
description: This configuration file connects the API Gateway resource to the remote service (Cloud Run).
version: 1.0.0
schemes:
- https
produces:
- application/json
paths:
/test:
post:
summary: Prophetize
operationId: prophetize
x-google-backend:
address: [https://prophetize-zqnzinxyeq-wl.a.run.app/](https://prophetize-zqnzinxyeq-wl.a.run.app/)
protocol: h2
responses:
'200':
description: <DESCRIPTION>
schema:
type: string
然后你可以按照 GCP 的文档用这个配置创建一个 API 网关。哦,请确保用您自己的服务 URL 替换上面的值。
雪花到谷歌 API 网关
这是我如何连接雪花上的点,以创建与 API Gateway 的集成:
use role accountadmin;
use schema temp.public;create or replace api integration prophet_test
api_provider = google_api_gateway
google_audience = 'test1-3s4aecfho43ih.apigateway.fhoffa.cloud.goog'
api_allowed_prefixes = ('[https://prophetize-4r3ddv95.wl.gateway.dev'](https://prophetize-4r3ddv95.wl.gateway.dev'))
enabled = true;
describe integration prophet_test;
create or replace external function prophetize(x string)
returns variant
-- IMMUTABLE
api_integration = prophet_test
as '[https://prophetize-4r3ddv95.wl.gateway.dev/test'](https://prophetize-4r3ddv95.wl.gateway.dev/test') ;
grant usage on function prophetize(string) to role sysadmin;
这就是你所需要的,现在你可以像在 Snowflake 中的任何其他查询一样调用刚刚生成的prophetize():
select prophetize('[[41,43,62,43],["2019-12-30","2020-01-06","2020-01-13","2020-01-20"]]');
其结果如下:
[
[
"2020-01-21",
51.3641167654911,
40.85673826625397,
61.745184538148166
],
[
"2020-01-22",
51.72223221323965,
41.87259513681375,
61.29144225035811
],
[
"2020-01-23",
52.0803476609882,
41.66374622035821,
61.55883149200517
], [...]
]
保护流量
你可能已经注意到了上面我的配置中的许多 URLs 现在你已经看到了它们,你可能想开始从你的帐户调用我的函数。那很好,但我更想保护他们。
雪花使这变得容易。创建上述集成后,将自动提供 GCP 的服务帐户。您可以用describe integration prophet_test获取它的值,然后使用该服务帐户更新gateway.yaml,这样其他人就不能调用它了:
swagger: '2.0'
info:
title: API Gateway config for Snowflake external function.
description: This configuration file connects the API Gateway resource to the remote service (Cloud Function).
version: 1.0.0
securityDefinitions:
snowflakeAccess01:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "ftyqmxcfyo@sfc-prod2-1-947.iam.gserviceaccount.com"
x-google-jwks_uri: "[https://www.googleapis.com/robot/v1/metadata/x509/](https://www.googleapis.com/robot/v1/metadata/x509/)ftyqmxcfyo@sfc-prod2-1-947.iam.gserviceaccount.com"
schemes:
- https
produces:
- application/json
paths:
/test:
post:
summary: Prophetize.
operationId: prophetize
security:
- snowflakeAccess01: []
x-google-backend:
address: [https://prophetize-zqnzinxyeq-wl.a.run.app/](https://prophetize-zqnzinxyeq-wl.a.run.app/)
protocol: h2
responses:
'200':
description: <DESCRIPTION>
schema:
type: string
然后按照这些雪花文档,用上面的安全配置更新您的 GCP API 网关。
请注意,这个 GCP 服务帐户是由雪花提供的,无论您使用什么云来托管您的雪花帐户。在这种情况下,我在 AWS 上的雪花上运行了整个演示,它能够毫不费力地调用 GCP 服务。
同时,在云运行中,确保停止允许未经验证的调用。这样,只有通过 API 网关授权的呼叫才能得到服务:

停止允许云运行上未经身份验证的调用。
了解更多信息
脸书预言家是一款多功能工具,拥有许多调节杠杆和方法:
Prophet 是一种基于加法模型预测时间序列数据的过程,在该模型中,非线性趋势与每年、每周和每天的季节性以及假日影响相适应。它最适用于具有强烈季节效应的时间序列和几个季节的历史数据。Prophet 对缺失数据和趋势变化非常稳健,通常能够很好地处理异常值。
阅读更多信息,请访问:
- 预测云成本的七个技巧(与 FB 的预言家一起)来自 Gad Benram 。
- 使用 Google Cloud Run、Pub/Sub、云存储和 Terraform 构建无服务器、容器化的批量预测模型 Sebastian Telsemeyer 。
- 云运行成本和特性,由 Ahmet Alp Balkan
后续步骤
- 用一个雪花免费试用账户试试吧——你只需要一个电子邮件地址就可以开始了。
- 我将用所有这些文件建立一个 GitHub 项目(完成后在这里更新)
玩弄先知:比特币预测
Knoema 已经对雪花市场中的多个加密硬币进行了估值,因此使用 Prophet 构建时间序列预测非常简单:
-- define the time series
select "Value" value, "Date" date
from KNOEMA_FINANCE_DATA_ATLAS.FINANCE.CMCCD2019
where "Cryptocurrency Name" = 'Bitcoin (btc)'
and "Measure" = 'PriceUSD'
and date > '2017-01-01'
order by "Date";-- prophetize
select prophetize(array_construct(
array_agg(value::float) within group(order by date)
, array_agg(date::date) within group(order by date))::string) str
from table(result_scan(last_query_id(-1)));-- prepare the viz
select date, value, 0 forecast, 0 fore_min, 0 fore_max
from table(result_scan(last_query_id(-2)))
union all
select x.value[0]::date, 0, x.value[1]::int forecast, x.value[2]::int fore_min, x.value[3]::int fore_max
from table(result_scan(last_query_id(-1))) a, table(flatten(a.$1)) x;

预言家对比特币价格的预测——用来自 Knoema 的数据在雪花上运行
你和 Prophet 玩得越多,你就越会发现预测在很大程度上取决于你给它输入什么值,以及你如何调整它。在这种情况下,根据我对时间序列使用的起始日期,预测会有很大不同——从 2016 年开始意味着 Prophet 将观察到一个更复杂的模式,从 2018 年开始向它提供数据,以此类推。
对我来说最好的部分?我可以在不离开舒适的雪花 SQL web UI 的情况下完成这一切:

在 Snowsight(雪花的网络用户界面)中可视化预测
想要更多吗?
我是 Felipe Hoffa,雪花的数据云倡导者。谢谢你和我一起冒险。你可以在 Twitter 和 LinkedIn 关注我,查看【reddit.com/r/snowflake】的了解最有趣的雪花新闻。
https://github.com/Snowflake-Labs/awesome-snowflake https://medium.com/snowflake/knoema-datasets-and-the-snowflake-data-marketplace-challenge-95ff0d7ac6eb
忘记手推车问题;现实世界中务实而公平的人工智能
公平和偏见
深思熟虑地(共同)设计人工智能系统可以在现实世界中发挥作用
《T2》中的人工智能末日场景,是由《T4》【过滤泡沫】 (2011)和数学毁灭武器 (2016)等书籍点燃的,正慢慢被对人工智能更加务实和细致入微的观点所取代。我们承认我们控制着人工智能并且能够以反映我们选择的价值观的方式设计它们的视图。

由 Med Badr Chemmaoui 在 Unsplash 上拍摄的照片
这种转变可以从计算机科学家越来越多的参与中看出,例如,通过诸如The Ethical Algorithm(2019)或 Understand,Manage,and Prevent Algorithm reliate Bias(2019)等书籍,这些书籍描述并承认算法公平性的挑战和复杂性,但同时为更公平和更道德的算法提供了具体的方法和工具。这种转变也可以从这些书中描述的方法已经进入所有主要云提供商的产品中看出,例如,在 FAccT 2021 教程“工业中负责任的人工智能:实践中吸取的教训”微软、谷歌和亚马逊向 FAccT 社区的多学科观众展示了他们公平的人工智能解决方案。
信息很明确:我们能够(也应该!)实现算法的公平性。
为了做到这一点,我们不需要在允许自动驾驶汽车上路之前首先“解决”电车问题,我们不需要从根本上消除不公正,或者完全摆脱偏见,然后我们才能建立有用和公平的人工智能工具。我们现在可以跳过哲学和理论上的“纸上”问题,专注于设计和构建实用的现实世界的解决方案。
事实证明,我们对人工智能有很多控制,而不是解决假设的问题,深思熟虑地(共同)设计人工智能系统可以在现实世界中产生影响。我用 fair AI 在雇佣招聘,价值驱动的新闻推荐来举例说明。
⚖️人才招聘会
在我们深入研究最常被引用(但在我的经验中并不经常实践)的负责任的人工智能和算法公平需求的“海报儿童”:雇佣和招聘领域之前——一个小小的提醒,由彭等人(2019)的下图进行了有益的说明:
偏见无处不在!

混合招聘系统的高级示意图。转载自所见即所得?彭等人(2019)的《代表标准对雇用中的人为偏见的影响》。
在人类中…
1999 年, Steinpreis 等人对人类雇佣偏见进行了原型研究。他们的方法很简单:收集简历,保持其内容固定,但通过将名字改为典型的男性或女性发音来改变候选人的性别。发出这些不同的简历,并记录下哪些收到了面试邀请。
瞧吧:“与拥有相同记录的女性求职者相比,男性和女性都更有可能雇佣男性求职者。”类似的方法,但在“受保护的属性”上有所不同的是 Bertrand 和 Mullainathan 的研究,他们发现“白人”的名字在面试中获得的回应比“非裔美国人”的名字多 50%。”
…在算法方面
已经发现算法也包含和/或复制偏差。你可能听说过亚马逊的 CV 过滤系统,这是算法公平世界中另一个经常被引用的例子。这个系统告诉自己男性候选人更受青睐。它对包含“女性”一词的简历进行处罚,比如“女子象棋俱乐部队长”。并且降低了两所女子大学毕业生的等级。”
科学研究发现了类似的结果,通过一种所谓的“无权限审核方法”陈等人发现,三个流行的简历搜索引擎(返回职位名称查询的求职者的引擎)表现出“对女性候选人(轻微)不利,即使在控制所有其他可见的候选人特征时也是如此。”
🦾人工智能拯救:公平意识的重新排名
幸运的是,事实证明,在雇佣和招聘的背景下让算法变得公平非常简单。以 LinkedIn 的“公平意识重新排名”为例他们的想法是“[确保]显示的女性候选人比例与符合该查询的相应档案比例相同。”
这个想法和技术实现都很简单——我们正在谈论一个事后重新排序的步骤,在算法上没有什么太复杂的——但现实世界的影响是显著的。作者报告“在不影响业务指标的情况下,公平性指标得到了巨大的改善。”这种影响超出了实验结果,因为他们的重新排名模型现在“部署到全球所有 LinkedIn 招聘人员用户中。”
这种有公平意识的重新排名是如何做到“公平”的?显然,这是一个小的干预,仅限于性别偏见(在他们论文中报告的 A/B 测试中),并且只是公平的一个操作化。另一种可能是让算法系统反映世界分布。另一个是代表申请人的分布。或者合格的候选人。
这才是重点;没有单一的解决办法。我们可以争论这在多大程度上是(不)公平的,但这总比完全不做公平排名要好。LinkedIn 明确选择了将这种公平理念付诸实施;一个主观的解决方案,但也是可以辩护的。
🤖更进一步:人工智能修正人类偏见
彭等人(来自图片)将雇佣中的偏差缓解算法向前推进了一步,旨在调整算法系统的输出,以便进一步补偿人类偏差。基本上;显示更多的女性填补传统上通常由男性填补的空缺。
作者发现他们的“过度补偿”策略是有效的,因为“平衡候选人名单中的性别代表可以纠正某些职业的偏见,”但不是在所有情况下;“这样做对人类持续偏好发挥作用的职业没有影响”(例如保姆和妇科医生)。在“人类持续偏好”旁边,作者发现了影响其偏见缓解策略有效性的其他因素,如决策者的性别、决策任务的复杂性以及性别的过度和不足。
后一项发现强调了招聘中偏见的复杂性,以及人类决策和算法系统之间的相互作用,同时强调了采取措施的重要性。不过,必须指出的是,作者使用众包进行了他们的研究,我认为可以肯定的是,外行人会表现出与受过培训的人力资源专业人员不同的行为。
📰价值驱动的人工智能新闻推荐
虽然不像人力资源和招聘那样是高风险领域,但算法新闻传播已经得到了广泛的关注,这要归功于(坊间的)帕里泽的过滤泡沫(事实证明,很难根据经验建立)。对我们来说,这是一个好消息,早在 2019 年,我们就与数据科学家团队一起为荷兰财经日报“Het Financieele Dagblad”(荷兰版的《金融时报》)设计并构建了一个定制的基于内容的新闻推荐系统。

来源:来自作者
那么,什么是新闻推荐中的公平呢?通过在我们组织中不同的利益相关者之间进行对话,我们开始定义我们认为我们的算法“应该”做什么。更具体地说,我们参与了 Bastian & Helberger 的一项研究,他“对来自不同部门的员工(记者、数据科学家、产品经理)进行了半结构化采访,从新闻编辑室的角度探讨了价值表达的成本和收益以及算法新闻分发中的任务敏感方法。”
从这些采访和随后的讨论中,我们提炼出了一个“编辑价值”的子集,在利益相关者之间共享,并且(并非不重要)在技术上是可行的。我们发现我们的算法新闻推荐应该继续:
- 让读者惊讶
- 提供及时、新鲜的新闻
- 支持多样化的阅读行为
- 增加文章的(阅读)覆盖面
有了这四个编辑价值,在我们的 UMAP 2020 年出版物 “超越点击优化:将编辑价值纳入新闻推荐” 中,我们进行了干预,以调整我们的推荐系统,明确提供更及时和新鲜的推荐(即我们列表中的第二个价值)。

A/B 测试结果显示,我们的干预治疗提高了动态性、意外收获和多样性,增加了及时和新鲜的新闻推荐(来源:作者)
与 LinkedIn 的公平意识重新排名类似,我们采用了一种重新排名策略来提升最近的新闻。我们的基线新闻推荐和新近提升推荐之间的 A/B 测试结果显示:( I)我们可以增加及时和新鲜的新闻传递,而不损害准确性(同样,与 LinkedIn 论文相同的故事),而且(ii)改进新鲜新闻推荐增加了四个值中的三个(新鲜度、惊喜和多样性)。
就像 LinkedIn 的例子一样,我们工作的贡献并不是带来公平或道德新闻推荐的终极解决方案。用新文章取代旧文章没什么了不起的。重要的是,我们与利益相关者坐在一起,共同决定和选择我们的推荐系统应该做什么。
🗣讨论
电车问题的普遍解决方案并不存在:伦理和公平是与环境、领域、文化和时间相关的。LinkedIn 的公平意识排名没有修正性别偏见,我们的价值驱动的新闻推荐不能取代编辑决定。
然而,在某些方面,两者都比未经调整的同行做得更好,也更公平。保持谦逊忘掉解决根本的不公正,根除歧视,开始接触并共同设计算法。决定什么是公平的不能也不应该由我们这些数据科学家来做:这不是我们的工作,也不是我们的专长。然而,我们的工作和专长应该是接触相关的利益相关者,共同决定和设计我们想要实现的目标。
注意
这篇博客是我在 DDMA 会议人工智能上的一次演讲的书面记录,演讲名为面向数据科学家的实用主义、伦理和公平的人工智能,它本身由之前两次演讲的几张幻灯片组成;一个是我在举办的关于人力资源中算法偏差和偏差缓解的反歧视黑客马拉松,以及我们的 UMAP 2020 论文的幻灯片:“超越点击优化:在新闻推荐中融入编辑价值。”
🔍参考
- 彭,a .,努希,b .,克奇曼,e .,因克彭,k .,苏里,s .,&卡马尔,E. (2019)。所见即所得?代表标准对雇佣中人的偏见的影响。人类计算和众包 AAAI 会议记录,7(1),125–134。
- “性别对求职者和终身职位候选人简历审查的影响:一项全国性实证研究。”性别角色 41,509–528(1999 年)。
- 玛丽安·伯特兰和森迪尔·穆莱纳桑。Emily 和 Greg 比 Lakisha 和 Jamal 更适合工作吗?劳动力市场歧视的现场实验。NBER (2003 年)。
- 路透社:https://www . the guardian . com/technology/2018/oct/10/Amazon-hiring-ai-gender-bias-recruiting-engine
- 陈乐、马瑞军、阿尼科·汉纳克和克里斯托·威尔逊。调查性别对简历搜索引擎排名的影响。驰 2018,ACM。
- 沙欣·杰姆·格伊克、斯图尔特·安布勒和克里希纳拉姆·肯塔帕迪。2019.搜索和推荐系统中的公平意识排名及其在 LinkedIn 人才搜索中的应用。在第 25 届 ACM SIGKDD 知识发现国际会议论文集&数据挖掘(KDD’19)。美国纽约州纽约市计算机械协会,2221–2231。
- https://www . ifow . org/publications/artificial-intelligence-in-hiring-assessing-impacts-on-equality
- Bastian 和 n . hel Berger(2019 年 9 月)。捍卫新闻 DNA:新闻推荐者对价值敏感算法设计的态度。加的夫未来新闻会议。
- F.陆、和格劳思,“超越点击优化:在新闻推荐中融入编辑价值”,载于第 28 届美国计算机学会用户建模、适应和个性化会议论文集,美国纽约州,2020 年,第 145-153 页。
健忘的熊猫🐼
熊猫的内存报告可能会误导-学习如何看到真正的使用和节省内存!

资料来源:pixabay.com
pandas 库是 Python 中用于数据清理、数据准备和数据分析的工具。一旦你找到了它的扩展 API,使用它是一种乐趣。🎉
Pandas 将您的数据存储在内存中,使操作变得敏捷!🏎不利的一面是,一个大的数据集可能不适合你的机器的内存,使你的工作陷入停顿。☹️
通常,知道你的熊猫数据帧占用了多少内存是很方便的。几年来,我一直在研究熊猫,并把它教给学生。我甚至写了一本关于入门的小书。我听说默认显示的内存使用并不总是准确的。🤔但是有如此多的数据需要探索,而时间又如此之少,以至于我最近才开始着手调查。我很震惊地了解到内存欠计数可以有多大。😲
在这篇文章中,我将向你展示几种方法来获得你的熊猫对象的真实内存使用情况。然后我会分享八个解决你的数据放不进内存的方法。🎉

小熊猫也很可爱。资料来源:pixabay.com
我用文本数据制作了一个 40 列 100,000 行的数据框架——仅仅是一些狗和猫品种的名字。🐶🐈没什么疯狂的。
让我们一起探索吧!🚀
df.info()🔎
我总是使用[df.info()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.info.html)来获得一个新数据帧的基本信息。下面是该方法的相关输出:memory usage: 31.3+ MB。
注意+ 符号。嗯。你可能认为这意味着实际的内存使用比 31.3 MB 多一点——比如 32 或 33MB。保持这种想法。😉
df.memory_usage()
我们用[df.memory_usage()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.memory_usage.html)函数看看能不能挖一点。
结果是以字节为单位报告每列内存使用情况的 Series 对象。我们把结果求和,换算成 MB。
df.memory_usage().sum() / 1_000_000结果在32.8
好吧。这比df.info()报道的要高一点。但是我们在同一个邮编。我可以忍受。但是等等,好像还有一个deep关键词。这是怎么回事?🤔我们来深入挖掘一下!
df.memory_usage(deep=True)
让我们将deep=True参数传递给df.memory_usage()方法,求和并将结果转换为 MB。df.memory_usage(deep=True).sum() / 1_000_000导致256.8 MB。这几乎是 8 倍的内存!😲
这是怎么回事?
与其他数据类型不同,对象数据类型列没有固定的内存分配,每个单元格的内存分配都是相同的。使用的内存量取决于字符的数量。更多的字符意味着更多的内存。有点像这样:
莫人物,莫记忆。资料来源:giphy.com
除了莫字符,莫记忆!
变量检查器
请注意,如果您使用方便的变量检查器 JupyterLab 扩展,它也会显示不准确的 32.8 MB 大小。
df.info(内存使用=真)
让我们回到df.info()。你可以把参数memory_usage=True传给它。然后它报告了一个接近df.memory_usage(deep=True) : 244.9 MB的东西。
想让 df.info()每次返回更准确的数字?
使用pd.options.display.memory_usage = 'deep'。请注意,该设置不会影响df.memory_usage()的报告。
老式的 Python 系统函数说明了什么?
让我们检查一下。
import sys
sys.getsizeof(df) / 1_000_000
sys.getsizeof()函数报告256.800016 MB,几乎与df.memory_usage(deep=True)相同。这个数字看起来可信。🎉
为什么真实内存总是不报?
清点人数需要资源。还有熊猫开发团队——顺便说一下,我们都应该感谢他们出色的工作👏—默认情况下,决定节省资源。
只是不要被误导!⚠️

熊猫可能健忘,也可能不健忘,但据报道,大象有极好的记忆力。资料来源:pixabay.com 和阿加莎·克里斯蒂
您已经看到了几种获得更准确内存信息的方法。酷毙了。但是当你想节省一些内存的时候应该怎么做呢?
我没有足够的内存,我该怎么办?
- 只读入你需要的栏目。
pd.read_csv()有一个usecols参数,可以用来指定列的子集。Pro move:提前检查您的文件,只引入您需要的列。😎 - 向下转换数值。如果你不需要所有的数字,节省的费用会很可观。从 float64 迁移到 float16 将会减少 75%的内存使用量!⭐️将
pd.to_numeric()与downcast一起使用。 - 将分类数据转换为类别数据类型。根据
memory_usage()的说法,将我们的宠物对象列更改为分类将内存占用减少到 4.8 MB。通过deep=True会导致显示的内存使用量略有增加。最大的问题是,对象数据类型占用的内存是分类数据类型的 50 多倍!😲如果转换整个数据帧,使用df.astype(‘category’)。 - 如果您有稀疏数据,请使用稀疏数组。稀疏数据是主要具有相同值的数据。1000 万个 float64 值使用 80MB 内存。如果这些值中的大部分是相同的,那么在转换为稀疏数据时可以节省大量内存。使除了 10 个值之外的所有值都相同并转换为稀疏值会将内存降低到. 000248MB!👍用
pd.arrays.SparseArray()转换成稀疏。 - 使用 生成器表达式 代替循环遍历列表以节省内存。
- 用
[read_csv()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)函数的chunksize参数一次读入数据行的子集。这将创建一个熊猫 TextFileReader 对象。这就像一个 Python 生成器。然后,遍历一大块行,直到遍历完所有行。 - 检出Dask。它提供分布式计算解决方案,将您的数据和处理分散到多台机器上。dask 系列包模仿了 pandas API 和其他常见的 Python 数据科学 API。
- 获取更多内存——要么从亚马逊、谷歌或微软的云中租借,要么增加本地机器的内存。如果你在本地工作,8GB 通常可以应付,但 16GB 更好,尤其是如果你使用视频会议和浏览网页。🕸
你有其他节省记忆的方法吗?请在 discdiver 的评论或 Twitter 上与我分享。📣
包装
现在你知道如何找到熊猫的真实内存使用情况了。您还看到了处理内存限制的方法。像往常一样,不要过早地进行优化——如果您的数据很小,这不是什么大问题。但是当你的数据很大的时候,这是一个非常大的问题。😀
我希望这篇获得准确的内存报告和节省内存的指南对你有所帮助!如果你有,请分享到你最喜欢的社交媒体上。🎉
我写关于数据科学、 Python 、熊猫和其他技术主题的文章。如果你对此感兴趣,请阅读更多内容并加入我在 Medium 上的 15,000 多名粉丝。👍

大象也很可爱!资料来源:pixabay.com
快乐智能记忆使用!🧠
忘记做圣诞卡了?我们用 AI 做一个吧!
在 OpenCV 和 UbiOps 的一点帮助下
介绍
圣诞节又到了,我想这将是一个用编码和人工智能做些有趣事情的好机会!让我们制作一个简单的图像处理应用程序,给图片中的每个人一顶漂亮的圣诞老人帽子,并挂上一些圣诞装饰品,使图片更加喜庆。

模型的输入和输出示例。图片由作者提供。
你可以通过使用令牌Token b1cc8511a5c8d59dfc43834b426deec265fa7729前往这个页面来尝试这个应用的工作演示。填写完令牌后,您可以单击“连接”按钮,然后您将被带到一个可以上传图片的界面。只需点击运行按钮,该应用程序将为您的图像添加一些节日欢呼。
免责声明:确保每个面部上方都有足够的空间放置圣诞帽。此外,图像分辨率越高,建模时间越长。分辨率较低的图像效果更好!

交互式演示屏幕。图片由作者提供。
应用程序的工作方式
让我们看看这个应用程序是如何工作的。它实际上相对简单,只需要大约 50 行代码。它分 4 步工作:
- 在输入图像上调整圣诞装饰图像的大小并叠加
- 检测输入图像中的人脸(使用哈尔级联)
- 把圣诞帽戴在脸上
- 保存生成的图像并将其作为输出返回

模型的示意图。由Freepik制作的图标来自www.flaticon.com。作者提供的示意图。
app 本身在 UbiOps 中服务,部署后自动生成界面。
代码
下面你可以看到上传到 UbiOps 的代码。
在__init__函数中,我们通过加载必要的叠加图像和用于人脸检测的 Haar 级联分类器来初始化模型。分类器是一个标准的分类器,默认由 open-cv 提供。你可以很容易地把这个换成不同的 Haar 级联分类器来进行人脸检测。如果你想更多地了解哈尔喀斯,Girija Shankar be hera的这篇文章很棒!
每次向模型发出请求时,都会调用request函数,所以这是主要代码块所在的地方。我们从读入输入图像并检查其尺寸开始。try-except 子句的存在是因为我们无法预先知道输入图像是 BGR 图像还是二进制图像,这将影响 frame.shape 返回的值。一旦我们知道了图像的尺寸,我们就可以调整圣诞装饰图像的大小,并使用 cvzone 将它们覆盖在输入图像上。
之后,我们将输入图像转换为灰度图像以进行快速处理,并使用我们的分类器来检测人脸。我们遍历找到的面,并对每个面执行以下操作:
- 我们检查面部是否大于最小阈值,以确保我们筛选出一些错误的检测。
- 我们调整圣诞帽图像的大小以适合头部的大小
- 我们把圣诞帽放在脸的上方
最后,我们将生成的图像写入一个 PNG 文件,并将其作为输出返回。
其他必要的文件
为了正确部署应用程序,我们需要的不仅仅是代码本身。我们还需要一个详细说明代码依赖关系的需求文件,当然还有所有的图像文件和 Haar cascade 文件。
对于此模型,requirements.txt 文件如下所示:
我们使用的图像取自 pngtree 和 pngkey ,Haar cascade 文件是 OpenCV 的标准文件。
我们只需要一个文件来将模型部署到 UbiOps,那就是 ubiops.yaml 。当我们将代码推送到 UbiOps 时,会生成一个 Docker 映像,其中安装了所有 Python 依赖项。然而,在我们的例子中,我们需要的不仅仅是 Python 依赖。 Opencv 需要一些额外的操作系统级包,这些包通常已经安装在你的本地机器上,但不在 Docker 镜像中。我们需要告诉 UbiOps 安装 APT,这正是 ubiops.yaml 的作用。我们需要的是这样的:
为应用服务
代码由 UbiOps 中的一个 python 3.8 部署提供,其中input_image作为输入,festive_image作为输出。我们使用的完整部署包可以在这里找到。UbiOps 通过我们可以使用的 API 端点公开代码,但它也自动生成一个简单的接口。这个接口对于这个模型来说已经足够好了,所以我们只需要创建一个 API 令牌来访问这个接口,这样就完成了!你已经创建了一个简单的图像处理应用程序来转换你的图像,添加一些非常需要的节日欢呼。
后续步骤
当然,本文中描述的模型非常简单,有时可能会错误地将背景噪声识别为人脸。为了避免这种情况,可以使用不同的面部检测算法,或者在面部循环中使用不同的滤波器参数。这篇文章由马尔·杨奇煜撰写,是关于 Python 中不同人脸检测方法的很好的参考资料。
然而,代码中的主要步骤适用于广泛的用例,而不仅仅是这个圣诞用例。这个应用程序可能只是让你的图像更快乐一点,但它确实告诉你如何检测人脸,以及如何根据这些数据改变图像。例如,如果你把圣诞帽换成太阳镜并改变偏移量,你可以很容易地制作一个 Snapchat 滤镜。随意摆弄代码,创造出完全不同的东西。希望这个圣诞模型能给你一些探索 Python 中图像处理的灵感。
请在评论中告诉我你对我的实现有什么看法,不要忘记添加你的圣诞图片!
您对 Python 的图像识别和处理感兴趣吗?那你也应该看看 这篇文章讲的是一个用 Python 和 Mendix 做的年龄估算器 app 。
统计推断的形式介绍
假设检验的技术演练

作者拍摄的照片。与自然连接!
当面临是否向整个客户群部署营销活动的决策时,从公司的战略角度来看:通过基础“样本”实施活动所能实现的增量效应的显著性水平的衡量和测试,可能会决定成功(“高”投资回报)和/或失败(金钱甚至声誉损失)。在这个舞台上,统计成为最好的工具。
如果你开始阅读这篇文章,你可能会想知道这是否与 A/B 测试有关。是的,它是。然而,我在这篇文章中关注的更多的是从 A/B 测试中获得的结果的统计评估,而不是方法背后的详细解释(例如,测试的设计、计划和运行)。通过这样做,我能够将决策方保持在分析的核心。
先了解一些背景信息。A/B 测试是一种可用于对 A 和 B 两种变异体进行实验的方法。这两种变异体可能有不同的名称,最常见的是对照组和治疗组,人们试图找出这两种变异体之间的任何差异。因此,统计分析用于检验这种差异的显著性。在建立 A/B 测试时,需要考虑的不同因素包括:1)随机选择过程,其中构成群体的任何个体都有被选择并成为“样本”一部分的同等概率;2)随机“样本”代表群体中的不同群体,因此没有偏见;3)并且“样本”具有相当大的规模,可以进行任何测试和分析。让我们想一想,由于缺乏资源和时间,我们无法测量所有的人口。
为了能够在给定的时间尺度下进行任何调查,根据上述标准从人群中抽取样本,从而可以推断出人群的特性并回答调查中的问题。因此,我们希望确保从这类人群中抽取的样本量足够大,以便在评估结果时能够有一定的置信度。多大才算大?在这一点上可能是个问题。如上所述,这篇文章没有详细阐述 A/B 测试和预评估阶段背后的方法,我建议读者进一步研究这一部分。不过,我希望在接下来的文章中,我可以强调在进行假设检验时,选择一个相当“大”的样本量的重要性。
在这里,我们已经进入了统计领域,在继续下一步之前,需要定义一些术语:
- 假设检验:一个假设,一个被公式化并被检验证明为真的假设,如果它是真的或者其他。因此,定义了两个语句:
1.1)零假设下的等式声明(Ho):
Ho:“对照组和治疗组是一样的。这两者之间没有区别”
1.2)及其补充陈述,即替代假说(H1)
H1:“治疗组的表现更好,因此这与对照组之间存在差异。”
2)增量效应:定义为在实验期间对治疗组进行的激励/治疗所触发的两个变量之间的差异
上述内容可以定义如下:
H0: d = 0
H1: d ≠ 0
其中 d 是两个变量之间的差异。在统计学中,这就是所谓的双尾检验。使用众所周知的钟形曲线,如下图所示

作者绘制的图像
双尾检验:这是要检验的区域,即正态分布曲线下的区域,并且在一个区域内,肯定不会拒绝说明两个变量之间没有显著差异的零假设。一个目的是识别和测试两个变量之间的增量差异的显著性,如果有的话,不区分哪个方向,意味着左/右单尾测试。
现在,如果我退后一步,提出以下两个关键问题:1)哪个假设是真的?意思是哪个假设与数据相符?以及 2)我们可以自信地说这种情况达到了什么样的显著水平?换句话说,两组之间有显著差异吗?
这是我们接下来要讨论的内容!让我们从背后的数学开始:
随机变量 X 被定义在一系列离散结果下,即 1(真)和/或 0(假),这些结果是在随机过程下产生的,特别是对于具有给定试验次数的实验的伯努利过程。因此,使用了伯努利分布,它只是二项式分布的一个特例。为了表示这些结果的分布,(p)将是事件为真的概率和/或(1-p)为假的概率。在这里,假设事件彼此独立,即一个事件的发生不影响另一个事件发生的概率。在 A/B 测试中,我们的目标是测量每组中发生的真实事件(成功)的数量,并确定这两者之间的增量差。在商业环境中,交谈率是评估和衡量成功的最常见(可变)指标。
因此,
基于伯努利分布:


根据中心极限定理(CLM),
从总体中抽取许多样本可以逼近总体的真实平均值。因此,p 的分布将是正态分布,其标准偏差等于平均值的标准误差。
这是,

其中 n 是观察次数(样本大小)。
从等式 4 中可以看出,这是等式的分母,表示反向相关性,分母越大(样本越大),σ越小(标准差越小)。这是一种数学表示,说明样本大小是抽样平均值相对于总体平均值的偏差(误差)大小的关键决定因素。
从上面可以看出,两组都可以表示为遵循近似的正态分布

现在,下表列出了一些 A/B 测试的虚构数字。旨在衡量发送给治疗组的活动的成功水平,定义为通过接受活动中的报价并将其与未接受任何报价的对照组(除了业务照常沟通(BAU))进行比较而转化的客户数量,两组之间的任何差异可以确定为活动报价触发的增量差异。

来自每组的两个感兴趣的参数是:1)平均值,这是(p)等于上表中该组的转换率,以及 2)如等式 5 所示导出的平均值的标准误差。
有了上面的知识,人们现在能够为控制组和目标组生成分布,

作者策划:对照组与治疗组
从上面的图表中,我们可以看到 x 轴上的对话率。然而,为了能够比较两组的对话率并推断出这两组之间的差异的统计显著性,我们需要制定零假设和替代假设。
概率论中,正态分布的独立随机变量之和也是正态分布的。因此,两组之间的概率差遵循正态分布。
由此可见,在零假设下,【H0:】T5
- 平均值是两组之间的概率差:

2.标准差(方差的平方根)等于两组的方差。根据总和的方差,它等于方差的总和:

在替换之后,我们得到池的标准误差,SEp:

其中 pp 是池的会话速率估计值:

等式 11 基于以下假设导出:在零假设下,如果对照组和目标组是相同的,即这两者之间没有差异,则它们属于相同的基础分布。因此,来自对照和目标的实际输出可用于导出合并的标准误差:1)在零假设下均值为零(0 ),表示两组之间没有差异,以及 2)均值等于两组之间的差异,用于替代假设。
这是,
在原假设下, H0:

在另类假设下, H1:

有了这两个假设的平均值和标准误差,我们可以继续计算用于统计推断目的的置信区间(CI)。
在传统的 95%置信度下,置信区间的下限(-)和上限(+)计算如下:

有了上述所有信息,现在可以直观地表示零假设和替代假设:

作者在 RStudio 中生成的情节。零假设与替代假设
在传统的 95%置信度下,两组之间的增量差异即 0.001481,显示为落入临界区域(红色区域),即在置信区间之外,因此我们拒绝零假设,支持两组之间存在显著差异的替代假设。
因此,两组之间转换率的增量差异在 5%的显著性水平上在统计学上不同于零。这是:如果空值为真,那么这种极端观察到的增量差异发生的概率很小,只有 5%。
在α水平较低时,犯 I 型错误的概率降低:这是拒绝 null (Ho)的概率,当事实上为真时。这也被称为假阳性。

然而,当改变α的水平时,有一个权衡,这在下图中由红色虚线示出。

作者在 Rstudio 中生成的情节。第一类误差和第二类误差之间的权衡
低水平的 β 降低了犯类型 II 错误的概率:当事实上为假时,不能拒绝空值(Ho)。也称为假阴性。

以上说明,在定义置信水平时,两个误差之间是有权衡的!
两个变量之间预期的增量差异将决定在 5%显著性水平(α)或更低水平下检测这种增量差异的高概率(统计功效)所需的样本量。因此,你的样本大小不是理所当然的。只要这个数字足够大,并且你的实验结果经过了正确领域的审查,你就最大化了正确决定站在你这边的机会!
结论
在这篇文章中,
1)我概述了在设置 A/B 测试时要考虑的三个关键要素,在本例中,是在两个变量之间进行实验以确定性能差异。
2)由于我的重点是检验 A/B 检验结果的统计显著性,我提供了假设检验的定义,并描述了支持假设检验的主要和补充陈述的表述,即零假设(H0)和替代假设(H1)
3)我借助数学推导出两个假设,以检验两组之间的增量差异的显著性。
4)在这篇文章中,我采用了不同的方法来展示一个相对“大”样本的重要性,以及它与预期增量差异的相关性。
5)我的目的是确定当定义置信水平来测试两组之间的增量差异的统计显著性时,即由活动提议触发的治疗组的更好表现,在拒绝事实上为真的空值(H0)和拒绝事实上为假的空值(H0)之间存在权衡。更准确地说:
5.1)得出结论,两组之间的增量差异很大,而实际上并不明显,这将导致部署的营销活动不成功,成本高昂,转化为负投资回报(ROI)
5.2)或者另一方面,确定两组之间的增量差异并不重要,因为事实上它因此错过了通过不正确测试的良好活动带来大量客户和收入的机会。
感谢阅读:)
在我的下一篇文章中再见。
AM!
在 python 中格式化字符串和数字
在 python 中格式化字符串/数字输出的 6 种方式

图片来自凯利·西克玛
关于这篇文章
大多数时候,一个简单的print()语句可能会导致混乱的代码。有时您不需要记录器来处理这项工作。Python 提供了不同的输出选项来处理字符串输出。这里有一些
格式化字符串
1.使用%s in statements
print(“Some text **%s** some text **%s** some text “ %(str1,str2))
str1 和str2 依次代替%s和%s

您甚至可以在字符串输出中进行数学运算。

多次打印一个字符
2.使用 f 前缀格式化
我们可以使用 f-string 方法编写相同的代码。

它克服了%s 的限制—您不能指定顺序(“轻松”)。所以当你使用{variable_name}时,你把它们嵌入到你想要的语句部分,自然就克服了“顺序问题”
3.使用 f 前缀整齐地对齐输出
您可以使用 f 格式中的 **:>**、**:<**或**:^**选项来左对齐、右对齐或居中对齐您想要格式化的文本。

不格式化
格式化输出文本的对齐方式后…

格式化后向右对齐
4。使用格式关键字
我们可以使用 python 中的fortmat() 字符串函数,按照我们想要的顺序输出想要的文本。

在 python 中使用 format()函数
格式化数字
现在使用f keyword 扩展格式(看上面的部分),让我们试着在数字中使用,特别是涉及小数的( float )
1.限制小数点后的位数
例如:如果我想限制圆周率的值(小数点后第二或第三位)

数字输出
通常,我们会得到这样的结果

正常的预期产量
现在,通过格式化数字,我们可以将小数位数限制为两位数…

限制到小数点后两位
或 3 位数…

限制到小数点后 3 位
2.在 pandas 数据框中格式化输出
更进一步说,如果你想在数据框中以特定格式显示数字,当使用pandas 时,你可以使用 pd.options.display来显示你想要的方式。以下是启用options.display设置前后数字显示的示例。
让我们举个例子——
我们正在读取一个文件 test.csv并显示其内容。我们看到长度列显示了 6 个小数位。

正常显示,长度栏显示 6 个小数点
如果我们只对显示两位小数感兴趣,我们可以使用 pd.options.display属性来改变它。下面是应用格式后数据帧的输出。

将浮点数据类型的格式设置为两位小数后的输出
注:从这里开始,对于所有的熊猫显示(甚至对于其他数据帧),将只显示 2 个小数点。如果您想将其设置回小数点后 4 或 5 位,您必须将格式设置回您想要的格式。直到那时,它将继续显示只有 2 个小数点。
3。格式化 numpy 中的输出
Numpy 具有将小数点精度更改为所需精度的设置。
**np.set_printoptions(precision=2)**
让我们把输出看作是对前面熊猫例子的扩展。

更改 numpy 中的小数点精度
正向和反向 KL 散度

爱丽丝·山村在 Unsplash 上的照片
在本文中,我们将调查正向和反向 KL 偏离之间的差异,以及这可能对您的项目产生的影响。为了做到这一点,我们将着眼于理论,然后用一些实验来证明实际结果😊
什么是 KL 发散?
很高兴你问了!本质上,描述了一个概率分布与另一个的偏差。它实质上是从“真实”分布和我们想要与“真实”分布进行比较的“预测”分布之间的交叉熵中减去“真实”分布的熵。这里的想法是,如果两个分布相同,那么交叉熵应该等于熵,所以结果将是 0。否则,交叉熵将大于熵项,因此结果将大于 0。换句话说,该值越接近 0,则“真实”和“预测”分布越相似。
下面给出了该方程,以及从初始定义导出的一些进一步的形式:

图片作者:KL 散度方程
这为什么有用?好吧,假设你想用一个我们可以控制参数的模型给出的“预测”分布来拟合一些“真实”的概率分布。有一个度量标准告诉我们模型分布与实际目标分布有多接近是很有用的。交叉熵可以服务于这个角色,但它并不持有直观的价值;也就是说,KL 散度直观地告诉你,你离单个数字的解有多近。
不对称的证明
首先,一个定义。无论参数的顺序如何,对称函数都具有相同的值。
看起来 KL 散度也应该是一个对称函数。如果它给出了两个分布之间的不相似性的度量,那么函数的分布输入的顺序应该无关紧要,因为这不会改变任何关于不相似性的东西,对吗?
好吧,我们来做个实验!为了简单起见,我们来看两个任意的伯努利分布,一个定义为 p(x) ,一个定义为 q(x) 。

图片作者: p(x) 有 p = 0.1 和 q(x) 有 p = 0.6
当我们计算具有不同参数顺序的相同分布的 KL 散度时,我们得到的值会发生变化:

作者图片:参数排序影响结果!
因此, KL 发散不是对称的。我们定义如下:
- KL(p||q)是前向 KL 散度
- KL(q||p)是反向 KL 发散
理论
那么有什么区别呢?再次设置场景,我们经常想要最小化 KL 散度,以使可控的“预测”分布符合一些固定的“真实”分布,但是我们应该最小化哪个 KL 散度度量?在下面的部分中, p(x) 是固定的“真实”分布, q(x) 是可控的“预测”分布。为了说明这一点,我将下标 q 和 θ ,它们是我们可以改变的 q 分布参数。
让我们首先来看看前向 KL 散度的最小化:

作者图片
换句话说,凡是 p(x) 有大概率的地方, q(x) 一定也有大概率。这是均值搜索行为,因为 q(x) 必须覆盖 p(x) 中所有高概率的模态和区域,但是 q(x) 不会因为具有高概率质量而受到惩罚,而 p(x) 不会。
现在,让我们将这与反向 KL 发散的最小化进行对比:

作者图片
让我们逐项分析一下。第一项类似于 KL 向前发散的目标。也就是说,它陈述了在 q(x) 具有高概率的地方, p(x) 也必须具有高概率。这是模式搜索行为,因为来自 q(x) 的任何样本必须位于 p(x) 的模式内。注意, q(x) 不会因为没有在 p(x) 的所有模式上放置概率质量而受到惩罚。第二项其实只是 q(x) 的熵!这阻止了分布坍缩到非常窄的模式。
实验
为了证明这一点,让我们尝试预测一个 GMM(2)分布, p(x) ,一个正态分布, q(x) 。“真实”分布 p(x) 如下所示:

作者图片:均值[-1,2],方差[0.25,0.5]和权重[0.5,0.5]的 GMM 分布
我觉得很懒。我不想计算最优化方程的导数的解析形式,这太复杂了。相反,让我们使用进化策略(ES)算法和蒙特卡罗采样来优化函数!这很好,因为我们不再需要任何梯度信息;更多信息,请参见我写的关于 ES 这里 的文章。对于正向和反向情况,我们将针对 q(x) 的均值和标准差进行优化。
先说前进 KL 发散。学习曲线如下所示:

作者图片
最终,该算法的平均值为 0.0401,标准偏差为 1.65,我们可以看到最终的 q 分布相对于下面的 p 分布的位置:

作者图片:最小化 KL 向前发散
显然,“预测”分布并没有确定“真实”分布的任何一种模式,而是证实了从理论中得出的均值寻找行为。
现在,让我们对反向 KL 发散做同样的事情。同样,学习曲线如下:

作者图片
这一次,算法确定平均值为-0.745,标准偏差为 0.585。我们可以看到合成的 q 分布相对于下面的 p 分布的位置:

作者图片:最小化反向 KL 分歧
显然,优化反向 KL 发散导致从“预测”分布中寻找模式的行为,几乎忽略了“真实”分布的其他模式。
总的来说,当优化模型目标函数时,前向和反向 KL 发散之间的细微差异会导致不同的行为;重要的是要仔细考虑哪一种更适合您的特定场景!作为机器学习设置中的一般规则,我们在监督学习中使用正向 KL 散度,在强化学习中使用反向 KL 散度。
如果您觉得这篇文章有用,请考虑:
推广的方式,我希望这篇文章是一个有趣的阅读,并让我知道你的想法!!
相关分析的基础
如何恰当地测量数据中的二元关系

情人节可能是一个遥远的记忆,但它仍然感觉像是一个与你讨论关系的完美机会——那是你数据中的关系。
在这篇文章结束时,你会对最常见的相关系数以及何时使用它们有更好的理解。不再依赖默认设置,这种自由会让你在解释和展示相关研究的结果时更加自信。
我们将看看:
- 皮尔逊氏 r
- 斯皮尔曼氏 rho
- 肯德尔氏τ
- 点双列相关
如果你想继续,你可以在这里找到我使用的数据集
如何衡量关系
我们可以通过测量变量之间的协方差来确定它们之间是否存在关系。在我们进入协方差之前,记住方差是我们的数据偏离均值的平均值(等式 1)。

等式 1——方差等式。其中,它等于第 I 个分数(xi)和平均值(X)之间的平方差的和(∑)并除以观察次数(N)减 1。
我们将上述等式中的偏差平方,以防止正负偏差相互抵消。举个简单的例子,假设我们有下面一组值(2,3,5,7,8)。这些值的总和是 25,因此平均值为 5。使用等式 1,我们得到:
[(2–5)² + (3–5)² + (5–5)² + (7–5)² + (8–5)²] / 5–1 = 6.5
如果我们不求离差的平方,得到的方差将为零,显然不是这样。
那么,协方差就是两个变量相对于彼此如何变化的度量。为了计算这一点,我们只需找到偏差叉积的平均值(等式 2)。如果关系存在,当一个变量偏离时,第二个变量也会偏离。如果两个变量偏离方向相同,则协方差的结果值将为正(两个正值的叉积)。相反,如果两个变量的偏离方向相反,则协方差的结果值将为负(正值和负值的叉积)。

等式 2——协方差等式。其中它等于每个变量 x 和 y 的方差的叉积。
协方差的问题是它的效用有限,因为值没有标准化。例如,在我们将使用的数据集中,有一个用于身体质量指数(身体质量指数)的变量。该值可以用千克/米或磅/英寸来测量,换算系数为 703。根据使用的单位,协方差值会有很大不同。尽管这些不同的价值观代表着同样的东西,我们怎么能比较它们呢(身体质量指数)?
通过计算方差的平方根,我们得到了方差的标准化度量(也称为标准差)。这样做可以让我们以一种有用的方式比较与平均值的偏差,而不依赖于变量的测量单位。当我们将这个想法扩展到协方差时,结果是一个标准化的协方差,称为相关系数(等式 3)。

等式 3——标准化协方差(r)的等式。其中协方差除以 x 和 y 的标准偏差的叉积,也称为皮尔逊相关系数。
这个值非常有用,因为结果介于-1 和+1 之间。这里,r 值为-1 表示完全的负关系,r 值为+1 表示完全的正关系,r 值为 0 表示没有线性关系。
r 值也用作效果大小的度量,其中值+/- 0.1 表示小效果,+/- 0.3 表示中等效果,+/- 0.5 表示大效果。
在下一节中,我们将探讨不同类型的相关性,以及如何为您的研究问题选择合适的测试。
二元相关性
最常见的二元相关包括如上所述的皮尔逊相关、斯皮尔曼相关、肯德尔相关和点双列相关。
皮尔逊氏 R
让我们从使用皮尔逊相关来探索我们的数据集开始。Pearson 的 r 是 python 中默认的相关性。如果我们绘制一张显示变量之间关系的热图(图 1 ),我们会得到以下结果:

图 1——使用 Pearson 的二元相关系数标注 r 值的热图。作者图片
假设我们想确定年龄和一个人要支付的健康保险金额(费用)之间是否有关系。将我们的注意力转向上图的左下角,我们看到变量之间存在正相关(和中等效应大小), r = 0.30。我们很快就会看到,在使用默认设置时,我们必须小心谨慎。
如果我们只对确定是否存在线性关系感兴趣,我们只需要确保我们的变量至少在一个区间水平上被测量(意味着它们是有序的,并且水平之间有相等的距离)。这里,年龄和费用都满足这个假设。然而,如果我们想确定这种关系在统计学上是否显著,就必须考虑进一步的假设。具体来说,为了使测试有效,我们的变量应该是正态分布的。
首先,让我们画出每个变量的分布图来检验正态性(图 2)。很明显,即使没有额外的测试,两个变量也不是正态分布的。对于年龄来说,这似乎不是极端分数(异常值)造成的。除了 20 岁左右的峰值之外,其余的年龄值都是相似的。另一方面,对于电荷,分布严重向左倾斜。对于那些付费的人来说,这是一个好消息,因为这意味着大多数人支付更少的保险费用!

图 2 —变量电荷(左)和年龄(右)的分布图。作者图片
调查异常值的一个好工具是使用箱线图(图 3)。这些图让我们用四分位数来可视化数据。方框内的线代表中位数(Q2-第 50 百分位),方框以第 1(Q1-第 25 百分位)和第 3(Q3-第 75 百分位)四分位为界。从第三季度减去 Q1 的值,我们得到四分位数间距(IQR)。将 1.5x IQR 加到 Q3 上,然后从 Q1 中减去该值,得到了最小值和最大值(不包括异常值),这些值用从方框向外延伸的线(称为晶须)来划分。任何超出胡须的值都被视为异常值。如可变电荷的箱线图所示,存在许多异常值。

图 3 —年龄(左)和费用(右)变量的箱线图。作者图片
这是一个很好的例子,说明皮尔逊相关不适合用来衡量两个变量之间的关系。相反,我们将不得不参考其他双变量选项之一。
斯皮尔曼的 rho vs 肯德尔的 tau
Spearman 和 Kendall 相关系数是根据排序数据计算的。当数据是有序的(意味着它们是有序的,级别之间的距离不相等)或者数据不符合皮尔逊相关的假设(如我们的示例)时,可以使用它们。根据所用的相关系数,您可以在下面找到相关性的不同之处。
值得注意的是,我们发现年龄和电荷之间的关系在使用秩序相关性时更重要。相反,与皮尔逊的 r 相比,变量身体质量指数和吸烟者与费用之间的关系更弱相关
点双列相关
在我们的数据集中,独立于使用的相关性检验,年龄和吸烟者与费用的关系最密切。我想让你注意可变吸烟者,因为它代表了一个特例。吸烟者是一个二元变量(不是吸烟者对吸烟者),二元变量和连续变量之间的关系应该使用点双列相关来研究。使用下面的代码,我们得到了 0.79 的相关性,这与使用 Pearson 的 r 得到的结果相同。事实上,当包含一个二元变量时,点双列相关在数学上等同于 r。
摘要
在本文中,我们学习了如何衡量两个变量之间的关系。我们看到,使用默认设置来执行相关性分析可能会有问题,并导致不适当的结论。我们讨论了最常见的相关系数以及何时使用它们。如果你想看看我的笔记本,请访问我的 Github 页面。
有用的资源
关联.&text=Linearity%20assumes%20a%20straight%20line,distributed%20about%20the%20regression%20line.) —统计解决方案
有用的引导到相关系数
解释自然语言处理的基础——Bleu 评分和 WER 指标
直观的 NLP 系列
NLP 模型的两个基本指标(Bleu 分数和单词错误率)的简明指南,用简单的英语编写

在 Unsplash 上 engin akyurt 拍摄的照片
大多数 NLP 应用程序,如机器翻译、聊天机器人、文本摘要和语言模型都会生成一些文本作为输出。此外,像图像字幕或自动语音识别(即语音到文本)输出文本,即使它们可能不被认为是纯 NLP 应用程序。
预测的产量有多好?
训练这些应用程序时的常见问题是,我们如何决定输出有多“好”?
对于像图像分类这样的应用,预测的类别可以明确地与目标类别进行比较,以决定输出是否正确。然而,对于输出是一个句子的应用程序来说,问题要复杂得多。
在这种情况下,我们并不总是有一个普遍正确的答案——我们可能有许多正确的答案。例如,当翻译一个句子时,两个不同的人可能会给出两个略有不同的答案,但两个答案都是完全正确的。
例如:球是蓝色的,球是蓝色的。
对于像图像字幕或文本摘要这样的应用程序来说,这个问题甚至更难,因为在这些应用程序中,可接受的答案范围甚至更大。

同一张图片可以有多个有效的标题(图片由作者提供)
为了评估我们的模型的性能,我们需要一个量化指标来衡量其预测的质量。
在本文中,我将介绍两个主要的 NLP 指标,您可能会在您的 NLP 模型中频繁使用这两个指标。
此外,如果您对 NLP 感兴趣,我有几篇文章探索了这个领域的其他有趣主题。
NLP 度量
多年来,已经开发了许多不同的 NLP 度量来解决这个问题。其中最受欢迎的是所谓的布鲁分数。
它远非完美,而且有许多缺点。但是计算和理解起来很简单,并且有几个引人注目的好处。尽管它有许多替代方法,但它仍然是最常用的指标之一。
它基于这样一种思想,即预测的句子越接近人类生成的目标句子越好。
Bleu 分数在 0 到 1 之间。0.6 或 0.7 的分数被认为是你能达到的最好成绩。即使是两个人也可能会对一个问题提出不同的句子变体,并且很少会达到完美的匹配。出于这个原因,接近 1 的分数在实践中是不现实的,并且应该发出您的模型过度拟合的信号。
在我们进入如何计算 Bleu 分数之前,让我们先了解两个概念。N-grams 和精度。
n 元语法
“n-gram”实际上是常规文本处理中广泛使用的概念,并不特定于 NLP 或 Bleu 分数。它只是描述“一个句子中的一组‘n’个连续单词”的一种花哨方式。
例如,在句子“球是蓝色的”中,我们可以有 n 个字母组合,如:
- 1-gram(unigram):“The”,“ball”,“is”,“blue”
- 2-gram (bigram):“球”,“球是”,“是蓝色的”
- 三字组(三元组):“球是”,“球是蓝色的”
- 4 克:“球是蓝色的”
请注意,n-gram 中的单词是按顺序排列的,因此“蓝色是球”不是有效的 4-gram。
精确
该指标衡量预测句子中同时出现在目标句子中的单词数。
比方说,我们有:
- 他吃了一个苹果
- 预言句:他吃了一个苹果
我们通常使用以下公式计算精度:
精度=正确预测字数/总预测字数
精度= 3 / 4
但是像这样使用精度是不够的。我们还有两个案子需要处理。
重复
第一个问题是这个公式允许我们作弊。我们可以预测一句话:
- 他吃了一个苹果
- 预测句:呵呵呵
并且得到一个完美的精度= 3 / 3 = 1
多重目标句
其次,正如我们已经讨论过的,有许多正确的方法来表达同一个句子。在许多 NLP 模型中,我们可能会得到多个可接受的目标句子来捕捉这些不同的变化。
我们用一个修正的精度公式来说明这两种情况,我们称之为“削波精度”。
限幅精度
让我们通过一个例子来理解它是如何工作的。
比方说,我们有以下句子:
- 他吃了一个甜苹果
- 他正在吃一个美味的苹果
- 预测句:呵呵,他吃美味的水果
我们现在做两件不同的事情:
- 我们将预测句子中的每个单词与所有目标句子进行比较。如果该单词匹配任何目标句子,则认为它是正确的。
- 我们将每个正确单词的计数限制为该单词在目标句子中出现的最大次数。这有助于避免重复问题。这将在下面变得更加清楚。

裁剪精度(图片由作者提供)
例如,单词“他”在每个目标句子中只出现一次。因此,即使“他”在预测的句子中出现了三次,我们也将计数“裁剪”为一,因为这是任何目标句子中的最大计数。
裁剪精度=正确预测字数/总预测字数
削波精度= 3 / 6
注意:在本文的其余部分,我们将只使用“精度”来表示“削波精度”。
我们现在准备继续计算 Bleu 分数。
Bleu 评分是如何计算的?
假设我们有一个 NLP 模型,它可以生成如下的预测句子。为了简单起见,我们只取一个目标句子,但是和上面的例子一样,多个目标句子的过程非常相似。
- 因为下雨,警卫迟到了
- 因为下雨,警卫迟到了
第一步是计算 1-grams 到 4-grams 的精度分数。
精确 1 克
我们使用刚刚讨论过的限幅精度方法。
精度 1 克=正确预测的 1 克数/总预测的 1 克数

精度(图片由作者提供)
所以,精度 1 克( p₁ ) = 5 / 8
精确 2 克
精度 2-gram =正确预测的 2-gram 数/总预测的 2-gram 数
让我们看看我们预测的句子中所有的 2 个字母:

精确 2 克(图片由作者提供)
所以,精度 2-克( p₂) = 4 / 7
精确 3 克
同样,精确 3 克( p₃ ) = 3 / 6

精确 3 克(图片由作者提供)
精确 4 克
并且,精度 4 克( p₄ ) = 2 / 5

精确 4 克(图片由作者提供)
几何平均精度分数
接下来,我们使用下面的公式合并这些精度分数。这可以针对不同的 N 值并使用不同的权重值来计算。通常,我们使用 N = 4 和统一权重 wₙ = N / 4

精准评分(图片由作者提供)
简洁惩罚
第三步是计算“简洁代价”。
如果您注意到精度是如何计算的,我们可以输出一个由单个单词组成的预测句子,如“The”或“late”。对于这种情况,1 克的精度应该是 1/1 = 1,这表示满分。这显然是一种误导,因为它鼓励模型输出更少的单词并获得高分。
为了弥补这一点,简短惩罚惩罚太短的句子。

简洁处罚(图片由作者提供)
- c 是预测长度=预测句子的字数和
- r 是目标长度=目标句子的字数
这确保了简洁性损失不能大于 1,即使预测的句子比目标长得多。而且,如果你预测的字很少,这个值会很小。
在这个例子中,c = 8,r = 8,这意味着简洁代价= 1
Bleu 评分
最后,为了计算 Bleu 分数,我们用精确度分数的几何平均值乘以简洁性损失。

Bleu 评分(图片由作者提供)
可以针对不同的 N 值计算 Bleu 分数。通常,我们使用 N = 4。
- BLEU-1 使用 unigram 精度分数
- BLEU-2 使用一元和二元精度的几何平均值
- BLEU-3 使用一元、二元和三元精度的几何平均值
- 诸如此类。
如果你在互联网上查看不同的资源,你也可能会遇到一种稍微不同的方式来编写 Bleu 分数公式,这在数学上是等价的。

Bleu 评分公式(图片由作者提供)
在 Python 中实现 Bleu 评分
在实践中,您很少需要自己实现 Bleu 分数算法。nltk 库是 NLP 功能的一个非常有用的库,它提供了 Bleu Score 的实现。
现在我们知道了 Bleu Score 是如何工作的,还有几点我们应该注意。
Bleu 分数是基于语料库计算的,而不是单个句子
虽然我们使用了匹配单句的例子,但是 Bleu 分数是通过将整个预测语料库的文本作为一个整体来计算的。
因此,你不能单独计算语料库中每个句子的 Bleu 分数,然后以某种方式平均这些分数。
Bleu 评分的优势
Bleu Score 如此受欢迎的原因是它有几个优点:
- 它计算速度快,容易理解。
- 这与人类评价同一文本的方式一致。
- 重要的是,它是独立于语言的,这使得它可以直接应用于您的 NLP 模型。
- 当你有一个以上的基本真理句子时,可以使用它。
- 它的应用非常广泛,这样可以更容易地将您的结果与其他工作进行比较。
Bleu 评分的弱点
尽管广受欢迎,但 Bleu Score 一直因其弱点而受到批评:
- 它不考虑单词的意思。对于一个人来说,用一个不同的词表达同样的意思是完全可以接受的,比如用“守夜人”而不是“警卫”。但是 Bleu Score 认为这是一个不正确的词。
- 它只查找完全匹配的单词。有时同一个词的一个变体可以被使用,例如“rain”和“raining ”,但是 Bleu Score 认为这是一个错误。
- 它忽略了单词的重要性。使用 Bleu Score,与句子不太相关的不正确单词(如“to”或“an ”)会受到与对句子意义有重要贡献的单词同样严重的惩罚。
- 它不考虑单词的顺序,例如,句子“警卫因下雨而迟到”和“因警卫而下雨迟到”将得到相同的(单字母组合)Bleu 分数,即使后者完全不同。
语音转文本应用使用单词错误率,而不是 Bleu 分数
虽然自动语音识别模型也输出文本,但是目标句子是明确的,并且通常不需要解释。在这种情况下,Bleu 分数不是理想的指标。
这些应用程序通常使用的度量标准是单词错误率(WER),或者它的兄弟,字符错误率(CER)。它一个字一个字地(或一个字符一个字符地)比较预测的输出和目标抄本,以计算出它们之间的差异。
差异可以是存在于转录本中但在预测中缺失的单词(被计为删除)、不在转录本中但已被添加到预测中的单词(插入)、或者在预测和转录本之间改变的单词(替换)。

统计转录本和预测之间的插入、删除和替换(图片由作者提供)
度量公式相当简单。它是差异相对于总字数的百分比。

单词错误率计算(图片由作者提供)
WER 计算是基于衡量两个单词之间差异的莱文斯坦距离。
尽管 WER 是语音识别中使用最广泛的度量标准,但它有一些缺点:
- 它不区分对句子意义重要的词和不相关的词。
- 在比较单词时,它不考虑两个单词是仅仅单个字符不同还是完全不同。
结论
希望这能让你理解 NLP 的两个最重要的指标,以及它的优点和缺点。
最后,如果你喜欢这篇文章,你可能也会喜欢我关于变形金刚、音频深度学习和地理定位机器学习的其他系列。
让我们继续学习吧!
自然语言处理的基础直观解释:波束搜索,它是如何工作的
实践教程,直观的 NLP 系列
波束搜索如何增强预测的简明指南

许多 NLP 应用程序,如机器翻译、聊天机器人、文本摘要和语言模型都会生成一些文本作为输出。此外,像图像字幕或自动语音识别(即语音到文本)输出文本,即使它们可能不被认为是纯 NLP 应用程序。
所有这些应用都使用一些常用的算法,作为产生最终输出的最后一步。
- 贪婪搜索就是这样一种算法。它经常被使用,因为它简单快捷。
- 另一种方法是使用波束搜索。它非常受欢迎,因为虽然它需要更多的计算,但通常会产生更好的结果。
在本文中,我将探索波束搜索,并解释为什么使用它以及它是如何工作的。我们将简单地讨论一下贪婪搜索作为比较,这样我们就能理解波束搜索是如何改进它的。
另外,如果您对 NLP 感兴趣,我还有几篇文章,您可能会觉得有用。他们还探索了这一领域的其他有趣主题,如变形金刚、语音转文本和 Bleu 评分标准。
- 变形金刚直观讲解:功能概述 (变形金刚怎么用,为什么比 RNNs 好。架构的组件,以及训练和推理期间的行为)
- 变压器如何工作,循序渐进 (内部操作端到端。数据如何流动以及执行何种计算,包括矩阵表示)
- 自动语音识别 (语音转文本算法和架构,使用 CTC 丢失和解码进行序列对齐。)
- Bleu 评分 ( Bleu 评分和单词错误率是 NLP 模型的两个基本指标
我们将从获得一些关于 NLP 模型如何产生它们的输出的上下文开始,以便我们能够理解波束搜索(和贪婪搜索)适合在哪里。
注意:根据他们正在解决的问题,NLP 模型可以生成字符或单词形式的输出。与波束搜索相关的所有概念都同样适用于这两个术语,因此我将在本文中交替使用这两个术语。
NLP 模型如何生成输出
让我们以序列到序列模型为例。这些模型经常用于机器翻译等应用。

机器翻译的序列对序列模型(图片由作者提供)
例如,如果这个模型被用来从英语翻译成西班牙语,它将把源语言中的句子(例如英语中的“You are welcome”)作为输入,并输出目标语言中的对等句子(例如西班牙语中的“De nada”)。
文本是单词(或字符)的序列,NLP 模型构建了由源语言和目标语言中的整个单词集组成的词汇表。
该模型将源句子作为其输入,并将其通过一个嵌入层,随后是一个编码器。然后,编码器输出压缩捕获输入的基本特征的编码表示。
然后,这种表示与一个“
然后通过输出层传递,输出层可能由一些线性层和一个 Softmax 组成。线性层在输出序列中的每个位置输出词汇表中每个单词出现的可能性的得分。然后 Softmax 将这些分数转换成概率。

词汇表中每个字符在输出序列中每个位置的概率(图片由作者提供)
当然,我们的最终目标不是这些概率,而是最终的目标句子。要做到这一点,模型必须决定它应该为目标序列中的每个位置预测哪个单词。

该模型根据概率预测输出句子(图片由作者提供)
它是怎么做到的?
贪婪搜索
一个相当显而易见的方法是简单地选择在每个位置上概率最高的单词并预测它。它计算速度快,容易理解,而且经常能得出正确的结果。

贪婪搜索(图片由作者提供)
事实上,贪婪搜索是如此容易理解,我们不需要花更多的时间来解释它😃。但是我们能做得更好吗?
啊哈,终于说到我们真正的话题了!
波束搜索
波束搜索对贪婪搜索进行了两项改进。
- 通过贪婪搜索,我们在每个位置只取一个最好的单词。相比之下,波束搜索扩展了这一点,并选取了最佳的“N”个单词。
- 使用贪婪搜索,我们孤立地考虑每个位置。一旦我们确定了最适合那个职位的词,我们就不会检查它之前是什么。在前一个位置),或者在它之后。相比之下,波束搜索选择目前为止的“N”个最佳序列,并考虑所有前面的单词与当前位置的单词组合的概率。
换句话说,它把“搜索的光束”投射到比贪婪搜索更广的地方,这就是它的名字。超参数“N”称为波束宽度。
直觉上,这给了我们比贪婪搜索更好的结果。因为,我们真正感兴趣的是最好的完整句子,如果我们在每个位置只选择最好的单个单词,我们可能会错过它。
波束搜索—它的作用
让我们举一个简单的例子,波束宽度为 2,并使用字符来保持简单。

波束搜索示例,宽度= 2(图片由作者提供)
第一位置
- 考虑模型在第一个位置的输出。它从“
”标记开始,获取每个单词的概率。它现在选择了那个位置的两个最好的字符。例如“A”和“C”。
第二胎位
- 当到达第二个位置时,它重新运行模型两次,通过将可能的字符固定在第一个位置来生成概率。换句话说,它将第一个位置的字符约束为“A”或“C ”,并生成两个具有两组概率的分支。具有第一组概率的分支对应于在位置 1 具有“A ”,具有第二组概率的分支对应于在位置 1 具有“C”。
- 它现在基于前两个字符的组合概率,从两组概率中挑选出总共两个最佳字符对。所以它不会只从第一组中选择一个最佳字符对,从第二组中选择一个最佳字符对。例如“AB”和“AE”
第三位置
- 当它到达第三个位置时,它重复这个过程。它通过将前两个位置约束为“AB”或“AE”来重新运行模型两次,并再次生成两组概率。
- 再一次,它根据两组概率中前三个字符的组合概率来挑选两个最佳字符三元组。因此,对于前三个位置,我们现在有两个最佳的字符组合。例如“美国广播公司”和“AED”。
重复直到结束标记
- 它继续这样做,直到它挑选一个“
”标记作为某个位置的最佳字符,然后结束序列的那个分支。
它最终以两个最佳序列结束,并预测具有更高总体概率的序列。
波束搜索——工作原理
我们现在从概念上理解了波束搜索。让我们更深入一层,了解这是如何工作的细节。我们将继续同一个例子,使用波束宽度 2。
继续我们的序列到序列模型,编码器和解码器可能是一个由一些 LSTM 层组成的递归网络。或者,它也可以使用变压器而不是循环网络来构建。

基于 LSTM 的序列对序列模型(图片由作者提供)
让我们关注解码器组件和输出层。
第一位置
在第一个时间步中,它使用编码器的输出和一个“

第一个位置的字符概率(图片由作者提供)
现在,它选择两个概率最高的字符,例如“A”和“C”。
第二胎位
对于第二个时间步长,它像以前一样使用编码器的输出运行解码器两次。与第一个位置的“

第二个位置的字符概率(图片由作者提供)
它为第二个位置生成字符概率。但这些都是个别人物的概率。它需要计算前两个位置的字符对的组合概率。假设“A”已经固定在第一个位置,则“AB”对的概率是“A”出现在第一个位置的概率乘以“B”出现在第二个位置的概率。下面的示例显示了计算过程。

计算字符对在前两个位置的概率(图片由作者提供)
它对两次解码器运行都这样做,并在两次运行中挑选具有最高组合概率的字符对。因此,它选择“AB”和“AE”。

该模型根据组合概率挑选两个最佳字符对(图片由作者提供)
第三位置
对于第三时间步,它再次像以前一样运行解码器两次。与第一个位置的“

第三个位置的字符概率(图片由作者提供)
它计算前三个位置的字符三元组的组合概率。

计算前三个位置的字符三元组的概率(图片由作者提供)
它在两次运行中选择两个最好的,因此选择“ABC”和“AED”。

该模型基于组合概率挑选两个最佳字符三元组(图片由作者提供)
重复直到结束标记
它重复这个过程,直到生成两个以“
然后,它选择具有最高组合概率的序列进行最终预测。
结论
这让我们了解了波束搜索是做什么的,它是如何工作的,以及为什么它能给我们更好的结果。这是以增加计算量和执行时间为代价的。因此,我们应该评估这种权衡对于我们的应用程序用例是否有意义。
最后,如果你喜欢这篇文章,你可能也会喜欢我关于音频深度学习、地理位置机器学习和图像字幕架构的其他系列。
让我们继续学习吧!
2021 年 4 月要读的四篇深度学习论文
思想和理论
从元梯度到时钟值,神经网络的全局工作空间理论和训练稳定性的边缘

欢迎来到四月版的【T2:机器学习拼贴】系列,在这里我提供了不同深度学习研究流的概述。那么这个系列是关于什么的呢?简单地说,我为我最近最喜欢的一篇论文起草了一张幻灯片的视觉摘要。每一周。在月末,所有的视觉拼贴画都被收集在一篇总结性的博客文章中。因此,我希望给你一个视觉和直观的深入了解一些最酷的趋势。所以,废话不多说:这里是我在 2021 年 3 月读过的四篇最喜欢的论文,以及为什么我认为它们对深度学习的未来很重要。
“通过元学习子目标发现选项”
作者:Veeriah 等人(2021) 📝论文
一段话总结:电机控制是一个极具挑战性的问题。我们人类非常擅长这一点,因为我们在多个扩展的时间尺度上进行规划:我们不是绘制出每一个肌肉动作,而是在抽象的层面上进行推理,并执行一系列精细的动作。分层强化学习(HRL)旨在借助所谓的时间抽象来模仿这种方法。简单地说,时态抽象就是一个在一段时间内执行的机动程序。选项(萨顿等人,1999 )是这种时间抽象的一种特殊类型。它们由一个子策略和一个相应的终止条件组成。选项策略由更高级别的管理器调用并执行,直到终止条件停止它。HRL 的一个关键问题是如何自动推断出有用的选项,这些选项可以在多项任务中转换?Veeriah 等人(2021)提出通过元梯度学习选项参数化。在外环中,元梯度通过优化更新步骤过程传播高阶梯度来优化超参数,这取决于它们(以可微分的方式)。在本文中,优化的超参数被选择为指定选项的神经网络。所提出的称为 MODAC 的多寿命元梯度方法能够发现有用的选项,这些选项转移到新的设置,其中仅允许管理器策略被重新训练。因此,元梯度方法可以从任务分布中提取有意义的规律。他们在一个标准的四个房间的问题上测试他们的方法,然后将其扩展到更具挑战性的 DeepMind 实验室领域。

ML-Collage [9/52]:数字改编自 Veeriah 等人(2021) |📝论文
“发条变分自动编码器”
作者:Saxena 等人(2021) 📝论文
一段话总结:递归生成模型在生成长序列的清晰图像和捕捉视频中的长期依赖关系方面存在困难。Saxena 等人(2021)的时钟变分自动编码器(CW-VAE)旨在通过扩展递归状态空间模型(RSSM;Hafner et al. 2019),这是一类复发性 VAEs。CW-VAEs 的核心是通过引入以不同固定时钟速度变化的潜在时间层次来扩展这些潜在动态模型。顶层以较慢的速率适应,并调节较低层的生成过程。等级越低,速度越快。在最低层,该模型通过转置 CNN 的上采样输出生成的图像。使用证据下限(ELBO)目标对整个递归 VAE 架构进行端到端训练。作者证明,这种动态潜在变量的时间抽象层次优于许多基线,这些基线不包含潜在层次或所有级别以相同的速度跳动。我特别喜欢 cool ablation 研究,它旨在提取存储在不同级别的内容信息。通过切断流入顶层的输入信号,作者能够证明顶层向较低层提供全局非特定信息。最后,他们还表明,潜在的动态能够适应预先条件序列输入的速度:高频序列导致更多的信息被快速的低水平潜在变量捕获。总之,作用于不同时间尺度的机制的层次结构不仅对于强化学习非常有用,而且对于生成模型也非常有用。

ML-Collage [10/52]:数字改编自 Saxena 等人(2021) |📝论文
“通过共享的全局工作空间协调神经模块”
作者:Goyal 等人(2021) |📝论文
一段话总结:最突出的意识理论之一是全球工作空间理论。它提出了一个简单的认知架构,其中经过处理的感官知觉被投射到一个共享的工作空间,也称为“黑板”。来自不同来源的信息被选择性地写入这个工作空间,并被下意识地处理。这个处理阶段集成了不同的模态并丢弃了不相关的特征。之后,转换后的信息被传播到与意识过程相关的其他大脑区域。Goyal 等人(2021)从这种高级意识的神经科学理论中获得灵感,并概述了一种将工作空间与注意力机制相结合的计算框架,以促进学习到的神经模块之间的协调。更具体地说,作者提出了一个低维瓶颈(也称为共享工作空间)来促进专家模块的同步。不同的神经网络(例如变压器或不同的 LSTMs)必须竞争写入“瓶颈”工作区。然后,基于软或硬注意机制更新输出表示。关键思想是带宽限制有助于独立但整合的机制的协调学习。使用一组详尽的实验,作者表明,所提出的机制促进了模块之间的专业化,并有助于稳定它们的端到端训练。此外,工作空间的低维特性减少了专家之间昂贵的成对注意力交互。因此,它不仅有益于训练,而且有益于推理。

ML-Collage [11/52]:图片改编自 Goyal 等人的作品(2021) |📝论文
“神经网络上的梯度下降通常发生在稳定性的边缘”
作者:科恩等人(2021) 📝论文
一段话总结:深度学习中最迷人但仍未得到充分解释的观察结果之一是,我们似乎能够仅使用随机梯度下降等简单算法来有效优化数十亿个参数。但是我们对学习动力和趋同行为到底了解多少呢?Cohen 等人(2021 年)后退一步,研究批次由整个数据集组成时梯度下降的特殊情况。作者表明,这种全批次梯度下降版本在一个非常特殊的制度。也就是说,处于“稳定的边缘”。这个边缘是关于什么的?神经网络训练有两个阶段:在最初的第一阶段,训练损失 Hessian(也称为锐度)的最大特征值逐渐增加,直到它达到 2/学习速率。在这个阶段,训练损失单调下降。一旦这个特征值达到 2/学习率,就达到了“稳定边缘”。之后,梯度下降抑制了清晰度的进一步增长。相反,它徘徊在 2/学习率阈值之上。在短时间内,训练损失不再表现为单调,而是波动的。但是在更长的时间尺度上,梯度下降仍然可以减少损失。作者通过多项任务和不同架构(包括标准 CNN 和变压器)验证了这一经验观察。由此产生的发现质疑了关于梯度下降的传统优化智慧的许多方面:梯度下降如何抑制清晰度的持续增长?这对学习费率表意味着什么?我们真的需要让它们随着时间退火吗?好的科学工作开启了许多有趣的未来研究问题,这项工作无疑属于这一范畴。

ML-Collage [12/52]:数字改编自 Cohen 等人(2021) |📝论文
这是这个月的。让我知道你最喜欢的论文是什么。如果你想获得一些每周 ML 拼贴输入,查看 Twitter 上的标签# ML collage。你也可以看看我上一篇博文中的拼贴画:
最后,如果你想了解更多关于 RL 和其他领域的元梯度的潜力,你可以查看我以前的调查博客。我也有机会在最近的 ML Street Talk 播客插曲中采访了主要的元渐变作者之一——来自 DeepMind 的汤姆·萨哈维:
2021 年 8 月要读的四篇深度学习论文
从优化器基准到网络剖析,视觉变形器&彩票子空间

欢迎来到八月版的【T2:机器学习拼贴】系列,在这里我提供了不同深度学习研究流的概述。那么什么是 ML 拼贴呢?简单地说,我为我最近最喜欢的一篇论文起草了一张幻灯片的视觉摘要。每一周。在月底,所有由此产生的视觉拼贴都被收集在一个摘要博客帖子中。因此,我希望给你一个视觉和直观的深入了解一些最酷的趋势。所以,废话不多说:这里是我在 2021 年 7 月读过的四篇我最喜欢的论文,以及为什么我认为它们对深度学习的未来很重要。
“穿越拥挤的山谷——深度学习优化器的标杆”
作者:施密特、施耐德、亨宁(2021) |📝论文 | 🗣 谈话 |🤖代码
一段话总结:调优优化器是每个基于深度学习的项目的基本成分。存在许多试探法,例如臭名昭著的学习率起点 3e-04(又名卡帕西常数)。但是,我们能超越轶事,提供跨任务空间优化器性能的一般见解吗?在他们最近的 ICML 论文中,Schmidt 等人(2021)通过运行超过 50,000 次训练运行的大规模基准来调查这个问题。他们针对不同的调优预算、训练问题和学习率计划,比较了 15 种不同的一阶优化器。虽然他们的结果并没有确定一个明确的赢家,但他们仍然提供了一些见解:
- 不出所料,不同优化器的性能很大程度上取决于所考虑的问题和调优预算。
- 评估多个优化器的默认超参数大致与优化单个优化器的超参数一样成功。这可能是由于自适应方法(如 Adam)的隐含学习速率表。
- 平均来说,添加一个未调优的学习率计划可以提高性能,但是相关的差异相当大。
- 亚当仍然是一个强大的基线。较新的方法无法始终胜过它,突出了专门优化器的潜力。
不幸的是,该基准不包括任何深度 RL 或 GAN 风格的训练任务。尽管如此,这样的实证研究帮助了那些在有限的计算中挣扎的从业者。

ML-Collage [25/52]:作者的数字。|📝论文
“理解深度神经网络中单个单元的作用”
作者:鲍尔等人(2020) |📝论文 | 🗣 谈话 |🤖代码
一段话总结:理解卷积神经网络(CNN)中个体激活的功能性作用具有挑战性。Bau 等人(2020)揭示了与语义概念相关的单元的出现(即过滤器激活)。他们引入了“网络剖析”——一个系统识别这种语义的框架。通过将卷积过滤器产生的上采样激活与语义分割模型的预测进行比较,他们定义了概念一致性分数。该技术被应用于 VGG-16 场景分类器和在厨房图像上训练的渐进 GAN。对于基于 CNN 的分类器,他们观察到与物体和部分相关的单元出现在后面的层中,而前面的层主要与颜色相关。作者表明,这种神经元对于网络的分类准确性非常重要,它们的切除会损害性能。另一方面,对于生成器网络,在早期层中可以更频繁地发现对象/部分神经元,而后期层则专注于颜色。这凸显了一个训练有素的辨别网络和一个必须生成场景的网络之间的信息流差异。最后,GAN 的生成输出可以通过人工修剪概念单元来进行因果操作。这开启了许多围绕靶向特定神经元的有趣应用,例如对立的例子和图像的结构化印记。

ML-Collage [26/52]:作者的数字。|📝论文
ConViT:用软卷积电感偏置改善视觉变压器
作者:d'Ascoli 等人(2021) |📝纸张 |🤖代号
一段话总结:卷积提供了很强的电感偏置。隐含的重量共享和局部性概念导致翻译等值变异,使人想起在初级视觉皮层中观察到的激活模式。尽管在小数据领域表现强劲,但 CNN 在捕捉空间长程相关性方面仍存在困难。另一方面,视觉变形器和它们的自我注意机制是灵活的,并且擅长于大数据体制。但是它们需要许多参数、数据和某种形式的预先训练或提炼。d'Ascoli 等人(2021)试图通过引入门控位置自我注意(GPSA)来获得两个世界的最佳结果。GPSA 为位置 SA 配备了软卷积感应偏置,并且具有额外的自由来逃离局部性。它充当普通软注意层的插入,并且可以被初始化以模仿卷积。训练过程可以调整门控参数,该门控参数调节对位置和内容信息的关注。作者表明,与标准视觉转换器架构相比,这导致 ImageNet 在样本和参数效率方面的显著改善。此外,他们还分析了不同的 GPSA 层和他们的头部对局部性的了解程度。有趣的是,他们发现早期层保留了更多的局部化初始化,而后期层则更多地关注内容信息。

ML-Collage [27/52]:作者的数字。|📝论文
“我们需要多少自由度来训练深度网络:损失景观视角”
一段话总结:彩票假说假设稀疏可训练神经网络的存在。它质疑过度参数化在优化网络中的作用。但是为什么会这样呢?有什么理论支撑,又是什么决定了稀疏度?Larsen 等人(2021)根据达到期望损失子水平集的成功概率推导出一个理论。直观地说,随着网络可用的自由度越来越多,这种可能性也越来越大。但是有更关键的因素决定所需的维数:参数子空间与子水平集的距离及其几何形状。作者证明了一个强有力的定理,该定理将戈登逃脱定理推广到一般集合。主要结果强调了成功概率中存在相变。当从更好的初始化开始时,需要更少的维度。直觉上,看向一个随机方向(子空间)并看到月亮(损失子水平集)的概率取决于你与月亮的距离。作者针对各种架构/问题设置验证了这些理论见解,并提出了所谓的“彩票子空间”:通过利用来自先前训练运行的信息,他们基于轨迹的 top-d 主分量构建了参数的低维投影。他们表明,对于可比的压缩比,这些子空间约束的神经网络甚至可以胜过彩票。

ML-Collage [28/52]:作者的数字。|📝论文
这是这个月的🤗让我知道你最喜欢的论文是什么。如果你想获得一些每周 ML 拼贴输入,查看 Twitter 上的标签# ML collage。你也可以在最后的总结中找到拼贴画📖博客帖子:
2021 年 12 月要读的四篇深度学习论文
从感官替代到决策转换器、持续进化策略和敏锐感知最小化

欢迎来到 12 月份的【T2:机器学习-拼贴】系列,在这里我提供了不同深度学习研究流的概述。那么什么是 ML 拼贴呢?简单地说,我为我最近最喜欢的一篇论文起草了一张幻灯片的视觉摘要。每一周。在月底,所有由此产生的视觉拼贴都被收集在一个摘要博客帖子中。因此,我希望给你一个视觉和直观的深入了解一些最酷的趋势。所以,废话不多说:这里是我在 2021 年 11 月读过的四篇我最喜欢的论文,以及为什么我认为它们对深度学习的未来很重要。
‘作为变压器的感觉神经元:用于强化学习的排列不变神经网络’
一段话总结:人类有令人难以置信的可塑性适应能力。我们可以从很少的数据中学习交换完全分离的感觉形态的信息流。例如,人类能够使用电极阵列学习用舌头看东西。这种现象通常被称为感官替代。另一方面,众所周知,神经网络易受输入空间变化的影响。例如,dqn 很难处理颜色变化或噪声扰动 (Lake et al .,2016) 。那么,我们如何才能让神经网络变得更加健壮呢?他们会比我们人类更容易被塑吗?唐&哈(2021)在这个方向上迈出了第一步,提出了一组受变压器启发的代理,将本地信息组合成一个全局代码。该架构通过设计是位置不变的,并且在不同的输入维度上共享参数。因此,网络处理一组任意排序的输入维度或面片。此外,它是循环的,因此甚至可以捕捉在线发生的排列。如果需要,这可以允许网络恢复。作者使用进化策略来训练网络,并表明它能够处理低维控制和高维视觉任务的混乱,嘈杂和闭塞的输入。此外,当输入被混洗时,潜在代码不改变,这表明模型确实已经学习了输入不变性。最后,他们提出了一种简单的行为克隆方法,使用非排列不变专家来有效地教授排列不变学生。

ML-Collage [33/52]:作者的数字。|📝论文
“决策转换器:通过序列建模进行强化学习”
作者:陈、陆等(2021) |📝论文 | 🗣 谈话 |🤖代码
一段话总结:强化学习问题从根本上来说是硬的。一个空白的代理人必须处理探索问题,面对不断变化的数据分布,并且必须从嘈杂且通常稀疏的奖励信号中学习。普通的 RL 算法试图通过利用自举的概念来求助于近似的动态规划:代理基于环境回报信号和未来回报的另一个估计的组合来改进它自己的估计。这在例如 DQNs 中是成功的,但是由于预测目标的变化性质,这也可能破坏学习动力。决策转换器(Chen 等人,2021)将 RL 问题颠倒过来,并将其视为条件轨迹生成问题。更具体地说,在屏蔽掉序列中的未来轨迹之后,变压器被训练来自动回归预测动作。变压器以先前的状态和动作序列以及观察到的返回为条件。因此,网络可以被“操纵”以完成所观察剧集的剩余部分。它在长度为 K 的序列的离线轨迹缓冲器上被训练。作者表明,这种生成建模方法优于传统的行为克隆和标准的离线 RL 基线。此外,变压器有效地学习对回报分布建模。这意味着人们可以向网络提供一个目标回报作为输入,而代理实际上设法生成一个实现它的轨迹。这意味着网络不仅学会了模仿,还能概括预期收益。此外,决策转换器可以很好地处理稀疏奖励,并学习根据其观察到的轨迹不断更新其奖励概率。

ML-Collage [34/52]:作者的数字。|📝论文
‘具有持续进化策略的展开计算图中的无偏梯度估计’
作者:Vicol 等人(2021) |📝论文
一段话总结:现代深度学习充满了展开的优化问题:例如训练递归网络,基于梯度的元学习如 MAML,通过动力学模型进行区分或训练已学习的优化器。最终,这需要通过一个动态系统传播梯度,这可能导致梯度消失或爆炸。为了克服这种不稳定性,研究人员经常求助于进化策略,这种策略避开了解析梯度的显式计算。相反,它们依赖于对网络参数群体的评估,并基于观察到的适应度来构建“进化梯度”。所得到的梯度是无偏的(与随时间截短的反向传播 TBPTT 相比),但是没有从截短的展开所带来的存储优势中获益。Vicol 等人(2021)引入了持续进化策略(PES),它允许通过一系列截断展开进行无偏梯度估计。这是通过累积与用于生成网络群体的噪声相关联的校正项来实现的。作者导出了一个二次损失的理论结果,并提供了一个可以利用解析梯度知识的版本。该算法为标准的开放 NES 算法提供了一个易于实现的补充,作者表明它在一组基准任务上表现良好:这些任务包括优化用于训练神经网络的超参数,训练已学习的优化器,甚至更有效地训练 RL 代理。与传统的 ES 梯度相比,PES 梯度导致更低的损耗,并表现出小得多的变化。

ML-Collage [35/52]:作者的数字。|📝论文
‘有效提高泛化能力的清晰度感知最小化’
作者:Foret 等人(2021) |📝纸张 |🤖代码(JAX) |🤖代码(PyTorch)
一段话总结:“平坦最小值假说”( Hochreiter & Schmidhuber,1997 )将损失面的几何形状与神经网络的泛化特性联系起来。低曲率网络通常可以获得更好的测试性能。直观上,参数空间中的鲁棒性隐含着输入空间中的鲁棒性。如果我们可以摆动 W,我们可以摆动 Foret 等人(2021)的锐度感知最小化(SAM)直接将这种直觉表述为目标函数。更具体地,作者提出联合最小化训练损失值及其锐度。因此,优化过程在具有均匀低损耗的邻域中寻找参数。这样做需要解决最小-最大优化问题:最小化关于参数的损失,同时在固定半径邻域内最大化它。作者提供了最大化问题的有效近似,它基于一阶泰勒级数近似和对偶范数问题的解。最终,这归结为另一个反向传递的额外计算成本。他们表明,当从头开始训练时,这种简单的修改导致许多数据集、增强和模型的测试性能提高。此外,在许多情况下,使用 SAM 对预训练网络进行微调也会得到改善。此外,该模型对标签噪声下的训练更具鲁棒性。在 CIFAR-10 的嘈杂版本中,他们显示 SAM 与为这种情况设计的专用数据增强技术相比非常有竞争力。最后,他们根据经验分析了找到的最小值的曲率,并表明与没有 SAM 训练的模型相比,它表现出更小的曲率。

ML-Collage [36/52]:作者的数字。|📝论文
这是这个月的🤗让我知道你最喜欢的论文是什么。如果你想获得一些每周 ML 拼贴输入,查看 Twitter 上的标签# ML collage。你也可以在最后的总结中找到拼贴画📖博客帖子:
2021 年 2 月要读的四篇深度学习论文
入门
从神经科学到自动分化,神经网络理论&神经过程中的欠拟合

您是否希望更好地了解目前正在进行的不同深度学习研究流?您是否有太多打开的 arXiv 标签,以至于无法浏览?看完整视频时间太少?如果有一篇论文的关键思想和概念的快速总结就好了。然后我很高兴地向大家介绍:机器学习拼贴’系列。在这个系列中,我为我最近最喜欢的一篇论文起草了一张幻灯片的视觉摘要。每一周。到了月底,我会把所有的拼贴画收集到一篇总结性的博客文章中。这是第一版。以下是我在 2021 年 1 月读到的四篇我最喜欢的论文,以及我为什么认为它们很重要。
“无监督深度学习识别单个 IT 神经元中的语义解缠结”
作者:希金斯等人(2020) |📝论文
一段总结:Ramon y Cajal 提出的“神经元学说”指出,神经系统由独立的离散单元组成。这导致人们特别强调神经元是认知计算的核心。从那以后,细胞神经科学迅速从单细胞记录转向群体记录,越来越多的工作集中在神经元群体的潜在集体动力学上。随着神经科学研究的焦点转移,神经元学说也被新的群体学说所掩盖。Higgins 等人(2020 年)回到过去,研究了猕猴下颞(IT)皮层中的-VAEs 潜在代码如何模拟单个神经元记录。他们发现,当改变视觉刺激的不同语义特征时,解开的潜在单位可以很好地解释单细胞活动的大部分变化。此外,他们发现增加的解缠结(更高)导致神经数据的更好拟合。这提供了证据表明,它的神经元可能实际上服务于一个特定的功能:语义视觉概念的分离。最后,Higgins 等人(2020)表明,在人脸上训练的 VAEs 实际上可以基于非常有限的神经记录(最多只有 12 个神经元)来重建视觉刺激。

ML-Collage [1/52]:数字改编自 Higgins 等人(2020) |📝论文
“随机自动微分”
作者:奥克泰等人(2020) 📝论文 | 🗣 谈话 |🤖代码
一段话总结:反向模式自动微分(AD)又名反向传播是现代深度学习成功故事的支柱。我们使用链式法则、由模型定义的线性化计算图、可区分的目标…以及随机采样的小批量数据来计算梯度。所以最后我们只能依靠随机估计。从统计学的角度来看,这不是一个问题,事实上,人们长期以来一直在争论由随机梯度下降引起的隐式正则化。但是,如果我们完全接受随机性,我们能降低反向传播的记忆复杂性吗?Oktay 等人(2020)提出了两种随机修改:
1)从计算图中穿过的所谓鲍尔路径的二次采样。
2)在计算雅可比矩阵需要大量内存的位置注入随机矩阵。
得到的梯度估计是无偏的,但是具有较大的方差,这与减少的存储器需求相权衡。对于标准的 MLP、CNN & RNN 设置,给定固定的内存预算,他们提出的随机 AD 算法优于经典 AD,并且可以帮助解决更多的问题。

ML-Collage [2/52]:数字改编自 Oktay 等人(2020) |📝论文
“关于神经网络的谱偏差”
一段话总结 : ReLU 神经网络是通用函数逼近器。但是 ReLU nets 喜欢学习什么函数,以及学习动态如何调整拟合的函数空间?Rahaman 等人(2019)使用傅立叶分析表明,他们偏向于首先学习低频模式。它们提供了 ReLU 前馈网络的精确解析频谱分析以及可解释的上限。拟合的傅立叶分量取决于权重的谱范数,作者发现该范数(以及拟合的最高频率)在训练过程中增加。此外,他们根据经验表明,低频成分对随机参数扰动更为稳健。他们在简单的正弦和 MNIST 回归任务上验证了他们的见解。最后,他们介绍了一个花瓣分类任务,这表明数据流形的复杂性可以在很大程度上决定一项任务的学习难度。更复杂的流形可能更容易在傅立叶空间中吸收。这对对抗性鲁棒性的设计以及课程学习有直接的影响。

ML-Collage [3/52]:数字改编自 Rahaman 等人(2019) |📝论文
“注意力神经过程”
一段话总结:神经过程(NP)学习将上下文数据映射到回归函数的分布。传统上,这种映射是通过保持顺序不变的自动编码器架构来建模的。该架构在确定性输出路径和第二潜在路径之间进行分离,确定性输出路径捕获上下文中的局部结构,而第二潜在路径模拟与底层随机过程相关联的全局结构。为了在单个上下文点上聚合,NPs 意味着在确定性嵌入上聚合。Kim 等人(2019)认为,这导致了环境的淘汰和不适应。相反,他们建议使用注意机制来有效地学习 NPs 的参数化核函数。他们表明,尽管注意力增加了计算的复杂性,但获得一个好解的有效运行时间却大大减少了。此外,从几个像素进行图像重建可以产生清晰的视觉印象。正如在其他基于注意力的论文中常见的那样,它们表明多头注意力层的不同头关注不同的关键上下文点。

ML-Collage [4/52]:数字改编自 Kim 等人(2019) 📝论文
这是这个月的。让我知道你最喜欢的论文是什么。如果你想获得一些每周的 ML 拼贴输入,在 Twitter 上查看标签# ML collage。罗伯特·兰格
2021 年 7 月要读的四篇深度学习论文
从大规模深度 RL 到对抗性鲁棒性,SimCLR-v2 &学习神经网络空间

欢迎来到七月版的【T2:机器学习拼贴】系列,在这里我提供了不同深度学习研究流的概述。那么什么是 ML 拼贴呢?简单地说,我为我最近最喜欢的一篇论文起草了一张幻灯片的视觉摘要。每一周。在月底,所有由此产生的视觉拼贴都被收集在一个摘要博客帖子中。因此,我希望给你一个视觉和直观的深入了解一些最酷的趋势。所以,废话不多说:这里是我在 2021 年 6 月读过的四篇最喜欢的论文,以及为什么我认为它们对深度学习的未来很重要。
‘什么才是对政策有深度的演员的批评方法?大规模研究
作者:Andrychowicz 等人(2021) 📝纸 |🤖代码
一段话总结:政策上的深度强化学习代理是出了名的难调。结果的再现可能具有挑战性,并可能导致类似“深度 RL 还不起作用”的陈述。有一点是肯定的:深度 RL 训练循环不像训练有监督的 MNIST CNN 分类器那样防弹。那么,如何弥合这一差距呢?Andrychowicz 等人(2021 年)首次尝试对 DRL 超参数稳健性进行实证研究:他们训练了 25 万名代理人&评估 50 多个基本选择的超参数。这项研究是使用 MuJoCo 控制环境的子集和谷歌的 Seed RL 框架进行的,该框架为培训分布式演员-评论家代理提供了一个通用基础设施。作者比较了不同的政策损失目标,网络架构,优化,正则化和优势估计技术。他们的结果证实了许多常见的 DRL 智慧:例如,使用 PPO 裁剪目标、tanh 激活和训练单独的演员-评论家网络。但它们也强调了一系列新的见解:策略的初始化似乎相当重要,建议确保策略分布和观察的零均值和独立性。此外,观察值的平均归一化显著提高了性能。就我个人而言,我非常喜欢这种大规模的研究,并相信它们提供了一种有价值的资源,可以节省相当多的时间和令人头疼的调优问题。

ML-Collage [21/52]:作者的数字。|📝论文
‘模拟中枢神经系统前部的初级视觉皮层提高了对图像扰动的鲁棒性’
一段话总结:如何让卷积神经网络不那么容易受到对抗性攻击?Dapello 和 Marques 等人(2020)从我们的视觉皮层中获得灵感,并将 V1 的经典 Gabor 滤波器模型与标准计算机视觉架构相结合。更具体地说,他们提出将具有加性高斯噪声的固定权重生物约束滤波器组作为标准 CNN 的前端。他们称这个前端为 VOne 块,它与 1 乘 1 瓶颈一起为标准类 ResNet CNN 的第一卷积层提供了一个替代。作者表明,这种简单的前端块大大提高了对白盒攻击的鲁棒性,同时保持了有竞争力的 ImageNet 性能。他们执行了一组消融实验来解开滤波器组和随机性的贡献。他们的实验表明,类 V1 特征和随机性以非平凡的方式有益地相互作用:将两种成分结合起来的总改善超过了它们各自贡献的总和。作者推测,随机性不仅在推理时使攻击不那么有效,而且在训练时促进了健壮特征的学习。最后,作者表明,中枢神经网络的对抗性鲁棒性与其 V1 脑反应预测性相关。这篇论文提供了一个如何将深度学习与经过实验验证的自下而上的神经科学建模相结合的美丽例子。

ML-Collage [22/52]:作者的数字。|📝论文
‘大的自我监督模型是强的半监督学习器’
一段话总结:这些年来,我们已经看到了自我监督预培训的革命。这包括大型自然语言模型,如 GPT,以及对比预训练的计算机视觉模型,如 SimCLR-v1 和 MoCo 。一个关键的研究问题是如何充分利用未标记数据?我们如何仅使用无监督的信息来提取核心表示,这对下游任务是有用的?SimCLR-v1 使用图像不同的增强以及对比损失来最大化/最小化正/负图像对的代表性相似性。之后,使用少量标记数据对预训练的架构进行微调。因此,未标记的数据以一种纯任务不可知的方式被使用。在 SimCLR-v2 中,Chen 等人(2021)建议再次使用未标记的数据:在对网络进行微调后,仅使用未标记的示例将其预测提取到不同的架构中。因此,SimCLR-v2 结合了无监督的与任务无关的预训练,调整&特定于任务的提取。作者认为,这种对未标记示例的特定任务使用允许大型神经网络更好地传输它们的一般知识。较大的模型在“小标签数据体制”中表现出色,并且它们能够胜过那些纯粹使用监督分类损失训练的对应模型。最后,他们还表明,更深的投影头和第一个投影头的微调可以提高最终性能。

ML-Collage [23/52]:作者的数字。|📝论文
‘学习神经网络子空间’
一段话总结:还有什么比训练单个神经网络更好的呢?在一次运行中训练性能良好的网络的整个子空间。Wortsman 等人(2021)介绍了一种新的训练范例,它使得在 5 个步骤中训练神经网络的线性(或非线性)组合成为可能:1)独立初始化 m 神经网络。2)从 m-1 单工中取样一个点。3)基于先前采样的点计算 m 个网络的(可能是非线性的)组合。4)根据一批数据计算“连接”神经网络的损失。5)通过线性/非线性组合操作传播梯度,执行反向传播以更新 m 个网络。作者表明,这允许在 ImageNet 上训练表现良好的网络的整个线条、曲线和简化。此外,他们引入了正则化器,通过最小化 m 个网络端点之间的余弦相似性来促进功能多样性。直观上,子空间端点之间的距离由此被最大化。这有助于子空间中点,其对于标签噪声是鲁棒的并且被很好地校准。一个假设的原因可能是中点提供了一个不太尖锐的最小值,这已被证明可以更好地概括 (Dziugaite 和 Roy,2017) 。如果你对 Frankle 等人(2020)的线性模式连接的发现感兴趣,那么你会喜欢这篇文章。

ML-Collage [24/52]:作者的数字。|📝论文
这是这个月的🤗让我知道你最喜欢的论文是什么。如果你想获得一些每周 ML 拼贴输入,查看 Twitter 上的标签# ML collage。你也可以在最后的总结中找到拼贴画📖博客帖子:
[## 2021 年 6 月要读的四篇深度学习论文
towardsdatascience.com](/four-deep-learning-papers-to-read-in-june-2021-5570cc5213bb)
2021 年 6 月要读的四篇深度学习论文
从贝叶斯神经网络到自我监督学习、类别选择性和来自统计学的核心思想

欢迎来到六月版的【机器学习-拼贴】系列,在这里我提供了不同深度学习研究流的概述。那么什么是 ML 拼贴呢?简单地说,我为我最近最喜欢的一篇论文起草了一张幻灯片的视觉摘要。每一周。在月底,所有由此产生的视觉拼贴都被收集在一个摘要博客帖子中。因此,我希望给你一个视觉和直观的深入了解一些最酷的趋势。五月是一个相当不错的月份,包括虚拟 ICLR 2021 会议、ICML 审查决定以及 NeurIPS 截止日期。因此,让我们深入研究我在 2021 年 5 月读过的四篇最喜欢的论文,以及为什么我认为它们对深度学习的未来很重要。
“过去 50 年最重要的统计思想是什么”
作者:盖尔曼&韦赫塔里(2021) |📝论文
一段话总结:深度学习位于统计学和计算机科学的交汇点。许多流行的核心思想源于结合计算技巧来解决基本的统计问题。例如,权重正则化在统计学中有着悠久的传统,并允许在高维回归模型中进行推断。同时,稀疏性提高了所考虑变量的可解释性。或者变分推理——在贝叶斯深度学习和变分自动编码器中非常突出——它提供了一个优化框架来近似一个难以处理的贝叶斯推理。因此,重要的是反思统计的核心思想,并问问我们自己它们是如何塑造我们今天的思维的。Gelman 和 Vehtari (2021)提炼出 8 个核心思想:反事实因果推理、基于引导/模拟的推理、过度参数化模型&正则化、层次模型、通用计算算法、自适应决策、稳健推理和探索性数据分析。多好的名单啊!很难找到不属于这些类别的子领域。试试看。那么将他们团结在一起的共同主题是什么呢?它们合并多个范例,随数据缩放,并将拟合的模型与数据分开。总的来说,这是一个很好的周末读物,它提供了一个很好的历史发展概况。就我个人而言,我喜欢这一前景,包括统计的单元测试和可解释机器学习的近期努力的继续。

ML-Collage [17/52]:作者的数字。|📝论文
“贝叶斯神经网络后验概率到底是什么样子的”
作者:伊兹迈洛夫等人(2021) |📝论文
一段总结:贝叶斯深度学习有望提供校准的不确定性估计,以支持有效的决策和精心的预测。但这也带来了为数百万个权重参数推断高维后验概率的挑战。为了解决这个问题,人们提出了许多近似的方法。这包括深度集成,它通过组合来自多个模型的预测或平均场变分推断来获得不确定性。但是这些方法实际上有多接近真实的后验概率仍然是一个悬而未决的问题。伊兹迈洛夫等人(2021)试图通过哈密顿蒙特卡罗(HMC)和 512 个 TPU 来回答这个问题。HMC 提供了一个梯度引导的抽样程序,它规模很好,并保证从真实的后验渐近产生样本。在大规模并行化的推动下,作者研究了关于后验混合、链数以及后验近似质量的基本问题。他们发现更长的链和更平行的链有助于推断更准确的后验概率。在多项基准测试中,HMC 的表现优于所有其他被考虑的基准。作者指出,许多技术提供的置信度估计不一定反映它们在分类任务上的准确性。以前有人认为,“冷”回火后验分布——由温度系数锐化——表现明显更好。伊兹迈洛夫等人(2021 年)表明,这实际上是一个假象,可以通过在 CNN 中禁用数据增强和使用滤波器响应归一化来克服。绝对是所有贝叶斯深度学习爱好者的推荐读物。

ML-Collage [19/52]:数字改编自伊兹迈洛夫等人(2021) |📝论文
“巴洛双胞胎:通过减少冗余的自我监督学习”
作者:Zbontar,Ling 等(2021) |📝纸张 |🤖代码
一段话总结:还记得那个臭名昭著的乐村蛋糕以及相关的预测自我监督学习(SSL)是深度学习的未来吗?SSL 的核心是通过引导以前收集的数据样本来解决信用分配信号稀疏的问题。例如,这可以是视频序列预测、去噪或对先前灰度图像着色的形式。SSL 方法的一个流行前身是暹罗网络。在暹罗网络中,人们扭曲样本,并训练网络生成与原始样本的扭曲版本接近的表示。因此,网络被推动以捕捉核心特征并压缩输入。在现代版本中,这种联合嵌入训练通常依赖于一系列技巧,例如在两种表示生成机制之间引入不对称性。Zbontar,Jing 等人(2021)通过提出一个简单的信息瓶颈目标来克服这些诡计,该目标作用于嵌入表示的互相关矩阵。更具体地,对角线元素被推到接近 1,而非对角线元素因大于 0 而被惩罚。因此,两件事情同时完成:表示对于失真应该变得不变,并且不必要的分量的冗余被强制减少。作者在各种半监督学习任务上测试了他们的方法,并表明与其他基线不同,提出的 Barlow Twin 目标即使在小批量的情况下也能很好地工作,并且它随着表示的维度而不断改进。

ML-Collage [19/52]:数字改编自 Zbontar 等人(2021) |📝论文
“被认为有害的选择性:评估 DNNs 中类别选择性的因果影响”
一段话总结: OpenAI 的显微镜项目试图弄清楚人工网络中复杂的内部工作原理。他们还提供了一套美丽的可视化论证非常选择性活跃的神经元的存在和功能。这种现象让人想起在大脑中发现的著名的詹妮弗·安妮斯顿神经元。但是,对于神经网络正常工作来说,学习神经元类别选择性是必要的和/或充分的吗?Leavitt 和 Morcos (2021)通过引入正则化项来研究这个基本问题,正则化项促进/抑制神经元或特征图变得有选择性。在一组实验中,他们能够表明,如果类别选择性降低,在 TinyImageNet 上训练的 ResNets 的测试准确性可以提高。此外,如果选择性太高,甚至会损害性能。因此,尽管有很强的选择性,但神经网络似乎更有效。但是,网络能简单地学会“隐藏”正则化子的选择性吗,例如通过神经元的线性组合来分配它?作者表明这一假设没有证据。为此,他们比较了用不同正则化强度训练的神经网络的 CCA 转换表示。神经网络不是隐藏选择性,而是通过非仿射表示变换来抑制它。那么这对深度学习研究意味着什么呢?也许我们应该对神经/拟人化更谨慎一点,并尊重我们自己在分析人工神经网络时的偏见。

ML-Collage [20/52]:数字改编自 Leavitt 和 Morcos (2021) |📝论文
这是这个月的🤗让我知道你最喜欢的论文是什么。如果你想获得一些每周 ML 拼贴输入,查看 Twitter 上的标签# ML collage。你也可以在最后的总结中找到拼贴画📖博客帖子:
[## 2021 年 5 月要读的四篇深度学习论文
towardsdatascience.com](/four-deep-learning-papers-to-read-in-may-2021-706e02071473)
2021 年 3 月要读的四篇深度学习论文
思想和理论
从合成梯度到胶囊网络,网络训练守恒定律&多智能体生成模型

欢迎来到二月底的“机器学习-拼贴”系列,在这里我提供了不同深度学习研究流的概述。那么什么是 ML 拼贴画呢?简单地说,我为我最近最喜欢的一篇论文起草了一张幻灯片的视觉摘要。每一周。在月底,所有由此产生的视觉拼贴都被收集在一个摘要博客帖子中。因此,我希望给你一个视觉和直观的深入了解一些最酷的趋势。所以,废话不多说:这里是我在 2021 年 2 月读过的四篇我最喜欢的论文,以及为什么我认为它们对深度学习的未来很重要。
“理解合成梯度和解耦神经接口”
作者:Czarnecki 等人(2017) |📝纸张 |🤖代码
一段话总结:反向传播是当前深度学习革命的驱动力。从本质上讲,反向传播是对链式法则的图论解释:为了计算特定权重矩阵的损失梯度,我们必须首先计算正向传播中的必要梯度。但是如果我们不需要等待上游梯度的传播呢?合成梯度(SG)的框架试图通过使用误差梯度的代理模型来“解锁”向前和向后传递。该模型是同时学习的,并作为反向投影梯度的替代。SGs 可以对大规模分布式训练的神经模块进行解耦。我们可以在不同的加速器上以一种不纠缠的方式训练神经网络的不同部分。但是,潜在的机制是什么,以及由此产生的学习动力是否有一些理论保证?Czarnecki 等人(2017)证明了线性网络情况下线性 SG 模块的收敛保证。此外,他们表明,即使 SG 训练的网络实现了相同的功能,表示在各层之间更加分散。最后,他们介绍了不同的信用分配算法,如 backprop,SGs 和(直接)反馈校准的统一观点。所有这些都可以归结为多智能体问题:多个模块/网络同时学习“共谋”。

ML-Collage [5/52]:数字改编自 Czarnecki 等人(2017) |📝论文
“标准胶囊:处于标准姿势的无人监管胶囊”
一段总结:胶囊网络(Hinton et al .,2000)通过将特征分解为描述符和姿态来模拟层级关系。在一类变换下,描述符被训练为不变的(它们不会改变),而姿势被训练为等变的(它们以可预测的方式改变)。通过堆叠得到的特征并对它们进行端到端的训练,我们可以获得特征的层次结构,这些层次结构捕获输入部分之间的语义关系。Sun 等人(2020)将这种胶囊分解与注意机制一起应用于 3D 点云任务。不是使用预先对齐的点云,而是通过两次随机变换来增强对象。之后,胶囊网络学习在规范框架中表示两个变换的点云。整个过程是无人监督的,并且使用一组辅助目标来塑造表示特征。如同在自我监督学习中一样,所得到的特征可以用于不同的下游任务。这些包括自动编码和重建,但也点注册和简单的 SVM 分类。这表明网络已经学会了形成“心智图像”,这有利于以对象为中心的推理。

ML-Collage [6/52]:图改编自孙等(2020) |📝论文
“神经力学:深度学习动力学中的对称性和破缺守恒定律”
一段话总结:对深度神经网络的复杂学习动力学有一个坚实的理论把握是很难的。许多理论工作必须引入不切实际的假设,如线性激活或连续时间 SGD 动态。这些结果可能会提供一种直觉,但当你希望归纳为最先进的训练范式时,你仍然需要祈祷。Kunin 等人(2020 年)没有做出任何假设。相反,它们利用了 batch-norm 或 softmax 激活函数等常见操作引入的对称性。他们从统计物理学的角度出发,证明了这种运算会导致对称性,从而导致梯度和 Hessian 上的几何约束。另一方面,这些约束意味着在梯度流(SGD 的连续时间版本)下权重统计的守恒定律(例如,权重的和、范数或平方范数)。在对重量衰减、动量、批量随机性和离散时间进行了一些修改后,他们能够求解一个常微分方程。)描述了权重统计的时间演变。这表明他们的预测适用于在微型 ImageNet 数据集上训练的流行的 VGG-16 架构。总之,他们为推导实用的神经网络 Noether 定理提供了第一次尝试。

ML-Collage [7/52]:数字改编自库宁等人(2020) |📝论文
“使用程序化弱监督生成多智能体轨迹”
一段话总结:产生协调的多智能体行为是困难的。可能轨迹的空间在所考虑的因素的数量上呈指数增长。常见的方法利用中间变量,以便根据一些常见的静态输入来调节生成。但这些中间变量要么难以解释,要么推导/标注成本高昂。Zhan 等人(19’)提出利用弱编程标签来调节生成的变分 rnn。这些标签是通过廉价的启发式标签函数获得的,并提供了对共享宏意图的可解释的解释。宏观意图的动态可以通过第二个 RNN 的监督训练来学习。作者表明,宏观意图允许模型捕捉轨迹的多模态分布,并在篮球分析师的人类偏好研究中验证了他们的结果。该模型捕捉真实人类游戏的关键统计数据,并能够从相同的老化中生成一系列不同的协调轨迹。

ML-Collage [8/52]:数字改编自詹等(2019) |📝论文
这是这个月的。让我知道你最喜欢的论文是什么。如果你想获得一些每周 ML 拼贴输入,查看 Twitter 上的标签# ML collage。最后,你也可以看看之前的总结博文。
2021 年 5 月要读的四篇深度学习论文
思想和理论
从机器人的不对称自我游戏到网络的泛化,门控线性网络&元学习更新规则

欢迎来到四月底的“机器学习-拼贴”系列,在这里我将概述不同的深度学习研究流。那么什么是 ML 拼贴呢?简单地说,我为我最近最喜欢的一篇论文起草了一张幻灯片的视觉摘要。每一周。在月底,所有由此产生的视觉拼贴都被收集在一个摘要博客帖子中。因此,我希望给你一个视觉和直观的深入了解一些最酷的趋势。所以,废话不多说:这里是我在 2021 年 4 月读过的四篇最喜欢的论文,以及为什么我认为它们对深度学习的未来很重要。
“机器人操作中自动发现目标的不对称自我游戏”
作者:OpenAI 等人(2021) |📝纸张 |💻 WWW
一段话总结:一年半前,OpenAI 发布了他们令人印象深刻的关于学习灵巧操作来解决魔方的工作。训练程序依赖于 LSTM-PPO 代理,该代理基于日益复杂的自然课程消耗大量数据。早在 2019 年,这一课程是由一种名为自动领域随机化的技术构建的。在最近的工作中,OpenAI 提出了一种替代技术来创建丰富的训练分布:他们缩放不对称的自我游戏,以实现对看不见的对象的零镜头概括。更具体地说,他们在一个普通的求和游戏中训练了两个代理,Alice 和 Bob。Alice 在环境中跑来跑去,为 Bob 提供了一个目标状态。后来,鲍勃试图实现这个目标。它们相互竞争,就像在 GAN 设置中一样。与许多其他课程学习方法不同,我们总是确信目标状态必须是可达到的。为什么?因为爱丽丝的政策能够到达那里。因此,我们可以使用她的轨迹作为额外的监督学习信号。但是我们需要小心,因为这个演示很可能不是最佳的。OpenAI 只在 Bob 自己无法达到目标时使用监督。此外,为了稳定学习动态,OpenAI 建议对政策更新进行 PPO 风格的剪辑。作者称这种选择性且稳定的机制为“爱丽丝行为克隆”(ABC)。他们提供了一套广泛的消融,表明自我发挥涵盖了广泛的目标空间,ABC 提高了采样效率。

ML-Collage [14/52]:数字改编自 OpenAI 等人(2021) |📝论文
“深度引导框架:优秀的在线学习者是优秀的离线概括者”
作者:Nakkiran 等人(2021) |📝论文
一段话总结:研究神经网络中泛化的正确框架是什么?传统方法限制了测试和训练错误之间的泛化差距,难以为深度学习提供见解。通常,神经网络将训练误差降低到 0。在这种情况下,训练测试误差分解不能提供有效的见解。Nakkiran 等人(2021 年)提出研究不同的差距:在每个更新步骤中对新批次进行训练的网络之间的性能差异。“理想”世界又名。在线学习)和一个训练有素的网络。“真实的世界”又名。线下学习)。作者在一组合成数据集和通用架构上证明,这种差距在现实设置中似乎很小,这反过来允许以下猜想:离线学习中的一般化似乎等同于在线学习中的快速适应。那么为什么这可能是一个重要的见解呢?简而言之,它为研究深度学习工具箱中许多可以说是不透明的“黑客”开辟了一个新的视角。例如,在这篇论文中,作者讨论了 SGD 的隐式正则化、过度参数化和欠参数化,以及什么使数据增强技术变得优秀。

ML-Collage [13/52]:数字改编自 Nakkiran 等人(2021 年)|📝论文
“门控线性网络”
一段话总结:现代深度学习大多依靠反向传播和离线梯度下降训练。神经科学家声称,向前和向后传递所需的重量对称性以及误差的全局传播在生物学上是不可信的。另一方面,门控线性网络(GLNs)提供了一种新的神经架构家族,其通过凸规划被无反向传播地在线训练。每个神经元被直接训练来输出最终目标的预测,而不是学习渐进的特征层次。该预测被转发到另一层神经元,该层神经元再次被训练来预测目标。这就产生了专家混合的层次结构。训练参数是分配给相应输入预测的相对重要性。GLNs 允许边信息(又名。特征),其由上下文函数处理并允许权重的专门化。将混合预测堆叠在一起会产生一个决策边界,该边界线性地依赖于输入。线性度允许轻松检查预测的稳健性和其他条件不变的情况下的(如果一个输入维度发生变化,预测会发生什么?)可解释性。Veness 等人(2019 年)表明,GLNs 的局部性对抗灾难性遗忘,并且它们特别适合在线/单遍学习。

ML-Collage [15/52]:数字改编自 Veness 等人(2019) |📝论文
“元学习双向更新规则”
作者:桑德勒等人(2021) |📝论文
一段话总结:back prop 和 SGD 之后是什么?一个令人兴奋的未来方向是通用元学习,旨在学习归纳偏差和学习规则本身。训练包括学习算法的标准内循环执行和该算法的昂贵的外循环改进。在 BLUR(更新规则的双向学习)中,Sandler 等人(2021)提出元学习一个共享的低维基因组,它调节学习和推理。虽然在反向传播中有两种神经元状态(正向活动传播和反向梯度聚集),但模糊允许神经元具有任意数量的状态。然后,元学习基因组由一组小矩阵组成,当执行权重更新和任务相关信息的传播时,这些小矩阵确定这些不同状态如何相互作用。根据不同前馈网络训练运行的任务分布对矩阵进行元训练。得到的基因组能够在元序列分布上胜过 SGD,并且学习不同于对未知损失的简单梯度下降的非平凡更新过程。它概括了任务和前馈体系结构。然而,重要的是,基因组必须在一组由大型网络组成的训练运行中进行元训练,以便推广到小型网络。

ML-Collage [16/52]:数字改编自 Sandler 等人(2021) |📝论文
这是这个月的🤗让我知道你最喜欢的论文是什么。如果你想获得一些每周 ML 拼贴输入,查看 Twitter 上的标签# ML collage。您也可以查看去年四月版摘要中的拼贴画📖博客帖子:
2021 年 9 月要读的四篇深度学习论文
思想和理论
从 Auto-ML 到 Vision Transformer 培训&陈述和灾难性的 Fisher 爆炸

欢迎来到九月版的【T4:机器学习拼贴】系列,在这里我提供了不同深度学习研究流的概述。那么什么是 ML 拼贴呢?简单地说,我为我最近最喜欢的一篇论文起草了一张幻灯片的视觉摘要。每一周。在月底,所有由此产生的视觉拼贴都被收集在一个摘要博客帖子中。因此,我希望给你一个视觉和直观的深入了解一些最酷的趋势。所以,废话不多说:这里是我在 2021 年 8 月读过的四篇我最喜欢的论文,以及为什么我认为它们对深度学习的未来很重要。
‘Auto-sk learn 2.0:通过元学习实现自动学习’
一段总结: Auto-ML 有望消除繁琐的超参数手动调整和模型选择。一个例子是 Auto-Sklearn API ,它提供了一个简单的高级接口来自动评估多个预处理和模型拟合管道。以前的 Auto-ML 系统的一个关键因素是使用所谓的元特征,这些元特征最初是为手头的数据集计算的。然后,这些特征被用于选择“策略”,以便在解决方案空间中进行顺序搜索。策略选择基于到代表性数据集的元数据集的元特征距离。如果您的数据集与元数据集有很大不同,有时这可能会导致泛化问题。此外,很难设计代表性的元特征和调整 Auto-ML 算法本身的超参数。Auto-Sklearn 2.0 旨在通过引入两个修改来克服这两个挑战:首先,他们不依赖元功能,而是使用初始管道的元学习组合。最初,这些候选投资组合被评估,以便启动贝叶斯优化内部循环。其次,他们引入了元学习策略选择器,该选择器基于所考虑的数据集中的样本和特征的数量来规定模型选择策略(例如,交叉验证与简单维持评估)和预算分配策略(全额预算与更积极的连续减半)。因此,该系统更接近于一种分层的元-元方法。作者在 OpenML 基准上验证了他们提出的修改,并为 10 分钟和 60 分钟的时间预算提供了一种新的最先进的方法。

ML-Collage [29/52]:作者的数字。|📝论文
‘如何训练自己的 ViT?《视觉变形金刚》中的数据、增强和规则化
一段话总结:虽然视觉变压器(ViT)模型非常灵活,不需要预先支持归纳偏差(如卷积的平移等方差),但它们的训练协议可能相当复杂,最终结果可能对超参数敏感。Steiner 等人旨在研究计算预算、模型大小、增强/正则化和训练数据量之间的权衡。本文为从业者提供了有价值的见解,并展示了超过 50k ViT 训练运行的结果。具体来说,他们表明,通过使用数据扩充(例如,混合& RandAug)和模型正则化(例如,权重衰减& dropout)的正确组合,可以实现与基于 10x 数据训练的模型相当的模型性能。针对大数据预先训练的 vit 也会产生更适合下游传输的表示。此外,作者表明,仅微调单个最佳转换器(在预训练数据集上评估)通常会产生与基于微调数据选择的模型相当的模型。因此,对单个 ViT 进行微调,以便为您的传输应用获得良好的模型,这可能更具成本效益。最后,作者比较了不同的扩增和正则化技术。他们发现,数据扩充在更多情况下似乎比模型正则化更有效。总的来说,论文的主要优势在于他们使用了标准化的训练体系,这使得他们能够提出有证据支持的主张。

ML-Collage [30/52]:作者的数字。|📝论文
‘灾难性费希尔爆炸:早期费希尔矩阵影响泛化’
作者:Jastrzebski 等人(2021) 📝论文
一段话总结:经常有人读到深度学习中随机梯度下降的“隐式正则化”。但这实际上指的是什么呢?Jastrzebski 等人研究了一种由于使用大的学习率而产生的正则化。他们表明,在训练的早期,小的学习率会导致 Fisher 信息矩阵轨迹的强烈振荡。这种“爆炸”似乎会导致更差的最终概括,可以通过提高学习速度的训练来避免。基于这一认识,作者定义了一个显式正则化子,它促进了一个小的 Fisher 迹。他们表明,这个正则项缩小了学习率较小的训练运行的性能差距,并提供了正则项在训练早期使用时特别有效的证据。作者认为,这种效应可能是由有限的记忆造成的,并表明费希尔矩阵的轨迹与噪声样本的梯度成比例。通过惩罚轨迹,可以降低这些例子的学习速度并减少过度拟合。最后,他们表明,费希尔罚函数导致平坦的极小值(由黑森轨迹测量的低曲率),这已被证明是更好的概括。因此,本文的主要贡献在于将早期训练阶段的不稳定性与观察到的 Fisher 信息行为联系起来。

ML-Collage [31/52]:作者的数字。|📝论文
‘视觉变形金刚看起来像卷积神经网络吗?’
作者:Raghu 等人(2021) |📝论文
一段总结:视觉变形金刚如何解决任务?它们的表征结构与常规 CNN 相似还是完全不同?研究这个问题的一个强有力的工具是代表性相似性分析(RSA)。RSA 使用中心内核对齐来比较不同输入的两个网络层的激活。得到的数值度量告诉您这些表示有多相似。 Kornblith 等人(2019) 之前使用这种方法来揭示 ResNets 的计算力学。那么和 ViTs 相比有什么区别呢?令人惊讶的是,ViT 层在所有层中具有更一致的相似性。这意味着信息通过架构传播得更强。Raghu 等人表明这是由于两个原因:首先,自我注意机制允许在比局部卷积更早的阶段聚集全局信息。其次,ViTs 中的 skip 连接允许通过几十层来传递早期的聚合信息。如果在某个程序段训练一个禁用跳跃连接的 ViT,这将在所有前面的和所有后面的程序段之间实施“通信”分区。另一个发现是,ResNets 需要更多的早期层来获得用少量 ViT 层就能获得的表示。这也可能是因为注意力机制能够在早期整合全局信息。最后,作者表明,vit 需要在大量数据上进行训练,以学习位置的归纳偏差。甚至 ImageNet-1k 似乎也不够,只有谷歌内部的 JFT-300 数据集。

ML-Collage [32/52]:作者的数字。|📝论文
这是这个月的🤗让我知道你最喜欢的论文是什么。如果你想获得一些每周 ML 拼贴输入,查看 Twitter 上的标签# ML collage。你也可以在最后的总结中找到拼贴画📖博客帖子:
提升熊猫技能的四个功能
分配、映射、查询和分解。城里最热门的方法

介绍
无论你是数据科学家、数据工程师、数据分析师还是机器学习专家,你都必须处理表格数据。如果您是 Python 用户,那么在处理表格数据时,最常用的库是 Pandas 🐼。由于表格数据无处不在,Pandas 可能是所有美国数据人员中使用最多的库之一。
Pandas 提供了一个功能丰富的 API,用于转换数据和提取有价值的见解。不幸的是,许多人,包括过去的我自己,没有充分利用它提供的所有功能。这经常导致庞大、过度复杂和低性能的熊猫代码😔。
我想为改变这种情况做出贡献,并帮助你提升你的熊猫知识,这样你未来的代码将更好读,也更有性能💪!为此,在这篇文章中,我向你介绍四种不同的熊猫功能,即assign, map, query,和exlpode。当掌握了这些,我们就在考虑清晰度和性能的正确方向上迈出了一步!
你准备好了吗?我们开始吧!
神奇四侠
在我们研究具体的 Pandas 功能之前,我们首先需要一些数据来处理。在下面的例子中,我使用了著名的虹膜数据集。如果你不想为了获取数据而安装一个专用的库,只需输入data = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')就可以了。
在我们开始之前的最后一句话,下面的大多数例子在内容上可能没有太多意义,但是阐明了每个函数的细节。
都准备好了吗?让我们开始吧!
分配
我们要看的第一种方法是[assign](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.assign.html)方法。此方法允许您向数据帧添加列。代码最好用代码来解释,所以这里来一个例子
我们在这里做了什么?这相当容易!我们使用assign创建了两个新列,将这些列的名称作为关键字参数传递给函数,并使用为它们分配结果列应该包含的值。如您所见,要分配实际值,您有三种不同的选择。
- 您可以使用一个标量值,它将新列的所有条目设置为该值。
- 您可以使用一个数组或系列,这将导致该数组被用作列的值。该数组的长度必须与调用 assign-method 的数据帧的长度相同。
- 您可以使用一个函数,或者更一般的一个可调用函数,它将一个数据帧作为其唯一的输入,并返回一个标量或序列。当返回一个序列时,它的长度必须与输入数据帧的长度相同。
这个选项的巧妙之处在于,可调用函数的输入数据帧就是调用 assign-method 的数据帧。这意味着什么,为什么它是整洁的?例如,如果您首先对聚合执行[g](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.assign.html)roupby,然后调用assign,那么您可以在函数中使用聚合来计算新列的值。这也是您在示例代码中看到的。对我来说,这真的很紧凑,同时还很有表现力。
如示例所示,可以用一个分配调用来创建多个列。因此,你只需要传递多个关键字参数;每个要创建的列一个。这很酷,因为以后的赋值可以利用以前创建或修改的列。举个简单的例子,您可以运行df.assign(x_axis=np.random.rand(len(df)), y_axis=**lambda** in_: in_.x_axis ** 2),其中第二个赋值使用了第一个赋值中创建的列。
最后,我想提到一个小技巧,它允许您创建没有正确 Python 变量名的列。为此,您必须创建一个字典,将列名作为键,将赋值操作作为值,并将这个字典解包后传递给赋值方法😵。这听起来比实际要难。为了更清楚,让我们用一个例子来结束这一段,在这个例子中,我们用无效的 Python 变量名df.assign(**{'X-Axis': np.random.rand(len(df)), 'Y-Axis': **lambda** in_: in_['X-Axis'] ** 2})创建了两个新列。
地图
可以在 Pandas 系列对象上调用的另一个方便的函数是[map](https://pandas.pydata.org/docs/reference/api/pandas.Series.map.html)函数。使用map,您可以用另一个值替换系列中的每个值。这是一个简单的例子,我用赋值函数调用做了一些 dogfooding😃
在这段代码中,我们使用map有条件地将to_big_to_small列的条目设置为两个不同的字符串。此外,我们使用map来添加一个新列inverted_name,它保存每个物种的颠倒名称。当然,这个例子在内容方面不是很有用,尽管它举例说明了如何调用map的两个选项。
- 您向 map 函数传递一个集合类型,比如字典或序列。将要发生的是,你的序列的值将被用作键,从给定的集合中查找相应的值。任何不属于集合的值都将被映射到
NaN或None。为了不那么枯燥,我给你另一个玩具例子pd.Series(range(3)).map({1:'medium', 2:'high'})。当您执行该操作时,会产生一系列条目[NaN, 'medium', 'high']。 - 您向
map传递一个函数或 callable,它将一个标量作为输入并返回一个标量值。这样做时,该函数将使用每个值作为输入参数,按元素方式应用于序列的每个条目。这就是你在第 6 行看到的,我们颠倒了花卉物种的名称。
作为建议,不要用那种方法做任何数学运算。当直接应用于一个系列时,这可以更有效地完成,因为它在后面利用了 NumPy 矢量化。
最后,如果您想对整个数据帧而不是一个序列进行元素操作,您可以使用[applymap](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.applymap.html)函数,它的行为与map相同。
询问
在我们研究了操作数据容器的函数之后,让我们看看如何从数据帧中提取数据。提取行的一个有用的函数是query函数。当然,我们从一些代码开始
我们在这里做了什么?我们使用传递给query的逻辑过滤表达式选择了所有行的子集。过滤器表达式是一个字符串,可以包含各种逻辑比较,如>,<,>=,<=,!=,==,等,以比较数据帧的列。然后,query函数对该表达式求值,并将表达式求值的所有行返回给**True**。
在表达式中,通过使用列的名称来引用列。要引用不是有效 Python 变量名的列名,必须用反斜线将它们括起来,如第 6 行所示。
如果您想从外部作用域引用任何变量,您可以通过在它们的名称前加上@字符来实现,正如您看到的length_th变量。
值得注意的是,您可以使用索引操作来执行相同的操作。然而,当您使用query时,产生的代码不那么冗长,更好阅读。
激增
我们在这篇文章中讨论的最后一个函数是[explode](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.explode.html),显然是名字最引人注目的一个💣。这个功能有什么用?当一列的条目类似于列表时,explode函数很有用。具体地说,它使您能够为这些列表的每个条目创建一个新行。进行此操作时,一行的所有其他条目都将被复制,索引也是如此。您可以通过传递包含类似列表的对象的列的名称来调用它。和往常一样,让我们用一个例子来说明这一点
在给定的示例中,我们首先创建一个包含 3 行的数据帧。列a的条目最初分别是长度为 1、2 和 4 的列表。分解列a上的数据帧后,得到的数据帧大小为 1+2+4 = 7。我可以推荐复制这个例子,并对它进行试验。
现在你可能明白为什么这个函数叫做 explode 了;当使用它时,你的数据帧的尺寸会爆炸。抛开小玩具的例子,假设您有一个 500_000 行的数据帧,有一列包含 100 个条目的列表。当您对该列调用 explode 时,最终会得到 50_000_000 行。这可能是一个问题。所以我的建议是:慎用!
需要知道的一件重要事情是,explode 不会改变它所应用的列的数据类型。由于 Pandas 用 object 类型存储类似列表的值,这意味着在展开一列后,它仍然是 object 类型。如果您想改变这一点,您必须使用astype方法显式地这样做。这也是您在示例代码中看到的。

包裹
在这篇文章中,我们看了四个不同的熊猫函数来处理数据帧和序列。当您开始使用这些函数时,您未来的代码将更加优雅、易读和高效。相信我。如果你真的想的话,你也可以利用这些函数来给你的同事留下深刻的印象😎。
感谢您关注这篇文章。一如既往,如果有任何问题、意见或建议,请随时联系我或关注我,无论是在 medium 还是通过 LinkedIn 。
所有分析专家都应该警惕的四个逻辑陷阱
如何避免在工作中犯错误

逻辑——我指的是逻辑的数学学科——是我多年前研究的一门真正纯粹而美好的学科。因此,我总是非常清楚,人类在推理中会犯最基本的逻辑错误,这可能会导致完全错误的决定和行动。分析专家也不例外。在分析程序中,数学逻辑并没有真正教得很好,在急于确认模型或产生输出时,人们很少停下来思考他们的方法是否通过了逻辑审查。
在这篇文章中,我想概述四种人们经常犯的逻辑推理错误。当我第一次介绍它们时,每个听起来都很明显,你的反应可能是“我永远不会那样做”。但是当我介绍一个我经常看到这种错误的典型分析情况时,你可能会三思。
1.肯定随之而来的“谬误”
假设我告诉了你一些关于我自己的事情:
每当我有一个截止日期要满足,我就变得焦虑。
如果你感觉到我很焦虑,你可能会认为我有一个最后期限要满足。那可能不是真的。除了临近的截止日期,可能还有其他原因让我焦虑。
当我们知道语句 A 总是隐含语句 B,并且我们用它来断言语句 B 总是隐含语句 A 时,肯定结果谬误的就发生了。我们不能这样做。陈述 B 是必要的,但不足以暗示陈述 a。
以数据科学为例,我们通常认为:
我的模型是一个令人满意的预测器,因此它是一个令人满意的拟合。
我看到很多人犯的错误是宣称相反的情况:我的模型是一个令人满意的拟合,因此它是一个令人满意的预测。我们在预测分析中将数据分为训练样本和测试样本的全部原因是为了确定训练样本中的拟合在训练样本之外具有足够的普遍性,我们可以声称该模型具有令人满意的预测性。
2.否认先行谬误
记得我告诉过你,每当我有最后期限要满足时,我就会焦虑。嗯,我是在假期写这篇文章的,因为我没有截止日期,所以你可能会认为假期对我来说很轻松。同样,这可能不是真的。可能选礼物也让我焦虑?
否定先行谬误发生在当我们知道陈述 A 总是隐含陈述 B,并且我们用它来推断对陈述 A 的否定总是隐含对陈述 B 的否定的时候。使用和前面相同的数据科学例子,我看到数据科学家经常说
这个模型是一个垃圾预测器,所以它是一个垃圾拟合
这是否认前因的最好例子。实际上,该模型可能是一个垃圾预测器,因为拟合太好了——它如此精确,以至于它已经考虑了训练集中的大部分随机误差,因此不能推广到测试集。过度拟合就是这样。
3.“析取”谬误
据说拿破仑·波拿巴曾经说过:
我无时无刻不在想,喝咖啡是不是太晚了,喝葡萄酒是不是太早了。
想象一下,你碰到波拿巴先生,他告诉你,他想知道他是否应该喝杯咖啡。你可能会得出结论,他此刻不在他的“葡萄酒区”。再说一次,你可能错了。他可能同时与和这两个的困境角力。
析取谬误发生在你被告知语句 A 或语句 B 为真,你证明语句 A 为真,结果你假设语句 B 为假。
在数据科学中,这可能是现实生活中分类预测器实现的一个实际问题。想象这样一个预测者将一个观察分类为 a 类。由此很容易得出结论,该观察因此在现实生活中是而不是B 类、C 类等。虽然模型输出互斥的类,但导致这些类的潜在概率可能意味着给定的观察值很有可能属于任意数量的类。几乎没有分类器可以让你明确地、100%确定地跳到一个类别——这就是为什么我们有像假阳性和假阴性率这样的指标。
4.“虚假链”谬论
说到咖啡,咖啡对我真的很重要。这里有两个关于我如何使用咖啡的陈述。
每当我工作落后时,我就喝杯咖啡。
每当我需要提神的时候,我就喝咖啡。
基于此,如果我告诉你我现在工作落后了,你可能会建议我需要一个提神的东西。但是你的建议可能是错误的。也许当我工作落后时,我真正需要的是小睡一会儿?
当你知道陈述 A 总是隐含陈述 C,陈述 B 总是隐含陈述 C,你由此得出陈述 A 总是隐含陈述 B 的结论时,假链谬误就发生了。
在分析学中,我看到这个谬误被大量用于相关性。比方说,我对一家公司的一群员工进行了分析,发现他们的 SAT 成绩与他们的工作表现相关。假设有人通过单独的分析发现工作面试分数与工作表现相关。因此,人们很容易相信 SAT 成绩一定与面试成绩相关联。但是,假设这些变量可以完全相互独立是没有任何依据的。
这些错误引起你的共鸣了吗?还是你看到人掉进的其他逻辑陷阱?随意评论。
学习人工智能要避免的四个错误
入门,人工智能
人工智能是美妙的,但我们应该以正确的方式对待它。

学习人工智能使我免于从事枯燥的工作。
在完成我的航空航天工程本科学业后,我马上开始研究人工智能。在学习了 4 个月的课程、论文、书籍,并亲自尝试之后,我得到了一份梦寐以求的工作:R&D 的一个项目,建造一个实时双向手语翻译机。一些不存在的东西。我正要创造未来!
这四个月让我逃离了我肯定会讨厌的生活。我想要更刺激的东西,比如逆向工程我们的大脑和思维。我深入到一个新的、未被探索的世界,向我展示了它的光明和阴影。以下是我在进入人工智能领域的过程中学会避免的 4 个错误。尽情享受吧!
从理论开始
“不要从定义和理论开始。相反,从将主题与你想要的结果联系起来开始。”
—杰森·布朗利博士机器学习大师
如果你读过我的一些文章,你可能已经注意到我喜欢理论人工智能。它有一种让我惊讶的哲学意味。我喜欢思考这个领域的未来,以及它对我们意味着什么。AGI 将如何塑造我们的生活?我们会在不知不觉中创造它吗?会危险还是和平?
我也喜欢阅读历史基础。认知科学和计算机科学在 20 世纪中期诞生时是如何分开的?象征性的人工智能是如何失宠,让神经网络介入,最终达到它们今天享有的霸权地位的?为什么艾会遭遇冬令?
我也想知道东西是从哪里来的。什么是卷积?仅仅基于注意力的变形金刚是如何在最近几年推翻其他范式的?增加参数怎么可能让模型在质量上更强大?
所有这些问题都像飞蛾扑火一样吸引着我。然而,当我在 2017 年开始学习人工智能并参加吴恩达和杰夫·辛顿的课程时,我知道人工智能的哲学、历史和理论方面不会让我找到工作。我想做一个现实生活中的项目。我想弄脏我的手。我想获得从零开始实际建造东西的专业知识。书本不能教我这些。故事和深刻的反思不能教会我这些。我需要实用的知识和有用的技能来使这个项目不至于失败。
但是道路并不是对每个人都是平等的。从理论开始有两种情况是有意义的。首先,如果你在大学学习计算机科学,即使你不想学,你也可能会学到人工智能的基础。但是因为你还在上大学——一个项目的潜在成功并不在你的肩上——利用它可能是值得的。理论和历史不是人工智能最紧迫的方面,但它们肯定是与其他人竞争的优势。
第二种情况是如果你要去学术界。学者和研究人员知道他们所研究领域的支柱。他们不会简单地用 AI 去建立一个公司或者一个项目;他们创造了那些算法。他们知道为什么变形金刚比其他型号更成功。他们知道为什么象征性的 AI 不起作用。他们知道是因为他们创造了它。他们也创造了深度学习。人工智能的每一个重大突破都来自于了解实践背后的理论的学者。
完全否定这一理论
“在人工智能领域,我们最需要的是思考者,而不是程序员。”
—斯里达尔·马哈德万,计算机科学家
如果你想进入人工智能行业,从理论开始并不是一个好主意。但是忘记人工智能有着支持实际应用的历史和理论背景是不明智的。你可能不会发明下一个伟大的深度学习算法,但了解 ReLu 受欢迎背后的原因或为什么每个神经网络都使用批处理规范化可以帮助你做出更好的决定。
在不知道“为什么”的情况下建立模型的主要问题是,如果环境使你偏离了通常的道路,你可能没有回到正轨的知识。如果您的模型开始得到疯狂的结果,您可能需要调试它。知道它们的原因是找到机器里幽灵的唯一方法。
更实用的知识——编码、神经网络架构、最先进的(SOTA)模型,甚至统计和代数——如果你不理解你试图解决的问题,是没有用的。引用计算机科学家斯里达尔·马哈德万的话,“我们在人工智能中最需要的是思考者,而不是程序员。”
到目前为止,你可能已经意识到,在实践和理论知识之间找到一个折中的解决方案是走上正确道路的关键:不要从理论开始,但也不要忘记它。也许最好的选择是杰森·布朗利所说的自上而下的方法:一种学习阅读、驾驶或编码等技能的自然方法。许多人在业余时间通过兼职项目学习编码。对人工智能感到兴奋,让它激发你的好奇心,让它成为一种探索。然后,你会发现这个理论很有趣。
从深度学习开始
"未来取决于某个对我所说的一切深感怀疑的研究生。"
—杰弗里·辛顿,深度学习的“教父”
深度学习无疑是最成功的 AI 范式。象征性的人工智能统治了 30 年,但它没有实现深度学习所实现的任何成就。自 2012 年以来,深度学习发展如此之快,以至于给其母领域蒙上了阴影。DL = ML = AI 是不正确的,但这是媒体对大众描述这个领域的方式;深度学习已经成为 AI 的代名词。
深度学习是乐趣,是成功,是金钱。然而,从屋顶开始建造房子不会让你建造墙壁。吴恩达最受欢迎的课程从线性回归和线性代数开始是有原因的。因为它为你提供了一个无价的工具包,将深度学习框架在一幅图画中,这幅图画包括了在它之前出现并奠定了它的基础的其他技术和方法。
如果你从深度学习开始,你不会找到一个理由回去学习其他机器学习算法,学习代数或统计,或其他在过去成功的技术——今天仍然如此。你将拥有强大的工具;你会拿到锤子的。但是对于锤子来说,所有东西看起来都像钉子。深度学习已经找到了最出名和最受欢迎的方法,但是有些问题可以用其他方法更有效地解决。深度学习需要庞大的数据集和大量的计算能力。不是每个公司都负担得起这些资源。
如果经过仔细考虑后,你发现从深度学习开始是实现目标的最佳方式,那么就去做吧。但不要盲目跟风,否则你可能会撞上一堵爬不上去的墙。深度学习是现在 AI 对成功的定义,但可能不会是永远。如果另一种范式推翻了它,你最好及时脱离这一潮流。话虽如此,你最终还是要在你的工具箱里为深度学习留一个位置。那是毋庸置疑的。
对艾的艺术水平过于夸大了
"机器智能是人类需要创造的最后一项发明."
—尼克·博斯特罗姆
这件事发生在我身上。不是因为我被流行文化对 AI 的描述与《T2》、《黑客帝国》、《T4 我》、《机器人 T5》等电影混淆了,而是因为即使是有声望的媒体也没有讲述真实的故事。去年 GPT 3 号也发生了同样的事情(正如我在这篇长文的中提到的)。大肆宣传变得疯狂,因为当现实更加微妙时,人们将该系统描绘成全能的。
人工智能发挥了作用,它的应用影响了——或者更好地说,影响了——一系列广泛的行业。人工智能可以提供重要的竞争优势。人工智能吸引了大量的资金和兴趣,转移了大量的资金——商业人士会尽一切努力留住这些资金。没有多少公司真正在使用人工智能或深度学习,这不是一个秘密。他们谈论人工智能驱动的产品,因为它很畅销,但他们的解决方案可以通过更简单、不太豪华的技术完美实现。
如果你想知道技术的状态,你需要阅读论文,听听不依赖于该领域成功的专家的意见。你不会从计算机科学家那里听到与哲学家或人工智能伦理学家相同的观点。找到正确的来源,你就能比较金钱的故事和实际发生的事情。
我们离 AGI 还很远。我们正以相当快的速度前进,但我们仍然很远。更大的型号是趋势,但我们不知道它会把我们引向何方。我们可以做出假设,但没有人真正知道。反正进入一个新的行业,少一点炒作也是正常的。事物从外面看更闪亮。这在每个行业都会发生,尽管程度不尽相同。AI 特别被炒作。把这个事实考虑进去才是最重要的。
结论
人工智能是一个非常好的研究或工作领域。每年我们都会看到新事物的出现,它越来越深入我们的生活。未来将是人工智能驱动的,所以我们最好睁大眼睛。但是因为人工智能受到如此多的关注,所以特别小心是很重要的。以下是用一句话概括的四个错误:
- 遵循自上而下的方法。
- 找到实用和理论 AI 的平衡点。
- 不要让趋势决定你的道路。
- 不要让炒作把 AI 变成海市蜃楼。
免责声明:本文中的建议来自我自己的经验。其他人可能有过不同的经历,可能不同意我的观点。从这些角度来思考这篇文章:这是一个我希望能对你有所帮助的观点!
订阅 获取更多关于 AI、哲学、认知科学的内容!
推荐阅读
</5-reasons-why-i-left-the-ai-industry-2c88ea183cdd>
在数据科学面试中你可能会遇到的另外四个问题

由有数据科学采访经验的人制作的迷你系列的第 2 部分
朋友们,你们好!欢迎回来,继续我们关于数据科学面试中可能会遇到的面试问题的系列报道。如果你错过了第一篇文章,你可以点击链接查看。
由于我在最初的帖子中给出了更好、更全面的解释,所以我将保持这篇介绍简短而甜蜜。让我简单回顾一下这些帖子的结构。在所有四个问题中,您将看到两个小节:
- 动机:这描述了面试官在这个问题背后的意图。理解这一点很重要,因为有时问题如何回答比答案本身更重要。比如之前的帖子有一个关于考生如何学习新东西的问题。“获得学位”不一定是错误的答案,但这并不表明候选人一定愿意或能够随时学习新事物。
- 潜在答案:任何面试问题都很少有“放之四海而皆准”的答案,所以我尽量给你的潜在答案提供多个选项。
还有最后一个提醒:我在两篇文章中提出的问题涵盖了所有的数据科学技能。根据您申请的具体职位,您可能会也可能不会遇到类似的问题,但我仍然希望提供广泛的问题类型,以涵盖“全部”数据科学技能。
好了,我答应了一个简短而甜蜜的介绍,所以让我们开始提问吧!
1.跨各种云平台(包括 AWS SageMaker),可以直接从 Jupyter 笔记本部署模型。你能解释一下为什么这不是一个更好的模式吗?你会考虑用什么来代替?
动机:这是一个与“纯”数据科学关系不大的问题,更多的是关于一般的软件工程,而且这个问题的答案没有如何回答的问题重要。简而言之,这不是一个更好的计划的原因是因为它没有坚持软件工程效率和弹性的核心原则。我的意思是,这种“部署在笔记本电脑中”的过程是一个笨重的过程,尤其是如果您想将其扩展到数百个型号。
从许多角度来看,这种“部署在笔记本中”的模式是非常低效的。我将在下面的列表中快速列举这些低效之处:
- 不自动化:在 DevOps 的世界里,我们更喜欢像 CI/CD 管道这样的东西尽可能自动化。您不仅需要手动将代码移动到这个 Jupyter 笔记本实例中,而且还需要在笔记本中手动运行代码来部署模型。
- 不可扩展:考虑到上面的要点,如果你的公司开始部署数百种型号,这将变得难以管理。即使您可以让所有的数据科学家进行初始部署…
- 不可大规模维护:即使你有很多人通过笔记本手动部署模型,它仍然不可大规模维护。如果你曾经不得不使用一个特定的软件库在任何模型上做一个软件补丁,我会不寒而栗地想到在这种模式下会做多少噩梦。
潜在答案:作为“动机”部分的一部分,我开始插入一些答案,但只是为了确保你特别清楚那些是什么,让我们在这里重申它们。再说一次,没有“放之四海而皆准”的答案,所以请允许我分享一些面试官希望听到的不同答案:
- 使用云提供商的 ML 服务的另一个方面:我 100%确定 AWS SageMaker 就是这种情况,我假设其他云服务也可能如此。尽管您可以从他们的 Jupyter 笔记本电脑上进行部署,但他们仍然有以不同方式部署您的模型的其他选项。AWS SageMaker 特别提供了直接部署批处理推理作业或实时 API 的选项。
- 使用 CI/CD 管道:从 DevOps 的角度来看,这是“必须的”。这个答案表明候选人理解自动化你的代码的好处。当然,这个答案本身还不够好,因为您需要解释管道是如何部署模型的,这导致了最后一个问题…
- 通过“基础设施即代码”实现自动化:这是你的面试官真正想听到的。它结合了前面两个要点,基本表述为:“我知道如何以一种高度可伸缩、高效和弹性的方式自动化云部署。”我很确定每个云提供商都有自己的“基础设施即代码”服务。AWS 的叫做 CloudFormation。但即使他们没有,我也不能在这里推荐足够多的 Terraform。我有一个关于 Terraform 的完整的其他系列,你可以通过这个链接了解更多。
2.您的公司已经部署了数百个模型,并希望通过产生一致的预期推理范围来确保每个模型保持高性能。当模型的性能随着时间的推移而下降时,这个概念叫什么?您可以采取什么步骤来确保这种下降不会在如此大量的模型中发生?
动机:因为企业使用预测模型的推理输出来支持商业决策,所以你总是希望推理输出尽可能准确自然是很重要的。一个产生负面结果的模型不仅会导致糟糕的商业决策,还会产生一些非常严重的后果。例如,如果特斯拉的自动驾驶算法停止正常工作,如果特斯拉汽车因算法性能不佳而发生事故,这可能会导致人员死亡。
虽然您可以让一个人手动检查每个模型以确保它正确执行,但问题特别指出,您需要确保数百个模型需要保持高性能。显然,如果进行手动测试,这将变得难以管理。尽管如此,这里的动机是确保候选人理解什么是模型性能退化,以及如何在更自动化的水平上管理它。我们将在下一节讨论具体的潜在答案,但我不会太担心记住我在下面列出的所有潜在指标。相反,我更关注的是您需要以自动化的方式保护模型性能的一般概念。
潜在答案:关于这个概念叫什么的问题,只有一个真正的答案,那就是模型漂移。模型漂移是一个概念,因为输入到模型中的数据可能会随着时间的推移从最初的预期值范围发生变化,模型在生产中保持不变的时间越长,其性能可能就越差。(这不要与遇到全新的价值观相混淆,我们将在下一个问题中讨论。)
从自动化的角度来看,评估模型随时间漂移的方法将是通过捕捉各种可以用数值量化模型漂移的指标。没有“一个标准可以统治所有人。”如果您想要评估二元分类模型的质量,您可能会查看精度、召回率、ROC AUC 或 F1 分数等指标。对于回归模型,您可能会查看均方根误差(RMSE)、R 平方或平均调整误差(MAE)等指标。您可能还应该运行数据质量指标,如群体稳定性指数(PSI),以确保最近的数据不会偏离原始训练数据太远。
基于这些度量的结果,您可以拥有类似于“分层”自动化的东西来处理模型漂移,也许是类似于“交通灯”的分层系统。绿色层中的模型将是不错的选择。黄色层中的模型会自动向模型所有者发出通知,其中包含类似“嘿,我们发现这里有点不确定。你可能会想看看这个。”对于红色层中的模型,您可能希望有一个自动化的重新培训/重新部署机制。最后一层涉及到非常流行的概念,称为 MLOps ,虽然我不打算在这里讨论它,但我认为如果你能很好地阐述 MLOps,特别是在这种情况下,你的面试官会印象深刻。😃
3.几个月来,您部署到生产中的模型已经生成了一系列预期的推论。一天早上,你走进办公室,发现模型在过去的 24 小时内开始产生完全不同的推论。为什么模型会突然产生不同的推论,你会怎么解决这个问题?
动机:乍一看,这可能听起来像是另一个软件工程问题,因为我们正在谈论处理生产中的故障模型,但实际上这里完全不是这样。注意,在这个场景中,模型仍然产生推论,这意味着支撑模型的软件解决方案运行良好。现在,如果我用不同的方式来表达这个问题,并且注意到这个模型根本没有产生任何推论,那么是的,这可能更像是一个软件工程问题。
现在,您可能会认为这是一个模型漂移问题,因为我们已经讨论了上一个问题,但这并不完全是这里的问题。这里问题的真正根源很可能与数据质量问题有关。模型漂移更多地与更长的时间周期相关联,这里的问题指出了一夜之间的变化。同样,这可能是一个数据质量问题,一些上游来源可能对他们发送给你的模型的数据进行了彻底的新更改。例如,假设您有一个经过训练的模型来分析冰淇淋销售的价格预测。如果模型只在口味只有“巧克力”或“香草”的数据集上训练,那么如果你的上游来源开始在一夜之间发送关于新口味的信息,如“草莓”、“曲奇”、“朗姆酒葡萄干”和“洛基路”,你的模型将会崩溃。
所以基本上,你的面试官希望你明白,数据质量可以通过引入全新的、完全意想不到的价值,从根本上改变你的模型的性能。现在让我们开始讨论你可能如何处理这种情况。
潜在答案:这是一个潜在答案范围非常有限的问题。具体来说,我只能想到两个可行的选择:
- 使用新值对数据集重新训练模型:这种方法肯定有助于解决问题的根本原因,但也是两种方法中较为困难的一种。根据新值的构造方式,您可能需要修改培训代码来适当地处理新值。这可能非常耗时,并且取决于您的公司选择如何验证新模型,或者在这种情况下验证模型的新版本,这可能是一个需要更长时间的解决方案。但它也可能是值得的,所以我绝对不想阻止它作为一种选择。
- 过滤掉任何带有新值的记录:这并不能完全解决为模型处理新值的根本问题,但这绝对是一个快速的权宜之计,可以确保模型至少对它熟悉的记录仍然产生高质量的推论。回到我们上面的冰淇淋例子,这可能意味着要求您的上游来源只发送有关“巧克力”或“香草”口味的记录。关于其他新口味的记录将被丢弃。同样,这并不理想,但这将是一个快速的解决方案。
实际上,最佳解决方案可能是上述两种选择的组合。你可以建议第二种选择,作为目前的快速创可贴措施,这将为你赢得一些时间,用新的价值观正式重新训练模型。然后,当新的模型被训练和正确验证后,您可以部署它,然后要求您的上游源使用新的值释放记录中的闸门!
4.您正准备将一个模型作为可消费的软件解决方案部署到生产环境中(例如,实时 API、batch cronjob)。除了创建解决方案本身,在将解决方案部署到您的生产环境时,您还需要考虑哪些因素?
动机:最后一个问题包含了数据科学的软件工程方面,作为一个软件工程产品,你的建模解决方案需要遵循开发任何软件工程产品的最佳实践。具体来说,面试官希望你至少能完成三类特定的活动:自动化部署,创建自动化测试,以及确保最佳安全实践。
可能的答案:在这篇文章的所有问题中,这个问题可能是你可以回答这个问题的最广泛的选项。在“动机”这一小节中,我们谈到了面试官希望看到的三种特定类型的活动。让我们快速列出这些类别的项目列表。
从自动化部署开始:
- 您可以创建一个 CI/CD 管道,它从您的 Git 存储库中获取代码,对其进行适当的打包(例如用 Docker 进行容器化),然后将其部署到适当的测试和生产环境中。
- 您可以使用一个“基础设施即代码”工具,如前面提到的 Terraform,在基于云的平台(如 AWS、Google 云平台)等提供商上创建部署。
- 如果您在一个类似 Kubernetes 集群的内部环境中工作,您可以创建 YAML 文件来配置您的模型应该如何在相应的环境中部署。
下一个类别是创建自动化测试。在这里分享一些选项之前,我应该注意到我实际上有一篇完整的、独立的博客文章,专门致力于您可以为模型部署创建的许多不同的测试。
- 应该为任何建模项目创建的最明显的一组测试是单元测试。顾名思义,单元测试有助于测试出您编写的代码,以确保无论您为代码编写多少单元测试,代码都能通过。
- 鉴于许多建模解决方案是作为实时 API 部署的,我认为下一组最重要的测试是性能测试。这一点很重要,因为如果进入 API 的流量超出了单个副本的处理能力,您可能需要注意可伸缩性。有一个很棒的工具叫做 Locust,你可以在你的 Python 代码中使用它,我已经在这个链接的博客文章中写了一篇关于这个工具的完整文章。
最后,最后一类是确保最佳安全实践。不幸的是,我们生活在一个有很多坏人的世界里,所以我们需要确保我们的建模解决方案得到适当的保护,以保护模型的完整性,并保护很可能是客户数据的数据。
- 许多建模解决方案被部署为 Docker 容器,有几个容器扫描工具可以扫描这些 Docker 容器,寻找潜在的安全漏洞。Docker Desktop 最近集成了一个名为 Snyk 的供应商后端,所以现在如果你用 Docker Desktop 执行一个
docker scan命令,它将在幕后使用 Snyk 向你显示不同级别的潜在安全漏洞。(例如,低、中、高、关键) - 如果您与 AWS 这样的云提供商合作,您将需要确保您的身份&访问管理(IAM)策略得到适当调整,以提供“最低特权”安全访问。IAM 不仅仅是 AWS 的本地服务。我确定它在谷歌云平台上,我猜它也在微软 Azure 上。这些服务有助于确保只有正确的参与者有权与您的建模解决方案进行交互。
我们的第二组面试问题到此结束!我希望这些对你考虑自己的数据科学面试有所帮助。在这个时候,我没有起草任何其他问题,但如果我想出另外几个问题,那么我可能会在这个系列中写第三篇文章。感谢您的阅读,祝您求职顺利!🏆
你在学校可能没学过的四种乘法
答案有许多不同的方式。
当我们学习乘法时,我们学习把等式分成几部分。首先,我们使用 1 的位置值找到产品。然后我们转向十位数,接着是百位数。最后,我们总结一切,得出我们的答案。这种方法很有效,但并不总是最有效的。这里有一些其他的方法可以加快这个过程。
在这些例子中,我使用的是 2 位数和 3 位数。这些方法也适用于较大的数字。

卢卡斯·范·奥尔特在 Unsplash 上的照片
晶格方法
画一个网格,用对角线分割每个方块。将一个数字写在顶部,另一个写在右侧,每列或每行一个数字。
586 x 45 =

586 x 45:顶部 586,右侧 45
在每个单元格中,将行乘以列。将乘积分割成十位值和一位值。将十位数写在对角线上方,将一位数写在对角线下方。

5 x 4 = 20。把 2 放在线上,0 放在线下

完整的网格
现在,用对角线来看网格。将对角线上的数字相加。如果总和大于 9,则将十位数进位值带入下一列。

穿过蓝色和白色对角线求和
586 x 45
-> 2, (2+0+3), (5+4+2+2), (0+3+4), 0
-> 2, 5, 13, 7, 0
-> 2, 6, 3, 7, 0
= **26370**
最后,用数字写出对角线上的总和,你就会得到答案。
586 x45 = 26370

直线法
当数字很小时,这种方法对于 2 位数和 3 位数的数字非常有效。当你有许多相交的线时,它会变得有点乱。
画一系列代表第一个数字的每一位的平行线。线条应该大致呈 45 度角,并且每个数字之间有一个间隙。
对于这个例子,我们将使用 223 x 52

223 由线表示
百位值是 2;最上面的两条线代表它。接下来的两行表示十位,最后三行表示一位值。
接下来,我们画第二个要乘的数。我们通过绘制一组与第一组平行线相交的新的平行线来做到这一点。

223(橙色)x 52(蓝色)
这次下面一组线代表五个十,上面两条线代表一。注意高位值线总是在左边。
现在我们在线的交叉处画点。

交叉点上的点
接下来,我们沿着 x 轴的位置对这些点进行分组。每组点代表我们最终答案中的一个数字。我们对每组中的点求和。如果总和大于 9,则将 10 的值带入下一列。

每组点代表一个数字。把这些点加起来
写出各组的总和作为答案。
223 x 52
-> 10 ,(4 + 10) ,(4 + 15) , 6 # sum the dots
-> 10, 14, 19, 6 # 14 and 19 are greater than nine
-> 10+1, 4+1, 9, 6 # carry the 1 from 14 and 19
-> **11596**
223 x 52 = 11596

十字交叉法
在这种方法中,你从右向左移动。在第一步中,我们将 1 乘以 1。接下来,我们进入十列,将十乘以一,将一乘以十,并将这两个计算结果相加。我们继续跨越等式。整体模式如下所示。

十字形图案
呀,看起来很复杂。当我们一步一步来看,就更有意义了。

这个过程是对称的。我们在边缘只有一个计算(1 x 1 或 100 x 100)。在中间,我们有三个计算。
最棘手的部分是确保将正确的位置值带入下一列。
125 x 648
-> 6, 16, 46, 36, 40
-> 6+1, 6+4, 6+3, 6+4, 0
-> 7, 10, 9, 10, 0
-> 7+1, 0, 9+1, 0, 0
-> 8, 0+1, 0, 0, 0
= **81000**
125 x 648 = 81000

该滑动方法
这个方法几乎是神奇的。你从做与你预期相反的事情开始——反转一个乘数的数字。
这个颠倒的数字充当了一个窗口。它在等式中一次移动一个位置值。
424 x 83 =
从尽可能靠左的窗户开始。窗口的个位值应该在另一个乘数的最大位值之下。将这些数字相乘

第一步:83 反过来变成 38。乘以 4 x 8
将窗口向右滑动一个位置值。将两列相乘,并对乘积求和。

第二步:向右滑动,将各列相乘并求和。
继续向右移动窗口。

第三步:滑动,乘,和。
直到窗口的最大位值低于乘数的 1 位值。

将每一步的总和组合在一起。将适当的位置值移到下一列。
424 x 83
-> reverse 83 -> 38
-> 32, 28, 38, 12 # column sums
-> 32+2, 8+3, 8+1, 2
-> 34, 11, 9, 2
= **35192**
424 x 83 = 35192
快乐倍增!
Python 中高效机器学习的三种流行特征选择方法

叶夫根尼·切尔卡斯基在 Unsplash 上拍摄的照片
使用真实数据集执行特征选择方法,并在每个方法后检索所选特征
特征选择是机器学习最重要的部分之一。在现实世界的大多数数据集中,可能有许多要素。但并不是所有的特征都是某个机器学习算法所必需的。使用太多不必要的功能可能会导致很多问题。第一个肯定是计算成本。不必要的大数据集将花费不必要的长时间来运行算法。同时,它可能导致完全没有预料到的过拟合问题。
有几种特征选择方法。我将在这里用 python 演示四种流行的特征选择方法。如果我们不得不从头开始执行,这将是一个漫长而耗时的过程。但是幸运的是,python 具有强大的功能,使得使用几行代码来执行特性选择变得非常容易。
在开始特征选择方法之前,请随意下载用于本练习的数据集:
让我们首先导入数据集:
import pandas as pd
import numpy as np
df = pd.read_csv('Feature_Selection.csv')
数据集太大。它有 108 列和 11933 行。因此,我不能在这里显示截图。以下是一些栏目:
df.columns
输出:
Index(['x.aidtst3', 'employ1', 'income2', 'weight2', 'height3', 'children','veteran3', 'blind', 'renthom1', 'sex1',
...
'x.denvst3', 'x.prace1', 'x.mrace1', 'x.exteth3', 'x.asthms1', 'x.michd', 'x.ltasth1', 'x.casthm1', 'x.state', 'havarth3'], dtype='object', length=108)
假设我们想要使用机器学习算法来预测‘hawarth 3’变量。这是 X 和 y。
X= df.drop(columns=["havarth3"])
y= df['havarth3']
现在,我们将使用不同的方法找出哪些特征是预测“havarth3”变量的最佳方法。
单变量特征选择
该方法基于单变量统计测试选择最佳特征。将用于此目的的函数是 sklearn 库中的 SelectKBest 函数。此函数移除除了顶部指定数量的特征之外的所有特征。在该数据集中,有 107 个要素。k 值 10 仅用于保留 10 个特征。选择 f_classif 的 score_function,它使用方差分析表中的 F 值来选择特征。还有另外两个分类选项。分别是 chi2 和 mutual_info_classif。请随时检查他们自己。
这是流程。
从 sklearn 库中导入方法。
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
传递前面提到的 score_function 'f_classif '和您希望在' SelectKBest '函数中保留的特征数,并将 X 和 y 拟合到函数中:
uni = SelectKBest(score_func = f_classif, k = 10)
fit = uni.fit(X, y)
这是该函数选择的 10 个特征:
X.columns[fit.get_support(indices=True)].tolist()
输出:
['employ1',
'rmvteth4',
'genhlth',
'x.age.g',
'x.age80',
'x.ageg5yr',
'x.age65yr',
'x.rfhlth',
'x.phys14d',
'x.hcvu651']
特征选择完成了!
使用相关矩阵的特征选择
该过程计算所有特征与目标特征的相关性。基于这些相关值,选择特征。对于这个项目,阈值选择为 0.2。如果特征与目标的相关性超过 0.2,则选择该特征用于分类。
cor = df.corr()
cor_target = abs(cor["havarth3"])
relevant_features = cor_target[cor_target > 0.2]
relevant_features.index
输出:
Index(['employ1', 'genhlth', 'x.age.g', 'x.age80', 'x.ageg5yr', 'x.age65yr', 'x.hcvu651', 'havarth3'],
dtype='object')
请注意,“havarth3”变量也被选中。因为‘hawarth 3’变量与自身的相关性最高。因此,请记住在执行机器学习算法之前删除它。
包装方法
这是一个有趣的方法。在这种方法中,使用一种机器学习方法来找到正确的特征。此方法使用 p 值。这里我将使用 statsmodels 库中的普通线性模型。我选择 statsmodels 库,因为它提供 p 值作为模型的一部分,而且我发现它很容易使用。
import statsmodels.api as sm
X_new = sm.add_constant(X)
model = sm.OLS(y, X_new).fit()
model.pvalues
输出:
const 2.132756e-01
x.aidtst3 6.269686e-01
employ1 4.025786e-20
income2 3.931291e-04
weight2 2.122768e-01
...
x.asthms1 3.445036e-01
x.michd 3.478433e-01
x.ltasth1 3.081917e-03
x.casthm1 9.802652e-01
x.state 6.724318e-01
Length: 108, dtype: float64
看所有的 p 值。现在,基于 p 值,我们将逐个移除特征。我们将继续运行 statsmodels 库中的机器学习算法,在每次迭代中,我们将找到具有最高 p 值的特征。如果最高 p 值大于 0.05,我们将移除该特征。将进行相同的过程,直到我们达到最高 p 值不再大于 0.05 的点。
selected_features = list(X.columns)
pmax = 1
while (len(selected_features)>0):
p= []
X_new = X[selected_features]
X_new = sm.add_constant(X_new)
model = sm.OLS(y,X_new).fit()
p = pd.Series(model.pvalues.values[1:],index = selected_features)
pmax = max(p)
feature_pmax = p.idxmax()
if(pmax>0.05):
selected_features.remove(feature_pmax)
else:
break
selected_features
输出:
['employ1',
'income2',
'blind',
'sex1',
'pneuvac4',
'diffwalk',
'diffdres',
'smoke100',
'rmvteth4',
'physhlth',
'menthlth',
'hlthpln1',
'genhlth',
'persdoc2',
'checkup1',
'addepev2',
'chcscncr',
'asthma3',
'qstlang',
'x.metstat',
'htin4',
'wtkg3',
'x.age.g',
'x.ageg5yr',
'x.age65yr',
'x.chldcnt',
'x.incomg',
'x.rfseat3',
'x.rfsmok3',
'x.urbstat',
'x.llcpwt2',
'x.rfhlth',
'x.imprace',
'x.wt2rake',
'x.strwt',
'x.phys14d',
'x.hcvu651',
'x.denvst3',
'x.prace1',
'x.mrace1',
'x.ltasth1']
所以,这些是选择的特征。
结论
我在我的一个项目中使用了所有四种方法,使用包装器方法得到了最好的结果。但并非所有项目都是如此。当您有很多像这个项目这样的特性时,尝试至少几种特性选择方法是一个好主意。不同的功能选择可能会给你完全不同的功能集。在这种情况下,使用另一种方法来确认是一个很好的解决方案。在机器学习中,收集正确的特征是成功的一半。
更多阅读:
[## 文本数据的探索性数据分析,包括可视化和情感分析
towardsdatascience.com](/exploratory-data-analysis-of-text-data-including-visualization-and-sentiment-analysis-e46dda3dd260)
在数据科学面试中你可能会遇到的四个问题

DS 面试问题
招聘台另一边的人设计的问题的迷你系列的第一部分
朋友们,又见面了!随着我们进入一个在大流行后的世界中如何工作的新领域,你可能已经注意到,许多人正在抓住以前可能没有的新机会。我具体指的是远程工作的出现如何为以前可能成为障碍的职位带来了新的机会。还有一个不幸的巧合是,由于失业是疫情的一个原因,一些人现在可能正在寻找新的机会。
不管你的情况如何,在任何求职过程中,几乎都无法逃避这一令人生畏的活动:面试。我自己也经历过数据科学面试,我绝对能体会到面试过程有多紧张!数据科学面试流程通常是一个多阶段的方法,通常包括一个或多个编码评估、一个“文化契合度”面试,当然还有一个技术问答时间。在这个迷你系列中,我们将通过一些您在自己的数据科学面试中可能会收到的问题的具体示例来涵盖最后一点。
为了让你放心,我并不是一个凭空捏造问题的人,让我分享一点我的个人经历和背景。我目前是一家财富 50 强公司的高级机器学习工程师(MLE ),我有非常好的机会参与新 MLE 的招聘过程。我和其他队友一起设计了一系列我们自己面试时会用到的问题,我也曾站在招聘桌的一边,观察应聘者在被问到这些问题时的表现。
当然,我显然不能分享我们公司使用的问题,但我想我会精心设计一套全新的问题,这些问题与您在真正的数据科学面试中可能会得到的问题具有相同的总体感觉。为了帮助你从回顾这些问题中获得最大收益,我不仅分享了问题的潜在答案,还分享了问题背后的动机。虽然正确的答案总是好的,但问题背后的动机可能更重要,因为它能让面试官更多地了解你作为候选人的身份。
因为这些问题非常具体,所以我想在这篇文章中只关注四个问题。在我写这篇文章的时候,我已经精心制作了总共八个问题,所以在这个问题之后肯定会有至少一个帖子。这些问题涵盖了数据科学和机器学习的所有领域,所以请记住,这些问题中的一些可能与你申请的职位无关。
好了,让我们开始提问吧!
1.您被要求创建一个预测模型,为一家银行公司评估潜在的欺诈案例。为您提供了一个包含 100 万条记录的真实数据集,但只有 10,000 条记录被证明是真正的欺诈。(假设向你提供一个二进制特征,其中 0 =不欺诈,1 =欺诈。)在构建预测模型时,您可能会有哪些顾虑?
动机:这个问题的核心基本上是如何恰当地解决目标阶层失衡。二元分类模型是世界上最流行的模型之一,像这样的目标类不平衡是非常普遍的。你很少能在你的目标类上得到 50/50 的分成。它几乎总是会以这样或那样的方式倾斜,确实有像这样的情况,不平衡可能相当极端。因为这是一个如此普遍的问题,所以公司雇佣一个懂得如何恰当解决这个问题的候选人自然是很重要的。
潜在答案:在这个特定场景中,只有 0.01%的记录是欺诈性的。训练模型时使用完整的数据集通常是理想的,但像这样的目标类不平衡的一个大问题是模型很可能不公平地偏向“非欺诈”类。如果您要在这个完整的数据集上训练一个模型,您很可能会有许多假阴性,这意味着您的模型将允许太多的欺诈案件毫发无损地通过。
有几种不同的方法可以解决这样的问题。最理想的可能是只对数据的子集进行训练。换句话说,您可以保留所有的欺诈记录,但将非欺诈记录减少到原始数据集的一小部分。为了正确验证模型,您需要留出一部分数据集,这当然会使您的小数据集变得更小。围绕这一点的一个措施是实现某种类型的交叉验证,像 Scikit-Learn 的 K-Folds 验证,这将使您能够最大限度地利用您的数据,同时保护您的模型的完整性。
其他解决方案可能包括用类似于合成少数过采样技术(SMOTE) 的东西来合成与你的代表性较低的类相似的新数据。鉴于这个问题是围绕银行信息的,我可能不会选择这个选项,因为在这种情况下编造数据是一个巨大的禁忌,但作为一名面试官,我可能会给这个答案几点创造性思维!
2.你的雇主决定采用你没有经验的新云平台(例如谷歌云平台、微软 Azure)。你知道该平台作为机器学习环境是可行的,但目前缺乏该平台的机器学习服务如何工作的知识。您可能会采取哪些步骤来了解新平台的更多信息?
动机:这是一个实际答案并不那么重要的问题。面试官问这样一个问题实际上是想了解你如何自学一项新技能。数据科学世界是一个快速发展的世界,因此候选人表现出他们能够努力掌握这些新技能是非常重要的。
潜在答案:同样,这个问题的具体答案在这里并不重要。只要你能表现出学习新事物的能力,你就能很好地回答这样的问题。也就是说,这里有一些你可以提供的答案:
- 查看云平台是否有任何官方培训材料
- 通过 Coursera、Udemy 或 Udacity 等平台参加在线课程或 MOOC
- 获得支持该云平台的认证
- 通过双手工作
- 咨询在线出版物中的文章,如《走向数据科学》!眨眼
3.给我解释一下有监督和无监督学习的区别。你能不能提供一个场景,在这个场景中你可能会采用这些不同的机器学习类型?
动机:如果你认为这是一个“垒球”问题,那你绝对是对的。这并不完全是面试官试图欺骗你。更重要的是,面试官会像这样抛出一个简单的问题来快速淘汰不合格的候选人。当然,对于普通人来说,这不是一个简单的问题,但是任何数据科学家都应该能够毫无疑问地回答这个问题。只是要意识到这些问题确实会被问到,所以不要被迷惑,给出一个比你需要的更复杂的答案。
潜在答案:同样,这应该是一个简单的答案,但为了保持一致,我将继续写在这里。监督学习算法利用基础事实目标——无论是分类还是回归问题——在数据中寻找模式,以便在未来对类似数据进行推理。监督学习的一个经典例子是在第一个问题中提到的银行欺诈模型。在这种情况下,监督学习算法将在提供的输入特征中寻找模式,以尽可能接近地匹配地面真实目标。
无监督学习没有利用地面真实目标,因此这些算法主要用于聚类目的。根据所选择的算法,您可以定义一些分类,模型将在这些分类中对数据进行适当的分段。像这样的聚类通常用于生成关于客户概况的洞察。通过将志趣相投的消费者组合在一起,公司可以更好地针对特定客户群提供服务,为他们提供更适合该群体更具体需求的服务。例如,我曾经为 Udacity nanodegree 做过一个项目,该项目使用关于星巴克客户的数据的聚类算法来确定哪些群体可能对某些广告或优惠券做出最佳回应。(以防你好奇,这是我为那个项目写的完整博文。)
4.您正在合作的一位数据科学家训练了一个模型,并将其序列化为 pickle(。pkl)文件。他们为您提供序列化的 pickle 文件,并要求您将其部署到生产环境中进行推理使用。在测试过程中,您不能让序列化模型为您生成一个推理,因为它会抛出一个错误。(假设提供给您用于测试的样本数据是正确的。)这里的问题可能是什么,您如何着手解决它?
动机:创建一个预测模型是一回事,但知道如何正确使用它是另一回事。无法回避的事实是现代数据科学模型是使用现代软件工程实践部署的,因此,我们在尝试实现这些模型时经常会遇到典型的软件问题。这是你可能会看到也可能看不到的问题之一,取决于你申请的职位类型,因为许多公司都有专门从事这类活动的职位。即使您申请的角色不将实现模型作为其核心活动,这也是数据科学领域的任何人都需要理解的重要问题之一。
潜在答案:在尝试使用反序列化模型时,有很多事情可能会出错。这可能是一些细微的差别,比如加载时不小心指向了不正确的文件。以我个人的经验,遇到这些问题的最普遍的根本原因是模型被加载到一个不同于它最初被训练的运行时环境。作为一个软件产品,一个模型在某个时间点用特定版本的编码语言和编码库来训练。例如,使用旧版本的 Python 库(如 Pandas 或 Scikit-Learn)在 Python 3.6 上训练的模型很可能无法在使用相同库的最新版本的 Python 3.10 上工作。这是因为底层软件会随着时间的推移而改变,尽管反序列化模型可能会寻找那些较旧的软件依赖关系,但当那些较旧的软件依赖关系已经更新并因此不再存在时,它很可能会失败。
这就是为什么在培训和后期服务模特时使用虚拟环境或 Docker 容器非常重要。这些工具帮助我们恰当地固定软件版本,以确保一个模型可以在将来继续被正确地使用。对于这个特定的问题,一个答案可能是您获取现有的序列化 pickle 文件,并将其包装在 Docker 容器中,该容器模拟它最初被训练的运行时环境。虽然这个答案当然可行,但是更好的选择——如果可能的话——是用最新的软件依赖集重新训练模型。之所以是更好的选择,是因为 Python 库经常更新以修补安全漏洞,所以最好有一个最新的运行时环境来帮助缓解任何安全问题。
伙计们,这篇文章到此结束!希望这些问题对你继续准备下一次数据科学面试有所帮助。同样,我已经策划了更多这样的问题,所以我肯定会再写至少一篇这样的帖子。感谢阅读,下期再见!
创建数据科学博客的四个理由
技术写作
从哪里以及如何开始

文森特·范·扎林格在 Unsplash 上拍摄的照片
介绍
下个月(2021 年 9 月)是我活跃在媒体上的两周年纪念日。写作,不太专业的写作,不是我的强项。它开始是为了分散我写一本书那么长的论文的注意力,但最终变成了一个为期两年的承诺,未来还会有更多的承诺。
我付出了如此多的努力来让它工作,并在数据科学的各个领域创建了 50 多个原创博客帖子,包括编程( R 、 Python 和 SQL )、机器学习(监督和非监督)、实验和因果推理( A/B 测试、准实验设计和观察设计)。
作为回报,我从我的写作中受益匪浅,忠实的读者群,紧密的社区,以及连续三次的额外作家奖金(不能抱怨),这只是其中的几个。
在今天的帖子中,我们来谈谈为什么你也应该创建一个技术博客,以及如何创建。
1。创建展示我技能的在线作品集
我的学术背景是福也是祸。完成一个有竞争力的博士项目展示了我快速学习的智力。但是,与此同时,公司可能会想:
“学术有多少实际经验?”
相信我。你不知道这个问题问了我多少次。
从该公司的角度来看,这代表着健康的犹豫或合理的担忧,因为谈判桌上的赌注很高。
更新在线技术博客发出了一个强烈的信号。也就是说,我对这个主题非常了解,并决定做更多的工作:写一个关于它的循序渐进的教程。数据科学主要有三个职业方向:分析、推理和算法。选择最适合你背景的领域,根据长期职业轨迹定制内容和写作风格,这将发出更强的信号。
与个人网站或其他替代品相比,技术博客是一种更具吸引力的表现形式,有助于双向对话,这是网站所缺乏的。此外,Medium 还提供了大量很酷的功能,如笔记、高亮显示和共享,让您的受众更容易与内容互动。
2。更好地理解材料
教学是最好的学习方式。
我曾经认为统计学概念很简单,但如果不使用任何术语,就无法解释 p 值和假设检验。我曾经相信我理解实验和因果推理,直到我在一次面试中被匹配的技术细节卡住。
还有很多其他“我以为但不在现实中”的情况。我们对从课本上学到的概念和方法保持短暂的记忆,但如果不刷新记忆,就会很快忘记。
从教育学的角度来看,科技写作是将你所学的 传递 的过程。经历过这个过程的学生能更好地理解内容。在记笔记或写东西之前,我总是为自己对这个主题知之甚少而感到谦卑。
3。与社区联系
志同道合的人保持相同的习惯。
作为一个狂热的读者,我花了几个小时阅读其他人的作品。这是一个漫长的旅程,一路上我建立了许多有意义的联系。
数据科学家同事寻求潜在的合作机会。
项目经理对业务应用很好奇。
在实验和因果推理领域大量投资的风险投资家们想知道它的未来。
通过创作有益于他人的内容,我的职业网络得到了显著发展,并与许多其他有趣的人建立了联系。以下是一些数字:
大约 1,700 名媒体追随者
LinkedIn 上约 3,000 名关注者,人数还在增加
我收到的最好的建议之一是你的作品就是你的品牌。通过创建一个品牌,你将在行业中获得牵引力。
4。帮助他人更好地理解材料
有大量的在线课程试图推销“在 10 周或更短的时间内学会数据科学”、“破解数据科学面试,让你赚到第一个一百万”的理念
这种类型的 clickbait 内容在网络上无处不在,初学者可能会迷失在搜索真实内容的道路上。因此,我最大的写作动机是通过创建每个人都可以访问的真实内容来使数据科学民主化。
我的写作策略是对现有作品做一个彻底的“文献综述”,找出增量价值(即差距),并就该话题写一系列原创帖子。

从哪里开始
Medium 是最好的支持内容写作的写作平台。我喜欢在讲台上阅读和写作。它提供了灵活的写作风格,其笔记功能是业界最好的。
如果你是数据科学的新手,试着写一些基本概念之类的主题,比如什么是机器学习中的交叉验证,什么是统计学中的 bootstrap,以及其他基本概念。
如果你对这些话题更有经验,试着开始更有挑战性的话题,比如写实践教程,例如,如何用 Python 构建决策树。
从自己最舒服的层次开始,快速迭代到下一个层次,这是技术写作成功的关键。退一步说,我在平台上的第一篇博客文章是不可读的。然而,在过去的两年里,我的写作风格有了明显的改善。从小处着手,快速迭代。
感谢阅读到目前为止!如果我启发了你写一些东西,请在评论中告诉我。我会在我的社交媒体(如 LinkedIn 和 Twitter)上推送你的第一篇帖子。
外卖食品
1。创建一个展示我技能的在线作品集。
2。更好地理解材料。
3。与社区联系。
4。帮助他人更好地理解材料。
Medium 最近进化出了它的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。
https://leihua-ye.medium.com/membership
喜欢读这本书吗?
还有,看看我其他关于人工智能和机器学习的帖子。
开启数据科学学习之路的四项技能

从哪里开始数据科学学习之旅的初学者指南!
每周至少有两次,技术人员和非技术人员都会来问我关于从哪里开始学习数据科学和机器学习的想法。人们联系我的原因是因为我有一个非常非传统的背景。简而言之,我从一个几乎没有技术知识的纯商业职业道路转向了在非传统教育资源的帮助下成为一名成熟的机器学习工程师。(非传统=我在这方面没有拿到正式学位。)
在 2020 年初,我写了一个非常强大的指南,分享我做的每一件小事,但我发现这对初学者来说太难消化了。此外,与我交谈的人有着不同的背景。有些人像我一样,没有什么技术技能,希望从另一条职业道路转向,有些人在计算机科学方面更有经验,只是他们目前的重点可能是 web 开发。在这两种情况下,我写的健壮指南都太多了,我承认我在那里有点疯狂。😬
也就是说,我在这里创建了一个新的入门指南,大大缩小了关注范围,并帮助人们涉足这个数据科学的世界。如果你是初学者,并且对我是如何撰写这篇文章感到好奇,我希望你记住的主要事情是:数据科学是在数据中寻找趋势的实践,主要目的是做出更明智的商业决策。我在这里强调了“数据”这个词,因为,正如你可能猜到的,如果你没有任何数据可以使用,那么数据科学就会失败!
对于本入门指南,我们不打算深入研究机器学习或您可能感兴趣的任何更复杂的实践。考虑到数据科学就是与数据打交道,我们将在本文中介绍的前两项技能——Python 和 SQL——通常都与数据打交道有关。此外,我非常支持实际应用,因此后两种技能——Git 和命令行界面——将开始向您介绍一些更通用的计算机科学技能,所有数据科学家和机器学习工程师都经常使用这些技能。学习这些技能没有特别的顺序,所以你可以从任何你喜欢的地方开始。
好了,让我们进入 Python 的第一部分吧!
计算机编程语言
尽管在许多计算机科学领域都有使用,Python 无疑是当今数据科学领域最流行的编码语言之一。(仅供参考,其他的包括 R 和 Julia,但是 Python 仍然是最广泛使用的。)我个人是通过 Java 开始学习编码的,让我说……Python 要容易学得多。Python 还允许添加模块来增加额外的功能,称为 Python 库。数据科学中最常用的 Python 库包括 Pandas、Numpy、Scikit-Learn、Matplotlib 等等。不要担心那些库名对你来说是陌生的。作为一个初学者,我鼓励你只是把重点放在学习 Python 上。
虽然你可以在网上找到很多学习 Python 的优秀资源,但我个人推荐的是 Udacity 的 Python 编程入门。我个人今天从 Udacity 学到了 75%的技能,所以我真的很欣赏他们如何组织他们的内容。此外,本课程是免费的,可以通过任何带有网络浏览器的设备轻松完成。
结构化查询语言
结构化查询语言(SQL)是当今每个计算机科学行业中最古老、最容易使用的数据查询语言之一。我认识的几乎每个人都以某种形式使用它。SQL 很有趣,因为它在基础级别上非常强大,或者您可以真正进入兔子洞学习更高级别的东西。在我的日常工作中,我通常不需要那么深入,我用来学习 SQL 的课程是 Udacity 的数据分析 SQL。另一个免费课程,他们实际上与 Mode(一家专门从事数据分析软件的公司)合作创建了这个课程内容。我真的认为这可能是我上过的最好的免费课程。它的结构非常好,可以帮助完全的初学者快速掌握一些更高级的 SQL 主题。这门课怎么推荐都不为过!
饭桶
虽然这不完全是数据分析或数据科学技能,但对于在任何代码库(包括数据科学代码库)上与其他人合作以及在 GitHub 之类的东西上构建工作组合来说,这仍然是极其重要的。幸运的是,Git 是一个非常容易学习的技能,虽然有大量优秀的免费资源,但我不得不再次向 Udacity 的 Git 版本控制脱帽致敬。本课程很好地利用可视化材料从概念上演示了 Git 是如何工作的,然后向您展示了如何通过命令行界面(CLI)应用这些 Git 命令。说到客户端…
命令行界面(CLI)
如果你曾经看过任何类型的黑客电影,包括像 1983 年的 WarGames 这样更愚蠢的电影,那么你很可能已经看过那种看起来不祥的黑屏,上面有奇怪的词,如“sudo”或“curl”这可能是我最喜欢用来描述 CLI 用户对这个话题的感受的迷因:

从 iOfficialHacker Instagram 帐户使用的 Meme
事实是,每个人——包括数据科学家而不仅仅是黑客——都使用 CLI 来执行某种活动。如上所述,Git 是我们数据科学社区如何经常使用 CLI 的一个很好的例子。对于最后一项技能,我将根据你的学习风格推荐两种不同的资源。如果你更喜欢面向视频的在线课程,我推荐 Udacity 的 Linux 命令行基础免费课程。如果你更喜欢一个基于文本的,交互式的大约一个小时的演练,Ubuntu——Linux 操作系统的官方维护者之一——创建了他们自己的教程,你可以在这里找到。
各位,今天的帖子到此结束!我们保持它的简短和甜蜜,以使它更容易被更多的观众所理解。提醒一下,如果你想看我的完整的健壮指南,你可以在这里找到。感谢您查看这篇文章,请务必不要离开,因为我将继续在这个非常酷的数据科学世界中写我自己的心得!
开始使用 Elasticsearch 需要掌握的四件事
实践教程
弹性研究概念和原则的简明概述

elastic search(ES)是一个为可伸缩性和冗余性而设计的分布式搜索引擎。ES 近年来变得越来越受欢迎,因为它在机器学习、存储和处理大量数据以进行分析以及许多其他应用方面具有健壮性和可扩展性。在这篇博文中,我们将讨论数据从业者在开始使用 ES 时需要掌握的四件事情:提供 ES 集群、设计索引、编写查询和优化索引。
1.设置 ES 集群
首先,您需要知道如何设置一个 ES 集群。
Elasticsearch 是一个分布式搜索和分析引擎,是 Elastic Stack 的一部分。针对 es 索引运行的查询以及这些索引中的数据分布在各个节点上。当您建立一个 Elasticsearch 集群时,您添加这些不同的节点(即服务器)。ES 自动处理集群中节点间的查询和数据分布。这确保了可伸缩性和高可用性。
您可以通过众多托管服务提供商之一提供 ES 集群,包括亚马逊网络服务(AWS)亚马逊弹性搜索服务、 Bonsai 或Elastic.co。你也可以在你的机器上本地运行 ES。关于如何以及在哪里提供、部署和管理集群的任何决定都取决于您正在构建哪种解决方案以及您打算将 ES 用于什么目的(下面将详细介绍)。
顺便说一下:AWS 最近(2021 年 4 月)发布了自己的“OpenSearch”项目——Kibana 的 Elasticsearch 的开源分支。这个项目包括 Opensearch(基于 Elasticsearch 7.10.2)和 OpenSearch 仪表盘(基于 Kibana 7.10.2)。AWS 计划将其提供的 Elasticsearch 和 OpenSearch 合并为一个新名称:亚马逊 OpenSearch 服务。
如果你想了解更多关于建立一个 ES 集群的知识,请查看我之前的博客文章,获得关于如何使用 Bonsai 提供免费 ES 集群的实践指导。
2.设计指数
其次,设计 es 索引(即定义映射)是掌握 ES 的关键。这里,几个概念是关键:文档、字段、索引、映射、节点和碎片。
文档、字段和索引
Elasticsearch 中的数据以名为“ 文档 ”的 JSON 对象的形式存储在 索引 中。文档包含字段。这些字段是可以包含值(例如字符串、整数或布尔值)或嵌套结构的键值对。索引,反过来,表示两件事:它们是遵循一个模式的数据的逻辑分组,但是它们也是通过碎片对数据的物理组织——把我们带到 es 中的下一个关键概念:节点和碎片。
节点和碎片
当我们说 ES 是为冗余而构建时,我们实际上指的是什么?具体来说,ES 框架通过节点和碎片,以及主碎片和副本来工作。每个索引由一个或多个物理碎片组成。这些物理碎片形成了一个逻辑组,其中每个碎片都是一个“独立的索引”。
存储在索引中的数据(即文档)跨碎片进行分区,而碎片分布在各个节点上。每个文档由一个“主碎片”和一个“副本碎片”组成。这种设计意味着数据驻留在多个位置,因此可以快速查询,并且可以从多个位置(即碎片)获得。关键组件的这种重复正是 es 设计冗余的原因。
选择正确的碎片数量和尺寸
节点和分片的设计还有一个优点,即不同分片中的数据可以并行处理。通常,在 CPU 和内存允许的范围内,可以通过添加更多的碎片来提高搜索速度。然而,添加碎片会带来一些开销,所以仔细考虑集群中合适的碎片数量(及其大小)是很重要的。
定义您自己的 ES 映射
编写好的 ES 映射需要一些实践(尽管那些熟悉在其他数据库框架中设计模式的人可能会发现转换相当容易)。在这里,重要的是要学会定义自己的映射,而不是使用动态字段映射,并且要知道字段类型的选择对索引大小和查询灵活性的影响。
Elasticsearch 有一个特性叫做“动态字段映射”。启用后,当您将文档写入索引时,动态字段映射会自动推断文档的映射。但是,这不一定会得到您想要的结果,因为它可能不会选择最佳的字段类型。您通常希望定义自己的映射,因为字段类型的选择决定了索引的大小和查询数据的灵活性。
文本与关键字字段类型
例如,您可以将text字段类型用于字符串值。使用这种字段类型,当您的文档被索引时,字符串被分解成单独的术语,从而在查询时提供了部分匹配的灵活性。字符串值的另一个选项是keyword字段类型。但是,这种类型在索引时不会被分析(或者说:“标记化”),并且会将您的查询选项限制为精确匹配。
我的数组字段呢?
编写映射时需要注意的另一件事是 ES 没有数组字段类型。如果您的文档包含数组,您必须使用该数组中值的类型。例如,对于整数数组,正确的 ES 字段类型是integer(见本页对 ES 字段类型的完整概述)。
要深入了解如何定义 es 映射和填充索引, 查看我之前关于用 Python 创建和管理 ES 索引的博客文章的第一部分。
3.编写查询
你需要学习的第三件事是编写有效的查询。这里需要掌握几个概念:DSL、相关性分数和过滤与查询。
使用领域特定语言(DSL)进行搜索
Elasticsearch 完全是关于搜索的(嗯,大部分是)。对 Elasticsearch 的查询是用 Elasticsearch 领域特定语言(DSL) 编写的。DSL 是查询的所谓“抽象语法树(AST)”,基于 JSON。当执行一个查询时,ES 会计算一个相关性分数,这个分数会告诉我们文档与查询的匹配程度。ES 返回的结果(即文档)按相关性分数、、排序,相关性分数在结果的_score字段中找到。
DSL 包括两类条款。第一种类型是叶查询子句,用于搜索特定字段中的精确值(例如,当使用 [term](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html) 查询来查找与精确值对应的文档时)。第二种类型是复合查询子句 —用于以逻辑方式组合多个查询的查询(可能是不同的类型,包括叶查询和复合查询)。复合查询子句也可以用来改变这些查询的行为。
查询和过滤上下文
ES 查询可以包括查询和过滤器上下文。过滤上下文用于排除与您在语法中设置的特定条件不匹配的文档。因此,查询和过滤上下文与相关性分数也有不同的“关系”:过滤上下文不影响它,而布尔上下文对它的值有贡献。
决定是使用过滤器还是查询上下文是编写有效查询的重要部分。一般来说,由于频繁使用的过滤器被自动缓存以增强性能,过滤器更便宜(计算上)。然而,过滤器用于搜索明确的条件,即有明确的“是”或“否”答案。例如,如果您想要识别特定字段具有精确数值的文档,则筛选器非常有用。
在其他情况下,什么“匹配”你的搜索条件的问题就不那么明确了。对于这些“不明确”的情况,应该使用查询上下文。这种搜索情况的一个例子是,当您使用匹配查询在包含图书元数据的索引中查找部分书名时(我们假设您已经忘记了要查找的图书的确切书名)。这里,不同的文档(具有不同的标题字段值)可能比其他文档与您的搜索更相关。在这个具体的例子中,我们正在处理全文搜索,也就是说,对搜索分析过的文本字段的查询(“匹配”查询是全文搜索的标准查询)。
关于编写 es 查询和使用 Python Elasticsearch 客户端 , 查询 ES 的深入概述,请查看我之前关于使用 Python 创建和管理 ES 索引的博文。
4.优化您的指数
最后,你需要掌握优化 es 指数的策略。
不同的指数可能服务于不同的目的,因此需要特定的优化策略。例如,如果您使用 ES 来处理和存储大量数据,您可能需要优化磁盘使用。在这里,您需要学习如何有效地定义映射(例如,避免使用动态映射,并使用尽可能小的字段类型),以及如何使用带有索引生命周期管理(ILM) 和自动索引翻转的热-暖-冷架构来优化成本。
对于其他应用程序,您可能需要优化搜索速度,在这种情况下,您可能需要研究索引排序,获得更快的驱动器或更快的 CPU(取决于搜索的类型),或者更有效的文档建模(例如,避免连接)。
要深入了解优化您的 ES 磁盘使用指数,请查看我之前的博客文章 在 Elasticsearch 中优化磁盘使用。
等许多用途。毫无疑问,ES 是添加到您的数据科学工具包中的一个有用的框架。在这篇博文中,我们介绍了 Elasticsearch 的一些核心概念和原则,以帮助您开始在自己的应用程序中使用 es。
感谢阅读!
https://medium.com/@ndgoet/membership
如果你喜欢这篇文章,这里还有一些你可能喜欢的文章:
[## 优化弹性搜索中的磁盘使用
towardsdatascience.com](/optimising-disk-usage-in-elasticsearch-d7b4238808f7)
免责声明:“elastic search”和“Kibana”是 Elasticsearch BV 在美国和其他国家注册的商标。本文中对任何第三方服务和/或商标的描述和/或使用不应被视为对其各自权利持有人的认可。
在依赖 中的任何内容之前,请仔细阅读 本免责声明 我关于 Medium.com 的文章 。
在 Python 中你应该知道的四件事
学习如何在 Python 中分割序列、循环序列、压缩/解压缩可重复项,等等

照片由 Gema Saputera 在 Unsplash 上拍摄
有了大量可用的 Python 资源,很难知道哪些可用的工具实际上是有用的。
在本文中,我们将重点讨论四种工具,在我看来,了解这些工具在 Python 中非常有价值。我们先讨论如何在 Python 中 切片序列 ,具体是列表和字符串,包括如何轻松反转。然后,我们将使用 enumerate() 函数,继续寻找遍历序列的最佳方式之一,跟踪索引和元素。之后,我们将学习 zip() 函数,该函数可用于 zip 和 unzip iterable 对象。最后,我们将回顾使用 f 字符串 格式化字符串的最佳方式。
1.切片序列
切片允许我们从一个序列中获取一部分,比如一个列表或字符串。
变量【开始:停止:步进】
为了分割一个序列,我们需要在方括号中使用冒号。换句话说,下标符号[方括号]中的冒号(:)构成切片符号。尽管我们可以在括号内提供三个可能的值(开始值、停止值和步/步幅值),但我们实际上并不需要提供所有三个值,除非我们需要这样做,如下所示。
让我们看一些例子。
指定开始和停止值
我们分割一个序列(比如一个列表)的一种方法是指定起始值和终止值。换句话说,如果我们想要列表中两个特定点之间的所有元素,我们可以使用以下格式:
变量【启动:停止】
变量[start:stop]返回变量中以位置 start 开始的部分,直到但不包括位置 stop。
例如,如果我们想获得从索引 2 到索引 6 的所有元素,我们可以这样做:
num_list = [0,5,10,15,20,25,30,35,40]num_list[2:7]
#[10,15,20,25,30]
注意起始值是如何包含的,但终止值是如何排除的。由于我们没有提供步长值,默认步长值是 1 。因此,我们从索引 2 开始,然后向索引 3 前进 1 步,再向索引 4 前进 1 步,依此类推。换句话说,因为步长值是正的,所以在对列表进行切片时,我们将索引增加 1(向右移动)。
仅指定起始值
如果我们想从一个特定的数字开始并遍历整个列表,那么我们只需要提供起始值。
变量【开始:】
变量[start:]返回从位置 start 开始到序列结束的变量部分。
例如,如果我们想从整个列表的第二个索引中检索所有元素,我们可以使用下面的代码:
num_list = [0,5,10,15,20,25,30,35,40]num_list[2:]
#[10,15,20,25,30,35,40]
正如我们所看到的,如果我们只在冒号前提供一个索引,那么这将是我们的开始索引,我们将获得列表中的其余元素(因为步长值仍然是 1)。
仅指定停止值
如果我们想从列表的开头开始,一直到一个特定的索引,那么我们只需要提供停止值。
变量[:停止]
变量[:stop]返回从序列开始处开始的变量部分,直到但不包括位置 stop。
例如,如果我们想要检索从列表开始到索引 7(包括索引 7)的所有元素,我们可以这样做:
num_list = [0,5,10,15,20,25,30,35,40]num_list[:8]ornum_list[:-1]
#[0,5,10,15,20,25,30,35]
如果没有为起始值提供数字,那么它假设我们希望从索引 0 开始。由于我们想要检索索引 7 之前的所有元素,我们将使用停止值 8,因为它是排他的。我们也可以使用-1 作为停止值。
使用正指数和负指数
我们也可以混合搭配正负指数。例如,如果我们想要检索索引 2 到索引 7 之间的所有元素,我们可以这样做:
num_list = [0,5,10,15,20,25,30,35,40]num_list[2:8]or num_list[2:-1]ornum_list[-7:-1]ornum_list[-7:8]
#[10,15,20,25,30,35]
请注意,在所有情况下,停止值都在起始值的右侧,因为我们使用的是正步长值。换句话说,相对于起始值,停止值必须在步长值的方向上。如果步长值为正,则停止值必须在起始值的右侧。如果步长值为负,则停止值必须位于起始值的左侧。稍后会详细介绍。
检索整个列表
我们还可以通过使用不带开始或结束值的冒号来检索整个列表。
变量[:]
变量[:]返回整个序列。
num_list = [0,5,10,15,20,25,30,35,40]num_list[:]or num_list[::]
#[0,5,10,15,20,25,30,35,40]
步幅值
到目前为止,我们只指定了开始和/或停止值,我们从开始值开始,在停止值之前结束(因为它是唯一的)。但是如果我们不想要这两点之间的所有元素呢?如果我们想要所有其他元素呢?这就是 步长值 的由来。
假设我们需要列表中的所有其他值,从索引 0 开始。或者我们只需要偶数索引的元素。我们可以通过改变步长值来实现:
变量[::步骤]
num_list = [0,5,10,15,20,25,30,35,40]num_list[::2]
#[0,10,20,30,40]
因为我们没有指定开始或停止值,所以它假设我们想要从序列的开始处开始并遍历整个列表。所以它从索引 0 开始,然后到索引 2(因为步长是 2),然后到索引 4,依此类推。
之前我们提到过,相对于起始值,停止值必须与步长值方向相同。换句话说,如果步长值为正,这意味着我们向右移动,停止值必须在起始值的右边。如果步长值为负,则停止值必须位于起始值的左侧。否则,将返回一个空列表:
num_list = [0,5,10,15,20,25,30,35,40]num_list[8:5]
#[]num_list[8:5:-1]
#[40,35,30]
正如我们所看到的,在两个例子中,开始值是 8,停止值是 5,所以停止值在开始值的左边。在第一个示例中,步长值为+1。因为停止值在开始值的左边,而我们的步长值是正的,所以返回一个空列表,因为我们不能向停止值的方向移动。然而,在第二个示例中,我们将步长值更改为-1。因此,我们从索引 8(40)开始,向负方向或左方向移动 1 个索引到索引 7(35),然后到索引 6(30)。我们不去索引 5,因为停止值是唯一的。
颠倒顺序
也许步长值最重要的实际应用是反转一个序列。例如,如果我们想以相反的顺序检索整个列表,我们可以使用-1 作为步长值:
num_list[::-1]
#[40,35,30,25,20,15,10,5,0]
因为我们没有指定开始或停止值,所以将检索整个序列。但是,因为我们的步长值是-1,所以它以相反的顺序获取元素。
如果我们的止损值大于序列中可用的最高指数,该怎么办?或者我们的开始和/或停止值是否超出范围?换句话说,如果我们要求的东西比现有的多,会发生什么?
例如,如果我们尝试以下方法:
num_list = [0,5,10,15,20,25,30,35,40]num_list[2:12]
#[10,15,20,25,30,35,40]
正如我们所看到的,即使我们请求的条目比序列中的多,它也只是返回所有存在的元素,而不会给我们一个错误。相比之下,如果我们试图索引一个超出范围的元素(而不是切片),那么我们会得到一个 IndexError,就像我们前面看到的那样。
num_list[12]
#IndexError
分割字符串
索引和切片对于字符串也是同样的工作方式。
word = 'Python'
因此,为了通过切片获得子串“yt ”,我们可以这样做:
word[1:3]
#'yt'
要反转一个字符串,我们可以使用步长值-1:
word[::-1]
#'nohtyP'
回文示例
让我们用我们所学的知识来解决一个非常常见的 python 编码问题。我们想写一个函数,接受一个字符串,并返回这个字符串是否是一个回文。如果一个字符串的倒数与原字符串相同,则该字符串为回文。例如,“civic”是回文,但“radio”不是,因为“radio”的反义词是“oidar”,而“civic”的反义词是“civic”。
我们刚刚学习了如何通过使用步长值-1 来反转序列。因此,我们可以很容易地编写一个函数来实现这一点,如下所示:
isPalindrome(word):
return word == word[::-1]
就是这样!表达式 word == word[::-1] 的计算结果为 True 或 False。如果我们传入的字符串等于它的倒数,那么表达式的计算结果为 True,返回 True。如果我们传入的字符串不等于它的倒数,那么表达式的计算结果为 False,并且返回 False。
isPalindrome('civic')
# TrueisPalindrome('radio')
# False
切片分配
如果我们记得,列表是 python 中的可变对象。换句话说,它们能够变异或改变。因此,我们可以使用片分配操作来适当地改变或编辑列表。
代替
*num_list = [0,5,10,15,20,25,30,35,40]**num_list[2:5] = [1,2,3]**num_list
#[0,5,1,2,3,25,30,35,40]**num_list[2:5] = [1,2,3,4,5,6]**num_list
#[0,5,1,2,3,4,5,6,25,30,35,40]*
注意我们如何用更多或更少的元素替换列表的一部分。
删除
我们也可以使用关键字删除列表的一部分或一部分:
*num_list = [0,5,10,15,20,25,30,35,40]del num_list[2:5]num_list
#[0,5,25,30,35,40]*
字符串和元组是不可变的。因此我们不能像对列表那样编辑或改变它们。
分割字符串与列表
分割列表将返回该列表的副本,而不是对原始列表的引用。
我们可以在这里看到这一点:如果我们将我们的列表片分配给另一个列表,因为列表片返回一个副本,而不是对原始列表的引用,我们可以修改新列表(因为列表是可变的)而不影响原始列表:
*num_list = [0,5,10,15,20,25,30,35,40]**# assign a slice of num_list to new_list** new_list = num_list[2:5]new_list
#[10,15,20]**# replace the third element of new_list with 3** new_list[2] = 3**# new_list changes** new_list
#[10,15,3]**# num_list remains the same** num_list
#[0,5,10,15,20,25,30,35,40]*
相比之下,当我们分割一个字符串时,返回的是对原始字符串对象的引用,而不是副本。记住,字符串在 Python 中是不可变的。
我们可以使用 Python 的 标识操作符(is) 和 相等操作符(==) 来确认对一个列表切片返回一个副本或者一个不同于原始列表的对象,但是对一个字符串切片返回一个对原始字符串对象的引用:
***Lists:** num_list = [0,5,10,15,20,25,30,35,40]num_list == num_list[:]
#Truenum_list is num_list[:]
#False**Strings:** word = 'Python'word == word[:]
#Trueword is word[:]
#True*
相等运算符(==)检查值是否相等。identity 运算符(is)检查这两个变量是否指向内存中的同一个对象。
关于切片序列的更多信息:
* *
2.枚举()函数
enumerate()允许我们遍历一个序列,但它同时跟踪元素和索引。
枚举(iterable,start=0)
enumerate() 函数接受一个 iterable 作为参数,如列表、字符串、元组或字典。此外,它还可以接受一个可选参数, start ,该参数指定我们希望索引从哪个数字开始(默认为 0)。
使用 enumerate() 函数,我们可以编写一个 for 循环:
*num_list= [42, 56, 39, 59, 99]for index, element in enumerate(num_list):
print(index, element)# output:
0 42
1 56
2 39
3 59
4 99*
enumerate() 函数返回一个枚举对象,该对象是一个迭代器。当从这个枚举对象访问每个元素时,返回一个元组,其中包含索引和该索引处的元素:(index,element)。因此,在上面的 for 循环中,在每次迭代中,它都将这个返回元组的元素分配给 index 和 element 变量。换句话说,返回的元组在 for 语句中被解包。
我们还可以通过将 1 作为 enumerate()函数的 start 参数的参数来指定从 1 开始索引:
*num_list = [42, 56, 39, 59, 99]for index, element in enumerate(num_list, start=1):
print(index, element)# output:
1 42
2 56
3 39
4 59
5 99*
关于 enumerate()函数和迭代器的更多信息:
* 
托马斯·索贝克在 Unsplash 上拍摄的照片
3.zip()函数
zip() 功能因其类似于物理拉链的机制而得名。当你拉上拉链的时候,你把两边都拉到了一起。这就是 zip()函数的工作方式!它将来自多个可迭代对象(如列表)的相同索引的元素放在一起,作为相同元组的元素。
zip(*iterables)
例如,假设我们有两个列表, first_names 和 last_names ,我们希望将两个列表中相同索引的元素组合成一个元组列表,如下所示:
first_names = ['Jane', 'John', 'Jennifer']
last_names = ['Doe', 'Williams', 'Smith']Desired Output:
[('Jane', 'Doe'), ('John', 'Williams'), ('Jennifer', 'Smith')]
我们可以使用 python 内置的 zip() 函数来实现这一点:
first_names = ['Jane', 'John', 'Jennifer']
last_names = ['Doe', 'Williams', 'Smith']full_names = list(zip(first_names, last_names))print(full_names)
# [('Jane', 'Doe'), ('John', 'Williams'), ('Jennifer', 'Smith')]
函数接受 iterables 作为参数,比如列表、文件、元组、集合等等。然后,zip()函数将创建一个迭代器,从传入的每个 iterables 中聚合元素。换句话说,它将返回一个元组的迭代器,其中第个 元组将包含来自中传递的每个 iterables 的第 I 个元素。一旦最短的输入 iterable 用尽,这个迭代器将停止。
注意:由于 zip() 函数返回一个迭代器,我们需要使用 list() 函数,它将使用这个返回的迭代器(或 zip 对象)来创建一个列表。此外,只要传入的 iterables 是有序的(序列),那么元组将包含与 zip()函数中传入的参数从左到右顺序相同的元素。
使用 zip()函数解压缩 Iterables 与压缩不同的是,解压缩把东西分开。我们还可以使用 zip() 函数,通过添加如下解包操作符*来解压缩 python 中的可迭代对象:
first_and_last_names = [('Jane', 'Doe'), ('John', 'Williams'), ('Jennifer', 'Smith')]first_names, last_names = zip(*first_and_last_names)first_names = list(first_names)
last_names = list(last_names)print(first_names)
# ['Jane', 'John', 'Jennifer']print(last_names)
# ['Doe', 'Williams', 'Smith']
解包操作符* 将把元组的名字和姓氏 列表解包成它的元组。然后,这些元组将被传递给 zip() 函数,该函数将获取这些单独的可迭代对象(元组),并将它们的相同索引元素组合成元组,形成两个单独的元组。最后,通过元组解包,这些分离的元组将被分配给名和姓变量。然后我们使用 list() 函数将这些元组转换成列表。
关于 zip()函数和解包操作符的更多信息:
4.f 弦
F-strings 是 Python 3.6 及以上版本中一种新的字符串格式化方式。对于大多数人来说,它们是格式化字符串的首选方式,因为它们易于阅读并且更加直观。
我们将使用 名字 , 姓氏 和 年龄 变量创建一个字符串,其中包含某人的名字、姓氏和年龄,格式如下:
‘名字姓氏年龄岁’
为了指定我们想要使用一个 f-string ,或者格式化的字符串,我们只需要在字符串前面放一个 f。然后,我们可以直接将变量添加到我们希望它们出现的花括号中。因此,我们不需要像使用【format()方法那样使用任何方法或在字符串末尾传递任何变量。
f'{var_1} {var_2}是{var_3}岁'
因此,为了用 f 弦 完成上述任务,我们将使用以下代码:
first_name = 'John'
last_name = 'Doe'
age = 43sentence = f'{first_name} {last_name} is {age} years old'print(sentence)
# 'John Doe is 43 years old'
类似于 format() 方法,我们也可以运行 f-string 内的方法或函数。例如,如果我们想让名字大写,姓氏小写,我们可以在 f-string 中使用相应的字符串方法:
first_name = 'John'
last_name = 'Doe'
age = 43sentence = f'{first_name.upper()} {last_name.lower()} is {age} years old'print(sentence)
# 'JOHN doe is 43 years old'
如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名媒体会员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你用我的 链接 注册,我会赚一小笔佣金。
https://lmatalka90.medium.com/membership
结论
在本教程中,我们看了 4 个非常有用的 Python 工具。我们首先学习了如何分割序列,比如列表和字符串,通过使用方括号和一个或多个冒号来检索这些序列的部分。我们还看到了切片赋值是如何工作的,以及切片一个列表和切片一个字符串之间的区别,因为切片一个列表会返回该列表的副本,而切片一个字符串会返回对原始字符串对象的引用。接下来,我们看了如何使用 zip() 函数压缩可迭代对象,以及使用带有解包操作符的 zip() 函数解压缩可迭代对象。然后,我们学习了如何使用 enumerate() 函数在遍历 iterable 对象时跟踪元素和索引。最后,我们学习了如何使用优雅简洁的 f 字符串来格式化字符串。
如何超级学习数据科学
成为高效快速学习者的秘诀

Marc-Olivier Jodoin 在 Unsplash 上拍摄的照片
我想写这篇文章,因为我收到了很多关于如何学习数据科学的问题,我理解这种挣扎。一开始真的很难应付,尤其是当你发现你必须学习编程、统计、数学等等的时候。这份清单似乎是无穷无尽的,但是请相信我,它并没有你想象的那么糟糕。
我的目标有两个:
- 我想给你一些指导和建议,让你的学习之旅更加顺利
- 我想和你分享一些帮助我加快学习速度的小技巧

作者创建的图像
说到这里,让我们开始吧!
1)你学了多少由两个变量决定…
首先,你要知道“学习”指的是知识和技能的获得。所以当我说“学习”时,我指的是学习理论(知识)和学习如何应用这些知识(技能)。
这不是火箭科学,但有两个主要因素影响你在给定时间内学到多少东西:

- 投入的时间:同样,这不是火箭科学。如果你每天花 2 小时学习数据科学,而不是 1 小时,你可以筛选两倍的材料,花两倍的时间应用你的技能(例如编程)。
- 保留量:学习技能是一回事,保留又是另一回事。你可能听说过遗忘曲线。简单来说,你需要在学习数据科学和实践你所学的东西时保持一致。
就我个人而言,我认为我做出的最好的决定之一是承诺在 52 周内每周学习和撰写一次与数据科学相关的任何内容,因为这迫使我投入大量时间并保持一致。
2)从基本面开始
如果你读过我以前的文章,我可能在这一点上听起来像是一张破唱片,但从基本面开始会有很大的帮助。可能感觉这是一条较慢的路线,但是这将允许你在将来学习建立在这些基础上的更复杂的概念。
我建议学习的基础知识是:
- 统计与概率:数据科学和机器学习本质上是现代版的统计学。通过先学习统计学,在学习机器学习概念和算法时,你会轻松得多。
- 微积分和线性代数:像统计学一样,许多数据科学概念都建立在基本的数学概念之上。为了理解成本函数,你需要知道微分学。为了理解假设检验,你需要理解整合。再举一个例子,线性代数对于学习深度学习概念、推荐系统和主成分分析是必不可少的。
- 编程(Python,SQL): SQL 可以说是任何类型的数据相关职业中最重要的技能,无论你是数据科学家、数据工程师、数据分析师还是业务分析师,这个清单还会继续下去。至于 Python,它似乎是数据科学家使用的主要脚本语言(而我对 R 一无所知)。
关于上面的题目,你不一定要把所有的都学完,但是在一头扎进机器学习和深度学习之前,你绝对要先了解一下基本面。这就引出了我的下一个观点…
如果你想要一些学习这些的资源,可以看看我下面的文章:
3)不要试图记住所有的东西
理解你所学的是一回事,但试图记住所有的东西是另一回事。尤其是当涉及到 SQL、Python 和 Pandas 时,不要觉得你必须学习它们提供的每一个函数和方法。相反,在编程时,专注于学习如何谷歌正确的问题。
我曾与数据科学社区的资深人士交谈过,但我从未见过一个人能够记住每一个 SQL 和 Python 函数。这是一种低效的时间利用,可以更好地用在其他事情上,如建设项目!
4)在“做”中学习
正如我之前提到的,通过做而不仅仅是学习,你会学到更多的知识和技能。类似于你在学校学了一个新概念后怎么做作业,需要不断地把学到的东西运用到项目中。
而且不用担心完成复杂的项目。甚至像对数据集进行探索性数据分析这样简单的事情也会帮助你加速学习。
以下是让你开始的一些想法:
想法 1: SQL 案例研究
链接到案例 。
本案例的目的是确定社交网络 Yammer 用户参与度下降的原因。在深入研究这些数据之前,您应该先阅读一下 Yammer 的概述这里是。您应该使用 4 张表。
以上案例的链接将为您提供更多关于问题、数据和应该回答的问题的细节。
如果你需要指导,请点击这里的查看我是如何完成这个案例研究的。
想法 2: Trustpilot 网络搜索引擎
学习如何网络搜集数据简单易学而且非常有用,尤其是在为个人项目收集数据的时候。抓取客户评论网站,如 Trustpilot,对公司来说是有价值的,因为它可以让他们了解评论趋势(变得更好或更差),并通过 NLP 了解客户的意见。
首先,我会熟悉 Trustpilot 是如何组织的,并决定分析哪种业务。然后我会看一下如何获得 Trustpilot 评论的演练。
想法三:机器学习大赛
在我看来,没有比通过竞赛展示您的代码更好的方式来表明您已经为数据科学工作做好了准备。Kaggle 举办了各种各样的比赛,包括建立一个模型来优化某个指标,其中之一是大型机器学习比赛。
如果您想获得一些灵感和指导,请查看其中一个解决方案的分步演练。
感谢阅读!
我希望这些建议对你有帮助!最重要的一点是,你要坚持学习——我认为这比你的学习方法和你使用的学习资源更重要。将其他一切都视为可以调整的更小的超参数;).
我祝你学习一切顺利!
不确定接下来要读什么?我为你挑选了另一篇文章:
又一个!
特伦斯·申
四种不同寻常的 Python 代码味道
以及如何处理它们。

照片由来自 Pexels 的 Michael Burrows 拍摄,由作者使用 Python 修改
当我想到编程和教育的时候,我畏缩了。我畏缩是因为课程涉及所有编程方面,除了一个——软件设计。可悲的是,软件设计是软件开发的关键要素。
"写代码不是生产,也不总是技艺,尽管它可以是,它是设计."— 乔尔·斯波尔斯基
如果没有软件设计,人们会停留在 20 世纪 90 年代——那时软件通常是从零开始实现的。然而今天,最小的创业公司都会产生数千行代码,更不用说科技巨头、游戏工作室、汽车制造商等等。
这些公司通常基于以前版本的代码开发新软件,这为创新和创造提供了空间。当然,如果没有一个可维护、可重用、可读和高效的代码库,这是不可能的。这些特性共同阐明了良好的代码重构实践或反代码味道的本质。
“代码味道”这个术语是由 fowler 和 kent 在他们的书《重构:改进现有代码的设计》中提出的。但实际上,这个术语只不过是糟糕的代码设计的一个厚颜无耻的同义词。
也就是说,在这篇文章中,我们将讨论四种不寻常的坏代码味道以及重构它们的方法。它们是“不寻常的”,因为据我所知,我们将要讨论的代码味道不是你通常在互联网上偶然发现的。所以,我希望你能像我一样从中受益。让我们开始吧:
Lambda 函数的误用
函数是传统函数的语法糖。它们是运行时调用的匿名构造。它们的效用源于它们的简洁。
然而,当 lambda 变得太长而难以阅读或太复杂而难以理解时,它就失去了魅力和有效性。更重要的是,lambda 在封装不可重用代码方面崛起并大放异彩。否则,您最好使用标准函数。
为了解决 lambda 不恰当使用的不同场景,我们汇编了 lambda 开始发臭的三个用例:
#1.将 Lambda 绑定到变量
考虑这个例子:
好闻:
def f(x, y):
return x + y
难闻的气味:
f = lambda x, y: x + y
乍一看,人们可以自信地说,将 lambda 绑定到一个变量就像显式的 def 声明一样好。但是实际上,这种实践是一种软件反模式,因为:
- 首先,它违背了 lambda 函数的定义。也就是说,你给了一个匿名函数一个名字。
- 第二,它把 lambda 函数的目的抹杀了。也就是把 lambda 嵌入到更大的表达式中( PEP 8 )。
#2.长λ
到目前为止,很明显长 lambda 函数是糟糕代码设计的暗示。然而,问题是允许测量这种长度的启发式方法。
嗯,研究表明 lambda 表达式应该遵守以下标准:
- NOC ≤ 80
NOC:字符数
因此,lambda 表达式不应超过 80 个字符。
#3.肮脏的λ
Lambda 函数吸引了许多开发人员,尤其是初级开发人员。它的便利性和美学设计很可能会让人陷入肮脏的λ陷阱。
你看,lambda 被设计成执行一个表达式。建议此表达式的字符数少于一定数量。为了避开这种约束,出现了一些卑鄙的手段和变通方法。
嵌套的 lambda 函数和内部标准函数是臭名昭著的肮脏的变通方法。让我们举一个例子来近距离观察这一点:
难闻的气味:
# inner lambda function
func = lambda x= 1, y= 2:lambda z: x + y + z
f = func()
print(f(4))
好闻:
def func(x=1, y=2):
def f(z):
return x + y + z
return f
f = func()
print(f(4))
正如您所看到的,虽然 lambda 示例更简洁(3 行对 6 行),但是 lambda 代码更混乱,更难破译。这种做法引起的混乱的一个例子是这个线程。
长范围链接
长范围链接是嵌套在封闭函数中的内部函数的集合。内部函数在技术上被称为闭包。以下示例提供了一个更清晰的画面:
def foo(x):
def bar(y):
def baz(z):
return x + y + z
return baz(3)
return bar(10)print(foo(2)) # print(10+3+2)
用内部函数填充函数是一个非常有吸引力的解决方案,因为它模拟了隐私,这对于 Python 这样的语言来说特别有用和方便。这是因为,与 C++和 Java 不同,Python 几乎没有私有和公共类变量的区别(尽管有一些黑客攻击)。然而,这种实践开始嗅到闭包越深的味道。
为了解决这个问题,已经为闭包设置了一个阈值试探。该指标规定最多有 3 个闭包。否则,代码开始看起来模糊,变得难以维护。
无用的异常处理
异常处理程序是程序员用来捕捉异常的常用工具。它们在测试代码中非常有用。然而,如果异常是(1)不准确的或(2)空的,它们就变得没有用了。
#1.不准确的例外
try … except 语句给了程序员管理异常的自由。这导致了非常一般和不精确的异常。看看这个:
try:
pass
except Exception:
raise
# OR
try:
pass
except StandardError:
raise
在这个例子中,异常太过笼统,很可能预示着一系列的错误,很难发现问题的根源。这就是为什么建议对异常要精确和具体。下面的示例是一个很好的实践,它专门用于指示导入错误:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
#2.空异常
谈到错误处理程序,没有什么比纯粹的异常更糟糕的了。
空except:捕捉systemExit和KeyboardInterrupt异常,用 Ctrl+C 渲染程序中断更加困难。更不用说掩饰其他问题了。
为了解决这个问题,Python 风格指南 PEP 8 建议将简单的异常限制为两种用例:
- 无论问题的性质如何,用户都希望标记错误或记录追溯。
- 如果用户想从底部到顶部提出异常,
try … finally是一个很好的选择。
#3.补救措施?
与其他引用的代码味道不同,重构异常没有放之四海而皆准的解决方案。然而,一般的补救措施是尽可能具体和仔细地编写异常处理程序。
著名系列(len(sequence))
坦率地说,range(len())是一个坏习惯。这曾经是我默认的循环机制。但是,我很高兴现在我不记得我最后一次使用它。
range(len())吸引新的 Python 开发者。它甚至吸引了经验丰富的开发人员,他们的数字循环(C++之类的循环)已经在他们的大脑中形成。对于这些人来说,range(len())感觉像家一样,因为它复制了与传统数值循环相同的循环机制。
另一方面,range(len())被 Python 战士和经验丰富的开发人员所轻视,因此被认为是迭代反模式。原因是range(len())使得代码容易出现 bug。这些错误很大程度上源于程序员忘记了range()的第一个参数是包含性的,而第二个是排他性的。
为了一劳永逸地解决这个问题,我们将列举使用range(len())的常见借口及其正确的替代表达。
- 您需要序列的索引:
**for** index, value **in** enumerate(sequence):
**print** index, value
- 您希望同时迭代两个序列:
**for** letter, digit **in** zip(letters, digits):
**print** letter, digit
- 您想要迭代序列的一个块:
**for** letter **in** letters[4:]: #slicing **print** letter
如你所见,避免range(len())是可能的。尽管如此,当序列索引的使用超出了序列本身(例如函数)时,使用range(len())似乎是一个明智的选择。例如:
**for** x **in** range(len(letters)):
**print** f(x)
外卖食品
技术进步给人们编写和分析代码的方式带来了巨大的变化。变得更好。然而,反模式、代码味道、糟糕的代码设计等等,仍然是一个非常主观和开放的话题。
软件设计原则是主观的,因为它们基于现实生活的经验和固执己见的观点。这也许就是为什么软件开发者聚会不能没有软件设计辩论的原因。
例如,一些开发人员发现长 lambda 函数会使代码变得很臭,而其他开发人员则喜欢 lambda,并认为它是 pythonic 式的,无害的。我个人认为,袖手旁观站在前者一边。
简而言之,没有一个软件能够在没有重构实践的情况下生存下来,正如俗话所说:
“臭了就换。”—肯特·贝克和马丁·福勒
我希望这篇文章能让你的代码看起来更好。
参考
https://www.semanticscholar.org/paper/JSNOSE%3A-Detecting-JavaScript-Code-Smells-Fard-Mesbah/86dd17663c963772e6dd3ec8e2b1ab4a8a0e377f https://ieeexplore.ieee.org/document/7780188
傅立叶变换,每个人都做

安德烈·卡鲁茨基拍摄的图片
时间序列建模中的傅里叶变换

图片来自 xkcd
L 毫无疑问。我们的耳朵对所有到达它们的声音进行傅立叶分析;它们是大自然给我们的一个内置傅立叶变换设备。当然,对于任何能够处理音频信号的生物来说都是如此。本质上,我们的耳朵从不断从各个方向轰击我们的音频时间序列中构建了一个频谱。
我不会深入傅立叶变换(FT)的数学细节和公式,而是尽可能简单地解释它。傅立叶变换操作采用基于时间的模式(公平地说,它也可以是基于空间的模式,但让它保持简单),通过“滤波器”运行,并返回正弦和余弦函数的组合以及相关的函数偏移、频率和幅度。信号可以是任何与时间相关的周期函数,由正弦和余弦函数组合而成,如下所示:

图一。作者图片
换句话说,FT 将时域中的周期函数转换为频域中的函数:

图二。作者图片
约瑟夫傅立叶定理指出,任何周期函数都可以表示为正弦和余弦函数的和。这个和可以是无限的。对函数形状有贡献的正弦和余弦函数称为傅立叶级数。
时间序列分析中的傅立叶变换
傅立叶级数如何用于时间序列分析?在这篇文章中,我想介绍几个应用。
FT 在时间序列分析中的第一个应用是检测季节性。其背后的想法很简单:将离散傅立叶变换(DFT)应用于时间序列,以找到傅立叶级数的频率,并查看哪些项具有最高的振幅。这些术语是最有影响力的,它们的周期指向一个系列的季节性。警告:因为时间序列不是连续函数,所以使用离散傅立叶变换是必要的。
我将使用 2015 年至 2019 年间我的项目之一科罗拉多犯罪数据的时间序列来说明这一应用。

图三。作者图片
目测指向系列的季节性成分(最有可能是年度季节性)。为了证实我的评估,我在训练集中使用了 numpy.fft.rfft() 和 numpy.fft.rfftfreq() 。
numobs = len(ts)
ts_ft = np.abs(rfft(ts))
ts_freq = rfftfreq(numobs)plt.figure(figsize=(18, 8))
plt.plot(ts_freq[2:], ts_ft[2: ])
plt.xlabel('Frequency (1/day)')
plt.show()

图 4。作者图片
ts_season = pd.DataFrame({'Amplitude':ts_ft[2: ], 'Freqency':ts_freq[2: ], 'FFF':ts_raw[2:], 'Phase':ts_phase[2:]})
ts_season['Period in days'] = (1/ts_season['Freqency'])
df=ts_season.sort_values(by=['Amplitude'], ascending=False).head(6)
df=df.reset_index()
df=df.rename(columns={'index':'F_label'})
for i in range(0,len(df.index)):
df.iloc[i:, 0]='F_'+str(i+1)
df

表 1。作者图片
正如预期的那样,结果表明数据集的季节性具有强大的年度成分(365 天)和可能的每周成分(约 7 天)。
第二个应用:通过从时间序列的频谱中去除一些频率来平滑时间序列,也称为“去除噪声”其思想是将傅立叶变换应用于时间序列,去除阈值以上的频率,并将其逆傅立叶变换回时域。rfftfreq()函数中的 d 值控制 FFT 平滑函数的平滑程度。逆 irfft()函数中的参数 n 需要用于时间轴上的奇数个间隔;否则,你的函数会抛出一个错误(对于偶数,没有 n 不会产生错误。
def ts_smooth(df, threshold=2e4):
fourier = rfft(df)
frequencies = rfftfreq(len(df), d=2e-3 / len(df))
fourier[frequencies > threshold] = 0
return irfft(fourier, n=1825)df_ts['Number of Offenses, smoothed'] = ts_smooth(df_ts['Number of Offenses'])with plt.style.context('ggplot'):
fig, ax = plt.subplots(figsize=(18,8))ax.plot(df_ts['Number of Offenses'],linewidth=2)
ax.plot(df_ts['Number of Offenses, smoothed'], linewidth=5)
ax.set_title('FFT Smoothing', fontsize=23);
ax.set_ylabel('Number of Offenses', fontsize=22);
ax.set_xlabel('Year', fontsize=22);
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=2))
plt.gcf().autofmt_xdate()
ax.tick_params(axis='y', labelsize=16)
ax.tick_params(axis='x', labelsize=16)
plt.legend(['Real data','FFT smoothing'], fontsize=15)
plt.show()

图五。作者图片
上图使总体趋势和季节模式更加清晰。这也使得建模比有噪声的原始数据集更容易和更快。
结论
正如我们所见,傅立叶变换是一种有用的技术,可以检测时间序列的季节性或消除噪声信号。然而,在时间序列分析中,FT 并不是一个万能的工具。如果季节性很强,可以首先使用 rfft()和 rfftfreq()函数检测季节性成分,然后建立平滑曲线模型。然而,如果在你的时间序列中有一个意外的事件(突然下降或其他),则不应该使用 FT。
时间序列的傅立叶变换
了解什么是傅立叶变换,以及如何用它来分解时间序列。使用一个关于 CO2 时间序列数据的 Python 示例。

时间序列的傅立叶变换。简·侯伯在 Unsplash 上拍照。
在这篇文章中,你将通过一个最直观的应用时间序列分解来学习什么是傅立叶变换。您还将看到如何使用 NumPy 对一个著名的时间序列数据集执行快速傅立叶变换。
傅立叶变换
傅立叶变换的官方定义指出,它是一种允许你将依赖于空间或时间的函数分解成依赖于频率的函数的方法。当然,这是一个非常技术性的定义,所以我们将使用一个时间序列数据的示例来“分解”这个定义。
傅立叶变换将依赖于空间或时间的函数分解成依赖于频率的函数。
我写这篇文章的目的是,在这篇文章结束时,你将能够理解这句话。
傅立叶变换的其他常见应用是在声音或音乐数据中,但也在信号处理中。基本上,任何处理波形数据的领域都会受益于傅立叶变换。
时间序列:以固定的时间间隔测量变量
虽然傅立叶变换在许多应用中都很有用,但时间序列是最容易上手的。时间序列仅仅是测量一个变量随时间变化的任何数据集。
时序的测量频率表示测量发生的频率。例如,您可以测量日温度、月温度、年温度。
我们一般使用有规律的时间间隔。当然,你也可以不定期的测量温度。然而,我暂时不考虑这一点,因为这不是标准,它使一切变得更加复杂。
时间序列:季节性、趋势和噪声的组合
时间序列的一个非常重要的方面是季节性。许多变量,无论是销售、天气还是其他时间序列,通常都表现出固有的季节性。
让我们考虑几个例子。在月度温度数据中,我们可以预计夏季月份总是较高,冬季月份总是较低。温度也有每日季节性:夜间较冷,白天较热。例如,在销售数据中,我们可以预计圣诞节期间的销售额会逐年增加。
当一个时间序列变量仅依赖于某个季节性时,我们可以将数据呈现为一个重复的模式,它将遵循某种波形。然而,在大多数情况下,T2 不仅仅是季节性的。
使用三角学创建示例波
作为一个例子,下图显示了温度时间序列中的单季节效应。你可以清楚地看到全年的数据波动(夏季较高,冬季较低):
这是重温三角学基础知识的好机会。现在,我将只解释我如何创建波,而不涉及太多的细节。首先,我们基于著名的余弦函数创建一个基线温度。我们让负在夏天有峰值(标准从峰值开始)。我们还将月份乘以 0.5,这样每年就只有一个峰值(而不是两个)。
时间序列的傅立叶变换。创建基线温度数据集。
该图将如下所示:

基线温度数据。
我们仍然需要改进这一点:平均值和振幅完全不像温度数据。从 y 轴上的值可以看出这一点。让我们首先使用以下代码添加一个平均值:
时间序列的傅立叶变换。移动平均值。
这将导致 y 轴上的值向更高的值移动。现在,该图将如下所示:

时间序列的傅立叶变换。平均值较高的温度数据。
现在,作为最后一步,我们要增加振幅。最低值和最高值之间的当前差值不是温度数据的真实表示。您可以使用以下代码来实现这一点:
时间序列的傅立叶变换。增加振幅。
最小值和最大值现在相距更远。该图现在看起来像一年的实际温度数据(摄氏度)(x 轴上的月份):

时间序列的傅立叶变换。最终数据随季节温度变化。
向时间序列添加第二个季节变化
下一步,让我们看看如果我们也创造一个白天/晚上的季节性会发生什么。日/夜模式以 24 小时为基础,可能如下所示:
时间序列的傅立叶变换。创造每日变化。
每小时的数据有 24 个值,白天上升,晚上下降。它看起来如下(查看轴以理解与前面的图的区别):

时间序列的傅立叶变换。昼夜温度变化的每小时数据集。
然后你可以通过对这些模式求和来组合它们。当然,你需要提升月数据,因为所有东西都需要在最小的尺度上:在这个例子中是在小时尺度上。
在气温数据中,各年的月平均值不会完全相同。两种影响会对此产生影响:趋势和噪音。趋势是增加或减少的长期过程。例如,随着全球变暖,我们的温度波动将逐年升高。
另一方面,噪声代表随机效应,使得温度每年并不完全相同。它代表了我们无法通过任何模型解释的东西。
在这一点上,我想你对我们如何将季节性的不同影响结合到一个单一的时间序列变量中有了一个感觉。然而,现实是反过来的 : 我们获得一个作为混合过程的时间序列变量,我们想要分解它以识别不同的季节性、趋势和噪声。
我们可以使用傅立叶变换来检测时间序列中的季节性。
时间序列数据的傅里叶变换
现在让我们通过使用傅立叶变换来分解时间序列,从而得到真实的东西。如前所述,傅立叶变换允许你把一个依赖于时间的函数分解成一个依赖于频率的函数。
我们的时间序列数据是依赖于时间的函数:我们有每个时间点的温度值。
如果我们假设时间序列数据中只有季节性,我们可以用不同的方式描述函数。我们可以几乎完美地描述我们的数据,说它是“一个年度波动”(夏天上升,冬天下降)。如果我们这样做,我们实际上将数据集描述为一个频率:毕竟, yearly 只是一个频率。
傅立叶变换是从单个时间序列变量中提取不同季节性模式的强大工具。
傅立叶变换可以让你做到这一点:将时间序列描述为频率,而不是时间的函数。最重要的是,当你在一个变量中混合了多个频率(多个季节性)时,它甚至可以被应用。
傅立叶变换是从单个时间序列变量中提取不同季节性模式的强大工具。例如,对于每小时的温度数据集,傅立叶变换可以检测到昼夜变化和夏季/冬季变化的存在,它会告诉您这两个季节性(频率)存在于您的数据中。
离散傅立叶变换
让我们看看傅立叶变换是如何工作的。对于时间序列数据,我们需要的傅立叶变换版本是离散傅立叶变换。之所以称之为离散是因为输入数据是以离散间隔测量的:我们的时间序列数据不是连续函数。
让我们首先了解离散傅里叶变换(DFT)的工作原理:
- 输入是原始变量的数字序列(每个时间步长一个值)
- 输出是每个频率的一个振幅(或信号强度)值。这些由傅立叶系数表示
这个新的级数通过使用傅立叶公式简单地计算,公式如下:

时间序列的傅立叶变换。公式。
计算之后,您获得了关于变量中出现的频率的数据。结果系列中的每个值都是特定频率的强度。如果这个频率的振幅很高,那么这个季节性在你的时间序列(或者其他波)中很重要。
简而言之,你从数值开始,通过离散傅里叶变换的数学函数,你已经获得了每个频率的强度。
快速傅立叶变换
离散傅立叶变换的快速版本称为快速傅立叶变换。它给出了与离散傅里叶相同的结果,但从算法的角度来看,它已经过优化。可以使用 Cooley-Tukey FFT 算法计算快速傅立叶变换。
快速傅立叶变换是许多领域的标准之一,作为傅立叶变换的切入点非常棒。
在 Python 中对时间序列应用快速傅立叶变换
最后,让我们将所有这些放在一起,处理一个示例数据集。我们将使用来自 statsmodels 的著名 CO2 数据集。这是很好的工作,因为它有一个非常明显的年度季节性。
我们将使用 NumPy 代码完成快速傅立叶变换,并了解如何执行和解释它。最后,我们将把结果与一个专门用于分解时间序列的函数进行比较,这样我们就可以看到我们是否做对了。
您可以通过以下方式获得 CO2 数据:
时间序列的傅立叶变换。获取二氧化碳数据。
数据如下所示:

时间序列的傅立叶变换。二氧化碳数据。
让我们通过创建一个图来看看数据。您可以使用下面的代码来做到这一点:
时间序列的傅立叶变换。绘制二氧化碳数据。
您将获得下图,该图显示了一段时间内非常明显的上升趋势和年度季节性:

时间序列的傅立叶变换。二氧化碳数据图。
现在让我们应用快速傅立叶变换,并绘制结果。正如所料,我们现在获得了每个频率的强度图:
时间序列的傅立叶变换。应用快速傅立叶变换并绘制结果。
情节看起来如下:

时间序列的傅立叶变换。结果是每个频率的强度图。
为了更好地理解我们所看到的,让我们用时间段来代替频率。您可以使用以下代码将频率转换为时间段:
时间序列的傅立叶变换。将频率转换为周期。
您现在将获得一个以周为周期的 x 轴:

时间序列的傅立叶变换。改进的 x 轴。
我们能做的最后一件事就是让剧情变得更流畅。我们可以通过将每个周期的信号强度重新组合成每周的总和来做到这一点。这可以通过以下方式完成:
时间序列的傅立叶变换。平滑图表。
生成的图形如下所示:

时间序列的傅立叶变换。最终剧情。
在这个最后的情节中,你可以清楚地看到一个巨大的峰值:这个我们忽略了,因为它不相关。然而,最后的峰值是第 52 周的峰值:这个峰值向我们表明,52 周(每年)的季节性非常明显。
这就是你如何对时间序列使用傅立叶变换。理解这一理论对于信号处理和其他用例非常重要。
作为最后一步,我想向您展示一种更好的方法来为您可能有的任何日常使用进行时间序列分解。以下代码显示了如何使用 statsmodels 进行分解:
时间序列的傅立叶变换。Python 中分解时间序列的快速方法。
这样做的好处是,您可以在一次执行中获得快速而漂亮的结果,如下所示:

时间序列的傅立叶变换。Python 中的快速时间序列分解图。
结论
在本文中,您了解了傅立叶变换的工作原理,以及如何用它来检测时间序列中的季节性。您已经看到了一个关于 CO2 数据的应用程序,其中我们使用傅立叶变换来检测每年的季节性。傅立叶变换有许多用例,例如在声音分析中,但我将在以后的文章中继续讨论。
现在,感谢你的阅读。我希望你已经学到了一些东西。请继续关注更多数学、统计和数据科学内容!
傅立叶变换:直观的可视化
时间序列数据处理
应用于简单时间序列数据的离散傅立叶变换的直观可视化。

作者图片
这篇文章可视化的分解时间序列信号到其谐波使用傅立叶变换。以直观的方式解释该公式,以帮助理解其含义。
为什么是傅立叶变换?
傅立叶变换是一种极其强大的工具,广泛应用于各种领域。它的强大之处在于它能够将时间序列信号分解成正弦波形。例如,当对信号去噪并试图找到波形的谐波时,这可能是有用的。
示例应用
比方说,有人想从喷气发动机的振动信号中提取信息。这种信号非常嘈杂,因为喷气发动机可能包含数千个运动部件,每个部件都会产生振动信号。可以想象,由于发动机在旋转,每个分量的时间序列信号将大致为正弦曲线。如果您可以将时间序列解构为一组正弦信号,也许您可以识别特定组件的振动信号,然后识别这些部件是否按预期运行。
公式

其中 g(t)代表时间序列信号,f 是频率,G 是每个频率幅度的函数
当第一次看傅立叶变换的方程时,它可能看起来令人望而生畏。在本文中,我将给出一个小例子,帮助您以直观的方式理解这个公式在做什么。
我们的任务
为了理解傅立叶变换,让我们设定一个任务,如果你能完成它,你就会理解傅立叶变换!

作者图片
以上是三个时间序列信号。蓝色和红色信号是正弦信号(周期分别为 4π和 2π)。绿色是两者之和。假设我们只有绿色信号。我们可以只使用绿色信号提取蓝色和红色信号吗?
极坐标包装
回到公式,e ^ 2πi 项你可能很熟悉。这是复平面中的一个位置,具体地说是 e ^ 2πi = 1,并且位于实轴平面上。当取 e ^ 2πit 时,可以想象在复平面中描绘一个圆,圆的每个位置由时间 t 表示。当乘以 g(t)时,可以简单地将时间序列信号映射到复平面中的圆。

作者图片
正如你所看到的,这些是和之前一样的时间序列信号,围绕着 argand 图。公式中唯一缺少的是指数中的频率项和积分。
改变频率
到目前为止,我们已经看到傅立叶变换的一部分仅仅是将时间序列信号包裹在极坐标中。但是,这如何帮助我们识别哪些正弦波用于构成绿色信号呢?
指数中的频率项可以被认为是我们在极平面中包裹时间序列信号的频率。频率越高,时间序列信号绕极坐标的圈数越多。
记住蓝色曲线的周期是 2π,红色是 4π,绿色是两者之和。让我们看看,当我们改变时间序列信号围绕极平面的周期时,会发生什么。

作者图片
正如你所看到的,信号似乎有点混乱,直到周期达到 2π,然后突然混乱变成有序。
这很漂亮,但我们仍然不知道什么正弦方式构成绿色信号。
重心和固有频率
傅立叶变换公式中最后要解释的是积分。
在上图中,我将每条曲线的重心显示为一个灰点。这可以解释为傅立叶变换公式中的积分项。你可以看到,重心总是在零附近,然后当接近一个固有频率时,重心突然远离零。对于信号 1 和 3,2π的周期对应于它们的固有频率,并且重心远离原点。信号 2 的重心停留在零,因为它的周期是 4π,而不是 2π。
因为信号 3 的重心远离原点,所以我们可以确定 2π的周期对应于信号 3 的固有频率。
就是这样!傅立叶变换公式给你的,只是重心到我们看到的曲线原点的距离。当这个距离达到峰值时,我们知道我们正在接近一个自然频率。
回到公式
因此,概括地说,我们已经看到,傅立叶变换公式中的 G(f)项表示包裹在复平面周围的时间序列信号的重心原点的距离。当离原点的距离很大时,这个频率就是时间序列的固有频率。
让我们画出信号 3 从质心到原点的距离。

作者图片
在周期 2π和 4π处,重心到原点的距离非常高,这意味着可以将信号 3 近似为周期为 2π和 4π的两个正弦波之和。任务完成!
结论
这是傅立叶变换的一点介绍,以及如何用视觉的方式来解释它们。
支持我👏
希望这对你有所帮助,如果你喜欢,你可以 关注我!
您也可以成为 中级会员 使用我的推荐链接,访问我的所有文章以及更多:https://diegounzuetaruedas.medium.com/membership
你可能喜欢的其他文章
傅立叶变换:动画可视化
时间序列数据处理
一个简单的傅立叶变换的动画例子

作者图片
介绍
傅立叶变换广泛应用于工程领域。它们有广泛的应用,从去噪和滤波到电子电路设计。在本文中,我展示了傅立叶变换的直观可视化,其中我通过将时间序列信号包装在极坐标中来实现傅立叶变换。最后,我表明傅立叶变换可以被认为是复平面的原点和时间序列信号的质心之间的距离。
在之前的一篇文章中,我用直观的方式解释了傅立叶变换。在这篇文章中,我将进一步介绍可视化,并详细说明我是如何制作这些可视化的。
为什么是傅立叶变换?
傅立叶变换可以帮助我们将时间序列数据分解成一系列正弦波。组成时间序列信号的核心频率是谐波。将信号分解成其固有频率在工程中有许多用途,例如预测工程系统中组件的未来故障。
合成时间序列数据

作者图片
这里有三个时间序列波,蓝色的频率为 10 赫兹,橙色的频率为 20 赫兹,绿色的是两个波的组合。你可以通过计算 x 轴上一个单位的周期数来判断这种情况。
我们的目标是分解绿色信号,找到它的自然频率(10 赫兹和 20 赫兹)。
在极坐标中换行

以上是傅里叶变换方程。当用正弦波逼近输入函数 g(t)时,得到的函数 G(f)给出了每个频率有多重要的函数。g(t)的自然频率将导致 g 的更大幅度。
在我以前的文章中,我解释了傅立叶变换的一部分实际上只是将时间序列信号包裹在 argand 图周围(来自方程中的指数项)。这是上面围绕原点从 0 辐射源到π辐射源的三个时间序列信号。

作者图片
最后,傅立叶变换中的积分可以被认为是围绕复平面的时间序列信号的原点和质心之间的距离。通过改变时间序列信号环绕复平面的速度,我们可以看到质心何时远离原点,从而识别自然频率。
动画片
您将只能在笔记本电脑上看到这些动画,而不能在移动应用程序上看到。我建议你换成笔记本电脑。

作者 GIF
这是复平面中合成时间序列数据的动画。我们包裹信号的频率接近蓝色曲线的自然频率。
在上面的 GIF 中,当频率接近 10 Hz 时,关注每个信号的质心。如您所见,蓝色和绿色曲线的质心突然远离原点,而橙色曲线的质心保持在中间。傅立叶变换就是这样告诉我们,10 赫兹是蓝色和绿色曲线的自然频率!

作者 GIF
这是一个从 0 到 22 赫兹的动画。记住蓝色曲线的自然频率为 10 赫兹,橙色曲线的自然频率为 20 赫兹,绿色曲线的自然频率为两者之和。
让我们看看静止帧,这样我们就不会太晕了:


作者图片
在 10 赫兹时,蓝色曲线的质心远离原点,在 20 赫兹时,它停留在中心。橙色曲线正好相反。最后,在两种情况下,绿色曲线的质心都远离原点,我们现在知道这是绿色曲线的两个固有频率。
画出离原点的距离
对于每条曲线,我们现在可以绘制质心到原点的距离,知道幅度的增加将表明分解为正弦波时频率影响的增加。

作者 GiF
蓝色曲线的距离尖峰为 10 Hz,橙色曲线的距离尖峰为 20 Hz,绿色曲线的距离尖峰为 10Hz 和 20Hz。因此,为了逼近绿色曲线,我们可以取频率为 10 Hz 和 20 Hz 的两个正弦波之和。
密码
我将为感兴趣的人快速浏览一些 python 代码。
为了创建时间序列数据,我创建了正弦波,从 0 到 1 绘制它们,这种方式适应了信号的频率。
为了将信号包裹起来,我取一系列从 0 到π辐射的角度,并将信号幅度作为复平面中每个矢量的幅度。
要获得质心,我只需将时间序列信号的角度和幅度转换为复数,取其平均值,将得到的复数绘制回 argand 图。
为了制作动画,我使用了一个名为赛璐珞的 python 库,它允许我在循环中拍摄情节的快照,然后将这些快照保存为 GIF。
结论
在这篇文章中,通过简单的动画形象化傅立叶变换。我展示了时间序列信号的自然频率如何与 argand 图中的信号相关。我表明,通过观察曲线的质心和原点之间的距离,可以找到时间序列信号的自然频率。
如果你想更好地理解这与傅立叶变换方程的关系,我推荐你去看看我的另一篇关于傅立叶变换的文章。
支持我
如果你喜欢它,你可以跟我来 !
你也可以通过我的推荐链接成为中级会员,访问我所有的文章以及更多:【https://diegounzuetaruedas.medium.com/membership】T2
成功持续培训战略的框架
什么时候应该重新培训模型?应该使用哪些数据?应该重新培训什么?数据驱动的方法

Monika Pejkovska 在 Unsplash 上拍摄的照片
这篇文章是我和我的同事李然·纳胡姆合著的
ML 模型建立在这样的假设上,即生产中使用的数据将与过去观察到的数据相似,即我们用来训练模型的数据。虽然对于某些特定的用例来说这可能是正确的,但是大多数模型都工作在动态数据环境中,在这种环境中,数据不断变化,并且很可能发生“概念漂移”,从而对模型的准确性和可靠性产生负面影响。
为了解决这个问题,需要定期对 ML 模型进行再培训。或者如谷歌的“ MLOps:机器学习中的连续交付和自动化管道”:::为了应对这些挑战并保持你的模型在生产中的准确性,你需要做以下事情:积极监控你的模型在生产中的质量[……]并经常重新培训你的生产模型。“这个概念叫做‘持续培训’(CT),是 MLOps 实践的一部分。持续训练旨在自动和持续地重新训练模型,以适应数据中可能发生的变化。
进行持续再培训有不同的方法,每种方法都有自己的优点、缺点和成本。然而,与赤脚走路的鞋匠类似,我们——数据科学家——似乎过度进行再培训,有时是手动的,并经常将其作为“默认”解决方案** ,而没有足够的生产驱动的洞察力。**
每个 ML 用例都有自己的动态数据环境,可能会导致概念漂移:从实时交易,到对手改变数据分布的欺诈检测,或具有大量新电影和新趋势的推荐引擎。然而,不管用例如何,在设计持续培训策略时,需要解决三个主要问题:
****1 —什么时候应该重新培训模型?由于目标是保持运行高度相关的模型,并且在任何时间点都以最佳状态运行,那么应该多长时间对模型进行一次再培训
****2 —应该使用哪些数据?选择适当数据集的常见假设是,数据的相关性与其最近的时间相关,这引发了一系列问题:我们应该只使用新数据还是添加旧数据集?什么是新旧数据的良好平衡?多新的数据被认为是新数据,或者新旧数据的分界是什么时候?
****3 —应该重新培训什么?我们能否替换数据,用相同的超级参数重新训练相同的模型?或者我们应该采取一种更具侵入性的方法,运行一个完整的管道来模拟我们的研究过程?
上述三个问题中的每一个都可以单独回答,并有助于确定每种情况下的最佳策略。然而,在回答这些问题的同时,还有一系列需要考虑的因素,我们在此进行了研究。对于每个问题,我们描述了不同的方法,对应于 ML 过程的自动化和成熟度的不同水平。
什么时候重新培训?
三种最常见的策略是:定期再培训、基于绩效或基于数据变化。
定期再培训
定期再训练计划是最简单直接的方法。通常基于时间:模型每 3 个月重新训练一次,但也可以基于数量,即每 10 万个新标签。
定期再培训的优势同样简单明了:这是一种非常直观和易于管理的方法,因为很容易知道下一次再培训迭代将在何时发生,并且很容易实现。****

作者图片
然而,这种方法经常暴露出不合适或者效率低下。你多久对模特进行一次再培训?每天?每周吗?每三个月?一年一次?虽然人们希望频繁地重新训练以保持我们的模型更新,但是在没有实际原因(即没有概念漂移)的情况下过于频繁地重新训练模型是昂贵的。此外,即使再培训是自动化的,它也需要重要的资源,包括计算资源和数据科学团队的资源,他们需要在部署后监督再培训流程和生产中的新模型行为。然而,大间隔的再训练可能会错过连续再训练的要点,并且无法适应数据的变化,更不用说对有噪声的数据进行再训练的风险了。
在一天结束时,如果频率与你的领域的动态相一致,定期的再培训计划是有意义的。否则,选择一个随机的时间/里程碑可能会使您面临风险,并且留给您的模型会比先前版本的相关性更低。
基于性能的触发器
这几乎是一个常识性的说法,基于一句古老的工程格言:“如果它没坏,就不要修理它。”确定何时重新训练的第二个最常见的方法是利用基于性能的触发器,并在检测到性能下降时重新训练模型。

作者图片
这种方法比第一种方法更具经验性,它假设您对模型在生产中的性能有一个连续的视图。
当仅仅依靠表现时,主要的限制是你获得你的基本事实所花费的时间——如果你获得它的话。在用户转化预测案例中,可能需要 30 或 60 天才能获得基本事实,在交易欺诈检测或 LTV 等案例中甚至需要 6 个月或更长时间。如果你需要等很长时间才能得到完整的反馈,那就意味着在业务已经受到影响之后,你再培训这个模型就太晚了。
另一个需要回答的重要问题是:什么被认为是“性能下降”?您可能依赖于阈值的灵敏度和校准的准确性,这可能会导致您过于频繁或不够频繁地重新训练。
总的来说,使用基于性能的触发器有利于快速反馈和大量数据的用例,如实时竞价,在这种情况下,您可以在尽可能接近预测时间的时间间隔内,以高置信度(大量)测量模型的性能。
由数据变化驱动
这种方法是最动态的,自然会从领域的动态性中触发再训练。通过测量输入数据的变化,即模型使用的要素分布的变化,您可以检测数据漂移,这表明您的模型可能已经过时,需要保留新数据。
对于没有快速反馈或无法实时评估模型在生产中的性能的情况,这是基于性能的方法的替代方法。此外,即使在快速反馈的情况下,结合使用这种方法也是一种很好的做法,因为这可能表明性能不佳,甚至没有降级。了解数据变化以开始再培训过程是非常有价值的,尤其是在动态环境中。

截图自 superwise.ai
上面的The 图由监控服务生成,显示了一个营销用例的数据漂移指标(上图)和性能 KPI(下图)。数据漂移图是一个时间轴,其中 Y 轴显示每天(即这一天的数据)相对于训练集的漂移水平。在这个营销用例中,新的营销活动被频繁引入,业务扩展到新的国家。显然,生产中的数据流正在漂移,变得越来越不像模型训练所依据的数据。通过更全面地了解生产中的模型,可以在业务部门观察到性能下降之前触发再培训迭代。
那么什么时候再培训呢?这取决于关键因素,例如:反馈的可用性、数据量以及模型性能的可见性。总的来说,在选择合适的时间进行再培训的问题上,没有一个放之四海而皆准的标准。相反,根据您的资源,目标应该是尽可能以生产为导向。
应该使用哪些数据?
虽然我们已经看到时间就是一切(例如:我什么时候重新培训我的模型?),现在我们来看看所有 MLOps 的神经:数据。再培训时,我如何选择要使用的正确数据?
固定窗口大小
最简单的方法是使用固定的窗口大小作为训练集。例如,使用最近 X 个月的数据。显然,该方法的优点在于其简单性,因为它非常直接。
缺点来自选择正确窗口的挑战:如果窗口太宽,它可能会错过新的趋势,如果窗口太窄,它会过度拟合和嘈杂。窗口大小的选择还应该考虑再训练的频率:如果只使用上个月的数据作为训练集,那么每 3 个月再训练一次是没有意义的。
此外,选择的数据可能与生产中正在传输的数据有很大不同,因为它可能紧接在变更点之后发生(在快速/突然变更的情况下),或者可能包含不规则事件(例如,节假日或选举日等特殊日子)、数据问题等。
总的来说,与任何其他“静态”方法一样,修复窗口方法是一种简单的启发式方法,在某些情况下可能效果很好,但在变化率多种多样且经常发生不规则事件(如假期或技术问题)的情况下,将无法捕捉到您环境的超动态性。
动态窗口大小
动态窗口大小方法试图通过以更数据驱动的方式确定应该包括多少历史数据,以及通过将窗口大小视为可以作为再训练的一部分进行优化的另一个超参数,来解决预定义窗口大小的一些限制。
这种方法最适合有快速反馈的情况(即:实时投标或食品交付 eta)。最相关的数据可以作为测试集,可以在上面优化窗口大小,就像模型的另一个超参数一样。在下面的例子中,最高的性能是通过最后 3 周获得的,这是这个迭代应该选择的。对于将来的窗口,根据与测试集的比较,可以选择不同的窗口。

作者图片
动态窗口大小方法的优势在于,它更多地由数据驱动,基于模型性能(这是真正的底线),因此它对于高度时态的环境更健壮。
缺点是它需要一个更复杂的训练管道(见下一个问题“训练什么”)来测试不同的窗口大小并选择最佳的一个,并且它需要更多的计算。此外,像固定的窗口大小一样,它假设最近的数据是最相关的,但这并不总是正确的。
动态数据选择
选择数据来训练模型的第三种方法寻求实现任何再训练策略的基本目标,并且是任何 ML 模型的基本假设:使用与生产数据相似的训练数据。或者换句话说,模型应该根据与现实生活中使用的数据尽可能相似的数据进行重新训练,以发布预测。这种方法很复杂,需要生产数据的高度可见性。
要做到这一点,您需要对生产中的数据演变进行彻底的分析,以了解它是否以及如何随时间而变化。一种方法是计算每两天之间输入数据的偏差,即某一天的数据与另一天的数据有多大差异,并生成一张显示数据随时间变化模式的热图,如下图所示。下面的热图是一段时间内漂移评估的可视化,其中轴(列和行)是日期,每个点(矩阵中的单元格)是两天之间的漂移水平,漂移越高,单元格越红。

作者图片
上图中,您可以看到这种分析的结果,它有助于找出与当前正在传输的数据尽可能相似的数据。从这个观点中可以很容易地得出不同类型的见解:
1-12 月与其他数据(之前和之后)非常不同。这种洞察力使我们能够避免将整个期间视为一个整体,并排除那些您想要重新培训的日子,因为本月的数据并不代表您在生产中观察到的正常数据。
2-数据的季节性可以可视化——这可以引发对工作日和周末使用不同模型的必要性的讨论。
这里还有一件非常重要的事情:你实际上可以有一张图片来证明最近的数据不一定是最相关的。
in·肖特:选择正确的数据来重新训练模型需要对生产中的数据行为有一个透彻的了解。虽然使用固定或动态的窗口大小可能有助于您“勾选方框”,但它通常仍然是一种猜测,可能成本更高,效率更低。
应该重新培训什么?
既然我们已经分析了什么时候再培训,应该使用什么数据,让我们来解决第三个问题:应该再培训什么?人们可以选择仅基于新数据重新训练(改装)模型实例,以包括一些或所有数据准备步骤,或者采取更具侵入性的方法并运行模拟研究过程的完整管道。
再培训的基本假设是,在研究阶段培训的模型将由于概念漂移而变得过时,因此需要再培训。然而,在大多数情况下,模型实例只是在研究阶段构建的更广泛的管道的最后一个阶段,并且包括数据准备步骤。问题是:漂移及其影响有多严重?或者在再培训的背景下,模型管道的哪些部分应该受到挑战?
在研究阶段,您在模型管道步骤中试验和评估许多元素,以优化您的模型。这些要素可以分为两个高级部分,数据准备和模型训练。负责准备数据的数据准备部分(咄!)供模型使用,包括特征工程、缩放、插补、降维等方法。模型训练部分负责选择最优模型及其超参数。在流程的最后,您将获得一系列连续的步骤,这些步骤获取数据,准备供模型使用,并使用模型预测目标结果。
仅用新的相关数据重新训练模型,即流水线中的最后一步,是最简单和最天真的方法,并且可能足以避免性能下降。然而,在某些情况下,这种仅提供模型的方法可能是不够的,应该对再培训的范围采取更全面的方法。扩大再培训的范围可以从两个方面进行:
1 — 再培训什么?应该使用新数据重新培训管道的哪些部分?
2 — 再培训的级别:您是否只是用新数据来重新调整模型(或其他步骤)?你做超参数优化吗?还是挑战模型本身的选择并测试其他模型类型?
另一种看待这个问题的方式是,在再培训过程中,你基本上试图自动化并避免模型优化研究的手动工作,如果没有自动化的再培训过程,这些工作将由数据科学家完成。因此,你需要决定你想在多大程度上尝试和模仿人工研究过程,如下图所示。

**MLOps:机器学习中的连续交付和自动化管道中描述的模型研究阶段
Note 认为,自动化流程的第一步更加复杂,随着围绕这些实验建立的自动化程度越来越高,流程变得更加健壮和灵活,以适应变化,但这也增加了复杂性,因为需要考虑更多的最终案例和检查
示例和结论
让我们以一个简单的模型管道为例,它是我们的 awesome 数据科学团队为一些分类任务进行的手动研究的结果:

作者图片
您可以采取简单的方法,只需重新训练模型本身,让它学习新的树,或者您可以包括一些(或所有)数据准备步骤(例如,重新学习估算器中的平均值或缩放器中的最小/最大值)。但是除了选择要重新训练的步骤之外,你还需要决定要训练到什么水平。例如,即使您选择只对模型进行重新培训,也可以在多个级别进行。您可以只重新训练模型本身,并让它学习一个新的树,即 model.fit (new_X,new_y),或者您可以搜索并优化模型 hyper 参数(最大深度、最小叶大小、最大叶节点等)。)或者甚至质疑模型本身的选择并测试其他模型类型(例如逻辑回归和。随机森林)。数据准备步骤也可以(也应该)重新训练,以测试不同的定标器或不同的插补方法,甚至测试不同的特征选择。
当选择采用更全面的方法并执行超参数优化/模型搜索时,您还可以使用 Auto-ML 框架,这些框架旨在自动执行构建和优化模型管道的过程,包括数据准备、模型搜索和超参数优化。而且不一定要涉及复杂的元学习。这很简单:用户选择一系列模型和参数。有很多工具可用: AutoKeras , Auto SciKitLearn 。然而,尽管 AutoML 很有吸引力,但它并不能免除用户在模型的整个生命周期中拥有一个健壮的过程来跟踪、测量和监控模型,尤其是在生产中部署它们之前和之后。
最终,“拨动开关”和自动化您的过程必须伴随着健壮的过程,以确保您保持对您的数据和模型的控制。
为了实现高效的持续培训,你应该能够以生产驱动的洞察力为主导。对于任何一个用例来说,创建一个健壮的 ML 基础设施在很大程度上依赖于实现对模型健康和生产中数据健康的可见性和控制的能力。这是成为数据驱动的数据科学家所必需的;)
机器学习算法原型框架(Python)
利用 Python 中的 scipy 开发损失函数的经典机器学习算法原型的通用框架
简介
阅读科学文章和尝试新的有前途的算法是许多数据科学家的重点。不幸的是,这些算法位于小的存储库中,并且通常包含几个错误,因此它们很难使用,并且您将花费相当多的时间来调试(或者解决依赖冲突)。幸运的是,这些算法通常可以简化并使用损失函数来表示,在本文中,我将使用主成分分析(PCA)和支持向量机(SVM)作为主要示例,但它适用于更多技术。
这种方法有多种优势:
- 了解机器学习算法的底层行为。
- 避免由于可用实现中的某些默认设置而导致的错误。
- 易于针对数据的某些特性进行定制(以防违反常见假设)。
- 不要浪费时间为你的问题寻找一个好的算法实现。
- 通过调整损失函数(如 Huber 或 Hampel),容易为异常值建立鲁棒性。
- 大多数算法假设误差项呈正态分布,然而,这并不总是有效的。通过调整损失函数,这些误差项可以归一化。
可能的缺点:
- 性能/速度
- 数值不稳定性
主成分分析的损失函数表示
主成分分析(PCA)可以被表示为寻找最大化方差的投影,第一主成分可以被获得为:

其中 w 是第一主成分(p×1)的加载向量,p 是数据的维数,x_k 是样本 k(p×1),总共有 N 个样本。更多信息可以在“支持向量机:方法和应用”(J. Suykens)中找到。
在当前形式中,如果 w 变得无限大,则该损失函数最大,因此范数通常被限制为 1(归一化):

这可以翻译成 Python 代码,如下所示:
这导致了一个约束优化问题,我们可以使用 scipy.optimize 轻松地解决它,它支持许多不同的求解器,具体取决于您的需求,并且已经根据您的输入选择了一个合适的求解器。
将生成一些随机高斯数据(维数 p=2 ),并且将使用来自 sklearn.decomposition 的 PCA 实现对其进行基准测试。
PC1 使用 sk learn:[-0.42388046 -0.90571814]
PC1 使用损失函数:[-0.42388046-0.90571814]
第一个主成分的加载对于两个实现是完全相同的,这表明该框架仅使用几行代码就可以强大地表示算法。
最后,我们将在 i7–8750h CPU(2.2 GHz,12 个内核)上对两种实现的速度性能进行基准测试,以获得第一个主成分。scikit-learn 实现使用 LAPACK 库(Fortran)解决了奇异值分解。我们将对 X 数据集中的多个样本进行比较。条形图中显示的时间包括创建实例和定义方法。

在这种情况下,损失函数的实现也明显快于用于计算第一主分量的奇异值分解。scikit-learn 实现赶上了大样本量,但这只是因为它开始对数据进行随机下采样,因此损失函数实现更快、更准确,而在该基准测试中只有几行代码。
SVM 的损失函数表示
支持向量机可以在原始空间和对偶空间中求解(如果使用的核可以在原始空间中表示)。为了简单起见,这里实现的 SVM 将在原始空间中求解。有关原始和对偶空间的更多背景信息,请参见“支持向量机:方法和应用”(J. Suykens)。
原始空间中线性 SVM 的损失函数被定义为:

有以下限制:

其中 w 是我们想要获得的权重向量(p x 1),gamma 是一个超参数,它指定了二阶正则化和误分类数之间的理想折衷(如果 gamma 很大,将会有更多的过拟合)。x_k 是样本 k(p×1),总共有 N 个样本。ζ_ k 是样本 k 的松弛变量,样本 k 被错误分类得越多(离判定边界越远),该变量就越大。y_k 是样本 k 的标签,可以是正(+1),也可以是负(-1)。b 是决策边界的偏移量。
将其转换为 Python 代码会产生以下类(铰链损耗的平方):
现在将基于损失函数的这个类与 sklearn 实现进行比较(就像我们对 PCA 所做的那样)。这会产生以下 python 代码:
重量 sklearn:[0.349575-0.17398369]
重量损失:[ 0.34916208 -0.17402776]
权重之间有微小的差异,但是如果我们画出决策边界,我们可以看到几乎是相同的。

现在,性能将进行基准测试,类似于我们对 PCA 所做的,两种实现都允许运行,直到收敛(迭代次数没有截止)。这导致:

对于 1000 个样本,定制实现大约慢 10 倍,对于 50000 个样本,这降低到大约慢 3 倍。总的来说,这对于一个两行长的原型来说是不错的。请注意,约束是以非线性方式定义的,而它们实际上可以写成线性约束。改进这一点也将改善定制应用程序的计时。
结论
通过编写一个优化损失函数的小类来原型化机器学习算法是快速、准确和容易的。这样做将增加你对问题的了解,从而允许你改进算法。如果原型满足您的需求,但是数值稳定性或速度对于您的应用程序来说不够,那么建议您在论文中搜索快速实现,或者查看一些 git 库。
参考文献
JAK·苏肯斯,T·范·盖斯特尔,J·德·布拉班特,B·德·穆尔,J·范德瓦勒。(2002).“最小二乘支持向量机:方法和应用”。世界科学
n . Halko、p . g . Martins son 和 j . a . Tropp(2011 年)。《寻找具有随机性的结构:构造近似矩阵分解的概率算法》。暹罗评论,53(2),217–288。
Martinsson,P. G .,Rokhlin,v .和 Tygert,M. (2011 年)。“矩阵分解的随机算法”。应用和计算谐波分析,30(1),47–68。
构建机器学习解决方案
行业笔记
如何架构一个机器学习解决方案来实现一个产品目标?
现代产品的目标,无论在哪个领域,都在很大程度上依赖于由计算机解决的算法。典型的方法采用基于启发式的解决方案,即如何完成任务的逐步指令。通常这种方法不足以解决现实世界的情况。在存在代表这些情况的数据的情况下,机器学习(ML)是一种非常好的方法,它通过从数据中学习来找到概率解决方案。
图 1:使用机器学习识别小狗。如何区分小狗到松饼的图像,写一个循序渐进的指南是相当困难的。使用卷积神经网络可以更精确地建立模型。由杰瑞米·霍华德发布推文。
人们很容易认为任何产品目标都可以用 ML 来表达。然而,由于其对模式识别的严重依赖,ML 具有不确定性,因此,有必要确定产品目标的哪一部分应该成为基于 ML 的框架的候选者。例如,在财务问题上,申报多少税款并不适合 ML,因为做错了可能会被认为是重罪。有复杂的,但设定的指导方针,以计算出税额。另一方面,一个人来年在垃圾食品或衣服上的花费可能是 ML 的理想候选。没有固定的规则,可以根据口味、可用性、天气、全球趋势等变化很大。在这篇文章中,我将阐明这个问题。特别是,我将分享找出 ML 可解决的任务的方法,数据需求,以及不同任务类型的 ML 方法。
当面对只有少量数据需要处理的简单场景时,人类专家通常非常擅长提供明智的决策。在这种情况下,ML 解决方案的表现可能会差得多。例如,找到典型感染的治疗方法,确定餐馆的每周菜单等。另一方面,ML 解决方案可能会在面对大量数据的各种场景时表现得更好,例如推荐不同类型的电影、不同产品的价格建议等。虽然这些因素听起来很适合启动一个 ML 项目,但是这样一个简单的框架还不足以决定项目的成功。我们描述了可以简化估算的三个步骤。
第一步:关注问题
你应该从一个需要解决的产品目标开始。一旦解决了这个问题,你应该对实现目标的方法持开放态度。它不一定是 ML。避免追随让你兴奋的下一个最好的事情,尽量做到客观。有时,这可以通过从以前的经验中提取的简单启发来完成。有时需要设计一种基于一组复杂的、相互关联的信号的算法。有时简单的描述性统计可能会奏效。有时候以上都不行。解决方案需要从数据中学习。例如,电影推荐可以像最近的大片一样简单,可以来自更复杂的粉丝群驱动的类型分析,可以基于地理区域中其他人正在观看的内容,甚至可以基于映射为复杂电影数据的观看习惯。
一旦你确定简单的分析不能解决问题,就把产品目标框定为一个 ML 问题,并反复评估这个框架,直到你确定它足够简单。例如,如果问题是推荐电影,那么框架可以依赖于电影元数据和人们已经观看的内容之间的某种关联。虽然提出极其复杂的元数据映射可能很诱人,但必须有一个足够简单的版本,能够轻松涵盖常见情况。
框架应该在每次迭代中从宽到窄。你可以从识别它是有监督的,学习发生在已知标签上,半监督的,学习发生在弱标签上,还是无监督的,学习发生在没有任何标签的情况下开始。用不同的方法来描述同一个问题是可能的。例如,识别信用违约的情况可以基于先前违约的已知情况或异常值来完成。如果问题被当作监督学习来处理,它可以进一步被建模为回归、分类或其他众所周知的监督学习子类别。例如,信用违约问题可以被研究为研究违约金额或违约与否的二元情况。

图 2:将建模产品目标缩小到 ML 问题。作者图。
如图 2 所示,缩小到合适的建模方法应该主要依赖于手头的数据可以达到多少精度。例如,如果标签丢失,那么进行监督学习就没有意义,如果关于违约金额的数据很少,那么将其作为回归问题进行研究就不切实际。在许多现实世界的情况下,建模可能是复杂的,可能需要将目标划分为子任务,每个子任务可以如上所述进一步建模。
步骤 2:理解数据需求
数据是 ML 解决方案的血液。相关数据的缺乏将决定 ML 解决方案的成败。更重要的是,数据需要干净。如果数据不干净,就需要考虑,清理是否可行。如果答案是肯定的,那么您可以继续,但是要注意的是,大量的工作将用于清理数据。如果答案是否定的,您可能需要重新考虑建模方法。
比如,想象一下理解一套产品是否被客户喜欢/不喜欢的问题。如果大部分反馈文本都是垃圾邮件,你可能不得不放弃使用反馈文本来建立情感模型的想法。如果情况不是这样,但是文本中充满了混合语言,提取喜欢/不喜欢的有意义的表示可能太困难了。在这种情况下,必须努力清理/转换数据或收集更多有用的数据。另一方面,如果反馈包括数字/顺序/分类尺度上的评级,建模工作和随后的解决方法研究可能会非常有效。从数据中缺失的信号中提取特征通常非常有用。
步骤 3:探索健壮、高效的基线解决方案
一旦确定了建模类别,就该考虑解决方法了。通常有许多最先进的解决技术可供您考虑。对于回归/分类问题,可以考虑使用线性方法、集成方法、深度学习等来实现。从最复杂的开始,也从最简单的开始,都不是一个好主意。选择一些强大的,可以涵盖许多试验中最突出的案件。排除那些计算时间长或者解释复杂的。如果花费的时间太长,将会减慢所有后续的迭代,最终会阻碍改进。如果太难解释,就很难确定改进,最终可能迫使解决方案停滞不前。
通常集合方法,如随机森林,梯度增强树,提供了良好的基线。它们提供了不错的结果,对变化是健壮的,提供了一定程度的可解释性,并且可以相当快地执行。
一旦基线被实施和评估,就该计划改进方向了。所有被接受的改进试验必须比基线表现得更好。
重复 3 步流程
一旦您获得了第一个基线解决方案的结果,重复三步流程。看看是否有可能进行更窄的建模,以及是否有更好的代表性数据可用。如果是这样,转到可能给你更准确结果的替代方法。不要专注于使运行 ML 解决方案的过程更有效,因为可能会有进一步的改进,从而排除所有的改进。例如,在面对更多数据时,除了通常提高准确性的常见方法,如自动特征选择、超参数调整等,您还可以采用更高级版本的集成方法、深度学习方法。
尽量让迭代更简单。一个里程碑可能包括许多迭代,并且可以基于一个固定的期限间隔或主要的改进点。涉众应该至少在里程碑的演示过程中参与进来。没有利益相关者的同意就进入微调的兔子洞通常是一个大错误。
评论
我们的开发工作,主要是在 AI/ML/Data 领域,因为过于关注算法而受到困扰。虽然选择正确的算法会更快更容易,但是识别和使用正确的数据是扩展这类工作的关键。寻找正确的数据是一场冒险,在没有朋友和同事的情况下做这件事很难。所以,总而言之,不要忘记交很多你指导或被指导的朋友。如果你有不同或补充的观点,请联系我们。
弗兰肯斯坦偏见
公平和偏见
我们在创造 AI 怪物吗?

作为一名计算机科学家,当我说计算机程序正以惊人的速度让我们失望时,我不会掉以轻心。有一次,一个谷歌图片搜索程序意外地认为黑人是大猩猩。或者那次微软制造了一个人工智能聊天机器人,它在不到一天的时间里成为了希特勒的粉丝。还有,那次亚马逊建立了一个简历排名程序,这个程序对雇佣女性没有兴趣。
为什么这种令人挠头、可能改变生活、但看似可以避免的结果在计算机程序中如此频繁地发生?我认为这与我称之为弗兰肯斯坦偏见的东西有关。下面我来解释。
在 20 世纪 60 年代和 70 年代,心理学家丹尼尔·卡内曼和阿莫斯·特沃斯基进行了一系列实验,询问“当人们不知道正确答案时,他们是如何做决定的”。这听起来像是一个罕见的事件,但人们实际上一直在这样做。这个人会很适合我的公司吗?在这样的雪地上开车有多危险?现在买 GameStop 股票还来得及吗?没有办法提前知道这些问题和数以百万计的其他问题的正确答案,但你的大脑无论如何都会做出决定。怎么会?
卡尼曼和特沃斯基(K&T)的工作后来获得了诺贝尔奖,他们命名了一系列偏见。例如,“可用性偏差”说,当人们能够很容易地回忆起类似的事件时,他们会认为事件更有可能发生。这就是为什么人们在飞机失事后更加害怕飞行。K & T 说出了几十个偏差;生动性偏差、代表性偏差、锚定偏差——所有关于大脑在不确定时如何做决定的规则。
但是几十年后,人类不再是现代世界中唯一的决策者。电脑越来越多地参与到我们的日常生活中。他们做每一件事,从提供指示,到审查抵押申请,到为法官决定判决建议。
随着所有这些对软件的有效使用,我们有责任回答这样一个问题:这些计算机程序在做决策方面有多好?
奇怪的是,经常是那些编写计算机程序的人被问到这个问题,就像 K&T 的其他问题一样,没有真正的方法知道正确的答案。我认为这导致了另一种偏见,一种 K & T 没有研究的偏见,我称之为弗兰肯斯坦偏见。
在 1818 年玛丽·雪莱的小说中,一位年轻的科学家维克多·弗兰肯斯坦在多年的辛勤工作后创造了一种新的生物。这是书中的一段引文:
我(弗兰肯斯坦)努力工作了将近两年,唯一的目的就是给一个没有生命的身体注入生命。为此,我剥夺了自己的休息和健康。我热切地渴望着它,远远超过了克制。
好莱坞后来把这句话变成了现在著名的“它活着”台词,但你明白了——创造东西是令人兴奋的,尤其是当它需要大量的努力和专业知识来完成的时候。
这种情绪同样适用于创造人工智能程序的计算机科学家和软件工程师。
其中一些人工智能程序非常复杂。AI 背后的数学有一些大多数人叫不出名字的符号。一些人工智能应用程序有数万行代码,用五种不同的 T21 语言编写。
因此,当计算机科学家和工程师最终拥有足够的知识来制造一个做某事的人工智能系统时,自然倾向于强调它的优势,有时不会充分考虑它潜在的缺点。
为什么我们需要考虑健壮测试?这是我们的人工智能,它当然工作得很好。你看到我要做的数学运算了吗?
这是弗兰肯斯坦偏见,随着我们越来越依赖人工智能技术,它的影响也变得越来越严重。
例如,弗兰肯斯坦偏见在 2020 年得到了展示,当时谷歌的计算机科学家偶然想到“我们需要对人工智能做更多的测试,也许我们建造这些系统的方式“存在根本缺陷”。尽管谷歌多年来在几乎所有可以想象的领域推出新的人工智能应用,从唇读和音乐到气候变化和饥荒。
它回避了一个问题:在我们提议将人工智能用于重要的现实世界任务之前,我们难道不应该知道如何测试它吗?
我认为,在自动驾驶汽车世界中,弗兰肯斯坦偏见也陷入了持续的错误计算。记住,像通用、谷歌 Waymo 和丰田这样的公司都表示,他们将在 2020 年前大规模生产无人驾驶汽车。好吧,现在是 2021 年,结果是,比更不准确。你几乎可以想象在 2015 年左右,当人工智能技术爆炸,无人驾驶汽车似乎不可避免地就要出现时,那些工程商店发出的乐观情绪。这些预测一头扎进了严酷的事实中,即在现实世界中测试一些对生死有影响的东西是多么具有挑战性。
最后,我们一次又一次地在计算机化的面部分析领域看到弗兰肯斯坦的偏见,出于某种原因,计算机科学家反复尝试使用面部图像来做一些事情,如"犯罪"探测器、政治派别传感器和性取向观察者。尽管没有证据表明一张脸可以预测这些特征(事实上与相反)。不出所料,其他人随后出现并指出否定这些发现的基本事实,但没关系,标题已经被抓住,损害已经造成。
是时候改变了。软件是呆在实验室里的神秘事物的日子已经一去不复返了。我们需要承认,我们如何测试软件和最初构建软件一样具有挑战性。
这始于大学课程,目前计算机科学(CS)课程中对测试的强调太少。大学不仅需要教计算机科学专业的学生如何用数据结构和面向对象设计之类的东西构建一个计算机程序,还需要教他们如何批判性地思考这个程序在现实世界中可能如何运行。随着技术融入社会课程的开展,你已经开始看到一些这种情况,但它们仍然太不常见,每年都有新的计算机科学毕业生进入劳动力市场。
其次,生产面向公众的应用程序的公司需要接受第三方的测试。很多时候,公司都躲在【专有信息】或【用户隐私】的声明后面,以避免他们的申请受到外部团体的审查。但是黑盒测试是我们知道如何做的事情。我们已经做了几十年,现在比以往任何时候都更需要它。
最近一个很好的例子是 Markup 的公民浏览器项目,该项目查看脸书向不同人展示的广告,以决定 FB 是否违反了自己关于如何定位广告的规则。令人惊讶的是,他们经常做。这种测试应该被每一个生产面向公众的软件的团队所支持。
如果我们采取这两个小步骤,提高计算机专业学生的意识和在公司层面接受外部测试,我认为我们会看到软件向公众发布的方式有巨大的改进。希望我们甚至可以达到这样一个点,即围绕人工智能和计算机科学的坏消息循环似乎将被打破,并被对下一代更具启发性的东西所取代。这是这位计算机科学家的希望,我们朝着这个方向前进,并尽快做到这一点。
~约翰·j·霍华德博士
约翰·霍华德 是一名计算机科学家,拥有生物识别算法有效测试方面的博士学位。这里提出的观点是他的。他们不代表他的任何附属机构的观点。如果你觉得这很有趣,你可以关注 Twitter 上的https://twitter.com/John_J_Howard或LinkedIn。
iGaming 中的欺诈检测
机器学习|数据科学|游戏
我们如何使用机器学习来标记欺诈和恶意行为

马库斯·斯皮斯克在 Unsplash 上的照片
我们生活在一个数字世界。我们所做的一切都直接或间接地受到某种数字技术的驱动。犯罪行为也已经数字化。网络罪犯利用技术进步及其弱点进行非法活动。我们这个世界的数字化为网络罪犯创造了一个环境,他们可以直接瞄准全球各地的个人和企业。世界上所有的行业都受到网络犯罪的影响。注册欺诈审查员协会报告称,企业因欺诈损失了约 5%的年收入[1]。仅在 2020 年,身份欺诈就造成了 560 亿美元的损失[2]。
赌博业(网上赌场)极易受到犯罪行为的影响。从洗钱到信用卡和身份欺诈,犯罪分子早在赌场行业转移到网上之前就已经瞄准了它。有人可能会说,iGaming 让犯罪分子更容易实施他们的恶意活动,特别是由于该行业随处可见[3]。
打击欺诈活动总是一个棘手的问题。尽管该行业受到高度监管和审查,但有创造力的罪犯仍设法逃脱法网。多个行业中存在多种欺诈检测解决方案[4,5,6];然而,赌博活动的动态性和不可预测性受到众多因素的影响,这使得欺诈检测的任务更加困难!即使仅仅考虑不同类型的可能的欺诈活动(或者至少是已知可能的),我们最终也会得到一个巨大的欺诈特征列表,每个特征都有所不同。
那么,我们是怎么做到的呢?
第一步:问题陈述
重要的事情先来。我们的目标是什么?我们有一个由分析师组成的内部风险和欺诈团队,他们手动审查玩家及其活动,以标记欺诈活动。作为数据科学家,我们希望帮助自动化他们的工作流程。分析师必须手动分析数百万笔交易;那么,为什么不让人工智能来承担重任呢?然后,人工智能会通知分析师潜在的欺诈玩家,然后他们会仔细检查。因此,大大减少了他们的工作量,提高了他们的效率。
因此,我们将我们的目标解决方案公式化为一个分类器,它将一个玩家标记为**Fraud**或**Not Fraud**。我们的分析师标记了他们分析的每一个账户。这一过程也促使我们决定构建一个分类器,因为我们可以访问由 13,591 名确认的欺诈者组成的 451,123 名玩家的标记数据集。正如所料,数据集严重失衡(约 3%的数据集是欺诈标签)。
步骤 2:数据准备和分析
我们排除了那些没有被贴上欺诈者标签且没有任何活动的玩家。这一过程共涉及 197,733 名玩家(其中 184,142 人之前未被标记为欺诈)。这种消除在两个主要方面帮助了我们的任务:降噪和对大多数类进行欠采样(我们的欺诈样本现在占整个数据集的 6.87%)。
我们收集、处理和设计了每个玩家超过 1000 个数据点。我们进行了特征选择和探索性数据分析,以达到每个样本 25 个特征的最终数量。
我们的特征库包括以下类别的变量:
1.多会话行为集合
2.游戏模式
3.会话识别和地理定位
4.人口统计数据
5.支付信息
我们的数据也受到缺失值的影响。在我们的例子中,缺失数据的百分比相对较低,所以我们决定使用中位数来估算缺失数据。由于高特征偏斜度和方差,我们选择了中值而不是平均值。我们将这种偏斜归因于不同的演奏风格以及样本中存在的异常现象。我们研究了不同的数据缩放和标准化技术及其对我们分析的影响。
由于欺诈行为往往会定期变化,我们还想了解欺诈在多大程度上受到概念漂移的影响。
我们将数据集分成几个部分,包括 1 年、6 个月、4 个月、1 个月和 1 周。使用 Mann–WhitneyU测试,我们评估了我们的特征分布态射。

月度箱中显著不同特征的百分比。来源:作者
根据我们的分析,我们预计每月会有 10%到 40%的功能遭受数据漂移。我们观察到第 36 个月和第 37 个月之间的漂移率最高。这几个月代表 2020 年初,正好赶上新冠肺炎疫情爆发。我们使用基于贝叶斯结构时间序列的算法,调查了新冠肺炎疫情(2020 年 2 月/3 月)开始时对数据基本分布的因果影响。如果所述事件没有发生,该算法使用基于贝叶斯的模型来预测预期的后验行为,并将其与真实观察到的行为进行比较。

新冠肺炎开始对数据分布的因果影响。来源:作者
虽然我们可以观察到该事件的负面影响,但获得的结果在统计上并不显著。因此,从统计学角度来说,我们必须排除新冠肺炎作为样本中数据漂移的可能动机。尽管如此,这两个测试都证实了我们数据中的数据漂移。
步骤 3:预测建模
使用分层的 10 重交叉验证,我们评估了多种预测算法在几种管道上的性能(不同的缩放/标准化技术,有和没有过采样,以及其他实验技术)。性能较好的技术(LGB —光梯度增强、RF —随机森林、DT —决策树、LR —逻辑回归)的结果如下表所示。

评估技术的性能结果。来源:作者
我们的评估表明,LGB 技术取得了最好的结果。我们使用贝叶斯优化和分布式 Parzen 估计树(TPE)进一步调整了它的超参数。
我们还从建模的角度研究了概念漂移问题。使用月箱,我们建立了一个实验,包括对不同序列的箱进行训练和测试。我们首先在整个数据集上进行训练,并排除最后 2 个月的测试,随着每次迭代,我们将一个月的时间从训练集转移到测试集。

量化漂移率的模拟实验示意图。来源:作者
随着迭代的进行,我们进一步绘制召回衰减图。迭代 0 表示我们数据中的当前月份(即,我们通过每次迭代从当前移动到过去)。

上面的可视化清晰地显示了在大约第 9 次(2019 年 11 月/12 月)和第 8 次(2020 年 2 月/3 月)迭代时召回率的急剧下降。我们越深入到 2020 年,观察到的回忆就越糟糕。再次确认数据漂移。这个实验帮助我们确定了生产中模型重新训练频率的基线。
步骤 4:说明性分析
预测一个潜在的欺诈玩家对我们来说是不够的。我们想更进一步,向我们的欺诈分析师解释为什么我们要向他们发送可疑行为通知。这种额外的详细信息不仅可以更深入地了解我们的模型是如何工作的,还可以使欺诈分析师快速确定最佳行动方案;因此,节省了更多的时间。
我们通过使用局部可解释的模型不可知解释(LIME) [7]来实现这个任务。我在另一篇文章中解释了石灰的工作原理。请随意查看。
使用 LIME,我们能够检索每个预测的前 3 个最有影响的特征。然后,我们处理这些数据,并向我们的分析师发出警报。下面我们展示了一个欺诈玩家的样本输出。

LIME 在欺诈玩家上提供的输出。来源:作者
从上面,我们知道,由于玩家的登录不匹配和投注行为,该特定玩家被标记为可疑。
结论
在本文中,我们讨论了如何使用机器学习来预测在线赌场环境中的欺诈行为。我们在 197,733 名玩家的数据集上使用交叉验证评估了我们的最终模型,欺诈样本占样本的 6.87%。表现最好的模型是 LGB,其精确度为 0.842 ( 0.063),召回率为 0.644 ( 0.115)。我们还讨论了如何调查数据中的概念漂移问题,以及这些结果如何影响我们的训练策略。我们还展示了如何更进一步,使用 LIME 等技术从我们的模型中生成可操作的见解。
喜欢这篇文章吗?我们在发表的论文中对此进行了更详细的讨论。请查看《斯普林格自然计算机科学》。
https://link.springer.com/article/10.1007/s42979-021-00623-7 https://david-farrugia.medium.com/membership
参考
[1]注册欺诈审查员协会:ACFE 向各国提交的报告| 2020 年全球欺诈研究。注册欺诈审查员协会技术报告。2020.http://www.acfe.com/report-to-the-nations/2020/。
[2]https://www . javelin strategy . com/content/2021-身份-诈骗-举报-转移-角度-身份-诈骗
[3]班克斯,詹姆斯(2012)。网丨上丨赌丨博和犯罪:一个确定的赌注? 《伦理杂志》。
[4] Yamanishi K,Takeuchi Ji,Williams G,Milne P .使用有限混合和折扣学习算法进行在线无监督离群点检测。数据最小已知发现。2004;8(3):275–300.
[5] Burge P,Shawe-Taylor J .一种无监督的神经网络方法,用于描绘移动电话用户的行为,以用于欺诈检测。并行分布式计算。2001;61(7):915–25.
[6]波顿 RJ,手 DJ,H DJ。用于欺诈检测的无监督剖析方法。载于:《信用评分与信用控制论文集》第七卷,2001 年。第 5-7 页。
[7]里贝罗,M.T .,辛格,s .和盖斯特林,c .,2016 年 8 月。“我为什么要相信你?”解释任何分类器的预测。第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集(第 1135-1144 页)。
想给我买杯咖啡吗?
https://paypal.me/itsdavidfarrugia?country.x=MT&locale.x=en_US
想联系吗?
我很想听听你对这个话题的想法,或者其他什么。如果你想联系我,请给我发电子邮件,地址是 davidfarrugia53@gmail.com。
利用图形分析进行欺诈检测

利用用例的网络结构提高预测性能
C 如今,用当今所有强大的机器学习算法来解决数据科学问题似乎轻而易举。如果经过正确调整和训练,这些算法能够有效地从数据中提取关键特征,学习常见模式,并最终提供准确的预测。
但当问题不在于数量而在于网络时,会发生什么呢?
通常在银行业中,仅依靠交易金额或其他特征很难发现隐藏欺诈性金融交易的空壳公司。然而,交易路径是模型可以用来提高其性能的关键信息。
同样,在医疗保健中,检测欺诈也很困难,因为它涉及到医疗服务提供者、医生、受益人的同行共同提供虚假理赔。
在这种情况下,还有哪些选择?
面对这类问题,人们通常会在两个必要条件之间摇摆不定:性能和可解释性。
- 性能:使用 图形神经网络 ( GNNs ) 模型或其变体如图形卷积网络(GCN) 、图形注意力网络(GAT) 等,图形可以产生优异的效果。为什么?主要原因是它们能够用向量表示图的节点、边或子图,并从中学习。[ 1 ]但是,它们会导致模型过于复杂且难以解释。
- 可解释性:通过从一组机器学习算法中进行选择,可以获得可解释性模型,但有时会牺牲性能。
幸运的是,还有另一种选择:结合了机器学习和图形分析。
该方法包括以图形形式表示问题,计算网络特征,并使用该信息丰富 ML 算法学习的数据集。因此,这种方法有可能提高模型性能,而不损害可解释性。
本文的目标是通过一个具体的用例来解释和说明这种方法:医疗行业的欺诈检测。
阅读本文后,您将了解:
- 如何以图形方式可视化您的数据并计算图形主要特征
- 如何对你的数据进行图聚类?
- 如何利用这些特性提升你的模型性能?
1.数据集丰富
1.1.关于数据集
数据由什么组成?
该数据集来自 Medicare,由提供者提交的索赔以及每项索赔的受益人信息组成。
更具体地说,它包含以下信息:
- 关于索赔:开始和结束日期、状态、涉及的医生(提供者、主治医生、手术医生)、诊断等。
- 关于患者:年龄、性别、所在地、健康状况等。
有关数据集的更多信息可在此处获得[ 2 ]。
目标是预测索赔是否具有欺诈性。
我们希望发现哪些欺诈案件?
它们主要是 4 个欺诈使用案例,通常在医疗保健行业占主导地位:
- 对未实际提供的服务计费
- 重复同一服务的索赔
- 歪曲提供的服务
- 收取比实际提供的服务更贵的费用
这些用例,尤其是前三个用例,在仅使用索赔、诊断或患者的可用信息时很难发现。
然而,提供者在医师网络中的位置带来了有价值的信息。例如:
- 对未实际提供的服务收费的从业者将倾向于具有更高数量的索赔,因此代表与其他节点紧密链接的中心节点。
- 重复索赔的医生将倾向于对相同的主刀医生和主治医生提出大量索赔,因此代表与相同节点紧密链接的节点,等等。
1.2.如何从表格到图形?
第一步是通过图形化表示和可视化来探索数据。
但是首先,图是由什么组成的?一个图形本质上包括:
- 节点(或顶点):表示数据中的实体。在我们的例子中,他们可以代表医生或病人。
- 边:它们象征着实体之间的一种联系,可以按照一定的准则进行加权。

图 1 — 图形组件,i 作者演示
在本文的其余部分,图表将由代表医生的节点和代表索赔的边组成。
使用库 Networkx [ 3 ]可以很容易地将数据集转换成图形,如下例所示。
图形的可视化可以使用库 Plotly [ 4 来完成。代码示例可以在这里找到。

图 2—图表探索,作者提供的图片
1.3.从图表中可以提取出什么有用的信息?
一旦数据集被转换成图形,我们可以从中获得什么信息?可以为代表医生的每个节点计算各种各样的指标。给定我们的用例,我们将只关注 4 个:节点的度、紧密度中心系数、特征向量中心性和 PageRank。它们主要捕捉一个节点在图中的中心位置和影响力。
度
它表示与顶点关联的边的数量
接近中心性
顾名思义,接近中心性度量一个节点与其他节点的接近程度和中心程度。对于给定的节点 u,它表示从 u 到所有 n-1 其他节点的最短路径距离之和的倒数,如下式所示:

其中 d(u,v) 是 v 和 u 和 n 之间的最短路径距离,是图中的节点数。
为了说明这一指标背后的概念,让我们举一个简单的例子:

图 3——作者展示的接近中心性
特征向量中心性
特征向量中心性基于其邻居的中心性捕获节点的中心性。这意味着具有高得分的节点是连接到同样具有高得分的其他有影响力的节点的节点。
它由什么组成?数学上,计算如下。对于给定的图 G(V,E) 具有|V|个顶点 A 是邻接矩阵,即如果顶点 u 链接到顶点 v,则ᵤᵥ =1,否则为 0 。
顶点 v 的相对中心度 x 可以定义为:

可以用向量表示法改写为特征向量方程:Ax =λx .**x的 vth 分量给出了顶点 v 在网络中的相对中心性得分。
关于分数及其计算的更多信息可以在这里找到[ 6 ]。
PageRank
关于 PageRank 分数,它依赖于归一化的特征向量中心性或归一化的声望 p.
它由什么组成?使用标准化邻接矩阵 N 进行计算,定义如下:

其中 od(u) 为节点 u. 的出度
节点 v 的归一化特征向量声望分数 p(v) 通过求解以下等式来计算:

更多信息可以在这里找到。
page rank 与特征向量中心性相比如何?由于两个指标都使用其邻居的中心性来测量节点的中心性,因此让我们来研究两个具体示例的结果。

图 4-特征向量中心性和 PageRank, i 作者举例说明
计算这些指标可以使用库 Networkx [ 3 ]来实现,如下面的代码所示。
下面是生成的数据帧的摘录。

图 5—提取具有图形特征的数据集
下图显示了目标潜在流量和图表特征之间的相关性。

图 6—目标电势分布与图形特征的相关性
2.使聚集
一旦计算出图表的特征,就可以更进一步,将医生分组。如何?这可以通过使用社区检测算法来实现。让我们探索一下最常见的方法:鲁文方法、信息图和随机漫步。
2.1.勒芬
Louvain 方法通过最大化每个社区的模块性得分来检测大型网络中的社区。
什么是模块化得分?
模块性得分测量一个图到几个社区的给定聚类的强度。为此,它依赖于社区内边的集中与所有节点之间链接的随机分布的比较,而不管社区。
更特别的是,它比较了:
- 一个簇内的边数
- 如果网络是一个随机网络,具有相同的节点数和每个节点的相同度,但边是随机连接的,则可以在集群中找到的预期边数
模块化得分的数学定义如下:


关于模块化得分的更多信息可以在这里找到[ 8 ]。
鲁汶算法如何最大化分数?
Louvain 方法使用了一种层次聚类算法:
- 一开始,每个顶点代表一个社区。然后,在每一步,顶点被局部地重新分配给对模块性分数增加的贡献最高的社区。
- 一旦没有顶点可以重新分配,每个社区就变成一个独立的顶点,这个过程重新开始。
- 当一个步骤中只剩下一个顶点或者模块性不能再增加时,算法停止。
关于算法的更多信息可以在这里找到。
2.2.信息图
Infomap 过程类似于上面描述的过程,但是具有另一个目标函数:它不是最大化模块性得分,而是最小化所谓的 map 等式。
地图方程代表什么?
在不深入数学细节的情况下,map 方程的基本思想是测量聚类的效果,当用作 Huffman 代码时,压缩关于探索你的图的随机漫步机的信息。
为了说明这个概念,让我们想象一个随机漫步人在探索网络。walker 在两个节点之间进行转换的概率由网络的结构和权重给出。
到目前为止,网络的每个节点都被编码成一个单独的码字。但是,如果您能够利用网络结构(即社区的存在)来最大限度地减少唯一代码字的数量,会怎么样呢?
事实上,考虑到网络中有一些区域,一旦进入,随机漫步机往往会无限期地停留,因此有优化的空间:我们可以为每个区域使用前缀代码,然后为模块内的每个节点使用唯一的码字。这些码字可以被其他区域的节点重新使用。
更多信息可以在这里或者在这些论文 10 、 11 、 12 中找到。
2.3.步行陷阱
Walktrap 算法也是基于随机行走的。它通过运行短距离随机行走,在一个图中找到密集连接的子图,即社区。
这种方法背后的想法是,散步更有可能留在一个特定的社区建设。
更多信息可以在这里找到[ 13 ]。
运行这些社区检测算法可以使用库 igraph [ 5 来实现,如下面的代码所示。
这样就可以图形化地显示聚类的结果,如下图所示。

图 7—社区检测结果,作者提供的图片
3.系统模型化
现在,最终的问题来了:底层业务用例的网络表示为模型带来了真正强大和健壮的价值吗?让我们通过我们的用例来探索答案。
3.1.性能提升到了什么程度?
关于培训设置
我测试了 3 个场景,这些场景在用于模型训练的特性方面有所不同:
- 场景 1 —基线:关于索赔和患者的信息(参见第 1.2 节。)
- 场景 2 —基线和图表的特征:这些特征包括上述 4 个指标(参见第 1.3 节。):代表医生的节点的度、他们的接近度中心系数、特征向量中心性和 PageRank。
- 场景 3——基线、图的特征和检测到的社区:测试的算法是上面解释的算法(参见第 2 节。):Louvain 方法、InfoMap 和 RandomWalk。
关于训练设置,我将数据集分成两部分:一个训练集,代表初始数据集的 80%,和一个验证集。对于每个场景,我测试了多种分类算法,并使用三重交叉验证方法根据训练集的 AUC 选择了最佳算法。
结果
下表包含使用验证集上最佳模型的每个场景的 AUC 分数。它还包含 3 个最重要的变量。

图 8—结果表
到目前为止,最后一种情况优于第一种情况。下图中的 ROC 曲线证实了这一观察结果。

图 9-ROC 曲线
3.2.可变重要性呢?
场景 3 中的最佳模型是随机森林。因此,通过计算每个树中杂质减少累积的平均值和标准偏差,可以洞察每个变量的重要性。
下图显示了场景 3 最佳模型的最重要变量。

图 10—特征重要性(场景 3)
与图形相关的特征在模型预测中具有更高的重要性。这种重要性可能有较大或较小的可变性,这取决于它们在构造中包含的随机性的大小。
关键要点
从这个用例中可以得到什么启示?
- 使用图形分析可以显著提高模型的预测能力。为什么?常规的 ML 方法包括从单个观察中学习,而带图 ML 使用现有的网络结构来检测新模式,并添加关于实体如何相互连接以及它们的关系性质的有价值信息。由于初始特征集没有捕捉到这些信息,带图的 ML 可能会提高模型性能。
- 使用图形分析会导致很高的计算成本。根据所使用的算法,这可能比在特征工程步骤中添加一些根据手工挑选的信息手动构建的特征成本更高。
资源
[1]周杰,甘渠翠,,胡,张正彦,,程阳,,王,,孙茂松,图神经网络:方法与应用综述,艾开
[2] Kaggle,医疗保健提供商欺诈检测分析
[3] Networkx 库
[4] Plotly 库
[5] iGraph 库
[6]维基百科,特征向量中心性
[7] Günce Keziban Orman,Vincent Labatut。人工网络社区发现算法的比较。发现科学国际会议,2009 年 10 月,葡萄牙波尔图
[8]维基百科,模块化
[9]维基百科,卢万法
[10] Aaron Clauset,M. E. J. Newman,Cristopher Moore,在非常大的网络中发现社区结构,2004 年 8 月
[11] Carmel Farage,Daniel Edler,Anna Eklö,Martin Rosvall,Shai Pilosof,使用信息图确定生态网络中的流量模块
[12]尼克拉斯·勇克,利用卢万和信息地图进行社区探测,2020 年火星
[13] Pons、Pascal 和 Matthieu Latapy,使用随机行走的大型网络中的计算社区
欺诈预测算法:从欧盟人工智能法规草案的角度看
欧盟人工智能条例草案可能会对欺诈预测算法产生影响,可能需要审查和完善

来源:vectorjuice 创建的人向量(通过 Freepik)
欺诈预测模型在金融服务和新兴技术行业(包括电子商务)中已经存在了十年或更长时间,它在多个其他行业中针对各种使用案例(例如保修欺诈预测)发展缓慢
欺诈或网络安全预测模型是一种典型的预测模型,其特定目的是在给定特定输入参数的情况下识别欺诈或网络安全威胁的指标。这些模型可以是统计模型或机器学习模型(这里称为“算法”)。这些算法中的许多主要是基于预先识别的模式和/或历史数据来识别潜在的不一致或不适当的交易;以及它的概率值。例如,金融服务试图识别在贷款时寻求信贷的潜在欺诈性申请,或者电子商务试图基于客户的一组数字足迹/动作来消除潜在的欺诈性交易。
更常见的是,这些算法将 3 个方面的信息作为输入(a)交易数据,(b)客户身份相关数据(即一种客户评分形式)和人口统计数据。算法会检查这些数据方面,以查看是否存在与代表欺诈或网络安全问题的预先识别/历史交易相似的模式。
在某些情况下,欺诈行为通常可以直接从交易中识别出来,而在某些情况下,它们可以从交易中推断出来或在交易中假设出来。推断或假设是指在这些情况下,数据所显示的内容并不能得出欺诈的结论,但却有可能导致欺诈。这些推论和假设是经过一段时间建立起来的。例如,来自过去欺诈案例比例较高的地区的个人申请的信贷;可能有被算法归类为欺诈的风险。训练数据集对于开发预测欺诈行为的平衡算法至关重要。不平衡的数据集或有偏差的数据集可能会导致本质上具有歧视性的不良结果。
考虑到确定欺诈交易的性质和复杂性,组织注入人在回路算法来验证预测的结果,从而消除误报。只有概率(比如说 60-70%)高于某个阈值的预测才会被考虑用于人在回路的评审。然而,这并不是一致的行业惯例,因为在许多流程中,交易是基于预测而被归类为欺诈的,而没有人工验证(“自动算法”)。值得注意的是,在某些情况下,例如,在线支付欺诈的预测模型,在某些情况下可能没有验证机制来消除误报(限于推断),而不管是否存在人在回路中的审查或其他情况。
最近,算法经常因歧视和对种族、性别和/或其他因素的偏见而受到批评。这对于欺诈预测算法来说没有什么不同。在各个地区,监管机构正试图引入与管理算法相关的政策和框架。
欧盟(EU)也在考虑可以帮助管理算法的法律。拟议法规的草案强调了拟采取的措施和罚款。欧盟法规打算对违规公司处以 3000 万欧元或全球总营业额的 6%的罚款,以较高者为准。
除其他外,拟议的法规提到,如果算法预测犯罪或预测某人提供的信息的可信度,影响该人的人身自由,则应被列为高风险人工智能。高风险人工智能应进行符合性评估(即人工智能系统的审计),以确定采取了足够的措施来避免潜在的伤害或可预见的意外后果。此外,该规定提出,禁止任何让用户形成意见或做出不利于他们的决定的算法。对用户进行分类的社会评分也是禁止的,这反过来会对他们产生不利影响。
该条例还提出了一项义务,即在意识到事件发生后 15 天内向当局报告任何违规或违法行为。虽然全球的技术治理专业人士都在对拟议法规的充分性/不足性发表评论,但有必要了解此类法规对欺诈预测或广泛应用于各行各业的网络安全算法的潜在影响。
这些法规目前分别适用于欧盟的提供商(直接或通过第三方开发和部署算法的人)和用户,无论他们来自哪个国家或国籍。根据该法规,欺诈预测模型需要具备以下条件:
1.高质量数据集,用于在部署前对上述数据进行沙盒培训或测试。
2.清楚地阐明算法的预期用途,并评估可预见的意外后果。
3.展示为防止伤害所做努力的符合性声明,包括可能的误解或假设情景。
4.适当的用户界面,不会影响用户采取不利于他们的行动或决定。
虽然上述原则看似规范,但也存在与之相关的内在挑战。它们是:
1.历史欺诈数据集通常不完整且不完整,在描述欺诈的性质、证据以及与被归类为欺诈的交易相关的触发因素方面存在差距。因此,它们包含几个部分记录的推论和假设,从而暴露了缺乏欺诈的高质量数据集和嵌入在这种算法中的固有社会评分。
2.在没有指导方针或框架的情况下,定义和识别意外后果将是主观的。
3.符合性声明或评估要求组织详细说明在确定结果时的假设和推论,因此需要重新考虑预先存在的算法。
尽管上述原则显示出与提议的法规相关的复杂性,但是组织可以采取某些明确的步骤。它们是:
1.重新审视预先存在的欺诈预测或网络安全算法,以理解和评估培训数据、绩效指标(以特定的准确度)、假设和推论。
2.进行算法风险分析,以确定由此产生的潜在意外后果。记录风险,让风险承担者达成共识。
3.制定风险缓解计划,包括定义适当的风险处理和控制实施。
当务之急是,随着全球对人工智能危害的关注,这些法规将迅速成熟。在这种情况下,缺乏管理欺诈预测算法的结构化方法可能会对组织的声誉产生严重的不利影响。因此,重新访问-修订-恢复值得信赖和合规的欺诈预测或网络安全算法。
原文发表于 Linkedin Pulse 此处
用于训练深度学习模型的免费 GPU
是的,你没听错。它是免费的。

GPU 是训练深度学习模型的重要组成部分,而且价格不菲。在本文中,我们研究了一些提供免费 GPU 的平台,这些平台没有免费试用期、有限的免费积分或注册时需要信用卡的限制。
快速比较
我们正在考察的 3 个平台是 Gradient、Google Colab 和 Kaggle。下面是每个平台提供的一些硬件规格和特性的快速总结。

特征对比。(图片作者)
Maximum Execution Time Per Session:代码在超时前可以运行的最长时间
Idle Time:您可以让笔记本电脑在关机前空闲的最长时间
*:Google Drive 提供 15GB 免费存储空间
梯度
Paperspace 的 Gradient 提供基于云的端到端 MLOps 解决方案。作为其产品供应的一部分,Gradient 提供社区笔记本电脑,这些笔记本电脑是公共的和可共享的 Jupyter 笔记本电脑,运行在免费的云 GPU 和 CPU 上。

(来自 Paperspace 的截图)
赞成的意见
- 8 个 CPU,30GB RAM,是所有 3 个中最高的
- 1-6 小时之间的长空闲时间
骗局
- 没有私人笔记本电脑,如果运行在免费的 GPU
- GPU 取决于可用性
- 8GB 的低 GPU 内存
- 5GB 的低可用存储空间
Gradient 有不同的定价层,允许不同级别的 CPU / GPU 实例类型。让我们来看看免费层。
1.注册一个账户
只需一键注册,就能轻松唱出渐变效果。

(来自 Paperspace 的截图)
2.创建笔记本
- 命名您的项目
- 选择运行时

(来自 Paperspace 的截图)
3.选择一台 GPU 计算机。一定要选择那些标有“免费”的。在免费 GPU 上运行的笔记本电脑将是公共的,最多 6 小时后会自动关机。

(来自 Paperspace 的截图)
业余爱好者和学生的免费层计划只允许选择 Quadro M4000 GPU。免费 GPU 也受到可用性的限制,在高峰时期可能不可用。
3.启动 Jupyter 实验室
启动笔记本会将我们带到一个允许我们启动 Jupyter Lab 的工作区。让我们使用 Jupyter 实验室的终端来检查 GPU 和 CPU 规格。
nvidia-smi
免费版本提供了一个带 8GB RAM 的 Quadro M4000 GPU

(截图来自 Paperspace)
lscpu
无梯度 GPU 机器还配备了 8 个英特尔至强 E5–2623 CPU 和 30GB RAM。

(来自 Paperspace 的截图)
cat /proc/meminfo

(来自 Paperspace 的截图)
Google Colab
Google 推出的 Google Collaboratory 是一款 Jupyter 笔记本 IDE,可以使用免费的 GPU 和 TPU。你只需要一个谷歌账户就可以开始了。Google Colab 允许您将 Google Drive 作为 Colab 项目的存储文件夹,这使得读取和保存数据变得轻而易举。是的,你还可以免费获得 15GB 存储空间的 Google Drive
赞成的意见
- 与 Google Drive 集成用于数据存储
- 没有使用限制
- 允许私人和公共笔记本
- 12 小时的长执行时间
骗局
- 大约 30 分钟的短暂空闲时间
- 每次会话前需要重新安装和验证 Google Drive
要在 Colab 中使用 GPU,在顶部功能区选择硬件加速器的 GPURuntime→Change Runtime Type

(截图来自 Google Colab)
根据谷歌 Colab 的常见问题,Colab 提供了多种 GPU,如 Nvidia K80s,T4s,P4s 和 P100s,但是您将无法选择特定的 GPU 类型。让我们来看看 Colab 必须提供的一些硬件规格。
nvidia-smi

(截图来自 Google Colab)
在这个特殊的会话中,我被配备了大约 12GB 内存的 Tesla K80。
lscpu

(截图来自 Google Colab)
Colab 还提供 2 个英特尔 Xenon 2.3GHz CPU 和 13 GB RAM。
cat /proc/meminfo

(截图来自谷歌 Colab)
卡格尔
Kaggle 是一个数据科学社区空间,以举办顶级机器学习和深度学习竞赛而闻名。它提供 Kaggle 笔记本,这是由免费 GPU 和 CPU 支持的可共享 Jupyter 笔记本。
Kaggle 提供至少 30 小时的动态 GPU 配额,该配额在 UTC 时间每周六午夜重置。我通常每周获得 30 到 41 小时的 GPU 配额。我喜欢 Kaggle 笔记本的一个原因是它的提交模式,允许用户在后台运行整个笔记本。这意味着我们不必在代码运行时保持浏览器打开。Kaggle 还允许通过简单地快速保存或在提交模式下运行笔记本来对笔记本进行版本控制。这使我们能够查看以前的笔记本版本并跟踪我们的进度。
赞成的意见
- 提交模式允许代码在后台运行
- 允许其他用户对笔记本发表评论
- 16GB GPU 内存,所有 3 家供应商中最高的
- 允许公共和私人笔记本
- 访问 Kaggle 数据集
- 笔记本版本控制
骗局
- 每周 30~40 小时的动态 GPU 配额
- 交互式 GPU 模式下 20 分钟的短暂空闲时间
让我们来看看 Kaggle 必须提供的一些硬件规格。
nvidia-smi

(截图自 Kaggle)
Kaggle 提供 16GB 内存的 P100 GPU。
lscpu

(截图自 Kaggle)
它还提供 2 个 2.00GHz 的英特尔 Xenon CPU,最大 13GB RAM
结论
我们审查了 3 个不同的平台,免费提供支持 GPU 的 Jupyter 笔记本电脑。之所以选择这些平台,是因为它们不需要信用卡来注册,没有信用额度限制或试用期。
如果我打算创建可共享的笔记本,Kaggle 是我的首选平台。在我之前关于训练深度学习情绪分析模型的文章中,我利用 Kaggle 笔记本进行训练和推理,请随意查看。对于大量使用 GPU 的用户来说,每周的 GPU 配额可能会令人沮丧。Kaggle 提供了一些关于如何更有效地使用 GPU 的技巧。请随意分享您的经验和替代平台。
参考资料:
-
加入 Medium 阅读更多这样的故事。
用于生成真实假数据的免费资源
了解如何为您的数据科学项目创建模拟和虚拟数据

沃尔坎·奥尔梅斯在 Unsplash 上拍摄的照片
我们都知道数据是必不可少的。问题是很多时候我们没有足够的钱。当我们开发数据应用程序或管道时,我们需要用类似于生产中可能看到的数据来测试它们。
很难手动创建足够数量和种类的真实数据集(例如,不同的数据类型、特征)。此外,手工创建的数据容易受到我们潜意识和系统性偏见的影响。
幸运的是,有免费的在线资源可以生成逼真的假数据供我们测试使用。让我们来看看其中的一些:
(1)Faker(2)Mockaroo(3)generated ATA
(1)造假者
术语“Faker”是模拟数据生成的同义词,因为有许多针对不同编程语言的 Faker 数据模拟库(例如, NodeJS , Ruby , PHP , Perl )。这里精选的 Faker 库是 Python 版本下的库。
Faker 是一个帮助你生成假数据的 Python 库。从文档中,我们可以看到,可以很容易地安装以下命令:pip install Faker
安装完成后,我们实例化一个 Faker 类对象并调用各种方法来生成我们想要的模拟数据类型:

来自 Faker GitHub Repo 的截屏图|根据 MIT 许可使用的图片
此外,Faker 有自己的pytest插件,它提供了一个可以在测试中使用的faker夹具。
链接
(2)摩卡鲁
Mockaroo 允许您根据您定义的规范,快速方便地下载大量随机生成的测试数据。
这个平台的奇妙之处在于不需要编程,您可以下载许多不同格式的文件(例如 SQL、XML、JSON、CSV)直接加载到您的测试环境中。注册后,您还可以创建并保存您的模式以备将来重用。
有了 Mockaroo,你可以设计自己的模拟 API并通过利用 Mockaroo docker 镜像将它们部署在你的私有云中。

Mockaroo 主页截图|图片经 Mockaroo 许可使用
链接
(3)生成数据
GenerateData 是一款免费的开源工具,可以让你快速生成大量的自定义数据。像 Mockaroo 一样,该网站提供了一个易于使用的界面(带有快速启动功能),用于创建各种格式的大量不同类型的数据。

在 GPL3 许可下使用的生成数据(V4) |图像的屏幕截图
在主网站上测试完演示之后,你还可以下载免费的、功能齐全的 GNU 许可版本。如果您需要的模拟数据超过了每次运行 100 行的最大值,那么 20 美元的小额捐款就可以让您一次生成并保存多达 5,000 条记录。
在撰写本文时,GenerateData (V4)的新版本接近测试版,所以请查看 GitHub repo 以获取更新。
链接
- 生成数据网站 (最新版本— v4)
- 生成数据网站 (旧版本— v3)
- 生成数据 GitHub
(4) JSON Schema Faker
JSON 文件格式是存储和传输数据对象最流行的方式之一。因此,生成假数据和定义数据结构的 JSON 模式将是有益的。
JSON 模式伪造者将 JSON 模式标准与假数据生成器结合起来,允许您生成符合模式的假数据。
该网站有一个用户界面供您定义模式。您可以选择并构建已经为您准备好的示例列表,而不是手动编写模式。

JSON Schema Faker 工具|在麻省理工学院许可下使用的图像截图
链接
(5) FakeStoreAPI
到目前为止,您应该已经遇到了相当多的通用(即 Loren Ipsum)类型的模拟数据。这就是 FakeStoreAPI 改变事情的地方。
它是一个免费的在线 REST API,用于为电子商务或购物用例创建伪真实数据,无需运行服务器端代码。模拟数据将与需要 JSON 格式的零售相关数据(例如,产品、购物车、用户、登录令牌)的项目高度相关。
只需几行 API 调用代码,就可以轻松创建或修改模拟数据:

截图来自 FakeStoreAPI 网站|图片经 FakeStoreAPI 许可使用
链接
- FakeStoreAPI 网站
- 【T42FakeStoreAPI GitHub**
(6)素甲鱼
Mock Turtle 是一个用户友好的基于 GUI 的平台,用户可以在 JSON 模式中生成假数据。
该工具模仿 JSON 树结构,您可以在每次点击时直接看到模式的变化。
除了 JSON 模式解析,它还允许免费生成嵌套结构和大型数据集。

截图来自素甲鱼网站|图片经素甲鱼许可使用
链接
知道其他优秀的模拟数据生成器吗?请在评论区告诉我。
在你走之前
欢迎您来到加入我的数据科学学习之旅!点击此 Medium 页面,查看我的 GitHub ,了解更多精彩的数据科学内容。同时,享受生成假数据的乐趣吧!
* *
自由意志和人工智能(AGI)
关于人工智能的课程来自于关于我们大脑的课程。专注于自由意志的本质。
两年来,我一直试图通过冥想来训练我的大脑。对我来说,你能注意到大脑的实际工作方式不同于感知的工作方式的频率和容易程度是不寻常的。像在你的视野上叠加图像,注意到任意选择是如何做出的(它们出现了),甚至是自我想象的负面情绪的短暂性质都可以很容易地挑战我们的现状。
唤醒应用有一个新的系列,简洁地描述了自由意志的短暂感觉。毫不奇怪,我们如何看待我们通过自己的主观经验创造的人工智能。也就是说:我们通过我们如何思考和看待世界来看待人工智能。我们的思想和景象并不完全反映现实,当你冥想和检查现实的本质时,你可以观察到的差距就是我们决定是否要向我们的机器创造灌输的差距。
最终,大脑的本质使其感觉像是有人类的感觉,这可能是硬连线在代码中的,以确定它如何成为一个人工智能。一些感觉在代码中设置起来更直观,一些代表了人工智能研究中的开放问题。在硬币的另一面,我们可以让没有承载或期望的人工智能感受到我们作为人类时经常体验到的任何感觉。在这篇文章中,我将带你看一下《自由意志》在山姆·哈里斯的 90 分钟课程,重点是它对人工智能的意义。
- 第四节 1。原因&效果, 2。没有思想者的思想, 3。选择、理由、&知识和 4。爱&恨与创造智能计算机系统关系最大,所以我会在那里花更多的时间。
- 最后三课 5。罪名&刑罚, 6。责任的悖论和 7。为什么做任何事?根据这些心理结构,与伦理和功能社会的创建有更多的关系。这三个将不是关于创造人工智能,而是人工智能如何更好地融入这个社会。
在写这篇文章的时候,很多主题都提到了人工智能(AGI)和计算机意识。提出的观点是早期的探索,我怀疑随着我们了解更多,这些主题将被重新审视。

照片由来自 Pexels 的 nicollazzi xiong 拍摄。
预赛
我在这篇文章中频繁使用的一些术语可能有多种含义,但在这篇文章中,我认为它们是:
- 冥想:研究心灵本质的行为,通常通过安静地专注于意识的个别方面(比如呼吸)。
- 自由意志:主观感觉,你的决定、生理以及主要是你的自我感觉在某种程度上决定了你的行动。
- 人工智能:推理并与世界互动的智能体。
作为一个说明性的精神练习(冥想),让你对自由意志的幻觉有所了解,请密切关注这项随意的任务,以及你的大脑是如何得出结论的:在过去的一个月里,你读过的最喜欢的文章是什么?
(停下来仔细想想发生了什么)
现在,想想另一篇文章。
你能控制想到哪些文章吗?这种感觉是,随机的建议似乎是你当前状态的结果。这是一个明显的例子,说明我们没有自由意志,实际上,我们欺骗自己的幻觉是一种幻觉,即自由意志的幻觉根本就存在。我绝不期望你在做了这些之后认为你是一个自治的实体,这可能只是启发性的,让你想要进一步调查。
自由意志幻觉的核心幻觉和欺骗我们的人工智能
仔细研究心灵的本质,显示出我们对于经验的主观力量。存在的主观性是我们的联系,我们制造的机器主要反映了这一概念。就像上面的例子一样,我们大脑中的幻觉实际上是存在自由意志的幻觉——也就是说,当我们仔细检查正在发生的事情时,自由就消失了。
考虑这些状态和普通操作对于在回路中使用强大的人工智能进行规划是至关重要的。现在,我将从 Sam 身上学到一些东西,以及我们可以从中学到什么。
第一课。因果关系
考虑电话响铃的原因——一些数字信号被传输到扬声器(在此之前还有许多数字信号),电振荡产生声波。电话铃响的原因可以有不同的解释(在工程链上),人类的思维也存在同样的模糊性。不同之处在于:在人类的思维中,除了我们自己,我们不会真正考虑其他可能的原因。最终,人类大脑中的启动(一组神经元对刺激做出反应)和代码中的中断触发动作几乎没有区别。在对人脑的认识上,我们受到神经科学的限制,而在计算机上,我们已经消除了大部分捏造的不确定性。对一个系统的基本科学理解的差异并不排除不确定性在高层次上表现相同。
对人工智能的影响:改变软件中因果的概念
对于人工智能来说,接受事件的原因实际上会更容易——我们希望我们的代理人根据他们拥有的信息采取行动(除非我们添加更多抽象的幻觉)。 我们可以很容易地连线一个 AI,让它察觉到许多事件都是它自己造成的 。这将通过用外部程序更新它的先验(任何信念的分布)来完成,但是让计算机认为这是它自己的成果。
第二课。没有思考者的思考
我们有两种行动和精神调查的模式,自愿的和非自愿的——只有前者(自愿的)表示思想。如果你重新考虑预备课程中提出的关于选择的冥想练习,很容易证明认同思想不是自由意志。认同思想与其说是控制,不如说是注意(这是许多冥想练习的第一课之一)。短语没有思考者的思考指的是我们都经历过许多想法,但仔细观察,我们的意识中没有一个思考者(以思考者的形式,对出现的大部分信息做出反应和策划)。
对人工智能的影响:人工数据流的分级人工智能
我们可以让机器人真正以其思想真正与思考者相关联的方式行动,但我认为这混淆了直接计算的好处(在一些研究好奇心中)的功效。一个具体的组织可以是一个具有计算结构的人工智能,因此似乎有两个计算级别:一个是控制,一个是信息进展的环境——有点像一个具有独立多模态数据处理单元的 RL 循环(在这一点上,我很明显,我们没有术语来讨论这些东西看起来会是什么样子)。这种结构可以反映人类对思想者和意识的感知。
第三课。选择、理性和知识
没有自由意志,推理行为和知识的实质就会受到质疑。运气似乎是对随机性的心理反应,而不是真正的属性。据我所知,对目标的推理是一种自我价值的更新,而不是一种选择。最终的决定不会直接在你的控制之下。本质上,有些违背直觉,缺乏自由使得推理成为可能。这个世界反对自由选择,因为它们可能是错误的(就科学等法律而言)并会受到惩罚。真正的自由是认识到你不能控制先前认同的经验。
对人工智能的影响:操纵计算机与随机性的关系
人工智能可以对运气(随机性和不确定性)以及它如何与其智力结构相结合有不同的理解。这种更直接的人工智能方法利用了计算的优势,但如果我们寻求创造意识,拥有将命运与随机性联系在一起的人工智能可以提供强大的自我来源。就像自我意识一样,在我们目前如何看待人工智能的问题上,知识的表述似乎不是很实用,这让我认为这可能是最大的改进机会之一。
第四课。爱与恨
我们如何体验不同类型的情感,以及为什么体验不同类型的情感,这种二分法是人类魅力的一部分。很难描述发生了什么,但我们都感觉到了。爱是一种不可思议的感觉,它看起来像是偶然发现的,而仇恨则让人难以置信地专注。爱是对人或事物的一种感觉(而不是他们如何做决定),而仇恨是非常具体的自由意志和行动判断(认为他们应该采取不同的行动)。自由意志的争论从这里开始引入伦理讨论,考虑这样的场景,比如原谅那些被证明犯下滔天罪行的人,部分原因是退化的生物学,比如脑瘤。
对人工智能的影响:更容易制造爱计算机
乍一看,很难制造出同样仇恨的人工智能。人工智能可以被制造成想要优化,但是真正的仇恨代表了一种复杂的“如果”( what if)思维结构。让我们为爱机器人的人敞开大门吧——当机器人完美地完成任务,成为更大系统的一部分时,我们就会爱上它。这两者都有将人类价值提取为数字近似值的复杂问题,但经过这次分析,我比我最初想象的更加乐观。

photo bycotton brofromPexels。
幻想、设计、陷阱
机器学习研究人员已经通过研究大脑的结构学到了很多东西。基于头脑的感知本性来设计系统要复杂得多,但我认为这能让我们更深刻地理解感觉聪明意味着什么。很可能我们设计的变得普遍智能的人工智能将而不是具有反映人类大脑的精神行为(注意:这取决于 AGI 研究如何进行,全脑仿真是研究的一个选项,但这需要神经科学的巨大进步,所以有些人持怀疑态度)。
我工作过的所有学习系统都形成了智能,作为探索和近似的迭代计算设备。对我来说,现在还不可能考虑体验这样一个系统的世界会是什么样子。
清楚地理解给予人工智能的计算、引用和开发的本质对于减轻任何潜在的危害是至关重要的。我会说,我们希望让我们的人工智能在上面讨论的大多数轴上明显非人类(人性往往意味着矛盾和不确定性,但也创造了爱的能力),以便明确量化这些试剂的潜在有害影响。
我非常感兴趣的是,我们可以从我们的存在本质中学到什么,以及它如何影响我们构建的系统。在我的第一篇关于基于模型的强化学习的文章中,我讨论了它与大脑结构和心理规划的内在联系。如果你认为我错过了什么或者想讨论这个,请留下评论或者联系我。将来我可能会更详细地探索冥想和计算机智能之间的联系。这有点像我们如何创造一个自由意志机器人的建议可能会导致意识仿真。
现在谈谈自由意志课程的其余部分。

来源——作者(普莱西德湖)。
幻觉的含义
我们的社会实际上是在个人拥有自由意志的假设下构建的。当有更多的人工智能明显缺乏自由意志时,看看它们是否被永久地视为与人类不同的独立实体类型将是有趣的(至少在减轻风险方面,法律先例很难远离自由意志的概念)。人工智能可以潜在地教会我们一些事情,比如减少对通过生物机会危害社会的人的惩罚,而是消除危险。在经历了互联网的黄金时代后,我将关注的下一波浪潮是与人工智能的互动如何重构我们社会的习惯、文化和法律。
第五课。犯罪与惩罚
如果一个人在森林里被一只熊和一个人攻击,责备的反应会非常不同。会因为自由意志而更加憎恨那个男人。这种直觉相当于我们对有计划的惩罚的反应——那些有自由意志幻觉的人应该有更多的控制权。我们能学到的是消除社会保护彼此免于个人错误指责的责任的歧义,尤其是当我们知道生物结构的失败会导致人类的行为时。
注:有趣的是,律师在中世纪曾代表动物!老鼠因为吃猫可以上法庭,陪审团被告知老鼠太忙无法出席( 例 , 例 2 )!
第六课。责任的悖论
从自由意志的角度来看,真正的随机会支持个人控制。跟随你的道路的行动不那么自由;我们更偏向。对于一个职业高尔夫球手来说,错过一次推杆更令人震惊,因为他们的线路肯定出了什么问题——但有一个原因是可以辨别的。理论上,打高尔夫球的人应该承担更少的责任,因为它看起来更随机。
现在,计算机计算似乎与神经计算完全不同,但是随着大脑模型的改进,同样程度的决定论也很容易被观察到。大脑中事实的主观性(人类偏见)允许自由意志的主观性,但原因不会改变预先设置的神经组成。没有科学证据反驳我们在相同的神经状态和环境下会做出不同的决定;我们生命中的每一刻都是 起因 。
如果人们不那么负责任,如果这种邪恶的疗法是有疗效的,那我们把它给谁呢?有没有我们认为“太邪恶”而无法治愈的人?
第七课。为什么做任何事?
结论回答了这个问题:如果我们没有自由意志,我为什么要做任何事情?没有自由意志,我们意识到我们是环境和我们相处的人的产物。没有自由意志,我们就是集体的一部分——一个共同更新每个人的集体。这一群人可以将社会最佳利益与过失分开,并可以驱散骄傲和羞耻的观念(通过意识到它们是有意识的构造)。更新是我们大脑和我们经验的生物学先验。
机器人是集体的一部分
仍然做任何事情的原因是因为你的行为创造了你周围的人。这成为了一个富有同情心的反馈循环,你让你周围的人变得有能力,他们也让你变得有能力。关键是,我们是集体的一部分,没有自由意志,许多是的负面因素就不存在。
通过探索这一点,我觉得人工智能可能比个人更符合集体观念。如果这是真的,这将是数字世界的一股有趣的力量。
如果你想支持这个:赞,评论,或者伸手!
像这样?原来是贴在我的 简讯 民主化自动化 上的。订阅❤.
自由数据科学家?彻底忘掉“2021 年学习指南”
学习新的库还是最终做客户想要的?
独立专家的战略和战术

插图来自上卷
远程工作是当今的一种新常态。离开办公室的头几个月相当有趣,但那份工作还是那份工作:依赖固定的薪水/时薪,有限的机会,失去温暖工作的风险。我们很多人都尝试过单干,在网上寻找客户,学习新的热门技能。然而,你可能会注意到,你好不容易征服的新客户不会为 Udemy 证书和 Tensorflow 技能付钱——他们只想要尽可能便宜的两周内 99%准确的解决方案。别忘了还有那个时间追踪"。因此,对你来说——更多的压力,更少的钱,更少的满足感 来自所谓的独立、创造性和鼓舞人心的工作。在这篇文章中,我想总结一下我在维罗纳大学会议上详细谈到的实用见解,它将帮助你建立一个独立的专家职业生涯。另外,我邀请你参加下周的俱乐部聊天,我们可以一起更详细地讨论我们的经历,并互相帮助:
https://www.joinclubhouse.com/event/Md0N42wq
客户真正想从你这里得到什么
商业的建立是为了满足多种目标:创收、社会和环境影响、关系(用美元衡量)、创造就业机会、空气质量等。为了最大限度地提高上述数字,创始人和经理们创建了这样一种结构,在这种结构中,每个人都有自己的位置来完成合格的工作。作为一名员工,你产生了这个结果的一部分(在我们的例子中是技术),但有时结构并没有像预期的那样做。
作为一名独立专家,你不会与工资单上符合该职能的受雇数据科学家竞争。那你为什么一直做和他们一样的事?
这就是使用外部帮助的地方,提供资金、关系、专业知识或任何其他资源来实现结果。在这里,你作为独立专家可以介入提高数字,因为系统不能。而一个体制内的被雇佣者和独立专家的区别在于工作的侧重点:两者都可以写代码,但是第一个向直接经理汇报通过 CI/CD 测试,18:00 离职,第二个向所有者汇报收入的增长,并对其负责。你想成为哪一个?你现在在做什么?
改变你的心态

图片来自http://think apps . com/blog/post-launch/how-start-startup-competition-losers/
听起来很吓人,对吧?如果你只是一个技术专家,你如何承诺业务增长?有三种典型的心理障碍会导致你和客户都不满意的结果:
- “我不够好”。如果你用 FAANG 的标准来比较自己,他们有从 1 到 10 的等级——也许吧。但是,只有当你的目标是有一份稳定的工资单,并且是系统中的一个功能时,这才重要。从技术角度来看,你实际上可以为 4/10 的客户提供更多价值,但与拥有 10/10 的技术技能、4/10 的业务知识和 4/10 的独特性的人相比,你了解 10/10 的客户业务并拥有 10/10 的独特价值主张。

插图来自https://libraryofconcepts . WordPress . com/2017/10/29/当今人类发展的三个最相关阶段-kegan-13/ 。雇员通常坐在“社会化思维”的队列中,自雇者是“自我创作”,企业家是“自我改造”。这个例子显示了思维上的差异:雇员希望符合群体规范,个体户希望与众不同,企业家了解他们所有人并把他们联系起来
- “不敢多问”。忘掉金钱谈判中的情绪——这完全是关于投资回报的。如果你能在一个月内为你的客户赚到 100,000 美元,对客户来说要价 20,000 美元是一笔划算的交易:5 倍的投资!谁在乎在你的国家一个数据科学家的月薪是 3000 美元——他们满足于做一个功能,你决定提供结果!

来自https://www.consultingsuccess.com/consulting-fees的插图显示,当然还有其他更经典的顾问收费财务模型,但我强烈建议你成为“基于价值和投资回报率”的那一组。这是顶级的!
- “我会失去我现在所拥有的”。最常见也是最不相关的拦截器。如果你在做你喜欢的事情,并且做得很好,你可以每周工作 10-20 小时来取得成果。没有必要为了成为独立专家而辞职。法律上这也是不被禁止的(但是检查你的合同和当地法律)。你有晚上和周末的时间和新客户一起工作,之后,你可以决定哪种生活方式更适合你和你最亲近的人。
你是否已经看到你需要关注什么了?是网上全新的 ML 课程还是别的?让我知道:)
改变你的战略和战术
满足于你擅长的事情
有不同的技巧可以帮助你理解自己独特的竞争优势(通常被无耻地宣传为有目的的探索):

来自https://zek luu . com/en/self-development-iki Gai-El-sentido-de-la-vida/的插图显示,为了避免竞争并建立一个独特的、独立于其他技能和业务的平台,你需要在你的才能(你所热爱的)、你所训练的技能、经济价值和世界的要求的交叉点上努力
简而言之,你应该利用你的才能(而不是社会教条行为)在一个高薪且有影响力的专业领域使用你擅长的技能(再次强调,而不是被认为很酷的东西(而不是在别人告诉你的地方工作)。关于这个话题,我写了一整篇文章,请大家看看:
https://medium.com/@alexrachnog/from-developer-to-entrepreneur-what-is-your-way-up-497fd5512b9c
利用你的网络
这仍然是获得好客户的最简单的方法,几乎没有人使用这种方法,因为“这很酷”,而不是与你已经认识的人建立关系。你的家人、学校和大学的同学、老师、同事和老板、邻居和熟人——他们都认识认识其他人的人。开始对他们的生活感兴趣,帮助他们,告诉他们你的新的独特主张。如果你做的事情明显是你(为他人)擅长的,并且是受欢迎的和有影响力的领域,你会更快地得到你的项目,并且会和欣赏它并信任你的人一起做完全适合你的事情。
公开展示你的专业技能
我知道你的关系网可能是有限的,或者不包括你想工作的地区的人。怎么去?开始对网上陌生人有用!正如我们所商定的,你在人才、技能和业务领域的独特交汇处工作,因此开始帮助他人回答专业社区中的问题,参与讨论和在线会议,分析行业新闻,展示见解和案例研究。Hubspot 的销售之王也同意这一点(查看“权威消息”):
https://blog.hubspot.com/marketing/using-content-marketing-professional-services
在媒体上积极主动(选择你喜欢的一个),你的网络会爆炸。
衡量你自己和你的努力
作为一名数据科学家,你明白,如果你根据垃圾数据进行建模和决策,结果将会是这样。衡量你的财务(甚至用 Excel),你的工作努力(用 Toggle 之类的东西),你的内容的参与度,作为一个最小的活动集。我建议将客观的关键结果作为设定目标和衡量后续进展的方法:
https://rework.withgoogle.com/guides/set-goals-with-okrs/steps/introduction/
现在你是一家单人企业,所以你集所有关键“角色”于一身:首席执行官、首席财务官、首席技术官、CMO。你在这些方向上所做的一切都必须被定期跟踪和反思,以便改进。
承担责任并寻求反馈
现在我们开始讨论你需要学习什么,而不是技术指南。问问你的客户哪些事情进展顺利,哪些事情不太规律,并专注于此!你的成功将只取决于你所帮助的人的满意度,这通常表现为节省或赢得的时间、金钱、健康、信息、关系和机会。对这些结果负责并关注它们,而不是你写的代码,你会发现你真正需要学习的包括:
- 业务模式和流程:因为你需要衡量你对客户业务的影响
- 销售和营销:因为你需要推销你独特的专业知识
- 沟通与谈判:因为你需要了解你的客户,建立双赢的关系
稍后,你会意识到所有的编码部分都可以由其他人来完成,这些人实际上只专注于此并彻底地阅读每一篇“202x 数据科学指南”,但这是另一篇博文的故事:)
结论
事实上,我这里有一个稍微长一点的演示,包含了一点更广泛的经济学和社会学观点,但是它的要点你已经在这篇文章中读到了:
我希望这篇文章可以向您展示,对于独立/自由职业的数据科学专家来说,技术技能、热门课程和书籍是很好的选择,但对于希望在公司内部建立职业生涯的人来说,这些并不重要。你可以用线性回归做更多的影响,知道在哪里应用它,而不是做非常复杂的事情,最终可能被遗忘。你可以选择自己的生活方式和人际关系。
我想再次提醒你下周俱乐部会所的谈话。我们人不多,团结互助吧:)
https://www.joinclubhouse.com/event/Md0N42wq
附言
如果你觉得这个内容有用,有观点,可以在 Bitclout 上支持我。你也可以在脸书博客或 LinkedIn 上与我联系,在那里我会定期发布一些对媒体来说太短的人工智能文章或新闻,并在 Instagram 上发布一些更私人的内容。如果你期待成为一名人工智能企业家并解决具有挑战性的问题,ping 神经元实验室,我们正在与顶级人工智能自由职业者合作:)
自由职业、自学和明智选择项目的重要性
作者聚焦
数据科学是不是该“分手”了?
在 Author Spotlight 系列中,TDS 编辑与我们社区的成员谈论他们在数据科学领域的职业道路、他们的写作以及他们的灵感来源。今天,我们很高兴与 Kurtis Pykes 进行对话。

照片由 Kurtis Pykes 提供
Kurtis 是一名前邮递员转行的博客写手和数据科学家,对自然语言处理(NLP)有浓厚的兴趣。他目前是 Upwork 的自由职业者,涵盖从技术写作到各种 NLP 任务的项目。Kurtis 是一位多产的 TDS 贡献者,热衷于利用机器学习和数据科学的力量来帮助人们变得更有生产力和效率。
是什么让你考虑将数据科学作为职业?
我是一名邮递员。我讨厌我的工作,但我不得不做它来资助我读完大学。每当我在岗位上走动时,我都会听一些我崇拜的人的采访。有一天,我碰巧在听比尔·盖茨的采访,听众中有人问他,如果他没有创建微软,他会做什么。他回答说“我会用自然语言数据来测试极限”,他会成为一名人工智能研究员。请注意,这是我第一次听说这些事情,所以我回去做了一些研究。
浏览了一段时间后,我总结道:“是的,不适合我。不够聪明。”然后,大约一个星期后,我的雇主告诉我,我是“多余的要求。”既然是代理工作,就意味着立即生效。我很沮丧,我就这样被解雇了。我对自己发誓要获得一项不需要体力劳动的技能,这样我就能经得起未来的考验。当时唯一能想到的就是比尔盖茨访谈,于是买了几本书开始学习。剩下的就是历史了。
自学和从零开始建立职业道路听起来令人生畏!一路走来,你学到的最重要的一课是什么?
在休假了大约六个月后,我决定做一些公益工作,为我的简历积累一些经验,以应对最糟糕的情况——被裁员。与此同时,我知道请求我服务的人正在招聘,但预算有限,所以我想如果我给他们留下深刻印象,我就有可能确保我的未来。
当我接到任务时,我不明白目标是什么,但我真的想展示我有一点点聪明。史上最糟糕的选择。进展不顺利。一个月后,给我这份工作的人建议我去学校接受更多的教育——这是这么长时间以来我的自尊心受到的最大伤害。作为回应,我开始在独立项目上严格工作,特别是在一个类似于我在公司被设定的任务的项目上。
我向任何想进入数据相关领域的人提出这个建议,确保你做的是项目。现在,作为一名自由职业者,我尽我所能去了解客户的确切目标是什么,他们希望如何实现这些目标,以及他们希望的时间框架。我不会留下任何怀疑的余地。
一旦你进入了新的工作领域,是什么激励你开始为广大读者写这方面的文章?
我的第一份技术工作的直线经理建议我写下我所学到的一切,因为这有助于我理清思路。我听从了他的建议,尝试了一下。起初保持一致非常困难,但后来我开始看到一些进步。人们在 LinkedIn 上联系我,告诉我他们多么感谢我的文章。那种感觉——知道我在帮助别人——真的引起了我的共鸣,所以从那时起,我决定为我正在做的工作承担更多的责任。我相信这是博客最棒的部分。
你经常写的话题之一是作为数据科学自由职业者的生活。你是如何成为其中一员的,你最喜欢它的什么?
自由职业对我来说是偶然发生的。我从来没有打算成为一名自由职业者,但自从这件事发生后,我觉得自己好像更加享受生活了。我是那些被规章制度束缚时感到窒息的人之一,当你从事全职工作时,这种情况有时会发生。因此,作为成为自由职业者的结果,我能够享受的自由对我来说是非常令人耳目一新的——我更喜欢这样的想法:“我不必做这件事,但我会做,因为我想做。”
如果有人在考虑做自由职业者,我建议你做好准备,维持至少六个月的生活(当然,如果你像我一样陷入困境,那么你真的别无选择)。此外,一定要确保你的营销方式能吸引你想要的客户,否则你会得到一堆随机的工作建议。例如,当我第一次创业时,我收到了很多创业公司的技术写作职位的邀请,而我脑海中一直浮现的都是,“Hellooo!我其实也是一名数据科学家。”
我意识到我并没有真正向人们展示我的技术能力或者我是如何解决特定任务的。现在我已经开始多做一点了,慢慢地但肯定地,潮流开始转变了。
从你的角度来看,你希望在数据科学社区看到什么变化?
我很乐意看到社区里更多的人专攻。数据科学中有太多需要学习的东西,对于一个试图进行职业转型的新人来说,这可能会让人不知所措。如果你决定专攻某一领域,还有很多东西要学,但不同的是你可以有一个固定的焦点,这将使技能的获得成为一个更加无缝的过程。
更广泛、更有结构性的发展呢?
听起来很疯狂,我希望看到数据科学被打破。术语“数据科学”涵盖了广泛的任务,因此特定公司对一个角色的要求不一定会转化为另一个。这使得从业者的工作转变更加困难。我相信在数据科学的保护伞下拥有预定义的任务将会产生具有更合理要求的工作规范。
想了解更多关于 Kurtis 的工作和数据科学的兴趣吗?你可以在 NLP、自由职业者网站上找到他的文章,以及更多关于和他的媒体简介的文章。以下是我们最近最喜欢的一些。
- 为什么我停止申请数据科学工作 ( TDS ,2021 年 4 月)
Kurtis 的最新病毒式帖子详细介绍了他成为自由职业者的道路,特别是关于建立投资组合和声誉,以健康的速度产生入站查询。 - 作为一名远程数据科学家蒸蒸日上 ( TDS ,2020 年 12 月)
即使疫情已经在我们身后(但愿有一天!),远程工作是要留在这里的,最好是越早越好。 - 如何撰写 Upwork 求职信,赢得合同 ( 数据驱动投资者,2021 年 2 月)
像 Upwork 这样的自由职业者平台竞争非常激烈,因此优化你个人资料的每个细节至关重要——在这篇文章中,Kurtis 将重点放在永远重要的求职信上。 - 克服数据科学骗子综合症的 5 种方法 ( TDS ,2020 年 11 月)
无论教育水平或工作经验如何,数据科学作为一个领域的广阔性意味着掌握其中的任何领域都是一项重大事业,并可能导致信心的丧失。在这篇文章中,Kurtis 分享了他作为一名自学成才的数据科学家所学到的经验。
请继续关注我们的下一位特色作者,即将推出!如果你对你想在这个空间看到的人有建议,请在评论中给我们留言!
频繁模式挖掘、关联和相关性
利用 Apriori 算法识别数据集的频繁模式并通过 Weka 软件关联数据集

马文·迈耶在 Unsplash 上的照片
在数据挖掘中,频繁模式挖掘是一个主要关注点,因为它在关联和相关性中起着重要作用。首先要知道什么是频繁模式?
频繁模式是在数据集中频繁出现的模式。通过识别频繁模式,我们可以一起观察强相关的项目,并容易地识别它们之间的相似特征和关联。通过进行频繁的模式挖掘,它导致进一步的分析,如聚类、分类和其他数据挖掘任务。
在开始挖掘频繁模式之前,我们应该关注“支持度”和“置信度”这两个术语,因为它们可以提供一种衡量关联规则对于特定数据集是否合格的方法。
支持:给定规则在被挖掘的数据库中出现的频率
置信度:给定规则在实践中被证明为真的次数
让我们通过一个样本数据集来练习一下;

作者图片

支持计算-按作者分类的图像

可信度计算-按作者排序的图像
示例:一个可能的关联规则是 A => D
交易总数(N) = 5
Frequency(A,D)= > A 和 D 的实例总数为 3
频率(A)= > A 中出现的总次数
支持= 3 / 5
信心= 3 / 4
在对支持度和置信度这两个术语有了清晰的概念之后,我们可以转向频繁模式挖掘。频繁模式挖掘,有两类要考虑,
- 利用候选生成挖掘频繁模式
- 无候选生成的频繁模式挖掘
本文主要研究利用关联挖掘中常用的 Apriori 算法挖掘频繁模式并生成候选模式。让我们用一个例子来理解 Apriori 算法,它将帮助你清楚地理解它背后的概念。让我们考虑上面提到的样本数据集,假设最小支持度=2 。
- 生成候选集 1,进行第一次扫描,生成一个项目集
在这一阶段,我们获得样本数据集,并对每个个体进行计数,得到频繁项集 1(K = 1)。

候选集 1
“候选集 1”图显示了单个项目的支持计数。因此,最小支持度是 2,并且基于此,项目 E 将作为不频繁项目(不合格)从候选集合 1 中移除。

第一次扫描的频繁项目集
基于最小支持值的频繁项集将在图“第一次扫描的频繁项集”下显示为“一项集”。
2。生成候选集 2,进行第二次扫描并生成第二个项目集
通过这一步,您创建了频繁集 2 (K =2 ),并获得了它们的每个支持计数。

候选集 2
“候选集 2”图形通过连接候选集 1 生成,并取相关出现的频率。因此最小支持度是 2,项目集 B,D 将作为非频繁项目集从候选集 2 中移除。

第二次扫描的频繁项目集
“第二次扫描的频繁项目集”是基于最小支持值的频繁项目集,它将生成“第二个项目集”。
3。生成候选集 3,进行第三次扫描并生成第三个项目集
在这个迭代中,创建频繁集 3 (K = 3)并计算支持度。然后与来自候选集合 3 的最小支持值进行比较。

候选集 3
如您所见,我们将候选集 3 与生成的第三个项目集的最小支持值进行了比较。第三次扫描的频繁集与上述相同。
4。生成候选集 4,进行第四次扫描并生成第四个项目集
通过考虑频繁集,我们可以通过连接候选集 3 来生成候选集 4。那么可能的候选集合 4 是;最小支持度小于 2 的[A,B,C,D]。因此我们必须从这里停止计算,因为我们不能再进行迭代了。因此,对于上述数据集,频繁模式是【A,B,C】和【A,C,D】。
通过考虑频繁集之一为{A,B,C}和如下可能的关联规则;
- A => B,C
- a,B => C
- a,C => B
- B => A,C
- b,C => A
- C => A,B
然后我们假设最小置信度= 50%,并计算每个可能关联规则的置信度,然后我们可以识别最小置信度小于 50%的不合格关联规则。那么剩下的置信度大于或等于 50%的关联规则就是合格规则。

作者图片
正如你在 Apriori 算法中看到的,每一步它都在生成候选项,当候选项列表变大时,它会花费很多时间。
下面是 Apriori 算法的伪代码;

图片来自关于用于优化数据挖掘过程的算法的研究问题 (2010)
现在让我们关注如何使用 Weka 进行关联。您可以遵循以下步骤。
- 打开 Weka 软件,点击“探索”按钮。

Weka 初始图形用户界面—作者图片
点击“浏览器”按钮后,你会看到一个名为“Weka 浏览器”的新窗口。

Weka Explorer —作者图片
2.打开首选数据集
Weka Explorer > Preprocess > Open File
按照上面的顺序,您可以通过选择一个内置数据集或任何想要应用于 Apriori 算法的数据集来加载数据集。
打开选定的文件后,您可以在预处理选项卡下看到属性和其他统计信息。然后,您可以单击“编辑”按钮,在查看器中打开当前数据集进行编辑。

预处理选项卡中的编辑按钮—按作者排序的图像
需要注意的是,您的数据集包括数值数据,您可以使用“预处理”选项卡下名为“离散化”的过滤器将其离散化
3.转到“关联”选项卡,使用“选择”按钮选择“先验”。

选择 Apriori 算法—作者图片
4.左键点击先验并选择“显示属性”

显示属性-按作者显示图像
5.自定义算法属性,然后点击“保存”

配置算法属性-按作者排列的图像
例如,在关联完成后,我们可以更改您从数据集中获得的规则数量。
6.点击“开始”按钮

作者图片
T4:请注意,如果没有选择进行关联的离散数据,则不能启用“开始”按钮,这一点很重要
7.观察结果
Associator 输出如下,在这种情况下,算法已经为所提供的数据集找到了 10 个最佳规则。

应用关联后的最终结果—图片由作者提供
结论
这篇文章提供了一些你可能知道的关于频繁模式挖掘、Apriori 算法、支持度、置信度以及如何通过 Weka 软件进行关联的事实。希望这篇文章能帮助你提高对上述几点的认识。
感谢您的阅读🤗!!!!!
参考
[1]扬·伦古,亚历山大·皮尔詹,关于用于优化数据挖掘过程的算法的研究问题 (2010)
Frequentist A/B 测试说明
本文将解释 A/B 测试的 frequentist 方法,并提供一个何时以及如何使用它的示例代码

A/B 测试通常用于所有行业,以在业务的不同方面做出决策。从撰写电子邮件,到选择登录页面,实施特定的功能设计,A/B 测试可用于根据统计分析做出最佳决策。本文将涵盖 A/B 测试的 frequentist 方法的基础,并概述如何通过 A/B 测试得出决策的示例。我还将为一个特定的示例提供代码的相关 Python 实现。
目录
- 什么是 A/B 测试
- 频率主义方法
-零&替代假设
-样本均值估计
-置信区间
-检验统计量- P 值
- 例子
- 结束语
- 资源
什么是 A/B 测试
推断统计学通常用于根据对总体样本的观察来推断总体的某些情况。A/B 测试是推理统计学在研究用户体验中的应用。它由 A 和 B 两个变量的随机实验组成[1]。一般来说,通过测试每个变体的用户响应,可以找到统计证据证明一个变体比另一个更好,或者你可以得出结论,选择 1 而不是另一个没有统计学意义。一个公司必须进行 A/B 测试的常见应用将是做出决定来提高他们的用户的转化率,提高他们的产品的适销性,增加他们的日常活跃用户,等等。
频繁主义方法
这是更传统的统计推断方法,通常在大学的基础统计学课程中介绍。这种方法的简单概述可以是以下方式。
- 确定无效假设和替代假设
- 无效假设:指定人群之间没有显著差异,任何观察到的差异都是由于采样或实验误差造成的。
- 替代假设:与原假设相反的假设
- 计算样本量以达到统计显著性(通常为 95%)
- 计算测试统计数据,并将其映射到 p 值
- 根据 p 值是否小于/大于 p 临界值,接受或拒绝零假设
无效&替代假设
确定要测试的假设通常是通过你给定问题的领域知识。零假设通常是关于被认为是真实的总体的陈述。替代假设是与原假设相反的陈述。一个简单的例子可以概括在下面的场景中;你想通过增加一个独特的功能来提高用户访问你网站的转化率。无效假设是,在网站上添加这一独特的功能不会对转化率产生影响。另一个假设是,添加这个新功能会影响转化率。
样本均值估计值
一组观察值的样本均值估计实质上是总体均值的估计[2]。它可以用下面的公式表示:

其中 N 代表样本中的项目总数,xi 代表事件发生的次数(图片由西瓦·加比【3】提供)
在理想情况下,我们希望方差(A 和 B)的样本均值估计值之间的差值较高。两者之间的差异越大,表明测试统计数据之间的差距越大,这意味着变量之间会有明显的赢家。
置信区间
置信区间是这样定义的值的范围,使得参数值有一个特定的概率位于其中。它可以用下面的公式来概括:

u 代表样本均值估计值,t 是置信水平值,sigma 是样本标准差,N 是样本大小(图片由 Siva Gabbi 提供【3】)
测试统计
检验统计量是正态分布上的一个点值,它显示了检验统计量与平均值的差距(以标准偏差的数量表示)。基于样本大小和其他因素,有各种各样的检验统计公式。下图中可以看到该公式的一些变体。

图片来自克里斯塔·金【6】
根据测试统计产生的值,可以将测试统计映射到 p 值,并根据 p 值是高于还是低于 p 临界值来接受或拒绝假设。
P 值
在统计学中,p-值是零假设(被测试的理论是错误的)给出的特定实验结果发生的概率。p——值也叫概率值。如果p-值很低,零假设不太可能,并且该实验作为不同理论的证据具有统计学意义[4]。在许多领域,一个实验必须有一个小于 0.05 的p-值,才能被认为是替代假设的证据。简而言之,低 p 值意味着零假设为假的可能性更大。如上所述,一旦确定了 p 值,解释结果就相当简单了。
例子
一家大型银行的抵押贷款部门对首次借款者的贷款性质感兴趣。这些信息将用于定制他们的营销策略[5]。他们认为,50%的首次借款人会比其他借款人获得更少的贷款。他们进行假设检验,以确定该百分比是否与 50%相同或不同。他们对 100 名首次借款人进行了抽样调查,发现其中 53 笔贷款的规模小于其他借款人。对于假设检验,他们选择 5%的显著性水平。
零假设 : p = 0.5
备选假设 : p!= 0.5
这将作为双尾测试运行。
假设我们的显著性水平是 5%,并且这是一个双尾检验,我们的置信区间将是 1–0.05/2 = 0.975。通过运行上面的代码,您将得到 p 临界值 1.96
根据上面的代码,我们注意到测试统计量是 0.6。这仅仅是零的标准正态分布的平均值。就标准差而言,样本比例和假设比例实际上没有区别。
检验统计量在临界值内,因此我们不能拒绝零假设。这意味着,在 95%的显著性水平上,我们不能拒绝零假设,即 50%的首次借款人拥有与其他借款人相同规模的贷款
结束语
总之,A/B 测试的频率主义方法用于根据结果的统计显著性做出有利于两个变量 A 或 B 之一的决定。这是通过识别与测试相关的无效和替代假设、识别样本大小和计算某个置信区间的测试统计来完成的。一旦获得了检验统计量,我们就可以确定 P 值,并得出我们是接受还是拒绝零假设的结论。
资源
- [1]https://en.wikipedia.org/wiki/A/B_testing
- [2]http://www . stat . Yale . edu/Courses/1997-98/101/samp Mn . htm #:~:text = The % 20 sample %20mean%20 from % 20a,estimate % 20of % 20the %人口% 20 mean % 20。&text = For % 20 example % 2C % 20 假设%20the%20random,(70%2C5))。.)
- [3]https://www . dynamic field . com/lesson/frequentists-approach-to-ab-testing/
- [4]https://simple.wikipedia.org/wiki/P-value
- [5]https://opentextbc . ca/introbusinessstatopenstax/chapter/full-hypothesis-test-examples/
- [6]https://www . kristakingmath . com/blog/test-statistics-for-means-and-proportions
如果你喜欢读这篇文章,下面是我写的一些你可能也会喜欢的文章:
[## 贝叶斯 A/B 测试解释
towardsdatascience.com](/bayesian-a-b-testing-explained-344a6df88c1a)
频繁主义者和贝叶斯推理
统计在不同的情况下有不同的用途。例如,描述统计学是一个分支,处理汇总现有的数据样本。描述统计学处理的是样本本身——不需要任何推断。然而,在现实世界中,我们必须经常解决的一个更具挑战性的问题是使用样本来推断样本所来自的人群的一些情况。例如,假设您掷骰子 10 次,并看到以下结果:
4 5 2 6 1 5 6 5 3 1
描述性统计可以告诉你,被滚过三次,5 就是你的样本的“众数”。但这可能还不够。我们可能会问这样一个问题“这是一个公平的死亡吗?”试着根据我们看到的滚动骰子有限次的例子来回答这个问题。回答这类问题是推理统计学的工作。
然而,推理统计学有两个对立的分支,试图使用不同的假设、理论基础和某种程度上的哲学信念来回答这些问题:频率主义统计学和贝叶斯统计学。这篇文章旨在解释这两个分支,以及这两个分支之间争论的主要来源。
频繁推理
频率主义统计学主要是在 20 世纪发展起来的,并逐渐成为当时占主导地位的统计范式。直到今天,它仍然是科学文献中使用的更流行的方法——我在我的上一篇文章中描述的概念,如 p 值和置信区间属于频率主义范式。
其核心是,frequentist 统计是关于可重复性和收集更多的数据。概率的频率主义解释是可重复实验的长期频率。例如,假设一枚硬币正面落地的概率为 0.5,这意味着如果我们抛硬币足够多次,我们将有 50%的机会看到正面。
根据这个定义,你不能真正定义不可重复事件的概率。例如,在 2018 年国际足联世界杯之前,假设你在某处读到巴西赢得比赛的概率是 14%。这个概率真的不能用纯粹的频率主义者的解释来解释,因为实验是不可重复的!2018 年世界杯只会发生一次,不可能在完全相同的条件、球员和之前的事件下重复完全相同的实验。
根据 frequentist 推论,我们得出的概率估计中的任何不确定性都被认为是由于抽样误差造成的,即实际人口和最终抽取的样本之间的差异。所以对于常客来说,大样本解决了大多数问题,因为你的样本变得更接近真实的人口分布。
值得注意的是,常客们不相信被估计的参数有任何潜在的概率分布。例如,如果你试图估计一枚硬币正面朝上的概率,这个参数是一个固定的常数,我们不知道,但它不是固有的概率。我们只是不能确定它的价值,因为我们在处理一个样本,而不是人口本身。
置信区间是一个频率主义者的概念,似乎与这一观点相矛盾。例如,我们可以说硬币 p(H)的正面概率由一些特定值以 95%的概率限制:
L < p(H) < U,其中 L 和 U 取决于样本
这种情况下 p(H)不是概率性的吗?实际上并非如此——p(H)是固定且未知的,随机变量实际上是 L 和 U 的边界。L 和 U 是根据您绘制的样本计算的,因此这只是说,如果您不断绘制样本并每次都计算 L 和 U,则真实、固定、未知的参数在 95%的时间内都在这些边界内。并没有说 p(H)本身是概率性的!
现在,在上个世纪的大部分时间里,p 值和置信区间已经形成了跨越大多数学科的科学过程的支柱。然而,频率主义推理的一个关键问题是缺乏上下文和对抽取样本的完全依赖。正如我在以前的帖子中提到的,盲目使用 p 值会导致一系列问题,尤其是大量的“假阳性”——这些结果似乎是统计上的显著影响,但实际上并不是。但是我们如何将“语境”带入推理的问题中呢?这就是贝叶斯统计的用武之地。
贝叶斯推理
“贝叶斯推理”这个名字来自贝叶斯定理,而贝叶斯定理又是以 18 世纪英国统计学家托马斯·贝叶斯的名字命名的。事实上,大约在同一时期,贝叶斯定理背后的关键思想也被法国学者皮埃尔·西蒙·拉普拉斯独立使用。贝叶斯和拉普拉斯是非常不同的人——贝叶斯是长老会的牧师,而拉普拉斯现在被认为是不可知论者或无神论者。然而,他们都同意一个关键点——世界是完美的和确定的。
对这一观点最好的说明是著名的思想实验,被称为拉普拉斯的恶魔。这个想法是,如果有一个全知的实体知道宇宙中每一个粒子的位置和速度,它就能够知道过去发生的一切和未来将要发生的一切,只需要使用经典力学的定律(并且大概使用足够的计算能力)。这个恶魔是科学决定论的一个例子。
现在,这可能看起来和概率本身的概念有点不一致。如果这个世界是确定性的,那么我们得出的不确定性和概率性估计在哪里呢?对贝叶斯和拉普拉斯来说,概率更多的是由于我们对世界的不完善的知识,而不是世界本身的任何潜在的不确定性。所以在贝叶斯的世界观里,概率本质上代表了我们对某件事的相信程度,这大概更接近大多数人对概率的直观想法。
所以让我们来看看它的核心。假设你想评估一个假设 H,基于你在实验中采集的一些数据 D。贝叶斯定理的公式表述为:
P(H|D) = P(D|H)*P(H) / P(D)
P(D)是一种归一化常数,虽然有很多关于计算它的有趣想法,但这不是本文的重点。让我们看看其他的术语。
P(H|D) ~ P(D|H)*P(H)
P(H|D)是你想计算的概率,叫做后验概率。这是假设为真的条件概率,假设你看到了这个特定的数据。
P(D|H)被称为可能性,是假设假设为真,你得到这些数据的概率。这个术语实际上是我们在一个常客设置中唯一感兴趣的术语。如果假设为真,P 值被计算为观察数据至少达到这一极限的概率,其计算方式类似于 P(D|H)的计算方式。
贝叶斯定理的一个重要元素是 P(H)项——先验,这是贝叶斯主义者和频率主义者之间争论的主要来源。这是在我们看到数据之前,我们赋予假设为真的概率。这可能是一个难以理解的概念,这是有充分理由的。假设的概率正是我们想要计算的,对吗?在看到数据之前,我们怎么知道它是什么?
这就是你把“背景”正式带入问题的地方。先验知识代表了你过去的知识和经验的组合,包括你或学术界以前可能进行的实验的任何结果。其核心是,贝叶斯定理是基于最新数据更新你的信念。使用贝叶斯定理计算后验概率 P(H|D)后,实际上可以在下一个实验中使用这个后验概率作为先验概率!所以你不断收集新数据,每次都更新你的信念,希望随着时间的推移,有了足够的数据,你会向真理靠拢。
然而,你可以理解为什么常客们反对这个想法。先验不会只是代表实验者的偏见吗?根据我们选择的先验,我们会得到不同的结果吗?这些都是有效的问题,但先验是贝叶斯推理的关键部分,选择一个好的先验本身就是一个完整的研究领域。我们将在下一节看一个先验的例子。
比较这两种方法
首先,让我们谈谈贝叶斯推理解决的频率主义方法的一些缺点。一个是假阳性的问题。考虑一个试图在 1000 人中检测一种罕见疾病的测试。这种疾病只发生在 1%的人口中,也就是说 10 个人。该测试本身相当准确——当一个人患有疾病时,它保证能检测出来,而当这个人没有疾病时,它有 99%的机会正确识别他们没有疾病。如果你对所有人进行这个测试,会发生什么?
对于 10 个患有这种疾病的人,它会正确地识别出这一点。对于没有患病的 990 人,它会正确地识别出其中 99%的人,但对于其中 1%的人(9.9,因此大约 10 人),它会将他们错误地分类为患有疾病。乍一看,这些似乎是合理的——测试做得很好,对吗?但是考虑一下这个。如果你做了测试,结果呈阳性,那么你真的患病的几率有多大?10 个人在实际患病时得到了阳性结果,但另外 10 个人在没有患病的情况下得到了阳性结果——所以阳性结果实际上意味着你患病的可能性只有大约 50%!尽管测试有 99%的准确率,但是哪里出错了呢?
这是检测人群中发病率低的任何东西的基本问题——频率主义者的推论不善于解释这种低发病率。在本例中,您可以用所有可能运行的实验来替换“人群”,用能产生具有科学意义的实际阳性结果的实验来替换“疾病”,用我们的标准 p 值/统计显著性测试框架来替换“测试”。真正的阳性结果可能很少,我们的统计显著性测试通常允许 5%的假阳性率(高于本例)。如果我们对前面的例子进行类似的分析,我们会再次得出这样的结论:也许许多发表的“有统计学意义的”科学研究只是假阳性。在一天结束的时候,频率主义者的推断在很大程度上只是给你一个二元的是/否,关于你的结果是否重要(尽管像置信区间这样的东西可以有所帮助)。如果你最终得到一个“是”,考虑到积极结果的罕见性,你的结果实际上有多大的可能性?频繁主义者的推论并没有试图回答这个问题。
现在,我们之前得出 50%的方法实际上是使用贝叶斯定理!换句话说,我们计算出:
P(疾病|阳性检测)= P(阳性检测|疾病)*P(疾病)/P(阳性检测)
之前的计算可能看起来非常直观,那是因为贝叶斯定理只是形式化了一个非常直观的想法。因此,贝叶斯推断可以通过考虑潜在发病率(这里是 P(疾病))较低的事实来帮助解释这些假阳性。频率主义者的推理并不试图计算像 P(疾病|阳性测试)这样的量,因为在频率主义者的概率定义中,你要么患有疾病,要么没有——这里不涉及“概率”。
一如既往,这个想法的一个最简单的表现是在 XKCD 漫画中捕捉到的:

来源: XKCD
这可能是一个极端的例子,但这触及了频繁主义者推理的潜在问题的核心。太阳自发爆炸的可能性很低,所以这两个骰子出现的可能性比太阳爆炸的可能性大得多。由于频率主义者的推断没有考虑太阳爆炸的可能性(唯一重要的数据是掷骰子),采取纯粹的频率主义方法可能会遇到这样的问题。虽然在这里很容易发现问题,但在科学研究这样的背景下,很难发现这可能发生在你的实验中。
因此贝叶斯推理更容易解释和推理,因为它帮助我们计算我们感兴趣的概率(频率主义者的推理并不试图计算)。然而,它也有自己的缺点,如前所述,这些缺点主要归结为先验的选择。
在这些先前的例子中,要么先验是清楚的(人群中疾病的发病率),要么我们知道它足够低而不重要(太阳爆炸的概率)。但是计算这个先验并不总是容易的。例如,在学术出版的情况下,获得正面结果的先验概率是多少?甚至很难定义这个数量意味着什么。
有时当很难找到一个好的先验时,我们可以使用所谓的“无信息”先验。例如,如果我们试图根据数据评估两个潜在的假设,但在观察数据之前我们不知道这两个假设的可能性有多大,我们可以给每个假设设定 50%的概率。乍一看,这似乎是合理的,但是尽管没有提供任何信息,这种先验知识实际上可能会以你可能没有意识到的方式影响你的计算。在疾病的例子中,如果你不知道潜在的疾病发生率,并决定使用一个不提供信息的先验,将你患或不患疾病的概率(50%)放在一起,你的结果将会大相径庭。
从根本上说,这就是贝叶斯推理的问题。先验被认为是编纂主观信念,但在一个严格的科学过程中,真的有主观信念的位置吗?如果我们能够使用贝叶斯推断说我们的假设为真的概率是 70%,而其他人用不同的先验进行了相同的研究,得出的概率是 40%,我们如何确定哪个结果是可信的?谁有“更好”的优先权?这些都是具有挑战性的问题,不一定有好的答案。因此,你的结果对先验选择的稳健性是贝叶斯方法的一个重要方面。
结论
我相信贝叶斯方法的部分吸引力在于它是一种非常基本的人类思维过程的正式表示。有一个预先存在的信念,然后根据新的数据更新这个信念的想法——有一些非常自然的东西。如果我们先前的信念非常坚定,我们可能不会改变我们的观点,不管数据有多么令人信服(就像太阳爆炸的例子)。但是,如果我们持观望态度,那么基于新数据更新我们的信念肯定能让我们更接近真相。我们可能不会通过每天计算先验和后验项来明确地应用贝叶斯定理,但我们确实在生活的许多方面在精神上使用它。这也是其结果在疾病例子中如此直观的部分原因。将此与频率主义推理中使用的 p 值进行比较——它们一点也不直观,我们看到采取严格的频率主义方法会导致麻烦。
与此同时,将这种主观性的概念引入科学过程似乎一开始就有一点缺陷,即使量化你的主观性是关键所在。如果我们为谁拥有正确的先验知识而争吵不休,科学怎么会进步呢?与此同时,如果科学中的再现性危机是由于不适当地应用频繁推理的思想而引起的,那么转换到不同的框架可能无助于解决所有的问题。如果你可以误用频繁主义推理来得到你想要的结果,你当然可以对贝叶斯推理做同样的事情。
这两种方法可能更适合不同的问题,并且有许多混合技术正在考虑中,它们结合了两种框架的最佳方面。所以没有正确的答案,就像大多数事情一样,如果有是1,那么它很可能在中间的某个地方。
参考
[1] 统计学中的频率主义和贝叶斯方法
[2] 频率主义者和贝叶斯推理的比较
[4] 贝叶斯 vs 频率主义者方法
常客 vs 贝叶斯统计
用 Python 进行参数估计的实用介绍
参数估计是统计推断、数据科学和机器学习工作流的关键组成部分。尽管这个主题可能很复杂,但我们还是用一些理论和代码介绍了比较两种方法的过程。

演职员表:https://unsplash.com/@cgbriggs19
无论是尚未发生的结果,还是我们尚无法一瞥的现实,我们都沉迷于了解未知。我们花费巨大的资源,希望对未来做出更准确的预测,并欣赏那些预测一贯正确的人。在过去的一个世纪里,新兴的统计推断领域已经为这些不可知的结果和关系提供了一个更强大的工具集。统计推断的目的是使用可观察的数据来推断一个随机变量 (RV)的性质。术语“随机”可能会引起混淆,它并不意味着一个变量完全随机地取值,而是它取不同的值,这些值是由潜在的概率分布决定的。
在这篇博文中,我们将使用一个最简单的 RVs,即抛硬币的结果,来理解推理的一个基本方面,即参数估计。虽然硬币是一个简单的 RV,因为它可以取两个值-正面或反面,但您可以考虑其他 RV,如骰子滚动(在 6 面骰子的情况下可以取 6 个值)或股票价格(理论上可以取任何正值)。
在统计推断中,我们希望了解 RVs 之间的关系,以便了解和预测我们周围的世界。控制不同 RVs 之间关系的实体称为参数,通常用希腊字母θ (theta)表示。我们可以用以下方式用数学方法写出这种关系:

y 是我们的因变量(或结果变量),X 是我们的独立变量(或预测变量)。θ是参数空间,包含所有决定 Y 和 x 之间关系的潜在值。
虽然一个参数的真实值根据定义是未知的,我们可以用它的近似值来工作。在这篇博文中,我们将探讨两种不同的方法。我们将从使用最大似然估计(MLE)的频率主义者(或经典方法)开始,然后我们将继续讨论贝叶斯框架。但在此之前,让我们简要讨论一下二项式分布,这是一种相对简单但却非常重要的分布,每个数据科学家都应该知道,以及如何通过编写 Python 代码来模拟它。
二项式分布
我们将围绕抛硬币的例子进行讨论(这是任何统计文本都必须的)。具体来说,我们感兴趣的是在一次给定的投掷中硬币正面朝上的概率。在这种情况下,我们抛硬币的结果是我们的 RV,它的值可以是 0(反面)或 1(正面)。
我们可以将单次抛硬币的结果表示为伯努利过程,这是一个有趣的术语,它表示 Y 是一个有两个潜在值的单个结果。形式上,我们有:

在这个上下文中, p 是硬币正面朝上的概率,这是我们感兴趣的参数。我们的任务将是尽可能精确地估计 p。
因此,我们有:

那么,给定一枚硬币,我们将如何估计 p ?我们可以只抛一次硬币,但这不会提供太多信息。想象一下,真相是 p=0.5 (硬币是公平的,有相等的概率翻转正面或反面),一次翻转后我们观察到一个正面。如果我们只依赖于那一次翻转,我们可能会得出 p=1,所以翻转头部的概率是 100%,我们会一直翻转头部,这听起来很可疑。
我们要做的是观察大量的翻转。当一个伯努利过程重复多次时,它被称为二项式过程。二项式过程建立在所有试验的假设之上,或者在我们的例子中是掷硬币,都是独立的——无论你现在掷的是正面还是反面,都不会对后面的迭代产生影响。
假设现在我们掷硬币 n 次。在这些 n 次投掷中,总的人头数 Y 是一个带有参数 n 和 p 的二项式随机变量。n 表示试掷或掷硬币的次数, p 表示成功的概率,或投掷人头的概率。最后,二项式分布的概率质量函数(PMF)给出了对于每一个 p 值,在 n 次试验中准确观察到 Y 个头的概率。
形式上,我们有:

既然我们对参数估计和将要使用的分布有了理论上的理解,我们就可以开始编码了。
模拟一些数据
现在让我们假设有人给了我们一个有 60%概率翻转正面的有偏硬币,但是我们不知道我们想自己估计这个概率。
我们可以使用scipy.stats库从二项式分布中得出结果。模拟是非常有用的,因为我们可以硬编码“真实”的参数,然后允许我们比较不同的框架在近似它方面的比较。
让我们模拟 10000 次抛硬币,观察一些结果。
import numpy as np
import scipy.stats as stats
from matplotlib import pyplot as pltnp.random.seed(42) # set seed for reproducibility# Set the probability of heads = 0.6
p = 0.6# Flip the Coin 10000 times and observe the results
n_trials = 10000data = stats.bernoulli.rvs(p, size = n_trials)# plot results
plt.hist(data);

10000 次抛硬币的直方图
sum(data)# 6108 coin flips out of 10000 are heads, since heads are coded as 1s and tails are coded as 0s
正如预期的那样,正面和反面的比例接近 60/40,在 10000 次掷硬币中有 6108 次是正面,这只是因为我们告诉虚拟硬币翻转器,硬币有 60%的机会是正面!
现在我们有了数据,让我们比较频率主义者和贝叶斯方法如何获得感兴趣的参数: p 。
频繁主义者的方法
频率统计使用最大似然估计(MLE)。虽然对极大似然估计的全面处理超出了这篇博文的范围,但它的工作就在它的名字里:它符合一个模型,这个模型最大化了观察到的观察数据的可能性。
对于二项分布,MLE 是成功的样本比例[1]。这仅仅意味着,在频率主义框架下,我们假设 p 的真实值是所有掷硬币中正面的数量:如果我们在 10 次掷硬币中有 6 次正面,那么我们认为 p 应该接近 6/10,或者 60%。

最大似然估计是成功的样本比例
在获得 p 的估计值后,下一步是量化该估计值的不确定性。记住,我们永远不知道它的真实价值,所以我们也必须量化它的全部潜在价值。这个范围称为置信区间,很容易计算出二项分布。首先,我们计算参数的标准误差,即其标准偏差乘以√N(样本大小)。然后,我们可以通过将标准误差乘以 95% Z-stat(等于 1.96)来找到我们的 95%置信区间。
总之,我们有:

捕捉二项分布的不确定性
让我们看看当我们投掷 10 枚硬币时会发生什么。在下图中,绿线表示 p 的“真实”值,我们在模拟数据时决定该值为 0.6。红色虚线表示最大似然估计,蓝色虚线表示置信区间,即 p 所在的可信值范围。

MLE 估计 10 次抛硬币
因为我们观察了 5 个头,MLE 是 0.5(回想一下 p 的真值是 0.6)。不确定性被置信区间捕获,置信区间表明 p 的真实值有 95%的概率在~ 0.2 和~ 0.8 之间。由于置信区间与样本大小成正比,我们可以预计它们会随着抛硬币次数的增加而缩小——我们拥有的数据越多,我们对自己的预测就越有信心。为了说明这一点,让我们看看当我们翻转越来越多的硬币时会发生什么。

随着 n 的增加,MLE 和 CI 估计值
在上面的图中,我们在 1 次翻转、10 次翻转、25 次翻转等多达 10,000 次翻转后拍摄结果的快照。这些图让我们了解了当我们掷硬币的次数越来越多时,我们的估计值以及我们对这些估计值的信心是如何变化的。
随着我们一遍又一遍地继续抛硬币,我们获得了越来越多的关于硬币性质的信息。因此,我们应该期待我们的估计会变得越来越精确,也越来越准确。当我们只抛硬币几次(比如 1 到 100 次)时,我们可以看到我们的置信区间相当宽。这是因为我们还没有看到足够的信息来排除头部的真实概率位于我们当前最大似然估计两侧的可能性。然而,随着我们继续抛硬币,观察到越来越多的关于我们感兴趣的参数的证据,我们看到我们的置信区间开始变窄并接近 MLE。当我们把硬币抛了 10,000 次后,我们的置信区间只是稍微偏向我们的最大似然估计。
让我们凭直觉思考这个问题:随着我们获得更多的证据,我们应该对我们的估计越来越有信心。此外,最重要的是,我们应该期待我们的估计越来越接近事实!这是大数定律:随着样本量的增加,其参数 estimand 越来越接近总体的真实值。我们将正面的真实概率设置为 0.6,这一点得到了证实,事实上,我们在翻转 1000 次后的最大似然估计为 0.61,并且在此之后不再波动(只是置信区间变窄)。
贝叶斯方法
本节素材——尤其是模拟代码,大量亏欠https://tinyheero . github . io/2017/03/08/how-to-Bayesian-infer-101 . html[2]。
回顾一下,贝叶斯定理通过将模型参数建立为基于我们观察到的数据的分布条件来估计模型参数。

贝叶斯定理
- P(θ)是我们模型参数的先验分布,它代表了我们在看到任何数据之前对结果和预测变量之间关系的看法。
- P(X|θ)是似然项,表示先验数据与观测数据的拟合程度。
- P(X)是预测变量的边际分布。换句话说,它代表观察到给定所有θ可能值的数据的概率。当处理离散分布时,P(X)可以通过对θ的所有值求和得到;在连续情况下,它是通过对θ积分得到的。
院长
贝叶斯工作流程的第一步是指定我们对结果变量的先验信念。对于这个例子来说,这意味着对我们关于抛硬币正面朝上的概率的信念进行编码:没错——我们把一个概率放在一个概率上。
上面的代码块创建了先验分布。首先,np.linspace函数创建 11 个介于 0 和 1 之间的值,间隔为 0.1。其次,我们硬编码了与先验分布中每个值相关的概率。随意使用不同的概率值——只要它们的总和为 1!

θ的先验:翻转头部的概率
先验分布概括了我们在没有看到任何数据的情况下对击中头部的概率的想法。为简单起见,我们将允许θ从 0 到 1 只取 10 个 0.1 增量的值。我们假设我们不知道硬币是有偏差的,也没有任何迹象表明它会有偏差。
因此,让我们建立一个峰值为 0.5,值为 0.2 的分布:我们说有 20%的机会硬币是公平的。我们也在考虑硬币可能不公平的可能性,这反映在θ从 0.1 到 0.9 的概率上。我们认为唯一不可能的情况是 p 等于 0(没有机会永远不摇头)或 1(没有机会永远不摇头)。
可能性
既然我们已经定义并编码了我们先前的信念,贝叶斯方法的下一步就是收集数据并将其纳入我们的估计。这一步与我们在 Frequentist 方法中所做的没有什么不同:我们将观察完全相同的数据,并再次使用似然函数来提取关于参数空间的信息。唯一的区别是,我们现在不仅仅是在 MLE 之后,或者我们在 Frequentist 方法中得出的点估计,我们需要参数空间中每个值的似然值。
可能性可能是一个难以理解的复杂概念,但它所做的基本上是返回一个数字,告诉我们某个值 p 符合数据的程度。一组 p 的高似然值意味着它们“适合”数据,反之亦然。我们基本上是在问:对于任何给定的 p,我们能确信它确实产生了我们所见证的数据吗?
二项式可能性的等式是其概率质量函数(PMF) [3]。

二项式似然函数
让我们解开上面的等式。我们说:给定 n 次投掷和 y 次投掷,与 p 相关的可能性是多少?对于θ中的每个 p 值,似然性评估该 p 值的概率。举个例子,如果我们观察到 1 个头像,那么 p= 0 的可能性一定是 0——因为我们观察到至少 1 个头像,那么永远不会翻转头像的可能性一定是 0。另一个例子,虽然不太可能(看我在那里做了什么?)将见证 10 次翻转中有 10 次正面朝上。在这种情况下,可能性将测量值 p = 1 是极有可能的,并且很可能分配它接近 100%的概率。
现在让我们计算可能性,并将其可视化。我们将保留前一个示例中的前 10 个数据点,因此 10 次翻转中有 5 次是正面。

观察 10 次抛硬币中 5 次正面的可能性
您会注意到,可能性在 0.5 左右达到峰值,离它越远,值就越小。这是有道理的:这种可能性用数据更新了我们之前对θ的信念,数据显示,10 次翻转中有 5 次是正面——根据我们观察到的数据,θ最有可能的真实值是 0.5。因此,0.5 将获得最高的可能性。反之亦然,像 0.1 和 0.9 这样的值不太可能是真实值,我们看到图表中相应地反映了这一点。反过来,极端值没有得到数据的证实,因此给出了非常小的似然值。
然而,需要注意的是可能性不是有效的概率分布。你可以自己检查一下,把θ的所有概率加起来,结果不等于 1!这就是归一化常数/分母的用武之地:将每个可能性概率除以归一化常数(它是一个标量)得到一个有效的概率分布,我们称之为后验概率。
后验分布
现在我们已经计算了似然值,我们通过将它们与先前的值相乘来获得贝叶斯定理的分子,这产生了θ和 x 的联合分布。反过来,分母通过对所得向量求和来获得(忽略θ)。
您可能已经看到,分母常常使贝叶斯推理在计算上难以处理。后面的博客文章将解释为什么会这样,但是对于这个场景,我们的优势是使用离散的参数空间(求和比积分容易),并且只取 10 个值,所以计算分母是完全可行的。
在下一篇博文中,我们将讨论当我们使用连续发行版时会发生什么。现在,请注意我们推导 X 的边际分布的能力是可能的,因为我们使用的是一个变量,而这个变量只有很少(11)个值。这使得对参数空间中的所有值求和变得容易,而如果我们处理的是可能有数千个(或无限个)预测值的多个预测值,情况就不一样了!如在连续的情况下)值的数量。

后验分布是可能性和先验之间的折衷
那么后验分布是怎样的呢?它反映了我们对我们感兴趣的参数的信念,包含了我们可以获得的所有信息。它是两个部分的产物:我们对θ的先验信念,以及反映我们从观测数据中获得的信息的可能性或证据。结合这两部分,我们得到了我们感兴趣的参数的概率分布。这是区分贝叶斯和频率主义方法的关键。在 frequentist 方法论中,我们的答案以点估计的形式表示(有一个置信区间)。然而,在贝叶斯方法中,我们的答案以概率分布的形式表达,允许我们对每个潜在的 p 正确的概率进行赋值。
在上面的例子中,在观察了 10 个翻转和 5 个头部之后,我们的先验分布已经被向θ= 0.5 的可能性挤压,这似乎越来越成为最有可能的答案。但是,我们还没有看到足够的信息来排除θ位于 0.5 一侧某处的可能性,所以我们将继续观察更多的数据。类似于我们在 frequentist 讨论中所做的,让我们看看当我们看到越来越多的数据时,我们的贝叶斯结论是如何变化的。
把所有的放在一起
现在让我们看看在贝叶斯框架下,随着抛硬币次数的增加会发生什么。下图覆盖了后验分布(蓝色,左侧 Y 轴上的值)和可能性(红色,右侧 Y 轴上的值)。

n 增加时的后验概率和可能性
让我们从分析我们已经抛过一次硬币并观察到正面的情况开始。在 frequentist 方法中,我们看到,在这种情况下,我们对 p = 1 的估计,显然是一个不正确的结论,然而我们没有其他方法来回答这个问题。在贝叶斯世界中,我们的答案非常不同。因为我们定义了我们的先验信念,即θ最可能的值是 0.5,所以我们只受到第一次翻转的轻微影响。凭直觉想一想,如果你真的相信一枚硬币是公平的,你抛了一次,硬币正面朝上,这足以证明这枚硬币不公平吗?大概不会!
当要处理的数据相对较少时,贝叶斯方法比频率主义方法表现得更好。频率主义者答案的可行性依赖于大数定律,因此在缺乏大量数据的情况下,结果并不总是可靠的。
然而,随着我们开始观察更多的硬币翻转,我们开始看到我们的贝叶斯答案变得非常清楚,最终我们将所有的鸡蛋放在 p = 0.6 的篮子里。仅仅翻转 100 次后,我们给不等于 0.6 的值分配了一个非常小的概率,最终我们分配给 0.6 的概率收敛到 1,或者大约 100%。这意味着我们接近 100%确定,60%的时间,我们的硬币将是正面。
在背景中,可能性(或观察到的数据)开始支配我们一开始建立的先验信念。这是因为证据是压倒性的,所以我们更依赖它。如上图所示,随着 n 的增加,似然性和后验分布收敛(注意,X 轴和 Y 轴上的比例不同,因为似然性不是概率分布)。当我们观察到更多的数据时,先验的影响会被冲掉,数据会自己说话。
结论
在这篇博文中,我们研究了估计未知参数的两种不同方法。在 Frequentist 方法中,我们让数据说话:我们通过建立一个尽可能符合观察数据的模型来估计 X 和 Y 之间的关系。这给了我们一个单点估计,最大似然估计,不确定性被模型的标准误差捕获,它与样本大小成反比。因此,典型的 Frequentist 努力收集尽可能多的关于感兴趣的参数的数据,以便达到更精确的估计(至少在理论上)。
在贝叶斯方法下,我们从变量之间的关系的概念开始分析:先验分布。然后我们观察我们的数据并更新我们对参数分布的信念:这给出了后验分布。贝叶斯框架下的一个重要但微妙的区别是,我们将参数视为随机变量,以捕捉其真实值的不确定性。这需要在建模过程的每个阶段都使用发行版。
如果我们回忆一下我们展示的频率主义方法的图表,我们会发现,随着样本量的增加,贝叶斯和频率主义的答案是一致的,这是理所应当的!随着我们获得关于我们感兴趣的参数的更全面的信息(即观察更多的数据),我们的答案应该变得更加客观。
所以你可能会想,如果他们最终给出相同的答案,那么采用不同的方法又有什么意义呢?这实际上取决于用例。我们认为,在你有很多很多数据的情况下,部署一个完全成熟的贝叶斯框架可能是多余的。在数据较少的情况下,例如在社会科学中,处理后验分布的能力是非常有洞察力的。此外,在频率主义者的方法中,我们完全受制于数据的准确性。如果我们的数据不准确或有偏差,那么我们的估计也会如此。在贝叶斯方法中,我们可以通过设置更强的先验来抵消这种影响(例如,对我们先前的信念更有信心)。我们还认为,贝叶斯分析在简单性方面的不足,在整体精度方面得到了弥补,在许多情况下,向客户或同事展示后验分布比点估计更能提供信息。
在这篇博文中,我们将先验空间视为相对简单的空间,只有 11 个 p 可以取的任意值。但是如果 p 可以取 0 到 1 之间任何可能的值呢?当我们开始处理参数空间的连续分布时,事情变得有点不确定,这将是下一篇博客文章的主题,我们将了解为什么使用马尔可夫链蒙特卡罗近似法——敬请关注!
我们意识到有很多东西需要打开,所以这里有一个 TLDR 给你:
Frequentist 方法使用最大似然估计(MLE)来估计未知参数:在给定我们观察到的数据的情况下,点估计是参数最可能的真实值。
Frequentist 答案完全由观察到的数据形成,并以单点估计的形式交付。这使我们受到数据准确性和质量的支配。
-贝叶斯方法将先验概率分布与观测数据(以似然分布的形式)相结合,以获得后验概率分布。
-虽然贝叶斯方法也依赖于数据,但其估计值结合了我们关于感兴趣参数的先验知识 ,其答案以感兴趣参数的概率分布的形式给出。我们可以通过设定更强的先验来抵消对数据的依赖。
-随着样本量的增加,统计推断变得客观,频率主义者和贝叶斯估计开始彼此相等。
完整代码
https://github . com/gabgilling/Bayesian-Blogs/blob/main/Blog % 20 post % 201% 20 final . ipynb
引文
[1]https://online.stat.psu.edu/stat504/lesson/1/1.5
[2]https://tinyheero . github . io/2017/03/08/how-to-Bayesian-infer-101 . html
承认
感谢我们在 IBM 的同事:Alexander Ivanoff、Steven Hwang、Dheeraj Aremsetty 和 Lindsay Sample 的校对和评论!
从 0 到数据网格:Kolibri Games 打造数据驱动型公司的 5 年历程
数据网格案例研究
一家初创公司从零开始构建数据网格和数据驱动文化的经验教训。

总部位于柏林的 Kolibri Games 经历了一段疯狂的旅程,从 2016 年一家基于学生宿舍的初创公司飙升至 2020 年被育碧公司收购的头条新闻。
虽然五年来发生了很多变化,但有一点始终未变:该公司致力于建立一种洞察驱动的文化。随着几乎每周一个新版本的发布,他们的移动游戏不断变化并产生大量数据——每天处理 40 种不同事件类型的 1 亿个事件,有些事件有数百个触发器。
一路走来,该公司的数据组织从一个营销分析师团队发展到 10 多名工程师、分析师和科学家,他们负责确保数据运营的可靠性、可扩展性和自助性。为了推动这种爆炸式增长,该团队正在构建一个 数据网状架构 ,以数据驱动的文化为后盾,这将让成千上万更成熟的公司羡慕不已。
最近,我们与该公司的数据工程负责人 António Fitas 坐在一起,讨论 Kolibri Games 的数据故事,分享他们的数据组织如何在每一步发展,包括他们使用的技术,他们雇用的团队成员,以及他们面临的数据挑战。
他们的故事非常吸引人,对于那些开始数据网格之旅的人来说,这是一个很好的资源。让我们开始吧。
2016 年:首次数据需求
2016 年,Kolibri Games 的创始人开始在德国卡尔苏赫理工学院的学生公寓里一起开发一款游戏。他们凭借自己的第一款手机游戏闲散矿工大亨取得了早期的成功,创始人建立了一些与数据相关的基本目标和目的。
数据目标和目的
建立基本的商业报告,以确定游戏是否正常运行,以及公司是否赚钱,方法是:
- 报告应用内购买收入
- 报告广告收入
- 报告特定于游戏的 KPI
- 报告崩溃和错误
数据团队和技术团队

图片由 Kolibri Games 提供。
作为一家精益初创企业,创始人完全依赖第三方工具,包括:
- 脸书分析公司
- 广告合作伙伴
- Firebase(帮助修复应用程序崩溃和错误)
- 游戏分析(针对游戏内关键绩效指标,如留存率)
数据挑战
- 跨不同工具的分散分析
- KPI 的计算方式不透明
- 报告不同工具之间的不一致
- SDK 集成带来的技术问题
- 技术限制,例如更深入地挖掘指标和缺乏灵活性
“这种方法远非完美,但这不是我们首先要解决的问题,”安东尼奥说。“我们很幸运,我们有很多玩家有机地加入了游戏,但我们希望得到更多。为此,我们希望借助数据提升我们的营销和用户获取运营。”
2017:追求效果营销
随着“无所事事的矿业大亨”越来越受欢迎,运营公司所需的团队也越来越受欢迎——搬出学生公寓,搬进卡尔斯鲁厄一间合适的办公室。随着该组织专注于获取新客户,该团队建立了数据功能来衡量和改善绩效营销。
数据目标和目的
加强绩效营销,让更多用户加入游戏,同时通过以下方式确定哪些活动是有利可图的:
- 计算活动的广告支出回报(roa)
- 创建简单的用户终身价值(LTV)预测
- 构建付费广告竞价脚本以优化活动绩效
数据团队

图片由 Kolibri Games 提供。
还没有招聘数据——一位营销经理负责绩效营销。
数据技术堆栈

图片由 Kolibri Games 提供。
为了深入了解 ROAS 和 LTV,该团队在他们的武器库中添加了第三方移动测量合作伙伴(MMP)工具 AppsFlyer。这个工具帮助营销经理了解哪些用户获取活动表现良好,花费了多少,以及新获得的玩家产生了多少收入。AppsFlyer 还通知本地运行的脚本来优化投标管理操作。
数据挑战
- 缺乏透明度
- 易出错的
- 没有版本控制
- 数据更加分散
“我们基本上被蒙住了眼睛,”安东尼奥说。“我们没有任何版本控制或工程最佳实践来管理我们为设定出价而运行的代码。”
尽管如此,Kolibri Games 第二年的年收入仍超过 1000 万欧元。为了更上一层楼,是时候投资一些改进了。
2018:专业化和集中化
在第三年,这家年轻的公司搬到了柏林,雇佣了更多的开发人员和设计师,安东尼奥也及时加入了 5000 万下载量的庆祝活动。与另一名数据工程师和营销团队一起,一个专业的数据组织开始形成。
数据目标和目的
通过创建一个工具来收集所有信息,提供透明度,并通过以下方式更深入地挖掘数据,从而实现数据集中化和绩效营销专业化:
- 投资专有的自有解决方案来集中数据
- 收集原始数据
- 建立中央数据仓库
- 设置仪表板
数据团队

图片由 Kolibri Games 提供。
António 和另一名数据工程师致力于构建初始技术堆栈,而一名营销分析师则专注于构建仪表盘以实现绩效营销。
数据技术栈

图片由 Kolibri Games 提供。
António 和他的团队构建了他们的数据平台的第一个版本,他们将 Azure 用于几乎所有的服务。他们建立了事件遥测技术,为游戏中的特定事件或动作生成数据点,建立了批处理作业,将 API 中的数据集成到他们的数据湖中,并做出了他们的第一次技术转换:从 Power BI 迁移到 Looker,以获得另一层数据操作和现成的功能,如版本控制。
- 数据工厂(Azure)
- 活动中心(Azure)
- 流分析(Azure)
- 数据湖分析(Azure)
- 权力 BI,然后 Looker
- SQL 数据库
数据挑战
- 查询性能
- 稳定性和可靠性
- 保持系统的活力
António 说:“我们的 SQL 数据库正在成为一种限制。“在我们的仪表盘运行的同时,集成数据的工作正在写入数据,或者分析师正在进行即席查询,基本上,整个服务开始变得非常不可预测和非常缓慢。我们开始发现我们的一些工作经常失败,而且我们的警报或监控很有限。我们决定以数据为导向,开始解决我们遇到的一些问题。”
2019:面向数据
随着又一次成功的游戏发布、品牌重塑和全球认可,Kolibri Games 在 2019 年迎来了更大的增长。该公司在 7 月份达到了 1 亿次下载和 100 名员工的双重里程碑。随着更多的用户和更多的产品,产生了更多的原始数据,安东尼奥和他的团队知道他们只是触及了数据如何推动公司前进的皮毛。
数据目标和目的
通过了解玩家行为、进行数据支持的实验,以及通过以下方式完善数据技术体系,为游戏创造洞察力:
- 建立一个货币化仪表板,显示公司通过优惠、商店和广告赚了多少钱
- 构建进度和参与度仪表板,以了解玩家如何与游戏互动(例如他们何时离开以及他们如何与某些功能互动)
- 运行 A/B 测试
- 提高仓库的性能和数据管道的可维护性
数据团队

图片由 Kolibri Games 提供。
安东尼奥知道他们需要更多的人来让他们的海量数据变得有用。他们在数据平台团队中增加了一名游戏数据主管和两名 BI 开发人员。数据工程师与基础设施密切合作,维护系统、集成新工具和维护流用例,同时为 BI 开发人员构建框架,以处理数据集成、数据建模和数据库可视化。
数据技术栈

图片由 Kolibri Games 提供。
不断增长的数据团队需要更大的灵活性和更简单的协作,因此 António 用 Databricks 替换了一些 Azure 服务。他们尝试使用 Spark 来利用他们的数据湖作为他们的数据仓库,但发现在该平台上工作的人更喜欢 Python 和 SQL——他们在使用 Spark 时没有看到他们期望的 Looker 性能。因此,安东尼奥和他的团队最终用雪花取代了他们的 SQL 数据库,雪花成为他们所有分析的主要计算引擎。
数据挑战
- A/B 测试很难设置,缺少透明度,并且无法显示或演示
- 游戏中没有数据驱动的决策
安东尼奥说:“大多数决定仍然是根据直觉和社区反馈做出的。“我们继续生成更多数据,但我们知道我们可以更多地利用这些数据,并围绕这些数据构建更多使用案例。”
2020 年:实现数据驱动
2020 年初,Kolibri Games 被法国游戏巨头育碧收购。随着资源的增加,António 的团队继续发展,将机器学习功能分层到他们的平台中,并从关于数据网格架构和特定领域数据所有权的对话中受到启发。为了开始构建数据驱动的文化,他们引入了 特定于数据的服务级别协议(SLA),并专注于增加对数据的自助式访问。
数据目标、SLA 和目的
做出完全由数据驱动的决策,以释放公司游戏的全部潜力,特别是让产品经理帮助跟踪:
- 90%的闲置矿业大亨决策需要数据支持
- 90%的问题的洞察时间需要少于 1 小时
- 90%的变更需要通过分析进行验证
为了实现这一目标,数据平台团队将:
- 改进 A/B 测试流程,以帮助对要实现的功能和更改做出明智的决策
- 通过为玩家群体创建游戏配置来提高个性化
- 使用预测分析来预测 LTV 和流失,以相应地调整游戏
- 让人们能够回答与数据相关的问题,而无需咨询数据分析师
数据团队

图片由 Kolibri Games 提供。
由于数据组织专注于特定领域的数据所有权,因此让新聘分析师直接融入产品团队是有意义的,他们与产品经理密切合作,了解需求并调整优先级,以反映产品的实际需求。第三名数据工程师和两名数据科学家也加入了数据平台团队,专门从事 ML 算法和 A/B 测试数据管道的工作。
数据技术栈

图片由 Kolibri Games 提供。
António 的团队将数据仓库架构添加到雪花中,更好地定义了他们应用业务逻辑的地方。他们也从做 ETL 转到了 ELT,直接在雪花里做清洗和转换。他们将其与数据转换工具 dbt 结合起来,在平台上工作的每个人之间进行协作,增加透明度和可见性。
数据工程团队还专注于抽象数据管道,以便产品分析师可以与游戏开发团队一起设计和定义新的数据事件。通过遵循数据工程师制定的指导原则,他们现在可以将数据放入仓库并对数据建模,而不需要数据工程师。António 和他的团队还引入了 Airflow 作为数据集成、所有 dbt 模型和数据验证的主要编排。
数据挑战
- 数据信任
- 软件稳定性
- 扩展个性化
“我认为,当我们试图衡量‘我们是否真的在利用数据进行产品开发’时,这项工作做得非常好。”安东尼奥说。“让这些 KPI 围绕我们的问题,并衡量这些事情,真的有助于人们更多地考虑它,并推动它。我认为,就让更多的人思考数据而言,这项工作本身证明是卓有成效的。但此时发生的情况是,我们获得了更多的数据,更多围绕数据的新用例,以及许多新模型,但监控所有这些并确保事情正确变得越来越困难。”
2021 年:构建数据网格
随着今年的展开,安东尼奥和他的团队专注于建立 数据信任和可靠性——这对于他们实现具有特定领域数据所有权的数据网状架构的使命至关重要。
数据目标和目的
帮助公司利用可靠的数据进行扩展,同时构建数据网状架构,提高开发速度和减少事故,减少事故数量,并通过进一步的高级分析提高玩家个性化。安东尼奥和他的团队计划通过以下方式实现这一目标:
- 提高测试能力
- 构建通用的发布和开发流程
- 实施更多监控和警报
- 专注于高级分析
- 围绕数据监控和工程最佳实践协作扩展数据平台功能
- 构建领域跨职能团队
数据团队

受数据网格概念的启发,该公司计划通过增加项目经理来扩展嵌入产品和营销的领域团队,项目经理将帮助他们的团队和 BI 开发人员定义工作,以帮助集成新的和维护现有的数据源。中央数据平台团队将继续专注于构建解决方案、框架、维护基础设施和高级分析。
数据技术栈

今年,数据团队正在努力集中开发和发布流程,以便数据平台、营销和产品团队都遵循相同的合并请求并发布到生产流程中。

Kolibri Games 还增加了一个新工具 Monte Carlo,用于端到端、全自动的 数据可观测性 和血统。在尝试构建自己的数据监控定制解决方案后,他们意识到需要一名全职人员来构建一个框架,以将其扩展到不同的用例并监控所有数据资产。数据可观察性通过使用机器学习来监控数据仓库中所有数据的质量,并提供自动生成的端到端数据血统来加快故障排除和 事件解决 来帮助解决这个问题。
5 年数据之旅的 5 个关键收获
归根结底,建立一家数据驱动的公司是一场马拉松,而不是短跑。
对于 António 来说,实施数据网格和实现端到端数据信任是其团队旅程的顶点。以下是他在组建数据团队(无论其形状或规模如何)以在每个发展阶段取得成功时的关键要点。
- “构建您自己的数据堆栈是值得的,因为它为您提供了所有这些功能,并使您能够在产品开发或团队工作中以数据为导向。”
- “我们的数据平台已经经历了多次迭代,因此您必须选择并能够理解何时是改变技术的合适时机,针对哪种数据量,针对您正在运行的哪种流程。”
- “如果您想建立对数据的信任,拥有更高程度的数据质量和数据可观察性非常重要。重要的是,当出现问题时,你能够理解,并且能够很容易地指出来。”
- “在升级到更高级的数据应用程序之前,掌握基本知识非常重要。在我们的情况下,我们应该早点聘请分析师来更多地利用数据。”
- “建立数据驱动的文化非常重要,有时甚至比建立正确的技术堆栈更重要。”
随着越来越多的组织采用数据网格和分布式架构,创新、效率和可伸缩性的机会从未如此之大。尽管如此,重要的是要认识到,当涉及到实现数据网格和建立分布式数据团队时,技术和过程只能让您走这么远。归根结底,成为数据驱动型企业总是始于文化,也终于文化。
有兴趣了解数据可观察性如何促进数据网格架构?巴尔 和 其余的蒙特卡洛团队 了解更多
还有别忘了 RSVP 对于 的影响:2021 年 11 月 3 日的数据可观测性峰会 听听 扎马克 ,数据网的创始人,以及其他数据界的领军人物!
特别感谢安东尼奥和他的团队分享他们的故事!
从初学者的角度:理解可视化和用 Tableau 构建图表
了解可视化的背景,并使用 Tableau 构建仪表板

米利安·耶西耶在 Unsplash 上拍摄的照片
简介
作为一名在数据科学和分析领域工作的顾问,我经常不得不处理大量的数据,构建模型并从中获得见解。然而,当涉及到与他人交流数据和发现时,以纯文本、excel 文件或电子表格的形式呈现结果对于其他人来说不容易快速掌握和理解所发现的信息。这就是数据可视化的价值所在——通过图形或地图以可视化的方式呈现数据,并突出显示数据中的关键见解、趋势或模式。
在本文中,我将分享数据可视化的含义,以及我们如何使用 Tableau 开发交互式可视化。工具“Tableau”是一种可视化工具,目前被许多组织广泛使用。Tableau 附带了一个用户友好的界面,这是一个拖放界面,这使它成为组织使用的一个很好的选择,因为组织中的任何人都可以很容易地掌握这项技能。
[**Table of Contents:**
(1) What does Data Visualization mean?
(2) Tableau Overview
(3) Tableau Interface & Connecting to Data Sources
(4) Understanding Our Data Set
(5) Building Visualization
(6) Building a Final Dashboard](http://x)
(1)数据可视化是什么意思?

确定 A 组和 B 组中“8”的数量(图片由作者提供)
让我们从一个简单的活动开始,如上图所示,我们有两组随机字符的盒子——A 组和 B 组。现在让我们通过计算 A 组和 B 组中 8 的数量并比较所用时间来计时。你会注意到,与集合 A 相比,识别集合 B 中的数字“8”要容易得多,也快得多,因为它已经进行了颜色编码。

表格形式的销售额(图片由作者提供)
现在,让我们来看看这个包含区域 A 和区域 B 每月销售额的表,您能快速确定哪个月的销售额达到峰值或下降吗?

将地区销售额绘制成图表(图片由作者提供)
上面的折线图展示了 A 区和 B 区的销售情况,您能从折线图中看出哪个月的销售额达到峰值或下降得更快吗?从折线图中,我们可以很快注意到,A 地区的销售高峰出现在 9 月和 10 月,而 B 地区的销售高峰出现在 7 月和 8 月。
这些活动解释了可视化的目标,即更容易、更快地看到数据中的模式。数据可视化有助于人类更好地进行可视化,因为与口头/文本信息相比,人脑处理视觉格式信息的速度要快得多。使用带有正确颜色的图形格式来可视化数据有助于人类大脑轻松理解和处理信息,而不是花费时间缓慢而仔细地检查大量的文档、电子表格和报告。
“能够可视化数据并利用数据讲述故事是将数据转化为可用于推动更好决策的信息的关键。”——Cole Nuss baumer kna flic
(2) Tableau 概述
Tableau 是在“2003 年”由帕特·汉拉汉、克里斯蒂安·沙博特和克里斯·斯托尔特创建的,当时他们在斯坦福从事一个计算机科学项目。Tableau platform 提供了一系列产品,从数据准备到数据可视化,再到与他人共享您的可视化,此外还添加了治理和数据管理,以便为全周期的自助分析提供支持。用于建筑可视化的 Tableau 产品包括:
- Tableau Desktop —最适合开发者开发仪表盘、故事、报告。
- Tableau Server —最适用于将使用 Tableau Desktop 创建的仪表板、故事、报告发布到服务器,供其他人分析报告。(Tableau 管理员可以为每个用户设置权限,允许他们仅查看或通过编辑报告进行更改)。
- Tableau Online —在完全托管在云中的分析平台上构建仪表盘、故事、报告,跳过软件安装和升级的设置时间。
除了上面提到的产品,Tableau 还有其他产品,如数据准备工具 Tableau Prep,一个任何人都可以免费在线探索、创建和共享数据可视化的公共平台,等等。如果你很好奇,想了解更多 Tableau 提供的产品,可以参考他们的官网。
我将在本文中使用的平台是 Tableau Online ( 如果这是您第一次使用 Tableau ,您可以注册 14 天的试用版)。
(3) Tableau 接口&连接数据源
在 Tableau 上构建报告之前,您需要在 Tableau 工作区中做的第一件事是创建一个项目,该项目存储所开发的报告的工作簿。

创建项目和工作簿(作者图片)
在菜单栏上—选择“浏览”→创建“项目”→在创建的项目中创建工作簿。

数据连接器列表(图片由作者提供)
第一次打开新工作簿时,Tableau 会提示您连接到数据。Tableau 提供的一个很棒的功能是不同连接器的列表,允许您连接到各种数据源,无论数据是本地文件、文本文件、本地数据库还是云中的数据,如 Google Big Query、Cloudera Hadoop 等。可用连接器列表可在“连接器”选项卡上查看。此外,单个 Tableau 工作簿可以连接到来自不同数据源的多个数据集。这些多个数据集可以在 Tableau 中使用“Join”表功能相互连接,或者在不同的工作表上单独使用。
我们将使用 Tableau 平台提供的可用公共数据集—超级商店数据样本。超级商店数据示例包含按类别、子类别、销售额、利润等分类的产品信息。如果您想下载数据并手动导入,您可以从 Kaggle 下载 CSV 文件。

连接到超级商店数据源(Gif by Author)
在“连接到数据”对话框中,选择“超级商店数据源”并单击“连接”。连接到数据源后,将打开一个新的工作表,这是一个空白的工作表,您可以在其中开始开发您的第一个可视化视图。

数据源(作者 Gif)
要更好地查看导入的数据,请选择“数据源”选项卡进行导航。在 Data Source 选项卡中,我们可以查看连接的数据源和关于数据的其他详细信息,例如列的类型和值。数据网格提供了默认情况下连接的前 100 条数据记录的示例视图。
现在,让我们开始回到工作表视图,以便更好地理解开发可视化的界面。

了解 Tableau 工作区界面(图片由作者提供)
上图显示的是“Sheets”视图,这是我们构建可视化的地方。让我们来看一下界面上可用的组件:
(1)数据来源:
- 单击 Data Source 选项卡会将您带到 Data Source 页面来查看您的数据集。
(2)工作表/仪表板/故事选项卡:
- 工作表标签表示工作簿中的工作表,并表示用于开发可视化的工作空间(也表示特定的可视化,如条形图、饼图等)。)
- 仪表板标签代表一个区域,用于组合从多个工作表创建的可视化。
- story 选项卡可以像故事书一样包含顺序排列的表或仪表板的组合,以故事格式与他人共享信息。
(3)菜单:
- 菜单栏由各种不同的命令组成,如文件、数据、工作表、仪表板等。
(4)工具栏:
- 工具栏允许执行各种功能,如保存工作簿、添加新数据源、添加新工作表、复制工作表、清除当前工作区、按升序或降序对图表排序等。
(5)数据窗格:
- 数据源连接和数据字段显示在数据窗格部分。
(6)分析窗格:
- 分析窗格附加分析功能,如添加参考线、平均线、箱线图、分布带、趋势线、预测等。通过将分析窗格中的函数拖放到视图上,可以轻松地将它们添加到视图中。
(7)维度:分类值
- 由我们的数据集中被 Tableau 视为分类的列/字段组成。分类值允许我们对数字数据进行分割。(注意分类值的图标颜色为蓝色)
(8)测量/度量:连续值
- 由我们的数据集中被 Tableau 视为数字的列/字段组成。(注意数值图标颜色为绿色)
提示:如果分配错误,您可以通过右键单击字段并选择“转换为度量”来手动将字段从分类转换为度量,反之,也可以将字段从度量转换为离散或维度。
(9)货架和卡片:
- 这些是行架、列架、页架、过滤器架或标记卡。根据添加的数据,将列从数据窗格拖到卡片和架子上会在视图区域中创建可视化效果。
(10)视图:
- 这是创建可视化的工作区的画布。
如果您想了解工作区环境的更多细节,如按钮参考、状态栏等,您可以参考 Tableau 帮助页面上的文档。
(4)了解我们的数据集

超市数据源(图片由作者提供)
Tableau 附带的示例超级商店数据源是一家销售家具、办公用品和技术产品的全球零售连锁店,每行包含每个订单的订单详细信息和信息,如运输模式、客户名称、地区、城市、州、产品类别、子类别等。这个数据集中总共有 20 个字段和 9994 行或记录。
现在,假设我们在一个场景中,您扮演商店经理的角色,利益相关者希望获得以下信息:
(1)哪个品类的产品最赚钱?
(2)哪个类别在各个地区/州的表现更好?
(3)随着时间的推移,利润&销售趋势如何?
让我们看看如何从我们的数据集中获得利益相关者要求的信息,并构建一个图表来可视化它们并获得答案!
(5)建筑可视化
我们将从所需的最简单的信息开始构建— 哪一类产品最有利可图?

图表 1:按类别划分的利润(按作者划分的 Gif)
我们将构建一个高层次的概览来查看所有商店按类别细分的总体利润。
步骤 1:将列[ category ]从数据窗格拖到列架中。
第 2 步:将[sum(profit)]从数据窗格拖到行架上。
~请注意 Tableau 如何基于所选的测量名称&值自动创建视图
步骤 3:在右上方,有一个演示选项,它是 Tableau 根据所选的测量名称和值提供的关于可以使用的其他选项的建议。例如,在我们的场景中,建议使用饼图、条形图、打包气泡图等。单击“打包气泡”选项,查看图表如何变换。
第 4 步:将[sum(profit)]添加到标记架下的标签图标,以在图表中显示利润值。
- 调整标注文本大小-右键单击标记架下的标注并选择编辑标注,高亮显示文本并选择字体大小。
第 5 步:使用图表颜色——右键单击标记架下的颜色,然后选择编辑颜色,选择您喜欢的颜色。
第 6 步:通过点击文本
步骤 7:从工具栏上的 fit 图标将视图设置为整个视图,将可视化效果置于中心。

图表 1:按类别分类的利润(按作者分类的图片)
从包装泡沫图中,我们可以立即看出,根据泡沫的大小,“技术”类别的利润最高,而“家具”类别的利润最低。这表明超市的盈利能力高度依赖于科技产品,其次是办公用品。
祝贺你,你刚刚完成了你的第一个可视化画面!🤗
接下来,让我们更深入地探讨一下,在每个地区/州,哪个类别的表现更好?在新的工作表中构建这个新视图,通过底部的图标添加一个新的工作表。

图表 2:各州各地区分类销售情况(作者 Gif)
层次结构概念可用于确定按地区和按州的销售业绩。例如,在我们的场景中,可以根据位置从较高的级别创建层次结构:区域→州→城市。
步骤 1:将[国家/地区]、[地区]、[类别]列从数据窗格拖到列架上。
第 2 步:将列[sum(Sales)]从数据窗格拖到行架上。
步骤 3:根据类别向图表添加颜色—将[类别]拖到标记架下的颜色图标上。

Tableau 工具栏(图片由作者提供)
第 4 步:交换行和列——Tableau 有一个快速功能,可以立即将行切换到列,将列切换到行。要执行这些更改,只需选择工具栏上的“交换行和列”图标。
第 5 步:根据类别内的销售总额对条形进行降序排序——要执行这些更改,只需选择工具栏上的“降序排序”图标。

Tableau 中的层次结构(图片由作者提供)
步骤 6:通过单击字段[国家/地区]中的(+)按钮,从进入状态视图。
第七步:通过点击文本

图表 2:各州各地区的分类销售额(图片由作者提供)
从层次结构图中,我们可以用一种交互式的方法来查看地区、州甚至城市的销售额。这使我们能够快速识别每个状态下哪些类别的表现更好。例如,技术产品在阿拉巴马州有更好的销售,家具在亚利桑那州表现更好。这让我们更好地了解每个州的不同需求,并有助于资源规划。
干杯!我们完成了第二个可视化的构建,并学习了如何使用层次结构来深入查看更详细的视图。😎
我们的下一个可视化添加了一个小的时间序列,用于确定— 利润&销售随时间的趋势是什么?同样,从底部的图标为我们的第三次可视化添加一个新的工作表。

利润和销售趋势(作者 Gif)
该可视化引入的概念是参考线和趋势线,它们是“分析”选项卡下提供的功能。参考线向视图添加参考点。(例如:如果您正在查看几个产品的每月销售额,添加一条参考线作为平均销售额标记可以让您快速查看每个产品相对于平均值的表现)。趋势线突出显示趋势并显示基于数据的总体趋势,Tableau 提供不同的趋势线算法,包括—线性、对数、指数、多项式&幂。然后,Tableau 将根据选择的算法构建一个线性回归模型。现在让我们进入构建第三视图所需的步骤。
步骤 1:将列[Year(Order Date )]从数据窗格拖到列架中(注意,日期字段从年份开始,因为 Tableau 会自动为日期属性创建一个层次结构)。
步骤 2:向下钻取到月份字段并删除季度字段。
步骤 3:将[sum(Sales)]和[sum(Profit)]列从数据窗格拖到行架上。
第四步:切换到分析标签,并添加平均线和趋势线。
- 将“平均线”从“分析”选项卡拖到视图中,然后选择“表格”
- 将趋势线从分析选项卡拖到视图中,并选择“线性算法”
第五步:在马克卡下面为利润和销售额图表选择一种颜色。
第六步:通过点击文本

图表 3:利润和销售趋势(图片由作者提供)
在这张图表中,我们可以看到销售额和利润呈上升趋势,利润和销售额在接近年底时逐渐增加。此外,高层视图显示,每年 10 月份的销售额都会有所下降。这是一个可以被研究以识别新的商业机会的领域。
太好了!我们完成了第三次可视化的构建,并学习了如何使用 analytics 选项卡上的可用功能。😜接下来,我们将创建第一个仪表板,它将所有 3 个视图合并成一个仪表板。
(6)构建最终仪表板
首先,我们没有添加新工作表,而是从工作区底部的图标中选择“添加新仪表板”。

在 Tableau 中添加新仪表板(图片由作者提供)
仪表板是一种很好的方式来呈现一个或多个视图,包括在每个工作表、文本、图像、网页等中开发的可视化。请注意,在仪表板页面上,我们可以看到左侧已经开发的所有三个表单。要将所有 3 个视图添加到仪表板中,只需将工作表拖动到仪表板区域。

构建仪表板(Gif by Author)
第 1 步:将所有 3 张表拖动到仪表板区域。
- 请注意,第一个视图会自动填充整个仪表板区域。
- 调整每个可视化的大小

使用“文本”添加标题(图片由作者提供)
步骤 2:通过将文本对象拖入仪表板视图来添加标题。给一个标题:超市利润和销售仪表板。

向视图添加过滤器(按作者排列的图像)
步骤 3:添加过滤器
- 要添加过滤器,请导航回我们的第三张可视化工作表。
- 将[订单日期]拖至过滤器架,并选择按年份过滤。
- 右键单击属性[YEAR(Order Date)]并选择 show filter,一个交互式过滤器将被添加到右侧的视图中。
- 请注意,工作表中被筛选的内容也将反映在仪表板工作表中。

在仪表板视图中添加过滤器(按作者排序的图像)
步骤 4:从仪表板筛选
- 切换回仪表板选项卡,通过选择第三个可视化效果→过滤器→订单日期年份上的下拉选项来添加过滤器
- 试着摆弄一下过滤器,你注意到了什么?该过滤器仅适用于利润和销售趋势图。
- 要使过滤器也适用于其他可视化,只需选择“订单年数据过滤器”→“下拉选项”→“应用于工作表”→“全部使用此数据源”。
第五步:此外,美化你的仪表板,从布局选项卡添加颜色,边框,填充。

构建最终仪表板(图片由作者提供)
干得好!我们最终构建了一个仪表板,它将我们的可视化结合到一个添加了交互式过滤器的视图中。😄
除了在 Tableau 中构建仪表板,用户还可以选择将他们的视图组合成一个故事。Tableau 中的故事是一个或多个工作表或仪表板的遍历,每个视图或仪表板都被视为一个故事点。如果你想了解更多关于 Tableau 的故事,你可以参考 Tableau 帮助页面上的文档。
结论:
数据可视化仍然是数据科学家需要的一项重要技能,我认为这是一项容易学习的技能,但要成为一名优秀的讲故事者需要时间来掌握,方法是构建一个能够吸引观众注意力并传递正确信息的可视化工具。为了培养这些技能,需要大量的实践、阅读、观察和参考其他仪表板设计。最后,在您开始学习数据可视化之前,了解您正在使用的工具,熟悉该工具,从那时起,您可以慢慢提高您的技能。
感谢你阅读我的文章,如果你喜欢并愿意支持我:
参考和链接:


浙公网安备 33010602011771号