TowardsDataScience-博客中文翻译-2020-一百二十三-
TowardsDataScience 博客中文翻译 2020(一百二十三)
无监督学习—第 1 部分
FAU 讲座笔记关于深度学习
动机和受限玻尔兹曼机器
FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!
航行
欢迎回到深度学习!所以今天,我们想谈谈无监督方法,特别是,我们将在接下来的几个视频中重点关注自动编码器和 GANs。我们今天将从基础、动机开始,并研究一种相当历史的方法——受限玻尔兹曼机器。我们仍然在这里提到它们,因为它们对无监督学习的发展很重要。
无监督学习的动机。 CC 下的图片来自深度学习讲座的 4.0 。
让我们看看我为你准备了什么。所以,我说的主要话题是无监督学习。当然,我们从我们的动机开始。所以,你可以看到,我们到目前为止看到的数据集是巨大的,它们有多达数百万个不同的训练观察,许多对象,特别是少数模态。我们所看到的大部分东西本质上都是相机拍摄的图像。可能使用了不同的摄像机,但通常只有一个或两个模态在一个数据集中。然而,通常情况并非如此。例如,在医学成像领域,您通常有非常小的数据集,可能只有 30 到 100 名患者。你只有一个复杂的对象,那就是人体和许多不同的模态,从 MR、X 射线到超声波。它们都有非常不同的外观,这意味着它们在加工方面也有不同的要求。那么为什么会这样呢?在德国,实际上每 1000 名居民有 65 次 CT 扫描。这意味着仅在 2014 年,德国就有 500 万次 CT 扫描。所以,应该有大量的数据。为什么我们不能使用所有这些数据?当然,这些数据是敏感的,它们包含了病人的健康信息。例如,如果你有一个包含头部的 CT 扫描,那么你可以渲染脸部表面,你甚至可以使用一个自动系统来确定这个人的身份。也有不明显的暗示。例如,如果你有大脑的表面,这个表面实际上是某个人的特征。你可以通过大脑形状的来识别人,准确率高达 99%。所以,你可以看到这确实是高度敏感的数据。如果你分享整本书,人们也许能认出这个人,尽管,你可能会说很难从一张切片图像中认出一个人。因此,有一些趋势使这样的数据变得可用。但是,你仍然有问题,即使你有数据,你需要标签。所以,你需要专家来查看数据,告诉你存在什么样的疾病,哪个解剖结构在哪里,等等。这也是非常昂贵的获得。
类激活映射。来自深度学习讲座的 CC BY 4.0 下的图片。
因此,如果我们有一些方法可以在很少注释甚至没有注释的情况下工作,那就太好了。我这里有一些这方面的例子。一个趋势是弱监督学习。因此,这里有一个相关任务的标签。我们在这里展示的例子是来自类标签的本地化。比方说,你有图像,你有像刷牙或砍树这样的课程。然后,你可以使用这些加上相关的梯度信息,像使用可视化机制,你可以在特定的图像中定位类。这是一种可以获得非常便宜的标签的方法,例如,对于边界框。还有半监督技术,在这种技术中,你只有很少的标记数据,你试图将它应用到一个更大的数据集。这里的典型方法是自举。从一个小的带标签的数据集创建一个弱分类器。然后,将它应用于一个大型数据集,并尝试估计该大型数据集中的哪些数据点已被可靠地分类。接下来,你把可靠的系统放入一个新的训练集,用这个新的训练集,你可以重新开始尝试建立一个新的系统。最后,你迭代,直到你有一个更好的系统。
当然,也有不需要任何标记数据的无监督技术。这将是接下来几个视频的主题。所以我们来看看无标签学习。这里的一个典型应用是降维。这里,你有一个数据在高维空间的例子。我们有一个三维空间。实际上,我们只是给你展示这个三维空间的一部分。你可以看到数据被卷起,我们在这张图片中用相似的颜色来标识相似的点。你可以看到这个三维流形,通常被称为瑞士卷。现在,瑞士卷实际上并不需要三维表示。所以,你想做的是自动展开它。你可以看到在右边,维度减少了。所以,这里只有两个维度。这已经使用非线性的流形学习技术或维度缩减技术自动完成。使用这些非线性方法,您可以将数据集分解成更低的维度。这很有用,因为较小的维度应该携带所有你需要的信息,你现在可以用它作为一种表示。
使用自动编码器的表征学习。 CC 下的图片来自深度学习讲座的 4.0 。
我们还将在接下来的几个视频中看到,您可以将此用作网络初始化。你已经看到了第一个自动编码器结构。你训练这样一个有瓶颈的网络,在那里你有一个低维的表示。后来,你把这种低维的表现,并重新利用它。这意味着您实际上删除了网络的右边部分,并用一个不同的部分替换它。在这里,我们用它来分类,同样我们的例子是分类猫和狗。因此,你已经可以看到,如果我们能够进行这样的降维,在低维空间中保留原始信息,那么我们可能会有更少的权重来处理分类任务。顺便说一下,这与我们在讨论迁移学习技巧时已经讨论过的非常相似。
基于 t-SNE 的维数约简。来自深度学习讲座的 CC BY 4.0 下的图片。
您也可以使用它进行聚类,您已经看到了这一点。我们已经在可视化一章中使用了这种技术,在这一章中,我们进行了非常好的降维,我们放大并查看了这里的不同地方。
无监督学习的应用。 CC 下的图片来自深度学习讲座的 4.0 。
你已经看到,如果你有一个好的学习方法,可以提取一个好的表示,那么你也可以用它来识别这样一个低维空间中的相似图像。嗯,这也可以用于生成模型。所以在这里,任务是生成逼真的图像。你可以用这个来解决丢失数据的问题。这就导致了半监督学习,你也可以利用这一点,例如,增强。你也可以用它来进行图像到图像的翻译,这也是一个非常酷的应用。我们稍后将看到所谓的循环 GAN,在这里您可以真正地进行域转换。你也可以用这个来模拟强化学习中可能的未来。所以,我们会有各种各样有趣的领域,我们也可以在这些领域应用这些无监督的技术。这里有一些数据生成的例子。你用左手边训练,然后在右手边生成这些图像。这将是一件很有吸引力的事情。你可以生成看起来像真实观察的图像。
对我们班上接下来几个话题的概述。 CC 下的图片来自深度学习讲座的 4.0 。
所以今天,我们将讨论受限玻尔兹曼机器。如前所述,它们具有重要的历史意义。但是,老实说,现在它们已经不常用了。它们是我们之前看到的重大突破的一部分。比如在谷歌梦里。所以,我觉得你应该了解这些技术。
MNIST 之梦。使用 gifify 创建的图像。来源: YouTube
稍后,我们将讨论自动编码器,它本质上是一种新兴技术,有点类似于受限玻尔兹曼机器。您可以在前馈网络环境中使用它们。你可以使用它们进行非线性降维,甚至可以扩展到生成模型,比如变分自动编码器,这也是一个很酷的技巧。最后,我们将讨论一般的敌对网络,这可能是目前最广泛使用的生成模型。这个非常普遍的概念有许多应用。您可以将它用于图像分割、重建、半监督学习等等。
受限玻尔兹曼机综述。 CC 下的图片来自深度学习讲座的 4.0 。
但我们先从历史角度来看。大概这些像受限玻尔兹曼机这样的历史东西,如果你在某个时候和我一起遇到考试,就没那么重要了。尽管如此,我认为你应该知道这项技术。这个想法非常简单。所以,你从两组节点开始。其中一个由可见单元组成,另一个由隐藏单元组成。他们是有联系的。所以,你有可见的单位 v ,它们代表观察到的数据。然后,您有了捕获依赖关系的隐藏单元。所以它们是潜在变量,应该是二进制的。所以它们应该是 0 和 1。现在,我们可以用这个二分图做什么呢?
RBM 寻求最大化玻尔兹曼分布。来自深度学习讲座的 4.0CC 下的图片。
嗯,你可以看到,受限玻尔兹曼机是基于一个能量模型,它的联合概率函数是 p( v , h )。它是用能量函数来定义的,这个能量函数用在概率中。所以,你有 1/Z,这是一种归一化常数。然后,E 的-E 次方( v , h )。我们在这里定义的能量函数 E( v , h )本质上是一个偏差与 v 另一个偏差和 h 的内积,然后是一个用矩阵 W 加权的 v 和 h 的加权内积。所以,你可以看到这里的未知数本质上是 b 、 c 和矩阵 W 。所以,这个概率密度函数叫做玻尔兹曼分布。它与 softmax 函数密切相关。请记住,这不仅仅是一个完全连接的层,因为它不是前馈。所以,你输入受限玻尔兹曼机器,你确定 h ,然后从 h 你可以再次产生 v 。因此,隐藏层以随机方式模拟输入层,并在无监督的情况下进行训练。
我们使用波尔兹曼分布的对数似然性来推导训练过程。 CC 下的图片来自深度学习讲座的 4.0 。
所以让我们来看看这里的一些细节。正如我已经提到的,可见和隐藏的单元形成了这个二分图。你可能会说我们的 RBM 是带有隐藏变量的马尔可夫随机场。然后,我们想要找到 W 使得我们的概率对于低能态是高的,反之亦然。该学习基于负对数似然的梯度下降。所以,我们从对数似然开始,你可以在这张幻灯片上看到一个小错误。我们在 p( v , h 中少了一个日志。我们已经在下一行中解决了这个问题,我们有 1/Z 的对数和指数函数的和。现在,我们可以使用 Z 的定义并扩展它。这允许我们把这个乘法写成第二个对数项。因为它是 1/Z,所以它是-log Z 的定义。这是对-E( v , h )的指数函数的 v 和 h 之和。现在,如果我们看看梯度,你可以看到完整的推导在[5]中给出。你实际上得到的是两个和。一个是 p( h , v )乘以关于参数的能量函数的负偏导数的总和减去 p( v , h )乘以关于参数的能量函数的负偏导数的总和。同样,您可以将这两个术语解释为数据的期望值和模型的期望值。一般来说,模型的期望值是难以处理的,但是你可以用所谓的对比散度来近似这个。
对比差异的更新规则。 CC 下的图片来自深度学习讲座的 4.0 。
现在,对比分歧是这样运作的:你把任何一个训练的例子都看作是对。然后,通过计算 v s 加上偏差的加权和的 sigmoid 函数,设置隐藏单元的二进制状态。这给了你隐藏单元的概率。然后,您可以运行 k Gibbs 采样步骤,通过计算给定 h 的 v 下标 j =1 的概率,再次计算对 h 加上偏差的加权和的 sigmoid 函数,从而对重构 v 波形进行采样。所以,你用的是在第二步中计算的隐藏单位。然后,您可以使用它对重建的 v 波浪号进行采样。这允许您再次对 h 波浪号重新取样。所以,你运行这个程序几个步骤,如果你这样做了,你就可以计算梯度更新。矩阵 W 的梯度更新由η乘以vh 转置减去 v 波浪号 h 波浪号转置给出。偏差的更新为η乘以 v — v 波形,偏差 c 的更新为η乘以 h — h 波形。这也允许你更新权重。这样你就可以开始计算适当的权重和偏差。所以 Gibbs 抽样的迭代次数越多,梯度的估计偏差就越小。在实际操作中, k 简单选择为一。
RBM 上的 RBM 创建深度信任网络。 CC 下的图片来自深度学习讲座的 4.0 。
你可以在此基础上扩展成一个深度的信念网络。这里的想法是,然后你在顶部再次堆叠层。深度学习的想法就像一层层的。所以我们需要更深入,这里我们有一个受限玻尔兹曼机器,在另一个受限玻尔兹曼机器上面。所以,你可以用它来创建真正的深层网络。您可以使用的另一个技巧是,例如,使用最后一个图层对其进行微调以完成分类任务。
行动中的深度信任网络。使用 gifify 创建的图像。来源: YouTube
正如你在[9]中看到的,这是第一个成功的深度架构之一。这引发了深度学习的复兴。现在人民币已经很少用了。所以,深度信念网络不再常用了。
在这个深度学习讲座中,更多令人兴奋的事情即将到来。 CC 下的图片来自深度学习讲座的 4.0 。
这就是我们下次讨论自动编码器的原因。在接下来的几个视频中,我们将探讨更复杂的方法,例如,生殖对抗网络。所以,我希望你喜欢这个视频,如果你喜欢它,那么我希望在下一个视频中看到你。再见!
如果你喜欢这篇文章,你可以在这里找到更多的文章,在这里找到更多关于机器学习的教育材料,或者看看我们的深度 学习 讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube、Twitter、脸书、LinkedIn 或 T21。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中生成文字记录,试试自动博客。
链接
链接 —变型自动编码器:
链接—NIPS 2016 good fellow 的 GAN 教程
链接 —如何训练一个 GAN?让 GANs 发挥作用的技巧和诀窍(小心,而不是
一切都是真的了!)
链接——有没有想过怎么给自己的甘起名?
参考
[1]陈曦,陈曦,闫端,等.“InfoGAN:基于信息最大化生成对抗网的可解释表征学习”.神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2172-2180 页。
[2] Pascal Vincent,Hugo Larochelle,Isabelle Lajoie 等,“堆叠去噪自动编码器:用局部去噪标准学习深度网络中的有用表示”。《机器学习研究杂志》第 11 期。2010 年 12 月,第 3371-3408 页。
[3] Emily L. Denton,Soumith Chintala,Arthur Szlam 等,“使用拉普拉斯金字塔对抗网络的深度生成图像模型”。载于:CoRR abs/1506.05751 (2015 年)。arXiv: 1506.05751。
[4]理查德·杜达、彼得·e·哈特和大卫·g·斯托克。模式分类。第二版。纽约:Wiley-Interscience,2000 年 11 月。
[5]阿斯嘉菲舍尔和克里斯蒂安伊格尔。“训练受限制的玻尔兹曼机器:介绍”。载于:模式识别 47.1 (2014),第 25–39 页。
[6]约翰·高迪尔。用于人脸生成的条件生成对抗网络。2015 年 3 月 17 日。网址:http://www.foldl.me/2015/conditional-gans-face-generation/(2018 年 1 月 22 日访问)。
【7】伊恩·古德菲勒。NIPS 2016 教程:生成性对抗网络。2016.eprint: arXiv:1701.00160。
【8】Martin HEU sel,Hubert Ramsauer,Thomas Unterthiner 等,“通过双时标更新规则训练的 GANs 收敛到局部纳什均衡”。神经信息处理系统进展 30。柯伦联合公司,2017 年,第 6626–6637 页。[9]杰弗里·E·辛顿和鲁斯兰·R·萨拉胡季诺夫。"用神经网络降低数据的维数."刊登在:科学 313.5786(2006 年 7 月),第 504–507 页。arXiv: 20。
【10】杰弗里·e·辛顿。“训练受限玻尔兹曼机器的实用指南”。神经网络:交易技巧:第二版。柏林,海德堡:施普林格柏林海德堡,2012 年,第 599-619 页。
[11]菲利普·伊索拉,,周廷辉等,“条件对立网络下的意象翻译”。在:(2016 年)。eprint: arXiv:1611.07004。
[12]迪耶德里克·P·金马和马克斯·韦林。“自动编码变分贝叶斯”。载于:arXiv 电子版,arXiv:1312.6114(2013 年 12 月),arXiv:1312.6114。arXiv:1312.6114[统计。ML】。
[13] Jonathan Masci、Ueli Meier、Dan Ciresan 等人,“用于分层特征提取的堆叠卷积自动编码器”。载于:人工神经网络和机器学习— ICANN 2011。柏林,海德堡:施普林格柏林海德堡,2011 年,第 52-59 页。
[14]卢克·梅茨、本·普尔、大卫·普法乌等人,《展开的生成性敌对网络》。国际学习代表会议。2017 年 4 月。eprint: arXiv:1611.02163。
[15]迈赫迪米尔扎和西蒙奥辛德罗。“条件生成对抗网”。载于:CoRR abs/1411.1784 (2014 年)。arXiv: 1411.1784。
[16]亚历克·拉德福德、卢克·梅斯和索史密斯·钦塔拉。深度卷积生成对抗的无监督表示学习 2015。eprint: arXiv:1511.06434。
[17] Tim Salimans,Ian Goodfellow,Wojciech Zaremba 等,“训练 GANs 的改进技术”。神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2234–2242 页。
【18】吴恩达。“CS294A 课堂笔记”。2011 年。
【19】张寒、徐涛、李洪生等,“StackGAN:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:CoRR abs/1612.03242 (2016 年)。arXiv: 1612.03242。
【20】张寒、徐涛、李洪生等,“Stackgan:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:arXiv 预印本 arXiv:1612.03242 (2016)。
【21】周,Aditya Khosla,Agata Lapedriza 等,“学习深度特征用于鉴别性定位”。In: 2016 年 IEEE 计算机视觉与模式识别大会(CVPR)。拉斯维加斯,2016 年 6 月,第 2921–2929 页。arXiv: 1512.04150。
[22]朱俊彦,朴泰成,菲利普·伊索拉等,“利用循环一致的对立网络进行不成对的图像到图像的翻译”。载于:CoRR abs/1703.10593 (2017 年)。arXiv: 1703.10593。
无监督学习—第二部分
FAU 讲座笔记关于深度学习
自动编码器
FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是讲座视频&配套幻灯片的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!
航行
欢迎回到深度学习!今天,我们想继续讨论无监督方法,并研究一种非常流行的技术,即所谓的自动编码器。
一个“自动”编码形状的例子(双关语)。使用 gifify 创建的图像。来源: YouTube
这是我们的幻灯片。我们讲座的第二部分和主题自动编码器。嗯,自动编码器的概念是我们想要使用前馈神经网络的想法。你可以说前馈神经网络是产生某种编码的 x 的函数 y 。
给定一些额外的约束,自动编码器尝试再现输入。 CC 下的图片来自深度学习讲座的 4.0 。
现在,问题是:“我们如何在这样的星座中产生损失?”这个想法相当简单。我们在顶部添加了一个附加层,该层的目的是计算解码。所以,我们还有另一层,那就是 g( y )。g( y )产生一些 x 的帽子。我们可以定义的损失是 x hat 和 x 需要相同。所以自动编码器试图学习身份的近似值。嗯,听起来很简单。老实说,如果我们在输入和隐藏层中对于这里的 y 有完全相同数量的节点,那么最简单的解决方案可能是同一性。那么这到底有什么用呢?
不同的自动编码器损失函数。来自深度学习讲座的 4.0CC 下的图片。
我们来看看一些损失函数。你通常可以使用一个损失函数,然后在这里对 x 和一些 x 进行运算。它可以与负对数似然函数成比例,其中有 p( x | x ')和结果函数。然后,以类似的方式,正如我们在本课程前面看到的,你可以使用平方 L2 范数,假设你的函数的概率密度是均匀方差的正态分布。然后,你以 L2 的损失而告终。简单来说就是 x 减去 x ,这包含在 L2 范数中。当然也可以做交叉熵之类的事情。所以,如果你假设伯努利分布,你会看到我们最终得到的是交叉熵。这就是加权的 x 乘以 x 的对数加上 1- x 下标 I 乘以 1-x下标 I 的和。记住,如果你想这样使用它,那么你的 x 需要在概率范围内。因此,如果您想要应用这种损失函数,那么您可能想要将它与 softmax 函数结合使用。
不完整的自动编码器。 CC 下的图片来自深度学习讲座的 4.0 。
好了,这里有一些构建这种自动编码器的典型策略。我认为最流行的是欠完整自动编码器。所以在这里,你通过在隐藏层使用更少的神经元来实施信息压缩。你试图找到一种变换,这种变换实质上是对隐藏层进行降维。然后,您尝试从这个隐藏层扩展到原始数据域,并尝试找到产生最小损失的解决方案。所以,你试着在这里学习压缩。顺便说一句,如果你用线性图层和平方 L2 范数来做这件事,你基本上学会了主成分分析(PCA)。如果将它用于非线性图层,最终会得到类似非线性 PCA 泛化的结果。
稀疏自动编码器。 CC 下的图片来自深度学习讲座的 4.0 。
还有类似这些稀疏自动编码器的东西。这里,我们有一个不同的想法。我们甚至增加了神经元的数量,以模拟一个一键编码的向量。所以,你可能会说:“为什么要增加神经元的数量呢?然后,你甚至可以找到一个更简单的解决方案,比如身份,然后忽略其中的几个神经元!”所以,这个想法不会直接奏效。你必须加强稀疏性,这也创造了稀疏自动编码器的名称。这里,您必须使用一些额外的正则化来增强激活的稀疏性。例如,您可以在 y 的激活上使用 L1 范数来实现这一点。请记住,稀疏自动编码器中的稀疏性源于激活中的稀疏性,而不是权重中的稀疏性。如果你看看你的身份,你会发现这只是一个对角线矩阵,对角线上有 1。所以,这也是一个非常稀疏的解决方案。因此,再次强调激活的稀疏性,而不是权重。
稀疏自动编码的作用。使用 gifify 创建的图像。来源: YouTube
还能做什么?你可以使用自动编码器变体。你可以把它和我们在这个课程中学到的所有食谱结合起来。您可以构建卷积自动编码器。在这里,您可以用卷积层替换完全连接的层,也可以选择添加池层。
更多自动编码器变体。 CC 下的图片来自深度学习讲座的 4.0 。
还有去噪自动编码器,这也是一个非常有趣的概念。在这里,噪声破坏了输入,目标就是无噪声的原始样本。因此,这就产生了一个经过训练的系统,它不只是进行降维或寻找稀疏表示。同时,它还执行去噪,您可能会认为这是一种额外的正则化,类似于 dropout,但本质上应用于输入图层。还有一篇名为 noise2noise 的非常有趣的论文,其中他们表明,即使你有一个嘈杂的目标,你甚至可以建立这样的去噪自动编码器。这里的关键是,在输入和目标中有不同的噪声模式,这样你也可以训练去噪自动编码器,至少如果你建立在卷积自动编码器之上。
去噪自动编码器也用于图像生成。来自深度学习讲座的 CC BY 4.0 下的图片。
现在,你甚至可以使用去噪自动编码器作为生成模型。这里的想法是,如果你频繁地采样你的腐败模型,你的噪声模型。然后,去噪自动编码器学习相应输入的概率。因此,如果有 x 作为典型样本,那么通过迭代应用噪声和去噪将会经常重现该样本。因此,您可以使用马尔可夫链,交替使用去噪模型和腐败过程。这就产生了 p( x )的估计量。老实说,这通常很昂贵,并且很难评估收敛性,这就是为什么所谓的变分自动编码器更常见的原因。我们将在几张幻灯片中讨论这些不同的自动编码器。
堆叠自动编码器嵌套自动编码器。 CC 下的图片来自深度学习讲座的 4.0 。
我们需要先介绍一些变化。有所谓的堆叠式自动编码器。在堆栈式自动编码器中,实际上是将自动编码器放在自动编码器的内部。这使得我们能够构建真正的深度自动编码器。我们在这个概念中看到了这一点。自动编码器 1 在隐藏层中使用由蓝色节点指示的自动编码器 2。你可以把它们堆叠成一个自动编码器。
此自动编码器的堆叠版本。 CC 下的图片来自深度学习讲座的 4.0 。
这产生了下面的模型,然后想法是有一个逐渐的维度减少。你可能已经猜到了:这也是卷积和池经常用到的东西。
离散空间中的潜在空间阐释。来自深度学习讲座的 CC BY 4.0 下的图片。
现在让我们进入变分自动编码器的概念。这是一个有点不同的概念。在传统的自动编码器中,您试图计算一个确定性的特征向量,该向量描述了某种潜在空间中的输入属性。比方说,你有一个潜在的空间,它描述了不同的特征,例如,一张脸。然后,你可能会说,这个编码器然后把图像投射到一些可能未知的潜在属性上。在这里,我们给他们一些额外的解释。所以对于每一个属性,你都有一个特定的分数,然后根据这个分数,你再次生成原始图像。变分自动编码器的关键区别在于你使用一种变分的方法来学习潜在的表示。它允许你以概率的方式描述潜在空间。
离散与分布建模。 CC 下的图片来自深度学习讲座的 4.0 。
所以这个想法是,它不仅仅是一个简单的每个维度的分类,而是你想要描述每个维度的概率分布。因此,如果我们只有常规的自动编码器,你会在每张图片的左侧看到缩放比例。可变微笑将是一个离散值,您可以选择一个或多或少微笑可用的点。相比之下,变分自动编码器允许您描述属性“微笑”的概率分布。你可以看到第一排没有那么多微笑。第二排是蒙娜丽莎,你不能确定她是否在微笑。人们已经为此争论了几个世纪。你可以看到变分自动编码器能够通过在这个潜在变量上增加一个方差来描述这种不确定性。所以,我们可以看到我们不确定这是不是一个微笑。然后,我们有非常清晰的微笑的例子,然后,当然,分布有一个低得多的标准差。
变分自动编码器使用分布对潜在空间建模。 CC 下的图片来自深度学习讲座的 4.0 。
那么这将如何工作呢?嗯,你有一些编码器,将你的输入映射到潜在属性,然后解码器对这个分布进行采样,以产生最终的输出。所以,这意味着我们有一个概率分布的表示,它加强了一个连续和平滑的潜在空间表示。相似的潜在空间向量应该对应于相似的重建。
变分自动编码器的统计动机。来自深度学习讲座的 CC BY 4.0 下的图片。
嗯,这里的假设是我们有一些隐藏的潜在变量 z 产生一些观察值 x. 然后你可以通过确定 z 的分布来训练变分自动编码器。那么,问题是这个分布 p( z | x )的计算通常是很难处理的。所以,我们必须用一个易处理的分布来近似我们的 p( z | x )。这意味着易处理的分布 q 会导致我们必须确定 q 的参数的问题。例如,您可以为此使用高斯分布。然后,你可以用这个来定义 P( z | x )和 q( z | x )之间的 Kullback-Leibler 散度。这相当于最大化 p( x | z )的对数的期望值减去 q( z | x )与 p( z )的 KL 散度的重构似然。这迫使 q( z | x )类似于真实的先验分布 p( z )。
变型自动编码器设计草图。 CC 下的图片来自深度学习讲座的 4.0 。
所以现在,p( z )经常被假设为各向同性的高斯分布。现在确定 q( z | x )归结为估计参数向量 μ 和 σ 。所以,我们用神经网络来做这件事。谁会想到呢?我们估计我们的 q( z | x )和 p( x | z )。所以在这里,你可以看到大致的轮廓。再次,你看到这个自动编码器结构,我们有这个编码器 q( z | x )产生潜在空间表示,然后我们的 p( x | z )再次产生我们的输出x’。 x 应该和 x 差不多。
可变自动编码器网络结构综述。 CC 下的图片来自深度学习讲座的 4.0 。
那么,让我们更详细地看看这个。您可以看到,在编码器分支中,我们基本上有一个经典的家用前馈神经网络来降低维度。我们接下来要做的是引入一个关键的变化。这里用浅红色和浅绿色表示。现在这里的关键思想是,在由颜色指示的特定层中,我们改变激活的解释。在这些神经元中,它们本质上只是前馈层,但我们将上面的两个神经元解释为我们潜在分布的平均值,而下面的两个神经元解释为潜在分布的方差。现在,关键问题是,为了进入下一层,我们必须从这些分布中进行采样,以便获得实际观察值并对其进行解码。那么,如何才能做到这一点呢?这里我们有一个问题,因为我们不能通过随机抽样过程反向传播。
重新参数化的把戏。来自深度学习讲座的 CC BY 4.0 下的图片。
这里的想法是编码器产生均值和方差。然后,我们产生一些 z ,这是我们的函数 q( z | x )的一个采样。这是一个随机节点,随机性的问题是我们不知道如何反向传播这个节点。因此,我们在正向传递中引入的关键元素是我们重新参数化了 z 。 z 确定为 μ 加上 σ 乘以某个 ε 。 ε 是随机信息。现在它源于一个简单连接到 z 的随机发生器。例如,你可以选择它是一个均值和单位方差为零的高斯分布。这样,我们就可以反向传播到 μ 和 σ 中,因为随机节点在右边,我们不需要反向传播到随机节点中。因此,通过这种重新参数化的技巧,我们甚至可以将采样作为一个层引入网络。所以,这是非常令人兴奋的,你已经猜到了。这也很好,因为我们可以利用这个噪声,从这个特定的分布中产生随机样本。因此,我们可以使用自动编码器的右侧来产生新的样本。所有这些在反向传播中都是确定的,你可以用和我们以前一样的方法计算梯度。您可以像以前一样应用反向传播算法。
不同潜在空间的比较。 CC 下的图片来自深度学习讲座的 4.0 。
那么这有什么作用呢?在这里,我们有一些潜在的空间可视化。如果仅使用重建损失,可以看到样本分离良好,但没有平滑过渡。显然,如果你只有 KL 散度,那么你就不能描述原始数据。因此,你需要一个组合,同时优化输入分布和各自的 KL 散度。这很酷,因为我们可以从潜在空间的分布中采样,产生新的数据,然后用解码器重建,对角线先验强制独立的潜在变量
使用变分自动编码器的图像生成。 CC 下的图片来自深度学习讲座的 4.0 。
所以,我们可以编码不同的变异因素。这里,我们有一个例子,我们平滑地改变微笑的程度和头部姿势。你可以看到这种解开实际上是有效的。
变分自动编码器中的潜在空间探索。使用 gifify 创建的图像。来源: YouTube
所以,我们总结一下。变分自动编码器是一个概率模型,允许您从一个棘手的密度生成数据。相反,我们能够优化一个变分的下限,这是通过使用重新参数化的反向传播来训练的。
变型自动编码器概述。 CC 下的图片来自深度学习讲座的 4.0 。
优点是我们对生成建模有一个原则性的方法。潜在空间表征对于其他任务可能非常有用,但缺点是这只能最大化可能性的下限。因此,标准模型中的样本通常比生成敌对网络中的样本质量低。这仍然是一个活跃的研究领域。因此,在这个视频中,我给了大家一个非常好的自动编码器总结,重要的技术当然是简单自动编码器、欠完整自动编码器、稀疏自动编码器和堆叠自动编码器。最后,我们一直在研究变分自动编码器,以便能够生成数据,并能够描述我们的潜在变量空间中的概率分布。
在这个深度学习讲座中,更多令人兴奋的事情即将到来。来自深度学习讲座的 4.0CC 下的图片。
在下一个视频中,我们将看到数据生成是一项非常有趣的任务,我们基本上可以从无人监管的数据中完成。这就是为什么我们要研究生成性对抗网络。您将看到这是一项非常有趣的技术,它已经在许多不同的应用程序中得到广泛使用,以便使用深度神经网络的能力来执行数据生成。所以,我希望你喜欢这个视频。我们讨论了无监督学习的非常重要的点,我认为这些是广泛使用的最先进的技术。所以,如果你喜欢这个视频,请继续关注,期待在下一部中与你见面。谢谢您们。再见!
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客。
链接
链接 —变型自动编码器:
链接—NIPS 2016 good fellow 的 GAN 教程
链接 —如何训练一个 GAN?让 GANs 发挥作用的技巧和诀窍(小心,而不是
一切都是真的了!)
链接——有没有想过怎么给自己的甘起名?
参考
[1]陈曦,陈曦,闫端,等.“InfoGAN:基于信息最大化生成对抗网的可解释表征学习”.神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2172-2180 页。
[2] Pascal Vincent,Hugo Larochelle,Isabelle Lajoie 等,“堆叠去噪自动编码器:用局部去噪标准学习深度网络中的有用表示”。《机器学习研究杂志》第 11 期。2010 年 12 月,第 3371-3408 页。
[3] Emily L. Denton,Soumith Chintala,Arthur Szlam 等,“使用拉普拉斯金字塔对抗网络的深度生成图像模型”。载于:CoRR abs/1506.05751 (2015 年)。arXiv: 1506.05751。
[4]理查德·杜达、彼得·e·哈特和大卫·g·斯托克。模式分类。第二版。纽约:Wiley-Interscience,2000 年 11 月。
[5]阿斯嘉菲舍尔和克里斯蒂安伊格尔。“训练受限制的玻尔兹曼机器:介绍”。载于:模式识别 47.1 (2014),第 25–39 页。
[6]约翰·高迪尔。用于人脸生成的条件生成对抗网络。2015 年 3 月 17 日。网址:http://www.foldl.me/2015/conditional-gans-face-generation/(2018 年 1 月 22 日访问)。
【7】伊恩·古德菲勒。NIPS 2016 教程:生成性对抗网络。2016.eprint: arXiv:1701.00160。
【8】Martin HEU sel,Hubert Ramsauer,Thomas Unterthiner 等,“通过双时标更新规则训练的 GANs 收敛到局部纳什均衡”。神经信息处理系统进展 30。柯伦联合公司,2017 年,第 6626–6637 页。[9]杰弗里·E·辛顿和鲁斯兰·R·萨拉胡季诺夫。"用神经网络降低数据的维数."刊登在:科学 313.5786(2006 年 7 月),第 504–507 页。arXiv: 20。
【10】杰弗里·e·辛顿。“训练受限玻尔兹曼机器的实用指南”。神经网络:交易技巧:第二版。柏林,海德堡:施普林格柏林海德堡,2012 年,第 599-619 页。
[11]菲利普·伊索拉,,周廷辉等,“条件对立网络下的意象翻译”。在:(2016 年)。eprint: arXiv:1611.07004。
[12]迪耶德里克·P·金马和马克斯·韦林。“自动编码变分贝叶斯”。载于:arXiv 电子版,arXiv:1312.6114(2013 年 12 月),arXiv:1312.6114。arXiv:1312.6114[统计。ML】。
[13] Jonathan Masci、Ueli Meier、Dan Ciresan 等人,“用于分层特征提取的堆叠卷积自动编码器”。载于:人工神经网络和机器学习— ICANN 2011。柏林,海德堡:施普林格柏林海德堡,2011 年,第 52-59 页。
[14]卢克·梅茨、本·普尔、大卫·普法乌等人,《展开的生成性敌对网络》。国际学习代表会议。2017 年 4 月。eprint: arXiv:1611.02163。
[15]迈赫迪米尔扎和西蒙奥辛德罗。“条件生成对抗网”。载于:CoRR abs/1411.1784 (2014 年)。arXiv: 1411.1784。
[16]亚历克·拉德福德、卢克·梅斯和索史密斯·钦塔拉。深度卷积生成对抗的无监督表示学习 2015。eprint: arXiv:1511.06434。
[17] Tim Salimans,Ian Goodfellow,Wojciech Zaremba 等,“训练 GANs 的改进技术”。神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2234–2242 页。
【18】吴恩达。“CS294A 课堂笔记”。2011 年。
【19】张寒、徐涛、李洪生等,“StackGAN:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:CoRR abs/1612.03242 (2016 年)。arXiv: 1612.03242。
【20】张寒、徐涛、李洪生等,“Stackgan:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:arXiv 预印本 arXiv:1612.03242 (2016)。
【21】周,Aditya Khosla,Agata Lapedriza 等,“学习深度特征用于鉴别性定位”。In: 2016 年 IEEE 计算机视觉与模式识别大会(CVPR)。拉斯维加斯,2016 年 6 月,第 2921–2929 页。arXiv: 1512.04150。
[22]朱俊彦,朴泰成,菲利普·伊索拉等,“利用循环一致的对立网络进行不成对的图像到图像的翻译”。载于:CoRR abs/1703.10593 (2017 年)。arXiv: 1703.10593。
无监督学习—第三部分
FAU 讲座笔记关于深度学习
生成性对抗网络——基础
FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是讲座视频&配套幻灯片的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!
航行
一个常见的 AI 误区是甘主要是用来拜猫的。使用 gifify 创建的图像。来源: YouTube
欢迎回到深度学习!所以今天,我们最终想要研究生成对抗网络,这是无监督深度学习中的一项关键技术。让我们看看我为你准备了什么。
嗯,无监督深度学习部分生成对抗网络来自于 GANs 玩下面这个游戏的关键思想:你有一个生成器和一个鉴别器。有人可能会说,发生器是一个制造假图像的人。然后,辨别必须弄清楚生成器实际上生产的是真的还是假的。因此,鉴别者可以决定真假,为了训练鉴别者,他可以访问许多真实的数据观察。因此,鉴别器的结果是输入是真的还是假的。当然,这很难要求个人和艺术家去画东西。因此,我们用深度神经网络代替工具,D 是鉴别器,G 是生成器。发生器接收一些潜在的输入一些噪声变量 z 并从噪声变量和参数中产生一些图像。然后鉴别者试图判断这是真的还是假的图像。因此,鉴频器的输出将为 1 表示真实,0 表示虚假。
甘的损失。来自深度学习讲座的 CC BY 4.0 下的图片。
一旦我们找到了这种神经网络表示,我们也能够描述损失。我们的鉴别器的损失是最小化以下函数,该函数取决于鉴别器的参数和发生器的参数。本质上是将数据中的预期值 x 最小化。这只是我们的鉴频器输出的对数减去一些产生的噪声的期望值,也就是 1 的对数减去一些噪声发生器的鉴频器。所以,它被训练来区分真实数据样本和虚假数据样本。现在,如果你想训练发电机,你要使发电机的损耗最小,即鉴频器的负损耗。因此,生成器将鉴别器正确的概率降至最低。你训练生成域图像来愚弄 d。可选地,你可以为一个玩家的每一步运行另一个玩家的 k 步,并且均衡是鉴别器损失的鞍点。
GANs 把他们的最优化表述为一个极大极小游戏。 CC 下的图片来自深度学习讲座的 4.0 。
如果你更仔细地观察,你会发现发电机的损耗与鉴频器的负损耗直接相关。所以,你可以用一个价值函数来总结这个博弈,这个价值函数指定了鉴别者的收益,即 V,这是鉴别者的负损失,这就导致了下面的极大极小博弈:所以,可以通过将鉴别者的 V 最大化来确定发生器的最优参数集,这个最优参数集被嵌套到 G 的参数的极小化中。
最佳鉴别器可以作为模型和数据的比率找到。 CC 下的图片来自深度学习讲座的 4.0 。
那么,让我们来看看最佳鉴别器。这里有一个关键的假设,即两个密度在任何地方都不为零。否则,一些输入值将永远不会被训练,并且鉴别器将在这些区域中具有不确定的行为。然后求解鉴频器损耗梯度,鉴频器损耗梯度为零。您可以通过以下方式找到任何数据分布和任何模型分布的最佳鉴别器:最佳鉴别器是数据分布除以数据分布加上模型在您的整个输入域 x 上的分布。不幸的是,这种最佳的鉴别是理论上的,是无法实现的。因此,对于 GANs 来说,拥有一个评估机制是非常关键的。你可以用监督学习来估计这个比例。那么这就导致了欠拟合和过拟合的问题。
这个修正的损失是不饱和的。来自深度学习讲座的 4.0CC 下的图片。
现在,我们还能做什么?我们可以做非饱和博弈,修改发电机的损耗。然后,在这个例子中,我们不再对两者使用相同的函数。相反,我们有一个新的发生器损耗,在给定一些输入噪声的情况下,我们只需计算发生器鉴频器对数的期望值。在 minimax 中,G 最小化 D 正确的对数概率。在这个解中,G 最小化了 D 出错的对数概率。它是启发式的,因为当 D 太聪明时,它会对抗 G 的消失梯度。这在开始时尤其是个问题。然而,这种平衡不再能用单一损失来描述。
GAN 损耗的其他变体。 CC 下的图片来自深度学习讲座的 4.0 。
因此,有很多像扩展这样的东西非常受欢迎,比如特征匹配损失或感知损失。这里,G 试图匹配 d 的某个中间层的特征 f( x )的期望值。您已经看到,f 可以是某个其他网络和某个第 3 层或第 5 层表示。然后,对于真实输入和生成的噪声图像,您希望这些表示的期望值相同。所以,这里你要防止发生器对电流鉴频器的过度训练。顺便说一句,这也是许多其他领域的常见损失。
沃瑟斯坦的损失。来自深度学习讲座的 4.0CC 下的图片。
还能做什么?嗯,有所谓的瓦瑟斯坦损失。这是从瓦瑟斯坦距离推导出来的,也就是众所周知的推土机距离。在这里,您将学习一个鉴别器,它可以最大化真假样本之间的差异,同时,您可以限制梯度,使其保持在某个限制之后。所以,你实际上是把梯度限制在一个特定的 Lipschitz 常数上,它是梯度的最大斜率。这里,在右侧的图像中,您可以看到,在快速饱和的红色鉴别曲线之外,您可以创建一个具有非饱和损耗的鉴别器。这样,即使在已经被鉴别器饱和的区域,你也总能找到好的渐变。同样,这有助于抵消鉴别器中的消失梯度。更多的损失函数存在,如 KL 散度。然后,甘实际上做最大似然,但近似策略比损失重要得多。
使用 GANS 可以非常好地生成人脸。使用 gifify 创建的图像。来源: YouTube
那么,我们如何评价甘斯呢?当然,我们可以看着图像说:“是的,它们看起来很逼真!还是没有?”但是这对于大型数据集来说有点棘手。所以,你必须为图像打分。一个想法是初始得分。
使用初始分数评估 GANs。 CC 下的图片来自深度学习讲座的 4.0 。
初始分数基于两个目标。一个目标是生成的图像应该是可识别的。因此,例如,您使用 ImageNet 上的 Inception v3 预训练网络,并且您希望分数分布由一个类支配。基于图像的类别分布应该具有低熵。同时,您希望生成的图像是多样的。所以总体的阶级分布应该或多或少是均匀的。熵应该很高。因此,您可以将这个初始得分表示为 p(y| x )和 p(y)之间的 KL 偏差的期望值的 e 次方。
弗雷歇盗梦空间评分。来自深度学习讲座的 4.0CC 下的图片。
另一种测量是使用中间层的弗雷歇起始距离。例如,Inception v3 的最后一个池层是在 ImageNet 上预训练的。然后,通过多元高斯分布对数据分布进行建模。真实图像 x 和生成图像 g 之间的 FID 分数可以表示为 l2 范数下的 x 和 g 的平均值之差加上 x 和 g 的协方差矩阵的迹减去协方差矩阵 x 乘以协方差矩阵 g 的平方根的两倍。这比初始得分更健壮。我们不需要阶级概念。在这种情况下,我们可以简单地对多元高斯分布进行建模。
GANs 的优点。 CC 下的图片来自深度学习讲座的 4.0 。
GANs 的一大优势是它们能够并行生成样本。限制很少。例如,与有大量限制的玻尔兹曼机器相比:在这个模型中你不需要马尔可夫链。也不需要变分界限。已知 gan 是渐近一致的,因为模型族是通用函数逼近器。这是对甘斯的第一次介绍。
在这个深度学习讲座中,更多令人兴奋的事情即将到来。 CC 下的图片来自深度学习讲座的 4.0 。
在下一个视频中,我们想谈谈更高级的 GAN 概念,如条件 GAN,我们也可以在生成过程中开始并模拟约束和条件。人们还研究了一种非常酷的技术,称为循环 GAN,它允许不成对的域翻译。所以,你可以从白天到晚上翻译图像。你甚至可以把马翻译成斑马,斑马翻译成马。一个非常非常酷的技术即将出现。我希望你喜欢这个视频,我期待着在下一个视频中见到你。非常感谢!
辛普森甘创造你最喜爱的卡通人物。使用 gifify 创建的图像。来源: YouTube
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客。
链接
链接 —变分自动编码器:
链接—NIPS 2016 good fellow 的 GAN 教程
链接 —如何训练一个 GAN?让 GANs 发挥作用的技巧和诀窍(小心,而不是
一切都是真的了!)
链接——有没有想过怎么给自己的甘起名?
参考
[1]陈曦,陈曦,闫端,等.“InfoGAN:基于信息最大化生成对抗网的可解释表征学习”.神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2172-2180 页。
[2] Pascal Vincent,Hugo Larochelle,Isabelle Lajoie 等,“堆叠去噪自动编码器:用局部去噪标准学习深度网络中的有用表示”。《机器学习研究杂志》第 11 期。2010 年 12 月,第 3371-3408 页。
[3] Emily L. Denton,Soumith Chintala,Arthur Szlam 等,“使用拉普拉斯金字塔对抗网络的深度生成图像模型”。载于:CoRR abs/1506.05751 (2015 年)。arXiv: 1506.05751。
[4]理查德·杜达、彼得·e·哈特和大卫·g·斯托克。模式分类。第二版。纽约:Wiley-Interscience,2000 年 11 月。
[5]阿斯嘉菲舍尔和克里斯蒂安伊格尔。“训练受限制的玻尔兹曼机器:介绍”。载于:模式识别 47.1 (2014),第 25–39 页。
[6]约翰·高迪尔。用于人脸生成的条件生成对抗网络。2015 年 3 月 17 日。网址:http://www.foldl.me/2015/conditional-gans-face-generation/(2018 年 1 月 22 日访问)。
【7】伊恩·古德菲勒。NIPS 2016 教程:生成性对抗网络。2016.eprint: arXiv:1701.00160。
【8】Martin HEU sel,Hubert Ramsauer,Thomas Unterthiner 等,“通过双时标更新规则训练的 GANs 收敛到局部纳什均衡”。神经信息处理系统进展 30。柯伦联合公司,2017 年,第 6626–6637 页。[9]杰弗里·E·辛顿和鲁斯兰·R·萨拉胡季诺夫。"用神经网络降低数据的维数."刊登在:科学 313.5786(2006 年 7 月),第 504–507 页。arXiv: 20。
【10】杰弗里·e·辛顿。“训练受限玻尔兹曼机器的实用指南”。神经网络:交易技巧:第二版。柏林,海德堡:施普林格柏林海德堡,2012 年,第 599-619 页。
[11]菲利普·伊索拉,,周廷辉等,“条件对立网络下的意象翻译”。在:(2016 年)。eprint: arXiv:1611.07004。
[12]迪耶德里克·P·金马和马克斯·韦林。“自动编码变分贝叶斯”。载于:arXiv 电子版,arXiv:1312.6114(2013 年 12 月),arXiv:1312.6114。arXiv:1312.6114[统计。ML】。
[13] Jonathan Masci、Ueli Meier、Dan Ciresan 等人,“用于分层特征提取的堆叠卷积自动编码器”。载于:人工神经网络和机器学习— ICANN 2011。柏林,海德堡:施普林格柏林海德堡,2011 年,第 52-59 页。
[14]卢克·梅茨、本·普尔、大卫·普法乌等人,《展开的生成性敌对网络》。国际学习代表会议。2017 年 4 月。eprint: arXiv:1611.02163。
[15]迈赫迪米尔扎和西蒙奥辛德罗。“条件生成对抗网”。载于:CoRR abs/1411.1784 (2014 年)。arXiv: 1411.1784。
[16]亚历克·拉德福德、卢克·梅斯和索史密斯·钦塔拉。深度卷积生成对抗的无监督表示学习 2015。eprint: arXiv:1511.06434。
[17] Tim Salimans,Ian Goodfellow,Wojciech Zaremba 等,“训练 GANs 的改进技术”。神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2234–2242 页。
【18】吴恩达。“CS294A 课堂笔记”。2011 年。
【19】张寒、徐涛、李洪生等,“StackGAN:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:CoRR abs/1612.03242 (2016 年)。arXiv: 1612.03242。
【20】张寒、徐涛、李洪生等,“Stackgan:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:arXiv 预印本 arXiv:1612.03242 (2016)。
【21】周,Aditya Khosla,Agata Lapedriza 等,“学习深度特征用于鉴别性定位”。In: 2016 年 IEEE 计算机视觉与模式识别大会(CVPR)。拉斯维加斯,2016 年 6 月,第 2921–2929 页。arXiv: 1512.04150。
[22]朱俊彦,朴泰成,菲利普·伊索拉等,“利用循环一致的对立网络进行不成对的图像到图像的翻译”。载于:CoRR abs/1703.10593 (2017 年)。arXiv: 1703.10593。
无监督学习—第 4 部分
FAU 讲座笔记关于深度学习
条件和周期甘斯
FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是讲座视频&配套幻灯片的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!
航行
需要你新专辑的封面吗?我能帮助你。使用 gifify 创建的图像。来源: YouTube
欢迎回到深度学习!今天我们想讨论一些更高级的 GAN 概念,特别是条件 GAN 和循环 GAN。
条件 gan 允许控制与某个变量相关的输出。 CC 下的图片来自深度学习讲座的 4.0 。
让我们来看看我幻灯片上的内容。这是我们无监督深度学习讲座的第四部分。首先,我们从条件句开始。到目前为止,我们遇到的一个问题是,生成器创建了一个假的通用图像。不幸的是,它不是针对某个条件或特征的。所以让我们说,如果你有文本到图像的生成,那么,当然,图像应该依赖于文本。因此,您需要能够以某种方式对依赖性进行建模。如果你想生成 0,那就不要生成 1。所以,你需要放入一些条件,你是否想要产生数字 0,1,2,3,等等。这可以通过[15]中介绍的编码条件来实现。
使用调节向量来控制 GAN。 CC 下的图片来自深度学习讲座的 4.0 。
这里的想法是,你本质上把你的潜在向量,分成了本质上有观察的集合。然后,你还有条件,它被编码在条件向量 y 中。你把两者连接起来,用它们来产生某种东西。此外,鉴别器然后获得生成的图像,但是它也获得对条件向量 y 的访问。因此,它知道应该看到什么,以及生成器的具体输出。所以,他们两个都接受了条件,这实质上又导致了一个两人的极小极大博弈,这个博弈又可以被描述为一个依赖于鉴别者的损失。这里的延伸是,你另外有损失中的 y 的条件。
现在,我们可以控制面部表情。 CC 下的图片来自深度学习讲座的 4.0 。
那么这个东西是怎么工作的呢?您添加了一个条件特征,如微笑、性别、年龄或图像的其他属性。然后,发生器和鉴别器学习在这些模式下操作。这就产生了一个属性,你可以生成一个具有某种属性的面。鉴别器知道这是给定特定属性的脸。所以,在这里,你可以看到不同的生成人脸的例子。第一行是随机样本。第二行是老年人的财产。第三行给出的条件是老年加上微笑,这里你可以看到条件向量仍然能够产生类似的图像,但你实际上可以在上面添加这些条件。
因年老而变得健康的甘人。使用 gifify 创建的图像。来源: YouTube
因此,这允许创建真正非常好的东西,如图像到图像的翻译。下面,你有几个输入和输出的例子。基本上,您可以为街道场景创建标签,可以为地图生成航拍图像,可以为立面生成标签,或者为彩色、白天和夜晚以及照片的边缘生成标签。
条件甘的应用还有很多。来自深度学习讲座的 CC BY 4.0 下的图片。
这里的想法是,我们再次使用标签图像作为条件向量。这使我们观察到这是领域翻译。简直是有条件的甘。给出了判别器的正例。下面的例子展示了一个手袋及其边缘。然后,通过将手提包的边缘交给生成器来创建一个愚弄鉴别者的手提包,来构造负样本。
从边缘到手提包的有条件的 GAN。 CC 下的图片来自深度学习讲座的 4.0 。
你可以看到,我们能够通过使用条件甘来生成非常复杂的图像。现在,这里的一个关键问题是,当然,你需要两个图像对齐。因此,你的调节图像,如这里的边缘图像,必须与相应的手提包图像完全匹配。如果他们没有,你就不能训练这个。因此,对于使用条件 gan 的域翻译,您需要精确匹配。在许多情况下,您无法获得精确匹配。假设你有一个展示斑马的场景。你可能找不到显示完全相同场景的配对数据集,但是有马。因此,您不能仅将它与有条件的 GAN 一起使用。
我们能把斑马和马联系起来吗? CC 下的图片来自深度学习讲座的 4.0 。
这里的关键因素是所谓的循环一致性损失。所以,你把 gan 和可训练的逆映射结合起来。这里的关键思想是,有一个条件 GAN 输入 x 作为调理镜像,然后产生一些新的输出。如果你把这个新的输出用在 F 的条件变量中,它应该会再次产生 x 。所以,你用条件变量来形成一个循环,这里的关键是,G 和 F 应该是彼此的倒数。
循环一致性损失允许我们训练不成对的域翻译。 CC 下的图片来自深度学习讲座的 4.0 。
所以,如果你取 F(G( x )),你应该再次以 x 结束。当然,如果你取 G(F( y ),那么你应该再次得到 y 。这就产生了下面的概念:所以,你有两个生成器和两个鉴别器,一个从 x 生成 y 。一个 GAN F 正在从 y 产生 x 。你仍然需要两个鉴别器 Dₓ和 Dᵧ.循环 GAN 损耗进一步具有作为损耗的附加的一致性条件。当然,典型的鉴频器损耗是 Dₓ和 Dᵧ.的原始 GAN 损耗当然,它们分别与 G 和 f 耦合,在上面,你把这个循环一致性损失。循环一致性损失是一种耦合损失,它同时将 x 转换为 y 并将 y 再次转换为 x ,并确保在 y 中生成的斑马纹仍然不会被鉴别器识别为假的。同时,你有逆循环一致性,然后使用 F 将 y 转化为 x ,然后再次使用 G 将 x 转化为 y ,同时愚弄关于 x 的鉴别器。所以,你需要两个鉴别器。这就导致了循环一致性的丧失,我们已经在这里为你记下了。例如,你可以使用 L1 规范和那些 L1 规范的期望值来形成特定的恒等式。因此,总损耗等于我们之前讨论过的 GAN 损耗加上λ周期一致性损耗。
来自深度学习讲座的 4.0CC 下的 CycleGANs 图像示例。
所以,这个概念很容易理解,我可以告诉你这已经被广泛应用了。所以,有很多很多例子。你可以从莫奈翻译到照片,从斑马翻译到马,从夏天翻译到冬天,以及各自的逆运算。如果你再加上更多的 GANs 和更多的周期一致性损失,那么你甚至可以拍一张照片,把它翻译成莫奈、梵高和其他艺术家的作品,让他们代表一种特定的风格。
自行车 GANs 也在自动驾驶中得到应用。 CC 下的图片来自深度学习讲座的 4.0 。
当然,这对于自动驾驶也很有意思,例如,您可以输入一个场景,然后生成不同的分段遮罩。所以,在这个任务中你也可以用它来进行图像分割。这里,我们对 GAN 周期进行了烧蚀研究,显示了单独的周期、单独的 GAN、GAN 加上正向损耗、GAN 加上反向损耗以及完整的 GAN 周期损耗。你可以看到,随着周期 GAN 的丢失,如果你把它与你各自的地面真相相比较,你会得到更好的来回翻译。
在这个深度学习讲座中,更多令人兴奋的事情即将到来。来自深度学习讲座的 CC BY 4.0 下的图片。
好了,关于 GAN 还有几件事要说,这些是高级 GAN 概念,我们下次在深度学习中会谈到。所以,我希望你喜欢这个视频,并期待在下一个视频中见到你。再见!
循环甘斯使外科训练稍微更加现实。使用 gifify 创建的图像。来源: YouTube
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客。
链接
链接 —变分自动编码器:
链接—NIPS 2016 good fellow 的 GAN 教程
链接 —如何训练一个 GAN?让 GANs 发挥作用的技巧和诀窍(小心,而不是
一切都是真的了!)
链接——有没有想过怎么给自己的甘起名?
参考
[1]陈曦,陈曦,闫端,等.“InfoGAN:基于信息最大化生成对抗网的可解释表征学习”.神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2172-2180 页。
[2] Pascal Vincent,Hugo Larochelle,Isabelle Lajoie 等,“堆叠去噪自动编码器:用局部去噪标准学习深度网络中的有用表示”。《机器学习研究杂志》第 11 期。2010 年 12 月,第 3371-3408 页。
[3] Emily L. Denton,Soumith Chintala,Arthur Szlam 等,“使用拉普拉斯金字塔对抗网络的深度生成图像模型”。载于:CoRR abs/1506.05751 (2015 年)。arXiv: 1506.05751。
[4]理查德·杜达、彼得·e·哈特和大卫·g·斯托克。模式分类。第二版。纽约:Wiley-Interscience,2000 年 11 月。
[5]阿斯嘉菲舍尔和克里斯蒂安伊格尔。“训练受限制的玻尔兹曼机器:介绍”。载于:模式识别 47.1 (2014),第 25–39 页。
[6]约翰·高迪尔。用于人脸生成的条件生成对抗网络。2015 年 3 月 17 日。网址:http://www.foldl.me/2015/conditional-gans-face-generation/(2018 年 1 月 22 日访问)。
【7】伊恩·古德菲勒。NIPS 2016 教程:生成性对抗网络。2016.eprint: arXiv:1701.00160。
【8】Martin HEU sel,Hubert Ramsauer,Thomas Unterthiner 等,“通过双时标更新规则训练的 GANs 收敛到局部纳什均衡”。神经信息处理系统进展 30。柯伦联合公司,2017 年,第 6626–6637 页。[9]杰弗里·E·辛顿和鲁斯兰·R·萨拉胡季诺夫。"用神经网络降低数据的维数."刊登在:科学 313.5786(2006 年 7 月),第 504–507 页。arXiv: 20。
【10】杰弗里·e·辛顿。“训练受限玻尔兹曼机器的实用指南”。神经网络:交易技巧:第二版。柏林,海德堡:施普林格柏林海德堡,2012 年,第 599-619 页。
[11]菲利普·伊索拉,,周廷辉等,“条件对立网络下的意象翻译”。在:(2016 年)。eprint: arXiv:1611.07004。
[12]迪耶德里克·P·金马和马克斯·韦林。“自动编码变分贝叶斯”。载于:arXiv 电子版,arXiv:1312.6114(2013 年 12 月),arXiv:1312.6114。arXiv:1312.6114[统计。ML】。
[13] Jonathan Masci、Ueli Meier、Dan Ciresan 等人,“用于分层特征提取的堆叠卷积自动编码器”。载于:人工神经网络和机器学习— ICANN 2011。柏林,海德堡:施普林格柏林海德堡,2011 年,第 52-59 页。
[14]卢克·梅茨、本·普尔、大卫·普法乌等人,《展开的生成性敌对网络》。国际学习代表会议。2017 年 4 月。eprint: arXiv:1611.02163。
[15]迈赫迪米尔扎和西蒙奥辛德罗。“条件生成对抗网”。载于:CoRR abs/1411.1784 (2014 年)。arXiv: 1411.1784。
[16]亚历克·拉德福德、卢克·梅斯和索史密斯·钦塔拉。深度卷积生成对抗的无监督表示学习 2015。eprint: arXiv:1511.06434。
[17] Tim Salimans,Ian Goodfellow,Wojciech Zaremba 等,“训练 GANs 的改进技术”。神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2234–2242 页。
【18】吴恩达。“CS294A 课堂笔记”。2011 年。
【19】张寒、徐涛、李洪生等,“StackGAN:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:CoRR abs/1612.03242 (2016 年)。arXiv: 1612.03242。
【20】张寒、徐涛、李洪生等,“Stackgan:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:arXiv 预印本 arXiv:1612.03242 (2016)。
【21】周,Aditya Khosla,Agata Lapedriza 等,“学习深度特征用于鉴别性定位”。In: 2016 年 IEEE 计算机视觉与模式识别大会(CVPR)。拉斯维加斯,2016 年 6 月,第 2921–2929 页。arXiv: 1512.04150。
[22]朱俊彦,朴泰成,菲利普·伊索拉等,“利用循环一致的对立网络进行不成对的图像到图像的翻译”。载于:CoRR abs/1703.10593 (2017 年)。arXiv: 1703.10593。
无监督学习—第五部分
FAU 讲座笔记关于深度学习
高级 GAN 方法
FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!
航行
使用 GANs 创建的 x 射线投影。使用 gifify 创建的图像。来源: YouTube
欢迎回到深度学习,回到上一个视频,我们讨论了关于生成敌对网络的不同算法。今天,我们想看看第五部分的无监督训练。这些基本上是关于甘斯的贸易技巧。
单面标签平滑有助于训练 GANs。 CC 下的图片来自深度学习讲座的 4.0 。
有一个技巧可以帮到你很多,那就是单面标签平滑。所以,你可能想做的是用一个平滑的版本替换真实样本的目标。所以。你不用 1 的概率,而是用 0.9 的概率。你不能用同样的东西来做假样品。你不能改变他们的标签,因为否则,这将加强不正确的行为。因此,您的生成器将生成类似于它已经生成的数据或样本的样本。好处是你可以防止鉴别器给你的发生器很大的梯度,你也可以防止外推鼓励极端的样本。
GANs 不需要在鉴别和发电机之间进行平衡。来自深度学习讲座的 CC BY 4.0 下的图片。
发电机和鉴别器之间的平衡是必要的吗?不,不是的。GANs 通过估计数据和模型密度的比率来工作。因此,只有当鉴别器是最佳的时,才能正确地估计比值。所以,如果你的鉴别器超过了发电机也没关系。当鉴别器变得太好,你的梯度,当然,可能会消失。然后,你可以使用一些技巧,比如我们之前讨论过的非饱和损失。你也可能会遇到发电机梯度过大的问题。在这种情况下,您可以使用标签平滑的技巧。
深度卷积 GANs。 CC 下的图片来自深度学习讲座的 4.0 。
当然,你也可以使用深度卷积 GANs。这就是 DCGAN,您可以在生成器中实施深度学习方法。因此,您可以用步进卷积和转置卷积来替换池层。对于更深层次的架构,您可以完全删除连接的隐藏层。然后,生成器通常使用 ReLU 激活,除了使用双曲正切的输出层。例如,这里的鉴别器对所有层使用泄漏 ReLU 激活,并且它们使用批量标准化。
生成的图像可能显示出很强的批内相关性。 CC 下的图片来自深度学习讲座的 4.0 。
如果你这样做,那么你可能会在下面的问题中结束:你可以在这里看到一些生成结果。在批内,可能有很强的批内相关性。所以在这个批次中,所有生成的图像看起来都非常相似。
虚拟批次标准化有助于批次内关联。来自深度学习讲座的 CC BY 4.0 下的图片。
这就引出了虚拟批处理规范化的概念。您不希望对两个小型批处理使用一个批处理规范化实例。您可以使用两个单独的批处理规范化,或者更好的是,您可以使用虚拟批处理规范化。如果代价太大,可以为每个样本选择实例归一化,减去平均值,然后除以标准偏差。如果您选择虚拟批次标准化,您将创建一个随机样本的参考批次 R,并在训练开始时修复它们一次。然后,对于当前小批量的每个 x 下标 I,您创建一个新的虚拟批量,该虚拟批量是由 x 下标 I 组成的参考批量。除了当前批处理之外,您总是需要传播然后向前 R。这就允许你用这些统计数据标准化 x 下标 I。因此,这可能有点昂贵,但我们已经看到,这对于稳定训练和消除批内相关性非常有用。
历史平均可以稳定 GAN 训练。来自深度学习讲座的 4.0CC 下的图片。
还有历史平均的想法。因此,你添加了一个惩罚项,惩罚那些远离历史平均值的权重。然后,可以以在线方式更新这些参数的历史平均值。强化学习的类似技巧也可以用于像经验重放这样的生成性对抗网络。你保存了过去几代的回放缓冲区,并偶尔显示它们。您保留来自过去的生成器和鉴别器的检查点,并偶尔在几次迭代中交换它们。
使用 DCGAN 创建的图像示例。 CC 下的图片来自深度学习讲座的 4.0 。
所以,如果你这样做了,你就可以像 DCGAN 那样做了。这是一个时代后的卧室。你可以看到你可以创造出很多不同的卧室。所以这是一个非常有趣的事情,你实际上可以达到什么样的多样性。
来自 GANs 的动漫人物。使用 gifify 创建的图像。来源: YouTube
另一个有趣的观察是,您可以对生成的图像进行矢量运算。因此,例如,您可以生成条件“戴眼镜的人”的三个实例的平均值。有了这个平均值,你可以减去“不戴眼镜的男人”的平均值,然后计算“不戴眼镜的女人”的平均值,并把它加在上面。你得到的是“戴眼镜的女人”。
条件允许这种向量运算。 CC 下的图片来自深度学习讲座的 4.0 。
所以,你真的可以用这个技巧来使用约束生成,来生成一些你可能没有条件变量的东西。因此,甘一家学会了一种分配表示法,这种表示法将性别的概念与戴眼镜的概念区分开来。如果你对这些实验感兴趣,我推荐你去看看[1]。
训练中的模式崩溃将阻止学习整个分布。 CC 下的图片来自深度学习讲座的 4.0 。
让我们来看看一些更先进的 GAN 方法。可能出现的典型问题是模式崩溃。因此,如果您尝试让这种目标分布具有几个在二维空间中以环状方式分布的聚类中心,那么您可以看到,您的生成器可能会在数据分布模式中旋转。所以,你做 5000 步,10000 步,直到 25000 步,你开始在模式之间跳跃。这里的问题当然是你永远不会收敛到一个固定的分布。一个可能的原因可能是,G 的最小化超过 D 的最大化不等于 D 的最大化超过 G 的最小化。因此,内环中的鉴别器收敛于正确的分布,内环中的生成器将所有质量放置在最可能的点上。实际上,如果你对两个网络同时进行随机梯度下降,两种效应实际上都可能出现。解决方法是使用迷你鉴别或展开的 GANs。
小批量歧视迫使批内出现差异。来自深度学习讲座的 CC BY 4.0 下的图片。
因此,小批量鉴别遵循直觉,允许 D 同时查看多个样本,以帮助生成器避免崩溃。因此,您从中间层提取要素,然后添加一个小批量层,该层计算每个要素与小批量中所有其他样本的相似性。您将相似性向量连接到每个特征。然后,为来自生成器和训练数据的样本分别计算这些小批量特征。您的鉴别器仍然输出 0 和 1,但是使用小批量中所有样品的相似性作为辅助信息。这就是小批量歧视。
展开 GAN 训练带来了来自训练 rnn 的想法。 CC 下的图片来自深度学习讲座的 4.0 。
您也可以遵循展开的 GAN 的概念。这里你想要理想的发电机。这里的问题是,在计算发电机的梯度时,我们基本上忽略了最大运算。这里的想法是将我们的 V 视为生成器的成本,您需要通过最大化操作反向传播。
展开过程在示例中示出。 CC 下的图片来自深度学习讲座的 4.0 。
这本质上导致了一个非常相似的概念,正如我们已经在递归神经网络中看到的。因此,您可以在不同的参数集上使用随机梯度下降来展开这些迭代。所以,在几次迭代中,你会得到这种展开的梯度。这就允许我们建立一个计算图来描述鉴别器中学习的几个步骤。当你计算生成器的梯度时,你通过所有的步骤反向传播。当然,完全最大化鉴别器的价值函数是困难的。因此,必须在 k 值较低时停止,但可以看到,在 k 值较低的情况下,如 10,这大大降低了模式崩溃。
展开的 gan 防止模式崩溃。来自深度学习讲座的 CC BY 4.0 下的图片。
这是一个展开的 GAN 的例子。你有标准 GAN 的目标函数。这是一种交替模式,展开 GAN 后,可以看到,在步骤 0 中,分布仍然相同。但是在第五千步中,你可以看到分布在一个更大的区域。在第一万步中,你可以看到整个域都被填满了。一万五千步后,你形成一个环。在两万步之后,你可以看到我们的某些最大值出现了,在两万五千步之后,我们设法模仿了最初的目标分布。
用甘斯创作的肖像。使用 gifify 创建的图像。来源: YouTube
也可以使用 GANs 进行半监督学习。因此,这里的想法是通过将 K 类问题转化为 K+1 类问题来使用 GAN。在那里,你有真正的类,它们是监督学习的目标类。
甘也适合半监督训练。 CC 下的图片来自深度学习讲座的 4.0 。
然后,您有一些额外的类来模拟我们的生成器 g 生成的假输入。真实的概率基本上是所有真实类的总和,然后在 GAN 游戏中使用鉴别器作为分类器。
多尺度方法也适用于 gan。来自深度学习讲座的 CC BY 4.0 下的图片。
同样,我们也可以使用我们深度学习课程中的其他想法。比如拉普拉斯金字塔。你也可以做一个拉普拉斯金字塔。因此,到目前为止,我们已经观察到 GANs 非常擅长生成低分辨率图像。高分辨率图像要困难得多。在这里,您可以从生成低分辨率图像开始。所以在这里,我们从右到左。他们将从噪声开始,生成一个小分辨率的图像。然后,您有一个生成器,它将生成的图像作为一个条件和附加噪声来生成高频更新,以放大图像。最后,您可以在下一个标度中再次这样做,再次尝试预测这些图像的高频,添加高频并使用它来放大,再次得到一个丢失高频的模糊图像。同样,在生成高频镜像时,您可以将它用作条件向量,以抑制高频。因此,我们一步一步地使用条件 gan 来产生这种情况下缺失的高频。
拉普根的训练程序。 CC 下的图片来自深度学习讲座的 4.0 。
你通过在每一层训练一个鉴别器来训练生成器。鉴别器的输入是不同比例的图像。所以你一步一步地缩小图像,然后从缩小的图像中你可以计算出差异图像。两者之间的差异图像会给你正确的高频。训练鉴频器,使其能够区分正确产生的高频和人为产生的高频。这是拉普根训练,但我们仍然只有 64 乘 64 像素。
堆叠 GAN 允许多级 GAN 处理。 CC 下的图片来自深度学习讲座的 4.0 。
另一个想法是 StackGAN。这是现在用于从文本生成照片真实感图像。所以,任务是你有一些文本,并生成一个合适的图像。使用两阶段条件 GAN 将问题分解为草图优化。当然,这里的类比是,举例来说,在人类绘画中,你会先画草图,然后画出细节。所以,你有两个阶段。一个 GAN 绘制低分辨率图像。它以文本描述为条件,从给定的文本中规划出大致的形状、基本颜色和背景。然后,第二阶段 GAN 根据第一阶段的结果和文字说明生成高分辨率图像。它纠正缺陷并增加细节。
StackGAN 的例子。来自深度学习讲座的 CC BY 4.0 下的图片。
这里有一些例子,有文字描述。我们从描述中生成鸟类。你可以看到第一阶段的一代仍然缺少很多细节。随着第二阶段的产生,第一阶段造成的许多问题得到了解决,你可以看到新的图像具有更高和更好的分辨率。你可以在[20]中看到整篇论文。
我们对 gan 的观察总结。 CC 下的图片来自深度学习讲座的 4.0 。
让我们总结一下:gan 是生成模型,它使用监督学习来逼近一个难以处理的成本函数。您可以模拟许多不同的成本函数。实际上很难在鉴别器和生成器之间找到平衡。顺便说一下,它不能生成离散数据。您仍然可以将其用于半监督分类、迁移学习、多模态输出和域迁移。现在有很多报纸出现。这些还可以创建高分辨率输出,例如 BigGAN,它可以制作非常高分辨率的图像。
比根眼中的世界。使用 gifify 创建的图像。来源: YouTube
下一集深度学习,我们将会看到一些有趣的事情。我们将探讨如何运用神经网络来定位物体。因此,我们进入目标检测和定位。然后我们将检测对象类。我们试图检测类的实例。然后,我们将进一步尝试分割物体的轮廓。
在这个深度学习讲座中,更多令人兴奋的事情即将到来。来自深度学习讲座的 CC BY 4.0 下的图片。
所以,我们真的想进入图像分割,而不仅仅是找到物体和图像,而是真正尝试识别它们的轮廓。我们还将很快研究一种经常被引用的技术。所以,你可以每天查看引用次数,你会发现引用次数增加了。
无监督学习的综合问题。 CC 下的图片来自深度学习讲座的 4.0 。
我们这里也有一些综合问题:对比发散的基本思想是什么?自动编码器的特征是什么?如何去噪自动编码器的工作?另外,不要忘记变化的自动编码器。我认为这是一个非常酷的概念,重新参数化技巧告诉我们如何通过一个非常酷的采样过程进行反向传播。当然,你应该调查甘斯。什么是最佳鉴别器?模式崩溃是什么问题?我特别鼓励你看看自行车甘斯。所以现在骑自行车的人非常非常受欢迎。它们真的很好,因为你可以处理像不成对域翻译这样的事情。这在很多很多不同的应用中被使用。因此,如果你真的想在简历中表明你有深度学习的经验,你应该知道这些方法。那么,你应该知道这样的方法。嗯,还有一些进一步的阅读。有一个非常好的关于变分自动编码器的讨论,我们在这里链接。有一个很棒的关于甘的教程,作者是古德菲勒——甘之父。所以,我推荐在这里看这个视频。然后,我们有更多的交易技巧,你可以在这里找到甘黑客。如果你想知道如何命名你的 GAN,那么你可以看看这个参考。当然,我们也有大量的参考资料,我真的建议大家都看看。所以,非常感谢看这个视频。我希望你喜欢我们对生成性敌对网络的简短总结,并期待在下一期与你见面。非常感谢,再见!
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客。
链接
链接 —变分自动编码器:
链接—NIPS 2016 good fellow 的 GAN 教程
链接 —如何训练一个 GAN?让 GANs 发挥作用的技巧和诀窍(小心,而不是
一切都是真的了!)
链接——有没有想过怎么给自己的甘起名?
参考
[1]陈曦,陈曦,闫端,等.“InfoGAN:基于信息最大化生成对抗网的可解释表征学习”.神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2172-2180 页。
[2] Pascal Vincent,Hugo Larochelle,Isabelle Lajoie 等,“堆叠去噪自动编码器:用局部去噪标准学习深度网络中的有用表示”。《机器学习研究杂志》第 11 期。2010 年 12 月,第 3371-3408 页。
[3] Emily L. Denton,Soumith Chintala,Arthur Szlam 等,“使用拉普拉斯金字塔对抗网络的深度生成图像模型”。载于:CoRR abs/1506.05751 (2015 年)。arXiv: 1506.05751。
[4]理查德·杜达、彼得·e·哈特和大卫·g·斯托克。模式分类。第二版。纽约:Wiley-Interscience,2000 年 11 月。
[5]阿斯嘉菲舍尔和克里斯蒂安伊格尔。“训练受限制的玻尔兹曼机器:介绍”。载于:模式识别 47.1 (2014),第 25–39 页。
[6]约翰·高迪尔。用于人脸生成的条件生成对抗网络。2015 年 3 月 17 日。网址:http://www.foldl.me/2015/conditional-gans-face-generation/(2018 年 1 月 22 日访问)。
【7】伊恩·古德菲勒。NIPS 2016 教程:生成性对抗网络。2016.eprint: arXiv:1701.00160。
【8】Martin HEU sel,Hubert Ramsauer,Thomas Unterthiner 等,“通过双时标更新规则训练的 GANs 收敛到局部纳什均衡”。神经信息处理系统进展 30。柯伦联合公司,2017 年,第 6626–6637 页。[9]杰弗里·E·辛顿和鲁斯兰·R·萨拉胡季诺夫。"用神经网络降低数据的维数."刊登在:科学 313.5786(2006 年 7 月),第 504–507 页。arXiv: 20。
【10】杰弗里·e·辛顿。“训练受限玻尔兹曼机器的实用指南”。神经网络:交易技巧:第二版。柏林,海德堡:施普林格柏林海德堡,2012 年,第 599-619 页。
[11]菲利普·伊索拉,,周廷辉等,“条件对立网络下的意象翻译”。在:(2016 年)。eprint: arXiv:1611.07004。
[12]迪耶德里克·P·金马和马克斯·韦林。“自动编码变分贝叶斯”。载于:arXiv 电子版,arXiv:1312.6114(2013 年 12 月),arXiv:1312.6114。arXiv:1312.6114[统计。ML】。
[13] Jonathan Masci、Ueli Meier、Dan Ciresan 等人,“用于分层特征提取的堆叠卷积自动编码器”。载于:人工神经网络和机器学习— ICANN 2011。柏林,海德堡:施普林格柏林海德堡,2011 年,第 52-59 页。
[14]卢克·梅茨、本·普尔、大卫·普法乌等人,《展开的生成性敌对网络》。国际学习代表会议。2017 年 4 月。eprint: arXiv:1611.02163。
[15]迈赫迪米尔扎和西蒙奥辛德罗。“条件生成对抗网”。载于:CoRR abs/1411.1784 (2014 年)。arXiv: 1411.1784。
[16]亚历克·拉德福德、卢克·梅斯和索史密斯·钦塔拉。深度卷积生成对抗的无监督表示学习 2015。eprint: arXiv:1511.06434。
[17] Tim Salimans,Ian Goodfellow,Wojciech Zaremba 等,“训练 GANs 的改进技术”。神经信息处理系统进展 29。柯伦咨询公司,2016 年,第 2234–2242 页。
【18】吴恩达。“CS294A 课堂笔记”。2011 年。
【19】张寒、徐涛、李洪生等,“StackGAN:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:CoRR abs/1612.03242 (2016 年)。arXiv: 1612.03242。
【20】张寒、徐涛、李洪生等,“Stackgan:利用堆叠生成式对抗网络进行文本到照片级真实感图像合成”。载于:arXiv 预印本 arXiv:1612.03242 (2016)。
【21】周,Aditya Khosla,Agata Lapedriza 等,“学习深度特征用于鉴别性定位”。In: 2016 年 IEEE 计算机视觉与模式识别大会(CVPR)。拉斯维加斯,2016 年 6 月,第 2921–2929 页。arXiv: 1512.04150。
[22]朱俊彦,朴泰成,菲利普·伊索拉等,“利用循环一致的对立网络进行不成对的图像到图像的翻译”。载于:CoRR abs/1703.10593 (2017 年)。arXiv: 1703.10593。
使用 Scikit-learn、Spotify API 和 Tableau Public 进行无监督学习
在这篇文章中,我将使用来自 Scikit-Learn,KMeans 的无监督学习算法,来比较使用 Spotify 的 Web API 的休斯顿艺术家。
来自 Pexels 的 ThisIsEngineering 摄影
对于这个机器学习示例,我还将介绍 OSEMN 框架。首字母缩写 OSEMN 代表获取、清理、探索、建模和解释。对于研究机器学习问题的数据科学家来说,这是最常见的框架。
事不宜迟,我们开始吧。
使用 Spotify API 获取数据
首先,我们使用 Spotify API 客户端获取数据。如果你不熟悉 Spotify API,你会发现 CodeEntrepreneur 的Python 30 天——第 19 天——Spotify API——Python 教程非常有帮助,尤其是因为文档是用 JavaScript 编写的。Spotify 的 Web API 需要开发者账户,API 调用需要认证令牌。
我们将使用 Spotify 的 Get Artist endpoint 来获取来自德克萨斯州休斯顿的 30 位艺术家的数据。您可以下载。如果您想为 API 客户端使用相同的艺术家,请从我的 GitHub 库中下载 xlsx 文件。
确保您设置了客户端 id 和客户端密码:
client_id = 'your_client_id'
client_secret = 'your_secret_id'
spotify = SpotifyAPI(client_id, client_secret)In [ ]:spotify.get_artist('35magIA6t9JpNwT0sPEBgM')Out[ ]:{'external_urls': {'spotify': 'https://open.spotify.com/artist/35magIA6t9JpNwT0sPEBgM'},
'followers': {'href': None, 'total': 383},
'genres': ['houston rap'],
'href': 'https://api.spotify.com/v1/artists/35magIA6t9JpNwT0sPEBgM',
'id': '35magIA6t9JpNwT0sPEBgM',
'images': [{'height': 640,
'url': 'https://i.scdn.co/image/ab67616d0000b27326ac896c0d9a0e266c29ec27',
'width': 640},
{'height': 300,
'url': 'https://i.scdn.co/image/ab67616d00001e0226ac896c0d9a0e266c29ec27',
'width': 300},
{'height': 64,
'url': 'https://i.scdn.co/image/ab67616d0000485126ac896c0d9a0e266c29ec27',
'width': 64}],
'name': 'Yb Puerto Rico',
'popularity': 26,
'type': 'artist',
'uri': 'spotify:artist:35magIA6t9JpNwT0sPEBgM'}
由于 api 响应返回一个 JSON 对象,我们可以解析每个艺术家的数据以获得我们需要的信息。我使用一个 for 循环从每个艺术家那里提取数据,并将他们的结果添加到列表中。您还可以尝试使用Get multiple Artists端点在一个响应中获得多个艺术家。
下面是我加载。csv 文件并从 Spotify 获取艺术家信息:
# Load .csv with artists and spotifyIDs
import pandas as pdcsv = "Houston_Artists_SpotifyIDs.csv"
df = pd.read_csv(csv)
X = df['Spotify ID']# For loop to collect JSON responses for each artist
json_results = []for i in X:
json_results.append(spotify.get_artist(f'{i}'))
从 Spotify 中清除数据
一旦我们解析了每个人的信息,我们就不再需要 api 客户机了。我们可以使用 python check 获取存储在我们列表中的每个艺术家的追随者数量和受欢迎程度分数。我们还可以检查任何重复,并处理任何丢失的值。
下面是我将 JSON 信息解析成 Pandas 数据帧的代码:
In [ ]:names = []
followers = []
popularity = []
genres = []
urls = []
for i in json_results:
names.append(i['name'])
followers.append(i['followers']['total'])
popularity.append(i['popularity'])
genres.append(i['genres'])
urls.append(i['external_urls']['spotify'])
df = pd.DataFrame()
df['names'] = names
df['followers'] = followers
df['popularity'] = popularity
df['genre'] = genres
df['url'] = urls
df.head()Out [ ]: names followers popularity genre url
0 AcePer$ona 15 1 [] https://open.spotify.com/artist/4f06tvRb3HaDFC...
1 AliefBiggie 26 0 [] https://open.spotify.com/artist/1WkWfhdsdSqVYT...
2 Amber Smoke 93 2 [] https://open.spotify.com/artist/2JrntJAExmduLd...
3 Beyoncé 23821006 89 [dance pop, pop, post-teen pop, r&b] https://open.spotify.com/artist/6vWDO969PvNqNY...
4 Chucky Trill 957 25 [houston rap] https://open.spotify.com/artist/2mdDdKL0UzOqSq...
探索来自 Spotify 的数据
有了熊猫数据框架中的数据,我们就可以开始分析样本艺术家了。通过查看追随者的数据表,我们可以看到两个离群值,碧昂斯和特拉维斯斯科特。
图片由雅各布·塔德斯提供
我们也可以看到这两位艺术家有相似之处,但又略有不同。虽然碧昂斯有更多的粉丝,但特拉维斯·斯科特在 Spotify 的受欢迎程度上超过了碧昂斯,特拉维斯得分 96 分,碧昂斯得分 89 分,比“女王 B”高出整整 7 分。
图片由雅各布·塔德斯提供
我们也可以通过追随者和受欢迎程度来查看顶级艺术家,而在光谱的另一端,我们可以通过追随者和受欢迎程度来查看底层艺术家。
由关注者:
图片由雅各布·塔德斯提供
按受欢迎程度:
图片由雅各布·塔德斯提供
虽然这有助于了解谁是谁,谁有什么样的追随者或受欢迎程度,但这篇文章的目的是使用无监督学习算法来比较这些艺术家。
用 Scikit-learn 对数据建模
“无监督学习(Unsupervised Learning)是一种机器学习算法,用于从由没有标记响应的输入数据组成的数据集进行推断。最常见的无监督学习方法是聚类分析,用于探索性的数据分析,以发现数据中隐藏的模式或分组。”— Mathworks
因为我们想比较这些艺术家,我们将使用无监督学习算法来将我们的艺术家分组/聚类在一起。更具体地说,在这个例子中,将使用 Scikit-Learn 的 KMeans 算法。我们从 sklearn 导入模块吧。你可以按照这里的说明安装 sklearn 。
from sklearn.cluster import KMeans
[*KMeans*](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans)
算法通过尝试将样本分成 n 个方差相等的组来对数据进行聚类,从而最小化一个称为惯性或类内平方和的标准。**Scikit-Learn.org
缩放要素
在训练任何机器学习算法之前,缩放您的特征始终是一种最佳做法。处理异常值也是很好的实践。在本例中,我将保留我们的异常值,并使用最小最大缩放器来缩放我们的小数据集中的要素,但我们也可以使用鲁棒缩放器来使用对异常值鲁棒的统计数据来缩放要素。
*from sklearn.preprocessing import MinMaxScaler
s = MinMaxScaler()
Scaled_X = s.fit_transform(X)*
训练模型
现在我们已经缩放和转换了我们的特征,我们可以训练我们的 KMeans 算法。我们需要设置多个集群,有几种方法可以帮助选择最佳的集群数量,但是对于我们的示例,我们将使用 8 个集群。我们将使用 predict 方法根据每个艺术家的追随者和受欢迎程度来预测他们的群体或聚类。
*kmeans = KMeans(n_clusters=8, random_state=0).fit(Scaled_X)
y_kmeans = kmeans.predict(X)*
查看集群
为了查看集群,我们可以使用方法从 Kmeans 模型中提取标签。标签 _* 。我们也可以通过使用的方法来查看星团的中心。簇 _ 中心 _ 。*
*df['labels'] = kmeans.labels_
centers = kmeans.cluster_centers_*
图片由雅各布·塔德斯提供
图片由雅各布·塔德斯提供
虽然我们可以在笔记本中绘制这些内容,但我将使用 Tableau Public 创建一个供公众访问的仪表板。让我们将数据框保存为 Excel 文件。
保存结果
下面,我们将过滤我们的数据框架,只包括艺术家的名字,追随者,受欢迎程度和标签。然后我们将按标签值对数据进行排序。
*final = df[['names','followers','popularity','labels']].sort_values(by='labels', ascending=False)*
最后,我们将使用内置的熊猫方法,。to_excel* ,保存文件。*
*final.to_excel('Houston_Artists_Categories_8-7-2020.xlsx')*
从 Kmeans 解释聚类
我使用 Tableau Public (它是免费的)来创建一个结果的交互式仪表板。通过艺术家分组,我们可以看到碧昂斯和特拉维斯·斯科特在他们自己的组中,而其他休斯顿的艺术家通过相似的追随者和受欢迎程度分组在一起。感谢您阅读这篇文章,我希望您在使用无监督学习比较休斯顿艺术家时发现它是有帮助的!
图片由雅各布·塔德斯提供
这是仪表盘的链接。
另外,这里有一个回购的链接。
如果你愿意为这个项目做贡献,请通过 LindedIn 联系我。
Keras 中的无监督机器学习示例
使用自动编码器对欺诈性健康保险索赔进行异常检测。
这篇文章是关于无监督学习和我在健康保险欺诈索赔检测方面的研究。
在健康保险中,欺诈性索赔检测存在一些挑战。首先,没有与医疗保险索赔欺诈相关的公开数据,这与数据隐私问题有关。第二,很难确定一套有助于识别欺诈性索赔的规则。这意味着带有标签数据的监督机器学习方法很难适用于我们的情况。无监督的机器学习似乎会是更好的匹配。在无监督的机器学习中,网络在没有标签的情况下训练,它发现模式并将数据分成组。这对于数据中的异常检测特别有用,在这种情况下,我们要寻找的数据很少。医疗保险欺诈就是这种情况——与索赔总额相比,这是不正常的。
来源:谷歌图片
我建议通过使用 Python 书籍的实践无监督学习来更好地实践对这个主题的理解。这本书有一个 GitHub 回购。在我的例子中,我使用了本书中的异常分数计算函数。
我们识别欺诈的方法是检测异常情况。在无监督学习中,可以用自动编码器检测异常。Autoencoder 将原始数据转换为学习过的表示,基于此,我们可以运行一个函数,并计算学习过的表示离原始数据有多远。欺诈性数据以更高的错误率重建,这有助于识别异常。自动编码器适用于无监督学习——训练不需要标记数据。
来源:谷歌图片
我的例子是基于定位欺诈性健康保险索赔的想法。可能有各种类型的欺诈,例如,医院可能会向保险公司收取过高的费用。我们的任务是检测欺诈性索赔,该模型在 Keras 中使用无监督的方式进行训练,没有标签。
很难获得健康保险的公共数据(隐私问题)。出于这个原因,我使用生成的数据(基于这篇文章— 没有数据的数据科学):
- 培训:100 000(有效索赔),100 0(欺诈索赔)
- 测试:30 000(有效索赔),30 0(欺诈索赔)
- 欺诈索赔规则:索赔的保险费用增加一倍
检测数据重建错误率的异常分数函数:
def anomalyScores(originalDF, reducedDF):
loss = np.sum((np.array(originalDF) - \
np.array(reducedDF))**2, axis=1)
loss = pd.Series(data=loss,index=originalDF.index)
loss = (loss-np.min(loss))/(np.max(loss)-np.min(loss))
print('Mean for anomaly scores: ', np.mean(loss))
return loss
Autoencoder 用 Keras/TensorFlow 实现。神经网络定义为 3 层(节点数=数据维数)。使用线性激活,优化器亚当:
# Call neural network API
model = Sequential()# Apply linear activation function to input layer
# Generate hidden layer with 14 nodes, the same as the input layer
model.add(Dense(units=14, activation='linear',input_dim=14))
model.add(Dense(units=14, activation='linear'))# Apply linear activation function to hidden layer
# Generate output layer with 14 nodes
model.add(Dense(units=14, activation='linear'))# Compile the model
model.compile(optimizer='adam',
loss='mean_squared_error',
metrics=['accuracy'])
这是无人监督的学习—欺诈标签不包含在培训中:
# Train the model
num_epochs = 10
batch_size = 256history = model.fit(x=dataX, y=dataX,
epochs=num_epochs,
batch_size=batch_size,
shuffle=True,
validation_data=(dataX, dataX),
verbose=1)
该模型在 10 轮中被训练。每次运行后,计算异常分数以测量重建精度。最佳模型被保存。使用精度召回和接收器操作特性来测量准确度。示例培训结果:
作者:安德烈·巴拉诺夫斯基
欺诈检测逻辑在欺诈检测笔记本中实现。预测功能在无标签的测试数据上执行。使用异常分数函数计算异常分数。我已经计算了平均异常分数,这将有助于定义区分有效索赔和欺诈索赔的阈值。基于测试数据的计算平均值:
作者:安德烈·巴拉诺夫斯基
最后,我将预测标签与实际测试集标签进行比较,这使我们能够通过训练好的模型来衡量欺诈检测的准确性。
欺诈检测阈值= 0.01 。
结果:
- 有效索赔:30 000
- 欺诈:286(准确率 95%)
- 未被认定为欺诈的:14
作者:安德烈·巴拉诺夫斯基
欺诈检测阈值= 0.005 (更接近计算平均值 0.003)。
结果:
- 有效索赔:29 636
- 欺诈:293(准确率 98%)
- 有效识别为欺诈:364
- 未被认定为欺诈的:7
作者:安德烈·巴拉诺夫斯基
欺诈检测阈值= 0.003 (等于计算的平均值 0.003)。
结果:
- 有效索赔:26 707
- 欺诈:300(准确率 100%)
- 有效识别为欺诈:3293
作者:安德烈·巴拉诺夫斯基
结论
随着异常分数变小,我们对异常进行更严格的检查。这使我们能够捕捉所有欺诈性索赔,但作为回报,我们会将更多有效索赔标记为欺诈。
从上面的图表中可以看出,识别低价值的欺诈性索赔更加困难。当数量较少时,这是有意义的——更有可能被遗漏。
源代码 : GitHub 回购
使用 BERT 的无监督 NER
图一。图示了使用 BERT (bert-large-cased)执行的无监督 NER 的标记句子样本,没有微调。这些例子突出了用这种方法标记的几个实体类型。标记 500 个句子产生了大约 1000 种独特的实体类型——其中一些被映射到上面显示的合成标签上。Bert-large-case 模型无法区分基因和蛋白质,因为这些实体的描述符落在屏蔽术语的预测分布的同一尾部(它们在基本词汇中也是不可区分的)。区分这些密切相关的实体可能需要 MLM 对特定领域的语料库进行微调,或者使用定制的词汇从头开始预先训练模型(下面将进行讨论)
TL;博士
【2022 年 1 月 发布的这种方法的改进版本 描述了如何将其扩展到大量的实体类型(例如,跨越生物学和 PHI 实体领域的 68 种实体类型,如人、位置、组织)。
在自然语言处理中,识别句子中感兴趣的实体,如人、地点、组织等。需要带标签的数据。我们需要用感兴趣的实体来标记句子,其中每个句子的标记都是手动或通过某种自动方法来完成的(通常使用试探法来创建有噪声/弱标记的数据集)。然后,这些标记的句子被用来训练一个模型,以识别这些实体作为监督学习任务。
这篇文章描述了一种实现无监督 NER 的方法。NER 是在没有标记句子的情况下使用 BERT 模型在无监督的情况下完成的,该模型仅在具有掩蔽语言模型目标的语料库上被无监督地训练。
该模型在 25 个实体类型(维基文本语料库)的小数据集上具有 97%的 F1 分数,在 CoNLL-2003 语料库上对于人和地点具有 86%的 F1 分数。在 CoNLL-2003 语料库上,它对于人、地点和组织具有较低的 F1 分数 76%,这主要是因为句子中固有的实体歧义(在下面的评估部分中检查)。这两项测试都是在没有对模型在上进行测试的数据进行任何预训练/微调的情况下进行的(与对特定领域数据进行预训练/微调模型或使用标记数据进行监督训练形成鲜明对比)。
这是怎么回事?
如果我们被问到一个术语的实体类型 ( 术语 既指 单词 又指 短语我们从未见过,我们可以通过术语的发音和/或术语出现的句子结构来猜测。也就是说,
- 一个术语的子词结构提供了其实体类型的线索。
**Nonenbury is a _____**
- 这是一个虚构的城市名称,但我们可以猜测它可能是一个后缀为“bury”的地点。在这里,术语后缀给了我们一个线索,即使我们从句子上下文中没有任何其他关于实体类型的线索。
- 句子结构提供了术语实体类型的线索。
**He flew from _____ to Chester**
这里,句子的上下文给了我们一个线索,即未知项是一个位置。即使在(例如 Nonenbury)* 之前没有见过,我们也可以猜测句子中空白位置的任何术语都可能是位置。*
伯特的掩蔽语言模型 head(MLM——图 7* )可以预测上述掩蔽位置的候选单词,给定之前描述的训练目标——它通过预测句子中被删除的单词来学习。然后,在推断过程中使用这种学习,以输出对句子中被屏蔽的术语的预测,其中该预测是对 BERT 的固定词汇的概率分布。这个输出分布有一个明显但很小的尾部 ( < ~总质量的 0.1),其中驻留了捕获术语的上下文敏感实体类型的候选单词。这个尾部充当使用 BERT 词汇表表示的术语的*上下文敏感签名。例如,句子中屏蔽位置的上下文敏感签名如下所示**
**Nonenbury is a _____***Context Sensitive (CS) Predictions:** village hamlet town settlement parish Village Hamlet farm place Town*
BERT 的固定词汇(BERT-large-cased 为 28,996)用作一组通用描述符(例如专有名词、普通名词、代词等。).这些描述符的子集(可能是重叠的)由下面描述的聚类过程获得,独立于其句子上下文来表征术语的实体类型。这些子集是术语的上下文无关签名。BERT 词汇表中捕获接近上述上下文敏感签名的实体类型的上下文无关子集是
*['villages', 'towns', 'village', 'settlements', 'villagers', 'communities', 'cities']
['Village', 'village']
['city', 'town', 'City', 'cities', 'village']
['community', 'communities', 'Community']
['settlement', 'settlements', 'Settlement']
['Township', 'townships', 'township']
['parish', 'Parish', 'parishes']
['neighborhood', 'neighbourhood', 'neighborhoods']
['castle', 'castles', 'Castle', 'fortress', 'palace']
['Town', 'town']*
在上下文敏感签名/聚类和上下文无关签名/聚类之间的 BERT 词汇表的嵌入空间中实现的最接近匹配函数(基于单词嵌入的余弦相似度)产生表示术语的 NER 标签的上下文无关签名的子集。具体来说, m 条款 {B1,B2,C3,…。Bm} 构成上下文敏感签名,n 组术语 {{C11,C12,C13,…Ck1} , {C21,C22,C23,…Ck2},… {Cn1,Cn₂,Cn₃,…Ckn}} 构成上下文无关签名,产生表示术语(下面图 2)的 NER 标签的上下文无关签名的子集。
图二。 NER 标注了一句话。(1)在最小预处理之后,将带有屏蔽词的输入句子输入到模型中。(2)对 BERT 的 28,996 个词汇的前 10 个预测。(3)这 10 项在伯特的词嵌入空间中被一个函数重新排序。(4)来自重新排序的术语的前 k 个术语以及 6000 个聚类(离线计算)作为输入被馈送到输出匹配聚类的聚类匹配函数。这些聚类的标注(可以是用户定义的标注-一次性手动步骤,或者在某些用例中按原样使用)随后被聚合以输出 NER 标注。图中执行 3、4 和 5 的函数都是在 BERT 的嵌入空间中使用字向量之间的余弦相似性来完成的。约 6000 个聚类的一次性离线生成也是使用 BERT 的单词嵌入空间中单词向量之间的余弦相似度来完成的。图中显示了隐藏大小为 768 的 BERT 基本模型。帖子中的 NER 例子是用隐藏尺寸为 1024 的大号伯特箱完成的
给定我们可以从 BERT 的词汇表中自动收获的上下文无关签名的数量为数以千计( ~6000,对于 bert-large-cased ) —这种方法允许我们在细粒度级别上对大量实体类型执行无监督的实体识别,而不需要标记数据。
上面描述的无监督 NER 方法很大程度上是因为,正如本文 中的 所考察的
- BERT 的原始单词嵌入捕捉有用的和可分离的信息(明显的直方图尾部,小于 0.1 %的词汇)关于使用 BERT 词汇中其他单词的术语。这用于生成 6000+个集群
- 由具有 MLM 头的 BERT 模型输出的这些嵌入的变换版本被用于预测屏蔽字。预测也有一个明显的尾巴。这用于选择术语的上下文敏感签名。
执行无监督 NER 的步骤
一次性离线处理
一次离线处理从从 BERT 词汇表中获取的上下文无关签名集合创建到单个描述符/标签的映射。
第一步。过滤 BERT 的词汇以挑选上下文敏感的签名术语
伯特的词汇是普通名词、专有名词、子词和符号的混合体。这个集合的最小过滤是去除标点符号、单个字符、子词和 BERT 的特殊符号。得到的 21,418 个术语的集合—普通名词和专有名词的混合用作描述实体类型的描述符。
第二步。从 BERT 的词汇表中生成上下文无关的签名
如果我们简单地从尾部为 bert 词汇表中的每个术语挑选上下文无关的签名,我们将获得相当大量的聚类 (~20,000) ,即使具有 0.5 的高余弦相似性阈值(对于 BERT 大型模型,对于高于 0.5 的余弦阈值的术语,平均约有 0.1%的术语位于尾部)。这不仅是大量的聚类,它也不能捕获这些签名之间的相似性。所以,相反我们
- 遍历 BERT 词汇表中的所有术语(忽略子词和大多数单个字符;补充说明有更多细节),并为 0.5 以上的每一项挑选上下文无关的签名。将单词尾部的术语视为一个完整的图,其中边的强度是余弦相似值。
- 选择与图中所有其他节点具有最大连接强度的节点。
- 该节点充当由这些节点组成的上下文无关签名的中枢。此节点是此图中所有其他节点的最近邻居。
图三。在一个完整的图中寻找枢轴节点。在上面的完整图形中,节点“平滑地”具有到其邻居的最大平均连接强度。所以“平滑地”是这个图的中枢节点——这个图中所有其他节点的最近邻居。**
- 一旦一个术语被选作签名的一部分,它将不会被考虑用于 pivot 候选评估(但是,如果另一个术语的 pivot 节点计算使其成为 pivot,则它可以间接成为 pivot)* 。本质上,一个术语可以是多个集合的一个元素,一个中枢或间接中枢。*
*airport 0.6 0.1 Airport airport airports Airfield airfield
stroking 0.59 0.07 stroking stroked caressed rubbing brushing caress
Journalism 0.58 0.09 Journalism journalism Journalists Photography
journalists
smoothly 0.52 0.01 smoothly neatly efficiently swiftly calmly*
在上面的示例签名中,两个数值是子图边强度的平均值和标准偏差。第一列术语用作代表该签名的枢纽术语。这些术语充当实体标签代理。这些可以手动映射(一次性操作)到用户定义的标签。在下面的图 4a 和 4b 中示出了映射这些实体集群的例子。我们只需要映射那些代表与我们的特定应用程序相关的实体类型的集合。其余的可以通过编程映射到一个合成标签“other/misc”。参考部分描述了一种使用模型本身来引导/加速描述符到用户定义标签的手动映射的方法。
因为伯特的词汇中大约 30%是专有名词(人名、地名等)。)尽管我们只是标注了一小部分术语(约 2000 个人工标注集群,耗时约 5 个工时,如图 4 和 4b 所示)而不是大量的句子,但看起来我们似乎在作弊。将句子的标注问题转化为标注上下文不敏感描述符的一个关键优点是,这是一个一次性的过程。这与监督训练方法形成对比,在监督训练方法中,我们必须不可避免地创建更多标记数据,不仅要训练我们的模型,还要根据我们在训练(通常在部署中)之后发现的不分布的句子对其进行再训练。然而,在我们的情况下,更糟糕的情况是,我们必须在没有监督的情况下对这些新句子重新训练/微调我们的 BERT 模型——我们不必再做任何标记。
上面描述的上下文不敏感签名生成产生大约 6000 个集合,平均基数大约为 4 +/- 7 个节点。这 6000 组数据的聚类强度平均值为 0.59,偏差为 0.007,这些聚类非常紧密,因为平均值远远高于我们从分布(图 4c)* 中选择的阈值。大约 5000 个词汇术语 (17 %的词汇)是单体集合,被忽略。如果选择集合的阈值改变,这些数字也会改变。例如,阈值 0.4 会将总尾部质量增加到 0.2%,并且还会增加聚类平均值*(但是聚类会因实体类型混合而变得嘈杂)。**
图 4 。BERT 的上下文无关签名集统计信息(bert-large-cased)。平均基数约为 4,标准偏差为 7。这 6110 组的聚类强度的平均值为 0.59,偏差为 0.007,这些聚类是非常紧密的聚类,因为平均值远远高于我们从分布中选择的阈值。我们将看到,相比之下,上下文敏感术语通常是弱聚类。大约 17%的 BERT 词汇是单态的。聚类不考虑子词、特殊标记和大多数单字符标记。
图 4a。BERT(BERT-large-cased)词汇中簇的实体分布。大部分实体集中在人员、位置和组织中。AMB 指的是在给定簇中的术语的情况下不明确的簇。例如,如下图 4b 所示,7 个聚类在人和位置之间具有模糊性。其他人在人、物、运动/生物等方面有歧义。当我们想要发现特定领域的实体类型时,使用自定义词汇表将是有价值的——这可能会消除对个人、位置和组织的偏见。
图 4b。BERT 词汇中的实体子类型分布。这些是图 4a 中主要类型的细粒度实体子类型。
从 BERT 词汇表中获得的上下文无关聚类的例子
图 4c。来自 BERT 词汇表的聚类示例(bert-large-cased)。不明确的上下文不敏感聚类被标记为 AMB。当子词被考虑用于聚类时,附加注释显示子词聚类(尽管对于本文中的实体识别结果,它们被过滤掉了)
每个输入句子的实体预测
执行这些步骤来标记输入句子中的术语。
第三步。最小预处理输入句子
给定一个输入句子来标记实体,对输入进行非常简单的预处理。其中之一是大小写规范化——全大写的句子(通常出现在文档标题中)被转换为小写,同时保留每个单词中第一个字母的大小写。这有助于提高下一步检测短语跨度的准确性。
*He flew from New York to SFO
*becomes*
He flew from New York to Sfo*
第四步。识别句子中的短语跨度
一个 POS tagger (经过理想训练也能处理所有小写单词句子)用于标记输入句子。这些标签用于识别短语以及大写每个名词短语的第一个字母。
*He flew from **New York** to **Sfo***
标记为名词形式的术语在上面用粗体表示。BERT 的屏蔽词预测对大小写非常敏感,因此使用一个好的词类标记器来可靠地标记名词形式,即使只是小写也是标记性能的关键。例如,下面句子的屏蔽预测通过改变句子中一个字母的大小写来改变实体意义
*Elon **M**usk is a ____
**CS Predictions:** politician musician writer son student businessman biologist lawyer painter memberElon **m**usk is a ____
**CS Predictions:** brand Japanese beer German common Turkish popular French Russian Brazilian*
顺便说一句,BERT 的屏蔽预测仅对于检测实体类型(上面第一个例子中的 人 )是可靠的,对于事实上准确的预测是不可靠的,尽管事实上 BERT 可能偶尔做出事实上准确的预测。
第五步。使用伯特的 MLM 头来预测每个屏蔽位置
对于句子中的每个名词术语,生成一个包含该术语的句子。使用伯特的 MLM 头来预测屏蔽位置的上下文敏感签名。
*He flew from __ to Sfo
**CS Predictions:** Rome there Athens Paris London Italy Cairo here Naples EgyptHe flew from New York to ___
**CS Predictions:** London Paris Singapore Moscow Japan Tokyo Chicago Boston France Houston*
找到这些节点相对于集合中其他节点的强度,就像我们在图 2 中找到枢轴节点一样。按实力排序。这给出了单词嵌入的嵌入空间中的 CS 预测的重新排序列表。重新排序将共享实体意义的术语集合在一起,尽管重新排序是在独立于上下文的单词嵌入的嵌入空间中进行的。例如,下面第一个例子中的重新排序将术语“there”和“here”(空白位置的有效上下文敏感预测)推到最末尾。我们将在下一步中挑选这些重新排序的节点的顶部 k (k ≥ 1)。
*He flew from __ to Sfo
**CS Predictions:** Rome there Athens Paris London Italy Cairo here Naples Egypt
**CI space ordering of CS predictions**: Rome Paris Athens Naples Italy Cairo Egypt London there hereHe flew from New York to __
**CS Predictions:** London Paris Singapore Moscow Japan Tokyo Chicago Boston France Houston
**CI space ordering of CS predictions**: Paris London Tokyo Chicago Moscow Japan Boston France Houston Singapore*
第六步。查找上下文相关签名和上下文无关签名之间的紧密匹配
产生合理结果的一个简单的紧密匹配函数是,从前一项中仅选取上下文敏感签名的一个中枢节点,并与上下文无关签名集中的所有 6000+中枢做该项的点积,然后对它们进行排序以获得实体标签候选。在这种情况下,紧密匹配功能实质上是寻找与上下文敏感聚类中枢最近的上下文不敏感聚类中枢。除了顶部支点,我们还可以采用顶部 k 个支点来提高标记/预测的可信度(图 5)* 。*
图 5 。单词嵌入空间中上下文相关签名和上下文无关签名的紧密匹配。(A)紧密匹配的简单实现是上下文敏感签名的中枢节点和上下文无关签名中集合的中枢之间的点积。在这种情况下,紧密匹配功能实质上是寻找与上下文敏感聚类中枢*最近的上下文不敏感聚类中枢。更好的实现是基于上下文敏感签名中的节点的平均值和标准偏差来决定被认为是中枢的节点的数量,然后选择要在二分图中考虑的中枢的数量,以找到与每个上下文敏感聚类中枢最近的上下文不敏感聚类中枢。(b)示出了对于上下文敏感的和仅一个节点上下文无关的项,计数为 3 的情况(奇数可能是打破平局的更好选择;此外,我们不需要上下文不敏感集合中的 3 个节点,因为它们是紧密的集群,平均偏差为 0.007,如我们之前看到的)。在计算中使用来自上下文敏感签名的所有节点不太可能产生好的结果,因为上下文敏感节点中的平均标准偏差要高得多。这可能是因为当在嵌入空间中评估时,上下文敏感签名扩展到更大的区域,甚至当捕获单个实体类型时。*
仅具有上下文敏感签名的顶部中枢的标签预测如下所示。标签和用户标签如下所示。
*He flew from __ to Sfo
**CI space ordering of CS predictions**: Rome Paris Athens Naples Italy Cairo Egypt London there here **Tags**: Italy Venice Athens Bologna Madrid Carthage Roma Sicily Turin Vatican**User Label** - location location location location location location location location location locationHe flew from New York to __
**CI space ordering of CS predictions**: Paris London Tokyo Chicago Moscow Japan Boston France Houston Singapore**Tags**: London Madrid Geneva Vienna Bordeaux Chicago Metz Athens Cologne Istanbul**User Label** - location location location location location location location location location location*
评估结果
该模型在两个数据集上进行评估:( 1)具有要标记的三种实体类型(人、位置、组织)的标准数据集 CoNLL-2003,以及(2)具有大约 25 种实体类型的维基文本数据集。
在 CoNLL-2003 数据集中,所有三种数据类型的平均 F1 分数(PER-81.5%;LOC-73%;ORG—66%;MISC-83.87%)* 仅为 76%。这是由于两个原因。*
- 在测试数据的很大一部分中,CoNLL 中的文本结构不是完整的句子——它是板球比分的简洁报告,没有规则的句子结构。由于该模型没有对句子进行预训练或微调,因此它很难预测这些非分布句子中的屏蔽词。在实践中,这可以通过预训练或至少在新的句子结构上微调模型来减轻
- 测试数据将许多来自特定位置的团队标记为一个位置。该模型几乎总是将它们标记为位置,而不是团队名称(org)。使用这种无监督的 NER 方法,这个问题没有简单的解决方案。它将只使用最自然地匹配屏蔽位置的实体描述符来标记术语。它不能用不能使用其描述符映射的人工标签来标记术语。虽然从一个角度来看,这可能被认为是一个缺点,但这也是该模型的关键优势——它用来标记屏蔽位置的描述符自然地出现在它被训练的语料库中——它不是从无关的人类标记源学习的。将这些描述符映射到用户定义的标签可能是一种方法,但它可能不是一种干净的解决方案(例如,在上述将位置描述符视为组织和位置的模糊标签的情况下)**
图 5a 。CoNLL-2003 结果
在小测试数据上的模型性能是大约 97%的平均 F1 分数,但是具有全部自然发生的句子集合和大约 25 种标签类型
图 5b 。约 25 种实体类型的维基数据结果
图 5c。维基数据集的实体分布。在这个数据集上,F1 得分的平均表现为 97%。这种方法的一个关键区别是,模型不仅没有使用标记数据进行训练,甚至没有在测试数据集上进行预训练和微调。
这种方法的局限性和挑战
语料库偏倚
虽然单个实体预测说明了模型从子词信息中解释实体类型的能力,但实际上,它们只能与具有多种实体类型的句子结合使用。没有太多上下文的单个实体句子对语料偏差很敏感,如下图所示的谷歌和脸书预测。
*Facebook is a __
**CS Predictions**: **joke monster** killer friend story person company failure website faultMicrosoft is a __
**CS Predictions**: company website competitor people friend player Winner winner person brandGoogle is a __
**CS Predictions**: friend website **monster** company killer person man story dog winner*
实体预测中的模糊性
这种方法产生了两种模糊性
- 由上下文不敏感描述符表征的实体类型中的模糊性(图 4c 中的示例)。包含“银行、银行、银行、银行”的集群可以代表一个组织或位置。然而,在大多数情况下,当通过实体类型的多数投票将上下文敏感签名与上下文不敏感签名紧密匹配时,即使一些匹配的上下文不敏感签名是不明确的,也可以解决这种不明确性。
- 下面描述的第二个歧义更难解决
有些句子允许不同的实体类型来填充一个隐藏的术语。例如,在预测下面句子中的实体类型“纽约”时
*He felt **New York** has a chance to win this year's competition*
屏蔽词的实体预测可以是暗示人的词,这是如下所示的有效预测
*He felt __he____ has a chance to win this year's competition*
模糊性是由于屏蔽而产生的,在大多数情况下,可以通过确定被屏蔽的术语本身的实体类型(纽约)来解决。
*New York is a _____**CS Predictions:** city town place City capital reality square country dream star*
然而,在某些情况下,甚至被屏蔽的术语也是含糊不清的,使得确定实体具有挑战性。例如,如果原句是
*He felt **Dolphins** has a chance to win this year's competition*
海豚可以是一个音乐团体或运动队。
这些挑战在很大程度上可以通过多种方法来解决
- 在特定领域语料库上微调模型可以帮助减少特定领域实体类型中的歧义。例如, BERT 预训练中的 BRAF (这是一个基因)在其签名中没有基因意义,而基因意义存在于生物医学语料库上微调的模型中。
*BRAF is a _____
**CS Prediction**: British German new standard the variant name version World worldIn a model fine tuned on a biomedical corpus,
BRAF is a _____
**CS Prediction**: protein gene kinase structural non family reaction functional receptor molecule*
- 用自定义词汇表从开始预训练模型可以帮助解决实体歧义,更重要的是还可以提高实体标记性能。BERT 的默认词汇丰富,包含全词和子词,用于检测实体类型,如人员、位置、组织等(图 4a 和 b) 。然而,它在获取生物医学领域的全部和部分术语方面存在缺陷。比如像IMAtinib、nilotinib、dasatinib这样的药物的标记化,不考虑常见的子词【tinib】。伊马替尼标记为 i ##mat ##ini ##b ,而达沙替尼标记为 das ##ati ##ni ##b 。如果我们在生物医学语料库上使用句子片段创建自己的词汇,我们会得到 im ##a ##tinib 和d # # as # # a # # tinib——捕捉常见后缀。此外,自定义词汇包含来自生物医学领域的完整单词,更好地捕捉生物医学领域的特征。例如像先天性、癌症、致癌物、心脏病专家等词语。在默认的 BERT 预训练模型中不存在。默认 BERT 词汇中的人称、位置的优势被专有名词和子词所取代,这些专有名词和子词在生物医学语料库中捕捉药物和疾病状况。此外,从生物医学语料库中提取的定制词汇具有大约 45%的新完整词,其中只有 25%与公开可用的 BERT 预训练模型的完整词重叠。当微调 BERT 模型时,有一个选项可以添加 100 个自定义词汇,但不仅数量很少,默认的 BERT 词汇(如前所述)严重偏向某些实体类型,如人员、位置、组织等,如图 4a 所示。
***Token:** imatinib dasatinib
**BERT** (default): i ##mat ##ni ##b das ##ati ##nib
**Custom**: im ##a ##tinib d ##as ##a ##tinib*
最后的想法
NER 是一个从输入句子到对应于句子中术语的一组标签的映射任务。传统上,模型被训练/微调以使用标记数据作为监督任务来执行该映射。这不考虑利用像 BERT 这样的预训练模型,该模型在语料库上无监督地学习。
这篇文章描述了一种在无监督的情况下执行 NER 的方法,而不需要对用屏蔽语言模型目标无监督训练的预训练/微调 BERT 模型进行任何改变。除了矢量处理的最后阶段使用传统算法(聚类和最近邻居)来确定 NER 标签之外,这是通过仅端到端地对学习到的分布式表示(矢量)进行操作来实现的。此外,与来自顶层的向量用于下游任务的大多数用例相反,BERT 对屏蔽句子的输出仅用作种子符号信息,以在算法上对其自己的最低层(其单词嵌入)进行操作,从而收获句子的 NER 标签。
图六。传统的有监督的 NER(左图)与本文描述的无监督的 NER(右图)形成对比。传统上,NER 一直是一项受监督的标签映射任务,其中模型被训练/微调以执行该任务(左侧路径)。相比之下,对于无监督的 NER,按原样使用用屏蔽语言模型目标无监督训练的预训练/微调模型,并且模型的输出被用作播种信息,以在算法上对 BERT 模型的最低层(其单词嵌入)进行操作,从而收获句子的 NER 标签。
总之,执行 NER(传统上是监督学习任务)所需的所有信息已经存在于非监督的 BERT 模型中,其关键部分作为单词嵌入驻留在其最低层中。
上述无监督 NER 的原型实现可在 Github 上获得
相关作品/参考文献
https://homes.cs.washington.edu/~eunsol/open_entity.html这篇 2018 年的论文使用远程监督来执行实体识别。细粒度标签是为训练模型众包的。
https://www.aclweb.org/anthology/N19-1084.pdf。本文使用监督多标签分类模型对超过 10,000 个自由类型执行细粒度的实体分类
命名实体识别一直是一个被广泛研究的问题,迄今为止,arXiv 中约有 400 篇论文,Google scholar (自 2016) 中有~50000 个结果。
附加注释
贝茨·MLM·海德—快速回顾
伯特的 MLM 头本质上是伯特模型,上面堆叠了一个单一的变换层。下图显示了带有 9 个标记的句子的 BERT 输出(标记化后),是一个 9 x 768 矩阵(768—BERT 基本模型的维度)。这穿过了 MLM 头部的致密层。对具有所有 28,996 个字向量的 9x768 输出执行点积,以找出句子中某个位置的向量输出与 28,996 个字向量有多相似。对于屏蔽的位置,这产生了在该位置的标记的预测。在训练/微调模式中,掩蔽位置的预测误差被反向传播到模型中,一直向下传播到嵌入(解码器权重和嵌入层权重是相同的)。在推理模式中,嵌入用于表示标记化的文本,以及在头的顶层输出逻辑。**
图 7。伯特的 MLM 头像— 显示一个 9 个单词的符号化输入流过模型及其 MLM 头像。解码器使用来自嵌入层的相同向量(在代码中绑定权重,但单独驻留在 pytorch.bin 文件中)。
这种方法的性能
对于像这样的句子,
在使用 BERT 的典型监督方法中,通过将整个句子发送到微调的 BERT 模型一次,将获得如下所示的 NER 输出标签 (B_PER,I_PER,O…)
本帖中描述的无监督 NER 方法要求我们将上述句子传递给一个 MLM 负责人四次,以识别四个实体——John Doe、New York、Rio De Janiro 和 Miami (前面描述的这四个实体位置由 POS tagger 与 chunker 协同识别)。
具体来说,下面句子的 4 个标记化版本将被传递到 MLM 模型中
以检索每个屏蔽位置的上下文敏感签名,然后将其与上下文不敏感签名进行匹配,以产生每个位置的实体预测,如下所示。
尽管原则上我们可以一次检索输入句子中每个单词的 MLM 上下文敏感签名,但实际上我们必须将句子的屏蔽版本分别发送到 MLM 模型以确定实体类型,因为不清楚是否有一种方法来组合对跨越多个单词的短语或子词的上下文敏感预测, 确定实体类型(如果原始句子只有单个单词实体,并且这些单词的标记化版本也存在于 BERT 的词汇表中——我们可以一次推断上下文敏感签名)。 例如,部分出现在词汇中的短语,如 New York ,以及分解为子词的单词,如Imatinib-I # # mat # # ini # # b。使这个问题复杂化的是具有不同默认含义的子词,例如伊马替尼中的I-I # # mat # # ini # # b,产生具有高方差的上下文敏感签名。像在子词上的波束搜索这样的尝试产生新的看似合理的单个记号,但是很可能不是基本词汇表的一部分,从而导致上下文敏感签名中的较大差异。鉴于 SpanBERT 具有预测跨度的能力,它似乎是一个可以考虑的选项,但它仍然可以预测屏蔽短语中的每个标记——它不会对屏蔽短语给出一个预测。
在实践中,通过并行预测一个句子的所有屏蔽版本,可以解决单个句子的多个屏蔽句子的性能问题。在上面的例子中,被屏蔽的术语占句子中术语总数的 50%——但实际上,平均来看,这个数字要少于这个数字。如果我们也用一个单独的句子来确认句子中每一项的实体预测,该单独的句子仅包括 fromTermis a _ _(如句子“Nonenbury is a __”),那么发送到 MLM 模型进行预测的句子的数量将是该句子中被屏蔽的项的数量的两倍。**
引导将标签描述符映射到用户定义的标签
如果我们对应用程序中的一组特定实体感兴趣,那么我们可以利用任何未标记的语料库,这些实体主要出现在
- 通过模型发送这些句子,并获取模型输出的标签描述符
- 通过出现次数对这些描述符进行排序,应该会在顶部产生描述我们感兴趣的实体的描述符。
- 我们只需要手动扫描这些描述符,并将它们映射到我们选择的实体标签。
- 如果我们用来获取这些标签的未标记语料库真正代表了我们的实体类型,那么这应该覆盖了我们实体的很大一部分
这种无人监管的方法
- 将特定用例中带有感兴趣实体的句子的标注问题转化为标注代表这些感兴趣标签的上下文不敏感描述符。通过这样做,如前所述,它消除了使用更多标记数据来重新训练模型以处理非分布句子的需要。
- 它还利用了一个经过训练的词性标注器来标注任何句子。然而,识别签名和候选描述符的关键部分是由被无监督地训练/微调的 BERT 执行的。
无子词过滤的上下文不敏感聚类统计
由于难以为子词找到标签,所以不考虑用子词来创建上下文不敏感的聚类。然而,将它们考虑在内的聚类运行揭示了捕获对某些应用可能有价值的有趣信息的聚类。Bert 大箱模型词汇表有 6477 个子词,其中 1399 个形成了簇中枢。其余的被吸收到 59 个非子词簇中枢 (2872 个是单态)。
将子词作为中枢以及包含子词的其他非子词中枢的上下文不敏感聚类。子词不包括在创建上下文不敏感的聚类中,它们在这里显示只是为了强调一些聚类捕获有趣的可解释信息(其他的不形成实体标记的观点)。
此方法的其他使用案例
假设实体类型的确定纯粹是基于一组术语来完成的,那么可以将它用于各种应用程序
- 查找两个或多个术语是否属于同一实体类型。分别输入包含这些术语的句子,找到上下文敏感签名,并检查模型输出的标签是否相同/相似
- 获取特定实体类型的更多术语。
- 当不仅仅局限于标记名词短语时,这种方法的输出可以(可选地结合词性标记器和依存解析器)用于为下游监督任务生成标记数据,如分类、关系提取等。在某些情况下,如果不替换被监督的任务本身,至少可以创建一个基线。
【2021 年 2 月更新。对术语(或一般短语)(如“Nonenbury”)的实体类型预测可以使用术语的[CLS]表示来完成(假设模型已经在下一个句子预测任务中训练好)。这种方法可以与上面文章中描述的上下文不敏感预测一起使用—使用合成句子“Nonenbury is a ____”预测实体类型。
这篇文章是从 Quora 手工导入的
无监督的自然语言处理:处理非结构化文本背后的方法和直觉
由 Raphael Schaller 在 Unsplash 拍摄的照片
tldr 这是自然语言处理中非监督技术及其应用领域的入门书。它始于单词向量背后的直觉,它们的使用和进步。这就演变成了关于语言模型的详细讨论的中心阶段——介绍、在行业中的积极使用以及不同用例的可能应用。
在新兴但先进的自然语言处理(NLP)和自然语言理解(NLU)领域,无监督学习占据着精英地位。这是因为它满足了一个令人垂涎的科学领域的两个标准——它无处不在,但同时理解起来又相当复杂。
我将尝试把我在这个领域的经验和知识分解成简单的块,希望你能更多地了解这个领域,甚至更多地了解——对解决和处理 NLP 问题有更好和更结构化的直觉。
我的工作主要是处理无监督的数据集,即没有标签或目标变量的数据集。在这个行业中,经常会出现这样的情况:你首先收到一个业务问题,然后头脑风暴,想出可能的解决方案。有时,您会提出创新的数据集和标签来解决您的问题。通常,标签是不存在的,你要么与 Mturkers 打交道(为门外汉, Mturk 是一个众包数据注释平台),要么在没有任何标签的情况下解决问题,即使用无人监督的技术。
让我们深入到单词向量和语言模型这两个最基本、最普遍的子领域。除了介绍基本概念和理论,我还将包括我个人经验中关于最佳实践、实际和工业应用以及相关图书馆的优缺点的笔记。
词向量
为什么是单词的向量?
将单词表示为向量——50-300 个浮点值的数组是 NLP 中最大的飞跃之一,也是最容易理解的一个。
在现在无处不在的单词向量出现之前,词汇表中的单词是使用传统的单键向量编码进行矢量化的,如下所示。该图示出了在句子“我爱 NLP”中包含 3 个单词的词汇的单热点向量。这种方法在 TF-IDF 等 ML 算法中仍被广泛使用,在数字电路中也很普遍。
图片作者:one-hot 编码:这里的单词“love”由向量[0,1,0]表示
在过去十年之交,单词向量模型随着 word2vec[1]和 Glove[2]等出版物的出现而出现。有了它们,NLP 领域很快转变为几乎所有可能的任务都采用它们。
单词向量是如何训练的?
词向量模型有两种风格——跳格模型和连续词袋(CBOW)模型,如下图所示。这两个模型基本上都基于相同的基本原则——关于一个单词的信息存在于它在中使用的上下文中。例如,“男人”和“女人”这两个词用在非常相似的上下文中,比如“男人可以做某事”和“女人可以做某事”。这些上下文,超过数百万个句子和数十亿个标记,通过模型学习概括为“男人”和“女人”在用法上是相关的,而“男人”与“他/他”相关联,“女人”与“她/她”相关联。因此,在大型数据集上,基于这些在各种句子中使用形成的关联,词向量开始变得很有意义。
CBOW 体系结构试图根据上下文猜测当前单词,而 Skip-gram 猜测给定当前单词周围的单词。例如,在句子中——“气候变化正在对自然产生不利影响。”在给定的上下文中,CBOW 模型将试图预测影响的单词,即句子中的其他单词。下图说明了这两种方法。
来自出版物的基本图像— 向量空间中单词表示的有效估计[1] :用于训练单词向量的模型变量。
当你在一个包含网络文章等内容的大型数据集的数十亿个标记上训练这样一个模型时,你得到的是一个向量形式的词汇表中每个单词的非常有效的表示。这些向量可以是 300 维长,即每个单词由 300 个实数表示。解释这些向量的最著名的例子如下图所示。
作者的图像:一个例子说明了二维可视化时的词向量。
根据该图,下面的矢量方程应该成立:
King_vec - Man_vec ~= Queen_vec - Woman_vec
或者基本上,换句话说,向量为这些对投射相似的关系。
图片来自出版物—https://papers . nips . cc/paper/5021-distributed-presentations-of-words-and-phrases-and-they-composition ity . pdf:展示不同国家与其首都之间关系的二维单词向量
词向量可以展示在现实世界应用中有用的有趣特征。有了单词向量,机器能够以更像人类的方式理解和处理文本。这种对文字和一般文本的理解延伸到其他形式的媒体,如语音、图像和视频,这些媒体通常首先转换为文本,然后进行进一步处理。稍后将详细介绍。
子词嵌入
在 2017 年发表的一篇论文[3]中,词向量的表示质量有了巨大的提高。这种新方法利用所谓的子词嵌入来构建向量。通过将一个单词分解成子单词或字符 n-grams,关注单词的形态学。我们以“哪里”这个词为例。取 n=3,它被分解为以下 n 元文法:
where -: <wh, whe, her, ere, re>
然后这些子词向量被组合以构建词的向量。这有助于更好地学习语言中单词之间的联系。想象一下,我们是在更精细的尺度上学习。这有助于学习词汇内部的现象。例如,“cat”和“cats”之间的区别类似于“dog”和“dogs”这样的词对。同样,“男孩”和“男朋友”的关系与“女孩”和“女朋友”的关系相同。这种方法还有助于为模型在训练集中尚未看到的 OOV(不在词汇表中)单词创建更有意义的表示。
词向量有什么用?
在我的另一篇文章中,我会更详细地讨论词向量的应用。简而言之——词向量对于快速计算非常有用,尤其是在计算资源有限的情况下。在各种语料库(新闻、网络、Twitter 和 Reddit 等社交媒体)上找到预先训练好的词向量很容易。您可能希望使用在最接近您的应用数据集的数据集上训练的词向量。例如,twitter 数据集上训练的单词向量将不同于新闻文章上训练的单词向量。
单词向量可用于构建单词或句子的向量,用于相似性或聚类任务。即使像为数据集绘制单词云这样简单的任务也是分析数据集的一种强大方法。然而,单词向量的真正力量是通过语言建模释放出来的。
作者图片:由这篇博客文章生成的文字云
语言模型
什么是语言模型?
语言建模是所有无监督 NLP 任务的主要工具。根据定义,维基百科恰当地将语言模型定义为:
统计语言模型是单词序列的概率分布。
因此,用更简单的话来说——语言模型用于捕捉和预测一个句子或一个文档中单词之间的关系。基本上,语言模型预测句子中下一个单词的条件概率分布,由下式给出:-
使用这个,一个句子出现的概率由下式给出:-
长话短说,语言模型用于学习数据集中的单词关联,以便它可以用于预测句子中的下一个单词,或句子的有效性-根据它从训练数据集中学习到的分布,这个句子出现的可能性有多大。所以一个模特可以说“嗨,你好吗?”比起像“嗨,晚安!”这样古怪的话,这是一个更可能的英语句子。
作者图片:语言模型在电话键盘应用中被用来预测下一个单词。
如上图所示,在语言模型的一个最明显的用途中——键盘应用程序在我们打字时提示下一个单词。这也是自动更正的工作方式。让我们使用下图更详细地看看这是如何发生的。
作者图片:语言模型的工作图
句子的单词或上下文被转换成单词向量。这些作为语言模型的输入,语言模型本质上是基于时间序列的神经网络。最后,我们得到词汇表中所有单词的概率值,即某个特定单词有多大可能适合作为给定输入上下文的下一个单词。实际上,词汇表是巨大的(~300k 或更多),这些输出概率只对几十个单词有意义,而其余的值很小(如 0.00001)。
体系结构
从体系结构上来说,语言模型有两个主要部分——编码器和解码器。顾名思义,编码器用于使用时间序列神经网络模型对输入(词向量)进行编码。对于时间序列,我的意思是该模型考虑了单词在句子中的位置顺序,其中单词 _2 在单词 _1 之后。另一方面,解码器与编码器相反,它使用编码器的输出(特征向量)来输出单词,一次一个单词,在循环到结尾时完成一个句子。这是一些深层的架构性的东西,除非你自己编码,否则你可能不需要。只是一个很好的了解术语,否则。
作者图像:语言模型的典型结构
语言模型的应用
我们讨论的是一个基本的开箱即用的语言模型。语言模型可以在无监督的环境中以多种方式使用。让我们看看一些更受欢迎的:
- 向量化把一个句子变成一个向量。这是一种比任何平均单词向量更好的句子矢量化方法。
- 句子/文件分类在监督设置下的任务(其中有目标标签)。在这里,操作上-您使用预训练的非监督语言模型来进一步训练(微调)监督分类任务。在没有任何标签的情况下,您可以执行聚类来分割数据进行分析。
- 生成任务正如我们在前面的图中看到的。句子生成是一个新兴的领域,最近像 GPT 3 这样的人成为头条新闻。对于像广告( pencil 、 persado )、游戏(ai dungons)、新闻或文档摘要( agolo )、对话模型、聊天机器人、键盘/谷歌自动完成、问题回答等等这样的任务,生成任务可以从零开始逐代变化。如果你有一个合适的数据集,任何类型的生成都是可能的,就像有人为《权力的游戏》所做的一样。一些高级应用在多媒体设置中使用语言模型,如图像字幕、各种语音到文本和文本到语音任务,如 Alexa ,手写识别等等。
- 用于跨语言翻译的机器翻译已经走过了漫长的道路。像谷歌翻译这样的应用程序使用语言模型将语音转换成文本,然后翻译成不同的语言。
- 信息检索大型数据集上的任务,如实体解析、基于方面的情感分析、文档标记。一些最强大的应用程序将语言模型与知识库结合使用。
这些是一些受欢迎的。任何顺序消费或生成的数据都可以用语言模型来建模。使用人工智能的音乐生成就是这样一种应用。那里有难以想象的大量应用,而且每分钟都在扩大。随着来自学术界和企业的大量研究,建模能力正在迅速提高。相关任务的艺术状态随着每一次主要人工智能会议的召开而进一步推进——以至于现在很难跟踪整个领域——你现在必须专注于一个或几个前述的子领域。
少射和零射学习
人工智能中一个有趣的新生发展是少量学习的概念[4]。这意味着一个经过训练的模型可以通过整合先前的知识,仅用少数几个有监督信息的例子来学习一个新任务。
这是人工智能领域的一个巨大进步,因为传统上,你需要难以置信的大量数据来学习甚至简单的任务。在语言模型的背景下,像 BERT 和 GPT-x 模型这样的预训练模型是在数十亿个令牌(> 100GB 的原始文本数据)上训练的,即使如此,针对特定任务微调这些模型也需要 100 多万个数据点。相比之下,很少尝试的学习者可以利用每个标签的几分来学习新的任务。这个概念提升到了一个全新的水平,即零触发学习,其中使用的不是数据点,而是关于类的元数据级别的信息作为输入。这是一个新的活跃的研究领域,仍处于早期阶段。一旦我们获得了可接受的精度指标,这将是一个非常有前途的领域。
参数爆炸
人工智能模型的准确性和有用性与数据集和模型参数大小有直接关系。
作者图片:根据参数大小绘制的各种语言模型
该图显示了 2017–2020 年期间的主要语言模型。参数大小每年都在增加一个数量级——BERT-Large(2018)[5]有 3.55 亿个参数,GPT-2(2019 年初)[6]有 1.5B 个,T5(2019 年末)[7]进一步扩展到 11B,最后 GPT-3(2020 年中期)[4]有 175 亿个。
有了这些,对这些模型的研究和培训的访问已经转移到了像谷歌,OpenAI,微软和脸书这样的大公司。GPT-3 需要 700GB 的 GPU 内存进行训练,远远超过了普通消费级 GPU 的 10-16GB 内存,在 cloud Tesla V100 GPUs 上进行并行训练的成本超过 460 万美元。我们这些凡人只能使用这些巨大的预训练模型的较小版本来完成我们无关紧要的任务。这不一定是一件坏事,也是人工智能进步的必然结果,但考虑到这一基础技术的未来,这是值得我们深思和铭记的事情。
期待听到你的任何评论、讨论,或者任何你想和我分享的想法。
参考
[1] Mikolov,Tomas,et al. 向量空间中单词表示的有效估计。
[2]j .潘宁顿、r .索彻和 C. D .曼宁(2014 年 10 月)。 Glove:单词表示的全局向量。载于《2014 年自然语言处理经验方法会议论文集》(第 1532-1543 页)。
[3] Bojanowski,p .,Grave,e .,Joulin,a .,& Mikolov,T. (2017 年)。用子词信息丰富词向量。计算语言学协会汇刊,5,135–146。
[4]布朗、T. B .、曼、b .、赖德、n .、苏比亚、m .、卡普兰、j .、达里瓦尔、p .……和阿加瓦尔(2020)。语言模型是一次性学习者。 arXiv 预印本 arXiv:2005.14165 。
[5] Devlin,j .,Chang,M.W .,Lee,k .和 Toutanova,k .,2018 年。 Bert:用于语言理解的深度双向转换器的预训练。 arXiv 预印本 arXiv:1810.04805 。
[6]a .、Wu、j .、Child、r .、Luan、d .、Amodei、d .和 Sutskever,I .,2019 年。语言模型是无监督的多任务学习器。 OpenAI 博客, 1 (8),第 9 页。
[7] Raffel,c .,Shazeer,n .,Roberts,a .,Lee,k .,Narang,s .,Matena,m .,周,y .,Li,w .和刘,P.J .,2019 年。用统一的文本到文本转换器探索迁移学习的极限。arXiv 预印本 arXiv:1910.10683 。
无人监管的纽约街头
使用聚类分类更深入地研究人口普查区域的贵族化
米尔蒂亚迪斯·弗拉基迪斯在 Unsplash 上拍摄的照片
我在纽约市出生和长大,在 90 年代中后期,我作为一个孩子看到了哈莱姆区从一个压倒性的少数族裔社区变成了今天的中产阶级化的褐色砂石天堂。已有关于邻里关系变化的学术论文,Ellen & Ding (2016)最近的一篇论文是我与我的模型进行比较的基准。
采用数据科学的方法,我想问一个非常具体的问题:
机器学习算法能检测中产阶级化吗?
这个项目要理解的最重要的特点是,这是无监督学习。这意味着没有为模型提供目标变量。因此,模型不是预测一个已经决定的结果,而是获取数据并得出自己的结论。最后,我将把它与我引用的学术论文中的发现进行比较。
数据
这类工作的最佳数据集是美国人口普查区域数据,通过一些研究,我发现了布朗大学(纵向区域数据库——LTDB)进行的一项关于多样性的研究。该研究收集并汇编了 2000 年、2010 年和 2012 年的人口普查和美国社区调查(ACS)信息。
数据类型自然地被分成两个不同的数据集。人口普查本身包含了一般的人口数据。这包括年龄、家庭规模、种族和民族。调查数据包括更详细的信息——移民身份、就业类型和收入。所有这些特征都包含在四个区的每个人口普查区域中。在识别中产阶级化方面,这两个数据集的组合将是最有效的。该项目以下列方式继续进行。
- 数据清理和预处理
- 数据探索
- 集群创建
- 与 Ellen & Ding (2016)的定性比较
- 结论和进一步的工作
1.数据清理和预处理
第一步是处理 2000 年美国人口普查数据,第一步是隔离纽约市。我用自己创建的一个助手函数做到了这一点,这样我就不必将函数定义放在代码中。要完全理解这个代码,你需要知道斯塔滕岛不包括在这项研究中。它在种族构成和人口密度方面的显著特征使它成为这个群体中的异类。
因此,通过一个快捷的功能,我能够将纽约市的四个区从美国所有的县中分离出来。接下来是我想要的总人口的百分比。
然后我把数据分成两类,人数据,房数据。人民方面可以包括文化遗产(即俄罗斯人、波多黎各人、爱尔兰人后裔),而房屋会告诉我们关于建筑和房屋的细节(即租金与自有、多单元建筑与单户住宅)。
由于中产阶级化意味着变化,因此总计数不会对模型有太大影响。我需要更清楚地了解这些邻里关系的变化,这意味着找出这些比率是如何变化的。我需要找到变化的百分比,为此我需要找到开始日期的百分比。
用总人口数作为分母,我很快做了一个函数来计算有多少人口符合这些子集。这适用于住房和人员子集。这将有助于回答一些更具体的问题。
白人占人口的百分比是多少?非裔美国人?有多少人拥有自己的房子?蓝领工人和白领工人的比例是多少?失业?首先,我必须手工制作这些列表。它们的名字都是唯一的,所以我必须对它们进行排序,但是一旦我这样做了,我就把列名保存为列表。
下面的函数允许我获取百分比,同时删除现在不需要的完整计数列。
2010 年人口普查数据重复了这一过程。然后将两个数据集合并。接下来是最重要的部分,这是整个项目的基础——计算百分比变化。
群体百分比的增加或减少将是无监督学习模型中的驱动因素。这是两种功能的结合。第一个从每个数据集(2000 年和 2010 年)中提取列,并将它们保存为压缩文件。第二个获取百分比变化,并将其保存为自己的列。
这可能会导致一些无穷大的值,但可以很容易地替换。
对样本数据重复这两个过程。在这个漫长的数据清理和预处理的最后,我们有了一个包含纽约市每个人口普查区域的百分比变化的数据框。接下来,我们进入了项目的探索部分。
2.数据探索
对于数据探索部分,我使用了 Python 的 Seaborn 包和 Tableau 的组合。对于 Python 部分,我将包含附带的代码。
有几个指标可以衡量中产阶级化。白人或非白人人口的变化和中位收入的变化。我的探索集中在这些事情上。
我的第一步是检查发行版。
作家创造的海边情节
你可以从这个图表中得到一些东西。首先,非白人人口发生积极变化的人口普查区域比白人人口多。第二,你可以看到,越多的人口普查地区的非白人人口越多,而白人人口越多的地区,非白人人口也越多。
我还想处理空间数据,所以我在 Tableau 上制作了以下图表。第一幅展示了白人人口增长最多的人口普查区域。
由作者创建的 Tableau 地图
Bedford-Stuyvesant 拥有前四名,该社区的白人人口增长了 2000%以上。深蓝色的点都在贝德福德-斯图文森。我们关注的最后一个指标是收入的变化。曼哈顿的地图最好地证明了这一点。
由作者创建的 Tableau 地图
哈林区中心在红色圆圈内。根据人口普查数据,每个家庭的平均收入已经上升了 250%以上。这是一个难以置信的数字,无法用工资增长来解释。这只能用一群新的人来解释,他们比以前住在那里的人拥有更多的财富。
3.集群创建
该过程的下一步是创建集群。聚类是一种无监督的分类技术,它查看所有数据,并根据其特征的相似性进行分组。在二维空间中,质心模型看起来像这样。
KMeans 聚类 Gif — Wikimedia Commons
然而,对于我的数据集,我们正在寻找 100 多个特征。这很难想象,集群也很难完成它的工作。使用所有的特性意味着尝试在 108 维空间中创建集群。此时,星团中各点之间的距离毫无意义。所以我不得不使用子集。
我尝试了三个独立的模型,每个模型都有三个不同的特性子集。第一个是层次凝聚聚类(HAC)、KMeans 和主成分分析(PCA)。关于集群的详细解释,请查看这篇来自 Analytics Vidhya 的关于集群的博客。最佳模型是根据其轮廓得分选出的。这考虑到了它的变形和惯性。基本上,星团有多紧密,它们之间的距离有多远。
最终结果以 PCA 结束,其中某个子集是具有最佳轮廓分数的模型。
使用第二子集的 PCA 具有最好的轮廓分数,并被选为最终模型。以下是这些结果的一些空间图表。
布鲁克林的集群模型。作者的 Tableau 图
该群集的缺陷是不能对普查区域的未来状态做出假设。这些数据都是关于人口变化的,但不包括 2000 年人口普查数据的原始状态。这意味着集群只知道人口普查区域的最终状态,而不会对易受中产阶级化影响的社区做出假设。
在这个集群的模型中,布鲁克林北部的大部分地区都遭受了中产阶级化。这是重新规划法和布鲁克林在一段时间内快速发展的产物。
为了与无监督学习保持一致,模型不会给聚类分配标签。相反,它们被分配了分组号。只有在分析过程中,我才给每个集群分配标题。最简单的方法是将空值分配给公园、人口较少的商业区或监狱(以莱克岛为例)。接下来是“稳定”地带。这里收到的名称并没有明确表明 2010 年的中产阶级化水平,而是表明人口或收入水平没有发生显著变化。“混合物”标签是最难理解的。由于这个模型没有考虑可能性,我不能把它归类为易受中产阶级化影响的地块。这个小组需要研究他们在城市中的位置。我在曼哈顿的领域知识比在布鲁克林强得多,所以我将使用聚类图来阐述我的下一个观点。
曼哈顿的聚类模型。作者的 Tableau 图
在上面的曼哈顿地图中,注意深灰色区域。它们包括上东区、中城和炮台公园城。作为一个群体,他们没有理由不属于稳定的群体。然而,我们必须记住,该模型工作的时间范围是 2000 年至 2010 年。2001 年 9 月,由于世贸中心的大火仍在燃烧,炮台公园城变得无法居住。所以它从一个非常高级的社区变成了一个几乎无人居住的社区。像上东区和中城这样的其他街区似乎被错误地分类了。这就是为什么贴上了“混合物的标签。它就像是不属于任何其他类别的小册子的总称。
“”集群展现了一幅鲜明的画面。收入和白人人口突然增加或非白人人口大量减少的地区出现了。下东区和哈莱姆区是明显的分类。然而,《地狱厨房》却让人大跌眼镜。虽然不知道是一个历史上的少数民族社区,但在开发真正开始之前,它基本上是商业区。
4.与 Ellen & Ding (2016)的定性比较
下一步是对模型的分类和 Ellen & Ding 建立的度量标准之间的异同进行定性分析。
艾伦&丁与布鲁克林集群模式的并列比较
在上面的模型中,你可以看到聚类模型在多大程度上确定了人口普查区域的中产阶级化。布鲁克林北部,包括威廉斯堡和贝德福德-斯图文森,几乎都在这里。但是在由该组指标生成的地图中要小得多。
艾伦&丁与曼哈顿集团模型的并列比较
在曼哈顿,头条新闻是艾伦和丁没有像该集群那样认为人口普查区正在变得中产阶级化。虽然他们在许多相同的社区上意见一致,但聚类模型也将曼哈顿北部——华盛顿高地和因伍德确定为中产阶级化。
5.结论和进一步的工作
请记住,虽然这些数据是从 2000 年到 2010 年的,其中一些信息来自 2012 年的 ACS,但结果非常清楚。纽约经历了大规模的中产阶级化,布鲁克林超过 17%的人口普查区都进行了中产阶级化。布鲁克林在 2020 年仍在经历大规模的中产阶级化,其结果尚未明朗。
该项目的下一步将包括使用 2020 年的人口普查数据和最新的 ACS 数据。看看其他行政区是如何发展的,以及是否有新的中产阶级热点,将会很有趣。
联系我
如果你想更多地谈论这个项目或联系,你可以在 LinkedIn 上找到我。或者,如果你想要一个项目的解释,包括详细的降价,请查看 Github repo 。
来源
- LTDB — 布朗大学纵向束数据库
- 艾伦&丁 推进我们对中产阶级化的理解 (2016)
- 分析 Vidhya — 聚类和不同聚类方法的介绍
无监督图像映射
探索大量图像的简单有效的方法
作为一名数据科学家,我经常参与反欺诈调查任务。因此,探索是调查的重要组成部分。它允许一个人熟悉分析的主题。
我将在这里详细介绍一种简单、快速、高效且可重复的方法,让你对你所拥有的图像有一个整体的概念。这是我的第一篇文章,所以请不要犹豫,提出你的问题和意见。享受😉
内容
- 先决条件
- 数据
- 描述图像
- 推断
- (英)可视化(= visualization)
先决条件
该算法使用 Python 3.6.8 和库 keras(版本 2.2.4)、pandas(版本 0.24.1)、scikit-learn(版本 0.22.2.post1)、numpy(版本 1.18.2)和 matplotlib(版本 3.0.3)。
要安装 Python,如果你在 Windows 或 Mac 上,你可以在这里下载安装程序。对于 linux 用户,下面的 bash 命令将安装 Python 3.6: sudo apt-get install python3.6
对于库,终端中的以下命令(bash、powershell 等。)将安装它们:pip install keras==2.2.4 pandas==0.24.1 scikit-learn==0.22.2.post1 matplotlib==3.0.3 numpy==1.18.2
最后,使用 Tableau 软件对结果进行可视化。这是一个付费软件,但你可以在这里免费试用。
我们现在可以导入库并指定图像的路径:
## Imports
from datetime import datetime
from keras.applications.resnet50 import preprocess_input, ResNet50
from keras.models import Model
from keras.preprocessing import image
from pandas import DataFrame
from random import sample
from sklearn.manifold import TSNEimport matplotlib.pyplot as plt
import numpy as np
import os
import time## Parameters
INPUT_DIRECTORY = 'UIC_dataset/'
assert os.path.exists(INPUT_DIRECTORY), 'Directory does not exist'
数据
在这个例子中,我选择使用 EuroSAT (RGB)数据集,这里是。
EuroSAT 数据集以 Sentinel-2 卫星图像为基础,覆盖 13 个光谱带,由 10 类 27,000 个带标签和地理参考样本组成——euros at:一种用于土地利用和土地覆盖分类的新型数据集和深度学习基准,作者:Helber、Patrick 和 Bischke、Benjamin 和 Dengel、Andreas 和 Borth、Damian,载于 2019 年《IEEE 应用地球观测和遥感专题杂志》
描述图像
第一步是找到一种方法来丰富地描述图像。一种快速简单的方法是使用已经在一般分类任务上训练过的神经网络作为编码器。我们的目标不是分类,而是使用网络提取的特征将相似的图像分组在一起。在 ImageNet 数据集上训练的 ResNet50 残差神经网络是一个非常好的开始。
想了解更多关于残差神经网络的知识?第一部分 这篇文章 解释得很好。
为什么在 ImageNet 数据集上训练 ResNet50?ImageNet 项目是一个大型视觉数据库,设计用于视觉对象识别软件研究。该项目已经对超过 1400 万张图像进行了手工注释,以指示所拍摄的对象,并且在至少 100 万张图像中,还提供了边界框。ImageNet 包含 20,000 多个类别,其中一个典型的类别,如“气球”或“草莓”,由数百个图像组成。
因此,经过训练对 ImageNet 图像进行分类并获得良好分数的神经网络将学会正确区分图像的形状和特征。这种能力对我们来说非常珍贵。问题是我们的 ResNet50 目前只知道如何从 ImageNet 类列表中预测一个类。
为了克服这一点,我们必须移除用于分类的网络的最后一层。网络的输出将是维度 2048 的特征向量。
## Model
# Retrieve the base model trained on ImageNet
base_model = ResNet50(weights='imagenet')# Removing the last layer by selecting the layers from the first to the penultimate one.
model = Model(inputs=base_model.input, outputs=base_model.get_layer('avg_pool').output)# Display layers
print(model.summary())## Get image paths
image_file_names = list()
image_file_paths = list()for root_path, directory_names, file_names in os.walk(INPUT_DIRECTORY):
for file_name in file_names:
if file_name.lower().endswith(('.jpg', '.jpeg', '.png')):
image_file_names.append(file_name)
image_file_paths.append(os.path.join(root_path, file_name))
print('{} images found'.format(len(image_file_paths)))## Sampling
image_file_names, image_file_paths = zip(*sample(list(zip(image_file_names, image_file_paths)), 1000))
image_file_names = list(image_file_names)
image_file_paths = list(image_file_paths)## Get image features
image_features = list()start_time = time.time()for index, image_file_path in enumerate(image_file_paths.copy()):
try:
img = image.load_img(image_file_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x) image_features.append(model.predict(x)[0])
except OSError:
del image_file_paths[index]
del image_file_names[index]
print("ERROR: Can't load image {}".format(os.path.basename(image_file_path)))image_features = np.array(image_features)print('Done ({:.0f} min)'.format((time.time() - start_time) / 60))
推断
我们人类发现很难掌握超过 3 个维度。所以想象一下 2048 年…
我最喜欢的可视化大矢量的方法之一是 t-SNE 算法。t-SNE 代表 t-分布式随机邻居嵌入。
是一种基于随机近邻嵌入的可视化机器学习算法。这是一种非线性降维技术,非常适合于在二维或三维的低维空间中嵌入用于可视化的高维数据。具体而言,它通过二维或三维点对每个高维对象进行建模,以这种方式,相似的对象通过附近的点进行建模,而不相似的对象通过远处的点以高概率进行建模。
t-SNE 算法包括两个主要阶段。首先,t-SNE 在高维对象对上构建概率分布,使得相似的对象被分配较高的概率,而不同的点被分配较低的概率。第二,t-SNE 在低维图中的点上定义了类似的概率分布,并且它最小化了关于图中点的位置的两个分布之间的 Kullback-Leibler 散度(KL 散度)。
像许多算法一样,参数必须仔细选择。这篇文章很好地解释了 t-SNE 不同参数的影响。
在我们的案例中,以下参数值使我们获得了令人满意的结果。
## Compute t-SNE
start_time = time.time()t_SNE = TSNE(n_components=2,
perplexity=20,
n_iter=2000,
metric='euclidean',
random_state=8,
n_jobs=-1).fit_transform(image_features)print('Done ({:.3f} s)'.format(time.time() - start_time))
(英)可视化(= visualization)
一旦投射完成,我们就可以想象结果。
Matplotlib
一个简单的散点图已经可以用来确定一些分组。
## Plot results
# Increase plot size
plt.figure(figsize=(12, 12))# Set title
plt.title('t-SNE plot')# Plot and show
plt.scatter(t_SNE[:, 0], t_SNE[:, 1], marker='.')
plt.show()
我们已经可以区分出一组与众不同的图片——作者的图片
这个简单图形的缺点是,它不允许您查看由点表示的图像。为此,需要更高级的可视化解决方案,如 Power BI 或 Tableau 软件,详情如下。
Tableau 软件
Tableau 是一个付费的数据可视化软件,使用起来相当简单,允许大量不同类型的可视化,包括交互式可视化。
我们必须首先保存 t-SNE 的结果。
## Save results
data_frame = DataFrame(data={'Image_file_names': image_file_names,
'Image_file_paths': image_file_paths,
'Image_features': [str(vector).replace('\n', '') for vector in image_features],
'X': t_SNE[:, 0],
'Y': t_SNE[:, 1]})
data_frame = data_frame.set_index('Image_file_names')data_frame.to_csv(path_or_buf='Unsupervised_image_cluterization_run_{}.csv'.format(datetime.now().strftime("%Y_%m_%d-%H_%M")),
sep=';',
encoding='utf-8')
然后,在 Tableau 软件中,点击“新数据源”>“文本文件”,选择你的 CSV 文件打开。
Tableau 加载页面-作者提供的图像
数据加载后,转到“第 1 页”。
Tableau 数据页面-作者图片
在这里,右击“X”>“转换为尺寸”。对“Y”做同样的操作。
通过拖放将“X”和“Y”分别添加到“列”和“行”字段中。
点击将鼠标移到“列”字段中的“X”上时出现的小箭头,然后点击“连续”。对“Y”做同样的操作。您应该得到一个类似于散点图的视觉效果。
预计到以后,将“图像文件路径”拖放到“标记”窗格的“细节”框中。
Tableau 表单页面-作者提供的图像
为了使视觉更美观,你可以让网格、轴和工作表的名称消失。为此,右键单击网格>“格式”,然后在右侧的“格式字体”窗格中,单击“线条”图标,并通过选择“无”来禁用不同的线条。
然后,右击轴,您可以禁用“显示标题”选项。右键单击标题激活“隐藏标题”选项。
最后,在“标记”窗格中,您可以修改点的形状、大小、颜色等。就我个人而言,我喜欢让它们看起来像不透明度为 75%的小方块。这让我想起了小的拍立得照片,我们会把它们分类放在一张桌子上。
您也可以将“图像文件名”拖放到“工具提示”中,使图像的名称出现,然后双击“工具提示”,您可以编辑工具提示的内容,修改为只保留“< ATTR(图像文件名)>”。
纸张修饰—图片由作者提供
我们现在可以切换到“Dashboard”选项卡,方法是单击工作表 1 底部的“New Dashboard”图标。
让我们通过将“宽度”和“高度”分别更改为 1600 像素和 900 像素来增加“尺寸”窗格中的尺寸。
然后,您可以将“工作表 1”从“工作表”选项卡拖放到仪表板。右键点击标题使其消失。
在“对象”窗格中,将“网页”拖放到仪表板上“工作表 1”的右侧。然后单击“确定”,将 URL 留空。
Tableau 仪表板页面-按作者分类的图像
这个网页是显示图像的一种方式。目的是通过将鼠标悬停在一个正方形上来显示网页中的图像。为此,我们将启动一个本地 web 服务器。在您的终端中,转到要服务的目录并键入cd <path where UIC_dataset folder is>
,然后通过键入python -m http.server --bind 127.0.0.1
启动一个 Python web 服务器。您的服务器现已启动。
在顶部的“仪表板”标签中>“操作……”>“添加操作>”>“转到 URL……”。在“运行操作于:”中,选择“悬停”。在“URL”中,输入 URL“http://127 . 0 . 0 . 1:8000/<图像文件路径>”。在“URL 目标”中,选择“网页对象”。最后,点击“确定”。
动作窗口—按作者分类的图像
注意:如果您在 Windows 中工作,您可能需要通过将“\”替换为“/”来更改“图像文件路径”。为此,在“工作表 1”中,右键单击“数据”窗格底部,然后单击“创建计算字段…”。输入名称“路径”,并输入如下计算公式。然后在“Dashboard”>“Actions”>双击“Hyperlink1”,用“http://127 . 0 . 0 . 1:8000/
计算字段窗口-按作者排序的图像
瞧!当你飞过它们时,你的图像就会出现。
结果—作者提供的图片
所以我们可以看到相似的图像被分组在一起。可以看到一些星团,如右上角的“住宅”星团或底部明显分离的“海湖”星团。
结论
因此,我们看到了一种简单有效的方法来获得一个图像数据集的好主意。这个想法对你进一步的分析工作会非常珍贵。
我希望你喜欢这篇文章,它让你想了解更多关于数据分析的知识。请随意提问和评论。
代码在我的 gitlab 上有一个 Jupyter 笔记本,如果你愿意,你可以贡献给它。
更多的文章将会出现,包括一篇关于清理纯文本邮件的文章。敬请关注,稍后见😉
用显微镜和算法理清生物学
我们的新研究论文使用数据科学来分析器官在胚胎中是如何形成的。这里有一个针对感兴趣的非专家的快速总结。
从数据科学的角度看胚胎中细胞的美丽。(图片由作者提供)
随着胚胎的生长,其内部的无数细胞聚集在一起,组装成不同的器官,每个器官都有其独特的形状、大小和生物功能。这一基本过程看起来不太像是工厂里的汽车机器人组装,而更像是一群忙碌的蚂蚁。这些细胞探索它们的周围环境,通过化学信号进行交流,在彼此身上爬行,推拉它们的邻居……这是一个令人费解的混乱,但它确实产生了比汽车复杂得多的生物机器。
对于想要弄清楚这一切是如何工作的生物学家来说,显微镜是一个必不可少的工具,因为它们可以直接观察胚胎中的细胞。现代显微镜是一种高科技设备,可以产生极其详细和大规模放大的全 3D 图像。然而,因为器官的形成是如此复杂,仅仅通过看这些图像通常很难理解发生了什么。这就是为什么许多生物学家已经开始使用计算机算法来帮助他们筛选出重要的信息。由于过去几年统计学和机器学习的快速发展,计算机已经非常擅长解决这类问题,尽管它们通常需要特定的数据格式(所谓的特征空间)或非常大量的数据(所谓的大数据)。不幸的是,细胞的图像没有形成特征空间,显微镜检查通常太耗时,无法产生大数据。这使得很难使用现代计算工具来研究器官的形成。
我们的目标是克服这一限制,并应用计算机的能力来分析斑马鱼胚胎中一组称为侧线原基的细胞。这组细胞代表了器官形成的一个有趣例子,其中细胞以高度协调的方式同时移动和改变它们的形状。为了使计算分析成为可能,我们开发了新的算法,将细胞图像转换到一个特征空间,该空间编码几乎相同的信息。使用这种格式,我们能够对侧线原基的许多不同图像进行数字组合和统计分析。我们以不同的方式过滤和可视化数据,以帮助我们找到和解释侧线细胞如何组织的最重要模式。我们的分析检测到了一些已知的模式,证实它工作正常。更有趣的是,它还揭示了一些以前未知的模式,例如位于原基中心的细胞与位于外部的细胞在形状上的差异。基于这些结果,我们可以为侧线细胞组织自身的物理相互作用提出一个新的假设。
一个年轻的斑马鱼胚胎的显微图像,带有一个特殊的标签,突出了某些细胞,包括侧线原基(白色箭头)的细胞。比例尺:200 微米。(图片作者)
侧线原基的高倍特写显微镜图像。比例尺:10 微米。作为参考,假设人类头发的平均直径略小于 100 微米。(图片作者)
在这张图片中,原基的单个细胞已经通过计算机识别并分开,突出了它们在形状上的不同。这样的图像是我们新的图像转换算法和后续计算分析的起点。比例尺:10 微米。(图片作者)
我们开发的算法开辟了使用计算机分析显微镜图像的新途径。通过这种分析发现的模式可以通过额外的实验进行更详细的研究,这将最终导致对细胞群如何组装成器官的更好理解。这些知识将帮助我们治疗由器官形成问题引起的疾病,并使我们更接近于为移植而人工培养器官的可能性。从长远来看,我们甚至可以完全控制器官的形成过程,设计出全新的生物机器。
本文由 Jonas Hartmann 撰写,Elisa Gallo 和 Julia Suter 提供了反馈。这项研究是在德国海德堡的欧洲分子生物学实验室进行的。同行评审论文全文可在 eLife 杂志上免费获得:
从 3D 显微数据中提取代表性数值特征的计算策略使得能够深入…
elifesciences.org](https://elifesciences.org/articles/55913)
用人工智能解开医学缩略语的字母汤
直接谈论医疗保健中的人工智能|帖子#1
照片由阿玛多·洛雷罗在 Unsplash 上拍摄
本帖为 首发 在我的 博客 直谈 AI 在医疗保健 。每篇文章都以非技术术语解释了最近的人工智能研究,并强调了医疗保健和生物技术组织的经验教训,重点是实用的见解,以帮助你了解你今天可以做什么,明天应该做什么。订阅邮件列表 这里 。
让我们从 2019 年 12 月举行的关于神经信息处理系统 (NeurIPS)的会议上的健康机器学习研讨会的一篇论文开始这个系列,这可以说是机器学习和人工智能领域最具影响力的会议。
这项工作由多伦多大学的研究人员完成,解决了自动医疗文本处理中的一个问题,该问题在开发产品以支持临床决策支持、质量报告和利用管理等用例时经常遇到。
医学文本中有丰富的缩写和首字母缩略词,其含义有时很模糊:RA 是代表“右心房”还是“风湿性关节炎”?出错会破坏算法,导致不准确的结果和错误。这个问题被称为“缩写歧义消除”,目标是从上下文中推断缩写的含义。
大多数自然语言处理(NLP)算法使用来自相邻单词的上下文。一些现代方法甚至使用一两个相邻句子的上下文。但医学文本中的缩写词通常会带来更大的挑战:在句子“患者接受放疗以治疗病情”中,“放疗”可能意味着“放射疗法”或“呼吸疗法”。但是只看一两句话是不够的:需要完整医疗记录的上下文。
考虑到这一点,研究人员设计了论文中的主要创新:一种简单而聪明的方法来表示完整笔记的上下文,并将其与句子的上下文结合起来。相对于以前的方法,这种增强加上一些较小的调整使性能提高了 4–14%。4%的改进可能看起来很小,但实际上对于相对成熟的现有方法来说已经是高端了。
医学缩写是一个棘手的问题,因此这项工作可以帮助改进医学文本处理。但它也强调了医疗机构在实施人工智能解决方案时更广泛的经验教训。
研究人员的第一个见解是将缩写歧义消除识别为自动医学文本处理中的一项重要任务,并专门关注它。一般来说,最强大的人工智能解决方案是为非常有针对性的用例开发的。因此,机器学习和人工智能团队在专注于任务而不是通用用例时最有效。确定这些任务并评估它们的业务影响应该是技术团队和更广泛的组织之间的持续协作。
第二个洞见是理解医学文本不同于更一般的自然语言处理任务,以及改进现有的专门针对医学背景的方法。虽然这种情况下的研究团队是学术型的,但这种类型的改进是业内熟练的数据团队可以实现的。
最后,这项工作在一个特定的挑战上取得了良好的结果。但是对医学文本处理及其实际应用的更广泛的影响是什么呢?很可能是真的,但是很小。这是机器学习系统最常见的情况。机器学习是一个不断迭代和小改进的游戏,缓慢而稳定的人会赢得比赛。
订阅 邮件列表,定期更新人工智能在医疗保健和生物技术领域的实际应用。
直到机器学习的技术债务把我们分开
CACE 原理和为什么 ML 中的技术债务是不同的
埃胡德·纽豪斯在 Unsplash 上拍摄的照片
我简介
技术债 。如果这些话没有让你不寒而栗,你可能太新手了,或者你已经完全放弃了。在最近的一篇论文中,谷歌的一组研究人员讨论了隐藏在机器学习(ML)系统中的技术债务。
ML 允许我们快速构建有用的复杂预测系统,但这不是免费的。作者指出,技术债务框架可以揭示 ML 系统中的大量持续维护成本,例如:
- 边界侵蚀,
- 纠结,
- 隐藏的反馈回路,
- 未申报的消费者,
- 数据依赖性,
- 配置问题,
- 外部世界的变化,
- 系统级反模式
如今开发和部署 ML 并不昂贵,但是等式的另一部分是:长时间的维护。这被证明是困难和昂贵的,如果技术债务得不到控制,情况会变得更糟。
起源和财政类比
技术债务最早是由沃德·坎宁安在 1992 年提出的,当时他在论证软件工程快速发展的长期成本。他将其比作财政债务。这种比较引起了共鸣,因为债务本身并不是一件特别坏的事情。我们可能会欠下债务,但如果我们有一个明确的目标和如何偿还的计划。当我们不这样做时,事情会变得更加复杂。
我们先来看财政债务。如果是战略性收购,并计划获得比债务利息更高的回报,那就有意义。现金流的期限和时机也要考虑,即“下一笔债务何时到期?”vs .下一个收入流什么时候到来?”。你明白了。并非所有的债务都是坏的,但所有的债务都需要处理。虽然财政债务大多只有一个方面,即金钱,但技术债务可以通过多种方式偿还:
- 代码重构,
- 单元测试增强,
- 删除死代码和注释,
- 减少依赖性,
- 文件审查
解决技术债务并不意味着增加新功能,而是净化环境,使未来的增强更容易,错误更少,维护更容易。
与财政债务一样,任何延迟都意味着复利,而且与财政债务不同,对于技术债务来说,它们在沉默中增长。正如作者提醒我们的,当谈到机器学习中的技术债务时,它是两个移动部分的组合:对代码和 ML 方面的关注。
侵蚀抽象边界
在传统的软件工程中存在很强的抽象界限,并以封装和模块化设计的形式出现。这些实践允许代码可维护,并确保变更和增强是隔离的。
有了 ML,事情变得更加复杂。如作者所述,ML 的本质用于“在不依赖外部数据的情况下,无法在软件逻辑中有效表达所需行为的情况”。
纠缠
ML 使用混合输入,仅仅一个输入的存在就会影响其他输入的重要性。如果我们有特性[ x1 , …, xn ],那么对例如 x1 输入分配的改变可能会影响剩余的 n-1 特性对它们的使用,例如它们将采用的重要性或权重。
类似地,删除或添加新功能也会导致变化。作者称之为“CACE”原则,因为改变任何事物都会改变一切。该原则不仅适用于输入,也适用于学习设置、采样方法、超参数、数据选择等。
校正级联
想象一个模型 M1 解决问题一个。如果类似的问题A’出现,一个捷径就是创建M1’作为 M1 的一个调整。研究人员认为这造成了对 M1 的依赖,使未来的改进分析变得复杂。模型级联建立作为另一个问题,一个“将被模型 M1 解决”。
一个提议的解决方案是增强 M1 来直接学习校正,具有区分案例的特征或者接受为 A’问题建立单独模型的需要。
未申报的消费者
他们被定义为默默的依赖他们系统的模型输出。因为他们对团队管理模式 M1 不了解,他们有受到 M1 任何变动影响的风险。这种可见性债务可能会导致 M1 实施变革的成本和难度增加。他们也能创造隐藏的反馈循环。
代码依赖与数据依赖
虽然代码依赖可以被编译器发现,但是数据依赖却很难跟踪。研究人员指出了三个原因:
- 不稳定的数据依赖关系
利用系统的输出作为系统的输入被证明是不稳定的。这在定性和定量方面都是有效的。正如作者指出的,当两个不同的团队参与时,事情会变得更糟。当一个团队拥有系统的输出,而另一个团队拥有将该输出作为输入的模型时。在这个设置中,变化可能随时发生并影响模型团队。为了减轻这一事件,作者建议对给定的输出进行版本控制。
2。未充分利用的数据相关性
假设一个产品编号方案从旧编号过渡到新编号,并且两个方案都作为特性保留。新产品只收新号,老的同时维护新旧。每当删除数据库中的旧号码时,ML 系统都会遇到问题。作者将这些特性分为捆绑特性、遗留特性和相关/工程特性。
作为一个缓解方案,建议运行“保留一个特性评估,这样可以删除不必要的特性。
3。数据相关性的静态分析
虽然代码依赖可以被编译器发现,但是数据依赖却很难跟踪。一个自动化的特性管理系统是一个有帮助的工具,更多细节请参见源代码。
隐藏的反馈循环
当两个独立的系统相互影响时,就会发生这种情况。我们以一个电子商务页面为例。一个系统向用户推荐相似的项目,而另一个系统选择最相关的相关评论。一个系统的变化可能会影响用户的行为,从而影响其他组件的点击率。
水管问题
在现实世界的 ML 系统中,ML 代码所占的份额相对较小。围绕它的轨道通常被描述为管道/管线,如下所述:
图片作者论文作者
在这种情况下,技术债务以设计模式的形式出现。研究人员定义如下:
- 粘合代码支持代码不同部分的互操作,如库或程序。这反过来会冻结系统,因为测试任何替代方案都变得及时且昂贵。作为解决方案,建议将其转化为 API。这允许更多的可重用性,并降低了改变包的成本。
- 管道丛林往往发生在资料准备阶段。特别要注意的是,ML 系统中的连接、中间文件的采样和解析很快就会变得越来越多。作为一种解决方案,建议在进行数据收集和特征提取时保持整体方法。从头开始重建管道的决定可能是一项重大努力,但可以降低未来成本,并且不会阻碍创新速度。
作者指出,如果“研究”和“工程”角色不分离,角色在同一个团队中工作或由相同的人担任,那么胶水代码和管道丛林的摩擦可以减少。
我们的债务水平如何?
作者建议问几个问题,作为潜在债务水平的温度检查:
- 改进一个模型或信号会降低其他模型或信号吗?
- 一个新的变化对系统的影响能有多精确的测量?
- 团队的新成员需要多长时间才能适应?
最后一个问题似乎是最能说明问题的,如果一个新的加入者可以很快加入,并且只使用文档,而不与团队成员互动,这可能是一个精益 ML 系统的标志。
在技术债务上走得更远
如果你对技术债务的渴望没有得到满足,这里有更多的陷阱可以寻找:
- 死的实验代码路径,
- 普通的气味,
- 抽象债务,
- 配置债,
- 数据测试债务,
- 再现债务
结论
术语技术债务是一个有意义的比喻。至于财政债务,如果不加以控制,迟早会产生滚雪球效应。还清债务将是一个痛苦的过程。作者注意到,如果一个团队可以快速移动和释放,仍然不足以确定债务水平低。相反,仅仅是行动迅速这一事实就可能带来技术性债务。
布莱斯·帕斯卡在他的一个 letters⁴:中说得很好
“我把这封(信)写得比平时长,因为我没有时间把它写短。”
这是有症状的,可以移植到软件工程中,因此也移植到 ML 中。对快速解决方案的需求也意味着,在 ML 系统的不同移动部分进行适当规划、内务处理和思考的时间减少了。除了计划,文档可能是软件工程的穷孩子& ML。团队知道他们需要编写和维护它,但是这不是一个令人愉快的任务,然而却很有帮助。也许是时候接受一个新的座右铭了: ML 团队总是偿还他们的债务!
编码快乐!
感谢阅读!喜欢这个故事吗? 加入 Medium 完整访问我的所有故事。
参考
[1] Sculley,d .等人,“机器学习系统中隐藏的技术债务” NIPS (2015),http://papers . NIPS . cc/paper/5656-hidden-technical-debt-in-machine-learning-systems . pdf
[2]沃德·坎宁安(1992 年)。wy cash 投资组合管理系统,http://c2.com/doc/oopsla92.html
[3]麦克马汉等人(2013 年)。广告点击预测:战壕里的风景。”
[4]布莱士·帕斯卡(1657),《信札·外省人》(Les Provinciales)
成为机器学习工程师的不为人知的真相
从事人工通用智能研究?自动驾驶汽车?不…组成训练集并在基础设施上工作?更有可能。
照片由 Unsplash 上的 Gwendal Cottin 拍摄
我最近参与了 Reddit 上一个有趣的讨论,我的一些回答得到了高度评价。它的要点是作为一名机器学习工程师的不为人知的真相。我以策划的方式分享关键要点,因为我是更积极的参与者之一。
作为一名 ML 工程师有哪些不为人知的真相?关于 Reddit
这里有几个你可能会感兴趣的链接:
- [Labeling and Data Engineering for Conversational AI and Analytics](https://www.humanfirst.ai/)- [Data Science for Business Leaders](https://imp.i115008.net/c/2402645/880006/11298) [Course]- [Intro to Machine Learning with PyTorch](https://imp.i115008.net/c/2402645/788201/11298) [Course]- [Become a Growth Product Manager](https://imp.i115008.net/c/2402645/803127/11298) [Course]- [Deep Learning (Adaptive Computation and ML series)](https://amzn.to/3ncTG7D) [Ebook]- [Free skill tests for Data Scientists & Machine Learning Engineers](https://aigents.co/skills)
上面的一些链接是附属链接,如果你通过它们购买,我会赚取佣金。请记住,我链接课程是因为它们的质量,而不是因为我从你的购买中获得的佣金。
1.使用深度学习
许多机器学习爱好者认为他们会玩花哨的深度学习模型,调整神经网络架构和超参数。别误会,有些人会,但不多。
事实是,ML 工程师将大部分时间花在“如何恰当地提取类似真实世界问题分布的训练集”上。一旦你有了这些,你就可以在大多数情况下训练一个经典的机器学习模型,它会工作得足够好。
出于好奇,这些算法中最难解决的问题是什么?又是用哪一个来解决的呢?
由 Caleb George 在 Unsplash 上拍摄的照片
深度学习最近在计算机视觉(例如,自动驾驶汽车)和自然语言处理(GPT-3 等)方面取得了最大的成功。).因此,在这些领域工作的研究人员和从业者最有可能使用深度学习。
IMO 有史以来最大的成就就是 DeepMind 的 AlphaGo Zero。自动驾驶汽车可能是对社会影响最大的汽车。自然语言处理的最新成果是 GPT-3。
深度学习模型与经典的 ML 模型相比是否很难解释?
OP 说得好:
我看不出解释卷积神经网络会比解释基于支持向量机、随机森林或梯度推进的整个分类框架更难。
我觉得随着 NNs 对可解释性的研究越来越多,这种说法越来越不真实了。
当将 NNs 与 GLMs 或朴素贝叶斯等优秀的传统统计学进行比较时,它显然仍然成立。但是一旦你转向基于 CART 的方法或者任何使用内核技巧的方法,这种虚构的可解释性就不复存在了。
自动驾驶汽车领域将在未来四年内增长 42%,顶级工程师的薪水…
medium.com](https://medium.com/@romanorac/autonomous-systems-dcf6af4f88c5)
2.学习机器学习
在学习的时候,你倾向于浏览很多关于 arxiv-sanity 的论文,里面有一些非常酷的算法。然后你进入这个行业,你看到的都是相对基础的东西,如逻辑回归、前馈神经网络、随机森林(决策树)、单词袋而不是嵌入,你觉得这些模型可以由普通大学生甚至聪明的高中生实现。也许如果你幸运的话,你会看到 SVM。
基础设施和数据管道是所有真正的工程工作发生的地方。
职业生涯刚开始的时候感觉和上面的 OP 差不多。但是为什么在没有必要的情况下,你会使用一个更复杂的工具来完成任务呢?许多现实世界的问题不需要最先进的神经网络架构来解决。有时一个简单的逻辑回归就能完成任务。
评论的第二部分适用于较小的初创公司,在这些公司中,你通常必须自己处理数据管道。在较大的公司中,有专门的部门处理基础设施。但是没有捷径——数据科学家仍然需要充分了解数据基础设施是如何工作的。
3.学习理论
想学多少理论就学多少,但最终,你的工作将是 99%的数据清理和基础设施工作。
99%有点夸张了。换句话说:机器学习工程师不只是玩花哨的模型。有时他们需要通过清理和标记数据来弄脏自己的手。
为什么不用软件和服务给数据贴标签?
这是非常正确的。以至于我以为只有我一个人。我主要在 NLP 工作,99%的工作是用 Java 标记数据和制作一些基础设施。
对于实践中使用的大数据集来说,数据标注服务通常过于昂贵。有些数据集的标注并不简单。我有过一次在发票分类上工作的经历,你需要专业的会计师来标记这些数据。
机器学习在现实世界中是怎样的?
用 imgflip 创建的迷因
我越来越注意到,在理解数据科学家做什么方面存在差距。当期望与现实不符时,许多有抱负的数据科学家会感到失望。数据科学不仅仅是调整你最喜欢的模型的参数,并在 Kaggle 排行榜上获得更高的排名- 如果我告诉你现实世界中没有排行榜会怎么样?!?
这就是为什么我写了你的第一本云中的机器学习模型电子书来展示如何从头到尾处理一个实际的数据科学项目。这本电子书的目标是数据科学爱好者和软件工程师,他们正在考虑从事数据科学职业。
一步一步的指导,将告诉你如何训练一个机器学习模型,建立一个网络应用程序,并部署到…
medium.com](https://medium.com/@romanorac/hands-on-data-science-course-e764853f516b)
在你走之前
在 Twitter 上关注我,在那里我定期发布关于数据科学和机器学习的消息。
照片由Courtney hedge在 Unsplash 拍摄
揭示“民主化”数据科学/机器学习的常见误解
意见
你的志向是成为数据科学家还是机器学习专家?那么,请允许我戳穿炒作,澄清一些你可能已经被扼杀的误解。
尼克·舒利亚欣在 Unsplash 上的照片
大约 4 年前,正是 YouTube 上这个特定的视频——MarI/O——视频游戏的机器学习激起了我对人工智能&机器学习的兴趣。作为一个狂热的游戏玩家,同时也有经济学的学术背景,我对自己说,“哦,我已经有了让马里奥自己做这些事情所需的一半技能了”。
你看,这是我对机器学习(或一般的数据科学)的第一个误解。我一点也不知道什么是强化学习,在哪里&如何使用。但我在乎吗?没有。我所想的就是创造我自己的 ML 模型。
这里的教训是?误解的产生是由于一知半解&缺乏深入探究兔子洞的好奇心。[1]
不管怎样,我自学了编码&现在我向我的客户提供我在计算机视觉和 ML 方面的专业知识。
你能从这篇文章中期待什么
看最近的趋势,AI 肯定是上升的。对任何人来说,错过目前大量的就业机会都是不明智的。幸运的是,现在比以往任何时候都更容易进入机器学习或数据科学领域。现在有成千上万的在线资源,自学 ML 变得更加容易。
但是,随着学习资源的容易获取,一个主要的警告也随之而来。
你学会了编码,你只是弄清楚了什么是SVM&如何调整它的超参数以达到很好的效果。一切都很好,但是现在问问你自己。你对如何将新学到的知识和技能运用到现实世界的问题中有什么线索吗?
如果你对这个问题没有答案感到惊讶,那么,快速阅读文章的其余部分。
通过这篇文章,我希望在你进入机器学习领域之前澄清你可能有的一些误解。
观看&向卑微的巨人学习
吴恩达他们这样做的动机是什么?通过帮助社区繁荣,让他们在不久的将来更容易被雇佣,让世界变得更美好。
几年前,当我在 Python 上写下我的第一个 print("Hello World") 语句时,他们的资源对我来说是无价的,为我现在的抱负奠定了基础。但是,这就足以让你在这个行业真正就业吗?
一点也不。
像训练营、MOOC、视频教程等在线学习资源的本质是,它们被推销为“自学编码”。正如他们所说,这正是你投入时间和金钱的地方。你学习编码,而不是以非常具体的方式或风格理解为什么编码。
这本身就产生了一个问题;
学习上述课程的学生希望这足以在现实生活中找到一份工作。但如果是这样的话,仅参加 Udemy 课程的 300 多万学生就足以填补该行业的 ML 职位空缺。
因此,很明显,MOOC 或其他自定进度的在线课程不会帮你切断线索。
原因如下。
机器学习教育资源大众化的陷阱
一般来说,机器学习或数据科学领域主要由院士主导。由于某些学者愿意为社区贡献他们的知识,这种趋势似乎正在逐渐变好。
个人的这种慈善方式使全球成千上万的个人能够在这一领域寻找就业机会。此外,我们还可以看到该领域发展的速度有多快,因为他们决定与世界其他地方分享他们的知识。
简而言之,民主化对整个社区都有好处。
但是“让数据科学民主化&机器学习”无论如何现在都是一个热门话题。每个人都想为社区创建一两个教程。你可能会想,为什么我会特别指出来呢?
因为我不想让社区被误导。
为了重申这句话,让我给你一个另一位作家 Rahul Agarwal 描述的真实事件的例子。
Rahul Agarwal 在他的文章— 不要让数据科学 民主化,陈述了一个面试的例子,其中候选人是有经验的&可能也是自学的。[2]
引用他的文章;
“……他很好地解释了更高层次的概念,我决定更深入地挖掘他对他在项目中应用的技术的数学理解。这就是事情发生变化的地方……”
他对采访的描述是一个典型的例子,说明一个人仅仅依靠浏览教程,一个接一个地创建项目&建立一个可靠的投资组合。可以说,仅仅学习如何编写代码是不够的。
我们能从这个背景中学到什么?
你可能是一名全明星程序员,但如果你不能理解基本的基本概念,你就不会进步到足以被雇用的程度。
为什么会这样呢?
你知道,大多数企业经常以小本经营。此外,生产环境是不稳定的,不仅易受市场竞争的影响,也易受消费者的突发奇想的影响。这使得企业处于不利地位&被迫关注产品中最微小的细节。
从加快数据管道到在几毫秒内做出推论,这可能是一个获取巨额利润或破产的问题。拉胡尔试图通过他的文章传达的就是拥有如此精确的鹰眼。
但你不必总是有一双鹰眼
与 Rahul 的观点相反,机器学习领域的另一位专家&企业家是 Caleb Kaiser。他提倡将 ML 软件提供给那些迫切需要它的人,尤其是那些不是数据科学家的开发者。他的文章— 深度学习不再难 是一篇关于生产能力 ML 软件领域的精彩报告。
在这篇文章的上下文中,引用了他文章的一段摘录;
“……社区内的人们开发库和项目,抽象出公共的实用程序,直到工具能够足够稳定地用于生产。
在这个阶段,使用它来构建软件的工程师不关心发送 HTTP 请求或连接到数据库——所有这些都被抽象掉了——而只专注于构建他们的产品。"[3]
这里的关键词——“所有这些都被抽象掉了”。
现在,作为一名企业家,他不仅有义务向他的员工,也有义务向他的财务支持者解释产品。他认为,试图找出产品内部运作的基本概念可能是浪费时间。此外,考虑到他在公司的职位,他花时间学习与业务无关的新东西对公司来说是金钱损失。相反,他可以雇佣其他人,一个这方面的专家来做这件事。
我的观点是,如果你缺乏机器学习的基本概念的知识也没关系,如果你的优先事项是,比如说经营一家公司。但是如果你想找一份机器学习专家的工作,那么你必须做你应该做的事情。
AutoML 不是邪恶的天才,准备夺走你的工作
我真的不明白反对自动化背后的逻辑。当工作可以自动化时,为什么要弄脏自己的手呢?自动化不仅高效,还能为你节省时间去做其他事情!不管怎样,我想抗议自动化的历史可以追溯到人类刚刚开始创新技术的时候。
仔细阅读由一个名为勒德分子的组织发起的新勒德主义运动。见鬼,我们在经济学中也用一个术语来指代对技术失业的恐惧,这种恐惧被称为勒德谬误。
更多地谈论卢德主义就脱离了文章的内容,所以这是另外一个话题。
不管怎样,让我再一次把你的注意力引向 Rahul 的文章,这里有一些我不能同意的他提到的东西。
“……此类软件包的可用性让许多人认为数据科学可以完全自动化,从而完全消除对数据科学家的需求。或者,如果流程不能自动化,这些工具将允许任何人成为数据科学家。”[1]
我相信他担心像 MindsDB 这样完全没有根据的 AutoML 软件的出现。
MindsDB 是一款令人惊叹的开源 AutoML 软件,请查看它们。
在桑德尔·皮帅向全球观众宣布谷歌的新发明后,出现了任何人都可以使用 AutoML 软件创建神经网络的误解。在他的推介中,他表示 AutoML 将使我们的社区能够创建和设计神经网络,这在以前是只有少数拥有博士学位的人才拥有的技能
我引用他的话。
今天,设计神经网络是非常耗时的,并且需要专业知识,这限制了它在较小的科学家和工程师群体中的使用。这就是为什么我们创造了一种叫做 AutoML 的方法,表明神经网络设计神经网络是可能的。我们希望 AutoML 将利用今天一些博士拥有的能力,并在三到五年内使成千上万的开发人员为他们的特殊需求设计新的神经网络成为可能。【5】
你读过他在哪里提到 AutoML 是为开发者准备的吗?明白这意味着什么。
打个比方,假设我拥有一家公司&我们的应用程序可以使用生成对抗网络(GANs) 让你的照片看起来更老。有一个职位可以进一步开发我的应用程序。我可以雇佣一个拥有博士学位或者有经验的软件开发人员。当然,拥有博士学位的人会更好地理解 GAN 到底是如何工作的。虽然开发者更喜欢使用像 Keras 这样的框架来抽象构建 GAN &更关注于完善应用程序的工作方式。
如果我想让我的公司持续盈利,我应该雇佣一个有博士学位的人还是一个开发人员?
毫无疑问,考虑到我所受到的限制,我会把赌注压在开发者身上,让他按时交付给我一个可生产的产品。
抛开个人观点,技术上的抽象是不可避免的。在某个时间点,重复的任务,如数据扩充、数据清理等需要进行抽象,以节省开发人员的时间。
最后,结束
数据科学& ML 的领域极其广泛,即使在其子领域内也有特定的需求!一个人不可能在一生中成为真正的数据科学大师。但幸运的是,在数据科学领域成为一名万事通&而非大师也是一件好事。你只需要在正确的情况下运用正确的技能。
我们生活在一个惊人的时间点上。
毫无疑问,人工智能和人工智能领域的进步有时是势不可挡的。我们很多人都渴望从经济上充分利用这个机会。你可能对一份全职工作很满意,而你的朋友可能想开始自己的 ML 事业。正如我之前提到的,你的每一种方法肯定是不同的。
所以,知道你未来想做什么&为你的理想找到正确的方法。
此外,我们应该时常提醒自己,这种快节奏的发展给我们作为一个社区带来了好处。变化是好的,我们只需要知道如何根据不断变化的技术环境塑造自己。
参考文献:
[1] Imarticus Nirmal,关于机器学习的 10 个常见误解,数据科学协会(2018)
[2] Rahul Agarwal ,不要让数据科学民主化,走向数据科学 (2020)
[3] Caleb Kaiser ,深度学习不再困难,走向数据科学 (2020)
卢德派的领袖。手绘蚀刻,勒德—维基百科 (1812)
[5]雷切尔·托马斯,谷歌的 AutoML:打破炒作, fast.ai (2018)
揭示网络中的重要节点
揭示数据中隐藏层次的概率方法
编剧基尔弗·j·坎波斯,尼古拉斯·波扎·莫雷诺,亚历杭德罗·阿尔瓦雷斯,托马斯·维拉。
图数据库(或网络数据集)中最重要节点的检测是各种科学学科,尤其是数据科学中广泛关注的问题。近年来,由于现代计算机存储和计算能力的进步[1],以及 21 世纪初网络理论的爆炸式繁荣[2,3,4],其相关性一直在增加。
基本上,可以通过一组节点或实体以及一组描述这些实体之间如何交互或相关的链接来描述的任何数据集。这些类型的系统(或数据库)的一些例子是:
- 社交网络:人们用节点来表示,链接表示他们之间不同的社会联系(友谊、合作、共同爱好等)。).这些类型的网络出现在科技产品中,如脸书、推特、LinkedIn、Instagram、抖音等。在后者中,最重要的节点与高影响力的人“影响者”相关,这些人对现代营销部门越来越感兴趣[5]。
- 生物有机体:有机体的代谢可以用网络(代谢组学)来表示,其中的节点是生物分子(代谢物或酶),如果代谢物是酶介导的酶促反应的离析物或产物,则代谢物与酶相连。我们还可以通过蛋白质相互作用网络(蛋白质组学)将生物体内物理相互作用的所有蛋白质联系起来。最重要的节点与可能的药物靶标相关,这对于新治疗方法的设计非常重要,例如在寄生虫病中[6]。
- 运输网络:在这个场景中,节点代表地理位置(城市、机场、港口等。)并且如果存在连接两个节点的路由,则这两个节点是连接的。例如,在机场网络的情况下,如果从一个机场到另一个机场有直飞航班,则两个机场是连接的。最重要的节点/机场与大多数人流动通过的机场有关,如果我们假设标准的商业航班,因此避免或最大限度地减少流行病的传播,在这样的机场放置控制点和疫苗接种活动是非常重要的[7]。
- 计算机和物联网设备网络:这里的节点由物联网生态系统的所有设备(智能手机、基于 Arduino 的传感器、树莓、平板电脑、智能设备、计算机等)组成。)并且连接可以是有线的和/或抽象的,例如 wifi、3G、4G、5G、蓝牙等。
- 地震活动和气候:网络的多功能性也通过表现时间性质的数据来显示,如地震活动或气候,按时间来衡量。在这种情况下,节点是地理区域,如果两个节点之间存在高度的相关性或因果关系,则这两个节点是连接的[8]。
- 在线商店:我们可以将电子商店的产品表示为一个网络,在这个网络中,如果两个产品都是由同一个用户搜索或购买的,那么这两个产品就是相连的。另一种联系是由这些产品之间的关系(元数据)提供的。例如,网球拍和袜子可以共享属性:运动、户外、爱好。因此,球拍和袜子可以连接,但球拍和床不能连接。
- 互联网:在这种情况下,路由器是节点,链路是允许它们通信的有线或无线连接[9]。
- WWW(或万维网):允许我们通过节点来描述网页的世界,并且如果有从一个网页到另一个网页的超链接,这些网页中的两个是连接的。在这种情况下,WWW 是一个有向网络(因为它可能是从 A 页到 B 页的超链接,但不一定是从 B 到 A)。如果大量页面“指向”一个网页,我们可以说这个网页是相关的。网页的相关性或重要性的概念被用于像 Google 这样的搜索引擎的设计中。
前面所有的例子都允许我们从不同的角度来看数据,例如,作为组成系统(数据集)的元素之间的交互图。因此,使我们能够利用现有的数据挖掘和人工智能工具来揭示层次结构、模式、漏洞、重要元素等。这对于由记录列表组成的传统数据库模式来说是极其困难的。
具体来说,网络分析能为我们提供什么?
我们通过一个例子来回答这个问题。让我们想象一下,我们正试图在货物运输领域创建一家初创公司,例如像联邦快递、DHL、UPS 这样的企业。降低成本同样重要,对宏观公司和初创公司都是如此。我们需要问的第一个问题是主仓库放在哪里?尽管这个问题起源于被称为运筹学的数学学科。另一方面,网络理论允许我们从新的角度来处理这个问题,例如,通过计算中心性指数。特别是,计算在统计上最接近网络中任何点的节点(或站点)(紧密度中心性指数),或更容易从任何起点流向任何目的地的节点(或站点)(中间中心性指数)。这是寻找最中心的节点对一个公司有价值的几个例子之一。
“在下面的论文中,我们将感兴趣的是检测最重要的、相关的、有影响的或中心的节点。”
根据所研究的系统,重要性、相关性或影响的概念可能会有所不同。然而,对于大多数系统来说,一个重要的节点是
- 最连通(度中心性[10])。
- 最接近其余节点(接近中心性[11])。
- 通过它传递更多的信息(中间中心性[12])。
- 一个连接到其他重要节点(特征向量中心性[13])。
- 在许多其他人当中[14]。
这里我们将对基于信息流的方法感兴趣。
典型地,出租车司机不通过最短路线从 A 点到 B 点,因为城市交通网络中两点之间的最短路径可能遭受瓶颈效应(即可能饱和)。相反,出租车司机会选择比最短路线更省时的路线。同样的情况也发生在信息环境中,信息并不总是以最短的路径传播。因此,传统的中介度量(中间性)并没有利用网络中两点之间存在的路径多样性所提供的所有信息。
受 Mark Newman 的论文[15]的启发,下面我们从一个更简单的方法来探索他的方法,即通过吸收性均匀随机行走对网络中的信息包流进行建模。我们在下文中将这种方法称为纽曼方法。
随机漫步的方法论
我们从以下启发性的原则开始。信息网络中最相关的节点通过信息包与最常访问的节点相关,即大多数信息通过的那些节点。为了进一步阐明这个想法,想象从灰色节点集合开始的三次随机行走。为了到达蓝色节点,它们必须不可避免地经过红色和绿色节点,这样后者将比其他节点拥有更多的信息流。
图 1 两组节点(灰色和蓝色)之间的随机游走。
数学上,我们可以通过其转移矩阵 P_ij 描述随机游走,由下式给出:
等式 1
其中,邻接矩阵 A 是图的代数表示,如果节点 I 和 j 相连,则其输入 A_ij 等于 1,否则为 0(见图)
图 2 图或网络及其邻接矩阵。
k_i 是一个节点拥有的连接数。它被称为节点的度。例如,在图 2 中,节点 A 具有度 2,而节点 B 具有度 3。
对比结果
表 1 显示了应用于维克多·雨果的小说《悲惨世界》中的人物之间的同现网络的不同方法之间的比较[10]。根据每个度量显示前 10 个最重要的字符。应当指出,几乎所有的措施都把主角“冉阿让”以及反面角色沙威视为最重要的因素。顶部的其他主要人物是伽弗洛什和马吕斯。只有亲近也包括珂赛特在内。
表 1。不同中心性度量的比较分析
请注意,排名与小说的主要人物非常一致,即使只考虑了互动(没有权重),忽略了其频率。
随机漫步中间方法的实现
我们首先引入实现基于随机行走的纽曼方法所必需的一组库。
使用的 Python 包
(i) Networkx 能够通过适当的方法进行图形处理和基本分析。
(ii) Numpy 为我们提供了一套代数运算的工具。
(iii) Matplotlib 用于可视化结果。
我们还实现了一个函数来读取 sif 文件(简单交互文件)
这个函数允许我们读取 sif 格式的数据集,并构建一个 networkx 图。然后,使用nx.to_numpy_matrix(G)
我们创建其相应的邻接矩阵。
“转移”函数允许我们计算从节点 I 到节点 j 的概率。注意,这与等式(1)中的写法相同。然后,我们通过使图上的随机行走进化更大数量的步骤来模拟网络中的信息流。这是通过允许 walker 根据其转移概率从一个节点移动到一个邻居节点来实现的。
对于随机行走执行的每一步,我们将访问过的节点存储在一个名为 Orbit 的列表中。然后,我们计算随机漫步在图 G 的每个节点 I 上的访问频率,以这种方式获得每个节点的中心性。为了可视化的目的,我们从一个特定的色标中心值。
使用 nx.draw 函数绘制网络,使用 Kamada Kawai 布局计算节点的位置,这提供了网络的良好表示。色标用红色调表示最中心的节点,用蓝色调表示最不中心和最外围的节点。
最后,下面的代码块旨在导出使用该方法获得的排名的前 10 名,并将其存储在 pandas 数据帧中,以供表 1 中所示的后续分析和比较。
将中心性值标准化,并设计条形图来比较这里研究的每个中心性测量的重要性的规模和分布。
各种数据集中的应用
悲惨世界网络图。
冉阿让突出显示为最中心的节点,以红色显示。接下来,我们将看到从所研究的不同方法获得的图,其轴是所涉及的节点及其在网络中相对于从轨道列表的 H 直方图获得的密度的影响或中心性(从 0 到 1)。由节点除以轨道的最大值产生。
特征向量中心性:认为伽弗洛什是最有影响力的节点,其次是冉阿让。
度中心性:冉阿让被认为是网络中最有影响力的节点,其次是伽弗洛什。比预期的要近。
接近中心性:显示冉阿让为最中心节点,然后显示随后的 4 个形成具有大致相同重要性值的平台。沙威(与冉阿让对立的人物)、马吕斯和伽弗洛什脱颖而出。
中间中心性:它将冉阿让显示为最有影响力的节点,并且由于其试探法中使用的测地线概念的限制性,以下中心性值与冉阿让相比呈现相当低的值。
纽曼基于随机游走的中心性:给我们一个与小说中最有代表性的人物很符合的排名:冉阿让、伽弗洛什、马吕斯、沙威。包括更多的信息,例如转移矩阵中的共现频率,肯定会改善这个结果。
文艺复兴时期的佛罗伦萨家族网络。
这个网络取自帕吉特等人的作品,并根据描述不同家庭间婚姻网络的历史文献构建而成。从[17,18]我们有证据表明,美第奇家族是 15 世纪佛罗伦萨最强大的。
扎卡里空手道俱乐部网
这个网络取自 Wayne Zachary 关于小型社会团体裂变的研究[19]。节点是大学空手道俱乐部的成员,它们之间的链接表示它们之间在俱乐部之外的社交互动。扎卡里的工作表明,最重要的节点是 33,32,和 0,分别是俱乐部的主席,副主席,和唤醒。了解了这一点,我们注意到,通过应用纽曼的算法,发现俱乐部主席和老师是这个网络中最有影响力的节点。
结论
- 在基于随机游走的网络型数据库中实现了一种重要节点分析方法。
- 在几个测试网络中,其性能与文献中报道的其他中心性方法进行了比较,在这些测试网络中,存在关于节点的层次或重要性的部分或全部信息,显示纽曼方法具有更好的结果。
- 鉴于其性质,它可以并行化,采取许多轨道,而不是只有一个。
- 更实际的方法是考虑转移矩阵的渐近分析(稳态),这相当于进行无限长的随机行走。然而,关于暂时统计状态的信息却丢失了,而这些信息是人们非常感兴趣的。
代码
所有代码都可以在存储库中找到:
【https://github.com/vtomasv/uiNin
参考文献。
- Grochowski,EG,Hoyt,RF & Heath,JS 磁硬盘驱动器外形尺寸演变。IEEE 磁学汇刊 29,4065–4067(1993)。
- A.博纳博·巴拉巴斯(2003 年)。“无标度网络”。科学美国人:50–59。
- 施·斯特罗加兹,DJ·瓦茨(1998 年)。“小世界网络的集体动力”。大自然。393 (6684): 440–442.
- Amaral,LAN,Scala,a .,Barthélémy,M. & Stanley,何类小世界网络。美国国家科学院学报 97,11149–11152(2000)。
- https://medium . com/swlh/what-is-influencer-marketing-the-complete-guide-2ef 95 a 6 EB 4a 3
- Herrera-Almarza G .,等从网络理论的角度看大肠杆菌蛋白质相互作用网络中必需基因的性质,科学与工程计算方法杂志 17 (1),209–216(2017)。
- 复杂网络中的流行病过程。现代物理学评论 87,(2015)。
- Yook,SH,Jeong,h .和 Barabási,AL 模拟互联网的大规模拓扑结构。美国国家科学院院刊 99 ,13382–13386(2002)。
- Bottinelli,a .,Perna,a .,Ward,A. & Sumpter,2012 年欧洲复杂系统会议录。2012 年欧洲复杂系统会议论文集 591–606(2013)。doi:10.1007/978–3–319–00395–5
- 社会网络分析方法与应用。(剑桥大学出版社,1944 年)。
- 图的中心性指数。心理测量学。31, 4, 581–603 (1996).
- 一个更快的中间中心性算法。今天。数学。搭档。25, 163–177 (2001).
- 《权力与中心性:一系列衡量标准》。我是。你好。社会主义者 92, 1170 (1987).
- 复杂网络中的重要节点识别。物理报告 650,1–63(2016). 650,
- 纽曼,MEJ (2005)。“基于随机游走的中介中心性的度量”。社交网络 27:39–54。
- 斯坦福图表库:组合计算的平台。(艾迪生-卫斯理,雷丁,马,1993)。
- 帕吉特、JF 和安塞尔、CK《强力行动和美第奇家族的崛起,1400-1434》。我是。你好。社会主义者 98, 1259 (1993).
- 社会和经济网络。(普林斯顿大学出版社,2010 年)。
- Zachary WW --小团体中冲突和分裂的信息流模型。你好。安东尼。第 33,452-473 号决议(1977 年)。
在一个文件夹中解压缩、更新和再压缩 XML
使用 python 自动化办公程序
作者图片
日常办公中,经常要带着一堆文件做一些事情。解压,移动,重命名,更新,再次压缩,发送或加载到 FTP。所有这些事情做起来都很简单,但是非常耗时,你必须手动地在数十或数百个文件上重复它们。
幸运的是,您可以使用编程语言来自动化这些重复的任务。Python 是一个理想的选择,因为它很容易在计算机上安装,几乎不用试错,即使是计算机新手也能创建程序。Python 是一种通用的编程语言,基本上你可以用它解决任何问题。
让我们来探讨一个在许多行业中相当常见的任务。我们将:
- 解压缩一组文件
- 更新它们的内容—在我们的示例中,我们将更改 XML 节点的内容
- 使用
zipfile
和shutil
库再次压缩结果
你可以在 github 笔记本-Unzip _ Update _ Zip _ full . ipynb中跟进这个练习。
安装 Python
在 Jupyter 笔记本中执行的示例 python 代码
有几种方法可以在你的电脑上设置 python。我个人很喜欢使用 Anaconda 和 Jupyter 笔记本。您下载并安装 conda 包,该包旨在通过所有可能的增强使 python 环境易于管理,并运行笔记本,这是包的重要部分。
在笔记本中,您可以运行包含一行或多行代码的单独单元格,并立即看到结果。这种方法非常适合原型开发。在 google、 stackoverflow、和教程的帮助下,例如在 medium 上,你可以快速组合你需要做的事情所需的代码片段。
解压缩
让我们探索一下如何在 python 中处理解压文件的任务。只要去谷歌输入“解压 python”就可以了。它会快速列出结果,你可以选择,比如说最大的编码问答网站之一——stack overflow 的 Python 解压文件。在 3 行代码中,您将了解如何做到这一点:
import zipfile
with zipfile.ZipFile(path_to_zip_file, 'r') as zip_ref:
zip_ref.extractall(directory_to_extract_to)
你在import
图书馆工作所需的.zip
文件— zipfile
。这允许您使用它的函数和方法来解包归档文件并再次压缩它们。
首先,使用zipfile.ZipFile(path_to_zip_file, 'r')
打开归档文件进行读取,然后将包的内容提取到目录zip_ref.extractall(directory_to_extract_to)
中。
我使用了with
符号来确保打开归档文件,执行一个操作,然后关闭归档文件,以便从内存中释放其内容。它可以防止在处理成百上千个文件时出现内存泄漏。
解压缩包含许多文件的文件夹
在 python 中解压缩一个文件需要使用三行代码。要解压缩一堆文件,您只需再添加几行。您必须识别文件夹中的 zip 文件,并将它们传递给我们上面描述的过程。
os
库让你既可以获得文件夹os.listdir()
的内容,又可以使用os.path.join(folder,file)
将文件夹和文件名组合起来。Listdir 返回文件和子文件夹。您可以添加file.endswith(".zip")
来仅识别档案。
或者你可以使用
os.path.splitext()
。它的第二个输出是文件扩展名。
知道了文件夹中的所有文件,就可以应用前面的代码来解压缩它们。同样,您可以遍历文件并解压缩每个文件,或者将解压缩打包到一个函数中,该函数在一行综合符号中调用。
def unzip(folder: str, file: str, folder_to_extract: str) -> list:
"""unzips a file in a folder into folder_to_extract
returns a list of files in the zip archive"""
with zipfile.ZipFile(os.path.join(folder,file), 'r') as zip_ref:
zip_ref.extractall(folder_to_extract)
return zip_ref.namelist()# applying a function to the output can be squeezed into the list comprehension
[unzip(folder, f, "temp") for f in os.listdir(folder) if f.endswith(".zip")]
更新提取的 XML
一旦我们将 XML 提取到temp
文件夹中,我们就可以使用它了。Python 包含 xml.etree 库来处理 xml 文件。在我们的例子中,我们知道 zip 存档包含一个 XML 文件a.xml
,尽管您可以使用zip_ref.namelist()
列出存档中的所有文件。
要更新 XML 文件,您必须导入树库并加载 XML 文档。
from xml.etree import ElementTree as ET# parse the XML document into a variable
tree = ET.parse(path)# get the root emelement containing all the XML nodes
root = tree.getroot()
请记住,从
tree
派生的任何变量都是一个引用。当您更新这些变量的内容时,您也更新了tree
。
假设我们想要更新 XML 中的<id>...</id>
节点。我们必须首先找到它。etree 库中有几种定位 XML 节点的方法。
.find()
找到 XML 元素的第一次出现.findall()
列出子元素的所有外观
这两种方法都接受元素的名称,或者您可以使用xpath
找到它。Xpath 是一种在 XML 中定位所需元素的地址。一旦找到使用的节点,就用.text
参数来获取写在标签之间的值。
# in the <data> find the <id>...</id> node and show its content (.text)
id = root.find("id").text
我们的 Id 由下划线“_”分隔成三部分:
- 前缀
- 版本
- 日期
其中一个 XML 的 id 是test_001_20201026
。.text
返回字符串形式的值,您可以应用.split("_")
函数将文本分解成细节。
[In]:
split_id = id.split("_")
print(split_id)[Out]: ["test","001","20201026"]
输出是一个 python 列表,可以很容易地按元素更新。首先我们改变前缀split_id[0] = new_prefix
。然后我们更新版本。
split_id[0] = new_prefix
split_id[1] = "{:03d}".format(new_version)
如果需要将1
转换为001
,我们已经使用"{:03d}".format(new_version)
添加了最多 3 个字符的前导零。
更新的值可以通过.join("_")
组合成一个字符串,原始的 XML 组件可以用它来更新:
root.find("id").text = "_".join(split_id)
正如我提到的,对从tree
派生的变量的任何更新也会更新tree
。我们已经实现了我们想要的 XML 更新,我们只需要使用tree.write(output_path)
将其导出。
让我们看看 XML 更新的完整代码:
压缩更新的 XML
现在更新后的a.xml
位于temp
文件夹中。我们只需要压缩它,并将这个归档文件放到processed
文件夹中。让我们首先创建输出文件夹,如果它不存在的话。我们将使用pathlib
库中的Path
。
# create the output folder if it doesn't exists
Path(output_folder).mkdir(parents=True, exist_ok=True)
然后,我们使用zipfile
lib 将 XML 打包到 zip 存档中。现在我们必须打开归档文件进行写入'w'
。然后我们使用这个档案和.write(path_to_file, name_of_this_file)
的引用。
如果不指定第二个参数
name_of_the_zipped_file
,那么包括文件夹和子文件夹在内的整个路径都会被压缩。
如果你不知道文件名,os
库可以用它的os.path.basename()
功能帮你。
with zipfile.ZipFile(output_path, 'w') as myzip:
myzip.write(path_to_processed_xml, os.path.basename(path_to_processed_xml))
压缩时,指定压缩文件的名称,以避免压缩包含的文件夹。作者图片
尽管有时你也需要打包文件夹和文件。在我们的例子中Folder_001_20201101.zip
包含一个文件和另一个文件夹中的文件。
- folder_A/a.xml
- efg.txt
在这种情况下,使用 zipfile 会有点太完整,但是在[shutil.make_archive](https://docs.python.org/3/library/shutil.html)(output_folder, format, folder_to_pack)
中有一个替代方法。这个方法只将folder_to_pack
的内容存档,并将结果放在output_folder
中。您可以选择zip
、tar
、gztar
、bztar
、xztar
格式。
把它们放在一起
现在我们知道了该过程的所有组成部分:
- 将一个文件夹中的多个归档文件解压缩到一个临时文件夹中
- 更新了每个解压后的文件
- 并将更新后的文件再次压缩到归档文件中
在这个最后的练习中,我们必须做一些小小的调整。我们将使用原始存档的名称,更新它,同时更新所有包含的 XML 的内容。原因是归档中可能有两个或更多的 XML,每个都有不同的 id,我们将它们全部压缩回更新的 zip 归档(不能有两个不同的名称)。
完整的代码,可以在这个笔记本中找到—Unzip _ Update _ Zip _ full . ipynb
结论
在这个简单的教程中,您已经看到了 python(或任何其他编程语言)的威力。在几行代码中,您可以自动执行任务,如果手动执行,将会花费大量时间。当决定是否值得花时间编码时,我使用这个原则:
如果你做一次小事情,手动做。如果它很大,你在许多项目上重复同样的操作,或者你认为你将来不得不这样做——用编程语言自动化。
这个例子中的操作可以有许多变化。您可能希望更新不同的 XML 节点。zip 可能包含 CSV 文件。您宁愿更新日期,而不是前缀和版本。您可能需要修改输入—例如,将版本增加 1 或在日期上添加一周。
只要对代码稍加修改,所有这些都是可能的。您也可以在 Github上的 jupyter 笔记本中查看完整的示例。
我希望你喜欢这篇关于压缩和 XML 处理的教程,也希望你喜欢用 python 可以实现的东西。可能性是无限的。
Other articles:* [Plotly Express complete tutorial](/visualization-with-plotly-express-comprehensive-guide-eb5ee4b50b57)
* [Very illustrative highlighted line chart](/highlighted-line-chart-with-plotly-express-e69e2a27fea8)
* [Plotly Histogram - Complete Guide](/histograms-with-plotly-express-complete-guide-d483656c5ad7)
* [Everything you wanted to know about Kfold train-test split](/complete-guide-to-pythons-cross-validation-with-examples-a9676b5cac12)
* [How to turn a list of addreses into a map](/pythons-geocoding-convert-a-list-of-addresses-into-a-map-f522ef513fd6)
与 Milvus 一起运行
向量相似性搜索引擎。构建推荐并搜索图像/视频、音频或非结构化文本。
马库斯·温克勒在 Unsplash 上的照片
什么是 Milvus?
一个矢量相似性搜索引擎,看起来已经可以生产了。据网站:
- 它提供了多种相似性度量和索引类型。
- 水平缩放。
- 读写几乎是实时进行的,这意味着我们可以在引擎在线时插入记录。
- 公开一个 REST 接口。
听起来很酷!
对于那些还不知道的人来说,像这样的技术有很多用例。在机器学习的帮助下,我们可以搜索图像、视频和音频。
假设我们训练了一个对图像进行分类的 CNN。如果我们在最终输出之前查看任何层的输出,我们可能会发现描述输入的 N 维特征向量。随着我们在网络中移动,这些特征变得更加具体。开始时,我们可以识别纹理、形状等。接近尾声时,我们辨认出像猫耳朵和狗尾巴这样的物体。我们可以获取这些层的输出,通过某种方法将其展平,并在搜索引擎中对其进行索引!瞧啊。所选择的层将对什么被认为是“相似的”产生影响。这将因使用情形而异。这个例子是基于内容的图像检索(CBIR)的一个应用。
我们在建造什么?
一个非常简单的在 Dockerized 环境中使用 Milvus 的 CBIR 实现。这是完整的回购协议和我们将使用的技术列表。如果你想下载回购,只是乱搞,它已经准备好了。
在 GitHub 上创建一个帐户,为 dshvimer/milvus 的启动和运行开发做出贡献。
github.com](https://github.com/dshvimer/milvus-up-and-running)
- python——因为
- Docker —这样每个人都有一个标准的环境
- py torch——因为我总是跳 Keras,想学点新东西。
- Jupyter 笔记本—与 Milvus 互动的简单方式
设置项目
在一个新的目录中,让我们创建更多的空目录。
-project
-notebook
-milvus
-conf
在顶层目录中,创建一个名为docker-compose.yml
的文件,内容如下:
version: '2.0'
services:
notebook:
build:
context: ./notebook
ports:
- '8888:8888'
volumes:
- ./notebook:/home/jovyan
links:
- milvus
milvus:
image: milvusdb/milvus:0.9.1-cpu-d052920-e04ed5
ports:
- '19530:19530'
- '19121:19121'
volumes:
- ./milvus/db:/var/lib/milvus/db
- ./milvus/conf:/var/lib/milvus/conf
- ./milvus/logs:/var/lib/milvus/logs
- ./milvus/wal:/var/lib/milvus/wal
我们定义了两个 docker 容器,一个用于 Milvus,另一个用于 jupyter 笔记本。Milvus 容器通过links
属性对笔记本可见。我们声明的卷是为了让 Milvus 文件系统与我们的操作系统共享一些文件夹。这让我们可以轻松地配置和监控 Milvus。因为我们给了笔记本容器一个上下文来构建,所以我们需要在notebook
目录中创建一个名为Dockerfile
的文件,其内容如下:
FROM jupyter/scipy-notebookRUN pip install pymilvus==0.2.12RUN conda install --quiet --yes pytorch torchvision -c pytorch
这不是声明依赖关系的最佳方式,但可以在以后进行优化。我们还应该下载一些图片来玩。随意下载我用的这里的:把它们放入notebook/images
。
最后一步,下载启动器 Milvus 配置文件并放入milvus/conf/
中。现在只要 Docker 安装并运行,我们运行docker-compose up
,我们就活了!
如果您在控制台输出中看到以下行:
milvus_1 | Milvus server exit...milvus_1 | Config check fail: Invalid cpu cache capacity: 1\. Possible reason: sum of cache_config.cpu_cache_capacity and cache_config.insert_buffer_size exceeds system memory.milvus_1 | ERROR: Milvus server fail to load config file
这意味着 Docker 没有足够的内存来运行 Milvus。如果我们打开配置文件并搜索“cpu_cache_capacity ”,我们会看到一些有用的文档。"T11'插入缓冲区大小'和' cpu 缓存容量'之和必须小于系统内存大小。"
将两个值都设置为 1,然后打开 Docker 的设置,确保将其配置为任何大于 2GB 的值(必须大于)。确保应用设置并重启 Docker。然后再试试docker-compose up
。如果有其他问题,请在评论中告诉我。
PyTorch 特征向量
有趣的东西,开始了。一旦一切都运行了,我们应该有一个 URL 来访问我们的 jupyter 实例。让我们创建一个新的笔记本并开始编码。一次一个细胞。
首先是进口:
import torch
import torch.nn as nn
import torchvision.models as models
import torchvision.transforms as transforms
from torch.autograd import Variable
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
现在让我们定义一个助手类来提取特征向量:
我为什么选 ResNet18?因为它有一个输出长度为 512 的平面向量的层。学习新事物时,方便和容易是合理的。这个类有很大的扩展空间。我们可以一次从多个层提取特征,并一次输入多个图像。就目前而言,这已经足够好了。
现在,我们可以加载我们的图像,并开始查看相似性:
feat_vec = FeatureVector()
dog1 = Image.open('./images/dog1.jpg')
dog2 = Image.open('./images/dog2.jpg')
dog3 = Image.open('./images/dog3.jpg')
cat1 = Image.open('./images/cat1.jpg')
cat2 = Image.open('./images/cat2.jpg')
person1 = Image.open('./images/person1.jpg')
person2 = Image.open('./images/person2.jpg')def compare(a, b):
plt.figure()
plt.subplot(1, 2, 1)
plt.imshow(a)
plt.subplot(1, 2, 2)
plt.imshow(b)
a_v = feat_vec.get_vector(a)
b_v = feat_vec.get_vector(b)
print('Similarity: {}'.format(feat_vec.similarity(a_v, b_v)))compare(dog1, dog2)
在第一个例子中,小狗和成年金毛猎犬图像的相似性得分约为 0.79。当我们比较一只小狗金毛寻回犬和一只哈巴狗时,我们得到的相似性分数约为 0.58。
使用 Milvus:连接、插入、查询
让我们做我们来这里要做的事。我们从连接 Milvus 开始,创建一个集合
from milvus import Milvus, IndexType, MetricType, Status# Milvus server IP address and port.
# Because the link to milvus in docker-compose
# was named `milvus`, thats what the hostname will be
_HOST = 'milvus'
_PORT = '19530' # default value# Vector parameters
_DIM = 512 # dimension of vector_INDEX_FILE_SIZE = 32 # max file size of stored indexmilvus = Milvus(_HOST, _PORT, pool_size=10)# Create collection demo_collection if it dosen't exist.
collection_name = 'resnet18_simple'status, ok = milvus.has_collection(collection_name)
if not ok:
param = {
'collection_name': collection_name,
'dimension': _DIM,
'index_file_size': _INDEX_FILE_SIZE, # optional
'metric_type': MetricType.L2 # optional
}print(milvus.create_collection(param))# Milvus expo
_, collection = milvus.get_collection_info(collection_name)
print(collection)
现在我们可以插入图像的特征向量。我们需要将向量转换成 python 列表:
images = [
dog1,
dog2,
dog3,
cat1,
cat2,
person1,
person2
]# 10000 vectors with 128 dimension
# element per dimension is float32 type
# vectors should be a 2-D array
vectors = [feat_vec.get_vector(i).tolist() for i in images]# Insert vectors into demo_collection, return status and vectors id list
status, ids = milvus.insert(collection_name=collection_name, records=vectors)
if not status.OK():
print("Insert failed: {}".format(status))
else: print(ids)
如果成功了,我们应该会看到 Milvus 用来识别图像的 ID 列表。它们的顺序与我们的图像列表相同,因此让我们创建一个快速查找表,以便在给定一些 ID 的情况下轻松访问图像:
lookup = {}
for ID, img in zip(ids, images):
lookup[ID] = imgfor k in lookup:
print(k, lookup[k])
我们可以将新项目刷新到磁盘上,并为收藏获取一些信息:
# Flush collection inserted data to disk.
milvus.flush([collection_name])# Get demo_collection row count
status, result = milvus.count_entities(collection_name)
print(result)
# present collection statistics info
_, info = milvus.get_collection_stats(collection_name)
print(info)
让我们搜索!
# execute vector similarity search
search_param = {
"nprobe": 16
}print("Searching ... ")param = {
'collection_name': collection_name,
'query_records': [vectors[0]],
'top_k': 10,
'params': search_param,
}status, results = milvus.search(**param)
if status.OK():
print(results)
else:
print("Search failed. ", status)
如果我们看到结果列表,这意味着一切都很好。我们可以用下面的代码片段将它们可视化
for neighbors in results:
for n in neighbors:
plt.figure()
plt.subplot(1, 2, 1)
plt.imshow(images[0])
plt.subplot(1, 2, 2)
plt.imshow(lookup[n.id])
print('Distance: {}'.format(n.distance))
要删除收藏:
milvus.drop_collection(collection_name)
结论
启动并运行起来非常容易。这里大部分与 Milvus 相关的代码来自网站上的入门示例。我们的一个向量大小约为 1KB,因此我们可以将一百万个特征向量放入 1GB 的内存中。我们在这里没有使用索引,这会增加成本,但这仍然是一种非常有效的图像索引方式。网站文档很棒,但是我认为通读配置文件是理解这个东西能做什么的好方法。在这篇文章中,我们把它保持得非常简单,但是对于那些想更进一步的人来说,这里有一些想法:
- 预处理特征向量。(即标准化)
- 尝试不同的层,如果它们不平坦,尝试最大池化或平均池化,然后平坦化
- 应用降维技术:tNSE、PCA、LDA
- 使用自动编码器进行预处理
这是我的第一篇文章。所以如果你喜欢,请告诉我。如果有什么不工作或格式被关闭,也让我知道!在外面保持优雅。
升级代码
从注册建筑师的角度看建筑规范符合性的未来:UpCodes Web & UpCodes AI
作为一名注册建筑师和数据科学家,我对通过数据科学和机器学习简化建筑实践中的工作流感兴趣。我作为一名建筑师已经工作了 4 年,我知道建筑师、工程师和承包商在建筑法规合规性方面面临的挫折。需要有一种更好的方法来设计符合规范的建筑——多亏了一家名为 UpCodes 的初创公司,这种方法确实存在。
什么是建筑规范?
简要概述— 建筑规范是确保建筑用户安全和无障碍的标准。例如,建筑法规限制火灾时出口的距离,要求容纳更多人的房间有更多的门,并强制规定楼梯台阶的最大高度。
虽然建筑规范并不意味着抑制建筑师和设计师的创造力,但它往往会成为设计问题创造性解决方案的障碍。架构师经常会看到代码符合性的图表——并且只是想准确地提供所显示的内容以确保符合性。可以说,构建代码可能是一个令人沮丧和痛苦的需求,它经常抑制设计过程的创造性流动。
左图:符合美国残疾人协会指南的无障碍浴室的三维示意图。右图:剖面图显示了符合 ADA 指南的间隙和安装高度。来源。
我使用哪种建筑规范?
更复杂的是,强制执行的建筑法规在不同的司法管辖区可能会有所不同。不同的建筑规范可能会在地方一级或国家一级采用,这可能会变得非常混乱!有地图和其他文档显示各州的代码采用情况。
例如,在不涉及太多细节的情况下,佛罗里达州迈阿密的一栋新公寓楼与加利福尼亚州旧金山的同一栋楼相比,将有不同的建筑规范要求。在迈阿密——建筑规范坚持设计要求,以应对飓风和风暴潮的可能性,而在旧金山——建筑规范假定需要更坚固的建筑来抵御地震。
建筑规范因管辖范围和面临的独特挑战而异。左:佛罗里达。来源。右图:旧金山。出处。
我引用哪个代码段?
一旦我们弄清楚了管辖区使用的建筑规范,我们必须确保我们引用了规范的正确的部分。有不同的章节涉及建筑设计的各个方面。有关于占用,建筑高度&面积,建筑结构类型,出口,内部装修等章节。
因此,当我们设计建筑时,我们必须在物理代码簿(或者 PDF 文档,如果你幸运的话)的页面中搜寻,找到我们需要参考的正确部分,以确保合规性。仅 IBC 2018(一个通用的建筑标准)就有 726 页——这可能是你的项目必须遵守的许多建筑规范之一。所以你可能需要为你的项目引用成千上万的页面。
国际代码委员会(ICC)开发的代码集。他们是开发建筑规范的几个主要实体之一。有很多要记录的!来源。
作为一名建筑师,可能需要数年的时间来积累足够的经验和专业知识,以便对建筑规范足够熟悉,从而培养对符合规范的设计的敏感性。我注意到的是这样的:年轻的设计师通常不确定一个特定的设计决策是否符合代码,直到更高级的架构师检查他们的工作。这导致对设计安全和无障碍空间缺乏信心,不得不返工,而成功取决于对更年长、更有经验的员工的依赖。
一定有更好的方法…
所以现在你明白了构建代码的头痛之处,一定有更好的方法,对吗?自从计算机出现以来,科技公司彻底改变了建筑师设计建筑的方式。 Autodesk 改变了建筑师通过 AutoCAD 和 Revit 绘制图纸的方式。 Adobe 改变了建筑师通过 Photoshop、Illustrator 和 InDesign 制作图表、渲染和演示的方式。那么,技术如何解决建筑法规合规性的问题呢?
升级代码
输入: UpCodes 。这家初创公司利用数据和软件开发的力量为架构师创造了两种工具。第一个工具是UpCodes Web——这是一个搜索引擎,(想想谷歌)增强了机器学习和分析,唯一的目的是找到你需要的建筑代码,超级快。第二个工具是 UpCodes AI —这是 Revit 的一个插件,允许我们实时查看代码错误!这些工具有可能每年为 AEC 专业人员节省数千小时的辛苦时间。
UpCodes 网站
Upcodes Web 是一个查找建筑规范的一站式商店,而不是在多个代码簿、网站或 pdf 中查找。通过提供“项目输入”,如我们的建筑类型、建筑类型、喷水灭火系统和建筑占用等级,UpCodes 可以过滤以仅显示与我们的项目唯一相关的建筑代码。这有助于所有年龄段的架构师和工程师更快速、更自信地浏览代码。
通过提供“项目输入”,UpCodes 将与我们的项目无关的代码变灰,只突出显示我们关心的代码。资料来源:UpCodes
有时,司法管辖区会对通用建筑规范进行修改,如国际建筑规范(IBC)——UpCodes 帮助我们识别这些变化。UpCodes 随时更新 UpCodes 网络工具,更新我们管辖区最近可能实施的任何修订,因此我们始终关注最新的指南。
例如,通过选择“California”作为我们的辖区,我们可以快速突出显示并了解加州与典型基础建筑规范的独特差异,如 IBC。资料来源:UpCodes
在设计的早期阶段,建筑师需要确定支持建筑规模的建筑类型。一般来说,建筑物越大和/或越高,建筑系统就必须越坚固。存在与建筑面积、楼层数和建筑高度相关的限制,这些限制会随着建筑占用、建筑类型和其他因素的变化而变化。为了解决这个问题,UpCodes Web 工具有一个计算器功能,在提供您的“项目输入”后,允许我们检查我们没有超出允许的建筑面积、建筑高度或楼层数。
计算器功能一瞥。在提供我们的项目输入之后,一个绿色的“检查”意味着我们的项目是代码兼容的。红色的“X”表示我们不符合规范。资料来源:UpCodes
UpCodes Web 将代码研究变成了一项更友好、更有吸引力的社交活动!通过在 UpCodes Web 中创建一个项目,团队成员可以评论、标记和共享可能需要进一步审查或可能引发项目设计变更的代码摘录。我们可以边看建筑规范边聊建筑规范。
您可以在 UpCodes web 应用程序中与您的项目团队一起对代码摘录进行评论。资料来源:UpCodes
UpCodes AI
UpCodes AI 是 Autodesk Revit 的一个插件。对于那些使用 Revit 的人来说,你们是否有过这样的想法:
“如果 Revit 能告诉我这些(楼梯、走廊、门、ADA 卫生间等)是否符合规范,那就太好了。”
你猜怎么着:这正是 UpCodes AI 所做的!目前,该项目只关注构建代码的两个方面:egress 和 ADA。将来,有望支持更多的构建代码方面,使该工具更加全面和健壮。
要使用该工具,您只需下载并安装插件,它就会与您现有的 Revit 模型集成,自动分析模型的构件和几何图形。该工具可以标记建筑规范错误,并按类别对其进行分类,无论是 ADA、浴室还是门。我们可以单击这些类别来突出显示模型中的单个问题。从这里开始,我们可以进行必要的设计更改以符合代码。这个工具有可能改变我们使用建筑规范的方式,集成到我们用来建模和记录建筑设计的主要软件中。我们不再需要等待更有经验的高级架构师(或者外部顾问)的代码审查。有了这个工具,每个人都可以随时检查他们的工作是否符合代码。 UpCodes AI 允许我们在设计时检查我们的工作,而不是在设计之后。查看下面 UpCodes AI 的视频演示。
UpCodes AI 的视频演示。来源:UpCodes
当我们在 UpCodes AI 中查看问题时,该工具会显示与错误相关的特定代码信息。首先,它向我们简要概述了这个问题。第二,它将建筑规范中通常隐晦的语言解释成“外行人的术语”,以便每个人都能理解问题。第三,它提供了原始代码摘录以供参考,只需单击一下就可以带您到 UpCodes Web 应用程序,如果需要,可以查看更多的构建代码。最后,它列举了我们模型中的每一个代码违规实例——我们可以使用“Inspect”按钮直观地研究每一个违规。见下图。
UpCodes AI 如何引起我们对代码违规的注意。资料来源:UpCodes
随着时间的推移,UpCodes 会自动更新新功能。来自 UpCodes AI 用户的反馈决定了该工具如何开发和进化。他们优先考虑用户反馈中最受欢迎的请求。你可以在这里给升级代码 AI 更新日志留下反馈。
后续步骤
了解更多关于 UpCodes AI 工具如何在幕后工作,以及如何改进它将会很有趣。是否只是访问指导建模图元尺寸的 Revit 参数来确定合规性?
UpCodes AI 还能如何使用机器学习算法来预测问题区域?它可以使用自然语言处理来提取房间名称的含义,然后预测并分配这些房间的入住等级吗?还是必须依赖建筑师在 Revit 模型中手动输入的占用等级参数?这个工具可能有很多方法可以通过数据科学和机器学习/人工智能努力来改进。
来源:作者。
结论
UpCodes 试图以一种更加包容和用户友好的方式来打破建筑师设计建筑的方式。从本质上来说,建筑规范是建筑师和工程师必须遵守的规则的集合,以创造安全和无障碍的空间供人们使用。到目前为止,作为一个职业,我们总是在几个不同的资源中手动检查这些规则的合规性。
UpCodes Web 将建筑代码集中到一个 Web 应用程序中,并利用项目数据使代码合规性更容易、更直观。UpCodes AI 更进一步,允许我们在架构师习惯的软件环境中进行代码检查。建筑的未来取决于数据以及我们如何利用数据来更高效地设计我们的建筑环境。UpCodes 可能是这个未来的一大部分。
预测 NFL 几乎是不可能的…是吗?
采用新开发的色谱柱选择技术的综合测试系统
图片来源:perfectduluthday.com
作者:Matthew Littman 商业分析硕士
加州大学欧文分校
介绍
我以前的文章“超级碗预测模型”讨论了预测超级碗冠军的整个建模过程,重点是缺失值的数据插补方法。该过程如下:
- 从多个来源收集数据(3 个网站)
- 连接数据(1579 行,242 列)
- 清理数据
- 估算缺失值-通过链式方程进行多重估算(MICE)
- 对数据进行采样-对少数进行综合过采样(SMOTE)
- 选择重要列—递归特征消除(RFE)
- 拆分数据(80%培训,20%验证)
- 通过逻辑回归运行数据
- 当前年份(2019 年)的测试数据
利用 ROC 曲线,该前一种方法的曲线下面积为 95%。ROC 曲线是通过并列真阳性率(TP/P)和假阳性率(FP/N)来可视化不同分类模型之间的比较的标准方式。当对错是唯一重要的结果时,这种方法很有效。从 32 支球队的常规赛数据预测超级碗不是一件容易的事;因此,测试系统应该反映这种可变性,并为接近的预测加分,即使它们不是真阳性。结论是 ROC 曲线不是有效的测量工具。
正如我在上一篇文章中提到的,有一些地方我想深入研究,也就是第六到第九点。本文重点介绍了一个全新的健壮测试系统、两种列选择技术(随机森林和一种新颖的“RFE 循环”方法),以及一个附加的算法/模型(神经网络)。我之前的文章包括了本赛季前 13 周的数据,但随着常规赛的结束,这篇文章包括了我对 2019-2020 NFL 赛季超级碗冠军的最终预测。
数据源
提醒一下,图 1 显示了所使用的数据源。
图一。数据来源
清洁
每个团队的统计数据都是特定年份中与该团队相关的独立事件。这意味着,所有的计算或比较都是在按年份分组并进行范围标准化之后进行的,以便在该年的每个统计中清楚地对每个团队进行排名。
超级碗预测的改进测试系统
新的测试系统反映了每年预测的累积总数,以确保对“接近”但不一定正确的预测进行无偏见的评分和奖励。评分规则如表 1 所示。
表 1。评估/比较模型和技术变化的新评分系统
新系统计算包含超级碗的每一年的分数,最高年分数为 30 分。这一过程在所有年份都重复进行,在超级碗时代的 53 年中,最高得分为 1590。对于每一年,该年的数据用于测试,而其余的用于训练。
评分系统背后的基本原理是,“赢得会议的分数”和“输掉会议的分数”代表该模型是否能够准确预测超级碗的竞争者。预测正确的超级碗冠军赢得 10 分,以便测试系统支持超级碗冠军预测。有 12 支球队进入了季后赛,6 支来自亚足联,6 支来自 NFC。由于这种季后赛结构,任何球队的最大可行距离将是距离联盟第一名 5 个位置。如果一支球队超过了这个距离,这个模型将会预测这支球队没有进入季后赛,从而导致负分。
评分系统示例:
为了进一步理解评分系统,我将通过一个对 2018 年超级碗的预测进行评分的示例(出于说明目的,使用了假数字)。2018 年超级碗的获胜者是新英格兰爱国者队,而失败者是洛杉矶公羊队。图 2 给出了预测示例。
图二。示范 2018 赛季评分系统的预测示例。
在两场会议一起进行的预测中,爱国者队排名第二,公羊队排名第四。这两个队被分成各自的小组,因为最终,亚足联的冠军将对阵 NFC 的冠军。一旦分开,爱国者现在是第一,公羊是第二。
表二。示例年得分计算明细:2018 年
列选择技术
有了新的测试系统,我们尝试了几种色谱柱选择技术来改进模型。广泛使用的随机森林和新建立的“RFE 环”(下面详细描述)都被添加到测试方法列表中,该列表先前包括 RFE 方法和“初始列”。上一篇文章中的最初专栏是通过 RFE 和信息增益的结合发现的。
随机森林
随机森林算法可用于特征选择以及分类。决策树的思想是,所有的观察结果都可以根据对或错的陈述(例如,触地得分> 30)被任何属性分割。随机森林是决策树的组合(在我们的例子中是 1000 棵)。该算法随机选择一个色谱柱,然后使用杂质平均减少量(MDI)或基尼系数最大化分离 (Breiman 2001) 。“它被定义为在集合的所有树上平均的节点杂质的总减少量(由到达该节点的概率加权(由到达该节点的样本的比例近似))(李 2017) 。从本质上讲,该算法寻找最能分割数据的特征。
RFE 环线
利用递归特征消除方法,我开发了一种在数据集中选择重要列的新方法。RFE 从所有列中随机选择一个子集,并使用一个决策函数来决定该子集中的哪些列是最重要的列。它重复这个过程,直到剩下的列数等于用户指定的数目。
为了选择数据集的重要列,我开发了一种使用 RFE 的新方法,我称之为 RFE 循环。在 RFE 循环中,一个字典记录了被测试的每一年的重要列的数量。一旦所有年份都经过测试,字典就会被检查,计数最高的列(用户指定的列数)将被选为最重要的列。当与 K-fold 或 hold one out 测试方法配对时,这种技术工作得非常好,因为算法已经在重复运行。
伪代码:
表 3。RFE 循环算法的伪代码
建模
除了两种新的色谱柱选择技术之外,还使用 TensorFlow 的 Keras 构建了一个神经网络,尝试与逻辑回归模型竞争。神经网络通常适用于高维数据以及大量数值数据。我搜集的 NFL 数据集没有大量的数据(1579 个观察值),但它确实有很高的维数(137 列)。该模型使用不同数量的隐藏层和参数创建了多次:
表 4。用 Keras 建立的神经网络的参数
测试系统的结果
图 3。模型选择、数据插补和列选择方法的综合测试结果比较
如图 3 所示,技术/方法的最佳组合是逻辑回归,缺失值由先前的 MICE 计算文件处理,初始列在我的第一篇文章 Super Bowl 预测模型中。这种组合对于正确预测的超级碗的数量和总得分都是最好的。图 3 包括:
- 两种建模方法(逻辑回归和神经网络)
- 五种列选择技术(RFE 循环、RFE、随机森林、初始列和所有列)
- 三种数据插补方法(先前计算的 MICE 值、MICE 和平均值)
RFE 循环法的总分略低于初始列的总分。此外,初始列正确地预测了另外两个超级碗。基线模型是包含所有列和缺失值平均值的逻辑回归。当涉及到正确的超级碗预测时,该基线比其他一些组合稍好,但在总分上它输给了几乎所有其他模型。唯一的例外是包含所有列和先前计算的 MICE 值的神经网络。图 3 显示了模型的不同组合以及它们的表现,而图 4 根据总分对不同方法进行了分类。
图四。类别预测方法比较:模型选择、列选择、数据插补
图 4 阐明了相互比较时,每项技术对总分的贡献程度。对于模型选择,平均而言,逻辑回归得分比神经网络高约 2.7%。对于列选择,RFE 循环的性能比使用所有列时高 20%,比第二高的初始列方法高 3.3%,比仅使用 RFE 高 10.9%。随机森林技术的性能比普通 RFE 方法稍好。值得一提的是,RFE 方法每年大约需要 45 秒(总共 53 年),而随机森林方法每年大约需要 5 分钟。这点时间差,不值总分的些微增益。
继续进行数据插补,之前计算的 MICE 值比仅使用平均值高 6.2%。为了强调每个 MICE 计算之间的细微差异,先前计算的 MICE 值和新计算的 MICE 值之间的差异大约为 3%。这表明,如果不使用之前计算的值,结果可能会略有不同。
总的来说,考虑到所用的不同方法可能得到的总分范围很广,很明显色谱柱选择的影响最大。当谈到模型选择时,导致最终算法的步骤远比选择的“模型”重要。根据这个项目,建模过程的每个部分都会极大地影响预测能力的结果,但是最重要的部分是列的选择。由于 NFL 捕获的统计数据的数量,列选择很可能是建模过程中最重要的部分。辨别哪些统计数据最有意义的能力是这个项目的缩影。
通过 RFE 环技术选择的 20 根柱子如下表 5 所示。
表 5。根据 RFE 循环技术最重要的列
在所有 12 个模型都经过测试后,我很好奇是否有哪个年份的大多数模型预测正确。结果显示,12 个模型都预测正确的 6 年(1972 年、1979 年、1985 年、1991 年、1996 年和 2003 年)表现突出。
图五。显示每年正确预测超级碗的模型数量
1972 年:不败的迈阿密海豚队
1979 年:12-4 匹茨堡钢人队与圣地亚哥充电器队平了最佳记录
1985 年,芝加哥熊队以 15 比 1 领先(最佳记录)
1991 年:14-2 华盛顿红人队(最佳记录)
1996 年:13-3 绿湾包装工队,进攻得分比防守允许的得分多 37 次触地得分。第二高的是 49 岁的人,只有 18 人。
2003 年:14–2 名新英格兰爱国者(最佳记录)
记录显然对预测有很大的影响,因为有好记录的球队往往有其他好的统计数据。在选择了之前讨论过的最佳方法(逻辑回归、RFE 循环和之前计算的小鼠值)之后,整个测试过程的可视化可以在下面的图 6 中看到。
图 6。整体模型评估,显示模型对预测赢家的选择及其机会百分比(根据预测是否正确以红色/绿色显示),以及实际赢家和模型给予实际赢家的机会百分比(黑色)。
图 6 显示了所有年份的预测赢家、实际赢家和超级碗竞争者。这表明,即使模型是不正确的,它也可能只是预测超级碗的输家是赢家。例如,2015 年,卡罗莱纳黑豹队在超级碗比赛中对阵丹佛野马队。该模型预测了卡罗莱纳黑豹队,而实际的赢家是野马队。因此,虽然模型不正确,但它仍然预测了一支参加超级碗的球队。
结论
总之,新的测试系统允许以前不可能的模型比较。该系统允许在神经网络和以前的逻辑回归之间进行比较。此外,测试了两种新的列选择技术,其中“RFE 循环”获得了最佳平均总得分的第一名。图 7 中橙色部分显示了整个模型的变化。
图 7。对以前方法的流程变更进行建模。
使用这种改进的预测模型,截至分区赛,2019 年超级碗的预测赢家是旧金山 49 人队,胜率为 36%,如图 8 所示。
图 8。2019-2020 NFL 赛季超级碗预测,截至通配符回合
相关作品/参考文献
随机森林列选择
布雷曼,狮子座。2001.“机器学习。”https://doi.org/10.1023/a:1010933404324。
李,瑟辛。2017.“树木模型的特征重要性测量—第一部分”中等。名副其实。2017 年 10 月 28 日。https://medium . com/the-artificial-impostor/feature-importance-measures-for-tree-models-part-I-47f 187 C1 a2 C3。
Github
一个全自动的模型版本发布在我在 https://github.com/kelandrin/Superbowl-Prediction-Model/的 Github 上
请随意下载并体验不同的功能!
只要确保下载了适当的包(列在主文件的顶部),然后运行主文件,你就可以开始了!
可能的网络应用即将推出!
使用 Python API 更新 Quip 电子表格
什么是妙语,你为什么要在意?
Quip 是一个用于移动和网络的协作生产力软件套件。它允许多组人员作为一个组来创建和编辑文档和电子表格,通常用于商业目的。(维基百科)
Quip 和 Google Docs/Sheets 的一个主要区别是 Quip 有一个原生的桌面应用程序。
Quip 电子表格截图(Lynn Zheng)
在这篇文章中,我将向您展示如何使用其 Python API 客户端来自动化创建、插入和更新 Quip 电子表格的过程。为了增强 API 的功能,我对它的官方 GitHub 库做了一个分支,并加入了一些有用的 pull 请求,这些请求还没有合并到主分支中。从我的库下载quip.py
继续本教程。
Quip API 基础
官方 API 文档位于本网站。您将需要一个访问令牌来与 Quip 的 API 进行交互。访问页面https://quip.com/dev/token生成个人访问令牌。
要打开 Python 客户端:
import quip
ACCESS_TOKEN = "" # your access token
client = quip.QuipClient(access_token=ACCESS_TOKEN)
Quip API 的一个基本实体是线程。
Quip 将文档和消息集成到一个单元中,我们称之为线程。Quip Automation API 中的大多数操作都是在线程上进行的。线索可以简单地是消息列表,即聊天线索,或者除了消息列表之外,它们还可以具有文档。(装备 API 文件
在 Quip 中创建电子表格
向new_document
传递一个空字符串作为第一个参数,告诉 Quip 使用它的默认 HTML 模板。
jso = client.new_document("", title="My Spreadsheet", type="spreadsheet")
您还可以指定一个 HTML 字符串作为第二个代码段中的模板。如下创建一个名为template.html的文件。这个电子表格模板只包含两列。
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>with open("template.html", "rt") as f:
template = f.read()
jso = client.new_document(template, title="My Spreadsheet", type="spreadsheet")
抓住thread_id
发来的服务器响应。我们将需要它作为我们创建的电子表格的参考,以插入/更新记录。
thread_id = jso["thread"]["id"]
让我们将标题(默认为 A 和 B)更新为更具描述性的内容。
client.update_spreadsheet_headers(thread_id, "Name", "Email")
检查标题设置是否正确:
spreadsheet = client.get_first_spreadsheet(thread_id)
headers = client.get_spreadsheet_header_items(spreadsheet)
print(headers) # prints ['Name', 'Email']
按标题检索电子表格
title = "My Spreadsheet"
jso = client.get_matching_threads(title, only_match_titles=True)
# get the id of the first thread
thread_id = jso[0]["thread"]["id"]
将记录插入电子表格
client.add_to_spreadsheet(thread_id, ["John Doe", "jdoe@gmail.com"])
client.add_to_spreadsheet(thread_id, ["Jane Doe", "jane@gmail.com"])
更新电子表格中的记录
假设简将她的电子邮件地址更新为 jd12@gmail.com,让我们更新电子表格来反映这一变化。
client.update_spreadsheet_row(thread_id, "Name", "Jane Doe", {"Email": "jd12@gmail.com"})
一个警告:Quip 的 API 实现了严格的速率限制,默认为每分钟 50 个请求,这意味着每分钟最多只能插入/更新 50 条记录。在文档中阅读更多关于自定义标题X-Ratelimit-Limit
的信息。
与您组织中的其他 Quip 用户共享电子表格
假设您想与电子邮件地址为 smith@gmail.com 的同事共享该电子表格。
email = "smith@gmail.com"
jso = client.get_user(email)
member_id = jso["id"]
client.add_thread_members(thread_id, [member_id])
这些是 Quip 的电子表格 API 的基础。感谢阅读!
更新 BigQuery 中的已分区表
BigQuery 已经取得了很大的进步,但是一些重要的方面(比如通配符搜索)仍然缺少一些在 SQLServer 中相对简单的功能。其中一个功能是更新分区表的能力。更新一个分区很容易,但是,如果您有 100 个分区,单独更新它们会很麻烦。
下面是一个更系统化的尝试。请记住你的 GCP 成本,因为这可能不是最具成本效益的方式。如果您确实找到了更高效或更经济的方法,请将您的解决方案添加到回复部分。
为了更新一个分区表,我们将首先创建一个包含所有需要更新的分区的表,然后为每个分区创建一个 update 语句。最后,我们将遍历每个 update 语句来完成更新。
create table `myResource.Dataset.tablePartitions` AS
with parts as (
select distinct _table_suffix as dates from `myResource.Dataset.prefix_*`
)
select
concat('update ','`myResource.Dataset.prefix_',dates,'` set columnUpdate = "abc" where columnB = "xyz"') as tab
,row_number() Over() as rn
from parts;
要创建一个表,只需查询您要分区的表的每个不同分区。本例中为 Dataset.prefix_* 。表分区,或 myResource。Dataset.tablePartitions,是一个新表,将被创建和引用以创建 update 语句。如果不需要保存每个分区的记录,也可以在这里创建一个临时表。如果您选择这样做,请确保一次性运行上面和下面的代码。
declare num_partitions int64;
declare query string;
set num_partitions = (select count(distinct _table_suffix) from `myResource.Dataset.prefix_*`);while num_partitions > 0 Do
set query = (select tab from `myResource.Dataset.tablePartitions` where rn = num_partitions);
Execute Immediate query;
set num_partitions = num_partitions-1;
END While;
后一部分将引用在步骤 1 中创建的 update 语句,并遍历它们。根据分区的大小、GCP 成本结构和分区的数量,您可能希望分批完成工作,而不是像这里一样遍历每个分区。要批量执行,调整 num_partitions 变量和 while 语句条件。
这是一个快速的解决方案,可以改进。如果你发现了一种更新 BQ 中的分区表的更好的方法,我很想听听。希望这是有帮助的,并为您节省一些时间。
使用 Python 更新 Github 存储库
使用 GitPython 自动从远程目录中提取
照片由 Richy Great 在 Unsplash 上拍摄
我每天至少运行两次以下命令:
>>>git fetch upstream master
>>>git merge upstream/master -m 'Here we go again...again'
>>>git push
每次 10 个单词,在我为期 15 周的训练营中每天跑两次,总共 1500 个单词。客观地说,这相当于我为你写的三篇高质量的博客。真的,必须做点什么。
GitPython
Git python 创建了一个 repo 对象,它允许你与你自己的库或者你的代码所依赖的公共库进行交互。
安装
>>>pip3 install GitPython
安装过程会仔细检查库的依赖关系。但是,您应该将您的用户名和密码添加到您的 git 配置中。
设置
您可以简单地将下面两个代码片段中的任何一个放在脚本的顶部,以编程方式更新您的本地存储库。
如果您想从远程源更新您的代码本地存储库,代码很简单:
但是,如果您想从远程上游存储库进行更新,代码会稍有不同:
申请
我以前的文章概述了如何使用 python 制作一个命令行工具。让我们使用该教程来构建一个“自动更新程序”。
>>>mv autoupdate.py autoupdate
>>>chmod +x autoupdate
>>>cp autoupdate ~/.local/bin/autoupdate
>>>source ~/.zshrc
>>>autoupdate
就这样,简单多了!新讲座?没问题。《纽约时报》更新了他们的知识库?我的地图会在下次打印时更新。
编码快乐!
升级您的 Nvidia GPU 驱动程序以获得更好的性能🚀
你的训练不稳定?考虑将 Cuda 升级到最新版本
我有一个运行在 Ubuntu 16.04 发行版和 Nvidia 1080 TI 上的 GPU 服务器。2018 年买的,到今天还在用 Cuda 9.0,驱动版本 384.130。
我的设置
我决定升级到 Cuda 10.2,用最新版本的驱动(440.33.01)。出于几个原因,我很早就想这么做了:
- 我偶尔会注意到我当前设置的不稳定训练和 GPU 故障
- 一些最新版本的通用深度学习框架(主要是 PyTorch)只能在 Cuda 10+上运行
所以这是做这件事的最佳时机。我在这篇文章中记录了不同的步骤。我们走吧!
- 头顶https://developer.nvidia.com/cuda-downloads
- 选择您的
-操作系统(Linux)
-架构(x86_64)
-发行版(Ubuntu)
-版本(16.04)
-安装程序类型(runfile (local)) - 一旦您选择了元素,您将会得到以下两个命令的提示。处决他们
**wget** [**http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_440.33.01_linux.run**](http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_440.33.01_linux.run)**sudo sh cuda_10.2.89_440.33.01_linux.run**
4.重启你的机器
**sudo reboot now**
你现在应该没事了。但是,如果您在运行nvidia-smi
时遇到此错误消息
未能初始化 NVML:驱动程序/库版本不匹配
这意味着您以前的驱动程序太旧,无法被**cuda_10.2.89_440.33.01_linux.run**
脚本检测和删除。
这就是为什么你需要清除 Nvidia 旧的依赖:
**sudo apt-get update
sudo apt-get --purge remove cuda
sudo apt-get autoremove
dpkg --list |grep "^rc" | cut -d " " -f 3 | xargs sudo dpkg --purge
sudo apt-get purge nvidia*
sudo apt-get update
sudo reboot now**
5.创建指向 Cuda 最新版本的符号链接
**sudo ln -s /usr/local/cuda-10.2 /usr/local/cuda**
6.更新您的。bashrc
旧行: 导出路径=/usr/local/cuda-9.0/bin:$ PATH
导出 LD _ LIBRARY _ PATH =/usr/local/cuda-9.0/lib 64:$ LD _ LIBRARY _ PATH
新行: 导出路径=/usr/local/cuda/bin:\(PATH 导出 LD _ LIBRARY _ PATH =/usr/local/cuda/lib 64:\) LD _ LIBRARY _ PATH
然后重启以保存更改。
7.安装 Cudnn
在这里创建一个 Nvidia 开发者账号。然后,点开这个链接,下载 Cudnn。
下载该文件后,运行以下命令:
**sudo cp cuda/include/cudnn.h /usr/local/cuda/include** **sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64** **sudo chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn***
8.检查您的安装
我用支持 Cuda 10.2 的最新 PyTorch 版本创建了一个新的 conda 环境。安装后,我运行以下命令:
**import torch****torch.cuda.is_available()
# True****torch.version.cuda
# '10.2'****torch.backends.cudnn.version()
# 7605**
但是您也可以使用您最喜欢的框架进行检查。
感谢阅读,我希望这是有用的!
干杯!
升级 Python 列表
向 Python 列表添加有用的功能
图片来源:JoeyBLS 摄影
介绍
Python 列表很好。但他们并不伟大。有如此多的功能,可以很容易地添加到他们,但仍然缺乏。用布尔进行索引,轻松地用它们创建字典,一次追加多个元素,等等。嗯,不再是了。
Fastai 已经拿出了自己的数据结构叫做L
。它能做 Python 列表能做的一切,甚至更多。
本文的目的是向您展示自己编写这样有用的功能是多么容易。尤其是如果你是一个初学者,试着创建一个迷你版本的库。试着写一些你希望存在的功能。这将是一次很好的学习经历。
现在,让我们来了解一下 L 。这是 Colab 的链接。在您的 Colab ( 文件- >驱动器中保存一份副本)上制作一份副本,并且只运行第一个单元格一次。你的笔记本会崩溃。但是你马上就可以使用图书馆了。
我是什么?
就像我之前提到的,它类似于 Python 列表,但是可以实现更多。让我们从导入库并创建L.
的实例开始
我们看到它打印了列表的长度,然后是内容。再也不用一直单独打印长度了。
如果你和我一样,不喜欢用方括号。移除它们。
编写.append()
来追加元素又是如此乏味。此外,一次只能追加一个元素。咩。移除移除。
请注意,这些东西非常容易编码。我们只是在幕后定义了一个__add__
魔法方法来决定+
操作员将做什么。如果你想学习更多关于魔法方法的知识,你可以阅读我的文章如何在 Python 中熟练使用 OOP。
我们来考察一下__add__
的方法。
它用当前元素和新元素创建 L 的新实例。很简单,对吧?
我们也试试__mul__
吧。
它将列表复制两次。另外,请注意,它只打印前 10 个元素,然后显示...
这比显示所有元素的 Python 列表要干净得多。
你可以在 l 中找到独特的元素。
你可以很容易地把它转换成一本字典。
然而,L 的真正强大之处在于它的索引功能。
- 使用索引列表进行索引
2.使用布尔进行索引
3.多重赋值
4.处理无问题的连接
很多时候,我们用 Python 返回一系列列表。我们需要 if 语句来检查其中是否有一个是空的,否则它们会抛出一个错误。不是和 l。
结论:
总而言之,这是一个很好的数据结构,可以很容易地用来代替列表。试试笔记本。探索它。这就是本文的全部内容。
~快乐学习
参考资料:
https://github . com/fastai/fastai _ dev/blob/master/dev/01 _ core _ foundation . ipynb
直接从终端上传文件到 Google Drive(使用 Curl)
将数据从计算机推送到云的另一种方法。
在许多情况下,从一台新机器向另一台机器发送数据可能很困难。这方面的例子包括隐藏在登录门户后面但不允许 ssh 隧道的 HPC 设施,或者只安装了几个核心程序的简单无头机器。在本文中,我们将使用 cURL(一个用于传输数据的命令行程序)将一个压缩文件(包含日志文件)推送到我们的 google drive 帐户上,以便进行进一步的分析。
照片由 Element5 数码在 Unsplash 上拍摄
装置
大多数机器都会安装 cURL(试着输入which curl
)。如果不是这样,我们可以安装它
sudo apt install curl # Linux Debian/Ubuntu
或者
brew install curl # Mac
现在我们已经安装了它,我们可以看看如何创建发送文件所需的凭证。
创建您的项目凭据
由于我们允许访问我们的谷歌驱动器,我们希望能够管理这一点。这是通过创建一个具有用户定义权限的项目来实现的,该项目充当我们的用户(在本例中,我们在不同的机器上)和我们的帐户之间的代理。我们首先转到下面的页面(下面的链接)并创建一个新项目。
Google 云平台让您可以在同一基础设施上构建、部署和扩展应用程序、网站和服务…
console.developers.google.com](https://console.developers.google.com/apis/credentials?pli=1)
完成后,我们选择“凭据”选项卡(在左侧),然后从顶部选择“创建凭据”。
当询问应用程序类型时,我们选择电视和其他。
最后,这会生成一个client id
和一个client seacret
。
这是您的用户名和密码,请将其复制到安全的地方。
现在我们需要验证设备
为此,我们ssh
进入我们希望上传的机器,并运行以下命令:
curl -d "client_id=**<client_id>**&scope=https://www.googleapis.com/auth/drive.file" https://oauth2.googleapis.com/device/code
这样,我们会得到以下格式的响应
{"**device_code**": "<long string>",
"**user_code**": "xxx-xxx-xxx",
"expires_in": 1800,
"interval": 5,
"**verification_url**": "https://www.google.com/device"}
这里我们需要访问 URL(https://www.google.com/device)并提供用户代码来完成我们的验证。我们现在继续选择我们的 google 帐户并授予相关权限。进行此操作时,确保记下设备代码用于下一步。
获取不记名代码
当我们开始上传时,这是我们需要用来识别我们的帐户的代码。我们通过使用以下内容获得它:
curl -d client_id=**<client id>** -d client_secret=**<client secret>** -d device_code=**<device code>** -d grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code https://accounts.google.com/o/oauth2/token
客户端 id 和密码保存在第一步中,设备代码保存在上一节中。输出应采用以下格式:
{
"access_token": ".....",
"expires_in": 3599,
"refresh_token": "....",
"scope": "https://www.googleapis.com/auth/drive.file",
"token_type": "Bearer"
}
记下访问令牌,因为上传阶段会用到它。
上传文件
下面给出了我们用来上传文件的命令
curl -X POST -L \
-H "Authorization: Bearer **<enter** **access token here****>**" \
-F "metadata={name :'**<our.zip>'**};type=application/json;charset=UTF-8" \
-F "file=@**<our.zip>**;type=application/zip" \
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart"
在允许上传数据之前,您可能需要启用应用程序 API。如果是这种情况,错误消息中会给出执行此操作的链接。
这里的多部分文件预计只有几 MB 大小。然而,如果你正在考虑移动更大的文件可恢复的可能更适合(见https://developers.google.com/drive/api/v3/manage-uploads
用一个脚本把它包起来
现在我们知道我们的命令工作,我们可以创建一个可执行脚本来为我们做所有的工作。在这里,我们可以提供一组文件,它将它们压缩,然后发送到 google drive。
我们首先用nano curlgoogle;
创建一个新文件,并输入以下代码——记得添加您自己的个人身份验证令牌!选择 Python 2.7 是因为这仍然是旧系统上的默认 Python 版本,但是下面的脚本也应该适用于 python 3。
如果 curl 已经存在于系统中,它应该不需要新的依赖关系。
#!/usr/bin/python'''
A quick python script to automate curl->googledrive interfacing
This should require nothing more than the system python version and curl. Written for python2.7 (with 3 in mind).Dan Ellis 2020
'''import os,sys,jsonif sys.version[0]=='3':
raw_input = lambda(x): input(x)##############################
#Owner information goes here!#
##############################
name = 'curldata'
client_id= '**<enter your client id>**'
client_secret='**<enter your client secret>**'############################## cmd1 = json.loads(os.popen('curl -d "client_id=%s&scope=[https://www.googleapis.com/auth/drive.file](https://www.googleapis.com/auth/drive.file)" https://oauth2.googleapis.com/device/code'%client_id).read())str(raw_input('\n Enter %(user_code)s\n\n at %(verification_url)s \n\n Then hit Enter to continue.'%cmd1))str(raw_input('(twice)'))cmd2 = json.loads(os.popen(('curl -d client_id=%s -d client_secret=%s -d device_code=%s -d grant_type=urn~~3Aietf~~3Aparams~~3Aoauth~~3Agrant-type~~3Adevice_code https://accounts.google.com/o/oauth2/token'%(client_id,client_secret,cmd1['device_code'])).replace('~~','%')).read())
print(cmd2)# zip files
cmd3 = os.popen('zip -r %s.zip %s'%(name,' '.join(sys.argv[1:]))).read
print(cmd3)cmd4 = os.popen('''
curl -X POST -L \
-H "Authorization: Bearer %s" \
-F "metadata={name :\'%s\'};type=application/json;charset=UTF-8" \
-F "file=@%s.zip;type=application/zip" \
"[https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart](https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart)"
'''%(cmd2["access_token"],name,name)).read()print(cmd4)
print('end')
然后我们使它可执行chmod a+x curlgoogle
,允许我们以可执行的方式使用它:
**./curlgoogle** file1 file2.txt file3.jpg etc...
结论
现在我们有了一个简单的方法,可以将多个日志文件从一台无头机器发送到一个 google drive 存储库中,供多人访问以进行分析。
如果你需要更多的信息,由 Tanaike 和 HAKS (以及其他人)提供的堆栈溢出回答对创建这篇文章特别有帮助。
SARS-新冠肺炎感染人数的上限和检验偏差
我看着新冠肺炎
估计目前该疾病在各国传播的最大可能程度
在之前的一篇文章中,我提出了不同国家可能被当前的 SARS-新冠肺炎疫情感染的人数的上限和下限——无论他们是否表现出症状——以及提供一个接近实际数字的中心估计值。总的来说,这些界限和核心估计数表明,该疾病并没有像一些人声称的那样广泛传播,而且所有国家离群体免疫的可能性还很远。我在那篇文章中的结论和主要观点已经被最近发表的几项研究所证实。然而,我的朋友兼语言学家同事博班·阿尔塞尼耶维奇在对那篇文章的私人回复中注意到我的上限有一个错误。在这篇文章中,我进一步完善了疾病传播的上限,以回应博班的批评。我表明,尽管有这个错误,前一篇文章的主要结论仍然成立,甚至得到了最近数据的支持。在这里,我还考虑了额外的重要细节,比如测试的准确性,为了简单起见,在之前的帖子中有意忽略了这些细节。使用这些新的改进,我使用更近的数据提供了更精细的疫情扩散范围,并且我研究了这些告诉我们不同国家遵循的测试政策。
更可靠的上限
人们在有限的时间内测试呈阳性
在我的上一篇文章中,我使用了人群中检测结果呈阳性的比例——阳性检测率——作为感染该疾病人数的上限——终生患病率。这种关系成立的原因是检测偏差:当已经有迹象表明他们可能已经被感染时,人们更有可能接受检测,无论是通过明确的症状,还是通过与其他已知被感染的人的密切接触。由于这个原因,在任何一天,被检测者中的阳性比例都会高于普通人群。
上述关系在任何一天都成立,但是——正如博班·阿塞尼耶维奇友好地向我指出的——它不需要在更长的时间内成立。问题是,人们从感染中康复后,只能在一定时间内保持检测阳性。例如,如果我们有一百个人,在五天的时间里,我们每天测试其中的十个人,每天获得两个阳性结果,我们可以推断在任何一天,被感染的人不超过百分之二十,这是正确的。然而,如果我们假设在第一天测试为阳性的人在第五天也测试为阳性,那么这一估计只能延伸到整个五天。如果不是这种情况,我们就需要把在非重叠日感染的人口比例加起来。请注意,这个问题的解决方案并不像将不同日期的积极因素相加那么简单。如果我们这样做的话,我们将会把一些受感染的人计算几次,直到他们检测呈阳性。简而言之,如果人们在很长一段时间内测试呈阳性,那么我上一篇文章的上限或多或少是正确的。然而,如果人们在更短的时间内测试呈阳性,我会严重低估上限。
为了解决这个问题,我们需要知道人们在被感染后,甚至在康复后,多久会继续检测为阳性。在最近发表的一项研究中,杜和他的同事们调查了人们在 SARS-新冠肺炎检测中呈阳性的时间长度。他们发现,这一持续时间取决于某人被感染的病毒载量(即初始感染的严重程度),以及患者的年龄(老年人比年轻人保持阳性的时间更长)。在他们研究的 161 人中,他们发现一名患者在被感染 50 天后仍呈阳性。更普遍的是,他们发现 25%的人在不到 17 天内保持阳性,50%的人在最多 21 天内测试呈阳性,75%的人在 28 天或更短时间内测试呈阳性(在技术术语中,这三个数字被称为分布的四分位数)。
图 1:在确认患有该疾病后,CoV-19 检测为阴性的概率。使用杜等人(2020)报告的四分位数(由图中的点表示)拟合到威布尔分布(参数 k=2.88,λ=25.68)。
杜等人报告的数字很好地符合威布尔概率分布(绘制在图 1 之外)。这是一个两参数的等待时间分布,通常用于可靠性分析(例如,估计设备故障前的预期时间)和生存分析(例如,估计治疗对病人预期未来寿命的影响)。有趣的是,拟合分布的形状参数反映了统计学术语中所谓的“老化过程”( k > 1 ):在我们的情况下,这意味着一个人测试阳性的时间越长,我们就越不可能发现这个人测试阳性的时间更长;换句话说,检测阴性的概率随着时间的推移而增加。
如何累积阳性检测率
在一段时间内累计阳性检测率的关键在于,每天只累加与前一天已经检测为阳性且仍为阳性的那部分人群不对应的阳性检测。换句话说,每天只有的新阳性应该被累加。累积一段时间内的新阳性结果将为我们提供一个真实的患病率上限。实际上,这意味着重复应用图 1 中的曲线:在疫情的第一天,我们增加了整个阳性检测率。在接下来的几天里,我们只累计前一天低于图 1 曲线的阳性检测率案例部分。这种累积过程避免了遗漏那些过去测试为阳性,但此后变成阴性的患者,并且通过重复应用曲线来确保不重叠防止了对那些仍然为阳性的患者进行两次计数。我将这一措施称为部分累积阳性检测率。
请注意,上面概述的累积过程需要足够详细的每日测试数据,而我在上一篇文章中使用的度量可以仅使用累积的测试数量和相应的累积案例来计算。不幸的是,对于不报告每日进行的检测数量,而是报告多日累计批次的国家,如德国(目前报告了 8 个批次)或西班牙(目前报告了 4 个批次),这使得很难获得可靠的上限估计值。
没有测试是完美的:敏感性和特异性
需要考虑的另一个因素是,尽管测试可能很准确,但没有一个测试是完美的。CoV-2 测试有多个提供者,所提供的不同测试在多个属性上有所不同。根据约翰·霍普金斯大学彭博公共卫生学院的一份报告,在不同的测试中,现有测试的 T2 敏感度,即“真实阳性率”,即测试呈阳性的感染者的比例,在 87%到 93%之间。同一消息来源称,测试的特异性——即“真实阴性率”,即未被感染的人测试呈阴性的概率——在 95%到 100%之间。尽管这些数字看起来很高,但事实上它们可以改变测试结果。例如,假设我们测试了 100 个人,我们得到了 80 个肯定的结果。我们可能会得出结论,有 80 人被感染,20 人未被感染。然而,如果我们把自己放在测试准确性最差的情况下——87%的灵敏度和 95%的特异性——我们实际上应该预期:
- 在测试呈阳性的 80 人中,79.57 人实际上对应于被感染的人(即真阳性)。剩余的 0.43 人预计是假阳性——由于测试的局限性,未感染的人测试为阳性。
- 在测试为阴性的 20 人中,只有 8.11 人对应于未被感染的人(即真阴性)。剩下的 11.89 人极有可能是假阴性——测试未能检测到的感染者。
考虑检测灵敏度和特异性,对阳性检测率进行校正。
考虑到上述情况,在阳性检测率为 80%的情况下,测试的灵敏度和特异性告诉我们,我们应该预计 79.57+11.89=91.46%的人被感染,8.11+0.43=8.54%的人未被感染。换句话说,如果我们直接使用测试数据,我们的估计会有超过百分之十的误差。即使我们不容易知道谁是假阳性或假阴性,我们也可以合理确定地知道有多少错误归因。一般来说,你可以用旁边的公式直接修正正比率。
不同国家的上限
修正的上限
图 2:一些代表性国家的每日阳性检测率、累计阳性检测率(我在上一篇文章中使用的上限)和此处建议的校正估计最大流行率的比较。
我使用了从数据中的我们的世界获得的检测数据来计算新的上限测量,结合了部分累积法和上述检测准确度校正(假设最差精度情况为 87%的灵敏度和 95%的特异性),适用于所有报告了一系列至少 45 天的每日阳性检测率的国家。
图 2 显示了部分累积的度量如何随着时间的推移产生恒定的累积。最重要的是,将其与累积阳性检测率(我在上一篇文章中提出的患病率上限)进行比较,后一种方法在该疾病在一个国家最流行的时候达到峰值,此后持续下降。这种下降反映了累积阳性检测率未能解释许多已解决的疾病病例,即,我们不应指望终生患病率指标会下降。相比之下,新的上限指标的表现与人们预期的一样:它快速增长,直到疾病达到峰值,然后稳定下来,进入较慢的增长。唯一的下降(使用七天运行平均值衰减)出现在每日测试速率的噪音振荡中。
图 3:至少 45 天的每日测试序列可用的国家的计算上限(红色三角形)。蓝色和黄色圆点分别表示情景 1 和情景 2 中提出的偏差的结果。
图 3(上图)中的红色三角形显示了超过 45 天的每日测试结果可用的国家的计算上限。只有三个国家——按降序排列为英国、塞内加尔、巴拿马和比利时——的 SARS-新冠肺炎终生患病率可能超过 60%,绝大多数国家远低于 30%。然而,正如我下面所讨论的,上限实际上是非常宽松的。一旦将测试偏差考虑在内,这些数字会大幅降低。
缺少日常测试数据时回归上限
图 4:逻辑回归预测中位数累积阳性率的上限。使用红点拟合回归,并用于预测蓝点。
不幸的是,许多国家没有报告每日测试数据,例如西班牙或德国,而其他国家只是在最近才开始提供这种每日报告,以便能够在一定程度上可靠地重建上限,例如智利或法国。然而,我们仍然可以根据其与累积阳性检测率的相关性来估算这些国家的上限。图 4(除此之外)绘制了累积率中值与那些有足够数据的国家(红点)的上限度量之间的关系。这里要注意是,使用平均值累积速率,回归会更加准确。然而,我使用了中间值,因为它对于数据点很少的国家更稳健(如西班牙只有四批数据)。我使用虚线绘制的回归线来插入其余国家的上限值(图 4 中的蓝点)。请注意,与我在的上一篇文章中使用的外推法相比,这仍然是回归训练范围内的插值,因此更加可靠。
图 5。回归-对于至少 45 天的每日测试序列可用的国家,插值上限(红色三角形)。蓝色和黄色圆点分别表示情景 1 和情景 2 中提出的偏差的结果。
图 5 中的红点标出了那些无法直接计算的国家通过回归插值得出的上限。和以前一样,在绝对最坏的情况下,只有三个国家(伊朗、西班牙和荷兰)的患病率可能超过 50%,而绝大多数国家的患病率远低于 30%。
缩小界限
偏倚和患病率之间的数学关系
现在,我将简短地——但也是必要地——谈谈数学符号,因为这对于理清测试偏差与流行度指标之间的关系至关重要。
根据概率论,我们可以将测试偏差定义为测试感染了疾病的人的概率与测试未感染的人的概率之间的比率。理想情况下,当两个方向都不存在实际偏差时,偏差的测量值应该正好为零,也就是说,感染者和非感染者接受检测的可能性完全相同。这是通过以对数标度定义等式 1(上面)中的测量值 B 来实现的。等式 2 是通过应用贝叶斯定理(概率的基本规则之一)从等式 1 得出的,该定理指出,对于任何事件 A 和 B ,它们的条件概率与P(A | B)= P(B | A)×P(A)/P(B)相关,并且抵消了所得的 P( 测试 ) 项。最后,应用概率的另一个基本规则——P(不是 A)= 1-P(A)——我们得出了至关重要的等式 3。这最后一个等式确定了——对于给定的一天——偏差是上限的对数比值比(即,博彩赔率)和真实患病率之间的差异。
[……]等式 3[……]必然意味着每日阳性检测率是每日流行率的严格上限
BB的正值代表偏向于检测患病人群,这是所有国家都存在的情况。正如我在之前的帖子中所讨论的,所有人都自然而然地优先检测有暴露于病毒迹象的人(例如参见美国疾病控制中心关于新冠肺炎检测的标准)。因此,我们可以相当肯定地说,对所有国家来说。请注意,相反的情况意味着非感染者比感染者更有可能接受检测,这在任何可能的情况下都没有意义——除非检测机构有意避免找到 SARS-CoVID 病例,这多少有些令人惊讶。
反过来,根据等式 3,这必然意味着每日阳性检测率是每日患病率的严格上限。通过将阳性检测率项替换为上述部分累积的阳性检测率,以及感染终生流行率的日流行率,等式 3 可以扩展到比特定一天更长的时间段。
“基于统计的常识”
从上面的等式 3 中,我们还可以推断出真实患病率的对数优势比正好是上限减去偏差。因此,为了限制真实患病率,限制偏差值 B 就足够了。我们可以将现有的数据与一些常识性的假设结合起来——我称之为基于统计的常识——以更好地了解各国的流行情况。
首先,现在众所周知的是,大部分感染 CoV-2 的人从未出现任何明显的症状,尽管这些无症状患者的确切比例仍在调查中(参见此处的了解不同研究报告的不同比例的概述)。据报道,无症状感染的最高比例约为 70%(来自对意大利北部 Vo '的 3000 名居民的测试)。
现在假设 60%的人口——专家估计达到群体免疫所需的最低水平——在某个时候已经被 CoV-2 感染。在评估患病率的最坏情况下,让我们假设只有 30%的感染者表现出任何症状——就像 Vo '的情况一样。我有意将这个非常高的无症状百分比作为偏倚的下限(因此也是患病率的上限)。采用任何较低的无症状百分比都会导致更大的测试偏差。要达到 60%,我们需要观察患病率的上限值是多少?
让我们假设两种可能的情况:
- 情景 1 :假设每 20 个没有真正感染 CoV-2 的人中就有一个显示出被感染的迹象——或者是通过与 SARS-新冠肺炎一致的症状,或者是通过与已知感染者的密切接触。与大多数国家正在做的事情相似,我们选择只检测表现出疾病症状的人。因此,我们有 P( 测试|感染 )= 30%和 P( 测试|未感染 )= 5%。这意味着感染者接受检测的可能性是未感染者的六倍。然后,根据等式 1,我们的偏差将是 B = log .3 /.05 = 1.79,这反映出感染者接受检测的可能性是非感染者的六倍。我们可以使用测试偏倚的值来查看真实的终生患病率为 60%时需要的上限值。从等式 3 我们知道上限的对数比值比等于真实患病率的对数比值比加上偏差值:log .6 / .4 + 1.79 = 2.2。将对数优势比转换为简单的概率值,这意味着要获得 60%或更高的真实患病率,需要找到 90%以上的上限。
- 情景 2 :在实践中,许多国家不仅仅要求测试症状或 CoV-2 暴露的迹象;他们实际上将测试限制在那些有严重症状需要住院治疗的人,或者属于非常特殊的关键或高风险人群(例如,医务人员、老年人……)。例如,许多国家都有报告称,即使人们表现出明显的非典-新冠肺炎症状,他们也很难接受检测。在这种情况下,情景 1 中描述的偏差实际上是一个很大的低估。我们可以预期测试偏差会大得多。本着这种精神,如果我们假设一个受感染的人比一个未受感染的人被检测的可能性高 20 倍,我们将得到 B= 3.00。重复上面的计算,在这种情况下,60%的真实患病率需要观察不小于 97%的上限值。
图 6:在两种偏倚情况下,可能的估计流行率上限和达到此上限所需的相应真实流行率值之间的关系。
如图 6 所示,这些情景可用于猜测观察某个上限值所需的真实流行率。在这两种情况下,除了接近 100%的上限值,真实流行率必须大大低于上限值,通常是 4 或 5 倍。
在图 3(对于直接计算的上限)和图 5(对于通过回归内插的上限)中,应用来自两种情况的猜测偏差的结果由蓝色(情况 1)和黄色(情况 2)点绘制。重要的是,除了英国、塞内加尔和巴拿马——拥有可靠的每日序列的国家——以及伊朗和西班牙——通过回归估计的国家——预计绝大多数国家的患病率低于 20%,即使在非常低的偏倚情景 1 中也是如此。在情景 2 更现实的偏差下,只有英国、伊朗和塞内加尔的终生患病率超过 10%。
结论
这些场景有多真实?西班牙、法国和爱沙尼亚
上述两种情况结合了对偏差可能有多大的粗略常识性猜测,以及统计上合理的上限测量。人们当然会怀疑这些估算中的常识成分。然而,请注意,常识推理是概率论的核心。正如皮埃尔·西蒙·拉普拉斯所说,
[…] 概率的理论不是建立在基础上的,而是建立在计算基础上的。 ——**皮埃尔·西蒙·拉普拉斯《概率哲学随笔》 1814 年
概率论只不过是简化成微积分的常识。这个想法后来在 Richard T. Cox 的一个著名定理( Cox 的定理)中得到更正式的证明,表明常识和直觉知识可以被编纂,然后概率论的规则提供了对这些知识进行推理的最合理的方式——事实上是唯一的方式。我提出的常识性情景只是对我们先前知识的简单公开量化,即在大多数国家,CoV-2 检测偏向于感染者。这里使用的方法能够——如果有人有理由相信偏差应该更高或更低——只需插入一个新的先前猜测,并获得与这些假设最一致的结果。我们现在可以使用来自我们对其真实流行率有可靠估计的国家的数据来调查各国之间真正的阳性检测偏倚。
[……]在西班牙,感染者接受检测的可能性是未感染者的 127 倍。
最近,西班牙的卡洛斯三世健康研究所发布了其在 T2 的第一轮 ENE-COVID19 研究的初步结果(链接是西班牙语的,点击此处查看路透社的英语摘要)。这是一项大规模的血清流行病学研究,旨在从 4 月 27 日至 5 月 11 日期间随机抽样的 6 万多名西班牙居民的血液样本中寻找 CoV-2 抗体,这些样本经过精心选择,以提供西班牙人口的准确代表性。他们报告说,大约 5%的西班牙居民会被病毒感染,95%的置信区间在 4.7%到 5.4%之间。这非常接近西班牙在情景 2 下的估计,即 4.64%。然而,看起来西班牙的测试偏差实际上比设想 2 所猜测的还要高。考虑到西班牙患病率的估计上限(49.32%),加上 5%的真实患病率,使用等式 3,我们将得到测试偏差 B= 3.00,与第二位小数的情形 2 相同。这意味着,在西班牙,感染者接受检测的可能性是非感染者的 20 倍。然而,请注意,根据 ENE-COVID19 研究,不是我故意采取的 70%的最坏情况,只有 2.5%的 CoV-2 抗体携带者没有表现出任何症状,另有 4.6%的人表现出两种或更少的症状(怀疑一个人可能被感染的最低要求是三种症状)。这本身就可以解释从情景 1 到情景 2 的转变。
从 ENE-COVID2 研究报告的数据中可以推断出更多关于西班牙检测偏倚情况的详细事实。该研究报告从 60,640 名以前没有接受过 CoV-2 检测的人和 247 名已经接受过检测的人身上采集了样本。在这些人中,只有 4.7%未检测的人有 CoV-2 抗体,而之前检测过的人有 87%。有了这些数字,通过应用贝叶斯定理,我们可以直接使用等式 1,计算出西班牙的真实偏差为 B=4.85 。换句话说,在西班牙,感染者接受检测的可能性几乎是未感染者的 127 倍。测试偏差中一个完整对数单位的增加表明西班牙的上限(通过回归插值)实际上被低估了,应该在 87%左右,而不是回归插值的 49.32%。
上述不匹配的部分原因可归因于回归的使用。然而,这背后还有另一个更令人担忧的原因。不同国家报告的测试数据差异很大(参见此处的了解每个国家的详细信息)。一些国家报告了进行检测的次数,一些国家报告了采集样本的次数,另一些国家报告了接受检测的人数,一些国家报告了其中几项措施,还有一些国家根本没有说明。在西班牙的具体案例中,报告的是进行测试的次数— ,但是请注意,通常会对一个人进行几项测试。累计阳性检测率计算为确诊病例与检测次数的比率。截至今日,西班牙的这一比例为 11.95%。然而,87%的上限与 ENE-COVID19 研究中报告的人数的阳性检测率完全一致。换句话说,在所有只报告检测次数而没有提及实际检测人数的国家中,上限很可能被严重低估。
关于西班牙测试策略的说明应该在这里给出。87%接受检测的人实际上是阳性的——注意这个数字可能更高,因为许多在检测后不久死亡的人不能参加血清阳性反应研究——揭示了一个相当有问题的检测策略。这种偏差如此之大,以至于只能用来确认我们已经几乎可以肯定是谁被感染了。请注意,阳性检测率实际上接近实际检测的灵敏度——这很可能是一个灵敏度为 87%,特异性为 95.3%的检测。换句话说,在西班牙,接受疾病检测的事实本身就构成了对疾病的检测,几乎和检测本身一样可靠!我不认为这是一个非常有用的测试应用。
[……]在爱沙尼亚,感染者接受检测的可能性是未感染者的 68 倍
同样,5 月 6 日,爱沙尼亚塔尔图大学发布了第一波全国新冠肺炎血清学研究的结果。他们在 4 月 24 日开始的七天时间里测试了爱沙尼亚的 2007 名成年居民,他们发现了三例 CoV-2 抗体。这表明截至 5 月 1 日,爱沙尼亚人口的患病率约为 0.15%(95%置信区间[0%–0.32%])。这非常接近爱沙尼亚在情景 2 下的估计值,即 0.51%。如前所述,将抗体数据与爱沙尼亚上限(9.32%)相结合,爱沙尼亚的偏倚估计值为 B =4.23。这相当于说,在爱沙尼亚,感染者接受检测的可能性是非感染者的 68 倍。这确实与爱沙尼亚政府的新冠肺炎检测指南相一致,该指南通常建议仅对有症状的患者进行检测,特别是当他们被认为有风险时(除了进行单独批次的随机检测以评估疾病在全国的传播程度)。与西班牙的回归上限不同,爱沙尼亚的估计值是直接从日常测试数据中计算出来的,但它仍然基于所进行的测试数量——而不是测试的人数——所以它可能被低估了。这意味着测试偏差实际上可能比这更高,也许和西班牙一样高。
此外,由于计算样本数量相对较少,爱沙尼亚的血清阳性率估计值可能不那么准确。我怀疑这个比率的原因是双重的:首先,它的 95%置信区间将包括 0%和两倍以上的比率。第二,爱沙尼亚目前的确诊病例数实际上相当于其人口的 0.13%,而且——正如我在上一篇文章中所主张的——这是终生患病率的绝对最小值。只有 0.15%的流行率非常接近于最小值,这表明爱沙尼亚是相当独特的,因为它发现了几乎所有的 SARS-新冠肺炎病例。
[……]法国的感染者接受检测的可能性“仅仅”是非感染者的 7.79 倍。
最近,来自法国巴斯德研究所的研究人员在科学杂志上发表了一项关于 T2 的详细研究,使用非常详细的人口数据模拟了 CoV-2 在法国人口中的流行情况。这比全国患病率研究低了一步,但仍然是一个非常可靠的估计。他们得出结论,到 5 月 11 日,大约 4.4%的法国人口——95%的置信区间在 2.8%和 7.2%之间——在某个时候感染了 CoV-2。这仅略低于法国在情景 1 下的估计值(5.64%)。使用法国的插值上限(26.39%),将意味着法国实际上具有相当低的测试偏差 B = 2.05 法国的感染者接受检测的可能性“仅仅”是非感染者的 7.79 倍。然而,我们应该对这种偏差估计持保留态度,因为法国的上限(和西班牙的上限一样)是通过对大量测试进行回归而获得的,我们从西班牙的数据中知道这导致了严重的低估。
英国正在发生什么?
在 2020 年 5 月 15 日完成这篇文章时,英国在可以直接从每日测试率计算上限的国家中脱颖而出。其上限是惊人的 77.8%的最大可能终生流行率。英国报告的是每天接受测试的人数,而不是进行的测试,因此上限很可能没有被低估。虽然,正如我已经表明的,即使引入非常小的检测偏倚也会显著降低这一数字——例如,情景 1 下的 36.87%,已经与群体免疫的任何希望相去甚远——即使是高偏倚情景 2 也使英国的估计患病率为 14.91%。我怀疑英国的真实流行率实际上远低于这个数字,可能更接近西班牙的 5%(因为它有非常相似的死亡数字)。这将使英国的检测偏差为B= 4.25——几乎与爱沙尼亚相同,表明一个感染者被检测的可能性是一个非感染者的大约 70 倍。
带回家的信息
在修正上限测量值并更详细地研究阳性检测偏倚的明确测量值时,我必须重申我在 4 月 29 日提出的主要观点——如上所述,这一点已经得到了开始可用的真实流行率研究结果的证实:群体免疫非常遥远,需要很长时间才能达到,直到疫苗可用。因此,重要的是,各国——即使它们已设法控制住了疫情高峰——仍要非常小心,以避免今后再次出现感染。显然,在大多数国家,解除一些限制将成为经济和公共卫生当务之急——正如我在之前的帖子中提到的,**深度经济危机也会导致许多人死亡。然而,在疫苗问世之前,试图完全恢复到疫情之前的常态是鲁莽的。这有可能重演——或者更糟——发生在米兰、马德里、伦敦或纽约医院的悲剧。
“无论如何,最终每个人都会得这种病,所以试图阻止它是没有意义的”这种观点本身就是鲁莽的——尤其是在公共卫生官员的嘴里。它忽略了一个证据,即经历病例的逐渐泄漏是不一样的——在许多国家,这可以通过卫生服务得到很好的控制——因为它将经历突然的压倒性病例雪崩,正如我们已经在意大利、西班牙和其他几个国家看到的那样。在第二种情况下,生命的代价肯定会高得多。
这里进行的计算也强调了拥有可用的每日测试数据的重要性。这是一些国家目前没有做的事情,但这是监测各国疫情进展的一个关键部分。反过来,这对于评估用于控制疫情的不同政策选择的效力至关重要。此外,正如西班牙发布的 ENE-COVID19 研究所表明的那样,各国报告已接受检测的人数和已进行检测的人数至关重要。只有这样,我们才能计算出可靠的跨国数据。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
根除在线用户行为中的异常现象
实践教程
用于识别异常在线活动根本原因的比较马尔可夫链分析
作为一名训练有素的认知神经科学家,我有理解人类行为和信息如何引导决策的经验。现在,随着我转变为一名数据科学家,部分由于我在 Insight 的数据科学奖学金,我开始了解到许多其他在更大范围内跟踪和理解行为的媒介和方法。
在我的研究员生涯中,我为一家软件公司 Lazy Lantern 做顾问,该公司协助其他公司监控客户如何与他们的在线平台互动。更具体地说,Lazy Lantern 为其客户公司提供对其网站和 iOS/Android 应用程序的自动监控和分析,从而了解这些平台上的客户流量、互动和整体行为。
问题
为了理解 Lazy Lantern 如何跟踪客户行为,让我们考虑一个典型零售网站的用户旅程,如下图所示。
图一。这些是反复出现的链接或事件,客户通常会点击这些链接或事件在零售网站上购物。[图片由作者提供]
在主页上,客户可以点击产品列表,然后锁定感兴趣的产品,将该产品添加到购物车中,最后结账。考虑到在给定的时间内,网站上会有许多这样的客户交互,Lazy Lantern 使用时间序列模型 Prophet 来预测给定链接或事件(如产品列表、产品等)的交互率。)在给定时间段内。Prophet 模型每小时评估一次这些事件的预期点击数,并得出给定时间段的预期正常点击数范围。要了解更多关于 Prophet 模型如何在 Lazy Lantern 中使用以及提高其检测效率的方法,请查看我的 Insight 同事 Yeonjoo Smith 的博客这里 。
如果客户与这些链接的交互次数高于或低于模型预测的范围,算法将触发 异常 ,并向客户公司发出警报。虽然该模型能够检测出这些事件中每一个单独的用户交互率的异常,但它无法确定触发的异常是否实际上是平台上事件的连锁反应的一部分。
例如,让我们考虑与以前相同的用户旅程,但这次它被中断了,如下图所示。
图二。有时零售网站上的链接可能会断开,这导致在一系列事件中点击后续链接的用户数量下降。[图片由作者提供]
在这里,客户再次从主页进入,单击产品列表,单击感兴趣的产品,但是由于一些故障,他们无法将产品添加到购物车中。在这种情况下,该算法将对“添加到购物车”和“结账”事件发出异常警报;然而,除此之外,它无法向客户提供任何信息。
在本例中(图 2 ),可能是“添加到购物车”按钮被破坏,这导致了级联效应,导致“结账”按钮也被破坏。然而,该算法只是将这些识别为独立的异常,而不一定是事件之间的重叠和关系。因此,提出了这个项目的中心问题:我们如何识别哪个事件是这些重叠触发异常的潜在根本原因?查明这些连锁异常效应的根本原因将为客户公司提供关于其平台上潜在问题的更细致的反馈,然后他们可以快速解决这些问题,以确保未来的客户满意度,避免不必要的收入损失。
数据
虽然在上面的例子中很容易理解什么事件是问题的根本原因,但实际上,答案是…不那么简单。在调查实际公司平台的客户行为时,会发生多个用户和用户交互,但并非所有用户和用户交互都清晰、整齐地对应于触发的异常。为了建立一个可扩展的、通用的模型来封装跨不同平台和用例的潜在用户交互的复杂性,我必须首先收集相关的数据。
对于给定的客户公司,发生的每个事件异常都存储在 InfluxDB 数据库中,带有相应的事件标签、违规的开始和结束时间以及发生异常的平台(即 web、iOS 或 Android)。累积这些异常计算的原始用户交互存储在 MongoDB 数据库中,按公司和平台划分;其中包含事件标签、用户身份和用户与事件交互的时间戳。
图 3。这里描述的解决方案使用的数据分布在 InfluxDB 和 MongoDB 上。异常事件通过 Prophet 算法聚合,原始事件对应于这些异常事件,是单独的交互。[图片由作者提供]
首先,我评估了异常事件列表,并评估了哪些异常在时间上相互重叠。这些是连锁异常,在真实数据中,它们通常在 2 到 15 个异常事件之间。我们可以将异常之间的时间重叠称为 异常周期 。考虑到我们最初的例子,“添加到购物车”和“结帐”这两个异常事件发生的时间段将导致一个这样的异常时间段,因为它们的警报在时间上重叠。
在生成那些重叠的、连锁的异常的列表之后,我通过在异常时段和原始事件之间进行时间匹配,提取了在结果异常时段内发生的 原始事件 。现在有了这些原始事件,我们可以尝试查明哪个事件是级联异常的起因或根本原因。
解决方案
有了对应于异常时期的原始事件列表,我现在必须找出异常时期的根本原因是什么。异常时期的原始事件数以千计,当然与时期的长度直接相关。因此,当务之急是找到解决根本原因问题的解决方案,即:
- 快速 由于在给定的异常时段内需要解析的事件数量庞大,因此需要部署的解决方案必须省时且易于实施。
- 灵活 因为 Lazy Lantern 有超过 160 家客户公司,每家公司都有多个平台,所以解决方案必须与数据无关,并且不需要过度定制。
考虑到这些限定条件,我的解决方案是利用马尔可夫链模型并进行一些比较分析。马尔可夫链是一个“根据某些概率规则经历从一种状态到另一种状态的转换的数学系统…其中转换到任何特定状态的概率仅取决于当前状态。”为了将这个定义与手头的问题直接联系起来,马尔可夫链模型将能够告诉你在给定的时间段内用户从一个事件转移到另一个事件的可能性。
对于异常时间段,我决定用户如何遍历相关事件,跟踪哪个事件紧跟在前一个事件之后。然后,在对给定事件的所有用户的交互进行平均后,我通过创建逐个事件的马尔可夫矩阵(即矩阵中的所有列总和为 1),生成了用户将从一个事件转移到另一个事件的。
这个转换矩阵在 x 轴和 y 轴上向我们展示了用户在这个异常的时间段内经历的所有原始事件。为了公司数据的匿名性,这些事件在图 4 中用数字表示,但是这些数字本质上对应于初始示例中的事件,例如“将产品添加到购物车”、“结账”等。矩阵中每个单元的值对应于从一个事件(x 轴上编号的事件)遍历到下一个事件(y 轴上编号的事件)的用户比例。
图 4。为了查明异常的潜在根本原因,我进行了比较马尔可夫链分析。在这个分析中,我从一个正常的时间段减去了事件转换,从异常的时间段回溯到正好一周之前。这产生了一个差异得分矩阵,它展示了两个时间段之间的概率变化。该矩阵允许人们看到哪个事件转换(x 轴上的事件到 y 轴上的事件)导致两个时间匹配的时间段之间用户之间的事件转换的最大变化。[图片由作者提供]
既然我已经生成了异常时期的马尔可夫链转移矩阵,我需要某种基线来与之比较。该基线是通过提取在相同的确切时间段内发生的原始事件而获得的,但是回溯到异常时段之前的一周,其中没有检测到异常。我认为这将是一个很好的代理,说明在没有任何站点问题的类似“正常”时间段内,用户的事件遍历是如何发生的。对于这个正常的时间段,我再次以完全相同的方式生成了一个转移矩阵。
现在有了异常时段的转移矩阵和相似时间匹配的非异常时段的转移矩阵,我决定用 比较 它们之间的概率:从异常矩阵中减去正常矩阵。得到的矩阵将由两个时间段的两个概率的增量变化组成(图 4 )。
这个概率差异得分矩阵告诉我们,在两个时间段之间的相同事件之间,用户的转换可能性有多大差异。回到我们最初的例子,如果我们跟踪正常日子里与我们的零售网站互动的客户的转变(图 1 ),然后将其与零售网站行为不当的时间(图 2 )进行比较,从差异得分矩阵中,我们会看到在这两个时间段内转变的比例差异在事件“将产品添加到购物车”和“结账”之间这表明,与网站上的这些事件相对应的最终行动应该得到解决,以便纠正这种异常现象。
这种解决方案是理想的,因为无论客户及其不同的业务类型和事件如何,它都能很好地执行。具体来说,马尔可夫链矩阵只跟踪客户正在交互的事件,因此不知道具体的数据类型。借助该解决方案,我可以明确指出给定客户端平台上的哪些事件或操作导致了通常的流量行为,从而找到异常的根本原因。凭借这种洞察力,Lazy Lantern 可以将客户平台的具体痛点传递给客户,然后客户可以在他们的网站或应用程序上有效地解决这些问题。
产品
为了使解决方案可扩展,我决定创建并部署一个 Streamlit 仪表板。有了这个仪表板,Lazy Lantern 可以在一个地方轻松检查所有客户的消费行为。通过下拉菜单,用户可以选择他们感兴趣的客户端,选择该客户端的特定平台(即 web、iOS 或 Android),然后从 InfluxDB 链接列表中选择该特定客户端和平台的相关异常。在选择了特定的异常之后,从 MongoDB 中提取与该异常及其时间匹配的非异常相对应的原始事件,并部署上述矩阵解决方案。
图 5。Streamlit 仪表盘允许用户专门关注公司、平台和异常情况。结果输出允许判断哪些事件转变导致异常和非异常时间段之间用户行为的最大变化。了解事件转换中的这些变化有助于了解哪些事件可能是异常的根本原因。[图片由作者提供]
仪表板输出结果矩阵,如图 4 所示;Lazy Lantern 可以直观地检查差异矩阵,以发现哪些事件导致了两个时间段之间的变化。此外,仪表板还输出一个摘要图(图 5 ),该图突出显示了导致两个时间段之间最大概率变化(正和负)的前五个事件转换。有了这个摘要,Lazy Lantern 可以快速评估客户平台上的哪些事件转换对客户行为的变化影响最大,并相应地提醒他们的客户。
该仪表板是该解决方案的理想产品,因为人们可以轻松、相对快速地在客户端和异常之间切换,而不必修改内部代码来访问数据并将其与相应的解决方案匹配。
未来考虑
这个项目从构思到实施,历时约三周。虽然这里详细描述的解决方案快速灵活,但有了更多的时间和数据,我的解决方案还可以改进,为用户提供更多定制的反馈。在当前的解决方案中,我只研究了给定平台上事件之间的单步转换。其他需要考虑的是多个步骤的事件链,不仅仅是上一次或下一次点击。这将有助于洞察客户采取的多种类型的“典型”活动路线,例如购买商品的路线,阅读更多关于公司的信息并找到其社交媒体平台的另一条路线。这些高阶马尔可夫链将允许向客户提供更多关于异常用户流量的定制反馈。
补充该解决方案的另一个考虑可能是为每个客户公司训练定制的隐马尔可夫模型,以获得存在于他们平台中的事件状态的表示。这将为我们提供比我们从当前解决方案中得到的快照分布更稳定的事件转移概率分布。然而,这种方法的一个警告是,它不仅需要大量数据来生成模型,而且它不会如此容易或快速地适应客户可能在平台中做出的更改,并且必须不断更新和重新训练。
我要感谢 Lazy Lantern,特别是 Bastien Beurier,给我机会研究这个问题。这是我第一次提供以业务为中心的解决方案,我非常感谢我得到的支持和反馈。这对您刚刚阅读完的数据解决方案和产品至关重要!你可以在我的 GitHub 上找到代码和一些样本数据。
熊猫的样本高于平均值
入门
为您的机器学习对齐不一致的报告数据
图片作者(许可)
许多模型输入累积变量,如几小时内的降雨量或几个月内的公司收入。不幸的是,数据源通常在时间上不一致。一个传感器每隔奇数小时提供数据,另一个在偶数小时提供数据。一家公司在五月提供信息,另一家在六月。
如果您不想等待所有数据源都收集输入数据,或者当不适合向模型提供来自不同时间段的数据时,您必须将测量结果分散到相同的时间段。熊猫本身可以完成部分工作,但在本文中,我们将探索如何用平均值进行上采样,这需要一点额外的编码。
您可以通过 Github 上共享的笔记本运行本教程中的所有示例—up sample _ to _ average . ipynb
重采样
向下采样
python 的 Pandas 中的重采样允许您将频率较高的值转换为频率较低的值— **downsample**
,例如,将每小时的数据转换为每天的总和、计数和平均值,或者将每天的值转换为每月的值。
# downsample:
CAT|DATE|VALUE
abc|0101|10
abc|0102|20
abc|0103|15# downsample
**[IN]:** df.groupby("CAT").resample("W", on="DATE").agg({"VALUE":["sum","count","mean","first","last"]})**[OUT]:** CAT|DATE|SUM|COUNT|MEAN|MIN|MAX|FIRST|LAST
abc|0107|45 | 3 | 15 | 10| 20| 10 | 15
它被称为downsample
,因为数据行的数量减少了。可以申请sum
、count
、mean
(平均)、median
、min
、max
、first
或last
。基于每日输入,您可以重采样到周、月、季度、年,也可以重采样到半月——参见 pandas 文档中重采样选项的完整列表。您还可以对乘法进行重新采样,例如5H
以 5 小时为一组。
向上采样
重新采样到更频繁的时间戳被称为**upsampling**
。你可以把几天变成几小时,或者几个月变成几天。进行上采样时,必须首先将日期时间列设置为数据框的索引(.set_index
),然后才能进行上采样。
# error in case you try upsample using .resample("D", on="col")
**ValueError**: Upsampling from level= or on= selection is not supported, use .set_index(...) to explicitly set index to datetime-like
除上述功能外,上采样还支持backfill/bfill
、ffill/pad
和nearest
。但是如果你认为应用mean
会把每天的值分割成每小时的平均值,那你就错了。所有加起来的样本都用NaN
填充。
为什么我们要向上采样到平均值
假设你有一个商店组合,试着估算一下销售额。您输入Jan-1
、Jan-2
和Jan-3
的收入,并执行回归以猜测Jan-4
的目标值。你对你所有的商店进行训练,并使用模型来预测未来的销售。
但是如果有些商店只提供Jan-2
和Jan-3
的数据呢?其他仅在Jan-1
和Jan-3
上。您可以使用这 3 天中的sum
或average
进行缩减采样和建模,但在这种情况下,您会丢失有价值的输入信息,如周五的收入或周一的收入。
与普遍看法相反,这种情况很典型。当分析公司的基本数据以预测未来的股票价格时,一些公司每季度报告一次,而另一些公司每年报告两次。有些在 11 月,有些在 8 月。如果你等到每个人都提供了他们的数据,你可能会得出一个精确的预测,但那时所有有利可图的股票都会被卖出。
图片作者(许可)
通常 80%的输入保持相同的模式,20%包括一些重要的场景具有不寻常的结构,你必须重新计算。
要解决这些数据泄漏,您可以向上采样到平均值。
用平均值向上采样
我说的是平滑不一致的报告数据的选项,这样您就可以
**[IN]:**
data="""
**CAT|DATE|VALUE**
abc|0101|10
abc|0103|20
abc|0105|15
efg|0102|40
efg|0105|30"""**[OUT]:**
**CAT|DATE|VALUE**
abc|0102|10
abc|0103|10 # 20 on 0103 covers interval 0102-0103 (2 days)
abc|0104|7.5
abc|0105|7.5 # 15 on 0105 covers interval 0104-0105 (2 days)
efg|0103|10
efg|0104|10
efg|0105|10 # 30 on 0105 covers interval 0103-0105 (3 days)
上面的例子很简单,但是想象一下你有几千个类别。有些是每天报告,有些是单双日报告,其余的是每三天或不定期报告。
如何做一般的魔术
为了计算平均值,你需要两个东西——sum
除以count
。您知道总数,因为它已被报告,但从最后一个值算起的天数(月数、周数……)未知。幸运的是,熊猫重采样包含一个参数.group
,它显示了上采样时创建了多少个群组。
不幸的是,它本身不能与groupby
一起工作,所以我们将首先查看单个类别。
data="""
CAT|DATE|VALUE
abc|**0101**|10
abc|**0103**|20
abc|**0106**|15"""
重采样方法有两个属性:
indices
—显示输入数据出现的位置groups
—用组索引对每个日期时间值进行索引。
# indices
[In]: df.set_index("DATE").resample("D").**indices**
[Out]:
defaultdict(list,
{Timestamp('1900-01-**01** 00:00:00', freq='D'): [0],
Timestamp('1900-01-**03** 00:00:00', freq='D'): [1],
Timestamp('1900-01-**06** 00:00:00', freq='D'): [2]})# groups
[In]: df.set_index("DATE").resample("D").**groups**
[Out]:
{Timestamp('1900-01-01 00:00:00', freq='D'): 1,
Timestamp('1900-01-02 00:00:00', freq='D'): 1,
Timestamp('1900-01-03 00:00:00', freq='D'): 2,
Timestamp('1900-01-04 00:00:00', freq='D'): 2,
Timestamp('1900-01-05 00:00:00', freq='D'): 2,
Timestamp('1900-01-06 00:00:00', freq='D'): 3}
1 月 1 日和 2 日形成第一组,3 日至 5 日是第二组,最后一个数据样本属于最后一组。大多数情况下,报告的数据包含报告日期的值—1 月 3 日报告的 20 个数据涵盖 1 月 2 日和 1 月 3 日。在这种情况下,您使用label
参数并将其设置为right
。
# groups
[In]: df.set_index("DATE").resample("D", label="right).**groups**
[Out]:
{
Timestamp('1900-01-02 00:00:00', freq='D'): 1,
Timestamp('1900-01-03 00:00:00', freq='D'): 1,
Timestamp('1900-01-04 00:00:00', freq='D'): 2,
Timestamp('1900-01-05 00:00:00', freq='D'): 2,
Timestamp('1900-01-06 00:00:00', freq='D'): 2,
Timestamp('1900-01-07 00:00:00', freq='D'): 3,}
或者,您可以将组转换成数据帧,并移动值
df_groups = pd.DataFrame(df.set_index("DATE").resample("D").groups, index=["group"]).T.shift(1)
然后你计算每组中出现的次数。
s = df_groups.groupby("group").size()
s.name = "count"
并将计数与日期和回填值连接起来。它会生成一个数据帧,其中包含该时间段的总和以及该时间段内的发生次数,这就是计算平均值所需的全部内容。
如果你现在兴奋地大叫,坚持住,我们还没有到达终点。我们已经计算了单个组的平均值,但是如果我们想要groupby
多个类别,例如,当我们有许多商店、公司或传感器要处理时,我们必须分别计算每个组的平均值。
这并不复杂,但如果您有许多输入,这可能会很耗时。参见下面的代码:
您已经将数据平滑到平均值,但通常您不需要每个月的平均值。您只需要涵盖不同的报告期。例如,在审查上市公司业绩的财务分析中,大多数公司在季度末报告数据。但是有些是在不同的月份,甚至不是每季度。如果你想对一大堆公司的行为建模,你首先要对那些没有季度报告的公司进行平滑平均,然后使用rolling
函数将输入限制为仅季度。
更多的输入意味着更多的模型参数和更长的计算时间
让我们看一下股票市场分析的例子:
编码再次让我们感到惊讶。当您对天应用.resample("D", label="right")
重采样时,结果与.resample("D", label="right", **closed="left"**)
相同。如果在重新采样到月时做同样的操作,label="right"
与label="right", **closed="right"**
相匹配。因此,您必须为每月计算指定label="right", closed="left"
,或者使用上述带有shift
的变通方法。
结论
我希望你不仅学到了关于重采样的知识,还学到了在输入机器学习模型时如何使用替代方法来对齐不一致的数据。
The images were with [canva.com](https://partner.canva.com/vdek) (affiliate link, when you click on it and purchase a product, you won't pay more, but I can receive a small reward; you can always write canva.com to your browser to avoid this). Canva offer some free templates and graphics too.
Other articles:
* [Everything you wanted to know about Kfold train-test split](/complete-guide-to-pythons-cross-validation-with-examples-a9676b5cac12)
* [Why it's worth considering another file types than csv](/stop-persisting-pandas-data-frames-in-csvs-f369a6440af5)
* [How to turn a list of addreses into a map](/pythons-geocoding-convert-a-list-of-addresses-into-a-map-f522ef513fd6)Great thanks to [Towards data science](https://towardsdatascience.com/)
Github 上的完整代码—up sample _ to _ average . ipynb。
镦粗是自维恩图以来最伟大的可视化设置
一个新的 R 包,用于查看复杂数据中的交叉点
作者图片,灵感来自一张来自原始论文的图片
我坚信翻转器是我见过的最漂亮、最直观的大型复杂集合交集可视化。
维恩图让我微笑,但冷门让我感到强大。冷镦机可以可视化维恩图只能梦想的数据。
但首先,让我们回顾一下文氏图。
维恩图综述
维恩图在我们今天的文化中无处不在。它们易于阅读,能有效地传递信息,而且玩起来也很有趣。但是如果你想形象化三个以上的类别,你会怎么做?
让我们看一个简单的例子。
假设我们有一个关于世界各国的数据集,我们有每个国家的一些信息。
这是一个愚蠢的例子,但信息是准确的
将不同国家之间的相似性和差异可视化的维恩图可能如下所示:
作者图片
这张图看起来很漂亮,但我不能代表太多,它会很快变得杂乱无章。
如果我想比较另一个国家呢?嗯,我运气不好。你真的想尝试破译类似这种的东西吗?这个呢?
“史蒂夫·米勒·维恩图:你是一个采摘者、一个微笑者、一个情人、一个罪人、一个小丑、一个吸烟者还是一个午夜吸烟者? dullhunk 的(艺术家未知)由 2.0 在 CC 下授权
是啊,我不这么认为。
介绍:冷镦机
UpSet 是一种非常新的可视化技术,它通过用条形图以表格形式呈现信息来解决这个问题。你可以在每一个类别中拥有你想要的任意多的东西,并且很容易找到它们之间的交集。UpSetR 是实现它的一个 R 包。
有一个来自 IMDB 的数据集,看看有多少部电影有相同的演员,他们是谁?没问题!想看看癌症患者的基因中是否有相同的一组突变,它们是什么?颠覆者为你而来!
UpSetR 最适合在包含大量要素的复杂数据集中查找模式。这是通过将不同要素中具有许多相同值的数据点分组来实现的。也就是说,冷镦机寻找最大的相交集。
对于已经是二进制的变量(这意味着两个类别),或者可以转换成二进制的变量,这是最好的。需要注意的是,一键编码可以将任何分类特征转换为二进制特征。事实上,目前的实现只适用于二进制变量。
例如:心理健康数据
我正在为这个 Kaggle 数据集开发一个分类模型,我试图理解不同的列是如何相互关联的。
数据集包含了科技公司对心理健康的态度,以及员工心理健康的信息。调查数据包含了从雇主是否提供心理健康福利到员工自己是否接受过心理健康治疗的所有问题的答案。
在这一点上,还不清楚这些特性是如何相互关联的,我想知道发生了什么。
之前,我已经清理了一些数据,所以现在我将把它输入到 R 中。然而,在我创建颠覆可视化之前,我想一次性编码我的数据,因为它大部分是分类数据。
一键编码
one-hot encoding 是一种通过创建新列将分类变量转化为二进制变量的方法。例如,我们的 work_interfere 栏有 3 个选项:经常、有时、从不。在我们一次性编码我们的数据后,我们将有 3 列:work _ interfere _ occurly,work _ interfere _ sometimes,work_interfere_never,如果该值适用,则每一列包含 1,如果不适用,则包含 0。如果你想了解更多,网上有很多很棒的教程。
下面是 R 代码:
data = read.csv('survey_data.csv', na.strings="Not Applicable")#install packages (can skip if already installed)
install.packages("mltools")
install.packages("data.table")
install.packages("UpSetR")#one-hot encode
library(mltools)
library(data.table)
newdata <- one_hot(as.data.table(data))#create the visualization
library(UpSetR)
upset(newdata, order.by=”freq”, main.bar.color = “#995ee1”, sets.bar.color = “#995ee1”, group.by = ‘degree’)
您可以在此下载调查数据。
你会得到这个可爱的东西:
作者图片
如何解读
左侧栏
在左侧,有代表每个集合的总大小的条。在性别 _ 男性的案例中,我们可以看到大约有 950 名调查受访者认为自己的性别是男性。这些集合是不分离的——也就是说, mental_interview_No 包括所有对“你会在面试中向潜在雇主提出精神健康问题吗?”这个问题回答“不”的人,无论性别如何
顶栏
在顶部,我们可以看到每个交叉集合的大小。如果黑点被填充,则该类别包含在集合中。如果圆点是灰色的,则该类别不在集合中。注意集合是不相交的,这意味着它们是不重叠的。你可以在顶部的横条中看到每个数据点,不像左边的横条。
示例 1: 由于左起第一个条上的所有点都已填写,该条代表对由性别变量表示的问题回答为男性的所有 475 人,对心理 _ 健康 _ 面试、观察 _ 结果和自雇者,以及对技术 _ 公司回答为“是”。
示例 2: 然而,右边第二组代表一名单身男子( Gender_Male ),他没有听说过或观察到患有精神健康疾病的同事在其工作场所造成的负面后果(OBS _ result),但是一家科技公司的自营职业者,并将在采访中提及精神健康问题。我们知道这位工人是个体经营者,并且会在采访中提到精神健康,这是基于可视化中某些点没有被选中的事实以及我们对其他可能选项的了解。
在这个可视化中,考虑在可视化中没有出现的信息非常重要,就像第二个例子一样。在某些情况下,这是最有趣的部分。
心烦意乱的形象告诉我们
我们来看左起第一列(例 1 )。
我知道我有大约 1200 个数据点,其中 988 个是男性。有 475 名男性表示,他们不会在面试中向潜在雇主提出心理健康问题mental _ health _ interview _ No,他们目前在一家科技公司工作 tech_company_Yes ,他们没有听说或观察到工作场所有心理健康问题的同事会带来负面后果OBS _ result _ No,他们也不是自由职业者自由职业者 _No ,这一事实意义重大,因为显示,近一半的男性(48
如果你把对这四个问题做出相同回答的 132 名非男性加入进来,就像我们在左起第二列看到的那样,那么你会发现整个数据集中有将近一半的人对这四个问题做出了完全相同的回答(48%)。
释义
这些结果告诉我,人们,尤其是男性,不会在工作场所公开谈论心理健康。这是一个有趣的初步发现。
潜在的改进
如果我想改进我的分析,我可以将序数变量(具有顺序感的变量,如从 1 到 5 的范围,或“没有、一些、很多”)转换成二元变量,通过宁滨(将相关值分成两个复合类别)保留一些层次感。这将允许他们更强烈地考虑到 upser 的分析中,因为 upser 可以考虑的选项更少。
总结想法
我很喜欢 UpSetR 软件包,认为这是进行探索性数据分析的一种很好的方式。它的文档很不错,并且有一个可用的 Python 版本。
如果您有任何问题或意见,请联系我们!我希望你能像我一样喜欢这种想象。
城市无人机:设施定位问题
当成群的无人机涌入我们的城市时会发生什么,为什么城市规划者应该关心?
城市需要无人机吗?
根据美国联邦航空局的一份报告,到 2021 年,预计将有 447 万架小型无人机在美国运营,高于今天的 275 万架。自 2017 年以来,已经有超过 100 万无人机所有者在美国联邦航空管理局(FAA)注册。到目前为止,正如预期的,商业无人机购买量快速增长的主要驱动力是它们的高机动性和在计算机视觉中的应用:在危险区域拍照,建筑物检查,交通监控,摄影测量等。
然而,这仅仅是开始。预计无人机将在未来的城市中执行重要任务:如果一座桥梁即将倒塌,一场火灾正在蔓延或一个人陷入困境,它们将立即提供从天空鸟瞰的报告。它们将补充我们的运输系统,把东西搬来搬去,或者把人快速送到某个地方。事实上,亚马逊的 Prime Air 无人机送货服务已经处于开始运营前的最后开发阶段。无人机也将是长着翅膀的机器人,执行诸如修桥或救火等任务。
在本帖中,我们将讨论无人机将如何影响城市,以及城市规划者将如何扩展他们的专业知识范围,以便能够处理城市空域、城市空中交通及其与传统城市空间的相互作用。我们将通过解决无人机站在一个城市中的高效放置问题,并查看不同的城市空中交通配置如何导致不同的操作区和城市机动性来实现这一点。
为什么城市规划者应该关注?
到目前为止,我们大多数人只是偶尔见过无人机。但是,当成群的无人机涌入我们的城市时,会发生什么?我们可以充满信心地预计,无人机的大规模部署将给规划、管理和设计可持续城市带来一些重大挑战。无人机技术的大规模扩散将对我们城市的本质产生影响。某些类型的无人机应用将需要新的物理基础设施。
无人机系统可能会影响建筑物的设计和建造方式。例如,如果无人机对接站将被放置在建筑物的屋顶上,那么屋顶将必须易于人类接近,同时也便于运输货物进出。新建筑的设计必须考虑到这一点(例如,增加内部或外部电梯井)。改造旧建筑以适应新环境也是一个严峻的挑战。还需要解决对建筑环境的视觉影响。
将出现新型基础设施,如形成无人机移动网络的客运和物流枢纽,以及配备有雷达、 信号干扰机 和 无人机捕捉技术 的地面反无人机系统,用于打击具有流氓或危险行为的无人机。必须通过地理围栏指定并强制执行关键基础设施和建筑物(如政府大楼、机场或监狱)上空的禁飞区。将所有这些与现有的建筑环境相结合,并为其运作创建必要的监管框架,将对建筑师、城市规划者和决策者的日常实践产生重大影响。
高度自动化的无人机操作将需要固定的起降坞站,集成充电或加油系统。这可能是一个放置在建筑物顶部的移动或永久车站,与现有的交通基础设施或其他类型的基础设施(如小型车站的灯柱)相结合。这些扩展坞很可能会集成电池充电功能。鉴于大多数发达国家的能源政策,必须考虑和认真规划飙升的电力需求对电网和相关排放的影响。
例如,私人拥有无人机的成本可能比租赁无人机的成本要高得多,尤其是对于那些可能只需要无人机执行单一任务的公司。然而,随着全市租赁系统的到位,城市、公司和用户将不需要购买无人机,有效地在他们之间分配成本。因此,基于遍布城市的无人机港口(或站)系统规划无人机租赁服务是必要的。通过提供在无人机站等待的分布式自主无人机的公共无人机租赁服务,这可以减少空中无人机的总数以及利用无人机完成城市服务、公民和其他用户请求的任务的总成本。这意味着有必要解决许多其他问题中的下列问题:
- 在哪里放置扩展坞?
- 他们有多少人?
- 凭什么能力?
设施选址问题
上述问题可以在数学优化的帮助下得到解答,特别是用线性规划如果公式化为容量受限设施选址问题。
后者是为工厂、仓库、发电站或其他基础设施选址的经典优化问题。一个典型的设施选址问题涉及在潜在可用的地点中确定最佳地点,服从特定的约束,该约束要求在几个地点的需求由开放的设施服务。与此类计划相关的成本包括通常与从设施到需求地点的距离总和成比例的部分,以及与设施的开放和维护成本成比例的部分。该问题的目标是选择设施位置,以最小化总成本。设施的服务能力可能有限,也可能有限,这将问题分为有能力和无能力两种情况。
给点上下文吧!
想象一下这样一种情况,我们的任务是为在埃里温市放置无人机停靠站草拟一份概念计划。具有城市中每日(每小时、每周或每月)名义需求的空间分布(出于演示目的,出租车需求被用作替代):
以及许多安装无人机站的潜在地点(在我们的示例中有 30 个):
我们如何确定放置扩展坞的最佳位置?嗯,这显然取决于成本。
第一类成本是购买和安装扩展坞。为了简化问题,让我们假设 Alonso 的单中心城市模型,根据该模型,房地产价格随着与中央商务区的距离增加而按照某种指数或幂衰减规律下降:
这显然是一种权衡:虽然大部分需求在空间上集中在中心位置(见需求图),因此在中心位置安装扩展坞以降低传输成本是有意义的,但相反,我们会因选择中心位置而产生更高的成本(虽然价格是根据一些常识选择的,但它们仅用于演示目的)。
第二类成本是操作无人机的成本,可以安全地假设这与飞行距离成比例。然而,这里事情变得有趣了,这些距离将取决于底层(实际上是上层所在)的城市空中交通路径方式!在下图中,我们可以看到空中交通简单配置的两个例子,笛卡尔网格( A )和迷宫式布局( B ):
让我们再看两个例子:上面网格的最小生成树,通常用于在通信网络中建立物理线路以减少总线路长度,以及实际的埃里温街道网络,因为现实场景之一是无人机将直接在现有街道网络上方运行,以减少视觉污染并出于安全原因( D )。
由于四个空中交通路径系统如此不同,我们可以直观地预期无人机站选址问题的解决方案也会产生差异。
数学公式
为了验证这一点是否正确,解决方案之间的比较,以及这对未来的城市规划者和交通工程师意味着什么,我们需要解决一个线性优化问题。考虑 n 个客户 i = 1,2,…,n 和 m 个地点放置无人机对接站 j = 1,2,…,m 。将连续变量 Xij ≥ 0 定义为从无人机站 j 到客户 i 的服务量,如果无人机站安装在位置 j 处,则定义为二进制变量 Yj = 1 ,否则定义为 Yj = 0 。容量受限的设施位置问题的整数优化模型现在可以公式化如下:
该问题的目标是最小化无人机站安装成本和无人机运行成本的总和。第一组约束要求严格满足每个客户的需求。每个无人机站 j 的能力受到第二组约束的限制:如果安装了无人机站 j ,则考虑其能力限制;如果没有安装, j 满足的需求为零。第三组约束强加了可变的上限。尽管它们是多余的,但它们产生了比等价的较弱公式更严格的线性规划松弛(线性规划的很好的介绍可以在这里找到)。为了直观地了解这些问题是如何解决的,这篇维基百科文章提供了一个相当好的初步概述。幸运的是,有许多优秀的数学优化求解器。让我们看看如何用 Python 自己编码:
from pulp import *
COSTUMERS = positive_flow_inds # the demand vector
potential_stations = np.random.choice(COSTUMERS,30) #choose 30 potential sites
STATION = ['STATION {}'.format(x) for x in potential_stations]
demand = dict(polyflows[polyflows.inflow>0]['inflow']) #setting up the demand dictionary
STATION_dict = dict(zip(STATION, potential_stations))
#installation cost decay from center (given a vector of distances from a central location)
costs_from_cen = 150000 - 1.5*dists_from_cen**1.22
install_cost = {key: costs_from_cen[val] for key, val in STATION_dict.items()} #installation costs
max_capacity = {key: 100000 for key in FACILITY} #maximum capacity
#setting up the transportation costs given a distance cost matrix (computed as pairwise shortest paths in the underlying air
#traffic network)
transp = {}
for loc in potential_stations:
cost_dict = dict(zip(COSTUMERS, costmat_full[loc][COSTUMERS]))
transp['STATION {}'.format(loc)] = cost_dict
# SET PROBLEM VARIABLE
prob = LpProblem("STATIONLocation", LpMinimize)
# DECISION VARIABLES
serv_vars = LpVariable.dicts("Service",
[
(i,j) for i in COSTUMERS for j in STATION
], 0)
use_vars = LpVariable.dicts("Uselocation", STATION, 0,1, LpBinary)
# OBJECTIVE FUNCTION
prob += lpSum(actcost[j]*use_vars[j] for j in STATION) + lpSum(transp[j][i]*serv_vars[(i,j)]
for j in STATION for i in COSTUMERS)
# CONSTRAINTS
for i in COSTUMERS:
prob += lpSum(serv_vars[(i,j)] for j in STATION) == demand[i] #CONSTRAINT 1
for j in STATION:
prob += lpSum(serv_vars[(i,j)] for i in COSTUMERS) <= maxam[j]*use_vars[j]
for i in COSTUMERS:
for j in STATION:
prob += serv_vars[(i,j)] <= demand[i]*use_vars[j]
# SOLUTION
prob.solve()
print("Status: ", LpStatus[prob.status])
# PRINT DECISION VARIABLES
TOL = .0001 #tolerance for identifying which locations the algorithm has chosen
for i in STATION:
if use_vars[i].varValue > TOL:
print("Establish drone station at site ", i)
for v in prob.variables():
print(v.name, " = ", v.varValue)
# PRINT OPTIMAL SOLUTION
print("The total cost of installing and operating drones = ", value(prob.objective))
四个解决方案
解决上述优化问题产生了配置 A 和 B 的以下解决方案:
对于 C 和 D :
现有街道网络配置的小动画,用于说明系统动态:
我们从图中看到,尽管所有四种布局都有一个共同的优化模式,无人机站的最佳数量大致相似(从 8 到 11),大型供应商站的空间聚类也相似(较大的圆圈表示较大的供应量),但最佳位置和需求覆盖区域(以颜色显示)有很大不同!
这意味着空中交通路径设计的微小变化会对无人机站的最佳位置、每个站覆盖的地理区域以及不同区域的空中交通量产生巨大影响。我们也可以看看每个航空系统的最佳总成本。特别是,我们发现最好的路径系统是笛卡尔网格(~ 250 万美元),然后是现有的街道网络(~ 410 万美元),然后是迷宫系统(~ 450 万美元),最差的是其最小生成树(~ 600 万美元)。我们看到结果暗示了未来规划者将不得不面对的权衡:成本对安全对美观对实用性。
结论
在这篇文章中,我们试图提高建筑师、城市规划者和政策制定者对无人机技术即将给我们的城市带来的巨大变化的认识和警觉。我们研究了埃里温的案例,并解决了一个简单的数学优化问题,以找到无人机停靠站的最佳位置来满足需求(包括商业和城市运营,如紧急服务)。我们看到了城市空间规划的差异如何对上述问题的解决产生巨大影响。与城市街道空间不同,城市街道空间的大部分存在都是逐渐演变的,城市空气空间必须在相对较短的时间框架内进行规划、设计和部署。
在现实环境中解决设施选址问题时,显然会有更多的变量需要考虑,这使得优化问题更难解决。例如,在我们的例子中,我们假设了一次性需求结构,而在大多数现实世界的设置中,需求是不稳定的,需要随机优化。
然而,这篇文章的目的不是提供解决无人机站选址问题的手册(让我们把它留给运筹学专业人士),而是展示它对城市空间和移动性的影响,并指出扩展城市规划者和其他城市爱好者兴趣范围的必要性。
附注:你可以在这里找到更多关于主题的信息。
基于 Python 的城市物流网络仿真
使用 SimPy、OSMnx 和 fleet . js 构建 Anylogic 的 GIS 功能
Anylogic 可能是目前最流行的物流应用模拟软件包之一。一个非常好而且非常独特的特性是可以将 GIS 地图包含到模拟模型中。它允许在地图上放置模拟元素,并根据真实的空间信息沿现有路线移动它们。这很酷,因为它可以用来模拟整个供应链,包括为复杂的问题提供一个伟大的,有形的可视化的手段。例如,项目使用 Anylogic 评估法国格勒诺布尔市中心更可持续的城市物流网络的不同设计和交付方案。数据驱动的模拟模型允许计算多层供应链网络中各种转运节点位置和不同类型运输设备的 KPI。
随着该功能的成功,Anylogic 的家伙们甚至构建了anylistix,将预先构建的&可定制模拟模型与商业求解器相结合,用于集成供应链规划&优化。
显然,那些商业特性是有代价的,所以我们来看看这种模式是否也可以用不同的手段来实现。
场景和范围
这个职位的模拟模型将基于一个小型的案例研究。
面对人类越来越习惯于甚至是日常必需品的送货上门这一事实,汉堡阿尔托纳的法国面包店 Die Patisserie 想要为附近的顾客提供甜点。
确定了 3 个主要购买者:失物招领处中央基金会、猴子音乐俱乐部和出版社卡尔森出版社。
不同位置的坐标(纬度、经度):
- 法式蛋糕店(53.55668,9.92815)
- 中央公园(53.55817,9.92829)
- 猴子音乐俱乐部(53.55706,9.93161)
- 卡尔森出版社(53.55703,9.92684)
为了简单起见,假设访问节点的顺序是固定的。旅游的起点和终点都在蛋糕店(1。):
作为旅程的一部分要访问的节点
仿真模型
简单场景的模拟模型是通过以下方式创建的:
- 用于检索地理信息和计算最短路径的 OS mnx/networkx(Python)
- SimPy/Casymda 用于模拟游览(Python)
- 基于浏览器的动画(JavaScript)的传单. js
1.OSMnx
令人惊叹的 OS mnx T1 包提供了从 OpenStreetMap 获取街道网络的 T2 网络图 T3 的可能性。通过指定要包括的 OSM 节点的中心和距离,可以获得我们场景的相关部分:
CENTER = (53.55668, 9.92815)
DISTANCE = 300
G = ox.graph_from_point(CENTER, distance=DISTANCE, network_type='drive')
OSMnx 让我们为旅游的 4 个地点中的每一个选择最近的 OSM 节点,并且还提供了绘制网络的方便方法。蓝点代表由边连接的 OSM 节点。4 个相关位置以红色显示:
提取的街道网络的 OSMnx 图
为了准备仿真模型所需的所有信息,现在使用 networkx 计算网络中 4 个相关节点之间的所有最短路径,并且包括每条路线的所有分段线性段的详细信息。结果被保存到磁盘上,以避免每次运行模型时进行提取和重新计算(当然,这也是为了尽可能降低 OSM 服务器的负载)。
上述方法可以被改进,例如,通过从给定的相关位置自动确定要加载的区域。不是为每个相关位置选择最近的 OSM 节点,而是首先寻找网络中最近的边会更精确。随着网络规模的增长,从 OSM 服务器直接查询相关节点之间的最短路径可能是一个更好的主意,而不是获取整个网络(Anylogic 似乎就是这样做的)。
2.Casymda/SimPy
Casymda 在 SimPy 之上提供了基于块的离散事件模拟模型建模。
我们的模型可以用一个简单的流程来描述:
模拟的流程模型
卡车实体在参数化的Source
中创建,然后在自定义的DriveTour
模块中处理,该模块包含根据路线长度和卡车移动速度计算时间的逻辑。它还提供了为动画计算中间实体位置的选项(时间间隔取决于模拟运行的实时因子)。模拟模型也可以在不调度任何动画相关行为的情况下运行,以最小化执行时间。要访问的节点及其顺序通过文本注释stops=["ZFB", "MMC", "CAV"]
指定。
动画是通过 flask 暴露信息和资源实现的(类似于本帖中描述的基于 tile-map 的动画)。
3.传单. js
为了可视化地图上节点和实体的位置,传单只需要几行。为了设置旋转角度,有一个旋转。标记插件满足我们的需求。
marker = L.marker(element.coords, { icon: new L.Icon({iconUrl: element.icon_path}) }).addTo(map);
marker.bindPopup(element.text);
marker.setRotationAngle(element.direction);
结果
从克隆的存储库中通过 http://localhost:5000 运行模拟:
docker-compose up geo-web-animation
下面的截屏显示了一辆卡车按照定义的顺序( Patisserie —失物招领—Monkey ' s—Carlsen Publishing—Patisserie)访问所有节点的完整旅程。单行道被正确地考虑在内,例如当从猴子音乐俱乐部 (3。,最右边的节点)到卡尔森出版社 (4。最左边的节点)沿着线。
基于浏览器的动画的屏幕截图
基于神经网络的城市声音分类
使用深度学习进行声音分类
每天我们都会听到不同的声音,这是我们生活的一部分。人类可以很容易地区分不同的声音,但是如果计算机也能把声音分类,那该多好啊。
在这篇博文中,我们将学习使用带有神经网络的机器学习对城市声音进行分类的技术。该数据集取自一个名为城市声音的分析视频竞赛。该数据集包含 8732 个标记的城市声音摘录,来自 10 个类别:空调、汽车喇叭、儿童玩耍、狗叫、钻孔、发动机空转、枪击、手提钻、警笛和街头音乐。
我将使用 python librosa 库从音频剪辑中提取数字特征,并使用这些特征来训练神经网络模型。
首先,让我们得到所有需要的库,
**import** **IPython.display** **as** **ipd**
**import** **os**
**import** **numpy** **as** **np**
**import** **pandas** **as** **pd**
**import** **matplotlib.pyplot** **as** **plt**
**import** **librosa**
**from** **tqdm** **import** tqdm
**from** **sklearn.preprocessing** **import** StandardScaler
**from** **keras.models** **import** Sequential
**from** **keras.layers** **import** Dense, Dropout, Activation
**from** **keras.optimizers** **import** Adam
数据集可以在 google drive 中找到,可以从这里下载。
数据集包含保存声音摘录的 train、test 文件夹,并且存在具有每个声音摘录的标签的 train.csv 和 test.csv。我将只使用训练文件夹进行训练、验证和测试,它包含 5435 个标记的声音。
现在让我们阅读 train.csv,它包含有关声音摘录的标签信息。
data=pd.read_csv('/content/drive/MyDrive/colab_notebook/train.csv')data.head()#To see the dataset
让我们听听数据集中的任何随机声音,
ipd.Audio(‘/content/drive/My Drive/colab_notebook/Train/123.wav’)
现在,主要步骤是从数据集中提取要素。为此,我将使用 librosa 库。这是一个很好的音频文件库。
使用 librosa 库,我将从音频文件中提取四个特征。这些特征是 mel 倒谱系数(MFCCs)、tonnetz、Mel 标度谱图和来自波形的色谱图。
mfc=[]
chr=[]
me=[]
ton=[]
lab=[]
**for** i **in** tqdm(range(len(data))):
f_name='/content/drive/My Drive/colab_notebook/Train/'+str(data.ID[i])+'.wav'
X, s_rate = librosa.load(f_name, res_type='kaiser_fast')
mf = np.mean(librosa.feature.mfcc(y=X, sr=s_rate).T,axis=0)
mfc.append(mf)
l=data.Class[i]
lab.append(l)
**try**:
t = np.mean(librosa.feature.tonnetz(
y=librosa.effects.harmonic(X),
sr=s_rate).T,axis=0)
ton.append(t)
**except**:
print(f_name)
m = np.mean(librosa.feature.melspectrogram(X, sr=s_rate).T,axis=0)
me.append(m)
s = np.abs(librosa.stft(X))
c = np.mean(librosa.feature.chroma_stft(S=s, sr=s_rate).T,axis=0)
chr.append(c)
我有 186 个功能,每个音频文件都有各自的标签。
从音频文件中提取特征后,保存特征,因为提取特征将花费大量时间。
mfcc = pd.DataFrame(mfc)
mfcc.to_csv('/content/drive/My Drive/colab_notebook/mfc.csv', index=**False**)
chrr = pd.DataFrame(chr)
chrr.to_csv('/content/drive/My Drive/colab_notebook/chr.csv', index=**False**)
mee = pd.DataFrame(me)
mee.to_csv('/content/drive/My Drive/colab_notebook/me.csv', index=**False**)
tonn = pd.DataFrame(ton)
tonn.to_csv('/content/drive/My Drive/colab_notebook/ton.csv', index=**False**)
la = pd.DataFrame(lab)
la.to_csv('/content/drive/My Drive/colab_notebook/labels.csv', index=**False**)
将特征连接成一个数组,以便传递给模型。
features = []
**for** i **in** range(len(ton)):
features.append(np.concatenate((me[i], mfc[i],
ton[i], chr[i]), axis=0))
对标签进行编码,以便模型能够理解。
la = pd.get_dummies(lab)label_columns=la.columns #To get the classestarget = la.to_numpy() #Convert labels to numpy array
现在归一化的特点,使梯度下降可以更快地收敛。
tran = StandardScaler()
features_train = tran.fit_transform(features)
现在,我将创建训练、验证和测试数据集。
feat_train=features_train[:4434]
target_train=target[:4434]
y_train=features_train[4434:5330]
y_val=target[4434:5330]
test_data=features_train[5330:]
test_label=lab['0'][5330:]print("Training",feat_train.shape)
print(target_train.shape)
print("Validation",y_train.shape)
print(y_val.shape)
print("Test",test_data.shape)
print(test_label.shape)
下一步是建立模型。
model = Sequential()
model.add(Dense(186, input_shape=(186,), activation = 'relu'))
model.add(Dense(256, activation = 'relu'))
model.add(Dropout(0.6))
model.add(Dense(128, activation = 'relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation = 'softmax'))
model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer='adam')
这是将用于培训的最终模型。
history = model.fit(feat_train, target_train, batch_size=64, epochs=30,
validation_data=(y_train, y_val))
该模型将针对 epoch =30 进行训练,并且批量大小为 64。
在训练模型之后,它给出了 92%的验证准确度。
现在让我们看看我们的模型将如何在测试数据集上执行。
predict = model.predict_classes(test_data) #*To predict labels*
这将获得现在的值,以获得作为类的预测。
prediction=[]
**for** i **in** predict:
j=label_columns[i]
prediction.append(j)
预测有 104 个测试标签,现在计算有多少是正确预测。
k=0
for i, j in zip(test_label,prediction):
if i==j:
k=k+1
在 104 个标签中,这个模型已经正确预测了 94 个标签,这是非常好的。
在这篇博客中,我们讨论了如何使用 librosa 库从音频文件中提取特征,然后建立一个模型来将音频文件分类到不同的类别中。
本文中的所有代码都驻留在这个 Github 链接上:
permalink dissolve GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/shubham7169/Projects/blob/master/Urban Sound Classification.ipynb)
基于 Librosa 的城市声音分类——复杂的交叉验证
使用 scikit-learn 展示“将一个群体排除在外”策略
作者图片[Marc Kelechava]
概述
这篇文章的目的有两个:
- 我将展示一个实现一篇有趣的研究论文的结果的例子,该论文基于音频片段的声音内容对它们进行分类。这将包括 librosa 库的应用,librosa 库是一个用于音乐和音频分析的 Python 包。剪辑是来自城市的短音频剪辑,并且分类任务是预测适当的类别标签。
- 我将展示有效的交叉验证方案的重要性。鉴于我将使用的音频源数据集的细微差别,很容易从录音中意外泄露信息,这会使您的模型过拟合,并阻止其泛化。这个解决方案有点微妙,所以看起来是一个写博客的好机会。
原始研究论文
http://www . justinsalamon . com/uploads/4/3/9/4/4394963/salamon _ urban sound _ acmmm 14 . pdf
论文作者的源数据集
【https://urbansounddataset.weebly.com/urbansound8k.html
他们的数据集摘要
“该数据集包含来自 10 个类别的城市声音的 8732 个标记的声音摘录(< =4s) ):空调、汽车喇叭、儿童玩耍、狗叫、钻孔、发动机空转、枪击、手提钻、警笛和街头音乐。这些类别来自城市声音分类法。
我将从这些声音摘录中提取特征,并安装一个分类器来预测 10 个类别中的一个。我们开始吧!
关于我的代码的注释
我创建了一个回购协议,允许您完整地重新创建我的示例:
- 脚本运行器:https://github . com/Marc muon/urban _ sound _ classification/blob/master/main . py
- 特征提取模块:https://github . com/Marc muon/urban _ sound _ classification/blob/master/audio . py
- 模型模块:https://github . com/Marc muon/urban _ sound _ class ification/blob/master/Model . py
脚本运行器处理从磁盘加载源音频,解析关于源音频的元数据,并将该信息传递给特征提取器和模型。
下载数据
您可以使用研究论文作者提供的表格下载数据,该数据可提取至 7.09 GB:https://urban sound dataset . weebly . com/download-urban sound 8k . html
目录结构[可选部分—如果您想自己运行它]
显然,您可以派生代码并将其重新映射到您想要的任何目录结构,但是如果您想要遵循我的:
- 在你的主目录中:创建一个名为数据集的文件夹,并将解压后的 UrbanSound8K 文件夹放在那里【从‘下载数据’中的链接获得】
- 同样在您的主目录中:创建一个项目文件夹,并将克隆的 repo 放在那里,以~/projects/urban _ sound _ classification/…结尾
在代码中,我使用一些方法将每个音频文件提取的特征向量自动写入~/projects/urban _ sound _ classification/data
我这样做是因为特征提取需要很长时间,而且你不想做两次。还有检查这些特征向量是否存在的代码。
TL;dr——如果你遵循我的目录结构,你可以简单地运行 main.py 脚本,一切都应该工作!
为什么这个问题需要仔细的交叉验证
请注意,源数据被分成 10 个子文件夹,标记为“文件夹 1”、“文件夹 2”等。
我们有 8732 个四秒钟的各种城市声音的音频剪辑。这些剪辑是由研究论文的作者手动创建的,他们将它们分为几组,如“汽车喇叭”、“手提钻”、“儿童玩耍”等。除了 10 折,还有 10 个类。
折叠数与类别标签没有任何关系;更确切地说,折叠指的是这些 4 秒钟的训练示例拼接而来的未剪切的音频文件。
我们不希望的是模型能够学习如何根据特定底层记录的各个方面对事物进行分类。
我们需要一个通用的分类器,它可以处理各种各样的录音类型,但仍能正确地对声音进行分类。
论文作者关于正确简历的指导
这就是为什么作者为我们预先构建了折叠,并提供了以下值得引用的指导:
不要洗牌数据! 使用预定义的 10 折,执行 10 折(不是 5 折)交叉验证…
… 如果您重组数据 (例如,组合所有折叠的数据并生成随机的训练/测试分割) 您将错误地将相关样本放入训练和测试集,从而导致分数膨胀,无法代表您的模型在看不见的数据上的表现。 简单地说,你的结果会是错误的。
正确方法的总结
- 在折叠 1-9 上训练,然后在折叠 10 上测试并记录分数。然后在第 2-10 层进行训练,在第 1 层进行测试并记录分数。
- 重复此操作,直到每个折叠都作为保持一次。
- 总得分将是来自 10 个不同维持集的 10 个准确性得分的平均值。
重新创建纸质结果
请注意,研究论文没有任何代码示例。我想做的是首先看看我能否用我自己的实现重新创建(或多或少)论文的结果。
然后,如果这看起来是一致的,我将在一些模型改进上工作,看看我是否能击败它。
这是他们的模型精度的快照,来自论文【他们的图像,不是我的】:
图片来自研究论文作者贾斯汀·萨拉蒙、克里斯托弗·雅各布和胡安·巴勃罗·贝洛
因此,我们希望在如图 3a 所示的褶皱上达到高 60%/低 70%的精确度。
音频特征提取
作者图片[Marc Kelechava]
Librosa 是一个优秀且易于使用的 Python 库,它实现了音乐信息检索技术。我最近在这里写了另一篇关于使用 librosa 库的模型的博文。这个练习的目标是训练一个音频类型分类器,这个分类器来自我的个人图书馆的带标签的音频文件(标签=音乐类型)。然后,我使用训练好的模型来预测我的音乐库中其他未标记文件的流派。
我将使用从该练习中学到的一些音乐信息检索技术,并将它们应用于城市声音分类问题的音频特征提取。具体来说,我将使用:
快速了解音频转换[可选]
[我的另一篇博文对这一部分进行了更详细的阐述,如果你对此有特别的兴趣的话]
请注意,从技术上讲,将原始音频源转换为数字矢量并直接对其进行训练是可行的。然而,一个(降采样)7 分钟的音频文件将产生一个长度接近~9,000,000 浮点数的时间序列向量!
即使对于我们的 4 秒剪辑,原始时间序列表示也是一个大约 7000 维的向量。考虑到我们只有 8732 个训练样本,这可能是不可行的。
各种音乐信息检索技术减少了原始音频向量表示的维度,并使其更易于建模。
我们将用来提取特征的技术试图捕捉音频随时间变化的不同特性。例如,MFCCs 描述了声音的频谱包络[振幅频谱]。使用 librosa,我们可以随着时间的推移获得这些信息——也就是说,我们获得了一个矩阵!
特定音频文件的 MFCC 矩阵在 y 轴上具有系数,在 x 轴上具有时间。因此,我们希望汇总这些系数随时间的变化情况(跨 x 轴,或 numpy land 中的轴=1)。假设我们在一段时间内取一个平均值,然后我们得到每个 MFCC 系数在一段时间内的平均值,即特定音频文件的数字特征向量!
我们能做的是对不同的音乐信息检索技术或不同的汇总统计重复这个过程。例如,频谱对比技术也将随着时间的推移产生不同频率范围的不同频谱特性的矩阵。同样,我们可以随时间重复聚合过程,并将其打包到我们的特征向量中。
作者使用了什么
论文作者明确指出了 MFCC。他们提到提取前 25 个 MFCC 系数
每个系数的每帧值使用下面的汇总统计数据在时间上汇总:最小值、最大值、中值、平均值、方差、偏斜度、峰度以及一阶和二阶导数的平均值和方差,得到每个切片 225 维的特征向量
因此,在他们的情况下,他们在不同的汇总统计上不断聚集 25 个 MFCCs,并将它们打包到一个特征向量中。
我将在这里实现一些稍微不同的东西,因为它在前面提到的流派分类器问题中对我很有效。
我认为(对于每个片段):
- 一段时间内 MFCC 矩阵的平均值
- Std。MFCC 矩阵随时间的发展
- 一段时间内光谱对比度矩阵的平均值
- Std。光谱对比度矩阵随时间的变化
- 一段时间内色谱图矩阵的平均值
- Std。色谱图矩阵随时间的变化
我的输出(每个音频片段)将只有 82 维,而不是 225 维,所以建模应该会快一点。
终于有代码了!行动中的音频特征提取。
[请注意,我将在博客文章和 GitHub Gist 链接中发布代码片段。有时 Medium 不能正确渲染 Github Gists,这就是我这样做的原因。同样,所有的文档内代码都可以复制并粘贴到 ipython 终端上,但是 GitHub gists 却不行]。
这里引用我的脚本运行程序:
[## Marc muon/urban _ sound _ 分类
使用 Urban Sound 8K 数据集-Marc muon/Urban _ Sound _ classification 的模型的一系列博客帖子的代码
github.com](https://github.com/marcmuon/urban_sound_classification/blob/master/main.py)
我解析元数据(与数据集一起提供)并获取每个音频文件的文件名、文件夹和类标签。然后这被发送到音频特征提取器类。
AudioFeature 类包装 librosa,并提取您输入的特征作为字符串,如上所示。然后,它还会将每个音频剪辑的 AudioFeature 对象保存到磁盘。这个过程需要一段时间,所以我将类别标签和折叠号与特征向量一起保存在 AudioFeature 对象中。通过这种方式,您可以返回并在以后对提取的特征使用模型。
这个类实现了我之前描述的内容,即随着时间的推移聚合各种音乐信息检索技术,然后将每个音频片段的所有内容打包到一个单一的特征向量中。
建模
作者图片[Marc Kelechava]
由于我们将所有的 AudioFeature 对象放在上面的列表中,我们可以做一些快速理解来获得建模所需的内容:
模型类将实现作者描述的交叉验证循环(记住相关的陷阱!).
提醒一下,这是作者的第二个警告:
"不要只在一个分裂上评价!使用 10 倍(非 5 倍)交叉验证并平均得分
我们已经看到仅提供单次训练/测试分割结果的报告,例如,在第 1-9 倍进行训练,在第 10 倍进行测试并报告单个准确度得分。我们强烈反对这样做。相反,使用提供的折叠进行 10 次交叉验证,并报告平均分数。为什么?
并不是所有的拆分都那么“容易”。也就是说,与(例如)在折叠 2-10 上训练和在折叠 1 上测试相比,模型在折叠 1-9 上训练和在折叠 10 上测试时往往获得更高的分数。因此,在 10 次分割中的每一次上评估您的模型并报告平均准确度是非常重要的。
同样,你的结果将无法与文献中以前的结果相比。"
关于他们的后一点——(这来自论文)值得注意的是,不同的录音/折叠对于片段何时出现在前景或背景中有不同的分布——这就是为什么一些折叠容易而一些折叠困难。
TL;简历博士
- 我们需要在第 1-9 圈进行训练,在第 10 圈进行预测和评分
- 然后在第 2-10 层进行训练,在第 1 层进行预测和评分
- …等等…
- 使用这一过程对测试折叠的分数进行平均将与现有的研究相匹配,并确保我们不会意外地将关于源记录的数据泄露给我们的维持组。
遗漏一组
最初,我根据给定的折叠,使用 numpy 手工编写了上述分割过程的代码。虽然还不算太糟,但我意识到 scikit-learn 以 LeaveOneGroupOut KFold 拆分的形式提供了一个完美的解决方案。
为了向自己证明这就是我们想要的,我运行了来自sk learn 文档的 splitter 测试代码的一个略微修改的版本:
请注意,在这个玩具示例中有 3 个组,“1”、“2”和“3”。
当我将每个训练样本的组成员列表输入到分离器时,它正确地确保了相同的组样本不会同时出现在训练和测试中。
模特班
多亏了 sklearn,这最终变得非常容易实现!
在这里,我添加了一些缩放,但本质上分裂会给我们想要的 CV。在拆分器的每次迭代之后,我在 9 个折叠上训练折叠,并在维持折叠上进行预测。这种情况发生 10 次,然后我们可以对维持折叠返回的 10 个分数列表进行平均。
结果
"""
In: fold_acc
Out:
[0.6632302405498282,
0.7083333333333334,
0.6518918918918919,
0.6404040404040404,
0.7585470085470085,
0.6573511543134872,
0.6778042959427207,
0.6910669975186104,
0.7230392156862745,
0.7825567502986858]
In: np.mean(fold_acc)
Out: 0.6954224928485881
"""
69.5%与作者在他们的论文中对顶级模特的预测基本一致!因此,我感觉很好,这是按照他们的设想实现的。另请注意,他们还显示 fold10 是最容易得分的(我们也有),所以我们也在那里排队。
为什么不为此任务运行超参数搜索?[非常可选]
这就是事情变得有点棘手的地方。
“正常”CV 流程:
如果我们可以任意地训练/测试/分割,我们可以做这样的事情:
- 分离维持测试集
- 从较大的训练部分中,分离出一个验证集。
- 在列车上运行某种类型的参数搜索算法(比如 GridSearchCV)(非 val,非测试)。
- GridSearch 将在训练测试上运行 k-fold 交叉验证,将其分成多个折叠。最后,使用 GridSearchCV 的内部 k-fold 交叉验证中找到的最佳参数在训练部分上重新装配估计器
- 然后,我们采用拟合的最佳估计值,并在验证集上评分
因为我们在第 5 部分中设置了验证,所以我们可以在不同的模型系列或不同的参数搜索范围上多次重复步骤 3 和 4。
然后,当我们完成时,我们将采用我们的最终模型,并使用维持测试集来查看它是否通用,我们还没有触及这一点。
但是这在我们基于 Fold 的 LeaveOneGroupOut 方法中是如何工作的呢?假设我们试图如下设置一个 GridSearchCV:
但是现在,当 GridSearchCV 运行内部拆分时,我们将会遇到使用 LeaveOneGroupOut 解决的相同问题!
也就是说,想象这个循环的第一次运行,其中测试集是折叠 1,训练集是折叠 2-10。如果我们随后将训练集(折叠 2-10)传递到内部 GridSearchCV 循环中,我们将以内部 KFold 案例结束,其中相同的折叠用于内部 GridSearchCV 训练和内部 GridSearchCV 测试。
因此,它将(很可能)在内部 GridSearchCV 循环中过度选择最佳参数。
因此,我不会在 LeaveOneGroupOut 循环中运行超参数搜索。
后续步骤
我很高兴这正确地实现了研究论文——至少在非常接近他们的结果方面。
- 我想尝试从每个例子中提取更大的特征向量,然后按照这里相同的 CV 过程通过几个不同的基于 Keras 的 NN 架构运行这些向量
- 在特征提取方面,我也想考虑类之间错误分类的细微差别,看看我是否能为困难的例子想出更好的特征。例如,它肯定是越来越混乱的空调发动机空转类。为了检查这一点,我在之前的音频博客文章中提供了一些代码,您可以使用这些代码来查看每个类的假阳性率和假阴性率:https://github . com/Marc muon/audio _ genre _ classification/blob/master/model . py # L84-L128
感谢您读到这里!我打算很快写这篇文章的第二部分,讨论接下来的步骤。其他一些可能感兴趣的工作可以在这里找到:
【https://github.com/marcmuon】T3
T5https://medium.com/@marckelechava
引文
J. Salamon、C. Jacoby 和 J. P. Bello,“ 城市声音研究的数据集和分类法 ”,第 22 届 ACM 多媒体国际会议,美国奥兰多,2014 年 11 月。[ACM][PDF][BibTeX
使用 Mask-RCNN/Keras/ArcGIS 从 EagleView 航空影像中分割城市入水口特征影像
一个很有前景的深度学习实践
在我上一篇 博客 中,我谈到了使用 Mask R-CNN 和 deepLabV3+模型,使用 EagleView 超高分辨率影像对建筑物足迹进行图像分割。尽管这两种深度学习模型的输出通常是有希望的,但它们仍然缺少一定的准确性阈值。这是为什么呢?因为地面实况标签的 GIS 数据没有被任何人验证,所以许多地面实况标签或者不准确或者错过了实际的真实对象描绘,这可能潜在地混淆模型分类器。我的好奇心:如果我验证每个地面真实标签并尽可能精确地描绘每个特征,结果会更好、更有希望吗?输出的统计数据是什么,比如训练模型预测的精度和召回率?该模型的预测能否应用于实际工作中,以节省人类数字化仪潜在的耗时工作?
这次我选择入水口作为使用 Mask R-CNN 的训练模型的目标。寻找进水口特征的训练图像提出了几个挑战。进水口遵循一般的椭圆形和三角形模式,但由于多年的环境风化,颜色方案变化很大,有时甚至很难在航空图像上用肉眼发现。模型必须学会不被道路和房屋特征所迷惑,这些特征可以描绘出表面上相似的模式和形状。
为了测试实验并更好地理解模型输出,我亲自在 1 x 1 mile EagleView (Pictometry ) 3 英寸分辨率航空影像(图 1 和图 2)的一个图块顶部确定了 178 个进水口要素(基于之前供应商数字化的要素),并使用 ESRI 的 ArcGIS 软件将每个要素数字化为多边形要素,以获得地面实况标签。在用掩模 R-CNN 训练深度神经网络以从瓦片图像中识别入水口特征之后,将 1×1 英里瓦片图像的另一不同位置馈送给训练的模型,以查看该模型是否能够发现数字化仪遗漏的图像中的入水口特征。该过程产生了更好的结果,因为模型发现了更多人类数字化仪没有注意到或错过的进水口特征。
图 1:用于训练数据的红色轮廓瓦片图像和用于推断的蓝色轮廓瓦片图像。
图 2:用于训练的 20,000×20,000×3 RGB 波段的放大图像。
用 Mask-RCNN 模型训练:
Mask R-CNN 是一种先进的深度神经网络,用于解决机器学习中的实例分割问题。Mask-RCNN 有效地检测图像中的对象,同时为每个实例生成高质量的分割掩模。该方法通过与用于边界框识别的现有分支并行地添加用于预测对象遮罩的分支来扩展更快的 R-CNN。可以阅读研究论文更好的理解模型(图 3)。
图 3:用于实例分割的掩模 R-CNN 框架。来源:https://arxiv.org/abs/1703.06870
ArcGIS Pro 中的【导出深度学习的训练数据】用于导出瓷砖图像和进水口多边形特征,例如分割数据集(图 4)。输出图像的尺寸为 512x512x3,旋转角度设置为 90 度,以生成更多的图像来防止过度拟合,并帮助模型更好地概化。您可以应用传统的图像增强方法来生成更多的模拟图像,您可以在这里参考ImgaugPython 库。对于这个实验,我跳过了增强技术,因为裁剪图像的旋转确实生成了一些增强训练数据集。
图 4:进水口多边形特征(红色)覆盖用于生成训练数据集的图像
生成的训练数据集包含超过 1800 个图像和标签。通过进一步的数据处理以去除没有标记的图像,最终数据集具有超过 1764 个训练图像和标记。我用 32 GB CPU 的戴尔笔记本来训练模型。这是一个相当小的数据集,用于训练深度神经网络从航空图像中提取城市特征。对于应用迁移学习,我从在 ImageNet 数据集上训练的权重文件开始。虽然 ImageNet 数据集不包括进水口类,但它包括许多其他类型的图像,因此经过训练的权重已经学习了许多自然图像中常见的特征,这有助于训练模型。
我使用了令人印象深刻的开源实现 Mask-RCNN 库,MatterPort 在 Github 上构建了这个库来训练这个模型。
需要在类(Utils.dataset)中修改三个主要函数,以将您自己的数据集加载到框架中。参见下面的数据加载实现(图 5)。锚的比率设置为(16,32,64,128,256)以预测进水口特征的较小尺寸。IMAGES_PER_GPU 设置为=1,因此 CPU 可用于训练模型。图像和遮罩的示例(图 6)。
图 5 将训练图像和标签加载到模型
图 6:用于训练的随机图像和标签掩模
迁移学习技术应用于主干网 ResNet-101 模型。我首先用 8 个历元训练最后完全连接的层,以适应进水口要素类,然后用 100 个历元训练整个网络(图 7)
图 7:训练头部层以适应进水口特征
对于 32gb 的 CPU,完成训练过程需要 5 天以上的时间(图 8)。图表显示在特定时期后验证数据集的丢失达到稳定状态。当您的训练数据集很小时,这通常会作为过度拟合而发生。
图 8:训练全网络层 5 天 18 小时
图 9:培训损失图表
这是一个不在训练集中的测试图像,在数字化多边形中有一个进水口特征未被识别(图 10)
图 10:具有人类数字化仪的遗漏检测的测试图像和标签
从上图推断的进水口特征进行比较。有趣的是,通过推理发现了一个缺失的进水口特征。(图 11)
图 11:根据上图推断,确定了缺失的进水口特征。
带有推论的测试图像的另一个例子(图 12 和图 13)。
图 12:测试图像
图 13:从上面的测试图像推断。
然后,我使用一个 20,000 x 20,000 x 3 尺寸的完整 2019 分块图像运行 python 推理脚本,该图像距离训练中使用的分块图像有 3 英里远(图 14)。脚本裁剪并处理 1600 张(512x512x3 dim)图像以进行推理。使用 32GB 内存的 CPU 笔记本电脑完成这个过程大约需要一个小时。缺少进水口轮廓主要是因为使用了非常小的训练数据集和进水口要素顶部的树木覆盖。从该县的不同位置选择几个有代表性的切片作为训练数据集可以提高结果的准确性。
图 14:等于 1600 (512x512x1)个裁剪栅格的完整切片图像推断
我想使用统计精度和召回来衡量输出性能。对于那些不熟悉这些术语的人,这里有一些基本的:
精度:由模型分类的所有正例中真正正例的比例
召回:分类模型实际检索到的正例总数的分数。
随着二进制交叉熵置信度的阈值设置为≥0.9,该模型在 1 平方英里的推理瓦片范围内选择了 271 个候选者。然后,我手动审查候选人,选择最有希望的一个,并在航空图像中确认了 194 个。精度为 71.58%。召回率为 70.78%。当置信度阈值设置为≥0.75 时,精度下降到 53.98%。但召回率高达 78.11%,这意味着更多的进水口被正确识别,也有许多错误检测的进水口特征。根据项目的不同,我们更有可能最大化召回以检索更多的进水口特征,然后快速处理以手动消除误报。下面是与航空影像叠加的推理进水口要素的放大图(图 15)。
图 15:推断:假阳性例子和阳性进水口特征(红色)
结论:
虽然它是一个相对非常小的数据集,但 Mask-RCNN 使用迁移学习技术为超高分辨率图像分割提供了有希望的结果。通过增加来自该县不同位置的高质量训练数据集和应用数据变化增强方法,可以进一步增强性能的结果。还可以在多年影像中使用该模型来推断用于比较的要素检测,甚至可以使用 ArcGIS 工具模型构建器或任何开源代码进行低成本的要素描绘,以实现业务任务的自动化。更重要的是,上述深度学习训练过程可以应用于其他类型的图像实例或分割案例。综上所述,我要提一个有趣的事实:当我将置信度≥0.75 的结果与 vendor 在推理瓦片上数字化的多边形特征进行比较时。该模型描绘的入水口特征比人类数字化仪描绘的多 67 个,但遗漏了 45 个人类数字化入水口特征。这让我相信,如果我们应用正确的深度学习模型,并且做得正确,ML 或深度学习可以在实际的现实世界项目中使用,并为用户节省大量时间,并创造全新的体验。
1。 【明凯】何,乔治亚·格基奥萨里,彼得·多拉尔,罗斯·吉尔希克 (2018)。Mask-RCNN ,https://arxiv.org/abs/1703.06870v3
2。面具 R-CNNhttps://github.com/matterport/Mask_RCNN
3。 U-Net:用于生物医学图像分割的卷积网络:https//lmb . informatik . uni-freiburg . de/people/Ron neber/U-Net/
美国 2020 年人口普查
可视化美国过去 230 年的人口普查数据!
2020 年对所有美国人来说都是特殊的一年——这是美国人口普查年。美国人口普查是世界上最大的人口调查之一,由美国宪法授权。它每十年举行一次,帮助政府决定在哪里建设和维护学校、医院、交通基础设施和警察部门等等。总之,各种人口普查决定了每年超过 4000 亿美元的联邦资金的分配。
为了庆祝这一时刻,我收集了 230 年的美国人口普查数据,并把它们变成了一场条形图竞赛。我记录了进入这个数据项目的所有步骤——这样,如果你想在未来处理类似的项目,你可以遵循它们。
美国人口普查 230 年
早在 1790 年,美国只有 16 个州,总人口略低于 400 万——比今天的洛杉矶市还少!整个纽约州只有不到 35 万人,而人口超过 70 万的弗吉尼亚州是迄今为止人口最多的州。
但这种优势并没有持续很久——随着 1792 年华尔街的建立和战略煤炭和木材港口的建立,纽约迅速成为美国的经济领袖。1810 年,纽约州的居民接近 100 万,成为美国人口最多的州——这一称号在接下来的 150 年里一直保持着!
那么谁拿了第一呢?你猜对了——加利福尼亚!从 1940 年开始,随着航空航天和电子等先进技术的兴起,加州成为美国新的经济强国。平均而言,加州人口每十年增长 400 多万人——这一趋势一直延续至今。
这些只是数据可以向我们展示的一些例子,但还有更多东西需要探索。例如,是什么导致了俄亥俄州人口在 1820 年和伊利诺斯州人口在 1960 年的突然增长?为什么弗吉尼亚的人口在 1860 年后下降了?是什么导致了 20 世纪中期佛罗里达人口的快速增长?
创建美国人口普查条形图竞赛
除了分享一些关于美国的有趣事实,这篇文章还将帮助你解决自己的数据项目,并教你如何使用一些数据科学家最流行的工具。对于所有步骤的深入描述,你可以查看我关于 github.com 的教程。为了展示这些数据,我选择了一个条形图竞赛,这是一个在 2019 年变得非常受欢迎的数据动画工具——在 Twitter、脸书和 LinkedIn 上都有趋势帖子。
数据采集
像几乎所有的数据科学项目一样,我从获取数据开始。我决定使用维基百科精心策划的关于美国人口普查的文章。尽管通常不建议解析来自网络的数据,但在这种情况下,维基百科的美国人口普查页面布局相对一致,因此易于解析。尽管如此,与几乎所有解析的数据一样,需要进行一些清理。为了获得原始数据,我使用了熊猫的读取 HTML 函数。
pd.read_html(
“https://en.wikipedia.org/wiki/1790_United_States_Census”)
数据清理
一旦我得到了原始数据,是时候清理不同的格式,并确保所有的数字看起来合理。一致性检查在数据科学项目中经常被忽视,并可能导致很多麻烦。在我的例子中,年份 1800 与其他年份不太合拍,使用了完全不同的牌桌布局。与其他年份不同的是,1800 年的人口普查数据被分解到不同的地区。
**State**
New York (excluding Duchess, Ulster, Orange co...
New York (Duchess, Ulster, Orange counties)
在这种情况下,我很幸运地在早期发现了这些不一致之处。但实际上,你可能并不总是那么幸运。但是不用担心——继续下去是完全没问题的。一旦您开始可视化您的数据,这些小问题应该会变得更加明显。例如,在我们的例子中,这个误差会导致 1800 年纽约人口突然明显下降。一旦您看到这样的异常,有两种可能的情况:要么发生了很酷的事情,要么您的数据是错误的。两者最好不要混用!
为了解决不同地区的问题,我将行名与当前 50+1 州的名称进行匹配,然后对共享相同行名的所有人口进行汇总。经过一些额外的清理后,数据可以使用了。
数据可视化
一旦数据格式正确,大部分工作就结束了。为了创建条形图动画,我使用了一个名为“繁荣工作室”的应用程序,它似乎为这项任务提供了一个友好的界面和布局。
结论
我希望这个简短的数据项目演练对那些刚刚开始接触数据科学的人有所帮助。要看完整的教程,请去 github.com/AntonMu/Census2020。
即使从这个小数据项目中,我们也可以学到两个重要的经验:
数据清理很重要!
数据清理和一致性检查通常是任何数据科学项目中最耗时的部分,也很少是最迷人的部分。然而,要成为一名成功的数据科学家,你需要投入时间来正确地做这些事情,否则即使是最花哨的模型也无法挽救局面。
使用强大的可视化!
一旦你完成了数据清理——尽情享受吧!我选择用条形图比赛来可视化数据,但是有许多不同的方式来可视化数据,在解决之前探索一些选项是值得的。有时一个简单的表格就足够了,但通常有更好、更吸引人的方法来展示数据并从中学习。强大的可视化的好处是双重的。它可以提高你对数据的理解,并引导你发现数据中需要进一步清理的潜在缺陷。它可以提高你的观众对数据的理解。一个好的视觉效果可以吸引你的观众,并保证你的信息被传达出去——无论是对你的老板,你的家人还是你最好的朋友。
使用 Python 的美国选举 Choropleth
如何创建美国选举结果的时间序列图表
这次美国大选带来了高度紧张,毫无根据的欺诈指控,最重要的是,一些伟大的形象化。至少对数据科学家来说很重要。看起来你在任何地方都看不到展示选举结果的新方法。那么,为什么不多加几个呢?在本教程中,你将学习如何使用 Python 创建一些你自己的可视化。
来源:作者
您将学习如何创建两个从 1976 年到 2016 年美国总统选举结果的互动合唱曲。第一张地图有一个时间滑块。当您移动滑块时,地图将会改变以显示给定年份每个州的结果。对于第二张地图,每个州都变成了一个按钮。您可以单击状态来查看一段时间内的投票趋势。我们会检查代码,你可以在 GitHub 上找到完整的项目。你也可以在这里下载的地图。您应该能够在浏览器中打开并浏览它们。
来源: flaticon
Python 包
我们将使用叶子来构建地图。这是一个非常有用的软件包,用于创建简单的地理空间数据可视化。除了 leav,我们还将使用一些其他的 Python 包。您可以使用下面的代码导入它们。确保你已经安装了所有的软件包。
数据源
美国形状文件
我们需要的第一个数据集是一个美国形状文件。shapefile 是一种用于存储地理空间矢量数据的文件格式。在我们的例子中,我们有一组定义美国各州边界的坐标。我们将数据作为地理数据框读入。数据框的 51 行中的每一行都给出了国家的名称和坐标(即几何图形)。
让我们使用这个 shapefile 来创建我们的第一个叶子地图。在下面的代码中,我们初始化了地图。通过设置 location=[50.77500,-100],地图打开时会聚焦美国。然后,我们使用 US shapefile 和 GeoJson 函数向地图添加一个 choropleth。在图 1 中,您可以看到这段代码创建的地图。shapefile 为我们提供了一个工作基础,但我们需要另一个数据集来获得选举结果。
图 1:美国形状文件 choropleth
选举结果数据集
对于选举结果,我们使用麻省理工学院选举数据和科学实验室提供的数据集。它包含了 1976 年至 2016 年的美国总统选举结果。该数据集包含每个州、年份和当年参选的候选人的一行。为了使事情变得简单一点,我们应该首先将这个数据集转换成不同的格式。
使用下面的代码,我们将数据集转换成一个嵌套字典。对于每一年,我们都有一个以州名为关键字的字典。对于每个州,都有一本字典给出民主党和共和党候选人的票数。该词典的格式如下:
{
<year>: {
<state> : {'dem':<#votes>, 'rep':<#votes>},
<state> : {'dem':<#votes>, 'rep':<#votes>},
...},
...
}
将数据可视化
在我们进入交互式地图之前,让我们使用这些数据集来创建一个简单的 choropleth。我们首先需要定义两个函数。 state_style 函数返回一个字典,用来定义一个州的颜色和边界。在某一年,如果一个州投了民主党的票,它就变成蓝色;如果它投了共和党的票,它就变成红色。根据是由 style_dictionary 还是 style_function 使用,该函数返回的词典略有不同。
对于这个 choropleth,我们将使用一个样式 _ 函数。GeoJson 包使用此函数将 GeoJson 要素映射到样式。在我们的示例中,GeoJson 要素将包含状态信息(即名称和几何)。这些特征由 GeoJson 包传递给 style_function 。通过设置 year=2016,我们使用 2016 年选举的结果来定义每个州的风格。
我们现在可以使用这些函数来创建我们的第一个 choropleth。该代码与我们用来创建第一张地图的代码非常相似。唯一的区别是我们现在将 style_function 传递给 GeoJson 函数。如前所述,这给每个州一种基于选举结果的颜色。生成的地图如图 2 所示。现在,让我们看看如何改进这张地图,使它更具互动性。
图 2: 2016 年选举结果
地图 1: Choropleth 滑块
我们首先创建一个带有时间滑块的 choropleth 地图。使用函数 TimeSliderChoropleth 完成。该函数假设所有日期都是 Unix 时间格式(即时间戳)。因此,我们使用 year_to_ts 函数将选举年份转换为时间戳。例如,2016 年将被转换为“1451606400”。
我们需要定义的第二个函数, style_dictionary ,返回一个样式字典。这与 style_function 类似,只是我们现在处理的是时间序列数据。所以,对于每一个州,我们需要定义从 1976 年到 2016 年每一年的风格。 style_dictionary 函数返回如下形式的嵌套字典:
{
<ID>: {
<timestamp> : {'opacity':1, 'color':<hex_color>},
<timestamp> : {'opacity':1, 'color':<hex_color>},
...},
...
}
上面提到的 ID 是给予一个国家的唯一 ID。由自动分配。to_json() 函数。TimeSliderChoropleth 使用这些 id 将状态映射到它们的样式。因此,为了确保我们有正确的映射,我们首先创建一个从 ID 到州名的映射。这是在下面的第 7 到 13 行中完成的。该函数的其余部分用上面看到的形式创建字典。
我们现在准备创建我们的地图。同样,代码与之前类似,只是我们使用了 TimeSliderChoropleth 函数并传入了一个样式字典。代码的结果如图 3 所示。你可以滑动地图上方的滚动条来查看不同时间的选举结果。例如,从 2012 年到 2016 年,我们可以看到几个州变红。这导致了共和党候选人的胜利。
图 3: Choropleth 滑块
我们应该提到上面第 6 行中保存地图的代码。这一行将地图保存为 HTML 文件。您可以在任何浏览器中打开并浏览它。如果您正在使用 jupyter 笔记本,地图也会显示在您的代码块下方。如果地图太复杂,笔记本可能会出现渲染问题。在这种情况下,您必须保存地图并在浏览器中打开它,然后才能看到它。
地图 2: Choropleth 按钮
对于下一个地图,我们将把每个州变成一个按钮。你可以点击状态来查看一段时间内的投票趋势。首先,为了创建这些趋势图表,我们使用下面的代码。函数为给定的状态创建一个标准的 matplotlib 图表。在最后几行中,我们将图表转换成 HTML,并将其添加到 IFrame 中。这是为了能够嵌入到我们的叶子地图中。您可以在图 5 中看到为加利福尼亚制作的图表示例。
图 5:加州投票趋势
在创建按钮 choropleth 之前,我们必须定义最后一个函数。highlight_style 函数用于定义当鼠标悬停在一个状态上时该状态的样式。当这种情况发生时,状态会变得稍微有点阴影。这让我们可以在点击鼠标之前看到它的状态。
最后,为了创建地图,我们首先使用 2016 年的结果创建一个 choropleth。我们使用与图 2 中的地图完全相同的代码来实现这一点。然后,使用每个状态的几何图形,我们创建一个状态标记,并为每个标记添加一个弹出窗口。每个弹出窗口都包含一个上面讨论过的嵌入式图表。单击时,标记将显示弹出窗口,我们将能够看到投票趋势。
您可以在图 4 中看到这段代码的结果。您可以看到悬停在一个状态上是如何突出显示它的。德克萨斯和加利福尼亚也被点击来揭示他们的趋势。在笔记本中查看这张地图可能会有一些困难。在这种情况下,将其保存为 HTML 文件并在浏览器中打开。
图 4: Choropleth 按钮
与本文不同的是,美国大选还没有完全结束。在我写这篇文章的时候,还有一些选票需要统计。当他们完成时,我们将能够用 2020 年的数据更新可视化。我们会看到一些州改变颜色,而其他州的投票趋势将保持不变。这些变化的原因很复杂。像这样的观想有助于我们理解它们。
图像来源
所有图片都是我自己的或从www.flaticon.com获得的。在后者的情况下,我拥有他们的高级计划中定义的“完全许可”。
历代美国总统的声音
使用自然语言处理和主题建模分析总统历史中词语的信息、情感和复杂性。
皮特·苏扎拍摄的白宫官方照片
“言语就是力量:言语是为了说服、转化和强迫。”—拉尔夫·瓦尔多·爱默生
自美利坚合众国诞生以来,美国总统的演讲既反映了国家的现状,也呼吁改变总统认为国家应该走的方向。
总统演讲提供了国家领导人的想法和对国家发展方向的希望,以及他们打算如何利用自己的力量来推动这个方向。他们传递的信息将影响公众对信息的接受和采取行动的能力。
我使用自然语言处理和无监督学习的数据科学技术和工具,通过检查 990 多份总统演讲的情绪、演讲的复杂性和内容的重点,来更好地理解总统对演讲力量的使用。然后,我会按时间和政党寻找趋势、模式和其他见解。
从乔治·华盛顿 1789 年的第一次就职演说到吉米·卡特 1977 年的全国能源演讲,再到唐纳德·特朗普的 2019 年国情咨文,迄今为止(2020 年)每一位总统的演讲都在该项目*中进行了分析。
至此,以下是我的发现…
美国总统的感悟
使用的工具:text blob的极性和主观性
语音情绪以两种方式测量:极性(即语气中更多的负面/悲伤到语气中更多的正面/快乐)和主观性(即更多的基于事实到更多的基于观点)。
以下是情绪分析结果,其中每个点代表不同的总统,每种颜色代表一个政党>
作者截图
正如你在图表中看到的,没有强烈的颜色聚类,这意味着总统的情绪似乎没有明显的党派区分——这似乎更像是个人的转变。
在这里你可以看到共和党总统的名字>
作者截图
这里你可以看到民主党总统的名字>
作者截图
从这些图表中,我们可以看到,例如,与其他美国总统相比,富兰克林·皮尔斯的语气平均更消极/悲伤,内容更真实,而唐纳德·川普的语气平均更积极/快乐,内容更固执己见。
请记住,极性和主观性并不能告诉我们总统在说什么;一位总统可能会说一些积极的话,但它可能会对人们产生负面影响。这种情绪分析只能告诉我们总统是如何传递这些内容的,以及他们是否在用事实或观点来支持他们的声明。
美国总统演讲的老练度
使用的工具:textstat的成绩等级分析
“演讲的复杂程度”是基于一个人需要达到什么样的等级水平才能阅读文本的衡量标准——这里指的是在听到演讲时完全理解它所需的等级水平。
下图显示了这些年来每篇演讲是如何按照理解它所需要的等级来评分的。颜色仍然代表政党>
作者截图
从图表中我们可以看到,在美国早期,总统们的演讲有更高的诡辩性,平均来说需要大学水平或更高的教育水平才能读懂。大约在 20 世纪 20 年代,演讲的复杂程度有下降的趋势,这种趋势一直持续到今天。一个潜在的原因可能是总统自己的词汇,也可能是一个更加精心策划的决定;20 世纪 20 年代是收音机在家庭中变得更加普及的时期——随着更多的人能够听到总统的演讲,总统们是否改变了他们的词汇,以更广泛地与听到他们的公众联系起来?这种分析不能明确地告诉我们,但这是一个有趣的探索领域。
还要注意的是,所有年级的政党都是混合的,这表明在政党言论的复杂性方面没有明显的差异。
美国总统演讲的话题
使用的工具:使用 gensim 的 LDA 模型 的无监督主题建模
现在让我们试着更好地理解总统演讲的内容。
使用潜在狄利克雷分配(LDA)主题建模,总统演讲的七个主题被确定为:
- 美国工作和家庭帮助与需求
- 法律、宪法和权利
- 法律、条约和行动
- 公共权力和职责
- 与美国自由的战争
- 工作与商业
- 世界和平与战争和武力
在这些主题之间需要注意的是词语的定位和平衡,例如看“美国自由战争”和“战争与武力世界和平”,其中一个目标与其他目标缓冲,例如战争…拥有美国的自由。或者寻找世界和平…但也会有战争和武力。
以下是这些年来总统演讲中七个主题的趋势>
作者截图
同样,我们看不到政党之间在演讲主题上有很大的区别,相反,随着时间的推移,我们看到了更多的区别。在美国发展的最初几年,我们看到“法律、条约和行动”和“公共权力和义务”更为常见。近年来,我们看到“美国的工作和家庭帮助和需求”、“战争和武力的世界和平”和“美国自由的战争”更受总统们的欢迎。
让我们换一种方式来审视这些话题,通过按照美国不同的历史时期来看一个话题在美国历史的什么地方出现过。颜色代表每个政治演讲主题>
作者截图
从这个图表中我们可以看出,某些历史时期似乎是总统演讲主题的结束或开始。例如,在新政时期,我们第一次看到“美国工作和家庭”成为总统演讲的主要话题,此后我们继续看到它出现在几乎每个时代。
调查结果摘要
总之,这个项目的分析告诉我们:
- 情绪似乎因总统而异,不一定因党派而异。
- 演讲中用词的“复杂性”多年来一直呈下降趋势。
- 演讲的主题随着时间的推移和政党的不同而变化。
- 演讲的主题似乎与国情和公众关注的问题有关。
- 历史时期可能是几代人演讲话题转变的催化剂。
最后,我想再次强调,这一分析显示了一些趋势和模式,但同样重要的是向我们表明,从表面上看,不同总统和政党的讲话语气和定位可能有相似之处。考虑到这一点,我们都需要关注总统演讲的深层实质,以做出明智的投票和明智的支持。这可能不是一个新发现,但却是一个重要的提醒。
感谢您的阅读,希望您对这篇分析和见解感兴趣。如果您有任何意见、问题或只是想联系,请通过 LinkedIn 联系我。
关于这项工作的几点说明:
- 请记住,派对会随着时间的推移而演变和改变——就像人一样。今天的民主党人并不一定拥有与 1850 年时相同的议程或价值观。因此,在进行政党层面的分析时,应该考虑到这一点。任何关于政党的见解都是一种概括,而不是一种硬性的结论。
- 我目前是 Metis 的一名数据科学学生,每天都在学习。这项工作是我最近在数据科学领域所受教育的应用,但我仍在该领域不断成长,因此随着技能的进步,我希望重新审视和更新我的发现。我欢迎任何关于未来迭代的建议。
- 我所有的图表都是在 Tableau 中制作的,并根据兴趣与过滤选项进行交互。本博客中显示的图表是那些 Tableau 图表的截图。
非常感谢 Joseph Lilleberg,他从弗吉尼亚大学米勒中心的 网站 收集了所有总统演讲的文字记录,并把它们放在【Kaggle.com】的一个易于使用的 csv 文件中供公众使用。也感谢米勒中心使原始抄本可供公众查阅。
美国事故数据分析
对 2016 年 2 月至 2019 年 3 月全国交通事故数据进行分析。
介绍
近来交通事故变得非常普遍。T2 每年有近 125 万人死于交通事故,T4 平均每天有 3287 人死亡。此外,每年有 2000-5000 万人受伤或致残。道路交通事故是第九大死亡原因,占全球死亡总数的 2.2%。全球道路交通事故造成了 5180 亿美元的损失,单个国家的损失占其年度国内生产总值的 1-2%。
在美国,每年有超过 37,000 人死于车祸,235 万人受伤或致残。美国每年因交通事故损失 2306 亿美元,平均每人 820 美元。交通事故是出国旅行的健康美国公民每年死亡的最大原因。
(来源)
考虑到交通事故的严重性,我决定分析事故数据以发现一些有用的东西。我在这里,分享我的成果。
数据
数据集取自 Kaggle 。你可以在这里 找到。
这是一个全国范围的交通事故数据集,涵盖了美国 49 个州。从 2016 年 2 月到 2019 年 3 月持续收集数据,使用几个数据提供商,包括两个提供流交通事件数据的 API。这些 API 广播由各种实体捕获的交通事件,例如美国和州交通部、执法机构、交通摄像机和道路网络中的交通传感器。
数据集包含 2,243,939(224 万)行和 49 列(相当大的数据集)。需要注意的一点是,尽管数据集只包含三年的数据,但已经有 224 万起事故。
功能描述
如前所述,数据集包含 49 个要素,以下是对它们的描述。
数据集的要素描述
方法
在进入分析部分之前,让我们看看数据集中存在的空值。
下图仅显示了那些具有空值的要素。
具有空值的要素
探索性数据分析
我将首先从消除不必要的功能开始。
特性 Country 只包含一个条目——USA,这是显而易见的,因为我们处理的是美国的数据集。因此,我将删除此功能。
特征 Turning_Loop 也包含一个值——False。这意味着在任何事故附近都没有转弯环路。因为这个特性只包含一个值,所以我也将删除它。
让我们来看看源的特性。它代表报告事故的 API。
每个来源报告的事故数量
只有三个 API 来源报告了事故。可以看出,大多数事故(约 170 万起)是 MapQuest 报告的,其次是 Bing。
联邦法律正式规定美国有九个标准时区。整个 50 个州和哥伦比亚特区有六个主要时区。
在这六个重要时区中,我们看到(从下图中)数据集中只有四个时区。
大多数事故发生在时区上:东部标准时间,然后是太平洋标准时间。
数据集由一个令人兴奋的特性组成: TMC。 在谷歌上快速搜索会得到以下信息:
交通消息信道(TMC) 是一种向机动车驾驶员传递交通和出行信息的技术。它使用 ALERT C 或 TPEG 协议被数字编码成 RDS 类型 8A 组,通过传统的 FM 无线电广播传送。它也可以通过数字音频广播或卫星广播传输。TMC 允许在不中断音频广播服务的情况下,以用户语言无声地传递适合再现或显示的动态信息。
现在,让我们绘制出与 TMC 特征相关的事故数量。
相对于 TMC 的事故数量
该图显示大多数事故的 TMC 为 201。你可以参考 TMC 代码表来更好的理解。
最令人兴奋的特性是的严重性。代表事故的严重程度。
每种严重程度的事故数量
该图描述了大多数事故的严重程度等于 2(平均),然后是 3(高于平均),这是不幸的。几乎没有严重程度非常低(0 和 1)的事故。
让我们看看开始时间和结束时间的特性:
开始时间和结束时间特征
开始时间和结束时间特征描述了事故的开始和结束时间。为了更好地理解,我计算了每次事故的持续时间。
有趣的是,事故的持续时间从几分钟到几年不等。
前 10 个值的事故数量与持续时间
上面的图没有下面的图重要,但是,我想检查最常见的持续时间。大约 950,000 起(43%)事故持续时间为 29 分钟,然后是 6 小时。
需要注意的一点是,数据集描述告诉我们 Start_Time 和 End_Time 代表事故的起止时间。尽管一些事故的持续时间(通过取开始时间和结束时间之差计算)以小时计,甚至以月和年计,但一次事故持续几天或几年并不明显。也许这两个特征也包括修复时间,没有太多可以得出的结论。
查看每起事故持续时间的一个更重要的方法是查看持续时间单位。
每个持续时间单位的事故数量
该图描述了大约 77%的事故持续时间为分钟,而大约 22%的事故持续时间为小时。只有 52 起事故持续了几年,975 起事故持续了几天。这意味着持续时间更长的事故在美国很少发生。此外,持续时间短的事故更加频繁。
现在,让我们来看看每种严重程度的事故随时间变化的趋势。
每种严重程度的事故数量与时间
可以观察到,随着时间的推移,每种严重程度的事故数量都在增加。这令人担忧,需要采取严肃的行动。即使 2017 年事故数量有所减少,但在第 12 周左右,事故数量在那之后有所增加。严重度= 2 的事故更频繁,增加最多,其次是严重度= 3 的事故。
Start_Lat 和 Start_Lng 功能非常有趣,因为它们可以绘制在地图上,以获得事故的准确位置。首先,我将绘制两者之间的散点图。
散点图看起来不错,但同时,令人担忧的是,几乎美国的每个角落都被覆盖,这意味着在过去几年中,事故发生在大量的地点。
为了得到一个清晰的概念,我用美国地图上数据集给定的每个严重程度的坐标标绘了事故地点。
上面的情节看起来很乱!所以我们来分解一下。
严重性= 0 的事故
严重性= 1 的事故
严重程度= 2 的事故位置
严重程度= 3 的事故位置
严重程度= 4 的事故位置
我已经分别标出了每个严重程度的位置。
从上面的图表中,我们可以得出结论,大多数事故发生在美国的东部和西部,这说明了大多数事故发生在时区:东部标准时间和太平洋标准时间。
现在,让我们看看距离(mi) 特性。此功能显示受事故影响的道路长度(以英里为单位)。
上面的情节描述了大多数事故对道路的影响很小。
现在让我们看看美国最容易发生事故的城市。
事故数量最多的 10 个城市
我们看到大多数事故发生在休斯顿,其次是夏洛特和洛杉矶。
让我们看看美国最容易发生事故的州
事故数量最多的 10 个州
这里给出了美国各州及其代码的列表。
该图显示,加利福尼亚州的事故数量最多,其次是德克萨斯州和佛罗里达州。有趣的是,加利福尼亚州的事故数量几乎是德克萨斯州事故数量的两倍。
我们可以看到,美国最容易发生事故的城市是德克萨斯州的休斯顿,其次是北卡罗来纳州的夏洛特和加利福尼亚州的洛杉矶。
让我们更深入一点,绘制出与邮政编码相关的事故数量。
事故数量与邮政编码
可以看出,大多数事故发生在邮政编码为 91706 的地区,其次是 91765 和 91761。参考此链接了解更多关于邮政编码的信息。
现在让我们看看可见性(mi) 特性。它以英里表示能见度。
事故数量与能见度(mi)
该图显示,大多数事故发生在能见度高的时候,这意味着能见度不是发生事故时的一个重要问题。这是显而易见的,因为低能见度不是唯一的因素。
现在让我们看看事故发生时的天气情况。
事故数量与天气状况
该图描述了大多数事故的天气状况是晴朗的,随后是阴天,大部分是多云。与晴天不同,阴天和大部分时间多云是事故的合理因素,这意味着天气条件也不发挥重要作用。
让我们看看便利设施功能。该特征指示附近位置的便利设施的存在。
事故数量与舒适度
我们看到,几乎所有(98.84%)事故都没有无障碍设施,这很不幸。
现在我们来看看凹凸特征。该特征表明附近位置存在减速带或减速带。
事故数量与颠簸
我们看到 99.99%的事故都不是因为减速带。
这样,我们就结束了这个分析。
结论
对取自 Kaggle 的美国事故数据集进行了分析,并在上文讨论了结果。
我们发现了很多令人兴奋的事情,比如我们知道了美国哪个城市或州发生了最多的事故,我们甚至在地图上绘制了结果,还考虑了事故的严重程度。
希望你能了解一些东西,并喜欢这篇文章!!
对计数数据使用负二项式
提高你的统计游戏
负二项分布是一种离散概率分布,您的计数数据工具包中应该有这种分布。例如,您可能有关于某人在购买前访问的页面数量的数据,或者与每个客户服务代表相关的投诉或升级数量的数据。给定这些数据,您可能希望对过程进行建模,然后查看一些协变量是否会影响参数。在许多情况下,你可能会发现负二项分布非常适合。
在这篇文章中,我们将介绍分布,并计算其概率质量函数(PMF)。我们将通过使用二项式定理来涵盖它的基本属性(均值和方差)。这与通常的治疗方法形成对比,通常的治疗方法要么只是给你一个公式,要么使用更复杂的工具来得出结果。最后,我们将转而关注分布的解释。
负二项分布
假设你要掷一枚有偏向的硬币,硬币有正面朝上的概率 p ,我们称之为“成功”此外,你将继续抛硬币,直到在 r 成功。设 k 为沿途失败的次数(所以 k+r 抛硬币总共发生了多少次)。
在我们的例子中,我们可以想象:
- 用户可能会浏览您的网站。在每一页上,他们有 1%的概率看到他们想买的东西。我们想象当他们把物品放入购物篮时,他们准备结账。k 是他们会浏览但不会购买的页面数量。当然,我们将希望拟合模型以找到 r 和 p 的真实值,以及它们是否/如何在用户之间变化。
- 客户服务代表通常会收到投诉。接到投诉后,有概率 p 被训斥。然后,在被责骂几次之后,他们会因为行为的改变而停止抱怨。 k 是他们在改变行为之前没有被训斥的投诉次数。
你是否真的认为这是真的,一如既往,取决于你之前的信念和模型与数据的吻合程度。还要注意,失败的次数与事件的次数密切相关(k 对 k 加 r)。
使用一些组合学来写下概率质量函数是相对简单的。第 r 次成功发生在第(k+r)次抛硬币上的概率是:
- 第一次k+r–1翻转成功r–1的概率,次
- 第( k+r)- 次翻转成功的概率。
在第一次 k+r–1 次翻转中,有(k+r–1)次选择 k 次(r–1)次成功和次 k 次失败。(将 k A 和(r–1)B 排列成一行的方式的数量)。每一个都有相同的发生概率。这给了 PMF:
希望你记得一些关于组合和排列的基本事实。如果没有,这里有一个简单的事实回顾,你可以说服自己来帮助你。假设有 3 个 A 和 2 个 B,你想把它们排列成一个类似“AAABB”或“ABABA”的字符串。这样做的方法有 5 个选择 2(总共有 5 个东西和 2 个 B)这与 5 个选择 3(有 3 个 A)相同。为了看到这一点,假设每个字母实际上是一个不同的符号(所以这 5 个符号是 A1、A2、A3、B1、B2)。然后还有 5 个!=120 种排列不同符号的方式。但是有 3 个!=6 种在不改变 A 的位置的情况下重新排列 A1 A2 A3 的方法,以及 2!=2 种排列 B 的方法。所以总数是 5!/2!3!= 10.
诀窍是,二项式也适用于负数或者非整数。例如,如果我们扩展上面的内容,我们可以给分子中的每个 k 项添加一个减号:
负二项分布作为实际的负二项分布
因此得名“负二项式”
需要记住的另一个技巧是,我们可以用非整数来定义二项式。利用γ函数(γ函数)满足的事实,对于正整数 n ,
Gamma 函数扩展了阶乘
我们可以将二项式系数写成如下形式
n 不是整数的二项式系数
这使我们能够允许,在负二项分布中,参数 r 不必是整数。这将是有用的,因为当我们评估我们的模型时,我们通常没有办法将 r 约束为整数。因此, r 的非整数值不会有问题。(然而,我们将要求 r 为正数)。我们将回到如何解释非整数值的 r 。
负二项分布的性质
我们想计算期望和方差。作为热身,让我们检查负二项分布实际上是一个概率分布。为了方便起见,让q = 1–p。
负二项分布实际上是一种概率分布
关键点是第三行,这里我们使用了二项式定理(是的,它适用于负指数)。
现在让我们来计算期望值:
负二项分布的期望值
为了得到第三行,我们使用了恒等式
我们再次使用二项式定理得到倒数第三条线。
警告:这与你在维基百科上看到的相反。这是你将从Wolfram(Mathematica 的制造者)中找到的。这是因为维基百科考虑的是失败之前成功的次数,而我们计算的是成功之前的失败次数。一般来说,有各种类似的方法来参数化/解释分布,所以当在不同的地方查看公式时,要小心你的一切都是直的。
接下来,我们可以分两步计算方差。首先,我们重复上面的技巧,这次使用两次恒等式得到第三行。我们再次使用二项式定理来计算总和,并获得倒数第三行。
现在我们可以计算:
负二项分布的方差
同样,这与维基百科上的内容相反。
负二项分布的解释
我们已经介绍了负二项分布的“定义解释”:它是成功发生之前的失败次数,每一步成功的概率是 p。但是也有一些其他的方法来看这个分布,这可能是有启发性的,也有助于解释 r 不是整数的情况。
过分散泊松分布
泊松分布是一个非常简单的计数数据模型,它假设事件以一定的速率随机发生。然后,它对给定时间间隔内将发生多少事件的分布进行建模。在我们的例子中,它会说:
- 客户服务代表不断收到投诉。计数的变化只是由随机变化决定的。(比较他们的行为最终改变的模型)。同样,在对此进行建模时,我们可以基于外生协变量对代表之间的比率差异进行建模。
泊松分布的一个大问题是方差等于均值。这可能不符合我们的数据。假设我们用均值λ和停止参数 r 来参数化负二项分布。那么我们有
负二项分布的重新参数化
我们的概率质量函数变成了
均值λ参数化的负二项分布的概率质量函数
现在让我们考虑如果我们把极限取为 r →∞保持λ不变会发生什么。(这意味着成功的概率也趋向于 1,按照 p=r/[λ+r]定义的方式)。在这个极限中,二项式接近(–r)的 k 的幂除以 k!并且 r + λ接近 r。
均值λ固定的大 r 的负二项式的极限
在最后一行,r 的 k 次方相消,我们使用了指数的定义。结果是我们恢复了泊松分布。
因此,我们可以将负二项分布解释为泊松分布的推广。如果分布实际上是泊松分布,我们将会看到一个大的 r 和 p 接近 1。这是有意义的,因为当 p 接近 1 时,方差接近平均值。当 p 小于 1 时,方差高于同均值的泊松分布,所以我们可以看到负二项分布通过增加方差来推广泊松。
泊松分布的混合
负二项分布也是泊松随机变量的混合。例如,假设我们的客户服务代表每个人都以给定的比率收到投诉(他们从不改变他们的行为),但是这个比率在代表之间是不同的。如果这个比率是根据伽马分布随机分布的,我们得到一个负的二项分布。
这背后的直觉如下。我们最初说负二项分布是当我们掷硬币时,在成功之前失败的次数。相反,用两个泊松过程代替抛硬币。流程一(“成功”流程)的比率为 p ,流程二,“失败”流程的比率为(1-p)。这意味着,我们不是把负二项分布看作是数硬币,而是认为有独立的过程独立地产生“成功”和“失败”,我们只是在一定数量的成功之前数多少次失败。
伽玛分布是泊松过程等待时间的分布。设 T 为“成功”过程中成功的等待时间。t 是伽玛分布。那么失败次数的平均值为(1–p)T,并且服从泊松分布。
结论
最后几点值得指出。首先,没有一种解析方法可以将负二项分布拟合到数据中。相反,使用最大似然估计和数值估计。在 Python 中,您可以使用[statsmodels](https://www.statsmodels.org/devel/generated/statsmodels.discrete.discrete_model.NegativeBinomial.html)
包来完成这项工作。
此外,还可以进行负二项式回归,模拟协变量的影响。我们将在以后的文章中讨论这个问题。
在 Power BI 中对行使用聚合函数
在列上使用聚合函数是好的,但是在行上使用同样的方法是——太棒了!所有这一切只需要一行 DAX 代码!
约书亚·科尔曼在 Unsplash 上拍摄的照片
聚合函数是 Power BI 中的主要构件之一。无论是在测量中显式使用,还是由 Power BI 隐式定义,没有一个 Power BI 报告不使用某种聚合函数。
什么是聚合函数?
聚合意味着组合数据中的值,执行一些数学运算。可以是总和、平均值、最大值、最小值、计数、不同计数、平均值、标准偏差等。
但是,对聚合函数的深入观察不在本文的范围之内。在这里,我想演示如何以一种非常规的方式使用聚合函数,因为我相信它在一些特定的场景中是有用的。
聚合函数的默认行为
默认情况下,对列计算聚合。让我们看看下面的基本例子:
这是 SUM 聚合函数的一个典型例子。数字在年和月的级别上进行聚合,最后,我们可以在表中看到各个值的总和。
我们还可以执行 AVERAGE 来查找平均值,MIN 或 MAX 来查找最小值和最大值,等等。非常简单,可能大多数使用过 Power BI 或 Excel 的人都已经知道了。
行上的聚合—无需取消透视!
但是,如果我们想在行上而不是在列上执行聚合呢?有可能做到吗?如果是,如何实现?
让我们立即前往动力 BI 进行检查。我有一个 Excel 文件作为数据源,还有一个虚拟表,其中包含关于客户的数据以及他在一年内第一次购买的日期:
如您所见,有些客户每年都会购买一次产品,有些有缺口,有些是在以后几年购买的,等等。
现在,我想检索客户进行购买的最早日期,以便稍后可以基于该日期执行分析(例如,分析有多少客户在 2017 年 2 月进行了首次购买)。
我知道,你们大多数人可能会选择 Power Query 转换和 Unpivoting years 列,就像这样:
您会看到一个漂亮的新表格,所有日期都按客户分组:
但是,需要一个额外的工作负载来构建一个单独的列,该列将保存每个客户的最早日期(或最小日期)的数据,因此我们稍后可以使用该列进行过滤,甚至构建与[日期维度](http://However, an additional workload is necessary to build a separate column which will hold data about the earliest date (or MIN date) for every single customer, so we can later use this column for filtering purposes, or even for building a relationship to a date dimension. What if I tell you that you can do this with a single line of code and without any additional transformations? First, I will close Power Query editor and go straight to Power BI Data view:)的关系。
如果我告诉你,你只用一行代码就可以做到这一点,不需要任何额外的转换,那会怎么样?
首先,我将关闭电源查询编辑器,直接进入电源 BI 数据视图:
您会看到该表看起来与 Excel 中的一模一样。现在,我选择创建一个新列,当出现提示时,输入以下 DAX 代码:
First Purchase Date = MINX({Sheet2[2016],Sheet2[2017],Sheet2[2018],Sheet2[2019]},[Value])
让我们暂时停在这里,解释一下我们在做什么。因此,我们希望从每一行中提取最小日期。我们可以通过使用多个嵌套的 IF 语句和 MIN aggregate 函数来实现。因为 MIN function 只接受两个参数,所以我们会有多层嵌套的 IF 语句,这非常难看,几乎不可读。
这里的神奇之处就在花括号里! 通过使用它们,我们告诉 DAX 我们希望它从花括号内的列表中创建一个表,并使用 MINX 迭代器聚合函数,我们简单地遍历这个表并从中提取最小值。
那是多么的酷和优雅!它非常有效,下面是结果栏:
您可以很容易地发现 DAX 返回了预期值,因此现在我们可以将该列用作图表中的轴,在其上创建常规的日期层次结构,或者如果愿意,我们甚至可以在数据模型中创建首次购买日期和日期维度之间的关系。
结论
力量 BI 和 DAX 都是满满的隐藏宝石。老实说,我不得不承认,您可能不会每天都面临这样的场景,但是在某些特定的情况下,知道您可以以一种非常简单而强大的方式在行级别上执行聚合函数是很好的——使用一行代码!
订阅此处获取更多有见地的数据文章!
在你的 Mac 上使用 AMD GPU 来加速 Keras 中的深度学习
照片https://unsplash.com/photos/aVeKubCF-48
Mac + AMD 镭龙 RX5700 XT + Keras
如今,每个机器学习工程师都会希望使用 GPU 来加速他的深度学习计算。我碰巧从一个朋友那里得到了一个 AMD 镭龙 GPU。不幸的是,我看到 AMD 和 Nvidia GPUs 之间有很大的差异,而只有后者在深度学习库中得到了很大的支持,如 Tensorflow。我看到了一些文章,并让我的 mac+amd GPU 设置工作。🚀
这可以看作是对其他文章的理解(见“附加阅读”)和我这边在实现过程中的一些附加解决方案。
放弃
我与本文中使用的任何服务都没有关联。
我不认为自己是专家。如果你觉得我错过了重要的步骤或者忽略了什么,可以考虑在评论区指出来或者联系我。
我总是乐于听取建设性的意见以及如何改进。
本文写于 2020 年 3 月 10 日。
我无法监控我的所有文章。当你阅读这篇文章时,提示很可能已经过时,过程已经改变。
如果你需要更多关于某些部分的信息,请在评论中指出来。
目录
问题——答案
用于 Keras 计算的核心 Tensorflow 支持通过 CUDA 使用 Nvidia 显卡进行本地 GPU 加速。不幸的是,AMD 还没有这样的产品。
这个问题的答案是 PlaidML,这是一个 python 库和张量编译器,它允许我们加速矢量计算。
PlaidML 是一个先进的便携式张量编译器,用于在笔记本电脑、嵌入式设备或其他设备上实现深度学习,在这些设备上,可用的计算硬件没有得到很好的支持,或者可用的软件堆栈包含令人不快的许可证限制。
PlaidML 位于通用机器学习框架之下,使用户能够访问 PlaidML 支持的任何硬件。PlaidML 支持 Keras、ONNX 和 nGraph。
作为 nGraph 编译器堆栈中的一个组件,PlaidML 进一步扩展了专门的深度学习硬件(特别是 GPU)的功能,并使访问或利用子图级优化变得更加容易和快速,否则这些优化将受到设备计算限制的限制。
作为 Keras 下的组件,PlaidML 可以通过定制或自动生成的 Tile 代码来加速训练工作量。它在 GPU 上工作得特别好,并且它不需要在 Nvidia 硬件上使用 CUDA/cuDNN,同时实现可比的性能。
来源https://github.com/plaidml/plaidml
截至撰写本文时,以下硬件和网络已经过验证:
来源公文https://github.com/plaidml/plaidml/tree/plaidml-v1
由于 PlaidML 有助于 Keras 模型上的张量计算,它不会加速使用 Numpy 的独立张量计算。这可以通过使用 OpenCL 来完成,这将不在本文中讨论。查看“额外阅读”部分了解更多信息。
先决条件
如果你想继续下去,你应该
- 苹果操作系统
- 外部 AMD GPU
- Keras ,作为深度学习库
我的设置
马科斯·卡特琳娜
System Version: macOS 10.15.6 (19G2021)
Kernel Version: Darwin 19.6.0
Boot Volume: Macintosh HD
Boot Mode: Normal
Secure Virtual Memory: Enabled
System Integrity Protection: Enabled
外部 GPU
运行
system_profiler SPDisplaysDataType
会给你图形/显示输出。
它显示了我的外部 GPU:
Radeon RX 5700 XT: Chipset Model: Radeon RX 5700 XT
Type: External GPU
Bus: PCIe
PCIe Lane Width: x4
VRAM (Total): 8 GB
Vendor: AMD (0x1002)
Device ID: 0x731f
Revision ID: 0x00c1
ROM Revision: 113-D1990103-O09
Automatic Graphics Switching: Supported
gMux Version: 4.0.29 [3.2.8]
Metal: Supported, feature set macOS GPUFamily2 v1
GPU is Removable: Yes
库版本
keras=2.2.4=pypi_0
keras-applications=1.0.8=py_1
keras-preprocessing=1.1.0=py_0plaidbench=0.7.0=pypi_0
plaidml=0.7.0=pypi_0
plaidml-keras=0.7.0=pypi_0
将外部 GPU 连接到 Mac
安装软件包
pip install pyopencl plaidml-keras plaidbench
plaidml-设置
plaidml-setup
plaidml-setup 的设置步骤
plaidbench keras mobilenet
plaidbench keras mobilenet
运行 plaidbench 的结果
这表明 GPU 设置应该是可行的。现在让我们进入实际的实现。
实际实施
为了让它工作,你需要将它添加到笔记本/文件中:
import plaidml.keras
import os
plaidml.keras.install_backend()
os.environ["KERAS_BACKEND"] = "plaidml.keras.backend"
还有其他关于如何添加后端的建议。然而,它只在这个顺序下对我有效。首先安装后端,然后设置环境。(其他建议见“附加阅读”)
之后,做
from keras import backend as K
K
应该会给你这样的东西:
<module 'plaidml.keras.backend' from '/Users/XXXX/opt/anaconda3/envs/XXX/lib/python3.7/site-packages/plaidml/keras/backend.py'>
如果你不确定是否真的使用了 GPU,有几个命令可用,比如K._get_available_gpus()
。但它们对我不起作用。如果你得到的是类似上面的后端消息,它应该可以工作。你会在计算过程中看到无论如何,如果你的 GPU 正在运行或你的 Mac)
添加深度学习代码
为了测试它,你可以从他们的文档中使用基本的 Keras 示例代码:https://github.com/keras-team/keras/tree/master/examples
例如神经类型转移。
在我的标题中的基本图像上运行它(归功于 Nana Dua )并添加一些特殊的味道(归功于 Arno Senoner ,导致:
原创
风格转移
附加阅读和常见问题
- 在您的 Mac 上使用外部图形处理器
- AMD 上的 GPU 加速,使用 PlaidML 进行训练和使用 Keras 模型
- MAC OS 上 GPU 加速的机器学习
- 在深度学习中使用 GPU 可以带来哪些好处
- Stackoverflow 关于让 mac 与 GPU 一起工作
关于
丹尼尔是一名企业家、软件开发人员和律师。他曾在各种 IT 公司、税务咨询、管理咨询和奥地利法院工作。
他的知识和兴趣目前围绕着编程机器学习应用程序及其所有相关方面。从本质上说,他认为自己是复杂环境的问题解决者,这在他的各种项目中都有所体现。
如果您有想法、项目或问题,请不要犹豫与我们联系。
连接到:
你可以在https://www.buymeacoffee.com/createdd上支持我
使用 Apple 新的 ML 计算框架来加速 iOS 和 macOS 上的 ML 训练和推理
破解新的苹果 ML 计算框架,加速跨 CPU 和 GPU 的神经网络训练
随着最近新一波操作系统版本(BigSur,iOS 14 等。),苹果在最近的 WWDC 上宣布,它非常安静地引入了一个新的 ML 框架,以加速跨 CPU 或一个或多个可用 GPU 的神经网络训练。
ML Compute 并不完全是一个新的 ML 框架,而是一个新的 API,它利用了 CPU 的 Accelerate 框架提供的高性能 BNNS 原语和 GPU 的金属性能着色器。
在查看了文档并开始在 iOS/macOS 应用程序上使用它之后,我明白这并不是一个真正简单的高级框架,而是一些可能旨在加速现有第三方 ML 库的东西,如 ONNX 运行时或苹果平台上的 TensorFlow Lite 框架。
即使苹果的文档非常好,我也要说这些 API 对于在 iOS/macOS 上做通用 ML 来说并不是真正的开发者友好和快捷。例如,tensor API 非常粗糙,它需要处理 Swift 中的非托管指针。基本上,您自己负责管理传递给这些 API 的张量、节点和图形等对象的所有权和内存分配的生存期。
更一般地,ML Compute 根据定义并不为 TensorFlow 提供类似 Keras、PyTorch 或 Swift 的 ML APIs 来简化构建和训练 ML 模型,而是提供低级 API 来构建计算图和管理低级训练循环。
对于 iOS/macOS 上的通用 ML 编码,我建议继续使用 Core ML 和 CoreMLTools 这样的工具从其他框架(TensorFlow,PyTorch 等)导入模型。)或者,如果您想完全在设备上本地构建和/或训练模型,避免任何 Python 代码,最终可以尝试我开发的 SwiftCoreMLTools 库。
[## JacopoMangiavacchi/SwiftCoreMLTools
用于在 Swift 中创建 CoreML 模型的 Swift 库。这个库公开了一个(基于函数生成器)…
github.com](https://github.com/JacopoMangiavacchi/SwiftCoreMLTools)
无论如何,我个人的观点是,玩了这个之后,ML 计算可能会变得非常强大,甚至对于常规的 Swift ML 开发人员来说也是如此,例如,在此基础上增加一个 Swift Function Builder (DSL)高级 API,就像我为 SwiftCoreMLTools 开发的那个,以及一个高级 Tensor Swift API,有望与 Swift Numerics 多维数组集成。
为了快速测试这些 API 的能力,我决定开发并演示一个 PoC 应用程序,在 iOS 和 macOS 上使用 ML Compute 对 MNIST 数据集进行简单的浅层模型训练和推理。
演示 ML 计算游乐场
在进入这个 MNIST ML 计算应用的细节之前,请让我分享一个快速和肮脏的 Swift 操场,我最初用来熟悉 ML 计算张量和图形 API。
正如你在这里看到的,我还没有建立一个真正的 ML 模型,但我使用 ML 计算图来简单地运行一些基本的张量算术运算。
我认为先简单地熟悉一下这个会很有帮助。
准备 MNIST 数据集张量
现在,我们已经熟悉了用于构建张量和图形的 ML Compute API 的基础,让您开始了解如何构建第一个样本浅层模型来训练著名的 MNIST 数据集。
我们将首先高效地导入包含 MNIST 训练和测试数据集的 CSV 文件,然后看看如何在 ML Compute tensors 中进行转换。
如您所见,下面的代码并行读取,训练和数据集 CSV 文件,应用一些规范化,并转换 Swift Float 数组中的图像和标签。
这里有一个关于并发性和中央调度 API (GCD)的简短说明。为了快速并行处理一批数据,我在这里使用了方便的 dispatch queue . concurrent perform API 来轻松管理 Swift 中的并行 For-Loop。
效用函数
不幸的是,将 CSV 文件缓冲区读入 String 并使用 split()方法处理行实际上并不高效,因此我必须开发一种替代方法,使用更高效的 C 运行时 getline()函数逐行扫描 CSV 文件。
下面的其他函数将在稍后处理标签和损失函数成本时变得有用,以便使用损失函数所需的一种热编码技术来编码和解码标签(ML 计算不提供稀疏分类交叉熵)。
构建计算图
既然我们已经在 Swift Float 数组上加载了训练和测试图像和标签,我们终于可以开始构建 ML 计算图了,我们将分别使用它来训练和测试模型。
我们在此示例应用程序中特别使用的 ML 模型是一个非常简单的浅层神经网络,它有一个带有 relu 激活的密集层,后面是一个带有 softmax 激活的最终密集层,用于 MNIST 数据集的十位数类别。
正如你所看到的,ML 计算图是通过添加层节点和激活函数,向所有这些层和激活函数传递经典参数(如输入/输出张量的形状、权重/偏差初始矩阵等)而构建的。
这里需要注意的是,用于权重、偏差以及模型输入和输出的所有张量的形状。具体来说,你可以看到,当构建图形时,我们必须选择批量大小,我们稍后将用于训练和推理,根据批量大小创建所有这些张量形状。
构建训练图
现在我们有了一个 ML 计算图,我们可以构建一个 MLCTrainingGraph 来传递计算图和训练参数。
在这种情况下,我们将指定 softmax 交叉熵作为损失函数(ML Compute 不提供稀疏分类交叉熵), ADAM 作为具有标准默认参数的优化器。
训练图表
为了训练 MLCTrainingGraph,我们需要创建一个完整的训练循环,迭代所有批次的每个时期,只需将训练数据集中的样本总数除以上面用于创建张量和图形的批次大小。
具体来说,在批处理循环中,我们将从 Swift Float 数组获得图像切片和标签数据的 Swift 不安全缓冲区,我们将通过此数据切片的不安全指针构建 MLCTensorData,并最终将此张量数据传递给训练图执行方法,以最终使用批处理数据训练模型。
用验证数据测试图表
一旦该模型被训练了足够的时期,我们将验证该模型,建立一个类似的 MLCInferenceGraph 和饲料,一次一批,所有的测试数据。
在推理图执行闭包回调中,我们将通过简单地查看预测对应于测试标签的时间来计算模型的最终准确性。
完整的代码
和往常一样,这个故事的代码是完全开源的,可以在我的 GitHub 个人账户上获得:
通过在 GitHub 上创建帐户,为 JacopoMangiavacchi/MNIST-ComputeML 开发做出贡献。
github.com](https://github.com/JacopoMangiavacchi/MNIST-ComputeML)
特别感谢
最后,我想在此感谢 Apple ML Compute 团队,他们非常迅速、非常详细地为我提供了关于新 ML Compute 框架的建议和见解。
通过 SAP-C01 考试:用例层后,我在 AWS 上搭建了一个机器学习平台
“建筑是对真理的探索”——路易斯·康。问题是:什么真相?设计一个平台是一个不断寻求真理的过程。然而,如果“关于什么”没有很好地定义,这可能是一个无休止的过程。
约书亚·索蒂诺在 Unsplash 上拍摄的照片
这是我在 AWS 上构建机器学习平台之旅的第四章。这一章是基于我到目前为止在前面的部分中介绍的工作:ML 平台的高级概述 , 基础设施&软件层 ,以及 框架层 。
在这一部分,我将研究 AWS 上机器学习平台的第四层:用例层。
1 |那么,关于什么的真相?
当利益相关者选择一个新的用例时,最终目标是将这个用例放到机器学习平台上。实现这一目标受到解决三个谜题的限制:
- 用例背后的真相是什么?
- 用例所需的数据背后隐藏着哪些奥秘?
- 如何在机器学习平台上恰当地落地这个用例?
2 |用例背后的真相是什么?
即使机器学习是一个伟大的工具,它也不是大多数用例的正确答案。如果应用于错误的用例,它甚至可能是一种矫枉过正和预算浪费。这就是为什么,首先,业务分析师和数据科学家应该限定用例,并确保它有资格通过机器学习来解决。
“一个 大部分用例简答: 不使用机器学习。 保持简单!” 。
因此,如果用例可以通过传统算法和软件解决方案来解决,那么避免使用机器学习来解决它的复杂而危险的旅程是更明智的。
3|用例所需的数据背后隐藏着哪些奥秘?
现在假设我们的用例是一个真正的机器学习用例!还有两个重要步骤需要克服:
- 确定正确的数据源
- 将数据带到机器学习平台
3.1 |确定正确的数据源
传统上,具有深厚业务知识的人努力工作,以确定需要什么数据源,并试图编写一个清晰的用例规范,详细说明用例的棘手方面。
随着机器学习的出现,这个过程不再局限于拥有商业知识的人。数据科学家也应该融入这个过程,因为他们必须掌握那些棘手的方面,以努力产生一个强大的机器学习模型。
3.2 |将数据引入机器学习平台
提醒一下,从一开始,我就假设我试图构建的 ML 平台是数据的消费者,并使用另一个数据平台功能来带来想要的数据。
数据平台和机器学习平台的分离,作者作者
尽管如此,机器学习团队主要负责研究围绕数据的敏感话题。这些主题包括:
- 遵守一定的法规:数据是一座金矿,但它的使用要服从一定的条件。例如,欧盟的数据应遵循一般数据保护法规(GDPR)。“通用数据保护条例(EU) 2016/679 (GDPR)是欧盟法律中关于欧盟(EU)和欧洲经济区(EEA)数据保护和隐私的规定。它还解决了欧盟和欧洲经济区以外的个人数据传输问题。” 。要研究的其他法规可能是健康保险便携性和责任法案(HIPPA) 和支付卡行业数据安全标准(PCI-DSS) ⁴ 。
- 数据敏感性:为了遵守内容分发政策,一些数据属性应该匿名。例如,这适用于个人身份信息(PII)。
- 数据收集属性:在委派将数据带到数据平台的工作之前,必须回答几个问题:
-应该以流模式收集哪些数据?哪些数据是以批处理方式收集的?
-如何安排这些不同的数据收集流程?谁应该访问数据,谁不应该?
4 |如何在机器学习平台上恰当地落地这个用例?
几乎每个机器学习用例都可以通过七步通用工作流来解决:
- 数据准备
- 特征工程
- 模特培训
- 模型评估
- 模型打包和部署
- 模型服务
- 模型监控
到目前为止构建的 ML 平台就是为了简化这些步骤的执行。准确地说,上一篇文章中提到的抽象层,将是我们应用这些步骤的切入点。
提醒一下,这里是抽象层(框架层)的逻辑架构:
《机器学习框架的逻辑架构和实现》,作者作者
让我们讨论机器学习工作流的每一步,并看看在处理这些步骤时可能面临的一些挑战。
4.1 | 数据清理和准备
从 S3,使用由 Kubeflow 产生和管理的 Jupyter 笔记本,原始数据被加载和研究。
数据清理模式,作者作者
在此阶段,数据可能会发生很多变化。例如:
- 平衡数据:在某些情况下,数据是不平衡的。例如,当处理像将电子邮件分类为垃圾邮件和非垃圾邮件这样的用例时,与真实的电子邮件相比,我们可能有不显著数量的垃圾邮件。
存在多种技术来平衡数据,如过采样、欠采样和 SMOTE 。 - 标注更多数据:在监督学习中,有时标注样本的数量刚好不足以训练一个模型。在这种情况下,可以标记更多的数据。
亚马逊机械土耳其人可以用来完成这个任务。它是“一种网络服务,提供按需的、可扩展的人类劳动力来完成人类可以比计算机做得更好的工作,例如识别照片中的物体。” ⁵ 。 - 数据扩充:当我们没有足够的数据来正确训练机器学习模型时,数据扩充也可能是一种解决方案。这是一种用于从现有示例中生成更多标记数据的技术。例如,当用于图像时,可以通过翻转该图像,在该图像上应用一些滤镜,或者剪切该图像的一些部分以引入损失,从一个图像生成新图像。
结果数据存储在清理后的数据存储中。
4.2 | 特色工程
这是最具挑战性的步骤之一。识别特征需要大量的头脑风暴和想象力。优步特色的例子:“餐厅在过去一小时内的平均用餐准备时间。”, ' 餐厅最近七天的平均备餐时间。 ⁶
特色工程模式,作者作者
如前一篇文章 、中所述,可以计算两种类型的特征:
- 在线功能:基于流数据计算,应该以非常低的延迟进行访问。这些特性存储在 DynamoDB 中。存储特征定义意味着存储其属性:特征名称、特征类型(数值、分类)、特征的最小值和最大值等。
为了计算在线特征,ML 平台使用数据平台的流处理能力。换句话说,就两个平台之间的集成协议而言,这将是在数据平台上运行的作业。 - 离线特性:基于历史数据计算,无低延迟访问限制。这些特征将被存储在 S3。与在线特征一样,离线特征通过数据平台的批处理功能进行计算。
离线功能商店必须定期与在线功能商店同步,以“确保相同的数据和批处理管道用于培训和服务”**。
4.3 | 模型训练
训练阶段的第一步包括将数据分成三组:训练组用于训练模型,验证组用于超参数优化,以及测试组用于评估模型的性能。
模特培训模式,作者作者
清理后的数据和特征一起被输入到数据和模型准备层的模型训练功能中。然后将几个模型应用于数据,旨在筛选出一个性能模型。
如基础架构层文章中所述,FSx for Luster 用作存储来托管从 S3 复制的培训数据。有了这种存储,训练阶段被加速,因为工作节点可以具有比直接从 S3 访问数据好得多的数据访问性能。
该模式的最后一步是将训练好的模型连同其版本化元数据一起存储在训练好的模型存储的版本化存储库中。模型的元数据可以是模型的名称和版本、用于构建模型的数据版本、模型使用的特性、模型的输出格式等等。
4.4 | 模型评估
使用 Katib 和验证集,在选定的 ML 模型上测试不同的超参数组合,以最终选择性能最佳的组合。
然后使用测试集来测试 ML 模型,以评估其性能。
最后,生成的模型与其元数据一起存储在训练好的模型库中。
模式评价模式,作者作者
4.5 | 模型打包和部署
两个步骤组成了这个模式:模型打包和模型部署。每一步都有自己的规范。
模型操作模式,由作者
首先,经过训练的模型应该与特征提取器和样本数据集打包在一起,这将有助于在部署后验证模型。
不过需要注意一件棘手的事情:如果 ML 模型是实时服务的,那么模型的代码必须高效以遵守 SLA。有时,应该用 C++或 Java 之类的编译语言而不是 python 来重新实现。
其次,生成的包是存储在弹性容器注册表(ECR)中的 docker 映像。
最后,模型被部署为 docker 容器。可以考虑不同的部署策略:
- 单一部署:已经部署的模型被新的模型简单替换。同一时间只部署一个型号。
这种策略是有风险的,因为:
-在现有型号的更换过程中会造成一定的停机时间。
-新的模型版本可能包含一些错误,回滚策略应该准备好执行。 - 蓝/绿部署:这种技术保持了模型的两个版本:一个新版本(绿色)和另一个已经运行的版本(蓝色)。然后,根据新型号的性能,流量逐渐转移到新版本。
通过这种策略,停机时间被最小化,并且可以进行一些 A/B 测试。 - 多臂土匪:通过这种“聪明”的方法,交通逐渐被引导到最佳模式。
4.6 |型号上菜
为模型服务的两种可能模式:
- 实时服务:当模型在线部署时,它以 REST API 的形式向最终用户公开。Seldon Core 与 Kubeflow 及其 Ambassador API 网关很好地集成在一起,以管理入口流量和 API 端点展示。
上菜模式如下:
1。如前所述,在线功能商店必须定期与离线功能商店同步,以确保“相同的数据用于训练和服务”【⁶】*****2。 用户使用 API 端点将其上下文化的数据发送到模型:除了核心数据之外,请求中还可以包含一些重要的可追溯性信息,如发送时间、发送者的 IP 地址等。
3。特征提取器处理接收到的数据,并使用模型的元数据来识别正确的特征。
4。然后构建特征向量并提供给模型。
5。在最后一步中,预测被发送回用户以及预测存储。这个预测存储对于监控模型的性能是必不可少的。*
实时发球模式,作者作者
- 批量服务:如上一篇文章中所解释的,当 ML 模型应用于大输入量时,如用户选择的歌曲的一周历史,这种服务模式用于推荐下一周的正确歌曲。
图案如下:
1。就像实时上菜一样,离线和在线是同步的。
2。对于批量服务,从 S3 存储器中提取特征,因为对于快速访问没有限制。
3。最后,该模型的预测并不直接发送给用户,而是转到另一个存储器以备将来使用。
批量上菜模式,由作者
4.7 |型号监控
由于人类行为是不可预测的,ML 模型的性能容易退化。这就是为什么在生产中部署 ML 模型时应该考虑监控模式。
数据变化不是性能下降的唯一原因,其他原因可能是一些工作节点或某项服务不可用,这可能导致不遵守 SLA。
模式监控模式,由作者
为了监控模型,应该连续计算一些指标,并将其注入到性能指标存储中。
常见的做法是:
- 从预测存储中获取数据,并将其视为未标记的数据
- 为这些数据构建正确的预测:例如,可以从用户那里恢复正确的标签,或者使用 Amazon Mechanical Turk
- 运行作业以将模型预测与这些标注进行比较。
Prometheus 和 Grafana 也可以分别用于收集和可视化这些指标。这两种解决方案都与 Seldon Core 很好地集成在一起。
结论
在这篇文章中,我试图解释如何在机器学习平台上实现一个用例。
我首先讨论了当涉众选择一个新的用例时所面临的挑战,比如研究用例的真实性质,以及识别解决用例所需的数据源。
然后,以 框架层 为基础,我研究了机器学习模型生命周期中使用的不同模式,并给出了一些已知的最佳实践。
我相信在 AWS 上构建机器学习平台的过程中遇到的很多话题应该会更加详细。一个例子是深入到 API 网关层来有效地服务于实时模型。这将是我即将发表的文章的主题。
如果您有任何问题,请通过 LinkedIn 联系我。
[1]https://freeandopenmachinehlearning . readthedocs . io/en/latest/ml-business-use . html
[2]https://en . Wikipedia . org/wiki/General _ Data _ Protection _ Regulation
【3】https://en . Wikipedia . org/wiki/Health _ Insurance _ Portability _ and _ account ability _ Act
[4]https://en . Wikipedia . org/wiki/Payment _ Card _ Industry _ Data _ Security _ Standard
https://docs.aws.amazon.com/mturk/index.html
[6]https://eng . Uber . com/米开朗基罗-机器学习-平台/
差异隐私的使用案例
新兴技术的创新应用笔记
查尔斯·德鲁维奥在 Unsplash 上拍摄的照片
在这篇博文中,我们将简要介绍差分隐私(DP)的几个用例,从生物医学数据集分析到地理定位。
如果你有兴趣在深入其他用例之前学习差分隐私的基础知识,请查看我的博客文章 差分隐私的高级介绍 。
本文中的注释是为 SG OpenMined Explorers 研究小组创建的—有关与本文相关的幻灯片,请参见 差分隐私和联合学习的用例 。
让我们从基因组学的差分隐私应用开始!
基因组学
机器学习对于基因组学应用具有重要的意义,例如对于精确医疗(即,针对患者的临床/遗传特征定制的治疗)和从不同人群收集的数据中检测细粒度的见解。
鉴于大量基因组数据集的快速创建为这些应用的统计分析和机器学习研究提供了燃料,这种应用的主要隐私风险之一是使用辅助信息的链接攻击。链接攻击涉及利用公共数据库中的信息与敏感数据集重叠的场景(通常是匿名/去标识的,以审查数据集)。我们稍后将讨论去标识化和 k 匿名化。
有许多说明链接攻击的例子,例如在去标识的医院记录和选民注册数据库上部署的链接攻击,其结果是成功地找到了马萨诸塞州州长的患者档案。
此外,考虑下面的引用:
“已经证明,即使是粗略水平的信息,如次要等位基因频率(MAF)也可以揭示给定个体是否是研究队列的一部分,从而潜在地揭示个体的敏感临床表型。”
从基因歧视的角度来看,这是令人担忧的,因为个人可能会因为基因突变而受到不同的对待。
这个问题的现有解决方案包括:
- 去标识化,包括从数据中删除唯一的标识符,如姓名、电话号码,甚至车辆标识符。这种方法的缺点是您可能会丢失对分析有用的有意义的信息。
- k-匿名化,涉及从发布的数据中删除信息,直到一个数据记录与至少(k1)个其他记录属于同一等价类。这种方法的缺点是它没有提供正式的隐私保证,容易受到链接攻击以及其他攻击。
与差异隐私相关的优势:
- 防范链接攻击
- 启用两种类型的设置:
- 交互式设置,您可以在其中查询非公共数据库——答案被注入噪音或仅发布汇总统计数据
2.非交互式设置,其中公共数据被注入了噪声
这种应用与差压相关的缺点:
- 平衡隐私与效用(即考虑结果的准确性)。
- DP 方法只允许预设查询,例如:“返回 p 值”、“返回前 K 个 SNP 的位置”
优步用户数据
在讨论用例之前,让我们快速定义不同类型的查询敏感度。
Sensitivity⁹:的定义
- 查询的敏感度:当数据库发生变化时,金额查询的结果也会发生变化。
- 全局敏感度:任意两个相邻数据库中查询结果的最大差异。
- 本地敏感度:真实数据库和它的任何邻居的查询结果之间的最大差异。局部敏感度通常比全局敏感度低得多,因为它是单个真实数据库的属性,而不是所有可能数据库的集合。考虑局部敏感性时,平滑函数非常重要。
许多差分隐私机制基于全局敏感性,并不推广到连接(因为它们可以乘以输入记录)。
使用局部灵敏度的技术通常提供更大的效用,但是在计算上是不可行的。
用例
对于这个用例,让我们考虑 Uber 的一个示例应用程序——确定 users⁹.的平均行程距离较小的城市可能有较少的旅行,因此个人旅行可能会影响分析,这有助于解决差异隐私问题。
根据上一节的注释,考虑局部敏感性是有价值的,因为基于全局敏感性的 DP 机制不能推广到连接。下面的图片来自论文“面向 SQL Queries"⁹的实用差分隐私”显示了大量查询利用连接,这激发了对利用本地敏感性的方法的需求。
旁注:我强烈推荐阅读论文《SQL Queries"⁹的实用差分隐私》(参考资料中的链接),以获得类似的查询分析和弹性敏感度的详细定义。
图片来自“面向 SQL Queries"⁹的实用差分隐私”,第 2 页
作者提出弹性敏感度作为一种平衡局部敏感度的方法。这种方法的目的是“使用关于真实数据库中连接键频率的预计算指标,对查询中每个连接的影响进行建模”。请参见下表,了解弹性敏感度与其他 DP 机制之间的比较——我们看到弹性敏感度支持不同类型的等价联接,即“以两种关系中某一列的值相等为条件的联接”
图片来自“面向 SQL Queries"⁹的实用差分隐私”,第 4 页
作者展示了 FLEX,一个利用弹性敏感度的系统,如下图所示。以下是白皮书中描述的优势:
- 提供(ε,δ)-差分隐私,不需要与数据库交互。
- 只需要查询的静态分析和查询结果的后处理。
- 扩展到大数据,同时产生最小的性能开销。
图片来自“面向 SQL Queries"⁹的实用差分隐私”,第 9 页
医疗+物联网:心率监测
现在让我们转向一个涉及可穿戴技术和物联网的医疗保健应用。这里的用例是通过智能手表等设备收集固定间隔测量的健康数据流(例如,收集营业时间内每分钟测量的心率)。
在相应论文中描述的系统管道中,使用本地差分隐私来扰乱数据,其中数据贡献者添加了噪声。按照下面显示的管道,用户的智能手表识别数据流中的显著点,然后用噪声干扰它们,随后将有噪声的数据发送到服务器进行重建和存储。
照片摘自“保护隐私的个人健康数据流汇总”,第 5 页
生物医学数据集分析
对于下一个用例,我们将考虑使用不同的隐私保证来处理生物医学应用的大数据。DAMSEN⁴是一种系统,它支持针对众多数据分析任务的不同隐私保证,并利用有效的查询优化引擎来实现高准确性和低隐私成本。
如下图所示,DAMSEN⁴为数据分析任务(如直方图、长方体、机器学习算法(如线性和逻辑回归,可能推广到神经网络)和聚类任务)提供了不同的隐私保护。
注意:在与查询相关的数据分析任务的上下文中,直方图并不代表数据分布的传统可视化。直方图是一种特殊类型的查询,涉及将数据点分类到桶中。您可以将此类查询视为类似于 Pandas 的 groupby()函数,但功能更多。长方体是一项涉及多个汇总数据集和表格的分析任务——详细示例请参见 paper⁴大学。
照片摘自“Damson 演示:大 Data"⁴分析的不同隐私”,第 2–4 页
潜在项目想法:确保可视化的不同隐私保证。我找到的关于这个主题的两个资源是“个人数据的隐私感知可视化”和“可视化有差异的私人数据的挑战”。
有趣的是,DAMSEN 采用了压缩机制,这有助于将动力定位所需的噪音量降至最低:
CM 首先对数据进行编码,而不是在原始数据中添加噪声,就像在压缩感知中一样;然后,CM 将噪声添加到编码数据中,像在压缩感知中一样解码结果,并将其发布。因为转换后的数据是高度压缩的,它们需要更少的噪声来实现差分隐私。”⁵
减少噪音量很重要,因为我们希望确保被 DP 机制干扰的查询结果仍然尽可能准确。
分析电子健康记录
对于这个用例,我们考虑具有同态加密⁰.的 DP 扰动直方图论文《⁰》中提出的整个系统如下图所示:
照片摘自《通过混合方法传播保护隐私的生物医学数据》,⁰,第 3 页
我们可以看到,该系统涉及研究人员、可信第三方和云服务提供商等实体,每个实体在框架中都有自己特定的角色。
下图描述了提议框架的概念。我们可以看到用于密钥分发和安全直方图生成的同态加密组件所需的框架部分。根据该框架的 DP 部分,系统将加密的拉普拉斯噪声添加到直方图的每个箱的计数中,其中直方图计算的灵敏度为 1。
照片摘自《通过混合方法传播保护隐私的生物医学数据》,⁰,第 4 页
如前所述,直方图是一种查询,其结果可用于训练模型。
如下图所示,作者发现,虽然在原始数据集上训练的分类器实现了最高的性能,但作者在基于 DP 扰动 V 最优直方图采样的数据集上训练的分类器的性能类似于在基于无噪声 V 最优直方图采样的数据集上训练的分类器。当隐私预算减少到小于 0.1 时,这一发现出现例外,这导致大量噪声添加到数据中,AUC 下降,查询遗漏率增加。
照片摘自“通过混合方法保护隐私的生物医学数据传播”,⁰,第 7 页
因此,作者的一个结论是,隐私预算需要谨慎选择。他们还解释说,他们的安全模型可以防止所讨论的实体之间的信息交换出现各种泄漏——有关更多详细信息,请参见本文。
地理定位
微软的 PrivTree⁶系统利用不同的隐私来掩盖个人在地理位置数据库中的位置。该方法包括将地图分割成子区域,然后对每个子区域应用位置扰动,如下图所示。他们的系统,给定原始数据和一些其他参数(要使用的拉普拉斯噪声的尺度,用于决定是否应该发生节点分裂的阈值,等等)。),可以实现差分私有算法,并为几乎任何种类的位置数据输出噪声数据。
照片取自“隐私树项目:模糊你的“在哪里”privacy"⁶外景
美国人口调查局
一个有趣的用例是美国人口普查局决定将差分隐私作为隐私 strategy⁸.的一部分根据下图,他们打算在 2020 年通过“新隐私 system"⁷的全球首次大规模应用”来采用差别隐私。
照片片段摘自“Protections"⁷人口普查隐私史”
DP 研究挑战
让我们考虑一些我们在这篇博文中讨论的用例中常见的研究挑战(借用 DAMSEN⁵的话):
- "我们怎样才能最小化增加的噪音/最大化分析结果的效用?"
- “隐私预算是由数据所有者选择的参数,用于控制攻击者从发布的数据集中推断敏感信息的难度。每次分析都会消耗一些“隐私预算”。如何才能让预算尽可能长久?”
- 向读者提问:还有其他研究挑战需要考虑吗?
差分隐私引用
- 机器学习和基因组学:精准医疗与患者隐私 ↩
- 旨在增强基因组数据共享隐私的新兴技术 ↩
- 隐私保护的个人健康数据流聚合 ↩
- damson 演示:用于大数据分析的差分隐私 ↩
- 压缩机制↩
- 项目隐私树:模糊你的位置隐私 ↩
- 人口普查隐私保护的历史 ↩
- 保护美国统计数据的机密性:在人口普查局采用现代的避免披露方法 ↩
- 面向 SQL 查询的实用差分隐私 ↩
- 通过混合方法进行隐私保护的生物医学数据传播 ↩
- 在 SQL ↩ 中制作直方图频率分布
- “个人数据的隐私感知可视化” ↩
- “可视化差异私有数据的挑战” ↩
其他资源:差分隐私:使用大数据的技术说明
差分隐私代码库
感谢您的阅读!敬请关注未来关于联合学习用例的博文!😃
原载于 2020 年 4 月 30 日 https://blog.openmined.org。
Python 找到了带有数据重复问题的 Kusto 表
Python 与 Kusto 一起寻找重复
约书亚·迈克尔斯在 Unsplash 上的照片
Azure Data Explorer ( Kusto )是市场上最专注的关系数据库之一。整个系统运行在固态硬盘和内存中,以提供快速响应的数据分析。作为热路径数据存储,这可能是一个不错的选择。
由于各种原因,如客户端功能不良、数据管道不完善等。数据可能会多次被输入到 Kusto。这导致了数据重复的问题。如果摄取的数据是汇总数据,比如一组商店的总收入等,这个问题可能会更加严重。
数据重复会搞乱所有后续的数据分析,人们可能会据此做出错误的决定。因此,数据清理/重复数据删除是必要的。在此之前,我们需要首先确认,当前的 Kusto 表是否存在重复问题。
确认步骤是本文的重点。
主要思想包含以下步骤:
- 连接到 Kusto 集群。
- 查询表架构。
- 创建每行的唯一标识
- 对具有相同标识的行进行计数
- 查找任何计数大于 1 的标识值,标记为重复。
连接到 Kusto 集群
Python 有连接 Kusto 的包:Azure Data Explorer Python SDK。在这里,我们使用包:azure-kusto-data。
下面的代码片段将允许我们创建 KustoClient。它用于查询 Kusto 集群。在连接到 Kusto 之前,我们需要创建 AppId,并将其注册到 Kusto 集群。
查询表模式
getschema 将返回表模式。KustoClient 将返回表模式作为我们熟悉的 Pandas DataFrame。我们很容易做进一步的加工。
每行的唯一标识
假设,该表是一个汇总表。没有可以唯一标识该行的列子集。因此,我们将使用模式中的所有列来创建标识。标识将是所有列值的串联。
因此,我们将使用 tostring()操作符将所有非字符串数据转换为字符串。这就是 schema.apply( axis = 1) 的目的,其中 axis = 1 将逐行遍历表。
最后,Kusto 的 strcat() 将根据 hashOp 定义的操作连接所有的列。
如果对于另一个表,我们知道列的子集可以唯一地标识行,例如 user_id 和 order_id 的组合。在这种情况下,我们可以使用第二个 hashKusto 案例。
相同标识值计数并查找重复项
注意,我们上面创建的 hashKusto 值在 Kusto 查询中用作扩展。这将在 KustoTable 中创建一个额外的列, hash 。我们稍后使用 summarize 来获得每个标识散列的计数。
最后,重复的记录是 recordsCount > 1 的记录。
带走:
通过使用 Python,我们建立了一种简单直接的方法来验证和识别 Kusto 表中的重复行。这将为后续的数据分析提供坚实的基础。
利用数据共情成为更好的数据科学家
数据共情如何帮助您获得有意义的见解,并让您从优秀的数据科学家转变为伟大的数据科学家。来源:茱莉亚·尼库尔斯基,图标来自弗里皮克、 itim2101 ,以及www.flaticon.com的桉树。
办公时间
数据的上下文关系到数据项目的成功
英斯顿·丘吉尔曾经说过:“我只相信我篡改过的统计数据”。虽然这可能是一个极端的说法,但总体思路是正确的。数据可以有意或无意地以某种方式呈现,以支持不反映现实或潜在数据的论点。
CRISP-DM 模型的第二步是数据理解。这一步需要收集、描述和探索数据,以及识别数据质量问题。这种理解数据的大致轮廓是有用的。但是它没有提到一个重要的维度:数据共情。
对数据科学家工作的描述通常集中在硬技能和技术领域。这符合数据科学的维恩图。数据科学家受其领域专业知识的指导。在统计和机器学习模型以及编程工具的帮助下,他们从数据中提取知识。但是经常被忽视的软技能——例如 沟通技能怀疑态度 ,尤其是 同理心——在实现成功的数据科学项目和成为更优秀的数据科学家中发挥着至关重要的作用。****
定义数据共情
术语移情 是指
“理解、意识到、敏感地感受和体验他人过去或现在的感情、思想和经验的行为,而没有以客观明确的方式充分交流这些感情、思想和经验。”
移情和数据科学之间的逻辑联系是最终用户或利益相关者。通过同理心了解他们的需求和愿望将指导您的数据分析。这将使您能够创建更好、更有用的数据科学产品。然而,数据共情重在理解数据。它考虑了人类在数据收集过程中引入的主观性,并确定了偏差。****
乔希·卡拉布雷斯在 Unsplash 上的照片。
根据 Faghmous 和 Kumar (2014) ,数据移情意味着理解一个数据集的故事。数据是如何收集的,为什么要收集?根据数据的目的和收集过程,可以确定哪些偏差?元数据可以部分回答这些问题,元数据是与数据相关的结构化描述性信息。但是正如brnni Mann 和 Wintzer (2018) 指出的,数据共情走得更远。它描述了一个反思、解释和定性的过程:
- ****反思:我们应该思考任何可能影响数据收集过程的关于世界的无意识信念。这涉及到“人工智能中的偏见”——叙述。一个常见的例子是主要包含白人面孔的图像分类器数据集。该数据集不代表群体的多样性。任何使用这些数据构建的模型都将表现不佳。
- 解释性:我们需要考虑数据的背景。谁获取了数据,为什么,何时,如何获取的?以与疾病症状相关的数据为例。根据至少三种不同的情况,报告的症状可能会有所不同。(1)你说出你能想到的所有症状,而不需要医生提出任何引导性问题(潜在的回忆偏差)。(2)医生问你是否嗅觉丧失或喉咙痛(潜在的确认偏差)。(3)医生在没有问你任何问题的情况下对你进行检查并报告症状(潜在的观察偏差)。理解这些细微差别并揭示数据集中的这些偏差对于进一步的分析和见解的形成至关重要。
- ****定性:我们必须解决可能影响数据质量和收集流程的社会规范和价值观。尤其是自我报告的数据会受到社会规范的影响。社会期望偏差描述的是个体回答问题的方式符合社会规范和期望。
根据 Tanweer 等人(2016) 的说法,理解“……围绕数据的价值、意图和期望”是数据移情的关键。
数据共情的重要性
数据共情之所以重要,有几个原因。
- 首先,如果不应用数据移情,数据中的偏差可能仍然未被发现。这样会导致模型有偏差,结果无用。这在 Kaggle 比赛中可能无关紧要,因为你的主要目标是达到高精度。但是现实世界的项目有现实世界的含义。如果你在的招聘决策中使用有偏见的数据和模型,后果将是可怕的。
- ****第二,数据集的目的和背景可以指导你的数据分析过程。发现的偏差将决定您数据探索和准备步骤的重点。它会影响你对特性选择和工程的决定。甚至可以选择某些机器学习模型而不是其他模型来更好地控制偏差。
- ****第三,了解数据的背景可以带来新的数据收集流程和数据科学项目。一旦您确定了数据收集过程中的问题,请思考如何创建更好的数据集。你如何解释固有的偏见?假设你在你公司的历史招聘数据中发现了性别偏见。贵公司使用的其他数据是否存在类似的偏见或背景?你如何改善数据?利用这个机会来发现和描述这种偏见,以及如何在你的下一个项目中抵消它。
这对您的数据科学成功意味着什么
不要低估 CRISP-DM 模型第 2 步的重要性。如果你希望你的最终模型有用,数据理解,包括收集数据的步骤和理解周围的环境,是关键。虽然技术技能让你成为一名优秀的数据科学家,但考虑数据的社会维度会让你成为一名优秀的数据科学家。因此,要成为更好的数据科学家,请在您的项目中使用数据移情。不要只看数据集的数字,而要看上下文。****
结论
数据共情是理解数据的背景、价值和意图的过程。在您的数据科学流程中使用数据移情可以让您识别偏见。它有助于指导您的数据分析过程,并为您指出可以在下一个项目中回答的新问题。虽然我们喜欢相信数据在客观上是对的或错的,或真的或假的,但现实却更加微妙。在数据收集、数据探索和数据解释步骤中引入了人的主观性。作为一名数据科学家,你的工作就是承认这一点,并在你的分析中说明这一点。只有这样,你的模型和结果才是重要的。只有这样,你才能成为更好的数据科学家。
你想在媒体上阅读更多高质量的故事吗?考虑注册一个支持我和其他媒体作者的会员。
** [## 通过我的推荐链接加入 Medium-Julia Nikulski
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@julia.nikulski/membership)**
如果你想马上应用数据移情,但你目前没有项目想法,请查看我的文章如何开发新的独特的数据科学项目想法。
帮助您识别值得一试的新颖独特的数据项目的指南
towardsdatascience.com](/5-steps-to-develop-unique-data-science-project-ideas-6c2b3a0014b)**
在下一个 Golang 项目中使用环境变量
golang 中有多种方法可以使用环境变量和文件。
照片由 Moja Msanii 在 Unsplash 上拍摄
当创建生产级应用程序时,在应用程序中使用环境变量是事实上的。
也可以看 youtube 视频。
我们为什么要使用环境变量?
假设您有一个具有许多特性的应用程序,每个特性都需要访问数据库。您在每个特性中配置了所有的数据库信息,如DBURL
、DBNAME
、USERNAME
和PASSWORD
。
这种方法有几个主要缺点,但也有很多。
安全问题:
- 你在输入密码中的所有信息。现在,所有未经授权的人也可以访问数据库。
- 如果你使用的是代码版本控制工具
git
,那么一旦你发布代码,你的数据库的细节就会公之于众。
代码管理:
- 如果你改变一个单一的变量,那么你必须改变所有的特征。很有可能你会错过一两个。😌去过那里
- 您可以对环境变量进行分类,如
PROD
、DEV
或TEST
。只需给变量加上环境前缀。
开始时,它可能看起来像一些额外的工作,但是这将在你的项目中奖励你很多。
⚠️只是不要忘记在
**.gitignore**
中包含你的环境文件。
是采取行动的时候了。🔨
在这个教程中我们要做什么?
在本教程中,我们将以 3 种不同的方式访问环境变量。
你可以根据你的需要来使用它。
os
包装godotenv
包装viper
包装
创建项目
在**$GOPATH**
之外创建一个项目**go-env-ways**
。
初始化模块
打开项目根目录下的终端,运行下面的命令。
***go mod init goenv***
这个模块将记录项目中使用的所有包及其版本。类似于nodejs
中的package.json
。
让我们从最简单的开始,使用os
包。
操作系统包
Golang 提供了os
包,这是一种配置和访问环境变量的简单方法。
要设置环境变量,
***os.Setenv(key, value)***
要获得环境变量,
***value := os.Getenv(key)***
在项目中创建一个新文件main.go
。
***package main**
import (
"fmt"
"os"
)
// use os package to get the env variable which is already set
**func envVariable(key string) string** {
// set env variable using os package
**os.Setenv(key, "gopher")**
// return the env variable using os package
**return os.Getenv(key)**
}
**func main() {**
// os package
** value := envVariable("name")**
**fmt.Printf("os package: name = %s \n", value)** **fmt.Printf("environment = %s \n", os.Getenv("APP_ENV"))**
}*
运行以下命令进行检查。
***APP_ENV=prod go run main.go**
// Output
**os package: name = gopher
environment = prod***
GoDotEnv 包
加载.env
文件最简单的方法是使用godotenv
包。
安装
在项目根目录下打开终端。
***go get github.com/joho/godotenv***
godotenv
提供了一个Load
方法来加载 env 文件。
*// Load the .env file in the current directory
**godotenv.Load()**
// or
**godotenv.Load(".env")***
Load 方法可以一次加载多个 env 文件。这也支持
*yaml*
。更多信息请查看 文档 。
在项目根目录下创建一个新的.env
文件。
***STRONGEST_AVENGER=Thor***
更新main.go
。
***package main**
import (
...
// Import godotenv
**"github.com/joho/godotenv"**
)
// use godot package to load/read the .env file and
// return the value of the key
**func goDotEnvVariable(key string) string {**
// load .env file
**err := godotenv.Load(".env")**
if err != nil {
log.Fatalf("Error loading .env file")
}
**return os.Getenv(key)**
}
**func main() {**
// os package
...
// godotenv package
**dotenv := goDotEnvVariable("STRONGEST_AVENGER")**
fmt.Printf("godotenv : %s = %s \n", "STRONGEST_AVENGER", dotenv)
}*
打开终端并运行main.go
。
***go run main.go**
// Output
**os package: name = gopher**
**godotenv : STRONGEST_AVENGER = Thor***
只需在主函数中添加 os 包末尾的代码即可。
毒蛇包装
Viper 是 golang 社区中最受欢迎的软件包之一。许多围棋项目都是使用 Viper 构建的,包括 Hugo、Docker 公证人、Mercury。
毒蛇🐍是 Go 应用的完整配置解决方案,包括 12 因素应用。它设计用于在应用程序中工作,可以处理所有类型的配置需求和格式。读取 JSON、TOML、YAML、HCL、envfile 和 Java 属性配置文件
更多信息请阅读蝰蛇的官方文档
安装
在项目根目录下打开终端。
***go get github.com/spf13/viper***
要设置配置文件和路径
***viper.SetConfigFile(".env")***
要读取配置文件
***viper.ReadInConfig()***
使用键从配置文件中获取值
***viper.Get(key)***
更新main.go
。
***import** (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
**"github.com/spf13/viper"**
)
// use viper package to read .env file
// return the value of the key
**func viperEnvVariable(key string) string {**
// SetConfigFile explicitly defines the path, name and extension of the config file.
// Viper will use this and not check any of the config paths.
// .env - It will search for the .env file in the current directory
**viper.SetConfigFile(".env")**
// Find and read the config file
**err := viper.ReadInConfig()**
if err != nil {
log.Fatalf("Error while reading config file %s", err)
}
// viper.Get() returns an empty interface{}
// to get the underlying type of the key,
// we have to do the type assertion, we know the underlying value is string
// if we type assert to other type it will throw an error
**value, ok := viper.Get(key).(string)**
// If the type is a string then ok will be true
// ok will make sure the program not break
if !ok {
log.Fatalf("Invalid type assertion")
}
** return value**
}
**func main() {**
// os package
...
// godotenv package
...
// viper package read .env
** viperenv := viperEnvVariable("STRONGEST_AVENGER")**
fmt.Printf("viper : %s = %s \n", "STRONGEST_AVENGER", viperenv)
}*
打开终端并运行main.go
。
毒蛇不仅限于。环境文件。
它支持:
- 设置默认值
- 读取 JSON、TOML、YAML、HCL、envfile 和 Java 属性配置文件
- 实时观察和重读配置文件(可选)
- 从环境变量中读取
- 从远程配置系统(etcd 或 Consul)读取,并观察变化
- 从命令行标志中读取
- 从缓冲区读取
- 设置显式值
Viper 可以被看作是满足应用程序所有配置需求的注册表。
让我们实验一下:💣
在项目根目录下创建一个新的config.yaml
文件。
***I_AM_INEVITABLE: "I am Iron Man"***
要设置配置文件名
***viper.SetConfigName("config")***
要设置配置文件路径
*// Look in the current working directory
**viper.AddConfigPath(".")***
要读取配置文件
***viper.ReadInConfig()***
更新**main.go**
*// use viper package to load/read the config file or .env file and
// return the value of the key
**func viperConfigVariable(key string) string** {
// name of config file (without extension)
**viper.SetConfigName("config")**
// look for config in the working directory
** viper.AddConfigPath(".")**
// Find and read the config file
**err := viper.ReadInConfig()**
if err != nil {
log.Fatalf("Error while reading config file %s", err)
}
// viper.Get() returns an empty interface{}
// to get the underlying type of the key,
// we have to do the type assertion, we know the underlying value is string
// if we type assert to other type it will throw an error
**value, ok := viper.Get(key).(string)**
// If the type is a string then ok will be true
// ok will make sure the program not break
if !ok {
log.Fatalf("Invalid type assertion")
}
** return value**
}
**func main()** {
// os package
...
// godotenv package
...
// viper package read .env
...
// viper package read config file
**viperconfig := viperConfigVariable("I_AM_INEVITABLE")**
fmt.Printf("viper config : %s = %s \n", "I_AM_INEVITABLE", viperconfig)
}*
打开终端并运行main.go
***go run main.go**
// Output
**os package: name = gopher**
**godotenv : STRONGEST_AVENGER = Thor
viper : STRONGEST_AVENGER = Thor
viper config : I_AM_INEVITABLE = I am Iron Man***
结论
就这样,现在你可以探索他们更多的秘密了🔐。如果你发现一些值得分享的东西,不要犹豫😉。
完整的代码可以在 GitHub 上找到。
用 Flask 和 SQLalchemy,不要用 Flask-SQLAlchemy!
避免 Flask 应用程序中的 Flask-SQLAlchemy
作者: Edward Krueger 数据科学家兼讲师和 Douglas Franklin 助教兼技术作家。
在这篇文章中,我们将介绍如何使用带有 SQLAlchemy 的烧瓶,以及避免烧瓶 SQLAlchemy 的一些原因。此外,我们将展示拥有独立于应用程序的 SQLAlchemy 模型和数据库连接的好处。
Tobias Fischer 在 Unsplash 上拍摄的照片
SQLAlchemy 是什么?
SQLAlchemy 是一个 Python SQL 工具包和对象关系映射器(ORM ),允许应用程序开发人员使用 SQL 进行平滑和容错的事务数据库操作。ORM 将 Python 类转换成关系数据库的表,并自动将 Pythonic SQLAlchemy 表达式语言转换成 SQL 语句。这种转换允许开发人员使用 Python 语法编写 SQL 查询。SQLAlchemy 还抽象数据库连接,并自动提供连接维护。这些特性使 SQLAlchemy 成为装载和查询数据库的绝佳包。
什么是烧瓶?
Flask 是一个微框架,允许你用 Python 构建 web 应用。对于初学者来说,Flask 很容易上手,因为启动和运行一个简单的应用程序几乎没有样板代码。
例如,下面是一个有效的“你好,世界!”Flask web 应用程序:
**from flask import Flask****app = Flask(__name__)****@app.route('/')
def hello_world():
return "Hello, World!"****if __name__ == '__main__':
app.run()**
什么是 Flask-SQLAlchemy?
Flask-SQLAlchemy 是 Flask 的扩展,旨在通过提供缺省值和助手来完成常见任务,从而简化 SQLAlchemy 与 Flask 的使用。最受欢迎的助手之一是处理整个应用程序的数据库连接。但是,使用 base SQLAlchemy 可以确保数据库连接会话在整个应用程序中可用,而不需要 Flask-SQLAlchemy。
Flask-SQLAlchemy 的目的是处理连接的返回,以防止工作线程出现问题。当应用程序用户从一条路线切换到另一条路线时,就会出现这些问题。以下是 Flask 应用程序中出现线程问题时出现的常见错误。
**sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 12345 and this is thread id 54321.**
这通常是由于会话或数据库连接对于应用程序的一部分不可用。这个错误实际上会破坏您的应用程序,必须解决它才能继续开发。
烧瓶-SQLAlchemy 弱点
我们选择避免 Flask-SQLALchemy 默认行为来防止这种错误,而是使用 SQLALchemy 特性来处理这些问题。这是因为 Flask-SQLALchemy 与 SQLALchemy 相比有劣势。
其中之一是 Flask-SQLAlchemy 有自己 API。这增加了复杂性,因为 ORM 查询和模型的不同方法与 SQLAlchemy API 是分开的。
另一个缺点是 Flask-SQLAlchemy 使得在 Flask 上下文之外使用数据库变得困难。这是因为,使用 Flask-SQLAlchemy,数据库连接、模型和 app 都位于 app.py 文件中。由于模型在应用程序文件中,我们与应用程序之外的数据库进行交互的能力有限。这使得在应用程序之外加载数据变得困难。此外,这使得很难在 Flask 上下文之外检索数据。
如果使用正确,Flask 和 SQLAlchemy 可以很好地配合使用。所以,你不用把 Flask 和 SQLAlchemy 杂交成 Flask-SQLalchemy!
使用 SQLAlchemy,而不是 Flask-SQLAlchemy!
一次定义数据库和模型
理想情况下,您应该只需要定义一次数据库模型!使用单独的 database.py 和 models.py 文件,我们可以一次性为其表建立数据库连接和类,然后在需要时调用它们。使用 Flask-SQLAlchemy 进行组件分离要困难得多,因为您必须使用应用程序本身来创建数据库。
下面是一个使用 SQLAlchemy 定义数据库连接的文件。
示例 database.py 文件
注意,我们将上面 database.py 文件中的‘Base’类导入到下面的 models.py 文件中,以使用declarative_base()
。
示例 models.py 文件
该文件为数据库中的表“Records”创建模型或模式。
使用 SQLAlcehmy 的declarative_base()
允许您为应用程序使用的每个表编写一个模型。然后,在 Python 中,在应用程序之外和数据库中使用该模型。
在应用程序外部加载数据
拥有这些独立的 Python 文件很好,因为您可以使用相同的模型在应用程序之外查询或加载数据。此外,每个模型和数据库连接都有一个版本,这简化了开发。
这些模型和数据库连接可用于在数据管道、报告生成或任何其他需要的地方引用相同的模型或数据库。
单单是加载脚本就是使用 SQLAlchemy 的一个很好的理由。该功能允许使用单独的 Python 文件加载数据库,而不是使用应用程序加载数据。
下面是一个示例 Python 文件,它从 CSV 读取数据,并将数据插入到数据库中。
load.py 脚本示例
请注意,我们导入了模型、我们的自定义会话 SessionLocal 和我们在其他 Python 文件中定义的引擎。
这个单独的 load.py 文件允许我们在不运行应用程序的情况下将数据插入数据库。
声明性库和元数据
**declarative_base()**
基类包含一个**MetaData**
对象,其中收集了新定义的**Table**
对象。当我们调用行**models.Base.metadata.create_all()**
来创建我们所有的表时,这个元数据对象被访问。
作用域会话和本地会话:处理线程问题
SQLAlchemy 包括一个助手对象,帮助建立用户定义的**Session**
范围。通过**scoped_session**
函数,SQLAlchemy 可以处理工作线程问题。
sessionmaker 是一个工厂,用于通过从引擎的连接池中请求连接并将连接附加到新的会话对象来初始化新的会话对象。
初始化新的会话对象也称为“检出”连接。数据库存储这些连接/过程的列表。因此,当您开始一个新的会话时,您也在数据库中启动了一个新的进程。
scoped_session 是所有这些创建的会话对象的注册表,其中注册表的键/标识是某种形式的线程安全 id。
我们在上面的 database.py 文件中定义了 SessionLocal,方法是调用会话工厂 sessionmaker,并向其传递一些参数。
来自 database.py 的会话本地
scopefunc '是传递给 scoped_session 的可选参数,用作标识 getter 函数,返回用于查找或注册新会话的密钥。正在添加
_app_ctx_stack。ident_func `是两个函数之一:
- 如果安装了 greenlet,它会使用
getcurrent
(from greenlet import getcurrent
) - 否则,它使用
get_ident
(from threading import get_ident
),返回线程 id。
默认情况下 scopefunc 是get_ident
。因此,对于简单的应用程序,您只需:
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
这个新的 SessionLocal 允许应用程序的不同部分调用一个全局scoped_session
,这样所有的应用程序路由都可以共享同一个会话,而不用显式地将会话传递给路由。我们在注册表中建立的 SessionLocal 将一直保留,直到我们通过调用scoped_session.remove()
明确地告诉我们的注册表处理它:
这里我们可以看到对 scoped_session 的调用,其中我们的自定义会话 SessionLocal 作为参数传递。
app.py 文件通过调用 scoped_session 来定义 app.session
此外,作用域会话使我们能够访问 query_property。因此,如果您的样式由 flask_sqlalchemy 使用,您可以将它与 sqlalchemy 一起使用:
Base = declarative_base()
Base.query = db_session.query_property()
结束交易
方法db_session.close()
只结束本地会话对象的事务,但不结束与数据库的连接,也不自动将连接返回到池。
通过添加 db_session.remove(),我们可以确保连接被正确关闭。
db_session.remove()方法首先运行app.db_session.close()
,然后将连接返回到连接池。因此,我们在本地和远程数据库终止了该进程。如果数据库没有关闭这些连接,则存在可以达到的最大连接数。数据库最终会终止像过时连接这样的空闲进程;然而,这可能需要几个小时才会发生。SQLAlchemy 有一些池选项来防止这种情况,但是最好在不再需要连接时删除它们!
结论
正如我们所看到的,SQLAlchmy 有工具来处理开发人员求助于 Flask-SQLAlchemy 来避免的错误。通过正确实现 sessionmaker 和 scoped_session,您的 Flask 应用程序应该不会有任何线程问题,这些问题会在通过您的路由连接到数据库时出现。
因此,在处理线程和数据库会话时,使用 Flask 和 SQLAlchemy,而不是 Flask-SQLAlchemy!
特别感谢 Seth Kaufman 帮助编写我们的 Flask 应用程序,请务必查看 GitHub 上的资源库。
使用谷歌工作表,S3 和 Python 快速建立一个网站
非 web 开发人员生存指南
在 Unsplash 上 barnimages 拍摄的照片
在我们开始之前,先介绍一些背景知识:
几天前,我在寻找因新冠肺炎而免费或打折的课程。我想其他人可能也在这样做,所以我决定收集一些资源并在网上发布。
我开始用 Google Sheet 编辑课程,并计划在获得足够的资源后分享它。然而,有件事困扰着我。在手机上打开页面很糟糕,大多数人用手机浏览互联网。我以为我能做得更好。
问题是我在网站开发方面没有什么经验。此外,我不想花费超过几个小时来开发和发布网站。所以我决定快速建造一些东西。
以下是我为快速建立网站而设定的要求,以及我为满足这些要求而采取的方法:
要求
- 该网站应该加载速度快,在手机上看起来很好(或者至少比谷歌表更好)
- 我需要能够快速、轻松地添加或删除资源。请记住,我可能希望在未来从客户端添加更多的交互性。
- 尽可能多地使用 Python(尽可能少地使用 HTML/CSS/JS)
- 我应该只需要几个小时就可以开发和发布
- 维护成本应该非常非常接近零😛
接近
- 用于引导程序(仅 CSS,不包括 JS 组件)
- 使用 Google Sheets 管理内容。我使用 Google Sheets API 以编程方式将内容放入站点。如果需要,可以很容易地从 Google Sheet 创建一个 web API。
- 使用 Jinja2 从基本的 HTML/CSS 模板生成网站
- 在 AWS S3 bucket + Cloudfront 上托管站点(用于 SSL 证书)。用 53 号公路买下了域名
- 我对 AWS 服务的使用属于免费层。我不认为这种情况会很快改变。到目前为止,我只在网站上投资了 15€
几个小时后,我发射了stayhomeandlearn.org。
本文的其余部分是关于如何使用 Google Sheets、AWS 和 Python 构建静态站点的教程。
对于本教程,我们将建立一个从 Google Sheets 读取数据的脚本,使用预定义的模板生成一个静态站点,并将其部署到 S3 存储桶。这篇文章是为那些对 web 开发知之甚少,但想快速上手的程序员准备的。
教程中有五个部分:需求,回顾代码和 Jinja 模板,使用 Google Sheets API,构建和部署你的站点。
要求
这些你需要自己设置或检查。为此,我添加了一些链接。
- Python > = 3.7
- 谷歌账户
- 谷歌云平台(GCP)账户
- 亚马逊 AWS 账户
- AWS CLI (如果你有 Mac 的话可以使用 brew)
- 在 AWS CLI 中配置的配置文件
- 一点 HTML 和 CSS
代码和 Jinja 模板
首先,创建一个名为my_pokemon_stats
的目录,并从那里打开一个终端。然后,创建一个虚拟环境并安装所需的软件包,如下所示:
接下来,在那里下载并保存这两个文件:template.html和 site_builder.py 。这些是生成站点的构建块。
template.html
是我们将用于构建网站的 Jinja 模板。这是一个类似 HTML 的文件,您可以在其中添加将用 Python 处理的逻辑,并生成最终的站点。该文件如下所示:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="[https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css](https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css)" rel="stylesheet"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<title>My Pokemon Stats</title>
</head>
<body><header id="header">
<div class="container text-center">
<h1 class="pt-5 pb-1 font-weight-bold">
My Pokemon Stats
</h1>
<hr>
<p class="pt-2">
This is a site I use to store the stats of all my Pokemon.
</p>
</div>
</header><section id="pokemon_table">
<div class="container py-4">
<div class="table-responsive">
<table class="table table-hover">
<thead class="thead-dark">
<tr>
<th scope="col">Name</th>
<th scope="col">Type 1</th>
<th scope="col">Type 2</th>
<th scope="col">Total</th>
<th scope="col">HP</th>
<th scope="col">Attack</th>
<th scope="col">Defense</th>
</tr>
</thead>
<tbody>
{% for row in data %}
<tr>
<td>{{ row["Name"] }}</td>
<td>{{ row["Type 1"] }}</td>
<td>{{ row["Type 2"] }}</td>
<td>{{ row["Total"] }}</td>
<td>{{ row["HP"] }}</td>
<td>{{ row["Attack"] }}</td>
<td>{{ row["Defense"] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</section>
</body>
</html>
让我们来分解一下:
- 您可以放心地忽略
<head>
标签中的大部分内容。这是你将在大多数页面中看到的标准 HTML5 代码。然而,我们将仔细研究两个有趣的标签:<link>
和<title>
。 - 在这种情况下,
<link>
标签用于导入引导组件库。我们将使用它来为页面的不同部分定义简单的样式,并毫不费力地使它看起来很好。<title>
定义页面的标题(你在浏览器标签中看到的),它对 SEO 和社交媒体分享很有用。 - 接下来,在
<body>
标签中有一个<header>
部分。这是我们定义将出现在页面上的文本的地方。它将看起来像下面的图像。我使用了 Bootstrap 的标准样式来居中文本,并添加了一些填充。
- 最后,我们有了
<section id="pokemon_table">
。<div>
和<table>
标签为构建表格提供了一些基本的样式。接下来,我们在<thead>
标签中定义表格的标题。标签里面是 Jinja 施展魔法的地方 {% for row in data %}
是一个循环,遍历口袋妖怪的每一行数据。在每个<td>{{ row["..."] }}</td>
中,我们从字段中获取每一行的信息(例如名称、类型 1、类型 2)。这会生成如下所示的内容:
接下来,我们有了site_builder.py
文件。这个脚本从 Google Sheets 下载口袋妖怪的数据,处理数据和template.html
文件,然后将结果文件上传到 S3 桶。
import csv
import boto3
import gspread
import jinja2
from oauth2client.service_account import ServiceAccountCredentials
AWS_PROFILE = "INSERT-AWS-PROFILE-HERE"
BUCKET = "INSERT-BUCKET-NAME-HERE"
WORKBOOK = "INSERT-WORKBOOK-NAME-HERE"
def download_data():
"""Download data using the Google Sheets API"""
scope = [
"https://spreadsheets.google.com/feeds",
"https://www.googleapis.com/auth/drive",
]
credentials = ServiceAccountCredentials.from_json_keyfile_name(
"credentials.json", scope
)
client = gspread.authorize(credentials)
worksheet = client.open(WORKBOOK).get_worksheet(0)
sheet_values = worksheet.get_all_values()
print(f"Downloading: {worksheet.title}")
with open("my_pokemon_stats.csv", "w") as f:
writer = csv.writer(f)
writer.writerows(sheet_values)
def generate_site():
"""Generate site in local directory"""
print("Process data and build site")
template_loader = jinja2.FileSystemLoader(searchpath="./")
template_env = jinja2.Environment(loader=template_loader)
template = template_env.get_template("template.html")
with open("my_pokemon_stats.csv") as csv_file:
csv_reader = csv.DictReader(csv_file)
data = [row for row in csv_reader]
output = template.render(data=data)
with open("index.html", "w") as f:
f.write(output)
def deploy_site():
"""Deploy site S3 bucket"""
print("Upload data to S3")
session = boto3.Session(profile_name=AWS_PROFILE)
s3 = session.resource("s3")
s3.Bucket(BUCKET).upload_file(
Filename="index.html", Key="index.html", ExtraArgs={"ContentType": "text/html"}
)
if __name__ == "__main__":
download_data()
generate_site()
deploy_site()
代码由三个功能构成:download_sheets
、generate_site
和deploy_site
。我们将在接下来的小节中详细介绍如何访问 AWS 和 Google Sheets API。
使用 Google Sheets API
按照以下步骤使用 Google Sheets API 下载口袋妖怪的数据:
- 在谷歌工作表中创建一个工作簿(你可以复制我的:我的口袋妖怪统计)
- 进入谷歌 API 控制台
- 创建一个名为 MyPokemonStats 的新项目。
- 点击启用 API 和服务。搜索并启用 Google Sheets API。
- 回到Google API 控制台并再次点击启用 API 和服务。现在搜索并启用 Google Drive API。
- 点击创建凭证。 下 4 题选择:Google Drive API, Web 服务器(如 node.js,Tomcat) ,应用数据,和不,我不使用它们。
- 点击我需要什么凭证?为服务账户选择一个名称(例如 get-data)授予其一个项目角色编辑。为键类型选择 JSON 选项
- 将会打开一个对话框。保存 JSON 文件,复制到
my_pokemon_stats
目录,重命名为credentials.json
。 - 打开
credentials.json
文件。找到一个名为client_email
的键,复制它的值(例如 get-data@iam....).在 Google Sheets 中返回到您的工作簿,点击右上角的共享按钮,将客户电子邮件粘贴到人员字段,赋予其编辑权限。点击发送。 - 转到
site_builder.py
脚本,将WORKBOOK
变量设置为您在第一步中给工作簿起的名字。
设置 S3 时段和与 AWS 相关的配置
现在,让我们创建 S3 桶,并配置我们的代码以编程方式访问 AWS:
- 前往亚马逊 S3 控制台
- 创建 S3 存储桶
- 一旦进入桶中,点击属性,然后点击静态网站托管**
- 选择选项使用此桶托管网站**
- 在索引文件和错误文件下放置
index.html
- 保存来自端点的 URL。您将使用该 URL 连接到您的站点。
- 转到权限并点击编辑**
- 清除阻止所有公共访问,选择保存,并确认。当您更改此项时,互联网上的任何人都可以访问此存储桶的内容。当你发布一个网站时,这就是你想要的,但是,不要把任何私人的东西放在那里!
- 现在转到 Bucket Policy ,替换下面策略中的 Bucket 名称,粘贴到那里,点击 Save。
*{
"Version":"2012-10-17",
"Statement":[{
"Sid":"PublicReadGetObject",
"Effect":"Allow",
"Principal": "*",
"Action":["s3:GetObject"],
"Resource":["arn:aws:s3:::BUCKET-NAME-HERE/*"
]
}
]
}*
10.转到site_builder.py
脚本。将变量AWS_PROFILE
变量设置为用于访问 AWS 的配置文件名称(在 UNIX 系统中,它应该是~/.aws/credentials
中的一个配置文件)。
构建和部署您的站点
最后,您应该能够从项目的根文件夹中运行python site_builder.py
来生成站点。这将从谷歌工作表下载数据,使用 Jinja 处理template.html
文件,并将网站上传到 S3 桶。
如果您想要检查站点,请转到端点 URL(上一节中的步骤 6)。
结束语
这种方法绝不是完美的,但会帮助你快速出货。我用这个策略建造了stayhomeandlearn.org,效果很好。从 4 月 1 日到 4 月 16 日,这个网站有超过 15000 的访问者,这超过了我最乐观的预期。
这个网站正在慢慢走向死亡。然而,这个过程教会了我关注运输而不是浪费时间寻找完美的工具有多重要。我很快建立了网站,人们喜欢它,第一天之后,它的流量已经超过了我迄今为止做过的任何一个附带项目。完美是好的敌人,这是真的。
在我的例子中,出于样式和部署的目的,我必须向脚本添加更多的功能。有兴趣的可以看看我的 GitHub 资源库里的代码。
最后,现在你可以做几件事来让你的网站更有趣:
本文原载于 我的博客 。
参考
[1] G. Bauges,谷歌电子表格和 Python (2017)
[2] V. Drake,H .用 AWS S3、Route 53 和 CloudFront 固定你的静态站点(2017)
[3] A .巴拉达斯,口袋妖怪统计 (2016)
用机器学习预测赛马
将机器学习知识应用于现实世界分类问题的指南
背景
我是 HKU 大学计算机科学硕士的非全日制学生。在上学期的考试之后,我在想将机器学习应用到真实世界的数据集上会很有趣也很酷。
我很快就找到了机器学习的好网站, Kaggle 。Kaggle 为数据科学学生和专业人士提供了许多有趣的数据集。我搜索“香港”,因为我想找到一个与我密切/相关的数据集,我得到了香港赛马的数据集。非常感谢格雷厄姆·戴利在 Kaggle 上发布数据集。
我非常兴奋能够从事我的第一个真实世界机器学习项目。我觉得赛马是可以预测的,是典型的分类问题。
Julia Joppien 在 Unsplash 上拍摄的照片
摘要
在这篇文章中,我将与你分享如何做数据预处理,神经网络模型的建立和训练。我们准备用熊猫、tensorflow、numpy、sklearn 等常见的机器学习包。最后,我也会分享一些我在这个项目之后走出来的思考。
数据预处理
数据集包含两个 csv 文件:races.csv 和 runs.csv。这两个表通过列“race_id”相关联。我们将需要连接这两个表,以便为训练生成有意义的数据。
处理 races.csv 文件
用于处理 races.csv 文件的代码
- 第 1-6 行:导入我们将用于项目的包。
- 第 8–9 行:使用 pandas 读取 csv 文件。然后,选择我认为重要的 6 个栏目。
- 第 11–13 行:数据集包含 NaN 是很常见的,这意味着某些字段丢失了。在这里,让我们只是放弃他们。
- 第 15–23 行:一些列是字符串。但是,神经网络模型只处理数字,所以我们需要对它们进行编码。字符串列有不同的类型:名义列和序数列。我们对列“venue”使用 LabelEncoder,而对列“config”和“going”使用 OrdinalEncoder。
到目前为止,我们对来自 races.csv 的数据很满意。
处理 runs.csv 文件
用于处理 runs.csv 文件的代码
runs.csv 文件包含每场比赛的马匹数据,通过 race_id 与 races.csv 相关联。通常,每场比赛有 14 匹或更少的马一起比赛。该代码与我们对 races.csv 文件所做的非常相似,所以我不打算逐行解释。需要注意的一点是,在上面的第 10–13 行,我们需要删除一些有噪声的数据,原因在代码行内注释中有解释。处理后的数据帧头如下图所示。
您可能认为我们已经完成了 runs.csv 文件,但事实并非如此,因为我们需要考虑如何将数据输入神经网络。基本上,我们需要 races.csv 中的一行加上 runs.csv 中属于同一种族的所有行,并将它们放在一起作为神经网络的一个样本输入。下面的代码将对 runs dataframe 进行整形,以便相同种族的行将形成一行。
- 第 1–5 行:我们定义了一个小函数 her 来对列进行排序。
- 第 7 行:magic pivot 方法对 runs.csv 数据进行了整形,使相同种族的行成为一行。列的排序如下[(马龄,1),(马龄,2),(马龄,3) … ]。但是,我希望列像[(horse_age,1),(horse_country,1),(horse_type,1)……(horse _ age,2),(horse_country,2),(horse_type,2)……],这样我们将按顺序拥有 horse-1-features,horse-2-features,horse-3-features。我花了很长时间才弄明白该用哪个熊猫 API 来做这件事。不得不提的是,我们需要避免使用循环来争取更好的计算效率。
- 第 8–10 行:使用第 1–5 行中定义的函数对列进行排序。除了对马的特性进行分组之外,它还将“结果”列放在最后。因此最右边的列将是[……(结果,11),(结果,12),(结果,13),(结果,14)]。将它们放在最后,因为它们是输出,而不是特征输入。
- 第 12–14 行:正如行内注释所解释的,我们的神经网络需要 14 匹马的数据作为输入。在这里,我们简单地用 0 填充虚拟马特征。
准备训练和测试数据集
你看,数据预处理的工作量很大。幸运的是,我们快到了。现在,让我们做最后一点,为神经网络准备好数据。
- 第 1 行:通过“race_id”连接我们上面准备的两个数据帧。
- 第 2 行:选择除最后 14 列之外的所有列作为输入 X 。
- 第 3-4 行:应用特征缩放技术,标准化,这使得培训更容易。否则,网络很难学习特征“申报体重”(1100 sth)和特征“马龄”(大约 3-5)的参数。
- 第 6 行:将列“结果”转换为输出 y 。这是一个二元分类。因此,如果这匹马得了第一名,我们就放 1 ,否则就放 0 。
- 第 8–9 行:简单地打印出输入和输出的形状来看看。我们可以看到,我们有 6348 个比赛,每个比赛有 104 个特征和 14 个输出。
(6348, 104)
(6348, 14)
- 第 11–12 行:使用 sklearn 提供的一个方便的 util 方法来分割数据以训练和测试(验证)集合。
建立神经网络模型
首先,我想向你展示神经网络的架构如下。这是项目的核心。到目前为止,我们所做的所有数据预处理都是为了输入神经网络。
图片由作者提供:赛马的神经网络
- 输入层:104 个节点,从 races.csv 文件中取 6,从 runs.csv 文件中取 7x14。
- 隐藏层:只有 96 个节点。我认为这对于我们的项目来说已经足够了,因为这个分类的功能并不复杂。
- 输出层:14 个节点,每个节点表示一匹马是否赢得了比赛。
代码如下所示,非常简单,这要感谢 keras。请注意度量。我选择 precision, 𝑝𝑟𝑒𝑐𝑖𝑠𝑖𝑜𝑛 = 𝑇𝑃/(𝑇𝑃+𝐹𝑃) 作为评估参数,因为赌赢是我们的兴趣所在。
模型细节打印如下。可训练参数是 11,438,这是神经网络的能力。这意味着网络将学习和调整这些参数中的每一个,以便找到一个函数 y = f(X)来拟合我们的数据。
训练网络,策划表演
- 第 1–4 行:在输入数据用于训练之前,进一步扭曲数据。
- 第 6–8 行:培训本身。在训练过程中,控制台会打印进度。
- 第 10–26 行:绘制性能图,图表如下所示。
作者图片:精确绘图
作者图片:损失的策划
该网络足够强大,可以很好地适应训练数据集。然而,有很大的过度拟合。我们在验证数据集上可以达到的最佳性能大约是精度=0.3,这发生在纪元 60~80 左右。Precision=0.3 意味着我们可以在 10 个赢注中正确获得 3 个。这个性能没有我预期的高。原因可能是大多数比赛都是障碍赛,这意味着跑步者携带不同的重量来平衡他们赢得比赛的机会,参见参考文献 Racing 101 。
一些想法
- 在数据分析之前,应该学习领域知识。我的教训是,我不理解赛马术语,如“win_odds”和“actual_weight ”,所以我不知道哪些列是有用的功能。在研究了指南之后,事情变得清晰多了。
- 在编写代码之前做更多数据分析。找到数据集后,我很快开始编码。你可以看到我的另一个笔记本,其中我犯了一个大错误,我把一行 runs.csv 文件当成了一个样本。一匹马能否赢得一场比赛是相对于同场比赛的其他马而言的,所以我们要把一场比赛的 14 匹马的数据放在一起作为一个样本。
- 我听人说过,数据预处理通常比建模和训练花费更多的时间。我发现这个项目确实如此。Pandas 有数百个强大的 API 供您操作数据帧,要想选择正确的 API 快速完成工作,需要花时间熟悉它们。
- 做这个项目真的可以学到很多东西。这比课程作业要多得多。
总结
在这篇文章中,我与您分享了如何在 Kaggle 的真实世界数据集上端到端地应用机器学习技能。我的完整笔记本可以在这里找到。非常感谢您的阅读,并欢迎您的评论。
2020 年使用 Numpy 进行统计和算术运算
用于数据科学和机器学习的大多数数据都存储为数据帧或数字数组。在本文中,我们将讨论 Numpy
NumPy 为什么
NumPy 是 Python 为科学计算提供的库。机器学习和数据分析需要存储大量的数据,而更多的时候,NumPy 是用来存储数据的。下面列出了它的一些好处
- 与列表相比,Numpy 使用更少的空间来存储数据。您可以指定数组数据类型,以减少数组消耗的内存。
- 它比列表更快。
- 它给了你执行算术计算的能力,比如两个数组的元素相加,两个数组的元素相乘等等。您还可以使用 EDA(探索性数据分析)函数,如 min、max、avg 等。
l = [1,2,3,4,5,6]print ("Size of list is ",sys.getsizeof(l))a1 = np.array([1,2,3,4,5,6])print("Size of a is " , a1.nbytes)a2 = np.array([1,2,3,4,5,6], dtype="int16")print("Size of a is " , a2.nbytes)**------------------ OUTPUT OF THE CODE-------------------------------**
Size of list is 112
Size of a is 48
Size of a is 12
作者显示内存差异的代码截图
如您所见,与 Numpy 数组相比,list 使用了两倍多的内存。
怎么了
要安装 Numpy,请键入以下命令
pip install numpy
要导入 NumPy 库,您需要键入以下代码。
import numpy as np
as np 是不必要的。它允许您在调用函数时使用“np”而不是“numpy”或作为别名。
创建数组
您可以使用 NumPy 创建多维数组。
# 1D arrayd1 = np.array([1,2,3,4,5,6])print(d1)# 2D arrayd2 = np.array( [ [1,2,3] , [4,5,6] ])print(d2)**------------------ OUTPUT OF THE CODE-------------------------------**[1 2 3 4 5 6][[1 2 3] [4 5 6]]
语法是
variable = np.array( [ elements/array of elements ])
您可以通过添加来指定数据类型
dtype = “int16”dtype= “ int32 “
形状和尺寸
.ndim
返回你的数组的维度,.shape
返回一个长度为.ndim
的元组,其中包含每个‘行’的长度。
arr = np.array([ [1,2,3],[4,5,6],[6,7,8] ])print(arr.ndim)print(arr.shape) #arr is 3x3 matrix**------------------ OUTPUT OF THE CODE-------------------------------**
2
(3, 3)
变量 arr 是一个二维数组,每个数组有 9 个元素。它有三个一维数组,每个数组有 3 个元素。它基本上是一个 3x3 的矩阵。
作者显示 Numpy 数组中的维度的代码截图
访问元素
访问 NumPy 数组中的特定元素就像访问列表中的元素一样。返回的元组的长度数。形状或返回的值。ndim 是访问多维数组中单个元素所需的索引数。
# print a single element# syntax: arr[row , col]print(arr[0 , 0] , arr[2 , 2] , arr[1 , 2])#prints all elements in row 0print(arr[0 , :])#prints all elements in col 0print(arr[: , 0])#prints all elements in the matrixprint(arr[:,:])**------------------ OUTPUT OF THE CODE-------------------------------**1 8 6[1 2 3][1 4 6][[1 2 3] [4 5 6] [6 7 8]]
作者展示如何访问元素的代码截图
初始化数组
- 全为零的多维数组
print ( np.zeros((2)) ) # A 1D array with 2 elements set to zeroprint("------------------------------")print (np.zeros((3,3)) ) # A 3x3 matrix will all elements set to
# zero**------------------ OUTPUT OF THE CODE-------------------------------**[0\. 0.]
------------------------------
[[0\. 0\. 0.] [0\. 0\. 0.] [0\. 0\. 0.]]
注意语法,。零( (尺寸))
2。全 1 多维数组
print ( np.ones((2)) ) # A 1D array with 2 elements set to oneprint("------------------------------")print (np.ones((3,3)) ) # A 3x3 matrix will all elements set to one**------------------ OUTPUT OF THE CODE-------------------------------**[1\. 1.]------------------------------[[1\. 1\. 1.] [1\. 1\. 1.] [1\. 1\. 1.]]
注意语法,。个( (尺寸))
3。每个元素等于一个数字的多维数组
print ( np.full((2) , 6 ) ) # A 1D array with 2 elements set to 6print("------------------------------")print (np.full((3,3),77)) #A 3x3 matrix will all elements set to 77**------------------ OUTPUT OF THE CODE-------------------------------**[6 6]
------------------------------
[[77 77 77] [77 77 77] [77 77 77]]
注意语法。全( (维),数)
4。具有随机小数/整数的多维数组
print ( np.random.rand(4,2) )print("----------------------")print (np.random.randint(0,100, size = (4,2) ) )**------------------ OUTPUT OF THE CODE-------------------------------**[[0.97398125 0.86285608] [0.84382674 0.76331437] [0.71798434 0.2150087 ] [0.38535155 0.33849209]]
----------------------
[[ 5 10] [73 65] [29 38] [39 26]]
注意语法, .random.rand( ( dimension),number )
注意语法, .random.randint( min,max,size = ( dimension ) )
作者展示如何初始化 Numpy 数组的代码截图
5。单位矩阵
np.identity(3)**------------------ OUTPUT OF THE CODE-------------------------------**array([[1., 0., 0.],[0., 1., 0.],[0., 0., 1.]])
由于它是一个大小为 N×N 的矩阵,所以只需要给出一个值。
当心抄袭
复制 NumPy 数组有正确的方法和错误的方法。显然,你必须使用正确的方法。
作者代码截图
始终使用。copy() 方法复制一个数组。简单地设置 b = a 将使 b 和 a 指向同一个数组。因此, b 中的所有变化也会反映在 a 中,而这通常是不可取的。
基本算术
你可以在两个或多个数组上执行基本的算术运算,如加法、乘法等。
您必须确保数组的维度和形状相同
该操作将一个元素一个元素地执行。如果我们对数组 a 和数组 b 使用加法运算,a 的第一个元素将被加到 b 的第一个元素上,a 的第二个元素将被加到 b 的第二个元素上,依此类推。如果我们在数组 a 和数组 b 上使用减法运算,b 的第一个元素将从 a 的第一个元素中减去,数组 b 的第二个元素将从数组 b 的第二个元素中减去,依此类推。
我们也可以用标量对数组进行算术运算。该操作将按元素方式执行。
a = np.array([1,2,3,4])b = np.array([5,6,7,8])print(a+b)print(a-b)print(b-a)print(a*b)print(a/2)print(a + 2)**------------------ OUTPUT OF THE CODE-------------------------------**[ 6 8 10 12]
[-4 -4 -4 -4]
[4 4 4 4]
[ 5 12 21 32]
[0.5 1\. 1.5 2\. ]
[3 4 5 6]
作者展示算术函数的代码截图
统计函数
NumPy 还允许我们执行用于 EDA 的各种统计功能,如最小值、最大值、总和、平均值等
a = np.random.randint(0,100,size=(10))print(a)print(a.max())print(a.min())print(a.sum())print(a.mean())**------------------ OUTPUT OF THE CODE-------------------------------**[35 73 93 24 14 39 66 96 89 69]961459859.8
作者代码截图
使再成形
NumPy 允许我们改变数组的形状。我们可以把 2×3 的阵列改成 3×2 的阵列。我们在执行整形操作时必须非常小心,因为它经常变得令人困惑。
健全性检查:整形时,整形数组中元素的乘积。形状元组必须等于原始数组的乘积。形状元组。也就是说,原始阵列和重新成形的阵列中的元素数量必须相同。
您还可以将 reshape 中的一个元素指定为-1,python 将为您计算未知维度。只能将其中一个元素指定为-1,如果将多个元素设置为-1,将会出现错误。在将数组传递给各种函数时,我们经常需要对数组进行整形。这可能看起来令人困惑,但阅读下面的解释,事情就会清楚了。
b = np.zeros( (3,2))print("Orignial")print(b)print(b.shape)print("---------------")print("Reshaped")print(b.reshape(2,3))print(b.reshape(2,3).shape)print("---------------")print("Reshaped")print(b.reshape(-1,3))print(b.reshape(-1,3).shape)print("Reshaped")print(b.reshape(2,-1))print(b.reshape(2,-1).shape)**------------------ OUTPUT OF THE CODE-------------------------------**Orignial[[0\. 0.] [0\. 0.] [0\. 0.]](3, 2)
---------------
Reshaped[[0\. 0\. 0.] [0\. 0\. 0.]]
(2, 3)---------------Reshaped
[[0\. 0\. 0.] [0\. 0\. 0.]](2, 3)---------------Reshaped[[0\. 0\. 0.] [0\. 0\. 0.]](2, 3)
作者代码截图
首先,我们创建了一个 2 维数组或 3 行 2 列的矩阵,所有元素都设置为 0。接下来,我们尝试将这个数组转换成 2 行 3 列的数组,因此我们使用。整形(2,3)。注意,两种情况下的乘积都是 6。
接下来,我们传递值(-1,3)。我们告诉 NumPy 我们需要 3 列,并要求它计算行数。乘积一定还是 6,所以 NumPy 用 2 代替-1,我们得到一个 2×3 的矩阵。
在最后一种情况下,我们传递值(2,-1)。我们告诉 NumPy 我们想要 2 行,并要求它计算列。乘积一定还是 6,所以 NumPy 用 4 代替-1,我们得到 2×3 矩阵。
下面是我们的原始数组的一些更多的整形。
作者代码截图
b . shape(-1,8)给出一个错误,因为整数乘以 8 不会产生 6。永远记得在整形前做健全检查。
结论
我希望我已经帮助你理解了 NumPy 的基础知识。NumPy 库中还有更多可用的函数,所有这些函数都只需谷歌搜索一下。
我最近用 WordPress 创建了一个博客,如果你能看看的话,我会很高兴的😃
[## Python 项目教程-使用这些 Python 项目教程改进您的简历/作品集。
使用 Streamlit 共享部署您的机器学习 Web 应用程序在我以前的文章中,我谈到过构建一个…
realpythonproject.com](https://realpythonproject.com/)
在 LinkedIn 上与我联系
[## Rahul baner JEE——产品工程实习生——EY | LinkedIn
查看 Rahul Banerjee 在世界上最大的职业社区 LinkedIn 上的个人资料。拉胡尔有 4 个工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/rahulbanerjee2699/)
在 Twitter 上与我联系
使用 Python 来自动化您的 Excel 工作!
自动化那些讨厌的 Excel 报表!
在这篇文章中,你将学习如何自动化一些常见的、乏味的 Excel 任务。
很有可能,你无法逃避 Excel(而且你不完全逃避可能是好的!).学习如何使使用应用程序更容易,以及如何自动化重复的任务,是一项重要的技能!
在接下来的几分钟里,您将学习如何组合来自多个工作表的数据,基于这些数据创建汇总统计数据,以及创建有用的可视化效果。几行代码就搞定了!
让我们从导入熊猫库开始。如果你不熟悉这个图书馆,可以看看我在 YouTube 上的熊猫介绍系列!
我已经为本教程创建了一个文件,其中包括三个工作表,涵盖了三个不同月份的数据。你可以在这里下载文件,或者使用 URL 将文件直接导入熊猫数据框架。
在第一段代码中,您已经导入了 Pandas 库(并给它分配了别名pd
)。然后,您将 Excel 文件分配给一个 Excel file 对象。最后,您打印出了文件中所有工作表的名称,但是使用了.sheet_names
属性。
现在您已经知道文件中包含哪些工作表,让我们实际创建所有数据的数据框架。
使用这种方法而不是列出工作表名称的最大好处是,随着月份被添加到文件中,列表不需要修改!
让我们首先创建一个 dataframe 对象,并添加额外的数据文件。
在上面的代码中,首先创建了一个空的 dataframe 对象。然后使用 for 循环遍历 Excel 工作簿中的每个工作表,生成一个包含数据的临时 dataframe(跳过前三行),并将每一项追加到 dataframe df
。最后,您使用.head()
方法打印了前五个记录。
或者,如果您想将数据组合在一行中,您可以编写以下代码,该代码使用熊猫.concat()
函数:
分析您的数据
现在你已经合并了数据,让我们对此进行一些分析。
假设,您被要求查看不同月份按类型和地区划分的每笔销售的总价值。
我们可以使用 Pandas .pivot_table()
函数来实现这一点,我在这个 YouTube 视频中已经详细介绍过了:
让我们创建一个熊猫数据透视表:
上面,您已经创建了一个包含两个索引(月份和类型)的数据透视表。月份是使用熊猫生成的。dt
访问器,以整数形式返回月份,其中 1 等于一月。这些柱子是由区域组成的。
可视化您的数据
最后,让我们创建一些数据的可视化。
也许您想要创建一个图表,用堆叠的柱形图来显示数据。
让我们使用 Pandas 中的 matplotlib 集成来生成这个图表:
这会生成下图:
资料来源:Nik Piepenbreier
结论
在这篇文章中,您学习了如何从多个 Excel 工作表中的数据创建一个熊猫数据框架。您学习了如何快速分析数据并创建数据的可视化。
查看我的其他帖子或者在 YouTube 上订阅我的常用技巧!
使用 Python 构建掷骰子应用程序
一个简单的逐步指南,以建立一个骰子滚动模拟器
我最近申请了一份数据科学的工作,提交申请的要求之一是将代码复制并粘贴到一个小窗口中…整个过程似乎有些贬低,但我还是完成了。
提示要求我使用我想要的任何编码语言构建一个简单的骰子滚动器。因为 Python 是我学习最多的地方,所以我很自然地选择了它。我用的 IDE 是 Jupyter 笔记本。我做了一个更好的图形用户界面(GUI ),这样你就可以选择骰子的边数和你想掷的骰子数,因为我喜欢挑战自己。
这是一个有趣而简单的小项目,所以我决定分享我是如何做的。
创建功能
对于项目的这一部分,我导入了 2 个库:statistics 和 randint(来自 random)。这个项目不需要统计库,但是我认为使用这个库来收集你决定做的任何滚动的统计数据是很好的。
from random import randint
import statistics
现在我们准备创建我们的掷骰子函数。对于这个函数,需要两个输入:n 和 x。
n 是你掷骰子的边数。
x 是你掷骰子的数目。
# Define the dice rolling function using two inputs.
rolls = []
def roll_many(n, x):
for i in range(x):
roll = randint(1,n)
rolls.append(roll)
print(roll)
就是这样!很简单。现在你可以使用这个函数来获得骰子点数。
# This cell will simulate rolling 2 six-sided dice.
rolls = []
roll_many(6,2)
以下是运行它时应该显示的内容示例:
如前所述,您可以使用统计库来收集您掷骰子的统计数据。
statistics.mean(rolls)
下面是一个如何使用统计库来获取掷骰子统计数据的示例:
为函数创建 GUI
我从未尝试过让我的 Python 代码在 GUI 中工作,所以这部分对我来说是新的。在 Google 上搜索了一下之后,我决定使用 tkinter 库来完成这个项目的这一部分。
from tkinter import *
因为这部分对我来说比较新,所以为了简单起见,我决定不掷出多个骰子,而只掷出一个骰子。
对于初学者来说,接下来的代码片段可能有点复杂。这里我定义了一个窗口类。在课堂上,我定义了将出现在窗口中的不同东西:一个键入骰子边数的区域,一个滚动骰子的按钮,以及所有使用文本向用户指定这些区域的标签。
class MyWindow:
def __init__(self, win):
self.lbl1=Label(win, text='# of Die Sides')
self.lbl2=Label(win, text='Roll Result')
self.lbl3=Label(win, text='Dice Rolling Simulator', font=("Helvetica", 20))
self.t1=Entry()
self.t2=Entry()
self.btn1 = Button(win, text='Roll Dice')
self.lbl1.place(x=100, y=100)
self.t1.place(x=200, y=100)
self.b1=Button(win, text='Roll Dice', font=("Helvetica", 16), command=self.roll)
self.b1.place(x=200, y=140)
self.b1.config(height=1, width=8)
self.lbl2.place(x=100, y=200)
self.t2.place(x=200, y=200)
self.lbl3.place(x=100, y=35)
接下来,我为按钮定义 roll 函数。这里的 roll 函数与我们上面看到的非常相似,但是还有一些额外的行,以便 GUI 可以使用这个函数。
def roll(self):
self.t2.delete(0, 'end')
n=int(self.t1.get())
result=randint(1,n)
self.t2.insert(END, str(result))
最后,我使用 tkinter 定义了窗口,我给窗口添加了一个标题(显示在顶部的窗口的名称标题)以及窗口在屏幕上显示的尺寸和位置。window.mainloop()是一个事件监听循环,因此我们的应用程序可以随时响应新的输入。
window=Tk()
mywin=MyWindow(window)
window.title('Dice Roller')
window.geometry("400x300+10+10")
window.mainloop()
总的来说,该代码片段如下所示:
from tkinter import *
class MyWindow:
def __init__(self, win):
self.lbl1=Label(win, text='# of Die Sides')
self.lbl2=Label(win, text='Roll Result')
self.lbl3=Label(win, text='Dice Rolling Simulator', font=("Helvetica", 20))
self.t1=Entry()
self.t2=Entry()
self.btn1 = Button(win, text='Roll Dice')
self.lbl1.place(x=100, y=100)
self.t1.place(x=200, y=100)
self.b1=Button(win, text='Roll Dice', font=("Helvetica", 16), command=self.roll)
self.b1.place(x=200, y=140)
self.b1.config(height=1, width=8)
self.lbl2.place(x=100, y=200)
self.t2.place(x=200, y=200)
self.lbl3.place(x=100, y=35)
def roll(self):
self.t2.delete(0, 'end')
n=int(self.t1.get())
result=randint(1,n)
self.t2.insert(END, str(result))window=Tk()
mywin=MyWindow(window)
window.title('Dice Roller')
window.geometry("400x300+10+10")
window.mainloop()
并且,在运行代码之后…
瞧啊。让我们为骰子点数输入 20,看看我们会得到什么:
幸运数字七!这不是什么花哨的东西,但它是一个工作的骰子滚动模拟器。
如果您在编写代码时遇到问题,或者只是想复制并粘贴代码,以便拥有掷骰子模拟器,以下是 GitHub 资源库链接:
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/jkundycki/RollDice)
祝你好运,感谢你的阅读!
直接在浏览器上使用“RStudio Cloud”上的 R 编程
在无需安装软件和配置的情况下,使用 R on Cloud 进行、共享、教授和学习数据科学
序幕
云计算的新时代开始了……我发现了 RStudio Cloud (在我撰写本文时,它正处于测试版),适合专业人士、业余爱好者、培训师、教师和学生使用 R 来进行、分享、教授和学习数据科学。对于那些不知道的人来说, RStudio 是一个成熟的 R 编程 IDE 。这是您将用作桌面版本的确切视图,旨在解决一些棘手问题,例如:
- 安装 R
- 安装 RStudio
- 安装软件包和依赖项
- 加载包
- 运行并重新加载代码
现在,有了新的云体验,我可以简单地登录并从浏览器运行代码。多么可笑的简单!
RStudio Cloud 现已发布测试版。来源:https://rstudio.cloud/
RStudio 云网络研讨会,来源:Mine etinkaya-Rundel(第 4 页)
登录选项
- 通过您的用户名和密码登录
- 通过谷歌登录
- 通过 GitHub 登录。
如果凭据有效,您将看到以下登录页面:
RStudio 云术语通俗易懂
- 项目 —封装你的 R 代码、包和数据文件。只需在“项目”区域点击“新建项目”按钮。您的新项目将在 RStudio IDE 中打开。
- 工作区 —获得一个名为您的工作区的个人工作区,在其中创建项目。
- 私人空间 —仅与私人空间的特定成员协作。
- 成员 —管理其成员资格。
- 项目访问—对空间的所有成员可见,还是对项目创建者保密?
我继续创建一个新项目,并给项目命名为“AutoML H2O.ai in R”。在我这边效果惊人。我根本不用安装 R 或者 RStudio。导航窗格与在我的本地计算机上使用 RStudio 的体验相同。
考虑和限制
- 每个项目分配 1GB 的内存。每个帐户分配一个私人空间,最多 10 个成员和 25 个项目。如果您达到这些空间限制之一,您可以向 RStudio 云团队提交增加容量的请求,他们会尽最大努力满足您的需求。如果你用的是专业的
shinyapps.io
账号,就不会遇到这些空间限制。 - 如果连接不好,项目可能会停滞。您可以随时重新启动项目。
- 您不必重新运行代码。如果您不小心关闭了视图,您总是可以返回到它并继续下一行代码。
- 工作区和项目之间的包安装不同步。因此,如果某个包是未知的,您仍然需要为不同的项目安装它。
附加材料
免责声明:以下内容未经我的雇主正式认可。本文表达的观点和意见仅代表作者的观点和意见,不一定反映当前或以前的雇主、组织、委员会、其他团体或个人的官方政策或立场。本文中进行的分析是基于有限日期的开源信息。分析中所做的假设并不反映任何前任或现任雇主的立场。
使用 R 计算用于会计分析的样板文件
研究
用 30 家电信公司 CSR 计算样本的实证。
图片来自 Pixabay 的 Dariusz Sankowski
什么是样板文件,为什么要去除它?
在文本分析中,样板词是可以从句子中删除而不会显著改变其原始含义的词的组合,例如“超过百万 In”或“在…的末尾”根据 Mark Lang 和 Lorien Stice-Lawrence 的说法,样板文件已经成为监管机构和标准制定者发现的年度报告中一个特别有问题的属性,他们的分析表明,随着样板文件的减少,年度报告披露(来自 15,000 多家公司)得到了改善。研究的详细内容可在这里找到。
样板文件影响年度披露质量的原因之一是样板文件可能为隐藏信息提供机会,降低整体信息含量( Hoogervorst,2013 )。
数据
我用 30 份企业社会责任报告作为数据来演示如何计算样板。都是来自通信行业的公司,比如 AT & T,Sprint Corporation 之类的。都是用英文和 pdf 格式写的。
展示区(代码)
在我的计算演示中,我将遵循 Mark Lang 对样板的定义:报告中包含至少一个“样板”短语(4 个单词的短语,或四边形)的句子的单词百分比。
第一步——标记每个文档的所有句子
在这一步中,我们使用了“tm”包和“tokenizers”包。为了生成正确的四边形并减少计算量,我们在这一步中删除了数字。由于所有的原始文档都是 pdf,“tokenize_sentences”功能可以充分识别不规则的段落换行符,并将文本拆分成句子。
作者代码
第二步——将四边形放入一个列表中
在这一步中,我生成了四边形,并将所有的四边形放在一个列表中以供进一步分析,因为 Mark Lang 的方法要求在所有文档级别中查找常见的 4 个单词的短语。
作者代码
第三步—获得频率在 30%和 75%之间的四边形
在此步骤中,我手动设置阈值,只有出现在整个文档语料库的 30%和 75% 之间的 中的四边形将用于计算。我之所以要设上限,在马克·朗的论文里有解释。但一般来说,四联图有时包含无害的短语或监管披露,这将传达信息内容。样板文件的目的是发现文档是多么没有信息,所以我必须从计算中排除最流行的四边形。
作者代码
部分输出如下所示:
图 1–四边形
第四步——计算每个句子的字数和四角形
当我最初开始这项任务时,我在这一步遇到了很多麻烦,因为如果我把这一部分搞砸了,最终的输出将会很糟糕。一个句子可能根本没有四边形,也可能同时有多个四边形。一句话的字数很容易翻倍或翻倍。为了解决这个问题,我设置了一个临时变量来标记句子,以避免多次计数。
作者代码
最后一步——计算样板文件
让我们回顾一下样板文件的定义:
图 2 —样板方程
在我标记了所有的样板句子之后,我生成了每个文档的长度:
作者代码
最终计算的代码:
作者代码
最终输出如下所示:
图 3 —最终输出
最后
计算样本有助于更好地理解会计文本分析中一组报表的信息含量。做计算时,你必须小心重复计算样板句。
我有意避免使用“lapply ”,并在代码中使用了许多“for 循环”。它可以有效地帮助构建和组织用于调试目的的代码。此外,多个任务需要多次将输出分配给环境变量。由于 R 一直在提升“for loops”的性能,“for loops”的速度也没有以前那么差了。
这项工作可以列举如下:
《情感:一个文本分析包》。软件影响,100456 (2022)。【https://doi.org/10.1016/J.SIMPA.2022.100456
供大家参考,在这里可以找到所有的 R 代码。
python 版本可在此处找到:
帮助研究人员计算样本、冗余、特异性、相对流行率的函数集合…
towardsdatascience.com](/morethansentiments-a-python-library-for-text-quantification-e57ff9d51cd5)
请随时与我联系LinkedIn。
在 Flask 应用程序中为异步任务使用 Redis 队列
使用 Redis 和 Redis 队列处理长请求,防止应用程序编程超时
By:内容由 爱德华·克鲁格乔希·法默道格拉斯·富兰克林 。**
伊恩·巴塔格利亚在 Unsplash 上拍摄的照片
当构建执行耗时、复杂或资源密集型任务的应用程序时,等待这些任务在前端应用程序中完成可能会令人沮丧。此外,前端的复杂任务可能会超时。Redis Queue 通过将更复杂的任务推给工作进程进行处理来解决这个问题。
将 Redis 与 Redis Queue 一起使用允许您将那些复杂的任务输入到一个队列中,因此 Redis worker 在应用程序的 HTTP 服务器之外执行这些任务。
在本文中,我们将构建一个应用程序,它使用 Redis 队列对作业进行排队,对这些作业执行一个函数,并返回函数的结果。
这里是这个项目的代码到 Github 库的链接。
Redis 是什么?
Redis 是一个开源的内存数据库、缓存和消息代理。Redis 处理的消息本质上是 JSONs。Redis 非常适合在临时数据库中快速方便地处理特定的数据类型,并提供非常快速的查询访问和传递。
对我们来说,Redis 提供了两个好处。首先,它将复杂的任务推到另一个空间进行处理。第二,通过将任务分成独立的功能,即主应用程序和队列,开发人员可以更容易地处理复杂的操作。
对于这个应用程序,我们将使用 Redis 来保存 JSON 消息队列。Redis 可以是一个独立的数据库,可由许多计算机或系统访问。在我们的示例中,我们将使用它作为本地内存存储来支持我们的应用程序。
什么是 Redis 队列?
Redis Queue 是一个 python 库,用于后台处理的作业排队。由于许多托管服务在长 HTTP 请求时会超时,所以最好设计 API 来尽快关闭请求。Redis Queue 允许我们通过将任务推送到一个队列,然后再推送到一个工作器进行处理来实现这一点。
将 Redis 与 Redis Queue 结合使用,可以请求用户输入,向用户返回验证响应,并在后台对流程进行排队。所有这些都不需要前端用户等待这些过程完成。过程可以是任何东西,从机器学习模型到复制图像到复杂的模拟。
任何比您希望在应用程序前端完成的时间更长的事情都属于 Redis 队列。
模块化应用程序结构
我们将介绍如何使用 Docker 运行 Redis 数据库并初始化 Redis 队列工作器。worker 将允许我们处理应用程序队列中的作业。
我们将在接下来的小节中更详细地讨论这些文件。
我们将讨论我们的应用程序的以下组成文件: main.py 、 functions.py 和 redis_resc.py 。
有两种方法可以启动 docker 容器。在本文中,我们将一步一步地介绍标准流程。然而,可以使用 docker-compose 创建 docker 容器,我们将在另一篇文章中介绍。
安装 Docker 和 Redis
码头服务是一种集装箱服务。这意味着 Docker 在一个容器中运行代码,该容器中有应用程序从一个系统可靠地运行到另一个系统所需的依赖关系。它确保我们的应用程序从开发到测试再到生产始终如一地运行。
跟随链接到 Docker 文档获取全面的安装指南,帮助您为您的操作系统选择正确的 Docker 版本。
一旦在系统上安装了 Docker,您将需要安装 Redis。
对于 Mac 用户来说,home-brew 命令 brew install redis
将起作用。Windows 需要从 Github 下载。有了 Linux,可以直接从 Redis 下载最新的 tarball。
自述文件概述
要运行我们的应用程序,我们必须理解自述文件中的说明。
我们将使用 Pipenv 创建一个虚拟环境并安装适当的包。用命令pipenv install -- dev
安装这个程序的包。添加--dev
标志安装开发包和生产需求。在进入下一步之前,使用命令 pipenv shell 激活环境。
我们必须启动三个服务才能让应用程序正常运行:Redis 数据库、Redis 队列工作器和 Flask 应用程序。其中两个服务将在我们用来安装虚拟环境和进入 shell 的同一个终端中开始。
首先,运行命令:
**docker pull redis**
这将从 Docker Hub 中提取 Redis 映像。
然后,运行命令:
**docker run -d -p 6379:6379 redis**
这个命令有几个用途。首先,它初始化 docker 容器。-d
标志在后台运行 Redis 容器,为下一步释放终端。-p
标志向主机发布容器的一个或多个端口。最后,6379:6379
将 docker 容器中的端口 6379 绑定到本地主机上的端口 6379。如果不绑定端口,当 docker 容器中的本地机器和进程试图相互通信时,就会遇到问题。
运行我们的应用程序之前的最后一步是启动 Redis 队列工作器。因为我们是在分离模式下运行 Redis 映像,所以我们可以在同一个终端中执行这个步骤。
用命令rq worker
启动 Redis 工作器。只有在安装了 Redis 队列包的情况下,rq
命令才可用于终端,我们用 Pipenv install 安装了依赖项,用 pipenv shell 进入环境。运行rq
命令将允许 Redis 队列开始监听进入队列的作业,并开始处理这些作业。
初始化烧瓶应用程序
我们现在准备初始化 flask 应用程序。在开发服务器上,这是通过以下命令完成的:
**export FLASK_APP=app.main:app && flask run — reload**
命令gunicorn app.main:app
将在生产服务器上运行这个。Gunicorn 需要 Unix 平台才能运行。因此,如果您使用的是 macOS 或基于 Linux 的系统,这个命令可以工作,但不适用于 windows。
现在服务正在运行,让我们转到应用程序文件。
烧瓶应用程序组件
redis_resc.py
这个文件设置 Redis 连接和 Redis 队列。
redis_resc.py
变量redis_conn
定义了这个连接的连接参数,redis_queue
使用队列方法。Queue 方法初始化队列,可以给定任何名称。常见的命名模式有“低”、“中”和“高”通过为队列方法提供无参数,我们指示它使用默认队列。除了名称之外,我们只是将连接字符串传递给 Redis 存储。
函数. py
py 是我们定义在 Redis 队列中使用的函数的地方。
做什么由你决定。它可以是您希望对传递给员工的数据做的任何事情。这可以是任何事情,从机器学习到图像处理,再到使用信息处理连接数据库中的查询。你想让后端做的任何事情都可以放在这个函数中,这样前端就不会等待了。
对于我们的例子,这个函数有两个目的。首先,创建 job 变量来检索当前正在处理的作业。我们使用time.sleep(10)
来演示作业处理过程中不同的作业状态代码。我们将在本文后面更详细地讨论作业状态代码。最后,我们返回一个 JSON,其中包含关于作业和作业处理结果的信息。
Main.py
Main.py 是驱动应用程序的主要 flask app。关于设置 flask 应用程序的更多细节在这篇中型文章中概述。
** [## 用 Flask 和 SQLalchemy,不要用 Flask-SQLAlchemy!
避免 Flask 应用程序中的 Flask-SQLAlchemy
towardsdatascience.com](/use-flask-and-sqlalchemy-not-flask-sqlalchemy-5a64fafe22a4)
第一个路由函数resource_not_found
被设计用来处理由于对应用程序的不正确请求而导致的任何 404 错误。定义为home
的路线功能是导航到回家路线时运行的默认路线。当您对[http://127.0.0.1:8000](http://127.0.0.1:8000)
或本地主机 URL 执行 GET 请求时,这个路由就会运行。这条路线旨在让你知道 flask 应用程序正在运行。
我们可以用 Postman 测试一下,如下图所示。
本地主机地址邮递员测试
其余的路由,特别是 Redis 队列,将在下面详细介绍。
/排队
/enqueue
路由创建任务,并将任务放入队列。Redis Queue 接受诸如键值对之类的东西,因此您可以使用字典创建 post 请求,例如:
{“hello”: “world”}
向/enqueue
路由提交一个 JSON post 请求将告诉应用程序将 JSON 排队到 function.py 文件中的函数 some_long_function
进行处理。
/排队路由邮递员测试
/enqueue
路由一旦完成就返回创建的任务的job_id
。请注意job_id
,因为我们将使用它作为应用程序剩余路由的 URL 字符串的一部分。
/check _ 状态
这个路由采用job_id
并检查它在 Redis 队列中的状态。这条路线的完整网址是http://127.0.0.1:8000?job_id=JobID
。其中JobID
是在/enqueue
路线创建作业时生成的job_id
。
/check_status 路由邮递员测试
/check_status
route 将返回一个 JSON,其中包含 URL 中传递的job_id
和使用 rq.job 的get_status
方法的作业状态。如果您在十秒钟计时器之前发出 get 请求,则状态将显示为“队列”some_long_function
完成后,状态将返回“完成”
/get _ 结果
一旦任务被/check_status route
显示为‘完成’,get_result
将返回已处理任务的结果。结果由您在some_long_function
中的设置决定。该 URL 遵循与/check_status
相同的结构,因此它是:
[http://127.0.0.1:8000?get_result=JobID](http://127.0.0.1:8000?get_result=JobID)
/get_resut 路由邮递员测试
我们的some_long_function
返回关于作业的数据,如上图所示。
结论
在本文中,我们学习了一些关于使用 Redis Queue 构建任务队列的知识,以及如何在 docker 容器中利用 Redis 数据库。我们讲述了如何构建一个应用程序,使耗时的任务排队变得简单,而不会占用或影响我们的前端性能。
运行 pipenv install — dev 来安装 env。运行 pipenv 运行预提交安装来初始化 git 挂钩。运行 pipenv…
github.com](https://github.com/edkrueger/rq-flask-template)
这里是这个项目的代码到 Github 库的链接。自己测试一下,尝试排队几个 JSON 任务并查看结果!**
用强化学习训练一只永远不会死的小鸟
故障排除和性能调整直到完美的故事
拍打鸟
最近,我开始学习强化学习算法,flappy bird 是一个用于强化学习的流行游戏,特别适合初学者玩。
Sarvagya Vaish 在他的帖子中详细解释了 Q-learning 理论和游戏如何运作。他用 javascript 实现了他的想法。我更喜欢在 python 中查找参考代码。感谢 Cihan Ceyhan 提供了一个很好的 python 示例。
通过仔细划分状态空间,慈汉 Ceyhan 的 AI 智能体(flappy bird)可以飞过 5000 分。
然而,正如你所看到的,小鸟不可能在每场比赛中都达到高分,它可能会在任何分数崩溃。不够稳定。
有没有可能在任何游戏中训练一只永远不死的鸟?
状态矢量空间
在 Sarvagya 的帖子中,他定义了三个维度来代表一种状态:
- X —到下一根管道的水平距离
- Y —到下一根管道的垂直距离
- V——鸟的当前速度
在慈汉杰伊汉的代码中,如果鸟进入隧道超过 30 个像素(管道宽度=52px),鸟会将眼睛移到下一个管道。但是,这可能会导致 Q 表的冲突结果。对于相同的 X,Y,V(到下一个管道),如果鸟的当前位置靠近当前管道的边缘部分(红色),鸟可能会坠毁在当时对鸟透明的隧道中。
左:原始状态空间,中:隧道里的鸟是盲的,右:状态空间中引入的新维度
我在状态中添加了第四维:
**Y1**
-相邻两个管道之间的垂直距离,它有助于鸟根据两个连续管道的高度差提前采取行动。该值仅在鸟进入隧道部分时使用。它可以减少状态空间。
此外,鸟仍然可以感知当前管道,直到隧道中 50 像素长。之后,这只鸟几乎飞出了隧道。刚刚通过的管道不能再冲击鸟了。是时候关注下一个管道了。
Q-learning 的奖励
通过以上改进,小鸟可以轻松飞到 10000 分。但是,它仍然不稳定,在达到 10000 分之前有许多失败。
按照萨瓦吉亚的解释,机器人每走一步获得活着的 +1 奖励,如果死亡则获得 -1000 奖励。它在大多数情况下都能很好地工作。
让我们看看下面的场景。下一个管道比前一个有巨大的落差,游戏中两个管道之间的最大垂直落差是 142px。考虑到小鸟在第一张图中所示的位置,如果小鸟正在下落,想要顺利通过这两条管道,可能需要走路线 1 或路线 2 ,但两者都无法顺利通过下一条管道。如果垂直差没有达到最大落差,它在大多数情况下都是可行的。参考中图。
左:下一个管道中的巨大落差,中:正常情况,容易通过,右:最坏情况下的正确轨迹
我们训练鸟几百万次,鸟积累了那个位置的大量正值。最坏的情况是一个相当低发生率的事件,即使有一次导致崩溃的情况,它只有负 1000 奖励。剩余值仍然是一个很大的正值,或者小鸟可以很容易地从成功的训练中获得另外 1000 奖励。所以小鸟一旦遇到类似的情况就会再次坠毁。
它迫使鸟着眼于长期生存,远离任何导致死亡的行为。不管这只鸟过去成功跑了多少次,它都会在死亡时得到-1000 奖励的惩罚。
经过这次改进,大大增加了稳定性。
从死亡中恢复游戏
很少有机会遇到最坏的情况。换句话说,这只鸟在这些情况下没有足够的训练。它可能会遇到一次,但下一次,它不会遇到类似的场景。可能要过很久才会再次发生。
不太适合训练。我实时记录了鸟类旅程的最后 50 步,**the game can resume from the last 50 steps before the crash**
。在短时间内遍历所有可能的状态很有帮助。
我们以之前的案例为例。鸟在进入隧道时处于下落状态,无论走路线 1 或路线 2 或任何其他路线,它仍可能撞在下一根管道上。游戏从这一点重新开始,它可能会尝试其他动作并死亡。重新开始游戏,直到小鸟发现它应该处于上升状态才能进入这种情况。那么它可以经历任何情况,包括最坏的情况。
内存问题
在Bot
类中,它保存了每个动作的状态信息,一旦鸟死了,这些信息将用于更新 Q-table。
当 bird 达到几百万次时,它会消耗大量内存。也减缓了训练速度。
更改前后的内存消耗
每 500 万步,相当于大约 139,000 个分数,我更新 Q 表,然后减少数组列表。我仍然留有 100 万步的缓冲,以避免在 600 万步后鸟坠毁时对鸟的冲击。
每 500 万步更新一次 Q 表
更改后最大内存消耗在 1GB 左右,比之前少了很多。
q 表初始化
在最初的解决方案中,它需要一个单独的步骤来初始化 q 表,并且它还包括许多鸟从未经历过的状态。
在我的解决方案中,只有当鸟经历一个新的状态时,状态才被初始化。所以 Q-table 只包含鸟曾经经历过的状态。它不需要单独的步骤来初始化 Q 表。
要从头开始新的培训,只需删除data/
文件夹下的qvalues.json
文件。
确认
经过长时间的训练(10 多个小时),我进行了验证测试,最高分为 10 分,第 2 集。一旦小鸟得分达到 10 米,游戏将重新开始。这项测试表明,训练有素的代理人可以飞行很长时间,没有任何坠毁。即使在没有 UI 的情况下训练,我的 Mac 也需要将近 2 个小时才能达到 1000 万分。这次测试我只跑了两集。
总训练集:2,最高分:1000 万
从起点到第一个管道,鸟将毫无障碍地飞行很长一段距离,第一个管道之前的状态不会与接下来的训练相同,接下来的测试表明受过训练的代理完美地处理了旅程的开始。设置最高分=10,集=100,000,代理通过了测试,没有任何失败。
总训练集:100,000,最高分:10
第三个测试演示了任何游戏的稳定性和再现性。在这个测试中,最高分=10,000,插曲=2,000,经过训练的代理也没有任何失败地通过了。
总训练集:2000,最高分:10000
出于好奇,我做了最后的测试,看看这只鸟能飞多少分。我只给一集设置了 Max Score=50,000,000。
小鸟达到了 50 米的成绩!!
结论
现在我们可以说受过训练的特工(flappy bird)永远不会死。
密码
在 github 中:https://github . com/kykin 78/rl-flappybird
参照(References)
http://sarvayavaish . github . io/flappybirdrl/
https://github . com/CHN cyhn/flappybird-qle learning-bot
https://github . com/soura HV/flappybird
使用 SHAP 损耗值来调试/监控您的模型
你应该如何理解和使用 SHAP 损失值
近年来,负责任的人工智能一直是一个非常热门的话题。问责制和可解释性现在成为机器学习模型的必要组成部分,特别是当模型做出将影响人们生活的决策时,例如医疗诊断和金融服务。这是机器学习的一个非常大的主题,许多正在进行的工作都致力于各个方面。您可以查看关于这个主题的更多资源[1]。在这篇文章中,我将重点介绍SHAP(SHapley Additive explaining),这是最受欢迎的可解释性包之一,因为它的通用性(局部/全局可解释性;模型特定/不可知)和来自博弈论的坚实理论基础。您可以找到许多帖子和教程来了解 SHAP 如何帮助您了解您的 ML 模型如何工作,即您的每个要素如何对模型预测做出贡献。然而,在这篇文章中,我将谈论许多人可能不太熟悉的 SHAP 损失值。我将通过一个例子来介绍一些关键概念。我也分享一下我的一些想法。
首先,你可能想要检查由 SHAP 软件包提供的例子。有两个重要的注意事项:
- shap loss 值将向您显示每个要素如何影响 logloss 值与预期值的比值。注意,在这篇文章中,当我说损失值时,它指的是 logloss,因为我们将研究分类问题)
就像预测的 SHAP 值一样,SHAP 损失值表示每个要素对对数损失的影响。预期值是依赖于标签的基线值。当数据实例为真时,通过将所有实例的标签设置为真来计算预期值(当数据实例为假时,设置为假)
- 你应该使用“介入”方法来计算 SHAP 损失值
本质上,这意味着在整合缺失的特性时,应该使用边际分布而不是条件分布。实现边缘分布的方法是用来自背景数据集中的值来分配缺少的特征。
使用“介入式”(即边缘分布)或“tree_path_dependent”(即条件分布)是一个重要的细微差别(参见 SHAP 包中的 docstring ),值得进一步讨论。但我不想一开始就让你困惑。你只需要知道,在通常的做法中,TreeShap 计算 Shap 值的速度非常快,因为它利用了来自模型的树结构的条件分布,但条件分布的使用会引入因果关系的问题[2]。
训练 XGBoost 分类器
这篇文章中的例子是从 SHAP 包中的教程例子修改而来的,你可以在这里找到完整的代码和笔记本。我首先训练了一个 XGBoost 分类器。数据集使用 12 个特征来预测一个人的年收入是否超过 5 万英镑。
['Age', 'Workclass', 'Education-Num', 'Marital Status', 'Occupation', 'Relationship', 'Race', 'Sex', 'Capital Gain', 'Capital Loss', 'Hours per week', 'Country']
您可以使用 SHAP 软件包来计算 shap 值。力图将为您提供局部可解释性,以了解这些特性如何对感兴趣的实例的模型预测有所贡献(图 1)。汇总图将给出全局可解释性(图 2)。你可以查看 Jupyter 笔记本的第一部分。没有什么新的,只是 SHAP 的常见用法,所以我将把细节留给你,并跳转到第 2 部分, shap 值的模型损失。
图一。力图显示了每个特征如何将模型输出从基础值推至模型输出。请注意,输出是在对数优势比空间中。
图二。SHAP 摘要图给出了全局可解释性。量值大的要素意味着它对预测有更重要的影响。
解释模型的对数损失
现在对模型损失的贡献更感兴趣,所以我们需要计算 shap 损失值。在某种意义上,这类似于残差分析。代码片段如下。请注意,您需要
- 提供背景数据,因为我们使用“介入”方法。并且计算成本可能是昂贵的。所以你要提供一个合理大小的背景数据(这里我用 100)。
- 现在 model_output 是“log_loss”。
# subsample to provide the background data (stratified by the target variable)X_subsample = subsample_data(X, y)explainer_bg_100 = shap.TreeExplainer(model, X_subsample,
feature_perturbation="interventional",
model_output="log_loss")shap_values_logloss_all = explainer_bg_100.shap_values(X, y)
力图
现在,数据实例的预测图具有与图 2 类似的解释,但是是根据测井曲线损失而不是预测。图 3 给出了成功的预测(基础事实为真,预测为真),而图 4 给出了错误的预测(基础事实为真,预测为假)。您可以看到蓝色的要素如何试图减少基本值的对数损失,而红色的要素会增加对数损失。值得注意的是,模型损失的基础值(期望值)取决于标签(对/错),因此它是一个函数而不是一个数字。期望值的计算是通过首先将所有数据标签设置为真(或假),然后计算平均日志损失,对此您可以在笔记本上查看更多详细信息。我不知道这样计算基值是否有特别的原因,但毕竟基值只是作为一个参考值,所以我认为这应该没有太大关系。
图 3。对于数据实例,地面真值为真,模式预测为真。
图 4。对于数据实例,地面真值为真,模式预测为假。
概要图
类似地,我们有模型对数损失的汇总图(图 5)。这将告诉您特征如何影响模型对数损失(计算基于绝对平均值)。贡献较大的功能意味着它对模型损失的贡献很大,可能会增加某些数据实例的对数损失或减少其他数据实例的对数损失。因此,这里的摘要图应该显示与图 2 中 shap 值的顶部特征的一致性。但是我们可以看到排名顺序有点不同。虽然“关系”仍然是最重要的,但“年龄”、“教育程度”、“资本收益”、“每周工作时间”、“职业”的顺序不同。并且图 5 中的“资本收益”比图 2 中的“资本收益”具有相对较大的贡献。这表明“资本收益”在减少测井损失中起着重要作用,而相对而言,与“关系”相比,模型进行预测可能并不那么重要。值得注意的是,应谨慎解释图 5 中的摘要图,因为图 5 中的条形图是基于绝对平均值计算的,这意味着在对某个特征的重要性进行排序时,会考虑降低对数损失和增加对数损失的影响。简单地说,大量的(绝对)贡献不一定意味着一个特性是“好”的特性。
图 5。类似于图 2,但基于模型对数损失。
当然,您可以使用散点图而不是柱状图来查看详细的分布,以便更深入地进行模型调试(例如,提高模型性能)。我研究的另一种方法是将形状损失值分解为负分量(图 6)和正分量(图 7)。就模型调试而言,您希望获得更大的负值,并减少所有功能的正值,因为您希望所有功能都减少最终的模型 logloss。
图 6。每个要素的所有负形状损失值的总和。
图 7。每个要素的所有正形状损失值的总和。
监控图
现在我们到了最有趣的部分:使用 shap 损失值来监控您的模型。模型漂移和数据漂移是现实世界中的问题,您的模型会退化并导致不可靠/不准确的预测。但这些通常都是悄无声息地发生的,很难找出根本原因。在 SHAP 作者最近的一篇论文[3]中,他们使用 shap 损失值来监控模型的健康状况。这个想法很吸引人,我希望在这方面做更多的探索。请注意, API 是可用的,但似乎正在开发中。
首先,我们需要计算训练数据和测试数据的形状损失值。在监控环境中,您需要计算来自不同时间快照的数据集的 shap 丢失值。您可能还记得,我们在本节开始时已经这样做了。但是请注意,我们使用从整个数据集采样的背景数据。出于监控的基本原理,通过使用来自训练数据集和测试数据集的背景数据,分别计算训练数据集和测试数据集的 shap 损失值更有意义。代码片段如下:
# shap loss values for training data
X_train_subsample = subsample_data(X=X_train, y=y_train)explainer_train_bg_100 = shap.TreeExplainer(model, X_train_subsample,
feature_perturbation="interventional", model_output="log_loss")shap_values_logloss_train = explainer_train_bg_100.shap_values(X_train, y_train)# shap loss values for test data
X_test_subsample = subsample_data(X=X_test, y=y_test)explainer_test_bg_100 = shap.TreeExplainer(model, X_test_subsample,
feature_perturbation="interventional", model_output="log_loss")shap_values_logloss_test = explainer_test_bg_100.shap_values(X_test, y_test)
顶部特征的监控图如图 8 所示。首先,所有数据实例将按索引排序。这里我们假设指数表示时间的演变(沿着轴从左到右)。在这个玩具示例中,我们没有来自不同时间快照的数据,因此我们简单地将训练数据视为当前数据,将测试数据视为我们想要监控的未来数据。
根据 SHAP 帕克凯奇目前的实施情况,理解这些监测地块有几个要点。为了查看 shap 损失值是否具有时间一致性,将重复进行 t 检验来比较两个数据样本。当前的实现使用 50 个数据点的增量来分割数据。这意味着,第一个 t 检验将比较数据[0: 50]和数据[50:];第二个将比较数据[0: 100]和数据[100:],依此类推。如果 p 值小于 0.05/n_features,t 检验将失败。换句话说,它使用 95%的置信度,并应用了 Bonferroni 校正。如果 t 检验失败,将绘制一条垂直虚线来指示位置。有点令人惊讶的是,我们看到监控图显示了[“关系”、“教育数量”、“资本收益”]的 shap 损失值的不一致性,当我们输入测试数据的时间快照时就会发生这种情况(图 8)。
图 8。监控顶部特征的图。训练数据集和测试数据集被连接以模拟来自不同时间快照的数据。请注意,测试数据从索引 26047 开始。
我不太清楚使用 50 个数据点增量的原因。而在这个例子中,由于我们知道[0:26048]是训练数据,[-6513:]是测试数据。我将增量修改为 6500,看看它是否会给出不同的结果。但是当比较测试数据时,监测图仍然显示相同的不一致性(即,t-测试的失败)(图 9)。
图 9。监控顶部特征的图。类似于图 8,但是现在我们使用 6500 个数据点的增量。目的是将测试数据与训练数据的最后一个“时间段”直接进行比较。
最后,我觉得直接对训练数据和测试数据进行 t 检验是个不错的主意。这再次验证了训练数据集和测试数据集之间的形状损失值不一致的结论。
# t-test for top features (assume equal variance)
t-test for feature: Relationship , p value: 2.9102249320497517e-06
t-test for feature: Age , p value: 0.22246187841821208
t-test for feature: Education-Num , p value: 4.169244713493427e-06
t-test for feature: Capital Gain , p value: 1.0471308847541212e-27# t-test for top features (unequal variance, i.e., Welch’s t-test,)
t-test for feature: Relationship , p value: 1.427849321056383e-05
t-test for feature: Age , p value: 0.2367209506867293
t-test for feature: Education-Num , p value: 3.3161498092593535e-06
t-test for feature: Capital Gain , p value: 1.697971581168647e-24
训练数据和测试数据之间的 shap 损失值的不一致实际上是非常意外的,并且可能是麻烦的。请记住,我们只是从整个数据集使用训练/测试分割,因此有很好的理由相信训练数据集和测试数据集在数据分布或 shap 损失值贡献方面应该是一致的。无论如何,这只是一个简单的实验,需要进行更多的调查才能得出确切的结论。但我认为,SHAP 软件包表明监控功能只是初步的,可能有一些原因,例如:
- 在我看来,使用 50 个数据点的增量是任意的;
- t-test 看起来非常敏感,可能会发出许多错误警报。
另一个有趣的讨论点是背景数据的使用。注意,对于监测图,使用不同的背景数据(来自训练数据集/测试数据集的子样本)计算训练数据集和测试数据集的 shap 损失值。由于计算 shap 损失值的“介入”方法非常昂贵,我只尝试了 100 个数据实例大小的子样本数据。这可能会产生 shap 损失值的高方差结果。也许大规模的背景数据将减少方差,并给出监测地块中形状损失值的一致性。当我使用相同的背景数据(来自整个数据集的子样本)时,监测图中不会出现不一致。所以你如何选择背景数据很重要!
结论和讨论
希望这篇帖子能给你有用的介绍 shap 损失值。通过调查 shap 损失值,可以更好地调试 ML 模型。它也可以是一种有用的方法来监控您的 ML 模型的模型漂移和数据漂移,这在社区中仍然是一个非常大的挑战。但是请注意它的局限性:为了使用 shap 损失值进行监控,您需要了解新数据的真实情况,这通常只能在一段时间后才能获得。此外,不幸的是,这一功能仍在开发中,使用 t-test 的适当性需要进一步证明。
最后但同样重要的是,通过边际分布或条件分布计算 shap 值(TreeShap)可以给出不同的结果(见等式)。条件分布的使用会引入因果关系的问题,而边际分布会给模型提供不太可能的数据点[4]。对于使用哪一个,取决于什么场景,似乎没有一致的意见[2,5]。这篇论文[6]对这个话题有一些有趣的评论,我想在这里引用一下:
一般来说,用户是否应该用不属于原始训练分布的输入来呈现他们的模型是一个正在进行的辩论的主题。
….
这个问题适合于一个更大的讨论,即你的归因方法是否应该“忠于模型”或“忠于数据”,这已经在最近的几篇文章中讨论过了。
说明如何使用边际分布和条件分布来整合缺失值(即缺失特征)。这里 X1 是呈现特征,而 X2、X3 是缺席特征。转载自[2]。
谢谢你的时间。并且不要犹豫留下任何评论和讨论!
本帖中的所有情节都是作者使用 SHAP 软件包创作的。如果你认为你的任何作品没有被恰当地引用,请告诉我。
[1] 负责任机器学习简介
[2] Janzing,d .,Minorics,l .,& Blö baum,P. (2019 年)。可解释人工智能中的特征相关性量化:一个因果关系问题。https://arxiv.org/abs/1910.13413
[3] Lundberg,S.M .,Erion,g .,Chen,h .,DeGrave,a .,Prutkin,J.M .,Nair,b .,Katz,r .,Himmelfarb,j .,Bansal,n .和 Lee,S.I. (2020)。用可解释的人工智能对树木从局部解释到全局理解。自然机器智能, 2 (1),2522–5839。
[4]https://christophm . github . io/interpretable-ml-book/shap . html
[5]m . Sundararajan 和 a . naj mi(2019 年)。用于模型解释的多个 Shapley 值。 arXiv 预印本 arXiv:1908.08474 。
[6] Sturmfels,p .,Lundberg,s .,和 Lee,S. I. (2020 年)。可视化特性属性基线的影响。提取, 5 (1),e22。
使用简化 it 共享来部署您的简化 it 应用
使用 Streamlit 共享部署您的机器学习 Web 应用程序
按作者部署 Streamlit 应用程序 GIF
在我以前的文章中,我谈到了从头开始构建 Github Web Scraper 和 KNN 分类模型,并为 UI 使用 Streamlit。
[## 如何构建一个 Streamlit 应用程序来抓取 Github 配置文件
在本教程中,我们将使用 Streamlit 构建一个 web 应用程序,它从 GitHub 中抓取用户信息。它显示了基本的…
medium.com](https://medium.com/python-in-plain-english/how-to-build-a-streamlit-app-to-scrape-github-profiles-f36d41fb98c) [## 如何从头开始构建 KNN 分类模型,并使用 Streamlit 对其进行可视化
虽然像 sklearn 这样的库让我们的生活变得更加轻松,但是从头开始制作一个模型总是一个很好的做法…
towardsdatascience.com](/how-to-build-a-knn-classification-model-from-scratch-and-visualize-it-using-streamlit-9fe8059cc418)
如果不能展示给别人看,那么构建 UI 又有什么意义呢?
进入 Streamlit 共享!
Streamlit sharing 是 Streamlit 提供的一项服务,用于轻松部署您的应用。下面我将介绍部署过程中的步骤。
获得简化的共享
Streamlit 共享目前处于测试模式,您需要加入等待列表才能访问它。通常需要几天才能进入,我在 72 小时内就进入了。去他们的网站注册
你注册的页面截图
几天之内,你应该会收到一封允许你访问的邮件。
用必要的库创建一个文本文件
创建一个包含依赖项的 requirements.txt 文件。下面是创建文件的命令
pip freeze > requirements.txt
在键入上述命令之前,请确保您的虚拟环境已激活
将文件上传到 GitHub
在 GitHub 上创建一个公共存储库并上传。py 文件和 requirements.txt 文件。
我的 Github 回购截图
我将部署以下回购
登录以简化共享
前往关注网站,使用您的 GitHub 账户登录。
https://share.streamlit.io/截图一
授权 Streamlit 并允许其访问您的 Github Repos。
创建新应用程序
https://share.streamlit.io/截图二
点击新应用程序
https://share.streamlit.io/截图三
选择您的存储库和分支。在我的例子中,它是回购协议的主分支,名为“rahulbanerjee 26/KNN-细流”
主文件路径应包含 app.py 文件的路径或。包含 Streamlit UI 代码的 py 文件。如果您的 app.py 文件位于名为“app”的文件夹中,路径将为“app/app.py”。确保您提供了正确的路径。填写正确信息后,单击部署。
现在只要坐好,放松☺️
部署完成后,您将收到一条成功消息,并能够看到应用程序的演示。
成功部署的屏幕截图
对回购进行的任何更新都会自动重新部署应用程序,几分钟后就可以看到您的更改,当然前提是没有错误。
你可以在这里找到我部署的应用
我最近用 WordPress 创建了一个博客,如果你能看看的话,我会很高兴的😃
[## Python 项目教程-使用这些 Python 项目教程改进您的简历/作品集。
使用 Streamlit 共享部署您的机器学习 Web 应用程序在我以前的文章中,我谈到过构建一个…
realpythonproject.com](https://realpythonproject.com/)
在 LinkedIn 上与我联系
[## Rahul baner JEE——产品工程实习生——EY | LinkedIn
查看 Rahul Banerjee 在世界上最大的职业社区 LinkedIn 上的个人资料。拉胡尔有 4 个工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/rahulbanerjee2699/)
在 Twitter 上与我联系
使用强力学习技术获得新技能
研究新的发展,跟上时代,用一个简单的技巧征服新知识
摄影爱好在 Unsplash 上
如果你刚刚进入职场或试图改变职业道路,学习新技能和发展新能力会让你走得更远,让你在就业市场脱颖而出。但是你如何有效地获得和保留新知识呢?
我们很幸运能够获得比以前任何一代人都多的知识和信息。如果你有正确的问题,正确的答案只需点击几下鼠标。然而,重要的是要对能从不同角度解决我们问题的教育者持开放态度。
有几种方式和数不清的方法可以帮助你不用回大学就能学到新的东西;书籍、在线课程、志愿工作、实习等。但是在这个故事中,我想强调一个帮助我做好准备的简单技巧:强力学习。你可以用它来实现你想做的任何事情,但我的经验来自信息技术和数字系统的世界。因此,这就是我的例子的来源。
Learning Rate 是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。订阅这里!
强力学习
想象一下,你正在尝试学习一门新的编程语言,一个像 Kubernetes 这样的新平台,甚至一个新概念,比如测试驱动开发(TDD)。首先,你试图理解为什么;为什么 Kubernetes 很重要?为什么 TDD 能帮助你成为更好的软件工程师?为什么 Python 是一种很棒的新语言,可以添加到我的工具箱中?
口袋里有了为什么,你会试着找一本介绍性的书或视频系列来理解基础知识:Python 中的变量、控制流和循环,Kubernetes 中的 pods 和服务,或者如何模拟服务。但是强力学习告诉你的是不要投资一门课程;拿两个!
一开始,找一门很棒的入门课程,然后一头扎进去。学习理论,研究习题,完成每一节。然后,找到另一个初学者的课程,从不同的角度接近同样的主题,做同样的事情。
但是,这对你有什么好处呢?那不是完全浪费时间吗?我认为不是。第一次学习一门学科,一切都是新的。你的大脑被新的术语、规则和概念轰炸。到课程结束时,你将已经内化了很大一部分,但不是全部。
从不同的角度重新审视整个事情,会让你专注于细节,打磨掉粗糙的边缘。第二次,并不是一切都是新的,啊哈时刻来得更频繁。而且,新的角度会给你一个新颖的观点,让你不再做一次枯燥的修改。
学完第二门课程后,你会更有信心进入更高级的部分,并继续努力达到精通。
结论
在这个故事中,我们看到了什么是强力学习技术,以及它如何帮助你学习和掌握新概念。我们很幸运能够获得比以前任何一代人都多的知识和信息。如果你有正确的问题,正确的答案只需点击几下鼠标。然而,对能从不同角度解决我们问题的教育者持开放态度是至关重要的。
关于作者
我叫迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲中央银行、经合组织和宜家等主要客户设计和实施人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请在 twitter 上关注我的媒体、 LinkedIn 或 @james2pl 。
所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。
使用网络抓取和熊猫进行市场分析:西班牙的 ESL 教学
通过分析公开可用的数据,了解任何行业的竞争格局。以下是一个案例研究,利用西班牙最受欢迎的私人教师网站,考察了西班牙的 ESL(英语作为第二语言)市场。
介绍
互联网是一个势不可挡的地方。有大量公开可用的结构化数据集可供分析,但大多数信息都以 HTML 的形式存在,这些 HTML 是动态生成的,并经过优化以在视觉上取悦查看者,但对数据科学家的分析没有用处。
Web 抓取是一个强大的工具,它允许我们机械地获取公开可用的数据,并以一种对我们的需求有用的方式对其进行组织。一旦原始数据被提取、清理和处理,我们就可以轻松地使用 Pandas 来分析数据。
Web Scrape + Pandas = Insights / Competitive Advantage / Profit
使用这种有效工具组合的真实例子数不胜数:
- 竞争力分析。浏览 Craigslist,查看旧金山的租赁市场,并代入等式,确定某栋房子的价格是否过低或过高。
- 市场概况。浏览 Yelp,深入了解洛杉矶哪个县的塔克里亚斯代表不足。
- 可行性研究。浏览 LinkedIn,评估拥有特定技能的员工的地理位置,以帮助确定在特定地区开设新分支机构是否有意义。
案例研究:西班牙的 ESL 私人教师
西班牙的英语水平是欧洲最低的之一,因此对 ESL 教学有很高的需求(最近的一项研究将其在 33 个欧洲国家中排在第 25 位)。随着世界变得越来越相互关联,企业越来越国际化,了解英语这一世界语言的重要性是至关重要的。
课外 ESL 教学可以采取多种形式;自学教材,书院集体课或者私教。本案例研究将考察一个最受欢迎的联系私人教师和学生的网站上的私人英语教师市场:Tus Clases speciales。
想象一下,一位新教师正在西班牙开始他们的 ESL 教学之旅,并希望对市场有所了解。我们想要回答的一些基本问题:
- 总体概述。老师都在哪里?
- 小时费率。哪些地区的时薪最高和最低?
- 教师需求。根据人口数量,是否存在教师人数不足或过多的地区,这是否会影响报价?
- 收视率。收视率影响价格吗,有百分之几的老师有?
- 付费广告。有百分之多少的教师会为网站上的广告付费,这是否带来了明显的优势?
- 搜索结果。谁在顶端?算法是否偏向有评论的老师,付费客户,新老师,有照片的老师…?
是时候开始刮了。
第 1 部分:从特定区域的结果页面获取概要文件 URL
让我们从访问瓦伦西亚地区英语教师的搜索结果开始,瓦伦西亚是地中海沿岸的西班牙海鲜饭的阳光之地。
第一步是直观地检查特定 URL 的结果,检查 HTML,并了解我们希望如何处理抓取。
url = '[https://www.tusclasesparticulares.com/profesores-ingles/valencia.aspx'](https://www.tusclasesparticulares.com/profesores-ingles/valencia.aspx')
(显示了 5 个广告列表,但是在每个结果页面上有 20 个——除了每个地区的最终结果页面)
让我们使用 chrome 上的“inspect”功能来挖掘一些广告列表背后的 HTML。
我们可以看到,每个广告列表都封装在一个特殊的 div 类中,遵循特定的模式:
#profile 1:
<div class="trr aitem int">
#profile 2:
<div class="trr aitem destacado plus int">
这个线索允许我们识别每个广告列表何时开始和结束。成功抓取网页的关键是识别这些线索和模式,以便机械地提取数据。所有有趣的细节都在这个 div 类中。
我们的攻击计划是使用极其有用的 Python 库 Beautiful Soup 遍历每个广告列表并提取所需的信息。原始的 HTML 很难处理,但是漂亮的 Soup 使用惯用的搜索、导航和编辑方式引导我们通过解析树。
#pull raw html
html = get(region_url)
soup = BeautifulSoup(html.text, 'html.parser')
让我们使用 soup.find_all 和 regex 包 re 来查找正确指向单个广告列表的文本模式——这将产生可迭代的 20 个教师简介。
for element in soup.find_all('div', {'class' : re.compile(r'^trr aitem')}):
在每个广告列表(div 类)中,解析并保存各种数据点,其中最重要的是单个列表的 URL(包含我们想要抓取的大部分数据)。
#look for a specific class that indicates the presence of a stock photo, indicating that the teacher does not use their own photo
if element.find('span', {'class' : 'spr_parrilla fotoparr'}) is None:
has_picture=True
else:
has_picture=False#look for ad listing URL (that directs to seperate page of listing) for link in element.find_all('div', {'class' : 'rightcontent'}):
if link.a is not None:
#construct full URL which links to specific ad
base_url = '[https://www.tusclasesparticulares.com'](https://www.tusclasesparticulares.com')
scrapped_url = link.a.get("href")
profile_url = base_url + scrapped_url
break
else:
#rare cases with no profile_url, log this information
profile_url = 'EMPTY'
break
我们暂时结束了!增加页面排名(记住,我们是在每个广告出现在页面上时循环播放),将所有内容保存到字典中,然后添加到列表中。
page_rank += 1
profe_dict = {'profile_url' : profile_url,
'results_page_url' : region_url,
'page_rank' : page_rank,
'results_ad_status' : results_ad_status,
'has_picture' : has_picture,
'html' : html}
landing_page_dict_list.append(profe_dict)
由此产生的词典列表可以很容易地转换成 Pandas 数据框架并打印出来,以显示原始数据。
我们立即拥有 20 条记录,每条记录都有几个有用的数据点。下一步是访问每个配置文件 URL,以获取每个广告列表的更多信息。
第 2 部分:Ping 每个配置文件的 URL,获取每个教师的详细数据点
让我们继续使用适用于第 1 部分的公式:
- 访问 URL 并使用 chrome 可视化检查 HTML。
- 找到数据存储的模式,并使用 Beautiful Soup 访问这些数据。
- 遍历 URL,将抓取的数据保存到字典列表中,转换成 Pandas Dataframe 并检查数据。
钻研 HTML。
用美汤解析。以下是代码示例。(GitHub 上有完整的笔记本,嵌入在本文末尾)。
#TITLE
if len(soup.find_all('div', {'class' : 'detinfotit'})) == 0:
ad_title = 'COULD NOT SCRAPE TITLE'
#add code to try alternative scraping method
else:
title_element = soup.find_all('div', {'class' : 'detinfotit'})[0]
ad_title = title_element.text.strip()
try:
ad_title
except NameError:
ad_title = 'EMPTY'#GEO LOCATION
for item in soup.find_all('p', {'id' : 'pProvincia'}):
province = ' '.join(item.text.split()[1:])
try:
province
except NameError:
province = 'EMPTY'#PRICE
for item in soup.find_all('div', {'id' : 'dvPrecio'}):
price = item.text.replace("\n","").replace("\r","")
try:
price
except NameError:
price = 'EMPTY'
#DESCRIPTION
for item in soup.find_all('div', {'class' : 'detcntsection c5'}):
description = item.text.strip()
try:
description
except NameError:
description = 'EMPTY'
#PROFE AD STATUS - BASIC, VERIFIED, PLUS
element = soup.find('p', {'class' : 'mgbottom5 fs16 bold'})
if element is None:
profe_ad_status = 'EMPTY'
else:
profe_ad_status = element.text#CREATE DICT WITH ALL ENTRIES AND RETURN DICTIONARY
scraped_profile={
'url': url,
'ad_title' : ad_title,
'teaching_subject' : teaching_subject,
'province' : province,
'class_level_para' : class_level_para,
'class_level_niveles' : class_level_niveles,
'method' : method,
'price' : price,
'teacher_name' : teacher_name,
'rating_count' : rating_count,
'profe_ad_status' : profe_ad_status,
'description' : description,
'page_rank' : profile_dictionary['page_rank'],
'results_ad_status' : profile_dictionary['results_ad_status'],
'has_picture' : profile_dictionary['has_picture'],
'results_page_url' : profile_dictionary['results_page_url'],
'alternative_scraping' : alternative_scraping,
'teacher_has_profile_page' : teacher_has_profile_page,
'is_academy' : is_academy,
'html' : html
}
return scraped_profile
酷!现在,我们从西班牙一个地区的单个结果页面中获得了大量有趣的数据。以下是数据示例:
对于每个地区,有几十个结果页面,西班牙有 54 个地区首府需要我们分析。我们还有一点工作要做。
分页问题很容易解决,因为 URL 可以机械地构造:
base_url = [https://www.tusclasesparticulares.com/profesores-ingles/valencia.aspx](https://www.tusclasesparticulares.com/profesores-ingles/valencia.aspx?pagina=7)next_page = [https://www.tusclasesparticulares.com/profesores-ingles/valencia.aspx?pagina=2](https://www.tusclasesparticulares.com/profesores-ingles/valencia.aspx?pagina=2)paginated_url = base_url + '?pagina=[PAGE_NUMBER]'
一些快速测试告诉我们,如果我们访问一个不存在的分页网址,即'?pagina=9999' ,我们将被定向回基本 URL。使用一点逻辑,我们可以编写一个循环,该循环将访问特定区域的每个结果页面(以便找出给定区域有多少页面的搜索结果)。
results_page_profile_dicts = []
counter = 1
current_page = base_region_url#infinite loop and break out once pagination link false
while True:
html = get(current_page)
if html.url == current_page:
#If so, continue, pagination exists.
#CONTINUE WITH SCRAPING,
#dictionary with each profile and additional data from results page
results_page_profile_dicts.extend(get_profile_urls(current_page, html))
counter +=1
current_page = base_region_url + '?pagina=' + str(counter)
#If not, no more pagination exists
else:
break
#finish results page scraping
最后一个障碍是遍历西班牙所有地区的首府,以便提取大部分数据。让我们将所有值和 URL 存储在一个字典中,然后遍历每个值和 URL,合并分页逻辑,抓取广告列表结果页面,抓取各个个人资料页面,最后将所有内容保存到一个数据帧中。
region_lookup = {
'soria' : '[https://www.tusclasesparticulares.com/profesores-ingles/soria.aspx'](https://www.tusclasesparticulares.com/profesores-ingles/soria.aspx'),
'teruel': '[https://www.tusclasesparticulares.com/profesores-ingles/Teruel.aspx'](https://www.tusclasesparticulares.com/profesores-ingles/Teruel.aspx'),
......
'barcelona' : '[https://www.tusclasesparticulares.com/profesores-ingles/barcelona.aspx'](https://www.tusclasesparticulares.com/profesores-ingles/barcelona.aspx'),
'madrid' : '[https://www.tusclasesparticulares.com/profesores-ingles/madrid.aspx'](https://www.tusclasesparticulares.com/profesores-ingles/madrid.aspx')
}end_loop = len(region_lookup)
region_start = 0
for i in range(region_start, end_loop):
results_page_profile_dicts = []
counter = 1
current_page = base_region_url[PAGINATION LOGIC]
[SCRAPE]
[SAVE DATA TO DATAFRAME]
结果数据帧数据点:
我们有 57,123 项记录;大量的数据需要分析!在最初的装载和清理步骤之后,我们可以深入了解一些情况。
分析笔记
在我们开始分析之前,有一些事情需要记住。
- 范围。我们只关注一个网站;这一分析并不全面涵盖西班牙的整个 ESL 教学市场——我们试图通过使用单个网站作为整体市场的代理来获得洞察力。
- 要价。时薪是什么老师的单子;这并不代表他们实际得到的价格。
- 老师过滤。这个分析旨在只看真正的老师;那些没有价格、没有个人资料图片或没有个人资料页面的照片被排除在分析之外。
每小时收费服务
教师的小时工资是如何分配的?哪些地区的产品价格最高和最低?小时费率的快速浏览:
我们可以看到,50%的教师要价在 10-15 欧元/小时之间,平均值为 12.6 欧元。
深入粒度,哪个自治区(地区)的费率最高?
不足为奇的是,像 Pais Vasco、Cataluñ和 Madrid 这样的经济强国接近榜首。
如果你是一名刚进入上述市场的新教师,这些数据将有助于确定收费标准。
教师的地理和收入潜力
老师在哪里?
最大的社区拥有最多的教师。有道理。
从总体人口来看,是否存在某些教师人数不足或过多的领域,这是否会影响每小时的工资?
使用从西班牙官方国家统计来源提取的人口数据,我们可以使用一些方法来比较 ESL 教学的供需。
下图显示了每个首都教师总数的百分比和居民总数的百分比。例如,马德里的居民占所有首都的 23%,但教师仅占总人口的 17%。有人可能会说,居民比教师更集中的地区,对新入职的教师来说,意味着更大的市场机会。
根据上述数据,马德里和萨拉戈萨似乎最需要教师。巴塞罗那、巴伦西亚、塞维利亚和格拉纳达都因教师过剩而引人注目(与居民相比)。这是有道理的,因为上述所有国家的首都都是外国人非常向往的城市。
让我们采取一种稍微不同的方法,简单地看一下居民与教师的比例。
有意思!使用这种方法,我们可以看到我们在之前的图表中选择的一些顶级球队(马德里和巴塞罗那)实际上位于中间位置。这种方法支持加的斯、巴伦西亚、格拉纳达和巴塞罗那都是市场饱和地区的观点。
只知道供给和需求并不能给我们全貌;我们应该将提供的教师时薪和外部工资数据(基于地区)结合起来,以更好地了解市场机会。使用相同来源的全国工资数据,我们计算了各地区的平均时薪,并将其与各地区 ESL 教师的时薪进行了比较。
按正速率差降序排列。
巴利阿里群岛在这一点上领先;教师的小时工资为 14 英镑,而地区平均工资约为 10.8 英镑。有人可能会说,基于生活成本和收入能力,教师的要求高于平均水平,在这个地区会做得很好。一个相反的论点可能是,与人们的收入相比,教师的要价太高了,他们将无法找到工作,因为他们太贵了。这是分析的局限性;我们只知道老师的问率;我们不知道他们是否真的以这样的速度找到了工作。
这里我们有相同的图表,但只是简单地看一下 ESL 教师和平均值之间的比率差异。
让我们尝试得到一个更全面的图片,并将前面的两个概念结合起来:下图是一个散点图,y 轴表示高于地区平均值的每小时教学工资,x 轴表示每个教师的居民人数。该地区的人口决定了点的大小。最理想的城市会在图表的右上方;工资高,教师需求量大(#居民/教师)。
*圆点代表人口的大小
看起来岛屿在召唤我们!巴利阿里群岛的首府帕尔马-德马略卡岛是当地工资收入最高的地方,教师的潜在客户也相对较多。
这是个教英语的好地方。帕特里克·努南的照片。
小时费率的变化
各种因素之间的小时工资率如何变化?基于以下因素计算小时费率的变化:
- 性别。 大约有 10%的教师被授予“专业地位”(通过支付广告产品的费用被认为是特殊的),如“Profesora verificada”或“professor plus”。由于西班牙语是一种性别语言,我们可以解析出老师的性别。
- 已评级。有一个评分系统,客户可以给老师留下评论。这个类别只是看老师是否有评分。
- 广告助推。教师可以购买一款广告产品,在结果顶部显示他们的列表,并为他们的广告添加醒目的黄色背景。
- 是本地人。老师的母语是英语吗?这些所谓的“nativos”非常受欢迎,通常要价更高。我们试图通过在教师描述中使用正则表达式来解析出声称是“本地人”的配置文件。大约 7%的教师声称自己的母语是英语。
这里有很多东西要打开。
- 性别。 当中位数相等时,男性倾向于更高的要价。
- 已评级。至少有一个评级的教师倾向于列出更高的评级。有道理。
- 广告助推。为一个广告位置付费大大提高了要价。
- 是原生的。自称是本地人的老师比那些不是本地人的老师要求更高的工资。
深入探究收视率
大约 15%的教师至少有一个评级。其中,让我们深入了解每位教师的评级数量。
*只查看有评语的教师
大多数有评分的老师都不到 5 分;为了与其他老师区分开来,尝试获得 5 个以上的评分!收视率如何影响要价?
从逻辑上讲,随着收视率的增加,教师要求更高的时薪。神奇的范围似乎在 5-7 分左右。
付费广告的优势
大约 1.3%的教师支付广告费用来提高他们的成绩。下图显示了按“结果页”划分的教师人数,其中包括未付费教师和付费教师。搜索教师时,结果的第一页是第 1 页(包含 20 名教师)。结果的第二页是第 2 页。最多 500!
我们立即看到,绝大多数是未付费列表,一小部分付费列表位于图表的左下方。100 页之后的结果量是惊人的!谁会点击这么远去找他们的老师?
让我们深入研究一下前 20 页的结果。
我们可以更清楚地看到,付费列表导致更高的页面排名,此外,第一页结果的很大一部分是由支付广告费用的教师组成的。付费才能玩!
可视化另一种方式显然,付费教师将获得更相关的列表:
再一次,令人震惊的是 75%的老师(不付钱)在第 20 页的结果后被埋没了。这些老师肯定没有收到信息;它们必须是废弃或过时的配置文件。为了吸引眼球,人们必须支付广告费。不错的商业模式!
搜索结果
各种因素如何影响搜索结果中的排名?在上一节中,我们证明了广告可以带来更好的排名,但是如果有评级,有图片,个人资料页面或价格列表呢?人们可能会认为,拥有广告列表的这些基本元素会导致更高的搜索结果。
在存在评级的情况下,唯一有意义地影响结果排名的元素。所以,潜在的老师们,如果你想在结果中排名靠前,一定要有一些评级,并支付广告费用!
最后的想法
基于对我们的网络抓取数据的分析,我们可以提供以下行动项目:
- 通过支付的广告和评级,在搜索结果中获得更高的排名。
- 有至少 5 个评论,并声称你是一个母语人士,并保证要求更高的时薪。
- 选择一个对教师需求高、时薪高于平均水平的地区居住,比如帕尔马-德马略卡或圣塞瓦斯蒂安(这两个地方都很适合居住)。
结论
通过利用网络抓取和 pandas,我们已经获得了相当无序和混乱的数据,并将其转化为有意义的可视化和洞察力,让我们了解这个世界。
有用的链接
- https://www . data camp . com/community/tutorials/web-scraping-using-python
- https://www . plural sight . com/guides/web-scraping-with-beautiful-soup
- https://www.dataquest.io/blog/web-scraping-beautifulsoup/
笔记本电脑
所有的 Jupyter 笔记本和一个 CSV 格式的数据都可以在我的 Git 库中找到。
利用你的数据技能在线赚钱
卡尔·海尔达尔在 Unsplash 上拍摄的照片
从你的数据技能中获得在线收入的三种方法
现在,在世界大部分地区,许多人正在失去他们通常的谋生手段。冠状病毒疫情已经导致大量行业关闭,这意味着许多企业主无法进行交易,员工被大量解雇或休假。
在我所在的英国,国家统计局(ONS) 最近对 6171 家企业的调查显示,24%的企业暂时关闭,93%的企业营业额低于预期。在美国,仅上周就有 320 万人申请失业保险,使得自疫情开始以来的失业申请总数达到了惊人的 3300 万。
在美国,仅在上周就有 320 万人申请失业保险
作为一名数据科学家,我个人受到了这场危机的影响,暂时失去了目前朝九晚五的工作。我发现自己正处于一个巨大的个人经济不确定时期,在这个世界上,越来越少的公司在招聘,许多企业面临倒闭。
我发现自己正处于一个巨大的个人经济不确定时期,在这个世界上,越来越少的公司在招聘,许多企业面临倒闭
在过去的几周里,我一直在寻找独立使用我的技能来创造额外收入来源的方法,这可能至少部分地为未来提供一些财务保障。
在下面的文章中,我将分享我发现的三个关键领域,利用我的在线数据技能来创造额外的收入。
现在用这种方式赚取收入的额外好处是,你可以选择自己的时间来处理其他事情。如果你和我一样,也是一位家长,而你的孩子目前无法上学或去其他儿童保育机构,这一点尤其有用。
在线课程
如果你一直在数据领域工作,那么你就拥有了其他人可以学习的有价值的技能和知识。有许多在线平台允许任何有适当技能和经验的人创建和营销在线课程并赚取收入。
数据营 有一个由 270 名教练组成的网络,你可以申请加入。他们表示,他们目前拥有超过 590 万数据科学家的受众,课程讲师可以通过他们的收入共享平台赚取版税。目前网站上的常见问题是,讲师的平均月收入在 1000-2000 美元之间。
我目前正在申请成为这里的讲师,如果我成功了,我会用实际收入数据更新这篇文章。
如果你没有 Datacamp 的运气,或者觉得它不适合你,还有许多其他的在线课程平台,你可以在那里赚钱。其中之一就是 复数视线 。该课程平台招募数据专家来创建基于视频、书面或实践的教育材料。与 Datacamp 类似,付费是基于版税的,版税与你的内容获得的浏览量以及该平台的付费用户数量相关联。Troy Hunt 的这篇出色的 文章提供了一些关于为 Pluralsight 工作的见解,包括一些关于收入潜力的信息。
你可以在很多其他地方发布在线课程内容并赚钱。其中包括 Udemy 和 Skillshare 等课程平台。你也可以考虑在 Youtube 等社交媒体平台上发布一系列教程,这样你就可以从付费广告中赚钱。
博客
在过去的一年半时间里,我一直在写博客,并通过媒体合作伙伴计划赚取微薄的额外收入。就博客平台而言,媒体可能是最容易起步和赚钱的。你不一定需要有大量的追随者,如果你的作品有趣且质量高,那么 Medium 有可能以标签的形式发布,这样你就能获得大量的浏览量。
我目前每月收入约 400 美元,每周花 5-10 个小时写作,通常每周在平台上发布一次。我将很快写一篇后续文章,讲述我如何、何时以及为什么在媒体上写数据科学。
除了 Medium 之外,你还可以将自己的博客作为一个独立的网站。Wordpress 是一个很好的平台。你可以免费开博客,也可以付费购买额外的功能,比如独特的域名和更大的存储空间。如果你的博客能获得足够的流量,那么赚钱的方式有很多种,包括 Google Adsense 和像 Amazon Associates 这样的联盟项目。
自由职业
在这篇文章中,我要谈的最后一个领域是自由职业者机构和网站。网上有很多平台,你可以提供你的技能、经验和服务来换取报酬。Upwork 可能是最受欢迎的网站之一。在这里你可以创建你的个人资料和申请自由职业者的工作。
快速搜索现在广告中与数据相关的工作,会显示 16,744 个结果。
希望这篇文章为您提供了一个很好的起点,让您可以找到利用在线数据技能赚取额外收入的方法。冠状病毒的经济影响将被广泛感受到,因此你可能会发现,当你开始这些举措时,它们不会立即产生可观的收入。
然而,随着各种商业领域最终开始重新开放,我相信,如果你在这些领域建立了一些基础,你将看到你的收入增长。我认为,关键在于选择一个重点领域,持续不断地创造,并为未来建立一个轮廓。
感谢阅读!
我每月都会发一份简讯,如果你想加入,请点击此链接注册。期待成为您学习旅程的一部分!
放弃
本报告中表达的想法和观点仅代表我个人,不一定代表我公司的观点。本报告旨在提供教育,不应被理解为个人投资建议,也不应被理解为购买、出售或持有任何证券或采取任何投资策略的建议。
在我的锻炼中再次使用机器学习,这次是建立一个私人教练
以下完整视频
在之前的故事中,我试图解决如何发现锻炼是否以正确的形式进行,使用 OpenPose 收集锻炼数据,并使用动态时间扭曲将锻炼执行与作为基线的正确执行进行比较。
这一次,我添加了以下其他组件来大大增强整体体验:
- 令人敬畏的面部识别库(【https://github.com/ageitgey/face_recognition】T2),用于执行面部识别和加载适当的锻炼
- 令人敬畏的语音识别(【https://github.com/Uberi/speech_recognition】T4),用于处理用户的回答
- 令人敬畏的谷歌文本到语音转换(https://github.com/pndurette/gTTS),用来和用户交谈和指导
这是工作流程的图形表示
基本流程——作者绘制
我仍然使用 OpenPose 的“dockerized”版本(https://github.com/garyfeng/docker-openpose)——本地安装相当长——调整一些参数也有可能实现良好的 fps。
体验非常简单:
- 你进入锻炼区域,面部识别组件匹配你的面部,提取一个轮廓(现在只是一个名字)
- 培训师会问你是否准备好开始,并等待你的回答(至少回答“是”——这一部分是按照脚本编写的,当然,可以用更复杂的解决方案来扩展)
- 教练将你的相关“wod”(一天中的锻炼)与要进行的练习(目前只有一项)一起载入
- 在 OpenPose 组件记录身体数据的同时,您可以执行练习重复和设置
- 教练将收集的数据与正确的基线进行比较,评估身体每个部位的动态时间弯曲值,最后给出一个中值。
- 如果该值低于某个阈值,则认为锻炼是正确的,教练给出该反馈,否则它会发出警告(目前是一般的警告,但是应该可以根据哪些身体部位是不正确的给出具体的提示)
- 重复,直到所有的重复完成
但是让我们来看看实际情况——很抱歉视频编辑,肯定是我做得不好:)
我努力工作来获得一个体面的经历,但是,当然,还有很多事情要做。
例如,现在锻炼估计是有时间限制的,但是应该可以训练系统理解锻炼何时开始和结束,丢弃其他帧用于评估。
此外,这只是一种独特的锻炼类型(引体向上),是专门用我的身体测量值进行的基线正确锻炼,但应该可以用通用基线进行不同的锻炼。
关于执行过程中具体错误的更精确的反馈是另一个有趣的研究点。
实现了这一点,它可以用于任何类型的锻炼(健身,瑜伽等),也可以用于对象(使用自定义跟踪对象算法),在独立模式下,或作为真正的教练的助手。
这是另一个例子,展示了结合不同的工具和库,在几个小时内可以实现什么,这在几年前是不可想象的,并且一直让我感到惊讶!
我希望你喜欢看这个(但是也看看上面的视频),谢谢你!
附录
让我们来看一些代码,看看执行人脸识别和文本到语音转换是多么简单。
对于 OpenPose 部分和练习评价,只需参考我的以前的故事附录
人脸识别
只是使用了演示部分的代码
所有的魔法都在编码中。一旦一张已知的脸被编码,你就可以把它和相机捕捉到的画面进行比较
antonello_image = face_recognition.load_image_file("faces/anto.jpg")antonello_image_encoding = face_recognition.face_encodings(antonello_image)[0]
交谈并处理答案
只是将文本保存到 mp3 文件中,然后播放它来说话
def say(text, language = 'en'):
speech = gTTS(text = text, lang = language, slow = False)
mp3_file = 'text.mp3'
speech.save(mp3_file)
p = vlc.MediaPlayer(mp3_file)
p.play()
time.sleep(2)
为了处理答案,我们使用谷歌引擎。
代码超级简单
def process_answer():
recognizer = sr.Recognizer()
microphone = sr.Microphone()
with microphone as source:
recognizer.adjust_for_ambient_noise(source)
audio = recognizer.listen(source)try:
response = recognizer.recognize_google(audio)
print('Received response {}'.format(response))
except sr.RequestError:
print('Error')
except sr.UnknownValueError:
response = 'Sorry I cannot understand'return response
把所有这些放在一起,你可以进行一个基本的对话
person = recognize() # using the face recognitionsay('Hello ' + person + ', are you ready?')response = process_answer()if ('yes' in response):
say('Ok, let\'s start')
else:
say('No problem, maybe tomorrow')
基于机器学习的二手车价格预测
数据清洗、数据预处理、8 种不同的 ML 模型和一些来自数据的见解
图片由 Panwar Abhash Anil 提供
在我的 GitHub 页面 可以到达与此相关的所有 Python 脚本。如果您感兴趣,还可以在同一个存储库中找到用于这项研究的数据清理和数据可视化的脚本。
该项目也使用 Django 部署在Heroku上,也通过Dockerizing Django App部署在 Amazon EC2 上
内容
- 数据清理(识别空值、填充缺失值和移除异常值)
- 数据预处理(标准化或规范化)
- ML 模型:线性回归、岭回归、拉索、KNN、随机森林回归、Bagging 回归、Adaboost 回归和 XGBoost
- 模型的性能比较
- 来自数据的一些见解
为什么价格特征通过对数变换进行缩放?
在回归模型中,对于 X 的任何固定值,Y 都分布在这个问题数据中——目标值(价格)不是正态分布,它是右偏的。
为了解决这个问题,当目标变量具有偏斜分布时,对其应用对数变换,并且我们需要对预测值应用反函数来获得实际的预测目标值。
因此,为了评估模型,计算 RMSLE 以检查误差,并且还计算 R2 分数 以评估模型的准确性。
一些关键概念:
- 学习率:学习率是一个超参数,它控制我们根据损耗梯度调整网络权重的程度。该值越低,我们沿下坡行驶的速度越慢。虽然在确保我们不会错过任何局部最小值方面,这可能是一个好主意(使用低学习率),但这也可能意味着我们将需要很长时间才能收敛——特别是如果我们被困在一个平坦区域。
- n_estimators :这是在进行最大投票或平均预测之前,你想要建立的树的数量。树的数量越多,性能越好,但代码速度越慢。
- R 评分:是数据与拟合回归线接近程度的统计度量。它也被称为决定系数,或多元回归的多重决定系数。0%表示该模型不能解释响应数据在其平均值附近的任何可变性。
1.数据:
本项目使用的数据集是从 Kaggle 下载的。
2.数据清理:
第一步是从数据集中移除不相关/无用的特征,如“URL”、“region_url”、“vin”、“image_url”、“description”、“county”、“state”。
下一步,检查每个要素的缺失值。
显示缺失值(图片由 Panwar Abhash Anil 提供)
接下来,通过适当的方法用适当的值填充现在缺失的值。
为了填补缺失值,使用 迭代估算器 方法,实现不同的估计器,然后使用cross _ val _ score计算每个估计器的 MSE
- 平均值和中位数
- 贝叶斯岭估计量
- 决策树回归估计量
- 树外回归估计量
- kneighbors 回归估计量
使用不同插补方法的均方误差(图片由 Panwar Abhash Anil 提供)
从上图中,我们可以得出结论,extractree regressor估计量将更好地用于填充缺失值的插补方法。
填充后缺少值(图片由 Panwar Abhash Anil 拍摄)
最后,在处理缺失值后,零个空值。
异常值:用四分位差(IQR)法从数据中剔除异常值。
显示异常值的价格箱线图(图片由 Panwar Abhash Anil 提供)
显示异常值的里程表方框图(图片由 Panwar Abhash Anil 提供)
年度柱状图和柱状图(图片由 Panwar Abhash Anil 提供)
- 从图 1 中可以看出,低于 6.55 和高于 11.55 的价格是异常值
- 从图 2 中,不可能得出什么结论,因此计算 IQR 来发现异常值,即低于 6.55 和高于 11.55 的里程表值是异常值。
- 从图 3 来看,1995 年以下和 2020 年以上的年份是异常值。
最后,处理前的数据集形状= (435849,25),处理后的数据集形状= (374136,18)。总共删除了 61713 行和 7 列。
3.数据预处理:
标签编码器:在我们的数据集中,12 个特征是分类变量,4 个是数值变量(价格列除外)。为了应用 ML 模型,我们需要将这些分类变量转换成数值变量。而 sklearn 库 LabelEncoder 就是用来解决这个问题的。
归一化:数据集不是正态分布。所有功能都有不同的范围。如果不进行归一化,ML 模型将尝试忽略低值要素的系数,因为与大值相比,它们的影响非常小。因此为了归一化,使用了 sklearn 库,即 MinMaxScaler 。
训练数据。在此过程中,90%的数据被分割为列车数据,10%的数据作为测试数据。
4.ML 型号:
在本节中,不同的机器学习算法用于预测价格/目标变量。
数据集是受监督的,因此模型按给定的顺序应用:
1)线性回归:
在统计学中,线性回归是一种模拟标量响应(或因变量)和一个或多个解释变量(或自变量)之间关系的线性方法。在线性回归中,使用线性预测函数对关系进行建模,其未知模型参数根据数据进行估计。这种模型被称为线性模型。 更多详情
系数:每个系数的符号表示预测变量和响应变量之间关系的方向。
- 正号表示随着预测变量的增加,响应变量也增加。
- 负号表示随着预测变量的增加,响应变量减少。
显示线性回归性能的图表(图片由 Panwar Abhash Anil 提供)
显示数据集重要特征的图表(图片由 Panwar Abhash Anil 提供)
考虑到这个数字,线性回归表明 年份、气缸、变速器、燃油和里程表 这五个变量是最重要的。
线性回归的结果(图片由 Panwar Abhash Anil 提供)
2)岭回归:
岭回归是一种分析多重共线性数据的技术。当多重共线性发生时,最小二乘估计是无偏的,但是它们的方差很大,因此它们可能远离真实值。
为了在岭回归中找到最佳 alpha 值,应用了黄砖库alpha selection。
显示 Alpha 最佳值的图表
从图中可以看出,最适合数据集的 alpha 值是 20.336。
注意:α的值不是常数,它随时都在变化。
使用 alpha 的这个值,实现了 Ridgeregressor。
显示重要特征的图表
考虑到这个数字,拉索回归表明 年份、气缸、变速器、燃油和里程表 这五个变量是最重要的。
这个模型的最终结果(图片由潘瓦尔·阿布哈什·阿尼尔提供)
岭回归的表现几乎和线性回归一样。
3)套索回归:
套索回归是一种使用收缩的线性回归。收缩是指数据值向中间点收缩。lasso 程序鼓励简单、稀疏的模型(即参数较少的模型)。
为什么使用套索回归?
套索回归的目标是获得预测因子的子集,使定量响应变量的预测误差最小化。lasso 通过对模型参数施加约束来实现这一点,这会导致某些变量的回归系数向零收缩。
这个模型的最终结果(图片由潘瓦尔·阿布哈什·阿尼尔提供)
但是对于这个数据集,没有必要进行套索回归,因为误差没有太大的差别。
4)k 近邻回归器:回归——基于 k 近邻。
通过与训练集的最近邻居相关联的目标的局部插值来预测目标。
k -NN 是一种基于实例的学习,或懒惰学习,其中函数仅局部近似,所有计算都推迟到函数求值。 阅读更多
每个 K 范围 1-9 的误差图(图片由 Panwar Abhash Anil 提供)
从上图可以看出,对于 k=5,KNN 给出的误差最小。因此,使用 n_neighbors=5 和 metric='euclidean '来训练数据集。
KNN 的最终结果(图片由潘瓦尔·阿布哈什·阿尼尔提供)
性能 KNN 更好,并且误差随着精度的增加而减小。
5)随机森林:
随机森林是由许多决策树组成的分类算法。它在构建每棵树时使用 bagging 和特征随机性,试图创建一个不相关的树木森林,其委员会的预测比任何单棵树都更准确。 阅读更多
在我们的模型中,用 max_features 0.5 创建了 180 个决策
随机森林的性能(真实值与预测值之比)
这是一个简单的柱状图,说明了 年 是汽车最重要的特征,然后是 里程表 变量,然后是其他。
随机森林模型精度表(图片由 Panwar Abhash Anil 提供)
随机森林的性能更好,精确度提高了大约。10%很好。由于随机森林在建造每棵树时使用装袋,因此将执行下一个装袋回归程序。
6)装袋回归器:
Bagging 回归器是一种集合元估计器,它将每个基础回归器拟合到原始数据集的随机子集上,然后聚合它们的预测(通过投票或平均)以形成最终预测。这种元估计器通常可以被用作一种方法,通过将随机化引入到其构造过程中,然后从中进行集成,来减少黑盒估计器(例如,决策树)的方差。 阅读更多
在我们的模型中,DecisionTreeRegressor 用作估计器,max_depth=20,它创建了 50 个决策树,结果如下所示。
Bagging 回归器精度表(图片由 Panwar Abhash Anil 提供)
随机森林的性能比 Bagging 回归器好得多。
随机森林和 Bagging 的关键区别:根本区别在于,在随机森林中,仅从全部和特征中随机选择一个子集,该子集中的最佳分裂特征用于分裂树中的每个节点,这与 bagging 中考虑所有特征来分裂节点不同。
7) Adaboost 回归器:
AdaBoost 可用于提升任何机器学习算法的性能。Adaboost 帮助你将多个“弱分类器”组合成单个“强分类器”。库使用:AdaBoostRegressor&阅读更多
这是一个简单的柱状图,说明了 年 是汽车最重要的特征,然后是 里程表 变量,然后是型号等。
在我们的模型中,DecisionTreeRegressor 用作具有 24 max_depth 的估计器,创建 200 棵树&以 0.6 learning_rate 学习模型,结果如下所示。
AdaBoost 回归器的精度表(图片由 Panwar Abhash Anil 提供)
8) XGBoost: XGBoost 代表极端梯度增强
XGBoost 是一种集成学习方法。XGBoost 是梯度提升决策树的实现,旨在提高速度和性能。这种强大算法的美妙之处在于其可扩展性,它通过并行和分布式计算驱动快速学习,并提供高效的内存使用。 阅读更多
这是一个简单的重要性递减柱状图,它说明了哪一个 特征/变量是汽车的重要特征更重要。
根据 XGBoost 的说法,里程表是一个重要的特征,而从以前的车型年是一个重要的特征。
在该模型中,创建了 200 个最大深度为 24 的决策树,并且该模型以 0.4 的学习速率学习参数。
XGBoost 回归器精度表(图片由 Panwar Abhash Anil 提供)
4)模型的性能比较:
每个模型的精度比较(图片由 Panwar Abhash Anil 提供)
总体精度表(图片由潘瓦尔·阿布哈什·阿尼尔提供)
从上图可以得出结论,XGBoost 回归器以 89.662%的准确率表现优于其他模型。
5)来自数据集的一些见解:
从这一对情节中,我们不能得出任何结论。变量之间没有相关性。
配对图以寻找相关性
从 distplot 中,我们可以得出结论,最初,价格快速上升,但在某个特定点之后,价格开始下降。
显示价格分布的图表(图片由 Panwar Abhash Anil 提供)
3 从图 1 中,我们分析出柴油版车型的车价高于电动版车型的车价。混动变形车价格最低。
显示每种燃料价格的条形图
4 从图 2 中,我们分析出各种燃料的汽车价格也取决于汽车的状况。
燃料和价格与色调条件之间的条形图
从图 3 中,我们分析出 1995 年后汽车价格每年都在上涨,从图 4 中,汽车的数量也每年都在增加,在某个时间点,即 2012 年,汽车的数量几乎相同。
显示价格每年变化的图表
从图 5 中,我们可以分析出汽车的价格也取决于汽车的状况,从图 6 中,价格也随着汽车大小的状况而变化。
显示车况价格的柱状图
7 从图 7-8 中,我们分析了汽车价格以及汽车的各个变速器的价格。人们愿意购买有“其他变速器”的汽车,而有“手动变速器”的汽车价格较低。
柱状图显示了传输的价格(图片由 Panwar Abhash Anil 提供)
8 下面有相似的图形,具有相同的洞察力,但功能不同。
结论:
通过执行不同的最大似然模型,我们的目标是获得更好的结果或最大精度的更少误差。我们的目的是预测有 25 个预测值和 509577 个数据条目的二手车的价格。
首先,执行数据清洗以从数据集中移除空值和离群值,然后实施 ML 模型来预测汽车价格。
接下来,借助数据可视化特性进行了深入探讨。检查特征之间的关系。
从下表可以得出结论,XGBoost 是预测二手车价格的最佳模型。XGBoost 作为回归模型给出了最好的 MSLE 和 RMSLE 值。
精度表(图片由 Panwar Abhash Anil 提供)
仅此而已!如果你读到这里,感谢你的阅读。感谢任何反馈!并且可以在Linkedin上联系到。
对数据科学有用的 Excel 函数
Excel 数据科学之旅
数据科学家花大量时间处理数据。而且,当我们谈论数据时,excel 总是派上用场。Excel 有许多有用的功能,如加法、减法、乘法,但这些功能对计算很有用。在数据科学领域,我们需要海量的数据来训练我们的机器学习模型。数据可以来自不同的来源,但最终,我们需要对其进行组织。而且,在大多数情况下,我们将数据转换成表格格式。
一旦我们将数据转换成表格格式,我们就需要绘制不同的图形和图表来可视化数据特征并获得其他数据列中的关系。在绘制数据之前,我们需要对数据进行许多更改和执行许多操作。此外,还需要 excel 函数。
本文将讨论 excel 中一些最新的、有用的函数,这些函数通常用于我们的数据科学任务。
匹配功能
Match 函数有助于获取列表中任何项目的索引号。我们通常使用水平查找或垂直查找的匹配函数。我将在本文后面讨论垂直和水平查找。
句法
**MATCH(lookup_value, lookup_array, [match_type])**
这里,匹配类型可以是 0,表示精确匹配,-1 表示小于任何数字,1 表示大于任何数字。
匹配功能
查找功能
查找函数有助于从主数据源创建子数据。主数据源可以在同一个 excel 表中,也可以在不同的 excel 表中。子数据中的列应该是主数据源的一部分;否则,我们将得到这些列的空值。查找函数以两种方式搜索数据;第一种是垂直查找,第二种是水平查找。
垂直查找
主数据源和子数据中的垂直查找应该有一个公共的列名。主数据中的公共列应该出现在数据的最左侧。
句法
VLOOKUP(lookup value, range containing the lookup value, the column number in the range containing the return value, Approximate match (TRUE) or Exact match (FALSE))
这里,查找值是子数据和主数据中公共列值的值。该区域是主查找数据的选定数据部分。列号是应该出现在主数据中的子列名的列表。这些子列名有助于生成子表。
不同工作表中的主数据源
对于下面的例子,我们将使用带有 match 函数的垂直查找来获取主数据中的列索引。
=VLOOKUP($A29,lookup_table!$A:$K,MATCH(B$28,lookup_table!$A$1:$K$1,0),0)
匹配垂直查找
水平查找
水平查找,我们通常用于获取任何列名的计算结果值。结果列名应该是主数据的一部分。这些列的名称应该出现在主数据的第一行。
句法
**HLOOKUP(lookup_value,table_array,row_index_num,range_lookup)**
水平查找
索引和匹配功能
“垂直”和“水平”的工作条件是查找范围列表应该在最左侧或顶部第一位。有时,我们需要在任意位置与列表进行匹配。在这种情况下,我们使用索引和匹配。
句法
INDEX(array, row number,[column number])
我们的主要数据和右边的匹配列
=**INDEX(lookup_table_2!$A$2:$K$38,MATCH($B61,lookup_table_2!$K$2:$K$38,0),MATCH(Sheet1!C$60,lookup_table_2!$A$1:$K$1,0))**
这里,我们需要选择主查找表,然后使用 match 函数定义行和列的匹配。
索引和匹配函数示例
x 查找
垂直查找在从上到下的方向上查找匹配,X 查找为我们提供了从上到下和从下到上的随机方向的功能。
凝固法
freeze 方法有助于冻结任何列或行。当我们将函数复制到整个表时,这很有用。我们需要使用美元“$”符号来冻结任何行或列。冻结任何单元格的快捷键是键盘上的“f4”。
最后几点
我们已经讨论了一些主要函数,这些函数通常用于我们的数据科学任务。当我们必须处理数据可视化时,这些是许多方便的 excel 函数,我们必须从主数据源中获取子数据。此外,在数据科学访谈中,这些也是 excel 中常见的话题。
[## Pranjal Saxena -高级软件工程师-凯捷| LinkedIn
在凯捷拥有 2 年以上的经验,拥有基于 Python、Django、机器学习、深度…
www.linkedin.com](https://www.linkedin.com/in/pranjalai/)
好了,暂时就这样了。我希望这篇文章对你有用,继续享受数据科学。
对数据科学有用的计算机知识
戴维·冯迪马尔在 Unsplash 上拍摄的照片
从学术研究人员到行业专业人士,从工程和各种科学等传统技术/数学学科到社会科学、艺术、人力资源、销售和营销等领域,他们中的许多人现在都有了一个新的技术组成部分,即数据科学领域。在过去的几年中,这种新工具在许多行业和学科中带来了许多积极的变化,因此吸引了这些行业的人们以及其他尚未探索其功能的技术和非技术人员的极大兴趣。
有许多有用的在线资源可用于学习许多核心概念,如机器学习,以及许多使用 Python 和 r 等强大工具将它们应用于数据集的示例。虽然这些对于提取数据驱动决策的强大结果非常重要,但我发现对所需硬件平台的关注往往被忽视。与驾驶汽车类似,驾驶员可能不需要知道如何从头开始组装每个部件,但理解一些概念,如前轮/后轮驱动的区别,以及当你想开车去滑雪场时为什么更喜欢四轮/四轮驱动,将有助于一般驾驶。
我希望我对这里分享的一些核心组件所扮演的角色的类比理解可以帮助其他人了解如何充分利用它们,并最大限度地提高数据处理的效率。
母板
一个 主板 就像一个办公室里的经理。它的主要职责是管理作业请求并将其分配给与其连接的不同组件(硬盘、RAM 等)。尽管它没有做太多的主要工作,但它仍然需要不时地升级,正如你所期望的那样,经理需要随时了解他/她的团队的最新情况,因为他们提高了自己的技能并利用了现代技术。
哈迪斯克
帕特里克·林登伯格在 Unsplash 上的照片
一个 硬盘 类似于办公室里老式的学校信息存储。所有的信息都存储在硬拷贝上,组织在文件夹里(一点也不双关),放在书架上。随着存储信息的复杂性增加(从早期的主要文本到现代的视频和技术文件),所需容量的增加是补偿这种变化的必然结果。
信息必须从存储它们的地方提取出来才能被访问。它们通常被从硬盘复制到 RAM 进行处理,并且内容中的任何更新被从 RAM 复制回硬盘。
随机存取存储器
(图片来自 Pixarbay )
[随机存取存储器](http://Random-access memory) 类比于办公室里桌子的大小。这些年来,为了跟上存储信息的复杂性,它们所需的大小也像硬盘一样增加了。它们的容量决定了一次可以同时处理多少信息,就像你从书架上拿了多少文件可以放在桌面上阅读一样。
任务通常由多个阶段组成,并且只需要在每个阶段中同时加载一组特定的信息。用于运行该任务的软件通常会管理要加载的所需信息的变化。如果 RAM 容量足够大,可以同时加载所有阶段的所有信息,那么任务的执行速度会比另一种方法快,后者只能在需要时加载不同的信息集。如果任务需要同时加载比 RAM 所能容纳的更多的信息,那么它就不能被执行。列出了最低要求的软件(尤其是电脑游戏)(几乎总是包括 RAM)是这方面的完美例子。
中央处理器
Brian Kostiuk - @BriKost 在 Unsplash 上的照片
中央处理器 可以看作是做业务核心工作的团队。它们已经从早期的单核版本发展到了当今时代的多核版本。额外的核心可以理解为团队中有更多的成员,这允许将更大的任务分成更小的任务,并在并行计算中处理。根据每个正在运行的任务所需的资源,有些任务可能全部由单个内核处理,而有些任务可能需要多个内核才能成功执行。
图形处理单元
(图片来自 Pixabay )
图形处理单元 是来自显卡的处理单元,通常用于在屏幕上渲染漂亮图形所需的计算。在过去的几十年里,像科学家这样的人越来越喜欢用它来进行复杂的计算。与 CPU 相比,GPU 的运行方式经常被类比为大型公共汽车与跑车,其中一辆速度较慢,但可以同时搭载更多乘客,而另一辆速度较快,座位较少。GPU 包含更多简单的核心,这使得它更适合执行高度并行的任务,而 CPU 在完成更复杂的任务方面相对更高效。在这个和这个等文章中有更深入的对比。
结论
从小型企业到大型组织,随着全球数据量继续呈指数级增长,越来越多的数据科学家被雇用来利用隐藏在数据中的力量。特别是在有数据科学家而不是数据科学家团队的较小组织中,当任务是在具有 100 多个特征的数据集上运行卷积神经网络模型时,知道您可能需要比笔记本电脑更多的东西也很重要,就像如果您想要移动冰箱或床,您如何自动知道您需要比轿车更多的东西一样。
有用的熊猫功能你可能不知道
用这四个功能提升你的熊猫知识
简介
Pandas 库可能是用 python 执行数据分析的最流行的包。有很多教程介绍了熊猫的基本功能,但在这篇文章中,我想分享一些熊猫的功能,这些功能不太为人所知,但对于日常数据分析任务来说非常方便。
让我们开始吧。
加载数据
在了解为本文选择的函数之前,我们需要加载一些数据。我们将使用以下代码创建一个数据框。
import pandas as pd
client_dictionary = {'name': ['Michael', 'Ana', 'Sean', 'Carl', 'Bob'],
'grade': [['A', 'A'], ['C'], ['A', 'C', 'B'], [], ['F']],
'age': [19, 19, 17, 18, '-'],
'group': ['class_1', 'class_2', 'class_2', 'class_1', 'class_2'],
'suspended': [True, False, True, False, True]
}
df = pd.DataFrame(client_dictionary)
如您所见,这是一个非常简单的数据框。它表示关于学生的数据(行)并描述他们的详细信息,如姓名、年级、年龄、组以及他们是否被暂停(列)。
这个简单的数据框将帮助我们演示今天将要学习的所有函数。
infer_objects()
如果您已经使用 pandas 和数据框有一段时间了,您可能已经注意到 pandas 非常擅长推断为列输入的数据。如果你有一个整数列,它将分配整数类型,如果它们是布尔类型,它将分配布尔类型,等等。
然而,有些时候你需要强迫它去做。这通常是当您有一个数据框,其中的列被推断为对象,但经过仔细观察,您意识到它们应该是不同的数据类型。
为了看到它,让我们再看一下我们的数据框。
您可以看到最后一行中的 age 列有一个破折号,而不是数字(-)。这可能表明该学生的年龄未知,但会导致该列被读取为对象类型。
df.info()
现在让我们说,我们不想包括不完整的数据,所以我们将过滤掉年龄列中有破折号的条目,在我们的情况下只有整数的条目。
df = df[df.age != '-']
现在让我们看看 info()函数,看看 filtred 数据帧的类型是否得到了更新。
df.info()
正如您所看到的,条目较少(只有 4 个),但是年龄列的类型仍然是一个对象。这就是 infer_objects()函数有所帮助的时候了。您可以在整个数据框上调用它,它应该会再次推断类型。
df = df.infer_objects()
df.info()
爆炸()
为了研究 explode()函数,让我们再看一下数据帧。
请注意,“等级”列由等级列表组成,而不是一个等级本身。有时,您希望为列表中的每个项目创建一个条目,而不是将整个列表作为一个条目。您可以使用 explode()函数来实现这一点。
exploded_df = df.explode('grade', ignore_index=True)
exploded_df
正如你现在看到的,每个年级都有一个条目,列表“展开”了。请注意,函数 explode()将列名作为用于“explode”的参数。在我们这里是‘等级’。
我还将 ignore_index 参数设置为 True。如果我没有这样做,那么每个条目都会有来自原始数据框的索引。
pivot_table()
Pivot_table()函数允许我们像 Excel 一样创建数据透视表。如果你没有听说过 Excel 中的数据透视表,那么在熊猫身上尝试之前,最好先用 Excel 学习一下。
然而,数据透视表允许我们通过指定成为数据透视表条目的列、行和值来重新组织数据。让我们再看一下我们的数据框。
我们可以使用 pivot_table()函数来学习每组的平均年龄。
pd.pivot_table(df, index='group')
您可以看到,我们已经将数据透视表的索引指定为组列。我们没有指定数据透视表中应该有哪些列,所以 pandas 只是将其他数值放在那里,而没有进一步分割它们。
您可以看到,1 班的平均年龄为 18.7 岁,该班有 66.6%的学生停学,而 2 班的平均年龄为 17.5 岁,其中 75%的学生停学。数据透视表条目是子组的平均值。
如果我们现在将数据透视表列指定为原始数据框中的“暂停”列,会发生什么情况?
pd.pivot_table(df, index='group', columns='suspended')
你可以看到,现在我们有每个班级的年龄划分,以及他们是否停课的事实。表中的数值还是平均值。您实际上可以通过添加 aggfunc 参数来使用不同的聚合函数,比如 sum()、max()或 min()。
需要注意的是,pivot_table()函数中的列和索引应该是原始数据框中的分类变量。这样就可以分成更小的小组。
转置()
Transpose()函数非常简单,但是了解它是救命稻草。它只是将列变为行(转置您的数据框)。它的功能在示例中再次得到了最好的展示,所以让我们看看我们的原始数据框。
现在让我们转置它。
transposed = df.transpose()
transposed
如您所见,最初是行,现在是列,反之亦然。
总结
在本文中,您学习了如何使用四个新功能:
- infer_objects()
- explode(),
- 数据透视表()
- 和转置()
我希望从现在开始,无论何时你需要它们的功能,你都可以调用它们。编码快乐!
原载于 aboutdatablog.com: 有用的熊猫功能你可能不知道,2020 年 10 月 27 日。
PS:我正在 Medium 和aboutdatablog.com上撰写以简单易懂的方式解释基本数据科学概念的文章。你可以订阅我的 邮件列表 在我每次写新文章的时候得到通知。如果你还不是中等会员,你可以在这里加入。
下面还有一些你可能喜欢的帖子
* [## 关于 jupyter 笔记本你不知道的 9 件事
用这些建议提高你的工作效率
towardsdatascience.com](/9-things-you-did-not-know-about-jupyter-notebook-d0d995a8efb3) [## 9 大 Jupyter 笔记本扩展
改进笔记本电脑功能,提高您的工作效率
towardsdatascience.com](/top-9-jupyter-notebook-extensions-7a5d30269bc8) [## 9 熊猫有效数据分析的可视化技术
学习如何使用折线图、散点图、直方图、箱线图和其他一些可视化技术
towardsdatascience.com](/9-pandas-visualizations-techniques-for-effective-data-analysis-fc17feb651db)*
为您的下一个机器学习项目提供 7 个 PyTorch 函数
机器学习
探索各种 PyTorch 函数
图片来自 Pixabay 的 Gerd Altmann
PyTorch 是一个越来越受欢迎的机器学习库。在本文中,我们将探索 PyTorch 中的七个可用函数。
首先,我们将使用import torch
导入 PyTorch
功能一:torch.linspace
torch.linspace
用于在值start
和end
之间创建一个 1D 等距张量。我们可以用steps
参数指定张量的大小。默认为steps=100
例-1:
torch.linspace(1, 10)**Output:**
tensor([ 1.0000, 1.0909, 1.1818, 1.2727, 1.3636, 1.4545, 1.5455, 1.6364, 1.7273, 1.8182, 1.9091, 2.0000, 2.0909, 2.1818, 2.2727, 2.3636, 2.4545, 2.5455, 2.6364, 2.7273, 2.8182, 2.9091, 3.0000, 3.0909, 3.1818, 3.2727, 3.3636, 3.4545, 3.5455, 3.6364, 3.7273, 3.8182, 3.9091, 4.0000, 4.0909, 4.1818, 4.2727, 4.3636, 4.4545, 4.5455, 4.6364, 4.7273, 4.8182, 4.9091, 5.0000, 5.0909, 5.1818, 5.2727, 5.3636, 5.4545, 5.5455, 5.6364, 5.7273, 5.8182, 5.9091, 6.0000, 6.0909, 6.1818, 6.2727, 6.3636, 6.4545, 6.5455, 6.6364, 6.7273, 6.8182, 6.9091, 7.0000, 7.0909, 7.1818, 7.2727, 7.3636, 7.4545, 7.5455, 7.6364, 7.7273, 7.8182, 7.9091, 8.0000, 8.0909, 8.1818, 8.2727, 8.3636, 8.4545, 8.5455, 8.6364, 8.7273, 8.8182, 8.9091, 9.0000, 9.0909, 9.1818, 9.2727, 9.3636, 9.4545, 9.5455, 9.6364, 9.7273, 9.8182, 9.9091, 10.0000])
例-2:
torch.linspace(start=1, end=10, steps=5)**Output:**
tensor([ 1.0000, 3.2500, 5.5000, 7.7500, 10.0000])
功能二:手电筒.眼睛
torch.eye
返回对角线值为 1,其他值为 0 的 2D 张量
该函数需要两个参数— n
和m
。如果没有指定m
,那么它返回一个大小为nxn
的 2D 张量
例-1:
torch.eye(n=4, m=5)**Output:** tensor([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.]])
例-2:
torch.eye(n=3)**Output:**
tensor([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
功能三:火炬。满
torch.full
返回一个大小为size
的张量,其值填充为fill_value
size
可以是一个列表或元组。
例题-1:
torch.full(size=(3,2), fill_value=10)**Output:** tensor([[10., 10.],
[10., 10.],
[10., 10.]])
例-2:
torch.full(size=[2, 3, 4], fill_value=5)**Output:**
tensor([[[5., 5., 5., 5.],
[5., 5., 5., 5.],
[5., 5., 5., 5.]],[[5., 5., 5., 5.],
[5., 5., 5., 5.],
[5., 5., 5., 5.]]])
功能四:torch.cat
torch.cat
连接指定维度上的一系列张量dim
。所有的张量必须是相同的形状
例-1:
a = torch.ones(3,2)
b = torch.zeros(3,2)
torch.cat((a, b)) # default dim=0**Output:** tensor([[1., 1.],
[1., 1.],
[1., 1.],
[0., 0.],
[0., 0.],
[0., 0.]])
例-2:
x = torch.full((3,3), fill_value=4)
y = torch.full((3,3), fill_value=7)
torch.cat((x, y), dim=1)**Output:** tensor([[4., 4., 4., 7., 7., 7.],
[4., 4., 4., 7., 7., 7.],
[4., 4., 4., 7., 7., 7.]])
功能五:火炬.拿
torch.take
返回给定索引处输入张量元素的张量。输入张量被视为 1D 张量来返回值。
例-1:
# 1D input Tensor
b = torch.tensor([10, 20, 30, 40, 50])
torch.take(b, torch.tensor([2]))**Output:**
tensor([30])
例-2:
# 2D input tensor
a = torch.tensor([[1, 2, 3],
[4, 5, 6]])
torch.take(a, torch.tensor([3,4]))**Output:** tensor([4, 5])
功能 6: torch.unbind
torch.unbind
沿给定维度dim
删除一个张量维度,默认维度为 0,即dim=0
例-1:
a = torch.tensor([[1, 2, 3],
[4, 5, 6]])
torch.unbind(a)**Output:**
(tensor([1, 2, 3]), tensor([4, 5, 6]))
例-2:
a = torch.tensor([[1, 2, 3],
[4, 5, 6]])
torch.unbind(a, dim=1)**Output:**
(tensor([1, 4]), tensor([2, 5]), tensor([3, 6]))
功能七:火炬。张量克隆
torch.Tensor.clone
返回相同大小和数据类型的张量副本。
当我们使用x=y
创建张量的副本时,改变一个变量也会影响另一个变量,因为它指向相同的内存位置。
举个例子,
a = torch.tensor([[1., 2.],
[3., 4.],
[5., 6.]])
b = a
a[1,0]=9
b**Output:**
tensor([[1., 2.],
[9., 4.],
[5., 6.]])
为了避免这种情况,我们可以使用.clone
方法创建张量的深度副本。
举例:
a = torch.tensor([[1., 2.],
[3., 4.],
[5., 6.]])
b = a.clone()
a[1,0]=9
b**Output:**
tensor([[1., 2.],
[3., 4.],
[5., 6.]])
结论
在本文中,我们看到了 PyTorch 中七个可用函数的工作原理。希望这篇文章能帮助你理解这些功能。还有许多其他有用的功能。您可以参考官方文档获取可用功能的完整列表。
参考
资源
本文中使用的代码片段可以在我的 GitHub 页面上找到。
让我们连接
领英:https://www.linkedin.com/in/jimit105/
GitHub:https://github.com/jimit105
推特:https://twitter.com/jimit105
为数据分析任务查找数据集的有用站点
汇编一些有用的网站,提供免费和公开的数据集
作者图片
开放数据推动创新。它使人们能够将更多的精力放在研究上,而不是既费时又费钱的数据收集上。
在系列— 为数据分析任务获取数据集中,我们将探讨从互联网访问数据集的方法。在 f 的第一部分,我们学会了简化谷歌搜索,只在网络上查找特定的文件。
在数据科学过程中,数据的重要性怎么强调都不为过。数据分析任务的结果是…
parulpandey.com](https://parulpandey.com/2020/08/09/getting-datasets-for-data-analysis-tasks - advanced-google-search/)
在这一部分中,让我们看看一些站点,这些站点托管着可用于数据分析任务的免费且公开可用的数据集。一些资源在数据科学社区中非常有名,如 Data.gov 的 UCI 机器学习库、 Kaggle 数据集和T9。因此,我不会在这篇文章中触及它们。相反,本文的重点将放在一些鲜为人知的数据集聚合站点上。
这篇文章是寻找好数据集的完整系列文章的一部分。以下是该系列中包含的所有文章:
第 1 部分 : 为数据分析任务获取数据集—高级谷歌搜索
第 2 部分 : 为数据分析任务寻找数据集的有用站点
第三部分 : 为深度学习项目创建定制图像数据集
第 4 部分 : 毫不费力地将 HTML 表格导入 Google Sheets
第 5 部分 : 使用 Camelot,从 pdf 中提取表格数据变得很容易。
第六部分 : 从 XML 文件中提取信息到熊猫数据框架
第 7 部分 : 5 个真实世界的数据集,用于磨练您的探索性数据分析技能
数据公平吗?
公开数据对于研究团体和整个社会的利益至关重要。然而,共享的数据应该遵循一些基本的准则,这样它才能得到最大的利用。在“科学数据管理和监管的公平指导原则”中, Wilkinson 等人制定了数据管理和数据共享的原则。FAIR 是一个首字母缩写词,代表可查找、可访问、可互操作和可重用的数据。
现在,让我们来看看一些有用的网站,它们可以快速、轻松地找到公开的数据集。
1.谷歌数据集搜索
谷歌数据集搜索页面截图(图片由作者提供)
谷歌数据集搜索是一个致力于寻找数据集的搜索引擎。它是一个搜索引擎,搜索来自数据提供商的元数据。这意味着它对数据集的描述而不是其内容进行索引。因此,如果一个数据集是公开的,它很有可能会出现在谷歌数据集搜索中。在发布时,数据集搜索拥有来自全球的近 2500 万个不同的数据集。谷歌数据集搜索依赖于关键字搜索,像常规的谷歌搜索一样,在这个网站上寻找数据集时提供了一个简洁的自动完成选项。
查询“教育”的一些搜索结果(图片作者提供)
谷歌数据集搜索演示
如果你想让你自己的数据集在谷歌数据集搜索中被发现,确保你在自己的网页上使用一个开放标准(schema.org)来描述你的数据集的属性。
因此,如果您的网站上有一个数据集,并且您使用开放标准 schema.org 来描述它,其他人可以在数据集搜索中找到它。
🔗链接到网站:【https://datasetsearch.research.google.com/】T4
2.OpenML
OpenML ((图片由作者提供)
OpenML 是一个开放的数据科学平台,旨在使机器学习研究民主化。它提供了从医疗保健到教育到气候变化等各种领域的大量数据。
该网站上的每个数据集都有一个专门的网页,数据可以以多种格式下载,如 CSV、JSON、XML 等。OpenML 还可以用来建立机器学习模型,然后这些模型可以上传到网上,以便其他人可以使用它们。
openml.org 输血服务中心数据集 ( (图片由作者提供)
OpenML 数据集搜索演示
OpenML 本质上是为协作数据科学而设计的,人们可以共享他们的代码和结果。
🔗链接到数据集:https://www.openml.org/search?type=data
3.五三八
fivethirtyeight.com 上的开放数据集(图片由作者提供)
T21 是一个提供互动文章的网站。它展示了一些由有趣的精选数据集支持的令人信服的分析故事。这些数据集已经通过他们的 Github 库向公众开放。任何人都可以使用这些数据集,对从政治到体育的话题进行分析。
fivethirtyeight.com 数据仓库((图片由作者提供)
五个三十八个数据集演示
他们网站上一些有趣的数据集包括:
航空安全数据集——故事背后的数据旅行者应该避免乘坐过去发生过空难的航空公司吗?
复仇者联盟——故事背后的数据加入复仇者联盟就像从四层楼上跳下来一样致命。
🔗链接到数据集:https://github.com/fivethirtyeight/data
4.Github 上令人敬畏的公共数据集
令人敬畏的公共数据集存储库((图片由作者提供)
“ awesome public datasets ”是一个 GitHub 存储库,包含一些高质量的公共数据集,这些数据集已经按照行业进行了很好的分离。知识库提到——
这是一个高质量的以主题为中心的公共数据源 的列表。它们是从博客、回答和用户回复中收集和整理的。下面列出的大多数数据集都是免费的;然而,有些不是。
下面是对存储库中可用数据集的一些类别的快速浏览:
awesome 公共数据集存储库中的可用数据集类别(图片由作者提供)
精彩的公共数据集演示
🔗链接到数据集【https://github.com/awesomedata/awesome-public-datasets :
5.BuzzFeed 新闻
https://www.buzzfeednews.com/((图片由作者提供)
BuzzFeed 新闻 是美国新闻网站由 BuzzFeed、美国互联网 媒体出版,新闻娱乐公司。BuzzFeed News 以故事为特色,它在 Github 上开源了这些故事的数据、分析、库、工具和指南。
BuzzFeedNews’资源库包含 开源数据、分析、库、工具和指南 ( (图片由作者提供)
BuzzFeed 新闻数据集演示
你可以找到一些有趣的数据集,例如:
🔗链接到数据集:https://github.com/BuzzFeedNews/everything
结论
这些是一些托管开放数据集的数据聚合网站。这绝不是一个详尽的列表,但这是我最喜欢的一些。如果你正在寻找一些机器学习项目,我希望这些网站将被证明是非常有益的。
无用的机器学习
通过解决信任时刻来设计有用的 ML
Aserusainhuu 在 Unsplash 上拍摄的照片
TL;许多 ML 应用在理论上是有用的,但在实践中却变得毫无用处。让我们来看一个真实的案例研究,强调两种类型的偏见,以及理解信任时刻如何有助于一个具体的例子。最后,我留给你 3 个小行动来考虑。
喜欢读什么? 跟我上 中 , 领英 , 推特 。你想学习如何沟通,成为一名有影响力的数据科学家吗?查看我的《 用机器学习影响 》指南。
故事
我的 内心声音:“她是不是有外遇了?她一定是。操我!”你不能责怪我有这样的想法,当你美丽的妻子突然花了这么多晚上不在家——她从来没有工作这么多。
于是,我问:“怎么回事?你最近怎么看起来这么忙?一切都好吗?”
杰斯:“我不知道你们这些家伙为什么一直做这些 没用的 AI 东西 ,再来一次!他们不断让我们做更多的工作。”我完全没想到会这样。又哎哟。作为一个有爱心的丈夫,正确的做法是给她一个拥抱,并承担额外的家务(是的,我做了。)
更重要的是,我需要倾听——嗯,为了满足我自私的好奇心,为了追求更好的工作,为了我们 ML 社区的进步。
于是,我试探:“多告诉我一些。发生了什么事?为什么这么说?”
两种类型的偏见&一个不同的问题
J ess 继续:“我们得到了这个新的下一个最佳动作应用(一个 ML 应用)。每周,它都会给我们一份客户名单,列出要联系的客户和要提供的产品。真是该死的 没用的 。 我看看名单;我和大多数顾客一起工作;我知道他们不会买这个产品…这是浪费时间,但我们仍然必须这样做,让我们的 KPI 看起来很好。
Jess 刚刚描述了每个 ML 应用程序都面临的两个独特问题。让我们打开包装:
1。机器偏差。机器是错误的;我们人类是对的。机器学习模型不是也不可能是完美的——即使我们希望并认为它们是完美的。当我们进行日常工作时,人类会看到大量的数据,并随后将其内化为直觉和知识;但是这种数据可能无法在数据库中正确收集或表示。因此,机器无法进行全面分析,并利用它做出更好的预测。
2。人为偏见。机器是对的;我们错了。人类受到过度自信偏见的影响。换句话说,我们通常高估了我们预测的准确性,尤其是在我们的专业领域。也许,机器实际上比我们知道更多最新的信息;所以它能产生更好的预测。但是我们更相信自己而不是机器。
ML 社区中的许多人可能会立即问:我们如何修复机器(例如模型)?公司正在雇佣更好的数据科学人才,实施更严格的 ML Ops 实践,并升级到更好的工具。但是,这样做只能解决机器偏差问题。链条的强度取决于最薄弱的一环:ML 应用程序的用户。
我们无法消除天生的人类偏见,但我们可以 为信任 而设计。 有了信任,用户更愿意与机器协作。那么,我们如何培养用户和 ML 应用之间的信任? — 这才是我们应该反过来问的问题。
让我们看一个具体的例子,讨论我们如何利用信任时刻分析和简单的 UX 技术进行信任设计。
信任的时刻
注意: 下面这个例子的灵感来自于杰西的一线工作,她需要亲自为客户服务。虽然它关注的是一个用例, 但是这些原则适用于许多流程 ,在这些流程中,人们需要从 ML 应用中获取信息并决定如何行动。
为了更清楚、更具体地了解这些问题,首先,我们应该看看信任时刻——人类需要根据他们对机器的信任做出判断的瞬间。我们可以通过使用用户旅程分析来突出这些时刻。
想象一下,当你去一家银行的分支机构会见一名顾问时,这是一个从顾问的角度来看的典型旅程——ML 应用程序的用户:
信任时刻分析,作者的经验
理解信任的时刻有助于我们找到用户可能与来自 ML 系统的预测斗争时的具体压力点。让我们解开每个信任时刻暴露出的问题。
更深层次的问题和解决方案
信任时刻#1 :让我们看看第 4 步。这是用户看到预测,理解预测的含义,并决定是否应该和如何行动的时刻。
问题: 用户没有按照预测行动。通常,用户会看到提供什么或做什么的简单描述(见左图)。当用户需要决定是否要跟随时,他们要么盲目相信,要么倾向于他们当时的判断。鉴于我们的过度自信偏见,我们倾向于选择后者。
换句话说,许多预测——那些数据科学家花费心血创造的预测——从未真正“进入市场”;它们只是在用户的屏幕上闪现,然后消失。
这导致了另外两个问题。首先,由于错误的原因,用户-机器交互将在数据库中被捕获为“失败”。机器认为交互失败是因为数学错误;但实际上,它失败了,因为用户没有采取行动或做得不对。第二,当机器学习时,它们学习了错误的现实。这被称为反馈回路问题(我们将在下面讨论)。结果,它造成了产生不合理预测的恶性循环,并最终破坏了用户的信任。
这些都不是预测问题。它们是 UX 的问题。
目标:这一步的主要目标应该有两个方面:1)提高采取行动的百分比;2)提高行动的质量。
解决方案:考虑到这一点,我建议将断章取义的建议替换为 a 上下文提示。上下文提示应使用人类可读语言(左图)突出显示执行 ML 预测的“为什么”、“什么”和“如何”。根据算法的类型,有各种方法将机器决策翻译成人类可读的语言。
步骤 4 —提出建议:问题(左)和解决方法(右);作者的分析和经验
信任时刻#2 :让我们看看用户共享笔记的步骤 7。
问题: 用户无法提供良好的反馈。通常,该界面允许用户跟踪他们的进度并与其他成员协调;然而,它通常不是为获取 ML 应用的反馈而设计的(用户也没有这样做的动机)。如前所述,一个中断或不良的反馈回路会给 ML 模型从错误中学习带来问题。就像人类一样,好的反馈让我们学得更好更快。
目标:在这一步,主要目标是鼓励用户为自己和机器分享更好的反馈。
解决方案:最简单的解决方案是使用大多数人熟悉的 UI 元素;这些 UI 元素可以帮助标准化输入,并缩短输入信息的时间。
第 7 步—收集反馈:问题(左)和解决方法(右);作者的分析和经验
除了提供捕捉反馈的 UX,ML 应用还可以分享它如何使用反馈来改善未来的预测。这可以为用户创造参与感和回报。
注:所有截图均为保密清理。它们代表来自具有相似应用程序的组织的公共元素。
一步一步来
事实上,“无用的 ML 体验”是一个反复出现的主题。Jess 和我在不同的场合遇到了类似的问题。正如我在人工智能的最后一英里问题中所描述的,这归结为人与人工智能协作的脱节。解决这一问题需要一种综合方法来解决三个方面的问题。
如果我们不解决这个问题会发生什么?如果我们不解决信任问题,所有人都会不高兴。像杰斯这样的用户会不停地抱怨“人工智能的东西”有多没用,不会因为自我偏见而从令人惊叹的技术中受益;数据科学家可能会丢掉工作,因为模型的真实结果永远不会与一厢情愿的估计相符;商业永远不会实现人工智能的承诺价值;最重要的是,我将不得不继续听 Jess,我在数据科学领域的朋友,以及我的客户互相抱怨。
我们需要采取许多步骤来构建有用的 ML 应用程序。为信任而设计是伟大而简单的第一步。现在就采取行动。
建议的行动:
- 在你的公司中确定一个面向用户的 ML 用例
- 将用户旅程和信任时刻分析融入您的 ML 设计工作流程
- 与来自数据科学、工程和用户组(例如前线)的代表一起主持基于信任时刻的协作设计会议。
结论
许多 ML 应用被用户认为是无用的,不是因为预测的准确性,而是因为人类的偏见。作为 ML 应用程序的设计者和开发者,我们有责任为信任而设计。
解决方案通常很简单。通过识别信任时刻,我们可以设计有效的 UX 来提供更多上下文预测并关闭反馈循环,从而实现持续改进。
事实上,我们,人类和机器都是不完美的。为信任而设计提供了超越快速修复的东西——它为人类和机器建立了一座桥梁,以校准我们的信任并共同改进。
喜欢你读到的东西或者有什么疑问吗? 平我上 中领英推特 。你想学习如何沟通,成为一名有影响力的数据科学家吗?查看我的“ 影响与机器学习 ”指南。**
如果你喜欢这篇文章,你可能也会喜欢这些:
每个懒惰的全栈数据科学家都应该使用的 5 套工具
towardsdatascience.com](/the-most-useful-ml-tools-2020-e41b54061c58) [## 被遗忘的算法
用 Streamlit 探索蒙特卡罗模拟
towardsdatascience.com](/how-to-design-monte-carlo-simulation-138e9214910a) [## 数据科学很无聊
我如何应对部署机器学习的无聊日子
towardsdatascience.com](/data-science-is-boring-1d43473e353e) [## 12 小时 ML 挑战
如何使用 Streamlit 和 DevOps 工具构建和部署 ML 应用程序
towardsdatascience.com](/build-full-stack-ml-12-hours-50c310fedd51) [## ML 和敏捷注定的联姻
如何不对 ML 项目应用敏捷
towardsdatascience.com](/a-doomed-marriage-of-ml-and-agile-b91b95b37e35) [## 人工智能的最后一英里问题
如何培养人类和人工智能之间的信任
towardsdatascience.com](/fixing-the-last-mile-problems-of-deploying-ai-systems-in-the-real-world-4f1aab0ea10) [## 又一个 AI 冬天?
如何部署更多的 ML 解决方案——五种策略
towardsdatascience.com](/the-last-defense-against-another-ai-winter-c589b48c561)
参考
控制&人工智能时代的简约——【https://design.google/library/control-and-simplicity/】T2
AI &设计:以人为本—https://Design . Google/library/AI-Design-round table-discussion/
以人为中心的机器学习—https://medium . com/Google-design/Human-Centered-Machine-Learning-a770d 10562 CD
建立人与机器之间的信任—https://robotics . MIT . edu/Building-better-Trust-better-human-and-Machines
人机之间的信任,以及决策辅助工具的设计——https://www . science direct . com/science/article/ABS/pii/s 0020737387800135**
红移中的用户定义函数
红移中用户定义函数的快速入门
亚马逊红移是一个云数据仓库,有自己的红移 SQL 方言(PostgreSQL 的变种)。由于其低成本和与其他亚马逊网络服务的兼容性,这项服务变得越来越受欢迎。我最喜欢的红移集成是能够从 S3 卸载数据和拷贝数据。
在本文中,我们将重点介绍 用户自定义函数 (UDFs) 。
什么是用户定义函数?
UDF 是可以从红移数据仓库定制和创建的标量函数。每个函数可以接受固定数量的参数来返回一个单个输出。UDF 可以像内置的红移函数一样执行,比如replace
或lower
。
命名规格
亚马逊推荐所有 UDF 名字都以f_
开头。例如,用于计算两个日期之间的营业天数的 UDF 可以命名为f_calculate_business_days
。这将防止 UDF 名字和新红移函数之间的冲突——f_
前缀是专门为 UDF 保留的。
UDF 语言
可以使用 SQL select
语句或 Python 函数创建 UDF。用 SQL 编写的 UDF 性能更高,但是 Python UDFs 具有内置库的优势。除了 Python 标准库之外,Python UDFs 还支持 pandas、scipy、numpy 等函数。还有一个选项,通过从保存在 S3 的代码创建一个库来导入额外的 Python 库。
创造一个 UDF
所有的 UDF 都是使用CREATE FUNCTION
命令创建的。或者,我们可以使用CREATE OR REPLACE FUNCTION
来更新现有的 UDF。
任何 UDF 最多只能有 32 个参数。
SQL UDF
这是 SQL UDF 的结构:
create function f_sql_udf ([arg1 data type], ...)
returns [return data type]
stable as $$ select ...$$ language sql;
UDF 体由一个选择语句组成。SQL UDF 中的参数不能命名。它们必须被引用(按照它们被定义的顺序)为$1、$2 等等。参数可以采用任何红移数据类型。
蟒蛇 UDF
这是 Python UDF 的结构:
create function f_python_udf (arg_name [arg1 data type], ...) returns [return data type]
stable as $$ [Python code here]$$ language plpythonu;
与 SQL UDFs 不同,Python UDFs 需要参数名。已安装的库也可以作为 Python 代码的一部分导入。参考本页了解支持的 Python UDF 数据类型。
UDF 和用法示例
考虑一个非常简单的 UDF 清洗字符串。我们希望这个 UDF 将输入转换成小写,并用空格替换下划线。虽然这些清理步骤可以内置到 SQL 查询本身中,但是我们也可以使用 UDF 来使查询更加一致和易读。
结构化查询语言
create function f_clean_text (varchar)
returns varchar
stable as $$select replace(lower($1), '_', ' ')$$ language sql;
计算机编程语言
create function f_clean_text (text varchar)
returns varchar
stable as $$return text.lower().replace('_', ' ')$$ language plpythonu;
使用
我们可以用这个语句来测试我们的新 UDF。
select f_clean_text('eRROR_BAD_input')
我们可以将这个 UDF 应用于一个名为error_messages
的列
select f_clean_text(error_messages) from schema.table
多方面的
- 要查看用于创建现有 UDF 的代码,请查询
pg_proc
表 - UDF 支持 Python 日志库,这允许我们在 UDF 中记录警告和错误
- 数据库管理员可以使用 GRANT 和 REVOKE 来自定义 UDF 特权
- 要删除 UDF,运行
drop function udf_name(arguments)
这是一个练习和应用 SQL 的 Coursera 课程。
IBM 是通过开放的混合云平台和人工智能进行业务转型的全球领导者,为客户提供…
click.linksynergy.com](https://click.linksynergy.com/link?id=J2RDo*Rlzkk&offerid=759505.17916350380&type=2&murl=https%3A%2F%2Fwww.coursera.org%2Fspecializations%2Fdata-science-fundamentals-python-sql)
感谢您的阅读!
如果你喜欢这篇文章,可以考虑给我买杯咖啡——每一点小小的贡献都帮助我找到更多的时间在这个博客上工作。通过 Medium 关注我的最新更新。😃
作为一个业余爱好项目,我还在www.dscrashcourse.com建立了一套全面的免费数据科学课程和练习题。
再次感谢您的阅读!📕
数据科学的用户界面
首次迭代用户界面。原摄影师不详(来自 Pinterest Carharrt Moodboard,转自 lanecountyhistoricalsociety.org)
许多模型会因为实现不佳的用户界面而失望。理解界面需求就是问用户正确的问题。
与此同时,当你考虑到数据科学家制作的许多模型属于可重复的不同类别时,如时间序列、分类或聚类,构建一个用户界面不应该是可怕的,也不应该要求你为每个项目从头开始重新发明轮子。
要开发一个有用的问题列表,您需要考虑大多数业务用户中常见的驱动因素。虽然它们明显不同,但它们都属于一些明确的重要类别。
- 决策的价值是什么——在一些图像分类器或推荐器中,价值可能在一美元以下,如果涉及重大购买决策,价值可能高达数百万美元。
- 是否存在不利风险——也就是说,给出错误结果的模型是否会受到惩罚,或者您是否无法从正确答案中获益?如果营销成本非常低,并且所有群体都有可能获得某种提升,一些营销模式可能属于第二类(你可以通过更好的针对性获得更好的提升)。
- 模型多久运行一次?推荐器或图像分类器可能每秒运行一次,但是像前面提到的预测模型可能每月运行一次,甚至更少。
- 将如何使用模型输出—它是关于用户业务决策的最终答案,还是用于另一种计算(例如,考虑一个预测销售需求的模型,该模型用于决定生产中使用的原材料的订单数量,或用于决定人员配备水平)?
前两点强调了模型的风险,这反过来将决定企业需要投入多少精力来检查结果。尽管他们不太可能想要费力地通过模型上的详细统计诊断,但是对于高风险决策,他们很有可能想要投入资源来理解输入,这将通知 UI。例如,如果一个经济指数被用作需求预测模型的输入,他们可能既想看到价值,又想看到影响该指数的重要因素。
频率也决定了检查模型输入需要多少时间。显然,如果模型每秒运行一次,没有人会查看输入,但是如果一个月做一次决定,几个人可能会花几个小时仔细检查输入。在前一种情况下,模型输出可能就足够了,在后一种情况下,用户可能想要一个显示所有输入的报告和每个输入的审计跟踪(数据源和上次刷新日期)。
最后,输出的使用方式应该是数据呈现方式的一个关键决定因素。这里要考虑的一个关键问题是,模型输出是否可以“原样”使用,或者用户是否会在做出商业决策之前进一步操作它。如果用户想更多地操作它,在他们使用的平台中向他们提供输出是有意义的。例如,如果他们有一个预先存在的 Excel 电子表格,用于根据销售需求计算原材料订单数量,则以 Excel 表格的形式提供输出,他们可以将其放入自己的 Excel 工作簿中,以便在公式中引用您的模型输出。
在制作 POC 模型的常用范例中,尝试获得认可,然后才开始实施工作,这些问题可以留到最后解决。但是,没有真正的理由不在流程早期询问他们,这意味着您可以将您的 POC 展示为接近客户期望的最终实施。
如果你能尽早获得用户界面,这将比 AUC 再提高 1%更快更容易赢得客户。
面向笑话推荐的用户-用户协同过滤
使用 python 演示基于用户相似性的推荐系统
来源:作者照片
你家里有过蚂蚁吗?如果你有过,你可能知道蚂蚁最初是单独散开寻找食物的。但是一旦其中一只蚂蚁找到食物,它就会返回巢穴,留下气味,其他蚂蚁很快就会跟着走。然后你会看到一群蚂蚁在食物源和巢穴之间来回穿梭。这些蚂蚁展示了社交导航,这是一种推荐系统,每只蚂蚁都出去探索空间的不同部分,确切地说是空间,当它们发现它们认为社区会喜欢的东西时,它们会让每个人都知道。
推荐系统是当今世界的重要组成部分。顾客可能会看到很多可供选择的商品,却不知道该买什么。他们可能不知道一个服务于他们目的的产品,或者一部他们最终会喜欢的电影、一首歌或者一个笑话,但是他们还没有听说过。这就是使用推荐系统的原因。他们向客户提出具体建议,以克服上述问题。它们可以基于项目的内容(基于内容的推荐)、基于用户的会话活动(顺序的或基于会话的推荐)、基于相似用户喜欢的项目(用户-用户协同过滤)、或者基于与客户先前喜欢的项目的相似性(项目-项目协同过滤),或者可以是两个或更多上述系统的混合模型。
在本文中,我们将关注基于相似用户的推荐系统,也称为用户-用户协同过滤,并将其应用于笑话推荐。
资料组
笑话数据集取自加州大学伯克利分校自动化科学与工程实验室 旗舰项目Jester 研究项目的数据集 1。它拥有来自 73,421 名读者的 100 个笑话的评分。评级是范围从-10.00 到+10.00 的真实值(值“99”对应于“空值”=“未评级”)。在 73,421 名读者中,14,116 人对所有 100 个笑话进行了评级,其余 59,305 人对至少 15 个或以上的笑话进行了评级。
算法
我们将实现用户-用户协同过滤方法,向活跃用户推荐笑话。这种方法依赖于这样的想法:到目前为止具有相似评级行为的用户,分享相同的品味,并且很可能在未来表现出相似的评级行为。
来源:图片由作者提供。左图描述了基于用户的协同过滤方法,而右图描述了基于内容的推荐方法。
换句话说,用户-用户协同过滤是一种算法框架,其中基于与活动用户的相似性来识别相邻用户,然后基于相邻用户的评级来对项目评分,随后由推荐系统推荐基于项目的项目分数。亚马逊、Spotify、脸书、LinkedIn、谷歌新闻、网飞等公司是最受欢迎的使用某种形式的用户-用户协作过滤的公司。亚马逊的“ 买了这件商品的顾客也买了 ”就是这种滤镜的一个流行例子,如下图截图所示:
来源:图片由作者提供。亚马逊实现用户-用户协同过滤
推荐算法可以总结为 5 个步骤。
来源:作者图片
然而,这些步骤中的每一步都有各种各样的配置点,有助于选择设置用户-用户协作过滤。
让我们深入细节,看看每个步骤的各种配置点。
数据归一化
评级受个人规模的影响很大。一些人在评级时心地善良,倾向于给予高评级,而另一些人只是冷漠,倾向于对好内容给予中等评级。标准化是一种补偿这种用户行为的方法,它通过调整评级尺度使其与其他用户的评级相当或处于同一水平。
标准化评级的一个简单技术是从每个用户的评级中减去他们的平均评级。
下面是规范化的 python 实现。
def normalization(dataframe):
dataframe_mean = dataframe.mean(axis=1)
return dataframe.subtract(dataframe_mean, axis = 'rows')
让我们为笑话数据集实现这个方法。出于演示目的,我们将选择 10 个用户对前 10 个笑话的评级。
来源:作者图片
我们还可以在标准化步骤实现其他配置。
Z-score 是标准化评分数据的另一种可能方式,其中标准化值表示我们的分数与平均值的标准偏差。
计算相似度
用户间的相似度计算是协同过滤算法的主要任务。用户之间的相似度(也称为用户之间的距离)是一种数学方法,用于量化用户之间的差异或相似程度。对于用户-用户 CF 算法,首先计算评价了相同项目的用户 x 和 y 之间的相似性, sim ₓᵧ。为了计算这种相似性,使用了不同的度量。我们将使用基于相关性的相似性度量来计算用户 x 和用户 y、 sim ₓᵧ之间的相似性,使用皮尔森相关性
皮尔逊相关的选择是有意义的,因为每个用户的评级数据的相似性度量往往是正态分布的。像其他相关系数一样,这个系数在-1 和+1 之间变化,0 表示没有相关性。-1 或+1 的相关性意味着精确的线性关系。用户 x 和用户 y 之间的正相关意味着,如果用户 x 将一个笑话评价为正面的,那么用户 y 也将很有可能对同一笑话进行正面评价。
下面是使用 scipy 包的 Pearson 关联的 python 实现。
def similarity_pearson(x, y):
import scipy.stats
return scipy.stats.pearsonr(x, y)[0]
现在,我们实现上述方法来为评级数据集寻找皮尔逊相似性。请注意,这里我们使用评分数据集而不是标准化评分数据集来评估相似性,因为皮尔逊相关方法负责标准化步骤!
来源:作者图片
我们还可以在相似性计算步骤实现其他配置。
余弦相似度是通过计算两个评价向量之间的角度的余弦并确定两个向量是否指向大致相同的方向来计算两个用户之间的相似度的另一种可能的配置。余弦相似度是文本分析中常用的一种度量文档相似度的方法。
选择邻居
用户-用户协同过滤(UUCF)方法严重依赖于活跃的用户邻居信息来进行预测和推荐。邻域选择可以对活跃用户产生或破坏推荐,并且可以对评级预测和项目推荐有直接影响。
目前,任何商业推荐系统都有大量的用户,因此如果推荐系统想要保证可接受的响应时间,邻域必须由用户的子集组成。
下图显示了选择邻域的四种传统方法。
来源:作者图片
- 当数据集非常小时,使用所有数据集
- 当相似性分数高于特定阈值时选择数据集
- 通过相似性得分选择前 N 个数据集
- 使用 K-Mean 等聚类方法选择一个相似的聚类
我们将使用阈值方法为活跃用户选择邻居。让我们将索引为 2 的用户指定为活动用户。
作者图片
活跃用户只阅读了 10 个笑话中的 4 个,所以我们将找出剩余 6 个笑话中的哪个笑话将是对活跃用户的最佳推荐。
让我们选择 0.1 或更高的阈值来过滤掉邻居。
下面是使用阈值方法查找相似邻居的 python 实现。这里“ sim ”暗示为熊猫系列类型的相似性数组。
def neighbours(sim):
return [sim.index[i] for i, v in enumerate(sim) if v>=0.1]
这是我们的活跃用户的相似性数组的截图。请确保在工作前删除活动用户自身的相似性。
来源:作者图片
我们将为相似性数组实现“ 邻居 ”方法。
作者图片
从上面的截图可以明显看出,这里只有索引为 3、4、6、9 的用户才有资格成为邻居。
但是在任何有大量数据的商业推荐系统中,如果我们使用阈值方法,我们可能会有大量的邻居。所以问题来了,有多少邻居?
理论上讲,越多越好,如果我们有一个好的相似度矩阵。但是实际上,来自不同邻居的噪声降低了有用性。如果我们混合了许多低相似度的邻居,那么来自目标用户的差异会开始降低推荐的质量。在 25-100 之间,高相似度邻居经常用于实际和商业推荐系统中。
评分项目
使用邻居评级对项目进行评分是制作协作过滤模型的核心。加权平均是构建这种评分系统最常用的方法之一。我们将使用加权平均来计算我们的项目得分。
第一步是只选择那些还没有被活动用户评级的项目
作者图片
在我们的例子中,它是笑话 1、笑话 2、笑话 3、笑话 4、笑话 9 和笑话 10。由于其余四个笑话已经分级,我们不会对这些项目进行评分。
下面是邻居评级和邻居相似度熊猫数据框架的屏幕截图。我们将这两个数据帧和评级数据帧创建每个笑话的分数。请注意,这里我们使用标准化评级数据帧来查找 neighbor_rating。
来源:作者图片
下面是计算项目得分的 python 实现。
def score_item(neighbor_rating, neighbor_similarity, ratings ):
# aumr -> active user mean rating
aumr = np.mean(ratings.iloc[2, :])
score = np.dot(neighbor_similarity, neighbor_rating) + aumr
data = score.reshape(1, len(score))
columns = neighbor_rating.columns
return pd.DataFrame(data = data , columns = columns)
我们将实现“score_item”方法来查找所有笑话的分数。
来源:作者图片
在这里,可以清楚地看到,笑话 2 的得分最高,笑话 4 的得分最低。
物品选择
一旦决定了项目评分,得分最高的项目将是最佳推荐。因此,在我们的案例中, joke_2 将是最适合我们活跃用户的推荐。
向我们的活跃用户推荐笑话 2
然而,通过使用这种方法,推荐很有可能每次只饱和到几个推荐。这可能导致推荐质量下降。
这个问题的一个简单的解决方案是取前 n 个得分高的项目,并随机推荐其中的一个。
用户-用户协同过滤的陷阱
用户-用户协同过滤系统在过去已经非常成功,但是它们的广泛使用已经暴露了一些真正的挑战。让我们简单讨论一下使用这样一个系统的四个关键挑战:
冷启动:
如果用户是新用户,则不能计算其与其他用户的相似性,因为系统可能没有关于该新用户的任何形式的数据。
可扩展性:
随着用户或项目的数量开始增加,用户-用户协同过滤由于相似性计算的增长而遭受性能下降。
数据稀疏:
对于大的项目集、少量的评级,经常存在不能为用户做出适当推荐的情况。
影响:
一个组织或个人可以通过创建多个公民帐户并设置虚假评级来故意操纵为他人做出的预测。
结论
用户-用户协同过滤方法是最常用和研究最多的推荐技术,已经被整个行业广泛采用。这种方法背后的核心概念是“相似的用户往往有相似的品味。”
在这篇博客中,我们介绍了 UUCF 方法及其在笑话推荐中的实际应用,使用了 5 个步骤。我们还展示了在每一步中各种配置点的可能性。
在这些步骤中,我们没有选择最好的结果,而是从可接受的选择中随机选择。这是推荐系统最大的讽刺,因为我们并不寻找最好的结果,一点随机性总是受到用户的欢迎,而且是必要的,否则整个体验会变得单调。
参考
- http://eigentaste.berkeley.edu/dataset/
- https://github.com/abbi163/Jester-Joke-Recommender-System
- 马尔瓦·侯塞因·穆罕默德、穆罕默德·赫尔米·哈法吉、穆罕默德·哈桑·易卜拉欣。“推荐系统挑战和解决方案调查”。2019 年 2 月 2 日至 4 日,埃及阿斯旺,2019 年 ITCE
- 张志鹏,工藤康夫和小川哲也·村井。“使用基于覆盖的粗糙集进行基于用户的协同过滤的邻居选择”。运筹学年鉴,2016 年 11 月 8 日
- 迪特马尔·詹纳赫、马库斯·赞克、亚历山大·费尔费林和格哈德·弗里德里希。“推荐系统,介绍”。剑桥大学出版社,2011 年
- Rounak Banik,“使用 Python 的实用推荐系统”。Packt 出版公司,2018 年
- Coursera。明尼苏达大学的“最近邻协同过滤”课程。第一周和第二周。
使用数字孪生进行装配线供应策略规划
物流强化学习实践介绍
人工智能、数字双胞胎、工业 4.0……这些流行语你可能听过。但是应用它们来解决实际问题不是很酷吗?
学习实际应用而不是抽象概念?
了解哪些挑战需要应对,哪些陷阱需要避免?
太好了,所以这篇文章是写给你的!
它会…
- 描述如何使用强化学习来解决生产物流问题
- 解释强化学习和工业数字双胞胎的基本概念
- 介绍一个关于装配线供应战略规划的深入案例研究
它将包含代码,准备在你的机器上执行。基于 Docker,无需进一步安装。
**免责声明:本文是业余工作的成果。它代表了我们对所讨论主题的个人观点。这是一份记录我们个人经历的报告,而不是一份纯粹的科学研究。内容、概念和它们的实现可能以几乎任何可以想象的方式得到改进。我们仍然希望你喜欢阅读。
概述
- 简短介绍强化学习、数字双胞胎以及如何在健身房环境中包装 DES 模型
- 案例研究描述和模拟模型
- 不同强化学习算法的训练和评估
简介和基础知识
强化学习代表了一种来自机器学习的新兴技术。它可以在动态环境中自主衍生复杂的动作序列,并成功应用于各个领域,例如机器人和游戏。我们可以只提供一个环境,而不是为一个问题明确定义一个具体的解决策略。一个自我学习的代理将通过互动自主地发现成功的策略。
不用说,这并不是什么新鲜事,之前的研究显示了使用 RL 解决生产物流问题的可行性。
那么,为什么我们认为有必要再写一篇关于这个话题的文章呢?
首先,在 RL 以及数字双胞胎在生产/物流中的应用方面有很多积极的发展。我们认为,整合这些概念的潜力甚至更大。本文试图展示一个基于工具栈的工作示例,该工具栈无缝集成了两个来自各自领域的最流行的开源软件包:stable-baselinesforRL和SimPyfor implementationDigital Twins。
强化学习
如果你还在问自己 RL 能做什么,我们绝对推荐看看open ai 的家伙们在做什么。
诚然,这可能是一个非常复杂和高度工程化的例子,但它可以分解为一个代理和一个环境之间的简单交互。从技术上讲,这种交互是由一个接口(或者 Python 喜欢称之为抽象基类)定义的,它是 gym-package 的一部分。
下图说明了代理和环境之间的信息交换。首先,代理调用环境的步骤方法,提供要执行的动作。然后,环境处理该动作并返回:
- 系统的新状态(观察),
- 该步骤中发生的奖励(可能为零),
- 潜在地指示一集结束的完成值(以及后续复位的需要)
- 和一个信息-对象(可能包含附加信息,例如用于记录目的)。
主体与体育环境的互动
界面还规定了更多,如动作空间和观察空间的格式,以及渲染和重置行为。
由稳定基线包提供的各种 RL 算法已经准备好与实现这个 gym 接口的环境一起工作。剩下要做的就是创建一个合规的环境,在下一节中,我们将展示如何在物流领域实现这一点。
数字双胞胎和离散事件模拟
坦率地说, Digital Twin 可能是所有“物流 4.0 /工业 4.0”中使用最频繁的术语。尽管我们忍不住把它放入标题中,但从现在开始,我们将证明我们可以做得更好,并使用更具体的术语“离散事件模拟”(DES)。
为什么是 DES?离散事件模拟是物流系统分析和设计的广泛工具之一。今天的应用已经超越了系统规划的传统用途。它们包括更多的操作用例,如虚拟调试或短期预测。模拟模型正在与其他 IT 系统紧密结合。这有助于提高过程透明度,改善我们实时分析、控制和优化系统性能的手段。这听起来不是很接近数字双胞胎的承诺吗?**
大多数工业模拟应用仍然基于商业软件包。
然而,有几个开源的替代方案,它们通常更接近于通用语言编程。尽管它们往往缺乏一些方便的商业特性,但也有一些优点,比如更好的可伸缩性和简化的接口。
与 Python 相关,我们开始意识到两个流行的 DES 包: Salabim 和 SimPy 。两者不仅是免费和开源的,甚至是建立在世界上最流行的编程语言之一的标准库之上——让我们看看我们能从中得到什么!
Casymda 套餐
基于 SimPy ,我们添加了一些补充功能,以获得一些商业“基于块”DES 包的建模便利。
便于使用 BPMN 过程描述生成相应的仿真模型 python 代码。用 Camunda-Modeler 可以很容易地创建 BPMN 文件(基本上是 xml)。
该图形建模有助于维护高级模型结构的概览。生成的 Casymda 模型还包括一个通用的、令牌式的模拟流程动画,即装即用,可以在 web 浏览器中运行。对于演示和调试,动画可以暂停,其速度可以动态改变。如果在没有可视化的情况下运行模拟,则不会安排仅与动画相关的事件。这最大限度地提高了执行速度——当需要大量运行时,这对于 RL 尤为重要。
Casymda 的其他功能包括在 2D 平铺地图空间中沿最短路径的模拟移动,以及为方便开发而进行的渐进输入(如果您使用的是 vscode ,请选择 pyright )。想了解更多关于 Casymda 的信息,请看这篇文章、回购或(德国)网站。
在健身房环境中包装 DES 模型
为了能够在一个仿真模型中训练一个 RL 代理,我们需要让这个模型实现上面描述的 Gym 接口。
下图说明了耦合概念:
体育环境与仿真模型的互动
当健身房环境的step
功能被调用时(1
,所提供的动作被传播到仿真模型的相关模块(1.1
)。这是在ActionHolder
的帮助下实现的,因此一个消费决策逻辑可以根据接收到的信息进行调度。
随后,执行仿真,直到仿真模型触发next_action_needed
事件(1.2
)。这表示当前步骤结束,需要代理执行另一个操作。
一个健身步骤因此可以包括任意数量的离散的简单步骤,每个步骤又可以花费任意数量的模拟时间。
奖励在RewardHolder
对象的帮助下进行管理,该对象在环境初始化期间被连接到仿真模型的相关模块中。在每一步结束时,收集已发生的奖励(1.3
)。根据要解决的优化问题的类型,可以应用对收集的奖励的后处理(例如,考虑经过的时间量,以便代理可以学习时间有效的行为)。
为了检查一集是否结束(返回信息的完成部分),对照配置的done_criteria
( 1.4
检查模型的当前状态。这些可以包含例如要达到的一些目标或者要模拟的一定量的时间。
为了给代理提供一个观察结果,一个特定于模型的ModelStateToObservationConverter
被用来从模型中收集相关信息。创建的观察符合定义的observation_space
( 1.5
)。该步骤可以包括例如计算不同队列中实体的数量,或者检查库存水平,并根据该信息创建 NumPy 数组。
最后,收集的信息返回给代理(2
),代理可以根据奖励进行学习,并决定下一步的行动。
有了基础知识,让我们看看如何让它工作。
案例研究
早在去年 8 月,在柏林举行的 MIM2019 上,我们有机会参加了一场有趣的谈话,两位巴伐利亚人展示了他们关于改善工厂内牛奶运行系统的研究。这些内部交付通常用于装配线供应,并且参观通常遵循非常严格的计划。鉴于生产线上的实际需求往往会发生变化,他们的研究揭示了减少交付周期和提高系统利用率的巨大潜力——只需使旅游规划更加动态。
基于这一设置,我们构建了一个抽象和简化版本的装配线以及相应的材料供应系统,为强化学习算法提供了一个平台。
方案
下图显示了系统的布局示意图:
装配线的布局
未完成的产品从右上(I
)进入系统,并在 9 个不同的工位依次组装,排列成 U 形(I-IX
)。成品在最后一个组装步骤后离开系统(IX
)。
在装配步骤开始之前,工作站要求在工作站的库存中存在一定数量的A
或B
类型的资源。
每个工位一次只能容纳一件产品,只有在下一个工位为空时,才能转发成品(因此,容纳已完成产品的多个上游工位可能会被仍在加工产品或在开始加工前等待材料的下游工位阻塞)。
材料由卷扬机提供,能够运送有限的离散量(“箱子”)。卷扬机可以在一个料架上装载材料(A
和/或B
,位于底部)。一次可装载/卸载 1 个离散单位的材料(“箱子”)。装配线的目标是实现最大的生产量,这也与产品的交付周期小相关。
假设:
- 材料只能在储料器(
A
和B
)处装载,每个储料器可容纳无限量的材料,因此卷扬机不会在装载现场等待材料 - 材料只能在实际需要这种类型材料的工位卸载(因此卷扬机不能在需要
B
装配的工位卸载一箱A
- 车站(
I-IX
)的库存容量是无限的,因此卷扬机从不在卸载现场等待(否则,当卷扬机无论移动到哪里都无法卸载材料时,可能会发生活锁)
60 秒的生产节拍意味着最大生产量为 1440 件产品/24 小时。每个工位每件产品的材料需求为 1.5 (A)和 0.5 (B),因此平均需求为 9.5/60 秒=大约。0.16/秒(单位每秒)。
从库存到系统中平均消费站的平均距离约为。811m(需求加权,因为更高的需求导致对相应车站的更频繁的巡视)。
10 米/秒的卷扬机速度、25 个单元的卷扬机容量和每批 5 个单元 5 秒的(卸载)时间导致卷扬机的周期时间约为。212 秒,平均交付速度约为。0.12 单位/秒。这是假设卷扬机“满载”,总是满载地从一个单一的库存移动到一个单一的站。
因此,卷扬机最多能达到理论上可能的产品吞吐量的 75%(0.12/s 的输送量对 0.16/s 的需求量)。因此,预期的最佳吞吐量应该约为 1080/24 小时。
正如我们所见,卷扬机的输送性能代表了系统的限制因素(瓶颈),这意味着这里的每一项改进都将直接反映在整体吞吐量的相应增加上。
为了简单起见,没有假设随机模型行为(例如随机分布的负载或移动时间),因此模拟模型将是确定性的。
如上所述:系统作为一个整体是相当抽象和简化的——但是仍然至少捕获了一些真实世界问题固有的基本复杂性。我们的 RL 代理能够…
- 掌握底层力学?
- 区分不同的产品类型?
- 发现需求和供给点?
- 如何应对卷扬机能力的极限?
- 达到最大可能的吞吐量?
我们会找到答案的,但让我们先看看学习环境会是什么样子。
仿真模型
系统的仿真模型基本上由两个过程组成,如下图所示。
模拟模型中的流程:产品装配(左)和材料供应(右)
在左侧,产品在离开系统之前通过 9 个组装步骤(ProductStation
,旋转 U 形),偶尔会被下游工位阻挡或在某个工位等待材料。
在右侧,卷扬机通过无限循环的移动和装载/卸载过程步骤(在位置A
由TuggerSource
初始创建之后):
- 选择下一个移动目标并完成移动(如果下一个目标等于当前位置,则没有实际移动)(
TuggerMovement
)。 - 根据当前位置(或者是库存
A
/B
)或者是ProductStation
),选择下一个卷扬机工艺步骤: TuggerStock A
装载一个单位的A
(如果卷扬机容量未达到)TuggerStock B
装载一个单位的B
(如果卷扬机容量未达到)TuggerStation
如果可能,卸载一个单位的A
或B
(装载工位所需的物料)
请注意,即使不成功的加载或卸载尝试也会占用很少的固定时间,因此每个可能的健身步骤都保证会占用至少一些模拟时间(并且一个有时间限制的情节也保证最终会到达其终点)。
下面你可以看到一个过程动画,以及一个贴图动画。这里的代理遵循一个明确定义的简单规则,即总是向库存水平最低的站点交付 25 个单位的完整负载。要运行动画,只需克隆 repo ,运行命令,然后访问 http://localhost:5000 。
流程动画:
*docker-compose up web-animation-lia-process*
模拟过程的动画
平铺地图动画:
*docker-compose up web-animation-lia*
2D 空间中的运动动画
准备健身房环境
TuggerEnv
实现了 Gym-Env 接口,并包装了用于 RL-agent 训练的模拟模型。它转发关于下一步移动卷扬机的决定(动作),它跟踪到达水槽的成品的收集奖励,并检查一集是否完成(即 24 小时/86400 秒的指定时间已过)。
Gym-Env 的render
方法没有实现,因为任意时刻的动画——每当 Gym-step 完成时——对于离散事件模拟环境没有多大意义。动画是单独控制的。step
的info
返回值被配置为返回finished_products
的号码,该号码可以被记录。
观察和行动空间
通过TuggerEnvModelStateConverter
对象从当前模型状态中提取特定于模型的观察值。
具体来说,观察值由以下描述系统当前状态的信息组成(总共 48 个值)。
ProductStation
-相关观测值(5 个值 x 9 个站= 45 个值):
- 当前库存水平(标准化,最多 10 件)
- **忙-状态(二进制)
- **等待材料-状态(二进制)
- **空-状态(二进制,产品是否存在)
- **被继任者封锁-状态(二进制)
TuggerEntity
观察值(3 个值 x 1 个卷扬机= 3 个值):
A
的装载数量(相对于容量)B
的装载数量(相对于容量)- 当前位置(索引)
请注意,站点观察的某些部分实际上是多余的(例如,既不是忙碌也不是等待也不是空闲的站点只能是阻塞* ) —背后的基本原理是智能算法将(有希望)了解观察的不同组成部分的重要性,这样我们就不必担心提供所有潜在有用的信息。*
action_space
(类型gym.spaces.Discrete
)由 11 个可能的移动目标(9 个站+ 2 个股票,由索引编码)组成。
奖励
如上所述,装配线的既定目标是实现最佳的产品吞吐量,这相当于在一集(24 小时)内生产尽可能多的产品。
我们如何实现这一目标?哪种激励适合刺激这种行为?众所周知,设计合适的奖励函数并不是一件小事。事实上,即使是对(可以说更聪明的)人类来说,奖励和激励的设计也是管理和教育中的一个主要问题(还记得上次你为了通过考试而学习,而不是实际学习有用的内容)。
对于手头的环境,我们可以考虑在每集结束时,根据在固定时间内(24 小时)完成的产品数量,按比例给予单一奖励,这可能会正确反映我们最大化生产量的目标。然而,最终的奖励将会非常少并因此大大降低学习速度(以随机行动的平均持续时间为例,在代理人看到任何奖励之前,每集将需要完成 1000 多个行动)。**
另一个想法是奖励每一个成功交付材料到任何站,这将有可能在 2 个步骤内完成(移动到库存和移动到一个合适的站消耗装载的材料)。通过这种方式,我们将获得更少的回报,但也有一个明显的可利用性问题,这是由这样一个事实引起的:仅将材料交付到一个工作站实际上根本不会导致任何产品的完成。
作为一种妥协,我们简单地决定,产品每完成最后一个组装步骤,奖励 1 英镑,这可能在 12 个步骤内完成(最少,不一定是最佳策略)。即使表现出随机行为,这将允许代理人在一集期间产生大约 50 英镑的奖励,因此有足够的“随机成功”样本可供学习。
这种奖励的一个问题来自于这样一个事实,即获得奖励所需的模拟时间并没有被奖励本身所反映。由于每个健身步骤实际上会消耗大量不同的模拟时间(从 5 秒到> 100 秒),因此对吞吐量有巨大的隐含影响,而代理并没有意识到这一点。为了解决这个问题,我们引入了“时间成本”,这意味着我们简单地给每一步一个小的负奖励,与经过的模拟时间成比例。这最终留给我们一个后续问题,即这些“成本”应该有多大。如果定得太高,他们会否决培训开始时为数不多的实际奖励。如果太低,将没有足够的刺激来展示时间效率的行为。同样,作为一个简单的妥协,我们实现了成本的成比例增长,并在一集结束时获得了迄今为止最高的奖励,这保证了一定的平衡,并奖励增加的时间效率。
我们设计的上述奖励肯定不是“完美的”,而且感觉有点像在“奖励工程”上投入了太多的精力——尽管如此,这是我们的代理有望使用的第一个解决方案。
RL-代理培训和评估
上述环境的特征在于一个离散动作空间和一个连续(框)观察空间。稳定基线文档列出了可用的 RL 算法及其兼容性。
由于动作空间的类型,一些算法不可行(如 DDPG、SAC 和 TD3)。
为了训练稳定基线 RL 算法,使用DummyVecEnv
和标准MlpPolicy
将TuggerEnv
矢量化。为了利用多个 CPU 进行训练,可能需要使用一个SubprocVecEnv
(但是对于更简单的日志记录&分析,我们在这里没有使用那个,相反,我们并行进行了多个独立的训练运行)。
培训一名 ACER 代理(默认情况下仅 10,000 步,需要<1min):
*docker-compose up acer-training*
Plot performance (might require additional setup for mounting the display):
*docker-compose up acer-plot-training*
Tile-map animation of the trained agent ( http://localhost:5000 ):
*docker-compose up acer-web-animation-tilemap*
下面我们可以看到一位宏碁代理接受了 100 万步的训练:
ACER-agent 训练有素的 100 万步动画(<1.5h of training)
如我们所见,该 agent 大部分时间都设法将 25 个单元完全装载到卷扬机上,似乎将正确的(A/B)工位作为材料卸载的目标,并且选择当前库存水平较低的工位似乎也是合理的!
但是整体表现如何呢?
性能比较
为了进行比较,我们用 1 和 3 mio 的标准设置训练了四种算法(ACER、ACKTR、DQN 和 PPO2)。(健身房)台阶。培训时间长达 2.5 小时(DQN,3 分钟。步骤),使用如上所述的单进程 DummyVecEnv 。
下图显示了每个算法在训练运行过程中每集(24 小时)生产的产品数量,以及确定性最低库存试探法的性能(黄线;总是向具有当前最低库存的站输送 25 个单位的完整负载),以及完全随机动作的平均性能(蓝绿色线,在 100 集上测量)。
不同 RL 算法的训练进度(成品/集,越高越好)
- 正如我们所看到的,所有的算法都成功地将每集生产的产品数量显著增加到随机行动所达到的水平之上(底部的青绿色线条),这表明成功的学习进度。
- 此外,没有一个经过训练的算法达到最低库存试探法的性能(顶部的黄线)。
- 最低库存启发式性能达到系统的估计最大可能吞吐量(估计大约为。1080/集)。因此,可以认为这种策略接近全局最优。
- 在训练期间,表现可能会完全崩溃。最突出的:宏碁 _3mio。(蓝线,第 260 集,完全没有恢复)。其他算法也显示性能下降,但似乎恢复得更好(例如 ack tr-green,PPO 2-pink)。
- 性能最好的 RL 算法(ACER 为 1mio 训练。步骤,橙色线)达到了 856 个产品/集的最大吞吐量(接近最佳试探法性能的 78%)。
每集的次数因每集健身步数(24 小时模拟时间)的不同而不同,取决于每个健身步所需的模拟时间。ACER_3mio 的小插曲。从第 260 集开始,每集高达 17277 步的体操步解释了训练。这一集的每一步只需要 5 秒钟(这是所有健身步骤中最短的可能时间,通过重复访问同一地点来实现)。这种行为可能是由每步定义的负奖励引起的,与该步所需的模拟时间成比例。显然,代理人不记得如何产生积极的回报,只是试图通过最小化步骤时间来最大化短期回报。显然,这种行为不会导致任何成功的交付,更不用说完成任何产品了。
值得一提的是,所有的训练运行都是使用默认算法设置完成的,并且强烈建议对不同的超参数进行评估以实现性能优化。因此,对于 RL 代理来说,朝着理论上可达到的最佳值缩小性能差距并不是不可能的。
总结
简而言之:我们最好的 RL 代理在我们的生产物流环境中达到了大约 78%的最佳性能。
好吧,这是好是坏?
嗯,我们的代理无法达到手工编码的启发式方法的性能,这可能会令人失望。
但是,当我们开始的时候,我们相信我们可以得到一段通用的代码来处理我们特定的、相当复杂的环境中的重要关系吗?肯定不是!
这只是第一次尝试——我们还没有开始超参数调整或替代奖励的评估。
你对强化学习的体验是什么样的?
你用 RL 解决了哪些物流问题?
您是否发现了代码中的错误,或者您是否想提出改进建议?
或者,您对当前的实施和工具堆栈有什么疑问吗?
欢迎给我们留言,感谢您的阅读!
弗拉基米尔·霍夫曼 — 克莱门斯·l·施瓦茨 — 弗雷德里克·布兰德
利用人工智能打击假新闻
探索机器学习和自然语言处理的用途,使识别假新闻的过程自动化
所进行的工作: 大卫·柯布迪杰森·卡茨迈克尔·哈德奈娜·沃顿**
乔纳森·斯威夫特在 1710 年写道:“谎言飞来飞去,真理一瘸一拐地跟在后面,当人们意识到真相时,已经太晚了。”今天,这句话似乎有先见之明,因为在我们生活的这个时代,只需点击一下鼠标,新闻就能在全球范围内迅速传播。在过去的几年里,假新闻呈指数增长,严重饱和了我们的信息来源,比以往任何时候都更让美国人困惑。2016 年皮尤民意调查显示,近三分之二的美国成年人认为假新闻对时事造成了“很大的混乱”。2018 年,一篇新颖的论文发表在《科学》杂志上,分析了 2006 年至 2017 年间约 300 万人发的 126,000 条谣言。这项研究的结果相当可怕,可以用下面这段话来概括:
**“大约 12.6 万条谣言被 300 万人传播。虚假的消息比真实的消息接触到更多的人;前 1%的虚假新闻扩散到 1000 到 100000 人之间,而真相很少扩散到 1000 人以上。”(科学)
假新闻不仅接触到更多的人,而且传播速度比真相快得多。换句话说,在 Twitter 上,假新闻主导着真相,其他社交媒体平台也可能如此。此外,从真实新闻中主动分拣假新闻的任务复杂而繁琐。有一些机器学习(ML)分类技术可以用来处理这个过程,但连续训练完整的模型是非常耗时的。区分假新闻和真新闻的过程可以分解成更小的步骤,通过自动化这些步骤,任务变得更容易消化。
2016 年,发布了一个带有标签数据的假新闻挑战,比赛的目标是建立一个立场检测的分类模型,这是一个确定新闻标题和正文之间关系或立场的任务。更准确的说,是标题讨论,无关,赞同,还是不赞同文章正文。建立姿态检测 ML 分类模型是创建人工智能管道以区分假新闻和真实新闻的第一步。因此,我们的目标是应对这一挑战,并使用自然语言处理建立一个深度神经网络,看看我们能否击败获胜模型的准确性。虽然这个比赛是在几年前进行的,但我们认为神经网络的最新发展和自然语言处理的进步使得建立姿势检测模型值得重新审视。
竞赛网站(链接如下)为参赛者提供了训练集和测试集,以及加权准确率为 79.53%的基线 GradientBoosting 分类器。前三名的准确率分别为 82.02%、81.97%和 81.72%。为了这次竞赛的目的,使用下面图 1 所示的模式对准确性进行了加权。准确性分为两级评分系统,因为将标题和正文分类为相关或不相关(占总分数的 25%)对检测假新闻的整体任务来说用处不大,而且更容易做到。将标题正文对分类为同意、不同意或讨论的第二个级别占准确度分数的 75%。我们将使用相同的指标来确定我们模型的整体准确性。在最初的比赛中,不允许竞争者通过添加更多的标记数据来扩充他们的数据。然而,如果可行的话,我们希望向我们的训练集添加更多的标记数据,以开发更鲁棒的模型。
图 1 —竞赛的评分结构
EDA:
构建更好的分类器的第一步是更好地理解数据(我们将两个不同的数据集合并在一起)。该数据集有三个特征:文章正文、标题和立场,有 49,972 个观察值。在四种不同的姿态中,不相关的标签占了大约 75%的数据或 36,545 个观察值(见图 2)。讨论标签妥协了 17.8% (8,8,909 obs。)的数据,其次是同意标签(7.3%)和不同意标签(1.68%)。
图 2 —站姿计数的条形图。这是一个不平衡的数据集。
鉴于我们的特性数量有限,我们决定使用一些常见的自然语言处理(nlp)技术来生成几个。就标题的特点而言,平均标题由 11.12 个单词组成。然而,正如我们在图 3 中看到的,有许多离群值,标题由多达 40 个单词组成,表明分布是右偏的。不出所料,正文中的单词数要多得多,平均为 368.83 个单词,同样是右偏的。
图 3 —标题字数的箱线图。标题字数的分布是右偏的。
当标题和字数特征按立场分面时,类别之间似乎没有显著差异(图 4 和图 5),但是,这并不意味着有一个模式。如前所述,数据并不代表同意和不同意标签(其盒图值略有不同),因此数据的缺乏可能会掩盖真实的差异。图 5 是正文字数与标题字数的标记散点图。令人惊讶的是,这两个特征之间似乎没有很强的相关性。
图 4-每种站姿的身体字数箱线图。不同站姿类别的分布没有显著差异。
图 5-每种站姿的正文字数与标题字数的散点图。同样,每种姿势都有相似的分布。
值得注意的是,训练数据是唯一的,因为有许多不同的标题链接到同一文本。这代表了我们在现实生活中看到的情况,不同的作者会发布一个新闻故事,而这个故事实际上是由不同的媒体或报纸以新的标题报道的。虽然标题不同,但正文通常是相同的,只有一些小的变化。该数据集包含 1,683 篇独特文章的 49,972 个标题。虽然这表明每篇文章平均有 29.69 个标题,但事实证明,一些文章比其他文章更频繁地被“改变用途”。图 6 显示了每个唯一正文的标题数量,我们可以看到一篇文章被“改变用途”了 78 次,但在大多数情况下,数据集包含唯一的标题和正文对。
图 6 —每个正文标题数量的直方图
获奖模型:
赢得假新闻挑战的模型使用了两个模型之间的加权平均值:梯度提升决策树和卷积神经网络(CNN)。深度 CNN 使用嵌入应用于标题和正文。嵌入应用谷歌新闻预训练向量。卷积层的输出被发送到具有四级输出的 MLP。这四类是我们的四个量词:同意、不同意、讨论和无关。他们的模型在所有卷积层中使用概率为 50%的丢失进行正则化。他们的超参数被设置为逻辑默认值,但没有被评估来优化他们的网络。它们的 CNN 结构在下面的图 7 中有进一步的描述。
图 7 —竞争获胜的 CNN 模型结构(https://github . com/Cisco-Talos/fnc-1/tree/master/deep _ learning _ Model)
获胜提交的第二部分加权平均是一个决策树模型。该模型接受基于文本的特征的输入,这些特征来自文章的标题和正文。这些输入被输入到梯度推进决策树中,以预测标题和正文之间的关系(同意、不同意、讨论或不相关)。下面的图 8 概述了这种模型结构。这个决策树模型的输入非常依赖于特征工程。获奖模型的创作者通过预处理(generateFeatures.py
)、基本计数特征(CountFeatureGenerator.py
)、TF-IDF 特征(TfidfFeatureGenerator.py
)、SVD 特征(SvdFeatureGenerator.py
)、Word2Vec 特征(Word2VecFeatureGenerator.py
)和情感特征(SentimentFeatureGenerator.py
)进行特征工程。
图 8 —赢得竞赛的 XGBoost 模型结构(https://github.com/Cisco-Talos/fnc-1/tree/master/tree_model)
在检查了初始 EDA 之后,我们的下一步将是根据竞争中的顶级放置模型来创建我们的基线模型。在创建基线模型之后,我们可以采取额外的步骤来增强它的性能。考虑到获胜模型在他们的 CNN 中缺乏超参数调谐;可能有机会进一步改进他们的模型。此外,因为有如此多的方法来进行特征工程,所以在决策树模型方面,可能有机会试验各种特征工程方法来提高模型性能。
其他 EDA 数据:
图 9 —标题字数的箱线图。右偏分布如图所示。
图 10——按站姿统计标题字数的箱线图。不同站姿类别的分布相似。
参考资料:
描述假新闻 twitter 研究及其他假新闻相关研究的文章:https://www . thealantic . com/technology/archive/2018/03/largest-study-ever-fake-news-MIT-Twitter/555104/
*原创假新闻挑战赛网址:【http://www.fakenewschallenge.org/ *
帖子中引用的假新闻推特研究:https://science . science mag . org/content/359/6380/1146 . abstract
乔纳森·斯威夫特(1667–1745)引用:https://www.bartleby.com/209/633.html
获奖模型 github 页面和代码,我们将使用它来启发我们的第一个模型:https://github.com/Cisco-Talos/fnc-1
在 iOS 应用中实现 Keras CNN
如何利用 Keras 和 Swift 实现一个移动 CNN 可以识别你的狗品种看起来很像
作者拥有许可证
我第一次想到在一个应用程序中进行图像分类是在看电视节目《T2》的时候。对于任何非硅谷爱好者来说,这部剧是一部喜剧,剧中人物在一个科技孵化器里。孵化器的一名成员推出了一个应用程序,其中唯一的功能是告诉你你看到的图片是“热狗”还是“不是热狗”卷积神经网络(CNN)很可能最适合完成这项任务,虽然我过去上过这方面的课程,但我对如何在移动设备上实现和部署机器学习算法很感兴趣。
我的第一个行动是为一个图像分类应用程序选择一个主题,我选择了狗。谁不喜欢给自己的狗拍照呢?但是为了做到这一点,我需要一个相对大而广的数据集来训练 CNN。幸运的是,斯坦福大学有一个开源数据库,里面有 120 个不同的狗品种,每个品种至少有 150 张图片。
示例输入—作者提供的图片
我的下一个想法是,虽然给狗分类的应用程序会很有趣,但它可能相对来说很平凡。那么,如果模型取一张人的照片作为输入和输出,那么与人最相似的狗的品种是什么呢?该分类器将只在狗身上训练,但给定任何图像,包括一个人的图像,它将提供各种品种的概率结果,因此它将输出最可能的品种作为预测。
苹果 iOS 使用一种名为 Core ML 的工具来执行所有的机器学习任务,如图像识别。起初,我认为我可能需要用 Swift 来构建和训练一个模型,这是一种我相对不熟悉的语言。然而,在谷歌搜索了几次后,我发现苹果提供了一个核心 ML 转换器,它可以将 Keras 模型转换为可以部署在 iOS 应用程序中的核心 ML 模型。
接下来,我必须建立 CNN,并对大约 20,000 张图片进行训练。为了在不进行大量训练迭代的情况下获得足够的模型深度,迁移学习可能是最佳途径。我决定使用流行的 VGG16 网络,它在过去赢得了 ImageNet 竞赛。下面是该网络的概况。
VGG16 网络的架构—公共域
from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten, Dropout, MaxPooling2D, Activation, Reshape
from keras.preprocessing.image import ImageDataGenerator
from keras.applications.vgg16 import VGG16
我将层设置为不可训练,以保持原始的 VGG 权重,并在末端添加了 2 个完全连接的层,同时利用下降来控制过度拟合。我还“弹出”了 VGG 的最后一层,并添加了两个完全连接的层,以使其符合正确的输出数量。
model = Sequential()
model.add(VGG16(include_top = False, input_shape = (270,201,3)))
model.layers.pop()
model.layers.pop()for layer in model.layers:
layer.trainable = False
model.add(Flatten())
model.add(Dense(3000, activation = 'relu'))
model.add(Dropout(0.2))
model.add(Dense(118, activation = 'softmax'))
model.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])
然而,在开始训练之前,我需要对图像进行预处理。使用 Keras 的 ImageDataGenerator 非常有用,因为它可以根据给定的输入大小调整图像,并允许训练和验证分割。
data = ImageDataGenerator(rescale=1./255, horizontal_flip=True, validation_split=.2)train_gen = data.flow_from_directory('/Users/Derek/Desktop/ImageTrain', subset = 'training', class_mode = 'categorical', target_size = (270,201))#201 for ease in coremltest_gen = data.flow_from_directory('/Users/Derek/Desktop/ImageTrain', subset = 'validation', class_mode = 'categorical', target_size = (270,201))
我对模型进行了训练,直到验证错误开始增加,并将其保存为 Keras checkpoint .h5 格式。然后我把我的模型转换成。可用于 iOS 设备的 mlmodel 格式。
import coremltools
model.save('your_model.h5')
coreml_model = coremltools.converters.keras.convert('your_model.h5', image_scale = 1./255., class_labels=class_list, input_names='Image', image_input_names = "Image")
spec = coreml_model.get_spec()
coremltools.utils.convert_double_to_float_multiarray_type(spec)
coreml_model = coremltools.models.MLModel(spec)coreml_model.save('my_model.mlmodel')
在我开始应用程序开发之前,我必须学习一些 Swift 的基础知识,老实说,我还必须学习应用程序开发!我在 YouTube 上找到了一个很棒的教程,叫做《Chris 的编码》,它讲述了 Swift 和 Xcode 应用程序开发的所有基础知识。⁴:有了这个教程,我能够把一个单一视图应用程序放在一起,它接受来自用户相机胶卷的图像或通过应用程序拍摄的图像作为输入,并输出最可能的狗品种分类,以及狗的图片。虽然这个过程的大多数方面都很简单,因为 Apple 在 Xcode 中使用了许多拖放功能,但我必须手动预处理用户图像大小,以确保它适合 CNN 中的输入尺寸。
**func** full_preprocess(uiim: UIImageView, cgim: CGImage) -> CVPixelBuffer {**var** im = **self**.imageWithImage(image: uiim.image!, scaledToSize:CGSize(width: 67, height: 90))//This has to be half of the model input size because of the buffer**let** ratio:Double = 270.0/Double(im.cgImage!.height)**if** ratio != 1 {im = **self**.imageWithImage(image: uiim.image!, scaledToSize:CGSize(width: 67.0 * ratio, height: 90 * ratio))}**let** new_im:CVPixelBuffer = **self**.pixelBufferFromCGImage(image: im.cgImage!, image2: im)**return** new_im}
现在你有了它,一个利用数据科学和应用程序开发的项目,一个有希望让你一路开怀大笑的项目!
作者拥有许可证
参考文献
- 越南安乐,杨坚:热狗识别 app ,2017,https://www.youtube.com/watch?v=vIci3C4JkL0
- 斯坦福大学,斯坦福狗数据集,http://vision.stanford.edu/aditya86/ImageNetDogs/
- 苹果,芯 ML,https://developer.apple.com/documentation/coreml
- CodeWithChris, Code With Chris,https://www.youtube.com/channel/UC2D6eRvCeMtcF5OGHf1-trw
用蒙特卡罗模拟预测极端天气事件
用蒙特卡罗模拟检验温度情况
来源:图片来自 Pixabay
在之前的文章中,我概述了 ARIMA 等传统时间序列模型在预测极端温度值时的局限性,这些值本身就是时间序列中的异常值。
在处理极值时,蒙特卡罗模拟在量化极端事件发生的概率方面可能是更好的解决方案。
背景
在最后一个示例中,苏格兰 Braemar 的月平均最低温度值用于训练和验证 ARIMA 模型预测。这是使用从 1959 年 1 月到 2020 年 7 月的每月英国气象局数据完成的(包含公共部门信息在开放政府许可 v1.0 下许可)。
在这种情况下,蒙特卡洛模拟建立在相同的数据上,试图生成一系列温度值的情景分析。
首先,让我们仔细看看数据本身。
这是布拉马的月平均最低温度:
资料来源:英国气象局
让我们更详细地分析时间序列。首先,让我们绘制一个分布直方图:
来源:Jupyter 笔记本输出
通过查看直方图,我们可以看到分布显示负偏斜。我们来算一下这个来确认一下。
>>> series = value;
>>> skewness = series.skew();
>>> print("Skewness:");
>>> print(round(skewness,2));Skewness:
-0.05
从这个分析中,我们观察到分布是负偏态的,因此不一定遵循正态分布(至少不完全是)。
以下是残差的 QQ 图:
来源:Jupyter 笔记本输出
特别是,我们可以看到上分位数的值偏离了正态分布线。中位温度为 2.2°C,平均温度为 2.72°C(布雷马尔是英国最冷的地区之一),显著高于这一温度的值超出了正态分布的界限——我们预计,随着上分位数记录的温度降低,分布将呈现更为正常的形状。
此外,模拟天气模式可能相当棘手,因为地理分布会有所不同。例如,赤道的温度分布将与两极的温度分布大不相同。在这方面,为了准确地模拟天气,理解所讨论的时间序列的分布是必要的。
蒙特 卡罗模拟
对于此模拟,将生成 1000 个随机值。由于该分布已被确定为负偏态,这意味着生成的随机值也必须遵循类似的负偏态分布。
预测每月最低温度
为此,可以使用 scipy 库中的。如前所述,a(或偏斜参数)设置为 -0.05 。
**from scipy.stats import skewnorm
a=-0.05
distribution = skewnorm.rvs(a, size=1000)**
以下是生成的数组的示例:
**array([ 1.10993586e-01, 1.92293755e+00, -1.29797928e+00, -1.36817895e+00,
-4.08836917e-01, -2.20566871e-01, -1.80936352e+00,
...
-1.59656083e-01, 2.10239315e+00, 1.98068918e-01, -2.23784665e-01])**
下面是生成数据的图表,显示了非常轻微的负偏差:
来源:Jupyter 笔记本输出
原始系列的平均值和标准差计算如下:
**>>> mu=np.mean(value)
>>> mu
2.7231393775372124>>> sigma=np.std(value)
>>> sigma
4.082818933287181**
现在,形成假设分布的生成的随机数乘以 sigma(标准偏差),然后将乘积加到 mu(平均值)。
**y = mu + sigma*distribution
num_bins = 50**
这里是本程序的另一个例子(假设正态分布)。让我们生成一个温度模拟直方图:
**# Histogram
plt.hist(y, num_bins, facecolor='green', alpha=0.5)
plt.xlabel('Values')
plt.ylabel('Frequency')
plt.title(r'Histogram of Temperature Simulations')**
来源:Jupyter 笔记本输出
你会注意到最低模拟温度-11.32°C 刚好低于原始数据中记录的最低月平均温度值-8.6°C。从这个角度来看,该模型在估计每月可能出现的极端最小值方面做得相当好。
来源:Jupyter 笔记本输出
预测每日最低温度
也就是说,这个例子中的一个限制是我们处理的是月度数据,而不是每日数据。
假设我们希望预测最低的每日最低温度。这个模型在这个场景中有用吗?
事实上,1982 年 1 月 10 日 Braemar 记录的最低日最低温度为-27.2 摄氏度,这大大超过了蒙特卡洛模型模拟的最低温度-11.32 摄氏度。
这表明,分布可能比月度数据显示的更加负偏。使用每日数据可能会显示更大的负偏差,对于蒙特卡洛模拟可能会提供更多信息。
让我们将 a (我们的偏斜参数)降低到-2,看看会发生什么。
来源:Jupyter 笔记本输出
记录的最低月平均温度为-12.34 摄氏度。这仍然比记录的最低日温度高得多。
在这方面,虽然蒙特卡罗模拟对月度数据建模有用,但这种模拟仍然无法补偿我们没有所需数据的情况。
很有可能,Braemar 的每日温度数据将意味着一个更加负偏态的分布。也就是说,该系列的平均值和标准偏差也可能会有很大变化-如果不知道这些参数,那么蒙特卡罗模拟在估计每日值方面会受到限制。
当我们有正确的数据时,蒙特卡罗模拟可能是强大的——但它不一定能弥补数据的缺乏。
结论
这是如何使用蒙特卡罗模拟来模拟极端天气事件的介绍。
特别是,我们看到:
- 确定相关时间序列的正确分布的重要性
- 在 scipy 中使用 skewnorm 生成具有定义偏斜的随机数
- 用于识别极端电势值的蒙特卡罗模拟的实现
非常感谢您的宝贵时间,非常感谢您的任何问题或反馈。你可以在这里找到这个例子的 GitHub 库。
免责声明:本文是在“原样”的基础上编写的,没有任何担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。本文中的发现和解释是作者的,不以任何方式得到英国气象局的认可或隶属于该局。
使用神经网络来预测选民的偏好
随着总统选举的临近,政治分析师、预测者和其他利益相关方正在努力对选举结果做出最佳估计。传统上,民意调查被用来衡量政治候选人的受欢迎程度,但计算能力的提高和强大统计方法的发展为他们提供了一个有趣的替代选择。开始预测选举的一个好地方是首先预测选民的政治偏好。这就是我们将要做的。
在本文中,我们将在 R 中构建一个简单的神经网络来预测美国选民的偏好。
我们将使用 Keras 来实现这一点,这是一个令人惊叹的开源 API,它允许您以简单而强大的方式运行神经网络模型。虽然它是在 Python 中本地运行的,但是 RStudio 已经开发了一个允许与 r 无缝集成的包。
在我们开始之前,请确保您已经安装了以下 R 包,因为我们将使用它们来执行我们的预测:
install.packages("keras")
install.packages("tidyr")
install.packages("ggplot2")
install.packages("dplyr")
install.packages("fastDummies")
数据
用于训练神经网络的数据来自 2018 年合作国会选举研究,由 YouGov 管理。它由 Kuriwaki (2018)编制,并从哈佛数据节中提取。您可以在中下载这些数据。Rds 文件格式为 2006–2018 年此处。
假设您下载了文件并将其放在工作目录中,我们可以继续导入数据并查看其结构:
d <- readRDS("cumulative_2006_2018.Rds")
dim(d)[1] 452755 73
d
是具有 452,755 行(观察值)和 73 列(特征)的数据帧。这些特征包括地理、人口和经济变量,以及其他有趣的变量,如政治认可和新闻兴趣水平。当然,它们也包括每个个人的总统投票选择。这最后一个变量将是我们的因变量,例如,我们将使用我们的模型预测什么。最后,在前面提到的数据集源链接中提供了每个变量的详细解释。
由于我们有 2006 年至 2008 年的数据,让我们过滤d
以仅选择 2018 年(最近一次调查的年份)的回答:
dd <- d %>%
filter(year == 2018)
此外,让我们只选择我们的模型感兴趣的变量,并排除丢失的值:
dd <- dd %>%
select(st, dist, cong, # geography
gender, birthyr, age, educ,
race, faminc, marstat, # demographics
newsint, # news interest
approval_pres, # approval
ideo5, # ideology
voted_pres_16 # presidential vote
)
dd <- dd[complete.cases(dd),]
该数据框如下所示:
下表列出了各类选民偏好的受访者人数(变量voted_pres_16
)。可以看出,大约 88%的受访者投票给唐纳德·特朗普或希拉里·克林顿,9.91%的人投票给另一位候选人,大约 1.3%的人没有透露他们的偏好或没有投票。
回到我们的数据集dd
,排除变量age
,我们所有的特征都是分类的。因此,我们需要一次性将这些变量编码成虚拟变量。有很多包和函数可以做到这一点,但是这里我们将使用fastDummies
包中的函数dummy_cols
。
cat_vars <- colnames(dd)
cat_vars <- cat_vars[!cat_vars %in% c("age","voted_pres_16")]
all_data <- dummy_cols(dd,
select_columns = cat_vars,
remove_first_dummy = TRUE,
remove_selected_columns = TRUE)
我们还将我们的因变量voted_pres_16
转换为每个候选项的整数(从零开始)的数字向量,并从我们的数据帧中移除变量voted_pres_16
:
all_labels <- dd$voted_pres_16 %>%
as.factor() %>%
unclass() - 1all_data <- all_data %>%
select(-voted_pres_16) %>%
as.matrix()
最后,我们将我们的数据分成一个训练集(90%)和一个测试集(10%),这样在我们训练完我们的模型后,我们可以在“新”数据上测试它的性能。
party_levels <- levels(all_labels)
elems <- sample(1:nrow(all_data),
round(0.1*nrow(all_data)),
replace = F)# training data
train_data <- all_data[-elems,]
train_labels <- all_labels[-elems]levels(train_labels) <- levels(all_labels)# test data
test_data <- all_data[elems,]
test_labels <- all_labels[elems]levels(test_labels) <- party_levels
建立模型
我们手头的问题被建模为分类问题,其中表 1 中的每个候选代表一个分类类别(总共 5 个类别)。输入层被格式化,使得 148 个解释变量中的每一个都馈入输入层的一个神经元。这些神经元然后连接到隐藏层中的其他神经元。在这个例子中,我们为隐藏层使用了 100 个神经元。最后,输出层有 5 个单元,每个类别一个。图 1 包含了这个神经网络的图形描述。
图一。我们神经网络的代表
因此,我们定义我们的模型:
# Define model
model <- keras_model_sequential()
model %>%
layer_dense(units = 100, activation = "relu",
input_shape = dim(train_data)[2]) %>%
layer_dense(units = length(party_levels), activation = 'softmax')
第一阶段(输入到隐藏层)的激活函数是整流线性单位,或 ReLu,而第二阶段(隐藏到输出层)的激活函数是 softmax。
我们现在开始编译和训练模型。我们将在这里使用的优化算法是 adam ,这是一种自适应优化算法,通常用于训练深度神经网络。使用的损失函数是稀疏分类交叉熵。最后,我们将为模型获取大约 20%的训练数据,以迭代计算验证误差。
###### Compile the model ######
model %>% compile(
optimizer = 'adam',
loss = 'sparse_categorical_crossentropy',
metrics = c('accuracy')
)###### Train the Model #####
early_stop <- callback_early_stopping(monitor = "val_loss",
patience = 20)model %>% fit(train_data,
train_labels,
validation_split = 1/5,
callbacks = list(early_stop),
epochs = 500)
上述算法将适合我们的神经网络 500 个时期,如果测试模型性能在 20 个连续时期内没有增加,它将在此之前停止。
车型性能
训练完我们的模型后,我们希望通过预测和查看模型性能,使用我们的测试数据对其进行评估:
###### Evaluate Model ######
score <- model %>% evaluate(test_data, test_labels, verbose = 0)cat('Test loss:', score$loss, "\n")
cat('Test accuracy:', score$acc, "\n")
模型性能
测试损耗和准确度分别为 0.4882 和 0.8461!还不错!
尽管如此,我们现在想看看我们的模型失败了。图 2 详细展示了该模型的性能。
图二。混淆矩阵
上面的图像包含了我们模型性能的混淆矩阵。正确的分类率(对角线上的高精度和非对角线上的低值)显示为绿色,而不正确的分类率(对角线上的低值和非对角线上的高值)显示为红色。
对混淆矩阵的仔细观察表明,该模型没有对“没有投票”和“不确定/不记得”的类别做出正确的预测。这是因为相对于其他类别而言,属于这些类别的意见数量较少:回答“没有投票”或“不确定/不记得”的受访者数量分别仅占总样本的 0.86%和 0.43%(表 1)。因此,为了准确地预测这些类别,需要更多的信息:为了知道回答者是否没有投票给或者他们是否不记得他们投票给了,仅仅知道投票者的政治和意识形态偏好是不够的。
此外,似乎令人惊讶的是,该模型在将投票者分配到“其他”类别时表现非常差(非常差的 14.1%的准确率)。由于所有观测值中约有 9.91%属于这一类(见表 1),情况尤其如此。尽管如此,重要的是要注意到这一类别包括非常多样化的总统候选人,如加里·约翰逊(自由党)和吉尔·斯坦(绿党)。这些候选人有着不同的政治意识形态,代表着选民偏好和人口统计数据的混杂。因此,我们可能会认为,实际上可以预期,该模型无法准确预测任何属于这一类别的总统候选人的选票。
所以,我们建立了一个预测选民偏好的模型。我们如何预测选举的结果?
这是一个非常困难的任务,超出了本文的范围,但一个好的开始是用民意调查数据训练我们在这里开发的模型,并使用来自选民名册的数据来预测给定州或整个美国人口的政治偏好。
我希望你喜欢这篇文章,如果你喜欢,请告诉我!
Kuriwaki,Shiro,2018,“累积 CCES 共同内容(2006–2018)”,【https://doi.org/10.7910/DVN/II2DB6】T4,哈佛数据节,V4
图像分类:利用人工智能检测肺炎
用 Python (Keras)实现神经网络对 X 射线图像进行分类
正常肺(左)与肺炎(右)(来源)
在我的上一篇博客中,我向你们展示了如何创建一个神经网络来预测一名 NBA 球员在任何特定夜晚的表现。虽然这是一个非常有趣的项目,但由于新冠肺炎的原因,我无法在常规赛中测试它。考虑到全球疫情,我真的很犹豫是否要开始一个新项目,因为今年不仅在体育方面,而且在金融和情绪分析方面都被认为是异常值。带着这个问题,我开始搜索 Kaggle,发现了一个充满正常和非正常肺部(肺炎)X 射线图像的数据集。这引起了我的兴趣,所以我继续搜索更多的数据库,找到了更多带标签的照片。我能够将两个数据集合并到一个文件夹中(没有重复),总共有 6000 张图像。使用这些图像,我将向您展示如何创建一个卷积神经网络,它可以预测一个人是否患有肺炎,准确率约为 98%(测试集)。
数据集
- 科罗纳哈克
- GitHub COVID 数据集
- GoogleDrive (包含组合数据集、pickles 和带有图像路径/标签的 csv)
卷积神经网络
虽然我们看到的图像有颜色和形状,但在最基本的层面上,它们是数字列表,每个数字对应一个 RGB 值,然后由计算机处理,向您显示图像。卷积神经网络在图像处理中获得了牵引力,因为它们能够将 RGB 阵列分成(1×1)、(2×2)或(3×3)个像素,以便学习图像中的模式
图片来自等人的 Van Hiep Phung。铝
** 下面显示的所有代码都可以在我的GitHub** * **上找到
密码
带有的数据集。csv 太大了,无法上传到我的 GitHub 上,所以我在我的 GoogleDrive 上公开了它。
包导入
套餐
- Sklearn
- 克拉斯
- 张量流
- 熊猫
- Numpy
- 泡菜
- 马特普罗德利卜和西伯恩
列车测试分离
因为这是我的第一个图像分类项目,我花了几个小时去理解一个将数据恰当地分成测试和训练的架构——特别是因为我从多个来源收集了数据。我最终采用的方法是这样的:(1)我首先创建一个 CSV 文件,其中包含每个图像的路径和标签,(2)像往常一样分割训练和测试,根据标签对每个组进行分层,(3)然后我遍历每个图像路径并提取其 RGB 值
x 列车等级频率
根据计算机的速度,获取每个图像及其 RGB 数组可能需要几分钟的时间,所以我腌制了每个样本,以避免每次我想训练新模型时都这样做( GoogleDrive )。
在挽救了泡菜之后,现在是时候开始构建神经网络了。下面是模型架构的截图。ReLU 激活函数用于除输出层以外的每一层。Sigmoid 用于激活层,因为分类集是二进制的。
CNN 模型架构
我发现 sigmoid 激活对这个模型更好,因为它对二元分类更准确。如果你调整这个模型来预测肺炎的类型(病毒性,真菌性,等等。),则 softmax 激活对输出图层更好,使用 categorical _ crossentropy 比 binary_crossentropy 更好。
在同一个笔记本中运行下面的单元,开始培训过程。early_stopping 将防止模型过度拟合,而模型检查点在每次 val_loss 减少时保存权重。
模型评估
模型检查点参数能够在 30 个时期停止模型,以防止进一步过度拟合。从下面的图表中,我们可以看到训练和测试的准确率保持在 96%以上。然而,我学到的一件事是永远不要相信表面的准确性。为了更好地研究模型的性能,我绘制了 AUC、ROC 和决策边界曲线,以确定使用不同阈值时模型如何变化。同样,这些图形的所有代码都可以在我的 GitHub 上找到。
验证/培训损失和准确性
F1,AUC,ROC 分数
该模型的 F1、AUC 和 ROC 评分分别为 0 . 935、0 . 972 和 0 . 994。
TPR 和 FPR 与阈值
在选择阈值之前,首先重要的是要了解您试图解决的问题的背景,以及这将如何影响您想要的结果。在我们的病例中,我们希望对肺炎进行分类。另一方面,如果我们将一个正常的肺归类为患有肺炎,只要我们经常检测到肺炎,这并不是那么糟糕。决定这个问题的决策阈值是在产生最低成本的最佳值- 之间进行选择,这在每个机器学习问题中都是不同的。下面,您可以看到不同阈值. 2、. 5 和. 6 的混淆矩阵
不同阈值的混淆矩阵
为了在外部数据上测试这个模型,我从谷歌上收集了 17 张图片,并使用了 0.65 的概率阈值。正如你在下面看到的,这个模型有 100%的正确率和 56%的正确率。如果你下载了我的回购中的代码,有一个文件夹,你可以自己尝试一个预测。你所要做的就是下载图像,将文件命名为正常或非正常以记住它的标签,然后运行代码。
未来方向
- 对肺炎的类型进行分类(病毒性、真菌性等。)
- 使用灰度(1D 阵列)
- 应用重击来改变职业不平衡
- 使用尺寸为(96,96,3)或(204,204,4)的较大图像。我最初尝试使用更大的尺寸,但我的电脑太低了。拥有更大的图像可以使检测更准确,因为比后者有更多的细节。
用 AI 来交易?以下是 JP 摩根的方法
研究文摘
利用强化学习获得最优执行策略
在本文中,我们主要关注论文“在模拟市场反应存在的情况下用于自主执行的风险敏感紧凑决策树”,以讨论机器学习如何帮助我们获得更好的执行策略。在这个过程中,我们从其他论文中添加了更多的信息,这些信息是本文的基本理论,也是帮助我们理解问题的额外来源。
问题:如何执行命令?
想象一个交易者有一堆钱,这个交易者想买一堆股票。现在,交易者可以使用两个订单来购买股票:
- 市价指令簿:以当前市价买卖。交易者提交他/她想要购买的股票数量,然后交易所根据当前市场自动设定价格。
- 限价委托单:交易员预先设定的特定价格的买入和卖出。当别人想以这个价格卖出或买入时,交易所会撮合这两个,完成交易。
正如我们可以看到下图。如果交易者想执行限价单,他会将订单放在队列中;如果交易者想要执行市价单,他将立即以当前市价获得执行。
限价订单示例(归功于 Vyetrenko 和徐,2019)
限价订单与市价订单
当你要执行市价单时,你要确保执行优先于价格。
- 优势:您可以立即流动资产,因为交易所会自动匹配价格并执行订单。
- 缺点:当你购买资产时,你可能会有很多成本。你可能立即以 101 美元买入一只股票,但如果你只等 5 分钟,你也可以以 100 美元买入。
当你想执行限价单时,你把价格放在优先于执行的位置。
- 优势:你按照自己设定的价格执行订单,无论买入还是卖出。如果你想以 105 美元买 100 只股票,你先设定一个价格。如果系统匹配到想以 105 美元卖出 100 只股票的卖家,那么系统匹配你们两个并执行这个过程。所以你可以确定你想买的东西的价格。
- 劣势:你有长时间不执行限价单的风险。例如,当当前市场价格为 80 美元时,您可以将买入价设置为 50 美元。直到价格降到 50 美元(不太可能),你才能得到执行。
市场影响
另一个问题是市场影响。股票交易总是有供给方和需求方,这就要保持平衡。问题是大机构往往会在短时间内(比如一天内)买入很多股票。如果市价是 100 美元,他们想用 1,000,000 美元买 10,000 股。如果他们只是一次性地出示订单。市场中的所有人都会知道有人想购买大量股票,然后卖方会根据人性提高价格,这就是所谓的市场影响。为了解决这个问题,他们可以将大订单拆分成更小的子订单来降低成本。
执行策略:如何达到最优?
目标是在今天结束前执行并获得一定数量的股份。但是交易者想要实施一个最优策略来处理它。三个问题仍然存在:
1.每个子订单的比例是多少?
2.他们想什么时候执行订单?
3.对于每个子订单。他们是要执行市价单还是限价单?
对于每个子订单,我们称限价订单为被动订单,因为买家会设定价格,并被动地等待价格匹配。我们称市价订单为积极订单,因为买家希望积极地获得订单,而不考虑价格。
最优执行问题 vs .最优布局问题?
每个人都会问这个问题:我做交易的时候,怎么才能降低成本?从上一段可以看出,当一个交易者想买入一个时间窗口[0,T]给定的 S 股股票时。交易者希望如何最小化获取成本?我们称这个最优执行问题。
Bertsimas 和 Lo (1998)提出了一种基于动态规划原理(DPP)的最优执行策略,他们假设了线性价格影响:
线性市场影响
这意味着当前价格(Pt)是先前价格(Pt-1)、你购买股票的比例(St)和随机噪声的函数。他们得出的结论是,最优执行策略只是根据相等的时间间隔将全部股票平均分成若干份。
最佳执行策略
郭等(2013)给出了最优布局问题的理论。与最优执行相比,针对交易的最优布局问题发生在更小的时间窗口(10-100 秒),尤其是在 HFT(高频交易)领域。
强化学习方法
考虑这个问题的方法太多了。本文试图使用马尔可夫决策过程(MDP)和强化学习(RL)来解决这个问题。作者考虑了最优执行策略的价格影响,以及多主体的相互作用(对市场的模拟)。在本文中,3 个组件协同工作:
- 限价订单簿数据模拟器
- 强化学习算法:风险敏感 Q 学习
- 功能选择
市场模拟
模拟器互动
运行该策略有两个组成部分:
- 市场模拟器:让 RL 算法有足够的数据和交互来训练自己,这是一个游乐场。如果我们执行订单,模拟器将模拟市场影响。
- 强化学习代理:强化学习代理将与市场模拟器交互。它下订单以产生市场影响,然后从这个模拟器获得回应作为奖励。
培训流程(归功于 Vyetrenko 和徐,2019)
正如你在这张图片中看到的,他们在模拟市场环境中训练强化学习代理,这与实时执行代理有类似的方案。
如何定义市场影响?
回想一下,一些论文(Bertsimas 和 Lo,1998)使用线性函数来模拟市场影响。
线性市场影响
但在本文中,他们将市场反应作为 LOB(限价订单簿)数据和激进订单规模的函数。这意味着他们可以从 LOB 数据中获得洞察力,而不是使用公式中的假设。
强化学习
对于每个强化学习,有 3 个组成部分:
1.状态:有两种状态。对于代理人来说,状态表示头寸,这意味着还剩多少钱,交易者想买多少股票。对于市场来说,一个市场有市场价格,限制目前的订单规模。然后,他们将状态变量分离到箱中。意味着如果有 5 个变量,每个变量分别有 2、3、4、5、6 个箱。它将得到 23456 = 720 个状态。
2.动作(a) :在每一个时刻,都有一个动作选项:在限价指令簿或市价指令簿上押 o 大小,分别代表被动和主动。如果 o = 0,此时他们不执行任何订单。
3.奖励(R) :奖励是每次节约的成本。奖励定义为:
每次执行的奖励
在这个公式中,报酬是时间 t 时的执行价格(Pt)、交易者仅执行整个母订单时的价格(Pσ)和订单大小(ft)的函数。
在 Lo 的论文中,他们还使用 MDP 对最优执行策略进行过程建模。但是他们做了一些固定的假设,没有用动态数据来支撑。
因此,在本文中,他们使用 Q-learning 和 MDP 来模拟真实模拟动态环境中的反应。Q-学习中的 Q 值公式定义如下:
在这个公式中,Q 值是奖励 (R)总和、状态 (s)和动作 (a)的函数。定义 Q 值后。目标是获得最大化总贴现回报期望的最优策略:
由于有如此多的状态变量作为特征,他们还使用最小二乘策略迭代方法从总特征池中选择特征的子集。
决策树表示的结果
在强化学习算法中,他们提供了一个可变的参数β来表示不同的风险偏好。
在 Q-Learning 训练过程之后,他们得到一个学习的表格执行策略,然后他们使用决策树来表示这个结果。决策树的优点是决策树可以明确地解释特征。基于此,交易者可以根据状态变量的情况使用不同的策略,积极地(市价单)或消极地(限价单)。
基于决策树的策略(归功于 Vyetrenko 和徐,2019)
与基准测试相比,他们的结果更好。基于这种基于强化学习树的智能体取得了很好的效果。该代理可以节省 32%的总执行成本。但是对于标准差来说,这种策略增加了 27%的成本标准差,这是成本节约和风险之间的权衡,这是限价单的本质。
强化学习模型的结果(归功于 Vyetrenko 和徐,2019)
结论
在本文中,作者展示了强化学习算法可用于最优执行问题。它会考虑一个动态的环境,而不是做一个固定的假设。它在限价订单簿数据集上表现良好。和作者表明,他们可以用决策树来表示政策,以指导交易者做出决策。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
参考
[1] Bertsimas、Dimitris 和 Andrew W. Lo。"执行成本的最佳控制."金融市场杂志 1,第 1 号(1998):1–50。https://doi . org/10.1016/s 1386-4181(97)00012-8。
[2]gatherel,吉姆,亚历山大·席德。"市场影响的动态模型和订单执行的算法."SSRN 电子杂志,2012 年。https://doi.org/10.2139/ssrn.2034178。
[3]郭、辛、阿德里安·德拉拉尔和赵阮。"限价订单簿中的最佳位置."SSRN 电子杂志,2013 年。【https://doi.org/10.2139/ssrn.2318220】T4。
[4]郭、辛、阿德里安·德拉拉尔和赵阮。"限价订单簿中的最佳位置:一种分析方法."数学与金融经济学 11 第 2 期(2016):189–213。https://doi.org/10.1007/s11579-016-0177-5。
[5] Vyetrenko,Svitlana 和 Xu。"在模拟市场反应中自主执行的风险敏感紧凑决策树." arXiv 预印本 arXiv:1906.02312 (2019)。
用人工智能实时翻译手语
一个集成 AI 和 ASL 的项目
致谢:佩克斯的路易斯·金特罗
世界上有成千上万种语言。几乎所有最流行的语言都可以使用谷歌翻译等软件进行实时翻译。所使用的软件主要基于 NLP 算法,该算法通过文本接收一种语言并通过文本产生其翻译。对于真正的实时翻译,一些软件通过麦克风利用语音来翻译信息,而无需用户键入。这对口语很有用。但是,有 7000 万人不能说话或不能听,他们使用手语作为交流的方式。手语是一种不同的语言,因为它不能说。如果说不出来,那么现在的任何翻译软件都翻译不出来。那么如何翻译手语呢?当然是用相机和一点人工智能魔法!当前的手语翻译者利用摄像机进行翻译,例如signal 1,他使用彩色手套,并利用多个摄像机来理解手势。相机是给计算机视觉的一种方法,让它们能够看到世界。我决定尝试建立自己的手语翻译器。因为我住在美国,所以美国手语翻译是最有意义的。
卷积神经网络(CNN)是计算机可以对图像进行分类的方式之一。他们可以对数千张照片进行训练,并学习将每张照片分类到正确的类别中,或者在这种情况下是翻译。我选择做一个简单的 ASL 翻译,在这里我翻译了 ASL 字母表 。它由 26 个手形符号和一个删除和空格符号组成。我把这些标志翻译成英文字母。在我进入代码之前,我先简单介绍一下 CNN。
卷积神经网络
CNN 真的很酷,因为他们可以对图像进行分类。对于一个人来说,识别两个物品之间的区别是很容易的,比如一只狗和一只猫,但是对于一台计算机来说,要做到这一点就困难得多。计算机并没有真正“看到”图像。他们把它们看做一系列排列成阵列的数字。CNN 由多层组成。这些层通常是卷积层、池层和全连接层。
信用: Aphex34 ,通过维基 (CC BY-SA 4.0)
1)
信用: Trougnouf ,via wiki (CC BY-SA 4.0)
卷积层由一个指定大小的内核/滤波器组成,它在像素上滑动或卷积,将值相乘并求和,最终将其输出到一个新的更小的简化矩阵中。过滤器遍历照片中的每个像素,创建一个新的矩阵,称为特征矩阵。这个新的更小的矩阵很重要,因为它突出了图片中最重要的特征(因此得名)。它也更容易训练,因为更小=更少的重量=识别这些重量所需的训练更少。
2)
信用: Aphex34 ,via wiki (CC BY-SA 4.0)
下一层是池层。汇集层进一步减小了矩阵的大小。它在特征矩阵上传递一个池内核,并取最高像素值(最大池)或平均值(平均池)。在我的例子中,我使用了 max-pooling,因为它采用了图像中更极端的特征,比如边缘,这对识别手势很重要。现在我们有了一个更小的矩阵,重量更轻,需要的训练更少。该矩阵包含图中所有更高级别的细节。
3)
署名:维克拉姆·梅农
现在我们继续到全连接层。这里是分类发生的地方。矩阵首先被展平成向量,然后通过神经网络。它通过的神经网络类似于人工神经网络,因为它通过向量,应用权重和偏差,最终以分类结束。CNN 通过使用 softmax 激活 函数对图像进行分类,该函数给出了输入来自某个类别的概率。
工作原理
请点击此处查看 GitHub 资源库中的完整代码:
使用 CNN 翻译美国手语字母。为维克拉姆语-梅农语/美国手语-字母表-翻译的发展做出贡献
github.com](https://github.com/vikram-menon/ASL-Alphabet-Translation)
数据准备
这些层的输入是 ASL 数据集,可以在这里找到。数据被组织到 29 个文件夹中,每个文件夹中有 3000 张图片,代表字母表中的每个字母。3 个额外的文件夹是空间,删除和什么都没有。我组织了数据,这样 80%的照片是在训练中,20%是在验证中。此外,为了加快训练速度,我将数据集中的所有图片从 200x200 缩小到 48x48。
可选层和池层
该模型中使用了 4 个卷积层和池层。对于每一层,执行 5 个动作:
- 在第一行中,定义了过滤器的数量和过滤器尺寸。对于第一层,使用 64 个 3×3 滤波器。图像的输入尺寸在这里也被定义为 48x48。
- 矩阵经过卷积形成特征矩阵后,经过批量归一化。这减少了隐藏层值的移动。这使得训练更容易,因为它稳定了重量,提高了准确性。
- 我们接下来通过一个再逻辑单元函数运行它。这给该层带来了一些非线性,允许 CNN 理解输入的复杂图片。
- 下一行是汇集发生的地方。我们已经将池过滤器大小定义为 2x2,并使用最大池。这进一步减小了矩阵的大小。
- 最后,矩阵通过一个漏失层。丢弃层的作用是随机丢弃神经网络中的节点。删除节点的好处是网络对每个节点的权重变得不那么敏感。这使得网络的预测更加一般化,提高了准确性。在所使用的模型中,我们丢弃了 25%的现有节点,这些节点将在下一层中被新节点替换。
第一卷积层的输出现在成为下一层的输入。矩阵已经变得越来越小,但通过更多的层,它变得更小,只显示照片的关键部分进行分类。这些步骤发生 4 次,唯一改变的是卷积过程中使用的滤波器大小和滤波器数量。
全连接层
卷积后,是时候完全连接的层。但是在这之前,数据被展平到一个列向量中。
- 现在数据可以通过神经网络,使用了一个密集层。致密层相当于神经网络。它传递来自前面步骤的输入,并将其全部输出到它的神经元。神经元相互连接,将数据从一层传递到下一层。在这种情况下,有 256 个神经元。
- 然后经过批量归一化。
- 然后使用 ReLU 功能进行激活。
- 最后,使用 dropout 再次丢弃 25%的节点。
- 有两个完全连接的层,所以代码重复 512 个节点。
- 一旦通过第二个完全连接的层,输出通过一个 softmax 函数,该函数用于给出图像属于 29 个类别之一的概率。
- 最后几行设置学习率并评估模型的精度。
培训
既然我们已经定义了模型,我们必须训练它。训练模型是 CNN 活起来的地方。训练是“过滤器和全连接层的权重是多少?”已回答。CNN 使用反向传播来定义所有层的权重。反向传播包括四个步骤:向前传递、损失函数、向后传递和最后的权重更新。
1)
正向传递由穿过模型的图像组成。首先,所有的权重和偏差都是随机的,因此分类也是随机的。这是因为模型,特别是滤波器不知道如何识别图像的边缘和特征。
2)
分类精度用损失函数来表示。损失函数告诉你你的模型对每张图片的分类有多好。它将图像的预测标签与训练图像的实际标签进行比较。在我们的案例中,分类交叉熵被用作损失函数。
3)
接下来,是反向传递,其识别哪个权重导致损失函数高。
4)
当这些权重被识别时,权重被更新,使得损失减少。学习率指定了权重可以改变的程度。最终,目标是让预测的标签始终与图片的实际标签相匹配。
结果
经过 50 个时期的训练,该模型在数据集内达到了 100%的验证准确性。这相当令人印象深刻,但该模型能够达到 100%的准确性有一个明确的原因:数据集。当查看数据集中一个类别的图片时,它们实际上都是相同背景上的相同照片。因此,该模型很容易达到 100%的准确性,因为每张照片之间没有太多的变化,从而非常快地达到高准确性。
各时期模型的损失和准确性图表
现场预测
我仍然想让模型执行实时预测,以实现制作实时翻译器的目标。使用 cv2,我能够利用笔记本电脑上的网络摄像头捕捉帧,并通过模型发送它们,以预测每个帧的类别。
字母表的前几个字母
成功了!它能够预测大多数字母,但由于数据集范围有限以及我缺乏手语知识,有时会遇到困难。它也只翻译了美国手语字母,而不是单词,但这是一个开始!
这个项目制作起来非常有趣,因为最终的结果非常值得。请继续关注我的下一个版本!
联系我:
领英:https://www.linkedin.com/in/vikram-menon-986a67193
电子邮件:vikrammenon03@gmail.com
用人工智能解开反物质的秘密
反物质仍然是令人困惑的科学之谜之一。但人工智能可能会给它带来一些启示。照片由分形哈桑在 Unsplash
这是物质的邪恶双胞胎
M 之后——那是我们和我们周围的一切构成的所有东西。然后是反物质。它与物质具有完全相同的性质,但电荷相反。它应该在很久以前就毁灭了所有的物质——但神秘的是,它没有。物理学家正在使用人工智能来找出原因。
我们在游泳池里。当我竭尽全力的时候,你在快乐地潜水。突然你抬起头,向我喷出一股水。“啊,”我惊叫道,“你这个讨厌的小畜生!”
“你可以用反物质洗掉我的细菌,”你大喊一声,飞快地穿过水。我追着你。“你这是什么意思,”
我物理老师说的!当物质和反物质相遇时,会有一声巨响,然后两者都消失了。
当反物质遇到物质时,它会爆炸
他是对的。但是用反物质来让你的细菌消失是相当昂贵的。
“是啊,我从来没在商店里见过它……”
这是因为地球上只有两个地方产生足够大量的反物质。这些是美国的费米实验室和瑞士的欧洲粒子物理研究所。
哇,那它比黄金还稀有!”
没错。此外,把它用作清洁剂可能会有致命的后果。
“为什么,”
因为当物质和反物质相遇时,它会爆炸。物理学家解释说,根据爱因斯坦的公式, E=mc 。 E 代表能量, m 是质量, c 是光速的平方。它基本上意味着能量和质量是一回事。
反物质是一种相当容易爆炸的物质。action advance对 Unsplash 的拍照
物质和反物质都有质量。当物质和反物质相遇时,它们的质量转化为巨大的能量。这可能会非常具有爆炸性。
“好吧,那你可以这样洗掉我的细菌,”你哭着把一股水泼在我脸上。我惊讶地摇摇头。“好的,谢谢,”然后我继续我的长度。
你赶上我了。我们怎么知道反物质真的存在?
大爆炸理论预言了这一点。一开始,有很多能量。那种能量变成了物质和反物质粒子,就像反向爆炸一样。
然后物质和反物质再次湮灭为能量。但是不知何故留下了一点物质。我们是由物质组成的,我们之所以存在,只是因为其中一小部分神秘地存活了下来。
大爆炸应该在早期宇宙中创造了等量的物质和反物质。但事实并非如此
home.cern](https://home.cern/science/physics/matter-antimatter-asymmetry-problem)
“你的意思是,我们只是许多疯狂爆炸的残留物,”
原则上,是的。我们不知道为什么一些物质被遗留下来并形成了我们今天所知道的宇宙。以及为什么太空中几乎没有反物质了。
但是,如果费米实验室和欧洲粒子物理研究所的人正在制造反物质,难道他们不能把我们都毁灭吗?
不,他们制造的反物质太少了。此外,他们总是确保一切都非常安全。
“他们为什么要制造反物质?”
因为我们想知道它是如何工作的!以及它的性质是否与普通物质有所不同。这就解释了为什么大爆炸后会有物质残留。
欧洲粒子物理研究所基础实验的实验装置。由基地合作提供
但是尽管所有的实验努力,物质和反物质似乎是完全一样的。唯一的区别是它们的电荷相反。例如,质子带正电荷。反质子带负电荷,但数量完全相同。
人们测量电荷和反物质的其他属性吗?
是的。欧洲核子研究中心的基地合作是致力于这个问题的小组之一。他们将测量技术改进到令人印象深刻的程度。但是,即使在这种精确的水平上,物质和反物质似乎具有相同的属性。事实上,当我开始我的物理学家生涯时,我在那里实习了几个月。
物理学家正试图揭开我们这个时代最大的谜团之一。Billy Huynh 在 Unsplash 上拍摄的照片
哦酷!但你没有解决问题。
没有。而且不知何故,太空中也没有足够的反物质来解决这个问题。
太空中有反物质吗?
是的。来自外太空的宇宙射线由反物质组成。但它们不含那么多。总的来说,我们只在太空中发现了极小一部分反物质,相比之下,如果今天宇宙中有相同数量的物质和反物质,我们会有所期待。
那么物理学家对此做了些什么呢?
甚至更多的研究!和开发新的研究工具。
比如什么?
大型强子对撞机(LHC)的实验,世界上最大的粒子加速器在欧洲粒子…
www6.slac.stanford.edu](https://www6.slac.stanford.edu/news/2018-08-01-particle-physicists-team-ai-solve-toughest-science-problems.aspx)
比如人工智能。它可以帮助 T4 探测反物质。建造足够灵敏的探测器来探测反物质粒子是非常困难的。
“为什么,”
因为探测器是由许多电子元件组成的。电子产品总是会产生噪音。探测器需要将这种噪音与反物质留下的信号区分开来。人工智能的建立极大地改善了这一点。
到目前为止,我们还没有发现物质和反物质之间的任何不对称。也许人工智能会改变这一点。
“但现在这是一个谜!”
的确如此。但我的复仇不是!”当我把一大股水泼到你脸上时,我哭了。
在 JavaScript 中使用 ObservableHQ 处理您自己的数据。
使用自定义数据和极少的编码知识定制数据可视化。
World Delaunay —代码输出示例:D. Ellis
介绍
大多数人都在努力学习一门新的编程语言并立即使用它。那么,当你看到一个很酷的网络可视化,并想为它改编代码时会发生什么呢——提示:这就是 ObservableHQ 的用武之地。
Observable notebooks 允许用户使用现有代码,只调整他们感兴趣的参数,并根据他们的特定需求定制可视化。这篇文章旨在描述一个过程,在这个过程中,你可以从众多可观察到的可视化中选择一个,应用你自己的数据,并把它们放在你自己的网站上。
可视化代码
在本教程中,我们将使用一个改编版本的迈克 Bostocks 世界机场德劳内图;
可观察的示例 Fork:世界机场 Delaunay Ref。@fil/geo-delaunay Ref。jasondavies.com/maps/voronoi/airports
observablehq.com](https://observablehq.com/@wolfiex/pyobservable-example)
并将其加载到网页中。
可观察的 API
方便的是,ObservableHQ 的优秀人员提供了一个用户友好的 API,我们可以利用它——让我们不必手动复制任何代码。首先,我们可以使用以下脚本替换相关的可观察用户和笔记本名称。
<!DOCTYPE html>
<body>
<script type="module">var user = '**wolfiex**' // our username
var nbk = '**pyobservable-example**' // our notebook nameasync function run(){const apistr = `[https://api.observablehq.com/@${user}/${nbk}.js?v=3`](https://api.observablehq.com/@${user}/${nbk}.js?v=3`)
const notebook = await import(apistr);
const define = notebook.default}run()</script>
注意:可以用 *import define from 'https://api.observablehq.com/@wolfiex/pyobservable-example.js?v=3'*
一步完成,或者下载笔记本和 *'./mynotebook.js'*
代替网址。
可观察运行时模块
我们需要做的最后一件事是导入运行时模块,它将用于运行我们的可观察脚本。这里我们补充一下
import {Runtime, Inspector} from "[https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js](https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js)";
到脚本的顶部
new Runtime().module(define, Inspector.into(document.body))
在我们定义了define
之后,在 run 函数内。
显示输出
要查看输出,我们可以将代码上传到在线平台(例如 github.io )或运行本地服务器。后者可以通过使用 node、electron 或 python(如果你安装了的话)来完成。
如果使用 python,您可以启动一个简单的服务器并导航到本地主机 URL 地址127.0.0.1:8000
。
python -m SimpleHTTPServer 8000
选择我们希望显示的内容
到目前为止,我们已经嵌入了可观察笔记本的所有单元,产生了下面这个笨拙的例子:
整本笔记本的杂乱进口
https://wolfiex . github . io/observable tutorial/base _ import . html
这里为了便于展示,我们只希望显示图像"chart"
和滑块"rotate"
。为此,我们在运行函数中修改了new Runtime
命令。
仅嵌入图表
我们首先只显示“图表”本身。这是通过用下面的代码片段替换运行时代码来实现的。
new Runtime().module(define, name => {
if (name === "chart"){return Inspector.into(document.body)()}
});
将元素添加到特定位置
工业中可视化的许多应用依赖于仪表板的创建。在这里,一个页面被分成许多部分,每个部分代表不同的信息。在本例中,我们首先创建一个新的 div 元素,并将其放在<body>
标签下面(脚本中是而不是)。
<div id='**topmost**' style='position:absolute;display:block'></div>
这里的样式告诉它,它可以占据整个屏幕,并坐在其他 DOM 元素的前面。默认情况下,这将在左侧。
我们现在更新运行时代码,以包括旋转滑块(viewof rotate)
。为了可读性,我们用一个switch
语句代替多个if
语句。
new Runtime().module(define, name => {
switch(name){
case "chart": return Inspector.into(document.body)();
case "viewof rotate": return Inspector.into(**document.getElementById('topmost')**)();
}
});
这里viewof rotate
被放置在带有id = 'topmost'
的元素内,而不是主体内。这会产生下面的输出,其中我们的滑块不再显示在图表下方。
对象选择输出
https://wolfiex . github . io/observable tutorial/selected _ display . html
更改单元格值和数据
我们已经获得了一组可视化效果,并将它们放在我们的网页上——但是我们如何改变它们的输入来匹配我们自己的数据呢?
在分叉笔记本时,我们最初在准备本教程时做了一些更改。其中之一是引入一个fillcolour
单元来确定每个圆圈的颜色。我们从探索如何改变这一点开始,然后继续提供额外的数据。
改变变量值(如颜色)
我们首先将新的运行时命令分配给一个变量名—我们将把它命名为main
:
**const main =** new Runtime().module(define, name => {
switch(name){
case "chart": return Inspector.into(document.body)();
case "viewof rotate": return Inspector.into(document.getElementById('topmost'))();
}
});
我们现在可以使用以下代码更改fillcolour
变量的值:
main.redefine("**fillcolour**", 'red');
为绘图提供新数据
目前,用于绘图的数据已经上传到 ObservableHQ 服务器。相反,我们可能希望在观想中使用我们自己的数据。在下面的示例中,我们已经在本地下载了airports.csv
文件(参见 points 单元格中的 URL ),并将在更新图表输出之前读入并编辑它。
为了简单起见,我们使用数据驱动文档(d3) 库来读取 CSV 文件。
这已经在笔记本中使用,因此可以在代码的运行时段中提取。或者,可以用下面的脚本导入:
<script src="https://d3js.org/d3.v6.min.js"></script>
我们现在能够加载文件并更新笔记本的点单元。为此,我们定义了一个“解析”函数来处理从 CSV 读取的数据。
为了区分数据集,我们还向经度添加了一个随机分量,并在使用main.redefine
函数将处理后的数据推入points
之前取 70%的纬度值。
function **parsedata**(data){ //convert to numerical and add randomness
data = data.map(({ longitude, latitude })=>
[+longitude**+Math.random()**, +**latitude*.7**])
// update points cell
**main.redefine("points", data );**
}
和任何好的代码一样,我们实际上需要运行它。这可以通过以下方式实现:
d3.csv("./airports.csv").then(**parsedata**)
编辑/自定义单元格值和数据
https://wolf iex . github . io/observable tutorial/local _ data . html
读取变量
有时,我们感兴趣的只是在计算/模拟过程中,每次可变变量发生变化时提取它的值。在这里,我们可以返回一些函数,而不是返回一个元素进行显示:
case 'my_mutable_varname':
return {
**fulfilled**(value) { console.log(name, value); },
**rejected**(error) { console.error(error); }
};
其中,上述每个功能的定义如下:
- 观察者。完成 ( 值),其中值是每次执行后的结果
- 观察者。如果评估失败,则拒绝 ( 错误)返回错误。
添加新的样式或变化
在本节中,我们希望应用尚未在可观察笔记本中定义的样式。例如,如果想要将旋转滑块移动到右侧,我可以从在 HTML 页面中定义一个 CSS 部分开始:
<style>
.right{
float:right
}
</style>
接下来,我们需要告诉导入的元素它属于这个类。为此,我们将开关中的 Inspector 语句更改如下。
*const main = new Runtime().module(define, name => {
switch(name){
case "chart": return Inspector.into(document.body)();* *case "viewof rotate":* var **item** = Inspector.into( document.getElementById('topmost'))();**item._node.className += ' right';
** return **item**; *}
});*
在这里,我们分解了 inspector 返回的元素,并且可以完全访问它的所有属性。虽然我们可以通过item._node.style
直接访问样式组件,如果我们有多个变更,或者希望将相同的变更应用于许多项目,但是定义一个类通常更容易。
结论
这是一个完全实时的可观察笔记本,我们把它改编成了我们自己的网页。
在本教程中,我们制作了一个我们感兴趣的可视化副本,然后将其嵌入到个人网站中,并更改了其中的变量/数据。
有关 observable notebooks 或 javascript 的更多信息,请查看文档中的信息部分:
浏览和可视化数据。分享和发表你的见解。发现并获得灵感。
observablehq.com](https://observablehq.com/collection/@observablehq/observable-documentation)
代码库
每个示例使用的代码可以在下面的链接中找到。这可以使用 node(如果安装的话)使用npm i;npm start
运行,或者使用本文中的 GitHub 链接查看。
描述如何将一个可观察的笔记本嵌入到网页中的 medium 文章的材料/ …
github.com](https://github.com/wolfiex/ObservableTutorial/blob/main/base_import.html)
资源:
笔记本是一个可移植的模块,可以集成应用程序的数据和用户界面。插图:剪贴画等…
observablehq.com](https://observablehq.com/@observablehq/downloading-and-embedding-notebooks) [## 可观察总部/运行时间
Observable runtime 让您可以在任何 JavaScript 环境中运行 Observable notebooks 作为真正的反应式程序
github.com](https://github.com/observablehq/runtime)
使用分析推动明智的直觉
现实世界中的数据科学
真正的价值在于知情的直觉,而分析在形成这一点上的作用是无价的
我真的相信数据和分析部门有责任在组织内做出更好的决策。很少有从业者会不同意这种观点,但是对于我们来说,真正推动我们的愿景,理解人们如何做出决策是很重要的。
人类的决策过程是模棱两可的,到了神秘的程度。研究人员都同意的一件事是所有的决定都带有情感因素,这触及了数据和分析功能的核心使命。如何利用数据来影响情绪,进而影响决策过程?
我倾向于认为,所有人都是基于一个或两个因素的组合来做决定的。这要么是直觉,要么是信息。
通过直觉做出的决定通常很快,人们甚至不考虑这个问题。这是相当哲学化的,意思是说基于直觉做出决定的人将很难解释其背后的推理。决策者常常会利用自己的感觉得出结论,而结论又是基于研究领域的一些经验。
另一方面,我们根据信息做出决策。这些决定是理性的——基于事实和数据,不幸的是,这也意味着它可能相当缓慢。决策者会经常使用报告、分析和指标来形成自己的结论。这种方法导致准确的、可量化的决策,意味着一个人可以清楚地解释背后的基本原理。
我最初的研究领域是冶金工程,作为一名应届毕业生,我在一家铁合金冶炼厂工作。我记得每当我们从熔炉中放出熔化的合金,并闻到它散发出的烟雾时,年长的守卫是如何脱掉呼吸防护装备的。他们还会观察合金缓缓流动的旗帜、胡须、或照亮合金上方空气的火花。根据这些指标,他们会建议更改输入材料。这是基于直觉的决策。他们使用他们的感官,但无法解释为什么他们会提出某些建议,然而这是基于多年的经验。
基于直觉和信息的决策的特征(图片由作者提供)
我对同样问题的态度略有不同。我要求从熔融合金中提取一份样本。然后需要冷却,带到实验室,如果幸运的话,几个小时后我就能拿到结果。然后,化学分析结果将被插入冶金质量平衡,根据这个模型的输出,我将对输入的材料进行更改。我的方法是基于信息的,除了基于化学基础的学术研究外,几乎没有经验支持。
那么,哪种方法是正确的呢?嗯,我发现在大多数情况下,就需要改变什么而言,老一代的守卫者是对的。然而,他们没有搞清楚的是如何量化这种变化。他们的方法导致过程中更快的变化,因此朝着过程控制的正确方向迈出了一步,但是,它也很容易在相反的方向上超出控制范围。我的方法更准确,但需要更长的时间来实现,这意味着该过程将在更长的时间内失去控制,然而,超调的可能性较小。哪种方法是正确的这个问题的答案是我们数据和分析部门需要非常清楚地了解的。
这两种方法不一定有冲突。我们应该接受这样一个事实:决策总是带有情感色彩,因此直觉总是比信息更值得信任。那绝对没问题。在某些情况下,我们根本没有浪费时间分析问题的奢侈。我们必须根据直觉迅速做出决定。这些决策不仅仅是战术性的——试想一位首席执行官需要快速决策,以确保在竞争对手抢先一步之前打入市场。
不过,在我看来,我们在数据和分析方面的作用永远不会被否定。我们总是要做出更好的决策,知道我们在决策过程中做了什么,这意味着影响情绪。我们不应该推动我们的组织做出信息驱动的决策,而应该推动信息直觉的议程。这是一个细微的差别,但价值是巨大的。通过肯定直觉,你也将能够塑造它,一旦这发生,直觉将被告知。
当我们考虑问题的高级分析解决方案时,同样的原则也应该适用。lens.ai 的创始人 Mike Bugembe 最近说,组织犯的一个 T2 的关键错误是期望数据科学家应该孤立地解决业务挑战。他提出了一个重要的观察,即成功的人工智能部署将人类经验与技术能力相结合。这证实了我们在数据和分析方法中对知情直觉的绝对需求和价值,因为我们永远无法编码所有人类经验或在决策过程中孤立情感。
总之,尽管组织应该有使决策自动化的雄心,并且主要在规定的领域中运作,但是它不应该低估工作经验的价值,以及随后基于直觉的决策。在自动化决策不可行或不可能的情况下,应该使用数据来通知直觉,并有希望对其进行加工以改进决策。
通过 TigerGraph 使用 API 数据
从 PokéAPI 中提取数据并构建图表
为什么这很重要?
不幸的是,并不是互联网上的所有数据都是打包好的 CSV 文件。事实上,人们可能经常希望使用流行 API 中的数据,但是如何将这些数据加载到图形中呢?
议程
- 看看 PokéAPI 数据集
- 创建图表
- 将数据从 API 加载到您的图表中
步骤 0:设置
在这篇博客中,我们将使用 Python 3(更确切地说是 Python 3.6.9)、requests、json 和 pyTigerGraph。你既可以在 Colab 上创建一个笔记本,也可以在你的本地计算机上运行它,但是,为了这节课的目的,我建议你使用 Colab。
如果你还没有,你需要安装 pyTigerGraph。如果您使用的是 Colab,以下是安装方法:
!pip install pyTigerGraph
在这篇博客中,我们使用的是 pyTigerGraph 的 0.0.9.6.2 版本。
接下来,你要确保你已经准备好了一个盒子。如果您还没有准备好盒子,请执行以下操作:
- 转到http://tgcloud.io/。
- 单击我的解决方案。
- 单击创建新解决方案。
- 点击“空白图表”
- 通过步骤 1-4 获得一个免费盒子;记下你的域名。
- 单击“开始解决方案”
步骤 1:探索 PokéAPI
首先,我决定使用 PokéAPI。对于那些不知道的人来说,神奇宝贝是一种流行的视频游戏和卡牌游戏,玩家收集类似动物的生物(被称为神奇宝贝)并与之战斗。
出于此图的目的,我们将添加:
- 神奇宝贝名称
- 神奇宝贝类型(水、火等。)
接下来,我们将探索数据。文档位于此处:https://pokeapi.co/docs/v2。更具体地说,我们将关注神奇宝贝端点。
神奇宝贝 API
我们将使用 Python 来创建我们的图表。我们将使用的三个库是 requests(发出请求)、json(很好地打印我们的数据)和 pyTigerGraph(处理与图形相关的一切)。
import requests
import json
import pyTigerGraph as tg
接下来,看看 API 的神奇宝贝部分。在本例中,向链接 https://pokeapi.co/api/v2/pokemon/12/.发出了一个 GET 请求,让我们在 Python 代码中模仿一下:
URL = "https://pokeapi.co/api/v2/pokemon/12/" # URLres = requests.get(url = URL).json() # Makes the GET Requestprint(json.dumps(res, indent = 2)) # Printing the Results
这应该会打印出一个大的 JSON 对象。我们可以通过以下方式查看物种和类型:
print(res["species"])print(res["types"])
步骤 2:在 TigerGraph 中创建图形
首先,在 TigerGraph Cloud 中启动一个空白解决方案。记下你的域名!然后,在您的代码中,创建连接:
conn = tg.TigerGraphConnection(host="https://DOMAIN.i.tgcloud.io", password="tigergraph", gsqlVersion="3.0.5", useCert=True)
我们将使用 GSQL 来创建图表。在这个例子中,我们需要两个顶点:口袋妖怪和类型。这些应该用一条边连接(POKEMON 类型)。让我们将它添加到代码中:
# Sets up connection with GSQLprint(conn.gsql('ls', options=[]))# Create Edges (POKEMON_TYPE) and Vertices (Pokemon and Type)print(conn.gsql('''CREATE VERTEX Pokemon (PRIMARY_ID name STRING) WITH primary_id_as_attribute="true"CREATE VERTEX Type (PRIMARY_ID type STRING) WITH primary_id_as_attribute="true"CREATE UNDIRECTED EDGE POKEMON_TYPE (FROM Pokemon, TO Type)''', options=[])) print(conn.gsql('''CREATE GRAPH pokemon(Pokemon, Type, POKEMON_TYPE)''', options=[])) # Create the Graph
TigerGraph 云上的模式
您现在已经创建了图表!该加载数据了!
步骤 3:从 API 加载数据
首先,您需要通过更新 graphname 和添加令牌来更新您的连接凭据。
conn.graphname = "pokemon"conn.apiToken = conn.getToken(conn.createSecret())
现在,我们将尝试向我们的图表中添加一个神奇宝贝 butterfree。这将使用我们上面提出的请求。
URL = "https://pokeapi.co/api/v2/pokemon/12/" # URLres = requests.get(url = URL).json() # Makes the GET Requestprint(json.dumps(res, indent = 2)) # Printing the Results
为此,我们将把数据“上传”(我想你可以认为是“上传”)到 TigerGraph 中。首先,我们将增加物种到口袋妖怪顶点。
conn.upsertVertex("Pokemon", res["species"]["name"], attributes={"name": res["species"]["name"] })
厉害!接下来,我们将遍历这些类型,并将神奇宝贝连接到它的所有类型。
for ty in res["types"]: conn.upsertVertex("Type", ty["type"]["name"], attributes={"type": ty["type"]["name"] }) conn.upsertEdge("Pokemon", res["species"]["name"], "POKEMON_TYPE", "Type", ty["type"]["name"])
如果一切正常,恭喜你!你完了!现在你可以添加更多的神奇宝贝到你的图表中:
for i in range(1,100): # You can change the number based on how many Pokémon you want to add URL = f"https://pokeapi.co/api/v2/pokemon/{i}/" # URL res = requests.get(url = URL).json() # We don't have any parameters. conn.upsertVertex("Pokemon", res["species"]["name"], attributes={"name": res["species"]["name"] }) for ty in res["types"]: conn.upsertVertex("Type", ty["type"]["name"], attributes={"type": ty["type"]["name"] }) conn.upsertEdge("Pokemon", res["species"]["name"], "POKEMON_TYPE", "Type", ty["type"]["name"]) print("Added " + res["species"]["name"])
前往 GraphStudio,您可以在那里查看您的图形外观!如果所有东西都装好了,那么你做到了!恭喜你。
探索一番后会是什么样子!
第四步:轮到你了!
既然我们已经完成了这个示例,那么就轮到您来探索了!挑选出任何 API,然后使用 pyTigerGraph 创建一个图形。您甚至可以尝试调用额外的端点,继续增强图形!你已经得到了这个,我很高兴看到你会开发什么!
资源
可以在 Google Colab 上查看该项目:https://Colab . research . Google . com/drive/1 eibetcgq 18 tvp 9 _ dflgjiv3 edcum 5 hs?usp =共享
利用人工智能管理城市交通:用 k-NN 算法分类
利用人工智能管理城市交通:基于 K-近邻算法+可视化工具的分类
[## 视频片段:see tala eet hala-Tuhan Sapumanage:交通系统插曲
观看 Tuhan Sapumanage 展示他的人工智能解决方案
介绍
作为我学术研究的一部分,我参加了名为“人工智能(AI)和人机界面(HCI)”的模块,在该模块中,我有机会提出一个人工智能系统,该系统可用于指导大都市地区的交通,以及一个仪表板,该仪表板可用于向控制中心可视化交通流状况。
后来,在 2019 年 12 月,我应邀成为斯里兰卡国家电视频道黄金时段电视节目的演讲嘉宾,该节目旨在让年轻人有机会就我们面临的一些当代问题发表意见,在当天的主题为“交通系统”的演讲中,我提出了解决方案,作为我的 5 部分解决方案的一部分。所以让我们开始吧。
关于系统— I n 非技术简化语言
不管你住在哪里,都市区的交通显然是一个在许多方面影响我们的主要问题。在微观层面上,它使我们的日常安排被高度打乱,而在宏观层面上,它造成了巨大的经济损失。更不用说,还有拥堵带来的固有的环境污染,这在《电讯报》[ 1 ]的文章中有很好的解释。
虽然有许多想法和解决方案来改善交通流量,但没有多少显示出有希望的结果。因此,作为评估的一部分,我们被要求提出一个全面的基于人工智能的解决方案来解决上述问题。
我想到的是一个集成的解决方案,它有两个主要组件。人工智能系统和一个易于理解(和直观)的可视化工具。
AI 组件用于对拥塞的严重性进行分类(标记)。一旦人工智能系统决定某个特定的路口拥堵,它就会通过使用现有的交通灯网络向司机发出信号,决定将流入该路口的交通重新路由到下一个最佳替代方案。
更不用说,最好的部分是,该解决方案的设计方式不需要额外的专用基础设施,因为所需的输入可以由大都市的 CCTVs 获取,如上所述,交通指挥可以由现有的交通灯网络完成,前提是它们可以兼容连接。从而使其在经济上更加可行。
下一个主要组件是可视化工具。受苹果设计原则和史蒂夫·乔布斯设计哲学的启发,我确保减少混乱,使可视化工具易于理解和直观。这实际上充当了一个仪表板,可以放置在控制中心来监控交通流量和状态。
控制中心可以使用优化的界面来了解与交通流量和每个交叉点的当前状态相关的重要信息。来源:谷歌地图
该界面只使用了覆盖在地图上的圆圈(像谷歌这样的供应商会为地图这样做),并且只要求用户注意两个变量;圆的颜色和圆的大小。
圆圈的大小决定了特定连接的利用率百分比(从 0–100%)。也就是说,那里的车辆数量与可能的最大数量相比。而圆圈的颜色决定了拥堵的严重程度,拥堵程度是根据过往车辆的平均速度计算出来的。
关于系统——极客的技术信息
为了开发这个系统,我们首先创建一个样本。我们使用现有的闭路电视基础设施,并向人工智能系统输入车辆移动的平均速度和在给定路口的车辆数量。接下来,我们找到相关专家,请他们尽最大努力对初始样本进行分类。他们将速度分为不同的范围,他们认为交通流是自由流动的,缓慢的和拥挤的。接下来是利用率百分比,他们可以给出使特定路口畅通、缓慢和拥堵的车辆数量。两者都是数字数据。速度是每小时英里数/公里数,利用率百分比也是一个数字百分比。
接下来,基于 k-最近邻(k-NN)的人工智能模型可以针对每个交叉点的这种数据进行训练。在此之后,当应用于现实世界时,它应该能够分类一个路口是否拥堵(理想情况下是实时的)。每当人工智能系统决定一个特定的路口是拥挤的,它就会查看可选选项表。
备选路径表是一个包含交汇点 ID 和一组优先备选路径的表。一旦最初的路口出现拥堵,软件会在考虑新定向的交通后,计算下一个最佳替代方案的预计拥堵情况。它这样做,直到找到具有最小潜在拥塞的替代方案,从而引导输入流量有效地避免拥塞。
不用说,该系统可以定期升级、检查和更新,以提高其准确性。
特别感谢我的考文垂大学人工智能讲师 Richard Hyde 博士指导我们完成该模块,并在整个模块中提供帮助,这使我能够以一等荣誉的分数完成该模块,并在三个批次中获得该模块的最高分。
这是该系统的另外两个特点…
考文垂大学学术合作单位脸书专题页面:Tuhan Sapumanage 人工智能 TVShow
Charana 电视台脸书版专题报道(描述):Tuhan Sapumanage —人工智能— TVShow
Charana 电视台脸书版专题报道(视频):Tuhan Sapumanage 人工智能 TVShow
参考文献
[1] 来自电报的文章
落款,Tuhan Sapumanage —计算机(英国)理学士,CIMA Adv Dip MA,研究员—机器学习,特邀演讲人—电视&主题演讲,Blogger—AI&商业/经济学,Toastmaster,Gavelier,MUNer & Compère
LinkedIn|Twitter|Medium|脸书|insta gram|research gate
利用人工智能探测新冠肺炎
人工智能工具可以帮助各州制定更具体的新冠肺炎病预防策略,改善公共卫生。
https://www.groupe-imagerie-medicale.fr/上的原始照片
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
2019 年底在中国出现,这种疾病是由新型冠状病毒引起的,这种病毒属于冠状病毒。
在检测到的数万例病例中,有几例新冠肺炎是无症状的。这种病毒最常见的症状是发烧和干咳。有些人可能还会感到疼痛、头痛、呼吸困难或急促。这些症状表明急性呼吸道感染或放射学可检测到的肺部异常。我们可以使用人工智能算法来检测疾病,使用自动 X 射线分析来支持放射科医生。
为了测试人工智能在检测新冠肺炎上的表现,我使用了约瑟夫·科恩博士的团队提供的数据库。该数据可在 GitHub 上获得。
该数据库包含 152 个观察结果,是根据新冠肺炎病例的胸部 x 光或 CT 图像构建的。
导入我们将要使用的包
我们将导入必要的包。使用的主要模块将是 keras 建模。
我们导入包含图像标签的数据库和元数据。
该数据库包含 127 个关于新冠肺炎病的观察结果、4 个 ARDS、2 个肺囊虫、6 个链球菌和 2 个无发现。
导入数据
我们将数据库分为两组:感染新冠肺炎病毒的患者和其他患者。
我们的观察 90%会用于学习,10%用于验证。由于我们拥有的数据有限,我们将使用数据扩充。
预处理
预处理是使成功的
识别概率最大化的步骤。
我们将导入图像,并将其调整为 224x224 格式。
对于建模,我们将使用 25 个时期和 8 个批次大小。预训练的 ResNet 模型将用于填充我们拥有的小图像。
对于迁移学习,其思想是使用对数百万幅图像进行训练的网络的最后一层,以填充我们可用的少数图像。
对于建模,我们将使用 ResNet 的迁移学习。
对于第一次建模,我们在验证中获得了近 80%的准确性,在学习中获得了近 75%的准确性。
在损失中,我们的价值很低。这一结果是在 50 帧的基础上获得的,可以通过更多的图像得到极大的改善。
与我们拥有的图像数量相比,建模的结果是好的。如果有足够的数据库可以达到良好的性能,这种方法可以推广,并使大规模进行新冠肺炎筛选成为可能。
来源:
[## 冠状病毒:症状、诊断、治疗| Familydoctor.org
冠状病毒是一种在动物身上发现的病毒,可以传染给人类。冠状病毒症状包括咳嗽…
familydoctor.org](https://familydoctor.org/condition/coronavirus/) [## 冠状病毒疾病 2019(新冠肺炎)-症状
如果你出现新冠肺炎的紧急警告信号,请立即就医。紧急警告标志…
www.cdc.gov](https://www.cdc.gov/coronavirus/2019-ncov/symptoms-testing/symptoms.html) [## 临床对话
播客:在新窗口播放|下载我们邀请到了 NIAID 的安东尼·福奇博士和我们一起谈论新冠肺炎,这种疾病…
podcasts.jwatch.org](https://podcasts.jwatch.org/index.php/podcast-256-anthony-fauci-talking-with-patients-about-covid-19/2020/03/10/) [## 构建 X 射线和 CT 扫描的公共新冠肺炎数据集
在新冠肺炎疫情的情况下,简化诊断是否至关重要。去年,我们的团队开发了切斯特,一个…
josephpcohen.com](https://josephpcohen.com/w/public-covid19-dataset/) [## IEEE 8023/covid-chest Xray-dataset
我们正在用胸部 x 光或 CT 图像建立一个新冠肺炎病例数据库。我们也在寻找新冠肺炎病例…
github.com](https://github.com/ieee8023/covid-chestxray-dataset)
使用关联规则进行人力资源分析
或者:如何将 Apriori 用于购物篮商店分析之外的数据
米卡·鲍梅斯特在 Unsplash 上的照片
A 关联规则算法,如 Apriori 是一种很好的方法,可以找到数据集中经常出现的项目,并查看它们之间的关系。
这是一种无监督的机器学习模型,通常用于发现交易中的关系,例如客户购买。
如果一个项目的出现次数大于我们设置的阈值,则该项目被认为是频繁的。如果您有 100 行数据,并将阈值设置为 0.1,那么发生 10 次以上的所有数据都会显示在我们的结果中。
在这个例子中,我们将对不同类型的问题使用先验知识。我们将使用包含年龄、性别、教育水平等信息的人力资源数据集,我们将尝试找出员工没有流失时出现的常见特征。
首先快速回顾一下主要的先验要素:
支持 是一个项目出现多少次
freq(A,B)/Total置信度 是给定 A 发生的概率
freq(A,B)/freq(A)Lift 类似于 confidence 但这也说明了 B 有多受欢迎
freq(A,B)/support(A)*Support(B)
在本例中,我们将使用 Kaggle 的 IBM HR Analytics 员工流失和绩效,您可以从以下链接下载:
预测你有价值的员工的流失
www.kaggle.com](https://www.kaggle.com/pavansubhasht/ibm-hr-analytics-attrition-dataset)
这段代码将使用 MLxtend 库(http://rasbt.github.io/mlxtend/)用 Python 编写
首先,我们导入我们的库。这个项目只需要熊猫和 MLxtend 。
import pandas as pd
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
在阅读完数据后,我们可以看到有 35 列需要处理,但是我们将只使用我们认为更有趣的几列。
有几个使用起来不错的列,但是它们不是分类的,所以我们能做的是为它们创建库。Pandas qcut 函数可以为我们将年龄、离家距离和小时列分成 4 个箱。
pd.qcut(df['Age'], q=4)
这段代码向我们展示了年龄列可以分为以下四类:
类别(4,区间[float64]): [(17.999,30.0] < (30.0,36.0] < (36.0,43.0】<【43.0,60.0】]
因此,我们可以像这样创建一个 Age_Range 列:
df['Age_Range'] = pd.qcut(df['Age'], q=4, labels=['<=30', '>30 <=36', '>36 <=43', '>43'])
对 DistanceFromHome 和 HourlyRate 做了同样的操作后,现在我们必须为算法准备数据。Apriori 只接受布尔值,所以我们不会发送包含“单身”、“已婚”和“离婚”值的 MaritalStatus 列,而是将它转换为 3 个不同的列,分别称为“MaritalStatus _ 单身”、“MaritalStatus _ 已婚”和“MaritalStatus _ 离婚”,其中包含 0 或 1 值。
为此,熊猫 get_dummies 函数可以用于每个需要转换的列。首先,我们将创建一个包含所有将要使用的列的列表,以及另一个包含剩余列的列表。在使用 get_dummies 之后,原始列将被删除,只有布尔列会在那里,但是,未使用的列仍然在那里,所以我们删除它们。
columns = ['Attrition',
'Age_Range',
'BusinessTravel',
'Department',
'DistanceFromHome_Range',
'Education',
'EducationField',
'EnvironmentSatisfaction',
'Gender',
'HourlyRate_Range',
'JobInvolvement',
'JobLevel',
'JobRole',
'JobSatisfaction',
'MaritalStatus']not_used_columns = list(set(df.columns.to_list()) - set(columns))df = pd.get_dummies(df, columns=columns)df.drop(labels=not_used_columns, axis=1, inplace=True)
现在我们有了一个数据框架,可以使用并生成频繁项。
我们的数据集总共有 1470 行,所以让我们开始选择 0.05 的最小支持。这意味着只有在我们的数据中发生超过73 次的结果才会被考虑。而 max_len 是 antecedents 列中生成的列组合的数量。
#Apriori min support
min_support = 0.05#Max lenght of apriori n-grams
max_len = 3frequent_items = apriori(df, use_colnames=True, min_support=min_support, max_len=max_len + 1)rules = association_rules(frequent_items, metric='lift', min_threshold=1)rules.head(10).sort_values(by='confidence', ascending=False)
关联规则结果
就是这样!现在,您可以看到数据集中的频繁关系。
但是,如果我们只想知道在结果列中是什么给出了‘attraction _ Yes’还是‘attraction _ No’呢?
首先,让我们看看在我们的数据帧中每种情况出现了多少次。
df['Attrition_No'].value_counts()#1 1233
#0 237
#Name: Attrition_No, dtype: int64
否的情况比是的情况多得多,所以我们在选择阈值时也需要考虑到这一点,因为一个比另一个更常见。
对于否,让我们将阈值增加到 0.1,并过滤损耗 _ 否的后续列:
#Apriori min support
min_support = 0.1#Max lenght of apriori n-grams
max_len = 3frequent_items = apriori(df, use_colnames=True, min_support=min_support, max_len=max_len + 1)
rules = association_rules(frequent_items, metric='lift', min_threshold=1)target = '{\'Attrition_No\'}'results_attrition_no = rules[rules['consequents'].astype(str).str.contains(target, na=False)].sort_values(by='confidence', ascending=False)results_attrition_no.head(10)
关联规则结果在结果列中只有 attachment _ No
现在我们可以看到,在我们的数据集中,来自研发部门、工作级别为 2 的人出现的几率为 11%,然而几乎 95%的 都没有自然减员。
附注:前提和结果列是如下所示的冷冻集:
array([frozenset({ ' job satisfaction _ 4 ',' JobLevel_2'}),
frozenset({ ' Department _ Research & Development ',' JobLevel_2'}),
frozenset({ ' Department _ Research & Development ',' job inclusion _ 3 ',' job level _ 2 ' })……
如果您想美化它并导出这个结果,您可以使用这段代码:
df['antecedents'] = df['antecedents'].apply(lambda x: ','.join(list(x))).astype('unicode')df['antecedents'] = df['antecedents'].str.title().str.replace('_', ' ')
现在,让我们将阈值更改为 0.02,看看损耗有多少 _ 是:
关联规则结果在结果列中只有 Attrition _ Yes
信心最大的是 30 岁以下,单身,工作一级的人。但与前一个案例不同的是,这些案例中只有 45%的人出现流失。
这是对 HR 数据使用 Apriori 的基础!希望您在下一个项目中尝试一下,并在您的数据集中找到新的关系,这可以让您对您的问题有更多的见解。
你可以在这里下载所有用来创建这个帖子的笔记本:https://gist . github . com/eduardoftdo/e 3d 2 b 7 ca 4a 06 D8 d 86 b 144482d 0 aed 5 a 1
如果您有任何问题,并希望与我联系,请随时发送消息到 https://www.linkedin.com/in/eduardo-furtado/
利用注意力进行医学图像分割
探索最近两篇关于使用注意力进行分割的论文,获得一些直觉和一个简短的 PyTorch 实现。
注意力机制是过去几年深度学习研究的最热门领域之一,始于自然语言处理,最近出现在计算机视觉任务中。在本文中,我们将重点关注注意力如何影响最新的医学图像分割架构。为此,我们将描述最近两篇论文中提出的架构,并尝试给出一些关于发生了什么的直觉,希望它能给你一些如何将注意力应用到你自己的问题上的想法。我们还将看到简单的 PyTorch 实现。
彼得·卡斯普日克在 Unsplash 上的照片
医学图像的分割在两个要点上不同于自然图像:
- 大多数医学图像非常相似,因为它们是在标准化的环境中拍摄的,这意味着在方向、图像中的位置、像素范围等方面几乎没有变化
- 例如当试图分割肿瘤时,在阳性类像素(或体素)和阴性类之间经常存在很大的不平衡
注意:当然,代码和解释都是对论文中描述的复杂体系结构的简化,目的主要是给出一个直觉和一个好主意,而不是解释每一个细节。
1.请注意 UNet
UNet 是细分领域的首选架构,目前大多数细分领域的进展都以此架构为基础。在本文中,作者提出了一种将注意力机制应用于标准 UNet 的方法。如果你想重温一下标准的 UNet 是如何工作的,这篇文章非常适合。
1.1.提议的是什么
该架构使用标准的 UNet 作为主干,并且不改变收缩路径。改变的是扩展路径,更准确的说,是注意机制被整合到了跳过连接中。
注意事项 UNet 的框图,红色为扩展路径块。来源:注意 UNet:学习在哪里寻找胰腺
为了解释扩展路径的一个块如何工作,让我们把来自前一个块的对这个块的输入称为 g ,把来自扩展路径的跳过连接称为 x 。下面的等式总结了这个模块的工作原理。
上采样模块非常简单,而 conv 模块只是两个(卷积+批处理范数+ ReLU)模块的序列。剩下唯一需要解释的是注意力障碍。
注意模块的框图。这里的尺寸假定一个三维输入图像。来源:关注 UNet:学习去哪里寻找胰腺
- x 和 g 都被送入 1x1 卷积,使它们达到相同数量的通道,而不改变大小
- 在一个上采样操作之后(为了具有相同的大小),它们被相加并通过一个 ReLU
- 另一个 1x1 卷积和一个 sigmoid,展平为一个通道,对地图的每个部分给予 0 到 1 的重要性分数
- 然后,该注意图乘以跳过输入,以产生该注意块的最终输出
1.2.为什么有效
在 UNet 中,收缩路径可以被视为编码器,扩展路径可以被视为解码器。UNet 的有趣之处在于,跳过连接允许在解码器中直接使用编码器提取的特征。这样,当“重建”图像的掩模时,网络学会使用这些特征,因为收缩路径的特征与扩展路径的特征连接在一起。
在这种连接之前应用注意块允许网络将更多的权重放在相关的跳过连接的特征上。它允许直接连接集中于输入的特定部分,而不是馈入每个特征。
注意力分布乘以跳过连接特征图,只保留重要部分。这种注意力分布是从所谓的查询(输入)和值(跳过连接)中提取的。注意操作允许有选择地挑选包含在值中的信息。该选择基于查询。
总结一下:输入和跳过连接用于决定关注跳过连接的哪些部分。然后,我们使用跳过连接的这个子集,以及标准扩展路径中的输入。
1.3.简短实现
以下代码定义了(简化版本的)注意块和用于 UNet 扩展路径的“上行块”。“下行模块”与原始的 UNet 没有变化。
使用注意时,注意块和 UNet 的扩展路径块的简短实现。
注意:ConvBatchNorm 是 Conv2d、BatchNorm2d 和 ReLU 激活函数的序列。
2.多尺度引导注意
我们将要讨论的第二种架构比第一种更有创意。它不依赖于 UNet 架构,而是依赖于引导注意块之后的特征提取。
建议解决方案的框图。来源:医学图像分割的多尺度自引导注意
第一部分是从图像中提取特征。为此,输入图像被馈送到预训练的 ResNet,并且我们在 4 个不同的级别提取特征图。这很有意思,因为低级特征往往出现在网络的起点,高级特征出现在网络的终点,所以我们可以访问多个尺度的特征。使用双线性插值,所有的特征地图都被上采样到最大的地图的尺寸。这给了我们 4 个相同大小的特征图,它们被连接并馈入一个卷积块。这个卷积块(多尺度特征图)的输出与 4 个特征图中的每一个连接在一起,为我们提供关注块的输入,这比前面的要复杂一些。
2.1.提议的是什么
引导注意力模块依赖于位置和通道注意力模块,我们将从描述它们开始。
位置和通道注意模块框图。来源:医学图像分割的多尺度自引导注意
我们将尝试理解这些模块中发生了什么,但我们不会对这两个块中的每个操作进行太多的详细描述(这可以通过下面的代码部分来理解)。
这两个块实际上非常相似,它们之间的唯一区别在于试图从信道或位置提取信息的操作。在展平之前应用卷积会使位置更加重要,因为在卷积过程中通道的数量会减少。在通道注意模块中,由于在整形操作期间保持了通道的原始数量,因此通道的权重更大。
在每个区块中,重要的是要注意到顶部的两个分支负责提取特定的注意力分布。例如,在位置注意力模块中,我们有一个(WH)x(WH)注意力分布,其中 (i,j) 元素告诉我们位置 i 对位置 j 的影响有多大。在通道模块中,我们有一个 CxC 注意力分布,它告诉我们一个通道对另一个通道的影响程度。在每个模块的第三分支中,该特定注意力分布乘以输入的变换,以获得通道或位置注意力分布。与上一篇文章一样,在给定多尺度特征上下文的情况下,注意力分布然后乘以输入,以提取输入的相关信息。然后将这两个模块的输出逐元素求和,以给出最终的自我关注特征。现在让我们看看这两个模块的输出是如何在全局框架中使用的。
具有 2 个改进步骤的引导注意力模块的框图。来源:医学图像分割的多尺度自引导注意
引导注意力是通过对每个尺度(在建议的架构中为 4 个尺度)的一系列多个细化步骤来构建的。输入特征图被馈送到位置和通道输出模块,该模块输出单个特征图。它还通过自动编码器,自动编码器产生输入的重构版本。在每个模块中,注意力图由这两个输出相乘产生。该注意力图然后乘以先前产生的多尺度特征图。因此,考虑到我们工作的具体尺度,输出代表了我们应该关注多尺度的哪些部分。然后,通过将一个模块的输出与多尺度注意力地图连接起来,并将其作为下一个模块的输入,就可以得到一系列这样的引导注意力模块。
这里有两个额外的损耗是必要的,以确保优化步骤正确工作:
- 确保自动编码器正确重建输入特征图的标准重建损失
- 一种引导损失,它试图最小化输入的两个后续潜在表示之间的距离
然后,每个注意力特征通过卷积块来预测掩模。为了产生最终的预测,取四个掩模的平均值,这可以看作是各种尺度特征的模型的一种集合。
2.2.为什么有效
由于这个架构比前一个要复杂得多,所以很难理解注意力模块背后发生了什么。以下是我对各种模块的贡献的理解。
位置注意模块试图基于输入图像的多尺度表示来指定关注特定尺度特征的哪个位置。频道关注模块通过指定对哪个频道关注多少来做同样的事情。在任一个块中使用的特定操作在注意力分布中给予通道或位置信息更大的重要性。组合这两个模块给出了注意力图,该注意力图给出了每个位置-通道对的分数,即特征图的每个元素。
自动编码器用于确保特征图的潜在表示不会从一个步骤到另一个步骤完全改变。由于潜在空间是低维的,所以只提取关键信息。我们不希望这些信息从一个细化步骤改变到下一个,我们只希望进行小的调整。这些不会在潜在表象中被看到。
引导注意力模块序列的使用允许最终注意力图被细化,并且逐渐使噪声消失,并且给予真正重要的区域更多的权重。
将几个这样的网络以多种尺度组合起来,可以使网络具有全局和局部特征的视野。然后将这些要素组合成多比例要素地图。关注多比例要素地图和每个特定比例有助于更好地了解哪些要素会给最终输出带来更多价值。
2.3.简短实现
位置注意模块、通道注意模块和一个引导注意块的简短实现。
外卖食品
那么,从这些文章中可以学到什么呢?注意力可以被视为一种机制,它有助于根据上下文向网络指出哪些提取的特征需要关注。
在 UNet 中,这意味着,给定在扩展路径期间提取的特征,我们应该更加关注在收缩路径期间提取的哪些特征。这有助于使跳过连接更有意义,即传递相关信息而不是每个提取的特征。在第二篇文章中,给定我们正在工作的当前尺度,我们应该关注哪些多尺度特征。
一般的想法可以应用于广泛的问题,我认为看到多个例子可以帮助更好地理解注意力是如何适应的。
参考
[1] O. Oktay 等人《关注 UNet:学习去哪里寻找胰腺》(2018)
[2] A. Sinha 和 J. Dolz。“用于医学图像分割的多尺度自引导注意”(2020)
使用自动机器学习预测下一个将由食品药品监督管理局(FDA)批准的单克隆抗体(MAB)
目标
本实验的主要目的是通过学习从 Pubmed 获得的科学摘要,使用机器学习来预测哪种 MAB 将是下一个 FDA 批准的癌症治疗蛋白。这是一个基于 NLP 的二分类问题。
次要目标是评估自动化机器学习平台在实现主要目标方面能提供什么。来自加利福尼亚州 Mountainview 的人工智能初创公司 H2O.ai (www.h2o.ai)的商用 H2O 无人驾驶人工智能 AutoML 平台被选中。
癌症单克隆抗体市场
多年来,已经开发了许多治疗策略来研究、诊断和治疗癌症。方法像手术、化疗、放疗、骨髓移植、射频消融、激素治疗、靶向药物治疗、冷冻消融和免疫治疗是癌症患者的一些可用选择。
根据联合市场研究的数据,2017 年全球癌症药物市场价值约为 970 亿美元,预计到 2025 年将达到惊人的 1770 亿美元。如下图所示,一种称为单克隆抗体(MAB)的蛋白质类治疗药物价值约 410 亿美元:
生产单克隆抗体是一项极其费力、苛求、耗时且昂贵的工作。下图说明了 MAB 生产的简化工作流程,从发现癌症靶点到大规模生产,最后到医院治疗。
https://raw . githubusercontent . com/jonghang/jonghangassets/master/science/mab _ prod _ flow . png
数据
数据采集和处理
维基百科上发表的单克隆抗体列表被用作从 Pubmed 检索科学摘要的基础。该列表经过筛选,仅包含针对癌症的单克隆抗体。
Pubmed 搜索字符串的推荐格式用于检索摘要,如下所示:
<单克隆抗体名称>【TIAB】其中【TIAB】是检索包含搜索词的摘要和标题的搜索标签。例如,要检索 MAB 贝伐单抗的摘要,搜索字符串将是贝伐单抗【TIAB】
Pubmed 已经为 MATLAB、R 和 Python 提供了 API,使我们能够检索摘要。R API 是通过 easyPubMed 包使用的。
用于构造搜索字符串的 r 函数:
检索摘要有两个步骤:
步骤 1:检索 XML 文档:
步骤 2:使用相应的 XML 文档作为输入,通过组合每个 MAB 的多个摘要来创建数据框,添加可选的日期列,并通过唯一标识符 PMID 聚合数据:
每个 MAB 的数据框存储为单独的 CSV 文件。有 40 个 FDA 批准的单抗和 190 个未批准的单抗。检查所有 CSV 文件的质量和正确性。
然后将 CSV 文件合并成一个数据集。抽取其中的 1%作为样本外测试集。剩下的 99%按照 70:30 的拆分比例拆分为训练集和测试集,用于机器学习建模。
下图显示了数据采集和处理工作流程:
单克隆抗体的名字被用作停用词。在建立机器学习模型之前,将它们从摘要中删除以防止目标泄露。
数据定义
用于训练、测试和样本外评估的数据集具有以下模式:
训练集示例
自动机器学习(AUTOML)平台
本次实验使用的 AutoML 平台是前面介绍的无人驾驶 AI(DAI)H2O . AI(【】www . H2O . AI)。这是一个非常易于使用的平台,内置了最先进的机器学习算法和可解释性功能。进行这个实验是为了测试戴在处理基于自然语言处理的二元分类问题(如 Pubmed 文摘)时的表现。
H2O 无人驾驶人工智能(DAI)的实验设置
DAI 提供了一个友好、直观的界面来管理数据集和配置机器学习实验。
之前准备的相关数据集上传至 DAI,并出现在 DAI 中,如下所示:
通过指定要使用的训练集和测试集、要删除的训练集中的列以及要用作目标的列来开始实验:
戴为数据科学家配置机器学习实验提供基础和专家设置。基础设置中有 4 个配置选项— 精度、时间、解释性和计分器:
在引擎盖下,戴执行了一些分析,以便对每个默认选项的值给出建议。
准确性决定了在训练阶段执行渐进演化和集成时使用哪种 ML 方法。在低精度时,戴利用更多的特征和模型,允许它们相互竞争以获得最好的模型。无人驾驶人工智能以最高的精度执行模型和特征跟踪,并从所有这些变化中进行整合( H2O 无人驾驶人工智能文档)。
时间选项根据允许的迭代次数指定了相对时间,但是如果存在收敛,DAI 可能会执行提前停止。较高的数字可能会增加完成培训的时间。
可解释性选项指定了该实验的相对可解释性。更高的值有利于更易解释的模型。改变可解释性水平会影响特征预修剪策略、单调性约束和特征工程搜索空间。在较低的可解释性,戴可能会使用更多的和更复杂的数据转换器,否则在更高的价值。
记分员指出了该实验要优化的指标。AUC 是默认的,并且一直如此。可以很容易的被其他如精度,F1,F2 等代替。
戴提供了专家设置,允许数据科学家通过访问大量其他参数来更好地控制实验。在设置的模型选项卡中,我允许戴在整个培训过程中自行使用 XGBoost GBM 、 XGBoost Dart 、 LightGBM 和 Constant 模型,同时将 TenforFlow 模型设为强制。我认为 GLM、决策树、FTRL 和 RuleFit 模型不会提供任何优势,因此将它们关闭:
abstract_cleaned 列是唯一用于训练的列,这已成为 NLP 问题。因此,在 NLP 选项卡中进行了调整。用于 NLP 的内置基于单词的卷积神经网络(CNN) 和双向门控递归单元(BiGRU) 在基于字符的深度学习关闭时一直在执行。科学摘要的语言本质以及本实验的目的并不保证使用基于字符的 CNN 模型。
模型训练是通过点击启动实验开始的。从上传数据集到开始实验,持续时间约为 5 分钟。
开始一项实验
模型性能
模型构建完成后,会自动生成一份报告。它是作为 Microsoft Word 文档下载的。该报告描述了在该实验中构建的机器学习模型的性能。结果总结在下图中:
样本外评估
前面在数据处理工作流中描述过,1%的摘要被留出用于使用训练的 ML 模型进行样本外评估,以便数据可以尽可能接近地模拟看不见的数据。
使用阈值 0.5 将结果总结如下,其中P(FDA _ predicted . 1>= 0.5)为 1 否则为 0 :
新数据的预测
数据准备
使用单克隆抗体作为搜索关键词从 Pubmed 检索 2010 年至 2020 年发表的新摘要,如下所示:
单克隆抗体[TIAB]和“2010”[PDAT]:“2020”[PDAT]
共获得 5180 篇摘要,其中 4610 篇预测为 fda 批准的P(FDA _ approval . 1>= 0.5),570 篇预测为 FDA 未批准的P(FDA _ approval . 1<0.5)。摘要经过两个阶段的过滤:
包含用于摘要检索的 MAB 名称的摘要被排除以避免冗余
保留包含单词“单克隆”的摘要,以便仅使用与单克隆抗体研究相关的摘要
在上述过滤之后,摘要的数量减少到 1248 个,其中 980 个预测为 1,268 个预测为 0。
结果
预计将获得批准的前 10 位摘要发表于 2012 年 6 月 27 日至 2020 年 3 月 28 日之间。
通过目测预测为 1 的前 20 个摘要,用于乳腺癌和结肠直肠癌的抗表皮生长因子受体(抗 EGFR )似乎是有希望的候选者。另一个潜在的候选者是程序性细胞死亡-1 ( PD1 )是一种抑制性受体,表达在活化的 T 和 B 细胞上,靶向非小细胞肺癌。
总之,最有希望获得 FDA 批准的两种候选单克隆抗体是:
反表皮生长因子受体(反 EGFR)
程序性细胞死亡-1 蛋白(PD1)
预测摘要的层次聚类
FDA 批准的潜在 MAB 候选人现已确定。我不得不更深入地研究他们的科学研究,这些研究导致了这种候选单克隆抗体的发现。现在有可能使用数据科学技术从摘要中获取知识,而不必阅读摘要。我对预测为 1 的摘要进行了层次聚类,然后从每个聚类中提取出顶级术语,以确定是否可以从中获得新知识。r 被用来完成这项任务。
预测的 FDA 批准 1 被读入 R 数据框:
创建并清理了摘要语料库:
从语料库中移除稀疏术语并将其转换成文档术语矩阵(DTM):
DTM 被转换成便于聚类的数据框架:
由此产生的 DTM:
从 DTM 创建的数据框与源数据集相结合:
通过为后续聚类选择相关列,创建了一个新的数据子集:
使用所得到的分级模型作为输入来绘制树突图。对图进行视觉检查以确定 k 的合适值,k 是聚类的数量。当确定了合适的 k 时,在图中添加一条水平线,以指示它在何处分隔这些聚类:
提取聚类并将源数据集注入到每个聚类中,以便源数据集中的行接收相应的聚类编号:
我们创建了一个函数,通过对每个术语的频率求和来提取前 20 个术语:
产生的热门词汇如下所示。排除常见术语,如癌症、单克隆、使用等:
每个集群的顶级术语
从聚类中挖掘出的顶级术语似乎为研究 MAB 的背景提供了一些有用的见解,我们可以将这些见解转化为知识。我们能得到的大概知识如下:
集群 1 :新的单克隆抗体靶向抑制剂正在开发中。
集群 2 :针对结肠直肠癌和患者生存的抗 EGFR 单克隆抗体正在研发中。
簇 3 : PD 1 和 PDL1 是正在/已经通过在基因水平上研究其表达而开发的 MAB 靶标。这项研究涉及对免疫细胞/系统的研究。
集群 4 :可能涉及细胞周期检查点的抑制剂研究
以下目标有望获得 FDA 对癌症治疗药物的批准:
- 表皮生长因子受体(EGFR)
- 程序性细胞死亡-1
- 程序性细胞死亡配体-1(L1)
- 免疫检查点抑制剂
利益
我们可以从这项工作中获益。以下是其中的一些:
学术:学术研究人员能够计划和修改研究领域,目标和避免冗余。这有助于他们充分利用研究基金。有抱负的研究生可以在选择研究课题和导师方面做出更好的决定。
投资者:投资者能够确定投资哪个 MAB 和哪个机构,以加快新 mab 的开发。这可能会减少开发时间,增加临床试验和上市的时间。
政府:作为一个向研究人员提供财政支持的机构,它能够相应地规划预算,将资金分配到哪里。政府也可以利用这些知识来改革教育、研究、人才发展政策。医院能够更有效地为临床试验和治疗规划床位。
使用 AWS DMS 跟踪 MongoDB
数据摄取
AWS DMS 作为一个持续的数据摄取工具。
AWS DMS 是一项旨在将一个数据库迁移到另一个数据库的服务。无论是本地数据库到 AWS RDS 还是 AWS EC2(自管理数据库)到 RDS。目的很简单,并且假设迁移通常是短期的。DMS 不仅允许迁移整个数据库,还允许在满载时连续复制更改的数据。
从技术上讲,对迁移任务的持续时间没有限制。拥有一个本质上无限运行的迁移任务意味着它可以用于将数据库更改流式传输到 S3。因此,让我们来看看 DMS,以及我们如何使用它来填充我们的湖泊。
AWS 数据库迁移服务
DMS 服务概念相当简单,使用起来也很简单。如果默认值保持不变,则简单。有三个主要组件:端点、复制实例和任务。
端点
端点定义了到源和目标的连接。端点可以被配置为源或目标,以便限制误用。支持各种数据库,包括 AWS DocumentDB 和 S3。
任务
任务定义将哪个源端点迁移到目标。每个任务可以将一个源迁移到一个目标。端点可以在多个任务中引用。任务还定义了是执行完整迁移还是持续复制,或者两者都执行。完整迁移会在目标系统中创建时间点快照,而持续迁移会将每个更改复制到目标系统。
还可以将任务配置为从目标中删除现有的表或将其截断。其他优化设置包括在迁移中包括和排除哪些模式和表。
任务可以在多个状态之间转换,这些状态可以恢复、暂停或重置任务。如果作为任务的一部分迁移多个表,那么如果需要,可以单独重新加载每个表。对于正在进行的复制,该任务还在内部维护一个检查点状态,用于恢复复制。
可以在每个任务中应用一些基本的转换规则。它们作用于模式、表或列,并允许重命名、删除或在名称中添加前缀和后缀。数据不能被操纵。
复制实例
这些任务需要在一些 EC2 实例上执行。DMS 不是无服务器的,但是配置只涉及创建一个实例。不需要也没有能力通过 SSH 访问实例,甚至管理它。除非需要进行大量转换,否则大多数任务都是内存受限的。DMS 实例家族是一个很好的起点。Cloudwatch 指标允许对此进行监控,并且应该用于测试和容量规划。
跟踪 MongoDB 到 S3
我假设您有一个运行副本集的 MongoDB 服务器。如果没有,您可以很容易地在 AWS EC2 或 ECS 中设置一个。我将在 EC2 上使用一个,这是我专门为这个演示设置的。
首先,我们需要创建端点。有两个:源和目标。源端点应该指向 MongoDB 主机,目标指向 S3 桶。
复制实例
首先创建复制实例使我们能够测试到源和端点的连接。实例的大小应该由内存和磁盘需求决定。限制每个实例复制的表的数量是一个很好的做法。
下面的屏幕截图显示了如何配置该实例。https://docs . AWS . Amazon . com/DMS/latest/user guide/CHAP _ replication instance . html # CHAP _ replication instance。正在创建
创建复制实例非常重要,因为复制任务无法在实例之间轻松迁移。建议使用多个复制实例,尤其是当您有多个源和 50 多个表/集合要复制时。
源端点
AWS DMS 支持大量数据源,包括所有 RDS 数据库类型、MongoDB 和 S3。
是时候创建到我们的源 MongoDB 集群的连接了。如果您有一个集群和路由器,不幸的是,您不能连接到路由器,因为无法访问oplog
集合。您需要选择一个实例进行复制。您可以选择一个辅助节点,以便写入群集的数据不受影响,但数据仍能正确复制。
对于这个演示,我有一个 MongoDB 实例运行在 EC2 实例的副本集中。下面的配置是一个例子。
有几个关键的配置选项值得讨论。首先是元数据模式。DMS 支持 MongoDB 的document
或table
模式。document
模式将操作日志和文档保存为 JSON,而table
模式将其保存为 CSV。使用table
模式,可以使用nestingLevel
作为NONE
或ONE
来指定要展平的级数。
接下来是_id as a separate column
或者extractDocId
。这允许提取文档_id
作为一个新列。如果这是 false(未选中)并且元数据模式被设置为document
,那么输出文件有一个包含 JSON 字符串的单列。使用extractDocId=true
,输出文件有两列 CSV 格式,第一列是_id
,第二列是字符串形式的 JSON 文档。稍后当我们查看复制任务输出时,这一点会变得更加明显。你可以在这里找到更多信息。
目标端点
AWS DMS 支持多种目标数据库类型和 S3。配置 S3 目标相当简单,如下所示。bucket folder
定义了每个表的前缀。
最重要的设置是Extra Connection Attributes
。这是针对任何目标的。您可以指定压缩、分隔符、格式等。AWS 文档对此非常详细,并提供了很好的示例。我发现CDC Path
不起作用,也许这是因为 DMS API 实际上不允许指定这个。
迁移任务
一旦定义了端点,我们需要定义一个迁移任务。迁移任务定义了哪些数据以及如何将数据从源端点复制到目标端点。迁移类型设置允许作为一次性加载或连续复制进行迁移。
这个Task Settings
很值得讨论。第一个选项是Target Table Preparation Mode
;这定义了写入目标表的行为。对于 S3,这是指前缀。Do Nothing
将添加数据,Drop Tables on Target
将删除所选表格的表格前缀,truncate
将删除表格前缀下的所有数据对象。这是任务中所有选定表的全局设置。
Include LOB Columns in Replication
控制迁移多大的二进制对象。BLOB/CLOB 字段类型可能包含难以迁移的兆字节数据。DMS 允许读取这种类型的截断形式,或者可以完全排除它们。通常情况下,Limited LOB mode
是最佳实践,但是,当目标数据库/系统能够处理这种数据类型时,也可以使用Full LOB mode
。不幸的是,S3 目标端点不支持完整的 LOB 模式。
Enable Validation
这是一个很棒的功能,但同样不被 S3 支持。对于其他数据库类型,DMS 允许验证所有数据都已被完整准确地复制。对于 S3,我们可以在查看指标时看到这一点。
简单地说,Control Tables
允许审计和记录 DMS 动作和状态。除了日志之外,这对于快速检查状态也很有用。
运行和监控任务
创建并启动任务后,数据将开始通过复制实例流动。请注意,任务创建后,复制实例不能更改。如果您需要在新的复制实例上运行任务,则需要创建新的任务。
下面是 DMS 提供的一个监控的框架,碰巧相当详细。我的 MongoDB 源代码是一个带有模拟数据的小实例。所以只有几百份文件。然而,很明显,表/集合级别的监控是可能的,并且几乎可以通过 CloudWatch 即时更新,包括所有的插入、更新和删除。满载和 CDC 指标也在任务级别单独提供。EC2 指标以及这些指标可以决定在每个复制实例上运行多少任务,以及实例类型是否需要更新。
摘要
希望本指南为您提供了一个关于 DMS 的良好起点,以及它不仅可以用于数据库迁移,还可以用于数据湖的数据接收。我已经向您展示了一个连接到 MongoDB 的示例,但是,您也可以连接与 MongoDB 兼容的 DynamoDB!随着 DMS 和 DynamoDB 新版本的发布,这将增加更多功能,包括 CDC 复制。由于 DMS 是一项托管服务,因此它更易于操作,并提供了与 Cloudwatch 的完全集成,用于监控和警报。
将数据从 Python 同步到 AWS RDS
通过一个简单的 Python 脚本,我们可以将数据帧传输到 AWS RDS 数据库中的一个表中。
麦克默里朱莉在 pixabay.com
什么是亚马逊网络服务?
亚马逊网络服务是亚马逊公司提供的云平台。它是数据科学家和数据工程师等职位发布中最常强调/最受欢迎的平台之一。当今世界,随着大数据的日益增长,云平台变得越来越重要。除了灵活性、速度和实用性之外,像 AWS 这样的云平台是建立在你用多少就花多少的哲学基础上的,它们的可扩展成本。很多创业公司,世界巨头,政府机构都用 AWS。
什么是 AWS RDS(关系数据库服务)?
AWS RDS 是在 AWS 平台上创建传统数据库服务的服务。它可以安装得非常快,并立即站起来。在需要的范围内,你用多少就付多少。您可以根据增加的数据大小和调整您需要的速度。
如果在 AWS 上安装 RDS 系统,就不用和硬件打交道了。您不需要在数据库设置上花费太多时间,备份等操作是自动完成的。通常你只需要使用一些参数和能力。
AWS RDS 支持 AWS Aurora、PostgreSQL、MySQL、MariaDB、ORACLE、Microsoft SQL 数据库基础设施。
卡斯帕·卡米尔·鲁宾在 Unsplash 拍摄的照片
让我们开始在 AWS RDS 上创建数据库吧!
首先我们要开一个 AWS 账户。
我们需要进入 AWS 主页注册 AWS。进入该页面后,我们继续说创建一个 AWS 帐户。在所有步骤中,我们必须正确输入我们的信息,尤其是电子邮件地址。然后我们需要输入我们的付款信息。如果你没有超出限制,AWS 的一些服务是免费的。如果您输入了付款信息,请确保您没有超出这些限制。AWS 收取 1 美元的费用来验证您的支付帐户,然后将其退回。
有关详细信息,您可以按照步骤创建一个 AWS 帐户。
让我们进入 RDS 并创建数据库。
创建 AWS 帐户后,我们输入 RDS。
我们单击控制台左侧的数据库选项。我们通过在打开的页面上说创建数据库来迈出创建数据库的第一步。
我们需要在打开的页面上选择数据库基础设施。在本例中,我们将继续浏览 MySQL 。
对于我们的操作类型,我们现在选择免费层。
我们需要从 Settings 部分确定要创建的数据库名称、用户名和密码。我为这个例子创建了一个名为 experiment 的 db,并创建了一个名为 admincv 的用户。
Amazon 为要创建的数据库提供了一些标准特性。如果您是出于试用目的进行这项研究,为了不收费,最好不要打开存储自动缩放功能。如果你在亚马逊设定的限额内使用,就不会收费。
稍作等待后,系统将使数据库可用。然后在状态字段中显示为“可用”。
现在数据库出现了。
让我们进入我们创建的数据库。
这里,“连接和安全”区域中的端点和端口信息很重要,记下来很有用。然后将需要这些信息,以便我们可以从 Python 访问 DB。
现在我们切换到 Python,连接数据库!
1-我们下载我们的库。
import pandas as pd
import pymysql
from sqlalchemy import create_engine
2-我们输入我们的连接信息。
我们在主机区域输入上面的端点链接。我们需要选择 3306 作为端口。用户名是我们之前创建的“cvadmin”。密码是您为该用户创建的连接密码。我们的数据库名是“deneme”。在将它赋给数据库变量之后,我们完成了所有的操作。
host=’deneme.cykgvlpxbgsw.us-east-2.rds.amazonaws.com’
port=int(3306)
user=”cvadmin”
passw=”yourpassw”
database=”deneme”
3-我们通过收集连接信息来创建引擎。
以下代码中的 user、passw 等字段依赖于我们在上一步中创建的变量。
mydb = create_engine(‘mysql+pymysql://’ + user + ‘:’ + passw + ‘@’ + host + ‘:’ + str(port) + ‘/’ + database , echo=False)
我们将数据库中的数据打印出来。
我们用 name = "hisse "命令创建了一个表,现在我们可以打印我们拥有的数据。我有一个数据框架。它给出 Bist100 股票的每日价格。也可以用另一个 DF。
stockshistoricdata.to_sql(name=”hisse”, con=mydb, if_exists = ‘replace’, index=False)
让我们通过 DBeaver 检查数据是否打印在表上!
我们的数据现在在“hisse”表中。
结论
在数据科学项目中,为什么要将 Python 中的数据压入 AWS 上的数据库?你问这个问题是对的。如果你正在用大数据工作,如果数据在一个每日或每周新数据上,并且你的 python 代码工作几分钟或小时,这些情况可能是浪费时间。
为了避免这种情况,您用 Python 创建了一个脚本,这个新数据每天都打印这个表。它不会触及旧数据。您可以连接到“hisse”表,随时处理累积的数据。您可以通过打印一天的股票数据来节省时间和 CPU ,而不是从头开始创建所有数据。此外,多个人可以在同一个工作台上工作。
希望我写的东西有用。祝阅读愉快!
资源;
我的 Linkedin 个人资料;
https://www.linkedin.com/in/onur-okyol-ba253b72/
使用 AWS Sagemaker 和 Lambda 构建无服务器 ML 平台
构建一个无服务器的 ML 应用程序来预测 AWS 上的航班延误
AWS Sagemaker 徽标
大多数数据爱好者都知道如何构建和训练模型,但如何部署模型并使其在现实生活中有用,有时对于初学数据的科学家来说是一个具有挑战性的问题。幸运的是,有许多不同的平台和工具可以帮助模型部署。Amazon Sagemaker 是我的最爱之一,因为它大大减少了构建、训练和部署模型的努力和犹豫。在众多 AWS 功能和工具的帮助下,如 Lambda function、S3、Dynamo DB,构建一个工作的 ML 应用程序的整个过程只需点击一下鼠标。
在这篇文章中,我想演示我们如何利用 AWS 的能力来构建一个预测航班延误的无服务器 ML 应用程序。
目录
- 资料组
- 演示架构
- 创建笔记本实例
- 创建 Sagemaker 端点
- 创建 Lambda 函数
- 创建 API 端点
- 端到端测试
- 结论
资料组
该数据集来自美国交通部,包含 2018 年 721 万条飞行记录,共有 28 列。
https://www . ka ggle . com/yuanyuwendymu/airline-delay-and-cancel-data-2009-2018
由于数据量很大(721 万),我们使用 Google Bigquerry 进行数据清洗、预处理和简单的特征工程。由于这个项目的目的是演示 AWS 如何帮助模型训练和部署,我们不会花太多时间讨论如何用 Bigquerry 预处理数据(可能是未来的主题)。准备用于训练的已处理数据随后以 CSV 格式存储到 S3 存储桶中。现在我们可以开始在 AWS 上构建我们的演示了
演示架构
为了使这个应用程序有用,我们将利用 AWS API Gateway 和 Lambda 函数来构建一个 API,它接受包含航空公司信息的 HTTP POST 请求(一个真实的例子可能是一个将航空公司编号作为输入的应用程序或网站),POST 请求将触发 Lambda 函数来解析值,并将测试数据发送到部署了模型的 Sagemaker 端点。返回值将再次被 Lambda 函数解析,并将预测结果发回给用户。架构图展示了从用户输入到预测输出的端到端管道。
作者创建的架构图
创建笔记本实例
正如我们前面提到的,预处理的结果存储在一个 S3 桶中,以方便使用。但是,Sagemaker 可以使用不同渠道的数据。比如来自 AWS IoT 的 Dynamo DB、Aurora 甚至 IoT 设备数据。Sagemaker 还提供了各种工具来自动调整和选择模型。让我们首先在 Sagemaker 中创建一个 Jupyter notebook 实例。从 AWS 主页中,选择 service 并进入 Sagemaker。并且你会看到下面的选项,选择笔记本实例。
Sagemaker 控制台
如果你以前从未使用过亚马逊 SageMaker,在最初的两个月里,你可以在获得 每月 250 小时的 T2 免费等级。中号或者 t3。中型笔记本电脑用于构建您的模型,外加 50 小时 m4 。输入笔记本的名称和实例类型。如果您之前从未创建过 IAM 角色,请创建一个新角色或使用默认的 Sagemaker IAM 角色。IAM 角色控制实例的资源权限。
笔记本实例配置
亚马逊 SageMaker 内置了 Jupyter 笔记本,允许你用 Python、Julia、R 或者 Scala 写代码。我们将在这个项目中使用 Python 3。它还提供了笔记本实例启动时加载的示例笔记本列表。每个示例笔记本都有不同的用例,并包含每个步骤的详细注释。我强烈建议初学者仔细阅读这些笔记本,你会对如何使用 Sagemakers 有一个更好的想法。
Sagemaker 示例笔记本
现在让我们创建我们的笔记本,笔记本是基于乳腺癌预测. ipynb. 修改的,你可以通读原始样本。记得更改 S3 存储桶名称和 CSV 文件以匹配您的名称。
创建 Sagemaker 端点
最后一行代码将删除从笔记本中创建的端点,让我们先注释掉最后一行。然后,您可以通过点击 Run All 或使用 Shift 和 Enter 键逐步运行单元格来执行笔记本。通过运行笔记本,模型被训练和部署,并创建了一个 Sagemaker 端点。您可以从 Amazon SageMaker 控制台查看这个端点。您可以将默认端点名称更改为更有意义的名称。
创建 Lambda 函数
现在我们有了一个 SageMaker 端点。让我们创建一个 Lambda 函数来调用端点。它将解析 HTTP POST 请求,撤销 Sagemaker 端点,返回预测,解析结果并将其发送回用户。Lambda 可以使用 boto 3 sage maker-runtime . invoke _ endpoint()来调用端点
AWS Lambda 是一个有用的工具,允许开发人员基于每次使用的成本来构建无服务器功能。您还将受益于 FaaS 更快的开发速度、更简单的操作管理和可伸缩性。从 Lambda 函数中,从头选择作者。输入您的函数名,为此项目选择 Python 3.6。记住,选择 IAM 执行角色时,要使用一个策略,该策略允许您的函数调用 sagemaker 端点。
Lambda 功能配置
下面是 Lambda 函数的代码,它使用 ENDPOINT_NAME 作为环境变量,保存 SageMaker 端点的名称。记得在环境变量部分将变量分配给端点名称。
设置环境变量
import os
import io
import boto3
import json
import csv# grab environment variables
ENDPOINT_NAME = os.environ['ENDPOINT_NAME']
runtime= boto3.client('runtime.sagemaker')def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
data = json.loads(json.dumps(event))
payload = data['data']
print(payload)
response = runtime.invoke_endpoint(EndpointName=ENDPOINT_NAME,
ContentType='text/csv',
Body=payload)
print('res is !!!!')
print(response)
result = json.loads(response['Body'].read().decode())
print('result is!!!!')
print(result)
pred = int(result['predictions'][0]['score'])
#pred = int(result['predictions'][0])
predicted_label = 'delay' if pred == 1 else 'no delay'
return predicted_label
创建 API 端点
现在我们已经准备好了 Lambda 函数,让我们创建 API 来接收 HTTP 请求并集成一切。您可以按照 AWS 文档从 API Gateway 创建 API。或者只是按照这些简单的步骤。
- 打开 AWS API 网关控制台。选择创建 API 选择一个 API 名称,您可以将端点类型设为区域。选择创建 API。
创建新的 API
2.接下来,创建一个资源从动作下拉列表中选择,当资源被创建时,从同一个列表中选择创建方法来创建一个 POST 方法。
创建方法
3.在出现的屏幕上,输入以下内容:对于集成类型,选择 Lambda Function。对于 Lambda 函数,输入您创建的函数
4.设置完成后,将 API 部署到一个阶段。从动作下拉列表中,选择部署 API 。
部署 API
5.在出现的页面上,创建一个新阶段。并选择部署,这一步将为您提供调用 URL。
API 流程
端到端测试
现在我们已经构建了一个无服务器的 ML 管道,它可以从 HTTP POST 获取用户数据,并从我们部署的模型返回 ML 预测结果。我们可以在邮递员身上测试。Postman 是一个接口测试工具。做接口测试的时候,Postman 就像一个客户端。它可以模拟用户发起的各种 HTTP 请求,将请求数据发送到服务器,获得相应的响应结果,并验证响应中的结果数据是否与期望值匹配。现在,我们发送一个 POST 请求到上一步创建的调用 Url,它触发 Lambda 函数并调用我们的 Sagemaker 端点来进行预测。我们可以看到,我们得到的结果是“不成交”
邮递员测试
总结思路
AWS Sagemaker 是所有级别的数据科学家和 ML 应用程序开发人员实现健壮和完整的端到端 ML 解决方案的一个很好的工具。它可以自动化许多繁琐的工作,如超参数调整,模型选择,甚至数据标记。在 Lambda 函数的帮助下,ML 应用程序可以具有高度的灵活性和成本效益。
感谢您的阅读,我期待听到您的问题和想法。如果你想了解更多关于数据科学和云计算的知识,可以在 Linkedin 上找我。
参考
https://docs.aws.amazon.com/sagemaker/
在 Python 中为预定消息使用 AWS SQS
新闻捕手
如何开始使用 Lambda、S3 和 SQS 等 AWS 服务来创建新产品
Melanie Pongratz 在 Unsplash 上的照片
对于数据即服务产品来说,有时候,架构比想法本身更重要。这正是我们和朋友一起开发的产品的情况。Newscatcher 是一个 API,用于搜索在线发布的新闻文章。换句话说,我们从全球最受欢迎的新闻来源收集所有文章,将它们放在一个地方,并提供基于日期、来源和全文进行搜索的可能性。
到目前为止,我们已经发布了一个封闭的测试版。本质上,我们是开发者至上的团队,这就是为什么我们决定分享我们所经历的一切。Newcatcher API 的另一位创始人发表了一篇关于整个数据架构的文章。
两个人的团队在不到两个月的时间里为 200 名用户计划并发布了一个测试版,并且没有放弃他们的全职工作。
towardsdatascience.com](/launching-beta-data-product-within-two-month-with-aws-6ac6b55a9b5d)
我的目标是深入挖掘细节,谈谈产品的功能部分。解释数据管道,给出一些提示并揭示要避免的陷阱。我会努力让这篇文章既有趣又有用。如果您想知道如何构建相同的架构,也许您可以将它作为指南。
我们可以开始了吗?
挑战
让我们回到这个想法。我们希望构建一个包含最新新闻文章的 API。基点是每个在线新闻来源的 RSS 提要。 RSS 提要是简单的文本文件,包含文章的基本更新信息。几乎每个新闻来源都有一个储存标题、摘要、出版日期等信息的地方。我们的目标是创建一个数据管道,每小时从多个 RSS 提要获取信息。为了实现这个想法,我们面临一些简单的问题:
- 我们从哪里获得全世界成千上万新闻源的 RSS 提要?
- 如何每小时获取新文章?
- 我们把它存放在哪里,SQL 还是 NoSQL 数据库?
- 最快的查询方式是什么?
- 如何做一个 API?(是的,我们以前从未构建过 API)
为了回答第一个问题,我们使用了维基百科、 Alexa 和其他来源来搜集新闻来源网站和他们的 RSS 订阅。经过几个小时的手工清理,我们或多或少地获得了一些参考数据。csv 文件。一切都以. csv 开头。
下一步是每天多次使用 RSS 提要检索新文章。在这一点上,我们想出了使用 SQS 队列来逐步发送参考数据和获取文章更新的想法。它有两个主要优势:
- 容错。数据不是一个长时间的连续循环,而是通过成束的消息发送。一群人的错误不会影响其他人。日志中的错误很容易识别。
- 管理负载。易于管理其他服务的负载,如 DynamoDB 和 Elasticsearch。
SQS 队列和 AWS Lambda 串联完全符合我们的需求。多个 Lambda 函数可以同时启动。这意味着 lambda 可以接收每一串消息。公平地说,SQS 和 Lambda 函数的优势在数据管道中更加明显,我们接收 SQS 队列并将它们放入 DynamoDB 表中。在本文后面我们讨论 Lambda 函数的地方,只有一个用于发送 SQS 队列的函数。
现在让我们转到更技术性的部分。文章的下半部分包含了一个实际实现的生动例子。
数据管道
开始前的准备工作
在开始处理数据管道之前,需要完成一些步骤:
- 拥有一个 AWS 自由层账户
- 选择一个地区,对于您使用的其他服务,请选择该地区
- 使用 Linux 机器或创建一个 EC2 实例,该实例有权访问其他 AWS 服务
- 在您的 AWS 帐户上创建一个访问密钥
- 为此项目专门创建一个虚拟 Python 环境
- 安装 AWS CLI 并将配置为您之前创建的访问密钥
- 为 Python 安装
boto3
包
1.在亚马逊 S3 上提供数据
让我们从简单的事情开始。在 AWS 上打开 S3 服务,创建一个存储桶并上传您的。csv 文件在那里。恭喜你,三分之一完成了。
2.从传输数据。csv 文件到 NoSQL 表
如果您已经完成了前面提到的所有预安装要求,那么在访问不同的服务方面就不会有任何问题。
来自boto3
的资源和客户端
从现在开始,请记住,每次您想要使用 AWS 服务时,您都必须导入boto3
并建立适当的连接,无论是资源还是客户端。
我不知道何时使用它们中的每一个,试着阅读官方的文档或来自 Stackoverflow 的简短解释。对于您的项目,我们总是连接到 DynamoDB 作为资源,连接到 S3 作为客户端,连接到 SQS 作为客户端发送消息,并作为资源接收消息。
DynamoDB 中的表
还有一件事,你需要在 DynamoDB 中创建一个表。这并不困难:你进入 DynamoDB 服务,点击“创建表”。配置它的惟一方法是默认选择一个主分区键——这个变量对于每个观察都有一个惟一的值。如果您没有该变量,您可以创建两个变量 MD5 散列,这将为您提供一个唯一的 ID。例如:
将数据从 S3 发送到 DynamoDB 是一次性操作,如果您的数据没有被更改,则无需重复。该操作的代码片段从建立到所需服务的连接开始。
向 DynamoDB 发送数据的一种可能方式是通过一个字典列表,其中每个字典都代表来自您的。csv 文件。所以你需要一个函数来完成这项工作。每个变量将作为一个字符串发送。郑重声明你的。csv 文件的名称必须与您选择作为 DynamoDB 表主键的名称相同。
最后一部分是使用您之前打开的连接发送自身的过程。
你在if __name__ == '__main__':
下插入主代码,就可以把功能放在外面导入了。然后发射。虚拟环境中的 py。检查 DynamoDB 服务中表格上的“项目”选项卡。
3.向 SQS 发送参考数据
使用 AWS Lambda,我们将获取不可变的引用数据,并通过 SQS 将其发送给另一个 Lambda 使用。为了执行这个操作,我们需要创建一个 SQS 队列,以及具有所有权限的 Lambda 函数。
SQS 队列
这里没什么难的。您使用 SQS 服务并创建一个新队列。在标准和先进先出队列之间有一个选择。主要区别在于顺序:使用 FIFO 保存发送消息的顺序,而对于标准,不考虑发送消息的顺序。我们选择了标准的一个,我们真的不在乎顺序。
您还可以配置您的队列。该配置对您的主题和信息类型保持唯一性。在您的例子中,每条消息包含 6 个字符串变量。这里附上我们 SQS 队列的配置。
策略和角色
对于 Lambda 函数,最棘手的部分之一是 IAM 角色和策略。简而言之,一个角色就是一组策略。策略是授权一个服务对另一个服务执行的动作。一个角色可以附加多个策略。反过来,角色与服务相关联。您可以通过在现有策略中搜索来添加策略,也可以创建自己的策略。在下面的例子中,我们授权 Lambda 函数从 DynamoDB 表中检索信息,发送队列并离开日志。
λ函数
Lambda 的功能代码结构重复了步骤 2 中的代码,除了它不再是一次性的。对于我们的项目,这个函数是整个数据管道的起点。我们希望通过添加一个带有简单 cron schedule 表达式的触发器,让它每 30 分钟执行一次。
Lambda 函数的内部是这样的。
消息按照 SQS 队列的配置发送。我可以给你另一个建议。如果 SQS 的“交货延迟”选项不适合您,sqs.send_message
还有一个参数叫做DelaySeconds
。当您想要在 Lambda 函数中分离发送操作时,请使用此参数。例如,您有 10k 个观测值要发送,这些观测值将一个接一个地进行。取而代之的是,你将它们分成 5 个 2k 的片段,每个片段都有DelaySeconds=180
,你的下一个服务将会逐渐接收到它,而不会使你的平台过载。DalaySeconds
参数的最大限制是 900 秒,这就是为什么您总是必须根据零件数量删除 900,以获得队列组之间的最大延迟。
结论
希望你能在这篇文章/指南中找到有用的东西。你可以在我们的 Github 库上找到所有提到的代码。此外,我们已经发布了封闭测试版。如果您对新闻 API 感兴趣,注册,亲自测试我们的产品。
我计划写另外两个部分,分别是关于接收 SQS 消息、在 DynamoDB 上保存数据、使用 DynamoDB 流填充 es 索引、在 Flask 上创建 RESTful API 以及用 Zappa 安装 Gateway API 的测试版。注意安全,呆在家里。
使用 Azure Data Factory 基于 HTTP 上的 URL 模式增量复制文件
一个创新的 Azure 数据工厂管道,通过 HTTP 从第三方网络服务器增量复制多个文件
使用 Azure 数据工厂复制文件很简单;然而,如果文件被托管在第三方 web 服务器上,那么这就变得很棘手了,复制它们的唯一方法是使用它们的 URL。
在本文中,我们将看到数据工厂活动的一种创新用法,即动态生成 URL,通过 HTTP 获取内容,并将其存储在我们的存储帐户中以供进一步处理。
警告: Microsoft Azure 是一项付费服务,遵循本文可能会导致您或您的组织承担财务责任。
在继续本文之前,请阅读我们的使用条款:https://dhyanintech . medium . com/disclaimer-disclosure-disclosure-terms-of-use-fb3 BF BD 1e 0e 5
先决条件
- 有效的 Microsoft Azure 订阅
- Azure 数据工厂实例
- Azure 数据湖存储第二代存储
如果您还没有设置先决条件,请参考我们之前的文章,了解如何创建它们:
[## 使用 Azure 将 CSV 文件转换为 Power BI 视觉效果的权威指南
使用 Microsoft Azure 产品将新冠肺炎数据转化为惊人的 Power BI 视觉效果的分步指南。
medium.com](https://medium.com/@dhyanintech/a-definitive-guide-to-turn-csv-files-into-power-bi-visuals-using-azure-4483cf406eab)
本文将建立我们的数据工厂,从 GitHub 的新冠肺炎存储库中获取公开可用的 CSV 文件,GitHub 由约翰·霍普金斯大学系统科学与工程中心(JHU·CSSE)运营。我们对驻留在csse _ covid _ 19 _ data/csse _ covid _ 19 _ daily _ reports中的数据感兴趣。此文件夹包含每日病例报告,自 2020 年 1 月 22 日起,每天添加一次新报告。文件遵循一致的命名约定 MM-DD-YYYY 。战斗支援车
这是由约翰·霍普金斯大学运营的 2019 年新型冠状病毒视觉仪表板的数据存储库…
github.com](https://github.com/CSSEGISandData/COVID-19)
数据来源:GitHub 的文件列表(图片由作者提供)
为我们的项目获取这些文件的典型方式是从 GitHub 下载 zip 格式的存储库,在您的客户机上提取文件,然后手动将文件上传到我们的存储帐户。另一方面,如果我们希望我们的 Power BI 报告与新冠肺炎数据保持同步,我们必须每天上传一个新文件。我们希望找到一种解决方案来自动执行摄取任务,从而在无需额外手动操作的情况下保持数据最新。我们可以使用 Azure 数据工厂来实现这一点。我们的思考过程应该是:
- 创建一个从 GitHub 获取文件的管道,并将其存储在我们的存储帐户中
- 我们使用其 Raw URL 一次只能获取一个文件(在 GitHub URL 打开一个文件,点击 Raw 打开没有 GitHub UI 的文件):https://Raw . githubusercontent . com/CSSEGISandData/新冠肺炎/master/csse _ covid _ 19 _ data/csse _ covid _ 19 _ daily _ reports/01-22-2020 . CSV
数据源:获取 Raw URL(图片由作者提供)
- 回想一下,文件遵循一个命名约定(MM-DD-yyyy . CSV);我们需要创建数据工厂活动来自动生成文件名,即通过管道请求的下一个 URL。
- 我们需要多次重复这项任务;第一次,我们将获取存储库中已经存在的所有文件,然后每天一次。
- 使用 Azure 数据块转换接收的文件
活动通常包含 Azure 数据工厂工作的转换逻辑或分析命令,并定义对数据执行的操作。
管道是一起执行任务的数据工厂活动的逻辑分组。可以调度管道执行,或者可以定义触发器来确定何时需要开始管道执行。
延伸阅读:
[## Azure 数据工厂中的管道和活动— Azure 数据工厂
适用于:Azure 数据工厂 Azure Synapse Analytics(预览版)本文帮助您了解管道和…
docs.microsoft.com](https://docs.microsoft.com/en-us/azure/data-factory/concepts-pipelines-activities)
登录到 Azure 门户,找到并打开你的数据工厂。我们可以通过多种方式做到这一点:
Azure 门户:定位资源(图片由作者提供)
设置数据工厂组件
在概述页面上选择作者&监视器,以在新的浏览器选项卡中加载我们的数据工厂实例。切换到下一个标签页(我们的数据工厂),在左上角的菜单中选择管理。让我们从创建链接服务开始,告诉数据工厂我们的资源在哪里。
链接服务
链接服务就像连接字符串,它定义了数据工厂连接外部资源所需的连接信息。
我们需要创建两个链接的服务,第一个告诉数据工厂我们的数据源(即 GitHub)以及如何连接到它。我们需要提供 HTTP 地址( Raw 没有文件名的存储库 URL)作为基 URL(https://Raw . githubusercontent . com/CSSEGISandData/新冠肺炎/master/csse _ covid _ 19 _ data/csse _ covid _ 19 _ daily _ reports/)。遵循以下步骤:
Azure 数据工厂:创建链接服务(图片由作者提供)
Azure 数据工厂:创建 HTTP 链接服务(图片由作者提供)
第二个链接的服务告诉我们的数据工厂数据目的地(即存储帐户)。创建一个新的链接服务,在新链接服务刀片上搜索存储,从匹配的资源列表中选择 Azure Data Lake Store Gen2 ,点击继续。从下拉列表(4)中选择正确的存储帐户。
Azure 数据工厂:创建存储链接服务(图片由作者提供)
此时,您的屏幕应该如下所示。点击发布所有以保存您的更改,即保存。点击上的发布发布所有刀片,等待展开完成;可能需要几秒钟。
Azure 数据工厂:发布更改(图片由作者提供)
接下来,我们需要创建数据集来告诉我们的数据工厂使用什么数据及其格式。我们需要创建两个数据集链接到我们的两个链接服务。
数据集
数据集是数据的命名视图,它简单地指向或引用我们想要在活动中用作输入和输出的数据。数据集表示不同数据存储中的数据,可通过链接服务访问。
在左上角菜单中选择作者,在工厂资源刀片上找到数据集,点击显示的数字。选择新数据集并按照步骤创建我们的第一个数据集来表示我们的 GitHub 数据。
Azure 数据工厂:创建数据集(作者图片)
我们的新数据集将打开,显示进一步配置和定义我们的数据结构的选项。注意,连接选项卡下的基本 URL 填充了我们在链接服务中提供的原始文件夹 URL。我们的数据位于文件 URL,因此我们需要为数据工厂提供绝对 URL 来消费数据。我们将使用相对 URL 字段来导出文件的完整 URL(基本 URL +相对 URL)。然而,我们希望我们的管道获取多个文件;因此,我们将使用一个参数动态生成文件名,而不是提供一个简单的文件名。
我们可以使用参数将外部值传递到管道、数据集、链接服务和数据流中。通过参数化资源,我们可以每次用不同的值重用它们。
参数设置用于管道运行的整个持续时间。它们就像编程语言中的常量一样,定义在源代码的顶部。
切换到参数选项卡,点击 + New 创建一个新参数。如下所示设置字段;我们使用第一个 CSV 文件的名称作为默认值。切换到连接页签,将相对 URL 设置为@dataset().fileName
。
语法引用数据集参数: @dataset().PARAMETER_NAME
我们可以使用正确的语法键入参数名称,或者使用添加动态内容刀片来填充它(5–7)。
Azure 数据工厂中的动态内容使用表达式语言。
延伸阅读:
[## Azure 数据工厂中的表达式和函数——Azure 数据工厂
适用于:Azure 数据工厂 Azure Synapse Analytics(预览版)本文提供了有关表达式和…
docs.microsoft.com](https://docs.microsoft.com/en-us/azure/data-factory/control-flow-expression-language-functions)
Azure 数据工厂:创建和引用数据集参数(作者图片)
创建一个新的数据集来表示我们的存储帐户中的数据。遵循前面提到的步骤(在新数据集刀片上搜索Azure Data Lake Storage gen 2而不是 HTTP)。您的新数据集应该如下所示;发布所有更改,使它们可以在我们的数据工厂中使用。
Azure 数据工厂:创建数据集(作者图片)
既然我们已经满足了建立数据工厂的要求,那么是时候创建一个执行实际任务的管道了。让我们从从工厂资源刀片创建一个新管道开始(类似于创建一个新数据集)。
管道
为您的新管道命名,并在变量选项卡中创建两个类型为 string 和 01–22–2020 的变量(I 和 j)作为默认值。
变量可以在管道开始时设置,并在运行过程中读取和修改。变量在运行时包含实值,可以赋给参数。
它们就像编程语言中的常规变量。
Azure 数据工厂:使用变量设置管道(图片由作者提供)
活动
是时候将活动添加到我们的渠道中了;所有活动都可以在活动刀片上进行。我们将使用以下活动:
- 获取元数据:获取我们商店中存在的所有 CSV 文件的列表。最初,这将返回 null,因为我们的存储中还没有文件。该输出将作为下一个设置变量活动的输入。
- 设置变量 (1):用我们存储的最新文件名设置我们的变量 i 。最初,这将使用变量 j 的默认值(即 01–22–2020)设置 i ,因为从获取元数据活动的输入将为空。计算输出(变量 i )将作为下一个的输入,直到活动。
- 直到:生成从最近可用文件日期到今天的文件名,输入值 i 将作为开始日期,今天-1 将作为结束日期。生成的输出(变量 i )将作为下一个复制数据子活动的输入。
- 复制数据:通过 HTTP 复制实际的文件并存储到我们的存储器中。从到 activity(变量 i )的输入将被传递给我们的源数据集的参数 fileName,完成我们到原始 CSV 文件的 URL。该文件将通过 HTTP 访问,并保存到我们的存储。成功端将连接到我们的下一个设置变量活动。
- 设置变量(2 & 3):为下一次迭代增加变量 i 。我们需要两个设置变量活动,因为我们不能引用在值字段中设置的变量;因此,我们将使用变量 j 作为中间变量来增加 i 。
获取元数据
在常规类别下找到获取元数据,将其拖放到画布上。给它一个名字并继续,如下所示。
语法引用获取元数据活动的输出: @{activity('GET_METADATA_ACTIVITY_NAME').output.FIELD_NAME}
Azure 数据工厂:获取元数据活动(图片由作者提供)
设置变量(1)
在常规类别下找到设置变量,将其拖放到画布上。将其与获取元数据活动的成功(绿色)结束连接。给它一个名字,并如下设置变量 i
@if(empty(last(activity('ac_checkAllAvailableFiles').output.childItems)),variables('j'),formatDateTime(addDays(formatDateTime(replace(last(activity('ac_checkAllavailableFiles').output.childItems).name,'.csv',''),'MM-dd-yyyy'),1),'MM-dd-yyyy'))
点击值字段可以打开添加动态内容刀片;您可以键入或复制粘贴上面的表达式,或者使用 blade 的控件来创建表达式。
Azure 数据工厂:设置变量活动(图片由作者提供)
直到
将定位到迭代&条件类别下的处,将其拖放到画布上,并将其与之前设置的变量活动的成功结束连接。给它一个名字;在设置选项卡中,输入以下表达式:
@greater(dayOfYear(formatDateTime(variables('i'),'MM-dd-yyyy')),dayOfYear(subtractFromTime(utcnow(),1,'Day')))
移至活动选项卡,点击编辑图标添加其余活动。我们将在中添加其他活动,直到我们需要多次执行它们。单击编辑图标将显示一个空画布,表示我们现在正在向 Until 活动中添加要迭代的活动。
Azure 数据工厂:直到活动(图片由作者提供)
复制数据
在移动&变换类别下找到复制数据** a,将其拖放到画布上。给它命名,设置源和宿标签配置,如图所示。我们将用变量 i 给文件名参数赋值。下面是文件名表达式,方便复制粘贴:)**
@concat(formatDateTime(variables('i'),'MM-dd-yyyy'),'.csv')
Azure 数据工厂:用参数复制数据活动(图片由作者提供)
设置变量(2 和 3)
添加另一个设置变量活动。将其与复制数据活动的 s 成功结束连接。给它一个名称,并将变量 j 设置为
@addDays(formatDateTime(variables('i'),'MM-dd-yyyy'),1)
添加另一个设置变量活动,并将其与前一个设置变量活动的成功结束连接。将 i 设为@variables('j')
Azure 数据工厂:递增参数值(图片由作者提供)
我们的管道现在已经准备好了;它应该看起来像下面这样。此外,出于任何故障排除的目的,您可以参考本文末尾来自 GitHub 的我们管道的 JSON。
Azure 数据工厂:通过 HTTP 复制文件的管道
添加所有活动后的下一步是验证我们的管道。找到并选择 Validate 选项,以确保我们的管道没有错误并准备好执行。管道验证输出刀片将向我们显示验证的结果。
我们有两种选择来运行我们的管道和看到我们的劳动成果。我们可以调试运行我们的管道而不发布我们的更改,或者我们可以先发布我们的更改。建议先调试运行管道,然后发布更改;调试运行在管道的输出选项卡中显示 us 日志和其他有用的跟踪信息。花几分钟时间浏览输出日志,以清楚地了解执行和各种活动。示例输出如下所示。
Azure 数据工厂:典型的调试管道输出(图片由作者提供)
您还可以使用 Add trigger 选项立即运行管道,或者设置一个自定义触发器,以特定的间隔、时间或基于外部事件运行管道。
管道 JSON
结论
我们提出了一个通过使用 URL 在 HTTP 上复制数据的引人注目的问题。我们讨论了构成管道的各种组件,并建立了一个创新的数据工厂管道来解决手头的问题。我们还讨论了如何设置管道的自动执行,以及管道执行日志的简要概述。
后续步骤
如果您正在关注我们关于将 CSV 数据转换为 Power BI 视觉效果的系列文章,请阅读我们的下一篇文章,继续使用 PySpark 清理和转换 Azure Databricks 中的数据。
** [## 在 Azure Databricks 中将模式漂移的 CSV 文件清理并转换为关系数据
使用 PySpark 处理模式漂移文件并将其加载到 Azure Databricks 中的 Azure Synapse Analytics 数据仓库
如果您试图在您的数据工厂管道中添加和执行 Databricks 笔记本,我们有完美的东西向您展示。
[## 使用访问令牌在 Azure 数据工厂管道中执行 Azure Databricks 笔记本
关于如何使用 Azure Key Vault 安全访问在数据工厂管道中添加和执行 Databricks 笔记本的指南…
喜欢这个帖子?与 Dhyan 联系
让我们做朋友吧!你可以在 LinkedIn 上找到我或者在 Medium 上加入我。**
用 B 样条和 K 均值聚类时间序列
在时间序列数据中寻找趋势变得更加容易
斯蒂芬·道森在 Unsplash 上拍摄的照片
电子商务中的数据科学家不断发现自己在查看时间序列数据。在某些情况下,我们分析单个时间序列并开发预测模型。但是在的其他案例中我们正在回顾成千上万的时间序列,并试图找出有趣的模式。
处理一组时间序列可能会很尴尬。它们很难以有意义的方式聚集在一起。然而,使用 B 样条,我们可以简化我们的时间序列,更容易地进行探索性数据分析。
现实生活中的例子
假设您是一家大型在线零售商的数据科学家,您的任务是识别产品销售趋势。你可能会得到一个类似于的数据集,这个数据集在 UCI 知识库中。它包含 811 种不同产品的 52 周销量。让我们来看看随机抽样的产品及其标准化销售量:
一个趋势很明显。大多数产品经历了相对稳定的销售,而 3 个产品经历了零星的高峰。在这些时间序列中可能隐藏着其他趋势,但试图通过人工检查来发现它们将是非常耗时和无聊的。
我们可以通过 k-means 等无监督的机器学习算法来运行这些数据,但我们的结果可能会过度拟合。此外,重要的不仅仅是每周时间序列的值,还有相对的上下移动,这不会被这个表示所捕获。
因此,我们需要一种方法来以简洁的方式表示我们的时间序列,这种方法不仅可以捕获每周序列的绝对值,还可以捕获形状。这就是 B 样条的用武之地。
什么是 B 样条?
b 样条是一种通过使用多项式的分段组合来近似非线性函数的方法。在深入研究 b 样条之前,让我们先来看看数据集中的单个时间序列,并尝试用线性回归模型对其进行拟合:
虽然线性回归捕捉到了总体下降趋势,但它过度简化了系列中的模式。想象一下,如果不是一个线性回归,我们拟合两个回归模型,一个用于系列的前半部分,另一个用于后半部分。这可能会有所帮助。现在想象一下,如果我们拟合 52 个不同的回归模型,每个模型都适用于系列中特定的一周。虽然这个模型肯定会过度拟合,但它在描述原始系列方面做得很好。
在适合一个模型和适合 52 个模型之间可能有一个中间地带。这是 b 样条背后的思想——拟合一系列局部模型。
创建 B 样条逼近
b 样条有两个组成部分,一个基和系数。基础决定了超参数:使用多少个局部模型(称为结)以及在每个模型中使用什么次数的多项式。然后将系数乘以这个基数,以逼近原始数据。
b 样条基是一个对角矩阵,有 52 行——系列中的每个时间段一行,每个局部模型一列。我们可以创建一个 b 样条基,它使用 6 个局部模型或节点,并使用三次多项式,代码如下:
如果我们使用热图绘制该矩阵的值,我们会得到如下结果:
矩阵中的每一列都有唯一的非零值区间,这些区间共同覆盖了整个矩阵。因此,通过将矩阵中的每一列乘以不同的系数,我们将能够控制局部区间上近似的形状。下面是我们的 B 样条基的另一种表示。
通过使用不同的权重或系数组合这六个多项式,我们可以得到原始时间序列的非线性估计。我们可以使用最小二乘估计来获得最佳拟合系数。
这是一个比我们最初的线性回归好得多的近似值。接下来,让我们看看如何使用 b 样条来执行无监督学习。
B 样条聚类
上述 b 样条可以用 6 个系数来表示。想象一下,如果我们为原始数据集中的所有 811 个时间序列创建一个 b 样条近似。我们将有一个 811x6 的矩阵,比我们原来的 811x52 数据集维数低得多。
通过用不同的 K 值运行 K-means,我们看到对于 K 有几个好的选择,但是为了简单起见,让我们坚持 K=2
现在,让我们从原始时间序列中随机抽取一个样本,看看它们是如何用 K=2 进行聚类的
正如我们最初通过眼睛发现的,K-意味着区分具有持续销售的产品和具有大量零星峰值的产品。通过选择不同的 K 值,我们还可以识别时间序列中的不同趋势。我们来看看 K=5
此外,我们可以将我们的聚类的质心乘以基数,以查看每个聚类的平均时间序列。
摘要
B 样条提供了一种仅用少量数据点来表示时间序列的有效方法。当我们试图聚集数百、数千或数百万个时间序列时,这就很方便了。
在这个例子中,我们使用 b 样条来执行分割。我们发现了有趣的相似点和时间序列片段,可以用来为产品决策提供信息。但是相同的 b 样条近似也可以用于分类或回归。
参考和链接
[1] Github 完整代码在 Rhttps://Github . com/RoryMichelen/Medium-Articles/blob/master/Clustering _ w _ B _ splines . rmd # L42-L56
[2]数据集:https://archive . ics . UCI . edu/ml/datasets/Sales _ Transactions _ Dataset _ Weekly
利用贝叶斯分类器检测假新闻
有如此多的假新闻在流传,很难找到准确和未经捏造的消息来源。
照片由联合国新冠肺炎办事处通过联合国日内瓦办事处回应
有如此多的假新闻在流传,很难找到准确和未经捏造的消息来源。本文旨在使用朴素贝叶斯分类器对真假新闻进行分类。
什么是朴素贝叶斯分类器:
朴素贝叶斯分类器是一种确定性算法,它使用贝叶斯定理对数据进行分类。让我们看一个例子:
假设您想要预测今天下雨的概率:在过去的几天里,您通过观察天空中的云收集了数据。这是你的数据表:
此表显示了在下雨或不下雨的情况下,某个要素出现的次数。我们所拥有的实际上是一个包含下雨概率的表格,假设出现了灰色的云或白色的云。
现在有了数据,我们来做个预测。今天我们看到了灰色的云和没有白色的云,它更可能是一个雨天还是一个晴天?要回答这个问题,我们必须使用贝叶斯定理:
这个定理利用过去的数据做出更好的决策。
假设有灰色云,下雨的概率等于下雨的概率,乘以下雨的概率,除以灰色云出现的概率。
根据我们的数据:
P(B|A)(下雨的概率,给定灰色云)= 10/11
P(A)(下雨的概率)= 11/50+11 = 11/66 = 1/6
P(B)(灰色云的概率)= 1(灰色云已确认出现)
P(A|B) = P(B|A) * P(A) / P(B)
P(A|B) = 10/11 * 1/6 / 1
P(A|B) = 10/66
这是我们的结果!假设出现了灰色的云,下雨的概率是 10/66,也就是说,在 66 种不同的概率中,情景相同的情况下,有 10 种会下雨。
该项目:
简单介绍了朴素贝叶斯分类器之后,让我们来谈谈用朴素贝叶斯分类器检测假新闻。
假设新闻是假的,我们将统计一个词在标题中出现的次数。把它变成一个概率,然后计算标题是假的概率,与标题是真的相比。
我使用的数据集有超过 21,000 条真实新闻和 23,000 条假新闻。对于正常的数据集来说,这可能看起来不平衡,但这种不平衡对于计算初始概率是必要的:这是一个标题是假的概率,而不考虑它是什么。你可以联系我在 victorwtsim@gmail.com 的数据集。
代码:
import pandas as pd
import string
这是该程序的三个依赖项:pandas 用于读取 csv 文件,string 用于处理单词的大小写。
true_text = {}
fake_text = {}true = pd.read_csv('/Users/XXXXXXXX/Desktop/True.csv')
fake = pd.read_csv('/Users/XXXXXXXX/Desktop/Fake.csv')
这个脚本将读取两个数据集,其中包含假新闻和真新闻的实例。
def extract_words(category,dictionary):
for entry in category['title']:
words = entry.split()
for word in words:
lower_word = word.lower()
if word in dictionary:
dictionary[lower_word] += 1
else:
dictionary[lower_word] = 1
return dictionary
假设标题是假新闻,这个脚本计算一个单词出现的次数,并在字典中为每个单词出现的次数加一。
def count_to_prob(dictionary,length):
for term in dictionary:
dictionary[term] = dictionary[term]/length
return dictionary
该函数通过计算假新闻标题或真实新闻标题的总字数,将数字转换为概率。
def calculate_probability(dictionary,X,initial):
X.translate(str.maketrans('', '', string.punctuation))
X = X.lower()
split = X.split()
probability = initial
for term in split:
if term in dictionary:
probability *= dictionary[term]
print(term,dictionary[term])
return probability
该函数将相关概率相乘,计算出标题的“分数”。要进行预测,请比较使用假新闻和真实新闻词典时的得分。如果假新闻字典返回更高的分数,则该模型已经预测该标题是假新闻。
true_text = extract_words(true,true_text)
fake_text = extract_words(fake,fake_text)true_count = count_total(true_text)
fake_count = count_total(fake_text)true_text = count_to_prob(true_text,true_count)
fake_text = count_to_prob(fake_text,fake_count)total_count = true_count + fake_count
fake_initial = fake_count/total_count
true_initial = true_count/total_count
这个脚本使用上述所有函数为每个单词创建一个概率字典,然后计算标题的“分数”。
X = 'Hillary Clinton eats Donald Trump'
calculate_probability(fake_text,X,1)>calculate_probability(true_text,X,1)
这个最终脚本评估标题:“希拉里·克林顿吃了唐纳德·特朗普”,以测试模型。
True
该模型输出 True,因为标题显然是假新闻。
您可以改进我的计划的地方:
我创建这个程序作为一个框架,以便其他人可以对它进行改进。以下是一些你可以考虑的事情:
- 考虑短语和单词
一个单词本身没有意义,但是一个短语可以让我们更深刻地了解新闻是否是假的
- 通过网络搜集获得更大的数据集
网上有很多真新闻和假新闻的来源,你只需要找到它。
构建贝叶斯网络的主要启发式方法——项目管理评估实例
这篇文章展示了五篇论文的工作,其中项目管理度量与项目性能度量相关。我们使用在那些论文上发现的数据建立了贝叶斯网络(BN) ,并且我们在前面描述的标准下评估了结果网络。完成这项工作是因为我们想了解如何使用贝叶斯网络对项目管理系统建模,我们想知道哪些是最常见的限制,以及我们可以从以前的工作中获得哪些见解,目的是开发一个新的模型。
这不是对这些作品内容的批评,而是对这些研究在试图根据它们的信息来阐述 BN 时是如何有限的批评。在本节中,我们基于可靠的科学文献探索模型语义的重要性,并使用合格标准来确定构建真实贝叶斯网络的规则。
第一个限制:缺乏合成节点和概念结构
我们考虑的第一篇论文题为探索项目管理的价值:将项目管理绩效与项目成功(Mir&Pinnington,2014) 。为了实现这一目标,Mir 和 Pinnington 根据不同领域确定了关键项目的成功驱动因素。这些驱动器对应于 BN 的输入数据。此外,作者有一个抽样数据库,其中包括 4 周内收到的 154 份回复。****
我们可以通过选择具有中枢特征的 BN 来模拟 Mir 和 Pinnington 的研究(图 1)。在提出的因果模型中,没有合成节点。使用该 BN 的局限性来自于将标准视为从原因节点到项目成功节点的相互依赖因素的基本假设。使用该网络的主要限制来自于计算“项目成功节点的 CPT 所需的组合数量。这个数字可能太大,无法使模型足够精确。例如,如果每个节点有两种状态(真/假),项目成功节点将需要 4,096 个值来完成其 CPT。如果每个节点有五个状态,就需要 2.44 亿个值!该 BN 将失去其效用,因为完成“项目成功”节点的 CPT 所需的组合数量可能太大而不够精确。**
图一。 BN 基于 Mir & Pinnington 的/提议的带有合成节点的 BN。
这些原因解释了为什么我们建议使用合成节点。在这篇文章中,我解释了更多关于合成节点的内容:
在这篇文章中,我给出了一个更正式的观点,并讨论了建模的一个重要元素:合成节点。
towardsdatascience.com](/bayesian-networks-and-synthetic-nodes-721de16c47e2)
这些节点减少了目标节点的 CPT 大小,提高了因果关系可视化的质量。图 1(右侧)对应于我们的建议;它显示了一个基于合成节点的 BN,该 BN 可以替换同一图的左图中显示的网络。如果网络中的每个节点有两个状态,引入合成节点后,“项目成功”节点的 CPT 将有 4 个值要计算,“项目管理社会配置”节点有 8 个值,“项目管理环境配置”节点有 4 个值,“项目管理因素”节点有 8 个值,这意味着总共有 24 个值,而不是 4096 个值。
之后,我们根据这篇文章之前定义的标准,基于这项研究完成了对 Mir 和 Pinnington 的 BN 的简短批评:
在这段历史中,我们讨论了在基于贝叶斯理论建立模型时要考虑的结构标准
towardsdatascience.com](/the-hyperparameter-tuning-problem-in-bayesian-networks-1371590f470)
1 —确保语义一致性:由于每个节点没有具体的可测量输入,专家可能会曲解几个变量。例如,如何知道被评估组织的 PM 策略的水平?
2 —调整网络的完备性: Mir 和 Pinnington 的 BN 并不专注于项目管理的某个特定领域,但它汇集了各种概念。不可能确保网络包含了最重要的变量,也不可能揭示它们之间最重要的关系。作者在谈到其工作的局限性时强调了这一点:“(……)之前的工作也表明,项目成功的认知受到各种 和其他与项目环境相关的 因素的影响,例如,项目风险,或合同类型的选择” (Mir & Pinnington,2014)。
3 —保证结果的相关性:目标节点上的准确度和精确度之间的权衡很大程度上受研究中描述的方差的影响:“众所周知,除了 PM 性能之外,其他因素也会影响项目的成功。事实上,45%的差异(如多元回归分析的最佳拟合模型所示)可以通过 PM 性能结构来解释,而 55%的差异仍然无法解释。”(米尔&平宁顿,2014) 。
4 —限制组合爆炸:由于目标节点依赖于几个输入,因此馈送网络所需的数据量太大。然而,original Mir 和 Pinnington 的 BN 代表了一个很好的例子,说明引入合成节点如何能够大幅减少训练编码模型的计算机所需的信息量。
5 —保证学习质量: Mir 和 Pinnington 的 BN 是从一个数据库中构建的,该数据库来自一个抽样,包括在 4 周内收到的 154 份回复。然而,该信息不能被组织在具有允许学习所有 CPT 的结构的数据库中。对于这个网络,不可能测量学习的质量,进行训练/测试比率或使用其他测试指标。
总之,这个例子显示了语义结构和所需数据量之间的关系。本研究展示了引入合成节点如何减少 CPT 计算的示例,这些节点是必要的,但不足以构建满足资格标准的网络。
第二个限制:状态数不正确。
我们的下一项研究涉及一篇名为“量化大型业务应用程序开发中需求定义和管理过程成熟度对项目结果的影响” (Ellis & Berry,2013) 。作者定义了需求成熟度和项目运营绩效的不同度量之间的相关性。
我们的首要任务是恢复信息,以便创建一个 BN 来重现 Ellis 和 Berry 的结果。建议的网络有十三个输入,一个中间节点(需求成熟度)和五个输出。我们根据这项研究构建的网络分为两部分。第一个揭示了影响需求成熟度的几个因素(图 2)。
图二。根据(Ellis & Berry 2013)与项目成功的相关因素设计的 BN。
Ellis 和 Berry 论文的第二部分展示了需求成熟度如何影响项目绩效的不同度量(图 3)。
图 3 RDM 成熟度和成功指标
我们在这项研究的基础上,按照本文前面定义的标准,完成了对埃利斯和贝里的网络的简短批评:
1 —确保语义一致性:他们的 BN 表示需求工程专家选择的标准。这些标准并不详尽,但它们可能与目标相关。
2 —网络的完整性: Ellis 和 Berry 选择了专家认可的主要概念。他们论文的范围仅限于需求成熟度。每个概念明确对应每个节点。
3 —保证结果的相关性:目标节点有 Yes 或 No 两种状态,每种状态都依赖于 RDM 成熟度节点中所有状态的组合。也就是说,所有的性能指标都仅仅依赖于需求成熟度。每个输出节点都有两个明确的状态(是/否),但它们在 RDM 的四个状态中的依赖性限制了它们的精度。此外,十二个输入节点中 RDM 成熟度的依赖性限制了结果的精确度。
4 —限制组合爆炸。由于所有输入节点都与单个中间节点“RDM 成熟度”相关,并且它具有四个状态,所以其 CPT 的组合是高的(32 768 个值)。没有足够的数据来创建能够给出可靠输出的“RDM 成熟度”节点的 CPT。
5 —保证良好的学习质量。由于“RDM 成熟度”节点的 CPT 具有组合爆炸,很可能其 CPT 上的学习质量较低。甚至没有足够的数据来训练网络或测试它。所以网络不能保证学习的质量。
总之,这个网络具有完整的语义结构;然而,仅设置一个具有四种状态的中间节点增加了 CPT 中的组合。相反,最好创建几个合成节点。
第三个限制:语义没有严格定义
下一篇论文题为项目组合管理在培养深思熟虑的和紧急的战略(科普曼、科克、基伦&格明登,2017) 。作者提出的关键变量和模型在 182 个中小企业和大公司的双信息源跨行业调查中得到检验。****
图 4: BN 基于 Kopmann 等人(2017 年)
我们可以使用前两个案例中提到的标准来评估 Kopmann 等人(2017)的工作。
1 —确保语义的一致性:这个网络呈现了宏观环境中包含的可能影响投资组合成功的元素。这些元素被 PM 社区所接受。然而,可能有几个其他因素影响投资组合的成功,如环境、策略定义等。
2 —调整网络的完整性:无法确定该网络是否考虑了所有必要的变量。这些概念得到了项目管理专家社区的验证(Kopmann 等人,2017)。
3 —保证结果的相关性:由于变量数量很大,因此无法衡量结果的质量。此外,与每个变量相关的数据量不足以在它们之间创建关系。
4 —限制组合爆炸:有八个节点针对一个单个节点,数据量不够大,无法为目标节点创建准确的 CPT。此外,文中提出的每个中间节点都有几个输入节点。
5 —保证良好的学习质量:目标节点中的学习没有足够的精度,因为没有帮助建立其 CPT 的结构化数据库。
总之,Kopmann 等人(2017)的网络表明,应该定义 BNs 的语义。与其建立一个具有大范围和有限数量变量的因果模型,不如创建一个范围缩小的 BN(例如,不是项目组合管理而是项目管理),它具有详尽和必要数量的变量。
第四个限制:目标节点太多
接下来我们要批判的研究叫做“整合管理对建设项目管理绩效的影响”**(Demirkesen&Ozorhon,2017) 。本文包括了被描述为项目管理集成最佳实践的输入,它使用了一个可用作合成节点的“集成管理”节点。这个节点用几个性能指标来衡量:时间、安全、质量、成本和客户满意度。我们从 Demirkesen 和 Ozorhon 的工作中构建了 BN(图 5)。****
图五。BN 基于 Demirkesen & Ozorhon (2017 年)
这种因果网络的局限性在评估极端案例时显现出来。例如,图 6 显示了集成管理完全完成时的预期性能。该网络显示了即使 100%的证据处于“是”状态,也将如何传导到 64%的性能概率,这是 32%概率的改进。此外,当在每个定义的性能指标(时间、成本、质量、安全、客户满意度)中划分这个概率时,概率的增加变得不那么重要。
图 6(Demirkesen & Ozorhon,2017)的敏感性分析。
更一般地说,Demirkesen 和 Ozorhon 的模型缺少几个关键点。
1 —保证语义一致性:因果模型侧重于集成管理,节点与该领域相关。该研究的主要贡献在于解释了集成管理如何与项目的运营绩效相关联。Demirkesen 和 Ozorhon 模型的语义一致性是好的。
2 —调整网络的完备性:因果模型的节点用无法从所描述的项目中直接测量的变量定义。没有证据表明此网络中的相关概念是详尽的,或者包括所有关于集成管理的必要评估项目。
3 —保证结果的相关性: PM 绩效目标节点派生为五个节点。因此,答案的准确性降低了。引入更多测量性能的概念会降低结果在准确度和精确度方面的相关性。
4 —限制组合爆炸:集成管理节点上的组合较多,但仍可计算。目标节点中的 CPT 很低,因为每个 CPT 只取决于一个因素(PM 性能)。
5 —保证良好的学习质量:由于所有节点都有两种状态,并且本文中可用的数据足够多,所以 ML 的质量可能是好的。然而,这是不可能的,因为没有足够的措施来做新的测试。
总之,从 Demirkesen 和 Ozorhon 的文章《本文》中获得的信息使我们能够再造一个更好的 BN。然而,考虑到数据量,建议只研究一个目标(而不是五个),以确保结果的相关性。
第五个限制:因果路径的多重性和 ML 不可能性
最后一篇研究论文名为【建设项目中项目复杂性驱动的风险路径建模】 (Qazi et al .,2016)。这个网络有几个中间节点和四个目标节点,它们汇聚成“效用”函数。BNs 用于评估项目成本超支。数据来自对几家公司项目经理的调查。该模型对其 26 个节点中的每一个使用两种状态:真/假。它有八个输入节点和四个输出节点:******
Qazi 等人的模型,如图 7 所示,它探索了项目复杂性特征、风险和项目目标之间的相互依赖性。
图 7。BN 基于 Qazi 等人(2016 年)。
我们如何评估拟议中的 BN?
1 —确保语义一致性:作者选择了项目管理专家群体认可的主要概念。然而,没有证据表明这个模型包括了干扰项目开发的变量的详尽列表。
2 —调整网络的完整性:Qazi 等人的网络范围太大。由于有四个目标节点,网络是否考虑了影响这些节点的所有变量并不明显。这项研究没有解释为什么有些节点指向某些目标而不是其他目标。
3 —保证结果的相关性:目标节点有四个,其中一些是相互依赖的。这些节点有两种状态,因此精度和准确度应该是最大的。然而,不可能在每个目标节点中测量这些特征。
4 —限制组合爆炸:Qazi et al . BN 的每个节点都有两种状态。即使在有三个父节点的节点中,也没有组合爆炸。该论文明确地提出了所有的 CPT,因此完全重建整个网络是可能的。
5 —保证良好的学习质量。没有足够的数据来训练或测试网络。因此,没有数据库来通过算法测量每个目标的准确度和精确度。
关于拟定 BN 的数据可访问性存在限制。Qazi 等人的网络不能完全复制,也不能用新的数据集训练。它没有显示任何与 PM 最佳实践实现(没有可观察变量的度量)相关联的完善度(成熟度等级)。不可能评估每个目标节点中结果的相关性,也不可能评估整个 BN 的学习质量。**
综合
1。第一点(确保语义一致性)被大多数网络所满足,因为在所有情况下,信息都是从研究人员已经处理过的科学文章中提取的。在下一章中,我们应该包括专家使用的概念,并用相关的科学文献证明它们符合这个标准。
2。提出的因果模型不能保证网络的完整性。然而,(Ellis & Berry,2013)的研究更接近于构建一个模型,其输入特征有效地定义了需求的成熟度,其输出特征:项目的效率参数。
3。所研究的网络都不能保证结果的相关性。无法定义结果的精确度或准确度。这是构建 BNs 时最难的一点。没有足够的数据来测试这些网络,也不可能对学习算法应用性能测量。然而,(Demirkesen & Ozorhon,2017)教导我们更少的目标节点可以提高网络结果的相关性。
4。组合爆炸是构建 BNs 或更一般地说:网络时出现的一个重要问题。当几个输入节点指向一个目标节点时(Mir & Pinnington,2014),当中间节点中有太多状态时(Kopmann 等人,2017),或者当模型包括太多概念和子概念(Ellis & Berry,2013),都可能发生这种情况。然而,我们发现使用合成节点,并在每个节点中包含两个状态,减少了组合的爆炸。在我们的模型中,我们必须牢记这一启发。
5。我们了解到,为了保证学习质量,我们应该包含一个数据库,并在定义网络后应用指标。即使 Qazi 等人的论文给出了每个节点的 CPT,我们也不能基于 CPT 计算任何学习度量。
结论:定义 BN 构建规则
这篇文章中的分析允许我们提取工作规则来构建我们的模型。我们可以把这些规则总结为:
- 规则 1:限制模型的语义。我们已经展示了 PM 中的文献如何呈现不同性质的实体的相关性。然而,对于一个定义良好的 BN,建议从建模相同性质的实体开始。在我们的案例中,我们将使用项目管理成熟度的概念,排除关于公司核心竞争力或项目环境的概念。
- 规则二: 限制输入节点数量。链接到一个节点的许多输入节点会产生太多的组合而无法解决。这将在其子节点中产生组合爆炸。五个以上的输入节点会降低灵敏度分析的影响,因为反向传播算法将不得不覆盖太多的原因,并且每个原因的重要性将被削弱。
- 规则 3:将输入节点的状态数限制为两个。在输入节点中使用几个状态会导致子节点的组合爆炸。这降低了结果的准确性和相关性。同样,具有两种状态的节点是/否增加了网络的易理解性和客观性。**
- 规则 4:使用合成节点。这些节点应该代表网络的语义;因此,应与专家讨论它们在结构中的位置。建议使用合成节点来减少 CPT 爆炸。因此,训练算法所需的数据量将减少,BN 的完整性更高,可解释性以及准确性增加。
- 规则 5:只使用一个具有适当数量状态的目标节点。我们已经展示了使用多个目标节点如何限制灵敏度分析和网络的客观性。我们建议只有一个具有适当数量状态的目标节点。这个命题解决了可访问性、完整性、精确性、不确定性、可解释性和易理解性之间的折衷。
感谢阅读至此!!!
链接到这篇文章的完整研究可以在下一个链接中找到(这篇文章直到 2020 年 6 月都是免费的)
**** [## 一种基于贝叶斯网络的提高项目管理成熟度的方法
提出了一种建立项目管理成熟度和项目超额成本之间因果关系的方法
www.sciencedirect.com](https://www.sciencedirect.com/science/article/pii/S0166361519309480?dgcid=author)****
要了解 BN 的基础知识,我建议你看这篇文章:
假设世界上存在一种非常罕见的疾病。你患这种疾病的几率只有千分之一。你想要…
towardsdatascience.com](/will-you-become-a-zombie-if-a-99-accuracy-test-result-positive-3da371f5134)****
如果你想继续阅读这样的故事,你可以在这里订阅!
参考文献:
德米尔克森,s .,&奥佐洪,B. (2017)。集成管理对建设项目管理绩效的影响。国际项目管理杂志,35(8),1639–1654。【https://doi.org/10.1016/j.ijproman.2017.09.008】
埃利斯,k .,&贝里,医学博士(2013 年)。量化大型商业应用程序开发中需求定义和管理过程成熟度对项目结果的影响。需求工程,18(3),223–249 页。
Kopmann,j .、Kock,a .、Killen,C. P .、& Gemünden,H. G. (2017)。项目组合管理在培养深思熟虑的和紧急的策略中的作用。国际项目管理杂志,35(4),557–570。https://doi.org/10.1016/j.ijproman.2017.02.011
T12 米尔,F. A .,T26 平宁顿,A. H. (2014 年)。探索项目管理的价值:将项目管理绩效和项目成功联系起来。国际项目管理杂志,32(2),202–217。https://doi.org/10.1016/j.ijproman.2013.05.012
Qazi,a .、Quigley,j .、Dickson,a .、& Kirytopoulos,K. (2016)。项目复杂性和风险管理(ProCRiM):建设项目中项目复杂性驱动的风险路径建模。国际项目管理杂志,34(7),1183–1198。【https://doi.org/10.1016/j.ijproman.2016.05.008】T21****
用贝叶斯统计比较葡萄酒
分级建模和 Gibbs 抽样概述,用于比较多组数据。
照片由 chuttersnap 在 Unsplash 上拍摄
当被问及更喜欢哪种葡萄酒时,大多数人都会回答红葡萄酒或白葡萄酒(有时还会说玫瑰葡萄酒)。即使我们最终确定了葡萄酒的颜色,仍有成千上万种葡萄酒可供选择(它们尝起来都非常不同)。一个狂热的葡萄酒爱好者可以很容易地区分这些葡萄酒,并且在挑选葡萄酒时对葡萄酒的国家和品种非常挑剔。在这篇博客中,我们将使用统计数据来帮助我们选择哪种葡萄酒更好。
我们将考虑本博客的 Kaggle wines 评论 数据集。这个数据集包含了一些品酒师对世界各地生产的不同葡萄酒的评论。葡萄酒的等级由分数栏给出,从 1 到 100。让我们假设,我的一个朋友喜欢南非的长相思,另一个喜欢智利的霞多丽。他们都认为 15 美元是买一瓶酒的合适金额。现在让我们在不品尝任何一种的情况下完成这个。
让我们从看一下数据集开始这个旅程:
该数据集有 14 列 129971 个数据点。有三个数字列,X,点数,价格;其中 X 是索引。其余 11 列是字符类型。
数据集的结构
现在,我们需要在南非长相思和智利霞多丽之间做出选择,所以让我们从数据集中过滤这些数据点。
wine_groups <- wine%>%
filter( ((variety=="Sauvignon Blanc" & country=="South Africa") |
(variety=="Chardonnay" & country=="Chile")) &
price == 15)
注意:两国都生产这两种葡萄酒。所以我们需要使用这种组合过滤条件来选择数据,而不是在不同的过滤器中过滤品种和国家。
按照我们的特定条件选择数据,我们只得到 51 行。让我们先看一下所选的数据集,并形成我们的假设。首先,绘制这两种葡萄酒的箱线图,以估计点数的中值和范围。
从中可以看出“霞多丽”的值在 81 到 88 之间,中间值约为 85。长相思的数值范围从 85 到 90,中间值约为 87。从各组的中位数也可以明显看出,长相思比霞多丽有更好的分数,这可以用来形成我们的假设。查看这些值的平均值、中间值和标准偏差:
很明显,长相思被认为比霞多丽更好,但是我们不能确定这一点,因为数据很少。让我们进行一个双样本 t 检验来形成一个假设。
##
## Two Sample t-test
##
## data: points by variety
## t = -3.2599, df = 49, p-value = 0.00203
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -3.4482245 -0.8181847
## sample estimates:
## mean in group Chardonnay mean in group Sauvignon Blanc
## 85.08108 87.21429
解释这些结果并形成我们的无效假设。无效假设表明两组之间的差异为零。p 值为 0.00203,小于 0.05,表明我们有 95%的把握认为长相思更好,或者我们也可以说有 0.2%的几率差异为零。重要的是,两个平均值之间的差值不为 0。基于这个 t 检验,我们形成了我们的假设,长相思比霞多丽更好评级。我们将尝试使用贝叶斯推理方法来找出这种差异。
统计建模
我们现在将使用 Gibbs 采样器来明确地模拟两组葡萄酒之间的差异。这用于对平均值和标准偏差(或精度)值执行完全条件更新。Gibbs Sampler 简化了我们使用 MCMC 方法更新多个参数的任务,它使用一种潜在的方便的全条件概率,将过程分成一次更新一个参数。为了对一个特定参数进行更新,我们将所有其他参数的当前值代入。有三个参数,我们试图用吉布斯采样器来估计,
- μ,两个定义组的平均值;
- del,两组的积分差异;
- τ,精度(定义为 1/Sd);
我们假设数据的范围覆盖在μ+2d 中,一般精度为τ。因此,这两组可以重新参数化为 mu+del 和 mu-del。其层次模型如下所示:
分层模型图
吉布斯采样:
对于吉布斯采样器的先验值,我们的最佳猜测如下:点数从 80 到 95 不等,中间值约为 85-87,因此 mu 的最佳估计值为 85。我们假设标准差约为 10,因此τ的先验估计值为 1/100。我们将 del 的初始值设为 0,因为根据零假设,组间差异为 0。在采样器的预烧期之后,这种先前的猜测将收敛于它们来自数据的原始值。我们运行采样器 5000 次迭代。对于正态似然性,平均值遵循具有参数μ0 和𝜎2 的正态分布,标准偏差𝜎2 遵循逆伽马分布(因此τ遵循伽马分布),而δ1 也遵循正态分布。这些分布用于更新我们的吉布斯采样器中的参数。
在从 Gibbs 方法生成样本之后,我们使用 MCMC 拟合方法创建图来分析估计参数(μ、del 和 tau)的收敛性。
迹线和密度图。
从该图中可以观察到,对于所有三个参数,模拟的马尔可夫链已经收敛到其后验分布,并且μ、δ1 和τ的后验参数估计值遵循正态分布。因为μ、δ1 和τ的后验估计也遵循正态分布,所以我们在 Gibbs 方法之前的猜测被认为是正态似然函数的共轭先验。对参数的这种完全有条件的更新为我们提供了如下后验值:
让我们以 mu+del 计算第 1 组(在我们的例子中是“智利霞多丽”)的平均值,我们得到 85.084,以 mu-del 计算第 2 组(“南非长相思”)的平均值,我们得到 87.204,标准偏差为 2.778。基于这些值,我们可以拒绝零假设,并接受两种葡萄酒之间的点数差异不为零。
因此,在我们的案例中,我们有一个赢家,南非长相思比智利霞多丽得到了 2.1198 的分数。
啊,但是我的朋友似乎很坚决,所以我们决定以每瓶 15 美元的价格买下这两款酒。现在来看看南非长相思更好的概率有多大。
预测模拟
我们可以再次使用相同的吉布斯采样器对未观察到的数据进行预测。根据上一部分中使用的 Gibbs 抽样拟合模型,我们再创建两个各为 5000 的模拟,第一个用(mu + del)的最后一部分中的平均估计值表示“Chardonnay ”,第二个组用(model)的平均估计值表示“Sauvignon Blanc ”,具有公共标准偏差。在最后部分中接收的相同的吉布斯采样器输出拟合被用作该部分的仿真参数。
我们绘制了从该模拟接收的后验分布,并且它遵循正态分布曲线,
后验分布
这些样品帮助我们检查一种葡萄酒的平均水平是否比其他的好。一种酒的每一个样品都要与其他酒的每一个样品进行核对。这就产生了一个概率,告诉我们哪种酒更好,好多少。
结论
- 从我们的分析来看,很明显,南非长相思的评分 2.1198 分 优于智利霞多丽
- 此外,比较两个模拟组的平均值,我们观察到,对于 ,70.5% 的时间,南非长相思的评分优于智利霞多丽。
后续步骤
这种建模和比较也可以扩展到多个组,估计组内均值、跨组均值、精度等。
这里使用的数据集非常有趣,可以用于点估计、文本分析和 NLP 的回归建模(因为有很多文本列)以及更多…
欢呼..!!
在 LinkedIn 上与我联系并讨论这些想法。
在 GitHub 上找到其他令人兴奋的项目。
在维基百科上使用 BeautifulSoup
使用 BeautifulSoup 将表格(的一部分)变成字典
如果你不熟悉的话,网页抓取是从网页上获取数据并以列表、字典或表格的形式保存的过程。在 Python 中,包美汤是人们用来进行网页抓取的。从本质上说,web 抓取就是查看给定网站上的 html 代码,识别代码中您要查找的内容,并告诉您的代码从这些部分获取数据。这里有一个来自英国烘焙大赛第一页的例子。
在本例中,我们将关注第一个表,它包含面包师的全名、年龄、职业和家乡。下面是表格本身的截图
截图来自维基百科页面
现在,我们将查看该页面上的 html 代码,您可以右键单击该页面,然后单击“Inspect”,对我来说,这是倒数第三个,您的结果可能会明显不同。现在,您的屏幕应该看起来像这样:
从这里开始,你可以滚动 html 来阅读代码,找到你要找的东西,但是有一个更简单的方法。如果你看一下 inspect 页面屏幕的左上角,你会看到在一个正方形内有一个看起来像鼠标指针的图标。如果您单击该指针,然后将鼠标悬停在页面上感兴趣的区域上,将会显示该区域在代码中的确切位置:
如果你看一下 inspect 侧,行上高亮显示的文本对应于页面上当前高亮显示的文本。从那里,您可以查看该表的其余代码,并对事物的位置有所了解。现在我们已经为从页面抓取数据做好了准备。
假设我想创建一个字典,其中的键是参赛者的名字,值是一个包含参赛者年龄和家乡的列表。查看页面 inspection,我们可以看到该数据在页面上的位置:
现在进入代码,首先我要导入必要的包、请求和 BeautifulSoup,然后向页面发出请求,并创建我将用来从中提取数据的 Soup。
在这里,我可以创建我的字典,我将它命名为“参赛者姓名年龄城镇”:
遍历代码时,我们会稍微违反直觉,从最后开始。在第 6-8 行,我们看到一个“for”语句,意思是整个字典是一个字典理解(这只是一个列表理解,但作为字典而不是列表)。现在,让我们看看第 7 行的第一部分。
soup.find("table", class_="wikitable")
在 BeautifulSoup 中,说“find”而不是“find_all”只会返回您告诉代码要查找的任何内容的第一个实例。因此,虽然页面有多个表,但这将只返回第一个表,这很好,因为这是我们想要使用的表。现在转到附加在末尾的 find_all 语句,我们看到我要求它查找所有标记为“tr”的实例,这是 table row 的缩写。第 8 行基本上确保了每当我请求代码查找某个东西时,我不是在请求一个 None 对象,因为那会返回一个错误。
回到第 1 行,我们看到:
contestant_name_age_town = {item.td.text:
这是分配钥匙,正如我所说的,是参赛者的名字。所以,我说过,对于每一行,查看第一个标记为“td”的内容,并从中提取文本。有趣的是,字典中的值是:
[int(item.td.find_next_siblings(limit = 3)[0].text), item.td.find_next_siblings(limit = 3)[2].a.get('href')]
您可能注意到的第一件事是,这两个项目都以“item . TD . find _ next _ siblings(limit = 3)”开头。还记得 item.td 是怎么给我们选手名字的吗?接下来的三个条目为我们提供了该行的所有其他信息,或者 item.td 的接下来三个兄弟条目。当您执行“find_next_siblings”时,该函数将返回一个兄弟条目列表。因此,下一项是索引。列表中的第一项是年龄,所以这是第一个兄弟(特别是文本,它被转换成整数)。最后一项是家乡信息,这就是为什么它的索引是 2。从那里我得到了家乡页面的 url 片段。下面是字典理解的打印结果:
{'Annetha Mills': [30, '/wiki/Essex'],
'David Chambers': [31, '/wiki/Milton_Keynes'],
'Edward "Edd" Kimber': [24, '/wiki/Bradford'],
'Jasminder Randhawa': [45, '/wiki/Birmingham'],
'Jonathan Shepherd': [25, '/wiki/St_Albans'],
'Lea Harris': [51, '/wiki/Midlothian'],
'Louise Brimelow': [44, '/wiki/Manchester'],
'Mark Whithers': [48, '/wiki/Wales'],
'Miranda Gore Browne': [37, '/wiki/Midhurst'],
'Ruth Clemens': [31, '/wiki/Poynton,_Cheshire']}
现在,为什么我取了 url 片段而不仅仅是家乡名呢?因为在我的下一篇文章中,我将向您展示如何创建一个从多个页面中抓取的脚本,以便我们可以提取像家乡的人口和面积这样的数据。
利用伯特对抗工作诈骗
伯特模型有许多实际应用。在这里,我们用它来解决一个就业骗局。
BERT 是一种现代语言表示方法,由谷歌研究人员在 2018 年开发,并在 2019 年的出版物 中概述了 BERT:用于语言理解的深度双向转换器 的预训练。该方法对于诸如问题回答、语言推理和常识推理的任务是有用的。正如论文所概述的,当在几个基准自然语言理解(NLU)数据集上训练时,BERT 优于先前的自然语言处理(NLP)方法。其中包括通用语言理解评测( GLUE )数据集、多体裁自然语言推理( MultiNLI )数据集、斯坦福问答数据集( SQUAD )等等。
BERT 的独特之处在于它能够将双向上下文转化为单词表示。这到底是什么意思?通常,语言表示是上下文无关模型或单向/从左到右语言模型的结果。BERT 是预训练上下文表征的第一个扩展,包括来自两个方向的上下文。为了理解这一点,让我们考虑三种类型的文本表示:
1.上下文无关
一个上下文无关的模型,比如 word2vec 和 GloVe,会在句子“他是一个棒球投手”和“他渴了,所以他要了一罐水”中给单词“pitcher”相同的表示。虽然我们知道,基于上下文,单词“pitcher”有不同的含义,但上下文无关的模型无法提供有区别的表示。
2。 单向上下文
一个单向的上下文模型,比如 OpenAI GPT,会从左到右用前面的单词来表示每个单词。例如,“他曾是棒球投手”中的“pitcher”用“他曾是棒球手”来表示与上下文无关的模型不同,单向模型为单词表示提供了一些上下文。尽管如此,单向模型是有限的,因为单词只能用前面的文本来表示。这种局限性激发了对双向语言模型的需求,这种模型能够完全捕捉单词的上下文含义。
3。 双向语境
虽然单向模型提供了一些上下文,但有时为了完全理解一个单词的意思,两个方向都需要上下文。例如,考虑句子“他知道水罐在桌子上。”像奥博奈·GPT 这样的模特会用“他知道”来代表“投手”这个词伯特是双向的,他会恰当地用“他知道”和“水在桌子上”来表示“水罐”通过用前后文本表示单词,BERT 能够准确地表示单词在文本中的含义。你可以在谷歌人工智能博客这里阅读更多关于伯特捕捉双向语境的能力。
根据我们的理解,这提出了如何在实践中使用的问题。最相关的应用是谷歌的搜索引擎,它使用 BERT 来增强搜索结果。在这篇谷歌博客文章中,作者概述了实施 BERT 后对搜索结果的一些关键改进。例如,他们使用查询“你能在药店为某人买药吗?”在 BERT 之前,结果建议如何得到一个处方的资源。在伯特之后,结果正确地代表了情境:为另一个人拿处方药,而不是一般的处方。结果显示了相关内容的页面。
现在让我们考虑 BERT 的一个有趣的应用。近几十年来,企业已经采用了各种基于云的招聘广告解决方案,如应用程序跟踪系统(ATS)。虽然这使企业能够更有效地招聘员工,但它也让骗子有机会制作和发布欺诈性内容。具体来说,骗子们已经变得善于为蓝领和秘书工作制作令人信服的广告。此外,通过像 Workable 这样的应用程序跟踪系统,骗子可以毫不费力地收集成千上万份使用欺诈性帖子作为诱饵的简历。
雇佣诈骗有两个目的。首先是收集联系信息,如电子邮件、邮政编码、电话号码和地址。这些信息可以卖给营销人员和陌生来电者。雇佣诈骗的更恶意的目的是身份盗窃。这些虚假帖子通常会将用户从 ATS 引导到第三方网站,然后用户会在那里经历一系列虚假的面试活动。最终,用户被要求提供高度敏感的信息,如社会安全号码和银行账户信息,这些信息可用于洗钱。
最近,爱琴海大学发布了 就业骗局爱琴海数据集 ,试图揭露就业骗局问题。该数据包含约 18,000 条包含真实生活和欺诈性招聘广告的记录。识别虚假职位的任务自然属于二进制分类。具体来说,我们将使用 BERT 模型对虚假职位进行分类,通过使用双向上下文来表示职位发布中的单词,这些单词被标记为“欺诈”或“真实”。在这个用例中,在“欺诈性”帖子中找到的单词的上下文含义应该与在“真实”帖子中找到的单词的上下文含义不同。与单向和上下文无关的模型相比,捕获这些双向上下文差异应该导致分类性能的提高。在开始之前,感谢马頔·舒尔加,他的帖子“伯特来拯救”启发了我在这里的工作。
现在让我们开始吧!
1.导入包
首先,让我们导入一些必要的包:
import pandas as pd
import numpy as np
import torch.nn as nn
from pytorch_pretrained_bert import BertTokenizer, BertModel
import torch
from keras.preprocessing.sequence import pad_sequences
from sklearn.metrics import classification_report
2.数据探索
接下来,让我们将数据读入一个数据框,并打印前五行。我们还可以将最大显示列数设置为“无”:
pd.set_option('display.max_columns', None)
df = pd.read_csv("fake_job_postings.csv")
print(df.head())
为简单起见,让我们看看“描述”和“欺诈”栏:
df = df[['description', 'fraudulent']]
print(df.head())
我们分类模型的目标在“欺诈性”一栏中为了了解“欺诈”值的分布和种类,我们可以使用集合模块中的“计数器”:
from collections import Counter
print(Counter(df['fraudulent'].values))
“0”值对应于正常的工作发布,“1”值对应于欺诈性发布。我们看到数据略有不平衡,这意味着正常的职位发布(17,000)多于欺诈性发布(866)。
在继续之前,让我们删除“NaN”值:
df.dropna(inplace = True)
接下来,我们希望平衡我们的数据集,使“欺诈”和“非欺诈”类型的数量相等。我们还应该随机改变目标:
df_fraudulent= df[df['fraudulent'] == 1]
df_normal = df[df['fraudulent'] == 0]
df_normal = df_normal.sample(n=len(df_fraudulent))
df = df_normal.append(df_fraudulent)
df = df.sample(frac=1, random_state = 24).reset_index(drop=True)
再次验证我们得到了想要的结果:
print(Counter(df['fraudulent'].values))
接下来,我们想要格式化数据,以便它可以用作我们的 BERT 模型的输入。我们将数据分为训练集和测试集:
train_data = df.head(866)
test_data = df.tail(866)
我们生成一个包含“描述”和“欺诈”关键字的字典列表:
train_data = [{'description': description, 'fraudulent': fraudulent } for description in list(train_data['description']) for fraudulent in list(train_data['fraudulent'])]test_data = [{'description': description, 'fraudulent': fraudulent } for description in list(test_data['description']) for fraudulent in list(test_data['fraudulent'])]
从字典列表中生成元组列表:
train_texts, train_labels = list(zip(*map(lambda d: (d['description'], d['fraudulent']), train_data)))
test_texts, test_labels = list(zip(*map(lambda d: (d['description'], d['fraudulent']), test_data)))
生成令牌和令牌 id:
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', do_lower_case=True)train_tokens = list(map(lambda t: ['[CLS]'] + tokenizer.tokenize(t)[:511], train_texts))test_tokens = list(map(lambda t: ['[CLS]'] + tokenizer.tokenize(t)[:511], test_texts))train_tokens_ids = list(map(tokenizer.convert_tokens_to_ids, train_tokens))test_tokens_ids = list(map(tokenizer.convert_tokens_to_ids, test_tokens))train_tokens_ids = pad_sequences(train_tokens_ids, maxlen=512, truncating="post", padding="post", dtype="int")test_tokens_ids = pad_sequences(test_tokens_ids, maxlen=512, truncating="post", padding="post", dtype="int")
请注意,我们将输入字符串截断为 512 个字符,因为这是 BERT 可以处理的最大令牌数。
最后,为我们的测试和训练集生成一个基于“欺诈”值的布尔数组:
train_y = np.array(train_labels) == 1
test_y = np.array(test_labels) == 1
4.模型构建
我们创建了我们的 BERT 分类器,它包含一个“初始化”方法和一个返回令牌概率的“转发”方法:
class BertBinaryClassifier(nn.Module):
def __init__(self, dropout=0.1):
super(BertBinaryClassifier, self).__init__()
self.bert = BertModel.from_pretrained('bert-base-uncased')
self.dropout = nn.Dropout(dropout)
self.linear = nn.Linear(768, 1)
self.sigmoid = nn.Sigmoid()
def forward(self, tokens, masks=None):
_, pooled_output = self.bert(tokens, attention_mask=masks, output_all_encoded_layers=False)
dropout_output = self.dropout(pooled_output)
linear_output = self.linear(dropout_output)
proba = self.sigmoid(linear_output)
return proba
接下来,我们生成训练和测试掩码:
train_masks = [[float(i > 0) for i in ii] for ii in train_tokens_ids]
test_masks = [[float(i > 0) for i in ii] for ii in test_tokens_ids]
train_masks_tensor = torch.tensor(train_masks)
test_masks_tensor = torch.tensor(test_masks)
生成用于训练和测试的令牌张量:
train_tokens_tensor = torch.tensor(train_tokens_ids)
train_y_tensor = torch.tensor(train_y.reshape(-1, 1)).float()
test_tokens_tensor = torch.tensor(test_tokens_ids)
test_y_tensor = torch.tensor(test_y.reshape(-1, 1)).float()
最后,准备我们的数据加载器:
BATCH_SIZE = 1
train_dataset = torch.utils.data.TensorDataset(train_tokens_tensor, train_masks_tensor, train_y_tensor)
train_sampler = torch.utils.data.RandomSampler(train_dataset)
train_dataloader = torch.utils.data.DataLoader(train_dataset, sampler=train_sampler, batch_size=BATCH_SIZE)test_dataset = torch.utils.data.TensorDataset(test_tokens_tensor, test_masks_tensor, test_y_tensor)
test_sampler = torch.utils.data.SequentialSampler(test_dataset)
test_dataloader = torch.utils.data.DataLoader(test_dataset, sampler=test_sampler, batch_size=BATCH_SIZE)
5.微调
我们使用 Adam 优化器来最小化二进制交叉熵损失,并且我们使用 1 个时期的批量大小 1 来训练:
BATCH_SIZE = 1
EPOCHS = 1bert_clf = BertBinaryClassifier()
optimizer = torch.optim.Adam(bert_clf.parameters(), lr=3e-6)for epoch_num in range(EPOCHS):
bert_clf.train()
train_loss = 0
for step_num, batch_data in enumerate(train_dataloader):
token_ids, masks, labels = tuple(t for t in batch_data)
probas = bert_clf(token_ids, masks)
loss_func = nn.BCELoss()
batch_loss = loss_func(probas, labels)
train_loss += batch_loss.item()
bert_clf.zero_grad()
batch_loss.backward()
optimizer.step()
print('Epoch: ', epoch_num + 1)
print("\r" + "{0}/{1} loss: {2} ".format(step_num, len(train_data) / BATCH_SIZE, train_loss / (step_num + 1)))
我们评估我们的模型:
bert_clf.eval()
bert_predicted = []
all_logits = []
with torch.no_grad():
for step_num, batch_data in enumerate(test_dataloader):token_ids, masks, labels = tuple(t for t in batch_data)logits = bert_clf(token_ids, masks)
loss_func = nn.BCELoss()
loss = loss_func(logits, labels)
numpy_logits = logits.cpu().detach().numpy()
bert_predicted += list(numpy_logits[:, 0] > 0.5)
all_logits += list(numpy_logits[:, 0])
print(classification_report(test_y, bert_predicted))
这将显示一个包含精确度、召回率和 f1 分数指标的混淆矩阵,所有这些指标都描述了模型的性能。显然,这篇文章只是解决伯特雇佣骗局的初级读本。通过额外的微调,我们可以进一步提高准确性,并发现更多的欺诈性列表。BERT 模型相对于上下文无关和单向上下文模型的优势是显而易见的。双向语言处理使得 BERT 更擅长使用上下文来确定一个列表的合法性,从而保护求职者免受不良行为者的剥削。虽然这只是将机器学习用于解决现实世界问题的一种方式,但它是 BERT 如何有用的一个很好的例子。如果对 BERT 的其他应用感兴趣,可以阅读 假新闻分类用 BERT 和 俄罗斯巨魔推文:分类用 BERT 。如果你对伯特方法有兴趣,我鼓励你阅读 伯特拯救 。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!
使用 BigQuery、Firebase Analytics 来吸引、吸引和评估您的应用用户
处理点击流数据时的有用提示和重要转换,以及强大的查询示例。
什么是 Firebase Analytics?
你开发了一个令人惊叹的应用程序,但是你如何知道用户是否以正确的方式使用它,或者他们对应用程序的哪些部分更感兴趣?Firebase Analytics 是记录用户分析的最好的免费库之一。无论你的应用是用于 Web、iOS、Android,甚至是 Flutter, Firebase Analytics 都可以与之集成。一旦集成了分析库,您需要记录您感兴趣的所有事件以及特定于该事件的任何参数,如 app_purchase (购买金额)、 audio_play (音频 id)等。默认情况下,Firebase 向您显示许多不同的图表来解释您正在记录的事件。如果您想进行更多的定制分析,您可以在 firebase 仪表板中将您的 firebase analytics 链接到 BigQuery。BigQuery 将包含所有的原始数据事件,您可以处理它们来进行更复杂的分析。本文详细说明了如何…..
这篇文章是给你的,如果…
您刚刚创建并启动了您的移动应用程序(或网站),现在您有兴趣知道如何查询 Firebase 在我们说话时每秒钟为您处理的庞大数据集。或者您只是好奇,想知道对点击流事件数据的一些有用查询,这些查询可以为您提供一些可操作的见解。无论如何,荣誉和欢迎教程。今天,我们将讨论使用 Google BigQuery 的技巧、诀窍和更多内容。我们开始吧!
云控制台中的 BigQuery Web UI
一旦将 firebase analytics 链接到 BigQuery,您的控制台应该是这样的。我将在这个屏幕上提到几个我日常使用的项目:
- 查询编辑器:可以把它想象成我们写查询的黑板。
- 保存查询按钮:保存重要查询以供将来参考的按钮。
- 保存的查询:这是我们将要使用 save query 按钮保存的所有查询的主页。
- 查询历史:它存储您过去运行过的所有查询(当您想要重用查询时很有用)。
既然我们已经理解了基本的布局,让我们直接进入一些有用的查询。
日期时间格式
Firebase 擅长跟踪你的应用程序或网站的每次点击的大量事件数据。例如,关于应用首次打开的时间、应用最后更新的时间、应用内购买的时间等信息。这意味着与这些事件相关联的时间和日期对于提供洞察力非常有用。默认情况下,Firebase 将事件的日期和时间记录为列 event_timestamp 中的一个整数。
这个整数基本上是客户端记录事件的时间(以微秒计,UTC)。使用FORMAT_DATE
& FORMAT_TIME
将这个整数转换成两个独立的(人类可读的)日期和时间列可能很有吸引力:
SELECT
FORMAT_DATE('%d-%m-%Y', PARSE_DATE('%Y%m%d', event_date)) AS date,
FORMAT_TIME('%T', TIME(TIMESTAMP_MICROS(event_timestamp))) AS time
FROM analytics_xxxxxxxxx.events_*
这给出了以下简洁的输出:
如果您的最终目标是向您的同事或其他利益相关者展示这两个专栏,这种格式应该很适合您。
但是,您可能会使用事件日志文件中的日期和时间列对数据集进行大量转换。在那种情况下,FORMAT_DATE
将不会是最有效的转换。这是因为它返回的输出是类型为 string 的,而 BigQuery 支持的大多数日期和时间函数(比如添加两个日期,将日期截断到特定的粒度)要求日期是 date 或 DATETIME 格式。
在这种情况下,我喜欢使用TIMESTAMP_MICROS
函数从 event_timestamp 中提取日期和时间,然后使用CAST AS DATETIME
将这个时间戳转换为 DATETIME 对象:
SELECT
CAST(TIMESTAMP_MICROS(event_timestamp) AS DATETIME) As UTC_Time
FROM analytics_xxxxxxxxx.events_*
注意:默认情况下,存储的时间是 UTC 时区
与存储在 event_timestamp 列中的整数相比,这种格式更加清晰。同时,我们设法保留了 DATETIME 格式,这样任何日期或时间转换仍然是可能的。我们在下面的例子中演示了这种格式的一种用法。
将 UTC 时间转换为本地时间
UTC 是 Firebase 用来存储与事件相关的日期和时间的默认时区。事件数据库中还记录了另一个名为‘time _ zone _ offset _ seconds’的功能,该功能以秒为单位存储与 GMT 的偏差(根据国家的不同,可能为正值或负值)。因此,将这个偏移量加到任何给定的 UTC 时间上,就会得到正确的本地时间。
以下是使用 CTE(通用表表达式)计算本地时间的查询。它首先检查偏移量是否为空,在这种情况下,我们将 UTC 时间设置为本地时间。在非空偏移的情况下,我们首先将偏移秒转换为小时,并使用DATETIME_ADD
将其添加到 UTC 日期:
**WITH CTE AS (**
SELECT *,
CAST(TIMESTAMP_MICROS(event_timestamp) AS DATETIME) As UTC_Time,
device.time_zone_offset_seconds AS offset_seconds,
FROM analytics_xxxxxxxxx.events_*
**)****SELECT UTC_Time, offset_seconds,
CASE
WHEN offset_seconds is NULL then UTC_Time
ELSE DATETIME_ADD(
UTC_Time, INTERVAL CAST(offset_seconds/3600 AS INT64) HOUR)
END As local_time
FROM CTE**
老实说,我对我的数据库中的空偏移量感到很困扰(天哪,有很多!).因此,我决定通过检查 Firebase 存储的 geo.country 列中的国家来手工编码偏移时间,从而解决其中的一些问题。
因此,将上面的查询更新为:
**WITH CTE AS (**
SELECT *,
CAST(TIMESTAMP_MICROS(event_timestamp) AS DATETIME) As UTC_Time,
device.time_zone_offset_seconds AS offset_seconds,
FROM analytics_xxxxxxxxx.events_*
**)**
**SELECT *,
CASE
WHEN offset_seconds IS NULL AND geo.country IN ('India', 'Pakistan') THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(5.5 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country = 'United States' THEN DATETIME_SUB(UTC_Time, INTERVAL CAST(5 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country = 'Australia' THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(10 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country = 'Canada' THEN DATETIME_SUB(UTC_Time, INTERVAL CAST(5 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country = 'China' THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(8 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country IN ('France', 'Spain', 'Germany', 'Sweden', 'Italy', 'Sweden', 'United Kingdom', 'Ireland') THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(1 AS INT64) HOUR)
WHEN offset_seconds IS NOT NULL THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(IFNULL(offset_seconds,0)/3600 AS INT64) HOUR)
ELSE UTC_time
END As local_time
FROM CTE**
唷,这看起来好多了!我们已经设法修复了一些主流国家的时间,这些国家在应用程序上注册了大量的流量。
附注:我使用的时差并不准确,例如,加拿大作为一个国家,在西部和东部观察不同的时区,但为了本教程的目的,我采取了更简单的方法。
对本地时间进行转换,以提取星期几、工作日名称和时间
一旦我们计算出了本地时间,我们就可以通过引入进一步的转换来更进一步。包含上述所有代码的最终查询如下所示:
WITH CTE AS (
SELECT *,
CAST(TIMESTAMP_MICROS(event_timestamp) AS DATETIME) As UTC_Time,
device.time_zone_offset_seconds AS offset_seconds,
FROM analytics_xxxxxxxxx.events_*
),**CTE2 AS (**
SELECT *,
CASE
WHEN offset_seconds IS NULL AND geo.country IN ('India', 'Pakistan') THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(5.5 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country = 'United States' THEN DATETIME_SUB(UTC_Time, INTERVAL CAST(5 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country = 'Australia' THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(10 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country = 'Canada' THEN DATETIME_SUB(UTC_Time, INTERVAL CAST(5 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country = 'China' THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(8 AS INT64) HOUR)
WHEN offset_seconds IS NULL AND geo.country IN ('France', 'Spain', 'Germany', 'Sweden', 'Italy', 'Sweden', 'United Kingdom', 'Ireland') THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(1 AS INT64) HOUR)
WHEN offset_seconds IS NOT NULL THEN DATETIME_ADD(UTC_Time, INTERVAL CAST(IFNULL(offset_seconds,0)/3600 AS INT64) HOUR)
ELSE UTC_time
END As local_time
FROM CTE
**)****SELECT
DATE(local_time) as date, -- returns a DATE
EXTRACT(DAYOFWEEK FROM DATE(local_time)) as day_of_Week,
FORMAT_DATE('%a', DATE(local_time)) as weekday_name,
TIME(local_time) as time, -- returns a TIME
CASE
WHEN TIME(local_time) BETWEEN '06:00:00' AND '11:00:00' THEN 'Morning'
WHEN TIME(local_time) BETWEEN '11:00:00' AND '16:00:00' THEN 'Afternoon'
WHEN TIME(local_time) BETWEEN '16:00:00' AND '19:00:00' THEN 'Evening'
WHEN TIME(local_time) BETWEEN '19:00:00' AND '23:59:00' THEN 'Night'
ELSE 'LateNight'
END AS time_of_day
from CTE2**
注意:day_of_Week
是星期日=1 的数字;星期一=2,以此类推。
这些本地时间的转换对于评估你的应用用户何时最活跃,或者一周中的哪一天向他们发送应用内购买营销电子邮件是有意义的,是非常强大的。
为推荐系统准备数据
推荐系统基于用户的显式(例如:评级)和隐式(例如:花费的时间)偏好、其他用户的偏好以及用户和项目属性来建议用户感兴趣的项目。在最基本的层面上,为您的应用程序构建任何此类建议所需的数据框需要三列:user_id、item_id 和 rating。让我们看看如何从数据库中查询它。
我已经做了几个星期的播客数据集了(感谢我的朋友,他一直在做一个神奇的播客应用程序,叫做Podurama——可以在 Android 和 iOS 上使用);我记录了一个名为 logReview 的自定义事件。每当有人试图对应用程序上的播客进行评级并记录四条主要信息(以及其他信息)时,就会触发该事件:
- 收藏 Id :播客 Id
- guid :剧集 id
- 评级:1 到 5 之间的整数
- 交互类型 : 0-删除;1-创建;2-编辑
对于单个用户,该事件的行看起来是这样的:
SELECT user_pseudo_id, event_name, event_params
FROM analytics_xxxxxxxxx.events_*
WHERE event_name LIKE '%logReview%'
我知道这看起来很吓人,但请耐心听我解释发生了什么。这些事件参数(比如 rating 、 guid )并没有一个唯一的行,而是被分组到某种具有唯一键值对的 JSON 对象中。我可以解释得更详细,但没有什么能比得上托德·克佩尔曼的精彩解释。
底线是我们可以使用下面的查询中的UNNEST
只提取我们感兴趣的事件参数。再次向托德大声欢呼,感谢他为我节省了这么多时间,并在这个帖子中解释得如此漂亮。
SELECT user_pseudo_id,
(SELECT value.int_value
FROM UNNEST(event_params) WHERE key = 'rating'
) AS rating
FROM analytics_xxxxxxxxx.events_*
WHERE event_name LIKE '%logReview%'
我们在这里所做的是告诉 BigQuery 让unnest
或将和 event_params 分开到单独的行中,并且只从那些key = rating
所在的行中选取int_value
。
输出如下所示:
这看起来很棒,除了我们仍然不知道这个评级是哪个播客的插曲。因此,我们将继续提取剧集 id 和播客 id。
SELECT user_pseudo_id,
(SELECT value.int_value
FROM UNNEST(event_params) WHERE key = 'rating'
) AS rating,
**(SELECT value.string_value
FROM UNNEST(event_params) WHERE key = 'guid'
) AS episode_id,
(SELECT value.int_value
FROM UNNEST(event_params) WHERE key = 'collectionId'
) AS podcast_id**FROM analytics_xxxxxxxxx.events_*
WHERE event_name LIKE '%logReview%'
这看起来几乎完美!为什么几乎你问?这是因为我们没有考虑这个评级是否被更改过(记得我们为每个日志审查事件存储了交互类型)。
从逻辑上讲,我们希望保留用户对播客剧集的最新评价。为了实现这一点,我们将使用LAST_VALUE
窗口函数、PARTITIONED BY
用户 id 和剧集 id 和ORDERED BY
时间戳:
**WITH CTE AS (**
SELECT user_pseudo_id,
(
SELECT value.int_value
FROM UNNEST(event_params) WHERE key = 'rating'
) AS rating,
(
SELECT value.string_value
FROM UNNEST(event_params) WHERE key = 'guid'
) AS episode_id,
(
SELECT value.int_value
FROM UNNEST(event_params) WHERE key = 'collectionId'
) AS podcast_id,
(
SELECT value.int_value
FROM UNNEST(event_params) WHERE key = 'interactionType'
) AS interaction_type,
event_timestamp, timeFROM analytics_xxxxxxxxx.events_*
WHERE event_name LIKE '%logReview%'
)**SELECT DISTINCT user_pseudo_id, episode_id, podcast_id,
LAST_VALUE(rating) OVER (PARTITION BY user_pseudo_id, episode_id ORDER BY event_timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS latest_rating
FROM CTE**
LAST_VALUE...
调用本质上是对数据进行分区,首先是按用户 id,在每个用户 id 内,按播客剧集。然后,在这些用户剧集片段(或分区)的每一个中,结果行按照事件时间戳排序。最后,选择对应于分区中最后一行的额定值。
瞧啊。我们做到了。:)现在我们有了开始我们的推荐系统建模所需的数据框架。您可以单击保存结果按钮将数据框导出到本地计算机上。
用于版本更新的定制电子邮件
作为一名应用程序开发人员,每隔几周就会推出一个新版本的应用程序,这是很自然的事情。理想情况下,新版本将有更多的特性和功能,并解决了以前版本的一些令人讨厌的错误。因此,确保大多数早期用户已经过渡到这个最新版本是很重要的,如果他们还没有,通过电子邮件给他们一些提示。
我们将检测所有在我们的应用程序上活跃但尚未切换到最新版本的用户。我们认为那些在过去 10 天内使用过该应用程序的用户是活跃的。
我们将使用FIRST_VALUE
来检测用户第一次使用我们的应用程序时使用了哪个版本的应用程序。同样,我们将使用我们的好朋友LAST_VALUE
来检测与该应用程序最近交互相关的应用程序版本,并提取该应用程序上次使用的日期。我们把这些都储存在 CTE 里。
WITH CTE AS (
SELECT
user_id,
FIRST_VALUE(app_info.version) OVER (user_event_window) AS initial_version,
LAST_VALUE(app_info.version) OVER (user_event_window) AS latest_version,
LAST_VALUE(event_timestamp) OVER (user_event_window) AS app_last_used
FROM analytics_xxxxxxxxx.events_*
WHERE device.operating_system <> 'WEB' AND user_id IS NOT NULL
WINDOW user_event_window AS (PARTITION BY user_id ORDER BY event_timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
)
由于我们对 web 应用程序用户不感兴趣,我们指定了WHERE
条件来检查设备的操作系统。
我们还使用了一个WINDOW
调用user_event_window
来指定事件窗口,这使得代码使用起来更加简洁(通过简化所有冗余的PARTITION BY
调用)。
现在我们有了应用程序最后一次使用的日期(存储为app_last_used
),我们可以使用DATE_DIFF
从今天的日期中减去它。
DATE_DIFF(CURRENT_DATE(), DATE(TIMESTAMP_MICROS(app_last_used)), DAY) AS gap
如果结果小于或等于 10,这意味着该用户是一个活跃用户,因此是我们的应用程序更新电子邮件的目标。
现在是检索用户 id 的最终代码,这些用户应该根据他们上次使用应用程序的时间收到应用程序版本更新的电子邮件。
WITH CTE AS (
SELECT
user_id,
FIRST_VALUE(app_info.version) OVER (user_event_window) AS initial_version,
LAST_VALUE(app_info.version) OVER (user_event_window) AS latest_version,
LAST_VALUE(event_timestamp) OVER (user_event_window) AS app_last_used
FROM `podcastapp-767c2.analytics_193436959.events_*`
WHERE device.operating_system <> 'WEB' AND user_id IS NOT NULL
WINDOW user_event_window AS (PARTITION BY user_id ORDER BY event_timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
)**SELECT user_id, initial_version, latest_version,
DATE(TIMESTAMP_MICROS(app_last_used)) AS last_used,
DATE_DIFF(CURRENT_DATE(), DATE(TIMESTAMP_MICROS(app_last_used)), DAY) AS gap
FROM CTE
WHERE latest_version NOT IN ('1.1.3') -- update the version here in future
GROUP BY user_id, initial_version, latest_version, app_last_used
HAVING gap <= 10**
我希望这篇文章为您提供了一些在 BigQuery 中使用事件数据的有用技巧。查看这篇文章,了解如何利用流程挖掘从事件数据中获取更多关于工作时间损失率和冷启动建议的信息。将来,我会提供一些食谱和其他有趣的查询,您可以尝试用于 Firebase 事件分析。
直到下次:)
对 pm4py python 库的深入介绍
towardsdatascience.com](/process-mining-to-assess-app-user-behavior-from-clickstream-data-8e53a71428a4) [## 如何对自己的数据集使用 BigQuery API?
使用 Flask 和 Bigquery APIs 根据用户查询参数从 Bigquery 数据集中提取数据。
towardsdatascience.com](/how-to-use-bigquery-api-with-your-own-dataset-c901972cebd) [## 如何使用 AutoKeras 用一行代码建立图像分类模型?
甚至不需要知道 Conv2d、Maxpool 或批处理规范化层是做什么的!
用脑电波控制音乐播放列表
仅仅通过集中注意力来改变歌曲。
从小到大,我一直在想,是否有一天,只要想到你最喜欢的歌曲,它就会为你播放。我当时并没有意识到,但是像这样的技术如果存在的话,它的影响是巨大的。也就是说,如果我们能想到一首歌并播放出来,瘫痪的人能不能用同样的技术来思考,比如说,移动轮椅并转动轮子?
但现在,我将展示我如何使用 Muse 耳机和物联网技术来改变播放列表中的歌曲。这是我的妹妹在尝试这个系统,她让我们知道她正专注于通过举起拇指来切换歌曲。
如果她给出了一个口头信号,这可能会干扰她的注意力,因为这些神经离大脑更近,需要更多的肌肉运动。然而,拇指的轻微移动不会改变她的脑电波状态太多,这意味着这是一个很好的信号,让我们知道她什么时候开始集中精力改变歌曲。
背景资料
很好地理解脑电波是如何工作的,以及它们是如何被读取的,对于理解这个项目中的所有组件是如何组合在一起的非常重要。该项目还使用了物联网技术,包括一个连接到物联网集线器的扬声器和一个连接到集线器的 Muse 头带。
解释脑电波类型的图表。
我先从神经科学说起。如果你想更详细地了解脑电波,你可以阅读我的另一篇关于解读脑电波的文章,但我将在这里提供一个简短的总结。脑波分为五种主要类型——δ波、θ波、α波、β波和γ波。δ波是最慢的,出现在睡眠期间,γ波是最快的,出现在高度集中、注意力高度集中的情况下。有了 Muse 头带,我能够非常清楚地阅读β和α的状态,以及更难归纳和阅读的θ状态。这项工作做得非常好,因为这个项目最需要测量β波来检查浓度水平。
以下是该项目的物联网方面的更多细节。正如我之前所说,我需要将两个设备都连接到一个物联网集线器,以便更好地处理。Muse 头带每秒钟都会产生大量需要分析和解释的数据,如果在同一个脚本中完成,不会太准确。
物联网组件的信息流。
物联网集线器是两台物联网设备连接的中央服务器,用于发送和接收信息。在这种情况下,它确实非常有用,因为它可以减少客户端的大量繁重处理工作,还可以保持您的解决方案井井有条,因为无论连接了多少设备,信息都是在一个点上处理的。在这个特定的项目中,信息流可以在旁边的图表中看到。
如何测量浓度?
为了达到我们想要的目标,我们需要测量浓度。正如我之前提到的,β波的出现是这部分的完美目标。β波是在专注和学习的状态下出现的,比如你在做作业或者解题的时候。为了首先测量β波,电极需要靠近大脑的额叶或顶叶。
Muse 头带在 AF7 和 AF8 位置提供这些传感器。AF7 位置测量大脑额叶的左侧,AF8 位置测量大脑额叶的右侧。现在,数据从这些位置开始流动,需要建立一个阈值,以确定什么是集中状态,什么不是。
当你处于放松状态时,你的大脑很可能会产生α波而不是β波。这意味着从 Muse 头带传入的β波的频率将小于零,或者是负数。当你开始集中精力做某事时,比如解决一个数学问题,β波的频率会增加,显示大于零的数字。这意味着零很可能是我们在寻找的阈值,来决定你是否在集中注意力。
然而,为了使用零作为阈值,还需要考虑其他因素,例如,如果头带在数字中产生突然的尖峰,因为读取脑电波是一个非常敏感的过程,该怎么办?这也可以通过确保数字逐渐增加或在几秒钟内保持正数来解决,这意味着你肯定处于集中状态。
缪斯发带的代码可以在下面找到。我使用了一个名为 Muselsl 的 Python 库来处理这些头带。
[## alisyakainth/脑波播放列表/musedata.py
github.com](https://github.com/alisyakainth/brainwave-playlist/blob/master/musedata.py)
连接到扬声器
这个项目的第二个主要部分是将物联网中枢连接到扬声器,当达到专注状态时,扬声器负责切换到播放列表中的下一首歌曲。这是通过首先确保所有的处理都在物联网中枢中完成,以便它可以随时向扬声器发送信号来改变歌曲。一旦达到测试波的阈值,物联网中心就会向扬声器发送一首新歌,并立即播放。
为此,我使用了一个名为 winsound 的 Python 模块来控制设备的声音输出,比如开始和停止音轨。对于所有进出物联网集线器的连接,我使用了一个名为 Socket 的模块,它建立了一个 TCP 连接。我还为 Muse 头带使用了一个名为 BlueMuse 的特殊蓝牙流媒体服务,因为它可以与头带建立更强的连接,并且可以直接从这个流中访问数据。
现在,只要集中精神去改变一首歌,你就能改变它!正如一开始提到的,这项技术可以有更多的实际用途,比如帮助那些处于锁定状态的人交流或者以更好的方式控制假肢。我很兴奋看到这项技术的未来发展和它所拥有的东西!
物联网集线器和扬声器的代码可以在下面找到。
[## alisyakainth/脑波播放列表/iothub.py
github.com](https://github.com/alisyakainth/brainwave-playlist/blob/master/iothub.py) [## alisyakainth/脑波播放列表/扬声器. py
github.com](https://github.com/alisyakainth/brainwave-playlist/blob/master/speaker.py)
使用浏览器 Cookies 和 Voyager API 通过 Python 抓取 LinkedIn
在这篇文章中,我们将使用 requests 的 Sessions 方法、浏览器 cookies 和 LinkedIn 的 voyager API 从 LinkedIn 收集数据。
格雷格·布拉在 Unsplash 上的照片
抓取 LinkedIn 每天都变得越来越困难,尤其是如果你使用像 UiPath,Selenium 等开放软件的话。LinkedIn 软屏蔽你,并在登录时添加一个 reCAPTCHA,这变得很难绕过。LinkedIn 的 voyager API 可能是从 LinkedIn 提取信息的最佳方式。
LinkedIn 的数据可以用于许多目的,从线索生成开始,搜索工作,如果你是一名招聘人员,你可以为你的组织找到合适的候选人,如果你想为你的公司找到投资者,底线是你可以使用 LinkedIn 获得数据以满足你的需求。最重要的是你必须知道你在寻找什么。
我们开始吧
我们将使用 LinkedIn 的 voyager API 来抓取一家公司的 about 页面。
见/找航海家 API 的完整文档阅读 此处 。
首先,最重要的部分是获取浏览器 cookies,我们将在该过程的后期阶段使用它们。在深入研究不同类型的 Linkedin Cookies 之前,您将需要来自您的 LinkedIn 登录会话的两个主要 cookie,让我们看看如何访问我们的 cookie,只需遵循这些简单的步骤。点击谷歌浏览器中的选项(右上角有 3 个垂直点)。
2。在这之后,点击更多工具,然后是开发人员工具(你也可以通过使用键盘组合-ctrl+shift+I 来达到这里)。
现在,一旦您获得了开发人员工具的访问权限,您将看到名为 Elements、console 等选项卡。导航到 Application 选项卡,从这里复制两个 cookies 的值,分别命名为 li_at 和 JSESSIONID。
记下这两个 cookies 的值,并将其存储在某个我们稍后会用到的地方。我已经模糊了值,以防止我的帐户可能被滥用。
现在,我们已经完成了最初的部分,让我们进入有趣的部分——你猜对了——编码。
下面是完整的代码,我们一步步来看。
variables headers 是一个包含用户代理的字典,你也可以通过运行简单的 Google 搜索“我的用户代理”来使用自己的代理,你会得到类似这样的结果,只需粘贴你的结果并继续前进。
现在,LinkedIn 给每个公司页面分配一个唯一的 id,你可以很容易地找到它。一旦你有了那个,就用代码中的一来代替那个数字。
https://www . LinkedIn . com/voyager/API/entities/companies/{公司 id}
现在,我们将使用最初从浏览器中提取的 cookies 创建一个会话。
s.cookies['li_at'] = "your li_at cookie" s.cookies['JSESSIONID'] = "your JSESSIONID"
此外,我们需要 csrf-token 身份验证,并在我们的头中设置它。为此,我们需要修改 JSESSIONID 键,您的 JSESSIONID 将如下所示:
"ajax:7454514581611861831542146"
将需要从 JSESSIONID 中剥离"
,然后将其添加到标题中:
s.headers["csrf-token"] = s.cookies["JSESSIONID"].strip('"')
最后一部分非常简单,向 voyager API 发送 get 请求,并将响应转换为字典。
在这之后,你会看到关于该公司的所有信息。
脚注
有许多工具(我个人使用的一个工具是 PhantomBuster )可以做完全相同的事情,但是在规模上,它们本质上做的是在两个请求之间放置一个等待时间以及一些其他技巧。
这个脚本只是为了提取公司的详细信息,如果你试图在一个循环中运行它来一次获得成千上万 Linkedin 公司页面的详细信息,Linkedin 会阻止你,还可能永久禁止你的帐户,这可能非常非常难以恢复。
这只是我们用 voyager API 构建的一个工作流,你可以用它做很多很酷的事情,从获取一个人的个人资料开始,回复对话,发送连接请求或回复它们,用高级过滤器进行工作搜索,喜欢或评论帖子。简而言之,你可以做任何你在 LinkedIn 上做的事情,但是有它的 API,没有 UI。如果你还想看另一篇关于其他事情的文章,请在下面评论。
用 CAPM 评价上市投资公司的绩效
投资者选择投资 LIC 证券的主要原因是追求高于市场基准的回报,即阿尔法回报。我们利用资本资产定价模型分析了 118 家 ASX 上市投资公司过去 5 年的业绩。
投资回报应该补偿投资者投入资本的时间价值,以及部分或全部投资可能损失的风险。资本资产定价模型(CAPM)在金融领域被广泛使用,作为一种手段,在给定持有特定资产而非持有“无风险”资产(如主权政府债券)的相关风险水平的情况下,确定投资者预期从投资中获得的补偿水平。
风险类型
特殊(非系统)风险——指特定资产特有的风险。可以通过分散投资和保持结构良好的投资组合来降低特殊风险(Investopedia 2019a)。
系统性风险——指无法通过投资组合多样化来降低的市场范围风险。虽然投资者可以建立一个投资组合来限制他们的系统风险敞口,但 CAPM 理论表明,这将伴随着他们预期获得的回报的权衡(Investopedia 2019b)。
资本资产定价模型与计算金融资产的预期收益
因为有可能以消除特殊风险的方式分散投资,CAPM 假设投资回报不能补偿投资者持有这种类型的风险。因此,投资者必须分散投资,以避免承担无法获得补偿的风险*。
[如何实现这种多样化超出了本文的范围,但是,在以后的文章中,我将讨论现代投资组合理论,该理论能够开发旨在通过资产多样化消除特殊风险的资产组合,并根据个人风险承受能力偏好获得适当的系统风险敞口水平。]*
CAPM 方法描述了一项资产的预期回报与其系统风险之间的关系。为了计算给定风险的资产的预期回报,通过 CAPM,使用以下等式:
通过操纵这个等式,我们可以利用金融资产数据和回归分析来首先评估 CAPM 理论在实践中是否成立,其次评估特定金融资产的表现。
这种方法源自 Jensen (1968),在该方法中,系统地考察了美国共同基金的表现,以确定是否有任何基金能够“跑赢市场”(Brooks 2008,第 67-81 页)。
利用 CAPM 评估目前在澳大利亚证券交易所上市的投资公司的业绩
上市投资公司(lic)——LIC 类似于管理型共同基金,但是,投资者可以像在证券交易所买卖普通股一样买卖 LIC 股票。因此,历史定价数据在网上很容易获得,可以很容易地进行分析。一般来说,持有 LIC 证券的目的是获得 LIC 经理人的技能和专业知识,他们利用积极的投资策略来超越既定的基准。对于持有 LIC 证券的投资者,每年收取 1.0-1.5%的管理费。当回报率高于规定的基准时,低收入国家收取绩效费也并不少见,通常为基准回报率的 10-20%(first links,2016)。
被动交易所交易基金(ETF)——与主动管理的低收入国家不同,被动管理的 ETF 的目标是复制既定基准的表现,如市场指数(ASXETFS.com 2019)。投资者持有被动 ETF 的预期费用通常只是主动管理型低收入国家的一小部分。例如,我们的分析使用 Vanguard Australia n Shares Index ETF(VAS ),该指数试图在考虑费用之前跟踪标准普尔/ASX 300 指数的回报,截至 2020 年 5 月,费用为每年 0.1%(Vanguard 2020)。
为什么投资者更喜欢 LIC 而不是被动型 ETF? —使用上面介绍的 CAPM 术语,投资者选择 LIC 投资而不是被动 ETF 的主要原因是相信 LIC 经理采用的主动投资策略将产生“alpha”回报( alpha > 0),同时将风险敞口降至最低。
实例分析——评估过去 5 年里低收入国家的绩效
以下章节将利用 Jensen (1968)的 CAPM 方法,通过获得每种证券的 alpha 和 beta 参数的估计值,来检验澳大利亚低收入国家的历史表现。此外,我们将使用我们的发现来评估构建投资组合的潜力,以复制使用被动指数跟踪交易所交易基金(ETF),即先锋澳大利亚股票指数 ETF (VAS)和澳大利亚联邦政府债券的 LIC 资产的回报。
我们分析的首要任务是获得所需的数据。我们决定使用过去 5 年的月度回报数据,因为这是计算 CAPM 参数*的常见时间框架和频率,但是,分析和代码可以很容易地进行调整,以适应替代的时间框架和频率。在我们的分析中,我们使用了从 2015 年 6 月 1 日到 2020 年 3 月 1 日的退货数据。
[这是目前在雅虎(Au)上用于 beta 计算的时间框架和频率】*
数据收集
LIC 列表— 从https://www.asxlics.com获得当前在 ASX 交易的 118 个低收入国家的列表,作为数据帧导入 R 并清理。
# IMPORT AND TIDY LIC LIST #################################
LICs <- read.csv("https://www.asxlics.com/uploads/csv/20200401-lics.csv", header = TRUE)
n <- nrow(LICs)
LICs <- LICs[c(2:n), 1:3]
lic.colnames <- c("Code", "Company", "Market Cap")
names(LICs) <- lic.colnames
ticker <- as.character(LICs[,1])
row.names(LICs) <- ticker
无风险利率数据— 主权政府债券作为“无风险”资产在金融领域被广泛使用(Investopedia 2020b)。在我们的分析中,我们将使用 5 年到期的澳大利亚联邦政府债券的收益率数据*。这一数据可以从澳大利亚储备银行的网页上获得。
[选择 5 年时间框架只是因为它与为数据收集选择的 5 年时间框架非常匹配。]*
[**在将这些数据导入 R 之前,我们很快在 Excel 中将日期格式化为 YYYY-MM-DD。]
# IMPORT AND TIDY RISK-FREE RATE DATA ######################
Rf <- import("f2.1-data.csv") ## need to have manually formatted dates to YYYY-MM-DD in Excel
n <- nrow(Rf)
Rf <- Rf[c(12:n), c(1, 4)]
Rf <- Rf[!apply(Rf == "", 1, all),]
Rf$V1 <- as.Date(Rf$V1)
Rf$V4 <- as.numeric(Rf$V4)
Rf$V4 <- ((1+(Rf$V4/100))^(1/12)-1)
Rf <- xts(Rf$V4, order.by = Rf$V1)
names(Rf) <- c("Rf")
基准指数数据— 我们选择使用被动管理的先锋澳大利亚股票指数 ETF (VAS) 的定价数据作为市场回报的代理。该基金寻求跟踪标准普尔/ASX 300 指数的回报,因此,如果我们明确使用该市场指数的直接价格数据,或者在较小的程度上使用其他指数,如 All Ordinaries 或标准普尔/ASX 200 指数,我们预计会获得可比的结果。使用 Vanguard ETF 数据的原因是,它将使我们能够根据我们的初始 CAPM 建模轻松地生成复制投资组合。增值服务的历史价格数据从雅虎财经获得。我们使用“Adj. Close”价格数据,因为该数据系列针对股息分配进行了调整,并使我们的分析能够考虑投资者有权获得的股息现金流以及资本收益回报。
# IMPORT AND TIDY BENCHMARK DATA ###########################
Rb <- read.csv("https://query1.finance.yahoo.com/v7/finance/download/VAS.AX?period1=1430265600&period2=1588118400&interval=1mo&events=history")
n <- nrow(Rb)
Rb <- Rb[c(1:n-1), c(1,6)]
Rb$Date <- as.Date(Rb[, 1])
Rb <- xts(Rb$`Adj.Close`, order.by = Rb$Date)
names(Rb) <- c("Rb")
Rb$Rb <- Return.calculate(Rb$Rb, method = "log")
LIC 数据— 低收入国家清单随后被用于从雅虎财经获得每一个低收入国家的历史定价数据。再次使用“可调接近”价格数据。使用 R,将数据与无风险数据和基准数据一起编译到一个 xts 对象中,然后进行裁剪。
# IMPORT AND TIDY LIC DATA #################################
url_f <- "https://query1.finance.yahoo.com/v7/finance/download/"
url_e <- ".AX?period1=1430265600&period2=1588118400&interval=1mo&events=history"
n <- nrow(LICs)
data <- merge(Rf, Rb)
k <- nrow(data)
for(i in 1:n){
url_temp_ch <- as.character(LICs[i,1])
url_temp <- paste(url_f, url_temp_ch, url_e, sep = "")
Ra_temp <- data.frame(rep(NA, k))
try(Ra_temp <- read.csv(url_temp, na.strings = c("null")), silent = T)
n_temp <- nrow(Ra_temp)
try(Ra_temp <- Ra_temp[c(1:n_temp-1), c(1,6)], silent = T)
if(is.na(Ra_temp[1, 1]) != TRUE){
Ra_temp$Date <- as.Date(Ra_temp[, 1])
Ra_temp <- xts(Ra_temp$`Adj.Close`, order.by = Ra_temp$Date)
header <- as.character(LICs[i,1])
names(Ra_temp) <- header
Ra_temp[, 1] <- Return.calculate(Ra_temp[, 1], method = "log")
data <- merge(data, Ra_temp)
rm(Ra_temp)
}
else if(is.na(Ra_temp[1, 1]) == TRUE){
data_temp <- data
data_temp$Rf <- rep(data_temp[1, 2], k)
data_temp <- data_temp$Rf
header <- as.character(LICs[i,1])
names(data_temp) <- header
data <- merge(data, data_temp)
rm(data_temp)
}
}
n <- nrow(data)
data <- data[complete.cases(data[1:n, c(1, 2)]),]
LIC.list <- names(data)
names(data) <- LIC.list
n <- ncol(data)
LIC.list <- LIC.list[3:n]
生成 CAPM 变量— 如上所述,CAPM 回归分析要求我们计算每个 LIC 的“超额收益”和“市场风险溢价”。如果我们希望导出并保存数据,这些数据将被计算并添加到一个名为“capm.data”的新数据框架中。
# GENERATE CAPM VARIABLES ##################################
n <- ncol(data)
capm.data <- as.xts(merge(data$Rf, data$Rb-data$Rf))
names(capm.data) <- c("Rf", "mrp")
for(i in 3:n){
Ra.Er_temp <- as.xts(data[, i]-data$Rf)
header <- as.character(names(data))
header <- paste(header, ".Er", sep = "")
names(Ra.Er_temp) <- header[i]
capm.data <- merge(capm.data, Ra.Er_temp)
}
n <- ncol(capm.data)
LICs$Code <- LIC.list
计算 CAPM 参数α和β
编辑完数据后,我们现在准备计算 CAPM 参数α和β。为此,我们使用一系列线性回归,将我们的低收入国家的“超额收益”作为因变量,将“市场风险溢价”作为解释变量。值得注意的是,并非我们所有的低收入国家都有整个 5 年期的数据,因此,由于可用数据点较少,一些参数的估计会不太精确*。下面的代码计算参数 alpha 和 beta ,并使用 t-test 函数来生成 p 值,这样我们就可以对参数估计的精确度有所了解。
[同样,人们可能更喜欢调整时间框架和频率来缓解这一问题。】*
# LOAD t-TEST FUNCTION #####################################
ttest <- function(reg, coefnum, val){
co <- coef(summary(reg))
tstat <- (co[coefnum,1]-val)/co[coefnum,2]
2 * pt(abs(tstat), reg$df.residual, lower.tail = FALSE)
}
# CALCULATE CAPM PARAMETERS ################################
n <- ncol(capm.data)
capm.para <- data.frame()
for(i in 3:n){
try(
capm <- lm(capm.data[, i] ~ capm.data$mrp)
, silent = T)
para.temp <- data.frame(rep(0, 4))
try(para.temp <- capm$coefficients, silent = T)
para.temp <- as.data.frame(para.temp)
para.temp <- as.data.frame(transpose(para.temp))
try(para.temp[1, 3] <- ttest(capm, 1, 0), silent = T)
try(para.temp[1, 4] <- ttest(capm, 2, 1), silent = T)
names(para.temp) <- c("alpha", "beta", "alpha(0) ~ Pr(>|t|)", "beta(1) ~ Pr(>|t|)")
row.names(para.temp) <- as.character(LICs[i-2,1])
capm.para[i-2, 1:4] <- para.temp[1, 1:4]
try(rm(capm), silent = T)
rm(para.temp)
}
row.names(LICs) <- LICs$Code
LICs <- merge(LICs, capm.para, by.x = 1, by.y = 0, all.x = TRUE, all.y = TRUE)
对于 beta ,我们简单地测试了我们的估计值与 1 无关的假设,即 LIC 证券倾向于与市场整体一致*移动。
[该测试和随后的 p 值与我们的特定分析路线不太相关,但是,可以修改 t 测试来测试是否与任何特定值无关,因此,如果我们选择将我们的分析深入到个别低收入国家,以及它们在历史上如何对更广泛的市场波动做出反应,这可能是有用的。]*
对于 alpha ,我们的假设是我们的估计值从零开始是无关紧要的,这表明我们还没有发现 LIC 经理人的表现优于市场,或者根据我们收集的数据,有证据表明 CAPM 不成立。因此,我们只需检查我们是否获得了任何 lic 的正的且具有统计显著性的 alpha 值。
# CHECK FOR POSITIVE AND SIGNIFICANT ALPHA RETURNS #########
LICs$alpha.rtns <- ifelse(LICs$`alpha(0) ~ Pr(>|t|)`<= 0.05 & LICs$alpha > 0.0, "TRUE", "FALSE")
我们的结果显示,在此期间,没有 LIC 取得了统计上显著的(在 95%的置信水平下)和正的 alpha 回报。事实上,只有一个 LIC 的估计 alpha 值在统计上不同于零,在这种情况下, alpha 值为-0.0051,这表明相对于系统风险敞口,这个 LIC 的表现低于市场。如果我们将“显著性”截止值扩大到 90%的置信水平,我们只发现一个额外的具有显著 alpha 值的低收入国家,同样估计为负值,表明表现不佳。因此,我们可以得出结论,我们的分析无法找到证据表明,相对于风险敞口,积极管理的地方政府投资公司为投资者带来的回报明显不同于更广泛市场的回报。
排序结果表的标题
构建复制产品组合
由于我们现在已经看到,低收入国家并没有通过提供具有统计意义的更高回报来超越市场,我们能够将无风险资产和市场跟踪 ETF 相结合,以更低的风险敞口复制 LIC 的回报。从我们上面关于 alpha 回报的发现中,我们知道我们的复制投资组合和 LIC 证券投资组合的预期回报在统计上不会彼此不同*。因此,如果我们能够证明,与相对 LIC 相比,我们的复制投资组合表现出较小的回报差异,我们就可以确信,这些投资组合为投资者提供了可比的回报,同时降低了风险。
[在这一点上,我们还需要提醒自己,我们没有考虑到地方投资公司可能收取的任何管理费或绩效费。]*
计算 lic 及其相对复制组合的标准差
我们首先需要使用每个 LIC 之前产生的数据序列来计算 LIC 超额收益的标准差。
# CALCULATE SD(x) FOR LICs #################################
k <- ncol(data)-2
sd.temp <- as.numeric(vector())
er.list <- names(capm.data)
n <- nrow(er.list)
er.list <- er.list[3:(k+2)]
for(i in 1:k){
sd.temp[i] <- STDEV(capm.data[, er.list[i]])
}
sd.temp <- as.data.frame(as.numeric(sd.temp))
row.names(sd.temp) <- LIC.list
names(sd.temp) <- c("SD(ER_at)")
LICs <- merge(LICs, sd.temp, by.x = 1, by.y = 0, all.x = TRUE, all.y = TRUE)
接下来,我们需要计算复制投资组合的超额回报,首先计算每个时期的历史回报,然后减去无风险利率。由此,可以计算复制投资组合超额收益的标准差。
# CALCULATE SD(x) FOR REP. PORT. ###########################
k <- nrow(data)
j <- nrow(LICs)
sd.temp <- as.numeric(vector())
for(i in 1:j){
beta.temp <- as.data.frame(rep(LICs[i, 5], k))
rep.port.temp <- beta.temp
Rf.temp <- as.numeric(data$Rf)
rep.port.temp <- add_column(rep.port.temp, Rf.temp, .after = 100)
rtn.temp <- as.data.frame(data[, 2])
rep.port.temp <- add_column(rep.port.temp, rtn.temp, .after = 100)
names(rep.port.temp) <- c("Beta", "Rf", "Rtn")
port.temp <- (1-rep.port.temp$Beta)*rep.port.temp$Rf+rep.port.temp$Beta*rep.port.temp$Rtn
rep.port.temp <- add_column(rep.port.temp, port.temp, .after = 100)
names(rep.port.temp) <- c("Beta", "Rf", "Rtn", "Port. Rtn")
rep.port.temp$`Port. Rtn` <- as.numeric(unlist(rep.port.temp$`Port. Rtn`))
rep.port.temp$Rtn <- as.numeric(unlist(rep.port.temp$Rtn))
rep.port.temp$Exc.Port.Rtn <- as.numeric(unlist(rep.port.temp$`Port. Rtn`-rep.port.temp$Rf))
sd.temp[i] <- STDEV(rep.port.temp[, 5])
}
LICs$"SD(ER_pt)" <- sd.temp
最后,我们检查我们的复制投资组合的回报率的标准差是否低于 LIC 证券的回报率,这表明风险暴露较少。
# COMPARE SD(x) PERFORMANCE ################################
LICs$'Lower Rep. Port. Risk?' <- ifelse(LICs$`SD(ER_pt)` <= LICs$`SD(ER_at)`, "TRUE", "FALSE")
结果表明,对于我们分析中的每个 LIC,我们都能够产生一个复制投资组合,将被动指数跟踪 ETF 和无风险资产结合起来,这将产生可比的回报率,同时使投资者面临更小的风险。
结果表主管(包括复制组合风险分析)
结论
我们通过这一分析表明,在我们的样本期(2015 年 6 月 1 日至 2020 年 3 月 1 日)内,我们未能拒绝我们的假设,即 LIC 经理人无法持续提供高于持有被动指数跟踪 ETF 和无风险资产的复制投资组合所提供的回报。此外,持有 LIC 证券的投资者被收取更高的管理费,在某些情况下,还要收取绩效费,他们持有这些证券是因为他们相信,他们的 LIC 经理的专业技能将会以最低的风险敞口带来最高的回报。然而,我们已经看到,通过持有复制投资组合,投资者也将能够减少他们的风险敞口。
需要注意的是,与所有金融资产一样,过去的表现并不总是未来表现的可靠指标。上述分析使用了 5 年的月度价格数据,使用不同的时间框架和周期可能会产生不同的结果。我发布这篇文章的目的不是提供财务建议,而是分享方法和编码,让其他人根据自己的喜好复制。
感谢您一直读到文章结尾!很想听听大家对以上的任何评价。欢迎随时留言,或者通过 LinkedIn 联系我。
r 包装清单
# Packages #############################pacman::p_load(pacman, expss, jtools, NCmisc, PerformanceAnalytics, purrr, quantmod, rio, stats, tibble, tidyquant, utils, xts, zoo)
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
参考
ASXETFS.com(2019 年)——https://www.asxetfs.com【访问日期:2020 年 5 月 8 日】
ASXLICS.com(2019 年)——https://www.asxlics.com【访问日期:2020 年 5 月 8 日】
布鲁克斯,C . 2008,《金融计量经济学导论》,第二版,剑桥大学出版社
Firstlinks (2016 年)——https://www . first links . com . au/understanding-lic-fee-structures【2020 年 8 月 5 日访问】
投资媒体(2019 年 a)——https://www.investopedia.com/terms/u/unsystematicrisk.asp【2020 年 5 月 8 日访问】
investopedia(2019 年 b)—https://www.investopedia.com/terms/s/systematicrisk.asp【2020 年 5 月 8 日访问】
investopedia(2020 a)—https://www.investopedia.com/terms/c/capm.asp【2020 年 8 月 5 日访问】
investopedia(2020 年 b)—https://www.investopedia.com/terms/r/riskfreeasset.asp【2020 年 5 月 8 日访问】
澳洲储备银行(2020)——【https://www.rba.gov.au/statistics/tables/#interest-rates 【2020 年 08 月 05 日获取】
先锋(2020)——https://www . vanguard investments . com . au/ret/ret/investments/product . html #/fund detail/ETF/portId = 8205/?概述【访问日期:2020 年 8 月 5 日】
雅虎财经(2020 年)——https://au.finance.yahoo.com【2020 年 5 月 8 日采访】
图片:pixabay.com
使用类进行机器学习
使用面向对象编程来构建模型
Clem Onojeghuo 在像素上拍摄的照片
类提供了一种结合数据和功能的有用方式。类的模块化支持有效的故障排除、代码重用和问题解决。例如,如果您的代码中断,您将能够指向一个特定的类或类方法,而不必筛选太多其他代码。由于这些因素,模型开发自然地适合于面向对象的编程实践。
在本帖中,我们将讨论如何使用面向对象编程来读取数据、分割数据以进行训练、拟合模型以及进行预测。我们将使用天气数据,这些数据可以在这里找到。
在我们开始之前,让我们进口熊猫:
import pandas as pd
现在,让我们定义一个名为 Model 的类:
class Model:
def __init__(self, datafile = "weatherHistory.csv"):
self.df = pd.read_csv(datafile)
该类将有一个“init”函数,也称为构造函数,它允许我们在创建该类的新实例时初始化数据。我们可以将一个新变量“model_instance”定义为一个对象(模型类的一个实例):
if __name__ == '__main__':
model_instance = Model()
我们应该能够通过对象“model_instance”访问数据框让我们调用数据框并打印前五行数据:
if __name__ == '__main__':
model_instance= Model()
print(model_instance.df.head())
看起来不错。
接下来我们可以在初始化函数中定义一个线性回归对象。不要将它与“model_instance”混淆,后者是我们的自定义类“model”的一个实例:
class Model:
def __init__(self, datafile = "weatherHistory.csv"):
self.df = pd.read_csv(datafile)
self.linear_reg = LinearRegression()
同样,值得注意的是 LinearRegression 是一个独立于我们的自定义“模型”类的类,并且在代码行中:
self.linear_reg = LinearRegression()
我们正在定义 LinearRegression 类的一个实例。
现在,让我们确保可以访问我们的线性回归对象:
if __name__ == '__main__':
model_instance = Model()
print(model_instance.linear_reg)
接下来我们要做的是定义一个方法,让我们分割数据用于训练和测试。该函数将采用一个“test_size”参数,让我们指定训练和测试的规模。
首先,让我们从“sklearn”中导入“train_test_split”方法,并导入“NumPy”:
from sklearn.model_selection import train_test_split
import numpy as np
我们将建立一个线性回归模型来预测温度。为简单起见,让我们用“湿度”和“压力(毫巴)”作为输入,用“温度”作为输出。我们将分割方法定义如下:
def split(self, test_size):
X = np.array(self.df[['Humidity', 'Pressure (millibars)']])
y = np.array(self.df['Temperature (C)'])
self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(X, y, test_size = test_size, random_state = 42)
接下来,让我们打印“X_train”和“y_train”以供检查:
if __name__ == '__main__':
model_instance = Model()
model_instance.split(0.2)
print(model_instance.X_train)
print(model_instance.y_train)
我们现在将为线性回归模型定义一个“拟合”函数:
def fit(self):
self.model = self.linear_reg.fit(self.X_train, self.y_train)
我们还将定义一个“预测”函数:
def predict(self):
result = self.linear_reg.predict(self.X_test)
return result
现在,让我们打印我们的测试预测,其中测试规模是数据的 20%:
if __name__ == '__main__':
model_instance = Model()
model_instance.split(0.2)
model_instance.fit()
print(model_instance.predict())
我们还可以打印模型性能:
if __name__ == '__main__':
model_instance = Model()
model_instance.split(0.2)
model_instance.fit()
print("Accuracy: ", model_instance.model.score(model_instance.X_test, model_instance.y_test))
我们还可以向我们的 predict 方法传递一个“input_value”参数,这将允许我们做出样本外的预测。如果“无”通过,则将对测试输入进行预测。否则,将对“输入值”进行预测:
def predict(self, input_value):
if input_value == None:
result = self.linear_reg.predict(self.X_test)
else:
result = self.linear_reg.predict(np.array([input_value]))
return result
让我们用一些样本外的测试输入来预测:
if __name__ == '__main__':
model_instance = Model()
model_instance.split(0.2)
model_instance.fit()
print(model_instance.predict([.9, 1000]))
我们还可以将随机森林回归模型对象定义为模型字段,并运行我们的脚本:
class Model:
def __init__(self, datafile = "weatherHistory.csv"):
self.df = pd.read_csv(datafile)
self.linear_reg = LinearRegression()
self.random_forest = RandomForestRegressor()
def split(self, test_size):
X = np.array(self.df[['Humidity', 'Pressure (millibars)']])
y = np.array(self.df['Temperature (C)'])
self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(X, y, test_size = test_size, random_state = 42)
def fit(self):
self.model = self.random_forest.fit(self.X_train, self.y_train)
def predict(self, input_value):
if input_value == None:
result = self.random_forest.fit(self.X_test)
else:
result = self.random_forest.fit(np.array([input_values]))
return result if __name__ == '__main__':
model_instance = Model()
model_instance.split(0.2)
model_instance.fit()
print("Accuracy: ", model_instance.model.score(model_instance.X_test, model_instance.y_test))
您可以轻松地修改代码来构建支持向量回归模型、“xgboost”模型等等。我们可以通过向构造函数传递一个参数来进一步一般化我们的类,当指定时,该构造函数从可能的模型列表中选择。
逻辑可能看起来像这样:
class Model:
def __init__(self, datafile = "weatherHistory.csv", model_type = None):
self.df = pd.read_csv(datafile) if model_type == 'rf':
self.user_defined_model = RandomForestRegressor()
else:
self.user_defined_model = LinearRegression()
并且修改了“拟合”和“预测”方法:
def fit(self):
self.model = self.user_defined_model.fit(self.X_train, self.y_train)
def predict(self, input_value):
if input_value == None:
result = self.user_defined_model.fit(self.X_test)
else:
result = self.user_defined_model.fit(np.array([input_values]))
return result
我们执行如下:
if __name__ == '__main__':
model_instance = Model(model_type = 'rf')
model_instance.split(0.2)
model_instance.fit()
print("Accuracy: ", model_instance.model.score(model_instance.X_test, model_instance.y_test))
如果我们传递“None ”,我们会得到:
if __name__ == '__main__':
model_instance = Model(model_type = None)
model_instance.split(0.2)
model_instance.fit()
print("Accuracy: ", model_instance.model.score(model_instance.X_test, model_instance.y_test))
我将在这里停下来,但我鼓励您添加额外的模型对象。您可以尝试的一些有趣的例子是支持向量机、“xgboost”回归和“lightgbm”回归模型。添加帮助器方法也很有用,这些方法可以为任何数字列生成汇总统计信息,如平均值和标准偏差。您还可以定义通过计算统计数据(如相关性)来帮助您选择要素的方法。
概括地说,在这篇文章中,我讨论了如何在面向对象编程框架中构建机器学习模型。这个框架对于故障诊断、问题解决、字段收集、方法收集等等非常有用。我希望您能在自己的数据科学项目中找到 OOP 的用处。这篇文章的代码可以在 GitHub 上找到。感谢阅读,机器学习快乐!
使用聚类改进分类—一个用例
提升朴素贝叶斯文本分类
在今天的博客中,我们将给出一篇发表在印度期刊《国际学术研究通知》上的早期文章的直觉。标题中给出了故事的情节。体裁是文本分类。主角是朴素贝叶斯和 k 均值。
这篇文章有两个目的
- 激励你尝试自己的直觉(开始可能有点疯狂,比如使用聚类进行分类,实际上我被我的一位教授骂了一顿)并转化为正式的方法
- 将作为将直觉转化为成熟的研究文章的蓝图。最重要的部分是你如何系统地建立你的工作方法。
它可以分为以下任务
任务 1:确定朴素贝叶斯需要改进
我们选取了 3 个公开可用的数据集。挑选了另外 3 种最大似然算法,并做了实证研究。
图 1:朴素贝叶斯与其他分类器(来源:作者)
这足以说明与其他算法相比,朴素贝叶斯的性能确实不佳。
提示:为了再现性,给出尽可能多的程序细节。挑选足够流行的算法进行比较。
还值得努力吗?我举两个论据,朴素贝叶斯是最容易理解的方法之一,其次,它相当快。
为了快速理解朴素贝叶斯,您可以使用参考文献 3
任务 2:发展直觉
这没有固定的公式。我们的想法是朴素贝叶斯假设特征或属性相互独立。这是它非常快的原因之一,同时这也是一个限制的弱点。对于文本分类,单词是我们的特征。具体来说,使用由来已久的 tf-idf 技术将文本转换成数字。更多的细节你可以查阅参考文献 5。
T 也就是说,如果它想吃披萨,就给他吃披萨,而不是全餐自助餐。
我们如何找到独立的或者相对独立的单词?
嵌入:第一步是拥有单词的特征表示。我们的观点是,如果两个单词在文档中出现的频率相似,那么它们就是相似的。我们来举个例子。
图 2:单词的嵌入(来源:作者)
如果我们看上面的表,并假设勾号表示文档中存在该单词,而叉号表示文档中不存在该单词,那么我们可以得出结论
- 单词 1 和单词 2 不相似
- 单词 2 和单词 3 相似
现在,如果我们把这种直觉松散地延伸一下,得出不是很相似的词相对独立的结论,可能不是很不正确。
如何轻松找到一组相对独立的单词?
字数和文档数量都很庞大。我们怎么可能在这么大的矩阵中找到它呢?另一个直觉,如果我们能根据相似度对特征进行分组,我们能不能不得到相对独立的词(特征)组。怎么做?这难道不像是一个集群问题吗?答对了!我们简单的对单词嵌入使用 k-means
- 形成 k 个聚类,每个聚类将有一组相似的单词
- 从每个聚类中选出一个有代表性的单词(最接近平均值)
这是论文的关键所在。有一些细微的差别,我会推荐你读这篇文章。我们首先使用卡方来删除一些特征(改天会有更多),让我们假设它有助于剔除无关紧要的单词。这种特征选择方法,我们称之为 FSCHICLUST。
我们可能有兴趣知道,通过这种方法减少了多少单词?
图 FSCHICLUST 实现的特征减少百分比(来源:作者)
我们可以从图 3 中看到,现在使用的单词数量显著减少。你一定很怀疑,就这么几句话,真的有用吗?我们现在回答这个问题。
任务 3:建立你的方案作品
这是一个棘手的部分,我们需要通过打破它来真正地计划好它。
- 首先,它比普通的朴素贝叶斯好吗?
- 其次,如果是(第一个问题的答案),那么性能是否可以与其他分类器相比?
- 第三,如果我们用朴素贝叶斯应用任何标准的特征选择算法,我们的方法工作得更好吗?
我们必须证明这些词集是否提供了更好的分类准确性,这次我们增加了数据集的数量。
图 4:使用 FSCHICLUST 的朴素贝叶斯和特征选择(来源:作者)
与其他分类器相比,它做得好吗?分类器在相同的数据集上进行比较。
图 5:改进的朴素贝叶斯与其他分类器(来源:作者)
第三,与其他特征选择算法相比,它做得好吗
图 6:使用其他特征选择算法提出方法(来源:作者)
因此,我们看到我们所有的问题都得到了很好的满足,所以它可能也会满足审查者。
结论:
在本文中,我们讨论了如何使用 k-means 在文本分类中改进朴素贝叶斯。
- 我们首先确定朴素贝叶斯做得不好。
- 然后,我们开发了一个基于聚类的特征选择方案,只选择几个词
- 论证这个方案的工程,如前所述,这必须系统地进行,可能是最重要的一点。
参考文献:
[1] Dey Sarkar S,Goswami S,Agarwal A,Aktar J .使用朴素贝叶斯进行文本分类的新特征选择技术。国际学术研究通知。2014;2014.(【https://www.hindawi.com/journals/isrn/2014/717092/】T2
[2] Sarkar、Subhajit Dey 和 Saptarsi Goswami。“基于过滤器的文本分类特征选择方法的实证研究。”国际计算机应用杂志 81.6 (2013)。
[3]https://towards data science . com/all-about-naive-Bayes-8e 13 cef 044 cf
https://archive.ics.uci.edu/ml/datasets.php
使用 ColumnTransformer 组合数据处理步骤
在不同列需要不同技术的情况下,创建内聚管道来处理数据
这个 scikit-learn 工具非常方便,但也有自己的一些怪癖。今天,我们将使用它来转换华盛顿州渡轮埃德蒙兹-金斯顿航线的渡轮等待时间数据。(谢谢 WSF 提供的数据!).完全公开:我们今天只使用数据集的一小部分。
更全面的披露——来自 scikit-learn 的警告:“警告:[**compose.ColumnTransformer**](https://scikit-learn.org/stable/modules/generated/sklearn.compose.ColumnTransformer.html#sklearn.compose.ColumnTransformer)
类是实验性的,API 可能会改变。”
华盛顿州渡口。布莱恩·汉森在 Unsplash 上的照片
一般概念和用途
当您创建一个不同列需要不同转换的数据管道时,ColumnTransformers 就派上了用场。也许你有分类和数字特征的组合。也许您希望使用不同的插补策略来填充不同数字列中的 nan。您可以分别转换每一列,然后将它们缝合在一起,或者您可以使用 ColumnTransformer 来完成这项工作。
这里有一个基本的例子。在这种情况下,我们的输入要素是工作日(0–6 周一至周日)、小时(0–23)以及最高、平均和最低日温度。我想标准规模的温度功能和一个热编码的日期功能。
假设我已经加载了输入和目标数据帧(X_train,y_train ):
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline# define column transformer and set n_jobs to use all cores
col_transformer = ColumnTransformer(
transformers=[
('ss', StandardScaler(), ['max_temp',
'avg_temp',
'min_temp']),
('ohe', OneHotEncoder(), ['weekday',
'hour'])
],
remainder='drop',
n_jobs=-1
)
然后我们就可以开始转型了!
X_train_transformed = col_transformer.fit_transform(X_train)
我们得到:
<465x30 sparse matrix of type '<class 'numpy.float64'>'
with 2325 stored elements in Compressed Sparse Row format>
更有可能的是,您将把 ColumnTransformer 添加为管道中的一个步骤:
lr = LinearRegression()pipe = Pipeline([
("preprocessing", col_transformer),
("lr", lr)
])pipe.fit(X_train, y_train)
现在你的烟斗可以做预测了!或者用于交叉验证,而不会跨切片泄漏信息。
注意,我们需要以转换器期望的格式来指示列。如果转换器需要一个 2D 数组,那么传递一个字符串列的列表(即使它只有一列——例如[‘col1']
)。如果转换器需要一个 1D 数组,只需传递字符串列名,例如'col1'
。
但是事情并不总是这么简单——可能您的数据集具有空值,并且需要在同一列上进行多次转换,您想要一个自定义的转换器,或者您想要更深入地挖掘功能的重要性,可能并不是所有 OneHotEncoder 类别实际上都保证会出现在所有数据片中。
技巧 1:对任何需要多次转换的列使用管道
我第一次使用 ColumnTransformer 时,我认为它会按顺序执行转换,我可以从在任何列上简单地输入 nan 开始,然后 StandardScale(r)一个重叠的列子集,然后 OneHotEncode 另一个重叠的列子集,等等。我错了。如果您想要在同一列上进行多次转换,您需要一个管道。这意味着每组得到相同处理的列都有一个管道,例如:
# define transformers
si_0 = SimpleImputer(strategy='constant', fill_value=0)
ss = StandardScaler()
ohe = OneHotEncoder()# define column groups with same processing
cat_vars = ['weekday', 'hour']
num_vars = ['max_temp', 'avg_temp', 'min_temp']# set up pipelines for each column group
categorical_pipe = Pipeline([('si_0', si_0), ('ohe', ohe)])
numeric_pipe = Pipeline([('si_0', si_0), ('ss', ss)])# set up columnTransformer
col_transformer = ColumnTransformer(
transformers=[
('nums', numeric_pipe, num_vars),
('cats', categorical_pipe, cat_vars)
],
remainder='drop',
n_jobs=-1
)
技巧 2:跟踪你的列名
来自 scikit-learn 文档:“转换后的特征矩阵中的列顺序遵循在transformers
列表中指定列的顺序。除非在passthrough
关键字中指定,否则原始特征矩阵中未指定的列将从结果转换后的特征矩阵中删除。用passthrough
指定的那些列被添加到变压器输出的右边。”
对于上面的例子,预处理的数组列是:
[‘max_temp’, ‘avg_temp’, ‘min_temp, ‘weekday_0’, ‘weekday_1’, ‘weekday_2’, ‘weekday_3’, ‘weekday_4’, ‘weekday_5’, ‘weekday_6’, ‘hour_0’, ‘hour_1’, ‘hour_2’, ‘hour_3’, ‘hour_4’, ‘hour_5’, ‘hour_6’, ‘hour_7’, ‘hour_8’, ‘hour_9’, ‘hour_10’, ‘hour_11’, ‘hour_12’, ‘hour_13’, ‘hour_14’, ‘hour_15’, ‘hour_16’, ‘hour_17’, ‘hour_18’, ‘hour_19’, ‘hour_20’, ‘hour_21’, ‘hour_22’, ‘hour_23’]
这是非常繁琐的手工操作。对于提供功能名称的转换,您可以像这样访问它们:
col_transformer.named_transformers_['ohe'].get_feature_names()
这里,“ohe”是第一个示例中我的转换器的名称。不幸的是,不能创建更多特性/列的转换器通常没有这个方法,ColumnTransformer 依赖于其内部转换器的这个属性。如果你只使用有这个方法的变压器,那么你可以调用col_transformer.get_feature_names()
来轻松地得到它们。我还没有这个机会,但我们可能会在某个时候。或者这个列跟踪功能可能会被添加到未来的 ColumnTransformer 版本中。
注意:如果你使用管道(就像技巧 1 中一样),你需要更深入一点,使用管道属性named_steps
。在这种情况下:
col_transformer.named_transformers_['cats'].named_steps['ohe']\
.get_feature_names()
技巧 3:随意创造你自己的变形金刚
ColumnTransformer 可以与任何转换器一起工作,所以您可以随意创建自己的转换器。我们今天不打算太深入地研究定制转换器,但是在使用定制转换器和 ColumnTransformer 时,我想指出一点。
对于我们的 ferry 项目,我们可以用一个定制的转换器提取日期特性:
from sklearn.base import TransformerMixin, BaseEstimatorclass DateTransformer(TransformerMixin, BaseEstimator):
"""Extracts features from datetime column
Returns:
hour: hour
day: Between 1 and the number of days in the month
month: Between 1 and 12 inclusive.
year: four-digit year
weekday: day of the week as an integer. Mon=0 and Sun=6
"""def fit(self, x, y=None):
return selfdef transform(self, x, y=None):
result = pd.DataFrame(x, columns=['date_hour'])
result['hour'] = [dt.hour for dt in result['date_hour']]
result['day'] = [dt.day for dt in result['date_hour']]
result['month'] = [dt.month for dt in result['date_hour']]
result['year'] = [dt.year for dt in result['date_hour']]
result['weekday'] = [dt.weekday() for dt in
result['date_hour']]
return result[['hour', 'day', 'month', 'year', 'weekday']]
def get_feature_names(self):
return ['hour','day', 'month', 'year', 'weekday']
注意,ColumnTransformer 以 numpy 数组的形式“发送”列。为了从字符串转换这些时间戳,我将它们转换为 pandas 数据帧(可能不是最优雅的解决方案)。
注意,ColumnTransformer 将所有指定的列一起“发送”到我们的转换器。这意味着您需要设计您的转换器来同时获取和转换多个列,或者确保在 ColumnTransformer 的单独一行中发送每个列。由于我们的自定义转换器仅设计用于处理单个列,因此我们需要像这样定制 ColumnTransformer(假设我们希望在有两个 datetime 列的情况下重用它,我们希望扩展这两个列):
transformers=[(‘dates1’, DateTransformer, [‘start_date’])ct = ColumnTransformer(
transformers=[
(‘dates1’, DateTransformer, [‘start_date’]),
(‘dates2’, DateTransformer, [‘end_date’])
])
提示 4:对“罕见的”分类特征或标志要积极主动
这里的关键是您的模型期望在训练集、测试集和生产输入中有相同数量的特征。
如果我们有任何罕见的分类特征最终没有出现在这些组中,默认的 OneHotEncoding 设置将为不同的输入集产生不同数量的列。
类似地,如果有任何要估算的 nan,SimpleImputer 只创建一个“flag”列。如果一个或多个输入集碰巧没有任何 nan,那么在预处理阶段之后,列的数量将再次不同。
这可能会引发一些不同的错误,包括:
ValueError: Found unknown categories [0] in column 0 during transform
和
ValueError: The features [0] have missing values in transform but have no missing values in fit.
对于 OneHotEncoding 问题,可以在初始化 ohe 时列出类别。如果您有两个分类特征,第一个具有类别“一”和“二”,第二个具有“三月”、“四月”,您可以这样表示:OneHotEncoder(categories=[['one', 'two'], ['March', 'April]])
。
对于 simple imputr,您不能使用一个标志,删除带有 NaN 的列(如果 NaN 很少),调整您的训练测试分割(并确保您的生产输入考虑到这个差异),或者通过添加一个标志列来创建您自己的基于 simple imputr 的转换器,而不管 NaN 是否存在。
今天,这个数据准备步骤感觉有点不令人满意,因为我们还没有从我们的数据集得出任何结论或有趣的事实。但是你们都知道,这是我们预测轮渡等待时间(或者任何你想预测/分类/等等的事情)的必不可少的一步。
和往常一样,查看 GitHub repo 获取完整代码。编码快乐!
利用计算机视觉寻找最佳猫咪照片
与 YOLO、哈尔·卡斯卡特和 CPBD 一起
作者:基拉·巴拉德,安德鲁·傅,什拉万·纳格斯瓦兰,艾米莉·谢
这篇博客文章介绍了作者在哈佛应用计算科学研究所与 Austin Pets Alive 合作的 顶点 课程项目中所做的工作!领养孩子。本文所表达的观点仅代表作者的观点,并不代表他们的合作组织。
TL;博士
我们使用 ML 和计算机视觉技术来优化收容所猫的照片,以提高它们的收养率。见此视频或此海报。
介绍
鉴于美国动物收容所的拥挤问题,每年有数百万收容所的动物被实施安乐死。奥斯汀宠物活着!总部位于德克萨斯州的关注动物福利的组织 APA 试图通过倡导不杀动物来解决这个问题。作为他们努力的一部分,他们已经与一家技术公司 Adoptimize 合作,该公司提供软件来自动选择给定动物视频的最佳照片。由此产生的高质量照片转化为增加的收养率,从而降低安乐死率。然而,尽管 Adoptimize 产生了重大影响,但他们的技术只对狗有效,并不能推广到其他动物。
考虑到收养率较低,收容所的猫比它们的犬类同伴更需要这项技术。作为我们在哈佛的顶点项目的一部分,我们与 APA 和 Adoptimize 合作,为猫开创了一个类似的过程,总体目标是提高猫的收养率,以减少它们安乐死的机会。因此,这个项目的目标是产生一个模型,当给定一个猫的视频时,它能选择最佳的帧。我们最终设计了一个逻辑回归模型,对通过各种计算机视觉技术提取的特征进行预测。
trieu88 的【coraline 1】在 CC BY-ND 2.0 下获得授权
数据和标签
我们的数据由我们的合作伙伴提供的 79 个收容所猫的视频组成。一眼看去,这些视频平均持续时间为 23 秒,最短 2 秒,最长 55 秒。它们大多以每秒 60 帧的速度播放,分辨率一般为 200 万像素。
图 1:直方图显示,我们数据集中的大部分视频大约为 20 秒或更短,而所有视频都不到一分钟。
为了更好地理解我们的数据集,这里有一个示例视频:
虽然筛选起来很有趣,但这些数据在规模和质量方面带来了一些挑战。例如,许多视频是在弱光环境下拍摄的。有时猫在狗窝里,笼子的栅栏挡住了任何清晰的视线。在行为方面,有些猫特别胆小,躲着镜头。数据的另一个挑战是视频质量,因为许多视频是在移动设备上拍摄的,而不是在更高分辨率的摄像机上拍摄的。最后,数据集的大小有限,因为我们只有 79 个视频可以处理。
最重要的是,一个主要的障碍是我们的数据没有按照图像质量来标注。由于受监督的机器学习方法将最好地支持我们获得最佳照片的目标,我们需要找到一种以系统方式标记帧质量(因变量)的方法。
为了实现这一点,我们编写了一个简单的脚本,在我们的数据集中随机采样快照,通过一个准系统 UI 提供给我们,并记录我们的注释。对于质量本身的衡量,我们使用了通常在心理测量调查表格中使用的李克特量表,从 1 到 5 指定一个值,1 表示质量最低的照片,5 表示质量最高。在第一轮“实践”评分之后,为了就哪种类型的图像对应于每个李克特值达成普遍一致,我们坐下来,在我们的视频中共标记了 471 帧。
图 2:我们的标签界面截图。
在检查生成的数据集时,我们发现它略有偏差,因为高质量帧的比例很低(只有 12%的帧得分为 5)。因此,我们决定通过从互联网上获取额外的 20 个剪辑并对它们重复标记过程来扩展这个数据集,使我们的总数据集超过 500 个。唯一的挑战是互联网上没有猫的视频——任何地方都没有。
特征工程
物体检测
我们怀疑我们缺乏足够的数据用于深度学习方法,所以我们在合作伙伴的领域知识的指导下,将我们的努力集中在特征工程上。我们的第一个任务是检测一帧中是否有猫。我们研究了两种不同的对象检测算法:哈尔级联分类器[ 1 ](一种相对传统的方法)以及 YOLO [ 2 ](更接近最先进的技术)。
Haar 级联分类器使用 Haar-like 特征,该特征是相邻矩形区域中像素强度的和与差。Haar-like 特征用于训练决策树桩的 AdaBoost 集合。一系列这样的集成以增加的复杂度和降低的假阳性率来构造,从而尽可能快地拒绝负样本。我们能够使用在 OpenCV 中的猫脸上训练的开箱即用的实现。
YOLO 采用卷积神经网络(CNN)的形式,是一种单程对象检测算法,为对象提出边界框,并同时对它们进行分类。图像被分成网格,每个单元负责产生固定数量的边界框(包括边界框包含对象的置信度)以及类的概率分布,假设存在对象。在这个训练设置和猫数据集 [ 3 ]的帮助下,我们使用了在 ImageNet 上预先训练的 YOLO 网络,并对其进行了微调,以检测猫的头部、耳朵、眼睛和鼻子。
图 3:由 Richardpics2 拍摄的照片 cat-5 上通过我们微调的 YOLO 模型提取的特征。 CC PDM 1.0 。
我们决定使用 YOLO 网络进行对象检测,而不是 Haar 级联分类器,因为它具有更高的召回率和一次检测多个特征的能力。我们将检测到的鼻子、眼睛和耳朵的置信度分数保存为一组预测值。
图 4:鼻子和眼睛的定量对象检测特征测量相对于每一帧的我们的标记类的曲线图都显示了有希望的相关性。
衍生特征
使用边界框,我们能够计算一组额外的特征,包括:
- 从头部中心到框架中心的距离
- 头部相对于框架的大小
- 两只眼睛大小的比例
- 两只耳朵大小的比例
我们认为,头部与图像中点的距离将反映出猫的居中程度,而头部的相对大小将作为猫在图像中所占百分比的一个不错的代表。最后,通过眼睛和耳朵的比例,我们旨在捕捉猫的脸可能偏离相机的角度。
锐利
由于图像清晰度往往是照片质量的一个因素,我们研究了两种不同的清晰度指标:应用拉普拉斯滤波器后像素强度的方差,以及模糊检测的累积概率(CPBD) [ 4 ]。在将这两种方法应用于我们的数据集时,我们只测量了猫头部边界框内区域的锐度。
我们从拉普拉斯方差开始,但是发现这个度量不能准确地表示图像的清晰度。然而,CPBD 指标与我们的数据集表现出了稍好的相关性,并且更容易处理,因为它是在 0-1 范围内标准化的。因此,我们最终选择这种方法作为我们的图像清晰度的措施。
EDA 预测器
在对我们的特征进行进一步的探索性数据分析后,我们发现产生最有希望的相关性的预测因子是由 YOLO 产生的检测到的眼睛、鼻子和耳朵的置信度值。这是有意义的,因为网络的训练数据大多包含正面朝向的猫的图像,这些图像具有安静的特征(警觉的眼睛,没有咆哮的鼻子等)——这些特征在一张好的猫收养照片中是可取的。
图 5:针对耳朵的定量对象检测特征测量和针对每一帧的我们的标记类别的锐度的图都显示了有希望的相关性。
有趣的是,我们也注意到清晰度和图像质量之间的关系并不那么明显。经过进一步思考,这可能是因为“好”的猫照片不一定是最清晰的——一张适度清晰、但带有温暖模糊的照片可能比一张猫脸转向一侧的非常清晰的照片更有吸引力。
此外,我们在要素中发现了某种程度的多重共线性,这需要在建模中解决。
图 6:我们的预测因子的相关矩阵显示了共线性。
造型
基线模型
对于我们的基线,我们用来对我们开发的模型进行测试,我们只是从输入视频中返回任何检测到猫头的随机帧。
初始模型
我们最初的模型基于特征的主观函数,其中我们对子集应用任意权重——在对我们的特征进行更深入的研究之前——我们直觉地认为最相关的是:锐度和头部大小。然后,该模型根据这两个特征的相对排名对每一帧进行评分,并返回得分最高的图像。
然而,这个最初的模型主要是作为一个粗略的概念证明。一旦我们有了足够数量的带注释的数据,我们在构建最终模型时就转向一种更有纪律的数据驱动的方法。
最终模型
我们最终使用了一个逻辑回归分类器来预测给定每个特征的图像质量标签。我们应用 L1 正则化来解决我们在要素中发现的一些共线性。为了进一步调整,我们检查了系数,发现头部的大小和它与中心的距离证明是没有意义的,所以我们删除了这些特征。
最终的模型通过回归运行每一帧,然后选择具有最大可能性的图像作为好或优秀(在 Likert 标度上分别为 4 级或 5 级)。
乍一看,这个模型表现得相当不错。如果我们将先前的示例视频传递给它,我们将返回以下帧:
我们的逻辑回归模型选择的“最佳”框架。
考虑到原始视频很少提供猫完全可见的镜头(因为狗窝栅栏经常与猫重叠),以及经常转向天花板或地面的抖动相机,这被证明是一个特别好的结果(当然,我们通过测试定量评估性能,在下一节中进一步描述)。
其他模式探索
虽然逻辑回归最终产生了最好的结果,但我们也用其他模型进行了实验。简单地说,我们尝试了线性回归,但是发现它产生了无法解释的结果,并且没有胜过逻辑回归。
接下来,我们尝试从头开始训练 CNN。然而,根据我们调整参数的方式,准确性分数仅在 30–40%之间。这很可能是由于我们的数据集的大小,它对于模型中的参数数量来说太小了。这可能是由于给定剪辑中的许多采样帧在逐个像素的基础上是相似的,并且被类似地评级,从而导致网络学习适应特定的视频。
作为应用深度学习的最后一次尝试,我们还研究了迁移学习,使用了在 ImageNet 上预先训练的 InceptionV3 网络。这产生了同样令人失望的结果。
最终结果
考虑到这个问题固有的主观性质——因为没有量化标准来认为一张照片比另一张照片“更好”——我们创建了一个受 A/B 测试启发的框架来评估我们的模型相对于基线的性能。该界面以随机顺序向用户呈现两张照片:一张由开发的模型生成,另一张由基线生成。不知道哪个是哪个的用户必须选择他们认为更好的图像。
图 7:我们的基本盲 A/B 测试框架的界面。
利用这一点,我们根据基线评估了初始和最终模型的性能,并发现了有希望的结果。
初始模型在 64%的时间里被选择在基线之上,而我们的最终模型在 75%的时间里被选择在基线之上,证明了显著的改进(注意,不同的测试集被用于评估两个模型)。如果我们认为照片质量与基线不可区分是成功的,那么我们最终模型的性能指标是甚至更好: 96%的时候,用户要么喜欢我们最终模型的框架,要么无法将其与基线区分开来。
图 8:逻辑回归模型性能的最终结果。
总结与未来工作
通过我们改进的逻辑回归模型,我们的项目证明是成功的,至少在 96%的视频上表现得和基线一样好。我们最终交付给合作伙伴的是一个 web 应用原型,它允许用户上传一只猫的视频,并随后显示我们的模型认为是最好的帧。
在我们项目的范围之外,如果有更多的时间,我们还想探索许多项目。首先,web 应用原型需要相当长的时间来运行,主要是由于逐帧的 YOLO 对象检测。对于较长的视频来说尤其如此,因此并行化这个过程会很有帮助。此外,测量我们的项目一旦被我们的合作伙伴采用后的下游影响将是令人满意的——也就是说,在使用我们的模型返回的照片的情况下,确定猫的收养率是否确实提高了。
最后,作为数据科学家,我们永远不会完全完成;我们总是有能力完善和改进我们的模型——无论这意味着找到可扩展的方法来收集更多数据,还是进行进一步的实验来调整参数。
就这样,我们留给你一张猫的照片。祝你在网上找到另一个。
personaltrainertoronto 的《Kitty》由 2.0 的 CC 授权
致谢
我们要感谢我们在奥斯汀宠物生活和收养的合作伙伴,以及我们的课程导师克里斯·坦纳,感谢他们在整个项目中的指导。最后,我们要感谢哈佛大学应用计算科学研究院给予我们的大力支持。
链接
github:https://github . com/iacs-capstone-2020-adoptimize/final _ project
参考文献
[1] P. Viola 和 M. Jones,“使用简单特征的增强级联的快速对象检测”,2001 年 IEEE 计算机学会关于计算机视觉和模式识别会议的会议录。CVPR 2001 年,第 1 卷,第 I-I 页,2001 年 12 月
[2] J. Redmon,S. Divvala,R. Girshick 和 a .法尔哈迪,“你只看一次:统一的实时对象检测”, 2016 年 IEEE 计算机视觉和模式识别会议(CVPR) ,内华达州拉斯韦加斯,2016 年,第 779–788 页
[3] W. Zhang,J. Sun,和 X. Tang,“猫头检测-如何有效地利用形状和纹理特征”,欧洲计算机视觉会议第 802–816 页,Springer,2008 年。
[4] N. D. Narvekar 和 L. J. Karam,“一种基于模糊检测累积概率的无参考图像模糊度量(CPBD),”IEEE 图像处理汇刊,,第 20 卷,第 9 期,第 2678-2683 页,2011 年 9 月,doi:10.1109/tip . 2011 . 26661 . 2020106
利用余弦相似度构建电影推荐系统
使用余弦相似性构建基于 Python 的电影推荐系统的分步指南
你有没有想象过,在你已经喜欢的电影的基础上,你在高中学习的一个简单的公式会在推荐你一部电影的过程中发挥作用?
好了,现在我们使用余弦相似度(归一化向量的点积)来构建一个电影推荐系统!
什么是推荐系统?
推荐系统是一类重要的机器学习算法,为用户提供“相关”建议。Youtube、亚马逊、网飞,都在推荐系统上发挥作用,系统根据你过去的活动(基于内容的过滤)或根据与你相似的其他用户的活动和偏好(协同过滤)向你推荐下一个视频或产品。同样,脸书也使用推荐系统来推荐你线下可能认识的脸书用户。
推荐系统的工作基于内容或访问内容的用户之间的相似性。
有几种方法可以衡量两个项目之间的相似性。推荐系统使用这个相似矩阵向用户推荐下一个最相似的产品。
在本文中,我们将构建一个机器学习算法,根据用户喜欢的电影推荐电影。这个机器学习模型将基于余弦相似度。
获取数据集
构建电影推荐系统的第一步是获取适当的数据。您可以从网上下载电影数据集,或者从下面的链接下载,该链接包含一个 22MB 的 CSV 文件,标题为“ movie_dataset.csv ”:
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/MahnoorJaved98/Movie-Recommendation-System/blob/main/movie_dataset.csv)
现在让我们来探索数据集吧!
我们的 CSV 文件总共包含了 4802 部电影和 24 个栏目:索引、预算、流派、主页、id、关键词、原创 _ 语言、原创 _ 标题、概述、人气、制作 _ 公司、制作 _ 国家、发行 _ 日期、收入、运行时间、口语、状态、标语、标题、vote_average、vote_count、演员、剧组和导演(唉!).
在所有这些不同的特性中,我们感兴趣的是找出相似之处,以便提出下一个建议,这些特性如下:
关键词、剧组、流派 & 导演。
喜欢恐怖电影的用户很可能会喜欢另一部恐怖电影。一些用户可能喜欢在电影的演员阵容中看到他们最喜欢的演员。其他人可能喜欢某个人导演的电影。结合所有这些方面,我们入围的 4 个特征足以训练我们的推荐算法。
开始编码
现在,让我们从编码开始。首先,让我们导入我们需要的库,以及电影数据集的 CSV 文件。
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similaritydf = pd.read_csv(r"...\movie_dataset.csv")
我们将导入两个重要的库用于数据分析和操作;熊猫和 numpy 。我们还将导入 Scikit-learn 的 CountVectorizer,用于将一组文本文档转换成一个术语/标记计数的向量。
最后,我们将从 sklearn ,中导入余弦 _ 相似度作为我们相似度矩阵的度量(这将在后面详细讨论)。
我们将 CSV 文件读入数据帧 df ,然后可以在 Python IDE 的变量浏览器中访问它。
CSV 加载到数据帧中(图片由作者提供)
功能列表
我们将列出我们将使用的功能。如上所述,考虑到我们手头的问题,我们将只使用与我们最相关的特性。因此,我们选择的功能将是关键词,演员,流派 & 导演。
此外,我们将做一些数据预处理,并用空格/空字符串替换任何具有 NaN 值的行,这样在运行代码时就不会产生错误。这个预处理已经在 for 循环中完成了。
features = ['keywords', 'cast', 'genres', 'director']for feature in features:
df[feature] = df[feature].fillna('')
将相关特征组合成单个特征
接下来,我们将定义一个名为 combined_features 的函数。该函数将把我们所有有用的特征(关键字、演员、流派&导演)从它们各自的行中组合起来,并返回一个包含所有组合特征的行。
def combined_features(row):
return row['keywords']+" "+row['cast']+" "+row['genres']+" "+row['director']df["combined_features"] = df.apply(combined_features, axis =1)
我们将添加一个新列, combined_features 到我们现有的 dataframe (df)中,并将上述函数应用于每一行(轴= 1)。现在,数据帧的末尾将有一个额外的列,由多行组合特征组成。
我们的数据框架中的组合特征栏(图片由作者提供)
提取特征
接下来,我们将从数据中提取特征。
sklearn.feature_extraction 模块可用于从由文本和图像等格式组成的数据集中提取机器学习算法支持的格式的要素。我们将使用 CountVectorizer 的 fit . transform来计算文本的数量,并将转换后的矩阵 count_matrix 打印成一个数组,以便更好地理解。
cv = CountVectorizer()
count_matrix = cv.fit_transform(df["combined_features"])
print("Count Matrix:", count_matrix.toarray())
使用余弦相似度
我们将使用来自 Sklearn 的余弦相似度作为度量来计算两部电影之间的相似度。
余弦相似性是一种用于衡量两个项目相似程度的度量。在数学上,它测量的是在多维空间中投影的两个向量之间的角度余弦。输出值范围从0–1。
0 表示没有相似性,其中 as 1 表示两个项目 100%相似。
余弦相似度(图片由作者提供)
python 余弦相似度或余弦内核将相似度计算为输入样本 X 和 y 的归一化点积。我们将使用 sk learnCosine _ Similarity来查找计数矩阵中两个向量的 cos θ 。
cosine_sim = cosine_similarity(count_matrix)
cosine_sim 矩阵是一个 numpy 数组,用于计算每部电影之间的余弦相似度。下图可以看到,电影 0 与电影 0 的余弦相似度为 1;它们 100%相似(理应如此)。
类似地,电影 0 和电影 1 之间的余弦相似度是 0.105409(电影 1 和电影 0 之间的分数相同——顺序无关紧要)。
电影 0 和 4 比电影 0 和 3 更相似(相似性分数为 0.23094)(分数= 0.0377426)。
带有 1 的对角线表示情况是什么,每部电影“x”都与自己 100%相似!
余弦相似矩阵(图片由作者提供)
用户喜欢的内容
下一步是在 movie_user_likes 变量中输入用户喜欢的电影。
由于我们正在建立一个基于内容的过滤系统,我们需要知道用户的喜欢,以便预测类似的项目。
movie_user_likes = "Dead Poets Society"def get_index_from_title(title):
return df[df.title == title]["index"].values[0]movie_index = get_index_from_title(movie_user_likes)
假设我喜欢电影《死亡诗社》。接下来,我将构建一个函数来从这部电影的名称中获取索引。该索引将保存在 movie_index 变量中。
用户喜欢的电影的电影索引变量(作者图片)
生成相似电影矩阵
接下来,我们将生成一个类似电影的列表。我们将使用我们给出的电影的电影 _ 索引作为输入电影 _ 用户 _ 喜欢。enumerate()方法将向可迭代列表余弦 _sim 添加一个计数器,并以列表相似 _ 电影的形式返回它,其中包含每个索引的相似性得分。
similar_movies = list(enumerate(cosine_sim[movie_index]))
相似电影列表(作者图片)
按降序对相似电影列表进行排序
下一步是对列表中的电影进行排序相似 _ 电影。我们使用了参数 reverse=True,因为我们希望列表按降序排列,最相似的条目在顶部。
sorted_similar_movies = sorted(similar_movies, key=lambda x:x[1], reverse=True)
sorted_similar_movies 将是按照与输入电影 movie_user_likes 的相似性分数降序排序的所有电影的列表。
从下图可以看出,相似度得分为 0.9999999999999999993 的最相似的一个在最上面,其索引号为 2453(电影是我们作为输入给出的'死亡诗社',有道理吧?).
相似分数排序的相似电影列表(图片由作者提供)
印刷相似的电影
现在,项目的最后一部分来了,打印电影的名字,类似于我们通过 movie_user_likes 变量给系统输入的名字。
如 sorted_similar_movies 列表所示,电影按其索引号排序。打印索引号对我们来说没有用,所以我们将定义一个简单的函数,将索引号转换成电影标题,就像在 dataframe 中一样。
索引号→电影名称
接下来我们将在 for 循环中调用这个函数来打印来自 sorted_similar_movies 的第一个“x”个电影。
在我们的例子中,我们将打印 4802 部电影中最相似的 15 部电影。
def get_title_from_index(index):
return df[df.index == index]["title"].values[0]i=0
for movie in sorted_similar_movies:
print(get_title_from_index(movie[0]))
i=i+1
if i>15:
break
运行整个代码
现在应用程序来了。使用上述步骤编写您自己的推荐系统,并通过将您喜欢的电影交给 movie_user_likes 来运行代码。
我给了“死亡诗社”,它给我打印了以下类似的电影:
IPython 控制台(图片由作者提供)
可以看出,最相似的显然是电影本身。算法定义“无事生非”为下一部最相似的电影!(将它添加到我的“观察列表”😄)
本文到此为止!本文提供了一种实践方法,通过在任何 python IDE 上编写代码,从头开始构建推荐系统。
现在,一旦建立了算法,是时候拿些爆米花,看你的系统推荐的电影了!!😁
爆米花时间!(照片由 Unsplash 上的乔治亚·瓦吉姆拍摄)
如何在 SQL 中使用 cte
启动和运行 cte 的介绍
如果您曾经使用过 SQL,您就会知道当您创建一个对以后使用有帮助的编写良好的查询时,它是多么重要。通常,当您查询某个东西时,您只使用它一次,但是有时您需要引用旧的查询——这就是通用表表达式(cte)的用武之地!
一个 CTE 允许你定义一个临时命名的结果集,在一个语句的执行范围内临时可用,比如
[*SELECT*](https://www.sqlservertutorial.net/sql-server-basics/sql-server-select/)
、[*INSERT*](https://www.sqlservertutorial.net/sql-server-basics/sql-server-insert/)
、[*UPDATE*](https://www.sqlservertutorial.net/sql-server-basics/sql-server-update/)
、[*DELETE*](https://www.sqlservertutorial.net/sql-server-basics/sql-server-delete/)
或者[*MERGE*](https://www.sqlservertutorial.net/sql-server-basics/sql-server-merge/)
。
对于本教程,我将假设您具有初级—中级 SQL 经验。如果你没有,这里有一些很好的资源可以帮助你开始。
入门指南
我将从 Datacamp 的 SQL 课程中使用一个电影数据库。(如果你是一名拥有【edu】电子邮件的学生,并且想要获得三个月的免费 Datacamp 访问— GitHub 学生开发者包)。
电影数据库由以下表格(+列)组成:
- 电影——(id、片名、上映年份、国家/地区、时长、语言、认证、总票房、&预算)
- 人——(身份证,姓名,出生日期,&死亡日期)
- 评论——(电影 id,用户数量,评论数量,imdb 评分,投票数量,& facebook 点赞)
- 角色——(id,film_id,person_id,角色)
我们可以看到表格和列。可以用几把钥匙把桌子连接起来。下面是每个表的快照。
影片表( 【数据营】 )
人表(data camp)
评论表(data camp)
角色表(data camp)
CTEs 简介
如前所述,cte 在语句的执行范围内暂时可用。
这是 CTE 的基本布局。
**WITH** CTE_NAME(column_1, column_2, column_3)
**AS**
(--***normal SQl query***
SELECT *
FROM table)
在上面的代码中,CTE 必须以带有的开始。这告诉您的查询这是一个 CTE 语句。接下来, CTE_NAME 是你想给它取的名字。你可以给它起任何名字,但是由于这通常是用于以后的参考,所以它应该是有意义的。column_1、column_2、& column_3 是您希望为列设置别名的名称。最后,作为,是 SQL 语句的开始,我将其标记为# 普通 SQL 查询作为注释参考。
让我们看看它的实际效果吧!
我们的目标是编写几个可以构建到 CTE 中的查询。我们试图找到以下内容,
2014 年 IMDB 收视率最高的电影,演员的名字以“Matt”开头
我们可以立即看到查询可以分解成几个部分。
- Names = 'Matt '
- 电影和 IMDB 评级
- 2014 年
- 第三高的 IMDB
对于这个例子,我们将创建两个 cte。
第一个查询 Matt 这个名字
我们将首先编写一个没有 CTE 语法的查询来调用整个数据库中名字中包含“Matt”的所有人。我们还想加入 roles 表,以找出该演员所在的确切的 film_id 。
SELECT p.name, r.film_id
FROM people AS p
JOIN roles AS r
ON p.id = r.person_id
WHERE p.name LIKE 'Matt%'
所有“马特”名字的输出和他们出演的电影
现在我们有了一个调用所有 Matt 的查询,我们可以在以后构建 CTE 时使用它。
第二个问题—2014 年电影和 IMDB 评级
我们希望构建下一个查询来查找 2014 年的每部电影,并加入评论表来查找它们的 IMDB 评级。
SELECT f.id, f.title, f.release_year, r.imdb_score
FROM films AS f
JOIN reviews AS r
ON f.id = r.film_id
WHERE f.release_year = 2014
查询输出
现在,我们已经从两个查询中获得了所有必要的信息,可以找到答案,找出由名为“Matt”的演员主演的电影在 IMDB 中的评分最高
建造 CTE
让我们结合前面的两个查询来创建这个 CTE。当我们想在同一个语句中添加第二个 CTE 时,我们添加一个逗号并添加第二个 AS 语句,如下所示。
**WITH**
**MATT_cte**(actor, ***film_id***)
**AS**(
SELECT p.name, r.film_id
FROM people AS p
JOIN roles AS r
ON p.id = r.person_id
WHERE p.name LIKE 'Matt%')**,****IMDB_cte**(***film_id***, movie, release_year, IMDB_Score)
**AS**(
SELECT f.id, f.title, f.release_year, r.imdb_score
FROM films AS f
JOIN reviews AS r
ON f.id = r.film_id
WHERE f.release_year = 2014)
我们的 CTE 已经构建并保存了别名为 MATT_cte 和 IMDB_cte 的两个查询。这些别名将在我们运行最终代码时作为参考。
需要注意的是,如果您计划连接稍后创建的两个 cte,您将需要在两个 cte 中都有一个外键。在这种情况下,我们的外键在两个表中都是 film_id 。
使用 cte
我们都准备使用我们的 cte 并得到我们的答案!让我们加入我们新的临时结果,并找出它是哪部电影。提醒,我们正试图得到以下。CTE 将需要在同一个查询中被引用,所以我们在它下面添加了最后一个查询。
2014 年 IMDB 收视率最高的电影,演员的名字以“Matt”开头
WITH
MATT_cte(actor, film_id)
AS(
SELECT p.name, r.film_id
FROM people AS p
JOIN roles AS r
ON p.id = r.person_id
WHERE p.name LIKE 'Matt%'),IMDB_cte(film_id, movie, release_year, IMDB_Score)
AS(
SELECT f.id, f.title, f.release_year, r.imdb_score
FROM films AS f
JOIN reviews AS r
ON f.id = r.film_id
WHERE f.release_year = 2014)**SELECT *
FROM MATT_cte AS m
JOIN IMDB_cte AS i
ON m.film_id = i.film_id
ORDER BY i.IMDB_Score DESC**
查询输出
我们已经成功地找到了所有包含“马特”的名字,电影名称,IMDB 评分和上映年份。
我们最终的答案是,星际是 2014 年 IMDB 中收视率最高的电影,它有一个名字以“马特”开头的演员。
桌面壁纸由刺客大师
最终结果
我希望您看到 cte 为您的 SQL 查询带来的价值。如果您计划一次又一次地调用同一个查询,最好使用它。例如,如果我们只想要 IMDB 评分高于 8 的电影,我们可以创建一个临时结果来确保 CTE 始终可用。
SQL 中使用的另一个有用的方法是子查询。我计划分享一个关于如何使用子查询的教程,所以一定要跟着我学习更多的课程!
在 Salesforce 组织中使用自定义 JavaScript 模块作为静态资源
上传一次 JavaScript 模块,并在任何 Lightning Web 组件中使用它
本教程将引导您将自定义 JavaScript 模块与 Salesforce Lightning Web 组件集成,并在 Salesforce 组织中使用它们。
Salesforce Developer 101:术语和基本概念
某机构截图(作者:Lynn Zheng)
什么是 Salesforce 组织?
Salesforce 组织是一个面向客户的平台,包含 Salesforce 数据。
什么是闪电网页组件(LWC)?
lightning web 组件本质上是一个 Web 组件,它使用 Salesforce 品牌的样式并封装 Salesforce 数据。
开发环境和工具包
您将需要什么:
- 一个 Trailhead 账户,允许你创建一个 Trailhead 游乐场/测试组织
- Salesforce 开发人员体验(SFDX)命令行客户端
- Visual Studio 代码
如果您尚未设置完整的 Salesforce 开发人员体验(SFDX)环境,请转到 Trailhead,注册并完成快速入门:Lightning Web Components Trail。这将建立我们在本教程中需要的整个工具包,应该不会超过 20 分钟。
如果你是 Visualforce 或 Aura 开发人员,已经建立了 SFDX 但不熟悉 LWC,我建议你完成快速入门的最后一个模块: LWC 小径来创建一个 HelloWorld LWC。
如果您已经熟悉 SFDX 和 LWC,请继续创建一个简单的 HelloWorld LWC。LWC 不需要超过<div>Hello World</div>
的任何东西。
自定义 HelloWorld LWC 位于左侧面板的顶部
无论您来自何方,您最终都会看到一个 org 页面,其中包含一个带有文件helloWorld.html、helloWorld.js、和 helloWorld.js-meta.xml 的定制 LWC。
使用lightning-button
标签向自定义 LWC 添加一个按钮。它的label
属性包含它显示的文本。它的onclick
属性应该指向一个名为clickHandler
的事件处理程序。
在helloWorld.html中,为按钮添加 HTML:
<lightning-button label=”Say Hello in the JS Console” onclick={clickHandler}></lightning-button>
在 helloWorld.js 中,实现clickHandler
方法:
clickHandler() {
console.log('hello from helloWorld.js');
}
打开默认组织页面(在 Visual Studio 代码中,Command + Shift + P,SFDX: Open Default Org),打开 web 控制台,点击按钮,我们应该会看到控制台日志。
如果组织没有自动刷新,点击页面右上角的齿轮图标,进入页面设置,刷新当前页面,保存。
创建静态资源 JavaScript 模块
在force-app/main/default/static resources 下创建两个文件,helloModule.js、和hello module . resource-meta . XML .
要使用自定义 JavaScript 文件作为静态资源,我们需要将它包装在一个立即调用的函数表达式(IIFE)中。
helloModule.js 中的生活:
(function() {
function sayHello() {
console.log('hello from helloModule.js');
}
// this makes the sayHello function available in the window namespace
// so we can call window.sayHello from any LWC JS file
window.sayHello = sayHello;
})();
在hello module . resource-meta . XML中,我们指定了资源内容类型和缓存控制属性:
<?xml version="1.0" encoding="UTF-8"?>
<StaticResource ae na" href="http://soap.sforce.com/2006/04/metadata" rel="noopener ugc nofollow" target="_blank">http://soap.sforce.com/2006/04/metadata" fqn="helloWorld">
<cacheControl>Private</cacheControl>
<contentType>application/javascript</contentType>
</StaticResource>
将force-app/main/default/static resources部署到 org。在组织页面上,转到设置并搜索静态资源。应该有一个名为 helloModule 的资源,类型 application/javascript,私有缓存控制。
在 LWC 中使用静态资源
在 helloWorld.js 中,添加静态资源和加载静态资源的方法的导入:
import SAY_HELLO from '[@salesforce/resourceUrl](http://twitter.com/salesforce/resourceUrl)/helloModule';
import { loadScript } from 'lightning/platformResourceLoader';
然后实现一个在页面上呈现 LWC 时运行的回调:
renderedCallback() {
loadScript(this, SAY_HELLO)
.then(() => console.log('Loaded sayHello'))
.catch(error => console.log(error));
}
将此 LWC 部署到组织。刷新 org 页面,我们应该会看到控制台日志,表明已经成功加载了 helloModule 静态资源。
既然资源已经成功加载,我们就能够在 LWC 中使用函数sayHello
。在 helloWorld.js 中,更新按钮点击处理程序调用window.sayHello
:
clickHandler() {
console.log('hello from helloWorld.js');
window.sayHello();
}
部署到 org,刷新,点击按钮,我们应该看到来自 helloModule 的日志打印到控制台。
奖励:创建一个静态资源 JavaScript 模块,调用第三方 API
由于 Salesforce org 的默认安全设置,如果我们的 JavaScript 函数需要调用非 Salesforce 的第三方 API,我们需要将这些站点列为 CSP(内容共享策略)可信站点。我们将以 JSONPlaceholder 为例。转到设置并搜索 CSP 可信站点。添加新的可信站点,如下所示:(注意,Salesforce 不接受以正斜杠结尾的 URL,即https://mysite.com
有效,但https://mysite.com/
无效。)
CSP 可能需要两到五分钟才能生效。同时,向 helloModule.js 添加一个函数(仍在 IFFE 中),并将其公开给 window 名称空间:
function retrieveData(dataId) {
fetch('[https://jsonplaceholder.typicode.com/todos/'](https://jsonplaceholder.typicode.com/todos/') + dataId)
.then(response => response.json())
.then(json => console.log(json));
}
window.retrieveData = retrieveData;
更新 helloWorld.js 中的clickHandler
以使用带参数的window.retrieveData
:
clickHandler() {
console.log('hello from helloWorld.js');
window.sayHello();
for (let i = 1; i < 4; i++) {
window.retrieveData(i);
}
}
部署、刷新,如果没有 CSP 错误(这意味着 CSP 尚未生效),我们应该能够在控制台日志中看到一些从第三方 API 获取的 JSON 数据。
完整的文件如下:
helloWorld.html:
<template>
<lightning-card title="HelloWorld" icon-name="custom:custom14">
<div class="slds-m-around_medium">
<p>Hello, {greeting}!</p>
<lightning-input label="Name" value={greeting} onchange={changeHandler}></lightning-input>
<lightning-button label="Say Hello in the JS Console" onclick={clickHandler}></lightning-button>
</div>
</lightning-card>
</template>
helloWorld.js:
import { LightningElement } from 'lwc';
import SAY_HELLO from '[@salesforce/resourceUrl](http://twitter.com/salesforce/resourceUrl)/helloModule';
import { loadScript } from 'lightning/platformResourceLoader';export default class HelloWorld extends LightningElement {
greeting = 'World';
changeHandler(event) {
this.greeting = event.target.value;
}
clickHandler() {
console.log('hello from helloWorld.js');
window.sayHello();
for (let i = 1; i < 4; i++) {
window.retrieveData(i);
}
}
renderedCallback() {
loadScript(this, SAY_HELLO)
.then(() => console.log('Loaded sayHello'))
.catch(error => console.log(error));
}
}
helloModule.js:
(function() {
function sayHello() {
console.log('hello from helloModule.js');
}
function retrieveData(dataId) {
fetch('[https://jsonplaceholder.typicode.com/todos/'](https://jsonplaceholder.typicode.com/todos/') + dataId)
.then(response => response.json())
.then(json => console.log(json));
}
// this makes the sayHello function available in the window namespace
// so we can call window.sayHello from any LWC JS file
window.sayHello = sayHello;
window.retrieveData = retrieveData;
})();
更多资源,请查看 Trailhead 和 Salesforce 面向开发者的官方文档。
在家工作时使用计算机视觉和机器学习来监控活动
介绍在嵌入式系统上构建基于视觉的健康监测软件
世界上大多数人在这种封锁期间呆在家里面临的最大挑战之一是身体活动的突然限制,尤其是当被限制在一个小空间内时。为了帮助解决这个问题,我想看看我是否可以使用计算机视觉来帮助激励自己更加积极,这将是一件有趣的事情。
在这篇文章中,我将分享我的方法,以及一个完整的示例源代码,它展示了帮助监控和改善许多呆在家里的人的生活质量的潜力。这个想法是拥有一个低成本、支持 GPU 的基于视觉的系统(99 美元 NVIDIA Jetson Nano ),该系统可以在 edge 上执行大多数计算机视觉处理(例如,人脸检测、情感分类、人物检测和姿势估计)一体化易于安装的软件包。然后,该系统可以处理从本地收集到远程云的数据,以便进行后处理,并重新分发到为一个或多个健康状况提供仪表板的服务器。
为了解决隐私问题,我讨论了通过仅上传经过后处理的数据来保护用户隐私的方法,这些数据包含分类的情感数据、面部特征和身体姿势数据,而不是实际的相机馈送。虽然您还可以做更多的事情来隐藏数据,但是这个例子将为您指出正确的方向。
这个概念验证是一个简单的应用程序,它根据我的身体姿势和情绪显示我的活动仪表板。整个系统运行在 99 美元的 NVIDIA Jetson Nano 开发板和大约 40 美元的网络摄像头上。这种设置有助于人们在跟踪活动的同时专注于工作。
开启隐私模式的最终结果,因此仅显示已处理的数据。
让我们来看看如何构建和我一样的系统。
设置网络摄像机服务器
我采取的第一个设置是建立一个网络摄像头服务器,这样我就可以根据需要向系统添加尽可能多的摄像头,并且还可以以分布式和可扩展的方式处理这些帧。
在 Linux 中,我们可以通过一个名为“ Motion ”的程序轻松设置自动网络摄像头流。该计划允许您创建一个智能安全摄像机,检测运动,更重要的是作为服务器传输运动 JPEG (MJPEG)。这个特性非常有用,它允许我们异步运行这些应用程序,而不会使任何特定机器上的每个相机流陷入困境。
要在 NVIDIA Jetson Nano 上安装 motion,只需使用以下命令行。
sudo apt-get install motion
然后,我们编辑运动配置文件来设置分辨率和帧率。默认情况下,motion 应用程序被配置为检测运动和捕捉帧,这不是我们在用例中想要的。
nano /etc/motion/motion.conf
这里,您需要将摄像机馈送(帧速率)和流馈送( stream_maxrate )的分辨率和帧速率更改为 640 x 320 和 15 fps。
如果你有一个更强大的机器,如 Jetson Xavier ,你可以设置更高的分辨率和帧速率,以便更好地跟踪远距离物体。
然后,我们关闭自动快照和视频捕捉功能(即,将输出 _ 图片设置为关闭)。这一点很重要,否则你的硬盘会很快被新捕获的内容填满。
配置 Motion 后,您需要允许它在启动时作为服务运行。
nano /etc/defaultmotion
您将这一行编辑为
start_motion_daemon=yes
现在你需要编辑位于/etc/Motion/Motion . conf的主配置文件,并将 Motion 守护进程设置为 on。重启电脑后,Motion 现在应该会自动运行。
以下命令控制 Motion 服务:
- 启动 Motion 服务:
sudo service motion start
- 停止运动服务:
sudo service motion stop
- 重新启动 Motion 服务:
sudo service motion restart
要预览订阅源,只需打开浏览器并转到以下链接:
[http://localhost:8080](http://localhost:8080)
此时,您将能够看到摄像机馈送的预览。现在是我们真正使用它的时候了。
用于姿态估计的机器学习工具
该系统的主要目标之一是更好地了解一个人在家的活动。为了做到这一点,我们将创建一个姿势估计程序,跟踪一个人的姿势。更重要的是,姿势估计允许你通过省略你的相机的馈送来创建一个隐私层,并且只显示处理过的数据。
首先,您需要安装 Tensorflow 和 OpenPose 库。GitHub 成员 karaage0703 在为 NVIDIA Jetson Nano 整合安装脚本方面做了一项令人惊叹的工作。在这里你可以按照 GitHub 的说明来设置工具,下面是 Github 库的链接。
github clone [https://github.com/karaage0703/jetson-nano-tools](https://github.com/karaage0703/jetson-nano-tools)
特别是,您想要运行‘install-tensorflow . sh’和‘install-Pose-Estimation . sh’脚本来在您的机器上安装 tensor flow 和 Pose Estimation 库。
$ cd ~/jetson-nano-tools
$ ./install-tensorflow.sh
$ ./install-pose-estimation.sh
这个过程可能需要 30 分钟,所以在执行完命令后休息一下,做做伸展运动。一旦您有了合适的工具,让我们看看我写的 Python 脚本,它允许您捕获、处理和可视化数据。
姿态估计
我创建了一个 Python 脚本,它使用了刚刚安装的工具集,这是骨架覆盖在摄像机镜头上的结果。
在 NVIDIA Jetson Nano 上运行的 OpenPose 库的输出示例
你可以在这里查看我写的脚本:
git clone [https://github.com/raymondlo84/nvidia-jetson-ai-monitor](https://github.com/raymondlo84/nvidia-jetson-ai-monitor)
‘run _ web cam _ IP . py’脚本有两个基于 CMU 感知计算实验室 OpenPose 项目的关键功能。
OpenPose 代表了第一个在单幅图像上联合检测人体、手、面部和脚关键点(总共 135 个关键点)的实时多人系统
这个库是一个非常强大的工具,它可以通过 GPU 加速检测完整的人体骨骼。有了这些,现在想象你如何跟踪人体姿势,为你提供适当的反馈。例如,您可以创建一个颈部角度检测器,并在工作期间帮助固定您的身体姿势。
from tf_pose.estimator import TfPoseEstimator
from tf_pose.networks import get_graph_path, model_wh
脚本的主循环对 IP 摄像机捕获的每一帧进行推断。然后,这两行将执行推理并在框架上绘制结果
humans = e.inference(image, resize_to_default=(w > 0 and h > 0), upsample_size=args.resize_out_ratio)image = TfPoseEstimator.draw_humans(image, humans, imgcopy=False)
NVIDIA Jetson 的 GPU 可以在 320 x 160 分辨率下,使用 mobilenet_thin 模型,以大约 7–8 fps 的速度执行姿态估计。对于一台满负荷使用不超过 10W 功率的机器来说,这是非常令人印象深刻的。随着身体姿态的估计,现在可以预测一个人有多活跃。这类似于一个 FitBit,但我们使用的不是加速度计或陀螺仪,而是来自摄像机的视频信号。
在 NVIDIA Jetson Nano 上运行 OpenPose
人脸检测和情感分析
此时,我们计划要做的一切都已经实现了,但是为什么不利用捕获的视频做更多的事情呢?让我们看看如何从面部反应中检测情绪,以便用 GPU 构建一个快乐的仪表。要做到这一点,我们需要添加代码来决定一个人的面部和情绪。令人惊讶的是,这两个系统都在 GPU 上利用 Tensorflow,因此我们不需要分配大量的内存,只需要最少的开销。同样,还有额外的优化,如智能地选择基于身体姿态的人脸检测的边界框,以获得额外的速度。
目前,处理速度约为每秒 7 帧,面部检测和情感分析的分辨率为 320x160 。然而,使用分布式设置,我可以通过将工作卸载到 GPU 集群设置中的另一个节点上,轻松地将速率提高一倍或两倍。即使每秒更新 3 次,系统每天也将有大约 259,200 个样本。这不是一个微不足道的数据量。
为了执行情感分析,这次我将包括 Keras 库和人脸识别包。
import face_recognition
import keras
from keras.models import load_model
from keras.preprocessing.image import img_to_array
然后,这条线从图像中提取检测到的面部的位置。
face_locations = face_recognition.face_locations(small_image, model=’cnn’)
参数 mode='cnn' 使我们能够使用 CUDA GPU 加速代码,并在不同视角或遮挡情况下提供更好的准确性。
一旦它从图像中检测到人脸,人脸图像就会根据我们预先训练的模型(_ mini _ xception . 106–0.65 . HD F5)运行预测函数,并将人脸分为七类:愤怒、厌恶、害怕、快乐、悲伤、惊讶或中性。
emotion_dict = [“Angry”, “Disgust”, “Scared”, “Happy”, “Sad”, “Surprised”, “Neutral”]model = load_model(“emotion_detector_models/_mini_XCEPTION.106–0.65.hdf5”, compile=False)model_result = model.predict(face_image)
基本上,实际工作大约是 5 行代码,我还提供了额外的示例代码(web cam _ face _ detect . py)来单独运行这一部分进行您自己的测试。
在 GPU 上运行姿势估计、人脸检测和情感分析。
CPU/GPU 性能
从我的实验中得到的一个重要收获是,这些 CV+ML 算法可以与 GPU 设置很好地堆叠在一起。默认情况下,Tensorflow 的核心占用了大量内存,因此无论如何最好地利用资源是明智的。现在,随着 CPU 完全从处理中释放出来,我们有超过 300% 的 CPU 处理资源可用于许多其他任务,例如对已处理数据进行记账。
请注意,即使同时运行所有算法,我们的 CPU 使用率也非常低。
最后的想法
这里我们有一个低成本的监控系统,可以监控身体姿势,进行面部检测,并返回基本的情绪分析。这三个特性代表了一个全新的基于视觉的健康仪表板的基础,全部基于 GPU。最棒的是,这可以用一台 99 美元的机器来建造。想象一下可能性!
启用隐私模式
通过姿势估计、面部检测和情绪分析,我可以提取运动参数,如每天的平均运动,并跟踪我自己的情绪数据,而无需将我的图像与云共享。这个数据并不完美,但这种反馈可以被证明对改善长时间坐在电脑前的姿势非常有用(例如,颈部问题)。此外,通过一些小的修改,这可以很快变成一个睡眠监视器,并有其他潜在的健身用途可以扩展。
关于我
目前,我住在硅谷,并在英特尔担任 OpenVINO Edge 人工智能软件布道者。此前,我是 Meta 的联合创始人兼首席技术官,在那里我发布了两套增强现实开发工具包。作为 Meta 公司研发部门的负责人,我曾与数百名出色的工程师一起工作,创造出最先进的技术和 CV 算法,如 SLAM、3D 手部跟踪和 AR/XR 的新 UX。在我的博士研究期间,我还发表和开发了关于 HDR 视频处理的实时 GPGPU 应用程序,并用 3D 深度感应相机创建了增强现实原型。我始终相信,技术的可及性和简单性是创造颠覆性变革所必需的。现在,我看到人工智能边缘计算的快速增长可以以非常低廉的成本带来许多智能应用。而这篇帖子只是这种不断增长的趋势的开始。
使用 Dash 引导心脏病预测模型
如何设计你的用户界面并在 Dash 中运行
图片由 WrightStudio 从 Adobe Stock 获得许可。
背景
在之前的一篇文章中,预测心脏病的模型是使用 PyCaret 开发的。现在,假设我们希望在临床环境中试验这个模型。我们首先需要的是模型的 UI,这样它就可以被部署了。我们还将假设该工具用于筛选以推荐后续行动,而非诊断。
在此示例中,为了便于说明,我们将重点关注以下内容:
- 确定最低关键要求以及如何满足这些要求。
- 勾画出一个包含关键需求的用户界面。
- 使用 Dash 创建工作版本。
该应用程序是使用 PyCharm 开发的,所有资料都可以在我的 GitHub 上找到。
免责声明:在现实环境中,当部署一种新的预测模型来预防、诊断或治疗健康状况时,需要考虑许多因素,包括已证明的影响、伦理和算法偏差以及法律要求(即 SaMD ,患者隐私)。虽然这些考虑非常重要,但它们超出了本文的范围。
要求
与临床同事合作,假设确定了以下要求:
- 用于输入预测模型中用作特征的患者特征的位置。
- 患者的输出风险评分,也将他们分配到风险组。
- 协助卫生保健从业者理解/传达哪些风险因素导致了患者的风险。为此,我们将使用 SHAP 值。
- 根据患者所属的风险群体,推荐下一步行动。
- 有关用于生成预测风险分值的模型是如何开发的及其性能的信息。我们也可以包括一些关于队列和重要风险因素的一般信息。
用户界面
基于上述要求,由以下部分组成的简单结构是一个合理的起点:
- 数据输入(要求 1)
- 预测模型输出/解释/建议的下一步行动(要求 2、3 和 4)
- 模型开发信息(要求 5)
我们 Dash 应用的大致布局如图图 1 所示。
图一。使用 Dash 粗略勾画出我们想要创建的东西的轮廓。请原谅我的笔迹!(图片由作者提供)
Dash 应用程序
根据上述要求和草图,第一个工作应用如图图 2 所示。请注意,这些截图是在宽屏(24 英寸,16:9,1920 x 1080)上观看的。在较小或不宽的屏幕上,对齐可能会关闭。我强烈推荐克隆 GitHub repo 并亲自探索 UI!
图二。主视图!(图片由作者提供)
数据输入
在应用程序主视图的左侧,我们为用户提供了适当的机制来输入所需的信息,从而为预测模型生成特征(图 3 )。在可能的情况下使用下拉菜单(所有分类特征),否则可以直接为数字特征输入值。
图 3。主视图左侧面板,包含预测模型的数据输入。(图片由作者提供)
通常,数据预处理管道将嵌入到应用程序中,以处理插补或缩放等步骤。在这种情况下,由于最少的预处理,而且除了一种情况之外,所有输入的数据都是特征值,所以我选择保持简单。
预测模型输出/建议行动
应用程序的右侧根据我们的预测模型总结了所需的输出(图 4 )。首先,我们得到一个预测的风险评分,用于将患者归入三个风险组之一。
图 4。预测风险总结和建议措施。(图片由作者提供)
接下来,SHAP 值和瀑布图用于传达哪些患者因素对风险贡献最大。这个想法是,它将帮助用户看到模型认为哪些因素导致心脏病风险,如果可以修改,可以针对生活方式进行干预。当然,这伴随着通常的联想,而不是因果关系。shap 包瀑布图(Scott Lundberg )不容易整合到 dash 应用程序中,所以我使用 plotly 瀑布图创建了自己的副本。
最后,有一个(虚构的)行动建议,基于病人属于三个风险组中的哪一个。这个想法是提示一系列明智的后续步骤,无论是生活方式的改变,进一步的测试,还是后续的预约。这也可以用作参考已批准的预防/治疗医学疾病的指南的地方,或者作为转介到适当服务(即,参考营养咨询)的起点。应与临床同事合作制定风险分组和相应的措施。
模型数据
在本节中,我们添加了关于所用数据、所选模型、培训/调整流程、绩效指标、描述性比较心脏病患者和非心脏病患者的研究队列表以及基于 SHAP 的特征重要性的信息(图 5 )。
图五。屏幕底部的可扩展面板显示了模型开发的基本信息。(图片由作者提供)
我们还可以考虑包括整个研究群组的平均特征、外部验证程序或其他研究(如果适用)、支持该工具的已发表工作的参考文献、突出任何特征交互等。
改进的潜力
一如既往,任何试点用户界面都有改进的潜力,例如:
- 简化数据输入:我们本可以减少需要输入的信息,因为一些特征对预测风险没有影响。我保留了所有东西,这样其他使用相同数据集开发自己模型的人就可以简单地交换模型。pkl 文件,并按原样使用仪表板。
- 自动数据输入:我们可以使用文件上传或直接数据库连接来代替手动数据输入。但是我们所拥有的对于这个例子来说已经足够了,并且作为一个试验的一部分,不会有太多的负担。
- 模型校准:使用预测风险评分等级有助于推荐后续行动,如本例所示。如果我们向患者报告心脏病的可能性,我们的预测概率必须经过很好的校准(即,与心脏病发生的实际机会一致)。
你还会做出哪些改进,或者你会有哪些不同的做法?
摘要
我们为飞行员准备好了仪表盘。使用 Dash 更接近于部署范围的定制端。这可以通过 PowerBI 或 Qlik 等其他工具部署,作为可能的中端选项。我们也可以采用低端方法,使用例如 FastAPI 创建一个 API。在以后的文章中,我将尝试使用这些 UI 选项重新创建 Dash 应用程序。
感谢您的阅读,我希望您花些时间从这个例子中探索 Dash UI。一如既往,非常欢迎评论、想法、反馈和讨论!
利用数据科学和先进技术抗击流行病
数字生物学
抗击流行病需要生物技术、人工智能等等。我们准备好了吗?因为现在已经不是 1918 年了。
iStock 插图
黛安·迪厄利斯、彼得·伊曼纽尔、詹姆斯·佐丹奴和亚历山大·泰特斯
在军队中听到的一个常见表达是,“我们总是在打最后一场战争。”面对全球对新冠肺炎危机的反应,“最后一场战争”是 1918 年的疫情流感。
尽管历史提供了宝贵的教训,但根据当前的环境、能力和复杂性重新审视过去的问题和解决方案是至关重要的。新冠肺炎疫情造成了一个既要确保公共安全和健康,同时又要努力稳定和维持经济的两难境地。
与此同时,显而易见有益的可用先进技术并没有被充分利用来最大限度地利用道德上合理、有效和高效的方法来减少疫情对我们社会和经济的影响。如果说有什么时候可以使用这些工具,那就是现在。
疾病监测数据平台需要现代化
测试提供了对疾病特征和模式的理解——如发病率、流行率、恢复和人口统计学——并且应该更早开始。检测病毒感染和暴露的技术已经成熟,但它们缺乏协调,也没有与私营部门的扩大途径联系起来。基因组测试可以揭示谁风险最大,谁可能恢复的数据。因此,关键数据缺失,而这些数据是为决策提供信息所必需的,包括物理距离的范围、对社会经济振兴的影响以及美国国防力量的准备情况。
像新冠肺炎这样的传染病的早期识别需要全球分布的一系列硬件和软件,放置在足够多的位置,以创建一个链接收集站点的网络。这需要通过战略联盟和公私伙伴关系以及国际竞争者的合作企业来发展生物监测系统。这种能力和合作目前还不存在——无论是美国联邦政府还是我们的许多全球合作伙伴。与全球竞争对手的合作监控机制,尽管公认困难重重,但目前仍很紧张,因此也很脆弱。当然,实现这种“合作竞争”需要谨慎和相当的技巧,而这需要更加信任情报和外交服务。
应该定期使用计算工具
应该采用人工智能、机器学习和数字健康方法来模拟病毒的潜在传播,以及识别、设计和开发测试和治疗(如果不是预防的话)干预措施。在最令人担忧的病原体成为流行病的情况下,人工智能和数字卫生不属于准备协议的一部分。如果疫情开始,这种准备将是“超前的”——而不是在快速演变的危机中不得不“启动”疫情反应的这种努力。
当然,任何支持和提供个人实时医疗数据的方法都会在民用和军用环境中产生伦理、法律和社会问题。需要制定法律措施,以防止或减轻治疗和关注方面的潜在偏见,并减少数据黑客行为的风险和可能的影响。
供应链也需要技术现代化。新冠肺炎效应对全球贸易的影响向我们展示了美国供应链的脆弱性及其对外依存度,并揭示了对更灵活、更便捷的供应链的需求。这需要对进口进行严格检查,探索创新的制造技术,并防范来自国外的单点故障。
私营部门的许多公司已经证明,在上述计算工具的帮助下,他们可以快速灵活地将生物技术平台导向诊断和医学分子的生产和规模化。这些努力应该更有规律地加强传统供应链。
现在不是 1918 年,也不一定要再来一次
新冠肺炎危机应该从字面意义上来理解——一个变革的时代。我们可以从 1918 年的疫情中学到一些适用于当下的经验。正如 1918 年的疫情威胁、促使医疗反应系统做出反应并改变了医疗反应系统一样,今天的政府、民间和商业部门的基础设施和职能也必须如此。
当前新兴的生物技术可以——也应该——参与开发先进的诊断测试和工具,创建更准确的流行病学模型,创新医疗对策和制造平台,并以数字方式让美国公民参与应对。无论威胁是自然的还是人为的,这种方法必须在一个网络化的生物安保企业中使用,这个企业需要一个全国性的系统,以便能够作出更加有效和高效的反应。这样一个系统将能够更好地预测、准备(如果不能防止的话)下一次生物安保问题,而不仅仅是重复上一次的错误。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
Diane DiEuliis 是国防大学大规模杀伤性武器研究中心的高级研究员。彼得·伊曼纽尔是陆军未来司令部化学生物中心的高级生物工程研究科学家。James Giordano 是乔治敦大学医学中心神经病学和生物化学系的教授,也是海军战争学院生物安全、技术和伦理项目的高级研究员。亚历山大·提塔斯是高级再生制造研究所的首席战略官。本文中表达的观点仅是作者的观点,并不反映国防部或美国政府的官方政策或立场。
这篇关于 对抗流行病的技术 最初出现在国防上。
使用数据科学和人种学建立一个显示率预测器
图片来自 DarkoStojanovic
我最近为一个(匿名)医院系统开发了一个显示率预测器,为此我必须整合人种学和数据科学方法。许多读者要求这种集成的真实世界的例子,这个项目展示了人种学和数据科学如何能够结合起来,开发出对用户有意义并满足他们需求的有用的基于机器学习的软件。
第 1 部分:确定项目范围
医院系统中的一个特定诊所遇到了大量的预约失约,这给患者和员工都带来了时间浪费、挫败感和困惑。我被要求使用数据科学和机器学习来更好地理解和改善他们的调度。
我通过对诊所进行人种学研究开始了这个项目,以了解更多关于排班是如何正常发生的,它对诊所有什么影响,以及员工看到了什么样的驱动问题。特别是,我观察并采访了排班助理,以了解他们的日常工作和他们对失约的看法。
我从这一切中学到的一个主要教训是,在安排预约时,安排者不断地试图确定在给定的医生轮班中安排多少人,以确保出现正确的人数。例如,说 12-14 个病人是 Rodriguez 医生(虚构的名字)周三早班的一个好病人数。当决定是否在即将到来的周三为给定的患者安排与 Rodriguez 医生的预约时,预约助理试图确定,根据当前安排的预约,他们是否可以预期 12-14 名患者出现。这通常是一门不精确的科学。他们经常需要在一个特定的医生轮班中安排 20-25 名患者,以确保他们理想的 12-14 名患者那天真的会来。然而,这可能会造成混乱,有些日子来的病人太多,而有些日子来的病人太少。
图片来自杰拉德
这个问题——在给定的医生轮班中,我们可以期望或预测发生多少次预约——成为我用机器学习来回答的驱动问题。在与诊所的各种利益相关者核对以确保这确实是一个用机器学习来回答的重要而有用的问题之后,我开始构建。
第 2 部分:构建模型
既然我有了一个有驱动力的、可回答的问题,我决定把它分成两个连续的机器学习模型:
- 第一个模型学习预测给定约会发生的概率,从发生或未出现约会的历史中学习。
- 第二个模型使用第一个模型中的预约概率,估计每个医生轮班时可能发生的预约次数。
第一个模型结合了三个数据流来评估失约的概率:约会数据(例如多长时间前被安排,约会类型等。);患者信息,尤其是过去的预约历史;和医生信息。我进行了广泛的特征选择,以确定要使用的最佳变量子集,并在确定梯度提升之前测试了几种类型的机器学习模型。
第二个模型使用第一个模型中的概率作为输入数据来预测每个医生轮班时会有多少病人。我选定了这个模型的神经网络。
第 3 部分:构建应用程序
接下来,我与团队中的软件工程师一起开发了一个应用程序,以实时利用这些模型,并在调度人员安排约会时将信息传达给他们。我的人种学研究对于开发如何构建这个应用程序非常有价值。
在后端,应用程序计算所有未来约会发生的概率,并根据新安排或编辑的约会的新计算结果进行更新。每周一次,它将合并该周的新约会数据,并将出席率转换为每个模型的训练数据,并相应地更新这些模型。
通过我的人种学研究,我观察了日程安排者是如何安排约会的,包括他们在这个过程中使用了什么软件,以及他们如何使用每个软件。我用它来决定传达信息的最佳方式,定期向调度人员展示我的想法,以确保我的策略会有所帮助。
图片来自 Pixabay
我构建了一个界面来交流信息,以补充他们当前使用的软件。除了显示预计到达的患者数量,如果机器学习算法预测某个特定班次预订不足,它会在日历界面上用绿色标记该班次;黄色表示该班次预计有理想的患者人数,红色表示已经预计有过多的患者。颜色编码使信息在那一刻变得容易可视化:当试图为病人寻找预约时间时,如果有必要,他们可以很容易地找到绿色或黄色,但要避开红色。当放大一个特定的班次时,每个约会都将根据发生的概率进行颜色编码(可能、不太可能和中间)。
结论
这是整合数据科学和人种学来构建机器学习应用程序的项目的一个例子。我用人种学来构建应用的参数和框架。它将应用程序与调度程序的需求联系在一起,确保我开发的机器学习模型对那些会使用它的人有用。在他们发展的每一步之前的频繁检查也有助于确认我提出的概念实际上有助于满足他们的需求。
我的数据科学和机器学习专业知识也帮助指导了我的人种学过程。作为机器学习如何工作以及它可以回答什么样的问题的专家,我可以很容易地将我从人种学调查中获得的见解综合到可构建的机器学习模型中。我了解机器学习能够(和不能够)做什么,并且我可以直观地开发战略方法来利用机器学习解决他们遇到的问题。
因此,我作为人种学和数据科学家的双重角色使这个项目受益匪浅。我的人种学倾听技能使我能够发现调度人员面临的潜在问题,我的数据科学专业知识使我能够开发可行的机器学习解决方案。如果没有耐心地聆听大量的民族志,我就不会充分理解这个问题,但是如果没有我的数据科学专业知识,我就无法破译机器学习可以实际解决哪些问题以及如何解决。
这说明了为什么数据科学和人种学的联合专业知识在开发机器学习软件中是无价的。两个不同的个人或团队可以分别完成每个任务——一名人种学家分析用户的需求,一名数据科学家然后确定机器学习建模是否有帮助。但这似乎是不必要的脱节,可能会产生误解、困惑和混乱。通过增加额外的人员层,很容易导致人种学家发现基于机器学习的解决方案需要帮助的需求过于广泛或复杂,或者数据科学家试图将他们的机器学习“解决方案”强加给用户没有的问题。
发展这两方面的专业知识可以更容易地同时理解特定环境中的问题,并构建可行的数据科学解决方案。
你可以在这里找到原始出版物:【https://ethno-data.com/show-rate-predictor/】T2。有关该网站和其他文章的更多信息,请访问https://ethno-data.com/。
也感谢《数据科学》杂志发表这篇文章。更多关于他们工作的细节,请看。
利用数据科学获取客户
客户细分报告和客户反应预测
为了给自己的品牌带来新客户,公司一直在开发他们的客户获取流程和策略。尽管这并不容易!任何基本客户获取计划的第一步都是识别优质潜在客户,猜猜看!数据科学可以帮助我们做到这一点!这个项目是关于可以用来理解顾客的特点,并可能获得他们的策略。
该项目应用机器学习算法,以便从人口统计数据中获取潜在客户的信息。这是由贝塔斯曼子公司 Arvato Financial Solutions 提供的 Udacity 机器学习工程师纳米学位项目的顶点项目。我选择这个项目主要是因为提供的数据是真实的,而且几乎没有对其进行清理。除此之外,我真的很喜欢了解业务和客户的需求,以便为公司和那些使用商业产品或服务的人提供最佳体验。
项目的第一部分包括基于 Arvato Financial Solutions 的现有客户和德国普通人群构建客户细分报告。为此,我使用无监督学习技术来识别最能描述公司核心客户群的人群。
第二部分包括建立客户营销活动响应预测器,以识别最有可能转化为客户的个人。为了做到这一点,我尝试了一些监督学习算法,并最终找到了给我最好 ROC AUC 分数的算法。
你可以在我的Github页面查看我开发的所有代码。
数据:
如上所述,该项目的数据由德国贝塔斯曼的子公司 Arvato Financial Solutions 提供。有六个数据文件与本项目相关,如下所示:
第一部分)客户细分
- uda city _ AZDIAS _ 052018 . CSV:德国普通人口的人口统计数据
- uda city _ CUSTOMERS _ 052018 . CSV:邮购公司客户的人口统计数据
- DIAS 信息级别—属性 2017.xlsx :属性和描述的顶级列表,按信息类别组织
- DIAS 属性-值 2017.xlsx : 每个变量的数据值按字母顺序排列
第二部分)营销活动响应预测
- uda city _ maillout _ 052018 _ train . CSV:作为营销活动目标的个人的人口统计数据
- uda city _ maillout _ 052018 _ test . CSV:作为营销活动目标的个人的人口统计数据
注意:已将 DIAS 信息级别 和DIAS Attributes xlsx 文件 翻译为 data_info.csv 文件,该文件包含关于特征及其各自可能值的信息。
数据预处理:
为了给机器学习算法提供输入,必须执行几个干净的预处理步骤。特别是,所提供的数据需要经过 8 个步骤的预处理和特征工程。您知道 80-20 法则吗?嗯,许多人说数据科学项目大约 80%的时间花在数据准备(预处理)上,20%花在数据分析和机器学习方法上。这正是在这个特殊的项目中发生的事情。我建立了一个函数,可以完成所有必需的过程,如下所示:
第 1 步-删除功能
由于缺失值的数量,清理功能会删除 35 个特征(列)。这些列包含超过 40%的 nan 数据。信息的缺乏可能会对模型产生负面影响,正因为如此,我决定摆脱它们。除此之外,对于客户数据集 I,该函数还删除了三个额外的列(“CUSTOMER _ GROUP”,“ONLINE_PURCHASE”,“PRODUCT _ GROUP”)。
每个要素的缺失值百分比分布
第 2 步-转换丢失的代码
我创建了 data_info.csv 文件,该文件汇总了来自 DIAS 信息级别-Attributes 2017 . xlsx和DIAS Attributes-Values 2017 . xlsx 文件的信息。除此之外,我还包括了每个特征的缺失值代码,这样我就可以识别每个特征的所有缺失值,然后转换为 NAN。
这就是 data_indo 数据框架的样子:
编码前每个要素的缺失值总数(仅显示 50 个要素)
编码后每个要素的缺失值总数(仅显示 50 个要素)
第 3 步-删除行和数据插补
为了分析每行缺失值的数量,我将数据帧分成不同的集合。第一个具有大量缺失值(超过 250 个),其他的缺失值少于 250 个。通过这样做,我可以调查一些特征的分布,并比较两个数据框架。我意识到(许多特性的)分布是不同的,因此我决定继续处理丢失值较少的数据框,并删除所有超过 250 个 nan 变量的行。
第 4 部分—数据插补
尽管大多数特征要么是分类的,要么是顺序的,但我假设所有变量都是分类的。知道这一点后,我用特性中最常见的值替换了所有缺失的值(nan 变量),以补偿数据集中缺失的值。
第 5 部分—特征工程
用于构建客户细分的无监督学习算法需要数值。因此,所有的数据都必须用数字编码,这样模型才能按照预期的方式进行。
在分析了所有这些特性后,我决定如下操作:
- 奥斯特 _ 韦斯特 _KZ —将被重新编码为 0 和 1 二进制特征
- LNR——这似乎是一个索引,所以我们可以摆脱它
- CAMEO_DEU_2015 —此功能有许多带有“XX”类别的行(347 行)。我认为这些输入是丢失的值,用一个数字值替换它们,并应用一个热编码来重新编码变量。
- CAMEO_DEUG_2015 —该功能也有许多“X”输入。我做了和上面一样的功能
- CAMEO_INTL_2015 —同上述特征
- D19 _ letz ter _ KAUF _ branch e—该特征有 36 个类别(字符串),需要重新编码。
- EINGEFUEGT_AM —这是一个日期格式功能,需要重新编码(年和月列)
为了避免稀疏性问题,我将一个热编码限制为 44 和 33 个最频繁的特征标签。换句话说,我只为 44 个和 33 个最常见的特性类别中的每一个建立了一个二元变量,并将其余的视为噪声。我将设置变量的前 44 类 CAMEO_DEU_2015 和 CAMEO_INTL_2015 和 D19_LETZTER_KAUF_BRANCHE 的前 33 类。
我使用了前 44 和前 33 个最常见的类别,因为这样我可以保证 azdias 数据图的所有顶部组件都等于客户数据图的顶部组件。
主成分分析
由于我们有一个大型数据集,我们将执行降维。为此,我们需要执行特征缩放,以便主分量向量不会受到每个变量的缩放差异的影响。这种方法在处理基于距离的算法时非常重要,这就是我们的情况。
我使用了标准标度,将每个特征表示为 0,标准偏差等于 1。
缩放数据框后,我们可以应用降维。为了做到这一点,我使用了主成分方法,以便找到数据中最大方差的向量。首先,我使用了 dataframe 的所有功能。通过这样做,我们可以看到可变性的一般趋势。下图显示了每个组成部分解释的差异比率和解释的累积差异。
在查看了上面屏幕图中每个组件解释的差异后,我决定选择 215 个组件,它们占解释的差异的大约 89%。
k 均值聚类
我们可以绘制肘形曲线,以更好地确定要使用的聚类数。该方法获取 k(聚类)的值,并查看每个数据点到聚类中心的平均距离。我们可以注意到,该值随着 k 的增加而减小,我们选择 k 的数值,在该数值处,k 停止以显著的速率减小(肘部)。
我从使用 MiniBatchKMeans 开始,它是 KMeans 算法的变体,使用小批量来减少计算时间。这个算法的结果比标准的 KMeans 稍差,正因为如此,在确定了聚类数之后,我使用了常规的算法。
上面的肘形曲线显示了前 9 个集群的分数迅速降低。即使它在几个点上增加,在群集 11 之后,减少变得越来越不明显。正因为如此,我决定选择 11 作为聚类数。
比较普通人群和客户群
在将 PCA 和聚类模型构建到一般人群数据上之后,我们可以将相同的过程应用到客户数据上,并比较聚类分布。这个想法是为了找出公司最强大的客户群在哪里。换句话说,我们必须找出哪些分组代表过多或代表不足。那有什么帮助?好吧,让我们假设 15%的人被分配到一般人群的特定集群,25%的客户也“感觉”接近该集群的质心。这样的话,消费者的比例将会大于总人口的比例。这表明普通人群中的这些人可能是公司的目标受众。
下面的条形图显示了分配到 11 个集群的人员分布。基于前面的假设,我们可以注意到,代表性最强和代表性最弱的集群分别是集群编号 7 和 6。
为了了解这些集群的一些特征,我决定研究一些描述它们的“金融类型”的特征,并绘制它们的分布图。
特点:
- HH_EINKOMMEN_SCORE :估计家庭净收入(较低=较高收入)
- FINANZ_VORSORGER :准备好的个人财务类型(较低=较高财务类型)
- FINANZ_ANLEGER :投资者个人理财类型(较低=较高理财类型)
- FINANZ_HAUSBAUER :房屋所有者的个人金融类型(较低=较高金融类型)
- 金融极简主义者:金融兴趣低的人(低=高金融类型)
- FINANZ_SPARER :存钱者(较低=较高的金融类型)
- LP_STATUS_GROB :社会地位(下层=下层)
- KKK :购买力(低=高购买力)
- 安雷德 _KZ :性别(1 男 2 女)
估计家庭净收入
准备好的个人财务类型
投资者的个人理财类型
房主的个人理财类型
那些经济利益低的人
存钱的人
社会地位
购买力
性别(1 名男性,2 名女性)
解释:
我们可以注意到的第一件事是,在客户群体中,有一个集群代表过多,也有一些集群代表不足。
我们还可以注意到,过表示数量最多的三个集群分别是集群 7 、集群 11 和集群 3 。正因为如此,这表明这些集群更有可能成为公司的目标受众。
另一方面,代表性最不足的三个群组是群组 1 、群组 6 、群组 8
为了更好地了解每个聚类的总体情况,我们必须检查每个特征的分布。在我的例子中,我选择了代表每种金融类型的特征。
- HH_EINKOMMEN_SCORE :估计家庭净收入(较低=较高收入)
- FINANZ_VORSORGER :准备好的个人财务类型(较低=较高财务类型)
- FINANZ_ANLEGER :投资者个人理财类型(较低=较高理财类型)
- FINANZ_HAUSBAUER :房屋所有者的个人金融类型(较低=较高金融类型)
- 金融极简主义者:金融兴趣低的人(较低=较高的金融类型)
- 金融储蓄者(较低=较高的金融类型)
- LP_STATUS_GROB :社会地位(下层=下层)
- KKK :购买力(低=高购买力)
- 安瑞德 _KZ :性别(1 男 2 女)
拥有过度代表客户数据的集群由更有可能的个人组成:
- 收入高
- 做好充分准备
- 成为投资者
- 成为省钱达人
- 购买力一般/很高
- 男性
在代表性不足的群体中的人更有可能:
- 收入一般
- 准备一般
- 不投资他们的钱
- 经济利益很低
- 社会地位低而且非常低
- 购买力一般
- 不是男的就是女的
客户反应预测
既然我们已经发现了哪部分人更有可能成为邮购公司的客户,我们就可以建立一个监督模型来预测一个人是否会对营销活动做出反应。
“mailout.train”和 mailout.test 中的每一行都代表邮寄活动的目标个人。每个数据集包含大约 43 000 个数据行,训练数据集包括一个列“响应”,该列说明在活动之后某人是否成为公司的客户。
我首先使用 clean_df 函数来处理预处理部分的所有步骤。之后,我注意到数据集在类方面是不平衡的。事实上,98.76%的观察结果对应于没有对活动做出响应的人。因此,准确性度量似乎不是评估模型的好选择。我将使用 ROC AUC 指标,因为它不受不平衡的影响。
ROC AUC 指标
由于第二个模型是一个分类问题,我将使用 AUC-ROC 作为度量。ROC(受试者操作特征)代表概率曲线,它是通过绘制真阳性率(TPR)或召回率与假阳性率(1-特异性)的关系图来创建的。AUC 给出了可分离度。通过使用 AUC-ROC,我们能够知道我们的模型在分类这两类中的表现如何。AUC(曲线下面积)越高,模型预测活动成功的能力就越强(在我们的例子中)。
基线模型
我构建了一个函数,它接受要执行的模型或模型列表、用于馈送 GridSearchCV 和调整分类器的参数名称、X_train 数据、Y_train 数据和一个可选参数,以防我想要绘制条形图和比较不同的模型。
每当我建立一个分类模型时,我喜欢从使用逻辑回归算法的基本形式开始。起初,我删除了代表每个个体的 id 的列,得到了一个很差的结果。令人惊讶的是,在包含该行之后,我得到了 0.7 的结果,这对于基线模型来说是不错的。
构建其他模型
我在数据上测试了几个不同的监督学习模型。请注意,我没有对数据进行缩放,因为我最期待的是三个基于模型的更好的结果,正如我们所知,这些模型可以很好地处理非缩放数据。
梯度增强调谐
上面的柱状图表明,最有前途的分类器是 gradientBoosting。正因为如此,我选择了这个算法来调整使用。
我做了一个执行试验和错误调整,调整参数,如 n_estimators、loss、learning_rate、n_samples_split、min_samples_leaf、max_depth、max_features 和 subsample。
我最终得到了一个具有以下特征的模型:
根据模型的特征重要性:
结论
这个项目的主要目标是了解客户群,并预测一个人是否会对营销活动做出反应。这样,我们可以帮助一家德国邮购公司开发一种更有效的瞄准潜在客户的方法。
第一部分包括建立无监督模型,如 PCA 和 k-means 聚类,以执行客户细分。我们使用了 215 个组件和 11 个集群。应用这些方法后,我可以比较代表过多和代表不足的组别,并得出一些结论。例如,我注意到,被过度代表的群体中的大多数人(来自普通人群的人可能是公司的目标受众)收入高,是投资者,也是很好的存钱者。另一方面,普通人收入一般,不投资,购买力一般。
在第二部分,我建立了几个不同的监督学习模型,并对它们进行了比较。梯度推进算法给我提供了最好的 ROC AUC 分数,因此它被选择和调整。经过彻底的参数调整后,我在测试数据中得到了 0.78794 分。
这个项目真的很有挑战性,但是我从中学到了很多。我要感谢 Udacity 的所有支持(特别是我的导师 Mofetoluwa A .)和贝塔斯曼 Arvato Analytics 提供的所有这些数据。
使用数据科学进行营销分析
B2B 与 B2C 的区别
资料来源:联合国人类住区规划署
“根据 QuanticMind 的数据,97%的领导者认为营销的未来取决于数字营销人员与基于机器学习的工具一起工作的方式。”——数字营销学院
与 CRM (B2B)活动合作
在 B2B 营销中,企业使用客户关系管理(CRM)软件,如 Salesforce、Oracle 和 SugarCRM,来记录在决策和采购中起关键作用的业务合作伙伴的联系人。这些数据可以在带有营销分析软件的机器学习环境中使用,以绘制针对特定市场的广告活动的有效性。
- 销售渠道中包含的个性化事件,如呼出电话和电子邮件简讯,可以记录在图表中,以分析未来购买的结果。
- 商展和促销活动的出席情况在侧重于销售周期的营销分析中以时间戳记录。
B2B 营销中的一大挑战是在销售中确定决策的归属,因为在一次购买中可能会有几个人参与。B2B 营销的个性化可以扩展到每个联系人 100 万个事件,从编程变量生成图表和分析。
参与电子商务(B2C)活动
在 B2C 营销分析中,将销售决策归咎于一个人并不困难。在 B2C 营销中,没有相同的机会来跟踪具有特定采购代理的商业组织和公司。以 B2C 为代表的零售消费市场要广阔得多,是由电商平台需求定义的。
- 在线商店通过各种形式的 cookies 跟踪网站和移动应用程序上的消费者销售渠道,其中最大的企业网站通常在其平台上支持 1 亿至 2.5 亿注册用户。
- 这导致了来自由机器学习和数据科学实时驱动的自动化营销分析的电子商务数据的个性化的潜力。
- 企业跟踪与搜索引擎流量、回头客、PPC 广告和直接电子邮件活动相关的变量,以确定广告在销售周期中的有效性。
- 这些可变事件还可以通过营销分析软件绘制限时销售和假日促销的效果图。
计算营销活动的 ROMI 分析
营销投资回报率(ROMI)是一个 OPEX 模型,比较非资本支出与收益。该术语由 Guy Powell 于 2002 年创造,用于评估通过投资昂贵的商业广告来建立长期品牌形象、客户忠诚度和商誉的营销活动。 ROMI 是根据与收入、利润和计划支出变化相关的简单公式计算出来的。
- 鲍威尔认出了两种 ROMI,“模糊的”和“清晰的”。
- 模糊 ROMI 试图通过对顾客反馈中定性价值的统计测量来估计品牌忠诚度和商誉。
- 90%的营销分析使用夏普 ROMI 来跟踪商业周期中的总项目支出与新收入。
- 夏普 ROMI 指标通过机器学习和数据科学来评估 B2B 和 B2C 广告的有效性。
“大数据”存储库通过机器学习算法进行过滤,以帮助决策者通过图表分析来辨别模式,从而预测类似的成功。理想情况是创建一个经过培训的实时数据科学模型,根据客户的历史喜好和偏好向客户部署定制内容和显示。说明性和描述性模型都有好处。
使用描述性模型
描述性模型从电子商务和 CRM 资源中过滤“大数据”,从后视镜中评估 ROMI,即通过对过去活动的分析。
- 营销分析软件对销售周期中的近期活动进行优先排序,并应每天在数据科学笔记本中进行重新培训。
- 比较信息包括营销活动、结果和成本,作为跨销售渠道成功的变量。
使用预测模型
营销分析中的预测模型基于实时反馈,依赖于实时数据。来自客户和顾客的这些信息必须存储在一个可靠、安全和快速的数据库中。
- 营销分析的预测模型有助于决策者辨别如何改变广告活动内容,以符合消费者的口味和趋势。
- 预测模型在 ROMI 阶段开发,通过产品端和客户端推荐引擎优化广告活动。
这些方法可以帮助电商平台和店铺避免购物车被顾客抛弃。在由数据科学驱动的营销分析中,随着时间的推移,你更新模型越多,结果就越智能。
优化营销分析的成功
为了通过机器学习在广告活动的营销分析中取得成功,企业必须区分现有客户、新业务和续订。
- 在电子商务中,大多数平台收入来自重复交易,这可以通过向客户推荐产品来创建个性化显示进行优化。
- 在为数据科学中的指标和分析准备数据时,企业需要将客户事件变量收集到单个流中,然后标记每个事件,并为平台大规模聚合信息。
香槟图可用于确定数据分析中何时出现路径行为。
来源:作者
模式拟合显示了人们在购买产品之前是如何消费产品评价的。
来源:作者
结论
- 获取数据。要有耐心;这需要几周时间。获得所有许可以找出所有系统的位置并从那里出发需要很多时间。
- 获得所有系统的访问权限
- 就单一时间戳方法达成一致
- 就“成功”对销售的意义达成一致(时间、内容、地点、实体)
- 查找所有中点系统
- 就组织活动模式达成一致
- 每个人/组织/销售、产品系列/销售活动的单数据流数据
2.使用云数据库:不要将数据存储在平面文件或笔记本电脑中。计划规模,即使你只是踢踢轮胎。我真的很喜欢雪花,因为它很快,而且是基于云的。因此,如果你想把一个项目从欧洲转移到美国进行分析,这是可行的。如果它在您的数据中心,那么它穿越海洋的速度可能会慢 50-100 倍。
- 重新组织和规范化数据
- 输入时将其匿名,但留下一个解码系统(当人们钻研“证据”时)
- 规划大规模和长期的全球输入/输出—数据是一场流动的盛宴
- 为将来的“为什么/什么/何时”查询启用—添加一些帮助器列和表
- 将其连接到快速、可扩展的数据科学笔记本电脑
附加资源
- 这篇博客摘自 Grover Righter 的网络研讨会“使用数据科学进行营销分析”。点击此处观看整个网络研讨会。
- Zepl 的数据科学平台允许数据科学家和分析师快速构建 Python、R、Scala 和 SQL 模型的原型,为他们的营销分析用例创建丰富的视觉效果。在 www.zepl.com 免费试用
- 雪花通过为所有数据工作负载提供可扩展、灵活且安全的云数据平台,帮助营销分析团队从其数据中获取更多商业价值。在 www.snowflake.com免费试用
作者
Grover Righter 是 Zepl 的首席数据科学家。他专注于基于科学的营销项目,并运行着一个衡量电子邮件、搜索引擎优化和社交媒体有效性的分析引擎背板。他曾在各大知名营销自动化平台上工作,包括 Eloqua、Marketo、Pardot、HubSpot 和 Leadformix。
Grover 自 1981 年以来一直在高科技领域工作。他最初是一名数学家和设计工程师,在 RMS 公司、美国电话电报公司公司、Unisys 公司和 Novell 公司的主要技术的设计和开发中发挥了重要作用。但每次格罗弗制造出一个产品,他都会立即被招募去“销售它”,而不管组织内是否存在另一个销售团队。最终,格罗弗用完了他一生中作为一名工程师参加销售会议的机会,转而从事营销工作。
现在使用数据科学技能:文本可读性分析
如何使用 python 识别阅读水平分数
图片来自皮克斯拜
当营销效果分析被开发时,内容阅读水平经常被忽视。这应该是分析的一部分还是你的模型的一部分?如果你认为是,你会如何轻松地将不同的文档或创意与当前的阅读水平联系起来?今天我将回顾如何使用 python 进行阅读水平分析并创建报告。我们将把英语作为主要语言。同样的技术可以用来确定你的其他内容的可读性,比如中型博客。
为什么可读性很重要
无论你是想让你的客户了解你的新服务的好处,还是想让他们了解你的医疗实践,你都需要你的受众阅读并理解这些内容。太难了,你的读者就放弃你了。太简单了,读者会觉得你在居高临下地和他们说话。你不仅想让你的读者舒服地阅读你的文本,这也是搜索引擎优化的一个关键考虑因素。
你的读者是谁?
了解和研究你的典型读者是很重要的。如果你需要专注于一个领域开始,考虑教育水平。估计你的读者受教育的年数,然后减去三到五年来估计平均阅读水平。
如果你不能完全确定听众的教育水平,该怎么办?一些行业经验法则会有所帮助。
得分在 4 到 6 年级的书面文本通常被认为是“容易阅读的”如果你试图简单地为大众解释复杂的概念,这是你的范围。想想一般的博客和教育材料。
得分为 7 到 9 分的书面材料被认为是一般难度。这些读者期待一些更复杂的词汇。他们认为他们可能需要重读一段文字才能完全理解。操作指南文章可能属于这一范围。
任何十年级及以上的课文都被认为是非常难的。这应该留给白皮书、技术写作或文学作品,当你确定你的读者“准备好”和/或期待它的时候。你的读者在阅读和吸收你的内容上花费了相当多的精力。你知道当你读一本让你精疲力尽的书时?这是那个范围。
有哪些局限性?
当心标题、列表和其他“非句子”这些会影响你的分数。此外,根据您使用的指标,等级级别可能会有所不同。这些分数作为分析文本的一般起点。您可以确定哪些内容需要进一步检查。
代码
许多商业产品会扫描你的内容,并提供可读性指标。当这些产品对您不可用或者有成百上千的文档时,您将需要创建一个脚本来自动化这个过程。
我这里有一个脚本,它执行常见的自动化任务。它读入一个文件夹中的所有文本文档,然后给它们打分。有关如何在多个文件夹和数据源中抓取文本的更多信息,请参见这篇相关文章。
有一个繁琐的文档搜索任务?用 python 通过 5 个步骤实现自动化。
towardsdatascience.com](/using-data-science-skills-now-text-scraping-8847ca4825fd)
您可以在分析中使用几个软件包,包括 textstat 和可读性。在这个例子中,我将使用 textstat。使用起来很简单。
import textstat # [https://pypi.org/project/textstat/](https://pypi.org/project/textstat/)
import os
import glob # using to read in many files
import docx2txt # because I'm reading in word docs# where is the folder with your content?
folderPath = '<path to your top folder>\\'# I want to search in all of the folders, so I set recursive=True
docs=[]
docs = glob.glob(folderPath + '/**/*.txt',recursive=True)
docs.extend(glob.glob(folderPath + '/**/*.docx',recursive=True))
#... keep adding whatever types you needprint(docs)# the language is English by default so no need to set the language# Loop through my docs
for doc in docs:
if os.path.isfile(doc):
text = docx2txt.process(os.path.join(folderPath,doc))
print('Document: ' + doc)
print('Flesch Reading Ease: ' + str(textstat.flesch_reading_ease(text)))
print('Smog Index: ' + str(textstat.smog_index(text)))
print('Flesch Kincaid Grade: ' + str(textstat.flesch_kincaid_grade(text)))
print('Coleman Liau Index: ' + str(textstat.coleman_liau_index(text)))
print('Automated Readability Index: ' + str(textstat.automated_readability_index(text)))
print('Dale Chall Readability Score: ' + str(textstat.dale_chall_readability_score(text)))
print('Difficult Words: ' + str(textstat.difficult_words(text)))
print('Linsear Write Formula: ' + str(textstat.linsear_write_formula(text)))
print('Gunning Fog: ' + str(textstat.gunning_fog(text)))
print('Text Standard: ' + str(textstat.text_standard(text)))
print('*********************************************************************************')"""Flesch-Kincaid Grade Level = This is a grade formula in that a score of 9.3 means that a ninth grader would be able to read the document""""""Gunning Fog = This is a grade formula in that a score of 9.3 means that a ninth grader would be able to read the document.""""""SMOG - for 30 sentences or more =This is a grade formula in that a score of 9.3 means that a ninth grader would be able to read the document.""""""Automated Readability Index = Returns the ARI (Automated Readability Index) which outputs a number that approximates the grade level needed to comprehend the text."""""" Coleman Liau Index = Returns the grade level of the text using the Coleman-Liau Formula.""""""Linsear = Returns the grade level using the Linsear Write Formula."""""" Dale Chall = Different from other tests, since it uses a lookup table of the most commonly used 3000 English words. Thus it returns the grade level using the New Dale-Chall Formula."""
我的四个文档的结果。首先是这个博客。第二个是这个博客,去掉了链接。第三篇是 USAToday 的文章,第四篇是去掉了页眉和照片的 USAToday 文章。
Document: C:...readability\sampleblog.docx
Flesch Reading Ease: 56.59 (Fairly Difficult)
Smog Index: 13.8
Flesch Kincaid Grade: 11.1
Coleman Liau Index: 11.9
Automated Readability Index: 14.1
Dale Chall Readability Score: 7.71 (average 9th or 10th-grade student)
Difficult Words: 124
Linsear Write Formula: 10.833333333333334
Gunning Fog: 12.86
Text Standard: 10th and 11th grade
*********************************************************************************
Document: C:...readability\sampleblognolinks.docx
Flesch Reading Ease: 58.52 (Fairly Difficult)
Smog Index: 12.9
Flesch Kincaid Grade: 10.3
Coleman Liau Index: 10.5
Automated Readability Index: 12.2
Dale Chall Readability Score: 7.48
Difficult Words: 101
Linsear Write Formula: 10.833333333333334
Gunning Fog: 11.95
Text Standard: 10th and 11th grade
*********************************************************************************
Document: C:...readability\usatoday article no header photos.docx
Flesch Reading Ease: 21.47 (Very Confusing)
Smog Index: 19.8
Flesch Kincaid Grade: 24.6
Coleman Liau Index: 13.19
Automated Readability Index: 32.2
Dale Chall Readability Score: 9.49
Difficult Words: 317
Linsear Write Formula: 16.25
Gunning Fog: 27.01
Text Standard: 24th and 25th grade
*********************************************************************************
Document: C:...\readability\usatoday article.docx
Flesch Reading Ease: 21.47 (Very Confusing)
Smog Index: 19.8
Flesch Kincaid Grade: 24.6
Coleman Liau Index: 13.19
Automated Readability Index: 32.2
Dale Chall Readability Score: 9.49
Difficult Words: 317
Linsear Write Formula: 16.25
Gunning Fog: 27.01
Text Standard: 24th and 25th grade
*********************************************************************************
对于这个博客,分数受到移除链接的影响。USAToday 的文章没有受到移除标题和照片的影响。
参考资料和资源
- 全国成人识字调查。全国成人识字调查(NALS)显示了不同年龄、种族/民族和健康状况的人的识字水平。如果你知道你的读者的人口统计数据,你可以利用这次调查的数据来估计平均阅读水平。
- 社论:避免稿件可读性差的循证指南
- 卡格尔:
2019 年有一个有趣的比赛,我应用可读性分数来改善洛杉矶市的招聘信息。你可以看到不同的竞争者使用不同的技术。
使用 Kaggle 笔记本探索和运行机器学习代码|使用来自多个数据源的数据
www.kaggle.com](https://www.kaggle.com/silverfoxdss/city-of-la-readability-and-promotion-nudges)
结论
文本可读性是一个非常有趣的主题。了解谁是你的受众以及他们如何消费你的内容是非常重要的。忽略这一信息,你可能不会击中目标。
现在使用数据科学技能:文本抓取
有一个繁琐的文档搜索任务?用 python 通过 5 个简单的步骤实现自动化。
图片来自皮克斯拜
我们都被赋予了任务,而这些任务在本质上是乏味的。它们是手动的,很烦人。如果这是一个一劳永逸的项目,我们就努力完成它。有时候你知道将来会再次被要求。这时,您只需通过 python 脚本自动完成任务,这样就不会再有人受苦了。这是其中的一个例子。
最近,我被要求提供我们的数据分析师团队查询的每个数据库表、视图和列名的列表。十年,在此期间可能有 30 个数据分析师,在不同的位置有数百个不同的文档。每周都会添加新的表和列。我制作的任何列表都会频繁更改。这需要某种自动化。
我不可能手动查看成千上万的文档来寻找 SQL。那是疯狂的谈话!
我创建了一个可重复的 python 脚本。它也可以适用于不同的情况,如下所示。
- 确定包含特定客户引用的每个文档。
- 指出每一份提及某一法院案例或法律的文件。
- 客户更改了法定名称,需要更新哪些文件?
- 识别所有文档中的名字。
我已经确定了完成这项任务的五个步骤
1.你要去哪里找?
确定所有需要搜索的文件共享、代码库和内部网站点。
共享文件共享
确定团队使用的所有文件共享。如果人们把文件藏在他们的本地设备上,让他们把它们转储到一个共享的驱动器文件夹中。
Git/Bitbucket
决定是否要将 Git 仓库克隆到一个文件夹中来抓取 Git 本身。我只需要搜索某个主要的代码分支,所以我只是将它克隆到一个文件夹中。您甚至可以从您的开发工作中获得代码的本地克隆。
内部网站点
决定你将如何处理内部或外部网站。如果你使用外部网站,你可能需要先收集并转储你的发现。内部网站也是如此,尽管你可以使用 Sharepoint 或 Confluence APIs。在我的例子中,我对代码本身感兴趣,所以我不需要参考我们内部网站上的文档。
2.您想搜索什么类型的文件?
我在寻找运行的 SQL 和脚本来提取数据。我把搜索范围限制在。txt,。SQL,。hql,。您可能有其他类型的文件来拉。
3.你需要找到什么?
您可能在寻找一个特定的单词或术语。在我的例子中,我不得不寻找许多术语。您需要创建一个这些术语的列表。因为我没有所有可能的表、视图和列的列表,所以我必须生成这个列表。我将使用 DB2 作为例子:
4.创建你的单词表。
-- Generate my word list [DB2](https://www.ibm.com/support/knowledgecenter/SSEPEK_11.0.0/cattab/src/tpc/db2z_catalogtablesintro.html)
-- List of Tables in my set of databases
SELECT DISTINCT NAME , 'TABLE' AS TYPE, '' AS STATEMENT
FROM SYSIBM.SYSTABLES
WHERE CREATOR IN (<list of my databases>)UNION-- List of Columns in my set of databases
SELECT DISTINCT NAME , 'COLUMN' AS TYPE, '' AS STATEMENT
FROM SYSIBM.SYSTABLES
WHERE CREATOR IN (<list of my databases>)UNION-- List of Views in my set of databases,
-- include statements for complex views
SELECT DISTINCT NAME , 'VIEW' AS TYPE, STATEMENT
FROM SYSIBM.SYSTABLES
WHERE CREATOR IN (<list of my databases>)
;
这里有一些您可以从中提取的其他数据库目录表。
-- SQLServer
SELECT NAME , 'TABLE' AS TYPE
FROM SYS.OBJECTS
WHERE TYPE_DESC = 'USER_TABLE'
UNION...SELECT NAME, 'COLUMN' AS TYPE FROM SYS.COLUMNS-- Oracle
SELECT .... sys.dba_tables and sys.dba_tab_columns-- [Glue Catalog](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_databases)
this technique uses boto3 and get_database, get_tables (contains column info)
一旦你创建了一个单词列表,你就可以开始提取文档并扫描它们。
5.创建代码以生成匹配文件。
我在下面为这个例子创建了这个通用代码。我知道嵌套循环不是最有效的方法,但它对我的任务来说很好(与几百个文档相比,50k+单词)。
# import required packages
import pandas as pd
import glob
import os
from string import punctuation
import re
import sys# where are you searching?
folderPath = '<path to your top folder>\\'# read in all of the documents
# I want to search in all of the folders, so I set recursive=Truedocs = glob.glob(folderPath + '/**/*.txt',recursive=True)
docs.extend(glob.glob(folderPath + '/**/*.sql',recursive=True)
docs.extend(glob.glob(folderPath + '/**/*.py',recursive=True)
#... keep adding whatever types you need# I need to remove punctuation, particularly the '.' separator between the database name and the table name
punctuation = '''!()-;:\,./?@%'''# Read in the word list that has been created
word_df = pd.read_csv('mywordlist.csv')
word_list = []
word_list = word_df['NAME'].tolist()# Create the dataframe to hold the matching words
# and the file found in (optional)
matched_words = pd.DataFrame(columns = ['NAME', 'FILE'])"""Loop through all the files , remove punctuationn, split each line into elements and match the elements to the list of words"""
for doc in docs:
if os.path.isfile(doc):
f=open(os.path.join(folderPath,doc), 'r')
for line in f:
for ele in line:
if ele in punctuation:
line = line.replace(ele, " ")
line_list = []
line_list = line.split() for x in line_list:
matches = matches.append({'NAME': str(x), 'FILE': doc}, ignore_index=True# write my output file
matches.to_csv('matches.csv')
输出提供了匹配单词的列表以及保存匹配单词的文件名/位置。
额外的好处是这个列表包含了这个单词的每个实例。如果需要计数,可以很容易地将该逻辑应用到这个文件中。
结论
这个简单的脚本代替了一小时又一小时的苦差事。当六个月后有人再次提出这个要求时,很容易被复制。
采取措施消除你工作日中的苦差事。完全值得。
欢迎在下面分享你的代码片段。一如既往,有许多不同的方法来编码解决方案;我的样本只是其中之一。这可能不是最有效或最好的,但这种方法是可行的。
利用数据科学分析足球运动员的表现
最常见事件类型的分解技巧
不足为奇的是,传球是足球(或者对任何感兴趣的美国人来说是英式足球)中最常见的事件。一场好的传球比赛对足球的成功至关重要,因为它能让你通过控球来控制比赛,节省能量,从而给你带来更好的得分机会。传球是指使用良好的技术快速、准确、恰当地传球,同时在正确的时间做出正确的决定。
因此,不应该低估分析该领域中玩家表现的重要性。但是我们如何量化一个球员的传球技术呢?
传统的衡量标准是完成的通过次数。然而,使用传球是否完成的二元标签忽略了球员之间传球风格的巨大差异,也没有考虑到球队的流动。
我们知道这种传球类型的变化是存在的,因为专家和评论员讨论它的方式,“伟大的传球”,“侵略性的传球”,“可怜的球”。
使用二进制标签时,这些描述符会被完全忽略。
这个博客建立了一个预期传递模型来改变这种看法。我使用一个客观变量来衡量连续谱上的传球质量,根据之前的传球数据来分析任何传球所涉及的风险水平。对于那些对完整代码感兴趣的人,(包括所有的可视化),请随时查看这里的。
数据
我用来建立这个预期传球模型的数据是基于 20 支球队,打了 380 场比赛,总共尝试了 358,783 次传球。
初始变量包括:
- 球队、比赛、球员、主场、客场标识符
- 主客场全职比分
- 半,分,秒
- 通过的结果(1 或 0)
- 通行证的起点 x 和 y、终点 x 和 y 的位置标识符
- 如果传球是正常传球,或者是头球、传中、角球、抛球、任意球
作者图片
坐标假设球场为 105 米 x68 米,并且已经调整,从进攻方的角度来看,X 在进攻方向从 0-105 度,Y 从右到左。例如,从(x,y) = (95,15)开始的传球在对方禁区的右侧开始。
新增功能
尽管我们可以将原始数据输入到机器学习中,但特征工程是转换数据以产生与场景、问题和领域相关的特征的过程。在这种情况下,我设计的功能围绕两个要点——球的移动和团队表现:
- 利用毕达哥拉斯定理计算传球距离。
- 每场比赛的主客场位置指标。
- 向前或向后为传球方向。
- 对于目前控球的队伍来说,他们的比赛结果。(赢、平、输)
- 将球场分成 9 个大小相等的方块,标为 1-9
可能会有更多的功能可以被包括在内,所以如果你有任何补充,请随时发送给我!
初步探索性数据分析
探索性数据分析是指对数据进行初步调查的过程,以便在汇总统计数据和图表的帮助下发现模式、发现异常并检查假设。
通过距离完成(图片作者提供)
该图显示,很大比例的传球在非常低的距离(小于 5 米)处失败。这可能表明在传球的早期阶段被拦截,而不是非受迫性失误。在 15 到 30 米之间,完成的传球比失败的传球多得多,在 30 米之后,完成传球的比例急剧下降,而失败传球开始趋于平稳。
通过 X 年底完成(图片由作者提供)
这第二个视觉化显示传球完成也受球场上传球结束位置的影响。随着球进一步向对方球门移动,传球失误的比率会增加。这个柱状图也向我们展示了大部分的传球,完成的或者失败的,都是在中场结束的。
也许有趣的是,当看一遍从哪里开始时,完成率的这种差异并没有延续到相同的数量级。
通过开始完成 X (图片作者)
大多数“特殊”传球类型,如角球和任意球,完成率比普通传球类型低。
按传递类型完成传递(图片由作者提供)
无监督学习
无监督学习是一种机器学习,它在最少人工监督的情况下在数据集中寻找以前未检测到的模式。在这种情况下,我使用它作为一种自组织类型来了解各种不同的传递类型,首先删除传递是否完成,因为我不希望传递类型在成功时聚集,并避免数据在管道中进一步泄漏。
K- means 聚类是我使用的无监督学习算法。它遵循一个简单的程序,将给定的数据集分类成一些集群。与其他集群技术相比,它的伸缩性很好,工作速度也很快。这很容易解释。我选择了 22 个集群,目的是让一个团队中的每个球员都有 2 次传球,虽然它显示了球在球场上的一般运动,但更多的集群将提供关于传球通常如何进行的更详细的视图。下面显示了通过平均起点和终点的集群。
K 表示使用 22 个聚类进行聚类(图片由作者提供)
这些聚类类别被用作随后的监督学习算法的预测器。
监督学习
监督学习的定义是使用标记数据集来训练算法,以对数据进行分类或准确预测结果。在这种情况下,我们训练一个机器学习算法,以及训练数据集中是否完成了一次通过,并从测试数据集中删除通过结果,看看它可以预测一次通过是否完成的程度。
为了测试算法的性能,标准的做法是预先生成一个虚拟模型。在这种情况下,虚拟模型只是预测所有通道都将完成。在测试集中,完成了 71,001 次通过,18,695 次失败。每次选择“pass complete ”,精确度为 79.3% 。这几乎都是由于高日志丢失造成的噪声。
在尝试了多种不同的方法之后,我选择了 XGBoost。XGBoost 是一种算法,最近一直在结构化数据的应用机器学习和 Kaggle 竞争中占据主导地位。使用超参数调整,产生了以下混淆矩阵:
XGBoost 混淆矩阵(图片由作者提供)
它打破了模型的预测和实际发生的事情,彼此并列。在这里,我们可以看到,79.3%的数据集已完成通过。该算法预测 75%已完成通过。
20.7%未通过,模型预测 13%会通过。
该混淆矩阵可用于计算以下指标:
- 准确度得分: 0.88
- 精度分数: 0.9
- 召回分数: 0.95
- F1 得分: 0.92
- 测井曲线损失: 0.28
- AUC : 0.92
所有这些都大大优于基准假人模型。
通过风险和玩家分析
找到一个相对可靠的算法来预测是否通过(1 或 0),我将二进制输出转换为通过的概率,XGBoost 可以为我提供这个概率。
然后,我定义了度量传递风险。如果模型预测传球发生的概率为 0.8,并且完成了,我给球员传球得分加 0.2。如果他们传球没有完成,我给该球员传球得分减 0.8 分。然后,我对球员的传球次数进行平均,以定义平均风险克服分数。这个分数能够比较球员在传球中所冒的风险和克服的风险。
玩家平均风险战胜(图片由作者提供)
拥有相似的传球组合的球员,很可能在球场上踢相同或相似的位置。这里我们可以看到,与风格类似的玩家相比,玩家 263 的风险克服得分高于平均水平。
然而,在足球比赛中,我们不仅仅关心平均水平,稳定性也是分析球员表现的关键。
虽然与其他球员相比,球员 263 的传球表现略高于平均水平,但他比其他球员尝试更多的传球。这导致他在与一组类似的同龄人相比时被列为最优秀的传球手之一。像这样观察球员的表现可以让我们寻找其他有价值的替代者。玩家 409 具有非常高的平均风险克服率,但很少传球,他可能被低估或低估。
通过风险克服的次数(图片由作者提供)
这为教练提供了建立球队和球员替补席的机会,这些球员在统计上会比他们在转会市场上的价格更好,并识别表现不佳的球员。
考虑到克服风险和传球次数都是考察球员表现时要考虑的重要指标,将它们相乘可以得到一个总传球得分,从而可以进行进一步分析。在这里,我们可以看到 263 号球员在所有排名前 40 的球员中排名第二。
通过总分排名前 40 的选手(图片由作者提供)
这一观点使得进一步的发现成为可能,通过这些发现,教练可以从低水平的球队中识别出高水平的球员。可能被降级的球队,或者陷入财务困境的球队,甚至是其他联赛的顶级球员,都有可能被低价收购。
结论
我们可以使用数据科学来分析球员在传球中能够克服多少风险。为足球比赛中发生的所有行为建立类似的衡量标准是可能的——无论是铲球、射门还是控球。这有助于更深入地了解玩家和团队的表现(包括你自己和对手的表现),有助于提高表现并最终提高游戏成绩。
在团队中使用数据科学和机器学习并不新鲜,事实上,体育界完全充斥着统计数据。了解新的方法和使用新的技术来利用体育界存在的大量数据,可以帮助团队和教练超越他们的对手,不管是什么运动。
限制
上述工作有一个明显的局限性;也就是说,通过按风险克服程度对玩家进行排名,我们假设风险是好的。通行证里没有价值的概念,或者说报酬,所以很难建立风险/报酬模型。传球的价值在于它有可能带来机会或者把球带到对手的地盘,这一点很重要。不幸的是,这个数据集只包括传球结果的细节,然而,有了更多关于射门和进球的详细数据,就有可能开始建立这种模型。
进一步的工作
有了这个比较整个联盟球员的用例,一个高层次的模型是有意义的。然而,单个团队和球员可以玩得很不一样。进一步的工作可能包括建立模型来分析单个团队的表现,或者甚至在单个球员层面上进行更精细的分析。这有助于发现你自己球队的弱点,或者提供机会利用对手和特定球员的打法。这一点的开头详述如下。
团队级别的聚类(图片由作者提供)
玩家级别的聚类(图片由作者提供)
关于我
我希望你喜欢我的作品!我会很感激通过这里对它的任何反馈。我是一名数据科学家,热衷于处理体育数据。作为一名前职业赌徒,我对体育分析和预测有着独特的见解。我目前正在寻找进入体育数据行业,如果你想接触,请前往我的 LinkedIn!
[## 卡特 B. -数据科学家-自由职业者,个体经营者| LinkedIn
随着博客成功地发表了走向数据科学和分析 Vidhya,我目前正在寻找数据科学…
www.linkedin.com](https://www.linkedin.com/in/carterbouley/)
参考文献
保罗·鲍尔、赫克托·鲁伊斯、魏新雨和帕特里克·露西。2017.并非所有传球都是平等的:从跟踪数据客观地测量足球传球的风险和回报。《第 23 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集》(KDD '17)。计算机械协会,纽约,纽约州,美国。DOI:https://DOI . org/10.1145/3097983.3098051
用熊猫和 Dash 重新思考篮球比赛
得分尝试树框架确定 NBA 篮球是 32%投篮,32%对手投篮,20%失误,16%篮板
得分尝试树(全互动写起)
2019 年 5 月 12 日,猛龙-76 人,第七场,第四节,还剩 4 秒,比赛平手。我想我们都记得接下来发生了什么。现在被称为“一击”。NBA 历史上最重要的季后赛投篮之一。
人们可能不记得的是,那晚投篮对猛龙队不利。
猛龙-76 人投篮对比(2019 . 5 . 12)
总的来说,76 人的投篮明显比猛龙好。但是猛龙队以 92 比 90 赢得了比赛。发生了什么事?在一场财产交替的运动中,猛龙队怎么可能赢得那场比赛?
猛龙出手比 76 人多。如果一支球队比他们的对手更频繁地错失第二次机会,或者迫使失误比他们允许的更多,那么他们在导致他们获得超过对手的投篮机会的领域表现良好。利用评分尝试树框架,我们能够生成这种可视化。
猛龙-76 人投篮尝试和解(2019 年 5 月 12 日)
那么什么是评分尝试树框架呢?它遵循篮球比赛是一系列树的前提。更具体地说,得分尝试树,每次出现失误、得分或篮板时都会重置。它比每次控球的观点更深入一些,因为进攻篮板有可能在一次控球中出现多次得分尝试。
利用熊猫,我能够从 2018-2019 赛季的比赛数据中收集比赛数据,以符合这一模型。我从大数据球中以 csv 格式提取数据。然后,我开始开发一个标准流程,将一个接一个的数据转换到我的模型中。这主要包括删除与我的分析不相关的数据,如记录暂停、替换、犯规、死球篮板的数据,然后开发检查、修复和模型解释的流程。
收集详细数据
该模型的目的是定义投篮、篮板和失误指标,以此来制定每球得分的预期指标。你最终会得到下面的框架。
得分尝试树(链接)
我能够让 2018-2019 赛季的所有比赛都符合解释篮球的公式。本质上,该模型使用计算出的 EPos 和拥有数字正确地计算出了所有游戏的最终分数。
回到猛龙-76 人,我们可以看到他们在 4 得分尝试树指标中的表现。猛龙队在失误和篮板方面明显优于 76 人队。
猛龙-76 人 4 项指标对比(2019 年 5 月 12 日)
根据这个框架,我们知道每场得分( EPos )是 4 个指标的乘积。我注意到,如果我移除了 m% ,剩余的指标仍然在线性回归模型中以 0.995 的 R 预测 EPos 。为了这个练习的目的,我发现最直观的方法就是将射击视为 EShot 。
因为篮球是在两端进行的,所以看一下净 EPos、EPos 和 opp EPos 的区别(即对手的 EPos)是有意义的。如果你对 t% 和 oreb% 采取相同的净方法,你会得到代表投篮、对手投篮、失误和篮板的 4 个因素,分别符合净 EPos 的 32%、32%、20%和 16%。
四因素回归分析
我将这些因素标准化,使它们在数量上完全相同,这样我们就可以使用加权平均值来计算整体因素。我把这些 zbo 分数叫做 T29,它们本质上就像 2K 等级。我有不同的 zbo 分数参数用于游戏内和多游戏累积结果,以允许两个预期数据集以 75 为中心的友好分布。
回到猛龙和 76 人的比赛,我们可以看到两支球队在比赛中各自的表现。
猛龙-76 人比赛中 zbo 得分(2019 年 5 月 12 日)
给你。猛禽队在失误和篮板方面的强劲表现足以推动他们战胜 76 人队,尽管他们的投篮很糟糕。
我运行了整个 2018-2019 常规赛的因素,并为每个球队生成了下面的 zbo 分数。
2018–2019 常规赛 zbo 得分
值得注意的是,我的赛季末净 EPos 和下面的总体 zbo 分别符合 0.998 和 0.995 的实际赛季积分差。
就是这样。我希望下次你考虑一个球队或球员时,你会考虑他们如何影响所有四个类别,然后相应地评估他们的整体价值。
如果您对本文有任何疑问,请随时通过 david@belleville.app 与我联系。同样,在我的文章中也有更多信息,这里也有。
蒙特利尔的公寓租赁危机分析
网页抓取、数据清理、数据可视化等等
在蒙特利尔找一套公寓比以往任何时候都难,当前的危机当然也没有帮助。
2020 年 1 月,《蒙特利尔公报》估计,该市的空置率约为 1.5%(15 年来最低),租金价格在一年内上涨了约 3.6%。
随着 7 月 1 日(城市正式搬迁日)的到来,我决定看看目前的租赁市场,看看情况到底有多糟糕。
获取数据
为了做到这一点,我从寻找蒙特利尔公寓的主要网站 Kijiji 上搜集了(使用 BeautifulSoup)数据。更准确地说,我搜集了大约 3500 份公寓出租清单。对于每一个列表,我提取了价格、公寓的大小和离市中心的距离。我不得不使用离市中心的距离(最多 10 公里),因为大多数公寓的实际地址是不可用的。然而,离市中心的距离应该是一个很好的指标,表明公寓是否在理想的位置。对于熟悉这座城市的人来说,这是一张 10 公里半径的地图:
来源:使用 mapdevelopers.com 制作的地图
下面是用于从 Kijiji 获取数据并创建起始数据帧的代码:
如上所述,只有前 80 页的网站被刮,只有相对较新的清单。此外,睡眠功能用于通过暂停一段时间来控制循环的速率。我这样做是因为向网站发送太多太频繁的请求会导致网站的服务器关闭或网站变得太慢。
这是我此时的数据帧快照:
现在我有了数据,它需要被清理。
清理数据
清理数据分为两步。首先,我想只保留必要的信息。这意味着公寓的大小、离市中心的距离和价格是一个简单的数字(不需要其他符号或字符)。
第二,我删除了没有价格的公寓或没有实际价格的公寓(有些列为每月 1 美元,有些列为每月 10,000 美元,等等)。).
下面是用来清理数据帧的代码。
这里有个小提示:对于那些不知道的人,我们在蒙特利尔用一种奇怪的尺度来描述公寓的大小。
1 1/2 :一个房间,一个独立卫生间。更广为人知的是工作室。
3 1/2 :包括一个独特的客厅、卧室和厨房。更广为人知的是一居室公寓。
之后每增加一个房间,通常是一间卧室。所以 4 1/2 是两居室的公寓。
这是最终清理后的数据框的快照,它包含了 5 月 28 日在 Kijiji 上搜集的总共 3238 个公寓列表。
分析数据
公寓挂牌的平均价格是每月 1394 美元。根据蒙特利尔公报,2019 年该市的平均租金为每月 1080 美元。可租的和已租的之间的巨大差价!这是价格分布图。
import seaborn as sns
sns.set(font_scale=1.2)
sns.distplot(df['price'], color="red", axlabel='Prices ($)').set(title='Distribution of Prices')
如你所料,在这种类型的部门中,分布是向右倾斜的。绝大多数房源都是价格在 900 美元到 1,600 美元之间的公寓,但也有一些超过每月 3,000 美元。
现在让我们来看看城市里可供出租的公寓类型。
令人震惊的是,97.8%的房源都是一居室、二居室或三居室公寓。这说明了这个城市目前面临的租房危机的一个主要问题。对于买不起房子的 5 口之家来说,找房子真的成了问题。对于那些正在寻找一个工作室并且不想为一个完整的一居室公寓付钱的人来说,这也是一个挑战。
我们按户型来看一下均价。
plot1 = df.groupby('size')['price'].mean().plot(kind='bar', figsize= (10,5), color='salmon',title='Average Price by Size')
plot1.set_xlabel("Size",fontsize=14)
plot1.set_ylabel("Price ($)",fontsize=14)
plot1.title.set_size(16)
回到我刚刚提出的观点,工作室并不比一居室公寓便宜多少(1070 美元对 1174 美元)。供应不足可能是价格如此之高的原因。对于更大的公寓,我们看到了类似的情况,因为平均 5 间卧室以上的公寓每月 3407 美元,比平均 4 间卧室的公寓高出约 1000 美元。有点让你在生第四个孩子之前想一想!
以下是每种类型公寓每间卧室的价格比率:
- 工作室:1070 美元
- 单卧室公寓:1174 美元
- 双卧室公寓:780 美元
- 三居室公寓:560 美元
- 4 卧室公寓:576 美元
- 5 间卧室以上的公寓:681 美元
最好的价值似乎来自于租一个 3 或 4 卧室的公寓,这对于任何想要和平和安静的人来说显然不是理想的。不过,另一种选择要贵得多(在一套三居室公寓中,一个工作室和一个房间之间的额外租金每年超过 5000 美元)。
面对如此高的价格,人们将不得不搬到离市中心更远的地方,那里的租金应该更便宜。这是根据离市中心的距离列出的平均价格。
plots=sns.lineplot(x=df["distance_center"], y=df["price"], color='red').set(title='Price by Distance to Downtown')
我们确实看到了一个明显的趋势,离市中心越远,公寓就越便宜,除了 9 公里以外。这可能是因为距离市中心约 9 公里的地方是 Petite-Italie、Villeray 和 Mont-Royal 等社区,都是非常理想的居住场所。
现在让我们把它们放在一起。这是一张热图,按照到市中心的距离和面积显示了公寓的价格。
some_flats = df[(df['price']<3000) & (df['size']!= 7.5)]
heat = some_flats.pivot_table("price", "size", "distance_center")
sns.heatmap(heat).set(title='Price Heatmap')
再说一遍,数据很清楚。我们看到大公寓或工作室的供应不足,因为经常在离市中心一定距离的地方找不到一个房源(地图上的白色矩形)。
结论
在我看来,从提供的数据中可以得出三个结论:
- 在蒙特利尔,一居室或两居室的公寓仍然随处可见,价格相对正常(与其他类型的公寓相比)。
- 小型或大型公寓(工作室和 4 间以上卧室)的供应似乎明显不足,这可能会推动价格上涨,尤其是在靠近市中心的地方。
- 最好的价值来自于租一个 3 或 4 卧室的公寓,因为小的或大的会更贵。
非常感谢你的阅读!
参考
https://Montreal gazette . com/news/local-news/mayor-addresses-housing-crisis
使用数据科学在波士顿 Airbnb 上进行您的下一次旅行
预订 Airbnb 前的三个重要问题——位置、房型和价格
肖恩·帕沃恩在摄影工作室拍摄的照片
介绍
奥斯顿是美国马萨诸塞州的首府和人口最多的城市。它的经济、文化、历史和教育每年吸引成千上万的游客。我一直渴望去这个美丽的城市旅行,并最终在今年三月制定了我的计划。然而,一个意想不到的全球性疫情把我锁在纽约,推迟了我的计划。待在家里后,我一直在用数据科学技术计划下一次去 Airbnb 波士顿的旅行。我认为将数据科学融入旅行计划会更科学、更有趣。如果你感兴趣,你也可以把这个博客看作是你下一次波士顿之旅的一个有趣的、或许有见地的指南。
我将使用的开放数据集来自这里的和 2020 年 6 月 10 日编译的。原始数据集包括 3440 个房源,Airbnb 在波士顿 25 个社区的 16 个特征。在本帖中,我将为你提供你会关心的三个主要问题的数据可视化和机器学习解决方案:地点:哪些地区你有更多的选择或者你更有可能留在波士顿 Airbnb?房间类型:什么类型的房间最受欢迎?价格:影响价格的重要特征是什么?你能预测一下波士顿 Airbnb 的价格吗?
初步数据可视化
首先,我使用 seaborn 查看配对关系。它提供了 9 个有用的数字特征的一般信息和模式。
图一。
一些有见地的观点(查看图 1。):
- 纬度:从南 42.25 到北 42.40,波士顿 Airbnb 的房源数量增加。
- 经度:从西-71.15 到东-71.00,波士顿 Airbnb 的房源数量增加。
- 每月的评论数和评论数有正相关关系。
然后我应用了 Spearman 关联热图(图 2。)来回顾 9 个特征之间的相关性。
图二。包含 9 个特征的 Spearman 关联热图
一些有见地的观点:
- 纬度与价格(r=0.31)和经度(r=0.30)正相关。
- 每月的评论数和评论数呈正相关(r=0.44)。
- 可用性 365 和计算的主机列表计数正相关(r=0.25)。
此外,为了便于分析,我还处理了异常值,删除了价格高于$500 的行,虚拟化了房间类型中的特性,并排除了次要的房间类型(图 3。):酒店房间,合租房间。
图 3。
因此,新的 Spearman 关联热图具有 11 个特征(图 4。)应该更准确。
图 4。包含 11 个特征的 Spearman 关联热图
最后,更重要的一点:
- 价格和住宅类型:整栋住宅/apt 与价格正相关(r=0.67)。包间与价格负相关(r=-0.66)。整个住宅/公寓的平均价格高于私人房间的平均价格(将在后面显示)。
2。纬度与价格正相关。随着纬度从南到北的增加,Airbnb 的价格可能会趋于增加。
3。每月的评论数和评论数是正相关的。
4。每月的点评次数和点评次数与最低夜数(主机要求)负相关。
地点:哪些地区你有更多的选择或者你会更有可能留在波士顿 Airbnb?
图 5。显示波士顿 25 个不同社区的 Airbnb 列表数量。
Airbnb 最多的前 5 个街区是多切斯特、市中心、牙买加平原、罗克斯伯里和 Back Bay。
图 5。波士顿不同社区的 Airbnb 房源数量
图 6。显示了波士顿各个社区中 Airbnb 的比例。
看看这个。值得注意的是,与其他社区相比,多切斯特的 Airbnb 比例更高,为 12%。
图 6。
图 7。一张密度图显示了 Airbnb 在波士顿的分布。最亮的区域有最多的 Airbnb。你也可以在图 8 中查看波士顿 Airbnb 的实际地图。
我发现波士顿 Airbnb 在经度从西-71.08 到东-71.06 和纬度从南 42.34 到北 42.36 高度密集。
图 7。
图 8。来自 Airbnb 内部的
在图 9 中仔细观察它们。波士顿 25 个不同社区的 Airbnb 散点图。经度和纬度表示在 x 轴和 y 轴上。
图 9。
如果你想知道哪些社区更有可能找到你的 Airbnb,图 10 显示了前 5 个社区及其位置。会给你的计划提供有用的信息。
图 10。
房间类型:什么类型的房间最受欢迎?
图 11。显示,考虑到房源数量,整个住宅/公寓和私人房间是最适合的房型。
图 11。
如果你考虑最短住宿时间,见图 12。显示 91、1 和 2 的最低夜数(东道主要求)可能会给旅行者更多的选择。
图 12。
如果你看图 13。和图 14。,你会发现有大约 576 个 Airbnb 房源在 365 天内都不可用(要么非常受欢迎,要么永久关闭)。
有趣的是,在所有 365 天中,还有大约 452 个 Airbnb 房源可供选择。
图 13。
图 14。
接下来,让我们回顾一些关于不同房间类型的统计数据
图 15。显示旅行者倾向于在共享房间比在私人房间和整个家庭/公寓停留更长时间。
图 15。
图 16。和图 17。两者都证实,私人房间和整个家庭/公寓的平均评论数高于合租房间和酒店房间。
确认可能表明整个家庭/公寓和私人房间是您选择的热门房间类型。
图 16。
图 17。
最后,如图 18 所示。按房间类型显示一年中的平均可用天数。
共享房间有一个低得多的 131.94 天的可用性。但它只有 16 个列表。因此,数据会有偏差,不应被视为受欢迎程度的决定性因素。
与酒店房间相比,私人房间和整个家庭/公寓在一年中的可用天数较少。尤其是整个家庭/公寓的可用天数比酒店房间少 30 天。所以我们大概可以假设整个 home/apt 更受欢迎。
图 18。
价格:影响价格的重要特征是什么?你能预测一下波士顿 Airbnb 的价格吗?
在处理了离群值、哑变量、缺失值之后,我利用 3357 个观测值和 11 个变量建立了三个模型:线性回归、套索回归和随机森林。响应变量是价格。
图 19。
同时,我发现包房的平均价格大约是 81.22 美元。整个住宅或公寓的平均价格要高得多,约为 189.38 美元。
从测试数据集来看,波士顿 Airbnb 的实际平均价格约为 147.85 美元。根据测试数据集,波士顿 Airbnb 的预测平均价格约为 149.53 美元。同时,预测是建立在随机森林之上的。此外,您还可以在图 20 中查看波士顿 Airbnb 的实际价格与预测价格的分布。
图 20。实际价格与预测价格
模特表演
图 21。
0.549 的 R 平方(R ) 表示随机森林模型最好地解释了响应数据的可变性。40.423 处的平均绝对误差(MAE) 表示随机森林模型在预测和实际观测之间具有较低的绝对差异。这意味着它具有较低的预测误差。显然,随机森林是三种模型中最好的。
图 22。
图 22。显示了套索回归中的系数( alpha=0.1 )。显然,随着纬度、房型、经度的增加,反应变量价格也会增加。反之,房型包间的增加会导致价格的下降。系数的结果也符合我的预期,即位置和房间类型是价格的重要影响因素。
图 23。
图 23。显示了随机森林模型中的要素重要性排名图。房型全屋/apt,经纬度依然是预测价格最重要的特征。有趣的是,在随机森林中,计算出的主机列表计数和主机 id 是更大的影响因素。
图 24。
我还使用 Shapley 值来分析和解释随机森林中预测 Airbnb 价格的预测。
如图 24 所示,Shapley 值图可以进一步显示预测值与目标变量价格的正负关系[1]。
- 特征重要性:变量按降序排列。
- 影响:水平位置显示该值的影响是否与更高或更低的预测相关联。
- 原始值:颜色显示该变量在观察中是高(红色)还是低(蓝色)。
- 相关性:一个高水平的“房型整体家居/ apt”含量对价格有一个高和正的影响。“高”来自红色,而“积极的”影响显示在 X 轴上。同样,“最少住宿天数”与目标可变价格负相关。
图 25。
图 25。是 Shapley 值的简单版本,以降序显示每个变量对模型输出价格的平均影响,并忽略价格的正/负预测。当然,Shapley 值可以用来神奇地解释更复杂的模型,如深度学习。下一次,你可以使用这个算法向你的观众解释你的深度学习模型的黑盒。
结论:
使用数据科学不仅可以帮助做出商业决策,还可以使生活更加有趣和科学。到目前为止,在波士顿 Airbnb 的数据科学中,我将把这些指导应用到下一次波士顿之旅中:
- 地点:哪些地区你有更多的选择或者你更有可能留在波士顿 Airbnb?
让你做决定的前 5 个街区是多切斯特、市中心、牙买加平原、罗克斯伯里和后湾。从地理角度来说,您希望定位波士顿的经度在-71.08°和-71.06°之间,纬度在 42.25°和 42.40°之间。
2.房间类型:什么类型的房间最受欢迎?
一般来说,在房间类型为全屋/公寓和私人房间的情况下,您找到 Airbnb 的几率会更高。将两者进行比较,whole home/apt 在列表和每月平均评论方面的数字更高。《私人房间》在平均最少住宿天数、平均点评次数和 365 天的平均可用天数方面有更高的数字。
3.价格:影响价格的重要特征是什么?你能预测一下波士顿 Airbnb 的价格吗?
Lasso Regression 和 Random Forests 都同意位置(经度&纬度)和房间类型(整个家/apt &私人房间)对预测波士顿 Airbnb 的价格很重要。
很有意思,随机森林中的特征重要性函数和 Shapley 值都表明计算的主机列表数很重要,而在 Lasso 回归中就系数而言贡献为零。
如果你在乎价格,你可能会为你的下一次旅行选择一个包间。否则,从西南到东北,波士顿 Airbnb 的价格往往会增加。
这是我在 Medium 上的第一篇帖子。希望有帮助!我欢迎反馈和建设性的批评。你可以在 LinkedIn 上联系我:https://www.linkedin.com/in/lanxiao12。
在你走之前,可以在我的 GitHub 这里找到代码。快乐编码,快乐生活!
特别感谢 Menoua Keshishian。
参考:
[1]Data man 博士,用数据科学的 SHAP 价值观 (2019)解释您的模型
利用数据科学从公共基因组数据预测新型冠状病毒冠状病毒的起源
关于科学家如何发现蝙蝠可能是冠状病毒疾病 2019(新冠肺炎)的起源的演练。
电子显微镜下显示人体细胞中的新型冠状病毒病毒(黄色)
新型冠状病毒冠状病毒来自哪里?专家认为蝙蝠是病毒的源头。他们是如何得出这样的结论的?
传统上,大多数医学科学家将使用传统的生物信息学工具,如 BLAST 序列比对。然而,在这篇文章中,我将展示我们如何从数据科学的角度分析冠状病毒基因组。具体来说,我们将使用数据科学方法,通过将其基因组序列与感染其他动物(如鸡、牛、鸭和蝙蝠)的其他冠状病毒进行比较,来预测新冠肺炎的起源。基于我们的分析,我们将展示蝙蝠是如何与其他动物相比具有最高的基因组序列相似性的。
数据集
2019 年冠状病毒的基因组序列通过美国国家医学图书馆网站向公众开放(【https://www.ncbi.nlm.nih.gov/】T2 实验室/病毒)。事实上,有一个“更新”提醒,当你访问网页时,它会立即出现在顶部。
新型 2019 病毒在这里被称为新型严重急性呼吸综合征冠状病毒 2 基因组
你会注意到有两种主要类型的病毒基因组序列:核苷酸 a 和蛋白质。这里,我们将具体分析 4 种动物的核苷酸序列,即鸡、蝙蝠、牛和鸭。我们将它们与从感染者身上收集的 2019 年冠状病毒核苷酸序列进行比较。你也可以用这里学到的方法来分析蛋白质序列。
数据收集
这项分析的主要目标是确定病毒的可能来源。在实践中,我们需要扫描新冠肺炎冠状病毒的基因组和所有在动物中传播的病毒。然而,由于计算资源有限,我们将只分析从鸡、蝙蝠、牛和鸭传播的冠状病毒。
首先,让我们从 NCBI 病毒网页点击核苷酸链接,下载新冠肺炎冠状病毒的核苷酸序列。
点击核苷酸链接下载新冠肺炎冠状病毒的核苷酸序列
该网页是自我探索性的使用。你可以观察到在精炼结果过滤器的病毒部分下自动选择了“严重急性呼吸综合征冠状病毒 2”。此外,还有两种不同的序列类型:完成或引用序列。对于本演练,从核苷酸序列类型部分选择完整的序列类型。接下来,点击页面右上角的下载蓝色按钮。基因组序列将作为下载到您的机器上。fasta 文件格式。
一个可以下载冠状病毒基因组序列的网页。选择完整的核苷酸序列类型,并点击下载蓝色按钮下载基因组序列。
点击下一步,选择选项向下所有记录并选择默认选项用于 FASTA 定义行
一旦你下载了序列数据,让我们在你最喜欢的文本编辑器上打开它,看看基因组序列是什么样子的。
MN908947 |严重急性呼吸综合征冠状病毒 2 型分离株 Wuhan-Hu-1|全基因组
attaaaggttatatcttcccaggtaacaaaccaaccaactttcgatcttgtagatct
gttctaaacgaactttaaaatcttaaatctgtgtggctgtcgttcactcggctgcatgcttagtgcact
cacgcagtataattatataatactataatactatattactcgtctattc
您可以观察到第一行以 ' > ' 开头,表示对病毒的单行描述。在撰写本文时,NCBI 病毒数据库中有 34 个新冠肺炎冠状病毒样本。
接下来,让我们下载四种动物(即鸡、牛、鸭和蝙蝠)的冠状病毒核苷酸序列。
为此,从细化结果的病毒部分移除新冠肺炎冠状病毒选项(即严重急性呼吸综合征冠状病毒 2),并改为搜索冠状病毒。冠状病毒是所有在动物中传播的冠状病毒的学名。选择此选项将为您提供医学科学家过去收集的所有类型冠状病毒家族的核苷酸序列样本列表。有趣的是,你可以从搜索结果中看到,第一次收集到冠状病毒的基因组样本是在 1983 年!
你可以先从收集鸡的核苷酸基因组序列开始。鸡的学名是 gallus gallus 。进入提炼结果的主机部分,搜索 Gallus gallus (chicken) 。选择该选项后,搜索结果列表将会更新,您可以再次点击下载按钮下载鸡的完整核苷酸序列。
对剩下的 3 种动物重复这些步骤:1)牛(牛),2)鸭(鸭科),3)蝙蝠(翼手目)。
数据转换
我们的第一项任务是从序列数据 fasta 文件中读取新冠肺炎和其他四种动物的基因组序列,并将它们放到熊猫的数据框架中。为了实现这一点,我们将只需要提取序列字符(例如,attaag),并忽略所有以“>”开头的单行描述。以下代码通过'>'识别每个核苷酸序列,并提取两个'>'符号之间的序列字符。提取的序列字符随后被顺序附加到列表中。该列表包含每种动物基因组的整个字符串。
from nltk.corpus import stopwords
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pddef process_file(filename,target_val):
f = open(filename) #'datasets\\corona-nucleo-chicken-complete.fasta')
lines = ""
s1 = list()
step = 0
term = 0for line in f:
line = ''.join(line.split())
if line.startswith(">") and step==0:
line = line.split('>',1)[0].strip()
step = step + 1if line.startswith(">") and step>=1: #and step>=1:
line = line.split('>',1)[0].strip()
s1.append(lines)
lines = ""
step = step + 1
term = 0
lines = lines + line
序列的数字表示
接下来,我们需要从包含序列字符的字符串中生成特征。由于序列被表示为一系列字母字符,我们需要将序列字符分割成小的记号。例如,只有 2 个字符的令牌、只有 3 个字符的令牌、只有 4 个字符的令牌等等。此外,我们需要将标记转换成数字表示格式,以便我们可以将它们输入到机器学习算法中进行预测。一种常见的方法是应用单词包数据表示,计算每个令牌的频率/出现次数。它跟踪两个重要信息:序列字符的词汇表和每个标记出现的次数。
为了同时应用 n-grams 和词袋,我们可以使用来自 scikit-learn 机器学习库的计数矢量器 API。
count_vect = CountVectorizer(lowercase=False, ngram_range=(2,4),analyzer=’char’)
X1 = count_vect.fit_transform(s1)
在本演练中,我们将只设置最小的 n 元文法来开始从 2 到 4 序列的令牌的。例如,2-gram 最多包含 2 个字符(例如 at)、3-gram(例如 ACG)和 4-gram(例如 ACTT)。
def generate_ngrams(s1):
count_vect = CountVectorizer(lowercase=False, ngram_range=(2,4),analyzer='char')
X1 = count_vect.fit_transform(s1)
lcount = list()
lcount = []
for i in s1:
count = len(i)
#print(count)
lcount.append(count)count_vect_df = pd.DataFrame(X1.todense(), columns=count_vect.get_feature_names())
count_vect_df=count_vect_df.apply(lambda x: x / lcount[x.name] ,axis=1)
return count_vect_df
数据标记
一旦数据被转换成数字值作为特征,我们将需要为它们添加标签以进行预测。
df1 = process_file(‘datasets\\corona-seq-chicken.fasta’,”chicken”)
df2 = process_file(‘datasets\\corona-seq-duck.fasta’,”duck”)
df3 = process_file(‘datasets\\corona-seq-cattle.fasta’,”cattle”)
df4 = process_file(‘datasets\\corona-seq-bat.fasta’,”bat”)
在这里,您可以看到每个 fasta 序列文件都被分配了自己的标签(即鸡、鸭、牛和蝙蝠)。标注在数据转换过程结束时完成。
def generate_ngrams(s1):.....
count_vect_df = generate_ngrams(s1)
count_vect_df[‘target’] = target_val
return count_vect_df
如果您做的一切都正确,您应该能够以 pandas dataframe 格式的数值查看所有的特性。
来自鸡核苷酸序列的样本特征
探索性分析
有了以数据帧格式表示的所有序列,我们可以探索我们的冠状病毒数据集的%分布。我们可以观察到,我们的数据集的 64%是鸡的核苷酸序列,31%来自蝙蝠,剩下的 4%和 1%分别来自牛和鸭。
import matplotlib.pyplot as plt
plot_size = plt.rcParams[“figure.figsize”]
plot_size[0] = 8
plot_size[1] = 6
plt.rcParams[“figure.figsize”] = plot_sizedf7[‘target’].value_counts().plot(kind=’pie’, autopct=’%1.0f%%’)
建立预测模型
我们现在准备通过将我们标记的核苷酸数据集应用于机器学习算法来建立预测模型。在这种情况下,我们将使用 XGBoost 梯度增强算法来构建我们的预测模型。
from sklearn.model_selection import train_test_split from xgboost import XGBClassifier
from xgboost import plot_importance
import xgboost# create a train/test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=7, shuffle=True)model = XGBClassifier()
model.fit(X_train, y_train)
使用我们建立的模型,我们可以进一步分析,以确定核苷酸序列的哪些区域对确定哪些序列属于哪些动物具有最大的影响因素。我们可以观察到“CWG”、“AAAY”和“AAC”是区分 4 种动物基因组的前 3 个序列区域。
新冠肺炎冠状病毒的数据转换和文本表示
接下来,我们需要将新冠肺炎核苷酸序列文件加载到我们的程序中,以便进行预测。
与动物冠状病毒序列相似,我们需要对新冠肺炎冠状病毒进行数据转换和数值表示。n-gram 和词袋算法都需要应用,但附加步骤也是必要的。我们将详细解释这些步骤。
首先,我们将从 Fasta 文件中加载新冠肺炎冠状病毒的核苷酸。
cov = process_file(‘datasets\\corona-covid-19.fasta’,“COVID-19”)
cov
我们可以看到有 34 个新冠肺炎样本和 409 个特征。但是,请注意,特征的数量与训练特征不匹配。
因为我们要做预测(而不是建立模型),所以我们可以去掉目标标签
cov = cov.drop(‘target’, axis=1)
不幸的是,新冠肺炎产生的特征不会与我们动物的其他冠状病毒 100%相同。我们可以观察到新冠肺炎冠状病毒的特征数量是 409,这与动物冠状病毒的 1786 个特征相比要少得多。由于这种不匹配,在数据集与我们的预测模型完全兼容之前,我们需要执行另外两种类型的数据转换。
- 动物冠状病毒中有哪些特征是新冠肺炎冠状病毒所没有的?
这意味着发现动物核苷酸序列中的特征,但它们不存在于新冠肺炎冠状病毒中。一旦我们发现这样的特征,我们将需要在预测数据集中将其填充为“未知”。
mc = X_train.columns.difference(cov.columns)
mc
我们可以看到,“AAAM”、“AAR”和“AAAY”是我们在冠状病毒中发现的一些特征,但它们不存在于新冠肺炎冠状病毒中。
索引(['AAAM ',' AAAR ',' AAAY ',' AACK ',' AACM ',' AACR ',' AAGK ',' AAGR ',' AAGW ',' AAGY ',… 'YTWC ',' YW ',' YWA ',' YWAT ',' YY ',' YYC ',' YYCT ',' YYT '],dtype='object ',length=1392)
需要添加这些功能,以便与我们的训练数据集相匹配。因此,我们可以将值填充为未知。由于特性必须是数字形式,我们将使用“-999”数值来表示“未知”。
for newcol in mc: cov[newcol]=-999
2。新冠肺炎有哪些其他类型动物冠状病毒从未有过的新特征?
最重要的是,我们还需要找到存在于新冠肺炎但不存在于训练数据集中的特征。一旦我们发现这样的特征,我们将需要移除这些特征,以使它们与我们的训练数据集相匹配。
rf = cov.columns.difference(X_train.columns)cov = cov.drop(rf, axis=1)
我们可以看到,“AWGC”、“CS”、“CST”和“CSTG”是新冠肺炎病毒的一些新的核苷酸区域,这些区域以前在四种动物的冠状病毒中从未存在过。
索引(['AWGC ',' CS ',' CST ',' CSTG ',' GCS ',' GCST ',' GGAW ',' STG ',' STGG ',' TGCS ',' TRCC ',' TTYA ',' TYAC ',' WGCT'],dtype='object ')
在从预测数据集中移除所有这些特征之后,我们的预测数据集最终与我们的训练数据集相匹配。
现在,我们预测的数据集有 1786 个特征与训练数据集完全匹配
关键时刻
我们现在可以预测新冠肺炎冠状病毒的可能来源了!下一步是预测我们收集的 34 份新冠肺炎冠状病毒样本的可能来源。使用 XGBoost predict API 可以很容易地做到这一点。
model.predict(cov)
数组(['bat ',' bat ',' bat ',' bat ',' bat ',' T12 ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' T14 ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',' bat ',
基于预测值,我们可以看到,我们的模型预测所有36 个样本为蝙蝠。甚至没有一个样本被预测为其他动物。为了进一步分析这一点,我们将使用 XGBoost 的 predict_proba API 来获得每个预测的概率。
print(model.classes_)
similarities = model.predict_proba(cov)
np.round(similarities, 3)[‘bat’ ‘cattle’ ‘chicken’ ‘duck’]
array([[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041],
[0.957, 0.001, 0.001, 0.041]], dtype=float32)
基于预测概率,我们可以清楚地看到,bat 的预测概率极高,预测值为 0.957。这意味着新冠肺炎病毒有 95.7%的可能性来自蝙蝠,而只有 4.1%的可能性来自鸭子。病毒来自牛或鸡的概率只有 0.1%。因此,我们可以有力地得出结论,蝙蝠是 2019 年新型冠状病毒的可能起源。
将我们的结果与 BLAST 进行比较
正如本文开头提到的,BLAST(基本局部比对搜索工具)[1]是典型的标准方法,允许科学家比较核苷酸或蛋白质序列的差异。这个节目在这里公开:https://blast.ncbi.nlm.nih.gov/。从网站上,你可以上传你的新型冠状病毒序列为 FASTA 格式,该程序将根据其数据库查询你的序列,以找到任何与你的查询匹配的相似序列。与我们的方法不同,BLAST 没有对特征应用任何预测模型,而是使用启发式搜索算法。我们的预测方法的一个主要好处是,它可以发现更多的洞察力,并且可以发现标准启发式搜索通常无法发现的隐藏模式。
参考
[1] R. M .凯西(2005 年)。“BLAST 序列有助于基因组学和蛋白质组学”。商业智能网络。
利用数据科学研究美国的经济不平等
亨妮·斯坦德在 Unsplash 上的照片
数据新闻
我们如何利用公共数据来分析和理解美国黑人社区面临的挑战?
在我的上一篇文章中,我使用 BLS 和美国的人口普查数据创建了一个仪表板,以快速分析每个县按种族和行业划分的美国失业情况。本文将继续这个话题,研究一些受新冠肺炎影响最严重的县,并试图描绘出一幅围绕这些社区的更好的画面。
我的目标是找出主要是经济困难的黑人县,并找出他们之间的共性(或差异)。
我将这个过程分为四个步骤:
- 查找感兴趣的县进行比较(使用美国数据仪表板)
- 通过媒体和政策(通过网络搜集和 NLP)将各县联系起来
- 量化问题(使用开放数据源)
- 承认方法中的偏差和改进
查找感兴趣的县进行比较:
我首先查看了失业率最高的县。看起来密歇根州是受灾最严重的,内华达州和加利福尼亚州的部分地区,然后是南部的部分地区。
BLS 报告的截至 4 月底的失业率
利用人口普查数据,我们可以得出以下黑人人口最多的地区。
比例是美国人口普查局报告的各县黑人人口的%
对比了这两张图表后,下面是我选定的县的列表:
- 密西西比州图尼卡——31.7%的失业率
- 密西西比州霍姆斯——28.9%的失业率
- 密西西比州奇克索——31.4%的失业率
- 阿拉巴马州达拉斯——20.9%的失业率
- 阿拉巴马州威尔科克斯——22.8%的失业率
- 阿拉巴马州朗兹——26%的失业率
自上次衰退以来,威尔科克斯和霍姆斯的失业率一直很高(即使全国失业率降至 3.9%),平均收入也是六人中最低的。下图显示了各州各行业的就业依赖情况。
澄清一下,最上面的蓝色是贸易、运输和公用事业。
对于这两个州来说,政府部门和贸易/运输/公用事业部门在这个州占据了更高的比例。
通过媒体和政策将各县联系起来
现在,我们已经对各县的经济状况有了一个大致的了解,让我们看看还能收集到哪些其他数据源。了解我们正在研究的国家的历史/背景很重要,所以让我们从了解该地区的媒体报道和公共政策开始。为了实现前者,我依赖于典型的 NLP 预处理/可视化方法。我使用谷歌新闻查询格式([https://news.google.com/rss/search?q={](https://news.google.com/rss/search?q={)}
)从搜索“county _ name+‘economy’”中搜集了 100 篇文章,然后使用 TF-IDF ( Scikit-learn
)对每篇文章中的单词进行分词(使用nltk
删除停用词和词条)。
然后,我对所有的文章进行了主成分分析(Scikit-learn
),并用 600 篇文章绘制了前两个组成部分。对于那些不熟悉 PCA 的人来说,可以把它看作是文章中单词/主题的变化。对于所有的交互链接,你必须下载 html 文件。
你可以在这里观看这个剧情的互动版本。
看起来一般的经济报道都很相似,但是奇克索在第一部分有更多的变化。主要的分类集中在“疫情”和“失业”上。
我在另一个时间段(2008 年至 2019 年)进行了同样的分析,得到了以下更分散的结果:
奇克索去了左边,其他人大多居中或右边
然后我在 PCA 组件上也做了 TSNE。TSNE 很难简洁地解释,但可以把它想象成在高维空间中展开复杂的非线性关系(就像展开一个水果卷,但你可以在某种程度上根据颜色撕开并重新排列)。如果你有超过 50 个功能,TSNE 就不能很好地工作。
在这种情况下,类似于五氯苯甲醚的结果,链接此处
从互动情节的快速扫描来看,集群集中在“赌场”、“农业”、“贸易交易”、“移民”和“民权”。
TSNE 的左上方是关于黑带、无家可归者和学生的文章。中间是内战以来的民权和财富/不平等。右下角是主要涉及特朗普、贸易和工厂的文章。
通过对其中一些文章的后续阅读,我发现阿拉巴马州的三个县是黑带的一部分,这意味着它拥有该地区丰富的黑色表土。该地区也有阿拉巴马州一半的奴隶人口集中在那里的历史。1965 年有一次从塞尔玛到蒙哥马利的历史性游行。塞尔玛在达拉斯县,蒙哥马利(阿拉巴马州的首府)就在朗兹县的外面。
对于公共政策,我首先研究了选民分布和公共问题。在最近的选举中,我使用了 B allotpedia 和 P olitico :朗兹、达拉斯、威尔科克斯、图尼卡和霍姆斯是民主党人,奇克索是一个关键县(倾向共和党)。我想知道这是否解释了为什么奇克索媒体集群如此偏离正轨。
在我们深入研究之前,先快速概述一下美国的立法系统:正如每个州都有两名参议员和多名众议员代表美国参众两院一样,每个区都有一名参议员和众议员代表州参众两院。
为了找出这六个县所面临的问题,我去了地区立法者发起的议案。阿拉巴马州和密西西比州的选区划分如下:
亚拉巴马州
朗兹、达拉斯和威尔科克斯都是第七区的一部分。Proncey Robertson(共和党)是这个区的代表,Sam Givhan(共和党)是参议员。
密西西比河
图尼察和霍姆斯是第二区的一部分,奇克索来自第一区。2 区代表是尼克·贝恩(共和党),参议员是迈克尔·麦克伦登(共和党),1 区代表是莱斯特·卡彭特(共和党),参议员是大卫·l·帕克(共和党)。
我使用 billtrack50 来查看他们如何在州议会中发起法案,并使用与前面的法案摘要相同的 NLP 方法对它们进行聚类。总共有 140 个提案。
互动剧情此处
我没有发现 TSNE 特别有用,但如果你喜欢,你可以在这里查看一下。账单摘要上的 Gensim 关键字按出现次数为我们提供:
此外,各州的赞助法案似乎有些分歧:
互动剧情这里
阿拉巴马州的议案主要集中在枪支和犯罪上。下面是按地区(7 是阿拉巴马州,1 和 2 是密西西比州):
我对(0,0)中心附近的账单最感兴趣,因为这是我们在各区(县)之间最具共性的地方。
中心的主题:围绕消防员和其他基础设施、对许多选民的医疗/健康援助(在校学生的免疫接种、向不孕不育者提供怀孕补助等。).
第 2 区(图尼卡,霍姆斯):大多倾向于左派,涉及许多儿童问题,如送孩子、收养、儿童抚养、给年轻人发色情短信,以及烟草和尼古丁方面的毒品问题。
第 1 区(Chickasaw): 有各种各样的政策,左侧的主题非常相似(以及一些共同赞助法案的重复),但增加了一些道路/驾驶员法案(驾照/DUI 法案/高速公路和州际公路)。在中心,有一些关于教育的法案(教师收入,阅读障碍,利益冲突和税收条款)。扩散到右侧的都是表彰或祝贺运动队和教练赢得各种奖项和比赛并将其记入官方记录的法案。
第 7 区(达拉斯、朗兹、威尔科克斯):有很多关于枪支(特别是在校园内非法燃放枪支、隐蔽携带)和犯罪(添加到受管制物质清单中,使向警察撒谎成为犯罪)的法案。但靠近中心的法案大多是围绕州长、市政当局、董事会和司法部门的修正案(修改权限、条款、文件等)。还有一些税收和投资法案。
我们现在有了媒体讨论和公共政策关注的背景。我也想访问市政厅和地区会议记录,看看社区提出了什么问题,但是这些问题不容易找到。
我们的最后一步是看看我们是否能发现这些问题实际上是如何使用开放数据源来解决的。
量化问题:
美国的每个州通常都有指定的机会区,有些州还进一步发展了评分系统。伯克利已经在加州的一个地区(比一个县还小)做了一个很好的例子,见下图:
https://belonging.berkeley.edu/tcac-2020-preview
使用 OpportunityDb 我发现阿拉巴马州有 158 个机会区,密西西比州有 100 个。每个县有 0 或 1 个区,都属于“低收入社区”类别。我喜欢伯克利大学给他们的研究打分,所以我仔细研究了他们的方法,以了解我可以把什么转移到这些县。这里就不细说了,这些是他们用的指标:
2020 年机会映射方法
他们使用的一些有趣的数据点是“成人教育”、“工作接近度”和“学生贫困率”。他们还使用了一种叫做“CalEnviroScreen 3.0 指标”的东西,这也是一个有趣的研究。
密西西比州的公开数据主要集中于 GIS,而阿拉巴马州的则集中于州支出。他们的 web 界面不同于旧金山、芝加哥和纽约等地,这些地方似乎都有相同的 web 模板和相似的数据集。
对于密西西比州,我寻找了年龄分布和任何与学校/孩子相关的数据。他们从门户网站上得不到任何真正有用的东西,所以我只能依靠 census.gov。它已经过时了,但却是一个起点。看起来人口大多是中年家庭。
https://www2 . census . gov/geo/maps/cong _ dist/CD 113/CD _ based/ST28/CD 113 _ ms02 . pdf
https://www2 . census . gov/geo/maps/cong _ dist/CD 113/CD _ based/ST28/CD 113 _ ms01 . pdf
我还发现第二区和第一区的高中毕业率分别为 77.6%和 81.2%,而全国平均水平为 88%。
学区数据很有用,因为它能让孩子和他们的父母一起了解情况。首先,媒体对学校的报道(covid 之前)使用与之前相同的方法:
互动这里
左下方的聚类包括犯罪、盗窃和枪击。中间/顶部集群涵盖了贫困、失败和隔离,右侧涵盖了儿童殴打/引诱和儿童死亡(也是一系列根据标题看似与学校无关的犯罪)。
我利用国家教育统计中心(NCES)来尝试了解当地学区面临的挑战。您可以在此找到图尼察县学区,并搜索其他学区。我开始使用 bs4 和 Selenium 收集美国最大的 100 个学区以及我们的 6 个县学区的数据。清理完就剩下 70 个学区的数据( csv 链接此处)。
这是我收集的变量的df.hist()
图:
这是只有%变量的plotly
箱线图。在交互式版本中,你可以将鼠标放在圆点上来查看学区名称。
互动此处
密西西比州的三个区都有 97%以上的医疗保险覆盖率,这最初让我感到惊讶。然而,一些统计数据引起了我的注意,这里是这些箱线图的放大图:
- “拥有宽带互联网的家庭”:图尼察 64.6%,霍姆斯 37.2%,奇克索 45.9%。
- "女户主,无丈夫在场":图尼察为 53%,霍姆斯为 72%,奇克索为 36%。
- "学士以上学位":图尼察父母中有 9.3%,霍姆斯父母中有 9.6%,奇克索父母中有 4%。
- 图尼察 34.2%,霍姆斯 53%,奇克索 49.1%
作为参考,你可以将这些统计数据与加州这个非常富裕的县进行比较。92.3%上网,88%已婚夫妇,27.2%英语说得很好,79.9%父母本科以上学历。
在县一级很难找到儿童虐待/忽视/药物使用,所以我不能在那里找到任何东西。
对于阿拉巴马,我寻找犯罪和学校安全方面的数据。他们的开放数据库专注于国家支出,像这样划分(在 2019 年 10 月至 2020 年 6 月期间)。有大量的点击和页面标签,考虑到所有的数据都应该放在一个 excel 表中(如果你排除了所有收款人的支付日期),这真的很难处理。
http://open.alabama.gov/Checkbook/Category/
大部分支出是“补助和福利”,如果我们点击进入,我们会看到一些顶级类别:
- 医疗福利 65.41 亿美元
- 市/县学校系统 37.82 亿美元
- 退休和养老金福利 24.64 亿美元
- 拨款 13.36 亿美元
- 个人福利 10.13 亿美元
然后我查看了 37.82 亿美元中有多少拨给了达拉斯、朗兹和威尔科克斯学区。
- 达拉斯 2050 万美元
- 朗兹 980 万美元
- 威尔科克斯 1000 万美元
我要指出的是,这些并不真正与学区预算的规模成比例,这就是数据定义如此重要的原因。如果任何人知道更多关于学区预算和国家资助,请与我联系!但是在浏览达拉斯地区2020-2021的预算提案时,我发现
我想知道预算的减少是否与学校安全法案有关——尽管从外部来看这很难做出结论。阿拉巴马州似乎没有像和这个来自 NYPD 的这样的投诉或逮捕数据。
让我们将这些学区与密西西比州的学区进行比较。这是总体分布,所以你不用向上滚动:
- “拥有宽带互联网的家庭”:达拉斯 64%,朗兹 49.4%,威尔科克斯 49.2%。
- “女性户主,无丈夫在场”:达拉斯为 44%,朗兹为 67%,威尔科克斯为 58%。
- “学士以上学位”:达拉斯有 14.5%的家长,朗兹有 5.9%的家长,威尔科克斯有 6.5%的家长
- " %贫困线以下":达拉斯 31.8%,朗兹 45.6%,威尔科克斯 44.8%
承认方法中的偏差和改进
我能够深入了解这些以黑人为主的县的社区所面临的一些问题,但不幸的是,我无法将这些问题与失业直接联系起来,或者如何利用支出来解决这些问题。因此,我不会试图做出任何结论。
我在这里的目的是使用典型的数据科学库,提供一组分散的数据集背后的故事,便于我们理解。有几项我想提一下:
- 我们正在研究的很多东西都是相互关联的,即使有看似“直觉”的解释,这也可能是危险的。
- 有大量的定量数据,但其中大部分过于分散或更新不一致(即使是在开放的数据库中),无法快速收集和使用。这在粒度级别上也变得更加难以处理。
- 一个更全面的研究媒体的方法可能是找到关于每个国家历史的顶级书籍,然后运行 gensim 对它们进行总结(或者找到 100 本这样的书并进行 NLP 聚类)。这个过程只有和它的来源一样好。
- 研究黑人占少数且失业率高的县也是值得的,尽管数据越细越难找到。农村 vs 城市也是一个很好的细分来研究。
- 我们观察到的一切都在动态变化,使用收集到的数据时间越长,做出假设和决策的可靠性就越低。
- 我在这里没有太多的比较分析(例如,一些对照组/基线,或像加州研究那样的规模)。下一步可能是深入到我们研究和比较的县附近,但这需要更深入的城市规划和立法知识,因为我们开始处理的不可见变量会成倍增加。
- 下一次,我可能会更多地关注每个县就业所依赖的行业,而不是社区,因为这些数据更新得更加频繁和可靠。这是更标准的方法,所以这次我不想采用。
数据科学是各种模型的强大工具,但同样的技能集在提供更清晰的问题和数据描述方面也非常强大。没有固定的方法来做到这一点,这就是为什么我的方法与你习惯阅读的相比可能感觉粗糙。但至少,这是一种在 Kaggle 竞赛和预制 Jupyter 笔记本之外练习技能和学习的方式!
这里表达的所有观点都是我个人的,并不代表我所属的那些人的观点。