TowardsDataScience-博客中文翻译-2020-四十四-
TowardsDataScience 博客中文翻译 2020(四十四)
无人机和人工智能在新冠肺炎疫情期间加强社会隔离
使用计算机视觉和无人驾驶车辆抗击冠状病毒的关键传播
由于缺乏疫苗,到目前为止,受新冠肺炎影响的国家的多个政府采取的最有效的建议之一是社会距离或隔离,以“拉平曲线”,这意味着可以通过避免公共场所和拥挤的地方来减缓传播,在特定的时间范围内达到较低的新病例数量,较低的感染率意味着医疗保健系统压力较小,每天较少的医院就诊和较少的病人被拒绝。
有和没有社会距离的样本流行曲线。(图片鸣谢:Johannes Kalliauer/ CC BY-SA 4.0)
在一些国家(比如我住在秘鲁的利马),强制性社会隔离的条件是呆在家里,除非你在特殊情况下必须外出,比如补充食物、家庭或医疗紧急情况。为了遵守这一模式,秘鲁政府于 3 月 15 日发布了为期 15 天的全国紧急状态和边境关闭令(随后延长至 4 月 12 日)。然而,实施这一措施需要大量的警察和军官在隔离期间 24/7 在街上巡逻,并且考虑到根据传染率的变化可能会延长这一措施。这可能需要相当高的时间和成本,此外还有街上巡逻人员的传染风险。
一个想法是通过结合不同的人工智能技术,如无人机捕捉的图像处理和分类(计算机视觉),我们可以有效地加强这些措施。无人机是一种无人驾驶的交通工具,可以远程操作或配置为遵循预定义的路线,这样我们可以安全地在街上捕捉信息,减少官方人员传播的可能性,例如:
在将图像识别算法应用于视频并获得当前对象后,我们可以构建这些信息,并使用它来分析街道上的人、汽车、自行车或其他人的流量。现在有了这些结构化的信息,我们就可以制定战略和计划。
按地区显示检测到的人、汽车和自行车的数据。*重要提示:上面显示的数字仅用于演示目的,它们不是真实的,也不代表现实。
使用这些信息,我们可以实现以下一些目标:
1) 优化负责街道和大道的巡逻队的部署
2) 最大限度地降低 24/7 全天候监视的运营成本
3) 降低步行巡逻的传染风险
4) 覆盖因存在传染或高犯罪率而难以进入的区域
5) 将不合规区域之间的数据与社会隔离措施结合起来
我们必须用这一代人拥有的新武器来对抗这个疫情,其中一个也许是今天最重要的武器是我们可以用技术和现有算法生成的大量数据,这些数据赋予人工智能系统生命。
使用 OpenCV 的利马中心街道(原始视频:https://www.youtube.com/watch?v=0myE-TDPqlI
技术细节:
还有…学习的时候别忘了享受乐趣…
我自己训练的寻找蝙蝠侠的模型!
相关链接:
[## 利用无人机技术和深度学习构建面罩监控系统- neptune.ai
COVID19 的爆发让世界措手不及,影响了全球的政府、公司和个人。的…
海王星. ai](https://neptune.ai/blog/building-a-facemask-surveillance-system-with-drone-technology) [## 紧急情况下,冠状病毒的死亡,在卫生部和其他地方的通知…
利马政治、司法和社会领域的各种问题。
elcomercio.pe](https://elcomercio.pe/lima/sucesos/estado-de-emergencia-muertos-por-coronavirus-cambios-en-el-minsa-y-otros-hechos-noticiosos-de-la-semana-fotos-nndc-noticia/?foto=5) [## 两名罗文校友被困在秘鲁,作为对新冠肺炎宣布戒严令的回应
马丘比丘风景如画、连绵起伏的群山看起来就像是梦境。对于一个新的四人组…
thewhitonline.com](http://thewhitonline.com/2020/03/news/two-rowan-alumni-trapped-in-peru-as-martial-law-is-declared-in-response-to-covid-19/) [## 冠状病毒:什么是“拉平曲线”,它会起作用吗?
努力完全控制新型冠状病毒——造成数十万人感染的疫情病毒
www.livescience.com](https://www.livescience.com/coronavirus-flatten-the-curve.html) [## 计算机视觉的温和介绍-机器学习掌握
计算机视觉的最后更新,通常缩写为 CV,被定义为寻求发展的研究领域…
machinelearningmastery.com](https://machinelearningmastery.com/what-is-computer-vision/)
像热的一样放下它
数据科学/ Python 代码片段
了解熊猫。DataFrame.drop 文档。
我有一个经常性的梦,来自一个编码训练营的老师会不断地用尺子敲打我的头,告诉我去阅读一个包或库的文档。因此,作为过去,我会发现自己在钻研 Python 或 Panda 的文档。
今天,我发现自己迷上了熊猫。drop()函数。因此,在这篇文章中,我将尝试理解熊猫为曾经著名的 *.drop()*
所写的文档。
家政
让我们导入熊猫并创建一个样本数据框架。
如果我们在 Jupyter notebook 的一个单元格中键入df
,就会得到完整的数据帧:
一级数据帧操作
现在让我们去掉一些列。
上面的代码只是告诉 Python 去掉axis=1
中的'color'
和'score'
,这意味着在列中查找。或者,我们也可以很容易地不使用命名参数轴,因为它令人困惑。所以,现在让我们试试:
上述两种方法都会导致以下结果:
接下来,我们将删除一些行(或记录)。
上面,我们只是告诉 Python 去掉索引为 1、2、4 和 6 的行。请注意,索引是作为列表[1, 2, 4, 6]
传递的。这将导致以下结果:
多索引数据帧操作
在下一轮中,我们将使用多索引数据框架。让我们来设置一下:
多索引数据帧如下所示:
现在,让我们去掉'thinghy'
列:
这是我们得到的结果:
接下来,让我们去掉'pork rinds'
,因为我不喜欢他们:
这是我们得到的结果:
最后,让我们削减脂肪:
以上,level=1
简单来说就是第二级(因为第一级是从 0 开始的)。在这种情况下,它的碳水化合物,脂肪和蛋白质水平。通过指定index='fat'
,我们告诉 Python 去掉level=1
中的脂肪。
以下是我们得到的结果:
原地不动
到目前为止,通过我们所做的所有播放,不知何故,如果我们在单元格中键入df
,我们将得到的输出是未经修改的原始数据帧。这是因为我们所做的所有更改只在显示屏上生效。
但是如果我们想让这些改变永久化呢?进入:原地。
上面,我们在参数中添加了inplace=True
。这向 Python 发出了信号,我们希望更改能够生效,这样当我们输出df
时,我们将得到如下结果:
我们已经永久性地切除了脂肪。LOL!
感谢您的阅读!今天到此为止。
敬请期待!
辍学直觉
这篇文章的目的是提供一个非常简单的介绍背后的神经网络辍学的基本直觉。
当神经网络(NN)完全连接时,NN 中的所有神经元都投入工作,而不管它们在特定任务中是否有用。
全连接图层(图片来源— 链接
假设我们将 100 个神经元放入一个神经网络来完成一个分类任务,但实际上,只有 50 个神经元足以完成同样的任务。现在,因为我们已经让所有的神经元开始工作,它们将会做它们的工作来提取它们认为对分类是必要的特征。
这些特征可以分为 3 种类型:
- 最重要的功能(MSF)
- 次要特征(LSF)
- 噪声特征(NF)
最重要的特征
这些是数据中真正重要的部分,它们将极大地帮助我们对数据进行分类和归纳。有了它们,我们应该能够体面地进行分类。我们的神经网络需要提取这些特征。
不太重要的功能
这些是有好处的,但在分类中不起主要作用的。光靠他们,我们可能做不好分类。如果我们忽略了这些特征,也没关系。
噪声特征
这些是不好的特征,也不应该被神经网络拾取。这些特征对分类没有任何帮助。通过选取这些特征,神经网络将使数据过度拟合,而不会泛化。
因为我们已经让所有的神经元工作,并使用了梯度下降、随机梯度下降等方法来确保所有的神经元都工作,所以我们的神经元没有选择,只能从数据中选择所有类型的特征(MSF、LSF、NF)。这将导致过度拟合,并且神经网络不会泛化。
为了减少神经网络的过拟合和泛化,我们可以执行以下任一操作:
- 找到分类所需的最佳神经元数量
- 使用辍学技术
在我们的例子中,分类所需的最佳神经元数量是 50。但是,如果数据集发生变化,所需神经元的最佳数量也会发生变化。每次数据集改变时,寻找所需神经元的最佳数量是非常繁琐和不切实际的。因此,我们需要使用退出技术。
在 Dropout 中,我们在训练阶段随机丢弃 NN 中的一些神经元。假设我们随机丢弃神经网络中 50%的神经元。现在,分类的工作必须由剩下的 50%的神经元来完成。并且这些神经元不能懈怠并拾取不太重要和有噪声的特征,因为它们不会帮助我们分类,并且如果拾取的特征对分类没有帮助,梯度下降之类的东西会更多地惩罚 NN。因此,这些剩余的神经元被迫选择最重要的特征,这将减少过度拟合并更好地概括。
Dropout(图像源— 链接)
因此,在深度神经网络中,过度拟合的可能性非常高。因此,辍学作为一个正则化神经网络。要丢弃的神经元百分比是一个超参数,可以根据数据的过度拟合量进行调整。
这大致就是漏失如何在模型的泛化中发挥作用并提高其性能的。
参考
使用 OpenCV 和 Flask 的实时睡意检测系统。
本文概述了一种系统,该系统可检测一个人在驾驶时是否困倦,如果是,则通过使用语音信息实时提醒他。该系统使用网络摄像头和手机摄像头进行实时传输。
由 Gabe Pierce 在 Unsplash 上拍摄
动机
根据美国国家公路交通安全管理局的数据,每年大约有 100,000 起警方报告的交通事故与疲劳驾驶有关。这些事故导致超过 1550 人死亡,71000 人受伤。然而,实际数字可能要高得多,因为很难确定司机在撞车时是否困倦[1]。所以,为了让司机在任何此类事故发生前有所察觉,我们制定了这个系统。它预测眼睛和嘴巴的标志,以便通过检查一个人是闭着眼睛还是在打哈欠来识别他是否睡着了。
工作
该系统的工作可分为两部分:
- 检测或定位面部。
- 预测检测到的人脸中重要区域的标志。
一旦预测了界标,我们仅使用眼睛界标和嘴巴界标来确定眼睛纵横比(耳朵)和嘴巴纵横比(MAR ),以检查人是否困倦。
EAR 和 MAR 的计算如下所示:
耳朵和标记计算。
现在,既然我们有了代码,让我们来理解这个代码是如何工作的:
dlib 库中预先训练的面部标志检测器用于估计映射到面部的面部结构的 68-(x,y)坐标的位置[2]。这些 68-(x,y)坐标代表面部的重要区域,如嘴、左眉、右眉、左眼、右眼、鼻子和下巴。其中,我们只需要左眼、右眼和嘴的(x,y)坐标。这是通过以下方式完成的:
提取左眼、右眼和嘴的索引。
现在,每只眼睛由一组 6-(x,y)坐标表示,从眼睛的左角开始(就好像你正在看着这个人),然后围绕该区域的其余部分顺时针工作[3]:
左上:眼睛睁开时眼睛标志的可视化。右上:眼睛闭合时的眼睛标志。底部:绘制眼睛纵横比随时间的变化。眼睛纵横比的下降表示眨眼[3](soukupová和 ech 的图 1)。[4]
基于该论文, 使用面部标志点的实时眨眼检测 ,【5】然后我们可以导出反映这种关系的等式,称为眼睛纵横比(耳朵):
眼睛纵横比(EAR)方程。
利用这个概念,我们计算了嘴的长宽比:
用 68-(x,y)坐标表示面部。
正如我们看到的,嘴由一组 20-(x,y)坐标表示。因此,我们使用坐标 62、64、66 和 68,以与 EAR 计算相同的方式来计算它们之间的距离。
结果
当人困倦或打哈欠时发出警报。
此外,为了保留证据,我们保存了人感到昏昏欲睡的帧。
相框存放在单独的文件夹中作为凭证。
显示 EAR 和 MAR 随时间变化的图表。
使用网络摄像头通过流媒体进行系统演示:
使用手机摄像头通过流媒体进行系统演示:
GitHub 链接的源代码可从这里获得:
点击这里看演示根据美国国家公路交通安全管理局,每年约 10 万…
github.com](https://github.com/fear-the-lord/Drowsiness-Detection)
参考文献
[1]司机们在方向盘后面睡着了。疲劳驾驶事故的发生率:https://www . NSC . org/road-safety/safety-topics/疲劳驾驶
【2】用 dlib、OpenCV 和 Python 实现的面部地标:https://www . pyimagesearch . com/2017/04/03/face-landmarks-DLI b-OpenCV-Python/
[3]利用 OpenCV、Python 和 dlib 进行眨眼检测:https://www . pyimagesearch . com/2017/04/24/Eye-blink-detection-OpenCV-Python-dlib/
[4]使用 OpenCV 的睡意检测:https://www . pyimagesearch . com/2017/05/08/瞌睡检测-opencv/
[5]使用面部标志的实时眨眼检测:http://vision . Fe . uni-LJ . si/cvww 2016/proceedings/papers/05 . pdf
访问我的作品集:
https://souvik-portfolio-website.herokuapp.com/
深度学习的药物发现。在 10 行代码之下。
介绍 DeepPurpose,这是一个基于深度学习的工具包,用于药物-靶标相互作用预测、药物再利用和虚拟筛选。
TL;博士:深度学习正在彻底改变药物研发行业。在这篇文章中,我将展示如何使用 DeepPurpose toolkit 来解锁 50 多个用于药物-靶标相互作用(DTI)预测的模型,这是药物发现中的一项基本任务,只使用了 scikit-learn 风格的几行代码。DeepPurpose 还提供了一个简单的界面来完成 DTI 预测的两个重要应用:虚拟筛选和药物再利用。
简介
发现一种新药需要超过 10 年的时间,花费超过 26 亿美元。最近,许多用于药物发现的人工智能初创公司涌现出来,并成功应用深度学习技术来帮助药物发现研究,并大大缩短时间/节省成本[2,3]。因此,这是一个非常令人兴奋和蓬勃发展的领域💥!
然而,数据科学家社区对用于药物发现的深度学习的兴趣虽然增长迅速,但仍远远落后于其他深度学习应用,如 NLP 和图像。一个可能的原因是缺乏开源工具阻止了许多数据科学家探索这个令人兴奋的领域。现有的工具包,如 DeepChem、OpenChem、MoleculeNet 等。,极大地普及了深度学习在生命科学中的应用。在这篇文章中,我描述了一个名为 DeepPurpose 的新功能,它专门用于药物-靶标相互作用预测,这是药物发现过程的一项基本任务。所有数据科学家都喜欢 scikit-learn。因此,我们将 DeepPurpose 设计为一个 scikit-learn-fashion 框架,它用不到 10 行代码包装了 50 多个模型😇!
DeepPurpose 徽标。作者图片。
背景
先说一些生物化学的概念。疾病的主要类别通常归因于疾病途径中的靶蛋白。发现了一种调节靶蛋白的药物。通过这种疾病相关蛋白的调节,疾病可以被治愈。药物作用机制的主要范例之一是“锁和钥匙”理论[4]。蛋白质是一把“锁”🔒而药物发现就是找到正确的“钥匙”🔑以解开靶标(即,调节蛋白质的正确药物)。这种适合度被称为结合亲和力。
药物-靶标相互作用的“锁和钥匙”理论。Christopher Vakoc 授予的图像许可。
药物-靶标相互作用(DTI)测量药物分子与蛋白质靶标的结合亲和力。因此,我们很容易想象,一个准确的 DTI 深度学习模型可以大大有利于药物发现过程[5]。更具体地说,虚拟筛选和药物再利用是基于 DTI 的两个主要应用。虚拟筛选有助于识别可以与感兴趣的蛋白质结合的配体候选物,而药物再利用则为现有药物找到新的治疗目的。
任务说明。作者图片。
深层目的概述
DeepPurpose 将 DTI 模型公式化为一个编码器-解码器框架,它包括了大多数以前的作品[6,7,8,9,10]以及更多。两个编码器分别生成药物和蛋白质的嵌入,然后将它们连接到解码器,在解码器中预测结合亲和力得分。
一个编码器-解码器框架。作者图片。
DeepPurpose 使用最容易访问的输入数据格式。输入是药物靶标对,其中药物使用简化的分子输入行输入系统(SMILES)字符串,靶标使用氨基酸序列。输出是指示药物-靶标对的结合活性的分数。
药物和靶蛋白的表达。作者图片。
对于药物,我们提供 8 个编码器:四个经典的化学信息学指纹(摩根,Pubchem,Daylight 和 RDKit 2D),上面有深度神经网络(DNN);微笑字符串上的 1D 卷积神经网络(CNN ):CNN 之上的递归神经网络以平衡顺序次序;子结构分区指纹上的变压器编码器[11];分子图上的信息传递神经网络。
药物编码器。作者图片。
对于目标蛋白质,我们有 7 个编码器:在四个经典计算生物学指纹(AAC,PseAAC,联合三联体,准序列)之上的 DNN;CNN 上的氨基酸序列;CNN 上面的 CNN 和变换子序列指纹。
目标编码器。作者图片。
组合起来,有 56 个(8 乘以 7)药物靶标编码模型!此外,大多数模型都很新颖🆕!
深度目的框架
现在,在我们对 DTI 和 DeepPurpose 有了概念性的概述之后,我开始介绍 DeepPurpose 编程框架。这个框架由几个步骤组成,每个步骤由一行代码组成:
- 数据加载
- 编码器规格
- 数据编码和分割
- 模型配置生成
- 模型初始化
- 模特培训
- 再利用/筛选
- 模型保存和加载
让我们回顾一下每一步!为了获得更好的学习体验,建议在您自己的 Jupyter 笔记本文件中或浏览博客帖子笔记本时遵循这些步骤。要安装 DeepPurpose,您可以使用 DeepPurpose 活页夹云笔记本 ( 只需点击链接!)或者使用本地的 DeepPurpose 环境。安装说明可以在这里找到,你也可以在这里找到视频安装教程。
数据加载
DeepPurpose 接受一个 NumPy 数组的药物微笑字符串(X_drugs
)、一个 NumPy 数组的目标蛋白氨基酸序列(X_targets
)和一个 NumPy 数组的标签(y
),它们可以是表示相互作用结果的二进制 0/1,也可以是表示结合亲和力值的实数。输入药物和目标阵列应该配对,即y[0]
是X_drugs[0]
和X_targets[0]
的分数。DeepPurpose 将根据数据集自动在二元分类任务或回归任务之间切换。
除了通过自己的一些数据争论转换成 NumPy 数组之外,DeepPurpose 还提供了基准数据集加载器(DAVIS/KIBA/BindingDB)来简化预处理。例如,在本文中,我们将使用戴维斯数据集:
您还可以使用dataset.read_file_training_dataset_drug_target_pairs
函数从 txt 文件加载您自己的数据集,其中每一行都是一个药物微笑字符串、一个目标氨基酸序列和结合分数。
编码器规格
获得所需的数据格式后,我们需要首先指定用于药物和蛋白质的编码器。在这里,我们尝试将MPNN
用于药物,将CNN
用于目标。请注意,您可以通过更改编码名称来切换编码器。此处列出了编码器的完整列表。
(如果你正在使用 CPU 运行这篇博文,你会发现MPNN
和CNN
有点大,你可以尝试更小的编码器,比如用于药物的Morgan
和用于蛋白质的Conjoint_triad
。)
数据编码和拆分
现在,我们需要使用utils.data_process
函数为不同的编码器准备数据编码方案。在此功能中,我们可以指定训练/验证/测试分割分数、随机种子,以确保相同的数据分割具有重现性,并且还支持数据分割方法,如cold_drug
和cold_protein
,这些方法对药物/蛋白质进行分割以进行模型稳健性评估,从而测试未知的药物/蛋白质。该函数输出训练、验证和测试集 Pandas 数据帧。
模型配置生成
现在,我们用它的配置初始化一个模型。在此功能中,您几乎可以修改任何超参数(例如,学习率、时期、批量大小)、模型参数(例如,隐藏维度、过滤器大小)。此处的链接中列出了支持的配置。
对于这篇博文,我们将纪元大小指定为 3,这样您就可以在 CPU 和 GPU 上快速运行,并可以继续下一步。有关参考参数,请查看演示文件夹中的笔记本。
模型初始化
接下来,我们使用上述配置初始化模型:
模特培训
现在,只需输入model.train
函数,它就可以开始训练了!
训练损耗曲线会自动打印出来。此外,如果任务是二元分类任务,测试集 ROC-AUC 和 PR-AUC 曲线也将打印出来。
自动生成的损耗曲线。作者图片。
再利用/筛选
训练完模型后,我们可以使用models.repurpose
和models.virtual_screening
函数简单地重新调整用途和筛选:
例如,假设我们想从一组抗病毒药物中重新确定一种新冠肺炎靶向 3CL 蛋白酶的用途。我们已经在dataset
包装器中提供了相应的数据。
自动生成并打印出候选药物的排序列表:
自动生成重新调整结果的排序列表。作者图片。
接下来,我们展示如何对来自 BindingDB 数据集的数据样本进行虚拟筛选,然后使用virtual_screening
函数生成具有高结合亲和力的药物-靶标对的列表。如果没有提供药物/目标名称,则使用药物/目标列表的索引。将生成一个类似的排序列表。
模型保存和加载
最后,保存和加载模型也非常容易。加载功能还会自动检测模型是否在多个 GPU 上进行了训练。保存和加载我们刚刚训练的模型的示例:
我们还提供了一个预训练模型的列表,您可以在列表下找到所有可用的模型。例如,要加载在 BindingDB Kd 数据集上预先训练的MPNN+CNN
模型:
就是这样!现在,您可以为药物-靶标相互作用预测任务训练一个最先进的深度学习模型👏!
DeepPurpose 还支持许多更多的功能,例如,这个演示展示了如何使用 Ax 平台在 DeepPurpose 上进行贝叶斯优化等最新的超参数调优方法。
最后但并非最不重要的是,许多现实世界的药物开发涉及化验数据,这意味着数据仅由药物分子和与目标或细菌的结合分数组成。这个问题也被称为药物性质预测任务。DeepPurpose 还通过仅使用药物编码器来预测结合分数来支持这项任务。该框架与 DTI 预测非常相似,如下所示:
更详细的分步说明,你可以在这里找到这篇博文的笔记本:[ DTI 预测 ][ 药性预测 ]。
这就结束了我们关于 DeepPurpose 和 DTI 预测的博文!我希望你喜欢它,并对深度学习和药物发现的令人兴奋的交叉感兴趣,如果你还没有的话!我们还呼吁数据科学家为这个开源项目做出贡献!
了解更多,这里有 论文 和 Github 资源库 ,请明星、分享、投稿!
这是傅天凡、卢卡斯·格拉斯、马林卡·兹尼克、和孙的合作作品。
如果您有任何问题或反馈,请随时通过kexinhuang@hsph.harvard.edu联系我;或者干脆在推特上 PM 我@ kexinhuang 5!
参考
[1] Mullard,a .新药开发花费了 26 亿美元。《自然评论》药物发现 (2014)。
[2]弗莱明,Nic。人工智能如何改变药物发现?性质 (2018)。
[3]斯马利,e .人工智能驱动的药物发现引起了制药公司的兴趣。《自然生物技术》 (2017)。
[4] Gschwend DA,好 AC,昆茨 ID。面向药物发现的分子对接。分子识别杂志:跨学科杂志 (1996)。
[5] Mayr,Andreas,等. ChEMBL 上药物靶点预测的机器学习方法大规模比较。化学科学 (2018)。
[6]ZTürk H,Ozkirimli E. DeepDTA:深层药物-靶点结合亲和力预测。生物信息学 (2018)。
[7] Nguyen,Thin,Hang Le 和 Svetha Venkatesh。GraphDTA:使用图形卷积网络预测药物-靶标结合亲和力。 BioRxiv (2019)。
[8]椿、正史、健太郎富井和濑濑纯。化合物-蛋白质相互作用预测,对图形和序列的神经网络进行端到端学习。生物信息学 (2019)。
[9] Lee,Ingoo,Jongsoo Keum 和 Hojung Nam。DeepConv-DTI:通过对蛋白质序列进行卷积的深度学习来预测药物与靶标的相互作用。 PLoS 计算生物学 (2019)。
[10]陈,邢等.药物-靶标相互作用预测:数据库、网络服务器和计算模型.生物信息学简报 (2016)。
[11]黄 K,肖 C,黄 T,格拉斯 L,孙 j .卡斯特:用化学亚结构表示法预测药物相互作用。AAAI (2020)。
图形神经网络药物发现—第一部分
预测溶解度
了解如何使用生命科学的深度学习库 Deepchem 通过 GNNs 预测分子溶解度。
米拉德·b·法库里安在 Unsplash 上的照片
相关材料
目录
- 介绍
- 药物开发和机器学习之间的特殊化学
- 为什么分子溶解度很重要
- 用图形神经网络解决问题
- Deepchem 的实际操作部分
- 关于我
- 参考
介绍
这篇文章是药物发现背后的理论,图形神经网络和 Deepchem 库的实用部分的混合。第一部分将讨论机器学习在药物开发中的潜在应用,然后解释哪些分子特征可能对图形神经网络模型有用。然后,我们深入到编码部分,创建了一个可以预测分子溶解度的 GNN 模型。我们开始吧!
药物开发和机器学习之间的特殊化学
丹尼斯·约翰逊在 Unsplash 上拍摄的照片
药物开发是一个耗时的过程,可能需要几十年才能批准药物的最终版本[1]。它从药物发现的初始阶段开始,在此阶段它识别可能成为药物的某些分子组。然后,它经过几个步骤来排除不合适的分子,最后在现实生活中进行测试。在药物研发阶段,我们关注的重要特征是 ADME ( A 吸收、 D 分布、 M 代谢和 E 代谢)特性。我们可以说,药物发现是一个优化问题,我们预测 ADME 性质,并选择那些可能增加开发安全药物可能性的分子[2]。高效的计算方法可以发现具有理想特性的分子,从而加速药物开发过程,并提供相对于其他研发公司的竞争优势。
机器学习应用于药物发现只是时间问题。这允许以前所未有的速度和精度处理分子数据集[3]。然而,为了使分子结构适用于机器学习,必须执行许多复杂的预处理步骤,例如将 3D 分子结构转换为 1D 指纹向量,或者从分子中的特定原子提取数字特征。
为什么分子溶解度很重要
ADME 的特性之一,吸收,决定了药物是否能有效地到达患者的血流中。吸收背后的因素之一是水溶性,即某种物质是否可溶于水。如果我们能够预测溶解度,我们也可以很好地了解药物的吸收特性。
用图形神经网络解决问题
为了将 GNNs 应用于分子结构,我们必须将分子转换成模型可以理解的数字表示。这是一个相当复杂的步骤,它将根据 GNN 模型的具体架构而变化。幸运的是,大部分预处理被外部库覆盖,比如 Deepchem 或 RDKit 。
在这里,我将快速解释预处理分子结构的最常见的方法。
笑容
SMILES 是分子 2D 结构的字符串表示。它将任何分子映射到一个特殊的字符串,这个字符串(通常)是唯一的,可以映射回 2D 结构。有时,不同的分子可以映射到同一个微笑字符串,这可能会降低模型的性能。
指纹
将分子结构转换成圆形指纹。【来源】
指纹是一个二元向量,其中每一位代表分子的某个亚结构是否存在。它通常很长,可能无法包含一些结构信息,如手性。
邻接矩阵和特征向量
另一种预处理分子结构的方法是创建一个邻接矩阵。邻接矩阵包含关于原子连接性的信息,其中“1”表示它们之间有连接,“0”表示没有连接。邻接矩阵是稀疏的,并且通常很大,这可能不是非常有效的工作。
CH4(甲烷)转换成邻接矩阵(右上)、特征向量的向量(右中)和特征对向量的矩阵(右下)。邻接矩阵为我们提供了原子间连接性的信息,例如碳 C 连接到自身和所有其他 H 原子(邻接矩阵的第一行)。单个特征向量,假设为 v0,包含关于特定原子的信息。单个特征对向量包含关于两个相邻原子的信息,并且它通常是一个函数(和、平均等)。)的两个特征向量。
有了这个矩阵,我们可以以矢量的形式向 GNN 模型提供关于每个单个原子的信息和关于相邻原子的信息。在每个原子的特征向量中,可以有关于原子序数、价电子数或单键数的信息。当然还有更多,幸运的是它们可以由 RDKit 和 Deepchem 生成,
特征向量通常包含关于特定原子的信息。这个向量通常是通过使用 RDKit 或 Deepchem 包中的功能生成的。
溶解度
我们要预测的变量叫做 cLogP 和也被称为辛醇-水分配系数。基本上,值越低,它在水中的溶解度越大。 clogP 是一个对数比,因此值的范围从-3 到 7 [6]。
还有一个描述溶解度对数的更通用的等式:
溶解度方程。 MP 是熔点(摄氏度)。 logKow 是辛醇-水分配系数,又名。 cLogP
这个等式的问题是 MP 很难从分子的化学结构中预测出来。所有可用的溶解度数据集仅包含 cLogP 值,这也是我们将要预测的值。
Deepchem 的实际操作部分
Deepchem 是一个面向生命科学的深度学习库,构建在 Tensorflow、Numpy 或 RDKit 等少数几个包之上。对于分子数据,它提供了方便的功能,如数据加载器、数据拆分器、特征化器、指标或 GNN 模型。根据我的经验,设置起来很麻烦,所以我建议在我提供的 Colab 笔记本上运行它。我们开始吧!
首先,我们将下载 Delaney 数据集,它被认为是溶解度预测任务的基准。然后,我们使用 CSVLoader 类加载数据集,并指定一个包含 cLogP 数据的列,该数据被传递到 tasks 参数中。在 smiles_field 中,必须指定带有 smiles 字符串的列的名称。我们选择一个 ConvMolFeaturizer,它将按照我们将要使用的 GNN 模型所要求的格式创建输入要素。
随后,我们使用 RandomSplitter 分割数据集,并将数据分为训练集和验证集。我们还对 y 值进行了归一化处理,因此它们的平均值和单位标准偏差为零。
在这个例子中,我们将使用一个 GraphConvModel 作为我们的 GNN 模型。这是一个由 Duvenaud 等人创建的架构。你可以在这里找到他们的论文。作为 Deepchem 软件包的一部分,还有其他 GNN 模型,如 WeaveModel 或 DAGModel。您可以在此找到带有所需特征的型号的完整列表。
在这个代码片段中,还定义了一个人的 R2 分数。简单来说,这个值越接近 1,模型越好。
Deepchem 型号使用 Keras API。用 fit() 函数训练图形 _conv 模型。您也可以在这里指定历元的数量。我们用 evaluate() 函数得到分数。这里必须传递规格化器,因为在计算指标分数之前,需要将 y 值再次映射到之前的范围。
仅此而已!你可以用 Deepchem 做更多有趣的事情。他们创建了一些教程来展示你还可以用它做什么。我强烈建议过目一下。你可以在这里找到它们。
感谢您阅读本文,希望对您有用!
关于我
我是阿姆斯特丹大学的人工智能硕士学生。在我的业余时间,你可以发现我摆弄数据或者调试我的深度学习模型(我发誓这很有效!).我也喜欢徒步旅行:)
如果你想了解我的最新文章和其他有用的内容,以下是我的社交媒体资料:
参考
[1] 早期药物发现:化学信息学和计算技术在识别先导序列中的应用:https://www . science direct . com/science/article/ABS/pii/s 0968089612003598
https://www.cambridgemedchemconsulting.com/resources/ADME/ADME 属性
[3] 化学信息学和药物发现中的机器学习:https://www . science direct . com/science/article/pii/s 1359644617304695
[4]QSAR 和药物设计研究中的分子拓扑:https://www . research gate . net/publication/236018587 _ Molecular _ topology _ in _ QSAR _ and _ drug _ design _ studies
[5] 重访分子哈希指纹:https://chem bio info . WordPress . com/2011/10/30/重访-分子哈希指纹/
[6] 山本浩司博士讲座笔记:[http://www . piri ka . com/ENG/TCPE/logP-theory . html #:~:text = Definition % 3A,% 2Dphase %辛醇% 2f 水% 20 系统。&text = Values % 20 of % 20 kow % 20 is % 20 thus % 2C % 20 无单位。&text = Values %20 of % 20 kow % 20 通常为% 20,(20% 20 或%2025'C.](http://www.pirika.com/ENG/TCPE/logP-Theory.html#:~:text=Definition%3A,-phase octanol%2Fwater system.&text=Values of Kow are thus%2C unitless.&text=Values of Kow are usually,(20 or 25'C.)
【7】预测水溶性——比看起来难:http://practical chem informatics . blogspot . com/2018/09/Predicting-hydro-Solubility-its . html
图形神经网络药物发现—第二部分
预测毒性
了解如何使用 Deepchem(生命科学的深度学习库)预测 GNNs 的毒性。
马修·T·雷德在 Unsplash 上的照片
相关材料
目录
- 介绍
- 用图形神经网络解决问题
- Deepchem 的实际操作部分
- 关于我
- 参考
介绍
在本文中,我们将涵盖另一个决定药物能否通过安全性测试的关键因素— 毒性。事实上,毒性占被拒绝的候选药物的 30%,使其成为药物开发阶段考虑的最重要因素之一[1]。机器学习在这里将被证明是非常有益的,因为它可以在药物发现过程的早期阶段筛选出有毒的候选药物。
我假设你已经阅读了我的上一篇文章,它解释了我将在这篇文章中使用的一些主题和术语:)让我们开始吧!
用图形神经网络解决问题
特征工程部分与本系列的第 1 部分中的非常相似。为了将分子结构转换为 GNNs 的输入,我们可以创建分子指纹,或者使用邻接矩阵和特征向量将其输入到图形神经网络中。这个特性可以由外部软件自动生成,如 RDKit 或 Deepchem,所以我们不必太担心它。
毒性
最大的区别在于机器学习任务本身。毒性预测是一项分类任务,与溶解度预测相反,溶解度预测是一项回归任务,我们可能还记得上一篇文章。有许多不同的毒性效应,如致癌性、呼吸毒性、刺激/腐蚀等[2]。这使得工作变得稍微复杂了一些,因为我们可能还要处理不平衡的班级。
幸运的是,毒性数据集通常比溶解度数据集大得多。例如,当用于溶解度预测的 Delaney 数据集只有大约 3k 训练样本时,Tox21 数据集具有大约 12k 训练样本。这使得神经网络架构成为一种更有前途的方法,因为它可以捕捉更多隐藏的信息。
Tox21 数据集
Tox21 数据集是作为一个项目创建的,该项目挑战研究人员开发机器学习模型,以在给定数据上实现最高性能。它包含 12 种不同的标签,每一种都表示不同的毒性效应。总体而言,该数据集有 12,060 个训练样本和 647 个测试样本。
这一挑战的获胜方法是 DeepTox [3],这是一种深度学习管道,利用化学描述符来预测毒性类别。它高度表明深度学习是最有效的方法,图形神经网络有潜力实现更高的性能。
Deepchem 的实际操作部分
首先,我们导入必要的库。这里没有什么新东西 —我们将使用 Deepchem 根据 Tox21 数据训练一个 GNN 模型。GraphConvModel 是由 Duvenaud 等人创建的架构。它使用指纹算法的修改版本,使它们具有可区分性(因此我们可以进行梯度更新)。这是第一个 GNN 体系结构,被设计用来处理图形的分子结构。
Deepchem 包含了一个方便的 API 来为我们加载 Tox21。 load_tox21 功能。我们选择一个特征器作为 GraphConv —它将创建化学描述符(即特征)来匹配我们模型的输入要求。由于这是一项分类任务,ROC AUC 分数将被用作一项指标。
Deepchem 的美妙之处在于模型使用了类似 Keras 的 API。我们可以用。拟合函数。我们将 len(tox21_tasks) 传递给模型的参数、,这是一些标签(本例中是 12 个)。这将设置最终层的输出大小为 12。我们使用 32 的批量大小来加快计算时间,并指定模型用于分类任务。该模型需要几分钟时间在 Google Colab 笔记本上进行训练。
训练完成后,我们可以评估模型。这一点也不难——我们仍然可以使用 Keras API 来完成这一部分。ROC AUC 分数通过获得。评估功能。
在我的病例中,训练 ROC AUC 得分高于验证 ROC AUC 得分。这可能表明模型对某些分子过度拟合。
你可以用 Deepchem 做更多的事情。它包含几个不同的 GNN 模型,像本教程一样易于使用。我强烈建议看看他们的教程。对于毒性任务,他们收集了几个用不同模型运行的不同例子。你可以在这里找到。
感谢您阅读本文,希望对您有用!
关于我
我是阿姆斯特丹大学的人工智能硕士学生。在我的业余时间,你可以发现我摆弄数据或者调试我的深度学习模型(我发誓这很有效!).我也喜欢徒步旅行:)
如果你想了解我的最新文章和其他有用的内容,以下是我的社交媒体资料:
参考
【1】“制药业能降低流失率吗?”:【https://pubmed.ncbi.nlm.nih.gov/15286737/T21
【2】“使用机器学习方法和结构警报对药物设计的化学毒性进行计算机预测”:https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5826228/
【3】Deep tox:利用深度学习进行毒性预测:https://www . frontier sin . org/articles/10.3389/fenvs . 2015.00080/full
用图形神经网络发现药物——第三部分
GNN 解释方法实用教程
GNNExplainer 的可视化
相关材料
目录
- 什么是解释技巧
- 我们为什么要烦恼呢?
- GNN 解释方法的工具
- GNNExplainer 的实际操作部分
- 关于我
- 参考
什么是解释技巧
类别映射的一个例子——卷积神经网络的解释方法之一。【来源】
解释技巧帮助我们理解模型的行为。例如,解释方法被用于形象化图像的某些部分,或者观察它如何对某个输入做出反应。这是一个成熟的机器学习领域,具有许多不同的技术,可以应用于深度学习(例如,类激活图、梯度属性)和其他机器学习算法(例如,LIME)。
然而,只有少数人试图为图形神经网络(GNNs)创建解释方法。大部分在深度学习中开发的“重用”方法,并试图将其应用于图形领域。
如果你想了解更多关于可解释 GNNs 的最新研究,我强烈推荐你看看我以前的文章。在这里,我将保持理论简短,并集中于如何使用现有的 GNN 解释包,GNNExplainer。
我们为什么要烦恼呢?
深度学习模型可以有数百万个参数,它们经常以黑盒的形式出现在我们面前[1]。很难说这个模型将如何对新数据做出反应,以及为什么它会在给定特定输入的情况下做出某些预测。
通过解释方法,我们希望在模型中建立信任。它们从模型中提供了额外的见解,使模型更加透明和可解释。通过发展对模型的信任,我们可以安全地部署模型以供更广泛的使用。
GNN 解释方法的工具
不幸的是,对 GNNs 解释方法的研究相当新,所以没有很多现成的工具和研究论文。Duvenaud 等人在[2]中完成了关于该主题的第一批工作之一。他设法创造了一种梯度归因方法,突出了触发预测的某些分子亚结构。例如,他们的方法可以突出使分子有毒或可溶于水的分子亚结构。
突出显示了触发溶解度预测的分子亚结构。【来源】
幸运的是,斯坦福大学的研究人员开发了一种模型不可知的 GNN 解释方法,GNNExplainer [3]。在本文的剩余部分,我们将探索如何使用他们的工具。
如果你没有时间阅读关于 GNNExplainer 实现的整篇文章,但是你仍然想对它的工作原理有一个直观的了解,看看我的文章。
GNNExplainer 的实际操作部分
GNNExplainer 的交互式可视化。在“Syn2”数据集上运行。
GNNExplainer 实际上是第一个模型无关的开源工具,可用于 GNN 解释。斯坦福大学的研究人员做了大量工作来创建这个通用工具,但它包含很少的错误,并且相当难以设置。在本指南中,我将讨论我在安装过程中遇到的一些问题,并指导你如何创建如上图的 GNN 解释。
装置
请注意: 我的设置是支持 CUDA 的 GPU 的 Windows OS。安装说明可能不适用于不同的设置。但是,我将尝试指出您可能需要调整的步骤,以使其适用于其他操作系统需求。如果你只是好奇这个包是如何工作的,没有时间安装,请跳过这个说明。
要安装 GNNExplainer,先决条件是已经安装了 conda】。他们资源库的安装说明也可以在 Github 上找到。它们不适合我的设置,也没有什么错误,所以我花了一些时间根据我的需要调整安装说明。我的设置的工作说明如下。如果您有不同的操作系统,您可能需要更改 cudatoolkit 版本,或者安装没有 CUDA 支持的 Pytorch。
如何培养 GNN 模式
作者提供了一个 GNN 模型和几个图形数据集作为示例。这是一个很好的起点,可以测试一切是否正常工作,并对软件包有更多的了解。
安装软件包后,运行:
这将在示例 syn2 数据上训练所提供的 GNN 模型。它甚至可能需要半个小时,所以做好准备!Syn2 是一个由作者创建的合成数据集,称为“具有社区特征的随机 BA 图”。GNNExplainer 模型的基本事实是一个“类似房子”的结构(看上面的 GIF)。这是 GNNExplainer 将尝试查找的一组节点。
如何使用解释器
要使用在 Syn2 数据集上训练的模型运行 GNNExplainer,请运行:
这将创建一个解释文件,然后可以使用 Jupyter 笔记本可视化。我在运行它的时候遇到了一个错误。在脚本结尾保存准确性/损失数字时出现问题。所需的解释是在这一步之前计算的,所以这个问题并不重要。如果你还想解决这个问题并保存图,用修改保存路径的我的要点替换 explain.py 文件。它们将位于 log/ 文件夹中。
如何可视化结果
作者为我们提供了两个笔记本来可视化结果。它们几乎是一样的,但是交互式笔记本包含了额外的交互式解释示例。
在您从笔记本/ 文件夹中启动选定的笔记本之前,您必须再进行一次调整。转到 log/ 文件夹,将从 masked_ 开始的所有文件移动到syn 2 _ base _ h20 _ 020 _ explain/文件夹。这将确保我们不必更改笔记本代码中的任何路径。
将所有被屏蔽的 _*文件移动到 syn2_base_h20_020_explain 文件夹
这个笔记本非常简单,你只需要运行所有的单元格来生成图。对于 syn2 数据集,它们应该类似于下图:
运行GNN-解释者-即 ipynb 笔记本后的示例结果。
如何在分子数据上运行 GNNExplainer?
您可以潜在地使用该软件来运行 Tox21、致突变性或自定义图表数据集。为了做到这一点,请看一下原始的存储库说明。
我成功地在 Tox21 数据集上训练了 GNN 模型。然而,看起来软件中有错误,模型在训练后没有保存,这使得无法运行解释器。希望他们能尽快修好它。
PyTorch 几何中的 GNNExplainer
GNNExplainer 也是 PyTorch 几何软件包的一部分。然而,它只支持节点解释,并且没有原始包提供的可视化工具。不管怎样,还是值得一查的。
感谢您阅读本文,希望对您有用!
关于我
我是阿姆斯特丹大学的人工智能硕士学生。在我的业余时间,你可以发现我摆弄数据或者调试我的深度学习模型(我发誓这很有效!).我也喜欢徒步旅行:)
如果你想了解我的最新文章和其他有用的内容,以下是我的社交媒体资料:
参考
【1】深度学习中的解释方法:用户、价值观、关注点和挑战:https://arxiv.org/pdf/1803.07517.pdf
【2】****用于学习分子指纹的图上卷积网络:https://arxiv.org/abs/1509.09292
【3】gnnexplaner:为图形神经网络生成解释:https://arxiv.org/abs/1903.03894
利用条件期望进行缺失值的实用估计
基于多元正态条件期望的二阶估计
迈克·肯尼利在 Unsplash 上的照片
处理缺失值是数据科学中一个棘手的问题。有多种方法,下面列出了一些:
- 丢弃包含缺失要素的记录
- 用样本平均值或中位数替代缺失值
- 使用机器学习技术推断期望值,如变分自动编码器[1]
尽管我们可以选择丢弃包含缺失要素的记录,但考虑到这些记录中的非缺失要素可以提供有价值的信息,这通常是不可取的。
考虑到分布的唯一一阶矩,均值替代可以被认为是一种一阶近似方法。
另一方面,基于机器学习的方法通常计算量很大,并且缺乏直观的解释能力。这是一个研究前沿,积极的研究正在进行中。
在这篇文章中,我提出了一个简单的方法,除了利用第一阶矩之外,还利用了第二阶矩,并表明它为我们提供了一个更好的估计量。
1 多元正态条件期望法
假设 k 维随机向量 X 遵循多元正态分布,
X ~ N(μ,σ)
其中μ是平均向量,σ是 kk* 协方差矩阵。如果 X 被分割成两个子向量 X1 和 X2,分别具有大小 q1* 和 (k-q)* 1,则以 X2=x2 为条件的 X1 遵循多元正态分布,具有以下均值和协方差矩阵:
μ(x1|x₂)=μ₁+σ₁₂σ₂₂^(-1)(x₂—μ₂)……………………………………(1)
σ(x1|x₂)=σ₁₁—σ₁₂σ₂₂^(-1)σ₂₁(2)
其中μ₁和μ₂是 X1 和 X2 的先验均值向量,σ₁₁是σ的子矩阵,大小为 qq* ,σ₂₂是σ的子矩阵,大小为 (k-q)(k-q)* ,σ₁₂是σ的子矩阵,大小为 q(k-q)* 。
假设对于特定记录,X1 是缺失值特征的向量,而 X2 是有效值特征的向量。使用上面的μ(X1|x₂方程)我们可以估计 X1 的值,其中μ和σ用样本的均值和协方差矩阵代替,不包括缺失值记录。这可以被认为是一个二阶近似,因为它使用了一阶和二阶矩。可以一次估计多个缺失特征。
1.1 分类特征的估计
上面描述的条件期望方法并不直接应用于分类特征,但是通过一键矢量转换,它同样可以使用。步骤是:
- 将分类特征转换为指示特征的一键向量。例如, Dayofweek 转换成 7 个指标特征 Dayofweek_0,Dayofweek_1,…,Dayofweek_6,其中day ofweek _ 0=I【day ofweek 是星期一】等。
- 将指标特征视为连续的,并使用条件期望方法对分类特征缺失的记录进行估计。
- 将指标估计值的 argmax 作为类别的预测指标。
1.2 约束特征的估计
1.2.1 积极特征
假设一个特征只取正值,但是等式(1)给出的估计并不能保证肯定。然而,使用适当的变量转换,我们可以加强这种约束。假设 x 是一个正值特征。让我们对数变换 x 并用数据集中变换后的特征 u= log(x) 替换它。由于 u 可以取正值也可以取负值,因此我们可以估算 u 而不是 x 。最后我们可以通过 exp(u) 回退 x ,始终为正。
1.2.2 有界特性
假设特征 x 被限制在范围(a,b)内。我们可以引入一个无界变量 u 使得
x = a + (b-a)/( 1 + exp(-u) )
其中 1/(1 + exp(-u))是值在(0,1)内的 Sigmoid 函数。 u 用 x 表示为 u = -log( (b-a)/(x-a) -1) 。然后我们可以在一个数据集中用 u 替换 x ,估计缺失的us,最后计算缺失的xs。
1.2.3 交叉特征约束
假设一个特征 X₁总是大于另一个特征 X₂,X₁ > X₂.为了对估计值施加这样的约束,我们可以使用变换后的特征 X₁' = log(X₁-X₂来替换数据集中的 X₁。估计完 X₁'之后,我们就可以退出 X₁了,
X₁ = X₂ + exp(X₁')
这保证了 X₁ > X₂.
2 条件期望法的评价
为了评估条件期望方法在实践中的表现如何,使用了 UCI 机器学习库[2]上的电器能量预测数据集。这是一个实验数据集,旨在对低能耗建筑中的电器能耗进行回归分析。它有 19735 条记录和 29 个特征,包括两个随机变量 rv1 和 rv2 。功能描述粘贴在下面:
date time year-month-day hour:minute:second
Appliances, energy use in Wh
lights, energy use of light fixtures in the house in Wh
T1, Temperature in kitchen area, in Celsius
RH_1, Humidity in kitchen area, in %
T2, Temperature in living room area, in Celsius
RH_2, Humidity in living room area, in %
T3, Temperature in laundry room area
RH_3, Humidity in laundry room area, in %
T4, Temperature in office room, in Celsius
RH_4, Humidity in office room, in %
T5, Temperature in bathroom, in Celsius
RH_5, Humidity in bathroom, in %
T6, Temperature outside the building (north side), in Celsius
RH_6, Humidity outside the building (north side), in %
T7, Temperature in ironing room , in Celsius
RH_7, Humidity in ironing room, in %
T8, Temperature in teenager room 2, in Celsius
RH_8, Humidity in teenager room 2, in %
T9, Temperature in parents room, in Celsius
RH_9, Humidity in parents room, in %
To, Temperature outside (from Chievres weather station), in Celsius
Pressure (from Chievres weather station), in mm Hg
RH_out, Humidity outside (from Chievres weather station), in %
Wind speed (from Chievres weather station), in m/s
Visibility (from Chievres weather station), in km
Tdewpoint (from Chievres weather station), °C
rv1, Random variable 1, nondimensional
rv2, Random variable 2, nondimensional
2.1 连续特征的缺失值估计
选取了三个特征: T3 、风速、和 rv1、进行评估。随机抽取 10%的记录,对于所选记录,三个特征标记为“缺失”。日期特征被替换为两个分类特征星期和月,然后它们被转换为一个热点向量。然后使用第 1 节中描述的方法估算这些缺失值,并与它们的真实值进行比较。三个估计量的合成均方根误差(RMSE)总结如下:
Comparison of RMSEs of Three Missing Value Estimators
-----------------------------------------------------------------**Feature | Conditional-Expectation | Sample-Median | Sample-Mean**T3 | 0.617 | 1.961 | 1.957
Windspeed | 1.872 | 2.564 | 2.527
rv1 | 14.590 | 14.589 | 14.589
- 对于 T3 ,条件期望估计量的 RMSE 小于样本中位数或样本均值 RMSE 的三分之一。
- 对于风速,条件期望估计器的 RMSE 约为样本中位数或样本均值 RMSE 的 73%。
- 对于 rv1,所有的三个估计器都有大致相同的 RMSE。这是意料之中的,因为 rv1 只是一个随机变量。
为了大致了解每个要素与其他要素的相关程度,计算了每个要素与其他要素的平均绝对相关系数,如下表所示:
**Feature | Average of Absolute Correlation Coefficients**T3 | 0.33
Windspeed | 0.13
rv1 | 0.01
T3 与其他特征的相关性最高,而 rv1 与其他特征的相关性最低。这解释了三个特征的不同水平的估计 RMSEs。
2.2 分类特征的缺失值估计
Dayofweek ,从日期特征中提取,选取进行评估。随机抽取 10%的记录, Dayofweek 标记为“缺失”。然后使用第 1.1 节中描述的程序估算这些缺失值。估计精度为 33%。这看起来不高,但是如果我们选择最频繁的 Dayofweek Tuesday 作为我们的估计,那么准确率只有 15%!
3 但是现实世界的特征不是多元高斯…
的确,很少有真实世界的特征遵循多元正态分布。提出的条件期望方法是基于正态性假设,但这是一个合理的假设吗?这取决于现有的信息。已知多元正态分布是给定随机变量的均值和协方差矩阵的最大熵分布[3]。因此,当唯一已知的信息是一阶和二阶矩时,多元正态分布在实践中是一个合理的假设。我对电器能源预测数据集的评估表明,正态性假设可以导致对真实世界缺失值的稳健而直观的估计。
参考
[1]约翰·T·麦考伊、史蒂夫·克伦和刘烨·奥雷特。"缺失数据插补及其在模拟铣削回路中的应用."IFAC-PapersOnLine
第 51 卷,第 21 期,第 141–146 页(2018 年)。
[2]电器能源预测数据集。UCIMachine 学习知识库。http://archive . ics . UCI . edu/ml/datasets/Appliances+能源+预测。
[3]海姆·松波林斯基。"第三讲:最大化熵和信息."哈佛讲座。【https://canvas.harvard.edu/files/3549960/download? 下载 _frd=1 (2015)。
DS 项目:如何预测 Google Apps 评分?
通过练习本练习,丰富您的数据科学知识。
在这篇文章中,我与你分享我在分析和预测 Google Apps 评分方面的经验。这是我在数据科学面试中必须解决的测试之一。我必须指出,这是一种个人解决问题的方式,它可以帮助你得出自己的推理。
与任何其他 DS 项目一样,我们从从这里下载数据文件开始。
你可以从 这里 在我的 Github 上可视化这个项目的 Jupyter 笔记本,查看我在这个项目中使用的代码。
事不宜迟,我们走吧!
开始使用数据
第一步是数据预处理。我们根据数据的格式和类型清理、播放和转换所有元素和列。正如我们所看到的,我们的数据具有以下格式:
apps = pd.read_csv('GooglePlayApp-ELHOUD.csv')
apps.info()
数据帧包含 13 个不同的列和 8281 行。列“ Rating ”代表我们模型的 Y 向量:我们试图预测的内容。我们将“评级的不同值形象化:
apps['Rating'].value_counts()
在可视化“评级的值时,我们注意到在我们的数据(19.0)中有一个不合理的评级。一般来说,应用程序的评级在 0 到 5 星之间。我们删除了这个值,以避免我们的模型出现偏差。如果我们认为这是一个打字错误,我们可以用 1.9 替换它,但由于我们无法确定,并且我们与数据所有者没有直接联系,所以最好将其删除。
之后,我们会检查所有重复的应用程序并删除它们:
print('Number of apps at the beginning:', len(apps))
apps.drop_duplicates(subset='App', inplace=**True**)
print('Number of apps after removing duplicates:', len(apps))
我认为建议删除这三列(当前版本、 Android 版本、和上次更新),因为这三列对于我们的分析来说是不必要的,并且对评级没有直接影响(之后可视化相关性)。
为了使数据形象化,我们必须把它转换成数字。转换是通过替换所有的字符串并以不同的方式将它们转换成数字格式来完成的。在下图中,我们概括了所有的清洁、缩放和转换步骤。
我在下图中概括了所有的步骤:
我使用的转换代码的所有部分都设置在我的 Github 库上。
数据可视化
一旦我们完成了所有的转换,我们在开始时使用 Seaborn 可视化“应用评级的分布和“应用大小的分布。因此,让我们来看看它,检查是否正常,并尝试纠正它,否则:
sns.distplot(apps['Rating'],fit=norm)
print('- Total number of ratings:', len(apps['Rating']))
print('- Mean of distribution of rating :', np.mean(apps['Rating']))
print('- Standard deviation:', np.std(apps['Rating']))
我们注意到数据集评级的“拟合度”从技术上讲并不符合均值为 4.16、标准差为 0.559 的正态分布。这些信息将有助于以后定义和开发模型。让我们检查一下概率图:
**from** **scipy** **import** stats fig = plt.figure()
prob = stats.probplot(apps[‘Rating’], plot=plt)
所以,肯定不正常:我们有偏斜。
我想做一些变换,以适应高斯分布。让我们对数据进行 Box-Cox 变换,看看会发生什么…Box-Cox 变换表示如下:
之后,我们重新设想转型后“应用评分的分布情况:
更像高斯(正态)分布!我们将在这个项目的剩余部分使用这个转换。
接下来,我们想象不同的相关性。这是帮助我们选择模型重要特性的关键一步。相关矩阵如下所示:
apps.corr()
与相关性相关的一些备注:
- 很明显,安装数量与评论数量高度相关(k=0,59)。
- 价格越高,评级越低,相关系数为 0.02。
预测模型
我们建立了两个模型:
- 随机森林回归量
**from** **sklearn.ensemble** **import** RandomForestRegressor
**from** **sklearn.metrics** **import** auc, accuracy_score, mean_absolute_error, mean_squared_errorchosen_features = ['Reviews', 'Size', 'Installs', 'Type','Category', 'Price', 'Content Rating', 'Genres']
X = apps[chosen_features]
y= bcx_target *#transformed rating*
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.33, random_state=10)rf_reg = RandomForestRegressor()
rf_reg.fit(X_train,y_train)
y_rfpred = rf_reg.predict(X_test)
对于一个简单的 RF 回归器(带有转换后的评级),我们得到:
- 均方差:0.269
- 平均绝对误差:0.352
在下图中,我们可以更好地看到随机森林回归的实际和预测评级。:
现在,让我们想象一下随机森林的估计数对 MSE 的影响:
estimators = np.arange(10, 500, 10)
mse_list = []
**for** i **in** estimators:
rf_reg.set_params(n_estimators=i)
rf_reg.fit(X_train, y_train)
y_rfpred = rf_reg.predict(X_test)
mse_list.append(mean_squared_error(inv_boxcox(y_test,lam), inv_boxcox(y_rfpred,lam)))
plt.figure(figsize=(10, 5))
plt.xlabel("No. of Estimators")
plt.ylabel("MSE")
plt.title("Effect of Number of Estimators")
plt.plot(estimators, mse_list)
我们得到了大约 370 的一些估计量的最小均方误差。最低 MSE 大约等于 0,2697 。
- XGBoost 回归器
y_xgpred = xgb_model.predict(X_test)
mse=mean_squared_error(inv_boxcox(y_test,lam), inv_boxcox(y_xgpred,lam))
print('Mean Squared Error:',mse)
XGboost 的 MSE 近似等于 0,2695 。
在下图中,我们比较了两个模型(Random Forest 和 XGboost)的预测性能。
观点
为了不使开发时间过长,我在这里停了下来。虽然,如果我想在这方面更进一步,我会尝试这两个想法:
- 尝试一些神经网络模型(使用 Keras)。我相信如果我们为这个问题选择了最好的架构,我们会得到好的结果。
- 我还将着手处理数据集的第二部分,并应用 NLP(自然语言处理)来根据用户的评论预测应用程序的评级(通过使用所有的 NLP 技术,如标记化、文本分段……)
我建议您查看我在这个项目中使用的代码,方法是从 这里 在我的 Github 上可视化这个项目的 Jupyter 笔记本,并关注更多相关文章和项目。
ds4 ovid-19:在新冠肺炎,数据科学需要解决哪些问题?
探索 7 种类型的数据和行业垂直行业、数据集链接、数据科学技术和挑战的 40 个业务问题
在本文中,我希望分享我对我们能够解决的具有挑战性的数据科学问题的想法,这些问题在新冠肺炎有商业价值。新冠肺炎是小说《T2》的主人公,他是 2019【1】的后裔。本文对数据科学发烧友识别、制定和解决业务问题很有用,对领导指导他们的团队解决与其业务相关的数据科学问题也很有用。我观察到了业内两大趋势。
○我们遇到了业务问题,但不确定哪些数据有助于解决该问题?
○我们有数据,但是使用这些数据可以解决哪些业务问题?
在这两种情况下,起点是不同的。然而 在数据科学世界中,业务问题和解决业务问题的相关数据 同等重要。文章的重点是:
需要解决哪些业务问题?
与新冠肺炎相关的不同数据集有哪些?
什么样的机器学习/深度学习/统计技术可以用来解决这些问题和挑战?
总结特定行业垂直行业需要解决的问题
正如我在前面的文章[2]中提到的,有 7 种类型的数据即 数字、分类、文本、图像、视频、语音和信号 不分行业/领域来构建数据科学的问题。
使用数值和分类数据要解决的问题:
表-1 总结了 数值型、 分类型数据要解决的问题类型、要使用的数据科学技术以及解决这些问题的挑战。需要解决的核心业务问题是” 新冠肺炎对我的业务有什么影响?、、、我们感染新冠肺炎病毒的风险有多大? 。这些业务问题被表述为多步骤数据科学问题,如表-1 所示。
表-1:在新冠肺炎使用数值和分类数据要解决的问题列表
以下是解决上述问题的可用数据集列表。除了这些数据集,您可能还需要使用您有权访问的特定于您的组织的数据。您可以直接将原始开源数据加载到您的代码(python 笔记本)中或下载。csv 文件,然后加载它们进行进一步处理。
- 新型冠状病毒(新冠肺炎)病例,由(JHU)约翰·霍普斯金大学系统科学与工程中心(CSSE)提供:
https://github.com/CSSEGISandData/COVID-19
- 新冠肺炎受影响病例的日水平信息:
https://www . ka ggle . com/sudalairajkumar/novel-corona-virus-2019-dataset
- 新冠肺炎印度公司的具体数据可以通过该网址访问,该网址每天更新。您可以参考您所在国家/地区的具体数据进行进一步分析。
- 确诊、死亡、康复病例的时间序列数据:
https://data . hum data . org/dataset/novel-coronavirus-2019-ncov-cases
有一些有趣的文章可以处理[3]中提到的加载数据。
- GDP 增长率增长率/衰退数据参考:
https://datahub.io/core/gdp#data
https://tradingeconomics.com/country-list/gdp-growth-rate
https://data.worldbank.org/topic/economy-and-growth
- 消费物价指数数据可从以下网址下载:
https://datahub.io/core/cpi#data
- 就业数据参考:
https://datahub.io/core/employment-us#data
- 人口数据可从以下网址下载:
https://datahub.io/core/population
- 黄金历史价格:
https://datahub.io/core/gold-prices
- 天气数据集:
https://www.kaggle.com/muthuj7/weather-dataset
- 房地产 /房价数据:
https://datahub.io/core/house-prices-us#data
- 新冠肺炎脆弱性指数数据与参考文献[4]:
【https://github.com/closedloop-ai/cv19index
- 新冠肺炎药物研发数据集:
https://www . ka ggle . com/jaisimha 34/covid 19-drug-discovery/data
使用自然语言处理解决文本数据的问题:
如果您熟悉文本处理,那么这些问题可能会让您感兴趣。表 2 总结了一系列问题、相应的文本数据、解决这些问题的技术以及一系列挑战。来自变压器的双向编码器表示(BERT)的最新进展在解决这类问题中起着至关重要的作用。
表 2:新冠肺炎文本数据需要解决的问题列表
可用的数据集链接如下:
- 新冠肺炎开放研究数据集( CORD-19 )数据来自 Kaggle,包含 50,000 多篇文章:
https://www . ka ggle . com/Allen-institute-for-ai/CORD-19-research-challenge
- 政府措施数据集:
https://www.acaps.org/covid19-government-measures-dataset
- 假新闻检测器数据和模型可从以下网址获取:
https://github.com/yaqingwang/EANN-KDD18
在最近的一次 Kaggle 挑战赛中,我和我的爱立信同事一起解决了构建问答系统的问题。管道中遵循的步骤以及代码和结果在以下 Kaggle URL 中共享:
https://www . ka ggle . com/robin Liu bin/ericsso n-cord-19-challenge-task-6
图 1:解决疫情数据问答系统的管道
图 1 显示了解决问题的高级步骤,包括使用单词嵌入、BERT 方法的预处理,以及最终使用双语评估替角分数(BLEU)对结果进行排序。我的爱立信同事在这篇博客中讨论了各种实现方法。
https://www . ericsso n . com/en/blog/2020/4/ai-data-solutions-helping-fight-corona virus
语音数据要解决的问题:
表 3 总结了问题列表、参考语音数据、要使用的数据科学技术以及挑战列表。
表 3:新冠肺炎语音数据需要解决的问题列表
关于呼吸、咳嗽和语音声音的 Coswara 数据的详细信息(在数据收集阶段,您可以做出贡献并在以后用于建立模型)可从以下 URL 获得。咳嗽样本的诊断在[5]中有描述。
图像、视频数据要解决的问题:
表 4 总结了需要解决的问题、参考图像/视频数据、需要遵循的技术以及面临的挑战。
表 4:新冠肺炎图像、视频数据需要解决的问题列表
让我们检查可用的数据资源来解决上述问题。
- X 光、CT 影像数据集:
https://github.com/ieee8023/covid-chestxray-dataset
https://www.kaggle.com/bachrr/covid-chest-xray
https://towards data science . com/新冠肺炎-成像-数据集-胸部-x 光-CT-注释-协作-5f6e076f5f22
使用 Keras 在 X 射线图像中检测新冠肺炎的示例代码可参考[6]。
- 基因序列新冠肺炎的鉴定:
https://datascience.nih.gov/covid-19-open-access-resources
https://www.ncbi.nlm.nih.gov/genbank/sars-cov-2-seqs/
以下网址提供了有趣的资源,可以开始我们在基因组学和病理学领域的分析。提到了可用的计算资源,因为基因序列建模需要大量的计算能力。请利用现有资源,展示你的计算机视觉和其他机器学习技能。
https://datascience.nih.gov/covid-19-open-access-resources
https://covid19pathology.nih.gov/
按照行业垂直领域总结要解决的业务问题:
表 5 总结了新冠肺炎疫情各种垂直行业需要解决的数据科学问题列表。这个列表是所有垂直行业的常见业务问题的补充,例如“新冠肺炎对我的业务/股价/收入有什么影响?”。
表 5:根据行业垂直领域需要解决的具体问题列表
表 5 中介绍的数据科学技术包括 LSTM-长短期记忆、SSD-单次检测、YOLO-你只看一次、ARIMA-自回归综合移动平均、BERT-来自变压器的双向编码器表示、Seq2Seq 模型-序列到序列模型、CNN-卷积神经网络、CONVLSTM-卷积长短期记忆、NLP-自然语言处理。
我们的当务之急是安全离开疫情,然后努力实现业务连续性。COVID(公元前)前和 COVID(公元前)后的生活可能不一样。正如我们在历史上所见证的那样,每一次疫情都给人类行为和商品消费模式带来了一些变化。 捕捉消费者行为的变化 是各行各业的关键。能够提前抓住这一趋势的公司将是这一旅程的最大受益者。
结论:
在本文中,我主要关注数据科学家在数据可用的情况下可以解决的一系列问题。我收集了 40 个问题、相应的数据以及参考 URL 和数据科学技术来解决这些问题。这 40 个问题首先按数据类型排列,然后按行业垂直排列。具有多种数据类型(数字+文本+图像)的异构数据可用于解决进一步的一系列问题,如多模态聊天机器人、构建新冠肺炎助手等。在参考资料中共享的其他文章[7,8,9]中,可提及一些更有趣的问题。
参考文献:
[1]https://www . who . int/India/emergencies/novel-coronavirus-2019
[3]https://towards data science . com/新冠肺炎-数据处理-58aa 3663 F6
https://arxiv.org/pdf/2003.07347.pdf
[5]https://arxiv.org/pdf/2004.01275.pdf
[8]https://www . data revenue . com/en-blog/machine-learning-新冠肺炎
期待早日走出新冠肺炎,生活在更加健康美好的世界后新冠肺炎。请在评论区分享您的反馈。
双重引导已死:Windows 和 Linux 现在合二为一了
用 WSL 2 把你的 Windows 机器变成一个开发者工作站。
图片来自 Pixabay
我曾经有一台苹果笔记本电脑作为我的日常司机。在那里我几乎可以做任何事情;开发、提案写作、音乐创作等。但是,对供应商锁定的恐惧,对我依赖苹果的奇思妙想和恶习的担忧——可以说这是非常昂贵的——促使我寻求一种新的解决方案。
参见第二部分:
只需一个命令,就可以将任何机器变成开发人员工作站。
towardsdatascience.com](/dual-boot-is-dead-the-post-mortem-cee4db42d059)
我开始建立一个机器学习工作站;一个伟大的 CPU,大量的内存和一个称职的 GPU,等等。我选择的几乎所有操作系统都是 Ubuntu,除了我需要微软 Office 来写提案。Office online 还没有出现,让我们面对现实吧,LibreOffice 是一场灾难。所以,解决方案是双启动 Ubuntu 和 Windows 10。你体验到的从苹果转移到 Ubuntu 的自由是无与伦比的,你拥有的构建自己的 PC 的选项几乎是无限的。
很长一段时间里,双靴都是答案。一百万次上下文切换之后,WSL 来了。因此,我开始将部分工作流程转移到 Windows 上。但是,仍然有许多东西不见了。然而, WSL 2 似乎是一个游戏改变者。 在这个故事中,我将向您展示如何将您的开发工作流程迁移到 Windows 10 和 WSL 2,它的新功能以及在不久的将来可以期待什么。
学习率是我每周给那些对 AI 和 MLOps 世界好奇的人发的简讯。你会在每周五收到我关于最新人工智能新闻、研究、回购和书籍的更新和想法。在这里订阅!
什么是 WSL 2
WSL 2 是 WSL 架构的新版本。这个版本有几个变化,决定了 Linux 发行版如何与 Windows 交互。
在这个版本中,您可以获得更高的文件系统性能和完整的系统调用兼容性。当然,您可以选择以 WSL 1 或 WSL 2 运行您的 Linux 发行版,而且,您可以随时在这两个版本之间切换。WSL 2 是对底层架构的重大改进,使用虚拟化技术和 Linux 内核来支持其新特性。但是微软处理本质细节,所以你可以专注于重要的事情。
装置
微软承诺在不久的将来 WSL 2 会有一个流畅的安装体验,并且能够通过 Windows updates 更新 Linux 内核。现在,安装过程有点复杂,但没什么可怕的。
在这个例子中,我们将在 Windows 10 上安装 Ubuntu 20.04。但是这个过程对于微软商店中的任何发行版都是一样的。首先,您应该启用 Linux 的 Windows 子系统可选特性。以管理员身份打开 PowerShell,并运行以下命令:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
下一步,我们将把我们的系统更新到 WSL 2。为此,Windows 10 必须更新到 2004 版,并且必须在 BIOS 设置中启用英特尔的虚拟化技术。以管理员身份启动 PowerShell,并运行以下命令:
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
重新启动您的机器以完成 WSL 安装并更新到 WSL 2。然后,在安装新的发行版时,您需要将 WSL 2 设置为我们的默认版本。为此,以管理员身份打开 PowerShell 并运行以下命令:
wsl --set-default-version 2
运行命令WSL 2 requires an update to its kernel component. For information please visit [https://aka.ms/wsl2kernel](https://aka.ms/wsl2kernel.)
后,您可能会看到这条消息。按照这个链接,从那个页面安装 MSI,在您的机器上安装一个 Linux 内核,供 WSL 2 使用。安装内核后,再次运行该命令,它应该会成功完成,而不会显示消息。
最后但同样重要的是,我们应该安装一个 Linux 发行版。打开微软商店,搜索 Ubuntu 20.04 LTS 。安装后,你应该可以在我们的开始菜单上找到一个新的 Ubuntu 应用程序。启动它并按照说明(主要是创建一个新的 UNIX 用户)来完成安装。
要检查您的 Linux 发行版是否安装在 WSL 2 上,运行wsl --list --verbose
。如果结果表明它使用 WSL 1,您可以通过运行wsl --set-version <distribution name> <versionNumber>
来改变它。
仅此而已。你现在有一个完整的 Ubuntu 发行版在 Windows 10 中运行了!
开发人员工作站
安装好 Ubuntu 后,你就可以安装任何你需要的东西了。例如,如果您是数据科学家,您可以安装最新的 Anaconda 发行版,如果您是前端工程师,您可以安装 angular 和 npm 等等。但是有两个工具我想重点介绍一下:Visual Studio 代码和 Docker + Kubernetes。
Visual Studio 代码
Visual Studio 代码是许多开发人员的首选 IDE。现在我们已经启用了 WSL 2,VS 代码绝对必要的扩展是远程开发。
这个插件支持针对 WSL 2、容器映像甚至是通过 SSH 的远程 VM 上的源代码进行远程开发。因此,我们现在可以在运行于 WSL 2 上的 Linux 发行版中创建项目文件夹,并使用安装在 Windows 10 上的 Visual Studio 代码编辑器作为我们的 ide。
所有的特性都在那里:对 IntelliSense 的全面语言支持,git 集成,我们知道并喜欢的 Visual Studio 代码扩展,调试器和终端。所以,把手弄脏,开始编码吧!
Docker + Kubernetes
Docker for Windows 不错,但并不伟大。这是我最想念的东西,每当我需要为我的代码构建 docker 映像时,它就让我在 Windows 和 Ubuntu 之间切换。但是 WSL 2 提供了完整的 docker 支持,在我看来,这甚至比纯 Linux 体验更好。
要启用它,导航到 Docker 桌面设置并启用Use the WSL 2 based engine
选项。
为 WSL 2 启用 Docker
此外,您可以运行本地 Kubernetes 集群,方法是导航到设置的Kubernetes
部分并勾选复选框。
在 WSL 2 上启用 Kubernetes
你现在可以返回到 WSL 2 上的 Ubuntu,运行docker version
或kubectl version
并看到这两个已经启动并运行了。
运行在 WSL 2 上的 Docker 和 Kubernetes
额外收获:新的 Windows 终端
额外的好处是,你可以安装新的 Windows 终端。商店描述将新的 Windows 终端定义为一个现代的、快速的、高效的、强大的和多产的终端应用程序,供命令行工具和 Shell(如命令提示符、PowerShell 和 WSL)的用户使用。它的主要功能包括多个选项卡,窗格,Unicode 和 UTF-8 字符支持,GPU 加速文本渲染引擎,以及自定义主题,样式和配置。
此外,它非常漂亮,您可以通过它的可访问设置(只是一个 JSON 文件)来设计它的风格。在这里寻找灵感!有关新 Windows 终端的更多信息,请点击此处:
新的 Windows 终端在一个智能和高度可定制的包中结合了一切。
towardsdatascience.com](/new-windows-terminal-the-best-you-can-have-9945294707e7)
路标
仍然缺少一些特性,但是 WSL 2 已经走上了正确的道路。在接下来的几个月里,您将能够用一个命令安装 WSL。只需打开一个 Windows 终端,输入wsl.exe --install
。此外,首次安装时,WSL 2 将是新的默认设置。
但是有两个特性是开发者最期待的:GPU 支持和 GUI app 支持。
自 WSL 1 发布以来,向 WSL 添加 CUDA 和/或 GPU 计算支持是最受欢迎的特性。在过去的几年里,WSL、虚拟化、DirectX、Windows 驱动程序团队和其他合作伙伴一直在努力开发这一工程特性。敬请关注!
在 WSL 2 上训练深度学习模型(启用 CUDA)
此外,对 Linux GUI 应用程序的支持也即将到来。例如,您将能够在已经安装的 Linux 环境中运行您首选的 Linux GUI 文本编辑器或 IDE。你甚至可以在你的 Windows 机器上开发 Linux GUI 应用程序!
WSL 2 的 Linux GUI 支持
结论
在这个故事中,我们看到了 WSL 2 如何将您的 Windows PC 变成运行 Linux 发行版的开发人员工作站。速度已经有了,功能也有了,更多的功能即将出现,因此,我认为双引导已经死了!
学习率是我每周给那些对 AI 和 MLOps 世界好奇的人发的简讯。你会在每周五收到我关于最新人工智能新闻、研究、回购和书籍的更新和想法。在这里订阅!
关于作者
我叫 Dimitris Poulopoulos ,我是一名为 BigDataStack 工作的机器学习研究员。我也是希腊比雷埃夫斯大学的博士生。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲中央银行、经合组织和宜家等主要客户设计和实施人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据操作的帖子,请在 twitter 上关注我的 Medium 、 LinkedIn 或 @james2pl 。
DuckDB —用于数据分析的 SQLite
SQLite 是世界上最流行的数据库,非常适合事务处理,但对于分析来说,DuckDB 更快
照片由 Unsplash 上的agency followeb拍摄
当我写 Python Pandas 和 SQLite,forward Data Science 的时候,我并不知道另一个嵌入式数据库系统叫做 DuckDB。在文章发表一天左右,我收到了一条关于它的推文,所以我想我应该看看它。
DuckDB 并不像 SQLite 一样内置于 Python 中,但是在简单安装之后,您几乎不会知道其中的区别。
除了有一点不同。DuckDB 开发人员声称他们的数据库系统比 SQLite 的分析应用快 10 倍。当然,在数据库的设计中有这样的技术原因,但主要原因是有两种应用程序类型的关系数据库:联机事务处理(OLTP)和联机分析处理(OLAP)。
OLTP 应用程序通常是为响应外部请求而修改数据库表的业务流程。一个银行系统就是一个例子:人们取出钱,放入钱,他们的余额一直上下波动,这意味着数据库中的数据不断变化,以响应正在发生的交易。跟踪销售和库存水平的数据库可能会在商品销售给客户或从供应商处收到商品时进行类似类型的数据更新。
本质上,OLTP 系统花费大部分时间在数据库表中插入、删除和更新行。
OLAP 的系统没有那么有活力。它们更像是数据仓库。数据被存储起来,但不会经常改变。主要的操作类型是选择、读取、比较和分析数据。在线零售商可能会分析客户的购买数据,将其与其他客户进行比较,并尝试分析相似性。通过这样做,他们可以尝试预测个人的偏好,这样网站的访问者就可以获得个性化的体验。
OLAP 系统倾向于把大部分时间花在处理数据列、求和、寻找均值之类的事情上。
尽管数据库系统都具有相同的基本功能,但那些为 OLTP 设计的数据库系统在 OLAP 应用程序方面不太好,反之亦然,这是由于数据存储的方式—更容易访问列或更容易访问行。
所以 SQLite 适合 OLTP,DuckDB 更适合 OLAP。
您可以通过进行 pip 安装来试用我的原始文章:
pip install duckdb
并将代码的第一行从
import sqlite3 as sql
到
import duckdb as sql
代码的其余部分应该像以前一样工作。
不要期望在我在那篇文章中介绍的简单代码的操作中看到太多的不同,但是如果您需要做任何繁重的数据分析,那么您可能会发现 DuckDB 是一个更好的选择。
我以后会写更多关于这个话题的文章,但是现在,感谢你的阅读和快乐的数据分析。
声明:我与 DuckDB 或其开发者没有任何联系
如果你想了解未来的文章,请订阅我的免费简讯。
使用 Tensorflow 2.x 决斗双深度 Q 学习
用 TensorFlow 2.x 实现决斗式双深度 q 学习
在本文中,我们将了解决斗双深度 q 学习的概念和代码。这涉及到一些应用于深度 Q 学习方法的改进技术。让我们首先理解这个方法背后的概念,然后我们将研究代码。
双 DQN
这种方法解决了 DQN 高估的问题。这种高估是由于在 Q 学习更新等式中存在下一个状态的最大 Q 值。Q 值上的最大值算子导致最大化偏差,这可能导致代理在某些环境中的不良性能,在这些环境中,真实值的最大值为零,但是代理的最大估计值为正。
双 Q 学习更新,图像通过强化学习:
理查德·萨顿和安德鲁·g·巴尔托介绍
我们将在代码中使用上述等式的深度 RL 版本。
决斗 DQN
在决斗 DQN,有两种不同的估计如下:
- 估计给定状态的值:这估计代理处于该状态有多好。
- 对一个状态中每个动作的优势进行估计。
我们的 DDDQN
这两个估计值可以汇总为[Q = V+A-所有 A 的平均值]
使用 Tensorflow 2.x 的代码
神经网络:
- 我们从使用 TensorFlow 子类 API 定义 DDDQN 类开始,注意我们使用了两个密集层,因为我们有数字输入。您不需要指定任何输入形状。
- 请注意,我们的调用函数的状态值为“v ”, advantage 为“and Q 是聚合。
- 我们还为动作选择定义了一个优势方法。
体验回放:
- 我们的经验重放类包含两个方法,一个用于存储经验,另一个用于获取训练样本。
- 我们首先将内存定义为全零初始化的 numpy 数组。请注意,数据类型应该根据环境而定。
- 我们有一个指针,从零开始,每次存储经验时递增。请注意,索引是通过取模来定义的,因为索引永远不会超过缓冲区的大小。
- 在采样方法中,我们首先检查缓冲区是否已满,并且仅从可用的经验中进行采样。这是因为我们不想采样零值进行训练。
代理人:
我们的代理类包含以下方法:
初始值设定项:
- 我们首先定义所有需要的变量,并编译我们的目标网络和 q 网络。
- self.trainstep 用零初始化,它记录我们的 q 模型被训练的次数。
- self.replace 用于在目标网络中复制 q 个网络权重。我们将在培训方法中使用这一点。
行动选择方法:
- 我们希望我们的代理选择当时的最佳行动,但我们也希望我们的代理探索其他行动的优化。为此,我们采取随机行动,直到随机值小于或等于ε。
- 如果随机值大于ε,我们通过使用模型中的优势方法采取最佳行动。
更新 _ε,更新 _ 记忆,更新 _ 目标:
- update_epsilon 用于每次训练后更新 epsilon 值。请注意,epsilon 的最小值可以是 0.01,就像前面在 init 方法中指定的那样。
- Update_mem 充当连接器 b/w 代理,并在体验重放中存储体验方法。
- Update_target 用于用 q 个网络权重更新我们的目标模型。
DDDQN 训练方法:
- 训练方法用于为 q 值训练我们的 q 网络。
- 该方法以一个条件开始,即直到经验缓冲区具有至少批量大小的足够数量的经验,训练才会开始。
- 下一个条件在 q 网络被训练自替换次数后,每次更新目标网络。
- 然后我们抽样一批经验。这些样本批次是状态、动作、奖励、下一个状态和完成变量 numpy 数组。
- 然后由 Q 网络和目标网络分别预测当前状态和下一状态的 Q 值。用于执行此任务的代码将一组状态作为输入,并返回一组预测。
- 然后我们用 q 网络计算下一个状态的 q 值最大的动作。注意,我们没有使用优势法。
- 然后,我们计算批索引并执行更新操作。注意 本次更新使用双 DQN 更新,即我们根据下一状态下的 q 网络,为具有最大 q 值的动作放置由目标网络预测的 q 值,而不是下一状态的最大 q 值。
- 更新等式乘以 done 变量,因为对于终端状态,q 值总是零。
- 然后,我们训练模型,更新ε,并增加训练步长。
重要提示:这里使用了 numpy 数组,不需要循环。
重要提示:我们没有在训练方法中使用优势方法。我们只对动作选择而不是 q 值使用优势方法。
代理培训:
- 在下面的代码中,代理与环境交互并进行更新。
你可以在这里找到这篇文章的代码。为了更好地理解,您还可以在同一个存储库中查找 DQN 文件。
感谢你阅读我的文章,希望你喜欢并且能够理解我想要解释的东西。希望你阅读我即将发表的文章。哈里奥姆…🙏
参考资料:
显着扩大和更新的广泛使用的文本强化学习的新版本,最…
mitpress.mit.edu](https://mitpress.mit.edu/books/reinforcement-learning-second-edition) [## 菲尔的机器学习
你好。在 Neuralnet.ai,我们涵盖了各种主题的人工智能教程,从强化…
www.youtube.com](https://www.youtube.com/channel/UC58v9cLitc8VaCjrcKyAbrw) [## 用于深度强化学习的决斗网络架构
近年来,在强化学习中使用深度表征取得了许多成功。尽管如此,许多…
arxiv.org](https://arxiv.org/abs/1511.06581)
转储 Keras-ImageDataGenerator。开始使用 TensorFlow-tf.data(第 2 部分)
停止使用 Keras-ImageDataGenerator,因为…
本文是第 1 部分的后续。这里,我将使用mobilenet
模型比较tf.data
和Keras.ImageDataGenerator
的实际训练时间。
[## 转储 Keras-ImageDataGenerator。开始使用 TensorFlow-tf.data(第 1 部分)
停止使用 Keras-ImageDataGenerator,因为…
medium.com](https://medium.com/swlh/dump-keras-imagedatagenerator-start-using-tensorflow-tf-data-part-1-a30330bdbca9)
作者照片。来自 YouTube 视频
在第 1 部分中,我展示了使用tf.data
加载图像比使用Keras.ImageDataGenerator
大约快 5 倍。考虑的数据集是Kaggle-dogs _ and _ cats(217 MB),具有分布在 2 个不同类中的 10000 张图像。
在第 2 部分中,我考虑了一个更大的数据集,它通常用于图像分类问题。所选择的数据集是coco 2017(18gb),具有分布在 80 个不同类别中的 117266 张图像。COCO 数据集的各种版本都可以在这个链接免费试用和测试。选择更大的 18 GB 数据集的原因是为了获得更好的比较结果。对于实际的图像分类问题,数据集甚至可以更大,从 100 GB(千兆字节)到几 TB(兆兆字节)。在我们的例子中,18 GB 的数据足以理解比较,因为在 TB 中使用数据集将显著增加训练时间和计算资源。
训练次数结果(提前)
以上结果是在使用 TensorFlow 2.x 的 GPU 版本的具有 16 GB RAM、2.80 GHz with Core i7 的工作站上进行比较的。考虑的数据集是coco 2017(18 GB),具有分布在 80 个不同类中的 117266 个图像。
- 当使用
Keras.ImageDataGenerator
时,在使用 COCO2017 数据集的每个历元的训练期间,花费了大约 58 分钟。 - 将
tf.data
与变量cache=True
一起使用时,程序崩溃。这个崩溃背后的原因是所考虑的数据集(大小 18 GB)比工作站的 RAM 大。使用cache=True
,程序开始将图像存储在 ram 中以便快速访问,当图像超过 RAM 时(在我们的例子中是 16 GB),程序就会崩溃。我在一个更小的数据集 Kaggle- dogs_and_cats 上测试了相同的选项,效果很好。这表明,当考虑的数据集的大小大于 RAM 时,我们不应该使用cache=True
选项。 - 当使用带变量
cache=False
的tf.data
时,程序需要大约 23 分钟,比Keras.ImageDataGenerator
快 2.5 倍。 - 当使用
cache='some_path.tfcache'
时,在第一个时期tf.data
将在您的计算机目录中进行数据集/图像的转储。这就是为什么它在第一个时期比较慢,大约需要 42 分钟。在连续的历元中,它不必在计算机上再次存储图像,而是在第一个历元中使用已经创建的转储,这最终加快了训练时间。在连续的历元期间,每个历元仅花费 14 分钟。创建转储只有一次过程。对于超参数调谐,大约需要 14 分钟,相比之下需要Keras
58 分钟,大约快 4.14 倍。
注意:使用
cache='some_path.tfcache'
时在内存中创建的转储大约为 90 GB,这实际上远远大于数据集的原始大小(18 GB)。我不能确切地理解这一点的原因,因为没有来自 TensorFlow 的关于这一点的明确文档。希望这是以后整理出来的 glich。对于像 Kaggle- dogs_and_cats 这样只有 217 MB 的较小数据集,在速度或训练时间上与
tf.data
和Keras
不会有明显的差异,因为 RAM 足够大,可以一次存储所有图像。
培训模型代码
这里显示了创建和训练模型的初始代码。预训练模型mobilenet
用于执行迁移学习,预训练模型的基础层被冻结。
所有代码放在一起
在这里,我将第 1 部分和第 2 部分的代码结合起来。函数的注释和文档字符串将有助于理解代码。
结论
这篇文章表明,对于任何实际的图像分类问题,tf.data
比Keras.ImageDataGenerator
快倍 2.5 (when using cache=False)
到 4.14 (when using cache=**
**some_path.tfcache)
。我认为值得一试tf.data
。
搜索引擎优化和营销的预测分析
使用 Python 进行关键字研究
布雷特·乔丹在 Unsplash 上的照片
概观
Dunkin donuts 的市场部(MD)注意到,在过去的 6 个月中,他们的一些关键词排名下降了。因此,他们正在进行一个新的 SEO 项目,专注于在谷歌上排名第二的关键词。为此,将使用训练数据来开发预测模型,以预测有可能为网站带来最大流量的关键词。这些关键词将在接下来的六个月里成为一个全面的 SEO 项目的重点。
通过将预测模型应用于训练数据,将利用数据科学方法来解决这一业务问题,训练数据将包括除第 2 页排名之外的所有关键词。然后,结果将被应用到第 2 页的排名,以确定最好的关键字集中。成功将取决于在一年内将关键字排名提高到谷歌的第一页。
数据
总经理可以从塞姆拉什获取邓金的 10000 条关键词记录。这些数据包括:
关键词
位置
以前的职位
搜索量
关键词难度
CPC
URL
交通
流量(%)
交通成本
竞争
方法
1.从 SEMRush 导出关键字数据
2.从数据中提取第二页排名作为应用程序。
3.将数据分成 80/20 个训练测试集。
4.执行 EDA 以了解数据
5.创建 Tableau 仪表板以显示 EDA
6.基于训练数据的训练预测模型。
7.评估测试数据的性能
8.应用于第二页等级数据
9.确定第二页的关键词,集中搜索引擎优化的努力
可交付成果
数据清理和 EDA 代码
模型拟合代码
EDA 的 Tableau 仪表板
描述建议的报告
数据争论
数据争论过程将包括以下步骤:
- 加载必要的包
- 加载数据
- 查看数据和元数据
- 删除不必要的列
**import** **pandas** **as** **pd**
**import** **matplotlib.pyplot** **as** **plt**
**import** **seaborn** **as** **sns**
**import** **datetime**
**import** **numpy** **as** **np***# setup*
*#sns.set_style(style="whitegrid")*
sns.set_style('ticks')
*# display charts inline*
%matplotlib inline
*# to display all columns*
pd.set_option('display.max_columns', **None**)
*# setup*
*#sns.set_style(style="whitegrid")*
sns.set_style('ticks')
*# display charts inline*
%matplotlib inline
*# to display all columns*
pd.set_optdf.head()
ion('display.max_columns', **None**)Data is available here: [https://github.com/meagvo/DunkinDonutsSEOproject/blob/master/dunkin.csv](https://github.com/meagvo/DunkinDonutsSEOproject/blob/master/dunkin.csv)*#load the data*
df=pd.read_csv('dunkin.csv')
*#look at the column names*
df.columns
*#metadata 15 columns 10000 records*
df.info()
*#missing data for SERP Features by Keyword, but this column will be dropped because it isn't relevant for the analysis*
删除不必要的列
我们对大多数列值感兴趣,但是有几个对当前的分析没有帮助。因此,我们将删除以下两列:
- 趋势
- 按关键字排序的 SERP 特征
*#drop two columns*
df.drop(df[['Trends', 'SERP Features by Keyword']], inplace=**True**, axis=1)
探索性数据分析
df.describe()。T
可视化数据:散点图
plt.scatter(df['Position'], df['Previous position'])
plt.title("Position vs. Previous Position")
plt.xlabel('Position')
plt.ylabel("Previous Position")
plt.show()
从散点图可以清楚地看出,大多数位置与先前的位置相关,这意味着它们是稳定的。不过有一些看起来是排在 0 的,没什么意义。那一定意味着他们排不进前 100 位。因此,我们希望将重点放在前两个 SERPs 上。
让我们想象一下排在谷歌前 2 页的关键词/页面。
这些都是密切相关的。
plt.scatter(df['Position'], df['Previous position'])
plt.title("Position vs. Previous Position")
plt.xlabel('Position')
plt.ylabel("Previous Position")
plt.xlim(1, 20,)
plt.ylim(1, 20)
plt.show()
corr matrix = df . corr()SNS . heat map(corr matrix,annot= True ,cmap = ' RdBu ')PLT . fig(figsize =(20,20)) plt.show()
看起来流量、流量百分比和流量成本是共线的。因此,在分析中最好只包括其中一种方法。我们将分析流量原始指标。所以现在,我们将降低流量百分比和流量成本。
df.drop(columns=['Traffic (%)',' Traffic Cost'],inplace= True )
基线模型
作为该预测模型的简单模型,我们选择了多元线性回归。这是一个概念上的基本模型,与其他预测模型相比,解释相对简单。此外,随着研究问题的发展,我们可以将该模型应用于其他感兴趣的目标变量。'
在这个多元回归模型中,我们必须对数据进行预处理。对于连续变量,这意味着分别通过平均值和标准偏差对数据进行居中和缩放,但对于分类数据,这包括创建虚拟变量。
然后我们去掉包含任意日期的变量,比如时间戳。这在回归环境中很难处理。
关键字列将被分隔,因为它是标签列。这将从预处理数据中删除,因为它不会输入到回归模型中。
df1=df.drop(columns=’Keyword’) keyword=df[‘Keyword’] df1.head() df1.drop(columns=’Unnamed: 0')
df1.columns
continuous_var=df1.drop(columns='URL')
continuous_var.drop(columns='Unnamed: 0', inplace=**True**)
continuous_var.head()
cat_var=['URL']
预处理
连续变量将被缩放和居中,因为当所有变量具有相似的平均值和方差时,许多预测模型表现更好。此外,我们确保没有丢失的行或列,这是我们已经确定的。接下来,自变量被放入数组(x)中,目标变量(位置)被放入第二个数组(y)中。
scaler = StandardScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(continuous_var))
df_scaled.columns
df_scaled.head()
df_scaled.columns=[ 'Position', 'Previous position', 'Search Volume',
'Keyword Difficulty', 'CPC', 'Traffic', 'Competition',
'Number of Results']
df_scaled['URL'] = df1[cat_var]
df_scaled.head() df_new = pd.get_dummies(df_scaled,dummy_na=**True**) X=df_new.drop(columns='Position') y=df_new['Position']
训练和测试模型
接下来,我们将数据分为训练集和测试集。训练集将用于交叉验证模型的超参数,测试集将用于验证模型。
首先,我将使用默认参数创建一个模型。
*#Split into test/train*
X_train, X_test, y_train, y_test= train_test_split(X, y, test_size=0.33, random_state=42)
*# with sklearn*
regr = LinearRegression()
regr.fit(X_train, y_train)
y_pred=regr.predict(X_test)
explained_variance_score(y_test, y_pred)
看起来 URL 列扭曲了模型。现在让我们尝试删除 URL 列并再次运行模型。
df_scaled.drop(columns='URL', inplace=**True**)
X2=df_scaled.drop(columns='Position')
y2=df_scaled['Position']
*#Split into test/train*
X_train2, X_test2, y_train2, y_test2= train_test_split(X2, y2, test_size=0.2, random_state=42)
*# with sklearn*
regr2 = LinearRegression()
regr2.fit(X_train2, y_train2)
print('Intercept: **\n**', regr2.intercept_)
print('Coefficients: **\n**', regr2.coef_)
y_pred2=regr2.predict(X_test2)
explained_variance_score(y_test2, y_pred2)*# Calculate the absolute errors*
errors = abs(y_pred2 - y_test2)
*# Print out the mean absolute error (mae)*
print('Mean Absolute Error:', round(np.mean(errors), 2), 'degrees.')
*# Calculate mean absolute percentage error (MAPE)*
mape = 100 * (errors / y_test2)
*# Calculate and display accuracy*
accuracy = 100 - np.mean(mape)
print('Accuracy:', round(accuracy, 2), '%.')
这大大改进了模型。但是我们有可能做得更好。让我们试试随机森林回归。
*# Import the model we are using*
**from** **sklearn.ensemble** **import** RandomForestRegressor
*# Instantiate model with 1000 decision trees* rf = RandomForestRegressor(n_estimators = 1000, random_state = 42) *# Train the model on training data* rf.fit(X_train2, y_train2); *# Use the forest's predict method on the test data*
predictions = rf.predict(X_test2)
*# Calculate the absolute errors*
errors = abs(predictions - y_test2)
*# Print out the mean absolute error (mae)*
print('Mean Absolute Error:', round(np.mean(errors), 2), 'degrees.')
*# Calculate mean absolute percentage error (MAPE)*
mape = 100 * (errors / y_test2)
*# Calculate and display accuracy*
accuracy = 100 - np.mean(mape)
print('Accuracy:', round(accuracy, 2), '%.')
分析
获胜的模型是随机森林回归,因为它具有最低的 MAE 和最高的准确性。它还删除了 URL 列,该列似乎扭曲了第一次回归的结果。这将允许我们预测 Dunkin Donuts 的新关键字的位置。下一步是继续 Answerthepublic 和 Google Keyword Planner,提取相关的关键词,然后将信息插入这个模型,以确定哪个有可能在 Dunkin 中排名最高。然后,MD 可以通过全面的 SEO 活动来重点推广该关键词。
杜特尔特演讲的自然语言处理分析
第一部分:搜集杜特尔特总统的演讲
鉴于不同国家新冠肺炎的现状,各国政府加紧解决疫情问题的紧迫性进一步提高。菲律宾的情况也没有什么不同,因为罗德里戈·杜特尔特总统向菲律宾人民发表新闻发布会的频率已经上升。这启发了我去做一个个人项目,用自然语言处理(NLP)来分析他多年来的演讲。
当然,在我分析他的演讲之前,我需要先实际收集它们。这是杜特尔特演讲分析的 Part 1 ,将重点刮杜特尔特的演讲。本系列的后续文章将集中使用 NLP 来分析它们。对于我编写的代码,请查看我的 GitHub 库——尽管我承认我的代码在这里有点乱——如果你有任何意见或建议,请留下。最后,我还将更新我的自述文件,说明如何运行 Python 程序。
对我来说幸运的是,该国的总统通信运营办公室(PCOO)在他们的网站上发布了他的演讲,至少到某一点为止(页面显示它有 31 页,但如果你浏览超过某一页码,它会返回一个“找不到页面”的错误)。因此,我收集的演讲仅从 2020 年到 2018 年。
对于演讲的抓取,我主要使用了BeautifulSoup4
和requests
Python 库,同时还使用了pandas
来构建数据集,python-dotenv
用于环境变量,以及一些用于从 pdf 中提取文本的库。
抓取 PCOO 网站
最初,当我试图使用requests
库向 PCOO 网站发出 GET 请求时,由于某种原因,我一直收到一个连接错误。经过进一步的研究,我发现这是因为一些网站,包括 PCOO 的,普遍不喜欢机器人爬满它们。你可以通过访问他们的 robots.txt 看到这一点,显示了以下针对禁用机器人的设置。
User-Agent: *
Disallow:
因此,我不得不执行几个额外的步骤,作为克服针对机器人的设置的措施,以及为了防止我的 IP 地址被列入黑名单的预防措施。首先,我必须将我的机器人程序伪装成人类,方法是为我的每个请求附加一个 用户代理 ,我将它存储在我的.env
文件中(因此我安装了python-dotenv
)。其次,如果一个 IP 地址以极快的速度向一个网站发出 GET 请求,那就太明显了,所以我使用time.sleep
将每个请求分散 15 秒,让它看起来更人性化。不可否认,这增加了刮擦时间,但是稍后我会解释我是如何大大加速这个过程的。
Python 刮刀的主程序。这个主程序以每页的速度进行抓取。
上面的片段显示了在01_scraper.py
文件中找到的主程序的一部分,它抓取了网站每页的演讲。每页包含 20 篇演讲,在我的程序中,我将其中的每一篇都称为row
。每篇演讲都会将你带到演讲详情页面(示例),其中包含音频、完整的文字记录,可能还有新闻发布会的视频。完整的文稿会将您重定向到一个 PDF 格式的演讲文稿(示例)。
PCOO 网站发言截图
我在我的scraper_functions.py
中创建了一个名为extract_page
的函数,它使用上述过程处理每一行,并返回一个包含标题、演讲日期和提取文本的字典。
下一个问题是,我如何从 pdf 中提取文本?
PDF 提取:使用哪个库?
如果我想尝试更多的 PDF 库,为了减少抓取时间,我将 PDF 保存在我的存储库中。这样,我就不用再费力地浏览 PCOO 网站了。之后,我找到了四个用于从 pdf 中提取文本的 Python 库:
最初,我用的是PyPDF2
,但对于一些演讲,它只能提取空的新行,所以它会以类似\n\n\n\n\n\n\n\n
的东西结束。因此,我使用 regex 为创建了一个函数来检查提取的文本是否返回一个没有单词的字符串。如果函数返回了True
,那么我使用slate3k
来提取该语音。尽管如此,这个图书馆有时还是会有错误的结果,比如完全遗漏了演讲的某些部分,并且奇怪地将一些演讲的文本中的每个字母隔开。尽管如此,我还是使用PyPDF2
和slate3k
将所有结果编译成一个csv
。
接下来,我试用了tika
,因为我在试图分析时,对之前的结果太失望了,它的效果非常好。事实上太漂亮了,以至于我没有机会试用PDFPlumber
(所以如果你以前用过它,一定要让我知道它是否有同样的功能!).在提取所有内容时没有发现错误,所以使用这个库的过程非常顺利。我已经决定在我的分析中使用tika
结果,而不是其他三个包。
从 pdf 中提取文本的功能
多重处理
我在上面提到过,每个演讲有两个抓取阶段:演讲详情页面和 PDF 文稿页面,总计每个演讲超过 30 秒的抓取。鉴于每页有 20 篇演讲稿,我们要花 10 多分钟(加上另外 15 秒来抓取页面本身)才能提取一页中的所有演讲稿。大约有 21 个有效页面,所以理论上总共需要 210 分钟或者大约 3.5 小时来提取它们。然而,实际上我花了大约一周的时间来完成刮擦,因为在使用PyPDF2
和slate3k
时出现了许多错误。
这让我探索多重处理来加速整个过程,而不是使用tika
作为我的 PDF 提取器,并且它工作奇迹。
多重处理程序
由于我在第一次试运行时无法在本地保存 pdf,我不得不重新开始整个抓取过程。但是有了多重处理,我可以让多个工作人员同时处理同一组数据(在这种情况下,每页 20 篇演讲),而不是必须依次处理每篇演讲。
使用代表工作进程池的Pool
对象,我能够将数据(每页 20 行数据)映射到工作进程,工作进程同时运行extract_page
功能。在所有的工作完成之后,由函数返回的 20 个字典的列表被附加到正在工作的pandas
数据帧中。我还包含了一个文本文件,用于记录我处理的每个演讲(我在第一次试运行时也是这样做的)。
我用我的scrape_logs.txt
比较了第一次和第二次试运行时抓取一整页所用的总时间,差异明显。对于第一次试运行,完成一个完整的页面需要 13-20 分钟,而我的第二次涉及多处理的试运行只需要 4-5 分钟。这也要感谢tika
库的顺利运行,我在提取文本时没有遇到任何错误(尽管我确实遇到了这个与多重处理相关的奇怪的递归限制错误,我通过添加sys.recursionlimit(10000)
纠正了这个错误)。总的来说,多重处理试运行只持续了大约 1.5 小时!
我对 PDF 提取本身也很满意,看到使用tika
获得的文本中只有微不足道的错误。因此,我选择不再继续进行PDFPlumber
了。
总的来说,我成功地抓取了 PCOO 网站,以便收集杜特尔特的演讲,并将它们汇编成一个csv
文件,通过整合多重处理进一步加快了整个过程。
对于第 2 部分(可能还有第 3 部分),我将尝试分析我使用 NLTK 和 TF-IDF/N-gram 等 NLP 工具收集的数据。同样,请随意浏览我的 Github 库,如果您有任何意见或建议,请在下面留下!我将非常感激。
Python 中数据类型和变量的动态分配
数据科学/ Python 编程语言
让我们看看如何在 Python 中动态分配数据类型和变量,同时遍历一个循环。
假设你有一个包含 10 个元素的列表(list_main)。你必须把它分成三部分。第一部分分配给 list1,第二部分分配给 list2,第三部分分配给 list3。列表的这种划分或分割类似于 K 重交叉验证。对于外行来说,交叉验证是一个重新采样的过程,用来评估预测模型在实践中的准确性。在 K-fold 交叉验证中,数据集被分为训练数据(通常为 80%)和测试数据(通常为 20%,并将保持不可见的数据)。训练数据再次被分成 k 倍或分区,这又被认为是训练数据和验证数据。该模型将在训练数据上被训练,并且该模型的验证将使用验证数据来完成。
下面的代码将列表分成 3 个分区或部分,并将每个部分的元素分配给一个列表。
list_main = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
folds = 3
section = int(len(list_main)/folds)
start_index = 0
end_index = 0
counter = 1for i in range(folds):
if counter == 1:
end_index += section
list1 = list_main[start_index:end_index]
counter += 1
elif counter == folds:
list3 = list_main[end_index: ]
counter += 1
elif counter < folds:
start_index = end_index
end_index += section
list2 = list_main[start_index:end_index]
counter += 1
print(f'List1: {list1}')
print(f'List2: {list2}')
print(f'List3: {list3}')list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [7, 8, 9, 10]
输出:
List1: [1, 2, 3]
List2: [4, 5, 6]
List3: [7, 8, 9, 10]
但是,代码不是通用的,更像是硬编码类型。例如,如果 list_main 的划分(折叠)数量增加到 4,则需要另一个列表(list4)来存储列表元素。如果增加到 6 个,则总共需要 6 个列表。为了适应基于分区数量的变化,需要更改代码。具体来说,需要分配新的列表。然而,这导致了更多的复杂性和混乱。例如,如果 folds=4,那么第二个分区和第三个分区在上面的代码中具有相同的条件(计数器< folds).
©iambipin
It would have been better if we write a generic code that can allocate lists as the number of folds increases or decreases. The globals() function in Python made the seemingly impossible job possible. It returns the global symbol table as a dictionary.
print(globals()){'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x02A8C2D0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'demo_ref_globals.py', '__cached__': None, 'x'_ {...}}
The modified code:
The output:
Enter the no. of folds: 5
List 0: [1, 2]
List 1: [3, 4]
List 2: [5, 6]
List 3: [7, 8]
List 4: [9, 10]
You can do this dynamic allocation(frankly speaking, I don’t know the appropriate term for the allotment of data types)with other data types like variables, tuple, set, etc. You can find the codes 这里是)。
我们都在经历艰难时期。不确定性笼罩着未来。然而,每片乌云都有一线光明。疫情对地球的治愈程度超过了环保主义者的任何其他任务。所以我忍不住分享了我在 WhatsApp 上收到的朋友转发的这个很棒的迷因。我真的想感谢这个迷因的未知创造者,感谢他的创造力和对我们生活的世界的残酷现实的描绘。
来源:互联网(来源不明)
当世界正一瘸一拐地走过一个流行病已经达到巨大规模的前所未有的时代时,我们人类别无选择,只能求助于社交距离(每当我们冒险外出寻找必需品时)并呆在家里。当你处于自我隔离状态时,提升你的技能,学习新的东西。希望你能学到新的东西。编码快乐!!!
如何在 Vuejs 上实现动态组件
了解轻松创建模块化应用程序的解决方案
单页应用程序现在是大多数情况下的标准。从表现中分离业务逻辑在效率和质量方面带来了巨大的优势。事实上,大多数框架构建了一组静态文件,这是降低托管或部署复杂性的一个额外好处。这些特征对于企业应用程序来说是很好的,但是当我开始开发 RawCMS 的前端时,我发现这些特征非常有限。事实上,我需要一个模块化的系统,贡献者可以在没有任何限制或构建任何东西的情况下向界面添加功能。在这篇文章中,我将回顾我提出最终解决方案的步骤。
剧透:我用 Vuex 和普通 javascript 结束了 VueJs。结果是一个从任何公共 URL 加载组件的动态引擎,如果我可以从头开始,我会再次做出同样的决定😆
我需要的
在像 headless cms 这样的产品上工作,你想让人们扩展平台开发他们自己的模块是一个挑战。在前端部分,我被说服使用水疗方法,我习惯了玩角,但有一个挑战。构建完成后,动态加载组件、扩展 UI(如添加菜单项或路由)并不容易。
这就是为什么当我和莱昂纳多·马库奇开始着手这项工作时,我们记录了一些市场提供的技术机会。
我们发现了三种主要的解决方案,每一种都有利弊。
使用 Iframes
此解决方案包括部署多个 SPA,并使用一个中央 SPA 来管理外壳。因此它可以根据模块的数量(SPA 部署)加载菜单项。我放弃了这个解决方案,因为我害怕 iframe 的局限性和模块之间的交互。我担心像这样的解决方案只不过是一个链表。
Web 组件
我发现了一些关于 web 组件的好观点。对于我所寻找的,web 组件是一个很好的解决方案,但我会使用易于使用的技术解决方案,并广泛用于防止来自社区的拒绝,在我做出这个选择的时候,像 StencilJs 这样的解决方案还很年轻。
利用我们所拥有的来玩
最终的解决方案是使用广泛使用的库,让我不用构建就可以开发一个 SPA,并且可以动态加载新的插件。这非常简单,只需要使用 VueJs 天生给我们的东西。不信?只看下一章。
我们如何制作 VueJs 水疗模块
最后的决定是使用普通 VueJs,因为它允许我们在没有构建过程的情况下做伟大的事情。限制一点浏览器兼容性,我们可以使用 ES6,利用许多强大的功能,如承诺、阵列自动化等。在我们的例子中,该产品是为开发人员设计的,所以我们认为强迫他们使用 Chrome、Firefox 或 Edge 等现代浏览器并不是一个很大的限制。此外,如果一个开发者想继续使用 IE6,我们可能有一个比安装一个使用这个无头 cms 的浏览器更大的问题要解决。
所以,VueJs 是被选中的框架,然后我们有一系列的挑战来使它工作。在这一章中,我试图重新回顾所有将我们带到最终版本的步骤。
第一块砖:动态文件加载
我们首先使用的是动态加载 javascript 模块的机会。基本上,以下选项是等效的:
import {MyDefaultComponent} from '/MyDefaultComponentFile.js'//orconst filePath='/MyDefaultComponentFile.js';
import(filePath).then(x => x.default());
其中, MyDefaultComponent 是这样声明的:
import { XanderCage} from '/xxx.js';
const _myComponentInstance = function(){
//Declare your component here
};export default _myComponentInstance;
import 语句也可以以编程方式调用,使整个解决方案动态化,如下所示:
上面的代码片段是 RawCMS 引导模块调用 API 返回注册模块列表的地方。在这个特定的例子中,我将它们都添加到一个列表中,然后我一起解析所有的承诺,以确保在 init 阶段之前加载所有的承诺。可以对他的原始代码进行改进或优化,但这是我稍后将讲述的所有内容的基础。
组件集成
正如您在上一段中看到的,导入仅限于名为“config.js”的文件。这个文件必须放在插件文件夹的根目录下,并且将包含一个带有模块配置的 json 对象。为此,我使用了 Vuex,VueJs 的状态管理框架。这使得事情很容易管理。在主机应用程序上集成所有动态组件的代码只有几行代码:
在上面的例子中,我们通过解析承诺加载了所有模块(第一个模块是宿主应用程序,单独处理)。其他模块通过初始化(使用标准方法)和获取路线集成到应用程序中。
在这一步之后,我们的模块是主应用程序的一部分,可以使用了。
路线
通过将来自模块的单个路由添加到 Vue 路由引擎中,可以自动管理路由。我们只需要一个额外的步骤来管理国际化。这需要根据我们正在访问的路由来加载翻译,因此我们在路由管道上添加了一个链。
这段代码加载所有来自模块的翻译,并将其合并。c 核心标签用作故障转移。
菜单整合
基于模块的定义添加菜单项是一件非常简单的事情,只是一个渲染问题。组件的 js 端只是将来自插件的信息放在一个属性中,以便在模板端进行简单的管理。
在模板上,我们只需要使用材料设计组件来呈现元素。
模块间的通信
两种基本机制允许模块之间的通信
- 事件
- Vuex 状态
通过事件,我们可以通知所有模块有事情发生。因为事件系统是中心的,所有的事件名称都是按名称引用的,所以不存在物理依赖性。所有想要列出给定事件的模块都可以基于它来做和反应,即使它们在模块之外。基于这一原则,当用户登录时,登录组件会通知显示用户徽章的组件,但是您也可以附加您的组件。剩下的由 Vuex 库完成。在下一个代码片段中,登录的例子被翻译成了代码。
什么是 RawCMS.eventBus ?只不过是一个 Vue 组件。看看 RawCMS 的定义就知道了。
最后一点是关于 Vuex 的用法。我将定义 Vuex 模块以及如何从 Vuex 存储器读取/写入数据的代码段添加到代码片段中。
带什么回家
创建模块化 SPA 应用程序是可能的,并且在某些情况下是必需的。我的用例是一个开源的可扩展产品,并不常见,但是你可能会遇到类似的情况。试想一个应用程序太大,无法由一个团队或公司开发。使用事件总线和强大的约定将应用程序分解成模块,使之成为可能。我提出的解决方案是可行的,并且易于实现。使用几个月后,我对它的看法。
亲
- 易于设置
- 易于管理
- 容易理解
- 可以与后端代码集成
- 易于包装和移动
面向连接的网络服务(Connection Oriented Network Service)
- 不容易防止 js 错误(没有构建过程)
- 难以优化(没有构建,谁能负责压缩或最小化 javascript)?
- 不要在旧的浏览器上工作,因为没有任何填充或传输。
在 RawCMS 案例中,一个对开发人员进行评估的产品,UI 只是用来让技术人员建立一个无头 CMS,与采用智能解决方案的好处相比,它的局限性是微不足道的。在企业案例或具有不同类型用户的其他产品中,您可能需要一些额外的工作(可能在 DevOps 方面)来克服实际解决方案的限制。
参考
- raw CMS 项目(Git Hub 源代码)
- (电子书)来自 Andrea Koutifaris 的 Vuex 快速入门指南
- VueJs 主页
- RawCMS UI 的主要撰稿人 Leonardo Marcucci
动态加密货币交易回溯测试平台——Python
你的交易策略盈利了吗?观看 YouTube 系列:https://www.youtube.com/watch?v=PZDFXGIAm2g&t = 953s
allthestock.com
我最近对加密货币日交易非常感兴趣。而在网上快速搜索会返回一系列不同的指标和交易策略,比如均线/均线交叉,RSI 策略,成交量平衡等等。我发现自己从来没有找到一个资源来回答这个问题:“嗯,这真的有用吗?”。坦率地说,不经过数百次甚至数千次迭代测试策略,光看图表是不可能知道这个问题的答案的;对一个人来说,这是一项繁重的任务。我看过其他人的视频和文章,他们试图用手进行回溯测试,点击,输入,计算他们预定的策略所决定的买卖。在某些情况下,只是为了在数小时的回溯测试后找到问题的答案:“不,这个策略行不通。到下一个。”其他更具编程性的回溯测试方法可以加速这个过程,比如 TradingView pine 编辑器,或者一个基本的 python 脚本;但是,如果你想动态地改变止损/止盈水平、你选择交易的加密货币或策略本身的细节,该怎么办呢?回答这些问题需要对简单的回溯测试脚本进行耗时的修改。由于对加密货币交易的最初兴趣,我决定需要一个更好的平台,这个平台在网上任何地方都找不到(我可以免费找到),它将允许我动态迭代任何策略中激起我好奇心的任何更改。我决定学习更多关于动态 python 编程和币安 API 的知识,最终创建一个工具,帮助我这个初学 python 程序员和交易员回答互联网上每个“加密货币交易策略”帖子最前沿的这些问题。
下面是一个交易环境,在这个环境中,所有可能的交易策略都可以以非常动态的方式进行测试,即使是初级 python 程序员也可以创建和回测他们自己的交易想法,并最终给出他们问题的答案。利用该环境并实现您自己的想法的唯一先决知识是:对 python 结构(如 for 循环和 if 语句)的基本理解,对 pandas 的足够了解,以便从数据帧的正确列/索引位置获取适当的价格数据,以及对面向对象编程的潜在低级理解,这取决于您的策略的复杂性。
收集数据
首先,读入数据。在这个脚本中,我们利用了币安 API,该 API 允许从交易所上市的大量加密货币中收集数据。给出的示例是一个单独的脚本,它读取从 2019 年 3 月 28 日到 2020 年 6 月 1 日 12 种不同加密货币的每分钟价格变化,总共有 618,290 个 12 种加密货币的价格实例,结果是一个 211 MB 的数据帧(这可以扩展,但需要一点耐心)。在我的机器上,从币安 API 读取这个数据大约需要。5 个小时完成,但只要简单地写入 csv,就可以在将来使用该脚本时几乎立即检索到。
关于数据读取的一些值得注意的事情:
- 要访问币安 API,只需从命令行安装币安客户端。其他依赖项安装在它们各自的导入行上进行注释。
- 币安客户要求 API 密钥,这些只是实时向币安交易所发送交易订单所必需的,而不是读取数据所必需的。我保留了原来的格式,以防这是任何读者都想要的用例。
- 在收集了每个硬币的数据后,我们让脚本休眠 60 秒。这是为了防止币安 API 因为我们要求太多太快的数据而把我们踢出去。我没有遇到过这种格式的问题,但如果遇到错误,这个时间可能要增加。
- 此处包含一个简单的移动平均函数,以展示如何从价格数据中设计功能并添加到数据框架中。这可以是您选择的自定义函数,也可以是可以在网上找到的普通指示器的函数,如下所示。
- 体积数据也是可用的,但在本例中没有使用。如果感兴趣,请将其添加到第 32 行。
- csv 文件的自定义命名可以在第 72 行的引号中进行编辑。
从币安 API 读取的示例数据
太好了,现在我们有了一个大型加密货币价格数据集。在我们进入交易环境之前,让我们创建一个简单的内存类,它允许我们存储每个回溯测试的信息。
内存
这个类非常简单明了;一个简单的内存对象,允许我们添加买/卖动作,也可以在每集之后清除内存。
现在我们有了数据和内存对象,让我们进入交易环境。
我们的环境接受两个参数:我们刚刚创建的数据框架以及您希望包含在回溯测试过程中的货币比率(例如“BTC”、“LTC”等。).
我们的环境也有两个方法:reset()和 step()。
Env.reset()方法
这是另一个几乎不需要解释的项目:它只是将交易环境重置为默认状态。这样做的目的是在运行多集回溯测试时,我们将在每集之后调用 env.reset()来重置所有局部变量,如硬币余额、该集数据帧的索引位置、跟踪特定策略可能需要的任何变量,以及可能对日志记录有用的任何其他信息。环境的默认状态是美元余额为 1.0,每种加密货币的余额为 0.0。关于 reset()方法的一些重要注意事项:
- 请注意,每次重置都会抓取主数据帧的一小部分,并将其称为“episode_df”,而不是在回测期间遍历全部 600,000 多个数据实例。这是每集对策略进行回溯测试的时间间隔。本集数据帧的持续时间可使用常量分钟/集或天/集来指定。在这个例子中,我们使用 1 天或 1440 分钟的剧集长度。
- 在初始化环境时调用 reset()方法(在 init)方法。这将在第一次调用 Env 对象时设置所有环境变量。
Env.step()方法
阶梯方法是神奇的地方。我将把这个方法分为两部分:实施交易策略和计算业绩指标。
战略
在这个例子中,我没有使用你在深入的技术分析讨论中可能遇到的更复杂的交易策略,而是揭穿了我们在网上其他地方看到的一个常见策略的功效:移动平均线交叉策略。如果你不熟悉,这个思路的大意是,当一条短窗口均线穿越到一条长窗口均线上方→买入;而当短窗口均线穿越回长窗口均线下方→卖出。
现在,我不确定是否有人相信这个策略真的有效(在某些情况下可能有效),但是为了演示回溯测试环境,让我们考虑一下这个策略(并且因为实现更复杂的策略会消除一些修补自己想法的乐趣)。如下面的代码所示,我们有两个关键的 if 语句,它们检查移动平均线的变化,并决定是记录买入还是卖出(或者都不记录)。需要熟悉两个局部变量: money_in 和 to_buy。这些是字符串变量,记录你的资金目前存放在哪里,以及当开始买入时,资金将流向哪里。一旦进入买卖 if 语句,这些变量就会相应地更新;因此,你的余额字典会根据你所持股票的当前价格进行更新。请注意,在每次买入/卖出时,各自的余额会乘以交易费用乘数,在本例中为 0.99925。当使用 BNB 代币(币安交易所提供的最便宜的选项)支付费用时,该值基于 0.075%的币安交易费,但可以根据您的特定交易所的交易费而改变。
性能指标
我们将使用两个指标来评估回溯测试期间的策略表现:回溯测试期间之后的资产净值和回溯测试期间的平均市场变化。您的余额净值是通过根据您持有的货币的现价和您持有的货币数量将您的持有量转换为美元来计算的。区间的平均市场变化是通过在一集的开始和结束时取所有选定货币的价格的平均值,并相应地除以这些值来计算的。根据这些指标,最终目标是以比你持有市场平均股份时更高的净值结束这一集(显然,比你开始时有更高的净值)。
执行环境
在这里,我们一次一分钟地遍历环境,按照策略的指示进行购买和销售,并跟踪沿途的性能指标,以输出到日志中。
我们表现如何?
嗯,正如之前由于策略的简单性所预示的,不是很好。如图所示,在一个平均每天增长 0.2%的市场中,我们预计这一策略的实施将导致平均每天 4%的净值下降(哎哟)。但是,除了这一点之外,日志中还显示,我们现在有一个快速、动态、易于阅读的策略输出,该策略在 2019 年 3 月至 2020 年 6 月之间经过 100 多个随机选择的 1 天时间间隔的回溯测试,以及每次交易的买入/卖出信息。现在,你的问题有了一些答案!
episode: 96
['Buy BTC: 5255.99', 'Sell BTC: 5227.76', 'Buy ETH: 155.86', 'Sell ETH: 155.41', 'Buy LTC: 67.46', 'Sell LTC: 67.45', 'Buy IOTA: 0.3167', 'Sell IOTA: 0.3176', 'Buy IOTA: 0.3167', 'Sell IOTA: 0.3151', 'Buy LTC: 67.67', 'Sell LTC: 67.42', 'Buy XMR: 61.38', 'Sell XMR: 61.59', 'Buy EOS: 4.5225', 'Sell EOS: 4.5076', 'Buy ZRX: 0.2743', 'Sell ZRX: 0.2723', 'Buy ETH: 155.2', 'Sell ETH: 156.98', 'Buy XLM: 0.09605', 'Sell XLM: 0.09597', 'Buy LINK: 0.439', 'Sell LINK: 0.439', 'Buy LINK: 0.4418', 'Sell LINK: 0.4672', 'Buy BTC: 5308.08', 'Sell BTC: 5304.94', 'Buy XLM: 0.09966', 'Sell XLM: 0.09965', 'Buy XMR: 62.29', 'Sell XMR: 62.22', 'Buy TRX: 0.02312', 'Sell TRX: 0.02307', 'Buy LTC: 72.82']
interval: 2019-04-29 12:25:00 - 2019-04-30 12:26:00
net worth after 1 day(s): 1.0221672847272814
average market change: 0.988959335567251
episode: 99
['Buy XRP: 0.30917', 'Sell XRP: 0.31171', 'Buy BTC: 9641.57', 'Sell BTC: 9635.6', 'Buy TRX: 0.02252', 'Sell TRX: 0.02238', 'Buy XLM: 0.08462', 'Sell XLM: 0.08457', 'Buy LINK: 2.2158', 'Sell LINK: 2.211', 'Buy EOS: 4.2811', 'Sell EOS: 4.2527', 'Buy ETH: 212.07', 'Sell ETH: 211.26', 'Buy IOTA: 0.2835', 'Sell IOTA: 0.2833', 'Buy XLM: 0.08375', 'Sell XLM: 0.08317999999999999', 'Buy LTC: 89.2', 'Sell LTC: 89.34', 'Buy XMR: 79.39', 'Sell XMR: 79.15', 'Buy BTC: 9570.01', 'Sell BTC: 9548.48', 'Buy LINK: 2.1819', 'Sell LINK: 2.1595', 'Buy LTC: 89.33', 'Sell LTC: 89.4', 'Buy EOS: 4.1803', 'Sell EOS: 4.1903', 'Buy BTC: 9540.07', 'Sell BTC: 9559.46', 'Buy ETH: 210.83', 'Sell ETH: 208.78', 'Buy LTC: 90.68', 'Sell LTC: 90.39', 'Buy LTC: 90.76', 'Sell LTC: 90.44', 'Buy XRP: 0.31008', 'Sell XRP: 0.30991', 'Buy BTC: 9504.64', 'Sell BTC: 9490.15', 'Buy ETH: 209.7', 'Sell ETH: 209.77', 'Buy IOTA: 0.2853']
interval: 2019-07-28 16:39:00 - 2019-07-29 16:40:00
net worth after 1 day(s): 0.9218801235080804
average market change: 0.9984598063740531
net worth average after 100 backtest episodes: 0.9656146271760888
average, average market change over 100 episodes: 1.0021440510159623
显示的是 100 集里的两集的输出。为了简洁起见,我选择了一个盈利的剧集(96)和一个非盈利的剧集(99)来显示,而实际输出显示了所有 100 集的结果。然而,我们真正关心的不是单个事件的结果,而是这个问题:“我的策略平均表现如何?”。这显示在最终平均发作日志中。
对于运行许多不同策略并在单独的文件中记录以比较结果的人来说,python 日志包可能很有用。
最终,日内交易是一个危险的领域。我希望阅读这篇文章的人会发现这个工具在探索他们的交易想法时很有用,让他们在把策略带到市场之前就能了解他们的决定。对编程和算法交易知识有限的人来说,似乎缺乏做出明智交易决定的资源;我希望这能部分填补这个空白。
一些额外的想法
在我看来,使用本例中的环境是向对面向对象编程了解有限的人介绍动态算法交易的好方法。就我个人而言,我已经用这个工具对许多不同的策略进行了回溯测试,这些策略包含了更多的价格数据特性,并且允许一些额外的功能;即,将加密货币交易到加密货币的能力(例如 BTC/LTC 对等。),而不仅仅是加密货币兑换美元,反之亦然。这种更强大的功能并不是一件非常困难的事情;不过,如果有兴趣的话,一个更复杂的例子的概要可能是未来文章的一个想法。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
动态客户分析
在数据世界里争吵
制作和测试一个动态的最近频率货币(RFM)模型
卡罗尔·约翰逊,“五金店绘画”,堪萨斯历史博物馆
T he 2012 年新闻故事Target 可以预测其客户的怀孕,这可以说是机器学习上升到大众意识的分水岭时刻。不管是不是虚构的,这个故事像病毒一样传播开来,笼罩在那些体现了人工智能流行观点的惊奇和焦虑之中。大多数企业不需要如此深入地了解客户行为,但数据科学已经彻底改变了客户分析。
最近频率货币(RFM)客户细分模型是基本的客户分析框架之一。该模型的三个方面是:
:最近一次交易有多近(通常以天为单位)?
频率 :交易的频率(在指定的时间段内)?
货币 :花了多少钱(在特定时期)?
RFM 模型通常以静态方式实现,即在感兴趣的期末,比如季度或年度,对客户进行分类。此外,奇怪的是,在众多“如何”研究 RFM 模式的论文中,很少有人对其进行统计检验。我认为我们可以利用纵向数据或面板数据来改善这些缺点。
在本文中,我使用 Python 实现了一个动态 RFM 模型,该模型使用 90 天滚动窗口得出每月的 RFM 分数。这个练习的目标是构建一个动态 RFM 模型,它可以响应不断变化的客户行为。
然后,个人 R-F-M 分数被混合到综合 RFM 指标中,这些指标是根据特定的客户选择指标进行调整的。这些模型依次接受假设检验,以确定该模型是否具有任何商业或金融效用。
资料组
RFM 框架在网上被广泛讨论。所以为了简洁起见,我在这里就不再赘述了。这项工作的数据来自流行的在线零售数据集,涵盖了 2010 年 12 月至 2011 年 12 月期间英国在线批发商的交易。该数据集可从 UCI 机器学习库获得。
数据集中只有的交易数据,没有的客户人口统计信息,除了原产国。这种情况下的客户可能是企业。然而,人口统计信息,如客户公司的规模和他们相对于卖家的地理位置,可能是决定他们购买多少和多久购买一次的重要因素。这是数据的关键限制,但我们可以通过面板数据模型部分克服这个问题。
每个客户交易(购买/退货)都用唯一的发票号记录在数据集中,但是每个交易可以涵盖多个产品类别和每个类别中的多个项目。数据集前几行的快照如下所示。这些变量是:
InvoiceNo :每笔交易(采购/退货)的唯一发票号;
【invoice Date】:交易的日期和时间;
【存货编码】:采购的每个产品类别的唯一存货编码;
描述:产品类别的文字描述;
数量:产品类别中采购的项目数;
单价:项目的单价;
CustomerID :每个客户的唯一 id;
国家:客户所在国家。
最初有超过 54 万行的日内交易。为了更好地完善分析,我只关注英国客户。我还删除了那些“CustomerID”值为空的观察结果,因为我需要这些信息用于稍后的面板数据建模。这些将观测值缩减到 362k 左右。然后,我通过将每行的“数量”乘以其“单价”,创建了一个“总收入”(或客户总支出)变量。
数据清理
乍一看,数据集似乎相对干净,以 Excel 文件的形式出现,但它实际上是错误百出。因此,人们常说的数据科学家 80%的工作是数据清理的说法再次得到了证实!例如,数据集中“数量”的最大值(正值)和最小值(负值)是针对同一客户在同一天 12 分钟内输入的抵消金额!这是一个明显的“胖手指”错误。
下一个错误紧随上一个错误而来。第二大和最小的“数量”值也是用于仅相隔几分钟的抵销金额(见下文)。又一个“胖手指”!在整个数据集中有相当多的这些正/负抵消条目,加上其他明显的错误,例如客户只有一次负交易。
这些抵消条目,其中一些涉及巨大的异常值,如上面的例子所示,意味着采取删除所有负面交易的权宜之计会将偏差引入数据集和结果分析。此外,很明显,产品退货在交易数据中被记录为负面交易,这是我们不应该简单地删除所有负面交易的另一个原因。
在数据清理之后,我进行了一些探索性的客户和销售分析,强调了客户细分的重要性。例如,前四分之一的客户占总收入的 77.2%,而前十分之一的客户贡献了 57.8%(392 万英镑对 678 万英镑)。因此,客户群的明确分类对于有针对性的营销和保留策略至关重要。
数据工程和时间序列聚合
我求助于 Pandas 的 Python 时间序列工具箱,对从日内到日频率的数据集进行必要的聚合。我重命名了聚合后的变量:id、日期、发票号、类别、数量、单价、总额。除了“categories”是原始“StockCode”变量的一个计数之外,新名称只是原始名称的表面变化。
然后使用各种时间序列工具从每日数据中伪造出 RFM 模型每个方面的原变量。例如,下面是“days_since_last”变量的代码,该变量稍后将用于构建最近得分。
类似地,生成“trans_90d”和“revenue_90d”变量来分别捕获每个客户在 90 天滚动窗口期内的交易数量和总收入。考虑到滚动窗口的起点,这自然会导致数据集的前三个月被从后续分析中删除。
这些特征工程测量筛选出许多单个客户,如唯一的“id”变量值,这些客户仅在数据集的前三个月被记录和/或在数据集的剩余部分有一次观察,因此上面的原型 RFM 变量将具有空值。具体来说,最初的每日数据有 3,947 个唯一的“id”值,但在每月汇总之前缩减到 2,638 个。如果数据集覆盖了更长的时间段,可能会减少对独特客户记录的筛选,但这是我必须处理的。
此外,我设计了一个替代原始货币变量,即每个客户每月的平均总收入。“trans_90d”和“revenue_90d”之间可能有很强的正相关性,因为从逻辑上讲,越多的交易应该从客户那里获得越多的收入。当我们开始使用回归来估计权重以构建复合 RFM 分数时,高度的线性相关性是不期望的。因此,一些人主张在货币层面使用平均收入。无论如何,我生成了这个替代变量(“avg_revenue_90d”),看看它以后是否有用。
数据集最终汇总成月度频率。为什么有人会问每月一次?日频次数据中“days_since_last”和“trans_90d”变量的平均值分别为 42.64 和 4.61。这些数据表明,典型的客户每月进行约笔半交易。因此,在这种情况下,每月一次是客户分析的最佳时间间隔。
在每月汇总之后,我进一步删除了一些关键变量“总额”和“发票数量”的异常值。有 163 个观察值超出了两个变量平均值以上的 3 个标准差。没有低于平均值的观察值。这 2%的观察值作为异常值被丢弃,最终得到 7,892 行的月度数据集。
客户聚类
根据 RFM 的每个方面,有两种广泛的方法可以用来划分客户。第一种是对客户列表进行排序,将相等的数字放入不同的桶中,通常是四分位数或五分位数,并相应地对它们进行评分。另一种是聚类不同的客户群,K-means 聚类算法广泛用于此目的。
重要的是要注意每个步骤中的主要假设。第一个步骤是把相同数量的顾客塞进每个细分市场。相比之下,K-means 聚类是一种无监督的学习算法,因此当用于社会经济数据时,它可能会导致不平衡段,这些数据通常是倾斜的。
没有对错之分,但我更喜欢让数据自己表达。尽管如此,我还是意识到了长尾分布的问题,当偏差相当大时,它会导致大部分观测值集中在一个或两个片段中。过度聚类也是不可取的,因为它会降低后续 RFM 分数的粒度。
为了处理长尾问题,我通过采用“days_since_last”的自然对数(因为它只有非零的正值),以及“trans_90d”、“revenue_90d”和“avg_revenue_90d”的立方根来转换 RFM 原始变量。我挑选了一个 5 个集群的 K 均值,随后的集群按照序数升序标度进行评分(即 0 为最低分,4 为最高分)。
这种方法减少了一些偏斜,但它仍然反映了不平衡的客户群,这在我看来是很自然的。在所有三个 RFM 变量中,得分最高的客户群规模最小,但如前所述,前 10%的客户占总收入的一半以上。
**
每月 RFM 分数
按照这些步骤,我们得出了每个客户不同的月度 近期、频率和货币分数。由此产生的月度数据框架的三个快照如下所示。第一个是排序的数据帧,第二个和第三个描述了两个特定客户的记录(" id"==17611 & 13881 ")。
正如可以观察到的,每月的个人 RFM 分数根据演变的客户行为而变化。从这里有两条可能的路。这些单个的 RFM 分数可以被合并,以进一步将单个客户归类到更具体的子群中,例如归类到“频繁但低消费”组或“不频繁但高消费”组。
或者,我们可以用这些分数来制作一个综合 RFM 指标。鉴于我的目标是在下一篇文章中对 RFM 模型进行统计测试,我决定走第二条路。
RFM 综合指数
值得花些心思思考一下如何以及为什么我们可能想要设计一个综合 RFM 指标。事实上,“如何”和“为什么”是不可分割地交织在一起的,因为我们如何衡量个人得分以汇总成一个综合指标,将对其最终显示的内容产生决定性影响。
这就是为什么复合权重模型需要变得清晰和透明。一些常用的常用加权方法有:
等权;
主成分分析;
回归分析;
理论上的考虑;和
专家意见。不幸的是,对于我们应该如何进行,既没有强有力的理论,也没有专家的一致意见。
作为一个例子,让我们考虑一下,如果我们采取权宜之计,简单地将每个月的三个 R-F-M 分数相加,那么采用等权重方法(这是普遍的做法)会发生什么。我构建了这样一个月度“rfm_equal”变量,其相关矩阵(月度数据)如下所示。
显而易见的是,“rfm_equal”与“invoices_no ”(每月的交易/购买次数)的正相关关系比“gross ”(每月的总支出)强得多,分别为+0.56 和+0.34。主要原因是 RFM 模型本质上强调常规的客户活动,体现在新近性和频率方面,这三个方面的同等权重会让这种趋势自由发展。
尽管 RFM 模型最初可能是为了对客户活动的规律性进行评分而设计的,但一种替代的复合构造方法可能会改进它,使它更加灵活。关注客户活动当然没有错,但我想说明的是,为备选客户指标设计一个复合 RFM 指标是可能的。如果我们确实可以将相同的数据用于不同的目的,那么这将减少额外数据收集的需求,或者将允许现有数据的新用途。
此外,请注意“monetary”和“monetary_avg”分数的相关系数的差异。最初关于“货币”与“频率”高度相关的怀疑得到了证实。事实上,“monetary_avg”与“recency”和“frequency”的相关性低于原始的“monetary”变量。因此,从现在开始,我将使用“monetary_avg”作为我的动态 RFM 模型的默认货币方面。
面板数据建模
我转向面板数据回归建模来构建综合 RFM 指标的选择。面板数据分析有许多名称和伪装。也称为纵向、聚类或分层数据,面板数据通过横截面数据(在一个时间点从许多不相关的对象获取的数据)和时间序列(在几个时间点从同一对象获取的数据)的组合来区分。面板数据通常不同于时间序列,因为它的观察对象比时间段要多得多。
面板数据的一个主要优势是它允许一个使用受试者作为他们自己的对照。当你在随时间变化的条件下观察同一个对象时,你可以更好地估计这些变化是如何影响它的行为的。更好的是,你可以将这种观察维度添加到不同对象的(典型)横截面分析中。
换句话说,面板数据分析可以用来估计受试者内部的变化(在我们的案例中,随着时间的推移,在每个客户中)和受试者之间的变化(在不同的客户中),这导致了额外的术语“内部”和“之间”的估计。这些优势允许对数据中的因果关系进行更强有力的推断,这就是为什么面板数据技术被广泛用于生物医学研究。
在本文中,我只使用了“在”估计量面板数据模型。该模型基本上固定受试者的时不变属性,同时估计时变解释变量如何影响因变量。这就是计量经济学中广为人知的 固定效应模型 。这种模型的系数捕捉了时间序列变化对每个受试者的影响,同时控制了所有不随时间变化的属性,而不必明确列出它们。
这个案例中的客户是其他公司。数据集的主要限制是缺乏客户人口统计信息。很容易认为,客户公司规模、客户商业模式和与卖方的物理距离等因素在决定购买量和购买频率时非常重要。未能在回归中包含这些潜在的重要因素可能会导致系数估计值因 遗漏变量偏差 而失真。
在这种情况下,固定效果模型的好处是每个客户的这些“固定”属性都将在模型中针对进行控制!运行回归时,模型中考虑了客户的所有不变人口统计因素(在分析的时间段内)。因此,我可以安全地进行统计推断,因为我知道这些时不变因素不会对参数估计产生偏差。
瞄准“毛”
我构建的第一个综合 RFM 指标将每月客户支出作为其目标指标。创造销售无疑是企业存在的理由。为此,每月“毛”收入被用作回归分析的目标变量。**
目标月度“总量”变量严重右偏。它的平均值为 459,但最大值为 5540。它也有负值,请记住,产品退货是在交易数据中捕获的。因此,我通过取它的立方根来转换它,这与对数转换不同,它可以用于零和负值。转换后的分布“gross_cubic”确实更加对称,尽管双峰现象非常轻微。
构建和测试综合指标
复合 RFM 评分是在一个程序中建立和测试的。我首先按照时间段从最早(2011 年 3 月开始)到最晚(2011 年 12 月结束)对数据集进行排序,然后将它分成两半。分割前的排序确保了数据的时间顺序得到尊重。从样本的上半部分估算单个 RFM 系数加回归截距。这些估计数随后被用来计算综合 RFM 指数。****
只有数据集的下半部分用于综合指标的假设检验。以这种方式,我将测试从数据集的前一半“训练”中获得的复合权重是否可推广到后一半数据的“测试”中。这是训练测试与假设测试的混合,传统上倾向于对全部数据进行测试。**
固定效应面板数据回归是通过对每个客户(在汇总结果中被称为“实体”)进行最少两次观察(随着时间的推移)来完成的。只有客户效应是固定的,回归中没有时间效应,所以这是一个 单向固定效应模型 。**
为了保持简洁,我只显示了部分汇总结果,特别是参数估计及其各自的标准误差和 t 统计量。所有三个 RFM 变量在统计上是显著的。完整的总结结果,包括对可池性的 F 测试,可以在我的 GitHub 页面上找到,链接在文章底部。**
我根据上面的截距和系数构建了“rfm_gross”变量。然后取数据集的下半部分,对其运行两个回归模型。第一个模型只有“rfm_gross”作为感兴趣的回归变量,而第二个模型包括“invoices_no”、“quantity”和“categories”作为额外的控制变量。毕竟,人们会期望交易的数量、购买物品的数量和购买产品类别的数量对“总”支出产生一些影响。因此,“rfm_gross”与其他回归变量一起进行测试是合适的。**
第一个模型的“rfm_gross”系数是令人满意的+0.8830,或接近 1,这意味着它与因变量“gross_cubic”几乎是一对一的关系,并且在统计上也是显著的。在其他回归因素存在的情况下,第二个模型的“rfm_gross”系数下降到+0.6543,但仍具有统计显著性。可集合性的零假设,即不需要固定效应,也在两个模型中被拒绝。**
结果表明:
1)“RFM _ gross”是测试集中“gross _ cubic”的一个良好的(系数接近 1 且具有统计显著性)二元(内)预测因子;和
2)“RFM _ gross”仍然是“gross_cubic”的稳健(内部)预测值,尽管增加了其他控制变量。****
改进“rfm-equal”指标
随后,我开始考虑是否可以改进 RFM 模型的初衷,即追踪客户活动的规律性。除了用同等权重来构建一个综合 RFM 指标,我们还能做得更好吗?为了回答这个问题,我在很大程度上重复了上面的步骤,但是使用了“invoices _ no”作为目标变量。**
因此,首先将数据集分成两半,前半部分数据用于运行具有单向固定效应的面板数据回归。所有三个 RFM 变量再次具有统计学意义。截距和系数随后用于计算复合 RFM 指标“rfm_invoices”,并在数据集的后半部分进行了测试。**
我再次运行了两个模型:一个只使用“rfm_invoices”作为感兴趣的回归变量,另一个使用“categories”和“quantity”作为额外的回归变量。我假设“invoices_no”,即交易的数量,会受到客户购买了多少产品和多少物品的影响。这一次“总额”没有包括在内,因为我假设因果箭头是从“发票 _ 无”指向“总额”,而不是反过来。
两个模型中“rfm_invoices”的系数接近于 1,分别为+0.9734 和+0.8838,并且具有统计显著性。在这方面,在存在其他回归因素的情况下,综合指标“rfm_invoices”比“rfm_gross”更稳健,这证实了 rfm 模型最适合跟踪客户活动。**
然而,这个“rfm_invoices”比最初的等权“rfm_equal”指标更好吗?对此进行测试的一种方法是对“rfm-equal”进行与上述相同的测试程序。结果如下。
我们看到,“rfm_equal”在+0.1423 和+0.1328 处的两个系数都是统计显著的。虽然它们的份额小于“rfm_invoices”的系数,但在面对额外的回归变量时,它们同样稳健。这表明“rfm_equal”综合指标并不比“rfm_invoices”差多少。**
“rfm_equal”和“rfm_invoices”之间的强正相关关系通过下面的配对图得到了证实。考虑到其构造的简单性,在确定客户交易数量时,我们最好使用“rfm_equal”。**
结论
该项目从努力构建一个动态 RFM 模型开始,该模型将提供每月的客户行为演变的近期、频率和货币分数。为了做到这一点,我首先将原始的日内数据汇总成日频率,然后再汇总成月频率。在这种情况下,每月周期被确定为客户分析的最佳频率。**
在此之后,我使用面板数据计量经济学来构建 RFM 综合指数,目标首先是客户支出,其次是客户交易的发生率。然后,我对 RFM 模型进行了假设检验,这证实了它在同时测量客户选择指标方面的有效性。测试进一步证实了简单等权 RFM 综合得分是客户交易的有效预测指标。**
进一步的工作可能包括建立一个替代模型,可以更有效地跟踪客户的支出,也许是通过用购买物品的数量来代替新近性。替代面板数据模型,特别是贝叶斯分层模型,也可能有助于改善 RFM 模型。
(这个练习的完整 Python 代码可以在我的 GitHub 资源库中找到。如果直接渲染 GitHub 笔记本文件有问题,使用 nbviewer 。)
如果你看到了阅读这样的文章的价值,你可以在这里订阅 Medium来阅读我和无数其他作家的其他文章。谢谢你。****
PM 2.5 空气污染数据集的个例研究
towardsdatascience.com](/stacking-machine-learning-models-for-multivariate-time-series-28a082f881) [## 用预测概率处理不平衡数据
葡萄牙银行营销数据集的案例研究
towardsdatascience.com](/tackling-imbalanced-data-with-predicted-probabilities-3293602f0f2) [## 面向金融的顶级 Python 黑客
用比特币时间序列数据
medium.datadriveninvestor.com](https://medium.datadriveninvestor.com/top-python-hacks-for-finance-f9ea900a686c)****
动态规划与整数规划:哪个更适合背包问题?
最优化领域包括许多不同领域的模型和算法。你可以根据许多不同的标准对领域进行分类:线性对非线性,凸对非凸,连续对离散,等等。通常,一个问题可以用多种不同的方法来解决,这是不同的底层解决方案哲学相遇的地方,我觉得这很有趣。在本文中,我们将通过背包问题这一有趣且被充分研究的问题来深入探讨动态规划和整数规划之间的差异。
什么是背包问题
背包问题可能是众所周知的中级问题之一。但是,即使在 Leetcode 之前,由于它的递归性质和简单的问题设置,背包已经包含在整数编程课程和更高级的计算机科学课程的介绍中。作为一个优化人,背包问题是你在整数规划课上最先学习的问题之一。更何况背包问题实际上是一个 NP 难问题!然而,这是一个 NP 难题,我们可以非常有效地解决。我们就越有理由从它开始!
让我们回顾一下背包问题是什么。假设你要去旅行,你有一张清单,上面有 n 件你想放在背包(或者背包,如果你愿意的话)里随身携带的物品。每个项目都有一个权重和效用分数。您希望找到项目的子集,其总权重低于阈值 W ,并且其总效用分数最大化。
从描述来看,这个问题听起来足够简单。有一点需要注意的是,每一项都可以选择也可以不选择,但不能半选或分数选。这是 0–1 背包问题和分数背包问题之间的一个很好的区别,在 0–1 背包问题中,每个物品是一个整体,在分数背包问题中,可以选择一个物品的分数部分。在现实生活中,0–1 背包问题可以被视为决定是否应该选择手电筒,而分数问题可能是考虑应该选择 1 加仑水中的多少。
简单启发式
背包问题的主要权衡是在满足重量限制的同时获得尽可能多的效用分数。一个自然的想法是计算每个项目的效用/重量比,然后尝试适应每单位重量具有较高效用分数的项目,直到达到重量阈值。该算法是一种贪婪算法,实际上是分数背包问题的解决方案。然而,这并不能保证 0–1 背包问题的最优解,如下面的反例所示。
假设下表中给出了这些产品的规格:
体重阈值是 50。使用贪婪试探法,我们将选择项目 1 和 2,总效用为 160,总权重为 30。显然,这不是最佳解决方案,即选择第 2 项和第 3 项,其中总效用为 220,总重量正好为 50。其观点是,用相对比率排名是好的,但它没有考虑绝对权重值,并且不能以分数的方式选择项目。
事实上,人们可以利用这一弱点来创建背包问题的实例,这使得贪婪启发式算法的解决方案变得任意糟糕。
考虑以下重量阈值为 X 的背包问题
贪婪算法解只会选择总效用为 1 的项目 1,而不是选择效用得分为 X-1 的项目 2 的最优解。当我们使 X 任意大时,与最优解相比,贪婪算法的表现会任意差。
动态规划方法
动态规划基于这样的思想,即在最优解中,给定的项目 i 要么在所选择的子集中,要么不在。此属性定义算法的递归性质。设 I 为项目集合, u ᵢ, wᵢ 分别为项目 i 的效用和权重, W 为权重阈值,背包( I , W )为项目集合为 I 且权重阈值为 W 的背包问题的最优解。用数学术语来说,递归可以定义为
其中 I{i} 表示没有项目 i 的项目 I 的集合。
- max 语句中的第一项是最优解中第I项不是项的情况,因此该最优解与除第 i 项之外的具有相同权重阈值和相同项的背包问题的最优解相同。
- 第二项是最优解中项目It42】为的情况,要选择最优解中剩余的项目,需要求解一个新的背包问题,其中项目集合为 I{i} ,权重阈值为 W-wᵢ 。
有了这个递归定义,我们可以建立一个表来跟踪每个背包问题的最优解,从 0 项和权重阈值 0 开始到集合 I 和权重阈值 W 中的所有项。那么每当我们在计算背包( I{i},W-wᵢ )的解时,我们就可以在表中查找解。
下面是动态编程算法的 python 实现:
def knapSack(weight_threshold, weight_list, util_list):
"""
A Dynamic Programming algorithm that solves the 0-1 Knapsack problem. Args:
weight_threshold: Weight threshold
weight_list: List of weights for each item in item set I
util_list: utility score of each item i Returns:
The optimal utility score of the knapsack problem
"""
n = len(util_list)
lookup_table = [[0 for x in range(weight_threshold+1)]
for x in range(n+1)]
# Build table K[][] in bottom up manner
for i in range(n+1):
for w in range(weight_threshold+1):
if i==0 or w==0:
lookup_table[i][w] = 0
elif weight_list[i-1] <= w:
lookup_table[i][w] = (
max(util_list[i-1]
+ lookup_table[i-1][w-weight_list[i-1]],
lookup_table[i-1][w]))
else:
lookup_table[i][w] = (
lookup_table[i-1][weight_threshold])
return lookup_table[n][weight_threshold]
请注意,这里的 i 代表集合 I 中可供考虑的项目数量。例如, i = 2 表示我们只能从项目 1 和 2 的集合中进行选择。As w 遍历所有可能的权重, K[i][w] 表示带权重阈值 j 的背包问题的最优效用得分,并有项 1,2,…,i 。
让我们来看看 DP 算法在权重阈值为 5 的情况下的运行情况:
当算法以最优解终止时,表 K 看起来像下表:
在处可以找到最优解,K[3][5] = 20 ,选择项目 2 和 3 。
整数规划
另一种方法是整数规划方法。整数规划是一个数学优化程序,其中一些或所有的变量被限制为整数。整数规划是 NP 完全的,因此可以作为整数规划问题提出的背包问题也是 NP 难的就不足为奇了。当使用整数规划方法时,人们通常将决策建模为离散的决策变量,可行的决策由一组约束来描述。所得到的模型可以通过特殊的整数规划算法来求解,以获得最优解。在这种情况下,离散的决策是是否应该选择一个项目。我们引入 xᵢ ,其中项目 i 来自集合 I 来表示项目 i 是否被选中的决定。如果 xᵢ = 1 ,则选择项目 i ,否则 xᵢ = 0 且项目 i 不选择。
整数规划模型可以用公式表示如下:
该术语
是我们想要最大化的目标函数。在这种情况下,目标是最大化所选项目子集的总效用分数。
不平等
是背包约束,强制所选物品的总重量不超过 W 。
该模型是经典的整数规划背包问题。为了求解上述模型,可以利用任何整数规划求解器。一个好的选择是 Google 或 tools ,这是一个用于编写和求解优化模型的开源工具。
下面是使用 ORtools 和 CBC 整数规划求解器来建模和求解背包问题的 python 代码:
def mip(weight_threshold, weight_list, util_list):
"""
A Integer Programming model that solves the 0-1 Knapsack problem. Args:
weight_threshold: Weight threshold
weight_list: List of weights for each item in item set I
util_list: utility score of each item i Returns:
The optimal utility score of the knapsack problem
"""
n = len(weight_list)
# initialize the integer programming model with the open source CBC solver
solver = pywraplp.Solver('simple_mip_program', pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)
# Declare binary variable x for each item from 1 to n
x_dict = {}
for i in range(n):
x_dict[i] = solver.IntVar(0, 1, f'x_{i}') # Add constraint on total weight of items selected cannot exceed weight threshold
solver.Add(solver.Sum([weight_list[i]*x_dict[i] for i in range(n)]) <= weight_threshold) # Maximize total utility score
solver.Maximize(solver.Sum([util_list[i]*x_dict[i] for i in range(n)])) # Solve!
status = solver.Solve()
# Uncomment the section below to print solution details
# if status == pywraplp.Solver.OPTIMAL:
# print('Solution:')
# print('Objective value =', solver.Objective().Value())
# print('Problem solved in %f milliseconds' % solver.wall_time())
# for i in x_dict:
# print(f'{x_dict[i]} = {x_dict[i].solution_value()}') return solver.Objective().Value()
求解整数规划的标准方法叫做分支定界。这是一种分而治之的方法,它重复划分解决方案空间,直到找到并证明一个解决方案是最优的。
顾名思义,分支定界法由两个主要动作组成:
- 界限:给定一个解集,得到在解集中可以找到的最佳解的上/下界估计。例如,可以通过求解相应的分数背包问题来找到 0–1 背包问题的上界。由于分数背包问题允许选择项目的一部分,而 0–1 背包问题不允许,所以分数背包问题将总是产生相等或更好的目标值,这可以被视为 0–1 背包问题的目标的上界。
- 分支:当计算解集上的界限时,我们遇到满足问题的所有约束的解,但是由于解的值不是整数而不可行。在这种情况下,我们可以在一个小数值变量上分支,将当前的解空间分成两个:(在二元变量的情况下)一个强制小数值变量为 0,另一个强制小数值变量为 1。例如,求解分数背包问题可能会产生一个占第 2 项 50%的解。然后,可以通过将解空间分割为包含第 2 项或不包含第 2 项来对第 2 项的变量进行分支。
让我们来解决我们在动态编程中使用的示例问题,希望这样可以把事情搞清楚。
我们从背包的原始问题( I,W )开始,这个问题在分枝定界中被称为“主问题”。我们首先解决一个放松的主问题。在整数编程中,松弛通常指的是线性松弛,其中不是要求每个二进制变量 xᵢ 都是二进制的,而是放松这种约束,并强制每个 xᵢ 在[ 0,1 之间。这导致了一个线性规划,因此命名为“线性松弛”。有趣的是,在背包问题的情况下,线性松弛只是分数背包问题。所以我们可以用启发式算法来求解,得到最优解。对于更一般的整数规划松弛,解决一个线性规划是必要的。
求解背包的松弛( I,W )后得到 (x_1,x_2,x_3) = (1,1,0.67) 和一个 22.67 的目标。这个解决方案为我们提供了两条信息:
- 目标上的一个全局上界 22.67 ,由于 0–1 背包问题的解空间是分式背包问题的子集,0–1 背包的最佳目标不可能比 22.67 做得更好。事实上,它不可能比 22 更好,因为 0–1 背包问题中的所有系数都是整数。
唯一的分数变量是 x₃ ,非常适合分支。
接下来,我们通过添加约束条件对变量 x₃ 进行分支,并且我们获得两个子问题:
a)具有约束 x₃ = 0 的背包( I,W
b)具有约束 x₃ = 1 的背包( I,W
其中每个子问题是一个新的背包问题,我们重复相同的步骤,并解决每个子问题的松弛。
对于子问题 a),求解它的松弛得到 (x₁,x₂,x₃) = (1,1,0) 的解和 16 的目标。这是一个可行的方案,可以作为下界。换句话说,现在我们已经找到了目标为 16 的候选解决方案,我们只寻找目标比 16 更好的解决方案。任何其他目标更差的解决方案都可以放弃。
对于子问题 b),其松弛的解给出了 (x₁,x₂,x₃) = (1,0.5,1) 的解,以及一个 21 的目标。由于子问题 a)已经达到了一个最佳目标 16 ,全局上界可以从 22 更新到 21 ,因为找到更好解的唯一机会是在子问题 b 的解空间上,并且它能得到的最佳值是 21 。但是由于 x₂ 现在是分数,我们在 x₂ 上进一步分支,形成问题 b1)和 b2)。
b1)背包( I,W ),约束 x₂ = 0,x₃ = 1
b2)背包( I,W ),约束 x₂ = 1,x₃ = 1
求解子问题 b1),我们得到目标为 16 的解 (x₁,x₂,x₃) = (1,0,1) 。我们可以安全地丢弃这个分支,因为它可以达到的最佳目标是 16 ,这已经在子问题 a)中找到了。在这种情况下,由于该解决方案也是积分的,我们将停止,因为没有其他解决方案可以对问题 b1)进行研究,从而可能产生更好的目标。
求解子问题 b2),我们得到 (x₁,x₂,x₃) = (0,1,1) ,目标 20 。由于解是积分的,并且大于先前的下界 16 ,这是新的下界。由于这是我们需要探索的最后一个分支,我们可以说这是原问题的最优解。显示解的最优性的另一个证明是,全局上界是 21 ,并且不存在将产生总效用分数 21 的项目组合,因此目标 20 的解是最优的。
下面是总结上述步骤的流程图:
比较
让我们回头来看看这两种方法。这两种方法都使用某种递归方案:动态编程利用问题结构并从较小的问题递归地构建最优解,而整数编程递归地将问题空间划分为较小的主干,并使用估计的界限来丢弃不感兴趣的解分区以加速搜索。动态编程就像一个超级智能的枚举,它通过总是建立在简单问题的最优解上来避免不必要的计算。整数规划不一定只在解集内工作。相反,它使用从求解松弛中获得的信息来细化下限和上限,并努力缩小两个界限之间的差距。界限可以帮助消除不包含更好的解决方案的部分解决方案空间,这就是为什么分支界限可以非常有效。当问题结构很好,解集适中时,动态规划是很棒的。如果您有有效的方法来计算解决方案的质量下限和上限,那么整数规划会非常有效。
背包问题哪个好?
背包问题到底该用哪一个?为了回答这个问题,我们进行了两组实验:
- 在不同规模的随机生成的背包问题上运行这两种算法,看看规模对性能的影响
- 对随机生成的背包问题运行这两种算法,这些问题具有不同的背包约束紧度,以查看约束紧度对性能的影响。
问题大小对性能的影响
问题的大小是一个通常要考虑的因素,因为较大的问题通常需要较长的时间来解决。我们用 100 到 1000 个项目生成背包问题的实例。权重和效用分数是 0 到 100 之间随机生成的整数。权重阈值是固定的 100。我们在每个实例上运行两种算法 7 次,并以秒为单位记录平均求解时间。结果可以总结在下面的图中:
从上面的图中可以看出,对于小规模到中等规模的问题,动态规划方法比整数规划方法更有竞争力。随着问题规模的增大,两种算法的求解时间都在增加。在实验设置中,似乎一种算法相对于另一种算法没有明显的优势。
背包约束紧密度对性能的影响
我们考虑的另一个因素是背包约束的紧密性。严格的约束意味着大多数项目不会被选中,而宽松的约束意味着大多数项目最终会被选中。这直接影响动态编程的查找表大小。我们用 100 个项目生成背包问题的随机实例,这些项目的随机权重和效用分数在 0 到 100 的范围内。我们在每个不同的权重阈值(范围从 50 到 950)上运行每个算法 7 次,并以秒为单位记录平均求解时间。从下表可以看出结果:
从图中可以看出,随着权重阈值的增加,求解时间随着动态规划方法的增加而增加,而整数规划似乎不受太大影响。这是因为动态规划的表大小和迭代次数与权重阈值成正比,而整数规划更直接地受到整数变量和约束的数量的影响,所以在这种情况下约束紧密度不会对整数规划的求解时间产生巨大影响。
结论
从实验中我们可以看出,对于严格约束的背包问题,动态规划可以是一个可靠的选择,因为它的效率与整数规划相比是有竞争力的,但不需要建立模型和调用外部求解器。此外,动态规划还有查找表的好处,它包含了不同参数的背包问题的最优解。
另一方面,如果问题规模很大并且背包约束不是很紧,整数规划方法会更好。当背包约束的紧密度改变时,整数规划不会受到太大影响。动态编程的缺点是不能保持比例不变,这意味着如果我们将权重和权重阈值都乘以相同的因子,那么求解时间也会增加,因为查找表的大小是weight threshold
* number of items
。顺便提一下,整数规划求解器也有更多的武器,可以更快地找到可行的解决方案,更有效地优化边界。一个例子是,许多求解器内置了搜索可行解的试探法,以及收紧边界的内置截集。
希望这回答了我们何时应该使用哪种方法的问题。如果您熟悉优化领域中的列生成方法,您就会知道背包问题通常是我们需要高效解决的子问题。在文献中,背包问题总是用动态规划来解决,这一直让我很好奇。通过所有的分析,我认为这个选择是由于背包问题通常规模较小并且约束严格。希望这能吸引更多对优化感兴趣的人,并为每个算法如何找到最优解提供很好的见解。
对于对背包问题感兴趣的读者来说,Google ORtools 在这里有更多的讨论,也有同样主题的巨著。
时间序列数据的动态重放
在 Python 中利用 matplotlib 和双端队列
脑电 Fp2 和 C3 通道的动态图。
完整地静态绘制大型时间序列数据可能会导致非常紧凑的绘图,这些绘图几乎不会产生关于它们在较短时间尺度上可能包含的任何有趣影响的信息。为了识别这些影响,以可调节的速率回放数据可能是有用的。以下用 Python 3 编写的代码正是通过利用matplotlib
的交互模式以及双端队列(或称deques
)来实现这一点,双端队列是类似列表的容器,支持快速追加和在任一端弹出。
在下面的演示中,我将使用从大约 8 分钟的静息状态会话中获得的脑电图(EEG)数据。然而,我想强调的是,该代码适用于任何类型的时间序列数据,无论是来自电生理学、股票市场、产品销售还是气象学。
让我们首先导入所需的包,加载数据,并打开matplotlib
的交互模式。
接下来,我们将定义图中可见的时间量(即 x 轴的长度),并初始化数据的队列,dy1
和dy2
,以及它们对应的 x 轴dx
。interval
变量表示包含所有数据点索引的数组(在本例中,从 0 到 224,930),用于扩展 x 轴并设置其限制。因为 EEG 采集的采样频率是 500 Hz,所以我们需要将这个数组除以 500 来获得以秒为单位的时间。
现在,我们需要定义图形和它的轴。我选择了一个 2 乘 1 的子图,上面的代表通道 Fp2,下面的代表通道 C3。
最后,我们将图的 x 轴和 y 轴更新打包到一个 while 循环中,该循环只有在回放完所有数据后才会结束。变量start
控制时间序列移动的速度,因为它决定了 deques 的增量,因此也决定了图的更新。此外,y 轴的限值根据其相应数据的平均值mdy1
和mdy2
动态移动。
输出是一个以自定义速度重放整个时间序列数据的动态图,如本文顶部的 GIF 所示。
动态随机一般均衡模型
DSGE 模型的理论和数学,以及为什么 DSGE 模型应该用于商业
图片作者:特里斯特·约瑟夫
经济学通常被定义为一门社会科学,它从个人和社会在面临稀缺时所做选择的角度来研究人们的行为。这里的稀缺性指的是这样一种情况,即拥有有限的资源,但社会中的代理人却有无限的需求。由于这种差距,所有社会都面临着回答三个基本问题的任务:生产什么?如何产生?这应该为谁制作?
这些问题可以分成两大类来研究:微观经济学和宏观经济学。微观经济学关注经济中的细分部门。更具体地说,它研究企业、个人消费者和家庭的决策。另一方面,宏观经济学关注的是经济中的综合部门。经济学的这一分支关注政策建议,并评估诸如一般价格水平、就业和经济产出等方面。
图片作者:特里斯特·约瑟夫
有了这些定义,我们可以看到,宏观经济学家考虑经济的表现,同时也试图找出经济中可能阻碍宏观经济目标的领域。
现在,宏观经济政策问题通常涉及经济内部各方面的权衡。实施成功政策的一个关键因素是理解手头政策问题的竞争性方面的力量。评估这些优势的一种方法是进行实验。理想情况下,应该对一个经济体进行真正的实验,以理解和评估结果。然而,由于成本、时间和伦理的原因,这通常是不可能的。因此,唯一可以进行实验的地方是为理解经济而开发的模型。
为了更好地理解这一点,让我们考虑一个具有竞争性方面的政策问题。政府支出的增加会对经济产生什么影响?这个理论表明,政府支出的增加会刺激总需求和总产出。然而,对财政偿付能力的担忧可能会导致私人支出减少,从而降低产出。鉴于它们的相对优势,哪种结果更有可能出现?
图片作者:特里斯特·约瑟夫
通常情况下,模型构建会结合理论的某些方面。这是因为模型应该代表“真实生活”的某个方面。这种方法的问题是,我们不知道理论的效果是否强于某些外部因素的效果。为了评估这一点,应该利用动态随机一般均衡(DSGE)模型。
在宏观经济学(和宏观经济研究)中,DSGE 模型被认为是市场经济如何运作的相当好的代表。它为传统的、静态的经济表现提供了一种替代方法,并且它们可以适用于各种目的。对于经济政策分析,DSGE 模型是围绕三个相互关联的方面建立的:需求、供给和货币政策。
图片作者:特里斯特·约瑟夫
构建 DSGE 模型的方程是从关于经济中主要主体(家庭、企业和政府)行为的关键假设中推导出来的。随着时间的推移,这些代理人在市场上相互作用,直到他们达到某种“一般均衡”点。对于这个经济体,我们假设只有两种商品:中间商品和最终商品。中间产品是作为生产成品的投入,而最终产品是作为最终产品消费以满足当前需求的产品。
在这个模型中,家庭消费由不同公司生产的最终产品。既然有两种商品,就有两种公司。中间产品生产公司生产一种特殊的产品,然后将这种产品传递给最终产品生产公司。这家公司然后包装差异化的商品,然后在竞争市场上销售。
在所有这些相互关联的方面,DSGE 模型的最后一个组成部分是它们的随机性。这意味着模型的某些部分是随机确定的。随机事件是不可预测的,没有稳定的模式或顺序。因此,这增加了经济的不确定性,并造成经济波动。这是该模型的一个关键方面,因为如果没有它,经济将永远沿着一条已知的路径增长。
图片作者:特里斯特·约瑟夫
现在理解了代理之间的关系,对每个代理进行假设,然后开发单独的方程组。
家庭的问题是最大化效用,假设更多的消费会增加效用,更长的工作时间会减少效用。但是家庭不能消费无限多的商品。相反,它们受到预算约束,预算约束规定所有收入来源必须等同于所有收入用途。
当最大化问题被解决时,人们会发现(在其他条件不变的情况下),消费的增加只能通过延长工作时间来实现。因此,在消费和休闲之间有一个权衡。进一步的评估还将揭示,家庭必须在今天消费额外商品和未来消费之间做出选择。这些效应中哪一个会更强?
图片作者:特里斯特·约瑟夫
公司的目标是在一个完全竞争的市场中最大化利润。现在,完全竞争的假设并不总是成立的,但它是假设的,因为它代表了理想的情况和有效运作的市场。然而,完全竞争也意味着企业从长远来看不会获得经济利润。这是因为随着时间的推移,新公司的进入(因为没有进入壁垒),这压低了市场价格。
为了生产商品,企业使用资本和劳动力等投入。理想情况下,生产函数应该表现出稳定的规模收益。这意味着公司的产出将与所有投入的增加成正比,这表明没有投入被浪费。一旦实现了最大化,就会发现实际工资的下降会导致更高的劳动力需求量。这是意料之中的,因为这意味着以更低的成本雇佣工人,公司会愿意雇佣更多的劳动力。
图片作者:特里斯特·约瑟夫
现在这个过程可以对模型中的每个代理执行,我将附上继续这个过程的论文,但概念保持不变。一旦进行了所有的优化,当模型的一系列内生变量满足定义均衡的条件时,市场将清算(或实现“一般均衡”)。对于前面的例子,这意味着:一个家庭将决定消费、投资和工作的数量,以效用最大化为目标,假定价格是给定的。此外,企业将通过选择劳动力和资本的最优数量来决定生产多少,将投入价格视为给定并受制于技术。
虽然上述情景指的是经济活动和评估经济政策,但我认为 DSGE 模型适用于更多的情景。考虑一个试图让用户发布更多内容并增加平台整体参与度的内容创建平台。添加一个新功能(比如高级用户)会有什么影响?这个想法是,高级用户将可以访问平台上的独家群组和功能,而普通用户将无法访问。
嗯,理论可能表明,这将鼓励用户更加活跃,加入专属用户组,从而增加参与度。然而,对排斥的担忧可能会导致一些创作者对平台持负面看法,并降低整体使用率。鉴于它们的相对优势,哪种结果更有可能出现?为了评估这一点,应该利用 DSGE 模型。
参考资料和其他有用的材料:
奥利维尔·布兰查德的宏观经济学
N .格雷戈里·曼昆的宏观经济学
aeaweb.org/articles?id=10.1257/jep.32.3.113
sciencedirect.com/science/article/pii/S1517758017300930
new York fed . org/media library/media/research/EPR/10 v16 N2/1010 sbor . pdf
Seaborn 中的动态子情节布局
在一个网格中可视化支线剧情
Seaborn 是最常用的可视化库之一,我喜欢使用它。在我最近的项目中,我想以一种动态的方式可视化多个支线剧情。令我惊讶的是,我没有在网上任何地方找到直接的解决方案,所以我想分享我的方法。它在任何数据分析工作中都非常有用。
目录
问题是
让我们看看泰坦尼克号的数据集:
有多个分类变量,我们可能希望用计数图来形象化。通过在每个新单元格中复制代码来实现这一点并不是最佳选择:
seaborn 有一个 FacetGrid 选项:
然而,我想有不同的支线剧情,我可以为自己设置每个情节。
方法
谢天谢地,还有支线剧情功能:
categorical_vars = ['survived', 'pclass', 'sex', 'age', 'sibsp', 'parch',
'embarked', 'class', 'who', 'adult_male', 'deck', 'embark_town',
'alive', 'alone'] fig, axs = plt.subplots(nrows=2, ncols=2)for i, var in enumerate(categorical_vars):
row = i//2
pos = i % 2 plot = sns.countplot(x=var, data=titanic, ax=axs[row][pos])
这导致:
这说明了我经常遇到的问题。对于多个变量,我总是需要手动设置行数和列数。(fig, axs = plt.subplots(nrows=2, ncols=2)
)
解决方案
为了解决这个我,把它改成了:
categorical_vars = ['survived', 'pclass', 'sex', 'age', 'sibsp', 'parch',
'embarked', 'class', 'who', 'adult_male', 'deck', 'embark_town',
'alive', 'alone'] num_plots = len(categorical_vars)
total_cols = 3
total_rows = num_plots//total_cols + 1fig, axs = plt.subplots(nrows=total_rows, ncols=total_cols,
figsize=(7*total_cols, 7*total_rows), constrained_layout=True)for i, var in enumerate(categorical_vars):
row = i//total_cols
pos = i % total_cols plot = sns.countplot(x=var, data=titanic, ax=axs[row][pos])
这就导致了:
将其更改为两列,如下所示
将其更改为 4 列,如下所示
现在,我可以根据自己的意愿定义地块的布局,也可以决定要绘制什么。即使看起来挺容易的,网上也没找到相关的。所以也许这对你们有些人有帮助。)
关于
丹尼尔是一名企业家、软件开发人员和商业法毕业生。他曾在各种 IT 公司、税务咨询、管理咨询和奥地利法院工作。
他的知识和兴趣目前围绕着编程机器学习应用程序及其所有相关方面。从本质上说,他认为自己是复杂环境的问题解决者,这在他的各种项目中都有所体现。
如果您有想法、项目或问题,请不要犹豫与我们联系。
你可以在 https://www.buymeacoffee.com/createdd 支持我
连接到:
动态时间扭曲
解释和代码实现
听起来像时间旅行或某种未来技术,然而,它不是。动态时间弯曲用于比较两个不同长度的数组或时间序列之间的相似性或计算它们之间的距离。
假设我们想计算两个等长数组的距离:
a = [1, 2, 3]
b = [3, 2, 2]
怎么做呢?一个显而易见的方法是以一对一的方式匹配a
和b
,并对每个分量的总距离求和。这听起来很容易,但是如果a
和b
的长度不同呢?
a = [1, 2, 3]
b = [2, 2, 2, 3, 4]
如何将它们搭配起来?哪个应该映射到哪个?为了解决这个问题,出现了动态时间扭曲。正如它的名字所表明的,扭曲系列,使他们能够匹配。
用例
在深入研究这个算法之前,你可能会问它有用吗?我们真的需要比较两个不等长时间序列之间的距离吗?
是的,在很多情况下,DTW 都扮演着关键角色。
声音模式识别
一个用例是检测同类的声音模式。假设我们想通过分析一个人的声音轨迹来识别他的声音,在一个场景中,我们能够收集他说Hello
的声音轨迹。然而,人们以不同的方式说同一个词,如果他像Heeeeeeelloooooo
一样以慢得多的速度说你好,我们将需要一种算法来匹配不同长度的声音轨道,并能够识别它们来自同一个人。
股票市场
在股票市场中,人们总是希望能够预测未来,然而使用通用机器学习算法可能是穷尽的,因为大多数预测任务需要测试和训练集具有相同维度的特征。然而,如果你曾经在股票市场投机,你会知道,即使是同一种股票形态,在价格线和指标上也会有非常不同的长度反映。
定义和理念
维基上对 DTW 的简明解释,
在时间序列分析中,动态时间弯曲(DTW)是用于测量两个时间序列之间相似性的算法之一,这两个时间序列的速度可能不同。DTW 已被应用于视频、音频和图形数据的时间序列——事实上,任何可以转化为线性序列的数据都可以用 DTW 进行分析。
比较不同长度的数组的想法是建立一对多和多对一的匹配,从而使两者之间的总距离最小化。
假设我们有两个不同长度的数组红色和蓝色:
显然,这两个系列遵循相同的模式,但蓝色曲线比红色曲线长。如果我们应用一对一的匹配,显示在顶部,映射没有完全同步,蓝色曲线的尾部被遗漏了。
DTW 通过开发一对多匹配克服了这个问题,这样具有相同模式的波谷和波峰就完美匹配,两条曲线都没有遗漏(如底部顶部所示)。
规则
一般来说,DTW 是一种计算两个给定序列(如时间序列)之间最佳匹配的方法,具有一定的限制和规则(来自 wiki):
- 第一个序列的每个索引必须与另一个序列的一个或多个索引匹配,反之亦然
- 第一个序列的第一个索引必须与另一个序列的第一个索引匹配(但不必是唯一的匹配)
- 第一个序列的最后一个索引必须与另一个序列的最后一个索引相匹配(但它不必是唯一的匹配)
- 来自第一序列的索引到来自另一序列的索引的映射必须是单调递增的,反之亦然,即如果
j > i
是来自第一序列的索引,则在另一序列中不能有两个索引l > k
,使得索引i
与索引l
匹配,索引j
与索引k
匹配,反之亦然
最佳匹配由满足所有限制和规则并且具有最小成本的匹配来表示,其中成本被计算为每个匹配的索引对的值之间的绝对差的和。
总结起来就是头尾一定要位置匹配,不能交叉匹配,不能遗漏。
履行
该算法的实现看起来非常简洁:
其中DTW[i, j]
是具有最佳对准的s[1:i]
和t[1:j]
之间的距离。
关键在于:
DTW[i, j] := cost + minimum(DTW[i-1, j ],
DTW[i , j-1],
DTW[i-1, j-1])
也就是说,长度为i and j
的两个数组之间的成本等于尾部之间的距离+长度为 *i-1, j*
、 *i, j-1*
和 *i-1, j-1*
的数组中的最小成本。
用 python 来说就是:
示例:
a and b
之间的距离将是矩阵的最后一个元素,即 2。
添加窗口约束
上述算法的一个问题是,我们允许一个数组中的一个元素匹配另一个数组中无限数量的元素(只要尾部最终能够匹配),这将导致映射过度,例如,下面的数组:
a = [1, 2, 3]
b = [1, 2, 2, 2, 2, 2, 2, 2, ..., 5]
为了最小化距离,数组a
中的元素 2 将匹配数组b
中的所有元素 2,这导致数组b
严重弯曲。为了避免这种情况,我们可以添加一个窗口约束来限制可以匹配的元素数量:
关键的区别在于,现在每个元素都被限制为匹配范围i — w
和i + w
中的元素。w := max(w, abs(n-m))
保证所有指标能够匹配。
实现和示例如下:
应用包
Pypi 上还有一些贡献包可以直接使用。这里我用 fastdtw 演示一个例子:
它给出了两个列表的距离和索引映射(这个例子可以扩展到一个多维数组)。
最后,您可以在这里查看实现。
参考:
[1]https://databricks . com/blog/2019/04/30/understanding-dynamic-time-warping . html
https://en.wikipedia.org/wiki/Dynamic_time_warping
闪亮的动态用户界面(包括演示应用)
高级 R 闪亮吸头系列
为您的公司创建专业的 web 应用程序
用 R Shiny 构建企业级应用!—此处提供演示
序文
闪亮的已经成为一个非常流行的解决方案,直接从 R 构建交互式网络应用。如此受欢迎,以至于公司中的大多数数据分析团队都将该框架作为其工具包的一部分。
然而,R Shiny 经常被认为是快速原型开发的好框架,但是对于工业化的、可扩展的解决方案来说不够健壮。
在本系列中,我将分享一些高级技巧,旨在克服这些异议,并帮助您构建健壮/可持续/可扩展的应用程序,为生产中的业务使用做好准备!
生产定义如下:
真实用户使用和依赖的软件环境,如果出现问题,会产生真实的后果——首席技术官郑中
注:为了从本教程中获得最大收益,感兴趣的读者应该已经熟悉基本的 Shiny 原则(例如反应性)、R 编程(例如函数定义、tidyverse、 purrr::map() )、web 开发(例如 html 标签和 css)以及 RStudio 项目。
目标和动机
在本教程中,我将重点描述一种基于用户输入动态生成 UI 组件的可再现方式。
这个特性在很多情况下都非常有用,因为你的应用程序的用户很可能会在他们的仪表板上显示一个先验未知数量的信息。仅举几个例子:
- 在用户投资组合管理应用程序中添加/删除股票
- 在时间序列预测应用中考虑/忽略特定事件
- 在零售商业绩分析应用程序中包含/排除商店
- …
此外,我还将描述如何定义观察器来触发动态生成的按钮的动作,这不是一个简单的任务(因为它需要一点 JavaScript)。
闪亮的应用伴侣
本教程附带一个 R Shiny 演示应用程序,你可以在这里访问。
在这个特殊的教育示例中, you (用户)可以根据需要选择尽可能多的陌生事物角色,并通过我称之为 的信息卡 显示每个角色的基本信息。
这里用户显示了 3 个陌生事物角色的信息卡
每个角色的信息卡提供了额外的功能:
- 访问 到演员的详细维基百科页面(点击“更多”按钮)
- 删除信息卡 的可能性(点击“删除”按钮)
我的建议:为了从本教程中获得最大收益,我建议尝试通过组合整篇文章中提供的各种代码来重建应用程序。主块以逻辑方式编号,这样你就不会在途中迷路。如果有必要的话,我的 bitbucket 账户上的全部代码也可以在这里找到。请看看在项目结构中哪里存储图像。
0 —分析顺序
我指导您完成代码的方法如下:
- 设置场景:描述需要的 R 包、底层数据集、应用主干
- 定义用户输入:应用程序中用于捕获用户输入的 HTML 小部件的描述
- 定义 infocard 函数:生成 HTML 代码的函数,结合 purrr::map() 函数,将非常有助于“即时”生成 infocard
- 服务器端定义:创建反应值和观察器,使应用程序“闪亮”
1 —设置场景
要为本教程构建 R Shiny companion 应用程序:
我使用了以下 4 个包 : 闪亮、闪亮主题、闪亮主题和无光泽
**# PART 1 - SETTING THE SCENE****# section 1.0 - load required packages**library(shiny) # web app framework for R
library(shinythemes) # themes for shiny
library(shinyWidgets) # custom input widgets for shiny
library(tidyverse) # collection of R packages for data science
我建立了一个小型的数据集,里面有关于主要陌生事物角色的基本信息(来源:维基百科):
**# section 1.1 - build dataset**crm_tbl <- **tibble**(
character = c("Joyce Byers", "Jim Hopper",
"Mike Wheeler", "Jane Hopper",
"Dustin Henderson", "Lucas Sinclair",
"Nancy Wheeler", "Jonathan Byers",
"Karen Wheeler", "Will Byers",
"Max Mayfield", "Steve Harrington"),
actor = c("Winona Ryder", "David Harbour",
"Finn Wolfhard", "Millie Bobby Brown",
"Gaten Matarazzo", "Caleb McLaughlin",
"Natalia Dyer", "Charlie Heaton",
"Cara Buono", "Noah Schnapp",
"Sadie Sink", "Joe Keery"),
image = c("img/winona_ryder.jpg", "img/david_harbour.jpg",
"img/finn_wolfhard.jpg", "img/millie_bobby_brown.jpg",
"img/gaten_matarazzo.jpg", "img/caleb_mclaughlin.jpg",
"img/natalia_dyer.jpg", "img/charlie_heaton.jpg",
"img/cara_buono.jpg", "img/noah_schnapp.jpg",
"img/sadie_sink.jpg", "img/joe_keery.jpg"),
wiki = c("[https://en.wikipedia.org/wiki/Winona_Ryder](https://en.wikipedia.org/wiki/Winona_Ryder)",
"[https://en.wikipedia.org/wiki/David_Harbour](https://en.wikipedia.org/wiki/David_Harbour)",
"[https://en.wikipedia.org/wiki/Finn_Wolfhard](https://en.wikipedia.org/wiki/Finn_Wolfhard)",
"[https://en.wikipedia.org/wiki/Millie_Bobby_Brown](https://en.wikipedia.org/wiki/Millie_Bobby_Brown)",
"[https://en.wikipedia.org/wiki/Gaten_Matarazzo](https://en.wikipedia.org/wiki/Gaten_Matarazzo)",
"[https://en.wikipedia.org/wiki/Caleb_McLaughlin](https://en.wikipedia.org/wiki/Caleb_McLaughlin)",
"[https://en.wikipedia.org/wiki/Natalia_Dyer](https://en.wikipedia.org/wiki/Natalia_Dyer)",
"[https://en.wikipedia.org/wiki/Charlie_Heaton](https://en.wikipedia.org/wiki/Charlie_Heaton)",
"[https://en.wikipedia.org/wiki/Cara_Buono](https://en.wikipedia.org/wiki/Cara_Buono)",
"[https://en.wikipedia.org/wiki/Noah_Schnapp](https://en.wikipedia.org/wiki/Noah_Schnapp)",
"[https://en.wikipedia.org/wiki/Sadie_Sink](https://en.wikipedia.org/wiki/Sadie_Sink)",
"[https://en.wikipedia.org/wiki/Joe_Keery](https://en.wikipedia.org/wiki/Joe_Keery)")
)
应用中使用的输入存储为tible
我选择用 2 个活跃的角色初始化应用程序,这意味着当应用程序启动时,将显示 2 个信息卡:
**# section 1.2 - set initial selection** current_user_selection <- c("Jim Hopper", "Joyce Byers")
最后,我为应用程序构建了一个基本的主干,由以下部分组成:
- 一个导航条页面(空白引导 3 带有顶级导航条的页面)
- 一个左侧栏(我用了shiny::well panel()函数)
- 信息卡区域
**# PART 2 - UI PART****# app backbone**ui <- **navbarPage**(
title = "R Shiny advanced tips series",
collapsible = TRUE,
windowTitle = "R Shiny tips",
**tabPanel**(
title = "Demo",
**# section 2.1 - header**
**# section 2.2 - sidebar panel**
div(
class = "container",
column(
width = 3,
**wellPanel**(
**p("PLACEHOLDER - USER INPUTS")**
)
),
column(
width = 9,
div(
# render thumbnails dynamically (ui)
**p("PLACEHOLDER - INFOCARDS")**
)
)
)
)
)**# PART 3 - SERVER PART**
server <- function(input, output, session) {
}**# PART 4 - RUN APPLICATION**
shinyApp(ui = ui, server = server)
header (backbone 的 2.1 节)是一个简单的容器,我在其中显示了应用程序的基本信息。我利用现有的引导类使文本引人注目(见页眉和 lead 类)
# >> insert in section 2.1div(
class = "**container**",
h1(class = "**page-header**",
"Generate dynamic UI components",
tags$small("- Thomas Filaire")),
p(class = "**lead**",
"Learn how to generate UI components dynamically based on user inputs"),
p("Note: this application is the companion of my Medium post; read it to understand its underlying principles!")
)
2 —定义用户输入
添加新信息卡的选择器+按钮
为了说明动态 UI 功能,我构建了一个非常简单的选择器,供用户选择她/他最喜欢的陌生事物角色。选中后,只需点击“添加”按钮即可显示相应的信息卡。
虽然 shiny 包中的基本的selectin put()很棒,而且我大部分时间都在使用它,但我还是选择了shinyWidget::pickerInput()替代,它提供了许多好处,特别是 live search 功能。测试它,我相信你会采纳它!
# >> insert inside wellPaneldiv(
shinyWidgets::**pickerInput**(
inputId = "pi_character_selector",
label = "Select character(s)",
choices = crm_tbl %>% pull(character),
multiple = FALSE,
selected = "Mike Wheeler",
options = **pickerOptions**(
actionsBox = FALSE,
**liveSearch = TRUE**,
size = 10
)
)
),
div(
**actionButton**(
class = "btn-primary",
inputId = "ab_show_character",
label = "Add"
)
)
)
3-定义信息卡功能
我构建了一个函数来生成 infocard (因此是一段 HTML 代码),稍后我将在一个 purrr::map() 函数中从服务器端调用它,以将其应用于一个陌生事物字符列表。
作为一名优秀的程序员,你应该拥抱函数式编程,因为它迫使你创建易于独立分析的函数,并避免不必要的代码重复,提高可读性。
该函数将一个角色的名字作为输入,并返回 infocard (HTML 对象)。需要注意的 3 件重要事情:
- 请注意呈现 HTML 代码是如何像生成数字、列表、图表等一样简单。,我们平时用函数做的。
- 注意 bootstrap 3 的预先存在的类 (img-rounded,caption,btn-default)的用法,加上分配给‘remove button’的 rm_btn 类,我将在本教程的第 4 部分进一步阐述。
- 注意非常有用的 stringr::str_glue() 函数的用法,我用它给每个按钮分配唯一的 id。这是一个关键部分,因为 id 必须是唯一的,并且需要在点击相应按钮时触发动作。
【str _ glue()使得在字符串内插入变量值变得容易。为了使每个按钮的 id 都是唯一的,我采用了以下模式:
- 对于“更多”按钮:ab _ more _ character _ name(ab 代表 actionbutton)。
- 对于“移除”按钮:ab _ remove _ character _ name。
如 ab_more_joyce_byers、ab_remove_joyce_byers 等。
我还使用了 stringr 包中的函数来小写/大写所选角色的名字,并添加/删除“_”,从而使 string 成为一个有效的 id。
# >> insert infocard definition as section 1.3 in PART 1 - SETTING THE SCENE of your app.R file**# section 1.3 - define custom infocard**my_infocard <- **function**(selected_character) {
# selected_character == value from user pickerInput
# e.g. "Mike Wheeler"
selected_image <- crm_tbl %>%
filter(character == selected_character) %>%
pull(image) # get image url from dataset
selected_actor <- crm_tbl %>%
filter(character == selected_character) %>%
pull(actor) # get actor's name from dataset
selected_wiki <- crm_tbl %>%
filter(character == selected_character) %>%
pull(wiki) # get wikipedia's link from dataset
# piece of UI to render dynamically
column(
width = 4,
div(
class = "**thumbnail text-center**",
# picture
img(
class = "**img-rounded**",
style = "height: 300px;",
src = selected_image
),
# main information
div(
class = "**caption**",
h4(selected_character),
p(selected_actor)
),
# link to wikipedia's page
**actionButton**(
class = "**btn-default**",
inputId = **str_glue("ab_more_{selected_character %>%
tolower() %>%
str_replace_all(' ', '_')}")**,
label = "More",
onclick = **str_glue("window.open('{selected_wiki}', '_blank')")**
), # remove button
**actionButton**(
class = "**btn-default** rm_btn",
inputId = **str_glue("ab_remove_{selected_character %>%
tolower() %>%
str_replace_all(' ', '_')}")**,
label = "Remove"
)
)
)
}
4 —服务器端定义
一旦我们定义了应用程序的主干,并构建了生成定制信息卡的函数,让我们跳到服务器端。
首先,我使用了一个event reactive()函数来捕获用户通过 pickerInput 小部件选择的任何新字符。event reactive()仅当用户点击“添加”按钮(其 id 为 input$ab_show_character)确认其选择时,才允许更新电抗组件。
# >> insert in server part # get user's selected character when 'Add' button is clicked
current_character <- eventReactive(
eventExpr = input$ab_show_character, {
input$pi_character_selector
})
每当用户选择一个新字符时,必须捕获信息并将其添加到先前选择的字符列表中。我使用了一个reactive values()来存储选择的字符,用第 1 部分定义的 current_user_selection 初始化。
每当单击“添加”按钮时,observeEvent 都会更新 reactive_values。我在管道中插入了一个 unique() ,以确保信息卡被多次创建,因此只显示一次。
# >> insert in server part# store user's selection
reactive_values <- reactiveValues()
reactive_values$character_list <- current_user_selection# add character when relevant
observeEvent(input$ab_show_character, {
reactive_values$character_list <-
c(reactive_values$character_list,
current_character()) %>%
**unique**()
})
基于 reactive_values$character_list(用户选择的字符列表),我在 renderUI 块中根据需要生成尽可能多的信息卡,然后通过相应的 uiOutput 在 UI 中“渲染”:
# >> insert in the main area of ui section**uiOutput**(outputId = "infocards")
为了构建 UI 部分,我在 函数中传递了字符列表,以便根据需要多次调用自定义的 my_infocard() 函数。当 purrr::map() 返回一个列表时,我用 tagList() 函数将结果管道化,以将输出绑定在一起,并生成一个唯一的(可能很大的)HTML 部分。
请看下面截图中关于 tagList() 如何工作的直观解释:
tagList()将几段 HTML 代码组合成一个块,然后可以通过经典的“renderUI x uiOutput”组合来呈现
在开发的这个阶段,应用程序应该几乎按照预期工作。
最后的触碰
最后添加的功能是通过点击“删除”按钮来删除信息卡。
我在这里使用了一点 JavaScript。我不会详细讨论 JavaScript(我远不是这一领域的专家),但请注意:
- JavaScript 通过标签 (head 和 Script)插入到 R Shiny 应用程序的 HTML 代码中
- 每当点击带有 rm_btn 类的按钮时,代码只是存储按钮 id (rm_btn_id)
# >> insert in the tabPanel, below title# JS function to identify button id when clicked
tags$**head**(
tags$**script**(
HTML("$(document).on('click', '**.rm_btn**', function () {
Shiny.onInputChange('**rm_btn_id**', this.id);
});"
)
)
),
因为“移除”按钮有 rm_btn 类(见 1.3 节中的定义),所以每当它们被点击时,Shiny 将访问它们各自的 id。最后,我利用这一点,通过一个observe event(),从字符列表中删除相应的字符。
# >> insert in server part# remove infocard
**observeEvent**(input$**rm_btn_id**, {
reactive_values$character_list <-
reactive_values$character_list %>%
.[reactive_values$character_list %>%
toupper() **!=** input$rm_btn_id %>%
str_remove("ab_remove_") %>%
toupper() %>%
str_replace("_", " ")]
})
我们完事了。如果你能坚持到现在,恭喜你!。
关键要点
- shinythemes 是一个非常棒的软件包,可以非常容易地让你的应用程序看起来很专业
- 顺序是:用户输入列表+ map("生成 HTML 代码的函数")+ tagList()非常强大,并且在我看来是可读的。
- 创建函数来生成 HTML 片段,以避免代码重复,并轻松使用上述序列
结论
我希望这篇文章对您有用,并能帮助您构建更好的应用程序。你可以在我的 bitbucket repo 这里 找到完整的代码。
请不要犹豫发送任何反馈或问题!
来源
动态与个性化
你需要知道的区别,以改善你的沟通
约翰·施诺布里奇在 Unsplash 上的照片
今天,人们希望网站和服务能够适应他们的具体情况。在特定时刻根据我们的需求定制的服务对我们更有用——让它成为谷歌的网络搜索,用地图规划下一个假期,在亚马逊上查找产品,或者在网飞上搜索下一个要疯狂观看的剧集。我们喜欢能在 Zazzle 上买到的定制商品和印有我们名字的可乐。
作为一名数据科学家,我思考了 web 服务定制的不同种类,并意识到有一些重要的类型需要区分。最重要的是:服务是动态的还是个性化的——或者两者都是?
动态服务会随着一天中的时间、一周中的日期或季节而变化。个性化服务因用户而异。
想想谷歌地图上的度假计划。当你什么都不输入的时候,什么部分显示给你?当然是离你现在位置尽可能近的东西。这完全取决于你。谷歌地图是个性化的。如果您搜索“餐馆”,如果您在下午或晚上搜索,结果可能会有所不同。下午的搜索可能会显示咖啡馆,而晚上的搜索可能会显示酒吧。我希望每个用户都有这种行为。所以是动态。
还有一些不太清楚的信号:设备类型(智能手机对平板电脑对台式机),互联网连接速度,如果你在一个有容量限制的计量网络上,例如移动互联网,我会想到。虽然这些可能会导致网络应用程序的变化,但本质上更具技术性。有些更多的是关于响应式网页设计。
如果仅仅是关于如何呈现而不是呈现什么,这就是一个响应性的网页设计主题。
典型的例子是为适应小屏幕而改变布局,以及为慢速或计量网络而改变图像大小/裁剪。
定制与个性化
定制和个性化都是产品对用户的适应。区别在于谁在推动适应:
定制是用户根据用户的需求调整产品。个性化是由销售者根据用户调整产品。
我故意不写个性化是对用户需求的调整,因为有时它实际上可能会伤害用户。想一想国外的一家商店,他们看到你是游客后会提高价格。
个性化可乐瓶。迈克·莫扎特的图片(来源)
给我看例子!
- 服装店有动态价格:当新一季开始时,旧衣服需要处理掉。价格在季末会降低。
- 可乐在瓶子上印名字。这是一个定制的例子。用户选择他们想要的瓶子,因此他们是推动产品“变化”的人。Nutella 做了类似的东西。
- 像宝马的汽车配置器就是配置定制的一个例子。日产计划扩展这种能力,并将其称为“超个性化”(来源)——当客户驾驶它时,它仍然是定制。
- 营销信函在这些信函中,你会收到一条信息,上面有你的完整地址、你的名字,可能还会对文本进行一些轻微的调整个性化。是的,很琐碎。是的,它只是简单地使用模板和规则。没人说个性化总是要硬的吧?
- Zazzle 提供许多可以定制的产品,例如印有你名字的 t 恤。
当然,有一些明显的候选软件,您也可以在其中看到这些主题:
- 动态定价被亚马逊(来源)、酒店(来源)、火车和汽车票(日期越近,车票越贵)广为人知地使用。这里的想法是通过算法根据需求调整价格。当供给不能改变时,这在理论上导致更好的资源利用。
- 大多数人真的不喜欢个性化定价,但这可能会发生在飞机票上(来源)。有传言称,一些公司提高了 iPhone 用户的价格,因为他们有更多的钱,更愿意支付,但我没有找到证据证明这一点。
- 网飞非常个性化,甚至将此作为他们业务的核心部分。我也以非常相似的方式想到了 Spotify。
- 搜索气泡是个性化的另一个例子。无论是谷歌搜索还是 Facebooks 的新闻订阅:影响你看到的内容都会产生巨大的影响。因为这是你无法控制的,所以这是个性化。
个性化的含义是什么?
P 个性化服务更难甚至不可能缓存在服务器端。你需要考虑隐私。您可能需要向用户传达这种个性化。可能会有法规强迫你公开正在使用的部分算法(例子),以确保没有针对少数族裔的偏见。
尤其是如果你应用机器学习,沟通决策过程是很困难的。这对于内部对准以及外部透明度来说都是一个问题。人们倾向于说机器学习算法不可解释,甚至说我们不理解模型如何做出决策。我强烈反对这种说法,但这是另一回事。如果你感兴趣,我推荐你阅读扎克·蔡斯·利普顿的《模型可解释性的神话》。
解释决策的需要可能会迫使你存储个人信息。万一有数据泄露, GDPR 强迫你通知受影响的人。这不仅是一场公关噩梦,而且为这个案子做准备会让事情变得更加复杂。总结一下:
只有在收益证明努力是合理的情况下,才个性化产品。
动态服务也有同样的问题吗?
D 动态服务不像个性化服务那样有隐私相关的问题。动态服务的信号也可能比个性化服务少。这使得沟通决策过程变得更加容易。影响因素较少意味着缓存可能更容易。这也可能意味着人们可以预先计算服务的结果!预计算很棒,因为它使确保服务的可用性变得更加简单。还能让服务快如闪电!
它是完全动态的还是个性化的?
N o!肯定不是!举个例子,以我的小服务 write-math.com 为例,它允许你画一个符号(希腊或拉丁字母,数字,箭头,其他一些)并告诉你你画了什么。它既不是动态的,也不是可定制或个性化的。
write-math.com 的截图。画出了希腊字母α,并认出了两个非常相似的符号。图片作者。
我可以通过让你选择想要识别的符号组来使它可定制。字母和数字很无聊吗?把它们关掉。
我也可以通过查看在一天中的哪个时间典型地查找哪些符号来使其动态化。我可以告诉你,很多人画阴茎,我猜想这可能与当地时间有关。
我也可以通过创建个人资料来个性化它。如果单个用户输入了足够多的符号,我会比显示“未知”符号更多地显示该用户已经输入的符号。
照片由Alperen yazg在 Unsplash 上拍摄
胜利的随机性!
想清楚你的目标。优选地从用户的角度来看。如果你有一个新闻聚合网站,用户不会从更动态的页面中受益。但是用户可能受益于探索更多内容的可能性。拥有更动态的页面是实现这一目标的一种方式。你可以在这里做各种有趣的事情,但是有一个简单的入门技巧:随机选择。不一定是每一个电话,但只要你想得到你认为好的动态。这给了你一个机会去观察用户的反应,理解技术上的困难,并收集更聪明的方法。
在 Power BI 中动态显示任务
棘手的任务有时可以比你想象的更容易解决,用一点 DAX 魔法!
尼克·费因斯在 Unsplash.com 拍摄的照片
几周前,我正在处理客户支持部门的一个请求。从本质上来说,业务请求是为了让主管能够动态地过滤需要执行的任务。
由于主管也有他们自己的任务,他们应该能够在他们自己的任务和来自所有代表的任务之间动态地切换视图。
USERNAME() & USERPRINCIPALNAME()函数
像往常一样,DAX 为您的挑战提供了便捷的解决方案。这一次,我将使用其中一个信息函数…或者更准确地说,不是一个,而是两个,它们非常相似,但在不同的环境下仍然会产生不同的结果。
让我们从 USERNAME() 函数开始。这个函数将返回当前连接的域名和用户名。所以,如果我创建这样的度量:
My User = USERNAME()
My User Principal = USERPRINCIPALNAME()
把它放在一个简单的卡片上,这是我得到的结果:
USERPRINCIPALNAME() 将返回 UPN(用户主体名)。根据您的设置,在 Power BI Desktop 中,结果可以与 USERNAME() 函数完全相同(就像我的例子一样),或者它可以返回登录到 Power BI Desktop 的用户的电子邮件地址。
但是,一旦您将报告发布到 Power BI Service,这两个函数将表现相同,并将电子邮件地址作为一个值返回:
解决原始问题
现在,回到我最初的问题,这里是我们如何利用这些函数找到一个优雅的解决方案。
这是一个包含与任务相关的数据的表格。如您所见,我有一个任务被分配到的用户、任务 ID 和任务创建的日期。
另一个表包含关于用户的数据(我创建了一个虚拟的第二个用户,只是为了模拟真实的场景):
两个表通过用户本地列连接,如下图所示:
最重要的一步是定义一个计算“我的”任务的方法——当我说“我的”时,我指的是浏览报表的用户的任务。
以下措施将有助于我们实现这一目标:
My Tasks = CALCULATE(
COUNTROWS(Tasks),
KEEPFILTERS(Users[User Local] = USERNAME()
)
)
使用 KEEPFILTERS() 函数,我们正在修改 CALCULATE 函数的默认行为,因为在 CALCULATE 函数中定义的过滤器参数将替换指定列上的所有现有过滤器。
应用 KEEPFILTERS ,如果计算过滤器替换当前上下文, KEEPFILTERS 会将过滤器添加到当前上下文。
也就是说,如果我将这种方法用于卡片视觉,我会得到以下结果:
由于我以 NIKOLAI\nickk 的身份登录,我看到有 5 项任务分配给了我,这是正确的。
最终抛光以获得更好的体验
现在,我希望我的主管用户能够选择他希望在报告中看到的内容:所有任务或仅分配给她/他的那些任务。为此,我将使用书签并在我的报告页面中做一些调整。
第一步是创建现有表的副本,并对其应用筛选器,以便只显示我的任务度量值大于 0 的行:
我将这个新表放在旧表的正上方,旧表显示所有任务。我将切换标题的背景颜色,这样用户也可以根据颜色来区分表格。
接下来是我的解决方案的最后润色:我将在报告画布上放置一个按钮,使我的用户能够在两个不同的视图之间动态切换。或者,更好的是,我将把两个按钮一个放在另一个上面,以节省报告页面的空间,同时保留书签操作的全部功能。
最后一步是创建书签,并为每个书签定义适当的操作:
“所有任务”书签将隐藏两个视觉效果(请参见上图),而“我的任务”书签将应用类似的逻辑,但方向相反:
最后,让我们为按钮定义操作,以便能够在刚刚创建的两个书签之间导航:
完成后,我们的最终解决方案是这样的:
在我们结束之前, 一个重要的备注 :为了让这个技巧在 Power BI 服务中工作,您需要切换我的任务度量中的函数,使用用户服务而不是用户本地:
My Tasks = CALCULATE(
COUNTROWS(Tasks),
KEEPFILTERS(Users[User Service] = USERNAME()
)
)
结论
乍一看,最初的请求似乎很棘手,很有挑战性。然而,通过应用一些基本但有用的 DAX 函数,并使用书签稍作调整,我们能够为我们的用户提供一个优雅而有效的解决方案。
感谢阅读!
订阅此处获取更多有见地的数据文章!
在 30 分钟内将 1 亿多条记录导入 DynamoDB
AWS 上周发布了一个新功能,只需点击几下就可以导出一个完整的 Dynamo 表,但了解如何用任何规模的数据来水合一个表也是值得的。
杰瑞米·毕晓普在 Unsplash 拍摄的照片
在设置将 DynamoDB 表完全导出到 S3 的过程中,任何人都不会受到影响。
然而,对于希望将数据导入 Dynamo 表的人来说,情况就不一样了。尤其是数据量大且速度快。
当表中的记录损坏时,可能需要快速大容量导入,修复它们的最简单方法是删除并重新创建整个表。或者在将数据流式传输到表中时,运行夜间批处理“校正”作业来纠正可能已经发生的任何日间异常是很有用的。
将这些类型作业的完成时间从一个多小时缩短到不到一分钟,让您对任何给定时间点的数据状态更有信心。它为在您的数据上构建低潜在应用程序提供了更稳定的基础。
简单的写作方式
假设我们在 A 点的 S3 存储桶中有数据,我们想把它移到 B 点的发电机表中…我们如何做呢?
将数据从 S3 转移到迪纳摩就像从 A 点转移到 B 点一样简单!|作者图片
最简单的方法是编写一个小脚本,将文件读入 DataFrame 对象,遍历该对象的行,然后执行一个dynamo.Table().batch_writer().put_item()
操作将项目插入到表中。
在 500k 行数据帧上运行此脚本会产生以下写入性能:
单线程发电机写进程的性能。|作者图片
如您所见,每秒对表的写入次数(w/s)的上限约为 650 w/s。Amazon 指出,对 Dynamo 的单个进程写入的真正限制是 1,000 w/s,但是由于网络和其他开销,观察到的值更低(从我的笔记本电脑本地运行)。
对于 500,000 条记录,将所有记录插入表中大约需要 15 分钟。根据您的使用情况,这可能是可以接受的。但是对于大型数据集的大容量插入—比如 1 亿行(!)—很明显,提高写吞吐率会有所帮助。
我们能做得更好吗?
达到发电机的速度极限
为了提高写性能,显然需要不止一个进程向表中写入数据。那么,我们如何让多个进程并行写入呢?
我发现实现这个的最优雅的方法是同时调用多个 Lambda 函数编写器实例。每一个都拾取数据集的一部分,并将其并行写入 Dynamo 表。
其工作方式是通过设置一个 Lambda 函数来触发 SQS 队列。这意味着如果一条消息被放入队列,Lambda 函数将调用并执行它的代码——将 SQS 消息值作为函数输入参数。
更进一步——如果这样一个 Lambda 包含类似上面的simple_dynamo_write.py
片段中的代码,并且放在队列中的消息是指向我们想要写入的数据的 S3 文件路径指针,那么应该清楚这些数据将如何进入 Dynamo!
每个 Lambda 实例将以 750 到 1000 w/s 的速度写入表,因此一旦我们同时执行多个实例,我们就可以实现更高的写入速度!
更新了 A 到 B 架构。|作者图片
诀窍是以一种 Lambda 可以高效无误地处理数据的方式来拆分和组织数据。AWS 对可以同时调用多少个 Lambda(1000)、单个 Lambda 调用在关闭前可以运行多长时间(15 分钟)以及单个 Dynamo 表每秒可以处理多少个写操作(40000)都有限制。
在使用服务时,知道相关的配额总是明智的,通常 AWS 在记录和提供这些信息方面做得很好。
考虑到这些限制,应该清楚的是,在完全并行化的情况下,我们不能将数据集分布到超过 1000 个 SQS 消息中,否则我们将达到 1000 个并发 Lambda 调用的限制。
每个文件也不能太大,否则 Lambda 将需要超过 15 分钟才能把它写到表中(提醒一下,之前写一个 500,000 行的文件需要将近 15 分钟)。Lambda 关闭中间文件并不好,因为如果不重新处理整个文件,就无法保证所有行都被写入。
控制所有这些因素的方法是创建最多 40 条 SQS 消息,由数据的 S3 文件路径的逗号分隔字符串组成。
例如,如果我们在 S3 有 3 个文件要写入 Dynamo,我们可以创建一个 SQS 消息,如下所示:
's3://bucket/file1.csv,s3://bucket/file2.csv,s3://bucket/file3.csv'
将此消息作为输入,Lambda 所做的是:
- 从输入字符串中弹出最后一个文件路径。
- 将文件数据写入 Dynamo 表。
- 在 SQS 队列上创建一个新消息,该消息在只剩下未处理的文件的情况下触发自身。
所以在编写完一个文件后,创建的新 SQS 消息将如下所示,关键是 Lambda 函数的一个新实例将几乎立即调用以开始处理file2
。
's3://bucket/file1.csv,s3://bucket/file2.csv'
一旦file2
得到处理,一个新的 SQS 消息将被放入队列:
's3://bucket/file1.csv'
在写入file1
之后,不再生成队列消息,不再调用 Lambdas,也不再有数据不在 Dynamo 表中!
为了更形象地展示这种递归策略,下面是一个 Lambda 函数代码示例:
现在,您将看到更多令人兴奋的视觉效果,而不是有限的写容量指标图!
达到每秒 75,000 次写入!|作者图片
包扎
使用这种架构,我们可以实现每秒向 Dynamo 写入高达 40k 的速度,因为最多可以并行运行 40 个进程,每个进程每秒写入 1k 行。
以前,100M 行的数据集在 1,000 w/s 的速度下需要 40 个小时,而在提高的速度下,我们只需 40 分钟就可以导入完整的数据集!(顺便说一句,Dynamo 表上的 40k 最大写入速度限制只是 AWS 的默认设置,可以根据要求增加)。
在使用 Dynamo 作为几个数据密集型应用程序的后端时,我发现以这种方式快速刷新整个数据集的能力非常有用。在特定行可能已损坏或被错误处理的情况下,修复数据的更多外科手术方法可能容易出错且耗时,因此不推荐使用。
最后,还有几个其他因素我没有机会在本文中涉及,比如对 Dynamo Capacity 模式的理想处理,以及 Dynamo 流等相关流程是如何受到影响的。
如果你对这些感到好奇,可以在下面的评论中提问或者在 Twitter 上联系。
感谢莱恩·凯利和迈克尔·彼得雷辛为本文提供灵感。
更多来自保罗·辛格曼
如果你同意“最模糊的墨迹比最强的记忆更强大”,那么你应该知道如何便宜地…
medium.com](https://medium.com/whispering-data/transcribe-your-zoom-meetings-for-free-with-aws-963f39a2aa3f) [## 解决无服务器数据管道中的碎片问题
如何在管理数十到数百个 lambda 支持的存储库时保持理智…
medium.com](https://medium.com/whispering-data/tackling-fragmentation-in-serverless-data-pipelines-b4027f506ee5)**
电子商务销售报告:错误图表、SQL 处理和 Data Studio 仪表板
这个项目旨在向您介绍如何利用 SQL 进行多数据集的关系映射和数据处理,并在 Data Studio 的帮助下创建一个自动化的报告仪表板
布莱克·维斯兹在 Unsplash 上的照片
SQL 是每个数据分析师都应该熟悉的基本语言之一,以便在关系数据库中存储、操作和检索数据。事实上,有许多不同的关系数据库管理系统(RDMS)使用 SQL 作为它们的标准语言,即 MySQL、Oracle、SQL Server 等。
也就是说,这个项目旨在最大限度地提高我使用 SQL 的能力,以探索和操作一家电子商务公司的多个数据集。不仅仅局限于数据处理;我决定扩展这个项目的范围,通过插入 Data Studio 构建一个报告仪表板来扩展结构化数据对可视化的适用性。
如果你感兴趣,可以在 Kaggle 查看公开提供的数据集。以下是该项目的主要亮点的快速总结:
- 用错误图映射数据集关系
- 将数据存储在中央数据库中的 SQL 处理
- 带有 Data Studio 的报告仪表板
1.数据集关系映射
我们应该如何处理彼此共享关系的多个数据集?
如果参考 Kaggle 提供的数据库,有 7 到 8 个独立的数据集代表一个电商销售报表:订单、客户、order_items、付款、发货等。在数据处理之前,我们需要确定所有数据集之间的关系,以避免可能导致数据丢失的错误映射。
以“order”和“customer”数据集为例,一个客户可以有 0 个或多个订单(一个 customer_id 对应不同的 order_id),但是一个订单只与一个客户绑定(一个 order_id 对应一个 customer_id)。
订单数据集
客户数据集
MySQL 自带构建 ERR 图的内置功能,允许我们可视化地映射和绘制数据集之间的关系。那么什么是 ERR 图呢?
实体关系图 (ER)显示数据库中存储的实体集的关系。换句话说,我们可以说 er 图帮助你解释了数据库的逻辑结构——Guru99.com
增强实体关系 图 (EER)基本上是 ER 图的扩展版本。EER 模型是用高级模型设计数据库的有用工具。有了它们的增强功能,您可以通过更精确地钻研属性和约束来更彻底地规划数据库—Cacoo.com
为了提供更直观的例子,
图片鸣谢:https://www . visual-paradigm . com/guide/data-modeling/what-is-entity-relationship-diagram/
数据集之间的关系由一个称为乌鸦食物符号的符号系统表示,如下所示:
图片来源:https://cacoo . com/blog/er-diagrams-vs-eer-diagrams-what-the-difference/
从本质上讲,ERR 图有助于我们更好地理解数据集之间的关系,以便我们能够更有效地进行数据处理。
对于这个项目,为了简单起见,我只选择了 5 个数据集,它们之间的关系可以很容易理解,如下图所示:
- (1)客户和订单:1 个客户可以有多个订单,所以批注样式应该是“一个或多个”。
- (2) orders 和 order_items: 1 个订单可以有多个 order_items,又是“一个或多个”。
- (3)订单和付款:1 个订单只能有 1 次付款,“有且只有一个”的造型。
- (4) order_items 和 products:类似地,1 个订单项目仅与 1 个产品相关联,这意味着“一个且只有一个”样式。
2.SQL 处理
什么是 SQL 处理,SQL 如何帮助将原始数据转换成更结构化、更可用的格式?
对于 SQL 处理的正式定义,
SQL 处理是 SQL 语句的解析、优化、行源生成和执行。根据语句的不同,数据库可能会省略其中的一些阶段— Oracle
本质上,我们导入原始数据库并操纵跨表数据,将其转换为一个(或多个)结构化数据库,该数据库易于消化、理解和扩展。
如果您回头参考上面的 ERR 图,我们能够将所有数据集连接到一个数据库中,作为进行进一步操作之前的参考中心。你可以从一个集中的中心加入和操作,但我建议将这些步骤分开,因为在与现有数据一起处理之前,用中心将未来数据导入工作流更容易。
转到连接过程,正如关系所表明的,可以使用连接(也称为内部连接)或左连接,这取决于您希望您的结构化数据库是什么样子。对于连接语法,它只映射存在于两个数据集之间的值,并删除只出现在其中一个数据集的值。对于左连接,除了映射连接的值之外,它还包括“左”数据集中不存在于另一个数据集中的值。
在我的数据集中,我对(1)使用了 JOIN 来只获取存在于两个数据集(客户和订单)中的值,而对(2)、(3)和(4)使用了 LEFT JOIN 来返回那些没有出现在其他数据集中的值。在这种情况下使用左连接的原因是为了识别从输入数据中推断缺失信息的“空”值。
MySQL 中的 SQL 查询
SQL 语句的一些重要亮点:
- 创建表:这是为了创建一个集中的数据库作为一个枢纽,我以前分享的是未来的数据输入所必需的。
- TIMESTAMPDIFF:这是将时间戳格式的值转换成我们更喜欢的时间指示器(例如小时、分钟)。在本例中,我将原始值转换为“分钟”,然后除以 60 除以 24,得到天数。
在创建了一个集中的原始数据库后,我开始将数据转换成一种更加结构化和可用的格式,即:
- 时间戳列(例如,order_approved_at、order_delivered_carrier):例如,我想计算从批准订单到将订单交付给承运人的天数。
- 价格列(如单价、运费):我想计算每个订单的总价
该 SQL 语句的关键亮点是按分组的。选择文本和聚合时(例如,求和、相减、相乘等。),我们需要使用 GROUP BY 将相同的数据分组。例如,我们可能有多个具有相同值的 order _ id,因此按 order _ id 分组以将多个 order _ id 的总价格合并为一个。
我们可以进一步深入数据库,以生成与我们的业务目标一致的列和值。
3.Data Studio 仪表板
什么是 Data Studio,它如何帮助构建视觉上引人入胜的报告仪表板?
处理完数据库后,我们可能希望直观地解释数据,以进行分析和报告。事实上,有多种平台提供与关系数据库系统集成的可视化服务,即 Tableau、Datorama 和 Data Studio。在这种情况下,我使用 Data Studio,因为它可以选择与 MySQL 集成,并且易于使用,可以在仪表板中进行进一步的处理,仪表板也使用 SQL 作为标准语言。
我不会详细介绍如何使用这个平台,因为它非常简单,你应该根据自己的需要来玩:https://datastudio.google.com/。
我的报告控制面板和关键分析亮点的快速快照:
- 总收入(包括总收入和净收入)约为 1200 万至 1400 万美元,但“tracked_gross_revenue”仅为 50 万美元,这意味着输入数据中没有正确跟踪大量缺失的收入。
- 交付流程:虽然平均预计交付日为 23 天,但实际交付日只需 12 天。这就解释了为什么交货延迟(预计交货天数和实际交货天数之差)是负数。
- 批准到交付持续时间:批准订单不到 1 天,将订单发送给承运人不到 3 天,订单到达客户手中大约需要 9 天。
- 产品信息:平均产品名称长度为 6 个字符,描述长度为 103,e-com 网站中的照片总量为 27k。
- 随时间变化的收入:2016 年至 2018 年,收入从 2017 年 3 月开始上升,此后持续稳定。
- 地理表现:大部分收入来自南美城市,但随着电子商务网站在全球范围内的广泛使用,我们看到了积极的趋势。
- 产品性能:在十大产品类别中,健康和美容产品是购买最多的。
- 支付类型:信用卡占所有支付类型的 74%,表明这是主要的支付方式。
瞧啊。这就是这个项目的结尾——电子商务销售报告。我希望这篇文章对你有用并且容易理解。
在不久的将来,请留意我在即将开展的数据科学和机器学习项目!与此同时,您可以在这里查看我的 Github 以获得完整的资源库:
github:【https://github.com/andrewnguyen07
www.linkedin.com/in/andrewnguyen07领英:
谢谢!
使用 Python 和 Microsoft Azure 进行电子邮件情感分析—第 1 部分
我们的“已发送邮件”文件夹说明了我们的行为举止?我们能利用这些和其他补充数据来确定工作中快乐或悲伤的趋势吗?
塞巴斯蒂安·赫尔曼在 Unsplash 上的照片
这是由多个部分组成的文章的第 1 部分。
简介
坦白地说,在大多数与数据相关的事情上,我认为自己是个“菜鸟”。我在传统数据中心和云基础架构方面有相当丰富的经验,但在处理数据方面还是新手。在过去的 12 个月里,卡格尔几乎是我最好的朋友。
也就是说,我一直在尽可能多的研究我缺乏的技能——微积分、统计学、编码、数据工程概念等等。我认为最好的学习方法之一就是去做,但也要记录下我所经历的过程。此外,确保保持它的乐趣!
我还加入了一个链接,链接到我写这篇文章时创建的笔记本。随意使用和修改你认为合适的!
概念背景
对于我们这些经常使用电子邮件的人来说,我们都发送过几次,或者多次,或者可能每天都发。
- “根据我的最后一封电子邮件…”
- “展望未来,我建议……”
- “这完全是胡说八道!”
这些看起来有点眼熟吗?对许多人来说,很容易通过电子邮件有意或无意地显示你当前的情绪状态。你可能厌倦了多次解释同样的情况,也许你的电子邮件反映了你越来越疲惫,或者也许你的车今天早上坏了,你只是今天过得不好。
不管原因是什么,我们的电子邮件历史实际上可以提供一个有用的视角,让我们了解我们在一个组织中的态度。
本文的剩余部分将集中在利用 Jupyter 笔记本、Microsoft Azure 文本分析 API 来提供动力,以及使用 Python 来探索、清理和呈现情感分析结果。
当然,我也会模糊或消毒某些数据,只是为了确保在这之后我还有一份工作。😃
开发环境
核心环境将包括以下内容:
- Outlook 已发送邮件 CSV 导出
- Azure 文本分析 API
- Azure 笔记本( Jupyter 笔记本 )
具体到 Python,我们将使用以下包:
- Numpy
- 熊猫
- MatPlotLib
- Azure AI 文本分析
现在我们已经了解了将要使用的工具的基础,让我们开始构建吧!
步骤 1 —部署 Azure 文本分析 API 实例
弗拉基米尔·阿尼奇耶夫在 Unsplash 上拍摄的照片
我们首先需要部署一个 API 实例,这是本文剩余部分的目标。导航到https://portal.azure.com并登录。如果您没有帐户,您可以通过使用以下方式之一创建订阅来访问免费试用/信用点数:
天蓝色通行证:https://www.microsoftazurepass.com/
VS 开发要领:https://visualstudio.microsoft.com/dev-essentials/
登录后,我们需要搜索文本分析 API。
- 点击创建资源。
- 键入文本分析按回车键。
- 点击创建。
创建文本分析 API 实例
接下来,我们需要输入关于服务及其定价层的详细信息。键入一个名称、订阅(如果您有多个活动)、位置(建议选择离您最近的一个)、定价层 (F0 是免费的,对此工作正常),以及一个供它居住的资源组。如果没有,点击创建新的并给它命名。
Azure 文本分析 API 信息
部署完成后,从左侧选择所有资源并点击您的 API 资源。然后,点击键和端点并将端点和键 1 复制到记事本或其他东西中以备后用。
关键点和端点检索
步骤 2— Outlook CSV 导出
下一步是获取您的电子邮件发送项目的 CSV 导出。考虑到我们正在寻找我们自己的个人情感分数,我们将只关心我们发送的物品。
- 打开展望
- 文件→打开&导出→导入/导出
- 导出到文件
- 逗号分隔值(CSV)
- 选择您的已发送邮件文件夹
- 选择一个导出位置
- 完成导出
步骤 3—设置和检查 CSV 数据
照片由 Kirill Pershin 在 Unsplash 上拍摄
现在我们已经有了 CSV,我们需要开始编写代码来探索和准备用于分析的数据。我强烈建议不要打开。csv 文件,因为我们中的许多人拒绝整理或保持我们的邮箱干净。相反,我们将坚持把它加载到熊猫数据帧中。
我们需要创建一个新的 Jupyter 笔记本来工作。我只是暂时把我的名字简单地叫做email 情操. ipynb 。如果你没有安装 Jupyter,也不想使用托管版本,我强烈建议你查看一下 Anaconda 获得一个全面的软件包。
现在我们有了笔记本,我们需要安装 Python 的 Azure 文本分析 API 包(如果你还没有的话)。
!pip install azure-ai-textanalytics
我们将假设我们的开发环境已经安装了 Pandas 和 Numpy(Anaconda 和 Azure 笔记本都提供了它们)。
然后我们可以继续导入必要的包。我们还将把我们的 Azure 文本分析 API 密钥和端点信息(来自步骤 1)分配到这个单元格中。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import figure
from azure.ai.textanalytics import TextAnalyticsClient
from azure.core.credentials import AzureKeyCredential#Key and enpoint from Azure Text Analytics API service
key = "f7c7c91cd70e493ea38521d1cbf698aa"
endpoint = "[https://mediumapi.cognitiveservices.azure.com/](https://mediumapi.cognitiveservices.azure.com/)"
我们还需要定义一些我们稍后将在笔记本中使用的函数。为了便于组织,我只是将两者都添加到一个单元格中,这样它们就在笔记本中的相同位置了。
我们需要一个函数来为文本分析 API 提供认证,以及一个用于核心情感分析的函数。我们遵循微软文档中下面的快速入门中的代码,但是会对核心函数做一些修改以满足我们的特定需求。
虽然 auth 函数很简单,但我们需要修改情感分析函数来迭代一系列列表(与单个硬编码字符串相比),只检索总得分(我们将在下一篇文章中探索情感得分范围),并递增我们稍后创建的频率表。
#Creating the Azure authentication function
def authenticate_client():
ta_credential = AzureKeyCredential(key)
text_analytics_client = TextAnalyticsClient(endpoint=endpoint, credential=ta_credential)
return text_analytics_client#Core function for running sentiment analysis
#Modified to fit our specific needs
#Added global variables we'll use later in this notebook
def sentiment_analysis_example(client,list_name):
global senti_results
senti_results = {'Positive':0,'Neutral':0,'Negative':0,'Unknown':0}
global senti_errors
senti_errors = []
documents = list_name
for row in documents:
response = client.analyze_sentiment(documents = row)[0]
try:
if response.sentiment == "positive":
senti_results['Positive'] += 1
elif response.sentiment == "neutral":
senti_results['Neutral'] += 1
elif response.sentiment == "negative":
senti_results['Negative'] +=1
else:
senti_results['Unknown'] +=1
except:
senti_errors.append(row)
return(senti_results,senti_errors)#Assigning authentication function to object
client = authenticate_client()
现在我们有了 Azure API 函数设置,我们准备开始探索和准备我们的数据集。
#Assign your filename to a variable
emailFile = ‘BenSent.CSV’#Display the first 5 rows of our CSV to inspect
#Notice encoding — this seemed to work for our CSV
email_data = pd.read_csv(emailFile,encoding=’ISO 8859–1')
email_data.head()
如果您运行上面的代码,您应该会看到类似下面的输出。
Outlook 导出提供了大量的列(有用或无用),但是您会发现缺少一个关键的数据点—时间戳。
不幸的是,Outlook 不提供将日期/时间属性映射到 CSV 导出的功能。为了简单起见,我们将只分析我们的数据集作为一个完整的批处理。我们将看看如何在后续帖子中包含日期。
步骤 4—清理和准备数据集
根据这种情况下的可用数据,我们将重点关注我们在电子邮件中对他人说了什么,并确定总体上是积极、中立还是消极的情绪。我们需要创建一个单独的对象,只包含来自 Body 列的内容。我们将用熊猫来做这件事。
#Assign Body column to new object
email_body = email_data['Body']#Display top 5 rows and the overall length of the series
print(email_body.head())
print('\n')
print("Starting email count:",email_body.shape)
在这里,我使用按列标签选择,考虑到我们有这些可用的。您也可以使用列索引,或者您喜欢的任何东西。
现在我们可以看到只有正文内容,这是我们将用来执行情感分析的内容。当我们继续清理这个的时候,我们将密切监视我们的系列的形状。我们目前从 1675 行开始。
接下来,我们会注意到前 5 行中有我们不想分析的奇怪字符,比如\r
或\n
等等。我们将使用一个简单的str.replace
来删除这些。
#Removing \r and \n characters from strings
email_body = email_body.str.replace("\r","")
email_body = email_body.str.replace("\n","")#Display top 5 rows and the overall length of the series
print(email_body.head())
print('\n')
print("Current e-mail count:",email_body.shape)
接下来,我们将删除不想分析完整电子邮件线程的转发或尾随电子邮件线程。一个例子是行索引 3,其中我们看到在电子邮件线程中我的回复后面有一个日期。
我将使用我知道会自动添加到每个已发送邮件中的东西——我的签名块——来清理这些尾随邮件。以此为目标,我们可以根据识别签名词和尾随消息将数据划分到不同的列中。
#Removing trailing email threads after start of my email signature
split_df = email_body.str.partition("Regards")
print(split_df[0:3])
print('\n')
print("Current e-mail count:",split_df.shape)
从形状和输出中,我们现在可以看到我们有 3 个不同的分区列——一个用于电子邮件正文内容,一个用于识别签名块单词(在我的例子中是“问候”),一个用于结尾消息。
我们现在需要删除这些额外的列,将注意力放回到正文上。我们还将删除被标识为没有信息的行。
#Removing extra fluff from partitioning
clean_col = split_df.drop(columns=[1,2]) #1 contains "Regards", 2 contains trailing text
#Removing rows with NaN - no data
clean_nan = clean_col.dropna()print("E-mail count before NaN removal:",clean_col.shape[0]) #Display before NaN removal
print("E-mail count after NaN removal:",clean_nan.shape[0]) #Display before NaN removal
我们可以看到,在分区之前,我们有 1,675 行。我们删除了包含我签名前后的两栏内容。删除了 NaN 的行后,我们只剩下 1,642 封电子邮件。我们需要通过删除 PTO 邮件和转发邮件来继续清理。我们还将在正文列中添加一个列名。
#Updating the primary column with name EmailBody
clean_nan = clean_nan.rename(columns={0:"EmailBody"})#Remove emails with default out of office reply
clean_pto = clean_nan[~clean_nan.EmailBody.str.contains("Hello,I am currently")]#Remove emails with a forwarded message
cleaned_df = clean_pto[~clean_pto.EmailBody.str.contains("---------- Forwarded message ---------")]print("E-mail count before removals:",clean_nan.shape[0]) #Pre PTO count
print("E-mail count after removing PTO messages:",clean_pto.shape[0]) #Post PTO count
print("E-mail count after also removing forwarded messages:",cleaned_df.shape[0]) #Post fwd removal
检查形状后,我们可以看到我们从1642行到1460行,最后到1399行。请记住,我们正在清理所有这些内容,以确保我们的情感分析返回尽可能准确的信息。
如果我们打印cleaned_df
系列,我们会看到我们的行看起来是空的。我们需要确保我们删除这些,这样我们的分析就不会出错。我们将通过使用 Pandas 的df.replace
来做到这一点,并用 NaN 替换空数据。
#Considering we know we still have rows with no data, we'll replace the empty space with NaN
#We can see all visible rows with nothing now show NaN
cleaned_df['EmailBody'].replace(" ",np.nan,inplace=True)
print(cleaned_df)
现在我们的空行将显示 NaN。我们现在可以使用pd.dropna()
删除这些行。
#We can now find all rows with NaN and drop them using pd.dropna
cleaned_df = cleaned_df.dropna()
print(cleaned_df)
print('\n')
print("E-mail count after dropping empty rows/rows with NaN:",cleaned_df.shape)
移除 NaN 后,行数减少到 1,288 行。请随意继续探索您的数据,以确保您没有应该删除的额外内容。虽然这并不完美,但我们确实希望结果尽可能合理。
至于最后一步,我们将把数据帧转换成包含字符串的列表。我们将用它发送给我们的 API 并返回我们的结果。
#Create an empty list to store values
#Iterate over each row in the dataframe and append it to the listsenti_list = []for row in range((cleaned_df.shape[0])):
senti_list.append(list(cleaned_df.iloc[row,:]))
#Length of list matches length of old df
print("E-mail count before error removal, ready for analysis:",len(senti_list))
我们可以打印列表的长度,以确保它与我们的 DataFrame 行数相匹配,事实也确实如此。
步骤 5—执行情感分析
现在我们有了一个“嗯,我清理了”数据的列表,我们可以开始将数据发送到我们的 Azure API,检索结果,并可视化我们的数据。
我们将提供新创建的列表作为核心情感分析函数中的 list_name 参数。该函数的编写方式不仅提供了结果的频率表,还提供了包含行本身的列表,这些行在分析时可能包含错误。
下一部分可能需要一段时间,这取决于有多少行被发送到 API。您可能还会发现自己不得不扩展自己的 API 服务。如果是这样的话,我建议你为了练习的目的,把你的清单削减一下。
#Trigger the sentiment analysis function, passing in our list of lists
sentiment = sentiment_analysis_example(client,senti_list)
一旦完成,我们就可以回顾最初的结果。
print(senti_results)
print("\n")
print("Sentiment errors:",senti_errors)
print("Error count:",len(senti_errors))
我们在这里可以看到两件主要的事情:我们的数据的总体情绪结果和在分析时出错的行。我们可以看到总共有 11 行没有被分析,这似乎是因为不同的空白。
我们需要遍历这个列表,遍历我们的原始数据集列表,并删除包含这些列表的所有列表。我们还将制作一份列表的副本,这样我们就有了历史版本,以备将来需要。
#Removing the errors from our list of lists
#Assigning to a new variable so we have the unmodified original
senti_cleaned = senti_listfor i in senti_errors:
for row in senti_cleaned:
if i == row:
senti_cleaned.remove(row)
print("E-mail count after removing error rows. Final used for analysis:",len(senti_cleaned))
我们可以看到我们正好下降了 11 行,这与错误计数相匹配。我们现在可以对我们的数据副本重新运行分析,以确保没有其他错误。
#Triggering next run of analysis on the final dataset
sentiment = sentiment_analysis_example(client,senti_cleaned)#Displaying the sentiment analysis results
print(senti_results)
print("\n")
print("Sentiment errors:",senti_errors)
print("Error count:",len(senti_errors))
查看输出,我们可以验证我们没有更多的错误(您的里程可能会有所不同),并准备好继续绘制我们的结果。
第六步——可视化
现在我们已经有了一个很好的字典,我们可以把它们绘制成很好的图表。对于本文,我们将关注两个视图:结果的总体情感百分比和每种情感类型的电子邮件数量。
为此,我们将使用matplotlib.pyplot
库。我们将创建一个饼图(以显示百分比)和一个条形图(以按结果显示电子邮件数量)。在显示之前,我们还将对图进行一些格式更改,例如:颜色更改、字体更改、填充/间距、显示大小等。
#Setting our Key/Value pairs from our results
keys = senti_results.keys()
values = senti_results.values()#Establishing some format changes for our charts
figure(num=None, figsize=(8,8),dpi=80)
colors = ['seagreen','lightsteelblue','indianred','silver']
explode = (0.1, 0, 0, 0)
plt.rcParams.update({'font.size': 12})#Creating the first plot (pie chart)
plt.subplot(221)
plt.pie(values,labels=keys,colors=colors, explode=explode,autopct='%1.1f%%',shadow=True,startangle=90)
plt.title('Overall Sentiment Against 1,277 E-mails, by Percentage',bbox={'facecolor':'1','pad':8},y=1.10)#Creating the second plot (bar chart)
plt.subplot(222)
plt.title('E-mail Count by Sentiment Result',bbox={'facecolor':'1','pad':8},y=1.10)
plt.bar(keys,values,width=.8,color=colors)#Adjusting the spacing/padding between subplots
plt.subplots_adjust(left=0.125, bottom=0.1, right=1.8, top=1.3, wspace=0.2, hspace=0.2)#Displaying the plots
plt.show()
现在我们可以看到我们的数据有了一个很好的可视化表示!虽然我们仍然有一堆来自 API 的“未知”响应类型,但我们可以说,总体而言,我们的响应并不像我们想象的那样消极。
在接下来的一些帖子中,我们会对每封邮件进行分类,并对其进行分组。我们还希望引入一些其他数据,与我们目前发现的数据进行对比。
希望这篇文章是有用的或者有趣的,并且你在这个过程中学到了一些东西。请记住,我对此非常陌生,非常感谢您的反馈!
使用 Python 和 Microsoft Azure 进行电子邮件情感分析—第 2 部分
使用新的电子邮件数据更深入地进行情感分析,并开始探索关系应用程序使用数据。
斯蒂芬·菲利普斯-Hostreviews.co.uk 在 Unsplash 上拍摄的照片
这是由多个部分组成的文章的第 2 部分。
第一部分回顾
简单回顾一下,本系列的第 1 部分着重于获取您的电子邮件发送项目的 CSV 导出,并使用 Microsoft Azure 的文本分析 API 返回每行的情感结果。
我们从用于增加频率表的 API 中获取的结果基本上向我们显示了正面、负面、中性或未知结果的总数。
我们还发现,完全理解时间线很困难,因为 Outlook 的任何导出功能都不包括日期时间数据,所以我们的分析只是针对“已发送邮件”文件夹中的大部分邮件。
第二部分导言
自从第 1 部分发表以来,我偶然发现了文本分析 API 的一个新版本(3.1 版),它可以返回一个“混合”的情感结果。我们将探讨这一点,以及以下值得注意的变化:
- 从名为 RescueTime 的工具中探索应用程序使用细节
- 查看情感分析结果的详细分数和输出
- 准备连接数据集并查找相关性
- 可视化数据
在第 1 部分中,我还提到了 Outlook 本身不允许您导出包含发送或接收日期/时间的电子邮件副本(CSV 或 PST 格式)。
打开 Outlook 应用程序并下载 CSV 的另一种方法是利用 PowerShell 来查询和保存信息。通过使用 PowerShell,我们能够操作 Outlook 应用程序中不可用的字段。
使用 PowerShell 检索带日期时间的电子邮件
下面的代码将提取您的已发送邮件文件夹的邮件正文和发送日期/时间,然后存储到一个 CSV 文件中。确保将-path 开关更新为您想要的值。
在 Excel 中查看文件时(假设您应用了默认设置),您会注意到一些格式问题,如:
为了解决这个问题并提供一种更容易在 Python 中使用的格式,我们将打开一个新的空白 Excel 文件,单击“数据选项卡,并在获取&转换数据部分中单击 From Test/CSV 。选择您的 CSV 文件并使用以下设置:
你会注意到我们把分隔符改成了|字符,因为我们在大多数邮件文本中很少使用,尤其是在我发送的邮件中。
我们还可以看到一个预览,显示它是如何格式化我们想要的。我们将点击底部的 Load ,将其保存为我们的工作 CSV,现在您就可以将它加载到数据帧中了!
大声向 杰森·布鲁诺 求助 PowerShell 脚本和修改 Excel 格式!
下载更新时间数据
斯蒂芬·菲利普斯-Hostreviews.co.uk 在 Unsplash 上的照片
改期从何而来?嗯,大约一年半以前,我下载了一个应用程序,它可以帮助跟踪应用程序中的活动时间,帮助你找到可以削减的地方,还可以大致了解你在哪里花了大部分时间。
我使用这个应用程序大约一个月左右,然后诚实地忘记我已经安装了它。哎呀!
对我有利的是,这个应用程序仍然在收集数据。RescueTime 提供了以 CSV 格式下载你所有数据的能力(在他们网站上你的个人资料中可以找到),所以我知道我要努力把它纳入我确定快乐/悲伤趋势的目标中。
此外,我与 RescueTime 没有任何关联,它只是一个我不久前决定尝试的免费应用程序,它非常有趣,足以融入这个故事。😃
加载和检查数据集
在本节中,我们将跳过许多逐行代码,因为我们使用了第 1 部分中的许多现有代码。我还提供了一个 GitHub 链接到 Jupyter 笔记本,如果你想查看、复制或修改它的话。
当我们导入新的电子邮件发送项目导出时,我们会在需要清理的数据中看到许多相似之处;但是,还要注意我们现在可以使用日期时间数据。呜!这在第 3 部分中可视化和连接数据集时非常有用。
您将看到的代码片段按照第 1 部分中的许多步骤完成了一些常规的数据清理,并添加了一些内容,例如将列转换为 datetime 并稍微更改了一些格式。我也在不断地学习,所以一些代码会不断地变得更有效率。
在导入 RescueTime 数据集并对其进行一些初步清理之后,我们可以获得以下一些信息:
非常有趣的是,它有我们可以探索的特定级别的细节,但它也提供数据,如:
- 记录日期
- 应用程序名称
- 应用类别
- 录制时的使用情况(秒)
只是为了好玩,这里有一个我记录的活动 Slack 实例的可视化,我们将在第 3 部分中触及。趋势下降可能是我工作的公司推出微软团队并开始摆脱 Slack 的一个标志。此外,很高兴我的星期六用法并不可怕!
记录的松弛窗口在我的屏幕上处于活动状态的实例…
我们将在第 3 部分进一步探索和加入 RescueTime 数据集,但现在我们将把重点转移到根据新的电子邮件数据集来改变我们的情感分析结果。
情感分析调优
马特·阿特兹在 Unsplash 拍摄的照片
回到我们的电子邮件数据集,我已经使用第 1 部分中的大部分内容清理了数据,考虑到我们现在有一个日期时间列,还添加了一些内容。
为了便于查看,我对主要情感分析功能进行了更改,以从 API 返回我们需要的详细信息,并对清理后的电子邮件数据集进行了一些修改,以利用这些附加功能:
…以及对电子邮件数据集的小改动,以从情感分析输出中获取更多细节。我们使用 DataFrame 中的“message”系列进行发送分析(相比之下,我们将它转换为一个列表)并添加额外的列。
在将我们的消息发送到文本分析 API 之后,我们可以看到我们的结果提供了与第 1 部分中类似的输出(包括更新的“混合”结果),以及我们的数据帧,该数据帧具有包含详细情感分数和总体情感结果的新列。
将这个结果输出到 csv 也是一个明智的选择,因为每次将结果发送到 API 时,都需要一段时间才能获得所有结果。😃
演示数据准备
简单回顾一下,我们最新数据集的一些优势包括:
- 电子邮件发送日期
- 清理的邮件详细信息
- 详细的情感分析得分结果
- 总体情绪标签
也就是说,我们可以使用当前状态下的电子邮件数据来绘图,但也可以看看一周中哪一天更积极/消极等,这可能会很有趣..获取每一行的最高报告分数也可能有所帮助。
为了简洁起见,我们首先将 email_clean 数据帧复制到一个名为 email_plot 的数据帧中,我们将(很明显)使用它来绘图。我们还将为一周中的某一天添加一个新列,并从我们的date
列进行翻译。
email_plot['day_of_week'] = email_plot['date'].dt.day_name()
我们也将做同样的事情来获得我们的最高分,但是我们将只让它检查与我们的分数输出相关的列。
email_plot['top_score'] = email_plot[['positive','neutral','negative']].max(axis=1)
现在我们有了一些额外的有趣数据,可以在绘图时使用!
可视化新数据
现在,我们已经对消息列进行了适当的清理,添加了情绪得分、总体情绪结果、星期几和最高得分的列,我们准备好绘图了!
最近,我更关注 Plotly,因为我觉得修改布局、颜色地图等更容易。与 MatPlotLib 相比。MatPlotLib 无疑仍然是一个很棒的库,但是我也计划在我的个人网站上发布一些,所以一个交互式的库更有意义。
也就是说,Plotly 能够在生成图时使用facet_col
轻松地将图分割成面板。在对情节细节做了一些调整后,我有一个有趣的散点图要看:
如果你是 Plotly 的新手,你可以点击右侧图例中的情绪结果来过滤上面的散点图。
如果我们先过滤,只显示积极的结果,我们实际上可以看到,随着我们从 2019 年 7 月转移到 2020 年 7 月,周四和周五有更多的电子邮件被自信地标记。
如果我们切换到负面结果,我们可以看到周一发送的带有负面标签的电子邮件数量大幅减少,上个季度的周一没有负面邮件!
然而,周二(温和增长)和周三的情况正好相反,因为随着我们进入 2020 年中期,我们可以看到更紧密的点群。
负面邮件(左)和正面邮件(右)
有趣的是,周末发送的电子邮件似乎大多是积极的,这可能有助于普遍的周末快乐在我的回复中发挥作用。
结论
虽然这并不意味着在情感结果和整体数据清洁度方面 100%准确,但它绝对是朝着更好的方向迈出的一步,并且能够开始查看我的电子邮件情感趋势。我认为同样值得一提的是,负面情绪并不意味着你是一个彻头彻尾的混蛋或骂人(我并不是一个那么糟糕的人……),而是指在系列中使用的某些词可能会触发 API,导致负面反应得分增加。😃
像往常一样,请在下面的评论区留下任何评论/想法/反馈。我总是在寻找更有效的方法来做某事,寻找我在做某事的过程中可能出现的错误,或者寻找一般的反馈!
请继续关注第 3 部分,我们将本故事中使用的数据与我们的 RescueTime 数据中的 datetime 数据相结合,以发现情感结果与大量应用程序使用之间的相关性!
刘汉宁·奈巴霍在 Unsplash 上的照片
使用 Python 的电子邮件通知机器人
一个重要的 PYTHON 技巧
教程—新冠肺炎案例的电子邮件通知示例
插图作者:金彩云
在数据科学中,项目的数据来源可能会随着时间而变化,分析结果也会随着时间快速变化。有时候结果的一点点变化可能不会让你感兴趣。但是自己一个人持续跟踪这种变化可能太累了…
本文展示了用 Python 编写电子邮件自动化机器人脚本的指南!
我们开始吧💥
📧准备电子邮件发件人
首先,让我们准备一个电子邮件发件人帐户。我推荐使用 G-mail,因为它易于注册,并且允许你手动调整安全选项。您可以使用您的个人电子邮件或您选择的其他电子邮件提供商。但是我建议为我们的电子邮件机器人创建一个新的电子邮件。🤖
在 G-mail 帐户准备就绪后,通过进入帐户安全设置并进行如下调整,降低帐户安全性以允许 Python 访问您的 G-mail 帐户并发送电子邮件:
- 用手机取消登录
- 通过两步验证取消登录
- 打开不太安全的应用访问选项
在 G-mail 中进行设置以允许 Python 发送电子邮件。
使用 Python 的✍Sending 电子邮件
现在,我们开始一个有趣的部分,编写一个脚本来登录您的电子邮件帐户并发送电子邮件。我建议使用一个简单的模块smtplib
来完成这项工作。首先,让我们创建一个send_email.py
文件,开始导入模块,如下所示:
**import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText**
然后,让我们为您的电子邮件发件人和收件人信息以及电子邮件内容准备所有变量,如下所示。您可以在email_recipients
列表中输入几个电子邮件收件人。
#Email Account **email_sender_account = "**<Your Sender Account>**"
email_sender_username = "**<Your Sender Username>**"
email_sender_password = "**<Your Sender Password>**"
email_smtp_server = "**<SMTP, eg smtp.gmail.com for gmail>**"
email_smtp_port =** <SMTP Porf, eg 587 for gmail>#Email Content
**email_recepients =** [**"**<recepient1>**","**<recepient2>**",".."**] **email_subject = "**<Email Subject>**"
email_body** = "<html of your body here>"
之后,我们只需要登录电子邮件服务器。然后,我们将使用for
循环来生成电子邮件并发送给所有收件人。
#login to email server **server = smtplib.SMTP(email_smtp_server,email_smtp_port)
server.starttls()
server.login(email_sender_username, email_sender_password)**#For loop, sending emails to all email recipients **for recipient in email_receivers:
print(f"Sending email to {recipient}")
message = MIMEMultipart('alternative')
message['From'] = email_sender_account
message['To'] = recipient
message['Subject'] = email_subject
message.attach(MIMEText(email_body, 'html'))
text = message.as_string()
server.sendmail(email_sender_account,recipient,text)**#All emails sent, log out. **server.quit()**
在此之前,您有一个 Python 脚本来向所有收件人发送电子邮件。现在,让我们将它应用到真实世界的用例中。
🌎真实世界的例子
⚠新冠肺炎—电子邮件通知机器人
在本例中,我将展示如何应用我们在上面创建的 Python 脚本向报告新新冠肺炎病例的收件人发送电子邮件。
首先,我们需要获得最新的新冠肺炎数据。通过使用带有几行 Python 代码的BeautifulSoap4
和request
模块,我们可以很容易地从 Worldometers 中抓取这个数据集,如下所示:
#import module **import requests, datetime
from bs4 import BeautifulSoup** #Set the endpoint: Worldometers **url = "https://www.worldometers.info/coronavirus/"
req = requests.get(url)
bsObj = BeautifulSoup(req.text, "html.parser")
data = bsObj.find_all("div",class_ = "maincounter-number")
num_confirmed = data[0].text.strip().replace(',', '')
num_deaths = data[1].text.strip().replace(',', '')
num_recovered = data[2].text.strip().replace(',', '')**
通过这个脚本,它找到了一个名为maincounter-number
的类的位置,该类表示新冠肺炎数据的数量:确诊病例、死亡病例和恢复病例。这些数据分别存储在num_confirmed, num_deaths, num_recovered
中。然后,我们也可以使用datetime
模块获取当前时间,并传递这些变量来为电子邮件正文创建一个 HTML 结构,如下所示:
**TimeNow = datetime.datetime.now()
email_body = '<html><head></head><body>'
email_body += '<style type="text/css"></style>'
email_body += f'<h2>Reporting COVID-19 Cases at {time}</h2>'**
**email_body += f'<h1><b>Confirmed cases</b>: {confirmed_cases}</h1>'
email_body += f'<h1><b>Recovered cases</b>: {recovered_cases}</h1>'
email_body += f'<h1><b>Deaths </b>: {deaths}</h1>'
email_body += '<br>Reported By'
email_body += '<br>COVID-19 BOT</body></html>'**
现在,让我们把所有的东西结合在一起,输入所有的电子邮件信息,然后运行python <filename>.py
,试试看是否可行,是的,可行!运行完脚本后,我的收件箱里直接收到了一封电子邮件,里面有实时更新的新冠肺炎案例:
运行 Python 脚本后,我的 Outlook 收件箱中的屏幕截图。
您可以看看下面完全组合的 Python 脚本:
电子邮件通知
计划您的机器人
现在,是时候让你的机器人每隔 xx 分钟或 yy 小时或 zz 天定期运行一次了。另外,你应该添加一个发送消息的条件,因为你不需要在 10 分钟内收到 100 封举报邮件。所以你可以这样做:
- 设置阈值,以便仅在报告了新的 XXXX 病例时发送电子邮件通知。一个普通的
if..else..
算法运行良好。 - 使用
while true: .../ time.sleep()
安排您的机器人 - 在 Mac/Linux 上使用
CRON
或者在 Windows 上使用 Windows 任务调度器来调度你的机器人。 - 如果你想要一个替代的方法来管理你的脚本定期运行,我推荐使用 PM2 来完成。
结论
本文以新冠肺炎电子邮件通知机器人为例,给出了构建用于自动和定期发送电子邮件的 Python 脚本的演练。本教程中使用的电子邮件发送者是 G-mail,但是可以用任何电子邮件提供商来代替。本文的主要 Python 模块包括**smtplib, request, datetime, bs4**
,我的主要概念是使用最简单的方法来完成工作。✌
作者消息
我希望你喜欢这篇文章,并发现它对你的日常工作或项目有用。如果你有任何问题,请随时联系我。
关于我&查看我所有的博客内容:链接
平安健康!
感谢阅读。👋😄
德国的电动汽车:电动汽车充电站分析
慕尼黑是德国电动汽车的领导者💚
Jannes Glas 在 Unsplash 上的照片
电动汽车在保证全球未来可持续发展方面发挥着重要作用。电动汽车的受欢迎程度正在持续增加,它们代表了内燃机的一种有吸引力的替代品。然而,为了确保电动汽车的成功,需要为电动汽车充电提供良好的基础设施。
在本文中,我们分析了位于德国各地的充电站。该数据可在以下网页上找到,其中包含向联邦政府报告的德国 ( 和 )可用的公共充电点!)。在其他来源中,您可能会发现此数据集中没有的充电位置。
[## 联邦铁路公司
卡丁车是德国最大的汽车制造商之一,是德国最大的汽车制造商之一…
www.bundesnetzagentur.de](https://www.bundesnetzagentur.de/DE/Sachgebiete/ElektrizitaetundGas/Unternehmen_Institutionen/HandelundVertrieb/Ladesaeulenkarte/Ladesaeulenkarte_node.html)
文章分为四个部分:
- 德国电动汽车充电站数据集
- 数据帧翻译
- 探索性数据分析和数据清理
- 回答问题并得出结论
如果你只对得到的结果感兴趣,直接进入文章的最后部分!▶️
德国电动汽车充电站数据集
从bundesnetzagentur . de下载 CSV 文件后,我们可以使用Pandas . read _ CSV函数将其加载到 Pandas 数据框中,并使用 pandas 可视化前 5 行。data frame . head方法。
如上所示,我们跳过了文件开头的 5 行(skip prows = 5),因为它们不包含有用的信息(只是关于正在显示的数据的注释)。
数据帧翻译
Bundesnetzagentur 提供德语数据集。因此,在开始探索性数据分析之前,我们必须将数据集翻译成英语。首先,我们使用 熊猫来翻译列名。data frame . renameT5 功能。
然后,我们使用熊猫翻译列的条目。Series.replace 方法如下所示。****
我们不打算翻译其余栏目的条目。但是,如果您想翻译它们,您可以使用 googletrans 库,因为这些列包含多个独特的元素。在这种情况下,硬编码翻译将非常耗时。
** [## 使用 googletrans 库翻译熊猫数据框
Googletrans 是一个使用 Google Translate API 的免费 python 库。在这篇文章中,我们解释了如何使用…
towardsdatascience.com](/translate-a-pandas-data-frame-using-googletrans-library-fb0aa7fca592)
数据帧被翻译!现在,我们准备开始探索性数据分析。
探索性数据分析和数据清理
探索性数据分析包括分析数据集的主要特征,通常采用可视化方法和汇总统计。目标是理解数据,发现模式和异常,并在我们执行进一步评估之前检查假设。
在 EDA 之初,我们想知道尽可能多的关于数据的信息,这是当 熊猫的时候。data frame . info方法就派上用场了。此方法打印数据框的简明摘要,包括列名及其数据类型、非空值的数量、数据框使用的内存量。
如上图所示,数据帧包含 13551 个观测值和 22 个变量。列 type_of_plug_2、p2[kw]、type_of_plug_3、p3[kw]、type_of_plug_4 和 p4[kw]包含空值,意味着第二、第三和第四充电点在充电站不可用(记住一个充电站可以有多个充电点)。我们使用 熊猫用字符串‘0’替换空值。series . fillna功能,表示没有充电点。
****公钥是允许用户远程检查测量值的数字序列。由于它们不能为我们的分析提供有用的信息,我们将删除这些列。
正如我们在下面看到的,现在,数据帧不包含空值。
删除空值后,我们修改不正确的数据类型。我们可以使用 pandas 来检查列的数据类型。data frame . info方法(就像我们之前做的)或者用 熊猫。DataFrame.dtypes 属性。该属性返回包含每列数据类型的序列。****
如上图所示,以下各列:(1)longitude [DG],(2) latitude[dg],(3) power_connection_[kw],(4) p1_[kw],(5) p2_[kw],(6) p3_[kw],(7) p4_[kw]为数据类型 object 而非 float 。我们可以用 熊猫。Series.astype 方法将这些列的数据类型转换为 float,将之前的逗号替换为点。
此外,我们必须将列调试日期转换为日期时间。为了实现这一点,我们可以使用 pandas.to_datetime 方法,指定格式来匹配数据。
现在,我们可以运行 熊猫了。DataFrame.info 方法再次检查不适当的数据类型和空值是否被正确修改。
如上所示,数据集不包含空值,数据类型是预期的类型。
整齐数据集具有以下结构:
- 每个变量在一个列中。
- 每个观察值位于不同的行。
- 每种类型的观测单元在不同的表格中。
正如您所看到的,列邮政编码 _ 城市包含两个变量:(1)邮政编码和(2)城市;因此,我们需要将该列拆分为两个不同的列。为此,我们可以用串法拆分( )熊猫。Series.str.split ),设置参数 n=1 和 expand=True 。
在 Pandas 中处理对象列时,前导空格和尾随空格是一个常见问题。我们必须确保列的条目在开头和结尾不包含空格,因为它们可能会在分析数据时导致错误的结论。
下面的代码显示了几个城市名称包含前导或尾随空格。
我们需要删除它们以避免数据分组时出现问题,因为如果我们不删除前导空格,例如“雷根斯堡”和“雷根斯堡”将被视为不同的城市。
如下所示,我们遍历对象数据类型的列,删除带有熊猫的条目开头和结尾的所有空格。方法。
最后,我们必须解决最后一个也是更具挑战性的清洁问题。在某些情况下,数据集中出现了同一城市的两个不同名称(如法兰克福和美因河畔法兰克福)。在其他时候,区名也与城市名一起被记录(例如斯图加特-慕尼黑)。
我们可以用 熊猫来识别错误的城市名称。Series.str.contains 的和方法如下所示。
我们寻找德国最重要的城市,并创建了一本字典,将错误的名称映射到正确的名称上。然后,我们用这本字典来解释熊猫。Series.replace 函数修改错误的城市名。
数据集包含更多的错误名称,但至少我们已经纠正了稍后将出现在可视化中的城市名称。
最后,我想指出数据框包含多个重复的行,如下所示。
这些重复的观测值不应被删除,因为它们代表位于同一点的几个充电站。
数据清理完成💚。现在,我们准备回答问题,并利用数据得出结论。
回答问题并得出结论
探索性数据分析和数据清理是让我们对数据有一个感觉并准备好轻松得出结论的步骤。现在!我们准备使用数据集回答以下问题。****
联邦各州的充电站数量
下图显示巴伐利亚州(3090) 是电动汽车充电站数量最多的州,其次是北莱茵-威斯特伐利亚州(2392) 和巴登-符腾堡州(1942)。相反,萨尔州只有91 个 EV 充电站。这是有道理的,因为萨尔州是一个人口稀少的州,没有大城市。********
**
德国哪些城市拥有最多的 EV 充电站?
如下图,慕尼黑(607) 是德国电动汽车充电站最多的城市,其次是汉堡(535)** 和柏林(519) 。科隆排名第四;但是它的充电站【134】要少得多。******
事实上,德国超过 12% 的充电站位于慕尼黑、汉堡,或者柏林如下图。
德国哪些城市的电动汽车充电站最多?
一个充电站可以有多个充电点。下面的饼图描绘了具有 1、2、3 和 4 个充电点的充电站的百分比。
如上图,德国超过 80%的充电站有 2 个充电点。相反,只有 1.3% 的站有 3 个负荷点。****
下面的图显示慕尼黑、汉堡和柏林也是拥有最多电动汽车充电点的城市。
充电站是什么时候投入运营的?
下图显示了每年有多少充电站投入运行(调试日期)。正如您所观察到的,近年来安装的新充电站的数量呈增长趋势。
如上图所示,除了 2012 和 2020 之外,本年与上年的变动百分比始终为正。需要指出的是,数据集包含 2020 年 5 月 5 日之前的信息。
然而,由于冠状病毒危机,预计 2020 年的新充电站数量将少于 2019 年。****
德国充电站的电力
电动汽车的充电时间取决于充电点的电量和车辆的电池容量。****
充电时间[h] =电池容量[kwh] /充电功率[kw]
因此,充电点的功率输出是一个需要考虑的重要因素,因为它决定了充电速度。
下表显示了德国充电点最常见的电源输出。
有2074122kW 的充电点,这是德国最常见的功率输出,其次是 11kW 。另一方面,**超快速150 kw**和 350kW 的充电点较少见;然而,你可以在德国找到超过 450 个这样的人。****
如下图,我们可以找到 62 种不同的动力输出用于德国的电动汽车充电。这些输出按升序排列如下,最常见的是 22.0、11.0、50.0、43.0、3.7、350.0、150.0、42.0、20.0、53.0 千瓦(见上表)。
下面的饼图显示了根据功率输出的充电点百分比。
大家可以观察到,德国充电点中的 78.28% 的充电功率为 22kW。超快速充电器( 350kW )仅占总充电点的 1.24% ,是德国安装的最大充电功率。
超快速充电器(> 300 kW)位于哪里?它们是什么时候安装的?
超快速充电点是指充电功率大于或等于 300 kW 的点。正如我们在上面看到的,只有三种不同的功率输出符合这个要求: 300,320,350 kW 。
下面这段代码显示,德国有 6 个 300 kW 的充电点、10 个 320 kW 的充电点、328 个 350 kW 的充电点在运行,总共有 344 个超快速充电点。
如前所述,一个充电站可以有多个充电点。在德国,我们可以找到多达 4 个充电点的充电站。
共有 341 个带超快速充电点的充电站,如下图所示。
350 kW 和 320 kW 的充电点位于只有一个充电点的充电站。相反,有 3 个充电站,2 个 300 kW 的充电点,如下图所示。
这些站主要位于巴伐利亚,在那里你可以找到超过 80 个带超快速充电器的站。
下图为站带超快速充电器 ( > 300 kW )于 2018 首次投入运行。此外,我们观察到大多数配备超快速充电器的站点安装在 2019 年。
德国第一个 EV 充电站是在 2008 年 7 月安装的,直到 10 年后的 2018 年 3 月,才安装了第一个带有超快速充电器(> 300 kW)的站。
德国最大城市运营的电动汽车充电站总数
接下来我们要一步一步的说明如何获得德国最大城市按年的充电站总数:(1)柏林,(2)汉堡,(3)慕尼黑,(4)科隆,(5)美因河畔法兰克福,(6)斯图加特,(7)杜塞尔多夫,(8)多特蒙德,(9)埃森,(10)莱比锡。
首先,我们用 熊猫。data frame . group by函数。这个函数涉及到拆分对象、应用一个函数、组合结果的一些组合。
我们获得了一个多索引数据框,因为按两列分组将得到两个索引。我们选择一列(例如 operator),因为所有列都提供相同的信息(计数)。然后,我们用 熊猫。data frame . un stack功能。该函数将最内层的索引级别透视到新的列级别。结果是一个数据帧( date_cities ),其中列表示城市,而行表示试运行日期,即在特定年份和城市投入运行的充电站数量的值。因为我们只想分析德国最大的城市,所以我们在数据框中选择相应的列( date_cities_10 )。****
上面的数据框包含在特定的年和城市投入运营的充电站的数量。由于我们对多年来各个城市的充电站总数感兴趣,所以我们必须计算累计总数,用 0 替换之前的空值。然后,我们使用 plot 函数创建一个多线绘图,其中每条线代表一个城市。
如上图所示,科隆、法兰克福、斯图加特、杜塞尔多夫、多特蒙德、埃森和莱比锡的充电站总数逐年缓慢增长。相反,自 2016 年以来,柏林、汉堡和慕尼黑的增长率要大得多。
慕尼黑充电站分布
分析地理空间数据的最佳方式是使用地图。leave是一个数据可视化库,允许直接从你的 Python 代码生成传单网络地图。首先,我们需要安装它,因为叶子包不是 Python 标准库的一部分。为此,我们在 Windows 终端中运行以下命令:
pip 安装叶片
安装并导入叶子后,我们可以用叶子.地图()函数生成一个地图对象。位置参数允许我们在一个特定的位置将地图居中(在我们的例子中是慕尼黑)。我们还可以提供一个初始缩放级别来将地图缩放到中心。
生成的地图是交互式的,这意味着您可以轻松地放大和缩小。
数据框包含充电站所在的纬度和经度。我们可以使用 CircleMarker() 函数在这些位置绘制圆形标记。
下图显示了充电站在慕尼黑的位置。正如你所观察到的,充电站相当均匀地分布在整个城市。然而,市中心的车站比郊区的多。
在上图中,您可以观察到一些标记比其他标记更不透明,这意味着多个桩号位于同一点(重叠的圆形标记)。
正如我们之前提到的,一个充电站可以有多个充电点。慕尼黑的充电站数量遵循以下分布:
- 1 个充电点:3.95%
- 2 个充电点:95.06%
- 3 个充电点:0.16%
- 4 个充电点:0.82%
我们可以根据充电点的数量定制标记的半径和颜色,如下所示。
正如你所观察到的,大多数加油站都有两个充电点(紫色的点)。有 4 个充电点(蓝点)的车站位于慕尼黑郊区。
数据帧包含一列,指示充电站的类型:(1)普通,或(2)快速。如果一个充电站至少有一个输出功率大于 22kw 的充电点,则认为它是快速的,如下所示。
在下图中,正常充电站用蓝色标记表示。相反,快充站用红色表示。
如上图所示,大部分站点正常,意味着所有充电点的功率输出都低于 22kW 。慕尼黑只有 10 个快充站。阿拉贝拉公园(及周边)是快速充电站较多的地方(总共 5 个)。
现在轮到你了!您可以生成其他城市的地图,并可视化充电站在这些城市中的分布情况🌐
我们的分析到此结束。然而,仍然有许多问题你可以用这些数据来回答。比如:有多少家公司在管充电站?德国有多少种不同的插头?德国最常见的插头是哪个?…还有更多!🙋
关键要点
- ****巴伐利亚是联邦州拥有更多电动汽车充电站(大约 3000 个)。
- ****慕尼黑、汉堡、柏林是德国电动汽车充电站数量最多的城市。
- 一个充电站可以有多个充电点** (1、2、3 或 4)。**德国超过 80%的电动汽车充电站拥有 2 个充电点。****
- 这些年来,运营中的新充电站的数量在增加。
- 德国的充电点的 78.3% 充电功率为 22kW 。超快速充电器 ( 350kW )仅占总充电点数的 1.24% 。
- 第一台超快速充电器(> 300kW)** 于 2018 年投入运行。**
- 科隆、法兰克福、斯图加特、杜塞尔多夫、多特蒙德、埃森和莱比锡的充电站总数逐年缓慢增长。相反,自 2016 年以来,柏林、汉堡和慕尼黑的增长率要大得多。
感谢阅读💜
阿曼达
TensorFlow 中的急切执行与图形执行:哪个更好?
←Part 1|←Part 2|←Part 3|深度学习用 TENSORFLOW 2。X —第 4 部分
使用代码示例比较急切执行和图形执行,了解何时使用两者以及 TensorFlow 为何切换到急切执行|使用 TensorFlow 2.x 进行深度学习
图一。急切执行与图形执行(图由作者提供)
T 这是 TensorFlow 2.x 系列深度学习的第 4 部分,我们将比较 TensorFlow 中可用的两个执行选项:
急切执行与图形执行
你可能没有注意到,你实际上可以在这两者中选择一个。原因是 TensorFlow 将急切执行设置为默认选项,除非您想找麻烦,否则它不会打扰您😀。但是,在 TensorFlow 1.x 版本中并非如此。让我们看看什么是急切执行,以及为什么 TensorFlow 在 TensorFlow 2.0 中从图形执行进行了重大转变。
图二。图形执行与急切执行的类比(由詹姆斯·庞德拍摄于 Unsplash |由 TVBEATS 拍摄于 Unsplash
急切的执行
渴望执行是一个强大的执行环境,它可以立即评估操作。它不构建图形,并且操作返回实际值,而不是稍后运行的计算图形。通过快速执行,TensorFlow 计算代码中出现的张量值。
急切执行简化了 TensorFlow 中的模型构建体验,您可以立即看到 TensorFlow 操作的结果。由于急切执行直观且易于测试,因此对于初学者来说是一个极好的选择。热切执行不仅使调试更容易,而且还减少了对重复样板代码的需求。急切执行也是研究和实验的一个灵活选项。它提供:
- 具有自然 Python 代码和数据结构的直观界面;
- 调试更简单,直接调用操作检查测试模型;
- 自然控制流用 Python,代替图形控制流;和
- 支持 GPU & TPU 加速。
在急切执行中,TensorFlow 操作由原生 Python 环境一个接一个地执行。这使得急切执行(I)易于调试,(ii)直观,(iii)易于原型化,以及(iv)对初学者友好。由于这些原因,TensorFlow 团队将急切执行作为 TensorFlow 2.0 的默认选项。但是,在接下来的章节中会有更多相关内容……
让我们来看看图形执行。
图形执行
我们在上一节中介绍了急切执行是多么有用和有益,但是有一个问题:
急切执行比图形执行慢!
图 3。在 Tensorboard 中的模型示例的图形可视化(图片由作者提供)
由于急切执行在 Python 中逐个运行所有操作,因此它不能利用潜在的加速机会。Graph execution 从 Python 中提取张量计算,并在评估之前构建一个高效的图。图形,或者说tf.Graph
对象,是带有tf.Operation
和tf.Tensor
对象的特殊数据结构。tf.Operation
对象代表计算单元,tf.Tensor
对象代表数据单元。无需原始 Python 代码就可以保存、运行和恢复图形,这为跨平台应用程序提供了额外的灵活性。有了图,您可以在 Python 不可用的移动、嵌入式和后端环境中利用您的模型。在本系列的稍后阶段,我们将看到,无论您选择哪一个执行选项,经过训练的模型都被保存为图形。
图表很容易优化。它们允许编译器级别的转换,例如具有常数折叠的张量值的统计推断,在线程和设备之间分布操作的子部分(高级级别分布),并简化算术运算。抓钩执行这些整体优化操作。在图形执行中,只有在我们完全调用了程序之后,才会对所有操作进行评估。因此,总而言之,图形执行是:
- 非常快;
- 非常灵活;
- 与并行运行,即使在子操作层面;和
- 非常高效,适用于多种设备
- 拥有 GPU & TPU 加速能力。
因此,尽管难以学习、难以测试且不直观,图形执行对于大型模型训练来说是理想的。对于小型模型培训、初学者和一般开发人员来说,急切执行更适合。
嗯,考虑到急切执行易于构建和测试,而图形执行高效而快速,您会希望用急切执行来构建,用图形执行来运行,对吗?好吧,我们会谈到那个…
寻找两全其美的世界?一个快速但易于构建的选项?继续读:)
在深入代码示例之前,我们先来讨论一下为什么 TensorFlow 在 TensorFlow 2.0 中从图形执行切换到急切执行。
TensorFlow 为什么采用急切执行?
在 2.0 版本之前,TensorFlow 优先考虑图形执行,因为它快速、高效且灵活。对于经验丰富的程序员来说,实现的难度只是一种权衡。另一方面, PyTorch 采用了一种不同的方法,并对动态计算图进行了优先级排序,这是一个类似于急切执行的概念。尽管动态计算图不如 TensorFlow 图执行效率高,但它们为新一波研究人员和人工智能程序员提供了一个简单而直观的界面。默认执行策略的这种差异使得 PyTorch 对新来者更有吸引力。很快,PyTorch 虽然是后来者,却开始追赶 TensorFlow。
图 4。TensorFlow vs. PyTorch 谷歌搜索结果由谷歌趋势(图由作者提供)
在看到 PyTorch 越来越受欢迎后,TensorFlow 团队很快意识到他们必须优先考虑急切执行。因此,他们采用了急切执行作为默认的执行方式,而图形执行是可选的。这就好比,PyTorch 将动态计算图设置为默认的执行方法,你可以选择使用静态计算图来提高效率。
由于现在 TensorFlow 和 PyTorch 都采用了初学者友好的执行方法,PyTorch 失去了对初学者的竞争优势。目前,由于其成熟性,TensorFlow 占据上风。然而,毫无疑问,PyTorch 也是构建和训练深度学习模型的一个很好的替代方案。选择权在你…
用渴望编码,用图形执行
在这一节中,我们将使用基本代码示例比较急切执行和图形执行。为了简单起见,我们将有意避免构建复杂的模型。但是,在本系列接下来的部分中,我们还可以使用更复杂的模型来比较这些执行方法。
我们已经提到 TensorFlow 优先考虑急切执行。但这还不是全部。现在,您实际上可以像急切执行一样构建模型,然后用图形执行来运行它。TensorFlow 1.x 需要用户手动创建图表。然后通过将一组输出张量和输入张量传递给一个session.run()
调用来手动编译这些图形。但是,在 TensorFlow 2.0 中,图形构建和会话调用被简化为实现细节。这种简化是通过用tf.function()
装饰者代替session.run()
来实现的。在 TensorFlow 2.0 中,您可以使用tf.function()
来修饰 Python 函数,使其作为单个 graph 对象运行。使用这种新方法,您可以轻松地构建模型,并获得图形执行的所有好处。
代码示例
这篇文章将通过几个基本的例子和一个完整的虚拟模型来测试 eager 和 graph 的执行。请注意,由于这是一篇介绍性的帖子,我们现在不会深入到一个完整的基准测试分析。
基本示例
我们将从两个初始导入开始:
*[**timeit**](https://docs.python.org/2/library/timeit.html) is a Python module which provides a simple way to time small bits of Python and it will be useful to compare the performances of eager execution and graph execution.*
要运行一个热切执行的代码,我们不需要做什么特别的事情;我们创建一个函数,传递一个tf.Tensor
对象,然后运行代码。在下面的代码中,我们创建了一个名为eager_function
的函数来计算张量值的平方。然后,我们创建一个tf.Tensor
对象,最后调用我们创建的函数。我们的代码以急切的执行方式执行:
***Output:** tf.Tensor([ 1\. 4\. 9\. 16\. 25.], shape=(5,), dtype=float32)*
让我们首先看看如何用图形执行来运行相同的函数。
***Output:** Tensor("pow:0", shape=(5,), dtype=float32)*
通过用tf.function()
函数包装我们的eager_function
,我们能够用图形执行来运行我们的代码。我们可以用如下所示的timeit
来比较这两种方法的执行时间:
*Output:
Eager time: 0.0008830739998302306
Graph time: 0.0012101310003345134*
如您所见,图形执行花费了更多的时间。但是为什么呢?嗯,对于简单的操作,图形执行的表现并不好,因为它必须花费初始计算能力来构建一个图形。我们看到了图形执行在复杂计算中的威力。如果我运行代码 100 次(通过更改 number 参数),结果会发生巨大的变化(主要是由于本例中的 print 语句):
*Output:
Eager time: 0.06957343100020807
Graph time: 0.02631650599960267*
全模型试验
既然您已经介绍了基本的代码示例,那么让我们构建一个虚拟神经网络来比较 eager 和 graph 执行的性能。我们将:
1-使 TensorFlow 导入使用所需的模块;
2 —建立基本前馈神经网络;
3 —创建一个随机的Input
对象;
4 —以热切的执行来运行模型;
5-用tf.function()
包装模型,用图形执行运行它。
*If you are new to TensorFlow, don’t worry about how we are building the model. We will cover this in detail in the upcoming parts of this Series.*
以下代码行执行所有这些操作:
*Output:
Eager time: 27.14511264399971
Graph time: 17.878579870000067*
正如您所看到的,我们的图形执行比急切执行多了 40%左右。在更复杂的模型训练操作中,这个余量要大得多。
最终注释
在这篇文章中,我们比较了急切执行和图形执行。虽然急切执行易于使用且直观,但图形执行更快、更灵活、更健壮。因此,对于初学者来说,使用缺省选项“急切执行”是显而易见的。然而,如果你想利用灵活性和速度,并且是一个经验丰富的程序员,那么图形执行是适合你的。另一方面,由于 TensorFlow 的最新改进,使用图形执行变得更加简单。因此,您甚至可以突破自己的极限来尝试图形执行。但是,请确保您知道在图形执行中调试也更加困难。
上面的代码示例向我们展示了对简单的示例应用图形执行是很容易的。对于更复杂的模型,图形执行会带来一些额外的工作负载。
*Note that when you wrap your model with tf.function(), you cannot use several model functions like model.compile() and model.fit() because they already try to build a graph automatically. But we will cover those examples in a different and more advanced level post of this series.*
恭喜
我们已经成功地比较了急切执行和图形执行。
给自己一个鼓励!
这应该会给你很大的信心,因为你现在对急切执行、图形执行以及使用这些执行方法的利弊有了更多的了解。
订阅邮件列表获取完整代码
如果你想获得 Google Colab 的全部代码和我的其他最新内容,可以考虑订阅邮件列表。
**如果你正在阅读这篇文章,我确信我们有着相似的兴趣,并且现在/将来会从事相似的行业。那么我们就通过Linkedin来连线吧!请不要犹豫发送联系请求!Orhan g . Yal n—Linkedin
如果您刚刚开始使用 TensorFlow,请考虑从本教程系列的第 1 部分开始:
* [## 深度学习应用 TensorFlow 2.x 初学者指南
了解 TensorFlow 平台以及它能为机器学习专家提供什么
towardsdatascience.com](/beginners-guide-to-tensorflow-2-x-for-deep-learning-applications-c7ebd0dcfbee)
或检查第二部分:
[## 通过 5 个简单的步骤掌握 TensorFlow 张量
探索 TensorFlow 的构建模块如何在较低的级别工作,并学习如何充分利用张量…
towardsdatascience.com](/mastering-tensorflow-tensors-in-5-easy-steps-35f21998bb86)
或者检查第 3 部分:
[## 用 5 个简单的步骤掌握 TensorFlow“变量”
了解如何使用张量流变量,它们与普通张量对象的区别,以及它们何时优于…
towardsdatascience.com](/mastering-tensorflow-variables-in-5-easy-step-5ba8062a1756)*
基于深度学习和 OpenCV 的早期火灾探测系统
深度学习| OpenCV
为室内和室外火灾探测创建定制的 InceptionV3 和 CNN 架构。
伊利亚·安东内尔在 Unsplash 上的照片
嵌入式处理领域的最新进展已经允许基于视觉的系统在监控期间使用卷积神经网络来检测火灾。在本文中,我们实现了两个定制的 CNN 模型,为监控视频提供了一个经济高效的火灾探测 CNN 架构。第一个模型是受 AlexNet 架构启发定制的基本 CNN 架构。我们将实现并查看它的输出和限制,并创建一个定制的 InceptionV3 模型。为了平衡效率和准确性,考虑到目标问题的性质和射击数据,对模型进行微调。我们将使用三个不同的数据集来训练我们的模型。数据集的链接可以在本文末尾找到。让我们进入编码部分。
1.创建定制的 CNN 架构
我们将使用 TensorFlow API Keras 构建我们的模型。让我们首先创建 ImageDataGenerator 来标记我们的数据。[1]和[2]数据集在这里用于训练。最后,我们将有 980 幅图像用于训练,239 幅图像用于验证。我们也将使用数据增强。
import tensorflow as tf
import keras_preprocessing
from keras_preprocessing import image
from keras_preprocessing.image import ImageDataGeneratorTRAINING_DIR = "Train"
training_datagen = ImageDataGenerator(rescale = 1./255,
horizontal_flip=True,
rotation_range=30,
height_shift_range=0.2,
fill_mode='nearest')VALIDATION_DIR = "Validation"
validation_datagen = ImageDataGenerator(rescale = 1./255)
train_generator = training_datagen.flow_from_directory(TRAINING_DIR,
target_size=(224,224),
class_mode='categorical',
batch_size = 64)validation_generator = validation_datagen.flow_from_directory(
VALIDATION_DIR,
target_size=(224,224),
class_mode='categorical',
batch_size= 16)
在上面的代码中,应用了 3 种数据扩充技术——水平翻转、旋转和高度移动。
现在,我们将创建我们的 CNN 模型。该模型包含三个 Conv2D-MaxPooling2D 层对,后跟三个密集层。为了克服过度拟合的问题,我们还将增加脱落层。最后一层是 softmax 层,它将给出火灾和非火灾这两个类别的概率分布。还可以在最后一层使用“sigmoid”激活函数,将类的数量改为 1。
from tensorflow.keras.optimizers import Adam
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(96, (11,11), strides=(4,4), activation='relu', input_shape=(224, 224, 3)), tf.keras.layers.MaxPooling2D(pool_size = (3,3), strides=(2,2)),
tf.keras.layers.Conv2D(256, (5,5), activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size = (3,3), strides=(2,2)),
tf.keras.layers.Conv2D(384, (5,5), activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size = (3,3), strides=(2,2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(2048, activation='relu'),
tf.keras.layers.Dropout(0.25),
tf.keras.layers.Dense(1024, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(2, activation='softmax')])model.compile(loss='categorical_crossentropy',
optimizer=Adam(lr=0.0001),
metrics=['acc'])history = model.fit(
train_generator,
steps_per_epoch = 15,
epochs = 50,
validation_data = validation_generator,
validation_steps = 15
)
我们将使用 Adam 作为优化器,学习率为 0.0001。经过 50 个周期的训练,我们得到了 96.83 的训练准确率和 94.98 的验证准确率。训练和验证损失分别为 0.09 和 0.13。
我们模型的训练过程
让我们对任何图像测试我们的模型,看看它是否能猜对。为了测试,我选择了 3 张图片,包括一张火的图片,一张非火的图片,还有一张我的图片,包含火一样的颜色和阴影。
在这里,我们可以看到我们上面创建的模型在对我的图像进行分类时犯了一个错误。模型有 52%的把握图像中有火。这是因为它被训练的数据集。在数据集中很少有图像教导关于室内火灾的模型。因此,该模型只知道室外火灾,因此当给定一个室内火灾一样的阴影图像时,它会出错。另一个原因是,我们的模型不是一个可以学习火的复杂特征的复杂模型。
我们接下来要做的是,使用标准的 InceptionV3 模型并对其进行定制。复杂模型能够从图像中学习复杂特征。
2.正在创建自定义的 InceptionV3 模型
这次我们将使用一个不同的数据集[3],这个数据集包含室外和室内的火灾图像。我在这个数据集中训练了我们以前的 CNN 模型,结果是它过度拟合,因为它无法处理这个相对较大的数据集,也无法从图像中学习复杂的特征。
让我们从为我们定制的 InceptionV3 创建 ImageDataGenerator 开始。数据集包含 3 个类,但是对于本文,我们将只使用 2 个类。它包含 1800 幅用于训练的图像和 200 幅用于验证的图像。此外,我添加了我的起居室的 8 张图像,以在数据集中添加一些噪声。
import tensorflow as tf
import keras_preprocessing
from keras_preprocessing import image
from keras_preprocessing.image import ImageDataGeneratorTRAINING_DIR = "Train"
training_datagen = ImageDataGenerator(rescale=1./255,
zoom_range=0.15,
horizontal_flip=True,
fill_mode='nearest')VALIDATION_DIR = "/content/FIRE-SMOKE-DATASET/Test"
validation_datagen = ImageDataGenerator(rescale = 1./255)train_generator = training_datagen.flow_from_directory(
TRAINING_DIR,
target_size=(224,224),
shuffle = True,
class_mode='categorical',
batch_size = 128)validation_generator = validation_datagen.flow_from_directory(
VALIDATION_DIR,
target_size=(224,224),
class_mode='categorical',
shuffle = True,
batch_size= 14)
为了使训练更加准确,我们可以使用数据增强技术。在上面的代码中,应用了两种数据扩充技术——水平翻转和缩放。
让我们从 Keras API 导入我们的 InceptionV3 模型。我们将在 InceptionV3 模型的顶部添加我们的层,如下所示。我们将添加一个全局空间平均池层,然后是 2 个密集层和 2 个下降层,以确保我们的模型不会过度拟合。最后,我们将为 2 个类添加一个 softmax 激活的密集层。
接下来,我们将首先只训练我们添加并随机初始化的层。这里我们将使用 RMSprop 作为优化器。
from tensorflow.keras.applications.inception_v3 import InceptionV3
from tensorflow.keras.preprocessing import image
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Input, Dropoutinput_tensor = Input(shape=(224, 224, 3))
base_model = InceptionV3(input_tensor=input_tensor, weights='imagenet', include_top=False)x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(2048, activation='relu')(x)
x = Dropout(0.25)(x)
x = Dense(1024, activation='relu')(x)
x = Dropout(0.2)(x)
predictions = Dense(2, activation='softmax')(x)model = Model(inputs=base_model.input, outputs=predictions)for layer in base_model.layers:
layer.trainable = Falsemodel.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['acc'])history = model.fit(
train_generator,
steps_per_epoch = 14,
epochs = 20,
validation_data = validation_generator,
validation_steps = 14)
在对我们的顶层进行 20 个时期的训练之后,我们将冻结模型的前 249 层,并训练其余的层,即前 2 个先启块。这里,我们将使用 SGD 作为优化器,学习率为 0.0001。
#To train the top 2 inception blocks, freeze the first 249 layers and unfreeze the rest.for layer in model.layers[:249]:
layer.trainable = Falsefor layer in model.layers[249:]:
layer.trainable = True#Recompile the model for these modifications to take effectfrom tensorflow.keras.optimizers import SGD
model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy', metrics=['acc'])history = model.fit(
train_generator,
steps_per_epoch = 14,
epochs = 10,
validation_data = validation_generator,
validation_steps = 14)
经过 10 个历元的训练,我们得到的训练准确率为 98.04,验证准确率为 96.43。训练和验证损失分别为 0.063 和 0.118。
上述 10 个时期的训练过程
让我们对相同的图像测试我们的模型,看看它是否能猜对。
这一次,我们的模型可以让所有三个预测正确。96%确定我的图像不包含任何火。我用于测试的另外两张图像是:
来自下面引用的数据集的非火灾图像
实时测试:
现在,我们的模型已经准备好接受真实场景的测试了。下面是使用 OpenCV 访问我们的网络摄像头并预测每一帧是否包含火焰的示例代码。如果一个帧中包含火,我们希望将该帧的颜色更改为 B&W
import cv2
import numpy as np
from PIL import Image
import tensorflow as tf
from keras.preprocessing import image#Load the saved model
model = tf.keras.models.load_model('InceptionV3.h5')
video = cv2.VideoCapture(0)while True:
_, frame = video.read()#Convert the captured frame into RGB
im = Image.fromarray(frame, 'RGB')#Resizing into 224x224 because we trained the model with this image size.
im = im.resize((224,224))
img_array = image.img_to_array(im)
img_array = np.expand_dims(img_array, axis=0) / 255
probabilities = model.predict(img_array)[0]
#Calling the predict method on model to predict 'fire' on the image
prediction = np.argmax(probabilities)
#if prediction is 0, which means there is fire in the frame.
if prediction == 0:
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
print(probabilities[prediction])cv2.imshow("Capturing", frame)
key=cv2.waitKey(1)
if key == ord('q'):
break
video.release()
cv2.destroyAllWindows()
下面是上面代码的实时输出。
Github 关于这个项目的链接是这里是。您可以在那里找到数据集和上面的所有代码。您可以从这里在 LinkedIn 上与我联系。如果有任何疑问,请在这里或我的 LinkedIn 收件箱中回复。
照片由 Anandaram G 在 Unsplash 上拍摄
结论
使用智能摄像机,您可以识别各种可疑事件,如碰撞、医疗急救和火灾。其中,火灾是最危险的异常事件,因为不在早期阶段控制它会导致巨大的灾难,导致人类、生态和经济损失。受 CNN 巨大潜力的启发,我们可以在早期从图像或视频中检测火灾。本文展示了两个火灾探测的定制模型。考虑到 CNN 模型的火灾探测准确性,它可以帮助灾害管理团队及时管理火灾,从而防止巨大的损失。
本文使用的数据集:
标签 1 表示火灾,而 0 表示正常
www.kaggle.com](https://www.kaggle.com/atulyakumar98/test-dataset) [## 2.火灾数据集
用于计算机视觉任务的室外火灾图像和非火灾图像。
www.kaggle.com](https://www.kaggle.com/phylake1337/fire-dataset) [## 3.深水/火灾-烟雾-数据集
用于训练火和帧检测的图像数据集 AI 火-火焰数据集是收集用于训练的数据集…
github.com](https://github.com/DeepQuestAI/Fire-Smoke-Dataset)
从社会地理角度看越南的早婚现象
这个分析是我在 IBM 数据科学峰会上工作的一部分。
1.介绍
在越南,千禧一代正在推迟或推迟他们的婚姻。在过去十年里,初婚的平均年龄从 24.5 岁上升到了 25.5 岁。这一趋势直接加速了人口老龄化,给这个亚洲增长最快的经济体之一带来了巨大的担忧。根据规划投资部的数据,15 至 64 岁的越南人占人口的 68%。与此同时,65 岁及以上的人是增长最快的群体。这个年龄组在 2019 年占人口的 7.7%,高于 2009 年的 6.4%。
作者图片
由于越南官员担心该国部分地区的低生育率,他们鼓励年轻人在 30 岁之前结婚生子。在政府的最新公告中没有太多关于具体战略、政策或提供给地方当局的指导的信息。在深入研究解决方案之前,以下是此分析的两个主要动机:
- 哪些因素可能推动了越南的晚婚趋势?
- 地理区域之间结婚年龄有统计学差异吗?
回答第一个问题将会对越南的婚姻状况有一个清晰的了解。相比之下,第二个答案将在实现阶段支持较低级别的本地化(如果有)。
2.数据
2.1.数据理解和收集
以下是本分析中使用的所有资料来源:
- 来自越南统计总局的统计数据,包括三个要素:(1)人口和就业;(2)教育;(3)健康、文化和生活水平(2020 年 5 月 29 日)。
- 从越南统计总局2018 年劳动力调查报告中收集的就业工时数据。
- 地理空间坐标:多边形数据集,包含开放开发湄公河数据库中越南各省政府的地理空间数据。这些 JSON 格式的数据为越南地图的可视化提供了输入。
- 越南行政区划列表:省级/市级。该信息来自越南统计总局(GSO)(2020 年 5 月 29 日)。
2.2.数据清理
由于政府机构获取和组织的所有数据都是结构化的,因此不需要进行大规模的清理和处理。然而,收集的数据不是集中的,而是以不同的形式存在。例如,关于具有四个主要标准的生活水平的统计数据以四种不同的形式分配。因此,在将每个数据集合并到用于分析的主数据集之前,仔细检查每个数据集是非常重要的。完成了一些小的清洁任务,包括:
- 从数据中删除越南口音,以便稍后分类
- 更改省/市名称以匹配地理空间坐标(JSON 格式的多边形数据集)
- 检查了每一列的数据类型
- 删除重复记录
数据清理的输出(前 5 行)如下所示:
作者图片
作者图片
2.3.解释性数据分析— EDA
EDA 是指对数据进行初步调查,以发现模式、发现异常、测试假设,并在汇总统计和图形表示的帮助下检查假设。
首先,检查每个因素的数据分布,以确定它们的基本结构:
作者图片
接下来,进行散点图可视化以了解更多关于数据集之间的相关性,并为聚类模型选择数据特征。
作者图片
这两个步骤导致选择了与聚类建模最相关的八个数据变量,该模型用于进一步的分析。
作者图片
散点图验证:在下面的例子中,月收入和初婚年龄之间存在正线性关系。这表明不同地区不同年龄组的月收入存在差异。同时,在分析之前已经考虑到的生活费用指数已经从模型中删除。
作者图片
3.聚类分析
3.1.方法学
由于该项目涵盖了无监督的机器学习问题,K-Means 聚类方法被应用于基于经济、社会和统计普查的越南行政省/市概况。K-means 的目标很简单:将相似的数据点组合在一起,发现潜在的模式。为了实现这个目标,K-means 在数据集中寻找固定数量(K)的聚类。聚类是指由于某些相似性而聚集在一起的数据点的集合。
K-means 分析的第一步是通过将数据集中的数值列的值更改为一个通用范围来规范化数据要素,而不会扭曲值范围的差异。这是必需的,因为我们的功能有不同的范围。
接下来,我们通过评估聚类数之间的关系和聚类平方和(WCSS)来确定最佳聚类数。理想的集群数量是 WCSS 的变化开始趋于平稳的地方(肘法)。
3.2.使聚集
下面是聚类分析中使用的数据变量的结果选择:
作者图片
使用上面提到的数据探索技术和 Elbow 方法,我们得出了数字 3,这是最佳的集群数量。
作者图片
使用三个期望的聚类进行聚类分析,我们在越南有三组省/市,它们的位置反映了聚类本身。
作者图片
从统计角度来看,我们总结了三个集群:
作者图片
为了验证该分析,使用了两个用三种颜色表示的聚类图。第一个反映了三个集群在月收入和结婚年龄方面的区别。第二张图显示了密度上的簇之间的分离。人们倾向于在低密度的省/市早早结婚。
作者图片
3.3.洞察力
基于上述聚类分析,我们将三个聚类划分为三组省/市,其相关特征如下:
- 第 1 组(第 0 类):偏远和欠发达地区(平均结婚年龄-22.8 岁)
这组记录了越南最早的婚姻。这些省份位于偏远和人口密度较低的地区,在经济和社会方面都欠发达。与其他地区相比,教育和培训方面的低投资可能会导致劳动力中的人口比例最低。
- 第 2 组(第 1 组):人口适中的发展中地区(平均结婚年龄为 25.6 岁)
这一最大的群体包括 42 个城市/省份,其中许多是区域连接枢纽。这些地区被视为第 3 组(第 2 组)的下一级城市/省份,地理位置优越(湄公河三角洲、红河三角洲、沿海地区)。更多的人有机会接受高等教育,这是进入劳动力市场的关键。
- 第三组(第二组):城市、中心和发展最快的地区(平均结婚年龄为 25.8 岁)
这个群体的平均结婚年龄最高。它包括河内、岘港和胡志明市——越南最大的三个城市。其他城市:海防、北宁、平阳和同奈也是最大的经济和工业中心。这个群体的人月收入最高,而且大部分都在职场。这些城市的移民数量逐年增加。
除此之外,上表总结的聚类分析还有其他一些发现:(1)第 1 组女性/男性比例为 100.8,其中人们结婚早,而第 3 组则下降到 95.8,其中晚婚更受欢迎。(2)就每周工作时间而言,第 3 组比第 1 组高 10%。这个群体的人倾向于优先考虑职业发展,而不是成家立业。(3)月收入与生活成本之间的相关性非常弱。(4)平阳的净迁移率最高,为 47.9,其他地区的平均迁移率为-2.1。
4.含义、结论和局限性
基于分析,以下是我的发现的总结,它解决了两个研究问题:(1)哪些因素可能导致了越南的晚婚?(2)不同地理区域之间的结婚年龄有统计学差异吗?
- 收入和婚姻之间存在正相关关系:许多城市居民等待更长时间才能进入婚姻市场,而更多的职业机会来自家庭以外的教育和经济转型。
- 农村和小城镇的早婚比城市多。随着蓬勃发展的经济将更偏远的贫困地区转变为城市地区,社会环境和生活水平发生了变化,人们不太可能结婚。
- 流动性与结婚年龄相关。在流动性和迁移率高的发达地区,人们倾向于晚婚。
总之,鼓励年轻人在 30 岁前结婚对越南官员来说是一个挑战。由于推迟结婚被广泛认为是现代发展中社会的一个不可避免的趋势,解决人口老龄化问题可能需要在国家和省市层面采取长期措施,例如:在贫困地区投资教育和培训,以吸引更多的人加入劳动力队伍,扩大经济中心和网络以减少不必要的移民,或者平衡不同地理区域之间的生活条件。
毕竟,我愿意在未来花更多的时间来发展这种分析,目前这种分析非常简单和幼稚。存在以下一些限制:
获得的数据都来自 2018 年,忽略了不同时期的趋势
社会和经济数据没有考虑性别层面。女性就业人数的增加和女性受教育程度的迅速提高等数字可以解释女性的变化与婚姻减少之间更强的相关性。
一些省/市使用不同的特征来评估其教育、社会和经济发展。这些缺失的数据影响了 Elbow 方法寻找最佳聚类数的有效性。
你可以通过我的 Github 获得我的分析的更多细节。
早期停止介绍:一种有效的神经网络正则化工具
为什么以及如何使用提前停车
图片来源:Unsplash
过度拟合:
对于所有的机器学习和深度学习问题来说,过拟合是一个非常严重的问题。当您的模型在训练数据上表现良好,但无法在测试数据上复制这种表现时,您可以理解这种情况的发生。
如果你不太喜欢阅读博客,并且想开始写代码,请看看 Kaggle 笔记本,或者,你也可以看看我们的视频教程。
图 1:三个模型的决策边界(图片来源:作者)
在上图中,我们看到一个二元分类问题(蓝色类和绿色类)。这三个图表示由三个模型获得的决策边界。第一个模型是做出更简单的假设,第二个模型是做一份体面的工作。
然而,真正的罪魁祸首是第三个模型,它试图记住训练数据,拾取训练数据中的微小波动,实际上对于完美的训练集精度来说走得太远了。模型的这种倾向被称为过拟合,这些模型没有学到很多东西,因此不能进一步应用它们的知识。(不能一概而论)
过拟合与模型参数的关系;
这些似乎是模型参数和过拟合之间的关系。让我们再来看看三个可供选择的模型,我们试图根据一个人多年的经验来预测他的工资
图 2:替代回归模型(图片来源:作者)
可以观察到-
- 第一个模型有两个参数,解释了不同年份之间的联系。工资一般。只考虑 x 的线性项
- 第二个模型有三个参数,它很好地解释了数据,并考虑了二次项
- 第三个模型有四个参数,被诊断为过度拟合,它只是跟踪所有的工资。
最重要的部分来了,参数数量越多的模型越容易过度拟合,并且随着神经网络的参数数量越多,它越容易过度拟合。
正规化和提前停止:
对抗过度拟合这一诅咒的一般策略集被称为规则化,早期停止就是这样一种技术。
想法很简单。该模型试图通过调整参数来疯狂地追逐训练数据上的损失函数。现在,我们保留另一组数据作为验证集,当我们继续训练时,我们保留验证数据的损失函数记录,当我们看到验证集没有改进时,我们停止,而不是遍历所有时期。这种基于验证集性能的提前停止策略称为提前停止。下图对此进行了解释。
图 3:提前停止演示(图片来源:作者)
从图 3 中可以观察到
- 在所有的时期,训练集的精确度持续增加
- 然而,验证集精度在 8 到 10 个时期之间饱和。这里是模型可以停止训练的地方。
因此,早期停止不仅可以防止过度拟合,而且需要相当少的历元数来训练。
代码摘录:下面的代码演示了我们将 20%的训练数据作为验证集。
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()trn_images, valid_images, trn_labels, valid_labels = train_test_split(train_images, train_labels,test_size=0.2)
一些其他的正则化技术是损失函数正则化、丢失、数据扩充等。如果有兴趣,你可以自担风险,在这个视频教程中浪费一些时间。
回调 API:
我们现在想到的一个问题是,当模型被训练时,我们如何监控发生了什么,以及如何保持跟踪?这就是我们从 Keras 回调 API 获得帮助的地方。
图 4:回调 API 的窗口模拟(来源:Unsplash)
回调 API 就像窗口,在黑盒模型训练过程中,允许我们监控,我们感兴趣的对象。
- 一个回调是一个强大的工具,用于定制 Keras 模型在训练、评估或推断过程中的行为
- 它可以让你定期保存你的模型到磁盘
- 您可以在训练期间查看模型的内部状态和统计数据
- 可以有多个回调一个用于保存,一个用于监控
- 回调可以附加拟合,评估,预测 Keras 模型
当然,我们不能在任何时候看到中间值,它可以在训练开始时、训练停止时、时期结束时或一批训练结束时。
我们确实默认使用了一些回调函数,比如我们在模型编译中提到的度量和损失函数。在这种情况下,我们不需要附加任何回调 API 或窗口。这被称为基础回调 API 。下图显示了这一点。
图 5:基础回调 API(图片来源:作者)
提前停止回调的一些重要参数:
- 监控:被监控的数量。默认情况下,它是验证丢失
- min_delta: 符合改善条件的监控量的最小变化
- 耐心:没有改善的周期数,在此之后训练将停止。
- 模式:为{“自动”、“最小”、“最大”}之一。是最大化问题还是最小化问题,我们最大化精度,最小化损失。
- restore_best_weights: 是使用最佳模型权重还是上一个时期权重
代码示例:
突出显示的部分是我们在模型拟合过程中需要做的唯一更改。
**callback = tf.keras.callbacks.EarlyStopping(patience=4, restore_best_weights=True)**
history1 = model2.fit(trn_images, trn_labels, epochs=50,validation_data=(valid_images, valid_labels),**callbacks=[callback]**)
结果:
这是在 Fashion MNSIT 上执行的,这是运行您的实验的一个很好的测试平台。
在没有提前停止的情况下,模型运行所有 50 个时期,我们得到 88.8%的验证准确度,而提前停止运行 15 个时期,测试集准确度是 88.1%。
这是其中一个种子值,总体而言,它清楚地表明我们实现了相当的结果,减少了 70%的时期。
========================================
谢谢你读到这里。这些是我们在加尔各答大学数据科学实验室创建的一些附加资源
a)用 Python 分类(https://www.youtube.com/playlist?list = plts 7 rwcd 0 do 2 zoo 4 sad 3 jrxnvfyxhd 6 _ S
b)用 Python(https://www.youtube.com/playlist?)进行聚类 list = plts 7 rwcd 0 do 3ts 44 xgwgvgxmeohyfi 3pm
参考资料:
https://sebastianraschka.com/books.html
通过部署 API 利用机器学习赚钱
使用 FastAPI、uvicon/guni corn 和 Python 将您的作品发布到 RapidAPI 市场💸
来源:@denarium _ bit coinviaunsplash
如果你正在读这篇文章,那是因为你已经创造了一些有价值的代码,你希望能够发表。无论您只是简单地将一些开源技术打包在一起,还是构建了一个出色的新算法,其他技术专家都很有可能会发现您的解决方案很有用。
在本文中,您将利用开源框架在的 3 个简单步骤中将您引以为豪的东西部署到 API 市场。你甚至可能获得一点被动收入。要获得好评和/或利润,需要一点努力和一点运气——让我们全力以赴吧🏀!
我可以在哪里分发我的作品?
作为一名有才华的数据专家,您对 API 非常熟悉。如果你需要快速复习,这里有一些我最喜欢的:
应用程序编程接口是一个现成的代码,可以简化程序员的生活。它有助于数字化…
towardsdatascience.com](/top-20-apis-you-should-know-in-ai-and-machine-learning-8e08515198b3)
API marketplace 允许开发者发布和货币化他们的工作,而不需要管理定制的支付系统和复杂的基础设施。RapidAPI 是我最喜欢的应用程序,为你能想到的每一种应用程序提供“免费增值”和付费订阅计划。假设您正在构建一个自定义应用程序,该应用程序将财务数据与新冠肺炎感染统计数据相关联,您将使用 RapidAPI 来发现、学习和扩展。
我为什么要发布 API?
开源软件运动推动了世界上一些最受欢迎、最赚钱的科技公司。开源脚本语言(Python、R、Julia)、数据库技术(SQL、MongoDB)和计算库(SciPi、Scikit-learn、tidyr)的存在使越来越多的数据专业人员能够构建各种规模的有价值的解决方案。为什么不贡献一个惊人的开发者资源生态系统呢?
如果你是一名新兴的数据科学家,这是推销你的才华和创业技能的最佳方式。我们开始吧!
我如何部署一个 API?
有多种方法可以让 API 启动并运行。以下是我最喜欢的几个 python 部署:
- 使用 Zappa 在 AWS Lambda 上部署无服务器 Web 应用
- 用 GitHub 页面、Flask 和 Heroku 构建一个简单的 Web 应用
- 使用 FastAPI 和 Uvicorn(我们将使用这种方法😉)
FastAPI 是一个闪电般快速、直观和健壮的 API 框架,它简化了开发过程。uvicon是一个流行的 WSGI 服务器,它使得在云中运行 python 应用程序变得很容易。
简单的部署步骤
我最近开发了一个简单的程序,从一篇新闻文章中抓取文本,为命名实体识别和词性标注处理文本,然后执行一些高级分析。
I .将此程序部署到我的本地计算机:
- 安装依赖项:
pip install fastapi uvicorn gunicorn
2.格式化端点。
在格式化您的代码之前,看一下 path params 文档:
3.运行它!
uvicorn main:app --reload
4.在 Swagger UI 中查看(生成的)文档:
[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
5.带着 API 兜一圈!
二。作为微服务部署到 Heroku:
- 将您的代码保存到一个 GitHub 库。
- 打开 Heroku,创建一个新的应用程序,连接你的 GitHub 帐户,链接你想要发布的特定存储库,并启用自动部署。
- 通过运行以下命令构建 requirements.txt 文件:
pip freeze > requirements.txt
4.制作一个 Procfile 以便 Heroku 知道如何部署应用程序:
web: gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
5.推送至 GitHub,等待 Heroku 部署您的解决方案!您可以查看我完成的例子如下适当的格式👇
如果您在将本地部署添加到 Heroku 时遇到问题,请查看此视频!
三。通过 RapidAPI Marketplace 分发,以便开发人员可以使用它:
- 注册一个 RapidAPI 帐户并“添加一个新的 API”。
- 添加一个基本 URL(链接到 Heroku app)并格式化相关的端点!
- 给 API 打上品牌!添加一个高分辨率的图像,雄辩的描述和诱人的功能。
- 格式化公共计划的定价属性。RapidAPI 提供多种订阅计划,可随消费而扩展。根据你的代码的,从一个完全免费的计划或免费层(‘免费增值’计划)开始让其他开发者上钩可能是有意义的。如果你更有信心,直接去“付费”并要求一个订阅的信用卡。
- 最后,将 API 发布到市场上!开发人员将能够使用你出色的新应用程序,你将获得有价值的反馈。未来的更新/附加特性将更好地服务于那些使用你的 API 的开发者。
让其他开发者订阅付费!
很多 API 是由公司开发的,而不是个人开发的。随着有才能的数据专业人员的数量随着需求的增加而增加,对有价值的算法和数据管道的廉价、复杂的替代品的需求也会增加。你可能不会马上获得被动收入,但是在寻找与数据相关的职位时,你已经很好地展示了独特的才能和企业家精神,提高了你的市场竞争力。我鼓励您尝试 FastAPI 和其他替代方案,看看哪种类型的解决方案最受欢迎。
如果您想讨论 API 格式和最佳实践、开源理念或您可以开发的各种按需软件选项,请联系我。我很乐意收到你的来信。
感谢阅读!😃
地球:“感谢新冠肺炎,我可以更轻松地呼吸了”
新冠肺炎封锁期间,我所在城市的空气质量发生了怎样的变化
来源:Pixabay —标清图片
在冠状病毒疫情期间,许多人呆在家里,一些行业已经暂停生产,因为政府已经制定了防止疾病传播的法规。这导致城市交通减少,一些工业暂时没有污染空气。由此可以推测,城市的空气污染有所减少。
为了验证这个假设,我分析了我的家乡斯洛文尼亚卢布尔雅那的污染数据。为了进一步支持这些假设,我采用了意大利贝加莫的污染数据,这是受冠状病毒影响最严重的欧洲城市之一。
在这篇文章中,我比较了世界卫生组织的两种对健康有重大影响的污染物的测量值。(no₂)城市中的二氧化氮主要是由交通产生的。 PM10 是直径在 2.5 到 10 微米之间的细小颗粒。世卫组织也提到了 PM2.5(直径小于 2.5 微米的颗粒),但我无法获得卢布尔雅那 PM2.5 的数据。我从欧洲环境署的数据库中检索了所有数据。
卢布尔雅那的空气污染
在下图中,我绘制了卢布尔雅那过去四年 NO₂和 PM10 的日平均浓度。每一年都有不同的颜色。
图表显示了斯洛文尼亚卢布尔雅那过去四年中 NO₂和 PM10 的日平均浓度。
对于 NO₂,我们可以看到上个月(2020 年)的数值低于前几年,但这些图表很难读懂,因为浓度每天都在变化。我使用了移动平均线来得到一个更平滑的图形。
图表显示了斯洛文尼亚卢布尔雅那过去四年的平滑平均日 NO2 和 PM10 浓度。当浓度未被报告或无效时,线路中断。
我们可以看到,在三月中旬之后——我国政府实施了限制——no₂的浓度低于前几年。PM10 的浓度与前一年相似——在三月底的一段时间里,由于风把撒哈拉沙漠带到欧洲,浓度甚至更高。
为什么 NO₂的浓度低于前几年的解释可能是 NO₂的主要来源是燃烧化石燃料的内燃机——交通。另一方面,PM10 来自更多不同的来源,包括发电厂、工业,还有交通,这可能是 PM10 没有改变的原因——燃烧季节仍在继续,许多工业没有停止生产。
贝加莫的空气污染
为了确保我们的结果与新冠肺炎封锁相关,我们检查了另一个城市的数据,该城市受到了意大利北部疫情-贝加莫的影响。这是受新冠肺炎影响最严重的城市之一。
图表显示了意大利贝加莫过去四年的日均 NO₂和 PM10 浓度。当浓度未被报告或无效时,线路中断。
对于 Bergamo,我再次在图表上绘制了过去四年的日平均值,因为它们并不完全清楚,我对卢布尔雅那的数据进行了平滑处理。
图表显示了意大利贝加莫市过去四年的平滑日均 NO₂和 PM10 浓度。当浓度未被报告或无效时,线路中断。
我们可以在意大利的 NO₂图表中观察到与卢布尔雅那之前相似的趋势。二月底,意大利在该国北部实施了限制。与此同时,与其他年份相比, NO₂ 的浓度开始下降。与其他年份相比,这一差异甚至比卢布尔雅那更为显著——与其他年份相比,浓度减半。
PM10 浓度没有差异。我还分析了佛手柑的 PM2.5 浓度,它们与 PM10 相似,与其他年份相比没有差异。
结论
从这个故事中呈现的数据,我们可以得出结论,被观察城市的空气质量有所改善。 NO₂ 浓度有巨大变化,这表明交通产生的污染明显减少,而颗粒物(测量为 PM10 和 PM2.5)仍停留在同一水平。根据参考资料,我可以得出结论,这是因为许多颗粒来源持续存在——包括燃烧化石燃料来加热。
新冠肺炎的后果是毁灭性的,将给我们未来的生活带来巨大的变化。然而,我们必须承认也有一些积极的方面。他们中的一个也看到了地球是如何被治愈的。过去几周我们呼吸的更清洁的空气是积极的事情之一,如果我们回到以前的轨道上,这种情况会很快改变。
土耳其地震和热门场馆数据分析
我应该在哪个安全的城市投资哪个部门?
1。简介
1.1。描述&背景讨论
土耳其是一个地震多发国家,T4 有 8200 万居民。由 81 个省份组成。它被北安纳托利亚、西安纳托利亚和东南安纳托利亚地震带环绕。土耳其地貌的多样性是地球运动的结果,几千年来,地球运动塑造了该地区的地形。
它有死火山,地震仍然频繁发生。在这个国家的北部和东部,有导致今天地震的大断层线。1999 年发生在北安纳托利亚断层线上的马尔马拉大地震导致数千人死亡。[1]
尽管土耳其是一个地震多发的国家,尽管它也是一个旅游国家。每年有数百万来自世界各地的游客参观它。甚至有一些外国侨民在土耳其购买房地产并进行交易。[2]
1.2。问题
投资者和消费者会对基于地震统计和每个城市热门地点的数据分析感兴趣。投资者可以在地震风险较低的地方开展项目,并投资于这些地方业务不太密集的工作。对于生活在城市的普通人来说,他们可能想要购买并居住在不太危险同时又靠近社交场所的地方。
因此,通过基于每个城市合理的过去(例如,100 年)进行地震统计来进行聚类研究,可以确定具有高地震风险或没有地震风险的区域。此外,通过比较这些地区的热门场馆,可以揭示地区之间的独特性。
2。数据
2.1。数据来源
本研究中用于解决问题的数据来源如下:
- 从 AFAD 地震目录页面,1920-2020 年间发生的里氏震级 4-10 级地震的统计数据以 csv 格式通过各种过滤方法获得。[3]
- 通过 OpenStreetMap ,提供了地震分布所需的 GeoJSON 数据和显示集群组的地图。[4]
- 通过 Foursquare API ,可以获得这些城市最受欢迎的场馆的类型信息,以及这些地方的经纬度信息。[5]
- 来自维基百科的是土耳其的城市列表。借助 Python GeoPy 库,通过逐一查询,获得城市的经纬度信息。[6]
2.2。数据探索和清理
从 AFAD 刮来的地震数据;获得了日期、地震纬度、地震经度、地震震级和深度信息。从多个来源下载或搜集的数据被合并到一个表中。在 1920 年 1 月 1 日至 2020 年 1 月 1 日和 2020 年 1 月 1 日至 2020 年 1 月 1 日大于 4.0 里氏共获得 5707 条数据。csv 文件中出现的一些缺少信息的变量没有包含在原始数据集中,因为它们是多余的。
图一。 AFAD 地震目录页。(图片由作者提供)
在接收 AFAD 地震数据时,实施了矩形搜索式。人们认识到,收到的一些数据来自土耳其境外。由于地震发生城市的名称不包括在地震统计中,因此地震发生城市的信息是通过使用 GeoPy 库和对每个数据的反向地理编码方法获得的。发生在土耳其以外的地震数据被从主数据集中删除。因此,总共有 4364 行数据保留在主数据中。
图二。摘自 AFAD 网站的第一个地震统计编辑版本。(图片由作者提供)
根据获得的数据集,通过查看震级直方图可以看出,发生的大多数地震的震级在 4 到 4.78 之间。直方图提供了有关地震分布的信息,有助于了解数据集的结构。
图三。地震震级直方图。(图片由作者提供)
此外,还检查了研究中数据集的标准偏差、最小值和最大值,并得出了意见。本次审查的表格如下所示。
图 4。创建的第一个数据集的统计信息。(图片由作者提供)
查看图 4,~ 0.47的震级标准偏差值表明,震级值比其他变量分布更均匀,彼此更接近。图 5 中的震级直方图也支持这一观点。下面的深度直方图显示了深度值的分布,也可以检查。
图五。地震深度直方图。(图片由作者提供)
当比较属性的最大值和最小值范围时,将会看到它们通常是彼此相差不太远的值。此外,当比较所有特性的最大值和所有特性的最小值时,可以理解不需要任何标准化或规范化。
2.3。处理缺失数据
发现第一个数据集中没有一些城市的统计数据。这意味着那些城市已经 100 年没有发生过大于 4.0 的地震了。这些城市分别是*****里泽*巴特恩 和 基利斯 。震级和深度变量仅填充了这四个城市的合理值,因此这些省份的行在数据集中不会显示为 NaN。
这些城市在统计的 100 年内没有大于 4.0 的地震记录,并不代表没有地震。一些小于 4.0 级但我们没有记录的地震可能已经发生。即使这些城市的边界内没有地震,邻近城市的地震也能影响这些城市。所以用零填充 NaN 的幅度部分是没有意义的。
然而,在从 AFAD 获得的统计数据中,发现一些深度值为 0.0 。考虑到这种情况可能是自然的,下面要推导的最大深度和最小深度的值被接受为这些省份的 0.0 。最大幅度值被接受为 3.0 ,最小幅度值被接受为 1.0。基于此,平均值值被接受为 2.5 。********
2.4。特征提取
每个城市的平均、最大和最小特征通过特征提取产生。这些属性被添加到编辑的第一个数据集。新属性是基于幅度和深度变量导出的。然后从数据集中删除了 Eq_Latitude 和 Eq_Longitude 属性。最后,主数据集被创建,将带有 81 个城市的经纬度信息的数据表添加到数据集。
****图六。主数据。(图片由作者提供)
3。方法学
使用 Python 叶库,对 4364 个地震点的地理细节进行可视化,以获得初步见解。这是一个有用的可视化,特别是在看到地震发生在哪些地区以及了解地震分布方面。
****图 7。土耳其 1920-2020 年间发生的地震。(图片由作者提供)
Foursquare API 被用来发现城市中受欢迎的场所。作为每个城市的限制, 100 个热门场馆和 20 公里直径被测量。在一些城市中,已经观察到当直径测量值较短时,没有返回流行的空间数据。为此,进行了 20 公里宽的搜索,以便从每个城市获得至少 10 排。共获得 6581 行数据。
图 8 。Foursquare API 查询获得的位置数据。(图片由作者提供)
为城市中确定的热门地点创建了一个汇总表。数据透视表显示了 Foursquare API 为每个城市返回的场馆总数。该表的图表如下。
****图九。各城市热门场馆总数。(图片由作者提供)
当检查图 9** 时,可以看到返回了许多大城市的 100 个结果。而伊斯坦布尔、亚洛娃、伊兹密尔、布尔萨、特拉布宗、阿达纳、梅尔辛、迪亚巴克尔和安塔利亚等省份则被视为热门地的富豪;阿加尔、通杰利、哈克里、锡尔特、埃尔祖鲁姆等省份保持在 20 结果以下。**
当然,这张图并没有包括各省所有的热门地点。因为搜索是在距离每个城市 20 公里的地方进行的,并且仅使用一个经纬度对来表示每个城市。考虑到它的面积,这个搜索可能被认为是对某些城市的窄搜索。
也可能有许多位置没有被 Foursquare 检测到或认为是受欢迎的。通过使用关于城市的更多纬度和经度信息执行更详细的搜索,可以获得更受欢迎的位置信息。
当总结使用 Foursquare API 获得的数据时,可以看到总共识别出了属于不同类别的 347 种受欢迎的场所。一个新的数据表已经创建,显示了各省最常见的 10 个场馆。
****图十。十大最常见的场馆。(图片由作者提供)
确定热门场馆后,对 347 个分类变量进行一次性编码,从主数据中提取城市属性,用 K-Means 算法进行聚类研究。K-Means 算法通过尝试将样本分成 n 个方差相等的组来对数据进行聚类,最大程度地降低了惯性或类内平方和标准。K-Means 算法是无监督学习中最常用的聚类方法之一。
****图 11。用于 K-Means 算法的数据集摘要。(图片由作者提供)
图 11 总结了 K-Means 聚类算法中使用的数据集(81 行 x 355 列)。空间距离有不同度量距离函数。研究中选择了 Sqeuclidean 指标。因为它让肘部断裂点看得更清楚。为了确定最佳聚类数,用不同的试验进行聚类研究。通过增加 K-Means 算法的聚类常数(K 值)来分析结果。用肘法分析时,确定最佳值为 K = 3 。这种情况在下图中也可以看到。
****图 12。优 K 数同肘法。(图片由作者提供)
在聚类研究之后,创建了一个新的数据表,给出了发现的聚类、城市名称、平均值。城市中发生地震的震级,以及每个城市中 10 个最常见的地点。
****图 13。最常见的场馆和集群编号。(图片由作者提供)
当对检测到的的 3 个星团进行地震危险性检查时,它们被标记为低 — 中 — 高。当计算每个聚类中所有城市的平均地震震级时,也确定了聚类的风险比。****
地震风险最高的城市群被确定为高,而地震风险最低的城市群被确定为低。创建了一个新的数据表,其中包含分类所拥有的城市总数、分类在形状和地图上的表示颜色以及分类标签。
****图 14。检测到的簇的标签、颜色和计数信息。(图片由作者提供)
当比较聚类之间的城市数时,可以看到聚类高以 46.9% 排在第一位。这一结果表明,该国大多数城市都处于地震的高风险之中。
另一方面,地震风险低的集群低的城市总数过高,不容低估。对于为防范地震风险而进行的各种投资,可以将注意力吸引到这一组中的省份。
****集群中等,地震风险处于中等水平,就城市总数而言似乎是最小的集群。下面,您可以查看包含聚类城市编号的饼图。
****图 15。聚类中城市的计数。(图片由作者提供)
4。结果分析
到目前为止,我们所取得的成果对那些希望生活在一个安全城市的普通人来说是一个指南,或者在这个方向上做出他们的房地产购买决定。有必要更详细和单独地研究集群,以便提出意见来指导投资者。
4.1。集群:“高”
****图十六。簇高的透视表。(图片由作者提供)
高集群是地震风险最大的城市集群。土耳其所有城市中的 38 个都在这个集群中。考虑到所有的集群,它在城市数量方面是第一个集群。当检查城市的特征结构时,可以看到它们通常位于远离大海的内陆地区,在多山的地方,其中一些有海边。
集群中拥有海岸的大多数城市都是爱琴海的邻国。集群中还有两个城市,相邻的马尔马拉、黑海和地中海。
****图 17。集群高第一公共场馆数据透视表。(图片由作者提供)
图 17 中给出的表格是在对集群中城市的“最常去的地方”进行比较后得出的。
根据该表,咖啡馆似乎是该集群 38 个城市中 24 个城市的第一个最常见的位置。然后,“酒店”和“土耳其餐厅”分别到来。预计对投资者来说,这些行业将会有激烈的竞争。更明智的做法是将注意力转向竞争力较弱的行业。
这个集群中几乎所有的城市都位于断层线上。在这方面,特别是那些想购买房地产的人,可以从距离断层线较远的集群中或集群低中选择一个城市。
此外,由于具有最高地震风险的集群,可能优选的是,要进行的投资是不受地震影响的成本较低的企业类型。对于高成本投资,地震风险较小的集群城市可能是首选。
当对该集群中从 1 到 10 的所有城市的所有公共场所进行求和时,列表顶部的前 20 个场馆如下图所示。
****图 18。集群高中所有最常见场馆的前 20 名图表。(图片由作者提供)
根据图 18** 中的图形,海鲜餐厅看起来是一个比其他行业竞争力弱的地方。可以在这个部门进行投资,特别是在这个集群的海滨城市。**
此外,作为第七家烘焙食品业务“甜品店”的替代方案,投资“面包店”板块,该板块服务的区域相似,竞争比图中要少,可以认为是一个很好的机会。
该集群中的一些城市位于内陆地区,那里是大陆性气候,并且位于冬季非常寒冷的山区。另一方面,看图表,可以看到有很多与茶、咖啡等饮料相关的业务。
与其进入这个竞争激烈的地区,“早餐点”可能是一个不错的投资选择,在这里你可以喝茶和咖啡,一方面吃早餐,另一方面竞争也较少。
4.2。集群:“中等”
****图 19。集群中的透视表。(图片由作者提供)
该集群由 10 个城市组成,地震危险度为二级。城市的邻居通常是从集群高的城市。在这方面,就穿过城市的断层线和地震风险而言,地形可能类似于集群高。除了穆拉、安塔利亚和梅尔辛,这些城市都没有海滨。安纳托利亚东部的城市位于山区和高海拔地区。
当根据“第一最常见地点”在集群中的城市之间进行比较时,获得下表。
****图 20。第一集群媒体公共场馆数据透视表。(图片由作者提供)
从该表中可以看出,咖啡馆是前两个集群中投资者普遍青睐的行业。所以竞争很大。特别是考察集群介质中的集群时,一些省份常见但竞争较少的“山板块可能适合投资。
关于这个问题的进一步评论,看一下前 20 个场馆列表将是有用的,其中包括所有城市中的公共场馆。下图显示了从 1 到 10 的所有常见地点的总和。
****图 21。集群媒体中所有最常见场馆的前 20 名图表。(图片由作者提供)
集群中临海的城市可以被认为是可以投资的城市,尤其是在旅游业方面。与集群高一样,我们可以检查在投资方面竞争力较弱且排名较低的行业。
根据该国旅游业的发展情况,排名前 20 位的“酒店”行业和“观景”行业可能是一个不错的投资选择,在高海拔城市,这两个行业的竞争力似乎较弱。
就房地产而言,海滨城市可能很有吸引力。然而,对于这一点来说,选择低地更合适,它具有最小的地震风险,并且有海滨。
4.3。集群:“低”
****图 22。簇低的透视表。(图片由作者提供)
是地震风险最小的集群。它总共由 33 个城市组成,城市数量在其他集群中排名第二。几乎所有拥有海岸线的城市都毗邻黑海。除了土耳其黑海的邻国科贾埃利和萨卡里亚之外,所有的城市都位于这个集群中。
这个集群中的城市可能是房地产投资的首选。那些想在海边和地震风险最小的地方买房的人应该详细评估这个集群中的城市以及这些城市的房地产机会。
当根据人口密度进行评估时,它由该国人口最多的城市组成,如伊斯坦布尔和安卡拉。人口密集,地震风险低于其他省份的事实,为投资铺平了道路。
下表显示了城市中“最常见的地方”。
****图 23。第一集群媒体公共场馆数据透视表。(图片由作者提供)
在这个集群中的城市,投资机会高于其他集群中的省份。大量的海滨城市、较少的地震和各种各样的投资领域使得集群低的城市更有吸引力。
因此,更好的决定是选择一个不同的、开放发展的部门,而不是像咖啡馆部门那样在每一个集群中都非常普遍和竞争激烈的部门。在下图中,您可以看到聚类低的城市的前 20 个位置列表。
****图 24。Cluster LOW 中所有最常见场馆的前 20 名图表。(图片由作者提供)
我们之前为集群高提到的“甜品店”和“面包店”的投资思路在这个集群也是成立的。当图 24** 被检查时,将会看到这些部分可以相互替代,因为它们处于相似的区域。**
黑海沿岸的城市发展了渔业。所以竞争不太激烈的“海鲜馆”可以是不错的投资。为海鲜餐馆供应鱼也是一个好的商业想法。
在“花园”和“农场”中,它们可以被评估为相似且竞争较小的业务类型,作为联合或单独投资。
当检查到目前为止所有集群的表格和图形时,将会看到“山”扇区在每个集群中处于显著的顺序。为此,在所有集群中海拔较高的城市,可以认为是一个很好的投资机会。
同样,当将所有集群放在一起考虑时,可以看到“农场”、“公园”和“广场”行业的竞争处于中等水平,它们在总数中所占的比例很大。
4.4。聚类图
所有检测到的聚类都用土耳其地图上的点可视化。 Python 叶子 库被用于此。你可以在下面的地图上看到我们在上面对星团所做的所有解释的可视化版本。
****图 25。土耳其地图中聚类点的可视化。(图片由作者提供)
上面地图上用红色显示的点属于集群高,地震风险最高。橙色点代表中,绿色点代表低。
除此地图外,还根据平均地震震级绘制了颜色分布的等值线图。平均地震震级和聚类一起显示在 Choropleth 图中。
另外,点击每个点时,相关城市名称、集群信息和百年平均地震震级信息作为弹出。
****图 26。土耳其地图中聚类点和平均地震震级分布的可视化。(图片由作者提供)
5。讨论
这项研究的第一个目的是通过利用地震数据分析城市中受欢迎的场馆,帮助商人和普通市民做出投资决策和未来的社会生活。
虽然该项目中使用的统计数据代表了城市的一部分,但它被视为代表了整个城市。例如,只发生在城市一个地区的地震被认为发生在整个城市。因此,基于城市的研究可以通过更深入的挖掘在地区或社区的基础上进行。此外,还可以用 Foursquare API 数据之外的不同数据源获取更多数据。因此,将有可能获得更清晰和不同的结果。
这个项目的另一个目的是通过检查旧的地震做出推论,并产生我们可以从中受益的信息。
例如,如果一个城市发生了太多地震,并且震级很高,那么该城市很可能会因断层活动而再次发生地震。但是,这种接受并不能得出多年没有地震的地方是安全的结论。本研究所使用的方法在将来可以用不同的数据和不同的方法来处理,可以得到不同的结果。
当检查图 25 中的红点时,可以看到它们与土耳其的地震危险地图是一致的。[7]
6。结论
因此,该项目有助于更好地了解城市在地震和社交场所方面的特点。该项目不仅支持了投资者,也支持了城市管理者或规划者的决策。它也为在与本研究类似的领域中使用数据分析类型的各类研究人员起到了指导作用。
研究中使用的所有数据集、Python 代码和图像文件都存储在相关的 GitHub 帐户中。[8]因此,它可以在将来用于不同的项目。
泽克·奇普拉克 物理学家,数据&计算机科学爱好者。
7。参考文献
- 1.维基百科“土耳其”话题。(土耳其语)
- 2.gyo der——为什么要投资土耳其?(土耳其语)
- 3. AFAD 地震目录
- 4. OpenStreetMap
- 5. Foursquare API
- 6.土耳其的城市(土耳其语)
- 7.项目的 GitHub 库
- 8.土耳其地震危险性图。
坚持科学…
使用混合聚类-LSTM 方法的地震时间序列预报——第一部分:EDA
在加州过去 50 年的历史地震中测试该方法
The notorious 1906 San Francisco earthquake hit the bay area on the April 18th 1906, leaving more than 3,000 deaths. Earthquake had a moment magnitude of 7.9 [[Image source](https://en.wikipedia.org/wiki/1906_San_Francisco_earthquake), [license](https://catalog.archives.gov/id/524396)].
这篇博客是描述这一时间序列分析细节的一系列博客中的第一篇
0.序
以我们目前有限的技术进步,地震的确定性预测只是一个无法实现的要求。这种限制可能有两个原因:1 —我们对地下断层结构的了解极其有限;2 —记录地震数据的地震仪具有固有的灵敏度限制。由于地震学研究的进步,随着我们对地震的物理理解的胜利,未来看起来是光明的。然而,仍然有一些地震的发生没有被注意到,例如帕克菲尔德(2004 年)地震,该地震预计发生在 1988 年的早些时候。另一种研究地震预报问题的方法是通过使用更先进的统计学和人工智能工具。作为一名数据科学家,我采取了一种不同的方法来对地震现象有更好的统计理解;因此,这里的“预测”一词只是指统计理解,而绝不是指确定性的地震预测。了解了这一点,现在让我们开始分析。
1.介绍
仅自上个世纪以来,地震就造成了数百万人死亡(T4)。除了生命威胁之外,随之而来的巨大经济和基础设施破坏可能给文明留下长久的创伤。例如,位于太平洋-北美板块边界附近的加利福尼亚州已经经历了许多毁灭性的地震,其中一些造成了大量的人员伤亡和经济损失(参见我的 GitHub 库文档中的简要列表。
这些地震时有发生,但我们有时会忽略全球地震网络( GSN )持续记录的大量地震数据。地震数据记录了各种各样的地震、断层系统、地理位置和几个传感器,提供了足够多样的数据集来从数据科学的角度研究地震分析。此外,数据科学中的工具可以在评估如此重要的社会危害问题时投入真正的试验。目前的物理地震模型无法预测一些地震事件。希望数据驱动的地震分析将为地震发生的系统学提供额外的见解。人口密集的住宅区可以真正受益于早期地震预警系统(例如,检查* 震动警报 )。尤其是基于强大的人工智能工具的。*
2.预测地震时间序列的困难
图一。1989 年洛马普列塔 6.9 级地震序列。注意没有前兆大事件的主震的发生。
图 1 显示了 1989 年洛马普列塔地震( 63 人伤亡,100 亿美元损失)期间前震(主震前)、6.9 级主震和余震(主震后)的序列。主震发生时几乎没有任何大的前兆信号。对于更传统的时间序列模型,如自回归模型,这使得地震预测的任务变得复杂。
2.问题陈述:
圣安地列斯断层从西北-东南加利福尼亚沿海岸延伸近 700 英里。这个断层导致了臭名昭著的 1906 年旧金山地震,以及后来的洛马普列塔和帕克菲尔德地震。但是,这不是唯一的断层系统,地震发生在许多附近的断层上,这些断层甚至可能以复杂的方式相互作用。这些地震的发生有什么系统性吗?如果有的话,它们能帮助我们辨别小地震是如何发展,导致大地震的吗?这里的分析更多的是基于数据,而不是基于物理。这意味着,任何震级和任何距离的地震对预测大地震都有同样的重要性;而且,没有事先的假设。只是,统计分析决定了地震重要性的权重。
4.模型工作流
模型工作流程由以下连续步骤组成: 1 — 数据收集。 2 — 数据清洗。 3 — 探索性数据分析(EDA)。 4 — 时间序列建模。 5 — 建议。对于这个项目的代码的完整访问,我邀请你在我的 GitHub 个人资料上看到这个库。大部分代码都是在 python 环境中编写的,在这里我使用了 Python 中的 Pandas、 scikit-learn 和 TensorFlow 库。
5.数据收集和清理
图 2:圣安地列斯断层几何学,臭名昭著的 1906 年旧金山、1989 年洛马普列塔和 2004 年帕克菲尔德地震就发生在这里【图片来自 Richard 等人,2014,来源,许可】。
我用美国地质调查局的 API 提取了加利福尼亚州附近过去 50 年的地震数据。多亏了美国地质勘探局,这个 API 是公开可用的。为了下载一个足够全面的地震目录,我下载了加利福尼亚州以外的地震,经度和纬度范围分别为(-133,-107)和(24,50)度(远超过加利福尼亚州)。对于这篇博客文章,我主要探索了 6.9 级洛马普列塔(1989 年)地震数据的 EDA 分析。这次地震发生在圣安地列斯断层的锁定段(见图 2)。以下函数用于读取 USGS 地震 API:
函数来提取 USGS API 地震数据。查看我的 GitHub 库了解完整的功能。
导入的 json 文件嵌套过多;因此,在数据清理期间,我对 json 文件进行了“去嵌套”,将它们转换成数据帧,修复列数据类型,估算 NaN 值,最后将它们连接成一个全局数据帧,这是可行的。关于数据清理的完整描述,请访问我的 GitHub 档案。最后,我通过时间戳将数据帧索引为时间序列数据帧:
这个时间序列是 不规则的 ,意味着时间间隔是不均匀的,正如许多对事件敏感性有限的传感器数据所预期的那样;有些地震数据有 8 毫秒的间隔,有些接近 1 天。这使得时间序列建模变得复杂,我将在以后的博客文章中讨论这个问题。
5.EDA — 50 年的地震数据
下载的数据包含丰富的信息,包括事件发生的时间、力矩大小、强度(由人类评估)以及地震的三维位置。出于数据大小的考虑,我们只将矩震级大于 2 的地震视为更重要的地震。
请注意,矩震级是对数标度单位,这意味着一般来说,6 级地震比 5 级地震大 10 倍。
对震级的时间演变的初步观察表明,时间序列中有一个突然的峰值,没有太多早期的注意,如图 1 所示。
**
图 3:过去 50 年的全部地震数据。总共有 85 次大于 6 级的地震(上图中的灰色线)。力矩大小分布也用直方图表示。震级分布紧密遵循泊松分布(图片由作者提供)。
图 3 显示了全部数据(近 313k 下载的地震数据)。震级大于 6 级的地震有 85 次,我认为这是破坏性地震的阈值(大英百科全书)。地震的破坏性是一个远超过矩量级的更复杂的函数,如震源深度、持续时间和震源机制;然而,在这里,我只是把一个相当简单的 6 级矩作为破坏性的阈值。地震的分布严格遵循著名的古腾堡-里克特幂律分布(log(N) = a-bM,其中 N 和 M 分别是频率和震级。a 和 b 是常数。).由于力矩大小以对数单位表示,图 2 直方图的线性下降表明了这种分布。我不会详细描述这个发行版,因为这超出了这篇博文的范围。重要的一点是,尽管这种分布描述了地震发生的全球分布,但仅依靠这种统计分布进行危险分析是非常不安全的,原因如下:
“假设我们有一个大地震,比如 7 级地震,它不遵循这种分布(如 2004 年帕克菲尔德地震)。它只是一个数据点,不会扰乱幂律分布,因为它只是数千个数据点中的一个!但是,这是一个不容错过的致命数据点!
因此,更详细的统计分析将极大地有助于更好地理解地震现象。
洛马普列塔地震前 30 天发生了什么?
图 4:洛马普列塔主震前 30 天事件的地震图(图由叶图书馆创建)(图片由作者提供)。
为了理解是什么导致了主震,我们需要追溯导致主震的事件。如图 4 所示,在主要事件前 30 天有一个大规模的活动。事件倾向于沿西北-东南方向聚集,主要集中在圣安地列斯断层的上部和下部锁定区域(参见图 2)。最后,上部锁定区域导致了 6.9 级地震。有了初步的评估,我们现在可以尝试看看是否有任何位置系统。
位置和震级之间的相关性
**
图 5:整个数据集的 2D 直方图。上图:经纬度之间有明显的 NW-SE 向分带。下图:在深度约 10 公里处,似乎有大地震的聚集现象(图片由作者提供)。
为了更好地理解数据集,我评估了数据框架中变量之间的相关性。2D 直方图(图 5)显示,大部分地震发生在西北-东南方向,与某种线理大致对齐。此外,震级-深度分布表明,大地震发生在近 10 公里的深度。这表明,我们可以使用聚类技术来提出一些工程特征,并尝试看看它们是否有助于我们解决预测问题。
特征工程:空间聚类
图 6:随着地震群的发展,随时间的平移和转换。我们可以将这些变化作为地震预报的特征。
图 6 显示了开发这些特性的示意性概念。由于该图是自我描述的,所以我将不进行解释。我使用 DBSCAN 算法对从第一个数据点开始的每 20 次连续地震的事件进行聚类。我使用经度、纬度和深度进行三维聚类。作为聚类的结果,我们可以定义三个特征:
1-事件密度(或聚类的空间大小)。
2-纵横比(簇的 3D 形状)。
3 簇质心平移。
DBSCAN 的超参数为 eps = 0.2 和 min_samples=5]。
特征重要性
为了对已开发的特征进行初步评估,我只过滤了洛马普列塔大地震前的时序数据部分。我对每 20 行的数据进行平均,并将从空间聚类中获得的特征添加到原始 dataframe 列中。
最后,我添加了一个目标标签,作为洛马普列塔主震的时间(time_to_failure)。
下面是数据帧结构:
洛马普列塔地震的数据图表。目标标签是 time_to_failure 列。有关列的完整描述,请参见 GitHub repository。
运行单一回归分析以初步评估特征。请注意,这种回归只是为了探索的目的,作为未来的努力,结果需要在其他不同的测试地震数据集上进行交叉验证。下面的相关图(图 7)显示,这些特征实际上是主震时间的强有力指标。
图 7:特征和目标标签之间的关联(失效时间)。可以看出,这些是故障时间的强有力指标。请参见 GitHub repository 以获得对专栏的完整描述(图片由作者提供)。
图 8 中的特性重要性图显示了有趣的含义。dept_std、long_std 和 lat_std 表示群集的纵横比。这意味着离故障越近,集群越倾向于在垂直和纵向上拉长,而在纬度上拉长得越少。这些是最强的特征。此外,密度是负相关的,这意味着集群的大小在故障之前会扩大。另一个有趣的方面是地震的平均震级,这是一个奇怪的例子。对其他几次地震数据集的检查也显示了这一趋势。这意味着在大地震发生之前,地震的平均震级实际上是下降的。换句话说,断层变得更加平静。这是一个奇怪的案例,需要进一步研究。
图 8:基于洛马普列塔地震线性回归的特征重要性。特征在正文中被讨论。请参阅 GitHub repositopry 以获取列的完整描述(图片由作者提供)。
未来的工作
这是我对这个数据集进行时间序列分析之旅的开始。至此,我想用几句话来结束这篇博文,并为以后的帖子留下更详细的描述。在这里,我进行了初步的 EDA 分析,并建议了一些基于空间聚类的工程特性。这些特征似乎描述了主震发生的时间。
在以后的文章中,我将使用开发的特性,特别是聚类特性来执行更高级的时间序列分析。基于早期的评估,我发现 LSTM 是适合我的目的的方法。两个方面引起了我对 LSTM 序列分析的兴趣:1——我的时间序列的不规则性。2 —没有明显前兆的地震的类似休克的性质。
敬请关注…
感谢你阅读我的博文。对更多阅读感兴趣?请查看我的 LinkedIn 和 GitHub 简介。
使用 Python 获取股票数据的最简单指南
我最近在大学里完成了一门数据科学的入门课程,对于我的期末项目,我决定我要研究股票市场数据。我想把我的重点放在算法交易上,需要一种快速简单的方法来收集股票数据,这种方法很容易使用。
我偶然发现了一个名为 yfinance 的库,它让我的项目变得简单多了!
我强烈建议通读文档。这是一个快速阅读,将有助于你任何涉及股票数据的项目。
在我们开始之前,我们需要安装 yfinance 库。为此,只需将以下内容复制到您的命令提示符中:
$ pip install yfinance
现在我们准备开始分析我们的股票市场数据。对于我的项目,我选择了 SPDR 的 P 500 ETF 信托基金,其股票代码为间谍。您可以使用任何您想要的股票代码,但是在本文中我将使用 SPY。
入门指南
幸运的是,yfinance 使得提取我们的数据并快速开始分析它变得极其容易。我们可以从导入 yfinance 开始,使用.download()
函数下载我们选择的任何股票代码的历史数据。然后,我们可以通过调用.head()
函数返回前 5 行数据来快速查看我们的数据。
import yfinance as yfSPY = yf.download('SPY')
SPY.head()
我们的股票数据在 Pandas 数据框架中得到了很好的格式化。例如,如果您只想查看数据集中的收盘价,这就很容易了。
SPY['Close']
也可以只下载特定日期范围内的数据。这将需要我们使用 yfinance 的 Ticker 模块,它允许我们使用 yfinance 做更多的事情。一旦这样做了,我们就可以使用.history()
功能来处理所有的股票数据,或者某个时间段内的数据。假设我们想要 2020 年 1 月初至 2020 年 2 月初的数据。
SPY = yf.Ticker('SPY')SPY_History = SPY.history(start="2020-01-01", end="2020-02-01")
SPY_History.head()
现在我们已经使用了 Ticker 模块,我们可以调用.info
来查看我们的数据的更详细的摘要。这将返回一个包含 100 个键的字典。
SPY.info
数据真多啊!我们也可以在字典中查看单个键。例如,如果我们想要查看当前 50 天的平均值,我们可以写:
SPY.info['fiftyDayAverage']
查看多个股票代码也同样简单。我们可以再次使用.download()
函数,并用空格分隔每个股票代码。然后,我们可以查看数据中的最后 5 行,以检查它是如何格式化的。
data = yf.download('SPY AAPL')
data.tail()
为了快速可视化我们的数据,我们可以使用 matplotlib 编写一行程序来比较 SPY 和 AAPL。
import matplotlib.pyplot as pltdata['Close'].plot(figsize=(10, 5))
对于任何需要快速、轻松地收集股票数据的人来说,【yfinance】是一个很好的选择,也是迄今为止使用 Python 获取股票市场数据最简单的方法之一!
轻松为您的手机创建人工智能应用程序—零编码体验
图片来自皇家菲尔德网站
我用可教机器和 P5JS 创建了一个简单的 AI webapp。当我用手机摄像头指向我的摩托车皇家恩菲尔德经典 350 时,这款应用程序显示了它们的每个部件的名称。下面是同样的视频:
Fabin Rasheed 的视频
在网上分享这个视频让许多朋友好奇这是如何工作的,我想我会写一个关于这个的教程。
这可以在 3 个较大的步骤中完成,并且需要非常非常少的编码。事实上,任何人都可以通过笔记本电脑、智能手机和 wifi 连接做到这一点。我将尝试用现有的教程视频解释第一步,并详细解释第二步和最后一步。好的,我们开始吧。
步骤 1:使用可示教机器(TM)
可教机器是一个漂亮的工具,可以用来进行基于人工智能的实验,如图像分类、声音分类等。你可以用它来分类你的蔬菜,创建一个应用程序来教你的孩子不同的形状等等。
从可教机器开始非常简单直观。不过,以下是可教机器“入门”系列的视频,帮助您入门。(这里就不细说 TM 怎么用了。)
采集样本:https://youtu.be/DFBbSTvtpy4
训练你的模型:https://youtu.be/CO67EQ0ZWgA
出口型号:https://youtu.be/n-zeeRLBgd0
练习到这里,慢慢适应 TM。然后,我们可以继续创建移动网络应用程序。
第二步:为应用程序创建数据
因此,可示教机器目前仅适用于台式机。但是这种实现也将其扩展到了移动电话。第一步是收集图像。
我所做的是:
- 用我的手机为自行车的每个部分录制了一段视频。
- 然后使用 Adobe Media Encoder 将视频转换成帧(图像)(你也可以试试这个)。每个部分的图像被放在不同的文件夹中。(所以有一个文件夹存放“油箱”图片,另一个文件夹存放“发动机”图片)
每个部分的图片在一个单独的文件夹中(图片由 Fabin Rasheed 提供)
3.这些文件夹随后被用作可示教机器的输入。(点击上传按钮,而不是网络摄像头按钮)
每堂课有将近 700 张图片。例如,此处显示的样本较少。(图片来自可示教机器)
4.然后对模型进行训练。
第三步:制作 app
好了,现在开始在智能手机中设置 webapp 的部分:
1.前往 https://github.com/nurecas/visualmanual点击克隆/下载——下载 Zip。(如果您还没有 Github 帐户,可能需要创建一个)。将其提取到一个文件夹中,最好是在桌面中,将文件夹重命名为 RoyalEnfield。
2.在括号、MS visual studio、记事本等文本编辑器中打开文件夹内的 RoyalEnfield.js。
3.现在打开你的可教机器实验,按“导出模型”。
4.现在在 Tensorflow.js 下,你会发现“上传我的模型”。点击那个。
来自可示教机器的图像
5.上传完成后,复制生成的链接。
6.使用 RoyalEnfield.js 打开文本编辑器。在第 4 行中,替换 URL,即,
变化
let imageModelURL = ‘[https://teachablemachine.withgoogle.com/models/s379EsNn/](https://teachablemachine.withgoogle.com/models/s379EsNn/)';
随着
let imageModelURL = ‘**the URL you just copied**’;
7.保存文件。
8.如果您使用的是 Mac,请打开终端(CMD+Space,键入终端)。
如果您在 Windows 中,打开命令提示符(在这种情况下,您可能需要安装 python )
9.使用“cd”命令更改您提取的文件夹的路径。例如,如果您在桌面中,请键入:
cd Desktop/RoyalEnfield/
10.键入以下命令启动本地服务器(这适用于 MacOS Catalina 或最新的 Windows 版本):
python -m http.server 8013
如果这不起作用,并且您有较旧的操作系统,请键入以下内容:
python -m SimpleHTTPServer 8013
如果你能创建一个 HTTPS 服务器而不是 HTTP 服务器,那是强烈推荐的。这里的步骤创建了一个简单的 HTTP 服务器,应该只用于测试/原型/实验>
11.服务器启动后,测试您电脑中的浏览器是否一切正常:
在浏览器的地址栏中输入 localhost:8013 并按回车键。如果一切顺利,继续。
12.现在你需要找到你的计算机的本地 IP 地址。这可以通过点击 Mac 顶部的 WiFi 图标并选择“打开网络偏好设置”来找到。你会看到“WiFi 连接* * * IP 地址是 x.y.z.a”。记下这个数字 IP 地址(x.y.z.a)
对于 Windows,检查此链接。
13.如果一切正常,那就把你的手机和 Mac 连上同一个 WiFi。
14.打开手机中的 Chrome,输入 chrome:flags ,然后按回车键。
15.搜索“不安全的来源被视为安全的”。在显示的文本框中输入您的 IP 地址和端口 8013。例如,如果您的 IP 地址是 192.168.23.3,请键入 http://192.168.23.3:8013 。
我知道这一步听起来令人毛骨悚然,但这一步必须完成,因为我们设置的服务器是 HTTP 服务器,而不是安全的 HTTPS 服务器。如果您通过其他方法创建了 HTTPS 服务器,您可以忽略这一步。>
图片来自谷歌浏览器
16.现在将禁用更改为启用。
< 请务必在玩完实验 > 后将其改回禁用状态
17.按重启键
18.好吧!我们已经走到了尽头。现在,在手机的网络浏览器中键入您的 IP +端口(例如http://192 . 168 . 23 . 3:8013/),然后按回车键。如果所有步骤都做对了,你就能让它工作了。
如果您看到黑屏,请再次尝试步骤 15–17。
我希望这能帮助你开始并运行一些简单的人工智能实验。如果你遇到任何问题,请随时在我的推特上给我留言:https://twitter.com/@fabinrasheed
所有的荣誉都归于可教机器和 P5JS 背后的神奇团队。
在 www.nurecas.com 跟随我的作品
谢谢:)
我与皇家恩菲尔德品牌没有关系,也不认可这个品牌。我喜欢这辆自行车,我只是想在这里展示智能手机中人工智能的一个用例。
使用 Metropolis-Hastings 轻松改进任何 GAN
无需在 TensorFlow 中进行额外培训即可创建更高保真度的样品
如何才能以尽可能少的工作来改进我们的 GAN?(图片来自 Pixabay )
从你的 GAN 得到可信的输出有困难吗?在本文中,我们将回顾最近对 GANs 的改进,该改进通过简单易用的 Tensorflow 2 实现来提高输出质量,让您自己的 Metropolis-Hastings GAN 起步!
关于报纸
2018 年末,优步工程发布了一篇题为“Metropolis-Hastings 生成对抗网络”(Turner 等人)的论文,其中作者介绍了一个简单的技巧,在 GAN 的不增加 GAN 的训练时间的情况下,提高了 GAN 的输出。如果你对 GANs 不是很熟悉,我建议在继续深入了解我们正在处理的模型之前,先阅读这篇文章。
来自“Metropolis-Hastings Generative Adversarial Networks”(2018,Turner 等人)的视频,展示了 MH 如何提高渐进式 gan 的输出
优步工作的基本前提是,通常在训练后被丢弃的鉴别器包含有价值的信息,用于确定哪些样本类似于真实的数据分布。作者提出了一种新颖的采样方案,其中使用 Metropolis-Hastings 从生成器的潜在空间中抽取样本,由鉴别器选择接受哪个生成的样本。
图 1:来自优步论文的 Metropolis-Hastings GAN 伪代码
这种方法的巧妙之处在于,它适用于任何 GAN 架构或损失函数,因为 MH-GAN 实际上只是一种训练后采样方法。在我们展示如何应用这种采样方法之前,让我们先训练一个 GAN 来使用它!
在 TensorFlow 2 中培训我们的 GAN
为了开始我们训练 MH-GAN 的旅程,我们首先要训练最小平方 GAN,因为它的稳定性和易于实现。如果你想了解更多关于 LS-GANs 的知识,我在文章底部提供了一个链接。对于数据,我们将使用 TensorFlow 中包含的时尚 MNIST 数据集,因此这些结果很容易在家中复制!
请注意,下面的一些训练代码改编自位于此处的官方 tensor flow DC-甘教程:
请注意,我们还使用了tensorflow-addons
包来实现一些更高级的功能,如 Ranger 优化器和 Mish 激活层,以平滑训练过程。
定义我们的生成器和鉴别器
训练我们的网络的下一步是定义我们的生成器和鉴别器对象,以馈入我们的 LS-GAN 类:
我们有一个基类来训练一个最小平方 GAN 以及一个生成器和鉴别器,现在是时候开始实现 MH-GAN 了!
大都会-黑斯廷斯算法
在实现 MH-GAN 时,我们需要了解的第一件事是 Metropolis-Hastings 算法。MH 是一种马尔可夫链蒙特卡罗方法,用于从难以直接采样的分布中进行采样。在这种情况下,我们试图从鉴别器隐含的真实数据分布中进行采样。
我们不会深入探讨 Metropolis-Hastings 背后的理论,但如果你想了解更多,我在本文底部提供了一个链接。
一旦我们有了一个经过训练的生成器和鉴别器,我们使用以下步骤来抽取遵循真实数据分布的样本(请随意参考上面的伪代码):
- 用真实的数据样本作为链的种子(作者这样做是为了避免 Metropolis-Hastings 带来的漫长磨合期)
- 对于 K 次迭代,我们从生成器中抽取一个随机样本,并从鉴别器中计算得分
- 在每次迭代中,如果以下表达式大于范围[0,1]中的随机数,则接受新样本并与下一次迭代进行比较:
图 2:MH-GAN 中接受新样品的条件(摘自优步 MH-GAN 论文)
本质上,该规则所做的是比较建议样本的鉴别器分数与当前样本分数的比率,以确定我们是否应该“接受”新样本。通过足够的迭代,我们的独立链将近似我们的鉴别器输出所暗示的真实数据分布!
如果我们在一定次数的迭代后无法接受任何样本,作者建议从合成样本重新开始链以保证收敛,尽管速度较慢。
****然而这并不是故事的结尾,因为我们的鉴频器的输出还有一个悬而未决的问题,我们将在下一节解决这个问题。
校准我们的鉴别器
在应用 Metropolis-Hastings 时所做的一个假设是,我们的鉴别器的概率是校准好的。这意味着鉴别器输出必须被解释为置信水平。不幸的是,神经网络分类器的原始输出几乎从未被很好地校准过,这意味着我们必须应用额外的步骤来校准输出。即使我们在最后一层使用 sigmoid 或 softmax 激活,也是如此!****
Scikit-Learn 文档中有很大一部分是关于校准的这里是,但是论文作者推荐的是使用一种称为保序回归的技术将网络输出转换为校准的概率,作为后处理步骤。不幸的是,这需要在一个固定的集合中完成,这意味着我们必须将我们的时尚 MNIST 分成一个训练和验证集合(幸运的是 Tensorflow 为我们做到了这一点!)
下面是一个校准曲线(一个说明模型校准的诊断工具,45 度线代表完美的校准),显示了我们的等张预测如何满足 Metropolis-Hastings 条件。另一方面,我们的原始输出显然没有校准好。
图 3:校准曲线显示对鉴频器输出应用保序回归后的改善
一旦我们校准了鉴别器,我们就可以使用校准的概率来确定我们上面概述的独立 MCMC 链中新样本的接受概率!
编码我们的 MH-GAN
现在,终于到了用我们上面编码的 LS-GAN 的子类进行校准和 Metropolis-Hastings 采样的时候了。请注意,我们可以很容易地将这个子类应用于遵循我们上面概述的 API 的任何其他种类的 GAN,甚至可以使它适应现有的 GAN 包。
请注意,这里有几件事情要做,首先我们需要实现一种方法来训练我们的校准器以及一种校准的评分方法。
为了训练校准器,我们只需拿出一组样本,从生成器中生成相同数量的样本。接下来,我们训练 Scikit-Learn 中的 IsotonicRegression 类,将鉴别器分数转换成真实概率。
最后,我们有我们的generate_mh_samples()
方法,它生成指定数量的接受样本,给出一个真实的例子来播种 MCMC 链。你能在这里看到一个共同的主题吗?校准后的评分和 MH 样品生成方法与 LS-GAN 的score_samples()
和generate_samples()
方法完全相同!
是时候使用时尚 MNIST 的数据来体验这个新的课程了!
比较结果
为了开始使用我们闪亮的新 MH-GAN 类,我们必须做的第一件事是加载我们的时尚 MNIST 数据,并将其分成我们的训练和验证集,以及归一化像素。好在 tf.keras 让这个超级容易!
既然我们已经有了训练集和测试集,我们要做的就是用上面声明的生成器和鉴别器初始化我们的MHGAN
对象,以及生成器和优化器学习率的噪声维度。然后,我们将训练 50 个历元(这是相当随意的,通常这需要对 GANs 进行更多的考虑),最后校准我们的鉴别器。我们的面向对象方法允许我们用 3 行代码就可以做到这一点!
训练完成后,我们可以通过使用正常的朴素 GAN 采样或优步论文中的 Metropolis-Hastings 算法,从我们训练的 MH-GAN 中提取样本。
让我们来看看使用 LS-GAN、MH-GAN 生成的 15 幅图像,以及一些真实图像进行比较:
图 4:LS-GAN 和 MH-GAN 输出与时尚 MNIST 数据集真实样本的比较
****哇!我们可以肯定地看到,MH-GAN 几乎完全避免了样品明显造假的问题!这一发现与优步团队的发现一致,他们在 CelebA 数据集上报告说,他们的方法大大减少了低保真度图像的数量。我们可以看到来自 LS-GAN 的样本实例看起来就像不明确的斑点,而这在我们的 MH-GAN 中发生的频率要低得多。
该团队还认为,它解决了模式崩溃问题,但在我对他们的方法的试验中,我并没有真正看到这种情况发生,但 MNIST 和时尚-MNIST 并不总是算法性能的最佳指标,这不是一个问题。
结论
如果你对我们在本文中展示的 GAN 的快速改进感兴趣,我强烈推荐阅读下面链接的 MH-GAN 原文!此外,我们已经展示了 TensorFlow 2 使应用这种技术变得极其容易,只需要很少的额外代码!
关于基于鉴频器的 GAN 采样,还有许多其他有趣的论文,如 Azadi 等人的“鉴频器抑制采样”和 Che 等人的“您的 GAN 实际上是一个基于能量的模型,您应该使用鉴频器驱动的潜在采样”,显示了该领域的前景。毫无疑问,看看未来几年这种趋势会变得有趣。
如果你对这篇文章有任何问题或意见,请不吝发表在下面!
参考资料和资源
链接到优步最初的 MH-GAN 论文:
**[## Metropolis-Hastings 生成对抗网络
我们介绍了 Metropolis-Hastings 生成对抗网络(MH-GAN ),它结合了马尔可夫链的各个方面
arxiv.org](https://arxiv.org/abs/1811.11357)**
优步工程公司关于 MH-GANS 的原始网站文章:
** [## 如何免费获得更好的 GAN:介绍大都会-黑斯廷斯 GAN
生成对抗网络在真实感图像生成和图像修复方面取得了令人瞩目的成就
eng.uber.com](https://eng.uber.com/mh-gan/)
一篇关于最小二乘 GAN 的有用文章
感谢 F-GAN,它建立了 GAN 训练的一般框架,最近我们看到了 GAN 的修改…
wiseodd.github.io](https://wiseodd.github.io/techblog/2017/03/02/least-squares-gan/)
Metropolis-Hastings 采样快速指南:
[## 从零开始:贝叶斯推理,马尔可夫链蒙特卡罗和大都会黑斯廷斯,用 python 编写
0-我的第一篇文章
towardsdatascience.com](/from-scratch-bayesian-inference-markov-chain-monte-carlo-and-metropolis-hastings-in-python-ef21a29e25a)**
轻松可视化 Scikit-learn 模型的决策界限
一个简单的效用函数来可视化 Scikit-learn 机器学习模型/估计器的决策边界。
图片来源: Pixabay(免费授权)
介绍
Scikit-learn 是一个令人惊叹的 Python 库,用于工作和试验过多的监督和非监督机器学习(ML)算法和相关工具。
它的构建考虑到了健壮性和速度——尽可能多地使用 NumPy 和 SciPy 方法和内存优化技术。最重要的是,该库为所有类型的 ML 估计器提供了一个简单而直观的 API(T10)——拟合数据、预测和检查模型参数。
图像:Scikit-learn 估计器图示
对于监督最大似然领域中的许多分类问题,我们可能希望超越数值预测(类别或概率)并可视化类别之间的实际决策边界。当然,这尤其适用于二元分类问题和一对要素,可视化显示在二维(2D)平面上。
例如,这是来自 Scikit-learn 官方文档的支持向量机(SVM)教程的决策边界的可视化。
图片来源: Scikit-learn SVM
虽然 Scikit-learn 没有提供现成的、可访问的方法来实现这种可视化,但在本文中,我们将研究一段简单的 Python 代码来实现这一点。
一个简单的 Python 函数
完整代码在我的 Python 机器学习上的 Github Repo 这里给出 。当然也欢迎你到探索整个库寻找其他有用的 ML 教程。
这里,我们展示了 docstring 来说明如何使用它,
实用函数的文档字符串
您可以将模型类和模型参数(对于每个模型类是特定且唯一的)以及要素和标签数据(作为 NumPy 数组)传递给函数。
这里的模型类表示精确的 Scikit-learn 估计器类 ,您在中调用它来实例化您的 ML 估计器对象。请注意,您不必传递您正在使用的特定 ML 估计器。只有类名就足够了。该函数将在内部拟合数据并预测以创建适当的决策边界(考虑您传递的模型参数)。
目前,函数仅使用前两列数据来拟合模型,因为我们需要找到网格样式散点图中每个点的预测值。
主代码部分
一些说明性结果
代码很无聊,而结果(和情节)很刺激,不是吗?
为了演示,我们使用了离婚分类数据集。这个数据集是关于完成个人信息表和离婚预测量表的参与者。该数据是在 UCI 门户上公开的数据的修改版本(在注入一些噪声之后)。有 170 个参与者和 54 个属性(或预测变量)都是实值。
我们在同一个数据集上比较了多个最大似然估计的性能,
- 朴素贝叶斯
- 逻辑回归
- k-最近邻(KNN)
因为这个特定数据集的二进制类是相当容易分离的,所以所有的 ML 算法表现几乎一样好。然而,它们各自的决策边界看起来彼此不同,这就是我们感兴趣的通过这个效用函数可视化。
图片:离婚预测数据集的类别可分性
朴素贝叶斯决策边界
来自朴素贝叶斯算法的决策边界是平滑的,并且略微非线性。而且,只有四行代码!
逻辑回归决策边界
正如预期的那样,来自逻辑回归估计器的决策边界被可视化为线性分隔符。
k-最近邻(KNN)决策边界
k-最近邻是一种基于特征超平面上数据分布的局部几何(以及它们的相对距离度量)的算法。因此,决策边界表现为非线性和不平滑的。
你甚至可以通过神经网络分类器
该函数适用于任何 Scikit-learn 估计器,甚至神经网络。这里是 Scikit-learn 的MLPClassifier
估计器的决策边界,它模拟一个密集连接的神经网络(具有用户可配置的参数)。注意,在代码中,我们传递了隐藏层设置、学习率和优化器(随机梯度下降或 SGD)。
检查模型参数的影响
如前所述,我们可以将我们想要的任何模型参数传递给效用函数。在 KNN 分类器的情况下,随着我们增加相邻数据点的数量,决策边界变得更加平滑。使用我们的效用函数,可以很容易地看到这一点。注意,在下面的代码中,我们如何在一个循环中将变量k
传递给n_neighbors
模型参数。
摘要
我们展示了如何编写一个简单的效用函数来接受任何 Scikit-learn ML 估计器(具有用户希望传递给模型的任何模型参数),用于二进制分类任务,并使用几行代码可视化正类和负类之间的判定边界。
该函数可与任何 Scikit-learn 估计器配合使用,并且可扩展和配置,以便在将来包含更多的类和多绘图功能。
再次说明,我在 Python 机器学习上的 Github Repo 里这里给出了 完整代码 。将根据需要添加更新。
如果您有任何问题或想法要分享,请联系作者在tirthajyoti【AT】Gmail . com。此外,您可以查看作者的 GitHub 资源库中的代码、想法和机器学习和数据科学方面的资源。如果你和我一样,对人工智能/机器学习/数据科学充满热情,请随时在 LinkedIn 上添加我或在 Twitter 上关注我。
[## Tirthajyoti Sarkar - Sr .首席工程师-半导体、人工智能、机器学习- ON…
通过写作使数据科学/ML 概念易于理解:https://medium.com/@tirthajyoti 开源和有趣…
www.linkedin.com](https://www.linkedin.com/in/tirthajyoti-sarkar-2127aa7/)
轻松访问世界上最大的数据源
Python 的维基百科 API
数据的重要性远高于在数据科学中构建最先进的算法。如果没有合适的大量数据,我们就无法很好地训练模型,以获得令人满意的结果。
作为世界上最大的百科全书,维基百科可以作为许多项目的巨大数据源。有许多网络抓取工具和框架允许从维基百科获取数据。然而,Python 的 Wikipedia API 可能是最简单易用的。
在本帖中,我们将看到如何使用维基百科 API 来:
- 访问特定页面的内容
- 搜索页面
您可以轻松地安装和导入它。我将使用谷歌 Colab,所以这里是它是如何在 Colab 中完成的:
pip install wikipedia
import wikipedia
页面的内容可以用 page 方法提取。页面的标题作为参数传递。以下代码将支持向量机页面作为 WikipediaPage 对象返回。
page_svm = wikipedia.page("Support vector machine")type(page_svm)
wikipedia.wikipedia.WikipediaPage
这个对象保存了可以通过 url 方法访问的页面的 URL。
page_svm.url[https://en.wikipedia.org/wiki/Support_vector_machine](https://en.wikipedia.org/wiki/Support_vector_machine)
我们可以用 content 方法访问页面的内容。
svm_content = page_svm.contenttype(svm_content)
str
内容以字符串形式返回。以下是 svm_content 字符串的前 1000 个字符。
返回的内容是一个字符串,这不是分析的最佳格式。我们可以处理这个原始字符串来推断有意义的结果。有一些高效的自然语言处理(NLP)库可以处理文本数据,比如 NLTK、BERT 等等。
我们不会详细讨论 NLP 任务,但让我们做一个简单的操作。我们可以将内容字符串转换成 python 列表,该列表将单词作为单独的元素包含在内。然后我们可以计算一个特定单词出现的次数。
content_lst = svm_content.split(" ")len(content_lst)
57779content_lst.count("supervised")
4
title 方法用于访问页面的标题。
references 方法返回页面上使用的引用列表。本页的前 5 个参考如下:
同样,我们也可以提取页面上图像的链接:
我们心里并不总是有一个确切的标题。假设我们正在寻找标题中包含“心理学”一词的页面。这可以通过搜索方法来完成。
在某些情况下,返回的列表太长,所以我们可能希望限制返回的项目。只需将所需的项目数传递给结果参数。
注:除非另有说明,所有图片均由作者创作。
编辑:感谢尼克·韦伯指出这一点。Wikipedia API 的创建者明确声明“这个库是为了易用性和简单性而设计的,而不是为了高级用途。如果您计划执行重要的抓取或自动请求,请使用 Pywikipediabot(或其他更高级的 Python MediaWiki API 包装器之一),它具有更大的 API、速率限制和其他功能,因此我们可以考虑 MediaWiki 基础架构。”
结论
维基百科是一个非常有价值的数据来源。它提供了对许多主题的结构化信息的访问,并作为机器学习和深度学习任务的数据源。例如,这些数据可以用来训练复杂的 NLP 模型。
维基百科 API 使得访问和使用这个巨大的数据源变得非常容易和简单。
感谢您的阅读。如果您有任何反馈,请告诉我。
用于机器学习模型的简单自动化特征工程
自动化模型开发的痛苦部分
照片由 Goh Rhy Yan 在 Unsplash 上拍摄
作为一名数据科学家,我们知道处理数据是我们的日常活动。从拉数据,分析数据,创建一个有用的机器学习模型。
虽然许多人认为创建机器学习模型很容易,但事实并非如此。人们可能认为我们只需要输入一些编码语言,瞧!机器学习模型做好了。
它可能是这样工作的,但是这个模型有用吗,对业务问题有什么影响吗?大部分时间可能不是。这是因为现实生活中的数据是杂乱的,如果没有适当的测量,它将导致一个有缺陷的模型。
提高机器学习模型性能的一种行之有效的方法是从现有特征或特征工程中创建新特征。
特征工程的概念很容易理解,因为这个想法是关于从现有的特征中创建新的特征。例如,我们有产品价格及其重量的数据。
从这两个特性中,我们可以创建一个新的特性。比方说每克的产品价格。在这种情况下,我们需要将价格除以产品重量。
就这样,我们得到了一个新的特性。这就是特征工程的概念。
机器学习模型的核心是数据,提高性能的方法是通过特征工程,尽管掌握特征工程需要很多技能。我们需要有创造力,了解商业领域。这肯定要花很多时间。
为了解决特征工程问题的局部部分,我们可以自动化时间任务特征工程过程。
自动化特征工程
用于执行自动化特征工程的主要开源库之一是 Featuretools 。它是一个库,旨在通过自动化过程来加快特征生成过程。
在 Featuretools 中,有三个我们应该知道的包的主要组件。它们是:
- 实体
- 深度特征综合(DFS)
- 特征基元
解释在下面的文章中。
- 实体是 Featuretools 中熊猫数据框的表示。多个实体被称为一个实体集。
- 深度特征合成 (DFS)是 Featuretools 中的一种特征工程方法。这是用于从单个和多个数据框创建新要素的方法。
- DFS 通过将特征原语应用于 EntitySet 中的实体关系来创建特征。特征基元是我们称之为手动生成特征的方法,例如,基元平均值是聚合级别的变量的平均值。
这是足够的理论;我们可能会直接跳到工具的实际用途。为了做好准备,我们需要先安装库。
pip install featuretools
现在,Featuretools 最适合用于具有许多关系的多个数据集。在这种情况下,我会使用来自 Kaggle 的 Olist Brazallian 电子商务数据集。
数据在 CSV 文件中,由许多数据组成。在这种情况下,我会选择一些数据作为例子。
olist_items = pd.read_csv('olist_order_items_dataset.csv')
olist_product = pd.read_csv('olist_products_dataset.csv')
olist_customer = pd.read_csv('olist_customers_dataset.csv')
olist_order = pd.read_csv('olist_orders_dataset.csv')
我们简单看一下数据。首先,我们来看看 olist_customer 数据。
我们可以看到数据包含一个唯一的变量作为标识,名为“customer_id”。当我们想使用 Featuretools 时,这个变量是必要的,因为特征工程的实体将使用这个唯一的变量作为分组指示符。
让我们看看 olist_order 数据。
我们可以看到,olist_order 数据包含“order_id”变量作为标识,还包含“customer_id”变量来指示是谁下的订单。
对于最后一个,我需要产品的数据和商品的订单号,但是因为它分散在两个数据集中,所以我将它合并成一个。我还会删除一些我们不需要的功能,并为标识重置索引。
olist_item_product = pd.merge(olist_items, olist_product, on = 'product_id')olist_item_product.drop(['order_item_id', 'seller_id'], axis =1, inplace = True)olist_item_product.reset_index(inplace = True)
现在我们有了所有需要的数据集。让我们尝试使用 Featuretools 来实现特征工程的自动化。
首先,我们需要准备的是执行 DFS 的实体。那么,我们到底需要在实体中准备些什么呢?正如我之前提到的,实体是一种数据框表示。在实体的情况下,我们将准备一个包含实体名称和带有标识的数据帧的字典。
实体的例子解释如下。
#We prepare the dictionary with the specification is
#'name of the entity' : (dataframe, identification)entities = {
"customer" : (olist_customer, 'customer_id'),
"order": (olist_order, 'order_id'),
'item_product':(olist_item_product, 'index')
}
接下来,我们需要指定实体之间的关系。当两个实体存在一对多关系时,我们称“一”实体为“父实体”,“多”实体为“子实体”。父子关系是这样定义的。
#The relationship are defined by the entitiy name and the variable identification
(parent_entity, parent_variable, child_entity, child_variable)#Example
relationships = [
('customer', 'customer_id', 'order', 'customer_id'),
('order', 'order_id', 'item_product', 'order_id')
]
在上面的例子中,我用“customer_id”变量定义了“customer”实体和“order”实体之间的关系,这两个变量存在于两个数据集中。
现在是自动化特征工程的时候了。这很容易做到;你只需要按照下面的线。请注意,这个过程需要一些时间,因为数据集非常大。
import featuretools as ftfeature_matrix_customers, features_defs = ft.dfs(
entities=entities, relationships=relationships,
target_entity="customer")
从上面的代码,我会解释一下。正如我之前解释的,创建自动化的方法是 DFS。在这种情况下,DFS 方法主要接受三个参数。它们是:
- 实体
- 人际关系
- 实体目标
前两个参数是我们之前创建的,最后一个“实体目标”是聚合的分组。在下面的例子中,假设我们想要基于客户级别的特征工程。
流程完成后,我们可以看到,我们最终获得了许多基于客户聚合的新特性。
feature_matrix_customers.columns
正如我们在上面的图片中看到的,由于自动化特征工程,我们现在有 410 个特征。
如果你对如何阅读一些列名感到好奇,我可以解释一下。以 SUM(item_product.price)为例。此列表示它是 item_product 实体的价格与客户聚合级别的总和。所以,用一个更人性化的术语来说,就是顾客所购买的商品的总价。
下一步,当然是用我们刚刚产生的数据开发机器学习模型。虽然我们已经创建了这个功能,但它是否有用还需要更多的实验。重要的是,我们成功地自动化了模型开发的耗时方面。
结论
特征工程是开发机器学习模型的一个重要方面,因为它正在影响我们的机器学习模型。然而,这个过程可能需要很长时间。
在这种情况下,我们可以使用名为 Featuretools 的开源库来自动化我们的功能工程过程。
Featuretools 中我们需要记住的三个术语是实体、深度特征合成、特征基元。
如果你想了解更多关于 Featuretools 的信息,你可以访问主页这里。
希望有帮助!
如果你喜欢我的内容,并想获得更多关于数据或作为数据科学家的日常生活的深入知识,请考虑在这里订阅我的时事通讯。
如果您没有订阅为中等会员,请考虑通过我的推荐订阅。
易于操作的开发环境
像越来越多的工程师一样,数据科学家正在向码头工人 T2 转移。这个框架将资源和应用程序从全球系统中分离出来,有助于更好的可复制性,从而解决了软件安装和部署过程中的一些问题。
虽然它主要用于部署独立的应用程序,但是我们可以通过一种稍微派生的方式来利用这种技术来构建轻量级和可移植的开发环境。
随着越来越多不同的工具和库,有时很难知道我们的工作站中安装了什么,以及如何轻松地管理所有这些东西。每个人都遇到过仅仅为了安装一个特定的 Python 库或 Bash 实用程序而进行几个小时的调试。
如果你想了解更多关于 Docker 技术的细节,在 Medium 这里已经有很多好的资源 。
带码头的移动实验室
当我收到最后一台笔记本电脑时,我没有在全局系统安装上安装任何库或代码实用程序。相反,我将许多日常工作转移到 Docker 容器中。
这种工作流程有很多优点:
- 您可以安装和测试库,而不用担心会破坏您的全局系统。全部隔离在容器中。
- 由于 Dockerfiles(在 Git 中跟踪),您可以跟踪不同的工作区以及它们是如何发展的。
- 您可以在任何计算机上运行您的任何工作区。只需要安装 Docker(这非常简单)。
- 您可以共享工作区。您的任何项目都可以在朋友的电脑上运行。
好的,听起来不错。安装或升级库时,我们将不再害怕。在任何地方运行项目的可能性是非常令人兴奋的,由于 Git,获得所有历史变更将节省时间。
尽管如此,还是有一点缺点:您必须编写很长的命令才能启动这些容器
在 Docker 容器中运行 Jupyter 记事本的 Docker 命令示例。
我们总是想要快捷简单的工具
为了解决这个问题,我首先想到了 docker-compose 。这个工具对于定义和运行多容器 Docker 应用程序非常有用。它可以将复杂的运行操作恢复成简单的docker-compose up
命令。
然而,这不是我们在我们的环境中使用的工具,至少有两个原因:
首先,您必须在包含docker-compose.yml
的文件夹中运行 docker-compose 命令,或者提供相当长的完整 docker 文件路径。这并不像我们习惯的那样,仅仅在你的控制台中输入jupyter-notebook
或者启动 Rstudio 应用程序那么简单。
其次,你得安装 docker-compose。好了,这还不是最难的。但是在安装工作空间时,您仍然需要添加这个层。
所以我问自己,在大多数 Unix 系统上,默认的工具是什么?简单回答:Bash。
行动诞生了。
操作:Docker 环境支持 Bash。
这个工具非常简单。事实上,它只是 docker 容器运行命令到 shell 脚本中简单表达式的映射。
环境——或“操作”——由一个docker 文件和一个配置文件定义。后者用于指定容器运行命令和所有需要的参数,如卷、环境变量等
Jupyter 笔记本操作后面的配置文件。
映射被解释成一个简单的 shell 脚本。我们可以用一个简单的operation briefing
构建所有的 Docker 图像。
然后,不用运行长 Docker 命令来运行 Jupyter 笔记本,只需键入operation jupyter
。
操作被设计得非常简单,它不是一个革命性的工具,只是一个小的附带项目。目标是能够运行单个应用程序或开发工具,而不用担心系统依赖性和安装。
当在一个更复杂的项目中工作时,我更喜欢在项目中建立 docker 文件甚至 docker-compose 文件,而不是在操作中构建它。这对项目的可重复性更好。
由于我主要使用 Python 和 R,我开始构建像 IPython 或浏览器内 Rstudio 环境这样的“操作”。我还利用这个解决方案设置了一些任务,虽然我不是每天都做,但是这些任务非常有用,比如 CSV 文件转换、图像旋转或日期时间操作。
这些小工具可以安装在我的全球系统上。它们不需要太多的依赖。尽管如此,我还是希望能够使用它们而完全不用担心我的系统配置,并且当我换到另一个工作站时能够快速找到它们。
有了手术,我手头就有了。
背后的故事
这个想法并不新鲜。杰西·弗雷泽勒,前 Docker-Google-微软工程师已经有了一个完整的 Docker 文件库来运行独立的桌面应用。我鼓励你去看相应的博文。
读了汤姆·克兰西的书后,我想到了“手术”这个名字。像军事行动一样,Docker 容器被定义、操作,然后分类。为了实现这个想法,我甚至添加了“秘密”行动的别名。例如,您可以启动运行operation ipython
或operation rattlesnake
的 IPython 控制台。
这个锁定也让我学习了一些关于 3D 建模和 Blender 渲染的知识。围绕码头鲸创作了一些艺术品。了解有关具体行为项目的更多信息。
https://www.behance.net/gallery/95156933/Operation
未来的发展
我利用锁定开始这个小项目,并提高我的 Bash 技能。由于我们过去面对许多新的工具和环境,它可能会定期更新。可以进行许多改进,例如:
- 优化图像定义并遵循 Docker 的良好实践。
- 更好的安装过程(apt-获得支持?).
- 潜在的卷“安全性”和授权违规。
- 改进文档。
- 添加操作“优先级”以快速构建特定的 Docker 映像。
- 比 Bash 更好的 CLI,无需使用任何其他工具。
目前每个操作都非常接近我的个人喜好。如果你想添加你自己的操作:添加你的 Dockerfile 并填充一个config.yml
文件,你就准备好了。
你有改进的想法吗?认为应该创造一些新的环境?你可以在 Github 上找到这个库。不要犹豫,添加问题或创建合并请求,在下面添加评论,或在 Twitter 上与我联系。我将很高兴收到你的来信。
红移性能的简单修复
由 Ricardo Gomez Angel 在 Unsplash 拍摄的照片
或者如何将自己从分布式数据库的糟糕查询中解救出来
edshift 很棒,直到它不再是那样。通常,当这种情况发生时,并不是红移的错。使用红移的人面临的最常见的问题之一是查询性能差和查询执行时间长。这可能很难理解,但大多数红移问题是显而易见的,因为人们只是习惯于查询关系数据库。虽然传统的 ACID 兼容关系数据库和 MPP 分布式关系数据库的外观是一样的,但是存储分布的基本原则完全改变了游戏。
与兼容 ACID 的关系数据库(如 MySQL、PostgreSQL 等)相比,红移的两个主要特点改变了一切。
- 底层存储 —列存储而不是基于行的存储
- 大规模并行处理架构——尽管在 MySQL、PostgreSQL 等中也是可能的。这也是红移的默认设置
现在,我们将列出一些快速修复方法和开始使用红移工作负载时需要记住的事项。如果你不了解红移,阅读下面的文档会很有帮助。
[## 影响查询性能的因素
许多因素都会影响查询性能。数据、集群和数据库操作的以下方面…
docs.aws.amazon.com](https://docs.aws.amazon.com/redshift/latest/dg/c-query-performance.html)
记住——红移中没有索引
与关系数据库不同,Redshift 不支持索引。不要编写与 MySQL 或 PostgreSQL 等关系数据库相同的查询。红移旨在当您选择您绝对最肯定需要查询的列时执行最佳——与您应该在基于行的数据库中SELECT
记录的方式相同,您需要在基于列的数据库中选择列。
没有索引?那么,如何有效地连接表呢?
关系数据库中的联接使用索引。正如我们刚刚确定的,红移中没有索引,那么您将使用什么?您将使用一个类似的探测结构来连接表。这种构造被称为分布键——一列数据基于它分布在红移星团的不同节点上。数据的分布方式由为给定表选择的分布样式定义。
[## 分发示例
AWS 文档中描述的 AWS 服务或功能可能因地区而异。要查看适用于…的差异
docs.amazonaws.cn](https://docs.amazonaws.cn/en_us/redshift/latest/dg/c_Distribution_examples.html)
统计的重要性
类似于任何其他数据库,如 MySQL,PostgreSQL 等。,Redshift 的查询规划器也使用关于表的统计信息。基于这些统计信息,当选择许多计划中的一个来执行查询时,查询计划决定采用哪种方法。这就是为什么时不时地去牌桌是个好习惯。没有一个好的频率来运行这个适合所有人。请注意ANALYZE
可能是一项耗时的活动。在决定频率之前,做一个快速的成本效益分析。
有一篇很棒的文章提到了我在这里谈到的一些事情。更多细节请参考。
Amazon Redshift 是一个数据仓库,可以快速、简单且经济高效地分析数 Pb 的数据…
www.intermix.io](https://www.intermix.io/blog/top-14-performance-tuning-techniques-for-amazon-redshift/#use_change_data_capture_cdc)
为您的列选择合适的压缩方式
列数据库的一个优点是可以实现高级别的压缩,因为大量同类数据是连续存储的,这意味着磁盘上的许多块包含相同数据类型的数据。这样不是更容易压缩吗!
对于基于行的数据库,一行中的所有数据都是连续存储的。这就是为什么减少扫描的行数更好。
因此,在基于行的数据库中很难进行压缩,因为一行可能包含不同数据类型的数据,这意味着磁盘上的相邻块可能具有不同的数据类型。
相同颜色的磁盘/内存块是连续的。图片来自维基共享资源(标记为重复使用)
[## 压缩编码
压缩编码指定在添加行时应用于数据值列的压缩类型…
docs.aws.amazon.com](https://docs.aws.amazon.com/redshift/latest/dg/c_Compression_encodings.html)
照顾好磁盘空间
管理磁盘空间通常是所有数据库的一个问题,尤其是当您处理分析负载时,因为分析师、数据工程师会创建大量的表以供进一步分析。即使事实并非如此,减少的可用空间也会严重影响查询性能,因为这会使查询执行引擎难以通过引发大量交换来在磁盘上创建临时内容。
如果您对磁盘空间没有任何控制,那么 Spectrum 中更灵活的选项更好—在这里,您实际上是将所有数据移动到 S3,它可以根据您的需要进行扩展,而不会因为增加磁盘空间而停机。
这些是你应该记住的一些基本的东西。你可以在 AWS 的文档中找到更多关于红移的想法。文档并不总是有用的。那时,你可以参考一些通过这篇文章分享的链接和下面的参考资料部分。
参考
如果你正在寻找红移的深入实用指南,没有什么比 Periscope 的这个更好的了。
这篇文章是一个案例研究,关于我们如何修复一些红移性能问题,我们开始运行,因为我们有更多的…
www.hudl.com](https://www.hudl.com/bits/the-low-hanging-fruit-of-redshift-performance) [## 亚马逊红移|亚马逊网络服务的十大性能调优技术
客户使用 Amazon Redshift 做各种事情,从加速现有的数据库环境,到摄取网络日志…
aws.amazon.com](https://aws.amazon.com/blogs/big-data/top-10-performance-tuning-techniques-for-amazon-redshift/) [## 查询 86.6 亿条记录 Starburst Presto 和…
如果您是应用程序所有者,迟早您会需要分析大量数据。好消息是什么?无论如何…
www.concurrencylabs.com](https://www.concurrencylabs.com/blog/starburst-presto-vs-aws-redshift/) [## 提高查询性能
以下是一些影响查询性能的常见问题,以及诊断和解决这些问题的方法说明…
docs.aws.amazon.com](https://docs.aws.amazon.com/redshift/latest/dg/query-performance-improvement-opportunities.html)
两个视频—
托尼·吉布斯的亚马逊红移最佳实践
通过真实使用案例对红移进行深入的回顾
SparkSQL 性能的简单修复
Emile Perron 在 Unsplash 上拍摄的照片
数据工程
针对 performant SparkSQL & PySpark 的快速简单的修复、最佳实践和检查
S park 是当今最流行的数据分析和工程工具之一。它拥有广泛的覆盖面和采用率,这促使主要的云提供商提供基于它的服务。有 Azure Databricks、AWS Glue 和 Google data proc——所有这些服务都在底层运行 Spark。Spark 受欢迎的原因之一是它同时支持 SQL 和 Python。对于独特的 RDD 特性,第一个 Spark 产品之后是 DataFrames API 和 SparkSQL API。从那以后,它统治了市场。
很多人在第一次尝试 Spark 时,都说 Spark 非常慢。这显然非常慢,因为他们不了解 Spark 的内部以最佳方式(甚至是足够好的方式)使用它。我写这篇文章是为了指出几个针对 SparkSQL 的快速修复方法,您可以在不深入 SparkSQL 内部的情况下使用它们。话虽如此,解决这个问题的最好方法是深入内部。但是在这里,我们将只讨论非性能 SparkSQL 问题的低挂果实。
查询任何传统关系数据库的经验法则
towardsdatascience.com](/easy-fixes-for-sql-queries-ff9d8867a617)
这是我的早期文章之一的延续,在那里我谈到了对任何关系数据库的 SQL 查询的快速和简单的修复。在某种程度上,许多相同的概念也适用于 SparkSQL 尽早过滤数据、正确过滤数据、高效分发数据、减少不对称等等。让我们继续讨论这些常见问题。
1.广播(广播加入)
就像数据库一样,Spark 的数据存储也有小文件和大文件。就像在传统的分布式数据仓库系统中一样,我们将维度表推送到集群的所有节点以避免混乱,我们在这里通过使用 SparkSQL 的广播特性来做同样的事情。Broadcast 做的完全一样——它提前将一个小表的所有数据复制到 worker 节点,以减少执行者之间的混乱。
减少执行人之间的推诿
我们可以指定提示来指示 Spark 在执行一个关系(表/文件)到另一个关系的操作时做什么。虽然这并不普遍,但普遍认为 Spark 工作中的更多阶段会导致更多的执行者之间的洗牌。让我们谈谈那个。
2.减少阶段的数量
我不断回想起 Jim Gray 的这个伟大类比,他谈到了从磁盘读取和从内存读取的延迟之间的巨大差异。在这种情况下,如果可以避免的话,从磁盘获取数据几乎是犯罪行为。
计算机性能有点像骗局。你总是在等待四样东西之一:磁盘 CPU 内存网络…
blog.codinghorror.com](https://blog.codinghorror.com/the-infinite-space-between-words/)
正如我在介绍中提到的,像 Redshift、Snowflake、Spark、Hadoop 等分布式系统。面临这个常见的问题,即在作业运行的网络上共享数据。这个共享数据是从磁盘中获取的。正如 Jim Gray 所展示的那样,磁盘 I/O 的成本非常高。显然,不仅仅是获取数据——这些数据的开销工作(如 serde)使情况变得更糟。
吉姆·格雷的存储延迟类比
减少给定 Spark 作业的阶段数量肯定有助于减轻您面临的一些性能问题。使用丰富的 Spark UI 来确定 Spark 作业的每个阶段有多少数据被打乱。
阅读关于洗牌的 Spark UI 的一个积极的副作用是,你可以了解除了级数之外的问题,比如你的数据的偏斜度。
3.分区修剪
过滤、下推谓词、分区修剪——本质上都是同一构造的实现。查询执行引擎希望您尽可能多地丢弃数据,以降低查询成本。在传统的数据库中,这是通过索引和分区来完成的。
分区是对数据进行分组,以便查询执行引擎查找查询所需的数据。修剪是一种能够拒绝查询不需要的整个分区的技术。您也可以使用查询提示在SELECT
语句中指定分区。
分区的替代方法是分桶。从概念上讲,它试图实现相同的性能优势,但分桶不是为每个分区创建一个目录,而是使用桶值的散列将数据分布到一组预定义的桶中。
4.小心缓存
首先要明白的是,和 Spark 中所有的转换一样,cache()
操作也是懒洋洋求值的。它不像动作那样调用驱动程序的数据移动。cache()
应该只在你确定缓存的 RDD 将被用于进一步的转换时使用。
不要因为 RDD 很小就进行缓存。不要仅仅因为它是维度表就缓存它(而是广播它)。缓存必须从数据血统的角度来看,即转换的 DAG。
理解缓存和广播之间的区别——前者将缓存数据的副本发送/广播到执行者的内存(和/或存储器)中。
请记住,过多的缓存会给 LRU 算法带来开销,因为它会不断驱逐被缓存的内容,并引入新的内容来替换它们。这个循环将会继续。
您可以继续查看 Spark UI 中缓存的数据量(百分比)。观察 UI 一定会让你的人生更早。
结论
这些是识别和修复 SparkSQL 性能问题的一些最快捷、最简单的方法。我会再写一篇关于修复 SparkSQL 查询的具体用例的帖子!
SQL 查询的简单修复
由思想目录在 Unsplash 上拍摄的照片。不是 101 篇文章,但是这里有一些提示和想法将会改变你写 SQL 的方式。他们可能不会改变你的想法。为了改变你的思维方式,你应该多读书,与真实的人交谈,并确定你需要改变你的思维方式。我可以一直唠叨下去。如果你能读一读这篇关于 SQL 的该死的文章,那不是很好吗!我已经花了将近十年的时间学习 SQL,并且仍然很强大。
更好的 SQL
查询任何传统关系数据库的经验法则
SQL 对于任何角色来说都是一个强大的工具。数据驱动着公司的所有决策。数据只使用一种语言,那就是 SQL。写 SQL(或者说,如果你是个书呆子的话)很简单。大多数人都能做到。只有一些人做得很好。这个会超级短超级有用。
不管您使用的是什么关系数据库管理系统或 RDBMS (MySQL、PostgreSQL、SQL Server、Oracle ),一些经验法则都适用于所有这些。以下是在你的数据库上做SELECT
的规则
1.总是使用 WHERE 子句(总是使用索引)
换句话说,只获取您绝对需要的数据——这可以通过使用古老的WHERE
子句来完成。只有在极少数情况下,您会发现不使用索引可以获得更好的性能。不要担心罕见的情况。索引强制数据做二分搜索法(尽管不同数据库的二分搜索法实现不同)。本质上,你将能够在对数时间而不是线性时间内SELECT
你的数据。
只获取你绝对需要的数据
例如,对一个有 10 亿条记录的表进行查询 而不使用 索引,可能需要多达 10 亿次才能得到您想要的记录。然而,使用 索引对您正在搜索的列进行查询 将花费更少的次数,并且将更快地获得结果,因为 10 亿的对数以 2 为底大约是 30(准确地说,是 29.897352854)。这是对搜索过程的过度简化。
感谢纠正日志上以 2 为基数的值不正确 普拉莫诺·温纳塔 。
2.确保使用了索引
当查询引擎无法使用索引时,可能会出现问题。这将导致查询速度缓慢。速度的快慢取决于查询所扫描的数据量。当查询引擎无法理解或映射带有表数据定义的搜索值的字符集(在WHERE
子句或JOIN
中)时,通常会出现问题。在这种情况下,显式类型转换通常会有所帮助。
不使用索引时,使用显式强制转换
来自 MySQL 文档
对于字符串列与数字的比较,MySQL 不能使用列上的索引来快速查找值。避免这类问题的一个方法是使用
[*CAST()*](https://dev.mysql.com/doc/refman/5.5/en/cast-functions.html#function_cast)
。
所有的数据库都非常相似。问题的严重性取决于任何数据库中查询引擎的实现。
3.明智地使用子查询
在许多数据库中,使用子查询会强制将数据复制到磁盘,并且对您的查询数据的计算将发生在磁盘上(数据将被一次又一次地读取和写入磁盘),而不是内存中。如果发生这种情况,如果数据很大,它会成为一个严重的开销。当这种情况发生时,延迟会成为性能杀手。查看由格蕾丝·赫柏上将制作的关于一纳秒意味着什么的惊人视频。延迟通常以纳秒为单位。
当心子查询和磁盘的使用
事实上,明智地使用任何在磁盘上创建(强制创建)临时表的方法—
GROUP BY
和ORDER BY
—是的,这也会导致数据子集被写入磁盘。在所有数据库中,您可以预定义一块内存(RAM)用于写入查询数据。如果您的数据集很大,并且您的查询数据的子集超过了这个限制,那么它肯定会被写入磁盘并从那里进行管理。JOINS
—是的,即使是JOINS
也可以将数据写入磁盘,以便进一步检索。一个JOIN
本质上是一个SEARCH
和MAP
操作。
4.避免排序/分类数据
排序操作成本极高。每个数据库都有自己的排序算法实现。他们可能使用了传统的排序算法,也可能想出了自己的排序算法。在任何情况下,由于这是一个非常耗费资源的操作,而且还涉及到将数据推入磁盘和从磁盘中取出数据,因此应该谨慎地使用排序。
5.不要使用[LIKE](https://mode.com/sql-tutorial/sql-like/)
查询
当您长时间查询数据时,传统的关系数据库会导致争用问题。这正是你做LIKE
查询时发生的事情。它们会影响整个数据库和其他正在运行的查询的性能。除了使用LIKE
,还有其他选择
- 关系数据库的全文功能。现在几乎所有的数据库都支持全文搜索。
- 如果全文搜索不是一个选项,你可以使用像 Elasticsearch,Solr 或 Algolia 这样的全文搜索引擎。它们是为文本分析而设计的。虽然,对于这些新系统,你没有一个像传统数据库那样强大的 SQL 接口。
使用关系数据库的全文功能,或者使用类似 Elasticsearch 的工具进行文本搜索
如果你想成为 SQL 超人
- 了解关系数据库的内部结构——数据库如何使用内存和磁盘
- 了解查询的执行顺序——首先评估查询的哪个子句。是
JOIN
先发生还是WHERE
从句先发生还是GROUP BY
先发生 - 了解查询引擎如何准确解析、估计、优化、重写和执行查询的底层实现细节。
- 了解基于云的关系数据库实现,如 Amazon Aurora、Amazon RDS 和 Azure SQL 数据库等等。
这并不是一份详尽的清单。还有更多关于DISTINCT
和OR
以及EXISTS
和IN
子句的用法,但我选择的这些似乎是最有问题的,也是最容易修复的。这些只是编写和重写查询时应该记住的一些通用规则。
轻松互动剧情——熊猫剧情后端
熊猫系列和数据框架中的一行交互式情节
熊猫提供了一种探索数据的简单方法(EDA)。一个例子是,我们如何在不导入任何可视化模块的情况下,仅从 Pandas 系列或数据框中创建绘图。我在下面的案例中展示给你看。
#I only use seaborn to import sample dataset
import pandas as pd, seaborn as snstips = sns.load_dataset('tips')
tips['tip'].plot(kind = 'hist')
仅仅通过使用.plot
属性,我们就可以默认生成一个 matplotlib 图。不过,在这篇文章中,我要展示的是我们如何用上面类似的线条创建一个交互式的 plotly plot。示例结果如下所示。
如果你想了解更多关于熊猫的 EDA,这里有一篇由 Pararawendy Indarjo 撰写的文章很好地涵盖了你可以用熊猫做什么,但在这篇文章中,我将只专注于创建一个互动的情节。
Plotly
Plotly 是一个模块,可以改善任何可视化,变得更加互动。2020 年 5 月 26 日,Plotly 发布了支持熊猫绘图的 4.8.0 版本。这是一个我个人很兴奋使用的新功能。后端是由 plotly-express 驱动的,这是 plotly 中的另一个包,用于创建快速、交互式的情节。以下是数据分析期间 plotly express 用法的示例。
import plotly.express as px
fig = px.histogram(tips['tip'])
fig.show()
现在,Plotly 4 . 8 . 0 版提供了一个后端来在 Pandas 系列或数据框中使用它,而不是导入 plotly.express。要实现这一点,您需要首先安装 Plotly 模块。
#If you never install Plotly
pip install plotly#If you have install Plotly previously
pip install -U plotly
安装了 Plotly 模块后,我们需要首先使用以下代码设置环境。
pd.options.plotting.backend = "plotly"
这样,我们已经将 pandas plot 后端从默认的 matplotlib 更改为 plotly 模块。让我们尝试我们能创造的各种各样的情节。
- 散点图
tips.plot.scatter(x = 'tip', y='total_bill')
- 箱线图
tips['tip'].plot.box()
- 水平条形图
#The y axis in the Plotly bar plot is the index, that is why I set up another column as the indextips.set_index('sex')['size'].plot.barh()
- 刻面图
tips[['tip', 'smoker']].plot.box(facet_col = 'smoker')
这是通过熊猫 Plotly 后端支持的几个情节。准确的说,目前只有scatter
、line
、area
、bar
、barh
、hist
、box
剧情可用。如果你想了解更多,你可以参考文档这里。
结论
在这篇文章中,我只是展示了如何使用 Plotly 从熊猫系列和数据框创建一个简单的互动情节。这个特性在本文创作时还是全新的,但是我相信在将来,这个功能会实现更多我们可以使用的情节。
如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的简讯。
如果您没有订阅为中等会员,请考虑通过我的推荐订阅。
用 Tableau 映射芝加哥的交通事故
让 Tableau 做繁重的工作。
当探索带有地理标记的数据时,地图是发现重要趋势的最有力的工具之一。Tableau 是创建地图的理想选择,因为它只需几次点击就能提供高质量的描述性可视化效果。在这篇博文中,我将通过使用 Tableau 调查过去几年芝加哥的交通事故来展示它的威力。
问题陈述
让我们想象一个假设的场景,芝加哥市已经获得了一项计划的资金,该计划旨在使该市的驾驶条件更加安全。部分预算将用于重新设计事故多发的十字路口和街道。作为参与该项目的数据科学家,您的首要任务是使用城市交通数据来确定哪些区域最需要关注。
数据
芝加哥公共数据门户包含了关于过去几年报道的所有交通事故的地点和细节的综合数据集。对于每个单独的事故,人们可以找到关于张贴的速度限制、受伤人数、照明条件、天气条件等信息。对我们来说最重要的是,每个事故的位置都以经度和纬度的形式报告。
使用 Tableau 查看数据
我们首先需要用 Tableau 读入数据。因为我使用的是 Tableau Public,所以我只是下载了数据并直接连接到 csv 文件。如果您继续操作,在打开一个空白工作表后,您应该会看到下面的屏幕。
包含芝加哥交通事故数据的空白 Tableau 工作表
我们首先简单地分别用经度和纬度填充列和行。因为我们想要每个地点的事故数量,我们可以拿起记录数量药丸,并把它放在带有计数测量的标记下。在这个例子中,我还把我的标记改成了金红色,但是这一步是可选的。现在,我们应该有一张地图了!当鼠标悬停在不同的点上时,我们会得到每个位置发生了多少起车祸的信息。
一张简单的地图,标明某一地点的事故数量
太好了!只需点击几下,我们就可以制作地图,现在我们可以开始调查了!对吗?
错了!
我们刚做的地图有个大问题。如果您一直在查看芝加哥数据门户上的数据,或者使用 Python 等其他工具,您可能会注意到经度和纬度坐标精确到小数点后 9 位。对于我们要完成的任务来说,这实在是太精确了。
交通事故的原始经度和纬度数据
当你放大并将鼠标放在地图上的不同坐标上时,你会注意到有许多地点发生了事故,但 Tableau 只报告了小数点后 2 位的经度和纬度。
在地图上放大,表明太精确的问题
为了解决这个问题,我们需要使用 Tableau 将我们自己的纬度和经度四舍五入到小数点后三位。如果您以前从未这样做过,请右键单击纬度测量,然后转到创建->计算字段。然后,键入以下内容:
创建四舍五入的纬度测量
一定要对经度做同样的事情。现在,我们可以用我们的新度量取代原来的经纬度药丸,并将其转换为维度。现在,当我们将鼠标放在不同的位置上时,我们将开始看到事故数量的汇总。
地图的放大图,显示了更多的事故总数
清理东西
我们现在拥有的地图比我们开始时的地图信息量更大,但它还可以做得更好。首先,它在视觉上不是很吸引人。为了补救这一点,我们可以采取以下措施:
1.)在屏幕顶部的工具栏上,选择地图->背景地图->街道。
2.)在标记下的下拉列表中选择地图选项。你可能也想玩一下大小设置。
更好看的地图
现在,这开始看起来更像一个实际的地图!尽管如此,还是有一些小问题。原来,这个数据集实际上包含了两个被错误标记为经度 0 的点。我们将通过右键单击我们的 round_lon 度量并选择 filter 来过滤掉它们。然后,只需将值设置为最接近芝加哥的经度和纬度值。确切的数字并不重要——它只需要不接近 0。
过滤掉经度异常值
接下来,你可能也注意到了在奥黑尔国际机场有大量的事故。如果你曾经在这个机场的上下车区开过车,这可能不会让你感到惊讶。对我们来说,问题是似乎没有任何关于事故可能发生在这个地区的细节。由于我们主要对城市的主要部分感兴趣,我们将从地图中排除这些点。为此,选择奥黑尔中间的点,然后点击“排除”
排除奥黑尔国际机场不需要的点
既然我们已经处理了异常值,我们就快完成了!让我们回到最初的问题陈述。请记住,我们感兴趣的是车祸发生率高的地区。这意味着我们可能不想让我们的视野被所有只有一两个事故的点所遮蔽。为了更容易地查看我们的地图,我们可以引入一个滑动过滤器,允许我们隐藏事故数量低于给定阈值的任何点。通过右键单击事故数量的标记,我们可以选择“显示过滤器”您现在应该在右侧有一个滑动条,这将允许您将地图限制为仅显示在所提供的范围内具有事故数量的点。
带有事故数量过滤器的最终地图
摘要
暂时就这样吧!总的来说,Tableau 允许我们通过将经度和纬度拖动到列和行中,几乎立即获得地图的工作版本。通过限制经度和纬度测量的精度,我们能够在统计交通事故数量时执行更具描述性的聚合。最后,我们使用 Tableau 的过滤和排除功能来消除异常值,使事情变得更加动态。
带有函数式编程的简易 Matplotlib 图例
使用多轴绘图时简化构建 matplotlib 图例的过程
介绍
Matplotlib 是标准的 Python 绘图库。它几乎可以完成您可能需要的任何事情,并生成出版物质量的图形。然而,它确实有点冗长。一个例子是,当一个图包含多个轴时,构建一个完整图例所需的代码量。
幸运的是,Python 标准库itertools
可用于开发一个简单的函数,收集所有轴上的所有标签,将它们组合成一个图例。
案例示例
我们来举例说明。考虑以下四个不同函数的数据—线性函数、对数函数、指数函数和幂函数。因为我们将每个函数的截距强制为零(或者指数函数和幂函数的截距为 1),所以我们可以很容易地计算出每个函数的斜率,即每个函数的斜率值为 f ( x =1000) = 100。让我们首先导入numpy
和matplotlib
并评估我们的函数:
然后我们可以绘制这些图进行比较:
我们四种不同功能的比较
很简单,对吧?但是,如果我们要线性化每一个函数呢?我们可以通过使用对数轴的各种组合来实现这一点。这意味着我们需要将每个函数绘制在它自己的轴上:
每个轴都有自己的图例
好了,我们已经线性化了每个函数…但是我们现在对每个图都有一个图例,而不是一个单独的图例!解决这个问题的标准方法是将每个对plot()
的调用分配给一个变量,然后在我们调用plt.legend()
时组合这些变量:
手动累积所有控点和标签会产生所需的图例样式
这是可行的——但是,有几个问题。首先,正如我们在介绍中提到的,它非常冗长。随着我们的情节变得越来越复杂,我们必须分配许多临时变量。其次,我们必须按照图例的正确顺序提供这些。第三,我们必须在对图例的调用中写出标签,而不是在相关行的实际情节调用中保留它们。
``chain`功能
那么我们能做什么呢?理想情况下,我们能够以编程方式获得每个轴的序列handles
和labels
,组合它们,并将它们传递给plt.legend()
。matplotlib
确实有获得handles
和labels
的功能!我们可以叫ax.get_legend_handles_labels()
。不幸的是,我们必须为每个轴调用这个函数,这意味着我们仍然需要编写一个for
循环,并将handle
和label
追加到一个列表中。这意味着我们也需要一种自动获取所有轴的方法…否则,我们只是将手动输入每一行替换为手动输入每一个轴!
幸运的是,plt.Figure
类确实包含一个axes
属性,它是轴的序列。但是我们仍然没有解决迭代每个轴的需要。解决方案在于采用函数式编程方法。在命令式编程中,我们编写一个控制结构来循环遍历某个值序列,我们可以使用函数式编程概念来将 映射 一个函数到那个序列。itertools
是这类技术的最佳选择。
itertools
是一个标准的 Python 库,包含了多个有用的函数。我们将使用[chain()](https://docs.python.org/2/library/itertools.html#itertools.chain)
,它将多个Iterable
有效地“组合”成一个Iterable
(例如,像一个链中的链接)。虽然chain()
对任意长度的参数序列进行操作,但是如果我们只有一个Iterable
的Iterable
呢?那样的话,我们还有另外一个功能,chain.from_iterable()
。这里有一个简单的例子来说明这些是如何工作的:
我们需要的另一个函数是zip()
。这个函数接受一个序列Iterable
并返回一个Iterable
的Iterable
,其中第一个Iterable
是每个参数的第一项,第二个是每个参数的第二项,依此类推。没有zip.from_iterable()
,但是我们可以使用*
操作符简单地“拍打”一下Iterable
。让我们也来举例说明一下:
Python 中的列表理解(在实践中)与map
相同,所以我们将使用该语言的习语来编写我们的函数。首先,我们得到句柄和标签,这给了我们[[handle_1, handle_2, ...], [label_1, label_2, ...]]
。
接下来,我们zip()
将轴 1 的句柄与轴 2、轴 3 等的句柄组合起来。,变成自己的Iterable
。对于标签也是如此。我们得到类似于([[handle_1, handle_2, ...], [handle_4, handle_5, ...]], [[label_1, label_2, ...], [label_4, label_5, ...]])
的东西。
最后,我们使用chain()
将所有句柄组合成一个Iterable
,将所有labels
组合成一个Iterable
,并返回一个Tuple[handles, labels]
。然后在作业中解包。
如果在函数调用中传递的是一系列轴,而不是一个数字,我们只需添加一个chain()
来组合fig
参数和剩余的args
参数。
让我们把它编码起来:
我们在类型注释中看到,这个函数可以接受plt.Figure
或plt.Axes
的序列。最简单的就是通过数字。然而,如果我们想改变图例中手柄的顺序,我们可以手动传递轴。该函数返回一个字典,然后我们可以使用 splat 操作符(**)将它作为关键字参数解包到plt.legend()
。让我们使用我们的新功能:
和以前一样,但是更容易!
我们做到了!不管我们创建了多少个轴,我们的函数总是会将每一行添加到我们的图例中。更好的是,我们可以通过在绘制线条时是否提供label
参数来轻松控制将哪些线条添加到图例中。这大大简化了多轴复杂地块的构建。当我们绘制每条线时,我们可以控制我们所需要的,不需要手动跟踪额外的变量及其顺序。
使用脸书的 DETR 轻松检测物体
面对宇宙的人。格雷格·拉科齐
用真实世界的例子简要介绍 DETR
在我之前的一篇文章,昆汀中,我和我试图从网上废弃的低质量图像中检测出人。为此,我们使用了 Yolo,一个流行的对象检测工具。我们的目标是从摄像机镜头中发现人。不幸的是,正如你在下面的图片中看到的,由于我们图像的质量,我们会错过很多人。
Yolo 在斯德哥尔摩关键区域从摄像机镜头中检索一帧并自动检测人员后的输出。我们注意到算法漏掉了一些人。
最近,我看到了脸书研究所的一篇有趣的论文。他们公开提供了 DETR ,代表检测转换器,这是一种使用 Pytorch 非常简单的对象检测算法。作为一个 python 迷,Pytorch 里的任何东西都让我开心!🤗
在本文中,我们将快速尝试 DETR 对一些高质量和低质量的图像。
在去 1000 个追随者的路上。 保证你跟着我在 AI 空间学习。我将在我的个人旅程中免费分享我所有的学习。
DETR 概况
DETR 可以检测从人员检测到牙刷检测的 91 类。作者提供的 colab 中提供了详尽的列表。然而,在这篇文章中,我们将主要关注人物检测,就像我们之前关于瑞典社交距离的文章一样。
让我们通过一个简单的图像来快速了解 DETR 的力量。我们在 GPU 上遵循以下步骤:
- 实例化 DETR 模型并将其推送到 GPU。
- 定义 DETR 可以检测的类别。
- 加载您的图像并使其正常化。这里要小心,需要是一个形状(800,600)的 RGB 图像。
- 使用 cuda 支持将您的图像推送到 GPU。
- 通过模型转发您的图像,并获得预测:i/预测框,带有检测到的对象在图像中的位置,ii/检测到的 100 个图像中每一个的预测概率。对于后者,我们对于每个检测到的图像,都有对应于每个类别的值的分布。例如,在使用 softwax 函数对其进行归一化之后,我们为每个图像获得大小为(1,N_CLASSES)的向量,其中 N_CLASSES = 91,以及每个类别的概率。输出形状:(100,91)
- 然后我们对前面输出的每一行应用 argmax 来获得类的索引,最大化对象从其中一个类中被提取的概率。请注意,之前使用 Softmax 进行规范化是不必要的,因为我们只对 argmax 感兴趣,即我们的概率向量中关于类的最大概率的索引。输出形状:(100,1)
- 现在我们有了图像中检测到的每个对象的预测类,我们可以在图像上画一个方框来显示该对象及其相关的类。在步骤 5 中,从 DETR 的输出之一中找到这种盒子的坐标。
DETR 的作者提供了一个可乐杯来展示它的易用性。" DETR 使用标准 ImageNet 规范化,并以[𝑥center,𝑦center,𝑤,ℎ]格式输出相对图像坐标中的框,其中[𝑥center,𝑦center]是边界框的预测中心,而ℎ𝑤是其宽度和高度。因为坐标是相对于图像维度的,并且位于[0,1]之间,所以为了可视化的目的,我们将预测转换为绝对图像坐标和[𝑥0,𝑦0,𝑥1,𝑦1]格式
DETR 在良好和低质量图像上的性能
我们修改了 colab 中提供的源代码,让一切都可以在 GPU 上工作。你可以看看我们的可乐布并玩玩它。在本节中,我们首先分析 DETR 在高质量图像上的输出。
原始图像与几个学生和一名教师写作。
应用步骤 1 到 7,我们可以用 DETR 检测图像中的物体。
检测原始图像中所有 100 个对象时的 DETR 输出。在矩形框的顶部,我们有被检测物体的概率。这个值越接近 1,我们的模型对它的预测就越有信心。
现在,人们可以根据目标过滤掉对象。我们的目标是主要关注人物检测。因此,除了前面列出的步骤 1 到 7 之外,我们只需要绘制与标签“person”相对应的方框。
DETR 只在原始图像中检测人物时输出。在矩形框的顶部,我们有被检测物体的概率。这个值越接近 1,我们的模型对它的预测就越有信心。我们注意到这个模型对它的预测非常有信心。
现在让我们看看 DETR 是如何在摄像机镜头中表现的,这通常对应于低质量的图像。我们决定用两个来自瑞典哥德堡的摄像机镜头的例子来玩。我们从一个例子开始,我可以检测到大约 17 个人。你自己察觉到有多少人?🤗
瑞典哥德堡的摄像机镜头。我们可以在这个图像中检测到大约 17 个人。
我们可以手动检测这类人,如下图所示。然而,在实践中,这将需要大量的时间和努力。因此,像 DETR 这样的工具对于自动人体检测是有用的。
瑞典哥德堡摄像机镜头的人工检测。我们可以在这个图像中检测到大约 17 个人。
现在,我们想知道我们的模型以足够的信心预测了多少人。可以将这个置信水平作为超参数进行调整(参见我们的 colab 中函数 detect 中的参数 confidence_level )。下面,我们展示了 DETR 的两个输出,第一个对应于设置为 70%的置信度。
我们在哥德堡拍摄的第一个镜头中 DETR 的输出。它检测到 12 个人的置信度高于 0.70。
第二输出对应于设置为 10%的较低置信水平。在这种情况下,模型实际上不确定预测,因为它预测对象类的概率至少为 0.10。
我们在哥德堡拍摄的第一个镜头中 DETR 的输出。它检测到了 36 个置信度高于 0.10 的人。
我们可以注意到,置信水平,或者对于给定对象检测到某个类别的概率,是一个关键的超参数。事实上,一些错过的人被 DETR 正确地检测到,但是概率低于 0.70。让我们试着看看当我们将置信度设置为 0.60 而不是第一个实验中的 0.70 时的输出。
我们在哥德堡拍摄的第一个镜头中 DETR 的输出。它检测到了 18 个置信度高于 0.60 的人。
我们仍然可以看到,我们的模型预测中存在一些不匹配。让我们用高于 0.70 的置信水平圈出模型没有检测到的对象(人),并用红叉标出假阳性。
我们在哥德堡拍摄的第一个镜头中 DETR 的输出。它检测到 12 个人的置信度高于 0.70。我们手动圈出遗漏的人,红叉出误报。
约罗和 DETR 的简单比较
正如引言中提到的,在之前的文章中,我们与 Yolo 合作,以便在从摄像机镜头中检索的帧中检测人类。正如我们看到的,在人体检测并不困难的帧中,有几个人被遗漏了。因此,现在有必要快速了解一下约罗与 DETR 相比如何。我们决定这样做是基于从摄像机镜头中随机截取的两个画面。
这一次,我们将使用 Yolo 的 Pytorch 实现。我们复制了在他们的实现中提出的对象检测,在这种情况下,我们进行一般的对象检测,而不过滤‘person’类。
对于 DETR,我们遵循之前在DETR 概述一节中列出的步骤 1-7。
首先,我们从在瑞典斯德哥尔摩拍摄的摄像机镜头中检索帧。下面我们可以看到一个低质量的图像,即使对一个人来说,也很难正确地检测到人。
原始帧 1。来自斯德哥尔摩的一段录像。
我们从使用 Yolo 检测任何物体开始。令人惊讶的是,该算法没有检测到任何人。由于源代码不够清晰,我保持检测原样。如果您在建议的代码中发现任何明显的问题,请告诉我!🤗
框架 1。在斯德哥尔摩用 Yolo 进行物体探测的镜头。
现在,让我们使用 DETR 进行‘人体检测’。这一次,非常容易,人们可以立即看到如下所示的结果,最低置信度设置为 0.70。
框架 1。在斯德哥尔摩用 Yolo 进行人体探测的镜头。
我们用如下所示的另一个框架来重现相同的实验。
原始帧 2。来自斯德哥尔摩的一段录像。
这次 Yolo 检测到一个人的概率是 0.32。我们并不确切知道为什么在这样的帧中没有检测到额外的物体。我们还可以注意到,检测到的人是不匹配的。基于此,应该使用具有不同权重参数的不同架构。在以后的文章中,我们可能会考虑此类任务的其他参数。
框架 2。在斯德哥尔摩用 Yolo 进行物体探测的镜头。
另一方面,如下图所示,DETR 在人体检测任务中表现出色。
框架 2。在斯德哥尔摩用 Yolo 进行物体探测的镜头。
显然,这样的实验不够严谨。人们应该建立一个更大的标记图像数据集,并在其上比较这两种架构。脸书的研究人员做了更彻底的分析。下面,我们报告他们论文中的一个比较表,其中我们可以看到 DETR 与更快的 R-CNN、ResNet-50 和 ResNet-101 的性能比较。
论文第 4 节中的表 1:“使用变压器的端到端对象检测”。
结论
在本文中,我们快速介绍了 DETR,这是一种非常容易使用的人体检测算法。然后,我们看到了它在好的和低质量的图像上的整体表现。最后,我们比较了 DETR 和一个叫做 Yolo 的流行算法。
总的来说,这篇文章只是对 DETR 的一个粗浅的介绍。关于算法的更多信息可以通过阅读研究论文和访问 github repo 找到。看看最初的 colab 和我们为这篇文章改编的 one 。
数据流中的简单异常检测
一种在数据流中寻找异常值的简单方法及其 Python 实现
在我的上一篇文章中,我已经解释了流算法的概念,并给出了许多如何应用它们的例子。其中之一是计算数据流的滚动平均值,而不保存数据流中的元素。现在,我想扩展这个例子,并向您展示在异常值检测环境中的另一个流算法用例。
当我们监控机器的功耗以检测任何异常行为时,就会出现这样的问题。如果我们看到异常值增加(不寻常的观察),这可能是这台机器的一个默认指标,可能值得检查。
定义和示例
离群值可以用多种方式定义。在本文中,我们将使用以下定义:
如果一个数字数据流中的一个元素不在目前所见元素平均值的 3 个标准偏差之内,则该元素被视为异常值。
这需要举一个小例子。让我们假设我们按这个顺序得到数据 3,2,4,3,5,3,2,10,2,3,1。让我们进一步假设我们从零的均值和方差(以及标准偏差)开始,即如果不等于零,第一个元素将总是被视为异常值。
所以, 3 被认为是离群值,因为 3 > 0+30。*现在我们根据目前看到的元素更新均值和方差,只有数字 3。因此新均值为 3,方差为 0 。
然后我们看到一个 2。我们有 2 > 3+30,所以 2 也被认为是异常值。这是有道理的,因为到目前为止我们只看到了一个 3,所以任何其他数字都不符合该模式。**平均值更新为(3+2)/2 = 2.5*,方差更新为((3–2.5)+(2–2.5))/2 = 0.25,这意味着标准差为 0.5 。
现在我们看到一个 4。由于 2.5–3 * 0.5≤4≤2.5+3 * 0.5,因此该数字不是异常值(即正常值)。平均值更新为(3+2+4)/3=3 ,方差更新为((3–3)+(2–3)+(4–3))/3 = 2/3,,因此标准偏差约为 0.81 。
以下数字 3、5、3 和 2 被认为是正常的。凭直觉,我们会认为下面的数字 10 又是一个异常值。让我们看看算法是做什么的。此时的平均值约为 3.1,标准偏差约为 1。因为 10 > 3.1+31* ,10 被认为是一个异常值,正如我们所希望的。**
如果你继续最后 3 个元素,你会看到它们都是正常的。
问题:要计算均值和标准差,我们得把目前看到的所有元素都背下来。如果我们有一个每天输出成千上万个元素的系统,这不是一个选项。
拯救流媒体算法
解决这个问题的一种方法是使用流算法,该算法在数据流的每个扫描元素之后更新其内部状态。内部状态由迄今为止在任何点看到的所有元素的均值和方差组成,在看到任何元素之前,从均值和方差为零开始。准确的说,让 mₙ 为均值 vₙ 为看到数据流的第 n 个元素后的方差,附加定义 m₀=v₀=0 。
计算平均值
在我关于流算法的文章中,我们已经看到了如何仅使用旧的平均值、正在扫描的最新元素以及迄今为止看到的元素数量来更新平均值。这意味着我们在任何时候都只需要用这种方法存储两个数字,而不是像简单方法那样存储 n 个。让我再展示一次,将数据流的第 i 个输入元素表示为 aᵢ:
这个公式不难开发,对吗?有了它,我们就有了预期元素大小的基线。现在,我们只需要标准偏差,我们可以将平均值分为异常值和正常数据点。我们通过计算方差,然后求它的平方根来得到标准差。
计算方差
在这种情况下,我们也可以毫不费力地找到一个递归公式。首先,看到 n 个元素后的方差如下所示
让我们试着用 n 、 vₙ、和最新的元素再写一遍。因为方差取决于平均值,我们也想包括 mₙ.在我们开始之前,让我们重新安排一下这个公式,让事情变得简单一些:
现在,我们的目标是把 vₙ放进去。一种方法是从下面的简单重排开始,分离平方和,直到索引 n ,它也作为术语出现在 vₙ 中:
这相当于
这反过来导致
现在,我们有了公式,让我们看看它在 Python 中是如何工作的!
用 Python 实现
我们可以通过以下方式实现上述解释:
*class StreamingMeanAndVariance:
def __init__(self):
self.mean = 0
self.variance = 0
self.n_elements = 0
def update(self, element):
self.variance = ((self.variance + self.mean ** 2) * self.n_elements + element ** 2) / (self.n_elements + 1)
self.mean = ((self.mean * self.n_elements) + element) / (self.n_elements + 1)
self.variance = self.variance - self.mean ** 2
self.n_elements += 1*
注意:update
方法的第一行计算方差,但是没有减去当前的均方值。第二行,计算当前平均值。在第三行中,从方差中减去它,因为它在第一行中仍然缺失。
为了使用它,我们做到了
*import numpy as np
m = StreamingMeanAndVariance()
n = 10000
for i, s in enumerate(np.random.randn(n)):
if not - 3 <= (s - m.mean) / np.sqrt(m.variance) <= 3:
print(i, s)
m.update(s)*
这将扫描数据流,该数据流在本例中由 10000 个正态分布的数字组成(我们将其表示为 N (0,1) ),并在异常值出现时打印出来。
如果您将正常点的间隔与平均值(黄色)一起绘制,您将得到下图:
用蓝色,你可以看到测量结果。绿色区域包含正常点,其外的测量值(以红色表示)被视为异常值。在黄色部分,您可以看到期望值(平均值)。
讨论
算法做了我们期待的事情!然而,到目前为止,我们没有看到它是如何处理分布的变化的,而只是在任何时候都是标准的正态分布的数字。
让我们测试算法在执行以下操作时的表现:
- 经过 10%的观察,我们将分布从 N (0,1)转移到 N (2,1)
- 在另一个 40%之后,我们将分布从 N (2,1)转移到 N (-2,1)
结果看起来像这样:
一切都在慢慢适应新数据。
好人
这看起来很有希望!一切都会自动适应新数据。当数据的均值从 0 转移到 2 时,我们可以看到许多异常值,这是有意义的。新平均值 2 的观测值越多,检测到的异常值就越少,因为大约 2 是新的常态。
当将平均值从 2 改为-2 时,我们可以看到更多的异常值,因为变化要严重得多。到目前为止,一切顺利。
坏事
如果你看图的右半部分,你可以看到对新数据的适应相当缓慢。一段时间后,平均值和标准差将再次达到正确水平,正如您所看到的,因为黄线(平均值)下降,绿色区域也再次变窄。但是直到它变平,没有异常值被检测到。
为了解决这个问题,我们只能使用最后的 k 个样本来计算平均值和标准偏差,因为这打破了第一次测量的影响。如果我们将 k 设为无穷大,我们就可以得到之前的算法。
我们设定的 k 越低,算法适应新数据的速度就越快。然而,将 k 设置得过小可能会导致丢弃异常值,因为算法认为新数据就像这个。在设置 k=1 的极端情况下,没有元素被认为是异常值,因为只考虑最新的元素。
根据不同的使用情况,也许几百或几千应该没问题。
结论
在本文中,我们看到了如何为数据流构建一个非常简单的异常检测机制。我们的算法不需要存储所有的测量值,这使得它非常容易应用,也可以在极其有限的硬件上应用,并且只需要恒定的存储。该算法甚至可以适应数据的变化,因此无需手动更新。
唯一需要调整的是适应率,我们在本文中没有涉及到,但这是一件容易的事情。
我希望你今天学到了新的、有趣的、有用的东西。感谢阅读!
作为最后一点,如果你
- 想支持我多写点机器学习和
- 无论如何都计划获得一个中等订阅,
为什么不做 通过这个环节 ?这将对我帮助很大!😊
说白了,给你的价格不变,但大约一半的订阅费直接归我。
非常感谢,如果你考虑支持我的话!
如有问题,在LinkedIn上写我!
使用 Algorithmia 轻松实现关键字提取算法的生产部署
基于 Algorithmia 的关键词抽取 NLP 模型的无服务器生产部署
图片来自 Pixabay 并由艺术 Chrome 插件风格化
最近,我发布了我的副业项目 AiArtist ,这是一个 chrome 扩展,可以自动为任何给定的故事或文章建议无版权的图片。构建广告的一个关键部分是从任何文本中提取关键字并将其部署到产品中。
今天我们将看到我如何使用 Python 关键短语提取库,Spacy 来开发一个关键词提取算法,并使用 Algorithmia 以无服务器方式将其部署到生产中。
自动建议图像
这篇文章的主要图片是由 AiArtist 通过给出文章的标题自动建议的。
让我们开始吧:
投入
算法的输入将是一些我们从中提取关键字的文本。例如:
Ahead of its mid-2020 world premiere, the first set of images of the updated Fortuner has surfaced online. While the Fortuner facelift's India launch is still some time away, these images give us a clear idea of what to expect from the mid-cycle update of Toyota's popular SUV.With this update, the Toyota Fortuner gets cosmetic restyling at the front, with a bumper and grille design that's now in line with newer Toyota SUVs like the RAV4 and Raize. The grille is a lot slimmer and has glossy black bits instead of the chrome trim, and the bumper is more pronounced with triangle-shaped faux air intakes on each corner. Also, the headlight shape seems to be mildly altered with new inserts that make the refreshed Fortuner look sharper than the pre-facelift version. The gloss-black finish on the skid plate completes the visual update for the SUV. The Fortuner facelift is also expected to get styling tweaks to the rear, including a mildly restyled bumper and tail-lamp inserts. There is no news on the interior upgrades for the updated Fortuner but it is safe to expect a better infotainment system and some minor changes. As far as engines go, Toyota sells the Fortuner with multiple petrol and diesel options globally, and the list includes 2.7 and 4.0-litre petrol engines, and diesel engines with 2.4, 2.8- and 3.0-litre displacements, depending on the market.
输出
输出将是文章中的关键字列表:
[ "fortuner", "bumper", "toyota", "update", "grille design", "toyota suvs" ]
在 Algorithmia 上部署
登录 Algorithmia 并点击仪表板中的创建新算法>算法。输入一个算法名,例如:关键字提取,保留所有默认设置,点击创建新算法。
Algorithmia 仪表板
一旦创建了算法,点击源代码选项卡。您将被带到如下所示的 IDE
源代码集成开发环境
在自动创建的关键字 Extraction.py 中输入下面的代码。
单击依赖项选项卡,输入以下内容,然后单击保存依赖项—
algorithmia>=1.0.0,<2.0
six
git+git://github.com/boudinfl/pke.git
spacy==2.2.4
nltk==3.3
thinc==7.4.0
[https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.2.5/en_core_web_sm-2.2.5.tar.gz](https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.2.5/en_core_web_sm-2.2.5.tar.gz)
在 IDE 的主控制台中点击保存,并点击构建。你会看到算法版本 XXXXX 现在在线。现在输入任何示例文本,例如:“老虎杀死了鹿”,并查看关键字 [“老虎”、“鹿”] 的输出
现在你的算法可以工作了,可以发布了。点击发布。
在发布工作流程中输入所有细节,如输入/输出,然后最后点击发布版本 x.x.x 。
现在你的算法已经可以使用了。您可以在双引号之间输入任何文本,并点击运行示例查看输出。
你可以使用任何编程语言并通过 API 调用算法,如安装和使用部分所示-
您已经正式将一种高效的关键字提取算法以无服务器的方式部署到生产环境中。恭喜你!
注意事项:
- 我只从文章中提取名词关键词。您可以相应地更改代码来提取其他词类关键字。
- PKE 图书馆使用 spacy.load('en ')在内部加载 spacy 英语模型。但是 Algorithmia 并不像他们博客中提到的那样支持它。
如果您使用的库依赖于在en_core_web_md
和en
之间创建符号链接的空间,请找到一个替代库,因为我们不支持手动创建该符号链接
但是我们通过在 Spacy 代码中动态链接" en_core_web_sm "到" en "巧妙地解决了这个问题。
# Link spacy code
import spacy
model_name = "en_core_web_sm"
from spacy.cli import link
from spacy.util import get_package_path
package_path = get_package_path(model_name)
# print (package_path)
link(model_name, "en", force=True, model_path=package_path)
使用自然语言处理的问题生成——教程
我推出了一个非常有趣的 Udemy 课程,名为“使用 NLP 生成问题”,扩展了这篇博文中讨论的一些技术。如果你想看一看,这里是链接。
使用 Python 实现简单的语音到文本转换
语音转文本
亚历山大·佩莱斯在 Unsplash 上拍摄的照片
语音是最常见的交流方式,世界上大多数人依靠语音相互交流。语音识别系统基本上将口头语言翻译成文本。有各种语音识别系统的实际例子。例如,苹果 SIRI 可以识别语音并将其截断为文本。
语音识别是如何工作的?
语音识别过程
隐马尔可夫模型(HMM),深度神经网络模型用于将音频转换成文本。完整详细的过程超出了本博客的范围。在这篇博客中,我演示了如何使用 Python 将语音转换成文本。这可以借助“ 语音识别” API 和“ PyAudio ”库来完成。
语音识别 API 支持几个 API,在这篇博客中我使用了谷歌语音识别 API。更多详情,请查看本。它有助于将语音转换成文本。
Python 库
将音频文件转换成文本
步骤:
- 导入语音识别库
- 初始化识别器类以识别语音。我们正在使用谷歌语音识别。
- 语音识别支持的音频文件: wav,AIFF,AIFF-C,FLAC 。我在这个例子中使用了' wav' 文件
- 我用过“拍摄”的电影音频剪辑,上面写着“我不知道你是谁,我不知道你想要什么,如果你想要赎金,我可以告诉你我没有钱”
- 默认情况下,谷歌识别器读取英语。它支持不同的语言,更多细节请查看这个文档。
密码
输出
如何转换不同的音频语言?
例如,如果我们想读取一个法语语言的音频文件,那么需要在 recogonize_google 中添加语言选项。其余代码保持不变。请参考更多关于文档
输出
麦克风语音转换成文本
步骤:
- 我们需要安装 PyAudio 库,用于通过麦克风和扬声器接收音频输入和输出。基本上,它有助于让我们的声音通过麦克风。
2.代替音频文件源,我们必须使用麦克风类。其余步骤相同。
密码
我只是说“你好吗?”
输出
用不同的语言交谈怎么样?
同样,我们需要在 recognize_google()中添加所需的语言选项。我说的是泰米尔语,印度语,并在语言选项中添加“ta-IN”。
我只是用泰米尔语说“你好吗”,它就会准确地用泰米尔语打印文本。
输出
注意:
谷歌语音识别 API 是一种将语音转换为文本的简单方法,但它需要互联网连接才能运行。
在这篇博客中,我们看到了如何使用 Google 语音识别 API 将语音转换成文本。这对 NLP 项目非常有帮助,尤其是处理音频文本数据。如果你有什么要补充的,欢迎随时留言评论!
感谢阅读。请继续学习,并关注更多内容!
你也可以在 KDnuggets 上阅读这篇文章。
可视化 3D 地下钻孔数据的简单技术
实践教程
绘制分散在 3D 坐标系中的连续和分类地理空间数据,使用 Matlab 应用于挖掘数据集
加拿大马拉其露天煤矿(作者摄影)
地下钻孔数据是通过钻探和提取岩石或土壤岩心收集的,由分散在三维空间中的样本组成,这些样本测量不同的连续变量或分类变量。每个样本记录:(1)由东、北和高程表示的 3D 空间坐标,(2)连续变量,例如元素浓度、污染物、矿石品位或温度等,以及(3)分类变量,例如岩性、蚀变或矿化单位。
左上图显示了钻孔样本在 3D 散点图中的位置,左下图放大显示了单个钻孔内的样本,右边的图像是显示物理岩石样本外观的带方框的岩心记录(作者拍摄的照片)
钻孔数据或类似的 3D 地理空间数据集用于地球科学和自然资源行业,以获得对地下的了解,用于各种不同的应用,例如采矿中的矿体建模、石油和天然气中的储层测绘、水文地质学中的污染物跟踪以及用于建筑或地质灾害目的的岩石或土壤稳定性描绘。除了传播和分析目的之外,可视化 3D 地理空间信息通常也是任何后续地质建模、工作流或探索性数据分析的第一步。
尽管可视化钻孔数据很重要,但一些地球科学家经常依赖昂贵的软件来绘制他们的 3D 数据,因为大多数从事岩石和土壤工作的人通常缺乏丰富的编程经验。绘制 3D 钻孔数据实际上非常容易,可以用任何编程语言完成,如 Python(使用 numpy 和 matplotlib)、R、Octave 或 Matlab。以下是一个用 Matlab 编写的简单教程,用于可视化应用于一个主要铜矿床的真实采矿数据集的钻孔数据。
挖掘数据集采用以下格式。
正在使用的挖掘数据集的标题行和前五行数据
虽然本教程是在采矿环境中介绍的,但可视化技能也适用于石油和岩土工程行业以及建筑、地质灾害和水文地质等领域中使用的相同类型的 3D 地理空间数据集。
首先,我们导入将在演示中使用的挖掘数据集和所有相关变量。数据集包含 16,258 个样本,分布在东距约 3 km、北距约 2 km、海拔约 1 km 的矩形区域内,每个样本测量连续的地球化学元素浓度以及分类地质蚀变单元。
data = importdata('Dataset.txt');%Spatial coordinates
x = data(:,1); %Easting coordinates in km
y = data(:,2); %Northing coordinates in km
z = data(:,3); %Elevation coordinates in km%Continuous variables
Cu = data(:,4); %Copper grade in ppm
Mg = data(:,5); %Magnesium grade in wt%
Al = data(:,6); %Aluminum grade in wt%%Categorical variable
Alte = data(:,7); %Geological alteration unit
在绘制任何变量之前,使用scatter3
功能,地理坐标将用于显示所有样本的位置。轴的比例应始终相等,除非夸大高程可能会暴露由于数据在其他两个主要方向上的空间范围而遗漏的要素。在 Matlab 中使用axis equal
命令可以很容易地缩放轴。以下示例比较了三维散点图与未缩放轴和缩放轴。
使用地理坐标显示的样本位置,左侧未按比例绘制,右侧按比例绘制
现在我们已经正确地缩放了轴,我们可以使用颜色来绘制变量,以表示它们在空间中的值。我们还可以使用对数色条或不同的颜色来更好地可视化某些变量或变量比率。下面展示了几个使用不同色条和色标的例子。
左侧为铜品位的 3D 散点图,带有线性色标,右侧为铝/镁比率的 3D 散点图,带有对数色标,均显示了整个体积内绘制变量的空间分布
还可以通过改变标绘点的大小或形状来引入额外的维度,这可以作为空间数据的多维探索性分析的额外工具。在下面的示例中,点的大小设置为等于铝镁比(Al/Mg ),颜色用于显示铜的品位。
多维散点图,使用位置在 3D 空间定位样品,使用大小显示铝/镁比率,使用颜色表示铜品位
多维图强调了在 Al/Mg 的中间值时如何发现更高等级的铜,因为更大和更小的点通常具有更小的铜浓度。
使用地质区块模型更好地可视化不同数量的分类数据
我们希望将采矿数据集中的四个不同分类变量可视化,这些变量由以下地质蚀变单元组成:绿泥石-绢云母、石英-绢云母、钾质和泥质。绘制此分类数据的一种方法是创建一个 3D 散点图,并根据其分类值为每个点着色,就像我们对连续变量所做的那样,如下例所示。
散点图显示了样品位置和四个地质蚀变单元:绿泥石-绢云母(Chl-Ser)、石英-绢云母(Qtz-Ser)、钾质和泥质
当处理分类数据时,当将分类单元或域可视化为块模型中的体积而不是分散在 3D 空间中的点时,我们获得了更多可操作的信息。通过以下方式生成块模型:( 1)创建贯穿整个体积的规则间隔点的网格,以及(2)基于来自数据的最近相邻样本的类别为每个点分配类别。对于更具代表性的块模型,应过滤这些点,以仅包括来自实际数据样本的设定搜索半径内的点。
这很容易编程和可视化,因为在大多数编程语言中有几个最近邻库可用,下面显示了一个在 Matlab 中编码的例子。
%Step size and radius inputs
SS = 0.01; % Step size in km
r = 0.01; % Search radius in kmxp=0:SS:max(x); yp=0:SS:max(y); zp=0:SS:max(z);
[X,Y,Z] = meshgrid(xp,yp,zp); % Create grid of points
Xp = X(:); Yp = Y(:); Zp = Z(:);Data_xyz = [x y z]; % Spatial coordinates in matrix
Block_xyz = [Xp Yp Zp]; % Block model coordinates in matrix[Idx D] = knnsearch(Data_xyz,Block_xyz); % Nearest neighbor search
Block_xyz(:,4) = alte(Idx); % Assign block values an alteration unit to nearest sampleBlock_xyz = Block_xyz.*(D<=r); %Filter to search radius %visualize Block_xyz with scatter3
应该使用足够小的步长来填充体积,同时保持合理的总点数,以便于处理和可视化。适当的步长将取决于所考虑的总体积,较大体积的步长成比例地较大,较小体积的步长较短。
对于正在使用的挖掘数据集,步长设置为 10 米,因此在所有三个方向上每 10 米有一个点。应测试不同的搜索半径,以确定哪一个能充分显示体积。根据以下示例,66 米到 100 米之间的搜索半径对于该数据集来说就足够了。
具有不同搜索半径的地质区块模型,显示了四个蚀变单元的空间分布
最后,可以在总体积内分别绘制每个区域的块段模型,以便更好地显示每个区域的空间分布,如下例所示。
使用 75 米搜索半径的蚀变单元的最终地质区块模型。组合块段模型显示在每个单独绘制的蚀变单元上方,突出显示每个单元在总体积内的空间分布位置和方式
块段模型使总结每个地质蚀变单元的位置变得更加容易:
- 绿泥石-绢云母单元自西向东由高到低逐渐倾斜
- 石英-绢云母单元更密集地聚集在该体积的东侧
- 含钾单位集中在该体积的西北角的顶部
- 在高海拔地区,粘土单位分布在东西和南北两个方向
结论
可视化钻孔数据在地球科学和自然资源行业中至关重要,许多地球科学家目前依赖昂贵的商业软件包来实现。使用任何标准编程语言绘制 3D 地理空间数据实际上都非常简单,本文展示了一些在 3D 空间环境中可视化连续、分类和多维变量的技术。
尽管此处介绍的教程使用了采矿数据集,但 3D 可视化技术也可应用于各种其他应用,例如绘制地下水污染物、土壤强度参数、岩石强度和稳定性、石油和天然气体积以及地下地热温度等。
作者说明
我希望这篇教程对所有读者都有用,尤其是对从事地球科学或自然资源行业的目标读者。我想鼓励所有在工业界和学术界使用地下钻孔数据或类似的 3D 地理空间数据集的人尝试编写自己的可视化脚本,而不是仅仅依赖商业软件。
随着我从学术界进入工业界,我目前正在寻找与自然资源或环境相关的地理空间数据分析项目。如果你想在这个领域合作或建立新的联系,请随时通过电子邮件或 LinkedIn 联系我!
在您的服务器上实现 Python 模型训练自动化的简单工具
我用来自动化我的 API 的工具
(src = http://python.org)
eb 自动化是未来的概念,但是非常复杂和难以设置。自动化解决方案通常涉及许多相互依赖的移动部件,并且容易发生故障。通常,这一过程包括三个步骤:
生成数据
自动化再培训
部署 API
这些步骤在理论上听起来很简单,但在实践中会创建一个相互依赖的文件和应用程序的复杂网络。通常,在这些情况下,正确的工具非常需要用于正确的工作,但是了解您的选项以及您可用的工具是战斗的一个重要部分。从获取数据到部署 API,这个难题的每一部分都需要紧密集成,从获取数据开始。
生成数据
(src = "http://python.org ")
“生成”可能是一个错误的术语,但创建可用于培训的数据是一项巨大的挑战。目前最好的工具是 Python。运行 Python 脚本来填充数据库当然是可行的,而且这可以用 RDS 很容易地完成。不过,在常规的 Linux VPS 端,我建议将 Python 与 CronJob 结合使用。
(src = "http://cronjob.com ")
CronJob 将在接下来的步骤中多次出现,这是有充分理由的。CronJob 允许您调度任务在分配的时间运行,这对于服务器自动化特别有用。这是通过使用由分钟、小时、月、星期几等组成的循环“Cron”时间戳来完成的。根据您的使用情况,CronJobs 也可以在更短或更长的时间范围内进行调度。如果有一个有价值的工具我会考虑在 Linux 领域内学习,CronJob 很可能是其中之一。在 Unix 系统上,您可以使用 CronJob 做很多不同的事情,了解如何使用 CronJob 无疑可以为您的服务器管理和部署增加很多功能。
通常,Python 和 CronJob 的协同工作足以让您的工作正常运行,并让 SQL 数据库或本地存储的数据文件不断填充新数据。通常,这些数据将使用 Python 从 API 中提取出来,并被推送到 JSON 或 CSV 格式,或者更理想的是推送到 SQL 数据库。
自动化再培训
自动化再培训是 CronJob 真正展示其能力的地方。虽然你当然可以在烧瓶路线上进行训练——但这肯定不理想。首先,关于路线的训练将会增加 CPU 和 RAM 的使用量,使得系统对于大量的请求非常不可用,并且会拒绝其中的许多请求。此外,根据您的模型,可能需要 10 分钟以上的训练时间,这对于 GET 请求来说一点也不理想。
所以通常情况下,解决方案是使用 CronJob 或 AWS Lambda 解决方案。在这两者中,克朗乔布最有可能
- 更便宜,
- 更具可扩展性
- 更多便利
- 更简单。
每当我部署一个 API 时,可伸缩性总是我最关心的问题。考虑到这一点,很难证明随着使用而增加费用的解决方案是合理的。在 VPS 上运行 CronJob 肯定是一个很好的方法,因为 AWS Lambda 的所有问题都可以完全避免,同时增加很少的问题。因此,通常情况下,CronJob 和您选择的语言的组合也是您的致命武器。
部署
在列出的所有步骤中,部署无疑是最简单的,但也是最复杂的。部署还涉及到更多的步骤,需要前面讨论的所有内容完全一致。不幸的是,这可能相当伤脑筋,因为一次中断可能会使您的整个系统变得无关紧要。
首先你需要一个网络服务器,我总是使用 Nginx。通常,另一个选择是 Apache,但是我选择 Nginx 有几个主要原因:
- 开放源码
- 背后是 10 年的发展
- 出色的表现
- 简单的配置
通常情况下,在 Nginx web 服务器上进行部署会涉及到编辑/etc/nginx/conf.d 中的文本文件,如果您想了解更多相关信息,我已经编写了完整的教程,您可以在这里找到:
应用程序部署通常会带来意想不到的后果和错误。部署可以是制定或…
towardsdatascience.com](/deploying-flask-with-gunicorn-3-9eaacd0f6eea)
本文还涵盖了 Supervisor,这将是部署难题的下一个重要部分。Supervisor 允许专用工作组内部的人工用户在后台运行命令。主管将持有运行我们网络服务器的命令,可以是 Django、Genie 或 Flask。Supervisor 配置也相对简单,在/etc/supervisor/conf.d 中有一个非常相似的配置文件,很容易编辑和访问。
Flask 是一个很好的部署选项,它既轻便又简单,非常适合在 web 服务器上返回 GET 请求的预测。使用 Flask API,通过 get 或 POST 请求输入和输出数据通常就像预测和返回一样简单。
拼图的最后一块将会是古尼康。Gunicorn 是运行 Flask 应用程序的客户端服务器。你可以通过 Pip 和一些包管理器来安装 Gunicorn(它在 Apt 中,而不是 Dnf 中)
sudo apt-get install gunicorn3
这是将从 supervisor 配置文件中运行的命令。然后用简单的
service supervisor reload
你将完全部署完毕,准备出发!
在 2020 年,有了所有这些有价值的工具,你可以在你的服务器上创建一些非常酷的模型和一些非常棒的自动化。拥有一个根据实时数据不断重新训练的模型将是非常有价值和非常可扩展的,这样做的解决方案肯定是最佳的!
简单的视觉问答
使用神经网络的视觉问题回答(VQA)的温和介绍。
快速回答——这张图片描述了什么运动?
图片来自 CloudCV VQA 演示
你可能马上就知道答案:棒球。很简单,对吧?
现在想象你是一台电脑。给你同样的图像和文字“在这个图像中描绘了什么运动?”并要求出示答案。不再那么容易了,是吗?
这个问题被称为视觉问答(VQA) :回答关于图像的开放式问题。VQA 很有趣,因为它需要结合视觉和语言理解。解决这一任务的模型展示了对图像的更一般的理解:它必须能够回答关于图像的完全不同的问题,有时甚至解决图像的不同部分。
起初,这似乎是一个很难解决的问题,但实际上它可能比你想象的更容易解决。在本帖中,我们将探索执行 VQA 的基本方法,并用 Python 构建我们自己的简单实现。下面是这篇文章最终产品的演示:
[## 简易 VQA 演示
在易 VQA 数据集上训练的可视化问答模型的 Javascript 演示。
easy-vqa-demo.victorzhou.com](https://easy-vqa-demo.victorzhou.com)
警告:这篇文章假设了卷积神经网络(CNN)的基本知识。我的CNN 简介涵盖了你需要知道的一切,所以如果有必要就从这里开始吧。
我们还将使用 Keras ,一个 Python 的深度学习库,来为我们的模型提供动力,所以如果你以前从未看过 Keras 代码,我建议你回顾一下我的Keras 神经网络简介。
这个前言说够了。我们开始吧!
只是找源代码/结果?跳到 结果 。
这篇文章最好在 victorzhou.com 浏览
1.数据集
在 visualqa.org 的可以找到 VQA 最著名的数据集,它包含 20 万多张图像和超过一百万个关于这些图像的问题(带答案)。这里有一些来自最初的 VQA 论文的例子:
印象深刻吧。不幸的是,这种程度的 VQA 超出了这篇博文的范围。我们将使用专门为这篇博文创建的自定义数据集: easy-VQA 。
易 VQA 数据集中的图像要简单得多:
问题也简单多了:
- 图像中是什么形状?
- 三角形是什么颜色的?
- 图像中是否有绿色形状?
- 图像包含一个圆吗?
总的来说,easy-VQA 包含 5000 幅图像和大约 50000 个问题,分为训练集(80%)和测试集(20%)。这些问题有 13 个可能的答案:
- 是/否:是,否
- 形状:圆形、长方形、三角形
- 颜色:红色、绿色、蓝色、黑色、灰色、蓝绿色、棕色、黄色
2.方法
执行 VQA 的标准方法如下所示:
- 处理图像。
- 处理问题。
- 结合步骤 1/2 中的功能。
- 给每个可能的答案分配概率。
请注意,我们正在使用一个固定答案集,其中保证可能的答案中只有一个是正确的。这让我们的生活变得容易多了,因为我们不必得出正确答案,我们只需回答实际上是一个选择题。大多数尖端的 VQA 系统有 1000 个可能的答案,但在这篇文章中,我们只允许包含在 easy-VQA 中的 13 个可能的答案。
步骤 1 和 2 通常分别使用来自计算机视觉和自然语言处理的方法,将原始图像/文本输入转化为经过处理的数据向量。然后,这两种输出表示可以一起用于分析,以最终选择最可能的答案。
一个例子
这里有一个非常简单的例子,说明 VQA 系统如何回答问题“三角形是什么颜色的?”关于上面可视化中的图像:
- 在图像中寻找形状和颜色。一个简单的 CNN 可以被训练识别出我们的图像包含一个蓝色的三角形。
- 了解题型。由于问题以“什么颜色”开头,很容易意识到答案应该是一种颜色。
- 对于每个可能的答案选项,根据前两步的信息确定其“强度”。答案“蓝色”将具有高强度,因为:(1)我们知道图像具有蓝色形状,并且(2)我们知道答案应该是颜色。
- 使用类似于 Softmax 的东西将每个答案的“强度”转换成概率。答案“蓝色”将有接近 100%的概率。
在接下来的几节中,我们将为 easy-VQA 数据集详细介绍实现这 4 个步骤的细节。
代码设置
如果你想跟随这篇文章,而不是从零开始,克隆易-VQA-克拉斯回购:
git clone [https://github.com/vzhou842/easy-VQA-keras.git](https://github.com/vzhou842/easy-VQA-keras.git)
cd easy-VQA-keras
pip install -r requirements.txt
否则,如果您想从头开始安装,请确保您使用的是 Python 3 并安装了几个包:
pip install easy-vqa keras tensorflow Pillow
我们需要 tensorflow 为 Keras 供电,我们将使用 Pillow 进行图像处理。我们还将使用 easy-vqa Python 包,这使得访问 easy-vqa 数据集变得简单。稍后会有更多相关信息——现在,让我们开始吧。
3.图像模型
首先:我们的形象模型。正如我们之前提到的,我们将构建一个卷积神经网络 (CNN)来从图像输入中提取信息。为此,我们将使用 Keras ,这是一个初学者友好但功能强大的 Python 深度学习库。我已经写了一篇关于使用 Keras 实现 CNN 的指南——在继续之前,在一个新的标签中打开它或者浏览它可能会有帮助。
我们的图像数据集并不复杂,所以我们可以用一个相对简单的 CNN 来处理它:
- 从数据集中的 64x64 图像开始。
- 通过使用“相同”填充的八个 3x3 滤镜的 conv 层,产生 64x64x8 的音量。
- 使用标准的最大池层将体积切割为 32x32x8。
- 通过另一个 conv 层,这一次有 16 个过滤器,产生一个 32x32x16 的体积。
- 再次使用最大池,切割到 16x16x16。
- 展平体积,这会产生一个具有 16 = 4096 个节点的层。
迷茫?以上所有概念都在我的CNN 简介 中有所涉及。
代码如下:
这段代码使用了 Keras 的模型(功能)API。我们没有使用 Keras 的顺序模型 API,因为我们稍后需要将我们的图像模型和问题模型结合起来(你会看到,继续阅读)。
4.问题模型
接下来:我们的问题模型。大多数 VQA 模型会使用某种递归神经网络 (RNN)来处理问题输入,但这对我们的用例来说有点大材小用。易 VQA 数据集中的问题简短、简单,来自一组固定的问题模板,因此与你在现实世界中可能看到的问题相比,它们更容易理解。
我们将采用一种更简单的方法,而不是复杂的 RNN 架构:
- 使用一个单词包 (BOW)表示法将每个问题转化为一个向量。
- 使用该向量作为标准(前馈)神经网络的输入。
如果你不完全明白那是什么意思,不要担心。我们将在下面完成这两个步骤。
单词袋(蝴蝶结)
BOW 表示通过计算每个单词在文本中出现的次数,将任何文本字符串转换为固定长度的向量。我已经写了一篇简短的、初学者友好的关于单词袋模型的介绍——如果你对它们不熟悉,我建议你现在就去读!从现在开始,我假设你对弓模型有一个基本的了解。
我们将利用 Keras 的记号赋予器类来实现 BOW:
注意,我们从easy-vqa
包中读取问题数据。如果你想了解这些 API 的细节,请参考 easy-vqa 文档。
神经网络时间!
如前所述,我们的问题数据集相对简单,因此我们的问题模型不需要太花哨的东西。我们将把我们的弓向量表示传递到 2 个全连接 (FC)神经网络层:
提醒:全连接层的每个节点都连接到前一层的每个输出。如果你需要复习,我们在我的 神经网络介绍 中使用了全连接层。
下面是我们的实现,它也使用了 Keras 的模型(函数)API:
vocab_size
变量是我们 BOW 向量表示的长度,它是我们问题模型的输入。
5.合并
我们将使用一个非常简单的方法来合并我们的图像和问题向量:逐元素乘法。用 Keras 的多重合并层实现这个是一行程序:
out
向量现在包含了从图像和问题中得到的信息。
一个例子
为了说明这是如何有用的,考虑这个(有点做作的)例子:
- 当图像包含蓝色形状时,图像向量中的第一个元素为高电平,否则为低电平。****
- 当问题包含单词“blue”时,问题向量中的第一个元素是高,否则是低。
那么out
向量中的第一个元素只有在图像和问题都与蓝色相关时才会为高。这个结果对于回答类似“图像中有蓝色的形状吗?”****
实际上,我们的模型不太可能准确地学习这种行为。记住,模型是通过在它的层中传播渐变来学习的,这不太可能产生如此简单的结果。相反,关注直觉:**
- 图像和问题向量中都嵌入了颜色信息。
- 乘法运算后,结果的某些部分可以用来回答关于颜色的问题。
实际上,我们可以用任何可微的方法来合并这两个向量。Keras 的合并图层部分中列出的其他合并方法包括Add
、Subtract
、Concatenate
和Average
,所有这些方法都做您认为它们做的事情。对于我们简单的数据集来说,大多数方法可能都和Multiply
一样好用——你可以自己尝试一下!
6.输出
最后,是我们的 VQA 系统给出答案的时候了。回想一下,我们正在使用一个固定答案集:我们知道所有可能的答案,并且只有一个保证是正确的。
对于这一步,我们将使用 Softmax 将我们的输出值转化为概率,这样我们就可以量化我们对每个可能答案的确信程度。如果你不熟悉 Softmax,我强烈建议在继续之前阅读我对 Softmax 的解释。**
首先,我们将加入一个全连接层,然后使用 Keras 内置的 Softmax 实现:
就是这样!剩下的工作就是构建和编译模型:
如果你需要复习,我在我的 CNN 系列中解释了 交叉熵损失 。
7.数据处理
既然我们已经弄清楚了我们的模型,我们只需要多一点代码来准备好所有的数据。对于这一部分,我建议在单独的标签中打开easy-VQA文档以供参考。为了简洁起见,我将省略对我们从easy-vqa
开始使用的方法的解释。
首先,我们将从easy-vqa
中提取一些数据:
接下来,我们将读取并预处理我们的图像:
然后,我们将创建用于训练模型的实际输入和预期输出:
Keras 的to _ categorial是一种从索引中生成 one-hot 向量的简便方法。我们需要一个热点矢量来匹配我们的输出 Softmax 层的尺寸。
作为一个可选步骤,我们将设置一个 Keras ModelCheckpoint 以在每个时期后保存我们的最佳模型:
终于,我们准备好训练了!
8.结果呢
为了节省空间,我不会在这篇文章中包含完整的代码,但你可以在 GithubT5上找到它。将这些行复制并粘贴到您的终端中,亲自训练模型:
**git clone https://github.com/vzhou842/easy-VQA-keras.git
cd easy-VQA-keras
pip install -r requirements.txt
python train.py**
运行代码会得到如下结果:
**Epoch 1/8
loss: 0.8887 - accuracy: 0.6480 - val_loss: 0.7504 - val_accuracy: 0.6838
Epoch 2/8
loss: 0.7443 - accuracy: 0.6864 - val_loss: 0.7118 - val_accuracy: 0.7095
Epoch 3/8
loss: 0.6419 - accuracy: 0.7468 - val_loss: 0.5659 - val_accuracy: 0.7780
Epoch 4/8
loss: 0.5140 - accuracy: 0.7981 - val_loss: 0.4720 - val_accuracy: 0.8138
Epoch 5/8
loss: 0.4155 - accuracy: 0.8320 - val_loss: 0.3938 - val_accuracy: 0.8392
Epoch 6/8
loss: 0.3078 - accuracy: 0.8775 - val_loss: 0.3139 - val_accuracy: 0.8762
Epoch 7/8
loss: 0.1982 - accuracy: 0.9286 - val_loss: 0.2202 - val_accuracy: 0.9212
Epoch 8/8
loss: 0.1157 - accuracy: 0.9627 - val_loss: 0.1883 - val_accuracy: 0.9378**
对于这样一个简单的模型来说,8 个时代一点也不差:
- 我们达到了 93.8% 的验证准确率
- 我们清楚地看到了培训的进展(损失减少,准确性提高)
- 该模型还没有过度拟合得太糟糕(训练/验证损失和精确度足够接近)
如果您愿意,您可以自己对代码进行试验,以获得更好的结果。我的带 Keras 的 CNN 简介中的扩展部分是一个很好的起点。考虑到这个问题相对简单,您应该能够非常容易地通过 99%的验证准确率。供参考:官方的 easy-VQA 演示使用了一个模型,该模型实现了 99.5%的验证准确性,参数仅略有不同。
9.结束了
您现在已经实现了一个工作的 VQA 模型!然而,这篇文章只是一个温和的介绍。您还可以做更多的事情:
- 了解递归神经网络 (RNNs),它可以比我们使用的简单的基于 BOW 的问题模型更强大。
- 以原始的 VQA 数据集为例,它包含更难的图像和问题。
- 查看 VQA 的调查,了解艺术模特使用的更复杂的方法。
- 试试 CloudCV VQA 演示(印象相当深刻!).
感谢阅读!
注意:这篇文章用了第一人称(“我”、“我的”),读起来好像是我(Victor Zhou)在说话。然而,正如最上面指出的,这篇文章是由我的好朋友Phillip Wang共同撰写的,他是最近从 CMU 毕业的计算机科学毕业生,也是 ML 的一员。谢谢菲利普。**
最初发表于https://victorzhou.com。
从广告服务向 Google Analytics 导入成本数据的简单方法
来源:沉积照片
为什么需要将成本数据导入 Google Analytics,以及如何做。
当你与许多广告服务打交道时,你最终会遇到这样一种情况:你需要衡量和比较它们的有效性。但问题是,非谷歌服务(如 Instagram、脸书广告、Bing、LinkedIn 广告等)没有与谷歌分析进行原生集成。因此,如果你想控制你的广告成本并评估广告活动的成功,你必须收集不同广告服务的活动数据,然后设法分析它们。
事实上,为了成功地工作并对任何营销变化做出快速反应,你需要获得关于活动效率的数据并存储在一个地方。由于谷歌分析仍然是最受欢迎和最方便的服务,让我们看看我们可以做些什么来建立基于任何广告服务的完整数据的报告。
所以这并不简单——你需要的只是数据,你广告服务的所有成本数据。您可以手动完成(例如,使用 CSV。文件),或者您可以设置自动数据导入,节省您的时间、金钱和精力。
我们建议使用 OWOX BI 连接器来自动收集和合并所有广告数据。这项服务是 Supermetrics 或 Funnel.io 等昂贵工具的免费替代品,免费到 2020 年底。
OWOX BI 数据导入的独特优势
这项服务是根据分析师和营销人员的要求创建的,这就是为什么它有许多独特的好处。
- 成本数据格式同。处理数据时最常见的错误是广告服务和谷歌分析视图中的货币不同。但是,OWOX BI 会自动转换货币,并在必要时扣除增值税。
- 数据的准确性和质量。OWOX BI 处理动态参数,检查您活动中的现有 UTM 标签,并借助 OWOX BI 数据监控工具报告可能的错误。
- 更新和历史数据。如果广告服务中的数据发生变化,OWOX 会在 21 天内自动更新数据。此外,您可以从广告服务下载过去 2-6 个月的广告,并评估您过去的活动。
图片由作者提供
简而言之,OWOX BI 服务可帮助您避免基于完全未采样数据制作营销报告的持续人工工作。
我们挑选了 7 个关于该服务的最受欢迎的问题,以便您可以看到它已准备好迎接任何挑战。
OWOX BI 向 Google Analytics 上传了哪些数据
OWOX BI Pipeline 从广告服务中导出这些数据:
- 来源(必需)
- 中等(必需)
- adCost(必需)
- 运动
- Google Ads 活动 ID(与您广告帐户中的活动 ID 完全匹配)
- 广告位置
- 关键字
- 广告内容
- 广告点击
- 印象
可选数据取决于您的谷歌分析数据集的配置。
OWOX BI 数据监控
有时,由于系统故障,广告服务 API 不提供下载的费用数据。结果就是你的 ROI 计算错误,甚至看不出成本数据的导入没有发生。
然而,在数据监控工具的帮助下,你可以确定从脸书、Twitter、Criteo 等广告服务导出到谷歌分析的成本数据。您可以在一个页面上使用 OWOX BI 项目中成本数据的每日统计数据,并获取所选日期的数据状态:
图片由作者提供
历史数据更新
广告服务中的信息可以更改,因为这些服务可以删除不正确的数据,如机器人活动、虚假点击等。因此,上传到您的 Google Analytics 个人资料的信息可能不准确。但是,OWOX BI 会自动检查 21 天的追溯数据,并根据需要进行更新。
也就是说,您的 Google Analytics 个人资料或 BigQuery 表格中的数据将与您的广告服务帐户中显示的数据完全相同。
谷歌分析何时提供这些数据
这些数据在 36 小时内可在谷歌分析中获得。一旦数据在广告平台上可用,使用 OWOX BI 服务导入和处理数据需要 12 个小时。处理完成后,可能需要24 小时才能在报告中获得数据。
在 Google Analytics 的什么地方可以看到导入的成本数据
采集/活动/ 成本分析报告 是您可以找到所有导入的成本数据的地方。此外,您可以使用以下工具通过 API 访问数据:
可以通过广告服务中的自定义活动过滤成本数据吗
您不能通过自定义活动过滤导入的成本数据,但可以对导入的 UTM 标签值使用 Google Analytics 过滤器。
例如,您可以按 utm_campaign 参数中的特定值筛选数据,以排除特定的成本。
图片由作者提供
我们建议将不同网站的活动划分到不同的帐户,以避免广告服务对每个活动的 API 调用次数的限制。
货币兑换是如何发生的
OWOX BI 使用一个开放的 API Yahoo Finance 来获取货币汇率。货币根据广告显示时的相关汇率进行转换。
换句话说,如果广告服务和 GA 视图的货币没有差异,数据就没有变化。当货币变化时,使用开放汇率 API 将成本数据转换为 GA 视图的货币。
请注意一些广告服务传输成本数据不含增值税(不像谷歌广告或脸书)。如果你不指定计算增值税的百分比,你最终会高估你的活动成本。使用 OWOX BI,您可以随时在数据管道的设置中更改增值税百分比。
图片由作者提供
觉得有意思?让我们看看如何开始使用 OWOX BI 导入成本数据。
OWOX BI 服务具有完全的透明性和安全性:只有 您可以控制对您的数据的访问级别 。
如您所见,您不必害怕提供对您个人资料的访问,OWOX BI 服务不会对您的数据进行任何更改。
使用 OWOX BI 从广告服务开始导入成本数据的 5 个步骤
- 使用您的促销代码并使用您的 Google 帐户登录。
- 选择要从中导入数据的广告服务。
- 提供对谷歌分析中选择的广告服务和数据集的访问。
- 定义设置(开始日期、增值税和货币)。
- 等待长达 36 小时,以获取您的谷歌分析个人资料中的所有数据。
如你所见,用 OWOX BI 导入成本数据很容易!放下服务中的日常工作,专注于真正重要的事情:
- 发现你广告的真正价值;
- 更多地了解你的客户;
- 有效管理你的广告预算。
弗雷德里克顿餐馆数据分析
在 Python 中探索、操作和分析数据
数据分析,21 世纪最热门、最繁荣的领域之一。不断增长的数据和对智能系统的旺盛需求要求对数据进行积极的分析。无论你使用 Siri 或 Alexa 之类的虚拟助手,还是在网飞或亚马逊之类的媒体服务提供商上获得内容推荐;数据分析是每个智能系统的基础。它已经在世界各地生根发芽,无论是支持企业发展的决策,还是成为我们生活方式的一部分。
在我们开始之前,让我们使用数据分析来探索加拿大的一个城市。这篇文章将带领你探索弗雷德里克顿的餐馆和附近的场地。使用数据科学方法论的术语,我们将推动它从描述问题到用可能的答案来总结它。
简介:
- 背景
弗雷德里克顿是加拿大新不伦瑞克省的首府,人口约 6 万。新不伦瑞克的主要城市中心之一,是该省第三大城市。
作为省会,它的经济与公共部门紧密相连;然而,这座城市也包含了一个成长中的 IT 和商业部门。该市拥有全省最高的大专以上学历居民比例,也是新不伦瑞克省人均收入最高的城市[1]。
作为这座城市的居民,我决定探索弗雷德里克顿的场馆。这座城市是完全多样化的,有很多社区,它正变得越来越密集,因为它吸引了全球更多的人。事实上,这里不能否认食物多样性的重要性。
- 问题
该项目的目的是探索弗雷德里克顿的场馆。由于弗雷德里克顿的居民区并不密集,人数也较少,所以我们希望找出弗雷德里顿市的餐馆类别及其在食物多样性中所占的份额。
- 利息
这个项目将有助于了解这个城市的不同菜系。任何政府官员或食品行业专家都可以利用这一分析结果来了解城市中的食品多样性。计划建立他们的餐馆或食品经销店的供应商可以利用这种分析来帮助他们做出决定。
数据:
以下数据来源是本次分析的一部分:
- 维基百科
加拿大邮政编码列表:E [2]
这一页有新不伦瑞克 FSAs(前分拣区)的邮政编码列表。上传页面数据,使用 Python 包抓取邮政编码表。这个数据包含所有街区的邮政编码,我们可以使用这个数据来获得弗雷德里克顿街区的空间坐标。
- Foursquare API
Foursquare 是一家建立了大量位置数据数据集的科技公司。目前,它的位置数据是最全面和相当准确的。它为苹果地图、优步和 Twitter 等许多流行服务提供位置数据。
使用 API [3],我得到了弗雷德里克顿社区的场馆数据。API 在 JSON 中提供了响应,并检索了场馆及其类别和其他详细信息。我用这些数据探索了这个城市的食物多样性。
方法:
- 废弃维基页面,获得邻居
为了探索城市,首先我们需要城市数据。那是从维基百科页面上检索到的;我用 Python 的 BeautifulSoup 包抓取了页面数据。wiki 页面中的表格被转换为下面的 pandas 数据框。
新不伦瑞克邮政编码
- 获取空间坐标
为了在地图上表示邻近区域,并从 foursquare API 获取场地,需要空间坐标。为了获得邻域的空间坐标,我使用了 Python 的地理编码库。
使用地理编码,我能够得到我们在上一步中搜索到的所有街区的经度和纬度。因此,创建了以下数据帧:
新不伦瑞克与自治市相协调
数据框的形状为(111,5),这意味着新不伦瑞克有 111 个邻域。未分配的邮政编码已从数据框中清除。
以上数据框包括新不伦瑞克省的所有行政区。可以使用叶库在地图上可视化;下面的图片是使用叶子库在顶部叠加了邻居的新不伦瑞克的表示。
叠加在新不伦瑞克地图上的街区
因为我们希望只探索弗雷德里克顿社区,所以我在一个新的数据框中分离出了“弗雷德里克顿”区的数据。
弗雷德里克顿街区
- 从 Foursquare 获取场地:
调用 Foursquare API 需要客户端 ID 和 Secret,可以在 Foursquare 开发者网站注册生成。Foursquare 为 API 端点提供了不同的过滤器选项。我首先试图为弗雷德里克顿的整个社区找到场地。弗雷德里克顿社区并不密集,所以我保持半径为 10000 米,限制为 100 米。从 Foursquare 收到 JSON 数据后,它被解释并转换成以下数据帧:
弗雷德里克顿社区活动场所
探索性数据分析:
合并后的数据框包含所有邻近地点的信息。让我们做一个热门的场馆编码。我将场地类别转换为新数据框的列,并在其中添加了邻居列。
数据框的形状是(4,53 ),表示有 52 个独特的场馆类别。使用此数据框,我们可以找到弗雷德里克顿社区最常见的活动场所。我尝试获得前三个公共场地,结果如下:
弗雷德里克顿最常见的地方
结果告诉我们弗雷德里克顿社区的三个最常见的场所。正如我们所见,最常见的场所包括三个社区的餐厅。然而,北弗雷德里克顿是唯一一个在公共场所没有餐厅的社区。与弗雷德里克顿的其他地区相比,北弗雷德里克顿的人口很少。因此,它的网点数量相对较少。
弗雷德里克顿只有四个街区。因此,在这里聚集邻域不是一个好的选择。因此,我们将对餐馆类别做进一步分析,以了解弗雷德里克顿的口味。
我再次使用 Foursquare API,但这次传递了类别 id,只获取食物类别的地点。JSON 响应以与我们之前相同的方式被解释,并被传输到数据帧中。有 22 个独特的食物类别,也包含一般类别,如就餐者,食物和美食广场。我列了一个一般类别的列表,并从数据框中删除了这些场馆。
由于我们希望探索弗雷德里克顿市的餐馆类别,因此我在数据框中为行政区添加了一列,并将值插入为弗雷德里克顿。
为了使数据更加结构化,我将场地类别作为列,并用类别的平均值乘以 100 对“区”进行分组。它给了我弗雷德里克顿市每一类的百分比值。具有类别平均值的数据框如下所示:
弗雷德里克顿市食品类别
为了可视化上述数据,我从上述数据框中获得转置数据,将百分比小数四舍五入为 2 点,并将数据框转换如下:
转置数据帧
上面的数据框现在很容易想象。一个水平条形图将是一个很好的选择形象化,并显示在弗雷德里克顿餐馆类别的百分比。
结果:
让我们使用 Matplot 和 Seaborn 库在上面创建一个条形图。以下是该数据的水平条形图:
条形图
该条形图显示了弗雷德里克顿各类餐馆的百分比。每个条形的百分比与其自身一起显示。图表清楚地显示,快餐店以大约 25%的份额领先。比萨和三明治店也领先于这个城市的任何一种特色美食。在弗雷德里克顿丰富多样的食物中,中国餐馆占有一席之地。在这座城市里,还有其他的美食可以提升弗雷德里克顿的品味。
结论:
在考虑了结果之后,可以说快餐店正在主宰弗雷德里克顿的食品市场。结果显示了城市中的食物多样性,考虑到城市的人口,这是相当活跃的。此外,不可否认的是,城市人口的增长将促进城市对更多美食的需求。因此,这将为打算投资食品行业的商家带来更多的机会。
此外,如果我们看到弗雷德里克顿的街区,餐馆类别可能不会出现在北弗雷德里克顿最常见的场所,但建筑在上面;它进一步抓住了利益相关者的注意力。
通过获取人口数字、社区主导位置及其利益的数据,可以进一步扩展这种分析的范围,以了解城市的确切需求;这可能是供应商做出决定的决定性因素。
参考文献:
【https://en.wikipedia.org/wiki/Fredericton】
****【2】https://en . Wikipedia . org/wiki/List _ of _ postal _ codes _ of _ Canada:_ E
****【3】https://developer.foursquare.com/
感谢您阅读文章!如果你喜欢,请在评论区分享你的想法。
Jupyter 笔记本和详细报告可从 GitHub 获取。
ECCV 2020 文摘
专家最有趣的自驾研究。
两周前,数千名计算机视觉研究人员聚集在 ECCV欧洲计算机视觉会议展示他们的最新成果。想看一眼最新的自动驾驶技术吗?这份文摘是给你的。
除了下面的论文,还可以查看我帮助组织的【g】标杆轨迹预测模型5 级行业网络研讨会 和 Kaggle ML 竞赛。**
感觉
基于柱子的自动驾驶物体检测
麻省理工和谷歌 的论文——作者提出了一个完全基于支柱的无锚点物体检测模型。这项工作将圆柱投影纳入多视图特征学习,预测每个支柱的边界框参数,而不是每个点或每个锚,这简化了 3D 对象检测,同时显著改善了最先进的技术。
用于自监督三维物体检测的单目可微分渲染
来自丰田研究所的论文 — 从图像中获取 3D 地面真实标签是一项艰巨而昂贵的任务。本文提出了一种自我监督的替代方案,该方案使用预训练的单目深度估计网络、差分渲染和定制的自我监督物镜来精确预测帧中所有对象的 3D 位置和网格。
雷达网:利用雷达对动态物体进行鲁棒感知
来自 ATG 优步的论文 — 一种联合使用激光雷达和雷达传感器进行目标探测和速度估计的方法。他们提出的 DNN 可以分为 2 个步骤:首先,基于体素的激光雷达和雷达数据的表示由主干和检测网络进行融合和处理。然后,执行另一次后期融合,并通过注意机制,通过与雷达数据融合来细化对象的径向速度。
重新思考伪激光雷达表示
来自 SenseTime 的论文— 对于 2D 探测任务,通常使用中间表示和任务来提高性能:其中一种方法使用伪激光雷达表示,即通过深度估计将 2D 输入转换为类似激光雷达的输入,然后由针对激光雷达输入的 3D 探测而定制的网络对其进行处理。在这项工作中,作者研究了这一点的惊人用途,但得出的结论是,激光雷达表示对任务没有帮助:在这里,他们提出了图像空间的变换和相应任务的网络,并表明这产生了可比的结果。
跟踪通过环视静态场景,用神经 3D 映射出现
来自 CMU 的论文——一种新的无监督 3D 对象跟踪方法,通过利用静态点的多视图数据训练 3D 映射网络,然后可以使用这些数据来产生可用于搜索和对应 3D 对象的特征。
朝向流感知
来自宾夕法尼亚大学的论文 — 在这项工作中,作者批评了视觉社区对“离线”方法的主要关注,并提出了一种结合多任务延迟和准确性的新评估设置:核心思想是将输入和输出(例如,对象检测任务)解释为流,并在评估期间将每个地面真实值与最近的预测进行比较。
福根:看到雨夜
来自 CMU 和阿尔戈艾的论文— 众所周知,数据偏差会极大地降低算法性能。为了解决这一问题,作者提出了一种新的基于 GAN 的图像到图像翻译架构,该架构解耦了域不变和域特定内容。提出的 ForkGAN 通过首先将夜间获取的图像转换为白天的图像,显著提高了在白天图像上训练的网络的性能。
用变形金刚进行端到端的物体检测
来自脸书的论文— 一种新的物体检测方法,不再需要许多手工制作的组件。主干用变换器编码器-解码器结构代替,整个任务作为直接集预测问题来计算成本。性能显示了这种新方法如何能够以少得多的操作和手动调整的参数产生与当前技术水平相似的性能。
预测和规划
图片来自 DSDNet:深度结构化自驾网络
DSDNet:深度结构化自驾网络
论文来自优步 ATG — 深度神经网络,用于联合学习自动驾驶的感知、预测和规划。基于激光雷达和地图输入,CNN 中枢学习探测物体。随后是预测层,它使用能量公式来推理多个智能体的社会似是而非的轨迹,最后是规划层,它将此考虑在内来规划安全轨迹。
PiP:自主驾驶的规划告知轨迹预测
来自香港大学的论文- 作者提出了一种管道,该管道不仅使用历史数据和当前位置,还将计划的自我轨迹考虑在内,从而引入了一种端到端的架构,该架构由交互的计划和预测模块组成。
学习车道图表示法进行运动预测
来自优步 ATG 的论文— 一种图形神经网络变体,可以比传统的光栅化地图图像更简洁地编码地图信息。然后,他们使用融合网络将来自 LaneGCN 的地图信息与从当前和以前的位置信息中提取的演员特征相结合,以做出最先进的多模态轨迹预测。
从观察和交互中学习预测模型
来自 UPenn、Berkeley 和 Stanford 的论文— 注入无监督的观察数据,例如来自车辆仪表板摄像头的数据,可以显著提高模型的准确性。为了克服无监督的性质以及领域差异,他们提出了一个图形模型,该模型根据交互作用以及分布先验上的观察数据来推断作为潜在变量的真实行为。
用于视频场景理解的概率未来预测
来自 Wayve 的论文— 作者从 RGB 视频中学习一种概率潜在表示,可用于对似是而非的未来进行采样。该框架首次联合预测自我轨迹、未来场景语义和几何以及其他智能体的动态。通过条件变分自动编码器方法学习潜在表示,该方法根据观察到的未来来调节所有可能的未来
猛击
图片来自 DA4AD:面向自动驾驶的端到端深度注意力视觉定位
DA4AD:基于端到端深度注意力的自动驾驶视觉定位
来自百度的论文 — 这项工作展示了单目视觉里程计的最新技术水平。这是通过将 VO 流水线的三个关键元素公式化为 ML 问题并采用神经网络对每个元素建模来实现的。
NeRF:神经辐射场
来自加州大学伯克利分校 的论文——在今年最具标志性的简历论文之一中,作者训练了一个网络来构建 3D 模型,并从现有的图片集中推断出现实主义的小说观点。结果明显优于以前的结构从运动和 ML 渲染方法。
深度 SFM:通过深度束调整从运动中构造
复旦大学和 Nuro 的论文 — 提出了一种新的基于深度光束法平差的运动结构(SFM)方法。通过引入分别用于深度和姿态估计的两个成本体,照片一致性和几何一致性在训练期间被共同加强,这提高了深度和姿态估计的性能,并具有优越的鲁棒性。
模拟和安全
交通事故因果关系认定基准
首尔国立大学的论文 — 本文提出了一个新的数据集,分析交通事故视频流中的因果关系。作者抓取 Youtube 以获得交通事故的剪辑,然后在时间上但也在语义上标记事故的影响和原因。基于此,不同的基准算法基于它们的分类性能被评估。
通过模拟感知和预测测试自动驾驶车辆的安全性
来自 ATG 优步的论文 — 作者从模拟数据开始模拟感知-预测堆栈输出。虽然模拟整个堆栈需要像 CARLA 这样的 3D 模拟器,但这种方法完全跳过了原始数据模拟(激光雷达、相机),只专注于模拟鸟瞰栅格。这大大减少了从模拟到现实世界的测试时间。
数据集
图像来自mapi pile 交通标志数据集,用于在全球范围内进行检测和分类
对全球范围内的交通标志数据集进行检测和分类****
来自 Mapillary 的数据集 — 在这项工作中,作者收集了可用于交通标志检测(where)和分类(what)的最大数据集。该数据集涵盖多个国家,包括来自 300 多个不同标志类别的 52k 完全注释图像。
数据科学家的计量经济学 101
数据科学家如何利用经济学家的工具箱
数据科学领域的人员通常对使用微观数据来解决特定领域的业务问题感兴趣。然而,对于他们来说,这是一个巨大的机会,可以在宏观层面上研究经济学和社会科学问题,而这些问题在传统上是社会科学学科的主题。计量经济学可能是数据科学家在这个方向上最接近的领域。本文的目的是向来自不同背景的数据科学家介绍计量经济学中使用的一些基本概念和工具,以及它们如何与我们所知的数据科学实践相关联。这主要是一篇介绍性的文章,只是触及了表面,但是如果有足够的兴趣,我可能会写更多关于特定工具和用例的文章。
什么是计量经济学?
基本上有两种经济学家:发展理论的人和检验这些理论的人。计量经济学家是使用统计技术来理解和解释具有经济维度的社会现象的后一类人。
计量经济学用例的一个例子是测试教育年限与工资率有关的假设,并能够使用经济理论和数据的组合来量化这种关系。另一个例子是使用历史数据测量汽油需求的价格弹性——即汽油消费对市场价格变化的敏感度。
计量经济学通常解决什么问题?
计量经济学处理与经济学有关的所有社会问题。该领域主要涉及宏观经济现象,如就业、工资、经济增长、环境、农业、不平等等。下面是来自计量经济学期刊的一个关于宏观经济问题的小样本:
- 衡量气候变化对 GDP 、农业和热带气旋破坏的影响
- 使用时间序列数据预测商业和住宅抵押贷款违约之间的空间相关性
- 利用贝叶斯观点解决时间序列预测问题
- 确定农场销售和出口的决定因素
计量经济学工具箱
除了一些例外,计量经济学工具箱中的大多数东西应该为数据科学家或任何计算科学家所熟悉。以下是一些常用工具的示例:
- 描述性统计(集中趋势和分散程度的测量)
- 推断统计和假设检验
- 时间序列建模和预测
- 各种回归
- 因果推理方法
除了统计模型之外,经济学家还广泛使用数学模型。事实上,经济学家经常被“指责”在模拟人类行为时使用了太多的数学。对这门学科有广泛的批评,他们试图模仿自然系统的确定性模型来描述复杂的人类行为问题,退一步说,这些问题相当不可预测或具有概率性。
最后但同样重要的是,可以说计量经济学工具箱中最重要和最强大的工具是面板数据模型。这个话题值得另文讨论,但我会在下面简单介绍一下。
面板数据模型
如果你之前没有听说过“面板数据”或“纵向数据”,那么这里是的一些描述。一个面板数据基本上是一个多维数据的观察,这是随着时间的推移重复测量。换句话说,这是一个数据集,其中测量了多个变量——如个人、组织、家庭、城市、国家。
这是面板数据的样子。消息来源
顾名思义,面板数据模型是一种统计工具,它提供了关于个体间和时间上差异的信息。以下 4 种是最流行的面板数据模型:
- 汇集 OLS
- 固定效果
- 随机效应
- 混合效果
理解这些模型需要一些讨论和数学公式。这个链接对这些建模框架进行了很好的讨论。
数据科学家的一些资源
- 计量经济学与 R :一个开放源码的书,理论与计量经济学模型的 R 实现
- 带 R 的计量经济学原理:另一本带 R 实现的书。我认为这本书对这一领域的初学者来说可能更容易理解
- 在这个源中有面板数据建模相关的资源在一个地方
- 那些喜欢看而不是读的人,这里有几个 YouTube 频道对面板数据模型的简单解释,它们的估计器和 R 中的相关代码
临终遗言
数据科学家在深入研究当今社会面临的社会和环境问题方面具有很大优势。他们不应该担心这是经济学家的领域,他们是局外人。我宁愿说,拥有不同背景和跳出框框思考能力的数据科学家比接受传统学科训练的人更有能力描述和预测社会问题。
如果你有问题想联系我,我在推特上。
使用 Python 的经济指标
使用 Python 和 Plotly 检索和绘制经济指标
经济指标经常被经济学家和金融分析师用来预测经济周期。在做投资决策之前,这个分析是非常重要的。
在本文中,我们将使用 Python 自动提取经济指标数据。我们需要的只是蟒蛇和熊猫。我们将为欧盟分析数据。
经济指标-类别
首先,让我们从一点理论开始。我想在这篇文章中介绍三大类经济指标。滞后指标,重合指标,超前指标。
- 滞后指标是那些在新一轮经济周期开始后发生变化的指标。
- 重合指标确实与周期峰值同时变化
- 领先指标确实能预测变化,因为它们发生在经济周期变化之前。
这些指标有不同的衡量标准,由不同的来源发布,如 OECD 和 Conference Board 。通过查看会议委员会的网站,我们可以很容易地找到以下三类经济指标:
在领先指标中,我们发现制造业的平均周工作时间、建筑许可、股票价格和领先信贷指数等等。
在重合的 指标内,我们发现工业生产和制造业、贸易销售额等。
最后,在滞后指标中,我们发现平均失业持续时间**商业和工业贷款、消费者服务价格指数和库存与销售比率。
你可以在会议板网站中找到这些指标的定义。
让我们用 Python 获取其中的几个来分析一下欧盟目前的经济形势。使用数据库经济学中的免费 API 提取所有指标。
我们用 Python 检索的经济指标有:利息、GDP 增长、失业率零售贸易变化和 10 年期欧元收益率曲线* 。好了,我们转到编码部分!*
检索经济指标的 Python 脚本
首先是导入我们将使用的所有必需的库。即熊猫、 Json 、请求和剧情。
我们将使用 Json 和请求从 API 中检索数据。然后,我们将使用熊猫来处理数据。最后, Plotly 创建我们的图形。
*import pandas as pd
import requests
import json
import plotly.graph_objects as go*
一旦我们导入了所有需要的库,我们就可以开始检索经济指标了。因为我们将提取多个指标,所以我们将构建一个可以重用的函数来提取所有指标。我将这个函数命名为 checkindicator :
*def checkindicator(url):
r= requests.get(url)
r = r.json()
periods = r['series']['docs'][0]['period']
values = r['series']['docs'][0]['value']
dataset = r['series']['docs'][0]['dataset_name'] indicators = pd.DataFrame(values,index=periods)
indicators.columns = [dataset]
return indicators*
我们的函数向将返回经济数据的 API url 发出请求。url 提取自数据库经济学。简单地说,我们进入 DBnomics 网站,搜索指标,选择它并复制 API 链接。
然后,我们传递 API 链接作为我们的 checkindicator 函数的一个参数,如下所示,以获取欧盟的选定指标。在我们的第一个例子中,我们将提取利率。
因为我们的 API 响应返回一个大的 json 对象,所以我们解析它以提取句点和值,如上面的代码所示。然后,我们创建一个包含日期和利率值的 Pandas 数据框架。
*interest = checkindicator('https://api.db.nomics.world/v22/series/Eurostat/ei_mfir_m/M.NSA.NAP.MF-LTGBY-RT.EU28?observations=1')*
运行代码后,我们的清单函数将返回一个包含每月利息信息的熊猫数据帧。如下图所示:
现在,我们准备提取所有其他指标。我们将以熊猫数据帧的形式将它们存储在变量中。既然我们已经提取了经济指标,我们可以将它们绘制在一起。
*euro_yields_10y = checkindicator('[https://api.db.nomics.world/v22/series/Eurostat/irt_euryld_m/M.EA.INS_FWD.CGB_EA.Y10?observations=1'](https://api.db.nomics.world/v22/series/Eurostat/irt_euryld_m/M.EA.INS_FWD.CGB_EA.Y10?observations=1'))unemployment = checkindicator('[https://api.db.nomics.world/v22/series/Eurostat/une_rt_m/M.NSA.TOTAL.PC_ACT.T.EA19?observations=1'](https://api.db.nomics.world/v22/series/Eurostat/une_rt_m/M.NSA.TOTAL.PC_ACT.T.EA19?observations=1'))interest = checkindicator('[https://api.db.nomics.world/v22/series/Eurostat/ei_mfir_m/M.NSA.NAP.MF-LTGBY-RT.EU28?observations=1'](https://api.db.nomics.world/v22/series/Eurostat/ei_mfir_m/M.NSA.NAP.MF-LTGBY-RT.EU28?observations=1'))inflation = checkindicator('[https://api.db.nomics.world/v22/series/WB/WDI/FP.CPI.TOTL.ZG-EU?observations=1'](https://api.db.nomics.world/v22/series/WB/WDI/FP.CPI.TOTL.ZG-EU?observations=1'))GDPgrowth = checkindicator('[https://api.db.nomics.world/v22/series/WB/WDI/NY.GDP.MKTP.KD.ZG-EU?observations=1'](https://api.db.nomics.world/v22/series/WB/WDI/NY.GDP.MKTP.KD.ZG-EU?observations=1'))monthly_change_retail_trade = checkindicator('[https://api.db.nomics.world/v22/series/Eurostat/sts_trtu_m/M.TOVT.G47.CA.PCH_SM.EA19?observations=1'](https://api.db.nomics.world/v22/series/Eurostat/sts_trtu_m/M.TOVT.G47.CA.PCH_SM.EA19?observations=1'))*
用 Python 绘制经济指标
为了用 Python 绘制我们的经济指标,我们将使用一个名为 Plotly 的库。
首先,我们需要导入它。接下来,我们需要创建一个 图 对象,我们将在其中添加痕迹。在我们的例子中,一个 迹线 将代表一个经济指标。因此,我们将拥有尽可能多的想要包含在图表中的指标。
为了简单起见,现在让我们只画出利率* 利率。在我们的 add_trace 对象中,我们指定 x 作为我们的 DataFrame 的索引(即索引代表日期)。而 y 将代表我们的值(即与每个日期相关的利率)。*
然后,我们使用**figupdated _ layout来使图形看起来更好看,并包含一个日期滑块和一个标题:
*import plotly.graph_objects as gofig = go.Figure()
fig.add_trace(go.Scatter(
x=interest.index,
y=interest['Interest rates - monthly data'],
name="interest",
line_color='deepskyblue',
opacity=0.8))fig.update_layout(xaxis_range=['2003-07-01','2020-12-31'],
title_text="Interest Rates, Unemployment, 10y yields, inflation UE, volume sales",xaxis_rangeslider_visible=True)fig.show()*
如果我们现在运行我们的代码,我们将得到下图,其中包含欧盟超过 15 年的 利率:
用 Python 和 Plotly 实现经济指标
到目前为止一切顺利。现在让我们加上所有其他经济指标,如失业率、GDP 增长等。到我们的 Python 图。
我们可以简单地通过添加新的轨迹来实现。见下面的代码,以绘制我们所有的宏观经济指标在一起。如上所述,每个轨迹代表不同指示器。我们为每个轨迹更改了名称和 l 线条颜色:
*fig = go.Figure()fig.add_trace(go.Scatter(
x=interest.index,
y=interest['Interest rates - monthly data'],
name="interest",
line_color='deepskyblue',
opacity=0.8))
fig.add_trace(go.Scatter(
x=unemployment.index,
y=unemployment['Unemployment by sex and age - monthly average'],
name="unemployment",
line_color='red',
opacity=0.8))
fig.add_trace(go.Scatter(
x=euro_yields_10y.index,
y=euro_yields_10y['Euro yield curves - monthly data'],
name="euro_yields_10y",
line_color='green',
opacity=0.8))
fig.add_trace(go.Scatter(
x=inflation.index,
y=inflation['World Development Indicators'],
name="inflation",
line_color='orange',
opacity=0.8))fig.add_trace(go.Scatter(
x=GDPgrowth.index,
y=GDPgrowth['World Development Indicators'],
name="GDP growth",
line_color='pink',
opacity=0.8))fig.add_trace(go.Scatter(
x=monthly_change_retail_trade.index,
y=monthly_change_retail_trade['Turnover and volume of sales in wholesale and retail trade - monthly data'],
name="% Monthly Change Volume Sales",
line_color='black',
opacity=0.8))fig.update_layout(xaxis_range=['2003-07-01','2020-12-31'],
title_text="Interest Rates, Unemployment, 10y yields, inflation UE, volume sales",xaxis_rangeslider_visible=True)fig.show()*
使用 Python 的宏观经济指标
不错!我们可以使用图表区域下方的滑块来动态更改图表的日期。
包扎
我们用 Python 创建了一个检索经济指标的脚本。然后,我们用 Plotly 将它们绘制在一起。
您可以根据想要分析的经济领域来更改或添加新的指标。可以对不同的国家进行类似的分析。我们已经为这个职位选择了欧元区。但是您可以通过修改 url 参数来轻松地更改它。
作为参考,请看下面用 Python 和 Plotly 构建一个显示经济指标的图表的最终代码。
如果你理解代码有困难,我在 Youtube 上有一个视频,一步一步地讲解代码和 API:
面向金融的 Python-使用 Python 绘制经济指标
*import pandas as pd
import requests
import json
import plotly.graph_objects as godef checkindicator(url):
r= requests.get(url)
r = r.json()
periods = r['series']['docs'][0]['period']
values = r['series']['docs'][0]['value']
dataset = r['series']['docs'][0]['dataset_name'] indicators = pd.DataFrame(values,index=periods)
indicators.columns = [dataset]
return indicators
euro_yields_10y = checkindicator('[https://api.db.nomics.world/v22/series/Eurostat/irt_euryld_m/M.EA.INS_FWD.CGB_EA.Y10?observations=1'](https://api.db.nomics.world/v22/series/Eurostat/irt_euryld_m/M.EA.INS_FWD.CGB_EA.Y10?observations=1'))unemployment = checkindicator('[https://api.db.nomics.world/v22/series/Eurostat/une_rt_m/M.NSA.TOTAL.PC_ACT.T.EA19?observations=1'](https://api.db.nomics.world/v22/series/Eurostat/une_rt_m/M.NSA.TOTAL.PC_ACT.T.EA19?observations=1'))interest = checkindicator('[https://api.db.nomics.world/v22/series/Eurostat/ei_mfir_m/M.NSA.NAP.MF-LTGBY-RT.EU28?observations=1'](https://api.db.nomics.world/v22/series/Eurostat/ei_mfir_m/M.NSA.NAP.MF-LTGBY-RT.EU28?observations=1'))inflation = checkindicator('[https://api.db.nomics.world/v22/series/WB/WDI/FP.CPI.TOTL.ZG-EU?observations=1'](https://api.db.nomics.world/v22/series/WB/WDI/FP.CPI.TOTL.ZG-EU?observations=1'))#inflation.columnsGDPgrowth = checkindicator('[https://api.db.nomics.world/v22/series/WB/WDI/NY.GDP.MKTP.KD.ZG-EU?observations=1'](https://api.db.nomics.world/v22/series/WB/WDI/NY.GDP.MKTP.KD.ZG-EU?observations=1'))monthly_change_retail_trade = checkindicator('[https://api.db.nomics.world/v22/series/Eurostat/sts_trtu_m/M.TOVT.G47.CA.PCH_SM.EA19?observations=1'](https://api.db.nomics.world/v22/series/Eurostat/sts_trtu_m/M.TOVT.G47.CA.PCH_SM.EA19?observations=1'))monthly_change_retail_trade.columnsimport plotly.graph_objects as gofig = go.Figure()fig.add_trace(go.Scatter(
x=interest.index,
y=interest['Interest rates - monthly data'],
name="interest",
line_color='deepskyblue',
opacity=0.8))fig.add_trace(go.Scatter(
x=unemployment.index,
y=unemployment['Unemployment by sex and age - monthly average'],
name="unemployment",
line_color='red',
opacity=0.8))fig.add_trace(go.Scatter(
x=euro_yields_10y.index,
y=euro_yields_10y['Euro yield curves - monthly data'],
name="euro_yields_10y",
line_color='green',
opacity=0.8))fig.add_trace(go.Scatter(
x=inflation.index,
y=inflation['World Development Indicators'],
name="inflation",
line_color='orange',
opacity=0.8))fig.add_trace(go.Scatter(
x=GDPgrowth.index,
y=GDPgrowth['World Development Indicators'],
name="GDP growth",
line_color='pink',
opacity=0.8))fig.add_trace(go.Scatter(
x=monthly_change_retail_trade.index,
y=monthly_change_retail_trade['Turnover and volume of sales in wholesale and retail trade - monthly data'],
name="% Monthly Change Volume Sales",
line_color='black',
opacity=0.8))# Use date string to set xaxis range
fig.update_layout(xaxis_range=['2003-07-01','2020-12-31'],
title_text="Interest Rates, Unemployment, 10y yields, inflation UE, volume sales",xaxis_rangeslider_visible=True)fig.show()*
原载于 2020 年 2 月 1 日 https://codingandfun.com。**
带 R 的经济订货批量
r 代表工业工程师
探索“sc perf”R 包
图片由 Tabakfabrik Linz 提供,可在 Unsplash
经济订货量
经济订货量( EOQ )是企业和组织内部的运营、供应链和物流部门使用的库存计划和管理方法。它表示每个订单要采购的最佳数量,以最小化组合订购和持有成本。它有助于确定满足给定年度需求所需的订单频率。
变量
- Q :最佳订货量
- D :年需求量
- S :订购成本(固定成本)
- H :单位持有成本(可变成本)
- 一:持有成本(利率)
- C :单位成本(变动成本)
- b :单位短缺罚款成本(可变成本)*
- ss: 安全库存 ***
*可能考虑也可能不考虑。
假设
- 需求率是恒定的,并且在一年中均匀分布
- 年度总需求是预先知道的(即确定性的)
- 立即下库存补充订单
- 存货的单价是不变的
- 订购成本是不变的
持有成本对订购成本
持有成本对订购成本曲线
上图显示了总成本曲线的行为,它是订单成本曲线和持有成本线的函数。由于规模经济采购,订单成本曲线随着订单量的增加而下降。另一方面,持有成本线随着库存水平的增长而线性增长。订单成本曲线和持有成本线的交点代表 EOQ 。
相关概念和公式
- 经济订货量( Q ): 代表每份订单的最佳项目数量,这将导致最低的年度总成本。它的公式可以表示为:
- 订单总数:代表每年补货订单的数量。它的公式可以表示为:
- 年度订货成本:表示补货订单对应的年度成本。它的公式可以表示为:
- 年度持有成本:代表在仓库或存储中持有存货的年度成本。这也被认为是投资于存货(可能存在多种风险)而非其他资产的年度机会成本。它的公式可以表示为:
- 年度总成本:表示年度库存管理成本(即年度订货成本和年度持有成本之和)。它的公式可以表示为:
来自 R 的 SCperf 包包含多个用于多种库存计划和管理方法的函数。对于下面的例子,让我们分别考虑一下 EOQ 模型变量的这些值: D = 2400 个单位, S =每订单 10 美元, H =每年每单位 0.3 美元, ss = 0 个单位。
让我们看看 R 代码!
结果:
既然我们已经获得了关于供应链分析师必须如何适当地计划和管理库存的相关信息,让我们建立一个图表来跟踪库存在一年中的可用性,并确定补货时间。
不考虑安全库存的库存图
上图证实了之前获得的结果。供应链分析师必须在一年中的第 0、2、4、6、8 和 10 个月下 6 个补货订单,每个订单 400 件,因为库存正好需要 2 个月的时间才能用完。
另一方面,如果我们假设安全库存为 50 件( ss = 50),库存图表将如下所示:
如上图所示,该图与原始库存图之间的唯一区别是 y 轴上移,对应于安全库存。每个订单的单位数量( Q )、需求率和订单总数分别保持不变。
总结思路
在当今竞争激烈的世界中,库存规划和管理是每个组织和企业的一项关键任务,应将其作为一种竞争优势,以尽可能低的成本实现最佳生产水平。
sc perf R 包包括多个功能,这些功能只需几行代码就可以为供应链分析师提供相关信息,使他们能够适当地计划和管理库存水平。
虽然有其他库存计划和管理软件可用,但 R 代表了一个获取简单库存计划和管理任务相关信息的伟大工具。在你的个人代码库中存储一个库存计划和管理 R 代码,只需输入相应的 EOQ 变量的值,就可以节省你大量的时间。
— —
如果你觉得这篇文章有用,欢迎在 GitHub 上下载我的个人代码。你也可以直接在 rsalaza4@binghamton.edu 给我发邮件,在LinkedIn上找到我。有兴趣了解工程领域的数据分析、数据科学和机器学习应用的更多信息吗?通过访问我的媒体 个人资料 来探索我以前的文章。感谢阅读。
罗伯特
数据科学家的经济学 101
数据科学家能从经济学家身上学到什么?
由 Unsplash 上的absolute vision拍摄
- 你以前听说过术语计量经济学吗?
- 你知道数学建模和统计学是数量经济学的基础吗?
- 你知道一些最大的数据仓库是由经济研究机构维护的吗?
仅仅看着这篇文章的标题,你可能会想,真的吗?经济学和数据科学有什么关系?作为一名有偏见的经济学家,我在这里不是要讲述经济学的伟大之处,而是给出经济学如何工作的内部观点——作为展示与数据科学联系的一种方式。我将根据(1)解决的问题,(2)使用的方法和(3)应用的工具来建立这种联系。希望您能够在此过程中与数据科学原理、工具和实践进行一些比较。
问题解决
经济学家发明了一个虚构的人——经济人(Homo economics)或“经济人”——来模拟人类行为。这就是经济学家所做的一切,用经济理论理解人类行为,并使用一些分析工具和技术——其中许多是标准的统计和数学模型。
经济学家发明了一个虚构的人来描述人类行为。
经济学问题大致分为两个分支学科。微观经济学关注的是社会基本构件之间的相互作用以及相互作用的结果,而宏观经济学则是缩小更小的细节,将世界视为一个庞大的互联系统。
比方说,一家公司正在推出一款新产品。如果他们把价格定得太高,很少有人会买。另一方面,如果价格太小,公司需要大量消费者购买产品才能达到一定的收入门槛。那么最大化利润同时最小化成本的最优 T21 价格是多少呢?微观经济学可以回答这个问题。
另一方面,宏观经济学从宏观的角度看待社会。技术创新将如何改变经济?气温升高对农业 GDP 有什么影响?全球疫情将如何打击失业?这些是宏观经济学家通常感兴趣的问题。
应用领域
你会发现经济学家涉足各个领域——从失业和不平等到气候变化经济学,再到广告和税收。这里有一个小例子,其中大部分对大多数数据科学家来说都很熟悉。
行为经济学家 可以量化消费者的反应&对营销活动、降价和增加新功能的态度
农业经济学家 帮助决定如何为农民制定针对自然灾害的正确保险政策。
产业经济学家 决定商品生产水平和给定市场需求的定价机制
体育经济学家已经对“球员被选中的方式或他们的薪酬有着巨大的影响,通过个人教练的决定,甚至是整个联盟的战略转变”【来源】。
计量经济学 是统计建模在理解复杂的社会和环境问题中的应用。这确实是应用经济学的一个很大的领域,我为此写了一篇全新的文章。
数据科学家如何利用经济学家的工具箱
towardsdatascience.com](/econometrics-101-for-data-scientists-584f4f879c4f)
方法&技术
如果不是全部,经济学的很大一部分是数据驱动和量化的。
在数量经济学中,经济学家创建了一个真实世界的模型——一个或大或小的部分——以了解不同组成部分之间的关系、它们的相互作用以及外部影响(如政策、激励、冲击)的影响。
因此,就像任何其他复杂互联系统的建模一样,经济学家依赖于一系列数学和统计技术。
微分方程等数学模型被用来量化输入的微小变化引起的输出边际变化。例如,价格的小幅下降将如何推动产品的购买并影响公司的底线?
另一方面,统计模型被用来开发和测试关于经济主体(人、农场、企业)和政策/激励措施影响之间关系的理论。事实上,“计量经济学”的整个领域都是基于标准统计模型的应用。数据科学家应该非常熟悉几乎所有这些工具:
- 描述性统计和假设检验
- 相关和回归分析
- 时间序列分析和可视化
- 预测分析和预测
- 面板数据建模:OLS,固定和随机效应模型
顺便说一句,许多经济学问题都是经验性的,可以通过遵循标准的科学流程来回答——提出假设、收集数据、检验假设、得出结论。然而,经济学家有时也会过于哲学化。他们通常会问一些主观的问题,其结果无法用客观的标准来衡量。
分析工具箱
如果我们从现在开始回顾 20 年,电子表格程序(主要是 MS Excel )是经济学家建立数学和统计模型的关键工具。Excel 几乎只用于可视化,即使在今天,仍有大量经济学家在使用它。
也有一小部分不同种类的经济学家喜欢用编程语言进行统计建模。 STATA 一直是(并将继续是)最受经济学家欢迎的编程平台。一小部分程序员的工具箱里会有其他程序,如 MATLAB 和 SPSS 。
随着新一代经济学家的出现,情况正在迅速变化。他们每天都在越来越多地拥抱开源软件平台。Python 和 R 正成为当今许多经济学家的首选平台,尽管很难说 Python 和 R 哪个更受欢迎。
很多经济学家,尤其是宏观经济学家,喜欢摆弄时间序列数据进行动态可视化,用数据讲故事。对他们来说, Tableau 似乎是一个很棒的新玩具。我认识几个经济学家朋友,他们现在专门使用 Tableau 进行交互式数据可视化和创建 web 应用程序。
临别赠言
随着学科界限的模糊,很难判断一个特定的研究问题是否属于一个特定的领域。许多经济学家现在在不同领域担任数据科学家。同样,许多数据科学家正在研究经济和行为问题,这些问题在过去是经济学家的专属领域。
每个学科都不同,但在解决的问题、使用的方法、理论结构和应用的工具方面也有相似之处。因此,从其他学科中学习一些东西来加强研究和分析能力总是好的。*
技术人员的经济学——需求(上)
使用 R 和 ggplot2 了解需求经济学
这个项目之所以存在,是因为我注意到,对于“需求”这个词在经济背景下的实际含义,尤其是在技术领域,存在着大量的误解。
谁要求东西?什么是曲线?需求曲线为什么会变化?为什么说价格的变化意味着需求的变化是错误的?需求和需求量的区别是什么?弹性到底是什么意思?怎么才能算出最大总收入?
介绍
在这篇文章中,我们要做的是使用 R 编程来分析和可视化我在 Excel 文件中创建的一些真实数据,探索需求中的概念。
从结构上来说,我们将使用 10 家假设的公司来分析对我们假设的新软件即服务(SaaS)应用程序的需求,该应用程序对每个许可证收取月费。这里有各种各样的公司,从小型到大型,他们愿意为多少许可证支付多少价格。
然后,我们将检查市场需求,并打破需求弹性的概念,试图找到我们最大化总收入的地方。
这是通过基于项目的工作在技术背景下解释经济学的多部分系列的第一部分。
在这项工作中,我在 Mac 电脑上使用 RStudio,带有 R Markdown (RMD)文件。
所有文件都可以从我的 GitHub 这里下载。
注意:如果您使用的是 Mac,请不要打开带有数字的文件。它会自动改变文件的编码,R 会不高兴的。如果发生这种情况,请删除该文件并下载一份新的 Excel 文件。
我还假设您可以设法在本地机器上设置一个 R 环境。最好是把你所有的文件放在一个文件夹里,无论你在哪里捣鼓按钮。
我们开始吧!
设置
导入数据
有时候用 r 导入 Excel 文件会有点棘手。
我认为使用 RStudio 最简单、最不容易混淆的方法是创建一个文件夹,用作您机器上的工作目录,然后单击“文件”选项卡,如下所示:
Mac 上 RStudio 中“文件”标签的屏幕截图
从那里,点击右边的三个点(…)。您可以导航到机器上数据和 R 文件所在的文件夹。
接下来,点击带有下拉菜单的“更多”按钮,然后点击“设置为工作目录”。这将有助于简化数据导入,并且是一个好习惯,因为它简化了 RStudio 中的代码和文件管理[1]。看起来是这样的:
Mac 上 RStudio 中的更多下拉菜单
完成后,继续点击“Demand_Data.xlsx”的实际文本,使用“Import Dataset…”选项将其导入,如下所示:
Mac 上 RStudio 中导入数据集…选项的屏幕截图
这将弹出 readxl 数据导入窗口,如下所示:
Mac 上 RStudio 中“导入 Excel 数据”窗口的屏幕截图
它应该自动工作,但仔细检查数据看起来不错。确保选中“第一行作为名称”框,以避免不必要的代码来正确地将它们放在一起。如果您想将数据集重命名为“Demand_Data”以外的名称,现在是这样做的好时机,这样可以避免不必要的代码。然而,您应该让它独自跟随这里。
完成后,让我们开始捣碎一些按钮!
代码
加载库
我们将需要这个项目的 readxl 和 tidyverse 库。如果您的 R 环境中没有安装它们,只需删除代码[1]中“ install.packages… ”行前的“ # ”符号。一旦安装了它们,您就不需要在您的机器上再次安装它们。
代码如下:
# If you do not have readxl or tidyverse installed, uncomment the following lines
# install.packages("readxl")
# install.packages("tidyverse")# Load Libraries
require(readxl)
require(tidyverse)
检查数据导入
让我们检查一下数据是否正常。我的代码显示了用代码而不是点击按钮来读取 Excel 文件的方法。确保您的工作目录设置在正确的位置,这样您就不必寻找整个文件路径。
我们将使用 head() 函数来检查前几行是否好看。
代码如下:
# Import data
Demand_Data <- read_excel("Demand_Data.xlsx")# Check data import
head(Demand_Data)
以下是输出结果:
Mac 上 RStudio 中需求数据前六行的屏幕截图
快速测试图
当处理经济数据时,做一个快速的图表总是一个好主意,只是为了确保没有什么奇怪的事情发生。记住,需求曲线,除了极少数例外,都是向右下方发展的[2]。让我们随机选择一列数量来绘制,并确保它通过这里的气味测试。
代码如下:
# Test plot
plot(Demand_Data$Qd_6, Demand_Data$Price, type = "l", main = "Test Plot", xlab = "Quantity", ylab = "Price")
以下是输出结果:
快速绘制其中一个数量列与价格的关系图,以便在 Mac 上检查 RStudio 中的数据
我知道,这不是你见过的最漂亮的图表。关键是,我们的数据通常向右下方倾斜,这正是我们想要看到的!谢谢需求定律[2]!
绘制所有个人需求曲线
看到一个图很好,但是同时看到我们所有的 10 条个人需求曲线会怎么样呢?我们将使用 ggplot 的魔力来实现这一点。
如果说随着时间的推移,我对 ggplot 有所了解的话,那就是整个软件包都是喜怒无常的,只以一种非常特定的方式喜欢数据。我们需要以一种与 ggplot 做事方式相适应的方式来组织我们的数据,而不是试图与系统对抗。
因此,我们将使用 stack() 函数来完成一项非常巧妙的工作,将我们的数据从 10 个不同列中的当前形式转换为一个更小、更适合 ggplot 的形式,其中价格和数量数据由 Qd_#标记在两个 glory 小列中。
在此过程中,我们将继续将其与价格数据合并到一个数据框中,以生成第三列,自动将正确的价格数据与正确的数量和标签数据放在一起。
最后,我们将更改由 stack() 函数生成的列名,使它们更适合我们的项目。
代码如下:
# Wrangle the data into a ggplot friendly structure
Wrangled_Data <- data.frame(Price = Demand_Data$Price, stack(Demand_Data[2:11]))
names(Wrangled_Data)[2] <- "Quantity"
names(Wrangled_Data)[3] <- "Qd_num"# Check the data
head(Wrangled_Data)
以下是输出结果:
在 Mac 上的 RStudio 中,ggplot 友好结构中的前六行争论和标记的需求数据
完成后,我们可以更容易地使用带有一些样式参数的 facet_wrap() 函数来优雅地显示所有的个人需求曲线。
代码如下:
# Plot the individual demand curves
ggplot(data = Wrangled_Data, aes(x = Quantity, y = Price)) +
geom_line(color = "steelblue", size = 1) +
geom_point(color = "steelblue") +
facet_wrap(. ~ Qd_num)
以下是输出结果:
Mac 上 RStudio 数据集中所有单个需求曲线的绘图屏幕截图
这里有很多东西要打开!让我们思考一下,在销售 SaaS 许可订阅的项目中,这 10 个个人需求图对我们意味着什么。
我注意到的一个现象是,许多公司并没有真正购买超过 5-6 美元的股票。随着价格降低,大多数公司开始购买更多的许可证。有些人不管价格如何都不会真的购买很多许可证,比如公司 4、8 和 10。
其他公司如公司 6、7 和 9 购买了大量许可证,并且随着价格的下降购买了更多的许可证。
其中一个基本概念是,个体企业有个体需求[2]。一些组织只是比其他组织更看重我们的 SaaS 应用程序,降低我们的价格可能不会对他们的购买决策产生太大影响[2]。
作为每月许可证的销售者,我们需要担心市场需求。让我们看看那个。
市场需求
市场需求最简单的定义是,它是所有个体企业需求曲线的总和[2]。这意味着,如果我们的市场上有 10 家公司,把所有的需求量和每个价格加起来,就会得到市场需求曲线[2]。
让我们来看看如何组装它。
代码如下:
# Create market demand
Market_Demand <- data.frame(Price = Demand_Data$Price, Market_Demand = rowSums(Demand_Data[2:11]))# Check the data
head(Market_Demand)
以下是输出结果:
Mac 上 RStudio 的市场需求截图
策划市场需求
在 ggplot() 的一点帮助下,只需绘制出每种价格下我们的需求总量,就可以实现数据的可视化。
代码如下:
# Plot market demand
ggplot(data = Market_Demand, aes(x = Market_Demand, y = Price)) +
geom_line(color = "steelblue", size = 1) +
geom_point(color = "steelblue") +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0)
以下是输出结果:
Mac 上 RStudio 的市场需求图截图
当我看到这一点时,我立即注意到,在这条市场需求曲线的某些范围内,价格的变化不会在曲线上的每一点产生市场需求数量的相同变化,因为它不是线性的[2]。
目测一下,我看到四个不同的区域有相似的斜率。接下来让我们来看看,并介绍弹性的概念。
弹性
需求弹性是简单地观察价格和数量的组合如何在曲线上的两点之间变化的概念。在数学上,它可以表述为数量的百分比变化除以价格的百分比变化。
简单地说,我们正在寻找两点之间的斜率,就像我们使用高中代数课上的经典公式 y = mx + b 一样,具体来说就是查看那个 m 值。
从我们的角度来看,商业问题是:
价格每改变一个单位,需求量会改变多少?
我用来说明这一点的是不同弹性区的价格范围。这可能不是世界上最正式的方式,但你真的可以看到市场需求曲线的不同区域在不同的范围内有不同的斜率。
代码如下:
# Add Elasticity zones
# 10-6.5 zone 1
# 6-4 zone 2
# 3.5-2 zone 3
# 1.5-0 zone 4
Market_Demand$Elasticity_Zone <- as.character(c(1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4))
Market_Demand
以下是输出结果:
Mac 上 RStudio 中弹性区域的市场需求截图
从使用 ggplot 进行 R 编程的角度来看,将数字向量放入函数 as.character() 中非常重要,这样 ggplot 将自动知道这些是分类值,而不是用于数学运算的数字[1]。我们将在下一个情节中看到这一点。
用弹性区域划分市场需求
虽然 ggplot 有时会令人沮丧,但它确实提供了一些很棒的特性。我们将通过在 aes() 函数中添加 color = Elasticity_Zone 来增加之前的市场需求代码,以便 ggplot 知道为每个区域分配不同的颜色[1]。
我们还将添加带有 method = "lm" 参数的 geom_smooth() 函数,使其为每个弹性区域建立线性模型【1】。稍后我们将制作一些专门的模型来更深入地研究这个问题。目前,这清楚地表明,需求曲线的不同部分可以有非常不同的斜率和弹性数字。
代码如下:
# Plot market demand with elasticity
ggplot(data = Market_Demand, aes(x = Market_Demand, y = Price, color = Elasticity_Zone)) +
geom_line(size = 1) +
geom_point() +
geom_smooth(method = "lm") +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0) +
ggtitle("Market Demand with Elasticity Zones") +
theme(plot.title = element_text(hjust = 0.5))
以下是输出结果:
Mac 上 RStudio 中市场需求的弹性区域截图
更深的弹性潜水
虽然在 ggplot 中使用线性模型非常有利于可视化,但我们需要制作一些专用模型来获得精确的斜率,以便以有意义的方式比较每个部分的弹性。
为此,我们将使用 lm() 函数来创建线性模型。有许多方法可以做到这一点并过滤数据,但这里的目标是尽可能清晰易读。
我们将做同样的基本过程四次
代码如下:
### Create Linear Models #### Filter Data
Zone_1_lm_data <- Market_Demand %>%
filter(Elasticity_Zone == 1)# Create linear model
Zone_1_lm <- lm(Market_Demand ~ Price, data = Zone_1_lm_data)# Create and print summary
summary(Zone_1_lm)
以下是输出结果:
Mac 上 RStudio 中弹性区域 1 的线性模型的汇总统计屏幕截图
代码如下:
# Filter Data
Zone_2_lm_data <- Market_Demand %>%
filter(Elasticity_Zone == 2)# Create linear model
Zone_2_lm <- lm(Market_Demand ~ Price, data = Zone_2_lm_data)# Create and print summary
summary(Zone_2_lm)
以下是输出结果:
Mac 上 RStudio 中弹性区域 2 的线性模型的汇总统计屏幕截图
代码如下:
# Filter Data
Zone_3_lm_data <- Market_Demand %>%
filter(Elasticity_Zone == 3)# Create linear model
Zone_3_lm <- lm(Market_Demand ~ Price, data = Zone_3_lm_data)# Create and print summary
summary(Zone_3_lm)
以下是输出结果:
Mac 上 RStudio 中弹性区域 3 的线性模型的汇总统计屏幕截图
代码如下:
# Filter Data
Zone_4_lm_data <- Market_Demand %>%
filter(Elasticity_Zone == 4)# Create linear model
Zone_4_lm <- lm(Market_Demand ~ Price, data = Zone_4_lm_data)# Create and print summary
summary(Zone_4_lm)
以下是输出结果:
Mac 上 RStudio 中弹性区域 4 的线性模型的汇总统计屏幕截图
现在我们有了每个弹性区域的线性模型的一些详细的汇总统计数据,我们需要在项目的背景下解释这些结果。
就像任何线性模型一样,我们希望检查我们的模型是否有足够高的质量来做出可靠的解释。这意味着检查所有的 p 值是否具有统计学意义,以及 R 平方值是否尽可能接近 1[1]。
当我们查看每个模型输出的系数部分和“Pr(>| t |)”列时,我们看到价格系数在所有四个模型中都是一个小于 0.05 的数字。这意味着我们可以至少 95%确定我们的结果不是偶然的[1]。事实上,我们至少可以 99%确定价格和数量需求之间的关系不是偶然的,因为这一列中的所有 p 值都小于 0.01 [1]。
取决于你问的是谁,无论是倍数还是调整后的 R 平方,0.7 或更高都是非常好的[1]。R-squared 衡量模型中自变量对因变量的解释程度[1]。在所有四种情况下,我们看到我们解释了 99%以上的因变量[1]。
考虑到这一点,我们想看看列中的【Price】行的斜率值[1]。虽然从技术上来说,把价格和数量调换一下会更合适,但这样更容易理解,而且无论如何都会让我们出于商业目的回到同一个地方[3]。
让我们来看看 4 区的最后一个模型。你应该这样理解:
价格每降低 1 个单位,需求量就会增加 540.4 个单位。
这符合需求法则,因为我们降低价格,就会有更多的需求。
一旦我们知道一切都是有意义的,并很好地解释了结果,让我们根据确凿的证据对结果进行比较。
比较结果
最简单的方法是创建一个小表,从汇总统计数据中提取斜率系数。
为此,我们将制作一个带有标记列的数据框,并以表格形式查看汇总统计数据的输出。模型的…系数[2,1]…* 部分在输出中导航,以获得汇总统计输出的第二行和第一列,即斜率值[1]。最后,为了我们的理智和一般可读性,我们将结果四舍五入到小数点后两位。*
代码如下:
*# Create table of slope coefficients for each zone
slopes <- data.frame(Zone_1_slope = round(summary(Zone_1_lm)$coefficients[2,1], 2),
Zone_2_slope = round(summary(Zone_2_lm)$coefficients[2,1], 2),
Zone_3_slope = round(summary(Zone_3_lm)$coefficients[2,1], 2),
Zone_4_slope = round(summary(Zone_4_lm)$coefficients[2,1], 2))
slopes*
以下是输出结果:
Mac 上 RStudio 中每个弹性区域的所有四个线性模型的斜率截屏
同样,是的,我知道从纯数学意义上讲,这不是一堆斜率[3]。它实际上是每单位价格变化时需求数量的变化[3]。这样更容易理解这个想法。
更新市场需求图
现在是时候通过标注单位价格需求量的变化来快速更新之前的市场需求图了,这样就可以清楚地看到发生了什么。我们需要将一些文本和数字粘贴在一起,适当地放置文本,并使用 abs() 函数来获得数字的绝对值,这样它们是正数,更容易阅读。
代码如下:
*# Plot market demand with elasticity
ggplot(data = Market_Demand, aes(x = Market_Demand, y = Price, color = Elasticity_Zone)) +
geom_line(size = 1) +
geom_point() +
geom_smooth(method = "lm") +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0) +
ggtitle("Market Demand with Elasticity Zones") +
theme(plot.title = element_text(hjust = 0.5)) +
annotate("text", label = paste("Qd change / P change:", abs(slopes$Zone_1_slope)), x = 430, y = 7, size = 3, color = "black") +
annotate("text", label = paste("Qd change / P change:", abs(slopes$Zone_2_slope)), x = 680, y = 4.5, size = 3, color = "black") +
annotate("text", label = paste("Qd change / P change:", abs(slopes$Zone_3_slope)), x = 1150, y = 2.5, size = 3, color = "black") +
annotate("text", label = paste("Qd change / P change:", abs(slopes$Zone_4_slope)), x = 1600, y = 1.5, size = 3, color = "black")*
以下是输出结果:
Mac 上 RStudio 中带有单位价格数量变化标签的市场需求图截图
那么这一切到底意味着什么呢?
价格高的时候,市场相对来说比价格低的时候更缺乏 T4 弹性。当价格从 10 美元涨到 9 美元时,我们得到的订阅需求数量的影响比从 2 美元涨到 1 美元时要小得多,因为从 2 美元涨到 1 美元时,曲线相对更有弹性。事实上,从区域 1 中的某一点到区域 2 中的某一点,所需的订阅数量相差近 14 倍。
我们需要问的真正问题是:
这如何帮助我们找到最大化总收入的地方?
好问题!让我们快速了解一下。
最高总收入
首先,我们需要为我们的市场数据创建一个列,简单地将价格乘以需求数量来获得总收入[2]。
代码如下:
*# Maximize Total Revenue
Market_Demand$Total_Revenue = Market_Demand$Price * Market_Demand$Market_Demand# Check the data
Market_Demand*
以下是输出结果:
Mac 上 RStudio 中市场需求数据的总收入屏幕截图
绘制数据
让我们画一张图,看看哪里的总收入最大化。
代码如下:
*# Plot market demand with elasticity
ggplot(data = Market_Demand, aes(x = Price, y = Total_Revenue, color = Elasticity_Zone)) +
geom_line(size = 1) +
geom_point() +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0) +
ggtitle("Total Revenue Curve for Market Demand with Elasticity Zones") +
theme(plot.title = element_text(hjust = 0.5))*
以下是输出结果:
Mac 上 RStudio 中市场数据的总收入曲线截图
查看图表,我们可以看到,在给定市场需求数据的情况下,2.50 美元的价格是总收入最高的价格,这是第三个弹性区域。这意味着,当我们把价格从免费提高到 2 美元时,我们的收入也在不断增加。我们以 2.50 美元的价格最大化总收入,总收入为 1,850 美元[2]。随着我们继续将价格从 3 美元提高到 3 美元以上,我们的收入实际上减少了!
结论
这个故事的结果是,了解市场是有好处的。我们开始为我们的 SaaS 订阅收集市场上个别公司的数据。在每个价格下他们愿意买什么?然后我们将这些数据整合到市场数据中。有趣的是发现需求曲线并不总是直线。在曲线的不同范围内,微小的价格变化会对需求量产生一系列的影响,正如我们在最后看到的,会影响总收入的最大值。
正如我在本文开头提到的,这是许多部分中的第一部分,以一种易于理解的方式专门为技术人员解释经济概念。
我希望你喜欢这篇文章。请让我知道你对未来工作的任何反馈或建议!
参考
[1] R. Kabacoff, R 在行动(第二版。) (2015),纽约州谢尔特岛:曼宁出版公司。
[2] F .米什金,《货币经济学》,银行业,&《金融市场》(第 9 版。)* (2010),马萨诸塞州波士顿:培生教育有限公司。*
[3] P .阿加瓦尔,需求的价格弹性(PED),https://www . intelligent economist . com/Price-elastic-of-Demand/
技术人员的经济学——均衡(第三部分)
使用 R 和 ggplot2 了解均衡经济学
欢迎来到技术人员经济学系列的第 3 部分!
本系列旨在帮助人们更好地理解经济学的基本原理,同时也培养使用 R 语言的技能。我注意到关于经济学有相当多的误解和完全错误的信息,所以这里的目标是澄清这些模糊的领域。
在这篇文章中,我们将探讨这样的问题:什么是均衡?如何找到均衡价格和数量?当数字计算不完美时会发生什么?我能期望获得多少收入?
本文假设你已经很好地理解了前面的两个部分,即技术人员经济学—需求(第一部分)和技术人员经济学—供给(第二部分)。这里的大部分内容都是基于这两篇文章中的代码以及对概念的解释。如果你想要完整的故事,在开始之前先看看这些。
介绍
今天,我们将利用我在 Excel 文件中创建的一些真实数据,使用 R 编程语言来探索需求和供应数据的交集。
就像前两篇文章一样,我们使用一个软件即服务(SaaS)应用程序的 10 个假设的供应商和 10 个假设的需求者,该应用程序为每个许可证收取月费。这些公司是各种规模的良好组合,并且都有不同的弹性。
这里的目标是将曲线相互叠加,找出市场在什么价格和什么数量下会达到均衡
在这项工作中,我在 Mac 电脑上使用 RStudio,带有 R Markdown (RMD)文件。
所有的数据和完成的 RMD 文件都可以在我的 GitHub 这里获得。
注:如果您使用的是 Mac,请不要打开这些带有数字的文件。它会自动改变文件的编码,R 会不高兴的。如果发生这种情况,请删除您打开的文件,并下载一份新的 Excel 文件。
我还假设您可以设法在本地机器上设置一个 R 环境。最好将所有文件放在一个文件夹中,以简化工作流程。
我们开始吧!
代码
加载库
为了完成这个项目,我们需要 readxl 和 tidyverse 包。如果您的 R 环境中没有安装它们,只需删除代码[1]中“ install.packages… ”行前的“ # ”符号。一旦安装了它们,您就不需要在您的机器上再次安装它们。
代码如下:
# Load Libraries# If you do not have readxl or tidyverse installed, uncomment the following lines
# install.packages("readxl")
# install.packages("tidyverse")require(readxl)
require(tidyverse)
检查数据导入
有时候 Excel 文件和 R 交互的时候是有气质的,尤其是 RStudio。使用下面的代码导入数据,并检查数据是否正常。
代码如下:
# Import Data
Supply_Data <- read_excel("Supply_Data.xlsx")
Demand_Data <- read_excel("Demand_Data.xlsx")# Check data import
head(Supply_Data)
head(Demand_Data)
以下是输出结果:
Mac 上 RStudio 中供应数据前六行的屏幕截图
Mac 上 RStudio 中需求数据前六行的屏幕截图
如果你导入数据,而价格和 Qs_# 或 Qd_# 不是列标签,是数据的第一行,你大概会看到类似 X1 X2 X3 等。作为列标题。如果发生这种情况,你可以遵循我在上一篇文章科技人的经济学——需求(第一部分)的“设置”部分描述的相同过程。这将向您展示如何以不同的方式导入数据,从而跟上本文。
赶上进度
一旦有了数据,就应该复制/粘贴需求和供应代码的相关部分来完成繁重的工作。请参考这两篇文章,了解以下代码块的作用。
代码如下:
# Demand first# Wrangle the data into a ggplot friendly structure
Wrangled_Data <- data.frame(Price = Demand_Data$Price, stack(Demand_Data[2:11]))
names(Wrangled_Data)[2] <- "Quantity"
names(Wrangled_Data)[3] <- "Qd_num"# Create market demand
Market_Demand <- data.frame(Price = Demand_Data$Price, Market_Demand = rowSums(Demand_Data[2:11]))# Add Elasticity zones
# 10-6.5 zone 1
# 6-4 zone 2
# 3.5-2 zone 3
# 1.5-0 zone 4
Market_Demand$Elasticity_Zone <- as.character(c(1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4))# Supply second# Wrangle the data into a ggplot friendly structure
Wrangled_Supply_Data <- data.frame(Price = Supply_Data$Price, stack(Supply_Data[2:11]))
names(Wrangled_Supply_Data)[2] <- "Quantity"
names(Wrangled_Supply_Data)[3] <- "Qs_num"# Create market supply
Market_Supply <- data.frame(Price = Supply_Data$Price, Market_Supply = rowSums(Supply_Data[2:11]))# Add Elasticity zones
# 10-5.5 zone 1
# 5-4 zone 2
# 3.5-0 zone 3
Market_Supply$Elasticity_Zone <- as.character(c(1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,3,3,3,3,3,3))
绘制均衡图
现在我们赶上了,让我们画出均衡图。
为此,我们将再次使用 ggplot。这一次有一点不同的是,代码将从第一行开始,然后一次添加一行来构建图形,而不是先将所有内容合并在一起,然后尝试用困难的方式来完成。
代码的 geom_line() 部分将声明我们使用的数据、美学,并分配几个其他样式参数。为了让它看起来更好,这段代码添加了垂直线和水平线来勾勒出轴的轮廓。我还决定用 xlim() 函数限制数据范围,因为我们实际上不会对太靠右的数据做任何事情。最后,应用一些标签。
代码如下:
# Plot the equilibrium
ggplot() +
geom_line(data = Market_Supply, aes(x = Market_Supply, y = Price), color = "darkred", size = 1) +
geom_line(data = Market_Demand, aes(x = Market_Demand, y = Price), color = "steelblue", size = 1) +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0) +
xlim(0, 1150) +
ggtitle("Market Equlibrium") +
theme(plot.title = element_text(hjust = 0.5)) +
xlab("Quantity") +
ylab("Price")
以下是输出结果:
Mac 上 RStudio 中平衡图的屏幕截图
嗯,成功了!
在经济学中,运行良好的市场在需求数量等于供给数量的平衡点上运行[2]。这通常也被称为市场清算价格,因为所有生产的数量都是需求[2]。换句话说,没有短缺,也没有过剩[2]。
目测一下上面的图,看起来我们有一个大约 6 美元的市场清算价格和大约 200 个单位的平衡数量。
让我们确认一下这些数字,再精确一点。
找出均衡数量和市场清算价格
首先,我要说的是,我们可能至少有十几种方法可以做到这一点。为了简单起见,并使本文的范围易于理解,我们将避免使用微积分,并采用一种“对谁来说足够好”的方法,这种方法无论如何都会产生几乎相同的答案。
无关注意:短语“对谁来说足够好”是引用自一个承包商的话,当我还是个孩子的时候,他为我的房子工作。这是一个小问题,但据我所知,房子仍然是完整的!
无论哪种方式,我们都将采用这种心态。
我们将从将需求和供应数据连接到一个对象开始。我是使用 inner_join() 函数和通过 Price 加入的粉丝,因为它简单。它还能确保一切正常。由于我们在每个数据集中有一个相同行数的公共列, inner_join() 基本上充当一个“拉链”函数,将数据集组合成一个干净的产品[1]。
代码如下:
# Join data together
Merged_data <- inner_join(Market_Demand, Market_Supply, by = "Price")
head(Merged_data)
以下是输出结果:
在 Mac 上合并 RStudio 中的需求和供应数据的 inner_join()函数的屏幕截图
接下来,让我们找出供给数量和需求数量之间的差异最小的地方。我们知道它们因为图形而相交,所以对应于最小差异的价格应该是我们的市场出清价格[2]。
代码如下:
# Find difference between supply and demand
Merged_data$Diff <- Merged_data$Market_Supply - Merged_data$Market_Demand
Merged_data
以下是输出结果:
Mac 上 RStudio 中带有数量差异栏的合并数据的屏幕截图
只要看一下图表,我们就可以知道,在 6 美元的价格下,我们看到的最小差异是 8 个单位。然而,如果我们有更多的数据,并且很难直观地分辨,会发生什么呢?
我们可以使用 which.min() 函数的组合来找到我们想要的最小值,在本例中是 Diff ,并使用 abs() 函数来获得Diff【1】的绝对值。绝对值函数是必要的,因为它不是像我们想要的那样给我们一个最小的差值,而是一个最大的负数,这不是我们想要的。函数末尾的逗号指定我们需要整行[1]。对于加分,试着去掉它,看看有什么不同。
代码如下:
# Find row of minimum difference
min_diff_1 <- Merged_data[which.min(abs(Merged_data$Diff)),]
min_diff_1
以下是输出结果:
Mac 上 RStudio 中需求和供应差异最小的行的屏幕截图
修改情节
接下来,我们将从几个方面修改前面的情节。首先,让我们更改 xlim() 函数中的值,以便我们可以放大到更接近交叉点的位置。第二,我们可以在市场结算价格和数量上添加一些线,以便更好地可视化我们的数据。为最小差异行创建专用对象的一个优点是,我们可以在这里引用它,而不必手动输入数字或以另一种方式重复计算。
代码如下:
# Add lines to previous graph based on the min_diff_1 numbers# Plot the equilibrium
ggplot() +
geom_line(data = Market_Supply, aes(x = Market_Supply, y = Price), color = "darkred", size = 1) +
geom_line(data = Market_Demand, aes(x = Market_Demand, y = Price), color = "steelblue", size = 1) +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0) +
xlim(0, 300) + ### ZOOM IN A BIT ###
ggtitle("Market Equlibrium") +
theme(plot.title = element_text(hjust = 0.5)) +
xlab("Quantity") +
ylab("Price") +
### NEW LINES ###
geom_hline(yintercept = min_diff_1$Price) +
geom_vline(xintercept = min_diff_1$Market_Demand) +
geom_vline(xintercept = min_diff_1$Market_Supply)
以下是输出结果:
Mac 上 RStudio 中带有市场清算价格和近似平衡数量线的平衡图的屏幕截图
那么,为什么有两条竖线而不是一条呢?
事实证明,我们的数据精度导致了一个小问题,我们没有一个完全完美的交集。我选择将两者都放在图表上,以使这一点变得明显。
这就是说,我们应该对市场出清价格为 6 美元,真正的均衡数量在 190 年代的某个地方感觉良好[2]。
总收入
经济学中最直接的计算方法之一是总收入,因为它就是价格乘以单位总数[2]。当处于均衡时,它是市场清算价格和在该价格下的需求量[2]。
对我们来说,我们将再次引用 min_diff_1 对象,因为它包含我们的市场清算价格和数量。在计算中,我选择用 mean() 函数对需求和供应数据进行平均,然后乘以价格。这使我们在该市场的总收入达到 1,134 美元。
代码如下:
# Calculate total revenue
total_revenue <- min_diff_1$Price * mean(min_diff_1$Market_Demand, min_diff_1$Market_Supply)
total_revenue
以下是输出结果:
Mac 上 RStudio 中按市场出清价格计算的市场总收入截图
比较和对比结果
请记住,在本系列的前两部分中,供应商希望以更高的价格销售更多的产品。
对于我们拥有的数据,当以每单位 10 美元的价格销售时,供应方的最大总收入是 9,840 美元。
在需求方面,我们的最高总收入为 1,850 美元,单价为 2.50 美元。
当我们在真实的市场场景中结合我们的数据时,市场的妥协变得很明显。市场出清价格是商品和服务的供需双方在中间相遇的地方[2]。当然,双方都没有达到理想或理论上的最大值,但这就是市场的本质。
额外材料—用线性模型预测平衡
我们有非常接近的数据,这当然很好,但是如果我们研究一些更理论化的东西,会发生什么呢?从这篇文章和前两篇文章中我们知道,我们有不同的弹性区域。从图形上看,我们可以看到非常接近 6 美元的价格是正确的,但如果我们只有几个数据点,并对线的斜率有很好的猜测,会怎么样呢?
我们将借用第一篇文章中的一些代码,创建一些线性模型,看看它们在哪里相交。这里重要的是,我们的模型解释了 99%以上的因变量,预测能力非常重要,因为我们在以下两个模型中的 p 值都非常小[1]。
关于 R 平方值和 p 值的含义的更完整的讨论,请参考前两篇文章,因为我在这里假设当我引用这些值时,您知道我的意思。
当我们查看我们的 min_diff_1 对象时,我们可以看到需求在弹性区 2 下降,而供应在弹性区 1。考虑到这一点,我们只需要建立线性模型。
先说供给。
代码如下:
# Create Supply linear model# Filter Data
supply_lm_data <- Market_Supply %>%
filter(Elasticity_Zone == 1)# Create linear model
Supply_Zone_1_lm <- lm(Market_Supply ~ Price, data = supply_lm_data)# Create and print summary
summary(Supply_Zone_1_lm)
以下是输出结果:
Mac 上 RStudio 中 1 区供应数据线性模型的汇总统计屏幕截图
需求是下一个。
代码如下:
# Create Demand linear model# Filter Data
demand_lm_data <- Market_Demand %>%
filter(Elasticity_Zone == 2)# Create linear model
Demand_Zone_2_lm <- lm(Market_Demand ~ Price, data = demand_lm_data)# Create and print summary
summary(Demand_Zone_2_lm)
以下是输出结果:
Mac 上 RStudio 中 2 区需求数据线性模型的汇总统计屏幕截图
接下来,我们将创建一个快速的数字序列作为新的价格数据。我将价格从 5.50 美元调整到 6.50 美元,因为这个范围正好符合供给和需求数据的弹性区域。我们将它增加 0.01 美元,这样我们可以得到更精确的结果。
代码如下:
# new price data
new_price_data <- data.frame(Price = seq(5.5, 6.5, by = 0.01))
之后,我们将使用经典的代数公式 y=mx + b 来整合我们的新数据。这将把我们的线性模型的截距加上斜率乘以价格加到一个大数据框架中。我们也可以用 round() 函数将这个数字四舍五入到小数点后 0 位,因为如果你考虑一下,出售一小部分 SaaS 订阅是没有多大意义的。
代码如下:
# Use coefficient and intercept data to fill in the blanks# Supply first
new_price_data$supply <- round(Supply_Zone_1_lm$coefficients[1] + (Supply_Zone_1_lm$coefficients[2] * new_price_data$Price), 0)# Demand next
new_price_data$demand <- round(Demand_Zone_2_lm$coefficients[1] + (Demand_Zone_2_lm$coefficients[2] * new_price_data$Price), 0)
最后,我们将做同样的基本减法,得到需求和供给之间的差异的 Diff 列,就像我们之前做的那样。我们也可以检查数据,以确保它是正确的。
代码如下:
# Find difference between supply and demand
new_price_data$Diff <- new_price_data$demand - new_price_data$supply# Check the data
head(new_price_data)
以下是输出结果:
Mac 上 RStudio 中每个新价格的预测供应、需求和差值表的屏幕截图
总结一下,我们将再次找到最小的绝对值差,以获得价格和数量。
代码如下:
# Find row of minimum difference
min_diff_2 <- new_price_data[which.min(abs(new_price_data$Diff)),]
min_diff_2
以下是输出结果:
Mac 上 RStudio 中预测数据的最小绝对值差异的屏幕截图
这里的结果非常相似。预测值给出了 6.02 美元的市场清算价格和 184 或 185 的均衡数量,这与真实数据非常接近。
在商业现实中,只要把价格定为 6 美元,并对结果感到满意,这就是巨大的支持。
结论
读完这三篇文章后,希望你对供给、需求和均衡在经济学意义上的含义有了更好的理解。具体到这里的均衡,我们的工作更多的是图形化的,而不是数学化的,因为我们在以前的文章中做了大量的数字运算。幸运的是,我们已经为 6 美元的市场出清价格建立了一个坚实的案例,并且很有可能销售不到 200 单位的 SaaS 产品。在现实生活中,这些数字可能会在两个方向上有所波动,但对于从个人原始数据开始的均衡分析来说,这肯定是一个现实的结果,一直到了解一项服务的整个有效运营市场。
参考
[1] R. Kabacoff, R 在行动(第二版。) (2015),纽约州谢尔特岛:曼宁出版公司。
[2] F .米什金,《货币经济学》,银行学,&《金融市场》(第 9 版。) (2010),马萨诸塞州波士顿:培生教育有限公司。
技术人员的经济学——供应(下)
使用 R 和 ggplot2 了解需求经济学
欢迎来到技术人员经济学系列的第二部分!
这个项目旨在帮助人们同时学习基本的经济学概念和 R 编程。我注意到关于经济学有相当多的误解和完全错误的信息,所以这里的目标是澄清这些模糊的领域。
什么是供给?谁提供东西?供应量和供应量之间有什么区别?我应该对我的商品或服务做多少评价?怎么才能算出最大总收入?
我将引用我以前的文章技术人员的经济学——需求(第一部分)中的许多观点,所以在开始这个项目之前,请确保您已经看过了。我将把这篇文章作为一个独立的项目来写,但是随着时间的推移,这个系列将建立在它自己的基础上。
介绍
今天,我们将使用 R 编程来分析和可视化我在 Excel 文件中创建的一些真实数据,从而探索供应方面的概念。
我们将使用 10 家假设的公司来分析对我们假设的新软件即服务(SaaS)应用程序的需求,该应用程序对每个许可证收取月费。这里有各种各样的公司,从小型到大型,他们愿意以什么价格出售多少许可证。
然后,我们将检查市场供应以及打破需求弹性的概念,试图找到我们最大化总收入的地方。
在这项工作中,我在 Mac 电脑上使用 RStudio,带有 R Markdown (RMD)文件。
所有的数据和完成的 RMD 文件都可以在我的 GitHub 这里获得。
注意:如果您使用的是 Mac,请不要打开带有数字的文件。它会自动改变文件的编码,R 会不高兴的。如果发生这种情况,请删除该文件并下载一份新的 Excel 文件。
我还假设您可以设法在本地机器上设置一个 R 环境。最好将所有文件放在一个文件夹中,以简化工作流程。
我们开始吧!
代码
加载库
为了完成这个项目,我们需要 readxl 和 tidyverse 包。如果您的 R 环境中没有安装它们,只需删除代码[1]中“ install.packages… ”行前的“ # ”符号。一旦安装了它们,您就不需要在您的机器上再次安装它们。
代码如下:
# Load Libraries# If you do not have readxl or tidyverse installed, uncomment the following lines
# install.packages("readxl")
# install.packages("tidyverse")# Load Libraries
require(readxl)
require(tidyverse)
检查数据导入
有时候 Excel 文件和 R 交互的时候是有气质的,尤其是 RStudio。使用下面的代码导入数据,并检查数据是否正常。
代码如下:
# Import Data
Supply_Data <- read_excel("Supply_Data.xlsx")# Check data import
head(Supply_Data)
以下是输出结果:
Mac 上 RStudio 中供应数据前六行的屏幕截图
如果您导入数据,并且价格和 Qs_# 不是列标签,而是数据的第一行,您可能会看到类似于 X1 X2 X3 等内容。作为列标题。如果发生这种情况,你可以遵循我在上一篇文章科技人的经济学——需求(第一部分)的“设置”部分描述的相同过程。这将向您展示如何以不同的方式导入数据,从而跟上本文。
快速测试图
做一个快速的图表总是一个好主意,只是为了让数据看起来很好,并且是合作的。它不一定要漂亮,但它可以帮助早期诊断问题。因为我们在看供给曲线,我们应该看到一个总的趋势,即根据供给定律,随着价格的增加,供给量(Qs_#)值会增加。让我们选择一家假设的公司来看看。
代码如下:
# Test plot
plot(Supply_Data$Qs_2, Supply_Data$Price, type = "l", main = "Test Plot", xlab = "Quantity", ylab = "Price")
以下是输出结果:
快速绘制其中一个数量列与价格的关系图,以便在 Mac 上检查 RStudio 中的数据
为了加分,你可以试着改变公司编号,自己制作不同公司的图表。我在这里选择了公司 2,但 1 到 10 之间的任何数字都可以,并给出不同的曲线。
绘制所有单个供应曲线
好代码的美妙之处在于它可以被快速、轻松地重用和修改。为了实现绘制所有单个供应曲线的目标,我们将在 ggplot2 [1]内的 facet_wrap() 函数内结合数据框对象类使用相同的 stack() 函数。重命名列有助于我们的理智和可读性,因为 R 会自动将列重命名为我们不希望它们被称为[1]的名称。
我们这样做是因为 ggplot2 以某种方式喜欢数据,所以我们可以获得更好的数据结构来利用它的函数,而不是试图让函数直接做一些它们不打算做的事情。
代码如下:
# Wrangle the data into a ggplot friendly structure
Wrangled_Supply_Data <- data.frame(Price = Supply_Data$Price, stack(Supply_Data[2:11]))
names(Wrangled_Supply_Data)[2] <- "Quantity"
names(Wrangled_Supply_Data)[3] <- "Qs_num"# Check the data
head(Wrangled_Supply_Data)
以下是输出结果:
Mac 上 RStudio 中 ggplot 友好结构中的前六行争论和标记供应数据
既然我们已经将数据整理成了一个合适的结构, facet_wrap() 将会更好地与我们合作。
代码如下:
# Plot the individual supply curves
ggplot(data = Wrangled_Supply_Data, aes(x = Quantity, y = Price)) +
geom_line(color = "darkred", size = 1) +
geom_point(color = "darkred") +
facet_wrap(. ~ Qs_num)
以下是输出结果:
Mac 上 RStudio 中数据集中所有单个电源曲线的绘图屏幕截图
让我们思考一下,在这个市场上有许多公司提供类似的 SaaS 解决方案的背景下,这意味着什么。这 10 家公司中的每一家在每一价格下都有不同的供应量组合[2]。
根据供应定律,随着价格的上涨,供应商希望供应更多的单位[2]。直觉上这是有道理的。做生意的全部目的就是赚钱,所以以更高的价格卖出更多的产品将是任何追求利润的企业的计划。我们反映了每个公司的情况。
我们也看到,我们的公司通常只会在某个价格后才开始供货。追求利润的企业不是慈善机构,所以他们只会在对公司来说值得的时候才开始供应设备。
企业,尤其是那些在竞争市场中提供 SaaS 服务的企业,在开始销售时有一定的成本水平,并且随着时间的推移成本会增加,这就是为什么需要更高的价格来证明提供更多单位的合理性[2]。
市场供应
就像上一篇文章中的市场需求一样,市场供给是所有个体企业供给曲线的总和[2]。对于每个价格,我们将所有 10 家公司的数量加在一起,得到市场供应曲线的最终数字[2]。
代码如下:
# Create market supply
Market_Supply <- data.frame(Price = Supply_Data$Price, Market_Supply = rowSums(Supply_Data[2:11]))# Check the data
head(Market_Supply)
以下是输出结果:
Mac 上 RStudio 中的市场供应截图
绘制市场供应图
我们将继续使用 ggplot 并添加一些样式组件来可视化市场供应。
代码如下:
# Plot market supply curve
ggplot(data = Market_Supply, aes(x = Market_Supply, y = Price)) +
geom_line(color = "darkred", size = 1) +
geom_point(color = "darkred") +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0) +
ggtitle("Market Supply Curve") +
theme(plot.title = element_text(hjust = 0.5))
以下是输出结果:
Mac 上 RStudio 中的市场供应图截图
就像第一篇文章中的市场需求曲线一样,我在曲线上看到了三个不同的区域,价格的变化以显著不同的方式改变了供应量。
这就引出了弹性的概念。
弹性
弹性的基本思想就是决定每单位价格变化时的供给量变化[3]。在关于需求的第一篇文章中,数学解释得更加详细。我们现在要做的是看看曲线的不同区域。
当供给曲线相对无弹性时,意味着单位供给量的变化小于价格的变化【3】。当供给曲线相对弹性时,单位供给量的变化大于价格的变化【3】。
这条曲线有三个不同的区域。在开始时有一个相对无弹性的区域,在过渡发生的中间部分,在较高的量处有一个相对有弹性的区域[3]。
同样,就像按需文章一样,我指定了弹性区域来简明地说明这一点。
代码如下:
# Add Elasticity zones
# 10-5.5 zone 1
# 5-4 zone 2
# 3.5-0 zone 3Market_Supply$Elasticity_Zone <- as.character(c(1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,3,3,3,3,3,3))
Market_Supply
以下是输出结果:
Mac 上 RStudio 中弹性区域的市场供应截图
这里我最喜欢的一个小技巧是用 as.character() 函数将弹性区域指定为字符而不是数字。这将使 ggplot 与区域合作,因为它意识到它们不是用来做数学运算的数字,而是本质上是分类的[1]。
用弹性区域绘制市场供给图
我们将通过在 aes() 函数中添加 color = Elasticity_Zone 来增加之前的市场供应代码,以便 ggplot 知道为每个区域分配不同的颜色[1]。我们还将添加带有 method = "lm" 参数的 geom_smooth() 函数,使其为每个弹性区域建立线性模型[1]。
代码如下:
# Plot market supply with elasticity
ggplot(data = Market_Supply, aes(x = Market_Supply, y = Price, color = Elasticity_Zone)) +
geom_line(size = 1) +
geom_point() +
geom_smooth(method = "lm") +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0) +
ggtitle("Market Supply with Elasticity Zones") +
theme(plot.title = element_text(hjust = 0.5))
以下是输出结果:
Mac 上 RStudio 中市场供应的弹性区域截图
线性模型和弹性
由于我们在关于需求的文章中研究了使用 lm() 函数的线性模型的细节,这次我们将使用使用 glm() 函数的广义线性模型来检查关于三个弹性区域的质量。
让我们看一下三个弹性区域的代码和输出,以及整个曲线的广义线性模型,以便更好地理解这个概念。
代码如下:
### Create Linear Models #### Filter Data
Zone_1_glm_data <- Market_Supply %>%
filter(Elasticity_Zone == 1)# Create linear model
Zone_1_glm <- glm(Market_Supply ~ Price, data = Zone_1_glm_data)# Create and print summary
summary(Zone_1_glm)
以下是输出结果:
Mac 上 RStudio 中弹性区域 1 的广义线性模型的汇总统计屏幕截图
代码如下:
# Filter Data
Zone_2_glm_data <- Market_Supply %>%
filter(Elasticity_Zone == 2)# Create linear model
Zone_2_glm <- glm(Market_Supply ~ Price, data = Zone_2_glm_data)# Create and print summary
summary(Zone_2_glm)
以下是输出结果:
Mac 上 RStudio 中弹性区域 2 的广义线性模型的汇总统计数据截图
代码如下:
# Filter Data
Zone_3_glm_data <- Market_Supply %>%
filter(Elasticity_Zone == 3)# Create linear model
Zone_3_glm <- glm(Market_Supply ~ Price, data = Zone_3_glm_data)# Create and print summary
summary(Zone_3_glm)
以下是输出结果:
Mac 上 RStudio 中弹性区域 3 的广义线性模型的汇总统计屏幕截图
代码如下:
# Compare against a GLM for the entire market supply# Create linear model
All_supply_glm <- glm(Market_Supply ~ Price, data = Market_Supply)# Create and print summary
summary(All_supply_glm)
以下是输出结果:
Mac 上 RStudio 中所有市场供应的广义线性模型的汇总统计屏幕截图
我们想看看所有这些输出中的两个组成部分。
首先,价格系数的估算栏告诉我们直线的斜率。简单地说,数字越大,曲线就越没有弹性[1][3]。数字越小,曲线相对弹性越大[1][3]。当参考前三个输出时,我们对曲线[1]不同部分的供应量有很好的预测能力。**
其次,我们想看看底部的 AIC (阿凯克信息准则)值。AIC 越接近 0,我们的模型就越适合。在前三个弹性区,我们有极小的 AIC 值,表明模型与线[1]密切相关。当试图获得所有数据的线性模型时,AIC 值要高 10-15 倍。这意味着我们有一个明显更差的拟合[1]。
我们可以看到,在处理非教科书数据时,假设整个市场的弹性是多么荒谬。
代码如下:
# Look at the linear model line on the graph without looking at elasticity of different parts of the curve
# Plot market supply with elasticity
ggplot(data = Market_Supply, aes(x = Market_Supply, y = Price)) +
geom_line(size = 1) +
geom_point() +
geom_smooth(method = "lm", color = "darkred") +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0) +
ggtitle("Linear Model of Market Supply without Elasticity Zones") +
theme(plot.title = element_text(hjust = 0.5))
以下是输出结果:
Mac 上 RStudio 中市场供应数据的线性模型可视化效果不佳
最大化总收入
与我们在需求文章中得到的答案不同,从供应商的角度来看,最大化总收入就是以更高的价格销售更多的产品[3]。当我们看一看在每个价格水平上产生的总收入时,我们可以看到这一思想反映了供给定律及其预测[3]。
代码如下:
# Maximize Total Revenue
Market_Supply$Total_Revenue = Market_Supply$Price * Market_Supply$Market_Supply# Check the data
Market_Supply
以下是输出结果:
Mac 上 RStudio 中市场供应数据的总收入屏幕截图
绘制总收入曲线
当可视化这些数据时,很明显,一旦我们达到供应曲线的相对弹性部分,随着我们以更高的价格销售更多的单位,总收入会显著增加[3]。
代码如下:
# Plot market supply with elasticity
ggplot(data = Market_Supply, aes(x = Price, y = Total_Revenue, color = Elasticity_Zone)) +
geom_line(size = 1) +
geom_point() +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0) +
ggtitle("Total Revenue Curve for Market Supply with Elasticity Zones") +
theme(plot.title = element_text(hjust = 0.5))
以下是输出结果:
Mac 上 RStudio 中市场数据的总收入曲线截图
结论
这里的要点是,市场是由许多公司组成的[2]。这些企业都有自己的能力在整个市场内生产商品和服务[2]。由于成本和定价的诸多因素,大多数公司只有在价格足够高时才会开始生产[2]。
供应法则告诉我们,随着价格上涨,供应商将供应更多的单位。当我们根据弹性将整个市场供给曲线分解成不同的部分时,我们可以看到,在曲线相对无弹性的部分提高价格对供给量的影响很小[3]。在曲线相对更有弹性的部分,供应商愿意以相对较小的价格增长供应更多的单位[3]。
综上所述,我们发现“供应”一词有细微差别。希望在本文结束时,您能更好地理解供应方面的关键术语,以及供应商必须如何响应市场。在本系列的下一部分中,我们将根据这篇文章和上一篇关于需求的文章来看看供应和需求之间的相互作用!
参考
[1] R .卡巴科夫, R 在行动(第 2 版。) (2015),纽约州谢尔特岛:曼宁出版公司
[2] F .米什金,《货币经济学》,银行业,&《金融市场》(第 9 版。) (2010),马萨诸塞州波士顿:培生教育公司。
[3]明尼苏达大学, 5.3 供给价格弹性(未注明)https://open . lib . umn . edu/principles economics/chapter/5-3-供给价格弹性/
房屋所有权经济学深潜
评估购房情景和相关的投资机会成本。
照片由 Breno Assis 在 Unsplash 上拍摄。
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
第一部分的经济学置业深潜。
引言。
对于那些以前考虑过或正在考虑买房的人来说,这篇文章旨在帮助你定制你的场景,并努力实现你的选择。我希望你会发现这里提供的金融模型(选择“查看原始数据”或点击下载),对你评估潜在的购房选择很有用。在这篇文章和这个模型的帮助下,你将更好地理解与房屋所有权相关的成本,以及不将首付和持续维护成本投资于其他资产(如被动市场 ETF)的内在机会成本。
鉴于我对投资的浓厚兴趣,以及我和妻子在 2018 年购买了一套房子,我最近修改了我的方法,以模拟我们的每月支出、长期储蓄计划,并预测我们将不得不分配给我们家庭投资策略的额外资金。此外,随着新冠肺炎局势的持续,这个话题很及时,因为更多的千禧一代现在正在考虑拥有自己的房子。这在很大程度上是由于许多人经历了不断发展的观点,考虑到对原地住所的要求,预计从大城市向郊区/住宅区的迁移,以及对许多家庭负担得起的东西越来越多的渴望,例如院子和更好的 WFH 办公空间。
在这篇文章中,我提供了背景和一个基于场景的模型,您可以用它来评估不同的房屋购买选项,包括可变的购买价格、首付金额和贷款条款等。基于场景的模型具有灵活的输入,允许你根据你当前的收入、月支出、个人财务状况和投资偏好进行定制。
请注意,该模型尚未考虑所有因素,例如 1)您是否应该再融资以及如何评估多个选项,2)它没有提供完整的租金与购买分析(我链接到一个有用的资源,它在房屋所有权 IRR 中考虑了净经常性成本),3)评估最常见的 15 年和 30 年固定贷款类型,但不评估其他贷款类型,例如, ARM 和 4)它没有考虑承担 PMI(低于 20%的首付)和消除 PMI,一旦贷款价值比成为<= 80%. In true product management fashion, I’ll iterate on future posts if there’s enough interest for features like this.
个人痛点和构建此基于场景的模型的原因。
虽然有许多有用的在线资源可以帮助你做出购房决定,其中一些我将在稍后分享,但我认为这篇文章的独特之处在于,它将这些分析向前推进了几个步骤,并可以根据你的决策集进行个性化。这篇文章分享了一个框架,让你在权衡投资房产还是其他潜在投资时,思考相关的机会成本。换句话说,根据你的个人假设,它将帮助你预测出你没有投入大房子的钱在市场上的回报(或你选择的其他资产);并允许你测试购买某一特定房屋与将资金投资于其他地方相比,你的情况更好/更差。
在我将根据对这篇文章的兴趣完成的后续工作中,我的计划是再次转向模式分析(这里的老例子)。在第 2 部分中,您将进一步提高您的数据科学分析和仪表板开发技能,创建一个交互式仪表板,它将您的财务模型根据您的个性化输入生成的各种场景绘制成图表。对于未来帖子,该模型将生成一个 CSV 文件,该文件可以用作交互式模式分析仪表板的平面文件数据源。
在这篇文章之后,我的其他相关文章进一步讨论了利用 Python 建立投资系统,包括:
- 第 1 部分:从 Yahoo!Jupyter 笔记本中的财务 API
- 第 2 部分:扩展第 1 部分的分析和可视化,提供获取生成的数据集所需的代码,并在 Dash by Plotly (Dash) web 应用程序中将它们可视化;
- 第三部分:建立在股票投资组合分析和 Dash by Plotly 方法的基础上,了解你的总股东回报(TSR),包括股息,并跟踪类似 Robo Advisor 的投资组合。
披露:本帖内容不应被视为投资建议。过去的表现不一定代表未来的回报。我写的是一般性的例子,并展示了如何评估家庭购买场景和将部分/全部资本分配给其他投资机会的相对机会成本。你应该向你的财务顾问提出所有与投资相关的问题,并对本文中提到的任何投资进行尽职调查。因此,我对使用本文中描述的方法可能遭受的任何损失不承担任何责任,并且在此明确否认任何此类责任。
在房屋所有权经济学上变得更聪明。
正如在简介中提到的,我的方法有四个限制(我知道):1)不评估再融资,2)没有完整的租金与购买分析,3)只关注固定利率抵押贷款(例如,15 年和 30 年)和 4)模型不考虑 PMI 情景。下面我分享解决# 1 和# 2 的资源。如果根据反馈对第四点感兴趣,那么我会考虑更新模型,加入 PMI。我的个人情况没有涉及 PMI,但这个决定是个人的,如果人们需要额外的指导,我会重新评估。
再融资评估。我真的很喜欢 Zillow 的所有工具,并且发现他们的再融资计算器在很高的层面上很有帮助,因为我已经评估了潜在的再融资。作为一般指导,简短的经验法则是了解你的成交成本是多少,也就是你完成再融资的费用是多少;假设这些是 2000 美元。然后看看你每月的储蓄和当前的月供;假设每月 100 美元。这意味着你需要大约 20 个月的时间(每月节省 2000 美元)才能赚回你的前期再融资成本。不用说,你应该在你的房子里呆 20 个月以上,这才开始有意义。
租与买。在考虑租房还是买房时,我相信 Travis Devitt 整理了一个有用的资源,这形成了我的一些想法,并帮助我更明智地考虑:链接到 Travis 的推文。
资源。在你开始阅读本帖中的模型之前,我建议你通读下面的前两个资源,以便更好地掌握房屋所有权的经济学和途径。值得注意的是,改善职位是非常详细和有益的;我用这篇文章中的数据建立了我的模型的几个基本假设。最后一个资源展示了美国持续存在的房屋所有权差距的数据和地址。不幸的是,我不是专家,也不知道所有的答案,但我愿意为事业做出贡献,并尽我所能提供帮助/答案,以支持缩小这一差距。请随时在推特上联系我, @kevinboller ,或者给这个帖子留下回复,如果你有什么原因建议我去调查,或者有什么问题我可以帮助回答。
- 财富前线家居规划指南。
- 改善——买房是一项好的投资吗?
- 关于美国房屋所有权差距的文章。
使用基于场景的模型。
输入工作表。
当您打开模型时,您将从输入工作表开始,该工作表将驱动整个过程中的其余公式。每月模型表上的时间表提供了 10 年的预测。如果你愿意,你当然可以进一步延长,但我很难相信普通人会做出 30 年的决定,我更喜欢评估更短的时间段;这尤其是因为所有的模型都是错的,试图预测未来 30 年的模型可能比未来 10 年更错。
输入表上的 C2 单元是整个模型中最重要的单元。此表中 C 列中的所有内容也不应修改,因为输入将根据在 C2 选择的选定方案进行填充,这将从 C 列的第 1 列扩展到第 n 列。在 C 列右侧的列中,如果愿意,您可以在右侧添加更多方案,您可以根据正在评估的方案更改假设。请注意,任何蓝色字体的单元格都意味着它们可以被修改,而任何黑色字体的单元格都不应该被修改,因为它们是基于公式的,并且与场景无关。虽然提供的场景都是积极的情况,例如,3.2%的房屋升值,你当然可以用多种不同的方式评估同一场景。例如,也许你想比较 3.2%的年房屋升值和 7%的年投资回报与 0%的房屋升值和 4%的投资增长的基本情况,以查看随着时间的推移对你的调整后净值的影响。
要点:始终要认识到,当您对场景 1-4 进行任何调整时,您应该始终返回并循环通过单元 C2 中的场景—将 1、2、3、4 输入到 C2,以便循环通过这些场景,并让它们的输入流过模型;一旦你习惯了剩下的工作表,这一点就会变得很明显。
如果你读过上面提到的参考资料,那么购房 细节和贷款细节部分应该很简单。在 D-G 列中,我包含了 4 个模板化的场景。收入和费用具有占位符值,应进行调整以反映您的个人收入和费用。我会输入税后收入数字,这样你就能更好地估算出扣除每月支出后的现金流;以及在支付这些费用后你可以用来投资的资本。对于 HOA 之后的剩余支出,比如房屋维护,我建议保持原样,因为它们是基于《改善邮报》的数据。同样的建议适用于房屋销售输入假设,包括销售和成交成本。
对于的投资表现,投资%的超额现金意味着,对于你在支付每月费用后保留的钱,你会将其中的多少投资于被动型 ETF、股票等。然后你必须估算一下你的名义回报率,我把它定为 7%。你可以选择比这更积极/更不积极。你的可用现金储备,你可能不需要,是在你需要更多现金来支持某个月的支出(支出超过收入)时留出的钱;如果你的月支出超过收入,但你在一年中管理现金流,预计有更多的现金流入,例如,RSU 每年两次授权,你可能会这样做;但这不一定是明智的,也不可能适用于大多数人。
净值输入,最后一部分,你将如何直接比较你的家庭投资和其他投资,以查看对你的净值的影响。同样,每年 3.2%的房屋升值是一个改善后的假设。首付机会成本是指,在你支付的首付比基础方案(总是在 D 列有基础)多的情况下,我们将扣除这笔资本如果投资在其他地方将会得到的回报(而不是用于更大的首付)。由于额外的首付优势反映在你购买更大的房子和/或支付更多预付款的情况下的房屋价值回报中,这将显示你相对于基础的净回报。在比较具有更高前期房屋成本的场景时,它还应该对所有场景进行比较。
月度模型工作表。
在 C1 单元格中,您将看到基于您在输入工作表中输入到 C2 的方案进行评估的当前方案。该模型显示了 10 年间的月度细分,并将这些细分累计到这 10 年的年度总计。第 37 行显示的是税前净营业利润,这是你的税后收入,并扣除你的每月开支。虽然我建议输入税后收入,但电子表格不能说明你的实际纳税情况;因此,我称之为税前,因为当你申报/纳税时,会发生进一步的调整。下面是你的债务偿还额(第 45-49 行)和一个时间表,其中列出了将投资的多余现金、这些投资的预计回报以及将随着时间推移而积累的现金储备(未投资的资金)。
你会在第 65-67 行看到你的可投资现金随着时间的积累。对于相关的较高成本场景,通过购买较小的房屋/支付较少的首付款,你本可以获得回报的机会成本也会以同样的方式随着时间的推移而增值。值得注意的是,这种模型中的投资回报提供了一个简化的、线性的视角,来观察你的资金随时间的增长。没有一项投资会以你的年预期回报率除以 12 个月来线性增长;此外,由于这是一种美元成本平均法,即当你每月有可用资本时进行投资,你的实际回报将比简化的模型框架表现出更大的波动性。无论如何,你不应该陷入月度回报,并认识到 1)平均而言,你的可投资资产(住房和 ETF 等)每年都会升值,2)这个模型旨在帮助你采取更长远的观点。理想情况下,考虑到交易和结算成本中的摩擦,在决定搬家/购买不同的房子之前,你会给自己留有 5 到 10 年的时间。
一段时间内的净值首先评估房屋净值的增长。这是由每年房屋升值的投入(根据投入的每月增长率进行调整)和基于抵押贷款条款的债务偿还所驱动的。为了最终确定净值计算,扣除了超出基本方案的额外首付款,增加了投资增长,您可以手动输入您想要的任何额外资产和负债。我个人的模型时间表比这个更详细,包括退休资产(Roth,401k 等。).准备好之后,如果你想了解你的净资产的完整情况,以及这些账户的预计贡献和随时间的相关增长,你应该考虑将这些构建到你的模型中。
虽然房屋净值随着时间的推移而增长,增加了你的总净值,但《改善》这篇文章很好地强调了“计算投资回报的问题”。为了简洁起见,除了房屋升值之外,还有三个核心驱动因素会影响你的房屋投资回报:1)交易成本,2)现金流,包括持续成本(注意,这些都反映在我们的模型中,见投入工作表中的第 49 行),以及杠杆,又称抵押贷款,增加了上行收益,但也增加了下行风险。因此,为了进行真正的比较,在图表和经常性成本+ IRR 工作表中,我们将看到您需要如何扣除估计的交易成本,以反映您的真实净值和您的住宅投资的预计 IRR。
图表工作表。
在图表工作表上,我们比较了前 5 年期间跨场景的一些核心指标。如果您对开发和扩展模型有所了解,那么将这一时间延长到 10 年或更长时间(如果您进一步扩展模型的话)应该很简单。
在第一张图中,我们比较了不同情景下的预计净营业利润(NOP,收入减去费用)。在这种情况下,您可以看到场景 1 中的 NOP 最大,场景 4 中的 NOP 次之。在场景 4 中,您选择支付与场景 1 相同的房屋,但是您选择了 15 年期抵押贷款而不是 30 年期抵押贷款。每个人都有自己的看法,但我赞同里克·埃德尔曼的 30 年抵押贷款理论——我更喜欢更大的流动性和多样化。使用这些情景,您可以在情景 2 中看到,您将拥有情景 1 中大约 70%的 NOP,在情景 3 中,您将拥有情景 1 中大约 35%的 NOP(在这种情景中,您购买的房屋价格是情景 1 的 3 倍)。
NOP,跨场景税前对比。
在第二个图表中,转到单元格 K101,该图表显示了所选方案的投资详细信息,下表对这些方案进行了细分。给定回报的线性度和关于投资多少(80%)的相同假设,您将看到您的总投资余额+方案 1 之后的超额现金将反映方案之间的 NOP 差异。您可以决定是否要修改方案的假设;例如,如果你买了一个较小的房子,也许你会将更多的资金用于投资(90%?)和/或更积极地进行其他投资,期望回报率高于 7%。
在第三张图中,转到 J160,你会在第二个 y 轴上看到你一段时间内的净值和债务偿还额。对于前三种情况,现有贷款余额占原始抵押贷款的百分比,以及房屋净值占房屋估价的比例相对一致。唯一的区别是,我已经假设了更大的房屋购买量/更大的借款额会有更高的利率。你还会看到,在情景 1 中,你的房屋净值反映了你净资产的 30%,在情景 2 和 3 中增加到约 60%和 90%+,在情景 4 中达到 40%(其中你选择了 15 年的抵押贷款;高于给定的场景 1)。虽然你可能会在第 O 列(单元格 0160)中得出结论,你对各种情景都不感兴趣,你的净值也相对相同,但这并不完全正确。在扣除预计结算成本(见 U161)后,预计结算成本估计了你出售房屋可获得的净实现价值,你会看到,5 年后,情景 2 和 3 实际上落后于情景 1 的调整后净值;而在场景 1 和场景 4 中,你实际上处于相同的位置(相同的购买,不同的抵押期限)。情景 1 和情景 4 之间的紧密联系表明,根据你的投资机会集,你相对不愿意在你的房子(期限较短的抵押贷款)上投资更多,而不是在多样化的 ETF 上投资更多(假设 7%的年化回报率)——税收后果,如抵押贷款利息的扣除或股息税,没有被考虑到这个框架中,但可能会影响这个比较。关于如何评估你的潜在房屋投资回报的最终细节,我们将进入最后一张工作表。
经常性成本+ IRR 工作表。
如前所述,改善的文章是很详细的,非常有助于变得更加了解房屋所有权的机制和含义。然而,读完这篇文章后,你仍然没有办法根据你的个人情况或决策来定制学习内容。鉴于我同意作者的退货方法,我在最后一张工作表中重新创建了那篇文章中的两个表。好处是你可以调整场景和输入,它们将基于与文章相同的结构流过这些表。
在房屋所有权年度经常性成本表中,列出了如何计算您正在评估的特定场景的净年度经常性成本(租金与购买成本)。关于这方面的详细信息,请参见《改善邮报》中的《房屋所有权的持续成本》。由于这可能会引起问题,我将指出我的帖子中的模型和改善的表格之间的差异。在增值表中,每年的财产税随着房屋价值的增长而增长,房主的保险随着通货膨胀而增长。虽然这更准确,但在模型的 10 年预测中,我让每个场景的满载每月抵押贷款付款(包括财产税和保险)保持不变。这是为了减少我们所覆盖的认知超载,并使其更容易理解相对于在线抵押计算器和估计付款的模型。由于我没有随着时间的推移适度增加财产税和保险,这意味着房屋所有权的回报被稍微夸大了;然而,由于这在不同的场景中是一样的,我相信这对你的评估没有实质性的影响。为了强调这种微小的差异,你会注意到在《改善邮报》的年度经常性房屋拥有成本表中,10 年后,年度财产税和购买 25 万美元房屋的房屋保险成本分别只增加了约 500 美元和 200 美元。
我还展示了两个 IRR 时间表,一个是五年投资期,另一个是十年投资期。你会注意到情景 4 的 IRR 最高,在情景 4 中,你支付的首付最低(与情景 1 相同),而且由于你有 15 年期而不是 30 年期的抵押贷款,你支付贷款的速度更快。在这种情况下,虽然情景 4 中的净年度经常性成本比情景 1 中的高,但是通过支付更多的债务本金所产生的更大的股权价值推动了更高的 IRR。当你能够从房屋升值中获益时,这展示了房屋所有权杠杆化回报的好处。
场景 1:5 年和 10 年持有期的房屋销售的现金流和内部收益率。
然而,我已经简化了年度经常性成本表中的一些内容,例如年度租金节省假设。对于您的所有个性化场景,节省的年租金应该是相同的(请随意在您自己的评估中反映这一点),但鉴于我假设不支付抵押贷款,在场景 4 和其他成本更高的场景中,节省的租金实际上更高。我需要考虑这是否可以用不同的方式表达,但结果是场景 4 的 IRR 可能被夸大了。现在,我将这些表作为跨场景的回报概况的概括说明。如果您愿意,可以很容易地覆盖第一个表格中关于经常性成本+ IRR 的 H 列和 I 列中的公式。你可以只输入你特定的房租储蓄和租房者保险储蓄,然后按通货膨胀率增长。
正如预期的那样,情景 2 和情景 3 的 IRR 比情景 1 略低,因为你看到了与情景 1 相同的价格升值,由于更大的利息成本,债务偿还略慢,并且由于更高的抵押贷款支付,你的净年度经常性成本更高。最后,与增值文章类似,你会发现,在更长的持有期内(10 年对 5 年),回报会有所提高,因为从购买房屋中收回前期交易成本需要时间。
我最后要指出的是,这个模型并没有对你的全部资产进行整体回报分析;在最终的工作表上,房屋所有权内部收益率是独立完成的。我在这里的建议是,少关注回报,而是关注产生最高调整后净值的结果,同时平衡你愿意为实现这一调整后净值而承担的风险。这是一个更复杂的话题,如果有相关的反馈和问题,我会考虑跟进。
结论。
总结这篇文章,我希望你能发现这个框架在评估你的个人机会方面是有用的,包括潜在的购买房屋,相关的购买价格和关键变量,如首付比例,抵押贷款利率和贷款期限。虽然我已经指出了一些非常有帮助的资源,我发现这些资源可以更好地理解房屋所有权的经济学,但我还没有找到另一种资源,它 1)个性化每月现金流,2)预测你随着时间推移积累的净值,包括房屋净值,以及 3)提供定制的时间表来评估潜在的投资回报、机会成本和你的房屋的潜在 IRR。
这一模型中的情景基本上得出与改善后的情景相似的结论。平均需要 4-5 年才能收回你的平仓成本,一套房子可能是一项合理的投资,甚至表现出与整个股市 ETF 相当的回报率(如 Vanguard 的 VTI )。这种情况并不总是如此,而《改善》这篇文章很好地指出了哪里可能会出错。
结合我所链接的资源,现在你有了一个可定制的模型,可以评估你在住房和投资机会方面的决策,你应该会感到完全知情,你会做出一个经过充分研究的决定,睁大眼睛进入房屋所有权阶段。这样做,我相信拥有一个家可以是一个伟大的地方;你会很好地理解它是如何融入你的整体个人财务状况以及你的预测投资和退休策略的。
如果你喜欢这篇文章,如果你点击“拍手”图标(不止一次)会很棒!)让我了解并帮助增加我作品的发行量。如果您想在后续帖子中对任何建议的编辑、功能请求或兴趣发表评论,也请让我知道。
你也可以在推特上联系我, @kevinboller ,我的个人博客可以在这里找到。感谢阅读!
EDA(探索性数据分析)——获得更多的数据洞察
作者图片
目录
- 介绍
- 图书馆
- 可视化的重要性
- 编码部分
- 结论
介绍
当我刚刚开始机器学习之旅时,我遇到了许多机器学习教程书籍、视频和课程。这教会了我不同类型的机器学习算法以及它们是如何工作的。所以,在完成这些教程后,我想我现在知道机器学习了。因此,我试图做一些简单的项目,但结果是不同的,就像我没有得到我期望的模型的准确性,我不知道哪里出错了。因此,我在互联网上搜索,寻找提高模型精度的方法,当然,我找到了很多方法,但我认为我错过的最重要的部分是对我的数据执行 EDA。
在我看来,对数据进行 EDA 就像在购买任何笔记本电脑、手机或平板电脑之前观看评论和拆箱视频,或者在购买汽车之前观看汽车评论者的视频,以了解更多关于我们将要购买的产品的信息。所以,现在我想你应该已经知道我们为什么要进行 EDA 了。在使用数据训练模型之前,我们将获得关于数据的见解。
我们这里要用的数据集是葡萄酒质量数据集。该数据集包含 12 个特征,即固定酸度、挥发性酸度、柠檬酸、残糖、氯化物、游离二氧化硫、总二氧化硫、密度、pH、硫酸盐、酒精和质量。在这些特征之外,我们需要预测代表葡萄酒质量的质量特征。
图书馆
Python 有大量的库,让我们在执行这些任务时更加舒适。为了对数据执行 EDA,我们将使用以下库:
Pandas 构建在 Numpy 之上,Numpy 用于处理和操作数据集。
Numpy 用于对数据执行数学运算,并处理多维数组和矩阵。
Matplotlib 基本上是一个绘图库,允许我们可视化我们的数据,以便我们可以获得更多关于它的见解。
Seaborn 也是一个构建在 matplotlib 之上的绘图库,允许创建有吸引力的绘图。
可视化的重要性
众所周知,为了更好地学习,我们需要将它形象化。你越能想象它,你对它就越有洞察力。因为我们的最终目标是更多地了解数据,所以我们尝试将数据可视化。它还帮助非技术人员更深入地了解数据。
因此,如果我们使用绘图、图表和其他可视化工具来可视化数据,而不是查看行和列形式的实际数据,那么我们就可以轻松地获得有关数据的更多信息。
有几种类型的图可用,但我们在这里只使用其中的几种。具体如下:
- 计数图
- 热图
- 箱线图
- 距离图
- 配对图
除了这些,我们还有小提琴情节,群体情节,联合情节等。为此我们将只讨论它的用法。但是这里我们将只使用这些列出的图。
让我们开始编码部分
在这一节中,我们实际上将使用我前面提到的库在给定的数据集上执行 EDA。那么,让我们开始吧。
导入库
我们将导入所有必需的库。
导入数据集
我们将使用 pandas 的 read_csv()函数导入数据集。因为我们的数据集使用“;”作为分隔符,我们将把它指定为方法的一个参数。
df.sample(5)将显示数据集的随机 5 个样本。这样我们就可以知道什么类型的特性和它们的价值。
上述代码的输出如下所示:
作者图片
描述数据集
pandas 的 describe()方法显示数据集的所有统计值,如计数、平均值、标准差、最小值、最大值等。分别是。
上述代码的输出如下所示:
作者图片
要查看数据集中的所有列,我们可以使用 pandas 的以下方法:
作者图片
检查缺失值
我们有几种方法来处理缺失值,但为此,我们需要知道有多少要素有缺失值。为了检查缺失值,pandas 有一个名为 isnull()的方法。我们将汇总要素的所有缺失值,以便了解有多少要素有缺失值以及有多少缺失值。
作者图片
因此,正如我们可以看到的,我们的数据集中没有任何缺失值,因此我们可以继续。
各列之间的相关性
找到所有特征之间的相关性有助于丢弃高度相关的特征。使用热图,我们可以看到所有功能之间的相关性,如下所示:
作者图片
正如我们在热图中看到的,高度相关的要素以较浅的颜色显示,而负相关的要素以较深的颜色显示。我们可以在热图中看到,特征密度和残糖高度相关,因此我们可以删除其中一个,我们还可以看到游离二氧化硫和总二氧化硫也高度相关,因此我们也可以删除其中一个。因为添加这两个特征不会产生任何新信息。
检查葡萄酒质量数据的分布
在这里,我们检查葡萄酒质量值范围的频率。通过这样做,我们可以了解数据集是如何分布的。因此,如果需要,我们可以决定重采样的策略。
我们创建计数图如下:
这样做的结果如下:
作者图片
从计数图中我们可以看到,质量为 6 的数据较多,质量为 3 和 9 的数据很少。
使用箱线图检测异常值
我们可以使用箱线图来绘制数据,以检测数据中的异常值,并了解我们的数据是否有偏差。
箱形图只是一个简单的矩形方框,显示最小值、最大值、中间值、第一和第三四分位数(分别为 25%和 75%)。使用方框外的圆圈显示异常值。如果中位数不在方框的中间,则数据是偏斜的。如果中位数接近顶部,则数据是正偏的,如果接近底部,则数据是负偏的。
我们可以创建如下的箱形图:
该数据集的箱线图如下:
作者图片
估计每个特征的 PDF
我们可以使用 dist plot 获得关于每个特征遵循的 PDF 的信息,如下所示:
作者图片
从图中可以看出 pH 服从正态分布。
探索所有特性之间的关系
为了探究所有特征之间的关系,我们可以使用配对图。它可以按如下方式创建:
葡萄酒质量白色数据集的配对图如下:
作者图片
结论
所以最后,我们在文章的最后。当然,EDA 中的内容远不止我在这里介绍的内容。总结 EDA,我们可以说,在你用它来训练你的模型之前,了解你的数据真的很有帮助。
你可以在我的 Github repo 中找到我的笔记本和数据集。
不要犹豫,在下面的评论区说出你的想法。
如果你觉得这篇文章有用,请分享。
感谢您阅读这篇文章。
参考资料:
由 Coursera 项目网提供。制作可视化是探索和分析的重要的第一步…
www.coursera.org](https://www.coursera.org/projects/exploratory-data-analysis-seaborn) [## 什么是探索性数据分析?
当我在考虑我应该开始写博客的第一个话题是什么的时候,EDA 突然出现了…
towardsdatascience.com](/exploratory-data-analysis-8fc1cb20fd15)
查看我的其他文章:
作为机器学习的初学者,任何人都可能很容易获得足够的关于所有算法的资源…
towardsdatascience.com](/deploy-a-machine-learning-model-using-flask-da580f84e60c) [## 使用 MoviePy 在 Python 中创建自己的基本视频编辑软件
伟大的图书馆创建自己的视频编辑软件
medium.com](https://medium.com/analytics-vidhya/create-your-own-basic-video-editing-software-in-python-using-moviepy-fcb229153f5c) [## 不使用 scikit-Learn 使用 Python 实现简单线性回归
使用基本库的分步教程
medium.com](https://medium.com/better-programming/simple-linear-regression-using-only-python-5c86af200bca) [## 用 Python 编写你自己的基于流行度的推荐系统,不需要库
推荐系统现在无处不在,像亚马逊、网飞和 Airbnb。所以,那可能会让你…
medium.com](https://medium.com/hackernoon/popularity-based-song-recommendation-system-without-any-library-in-python-12a4fbfd825e)
EDA:特征工程和分类数据编码
初学者回归技巧
房地产预测的回归技术——第二部分
我从我认识的最好的房地产经纪人那里偷了这张照片:我的妈妈!妈妈,生日快乐!
上周 ,我们开始了回归技术系列,使用散点图和条形图探索了爱荷华州艾姆斯的房地产数据集。这些技术是为了在我们的数据中建立关于模式的基本直觉。绘制我们的数据也允许我们筛选并了解我们正在处理的变量。在这个数据集中,有 79 个不同的变量用于预测房屋销售价格。太多了!
然后,我们总结了一些评估和填充缺失数据的方法。如果你想阅读全文,你可以在这里找到。
现在,把上周的 Jupyter 笔记本装上,让我们开始吧!你可以在这里找到我的 完整的笔记本 ,但是像上次一样,我鼓励你在本教程中发展你自己的。
在我们开始之前,请确保您已经完成了我们的第一个练习:
练习 1:** 如果您还没有,请使用上周概述的技术填写数据集中任何缺失的数据。然后你就可以开始钻研特性工程了。 **** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *****
特征工程
特征工程背后的理念是首先发现数据中可能驱动预测变量的模式,然后将其带到表面。这个由两部分组成的过程从探索我们的直觉开始。
什么赋予了家庭价值?
这是我的候选名单:
- 尺寸。我说的是总的可用内部空间。
- 房子坐落在多大的地产上?我喜欢园艺!
- 它有像棚子这样的外部结构吗?
- 游泳池怎么样?
请注意,其中一些问题有“是”或“否”的答案,回答“是”的简单行为会在您的脑海中推动销售价格上涨。当涉及到机器学习时,这并不一定有什么不同。
罗伯特·尼克森在 Unsplash 上的照片
现在想象一个机器学习算法,它只能根据它所拥有的数据来回答问题。如果我们查看我们的数据字典,我们只看到两个与家庭泳池相关的变量:
- PoolArea —以平方英尺为单位的面积。
- 泳池质量控制 —泳池质量。
一个人可以从一个给定的具有“极好”游泳池质量的家跳到“这个家必须有一个游泳池”。但是,不能保证您的算法或模型能够做到。因此,我们必须 通过特征工程将这种模式带到表面上来。
是写代码的时候了!我假设您已经准备好笔记本,并加载了数据集。
*df['HasPool'] = df.PoolArea.apply(**lambda** x: 1 **if** x > 0 **else** 0)*
这一行代码将特性 HasPool 添加到您的 Pandas 数据框中。
想知道一个家有没有大棚子怎么办?我想知道我潜在的新房子有没有网球场怎么办?好吧,我不想知道,但是有人想知道。让我们再来看看我们最好的朋友,数据字典。我看到一个名为mischaracter的变量,它有以下可能值:
*Elev Elevator
Gar2 2nd Garage (if not described in garage section)
Othr Other
Shed Shed (over 100 SF)
TenC Tennis Court
NA None*
嗯,那很简单。我们现在可以提取几个可能会或不会影响房屋价值的特征:
*df['HasShed'] =
f.MiscFeature.apply(**lambda** x: 1 **if** x == 'Shed' **else** 0)
df['HasTennis'] =
df.MiscFeature.apply(**lambda** x: 1 **if** x == 'TenC' **else** 0)
df['HasGar2'] =
df.MiscFeature.apply(**lambda** x: 1 **if** x == 'Gar2' **else** 0)*
请记住,您在训练集中设计的任何变量也需要在测试集中创建。
练习二:** 回答问题“房子有多少地上居住面积?”有描述这个量的变量吗?如果没有,使用你所拥有的数据和上面的技术,找出如何设计一个变量。*
处理特征工程的另一种方法是“试着用不同的方式说同样的事情”。你可以把现有的信息分成更小的部分。想象一下,向不理解的人更详细地解释一个概念。或者,您可以组合现有的变量,这类似于用更宽泛的笔画来解释一个概念。
在我们离开特性工程之前,我只想说:不要相信你的直觉。直觉通常是由经验和实验建立起来的。当直觉由于缺乏经验而失效时,研究是一个很好的替代品。例如,我不知道一个完工的地下室每平方英尺增加的价值比一个地上房间少。
编码分类数据
在我们能够从数据中获得任何统计见解之前,我们需要将其全部编码成数字格式。这将允许我们对我们的数据进行计算。为了获得如何做到这一点的直觉,我们需要考虑有两种类型的分类变量:序数和名词性。
序数:序数变量的可能值是不连续的,但有一个潜在的等级结构。序数变量的一个例子是将大学生分为四类:大一、大二、大三或大四。这些离散的类别有一个潜在的顺序。
名义上的:名义上的变量是没有明显的潜在等级或顺序的变量。颜色就是一个很好的例子。红色','蓝色','绿色'也可以列为'蓝色','绿色','红色',因为它们没有内在属性来给它们排名。
当我们想要将分类数据转换成数字时,定义这两个类别是很重要的。如果我们的类别是有序的,我们必须提供一个方法来保持底层的等级结构。
练习 3:** 将您的分类数据排序到 2 个列表中,如下所示:*
*ordinal = ['ExterQual', 'BsmtQual', 'GarageQual',
'KitchenQual', 'FireplaceQu', 'PoolQC',
'OverallQual', 'ExterCond', ... ]nominal = ['Neighborhood', 'MSZoning', 'Condition1',
'Condition2', 'RoofStyle', ... ]*
一旦我们把序数/排序数据分开,我们必须弄清楚它到底是如何排序的。同样,我们必须参考我们的数据字典来做到这一点。如果你还没有注意到,数据字典是一个必要的工具,你应该随时打开。例如,让我们以变量 BsmtExposure:
*BsmtExposure: Refers to walkout or garden level walls (split levels or foyers typically score average or above) Gd Good Exposure
Av Average Exposure
Mn Mimimum Exposure
No No Exposure
NA No Basement*
这个变量描述了地下室暴露在外面的程度。许多错层住宅都有带家具的地下室,有外部通道和露台或门廊。这被认为是“良好的暴露”,我们在对变量进行编码时必须考虑到这一点。
可能有许多方法可以将序数数据编码成数字,但我喜欢使用字典或映射。
*BsmtExposure_map = {
'Gd':4,
'Av':3,
'Mn':2,
'No':1,
'NA':0
}df.BsmtExposure = df.BsmtExposure.map(BsmtExposure_map)*
注意熊猫的用法。Series.map 转换我们的变量,秩保持不变。
同样,我们可以用变量 Functional,做同样的事情,它描述了房子的任何主要损坏或其他问题。值的范围从 Sal 到 Typ ,其中 Sal 表示房屋经历了灾难性的破坏,无法居住。 Typ 表示正常磨损。
*Functional_map = {
'Sal': 0,
'Sev': 1,
'Maj2': 3,
'Maj1': 4,
'Mod': 5,
'Min2': 6,
'Min1': 7,
'Typ': 8
}df.Functional = df.Functional.map(Functional_map)*
练习 3:** 用和上面两个例子一样的方式转换你所有的序数变量。**请记住,您的训练集和测试集都需要这样做。* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ****
好吧,每个人都喜欢相关矩阵的热图。我和其他人一样内疚,我为花了太多时间选择完美的彩色地图来搭配我笔记本的其他部分而内疚。因此,下面是我们在下一篇文章中将要做的一个例子(在我们讨论了为什么我们不能相信漂亮的脸蛋…或热图之后):
这将把我们带到统计测试…如果第一次约会是一个热图,那么进行统计测试就是深入挖掘,以发现你的新迷恋对象的内在是否像她的外在一样美丽。
在此之前,请随时留下您的任何问题、评论或更正!
使用探索性数据分析解读移动应用用户行为
关于使用移动应用程序数据进行探索性数据分析的方法和思维过程的分步走查
来自 Unsplash 的 Img 通过链接
在本文中,我将解释关于如何使用移动应用程序行为数据执行探索性数据分析(EDA)的方法和思维过程。EDA 是任何机器学习建模之前的关键步骤。
你期望学习的是如何从零开始,通过分析未清理的原始数据,挖掘出有趣的数据模式。它被分成 4 部分。
- 数据审查
- 数据可视化
- 相关分析
- 摘要
现在让我们开始吧🏃♂️🏃♀️.
- 数据回顾
获得原始数据后,第一步是理解每一列。
图 1 显示了原始数据的一个片段。有五万条记录。
图 1 原始数据片段
表 1 是所有列的简要总结。很快,你会发现这些数据包括应用程序安装的日期和时间,以及用户使用的功能。应用程序行为包括关于用户查看的应用程序屏幕列表的数据,用户是否玩过金融迷你游戏以及用户是否喜欢任何功能。
表 1 列说明摘要
第二步是以稳健的方式审查数据分布,重点是数字变量。具体来说,使用
dataset.describe()
图 2 有助于快速了解每个数值变量的最小值、最大值和平均值。有趣的是,用户的平均年龄是 31.7 岁,用户玩的平均屏幕数是 21。11%的用户玩过迷你游戏,17%的用户使用了高级功能,62%的用户最终注册成为会员。
图 2 列分布汇总
第三步是检查每个变量的数据类型,并在必要时进行类型转换。
具体来说,
dataset.info()
图 3 可变数据类型概述
我们发现列小时被当作一个字符串,如图 3 所示。因此,让我们只对小时进行切片,并转换为 int 类型。
dataset[“hour”] = dataset.hour.str.slice(1, 3).astype(int)
2.数据可视化
作为一名数据科学家,不仅要展示模型,还要直观地展示和解释发现。可视化是不可避免的一步。
具体来说,
dataset2 = dataset.copy().drop(columns = [‘user’, ‘screen_list’, ‘enrolled_date’, ‘first_open’, ‘enrolled’])
f = plt.figure(figsize=(15,6))
for i in range(1, dataset2.shape[1] + 1):
plt.subplot(2, 4, i)
f = plt.gca()
vals = np.size(dataset2.iloc[:, i — 1].unique())
plt.hist(dataset2.iloc[:, i — 1], bins=vals, color=’#3F5D7D’)
上面,我们将直方图仓的数量设置为等于每列中唯一值的数量。
如图 4 所示,可以看到一些有趣的模式。例如,年龄分布是正偏的,在 30 岁左右有一个很强的峰值。大多数用户不玩迷你游戏,使用高级功能,喜欢任何功能。
图 4 数值变量直方图
3.相关性分析
显然,上面的可视化只是关于单个变量的分布。但是我们需要知道每个变量是如何相互关联的。
3.1 自变量和因变量之间
第一步是理解自变量和因变量之间的相关性。自变量是列''登记的【T1 ',自变量是所有其他列。所以,具体来说,
dataset2.corrwith(dataset.enrolled).plot.bar(figsize=(15, 6),title = ‘Correlation with Reposnse variable’, fontsize = 15, rot = 15,grid = True)
图 5 显示了相关图。同样,一些有趣的发现。例如,屏幕数量与用户注册之间存在较强的正相关关系。总体而言,自变量和因变量之间没有很强的相关性。
图 5 自变量和因变量之间的相关条形图
3.2 自变量之间
第二步是理解独立变量之间的相关性。这有助于选择独立的特征,因为我们只训练具有独立变量的模型。所以我们需要确保变量之间没有很强的相关性。具体来说,
corr = dataset2.corr()
图 6 说明了相关矩阵。注意,我们只显示了下面的三角形,因为整个矩阵是对称的。由于最大相关性接近 0.3,我们可以得出结论,数值变量彼此不相关。
图 6 自变量之间的相关图
4.总结
使用一个小应用程序的行为数据,我们进行了数据审查,数据可视化和相关性分析。幸运的是,这些数据不需要太多的手工和琐碎的工作。但是我们发现了一些有趣的模式,可以作为你主菜前的开胃菜。
太好了!如果你觉得这篇文章有帮助,请随意点击👏s!如果您需要源代码,请随时访问我的Github页面🤞🤞。下一篇文章将介绍特征工程、数据处理和模型构建。
使用 SmartEDA 开发的 EDA
最少的代码和全面的探索性数据分析
由 Rosan Harmens 在 Unsplash 拍摄的照片
在从事数据科学或机器学习项目或任务时,我们都有快进到模型构建和预测阶段的冲动。然而,正如我们的导师和专家重申的那样,初始探索性数据分析(EDA)阶段对于从训练模型和预测的后期阶段获得更好的结果至关重要。估计花费在 EDA 和数据准备上的时间占数据科学项目总时间的 60–80%。
考虑到这一点,R 中有没有一些包可以让我们在加速 EDA 的同时还能做好它的工作?嗯,看起来有!
在本文中,我将展示 R 包 SmartEDA 的功能,它让我们在 EDA 领域的生活变得更加轻松。使用 SmartEDA、中的方法,只需一行代码,我们就可以获得以下各项:
- 更丰富的信息
- 可读性更好的格式化输出
- 日期集中每个要素的多点综合摘要
- 可视化单变量和双变量分析
SmartEDA 的所有上述功能都非常方便,尤其是在处理具有大量功能的数据集时。尝试使用传统的**str()**
和**summary()**
函数来处理超过 10 个特征的数据集!
现在让我们试驾一下 SmartEDA..
我们将使用来自 Kaggle 的泰坦尼克号数据集。你可以从这里下载。这包含了命运多舛的泰坦尼克号乘客的数据,以及他们是否在灾难中幸存。
#install.packages("SmartEDA")
library(SmartEDA)
data = read.csv("titanic.csv")
以下是数据集前几行的示例。
head(data)
数据集包含乘客信息,包括旅行等级、姓名、性别、年龄、船上兄弟姐妹和配偶的数量、船上父母和子女的数量、票价和出发港口等。
ExpData()
方法给出了关于数据集的顶级元数据信息。
ExpData(data, type=1)
使用type = 2
参数的相同方法给出了数据集中每个要素的简洁摘要,包括每个要素的变量类型、缺失案例百分比和唯一值数量。
厉害!对吗?等待..越来越好了。
连续特征总结
**ExpNumStat()**
方法生成数据集中所有连续要素的多点综合统计摘要,其中包含大量信息,包括负值、零值和正值的数量、缺失值的数量以及百分比、最小值、最大值、平均值、中值、标准差、变异系数、IQR、偏斜度、峰度和异常值的数量…咻!!
另外,**ExpNumStat()**
会自动识别数据集中的连续要素。在这里,下面我们只选取了可用于输出的所有概要点的一个子集。您可以通过删除列索引号来查看完整的输出,并只为您感兴趣的统计信息指定列索引。
ExpNumStat(data,by ="A",Outlier=TRUE,round= 2)[,c(1,2,4:6,9:10,12:15,18,23)]
ExpNumStat(data, by = "A", Outlier = TRUE, round = 2)[,c(1,2,9,16:22)]
此外,将by
参数设置为 G 或 GA,我们可以通过在 group 参数中指定一个分类特性来获得按“group”和“group plus all”划分的摘要。这在分类问题中特别有用,就像我们在这里遇到的问题,我们可以获得分类响应变量每个级别的连续特征的汇总(在这个数据集中为“幸存”)。
ExpNumStat(data[,-1],by = "GA",Outlier=TRUE,round= 2,gp = "Survived")[,c(1,2,4:6,9:10,12:15,18,23)]
在这种情况下,我们可以清楚地看到,票价特征对乘客是否幸存起着很大的作用。
分类特征总结
分类特征总结呢?这里使用的是**ExpCatStat()**
方法。
ExpCatStat(data, Target = "Survived")
上面的单行代码不仅提供了每个分类特征和目标特征之间的卡方统计和 p 值,还提供了每个特征的信息值(IV ),以及它与目标特征的关联程度和它的预测能力的有用标签。说到超越使命召唤!!
可视化
有了**SmartEDA**
、、就不全是数字输出了。无论是通过**ExpNumViz**
和**ExpCatViz**
方法进行单变量或双变量分析,它都可以提供可视化的探索数据。
双变量分析:连续特征对之间
将scatter = TRUE
参数传递给ExpNumViz()
会给出日期集的所有连续特征对之间的散点图。在这里,我们通过选择图的指数来绘制 Pclass 对 Fare 和年龄对 SibSp(船上兄弟姐妹/配偶的数量)。
ExpNumViz(data[,-1], scatter = TRUE)[4:5]
仅将数据集传递给方法会绘制每个连续要素的密度分布。
双变量分析:连续特征与分类反应特征
同样,只需要一行代码就可以生成箱线图,显示分类反应特征的不同水平的分布(“用 1 编码的存活”和用 0 编码的未存活”)。下面我们列举其中的两个例子。
ExpNumViz(data = data,target = "Survived")[4:5]
幸存乘客的票价中值更高(因此等级也更高)
有父母/孩子在车上的乘客有更高的生还机会
分类特征:单变量分析
ExpCatViz
除数据集外,没有任何其他参数,绘制每个分类特征中级别计数的%条形图。我们在下面列举了一些例子。
ExpCatViz(data)
只有 38%幸存下来
三等舱乘客比例最高,为 55%
分类特征:具有目标特征的双变量分析
ExpCatViz
方法采用 2 个附加参数target
和margin
,并生成数据集中所有分类特征与“幸存”目标分类特征的每个级别的柱状图。
照片由руслангамзалиев在 Unsplash 上拍摄
ExpCatViz(data, margin = 2, target = "Survived",
col = c("red","green"))[c(1,3:5)]
女性乘客的存活率更高
三等舱乘客的待遇。
冷却..更大的家庭没有存活下来。更好的生存变化与更小的家庭群体
机上儿童/父母人数较多的乘客存活率低/无存活率
上述两个情节可能指出了在一个有更多兄弟姐妹、父母和配偶的更大的家庭团体中旅行的乘客所面临的悲惨困境,即不能离开家人。看看存活率的悬殊!
总而言之,我们只用了不到六行代码就能完成大量的 EDA 数字运算和可视化。请给出你的反馈和意见,以及哪个是你最喜欢的 EDA 包,为什么。
感谢阅读!
又一个艾瑞斯·埃达
从超级流行的虹膜数据集中提取有用见解的尝试
在 Unsplash 上由zdenk macha ek拍摄的照片
介绍
在这本笔记本中,我对著名的 Iris 数据集进行了探索性的数据分析,并试图从数据中获得有用的见解。
数据集中存在的要素有:
- 萼片宽度
- 萼片长度
- 花瓣宽度
- 花瓣长度
导入库
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.set_style('darkgrid')
matplotlib.rcParams['font.size'] = 14
matplotlib.rcParams['figure.figsize'] = (9, 5)
matplotlib.rcParams['figure.facecolor'] = '#00000000'
加载数据
iris_df = pd.read_csv("IRIS.csv")
理解数据
iris_df.head()
iris_df.shape(150, 5)
从上面这条线我们可以看到,我们的数据集有 150 行和 5 列
iris_df.columnsIndex(['sepal_length', 'sepal_width', 'petal_length', 'petal_width',
'species'],
dtype='object')# Further inspecting the dataframe
def inspect_data(data):
return pd.DataFrame({"Data Type":data.dtypes,"No of Levels":data.apply(lambda x: x.nunique(),axis=0), "Levels":data.apply(lambda x: str(x.unique()),axis=0)})
inspect_data(iris_df)
让我们获得更多关于数据集的信息
iris_df.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 sepal_length 150 non-null float64
1 sepal_width 150 non-null float64
2 petal_length 150 non-null float64
3 petal_width 150 non-null float64
4 species 150 non-null object
dtypes: float64(4), object(1)
memory usage: 6.0+ KB
我们看到数据集的所有列都没有空值,其中四列是数字列,一列是分类列,这也是 dtypes 函数可以看到的。
iris_df.dtypessepal_length float64
sepal_width float64
petal_length float64
petal_width float64
species object
dtype: object
统计见解
iris_df.describe(include='all')
iris_df.describe() #Performing just for numeric columns
检查重复值
iris_df.duplicated().sum() # Total no of duplicates in the dataset3iris_df[iris_df.duplicated()] #This shows the actual duplicate rows
我们的数据集中有 3 个重复项,但是删除它们可能会打破我们数据集的平衡,因为我们看到我们的数据集是平衡的,在 describe 函数中,对于 species 列,我们看到频率为 50,这可以通过下面的代码行进一步证明。
iris_df['species'].value_counts()Iris-setosa 50
Iris-versicolor 50
Iris-virginica 50
Name: species, dtype: int64
因此,我们可以让重复值保持原样并继续。
检查缺失值
我们通过 info 函数确认了我们的数据集没有空值,但是让我们进一步证明它。
iris_df.isnull().sum(axis=0)sepal_length 0
sepal_width 0
petal_length 0
petal_width 0
species 0
dtype: int64
估计偏度和峰度
iris_df.skew()sepal_length 0.314911
sepal_width 0.334053
petal_length -0.274464
petal_width -0.104997
dtype: float64iris_df.kurt()sepal_length -0.552064
sepal_width 0.290781
petal_length -1.401921
petal_width -1.339754
dtype: float64
目标列上的可视化
我们的目标列是物种列,因为最终我们想要预测正确的花卉物种。
plt.title('Species Count')
sns.countplot(iris_df['species']);
这进一步表明,我们的数据集是平衡的,所有三个物种的记录相等。
可视化变量之间的关系
让我们比较萼片长度和萼片宽度列。
plt.title('Comparison between sepal width and length')
sns.scatterplot(iris_df['sepal_length'], iris_df['sepal_width']);
让我们再来比较一下,但这次我们也要在物种的基础上进行比较。
plt.figure(figsize=(16,9))
plt.title('Comparison between sepal width and length on the basis of species')
sns.scatterplot(iris_df['sepal_length'], iris_df['sepal_width'], hue = iris_df['species'], s= 50);
从上面的图像中,我们可以看出鸢尾属物种的萼片长度较小,但宽度较大。而我们看到云芝几乎位于长度和宽度的中间。而海滨锦鸡儿的萼片长度较长,宽度较小。
让我们比较花瓣长度和花瓣宽度列。
plt.title('Comparison between petal width and length')
sns.scatterplot(iris_df['petal_length'], iris_df['petal_width']);
我们可以看到两个独立的集群,但不确定物种,所以让我们把物种也纳入方程。
plt.figure(figsize=(16,9))
plt.title('Comparison between petal width and length on the basis of species')
sns.scatterplot(iris_df['petal_length'], iris_df['petal_width'], hue = iris_df['species'], s= 50);
我们看到 setosa 具有最小的花瓣长度和花瓣宽度,而 Versicolor 具有平均的花瓣长度和花瓣宽度,而 virginica 物种具有最高的花瓣长度和花瓣宽度。
现在让我们使用配对图来可视化所有列的关系。
sns.pairplot(iris_df,hue="species",height=3);
配对图代表我们的目标和变量之间的关系。我们可以看到,与其他物种相比,刚毛物种的特征有很大的差异,它具有较小的花瓣宽度和长度,而其萼片宽度高而其萼片长度低。类似的结论也可以从其他物种中得出,如花斑物种通常具有平均尺寸,无论是萼片还是瓣片。而海滨锦鸡儿具有高的花瓣宽度和长度,而它具有小的萼片宽度和大的萼片长度。
区分数字变量和分类变量
categorical_columns = iris_df.dtypes[iris_df.dtypes == 'object'].index
print('No of categorical fetures:',len(categorical_columns),'\n')
print(categorical_columns)
print('*'*100)
numerical_columns = iris_df.dtypes[iris_df.dtypes != 'object'].index
print('No of numerical fetures:',len(numerical_columns),'\n')
print(numerical_columns)No of categorical fetures: 1
Index(['species'], dtype='object')
****************************************************************************************************
No of numerical fetures: 4
Index(['sepal_length', 'sepal_width', 'petal_length', 'petal_width'], dtype='object')
这个函数进一步支持了我们之前的观察。
数字特征概述
iris_df[numerical_columns].describe()
我们可以看到,平均值和中值之间没有很大的差异,因此不需要进行数据转换。
变量之间的相关性
iris_df.corr()
此外,我们可以使用热图来可视化这种相关性。
fig = plt.figure(figsize = (15,9))
sns.heatmap(iris_df.corr(), cmap='Blues', annot = True);
从上面的热图中,我们看到花瓣长度和花瓣宽度有很高的相关性,花瓣宽度和萼片长度有很好的相关性,花瓣长度和萼片长度也有很好的相关性。
cols = ['sepal_width', 'sepal_length', 'petal_width', 'petal_length']
plt.figure(figsize=(20,4), dpi=100)
i = 1
for col in cols:
plt.subplot(1,11,i)
sns.distplot(iris_df[col])
i = i+1
plt.tight_layout()
plt.show()
我们可以通过这个 distplot 观察我们的列的分布,它显示遵循正态分布。
直方图
让我们来看看数据集各列的数据分布。
fig, axes = plt.subplots(2, 2, figsize=(16,9))
axes[0,0].set_title("Distribution of Sepal Width")
axes[0,0].hist(iris_df['sepal_width'], bins=5);
axes[0,1].set_title("Distribution of Sepal Length")
axes[0,1].hist(iris_df['sepal_length'], bins=7);
axes[1,0].set_title("Distribution of Petal Width")
axes[1,0].hist(iris_df['petal_width'], bins=5);
axes[1,1].set_title("Distribution of Petal Length")
axes[1,1].hist(iris_df['petal_length'], bins=6);
- 萼片宽度的最高频率在 3.0 至 3.5 之间,约为 70。
- 萼片长度的最高频率在 5.5 和 6.0 之间,约为 35。
- 花瓣宽度的最高频率在 0 到 0.5 之间,约为 50。
- 花瓣长度的最高频率在 0 到 0.5 之间,约为 50。
我们的列的单变量分析
sns.FacetGrid(iris_df,hue="species",height=5).map(sns.distplot,"petal_width").add_legend();
我们看到刚毛藻很容易分离,而杂色和海滨锦鸡儿的一些部分是混合的。
sns.FacetGrid(iris_df,hue="species",height=5).map(sns.distplot,"petal_length").add_legend();
我们再次看到,在花瓣长度的基础上,setosa 是可分离的,而其他两个仍然重叠。
sns.FacetGrid(iris_df,hue="species",height=5).map(sns.distplot,"sepal_length").add_legend();
我们看到,仅仅根据萼片长度来区分物种是很困难的。
sns.FacetGrid(iris_df,hue="species",height=5).map(sns.distplot,"sepal_width").add_legend();
而在萼片宽度的情况下,物种的重叠更为强烈。
fig, axes = plt.subplots(2, 2, figsize=(16,9))
sns.boxplot( y="petal_width", x= "species", data=iris_df, orient='v' , ax=axes[0, 0])
sns.boxplot( y="petal_length", x= "species", data=iris_df, orient='v' , ax=axes[0, 1])
sns.boxplot( y="sepal_length", x= "species", data=iris_df, orient='v' , ax=axes[1, 0])
sns.boxplot( y="sepal_length", x= "species", data=iris_df, orient='v' , ax=axes[1, 1])
plt.show()
- 此外,我们可以看到,箱线图描述了 setosa 通常具有较小的特征,很少有异常值。
- 杂色种具有一般的特征
- 与其他种类相比,海滨锦鸡儿拥有最长的特征宽度和长度。
我们可以使用数据集上的小提琴图进一步查看分布
fig, axes = plt.subplots(2, 2, figsize=(16,9))
sns.violinplot(y="petal_width", x= "species", data=iris_df, orient='v' , ax=axes[0, 0])
sns.violinplot(y="petal_length", x= "species", data=iris_df, orient='v' , ax=axes[0, 1])
sns.violinplot(y="sepal_length", x= "species", data=iris_df, orient='v' , ax=axes[1, 0])
sns.violinplot(y="sepal_length", x= "species", data=iris_df, orient='v' , ax=axes[1, 1])
plt.show()
数据的核心密度以及数据的完整分布通过 violin 图显示。我们可以看到各种特征的概率密度。
结论
- 数据集是平衡的,即所有三个物种都有相同的记录。
- 我们有四个数字列,而只有一个分类列,这又是我们的目标列。
- 花瓣宽度和花瓣长度之间存在很强的相关性。
- 刚毛物种是最容易区分的,因为它的特征尺寸很小。
- 杂色和海滨种通常是混合的,有时很难分开,而杂色通常具有平均特征尺寸,海滨种具有较大的特征尺寸。
使用 Panda 分析的 EDA
用一行代码生成详细的数据分析报告
探索性数据分析是任何数据科学问题的关键方面。理解数据及其模式是建立模型的基础。做 EDA 有很多方法。为此,我最近偶然发现了一个神奇的熊猫图书馆,名为“熊猫档案”。
这个库的美妙之处在于,只需一次点击,您就可以获得整个数据集的非常全面的报告。它生成一个结构整齐的 HTML 文件,包含图表和汇总数据的组合。我在 Kaggle 数据集(宫颈癌风险分类)上使用了这个库,并将向您展示输出结果。使用下面的代码片段,我已经使用熊猫档案报告模块生成了一份详细的数据报告。
# import the pandas profile library
from pandas_profiling import ProfileReport
# load the data from Kaggle
train1=pd.read_csv("/kaggle/input/cervical-cancer-risk-classification/kag_risk_factors_cervical_cancer.csv")
# data cleaning
train2 = train1.replace('?', np.nan)
# creating profile report
report = ProfileReport(train2, title='Profile Report', html={'style':{'full_width':True}})
以下是输出的快照:
概观
正如您从快照中看到的,您可以一次性获得所有重要的数据推断。这只是概述。点击变量选项卡,可以深入了解每个变量的特性。
变量
这里我们得到了数据及其分布的描述。该输出是针对数据中的每个变量分别给出的。接下来是相关性选项卡。为变量提供了五种类型的相关性。您可以分析每个相关性,以了解目标变量和因变量之间的关系。
相关
下一个选项卡用于缺失值。缺失值分析以五种不同的输出格式显示。计数条形图可快速查看每个变量缺失值的数量。还有矩阵、热图和树状图,为数据中所有缺失的值提供了一个很好的图形表示。
缺少值
热图
profile 报告中的最后一个选项卡提供了数据集的第一行和最后几行的样本。
样品
总体而言,pandas 的剖析模块减少了数据探索的工作量,因为所有关键的 EDA 结果都是剖析报告的一部分。基于该报告,可以执行进一步的数据探索。我在使用这个模块时发现的唯一缺点是,对于巨大的数据集,生成报告需要很长时间。我使用这个模块来了解变量之间的相关性,这给了我一个关于目标变量的可能强预测因子的想法。然后,我选择了最佳特征选择技术来理解哪些特征对目标变量贡献最大。您可以在下面的 Kaggle 笔记本中查看代码,
使用 Kaggle 笔记本探索和运行机器学习代码|使用来自宫颈癌风险分类的数据
www.kaggle.com](https://www.kaggle.com/krrai77/eda-cervical-cancer-risk)
EDA:geo pandas、Matplotlib 和 Bokeh 中的可视化
来自 tdwi.org的詹姆斯·鲍威尔
如今,每个人都沉浸在来自新闻来源、手机、笔记本电脑、工作场所等等的大量数据中。数据传递来自不同数据变量的大量信息,如日期、字符串、数字和地理格式。如何从庞大的数据集里有效地抓住核心价值,并让用户容易解读?答案是探索性数据分析(EDA)。EDA 是一种可视化和分析数据的工具,可以从数据集中提取洞察力。观众能够从通过 EDA 过程总结的重要特征中更好地理解数据集。
在本文中,您将了解到:
(1)带有 Geopandas 和 Bokeh 的动态地理图
(2)对 2016 年至 2019 年全球数据集的分析
(Matplotlib 和 Bokeh 中的可视化
动态 choropleth 图
Choropleth 地图提供了地理区域(即国家)的各种模式和符号,很好地展示了跨区域的测量结果。为了绘制全球幸福地图,我们将关注全球幸福状况调查,该调查根据 155 个国家的幸福水平进行排名,在联合国 发布。ka ggle 网站链接:世界幸福报告。情节的创建使用了 Python 库和包——Pandas、Geopandas 和 Bokeh。
下载世界地图文件
要渲染世界地图,需要有一个带有世界坐标的 shapefile。 Natural Earth 是下载地理空间数据的绝佳来源,其中充满了各种公共领域地图数据集。对于动态地理图的生成,1–110m 小比例尺数据是一个很好的地图数据集。
将 shp 文件转换为 Geopandas 数据帧
Geopandas 可以通过read_file
函数将 ESRI shapefile 转换为 GeoDataframe 对象。使用返回地理数据框架对象的read_file
命令,Geopandas 可以读取几乎任何基于矢量的空间数据格式,包括 ESRI shapefile。您可以在使用 geopands 函数读取数据集时指定列。
地理数据框架的代码片段
2015 年静态 choropleth 地图
首先,我们创建一个世界幸福报告的数据框架,并指定 2015 年。然后,可以将生成的数据框 df_2015 合并到地理数据框 gdf 中。为了以后使用散景创建可视化,我们需要 geojson 格式的数据作为绘图源。要素集合包含 GeoJSON 数据中的点、线和面。所以我们把数据帧转换成 JSON,转换成类字符串对象。
合并后的文件是一个 GeoDataframe 对象,可以使用 geopandas 模块进行渲染。然而,由于我们想加入数据可视化的交互性,我们将使用散景库。散景使用 GeoJSON 格式,用 JSON 表示地理要素。GeoJSON 将点、线和多边形(在散景中称为面片)描述为要素的集合。因此,我们将合并后的文件转换为 GeoJSON 格式。
Json 数据的代码片段
然后,我们准备用散景模块创建一个静态 choropleth 映射。我们首先用GeoJSONDataSource
包读入 geojson 数据。接下来,我们将调色板指定为“YlGnBu ”,并颠倒颜色顺序以匹配最高幸福分数的最暗颜色。然后,我们为颜色条应用自定义刻度标签。对于颜色条,我们将颜色映射器、方向和标记标签映射到颜色条包中。
choropleth 映射的代码段
我们使用指定的地块高度和宽度创建图形对象。然后,我们用 x 和 y 坐标为图形添加补丁,并在 fill_colors 参数中指定字段和转换列。要在 Jupyter 笔记本中显示散景图,我们需要放入 output_notebook()模块,并让图形显示在 show()模块中。
choropleth 映射的代码段
分析:
从下图中,我们看到加拿大、墨西哥和澳大利亚等国家的幸福指数更高。对于南美和欧洲国家,总得分分布在指数 5 和 6 附近。相比之下,尼日尔、乍得、马里和贝宁等非洲国家的幸福指数要低得多。
图 1:2015 年静态 choropleth 图
2015 年至 2019 年交互式 choropleth 地图
交互式 choropleth 地图增加了两个部分。一个是悬停工具的创建。我们为图表上显示的信息指定列。另一个是回调函数的创建。对于绘图交互,我们通过滑块指定年份来更新数据。我们将滑块值传递给回调函数,并调整数据。然后,我们将 slider 对象传递给 bokeh 列类中的 widgetbox 参数。最后,我们添加了curdoc
类来创建交互式 web 应用程序,该应用程序可以将前端 UI 事件连接到真实的、正在运行的 Python 代码。
choropleth 映射的代码段
对于那些在 Jupyter 笔记本中运行 choropleth 地图出错的人来说,有一个在终端中运行脚本的替代方法。
bokeh serve --show EDA_Plot.py
互动 choropleth 地图视频
2015 年至 2019 年世界幸福报告的分析图
2016 年 GDP 与幸福指数散点图
散点图的代码片段
分析:
我们研究了 2016 年 GDP 增长和幸福水平得分的相关性。由于这些国家按地区进行了颜色编码,我们可以看到东南部国家的 GDP 增长较低,其次是潜在的幸福得分。大多数中欧和东欧国家的 GDP 增长率在 0.8 到 1.4 之间,幸福指数在 5 到 6 之间。对于西欧地区来说,它们往往显示出较高的经济增长幅度和幸福指数。
图 2:2016 年 GDP 与幸福指数散点图
经济指数排名前 10 位和后 10 位的国家(人均 GDP)
分析:
对于前 10 大经济趋势国家,“阿拉伯联合酋长国”显示出增长趋势,2015 年至 2018 年经济增长 0.68%。缅甸是唯一一个人均 GDP 增长率为 0.41 的亚洲国家。令人惊讶的是,像“马拉维”、“几内亚”、“坦桑尼亚”这样的撒哈拉以南非洲国家是经济呈上升趋势的前 5 名国家。
我们可以看到,经济趋势下降的国家大多在非洲。从 2015 年到 2018 年,像'利比亚','也门','科威特','约旦','塞拉利昂'这样的倒数 5 个国家的经济指数较低。其中四个国家位于中东和北非。
图表 3:经济指数最高和最低的 10 个国家
阿联酋年度 GDP 变化
分析:
看到经济指数(人均 GDP 增长)排名前 10 位和后 10 位的国家,我们密切关注阿拉伯联合酋长国的经济趋势。1980 年,阿联酋出现了 40 年来最大的 GDP 增长值。然而,在 1982 年至 1986 年期间,增长率变成了负数。在未来 10 年,阿联酋的国内生产总值表现出相当稳定的增长,约为 0.1-0.2 个百分点。2009 年,受金融危机的影响,国内生产总值大幅下滑。
图 4:阿联酋年度 GDP 变化
总之:
- 要创建 choropleth 地图,geopands 可以将 shp 文件转换为数据框对象。对于可视化的创建,散景与 geopandas 包配合得很好。但是,最好记住,在合并两个数据集时,需要将发货文件中的国家/地区与外包数据进行匹配。
- Matplotlib 和 Bokeh 是 Python 中可视化工具的两个很好的包。散点图更好地显示了两个变量与数值的相关性。就发散图而言,它更好地显示了数据集的下降和上升趋势。对于 DateTime 格式变量,最好在绘图创建时注意缺少值的 date。线形图显示了时间序列数据的明显趋势。
边缘人工智能
亚历山大·戈德罗在 Unsplash 上拍摄的照片
Edge AI 到底是什么意思?这个问题我被问了好几次,我决定分享一下我对这个话题的想法。边缘人工智能通常指在设备上本地运行人工智能算法所需的组件,也称为设备上人工智能。最近,这意味着在设备上运行深度学习算法,大多数文章倾向于只关注一个组件,即推理。这篇文章将揭示这个难题的其他部分。
实验装置
边缘设备在成本/性能方面差异很大,为了使讨论更加具体,下面是本系列中使用的实验设置:
高通骁龙 855 开发套件[ 4
- 高通骁龙 855 开发套件。
- 对象检测作为要在边缘设备上运行的深度学习模型。有很多很好的文章描述了物体检测的最新技术[调查论文]。在本系列中,我们将使用 Mobilenet SSD 模型进行对象检测。
- Tensorflowjs 在 nodejs 环境中快速运行对象检测模型
为什么要在 Edge 上运行人工智能算法
为什么不能依靠云端运行 AI 算法?毕竟,在云上扩展资源以运行人工智能/深度学习模型来满足您的性能需求更容易。那么,为什么要担心在计算和功耗受限的边缘设备上运行它们呢?为了回答这个问题,让我们考虑两种情况:
a)基于云的架构,其中推理发生在云上。
b)基于边缘的架构,其中推断在设备上本地发生。
(为了尽可能公平地进行比较,在这两种情况下,都将使用 nodejs 服务器以及【tensorflowjs】【仅 cpu】,唯一的区别在于,在 情况 a) 中,web 服务器将在 EC2 实例上运行,而在 情况 b) 中,web 服务器将在边缘设备上本地运行【T19 这里的目标不是拥有一个平台(云或边缘)的优化实现,而是拥有一个框架来进行公平的比较。)**
基于云的架构
这是基于云的设置的样子,它将包括下面详细描述的步骤:
用于推理的纯云架构。(结尾的图像参考)。
步骤 1:请求输入图像
这里有两种可能的选择:
- 我们可以从边缘设备发送从相机捕获的原始图像(RGB 或 YUV)。原始图像总是更大,发送到云需要更长时间。
- 我们可以在发送之前将原始图像编码为 JPEG/PNG 或其他一些有损格式,在运行推理之前在云上将它们解码回原始图像。这种方法将涉及解码压缩图像的额外步骤,因为大多数深度学习模型都是用原始图像训练的。在本系列的后续文章中,我们将涉及更多关于不同 raw 图像格式的内容。
为了使设置简单,使用第一种方法[RGB 图像]。HTTP 也被用作向 REST 端点发送图像的通信协议(http://
步骤 2:在云上运行推理
- tensorflowjs 用于在 EC2 (t2.micro)实例上运行推理,仅使用单个 nodejs 工作实例(无负载平衡、无故障转移等)。
- 使用的 Mobilenet 版本在这里托管。
- Apache Bench(ab)用于收集 HTTP 请求的延迟数。为了使用 ab ,RGB 图像被 base64 编码并发布到端点。 express-fileupload 用于处理发布后的图像。
总延迟(RGB) = Http 请求+推理时间+ Http 响应
**ab -k -c 1 -n 250 -g out_aws.tsv -p post_data.txt -T "multipart/form-data; boundary=1234567890"** [**http://<ip-address>:<port>/detect**](http://10.221.1.231/detect)This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, [http://www.zeustech.net/](http://www.zeustech.net/)
Licensed to The Apache Software Foundation, [http://www.apache.org/](http://www.apache.org/)Benchmarking <ip-address> (be patient)
Completed 100 requests
Completed 200 requests
Finished 250 requestsServer Software:
Server Hostname: <ip-address>
Server Port: <port>Document Path: /detect
Document Length: 22610 bytesConcurrency Level: 1
Time taken for tests: 170.875 seconds
Complete requests: 250
Failed requests: 0
Keep-Alive requests: 250
Total transferred: 5705000 bytes
Total body sent: 50267500
HTML transferred: 5652500 bytes
Requests per second: 1.46 [#/sec] (mean)
Time per request: 683.499 [ms] (mean)
Time per request: 683.499 [ms] (mean, across all concurrent requests)
Transfer rate: 32.60 [Kbytes/sec] received
287.28 kb/s sent
319.89 kb/s totalConnection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 5.0 0 79
Processing: 530 683 258.2 606 2751
Waiting: 437 513 212.9 448 2512
Total: 530 683 260.7 606 2771Percentage of the requests served within a certain time (ms)
50% 606
66% 614
75% 638
80% 678
90% 812
**95% 1084**
98% 1625
99% 1720
100% 2771 (longest request)
基于云的架构的端到端推理延迟直方图(桶大小为 1s)。它显示了 Apache Bench (ab)在给定时间内生成的请求的推理延迟。
基于云的体系结构的端到端推理延迟按响应时间(毫秒)排序。这篇文章解释了这两个情节的区别。
正如我们在这里看到的,95%的请求延迟大约为1084 毫秒。
基于边缘的架构
Web 服务器(运行 tensorflowjs)在本地边缘设备上运行(高通骁龙 855 开发套件[ 4 ])。我们使用 Apache Bench 重复相同的步骤(这次是对本地主机而不是远程服务器的 http 请求),结果如下。
**ab -k -c 1 -n 250 -g out_device.tsv -p post_data.txt -T "multipart/form-data; boundary=1234567890"** [**http://localhost:3000/detect**](http://10.221.1.231/detect)This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, [http://www.zeustech.net/](http://www.zeustech.net/)
Licensed to The Apache Software Foundation, [http://www.apache.org/](http://www.apache.org/)Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Finished 250 requestsServer Software:
Server Hostname: localhost
Server Port: 3000Document Path: /detect
Document Length: 22610 bytesConcurrency Level: 1
Time taken for tests: 80.689 seconds
Complete requests: 250
Failed requests: 0
Keep-Alive requests: 250
Total transferred: 5705000 bytes
Total body sent: 50267750
HTML transferred: 5652500 bytes
Requests per second: 3.10 [#/sec] (mean)
Time per request: 322.755 [ms] (mean)
Time per request: 322.755 [ms] (mean, across all concurrent requests)
Transfer rate: 69.05 [Kbytes/sec] received
608.38 kb/s sent
677.43 kb/s totalConnection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 2
Processing: 290 323 36.0 317 737
Waiting: 290 322 36.0 316 736
Total: 290 323 36.1 317 739Percentage of the requests served within a certain time (ms)
50% 317
66% 323
75% 328
80% 331
90% 341
** 95% 357**
98% 397
99% 473
100% 739 (longest request)
基于边缘的架构的端到端推理延迟直方图(桶大小为 1s)。它显示了 Apache Bench (ab)在给定时间内生成的请求的推理延迟。
基于边缘的体系结构的端到端推理延迟按响应时间(毫秒)排序。这篇文章解释了这两块地的区别。
正如我们在这里看到的,95%的请求延迟大约为357 毫秒。
优化机会
正如您所看到的,延迟数字相当高,我们在这里获得的数字更像是上限延迟,有许多优化机会,其中一些详述如下:
基于云的架构:
- 拥有多个 nodejs worker 实例,并在它们之间实现负载平衡。
- 有多个部署(美国东部、美国西部等)并将请求发送到最近的部署。
- 批量处理多个输入图像,并在云上运行批量推理。
- 拥有一个基于 gpu 的 EC2 实例并使用 tensorflow-node-gpu 来加速推理
- 使用不同的通信协议,如 MQTT 更适合 IOT /云连接,以避免 HTTP 的开销。
基于边缘的架构:
- 针对您的边缘设备进行优化实施。在这种情况下,对于高通骁龙 855 开发套件[ 4 ]推理将在 GPU / DSP 或其 NPU 上加速。
- 最有可能的是,在设备上的实现将通过供应商框架依赖于本地库,如 SNPE 或 tensorflow-lite 。
- 优化数据路径,包括从相机捕捉图像到输入深度学习模型以运行推理。
结论
我们详细研究了决定您是否需要基于边缘的解决方案的一个因素,因为我们发现如果您的应用能够容忍云延迟,那么基于云的推理将是最快的方式。但是,如果您的应用对延迟敏感,那么您可以考虑基于边缘的解决方案。请确保对您的特定用例进行基准测试,从中选择一个。除了延迟之外,考虑基于边缘的解决方案还有其他一些原因:
- 您已经部署了边缘设备,并希望利用它来节省云计算成本。
- 隐私,你不希望数据离开边缘设备。
- 与云没有完全连接或连接性差的设备,基于边缘的解决方案成为必然
参考
[1]https://storage . Google APIs . com/open images/web/visualizer/index . html?set = train&type = detection&c = % 2Fm % 2f 0k 4j&id = 101 C3 faac 77 e 2e 29—来自开放图像数据集 V5 的汽车覆盖图像
[2]https://C2 . static Flickr . com/7/6021/6005573548 _ 11 b 7 b 17 c 9 b _ o . jpg—原车图片
[3]https://pix abay . com/illustrations/Google-Pixel-3-Google-cell-Phone-3738925/—Pixel 手机图片。
[4]https://www . Intrinsyc . com/snapdragon-embedded-Development-kits/snapdragon-855-hdk/—Intrinsyc 开发套件
[5]http://www . bradlanders . com/2013/04/15/Apache-bench-and-gnuplot-you-possible-do-it-wrong/
边缘计算 101
了解边缘计算的基本知识。
在本文中,我们将讨论
- 什么是边缘计算?
- 边缘计算、雾计算和云计算的区别
- 边缘计算有什么好处?
- 边缘计算用在哪里?
- 实施边缘计算的不同硬件选项
莱尼·屈尼在 Unsplash 上的照片
根据思科的估计,到 2021 年,每年将有近 850 Zettabytes (ZB)的数据在云外产生,物联网设备将占这些数据的很大一部分。
为了有效地使用物联网设备生成的数据,数据应该在设备之间无缝通信,以进行实时计算和推理,从而提高数据安全性并减少延迟。
边缘计算、雾计算和云计算解决了性能、安全性和成本效益方面的许多挑战。根据组织的数据计算、分析和存储需求,设计边缘计算、雾计算和云计算的平衡组合。
但是什么是边缘计算?
边缘计算直接在连接到产生数据的传感器或致动器的设备上进行。
边缘计算、雾计算、云计算有什么区别?
Edge、Fog 和云计算之间的区别基于数据生成、处理、访问和智能应用的位置。
边缘计算
- 数据处理在生成数据的同一设备上完成。
- 由于数据是在生成数据的同一台设备上处理的,因此网络连接问题将会减少,从而降低延迟。
- 数据是安全的,因为它不会传输到其他设备或网络进行处理。
雾计算
- 与边缘计算类似,数据处理更接近于使用局域网生成数据的设备
- 与在设备上进行数据处理的边缘计算不同,在雾计算中,数据通过局域网在设备和网关之间传输。
- 与远程存储和处理数据的云计算不同,在雾计算中,使用局域网在本地存储和处理信息。
- 由于雾计算中的数据是在本地存储和处理的,因此可以离线访问,与云相比延迟更短,并降低了数据安全风险。
- 在本地的一个中心位置处理来自不同设备或来源的数据。
云计算
- 由服务器、网络、存储、计算能力和通过互联网实现的应用程序开发组成的计算模型。
- 数据是通过互联网存储、访问和处理的。
- 随时随地访问云服务。
- 能够根据需求扩大和缩小资源规模
- 您只需根据云资源的使用情况付费。
为什么要用边缘计算?
边缘计算的优势
边计算有几个好处
- 减少延迟:由于计算发生在生成数据的位置,并且没有通过网络传输数据,因此减少了延迟,从而提供了更好的推理时间。
- 安全:所有的数据处理和推理都在边缘执行,因此没有数据离开设备或通过网络传输,因此不存在数据隐私和安全问题。
- 可扩展性:随着边缘计算的增加,让边缘计算数据中心与设备共处一地,可以让组织以更快的速度扩展边缘计算需求,并且仍然非常经济高效。
边缘计算用在哪里?
当需要减少延迟来处理数据时,使用边缘计算。如果您需要快速数据处理,那么应该在尽可能靠近数据生成源的地方执行,以避免由于数据传输而导致的任何延迟。
自动驾驶汽车、物联网、语音助手、机器或服务的预测性维护、交通管理等。实现边缘计算。
例如,语音助手接受您的语音命令,使用深度 NLP 应用自动语音识别将语音转换为文本,并应用语言上下文,搜索 web 并交付结果。所有这些都发生在边缘。
你有哪些边缘计算的选择?
边计算的选项
基于技术架构,Edge AI 硬件分为三类。
- 图形处理单元(GPU) :兼容性和性能都很好但是像 NVDIA 的 Jetson 板一样耗能更多。需要软件编程技能。
- 现场可编程门阵列(FPGA) :高能效,因为它们需要更少的计算资源,但需要软件编程技能和一些硬件定义专业知识。FPGA 的一个例子是英特尔 FPGA 加速服务器
- 专用集成电路(ASIC)-ASIC 的一个例子是谷歌的 TPU 设备,如 USB 加速器或 Coral Dev 板,具有良好的性能和高效的功耗。
那么如何决定你应该使用什么类型的计算呢?
边缘计算:如果你在寻找更快的数据处理、更高的推理时间、更高的数据安全性、更低的带宽甚至没有互联网连接,那么边缘计算是最好的选择。
云计算:如果你在寻找随时随地的数据处理需求。您的数据处理和存储需求在不同的时间是不同的,并且喜欢扩大和缩小数据处理资源;那样的话,云更适合你的需求。
雾计算:如果您有很多边缘设备,需要集中处理数据,数据安全性合理,但仍有很高的推理时间。此外,当互联网连接不太稳定或带宽较低时,雾计算可以满足您的需求。
结论
根据您的数据处理或推理需求、网络连接和数据安全要求,您可以选择一种或多种计算需求。
Python 中的边缘检测
上个季度,我在大学里帮助教授 Python 课程,结果学到了很多关于图像处理的知识。我想在本文中继续分享这些知识,因为我们讨论了使用 Python 进行边缘检测的理论和执行!
为什么要检测边缘?
我们真正应该问的第一个问题是“为什么要麻烦边缘检测?”。除了很酷之外,为什么它是一种有用的技术?为了激发这一点,考虑下面的纸风车图像及其“仅边缘”对应物:
风车(左)及其边缘(右)的图像
我们可以看到左边的原始图像有各种颜色和阴影,而右边的“仅边缘”表示是黑白的。如果问哪个图像需要更多的数据存储,我打赌你会说原始图像。这是有意义的。通过检测图像的边缘,我们去掉了很多细节,从而使图像“更轻”。
因此,在我们不需要保持图像的所有复杂细节,而是 只关心整体形状 的情况下,边缘检测会非常有用。
如何执行边缘检测—数学
在讨论代码之前,让我们快速看一下边缘检测背后的数学原理。作为人类,我们非常擅长识别图像的“边缘”,但我们如何教会计算机做同样的事情呢?
首先,考虑一个在白色背景中有一个黑色正方形的非常无聊的图像:
我们的工作形象
在这个例子中,我们认为每个像素的值在 0(黑色)和 1(白色)之间,因此现在只处理黑白图像。完全相同的理论将适用于彩色图像。
现在,假设我们正在尝试确定绿色高亮像素是否是该图像边缘的一部分。作为人类,我们会说是的,但是我们如何使用相邻像素来帮助计算机得出相同的结论呢?
让我们取一个小的 3×3 的局部像素框,以所讨论的绿色像素为中心。这个框显示为红色。然后,让我们对这个小盒子“应用”一个过滤器:
将垂直滤镜应用于局部像素框
我们将“应用”的过滤器如上所示,乍一看很神秘,但是让我们看看它是如何工作的。现在,当我们说 “将过滤器应用于像素的小局部框” 时,我们的意思是将红色局部框中的每个像素乘以过滤器元素中的每个像素。因此,红框中的左上角像素为 1,而滤镜中的左上角像素为-1,所以将这些像素相乘得到-1,这就是我们在结果的左上角像素中看到的。结果中的每个像素都是以完全相同的方式实现的。
下一步是对结果中的像素求和,得到-4。注意-4 实际上是我们通过应用这个滤镜可以得到的最小值(因为原始图像中的像素只能在 0 到 1 之间)。因此,我们知道所讨论的像素是顶部垂直边缘的的一部分,因为我们获得了最小值-4。
为了掌握这种变换,让我们看看如果我们对正方形底部的像素应用滤镜会发生什么:
我们看到我们得到了一个类似的结果,除了结果中的值之和是 4,这是我们通过应用这个过滤器可以得到的最高值。因此,我们知道我们在图像的底部垂直边缘找到了一个像素,因为我们得到了最大值 4。
要将这些值映射回 0–1 范围,我们只需将 4 相加,然后除以 8,将-4 映射到 0 ( 黑色),将 4 映射到 1 ( 白色)。因此,使用这种称为垂直索贝尔滤波器的滤波器,我们能够非常简单地检测图像中的垂直边缘。
水平边缘呢?我们简单地采用垂直滤波器的转置(关于它的对角线翻转),并将这个新的滤波器应用于图像以检测水平边缘。
现在,如果我们想要检测水平边缘、垂直边缘和介于两者之间的边缘,我们可以组合垂直和水平分数,如下面的代码所示。
希望理论清楚!现在让我们通过查看代码来结束。
如何执行边缘检测—代码
首先是一些设置:
- 把“pinwheel.jpg”替换成你想找到边缘的任何有趣的图片!确保它在同一个工作目录中。
以及边缘检测码本身:
需要注意一些事情:
- 图像周围将会有一个小边界,因为我们无法在边界像素上完全创建本地 3 x 3 框。
- 由于我们在水平和垂直边缘上都进行检测,所以我们只是将原始分数除以 4(而不是加上 4 然后除以 8)。这不是一个重大的变化,但它将更好地突出我们的形象的优势。
- 组合水平和垂直分数可能会导致最终边缘分数超出 0–1 范围,因此我们通过重新归一化分数来结束。
在更复杂的图像上运行上面的代码:
边缘检测的结果:
仅此而已!希望你学到了什么,敬请关注更多数据科学文章~
OpenCV 的边缘和轮廓基础知识
如何使用 Python 和 OpenCV 从图像中提取轮廓
我一直在尝试用 OpenCV 学习计算机视觉,在这篇文章中,我将探索边缘检测和轮廓。
上次我讲了内核和卷积的基础知识。这些方法被广泛用于不同的目的;其中一个引起了我的注意,我觉得这应该是学习计算机视觉的一个极好的下一步。
边缘检测和轮廓用于定位图像中颜色或亮度有很大变化的点。
原图由 Stefano 提供。
对我们来说,这看起来很简单直观,但对计算机来说,这可能会很棘手。
谨慎的
Canny 边缘检测是一种用于从图像中提取边缘的算法,由于它看起来非常简单,我相信我们可以从它开始。
该算法有四个阶段:
- 第一个 —用高斯模糊进行降噪;
- 第二个 —用 Sobel 核得到梯度方向和大小;
- 第三 —应用非最大抑制,去除不属于轮廓的多余像素;
- 第四个 —应用使用最小值和最大值的滞后阈值,通过强度梯度过滤轮廓。
尽管看起来不那么容易,但是用 OpenCV 实现 Canny 检测还是很舒服的。
我们从导入库开始。
import cv2
import numpy as np
import matplotlib.pyplot as plt
现在我们可以看看我们想要提取轮廓的图像。
image = cv2.imread('Images/12.png')
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)fig, ax = plt.subplots(1, figsize=(12,8))
plt.imshow(image)
插图由 Stefano 绘制。
要使用 Canny,我们需要将图像转换为灰度,然后使用方法。小心处理图像,以及最小和最大阈值。
我建议您尝试这些阈值,看看结果如何变化。
g = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
edge = cv2.Canny(g, 60, 180)fig, ax = plt.subplots(1, figsize=(12,8))
plt.imshow(edge, cmap='Greys')
轮廓。
很好,我们现在可以使用。寻找轮廓和。绘制轮廓,获取并绘制用 Canny 检测发现的外部轮廓。
contours = cv2.findContours(edge,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_NONE)cv2.drawContours(image, contours[0], -1, (0,0,255), thickness = 2)fig, ax = plt.subplots(1, figsize=(12,8))
plt.imshow(image)
图像上的轮廓。
酷,轮廓变量是一个包含所有 Canny 检测到的轮廓的列表——这意味着我们可以像这样访问和操作它们。
我们可以对这个列表进行排序,并传递 OpenCV 函数。countourArea 作为关键字,它将根据大小对所有检测到的轮廓进行排序。
让我们试着只画最大的等高线。
image = cv2.imread('Images/12.png')
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)contours, h = cv2.findContours(edge,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_NONE)contours = sorted(contours, key=cv2.contourArea, reverse=True)cv2.drawContours(image, contours[0], -1, (0,0,255), thickness = 5)fig, ax = plt.subplots(1, figsize=(12,8))
plt.imshow(image)
*请注意,我重新加载了原始图像,因为我们绘制了最后一个图像。
面积最大的等高线。
有意思,我想我期待的是别的东西,比如整个嘴唇,甚至是舌头。相反,最突出的轮廓是嘴的一部分,不知何故与牙齿相连。
我想这向我们表明,这些方法要么需要以前的操作,要么需要更直观的图像来达到预期的结果。以现在的方式,我们的轮廓在正确的位置,但它们太颗粒化,无法恢复一个完整的形状。
尽管如此,该方法允许我们选择我们正在寻找的特定轮廓,甚至过滤一些范围的值。
还有其他寻找轮廓的方法;例如,简单的二值化也可以完成这项工作。
image = cv2.imread('Images/12.png')
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
r, t = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)contours, h = cv2.findContours(t, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)cv2.drawContours(image, contours, -1, (0,0,255), thickness = 5)fig, ax = plt.subplots(1, figsize=(12,8))
plt.imshow(image)
具有阈值和二值化的轮廓。
同样,您可以尝试更改阈值,看看会发生什么。
凸包
轮廓的典型应用是检测图像中的几何形状,这对于简化涉及分类或对象检测的问题非常有用。
问题是,根据质量、角度、噪声和许多其他因素,轮廓很少是简单的多边形。这就是凸包出现的原因。这里的想法是简化由我们以前的边缘检测方法生成的多边形。
看看维基百科对凸包的定义:
在几何学中,一个形状的凸包或凸包络或凸闭包是包含它的最小凸集。
相当复杂,但是 OpenCV 用函数. convexHull 简化了这一步。
image = cv2.imread('Images/14.jpg')
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)g = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
edge = cv2.Canny(g, 140, 210)contours, hierarchy = cv2.findContours(edge, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)for c in contours:
hull = cv2.convexHull(c)
cv2.drawContours(image, [hull], 0, (0, 255, 0), 2)fig, ax = plt.subplots(1, figsize=(12,8))
plt.imshow(image)
很好,我们可以看到轮廓并不完全符合图纸,而是简化了水滴的形状。
我认为这是一个良好的开端,边缘检测,轮廓,以及不同的操作和步骤,我们可以添加到这个过程中。我鼓励你尝试边缘检测的参数、阈值和不同方法。
感谢阅读我的文章。我希望你喜欢它。
往期文章 :
核与卷积基础知识;
变换基础知识;
OpenCV 入门;
资源: OpenCV Canny;
OpenCV 特征检测;
OpenCV 凸包;
求简单多边形的凸包——罗纳德·l·格雷厄姆;
OpenCV 结构分析和形状描述;
学历还是经历?都是。
是的,你够好了,但是你必须努力。你好,我是尼克🎞 on Unsplash
一个老数学家的思考能教给一个数据科学家什么?
自从数据科学诞生以来,一直有一些争论没有得到解决。如果您关注社区中的讨论,您可能已经看到了许多关于以下问题的文章和帖子。
需要正规教育还是实际操作经验?
你应该专注于理论还是实践?
专攻一个领域还是努力成为通才?
你可能找到的答案通常位于光谱的极端部分。(尤其是当对话发生在 Twitter 上时,由于其受限的格式,完全不适合表达复杂的论点。)双方都有强有力的论据。
一方面,正规教育并不意味着深入的知识,尤其是在不属于标准课程的专业领域。作为一名数据科学家,需要一个学位可能意味着守门,这拒绝了许多有才华的人的进入。
另一方面,不了解事物如何工作的实践经验只是用户级别的知识。如果你会开车,并不意味着你能在发动机开始冒烟的时候修好它。在数据科学行业,我们都努力成为竞争环境中的竞赛机制。
同样的问题用不同的方式表述就是理论与实践的争论。对一些人来说,机器学习等同于证明定理。对其他人来说,它是在 Kubernetes 上清理数据或服务模型。哪一边是对的?
两者皆有。
数学如何面对同样的问题
科学史呈螺旋式上升。通常,我们会问几代人以前已经回答过的问题。由于时代精神,不同的背景促使我们重新评估问题,尽管许多旧的论点仍然存在。
数学家在 20 世纪也经历过类似的困境。在此期间,应用研究开始蓬勃发展。
纯数学是由它自身激发的,这在科学领域中是不常见的。问题赋予新理论生命,新理论又引发新问题,如此循环往复。群论基本上是由 variste Galois 创立的,目的是为了表明对于次数大于 4 的多项式,没有明确的求根公式。反过来,幺半群理论是出于对数学的好奇而形成的,以看看如果我们不假设每个元素的可逆性会发生什么。
这并不意味着幺半群理论没有用。相反,它在各个领域都得到了卓有成效的应用,尤其是在计算机科学领域。然而,这是由应用程序驱动的吗?没有。
然而,新一代的数学家经常挑战这一观点,因此出现了分歧。
理论还是应用?
雷尼的数学艺术
匈牙利数学研究的创始人之一阿尔夫雷德·雷尼给出了最精彩的答案。如果你对概率论感兴趣,你可能遇到过雷尼熵的概念,它是众所周知的香农熵的推广。
(如果这不熟悉,你可能见过这句话或它的一个变体:“数学家是把咖啡变成定理的装置。”这出自雷尼,尽管它被认为是保罗·erdős.的作品)
雷尼想,如果诗人有诗歌艺术,为什么数学家不能有数学艺术呢?
在他的著作中(不幸的是只有匈牙利语版本),他概述了数学家面临的几个关键困境。
学习还是研究?
知识面广还是知识面深?
自我批评还是自信?
个人工作还是团队合作?
理论还是应用?
数学精度还是直觉?
开辟新的研究领域还是在现有领域中寻找尚未解决的问题?
努力工作还是幸运的想法?
这些问题与今天的数据科学家、工程师和机器学习研究人员相关。雷尼的简答?
在所有的困境中,用“和”代替“或”。这是 Ars Mathematica。”阿尔弗雷·德·雷尼
让我们在数据科学的背景下解开这些单词。
理论与实践
为了建立一个共同点,让我们同意“教育与经验”实际上是一个“理论与实践”的困境。如果学位代表知识以外的任何东西,比如说社会地位,那么它就是守门人,因此是完全错误的。这里没有争论。所以我会把正规教育等同于理论知识,把工作经验等同于实践专长。
所以,回到数据科学。不要争论理论和实践孰先孰后,我们应该认识到两者都很重要,但不是两者都是进入这个领域的必要条件。
通往数据科学的道路有很多,其中也有很多。每一种都有它的长处和短处,但总的来说,它们很好地互补了。缺乏理论知识是完全没有问题的,因为不是所有的工作都需要你从头开始实现一个神经网络。(其实很少有人会。)
类似的论点也适用于那些来自更理论化背景的人。
像“数据科学需要多少数学?”是无效的。数据科学是巨大的。你想要哪一部分?有些部分根本不需要数学,而有些部分却充满了数学。然而,根据你的职业道路,你可能会需要了解数学。在这种情况下,计算机科学/数学学位是有用的,但如果你愿意花时间像学生一样学习,你也可以做到。
底线是,你最终将需要理论和实践,但是从一个方向开始是非常好的。
如果你喜欢把机器学习概念拆开,理解是什么让它们运转,我们有很多共同点。看看我的博客,我经常在那里发表这样的技术文章!
减少对妇女暴力的教育。
非洲家庭暴力信息图。
“对妇女和女孩的暴力行为(VAWG)是当今世界上最普遍、最持久和最具破坏性的侵犯人权行为之一,由于有罪不罚、沉默、耻辱和耻辱,这种行为在很大程度上仍未被报道。”
背景
在我提交的#改头换面星期一的文章中,我通过使用 Tableau 将补充图表绘制成故事点,改进了一个名为“消除对妇女暴力国际日”的 Viz。
不幸的是,Medium 不允许来自 Tableau 的交互式 Viz 块或代码嵌入,因此对于本演练,将使用静态屏幕截图来传达相关和重要的信息。
这是最初的,即。请随意在幻灯片/故事点上悬停,因为它们是交互式的!
数据源
人口和健康调查(DHS)是具有全国代表性的家庭调查,为人口、健康和营养领域的广泛监测和影响评价指标提供数据。
DHS 在非洲国家进行了一项关于妇女和男子如何为暴力侵害妇女行为辩护的调查。然后,数据集被分类为国家、参与者的人口统计数据、问题类型和同意率(认为在某些情况下暴力侵害妇女和女孩是合理的人的百分比)。
数据集特征的定义如下:
数据集的 Excel 文件或 Web 数据连接器 URL 可以从 data.world 获得。
静态故事点 1
应对非洲普遍存在的暴力侵害妇女行为
联合国对暴力侵害妇女行为的定义是"对妇女造成或可能造成身体、性或心理伤害或痛苦的任何基于性别的暴力行为,包括威胁实施这种行为、胁迫或任意剥夺自由,无论发生在公共生活还是私人生活中"。
从历史上看,非洲家庭明显重男轻女;非洲社会认为儿子是他们家庭的荣誉,而只有女儿的家庭会被打上烙印。儿子通常断奶较晚,吃得更好,更有可能入学。这些社会规范使女孩成长为低自我价值和低自尊的妇女,从而使永无休止的暴力循环永久化。因此他们认为在某些情况下殴打妇女是正当的。虽然这种错误的心态将很快被废黜。
联合国妇女署开展了一系列实质性和有效的区域努力,以扩大在非洲的外联范围,结束基于性别的暴力,并动员问责要求。民间社会团体为当地记者组织了关于性别暴力的讲习班;私营公司对性别歧视和性骚扰实行“零容忍”政策;中小学和大学已将提高认识活动纳入其课程。
在这项研究中,我们将深入探讨为什么我们会得出教育是消除暴力侵害妇女行为的关键促进因素这一结论,探究被调查妇女的哪些类型的行为会煽动男子做出身体上的冷酷行为,以及使用平均协议率作为 KPI,根据对妇女的家庭暴力对非洲国家进行排名。
按平均协议价值排名,厄立特里亚居首位,其次是阿富汗。
为了了解被调查女性导致她们受到男性同事身体虐待的行为,绘制了一个水平条形图——针对女性和男性平均认同值的调查问题。
女性和男性的平均一致值分别用紫色和银灰色进行颜色编码。
最站不住脚的虐待理由是当女人烧糊食物时。在另一个极端,参与者的男女都认为忽视他们的孩子为殴打提供了强有力的理由。
总体而言,与男性相比,更多的女性认为针对她们的暴力是正当的。这一事实有效地描述了这些国家的社会标准——对妇女的歧视以及在她们中间播下低自我价值和低自尊的种子——是如何使这种暴力循环永久化的。
静态故事点 4
深入研究参与调查的妇女的人口统计数据,可以发现,就教育背景而言,大多数受过高等教育的妇女似乎认为殴打的情况是不合理的。
静态故事点 5
高等教育似乎是根除对妇女和女童的不公正暴力的最大潜在因素。所有国家的平均同意率仅为 9.5%!显然,随着妇女的教育水平从高等教育倒退到未受教育,平均认同率大幅上升。如气泡图右侧所示,与教育水平较低的国家相比,多米尼加共和国的平均认同率仅为 0.3%。
就居住地而言,农村地区的妇女比城市人口更有可能认为暴力侵害她们是正当的。
尽管百分比差异不明显,但年轻妇女和女孩往往认为对她们的虐待是合理的。可以对这一年龄组进行进一步的研究。
结论
利用从上述信息图表的解释性分析中获得的洞察力,妇女赋权计划可以有效地分配资源,增加妇女接受高等教育的机会,以期大幅减少对她们的暴力行为,特别是在这些非洲国家。
VAWG 的不良心理后果影响到妇女一生的各个阶段。在这方面,教育劣势不仅是普及教育和女孩受教育权的主要障碍;这有可能转化为妇女在劳动力市场的有限机会。
虽然基于性别的暴力可能发生在任何人、任何地方,但一些妇女和女孩特别容易受到伤害——例如,年轻女孩、被认为是同性恋或双性恋的妇女、移民和难民、土著妇女和少数民族,以及经历人道主义危机的妇女。
对妇女的暴力行为仍然是实现平等、发展、和平以及实现妇女和女童人权的障碍。
参考
[1]阅读更多关于消除对妇女暴力的信息:【https://www.un.org/en/events/endviolenceday/
[2]以上故事点我的互动画面:https://public.tableau.com/profile/bryan.tan.jun.wei#!/viz home/violence against woman _ 15853280846490/story 1
财务报表发布对股票价格的影响
亨尼投资
一项研究分析了美国公司向美国证券交易委员会提交财报时的股价行为
在正确的时间购买正确的股票是成功投资的基础。作为一名数据科学家,我相信在数据中发现模式,这在投资领域是非常有利可图的。在这篇文章中,我将探讨“关于公司的好消息引发股价上涨”的模式,并与您分享我的观察。
机会
我们中许多看图表的人可能已经注意到,财务报表的发布会对股票价格产生直接影响。下面是一个从 www.vhinny.com借来的例子,关于 KHC 股票对该公司 10 季度报告的反应。
https://www.vhinny.com/display/KHC
在公司发布业绩后,你可以看到几乎任何股票的价格都会立即发生变化(下跌或上涨)。看到这种行为,投资者可能会想到两个问题。首先,有没有办法在价格变动发生之前预测它的走向?第二个,一旦发生变动,股票会继续朝着可预测的方向移动吗?
虽然一些投资者可能会发现第一个挑战很有吸引力,并在预测价格波动中看到机会,但我会站在以沃伦巴菲特为首的伟人一边,他可以说是有史以来最伟大的投资者,并简单地说:“我不知道怎么做”。为了使股价在财务报表发布后立即上涨,不仅要超过公司过去的收益,还要超过分析师对当前收益的预期。我认为,预测这两个事件中的任何一个都是一个挑战,由于缺乏可靠的信息,散户投资者无法应对。因此,避免一起尝试这种挑战可能是值得的。
另一方面,预测股价变化的第二个挑战是普通投资者可以用他或她拥有的工具应对的挑战。在本文中,我将探讨年度财务报表(10-K)的发布是否包含可操作的信号,投资者可以使用这些信号来决定是否有机会在购买时获利。
资源
为了进行这项研究,我使用了包含 www.vhinny.com的 10k 发行日期和 www.alphavantage.co的股票价格的金融数据。你可以在我的 GitHub 页面上找到本文讨论的分析的完整参考代码。
问题陈述和范围
目标:在本研究中,我将调查一旦财务报表发布,市场对此做出初步反应,是否存在做出投资决策的机会。
澄清:许多财务报表在闭市期间发布。在 KHC 的例子中(见上图),市场在 2020 年 2 月 12 日以 30 美元收盘,财务报表(10-Q)在盘后时间发布,市场在 2 月 13 日开盘,定价 KHC 下跌 10%,当天收盘时为 27 美元。在这项研究中,问题不是价格是否会下降 10%。确切地说是以下内容。一旦价格下降了 10%,是否有证据表明会进一步下跌?
数据集:本研究使用的数据集由 S & P 500 指数覆盖的 479 家公司组成,代表 2018 年 1 月至 2019 年 12 月(2 年)评估的 11 个行业领域。
方法:为了生成这个数据集,我首先确定了调查期间发布的财务报表的所有(公司,日期)对。对于财务报表发布的每个特定日期,我都添加了(公司,日期)在该日期没有发布财务报表的公司对。为了保持数据集大小的可管理性,后一种公司配对是为与发布财务报表的公司在同一行业运营的公司创建的。例如,如果在 2020 年 2 月 19 日,只有公司 A(信息技术)和公司 B(医疗保健)发布了他们的声明(正面示例),则在该日期将只介绍来自相同两个部门(信息技术和医疗保健)的公司(负面示例)。所有可用的(公司,日期)对都被夸大以覆盖“日期”和“日期+ 7 天”之间的时间段,以提供对股票价格行为的可见性。
插图:下面我举一个例子,一家公司于 2018 年 1 月 22 日发布了其财务报表(申报日期)。后续 7 个日历日(n_calendar)跟踪股价,一般相当于 5 个交易日(n_trading)。我还在“close”列中包含了“filing_date”时的股价,在“close_next_n”列中包含了“date”时的股价,以及表示“close”和“close_next_n”之间的百分比变化的“percent_growth”。列“归档 _ 发布”是指示该公司是否在“归档 _ 日期”发布财务报表的标志。如果“归档 _ 发布”为 0,则意味着该公司没有发布其财务报表,并用于与其他发布了财务报表的公司进行比较。
请注意 company_id=2236 在其财务报表于 2018 年 1 月 22 日发布后,如何从 2018 年 1 月 23 日的 197.84 美元涨到 200.09 美元
请注意,该公司(190)的提交日期与 2018 年 1 月 22 日相同,并且没有发布其申请(filing_released=0)。它也没有显示在这 7 天中任何有形的价格变化。
评估:我想评估一份“好消息”财务报表的发布是否对股价产生可操作的影响。为此,我将比较发布财报的公司(正面例子)和没有发布财报的公司(负面例子)的股价增长。为了消除市场趋势的影响,引入反面例子并进行比较分析而不是看绝对增长数字是很重要的。例如,如果一家公司属于“下降趋势”行业,积极的收益报告可能会阻止股价下跌,而不是显示积极的趋势。从绝对业绩来看,我们可以得出结论,该公司的财务报表没有影响,而与同行业的其他公司相比,该公司的业绩高于平均水平。
结果和讨论
该数据集包含 944 家公司的样本(每家公司 2 个样本,2018 年至 2019 年间每年 1 个样本)。财务报表一旦发布,我们需要一些时间来评估它对公司来说是“好消息”还是“坏消息”。我用财务报表发布后的第一天来决定它是正面还是负面的报表。如果第一天的价格增长超过了一定的阈值,我称之为信号,并得出结论,该声明具有积极的影响(购买该股票的信号)。为了说明这种方法,让我们考虑第一天价格增长 1%的阈值。这使我们有 257 家公司的样本(截至申请日)通过了这一门槛。相比之下,我们有 24315 家样本公司在相应的申报日期没有发布任何信息。接下来,让我们看看正面和负面例子的价格在第一天之后是如何变化的,看看它们的表现是否不同。下图显示了自财务报表发布后第一天,正面和负面示例的价格增长分布。
在该柱状图中,X 轴代表 n_trading=1(不含)和 n_trading=3(含)之间的价格增长百分比(从捕获即时价格增长后的 2 天开始)。粉色条柱(申报已发布)代表发布报告的公司;紫色柱(普通日)代表没有发布报告的公司。y 轴显示直方图上相应条柱内的样本百分比。
“备案发布”公司的样本分布在-0.001 均值附近,标准差为 0.025,“普通日”公司的样本分布在 0.002 均值附近,标准差为 0.026。计算这些分布的 p 值得到 0.072,这意味着缺乏证据来推断这些分布是不同的。然而,我们可以观察到,与“普通日”直方图相比,“申请释放”直方图向左移动。事实上,这与我的预期相反,即积极的财务报告会为价格在不久的将来向同一方向发展提供动力。
改变参数
现在我已经建立了实验,让我们看看阈值和偏移值的不同参数组合是否会产生不同的结果。我将使用 0.5%、1%和 1.5%的阈值来选择发布报告的公司的“正面例子”。我还将使用等于 1、2、3 和 4 的天数来评估股票价格的变化。这给了我们 3*4 = 12 种可能的参数组合。表现最好的组合(最低 p 值为 0.001)是阈值= 1%和移位= 4 天。下面是这个实验的分布。
“备案发布”公司的样本分布在-0.006 均值附近,标准差为 0.034,“普通日”公司的样本分布在 0.002 均值附近,标准差为 0.038。虽然这个实验确实具有较低的 p 值,这意味着分布中的差异具有统计学意义,但它使我们进一步远离了验证收益报告可以在财务报表发布后被用作积极信号,并且市场已经做出了最初的举动。
比较同一部门内的结果
到目前为止,该分析是针对数据集中不同行业的所有公司进行的。有人可能会说,不同的行业可能有不同的价格动态。因此,对我们“正面例子”来说,某些行业的上升趋势可能会超过报表驱动的运动。为了研究这个想法,我将每个实验的范围缩小到相同行业的公司,并进行相同的测试。下面是医疗保健部门的一项实验的摘录。
摘自 Jupyter 笔记本,补充本文
我鼓励读者参考本文附带的 Jupyter 笔记本了解详情。总之,这些测试没有提供令人信服的证据来支持财务报表发布事件具有作为投资者购买股票的信号的有形潜力的假设。
结论
在这项研究中,我旨在调查财务报表(10-K)的发布是否可以用作购买股票的信号。为了验证我的假设,我进行了一些实验,将发布财务报表的公司和不发布财务报表的公司的表现进行了比较。
这些实验没有显示支持本研究假设的证据,即看看投资者是否能在财报发布后观察到价格变化,并在趋势的方向和强度变得明确后加入趋势。
我请读者记住,这不是一个深入的分析,而是一个概念探索的快速证明。深入研究的机会包括调查公司年龄、市值、融资结构等各种细分。但是,作为一个投资者,我相信有更多有希望找到信号的地方应该首先探索。
使用机器学习来识别新冠肺炎期间受打击最大的股票中的共同因素。
towardsdatascience.com](/covid-19-rampage-on-the-stock-market-machine-learning-comes-to-explain-3332707954af)
我们连线吧!
我很高兴与和我有共同道路的人联系,这是对财务独立的追求。如果你也在寻求经济独立,或者你想和 T2 合作,交流想法,请随时联系我们!以下是一些可以找到我的地方:
- 【www.vhinny.com——投资研究平台,为您自己的分析提供金融数据
- https://www.linkedin.com/company/vhinny——加入我们在 LinkedIn 上的社区,在那里我和其他贡献者分享与投资相关的内容
干杯!
用于神经网络训练的梯度下降优化器
与 Apurva Pathak 合著
尝试梯度下降优化器
欢迎来到我们深度学习实验系列的另一部分,在这里我们进行实验来评估关于训练神经网络的常见假设。我们的目标是更好地理解影响模型训练和评估的不同设计选择。为了做到这一点,我们提出了关于每个设计选择的问题,然后运行实验来回答它们。
在本文中,我们试图更好地理解使用不同优化器的影响:
- 不同的优化器在实践中表现如何?
- 每个优化器对学习率或动量等参数选择的敏感程度如何?
- 每个优化器的收敛速度有多快?
- 选择一个好的优化器会带来多大的性能差异?
为了回答这些问题,我们评估了以下优化器:
- 随机梯度下降
- 带动量的 SGD
- 内斯特罗夫势头强劲的新加坡元
- RMSprop
- 圣经》和《古兰经》传统中)亚当(人类第一人的名字
- 阿达格拉德
- 循环学习率
实验是如何设置的?
我们使用不同的优化器训练神经网络,并比较它们的性能。这些实验的代码可以在 Github 的上找到。
- 数据集:我们使用猫狗数据集,它由 23,262 张猫狗图片组成,在两个类之间对半分割。由于图像大小不同,我们将它们调整到相同的大小。我们使用数据集的 20%作为验证数据(开发集),其余的作为训练数据。
- 评估度量:我们使用验证数据上的二进制交叉熵损失作为测量模型性能的主要度量。
图 1:来自猫狗数据集的样本图像
- 基本模型:我们还定义了一个受 VGG16 启发的基本模型,在这里我们重复应用(卷积->最大池-> ReLU ->批处理范数->丢弃)运算。然后,我们展平输出体积,并将其馈入两个完全连接的层(密集-> ReLU ->批处理-规范),每个层有 256 个单位,并在第一个 FC 层后丢弃。最后,我们将结果输入到一个具有 sigmoid 激活的单神经元层,产生一个介于 0 和 1 之间的输出,告诉我们该模型预测的是猫(0)还是狗(1)。
图 2:基本模型架构(使用 NN SVG 创建)
- 训练:我们使用 32 的批量大小和默认的权重初始化(Glorot uniform)。默认优化器是 SGD,学习率为 0.01。我们进行训练,直到验证损失在 50 次迭代中没有改善。
随机梯度下降
我们首先从普通的随机梯度下降开始。这由以下更新公式定义:
图 3: SGD 更新公式
其中 w 是权重向量,dw 是损失函数相对于权重的梯度。这个更新规则向损失函数的最大下降方向迈出了一步,帮助我们找到一组使损失最小化的权重。请注意,在纯 SGD 中,更新是针对每个示例应用的,但更常见的是对一批示例(称为小批)进行计算。
学习率如何影响 SGD?
首先,我们探讨学习率如何影响 SGD。众所周知,选择过低的学习速率会导致模型收敛缓慢,而过高的学习速率会导致模型根本不收敛。
图 4:优化器收敛图解,摘自杰瑞米·乔登网站
为了通过实验验证这一点,我们沿着 0.001 和 0.1 之间的对数标度改变学习速率。让我们先画出训练损失。
图 5:不同学习率下 SGD 的培训损失曲线
我们确实观察到,当学习率既不太小也不太大(红线)时,性能是最佳的。最初,增加学习率会加快收敛,但在学习率为 0.0316 之后,收敛实际上会变得更慢。这可能是因为步长越大,实际上可能会超过最小损耗,如图 4 所示,从而导致更高的损耗。
现在让我们画出验证损失图。
图 6:不同学习率下 SGD 的验证损失曲线
我们观察到,当我们选择太小或太大的学习率时,验证性能会受到影响。太小(例如 0.001),验证损失根本不会减少,或者减少得非常慢。太大(例如 0.1)并且验证损失不能达到较小学习率所能达到的最低值。
现在让我们画出每个学习率*所达到的最佳培训和验证损失:
图 7:不同学习率下 SGD 的最小培训和验证损失
上述数据证实了“金发女孩”理论,即选择一个既不太小也不太大的学习率,因为最佳学习率(3.2e-2)在我们尝试的值范围的中间。
*通常,我们预计验证损失会高于训练损失,因为模型之前没有看到验证数据。然而,我们从上面可以看到,验证损失有时比训练损失要低得多。这可能是由于脱落,因为神经元仅在训练时脱落,而不是在评估期间脱落,导致评估期间的性能比训练期间更好。当辍学率较高时,这种影响可能特别明显,就像我们的模型一样(FC 层上的辍学率为 0.6)。
最佳新币验证损失
- 最佳验证损失:0.1899
- 相关培训损失:0.1945
- 时代收敛到最小值:535
- 参数:学习率 0.032
新币外卖
- 选择一个好的学习率(不要太大,也不要太小)对于确保 SGD 的最佳性能至关重要。
带动量的随机梯度下降
概观
带动量的 SGD 是 SGD 的变体,通常比普通 SGD 收敛得更快。它通常定义如下:
图 8:用动量更新 SGD 方程
good fellow 等人的深度学习解释了算法背后的物理直觉[0]:
形式上,动量算法引入了一个扮演速度角色的变量v——它是参数在参数空间中移动的方向和速度。速度被设置为负梯度的指数衰减平均值。
换句话说,参数以随时间变化的速度穿过参数空间。速度的变化由两项决定:
- 𝛼,学习率,它决定了梯度对速度的影响程度
- 𝛽,速度随时间衰减的速率
因此,速度是梯度的指数平均值,它包含新的梯度,并随着时间的推移自然衰减旧的梯度。
人们可以想象一个球从山上滚下来,速度越来越快。重力对球施加力,使其加速或减速,如梯度项𝛼 ** dw* 所示。球也会遇到粘性阻力,导致其速度衰减,正如𝛽.所描述的那样
动量的一个作用是加速沿着梯度方向一致的维度的更新。例如,考虑梯度为常数 c 时动量的影响:
图 9:梯度为常数 c 时速度随时间的变化。
普通的 SGD 每次都会更新 - 𝛼 c ,而具有动量的 SGD 会随着时间加速,最终达到比普通更新大 1/1-𝛽倍的最终速度(使用无穷级数的公式得出)。例如,如果我们将动量设置为𝛽=0.9,那么更新最终会变成普通更新的 10 倍。
动量的另一个作用是抑制振荡。例如,考虑这样一种情况,即渐变经常沿着某个维度弯曲并改变方向:
图 10:动量图,来自 Ekaba Bisong 的更多关于优化技术的内容
动量项抑制了振荡,因为当我们把振荡项加到速度中时,它们就抵消了。这允许更新由梯度始终指向相同方向的维度支配。
实验
让我们看看学习率为 0.01 时动量的作用。我们尝试动量值[0,0.5,0.9,0.95,0.99]。
图 11:学习率为 0.01 时动量对训练损失(左)和验证(右)的影响。
上面,我们可以看到,将动量增加到 0.9 有助于模型训练更快地收敛,因为训练和验证损失以更快的速度减少。然而,一旦我们超过 0.9,我们观察到训练损失和验证损失实际上受到影响,模型训练完全不能收敛于动量 0.99。为什么会这样?这可能是因为过大的动量阻止模型适应梯度更新中的新方向。另一个潜在的原因是权重更新变得如此之大,以至于超过了最小值。然而,这仍是未来调查的一个领域。
我们是否观察到振荡的减少,这被吹捧为动量的好处?为了测量这一点,我们可以计算每个更新步骤的振荡比例,即与之前的更新相比,当前更新中有多少比例的参数更新具有相反的符号。事实上,增加动量会降低振荡参数的比例:
图 12:动量对振荡的影响
更新的大小呢——动量的加速属性增加了更新的平均大小吗?有趣的是,动量越高,初始更新越大,但后期更新越小:
图 13:动量对平均更新大小的影响
因此,增加动量导致采取较大的初始步骤,但较小的后续步骤。为什么会这样呢?这可能是因为动量最初受益于加速度,导致初始步长更大。后来,动量导致振荡抵消,这可能使后面的步骤更小。
支持这种解释的一个数据点是每个时期所经过的距离(定义为时期开始时的权重和时期结束时的权重之间的欧几里德距离)。我们看到,尽管动量值越大,后面的步长越小,但实际上它们移动的距离越大:
图 14:对于每个动量值,每个时期遍历的距离。
这表明,即使增加动量值会导致后面的更新步骤变得更小,但遍历的距离实际上更大,因为这些步骤更有效——它们不会经常相互抵消。
现在,让我们看看动量对一个小的学习率(0.001)的影响。
图 15:学习率为 0.001 时动量对训练损失(左)和验证损失(右)的影响。
令人惊讶的是,在小的学习率上增加动力有助于它收敛,而以前没有!现在,让我们来看一个大的学习率。
图 16:学习率为 0.1 时动量对训练损失(左)和验证损失(右)的影响。
当学习率较大时,增加动量会降低性能,甚至会导致模型无法收敛(参见上面对应于动量 0.9 和 0.95 的平线)。
现在,为了概括我们的观察结果,让我们看看所有学习速率和动量的最小训练损失和验证损失:
图 17:不同学习速度和动量下的最小训练损失(左)和验证损失(右)。每行中的最小值以绿色突出显示。
我们看到学习率和动量密切相关——学习率越高,“可接受的”动量值(即不会导致模型训练发散的值)的范围越低。相反,动量越高,可接受的学习率范围越低。
总的来说,所有学习率的行为表明,增加动量的效果类似于增加学习率。它有助于较小的学习率收敛(图 14),但可能导致较大的学习率发散(图 15)。如果我们考虑图 9 中的终端速度解释,这是有意义的——增加动量可以导致更新达到比普通更新本身大得多的终端速度。
然而,请注意,这并不意味着增加动量与增加学习速率是相同的——在增加动量和增加学习速率之间的收敛/发散行为方面有一些简单的相似之处。更具体地说,正如我们在图 12 和图 13 中看到的,动量也会减少振荡,并在训练开始时预先加载大量更新——如果我们只是提高学习速率,我们不会观察到相同的行为。
动量的另一种表述
还有另一种定义动量的方法,表述如下:
图 18:动量的替代定义
吴恩达在 Coursera 的深度学习专业中使用了动量的定义。在这个公式中,速度项是梯度的指数移动平均值,由参数β控制。更新被应用于权重,更新的大小由学习速率α控制。注意,当展开时,这个公式在数学上与第一个公式相同,除了所有项都乘以 1-β。
这种动量公式在实践中是如何工作的?
图 19:动量(替代公式)对训练损失(左)和验证损失(右)的影响
令人惊讶的是,使用这种替代公式,看起来增加动量实际上减慢了收敛!
为什么会这样呢?这种动量公式虽然抑制了振荡,但并不像另一种公式那样具有加速的好处。如果我们考虑一个玩具的例子,其中梯度总是一个常数 c ,我们看到速度永远不会加速:
图 20:恒定 c 的重复梯度下速度随时间的变化
事实上,吴恩达认为,这种动量公式的主要好处不是加速度,而是它抑制振荡的事实,允许你使用更大的学习速率,从而更快地收敛。基于我们的实验,增加动量本身(在这个公式中)而不增加学习速率不足以保证更快的收敛。
SGD 最佳验证损失与动量
- 最佳验证损失:0.2046
- 相关培训损失:0.2252
- 聚合到最小值的时期:402
- 参数:学习率 0.01,动量 0.5
带动力外卖的新加坡元
- 基于我们测试的参数,动量导致模型训练收敛更快,但不能保证改善最终的训练或验证损失。
- 学习率越高,可接受动量值的范围越低(模型训练收敛的范围)。
具有内斯特罗夫动量的随机梯度下降
动量的一个问题是,虽然梯度总是指向最大损失减少的方向,但动量可能不是。为了校正这一点,内斯特罗夫动量在一个前瞻点(w +速度)而不是 w 处计算梯度。这给梯度一个校正动量项的机会。
图 21:内斯特罗夫更新。左图:插图。右图:方程式。
为了说明内斯特罗夫如何帮助训练更快地收敛,让我们看一个虚拟的例子,其中优化器试图下降一个碗形的损失表面,最小值在碗的中心。
图 22。左:常规动量。右图:内斯特罗夫动量。
如图所示,内斯特罗夫收敛更快,因为它在一个前瞻点计算梯度,从而确保更新更快地接近极小值。
让我们在我们用于常规动量的学习率和动量的子集上尝试内斯特罗夫,看看它是否能加速收敛。我们来看看学习率 0.001 和动量 0.95:
图 23:内斯特罗夫动量对 lr 0.001 和动量 0.95 的影响。
在这方面,内斯特罗夫似乎确实在迅速加快收敛速度!如果我们把动量增加到 0.99 呢?
图 24:内斯特罗夫动量对 lor 0.001 和动量 0.99 的影响。
现在,内斯特罗夫实际上在训练损失上收敛得更慢,虽然它最初在验证损失上收敛得更快,但它变慢了,并在大约 50 个时代后被动量超过。
我们应该如何衡量所有训练运行的收敛速度?让我们看看常规动量在 50 个时代后的损失,然后确定内斯特罗夫需要多少个时代才能达到同样的损失。我们将收敛比定义为这个历元数除以 50。如果它小于 1,那么内斯特罗夫比常规动量收敛得更快;相反,如果它更大,那么内斯特罗夫收敛得更慢。
图 25。50 个时期后,内斯特罗夫损失收敛到常规动量损失的时期比率。内斯特罗夫跑得更快的训练用绿色突出显示;红色较慢;内斯特罗夫和常规动量都没有汇聚成黄色。
我们看到,在大多数情况下(10/14),加入内斯特罗夫会导致训练损失下降得更快,如表 5 所示。这同样适用于表 6 中验证损失的较小程度(8/12)。
添加内斯特罗夫的加速和其他参数(学习速率和动量)之间似乎没有明确的关系,尽管这可能是未来研究的一个领域。
内斯特罗夫势头的新币最佳验证损失
- 最佳验证损失:0.2020
- 相关培训损失:0.1945
- 聚合到最小值的时期:414
- 参数:学习率 0.003,动量 0.95
图 26。每次训练运行达到的最小训练和验证损失。每行中的最小值以绿色突出显示。
带内斯特罗夫动力外卖的新加坡元
- 内斯特罗夫动量法计算前瞻点处的梯度,以说明动量效应。
- 与常规动量相比,内斯特罗夫通常收敛得更快。
RMSprop
在 RMSpropr 中,我们对每个权重参数执行以下操作:
- 保持平方梯度的移动平均值。
- 将梯度除以移动平均值的平方根,然后应用更新。
更新方程式如下:
图 27: RMSprop 更新方程—改编自吴恩达的深度学习专业
这里,rho 是一个超参数,它定义了移动平均线适应新术语的速度,rho 越高,移动平均线变化越慢。ε是一个小数字,用来防止被零除。α是学习率,w_i 是权重 I,a_i 是移动平均值,dw_i 是权重 I 的梯度。
RMSprop 在概念层面上试图做什么?RMSprop 正在尝试规范化更新的每个元素,以便没有一个元素过大或过小。作为一个例子,考虑一个权重参数,其中梯度是5,5,5.第二个等式中的分母是 5,因此应用的更新将是-[1,1,1]。现在,考虑一个权重参数,其中梯度为[0.5,0.5,0.5];分母将是 0.5,给出与前一种情况相同的更新-[1,1,1]!换句话说,RMSprop 更关心每个权重的符号(+或-),而不是幅度,并尝试对每个权重的更新步长进行标准化。
这不同于普通的 SGD,后者对具有较大梯度的权重参数应用较大的更新。考虑上面的例子,其中梯度是[5,5,5],我们可以看到结果更新将是-[5,5,5],而对于[0.5,0.5,0.5]的情况,更新将是-[0.5,0.5,0.5]。
学习率和 rho 如何影响 RMSprop?
让我们在改变学习率𝛼(默认为 0.001)和系数𝜌(默认为 0.9)的情况下尝试 RMSprop。让我们首先尝试设置𝜌 = 0,并改变学习率:
图 28:不同学习速率下的 RMSProp 训练损失,rho = 0。
第一个教训是——看起来𝜌=0 的 RMSProp 表现不佳。这导致更新如下:
图 29:rho = 0 时的 RMSprop
为什么这不能很好地执行是未来研究的一个领域。
让我们在非零ρ值上再试一次。我们首先绘制了小学习率(1e-3)的训练和验证损失。
图 30:不同 rho 值下的 RMSProp,学习速率为 1e-3。
增加 rho 似乎减少了训练损失和验证损失,但是随着收益递减,当 rho 从 0.95 增加到 0.99 时,验证损失停止改善。
现在让我们来看看当我们使用更大的学习率时会发生什么。
图 31:不同 rho 值下的 RMSProp,学习速率为 3e-2。
在这里,训练和验证的损失完全不一致!
让我们看看所有参数的最小培训和验证损失:
图 32:不同学习速率和 rho 值下 RMSprop 的最小训练损失(左)和最小验证损失(右)。每行中的最小值以绿色突出显示。
从上面的图中,我们发现一旦学习率达到 0.01 或更高,RMSprop 就无法收敛。因此,这里找到的最佳学习率大约是 SGD 上的最佳学习率的十分之一!一种假设是分母项比 1 小得多,因此它有效地扩大了更新。因此,我们需要向下调整学习率来补偿。
关于𝜌,我们可以从上面的图表中看到,RMS 在高𝜌值(0.9 到 1)的数据中表现最佳。尽管 Keras 文档建议使用𝜌=0.9 的默认值,但也值得探索其他值——当我们将 rho 从 0.9 增加到 0.95 时,它大大改善了最佳获得验证损失,从 0.2226 增加到 0.2061。
RMSprop 上的最佳验证损失
- 最佳验证损失:0.2061
- 相关培训损失:0.2408
- 聚合到最小值的时期:338
- 参数:学习率 0.001,ρ0.95
RMSprop 外卖
- RMSprop 似乎在比普通 SGD 小得多的学习速率下工作(大约小 10 倍)。这可能是因为我们将原始更新(dw)除以平均梯度。
- 此外,探索不同的 𝜌 值似乎是值得的,这与 Keras 文档推荐使用默认值相反。
圣经》和《古兰经》传统中)亚当(人类第一人的名字
Adam 有时被认为是首选的优化器,因为它比 SGD 和其他优化方法收敛得更快[1]。本质上是 SGD 与 momentum 和 RMSProp 的结合。它使用以下更新公式:
图 33: Adam 更新等式
本质上,我们保留了一个类似于动量项的速度项——它是梯度更新的指数平均值。我们还保留一个平方项,它是梯度平方的指数平均值,类似于 RMSprop。我们也用(1—β)来修正这些项;否则,指数平均值将在开始时以较低的值开始,因为没有要平均的先前项。然后,我们将修正后的速度除以修正后的平方项的平方根,并将其作为我们的更新。
学习率如何影响 Adam?
有人建议学习率比β1 和β2 参数更重要,所以让我们首先尝试改变学习率,对数标度从 1e-4 到 1:
图 34:不同学习率下 Adam 的培训损失(左)和验证损失(右)。
我们没有绘制 0.03 以上的学习率,因为它们没有收敛。我们发现,随着学习速度的提高,训练和验证的损失会更快地减少——但只是到了一定程度。一旦我们将学习率提高到 0.001 以上,训练和验证损失都开始变得更糟。这可能是由于图 4 所示的“过冲”行为。
那么,哪种学习率最好呢?让我们通过绘制每一个的最佳验证损失来找出答案。
图 35:不同学习率下 Adam 的最小培训和验证损失。
我们看到学习率 0.001(碰巧是默认学习率)上的验证损失似乎是最好的,为 0.2059。对应的训练损失为 0.2077。然而,这仍然比最好的 SGD 运行差,后者实现了 0.1899 的验证损失和 0.1945 的训练损失。我们能战胜它吗?让我们试着改变β1 和β2 看看。
β1 和β2 是如何影响 Adam 的?
我们对β1 和β2 尝试以下值:
beta_1_values = [0.5, 0.9, 0.95]
beta_2_values = [0.9, 0.99, 0.999]
图 beta _ 1 和 beta_2 不同值的训练损失(左)和验证损失(右)。
图 37:最小培训损失(左)和最小验证损失(右)。每行中的最小值以绿色突出显示。
最佳运行是β1=0.5 和β2=0.999,这实现了 0.2071 的训练损失和 0.2021 的验证损失。我们可以将其与 Adam 的默认 Keras 参数(β1=0.9 和β2=0.999)进行比较,后者分别达到 0.2077 和 0.2059。因此,与 Keras 文档中的建议相反,使用不同的 beta_1 和 beta_2 值进行实验会有所回报,但改善并不大。
令人惊讶的是,我们无法击败最好的 SGD 性能!原来别人也注意到了,用动量或者其他优化算法,Adam 有时候效果比 SGD 差[2]。虽然原因超出了本文的范围,但它表明尝试不同的优化器以找到最适合您的数据是值得的。
最佳亚当验证损失
- 最佳验证损失:0.2021
- 相关培训损失:0.2071
- 时代收敛到最小值:255
- 参数:学习率 0.001,β1=0.5,β2=0.999
亚当外卖
- 与其他优化器相比,Adam 不能保证获得最佳的训练和验证性能,因为我们发现 SGD 优于 Adam。
- 尝试β1 和β2 的非默认值可以稍微改善模型的性能。
阿达格拉德
Adagrad 累加梯度的平方,并将更新除以该累加器项的平方根。
图 38: Adagrad 更新方程[3]
这与 RMSprop 类似,但区别在于它只是累加梯度的平方,而不使用指数平均值。这应该会导致更新的大小随着时间的推移而衰减。
让我们以不同的学习率来尝试 Adagrad,从 0.001 到 1。
图 39:不同学习速度下的 Adagrad。左:训练失利。右图:验证损失。
使用 3e-1 的学习率,最佳的训练和验证损失是 0.2057 和 0.2310。有趣的是,如果我们使用相同的学习率与 SGD 进行比较,我们注意到 Adagrad 最初与 SGD 并驾齐驱,但在后来的时代开始落后。
图 40: Adagrad 与 SGD 在相同学习速率下的对比。左:训练失利。右图:验证损失。
这可能是因为 Adagrad 最初被一个小数字除,因为梯度累加器项还没有累加许多梯度。这使得更新可以与 SGD 在初始时期的更新相媲美。然而,随着累加器项累积更多的梯度,Adagrad 更新的大小减小,因此损耗开始变平或者甚至上升,因为它变得更加难以达到最小值。
令人惊讶的是,当我们使用大的学习率(3e-1)时,我们观察到相反的效果:
图 41:大学习率(0.316)下 Adagrad vs SGD。左:训练失利。右图:验证损失。
在大的学习速率下,Adagrad 实际上比 SGD 收敛得更快!一种可能的解释是,当大的学习率导致 SGD 采取过大的更新步骤时,Adagrad 将更新除以累加器项,本质上使更新更小且更“最优”
让我们看看所有参数的最小训练和验证损失:
图 Adagrad 的最小训练和验证损失。
我们可以看到,Adagrad 的最佳学习率为 0.316,明显大于 SGD 的最佳学习率 0.03。如上所述,这很可能是因为 Adagrad 除以累加器项,导致更新的有效大小较小。
阿达格拉德最佳验证失败
- 最佳验证损失:0.2310
- 相关培训损失:0.2057
- 聚合到最小值的时期:406
- 参数:学习率 0.312
阿达格拉德外卖店
- Adagrad 累加梯度的平方,然后将更新除以累加器项的平方根。
- Adagrad 的更新量会随着时间的推移而减少。
- 【Adagrad 的最优学习速率比 SGD 大(在我们的例子中至少是 10 倍)。
循环学习率
循环学习率是一种让学习率在最小值和最大值之间循环变化的方法[4]。它声称消除了调整学习率的需要,并且可以帮助模型训练更快地收敛。
图 43:使用三角周期的周期学习率
我们尝试具有合理学习速率界限(base_lr=0.1,max_lr=0.4)的循环学习速率,并且步长等于 4 个历元,这在作者建议的 4-8 范围内。
图 44:循环学习率。左:列车失联。右图:验证损失。
由于学习率的周期性变化,我们观察到训练损失的周期性振荡。我们在验证损失中也看到了较小程度的这些振荡。
最佳 CLR 培训和验证损失
- 最佳验证损失:0.2318
- 相关培训损失:0.2267
- 时代收敛到最小值:280
- Params:使用上述设置。但是,我们可以通过调整周期策略(例如,允许最大和最小界限衰减)或调整最大和最小界限本身来获得更好的性能。请注意,这种调整可能会抵消 CLR 声称可以节省的时间。
CLR 外卖
- CLR 在最小和最大界限之间循环改变学习率。
- CLR 有可能消除调整学习率的需要,同时获得相似的性能。然而,我们没有取得类似的业绩。
比较
那么,经过上面的所有实验,哪一个优化器最终工作得最好呢?让我们从每个优化器中选择最佳运行,即验证损失最低的优化器:
图 45:每个优化器实现的最佳验证损失。
令人惊讶的是,SGD 获得了最好的验证损失,而且是以显著的优势获得的。然后,我们有 SGD 与内斯特罗夫动量,亚当,SGD 与动量,和 RMSprop,他们都表现相似。最后,Adagrad 和 CLR 排名最后,损失明显高于其他公司。
培训流失怎么办?让我们画出上面选择的跑步的训练损失:
图 46:对于上面选择的最佳运行,每个优化器实现的训练损失。
在这里,我们看到了一些与验证损失的相关性,但 Adagrad 和 CLR 的表现比它们的验证损失所暗示的要好。
融合呢?让我们首先来看看每个优化器收敛到最小验证损失需要多少个时期:
图 47:收敛到极小值的次数。
亚当显然是最快的,而 SGD 是最慢的。
然而,这可能不是一个公平的比较,因为每个优化器的最小验证损失是不同的。测量每个优化器达到固定验证损失需要多少个时期怎么样?让我们取最差的最小验证损失 0.2318(CLR 达到的损失),并计算每个优化器达到该损失需要多少个时期。
图 48:收敛到最差最小验证损失的周期数(0.2318,由 CLR 实现)。
同样,我们可以看到 Adam 确实比任何其他优化器更快地收敛到给定的损失,这是其声称的优势之一。令人惊讶的是,有动量的新币似乎比香草新币收敛得更慢!这是因为具有动量轮的最佳 SGD 所使用的学习率低于最佳普通 SGD 所使用的学习率。如果我们保持学习速率不变,我们会发现动量事实上的确会加速收敛:
图 49:比较 SGD 和带动量的 SGD。
如上所述,最佳香草 SGD 运行(蓝色)比具有动量运行(橙色)的最佳 SGD 收敛得更快,因为学习率为 0.03,高于后者的 0.01。然而,当通过与学习速率为 0.01(绿色)的普通 SGD 进行比较来保持学习速率不变时,我们看到增加动量确实加快了收敛。
为什么亚当打不过香草 SGD?
正如在 Adam 一节中提到的,其他人也注意到 Adam 有时在动量或其他优化算法方面比 SGD 更差[2]。引用 Vitaly Bushaev 关于 Adam 的文章,“过了一段时间,人们开始注意到,尽管训练时间很长,Adam 在某些领域并没有收敛到最优解,因此对于一些任务(例如在流行的 CIFAR 数据集上的图像分类),最先进的结果仍然只能通过应用具有动量的 SGD 来实现。”[2]虽然确切的原因超出了本文的范围,但其他人已经表明 Adam 可能收敛到次优解,即使是在凸函数上。
结论
总的来说,我们可以得出结论:
- 你应该调整你的学习率——它对你的模型的性能有很大的影响,甚至比优化器的选择更大。
- 根据我们的数据,vanilla SGD 的表现最好,但 Adam 的表现也差不多,只是收敛速度更快。
- 值得尝试 RMSprop 中的 rho 和 Adam 中的 beta 值的不同值,尽管 Keras 建议使用默认参数。
参考
https://www.deeplearningbook.org/contents/optimization.html
[1]迪德里克·p·金马和吉米·巴雷。 Adam:一种随机优化的方法。2014.arXiv:1412.6980v9
[2]https://towards data science . com/Adam-latest-trends-in-deep-learning-optimization-6be 9a 291375 c
[3]https://ruder . io/optimizing-gradient-descent/index . html # adagrad
[4]莱斯利·史密斯。https://arxiv.org/pdf/1506.01186.pdf
异常值的影响
威尔·梅尔斯在 Unsplash 上拍照
介绍
当我们开始处理数据时,我们(通常总是)观察到数据中几乎没有错误,比如缺失值、异常值、没有适当的格式等等。简而言之,我们称之为不一致性。这种一致性或多或少会扭曲数据,并妨碍机器学习算法进行正确预测。
在本文中,我们将尝试了解异常值如何影响机器学习算法的准确性,以及缩放如何帮助或影响我们的学习。为了简化目标,我们使用了两种非参数算法,k-NN 和决策树。
关于数据集
我们将使用从 UCI 机器学习库获得的埃及患者的丙型肝炎病毒(HCV)数据集。可从以下渠道获得:
http://archive . ics . UCI . edu/ml/datasets/肝炎+丙型+病毒+% 28 HCV % 29+for+埃及+患者
该数据包含了接受了约 18 个月 HCV 治疗剂量的埃及患者。共有 1385 名患者具有 29 种属性。这些属性包括年龄、白细胞计数、红细胞计数、血小板计数等。
处理数据
首要的事情是用 python 加载数据和所需的库。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
pd.set_option('display.max_columns', None) # This will help yoy view all the columns rather than the sample when using *dataframe.head()*df = pd.read_csv('HCV-Egy-Data.csv')
df.head()
一旦我们通过数据集,它几乎建议检查是否有任何我们前面提到的不一致。为此,我们将使用 python 的 info 函数。
df.info()
df.info()结果
在这里,我们观察到我们没有任何丢失的值,并且由于数据是数字数据,我们可以确定所有的属性值都是数字的,即 int64 或 float64 类型。此外,没有空值,因此我们可以使用我们的数据来建模。
我们还想看看是否有异常值,在 pandas 库中的一个快速检查是使用 describe() 函数。它为我们提供了所需的统计数据,如最小-最大值、分位数、标准偏差等。
df.describe()
这里,我们观察到 RNA EOT 的最小值为 5,这与我们的平均值相差甚远。现在我们确定至少有一个异常值。因此,我们将看到如何处理异常值影响我们的模型。
目标变量:基线组织学分期
一点背景,如果活检获得的组织足够大,观察者之间的一致是非常好的,特别是对于纤维化。为了帮助标准化病理学家之间的组织学评估,特别是提高从事不同临床试验的不同研究者之间的组织学测量的客观性,几个小组已经提出了用于分级活动和分期纤维化的组织学方案。在 Metavir 系统中,将坏死性炎症活性分级为 0-3 级。对于与疾病阶段的预处理评估问题更相关的量化纤维化,HAI、改良 HAI 和 Metavir 系统依赖于 0 至 4 或 0 至 6 的标度。
我们将使用 Metavir 系统,因为它给了我们 4 个多级分类,并取消了“基线组织学分级”,因为它们符合相同的逻辑。
df = df.drop('Baseline histological Grading',axis=1)
建模
由于我们的数据在不同的尺度上,我们执行了缩放以将每个属性放在一个共同的尺度上。这将进一步减少异常值的影响。
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(df.drop('Baselinehistological staging',axis=1))
scaled_features = scaler.transform(df.drop('Baselinehistological staging',axis=1))
df_feat = pd.DataFrame(scaled_features,columns=df.columns[:-1])
df_feat.head()
我们将利用 scikit-learn 库对我们的数据进行拆分和建模。
from sklearn.model_selection import train_test_split
X = df.drop('Baselinehistological staging',axis=1)
y = df['Baselinehistological staging']
X_train, X_test, y_train, y_test = train_test_split(scaled_features,df['Baselinehistological staging'],
test_size=0.20)# here test_size = 20 tells us that the data is split into train 80/20 ratio.
K-最近邻(k-NN)
一旦我们将数据分成训练和测试数据集,我们就可以运行 k = 1 或(n_neighbors = 1)的 k-NN 算法,并检查数据的准确性。
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=1)
knn.fit(X_train,y_train)
pred = knn.predict(X_test)
from sklearn.metrics import classification_report,confusion_matrix
print(confusion_matrix(y_test,pred))
print(classification_report(y_test,pred))
该模型的精确度为 24%,总体来说很差,但这不是我们的目标。我们可以运行肘法来选择最佳的 k 值。
error_rate = []# Will take some time
for i in range(1,40,2):
knn = KNeighborsClassifier(n_neighbors=i)
knn.fit(X_train,y_train)
pred_i = knn.predict(X_test)
error_rate.append(np.mean(pred_i != y_test))plt.figure(figsize=(10,6))
plt.plot(range(1,40,2),error_rate,color='blue', linestyle='dashed', marker='o', markerfacecolor='red', markersize=10)
plt.title('Error Rate vs. K Value')
plt.xlabel('K')
plt.ylabel('Error Rate')
其中我们看到最小误差率为 k = 35,精度为 31 %。
决策树
# decision Tree classifier
from sklearn.tree import DecisionTreeClassifier
dtree = DecisionTreeClassifier()
dtree.fit(X_train,y_train)
pred = dtree.predict(X_test)print(confusion_matrix(y_test,pred))
print(classification_report(y_test,pred))
运行上述代码,我们观察到准确率为 25 %,未能超过 k-NN。
移除异常值
我们将移除超出数据的 2 %和 98 %的异常值。
# Remove Outliers
df1 = df
col = list(df1.drop('Baselinehistological staging',axis=1).columns)
for i in col:
y = df[i]
removed_outliers = y.between(y.quantile(.02), y.quantile(.98))
index_names = df[~removed_outliers].index
df.drop(index_names, inplace=True)
我们观察到 k-NN 在 k =1 时的准确度为 28%,提高了约 16%。类似地,在 k = 21 时,给出了 33%,这大约增加了 6%,但是,对于决策树,我们的准确度几乎降低了 4%。
结论
我们可以得出结论,去除异常值增加了模型的准确性。尽管它在 k-NN 中显著提高了准确性,但在决策树中却降低了。这就引出了我们分析的下一步,即参数调整。我们将深入研究参数调整,以实现更高的精度。
参考
- https://aasldpubs . online library . Wiley . com/doi/pdf/10.1002/hep . 1840360720
- Dua d .和 Graff c .(2019 年)。UCI 机器学习知识库[http://archive . ics . UCI . edu/ml]。加州欧文:加州大学信息与计算机科学学院。
有效的利他主义、人工智能安全以及从世界状态中学习人类偏好
苹果 | 谷歌 | SPOTIFY | 其他
Rohin Shah 在 TDS 播客
要选择章节,请访问我们的 Youtube 视频这里
编者按:这一集是我们关于数据科学和机器学习新兴问题的播客系列的一部分,由 Jeremie Harris 主持。除了主持播客,Jeremie 还帮助运营一家名为sharpes minds的数据科学导师初创公司。你可以听下面的播客:
如果你走进一个房间,里面满是随机散落的物品,你会认为这些物品有多重要或多贵?
如果你走进同一个房间,却发现那些物品被精心地排列成一种非常特殊的配置,而这种配置不太可能是偶然发生的,那会怎么样?
这两个场景暗示了一些重要的东西:人类以反映我们价值观的方式塑造了我们的环境。在我的公寓里花 10 分钟散步,你可能会比花 30 分钟和我聊天更了解我重视什么,因为我试图用语言表达我的人生哲学。
这是一个非常重要的想法,因为事实证明,今天高级人工智能中最重要的挑战之一是找到向机器传达我们的价值观的方法。如果我们的环境隐含地编码了我们价值体系的一部分,那么我们也许能够教会机器去观察它,并且在我们不必明确表达它们的情况下学习我们的偏好。
利用从人类居住环境的状态中获取人类价值的想法最初是由伯克利博士和即将上任的 DeepMind 研究员 Rohin Shah 共同撰写的一篇论文提出的。Rohin 在过去的几年里一直致力于人工智能安全,并发表了广泛阅读的人工智能联盟时事通讯——他非常友好地加入了我们这一集的“走向数据科学”播客,在这里我们讨论了他的人工智能安全方法,以及他对高级人工智能系统风险缓解策略的想法。
以下是我们谈话中我最喜欢的一些带回家的东西:
- 像许多人一样,Rohin 在一定程度上是通过接触有效利他主义社区的成员来推动人工智能联盟和人工智能安全工作的。有效利他主义是一场哲学运动,其重点是确定人们如何通过慈善捐赠或职业生涯对世界产生最大的积极影响。它专注于问这样的问题:我能做什么样的举动,才能最大化我对世界贡献的预期价值?对于 Rohin 来说,强大的人工智能系统在未来可能造成的伤害——以及这些系统如果安全开发可能带来的好处——使人工智能对齐变得很有吸引力。
- Rohin 讨论了高级 AI 系统的两种重要的潜在故障模式,它们已经以不同的形式出现在当前的系统中。
- 首先,他强调了不良归纳的风险:人工智能从它们的训练数据中学到了错误的教训,导致它们以人类可能没有预料到或不想要的方式进行归纳。作为一个例子,他引用了对 OpenAI 的 GPT-3 模型的最初关注,当一名开发人员用一个无意义的问题提示该模型时(比如,“一个 woolrop 中有多少 glubuxes?”).GPT-3 号没有“诚实地”回答这个问题,而是说了一些类似“我不知道——我不熟悉这些词”的话,试图用最佳猜测来回答,比如“一个 woolrop 中有 3 个 glubuxes。”你可能会说这实际上是一个不错的概括:GPT-3 的回答基本上就像一个参加考试的学生,他想通过纯粹基于问题的上下文进行猜测来隐藏他们不知道问题答案的事实。但是,如果我们希望建立一个诚实的语言模型——一个在适当的时候承认自己无知的模型——那么未经微调的 GPT-3 似乎无法通过测试。随着人工智能系统变得更加强大,这种行为可能会变得更加有害,因此 Rohin 认为这值得关注。
- 其次,Rohin 讨论了向人工智能传达人类偏好的挑战。这是一个困难的问题:大多数人实际上不知道他们想要从生活中得到什么,甚至更没有能力与其他人交流这些愿望和价值观——更不用说与机器交流了,因为机器目前在推理方面缺乏上下文意识和灵活性。这就是 Rohin 教授机器从环境中推断人类偏好的工作的用武之地:他认为这种策略显示了作为人类偏好数据的额外来源的前景,机器可以用它来解读人类的价值观,而不需要我们能够明确地表达它们。我们讨论了这种策略的许多有趣的优点和缺点。
你可以在这里的 Twitter 上关注罗欣,在这里注册他的人工智能校准简讯,或者在这里的 Twitter 上关注我。
章节:
- 0:00 介绍
- 有效的利他主义
- 6:50 Rohin 对 AI 安全工作的介绍
- 11:18 为什么 AI 风险如此严重
- 18:33 育儿类比
- 22:15 统计学习理论
- 25:09 什么是偏好学习?
- 32:23 应用到更高的抽象层次
- 34:45 揭示偏好和世界状态
- 36:26 打碎花瓶的比喻
- 时间范围规则
- 49:03 总结
下面是第二季第四集的脚本:
Jeremie (00:00):
嗨,大家好。欢迎来到“走向数据科学”播客的另一集。我叫 Jeremie,除了主持播客之外,我还是 SharpestMinds 数据科学导师项目的团队成员。我对今天的节目非常兴奋,因为我已经想了很久让今天的嘉宾上播客了。我很高兴我们终于实现了。
Jeremie (00:16):
他现在正处于从伯克利毕业的过渡期。他在人类兼容人工智能中心工作,他将过渡到 DeepMind,在那里他将做一些校准工作。他的名字是罗欣·沙阿。此外,除了是人工智能和人工智能比对方面非常多产的研究人员之外,他还是人工智能比对通讯的出版商,如果你想了解人工智能比对方面的一些公开问题和未决问题,这是一个非常非常好的资源。我真的建议去看看。
Jeremie (00:47):
我们将谈论一大堆不同的事情,包括人工智能的哲学、机器学习和人工智能对齐的哲学、实现它的方法、存在的一些挑战,我认为我们将探讨 Rohin 提出的最有趣的提议之一,这是一个关于从环境状态中提取人类偏好的想法。所以,基本上,这里的想法是,人类,通过他们的活动,已经将他们的偏好隐含地编码在他们的环境中,我们做一大堆不同的事情,不同的行动,揭示了我们的偏好。如果我们能让人工智能观察这个世界,并根据这个世界的状态来推断出我们的偏好,那就太好了。这可能是一个伟大的方式来引导人工智能对齐的努力。
Jeremie (01:30):
我们将深入讨论这个提议,以及一大堆其他事情。我真的很期待这一集,所以我希望你喜欢。事不宜迟,我们开始吧。
杰里米(01:39):
你好,非常感谢你参加我们的播客。
罗欣(01:41):
是的,谢谢你邀请我。我很兴奋。
耶雷米(01:44):
很高兴你能来。总的来说,您在校准领域做了很多有趣的事情。但是,在我们解决一些更技术性的问题之前,有一个观察,我认为任何花时间从事比对工作或与比对研究人员交谈的人最终都会在某个点上做出结论,即该领域的绝大多数人似乎来自有效利他主义社区。我很想听听你的看法,第一,什么是有效的利他主义社区,什么是有效的利他主义,第二,为什么你认为在 EA,有效的利他主义,人工智能联盟和人工智能安全研究之间有这种深刻的联系。
罗欣(02:20):
是的,当然。最重要的思想有效的利他主义,非常容易维护,不涉及细节,是无论金钱,时间,资源,无论你愿意无私地花费什么,你都应该尽力做好,而不是…你应该考虑一下。很难反驳这一点。我不认为我真的见过有人不同意这一点。
Rohin (02:56):
现在,在实践中,有效的利他主义运动有一大堆额外的前提,旨在支持这项技能,但更具争议性。我认为有效利他主义的最基本的理念是事业优先化。很多人会说,“好吧,我想要,比如说,非洲的干净水。我将为此而努力。”他们会考虑在非洲获得清洁水的不同方法,也许你可以尝试对人们已经获得的水进行消毒,或者你可以尝试建立一些新的处理厂,以便为每个人提供新鲜的,流动的饮用水。他们会考虑如何最好地实现他们提供干净水的目标。
Rohin (03:47):
人们很少会想,“好吧,我应该为非洲的人们提供干净的水,还是在美国反对种族主义?我应该努力做哪一件事?还是我的钱成?”有效利他主义的主要前提是,事实上,你可以做到这一点。事实上,原因之间有很大的不同,仔细想想,首先选择正确的原因会产生更大的影响。
罗欣(04:20):
它非常专注于这一点,认真对待想法,实际评估它们,判断它们是否真实,而不是它们听起来是否疯狂。它们听起来是否疯狂确实与它们是否真实有些关系,但它们不一定相同。我认为这也是为什么它是人工智能安全研究的温床。人工智能安全的 EA 案例,人工智能安全的工作,是人工智能有很好的机会在下个世纪极具影响力,比如说。
Rohin (05:00):
有一些论点值得商榷,但你似乎不能排除它。看起来至少有一定的可能性,如果我们不注意我们如何做到这一点,人工智能系统可能会“接管”,因为所有关于世界的重要决定都是由人工智能系统而不是人类做出的。一个可能的后果是人类灭绝。我稍后会讨论这个问题,我确定,但是-
耶雷米(05:36):
所以【相声 00:05:37】—
rohin(05:37):
【cross talk 00:05:37】相信这个论点,然后它就变得极其重要和有影响力。这听起来很疯狂,但对我来说,EA 的优势之一是它将听起来疯狂的东西与真实的东西分开。
Jeremie (05:52):
看起来,实际上,重点是有一个额外的缺失步骤,许多人在决定贡献什么事业、做什么工作、花什么时间时没有考虑到这个步骤,这就是“哪些领域会给我的时间带来巨大的回报?”
罗欣(06:09):
是的,没错。
Jeremie (06:12):
我真的能回想起我与人们关于慈善事业的大部分对话,这些对话通常都集中在诸如慈善机构的管理费是多少之类的问题上。哦,我想把我所有的钱都捐给这个事业,而不是问一个更基本的问题,从造福每个人或造福人类的角度来看,这个事业真的会带来最好的投资回报吗?有趣的是,这种思维,一种更加第一原则的方法,将许多人引向人工智能校准和人工智能安全领域。如你所说,这是有道理的,你得到了这种超高风险高回报的配置文件。
Jeremie (06:50):
是什么吸引了你,例如,人工智能联盟,特别是人工智能安全工作,而不是其他任何生物恐怖主义,我可以想象所有可能发生在我们身上的可怕事情,但为什么特别是人工智能联盟?
罗欣(07:05):
是的,所以我的故事有点奇怪。这可能是一个经典的人工智能故事,因为它被非常怪异的论点所说服。2014 年进入有效利他。我大概在一年内听到了关于人工智能风险的争论。我被他们深深地说服了。我就是没买。
Rohin (07:37):
所以,直到 2017 年,我基本上没有怎么接触 AI 安全。我也不相信,基本上,有一个伦理学领域叫做人口伦理学,它试图解决这样一个问题,当不同的世界有不同的人口时,你如何比较它们有多好?我们不需要深入细节,但这是一个非常令人困惑的领域。很多不可能的结果表明,你可能想要这六个非常直观的属性,但是,不,你不可能同时拥有它们,就像这样。所以你是[相声 00:08:21]-
耶雷米(08:20):
这里的想法是,一个有 100 个体面快乐的人的世界比一个有 1000 个体面快乐的人的世界更好吗?是那种计算吗?
罗欣(08:31):
是的。这是我要处理的问题的一个例子。
Rohin (08:35):
所以,不管怎么说,2017 年夏天我一直在思考这个问题。最终,我想,“好吧,我想我应该给它一个合理的权重,”当然不是确定性,而是合理的权重,认为更多快乐的人实际上意味着一个更好的世界,即使他们是在未来。一旦你有了一个相当大的可能性,确保未来继续存在并拥有幸福的人就变得极其重要,因为它与现在如此相关。
Rohin (09:21):
所以,我想做一些更面向未来的事情,我在计算机科学和数学方面有很多技能,基本上,你想在人工智能校准方面工作的一切。我仍然不太相信人工智能风险,但我想,“好吧,一群聪明人已经考虑过这个问题,也许我应该研究一段时间,看看它是否有意义。”这就是导致我实际上改变的原因,一年后,我实际上开始相信这些论点。
耶雷米(09:57):
太有意思了。
罗欣(09:58):
我也看到了不同的论点。
Jeremie (10:00):
你被……比最初的争论本身更容易被这个问题吸引的人的素质所引导吗?你还记得当你在做这个东西的时候,你会说,“嗯,等一下。这其实是真的。”我现在明白了为什么尼克·博斯特罗姆,也许还有埃利泽·尤德科夫斯基,以及当时谈论这个话题的其他人说得有道理了。
罗欣(10:21):
我从来没有真正的啊哈时刻。我记得,在某一点上,我就像,“我想我现在相信这些论点,”但它不像我…我想我现在相信人工智能风险是实质性的和真实的。我不能指出一个具体的时间点,是的,现在我相信了。有一天,我正在思考这个问题,注意到,“哦,是的。我以前不相信这个。现在我知道了。”
耶雷米(10:52):
太有意思了。看起来在阅读超智能的人和阅读较少错误的人之间存在分歧,他们对这个问题感到非常兴奋,并且立刻感到非常害怕,因为,不管出于什么原因,他们天生就是这样的。然后是像你一样的人。这就像一个缓慢的燃烧,你慢慢地进入其中。我想这是问题的一部分,如果需要很长时间才能让人们认为这是一件非常重要的事情,那几乎是阐明问题的一部分。
耶雷米(11:18):
当你试图向人们解释为什么人工智能风险如此严重时,你有什么策略吗?为什么你认为可能对你有作用的概率是不平凡的,以加速这个过程?
罗欣(11:32):
是的,我应该指出,我仍然……例如,我对《超级智能》中的论点不是很满意。我要说的是,对我来说,激励它的是略微不同的论点,仍然相当强调超智能的东西。
耶雷米(11:50):
顺便说一下,我想很多人都没有听说过超智能。
罗欣(11:54):
哦,是的。
耶雷米(11:55):
如果你想讨论你提出的任何论点,也请随意提供背景资料。
Rohin (12:00):
是的,也许我会谈谈我个人喜欢的论点,因为我可以更好地解释它们。但是,就上下文而言,《超级智能》是牛津大学教授尼克·博斯特罗姆写的一本书。它于 2014 年出版,是第一篇[听不清 00:12:19]论述为什么人工智能风险是可能发生的事情,为什么我们应该认为它可能是合理的,什么解决方案看起来像是应该调查的,等等。
Rohin (12:33):
然后,就我个人而言,我将给出的论点是…所以,首先,我们将[听不清 00:12:45]作为一个前提,我们建立智能的人工智能系统,比如说,像人类一样智能。我们可以以后再谈,但那完全是另外一个话题了。我只想说,我认为这不太可能……我认为[听不清 00:13:03]在下个世纪发生的可能性相当大。但是,现在,把它当作一个假设。
罗欣(13:10):
智慧意味着你可以适应新的情况,当你面对新的情况时,你会了解它,然后做一些事情,这些事情是连贯的。有道理。我举的一个例子是 GPT-3 的一个具体例子,在这个例子中,我们甚至可以看到当前的神经网络。我相信观众会熟悉 GPT-3…听众,而不是观众。但如果不是,GPT-3 是 OpenAI 最近开发并发布的[听不清 00:13:47]语言一代[听不清 00:13:48]。
罗欣(13:51):
我想我喜欢《邮报》上给 GPT-3 做图灵测试的一个例子。GPT-3 的背景是一堆问题和答案。GPT-3 会提出一个问题,一个硬币里有多少硬币。这些都是废话,你没有听错。GPT-3,从某种意义上说,这超出了它的训练分布。据推测,它从未在其训练语料库中见过这句话。它可能从未见过 bonk 和 quoit 这两个词。这是实际的分布转移,你依赖于某种分布的一般化。
罗欣(14:43):
尽管如此,我认为我们都可以预测 GPT-3 不会输出一些随机的字符串。它可能会说些明智的话。事实上,它说的是,“你知道,一个杯子里有三块糖。”为什么是三个?我不知道。但是,你知道,在某种意义上这是明智的。它产生了一个听起来像英语的答案。
耶雷米(15:10):
在某种程度上,我们都有过这样的经历,如果我们写考试或其他什么,我们会被问及一个硬币里有多少颗糖,我们没有学习,嘿,一个硬币里有三颗糖。我们走吧。
罗欣(15:18):
完全正确,对吗?在某种意义上,GPT-3 确实概括了,它概括了一个学生参加考试的方式。在最初的帖子中,这被视为 GPT-3 实际上不合理的证据,因为它不知道如何说,“这个问题是无意义的。”
罗欣(15:39):
但是接下来的一个帖子是这样的,“实际上,你完全可以让 GPT-3 这样做!”如果你告诉 GPT-3…如果在上下文中,你说每当它看到一个无意义的问题,人工智能回应,“哟,是真实的。”然后,当被问到一个硬币里有多少颗糖时?它说,“哟,真实一点。”所以你知道它有能力辨别这是废话,它只是以一种更像一个应试者而不像一个谈话中的人的方式进行概括。我们提前知道了吗?不,我们没有。为了弄清楚这一点,我们不得不实际运行 GPT 3 号。
罗欣(16:23):
我认为人工智能的风险基本上是这样的,但如果你的人工智能系统是人类水平的智能,它肯定会被部署在新的领域,在新的情况下,我们以前没有见过。我们真的没有令人信服的理由相信它会继续做我们训练它做的事情,而不是别的事情。在 GPT 3 号,我们训练它做什么?好吧,在训练数据集上,至少,我们训练它做人类在那种情况下会写的任何事情。
罗欣(17:05):
当你看到一个杯子里有三颗糖……对不起,一个杯子里有几颗糖?在那种情况下人类会怎么做?我不知道。这并没有很好的定义,GPT 3 号做了一些明智的事情。我不认为你可以合理地说它没有做我们训练它做的事情,它只是做了一些连贯的事情。同样,如果你有人类水平或更高智能的人工智能系统,对世界采取超级有影响力的行动,并且它们被置于这些新的情况下,在这些情况下,它们将如何概括并不是事实,那么它们可能会采取对世界有很大影响的行动,而这不是我们想要的。
罗欣(17:49):
然后,也许是直觉【听不清 00:17:52】为什么这可能非常非常糟糕,就像人类灭绝级别的糟糕。一个特别的分布变化是,你从人类比人工智能拥有更多权力并可以关闭人工智能的训练环境,到人工智能足够智能并被广泛部署,但没有人可以…或者说人类作为一个整体不能关闭它的环境。在那种情况下,那是一种新的情况。AI 以前从未有过这种能力。它会以某种方式使用它吗……它会以某种不同于我们在训练中预期的方式进行概括吗?我们真的没有理由说不,它不会那样做。
耶雷米(18:33):
你认为这和养育孩子有相似之处吗?我只是在想人类的代际繁衍,我们的祖先在 17 世纪,至少在西方,我肯定会对我们今天处理性的方式,我们与长辈沟通的方式,我们管理机构的方式等等,我们所有的等级制度都完全不同。而且,在许多方面,我们[听不清 00:19:00]是中世纪或文艺复兴早期的道德框架。
耶雷米(19:07):
我想这里有所不同,至少我们仍然运行在相同的基础硬件上,或者非常相似的东西。也许这确保了最低水平的一致性,但是这种类比在某种程度上是否会破裂呢?
罗欣(19:18):
我认为这是一个很好的直觉。这个类比在某些方面是不成立的,比如,嗯…这个类比不太成立,因为这些原因,我会说稍微减轻一点重量。一个是,在抚养孩子的过程中,你对孩子有一定的影响力,但是你不能做一个完整的训练过程,在这个过程中,你要给他们一个梯度,让他们做每一步动作。你可能希望,鉴于你可以在人工智能系统上有更多的选择压力,你将能够避免这个问题。
Rohin (20:00):
但是,是的,我认为这就是我所指的基本动力。你对这些代理有一定的影响力,但是那些代理遇到新的情况,他们在这些情况下做一些事情,你没有提前考虑这些情况,你没有训练他们做正确的事情。
耶雷米(20:23):
我完全同意人工智能风险的观点,这是非常重大的风险。赌注非常高。当谈到你认为最有希望的解决方案或策略时,你自己是专业的,显然,在一个类别中,每个人都必须是,在对齐问题域中的一个子空间中。你决定关注的领域是什么?为什么你认为在这一点上最值得关注?
罗欣(20:50):
到目前为止,我告诉你的故事是一个概括。主要的问题是我们不知道如何概括,而且,很可能,你会得到一心一意追求权力的人工智能系统,这与超级智能的故事相似,可能会导致人类灭绝。基本机制是糟糕的概括,或者说是像你的能力那样的概括。你做了一些连贯且影响深远的事情,但是相对于人类想要的,你试图做的事情并不一般化。
Rohin (21:31):
我最感兴趣的许多事情在某种程度上都与泛化有关。我感兴趣的一件事是,我们能从经验上更好地理解神经网络是如何进行归纳的吗?对此我们能说些什么吗?有很多理论试图解释为什么神经网络有如此好的泛化能力。这不能用统计学习理论来解释,因为神经网络可以记忆随机噪声,但尽管如此,当标签不是随机噪声时,它似乎可以很好地概括。
Jeremie (22:15):
你介意解释一下统计学习理论作为参考吗?实际上,我不确定我是否能理解这种联系。
罗欣(22:23):
统计学习理论就像机器学习理论的一个分支,试图做几件事。但是,除了其他事情之外,尝试证明如果我们用这样那样的训练属性在这样那样的训练数据上训练一个机器学习模型,那么我们知道它将以这样那样的方式进行推广,并且它证明了关于这一点的定理。
Rohin (22:50):
重要的是,目前大多数方法都专注于对您的模型、您的假设类别做出假设。这些假设通常排除了对任意大小的数据集进行过度拟合的能力,因为如果可以的话,那么你真的不能说任何关于一般化的东西。但事实是神经网络真的可以适应任何数据集。他们可以记住字面上随机噪音的标签。所以,这些假设不适用于神经网络。
罗欣(23:28):
我感到兴奋的事情是,我们可以谈论数据集的假设,而不仅仅是模型吗?如果我们考虑数据集上的假设和模型上的假设,那么我们能说说神经网络是如何进行归纳的吗?这就像是一个超级模糊不清的希望,我还没有真正开始努力,据我所知,其他人也没有。
Rohin (23:55):
关于神经网络有太多的经验性的东西让我非常困惑,比如深度双重下降。我不明白。这是一种经验现象。不知道的可以去查一下。它可能不值得我去探究,只是太令人困惑了。不知道为什么会这样。对我来说毫无意义。我想知道为什么,我认为如果我们理解了这样的事情,我们也许能够开始陈述神经网络如何倾向于概括,也许这可以转化为我们可以说的关于安全的事情。
耶雷米(24:27):
这很有趣,因为泛化的故事似乎是问题的一个组成部分,当然,然后是另一个组成部分,我的意思是,有一些重叠,但看起来它们确实有不同的组成部分。告诉机器人类的偏好是一个挑战,我们告诉彼此我们想要从生活中得到什么的能力已经非常有限了,我的意思是,至少我个人认为这是一个有点不和谐的前景,不仅要表达我们的偏好,还要量化它们,并将其转化为某种损失函数,然后输入到模型中。你在这方面做了很多有趣的工作。
耶雷米(25:09):
事实上,我想谈谈你的一篇论文。我们在开始录音前讨论过这个问题,我很高兴听到这也是你认为最有趣的一个。我们观点一致,至少在这一点上。这是一个想法……嗯,论文的标题是世界状态中隐含的偏好。我想,首先,我想问一个问题来做个铺垫。什么是偏好学习?那是什么概念?
罗欣(25:34):
这实际上是我接下来要说的让我感到兴奋的事情。
耶雷米(25:38):
哦,太好了。
罗欣(25:39):
我已经谈到了概括,但是在你概括之前,你首先要训练正确的事情。这似乎是人工智能系统的一个很好的起点。如果你没有,你可能就完了。关于如何通过编写一个程序或一个方程来指定你想要的东西,这实际上是非常典型的,已经洒了很多墨水,正如你所知,深度强化学习或任何深度学习系统是如何工作的。但它通常与深度强化学习联系在一起。
罗欣(26:21):
优先学习的理念是,你不用写下一个等式来说明你想要什么,而是用一些更简单的方法来说明。例如,你可以在一个强化环境中观察两个轨迹,你可以观察代理采取的两个行为,你可以说,“啊,是的,左边那个。那个更好。”这给了代理一些关于它应该做什么的反馈。它不是试图写下一个方程,在每一种可能的情况下捕捉理想的行为。只是说,这两个里面,哪个更好?你可能会认为这对人类来说更容易做到,也更有可能是正确的。
Rohin (27:08):
这是一个偏好学习的领域,我认为这是一个我们如何为人类设计向人工智能系统提供反馈的机制的领域,这样我们就可以提供反馈,激励我们真正想要的行为,并且我们不会像在奖励功能方面那样犯很多错误。
耶雷米(27:34):
所以,我发现在这方面真正令人兴奋的是,人类表达的欲望和透露的欲望,或者表达的意图和透露的意图之间有这种众所周知的差异。我会说今天要健身三个小时,要做一堆编码,下个月要吃一堆纯素餐。如果你下个月来看我,我将不会做所有这些事情,我几乎不会做所有这些事情。问题是,哪个我是我?我是那个说嘿,我想成为那个人的有抱负的自己吗?或者我是那个一直坐在沙发上看网飞的傻瓜?
耶雷米(28:16):
这似乎真的解决了问题,因为如果探针显示偏好,无论是好是坏,我想这也可能是一种失败模式。你认为这种方法有价值吗?
罗欣(28:29):
是的,我认为你想同时使用两种信息来源,而不是其中任何一种。实际上,让我后退一步,区分你可能尝试做的两件不同的事情。有一件事,你试图了解人类重视什么,这是你正在谈论的那种事情,还有另一种框架,你只是想,“我想让我的人工智能系统做这样那样的任务,我想训练它这样做,但我不能写下这项任务的奖励函数。”
Rohin (29:01):
老实说,我实际上对后者更感兴趣,但前者也是我花了很多时间研究的,我对此感到兴奋。现在,我们谈论的是前者。
耶雷米(29:13):
我可以问一个天真的问题吗?我想我知道区别是什么,但我只是想让你明确地解决它。那两件事有什么区别?
罗欣(29:24):
一件事是,我可能想让我的人工智能系统用吸尘器打扫我的地板,或者其他什么。用真空吸尘器清扫我的地板的任务并不是仅仅由那句话来明确说明的。任何有 Roomba 的人都会告诉你 Roomba 超级笨的故事。其中一些只是 Roomba 不够智能,但也有一些是任务不是非常明确。
Rohin (29:57):
代理人应该在圣诞树下用吸尘器清扫吗?那里有一堆针,可能会破坏他们的吸尘器。谁知道呢。如果地板上有一些随机闪亮的按钮,应该用真空吸尘器清理还是放在一边?因为也许那个按钮很重要。什么样的东西,猫应该被吸尘?这只猫的毛很多,到处都是。如果你给猫吸尘,看起来会让你的房子更干净。
罗欣(30:31):
这里有很多模糊之处。我不会真的说这些是人类价值观,就像教你的 Roomba 如何吸尘似乎和教 Roomba 人类价值观不是一回事。首先,你真的不能在这里谈论太多暴露的偏好,因为我不经常用吸尘器打扫我的房子。如果一个人工智能系统要排队清空,我可能会让它更频繁地清空。
耶雷米(31:06):
你会说这是人类偏好的狭隘应用吗?狭义人工智能和 AGI 之间的区别似乎映射到了这一点上。
罗欣(31:16):
是的,我想我同意这一点。我会说,但在这个意义上,一切都是狭隘的人工智能。你只能得到变得越来越普遍的狭义人工智能,在某种程度上,我们决定不再称它为狭义人工智能,而开始称它为 AGI,因为它已经变得如此广泛。
Rohin (31:34):
我喜欢你的想法,你可以从一些可以应用于当今系统的东西开始,然后对其进行扩展。它变得越来越有能力,越来越通用,但它总是相同的技术。最终,我们用它创造的系统,我们会给它们贴上 AGI 或人类智能或超级智能的标签。同样的技术,同样的原理。这就是为什么我对这个问题的框架更感兴趣,而不是人类价值垃圾邮件。
罗欣(32:07):
当你进入更一般的系统,它与人类的价值观融合在一起。一旦你有了设计政府政策或其他东西的人工智能系统,无论你给它们什么样的反馈,它都会更好地教会它们人类的价值观。
耶雷米(32:23):
是的,我想,希望我们在越来越高的抽象层次上开始这样做,就像你说的那样。从某种意义上来说,我们向上填充卷积滤波器。
罗欣(32:34):
是的,正是如此。你问了一个关于表露偏好与口头偏好或表达偏好的问题。我想,是的,这是一个重要的区别。我绝对希望我们提出的任何方法都不依赖于一个或另一个,而是同时使用两者,这将会有冲突,我最希望的是,我们可以让人工智能系统搁置冲突,并根据其中任何一个集来做非常好的事情。也许,你必须有一些冲突解决机制,但是在某种意义上,人类已经必须这么做了。我们似乎有可能做这件事。
罗欣(33:28):
我认为这是一个非常好的方面,你不必在每种可能的情况下都致力于寻找行为。我们只是不知道这些。老实说,我们的价值观还不够明确,这是不对的。当我们遇到新情况时,我们的价值观会不断更新。现在,我们谈论民主,一人一票。如果有一天,在超人类主义的未来,如果有一天复制人成为可能,我想我们很快就不再想要一人一票了。因为如果你足够富有,你可以花钱让任何人当选。
耶雷米(34:19):
是啊。或者,我想,仅仅是在有限的关于大脑状态的更好的信息中,我们可以说,当然,这个政策让大多数人更快乐,但是它让人们更不快乐,我的意思是,看看那个可怕的多巴胺循环。这些人真的受到了很大的打击,你唤醒了他们的反应。
罗欣(34:37):
对,对,你肯定可以为社会福利做更好的优化,也许你不希望只有一人一票。
耶雷米(34:45):
好的,现在,我想这让我们回到了世界状态中隐含的偏好,大概有一些关于世界结构的事情透露了我们的偏好,我想这主要是透露了偏好,对吗?
罗欣(34:57):
是的。
耶雷米(34:57):
我们实际上做了什么。
罗欣(34:58):
是的,这绝对是一个显示偏好的方法。我认为这一点的一个重要方面是人们将…我认为我对此特别兴奋的原因之一,我想说的是作为前奏,这不是试图做困难的事情。当人们想到价值学习时,他们会想如果无人驾驶汽车可以在撞到两名乘客或杀死司机之间做出选择,它应该怎么做?这些都是艰难的伦理问题。我对它们不太感兴趣。我想从我们能否得到一个可靠地知道它不应该杀死人类的人工智能系统开始。如果有两个选择,是的…
罗欣(35:50):
总之,我们都同意或几乎都同意的基本内容,所以我认为观察世界的状况是了解这一点的好方法,这里的基本直觉是,我们已经在这个世界上生活了很长时间。我们有偏好,我们一直在重新安排世界,以适应我们希望世界成为的样子。因此,你可以颠倒这个过程,找出我们可能想要的东西。
Rohin (36:26):
有一个很好的玩具例子可以说明这一点。假设有一个房间,在房间的中间有一个易碎的花瓶。花瓶一旦被打破,就再也无法修复了。我们假设人工智能知道这一点。我们将假设人工智能知道所有的经验事实。它知道世界是如何运作的,它知道人类可以采取什么行动,它知道人类可以采取什么行动,它知道它自己可以采取什么行动,它知道世界的可能状态,但它不知道关于[听不清 00:36:58]功能的任何事情,它相当于人类的价值观。
罗欣(37:02):
它知道经验事实。它知道,这个花瓶,一旦打破,就无法修复。我们将把胶水之类的东西放在一边。然后它看着它看到的事实,它被部署在这个房间里,它看到它的人类,我称之为爱丽丝,在房间里,花瓶没有被打碎。现在你可以提出假设性的问题,比如好吧,如果爱丽丝想打破花瓶,我会看到什么?嗯,我会看到一个破碎的花瓶。如果爱丽丝不在乎花瓶,我还能指望什么呢?嗯,可能,在某些时候,最有效的方法是在房间里走来走去,同时打翻花瓶。所以,很可能在那种情况下,我也会看到打碎的花瓶。
罗欣(37:58):
如果爱丽丝不希望花瓶破碎,或者积极地希望花瓶不被打碎,我会期望看到什么?在这种情况下,我实际上看到了一个完整的花瓶,可能。因为我实际上看到了一个未破碎的花瓶,这告诉我,在这三种情况中,只有最后一种似乎与我的观察一致。所以,很可能,爱丽丝不想打破花瓶。你可以通过观察世界的状态,看到花瓶没有碎,来推断爱丽丝不想打碎花瓶的事实。
耶雷米(38:33):
这似乎与热力学第二定律有很深的联系,宇宙有很多方法可以解决花瓶破碎的情况,但是没有花瓶破碎的事实是一个巨大的信息。
罗欣(38:52):
对,完全正确。
Jeremie (38:57):
基本上,到了[相声 00:38:59]-
罗欣(38:58):
我想我没有什么要补充的了。
耶雷米(38:59):
这让我感到震惊,这是我的物理学家本能,但就世界看起来与我们对纯热力学随机性的预期有所不同而言,这里的假设是这些差异来自人类的偏好。这是描述…的公平方式吗
罗欣(39:17):
是的,没错。
耶雷米(39:19):
那这是否意味着某种故障模式呢?因为我想我们在我们的环境中编码信息,我想这是[听不清 00:39:25]显示偏好的事情,但含蓄地说,我已经把我的大脑状态硬编码到我的公寓里,每件事情的安排,任何厌恶女人,任何种族主义,任何恋足癖,所有可能是或可能不是我个性的一部分的怪异怪癖都含蓄地编码在房间里。这是应用这种技术的部分风险吗?
罗欣(39:54):
是的,所以,从理论上来说,如果你[听不清 00:39:59]这种方法,它会…它会得到所有显示的偏好吗?还有,嗯,我不知道它得到了一切。但大致来说,它得到了你透露的偏好。我相信有些事情是它不明白的。有时候,你只是不喜欢你表露出来的偏好,你认为它们应该是不同的。
罗欣(40:27):
你有一个明显的偏好,许多人都有一个明显的偏好,就是拖延,他们可能实际上并不赞同,他们不希望他们的人工智能系统给他们越来越多令人上瘾的材料,以便他们可以更好地拖延,这似乎是可能发生的事情。我将不得不更加努力地思考这到底是如何发生的,但我可以相信这将是一种影响。
Rohin (41:03):
同样,我到目前为止解释的技术似乎是世界上只有一个人,如果有多个人类,事情会变得复杂得多,我到目前为止一直忽略这种情况。
耶雷米(41:20):
这是你离开地面所需要的,对吗?
罗欣(41:22):
是的。
耶雷米(41:26):
在这种情况下,我想至少还有另一种风险模式,就是说,在这个花瓶的例子中,我们假设这个人实际上并不在乎这个花瓶,只是碰巧,在她的演示中,他避开了这个花瓶。有没有这样的风险,我想这是机器学习中的一个风险,听起来就像一个额外的分布抽样的例子,就像你会学到的-
罗欣(41:57):
是的。
耶雷米(41:57):
好的。
罗欣(41:58):
对,没错。如果花瓶被放在一个不显眼的地方,实际上爱丽丝在房间里走动时不太可能打碎花瓶,我们实际上把它写在纸上,我们表明在那种环境下,你实际上不会学到任何关于花瓶的重要东西。你就像,“呃,她可能不想把它弄坏。”你推断出她并不十分渴望花瓶被打碎,但是你没有推断出比这更强烈的东西。你不确定打碎花瓶是件坏事还是件坏事,是的,这并不重要。
耶肋米亚(42:44):
有意思。
罗欣(42:45):
如果打碎花瓶可以提高效率,那么你推断并观察到花瓶没有被打碎,然后你推断打碎花瓶是不好的。仍然有可能的是,人类,我们不是完美的最佳人,我们可能不会提高效率,所以我们可能会绕过花瓶,即使去花瓶会更快,即使我们不在乎花瓶。是的,这个方法会做出错误的推断。总的来说,在偏好学习中,你假设人类做人类做的事情来反映他们想要的,这两者之间有很大的矛盾。并不总是如此。
耶雷米(43:37):
没错,我想有时候纯粹是因为愚蠢。我们可能想要一件东西,只是不知道如何让它发生。
罗欣(43:45):
是的,没错。这在偏好学习中是一个巨大的挑战,事实上,包括我在内的许多人都试图解决这个问题。但我不会说,在把愚蠢和你真正想要的东西分开方面,已经取得了巨大的进步。
Jeremie (44:10):
我认为如果我们这样做,我们最终会解决很多其他问题[相声 00:44:12]。实际上,关于论文,我还有一个问题想问你。我认为,时间范围的规则,或者说时间范围在论文中的规则,真的很有趣,因为机器人或人工智能对人类对这个动作的时间范围有一定的假设,如果对时间范围的改变有假设,你会开始看到不同的行为。我很想听你详细说明一下,并描述一下那个场景。
罗欣(44:43):
我认为我关于时间范围的主要观点是,如果你假设时间范围很短,那么状态没有完全优化的情况就更情有可原了,因为人类没有足够的时间将状态完全优化到对他们来说最佳的状态,所以你可以-
耶雷米(45:11):
也许我应该填补这个空白,我知道这有点模糊,但是从时间的角度来看,我想我们谈论的是人类从房间的一个地方到一个理想的终点需要的时间,对吗?[相声 00:45:24]
罗欣(45:23):
是的,这就像机器人出现之前,机器人假设人类已经在环境中活动的时间。在房间的情况下,它的机器人被部署,看到一个完整的花瓶,它就像,“啊,是的,人类已经在这个房间里走了一个小时,”或类似的事情。
耶雷米(45:40):
对,如果你在房间里走了整整一个小时,花瓶还在那里,你就可以认为这个花瓶可能非常重要。
罗欣(45:48):
对,正是这样。论文中的实际设置略有不同,但这是正确的直觉。是的,花瓶的例子不能很好地说明这个问题,但是想象一下,你正在用卡片建造一座房子。这是另一个例子,世界的状态真的很能说明你的偏好。纸牌屋是超级的,超级的不熵。可以推断出很多。
耶雷米(46:21):
是的,安排越具体,我想就越…这很有趣,因为这正是保护人类的挑战所在,这种方法几乎有一种哲学上的保守倾向,因为我们假设我们已经到了值得保护的地方,因为我们已经对自己进行了编码。 我们在环境中已经有了这么多好的东西,而且看起来我喜欢这个时间范围的东西是它背后的政治哲学,它几乎给了你一个刻度盘,你可以通过假设不同的时间范围从光谱的进步端调谐到保守端。 如果你认为我们刚刚来到这里,这是一张白纸,那么,嘿,我们可以尝试任何事情。相反,我们并不确定人类在这种环境中想要什么…
罗欣(47:12):
是的。
耶雷米(47:12):
对吗?是啊。
罗欣(47:13):
没错,我从来没有这样想过,但是你说得对。基本上就是这样。另一种思考方式是,我实际上到了这一步,到了写这篇论文的地步,问我自己为什么我们给无为行动以特权?我们会说安全的行动是什么都不做。为什么?只是一个动作。这是一个答案,我们已经优化了环境,随机行动是可能的,所以…当前状态在我们的偏好排名中很高。随机的行为把我们从那个状态带到另一个随机的状态,所以可能期望我们的排名变低,而什么都不做的行为保持了它,所以它是好的。时间跨度越长,你就越想默认什么都不做。
耶雷米(48:07):
是的,是的,我记得在报纸上看到过,实际上,这几乎是直觉的衍生,当你看到它像那样摆放时,它是如此美丽。
罗欣(48:15):
我知道,所以很好。
耶雷米(48:18):
是的,是的。在某种程度上,这让我想到不同政治派别的人之间的许多争论会变得容易得多,如果我们应用这样的玩具模型,你可以说,嗯,嘿,对保守派来说是有价值的。进步是有价值的。不管怎样,我们最终都会陷入反面乌托邦,这里有一个参数,我们可以调整它来看看反面乌托邦的事情是如何发展的,这取决于我们对事物的重视程度。
耶雷米(48:43):
是的,不管怎样,我喜欢这项工作,我认为这是……不管怎样,对于任何对哲学、道德哲学和人工智能的交叉感兴趣的人来说,这是一个非常酷的工作。
罗欣(48:58):
好的,谢谢。我喜欢它的原因基本相同。
耶雷米(49:03):
甜。嗯,我很高兴我们有兼容的[听不清 00:49:06],然后。太棒了。嗯,我想我们已经谈了很多,但是你还有什么想谈的吗?我想确定的一件事是参考您发布的校准时事通讯。我认为每个人都应该检查一下,特别是如果你想进入这个领域。Rohin 发布了这个惊人的时事通讯,无论如何,我们会在播客附带的博客上链接到它。
杰雷米(49:30):
你有什么社交媒体链接或类似的东西想分享吗?
罗欣(49:35):
我认为联盟时事通讯是让我了解当前想法的最佳途径。如果你是这个领域的新手,我可能会推荐其他东西。我喜欢的更具介绍性的具体排名…它不完全是介绍性的,而是更永恒的材料,在对齐论坛上有一系列我写的博客帖子,称为价值学习序列。我喜欢这是一个很好的介绍,在那个论坛上还有另外两个推荐的序列,我也推荐,我也认为非常棒。
罗欣(50:21):
在社交媒体方面,我有一个 Twitter。它是@RohinMShah,但大多数情况下,它只是发送校准简讯链接。人们也可以随时给我发电子邮件。我的电子邮件在我的网站上,不能保证我会给你回复,因为我确实收到了很多电子邮件,但我认为我的回复率相当高。
耶雷米(50:50):
是的,好吧,我可以在我这边证明这一点。感谢你抽出时间,真的很感激,我真的很期待把这个放出来,也祝 DeepMind 好运,因为你几天后就要去那里了,真的,对吗?
罗欣(51:04):
是的,我周一会去那里。又是两个工作日。
耶雷米(51:09):
好吧,是的,享受这个漫长的周末吧。
罗欣(51:13):
凉。谢了。
耶雷米(51:13):
太棒了,非常感谢,罗欣。
高效互联的远程数据科学
在家建立数据科学职业生涯
在 Unsplash 上由 Cameron Venti 拍摄的照片
远程工作越来越受欢迎,因为雇主希望留住那些恰好不在附近的人才。然而,由于 Covid 的爆发,它很快从一个美好的必须品变成了一种必需品,像谷歌这样的公司将它作为一种限制传播的预防措施。在政府强制隔离的地方,远程工作是唯一的选择。
通常,数据科学工作只需要一台计算机、互联网和你的智慧。有人可能会认为,无论你是在家里、在海滩上(有 WIFI),还是在开放式办公室里戴着耳机分区,在数据科学这样的岗位上工作都很容易做到高效。这在一定程度上是对的,但当你唯一的办公室伴侣是一株植物,而你的同事们都眼不见心不烦的时候,你也很容易失去注意力,感到孤立无援,并很快变得沮丧。
在我的职业生涯中,我已经在不同的技术岗位上远程工作了五年多。我最近的远程工作是作为一名数据科学家。以下是一套帮助我作为远程员工继续保持高效工作和职业发展的策略。幸运的是,作为一名数据科学家,您可能已经熟悉了各种工具,可以继续在高水平上做出贡献!
保持联系
当你在远处时,很容易害怕错过。根据组织的文化,大量的创新和交流可能与地理上的接近有关。走廊谈话和白板会议是合作创新的源泉,反馈通常来自于隔着立方体墙壁的谈话。然而,这并不意味着你不能远程继续或合作创造性的数据科学。以下是一些建议。
擅长 Git
你已经在使用版本控制来共享你的笔记本和脚本了,对吗?除了基础知识之外,学习如何使用高级版本控制功能,如拉请求和版本区分,可以帮助您在团队成员不在时快速了解共享项目中的变化,这也将确保您的贡献在更广泛的组织中得到体现。
实际上,这适用于你所拥有的任何协作软件。代替白板,实际上很有可能在基于协作云的文档、电子表格和绘图程序(如 Google Drawings 或 Miro)上远程取得实时进展。关键是要认识到,虽然你可能从婴儿时期就开始画画,但软件界面可能需要一点练习才能“实时”擅长。熟悉捷径是值得的!好的一面是,一旦你使用这些工具中的一个创建了一些东西,你现在就有了永久清晰的文档,这可能不是潦草的白板会议的情况。这就引出了文档的话题。
记录一切
您花了一天时间探索一个新的数据源,并且希望分享您所学到的知识,以便您的团队可以决定是否使用它来构建模型。问题是你不能直接告诉他们,因为他们在地球的另一边,直到你睡着了才会起床。即使距离没有那么远,你仍然面临着用一个更有限的工具箱有效地分享你的详细想法的挑战。
为此,详细记录你的同事需要了解的一切。如果是代码,不要跳过注释,链接到任何必要的参考资料。如果是模型质量评估,清楚地写下模型如何工作,如何评估,以及在哪里可以找到任何验证集。许多工具都可以做到这一点,但维基和其他允许记录问答的工具对于捕捉最终产品如何形成的背景尤其有用。
当你不在的时候,有考虑周全的文档可以让队友取得进展。如果需要面对面的时间来解释,通常可以压缩时间来回答具体的问题,而不是讨论每一个细节。作为最后的奖励,当你想记住为什么或如何选择做某事时,你的文档会有答案!
走向高带宽
有时候你真的需要比打字速度更快地交换信息。如果松弛的信息或电子邮件不能传达重点,不要害怕开始一个即兴的松弛的电话,缩放,闲逛或任何让你使用语音,最好是视频。这不一定是正式的预约电话。只要所有人都确认他们有空,一个五分钟的聊天现在伴随着手的挥动和快速清晰的纸质图表可以减少很多挫败感。
保持高带宽另一种方法是清楚地确定你什么时候在工作,什么时候有空,什么时候没有。一个简单的“我要离线一小时”就可以了。当你们不在一起的时候,没有人知道你必须去办点事,不能回答问题。虽然我并不提倡管理者对办公桌前的时间进行微观跟踪,但在一个高度沟通的组织中,让相关人员知道你暂时没空可以避免不回应的表现。
优化你的环境
在家工作比和同事在办公室工作呈现出不同的物理动态。认识到这一点,你可以通过选择环境和控制时间表来积极主动地充分利用它。
仔细选择你的位置
当你在办公室的时候,很清楚你为什么在那里。虽然现代办公室肯定不是没有干扰的,但在一个特定的环境中可以提示你以这样或那样的方式思考。如果你熟悉睡眠卫生的概念——不要在床上做繁重的脑力工作,这样你的大脑就会养成在那个地方关闭的习惯——这听起来应该很熟悉。同样,在你的家里创造一个“工作区”也会有所帮助。即使它不是一个单独的房间,有一个你总是去工作的不受干扰的地方可以帮助你进入状态。
另一方面,远离办公室可以提供一些在办公室里不容易得到的东西。当你在一个问题上感到停滞不前时,试着换个位置。去另一个房间,或者你最喜欢的咖啡屋想一想,你会发现你正从另一个角度看问题。
把工作和生活分开
所以你离开了开放的办公室,不再去关注地板上每个同事的谈话。从理论上讲,这应该是一个万能药。现在你有安静的时间去进行那些深刻的思考了!除了现在,任何时候你都可以倒垃圾或者穿上网飞。诱惑是自然的,所以最好做好准备。一个策略是保持明确的工作时间。从 A 点到 B 点,你在工作,但不是在之后或之前。你也不做任何其他事情。如果你确实需要一些分散注意力的东西来打破安静或单调,那也计划一下吧。对我来说,最有效的方法是计划在午休时做一些与工作无关的事情。如果我想洗碗或者沉迷于娱乐,我会在休息吃饭的时候设置一个计时器。当计时器停止时,回去工作。
时间纪律的好处是,你可以保持高效率,而不会觉得有必要把工作时间延长到比正常情况下更晚。
听马斯洛的
到目前为止,这个列表主要集中在保持高效的实用技巧上。如果你打算长期在家工作,还有一个方面必须讨论。简而言之,保持你自己的精神健康和工作满意度。
腾出时间闲聊
很容易开始觉得你的同事是一些抽象的概念——只是一个松弛频道另一端的问答/提问聊天机器人农场。那可能不理想。即使对于那些因为电脑似乎比人更容易打交道而开始与电脑打交道的人来说,日常人际交往的数量大幅减少也会开始变得孤独。如果你的同事也离你很远,他们可能也会有同样的感觉。
如果你在办公室,当你在被称为咖啡机的建筑瓶颈处相遇时,每天至少会有几分钟的聊天。由于这种情况不再自然发生,所以可能需要有意识地考虑。如果你开始花几分钟时间在一对一的会议上补上一些不那么“议程驱动”的项目,它至少可以取代一个好的工作场所所能给予的那种团体感。和许多这些建议一样,这都是关于计划一些可能会自然发生的事情。
被听到
成为一名数据科学家的部分回报是有一个伟大的想法,然后看到它被使用,并且你的创造力得到认可。建立一个成功分享的好想法的组合是我们前进的方式。当与你互动的那群人受到限制时,你就更难确保自己的进步被人所知,而且感觉你的职业生涯可能会陷入停滞。这不一定是不可克服的。
一个策略是确保你的研究进展通过之前推荐的文档被广泛分享。多个利益相关者可能想要知道你的模型如何工作的一些细节,比如优点、缺点和准确性度量。共享这些数据的最佳方式可能取决于您所在组织的政策,但出于透明的考虑,在内部公共场所记录这些数据可能会很好。在公司的 wiki 上主动记录和参考细节,不仅可以让你不必不断地回答同样的问题,还可以在你取得的进步上打上你的印记。即使结果不是你所希望的,分享它们会建立信任,并表明你在认真测试你的方法。
更广泛地分享东西的一个可怕之处是可能会招致批评。然而,这是通向更好最终结果的途径的一部分。如果你的产品管理同事指出你的数据集缺少关键的人口统计数据,这并不意味着你的工作失败了。相反,这是一个优雅地解释你的理由或接受建议并改进的机会。最好在过程的早期就开始这种开放式复习的循环,而不是在过程结束时进行,因为那时课程的修改更加困难。
一些最后的话
远程工作可能会带来一系列挑战,这些挑战在共享空间中根本不存在,而且可能并不适合所有人。不过,主动适应 it 也能带来真正的机会。成功过渡到远程工作意味着保持专注、保持联系,并继续关注您的健康。如果你对此积极主动,你可能会发现你采用的实践实际上可以使你的数据科学更有影响力,即使最终你回到了办公室。
时间序列异常检测的有效方法
在当前的形势下,整个世界到处都在经历前所未有的情景,这通常被每个人称为“新常态”。但在成为“新常态 ”,这些异常或反常的结果会对任何组织产生积极或消极的影响,对制定长期业务战略来说,跟踪这些结果非常重要。因此,每个领域中的异常检测都将是一个重要的讨论主题,关于执行异常检测的有效方法的知识将是任何数据科学家和数据分析师都必须掌握的一项重要技能。
在我们深入研究之前,我们必须澄清,异常现象到底是什么?异常的定义可能因域而异。在我们上面看到的封面图片中,母狮是斑马群中的异类。因此,从技术上概括地说,我们可以说异常是异常数据点,它不遵循大多数数据点的集体共同模式,因此可以很容易地从其余数据中分离或区分出来。
现在,进入今天的主题范围,。我们将在本文中讨论什么、为什么和如何*时间序列异常检测部分。详细的** 编码走读 ,请访问我的 网站 。*
我在 YouTube 上的一段视频记录了一个类似的话题:
*** 更新 *如果你喜欢这篇文章,并希望更多地支持我对社区的贡献,请看看我的书 " 应用机器学习可解释性技术 " ,这是 GitHub 资源库,其中包含了书中涉及的各个章节的许多实践教程:https://GitHub . com/packt publishing/Applied-Machine-Learning-explability-Techniques。如果你喜欢 GitHub 资源库中提供的教程,请在资源库中做 fork 和 star,以示你对这个项目的支持!请订购该书的 纸质本 或 电子本 以示支持。
* [## 应用机器学习可解释技术:使 ML 模型可解释和可信…
应用机器学习可解释技术:使 ML 模型可解释和可信赖的实践…
www.amazon.com](https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref=as_li_ss_il)
什么是时间序列异常?
在时间序列数据中,异常值或离群值可以被定义为不遵循整个数据的共同集体趋势或季节或周期模式的数据点,并且与其余数据明显不同。大多数数据科学家所说的显著性是指统计显著性,换句话说,这意味着数据点的统计属性与序列的其余部分不一致。
突出显示异常数据点的时间序列图(图片由作者提供)
从上面的时间序列图中,我们可以看到,与整个序列显著不同的 5 个数据点用红圈突出显示。因此这 5 个异常数据点不符合时间序列的总体正弦性质,因此可以被称为 时间序列异常 。
为什么时间序列异常检测如此重要?
如前所述,为了评估【新常态】以及重组和重构业务战略和决策流程,跟踪每个部门的异常情况非常重要,并且迫切需要持续详细地研究这些异常情况。数据科学家的角色不仅在这些困难时期变得至关重要,而且对于数据科学家来说,想出一种方法来跟踪、研究和分析异常数据点并获得对业务有意义的信息也成为一种自然的期望。从销售和营销,到供应链和制造,企业的每个阶段都需要足够的信息,特别是关于这些异常的信息,以塑造其流程并最大限度地提高生产率和成果。因此,只要我们在数据中有一个共同的模式,特别是对于时间序列数据,这是非常重要的隔离离群值,并抽出时间和精力来研究这些。
时间序列异常检测怎么做?
现在,进入本文最重要的部分,关于部分如何做时间序列异常检测。从一个非常高的层次和一个非常通用的方式,时间序列异常检测可以通过三种主要方式来完成:
- 通过预测置信水平方法
- 统计剖析方法
- 基于聚类的无监督方法
在这一节中,我们将只关注技术,在下一篇文章或帖子中,我们将体验算法的确切代码部分以及如何用 Python 编程这些方法的有效方式。
基于预测置信度方法的时间序列异常检测
通过置信度方法进行异常检测(图片由作者提供)
使用时间序列数据进行异常检测的一种方式是通过使用历史数据建立预测模型,以估计和了解时间序列数据的总体共同趋势、季节性或周期性模式。使用预测模型来预测未来值,并基于误差率(可以使用 MAPE-平均绝对百分比误差来计算),我们可以得出预测值的置信区间或置信带,任何超出该置信带的实际数据点都是异常的。为了建立预测模型,也可以有效地使用流行的时间序列建模算法,如 ARIMA、萨里玛、GARCH、VAR 或任何回归或基于机器学习和深度学习的算法,如 LSTM。这种方法的主要优点是发现局部异常值,但主要缺点是,这种方法高度依赖于预测模型的效率。预测模型中的任何循环漏洞都可能导致假阳性和假阴性。
通过统计剖析方法进行时间序列异常检测
通过统计分析方法进行异常检测(图片由作者提供)
这种方法可能是统计学家和数学家最喜欢的方法,在经济和金融领域得到了有效的应用。生成给定数据的统计模型或概况可能是最快和最有用的方法,因为这种方法可以提供更可控和更可解释的结果。这可以通过计算统计值来实现,如历史数据的平均值或中值移动平均值,并使用标准偏差来得出一组统计值,这些统计值可以定义上限和下限,超出这些范围的任何值都可能是异常值。正如我所说的,这种方法非常方便,并且总是可以作为基线方法,而不是使用任何需要大量微调并且可能无法解释的复杂方法。这对于高度不稳定的时间序列也非常有效,因为当数据高度不稳定时,大多数时间序列预测模型算法都会失败。但是这种方法的主要缺点是检测局部异常值。正如我们在上图中看到的,在五个明显的异常点中,只有两个最重要的异常点被检测到。
通过基于聚类的无监督方法进行时间序列异常检测****
通过基于聚类的无监督方法进行异常检测(图片由作者提供)
无监督的方法对于异常检测非常有用,因为它不需要任何标记的数据,提到特定的数据点是异常。因此,聚类算法对于时间序列异常检测非常方便。目前,用于异常检测的聚类算法的一个常见缺陷或瓶颈是定义聚类数,这是大多数聚类算法需要的输入。虽然有许多估计聚类数的技术,但是对于时间序列数据,动态估计每个序列的聚类数是不可行的。这时,带噪声的应用程序的基于密度的空间聚类(DBSCAN)** 成为自然的选择。 DBSCAN 不需要任何预定义的聚类数,只有两个参数(一个聚类中的最小点数和ε,聚类之间的距离),所以非常容易调优,性能非常快。由于这些优点,DBSCAN 成为进行异常检测的最明显的选择,并且它不像传统的硬聚类技术(如 K-Means)那样将所有数据点分组到一个聚类中。DBSCAN 不将异常或离群数据点分组到任何集群,因此它变得非常容易应用。此外,DBSCAN 有助于绘制大多数其他方法可能会失败的【新常态】。但是 DBSCAN 也有一些缺点。一些异常数据点如果在稀疏间隔内重复多次,根据 DBSCAN,这些可能不会被映射为异常。因此,在这种情况下,使用基于滚动窗口的 DBSCAN 有助于更有效地绘制这些局部异常。**
更新如果你喜欢这篇文章,并希望更多地支持我为社区所做的贡献,请看看我的书“ 【应用机器学习可解释技术 ”,这是 GitHub 资源库,其中包含许多关于书中各个章节的实践教程:https://GitHub . com/packt publishing/Applied-Machine-Learning-explability-Techniques。如果你喜欢 GitHub 资源库中提供的教程,请在资源库中做 fork 和 star,以示你对这个项目的支持!请订购本书的** 实体本 或 电子本 以示支持。**
** [## 应用机器学习可解释技术:使 ML 模型可解释和可信…
应用机器学习可解释技术:使 ML 模型可解释和可信赖的实践…
www.amazon.com](https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref=as_li_ss_il)
因此,这就把我们带到了本文的结尾。在 我的个人网站 中,我 写了一篇详细的文章,讨论并提供了如何应用这些技术的精确 python 代码,并更深入地解释了常见的优点和缺点 。在那之前,请鼓掌并激励我进行更多的讨论,并与社区分享我的发现。希望我能帮上忙!继续关注:https://medium.com/@adib0073和我的网站:https://www.aditya-bhattacharya.net/***
有效的数据过滤。位置[]
照片由韦德·奥斯丁·埃利斯在 Unsplash 上拍摄
学习使用的多种方法。loc[]过滤 Pandas 中的数据帧
Pandas 是用于数据科学研究的最流行的 Python 包之一。它收集了大量用于处理结构化数据的强大方法。处理这些数据表(即 pandas 中的数据帧)的一个常规任务是过滤符合某个预定义标准的数据。在我自己的研究中,在各种过滤方法中,我经常使用 DataFrame 的 loc 属性过滤数据。在本文中,我将向您展示我们如何使用。loc[]用于有效的数据过滤。
基本设置
假设您已经构建了自己的 IDE,并在计算机上安装了 Python 和 pandas,基本的设置步骤如下所示。如果你想在 Visual Studio 代码中运行 Jupyter Notebook,请参阅我以前的文章。
首先,我将pandas
导入到笔记本中。出于当前教程的目的,我从 Kaggle 下载了 city_attributes.csv 数据集。这个数据集有 4 列:城市、国家、纬度和经度。当我导入文件时,我将城市设置为索引,以便以后进行更有意义的索引。
基本设置
在我们进行任何数据处理之前,看看我们正在处理的数据集总是一个好主意。为此,我只使用了sample()
和shape
来获得 2 个随机行,并检查数据帧的大小,这向我们显示数据有 36 条记录。
数据过滤
使用标签
第一种方法是使用标签过滤数据。这里有几个例子。如您所见,我们只需指定行和列的标签,符合这些标签的特定数据记录就会显示出来。
使用标签过滤数据
从上面的代码片段中,有几件事情需要强调。
- 我们可以指定单个标签或标签列表来过滤 loc[]中的数据。
- 筛选的数据可以是不同的类型:单个值、系列或数据帧,分别如示例所示。
- 当只设置了一个标签或标签列表时,它将返回所有列。
使用范围
另一种常用的方法是使用行和列标签的范围。下面是一些例子。类似地,如上所述,我们可以设置一个或两个范围,前者显示所有列,后者显示范围内的列。
使用范围进行数据过滤
使用布尔值
过滤数据的一个有效方法是使用与我们正在处理的轴的长度相匹配的布尔值列表。例如,在下面的代码中,我们能够通过只显示加拿大的城市来过滤数据。具体来说,我们通过将国家的值与字符串“Canada”进行比较来创建一系列布尔值,该系列的长度与数据帧的行号相匹配。由于 pandas 将 True 评估为 1,当我们请求这个系列的总和时,我们得到了 3,这正是我们通过运行cities.loc[cities[‘Country’]==‘Canada’]
得到的行数。
使用布尔进行数据过滤
当然,我们可以有一个更复杂的布尔求值表达式。下面给出一个例子。
使用布尔值进行数据过滤(多条件)
使用 Lambdas 或自定义函数
有时,我们需要有一个更高级的数据过滤标准,在这种情况下,我们可以使用 lambdas,如下所示。在 lambda 函数中,我们指定了名为 row 的参数,该参数引用数据帧中的系列,这样我们就可以像上面所做的那样对其求值以生成布尔列表。换句话说,这个方法是建立在使用布尔值的数据过滤方法之上的,尽管它们在概念上是不同的。
使用 Lambdas 进行数据过滤
如果我们想要设置更多的标准,我们甚至可以编写一个数据过滤函数。如下所示,我们有一个名为filtering_cities()
的函数,它评估多个标准并返回一个布尔值列表,可用于过滤数据。我们将简单地在 loc[]中设置这个函数来过滤数据。
使用函数进行数据过滤
结论
本文向您展示了如何使用 loc[]通过多种方式有效地过滤数据。当然,本教程只是通过介绍使用 loc[]进行数据过滤的基本元素来提供一个概念证明,还有其他几种数据过滤方法,我们稍后可以一起探讨。
有效的数据可视化
构建有效的数据可视化的技巧可以简化为 3 个简单的步骤
由于各种原因,如我们的智能手机成瘾,数据一直在以指数速度增长。我不想让任何人感到内疚,因为我也一样内疚——问题是……数字化前所未有地将全球人类联系在一起。我们非常依赖我们的智能手机来保持我们的信息——如果不是因为 Twitter,我不会知道周四晚上 8 点是 NHS 的感谢日,因此我们为什么鼓掌 1 分钟——结果数据是每天大量产生的,因此为什么 21 世纪被大量预测为数据时代。
“数据是 21 世纪的石油”
随着数据量的增长,无论是在 excel 电子表格中,还是在文本或图像中,从越来越大的数据批次中识别关键见解都变得极其困难。人类大脑试图识别模式以帮助学习和存储信息,但是在大型文本语料库(和其他形式的数据)中,如果没有一些视觉数据,找到关键信息可能会非常困难。机器学习的发展允许系统在没有显式编程的情况下自动学习和改善经验,简化了检测数据模式的任务,我们可以通过预测分析创建有用的模式可视化。此外,在我们开始建立预测模型或做出决策之前,了解我们掌握的数据至关重要,甚至超出了数据科学和数据分析的领域。
关于这一点,在这篇文章中,我将提供 3 个技巧来建立可视化,有效地传达你想要表达的信息。为此,我使用了 Kaggle 的 房价 数据集,您可以从房价竞赛的数据部分下载该数据集( 单击此处 )。要访问我用来生成图形的代码,可以在我的 Github 上访问(下面的链接)。
与中等博客文章相关的演示代码。-路径/到/文件;链接到文章有效的数据可视化…
github.com](https://github.com/kurtispykes/demo/tree/master)
图 1:NASA 在 Unsplash 拍摄的照片
什么是数据可视化?
在我们继续之前,如果我们想要构建有效的可视化,了解什么是数据可视化及其背后的目的是很重要的,所以不再多说…数据可视化是以可视化格式表示数据。可视化数据的目的是以易于理解的可视化方式总结和呈现数据,向读者突出显示数据中的关键信息。
在上面对数据可视化目的的描述中,我们可以提取两个要点,如果在任何数据可视化任务中记住这两个要点,将会立即使我们的可视化效果更好:
第 1 点:可视化应该概括并呈现容易理解的信息。“容易”这个词在这里很关键,因为它没有提到视觉化的复杂性。这一点很重要,因为有些图形可能需要更复杂,以达到易于理解的目的。另一方面,如果以简单的方式创建一些可视化效果来满足相同的目的,效果会好得多。到本文结束时,您应该能够区分何时使用简单或复杂的可视化。
第二点:数据即将呈现!在某些情况下,可能只有可视化的创建者才能看到,例如,当您自己处理机器学习分类任务时,您希望了解您的预测模型正在犯什么类型的错误。但是几乎总是我们最终会向观众展示我们的发现。因此,可视化必须针对特定的受众,也就是说,读者会对所获得的见解感兴趣,否则他们会感到厌烦。用前面的例子来说,向 CEO 展示你的预测模型所犯错误的可视化效果是无效的,而且可能会让你失去高管们的信任。相反,更好的做法是呈现可视化效果,允许采取可操作的步骤来带来商业价值。
“有超过 99 种分散注意力的方式,有趣的视觉化效果不是第一种”——没有人
从根本上说,我们进行数据可视化的原因是为了帮助读者看到正在分析的数据中的模式或趋势。从今以后,我将提供一个简单的一步一步的指南来产生有效的可视化。
提示#1 明确应该通过可视化来回答的问题
扭曲关键信息的可视化会妨碍做出有意义或准确决策的能力。发生这种情况的一种方式是使用一个繁忙的图,试图在任何时候回答许多问题。通过有一个你希望通过你的视觉化来回答的特定问题,它防止了矫枉过正和试图在一个数字上做太多事情。图 2 旨在确定数据集中缺失变量的数量,并使用类似交通灯的系统来突出显示任何一个要素中缺失变量的数量。可以通过添加说明每种颜色含义的图例来进一步增强该图,例如,红色=缺失数据超过 75%的值。
图 2:显示特性、每个特性中缺失值的数量以及相对于实例数量的百分比的表格。
提示 2 选择正确的图表
“一幅画胜过千言万语”
这听起来很简单,但可能非常困难…图表应该揭示你想告诉读者什么。如果你试图告诉读者,从收集的数据来看,目标特征或因变量的分布,那么直方图、violin 图、qq 图等图可以有效地完成工作。图 3 中的图结合了 3(直方图、Violin 图和 QQ 图),让我们确信数据的分布是正偏的,这对于我们选择用于解决问题的模型非常重要。为了改进这个图,我会将标题移到中间,将 核密度估计器 添加到直方图中,并决定使用不同的颜色来突出我正在制作的点——注意,这些改进只是为了使图表更漂亮,因为它很好地通知了我们特征是倾斜的。
图 3:目标变量的分布
提示 3 强调最重要的信息
使用颜色、大小、比例、形状和标签将读者的注意力引导到你想让他们识别的关键信息上——图 2 在交通灯系统中做得很好。我们希望向我们的读者揭示最重要的信息——在图 2 的情况下,读者可能是将设计功能和构建模型的机器学习工程师。红绿灯立即将我们的注意力吸引到哪些实例可能是一个挑战,以及哪些可能需要从数据中删除。值得注意的是,可视化允许机器学习工程师或数据科学家推迟思考的困难任务,因为可视化立即向我们显示我们的数据有什么问题,同时产生可以实施以改进我们的数据的想法。用于实现这一点的工程不一定是用于最终模型的工程,关键是它有助于我们做出可以采取行动的决策,即产生的想法可以用于设计快速基线模型。
图 4:显示特性相关性的热图。
在图 4 中可以看到另一个强调重要信息的例子。热图显示了功能之间的相关性,并使用更明亮的颜色来强调两个功能之间更强的关系。这使得挑选相关特征并对其做进一步分析变得容易。这样的信息对数据科学项目中的其他团队成员是有益的,因为它将有助于确定哪种方法对于这项任务是可行的。为了改进该表,我们可以在 x=y 线下方(或上方)的图上放置一个遮罩,因为它是冗余数据。
虽然我没有强调本文中可以使用的工具,但在某些方面,我们使用的工具可以帮助我们实现数据可视化的目的。数据科学家会知道 Matplotlib 和 Seaborn 等工具,但在本文中,我用来生成数据的工具是 Ploty.py。该框架允许交互式图表,这使得我们的可视化对读者来说更有吸引力。了解这个框架更多信息的一篇好文章是由 Will Koehrsen 撰写的,标题是“Python 中数据可视化的下一个层次,T2”。在这篇文章中,他提到了他从传统可视化工具切换到现代工具的理由,并给出了很好的入门演示。
结论
在可视化数据时应该记住的关键因素是,数据可视化是以一种容易理解的方式总结和呈现数据。因此,我们希望确保我们用可视化来回答特定的问题,在决定使用什么图表来显示数据时做出正确的选择。最后但同样重要的是,我们要确保我们强调的是我们希望读者抓住的关键信息,而不是用多余的信息混淆它们。
有很多方法可以可视化数据,提高这一技能的最好方法是实践。我用来为本文生成图表的 Github 代码远非最佳,没有充分利用 Plotly.js 的功能,并且缺乏深度——在这些数据中还有很多可以探索的地方。因此,有一个很好的机会让你去实践(我已经给了你一个轻微的开端)——简单地分叉我的工作(下面 Github 的链接),从 Kaggle ( 点击这里下载 )下载数据,安装需求,然后开始工作。
与中等博客文章相关的演示代码。-路径/到/文件;链接到文章有效的数据可视化…
github.com](https://github.com/kurtispykes/demo/tree/master)
如果你想分享你如何利用这篇文章来改进我的工作(或你已经完成的工作),这将是真正令我兴奋的,或者你只是想就任何与数据科学有关的事情联系我(即接下来可能要写的东西),你可以通过 Linkedin @KurtisPykes 联系我,或者只是对这篇文章发表评论。此外,我非常有兴趣听到你对这篇文章的反馈,所以请不要犹豫与我联系!
非常感谢您的宝贵时间!
其他资源关于此主题的有用资源…
Georgin Lau 和潘磊博士- 数据可视化的 5 步指南
鲁米博物馆- 与房价的详细回归
佩德罗马塞利诺- 用 Python 进行全面的数据探索
使用 PyCharm 和 Docker 的有效深度学习开发环境
借助全面承诺的 IDE 和虚拟化提高您的工作效率。
塞缪尔·伯克在 Unsplash 上的照片
在本文中,当您在远程环境(内部工作站、AWS、GPUs)中使用 GPU 时,我将指导您为深度学习培训建立一个有效的开发环境。
最后,您将在本地计算机上使用 PyCharm IDE 开发您的 ML/DL 代码,就好像它在您的本地环境中使用 Python 解释器一样。
动机
1.为什么要用 PyCharm 这种成熟的 IDE?
“因此,如果你想走得快,如果你想快速完成,如果你想让你的代码易于编写,就让它易于阅读。”
― 罗伯特·c·马丁, 干净的代码:敏捷软件工艺手册
- 当你训练你的深度学习代码时,你会做很多实验。你改变你的超参数,添加/删除层来优化模型,调整你的数据集…所以,过一会儿,代码可能会很难管理。因此,您需要编写整洁且可维护的代码。像 PyCharm 这样的 IDE 可以给你提供这样的环境。
- 在编码时,你必须实时观察你的变量和函数,看看它们是否如你所愿,否则你可能会在长时间的训练后遇到意想不到的结果。打印变量的值或函数的返回值是很常见的,大多数人都是通过在行间打字来完成的。这不是观察变量的正确方法;相反,你应该从外部观察它们。使用 PyCharm 变量资源管理器和 IPython 控制台可以轻松查看代码的行为和变量值。
- 阅读库的文档来为我们的任务找到合适的函数或对象是很费时间的。自动完成在编写快速代码时非常方便。然而,在像 Python 这样的动态类型语言中很难做到这一点。尽管其他 ide 和 Jupyter Lab 也有自动完成功能,但它们并不总是能正常工作。皮查姆非常擅长那项工作。
我认为这三点是使用 PyCharm 的关键因素,但还有许多其他的巨大优势:自动格式化、高级搜索、错误检查、轻松导航、智能重构、剖析、着色...
2.为什么应该使用 Docker?
如果你在 Ubuntu 机器上建立了深度学习环境,你就会知道匹配所有这些驱动程序、软件和库的版本有多难。如果你没有遇到任何困难,祝贺你!但是你可能还没有更新你的任何驱动,CUDA,或者深度学习(Tensorflow,PyTorch…)库,这意味着你随时都可能遇到这个困难。
深度学习框架(尤其是 TensorFlow)在版本更新上非常激进,这可能导致与 CUDA 版本或 NVIDIA 驱动程序不兼容。有时候,很难匹配这些软件的发布。此外,如果您不小心同时安装了不同版本的 NVIDIA 或 CUDA 驱动程序,处理起来可能会很复杂,您可能需要格式化您的系统。
Docker 解决了这些问题。你只需要安装 NVIDIA 驱动,其余的由 Docker 容器管理。
比如你正在做 TensorFlow,但是你看到在 PyTorch 的新版本中,有针对你的任务的完美功能,你想尝试一下。在同一台机器上管理不同的框架(和不同的版本)是一项挑战。使用 Docker,您可以管理它。它抽象了硬件驱动之上的系统;因此,您可以同时运行不同版本的框架和 CUDA。它类似于虚拟机,但没有虚拟机那么重。使用 Docker 有很多好处,但在这篇文章中,我不打算告诉这些。网上已经有很多很棒的文章,你可以广泛地阅读和获取信息。这篇文章是关于连接这两个产品。我们开始吧。
设置系统
流程图
1。 在本地电脑上安装 PyCharm (使用远程解释器需要专业版,PyCharm Professional 对学生免费)。
2。在你的远程机器上安装 Docker 。
2.1。 熟悉Docker 环境(可能需要一个工作日才能完全理解什么是映像、容器、如何从 Docker Hub 获取以及 Docker 系统的一般工作方式,但你会得到回报)。
2.2。把你喜欢的深度学习框架的 Docker 镜像下载到远程机器上。
现在,是时候将 PyCharm Python 解释器连接到 Docker 容器中的 Python 环境了。
1。启动 Docker 容器。转发端口 8022(可以这样改)到 22 ( 对于 SSH 连接来说是必须的)。示例:
sudo docker run --gpus all -it --rm -p 8022:22 -v /home/workstation/Desktop:/home/gorkem/Desktop --name ssh_container pytorch/pytorch:1.4-cuda10.1-cudnn7-devel bash
2。使用主操作系统的终端,检查您是否确实将您的端口 8022 转发到了 22 号集装箱。
sudo docker port <your container name> 22
-> 0.0.0.0:8022
3。在 Docker 容器中设置 SSH 服务器。
apt update && apt install -y openssh-servermkdir /var/run/sshdecho 'root:<USE_YOUR_OWN_STRONG_PASSWORD>' | chpasswd
# Root password was changed with <USE_YOUR_OWN_STRONG_PASSWORD>sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_configsed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshdecho "export VISIBLE=now" >> /etc/profileservice ssh restart
4。我无法通过 SSH 进入容器中的 root 用户,所以我创建了另一个 sudo 用户并建立了一个 SSH 连接。
adduser gorkem
adduser gorkem sudo
5。现在,你应该提交你的容器作为一个新的图像。否则,当您终止它时,您将丢失您对 contanier 所做的所有更新。我通常会在提交的图像末尾添加-ssh
标签。
docker commit <container_name> <name>/<name>:<tag>
6。关闭容器。
7。从提交的映像启动一个新的 Docker 容器。
sudo docker run --gpus all -it --rm -p 8022:22 -v /home/workstation/Desktop:/home/gorkem/Desktop --name ssh_container pytorch/pytorch:1.4-cuda10.1-cudnn7-devel-ssh bash
8。检查 SSH 状态,容器启动时会禁用(但可以设置为容器启动时自动启动),启动 SSH 服务器。
service ssh status
-> * sshd is not runningservice ssh start
-> * Starting OpenBSD Secure Shell server sshdservice ssh status
-> * sshd is running
9。SSH 服务器正在你的 Docker 容器中运行,现在你可以按照官方的 PyCharm 指南将你的 PyCharm 远程解释器连接到这个容器。在两个问题上你应该小心:
9.1 您的用户名是您在 Docker 中创建的用户名(在我的例子中,它是gorkem
)。
9.2 虽然 SSH 默认工作在端口 22 上,但是你必须使用转发端口(在我的例子中是 8022 )。PyCharm 首先连接到远程机器,然后 SSH 连接被转发(由 Docker)到我们的容器。
在从 PyCharm 直接连接到 Docker 容器之前,您可以使用类似于 Putty 的程序来测试 SSH 连接(还是要注意端口号和用户名),以确保容器端一切正常。
现在您可以在 PyCharm IDE 上开发您的算法,就好像您的培训是在您的本地 PC 上运行一样。
如果您有任何问题或改进,请评论。
觉得这篇文章有用?看看我下面的其他文章:
传统的 CNN(Alex net,VGG,GoogLeNet,ResNet,DenseNet …)在样本较多的情况下有很好的表现…
medium.com](https://medium.com/swlh/deep-learning-architectures-that-you-can-use-with-a-very-few-data-8e5b4fa1d5da) [## 如何解决你深度学习训练中的数据加载瓶颈
即使你没有固态硬盘!
medium.com](https://medium.com/@GorkemPolat/how-to-solve-data-loading-bottlenecks-in-your-deep-learning-training-1ddfcc24449b)
有效的 SQL 技能提升
Domenico Loia 在 Unsplash 拍摄的照片
如何通过现成的 leader 数据库(免费)使您的 SQL 升级更有效。
任何数据主题中的“提升技能”都意味着两件互补的事情:学习新技能(语言、算法等)。),并不断更新您已经建立的技能。
在这个故事中,我的目标是与你分享一些提升 SQL / PL-SQL / T-SQL 技能的方法。
让我们远离 SQL 懒惰
任何数据科学学科,或任何包含“..数据..”word 在某些时候需要查询数据库并进行一些开发。事实上,我参加过的任何工作面试(无论是作为面试官还是被面试者)都会测试应聘者的 SQL 专业知识以及其他方面。
但问题来了:一旦我们得到了这份工作,我们倾向于只使用我们技能组合中的一小部分来处理公司的数据生态系统,并最终实现老板的期望。我承认:有时我在编写查询或进行数据库开发时变得“懒惰”,只是因为数据库和工具允许我选择肮脏的方式来做事。一个显著的例子是:我曾经做过一个客户流失分析项目,在这个项目中,一个经过良好调整的 Teradata 集群被用来处理相对少量的电信交易。它可以在几毫秒内运行任何脏的分析查询。
另一方面,当数据库配置很差、容量太大或者没有适当调整时,我们必须找到构建查询或在其上开发的聪明方法。查询需要一个完美优化的代码,开发需要使用正确的对象(正确类型的索引、分区、统计信息集合等)..).此外,在这种情况下,我们需要深入了解我们正在处理的平台:在 MS-SQL Server 上最有效的技巧可能与在 Oracle 中不同,等等。
我很确定你也遇到过一些蹩脚的 DB,对吧?因此,在任何情况下,我们能找到的最好的解决方案就是不断提升我们的数据库和 SQL 知识。
如果你想知道为什么数据人员需要掌握 SQL,这里有一个很好的故事:
[## 每个有抱负的数据科学家必须学习 SQL 的 5 个理由
随着海量数据的出现,企业和行业正在收集和产生数十亿的数据…
medium.com](https://medium.com/analytics-vidhya/5-reasons-every-aspiring-data-scientist-must-learn-sql-2bab007a8d76)
我们的目标:提升 SQL 技能
在这里,我将解释一段时间以来我一直在做的事情,提升自己的技能,为他人提供培训,以及更广泛地分享知识。
简而言之,我用的是两个免费平台:【SQL Live】和【Dev Gym】。要访问它们,您需要创建一个 Oracle 登录名。
1.“SQL Live”在线数据库
它提供了对实时 Oracle(企业版!)数据库,已经设置了各种模式和模型类型,其中有一些默认数据,您可以实时查询这些数据。
作者截图
最有用的是 SQL 工作表,连接数据库和运行任何脚本(DML、DDL 等)的实际实时会话..).
作者截图
2.“开发健身房”培训平台
它包括锻炼、课程、关于 SQL、PL/SQL 的测验、分析、数据库设计、调优等..从完全的初学者到专家的任何水平。
我认为自己是专家,但我可以保证,在 Dev Gym,你总会找到比你更专业的人,从他们身上你可以学到很多东西。
我不会对你应该做哪些锻炼提出建议,你可以根据 SQL 水平和感兴趣的话题浏览和选择。我想给你的唯一建议是,先固定好自己的目标,然后按周或按月制定一个自我训练时间表,这样你就可以连贯地规划你想学的内容。
让 Dev Gym 和 SQL Live 一起工作
Dev Gym 的优势在于,您选择的任何培训(锻炼、课程、测验)都已经有了配置练习所需的源脚本,因此您不需要花费时间来构建虚假的表格和数据。
您只需要获取这些脚本,并在 SQL Live 中运行它们来创建必要的对象,然后您可以使用这些对象进行实际的训练和编码。
让我们来看一个例子:我们参加“sensive SQL”测验,并选择“关于分析函数的测验”模块。Code 按钮允许您导入代码,然后在 SQL Live 会话中运行代码,以构建和加载表。
作者截图
作者截图
现在,您可以构建查询,并通过 SQL 工作表对创建的对象进行锻炼
作者截图
SQL-Live 内置数据模型
使用“SQL Live”的另一个好方法是利用几个内置的模式,用不同类型的模型来表示现实世界中模型的简化版本。静态数据、OLTP、星型模式化已经可以使用了,或者您甚至可以导出模式和数据,并在其他数据库中重新创建它们,方法是根据您的需要修改 Oracle 语法。
作者截图
保持你的知识更新
几乎每个主要数据库供应商的新版本都引入了新功能。在过去的几年中,所有主要的数据库供应商都增加了许多新的聚类、分析和统计功能。
事情是这样的,其中一个玩家首先推出新功能,然后所有其他玩家通常会跟着做同样的事情。从这个角度来看,甲骨文通常是领先者。
“SQL Live”的另一个优势是它会定期升级到最新的数据库版本,这样您就可以尝试和学习新发布的功能,而无需花费时间升级数据库。
局限性和解决方法
“SQL Live”和“Dev Gym”基于 Oracle 技术,这意味着其中的所有材料都使用 Oracle 的 SQL 和 PL/SQL。那么,我们能做些什么来在另一个数据库上练习同样的练习、锻炼等呢?
这里有一个技巧:所有的“SQL Live”和“Dev Gym”脚本都可以导出(您将在编辑器附近看到导出代码按钮),并且您可以修改它们以在任何数据库上运行,主要是通过改变 DDLs 语句中的数据类型、修改 DMLs 或替换函数(数据转换、分析等)..)与您的目标数据库所接受的进行比较。
如果您不熟悉 Oracle 数据库,我相信它是值得学习的:Oracle 总是排在 Garner 魔力象限的最顶端。
提升 SQL 技能的其他方法
如果您不想使用上面解释的 Oracle 环境,我可以提出另外几个想法:
- https://www.db-fiddle.com/允许在各种数据库上运行实时 SQL 代码:MS SQL Server,MySQL,PostgreSQL。但是没有预先建立的物体、锻炼或训练:你需要准备你自己的环境。另一个好处是你不需要创建一个登录。
- 获取并安装 MySQL :设置需要 15 分钟,但是值得拥有。我已经描述了如何设置它,并可选地将其连接到 ETL 工具、R(对于 Python 也是可能的,但我在我的另一篇文章中没有解释如何做),或 Dashboarding 工具:
我在家里的“真实世界”数据科学环境:数据库,ETL,数据分析,仪表板,9 个步骤。
medium.com](https://medium.com/@maw.ferrari/create-a-real-world-data-science-environment-at-home-7a4255ff6fa5)
简而言之…
- 通过免费访问预先构建的数据库,可以在世界一流的数据库上升级 SQL,从而避免在安装和数据设置过程中花费时间
- 我解释了如何通过使用一个活动的 Oracle 数据库(SQL Live)和一组内置的模型、练习和锻炼(Dev Gym)来实现这一点。
- 然后,我们看到了如何将 Oracle 模型和练习迁移到其他平台(SQL Server 等..).
- 最后,我提到了 Oracle 的另外两种替代方案,它们允许 SQL 升级。
感谢阅读!**
如果你想订阅《灵媒》,请随意使用我的推荐链接https://medium.com/@maw-ferrari/membership:对你来说,费用是一样的,但它间接有助于我的故事。
随着时间的推移有效地可视化数据,以讲述更好的故事
使用 Python 和 Plotly 构建清晰易读的时序数据可视化,以支持您的叙述。
2018-2019 NBA 常规赛
不言而喻,时间是我们所做的几乎每一件事情不可或缺的一部分,包括构建我们对周围世界理解的叙事。当谈到基于数据的 T2 讲故事时,情况也是如此,我们经常需要将数据可视化。无论是公司的股票价格、候选人的选举民调数据,还是一个国家的人口数量,数据随时间的变化都是叙事的关键要素。
但是可视化时间序列数据可能是一个具有挑战性的命题。当有多个数据系列时尤其如此,这些数据系列在小空间内相互交错,就像一群第一次踢足球的不守规矩的 6 岁儿童。
看看下面的图表,它是由 StackOverFlow 用户发布的。
你能看懂这张图表吗?(来自斯塔克伟福
正如你可能想象的那样,发帖人正在寻求帮助,如何使图表更清晰易读。甚至很难识别出图中的单个痕迹,更不用说弄清楚任何可能存在的模式了。
我注意到这个图表只包括四个轨迹。
另一方面,在 FiveThirtyEight 看一看这位来自 Andrew Flowers 的美女。
那更好!(五三八)
该图表包括了不到 60(!)痕迹。但是 FiveThirtyEight 对饱和度、颜色和标签的明智使用彻底改变了游戏。即使在这 60 个数据系列之外,关键的 10 个系列也清楚地显示出来,使读者能够识别每个系列,并随着时间的推移跟踪它,以支持所写的散文。
显然,我们都希望我们的图表看起来更像后者,而不是前者。所以在这篇文章中,我想谈谈如何做到这一点,使用我常用的数据可视化工具(Plotly)来可视化数据。至于数据,让我们用 2018–2019 NBA 赛季数据来尝试重新讲述它的故事;当然,我们可以很容易地使用股票、城镇人口或我的体重数据。我们走吧。
在开始之前
数据
我把代码和数据放在我的 GitLab repo 这里 ( nba_storytime
目录)。所以请随意使用它/改进它。
Packages
我假设您熟悉 python。即使你相对较新,这个教程也不应该太难。
你需要pandas
和plotly
。用一个简单的pip install [PACKAGE_NAME]
安装每一个(在您的虚拟环境中)。
获取您的数据
我选择的数据集是每个 NBA 球队比赛结果的集合。用以下内容加载csv
文件:
all_records_df = pd.read_csv('srcdata/2018_2019_season_records.csv', index_col=0)
数据集包括每一场比赛,包括季后赛。数据集包括字符串形式的比赛日期,因此我们可以按日期过滤它们:
records_df = all_records_df[pd.to_datetime(all_records_df.date) < pd.to_datetime('2019-04-12')]
看起来是这样的:
这些数据包括每支球队在这些比赛日期的累计净得分、比赛次数、胜败情况。
换句话说,随着时间的推移,这些数据讲述了每个球队的赛季故事。我们来看看如何最好地讲述每个团队的故事,如何突出关键时刻,通过数据发现什么有趣的故事。
用数据讲故事
介绍
让我们把数据绘制成散点图。我们可以生成图表来查看每场比赛的累积胜率:
import plotly.express as px
fig = px.scatter(records_df, x='date', y='wins', color='team')
fig.show()
赢与玩的游戏——分散
这是一个很好的开始,但这是一个相当拥挤的图表,尤其是在赛季初。一些颜色在这里和那里很突出,但对我来说,似乎有太多的重叠,挑选出特定的数据集或注意数据中的模式是很清楚的。
让我们来看看其他一些可视化数据的方法。
整理数据
如果我们把散点图的点连接起来,把它转换成线图,会怎么样?
(代码方面,这将做到:fig.update_traces(mode=’markers+lines’)
)
赢与玩的游戏—带标记的折线图
好吧,还不错。因为我们想讲述一个团队发展的故事,所以折线图可能是比散点图更好的选择。(如果您不想看到这些点,请指定:fig.update_traces(mode=’lines’)
)
赢与玩的游戏—仅折线图
不过,这里有 30 条跟踪,很难分辨出哪条跟踪在做什么。此外,我们的边上的传说似乎是在一个随机的顺序,使发现困难。让我们解决这个问题。
我们所要做的就是传递一个类别参数值的实参,以你喜欢的任何顺序作为一个列表。我只是将数据按字母顺序排序,然后像这样传递:
tm_names = [i for i in records_df.team.unique()]
tm_names.sort()
fig = px.scatter(records_df, x='games', y='wins', color='team', category_orders={'team': tm_names})
使用有序名称
右边的图例现在按字母顺序排列,使我们能够更容易地找到并隔离正确的轨迹。
说到寻找痕迹——你注意到每条痕迹的颜色都变了吗?那是因为这些颜色是任意分配的。(当然是——我们还没有指定任何颜色映射!)这在某些情况下没问题,但我们可以做得更好。通常,一个数据源会有一种颜色,读者会将这种颜色与它联系起来。在这种情况下,为什么我们不给每条赛道分配颜色呢?
丰富多彩的语言
我包含了一个我整理好的字典文件,格式为{teamname: teamcolour}
。加载它:
import pickle
with open('srcdata/teamcolor_dict.pickle', 'rb') as f:
team_col_dict = pickle.load(f)
我们使用列表理解来构建一个颜色列表,其顺序与我们上面使用的团队列表(tm_names
)的顺序相同:
team_cols_list=[team_col_dict[tm] for tm in tm_names]
简单地传递这个列表作为color_discrete_sequence
的一个参数:
fig = px.scatter(records_df, x='games', y='wins', color='team', category_orders={'team': tm_names}, color_discrete_sequence=team_cols_list)
fig.update_traces(mode='markers+lines')
fig.show()
现在用队服!
这并不完美——太多的队服颜色是深绿色和红色的变体。但是,至少现在更容易知道哪个跟踪可能指向哪个团队。
还记得我们在上面看到的 538 图表吗?该图以去饱和灰色显示了大部分轨迹,有助于突出彩色轨迹。让我们试试类似的东西。
最简单的方法是修改我们传递的颜色列表。只需保持我们感兴趣的痕迹的颜色,并将所有其他颜色改为灰色。有很多方法可以做到这一点,但我通过构建一个全新的列表来做到这一点:
base_col = '#C0C0C0'
team_cols_list = list()
for i in range(len(tm_names)):
tm = 'TORONTO_RAPTORS'
if tm_names[i] == tm:
team_cols_list.append(team_col_dict[tm])
else:
team_cols_list.append(base_col)
以完全相同的方式绘制图表,您会看到:
特别强调一条线索(在这种情况下,是最终的 NBA 冠军)
想突出多个痕迹?这很容易做到。再加上猛龙的赛区对手。
base_col = '#C0C0C0'
hero_teams = ['TORONTO_RAPTORS', 'PHILADELPHIA_76ERS', 'BOSTON_CELTICS', 'BROOKLYN_NETS', 'NEW_YORK_KNICKS']
team_cols_list = list()
for i in range(len(tm_names)):
if tm_names[i] in hero_teams:
tm = tm_names[i]
team_cols_list.append(team_col_dict[tm])
else:
team_cols_list.append(base_col)
fig = px.scatter(records_df, x='games', y='wins', color='team', category_orders={'team': tm_names}, color_discrete_sequence=team_cols_list)
fig.update_traces(mode='markers+lines')
fig.show()
大西洋赛区记录(抱歉,尼克斯球迷)
太好了,但是还有一个小问题。一些痕迹(像黑色的布鲁克林篮网的痕迹)被灰色的痕迹掩盖了。我理解这是由于 Plotly 渲染散点图的方式。轨迹实际上是在图例上从上到下呈现的。因为网队的名字出现在顶部,它被埋在底部。
所以让我们改变一下我们队名的顺序。我们通过以不同的方式构造我们的团队名称列表来做到这一点——之后可以使用相同的剩余代码。
hero_teams = ['TORONTO_RAPTORS', 'PHILADELPHIA_76ERS', 'BOSTON_CELTICS', 'BROOKLYN_NETS', 'NEW_YORK_KNICKS']
tm_names = [i for i in records_df.team.unique() if i not in hero_teams]
tm_names.sort()
tm_names = tm_names + hero_teams
更好,对吗?(还是对不起尼克斯球迷)
收尾
支线剧情
我们的情节开始看起来相当不错——所以让我们对它们做一些最后的润色。第一,我想比较一下联盟中的两个“联盟”,并强调一下西部的西南赛区。
将分队添加到我们的列表中,并将‘conference’
传递给我们的facet_col
参数来创建两个支线剧情:
# Separate Conferences, and add highlights for
hero_teams = [
'TORONTO_RAPTORS', 'PHILADELPHIA_76ERS', 'BOSTON_CELTICS', 'BROOKLYN_NETS', 'NEW_YORK_KNICKS',
'HOUSTON_ROCKETS', 'SAN_ANTONIO_SPURS', 'DALLAS_MAVERICKS', 'MEMPHIC_GRIZZLIES', 'NEW_ORLEANS_PELICANS'
]
tm_names = [i for i in records_df.team.unique() if i not in hero_teams]
tm_names.sort()
tm_names = tm_names + hero_teams
team_cols_list = list()
for i in range(len(tm_names)):
if tm_names[i] in hero_teams:
tm = tm_names[i]
team_cols_list.append(team_col_dict[tm])
else:
team_cols_list.append(base_col)
fig = px.scatter(records_df, x='games', y='wins', color='team',
category_orders={'team': tm_names}, color_discrete_sequence=team_cols_list, facet_col='conference')
fig.update_traces(mode='markers+lines')
fig.show()
支线剧情
通过将两组数据分成次要情节,我们可以立即看出两次会议之间有趣的对比。很明显,右边的支线剧情(西部联盟)包括更多的轨迹,这些轨迹以更高的比分结束,表明更多的球队赢得了更高的总比分。除了一个异常点,这张图表表明 2018-19 赛季联盟最差的球队主要在东部联盟。
绘图主题/模板
这真是太棒了,我刚刚才知道,所以我想在这里简单地分享一下——尽管我正在学习如何使用它们。Plotly 包括一个“主题/模板”功能,允许您快速更改绘图的外观。
我可能会在另一篇文章中深入研究更多的细节,但是现在,请注意,传递模板参数将允许您改变许多绘图格式,例如:
fig = px.scatter(records_df, x='games', y='wins', color='team', category_orders={'team': tm_names},
color_discrete_sequence=team_cols_list, facet_col='conference', **template="plotly_white"**)
带有“plotly_white”主题
“plotly_black”主题
也许你更像是一个 ggplot2 的人
由于我指定了轨迹的团队颜色,轨迹颜色没有改变,但是主题化也会改变默认的颜色图。点击查看文档。
标题和字体大小
为了完整起见,这里有一个版本的图,标题、支线剧情名称和轴标题都经过了格式化处理——以产生一些接近我将在分析文章中使用的内容。
fig = px.scatter(records_df, x='games', y='wins', color='team', category_orders={'team': tm_names},
color_discrete_sequence=team_cols_list, facet_col='conference', template="ggplot2",
title='2018-19 NBA Regular season wins',
labels={'games': 'Games played', 'wins': 'Season Wins'}
)
fig.for_each_annotation(lambda t: t.update(text=t.text.replace('conference=', 'Conference: ')))
fig.update_traces(mode='markers+lines')
fig.show()
除了.for_each_annotation
方法之外,上述所有方法可能都非常简单。
我在这里做的是用我认为可读性更好的‘Conference: ‘
替换部分自动生成的支线剧情标题文本(比如‘conference=Eastern’
)。
这是由 lambda 函数完成的,其中 Plotly 的。for_each_annotation 负责遍历每个注释对象并应用 lambda。
结果如下:
这是我之前做的一个
这看起来是非常简单的数据,但在这种形式下,数据比我们的第一个图更容易消化。如果你不相信我——只需向上滚动,看看我们生成的前两个图。我可以等。
对吗?
通过突出个人的痕迹,我们不仅可以快速展示这些特定的团队是如何在会议的背景下被放置的,还可以展示他们自己的部门的海洋。每个轨迹的梯度显示了它们在季节的不同阶段经历的热(陡)或冷(平)条纹。
此外,在线 Plotly 图表提供了与鼠标悬停数据的交互性,这为用户提供了很好的服务,使他们不必在图表和图例之间来回切换。
不要忘记交互性
对于时间序列数据,我们几乎可以做无限多的事情,因此很难将数据跨时间可视化。如果做得不好,看起来实际上有无限的数据点和数据系列要绘制并传达给我们的读者。
因此,能够从噪音中获取关键细节或信息是很重要的,对我来说,简单的东西会帮助你做到这一点——无论是颜色、比例、支线剧情还是其他什么。事实上,我经常发现一个关键的区别是不要让读者被信息淹没。事实证明,越少往往越多!
这就是我今天的全部内容——感谢您的阅读,如果您有任何建议或要求,请告诉我。
如果你喜欢这个,比如说👋/关注推特,或点击此处获取更新。ICYMI:我还写了这篇关于用 Plotly Dash 构建 web 数据仪表板的文章。
[## 使用 Python 在几分钟内构建一个 web 数据仪表板
通过将您的数据可视化转换为基于 web 的仪表板,以指数方式提高功能和可访问性…
towardsdatascience.com](/build-a-web-data-dashboard-in-just-minutes-with-python-d722076aee2b)
另外,这是我写的另一篇关于可视化类别变量的文章:
[## 用 Python 处理和可视化多个分类变量——NBA 的赛程挑战
使用平行分类图和树形图来可视化、识别和比较多个输入变量在…
towardsdatascience.com](/processing-and-visualizing-multiple-categorical-variables-with-python-nbas-schedule-challenges-b48453bff813)
使用 Pandas 的 Groupby 功能进行有效的数据汇总和分析
迈克尔·佩恩在 Unsplash 上的照片
学习使用聚合函数,数据转换,过滤,映射,在数据框架中应用
Groupby 是熊猫很受欢迎的功能。它非常擅长汇总、转换、过滤和其他一些非常重要的数据分析任务。在本文中,我将结合实例详细讲解 groupby 函数的应用。
资料组
在本文中,我将使用 Kaggle 的“学生表现”数据集。请从这里随意下载数据集:
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/rashida048/Datasets/blob/master/StudentsPerformance.csv)
在这里,我将导入必要的包和数据集:
import pandas as pd
import numpy as np
df = pd.read_csv('StudentsPerformance.csv')
df.head()
Groupby 是如何工作的?
Groupby 函数根据您定义的条件拆分数据集。这里我展示了 groupby 函数背后的过程。它会给你一个概念,如果没有 groupby 函数,我们要做多少工作。在本节中,我将创建一个包含两列的更小的新数据集来进行演示。这两栏是“性别”和“阅读分数”。
test = df[['gender', 'reading score']]
test.head()
让我们找出不同性别的平均阅读分数
首先,我们需要根据性别分割数据集。仅生成女性数据。
female = test['gender'] == 'female'
test[female].head()
以同样的方式,为男性生成数据,
male = test['gender'] == 'male'
test[male].head()
使用上面的女性和男性数据集分别计算女性和男性的平均阅读分数。
fe_avg = test[female]['reading score'].mean()
male_avg = test[male]['reading score'].mean()
print(fe_avg, male_avg)
女性的平均阅读分数为 72.608,男性的平均阅读分数为 65.473。现在,做一个女性和男性平均阅读分数的数据图表。
df_reading = pd.DataFrame({'Gender': ['female', 'male'], 'reading score': [fe_avg, male_avg]})
现在,让我们用 groupby 函数解决同样的问题。根据性别分割数据,并对其应用“平均值”,只需一行简单的代码:
test.groupby('gender').mean()
这一小段代码给出了相同的结果。
分组依据中的组
我现在将使用原始数据集“df”。按“种族/民族”分组。
race = df.groupby('race/ethnicity')
print(race)
输出:<pandas.core.groupby.generic.dataframegroupby object="" at=""></pandas.core.groupby.generic.dataframegroupby>
它返回一个对象。现在检查“race”的数据类型。
type(race)
输出:pandas . core . group by . generic . data frame group by
因此,我们生成了一个 DataFrameGroupBy 对象。对此 DataFrameGroupBy 对象调用组将返回每个组的索引。
race.groups#Here is the Output:
{'group A': Int64Index([ 3, 13, 14, 25, 46, 61, 62, 72, 77, 82, 88, 112, 129, 143, 150, 151, 170, 228, 250, 296, 300, 305, 327, 356, 365, 368, 378, 379, 384, 395, 401, 402, 423, 428, 433, 442, 444, 464, 467, 468, 483, 489, 490, 506, 511, 539, 546, 571, 575, 576, 586, 589, 591, 597, 614, 623, 635, 651, 653, 688, 697, 702, 705, 731, 741, 769, 778, 805, 810, 811, 816, 820, 830, 832, 837, 851, 892, 902, 911, 936, 943, 960, 966, 972, 974, 983, 985, 988, 994], dtype='int64'), 'group B': Int64Index([ 0, 2, 5, 6, 7, 9, 12, 17, 21, 26, ... 919, 923, 944, 946, 948, 969, 976, 980, 982, 991], dtype='int64', length=190), 'group C': Int64Index([ 1, 4, 10, 15, 16, 18, 19, 23, 27, 28, ... 963, 967, 971, 975, 977, 979, 984, 986, 996, 997], dtype='int64', length=319), 'group D': Int64Index([ 8, 11, 20, 22, 24, 29, 30, 33, 36, 37, ... 965, 970, 973, 978, 981, 989, 992, 993, 998, 999], dtype='int64', length=262), 'group E': Int64Index([ 32, 34, 35, 44, 50, 51, 56, 60, 76, 79, ... 937, 949, 950, 952, 955, 962, 968, 987, 990, 995], dtype='int64', length=140)}
看看上面的输出。Groupby 函数将数据分成子组,现在可以看到每个子组的指数。太好了!但是仅有指数是不够的。我们需要看到每组的真实数据。函数“get_group”对此有所帮助。
race.get_group('group B')
我在这里展示部分结果。原来产量大很多。
找出每组的大小
对“race”对象调用 size 将给出每个组的大小
race.size()
循环每组
您可以在各组之间循环。这里有一个例子:
for name, group in race:
print(name, 'has', group.shape[0], 'data')
多变量分组
在上面所有的例子中,我们只按一个变量分组。但是通过多个变量分组也是可能的。在这里,我按“种族/民族”和“性别”分组。这将返回按性别分类的每个种族的数据数量。
df.groupby(['gender', 'race/ethnicity']).size()
此示例使用“size”聚合数据。还有其他聚合函数。以下是所有聚合函数的列表:
总和()
平均值()
大小()
计数()
标准()
风险值()
扫描电镜()
最小值()
中位数()
请试用它们。只需替换这些集合函数中的任何一个,而不是上面示例中的“size”。
使用多个聚合函数
我们可以在多个变量上使用 groupby,使用多个聚合函数也是可行的。下一个示例将按“种族/民族”分组,并将使用“最大”和“最小”函数进行聚合。
df.groupby('race/ethnicity').agg([np.max, np.min])
这里的聚合函数作用于每一列。因为我们没有指定任何列。
制作每场比赛的数学、阅读和写作的最低和最高分数的数据图表。
要做到这一点,使用前面的代码并像这样添加分数:
df.groupby('race/ethnicity')['math score', 'reading score', 'writing score'].agg([np.max, np.min])
对多个变量进行分组并使用多个聚合函数
为了证明这一点,我们将按“种族/民族”和“性别”进行分组。此外,使用两个聚合函数“min”和“max”。让我们制作一个数据框架,包含按性别划分的每个小组在数学、阅读和写作方面的最高和最低分数。
df.groupby(['race/ethnicity', 'gender'])['math score', 'reading score', 'writing score'].agg([np.max, np.min])
不同列上的不同聚合函数
按“种族/民族”分组,对数学成绩使用最大值和平均值,对阅读成绩使用中值和最小值。
df.groupby('race/ethnicity').agg({'math score': ['max', 'mean'],
'reading score': ['median','min']})
很酷,对吧?但是列名没有那么好和清晰。它们应该更清晰、更好。我们可以像这样更改列名:
math_read = df.groupby('race/ethnicity').agg({'math score': ['max', 'mean'], 'reading score': ['max', 'mean']})
math_read.columns=['Max Math Score', 'Average Math Score', 'Max Reading Score', 'Average Reading Score' ]
完全相同的数据框架,但更有条理。
对名义列使用聚合函数
在上面的所有例子中,我们在数字列上使用了聚合函数。对一些名义列(如“午餐”和“父母教育水平”)应用聚合函数。
df.groupby(['race/ethnicity', 'gender']).agg({'lunch': pd.Series.mode, 'parental level of education': pd.Series.mode, 'math score':np.mean})
正如您在上面的代码中看到的,对于名义数据,语法是不同的。就像提醒模式是出现最多的数据。
在 Groupby 中应用函数
计算一下有多少孩子的“父母教育水平”是高中水平。
df.groupby(df['parental level of education'].apply(lambda x: 'high' in x)).size()
如果您不习惯使用 lambda,请查看这篇文章:
[## 使用 Lambda、Map、Filter 和 Sorted 进行高效的 Python 编程
使用数字、字符串和字典列表的快乐编程
towardsdatascience.com](/efficient-python-programming-with-lambda-map-filter-and-sorted-cfdf536afc36)
将“数学分数”栏分成三个偶数桶,并将其定义为低、中、高分
df.groupby(pd.qcut(x=df['math score'], q=3, labels=['low', 'average', 'high'])).size()
如果你想设置分界点,并定义你的低,平均,高,这也是一个简单的方法。
df.groupby(pd.cut(df['math score'], [0, 40, 70, 100])).size()
使用 Groupby 转换
在数据帧“df”中生成一个新列,并添加一个包含每个数学分数与平均数学分数之差的列。
df['Distance From the Mean'] = df.groupby(['race/ethnicity', 'gender'])['math score'].transform(lambda x: x - x.mean())
看上面的数据框。末尾有一个名为“与平均值的距离”的新列。
使用 Groupby 筛选
您可以根据特定条件筛选出数据,使数据更有意义。筛选数据少于 100 行的组或种族。
df_n = df.groupby('race/ethnicity').filter(lambda x: len(x) > 100)
上面的代码说保留长度超过 100 的组。检查原始数据帧“df”和过滤数据帧“df_n”的长度。
print(len(df))
print(len(df_n))
原始数据帧的长度为 1000,应用过滤器后,数据帧的长度变为 911。
地图
绘制每组的平均阅读分数,并生成一个新列。
df['New'] = df['race/ethnicity'].map(df.groupby(['race/ethnicity'])['reading score'].mean())
看看这个数据框。最后有一个名为“新”的新列,包含相应组的平均阅读分数。
使用 Groupby 进行可视化
众所周知,一图胜千言。下面是 groupby 中可视化技术的一些演示。做一个父母教育水平的柱状图。
import matplotlib.pyplot as plt
plt.clf()
df.groupby('parental level of education').size().plot(kind='bar')
请尝试制作一个饼图。你只需要在上面的代码中使用' pie '而不是' bar'。如果你没有传递任何'种类',情节将是一个简单的线情节。让我们画出每组的平均数学分数。
df.groupby('race/ethnicity')['math score'].mean().plot()
结论
在本文中,您学习了以多种不同的方式对数据进行分组和汇总。您学习了使用 groupby 使用聚合函数、数据转换、过滤、映射和可视化。
我在这个视频中也解释了同样的内容:
欢迎在推特上关注我,喜欢我的 T2 脸书页面。
更多阅读:
完整的可视化课程
towardsdatascience.com](/your-everyday-cheatsheet-for-pythons-matplotlib-c03345ca390d) [## 使用 Python 的 Scikit-Learn 库的完整推荐系统算法:分步指南
一个简单、容易、有用的算法,只有几行代码
towardsdatascience.com](/a-complete-recommendation-system-algorithm-using-pythons-scikit-learn-library-step-by-step-guide-9d563c4db6b2) [## 数据科学家使用 Python 进行假设检验的完整指南
用样本研究问题、解决步骤和完整代码清楚地解释
towardsdatascience.com](/a-complete-guide-to-hypothesis-testing-for-data-scientists-using-python-69f670e6779e) [## 编程、软件工程和数据科学的最佳免费课程
麻省理工、哈佛和斯坦福等顶尖大学的免费课程
towardsdatascience.com](/best-free-courses-for-computer-science-software-engineering-and-data-science-50cd88cafd74) [## Python 中从头开始的完整异常检测算法:分步指南
基于概率的异常检测算法
towardsdatascience.com](/a-complete-anomaly-detection-algorithm-from-scratch-in-python-step-by-step-guide-e1daf870336e) [## 如何在 Python 中呈现多个变量之间的关系
了解如何使用 Python 中的多元图表和绘图来呈现要素之间的关系
towardsdatascience.com](/how-to-present-the-relationships-amongst-multiple-variables-in-python-70f1b5693f5)
使用 React 实现高效的数据可视化
如何高效处理 amCharts 图表
在 Unsplash 上由 Carlos Muza 拍摄的照片
amCharts 是一个用于数据可视化的 JavaScript 库,内置了对 TypeScript 和 ES6 模块的支持。也完全兼容角度、反应、 Vue.js 。amCharts 提供了多种图表类型供选择,如这里的所示。
我已经使用 amCharts 几个月了,现在我知道它的主要优点和缺点。当用于静态图表时,简直令人惊叹。动态图表呢?
初始化 amCharts 图表需要大量的时间和资源。想象一下,每当我们需要改变可视化的数据时,例如,作为事件的结果,都要这样做。这很容易成为 web 应用程序的瓶颈,尤其是在同一个页面上有很多图表的情况下。这就是记忆发挥作用的地方!
请注意,本文的主要目的不是展示 amCharts 是如何工作的,或者什么是记忆化。这就是为什么我强烈推荐阅读 这个 和 这个 第一个。
让我们构建一个高效的 React 组件来包装任何类型的 amCharts 图表。
掌握 React 组件组成
codeburst.io](https://codeburst.io/a-complete-guide-to-props-children-in-react-c315fab74e7c)
构建图表组件
我们的通用组件可以定义如下:
[am4core.create](https://www.amcharts.com/docs/v4/reference/instance_module/#create_method)
函数返回图表实例,这允许我们操纵图表本身的行为。图表的创建,即它的初始化,应该只在组件第一次呈现时执行。否则,这个组件会变得极其低效。这就是为什么我们将初始化函数包装在一个 useMemo 回调中。这样,我们就记住了返回 char 实例的函数,只有在第一次调用组件时才会调用它。每次组件重新呈现时,都会使用chart
缓存值,避免初始化开销。
如果我们希望图表可以被操作,而不是每次都重新创建,我们需要公开它对父组件的引用。为此,我们添加了onInitialization
道具。有了它,父级可以直接在它的实例上改变图表的外观、数据和行为。
这种方法的主要优势有两个:
- 通过为每个图表类型创建一个组件来避免代码重复
- 允许父组件随时随地与图表直接交互
运行中的图表组件
假设我们想要创建一个时态演变折线图,就像这样:
用 amCharts 制作的时间演变线图
要可视化的数据将从 AJAX 调用中检索,其结果取决于用户选择的时间跨度。首先,我们来定义一下TemporalEvolutionChart
组件:
父组件负责调用检索要在图表中显示的数据,并将其传递给它。这是通过将 AJAX 调用的结果赋给图表实例的[data](https://www.amcharts.com/docs/v4/concepts/data/)
属性来实现的。 amCharts 图表会自动呈现新的数据。
瞧啊。一旦用户更改了感兴趣的时间跨度,就会发出一个 AJAX 调用(这要感谢这里引入的 API 定义层),图表也会相应地更新。这是一种非常有效的方式,不需要每次都初始化图表。
结论
在本文中,我们展示了一种使用 amCharts 和 React 的有效方法。初始化 amCharts 图表是一项耗时的操作,应仅在绝对必要时执行。这种方法是一个很好的例子,说明了如何节省资源,并防止用户因非常慢的网页而感到沮丧。感谢阅读!我希望这篇文章对你有所帮助。如有任何问题、意见或建议,请随时联系我。
熊猫中有效的欧几里德距离计算
马库斯·斯皮斯克在 Unsplash 上拍摄的照片
-一个巧妙的小把戏
在数据科学中,我们经常会遇到地理问题,比如经典的房价预测问题。在大多数情况下,作为特性工程的一部分,使用k-nearest neighborhood(k-NN)或类似策略来计算基于位置的参考价格不会有什么坏处。
k-NN 中最重要的超参数是距离度量,欧几里德距离是地理空间问题的明显选择。也称为“直线”距离或 L 范数,使用以下公式计算:
使用 k-NN 进行特征训练的问题在于,理论上,它是一个 O (n)运算:每个数据点都需要将每隔一个数据点视为潜在的最近邻。在没有像空间索引这样的专门技术的情况下,我们可以通过一些矢量化来加快速度。
让我们从一组地理空间数据点开始:
我们通常不直接从latitude
和longitude
计算欧氏距离。相反,它们被投影到地理上适当的坐标系中,其中x
和y
共享相同的单位。我将在以后的帖子中详细阐述这一点,但请注意
在地球上的大多数地方,东北纬度与经度不同。离赤道越远,这种差异就越大。
非矢量化欧几里得距离计算如下所示:
在上面的例子中,我们计算相对于第一个数据点的欧几里得距离。因为我们使用了pandas.Series.apply
,所以我们循环了data['xy']
中的每个元素。如果我们对每个数据点重复这个过程,函数euclidean
将被连续调用 n 次。我们可以通过矢量化来提高效率。
计算现在是矢量化的。但是它的可读性较差,并且有许多中间变量。有没有更干净的方法?
事实证明,高效的欧几里德距离计算的诀窍在于一个不起眼的数字函数:numpy.absolute
。
Python 的一个经常被忽视的特性是复数是内置的原语。我们可以将它们转换成复数,而不是将xy
表示为二元元组。
注意数据类型已经从object
变成了complex128
。
除非你是受过纯数学训练的人,否则你可能直到现在才意识到(像我一样)复数可以有绝对值,并且绝对值对应于离原点的欧几里得距离。应用这些知识,我们可以将代码简化为:
还有最后一个问题:如果您需要持久化您的表,复数并不容易序列化。幸运的是,把一个复数分解回它的实部和虚部并不太难。
希望你会发现这是有用的。
Pandas 数据帧上条件逻辑的高效实现
数据科学,编程,熊猫,效率
是时候停止过于依赖。iterrows()和。应用()
Python 可以说是目前最酷的编程语言(感谢机器学习和数据科学),但与最好的编程语言之一 c 相比,它的效率并不太为人所知。条件逻辑就是一个例子。当开发机器学习模型时,很常见的是,我们需要根据从统计分析或前一次迭代的结果中得出的硬编码规则,以编程方式更新标签。承认这一点并不丢人:我一直用 Pandas apply 编写代码,直到有一天我厌倦了嵌套块,于是我决定研究(也就是谷歌)替代的、更易维护和更有效的方法(也就是其他方法)
演示数据集
我们将要使用的数据集是虹膜数据集,您可以通过 pandas 或 seaborn 免费获得。
虹膜数据集的前 5 行
150 排,听起来有点业余…
150,000 行,现在我们更认真了
假设在我们的初始分析之后,我们想要用以下逻辑来标记数据集:
- 如果萼片长度< 5.1, then label 0;
- otherwise if sepal width > 3.3,萼片长度< 5.8, then label 1;
- otherwise if sepal width > 3.3,花瓣长度> 5.1,则标注 2;
- 否则,如果萼片宽度> 3.3,花瓣长度< 1.6 and either sepal length < 6.4 or petal width < 1.3, then label 3;
- otherwise if sepal width > 3.3 且任一萼片长度< 6.4 or petal width < 1.3, then label 4;
- otherwise if sepal width > 3.3,则标记为 5;
- 否则标记为 6
在深入研究代码之前,让我们快速地将新的标签列设置为 None:
iris['label'] = None
熊猫。iterrows() +嵌套的 If-Else 块
如果你还在用这个,这篇博文绝对是适合你的地方!
1min 29s ± 8.91 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
还有跑的时间…好了,我们继续…
熊猫。应用()
Pandas [.apply()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html)
直接用于沿数据帧或的轴对序列的值应用函数。例如,如果我们有一个函数 f,它对一个可迭代的数求和(即可以是一个list
、np.array
、tuple
等等)。),并将其传递给如下所示的数据帧,我们将对一行求和:
def f(numbers):
return sum(numbers)df['Row Subtotal'] = df.apply(f, axis=1)
在上面的代码片段中,axis=1
表示应用函数的方向。.apply()
会默认有axis=0
,即逐列应用该功能;而axis=1
将逐行应用该函数。
现在我们对熊猫.apply()
有了一个基本的了解,让我们编写分配标签的逻辑代码,看看它会运行多长时间:
1.43 s ± 115 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
对于 150,000 行来说,1.43 秒是一个非常大的进步,但仍然非常慢。想象一下,如果您需要处理一个包含数百万交易数据或信用审批的数据集,每次我们想要应用一组规则并将设计好的功能分配给一个列时,将会花费超过 14 秒的时间。运行足够多的专栏,你就可以在下午剩下的时间里放松下来。
熊猫。loc[]索引
如果你熟悉 SQL,用.loc[]
给一个新列赋值实际上只是一个带有大量WHERE
条件的UPDATE
语句。因此,这肯定比对每一行或每一列应用一个函数要好得多。
13.3 ms ± 837 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
现在我们花的时间只有以前的十分之一,这意味着当你在家工作时,你有更少的借口离开办公桌开始网飞。然而,我们现在只使用内置的熊猫功能。虽然 pandas 为我们提供了一个非常方便的高级接口来与数据表交互,但效率可能会因为抽象层而降低。
Numpy。哪里()
Numpy 有一个低级接口,允许与 n 维可迭代对象(即向量、矩阵、张量等)进行更有效的交互。它的方法通常是基于 C 语言的,当涉及到更复杂的计算时,它使用优化的算法,这使得它比我们重新发明的轮子要快得多。根据 numpy 的官方文档,np.where()
接受以下语法:
**np.where**(*condition, return value if True, return value if False*)
本质上,这是一个二分逻辑,其中条件将被评估为布尔值,并相应地返回值。这里的诀窍是条件实际上可以是可迭代的(即布尔 ndarray 类型)。这意味着我们完全可以将df['feature'] == 1
作为条件传入,并将 where 逻辑编码为:
**np.where**(*df['feature'] == 1**,
'It is one',
'It is not one'* )
所以你可能会问,我们如何用一个像np.where()
这样的二分法函数来实现我们上面陈述的逻辑呢?答案很简单,却令人不安。嵌套np.where()
……(剧透:这个片段可能会触发)
3.6 ms ± 149 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
恭喜,你挺过来了。我不能告诉你我花了多少时间来计算右括号,但是嘿,这就完成了任务!我们又砍掉了熊猫的 10ms。然而,这个片段是不可维护的,这意味着,它是不可接受的。
Numpy。选择()
Numpy .select()
,与.where()
不同的是,该函数旨在实现多通道逻辑。
**np.select****(***condlist***,** *choicelist***,** *default=0***)**
它使用与np.where()
相似的语法,除了第一个参数现在是一个条件列表,它应该与选项具有相同的长度。使用np.select()
时要记住的一件事是,一旦满足第一个条件,就会选择一个 选项。这意味着,如果列表中某个超集规则位于某个子集规则之前,则该子集选项将永远不会被选中。具体来说:
condlist = [
df['A'] <= 1,
df['A'] < 1
]choicelist = ['<=1', '<1']selection = np.select(condlist, choicelist, default='>1')
因为命中df['A'] < 1
的所有行也将被df['A'] <= 1
捕获,所以没有行将被标记为'<1'
。为了避免这种情况发生,请确保在制定更具体的规则之前先制定一个不太具体的规则:
condlist = [
df['A'] < 1, # < ───┬ swapped here
df['A'] <= 1 # < ───┘
]choicelist = ['<1', '<=1'] # remember to update this as well!!selection = np.select(condlist, choicelist, default='>1')
正如你从上面看到的,你将需要更新condlist
和choicelsit
来确保代码运行顺畅。但是说真的,当网飞触手可及的时候,谁有时间做这些呢?好吧,我抓住你了,伙计!通过将其更改为字典,我们将获得大致相同的时间和内存复杂度,但代码片段更易于维护:
6.29 ms ± 475 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
大约是嵌套的np.where()
的两倍,但是这不仅将你从翻表括号调试中拯救出来,而且还改变了心不在焉的choicelist
。我将是第一个咬紧牙关的人,我已经忘记更新choicelist
太多次了,我已经花了四倍多的时间来调试我的机器学习模型。相信我,np.select()
跟dict
。值得!
荣誉提名
- Numpy 的矢量化运算:如果您的代码涉及循环和评估一元函数、二元函数或对数字序列进行运算的函数。您肯定应该通过将数据转换成 numpy ndarray 来重构代码,并充分利用 numpy 的矢量化运算来极大地提高脚本的速度。结论:这是一个情境赢家!在 Numpy 的官方文档中查看 此处 的一元函数、二元函数或运算数字序列的函数示例!
**np.vectorize**
:不要被这个函数的名字所迷惑。这只是一个方便的函数,实际上并没有让代码运行得更快。要使用这个函数,您需要首先将您的逻辑编码成一个可调用的函数,然后运行np.vectorize(your_function)(your_data_series)
。另一个大的缺点是,为了传递给“矢量化”函数,您需要将数据帧转换成一维的可迭代对象。结论:如果不方便用**np.vectorize**
,想都别想。**numba.njit**
:这才是真正的业务,真正的向量化。当谈到优化循环时,没有超级天才的 hacky 移动,你根本无法轻松击败 numba。它试图将任何 numpy 评估移动到尽可能接近 C 以提高效率。虽然它可以加快数字计算的速度,但它也将自己限制在数字计算上,这意味着没有 pandas 系列,没有字符串索引,只有 numpy 的 ndarray,类型有int
、float
、datetime
、bool
和category
。结论:如果你习惯于只使用 Numpy 的 ndarray,并且把你的逻辑转换成数值计算,那么你就是一个真正的冠军。从 这里了解更多 。
你可能也喜欢这个
如果你对其他 Python 技巧感兴趣,我为你整理了一份简短博客列表:
如果你想了解更多关于 Python、数据科学或机器学习的知识,你可能想看看这些帖子:
- 改进数据科学工作流程的 7 种简单方法
- 熊猫数据帧上的高效条件逻辑
- 常见 Python 数据结构的内存效率
- 与 Python 并行
- 数据科学的基本 Jupyter 扩展设置
- Python 中高效的根搜索算法
如果你想了解更多关于如何将机器学习应用于交易和投资的信息,这里有一些你可能感兴趣的帖子:
在你走之前…
如果可能的话,去找numba.njit
;否则,np.select
带着dict
会帮你远航,我的朋友。记住,每一点点的改进都是有帮助的!如果你从这里学到了新的东西,请告诉我!也请让我知道我是否还遗漏了其他一些巧妙的技巧!
再见!
[## Louis Chan—FTI Consulting | LinkedIn 数据科学总监
雄心勃勃的,好奇的和有创造力的个人,对分支知识和知识之间的相互联系有强烈的信念
www.linkedin.com](https://www.linkedin.com/in/louis-chan-b55b9287)
深度学习中的高效推理——问题在哪里?
卷积神经网络可以为许多计算机视觉任务(如图像分类、分割和检测)提供卓越的解决方案。众所周知,神经网络模型的大小与其准确性相关。随着模型大小的增加,精确度也会增加。这可以从表 1 中看出,表 1 显示了几种已知模型在 ImageNet 分类基准测试中的最高精度:
表 ImageNet 上不同分类模型的比较。
众所周知的摩尔定律表明,硬件容量每 1.8 到 2 年翻一番。此外,根据摩尔第二定律,半导体芯片制造厂的成本每 4 年翻一番。另一方面,在 2012 年推出 AlexNet 和 2018 年推出 Alpha-Go 之间的几年里,大型 AI 系统所需的计算量每 3 到 4 个月就会翻一番!(如下图所示)。这个突出的数字意味着深度网络的加速将取决于开发轻量级和算法高效模型的能力。因此,深度学习的软件效率对于推理产生系统将是至关重要的。
图 1:按年份和所需千万亿次浮点运算量(用于训练)划分的神经网络模型。
大多数实际应用的目标是以尽可能短的运行时间获得最高的精度。这在高效深度学习领域提出了几个有趣的问题。在本帖中,我们将解决以下问题:
- 网络架构如何影响运行时间?
- 我们如何在不降低模型准确性的情况下减少运行时间?
在本文的其余部分,我们将回答这两个基本问题。
架构与推理运行时
如表 1 所示,模型越大,越精确。为了找到运行时间最短、最精确的架构,我们需要了解三个因素之间的权衡:
- 浮点运算(FLOPs)
- 运行时间
- 准确(性)
下面的数字表明,虽然这三者之间有明显的正相关,但它们并不完全相关。这可以通过图的厚度看出,图中显示,对于运行时间(或 FLOPs 数量)相同的两个网络,精度可能会有显著不同。
图 ImageNet 上运算次数(千兆次)与最高精度的对比
图 3:以毫秒为单位的网络运行时间与 ImageNet 上最高精度的对比。
为了理解 FLOPs 和运行时之间的差距,需要考虑几个参数,例如框架、硬件、架构等等。让我们看一个例子,解释为什么 FLOPs 没有一对一的精度函数。在这个例子中,我们考虑深度可分卷积(DSC),它是由 Howard et al. 引入的,用于减少深度网络的参数数量。假设我们想要应用大小为 K×K×D 的卷积核,使用 DSC,我们将滤波器分成两个独立的核:对不同通道上的相同条目进行操作的深度核,以及对同一通道中的不同条目进行操作的点状核。例如,如果我们在具有 64 个输入通道的 112 x 112 特征图上进行 3 x 3 深度方向卷积,我们执行 3 x 3 x 64 x 112 x 112 = 7,225,344 次 FLOPs。然后,我们应用可分离分量,它是使用 1 x 1 核的常规卷积。对于该操作,我们取先前的 112×112×64 大小的卷积输出,并将其投影到 128 维的特征图中;这需要 64 x 112 x 112 x 128 = 102,760,448。将两个卷积的运算次数相加得到 109,985,792 次浮点运算。相比之下,相同大小的常规 3 x 3 卷积将需要 924,844,032 次浮点运算,这几乎是 9 倍的运算量!请注意,这两个模型的表达能力是不同的。然而,使用这个想法,的原始论文,用少得多的网络参数显示了相当的准确性。这个例子清楚地展示了如何用少得多的触发器实现相当的精度。但是,手术次数只是故事的一部分。内存带宽是第二部分——但我们将在另一篇文章中讨论。
现在我们来处理第二个问题。
在保持准确性的同时减少运行时间
从模型的角度来看,在深度神经网络中建立了几个启发式算法来减少推理的运行时间。让我们简单解释一下其中的几个:
量化 —在给定模型的情况下,量化的目标是将权重映射到更小的低精度量化级别集合中。级数反映了精度,并大致反映了存储数据所需的位数(通过对级数应用 log)。在量化过程中,我们希望一方面保持模型的准确性,另一方面将模型量化到尽可能少的级别。量化的影响是双重的。首先,它允许我们用更少的比特,即更少的内存来存储模型。第二,它帮助我们用便宜得多的手术取代昂贵的手术。例如,用半精度(16 位)浮点运算替换双精度(64 位)浮点运算。这反过来使我们能够减少给定网络的推理时间。量化的好处各不相同,取决于数据、量化精度、硬件等。
修剪— 现代架构通常过度参数化。然而,这使得大量的权重在推理时是多余的。修剪指的是将这些冗余权重设置为零的过程。与量化类似,修剪的最终目标是将尽可能多的权重设置为零,同时保持准确性。剪枝后,需要对模型进行微调。虽然在某些情况下,修剪可以保持准确性,但它不能用于轻松地减少等待时间,因为权重修剪会导致权重的零星擦除,从而难以利用该结构来实现更快的矩阵乘法。此外,如果通道被修剪(即,使用通道修剪),模型精度通常会降低。
知识升华— 这个术语指的是将复杂模型(老师)学到的知识转移到更简单模型(学生)的过程。最终,学生网络可以达到如果直接在相同的数据上训练则无法达到的准确度。因此,用更简单的模型也能达到同样的精度。这通常表现为较短的运行时间。虽然这个想法听起来很吸引人,但是最近的研究表明在很多情况下这是不切实际的。
激活统计— 在现代架构中,ReLU 是使用最广泛的激活函数之一。这种激活具有独特的稀疏特性,可以用来提高效率。例如,AlexNet 的特征地图的稀疏度在 19%到 63%之间。给定这样的稀疏特征映射,可以使用更有效的实现来减少存储器访问和 FLOPs。虽然这种解决方案可以保持准确性,但其运行时间优势可能会因数据集和网络架构而恶化。
神经架构搜索— 近年来,已经进行了几次自动搜索有效架构的尝试,以减少运行时间并保持准确性。这通常是通过在所有可能的架构空间或其子集内进行启发式搜索来完成的。NASNet、EfficientNet 和 AmoebaNet 就是这种类型的一些架构。这种解决方案的主要问题是找到这样一种架构需要大量的计算。通常,这种方法需要数千小时的 GPU 来寻找最佳架构。正因如此,对于大多数深度学习从业者来说是不适用的。
结论
近年来,深度学习效率的想法越来越受欢迎。提高深度学习芯片的硬件容量有几种方法;然而,这些要么是昂贵的,要么不能超过对计算资源的需求。这一基本问题引发了对算法解决方案的需求,这些解决方案将提高与深度网络推理相关的运行时间。在这篇文章中,我们看到了一些与设计高效深度学习算法相关的解决方案和挑战。在这个广泛的研究领域,所有的方法都有利弊。因此,在不牺牲准确性的情况下加速推理是一项极具挑战性的任务。
本帖最初发表于-https://deci . ai/efficient-inference-in-deep-learning-where-the-problem/
Vespa.ai 上高效的开放领域问答
开放领域问答已经成为衡量系统阅读、表现和检索一般知识能力的基准。基于检索的问答系统需要连接各种系统和服务,如 BM25 文本搜索、向量相似性搜索、NLP 模型服务、标记器和中间件,以将所有这些结合在一起。其中大部分是 Vespa.ai 的核心功能。在本帖中,我们在 Vespa.ai 上的一个可扩展的生产就绪应用程序中重现了基于检索的问答系统的最先进基线。
由莱斯特·索尔巴肯和乔·克里斯蒂安·贝古姆拍摄。
乔恩·泰森在 Unsplash 上的照片
介绍
科学进步的一些最有效的驱动力是基准。基准测试提供了一个共同的目标,一个目的,来提高每个人都可以使用的数据集的艺术水平。排行榜额外增加了竞争动机,提供了在同行中脱颖而出的机会。竞赛增加了激励研究人员实际完成工作的截止日期,而不是无休止地修补相关指标。
在机器学习领域,基准测试对于刺激创新和进步尤为重要。一项新的竞赛 NeurIPS 2020 高效开放域问答挑战赛,旨在推动问答系统的发展。这里的目标是开发一个能够回答问题而没有任何话题限制的系统。随着自然语言处理领域的最新进展,这一领域已经成为衡量系统阅读、表示和检索一般知识能力的基准。
当前基于检索的最新技术是密集段落检索系统,如开放领域问答论文密集段落检索中所述。它由一组主要为研究开发的 python 脚本、工具和模型组成。在这样一个系统中有许多部分。其中包括两个基于 BERT 的模型,用于将文本编码为嵌入向量,另一个基于 BERT 的模型,用于提取答案,近似最近邻相似性搜索和基于文本的 BM25 方法,用于检索候选项、分词器等。将这样的系统投入生产并不容易。我们认为将这些不同的部分整合起来,并演示如何用 Vespa.ai 构建一个开放域问答服务系统,以达到最先进的准确性,这将是非常有趣的。
如果你不熟悉, Vespa.ai 是一个针对大型数据集的低延迟计算引擎。它存储和索引您的数据,以便在服务时可以高效地执行对数据的查询、选择和处理。Vespa.ai 用于各种任务,如搜索、个性化、推荐、广告、甚至寻找爱情,以及许多其他需要在查询时进行计算的应用。在任何给定时间,它每秒钟在全球范围内处理数十万个查询。
问答系统的大多数组件都是 Vespa 的核心功能。不久前,我们改进了 Vespa 对基于术语的检索和排名的文本搜索支持。我们最近添加了高效的近似最近邻,用于语义、密集向量召回。对于混合检索,Vespa 支持许多类型的机器学习模型,例如神经网络和决策森林。我们还改进了对 TensorFlow 和 PyTorch 模型的支持,以运行更大的 NLP 和 Transformer 模型。
这很有趣,因为虽然这在研究环境中有明显的好处,但这种系统的真正价值在于它们在应用中的最终用途。Vespa 被设计为高性能和可扩展的生产就绪系统。因此,它提供了在生产中部署的简化途径,而无需处理维护许多不同子系统的复杂性。这使得 Vespa 成为一个有吸引力的包装。
在这篇博文中,我们将谈到
- 语义密集向量检索的快速近似最近邻。
- 稀疏向量检索的基于术语(BM25)检索。
- 在 Vespa 中导入多个预训练的基于 BERT 的模型,用于编码嵌入向量和提取答案。
- 标记化和其他事情的定制逻辑。
有关更多详细信息,请参考配套示例应用。
这篇文章的目标是为自然问题基准重新创建密集段落检索(DPR)论文结果。我们将首先对基于检索的问答系统如何在本文的上下文中工作进行高级概述。然后,我们将展示如何在没有任何外部服务或插件的情况下在 Vespa 上实现这一切,并重现该论文的最先进结果,该结果由给定一组问题的答案的精确匹配来衡量。我们将以对未来的展望和本系列的下一篇文章结束。
背景:基于检索的问答系统的剖析
自然问题基准由自然语言问题和答案组成。如何检索和表示回答问题所需的知识取决于每个系统。有两种主要的方法:检索和参数化。基于检索的系统使用搜索词或语义表示向量来回忆一组句子或段落,随后用机器学习模型进行评估以提取精确答案。参数系统将答案或多或少地直接存储在大型神经网络模型的权重中。也有对混合检索和参数化系统的研究,如检索增强生成系统,它最近从整体上提高了自然问题基准的艺术水平。我们将在这里关注基于检索的系统,但是将在以后的博客文章中探索参数化和混合的方法。
基于检索的问答系统通常将其“知识”存储在信息检索系统中。这可以是句子、段落或整个文档。这里我们将使用维基百科数据集,其中每一页被分成 100 个单词的段落。该数据集包含 2100 万个这样的段落。回答问题时,我们首先检索最有可能包含答案的段落。然后用机器学习模型对它们进行分析,以提取最有可能导致正确反应的跨度。这些阶段分别被称为“检索者”和“读者”。
从短文中提取答案。(图片作者)
寻回犬
检索器负责生成一组候选段落。由于后续阅读器组件的评估成本很高,因此拥有有效的检索机制至关重要。有两种主要的段落检索方法:基于术语的(稀疏的)如 BM25,和嵌入的(密集的)向量,每一种都有它们的优点和缺点。
基于术语的(稀疏)检索
基于术语的检索是经典的信息检索方法,涵盖了 TF-IDF 和 BM25 等算法。从概念上讲,文本由一个向量表示,其中每个维度代表词汇表中的一个术语。非零值表示它的存在。由于每个文本只包含词汇表中可能术语的子集,这些向量很大而且很稀疏。对于 TF-IDF 或 BM25,可以通过稀疏向量之间的点积来计算两个文本(例如,文档和查询)之间的相似性,其中对稀疏向量稍作修改(例如,术语重要性)。基于术语的方法依赖于倒排索引结构来进行有效的检索。在某些情况下,这可以通过 WAND 等算法进一步加速。
除了词汇化、词干提取和可能的停用词删除等预处理之外,术语与文本中找到的完全匹配。这可能是优点,也可能是缺点。对于非常突出的术语,例如姓名和地点,这大大缩小了搜索空间。然而,不包含确切术语的潜在相关文档将不会被检索到,除非使用查询扩展或相关技术。密集段落检索(DPR)论文使用 ElasticSearch 作为 BM25 的提供系统。
基于嵌入(密集)的检索
词汇表中潜在术语的数量可能非常巨大。嵌入向量背后的基本思想是将这个非常高维的稀疏向量压缩成一个非常小的密集向量,其中大多数维度包含非零值。这具有将查询或文档向量投射到低维空间的效果。可以这样做,使得几何上接近的向量在语义上也是接近的。DPR 的论文使用了两种 BERT 模型来编码文本:一种用于编码查询,另一种用于编码文档。在双塔配置中同时训练这两个模型,以最大化可能回答问题的段落的点积。
与稀疏表示相反,没有精确的方法来有效地找到最近的邻居。因此,我们在所谓的近似最近邻(ANN)中用准确性换取效率。已经提出了许多不同的人工神经网络搜索方法。有些与倒排索引结构兼容,因此它们可以很容易地在现有的信息检索系统中实现。例如 k-means 聚类、乘积量化(及其相关)和位置敏感散列,其中质心或桶可以被索引。与倒排索引不兼容的一种方法是 HNSW (分层可导航小世界)。HNSW 基于图结构,非常高效,并且有一个吸引人的特性,即图可以在运行时增量构建。这与大多数其他需要离线、面向批量索引构建的方法形成对比。
基于语义嵌入的检索很好地补充了基于术语的检索。语义相似的文档可以被召回,即使它们不包含完全相同的术语。与基于术语的检索的单词包方法不同,词序可以提供额外的上下文。然而,从历史上看,在问答问题上,基于术语的检索优于语义嵌入,但 DPR 的论文表明,如果编码经过专门训练,密集检索可以得到极大改善。DPR 的论文使用带有 HNSW 索引的 FAISS 进行相似性搜索。
朗读者
虽然检索器组件的工作是产生一组候选段落,这些段落有希望包含问题的答案,但是阅读器提取这些段落的实际答案。这需要某种形式的自然语言理解模型,使用的就是 BERT(或其他 Transformer)模型。这些模型通常很大,评估起来很昂贵,所以只有少量的候选段落通过它们。
转换器模型将令牌序列作为输入。文本的标记化可以通过几种不同的方式来平衡词汇大小和序列长度。由于 BERT 模型的完全注意机制,评估时间随着序列长度的增加而二次增加。因此,必须找到一个合理的平衡,基于 BERT 的模型使用一个单词块或类似的算法将不常用的单词分成子单词。
读者模型的输入是表示问题、文档标题和段落本身的标记的串联。该模型查找每个标记的嵌入表示,并通过一系列层,为每个标记产生新的表示。这些表示可以用于不同的任务。对于问答,添加了一个附加层来计算三个必要的输出:文章与问题的相关性,以及答案的开始和结束索引。
回答问题的伯特(图片作者
为了提取最终答案,使用产生最大相关性分数的段落。该模型的另外两个输出是每个标记成为开始标记和结束标记的概率。通过找到开始概率和结束概率之和最大的区间来选择最终答案。这会产生一个标记序列,在返回之前,标记器必须将其转换为单词。DPR 论文使用基于 BERT 的模型来输出跨度预测。
把这些放在一起
如上所述的基于检索的问答系统,能够进行基于术语和基于嵌入的检索,至少需要以下组件:
- BM25 信息检索系统存储了 2100 万条维基百科文本。
- 存储段落嵌入向量的高效向量相似性搜索系统。
- 一个模型服务系统,用于三种不同的基于 BERT 的模型:查询编码器、文档编码器和读者模型。
- 一个基于 BERT 的标记器。
- 中间件将这一切粘合在一起。
记号赋予器为文本生成记号序列。这些令牌被存储以供在读取器模型中使用。它们还被用在基于 BERT 的文档编码器模型中,以创建用于密集检索的嵌入向量。为了快速检索,需要对文本和嵌入向量进行索引。
每个查询都遵循类似的过程。记号赋予器产生一个记号序列,用来在基于查询 BERT 的编码器中产生一个嵌入向量。第一阶段,检索,是使用基于术语的检索或基于嵌入的检索来完成的。前 N 篇文章被传递给读者模型并相应地排序。分析最佳段落以提取包含答案的最佳跨度。
这是实现问答系统需要设置的一系列服务。在下一节中,我们将展示如何在一个 Vespa 应用中实现所有这些功能。
在 Vespa 上复制基线
上面提到的大部分组件都成为了 Vespa 中的核心功能。在下文中,我们将介绍如何在 Vespa 中进行设置。详情可参见配套示例应用。
(计划或理论的)纲要
使用 Vespa 创建应用程序时,通常从文档模式开始。该模式包含每个文档应该存储哪些数据的定义。在我们的例子中,每个文档都是维基百科数据集中的一段。因此,我们建立了一个模式,允许我们已经讨论过的不同检索方法:
- 稀疏检索使用传统的 BM25 基于术语的检索。
- 密集检索使用经过训练的模型编码的矢量表示。
- 混合检索使用上述的组合。
我们在一个文档模式中设置了所有这些:
schema wiki {
document wiki { field title type string {
indexing: summary | index
} field text type string {
indexing: summary | index
} field title_token_ids type tensor(d0[256]) {
indexing: summary | attribute
} field text_token_ids type tensor(d0[256]) {
indexing: summary | attribute
} field text_embedding type tensor(x[769]) {
indexing: attribute | index
attribute {
distance-metric: euclidean
}
}
}
}
这里,每个段落的标题和文本内容都由一个字符串和一个令牌序列字段表示。字符串字段被索引以支持 BM25 并支持 WAND 以加速检索。令牌序列被表示为张量,并被用作阅读器模型的输入。
标题和文本的嵌入向量被预先计算并存储为张量。该向量用于密集检索,因此我们在该字段上启用 HNSW 索引用于近似最近邻匹配。Vespa 一个很好看的特点就是 HNSW 索引不是离线预建的;它是随着数据被索引而在线构建的。这使得应用程序能够对输入系统的新数据做出更快的响应。
检索和排序
其中,Vespa 中的查询定义了 Vespa 应该如何召回文档(称为匹配阶段)以及 Vespa 应该如何对文档进行评分(称为排序阶段)。Vespa 提供了丰富的查询 API ,其中查询是用Vespa YQL 语言指定的。由于不同的检索策略(基于术语的和基于嵌入的)具有不同的查询语法,我们构建了一个定制的搜索器组件,它允许我们构建一个统一的搜索界面,并且只将实际的问题和检索策略作为参数传递。这简化了方法之间的比较。
检索策略在回忆内容和评分方式上都有所不同。在 Vespa 中,使用在文档模式中配置的等级表达式来表示得分。Vespa 支持多阶段排名,我们在这里利用了这一点,因此第一阶段代表检索者,第二阶段代表读者。我们设置了第一阶段的等级配置文件,如下所示:
rank-profile sparse inherits openqa {
first-phase {
expression: bm25(text) + bm25(title)
}
}
rank-profile dense inherits openqa {
first-phase {
expression: closeness(field, text_embedding)
}
}
rank-profile hybrid inherits openqa {
first-phase {
expression: 1000*closeness(field, text_embedding) + bm25(text) + bm25(title)
}
}
这里,我们设置了三个排序配置文件,一个用于稀疏检索,一个用于密集检索,一个用于混合检索。稀疏排名简档使用针对查询的标题和文本字段的 BM25 分数作为评分函数。密集简档使用接近度,例如查询和文档嵌入字段之间的欧几里德距离。混合概要文件是一个将两者结合起来进行混合检索的例子。第一阶段代表取回者。
对于读者模型,我们设置了基本配置文件 openqa ,它引入了检索策略之间的第二个共同阶段:
onnx-model reader {
file: files/reader.onnx
input input_ids: input_ids
input attention_mask: attention_mask
output output_0: start_logits
output output_1: end_logits
output output_2: relevance_logits
}rank-profile openqa {
second-phase {
rerank-count: 10
expression: onnxModel(reader).relevance_logits
}
summary-features {
onnxModel(reader).start_logits
onnxModel(reader).end_logits
}
}
这里,前 10 个文档由 reader 模型重新排序,这是 onnxModel rank 特性定义的。我们使用的实际模型是 DPR 团队在 HuggingFace 的模型库上发布的预训练模型。HuggingFace 发布了一款优秀的变压器模型导出,可以轻松将变压器模型(从 PyTorch 或 TensorFlow)导出为 ONNX 格式。在将模型导出到 ONNX 之后,我们可以将模型文件放在应用程序包中,并配置它在文档模式中的使用,如上所示。为了达到这个规模,Vespa 将这个模型分发到集群中的所有内容节点。因此,在排序期间,在内容节点上评估模型,避免将数据传输到外部模型服务。
读者模型有三个输出,其中 relevance_logits 输出用于评分。另外两个分别表示每个记号作为问题最终答案的开始或结束记号的概率。这些由定制的搜索器拾取,并且这些字段代表的实际跨度在那里被提取。
该应用程序包含一个额外的模型,即用于在运行时为查询生成嵌入向量的问题编码器模型。来自维基百科数据集的预先计算的文档嵌入由脸书研究所发布。我们直接使用这些嵌入。
Vespa 容器中间件——将所有这些放在一起
该应用程序具有以下在 Vespa 容器中作为 Java 实现的自定义插件:
- 一个 BERT 记号赋予器组件,负责从文本中生成 BERT 记号序列。
- 一种在索引过程中使用 BERT 符号化的定制文件处理程序。
- 一个定制的搜索器,为调用 BERT 问题编码器模型的查询检索嵌入表示。
- 控制检索逻辑的自定义搜索器(例如,稀疏、密集或混合)。
- 一个自定义搜索器,它读取阅读器模型的输出,提取最匹配的答案范围,并将该令牌序列转换为返回给用户的实际文本。
结果是一个服务,它接受一个文本问题并返回预测的答案,所有这些都在一个 Vespa 应用程序中。
数据和对数据的计算(例如 ML 模型评估)被分布到所有内容节点。自定义处理发生在无状态容器上。(图片作者)
结果
我们在这个应用程序中使用的基准是自然问题数据集。本节中的所有实验都是通过查询 Vespa 实例并检查黄金参考答案的预测答案来运行的。
寻回犬准确度总结
我们使用 Recall@position 作为检索者的主要评估指标。寻回犬的明显目标是在尽可能低的位置获得尽可能高的回忆。由于使用基于 BERT 的阅读器对最终的顶级段落进行重新排序,因此我们需要评估的段落越少,运行时间复杂度和性能就越好。
下表总结了使用开放领域问答任务的自然问题中的原始 3610 个 dev 问题的检索器准确性( NQ-open.dev.jsonl )。
检索准确性
DPR 论文报告召回 79.4 的@20,因此我们的结果与他们报告的密集检索方法的结果一致。我们将这种细微的差异归因于 HNSW 指数的不同设置。
阅读器准确度总结
我们使用精确匹配(EM)指标来评估阅读器的准确性。精确匹配指标衡量与任何一个基本事实答案精确匹配的预测的百分比。要使查询的 EM 分数为 1,答案预测必须与数据集中给出的最佳答案完全匹配。这很有挑战性。例如,“最后一次登月是什么时候?”有黄金答案“1972 年 12 月 14 日 UTC”或“1972 年 12 月”,预测答案“1972 年 12 月 14 日”将被评分为 0。
结果与上面的数据集相同,检索器对前 10 个结果进行了重新排序:
阅读器准确度
以上结果重现了 DPR 论文的结果,该论文是基于检索的系统的当前技术状态。
进一步的工作
在这篇博文中,我们一直专注于在 Vespa 的一个实例中重现 DPR 论文的结果。在本系列的下一部分中,我们将介绍一个更复杂的混合模型,并展示如何使用其他模型类型来提高准确性。我们将发表另一篇文章,讨论如何将总系统延迟降低到更合理的水平,同时衡量这对准确性的影响。
敬请期待!
使用 Lambda、Map、Filter 和 Sorted 进行高效的 Python 编程
使用数字、字符串和字典列表的快乐编程
一些内置函数,比如 lambda 函数,可以以更简洁的方式修改列表。我喜欢使用 lambdas,因为我可以用更少的代码编写程序,并且仍然清晰易懂。另外,它不会使你的程序变慢。
下面是语法:
lambda x,…. : expression
我在 x 后面加了几个点来象征更多的争论。
Lambdas 可以接受任意数量的参数,但只能接受一个表达式。
Lambda 用于匿名函数,即没有名称的函数。我们使用“def”来定义 python 函数。但是当我们使用 lambda 时,我们可以不使用' def '来创建函数。如果要保存,一个变量就够了。
让我们看一些例子。这个函数有一个参数 x,返回 x 的平方。
def squared(x):
return x*x
现在用 lambda 写同样的函数。
squared = lambda x: x*x
两个平方函数的工作方式完全相同。
现在来看一个简单的加法函数,它接受两个参数 x 和 y,并返回它们的和:
add = lambda x, y: x+y
使用 lambda 不是更简洁吗?它节省了额外的一行。
调用函数“add”并向其传递两个整数。
add(4, 5)
输出:
9
在处理列表时,它看起来会更有效率!
地图
Python 中的 Map 函数接受列表和函数,并返回由函数修改的列表。让我们来看一些例子。这里有三个列表 a,b,c。
a = [3,4,5,2,7,8]
b = [7,9,2,4,5,1]
c = [5,7,3,4,5,9]
在列表 a 和 b 上调用 add 函数:
add(a,b)
输出:
[3, 4, 5, 2, 7, 8, 7, 9, 2, 4, 5, 1]
这没有给出元素方面的增加。当你简单地添加到列表中时,它们只是连接在一起。它只是创建了一个更大的列表,包含了两个列表中的所有元素
通常,我们对两个相同大小的列表进行元素相加的方法是使用“for 循环”,如下所示:
res = []
for i in range(0, len(a)):
res.append(a[i]+ b[i])res
输出:
[10, 13, 7, 6, 12, 9]
我不得不写三行代码来添加两个列表。现在,让我们使用“map”用一行代码来完成它。
使用“map ”,您可以调用我们之前在列表 a 和 b 上定义的 add 函数来获得元素相加。它的工作方式完全类似于“for 循环”,并给出相同的输出。
list(map(add, a, b))
输出:
[10, 13, 7, 6, 12, 9]
是不是简洁优雅了很多?
让我们总结一下我们所做的。我们首先定义了一个名为“add”的函数,然后使用一个“map”函数来获得两个列表的元素范围的相加。我们能做得更好吗?
是啊!我们可以在同一行代码中调用' add '函数。
list(map(lambda x, y: x+y, a, b))
输出:
[10, 13, 7, 6, 12, 9]
我们在这里做的是,
- 我们用 lambda 定义了一个函数,它有两个参数 x 和 y。
- 向函数传递了两个列表 a 和 b。
- 使用地图,因为 a 和 b 是列表。我们想要 a 和 b 的元素相加。
事实上,您可以添加所有三个列表或任意数量的参数:
list(map(lambda x, y, z: x+y+z, a, b, c))
输出:
[15, 20, 10, 10, 17, 18]
如果你有一个包含三个参数的公式,而不是简单的加法:
list(map(lambda x, y, z: 2*x + 2.5*y + z, a, b, c))
输出:
[28.5, 37.5, 18.0, 18.0, 31.5, 27.5]
过滤器
过滤器将列表作为参数,将函数作为表达式。它在通过函数过滤掉元素后返回修改后的列表。这里有一些例子。
只返回列表中大于 5 的数字。在此之前,制作一个新列表 c:
c = [4,2,9,6,10,4,1]
list(filter(lambda x: x > 5, c))
输出:
[9, 6, 10]
在这里,我定义了返回大于 5 的数字的函数,并将列表 c 作为参数。看,它返回了所有大于 5 的 c 元素。
让我们来看另一个例子。只返回列表中的偶数。这一次,我将传递列表 a。
a = [3,4,5,2,7,8]
list(filter(lambda x: x % 2==0, a))
输出:
[4, 2, 8]
我们也可以在字符串上使用 lambda 和 filter。
上面所有的例子都有数字。接下来的几个例子是关于字符串的。这是一份名单:
names = [‘Abram’, ‘Arib’, ‘Bob’, ‘Shawn’, ‘Aria’, ‘Cicilia’, ‘John’, ‘Reema’, ‘Alice’, ‘Craig’, ‘Aaron’, ‘Simi’]
返回所有以 will 'A '开头的名字。
list(filter(lambda x: x[0]==’A’, names))
输出:
['Abram', 'Arib', 'Aria', 'Alice', 'Aaron']
分类的
sorted 函数是一种非常简单、容易的按字母排序数字或字符串的方法。以下是一些例子:
按名字的第一个字母对上面列表中的名字进行排序。
sorted(names, key=lambda x: x[0])
输出:
[‘Abram’, ‘Arib’, ‘Aria’, ‘Alice’, ‘Aaron’, ‘Bob’, ‘Cicilia’, ‘Craig’, ‘John’, ‘Reema’, ‘Shawn’, ‘Simi’]
太棒了!但是一个更简单的选择是:
sorted(names)
输出:
[‘Aaron’, ‘Abram’, ‘Alice’, ‘Aria’, ‘Arib’, ‘Bob’, ‘Cicilia’, ‘Craig’, ‘John’, ‘Reema’, ‘Shawn’, ‘Simi’]
这样,名字就按字母顺序排列了。同样的事情也适用于列表。
sorted(c)
输出:
[1, 2, 4, 4, 6, 9, 10]
λ、映射、过滤和用字典排序
使用 lambda、map、filter 和 sorted 来处理字典要简单和高效得多。
这是一个有四本字典的列表。每本词典都包括一个人的名字和他或她的年龄。
dict_a = [{'name': 'John', 'age': 12},{'name': 'Sonia', 'age': 10},{'name: 'Steven', 'age': 13},{'name': 'Natasha', 'age': 9}]
仅返回上面列表中的姓名列表:
list(map(lambda x: x['name'], dict_a))
输出:
['John', 'Sonia', 'Steven', 'Natasha']
同样,您可以只从 dict_a 中输出年龄:
list(map(lambda x: x['age'], dict_a))
输出:
[12, 10, 13, 9]
如果您希望姓名按字母排序或“年龄”列表按字母排序,只需在前面加一个 sorted:
sorted(list(map(lambda x: x['age'], dict_a)))
输出:
[9, 10, 12, 13]
你可能会想,把整本字典按年龄分类会更有用。在这种情况下,我们只需要使用 lambda 的密钥:
sorted(dict_a, key=lambda x: x['age'])
输出:
[{'name': 'Natasha', 'age': 9},{'name': 'Sonia', 'age': 10},{'name': 'John', 'age': 12},{'name': 'Steven', 'age': 13}]
输出最小的孩子的信息:
sorted(dict_a, key=lambda x: x['age'])[0]
输出:
{'name': 'Natasha', 'age': 9}
输出最大的孩子的信息:
sorted(dict_a, key=lambda x: x['age'])[-1]
输出:
{‘name’: ‘Steven’, ‘age’: 13}
如果我们需要列表以降序排列,而不是升序排列:
sorted(dict_a, key=lambda x: x['age'], reverse =True)
输出:
[{'name': 'Steven', 'age': 13},{'name': 'John', 'age': 12},{'name': 'Sonia', 'age': 10},{'name': 'Natasha', 'age': 9}]
或者,如果您想按字母顺序对姓名进行排序:
sorted(dict_a, key=lambda x: x['name'])
输出 10 岁以上儿童的信息:
list(filter(lambda x: x['age'] > 10, dict_a))
输出:
[{'name': 'John', 'age': 12},{'name': 'Steven', 'age': 13}]
三年后,你又回到了孩子们的年龄。所以,每个年龄加 3 就行了:
list(map(lambda x: x['age']+3, dict_a))Output: [15, 13, 16, 12]
结论
我希望本教程有助于提高您的 python 编程。
以下是 YouTube 上的视频教程:
欢迎在推特上关注我,喜欢我的 T2 脸书页面。
更多阅读:
当你在寻找一个范围而不是一个确切的数值,一个等级而不是一个分数
towardsdatascience.com](/sort-and-segment-your-data-into-bins-to-get-sorted-ranges-pandas-cut-and-qcut-7785931bbfde) [## Numpy 完全指南
日常工作中需要的所有数字方法
towardsdatascience.com](/a-complete-guide-to-numpy-fb9235fb3e9d) [## Python Matplotlib 的日常备忘单
完整的可视化课程
towardsdatascience.com](/your-everyday-cheatsheet-for-pythons-matplotlib-c03345ca390d) [## Python 中的线性回归算法:一步一步
学习线性回归的概念,并使用 python 从头开始开发一个完整的线性回归算法
towardsdatascience.com](/basic-linear-regression-algorithm-in-python-for-beginners-c519a808b5f8) [## Pandas 的 Groupby 功能详细,可进行高效的数据汇总和分析
学习对数据进行分组和汇总,以使用聚合函数、数据转换、过滤、映射、应用函数…
towardsdatascience.com](/master-pandas-groupby-for-efficient-data-summarizing-and-analysis-c6808e37c1cb) [## 学习使用 Python 的 Scikit_learn 库通过项目开发 KNN 分类器
适合机器学习新手
towardsdatascience.com](/clear-understanding-of-a-knn-classifier-with-a-project-for-the-beginners-865f56aaf58f)
高效 PyTorch —消除瓶颈
什么是高效的 PyTorch 培训渠道?它是产生具有最佳精确度的模型的那个吗?还是跑得最快的那个?还是容易理解和扩展的那个?可能是容易平行的那种?以上都是。
哈里·谢尔顿在 Unsplash 上拍摄的照片
PyTorch 是一款用于研究和生产领域的优秀工具,斯坦福大学、Udacity、SalelsForce、Tesla 等都采用了这一深度学习框架,这清楚地表明了这一点..然而,每种工具都需要投入时间来掌握技能,以便最有效地使用它。在使用 PyTorch 两年多后,我决定总结一下我使用这个深度学习库的经验。
高效的—(指系统或机器)以最少的浪费努力或费用获得最大的生产率。(牛津语言)
高效 PyTorch 系列的这一部分给出了识别和消除 I/O 和 CPU 瓶颈的一般技巧。第二部分将揭示一些关于有效张量运算的技巧。第三部分——高效的模型调试技术。
免责声明:这篇文章假设你至少对 PyTorch 有所了解。
我将从最明显的一个开始:
Roshni Sidapara 在 Unsplash 上拍摄的照片
建议 0: 知道代码中的瓶颈在哪里
命令行工具,如[nvidia-smi](https://developer.nvidia.com/nvidia-system-management-interface)
、[htop](https://hisham.hm/htop/)
、[iotop](https://linux.die.net/man/1/iotop)
、[nvtop](https://github.com/Syllo/nvtop)
、[py-spy](https://pypi.org/project/py-spy/)
、[strace](https://strace.io/)
等..应该成为你最好的朋友。您的培训渠道是否受限于 CPU?IO 绑定?GPU 绑定?这些工具将帮助你找到答案。
你可能甚至没有听说过它们,或者听说过但没有使用过。没关系。如果你没有立即开始使用它们也没关系。请记住,其他人可能会用它们来训练 5%-10%-15%的模型..比你更快,这最终可能会决定你是赢得还是失去市场,或者在工作岗位上获得批准还是拒绝。
数据预处理
几乎每个培训渠道都从Dataset
班开始。它负责提供数据样本。任何必要的数据转换和扩充都可以在这里进行。简而言之,Dataset
是一个抽象,它报告其大小,并根据给定索引返回数据样本。
如果您正在处理类似图像的数据(2D、3D 扫描),磁盘 I/O 可能会成为瓶颈。要获得原始像素数据,您的代码需要从磁盘读取数据,并将图像解码到内存中。每个任务都很快,但是当您需要尽可能快地处理成千上万的任务时,这可能会成为一个挑战。像 NVidia Dali 这样的库提供了 GPU 加速的 JPEG 解码。如果您在数据处理管道中面临 IO 瓶颈,这绝对值得一试。
还有一个选择。SSD 磁盘的访问时间约为 0.08–0.16 毫秒。RAM 的访问时间为纳秒。我们可以将数据直接存入内存!
建议 1: 如果可能的话,把你的数据全部或者部分移动到 RAM 。
如果您有足够的 RAM 来加载并在内存中保存所有的训练数据,这是从管道中排除最慢的数据检索步骤的最简单方法。
这个建议对云实例特别有用,比如亚马逊的p3.8xlarge
。这个实例有 EBS 磁盘,对于默认设置,它的性能非常有限。然而,这个实例配备了惊人的 248Gb 内存。这足以在内存中保存所有 ImageNet 数据集!你可以这样做:
我亲自面对了这个瓶颈问题。我有一台配备 4x1080Ti GPUs 的家用 PC。有一次,我拿了一个有四个 NVidia Tesla V100 的p3.8xlarge
实例,并把我的训练代码移到那里。鉴于 V100 比我的老款 1080Ti 更新更快,我预计训练速度会提高 15-30%。当每个时期的训练时间增加时,我感到很惊讶!这是我的教训,要注意基础设施和环境的细微差别,而不仅仅是 CPU 和 GPU 的速度。
根据您的情况,您可以在 RAM 中保持每个文件的二进制内容不变,并“即时”解码,或者解压缩图像并保留原始像素。但是无论你选择哪条路,这里有第二条建议:
忠告二:简介。测量。比较一下。每次你对渠道进行任何改变时,都要仔细评估它会产生什么样的整体影响。
这个建议只关注训练速度,假设你没有引入模型、超参数、数据集等的变化..您可以有一个神奇的命令行参数(神奇的开关),当指定时,它将为一些合理数量的数据样本运行训练。有了这一功能,您可以随时快速分析您的管道:
# Profile CPU bottlenecks
python -m cProfile training_script.py --profiling# Profile GPU bottlenecks
nvprof --print-gpu-trace python train_mnist.py# Profile system calls bottlenecks
strace -fcT python training_script.py -e trace=open,close,read
建议 3: 离线预处理一切
如果您正在对 512x512 大小的图像进行训练,这些图像是由 2048x2048 图片组成的,请事先调整它们的大小。如果您使用灰度图像作为模型的输入,请离线进行颜色转换。如果您正在进行 NLP —预先进行标记化并保存到磁盘。在训练中一遍又一遍地重复同样的操作是没有意义的。在渐进式学习的情况下,您可以保存多种分辨率的训练数据,这仍然比在线调整到目标分辨率要快。
对于表格数据,考虑在Dataset
创建时将pd.DataFrame
对象转换为 PyTorch 张量。
建议 4: 调整数据加载器的工作线程数量
PyTorch 使用 DataLoader 类来简化为训练模型而生成批处理的过程。为了加快速度,它可以使用 python 的多处理并行处理。大多数情况下,它开箱即可正常工作。有几件事要记住:
每个进程生成一批数据,这些数据通过互斥同步提供给主进程。如果您有 N 个工作线程,那么您的脚本将需要 N 倍多的 RAM 来在系统内存中存储这些批处理。你到底需要多少内存?
我们来计算一下:
- 假设我们为批量大小为
32
的城市风景和大小为512x512x3 (height, width, channels)
的 RGB 图像训练图像分割模型。我们在 CPU 端进行图像标准化(稍后我会解释为什么它很重要)。在这种情况下,我们最终的图像张量将是512 * 512 * 3 * sizeof(float32) = 3,145,728
字节。乘以批处理大小,我们得到100,663,296
字节,或者大约 100 Mb。 - 除了图像,我们还需要提供真实的面具。它们各自的大小是(默认情况下,masks 的类型是 long,8 字节)——
512 * 512 * 1 * 8 * 32 = 67,108,864
或者大约 67 Mb。 - 因此,一批数据所需的总内存为
167 Mb
。如果我们有 8 个工人,所需的内存总量将是167 Mb * 8 = 1,336 Mb.
听起来不算太糟,对吧?当您的硬件设置能够处理的批处理数量超过 8 个工作线程所能提供的数量时,就会出现问题。人们可以天真地放置 64 个工人,但这至少会消耗将近 11 Gb 的 RAM。
如果你的数据是 3D 体积扫描,事情会变得更糟;在这种情况下,即使是单通道卷512x512x512
的一个样本也将占用 134 Mb,对于批量大小 32,它将是 4.2 Gb,对于 8 个工人,您将只需要 32 Gb 的 RAM 来在内存中保存中间数据。
这个问题有一个部分的解决方案,您可以尽可能地减少输入数据的通道深度:
- 将 RGB 图像保持在每通道 8 位深度。图像转换为浮点和归一化可以很容易地在 GPU 上完成。
- 在数据集中使用 uint8 或 uint16 数据类型,而不是 long。
通过这样做,您可以大大降低 RAM 需求。对于上面的例子,内存高效数据表示的内存使用量将是每批 33 Mb,而不是 167 Mb。那就是 5 倍还原!当然,这需要模型本身的额外步骤来将数据规范化/转换为适当的数据类型。然而,张量越小,CPU 到 GPU 的传输时间就越快。
应该明智地选择DataLoader
的工人数量。您应该检查您的 CPU 和 IO 系统有多快,您有多少内存,以及 GPU 处理这些数据的速度有多快。
多 GPU 训练和推理
神经网络模型变得越来越大。如今的趋势是使用多个 GPU 来增加训练时间。幸运的是,它还经常提高模型的性能,使批量更大。PyTorch 拥有在几行代码内实现多 GPU 的所有特性。然而,有些警告乍一看并不明显。
model = nn.DataParallel(model) # Runs model on all available GPUs
使用多 GPU 最简单的方法是在nn.DataParallel
类中包装一个模型。在大多数情况下,它工作得很好,除非你训练一些图像分割模型(或任何其他产生大尺寸张量作为输出的模型)。在正向传递结束时,nn.DataParallel
将从主 GPU 上的所有 GPU 收集输出,以反向运行输出并进行梯度更新。
有两个问题:
- GPU 负载不平衡
- 在主 GPU 上采集需要额外的视频内存。
首先,只有主 GPU 在进行损失计算、反向传递和梯度步骤,而其他 GPU 在 60C 下等待下一批数据。
其次,在主 GPU 上收集所有输出所需的额外内存通常会迫使您减少批量大小。事情是这样的,nn.DataParallel
在 GPU 之间平均分割批处理。假设您有 4 个 GPU,总批量为 32。然后,每个 GPU 将获得其 8 个样本的块。但问题是,虽然所有非主 GPU 都可以轻松地将这些批处理放入其相应的 VRAM 中,但主 GPU 必须分配额外的空间来容纳来自所有其他卡的输出的 32 个批处理大小。
对于这种不均衡的 GPU 利用率,有两种解决方案:
- 继续使用
nn.DataParallel
并在训练中计算向前传球的损失。在这种情况下,您不会将密集预测掩码返回给主 GPU,而是只返回一个标量损失。 - 使用分布式训练,又名
nn.DistributedDataParallel
。在分布式培训的帮助下,您可以解决上述两个问题,并享受观看所有 GPU 100%加载的乐趣。
如果您知道要了解更多关于多 GPU 培训的信息,并深入了解每种方法的优缺点,请查看这些精彩的帖子以了解更多信息:
- https://medium . com/hugging face/training-large-batches-practical-tips-on-1-GPU-multi-GPU-distributed-settings-EC 88 C3 e 51255
- https://medium . com/@ the accelerators/learn-py torch-multi-GPU-proper-3eb 976 c 030 ee
- https://towards data science . com/how-to-scale-training-on-multi-GPU-DAE 1041 f 49d 2
建议 5: 如果你有 2 个以上的 GPU,考虑使用分布式训练模式
它将节省多少时间在很大程度上取决于您的场景,但我观察到,当在 4x1080Ti 上训练图像分类管道时,时间减少了约 20%。
同样值得一提的是,您也可以使用nn.DataParallel
和nn.DistributedDataParallel
进行推理。
关于自定义损失函数
编写自定义损失函数是一项有趣且令人兴奋的工作。推荐大家不定期尝试一下。在用复杂的逻辑实现损失函数时,有一件事你必须记住:它都运行在 CUDA 上,你有责任编写 CUDA 高效的代码。CUDA-efficient 的意思是“没有 python 控制流”。在 CPU 和 GPU 之间来回切换,访问 GPU 张量的单个值可能会完成工作,但性能会很糟糕。
前一段时间,我实现了一个定制的余弦嵌入损失函数,用于实例分割,来自“使用余弦嵌入和递归沙漏网络分割和跟踪细胞实例”的论文。它的文本形式非常简单,但是实现起来有点复杂。
我写的第一个天真的实现(除了 bug)花了几分钟(!)来计算单个批次的损失值。为了分析 CUDA 瓶颈,PyTorch 提供了一个非常方便的内置分析器。它使用起来非常简单,并且为您提供了解决代码瓶颈的所有信息:
建议 9: 如果您正在设计定制模块&损耗—剖析&测试它们
在对我的初始实现进行概要分析之后,我能够将我的实现速度提高 100 倍。关于用 PyTorch 编写高效张量表达式的更多内容将在高效 PyTorch —第 2 部分中解释。
时间与金钱
帕特里克·福尔在 Unsplash 上拍摄的照片
最后但同样重要的一点是,有时投资于更强大的硬件比优化代码更有价值。软件优化永远是一个高风险的旅程,有不确定的结果。升级 CPU、RAM、GPU 或全部一起升级可能更有效。金钱和工程时间都是资源,正确利用二者是成功的关键。
建议 10: 一些瓶颈可以通过硬件升级更容易地解决
结论
充分利用你的日常工具是精通的关键。试着不要走捷径,如果有些事情你不清楚,一定要深入挖掘。总有机会获得新知识。问问你自己或你的伙伴——“我的代码如何改进?”。我真的相信,对于计算机工程师来说,这种完美感和其他技能一样重要。
Eugene 是计算机视觉和机器学习工程师,拥有超过 10 年的软件开发经验。《掌握 OpenCV 用于实用计算机视觉项目》一书的作者。卡格尔大师。白蛋白核心团队成员。《pytorch-toolbelt 的作者。OpenCV、PyTorch 和 Catalyst 贡献者。https://www.linkedin.com/in/cvtalks/
高效 py torch——增压培训管道
为什么只报告你的模型的最高精度通常是不够的。
将你的 train.py 脚本转化为具有一些额外特性的强大管道(照片由 Nur Faizin 在 Unsplash 上拍摄)
每一个深度学习项目的最终目标都是为产品带来价值。当然,我们希望有最好的模型。什么是“最好的”——取决于特定的用例,我将在这篇文章中不讨论这个问题。我想谈谈如何从您的 train.py 脚本中获得最大收益。
在本帖中,我们将介绍以下技巧:
- 相反,高级框架自己制造了训练循环
- 使用其他指标监控培训进度
- 使用张量板
- 可视化模型的预测
- 使用 Dict 作为数据集和模型的返回值
- 检测异常并解决数值不稳定性
免责声明:在下一节中,我将包括一些源代码清单。它们中的大多数是为 Catalyst 框架(版本 20.08)定制的,并且在 pytorch-toolbelt 中可用。
不要重新发明轮子
建议 1 —利用 PyTorch 生态系统的高级培训框架
PyTorch 在从头开始编写训练循环时提供了极好的灵活性和自由度。理论上,这为编写任何训练逻辑提供了无限的可能性。在实践中,你很少会为训练 CycleGAN、提取 BERT 或从头实现 3D 对象检测编写奇异的训练循环。
从头开始编写一个完整的训练循环是学习 PyTorch 基础知识的极好方法。然而,我强烈建议,一旦你有所领悟,就转向高级框架。选项很多:触媒、 PyTorch-Lightning 、 Fast。AI 、点燃、其他。高级库通过以下方式节省您的时间:
- 提供久经考验的训练循环
- 支持配置文件
- 支持多 GPU 和分布式训练
- 检查点/实验的管理
- 自动记录培训进度
从这些高级库中获取最大价值需要一些时间。然而,这种一次性投资从长远来看是值得的。
优点
- 训练管道变得更小——代码越少——出现错误的机会就越少。
- 更简单的实验管理。
- 简化的分布式和混合精度训练
缺点
- 另一个抽象层次——通常,当使用高级框架时,我们必须在特定框架的设计原则和范例内编写代码。
- 时间投资—学习额外的框架需要时间。
给我看看指标
由 Mikail McVerry 在 Unsplash 上拍摄的照片
建议 2——在培训期间查看其他指标
在 MNIST、CIFAR 甚至 ImageNet 中,几乎每一个用于图像分类的快速入门示例项目都有一个共同点——它们在培训期间和培训之后报告一组最少的指标。最常见的是前 1 名和前 5 名的准确性、错误率、训练/验证损失,仅此而已。虽然这些指标是必不可少的,但这只是冰山一角!
现代图像分类模型有数千万个参数。你想只用一个标量值来计算它吗?
具有最佳 Top-1 准确度的 CNN 分类模型在泛化方面可能不是最佳的。根据您的领域和要求,您可能希望保存假阳性/假阴性率最低的模型或平均精度最高的模型。
让我给你一些建议,在培训期间你可以记录哪些数据:
- Grad-CAM 热图——查看图像的哪些部分对特定类别的贡献最大。
可视化 Grad-CAM 热图有助于识别模型制作预测是基于真实的病理还是图像伪影(尤金·赫韦德钦亚)
- 混淆矩阵——向你展示哪一对职业对你的模型最具挑战性。
混淆矩阵揭示了模型对特定类型做出错误分类的频率(Eugene Khvedchenya,ALASKA2 Image Steganalysis,Kaggle)。
- 预测分布——让您洞察最佳决策边界。
该模型的负面和正面预测的分布显示,有很大一部分数据该模型无法以置信界限进行分类(Eugene Khvedchenya,ALASKA2 Image Steganalysis,Kaggle)。
- 所有层的最小/平均/最大梯度值——允许识别模型中是否有消失/爆炸梯度或初始化不良的层。
使用仪表板工具监控培训
建议 3——使用 TensorBoard 或任何其他解决方案来监控训练进度
在训练模型时,您最不想做的事情可能就是查看控制台输出。一个功能强大的仪表盘可以让你一次看到所有的指标,这是一种更有效的检查培训结果的方式。
Tensorboard 允许在本地快速检查和比较您的跑步记录(Eugene Khvedchenya)
对于少量实验和非分布式环境,TensorBoard 是金标准。从版本 1.3 开始,PyTorch 完全支持它,并提供了一组丰富的功能来管理试验。还有更先进的基于云的解决方案,如Weights&bias、 Alchemy 和 TensorBoard.dev ,这使得在多台机器上监控和比较训练课程变得更加容易。
使用 Tensorboard 时,我通常会记录一组指标:
- 学习率和其他可能改变的优化参数(动量、重量衰减等)。)
- 花费在数据预处理和模型内部的时间
- 跨训练和验证的损失(每批和每个时期的平均值)
- 跨培训和验证的指标
- 最终度量值的训练会话的超参数
- 混淆矩阵、精密度-召回曲线、AUC(如果适用)
- 模型预测的可视化(如果适用)
一幅画胜过千言万语
直观地看模型的预测是超级重要的。有时候训练数据是有噪音的;有时,模型会过度拟合图像的伪影。通过可视化最佳和最差批次(基于损失或您感兴趣的度量),您可以获得对模型表现良好和较差的情况的宝贵见解。
建议 5 —可视化每个时期的最佳和最差批次。它可能会给你宝贵的洞察力
Catalyst 用户提示:此处使用可视化回调 I 示例:https://github . com/blood axe/Catalyst-Inria-Segmentation-Example/blob/master/fit _ predict . py # L258
例如,在全球小麦检测挑战中,我们需要检测图像上的麦穗。通过可视化最佳批次的图片(基于地图度量),我们看到该模型在查找小对象方面做得近乎完美。
最佳模型预测的可视化揭示了模型在小对象上表现良好(Eugene Khvedchenya,Global Wheat Detection,Kaggle)
相比之下,当我们看最差批次的第一个样本时,我们看到该模型很难对大型物体做出准确的预测。可视化分析为任何数据科学家提供了宝贵的见解。
最差模型预测的可视化揭示了模型在大型对象上表现不佳(Eugene Khvedchenya,Global Wheat Detection,Kaggle)
查看最差批次也有助于发现数据标签中的错误。通常,标签错误的样品损失更大,因此会出现在最差的批次中。通过在每个时期对最差批次进行目视检查,您可以消除这些错误:
标签错误的例子。绿色像素表示真阳性,红色像素表示假阴性。在此示例中,地面实况掩膜在实际上不存在的位置有一个建筑物覆盖区。(Eugene Khvedchenya,Inria 航空影像标注数据集)
使用Dict
作为数据集和模型的返回值
建议 4 —如果您的模型返回多个值,请使用
***Dict***
返回结果。不要用***tuple***
。
在复杂模型中,返回多个输出并不少见。例如,对象检测模型通常会返回包围盒及其标签,在图像分割 CNN-s 中,我们经常会返回中间遮罩以进行深度监督,多任务学习目前也很流行。
在许多开源实现中,我经常看到这样的情况:
出于对作者的尊重,我认为这是一种从模型返回结果的非常糟糕的方法。以下是我推荐使用的替代方式:
这个建议与“Python 之禅”中的一个假设有点共鸣——“显式比隐式好”。遵循这条规则将会使你的代码更加整洁和易于维护。
那么,为什么我认为第二种选择更好呢?出于几个原因:
- 返回值有一个与之相关联的显式名称。您不需要记住元组中元素的确切顺序
- 如果需要访问返回的字典中的特定元素,可以通过它的名称来实现
- 从模型中添加新的输出不会破坏代码
使用Dict
,你甚至可以改变模型的行为,根据需要返回额外的输出。例如,这里有一小段代码演示了如何为度量学习返回多个“主要”输出和两个“辅助”输出:
同样的建议也适用于数据集类。对于 Cifar-10 toy 示例,可以将图像及其对应的标签作为元组返回。但是在处理多任务或多输入模型时,您希望以 Dict 类型从数据集中返回样本:
当您的代码中有字典时,您可以在任何地方引用带有名称常量的输入/输出。遵循这条规则将使你的培训渠道非常清晰,易于遵循:
检测训练中的异常
就像人类可以阅读其中有许多错误的文本一样,深度学习模型也可以在训练管道中出现错误时学习“一些合理的东西”。作为开发人员,您负责搜索异常,并对它们的出现进行推理。(照片由布雷特·乔丹在 Unsplash 上拍摄)
建议 5 —使用
***torch.autograd.detect_anomaly()***
在训练过程中查找算术异常
如果你在培训过程中看到损失/指标中有任何 nan 或 Inf,你的脑海中应该响起警报。这表明您的管道出现了问题。通常,它可能由以下原因引起:
- 模型或特定层的初始化错误(你总是可以通过查看梯度大小来检查是哪些)
- 数学上不正确的运算(
torch.sqrt()
从负数,torch.log()
从非正数,等等)。) torch.mean()
和torch.sum()
归约使用不当(零大小张量上的均值会给出 nan,大张量上的求和容易导致溢出)- 在损失中使用
x.sigmoid()
(如果你需要损失函数中的概率,更好的方法是使用x.sigmoid().clamp(eps,1-eps
或torch.logsigmoid(x).exp()
来防止梯度消失) - Adam 类优化器中的低ε值
- 使用 fp16 训练时不使用动态损耗缩放
为了在代码中找到 Nan/Inf 第一次出现的确切位置,PyTorch 提供了一个易于使用的方法torch . autograded . detect _ anomaly():
将其用于调试目的,否则禁用,因为异常检测会带来计算开销,并使训练循环变慢约 10–15%。
结束了
感谢阅读!我希望你喜欢它,并从这篇文章中找到一些外卖。你想分享什么技巧和诀窍?请在评论中写下你的诀窍,或者如果你对 PyTorch 相关的特定主题感兴趣,也请告诉我!
Eugene 是一名计算机视觉和机器学习工程师,拥有十多年的软件开发经验。《掌握 OpenCV 用于实用计算机视觉项目》一书的作者。卡格尔主人。白蛋白核心团队成员。pytorch -toolbelt 的作者。OpenCV、PyTorch 和 Catalyst contributor。https://www.linkedin.com/in/cvtalks/
边缘高效强化学习
图片作者。
借助正交持久性,我们可以在边缘设备上实现顺序学习
在之前的帖子中,我们已经展示了如何利用模型训练(即需要所有数据,通常需要多次通过数据集)和预测(即基于具有预训练参数的单个函数)之间的差异,来有效地部署机器学习(ML)和人工智能(AI)模型。通过将训练好的模型传输到 WebAssembly ,可以将受监督和不受监督的模型高效地部署到云和边缘设备。我们已经能够在可用内存小于 64Kb 的设备上部署模型。相当酷。然而,我们经常被问到如何有效地更新模型(T10)(最好是本地更新模型(T11)):在边缘设备上更新模型(T14)状态的简单方法(T15)将允许有效的顺序学习和强化学习应用。
在边缘设备本身上更新模型状态的简单方法将允许高效的顺序学习和强化学习应用。
在这篇文章中,我们将解释如何使用正交持久性来更新 WebAssembly 二进制文件的状态,以实现这样的功能。我们将首先解释模型更新的概念(ML/AI)视图,然后关注 WebAssembly 中的实现。最后,我们将讨论正交持久性提供的可能性。
更新模型的状态
正如我们之前所描述的,经过训练后,大多数机器学习模型由一个简单的(尽管通常是高维的)数学函数和一组参数组成。例如,在神经网络中,所涉及的权重矩阵的条目构成了通过训练模型获得的参数。有点抽象地说,在训练之后,我们可以将模型定义为一个函数 f() ,它将输入 x 映射到(预期的)输出 y 。我们可以明确说明,函数的行为取决于参数的状态:
y = f(x;S1)
其中将包含(例如)所有必需的权重。**
在许多情况下,能够随时间更新状态 S1 是有用的。当(例如)存在概念漂移并且模型的性能随时间下降时,或者当部署到边缘设备的模型需要更新以反映本地情况时,这可能是有用的。在这种情况下(以及更多情况,参见我们下面的讨论),将更新为—即所涉及参数的新状态会很有用,而不会有太多麻烦。此外,当部署模型时,应该维护其更新的状态:即当在边缘设备上运行时,更新的模型应该保持。**
虽然概念上很简单——我们只是将新状态 S2 存储在某个地方——但是当使用 WebAssembly 部署模型时,在边缘设备上高效地实现持久状态更改有些棘手。然而这是很有可能的。
虽然在概念上很容易,但在边缘设备上有效实现持久状态改变在实践中往往很棘手。然而这是很有可能的。
更新 WebAssembly 二进制文件的状态
我们通常使用 WebAssembly 将模型部署到边缘设备。当考虑这种模型的持续更新时,对所涉及的一般过程有一个合理的理解是有用的:
- 我们部署 WebAssembly 二进制文件——它有效地包含了 f(。;)—去边设备。这些二进制文件存储在设备的“磁盘”上,包括它们的状态。****
- 边缘设备包含一个 WebAssembly 运行时,这是一个应用程序,它加载二进制文件并将其所谓的
data section
( 参见本文以获得关于 WebAssembly 二进制文件的更多信息)写入其(线性)内存:这个data section
通常用于存储模型的状态。运行时确保在边缘设备上执行预测(在我们的例子中,当。WASM 二进制被称为,见本教程)。**
一般来说,在 WebAssembly 二进制文件之间来回传输数据是相对容易的:我们通常在传递一个指向内存中存储(例如)特征向量的位置的指针时这样做(详见本教程—特征向量是y = f(x;S)以上符号介绍)。然而,传递一个持续的新状态 S 要棘手得多:不允许直接向现有的data section
写入,这样做也不能确保它在磁盘上的持久性。****
我们通过向所有需要持久更新的 WebAssembly 二进制文件中自动添加一个新的custom data section
有效地解决了这个问题。这个custom data section
在功能上与标准的 WebAssembly 数据部分相同,只是这次它可以被更新:我们将一个导出的update()
函数添加到已部署的。WASM 二进制文件,包含对模型状态进行任何更新所需的逻辑。因此,我们现在可以将状态从 S1 更新到 S2 以确保模型的更新。
然而,简单地更新线性存储器中的状态对于持久性来说是不够的;我们需要确保状态的任何变化也反映在磁盘上(即当打开和关闭设备时,我们希望 S2 被保留)。这是通过扩展标准 WebAssembly 运行时来解决的:我们的 edge 运行时主动监控线性内存中的状态 S 。当它改变时,运行时会在磁盘上覆盖所涉及的 WebAssembly 二进制文件的custom data section
。因此,我们现在有了一个新的、持久的状态。
因此,通过扩展 WebAssembly 的数据结构和默认运行时,有可能在边缘上允许 ML/AI 模型的高效持久更新。
因此,通过扩展 WebAssembly 的数据结构和默认运行时,有可能允许边缘上的 ML/AI 模型的高效持久更新。
持久状态更新的可能性
我们已经描绘了一些场景,在这些场景中,对已部署的 WebAssembly 二进制文件进行(本地)更新可能是有意义的:在概念漂移或本地变化的情况下,使用新的状态不时地更新已部署的模型可能是有用的。然而,快速和持久的更新允许更丰富的应用程序:
- 模型状态的快速和持久更新允许边缘设备上的模型的顺序学习。例如,当模型可以用求和形式来表达时,部署的模型可以很容易地用每个新的(标记的)可用数据点来更新。
- 模型状态的快速和持久更新允许在边缘设备上进行强化学习(从而将独立的 WebAssembly 部署扩展到受监督和不受监督的模型之外)。例如,可以使用
predict()
和update()
函数迭代地实现多武装强盗策略(并添加一些主动探索)。
我们将很快向我们的 WebAssembly Javascript 运行时添加持久更新,从而让您看到在此设置中“运行时覆盖到磁盘”的实际实现。然而,我们希望在上面的帖子中已经提供了一个有价值的方法草图。
放弃
值得注意的是我自己的参与:我是 Jheronimus 数据科学院 的数据科学教授,也是Scailable的联合创始人之一。因此,毫无疑问,我对 Scailable 有既得利益;我有兴趣让它成长,这样我们就可以最终将人工智能投入生产并兑现它的承诺。这里表达的观点是我自己的。**
数据科学中的因果推理:有效的抽样框架和设计
实践教程
病例对照设计:数学推导、解释、计算模拟和消除误解
1:背景和动机
当应用因果推断方法时,特别是在非随机环境中,病例对照设计家族是一个强有力的工具。它们是一个有效的抽样框架,用于恢复因果效应的无偏估计,这些估计可以从一个完整的队列研究中恢复,而无需实际进行所述队列研究。
像几乎所有的因果推断方法一样,病例对照设计最初是在医学和公共卫生相关领域发展起来的;这些设计范例中的许多语言和术语反映了这一事实。然而,这些都是强大的方法,可以(并且更普遍地)在任何对恢复非随机化设置中因果效应的无偏估计感兴趣的领域中利用,感兴趣的从业者包括统计学家、数据科学家和机器学习从业者。
让我们指定下面的玩具例子。我们希望在非随机化设置中恢复二元干预对二元结果的因果效应的无偏估计。下图显示了我们框架的一个因果 DAG 在 A 对YC无因果效应的空值下。如果这是一项队列研究,我们可以使用标准方法对 C 进行调整,并恢复A*Y 的因果效应的无偏估计。*****
作者图片
然而,假设为这个队列中的每个观察收集数据非常昂贵或耗时?相反,我们只想获取一小部分观察数据用于我们的分析。而如果二元结局 Y 高度不平衡,其中 Y=1 只代表队列人群的一小部分比例呢?因此,简单地对整个队列进行边际随机抽样是不可行的。与传统的机器学习不同,在传统的机器学习中,我们只关心预测,我们不能以优化我们预测目标的能力的方式方便地“平衡”我们的数据集;这可能极大地扭曲了和 Y 之间的经验关系,使得恢复 A 对 Y 的因果效应的无偏估计变得不可能。**
那么,有没有一种有效的方法(或一系列方法)可以用来有效地对我们的队列进行抽样,进行分析,并且仍然能够恢复我们感兴趣的因果效应的无偏估计?答案是肯定的。使用病例对照设计家族,我们在分析中包括病例和对照的有效取样部分;但是我们这样做的方式仍然允许我们无偏地估计利息的因果效应。
作为一个在使用这些范例方面受过良好训练的人,我发现与其他方法相比,关于这些方法的教育材料和资源很缺乏。围绕这些方法还有一些常见的误解和困惑。我的目标是这篇文章有助于缓解这些挑战。
这篇文章的内容如下:
作者图片
所以让我们开始吧。
2:5 个病例对照范例的详细示例
为了便于说明,让我们指定一个简化的玩具示例。假设我们有一个利益的二元干预和利益的二元结果。在我们的玩具示例中,我们的群组中总共有 13 个人。所有个体在随访开始时都以结果 Y=0 开始。每个人都被随访一段可变的时间,总共有 3 个人在随访结束时经历了结果 Y=1 。这 3 个人是观察值 7、9 和 13,在下图中用圆圈标记。我对这 3 个观察结果进行了不同的颜色编码,稍后会变得清晰。**
作者图片
需要记住几个关键点:
- 在下面的 13 个观测值中,一些有二元干涉 A=0 ,其余的有 A=1 。考虑到我们将对独立于干预状态的控制进行采样,我特意没有在下图中标出每个观察的干预状态。这个以后就清楚了。
- 在实际的病例对照分析中,为了恢复干预对结果 Y 的无偏因果估计,我们可能会因 C 而产生混淆,我们希望稍后进行调整。因此,在混杂因素 C 水平内匹配病例和对照可能是有益的。在下面的例子中,为了简单起见,我特意省略了混杂因素 C 。在实际分析中,如果在 C 上匹配是有益的,我们将在混杂 C 的层次内实现下面示例中的匹配标准。
2.1:事件密度采样
在发病率密度抽样中,我们从研究基地中产生病例的人-时间总量中抽取对照样本。取样控件的示例如下所示,取样控件由相应的彩色 x 表示。对于每种情况,我们匹配两个对照。下表显示了三个病例及其相应的六个匹配对照的图。
作者图片
对于事件密度抽样方案,有三个关键点需要记住:
- 随后可能成为病例的观察结果可以作为对照进行采样(注意观察结果 9 如何成为病例,也作为对照进行采样,与观察结果 7 相匹配)。
- 观察值通过替换进行采样,这意味着它们可以作为对照进行多次采样(注意观察值 8 如何作为对照进行两次采样)。注意,“替换取样”适用于本文讨论的所有取样方案的。****
- 假设我们从总的人-时间池中取样,观察值随机取样作为人-时间长度的控制(即加权随机取样)。因此,例如,在上面的图中,观察值 8 比观察值 12 具有更高的被采样作为对照的概率,假设观察值 8 的随访总长度更长。因此,我们使用加权随机抽样法对对照组进行随机抽样,每次观察的权重与观察在队列中所占的总人-时间成比例
我们现在有病例,也有控制手段。我们知道我们可以计算病例对照优势比估计量:
作者图片
我们可以从数学上证明,在利用发病率密度抽样的情况下,病例对照比值比估计值是我们在进行完整队列研究时估计的发病率比(IRR)的无偏估计值。这是有条件的,假设在干预 A=1 和 A=0 总体中,抽样控制的抽样分数是相同的。这就是为什么必须独立于干预状态对质控品进行取样的原因。
上述陈述的数学证明如下所示:
作者图片
2.1.1:病例对照分析中“比值比”的注释
关于病例对照研究的一个常见误解如下:
“病例对照研究估计比值比,需要罕见结果假设来估计风险比”
正如我们从入射密度采样的详细演练中看到的,上述陈述(一般而言)是不正确的。许多困惑源于围绕病例对照研究设计的拙劣语言。
从病例对照分析中估计的优势比与从队列分析中估计的优势比不是同一个经验指标。从算法上来说,它看起来是相同的度量。然而,参照病例对照研究,抽样“对照”并不是真正的对照。更确切地说,抽样“控制”是从一些独立于干预状态的随机抽样的基础研究中抽取的。该“研究基础”可以是处于危险中的人-时间、处于危险中的观察的总人口、在审查之前从未得出结果的处于危险中的观察的总人口等。“研究基础”的详细说明改变了对比值比的解释,该比值比是从病例对照研究中根据经验得出的。
正如我们在上面所看到的,采用发病率密度抽样的病例对照分析恢复了一个经验优势比,这是一个我们在进行全队列研究时估计的发病率比的无偏估计。注意,这和“罕见病”的假设完全没有关系。
请注意,有一个抽样方案(累积密度抽样),其中病例对照比值比估计值是我们进行全队列研究时估计的比值比的无偏估计值(见 2.3 节)。
让我们进入下一个抽样方案,风险集抽样
2.2:风险设定抽样
风险集抽样几乎与发病率密度抽样相同,除了对照抽样与人-时间匹配的相应病例。正如发病率密度抽样一样,作为风险集抽样结果的病例对照比值比估计值也是发病率比(IRR)的一个无偏估计值,如果我们进行了一项完整的队列研究,我们就会对其进行估计。
如果人-时间长度是干预 A 和结果 Y 因果关系的混杂因素,并且人-时间需要在分析的后期进行调整,出于统计效率和阳性相关的原因,使用风险集抽样而不是发病率密度抽样可能是有益的。
从同一个玩具示例开始,下面再次显示了该采样方案的示例实现。
作者图片
2.3: 累计发病率抽样
累积发病率抽样是经典的“病例对照”旗帜下的最后一种抽样技术。这也是(我相信)最容易理解的。
对于在随访监测结束时没有成为病例的每个观察结果,我们从观察总体中随机抽取对照样本。请注意,我们不再按时间匹配(如风险集抽样)或随机抽样控制与基于人-时间长度的加权随机抽样(如发病率密度抽样)。相反,到随访结束时,群组中仍为 Y=0 的每个观察值被采样作为对照的可能性相等。
同样,下面显示的是这种采样方案的一个示例实现。
作者图片
在累积发病率抽样的情况下,病例对照比值比估计值是我们进行完全队列研究时估计的实际比值比(or)的无偏估计值。这也是基于这样的假设:在干预 A=1 和 A=0 人群中,抽样控制的抽样分数是相同的。
上述陈述的数学证明如下所示:
作者图片
2.4:基于案例的采样
基于病例的设计与累积密度抽样的病例对照设计有某些相似之处。不同之处在于:
- 使用累积密度抽样,我们等到随访结束时才知道哪些观察结果发展成病例,哪些没有。然后,我们从从未成为病例的观察群体中抽取对照样本。
- 在基于病例的设计中,我们在随访开始时对对照进行取样,不管这些观察结果是否可能(在某一点上)发展成病例。
因此,在基于病例的设计中,我们从引起病例的潜在观察队列中取样。
下面显示的是这种采样方案的一个实现示例。
作者图片
在基于病例的设计中,病例对照比值比估计值是对风险比(RR)的无偏估计,如果我们进行了完整的队列研究,我们就会对 RR 进行估计。这也是基于这样的假设:在干预 A=1 和 A=0 人群中,抽样控制的抽样分数是相同的。
上述陈述的数学证明如下所示:
作者图片
2.5:病例群组抽样
病例队列设计与风险集抽样的病例对照设计有某些相似之处。在某些方面,病例-群组设计抽样方案更简单;尽管它需要比本文讨论的任何其他抽样方案更复杂的统计分析。
病例组设计的步骤如下:
- 我们从随访开始时从总人口中随机抽样一个亚队列开始。这个小组是一个简单的边际随机样本。
- 我们识别整个队列中的所有病例。注意,有些病例可能属于亚组,有些可能不属于。
- 然后,我们随着时间的推移跟踪亚队列中的病例和所有观察结果。当每个病例发展成一个病例时,我们对在该时间点仍在亚队列中的所有其他观察结果进行采样,作为该病例的匹配对照。
下面显示的是这种抽样方案的一个实现示例,其中观察值 2 到 10 作为“子群组”被随机抽样。
请记住以下几点:
- 类似于带有风险集抽样的病例对照设计,我们对每个病例对照进行人-时间匹配的抽样。
- 与风险设定抽样或本文中讨论的任何其他抽样方案不同,我们不一定要对每个案例进行相同数量的控制抽样。在每个病例匹配时,我们对亚队列中的所有观察结果进行采样,而不是对每个病例的恒定数量的对照进行采样。随着时间的推移,随着随访时间的结束,观察结果退出亚队列,与每个病例相匹配的对照组的数量变得越来越少。我们可以在上面的玩具例子中看到这种效果;观察 9 与 8 个对照匹配,观察 7 与 7 个对照匹配,观察 13 仅与 5 个对照匹配。
作者图片
3.病例对照分析中的混杂调整
不管采用何种抽样方案,在病例对照分析中,通常采用我们的抽样程序,在混杂因素水平内匹配病例和对照。就这样做的动机而言,一个常见的误解如下:
作者图片
注意,上述说法是不正确的。
这种匹配的目的是而不是来调整混杂(至少在分析的这一步不是这样)。我相信这种混乱很大程度上源于队列研究中的匹配比较。
在队列研究中,在混杂因素 C 的水平内,匹配干预 A=1 和非干预 A=0 观察值(具有一些指定的匹配率)确实会产生一个匹配人群,其中CA。这也是在一项队列研究中,通过 C 充分调整了混杂因素。假设满足因果推断的条件(一致性、正定性和可交换性),在匹配人群中,对 Y 的经验平均边际效应恢复了对 Y 的平均因果效应的无偏估计。****
同样,以上是队列研究中匹配的结果。病例对照研究中的情况并非如此。
在病例对照研究中,当抽样控制时,我们通常在混杂水平内匹配病例和控制。这不会通过 C 对混杂进行调整(至少不会在分析的这一步)。相反,在匹配之后,我们仍然需要通过 C 来调整混杂,无论是通过使用标准方法(条件作用)、倾向得分调整、边际结构建模、G 估计等。我们在 C 水平内匹配病例和对照的原因是出于两个重要的研究设计考虑:
- 抽样估计量的统计效率
- 当恢复因果效应的无偏估计时,减少积极性问题的可能性
通过在混杂因素 C 的水平内匹配病例和对照,我们保证在C 的每个水平内至少有一些病例和对照的观察实例,使我们更有可能获得我们所需要的足够数据,甚至有可能在以后对 C 进行调整。这与因果推理的肯定性要求有关。
这也可以通过检查下面的因果有向无环图(Dag)来理解。注意,这些示例 Dag 是在干预对结果没有因果影响的无效假设下绘制的(因此缺少从 A 到 Y 的有向箭头)。**
在图 1 中,我们从讨论中的整个群组开始。我们想要估计干预对结果 Y 的因果效应。我们可以看到,变量 C 是两个和*的共同原因。由 d-分离规则可知,路径从 A 到 C 到 Y 是开放的,用 C 混淆了 A 对 Y 。***
作者图片
在图 2 中,我们通过从一些潜在的研究基础中提取所有病例( Y=1 )和一个对照样本,在混杂因素 C 水平内匹配病例,来创建我们的病例对照人群。假定病例与对照的相同比例在 C 水平内匹配,在这个匹配的人群中 C 不再是结果 Y 的直接原因(因此缺少从 C 到 Y 的箭头)。
然而, C 直接告知我们用于选择控件的标准 S ,正如结果状态 Y 一样,因此定向箭头到 S 和 Y 到 S 。注意 S 是 C 和 Y 之间的碰撞体。此外,假设我们的病例对照分析仅限于我们匹配的人群,我们的条件是选择标准 S (因此围绕 S )。通过 d-分离,通过在碰撞器 S 上的调节,我们打开了从 C 到 Y 通过 S 的联想路径。因此,以我们的抽样标准 S 为条件,从 A 到 C 到 S 到的联想路径仍然是开放的,留下变量 C**
这就是为什么在混杂因素 C 的水平内匹配我们的病例和对照本身并不针对CofAonY的混杂因素进行调整。我们后面还需要针对 C 进行调整。
作者图片
最后,图 3 显示了我们在病例对照人群中使用标准方法(条件反射)对 C 进行调整。以 C 为条件从 A 到 C 到 S 的关联路径现已关闭。因此,如果我们估计在上匹配的总体中 A 对YC的平均条件效应,我们将恢复出对Y 的平均因果效应的无偏估计。******
作者图片
4.5 种范式的计算机模拟
为了巩固上述证明和概念,进行了计算模拟研究。根据以下 DAG 指定了一百万次观察的模拟队列:
在模拟队列中,随访时间的长度被随机分配到 30 到 100 个单位的观察值。目标是恢复对的相对因果影响的无偏估计。按照上面的 DAG,这可以通过在C 上的结果模型中的标准调节方法来实现。因此,AY以 C 为条件的条件估计,恢复了对AY 因果效应的无偏估计。********
在我们的模拟研究中,如果我们可以访问整个队列,我们将受益于恢复真实的“基于队列的”发病率比(IRR)、比率比(RR)和优势比(OR)。在我们的模拟中,我们将实现本文中讨论的五种病例对照抽样方法中的每一种,并展示它们如何产生与其对应的“群组”估计非常接近的估计。
从上面的模拟输出中,我们得到了以下结果。我们可以看到病例对照比值比估计值与他们估计的相应队列相对测量值非常匹配。
作者图片
5.总结和结论
如果你想了解更多的病例对照分析,特别是一级与二级对照,以及对照选择的考虑,我强烈建议你阅读 Wacholder 等人的 3 部分系列。
此外,如果你想了解更多关于因果推理的方法和注意事项,我会推荐哈佛大学的 Miguel Hernan 和 Jamie Robins(我以前的两位教授)的教科书“causalem Inference:What If”,加州大学洛杉矶分校的 Judea Pearl 的教科书“causalem”,以及斯坦福大学的达芙妮·黑仔和耶路撒冷希伯来大学的 Nir Friedman 的教科书“probabilical graphic Models:Principles and technologies”。这些都是很棒的文章。我计划在未来写更多关于因果推理的深度文章。**
因果推断:如果会怎样
希望以上有见地。正如我在以前的一些文章中提到的,我认为没有足够的人花时间去做这些类型的练习。对我来说,这种基于理论的洞察力让我在实践中更容易使用方法。我个人的目标是鼓励该领域的其他人采取类似的方法。我打算在未来写一些基础作品,所以请随时在 LinkedIn 上与我联系,并在 上关注我这里的 更新!
TigerGraph 和 Docker 的有效使用
TigerGraph 可以与 Docker 结合,在几乎任何操作系统上运行。在本文中,我们解决了大型 TigerGraph 图像及其未使用潜力的问题。
图片作者。Logos 分别来自 TigerGraph 和 Docker 的网站。
TigerGraph 是我首选的图形数据库和图形分析平台,因为它速度快、可扩展,并且有一个活跃的开源社区。由于附近没有 TigerGraph Cloud 服务器,我经常在本地使用 TigerGraph。
在撰写本文时, TigerGraph 软件要求规定支持以下操作系统:
- Redhat 和 Centos 版本 6.5–6.9、7.0–7.4 和 8.0–8.2
- Ubuntu 14.04、16.04 和 18.04
- Debian 8
对于使用这个列表之外的操作系统的人来说,一个合理的解决方案是使用容器化:Docker,在本文的例子中。
在本文中,我们将涵盖:
- 如何使用官方 TigerGraph 和里面的内容
- 剥离不必要的臃肿的官方码头形象
- 修改入口点以添加:
- 启动时运行
gadmin
- 运行绑定在某个目录下的 GSQL 脚本
- 将日志文件的输出发送到
STDOUT
4.使用 Docker Compose 运行 TigerGraph 图像
官方 TigerGraph 图像
运行开发人员版的官方 TigerGraph 映像可以通过以下命令获得:
docker pull docker.tigergraph.com/tigergraph-dev:latest
运行方式:
docker run -d -p 14022:22 -p 9000:9000 -p 14240:14240 --name tigergraph_dev --ulimit nofile=1000000:1000000 -v ~/data:/home/tigergraph/mydata -t docker.tigergraph.com/tigergraph-dev:latest
该源给出了关于如何构建图像的更深入的说明,但概括来说:
- 使用 Ubuntu 16.04 的基本映像
- 所有必需的软件,如 tar、curl 等。已安装
- 可选软件,如 emacs、vim、wget 等。已安装
- GSQL 101 和 102 教程以及 GSQL 算法库已下载
- SSH 服务器、REST++ API 和 GraphStudio 是 3 个值得注意的端口,它们可以暴露出来并用于与服务器通信
整个映像的下载量接近 1.8-2.0 GB(取决于版本),这给带宽带来了相当大的压力,尤其是对于 CI/CD 这样的资源敏感型使用情形。另一个值得注意的点是,使用 TigerGraph 所需要的只是一个 GSQL 套接字连接,它可以通过诸如 Giraffle 和 pyTigerGraph 之类的工具进行接口。
我已经确定了膨胀的两个主要来源:
- 可选和不必要的软件,如 vim 和 GSQL 教程 101
- TigerGraph Developer Edition 的最小操作不需要 GraphStudio 和二进制文件
剥离老虎图像
我用 Bitnami 的 MiniDeb 映像替换了基本映像ubuntu:16.04
,以便去掉几兆字节的不必要空间。这是黛比·杰西的作品。
下一步是删除在官方映像的apt-get
阶段安装的不必要的二进制文件。我将 Vim 作为唯一的命令行文本编辑器,但保留了诸如wget
、git
、unzip
、emacs
等二进制文件。不再安装。
在 TigerGraph 安装期间,严格执行硬件要求,如果不满足,安装将失败。因为我想让 DockerHub runners 自动构建和推送我的映像,所以我破解了这个检查,以便资源不足的 runners 可以继续构建映像。
这是通过用我的版本替换os_utils
二进制来实现的,这使得check_cpu_number()
和check_memory_capacity()
函数更加宽松。这个二进制文件可以在下面找到:
/home/tigergraph/tigergraph-${DEV_VERSION}-developer/utils/os_utils
这已经减少了大约 400MB 的膨胀,我的 DockerHub 图像报告了 1.52GB 的压缩大小 TigerGraph 3.0.0(我注意到下载这些层表明它大约为 1.62GB)。
注意:我曾试图随意删除 GraphStudio 二进制文件,但这无法通过gadmin start
脚本,因此必须进行更细致的调整,以便从 TigerGraph 中删除更多内容,例如编辑gadmin
Python 脚本。
一旦我下载并解压缩了这两个图像,它们之间的最终结果可以通过调用docker images
来查看:
我构建的源代码可以在这里找到我鼓励任何有建议的人联系我!
更新(2020 年 2 月 11 日):感谢 Bruno imi 在这项工作的基础上精简了 TigerGraph 企业版,并与我分享了他的代码。以下额外的剥离是他的工作,已经在这个形象实施。
安装目录下似乎有文档和不必要的构建工件(比如许多node_modules
)。可以在以下位置找到这些示例:
${INSTALL_DIR}/app/${DEV_VERSION}/document/
${INSTALL_DIR}/app/${DEV_VERSION}/bin/gui/server/node_modules
${INSTALL_DIR}/app/${DEV_VERSION}/bin/gui/node/lib/node_modules
${INSTALL_DIR}/app/${DEV_VERSION}/gui/server/node_modules/
${INSTALL_DIR}/app/${DEV_VERSION}/.syspre/usr/share/
${INSTALL_DIR}/app/${DEV_VERSION}/.syspre/usr/lib/jvm/java-8-openjdk-amd64–1.8.0.171/
其中INSTALL_DIR
是 TigerGraph Developer Edition v3 的/home/tigergraph/tigergraph
,而DEV_VERSION
是特定版本,例如3.0.0
。
执行 tiger graph Developer Edition v3.0.5 的新版本,并将其与我的新版本 v 3 . 0 . 5 进行比较,我们看到使用了以下数量的磁盘空间:
修改入口点
在我们添加功能之前,让我们先来看看最初的ENTRYPOINT
:
ENTRYPOINT /usr/sbin/sshd && su — tigergraph bash -c “tail -f /dev/null”
这做了两件事:
- SSH 服务器通过运行
/usr/sbin/ssh
启动。 - 通过以用户
tigergraph
的身份运行tail
命令,容器保持活动状态。这样做的目的是不断地从/dev/null
读取输出,这也是为什么容器的STDOUT
是空的。
启动时启动“gadmin”
为了改善用户体验,我添加了一行代码,在 Docker 入口点启动gadmin
服务
ENTRYPOINT /usr/sbin/sshd && su - tigergraph bash -c "tail -f /dev/null"
到
ENTRYPOINT /usr/sbin/sshd && su - tigergraph bash -c "/home/tigergraph/tigergraph/app/cmd/gadmin start all && tail -f /dev/null"
一个很简单却很有价值的改变!
使用卷在启动时运行 GSQL 脚本
TigerGraph Docker 映像缺少(MySQL、MariaDB 和 PostgreSQL 等其他数据库映像有)一个名为 Something 的目录,类似于docker-entrypoint-init.d
,用户可以在其中绑定数据库脚本以在启动时运行,例如用于模式创建或数据库填充。
有多种方法可以实现这一点,但我选择了一个相当简单的方法,在gadmin
和tail
命令之间添加下面一行:
该命令的工作原理是:
- 命令
if
将检查一个名为/docker-entrypoint-initdb.d
的目录是否存在,除非存在,否则不会执行下一步。 for file in /docker-entrypoint-initdb.d/*.gsql; do
行将对入口点文件夹中以扩展名gsql
结尾的所有文件开始 for-each 循环。su tigergraph bash -c
行将对 for-each 循环给出的文件运行 GSQL 命令。- 通过添加
|| continue
,如果脚本执行失败,容器和循环都不会停止。
如果放入entrypoint.sh
中,这看起来会更整洁,但这取决于你!最终结果看起来像这样:
将日志路由到标准输出
为了弄清楚日志属于哪里,可以运行gadmin log
,它将返回如下内容
ADMIN : /home/tigergraph/tigergraph/log/admin/ADMIN#1.out
ADMIN : /home/tigergraph/tigergraph/log/admin/ADMIN.INFO
CTRL : /home/tigergraph/tigergraph/log/controller/CTRL#1.log
CTRL : /home/tigergraph/tigergraph/log/controller/CTRL#1.out
DICT : /home/tigergraph/tigergraph/log/dict/DICT#1.out
DICT : /home/tigergraph/tigergraph/log/dict/DICT.INFO
ETCD : /home/tigergraph/tigergraph/log/etcd/ETCD#1.out
EXE : /home/tigergraph/tigergraph/log/executor/EXE_1.log
EXE : /home/tigergraph/tigergraph/log/executor/EXE_1.out
...etc
我最感兴趣的是管理日志,所以我将把tail
命令改为从/home/tigergraph/tigergraph/log/admin/ADMIN.INFO
而不是/dev/null
中读取。
现在,写入管理日志的任何内容都将自动传输到容器的日志中。所有三个步骤的最终产品现在是:
使用 Docker 编写 TigerGraph
请注意,我添加了一个健康检查,它每 5 秒钟调用一次 REST++ echo 端点来确定容器是否健康。如果您使用官方映像,您将需要 SSH 到容器中来手动启动所有服务:
如果您希望 GSQL 脚本在启动时运行,请在volumes
下添加以下条目:
- my_script.gsql:/docker-entrypoint-initdb.d/my_script.gsql
请注意,我添加了一个健康检查,它每 5 秒钟调用一次 REST++ echo 端点来确定容器是否健康。这对于许多应用程序都很有用,在我的用例中,用于在开始测试之前检查容器在集成测试期间是否准备好了。
如果您使用官方映像,您将需要 SSH 到容器中来手动启动所有服务:
默认密码是“tigergraph ”,在此之后您可以调用该命令
gadmin start all (v3.0.0 >=)
gadmin start (v3.0.0<)
GraphStudio 可以在您的网络浏览器的localhost:14240
中找到,Rest++可以在localhost:9000
中找到。
结论
在这篇文章中,我们有:
- 检查了官方文件,
- 识别并删除明显不必要的文件,
- 构建了一个精简版的 TigerGraph 图像,节省了大量的磁盘空间,
- 修改了
ENTRYPOINT
以向容器添加额外的自动化,以及 - 使用 Docker Compose 运行此图像。
如果你对进一步减小图片的大小有任何建议或想法,那么留下评论、问题或分叉,并在 GitHub 库上对本文中的代码提出请求。如果你想看更多 Docker 相关的指南,为数据库如 JanusGraph 建立自定义设置,请在下面留下评论。
你可以在 Docker Hub 上找到这些图片,我会随着新版本的出现继续更新这些图片,或者直到 TigerGraph 推出正式的更瘦版本。
如果您想加入 TigerGraph 社区并做出贡献,或者启动令人敬畏的项目并深入了解 TigerGraph 的未来,请在以下平台上加入我们:
如果你有兴趣看我的其他作品,那就看看我在 https://davidbakereffendi.github.io/的个人主页。
TigerGraph 的 Jon Herke 在社区中发挥了领导作用,让我们能够以有意义的方式做出贡献,Bruno imi 分享了他在精简 TigerGraph 企业版图像方面的发现,这些发现可在https://hub.docker.com/r/xpertmind/tigergraph找到。
使用 Scrapy 进行有效的网页抓取
https://unsplash.com/@markusspiske
Scrapy 的新功能使您的刮削效率
Scrapy 作为一个网页抓取框架是强大的和可扩展的。它有一个活跃的用户群,每次更新都会有新的功能出现。在本文中,我们将介绍其中的一些特性,以充分利用您的抓取项目。
在本文中,您将了解到
- 更有效地跟踪链接
- html 属性的更清晰提取
- Scrapy 中函数间更清晰的变量传递
- 使用 attribute 属性在没有 xpath 或 css 选择器的情况下获取 html 属性
1.以下链接
为了让你的蜘蛛跟踪链接,这是通常的做法
links = response.css("a.entry-link::attr(href)").extract()
for link in links:
yield scrapy.Request(url=response.urljoin(link), callback=self.parse_blog_post)
现在使用 requests 方法就可以了,但是我们可以使用另一个名为 response.follow()的方法来清理这个问题。
links = response.css("a.entry-link")
for link in links:
yield response.follow(link, callback=self.parse_blog_post)
看看我们为什么不必提取链接或使用 urljoin,这是因为 response.follow 接受标签。Response.follow()自动使用 href 属性。
for link in response.css("a.entry-link"):
yield response.follow(link, callback=self.parse_blog_post)
事实上,scrapy 可以使用 follow_all()方法处理多个请求。这样做的好处是 follow_all 将直接接受 css 和 xpath。
yield from response.follow_all(css='a.entry-link', allback=self.parse_blog_post)
2.提取数据
从标签中提取数据的常用方法是extract()
和extract_first()
。我们可以用一个方法get()
和get_all()
,看起来干净一点。
从
def parse_blog_post(self, response):
yield {
"title": response.css(".post-title::text").extract_first(),
"author": response.css(".entry-author::text").extract_first(),
"tags": response.css(".tag::text").extract(),
}
到
def parse_blog_post(self, response):
yield {
"title": response.css(".post-title::text").get(),
"author": response.css(".entry-author::text").get(),
"tags": response.css(".tag::text").getall(),
}
3.使用属性选择数据
如果您不习惯 xpath 或 css 选择器,Scrapy 可以让您以类似字典的方式获取属性。
从
**>>** response.css('a::attr(href)').getall()
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
到
**>>** [a.attrib['href'] **for** a **in** response.css('a')]
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
使用attrib
你可以获取 html 属性,而不是使用 xpath 或 css!
4.从回调传递数据
通常当你做一些网络抓取时,你需要将信息从一个函数传递到另一个函数。这是您通常使用 response.meta 函数的地方。
def parse_blog_post(self, response):
for link in links:
yield scrapy.Request(
link,
meta={"author": author, "date": post_date},
callback=self.parse_full_blog_post,
)
def parse_full_blog_post(self, response):
author = response.meta["author]
post_date = response.meta["post_date]
现在我们可以使用 follow_all()函数和名为cb_kwargs
的新关键字,这允许我们传递一个值的字典,然后我们可以在回调函数中访问它。
def parse_blog_post(self, response):
yield from response.follow_all(
links,
cb_kwargs={"author": author, "date": post_date},
callback=self.parse_full_blog_post,
)
def parse_full_blog_post(self, response, author, post_date):
我们在字典中定义变量author
和post_date
,并在parse_full_blog_post
中声明它们。干净多了!
我希望你会发现这些技巧对充分利用 Scrapy 框架很有用。
参考
- https://stummjr.org/post/scrapy-in-2020/——这篇文章的来源和一篇很棒的博客文章详细介绍了这些观点!
相关文章
今天如何最大限度地学习 python
towardsdatascience.com](/approach-to-learning-python-f1c9a02024f8) [## 你应该知道的 5 个 Python 技巧
如何轻松增强 python 的基础知识
medium.com](https://medium.com/swlh/5-python-tricks-you-should-know-d4a8b32e04db) [## Scrapy:这就是如何轻松成功登录
揭秘用 Scrapy 登录的过程。
towardsdatascience.com](/scrapy-this-is-how-to-successfully-login-with-ease-ea980e2c5901)
请看这里关于我在我的博客和其他帖子上关于项目的更多细节。更多技术/编码相关内容,请点击这里订阅我的简讯
我将非常感谢任何评论,或者如果你想与 python 合作或需要帮助,请联系我。如果你想和我联系,请在这里 asmith53@ed.ac.uk 或在 twitter 上联系。
EfficientNet:卷积神经网络的扩展做得很好
如何智能缩放 CNN 以实现精度增益
在 Unsplash 上由 Lidya Nada 拍摄的照片
自从 Alex net 赢得 2012 年 ImageNet 挑战赛以来,卷积神经网络在计算机视觉领域变得无处不在。他们甚至发现了它们在自然语言处理中的应用,其中最先进的模型使用卷积运算来保留上下文并提供更好的预测。然而,与所有其他神经网络一样,设计 CNN 的关键问题之一是模型缩放,即决定如何增加模型大小以提供更好的准确性。
这是一个繁琐的过程,需要手动反复试验,直到产生满足资源约束的足够精确的模型。该过程耗费资源和时间,并且经常产生具有次优精度和效率的模型。
考虑到这个问题,谷歌在 2019 年发布了一篇论文,涉及一个新的 CNN 家族,即 EfficientNet。与 GPipe 等先进模型相比,这些 CNN 不仅提供了更好的精度,还通过减少参数和 FLOPS(每秒浮点运算)流形提高了模型的效率。本文的主要贡献是:
- 设计一个简单的手机大小的基线架构: EfficientNet-B0
- 提供一种有效的复合缩放方法来增加模型大小,以实现最大的精度增益。
EfficientNet-B0 架构
表 1。基线网络的架构细节
复合缩放方法可以推广到现有的 CNN 架构,例如移动网络和 ResNet。然而,选择一个良好的基线网络对于实现最佳结果至关重要,因为复合比例方法仅通过复制基础网络的底层卷积运算和网络结构来增强网络的预测能力。
为此,作者利用神经架构搜索构建了一个高效的网络架构, EfficientNet-B0 。仅用 5.3M 参数和 0.39B FLOPS 就在 ImageNet 上实现了 77.3%的准确率。(Resnet-50 提供 76%的精度,参数为 26M,触发器为 4.1B)。
该网络的主要构建模块由 MBConv 组成,并添加了压缩和激励优化功能。MBConv 类似于 MobileNet v2 中使用的反向残差块。这些在卷积块的开始和结束之间形成快捷连接。首先使用 1x1 卷积来扩展输入激活图,以增加特征图的深度。随后是 3×3 深度方向卷积和点方向卷积,减少了输出特征图中的通道数量。捷径连接连接较窄的层,而较宽的层存在于跳跃连接之间。这种结构有助于减少所需操作的总数以及模型大小。
图一。反向剩余块
该块的代码可以推测为:
from keras.layers import Conv2D, DepthwiseConv2D, Add
def inverted_residual_block(x, expand=64, squeeze=16):
block = Conv2D(expand, (1,1), activation=’relu’)(x)
block = DepthwiseConv2D((3,3), activation=’relu’)(block)
block = Conv2D(squeeze, (1,1), activation=’relu’)(block)
return Add()([block, x])
复合缩放
图二。模型缩放。(a)是一个基线网络示例;(b)-(d)是仅增加网络宽度、深度或分辨率的一个维度的传统缩放。(e)是我们提出的复合缩放方法,它以固定的比例统一缩放所有三个维度。
卷积神经网络可以在三个维度上扩展:深度、宽度、分辨率。网络的深度对应于网络的层数。宽度与层中神经元的数量相关,或者更确切地说,与卷积层中滤波器的数量相关。分辨率就是输入图像的高度和宽度。上面的图 2 更清晰地展示了这三个方面的扩展。
通过堆叠更多的卷积层来增加深度,允许网络学习更复杂的特征。然而,更深层次的网络往往会受到梯度消失的影响,变得难以训练。虽然诸如批量标准化和跳过连接的新技术在解决这个问题上是有效的,但是经验研究表明,仅通过增加网络的深度而获得的实际精度会很快饱和。例如,Resnet-1000 提供了与 Resnet-100 相同的精度,尽管有额外的层。
缩放网络的宽度允许层学习更精细的特征。这一概念已在众多作品中广泛使用,如广域网络和移动网络。然而,与增加深度的情况一样,增加宽度会阻止网络学习复杂的特征,从而导致精度增益下降。
更高的输入分辨率提供了关于图像的更多细节,因此增强了模型推理更小对象和提取更精细模式的能力。但是像其他缩放维度一样,这本身也提供了有限的精度增益。
图 3。用不同的网络宽度(w)、深度(d)和分辨率(r)系数放大基线模型。
这导致了一个重要的观察结果:
观察 1 : 按比例增加网络宽度、深度或分辨率的任何维度都会提高精度,但是对于更大的模型,精度增益会减小。
图 4。为不同的基线网络调整网络宽度。
这意味着,为提高精确度而进行的网络缩放应该部分地由这三个维度的组合来贡献。图 4中的经验证据证实了这一点,在图 4中,对于不同的深度和分辨率设置,网络的精度以增加的宽度进行建模。
结果表明,仅缩放一维(宽度)会使精度增益迅速停滞。然而,将此与层数(深度)或输入分辨率的增加相结合,可以增强模型的预测能力。
这些观察多少有些意料之中,可以用直觉来解释。例如,如果输入图像的空间分辨率增加,卷积层的数量也应该增加,使得感受野足够大以跨越现在包含更多像素的整个图像。这导致了第二个观察结果:
观察 2: 为了追求更高的精度和效率,在 ConvNet 扩展期间平衡网络宽度、深度和分辨率的所有维度至关重要。
建议的缩放方法
卷积神经网络可以被认为是各种卷积层的堆叠或组合。此外,这些层可以被划分成不同的级,例如 ResNet 具有五个级,并且每个级中的所有层具有相同的卷积类型。因此,CNN 在数学上可以表示为:
等式 1
其中 n 表示网络,I 表示级数,F ᵢ表示第 I 级的卷积运算,L ᵢ表示 F ᵢ在级 I 中重复的次数。H ᵢ、W ᵢ和 C ᵢ简单地表示级 I 的输入张量形状
从等式 1 可以推导出,L ᵢ控制网络的深度,C ᵢ负责网络的宽度,而 H ᵢ和 W ᵢ影响输入分辨率。找到一组好的系数来缩放每一层的这些维度是不可能的,因为搜索空间是巨大的。因此,为了限制搜索空间,作者制定了一套基本规则。
- 比例模型中的所有层/级将使用与基线网络相同的卷积运算
- 所有层必须以恒定的比例均匀缩放
建立这些规则后,等式 1 可以参数化为:
等式 2
其中 w、d、r 是用于缩放网络宽度、深度和分辨率的系数;F̂ ᵢ、L̂ ᵢ、ĥᵢ、ŵᵢ、ĉᵢ是基线网络中预定义的参数。
作者提出了一种简单但有效的缩放技术,该技术使用复合系数ɸ 以原则方式统一缩放网络宽度、深度和分辨率:
等式 3
ɸ是一个用户定义的全局比例因子(整数),它控制有多少资源可用,而 α 、 β 和 γ 决定如何将这些资源分别分配给网络深度、宽度和分辨率。卷积运算的 FLOPS 与 d,w,r, 成比例,因为深度加倍会使 FLOPS 加倍,而宽度或分辨率加倍会使 FLOPS 增加几乎四倍。因此,使用等式 3 缩放网络将使总 FLOPS 增加(α * β * γ ) ^ɸ。因此,为了确保总 flops 不超过 2^ϕ,应用约束(α * β * γ ) ≈ 2。这意味着,如果我们有两倍的可用资源,我们可以简单地使用复合系数 1 将 FLOPS 缩放 2 倍。
参数- α 、 β 和 γ- 可通过设置 ɸ=1 并找到产生最佳精度的参数,使用网格搜索来确定。一旦找到,这些参数可以固定,复合系数 ɸ 可以增加,以获得更大但更精确的模型。这就是 EfficientNet-B1 到 EfficientNet-B7 的构造方式,名称末尾的整数表示复合系数的值。
结果
这种技术使作者能够生产出比现有的 ConvNets 精度更高的模型,同时也极大地减少了总体 FLOPS 和模型尺寸。
表二。针对 ImageNet 挑战,比较 EfficientNet 与现有网络
这种缩放方法是通用的,可以与其他架构一起使用,以有效地缩放卷积神经网络,并提供更好的精度。
表 3。向上扩展 MobileNets 和 ResNet。
参考资料:
- [高效网](http://Rethinking Model Scaling for Convolutional Neural Networks) , ICML 2019
- MobileNet v2, CVPR 2018
- GPipeNIPS 2019
- 官方发布的代码:https://github . com/tensor flow/TPU/tree/master/models/official/efficient net
EfficientNet 应该是 goto 预训练模型或…
比较不同预训练模型的时间和准确性,并最终创建一个集成来提高结果。
乔恩·泰森在 Unsplash 上的照片
一周前我还没有听说过这个术语,现在我认为 EfficientNet 是最好的预训练模型。在他们的论文中,他们已经展示了它的艺术状态,所以让我们来测试一下,当你为一个模型选择一个主干时,它是否应该是你的选择。我将把它的性能与广泛使用的 MobileNet、Inception 和 Xception 进行比较,比较的基础是每个时期训练和执行推理所用的时间,当然还有准确性。我决定用一场狗对猫的 Kaggle 比赛来做我的裁判,让一切都脱离我的掌控。在我们开始模型和比较之前,如果你想了解更多关于什么是 EfficientNet 和它的所有八个模型的架构,你可以先阅读我以前的文章。
让我们深入了解所有不同高效网络模型的体系结构细节,并找出它们的不同之处…
towardsdatascience.com](/complete-architectural-details-of-all-efficientnet-models-5fd5b736142)
目录
- 要求
- 加载数据集
- 模型
- 结果
- 训练时间
- 推理时间
- 测试集上的性能
5.全体
要求
您将需要 TensorFlow-Nightly,因为 EfficientNet 的稳定版本和 Kaggle 目前不支持下载数据集和提交结果。我将使用 Google Colab,所以如果你想编码,打开笔记本,不要忘记连接到 GPU。
!pip install tf-nightly-gpu
!pip install -q kaggle
您将需要生成一个 Kaggle 的 API 密钥。程序如所示,此处为。执行下面给出的代码来完成设置。
! mkdir ~/.kaggle
! cp kaggle.json ~/.kaggle/
! chmod 600 ~/.kaggle/kaggle.json
加载数据集
! kaggle competitions download -c 'dogs-vs-cats-redux-kernels-edition'
! mkdir train
! unzip train.zip -d train
! mkdir test
! unzip test.zip -d testimport ostrain_dir = os.path.join('/content/train', 'train')
test_dir = os.path.join('/content/test', 'test')
我使用了一个定制的数据生成器来批量加载图像,并定义了几个图像增强函数。
def data_gen(img_names, bat ch_size):
c = 0
n = os.listdir(img_names) #List of training images
random.shuffle(n)while (True):
img = np.zeros((batch_size, 224, 224, 3)).astype('float')
labels = []for i in range(c, c+batch_size):
train_img = cv2.imread(os.path.join(train_dir, n[i]))
train_img = cv2.resize(train_img, (224, 224))
train_img = train_img/255.if random.random() < 0.25:
train_img = cv2.flip(train_img, 1)
rno = random.random()
if rno < 0.1:
train_img = train_img[:196, :196, :]
elif rno < 0.2:
train_img = train_img[28:, 28:, :]
elif rno < 0.3:
train_img = train_img[28:, :196, :]
elif rno < 0.4:
train_img = train_img[:196, 28:, :]
elif rno < 0.5:
train_img = train_img[28:196, 28:196, :]
if rno < 0.5:
train_img = cv2.resize(train_img, (224, 224), cv2.INTER_CUBIC)img[i-c] = train_img
if len(re.findall('dog', n[i])) == 1:
labels.append(1)
else:
labels.append(0)labels = np.array(labels)
c+=batch_size
if(c+batch_size>=len(n)):
c=0
random.shuffle(n)
yield img, labelstrain_gen = data_gen(train_dir, batch_size)
如果您想了解如何创建更多的图像增强功能,请参考本文。
这是一篇详尽的文章,通过使用 OpenCV 的自定义数据生成器,涵盖了所有的图像增强功能。
towardsdatascience.com](/complete-image-augmentation-in-opencv-31a6b02694f5)
模型
我们将创建一个非常基本的模型,即加载预训练的网络,将其层设置为可训练,添加一个全局平均池层和一个密集层。所有的层都被设置为可训练的,这样即使有些层在这里被冻结了,也要花最长的时间来训练。他们将接受 10 个纪元的训练。
def create_model(base_model):
base_model.trainable = True
global_average_layer = tf.keras.layers.GlobalAveragePooling2D()(base_model.output)
prediction_layer = tf.keras.layers.Dense(1, activation='sigmoid')(global_average_layer)
model = tf.keras.models.Model(inputs=base_model.input, outputs=prediction_layer)
model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.0001), loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), metrics=["accuracy", "mse"])
return modeldef fit_model(model):
model.fit(train_gen, batch_size=batch_size, steps_per_epoch=25000 // batch_size, epochs=epochs)IMG_SHAPE = (224, 224, 3)
model_mob = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
model_inc = tf.keras.applications.InceptionV3(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
model_xcep = tf.keras.applications.Xception(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
model_B0 = tf.keras.applications.EfficientNetB0(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
model_B1 = tf.keras.applications.EfficientNetB1(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
model_B2 = tf.keras.applications.EfficientNetB2(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
model_B3 = tf.keras.applications.EfficientNetB3(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
model_B4 = tf.keras.applications.EfficientNetB4(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
model_B5 = tf.keras.applications.EfficientNetB5(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")fit_model(model_mob)
fit_model(model_inc)
fit_model(model_xcep)
fit_model(model_B0)
fit_model(model_B1)
fit_model(model_B2)
fit_model(model_B3)
fit_model(model_B4)
fit_model(model_B5)
结果
啊终于到了真相大白的时刻了。你一直在等待的部分。
训练时间
记录下训练时每个时期所用的时间,如下所示。
+-----------------+-------------------------+
| Model | Time per epoch (in sec) |
+-----------------+-------------------------+
| MobileNetV2 | 250 |
| InceptionV3 | 400 |
| Xception | 900 |
| EfficientNet-B0 | 179 |
| EfficientNet-B1 | 250 |
| EfficientNet-B2 | 257 |
| EfficientNet-B3 | 315 |
| EfficientNet-B4 | 388 |
| EfficientNet-B5 | 500 |
+-----------------+-------------------------+
(最后两个 EfficientNets 在 Colab 上抛出内存错误,我无法训练它们。如果你想创建这样的表格,你可以使用这个。)EfficientNet-B0 轻松击败所有人,Xception 是最慢的。
推理时间
为了避免差异,我加载了一个测试图像,并测量了预测它的总时间 100 次,取其平均值。结果如下。
+-----------------+-------------------------+
| Model | Time per epoch (in sec) |
+-----------------+-------------------------+
| MobileNetV2 | 0.034 |
| InceptionV3 | 0.049 |
| Xception | 0.038 |
| EfficientNet-B0 | 0.041 |
| EfficientNet-B1 | 0.048 |
| EfficientNet-B2 | 0.049 |
| EfficientNet-B3 | 0.054 |
| EfficientNet-B4 | 0.061 |
| EfficientNet-B5 | 0.070 |
+-----------------+-------------------------+
现在,这是个惊喜!我曾觉得训练时间会指示推理时间,但一点也不。MobileNet 这次拿了蛋糕,紧随其后的是花了最多时间训练的 Xception。效率网模型中的时间随着代的增加而增加,这是随着参数数量的增加而预期的。
准确(性)
我选择不包含验证集,这样在 Kaggle 上提交 CSV 文件后会有惊喜。使用的度量标准是测井损失。它的价值越低越好。
+-----------------+----------+
| Model | Log loss |
+-----------------+----------+
| MobileNetV2 | 0.238 |
| InceptionV3 | 0.168 |
| Xception | 0.111 |
| EfficientNet-B0 | 0.205 |
| EfficientNet-B1 | 0.160 |
| EfficientNet-B2 | 0.122 |
| EfficientNet-B3 | 0.137 |
| EfficientNet-B4 | 0.126 |
| EfficientNet-B5 | 0.125 |
+-----------------+----------+
例外表现最好!!紧随其后的是其他 EfficientNet 模型,除了 EfficientNet-B0,它真正的比较对象是 MobileNetV2,它名列前茅。EfficientNet-B0 可能是移动模型的有趣选择🤔。这些结果表明,深度学习仍然像彩票一样,任何人都可以表现得更好(在可比模型中表现良好)。
全体
当我知道 EfficientNet 有 8 个模型时,我想为它创建一个整体模型,看看效果如何。我们将制作两个集合模型,一个包含 MobileNet、Inception 和 Xception,另一个包含 6 个 EfficientNet 模型。我们将创建的集合将使用 ANN 来组合这些模型。我已经写了一篇关于如何做到这一点的文章,所以如果你想了解它是如何做到的,请参考。
通过制作预训练网络的集成堆叠集成模型,如…
towardsdatascience.com](/destroy-image-classification-by-ensemble-of-pre-trained-models-f287513b7687)
在为集合模型创建数据生成器而不是产生四维(批量大小、图像高度、图像宽度、通道)的 NumPy 数组时,我们在列表中传递它的次数作为模型的数量。
img = np.zeros((batch_size, 224, 224, 3)).astype('float')
# looping and adding images to img
img = [img]*no_of_models_in_ensemble
现在加载所有的模型放入集合中,冻结它们的权重,改变层的名称,这样没有两层有相同的名称,添加一些密集的层来创建一个人工神经网络,这就完成了。
def ensemble_model(models):
for i, model in enumerate(models):
for layer in model.layers:
layer.trainable = False
layer._name = 'ensemble_' + str(i+1) + '_' + layer.name
ensemble_visible = [model.input for model in models]
ensemble_outputs = [model.output for model in models]
merge = tf.keras.layers.concatenate(ensemble_outputs)
merge = tf.keras.layers.Dense(32, activation='relu')(merge)
merge = tf.keras.layers.Dense(8, activation='relu')(merge)
output = tf.keras.layers.Dense(1, activation='sigmoid')(merge)
model = tf.keras.models.Model(inputs=ensemble_visible, outputs=output)
model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001), loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), metrics=["accuracy"])
return model
两个集合模型都被训练 10 个时期,并且它们的对数损失值是:
- MobileNet、Inception 和异常集合:0.104
- 有效净系综:0.078
第一个集合模型确实有所改进,但没有那么多。然而,有效网络集合有了很大的提高。
比较所有这些结果,我们可以看到,我们不能抹杀其他模型相比,有效的网络和提高分数的竞争集成是一条路要走。
使用 Apache Spark 轻松调整超参数
如何在 Spark 上运行随机搜索而不用编写 Spark 代码?
图片由 Gerd Altmann 从 Pixabay 拍摄
我仍然无法决定超参数调优是我在处理机器学习管道时最喜欢还是最不喜欢的步骤之一;一方面,这是通常在项目接近尾声时发生的事情:那些定义问题的会议,花在挖掘数据上的所有时间,ETL 脚本开发的数周… 遥远的记忆,是时候看看事情是否联系在一起了!另一方面,有时候我觉得自己就像 坦塔罗斯,拿不到就挂在我面前的多汁水果!
如果您曾经有过这种感觉,那么这篇文章可能是一个很好的起点,可以加速这个过程并简化您的生活,尤其是有了 Apache Spark 基础设施之后!
超参数调谐 101
我会将学习算法的超参数定义为一条在训练过程之前嵌入模型中的信息,而不是在拟合过程中导出的信息。如果模型是一个随机森林,超参数的例子有:树的最大深度或在构建森林的每个元素时要考虑多少个特征。
如果你曾经评估过一个 ML 模型的质量,你会知道没有一个放之四海而皆准的配置,因为当我们将同一个模型应用于两个不同的数据集时,它会表现出显著不同的性能;超参数调整是一个简单的过程,旨在优化配置,使我们为我们的问题选择的模型具有最佳性能。
在非常高的水平上,我们希望使用机器学习算法实现的是最小化成本函数(或最大化质量度量)f(y_hat(x),y)
,其中y_hat
是模型预测的值(给定一组已知特征x
)y
是预期结果。
考虑具有单个超参数的 ML 算法。如果我们在数据集上拟合算法并评估性能,我们将获得成本函数 **f**
的特定值。如果我们画出成本如何根据不同的超参数选择而变化,我们最终会得到如下结果:
在上图中,就成本函数而言,一个参数选择给了我们比其他参数更好的结果:我们可能应该选择那个来构建最终的模型。上面的例子中,我们有一个单一的超参数,因此,我们的搜索空间只是一条曲线。如果我们的算法支持 **2**
超参数,那么搜索空间变成一个曲面:
同样,我们将选择给出最佳成本函数的一对超参数(hp_1,hp_2)
。
当我们有 **k**
超参数时,搜索一定发生在一个 超曲面**k**
维度上;参数越多,探索就越困难。
此时我们需要的是一个在超参数空间中导航的策略。我们可以使用两种非常简单的方法:
- 网格搜索- 这种方法非常简单:对于每组参数,我们将模型拟合到我们的数据集,并评估性能。最后,我们选择产生最佳结果的组合。请注意,搜索空间通常包含数百万个点,因此通常不可能进行广泛的测试;因此,网格搜索通常会超时运行。
- 随机搜索- 该方法非常类似于网格搜索,唯一的区别是搜索空间不是以“网格”方式导航,而是随机选择要测试的超参数元组。该策略通常优于网格搜索,因为后者对探测起点非常敏感(例如,考虑网格的第一个元素远离任何可接受的参数选择的情况)。
冰山
正如我之前所写的,超参数优化只是 ML 过程的冰山一角。对于这个演示,我们实际上需要定义问题并收集数据。幸运的是,一些可爱的人已经这样做了。我们将使用 2017 年举行的 Kaggle 梅赛德斯-奔驰绿色制造竞赛。
用梅赛德斯-奔驰自己的话说:在这场比赛中,戴姆勒向卡格勒挑战,以解决维数灾难,减少汽车在测试台上花费的时间。竞争对手将使用代表梅赛德斯-奔驰汽车功能不同排列的数据集来预测通过测试所需的时间。获胜的算法将有助于加快测试速度,从而在不降低戴姆勒标准的情况下降低二氧化碳排放。
我选择这个数据集/问题的原因是:
- 任务很简单:我们有特性和一个要预测的。句号。本指南的目的不是为了在模型质量方面实现出色的性能,而是为了展示如何使用 Spark 来调整参数。我想从表格中删除所有与数据预处理相关的复杂内容(例如,我避免了图像、音频、时间序列等。).
- ****数据集很小:一个(相当)大的数据集对于超参数优化本身来说不是问题(我们可以在数据集的样本上运行模型),但是处理大量的样本是一个挑战,我不想在本文中介绍(可以在另一篇文章中介绍!).
- ****我想要一个真正的问题:我不想使用 Iris、IMDB 或 Titanic 数据集。我相信,如果例子与现实生活中的情况相似,会更有效。
- ****预处理越少,代码越简单:重点要放在火花部分;在 Python 中,没有人需要数百行预处理!
介绍够了,让我们跳到有趣的东西。
准备好;设置;XGBoost!
数据集由几个分类变量、相当多的二元变量组成,并且相关变量是连续的。奔驰混淆了表格,所以功能只知道X_i
。如果你想要一个广泛的数据分析,我建议你去比赛页面,看看由社区制作的笔记本!为评估建议的度量是 决定系数 ,R,我们将坚持使用它来比较模型。我们将使用XGBoost来做预测, 一个优化的分布式梯度增强库,在 梯度增强 框架下实现机器学习算法【1】
梅赛德斯-奔驰数据集示例
我们试图实现的是使用 Spark 基础设施运行并行网格/随机搜索。 Apache Spark 自带一些机器学习工具(ml lib)。** 别提了!**
我可以听到你的反对意见:是的,XGBoost 网格搜索可以使用 MLLib 管道来实现(有一个 Nan Zhu 提供的很好的平台,解释了如何做到这一点),但是我认为 MLLib 没有为参数调整提供足够的灵活性:归根结底,你可能想要使用一个更智能的算法,纯 Python 将使实现更容易;有了下面的想法,你应该能够运行多种类型的搜索(贝叶斯,遗传)而不用忙于处理 Spark APIs:所有的东西大部分都是用普通的 Python 编写的!
方法学
让我们再做一步,定义什么是高级方法论。对于本文的范围来说,我们需要做一个最小的预处理:唯一的目的是让数据集对 XGBoost 可读。
我们要做的事情很简单:
- ****删除 ID 列:由于显而易见的原因,我们不想将 ID 提供给 XGBoost。
- ****对分类变量进行编码:我们将使用简单的均值编码(即对于每个类别,我们将其标签设置为一个训练数据 上目标变量的均值)。
预处理功能
正如我在上面指出的,比赛是基于 R 的,所以我们将继续使用这个指标来探究模型的性能;更准确地说,评估算法如下:
1\. Pick a set of hyperparameters2\. Perform 4-folds [Cross-Validation](https://en.wikipedia.org/wiki/Cross-validation_(statistics))3\. Get the average **R² score for the 4 runs and store it** 4\. Goto 1\. until timeout5\. Select the parameters with the **highest** average score (**R²=1 is the perfect model**)
厉害!现在我们终于准备好实现算法了!
定义搜索空间
运行网格或随机搜索的第一步是定义搜索空间。XGBoost 有很多很多参数可以在装配前设置。对于我们的问题,我们将使用 tree booster(库也提供了其他选项),我们将只关注以下参数:
learning_rate : 更新中使用的步长收缩,防止过拟合。在每个增强步骤之后,我们可以直接获得新特征的权重,并且 *eta*
缩小特征权重以使增强过程更加保守。【 xgboost 参数】**
colsample_bytree : 是构造每棵树时列的子样率。对于每个构建的树,进行一次子采样。【 xgboost 参数】**
子样本 : 训练实例的子样本比率。将其设置为 0.5 意味着 XGBoost 会在生成树之前随机采样一半的训练数据。这将防止过度拟合。子采样将在每个增强迭代中出现一次。xgboost 参数**
n_estimators :算法使用的树的数量。
reg_alpha : 权重上的 L1 正则项。增加该值将使模型更加保守。【 xgboost 参数】**
最大深度 : 一棵树的最大深度。增加该值将使模型更加复杂,并且更有可能过度拟合。【 xgboost 参数】**
gamma : 在树的叶子节点上做进一步划分所需的最小损失减少。 *gamma*
越大,算法就越保守。【 xgboost 参数】**
可以想象,以上是一个相当大的搜索空间!然而,当我们进行超参数调整时,我们并不是完全在黑暗中摸索。许多 ML 方法(以及 XGBoost)都有指导原则,可以帮助为网格的所有参数定义有意义的范围。比如,即使知道learning_rate
可以在[0,1]
,接近1
的值也不太可能有好结果。以下 Python 字典代表了我为 Mercedes-Benz 问题选择的搜索空间:
上面的字典将导致 6,890,400 个点进行探测。注意,即使每个测试需要 1 秒钟完成,我们也需要大约 79 天 18 小时的连续计算时间来探索整个网格!网格搜索永远不会尝试所有那些组合。
以下函数将网格作为 Python 生成器返回(以避免在内存中有大数据结构):
局部网格和随机搜索
现在我们有了搜索空间,让我们试着在本地实现网格搜索。
首先,我们需要一个方法来评估 R :
然后我们用下面的签名定义一个函数grid_search
:
**grid_search(timeout_seconds, cv_splits, boosting_rounds)**
搜索算法将在T5 之后终止。交叉验证将使用cv_splits
数量的分割,XGBoost 将使用boosting_rounds
迭代:
此外,我们将收集熊猫数据框架中的结果进行分析:
太棒了。让我们运行上面的代码一个小时,喝杯咖啡,把结果留到以后。
随机搜索
我们可以回收上面的大部分代码来实现随机搜索,唯一的区别是我们不需要预定义网格:我们可以只声明一个函数,返回探索面的一个随机点:
然后我们可以稍微修改一下网格搜索循环:
再次:跑步,咖啡,等待结果。
让我们随机搜索火花吧!
本文的要点是解释如何使用 Spark 基础设施来并行化上述算法。我们将只关注随机搜索。
我们可以使用各种策略来解决这个问题:
- 用户定义函数(UDF):我们可以实现一个 Spark UDF。例如,我们可以创建一个 dataframe,在一列中包含网格的所有元素,然后对该列应用 UDF,使用这些值作为 XGBoost 的输入参数。这个解决方案有几个缺点:首先我承诺过你会在没有火花知识的情况下运行这个算法,UDF 并不是一个很好的维持这个承诺的起点。第二点是,在各种 UDF 之间共享训练数据集可能是不安全的(可能有共享变量?欢迎评论中的建议!).
- MLLib :同样,这是 Spark 的一个相当高级的用例,我认为它不够灵活。
- 带有 Spark 后端的 Joblib:我们要用这个!你们中的许多人,可能已经知道 Joblib, 一套工具提供了Python 中的轻量级流水线操作 (函数的透明磁盘缓存和惰性重求值(memoize 模式),轻松简单的并行计算)。Joblib 特别针对大数据优化为 快速*健壮 ,并针对 numpy 数组* 进行了具体优化。对你来说可能听起来很新鲜的是,Joblib 有一个方便的 Spark 后端。通过几行代码,我们将直接在 Spark 上运行并行循环,而无需编写 Spark 代码!
在查看实现之前,我们需要指定我们将使用的架构。特别是,一旦算法有了交叉验证的结果,它将需要在“某个地方”把它们吐出来(供我们收集和分析)。我们将使用一个 MongoDB 实例:
上图显示我们将在 Jupyter 笔记本中有一个入口点。通过其中一个单元,我们将使用 Joblib-Spark 将执行发送到不同的节点;此外,在每个节点上,我们将使用普通 Joblib 来启用多线程。最后,每个执行器将把结果写在位于另一个服务器上的 MongoDB 实例中。
预处理代码将保持不变,我们可以重用该函数来生成随机组合,所以让我们编写一个神奇的循环:
Joblib 魔术发生在下面一行:
**Parallel(backend="spark", n_jobs=NODES)(delayed(evaluate)(X, y, kf, boosting_rounds) for p in range(0, NODES))**
让我们来分解一下:
Parallel
初始化 Joblib 环境。在这种情况下,我们需要指定后端(即“spark”)。- 涉及到一些“全局”变量;一个重要的参数是
NODES
,即集群中的节点数量。我们正在做的是将网格分成**NODES=3**
块,并将每个块发送给一个 Spark 执行器。 delayed
只是一个装饰器,用来捕获函数的参数(在这里是evaluate
,我们将在后面定义它)。需要for p in range(0, NODES)
来告诉Parallel
执行delayed
函数多少次(在这种情况下只执行**NODES**
次,因为执行程序将运行测试,直到超时发生**X
、y
、kf
和boosting_rounds
是evaluate
功能的参数。
引擎盖下发生了什么? Joblib-Spark 将通过网络发送函数(使用cloud-pickle进行序列化)。然后通过parallelize
Spark 方法,每个执行将被发送到单个节点。
我们需要构建将在每个 Spark 机器上执行的evaluate
函数:
如你所见,我们在evaluate
中定义了一个内部函数。这是必要的,因为除了在 Spark 上并行化网格搜索,我们还想在单个执行器上使用多线程。下面一行显示了默认后端的(普通)Joblib 的用法:
**Parallel()(delayed(evaluate_inner)(keys, g, X, y, kf, boosting_rounds) for g in df_grid)**
让我们运行上面的random_search_spark
函数一个小时,并将结果保存在我们的 MongoDB 实例中。我们希望在 Spark UI 上看到的是三个阶段,每个阶段将运行一个小时:
35 分钟后触发用户界面
60 分钟后的 Spark UI 任务失败,因为 Spark 上下文在超时后终止
比较和结论
旅程即将结束。我们已经收集了所有的结果,我们只需要分析它们!
Spark 测试一直在由 3 台机器(1 个驱动程序+ 2 个执行器)组成的集群上运行,每台机器有 4 个内核,而“本地”搜索算法一直在单台机器上执行。我们对所有的方法都使用了下面的常数。
**CV_SPLITS = 4 # Number of CV splits
TIMEOUT_SECONDS = 3600 # Timeout is 1 hour
BOOSTING_ROUNDS = 500 # XGBoost boosting rounds**
第一个有趣的发现是简单地比较每种方法执行了多少测试:
在这种情况下,我们获得了 3 倍的提升,这是给定节点数量的线性增长(注意:“本地”版本仍然有 4 个内核可用)。
为了了解方法“如何”探索超曲面,让我们画出算法获得的R:
在单台机器上使用网格搜索通过 4 倍 CV 获得的平均 R
在单台机器上使用随机搜索通过 4 倍 CV 获得的平均 R
在火花(3 个节点)上使用网格搜索通过 4 倍 CV 获得的平均 R
从上面的图表中,至少可以看出两点:
- 网格搜索探索似乎没那么有效。请注意曲线中的水平部分:每个部分中变化的参数对分数的影响非常小,因此可能不值得深入探究(当然,为了简单起见,我没有考虑参数之间的相互依赖性)。****
- Spark 并行化是可取的,因为它可以荒谬地增加尝试的次数。
通过这些方法找到的最佳参数:
****Grid Search (Local)**
Best **R²**: 0.5656Params:
learning_rate: 0.01,
colsample_bytree: 0.8,
subsample: 0.5,
n_estimators: 100,
reg_alpha: 0.01,
max_depth: 3,
gamma:0**Random Search (Local)**
Best **R²**: 0.5648Params:
learning_rate: 0.0354,
colsample_bytree: 0.88,
subsample: 0.8,
n_estimators: 1410,
reg_alpha: 0.10,
max_depth: 3,
gamma:0**Random Search (Spark)**
Best **R²**: 0.5643Params:
learning_rate:0.0524,
colsample_bytree:0.93,
subsample:0.88,
n_estimators:1413,
reg_alpha:0.409,
max_depth:3,
gamma:7**
注意网格搜索赢了,即使它只能做 32 次尝试!以上结果的结果是我们可能应该重新考虑调整哪些超参数以及如何定义网格/范围。例如,我们可以看到,所有的方法都同意这样的事实,即learning_rate
应该在[0.01,0.05]
中,而在我们的网格中,我们将最大值设置为0.25
: 我们可能浪费了大量的计算时间来寻找超曲面的错误区域! (旁注: *max_depth=3*
让我想到,也许,很多变量可以从数据集中剔除,但那是另一回事)。****
我认为上面的结果可以引出下面的问题:我们是否可以在探索算法中加入一些智能,做一些比这更聪明的事情?答案是“是的,我们可以”,但那是另一篇文章的主题!离开之前,如果你读到这里,你值得拥有 链接到最后的笔记本 !
外卖食品
- Joblib-Spark 可以成为在 Spark 基础设施上扩展算法的强大工具。其中一个主要优势是它不需要使用 Spark APIs 进行开发:要使用它,您不需要对 Apache 的分布式计算系统有很深的理解。
- Joblib 可能允许你用相对较小的努力提升和移动你现有的管道。
- 网格搜索和随机搜索是两种非常简单的方法,可用于进行超参数调整,并且易于实现。****
- 随机搜索通常优于网格搜索。
- 网格和随机搜索在超参数调优方面并不是最好的,因为它们没有利用已经执行的测试来理解探索过程中的方向。****
我希望你喜欢!让我知道你的想法,如果你愿意,看看这些其他的文章!
Spark 中加速连接的实用技巧
towardsdatascience.com](/the-art-of-joining-in-spark-dcbd33d693c) [## 聚类波洛克
杰森·布拉克绘画的聚类分析——如何利用 k-means 进行色彩分组
towardsdatascience.com](/clustering-pollock-1ec24c9cf447)****
轻松推荐相似图片
使用来自预训练卷积神经网络的特征来产生可比性
自动选择相似图像(来源:M. D. Korzec)
让我们来解决这样一个问题:拥有一个无序的、庞大的图像集,我们希望从中找到一个相似图像的子集。该解决方案产生了基于图像的项目-项目推荐系统,该系统可以用于例如在线商店。为此,我们将使用迁移学习,利用预先训练的卷积神经网络。
私人图片(来源:M. D. Korzec)
这些来自我私人收藏的图片包含了不同的动机,当面对成千上万的图片时,找到最相似的就变得非常困难了。利用所呈现的解决方案,我们将基于图像内容(即,不基于其元数据)获得相似性值,如下面的示例中来自相同图像集的相似性值。第一个图像描述了查询的参考图像,一辆我们在欧洲休产假时使用的货车,停在法国某处的山羊农场上。
具有相似值的与查询图像相似的图像(来源:M. D. Korzec)
在下面一行中,我们可以看到算法选择的最相似的图像。照片下面的数字是从 0 到 1 的相似度值,1 是可能的最高相似度。不仅显示了红色货车的图像,而且由于所有其他相似之处,我们第一次租赁的黄色货车由于水泵故障而需要更换。
许多在线产品可以与这样的推荐器一起工作,以提高转化率,无论是摄影师的收藏、电影推荐,还是可以从图像相似性中受益的其他商店(例如,CD 封面或视觉相似性可能增加转化率的其他产品)。这种基于项目的推荐系统被称为基于内容的推荐系统。欲了解更多信息,您可以参考[1]或快速进入关于走向数据科学 [2,3]的博客条目。
如果您已经具备 Python 和图像处理的基础知识,那么有一种非常简单的方法可以获得这样的建议。在接下来的段落中,我将为一组固定的图像提供其背后的高级逻辑:
1.获取和预处理数据
2.使用经过训练的卷积神经网络作为特征向量生成器
3.使用特征向量差异来计算相似性
4.使用最佳推荐列表
您可以使用现成的神经网络,不需要模型工程或培训。没有必要清理元数据,没有隐藏的工作,你只需要建立一个有效的数据处理一次,没有额外的工作。
1。获取并预处理数据
即使要实现一个原型,也需要一个大的图像测试集。我使用了 Coco 系列的一部分,结果令人印象深刻。在 15000 张图片中,推荐者发现了非常相似的内容。然而,由于这些图片根据用户在 Flickr 中的选择有不同的许可,所以我没有在这里发布这些结果。相反,我为这个博客创建了一个不同的测试集。所有上传的图片都来自我的本地图片库,大约有 5000 张图片,都是 jpg 格式,随着相机的改变,分辨率也有所不同。
预训练的深度神经网络需要特定格式的输入图像。对于本文,我在 PyTorch 库中使用 resnet18 [5],它需要 224x224 RGB 图像作为输入,图像值在范围[0,1]内。图像被标准化为具有平均值[0.485,0.456,0.406]和标准偏差[0.229,0.224,0.225],因此它们都被重新缩放以适应这种格式(注意不要在变换过程中丢失关于图像方向的元数据)。关于特定实现的细节将在我的下一篇博客中介绍。如果要使用其他卷积神经网络,先检查输入要求,并相应调整预处理。此外,请注意,这里 resnet18 的权重是从 ImageNet 上的训练中获得的。请记住,训练集和测试集应该是不同的。
2。使用经过训练的卷积神经网络作为特征向量生成器
当你第一次意识到与图像相关的神经网络的一个特征时,你可能会大吃一惊:
经过训练的卷积神经网络可以创建特征向量,通过比较这些特征向量来计算图像的相似性。
使用高级特征向量,而不是努力寻找用经典的图像处理方法来表征图像的方法,这些方法可用于比较它们(例如,从不同方向和局部边缘密度的边缘检测开始,然后扩展到不包括这些的所有情况)。可用的、经过训练的模型已经提供了你需要的一切,当它们在具有高动机可变性的巨大图像集上被训练时。你不需要理解向量的任何条目,你只需要知道相似的图像会有相似的条目。
以下示意图解释了将核心网络视为黑盒时特征和分类向量的计算
作为黑盒的卷积神经网络(来源:M. D. Korzec)
M>n,特征向量包含了大量加密图像的高层描述。因此,当抽象中间的所有层并忽略不用于推荐器的分类向量时,我们只处理一个函数
这是高中就熟悉的。这里,x 是中的矢量化 RGB 图像
当使用预先训练的模型时,所有的参数都是固定的,所以没有更多的自由变量,这里也没有列出。如第一部分所述,必须对给定的图像进行预处理,以适应所用网络的输入格式。
你不需要做的事情
当你想从头开始训练你的网络时,你需要
- 手动准备大量数据(图像-分类向量-对)
- 花时间在一些优化上
分类向量(例如,“图像包含汽车”可以由一个单位向量表示,该单位向量的位置表示汽车)是固定的,输入是固定的,并且网络的权重被优化以获得尽可能接近真实分类向量的猜测分类向量。f(x)的被充分研究的形式允许在优化迭代期间使用的自动微分的帮助下优化权重,并且首先使得深度神经网络的使用成为可能。如果你有兴趣了解更多相关话题,你可以参考一位前研究同事关于这个话题的博客文章[6]。
在具有更多条目的分类层之前的完全连接的一维层是图像内容的高级加密描述。早期图层仅描述低级特征(如边),分类向量可能相当小,因此最后一个完全连接的图层是一个不错的选择。它将包含有用的值,即使图像的内容在学习期间没有被分类。
因此,我们知道,我们可以省去训练神经网络的努力,我们仍然可以通过一个函数调用 f(x)从图像输入 x 中获得特征向量。然后,我们可以很容易地确定一个图像何时与另一个图像或多或少相似。
3。使用特征向量差异计算相似度
为了比较从不同图像的卷积神经网络的评估中导出的特征向量,采用余弦相似性是一种很好且简单的方法。在这里,你基本上只是计算所有图像对的余弦公式,对整个图像集这样做产生一个相似性矩阵。
余弦相似性(来源:M. D. Korzec)
在二维空间中,如上所示,该公式易于解释和可视化。它在更高维度中以同样的方式工作,例如考虑三个向量
凭直觉,a 和 b 的相似性应该高于 a 和 c 或 b 和 c 的相似性。事实上,当把这些数字代入上述公式时,人们会发现
因此,不出所料,
相似性计算是推荐系统中的主要课题之一[1]。在我们的例子中,也应该使用一些其他的度量来描述向量之间的差异。
4。使用最佳建议列表
因此,总的来说,当比较两个图像时,我们已经推导出要执行的以下逻辑步骤
比较两幅图像(来源:M. D. Korzec)
您只需要迭代感兴趣的集合中的所有图像。所有导出条目(s_kl)一起定义了完整的相似性矩阵。然而,当使用在线推荐的结果时,使用完整的相似性矩阵是没有效率的。当对最相似的图像感兴趣时,为了效率,可以通过相似性值对元素进行排序,并使用前 k 个列表,即最相似的 k 个图像。因此,来自矩阵(s_kl)的行 k 从大到小排序,并且高度相似的图像被保留并用于推荐。下图解释了用于从相似性矩阵生成前 4 个列表的较小向量/矩阵的集合。
相似性矩阵和前 4 个列表(来源:M. D. Korzec)
较暗的区块表示与该行中表示的图像最相似的四个图像,并且为了有效的请求而分开存储。当然,在典型的应用程序中,您会使用四个以上。
当您在 top-k 列表中有了所有排序的信息并接收到一个查询作为输入时,您只需转到该特定图像的相应行,并显示存储有相应行中存储的 id 的图像。
外卖信息
- 当我们想要获得基于图像的推荐时,经过训练的卷积神经网络可以完成这项工作。
- 我们使用预先训练的模型,所以没有必要建立一个训练管道。
- 我们本质上只评估一个函数来获得特征向量。
- 我们通过计算余弦来比较特征向量。
- 当新的图像被添加到集合中时,需要更新新的相似性值和 top-k 列表。
- 当您从足够大的图像集和训练有素的模型开始时,不存在冷启动问题。
如果你有 Python 代码涵盖了上述推荐者的想法,并且它将被用在一个网站上,有多种方法可以做到这一点。在我的下一篇文章中,我将解释上述步骤的 Python 实现的要点,并且我将解释如何建立一个简单的基于 Flask 的网站来使用这些结果。
测试集中相似的蒲公英图片(来源:M. D. Korzec)
[1] C. C. Aggarwal,推荐系统——教科书 (2016),施普林格
[2] P. Pandey,推荐系统的非凡世界 (2019),走向数据科学
[3] B. Rocca 和 J. Rocca,推荐系统介绍 (2019),走向数据科学
[4] T.-Y. Lin 等著,微软 COCO:情境中的通用对象(2014);使用:测试数据 2017
[5]何国光,张,任,孙,【深度残差学习用于图像识别】,2015
[6]m . KPF,面向机器的高中数学:可微分编程 (2020),面向数据科学
感谢阅读!喜欢这个话题吗?
如果你觉得这篇文章很有趣,你可能想看看我在这个主题上的其他文章:
推荐系统的重要性评估
medium.com](https://medium.com/swlh/the-core-value-of-recommender-systems-for-successful-internet-enterprises-7164a7bacdc6) [## 使用 PyTorch 推荐相似图片
使用 Resnet18 实现完全迁移学习
towardsdatascience.com](/recommending-similar-images-using-pytorch-da019282770c) [## 一个推荐图片的 Flask 应用程序
PyTorch 中基于卷积神经网络的相似图像推荐网站原型
medium.com](https://medium.com/@maciek.korzec/a-flask-app-for-image-recommendations-a865e1496a0d) [## py torch+Flask+PostgreSQL+Heroku 部署的映像建议
用 Flask 封装一个基于 PostgreSQL/ PyTorch 的图像推荐系统,导入数据并在 Heroku 上运行
towardsdatascience.com](/image-recommendations-with-pytorch-flask-postgresql-heroku-deployment-206682d06c6b)
efsync 我的第一个开源 MLOps 工具包
自动将 Python 依赖项和 ML 模型同步到 AWS Lambda 函数的 AWS EFS
谢栋豪在 Unsplash 上的照片
原载于https://www . philschmid . de。
介绍
在生产中成功使用机器学习的一部分是 MLOps 的使用。MLOps 通过持续培训(CT)增强 DevOps。因此,MLOps 的主要组成部分包括持续集成(CI)、持续交付(CD)和持续培训(CT)。 Nvidia 写了一篇文章详细介绍了什么是 MLOps。
我叫菲利普,住在德国的纽伦堡。目前,我在一家科技孵化创业公司担任机器学习工程师。在工作中,我为金融科技和保险公司设计并实现了云原生机器学习架构。我是无服务器和以无服务器方式提供机器学习模型的忠实粉丝。我已经写了两篇关于如何在 AWS Lambda 这样的无服务器环境中使用 BERT 这样的深度学习模型的文章。
在使用像 AWS Lambda 、 Google Cloud Functions 、 Azure Functions 这样的工具进行无服务器机器学习时,要克服的一个大障碍是存储。Tensorflow 和 Pytorch 的尺寸很大,像 BERT 这样的新型“艺术级”模型的尺寸超过 300MB。
今年 7 月,AWS 增加了对亚马逊弹性文件系统(EFS) 的支持,这是一个适用于 AWS Lambda 的可扩展的弹性 NFS 文件系统。这允许我们将 AWS EFS 文件系统挂载到 AWS Lambda 函数。
直到今天,将依赖项或模型文件同步到 AWS EFS 文件系统还是非常困难的。你可以用 AWS Datasync 来做这件事,或者你可以在同一个子网和 VPC 中启动一个 EC2 实例,并从那里上传你的文件。
为此,我构建了一个名为 efsync 的 MLOps 工具包。Efsync 是一个 CLI/SDK 工具,它自动将文件从 S3 或本地文件系统同步到 AWS EFS,并使您能够将 AWS Lambda 运行时的依赖项直接安装到您的 EFS 文件系统中。CLI 易于使用,您只需要访问一个 AWS 帐户和一个启动并运行的 AWS EFS 文件系统。
体系结构
作者创建的 efsync 架构
快速启动
-
通过 pip3 安装
-
将您的 pip 依赖项或文件同步到 AWS EFS
用例
Efsync 涵盖 5 种使用情形。一方面,它允许您安装所需的依赖项,另一方面,efsync 帮助您准备好您的模型,无论是通过从 S3 到 EFS 的同步还是使用 SCP 的本地上传。我为每个用例创建了一个示例 Jupyter 笔记本。
这 5 个使用案例包括:
- 将 Python 与 AWS Lambda 运行时的依赖项直接安装到 EFS 文件系统中,并在 AWS Lambda 函数中使用它们。 例题
- 将 S3 的文件同步到 EFS 的文件系统。 例题
- 使用 SCP 将文件上传到 EFS 文件系统。 例题
- 安装 Python 依赖项,并从 S3 同步到 EFS 文件系统。 例题
- 用 SCP 和 EFS 文件系统安装 Python 依赖项和上传文件。 例题
注: 每个例子都可以在 Google Colab 中运行。
实施配置可能性
在项目中使用 efsync 有 4 种不同的方式:
- 您可以创建一个
yaml
配置并使用 SDK。 - 你可以创建一个 python
dict
并使用 SDK。 - 您可以创建一个
yaml
配置并使用 CLI。 - 您可以使用带参数的 CLI。
您可以在 Github 资源库中找到每个配置的示例。我还包括了不同用例的配置示例。
注意 :如果你用 scp 从本地目录(如 *model/bert*
)同步一个文件到 efs ( *my_efs_model*
) efsync 会把模型同步到 *my_efs_model/bert*
,这是因为 SCP 递归上传文件。
例子
下面的例子展示了如何将 Python 依赖项安装到 EFS 文件系统,然后将文件从 S3 同步到 EFS 文件系统。出于配置目的,我们必须创建一个efsync.yaml
和一个requirements.txt
文件来保存我们的依赖项和配置。
1。安装 efsync
2。创建一个 **requirements.txt**
和依赖关系
3。用所有需要的配置创建一个 **efsync.yaml**
efsync.yaml
包含所有配置,例如:
标准配置
efs_filesystem_id
:AWS EFS 文件系统 id(挂载点)。subnet_Id
:EFS 文件系统的子网 Id,它运行在。ec2_key_name
:启动 EC2 实例所需的键名。aws_profile
:在.aws/credentials
中配置的具有所需权限的 IAM 配置文件。aws_region
:EFS 文件系统正在运行的 AWS 区域。
Pip 依赖关系配置
efs_pip_dir
:EC2 上的 pip 目录,将在此安装依赖项。python_version
: 用于安装 pip 包的 Python 版本- >应该作为 lambda 运行时使用。requirements
:requirements . txt 的路径+文件,该文件包含可安装的 pip 依赖项。
S3 配置
s3_bucket
: S3 斗名从文件中应下载。s3_keyprefix
: S3 keyprefix 为目录/文件file_dir_on_ec2
:保存 S3 文件的目录名
4。运行 efsync wit **efsync.yaml**
摘要
使用ef sync您可以轻松地将文件从 S3 或本地文件系统自动同步到 AWS EFS,并允许您将 AWS Lambda 运行时的依赖项直接安装到您的 EFS 文件系统中。从 S3 安装和同步文件大约需要 6 分钟,安装依赖项大约需要 4-5 分钟,同步文件大约需要 2 分钟。****
你可以在 Github 上找到库。如果您有任何问题或改进,请随时创建拉动式请求或问题。
感谢阅读。如果你有任何问题,随时联系我或评论这篇文章。你也可以在 Twitter 或者 LinkedIn 上和我联系。
特征脸 Python 中的人脸分类
深度学习的数据不够?试试特征脸。
如今,我们可以使用神经网络来执行最先进的图像分类,或在这种情况下的人脸分类。但是采取一种更简单的方法怎么样呢?这就是本文的目的。
官方回购: 访问这里 获取数据和代码。
最初,将原始像素值作为输入特征的想法可能看起来很愚蠢——这很可能是真的,主要是因为我们会丢失所有的 2D 信息,而且还有卷积神经网络来提取重要的特征(因为不是所有的像素都相关)。
今天我们将介绍特征脸算法的思想——它只是一种应用于人脸识别问题的主成分分析。通过这样做,我们希望降低数据集的维度,只保留解释最大差异的成分,然后应用简单的分类算法(如 SVM)来完成分类任务。
听起来像是一个计划,但是在阅读这篇文章之前,你应该知道什么? 这是个好问题。你要精通 Python 和它的数据分析库,也要知道什么是主成分分析,至少在高层是这样的。
还在读书?那我想你已经具备了先决条件。在开始编写代码之前,我们要讨论的最后一件事是文章结构,可以列举如下:
- 导入和数据集浏览
- 图像可视化
- 主成分分析
- 模型培训和评估
- 结论
好了,事不宜迟,我们开始吧!
导入和数据集浏览
正如您可能已经预料到的那样,我们将需要常见的怀疑对象— Numpy 、 Pandas 和 Matplotlib ,但也将使用来自 ScikitLearn 的一堆东西—像 SVM、PCA、train test split 和一些用于评估模型性能的指标。
下面是所有的进口:
import numpy as np
import pandas as pd
import matplotlib.pyplot as pltfrom sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
from sklearn.metrics import confusion_matrix, classification_reportimport warnings
warnings.filterwarnings(‘ignore’)
至于数据集,我们已经在 GitHub 上找到了,但现在似乎找不到了。可以从我的 GitHub 页面下载。
下面是你如何把它装载到熊猫身上:
df = pd.read_csv(‘face_data.csv’)
df.head()
现在,我们可以快速检查数据集的形状:
df.shape**>>> (400, 4097)**
所以,400 行和 4097 列,一个奇怪的组合。对于这些列,我们这里有归一化像素值(表示范围(0,1)内的值),最后我们有一个目标列,指示照片上的人是谁。
如果我们仔细看看目标列的唯一元素的数量,我们会得到数据集中的总人数:
df[‘target’].nunique()**>>> 40**
由于我们有 4096 个功能,这是一个单一颜色通道中 64x64 图像的清晰指示器:
64 * 64**>>> 4096**
太好了,我们现在有了关于数据集的一些基本信息,在下一节中,我们将进行一些可视化。
图像可视化
为了可视化几张脸,我们将声明一个将 1D 向量转换为 2D 矩阵的函数,并使用 Matplotlib 的 imshow 功能将其显示为灰度图像:
def plot_faces(pixels):
fig, axes = plt.subplots(5, 5, figsize=(6, 6))
for i, ax in enumerate(axes.flat):
ax.imshow(np.array(pixels)[i].reshape(64, 64), cmap=’gray’)
plt.show()
但是在绘制之前,我们需要将特征从目标中分离出来,否则,我们的数据集将溢出 64x64 矩阵边界:
X = df.drop(‘target’, axis=1)
y = df[‘target’]
就这样,现在我们可以使用声明的函数了:
这部分就讲到这里。下一次,我们将执行训练测试分割和 PCA。
主成分分析
本节的目标是通过只保留那些解释最大差异的成分来减少问题的维度。简而言之,这是常设仲裁院的一个目标。但在此之前,我们必须将数据集分成训练和测试部分:
X_train, X_test, y_train, y_test = train_test_split(X, y)
现在,我们可以将主成分分析应用于训练特征。然后很容易画出解释方差的累积和,这样我们就可以近似得出多少个主成分就足够了:
pca = PCA().fit(X_train)plt.figure(figsize=(18, 7))
plt.plot(pca.explained_variance_ratio_.cumsum(), lw=3)
仅通过查看图表,看起来大约 100 个主成分将保持大约 95%的方差,但让我们验证一下这一说法:
np.where(pca.explained_variance_ratio_.cumsum() > 0.95)
是的,看起来 105 个组件就够了。记住,95%不是一成不变的,你可以自由选择更低或更高的百分比。
让我们再次执行 PCA,但这次使用了额外的 n_components 参数:
pca = PCA(n_components=105).fit(X_train)
最后,我们必须转变培训功能:
X_train_pca = pca.transform(X_train)
太好了!这一节就到这里,下一节我们将训练和评估 SVM 模型。
模型培训和评估
到目前为止,培训功能已经发生了变化。训练模型的过程非常简单,只需制作一个实例并拟合训练数据即可:
classifier = SVC().fit(X_train_pca, y_train)
厉害!模型现在已经训练好了,为了在测试集上对它进行评估,我们首先需要将测试特征带到同一个特征空间。一旦完成,SVM 就被用来做预测:
X_test_pca = pca.transform(X_test)
predictions = classifier.predict(X_test_pca)
现在我们终于可以看到它的表现了。为此,我们将使用来自 ScikitLearn 的分类 _ 报告,因为它比 40x40 混淆矩阵更容易查看:
print(classification_report(y_test, predictions))
所以大约 90%的准确率,对于 40 个不同的类和默认模型来说当然不可怕。
对于本文来说就是这样,让我们在下一节快速浏览一下可能的改进领域。
结论
这是一个相当快速的指南——故意的。您可以自由地执行网格搜索来为分类器找到最佳超参数,或者甚至使用完全不同的算法。
此外,尝试选择 90%和 99%的解释方差比率,以查看模型性能如何变化。
感谢您的阅读,欢迎在评论区留下您的想法。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
特征值和特征向量
计算和可视化
这里有动画:https://BDS haff . github . io/BDS haff . github . io/blog/2020-03-23-计算-特征值-特征向量/
这是怎么回事
- 首先,我将谈谈是什么让我对特征值实际上是如何计算的感到好奇。
- 然后我分享一下我实现最简单的算法( QR 方法 )做一些基准测试。
- 最后,我将分享你如何将算法寻找特征向量的步骤动画化!
他们无处不在
特征值和特征向量在数学中随处可见,尤其是应用数学。统计学、机器学习、数据科学都属于这个范畴。
前段时间决定通过实现主成分分析( PCA )来学习 Rcpp 和 C++。我知道 PCA 问题的解决方案是样本方差-协方差矩阵的特征值分解。我意识到我需要用 C++编写我自己版本的内置eigen
函数,那时我意识到除了一个 2x2 案例,我不知道eigen
实际上是如何工作的。我发现的是我在这里读到的的 QR 法 。
为什么 n > 2 不一样
有了一个 2x2 矩阵,我们可以手动求解特征值。这是可行的,因为一个 2x2 矩阵的行列式是一个二次多项式,所以我们可以用正规代数来分解和求解它。但是如何计算大型矩阵的特征值呢?事实证明,当你不能分解和求解多项式时,你真正应该做的是分解矩阵。纯属巧合的是,数字爱好者 YouTube 频道最近发布了一个关于这个想法的视频在这里。如果你对这种类型的内容感兴趣,值得一试!
快速复习:它们是什么?
首先,快速复习一下什么是特征值和特征向量。取一个方阵 X 。如果有一个矢量 v 和一个标量 λ 这样
那么 v 就是XT5T7λ就是X 对应的特征值。
换句话说,如果你把 v 乘以 X 看作是对v 应用一个函数,那么对于这个特定的向量 v 来说,这个函数不过是一个拉伸/挤压标量乘法。通常,将一个向量乘以一个矩阵等于取向量分量的线性组合。但是如果你取一个特征向量,你不需要做所有的计算。只要乘以特征值就都好了。
计算:QR 方法
计算特征值和特征向量的 QR 法 从我心爱的 QR 矩阵分解开始。我在之前的帖子中写过。这种分解允许将矩阵 X=QR 表示为正交矩阵 Q 和上三角矩阵 R 的乘积。同样, Q 正交的事实很重要。
用于寻找特征值的 QR 方法 的中心思想是将 QR 矩阵分解迭代应用于原始矩阵 X 。
相似矩阵
这里我需要提一下 X 的特征值的一个数学性质。如果我们取任何一个可逆矩阵 M 那么这个矩阵
将具有与 X 相同的特征值。这样的矩阵 E 和 X 在形式上定义为 相似矩阵 ,简单来说就是它们具有相同的特征值。然而特征向量将会不同。同样,回想一下 QR 中的 Q 是正交的,因此是必然的。
QR 算法
所以, QR 方法 的思想是迭代以下步骤
- 将 QR 分解应用于 X 以便
2.让
和计算
注: E 是 类似于 到 X 。它们的特征值是相同的。
3.然后分解
4.因此
和
5.用 E 迭代单元本质上是对角的。
当 E 是对角线时,你得到的是对角线上的特征值,而 V 是特征向量!
这是 QR 法的最简单版本。有几个改进的版本,我就不赘述了,但是你可以在这里读到它们。
接下来,我想用 R 和 C++编写一个函数来实现这个方法,并验证它是否有效。
简单实现
我们将这样做:
- 展示一个用
R
编写的函数,该函数明确实现了用于寻找特征值的 QR 方法 。 - 通过将结果与内置的
eigen
函数进行比较来验证它是否工作。 - 在
C++
中实现相同的功能,并通过myc
包可用。验证它是否也能正常工作。 - 最后,比较它们的性能。
以下是我将使用的软件包:
library(tidyverse)
library(microbenchmark)
library(plotly)
library(myc)
R 函数
my_eigen
是一个非常简单的函数。前几行执行 QR 方法 的初始迭代。然后 while 循环迭代,直到 E 矩阵的对角线稳定下来,并且不再变化超过小的余量。带有values
和vectors
的返回列表应该与eigen
函数返回的相同。对于 QR 分解 步骤,我使用的是myc
包中的myc_qr
。
my_eigen <- function(A, margin = 1e-20) {
Q <- myc_qr(A)$Q
E <- t(Q) %*% A %*% Q
U <- Q
res <- diag(E)
init <- diag(A)
while (sum((init - res)^2) > margin) {
init <- res
Q <- myc_qr(E)$Q
E <- t(Q) %*% E %*% Q
U <- U %*% Q
res <- diag(E)
}
return(list(values = round(diag(E), 6), vecotrs = U))
}
验证它是否有效
让我们检查一下它是否工作。我将使用对称矩阵,因为我想确保特征值不是复数。
X <- matrix(c(
3, 2, 3, 2,
5, 1, 5, 4,
9, 3, 2, 1,
4, 5, 6, 7
), ncol = 4)
A <- t(X) %*% X
这是一个矩阵,我将使用它来验证我的函数是否按预期工作。
A## [,1] [,2] [,3] [,4]
## [1,] 26 40 41 54
## [2,] 40 67 62 83
## [3,] 41 62 95 70
## [4,] 54 83 70 126
下面是内置的eigen
函数返回的内容。
eigen(A)## eigen() decomposition
## $values
## [1] 268.6301739 39.1116701 5.8239493 0.4342066
##
## $vectors
## [,1] [,2] [,3] [,4]
## [1,] -0.3085888 0.02606027 -0.001691293 0.9508370
## [2,] -0.4823478 0.07140554 -0.858273366 -0.1600270
## [3,] -0.5053596 -0.81601931 0.242450805 -0.1412152
## [4,] -0.6455425 0.57300488 0.452306949 -0.2244074
正如您在下面看到的,当调用my_eigen
函数时,结果是相同的。
my_eigen(A)## $values
## [1] 268.630174 39.111670 5.823949 0.434207
##
## $vecotrs
## [,1] [,2] [,3] [,4]
## [1,] 0.3085888 0.02606027 0.001691289 -0.9508370
## [2,] 0.4823478 0.07140567 0.858273355 0.1600270
## [3,] 0.5053596 -0.81601935 -0.242450683 0.1412152
## [4,] 0.6455425 0.57300481 -0.452307035 0.2244074
当调用Rcpp
版本的myc_eigen
函数时,结果也是一样的。
myc_eigen(A)## $values
## [1] 268.6301739 39.1116701 5.8239493 0.4342066
##
## $vectors
## [,1] [,2] [,3] [,4]
## [1,] 0.3085888 0.02606027 0.001691289 -0.9508370
## [2,] 0.4823478 0.07140567 0.858273355 0.1600270
## [3,] 0.5053596 -0.81601935 -0.242450683 0.1412152
## [4,] 0.6455425 0.57300481 -0.452307035 0.2244074
此外,我们可以通过比较将和 λ 应用于特征向量的结果,并检查它们是否相等,来验证计算的分解是否正确。
*eigen_decomp <- myc_eigen(A)
v <- eigen_decomp$vectors[, 2]
l <- eigen_decomp$values[2]*
这里我们应用矩阵。
*as.numeric(A %*% v)## [1] 1.019261 2.792791 -31.915878 22.411177*
和预期的缩放比例 v 由 λ 给出相同的矢量。数值似乎朝着第 7 个有效数字有一点分歧,但解决方案是可以接受的接近。
*(l * v)## [1] 1.019261 2.792795 -31.915880 22.411175*
标杆管理
出于兴趣,我想比较一下这些函数计算特征值的速度。看起来在一个小矩阵上,比如我们在内置的eigen
函数上面使用的 4x4 矩阵,会慢一点。
*microbenchmark(eigen(A), my_eigen(A), myc_eigen(A))## Unit: microseconds
## expr min lq mean median uq max
## eigen(A) 179.003 191.6580 211.15584 201.8395 230.539 326.666
## my_eigen(A) 140.156 151.9090 161.32797 160.7745 169.035 221.650
## myc_eigen(A) 61.102 65.6775 71.19684 69.7855 75.054 92.629*
如果我们采用更大的矩阵,那么eigen
当然会更快。这个Rcpp
版本的 is my 函数只比纯R
函数快一点,可能是因为它使用了一个矩阵乘法函数myc_matmult
,这个函数明显比%*%
操作符慢。
*X <- matrix(rnorm(100), ncol = 10)
A <- t(X) %*% X
microbenchmark(eigen(A), my_eigen(A), myc_eigen(A))## Unit: microseconds
## expr min lq mean median uq max
eigen(A) 187.839 203.035 361.0305 230.057 341.2605 1444.53
my_eigen(A) 1698.668 1775.423 3067.5417 1911.548 2908.7345 18626.75
myc_eigen(A) 1225.512 1299.820 2178.2306 1547.336 2394.2235 12239.43*
可视化和动画
显然自己实施 QR 方法 并不是为了更好的表现。然而,我们能做的是构建一个函数,跟踪值是如何计算的,也许能更好地了解它是如何工作的。
下面是一个函数my_eigen2
,它执行与my_eigen
函数相同的计算,除了它不使用 while 循环,而是迭代给定的最大次数,并记录更新后的特征值。如果计算收敛,则迭代在达到给定的最大值之前停止。
*my_eigen2 <- function(A, margin = 1e-10, itrs = 40) {
Q <- myc_qr(A)$Q
Qt <- t(Q)
Elist <- vector("list", length = 21)
Ulist <- vector("list", length = 21)
E <- t(Q) %*% A %*% Q
U <- Q
Elist[[1]] <- E
Ulist[[1]] <- U
res <- diag(E)
for (i in 1:itrs) {
init <- res
Q <- myc_qr(E)$Q
E <- t(Q) %*% E %*% Q
U <- U %*% Q
Elist[[i + 1]] <- E
Ulist[[i + 1]] <- U
res <- diag(E)
print(sum((init - res)^2))
if (sum((init - res)^2) < margin) {
break()
}
}
return(list(
values = round(diag(E), 6),
vectors = U,
Elist = Elist[1:i],
Ulist = Ulist[1:i]
))
}*
想象一个 2 乘 2 的案例
为了可视化 QR 方法 如何工作,我决定使用一个 2x2 协方差矩阵。这是为了使其与 PCA 相关,并使其易于实际可视化。
*A <- matrix(c(
1.0, 0.3,
0.3, 0.8
), nrow = 2)
A## [,1] [,2]
## [1,] 1.0 0.3
## [2,] 0.3 0.8*
首先,我们让my_eigen2
进行计算,并建立矩阵列表,记录 QR 方法 如何收敛到答案。在 9 个步骤之后,计算收敛。
*eigen_decomps <- my_eigen2(A, itrs = 30)## [1] 0.005127351
## [1] 0.0003368977
## [1] 1.882642e-05
## [1] 1.011322e-06
## [1] 5.382776e-08
## [1] 2.858891e-09
## [1] 1.517664e-10
## [1] 8.055721e-12*
这些是实际的特征值和特征向量:
*eigen_decomps$values## [1] 1.216227 0.583773eigen_decomps$vectors## [,1] [,2]
## [1,] 0.8118117 -0.5839193
## [2,] 0.5839193 0.8118117*
以下代码在计算的每一步提取两个特征向量的方向,并将它们堆叠到 data.frame 中。我们可以使用这些来计算斜率,然后将它们可视化在密度图上。
正确的斜率是
和
*animation_data <-
map2(eigen_decomps$Elist, eigen_decomps$Ulist,
~ as.data.frame(1 / .x %*% .y)) %>%
bind_rows(.id = "frame") %>%
rename(x1 = "V1", y1 = "V2") %>%
bind_cols(d = rep(c("d1", "d2"), length(eigen_decomps$Elist))) %>%
pivot_wider(names_from = d, values_from = c(x1, y1)) %>%
bind_cols(
x0 = rep(0, length(eigen_decomps$Elist)),
y0 = rep(0, length(eigen_decomps$Elist))
) %>%
mutate(frame = as.numeric(frame)) %>%
mutate(
slope1 = y1_d1 / x1_d1,
slope2 = y1_d2 / x1_d2
)
animation_data## # A tibble: 8 x 9
## frame x1_d1 x1_d2 y1_d1 y1_d2 x0 y0 slope1 slope2
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 0.865 2.67 -7.00 1.76 0 0 -8.09 0.659
## 2 2 0.893 2.79 -2.27 2.03 0 0 -2.54 0.727
## 3 3 0.941 2.88 -1.71 2.10 0 0 -1.81 0.729
## 4 4 0.975 2.91 -1.53 2.11 0 0 -1.57 0.725
## 5 5 0.994 2.92 -1.46 2.11 0 0 -1.47 0.723
## 6 6 1.00 2.93 -1.43 2.11 0 0 -1.43 0.722
## 7 7 1.01 2.93 -1.42 2.11 0 0 -1.41 0.721
## 8 8 1.01 2.93 -1.41 2.11 0 0 -1.40 0.721*
使用ggplot
和plotly
,我们可以生成以下动画可视化
*data.grid <-expand.grid(x = seq(-5, 5, length.out = 200),
y = seq(-5, 5, length.out = 200))dens <- cbind(data.grid,
z = mvtnorm::dmvnorm(data.grid,
mean = c(0, 0),
sigma = A))
ggplotly(
ggplot(dens, aes(x = x, y = y, z = z)) +
geom_contour(color = "blue", alpha = 0.3) +
coord_fixed(xlim = c(-2, 2), ylim = c(-2, 2), ratio = 1) +
geom_abline(aes(slope = slope1, intercept = 0, frame = frame),
color = "red", data = animation_data
) +
geom_abline(aes(slope = slope2, intercept = 0, frame = frame),
color = "red", data = animation_data
) +
theme_void() +
theme(
legend.position = "none",
axis.line = element_blank(),
panel.grid.major = element_blank()
) +
geom_raster(aes(fill = z)) +
scale_fill_gradientn(colours = RColorBrewer::brewer.pal(n = 5, name = "BuGn"))
) %>%
animation_opts(frame = 500, redraw = TRUE) %>%
style(hoverinfo = "skip")*
可以在这里查看我博客上的实际动画:https://BDS haff . github . io/BDS haff . github . io/blog/2020-03-23-计算-特征值-和-特征向量/
我的外卖
- 我真的很感谢 LAPACK 或 Armadillo 这样的数值线性代数库,因为经历了最简单的特征值计算方法,我可以更好地欣赏创建它们的所有工作。
- 通过这个练习,我对计算特征值背后的细节变得非常熟悉。虽然有时令人沮丧,但我真的觉得我学到了很多东西,在我看来,真正彻底地学习了一些东西的感觉是最好的感觉之一。
开始数据科学项目前要问的八个问题
或者,如何像 DARPA 一样进行项目管理
图片来源: Pixabay
如果你熟悉国防高级研究计划局(DARPA),这个名字可能会让人联想到未来的军事技术、人形机器人和机械四足动物,所有这些都包裹在政府机密研究的神秘之中。你也不会太离谱。快速搜索就会出现为士兵设计的软外骨骼、千兆像素相机技术、机器人群体战术以及数百个其他 DARPA 赞助的研发项目。然而,该机构对数据科学的一个被忽视的贡献是其决策方法。
DARPA 概述
该机构的研究是科幻小说和汤姆·克兰西小说的素材。然而,人们很容易忘记 DARPA 也是一个(深呼吸)官僚机构,有完整的等级制度、标准操作程序和文书工作。也许这没有想象中的自我修复材料和精神控制机器有趣,但它确实回避了一个问题:所有的脑力都由他们支配,该机构如何选择追求哪些项目?
这是我们在数据科学和职业生活中每天都要面对的问题。我们的资源是有限的,项目失败是昂贵的,机会成本是真实的,那么哪些风险是值得冒的呢?
Heilmeier 的教义问答有助于将有趣的项目与重要的项目分开。
乔治·海尔迈耶:1975-1977 年间,工程师、发明家和 DARPA 主任。据该机构称,他精心设计了一套八个问题,“任何提出研究项目或产品开发努力的人都应该能够回答。”今天,它们被称为 Heilmeier Catechism,DARPA 仍然在项目提案和项目经理申请过程中使用它们。数据科学项目受益于问同样的问题。
乔治·h·赫利迈尔,图片来源: DARPA (公共领域)
开始项目前要问的八个问题:
- 你想做什么?绝对不要使用行话来阐明你的目标。
- 今天是如何做到的,当前实践的局限性是什么?
- 你的方法有什么创新,为什么你认为它会成功?
- 谁在乎呢。如果你成功了,会有什么不同呢?
- 有什么风险?
- 要花多少钱?
- 需要多长时间?
- 检查成功的期中和期末“考试”有哪些?
回答 Heilmeier 的问题将节省您和他人的时间。一些承担较大技术项目的办公室甚至会将这些问题作为建议书的强制性内容。即使不是必需的,通读 Heilmeier 的教义问答也可以帮助区分有趣的项目和重要的项目。以下是关于每个组件如何与数据科学流程相关的一些想法。
你想做什么?绝对不要使用行话来阐明你的目标。第二句话值得特别注意。数据科学家在他们的职业生涯中花了大量时间在各方之间翻译技术语言,当不与其他数据书呆子交谈时,行话充其量是低效的。在最坏的情况下,利益相关者可能会发现你居高临下,与问题脱节——他们可能会把你叫出来。行话也为误解提供了大量的机会。
如今是如何做到的,目前的做法有哪些局限?这个问题的范围值得思考——与其他地方相比,这里的是如何做到的?这个问题很快回答了解决方案是否已经存在——这是利益相关者想要知道的。了解数据科学领域当前的最佳实践,以及您的组织是否在使用它们。目前的方法还能更好吗?要诚实。
你的方法有什么创新,为什么你认为它会成功?一旦我们确定了其他人是如何处理这个问题的,考虑一下为什么。我们是在向我们的组织提议真正新颖的东西吗?新奇的想法出奇的少,但是即使我们提出的解决方案存在于其他地方,将其应用于我们的组织仍然是有价值的。如果一个解决方案可以解决手头的问题,经理或客户可能根本不在乎这个解决方案是否在其他地方使用过。
谁在乎呢?如果你成功了,会有什么不同呢?这个项目重要还是只是学术上的兴趣?如果我们提出一种新的方法,只是为了看看某物能弯曲和拉伸到什么程度,这个项目可能不属于“重要”的类别。在数据科学中,一个定义明确的问题在这里会有所帮助。项目在解决什么问题,为什么它很重要?
我们的资源是有限的,项目失败是昂贵的,机会成本是真实的,那么哪些风险是值得冒的呢?
有什么风险?要花多少钱?需要多长时间?简言之,谨慎的成功比意外的失败更可取。考虑追求项目的机会成本和减轻风险的可用机制,并了解您的意外情况。对于数据科学家来说,洞察这些可能需要与利益相关者进行额外的对话。这是我们可能都需要更多练习的地方。
检查成功的期中和期末“考试”是什么?我们必须对自己负责。想想真正的进步是什么样的,如何衡量。在数据科学中,管理对自己和投资方的期望可能是成功和失败的区别。利用你对潜在风险的了解来设定明确的预期,并与相关方进行沟通。
从 DARPA 那里可以学到很多其他的创新经验。在 2016 年的报告中,该机构将其在创新方面的成功归功于员工有限的任期和它提供的紧迫性(DARPA 项目经理的年流失率约为 25%),以及冒险和对失败的容忍度。查看他们的网站了解更多信息。
爱因斯坦,以及所有理论中最美丽的
广义相对论如何解释水星近日点的“异常”进动
英国理论物理学家保罗·狄拉克(1902–1984)是量子力学的创始人之一,他曾写道:
“很难将牛顿引力理论及其力的瞬时传播与狭义相对论的要求相协调,爱因斯坦在这一困难上的工作导致了他的相对论的推广——这可能是有史以来最伟大的科学发现。”
广义相对论被普遍认为是一个异常美妙的理论。几年来的几次测试证实了这一理论的一致性。我来描述一下其中一个测试,它正确解释了水星近日点的“异常”进动(见链接)牛顿的引力理论未能预测到。
图 1:图为水星近日点进动(来源)。
牛顿理论的问题是
近日点(行星轨道上离太阳最近的点)的进动(或旋转)有多种原因。其中两个是:
- 其他行星的存在导致了彼此轨道的扰动,这是主要原因
- 太阳的扁率(见图)明显不太相关
图 2:该图显示了一个半径被压缩成扁椭球体的球体(来源)。
水星岁差的近日点速率与牛顿引力理论的预测不符。法国天文学家和数学家于尔班·勒·威耶注意到了这一异常现象。由 T2·西蒙·纽康·T3 在 1882 年进行的最后一次测量估计,实际的岁差率与牛顿的预测相差 43 度。提出了许多特别的解决方案,但没有一个奏效。
正如下一节将要讨论的,在广义相对论中,这个额外的岁差完全可以用爱因斯坦的广义相对论来解释。对于后者的修订版,请查看下面的文章。
从简单论证中获得爱因斯坦方程
towardsdatascience.com](/a-heuristic-derivation-of-einsteins-gravity-equations-8d3659c8a46c)
用广义相对论计算水星的近日点进动
史瓦西解是描述太阳周围真空时空几何的爱因斯坦场方程的解。换句话说,史瓦西度规是太阳产生的时空曲率导致的太阳系度规。在以下情况下有效:
- 将太阳视为不旋转的物体
- 忽略源自太阳系其他行星的引力场。
史瓦西解具有以下线元素:
方程式 1:描述太阳周围真空时空几何的史瓦西解的线元素。
参数 R = 2 M 称为史瓦西半径。坐标 r 、 θ、和 φ 为球面坐标,如图 3 所示。
图 3:球坐标(来源)。
注意,从度规的各向同性来看,我们总是有θ = π/2(轨道被限制在赤道处)。事实上,根据两体问题(在我们的例子中,天体是太阳和行星),受中心力势作用的天体的运动将始终位于一个平面内。图 4 和图 5 示出了两种类型的轨道双体系统。限于平面的运动在牛顿和爱因斯坦引力理论中都是有效的。因此,在我们的分析中,只考虑位于该平面内的测地线就足够了。
图 4:两个质量相同的天体围绕一个共同的重心运行,在两个天体之外(这种情况出现在例如双星中)(来源)。
图 5:两个质量不同的物体围绕一个共同的重心运行(来源)。
该分析有效的第三个条件是径向坐标 r 必须远大于太阳的半径。这不是问题,因为太阳的史瓦西半径比太阳半径小得多。更具体地说,太阳的史瓦西半径大约为 2.95×10 米,而太阳的半径接近 6.96×10⁸米
图 6:德国物理学家和天文学家卡尔·史瓦西 ( 来源)
给定时空的对称性与在其中运动的粒子和光子的守恒量有关。由于史瓦西解的度规 g 既与时间无关(或时间平移不变量)又球对称,所以大质量粒子的能量和光子的能量都是守恒的。我们可以从数学上看到如下。
在一个度规为 g 的时空中,一个自由下落的物质粒子或光子遵守与那个时空相关的测地线方程(一条“直线”对弯曲时空的推广),它由(见史高斯)给出:
方程 2:测地线方程,由自由下落的物质粒子或光子遵守。
注意,由于光子也会被考虑,参数λ不可能是合适的时间 τ。测地线方程也可以写成:****
方程 3:测地线方程,用另一种形式写成。
现在请注意:
等式 4:时间和坐标ϕ.中度量的常数分量
Eqs。3 和 4 意味着:
等式 5:测地线的运动常数。
然后我们做如下定义:
等式 6:大质量粒子每单位质量的能量和光子的能量。
大质量粒子能量上面的~(见史高斯)用来表示这个能量是每单位质量。同理,由于 g 对 φ 的独立性,角动量是守恒的。我们定义:
方程式 7:大质量粒子单位质量的角动量和光子的角动量。
其中左边的项是大质量粒子每单位质量的角动量,右边的项是光子的角动量。我们现在需要轨道方程。大质量粒子动量的三个分量是:
等式 8:大质量粒子的三个动量分量。
光子的动量是:
方程式 9:光子动量的三个分量。
我们现在使用我们刚刚导出的动量分量,将它们代入粒子和光子的方程| p |=- m ,并求解 dr / dλ 。用于 dr / dλ 然后的等式为:
等式 10:关于 dr / dλ平方的等式。
现在直觉告诉我们用有效势改写这些方程,即:
方程 11:大质量粒子和光子的有效势的定义。
电势绘制在图 7 中。注意,由于两个方程的左边都是正的,有效势必然小于能量。图 7 显示了有质量和无质量粒子的有效势(注意图 7 中的 E 和 V 表示相同的量,上面有波浪符号~)。图中还标出了 dr/dλ =0 的转折点,禁域(其中 E < V )和圆形轨道(稳定和不稳定),其中 dV /dr =0。
图 7:有质量和无质量粒子(光子)的有效势。该图显示了稳定(最小值)和不稳定(最大值)的转折点、禁区和圆形轨道。
水星近日点的进动
从现在起,让我们只考虑大质量物体的运动,因为我们的目标是计算水星近日点的进动。
稳定的圆形轨道出现在有效势的最小值处。设 M 为太阳质量。对有效势求微分,将结果设为零,求解 r 我们得到稳定圆轨道的半径:
方程 12:围绕太阳振荡的大质量粒子的稳定圆形轨道的半径。
在牛顿力学中,行星在圆形轨道上的完整轨道返回到其初始 φ。现在利用圆轨道有 E = V 的事实,并利用到目前为止推导出的表达式,我们得到一颗行星拥有δφ=2π,的时间,即周期 P :
等式 13:行星绕太阳旋转周期的牛顿结果。
图 8:图中显示了一个测试粒子遵循牛顿万有引力定律或爱因斯坦方程的轨道之间的差异(来源)。
现在,在广义相对论中,旋转的行星不会回到它的原点。如果相对论效应很小,我们应该有一个绕着中心缓慢旋转的椭圆。我们能做的(见史高斯)是检查轨道近日点的运动。为此,我们进行三个快速计算(见史高斯):
- 根据角动量推导出 dφ /dλ的表达式
- 根据单位质量的能量推导出 dt / dλ 的表达式
- 定义新变量 u ≡ 1/ r
将它们代入等式。10 我们得到:
等式 14:du/dφ的相对论表达式。
我们现在定义 *y,圆度偏差如下:***
等式 15:变量 y 的定义,圆度的偏差。
对于牛顿轨道, y =0。为了得到相对论性的表达式,我们代入方程。15 成情商。14、降条款的顺序 y 。对于几乎圆形的轨道,我们得到下面的方程:
等式 16:dy/dφ的相对论表达式。
该解决方案如下:
等式 17:等式的解 y(φ)。16.
whee B 取决于初始条件。从余弦的论证,我们得出结论:当δ(kφ)= 2π时,轨道回到相同的半径。不同于 1 的 k 的存在就是它与牛顿结果的区别!如果相对论效应很小,我们可以做几个简单的近似来获得:**
等式 18:近日点从连续轨道前进。
特别是对于汞来说,我们得到了每年 0.43 英寸的位移,正如本文开头所提到的,这是通过实验确定的值。
似乎连爱因斯坦都被结果惊呆了。发现计算结果后,他几天都不能工作。用他自己的话说,他变得“欣喜若狂”
我的 Github 和个人网站 www.marcotavora.me 有一些其他有趣的材料,既有关于物理的,也有关于数学、数据科学和金融等其他主题的。看看他们!
爱因斯坦的引力、光的弯曲以及他如何成为世界上最著名的科学家
太阳对光的引力弯曲的解释
广义相对论(发表于 1915 年)阿尔伯特·爱因斯坦的几何引力理论,被许多科学家认为可能是所有现存物理理论中最美丽的
在这篇文章中,我将描述广义相对论的经典测试之一,可以说是最著名的一个,这是太阳(或任何球对称,与时间无关的引力场)对光的弯曲,如图 1 所示。
图 1:太阳光的弯曲(来源)。
可以看出,净偏转角有一个非常简单的表达式:
等式 1:掠日光子的净偏转。
其中 M 为太阳质量, b 称为撞击参数(见图 2)。
图 2:影响参数 b。
光弯曲的一种表现形式被称为引力透镜,目前被天文学家用作一种必不可少的测量工具(见图 3)。
图 3:爱因斯坦十字,在这里我们看到了同一个遥远类星体的四幅图像,这是强引力透镜的结果(来源
在我以前的一篇文章中(见下文,描述了另一个理论的成功测试,即水星近日点的“异常”进动。
广义相对论如何解释水星近日点的“异常”进动
towardsdatascience.com](/einstein-and-the-most-beautiful-of-all-theories-f4ad4ce7a0a2)
史瓦西解及其测地线
史瓦西度规 g 是太阳产生的时空扭曲导致的太阳系度规。它具有以下行元素:
方程 2:史瓦西解的线元素,太阳产生的时空曲率扭曲导致的太阳系的度规。
公制中使用的坐标是如图 4 所示的球坐标 ( r , θ, φ )。
图 4:球坐标 r(径向距离)、θ(极角)、ϕ(方位角)(来源)。
因为我们的目标是导出 Eq。1,我们将需要首先获得光子轨迹的表达式 φ ( r ),其中 φ 是方位角,而 r 是半径坐标。让我们从计算穿过太阳引力场的光子的动量分量开始。
计算光子的动量和守恒量
给定时空中沿测地线运动的粒子的守恒量与对应的度规张量 g 的对称性之间存在对应关系。由于史瓦西解同时具有球对称性和时间平移不变性,因此测试粒子的能量和角动量都是守恒的。这在数学上可以通过将测地线方程后接质点重写为(见史高斯)来看出:
方程 3:测地线方程,用动量 p 和 g 的导数来写,用这个符号,很容易看出动量守恒和相关时空的对称性之间的对应关系(更多细节见正文)。
现在,光子在零测地线上行进,这意味着参数 λ 一定是不同于适当时间 τ的某个仿射参数。由于史瓦西度规遵守以下条件
等式 4:史瓦西度规的两个常数分量。
情商。3 为我们提供了下列守恒量
等式 5:由度规张量分量的相应导数的消失产生的两个运动常数。
注意,球对称意味着运动发生在一个平面上,我们可以选择θ = π/2(也就是说 dθ / dλ = 0)。
光子
由于我们的目标是专门研究光线的弯曲,所以从现在开始,只考虑光子的运动(大质量粒子在这篇文章中讨论)。
方程式中的两个运动常数。5 分别是能量和角动量,
等式 6:运动的两个常数 E 和 L 分别是能量和角动量。
牛顿的能量概念需要负号才能在低速下恢复。
光子动量的三个相关分量的显式表达式很容易使用度规的史瓦西分量和等式来计算。6:
方程 7:光子动量分量的显式表达式。
我们现在把这三个分量代入|p| =m= 0,求解为( dr / dλ )。我们得到:
方程 8:根据仿射参数λ的光子轨道方程。
我们可以改写这个等式,定义一个“有效势”,由下式给出:
方程式 9:光子的“有效势”。
该有效电势绘制在图 5 中。图中标明了转折点(其中 dr/dλ =0)、禁域(其中E<V】、和圆轨道(其中 dV /dr =0)等重要元素。
图 5:光子的有效势。
光的引力弯曲
回想一下,我们这里的目标是获得穿过太阳引力场的光子的 φ ( r )。事实证明,这很容易简单地通过将动量的φ-分量(角动量)除以等式的平方根来实现。8.我们得到:
方程 10:光子 φ ( r )的轨道微分方程。
正如我们在简介中定义的,参数 b 是冲击参数。在牛顿力学中,直接表明 b 是径向距离 r 的最小值(无偏转时)。因此 b 是光子轨迹相对于径向移动的平行轨迹的“偏移”(参见史高斯)。
如同在牛顿的情况下,使用新变量u≦1/r .然后Eq 在数学上是方便的。10 变成了:
等式 11:根据新变量 u 的光子轨道。
现在让我们考虑极限,其中M/r<<1 或者等效地u<<1/M .我们事后定义下面的辅助变量 y :
等式 12:新变量 y 的定义。
最后一步是求解方程。11 。我们最终获得:
方程 13:作为 dφ/dy 方程的解的光子轨迹(根据变量 y)。
光子的偏转如下图所示(以及一些相关注释):
图 6:光子穿越太阳引力场时轨迹的弯曲。
快速计算表明,净挠度确实由方程给出。1:
等式 14:光子经过太阳附近后的净偏转,与等式中的表达式相同。1.
图 7:著名的英国天文学家、物理学家和数学家亚瑟·爱丁顿,第一个证实爱因斯坦对δφ的预测的团队的领导人(来源)。一张爱丁顿拍摄的著名的 1919 年日食实验照片(来源)。
代入太阳的质量,用太阳的半径作为撞击参数 b (见史高斯)我们得到最大偏转,大约等于 1 。75。这个结果在 1919 年由著名的英国天文学家、物理学家和数学家亚瑟·爱丁顿领导的英国团队进行的一个著名实验中首次得到证实。
感谢您的阅读,再见!一如既往,我们随时欢迎建设性的批评和反馈!
我的 Github 和个人网站 www.marcotavora.me 有一些其他有趣的材料,既有关于物理的,也有关于数学、数据科学和金融等其他主题的。看看他们!
搜索(第三部分)——弹性变压器
让 BERT 变得有弹性——Jupyter 笔记本上的可扩展语义搜索
这是一个关于如何通过 transformers 建立和添加语义搜索作为弹性搜索索引的技术教程。我们将经历所有需要的步骤,并将介绍实用程序类 ElasticTransformers。最后,我们将考虑一些速度比较。
这是关于搜索的三部分系列的最后一部分。对于这如何适应更广泛的搜索主题的非技术讨论,请考虑前两部分。
- Pt 1 是对搜索引擎典型构件的一个温和的介绍
- 在 Pt 2 中,我们对搜索的关键词和上下文嵌入进行了并排比较
在第 1 部分中,我们已经看到了 Elasticsearch 如何提供一系列现成的搜索功能。在本文中,我们将展示如何再添加一个——上下文语义搜索
图片由作者制作,用 gifox
“如何做”
我将在这里简要概述这种方法。也可以关注 github 。
体系结构
我们将在本地部署 Elasticsearch 作为 docker 容器。数据将存储在本地。使用 Jupyter notebook,我们将使用句子转换器库将数据分块并迭代地嵌入记录批,并提交给索引。最后,我们还将执行笔记本外的搜索。为了实现这一切,我准备了一个实用程序类 ElasticTransformers
积木
所有这些步骤也记录在 github repo 中,并作为随附笔记本的一部分执行。
- 数据我用的是 Rohk 的百万新闻头条。这些数据代表了美国广播公司新闻大约 18 年的头条新闻。长时间跨度以及数据集的大小为实验提供了良好的基础。
- Elasticsearch Docker 容器。在本地开始使用 Elasticsearch 的一个非常快速简单的方法是将其部署为 Docker 容器。按照步骤这里对于本教程,您只需要运行两个步骤:
- 拉动图像
- 使用 Docker 启动单节点集群
- 对于弹性上的向量搜索,我们使用密集向量搜索功能,这要感谢这些优秀的资源
- 如前所述,我们使用(SBERT) 句子转换器进行嵌入,作为一种高性能且非常容易访问语义相似性的方法
使用这些实用程序,我们依次:创建一个索引,编写几个不同大小的数据集以嵌入索引,并执行一些实验
对于懒惰的人…嗯,忙碌的人…
最后,所有这些步骤过去执行起来都很复杂。值得庆幸的是,现在是 2020 年,很多事情都变得简单了:我们可以在 Docker 上部署一个只有两行代码的 Elasticsearch(实际上是从 2016 年开始的), transformers 预先训练有一些先进的库,我们可以在我们舒适的 Jupyter 笔记本上完成以上所有工作…
所有这些步骤也记录在 github repo 中,并作为随附笔记本的一部分执行。
使用弹性变形器
ElasticTrasnformers 构建在 elasticsearch 库的基础上,它简单地包装了一些实例化步骤,添加了简单的索引创建实用程序&映射(我个人一直在努力解决这个问题),重要的是,它是一个易于使用的大文档分块工具,可以将嵌入内容写入搜索索引
初始化类以及(可选)要使用的索引的名称
et = ElasticTransformers(url = ’http://localhost:9300', index_name = 'et-tiny')
为索引创建规格。可以基于关键字搜索或语义(密集向量)搜索是否需要相关字段来提供相关字段的列表。它也有密集向量大小的参数,因为这些参数可以变化
et.create_index_spec(
text_fields=[‘publish_date’,’headline_text’],
dense_fields=[‘headline_text_embedding’],
dense_fields_dim=768
)
创建索引 —使用之前创建的规范创建一个索引以备搜索
et.create_index()
写入大文件 —将一个大的 csv 文件分解成块,并反复使用预定义的嵌入实用程序为每个块创建嵌入列表,然后将结果提供给索引。在笔记本中,我们展示了一个如何创建 embed_wrapper 的例子,注意实际的嵌入器可以是任何函数。我们使用带 distilbert 的句子转换器,因为它在速度和性能之间提供了一个很好的平衡。然而,这可能因您感兴趣的用例而异。
et.write_large_csv(‘data/tiny_sample.csv’,chunksize=1000,embedder=embed_wrapper,field_to_embed=’headline_text’)
搜索 —可以选择关键字(弹性中的“匹配”)或上下文(弹性中的“密集”)搜索。注意,它需要 write_large_csv 中使用的相同嵌入函数。这只检查 type = 'dense '是否作为嵌入搜索处理,否则可以采用常见的:' match ','通配符',' fuzzy '等。
et.search(query = ’search these terms’, field = ’headline_text’, type = ’match’, embedder = embed_wrapper, size = 1000)
我们将以几种不同的索引大小(小型:1k,中型:100k 和大型:110 万(所有)标题)索引来自一百万个新闻标题的数据。最后,我们将使用这些来执行一些速度比较。
速度…
我们刚刚索引了大约 110 万个句子,但是所有这些真的有规模吗?自然,扫描海量指数时总会有减速,但减速多少呢?
我进行了几次测试(每次重复 10 次):
- 不同长度的查询:1、2 和 5 个令牌
- 结果大小不同的查询 1、10 和 100 个结果
结果如下图所示:
- 关键词搜索—索引大小增加 1000 倍,速度降低约 8 倍;结果大小增加 100 倍,速度降低约 4 倍。所有这些都不到 10 毫秒
- 然而,在上下文搜索方面,性能会显著降低,从一个大(1mn)索引进行单独搜索需要 8 秒。与 100k 的中等规模指数相比,这显然是一个明显的放缓,仍然远远小于 1 秒
值得注意的是,交互式搜索应用程序的常见要求是在 1 秒内检索到结果,在某些情况下不到 300 毫秒,因此这是一个显著的减速。下面探讨了一些解决方案
作者图片
提高速度
搜索速度是一个至关重要的方面,因为搜索通常需要交互,文档大小通常也很重要。在这种情况下,我们可以看到,随着数据集大小的增加,速度呈指数级下降。这是因为我们将所有文档与查询进行比较,而不是在关键字搜索方法中使用倒排索引。有多种方法可以解决这个问题,但不幸的是,它们都需要在精度方面进行权衡。
例如,近似最近邻 (ANN)方法将使用更少的空间和更快的执行速度,代价是有时返回的结果并不完全相关——对于实现,请查看 Faiss 或airy以及这个关于混合嵌入、关键字搜索和使用 Faiss 的很好的例子。大谈规模人工神经网络的不同权衡以及如何选择一个— 十亿级近似最近邻搜索。另一种方法可能是执行聚集聚类并仅在检索时收集相关数量的结果。查看 fastcluster 的实现。
Haystack 为结合变形金刚和搜索提供了一个广泛的框架。然而,查询被认为是自然语言问题,并且采用了问答框架。不同之处在于,在 QA 框架中,查询和每个单独的候选文档之间的匹配质量是成对评估的。这本身就是一个计算量大得多的问题,与我们在这里所做的相反,在这里每个文档都由一个嵌入来表示,该嵌入在运行时与查询进行比较。较大的计算负荷最初是通过将搜索空间减少到较少数量的相关候选项来处理的。
冗长的文件
我们看到的上下文解决方案也受到文档大小的限制——受到 transformers 模型的令牌限制的约束。在这种情况下,我们可以容纳多达 512 个标记(类词块,例如单词 look 是一个标记,look是两个标记— look & ing,等等。).这种约束适用于标题或甚至段落,但不适用于全尺寸文档,例如新闻文章正文、研究论文等。
这些模型可以扩展到更长的序列,但是随着长度的增加,它们的内存使用量呈二次方增长。常见的解决方案倾向于保持标准长度,但使用变通方法,例如在相关的地方对嵌入进行一些平均。这仍然是一个活跃的研究领域,最近一个值得注意的新发现是big bird——一个基于 Google Research transformer 的模型,它可以处理更长的序列,同时保持内存使用量与文档大小成线性增长
结论
我们已经看到了如何轻松地部署一个 Elasticsearch 容器,并用一些我们可用的最强大的上下文嵌入来索引它。评估表明,对于大型索引,语义搜索可能会变慢,但是,我们也考虑了一些替代解决方案。
这个领域的未来仍然充满希望,并且越来越容易实现。
希望这是有用的。感谢您的阅读。如果你想和我打招呼或者只是想告诉我我错了,请随时通过 LinkedIn 联系我
弹性搜索分析教程
使用 Knowi 连接到 Elasticsearch 数据源,通过基于搜索的分析查询您的数据,并创建可视化效果。
安德烈斯·西蒙在 Unsplash 上拍摄的照片
目录
介绍
Elasticsearch 是一个可伸缩的全文搜索引擎,具有 HTTP web 接口和基于模式的 JSON 文档。当 Elasticsearch 作为基础引擎在后台使用时,它会大放异彩,为具有复杂搜索功能和许多需求的应用程序提供动力。
目前,Kibana 在 Elastic 广受欢迎的 ELK 堆栈中的位置使其成为可视化和分析 Elasticsearch 数据的最常用工具。虽然 Kibana 肯定有其自身的优点,但它也有一些缺点;也就是说,它不支持与任何其他数据源的集成,也不提供用户管理功能或对发出主动警报的支持。
在某些时候,Elasticsearch 用户可能会认为这些缺点中的一个或多个是交易的破坏者,并选择不同的可视化平台来解决这些缺点。这就是知识发挥作用的地方。除了 Elasticsearch、大量用户管理功能、对警报的支持以及基于搜索的分析和机器学习之外,Knowi 还提供了对 35 个其他数据源的广泛原生集成。如果您有兴趣了解如何使用 Knowi 来可视化来自 Elasticsearch 的数据,那么您来对地方了。
连接到 Elasticsearch
登录免费的 Knowi 试用账户后,您需要按照以下步骤设置您的 Elasticsearch 数据源:
- 前往屏幕左侧面板的中上方,点击“数据源”
- 转到列出的 NoSQL 数据源的右上方,点击 Elasticsearch。
- 点击屏幕底部的“测试连接”。
- 确保连接成功后,点击“保存”
图片来自作者
使用基于搜索的分析进行查询
既然我们已经建立了一个数据源,那么是时候对我们的数据进行查询了。我们的目标是分析来自佐治亚州的交通数据,并特别关注与元旦某个数据集的西行车辆相关的数据。为此,请遵循以下步骤:
- 当您保存数据源时,您应该会在屏幕顶部收到一个警告,提示“Datasource Added”。配置查询。点击“查询”开始一旦你这样做了,你将被带到一个查询生成器,你将在你的屏幕上方看到一个新的提示,上面写着“获取索引”这意味着 Knowi 会从您刚刚连接的 Elasticsearch 数据源中自动索引表。在执行任何其他操作之前,将您的查询命名为“报告名称*”下的“元旦西行公交”
- 向下悬停到“索引”点击栏内,您将看到您的 Elasticsearch 数据库中存在的每个索引。点击“运输”这将促使 Knowi 的广泛原生集成生成一个 Elasticsearch JSON 查询,该查询从 transit 表的所有列中调用前 10,000 行。
- 选择屏幕左下角的“预览”。这将向您显示预览数据,但是如果您查看可视化,您会注意到我自动选择了一个地图视图。因为我们的预览数据包含经度和纬度坐标,Know 足够智能,可以自动将预览可视化转换为地理聚类/自定义地图可视化。如果你点击可视化中的一个点,它将扩展地图。这正是我们想要看到的可视化类型,但是请记住,我们只对元旦开始的西行活动感兴趣。
- 为了过滤我们的数据,我们将使用 Knowi 基于搜索的分析功能,该功能简单、直观,通过允许非技术用户用简单的英语提问并实时接收结果来吸引他们。只需输入“告诉我 2017-01-01 西行”并稍等片刻。
- 如果你回头看看你的可视化,你应该看到在你的地图上有更少的观察,因为你把它过滤到一个特定的子集。这是对你的提示,你已经做了所有正确的事情,现在你只需要点击“保存并立即运行”来完成你的查询。
图片来自作者
祝贺您使用 Knowi 设置了您的第一个 Elasticsearch 查询和可视化!
分析和可视化您的数据
当您保存并运行您的查询时,Knowi 将原始数据作为数据集保存在 Knowi 的弹性数据仓库中,它还将您的预览可视化保存为 Knowi 帐户中的一个小部件。为了进一步分析和可视化您的数据,请按照下列步骤操作:
- 小部件被构建为存在于仪表板上。现在,你有一个没有家的部件。移动到左侧面板,点击“仪表板”,给你的小部件一个家然后,单击“+”图标创建一个新仪表板,并将其命名为“Westbound Transit Dashboard”单击“确定”保存此仪表板;一旦你这么做了,你会立刻被带到那里。
- 回到屏幕左侧的面板,在“仪表板”的正下方,点击“Widgets”在这里,您将看到您刚刚制作的“元旦西行过境”小部件。只需将它拖过并放开,就可以将其添加到您的仪表板中。
- 现在,您的小部件就在仪表板上,您可以对数据进行更多的分析和可视化。单击您的小部件右上角的 3 点图标,然后选择“分析”,以便转到当前为您的小部件提供支持的原始数据集。
- 我们的目标是在数据中添加不同路线分布的可视化。换句话说,我们想知道在元旦那天西行车辆最常经过的路线。因此,从列名所在的左窗格中,我们将把“route_name”(确保您选择了它而不是“route”)拖到“Grouping/Dimensions”中然后,即使它已经存在于“字段/指标”中,我们也要将它再次拖动到那里,但这一次,我们要将第二个“路由名称”字段中的“操作”更改为“计数”如果操作正确,您将看到六个路由名称以及它们出现的频率。
- 将“路由名称计数”字段从“字段/指标”拖到“排序依据”上,然后确保按降序对此字段进行排序。
- 现在,到你的屏幕顶部,在“数据”旁边,点击“可视化”然后,将“可视化类型”更改为“饼图”
- 因为我们想与地理聚类图并排查看新的饼图,所以我们不打算保存它;我们要克隆它。要做到这一点,前往你的屏幕右上角,找到“克隆”图标,它看起来像一张纸被放在另一张纸的上面,然后点击它。然后,将您的新部件命名为“元旦西行公交——路线频率”单击“克隆”完成此过程,然后单击“添加到仪表板”将新的小部件添加到您的仪表板。
如你所见,Glenwood 路是我们穿越最多的路,Moreland/Candler Park 紧随其后。在 Moreland/Cander Park 和 Perry Blvd/West highlights 之间有一个相当大的下降,然后在 Perry Blvd/West highlights 和接下来的三条路线之间有一个巨大的下降。
摘要
总之,我们在本教程开始时成功连接到 Elasticsearch 数据库,并使用 Knowi 基于搜索的分析功能来查询数据库中的运输数据集的特定子集,以使查询更容易。当我们成功运行这个查询时,Knowi 将查询的结果作为数据集存储在 Knowi 的弹性数据仓库中,并将我们用作小部件的预览可视化存储在 Knowi 帐户中。然后,我们创建了一个新的仪表板作为新部件的主页,并创建了另一个部件来进一步分析我们的数据集并回答一个重要的问题。
数据科学的弹性研究变得更加容易
弹性搜索功能与熊猫的便利
Eland 是一个全新的 python 包,它在 Elasticsearch 和数据科学生态系统之间架起了一座桥梁。
Elasticsearch 是一个功能丰富的开源搜索引擎构建在 Apache Lucene 之上,Apache Lucene 是市场上最重要的全文搜索引擎之一。
Elasticsearch 最为人所知的是它提供的丰富多样的 REST API 体验,包括用于全文搜索、排序和聚合任务的高效包装器,这使得在现有后端中实现这些功能变得更加容易,而无需复杂的重新设计。
自从 2010 年推出以来,Elasticsearch 在软件工程领域获得了很大的吸引力,到 2016 年,根据 DBMS 知识库 DB-engines ,它成为最受欢迎的企业搜索引擎软件栈,超过了行业标准 Apache Solr (也是基于 Lucene 构建的)。
自 2010 年发布以来,弹性搜索的谷歌趋势数据
Elasticsearch 如此受欢迎的原因之一是它所积累的生态系统。世界各地的工程师开发了开源的 Elasticsearch 集成和扩展,其中许多项目被 Elastic(Elastic search 项目背后的公司)吸收为其堆栈的一部分。
其中一些项目是 Logstash (数据处理管道,通常用于解析基于文本的文件)和 Kibana (构建在 Elasticsearch 之上的可视化层),导致了现在广泛采用的 ELK (Elasticsearch,Logstash,Kibana)堆栈。
ELK stack 很快获得了恶名,因为它在新兴和巩固的技术领域中有一系列令人印象深刻的可能应用,如 DevOps、站点可靠性工程、以及最近的数据分析。
但是数据科学呢?
如果你是一名数据科学家,正在阅读这篇文章,并且拥有 Elasticsearch 作为你雇主的技术堆栈的一部分,你可能会在尝试使用 Elasticsearch 为数据分析甚至简单的机器学习任务提供的所有功能时遇到一些问题。
数据科学家通常不习惯将 NoSQL 数据库引擎用于日常任务,甚至不习惯依赖复杂的 REST APIs 进行分析。例如,使用 Elasticsearch 的低级 python 客户端处理大量数据也不是那么直观,对于来自与 SWE 不同领域的人来说,学习曲线有些陡峭。
尽管 Elastic 在增强 ELK 堆栈以用于分析和数据科学用例方面做出了巨大努力,但它仍然缺乏与现有数据科学生态系统(pandas、NumPy、scikit-learn、PyTorch 和其他流行库)的简单接口。
2017 年,Elastic 向数据科学领域迈出了第一步,作为对软件行业日益流行的机器学习和预测技术的回答,它为 ELK stack 发布了第一个 ML 功能的 X-pack (扩展包),在其功能中添加了异常检测和其他无人监管的 ML 任务。之后没多久,回归和分类模型(1)也被加入到麋鹿栈可用的 ML 任务集合中。
上周,Elasticsearch 在数据科学行业获得广泛采用的另一个步骤是发布了 Eland ,这是一个全新的 Python Elasticsearch 客户端和工具包,具有强大的(和熟悉的)类似熊猫的 API,用于分析、ETL 和机器学习。
Eland:弹性和数据
Eland 使数据科学家能够有效地使用已经很强大的 Elasticsearch 分析和 ML 功能,而不需要深入了解 Elasticsearch 及其许多复杂性。
Elasticsearch 的功能和概念被转化成一个更容易识别的环境。例如,一个包含文档、映射和字段的 Elasticsearch 索引变成了一个包含行和列的数据框架,就像我们在使用 pandas 时看到的那样。
# Importing Eland and low-level Elasticsearch clients for comparison
import eland as ed
from eland.conftest import *
from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search, Q
# Import pandas and numpy for data wrangling
import pandas as pd
import numpy as np
# For pretty-printing
import json
典型的数据科学用例,例如将整个弹性搜索索引读入 pandas 数据框架进行探索性数据分析或训练 ML 模型,通常需要一些效率不高的快捷方式。
# name of the index we want to query
index_name = 'kibana_sample_data_ecommerce'
# instantiating client connect to localhost by default
es = Elasticsearch()
# defining the search statement to get all records in an index
search = Search(using=es, index=index_name).query("match_all")
# retrieving the documents from the search
documents = [hit.to_dict() for hit in search.scan()]
# converting the list of hit dictionaries into a pandas dataframe:
df_ecommerce = pd.DataFrame.from_records(documents)# visualizing the dataframe with the results:
df_ecommerce.head()['geoip']0 {'country_iso_code': 'EG', 'location': {'lon':...
1 {'country_iso_code': 'AE', 'location': {'lon':...
2 {'country_iso_code': 'US', 'location': {'lon':...
3 {'country_iso_code': 'GB', 'location': {'lon':...
4 {'country_iso_code': 'EG', 'location': {'lon':...
Name: geoip, dtype: object# retrieving a summary of the columns in the dataset:
df_ecommerce.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4675 entries, 0 to 4674
Data columns (total 23 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 category 4675 non-null object
1 currency 4675 non-null object
2 customer_first_name 4675 non-null object
3 customer_full_name 4675 non-null object
4 customer_gender 4675 non-null object
5 customer_id 4675 non-null int64
6 customer_last_name 4675 non-null object
7 customer_phone 4675 non-null object
8 day_of_week 4675 non-null object
9 day_of_week_i 4675 non-null int64
10 email 4675 non-null object
11 manufacturer 4675 non-null object
12 order_date 4675 non-null object
13 order_id 4675 non-null int64
14 products 4675 non-null object
15 sku 4675 non-null object
16 taxful_total_price 4675 non-null float64
17 taxless_total_price 4675 non-null float64
18 total_quantity 4675 non-null int64
19 total_unique_products 4675 non-null int64
20 type 4675 non-null object
21 user 4675 non-null object
22 geoip 4675 non-null object
dtypes: float64(2), int64(5), object(16)
memory usage: 840.2+ KB# getting descriptive statistics from the dataframe
df_ecommerce.describe()
上面描述的过程将引导我们以字典列表的形式获取索引中的所有文档,然后将它们加载到 pandas 数据框架中。这意味着在进程中的某个时刻,在内存中同时拥有文档本身和结果数据帧(2)。对于大数据应用程序来说,这一过程并不总是可行的,在 Jupyter 笔记本环境中探索数据集可能会变得非常复杂和快速。
Eland 使我们能够执行与上面描述的操作非常相似的操作,而没有任何涉及使它们适应 Elasticsearch 上下文的摩擦,同时仍然使用 elastic search 聚合速度和搜索功能。
# loading the data from the Sample Ecommerce data from Kibana into Eland dataframe:
ed_ecommerce = ed.read_es('localhost', index_name)# visualizing the results:
ed_ecommerce.head()
作为一个额外的特性,pandas 方面需要更多的争论,字段geoip
(它是索引中的一个嵌套 JSON 对象)被无缝地解析成我们的数据帧中的列。我们可以通过调用 Eland dataframe 上的.info()
方法看到这一点。
# retrieving a summary of the columns in the dataframe:
ed_ecommerce.info()<class 'eland.dataframe.DataFrame'>
Index: 4675 entries, jyzpQ3MBG9Z35ZT1wBWt to 0SzpQ3MBG9Z35ZT1yyej
Data columns (total 45 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 category 4675 non-null object
1 currency 4675 non-null object
2 customer_birth_date 0 non-null datetime64[ns]
3 customer_first_name 4675 non-null object
4 customer_full_name 4675 non-null object
5 customer_gender 4675 non-null object
6 customer_id 4675 non-null object
7 customer_last_name 4675 non-null object
8 customer_phone 4675 non-null object
9 day_of_week 4675 non-null object
10 day_of_week_i 4675 non-null int64
11 email 4675 non-null object
12 geoip.city_name 4094 non-null object
13 geoip.continent_name 4675 non-null object
14 geoip.country_iso_code 4675 non-null object
15 geoip.location 4675 non-null object
16 geoip.region_name 3924 non-null object
17 manufacturer 4675 non-null object
18 order_date 4675 non-null datetime64[ns]
19 order_id 4675 non-null object
20 products._id 4675 non-null object
21 products.base_price 4675 non-null float64
22 products.base_unit_price 4675 non-null float64
23 products.category 4675 non-null object
24 products.created_on 4675 non-null datetime64[ns]
25 products.discount_amount 4675 non-null float64
26 products.discount_percentage 4675 non-null float64
27 products.manufacturer 4675 non-null object
28 products.min_price 4675 non-null float64
29 products.price 4675 non-null float64
30 products.product_id 4675 non-null int64
31 products.product_name 4675 non-null object
32 products.quantity 4675 non-null int64
33 products.sku 4675 non-null object
34 products.tax_amount 4675 non-null float64
35 products.taxful_price 4675 non-null float64
36 products.taxless_price 4675 non-null float64
37 products.unit_discount_amount 4675 non-null float64
38 sku 4675 non-null object
39 taxful_total_price 4675 non-null float64
40 taxless_total_price 4675 non-null float64
41 total_quantity 4675 non-null int64
42 total_unique_products 4675 non-null int64
43 type 4675 non-null object
44 user 4675 non-null object
dtypes: datetime64[ns](3), float64(12), int64(5), object(25)
memory usage: 96.0 bytes# calculating descriptive statistics from the Eland dataframe:
ed_ecommerce.describe()
我们还可以注意到,内存使用从 pandas 数据帧中的大约 840 Kbs 变成了 Eland 数据帧中的仅 96 字节。我们不需要将整个数据集保存在内存中来从索引中检索我们需要的信息。大部分工作负载留在弹性搜索集群(3)中作为聚合或特定查询。
对于如此小的数据集,这并不重要。尽管如此,当我们扩展到千兆字节的数据时,不把所有东西都保存在内存中进行简单计算和分析的好处更加明显。
数据框架的弹性搜索功能
Eland 抽象了 Elasticsearch 中许多已经存在的 API,数据科学家不需要学习 Elasticsearch 的特定语法。例如,可以获得索引的映射(相当于检索熊猫数据帧的dtypes
属性)。尽管如此,目前还不清楚该如何做。使用 Eland DataFrame 对象,我们可以像在常规 pandas DataFrame 上一样检索dtypes
属性。
# getting the dtypes from pandas dataframe:
df_ecommerce.dtypescategory object
currency object
customer_first_name object
customer_full_name object
customer_gender object
...
total_quantity int64
total_unique_products int64
type object
user object
geoip object
Length: 23, dtype: object# retrieving the Data types for the index normally would require us to perform the following Elasticsearch query:
mapping = es.indices.get_mapping(index_name)
# which by itself is an abstraction of the GET request for mapping retrieval
print(json.dumps(mapping, indent=2, sort_keys=True)){
"kibana_sample_data_ecommerce": {
"mappings": {
"properties": {
"category": {
"fields": {
"keyword": {
"type": "keyword"
}
},
"type": "text"
},
"currency": {
"type": "keyword"
},
"customer_birth_date": {
"type": "date"
},
"customer_first_name": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"customer_full_name": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
}
...# Eland abstracts this procedure into the same pandas api:
ed_ecommerce.dtypescategory object
currency object
customer_birth_date datetime64[ns]
customer_first_name object
customer_full_name object
...
taxless_total_price float64
total_quantity int64
total_unique_products int64
type object
user object
Length: 45, dtype: object
有了这些抽象,Eland 允许我们使用核心的 Elasticsearch 特性,这些特性不是 pandas 的一部分(或者至少不是那么高效),比如全文搜索,Elasticsearch 最突出的用例。
# defining the full-text query we need: Retrieving records for either Elitelligence or Primemaster manufacturer
query = {
"query_string" : {
"fields" : ["manufacturer"],
"query" : "Elitelligence OR Primemaster"
}
}# using full-text search capabilities with Eland:
text_search_df = ed_ecommerce.es_query(query)
# visualizing price of products for each manufacturer using pandas column syntax:
text_search_df[['manufacturer','products.price']]
更多集成的可能性
本文只是触及了 Eland 为数据科学家和其他数据专业人员在日常操作中使用 Elasticsearch 所带来的可能性的表面。
特别是在 DevOps 和 AIOps 环境中,基于 ML 的工具还不是很成熟,数据专业人员可以从 Python 现有的机器学习生态系统中受益,以分析大量的可观测性和度量数据,这将是另一篇文章的主题。
Eland 无疑是向 Elasticsearch 迈出的一大步,我期待 ELK stack 的未来版本会带来什么。
如果你喜欢这篇文章
查看本次网络研讨会,其中塞斯·迈克尔·拉森(Eland 的主要贡献者之一)介绍了 Eland 的主要功能。
如果你想看到更多关于弹性搜索、数据科学、信息检索、可观察性背景下的 NLP 的内容,请随时在 LinkedIn 上 与我联系 和 阅读我关于这些主题的其他文章 。
脚注:
- 截至 ELK stack 7.8 版本,回归和分类机器学习作业仍处于试验阶段。
- 对于这些任务,可以使用更熟悉的类似 SQL 的查询界面,比如 Elasticsearch 的 JDBC 驱动程序。然而,这仍然需要对弹性搜索概念(例如,索引模式和分页)有一定的了解。
- 这类似于其他分布式计算模块,如 Dask。Eland 的 case 本质上在内部维护了一个查询构建器和任务图,只有在请求数据时才运行这些延迟的任务。
参考资料:
- 页(page 的缩写)Andlinger, Elasticsearch 取代 Solr 成为最受欢迎的搜索引擎 (2016),DB-engines 上博文的URL。
- Elastic.co,【Eland 官方文档 (2020),网址为。
- Seth Michael Larson,Eland 简介 Elasticsearch 支持的数据框架和机器学习 (2020),网上研讨会的 URL。