TowardsDataScience-博客中文翻译-2021-二十一-

TowardsDataScience 博客中文翻译 2021(二十一)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

在 PyTorch 构建卷积 VAE

原文:https://towardsdatascience.com/building-a-convolutional-vae-in-pytorch-a0f54c947f71?source=collection_archive---------2-----------------------

用神经网络生成新图像?

深度学习在计算机视觉中的应用已经从图像分类等简单任务扩展到自动驾驶等高级任务——神经网络揭示的最迷人的领域之一是图像生成。

随着生成对抗网络(GANs)在内容生成方面的能力和成功,我们经常忽略另一种类型的生成网络:变分自动编码器(VAE)。本文讨论了 VAE 的基本概念,包括体系结构和损失设计背后的直觉,并提供了一个简单卷积 VAE 的基于 PyTorch 的实现,以基于 MNIST 数据集生成图像。

什么是 VAE?

自动编码器

为了理解 VAE 的概念,我们首先描述一个传统的自动编码器及其应用。

图一。传统自动编码器的示意图。

在传统的计算机科学中,我们总是试图找到最佳的方法来将某个文件(无论是图像还是文档)压缩成更小的表示形式。自动编码器是一种特殊类型的神经网络,具有用于降维的瓶颈层,即潜在表示:

其中 x 为原始输入, z 为潜在表示,x’为重构输入,函数 fg 分别为编码器和解码器。目标是最小化重构输出 g(f(x)) 和原始 x 之间的差异,以便我们知道较小尺寸的潜在表示 f(x) 实际上保留了足够的特征用于重构。

除了满足降维的需要,自动编码器还可以用于去噪等目的,即,将扰动的 x 输入自动编码器,并让潜在表示学习仅检索图像本身,而不检索噪声。当去噪自动编码器用深度网络构建时,我们称之为堆叠去噪自动编码器。

在简单的词语中添加“变化”

在对自动编码器进行简短描述后,人们可能会问,如何改变这种网络设计来生成内容——这就是“变化”概念的来源。

当我们正则化自动编码器,使其潜在表示不会过度拟合到单个数据点,而是整个数据分布时(关于防止过度拟合的技术,请参考本文),我们可以从潜在空间执行随机采样,从而从分布中生成看不见的图像,使我们的自动编码器变得“可变”。为此,我们将 KL 散度的思想融入到我们的损失函数设计中(关于 KL 散度的更多细节,请参考这篇文章)。下面几节将深入介绍使用 PyTorch 从头开始构建 VAE 的具体过程。

计算环境

图书馆

整个程序仅通过 PyTorch 库(包括 torchvision)构建。在评估结果时,我们还使用 Matplotlib 和 NumPy 库进行数据可视化。这些库可以按如下方式导入:

资料组

为了简化演示,我们从最简单的视觉数据集 MNIST 训练了整个 VAE。MNIST 包含 60000 幅训练图像和 10000 幅测试图像,显示从 0 到 9 的手写数字字符。

硬件要求

由于 MNIST 是一个相当小的数据集,因此可以纯粹在 CPU 上训练和评估网络。然而,当在其他更大的数据集上使用时,建议使用 GPU 进行计算。为了确定是否使用 GPU 进行训练,我们可以首先根据可用性创建一个可变的设备 CPU/GPU:

网络体系结构

图二。VAE 的示意图。

我们的 VAE 结构如上图所示,它包括一个编码器,一个解码器,在两者之间的潜在表示被重新参数化。

编码器— 编码器由两个卷积层组成,后面是两个独立的全连接层,两个层都将卷积后的特征图作为输入。两个全连接层在我们预期的潜在空间的维度上输出两个向量,其中一个是均值,另一个是方差。这是 VAEs 和传统自动编码器之间的主要结构差异。

重新参数化— 通过计算平均值和方差,我们随机抽取一个可能出现在给定分布中的点,该点将被用作潜在表示,并输入解码阶段。

解码器 —该解码器类似于传统的自动编码器,具有一个全连接层,后跟两个卷积层,以基于给定的潜在表示来重建图像。

我们可以使用 PyTorch 构建 VAE 结构的上述组件,如下所示:

培训程序

损失函数

VAE 的核心概念之一是其损失函数的设计。简而言之,我们试图设计这样的损失,即它基于给定的图像重建得很好,但也适合整个分布,而不是仅过度适合图像本身。因此,VAE 损失是以下因素的组合:

二进制交叉熵(BCE)损失— 计算重建图像与原始图像的像素间差异,以最大化重建的相似性。BCE 损失的计算方法如下:

其中 xᵢx'ᵢ 分别表示原始和重建图像像素(总共 n 个像素)。

KL-散度损失— KL 散度衡量两个分布的相似性。在这种情况下,我们假设分布为正态分布,因此损耗设计如下:

这是通过我们预测的潜在向量(大小为 m )中每个值的平均值和 sigma 来计算的。

培养

下面的代码显示了培训过程。我们将批量大小设置为 128,学习速率设置为 1e-3,总的时期数设置为 10。

注意,为了简单起见,我们在这里只进行纯训练。然而,建议在每个时期之后,我们在测试集上计算有效性,以防止在训练期间的任何过度拟合。当验证损失达到最低点时,也应该保存检查点。

(英)可视化(= visualization)

训练之后,我们可以用下面的代码来可视化结果:

图 3。重建结果。左边是原始图像,右边是生成的图像。

从可视化中我们可以看到,我们已经成功地在原始图形的基础上生成了略有不同的数字图形,这就是 VAE 最终要实现的目标!

结论

所以你有它!希望这篇文章给你一个基本的概述和指导,告诉你如何从头开始构建你的第一个 VAE。完整的实现可以在下面的 Github 资源库中找到:

https://github.com/ttchengab/VAE.git

感谢您坚持到现在🙏!我会在计算机视觉/深度学习的不同领域发布更多内容。一定要看看我的另一篇关于一次性学习的文章!

使用 Plotly 和币安 API 构建加密货币仪表板

原文:https://towardsdatascience.com/building-a-cryptocurrency-dashboard-using-plotly-and-binance-api-352e7f6f62c9?source=collection_archive---------1-----------------------

轻松跟踪您的投资组合

资料来源:unsplash.com

根据 CoinMarketCap 的数据,截至目前,全球加密货币市场价值超过 1.5 万亿美元。最近,几家银行和信用卡公司批准将加密货币作为其金融产品之一,这预示着加密市场的光明前景。在过去的几年里,越来越多的人开始交易加密货币,全球有许多支持不同加密货币的交易所。在本文中,我们将关注币安交易所,它是当今世界上排名第一的 T2 交易所。它支持几乎所有的加密货币,并在许多国家可用。

在本文中,我们将讨论如何从币安 API 访问数据,并用 Plotly 创建一个仪表板。

下面是我们将要讲述的内容:

  • 如何设置币安 API
  • 如何使用币安 API 获取数据
  • 用 Plotly 构建仪表板

1.如何设置币安 API

币安提供两种 API 访问:1)实际的币安 API 和 2)测试币安 API。

1.1 设置实际的币安 API

实际 API 提供了对您实际账户的直接访问,使用此 API 进行的任何交易都将反映到您的实际账户中。这意味着我们在使用这个 API 时需要小心。

首先,你需要在https://www.binance.com/en/register?ref=AG3W30LV注册币安(如果你没有账户的话)(这个链接包括我的推荐代码,会给你 10%的交易费折扣。更多细节可以在https://www.binance.com/en/activity/referral找到

注册后,您将被要求(或者您可以从安全设置中完成)设置双重身份验证以获得额外的安全性。我会推荐选择 Google Authenticator。

设置好 2FA 后,您可以转到“设置”下的“API 管理”选项卡。您将被要求为您的 API 键提供一个标签(当您有多个键与一个帐户相关联时,这将非常有用)。

为您的 API 键提供一个标签后,单击 create API。您将被要求再次认证,然后您将能够看到您的“API 密钥”和“秘密密钥”这是你唯一一次看到它,所以把你的钥匙复制到某个安全的地方。默认情况下,这些键将被授予以下访问权限,这些权限是可以更改的。

我们将使用实际的 API 和测试 API 键来理解如何使用它们。为此,我们不想搞乱我们的实际帐户,所以我们将把实际的 API keys 权限改为只读。

我们将把实际的 API 密匙保存到下面提到的secret.cfg文件中(记住,永远不要共享或发布你的secret.cfg文件)

1.2 设置测试币安 API

测试币安 API 为您提供了与实际 API 交互时相同的感觉。我建议从这个(交易)开始,直到你确信你的应用程序运行良好。

首先,你需要在https://testnet.binance.vision/登录(目前,只有 GitHub 支持登录)

登录后,点击“生成 HMAC_SHA256 密钥”,你将再次被要求提供一个密钥标签。提供标签后,点击 generate,您应该能够看到您的 API 键。把它们复制到某个安全的地方。此外,请阅读主页上关于测试 API 的所有详细信息。

现在,我们将修改secret.cfg文件以包含测试 API 键,如下所述

我们已经成功设置了实际和测试 API 密钥,并将其保存到secret.cfg文件中。在下一节中,我们将关注使用这些 API 键获取数据。

2.如何使用币安 API 获取数据

2.1 安装 python-币安库

币安没有提供与 API 交互的 python 库,但是有一个非常著名的第三方库叫做python-binance,我们将用它来与 API 交互。

安装python-binance

$ pip install python-binance

2.2 获取账户信息

默认情况下,您将在您的测试帐户中以不同加密货币的形式获得一些余额,我们将在这一部分使用测试 API(因为我不想分享我的帐户信息)。另外,python-binance不能访问测试 API,所以我们需要更改端点 URL。

下面是获取测试帐户信息的代码

从上面的输出可以看出,它显示了一些重要的东西,比如 accountType、balances、permissions 等。

现在,让我们得到 ETH 平衡。

你可以用python-binance库做很多事情,详细的文档可以在这里找到。

2.3 获取历史数据

根据我的观察,测试 API 不提供真实的历史数据;相反,它提供虚拟数据。因此,为了访问真实数据,我们将使用实际的 API 和实际的 API 键。

获取从最早可用日期(币安)到现在的 ETH 价格

上述输出代表了币安 API 文档中提到的以下参数

将输出转换为数据框并保存为 CSV 文件

2.4 获取实时数据

我们可以使用币安的 WebSocket 来传输实时数据。这是你怎么做的

现在,要停止数据流并关闭 WebSocket

看起来我们已经找到了获取数据和信息的不同方法。你可以用python-binance库和币安 API 做很多其他的事情。我鼓励你看一看这个这个。现在,我们可以在下一节构建一个 Plotly 仪表板了。

3.用 Plotly 构建仪表板

在本节中,我们将使用 Plotly 构建一个仪表板,该仪表板将实时跟踪我们的测试帐户组合,并根据实时流数据更改帐户总价值。

这是我们最终的仪表板的样子(不要介意美观,因为您可以在以后更改它)

GIF:最终仪表板

如您所见,我们在控制面板中包括了以下功能。

  • 指标-USDT 的投资组合总价值
  • 指标-BTC 的投资组合总价值
  • 指标- BNB/USDT 换算
  • 饼图-投资组合分布(在 USDT)
  • 条形图-令牌分布

让我们看看代码。

首先,我们将导入所有需要的库。

其次,我们将读取我们的密钥,建立连接,并获得帐户信息。

第三,我们将定义一些函数来处理流数据并基于实时数据计算指标。

第四,我们将开始流式传输数据。

第五,我们将定义我们的仪表板布局、图表并托管它

就这样,你应该能够跟踪你的测试账户投资组合。您可以使用实际的密钥轻松地为实际帐户设置它,而无需更改端点 URL。

这就把我们带到了本文的结尾。你可以访问这个 GitHub repo 中的所有代码。请随意标记或收藏,以供将来参考。

最近开始用 Python 和机器学习写算法交易系列。你可以在下面找到第一条。

https://pub.towardsai.net/algorithmic-trading-with-python-and-machine-learning-part-1-47c56706c182

更多文章关注我。请随时在 LinkedIn 上联系我。谢谢大家!

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

为对象检测构建自定义 tf.data 管道

原文:https://towardsdatascience.com/building-a-custom-tf-data-pipeline-for-object-detection-246f5a01d60?source=collection_archive---------25-----------------------

从数据生产到模型优化的完整演练

图片来源于 Carol M. Highsmith 的“阿拉斯加管道”,国会图书馆公共领域

建立有效的输入管道是训练深度神经网络的重要性能优化。除此之外,数据供应甚至需要良好的结构和透明性,以避免成为培训中的错误来源。虽然目前许多开发都在 PyTorch 上运行,但如果您计划使用边缘设备或想要在具有数 TB 数据的大型训练集群上运行,Tensorflow 仍然是一条不错的道路。这就是带有 tf.data.Dataset 的 tf.data API 的用武之地:拥有一个高效的管道来为您提供训练数据,这些数据是通用的,可以扩展到数据中心维度。虽然,将它与您自己的数据一起使用仍然会令人沮丧,因为您可能会碰到现有教程的一些边缘(我碰到过很多)。

这是我给你的建议,也是我从中最大的收获:不要试图使用任何捷径——使用成熟的管道,因为它应该被使用,事情将会非常容易使用和理解。这就是我为您编写本教程的原因——提供一个端到端的示例,其核心很简单,但利用了 tf.data API 的大部分概念(没有使用任何在名为 cats/dogs 的目录结构中用特殊文件名编写文件的快捷方式)。

我们使用以下内容:

  • 3000 张图片
  • 每个图像包含三种颜色之一的对象(一个点)
  • 每个点被放置在图像上的随机位置

当然,我们希望根据给定的图像来预测点在哪里以及它有什么颜色。简单的任务,但是标签可以用目录结构来表示吗——我认为不可能。我是否希望将标签保存在 CSV 文件中,以便再次与基于 UUID 文件名的图像进行匹配——我尝试过,但并不有趣。

我希望我的数据以数据集记录的形式存储图像数据和标签信息,并希望这些数据流入我的模型中进行训练。

如果你也喜欢这个想法,请继续阅读。

在本文中,我主要关注相关代码,以使基于 tf.data 的管道工作。您将在连接的笔记本中获得完整的锅炉板代码:https://gist . github . com/FHermisch/1a 517121 ECB 11 d0e 0206226 AC 69915 ee

创建图像

“模拟”生成测试数据的大型复杂设置(如数据扩充、机械土耳其等)。),我选择用一些随机数据生成图像,并使用这些。因此,不会有从一些互联网来源加载的“随时可用”的设置。我们为测试和验证数据创建尽可能简单的图像。对我们来说重要的是,我们使用的数据将具有与自定义图像分类和对象检测任务相当的结构复杂性。如前所述,我们的任务是检测图像中矩形的位置以及矩形的颜色。

我们可以只用纯黑的背景。或者——为了有更多的视觉吸引力,使用一些美国宇航局的图像,因为这些图像通常非常令人印象深刻,而且大多是公共领域使用的。

NASA/科里休斯顿公共领域

Datatype/shape of base image, web base image: 
uint8 / (112, 112, 3) ,  uint8 / (112, 112, 3)

我们继续 NASA 的图像。注意,两个图像都是 112,112 大小,RGB 颜色通道作为“最后通道”(Tensorflow 样式)。

现在,让我们在这个基础上放置一些随机的东西。我们构建了一个函数,将一个给定颜色的对象放在图像上,并返回该对象被放置的位置。这是我们的简单解决方案,生成一些“物体检测”图像。

在“placeobject”函数中,我们初始化要放置在图像上的对象:

  • 构建一个 numpy 数组,数组的大小为对象应有的大小
  • 乘以颜色值,将每个像素转换为所需的颜色

为了在图像上放置物体,我们选择一个随机的相对 y 和 x 位置。现在,我们可以计算绝对像素位置,并将对象数据复制到基础图像中。

让我们看一看:现在在我们的基本图像上有一个对象,并且打印的位置与图像上的对象位置相匹配。

NASA/科里休斯顿公共领域

Position 0.9109465116914442 0.13220923689802044

我们现在有了一种方法,可以将具有某种颜色的对象放置在我们的基本图像上,并准确地知道我们将该对象放置在什么位置。位置和颜色将是我们以后检测的标签/基础。包含该对象的图像将是我们的训练数据。让我们通过随机选择颜色来自动生成大量的图像和标签。

让我们先生成 5 张图片并打印出标签。

Generated data (112, 112, 3) 0.8395090863371965 0.9547828984929204 ObjColorTypes.SPECIAL
Generated data (112, 112, 3) 0.5531254931489215 0.4768844126516376 ObjColorTypes.GREEN
Generated data (112, 112, 3) 0.47239734539676304 0.23156864975331592 ObjColorTypes.RED
Generated data (112, 112, 3) 0.539600313491926 0.14757914149460205 ObjColorTypes.SPECIAL
Generated data (112, 112, 3) 0.6978451492963156 0.5689848230831969 ObjColorTypes.RED

我们还应该对数据有一个直观的看法。后来,我们想训练一个人工智能从这些图像中学习一些东西——所以对人工智能好一点,在你把它喂给人工智能之前自己看一下:你能看到你想让人工智能看到的东西吗?!

NASA/科里休斯顿公共领域

写入 TFRecord 数据

首先,我们设置一个类,它包含了写这些记录所需的所有东西。原谅我,因为我是在 OO 范式中长大的,拥有类和实例化的对象对我来说很自然。您也可以在这里使用带有部分参数或任何其他参数的函数。

import randomclass QTFRec():

    def __init__(self, fname):
        self.fname = fname
        self.tfwriter = tf.io.TFRecordWriter(self.fname)

    def _bytes_feature(self, nparr):
        return tf.train.Feature(
            bytes_list=tf.train.BytesList(value=[nparr.tobytes()]))def _float_feature(self, nparr):
        return tf.train.Feature(
            float_list=tf.train.FloatList(value=nparr))def write_record(self, image, poslabel, collabel):feature = {
            'image_raw': self._float_feature(
                image.ravel()),          
            'img_shape': self._bytes_feature(
                np.array(image.shape, dtype=np.uint8).ravel()),
            'poslabel': self._float_feature(
                poslabel.ravel()),
            'collabel': self._float_feature(
                collabel.ravel())
        }tf_example = tf.train.Example(
            features=tf.train.Features(feature=feature))
        self.tfwriter.write(
            tf_example.SerializeToString())

    def close_record(self):
        self.tfwriter.flush()
        self.tfwriter.close()

在我们的类中,我们构建了一个 TFRecord writer,它将用于以 TFRecord 格式将数据写入磁盘。TFRecord 是一种以顺序方式存储数据示例的方法。其中每个例子由一组特征组成。
我们将‘write _ record’函数中的特征定义为一个字典。在这种情况下,我们有图像数据、图像上对象的位置、对象的颜色,并且我们还想存储图像数据的形状。
TFRecord 允许为特征选择特定的数据类型。对于我们的特性,我们使用字节列表和浮点列表。

现在,我们将实际数据放入特性中:我们从 numpies 中的数据开始,这非常方便。我们把它们平铺开来。ravel()')并将它们放入各自的功能构造函数中。您可能想知道为什么我们将图像数据存储为浮点数?这是一个设计选择(哎呀!—稍后阅读此设计选择的效果),因此我们已经在 0 <=val<=1 range, so we can later feed this directly to the training. You will see that there are a couple of places suitable for data conversions — if you have saved it here as uINT8 you can later convert it in the feeding pipeline.
中存储了带有颜色值的图像数据。我们需要的最后一件事是关闭 writer,以确保所有内容都已写入磁盘。我们添加了一个 close_writer 方法来完成这项工作(小插件:您可以将其更改为与 python 的‘with’语句一起工作)。

就是这样。还有一件事我们稍后会谈到:我们目前没有将验证数据从训练数据中分离出来。有人可能认为会有一个简单的“split_dataset”函数,我们可以在以后使用,但没有数据集。这是可以理解的,因为 tf.data 是为处理数十亿条记录而构建的,不能简单地以某种方式拆分数十亿条记录。我们稍后将扩展我们的类,以实际写入两组记录。但是让我们先继续训练数据…

我们创建了一个 QTFRec 实例,并构建了另一个小类来封装它,并提供了一个正好适合我们的数据生成回调的函数。好了,这个管用。现在,我们可以为我们的训练集生成合理数量的记录。

qtfr = QTFRec(fname)
tfrsaver = TFRsaver( qtfr)
generatedata(baseimg, 3000, tfrsaver.savedata)     
qtfr.close_record()

让我们使用这个数据集来设置一个输入管道来训练一个模型。接下来的步骤相当于使用 tfds 的教程,例如来自 tfds 的 MNist。我们将重点关注需要一些转换逻辑的部分,以使我们的数据适应模型训练需求(我们之前也可以用更适合的方式编写数据,但让我们这样做是为了向您展示可以为您的数据和管道放置自定义转换需求的位置)。

建造管道

再次打开写入的数据集很容易。

tfrds = tf.data.TFRecordDataset(TRAINSET_FNAME)

我们可以使用在线文档,但我喜欢使用内置的“帮助(tfrds)”来查看我得到了什么类型以及它提供了什么功能的便捷方式。

不出所料,TFRecordDatasetV2。
值得注意的功能:

  • 应用'
    ,在其上映射一个转换函数,并构建一个转换管道:看起来不错——我们稍后会用到它
  • 对于研究结构和内容来说,这听起来很方便
  • 其他流水线功能,批处理/混洗等。
  • 从管道末端取出一定数量的元素

让我们试着看看会发生什么:

for npelem in tfrds.as_numpy_iterator():
    print( type(npelem))
    barr = np.frombuffer(npelem, dtype=np.byte )
    print( barr.shape)
    break

让我们看看它会打印出什么。

<class 'bytes'>
(150629,)

我们得到了一个 150629 的数字形状,这应该是大约 112x112x3 = 37632?等等,发生什么事了?好了,我们将图像数据存储为浮点数(出于方便),因此我们将每个颜色值从一个字节(uint8)扩展到 4 个字节(float32)。我们真的应该改变这一点——所以要经常看看你的数据。想想,明明很清楚却被我错过了。我把它作为一个例子留给你。为了方便起见,有更好的方法来浪费你的磁盘和 IO,然后存储 4 倍的大小。

让我们继续。我们从数据集中得到一个张量,我们可以选择将不同的变换映射到这个集合。我们构建了一个 DataRead 类,作为上面的 writer 类的对等物。

class DataRead():
    def __init__(self):
        self.feature_description = {         
            'image_raw': 
                tf.io.VarLenFeature( dtype=tf.float32),
            'img_shape': 
                tf.io.FixedLenFeature([], tf.string),
            'poslabel': 
                tf.io.VarLenFeature( dtype=tf.float32),
            'collabel': 
                tf.io.VarLenFeature( dtype=tf.float32)            
        }def prepdata( self, fmap):
        pmap = tf.io.parse_single_example(
                fmap, self.feature_description)imgraw = tf.sparse.to_dense(pmap['image_raw'])
        imshape =  tf.io.decode_raw(pmap['img_shape'], tf.uint8)
        poslabel = tf.sparse.to_dense(pmap['poslabel'])
        collabel = tf.one_hot( tf.cast( 
            tf.sparse.to_dense(pmap['collabel']), tf.uint8),  tf.constant(3))[0]

        return (tf.reshape( imgraw, tf.cast(imshape, tf.int32)),
                tf.concat( [poslabel,collabel], axis=-1))

我们首先要解析张量,因为里面的所有东西都是字节。因此,为不同的元素设置一个 feature_description 字典。我们的“prepdata”函数稍后将被映射到管道。我们解析单个条目,以便能够访问指定记录中的每个特性。这是为数据添加额外转换代码的好时机。我们必须进行转型:

  • 将原始图像数据重新整形为结构化的形状:
    我们首先解码形状,并使用它将图像数据重新整形为其原始的 112x112x3 形状
  • 将标签数据放在一个张量中:
    我们将位置标签与 colortype 连接在一起,之前我们将其转换为一键表示

现在,我们得到了 1x112x112x3 的漂亮图像数据,用于将目标/地面真相的 a 标签训练为 1x5。

输入管道只是将一堆转换映射在一起。映射我们刚刚构建的解析函数。映射缓存函数。在每一次完整迭代后洗牌。从单个管道项目中形成批次。启动一些预取,以便总是在需要时为培训准备好批次。

datar = DataRead()traindat = tfrds.map( 
    datar.prepdata, 
    num_parallel_calls=tf.data.experimental.AUTOTUNE)
traindat = traindat.cache()
traindat = traindat.shuffle(
    1000, seed=1234, reshuffle_each_iteration=True)
traindat = traindat.batch(
    BATCHSIZE, drop_remainder=True)
traindat = traindat.prefetch( 
    tf.data.experimental.AUTOTUNE)

由于结果仍然是数据集,我们再次使用 as_numpy_iterator 函数。现在,数据以我们转换后的格式弹出,我们可以轻松地可视化图像数据和标签。

NASA/科里休斯顿公共领域

[0.602948  0.2850269 0\.        0\.        1\.       ]

一个非常简单的物体检测

本文的重点不是如何进行对象检测。所以我们没有进入下一步的细节:
建立一个有一些回旋的模型,最后有一些完全连接的层。输出只是一个 sigmoid,它将被训练以匹配我们的标签(这是非常基本的,但适用于这个极其简化的示例)。

Model: "functional_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 112, 112, 3)]     0         
_________________________________________________________________
conv2d (Conv2D)              (None, 112, 112, 16)      448       
_________________________________________________________________
re_lu (ReLU)                 (None, 112, 112, 16)      0         
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 38, 38, 16)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 38, 38, 32)        4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 38, 38, 32)        0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 13, 13, 32)        0         
_________________________________________________________________
flatten (Flatten)            (None, 5408)              0         
_________________________________________________________________
dropout (Dropout)            (None, 5408)              0         
_________________________________________________________________
dense (Dense)                (None, 128)               692352    
_________________________________________________________________
re_lu_2 (ReLU)               (None, 128)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 64)                8256      
_________________________________________________________________
re_lu_3 (ReLU)               (None, 64)                0         
_________________________________________________________________
batch_normalization (BatchNo (None, 64)                256       
_________________________________________________________________
dense_2 (Dense)              (None, 5)                 325       
=================================================================
Total params: 706,277
Trainable params: 706,149
Non-trainable params: 128
_________________________________________________________________

用 SGD 作为优化器,MeanSquaredError 作为 loss 进行编译。

运行它…哦,等等…我们没有验证数据!

Epoch 1/10
46/46 [==============================] - 1s 15ms/step - loss: 0.1976
Epoch 2/10
46/46 [==============================] - 1s 15ms/step - loss: 0.1801
Epoch 3/10
46/46 [==============================] - 1s 14ms/step - loss: 0.1655
...

我们确实需要一个验证集来获得任何有意义的见解。让我们改变写数据的代码。我们希望保留一定比例的图像用于验证,并将它们保存到另一个数据集。
我们需要添加代码来初始化(并在稍后关闭)一个额外的编写器。在“write_record”中,我们添加了一个随机步骤,该步骤生成一个介于 0 和 1 之间的均匀随机数,并根据与提供的验证分割百分比的比较,将生成的数据发送给训练或验证。

在这里,我们随机分割数据,但这也是放置一些更“智能”逻辑的地方,例如,确保在人脸检测场景中,验证集将只包含根本不在训练集中的人。这种分割逻辑应该接近数据的生成,并且不能在以后或在训练期间完成。

我们再次运行并为训练和验证提供文件名以及 20%分割百分比。

qtfrec = QTFRecVal(FNAME, 0.2, FNAMEVAL)
tfrsaver = TFRsaver( qtfrec)
generatedata(baseimg, 3000, tfrsaver.savedata)     
qtfrec.close_record()

运行以生成 3000 幅图像(20%将放入验证集)。

为验证建立第二个管道(我们不必打乱验证)。

tfvalrds = tf.data.TFRecordDataset(FNAMEVAL)
valdat = tfvalrds.map( 
    datar.prepdata, num_parallel_calls=tf.data.experimental.AUTOTUNE)
valdat = valdat.cache()
valdat = valdat.batch(BATCHSIZE, drop_remainder=True)
valdat = valdat.prefetch( tf.data.experimental.AUTOTUNE)

生成、编译和运行 100 个时期。

...
Epoch 98/100
38/38 [==============================] - 1s 19ms/step - loss: 0.0020 - val_loss: 8.0567e-04
Epoch 99/100
38/38 [==============================] - 1s 20ms/step - loss: 0.0022 - val_loss: 8.2248e-04
Epoch 100/100
38/38 [==============================] - 1s 18ms/step - loss: 0.0021 - val_loss: 7.9342e-04

看看损失是如何演变的。这里有一句关于准确性的话:我们不能使用现成的准确性函数,因为它们不能代表我们所做的。如果您想要一些准确性,您必须提供自己的函数:例如,检查是否预测了正确的颜色值,以及目标位置和预测位置之间的欧几里德距离是否低于某个阈值。

它能预测吗?

我会说是的——大部分是。颜色值预测得非常好,但我预计位置检测会执行得更好…
好消息:您现在可以使用 tf.data 管道为您的检测构建自己的自定义示例了。

NASA/科里休斯顿公共领域

Groundtruth label:      [0.5074 0.7342 0\.     0\.     1\.    ]
Prediction from model:  [0.5104 0.7335 0.0157 0.0145 0.9913]

完整的笔记本可作为一个要点:

https://gist . github . com/FHermisch/1a 517121 ECB 11 d0e 0206226 AC 69915 ee

使用 Python 中的 Plotly-Dash 构建房价数据仪表板

原文:https://towardsdatascience.com/building-a-data-dashboard-for-housing-prices-using-plotly-dash-in-python-7aca9c49592c?source=collection_archive---------32-----------------------

查看美国城市房价、收入数据和人口的仪表板示例

照片由罗恩·霍维尔Unsplash 上拍摄

以简洁、易于理解的方式向您的受众传达数据项目的结果可能非常困难——当我准备向受众展示数据时,我花费了比我愿意承认的更多的时间来考虑颜色、标记样式、图表格式等。我记得在我作为一名科学家的职业生涯早期,我使用 Excel 制作图表,并思考…为什么为我的数据集选择一种颜色如此困难?如今,数据仪表板似乎风靡一时,这是有原因的——它们可以帮助你以一种美观、易于理解的交付方式传达你的分析结果。虽然我仍然发现自己在制作仪表板时考虑了所有上述的设计因素,但所有这些决定都感觉容易多了。

我不能确切地告诉你为什么,但我发现房子和房价令人着迷。也许这是我多年来一直坚持的 HGTV 饮食习惯😆在考虑我下一篇数据科学文章的主题时,这似乎是一个很好的起点。

虽然我完全赞成尽可能简单地解释事情,但这毕竟是一个编码博客,所以我将在下面解释我创建这个仪表板的工作流程。如果你想跳过技术细节,直奔仪表盘,点击这里

仪表板中科罗拉多州丹佛市历史和预测房价的时间序列图。图片作者。

对于这个项目,我将使用 Plotly-Dash,这是一个用于创建分析数据 web 应用程序的 Python 库。Plotly 是一个数据可视化库,类似于 matplotlib,但允许您制作交互式图形,并将它们集成到 Dash 中。

我首先前往 Zillow 网站下载房价数据——我使用 Zillow 的所有住宅(单户住宅和公寓)的住宅价值指数(ZHVI)数据集作为原始时间序列数据,这些数据着眼于“中档”价格范围内的住宅。Zillow 将“中间层”定义为价值在第 35 至 65 百分位范围内的房屋,中位数在此范围内。我从 Kaggle 下载了收入数据——虽然有些人认为 Kaggle 数据集对于数据科学项目来说过于“干净”,但我还是选择了它,因为我实际上是在组合一些不同的数据集,为仪表板创建我自己的数据集。最后,我调用 Geonames API 来下载每个城市的纬度、经度和人口数据。当我进入 Zillow 数据集时,我发现了许多需要重命名的城市,以便使用 Geonames API。在我看来,清理数据并不是这份工作中最吸引人的部分,但却是一个没有得到足够重视的重要部分。一些城市的收入数据也有很多条目,所以我按照每个城市的平均值将它们分组:

经过一点清理后,我将城市放入一个 Python 列表中,并使用 Geonames API 遍历它们,以迭代方式下载每个城市的纬度、经度和人口。注意,你需要在 Geonames.org网站上注册才能使用他们的 Python API,关键是你的用户名:

有了这些结果,我将人口数据添加到一个 Python 字典中,将城市名作为键,将人口作为值,这样我就可以很容易地确定哪些城市的人口值为零(也就是说,API 不起作用)。我对 API 提取人口数据的成功率进行了快速统计,发现它成功下载了大约 94%的城市的人口数据。我从维基百科手动添加了另外 6%的人口。记住:编码永远不会让你到达目的地。但是在这种情况下,它让我完成了 94%的路程,这节省了我很多时间。编码并不否定对结果进行手动质量控制的需要。

接下来,我对 income 数据集执行了一个左外连接,以将其与 Zillow 数据集合并。这是一个 SQL 概念,意味着 Zillow 数据集的大小将保持不变。如果 Zillow 数据集中存在某个城市的收入数据,则仅将其添加到该数据集中。如果某个城市没有收入数据,它会用 NaN(不是数字)值填充该列。我还最终确定了在 Dash 中作为数据表使用的数据集:

最后,我还在仪表板上完成了一个用于房价时间序列的数据框架(下面的“df_h”),并在每个城市循环,预测未来两年的房价。我使用了 statsmodels 库中的自回归综合移动平均(ARIMA)模型。对于时间序列数据,这是一个非常好的机器学习算法。如果你对我为什么不使用 Scikit-Learn 来完成这个任务感到好奇,可以在 Github 上查看这个例子。

好吧!我们终于准备好了构建仪表板的所有数据。我是 Jupyter 实验室大多数 Python 开发的忠实粉丝,因为我喜欢在编写代码时能够轻松运行代码。然而,您可能想要切换到某种文本编辑器来在 Dash 中部署您的应用程序——我选择了 Spyder。你可以在 Jupyter 实验室运行 Dash,但我最终更喜欢文本编辑器。

要开始创建应用程序,您需要在计算机上创建一个目录来存储与应用程序相关的所有文件,并且需要在该目录中初始化一个虚拟环境。虚拟环境是您创建的文件夹中 Python 的一个独立实例,您必须重新安装 Python 标准库中未包含的任何库。在您的终端(Mac)中输入以下代码:

$ mkdir housing_dash && cd housing_dash
$ python3 -m venv venv
$ source venv/bin/activate(venv) $ python -m pip install dash
(venv) $ python -m pip install plotly
(venv) $ python -m pip install pandas
(venv) $ python -m pip install gunicorn

将应用程序需要的数据帧添加到这个文件夹中,并在同一个文件夹中创建一个 python 文件(这里的约定很简单,我选择了“app.py”)。此外,您需要在应用程序文件夹中创建以下文件(粗体文本=文件名):

requirements.txt' 您的虚拟环境使用以下版本的库(如果您运行不同的版本,请相应地调整版本):

dash==1.19.0 
pandas==1.2.3 
gunicorn==20.0.4

'runtime.txt' 在您的虚拟环境中运行 Python 版本:

python-3.9.0

’。gitignore' :

venv 
*.pyc 
.DS_Store 
.env

‘过程文件’:

web: gunicorn app:server

如果需要检查 Python 或 Python 库的版本,可以在终端中调用以下代码:

#check Python version
(venv) $ python3 --version
Python 3.9.0#check Pandas version
$ python3
>>>import pandas as pd
>>>pd.__version__
'1.2.3'#check Dash version
$ python3
>>>import dash
>>>dash.__version__
'1.19.0'

好了,这就是文件夹设置。下面是我的完整 Dash 应用程序代码。我导入了上面创建的 csv 文件,布置了应用程序,并创建了“应用程序回调”来增加图形的交互性。应用回调使用您定义的函数,并且任何时候输入参数之一改变(例如下拉菜单,用户查询一个表,等等),回调在你指定的输出上调用函数。注意,在函数和回调函数之间不能有任何空格,函数必须放在回调函数下面的下一行,否则将不起作用。

Dash 在其关键字参数中广泛使用字典和列表,因此在构建 Dash 应用程序时,熟悉这些 Python 概念肯定会有所帮助。

要部署应用程序,建议使用 Git 和 Heroku,尽管还有其他方法来部署您的应用程序,以便任何人都可以查看它。在这一部分,我不会讲太多细节,但是如果你已经做到了这一点,你就已经成功了。 Dash 有关于如何做到这一点的优秀文档,网上有大量资源可以帮助你部署你的应用。即使你对 Python 很有经验,部署你的应用程序也可能是一个令人抓狂的过程。如果您的应用程序成功部署到 Heroku,您可能会在第一次在浏览器中加载应用程序时收到一条错误消息,感觉就像这样:

功劳:生活大爆炸理论。

我可以提供一些建议:

  • 仔细检查你的 requirements.txtruntime.txt ,确保你用来开发代码的版本与你的。txt 文件。你的 Python 版本也必须完全像这样写:python-3.x.x ',
  • 三重检查您的代码,并在您的终端中运行:
heroku --tail
  • 深呼吸,耐心点。你能行的😃

当我在做这个项目时,我无法停止思考《瑞克和莫蒂》中外星人试图通过欺骗杰瑞与他们一起开发应用程序来接管地球的那一集😆

鸣谢:Giphy/RickandMorty.com

下面是我使用该应用程序的视频演示和一些截图。时间序列有一个下拉菜单,显示数据框架中每个城市(总共 913 个)的房价与年份的关系,其中大约一半城市有两年的房价预测。此外,当您筛选数据表时,地图和图形将会更新。您可以输入诸如' > 300000 '或'<100000’, and the table will accept multiple queries:

Video by author.

Image by author.

Image by author.

And there you have it! That is how you build an app using Dash in Python. One of my favorite things about data science is how interdisciplinary it is — this could be financial, medical, sales, engineering, or some other kind of data, but the data portion of the project will approximately be the same, regardless of the discipline.

Thanks for reading!

Martin

引用之类的内容

[1] Zillow,2021,Zillow 房屋价值指数数据(ZHVI),所有房屋,时间序列,原始中间层:https://www.zillow.com/research/data/

[2]金橡树研究集团,2017 年,美国家庭收入统计:

https://www . ka ggle . com/goldenoakresearch/us-household-income-stats-geo-locations

2021 年构建数据平台

原文:https://towardsdatascience.com/building-a-data-platform-in-2021-b759f6470426?source=collection_archive---------2-----------------------

如何构建一个现代化、可扩展的数据平台来支持您的分析和数据科学项目。

目录:

站台

整合

数据仓库

转化

演示文稿

运输

关闭

你知道有句谚语说得好——“给猫剥皮的方法不止一种”

作为一个自豪的猫父母,这对我来说是一个艰难的比喻,但当涉及到 21 世纪的数据时,这种情绪从未如此准确。

诚然,你可以用电子表格、python 脚本或终端命令解决大多数数据问题,但当你开始考虑规模、速度和一致性时,问题很快就会出现。此外,数据领域的一系列工具和流程抑制了协作并推动了工具集的专业化,而不是促进对统计、数据建模和有效可视化等核心数据科学概念的深入理解。

幸运的是,一个一致的框架已经开始出现。构建数据平台的新方法一部分是自己动手,一部分是替我做。它包括将托管服务缝合在一起,并在您的平台中设计足够的灵活性来预测未知。如果操作正确,这种现代基础设施可以让数据专业人员专注于解决复杂的数学和科学问题,而不是简化围绕管理和文档的陈旧流程。

站台

这种构建现代数据平台的方法中的一个关键概念是模块化。尽管有聪明的营销和销售活动,目前还没有一个供应商或技术拥有整个数据领域。因此,了解每个组件是为您的特定项目拼凑正确解决方案的关键…组件如下:

  • 来源
  • 综合
  • 数据仓库
  • 转换
  • 介绍会;展示会
  • 运输

综合

我们假设源组件是显而易见的。数据源有多种形状和大小,集成层应该足够灵活,能够考虑到所有的数据源。

在这个组件的 DYI 频谱上是流行的工具,例如 Airflow ,许多公司用它来构建健壮的端到端数据管道。其他 Apache 产品,如 Kafka 提供了一种更基于事件的数据集成方法,可以与 Airflow 结合使用,以进一步扩展定制数据管道。

托管服务在集成领域已经走过了漫长的道路。除了前面提到的 Apache 项目的企业级版本,如天文学家(气流)和汇流(卡夫卡),这个领域还有几个领导者提供灵活性,但足够固执己见,以有意义的方式帮助加速开发。从基于事件的角度来看, 是不可否认的领导者,而five tran等解决方案已经成为更传统的基于 ETL/ELT 的数据集成的实际解决方案。

数据仓库

可能现代数据平台中最模糊也是最关键的组件是数据仓库。这部分是因为 SQL Server、Postgres 和 MySQL 等传统数据库技术仍然非常有效。然而,像雪花这样的新来者的统治地位已经为未来突出了清晰的道路。基于云的数据仓库,如 Snowflake、RedShift 和 BigQuery,在存储、访问和管理数据的方式上比它们的前辈提供了许多好处。

无论您根据自己的情况选择哪种基于云的数据仓库,将该仓库划分为不同功能层的概念仍然是一个不断发展的概念。最佳实践开始出现,建议您的数据仓库至少有两个不同的“区域”;一个存储原始/非结构化数据,另一个存储规范化/转换后的数据。这个话题有很大的争论空间,但是拥有这两个不同区域的总体好处是能够有效地管理不断变化的规则,将原始数据转换为可消化的信息。

转换

如果数据仓库组件是现代数据堆栈中最关键的部分,那么转换组件是最容易被忽略的部分。大多数项目倾向于将转换分散到业务工具、可视化平台和电子表格等人工制品中,但是集中管理数据转换是成熟数据组织的一个明显特征。

随着 ETL 和 ELT 之间的斗争,有效管理转换的想法开始在主流中显现。虽然这看起来有些迂腐,但对一个常见缩写中的字母进行简单重组,开创了一个全新的时代,允许非数据人员参与构建数据产品。这种范式转变也赋予了数据治理和 MDM 等概念新的生命,这些概念严重依赖于业务涉众的输入。

从 DIY 的角度来看,Python 是至高无上的,因为它可以通过像 SQLAlchemy 和 Airflow 这样的模块轻松管理简单的基于 SQL/任务的转换,并且是为由 TensorflowScikit-learn 和更多其他模块驱动的更复杂的机器学习转换量身定制的。

从托管服务的角度来看,很难找到比 dbt 更好的产品。虽然所有主要的云提供商(AWS、微软、谷歌)都有自己的一套工具来管理他们平台上的转换,但从平台不可知的角度来看,dbt 似乎走在了前面。

介绍会;展示会

到目前为止,我们讨论的大多数组件都是纯基础设施。虽然大多数数据分析师、工程师和科学家将使用来自数据仓库和转换组件的内容,但大多数最终用户在访问表示层的仪表板之前不会看到任何内容。

坦率地说,表示组件是一个庞大的类别。谁说一个 Jupyter 笔记本,同样包含了变身元素,就不能同时作为演示工具?毕竟, Databricks 已经非常成功地运用了这一策略,因为它们似乎即将成为 20 年代的下一个大型科技公司 IPO 之一。

从历史的角度来看,可视化工具已经主导了转换和表示类别,像 LookerPower BIQlikSisenseTableau 这样的工具证明了管理转换和构建漂亮的可视化并不是互斥的概念。

随着数据堆栈的不断发展,我相信表现空间的冠军将是那些加倍重视可视化能力而较少依赖变革能力的人。随着组织集成更多数据源和数据量呈指数级增长,在表示层管理转换不仅会带来挑战,还会产生定义不清的信息和不准确的分析。

运输

考虑到交通因素,这种方法变得非常现代。在过去,终端用户通过仪表盘和外部分析工具消费信息是可以接受的,但越来越明显的是除非数据专业人员能够将他们的洞察力带回记录系统,否则他们的工作可能会毫无意义。

有时被称为“嵌入式分析”,数据传输的概念很简单,因为它弥合了数据工具和记录系统(即客户关系管理、营销自动化和客户成功平台)之间的差距。然而,很少有托管服务能够有效地解决这一问题,即使是已经出现的托管服务也仍在积极开发中。像 HightouchCensusSyncari 这样的公司似乎是第一批穿墙而过的公司,并且可能是大多数项目的唯一选择,除非他们拥有大量的开发人员资源和自动化信息交换的经验。

关闭

就在我写这篇文章的时候,数据格局正在发生变化。围绕数据平台可观察性和安全性的概念正在迅速流行,公司正在一夜之间实现解决这些问题。记住这一点,理解灵活性和不可知论是这条信息的主要内容。虽然这将会发生,但我敢打赌,在一个供应商将整个数据堆栈提取到一个统一的平台之前,还需要几年时间。因此,把这个框架带到未来,理解你将不得不改变你的思维,每天接受新的想法。

使用 Python 和 Dash 构建数据故事

原文:https://towardsdatascience.com/building-a-data-story-with-python-and-dash-98ee4933e700?source=collection_archive---------10-----------------------

从数据转向可视化,用更少的资源说更多的话,同时增加一些基本设计的深度。

弗朗西斯科·温加罗摄于佩克斯

“有些书可以浅尝辄止,有些书可以囫囵吞下,有些书需要咀嚼消化;也就是说,有些书只能读一部分;其他人阅读,但不是好奇地;有几本书必须完整地读完,而且要用心去读。”~弗朗西斯·培根爵士

我们绝大多数的数据探索都是相对简单的。我们需要比较两个值,或者我们需要查看我们的数据在上下文中是如何出现的。因此,我们很快在我们选择的笔记本上做了一个条形图或折线图,会意地哼了一声,然后继续我们清单上的下一个项目。

有时候我们需要潜得更深。我们需要从传递的信息中再挤出一点点。我们需要把我们的视觉呈现给其他人,而不是浪费他们的时间。在其他情况下,我们只需要充分利用有限的空间。

无论如何,它要求我们更长久地思考我们正在做的事情。它可能会伴随我们一段时间。

在这篇文章中,我将带你踏上一个小小的旅程,把一个稍微复杂一点的视觉化图像放在一起,讲述一个故事。别担心。虽然我已经使用了关键字“复杂”,这将是有用的。也许不能像直接复制和粘贴那样全合一,但至少可以作为一种机制来构建自己的工具包,也许还能产生一些创造性的想法。

只是为了管理预期,这不是一个完整的应用程序走查。这将是一项艰巨的任务。这是通过我自己的一个特定应用程序,引导您完成整个过程,以获得功能性的最终结果。我们的目标是强调一些我认为在寻找答案的最常见的地方缺失的关键概念。我只希望它能帮助一些人,哪怕只是一点点。

为什么是 Dash?

当我第一次开始用 Python 做数据工作时,我非常喜欢 Matplotlib。这很有意义,也符合我的编程方式。很容易很快就做出一些漂亮的图,可以输出用于其他目的,如出版或发行。有一天,我需要一些东西——具体是什么,我记不清了,但它让我冲了出来。

以前,我在网上旅行时遇到过 Plotly 和 Dash,但并没有太在意。我想把事情做完,而不是花时间去学习另一个库的细微差别。但是这一次不同。介绍快速简单,让我的兴趣达到了顶峰。所以我用 Plotly 蘸了蘸我的脚趾。

我被卖了。在大约三行代码中,我有了一个令人惊叹的(至少对我来说)情节,完成了我所需要的。过了一段时间,我冒险进入 Dash,因为我看到了快速创建自己的仪表盘的好处。

我最初的几次尝试完全失败了。这是一个我力不从心的简单例子。我试图跳过简单和基本,去实现我的复杂和理想。但是,我很快就得到它,并能够为我需要的东西建立一个可用的平台。

Dash 为我提供了一个相对轻量级、响应迅速的平台,不需要大型基础设施或技术管道就能快速获得结果。事实上,它与 Plotly 携手合作是一个意外收获。

我对这个平台的一个抱怨是文档经常缺乏。它有许多跳跃,从非常简单到更高级的中级,中间没有桥梁。追查丢失的东西可能会很有挑战性。就像所有的学习领域一样,答案是从知识守卫者手中夺来的,这是一个值得赢得和奖励的胜利,但也是一个主要的痛苦。

这是我决定把这篇文章放在一起的一个重要原因。

关于这个例子

对一些人来说,这可能是一个深奥的例子,但我讨厌使用陈词滥调,如泰坦尼克号生存或植物学或其他一些尝试和真实的比喻。为此,我使用我自己收集的数据存储中的数据。

作为一个金融迷,我对期货市场有一种特殊的亲切感,尤其是贵金属。然而,作为一个商业香肠,我喜欢看到原材料价格和消费者零售价格之间的相互作用。因此,我的数据包括来自多个分销商的市场数据和商品零售价格,涵盖 90 天的时间。市场数据以 5 分钟为间隔收集,而零售数据以 15 分钟为间隔收集。

市场数据来自一个构造为日期时间、开盘、盘高、盘低、收盘、成交量的表(即相当标准的市场数据格式)。零售数据由日期时间、商品、经销商和价格组成。

在很大程度上,我尽了最大努力来确保我的数据是干净的,所以没有太多的摄取处理。我对数据进行的唯一修改是编写视图,将零售价格时间戳时移至最近的 5 分钟间隔。这允许市场和零售数据表之间的清晰连接。出于分析的目的,这是一个无关紧要的变化。

获取数据

所有的艺术都需要一些原材料。在这种情况下,我们的原材料就是数据。这是通过一个简单的查询从数据库中获得的:

SELECT
  date(silver.datetime) as datetime,
  DATE_PART('week', CURRENT_DATE) - DATE_PART('week', silver.datetime) + 1 AS week_number,
  item,
  price,
  close AS spot
FROM retail_silver_norm_time
  JOIN silver ON (retail_silver_norm_time.datetime = round_time(silver.datetime))
WHERE
  silver.datetime BETWEEN CURRENT_DATE-90 AND CURRENT_DATE+1
ORDER BY datetime

我们来分析一下。

From retail_silver_norm_time 是规范化的白银零售价格视图。银表只包含市场数据。这两个表使用它们的日期戳连接在一起。因为它们来自不同的来源,日期戳具有不同的精度,但是使用 round 函数解决了这个问题。

在新的笛卡尔积中,我只想要时间戳覆盖 90 天窗口的数据。我使用 PostgreSQL 数据库,所以我使用内置标识符“CURRENT_DATE”。这是一个便利的特性,大多数数据库都有类似的特性。

请注意,我的窗口延伸到今天以后。我这样做是以防万一,以防我得到一个奇怪的日期戳。虽然这种情况并不常见,但在没有服务质量保证的情况下处理数据时,这种情况时有发生。

现在,定义了查询的整个基础,我具体想从大表中得到什么呢?这里我选择了 silver 表的 datetime,它只提取了日期部分。为了保持一致性,我保留了相同的名称。然后,我计算“周数”的值。这将用于最终产品。之后,我提取其他三个主要数据——商品、零售价格和现货价格。

这给了我一切需要建立我的情节。

预处理

当我的数据从数据库中出来时,我试图让它尽可能地直接有用。然而,我有一个令人讨厌的习惯,就是在多个地方使用同一个查询的结果。这没有什么不同,所以我需要做一点数据争论来获得我需要的一切。

对于这一部分,我将查询结果放入 Pandas 数据帧。

注意:现在你可能已经注意到了,我没有深入研究那些在别处很容易找到的项目。如果您不知道如何将查询中的数据放入数据框,在快速搜索的第一页上有一些精彩的教程(比这好得多)。

无论如何,这是我用来运行我的进程的代码:

df = dbf.query_return(qu.silver_regression_query1)
df.columns = ['datetime', 'week_number', 'item', 'price', 'spot']
df = df_cleanup(df)
df = silver_normalizing(df)df['ps_gap'] = df.price - df.spot
df.ps_gap = df.ps_gap.round(2)
df['date'] = pd.to_datetime(df['datetime']).sub(pd.Timestamp('2021-03-01')).dt.daysdf.date = df.date / 10
df.date = df.round()silver_reg_item = df['item'].unique()

让我浏览一下上面的代码。

第一行和第二行只是在我的函数返回查询结果时设置数据帧。第三行通过一个通用的清理函数发送数据帧,以填补空白并执行一些我希望在这个应用程序中使用的例行程序。第四行是一个转换函数,它将商品价格标准化为一个一致的比例,这样我就可以进行比较。只是应用程序中数据的另一个细微差别。

第 5、6 和 7 行是数据列和格式的补充。第六行为现货价格和零售价格之间的差异创建了一个计算列。第六行将该值四舍五入为两位数。第七行创建一个计算列,表示自 3 月 1 日以来的天数。第 8 行和第 9 行是对第 7 行计算的修改。他们将计算出的日期放入 10 的比例中,然后四舍五入到最接近的整数。

进行这些修改的原因并不清楚,也可能令人困惑,但在我们构建图表时,它们确实有其目的。还要注意的是,其中许多可以通过各种方式进行整合,以便在运行时执行。出于本例的目的,我选择将它们分开,以使整个范围更具迭代性,更容易理解。根据您的选择进行整合。

最后一行创建一个新的 dataframe,它只包含条目列表的唯一值。这提供了一种快速简单的方式来按项目进行过滤,在这里这样做消除了另一个查询的需要。

破折号构造

对于某些人来说,这可能有点复杂。但是,我会详细介绍一下。

现在,我们有一个数据集存储在一个经过预处理的数据帧中,其中包括我们的数据群体。这是我们要处理的数据的总和。我已经让你知道了我的数据是如何构建这个的,但是你也可以很容易地使用你自己的数据。重要的部分是获得一组现成的数据。

我们试图得到的是一个过滤后的数据视图,它以图表的形式显示出来。为此,我们需要一些机制。

首先,我们需要一个地方来保存图表。在我的例子中,我使用引导模板(因为我的前端设计技能没有什么值得大书特书的)并填充一个模型。我提出来只是为了说明这是可能的,但实现这一点的核心只是三个基本概念:

  1. dcc。Graph —这提供了一个占位符和一个目标 id。
  2. dcc。drop down——这个控件只是给我们一个选择项目的地方。
  3. dcc。RangeSlider —该控件允许我们按日期进行筛选。

dcc。下拉式

除了许多教程所涉及的内容之外,这里没有什么特别的。最大的方面是 1)id 和 2)填充值的循环。

dcc.Dropdown(
  id="silver_regresssion",
  options=[{
    'label': i,
    'value': i
  } for i in silver_reg_item],
  value='One Ounce Generic Silver')

id 被指定为“silver_regression”。请注意这一点,因为它稍后会回来。

该列表由 silver_reg_item 填充,这是我们在预处理的第 10 行中创建的数据帧。

dcc。范围滑块

rangeslider 不仅可以按项目过滤(从下拉列表中),还可以按日期限制视图。或者在这种情况下,与其说是日期,不如说是从当前周开始的周数。

dcc.RangeSlider(
  id='silver_week_slider',
  min=df['week_number'].min(),
  max=df['week_number'].max(),
  value=[
    df['week_number'].min(), 
    df['week_number'].max()
  ],
  marks={int(n): n-1 for n in df['week_number'].unique()},
  step=None
)

像以前一样,这些都是从例子中一字不差地摘录下来的。

这是为什么在预处理中使用硬编码值的一个很好的例子。正如您在最小值、最大值和值字段中看到的,所有这些都是基于 dataframe 列值的函数。这些本来是可以动态执行的,但是这会使代码变得更加不明显。

当你创造各种各样的展示时,为了你自己和你之后的人,试着先思考整个过程。早走一步往往可以避免以后的一些麻烦。

dcc。图表

dcc.Graph(id='silverReg')

说真的,正如我之前所说的,Graph 对象只是给了我们一个目标 id。

回电

从长远来看,试镜对我来说是最难理解的事情。它们看起来不直观,解释也不充分。只是在经历了大量的尝试和错误之后,终于有所发现。我也知道不能只有我一个人。所以让我试着用一种我希望是在我学习的时候的方式把这说得更清楚。

回调装饰器使用一些语句来创建接口组件和执行的逻辑之间的管道。使用这种安排,我们可以制作一些高度交互的复杂应用程序。

装饰器中的每个语句都由其功能来表示:输入、输出或状态。输入是反馈给回调的数据。输出是离开回调的数据。状态是当前状态。

对于每个语句,我们有两个维度——相关组件的 id 和数据包。这就是为什么所有的组件都需要被清晰地定义和调用。

这是我的回调装饰器:

@app.callback(
  dash.dependencies.Output('silverReg', 'figure'),
  [
    dash.dependencies.Input('silver_regresssion', 'value'),
    dash.dependencies.Input('silver_week_slider', 'value')
  ]
)

我们可以看到我们有两个输入语句。这些分别与 dropdown id 和 rangeslider id 相关。列表中的第二项是值。

类似地,我们的 output 语句记录了目标 id,返回的数据将是一个数字。这和我们的 dcc 吻合。图形对象。

超越室内设计师

一旦我们确定了输入和输出,并在应用程序主体和逻辑语句之间创建了链接,我们就可以构建后端了。可以说,这是金属与道路相遇的地方,并以一种功能的形式出现。

我将把这些拼凑起来,带您浏览逻辑决策,希望您能理解正在发生的事情及其原因:

def update_graph(silver_reg_item, week_num):
  if silver_reg_item is None:
    silver_reg_item = "One Ounce Generic Silver"

  if week_num is None:
    first_week = 52
    last_week = 0
  else:
    first_week = week_num[0]
    last_week = week_num[1]

我们的第一行是基本的函数定义。它需要两个参数,这很方便,因为我们的装饰者获得了两个输入(请注意幽默)。

其余的顶部行用于设置默认状态。在 Dash 应用程序中,所有回调都在启动时触发,因此您必须考虑这一点。

第一个条件是定义一个默认项目。第二个条件创建一个默认范围。由于组件中有默认值,这应该不是问题,但如果是,它会创建一个不会破坏任何东西的良好的软状态。

处理

数据处理似乎永远不会结束,对吗?在这里也是如此。由于我们将数据框架过滤成一个特定于项目和日期的框架,因此我们需要实现所有这些,然后执行一些直接计算:

df1 = df[df['item'] == silver_reg_item].copy()
df1 = df1[(df1['week_number'] >= first_week) & (df1['week_number'] <= last_week)]y_max = df1.price.max()
x_min = df1.spot.min()X = df1['price'].values.reshape(-1,1)
Y = df1['spot'].values.reshape(-1,1)linear_regressor = LinearRegression()
linear_regressor.fit(X,Y)df1['Y_pred'] = linear_regressor.predict(X)

这一部分做了几件事。首先,上面两行执行过滤。第一行按项目过滤主数据帧并创建一个副本。我们创建一个副本,这样我们就不会丢失原始主数据帧,并可以继续从中提取数据。第二行根据范围值过滤新的数据帧。这就给我们留下了简短的数据框架。

接下来,我想对数据进行线性回归。这是通过 SciKit 学习库完成的,需要将 dataframe 列转换为 numpy 数组。

第三和第四行从数据帧中分离出最小值和最大值的两个值。这些稍后会用到。

第五行和第六行将现货和价格的 dataframe 列重组为必要的数组。第七行和第八行调用函数,第九行生成一个包含基于它的值的列。这也可以在 Plotly 中直接完成,但我想改为像这样执行函数。

图表

我们在这里。我们一直在构建的代码:

fig = px.scatter(
  df1,
  y='price',
  x='spot',
  size=(df1.date * df1.date) * 2,
  opacity=.5,
  color='ps_gap',
  trendline="lowess",
  trendline_color_override="purple",
  hover_data=["datetime", "price", "spot"],
  color_continuous_scale=px.colors.diverging.RdYlGn_r,
  range_color=[df1.ps_gap.min(),df1.ps_gap.max()]
)

这是主要情节。它是一个 plotly express 对象,使用我们在前面的过程中创建的 df1 数据帧。作为散点图,它使用现货对零售价格。

如果我把这个图留在那里,它将是一个非常无聊的散点,会提供信息,但不会尽可能多。这是我添加了一些维度的地方。

使用 size 参数,我建立了一种方法,其中使用经过预处理的数据,大小根据距离而变化。随着日期越来越远(或越来越接近 3 月 1 日),尺寸会越来越小。越近的数据点越大。我一眼就能看出仅基于规模的相关性。

第二,我想要一个清晰简洁的方法来识别差异。为此,我使用了颜色和颜色渐变。每个标记的颜色基于“ps_gap”值,但是这些颜色是使用“px.colors.diverging.RdYlGn_r”标度专门选择的。这是一个相对较高的对比度,具有良好的区分度。末尾的“_r”反转渐变。最后,该范围是动态的,基于 ps_gap 列中的最小值和最大值。

这一部分的几个细节是,我将不透明度定义为 0.5,以便在聚类组中提供一些强度变化,并且我添加了一条默认的 LOWESS 趋势线。趋势线是一条平滑的趋势线,补充了上面计算的线性回归。

fig.add_traces(go.Scatter(
  y = df1['price'],
  x = df1.Y_pred,
  name='Regression',
  showlegend=False,
  line_width=2,
  line_color='black',
))

下一个加法是线性回归。为此,我们简单地在图中添加一个轨迹。您可能会注意到这是一个标准 plotly Graph 对象,而不是 plotly express 对象。可以,可以混搭。

此追踪将零售价格作为 Y 值,并将 X 值设置为等于计算的预测值。(是的,我知道那里发生了什么)

当我将图表打印到文件中时,我意识到一个挑战,那就是它往往会丢失上下文。我没有下拉菜单或任何其他标识符来告诉我我在看什么。所以,解决这个挑战的简单方法是用一个注释:

fig.add_annotation(
  y=y_max, 
  x=x_min,
  text=silver_reg_item + "<br>" +
    str(df1.datetime.min()) + " through " +
    str(df1.datetime.max()),
  showarrow=False,
  font_size=10,
  bordercolor='rgba(255,255,255,0.8)',
  bgcolor='rgba(235,171,52,0.5)',
  borderpad=5
)

该注释根据我们在处理部分定义的最小-最大值来设置位置。这有助于在不修改轴的情况下,没有很多复杂的麻烦地解决问题。

最后一步只是一些格式化:

fig.update_traces(marker=dict(
  line=dict(
    width=1,
    color='black')),
  selector=dict(mode='markers'))fig.update_layout(
  title="Silver Spot vs. Retail Relationship",
  plot_bgcolor="#FFFFFF",
  xaxis=dict(
    title="Spot",
    linecolor="#BCCCDC"
  ),
  yaxis=dict(
    title="Retail",
    linecolor="#BCCCDC"
  ),
  coloraxis_colorbar=dict(
    title="Retail-Spot Variance",
    ticks="outside",
    tickprefix="$")
)

第一次更新概述了痕迹。这让它们更容易区分。布局的第二次更新设置了标题、轴细节,并格式化了颜色条。

我们做的最后一件事是返回完整的数字:

return fig

这将获得完整的 Plotly 图形,并将其推到 dcc 中的占位符。装饰器中定义的图形。然后 Dash 完成剩下的工作。

最后的结果

辉煌的仪表板

上图是图表在应用程序中的样子。在顶部,我们可以看到下拉菜单,在底部,我们可以看到范围滑块。但是,当我们保存图像时,我们会得到以下结果:

保存的图表

如前所述,保存的图表具有更少的上下文。这使得注释更加重要。

最后的想法

我们走了很长一段路才走到今天,但我想确保关注的不仅仅是呈现的数据的维度,还有幕后的东西。最终的图表既简单又复杂。很好的搭配。

粗略地看一下,我们可以看到数据之间的关系,正如我们对这种散点图的预期。然而,如果我们真的检查它,我们不仅会被轴值吸引,还会被大小和颜色吸引。它用更多同样重要的元素来完善这个故事。

作为一个思维实验,如果我们不考虑尺寸和颜色,我们需要什么来呈现这些数据呢?还有多少其他图表?什么类型的图表?会有效果还是房地产成本太贵?

想象就像写作。我们错开句子结构。有些想法是迅速而明显的。其他的比较密集,需要慎重考虑。但是我们调整每件事的节奏,让我们的观众理解我们需要他们做什么。

有时候,一个非常简单直接的视觉就足够了。其他时候,我们需要挖掘复杂性。最好的方法,尤其是在构建一个内聚的仪表板或报告时,是构建我们需要说的内容。这需要以适当的方式优雅地组合我们的数据,让我们的结论被理解——或者让我们的观众得出他们自己的结论。

最后,进行实验。有些想法行得通,有些则会落空。但是,如果您理解了我在这里抛出的内容,那么您就已经有了构建自己的测试环境来探索数据的概念和工具的开端。

使用 PostgreSQL 在 Python 中构建数据仓库

原文:https://towardsdatascience.com/building-a-data-warehouse-in-python-using-postgresql-f10dce22e3aa?source=collection_archive---------2-----------------------

一种简化的方法来提供健壮且可扩展的数据仓库

娜娜·斯米尔诺娃在 Unsplash 上的照片

介绍

随着当今时代数据的丰富和激增,有一种以有意义的方式存储和重用这些信息财富的内在需求。这就好比厨房里堆满了各种各样的用具和工具,却没有一种有组织的方式来管理它们。嗯,除非你囤积得很快,否则你很可能会用勺子的后端来打开你的午餐罐头。

数据仓库能够以前所未有的方式按需缓存、标记、分析和重用您管理的数据。就像你母亲在她整洁有序的厨房里导航一样。请注意,没有放之四海而皆准的解决方案,有多少个仓库就有多少种建仓方式。

可以说,实现成功的数据仓库有三个关键因素:

  1. 服务器:首先,您必须提供一个既健壮又有弹性的分布式数据库系统。
  2. 索引:理想情况下,你的数据库系统应该有某种形式的索引,允许你以极快的速度访问记录。拥有一个全文索引将是一个额外的收获。
  3. Dashboard: 你应该有一个暂存区,在这里你可以以一种不变的方式导入、导出、可视化和改变你的数据。

在本教程中,我们将通过创建一个数据仓库来解决上面提到的第一点和最后一点,我们可以在其中存储数据集、数组和记录。此外,我们将创建一个仪表板,在那里我们可以用图形界面与我们的仓库加载,检索,变异和可视化我们的数据。或许在另一篇文章中,我们将实现第二点,即全文索引数据库。

服务器:PostgreSQL

PostgreSQL,简称 Postgres,是一个开放源代码的关系数据库系统,由于其扩展的功能和相对易用性,它通常是开发人员的首选数据库。尽管它被标榜为结构化数据库管理系统,但它也可以存储非结构化数据,包括但不限于数组和二进制对象。然而,最重要的是,Postgres 的图形用户界面使得动态提供和管理数据库变得太容易了,这是其他数据库系统应该注意的。

在我们的数据仓库实现中,我们将使用本地 Postgres 服务器来存储我们所有的数据。在我们继续之前,请使用此链接下载并安装 Postgres。在安装过程中,系统会提示您设置用户名、密码和本地 TCP 端口以连接到您的服务器。默认端口是 5432,您可以保持不变,也可以根据需要进行修改。安装完成后,您可以通过运行 pgAdmin 4 应用程序登录服务器,该应用程序将在您的浏览器上打开一个门户,如下所示。

PostgreSQL 服务器门户。图片作者。

将会有一个默认的数据库,标签为 postgres ,但是您可以通过右击 Databases 菜单,然后选择 Create 来创建您自己的数据库,以提供一个新的数据库。

Python 实现

现在您已经提供了您的服务器和数据库,您应该安装软件包 sqlalchemy ,它将用于通过 Python 连接到我们的数据库。您可以通过在 Anaconda 提示符下键入以下命令来下载并安装这个软件包:

pip install sqlalchemy

此外,下载、安装并导入所有其他必要的库到 Python 脚本中,如下所示:

首先,我们需要在我们的 records_db 数据库之间建立一个连接,并创建一个可以存储记录和数组的表。此外,我们需要创建另一个到 datasets_db 数据库的连接,我们将在其中存储数据集:

按照 Postgres 的命名约定,表名必须以下划线或字母(不是数字)开头,不能包含破折号,并且长度必须少于 64 个字符。对于我们的记录表,我们将创建一个数据类型为文本名称字段,声明为主键,以及一个数据类型为细节文本[] 字段,这是一个一维数组的 Postgres 表示法。要获得 Postgres 支持的所有数据类型的详尽列表,请参考此链接。我们将使用名称字段作为主键,稍后将用于搜索记录。此外,请注意,存储您的数据库凭证的一种更安全的方式是将它们保存在一个配置文件中,然后在您的代码中将它们作为参数调用。

随后,我们将创建以下五个函数来写入、更新、读取和列出数据库中的数据:

将字符串连接到查询时,请注意 SQL 注入漏洞。您可以使用参数化来防止 SQL 注入,如本文中的所述。

仪表板:简化

Streamlit 是一个纯 Python web 框架,允许您在指尖实时开发和部署用户界面和应用程序。在本教程中,我们将使用 Streamlit 来呈现一个仪表板,我们可以用它来与 Postgres 数据库进行交互。

在下面的代码片段中,我们使用了几个文本输入小部件来插入数据集的记录、数组和名称的值。此外,我们正在使用 Streamlit 的功能,以图表和数据框的形式交互式地可视化我们的数据集。

您可以在本地浏览器上运行仪表板,方法是在 Anaconda 提示符下键入以下命令。首先,将根目录更改为保存源代码的位置:

cd C:/Users/...

然后键入以下内容运行您的应用程序:

streamlit run file_name.py

结果

这就是你要的,一个可以用来实时标记、写入、读取、更新、上传和可视化我们的数据的控制面板。我们的数据仓库的美妙之处在于,它可以扩展到托管您可能需要的尽可能多的数据,所有这些都在我们刚刚创建的同一结构中!如果你想了解更多关于数据仓库的基础知识,我建议你报名参加科罗拉多大学关于数据仓库的课程。这是提高速度的好方法。

如果您想了解更多关于数据可视化和 Python 的知识,请随时查看以下(附属链接)课程:

使用 Streamlit 开发 Web 应用程序:

https://www.amazon.com/Web-Application-Development-Streamlit-Applications/dp/1484281101?&linkCode=ll1&tag=mkhorasani09-20&linkId=a0cb2bc17df598006fd9029c58792a6b&language=en_US&ref_=as_li_ss_tl

使用 Python 实现数据可视化:

https://www.coursera.org/learn/python-for-data-visualization?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW2aEwvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c

面向所有人的 Python 专业化:

https://www.coursera.org/specializations/python?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW16Ewvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c

GitHub 资源库:

https://github.com/mkhorasani/data_warehouse

新到中?您可以在此订阅并解锁无限文章

从联邦学校测试数据中建立数据库

原文:https://towardsdatascience.com/building-a-database-from-federal-school-test-data-128707fa46e7?source=collection_archive---------23-----------------------

乔治·李在 Unsplash 上的照片

在关系数据库中组织国家教育统计中心(NCES)的数据

介绍

作为两个孩子的父母,我和妻子研究了美国几个城市的学校质量。这项研究产生了一些流行的网站,这些网站展示了各个学校质量的各种衡量标准。两个最受欢迎的提供学校质量信息的网站是 GreatSchools.org 和 Niche.com。作为一名数据专家,我想知道这些网站从哪里获得数据。这两个网站都使用了美国教育部国家教育统计中心(NCES)提供的数据(GreatSchools.org 也使用了相当多的州教育部门的数据,比联邦数据更详细)。

在这一系列文章中,我将分享我下载和重构大量数据集的过程。首先,我将使用 Python 来重组数据,将其加载到 Mysql 数据库中,然后我将使用 Python 的一些流行的数据科学库来做一些特别的研究项目。

这第一篇文章的主要目标是介绍我如何成功地使用 Pandas 将从 NCES 获得的 10 年学校级考试成绩加载到 MySQL 数据库中。通过将这些数据加载到关系数据库格式中,我的目标是使大量的分析任务更加有效,因为我将在以后的文章中更深入地研究这些数据。希望这对那些对探索 Pandas 的 SQL 能力感兴趣的人有所帮助。

工具

本系列中的工作将使用几个流行的 Python 库和 MySQL 来执行,并可能使用一些其他工具来节省我的时间。

对于本文,我将使用 4 个 Python 库:Pandas 将用于数据处理任务,OS 和 GLOB 将用于访问目录和文件,SQLAlchemy 将用于连接我将加载数据的 MySQL 数据库。

数据

NCES 每年都会提供一套学校和地区级的绩效档案。每个学校级别的绩效文件显示了每个参与评估的美国学校在评估年度的全部结果。2017–2018 文件共有 265 列。前 9 列包含有关学校和数据收集年份的信息。额外的列包含被评估的学生数量和全校被认为熟练的百分比(熟练百分比),并按各种人口统计和种族群体进行细分。关于文件结构的详细信息可以在美国教育部的 EDFacts 数据文件网站上找到。对于这个项目,我已经保存了从 2009-2010 学年到 2018-2019 学年的所有学校级绩效文件。

构建数据管道

首先,我将导入要使用的库,并建立到 MySQL 数据库的连接。

接下来,我使用 SQLAlchemy 库建立了一个数据库连接,我们稍后将使用它来加载重构的学校级别的性能数据。对于 SQLAlchemy 数据库连接,一个重要的建议是,在建立连接时,将 echo 参数设置为 false,这是我从惨痛的教训中学到的。如果您按照我这里的步骤操作,您将会以 10,000 个数据块的形式向数据库写入数百万行。您不会希望每次成功执行写命令时都将日志写入笔记本。我在一个 jupyter 笔记本上犯了这个错误,写了几个小时数据就用完了内存。对于需要写入数据库的额外任务,我下载了笔记本。py 文件,并从命令行运行它。

最后,本文的主要目标是通过 Pandas 工具将这些数据加载到数据库中。所有重新格式化数据和将字符串值映射到数值的工作都是使用一个类完成的。虽然它们对于让您的程序在 Python 中工作并不重要,但我发现编写类有助于提高代码的可读性和组织不同的函数,以便它们能够很好地协同工作。

在这种情况下,Python 类将完成 5 个主要任务来为我的数据库准备数据:1)读取 csv 文件,2)找到测试分数数据所在的列,3)选择包含学校身份信息(例如,名称、州、机构等)的列,4)处理参与和分数信息并将数据堆叠为垂直格式,5)将测试分数数据中包含的字符串值转换为数值,以便在存储到数据库中时进行分析。

完成这些步骤后,转换后的数据将使用实体属性值(EAV)数据模型存储在我的数据库中。EAV 模型将使我们能够消除数据中的空值,并有效地存储数据以备后用。对于我们的 EAV 模型,每个实体将是一所学校,属性将是学校学生不同分组的测试结果。

处理年度绩效文件的步骤如下:

我用两个参数实例化了这个类。“file”参数将我们引向我们将要处理的文件,“str_replmts”参数是一个字典,它将性能文件的原始版本中包含的字符串值映射到已经定义并存储在字典中的数字替换。

接下来,我创建了一个函数,它识别并构建文件中存储测试分数参与和结果的列的列表。

接下来,有三个不同的函数用于选择包含关于学校的元数据的列。不同的函数需要考虑不同年份之间列名的细微变化。

接下来的两个函数将用于将测试分数数据转换成 EAV 数据格式。在我们的堆栈函数中调用这个转换函数,将字符串值转换成数字。

这个函数利用了将字符串值映射到数字的字典。一旦我们将数据加载到我们的数据库中,以数字形式存储考试分数数据对于促进分析将是非常重要的。这一步是必要的,因为 NCES 文件根据注册参与者的数量存储特定学生统计组的熟练程度分数。采取这项措施是为了保护学生的隐私。例如,为了使这些数据可用于分析目的,必须将字符串值“LE10”(代表“小于或等于 10%的熟练程度”)转换为数值。为了对数据集中的所有字符串值完成这个过程,我收集了所有数据文件中所有字符串值的列表,并在一个 csv 文件中手动执行映射。开发这个映射文件的完整过程超出了本文的范围。映射文件如下所示:

这个文件被转换成一个字典,这样它就可以用来将字符串映射成数字。

类中包含最多功能的函数是最终的 get_scores_data。该函数执行一系列任务,将测试分数数据转换为 EAV 格式,我将使用该格式将数据存储在我的 MySql 数据库中。

这个函数完成 4 个主要任务:1)它选择学校 id 和包含测试分数数据的列,2)它垂直堆叠数据,3)它解析列标题中包含的元数据(例如,什么人口统计组,什么科目,等等。)放入单独的列中,以便在数据加载到数据库中后更容易进行过滤,以及 4)它用上面的“str_replace”字典中的映射值替换非数值。

任务 1:选择学校 id 和包含测试分数数据的列

任务 2:垂直堆叠数据

任务 3:将每一列的元数据解析到单独的字段中。

任务 3:用映射值替换非数字:

在文件准备好写入数据库之前,此函数执行的最后一个操作是过滤/连接操作,该操作创建最终数据集,其中并排显示每个独特年份/人口统计组的参与者数量和熟练程度百分比。

为了对 NCES 文件执行这些操作,我使用了一个 for 循环来处理每个文件,并将其加载到 MySQL 数据库中。

请注意,我在 Pandas 的 to_sql 函数中使用了“chunksize”参数。在后台,SQL Alchemy 正在对 MySQL 数据库执行写语句。需要限制这些语句的长度(原因超出了本文的范围),将每个写命令的长度限制为 10k 记录似乎会阻止数据库关闭连接。关于这个 for 循环的另一个重要注意事项是,在将 for 循环中的下一个文件放入内存进行处理之前,' del data '语句将删除刚刚加载的数据帧。如果您在内存有限的机器上工作,这可能会很有帮助。

在一台配有 4 个内核和 16GB 内存的 Windows PC 上,对所有文件运行这个 for 循环大约需要 8 个小时。

下面是加载 10 年的性能数据后,我们的最终数据库表的示例。

除了在 EAV 模型中加载学校绩效数据之外。我还需要存储每个学校的附加元数据,以便在不同学校之间和内部进行分析。

我通过调用不同版本的 get_school_index 函数完成了最后一项任务,创建该函数是为了考虑每年文件格式的细微变化,将结果连接到一个数据帧中,然后将该数据帧加载到我的 MySQL 数据库中的一个表中。

一旦加载到数据库中,数据看起来就像这样。

概述

概括地说,我们刚刚使用 Pandas 和其他一些库将大量与美国公立学校考试成绩相关的历史数据加载到 MySQL 数据库中。希望本文能帮助您理解这个数据集,并为您提供一些关于如何使用当代数据处理工具和技术转换和加载数据的想法。感谢阅读!

在 Azure 上构建深度学习图像字幕模型

原文:https://towardsdatascience.com/building-a-deep-learning-image-captioning-model-on-azure-b14ce4682fbf?source=collection_archive---------16-----------------------

实践教程

这幅图像中发生了什么?关于如何在云上创建深度学习计算机视觉和 NLP 模型的教程。

你如何描述这幅图像中发生的事情?安托万·华多,“梅泽廷”(1718-1720)。大都会博物馆提供。

在我利用 AI/ML 的新角色入职时,我开始从头开始在云上构建深度学习模型。在大学期间,我在一家艺术博物馆实习,在那里我亲眼目睹了整个行业面临的挑战,即将艺术品数字化,以便让广大观众能够接触到它们。

即使一件艺术品被数字化以供在线访问,也不总是容易找到。用户可能很难在博物馆的数据库中找到一幅他们可能见过但不记得名字的画。他们可能会使用语义语言来描述图像(例如,“坐在长凳上拿着一件乐器的人”),而不是关键短语,如绘画的名称(“梅泽廷”)、日期(1718-20)或艺术家的名字(安东尼·华多)。这个用例启发我建立了一个神经网络,它可以识别图像的关键组成部分,并根据场景生成描述性的说明。

然而,图像字幕模型的应用超出了艺术博物馆的范围。处理许多需要易于搜索的描述的图像的组织(如工厂、报纸或数字档案馆)可以从自动生成标题中受益,而无需依赖劳动密集型的手动描述过程。此外,标题还有支持可访问性标准的额外好处。书面字幕可以通过自适应技术为视力残疾的个人大声朗读。

Azure Cognitive Services 提供图片标记图片描述服务。然而,我想看看如何从头开始在云中构建和部署一个模型。我的目标是使用 Azure 的工具和服务来训练、测试和部署深度学习模型,并最终看看它的性能与 Azure 的一些现有产品相比如何。

为了建立深度学习模型,杰森·布朗利的图像字幕模型充当了一个切入点。我使用 Azure Databricks 和 Azure Machine Learning 作为创建我的深度学习模型的平台。然而,无论您使用何种云提供商平台,一般的培训和部署工作流程都是相似的:

  1. 存储数据
  2. 在 Azure 上设置培训和测试环境
  3. 加载和预处理数据
  4. 训练和评估模型
  5. 注册模型
  6. 为部署准备模型
  7. 部署模型以计算目标
  8. 使用部署的模型(即 web 服务)进行推理

在接下来的内容中,我将介绍我是如何构建这个模型的,并分享为自己构建一个版本的技巧。最后,我讨论了为什么模型会有这样的表现,并找出了改进的机会。

技术堆栈和架构概述

当一幅图像被描述时会发生什么?有两个主要的考虑因素:第一,模型必须识别图像中的关键主题和支持细节。这个组件将由“计算机视觉”组成,该模型识别视觉上表示的内容并输出唯一的特征向量。第二个概念是自然语言处理。然后,该模型必须将其所见转化为一个连贯的句子,概括图像中正在发生的任何事情。

该项目建立在微软 Azure 云之上。具体来说,使用从 Blob 存储器摄取的数据在数据块上训练该模型。然后,这些模型被注册到一个 Azure 机器学习工作空间中,这样模型就可以作为 RESTful API 端点进行部署,以供最终使用。用户可以向端点发送图像的多个公共 URL,并接收从 Azure 计算机视觉认知服务和深度学习模型生成的标题。

下面是一个架构图,展示了所使用的工具和服务:

我如何在 Azure 上构建深度学习模型的架构图。图片作者。

我使用的数据集是 Flickr 8k 数据集,它由从 Flickr 的数据库中抓取的 8000 多张图片组成,该数据库在 Creative Commons 许可下可用。它还包括一个 CSV 文件,其中包含由一个人根据每张图片编写的五个标题(总共超过 40,000 个标题)。每张图片都有多种不同语法风格的标题,因为描述一张图片有多种方式,其中一些比另一些更准确、详细或简洁。

预先训练的单词嵌入模型 GloVe 用于将训练数据中的单词映射到更高维的空间,以提取单词之间的精确关系。

我使用的模型架构是一个递归神经网络 (RNN)和一个数据生成器的公式,用于逐步加载数据。前一种方法通过根据句子中以前的单词选择单词来帮助构建句子。后者避免了在集群节点的内存中一次性加载所有数据的负担。我利用预先训练好的 VGG16 模型来应用迁移学习(可以用 InceptionV3 模型作为替代)。这样,我可以使用 Keras 定制一个现有的模型来满足我的解决方案的需求。

为了评估生成的字幕的质量,我使用了 BLEU 评分,这是一个量化评估,用于评估字幕与“地面真实”(即人类编写的)字幕相比,听起来有多自然。

流程

了解如何通过八步在 Azure 上训练和部署深度学习模型。

1。将数据存储在 Blob 存储器中

Blob 存储是存储大量非结构化数据(如图像)的最佳选择。(您可以在此了解如何创建 Blob 存储帐户。)虽然你可以使用 SDK 或 Azure Portal 将下载的数据存储到 blob 存储中,但是 Azure Storage Explorer 有一个方便的 UI,允许你直接上传数据,而不需要太多的努力。

2。设置您的 Azure 环境虚拟机(VM)并使用 Databricks 挂载点加载数据

创建深度学习模型的环境可以通过 Azure 门户网站创建 Azure 机器学习(AML)工作区和 Databricks 工作区的实例来完成。从那里,您可以启动 Databricks 工作区,创建笔记本电脑,并启动计算集群。

您可以为您的计算集群选择许多不同的配置。对于 Databricks 运行时版本,最好使用版本名称中带有“ML”的运行时,这样可以确保安装的库版本与流行的机器学习库兼容。在数据块上旋转集群的好处在于,节点在不活动后会关闭,这是一个经济上有益的特性。

旁注:如果你使用的是 Flickr 16k 或者 30k 这样的大型数据集,我建议你在 GPU 上训练,这样训练起来更快。 Horovod ,一个诞生于优步的分布式训练框架,可以进一步加速深度学习训练。

如何在 Azure Databricks 中设置机器学习计算集群?图片作者。

在 Databricks 中,数据是通过一个挂载点获取的。这授权数据块中的笔记本读取和写入 Blob 存储容器中的数据,其中所有文件夹(即 Blob)都存在。为您的数据创建一个挂载点的好处是,您不必为您的特定数据源欺骗工具,而是利用数据块文件系统,就好像数据存储在本地一样。

下面是关于如何设置装载点来装载数据的代码片段:

然后,您可以使用前缀dbfs/mnt/mount-name导航到该目录。例如,可以编写类似于open('dbfs/mnt/mycontainer/Flickr8K_data/captions.csv', 'r')的代码来读取文件。

3。预处理图像和字幕数据

为了准备用于模型训练的数据,字幕数据集和图像目录需要预处理。这一步包括为训练数据集中出现的所有单词创建一个“词汇字典”(这是模型用来创建字幕的单词库),将图像整形为 VGG16(224×224 像素)模型的目标大小,并使用 vgg 16 模型提取每个图像的特征。

在处理所有字幕并应用标准自然语言处理(NLP)清理实践(例如,使所有单词小写并删除标点符号)后,词汇表大小为 8,763 个单词。

我不会深入讨论关于数据预处理的更多细节,因为在 Brownlee 的演示中已经很好地概述了这一步骤。

4。定义模型并根据数据对其进行训练

有时在 NLP 中,你的训练数据不足以让模型理解单词之间的准确关系。 GloVe 是一种表示向量空间中单词之间相似度的算法。

使用通过斯坦福大学 NLP 项目获得的预训练单词向量有助于区分训练词汇集中单词之间的关系,以创建可理解的句子。我使用了由 200 维向量表示的 40 万个单词的数据集。通过将训练词汇映射到预训练的手套模型,可以将得到的嵌入矩阵加载到模型中进行训练。

使用数据生成器函数加载字幕和图像数据避免了一次性将整个数据集存储在内存中的开销。关于模型架构如何工作的更多细节,我推荐查看 Brownlee 的解释。

在构建模型时,一个句子可以被认为是一系列单词。长短期记忆 (LSTM)是一种特殊类型的 RNN,它是一种神经网络,是处理序列的标准方法,通过特别注意前面的输入来保留序列的上下文。然而,与其他 RNN 不同,LSTM 可以根据前面的单词预测下一个最有可能出现的单词,从而逐字建立标题,其中时间顺序很重要。

下面是神经网络的架构图,它有两个输入,代表图像的特征向量和不完整的字幕。你可以在这里了解更多关于模型的不同部分(如照片特征提取器、序列处理器和解码器)。

该模型以一个“开始标记”开始字幕,并根据跟随前面单词的概率迭代添加单词。图片作者。

以下函数将神经网络架构转换为 Keras 定义的深度学习模型,并输出模型对象进行训练。数据生成器使用 model.fit() 函数将训练数据传递给模型。该模型被训练了 20 个时期,总共花费了 1 小时 36 分钟。

5。将部署模型注册为 Azure 容器实例(ACI)

训练好模型后,现在可以将它部署为 Azure 容器实例(ACI ),这样任何人都可以使用它并为任何图像目录创建标题。通常情况下,如果该模型用于生产,它可以作为 Azure Kubernetes 服务(AKS)部署,您可以在这里了解。

不久前创建的 Azure 机器学习(AML)工作区现在派上了用场。通过以下代码片段调用工作区,出于安全考虑,这需要您登录 Azure 帐户。

第二步是在 Azure 机器学习工作区中注册模型和结果所需的任何基本资产,以便端点可以访问它们。我注册了 model 和 tokenizer(词汇),因为输出句子的构造在整个过程中都引用了 tokenizer 来预测句子中最有可能出现的下一个单词。

让我们也确认一下模型和标记器是否成功注册了。

6。通过编写入口脚本准备部署配置

端点如何知道如何使用训练好的模型并给出输出?所有这些都是在 ACI 的入口脚本中定义的。输入脚本定义了预期的用户输入类型、如何处理数据以及如何格式化结果。

下面的代码定义了一个完成四个步骤的端点:

  1. 接收到映像目录的 SAS URI,并访问注册的模型和令牌化器
  2. 调用训练好的模型为每个图像构建标题
  3. 调用 Azure 计算机视觉认知服务资源来生成补充标题
  4. 以 JSON 格式返回自定义模型和 Azure 资源的标题

入口脚本必须特别有两个函数, init()run()。前者加载重要资产;后者获取数据,并执行大部分繁重的工作,对图像进行预处理并构建字幕。下面的代码片段将脚本写入名为“score.py”的本地文件,该文件将包含在 ACI 部署的配置中。

7。部署模型以计算目标

ACI 还需要一个已定义的环境,该环境具有对输入进行评分所需的必备依赖关系。环境和入口脚本在推理配置中定义。

关键时刻:一旦 ACI 被定义,它就可以作为 Azure Web 服务进行部署,这样它就可以被调用了。从部署返回的评分 URI 将用于通过 REST API 调用测试端点,因此复制 URI 并保存起来以备后用。

8。通过调用 Azure Web 服务为新数据打分

测试模型端点有两种方法:用 Python 或 Postman。端点接受图像的任何公共 URL。正如预期的那样,端点返回来自训练模型的标题和 Azure Cognitive Service 的图像标题服务进行比较。用来自任何网站的图片或您自己的图片进行测试,以查看不同的结果。

在 Python 中,使用请求库来构造 API 调用如下:

如果您更喜欢在 Postman 中工作,以获得更快的调试和 UI 的便利性,该过程如下所示:

在 Postman 中测试模型端点的第 1 步。图片作者。

在 Postman 中测试模型端点的第 2 步。图片作者。

瞧吧!您现在已经成功地在 Azure 上训练和部署了深度学习模型!

点击了解更多关于在云上部署机器学习模型的信息

项目成果

并非所有的字幕都是同等创建的。描述一幅图像有很多种方式,每种方式在语法上都可能是正确的。但是有些比其他的更简洁和流畅。

如前所述,BLEU 评分是衡量翻译质量的可靠方法,评分范围为 0 到 1。可以导入 NLTK Bleu 评分包,通过将预测的字幕与人类编写的实际字幕进行比较来评估模型的性能。

权重为(1.0,0,0,0)的 BLEU 得分为 0.48。通常,介于 0.50 和 1 之间的 BLEU 分数提供了良好的结果。点击了解有关计算 BLEU 分数的更多信息。

模型评估和改进

模型性能仍有改进的空间。它对背景简单、只包含少数几个不同主题的图像表现得相当好。

然而,它有时很难准确识别对象是什么(例如,将一个模糊的人物标记为一个人或无生命的物体标记为狗),以及在室内拍摄的照片,或者如果在室外,在某些季节拍摄的照片。我想知道为什么会这样,以及将来可以做些什么来使字幕更加准确和真实。

该模型适用于温暖天气拍摄的户外照片,但不适用于冬季场景。(图片来源通过知识共享)

我的假设是训练数据集有偏差。这些数据是在 2014 年从 Flickr 上搜集来的,当时数码相机已经普及,并被休闲摄影师所使用。许多照片是在面向家庭的环境中拍摄的,如体育比赛或后院。虽然也有在其他环境下拍摄的照片,但绝大多数照片包含了狗捡球、小孩在草地上玩耍以及一群人。

对于在图像中描绘的场景类型中有更多差异的较大数据集,我们可以期望在图像上得到模型以前没有见过的更准确的结果。然而,较大数据集的代价是较长的训练时间。为了缓解这种情况,一种选择是对数据进行分区,或者将其转换为 Delta Lake 或 parquet 文件,同时进行分布式培训或使用 GPU 虚拟机。

如果想提高模型的准确性,一种选择是使用训练模型时使用的超参数。例如,增加时期(即,模型通过整个训练数据集的次数)同时保持批量大小(即,它一次训练多少个样本)相对较小有助于模型捕捉数据集中更多的细微差别,因为梯度下降收敛的速度降低了。纪元数量和批量大小之间的适当平衡可以产生一个整体性能更好的模型,而不会增加训练时间。

改善结果的另一种方法是增加神经网络的复杂性,例如在模型结构中增加更多的层。通过使模型更加复杂,它可以产生潜在的更好的结果,因为它能够更详细地训练数据。

一旦模型得到改进并可以投入生产,它就可以作为 AKS 而不是 ACI 实例进行部署,用于大型目录。

最后的想法

来自 Flickr 8k 数据集的一只快乐的狗的训练照片,通过 Creative Commons 从 Flickr 获得。

和许多人一样,我发现吴恩达的深度学习机器学习课程对了解深度学习领域非常有帮助。如果这些话题对你来说是新的,我建议试试他的视频。

概括地说,我们介绍了如何在 Azure 上设置机器学习环境,使用 Databricks 中的 Keras 定义和训练深度学习模型,并将该模型部署为容器实例,以便对新图像进行评估。

使用单词嵌入和余弦相似度构建可部署的吉拉 Bug 相似度引擎

原文:https://towardsdatascience.com/building-a-deployable-jira-bug-similarity-engine-using-word-embedding-and-cosine-similarity-1c78eeb23a8d?source=collection_archive---------71-----------------------

循序渐进的方法

巴黎武装博物馆的一台英格玛机(鸣谢:作者自己的收藏)

介绍

在之前的文章中,我详细介绍了如何使用亚马逊的 BlazingText 来构建吉拉 bug 分类引擎。在那里,我还引用了相应的 Gitlab 。在README.md那里,我非常简要地提到了关于 word2vecword 嵌入和作为输出生成到word2vec算法的vectors.txt文件。

在本文中,我们将使用相同的vectors.txt单词嵌入来构建一个文本相似度引擎,以在给定的 bug 语料库中找到相似的 bug。

什么是单词嵌入?

我可能无法解释什么是单词嵌入,但是 YouTube 上有一个很好的视频很好地解释了这个问题。简而言之,在单词嵌入中,我们基于它们的上下文将语料库中的每个单词映射到一个向量空间,在这种情况下,上下文是与语料库中其他单词的接近度。

你们中的一些人可能会觉得这很有趣:macheads101 使用 word2vec 算法创建了一个单词嵌入,使用的是他在一段时间内收集的 Twitter tweets,然后创建了一个漂亮的小 web 应用程序来演示如何使用嵌入在语料库中找到相似的单词。

在我上面描述的vectors.txt的例子中,我也绘制了向量空间的 case 图,只是为了对数据有个感觉:

向量的 t-SNE 图. txt

(本质上,t-SNE 是一种降维算法,其中我们将一个 n 维空间映射到一个较低的维度(在这种情况下是 2-d 用于绘图)。另一种流行的降维算法是 PCA)

正如你所看到的,有一些单词根据它们的上下文被认为是“相似”的。注意到图中的那些长条纹了吗?这些对应于吉拉门票中的代码片段。注意到它们都聚集在一起了吗?

这种将单词表示为向量的方式的好处是,单词之间的“距离”接近于相似性或更确切地说是亲和力或“它们属于一起”的概念。有几种方法来衡量这一点,[2]有一个很好的列表。为了简单起见,我们将只使用余弦相似度(正如我们将在后面看到的,这是一个不错的主意)。

但是我们不是在和单个单词打交道

现在,记住最初的目标:我们如何估计吉拉臭虫的相似性?我们可以扩展这个单词相似性的概念吗?

在[3]中,Yatin Vij 提供了几个选项:

  1. TF-IDF 加权单词嵌入
  2. Doc2Vec
  3. 平均单词嵌入

同样,为了简单起见,我们将使用(3) ie。对 bug 中的所有单词执行向量加法(在这种情况下,只有 bug 摘要和描述)。但是在[3]中,这种方法要求平均而不是求和。如果一个 bug 比另一个 bug 有更多的单词,这将是一个问题,对吗?如果我们使用余弦相似度就不会,因为与欧几里德距离不同,余弦相似度使用向量空间上两点之间的角度来确定相似度。这意味着可以使用矢量和来代替平均值。

这概括了主要思想。接下来就是尝试一下,看看是否有希望成功。在下面的部分中,我将引用在这里找到的代码:

https://gitlab.com/foohm71/cuttlefish

(为什么是“墨鱼”?我的上一个项目叫做“章鱼”,所以我就顺其自然了)

算法探索

在本节中,我将浏览在cuttlefish存储库中找到的TextSimilarityExplorations.ipynb。这个 Python 笔记本是为在 Google Colab 上运行而设计的,我推荐它在那里运行。

注意:正如本文中所描述的,吉拉 bug 信息的语料库是从几个开源项目的吉拉票证的开源存储库中获得的。也有 2 个数据集被使用:JIRA_OPEN_DATA_LARGESET.csv被用来获得vectors.txt,我将使用JIRA_OPEN_DATA_ZOOKEEPER.csv来尝试这种方法。这两个数据集应该是正交的,因为“大数据集”不包含任何 Zookeeper 错误。我想这样做是为了看看单词嵌入方法有多健壮。

设置

基本设置材料:

第一部分即。drive.mount('/content/drive')基本上挂载你的 gdrive,这样你就可以从 gdrive 读入数据到 Colab。

读入数据

第一次读入vectors.txt:

wv = KeyedVectors.load_word2vec_format('/content/gdrive/My Drive/Colab Notebooks/Octopus2/BlazingText/vectors.txt', binary=False)

注意:您必须根据您上传vectors.txt文件的位置相应地修改路径(如果您计划运行笔记本)。

接下来,读入动物园管理员数据:

dataset = pd.read_csv("/content/gdrive/My Drive/Colab Notebooks/Octopus2/JIRA_OPEN_DATA_ZOOKEEPER.csv")

接下来,我们只需要idtitledescription字段,我们还将titledescription组合成一个名为features的字段

df = dataset[["id","title","description"]]
df["features"] = df["title"] + " " + df["description"]

features本质上是我们将要比较相似性的“文档”。

预处理

接下来,我们删除功能 ie 中不需要的文本。电子邮件地址和网址不能提供大量信息:

df.features = df.features.str.replace(r"[\n\r\t]+", " ")
df.features = df.features.str.replace(r"([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})", " ")
df.features = df.features.str.replace(r"((http[s]?|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?", " ")

审判

接下来的部分是问题的核心。我还跳过了一些代码,因为它们对我来说是探索性的代码。

首先是一些有用的函数:

第一个sentance2vector基本上是把一个句子(没错,是拼写错误)转换成 100 维向量来匹配vectors.txt中的单词嵌入。还要注意,我必须跳过词汇表中没有的单词。如果特性中的所有单词都不在词汇表中,这可能很糟糕。我认为情况不会是这样。

接下来是cosineSimilarity函数,它不言自明。

然后,我在数据帧中创建另一列来存储分数 ie。相似性估计并将其初始化为零:

df["score"] = np.zeros(len(df))

接下来是主要计算:

for i in range(0,len(df)):
   vect = sentance2vector(df.iloc[i].features)
   df.iloc[i,4] = cosineSimilarity(vector, vect)

注意:vectordf中第一行features列的矢量版本。

这实际上是计算第一行df相对于所有其他行的相似性。

那么相似度估计有什么好的吗?

为了找到答案,我需要把小麦从谷壳中分离出来。也就是说,只选择相似度高的 bug(我选择的阈值是 0.87)。

df1 = df.loc[df.score > 0.87]df2 = df1[["features","score"]]df2

然后我看了看那些高分的,和“目标”bug 比较:

Quota is not correctly rehydrated on snapshot reload traverseNode in DataTree will never actually traverse the limit nodes properly.

一些得分较高的是:

C Client might not cleanup correctly during close I was looking through the c-client code and noticed a situation where a counter can be incorrectly incremented and a small memory leak can occur.In zookeeper.c : add_completion(), if close_requested is true, then the completion will not be queued. But at the end, outstanding_sync is still incremented and free() never called on the newly allocated completion_list_t. I will submit for review a diff that I believe corrects this issue.andThe last logged zxid calculated by zookeeper servers could cause problems in leader election if data gets corrupted. It is possible that the last loggged zxid as reported by all the servers during leader election is not the last zxid that the server can upload data to. It is very much possible that some transaction or snapshot gets corrupted and the servers actually do not have valid data till last logged zxid. We need to make sure that what the servers report as there last logged zxid, they are able to load data till that zxid.

这还不错。第一个处理数据结构问题,目标也是如此。第二个与一些数据处理的过程问题有关,目标也是如此。

所以问题来了:在传统的 ML 中,你有一个标记数据集,你把它分成训练/测试子集,并使用测试子集来评估你的算法执行得有多好。在这种情况下,除非你非常熟悉 bug,否则执行评估真的非常具有挑战性。执行评估的一个简单方法是部署它,使用它,并有一种方法对算法进行评分(这个想法类似于 A/B 测试)。

部署

使这个算法可部署的一个简单方法是将其构建为 Docker 容器,并将其发布在 Docker 注册表上。在以前的文章(参见“构建可部署模型”一节)中,我描述了 octopus2 项目的步骤。对于墨鱼来说,步骤几乎是一样的,除了这里,我没有自己构建app.py,而是使用了我开发的一种方法,首先将app.py原型化为 Jupyter 笔记本,然后将其转换为容器的app.py

构建过程

我将首先从高级构建过程开始。为此,我们应该查看.gitlab-ci.yml文件:

构建主要有两个阶段:(a)从Cuttlefish.ipynb构建app.py;以及(b)构建和部署 Docker 容器。

(b)是一个漂亮的锅炉板,在前面的文章中也有描述。(a)基本上只是用nbconvert把笔记本转换成app.py,用remove_lines.py去掉不想要的代码(稍后再解释)。

墨鱼网

如果你仔细看看这个笔记本,你会注意到它几乎是一个清理过的TextSimilarityExplorations.ipynb版本。还有额外的标准 Flask 代码使它成为一个 API,差不多就是这样。

注意所有的# START REMOVE# END REMOVE。这些是为了让remove_lines.py知道删除哪些代码块。共有 3 个代码块:(a)第pip install部分(b)第app.run()部分。(b)适合作为笔记本测试代码,但不适合作为 Docker 容器部署。这将需要:

app.run(host='0.0.0.0', port='33')

运行发动机

我们终于到了有趣的部分!第一部分是做一个这样的docker run:

docker run --publish 5000:33 --name cuttlefish foohm71/cuttlefish:master

接下来我们给你一个选择:使用笔记本调用 API(testing.ipynb)或者运行脚本(test.sh)。两个人都很直率。test.sh只是一个使用test.json中有效负载的 curl,testing.ipynb只是使用requests对 API 进行同样的调用。

repo 上的README.md也描述了有效载荷格式:

仅此而已。我希望您发现这很有用!

(对于那些希望在 GCP 或 AWS 上部署这个的人来说,README.md有一些关于如何做的提示)

参考

[1]词嵌入,machead101,2017 年 7 月,【https://youtu.be/5PL0TmQhItY

[2]文本相似度:估计两个文本的相似程度,阿德里安·锡格河,2018 年 7 月,https://medium . com/@ adriensieg/Text-Similarities-da 019229 c894

[3]结合单词嵌入形成文档嵌入,Yatin Vij,2019 年 9 月,https://www . analyticsvidhya . com/blog/2020/08/top-4-sentence-embedding-techniques-using-python/

用 Python 中的 Scikit Learn 构建人脸识别系统

原文:https://towardsdatascience.com/building-a-face-recognition-system-using-scikit-learn-in-python-163fd423513b?source=collection_archive---------3-----------------------

计算机视觉

使用 Insightface 嵌入比较人脸

图片由 Gerd AltmannPixabay 拍摄

什么是人脸识别?

人脸识别的任务是将一个未知人的脸与数据库中存储的图像进行比较。映射可以是一对一或一对多,这取决于我们运行的是人脸验证还是人脸识别。

在本教程中,我们感兴趣的是建立一个面部识别系统,该系统将验证图像(通常称为探针图像)是否存在于预先存在的面部数据库(通常称为评估集)中。

直觉

建立这样一个系统有四个主要步骤:

1.检测图像中的人脸

可用的人脸检测模型有 MTCNN、FaceNet、Dlib 等。

2.裁剪和对齐面以获得一致性

OpenCV 库提供了这一步所需的所有工具。

3.找到每个面的矢量表示

由于程序不能直接处理 jpg 或 png 文件,我们需要某种方法将图像转换成数字。在本教程中,我们将使用 Insightface 模型为人脸创建多维(512-d)嵌入,从而封装与人脸相关的有用的语义信息。

为了使用一个库来处理这三个步骤,我们将使用insightface。特别是,我们将使用 Insightface 的 ArcFace 模型。

InsightFace 是一个开源的深度人脸分析模型,用于人脸识别、人脸检测和人脸对齐任务。

4.比较嵌入

一旦我们将每个独特的脸转换成一个向量,比较脸的本质归结为比较相应的嵌入。我们将利用这些嵌入来训练一个 sci-kit 学习模型。

附:如果你想跟随,代码可以在Github上找到。

设置

创建虚拟环境(可选):

python3 -m venv face_search_env

激活此环境:

source face_search_env/bin/activate

此环境中的必要安装:

pip install mxnet==1.8.0.post0
pip install -U insightface==0.2.1
pip install onnx==1.10.1
pip install onnxruntime==1.8.1

更重要的是,一旦完成 pip 安装insightface:

-从 onedrive 下载羚羊车型发布。(它包含两个用于检测和识别的预训练模型)。
-放在*~/.insightface/models/*下,所以*~/.insightface/models/antelope/*.onnx*有 onnx 款。

如果设置正确,应该是这样的:

如果你在antelope目录中查找,你会找到两个用于人脸检测和识别的onnx模型:

注意:自从上周最新发布的 *insightface* 0.4.1 以来,安装并不像我希望的那样简单(至少对我来说是这样)。因此,我将在本教程中使用 0.2.1。以后我会相应更新 Github 上的代码。如果你卡住了,请看这里的说明https://github.com/deepinsight/insightface/issues/891#issue-489506780

资料组

我们将使用 Kaggle 上可用的耶鲁人脸数据集,该数据集包含 15 个人的大约 165 幅灰度图像(即每个身份 11 幅独特的图像)。这些图像由各种各样的表情、姿势和照明配置组成。

一旦你有了数据集,继续把它解压到你的项目中新创建的data目录中(参见 Github 上的项目目录结构)。

让我们开始吧…

如果你想跟随,Jupyter 笔记本可以在 Github 上找到。

进口

*import os
import pickle
import numpy as np
from PIL import Image
from typing import List
from tqdm import tqdm

from insightface.app import FaceAnalysis
from sklearn.neighbors import NearestNeighbors*

加载 Insightface 模型

一旦insightface安装完毕,我们必须调用app=FaceAnalysis(name="model_name")来加载模型。

因为我们将onnx模型存储在羚羊目录中:

*app = FaceAnalysis(name="antelope")
app.prepare(ctx_id=0, det_size=(640, 640))*

生成 Insightface 嵌入

使用insightface模型为图像生成嵌入非常简单。例如:

**# Generating embeddings for an image*img_emb_results = app.get(np.asarray(img))
img_emb = img_emb_results[0].embedding
img_emb.shape------------OUTPUT---------------
(512,)*

资料组

在使用这个数据集之前,我们必须修复目录中文件的扩展名,使文件名以.gif结尾。(或.jpg.png等)。

例如,下面的代码片段将把文件名subject01.glasses改为subject01_glasses.gif

接下来,我们将数据分为评估集和探测集:每个受试者的 90%或 10 张图像将成为评估集的一部分,剩余的 10%或每个受试者的 1 张图像将用于探测集中。

为了避免采样偏差,将使用名为create_probe_eval_set()的辅助功能随机选择每个对象的探头图像。它将包含属于特定主题的 11 个图像(的文件名)的列表作为输入,并返回长度为 1 和 10 的两个列表。前者包含用于探针组的文件名,而后者包含用于评估组的文件名。

生成嵌入

create_probe_eval_set()返回的两个列表被顺序地提供给一个叫做generate_embs()的帮助函数。对于列表中的每个文件名,它读取灰度图像,将其转换为 RGB,计算相应的嵌入,最后返回嵌入和图像标签(从文件名中提取)。

现在我们有了一个生成嵌入的框架,让我们继续使用generate_embs()为探针和评估集创建嵌入。

需要考虑的事情很少:

  • os.listdir()返回的文件是完全随机的,因此第 3 行的排序很重要。为什么我们需要排序的文件名?记住第 11 行的create_probe_eval_set()要求在任何一次迭代中所有文件都属于一个特定的主题。

**

os.listdir()的输出,不排序(左)和排序(右)

  • 可选如果我们使用sklearn提供的分层* train_test_split功能,我们可以替换create_probe_eval_set()功能,去掉for循环,并简化上面代码片段中的几行代码。然而,对于本教程,我认为清晰比代码简单更重要。*

通常,insightface无法检测到人脸,并随后为其生成空嵌入。这解释了为什么probe_seteval_set列表中的一些条目可能是空的。重要的是,我们要过滤掉它们,只保留非空值。

为此,我们创建了另一个名为filter_empty_embs()的助手函数:

它将图像集(或者是probe_set或者是eval_set)作为输入,并移除那些insightface不能生成嵌入的元素(见第 6 行)。在此之后,它还更新标签(或者是probe_labels或者是eval_labels)(见第 7 行),使得集合和标签具有相同的长度。

最后,我们可以仅获得在评估集和探测集中的良好指数的 512-d 嵌入:

***assert** len(evaluation_embs) == len(evaluation_labels)
**assert** len(probe_embs) == len(probe_labels)*

有了这两个数据集,我们现在准备使用 Sklearn 库中实现的一种流行的无监督学习方法来构建我们的人脸识别系统。

创建人脸识别系统

我们使用评估嵌入为X.fit()来训练最近邻模型。对于无监督的最近邻学习来说,这是一种巧妙的技术。

最近邻方法允许我们找到距离新点最近的预定数量的训练样本。

注意:一般来说,距离可以是任何度量标准,例如欧几里德、曼哈顿、余弦、M inkowski、*等。*

因为我们正在实现一个无监督的学习方法,请注意,我们没有向fit方法传递任何标签,即evaluation_label。我们在这里所做的就是将评价集中的人脸嵌入映射到一个潜在空间。

**为什么??,你问。
简单回答:通过提前将训练集存储在内存中,我们能够在推理时间内加快对其最近邻居的搜索。

这是怎么做到的?
简单回答:在内存中以优化的方式存储树非常有用,特别是当训练集很大并且搜索新点的邻居变得计算量很大时。

基于邻居的方法被称为非一般化机器学习方法,因为它们简单地“记住”所有的训练数据(可能被转换成快速索引结构,如球树或 KD 树)。 [ 来源

注:见 Stackoverflow 讨论如果你还不服气!

推理

对于每个新的探针图像,我们可以通过使用nn.neighbours()方法搜索它的顶部 k 邻居来发现它是否存在于评估集中。举个例子,

*# Example inference on test imagedists, inds = nn.kneighbors(X = probe_img_emb.reshape(1,-1),
                            n_neighbors = 3,
                            return_distances = True
                            )*

如果评估集中返回的索引(inds)处的标签与探测图像的原始/真实标签完全匹配,那么我们知道我们已经在验证系统中找到了我们的脸。

我们已经将上述逻辑包装到了print_ID_results()方法中。它将探头图像路径、评估集标签和verbose标志作为输入,以指定是否应该显示详细的结果。

这里需要注意一些重要的事情:

  • inds包含evaluation_labels集合中最近邻居的索引(第 6 行)。例如,inds = [[2,0,11]]表示发现evaluation_labels中索引=2 处的标签最接近探头图像,随后是索引= 0 处的标签。
  • 由于对于任何图像,nn.neighbors将返回非空响应,如果返回的距离小于或等于 0.6(第 12 行),我们必须仅将这些结果视为面部 ID 匹配。(p . s . 0.6 的选择完全是任意的)。
    例如,继续上面的例子,其中inds = [[2,0, 11]]和假设dists = [[0.4, 0.6, 0.9]],我们将只考虑索引=2 和索引= 0 处的标签(在evaluation_labels中)作为真正的面部匹配,因为最后一个邻居的dist对于它来说太大而不是真正的匹配。

作为快速检查,让我们看看当我们输入一个婴儿的脸作为探测图像时系统的反应。不出所料,它显示没有找到匹配的面孔!然而,我们将verbose设置为 True,因此我们可以在数据库中看到其最近邻居的标签和距离,所有这些看起来都相当大(> 0.8)。

评估人脸识别系统

测试该系统是否好的方法之一是查看在前 k 个邻居中有多少相关结果。相关结果是真实标签与预测标签相匹配的结果。该度量通常被称为 k 处的精度,其中 k 是预先确定的。**

例如,从探针集中选择一个图像(或者更确切地说是一个嵌入),其真实标签为“subject01”。如果nn.neighbors为该图像返回的前两个pred_labels为['subject01 ',' subject01'],则表示k=2在 k (p@k)处的精度为 100%。同样,如果pred_labels中只有一个值等于‘subject 05’,p@k 就是 50%,以此类推…

*dists, inds = nn.kneighbors(X=probe_embs_example.reshape(1, -1),
                            n_neighbors=2,
                            return_distance=True)pred_labels = [evaluation_labels[i] for i in inds[0] ]
pred_labels----- OUTPUT ------['002', '002']*

让我们继续计算整个探针组的平均p@k值:

厉害!90%不算太差,但肯定可以改进(但那是另一次)…

你能坚持到底,我向你致敬!希望这篇热情洋溢的关于人脸识别的介绍足以让你入门,人脸识别是计算机视觉研究的一个活跃领域。一如既往,如果有更简单的方法来做我在本文中提到的一些事情,请让我知道。

直到下次:)

在 Django 中构建数据输入的快速 Web 界面

原文:https://towardsdatascience.com/building-a-fast-web-interface-in-django-for-data-entry-62f24947ef23?source=collection_archive---------11-----------------------

数据输入

关于如何安装 Django 并利用它快速构建数据输入的 Web 界面的教程

图片来自 PixabayInnova Labs

在本文中,我描述了一个在 Django 中为数据输入构建快速 Web 界面的简单策略。本文涵盖以下主题:

  • Django 概述
  • 安装 Django
  • 创建新项目
  • 创建新应用程序
  • 创建您的数据库
  • 构建数据输入 Web 界面

1 Django 概述

Django 是一个 Python Web 框架,旨在构建快速 Web 应用程序。Django 的一个实例叫做项目。一个项目可能包含一个或多个应用

Django 遵循模型-模板-视图(MTV)架构。MTV 与模型-视图-控制器(MVC)架构的不同之处在于控制器部分已经由框架本身通过模板实现。

Django MTV 架构由以下组件组成:

  • 模型:定义逻辑数据结构。实际上,模型是一个 Python 类,它代表数据库中的一个表。所有表示数据库逻辑结构的类都存储在一个名为 models.py 的脚本中。
  • 视图:它定义了业务逻辑,也就是说,它与模型进行通信,并将其转换成模板可读的格式。视图是一个 Python 函数,它将请求作为输入,并将 Web 响应作为输出返回。所有代表业务逻辑的功能都存储在一个名为 views.py 的脚本中。
  • 模板:定义一个文件的结构或者布局,比如 HTML 文件。它是通过 Django 模板语言编码的文本文档或 Python 字符串。所有的模板都存放在名为 templates 的 App 的子目录下。

下图展示了 Django MTV 架构以及模型、模板和视图组件之间的交互方式:

作者图片

2 安装 Django

首先,必须通过以下命令安装 Django 库:

pip3 install django

您可以决定将它直接安装在您的主工作环境中,或者安装到一个特定的virtualenv中。本文解释了如何构建一个 Python virtualenv

在创建新项目之前,必须配置关联的数据库。因此,你的机器上必须有一个正在运行的关系数据库(如 MySQL 或 Postgres)。我个人安装了 MySQL 服务器。由于我有一个旧的安装 XAMPP ,我已经利用了它提供的 MySQL 服务器。在 PhPMyAdmin 中,我创建了一个名为 mywebsite_db 的数据库,最初为空。姜戈会填充它。

为了与 SQL 服务器通信,Django 需要一个用于 SQL 的 Python 驱动程序。在 MySQL 的情况下,你应该安装mysqlclient Python 库。

根据您的操作系统,您可能会遇到一些安装问题,尤其是当您的操作系统非常旧的时候。就我个人而言,我在安装mysqlclient库时遇到了一些问题,通过遵循链接中提出的建议,我克服了这些问题。

在接下来的部分中,我将概述如何构建和运行 Django 应用程序。更多细节可以参考 Django 官方文档

3 开始一个新项目

一个 Django 网站实例被称为项目。在一个项目中,您可以运行许多 Web 应用程序。你可以使用 django-admin 工具创建一个新项目:

django-admin startproject mywebsite

其中 mywebsite 是您项目的名称。这个命令将在您运行前一个命令的文件夹中创建一个名为 mywebsite 的新目录。

作者图片

文件夹 mywebsites 包含两个元素:

  • manage.py,这是用于配置的主脚本
  • 与您的项目同名的文件夹(inner mywebsite )。

左图显示了内部 mywebsite 文件夹的内容。

在运行新项目之前,您必须在内部mywebsite/settings.py脚本中配置数据库参数,如下所示:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '*mywebsite_db*',
        'USER': 'root',
        'PASSWORD' : 'YOUR PASSWORD'
    }
}

您可以使用 manage.pyrunserver命令从这个文件夹中运行开发 Web 服务器:

cd mywebsite
python3 manage.py runserver

4 启动新的应用程序

在一个项目中,你可以随心所欲地运行应用程序。为了创建应用程序,您可以进入项目文件夹并运行以下命令:

python3 manage.py startapp myapp

其中 myapp 是应用名称。

注意,一旦创建了一个项目,对它的所有操作都将通过 **manage.py** 脚本来完成,例如 startappmigrate (您将在本文后面读到,等等)。

如果你想激活新的应用程序,你必须把它添加到活动应用程序列表中,包含在内部mywebsite/setting.py脚本中。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    **# Add you new application,
    '****myapp.apps.MyappConfig****'**
]

现在你必须告诉网络服务器一个新的应用程序已经被添加。你可以通过migrate命令来完成。您可以从项目的根目录启动它:

python3 manage.py migrate

5 创建您的数据库

现在环境准备好了。你可以专注于内容,在数据模型网站展示方面。

可以在以下文件中修改模型:

myapp/models.py

数据库中的每个表对应于模型中的一个类。例如,该表可以很容易地转换成下面的模型。

作者图片

**from** **django.db** **import** models

**class** **Person**(models.Model):
    Name = models.CharField(max_length=64)
    Surname = models.CharField(max_length=64)
    BirthDate = models.DateTimeField()
    Sex = models.CharField(max_length=1)

该模型独立于特定的 SQL 数据库,因此可以由 Django 翻译成任何 SQL 数据库(MySQL、Postgres……)

一旦创建了模型,您必须告诉 Django 您已经对您的模型做了一些更改。这可以通过makemigrations命令完成,然后是migrate命令,该命令应用所有尚未应用的迁移:

python3 manage.py makemigrations myapp
python3 manage.py migrate

6 构建数据输入 Web 界面

为了创建 Web 界面,您可以利用基于管理界面的 Django 功能。您可以通过以下命令激活管理界面:

python3 manage.py **createsuperuser**

现在,您必须授予管理员对所有模型类的访问权限。这可以通过编辑myapp/admin.py脚本来完成。您应该为希望授予管理员访问权限的每个表添加一个注册选项:

**from** **django.contrib** **import** admin

**from** **.models** **import** Person

admin.site.register(Person)

管理界面将在以下地址可用:http://127 . 0 . 0 . 1:8000/admin/。它看起来将如下所示:

作者图片

那都是乡亲们!

摘要

在本文中,我描述了如何在 Django 中为数据输入构建一个快速的 Web 界面。在环境的初始设置之后,部署 Web 界面非常简单,因为它可以利用 Django 提供的管理界面。

而你,你利用哪个框架来构建快速的 Web 界面?给我留言吧!我很乐意听听你的意见!

如果你已经走了这么远来阅读,对我来说今天已经很多了。谢谢!你可以在这篇文章中读到更多关于我的信息。

如果你想更多地了解 Django 是如何工作的,你可以阅读这篇有趣的文章,作者里努·古尔,他解释了 Django 的 MTV 架构。

相关文章

https://pub.towardsai.net/building-a-fast-interactive-dashboard-in-jupyter-through-gradio-95a1981772aa

离开前再多说一句:你可以从我的 Github 库:)下载本教程的完整代码

新到中?您可以每月订阅几美元,并解锁无限的文章— 单击此处

构建一个完全部署的太阳能计算器应用程序来模拟为您的家庭节省成本

原文:https://towardsdatascience.com/building-a-fully-deployed-solar-calculator-app-to-simulate-cost-savings-for-your-home-over-the-3d5f464824c0?source=collection_archive---------6-----------------------

实践教程

构建生产级太阳能计算器应用程序的过程,包括 Python 模拟、D3.js 可视化、用 Javascript 编写的交互式绘图工具、PostgreSQL 后端等等。

照片由玛格利特·波林德Unsplash 上拍摄

几个月前,我完成了纽约城市大学专业研究学院的数据科学硕士学位。我写了一篇关于我决定攻读数据科学研究生学位的深入文章,并权衡了在该领域采用更传统的学习和发展方法的利弊。如果你对这个话题感兴趣,或者你自己正在努力做这个决定,请在这里随意阅读。

在这篇文章中,我将讨论我作为研究生的最后几个月,通过一个太阳能计算器顶点项目进行讨论,这个项目是我和一个城市大学 SPS 的学生一起开发的。鉴于项目的复杂性(以及我们缩短的三个月时间表),我们决定将开发的主要部分分成两个子项目:

  1. 开发和编写一个 Python 模拟,根据用户输入到我们的应用程序中的特定输入来估计用户家庭的太阳能发电量,并将其扩展以衡量 15 年内的成本节约。
  2. 开发和部署完整的基于 web 的应用程序以及我们的 Python 模拟、Flask 框架、前端 JavaScript 绘图工具和 PostgreSQL 后端背后的工程。

因为我承担了第二个子项目的大部分工作,所以我将在本文中更详细地介绍这个过程。但是,如果您对模拟计算、我们用于创建这些预测的数据以及关于我们整体研究/发现的更多信息感兴趣,请随时在 Youtube 上观看我们的最终演示视频:

我们最终的顶点演示视频,提供了我们工作的背景,并概述了我们项目的所有组成部分|作者视频

初始研究和动机

在美国,在过去的 25 年里,在住宅屋顶安装太阳能电池板的势头越来越猛。利用太阳能为家庭供电不仅有助于减轻气候变化的影响,而且随着时间的推移,还可以为住宅消费者节省大量资金。不幸的是,根据 2019 年的皮尤调查,只有 6%的美国房主表示他们已经在家里安装了太阳能电池板。

由于这个紧缩的统计数据,我们真的很有兴趣了解更多关于当前太阳能市场的情况,以及在美国发展的一些障碍。我们发现,尽管消费者犹豫的原因很多,但其中一个主要原因是面板安装的前期成本。根据你需要为你的家提供足够电力的太阳能电池阵列的大小,安装费可能在 10,000 美元到 25,000 美元之间(税收优惠前)。对许多人来说,这个成本有点令人望而生畏。然而,重要的是要明白,一旦你投资了太阳能,你就从当地的电网服务提供商那里获得了大量的能源独立,同时也大大降低了你每月的能源费用。随着时间的推移,您每月节省的电费可能会抵消安装的初始成本。因此,我们认为,如果我们能够构建一个应用程序,将这一点有效地传达给公众,我们也许能够说服那些“犹豫不决”的人进行初始投资。

发展我们的目标

最终,我们的应用程序的目标变成了一个工具,旨在更好地告知纽约奥尔巴尼的居民将他们的住宅转换为太阳能的财务收益,并明确他们何时可能期望达到“收支平衡”点,即他们在家中安装电池板的初始投资成本将被他们通过停止常规电网服务节省的能源抵消。

为了做到这一点,我们需要开发一个 15 年的能源成本模拟,其中考虑了用户房屋的许多组成部分(即房屋的总面积、屋顶表面积、房屋建造年份、家庭成员人数等)。),以及他们的屋顶通常接受的阳光照射量(具体取决于房屋的纬度/经度和屋顶方向)。然后,我们将获取这些数据,通过我们的模拟运行这些数据,计算一个面板系统可以产生的能量,并将其与同一时期的电网服务成本进行比较。

尽管我们希望将来将该项目扩展到其他地区,但考虑到缩短的时间表和能源使用/成本数据的限制,我们不得不将地理范围缩小到奥尔巴尼大都市区。

解决围绕应用功能的问题

你可能在想…好吧,这听起来是一个很酷的项目,但是你实际上如何构建这个应用程序呢?为了完成这一过程,我们必须解决一些关于应用程序功能的重要问题:

  • 对于我们应用程序的用户来说,我们需要为他们特定的家庭获取大量的输入。我们如何设计一个用户界面,允许用户输入他们特定家庭的所有必要信息?

回答:在 Javascript/Typescript 中构建一个包含有角度的材质表单的用户界面,获取用户输入。然后,我们可以将这些信息从应用程序的前端发送到后端 PostgreSQL 数据库。这些数据的交换可以通过 Python 和 Flask 作为 API 端点来处理。

  • 对于不知道房屋面积的用户,或者想要调查屋顶面板的不同面积计算,我们如何让他们进一步调查并确保他们给出准确的估计?

回答:我们可以利用 Google Maps API 在页面加载中显示特定地址的用户住宅的航拍面积,然后覆盖一个平方英尺绘图工具/计算器(内置于 JavaScript 中),以允许用户绘制/确定其住宅的正确平方英尺估算值(参见下面的最终产品截图示例)。

  • 我们如何在部署环境中运行我们的太阳能计算器评估和脚本?

答:我们可以利用 Heroku dynos 和云计算在部署的环境中运行这些脚本,最终可以连接到我们的前端和后端环境。通过 Flask 端点触发这些脚本,dynos 就可以执行这些脚本并运行我们的函数。

  • 我们如何帮助用户可视化他们的成本节约?

回答:由于我们的 UI 将在 Javascript/Typescript 中构建,我们可以使用 D3.js 库创建视觉效果。我们可以展示从我们 15 年的模拟中得出的估计值,并与奥尔巴尼地区坚持常规电网服务的成本进行比较,以显示潜在客户的房屋何时能够从最初的太阳能电池板安装投资中“收支平衡”。

应用程序是如何设计的

在确定了这些大问题的解决方案并制定了最终的项目目标后,我们决定开始构建。经过大约两个月的紧张开发,我们提出了一个可行的解决方案。这里有一个图表和它是如何工作的简要概述:

开发框架和基础设施|作者图片

使用的编程语言、云资源和库 —该应用程序拥有完全托管的前端和后端基础架构。应用程序的后端部分是用 Python 构建的,并利用 Flask 库来服务一系列连接到我们前端系统的 HTTP 端点。运行在 Flask API 上的 Python 脚本执行关键功能,将用户输入数据从前端连接到 PostgreSQL 数据库,并在用户导航应用程序时管理 POST 和 GET 请求。这个后端系统完全由 Heroku 托管和管理。前端基础设施是用 Typescript 和 JavaScript 编写的,并利用 Angular JavaScript 框架来设计组件的样式,管理表单中的用户输入,创建与 Google Maps API 的交互,并为我们的 D3.js 可视化和仪表板提供画布。

应用程序如何工作

在页面加载时,用户看到的初始页面是一个请求家庭地址的表单。该表单链接到 Google Maps API,并在用户开始输入时提供自动填充选项,这些选项在地理上是有界限的,并限制在我们定义的纽约奥尔巴尼中心周围 0.1 度的纬度和经度(纬度 42.6526 度,-经度 73.7562 度)。这是为了确保我们的应用程序能够提供准确的估计,因为我们正在利用奥尔巴尼地区的特定数据,包括我们的太阳辐射数据/计算以及能源使用信息。

当输入奥尔巴尼特定的地址时,应用程序将打开一个表单,允许用户输入用于我们模拟的其他重要因素,包括估计的房屋面积、房屋建造年份、居住在房屋中的家庭成员数量、屋顶方向,以及估计适合他们屋顶的太阳能电池阵列的大小。为了帮助这些输入(特别是屋顶方向和太阳能电池阵列大小),我们创建了一个交互式绘图工具,允许用户直接在他们屋顶的航拍图像上计算他们预期的太阳能电池板阵列的面积。因为居住在用户家中的家庭成员数量是可变的,所以我们也提供了一个输入字段来获取该信息。一旦在表单中识别并确认了所有输入,就会显示一个最终的交互式地图和绘图工具,要求用户识别他们的屋顶相对于南纬的方位,最终从用户那里收集方位角。

JavaScript 内置的自定义绘图工具,覆盖谷歌地图以测量用户屋顶的平方英尺|作者图片

在这些输入完成之后,然后向用户提供所有计算/输入信息的汇总表。此表为用户提供了最后一次机会来查看我们的模型计算中将使用的数字,并纠正任何看似错误的内容。

确认用户输入和收集数据的最终汇总表-一旦用户确认,这些字段将用于创建成本估算|按作者分类的图像

当用户确认这些值时,前三个数字用于计算与美国东北部地区的平均数字相比的家庭能源使用的预计比率。然后,该比率用于向用户提供估计的平均每月能源账单,用户可以调整该比率以定制模拟中使用的比率,并确保该比率更接近他们的能源使用。

估计的平均月账单是通过用户和/或作者的 Realtor.com |图片提供的上述住房信息计算出来的

当用户准备好了,并且平均每月能源账单估计似乎正确时,应用程序运行模拟并提供概述和总结结果的可视化。此外,该应用程序提供了四种不同的场景,根据我们的研究,将效率和初始投资的两个极端值配对。每一个可视化都提供了一种额外的方式来观察所讨论的太阳能电池板系统的预计性能。

D3.js 可视化和摘要

我们使用 D3.js 库创建,内置翻转功能、工具提示和其他数据可视化最佳实践,使用户可以访问这些指标。

可视化 1 内置于 D3.js |作者图片

可视化#1: 显示了如果您放弃一个太阳能电池板系统,您预计要支付的长期(15 年)费用,以及您对所选太阳能系统的现金支出的估计。两条线的交点是你开始省钱的时间点,与没有面板系统的情况相比。鼠标悬停事件和工具提示会显示相对于最初 15 年太阳能投资的预计成本。

D3.js 中内置的可视化 2 |作者图片

可视化#2: 显示了预计的太阳能财务前景和估算的无太阳能电力成本之间的差异。从亏损到盈利的转变发生在第一张图中两条线相交的那一年,而每个条形表示给定年份之后的财务增量。相对于如果你的整个能源系统依赖常规电网服务你将支付的费用,条形图从负值变为正值的那一年,是你预期达到盈亏平衡点的时候。鼠标悬停事件也可用于查看自太阳能安装以来每年的相关增量计算。

D3.js 中内置的可视化 3 |作者图片

可视化#3: 在这张特殊的图表中,我们提供了高效率和低效率系统的预计每月产量的快照。覆盖在其上的是一条线,显示估计的每月能源使用量,左轴显示千瓦时,右轴显示每月成本(基于纽约州奥尔巴尼市 11.74/千瓦时的价格)。如果需要的话,这里可以使用鼠标悬停事件来隐藏特定的效率,以便为用户提供更好的清晰度。

提供不同的面板和成本方案

虽然这些可视化本身很有趣,但我们也想为用户提供一些不同的选项。由于成本预测和“盈亏平衡”范围在很大程度上受电池板安装的初始成本以及安装的太阳能电池板的效率的影响,我们希望展示一系列可能发生的情况。通过在场景中循环,用户可以很好地了解模拟中的变化。为这些场景选择的范围(初始安装成本为 12,000 美元或 20,000 美元,电池板效率为 15%或 19%)基于我们的研究和当前太阳能市场的可接受标准。

可视化效果根据为初始面板安装成本和面板效率选择的方案动态更新|图片由作者提供

结论

最后,应用程序很好地组合在一起,但是我们还有很多工作要做。我们能够创建一个用户界面和应用程序,让用户调查转换到太阳能的好处,并展示随着时间的推移进行转换的财务收益。然而,最重要的是,该应用程序针对个人的家庭,为每个用户提供了更现实的时间表。我们很高兴地看到,当我们将我们的许多模拟计算与其他领先工具(如谷歌的项目天窗)进行比较时,我们的“盈亏平衡”估计正好在他们自己的预测范围内。

最终,我们希望将这个项目扩展到更大的地理区域。虽然该应用程序目前只适用于纽约州奥尔巴尼地区,但我们认为它有潜力扩展到更广泛的受众。如果任何人有兴趣在这个持续的项目上合作,请不要犹豫联系我们!

如果您想亲自试用该应用程序,您可以访问此处:

(警告:由于成本限制,自最初发布以来,我们不得不缩减云基础架构的规模。因此,您可能会经历更长的加载时间)。

如果你喜欢这篇文章,请随意查看我的其他帖子。此外,我创建了一个数据科学作品集,您可以在这里查看。我的投资组合也有我的联系方式,如果你想接触这个项目或任何其他人!

用 PyTorch 构建 GAN

原文:https://towardsdatascience.com/building-a-gan-with-pytorch-237b4b07ca9a?source=collection_archive---------5-----------------------

凭空产生逼真的图像?

Goodfellow 等人在 2014 年提出的生成对抗网络(GANs)彻底改变了计算机视觉中图像生成的一个领域——没有人能相信这些令人惊叹和生动的图像实际上是纯粹由机器生成的。事实上,人们过去认为生成的任务是不可能的,并对甘的力量感到惊讶,因为传统上,根本没有我们可以比较我们生成的图像的地面真相。

本文介绍了创建 GAN 背后的简单直觉,然后通过 PyTorch 实现了一个卷积 GAN 及其训练过程。

甘背后的直觉

与传统分类不同,在传统分类中,我们的网络预测可以直接与真实的正确答案进行比较,生成图像的“正确性”很难定义和测量。Goodfellow 等人在他们的原始论文生成对抗网络,中提出了一个有趣的想法:使用一个训练非常好的分类器来区分生成的图像和实际图像。如果存在这样的分类器,我们可以创建并训练一个生成器网络,直到它能够输出可以完全欺骗分类器的图像。

图一。甘的管道。作者创建的图像。

GAN 是这一过程的产物:它包含一个基于给定数据集生成图像的生成器,以及一个用于区分图像是真实图像还是生成图像的鉴别器(分类器)。GAN 的详细流水线如图 1 所示。

损失函数

优化发生器和鉴别器都很困难,因为正如你可能想象的那样,这两个网络有着完全相反的目标:发生器希望创造尽可能真实的东西,但鉴别器希望区分产生的材料。

为了说明这一点,我们让 D(x) 是来自鉴别器的输出,这是 x 是真实图像的概率, G(z) 是我们的生成器的输出。鉴别器类似于二元分类器,因此鉴别器的目标是最大化功能:

本质上是没有负号的二元交叉熵损失。另一方面,生成器的目标是最小化鉴别器做出正确决定的机会,因此它的目标是最小化函数。因此,最终的损失函数将是两个分类器之间的极小最大博弈,可以如下所示:

这将在理论上收敛到以 0.5 的概率预测一切的鉴别器。

然而,在实践中,极大极小游戏通常会导致网络不收敛,因此仔细调整训练过程是很重要的。学习率等超参数在训练 GAN 时更为重要——微小的变化都可能导致 GAN 产生单一输出,而不管输入噪声如何。

计算环境

图书馆

整个程序是通过 PyTorch 库(包括 torchvision)构建的。GAN 生成结果的可视化使用 Matplotlib 库绘制。以下代码导入所有库:

资料组

数据集是训练 gan 时的一个重要方面。图像的非结构化本质意味着任何给定的类别(即,狗、猫或手写数字)可以具有可能数据的分布,并且这种分布最终是 GAN 生成的内容的基础。

为了进行演示,本文将使用最简单的 MNIST 数据集,它包含了 60000 个从 0 到 9 的手写数字图像。像 MNIST 这样的非结构化数据集实际上可以在 Graviti 上找到。这是一家年轻的初创公司,希望用非结构化数据集帮助社区,他们在自己的平台上有一些最好的公共非结构化数据集,包括 MNIST。

硬件要求

最好在 GPU 上训练神经网络,因为它们可以显著提高训练速度。但是,如果只有 CPU 可用,您仍然可以测试程序。要让您的程序自己决定硬件,只需使用以下代码:

履行

网络体系结构

由于数字的简单性,两种架构——鉴别器和发生器——由完全连接的层构成。请注意,有时全连接 GAN 比 DCGAN 更容易收敛。

以下是两种架构的 PyTorch 实现:

培养

在训练 GAN 时,我们优化了鉴别器的结果,同时改进了我们的生成器。因此,在每次迭代过程中会有两个相互矛盾的损失来同时优化它们。我们输入到生成器中的是随机噪声,生成器应该根据给定噪声的细微差异来创建图像:

结果

经过 100 个时期后,我们可以绘制数据集,并查看从随机噪声中生成的数字的结果:

图二。GAN 生成的结果。作者创建的图像。

如上所示,生成的结果看起来确实很像真实的结果。考虑到网络相当简单,结果确实看起来很有希望!

不仅仅是内容创作

甘的创作与之前在计算机视觉领域的工作大相径庭。随后出现的大量应用让学术界惊讶于深度网络的能力。一些惊人的工作描述如下。

CycleGAN

Zhu 等人的 CycleGAN 引入了一个概念,该概念将图像从域 X 转换到域 Y 而不需要成对样本。马变成了斑马,夏天的阳光变成了暴风雪,CycleGAN 的结果令人惊讶而准确。

图 3。朱等人展示的 CycleGAN 结果图片来自其 Github 页面。

高根

Nvidia 利用 GAN 的力量,根据画笔的语义,将简单的绘画转换为优雅而逼真的照片。尽管训练资源在计算上很昂贵,但它创造了一个全新的研究和应用领域。

图 3。高干的生成结果。左为原图,右为生成结果。作者创建的图像。

AdvGAN

GANs 还被扩展到清理对立的图像,并将它们转换成不会欺骗分类的干净的例子。更多关于对抗性攻击和防御的信息可以在这里找到。

结论

所以你有它!希望这篇文章提供了如何自己构建 GAN 的概述。完整的实现可以在下面的 Github 资源库中找到:

https://github.com/ttchengab/MnistGAN

感谢您坚持到现在🙏!我会在计算机视觉/深度学习的不同领域发布更多内容。一定要看看我关于计算机视觉方法的其他文章!

在 AWS 上的 Dash 中构建基于图的杂货推荐系统

原文:https://towardsdatascience.com/building-a-graph-based-grocery-recommender-in-dash-on-aws-3d96d262e365?source=collection_archive---------31-----------------------

照片由 PhotoMIX 公司Pexels 拍摄

为了准备最近在一家大型零售商的工作面试,我想接触一些零售数据,同时专注于回答一个现实生活中的商业问题——我们如何才能建立更有利可图的杂货篮。在最近熟悉了 Python 中的 NetworkX 包之后,我看到了一个极好的机会来构建一些视觉上吸引人的和交互式的东西来帮助回答这个问题。这篇文章概述了:

1)阐述商业案例

2)在 NetworkX 中构建图形

3)提出基于图表的建议

4)在 Dash 中创建一个应用程序,并将其部署到 AWS

所有的代码都在我的 GitHub 上。

阐述商业案例

我们怎样才能让购物者在我们店多消费,在其他店少消费?我从这个问题开始,并认为通过可视化数据集中篮子中产品之间的关系,人们可能很容易找到一些产品,这些产品本质上是将其他产品“粘合”在一起的。然后我们可以推测,这些将篮子粘在一起的产品——这些锚定产品——让顾客进入商店,如果我们降低这些商品的价格,我们可以让顾客来我们的商店而不是其他商店。但是为了可持续发展,我们需要在其他地方弥补不足。因此,看一下篮子,我们可以提高不太重要的商品的价格/利润,这些商品不会让顾客进门,但仍然会落在篮子里。最近我发现了 python 中的 NetworkX 包,我认为将食品杂货显示为网络中的节点是一种很好的方式,可以直观地表示篮子中物品之间的关系。

我开始寻找一个数据集,并在 Kaggle 上找到了这个优秀的数据集(随后,我还在 Dunnhumby 上找到了一个优秀的数据集——名为“完整的旅程”——我仍希望能深入其中)。

我认为,观察购买小篮子(底部四分位数,少于 5 件商品)的客户和购买中等尺寸篮子(第二个四分位数,5 至 9 件商品)的客户的图形结构之间的差异也会很有趣。

在网络中构建图形 X

如果我没有首先提到将这些数据显示为图表并不一定是找到主打产品的最佳方式,那将是我的失职。还有其他方法,例如在购物篮分析中使用的 apriori 算法,但是,我真的很想尝试最初从图形可视化中构建洞察力,以及在以后使用图形的结构来构建建议,所以使用了这种方法。另一件要注意的事情是,虽然从逻辑上看,人们也可以只查看哪 20 种产品被购买最多,并将其视为锚定产品,但也有可能有一些产品位于前 1000 名,但不是前 20 名,它们仍然是将许多其他产品粘合在一起的产品。如果你是南非人,篮子里的主打商品可能是你的 braai(烧烤)的 boerewors(一种香肠),但是这种商品不太可能是你的商店最畅销的商品之一,但了解这种杂货商品如何与其他商品结合在一起仍然是有价值的。

NetworkX 的使用非常简单。只要对数据做一点预处理,篮子项目就被视为在同一个篮子中的节点之间创建了边的节点。然后,根据两个项目一起出现在一个篮子中的次数对边进行加权。为了给出一个具体的例子,下图显示了项目的子图,这些子图表示在数据集中带有杏仁的篮子中找到的所有项目,以及这些项目之间的联系。

杏仁出现的杂货子图;作者图片

下面的代码显示了如何构建节点—边—节点对,然后将它们传递给 NetworkX 以创建网络:

瞧,我们有了一个图表网络。最棒的是,我们现在可以看到网络中节点之间的连接。我在这里省略了代码,因为它有点长,但是看一看 GitHub 页面上的 Jupyter 笔记本,就知道如何将这些代码组合在一起了。这里有如此多的数据,以至于我认为这是一个使用 Plotly 构建交互式绘图的理想机会。

小篮子的杂货图表的图像;作者图片

探究这张图表,我们可以看到一些东西。首先,这里有几个非常重要的项目(颜色较深的项目)似乎与大多数其他项目有联系。这些是香蕉和 T2 草莓。现在,回到最初的业务问题,“我们可以用这些信息做什么?”,这表明我们可以考虑降低这些商品的价格,以吸引更多的顾客。现在,如果我们看一下图表“云”之外的商品,例如 l 大鸡蛋,这些是我们可以提高价格(并增加利润)的商品,因为这些商品不太可能是顾客专门来我们商店购买的,但仍然落在许多篮子里。

这里值得注意的是,我期望在网络图中看到不同的聚类模式。我想象会有多个集群,或者网络中的高密度区域,其中某些种类的产品相互连接;然而,事实并非如此。虽然这在一定程度上削弱了以图形网络格式直观探索食品杂货的价值,但构建图形仍然允许人们使用它来创建推荐系统。

构建基于图的推荐系统

对于那些不熟悉推荐系统的人,请查看维基百科页面。虽然诸如协同过滤之类的方法对影响我们许多选择的大量推荐负责,例如网飞推荐,但是基于图的推荐系统也已经在许多应用中使用。在本文中,基于图的推荐器仅仅关注于推荐相似的产品,而没有考虑客户以前购买过什么。对于一篇关于二分图推荐系统(即用户和产品)的优秀文章,请查看本文

我采用了两种方法来构建推荐系统。第一种方法是最明显的,由此推荐系统推荐一个项目的前 K 个邻居,按照当前项目的邻居的边权重排序。第二种方法更有趣,也以稍微不同的方式看待推荐。

第二种方法为图中的每个节点生成一个图嵌入,其中每个节点的嵌入类似于创建词向量时创建的嵌入(如果您不熟悉词向量,请查看这篇精彩的文章)。事实上,用于创建这些嵌入的方法之一使用与创建单词嵌入完全相同的过程来创建节点嵌入。本文中介绍的方法称为深度行走。我是在阅读了这篇关于主题的精彩综述后构建的,这篇综述比我在这里要详细得多。基本上,节点嵌入是通过在网络中选择一个节点,然后从该节点开始进行 k 步随机行走,并记录在网络中访问的每个其他节点来创建的。这 k+1 个节点的选择然后被存储为一个字符串(k+1,因为我们在字符串中包括第一个节点)。在购物清单示例中,假设您从“杏仁”节点开始,那么您可以通过从该节点进行随机遍历来制作一串如下所示的节点:

杏仁->玉米片->初榨橄榄油->香蕉->苹果->柠檬

您将对网络中的每个节点执行此操作 n 次,采取 k 个步骤,并存储所有这些长度为 k+1 的“字符串”,这些“字符串”组成了流程中访问的节点。一旦你有了这些节点串的大小为 k x n 的集合,你就可以使用一个漂亮的包比如 Gensim 来学习这些节点的 Word2Vec 嵌入,而 viola,你已经为你的图形创建了嵌入。下面是这方面的代码,但请记住,这是大量借用自这篇伟大的文章,你应该看看。

现在,从上面的代码中可以看出,查找相似条目的方法很简单,只需使用 Word2Vec 方法。最 _ 相似()。

然而,在比较这里给出的两种推荐方法时,需要考虑一些事情。“最相似”嵌入方法的巧妙之处在于,每个节点的表示捕获节点的上下文信息的方式与 Word2Vec 捕获单词的上下文信息的方式相同。然而,当我们购买鸡汤时,我们可能会对人们用鸡汤购买的其他商品比对上下文相似的商品更感兴趣。当使用这两种方法时,我们最终会得到如下建议:

与杏仁最相似的东西:可乐罐、开心果、葡萄干、芒果干、经典烘焙咖啡、各种减肥茶、盐&胡椒开心果、爆米花

杏仁的近邻:苏打水,香蕉,什锦沙拉,开心果,覆盆子,柠檬,蓝莓,草莓,无籽黄瓜,格兰诺拉麦片

那么,哪个更好呢?很难说。最近的邻居更一般。香蕉、覆盆子和草莓放在很多篮子里,因此,在这种情况下,一些推荐可能不会比推荐顾客无论如何都会购买的普通产品更有价值。最相似嵌入法表明推荐项目与主项目扮演相似的角色(通过它们的上下文嵌入),因此可能互补性较弱,可能更容易互换。

尽管这很有趣,也很好玩,但这表明,为了真正增加价值,基于与其他客户的相似性向客户推荐商品可能是值得的。我看的数据集没有客户层面的数据,但如果你看看这篇文章(如上所述),它提供了一个同时使用客户和商品数据进行推荐的绝佳例子。

创建互动 Dash 应用

虽然 Dash 在许多方面与 R-Shiny 非常相似,但这种差异导致了一个相当尖锐的学习曲线。在用 Flask、JS 和 HTML 开发了一两个小东西之后,我发现 Dash 利用 CSS 的一些方式很难理解——例如,用 CSS 类“六列”代替“列-6 ”,并花了一些时间来理解这一点。虽然我不会在这里对 Dash 应用程序进行过多的详细描述——你可以在我的 GitHub 账户中查看代码——但我会给出一个简单的概述。

Dash 应用的购物清单生成器部分;作者图片

由于 Plotly 和 Dash 合作得非常好,我决定将这个项目转化为一个交互式应用程序,并部署到 AWS。我在 Medium 上找到了这篇精彩的文章,它带我完成了在 AWS 上将一个应用程序上传到 Elastic Beanstalk 的基本步骤,并让我的应用程序毫不费力地运行起来。我不会重述那里写的内容,因为它做得很好,没有必要,但是按照那篇文章,几分钟后你就可以开始了。

关于构建应用程序的过程,需要考虑几件事情。Dash 有一个回调系统,允许您的函数改变页面上的 Dash 对象。尝试用大量动态创建的移动部件做一些事情可能是一个相当大的挑战,尽管一旦你掌握了它,你可以做很多事情。学习曲线很陡,但我认为对于未来的仪表板来说这是值得的。为了防止应用程序在每次加载选项卡或下拉列表改变时都必须重新生成图表,我将图表数据保存为 pickle 文件,对于推荐者选项卡,在页面加载时加载它。这可能不是最佳实践,但它完成了工作。我也不太可能为这个小小的网络应用赢得任何 UX/用户界面奖,但这个想法更多的是建立一些东西和探索一些数据,而不是制作一些看起来完美的东西。

包裹

这个项目确实帮助我开始尝试首先回答一个商业问题,即“我们如何让顾客在我们的商店购买更多的商品”。通过找到一种可视化探索数据的新方法,我能够推翻我最初关于商品聚集在一起的假设——看起来更像是一个像云一样的杂货网络。然而,这让我开始探索使用图表来为产品提供建议,并最终构建了一个基本的 Dash 应用程序来在线探索数据。总的来说,这是一次极好的学习经历,让我有了许多改进的想法:

  • 我们可以构建一个包含客户和订单的图表,根据与其他客户的相似性向客户推荐产品
  • 还有其他方法来创建图嵌入,可以进行探索和比较
  • 将财务(价格和成本)数据添加到分析中,对于了解哪些产品可以涨价以及对整体篮子价值的影响是有价值的

用 Python 构建混合假新闻侦探应用

原文:https://towardsdatascience.com/building-a-hybrid-fake-news-detective-app-with-python-28ba87638ade?source=collection_archive---------16-----------------------

使用无监督 K 均值和有监督支持向量分类器算法的组合

当今世界,网络上到处都是新闻。我们可以在 CNN、BBC News、India Today、NDTV 和 Times of India 等各种新闻网站以及脸书、Twitter 和 Instagram 等社交媒体网站上轻松找到它们,只需轻点鼠标。新闻的目的是让我们了解身边正在发生的事情。

路易斯·科尔特斯在 Unsplash 上的照片

不幸的是,我们今天听到的消息的可信度值得怀疑。有人很容易在社交媒体网站上发布随机的东西,而不验证它是否真实。一些人,特别是政党成员,也可能在社交媒体网站上组建团体,歪曲新闻,恶意传播宣传,误导人们,转移对实际问题的注意力。尽管如此,许多主流新闻频道和报纸还是带着选择性的偏见进行报道,传播针对个人和社区的仇恨、阴谋论,其唯一目的是获得更多的电视收视率或简称为 TRP。也就是说,民主的第四大支柱正在瓦解。

照片由 Nijwam SwargiaryUnsplash 拍摄

新闻来源的可信度在新冠肺炎疫情期间创下新低。这一时期出现了各种错误信息运动,特别是在美国,劝说人们不要遵循 COVID 适当的行为和接种疫苗。因此,在相信这个消息之前,核实事实是必要的。

于是出现了各种事实核查组织,如 Alt News、BOOM 和 Factly,它们核查一篇新闻文章的可靠性。这些组织通过与目击者或有关当局核实,对新闻文章进行人工分类。但是,在许多情况下,他们可以认为反对他们意识形态的新闻文章是假的。所以,这些事实核查网站的可靠性也值得怀疑。因此,我们需要的是一种对新闻标题进行分类的 AI 方式。这在自然语言处理中是可能的。

为什么要混合模式?

现在的问题是,我们应该使用哪种方法。一般情况下,我们使用监督学习算法对新闻进行分类。这种方法有两个问题:

  1. 首先,通常可用的数据集都有新闻标题,这些标题被一些事实核查机构手动标记为真实或虚假。我们永远不能确定这个组织是公正的。
  2. 第二,监督学习算法需要这些标签进行训练。因此,人们最终偏向了分类器,违背了使用人工智能的初衷。

我们必须明白,在极少数情况下,消息肯定是真的或假的。大多数情况下,我们无法确定。所以,我们应该寻找的是,新闻是真是假的概率。

我们将使用的模型是由非监督 K 均值聚类算法监督支持向量分类算法混合而成的。K Means 算法通过捕捉特定单词的用法将新闻标题组织成簇。支持向量算法从这些聚类中学习,并预测未知新闻标题所属的类别。

如果你想了解我的仪表盘是什么样子,请访问 https://fake-news-headlines-detective.herokuapp.com/。

数据来源:

除了我在上一节提到的原因,通常可用的数据集包含来自美国的新闻。因此,我必须自己创建一个数据集,通过收集热门新闻网站的新闻标题进行训练,如《印度时报》、《新闻 18》、《印度快报》和《共和世界》。此外,我还从 Op India、News Punch 和 Great Game India 等纯数字新闻网站收集了这些信息,这些网站被国际事实核查网络(IFCN)视为假新闻网站。

为了训练,我从印度和美国的各种来源收集了 14787 个标题。GitHub 存储库中有这个数据集。同样的链接是https://github.com/pradeepprajan/Fake-News-Detective。您还可以找到包含 Python 代码的 Jupyter 笔记本。

安装必要的软件包:

除了常用的软件包之外,我们还需要安装以下特定于 dashboard 应用程序的软件包:

  1. 自然语言工具包(NLTK)
  2. 海生的
  3. Scikit 学习
  4. Plotly
  5. 破折号
  6. 仪表板引导组件

第 1 部分:用 K-Means 对标题进行聚类

导入必要的库

在开始之前,我们导入必要的库。可以参考我分享过的 GitHub 库中的 Jupyter 笔记本。

数据的读取和预处理:

首先,我们读取收集的训练数据集。因为数据集中的行是按照新闻源排序的,所以我们对它们进行了洗牌。

dataset = pd.read_csv('NewsArticles.csv',encoding='unicode escape')
dataset = dataset.drop(columns=['Unnamed: 0'])
dataset_copy = dataset.copy()
dataset_copy = dataset_copy.sample(frac=1).reset_index(drop=**True**)

一些探索性的数据分析:

我们找到每个来源发布的新闻文章的数量,并构建一个条形图。

news_articles_count = dataset_copy.groupby('Source_code',as_index=**False**).count()
news_articles_count = news_articles_count.rename(columns={'Headlines' : 'Article_Count'})
news_articles_count = news_articles_count.drop(columns='Sources')news_articles_bar_plot = sns.barplot(x=news_articles_count['Source_code'],y=news_articles_count['Article_Count'])

作者图片

创建单词语料库:

现在,我们创建一个单词语料库。在此过程中,我们执行以下操作:

  1. 删除特殊字符,因为它们对我们的模型没什么用。
  2. 将大写字母更改为小写字母,因为我们希望我们的模型将大写和小写的同一个单词识别为一个单词。比如新闻,新闻,新闻,要被算法识别为一个词。
  3. 将标题符号化,即将标题拆分成单词。
  4. 将单词词条化。它将单词转换成有意义的基本形式。

在创建语料库之前,我们安装了 S topwordsPunkt、Wordnet 字典。

lemmatizer = WordNetLemmatizer()
nltk.download('stopwords')
nltk.download('punkt')
nltk.download('wordnet')corpus = []
**for** i **in** range(0,len(dataset_copy)):
message = re.sub('[^a-zA-Z0-9]', ' ', dataset_copy['Headlines'][i])
message = message.lower()
message = word_tokenize(message)
message = [lemmatizer.lemmatize(w) **for** w **in** message **if** **not** w **in** stopwords.words('english')]
message = ' '.join(message)
corpus.append(message)
print(corpus)

将单词库转换成向量:

我们通过 TF-IDF(词频-逆文档频)矢量化将词语料库中的标题转化为向量。此外,我们将每个向量的维数限制为 1000。

tfidf_v = TfidfVectorizer(max_features=1000)
X = tfidf_v.fit_transform(corpus).toarray()

特征缩放:

在执行任何非监督分类之前,特征缩放是必须的

scaler = StandardScaler()
X = scaler.fit_transform(X)

应用 PCA:

因为形成的每个向量的维数是 1000,所以我们应用 PCA。这消除了维数灾难。

pca = PCA(n_components=2)
pca_result = pca.fit_transform(X)

K 均值聚类:

在执行聚类之前,我们需要使用肘方法找出所需的聚类数。

wcss = []
**for** i **in** range(1,20):
 kmeans = cluster.KMeans(n_clusters=i,init='k- means++',max_iter=300,n_init=10,random_state=0)
 kmeans.fit(pca_result)
 wcss.append(kmeans.inertia_)
 print("Cluster", i, "Intertia", kmeans.inertia_)
 plt.plot(range(1,20),wcss)
 plt.title('The Elbow Curve')
 plt.xlabel('Number of clusters')
 plt.ylabel('WCSS')
 plt.show()

作者图片

对应于图中“肘部”的聚类数为 6。因此,我们需要 6 个集群。

现在,我们执行聚类。我们还绘制了一个散点图来证明这一点。

Kmeans = cluster.KMeans(n_clusters=6,init='k-means++',max_iter=500,verbose=**True**,random_state=0)
clustered = Kmeans.fit_predict(pca_result)
PCA_df = pd.DataFrame(pca_result) 
PCA_df['cluster'] = clustered 
PCA_df.columns = ['x1','x2','cluster'] 
k_means_figure = sns.scatterplot(data=PCA_df,x='x1',y='x2',hue='cluster',legend="full",alpha=0.5)

作者图片

不得不承认聚类并不完美。但是我们必须明白,数据科学就是从获得的结果中推导出结论。因为我们可以从这种聚类中得出新闻的可信度,所以我们可以自信地说 K-Means 聚类对于可用的数据集工作得很好。结论在文末。

保存模型:

在 Pickle 的帮助下,我们保存模型以备将来使用。

Kmeans = Kmeans.fit(pca_result)
filename = 'news_classifier_KMeans2.sav'
pickle.dump(Kmeans, open(filename, 'wb'))

第二部分:预测那些看不见的标题群

监督培训

我们首先创建一个 pandas 数据框,其中包含用于训练的标题和由 K-Means 算法分配的聚类(在“预测”列下)。

现在,我们使用监督分类算法,如逻辑回归K-最近邻、支持向量分类器,对用于“预测”列聚类的相同新闻标题进行训练,然后选择具有最高准确度的算法。相同的代码可以在我的 GitHub 库中找到。结果总结如下:

从表中我们发现支持向量分类器朴素贝叶斯的准确率最高,为 99.93 %。在这里,我们用前者来训练。

SVC_classifier = SVC(C=300,kernel='linear',random_state=0)
SVC_classifier.fit(pca_result,y_train)# y_train is the 'Predictions' column of the Data Frame used for supervised training. 

预测未知标题的聚类:

这是包含未显示标题的表格。我通过使用 Newsdata.io 提供的 API 键获得了它们,我们称之为测试数据集。

为了获得准确的结果,我们结合测试和训练数据集,并重复预处理步骤。然后,我们将生成的 NumPy 数组拆分回训练和测试数据集的数组。pca_result_test 是测试数据集对应的 NumPy 数组。

现在,我们预测看不见的标题所属的群集:

clustered_test = SVC_classifier.predict(pca_result_test)

我们再次创建一个熊猫数据框,其中包含看不见的标题和预测的聚类。

然后,我们将训练和测试数据集的分类编号映射到类别编号 1 到 6,以使分类更加直观。

我们最终保存两个数据帧。我们将在创建仪表板应用程序时使用它们。

第 3 部分:构建仪表板应用程序并将其部署在 Heroku 上

最后,我们使用 Python 的 DashPlotly 包构建了一个交互式 web dashboard 应用程序,并将其部署在 Heroku 上。Heroku 是一个云平台即服务,开发者可以免费部署他们的应用程序。

推论和结论:

阅读完本文后,您可能想知道 K-Means 聚类在这种情况下是如何工作的。原因是 K-Means 分类器通过识别某些词的用法将标题组织成簇。TF-IDF 分配给每个单词的值与该单词在标题中出现的次数成正比,与包含该单词的标题的数量成反比。可信度存疑的新闻标题数量较多,拉低了频繁词的 TF-IDF 值。因此,这些标题的数据点更接近 K 均值散点图中的原点。另一方面,可信的新闻标题数量较少,因此频繁出现的词具有较高的 TF-IDF 值。因此,数据点远离散点图中的原点。

类别描述如下:

类别 1:

新闻主要是关于燃料、黄金和白银价格。新闻是假的可能性微乎其微。类别 1 下的标题数量是 53。常用词有— 燃油、汽油、翘尾、黄金、白银、暴跌。

类别 2:

新闻是假的几率稍微高一点。头条大多是关于经济、股市、铁路、航空、汽车、智能手机等。该类别下的标题数量为 798 个。常用的词有— 市场、俏皮、银行、三星、铁路、Flipkart、制造。

类别 3:

新闻有中等概率是假的。新闻标题大多是关于健康(大多与 COVID 相关)、经济、基础设施和技术的。一些政治新闻标题也出现在这个集群中。这个类别有 4089 个标题。常用的词有比特币、锁定、COVID、疫苗、限制、解锁、项目销售。

类别 4:

发现虚假和被操纵的新闻的概率很高。新闻标题大多与印度和世界的政治以及疫情有关。今天印度国内外主流媒体发表的大部分新闻文章都属于这一类。这一类别还包含说服人们不要服用 COVID 疫苗的宣传和谣言。但是我们也可以在这里找到一些体育和名人新闻。总共有 7018 条新闻标题属于这一类。常用词有— COVID、疫苗、洗手液、男演员、女演员、网球、火柴、莫迪、拜登、流氓、敌对、列宁主义、愚蠢、叛乱。

类别 5:

找到有偏见的、被操纵的和虚假的新闻的概率非常高。这一类包含了很多宣传。这个分类下有 2800 个标题。常用词有— 莫迪、拉胡尔·甘地、国会、BJP、自由派、左派、穆斯林、印度教、暴动、政府、巴基斯坦、邪教、骗局、谋杀、中国。

类别 6:

这是一个异常类别。这个类别有 29 个标题。所有的标题都来自 Alt-Market,这是一家以发布假新闻而闻名的新闻媒体。这是他们下一期时事通讯的发布通知。因此,我们可以忽略它们。

下面是显示每个类别下的文章数量的条形图。

作者图片

分类 1 到 3 下的训练数据集中标题的数量总共是 4940,与其他分类下的 9847 相比要少。相应的百分比分别为 33%和 67%。

那么,我们能从中得出什么结论呢?只有 1、2、3 类下的新闻标题才值得关注。其他标题下的新闻标题,除了体育标题,一般都是有毒的和固执己见的,更有可能在 WhatsApp 上转发或发布在脸书和推特上。因此,我们必须半信半疑地对待它们,或者忽略它们。

用 BigQuery 构建群体 A/B 检验的 K 均值聚类模型

原文:https://towardsdatascience.com/building-a-k-means-clustering-model-for-population-a-b-testing-with-bigquery-57410d1b7d89?source=collection_archive---------22-----------------------

你如何使用谷歌的数据仓库来建立同质的个人群体

马丁·桑切斯在 Unsplash 上的照片

最近,我让到建立了同质的相同规模的团队,这样我们就可以分析这两个团队随着时间的推移而发生的变化——一个团队在一个新的软件工具上接受测试,而另一个团队将继续使用通常的工具。换句话说:我的目标是将 n 个观察值划分成 k 个簇——但是我们稍后会谈到技术术语。

这里的挑战是找到一个合理的方法,可以被任何人理解,同时解决我的问题。在尝试了一个简单的方法后,我转向了 k-means 聚类机器学习模型。以下是我这样做的原因,以及如何使用谷歌 BigQuery 的内置模型解决类似的问题。

1.如何将不同的个体组成相似的群体?

我的目标是根据几个指标对人进行分类。为了简单和保密,我们假设我想创建 4 个员工小组来进行如何使用 Excel 的研讨会。我希望根据个人在以下方面的相似性来创建同质群体:

  • 资历,从加入公司开始计算的天数
  • 参加研讨会前对 Excel 的熟练程度,由员工自己评估,1-5 分
  • 平均每天花费在电脑上的时间,以分钟为单位,由电脑自己测量(默认设置或通过安装的应用程序)

这里你可能注意到了,考虑的指标都是连续的数值变量。如果它们不在您的特定用例中,我建议您将分类变量转换成数字变量。例如,这是我对定性项目“Excel 熟练程度”所做的:通过让“我对 Excel 一无所知”等于 1 和“我完全掌握 Excel,包括 VBA”等于 5,我将定性指标变成了定量指标。

然后要克服的主要障碍是创建类似规模的群体。如果唯一的约束是将员工分成具有相似特征(但不一定是相同规模)的组,计算每个指标的中位数,然后根据他们在中位数的哪一边来划分个人就足够了。但是这种方法不一定会导致相同大小的集群,而且现实往往不像理论上的手工绘图那样容易分割。

玛丽·勒费夫尔

第二个问题是我们有两个以上的指标来评估。当只评估两个度量时,有时可以找到一个图形化的解决方案,并且可以将观察结果(这里是个人)可视化地分组到或多或少可见的集群中。然而,引入两个以上的维度使得人眼和大脑很难容易地创建相同大小并且由具有相似特征的观察结果组成的集群。

为了总结第一部分,让我展示我们将在整个示例中使用的数据集:

玛丽·勒费夫尔

2.构建解决方案:如何创建和运行 k 均值模型?

首先, k-means 聚类是一种无监督的机器学习算法,旨在将相似的数据点分组在一起。这正是我们需要的。如果您想更多地了解 k-means 聚类是如何工作的,我推荐一位作者的这篇文章,在这篇文章中,您还将通过一个使用 Python 的示例得到指导:

基本上,k-means 聚类算法将从数据集中 y 个变量的框架内的 x 个点(x 由用户预先定义)开始。从这 x 个初始点,y 个变量中就其相似性而言最接近的点被聚集到每个聚类的先前点。最终,整个多维帧被分成 x 个部分,每个部分定义相似数据点的集群。因此,k 均值聚类的原理相对容易理解——这也是我选择使用这个模型而不是另一个模型的原因之一。如果说背后的数学执行是复杂繁琐的,那么它的基本原理就相对容易理解了。

在我们的示例中,我们希望获得 4 个聚类(这是上面解释中的 x ),我们有 3 个变量(这是 y ):资历、参加研讨会前对 Excel 的熟练程度,以及平均每天花在计算机上的时间。k-means 聚类模型已经内置在 Google 的 BigQuery 中,所以没有必要重新发明轮子。让我们简单地应用下面两个步骤,正如在 BigQuery ML 文档中所描述的。

步骤 1:构建模型

为此,您必须编写一个 SQL 查询,只提取与模型相关的变量。在我们的例子中,我们希望从源数据表中提取所有的观察值(或行),我们需要前面提到的 3 个变量。

步骤 2:运行模型

既然已经创建了模型,您可以使用下面几行代码将它应用到您的数据集。我们只是排除了自动创建的列“nearest_centroids_ distance ”,因为该字段的值不应该输入到运行模型的参数中。

请注意,机器学习算法的使用在这里被大大简化了。因此,严格来说,这里采取的步骤并不对应于“机器学习”。我在这里的目标是使用强大的工具,比如 k-means 聚类算法来帮助解决一个具体的问题——这个问题也可以用其他方法来解决。我想证明的是,机器学习也适用于几乎没有工程背景的人,并且可以应用于大量案例。

3.得到答案:如何解释模型的输出?

由于 k-means 聚类是一种无监督的机器学习模型,该模型将基于数据集和您在第一步中定义的参数运行。然后它会返回一个名为“CENTROID _ ID”的新列。该值对应于根据模型预测将每个观察值(在我们的示例中是每个个体)分配到的分类号。

玛丽·勒费夫尔

由于每次迭代都从数据集多维空间中的不同随机点开始,建议调整模型参数以最佳拟合您的数据,多次运行模型并比较其输出。如果你想深入研究机器学习算法的世界,你甚至可以尝试不同的模型,并将其他类型的推理应用到你的特定用例中。

最终你会得到一个令你满意的观察分段。在我的案例中,我将模型给出的结果和我的实地知识结合起来,建立了研讨会的最终小组。这里最重要的部分是最终的输出符合您的需求和您的特定用例。虽然你在这里唱的是机器学习算法,但你应该始终掌握你使用的数据类型,并牢记你分析的目标。这是正确解释模型输出并将分析结果传达给第三方的关键。

玛丽·勒费夫尔

结论

最重要的是,我认为 k-means 聚类在这个特定应用中的应用是帮助您做出更好决策的方法之一。最终,你如何处理机器学习模型的输出才是最重要的。

这就是为什么当您想要复制这种方法时,这里描述的三个步骤是必不可少的:

  1. 设置场景——你想解决什么问题?
  2. 构建解决方案 —您如何构建并运行最适合您正在处理的数据的模型?
  3. 得到答案 —你如何解释你的模型的输出?

你喜欢读这篇文章吗? 成为会员 加入一个不断成长的充满好奇心的社区吧!

https://marie-lefevre.medium.com/membership

手动构建线性回归

原文:https://towardsdatascience.com/building-a-linear-regression-by-hand-b930e63bf0ae?source=collection_archive---------13-----------------------

Unsplash 拍摄的图像

入门

让我们使用 Python 来创建估计我们自己的线和验证我们的结果所需的所有方程,而不依赖于库来训练我们的模型!

W 我们基于 x 的值采用线性回归来预测 Y 的值。因为我们需要知道 Y,所以这是一种监督学习方法。线性回归分为两种类型:基本的和多重的。让我们从简单的开始。所有代码的笔记本这里是这里是。所有的方程式都是用乳胶做的

在我们开始之前,理解线性回归是一种参数方法是至关重要的。

参数化方法:

1.它预先假定了函数的形状。

2.它将估计 f (X)的问题简化为估计一组参数。这种假设简化了任务,因为估计参数集合比使用完全任意的函数更容易。

3.这些方法中最困难的方面是做出正确的估计。我们只能猜测曲线的正确形式,从而导致错误的预测。

因此,我们必须估计参数,使我们能够创建一条最接近 Y 值的线,不管是已知的还是未知的。

简单线性回归

作者图片

这是简单线性回归的函数。这个方程的变体可以在统计文献中找到,但是它们都有相同的实质。可能是 W0 和 W1,α和β,等等。

不过,我想让你注意一件事。注意符号≈。当我们估计值时,我们的主要目标是使我们的预测接近 Y 到 x 的真实值。也就是说,我们的目标是尽可能地最小化真实值和估计值之间的差异。

因此,当处理 f (X) = Y 的估计,或者更具体地,f(X)的参数,其中 f (X) = Y 或者 Y = f (X)时,我们的目标不是完美地定义 f(X),而是估计最好地代表 f(X)的参数。但是,因为 y = ^f (X)++e,我们对 f(x)的估计将等于 y 加上 e 后的余数。

其中 Y = ^f (X) + e ,则^f (X) = ^B0 + ^B1X = Y.也就是说,为了估计Y,首先要估计^f (X)、^B0、B1 的参数。Y = ^Y + e 既然 Y = ^f (X) + e 和^f (X) = ^Y.

考虑到这一点,我们将使用的公式是:

作者图片

不再分心。

什么是 B0 和 B1

BO 表示截距,即 X = 0 时的 Y 值,或线性回归线开始处的 Y 值。这里有一个例子。我们希望根据活动中的投资金额来估计销售转化的数量。不投钱能卖多少?

B1 呢?斜率由 B1 的值表示。基本决定了趋势线。这在实践中是如何运作的?考虑根据体重计算身高的例子。身高以厘米为单位,体重以公斤为单位。我们发现斜率为 2.5。表示体重每增加一公斤,人的身高就增加 2.5 毫米。

假设我们知道 B0 和 B1 是什么,我们如何估计它们呢?这些参数可以用多种方法来估计。首先,让我们看看普通的最小二乘法(OLS),这是最常见和最简单的方法之一。要估算 B0,首先要估算 B1。

在统计学中,普通最小二乘法 ( OLS )是一种估计线性回归模型中未知参数的线性最小二乘法。OLS 通过最小二乘法原理选择一组解释变量的线性函数的参数:最小化给定数据集中观察到的因变量(被观察变量的值)和自变量的线性函数预测的变量之间的差的平方和。—来源:维基百科

让我们看看这意味着什么。我们想用这种方法达到什么目的?减少一些东西。应该尽量减少什么?观察数据和估计数据之差的平方和。让我们把这个等式放在一起。

反过来,我们有观察值和估计值之间的差异。作为回归结果的估计值称为估计值。观察值是真实值。因此,

observedValue - estimatedValue

现在,平方估计值和观测值之差。因此:

square (observedValue - estimatedValue)

最后,观察数据和估计数据之间差异的平方和。:

sum (square (observedValue - estimatedValue))

好的,但是这个和的意义是什么?observedValue 和 estimatedValue 是值。考虑一下:我们有两列,Y 和 Y。第一列是真实值,观察值,第二列是估计值。正如我之前提到的,我们构建了一个模型,并利用 X 来估计 Y,从而得到 Y。假设每一列都有三个值,Y = [5,9,2]和 Y = [6,7,2]。使用我们的公式,我们得到以下结果:

(5–6)²
(9–7)²
(2–2)²

总数是这三个操作的总和。结果是,(5–6)+(9–7)+(2–2)。作为这些程序的结果,我们得到了残差平方和(RSS)。这种情况下使用 RSS = 5。我们的目标是使用 OLS 来减少 RSS。

RSS 的一般公式是:

作者图片

我们如何用 Python 来编码呢?

OLS 是减少这种 RSS 的众多方法之一。另一种做法是,我不知道,猜测 B0 和 B1 的各种参数,计算所有的误差,选择最小的一个,但是发现的最小的误差可能没有那么微小。我们将以这样的方式结束。当我们有少量的功能和列时,OLS 是最快捷和最容易使用的方法。

我们将在文章中使用虚构的数据。

在本例中,我制作了两个数组来表示 X 和 y。我创建了 1000 个值,以便提供一个更有趣的视角。我把 X 和 Y 分成四份。训练数据将包含 80%的 X 和 Y 值(X 训练和 Y 训练),而 20%的数据将用于测试(X 测试和 Y 测试)。

在估计 B0 和 B1 之前,我们先讨论一下假设。线性回归的基本假设是什么?我们利用线性回归来预测新值或做出推论。有许多方法可以估计回归中的参数。许多方法,如 OLS,需要特定的假设,以使他们的结论尽可能准确和公正。这些前提不必在每个线性回归中都严格遵循!

因变量和自变量必须有线性关系。

当使用线性回归进行预测时,满足这一要求是合乎逻辑的。本质上,线性回归将通过数据画一条直线。如果数据没有线性关系,模型就无法处理数据的复杂性。我们如何检验这个概念?

在大多数假设下,有两种形式的确认。有图形确认,也有数学确认。只要可行,我将同时介绍这两种方法。当事情变得太复杂时,我就只覆盖视觉效果。

所以我们可以把 X 数据和 Y 数据对应起来,寻找趋势。让我们执行这个命令,看看会发生什么。

plt.figure(figsize=(10,10))
plt.scatter(X_train, y_train)
plt.show()

作者图片

对我来说,它似乎是线性的!我甚至能看到一条直线!但是这有什么意义呢?我不确定你,但视觉确认并不能完全满足我。当然,你的视角是由你的时间、金钱和教育决定的。然而,我们在这里拥有世界上所有的时间,它是免费的,我们有足够的知识来使用替代方法。

除了图表,我们如何评估线性关系?计算 X 和 Y 之间的相关系数。但是这种相关性到底是什么呢?

统计中相关相关是两个随机变量二元数据之间的任何统计关系,无论是否为因果。从最广泛的意义上来说,相关性是任何统计关联,尽管它通常指一对变量线性相关的程度。依赖性现象的常见例子包括父母及其子女的身高之间的相关性,以及商品价格和消费者愿意购买的数量之间的相关性,正如所谓的需求曲线中所描述的那样..—来源:维基百科。

在这个简短的解释之后,我将重申一个统计学家的口头禅:相关性并不意味着因果关系!在我们对因果关系做出明确的判断之前,我们需要进行一些统计测试。但这是另一天的话题!

在我们的数据中,我们希望计算 X 和 y 之间的相关程度。有各种方法来解决这个问题。皮尔逊系数是最常用的。其通式如下:

作者图片

也就是说,两个变量的标准差除以它们的协方差。让我们把事情分解一下,这样你能更好地理解它。我们将看两个部分。X 相对于 Y 的协方差,以及 X 和 Y 的方差。我将把这些信息留给方差的概念,其中包括一些图形解释。绝对值得一看。总之,协方差表示两个变量协同波动的程度。

在 Python 中我们如何计算两个变量的协方差?让我们用这个公式:

作者图片

仅此而已!样本的标准差是多少?随机变量的标准偏差是对其围绕总体均值的离差的度量。低标准偏差意味着数据点经常接近平均值或预期值。较大的标准差意味着数据点分布在较大的数值范围内(维基百科)。方差的平方根也是标准差。让我们使用 Python 通过利用方差公式并计算其根来创建我们的标准差公式:

作者图片

我们先来看看标准差。

如你所见,我们利用方差公式来寻找问题的根源。我们现在可以使用皮尔逊系数。让我们从原始公式开始,并从那里创建我们的函数:

作者图片

鉴于我们已经完成了一半以上,让我们进一步简化这个公式:

covarianceOfXY / StdX * StdY

让我们看看我们的数据结果如何。

The Pearson Correlation Coefficient between X and Y is [0.98478235].

而皮尔逊系数的意义是什么?皮尔逊系数是一个介于-1 和 1 之间的数字,1 和-1 表示完全线性相关,0 表示不存在相关。完全正相关是 1,而完全负相关是-1。

理想的价值观应该是什么样的?这是有条件的。有时 0.7 的相关性是最佳的,而其他时候 0.9 是不够的。这将取决于你的问题的性质。在多元线性回归中,您可以使用皮尔逊系数来查找模型中最重要的因素或排除相关变量。

现在我们已经确定了一个假设,让我们开始估计参数。

B0 和 B1 将使用 OLS 公式进行估算。以下是方程式:

作者图片

这么看,有点难,lol。但是,实际上,这很容易。让我们从 B1 开始:

作者图片

如前所述,B1 是 X 和 Y 之间的协方差除以 X 的方差。B0 只是 X = 0 时 Y 的值,考虑了 Y 的中值与角度系数和 X 的中值的乘积之差。

我们用 Python 估算一下 B0 和 B1?

因为我们在训练和测试中划分数据,所以我们的 X 和 Y 将是我们的训练 X 和 Y,是时候估算了!

Intercept: -4.959319577525191,        
Slope: [2.00341869].

换句话说,我们的线从-4.9593 开始,x 每增加一次,线就前进 2.003。现在我们将这些参数应用到新数据中,看看我们的预测结果如何!现在是时候建立我们的线性回归了!

因为我们之前分离了我们的数据,所以我们现在可以测试和评估我们的模型了!

y_pred = predict_function(b0_coeficient, b1_coeficient, X_test)

之后呢?现在是时候设计我们的返程路线了!

plt.figure(figsize=(8,6))plt.scatter(X_test, y_test,  color='blue')plt.plot(X_test, y_pred, color='red', linewidth=2)plt.title("Linear Regression Demonstration", fontweight="bold", size=15)plt.show()

作者图片

看来我们的回归很顺利!

自然,线性回归线永远不会到达所有点。或者,至少,如果他们是正确的,如果模型的意图是将其推广到新数据,这将不是一件好事。这是因为每个线性方程都有误差。

此刻,我们将加入我们等式的最后一个部分,关于它我们已经说过了。错误。

作者图片

误差是 y 的预测值和实际值之间的差值。误差的成本可能是多种因素的结果。有时是你没有考虑的单一变量,而其他时候你假设了现实中不存在的线性关系。

另一个原因可能是数据短缺。由于数据如此有限,你的估计可能无法揭示问题的真正本质。首先,有几种方法可以减少错误。你可能会寻找更多的数据,选择一个非参数或线性模型,并添加更多的变量。策略不同,将由您的评估决定。寻找更多的数据要花多少钱?值得寻找进一步的信息吗?测试另一个模型需要多长时间?专业工作时,你应该问所有这些问题。

有限制吗?是的。称之为不可逆转的错误。不可逆误差是随机的,根据定义,不能测量或观察。我们会给你带来我们的新方程,我会给你解释的。

Y = ^f(X) + e

当然,我们已经完成了第一阶段,并估计了 f(X)的参数。为了有助于理解,我们采用线性回归来确定或预测给定一定量的辉瑞疫苗应用于小鼠的一小时内的平均心跳水平。

但是,该错误尚未提交,也不会提交。为什么会这样呢?我们猜测你昨晚回家很晚,很累,睡了一夜。同一天晚上,你的一只老鼠皮图被马金奥斯拴住了。Pitu 和 gaiola 里的其他老鼠一样,变得极度紧张。幸运的是,没有人受伤。皮图第二天想跟你说委屈,但是因为你不和动物说话,所以你不知道发生了什么。

Pitu 的压力水平被发生的事情和你不明白发生了什么的事实所改变。压力水平是你的结果中的一个重要变量,但你忽略了 N 个原因,其中之一是你不会说“mouseguese”。

另一只小老鼠玛格达莱娜很孤独,没有人和她说话或一起玩。当你出去的时候,其他人有一个聚会,但是玛格达莱娜留在她的角落里,沉思她的悲伤。你很可能无法识别抹大拉的悲伤,因为你没有主修老鼠心理学。这个你无法测量甚至看不到的变量,在评估抹大拉的结果时将是至关重要的!

你明白我的意思吗?有些因素对于你的分析来说是不可观察或不可收集的。

你应该感到奇怪,但这是什么错误,为什么我相信我在哪里听到过?你在上面看到了它,但是它有一个不同的名字:RSS。我们会计算模型的 RSS 吗?

print(f'The RSS is {get_rss(y_pred, y_test)}.')# The RSS is 191.16066429.

有了这个数字,我们可以想办法减少它。但这不是今天的议题!我提到这个错误是有原因的。线性回归的第二个前提。

残留物必须以规则的方式分布。

为什么会这样呢?关于为什么这个假设应该被证实,以及当它不满足时会发生什么,即使它是必要的,有几个争议。由于这些都是非常技术性的问题,所以我不会在本文中讨论它们。

我们如何知道一个数据分布是否正常?有两种类型的图形:图形和数学。我将在这部分使用图形。如果我们想检查所有剩菜的行为,我们不能使用 RSS,因为 RSS 查看剩菜的总和,但我对剩菜的总和不感兴趣,而是对单个剩菜感兴趣。

还记得一开始的注册吗?我们来看公式 Y = ^Y + e,要计算残差,只需将 y 从左向右切换,结果为:y ^y =e

e =观察值—估计值

很简单,用 Python 来说:

residual_lr = get_residual(y_test, y_pred)

因此,我们将有一个剩菜阵列。我们会使用直方图来检查它们的分布吗?

plt.subplots(figsize=(12, 6))plt.title('Distribution of Residuals')sns.distplot(residual_lr)plt.show()

作者图片

这看起来是正态分布,尽管有点不对称!有没有另一种方法可以从图形上确认这是一个正态分布?有,有!它被称为 QQPlot 图!

lst = []
for i in residual_lr:
    for n in i:
        lst.append(n)sm.qqplot(np.array(lst), line='45', fit=True)
plt.show()

在这段代码中,我从一组数组中提取了值,并将它们放在一个列表中,供我们的 QQPlot 验证!你有它!

作者图片

这到底是什么我从来没见过的东西?你可能会好奇。我不会花太多时间去概念化 QQPlot,而是去解释它。如果你有兴趣了解更多

从一个 QQ 情节中我们可以得出什么结论?我们有一条红色的直线和一个蓝色的残差离差。我们可以使用 QQ 图来可视化我们的数据分布。如果它们完全沿着红线,我们就有一个完美的正态分布。我们的数据离这条直线越远,正态分布特征就越少。为了更好的理解,你可以在这里找到可视化的解释

基于这一可视化,我们得出结论,我们的废物有一个典型的分布,尽管一些点远离中心。

有几种统计检验可以确定分布是否正态,如夏皮罗-维尔克检验。但是现在,我们只要坚持视觉化!我们正前往下一站。

残差的方差应该是常数

线性回归模型在很大程度上依赖于同方差的前提(即“恒定方差”)。同方差定义了一种情况,其中误差项(自变量和因变量之间关系中的“噪声”或随机扰动)对于所有自变量值都是相同的。

当误差项的大小在独立变量值之间变化时,就会出现异方差(违反同方差)。违反异方差假设的影响与异方差的程度成正比。

这对我们有什么意义?当我们使用 MMQ 时,我们给所有的 X 值相同的权重。如果某些 X 值比其他值有更大的影响,我们就有问题了。

考虑基于家庭收入的奢侈品购买估计。我们有贫困的家庭,他们不买或者只买一些奢侈品。如果奢侈品的购买随着家庭收入的增加而增加,我们就会有一个恒定的方差。但假设只有一部分富裕家庭购买奢侈品,而其他人购买相对较少:我们有异方差的问题。

你还记得 B1 公式吗?X 值的方差在除数部分计算。因为 OLS 为 X 的所有变量提供了相同的权重,所以很大的变化会造成阻碍!

我们如何才能看到这一点?让我们使用 Python 吧!让我们从视觉表现开始。我们将根据预期值绘制残差图,以观察误差的变化。

plt.scatter(residual_lr, y_pred)
plt.show()

作者图片

老实说,我无法从这张图片中得出任何结论!这些点上似乎没有任何图案。那么,我们要测试一下吗?

H0 = homocedasticity
H1 != homocedasticityalpha = 0.05

让我们为此使用 statsmodels.stats 库!

print(sm.diagnostics.het_goldfeldquandt(residual_lr, y_pred))Test: 1.0206718127917291
p-value: 0.45956295321355667

我们不能因为α< p 值而拒绝零假设,因此我们不能否认同方差的存在!

咻!我们的模型确认并通过了所有的假设!你很可能在想“我们现在可以走了吗?模式太神奇了!”。如果你想利用模型来分析变量,你可以放松一下。你可以明天开始检查,看看是否能从中得到什么。如果你想利用这个模型来做预测,我们只是成功了一半!

现在是时候评估我们模型的可推广性了!如您所见,我们的模型在盯着测试数据方面做得很好。但是有多好呢?我们如何评估我们的模型?使用度量标准!

对此有多种测量方法。其中之一是 R 平方,通常称为决定系数。R2 是一种度量,它表示模型可以解释多少数据变化。换句话说,这个度量计算回归模型可能预测的方差的比例,因此向我们显示实际度量与我们的模型有多“接近”。它表示响应变量中可由预测变量或解释变量解释的可变性的比例。

它的 R 平方值从 0 到 1 不等,0 表示最差的估计值,1 表示最好的估计值。它通常用百分比表示。例如,R2 = 73 %表明模型可以解释我们数据中 73 %的波动性,而剩余的 27%理论上是剩余方差。

有可能出现负的 R 平方吗?是的,当你的模型有能力比所有 Y 值的均值更差的时候。

R2 公式到底是什么?让我们再看一遍我们的 RSS 公式。我们会根据它来改变它。我们有 RSS 中残差的平方和。然而,我们希望计算残差的总平方和。

在 RSS 中,我们取 Y 的每个观察值和估计值之间的差,或者 Y,对其求平方,并添加结果。在 TSS 中,我们计算 Y 值和 Y 平方平均值之间的差值。也就是说:

TSS = sum ( ( valuesX — meanY))

R2 基本上是:

1 — (RSS / TSS)

rss = get_rss(y_pred, y_test)
rst = rst_metric(y_test)print(f'The R2 of the model is {get_r2(rss, rst)[0]*100}%.')

该模型的 R2 达到了 97.177738738677

这意味着,我们的模型能够解释近 97.18 %的数据!该模型似乎可以推广到新的数据!

r 平方也可以通过平方皮尔逊系数来计算:

print(0.98478235 ** 2)# 0.969796276871522

你想知道如果你取平均值,R 的平方是多少吗?我们一起来看看吧!让我们做一个和 Y 一样大的列表,但是用 Y 的平均值代替。

plt.figure(figsize=(8,6))
plt.scatter(X_test, y_test,  color='blue')
plt.plot(X_test, lst, color='red', linewidth=2)
plt.title("Linear Regression Demonstration", size=15)plt.show()

现在,让我们来计算 R 的平方:

rst = tss_metric(y_test)rss = get_rss(lst, y_test)print(f'The R2 of the model is {get_r2(rss, rst)[0]*100}%.')

模型的 R2 为 0.0%。

还记得我说过 R 的平方可以小于 0 吗?RST 以上的 RSS 越大,R 的平方就越低。

然而,问题依然存在。估计线性回归的另一种方法是什么?好吧,我会迅速找到一个合理的策略。

这背后的解释如下。我们先挑 100 个截距和 100 个斜率值,然后测试 10000 个线性回归,比较一下,挑 RSS 最小的组合。我们开始吧!

这里我们运行 10,000 次回归。我们要不要计算得到最小的 RSS?

min_index = rss_list.index(np.min(rss_list))print(f'The lowest RSS is: {np.min(rss_list)} with index {min_index}.')# The lowest RSS is: 190.52186974065032 with index 4552.

与使用 OLS 相比,我们使用这种变通方法得到的 RSS 要小一些!用这个指数在测试数据上画出我们的回归线。

plt.figure(figsize=(8,6))plt.scatter(X_test, y_test,  color='blue')plt.plot(X_test, linear_reg[min_index], color='red', linewidth=2)plt.title("Linear Regression Demonstration", size=15)plt.show()

作者图片

R 的平方呢?

rst = tss_metric(y_test)rss = get_rss(linear_reg[min_index], y_test)print(f'The R2 of the model is {get_r2(rss, rst)[0]*100}%.')
# The R2 of the model is 97.18512940329813%.

正如你所看到的,这种差异可以忽略不计,几乎不存在。而使用 MMQ 方法我们得到 97.175%,这里我们得到 97.185%。

到此,我们将结束我们的文章!我试图通过理解五六行代码背后的东西来解决创建线性回归的最重要的方面,这些代码足以完成我们在这里讨论的所有事情。

剩下的问题是:是否需要检查所有这些?有没有另一种方法可以在不经历所有这些的情况下获得一致的结果?我现在想做的就是完成 Kaggle 的巨大线性回归。我真的有必要这样做吗?这是一场激烈的辩论!这里可以找到一些水花。但请记住,作为一名数据科学家,你必须解决问题,并向你的同行展示你的发现。

当你处理真实数据的时候,不会像这里的那些可爱,而是需要解决问题!

参考资料:

homscedastidade——应用统计中心https://estatistica.pt/homoscedasticidade/>。Acesso em: 24 套。2021.

测试正态分布和方差分布。disponível em:<https://Bio statistics-uem . github . io/Bio/aula 8/test _ normalidade _ homocedastidade . html>。Acesso em: 24 套。2021.

‌HOW,你能给一个只懂均值的人解释一下协方差吗?你将如何向只懂均值的人解释协方差?disponível em:<https://stats . stack exchange . com/questions/18058/how-would-you-explain-co variance-to someone-someone-who-understand-only-the-mean>。Acesso em: 24 套。2021.

‌DAMACENO,l .entendendo regresso linear:as suposis por tras de tudo!disponível em:<https://medium . com/@ lauradamaceno/entendendo-regression % C3 % A3o-linear-as-suposi % C3 % A7 % C3 % B5es-por-tr % C3 % A1s-de-tudo-d0e 29004 C7 f 8>。Acesso em: 24 套。2021.

‌SHRUTIMECHLEARN.逐步假设—线性回归。可在以下网址查阅:<【https://www . kag gle . com/shruteimechlar/分步假设线性回归】 >。访问时间:9 月 24 日。2021.

蒂托。scikit-学习还是状态模式?评估我的回归模型。可在以下网址查阅:<【https://nathaliatito . medium . com/scikit-learn-or-state models-asserting-my-return model % C3 % a3 % a3-3o-F4 c04 b361 fa 7】>。访问时间:9 月 24 日。2021.

使用 Python 的多行回归。可于:<https://ichi . pro/pt/return au-multiline-using-python-75787662189>查阅。访问时间:9 月 24 日。2021.

米兰达修女。 19 线性回归|基本生物统计。可查阅:<【http://www . lamp . uerj . br/db/_ book/regret % C3 % a3 % a3-o-linear . html # straight>。访问时间:9 月 24 日。2021.

构建医疗保健提供商将使用的机器学习模型。

原文:https://towardsdatascience.com/building-a-machine-learning-model-that-healthcare-providers-will-use-25fbf229c635?source=collection_archive---------29-----------------------

图片由 安德里亚·皮亚卡迪奥 来自 像素

当我第一次学习如何创建机器学习模型时,我所有的注意力都放在算法选择、交叉验证和超参数调整上。我应该对我的连续变量使用哪种缩放技术?我应该优化 AUC、精度还是召回率?我的极端离群值可以被 winsorized 吗,还是应该被删除?但事实证明,使用我们的机器学习模型的人根本不在乎技术术语。为什么琼斯博士和她的工作人员必须学习什么是 ROC 曲线,才能知道他们的病人有多大可能在医院得到缓解?

好吧,经过几个月的建模、思考和与临床提供者的互动,我得出了一个简单的结论:他们不应该!由数据科学家将模型转化为他们关心的见解。但是还有更多。让提供者仅仅理解机器模型的输出是不够的。除非护理团队信任并使用该模型,否则我们的工作不会产生任何影响。

事实证明,从“我的 ROC-AUC 是 0.8759”到“提供商定期从我构建的模型中获得价值”是一条充满各种意想不到的曲折的道路。在这篇文章中,我将分享我为实现这一目标所学到的一切。

我的旅程

首先,我将分享一些导致这篇文章的项目背景。大约一年前,我的任务是建立一个机器学习模型,预测癌症患者在 90 天内死亡的可能性。正如我从与肿瘤学家的多次互动中了解到的那样,我们试图避免的结果是,一名癌症晚期患者在重症监护室接受化疗的最后几天里,只能离开人世。一个更人道的结果是,这些病人被识别出来并被安置到临终关怀中心,这样他们就可以在家人的陪伴下舒适地结束他们的生命。付款人还激励肿瘤诊所增加临终关怀,作为基于价值的肿瘤护理计划的一部分。

我参与了这个项目从概念到试点的整个过程,我非常自豪地告诉大家,我们的死亡率预测器在全国多个肿瘤诊所得到了积极应用,并对患者护理产生了影响。目前正在研究这一影响的程度。

但是在“构思”和“试验”之间有一段旅程,因为通常感觉需要英雄主义来将这个项目的概念转化为有价值的东西。我知道有很多教训,我当然希望我在开始这个项目时就知道,在这篇文章的其余部分,我将分享它们。

第一课:阅读文献

如果你正在建立一个临床模型,可能会有许多同行评议的论文与你的项目相关。阅读这些论文,了解哪些变量具有最强的预测能力,模型达到的性能水平,以及最成功的算法。你会得到一些很好的想法和基准,可以用来比较你的结果。与你的利益相关者分享和总结同行评议的文献将有助于你提高自己工作的可信度。

第二课:建立你的临床咨询小组

一开始就建立你的临床顾问团队。不必是一大群人(2-3 人就可以了),你也不必同时会见所有人。理想情况下,他们是愿意和你一起深入探讨本质的数据书呆子。不要被医生吓倒——你会发现有些医生很感兴趣并想提供帮助。您还应该根据需要咨询护士、高级实践提供者(app)和实践人员。临床协作是建立推动采用所必需的信任和可信度的基础。这个过程必须从项目的最开始就开始。

第三课:用初学者的心态看问题。

在你启动你的 Jupyter 笔记本之前,问问你自己——我在试图解决什么问题?我使用的是正确的基本人群吗?我的预测是否正确?我的模型需要什么样的表现才有意义?走出去,采访你的临床医生和实习人员。你可能最终会改变你的基本人群,你的特征,甚至你的标签。不要认为你在以前的项目或工作中所做的会自动应用到这个项目中。要谦虚。用一个开放的“初学者的思维”去解决你遇到的每一个问题。

梅奥诊所有一个非常有启发性的案例研究,是关于一个叫做 SWIFT score 的预测再入院的模型。临床工作人员不太使用 SWIFT 评分,梅奥诊所停止了该项目。原因之一是:

“当我们看到对 SWIFT 评分预测算法贡献最大的患者特征时,我们立即发现一个问题——这些特征中没有一个是容易修改的,其中一些是绝对不可修改的!当临床医生得知一名来自疗养院的长期住在 ICU 的患者有再次入住 ICU 的高风险时,应采取什么措施?大多数人会很快丢弃这些信息,并在停止使用该工具后很快丢弃。

通过将 SWIFT 评分与再入院风险预测进行校准,我们挑选出了在床边不可操作的信息。更成功的方法可能是校准 SWIFT 评分,以确定可修改的临床特征,如果采取行动,将降低再入院的风险。”(维塔利·赫拉塞维奇&布莱恩·皮克林。健康信息技术评估手册。CRC 出版社,2018 )

多么不可思议的学习!他们有一个很好的模型,但是模型预测不可行。如果你没有从一开始就开始临床合作,你可能会像这个案例研究一样结束。

第 4 课:明确临床工作流程。

在进行访谈和背景研究时,明确说明实践或护理团队将如何以及何时使用您的解决方案。谁啊。怎么会?什么时候?对于如何从一开始就将你的模型插入到临床工作流程中,有一个可行的假设是至关重要的。这个假设将影响你如何开发你的模型和最终产品。

此外,当需要向一些试点实践/团队推广您的工具时,您必须能够建议这些工作流。例如,它会被纳入每日或每周的“会议”中吗,它会在护理点使用吗,它会被分诊护士使用吗,等等。你可能是错的,或者他们可能会做一些完全不同的事情。但是,如果你没有一个计划,他们可能会失去兴趣,根本不会使用你的模型!

第五课:建立你的“变革理论”

我曾经上过一堂发人深省的研究生课,讲的是创造健康行为改变干预。当我们提出行为改变干预的想法时,有人问我们——你的改变理论是什么?同样,如果你建立一个临床决策支持模型,比如预测患糖尿病的可能性、死亡风险等。—需要发生什么行为才能使该模型产生影响?

例如,在死亡率模型的情况下,我们假设我们的工具将导致临床医生和实践人员与他们的患者进行更多关于临终关怀和提前护理计划的对话,这将导致更高的临终关怀率。如果我们的试点项目未能影响临终关怀率,我们可以评估问题是否与模型的准确性、工具的设计、工作流程或变革理论有关。

同样,你的目标不是模型。你的目标是创造影响力。让这种想法占主导地位。

第 6 课:预计要花很多时间清理数据。

电子病历数据是有问题的,因为它是不完整的,充满了错误,并受到奇怪的离群值的困扰。如果你认为你能在 3-4 个月内建立一个模型,你就大错特错了。我们从熟悉数据的数据分析师和工程师那里得到的最佳建议是留出 3-4 个月的时间进行数据清理。

根据您的团队的成熟度,您可能需要花几周时间与数据工程师一起工作来找到您需要的表以及如何连接它们。使用实验室值时,您可能会发现一种实验室类型使用了许多不同的名称!你会看到字符串和数字混杂在几乎所有的数字字段中,每个变量都有极端的异常值。手动输入的数据,如身高和体重,将更是一场灾难。但是振作起来。你可以克服所有这些挑战,并在未来的项目中利用你的工作。

第 7 课:在数据清理和探索期间,定期与指导老师一起检查你的工作。

一旦你清理了显而易见的东西,就创建数据的分布图或条形图,并展示给你的临床顾问团队。检查你所有的假设是至关重要的。我建议每周或每两个月定期召开会议,向您的临床顾问和其他专家展示您的清洁方法和数据探索,以获得反馈。

这里有几个具体的例子。您知道您的实验室和生命体征有异常值,因此您应用标准的异常值剔除技术,如 winsorizing 或 IQR 方法。向您的临床医生顾问展示您的新数据分布,询问他们临界值是否在临床上有效。或者,也许你正试图以一种看起来非常逻辑和明显的方式将某些类型的治疗或诊断分组——将你的工作展示给能够验证该假设的人。什么都不要假设。你不知道那些数据表里潜伏着什么奇怪的怪癖!

第 8 课:将您的模型结果转化为您的利益相关者关心的指标。

当我说公司的业务或临床部门没有人关心您的 AUC 时,我说的是实话。(AUC 是评估模型的标准指标。)F1、精度、召回、对数损失、平衡精度等等也是如此。这些指标没有任何直观意义。因此,不要用复杂的表格、难以理解的图表和数据科学术语让非技术观众感到厌烦和困惑。(将这些幻灯片放在附录中,供您的数据科学家同事参考!)

他们关心的是你的模型在未来数据上测试时是否能产生稳定的结果。他们关心的是他们是否能信任这些结果,以及你的结果与科学文献相比如何。如果您生成一个高风险列表,讨论列表的准确性比使用技术术语 precision 更直观。

第九课:信任需要透明

为了与临床医生建立信任,您必须为模型及其验证提供透明度。如果这些模型要影响病人的护理,那么就需要高度的信任。我认为选择可解释的算法通常是一个好主意,比如逻辑回归或广义加法模型,这样你就可以确定模型对单个患者进行预测的原因。

为了患者的安全,我认为临床使用的每个模型都应该附有用于训练模型的患者人群、预测变量、模型的性能、验证方法和模型的局限性的信息。如果你想看一个透明性的例子,我认为这个 MDCalc 做得非常好。

第十课:评估模型的偏见和公平

人工智能中的偏见和公平是一个需要一整个系列博客文章的主题,所以让我在这里总结一下主要思想。模型对历史数据进行学习,因此,它们将把过去的歧视模式投射到未来。例如,一个训练有素的用于预测高风险患者的医疗保健成本模型不太可能识别出资金和医疗保健服务较少的贫困患者,从而无法为这些患者提供他们需要的额外护理。(https://un dark . org/2020/07/27/ai-medicine-race-bias-新冠肺炎)比较模型在性别、种族和其他健康的社会经济决定因素方面的表现是一个很好的做法,作为识别潜在偏见或伤害领域的起点。

第 11 课:参与推广和采用。

最后,不要止步于模型开发!参与工具的设计、试点项目的推广和采用流程。准备好向利益相关者陈述并回答问题。毕竟这是好玩的部分。看着你的模特“宝贝”长大,走向世界。无论这种模式是成功还是失败,从中吸取的经验教训都是无价的。

我希望这篇文章能激发读者思考新的方法,将你的工作从机器学习模型转变为现实世界的影响。我很想在下面的评论中听到你的想法。

使用图表技术构建 Python 项目的地图-可视化您的代码

原文:https://towardsdatascience.com/building-a-map-of-your-python-project-using-graph-technology-visualize-your-code-6764e81f3500?source=collection_archive---------5-----------------------

使用 Neo4j 计算安全分数——您的代码有多安全?

作者图片

作为一名数学家和工作数据科学家,我着迷于编程语言、机器学习、数据,当然还有数学。

这些技术、艺术和工具当然对社会非常重要,当你阅读这篇文章时,它们正在改变我们的生活,但另一种新兴技术正在成长。而且增长很快!

这是一项基于我在大学学习的数学领域的技术,也是第一次被发现(或发明..?我们下次再谈吧,好吗?伟大的莱昂哈德·欧拉给了他一个挑战,当时没有人知道如何解决。

这个挑战是关于一个潜在的形状或结构,以相关事物的形式存在——关系。

欧拉需要一种工具来研究关系和结构,在这种关系和结构中,某些物体之间的距离并不重要,重要的是关系本身。

他需要并发现了现在被称为数学图的东西(或简称为)。

这就是图论和拓扑学的诞生。

快进 286 年…

发现高层结构

不久前,我在一个包含数百个 Python 类、方法和函数的存储库中从事一个相对较大的项目(工作中),所有这些类、方法和函数都通过共享数据和相互调用来相互通信。

我在一个子文件夹中工作,其中包含了旨在解决大项目中一个子问题的代码,然后我突然想到:

如果能够可视化我在大画面中的位置,以及所有不同的对象是如何通过相互之间的调用和数据传递连接起来的,这不是很好吗?

那会是什么样子?

在几个晚上和(17 杯浓咖啡)里,我设法构建了一个 Python 程序,它将您的代码作为节点和关系以对象和调用、作用域和实例化的形式解析到 Neo4j 图形数据库中。

上图是通过这个 Python 映射项目解析我的一个 NLP 项目(人类语言上使用的机器学习)的结果。

对于不知道什么是图形数据库的人来说,让我们暂停一下这个故事。

首先,图是一个数学对象。它由所谓的节点和边组成。在 Neo 术语中,这些边被称为关系,这很合适,因为这正是它们所代表的——两个节点之间的某种关系。

这种图的一个经典例子是像脸书这样的社交网络,其中节点代表人,关系代表人与人之间的友谊。

然后,图形数据库存储这样的图形,以便您可以探索隐藏在大量路径中的模式。

我们应该记住的一件非常重要的事情是,在图形数据库中,节点以及关系都存储在数据库中。这意味着某些查询比在关系数据库中连接大量的表要快得多。

为了更清楚地说明我们在这里构建的是什么样的图形,我将勾画出它的结构。

我们指定 Python 项目的根文件夹。

图中的节点表示我们的项目/存储库中的文件对象。特别是函数、类和方法。这些节点有一些属性,比如它们在哪个文件中定义,如果它们有一个父节点(方法有类作为父节点,函数可以在其他函数中定义,等等。).

对于关系,我们有调用、实例化、显示方法属于哪个类的关系,等等。

作者图片

这个想法是,我们希望能够跟踪代码中的调用和依赖关系。

所以我手里拿着一个新的可视化工具——不是像 Matplotlib 这样的可视化数据的工具,而是可视化代码本身的结构。

乍一看,除了一个有趣的新方法来为“赢得”项目的办公室制作令人敬畏的海报之外,我没有想太多。

然而,在与我的一个同事(碰巧也是一个数学/图形数据库极客)讨论了它为许多不同的可能工具铺平了道路之后,我很快意识到这不仅仅是一个可视化工具。

测试和安全

当然,你可以看到代码中的依赖关系,这当然很好,它甚至可以帮助你发现一两个 bug,或者仅仅通过查看就可以优化代码,但是真正的力量来自于对嵌套代码结构的揭示。

例如,除非你真的很紧张,并且已经将你的代码分成小的可测试单元,然后在进行更大的集成测试之前,在(所谓的)单元测试中一个接一个地进行测试,否则你可能不容易回答这样的问题

  • 你的代码测试到什么程度了?也就是说,哪些功能是隐式测试的,而不是显式测试的,反之亦然?
  • 有没有不再被使用或者没有被测试的功能?
  • 哪些函数被隐式调用得最多?

坚持住卡斯帕。首先,隐式调用是什么意思?

嗯,当我调用一个函数(或者一个方法,生成器等等。)该函数可能调用另一个函数,依此类推。这些被其他函数调用的函数被隐式地调用。第一个函数被显式地称为或直接称为**

好吧…为什么这很重要?

因为,如果一个函数被很多不同的函数多次(隐式)调用,有一个细微的 bug,那么,首先,这个 bug 在某个时刻发生的概率比每次只被同一个函数调用一次的概率要大,其次,依赖那个函数的函数越多,一个潜在的 bug 对整个系统/程序造成的损害就越大。

事实证明,图是解决这类问题的完美设备。我们甚至可以用一种更微妙的方式来解决它们,通过使用图形算法,用分数的方式列出函数、方法和类的重要性。

解决方案

在能够使用 Python 中的 neo4j 之前,我们需要安装 neo4j 桌面环境并执行一个

***pip install neo4j***

让我们构建一个能够从 Python 与 Neo4j 通信的类。

现在,我们可以通过如下方式在另一个类中轻松构建一个图形加载器

***self.loader = LoadGraphData("Kasper", "strong_pw_123", "bolt://localhost:7687")***

让我们来看看我的一个爱好项目,由我上面描述的映射算法映射出来的。

作者图片

在这个项目中,蓝色节点是类,橙色节点是方法,红色节点是函数。

请注意,这些代码中有一些是测试这个 graph 项目的伪代码,当然是使用了正确的 Python 语法。

我们想知道测试了哪些函数,测试的隐含程度如何,即从最近的测试函数到给定的非测试函数有多少(嵌套)调用?

嗯,我们有图表。现在我们需要查询图形数据库。

看看下面的 Cypher 查询,它实现了测试和函数之间的最短路径算法,并与图片进行比较。

请注意,我们假设测试函数是这样的对象,它们或者在一个名称以“test”开头的文件中,或者在一个类中,或者在一个名称以“test”开头的函数中,或者仅仅是名称以“test”开头的函数、方法或类(对于类来说,它当然应该以“test”开头)。

乍一看,这种假设似乎有些牵强,但是我不认为我曾经在 Python 文件中编写过以“test”开头的测试函数,更不用说函数名本身几乎总是以“test”开头。

如果您有一个以“test”开头的文件,我假设该文件中的所有函数和方法都是测试函数。

cypher 查询的输出如下表所示:

作者图片

嗯…如果我们能在熊猫的数据框架里找到那张桌子,那当然很好…

让我们这样做:

我们将上面的 cypher 查询作为字符串(使用三重引号)存储在变量 query 中。然后在一个选择的函数或方法中,你可以像这样做

**loader = self.loader
records = loader.work_with_data(query)
df = pd.DataFrame(records, columns=["distances", "test_functions", "test_source", "targets", "target_source"])**

然后,您将在 DataFrame 对象中获得该表,然后就可以使用它了。

找到所有非测试函数可能会派上用场,所以让我们构建它。

在继续之前,我们应该定义我们所说的安全分数的含义。

对于给定的函数 f ,我们将 f测试范数定义为图中最近的测试函数与f之间的距离

  • 按照惯例,所有测试函数的测试范数都是 0。
  • 如果一个函数被一个测试函数调用,范数是 1,
  • 如果一个函数(未被任何测试函数调用)被另一个被测试函数调用的函数调用,则范数为 2,以此类推。
  • 如果一个非测试函数没有从测试函数到其自身的路径,那么测试范数是无穷大。

现在让我们定义整个项目的安全分数σ。设 NT 为非测试函数集合,设 N = |NT|。然后我们定义

注意到

  • 如果项目中的所有函数都被直接测试,也就是说,如果所有函数的测试标准都是 1,那么σ = 1
  • 如果没有一个函数被测试过,既不是直接测试也不是隐式测试(通过其他函数),那么σ就是空和,按照惯例是 0。

因此,0 < σ < 1,越接近 1,代码就越安全,越容易测试。

这个公式背后的思想是,一个给定的函数离测试越远,它的测试就越弱。然而,我假设对图中更远处的函数进行了“平均”弱测试。但这当然只是一个定义。我们总能改变这一点。例如,由许多不同的测试函数调用的函数可能比只由一个函数调用的函数测试得更好,而我们在这个版本的项目中根本没有考虑这一点。不过它可能会有更高的版本。

让我们实现这一点。

这是可行的,对于上面的项目,我们得到了大约 0.2 的分数,但是我们需要记住,只有当你在文件名或者你用来测试你的代码的对象的开头有“test”这个词时,这才是可行的。

我将把构建这个映射他/她自己的 Python 作为一个练习留给读者,因为我不被允许开放这个项目的源代码。但是,我会给你一些提示,告诉你如何自己构建这个。

  • 我有一个主类,当我逐行遍历文件时,它跟踪并存储节点和关系。
  • 当迭代时,我们跟踪我们在范围中的位置。我们在一个班级里吗?,一个函数?等。
  • 如果分别有对另一个函数或类的调用或实例化,我们存储对象并创建关系
  • 如果当前行包含定义,那么我存储对象和父对象(如果有的话),例如方法和类。然后我以 IS_METHOD_IN,IS_FUNCTION_IN 的形式存储关系。

所以基本上它是关于编码一个 python 语法解析器。

让我告诉你,这比你一开始想的要复杂得多。

我们需要跟踪其他文件的导入和调用,同时构建一个文件爬虫,因为您不知道存储库有多深。我们存储的每个对象都有一个创建它的源文件,我们需要将它存储为节点的属性,因为如果两个对象在两个不同的文件中被称为相同的,我们需要小心,不要在创建图形时将它们合并到同一个对象中。

当我看完所有的。py 文件,我从存储的数据中创建了一些 CSV 文件,我使用上面定义的 LoadGraphData 类通过 LOAD CSV 查询将这些文件从 Python 加载到 Neo4j 中。

已知项目的地图

这是一个你可能听说过的项目的地图。

美汤

作者图片

这是一张很好的地图,展示了美丽的汤里发生了什么。注意大的集群是如何连接的。

虽然这段代码还不完美,但我相信它在未来会变得非常有用。我目前正在开发一个更稳定的版本,它也考虑到了从 python 打开文件的问题。

如果你想了解更多关于这个项目的信息,你可以在 LinkedIn 上找到我。请随意和我聊一两个问题。

**https://www.linkedin.com/in/kasper-müller-96ba95169/ **

在 TensorFlow 和 Keras 中从头开始构建一个面具 R-CNN

原文:https://towardsdatascience.com/building-a-mask-r-cnn-from-scratch-in-tensorflow-and-keras-c49c72acc272?source=collection_archive---------2-----------------------

讲解如何建立一个基本的面具 R-CNN,以学习为目的,没有喧嚣。

如果你曾经想在 TensorFlow 中从头实现一个 Mask R-CNN,你很可能找到了 Matterport 的实现。这是一个伟大的,如果你只想使用一个面具 R-CNN。然而,由于它非常健壮和复杂,很难彻底理解它的每一点。更大的问题是,它不能运行新版本的 TensorFlow。

如果你有机会使用 PyTorch 实现,最常用的是 Detectron2 ,它也很难理解,因为它很复杂。

从所有关于 Mask R-CNN 如何工作的描述来看,实现起来似乎总是非常容易,但不知为何你还是找不到很多实现。

本文的目的是理解 R-CNN 掩码的基础,以及如何实现它。(假人用口罩 R-CNN?)因此,我的实现缺少了原始实现的一些重要部分,因为这主要是为了理解 R-CNN 是如何构建的。

*在我的实现中,基础模型不是特征金字塔网络(FPN),ROI Align 也没有实现。

为了训练和测试,我从 LIDC-IDRI 公共肺部 CT 扫描数据集生成了一个玩具数据集,目标是分割非常(可笑?)简单的形状。为此,我放置了不同大小的心脏,并开始进行 CT 扫描,这些是我的面罩 R-CNN 必须找到、分类和分割的对象。

这就是 R-CNN 完整的面具的样子。绿色虚线方框标记了不同的神经网络。因此,整个模型由 4 个神经网络模型组成。图片作者。

1。第一步,要有骨干模型。这是一个简单的分类器模型。在我的例子中,它是一个多类标签分类器,在 matterport 的例子中,它是一个带有 ResNet101 主干的预训练 FPN。当训练掩模 R-CNN 时,我们永远不会使用这个网络的预测,我们只需要一个内层特征图。在分类器网络内部生成的那些特征地图将成为我们的区域提议网络(RPN)的输入。

我们的分类器是从输入到标签的 keras 模型,但是我们也保存了从输入到 featuremap 的 keras 模型(featuremap_model)。在训练分类器之后,该特征映射模型将从输入图像生成特征映射。图片作者。

2。第二步是 RPN。我认为这可能是网络中最复杂的部分。RPN 需要找到感兴趣的区域(ROI)。为此,它预测了 4 个坐标,以及每个锚点的标签。什么是主播?

锚点是预定义的不同大小的矩形,覆盖整个输入图像。我们根据我们的对象选择锚的大小/比例。
我们将选择与我们的对象重叠的对象,RPN 的工作是移动它们以更好地重叠,并调整它们的大小以更好地适应(预测的 4 个坐标)。为此,RPN 还需要识别哪些锚代表对象,即哪些锚是前景锚,哪些锚是背景锚(预测的 2 个数字)。

选择固定数量的主播进行训练。为此,我们需要计算每个锚点和每个真实边界框之间的交集(IoU)。我们总是用相同数量的锚来训练,然而,在每个输入的情况下,前景锚的数量是不同的。(例如,如果我们在图像上有一个小对象,我们将有一个前景锚,如果我们有两个较大的对象,我们将有最大提议计数/2 个前景锚。)图片由作者提供。

因此,我们选择我们的建议计数(PC),它告诉我们有多少 RPN 的预测将对损失函数有贡献。(请记住,RPN 预测每个主播台!)
以我的 toydataset 为例,我们的背景(BG)远远多于前景(FG),所以我的 PC 只有 20。即使我在 CT 扫描上有一个大明星和一颗大心脏,我只有大约 10 个前景锚,我们需要一个平衡的训练。(10 FG / 10 BG)如果你有更多的多事输入图像,你的 PC 会更大。

请记住,RPN 模型预测每个锚点的增量值和 fg/bg 标签。

对于这 20 个锚,我们知道真相标签和真相增量。δ是 4 个坐标:(δx,δy,δW,δH)。前两个显示了我们需要滑动锚的中心点多少,后两个显示了我们需要改变锚的宽度和高度多少。

RPN 损失由 class_loss + boundingbox_loss 组成。PC 个预测对 class_loss 有贡献,FG 个预测对 boundingbox_loss 有贡献。

RPN 损失是 class_loss 和 bbox_loss 的总和。class_loss 是一个简单的稀疏分类交叉熵,bbox_loss 是一个光滑 L1 函数。背景锚点不会导致 bbox 丢失,因为我们只需要移动已经重叠的锚点。图片作者。

在训练期间,我们简单地使用 rpnloss 作为 classloss + deltaloss 之和。如果有必要,我们可以使用损失权重。

现在,我们选择我们预测的锚作为前景,并将其与相应的预测增量一起移动。所以我们会有 NumberOfForegrounds * 4 个坐标,这些是我们的 ROI。我们从特征图中剪切这些区域,并将它们调整到相同的大小:这些是提议。这些将是我们的类、boxrefinement 头和 maskhead 的输入。(这些神经网络模型需要有一个固定的输入形状,为此,我们总是可以用零填充我们的预测。)

图片作者。

因为我们最多有两个对象是输入图像,所以我们的 RPN 很有可能移动了不同的锚点来与同一个对象重叠。我们将使用非最大抑制来过滤掉高度重叠的提议,因为它们是不必要的。我们只会保留最好的。

3。最后一步是“头部”模型,这些可以并行训练。
在我们有了我们的建议之后,我们需要一个神经网络来进一步细化包围盒坐标,并且预测分类标签。因此,它不仅会预测一个区域是前景还是背景,而且如果它是前景,它会对它进行分类(在我的 toydatasets 案例中是心形或星形)。就像在 RPN 的情况下,只有前景建议会造成盒损失,并且任意固定数量的建议 classlabel 会造成类损失。

我们不仅为每个建议预测一组盒精化坐标,而是三组。三是班级人数+1 为背景。

所以在我们的例子中,我们预测每个提议的 3*4 坐标。我们将基于我们在同一网络中预测的类来选择适当的盒细化坐标。

在训练过程中,我们简单地使用 chloss 作为 classloss + deltaloss 的总和。如果有必要,我们可以使用损失权重。我们使用一个新的提议计数,因为我们对 RPN 提议使用非最大值抑制,以避免提议重叠。正因为如此,我们将只剩下很少(< 5)的前景框,我们希望有一个平衡的训练。(大约 5FG-5BG 提案)

maskhead 是一个卷积网络,末端有一个上采样层。它仅对接收到的 ROI(而不是整个图像)预测一个遮罩。

最后一个卷积层的滤波器数目等于类的数目。当检查预测掩码时,我们需要使用过滤器,对应于 classlabel。因此,如果我们的标签是:0:star,1:heart,并且我们的输入图像上有一颗心,我们将从 filter 维度中获取第一个轴。

正如我之前提到的,这些头部模型可以并行训练,但是,如果没有分类预测,你无法预测一个面具。(与预测的情况一样,您没有基础真实类标签,因此您将需要预测类标签来选择合适的掩膜。)

这就是了,我们有一个正常工作的 R-CNN。希望这篇文章有助于理解基础知识,以便您可以实现自己的,甚至是改进的 Mask R-CNN。

你可以在 https://github.com/rajkifranciska/maskrcnn-from-scratch
找到整个实现和 toydataset 生成文件

如果这篇文章有帮助,请引用我的话:

@misc {rajki_2021,
title = {在 TensorFlow 和 Keras 中从头开始构建一个面具 R-CNN },journal={Medium},
author={Rajki,Franciska},
year={2021},month={Mar}}

[1].瓦利德·阿卜杜拉
掩膜 R-CNN 用于 Keras 和 Tensorflow 上的物体检测和实例分割,2017
https://github.com/matterport/Mask_RCNN

[2.]吴雨欣,亚历山大·基里洛夫,弗朗西斯科·马萨,卢万延,罗斯·吉斯克
侦探 2 ,2019
https://github.com/facebookresearch/detectron2

[3].阿玛托三世,SG;麦克伦南,G;比达乌,L;McNitt-Gray,MF;迈耶河;美联社里夫斯;赵,乙;阿伯勒博士;亨施克,CI;埃里克·霍夫曼;卡泽罗尼,EA;麦克马洪;范·比克,EJR;Yankelevitz,D;Biancardi,AM;淡而无味,PH;布朗,密西西比州;恩格尔曼,RM;拉德拉赫,葛;Max,D;Pais 清,DPY 罗伯茨,RY;阿肯色州史密斯;斯塔基,A;巴特拉,P;卡利久里,P;法鲁奇,阿里;Gladish,GW;裘德,CM;Munden 佩特科夫斯卡,我;、乐;施瓦茨,LH;孙达拉姆湾;多德,勒;费尼莫尔,C;Gur,D;彼得里克,N;弗莱曼,J;柯比,J;休斯湾;卡斯特利,AV;Gupte,S;萨拉姆,M;医学博士希斯;MH 库恩;Dharaiya,E;伯恩斯河;Fryd,DS;萨尔加尼科夫,M;阿南德五世;Shreter,U;Vastagh,S;克罗夫特,由;克拉克唱片公司。
http://doi.org/10.7937/K9/TCIA.2015.LO9QL9SX】肿瘤影像存档,2015
T24

使用 Google Cloud Run 构建微服务

原文:https://towardsdatascience.com/building-a-microservice-with-google-cloud-run-90f8df9682da?source=collection_archive---------22-----------------------

在 Cloud Run 上设置一个简单的 web 应用程序来更新 Big Query 中的表

照片由 Sebastian Herrmann 拍摄自 Unsplash

云上运行快速介绍

Google cloud run 是一个完全托管的计算平台,用于在云上运行容器化的应用程序。Cloud run 通过基于应用流量的自动扩展功能,消除了管理所有基础架构的复杂性。

在本文中,我们将了解使用 python 和 flask 创建云运行微服务的方法,我们将把它们部署到 Docker 容器中。微服务将具有根据用户输入更新谷歌大查询表的功能。以下是将要使用的产品/服务:

  • Python 和 Flask
  • 码头工人
  • 谷歌云运行
  • 谷歌云容器注册中心

最终结果将是一个运行在 HTTP 上的 web 应用程序,用户可以提交他们的输入,更新 Google Big Query 中的一个表。

我们开始吧!

本文假设您已经设置了一个 Google Cloud 帐户。

所有的脚本都可以在这里找到: GitHub

(1)开发微服务所需的文件/脚本

对于这个例子,我们将创建一个简单的应用程序,用户可以通过将输入传递到微服务链接,将书名和作者的新记录插入到一个大的查询表中。

创建云运行服务需要准备 3 个不同的文件。

  • main.py
  • requirements.txt
  • Dockerfile 文件

文件号 1: main.py

该文件将启动 Flask app,并包含 python 函数,该函数接收用户输入并更新到 Google Big 查询表中。

from flask import Flask, request, make_response, jsonify
import pandas as pd
import gcsfs
from google.cloud import bigquery
from google.oauth2 import service_account
import pandas_gbq
import osapp = Flask(__name__)app.config["DEBUG"] = True #If the code is malformed, there will be an error shown when visit app[@app](http://twitter.com/app).route("/books", methods=["GET"])
def books_table_update():

    Title = request.args.get('title', None)
    Author = request.args.get('author', None)input_table = {'book_title':[Title],'book_author':[Author]}
    input_table = pd.DataFrame(input_table)
    input_table["book_title"]= input_table["book_title"].map(str)
    input_table["book_author"]= input_table["book_author"].map(str)

    #Push table to Google Big Queryclient = bigquery.Client()
    project_id = 'sue-gcp-learning-env'
    table_id = 'Books.books_title_author'
    pandas_gbq.to_gbq(input_table, table_id, project_id=project_id, if_exists='append')

    return "Table books_title_author has been Updated"

文件号 2: requirements.txt

要求文件,以指定安装所需的库。

Flask
gunicorn
google-api-core
google-cloud-bigquery
pandas
pandas-gbq
gcsfs

3 号文件:Dockerfile

Dockerfile 文件指定如何创建容器:

  • 从官方 python 3.9 映像构建一个容器
  • 将本地代码复制到容器映像
  • 在 requirements.txt 文件中安装软件包
  • 在容器启动时运行 web 服务
# Use the official lightweight Python image.
# [https://hub.docker.com/_/python](https://hub.docker.com/_/python)
FROM python:3.9-slim# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./# Install production dependencies.
RUN pip install  --no-cache-dir -r requirements.txtENV PORT 8080CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

(2)将所有 3 个文件/脚本上传到云壳编辑器

在将文件/脚本上传到云壳编辑器之前,您需要在 Google 云控制台中激活云壳并创建一个文件夹。

mkdir books_update

在云壳中打开编辑器

右键单击新创建的文件夹或通过文件,将所有需要的文件/脚本上传到 books_update 文件夹。上传完成后,点击“打开终端”返回外壳编辑器。

将所有 3 个文件上传到创建的文件夹中

(3)构建&部署新的 Docker 映像

太好了!我们现在准备构建一个新的 docker 映像,它将在我们选择的区域运行。

gcloud config set run/region asia-southeast1gcloud builds submit --tag gcr.io/sue-gcp-learning-env/books_update

构建 Docker 映像的命令

构建完成后,运行下面的命令来部署新构建的映像。您需要提供云运行服务名称。当容器构建完成后,将会提供您的服务 URL。

gcloud run deploy --image gcr.io/sue-gcp-learning-env/books_update --platform managed

部署 Docker 映像并设置云运行服务名称

(4)你的服务准备好了!

容器构建完成后,将提供服务 URL。或者,我们可以从云运行中跟踪我们部署的服务。

云运行服务:图书更新

(5)让我们测试一下我们的服务

在调用服务之前,让我们检查一下调用服务时将要更新的大查询表。在这个表中,books_title_author 当前有 2 条记录,我们将通过调用我们的服务向这个表中添加一条新记录。

大查询表:books_title_author(调用服务前)

在这里,我们调用服务并传递我们想要为新记录添加的输入值。如果服务运行成功,它将返回我们指定的消息:“表 books_title_author 已更新”。

调用云运行服务并传递用户输入

让我们在 Google Big Query 中检查我们更新的表。

大查询表:books_title_author(调用服务后)

正如我们在刷新后的表中看到的,新记录是根据调用 URL 时指定的输入插入的。我们已经成功地在 Cloud Run 上创建了一个简单的 web 应用程序,它更新了 Google Big Query 中的一个表。

结论

通过 Google Cloud Run 部署微服务变得更加容易和方便,因为管理服务器的过程已经得到处理。只需要几个步骤,您就可以立即部署无状态微服务。下面是文章中解释的步骤的摘要:

  • 准备 3 个主文件/脚本,包括(main.py、requirements.txt 和 Dockerfile)
  • 将您的文件上传到 Google Cloud shell 编辑器以创建 Docker 容器。
  • 部署完全构建的映像以创建完全托管的 web 应用程序。

这就是在云上创建微服务所需了解的全部内容。我希望这篇文章对那些学习使用 Google Cloud Run 创建微服务的人有用。

参考文献

[1]https://cloud . Google . com/run/docs/quick starts/build-and-deploy/python

[2]https://cloud . Google . com/blog/topics/developers-从业者/cloud-run-story-server less-containers

[3]https://www . kdnugges . com/2021/05/deploy-dockerized-fastapi-app-Google-cloud-platform . html

构建朴素贝叶斯机器学习模型对文本进行分类

原文:https://towardsdatascience.com/building-a-naive-bayes-machine-learning-model-to-classify-text-71431ce20844?source=collection_archive---------8-----------------------

这是一个快速入门指南,帮助您使用 Python 启动并运行一个简单而高度相关的 NLP 项目

Python 中的朴素贝叶斯(所有图片由作者提供)

介绍

自然语言处理(NLP)是一个非常令人兴奋的领域。它位于计算机科学、语言学和人工智能的交汇点,关注人类语言和计算机之间的交互。更具体地说:它的目标是理解如何给计算机编程,以理解和解释我们的自然语言。

现在这是一个非常热门的研究领域,我很幸运能够在这个研究领域绝对前沿的大学就读。虽然作为一名卑微的本科生,我并不经常接触这种前沿工作——如果我接触了,我会理解的!

尽管如此,建立模型对自然语言进行分类还是相对简单的。这是一个很酷的练习,因为它是相关的。这是一个非常真实的 ML 应用,你可以在自己的项目中使用。

贝叶斯定理

朴素贝叶斯

朴素贝叶斯算法是一种更简单的监督贝叶斯网络模型,它是一种基于贝叶斯定理的概率分类器(您可能还记得高中的统计数据)。但它的简单性并不使它成为一个糟糕的选择,即使数据集不是很大(只有几千个样本),它也可以产生高度准确的预测。

如果你真的是机器学习的新手,我建议阅读一些关于更基本算法的文章,然后回到这一篇,因为我将建立在这些文章中详细解释的概念上。

本质上,两个事件发生的条件概率是根据每个事件的条件概率计算出来的。因此,对于给定的一段文本,计算每个标签的概率,并输出具有最高概率的标签。

还有其他合适的选择,如支持向量机(SVM),它需要更多的时间和计算资源来工作,但会产生比朴素贝叶斯更准确的预测。或者,您可以考虑基于神经网络的深度学习方法,但这将需要更多的训练数据。

米卡·鲍梅斯特在 Unsplash 上的照片

这个例子

这是一种方法:

  1. 导入和设置数据。
  2. 做一些分析以了解更多关于数据环境的信息。
  3. 创建我们的因变量和自变量列表,用于训练和验证。
  4. 给标签编码。
  5. 从描述中提取特征。
  6. 使数据符合模型。
  7. 检查模型的准确性。

这个项目将演示如何根据银行交易的描述对其进行分类。我的数据集包含 12500 个样本,包括交易金额和交易类型等其他特征,您可以在模型中使用任意数量的特征,甚至可以选择一些特征来查看哪些特征对预测的影响最大,但为了简单起见,我们将只使用描述。

在我的数据集中,描述是这样的:

citylink
1Jul19 OYSTER
travelodge
6Jul19 RINGGO
SUNDRY DEBIT CONTACTLESS CAMDEN PARKING
stgcoach
trainline
Fin: CMT UK LTD  Cash at Transact

设置

当然,从进口开始。

  1. 创建数据框架的熊猫。
  2. sci kit-了解标签编码、特征提取、建模和测量成功指标
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.feature_extraction.text import CountVectorizer
from sklearn import naive_bayes, metrics

接下来,让我们处理 csv 文件,并为模型做好准备。(当然,你可能没有处理 csv 文件,只是把你所有的数据导入到熊猫数据框架中):

features = pd.read_csv("bank_transaction_features.csv")
labels = pd.read_csv("bank_transaction_labels.csv")

我有两个数据集:一个包含要素,一个包含标注(类别)。这些是它们各自的列:

**bank_transaction_features:**
bank_transaction_id, bank_transaction_amount, bank_transaction_type**bank_transaction_labels:**
bank_transaction_id, bank_transaction_category, bank_transaction_dataset

它们有一个共同点,ID 列。因此,我将在这一列中合并它们,并删除任何具有空条目的行(在我的数据中很少,您应该计算有多少,因此删除它们对预测的影响可以忽略不计):

combined_df = pd.merge(left=features, right=labels)
combined_df = combined_df.dropna()

探索性分析

总是从一些探索性的数据分析开始。我的数据集有数以千计的样本,我无法通过扫描看到所有的类别。我们需要做一些简单的事情来更好地理解数据。

该数据集有一列指定样本是用于训练还是验证。这将在以后派上用场,因为我们不需要创建我们自己的训练/验证分割。但是对于探索性分析,我们可以删除该列(只从我们将创建的新 dataframe 变量中删除该列,保留包含该列的变量)。

explore_df = combined_df.drop(labels=['bank_transaction_dataset'], axis=1)

我们可以很容易地看到数据中存在哪些类别,以及每个类别中有多少个样本:

print(explore_df['bank_transaction_category'].value_counts())

结果是:

ACCOMMODATION_AND_MEALS    3765
TRAVEL                     3166
BANK_OR_FINANCE_CHARGES    2659
MOTOR_EXPENSES             1609
INSURANCE                  1170
Name: bank_transaction_category, dtype: int64

现在,让我们检查一下培训/验证分割是什么(使用仍有相关列的数据帧):

train_set = combined_df.loc[combined_df["bank_transaction_dataset"] == "TRAIN"]
val_set = combined_df.loc[combined_df["bank_transaction_dataset"] == "VAL"]

len_train = len(train_set)
len_val = len(val_set)
len_whole = len(explore_df)
print('Amount of training data: ', len_train)
print('Amount of validation data: ', len_val)

输出:

Amount of training data:  9891
Amount of validation data:  2478

这使得训练/验证的比例为 80/20,这是一个很好的比例,所以根本不需要调整。

分类

最后,有趣的部分。首先,创建 x 和 y 训练和验证子集。我们可以通过创建只包含相关列中数据的列表来实现这一点:

y_train = train_set['bank_transaction_category'].values
x_train = train_set['bank_transaction_description'].values

y_val = val_set['bank_transaction_category'].values
x_val = val_set['bank_transaction_description'].values

现在变得非常有趣了。需要记住的是,ML 模型不“理解”文本和单词。他们理解数字。因此,准备数据以适合模型的第一件事是对标签进行编码。这意味着,给每个标签分配一个号码。例如:

ACCOMMODATION_AND_MEALS    => 0
TRAVEL                     => 1
BANK_OR_FINANCE_CHARGES    => 2
MOTOR_EXPENSES             => 3
INSURANCE                  => 4

这是通过创建一个 LabelEncoder 对象并对因变量数据( y )使用其 fit_transform 函数来实现的:

label_encoder = LabelEncoder()
y_train = label_encoder.fit_transform(y_train)
y_test = label_encoder.fit_transform(y_val)

描述数据也是如此,只是这个稍微复杂一点。在一些模型中,你有一组统一的描述,并且你知道它们是什么,你可以把每一个编码成一个整数,它们就准备好了。但是在这里,每个事务描述都可能是唯一的。

解决方案是从文本中提取特征,并将这些特征转化为模型可以理解的向量。

特征抽出

虽然在技术上很复杂,但这可以简单地实现,通过使用计数矢量器将文本转换为令牌矩阵,并转换训练和验证独立变量( x ):

count_vector = CountVectorizer(analyzer='word', token_pattern=r'\w{1,}')
count_vector.fit(combined_df['bank_transaction_description'])

x_train_count = count_vector.transform(x_train)
x_valid_count = count_vector.transform(x_val)

就是这样!我们可以拟合数据、训练模型并做出预测:

classifier = naive_bayes.MultinomialNB()
classifier.fit(x_train_count, y_train)

predictions = classifier.predict(x_valid_count)

准确(性)

您可以使用几个指标来确定模型的工作情况。我们会用准确性。这将告诉我们模型正确预测银行交易类别的频率:

print(metrics.accuracy_score(predictions, y_test))

该模型的精确度为:

0.91

一点也不差。

结论

这是一个有趣的例子,因为它是有形的。例如,在移动金融跟踪应用程序中将银行交易分类是这种算法的一个非常真实的用例。我希望您对朴素贝叶斯是如何工作的,以及如何实现它对文本进行分类有了很好的理解。

如果你确实学到了一些东西,有任何问题,认为我错过了任何重要的东西,或者计划在你自己的项目中使用这个算法,请通过留下回复让我知道,我们可以讨论它。

编码快乐!

订阅 📚为了不错过我的一篇新文章,如果你还不是一个中等会员,加入 🚀去读我所有的,还有成千上万的其他故事!

资源

Scikit Learnsk Learn . preprocessing . label encoderhttps://Scikit-Learn . org/stable/modules/generated/sk Learn . preprocessing . label encoder . html

Scikit Learnsk Learn . feature _ extraction . text . count vectorizerhttps://Scikit-Learn . org/stable/modules/generated/sk Learn . feature _ extraction . text . count vectorizer . html

维基百科 自然语言处理https://en.wikipedia.org/wiki/Natural_language_processing

MonkeyLearn 文本分类https://monkeylearn.com/text-classification/】T4

建立相关信息技术技能的网络

原文:https://towardsdatascience.com/building-a-network-of-related-it-skills-cfc6e1827261?source=collection_archive---------26-----------------------

我分析了 30,000 份工作描述,构建了一个相关 IT 技能的网络图。

介绍

IT 职位描述提到了大量不同的框架、编程语言和其他技能。HTML 和 CSS 这样的语言显然是齐头并进的,但是有哪些不太明显的联系呢?在这个分析中,我分析了 30,000 份职位描述,以便找出专业职位的不同技能之间的关系。

我必须承认,我最初对工作描述数据集有另一个想法,但在这个过程中,进行这种网络分析似乎很酷。我仍然会完成原来的项目,但同时我想与你分享这个“信息技术技能分析”的过程。

请记住,本文仅仅描述了构建网络的过程。实际结果可以在这里找到

获取数据

从这个项目一开始,我就认为寻找数据是最困难的部分。基本上,我在搜索符合以下标准的数据集:

  • 至少 10k 张唱片
  • 包含职位描述的完整文本
  • 所有职位描述都是针对 IT 职位的
  • 最好是全英文的
  • 最近(不到 3 岁)

我最初的想法是刮 Indeed.com。我很快使用 BS4 构建了一个简单的刮刀,但是在大约 1000 次请求之后,他们阻止了我。这给了我三个选择;改进刮刀以避免堵塞,刮另一个来源或寻找现成可用的数据集。我选择了后者,并很快在 Kaggle 上找到了这个数据集。尽管数据集不包含完整的描述,但有一列列出了所有技能,这正是我所需要的。

我下载了数据集,旋转了一个 Jupyter 笔记本,并调用了我忠实的熊猫 (Python 库)。

实体提取

这个概念

尽管数据集包含一个列有技能的列,但数据仍然非常粗糙。分析该列时,我们得到以下指标:

  • 总技能:366528
  • 绝技:6783
  • 最短的技能:几乎任何单个字符
  • 最长技能:咨询对应

当查看每项技能的出现次数时,最受欢迎的五项是:销售、管理、开发、执行和业务。考虑到所有这些信息(技能总数、拼写错误和不相关或过于普通的技能),生成一个有限的相关技能集可能具有挑战性。在网络图中,我们使用术语实体,在这种情况下是技能。提取实体(或者在这种情况下获得一个清晰的技能列表)是生成网络数据过程的关键步骤。

创建网络图的步骤。(图片由作者提供)

方法

在我们的数据集中,每条记录代表一个不同的工作描述。“关键技能”列包含由竖线(|)分隔的技能列表,例如:

“分析| SQL| MS Office|审计|金融服务| Oracle|数据挖掘|业务运营|资产管理|监控”。

将竖条上的技能分开后,我们有了如上所述的 6783 个独特技能的长列表。现在,让我们试着把这个长长的列表简化成更小、更简洁、更有用、更相关的技能。

首先,我试图通过将所有内容转换成小写并删除所有前导和尾随空格来尽可能避免明显的重复。这应该确保例如“javascript”和“JavaScript”不被视为独立的技能,而仅仅是大写的原因。

一旦完成,我过滤掉这些技能,只显示那些出现至少 50 次的技能。这使得独特技能的总数下降到 2079。

为了进一步过滤,我使用了一个 Python 库来指示一个单词是否在英语词典中。大多数技术都有“CSS”或“PHP”这样的名字,在英语中几乎没有任何意义。然而,其他一些语言和工具确实在字典中占有一席之地,如“python”或“azure ”,所以对于剩余的单词,需要进行一些手动审查。

在完成这个人机交互的审查和筛选过程后,我有了一个大约 400 项与 IT 工作相关的技能的列表。

将这些点连接起来

好了,现在我有了要使用的技能列表和完整的数据集,是时候把这些点连接起来了。为了统计描述中每个技能的出现次数,我使用了一个叫做虚拟表的东西。基本上,它是一个表,其中你的列只有 0/1 值,表示一个真或假的位置。第一列(或索引)包含工作描述,而每一列代表一项技能。如果技能存在,单元值(工作描述和技能之间的交集)将为 1,否则为零。结果看起来像这样;

虚拟桌子。行:工作描述,列:技能(作者图片)

使用这个虚拟表,我创建了一个关联表。该表本质上指出了哪些列(或技能)具有相似的 0 和 1 模式。换句话说,它显示了哪些技能经常出现在同一个职位描述中。例如,如果两种技能总是出现在相同的描述中,它们在相同的记录中总是具有“1 值”,这将导致完美的关联:1。

从相关表中,我可以创建一个有 3 列的网络图表;两个用于所有技能的所有组合(例如 A 列(源));“HTML”,col B(target)“CSS”等)和一个与这两种技能之间的相关性。我过滤了这个表,只显示相关性至少为 0.15 的技能组合(1 表示完全相关)。这是必要的,以防止他们所谓的“一团乱麻”,一个节点和边太多的网络图变得不可读。最后,我添加了一列“权重”,表示源技能在所有描述中出现的频率。权重将用于确定节点的大小(半径)。像 JavaScript 这样的流行语言出现在许多职位描述中,因此权重更大。

这张表包含了我可视化结果所需的所有信息。然而,即使数据已经准备好可视化,我们稍后还会回到这一步。网络图构建通常是一个迭代过程,在这个过程中,您使用最终结果(可视化)来细化、过滤和重新校准您的图模型。这基本上意味着你在数据和图表之间来回切换,以获得最佳结果。

实体提取的迭代过程。(图片由作者提供)

结果呢

视觉结果

在将前面步骤中的表格转换成 JSON 文件后,我构建了一个 D3.js 强制定向图。哪像这个

部分网络图截图。(图片由作者提供)

当然这仅仅是截图的汇编,完整的互动网络图可以在我的网站上找到,在那里你可以通过拖拽来缩放和移动节点。

节点的大小代表数据中的总出现次数,而边的厚度代表相关性的强度。换句话说,用粗边连接的两个大节点意味着这两种技能出现了很多次,并且经常一起出现。

技术细节

对于那些更熟悉开发网络图的人,我列出了一些关键指标:

  • 节点:177
  • 边缘:415
  • 平均聚类系数:0.48
  • 传递性:0.48
  • 派系数量:152

中心性、Pagerank、Between 和 degree 分布。这张表是按照中心性排列的前 10 名。(图片由作者提供)

表格和直方图中显示的所有信息仅仅是网络图中显示内容的汇总版本。例如,中心性表示每个节点(或技能)相对于整个网络有多少条边(连接)。

Pagerank 和 betweenness 是相似的,但是更高级的度量标准。如果你想了解更多关于这些(和其他)网络指标的信息,你可以在维基百科或其他许多免费在线资源上找到。

洞察力

网络图清楚地显示了由 IT 中常见角色(如数据、设计、系统、前端等)定义的不同集群。该图表还显示了集群之间的关键连接器。如果你想进入一个新的领域,这可能会很有帮助,因为关键的连接器技能提供了一个与两个领域都相关的良好起点。

开始他们的计算机科学或编码之旅的人也可以识别哪些技能可能是在他们最感兴趣的领域获得个人成长的良好开端。

虽然这张图表没有提供任何有待发现的突破性见解,但它似乎提供了一种非常直观和容易理解的方式来查看 it 招聘前景。

进一步研究和改进

更多数据

这适用于我几乎所有的项目,无论是专业的还是个人的。很少有更多的数据对模型、指标、可视化或其他数据应用程序没有好处的情况。虽然我很高兴发现这个数据集有 30k 条结构良好的记录,但如果能有更多就更好了。另一种可能性也可以是使用提取的实体并将它们应用于其他数据集。这相当简单,因为构建技能列表最需要干净的数据。

时间序列

我经常感兴趣的另一个观点是时间序列。对于这个项目来说,看到不同的 it 技能和它们的重要性是如何演变的将是特别令人着迷的。在多年的时间里,你可能会看到某些新技能是如何融合和扩展的,而其他技能会像我们银河系中的黑矮星一样慢慢萎缩和消亡。

无监督聚类

对于大多数职位描述来说,把它们归类到特定的职位群中并不困难。例如,大多数需要机器学习技能的工作最有可能被贴上数据科学或者数据工程的标签。这些集群通常是显而易见的,也是众所周知的,但以一种无人监管的方式发现集群将会很有趣。这意味着我们将所有数据输入机器,看看它是否能为我们找到特定的(重复出现的)配置文件。

高级实体配对

最后,我觉得在实体配对过程中可以做很多改进。我在个人项目上投入的时间和精力是有限的,我可能在开发的这个特定部分走了太多捷径。实体配对是复杂的,需要大量的手工修改和特定领域的知识。有无数的框架、语言和专业,其中许多我都不熟悉。我可能删除了相关的或者忽略了它们的配对。在实体提取和配对上花费更多的时间肯定会改进这个模型。

技术堆栈

Python (Pandas,Numpy,NLTK 和 RegEx),JavaScript (D3.js),HTML 和 CSS。

关于我:我叫布鲁诺,是一名数据科学顾问。如果你想看看我做的其他东西,比如咕哝说唱探测器,一定要看看我的个人资料。或者通过我的网站与我联系:https://www . zhongtron . me

用 Python 在 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 上构建一站式 API 调用程序

原文:https://towardsdatascience.com/building-a-one-stop-api-caller-on-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-with-python-f8ff845d5985?source=collection_archive---------17-----------------------

在电报机器人上检索最新的天气、新闻、推文和一丝快乐

图片由作者提供— motherofapi 电报机器人

在我之前的文章中,我写了我如何利用电报机器人进行爱的告白。这个想法实际上是在我构建我今天要写的这个 bot(如上面的截图所示)时产生的,它是一个一站式门户,集成了来自公共可用资源的多个应用程序编程接口(API)调用来检索信息。以下是我在这个机器人中包含的 API 列表,我将解释我是如何设法集成到我的电报机器人中的:

  1. 可引用的(/激励)——用于随机激励引用
  2. random . dog(/dog)—为一张随机的狗狗图片/gif
  3. reddit(/memes)—来自 Reddit 的随机 memes
  4. unsplash(/壁纸) —从 Unsplash 中随机选择壁纸
  5. openweathermap(/weather)——新加坡今天的天气
  6. 推特 (/tweets) —与用户输入相关的最新推文
  7. newsapi(/news)——新加坡今日最新消息

在 BotFather 上创建 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 bot、将其托管在 Heroku 服务器上的步骤,以及如何通过 Python 在 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 Bot 上构建命令处理程序,本文都不会提及。如果你有兴趣,可以参考我以前的文章或者去谷歌一下!从一开始就自己动手做东西绝对是一件有趣又充实的事情。

/motivate 命令

励志名言是我经常听到的,有时候当我需要一些额外的动力来度过一天时,我会浏览 Instagram 或脸书等社交媒体平台来寻找它们。谢天谢地,这样的 API 是存在的,而且它来自 quotable 。如果你点击链接,一个随机的引用将以 JSON 格式出现,这是一个非常好的结构化的数据返回方式。

# motivational quote
def motivate(update, context):
    quote = requests.request(url='[https://api.quotable.io/random',method='get'](https://api.quotable.io/random',method='get'))
    update.message.reply_text(quote.json()['content'])

这方面的 Python 代码非常简单,其中创建了一个命令motivate,然后该命令将对 quotable API 进行请求调用。在此之后,我们的机器人将只返回返回结果的内容部分中的内容,这将在电报上向用户显示报价。

作者图片—/激励命令

/dog 命令

在最初阶段,当我对用 Python 构建一个电报机器人非常好奇时,我遇到了这个 API。这个 API 会在你调用它的时候返回一个随机的狗图片或者 gif,好消息是我们也可以得到 JSON 格式的结果。

# dog pics
def dog(update, context):
    contents = requests.get('[https://random.dog/woof.json').json()](https://random.dog/woof.json').json())
    update.message.reply_text(contents['url'])

代码非常类似于motivate,其中我们创建了一个命令dog,它将在被请求时调用 random.dog API,并以 URL 的形式返回图像/gif。然后,我们继续在 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 上将 URL 返回给用户,这将直接在 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 上显示图像/GIF。

图片作者—/狗命令

/memes 命令

模因现在真的很受欢迎,谢天谢地流行论坛网站 Reddit 有这样一个 API。这个命令不像前两个命令那么简单,因为我们需要在 Reddit 上创建一个帐户,以便能够使用它的 API,其中包含一些认证信息(即 client_id、client_secret、password、user_agent、username )。

# memes
def memes(update, context):
    reddit = praw.Reddit(client_id='...',
                     client_secret='...', 
                     password='...',
                     user_agent='...',
                     username='...')
    subreddit = reddit.subreddit('memes;)
    meme = subreddit.random()
    update.message.reply_text(meme.url)

你可以参考上面关于如何设置帐户的链接,我在这里使用的 Python 库模块是 praw 你可以在这里找到文档。一旦我们用个人密钥设置了认证,我们就可以使用reddit.subreddit('memes')生成一个随机的 meme URL,当用户执行memes命令时,我们将返回这个 URL。

图片作者— /memes command

/wallpaper 命令

我相信 Medium 上的大多数作者都会熟悉平台 Unsplash ,它为我们提供了非常好的图片,供我们在文章中使用。我很高兴知道他们也有一个可供用户提出这种请求的 API。对于这个 API,您还需要在 Unsplash 上创建一个开发者帐户,您将获得一个 client_id 来包含在您的代码中。

# unsplash wallpaper
def wallpaper(update, context):
    url = '[https://api.unsplash.com/photos/random/?client_id=...'](https://api.unsplash.com/photos/random/?client_id=ZNEwrJqYtbXb1jHagKCfRVTnOe6d2rk2ACCN5d3P2HM')
    response = requests.get(url)
    wall_pic = response.json()['urls']['regular']
    update.message.reply_text(wall_pic)

使用 client_id ,API 将返回 JSON 格式的结果,其中我们将只提取URL常规维度(当用户调用wallpaper命令时,您也可以返回 raw、full、regular、smallthumb )。

作者图片—/壁纸命令

/天气命令

我记得当我在墨尔本学习时,每天早上出门前查看天气是必不可少的一步,因为那里的天气波动很大。谢天谢地,新加坡的天气波动不是很大,但是当你出门的时候,知道天气还是很好的。 Openweathermap API 是我在我的机器人中想要天气信息时的首选,它还包含其他信息,如道路风险、紫外线指数和空气污染指数。你需要为这个 API 创建一个开发者账户,在这里,你会得到一个 api_key。

# weather
api_key = "..."
base_url = "[http://api.openweathermap.org/data/2.5/weather](http://api.openweathermap.org/data/2.5/weather)?"
complete_url = base_url + "appid=" + api_key + "&q=" + "singapore" 
response = requests.get(complete_url) 
x = response.json() 
current_temperature = x['main']['temp']-273.15
feels_like = x['main']['feels_like']-273.15
weather_description = x['weather'][0]['description']
def weather(update, context):
    weather_stats = "\U0001F324 Singapore Weather \U0001F327" + "\n\nWeather Description = " + str(weather_description) + \
      "\nCurrent Temperature (in degree celsius) = " + str(round(current_temperature,1)) + \
      "\nFeels like (in degree celsius) = " + str(round(feels_like,1))
    update.message.reply_text(weather_stats)

因为我住在新加坡,所以我在请求中包含了 s ingapore 作为请求的一部分,当用户调用weather命令时,我将返回当前的温度、现在的感觉以及天气描述。注意 API 返回的温度是华氏温度,这解释了为什么需要减去 273.15 来得到摄氏度。还完成了一些文本处理和格式化步骤,以便将结果返回给用户,如下所示。

图片作者—/天气命令

/tweets 命令

我敢肯定,大多数数据科学爱好者都玩过 Twitter API,自然语言处理将在推文上完成,并可能导致情感分析。我的想法是让用户能够键入他们感兴趣的任何关键词,机器人将提取与输入的关键词相关的最新推文。我发现这在股票投资的时候(比如搜索“比特币】)或者有兴趣了解身边发生的事情的时候(比如搜索“裕廊东方】**)特别有用。

# twitter    
def tweets(update, context):
    update.message.reply_text(text='What Twitter topics are you interested in?')
def tweets_reply(update, context):
    user_input = update.message.text
    consumer_key= '...'
    consumer_secret= '...'
    access_token= '...'
    access_token_secret= '...'
    twitter = Twitter(auth = OAuth(access_token, access_token_secret, consumer_key, consumer_secret))
    latitude = 1.3521    
    longitude = 103.8198    
    max_range = 20
    query_search = user_input + "-filter:retweets"
    query = twitter.search.tweets(q = query_search, geocode = "%f,%f,%dkm" % (latitude, longitude, max_range), lang='en',count=3)
    answer = f'\U0001F4F1 Showing latest 3 tweets in SG for: {user_input}'
    update.message.reply_text(answer)
    update.message.reply_text(query['statuses'][0]['text'])
    update.message.reply_text(query['statuses'][1]['text'])
    update.message.reply_text(query['statuses'][2]['text'])

这个命令的代码比较长,它包含两个函数,一个是提示用户输入搜索词,另一个是内部调用 Twitter API,并将最近的 3 条相关推文返回给用户。像往常一样,需要一个开发者账户来获取消费者密钥、消费者秘密、访问令牌、访问令牌秘密。在获得 search_term 后,机器人将调用 Twitter API,并继续搜索新加坡最近的 3 条推文(即,我已经设置了纬度经度)。然后,tweets命令会将最近的 3 条 tweets 返回给用户。

图片由作者提供— /tweets 命令,输入“比特币”

/news 命令

最后一个命令将通过调用 newsapi API 为用户检索最新的新闻。注意,我没有将这个命令命名为news,而是分成了 5 个不同的命令covidtechnologybusinesssportsentertainment,因为 API 允许我根据类别发出请求。你还需要在这里注册一个开发者账户来获得 api_key。

# business news
newsapi = NewsApiClient(api_key='...')
business_news = newsapi.get_top_headlines(category='business', language='en', country='sg', page_size=3)
def business(update, context):
    business1 = list(business_news.values())[2][0]['title'] + '\n\n' + list(business_news.values())[2][0]['url']
    business2 = list(business_news.values())[2][1]['title'] + '\n\n' + list(business_news.values())[2][1]['url']
    business3 = list(business_news.values())[2][2]['title'] + '\n\n' + list(business_news.values())[2][2]['url']
    update.message.reply_text(business1)
    update.message.reply_text(business2)
    update.message.reply_text(business3)

我在 API 命令中列出了根据所选的不同类别检索最新的 3 条新加坡新闻。对于上面的代码,运行business命令将返回预览和来自新加坡的最新 3 条商业相关新闻的 URL 链接。

图片作者—/商业命令

结尾注释

有大量其他 API 可供开发人员免费使用,我一定会在这个机器人上添加更多命令,这样它就可以真正成为用户访问日常信息的一站式门户。这个机器人对每个人都是公开的,你可以在 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 上找到 motherofapi 来开始使用这个机器人。请注意,由于这个 bot 托管在 Heroku 平台上,当您运行它时,它可能需要 15 秒钟才能启动。希望你喜欢这篇文章以及我的机器人,并通过评论这篇文章向我推荐你希望在这个机器人中看到的可能的想法/API,干杯!😄

建立信用风险模型的可视化模型监控系统

原文:https://towardsdatascience.com/building-a-pipeline-monitoring-system-for-credit-risk-models-db55f9a49f7e?source=collection_archive---------19-----------------------

在本教程中,我们将从头开始使用 ML 构建一个信用风险模型,并使用一个使用 Datapane 的可视化跟踪系统来监控它。

纽约公共图书馆拍摄于 Unsplash

想买新房?有可能你需要从银行贷款,这将涉及信用风险评估。

什么是信用风险?信用风险是指借款人因未能支付所需款项而违约的可能性。风险是金融机构和其他贷方贷款模式的固有部分。

介绍

信贷风险建模是贷款人确定贷款偿还可能性的最有效方法。贷方使用历史数据,如支付历史、当前债务水平和信用历史的平均长度,来预测消费者未来拖欠贷款的可能性。在本教程中,我们将从头开始开发一个信用风险机器学习模型,并构建一个数据面板报告来监控和跟踪管道。

为什么需要模型监控?

我们希望确保该模型仍然可以基于新的客户数据准确预测违约者,因为人口构成可能会随着时间的推移而变化。让我们假设我们使用 2000 年至 2018 年的数据建立了一个信用风险模型——这是一个强大的数据集,因为它涵盖了很长一段时间以及像 2008 年金融危机这样的中断期。该模型在 2019 年之前表现良好,但不能确定它在 2020 年或 2021 年仍然有用——只要想想世界因 COVID 而改变了多少。监控系统有助于识别随时间的变化,以便我们可以在必要时调整我们的模型。

我们将在本教程中介绍模型开发的基础,我们的主要焦点将是使用 Datapane 创建跟踪系统。详细的代码可以在 Github 上找到

免责声明:本文是与 Datapane 合作撰写的,我是 datapane 团队的一名社区布道者。

利用机器学习建立信用风险模型

步骤 1 —初步分析

在本教程中,我们将使用来自 Kaggle 的德国信用风险分类数据集。该数据集包含 1000 个条目,具有 Hofmann 教授准备的 20 个类别/符号属性。在这个数据集中,每个条目代表一个从银行贷款的人。根据属性集,每个人被划分为好的或坏的信用风险。

来源:图片由作者创作

一旦数据加载完毕,我们将使用 Pandas Profiling 自动生成一份包含数据集基本信息的报告,如描述性统计、缺失值、相关性等。虽然通常的方法是生成一个 HTML 报告,但是我们将使用 JSON extract 来标识我们的 Datapane 报告所需的变量。

步骤 2-为报告创建数据可视化绘图

完成初步分析后,我们需要创建几个图来进行数据探索。这些图背后的想法是突出任何数据差异或现有数据的差异,这些数据是模型训练的基础。一旦创建了图,我们需要确保将它们存储在变量中,然后可以直接在我们的报告中使用。

我们为此创造了几个情节,你可以参考笔记本上的代码。

步骤 3 —预处理数据

一旦我们很好地理解了数据及其隐藏的特征,我们现在将着手建立我们的信用风险模型。但在此之前,我们将做一些基本的预处理步骤,以确保我们的数据得到很好的净化,我们可以建立一个体面的模型。

由于数据处理涉及大量数据转换,建议在报告中添加前后图像,以确保转换正常工作。

我们可以删除不需要的变量,并将数据集分成训练集和测试集。

步骤 4-训练多个模型以找到最佳模型

现在我们的数据已经准备好了,我们将训练我们的模型,根据已经标记的数据来预测一个人是否有信用风险(“Risk_bad”)。我们保留 25%的训练数据用于测试目的。

我们需要训练多个模型来找到表现最好的一个。为了快速做到这一点,我们将所有的模型添加到一个循环中,然后根据它们的回忆分数对它们进行评估。

我们以这样的情节结束-

基于此,我们将选择高斯 NB 作为我们的首选模型,因为它具有最高的准确性。

步骤 5——建立信用风险模型

我们将使用高斯 NB 算法来构建我们的模型。你可以在这里阅读更多关于这个的内容。

我们得到了 70.53%的准确率,这对于一个简单的模型来说是相当不错的。我们来评价一下分类矩阵。

我们得到了 68%的精确度和 65%的召回分数,以及 66%的 F1 分数。虽然分数不是最佳的,但我们总是可以提高。如果你对提高模型性能感兴趣,你可以在这里查看笔记本。

我们还将绘制 ROC 曲线,并将其保存为图。这些视觉元素将作为报告的一部分添加进来。

现在我们已经完成了创建信用风险模型的基本步骤,让我们设计并构建 Datapane 报告,它将作为一个监控系统来跟踪数据和模型如何随时间变化。

使用 Datapane 设计和构建可视化模型监控系统

步骤 1 —设计数据面板报告

要构建一份全面且涵盖 MLOps 清单大部分方面的报告,重要的是首先设计报告,然后在此基础上构建。我们会把报告写得非常简单,只有 5 页纸-

来源:图片由作者创作

  • Summary page —该页面将提供每个迭代的变更的高级视图,例如报告更新日期、更新注释(供数据团队向报告添加关于变更的注释)、基本模型属性以及下载报告的链接。
  • 项目详情 —该页面将提供关于项目、相关数据集和数据属性的简要说明。当与可能不了解项目完整细节的风险承担者共享报告时,这很有帮助。
  • 数据概要 —该页面将提供数据概要元素,例如数据的不同特征、相关性、缺失变量,以及在需要时访问整个数据集的方法。
  • 探索 —该页面将展示分析的数据可视化元素。分析过程中创建的所有图和可视元素都可以在此处分组和显示。
  • 模型跟踪 —这将是最后一页,提供关于所用模型、其性能参数和评估矩阵的信息。

步骤 2——在 Datapane 中构建报告页面

为了构建数据面板报告,我们将遵循一个 3 步流程

  • 定义页面的单个元素。
  • 定义包含所有元素的页面。
  • 将页面添加到报表中。

如果您是 datapane 的新手,请查看这里的指南开始使用。

例如,为了构建摘要页面,首先,我们定义文本块、图像块和 BigNumbers 块。

我们还将从我们的配置文件报告中提取值,并为它创建另一个块。

步骤 3-创建数据面板报告

接下来,我们将所有这些块添加到页面中。

最后,我们将所有页面添加到报告中。

这种结构增加了整个过程的简单性和模块化!类似地,定义所有页面并将它们添加到报告中。

步骤 4——将报告发布到 Datapane

一旦创建了报告并且预览了它 , 将报告发布到数据面板。最后你应该会有这个这样的东西。

步骤 5 —将数据面板代码添加到笔记本中

成功发布报告后,添加代码文件作为笔记本/脚本文件的一部分。

来源:图片由作者创作

因此,无论笔记本或脚本何时运行,报告都会得到更新,并反映可以根据需要与利益相关者共享的更改。

将数据面板报告集成到您的 ML 管道中

一旦您对 Datapane 报告感到满意,您就可以将笔记本作为数据管道的一部分来运行。有几种方法可以做到这一点:

  • 每次想要更新模型时,请手动运行笔记本
  • 从您的主 Python 笔记本创建一个 Datapane 脚本
  • 根据新数据定期重新培训的模型的工作
  • 气流用于更复杂的 ML 管道

结论

机器学习允许我们创造全新的产品和能力,这是通过传统的软件开发不可能实现的。然而,这些模型仍然可能以独特和不可预测的方式失败。

有了监控系统,团队可以实时跟踪模型并评估它们的性能。它还可以帮助识别基础数据中不断变化的模式和新的流入,以便在必要时重新训练模型。

使用 Datapane 这样的开源工具,而不是复杂的 MLOps 平台,可以非常容易地构建这个监控系统。它不仅是可视化的,而且可以通过电子邮件/Slack 共享,这样所有的利益相关者都可以及时了解最新情况,从而做出业务决策。

使用 Docker (2021)构建可移植的数据科学环境

原文:https://towardsdatascience.com/building-a-portable-data-science-environment-using-docker-2021-6d533fe2b86a?source=collection_archive---------19-----------------------

一个 Docker 驱动的虚拟环境,供初学者随时随地使用

图 1 —对接过程(原始)

在过去的一年中,我不得不三次更换我的工作笔记本电脑,并且在错误的地方设置新的开发机器总是一件痛苦的事情。

我最终决定尝试一下 Docker,并发现它非常有用。

然而,学习 Docker 是一个挑战,因为不完整的资源分散在互联网上。我不想成为 Docker 大师,我只需要知道足够多的信息来避免依赖性问题,并根据我的需要构建+复制我的工作环境。

我使用 Docker 作为数据科学和分析工作的首选环境。我很少被要求制作我的作品,但是,如果你需要的话,Docker (+ Compose)是一个很好的方法。

目录(单击导航)

目标计划
1/ Docker 先决条件
2/项目需求
构建
3/编写 Dockerfile
4/从 Dockerfile 构建映像
5/从映像创建容器
6/在存储(卷)上
使用

> >目标

在本演练结束时,您应该拥有一个设备齐全的数据科学/分析环境,它:

  • 可移植的——通过简单的拉取请求(类似 Git)可在任何机器上访问
  • 隔离/受控 -安装的依赖关系被冻结,没有更新/升级问题
  • 可复制的 -通过简单的“docker 运行”创建一个副本(或更改它)命令
  • 类似协作的 Git(超出范围)

这样的环境适合于原型开发、EDA 和探索库等等。

注意:如果你不熟悉 Docker 的基础知识,可以参考我个人用过的资源:

> >计划

1/ Docker 先决条件

要构建 Docker 容器,您的机器上需要 Docker。

前往 Docker 网站下载 Docker。按照这里的步骤在 Mac、Linux 或 Windows 上设置它。这是一个简单的 GUI 步骤序列,应该不会给你带来任何问题。

DockerHub 上注册,就能把你的图片推送到你的存储库。这将允许您在任何机器上下载映像,并准备好您的便携环境。

新,登录您的 DockerHub 帐户:

  • 启动您的终端并输入以下命令。出现提示时,输入密码。
docker login -u [USERNAME] 
# Dockerhub username

  • 通过运行官方的 hello-world 示例来测试 Docker 设置。
% docker pull hello-world .       # pull the example image% docker images -a               # list all available images% docker run hello-world        # create a container from the image

如果能看到“Docker 的你好!”在您的终端上,您已经有了一个正确安装的 Docker。如果不能,再尝试安装 Docker。

2/项目要求

我们在建造什么?

  1. 一个 Python 环境
  2. 常用软件包 — Pandas、PySpark、TensorFlow、Plotly、Matplotlib、NumPy
  3. 冻结包—避免依赖性问题
  4. Jupyter 笔记本 —通过浏览器提供的首选 IDE
  5. 存储 —虚拟存储应该是持久的,并且必须与我的本地存储绑定(以便于轻松添加新文件和数据库)

码头工作流程

Docker 的工作原理,简而言之:

  1. docker file——你为你想要的那种环境(容器)创建蓝图。
  2. 图像——你从 Dockerfile 文件中构建一个图像。
  3. 容器 -你从图片中创建一个容器。你所有的工作都会在这里完成。您可以根据需要启动和停止这个“虚拟机”。
  4. 上传(和下载)到云——把它推送到 DockerHub,这样你就可以在任何地方下载和使用它。

集装箱化的过程

项目结构

  1. 我将创建一个名为“analytics_env”的任意文件/项目结构。
  2. 添加一个“数据”文件夹。您可以将数据添加到系统上的这个文件夹中,并在您的容器中访问它,反之亦然。
  3. 将创建一个没有扩展名的“Dockerfile”。我们将在这里书写我们的虚拟环境蓝图。
  4. 存储任何上下文信息的“readme.txt”。

注意:不要浪费时间在本地系统上寻找 Docker 映像和容器。Docker 的 UI 仪表板(在步骤 1 中安装)在访问和管理它方面更加方便。

项目文件夹结构

您可以手动创建它,或者使用您的终端/IDE 来创建它。

> >构建

3/编写 Dockerfile 文件

一旦创建了项目结构“analytics_env ”,就可以打开 IDE 并导航到它的目录。接下来,我们可以打开“Dockerfile”并定义虚拟环境的蓝图。

FROM python LABEL maintainer="jaethalal" 
LABEL version="1.0" 
LABEL description="docker image for data science development env" RUN pip install jupyter numpy pandas matplotlib plotly dash EXPOSE 8888  
CMD [ "jupyter", "notebook", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root" ]

让我们将 docker 文件分解成它的组件:

  1. FROM python- Dockerhub 有一个准备好的带有基本环境的映像的注册表(比如我们的例子中的‘OS+Python’)。映像是分层构建的,基础层是一个操作系统发行版。您可以使用这些图像,并通过添加更多组件来修改它们。在这一步中,我们采用了基本的 Python 图像。
  2. 标签维护者,版本,描述- 添加标签进行识别。这是一个可选但强烈推荐的步骤。
  3. 运行 pip inst…- 一旦基本 python 映像被检索到,您运行一个 pip 命令在它上面安装所有的包。这个 pip 命令被附加到运行指令上。“运行”在映像构建时执行。因此,每当从这个 Dockerfile 文件构建映像时,所有列出的包都将被安装到 Python env。
  4. EXPOSE 8888- 因为 Jupyter 笔记本是通过浏览器访问的,所以你需要从你的容器向外界,也就是主机,公开一个端口(比如 8888)。
  5. CMD[“jupyter”..- 如果在运行容器时没有指定命令,默认情况下会执行 CMD 命令。如果你这样做,CMD 将失去优先权。因此,CMD 是设置默认指令的好方法。
    在这里,我们在 localhost:8888 上默认启动和服务 Jupyter 笔记本,只要容器运行。

我们完了!继续保存 Dockerfile 文件。

蓝图已经准备好了,现在唯一剩下要做的就是“造”。

4/从 Dockerfile 文件构建映像

我们将使用以下命令从 Dockerfile 文件构建一个映像:

% docker build -t prototype_env_image . # 'prototype_envm_image' is the name I've given to the image.                       # You can give it any name                      
# Do not miss the period(.) at the end of the command, it specifies the directory where your dockerfile is located

当您运行该命令时,需要一分钟时间。python 映像将被下载,docker 文件中列出的包将被安装在它上面。

让我们看看该命令的各个组成部分:

docker- 所有 docker 命令前面都有关键字“docker”
build-表示您正在从 docker 文件
prototype _ env _ image-中构建一个图像;用户自定义
。- 表示您正在从当前目录中的 Dockerfile 文件构建一个映像

要查看所有已构建图像的列表,您可以:

docker images -a                  # list all available docker images

这是我手头所有 Docker 图片的列表。您可以在列表顶部找到我们的“analytics_env_image”。

现在让我们进入最后一步。我们将从刚刚构建的 Docker 映像“analytics_env_image”中旋转出一个容器。

5/从图像创建容器

我们将把我们的容器命名为“analytics_env_c1”。

要从图像创建容器,请使用:

docker run \
--name analytics_env_c1 \
-v /Users/apple/analytics_env:/analytics_env \
-w /analytics_env \
-p 8888:8888 \
analytics_env_image

这是一个单独的命令,为了清楚起见,使用了“\”操作符将其分成多行。

当您运行该命令时,您会看到类似这样的内容。底部的 URL 表示您的容器已经创建并且正在运行。您也可以在命令中用“create”替换“run ”,它只会创建一个容器,而不会运行它。然后您可以使用“docker start”在以后运行它。

有效,运行=创建+启动

您只需在默认浏览器中“按住 ctrl 键并单击”最后一个链接,就可以重定向到 Jupyter 笔记本,也可以复制并粘贴它。

但是首先,让我们一步一步地构建这个命令的最后一个庞然大物:

# create a container from the image "analytics_env_image" 
**docker run analytics_env_image** # use --name to give the container a name= "analytics_env_c1" 
**docker run \
--name analytics_env_c1 \
analytics_env_image** # use -v to bind your local directory "/Users/apple/analytics_env" with a directory inside the container "/analytics_env" 
**docker run \**
**--name analytics_env_c1 \
-v /Users/apple/analytics_env:/analytics_env \
analytics_env_image ** # use -w to set the "/analytics_env" inside the container as the working directory 
**docker run \
--name analytics_env_c1 \
-v /Users/apple/analytics_env:/analytics_env \
-w /analytics_env \
analytics_env_image ** # use -p to assign the local machine port 8888 (unassigned; user-defined) to the container port 8888 (assigned to Jupyter Notebook) **docker run \**
**--name analytics_env_c1 \
-v /Users/apple/analytics_env:/analytics_env \
-w /analytics_env \
-p 8888:8888 \
analytics_env_image**

注意:每当需要使用冒号(:)操作符时,请记住它会将' left:right 映射为' host_machine:docker'

6/侧栏:存储上

我们有两种存储选项—卷和绑定装载。卷由 Docker 隐式管理,与主机的物理存储无关。绑定装载使共享存储成为可能。它使 docker 使用指定的目录作为其主要存储。

正如我们在需求部分讨论的那样,我们的存储需要:

  1. 持久 —当容器关闭时,数据不会消失
  2. 绑定 —添加到主机存储的文件应该反映在容器内部,写入容器存储的数据应该可以被本地主机访问

绑定安装是提供给我们 2。这就是我们在“docker run …”命令中使用“-v”(—volume)标记来装载主机存储并将其与“analytics_env_c1”的存储绑定的原因。

> >使用

7/从容器运行 Jupyter 笔记本

当你点击链接或访问“localhost:8888”时,你会发现你的 Jupyter 笔记本正在运行。

然而,有一个复杂的问题。下次您尝试运行容器并访问此 Jupyter 笔记本时,您将无法登录,除非您使用以下任一方法为笔记本设置密码:

  1. Jupyter 配置文件
  2. 一次性密码设置

我们将采用第二种更简单的解决方案——“一次性密码设置”。遵循以下步骤:

  1. 在 Jupyter 笔记本的右上角,点击“注销”
  2. 在下一页,点击“登录页面”
  3. 这里,你会看到这一页

  • 回到您的终端/IDE,从 Jupyter 笔记本重定向链接复制令牌

  • 粘贴令牌并输入您喜欢的任何密码。我先说“赛克”。

  • 点击“登录并设置新密码”。您将登录。下次运行该容器并访问该笔记本时,屏幕顶部会要求您输入密码(检查步骤 3 中的图像)。
  • 继续创建一个随机数据帧,并将其作为 CSV 导出到“/data”文件夹中,以测试您的存储设置。

  • 即使您是在容器中完成的,您也可以在本地系统中看到它。

8/在 Docker 中移动

  • 停止运行容器:说你累了,今天的工作做完了。你想关掉这个容器然后去睡一觉。有两种方法可以做到:
  1. 只需回到终端/IDE,然后按“ctrl+c”。
  2. 您可以打开一个新的终端并键入
docker stop analytics_env_c1
  • (重新)启动一个容器:下次您决定参与这个项目时,打开您的终端并键入:
docker start analytics_env_c1 # or docker restart analytics_env_c1

# These commands will not spit out the link for jupyter nb like the last time 
# but you can still visit localhost:8888 and you'll find it running
  • 列出所有的容器和图片:你可能会忘记你工作过的容器的名字。因此,您可以使用以下命令列出所有容器:
# list all containers
docker ps -a# list active containers
docker ps# list all images
docker images -a
  • 删除容器和图像:您可能想要删除容器或图像。您可以使用:
# delete all dangling containers (dangling - containers without a base image)
docker container prune# delete all dangling images (dangling - no containers related to the image)
docker image prune# To avoid caching RUN command while installing packages in the Dockerfile
# Caches prevent docker from fetching updated packages
RUN pip install pandas, numpy --no-cache# To avoid loading previous cache while building images
docker build --no-cache -t helloapp:v2 .
  • 检查容器/图像:如果你觉得勇敢,你可以使用下面的命令来检查容器或图像。它将向您显示所有的配置细节和有问题的映像/容器的状态。
# inspect the image
% docker inspect analytics_env_image#Inspect the container
% docker inspect analytics_env_c1

9/将 Docker 映像推送到云存储库— DockerHub

像 GitHub 一样,你可以在 DockerHub 上保存你的 Docker 图片,并在你需要的时候调用它。我们把“analytics_env_image”推送到 DockerHub。

  • 登录 DockerHub
  • 创建一个存储库“portable_analytics_env”
  • 打开你的终端
  • 导航到项目根位置(docker 文件所在的位置)
  • 使用标记 username/repo_name 构建 Dockerfile 文件(再次是)
# build the image with the tag 'username/repo_name'
docker build -t jeathalal/portable_analytics_env .# push the image to dockerhub
docker push jeathalal/portable_analytics_env

10/在新系统上使用 Docker

比方说,你的 MacBook 在一个晴朗的日子停止工作,你不得不买一台新的。理想情况下,您希望能够访问您在早期机器上拥有的相同环境。你花了几周时间配置和设计它。

还好你推给了 DockerHub。我们将从我的存储库中提取之前推送的图像。

安装 Docker 并登录到您的 DockerHub 帐户,如上面的第 1 节所示。就像我们在 hello-world 示例中所做的那样,简单地提取先前上传的文件。

% docker pull jaethalal/ds_env

大概就是这样!如果你愿意,请在评论中留下任何问题或反馈!

构建 Python CLI 工具从 Markdown 文件中提取 TOC

原文:https://towardsdatascience.com/building-a-python-cli-tool-to-extract-the-toc-from-markdown-files-ab5a7b9d07f2?source=collection_archive---------12-----------------------

通过自动化枯燥的任务来学习—第 1 部分

为降价文件创建目录—由作者创建的图像。

不久前,我在 markdown 上为我公司的 DevGuide 写了很多文章——我们用 Hugo 来构建它作为一个内部网站——并对创建和修改目录(TOC)这一非常重复、非常无聊的任务感到恼火。每当我更改标题、引入新的子章节或删除其他章节时,我都必须一次又一次地手动编辑目录。在回顾和编辑了几篇文章之后,我终于厌倦了寻找工具和“易于使用”但可配置的选项。我对它的缺乏感到惊讶。

所以我决定编写自己的最小 CLI 工具,从 markdown 文件中自动提取目录(TOC)。在本文中,我将介绍实现所需的需求、设计决策和核心功能。当然,这个项目是开源的,任何人都可以扩展它。

需求和初步想法

由于 TOC 通常被放在减价文件的不同位置,所以默认情况下没有必要将其插入文件的第一行。例如杰基尔雨果都要求降价文件的前几行包含他们各自的封面。

一般来说,编辑文件本身并不是一个好主意。事情偶尔会出错。理想情况下,我们希望最终决定权(插入 TOC)掌握在自己手中。只有当我们能够准确地定义决策参数和最佳结果时,我们才能够自动化决策——在这种情况下,这将是章节标题的语法内容和“感觉”。难以自动化。

总之,这意味着 TOC 应该

  • 返回到控制台检查结果并启用复制粘贴(这需要是默认设置),
  • 可选地放置在剪贴板中,
  • 可选地被复制到文件的第一行,
  • 可选地放置在单独的文件中。

此外,我们应该允许用户通过对包含的标题级别设置自定义限制来限制 TOC 的深度。有些人喜欢三个标题层次的目录,有些人只喜欢看主要的。

格式注意事项

关于 TOC 本身列举的实际格式,章节的可点击链接应该是首选。也许这只是我的懒惰,但是如果 TOC 不能被点击,我不能跳转到我感兴趣的章节,那么创建一个表格 OC 内容又有什么意义呢?这意味着我们需要以下输出格式之一:

第一个选项更常用:

GitLab 风格的目录链接降价。

或者 HTML 锚的第二个选项:

目录链接的 HTML 锚。

第二种选择需要在现有的降价文件中插入和格式化锚点,并在降价文件中引入 HTML。这两件事都很难论证——我也不是特别喜欢。

它们也与上面的需求相冲突,因为我们不需要将 TOC 直接插入到文件中,尤其是不需要到处都有多个分离的锚线。请记住,我们的目标是一个小而易用的解决方案,这个决定显然有利于第一种格式。

核心功能

在明确了最初的设计决策和我们自己设定的需求之后,让我们来看看需要的功能。一般来说,我们有以下步骤:

  1. 读取文件
  2. 清理文件
  3. 识别标题
  4. 格式化标题
  5. 创建目录
  6. 输出目录

我们开始吧。

读取文件

我们在这里不需要做什么特别的事情,我们只需要读取文件并根据换行符将它分成单独的行。

正在读取文件。

旁注:与使用readlines()相比,我更喜欢上面的语法,因为readlines()返回的行带有一个结束换行符,稍后必须对其进行清理。我们也可以一次将整个文件加载到内存中,因为降价文件很少有千兆字节的数据。

清理文件

在提取文件头之前,我们需要从文件内容中删除所有代码块及其内容。Python(以及其他编程语言)可以将有效的 hashtags 作为一行中的前导字符(例如,作为注释),这将与我们的头检测相冲突。由于这是一个简单的转换步骤,我们可以为它编写一个快速函数。

该函数接收一个行列表,过滤掉所有代码块并返回过滤后的列表。

识别标题行

在 markdown 中有两种创建标题的方法

  • 在标题标题前面的同一行中使用一定数量的标签(# ) 的常见选项
  • 或者,在下面的下一行中,为 1 级标题添加任意数量的等号(=)或连字符(-)作为 2 级标题。

第二种选择的明显缺点(除了难看之外)是语法将我们限制在两个级别的头。到目前为止,我也很幸运地在我参与的项目中没有看到第二种形式。然而,为了确保完整的功能,让我们包括两种格式的识别方法。

检测标题行的常见类型的逻辑非常简单:我们可以使用 regex 模式将一行标识为标题行:r"^#+\ .*$"(前导标签,后跟空格,然后是任何可能的字符)。

对于其他类型的标题,我们只需检查该行是否以等号(regex: r"^=+ *$")或连字符(regex: r"^-+ *$")开头,并且直到行尾除了空格之外没有任何其他字符。如果是这样,我们添加前面的行作为标题。为了下一步省事,我们还会统一头格式。

识别标题行并过滤掉其他行。

示例转换:

过滤非标题行的转换示例。

格式化标题

识别标题后,我们需要确定它们的级别,并为目录本身创建格式化的行。

GitLab 文档中,我们可以了解如何格式化 TOC 中常用的 markdown 链接:

  1. 所有文本都转换成小写。
  2. 所有非单词文本(如标点符号或 HTML)都将被删除。
  3. 所有空格都转换为连字符。
  4. 一行中的两个或更多连字符被转换为一个。
  5. 如果已经生成了具有相同 ID 的报头,则附加一个唯一的递增数字,从 1 开始。

下面的函数将涵盖这些规则中的大部分——无可否认,在一些边缘情况下,链接会失败,但对于 95%的情况,我们是好的。完美是令人钦佩的,但寻找边缘案例和实现解决方案所需的时间在目前是不值得的。当我们(或其他潜在的未来用户)确实遇到需要考虑的边缘情况时,我们总是可以轻松地扩展我的代码。

格式化标题和创建可点击的链接。

示例转换:

示例转换。

创建目录

对于目录本身,我们必须对标题和子标题进行格式化和编号。如果下一个标题的级别高于前一个,我们还需要重置编号。

将 TOC 中的每一行组装成一个字符串包括(按顺序):

  • 副标题可能的缩进,
  • 标题编号,
  • 标题文本和
  • 标题的链接。

我们还可以引入一个名为level_limit的变量来限制 TOC 的深度。

创建内容行的实际表格。

示例转换:

从准备好的数据创建 TOC 行的示例。

结合目前为止的工作

我们现在已经实现了核心功能,很快就可以开始研究将它转换成 CLI 包的必要条件以及如何输出结果。

核心功能。

输出目录

根据所需的结果,我们将 TOC 复制到剪贴板,将其插入 md 文件或写入一个新文件。这主要是标准实践的东西,也许除了为我们的新 TOC 文件找到一个合适的文件名。

将目录写入不同的通道。

创建 CLI 功能

为了能够从命令行调用带有可配置参数的包,我们使用了 argparse 模块。

记住我们的要求,我们希望用户:

  • 指定文件名(必需的参数)
  • 能够将目录复制到剪贴板(可选参数--copy)
  • 能够将目录插入文件(可选参数--insert)
  • 能够将目录保存到一个单独的文件中(可选参数--save)
  • 能够限制 TOC 的深度(可选参数--levels <number-of-levels>)

在创建了带有名称和描述的ArgumentParser之后,我们必须单独添加每个参数:

为 CLI 创建参数。

查看存储库文件中的全部参数

之后,访问参数/变量就像下面这样简单:

最棒的是,我们自动包含了--help参数背后的功能。这里的输出是:

打包、发布和访问

因为我们也希望能够在我们曾经接触过的任何其他计算机上安装它(并且也让其他用户可以使用它),我们可以创建一个简单的setup.py文件,打包代码并将其发布在 pypi 上。打包 CLI 工具与任何其他 python 打包过程并无不同。

如果你对setup.py和如何打包代码感兴趣,看看吧

快速旁注:为了测试你的打包软件,而不必把它上传到 pypi,然后通过 pip 安装,你可以简单地使用pip install .直接从你的setup.py文件所在的本地目录安装它(是的,这是一个点——表示当前目录)。

完成这一步后,世界各地的每个人都可以使用pip install extracttoc安装 CLI 工具了!

用途

下面是该工具如何从命令行工作的几个具体使用示例:

关闭思想

一般来说,编写软件使自己的生活变得更容易是很好的编码实践。然而,创建开源包(帮助其他人解决同样的问题)会迫使你写出高质量的好代码,这些代码可以被其他人理解并在 T21 的基础上扩展。在你认为没有人会阅读的代码中,你可能没有考虑高优先级的事情(比如不仅仅命名你的迭代变量x...)在考虑其他人将如何与代码交互时,突然变得更加重要。编写开源代码无疑会受到其他人的批评,这让我们关注风格和开发最佳实践——这让我们成为更好的程序员。

如果你觉得有空的话——试试,或者看看 github 上的源代码,如果你想看完整的话!

创建一个 CLI 工具对我来说是新的,但在我的工具箱里是一个非常方便的技能。我确信我将来会再次使用它。

一如既往,我们永远学不完。了解有关…的更多信息

Medium 上关注我,获取更多关于数据工程工具以及软件和个人发展的文章!

构建 Python 代码生成器

原文:https://towardsdatascience.com/building-a-python-code-generator-4b476eec5804?source=collection_archive---------10-----------------------

使用转换器将英语问题语句转换成 Python 代码

NLP 技术可以用来生成实际的代码吗?我们离一个用 AI 写软件的世界还有多远?

在这篇博客中,我尝试构建一个 python 代码生成器,它可以将简单的英语问题语句转换成相应的 python 代码。

图 1:生成 python 代码的转换器。😉(原始图像来自 unsplash

我们通过把它作为一个序列到序列(Seq2Seq) 的学习问题来处理这个问题。在这里,我们的英语句子将是我们的输入或 SRC 序列,我们的 Python 代码将是我们的输出或 TRG 序列。

在过去的几年里,变压器已经成为解决 Seq2Seq 问题的主导架构。大多数当今的 SoA 模型,如 BERT 或 GPT-3,都在内部使用转换器。我们今天所知的变形金刚是由谷歌在他们的 “注意力是你所需要的一切” 论文中首次介绍的。我们在博客中讨论的“英语到 Python”模型也在本文中找到了它的动机。

在我们开始解决问题之前,让我们先简要回顾一下变压器。

变形金刚

图 2:变形金刚(图片来自 d2l.ai )

变压器可以从三个方面来理解:

  1. 将输入序列编码成状态表示向量的编码器。
  2. 一种关注机制,使我们的 Transformer 模型能够关注顺序输入流的正确方面。这在编码器和解码器中重复使用,以帮助它们将输入数据置于上下文中。
  3. 解码器,对状态表示向量进行解码,以生成目标输出序列。

在我之前的 博客 中,我已经详细解释了这些组件中的每一个,并附有代码演练。

现在让我们看看如何将数据输入到转换器中。

了解培训数据

我们将使用定制的 数据集AI(TSAI)学院策划来训练我们的模型。这个数据集包含大约 5000 个数据点,其中每个数据点包含一个英文问题语句及其对应的 Python 代码。可以关注我的 项目回购 了解如何解析数据。

样本数据点:

英文语句:“写一个将两个数相加的函数**

Python 代码:

def add_two_numbers (num1 ,num2 ):
    sum =num1 +num2 
    return sum

这里的"英文语句"是我们的输入或 SRC 序列,而" Python 代码"是我们的输出或用于训练的 TRG 序列。

将数据符号化

我们的输入(SRC)和输出(TRG)序列以单个字符串的形式存在,需要进一步标记才能发送到 transformer 模型中。

为了标记输入(SRC)序列,我们使用了空间 。这在 PyTorch 的torch text . data . field中默认实现。我们将使用 torchtext.data.Field 通过 spacy 来标记我们的数据。

Input = data.Field(tokenize = 'spacy',
            init_token='<sos>', 
            eos_token='<eos>', 
            lower=**True**)

为了对我们的输出(TRG)序列进行标记化,我们使用了基于 Python 源代码标记化器构建的自定义标记化器。Python 的 tokenizer 为每个标记返回几个属性。我们只提取元组形式的令牌类型和相应的字符串属性(即(token_type_int,token_string))作为最终令牌。

标记化输入(SRC):

SRC = [' ', 'write', 'a', 'python', 'function', 'to', 'add', 'two', 'user', 'provided', 'numbers', 'and', 'return', 'the', 'sum']

符号化输出(TRG):

TRG = [(57, 'utf-8'), (1, 'def'), (1, 'add_two_numbers'), (53, '('), (1, 'num1'), (53, ','), (1, 'num2'), (53, ')'), (53, ':'), (4, '\n'), (5, '    '), (1, 'sum'), (53, '='), (1, 'num1'), (53, '+'), (1, 'num2'), (4, '\n'), (1, 'return'), (1, 'sum'), (4, ''), (6, ''), (0, '')]

数据扩充

由于我们的数据集仅包含 5000 个数据点,我们利用数据扩充来增加数据集的大小。在标记 python 代码时,我们随机屏蔽某些变量的名称(用‘var _ 1’、‘var _ 2’等),以确保我们训练的模型不仅仅关注变量的命名方式,而且实际上试图理解 python 代码的内在逻辑和语法。

例如,考虑下面的程序。

def add_two_numbers (num1 ,num2 ):
    sum =num1 +num2 
    return sum

我们可以替换上面的一些变量来创建新的数据点。以下是有效的扩充。

1.

def add_two_numbers (var_1 ,num2 ):
    sum =var_1 +num2 
    return sum

2.

def add_two_numbers (num1 ,var_1 ):
   sum =num1 +var_1 
   return sum 

3.

def add_two_numbers (var_1 ,var_2 ):
    sum = var_1 + var_2 
    return sum

在上面的例子中,我们使用随机变量替换技术将一个数据点扩展为另外 3 个数据点。

我们在生成 TRG 令牌时实现我们的扩充。

当随机选择变量来屏蔽时,我们避免关键字文字( keyword.kwlist )、控制结构(如下面的 skip_list 所示)和对象属性。我们将所有需要跳过的文字添加到 skip_list 中。

我们现在使用 Pytorch 的 torchtext.data.Field 来应用我们的扩充和标记化。

Output = data.Field(tokenize = augment_tokenize_python_code,
                    init_token='<sos>', 
                    eos_token='<eos>', 
                    lower=**False**)

我们的测试应用标记化后的标记化输出(TRG) :

TRG = [(57, 'utf-8'), (1, 'def'), (1, 'add_two_numbers'), (53, '('), (1, 'num1'), (53, ','), (1, 'var_1'), (53, ')'), (53, ':'), (4, '\n'), (5, '    '), (1, 'sum'), (53, '='), (1, 'num1'), (53, '+'), (1, 'var_1'), (4, '\n'), (1, 'return'), (1, 'sum'), (4, ''), (6, ''), (0, '')]

喂养数据

为了将数据输入到我们的模型中,我们首先使用 Pytorch 的torch text . data . bucket iterator创建批处理。这确保了具有相似长度的输入一起留在单个批次中,以便于训练。然后,我们将标记化输入(SRC)批次送入编码器,并在解码器中使用标记化输出(TRG)批次。我们的目标是使用编码器的标记化英语输入(SRC)来预测通过解码器的标记化 Python 输出(TRG)。然后,标记化的预测通过 Python 源代码标记化器的取消标记化函数取消标记化。

图 3:编码器的输入和解码器的输出。(图片来自谷歌 arxiv 研究)

损失函数

我们在数据集中使用了扩充来屏蔽变量文字。这意味着我们的模型可以预测特定变量的各种值,只要预测在代码中保持一致,所有这些值都是正确的。这将意味着我们的训练标签不是非常确定,因此以概率 1- smooth_eps 将它们视为正确,否则视为不正确将更有意义。这就是标签平滑的作用。通过添加标签平滑交叉熵中,我们确保了模型在预测一些可以通过增强来替代的变量时不会变得过于自信。

图 4:标签平滑(来源:深度学习,Goodfellow 等人 2016)

现在我们所有的组件都设置好了,我们可以使用反向传播来训练我们的模型。我们将数据集分为训练数据和验证数据。我们的模型被训练,直到我们的验证损失不再进一步改善。

值得注意的是,与不使用标签平滑的模型相比,标签平滑会导致更高的损失值。但这是意料之中的,因为我们不打算确定我们的标签预测。对于变量尤其如此,因为只要预测在整个目标代码序列中是一致的,就可以有多个正确的选项。

完整的训练代码请参考我的笔记本

样本结果

输入:“程序按关键字排序字典列表”
输出:

var_1 ={'Nikhil':{'roll':24 ,'marks':17 },
'Akshat':{'roll':54 ,'marks':12 },
'Akash':{'roll':15 },'marks':15 }}
sort_key ='marks'
res ='marks'
res =var_2 (test_dict .items (),key =lambda x :x [1 ][sort_key ])
print ("The sorted dictionary by marks is : "+str (res ))

输入:“列表奇数元素求和函数”
输出:

def sum_odd_elements (l :list ):
    return sum ([i for i in l if i %2 ==1 ])

输入:程序反转一串 输出:

var_1 ='Today is bad day'
var_1 [::-1 ]

更多样本请看我的项目回购

我们已经成功训练了一个模型,它能够将简单的问题陈述(英语)转换成相应的 python 代码。看起来我们离人工智能代替人类编写软件的时代不远了。软件开发人员当心!

参考知识库

**https://github.com/divyam96/English-to-Python-Converter https://github.com/bentrevett/pytorch-seq2seq

参考

[1]阿斯顿·张(Aston Zhang)和扎卡里·c·利普顿(Zachary C. Lipton)以及李牧和亚历山大·j·斯莫拉(Alexander J. Smola),潜入深度学习 (2020)。

[2] Ashish Vaswani,Noam Shazeer,Niki Parmar,Jakob Uszkoreit,Llion Jones,Aidan N. Gomez,Lukasz Kaiser,Illia Polosukhin,(2017),第 31 届神经信息处理系统会议(NIPS 2017),美国加利福尼亚州长滩

[3] Rafael Müller,Simon Kornblith,Geoffrey Hinton,标签平滑在什么情况下有帮助? (2019),第 33 届神经信息处理系统会议(NeurIPS 2019),加拿大温哥华

[4]伊恩·古德费勒(Ian Goodfellow)与约舒阿·本吉奥(Yoshua Bengio)和亚伦·库维尔(Aaron Smith),深度学习书籍 (2016),麻省理工学院出版社。**

在 AWS 中构建真实的数据湖

原文:https://towardsdatascience.com/building-a-real-life-data-lake-in-aws-ee3bc9b8bba1?source=collection_archive---------5-----------------------

AWS 特性如何影响为 AI 构建的 ACID 数据湖解决方案的架构

有一些重要的用例、需求和架构选择会改变数据湖的构建方式。在这里,我们将关注直接来自数据湖的数据消费的好处,同时解决接近实时的人工智能推理需求。

我们将简洁地介绍一些架构选择及其含义,同时查看使用 Spark over S3 的数据工程。

目标受众

读者应该对 Apache Spark 和 AWS 有所了解。

AI 推理延迟需求

我们将专注于推理时间延迟需求以分钟/秒为单位的用例。
在这种情况下,您可以选择基于 Apache Spark 的架构作为您的流&批处理 AI 处理的公共基础。您还可以在流式处理和批处理之间共享代码,同时提高下游读取性能。
如果这不是您的用例,您仍然可以为您的解决方案的数据湖部分实现以下大部分内容。

体系结构

作者图片

请注意,您不必准备好所有选项。例如,一个人可以选择完全放弃 Kinesis/Kafka,而仅仅依靠消防软管。
由于我们关注的是基于人工智能的用例,业务级聚合数据湖层超出了本次讨论的范围。此外,我们将关注可以结构化的数据。

视觉议程

作者图片

基础

你真的有大数据,需要数据湖吗?

这篇文章讨论大数据。在去之前,请确定你是否拥有/期望拥有大数据。如果没有,就不要去那里。

300GBs 不是“大数据”。

通用数据湖结构

数据应该被划分成适当数量的分区。数据保存在大文件中,通常约为 128MB-1GB。维护大数据的二级索引通常成本过高。

此外,通用解决方案集成了 Hive Metastore(即 AWS Glue Catalog)用于 EDA/BI 目的。数据通常来自 Kinesis/Kafka 等流媒体源或 S3 着陆区,后者本身通常是 Kinesis Firehose 的目标。

如何跟踪已经处理过的输入数据

Spark 结构化流已经包含.option("checkpointLocation", checkpoint_path)。它跟踪所有的偏移,不管你的输入:卡夫卡/MSK,S3 着陆区,Kinesis 等。

这是基本选项,请阅读下面更高级的选项。

为什么我应该使用分区?

在大多数情况下,数据湖消费者,ala you AI 应用程序,将只需要读取数据的子集。当数据被分区时,Spark 等查询工具可以利用分区消除,因此只需要扫描一部分数据。

注意,这对于低基数分区键 ala 数据到达月份很有效。对于其他用例,人们不得不求助于对原始分区键的某种散列/装箱试探法,或者利用诸如 Z 排序之类的解决方案。

如何定义分区中文件的数量

当数据湖消费者读取数据时,将扫描分区中的所有文件,至少是读取元数据。分区中的文件数量应该是扫描分区的活动 Spark 任务数量的几倍。
也就是说,如果你的分区有 30 个文件,但你的执行程序数乘以每个执行程序的内核数是 130,一般情况下每个执行程序有 100 个内核不做任何事情,你要为此付出代价,包括现金和查询性能。

其他调配的服务也是如此,如雪花集群大小或红移插槽。

如何定义数据格式

因为所有文件至少都要扫描元数据,所以最好使用支持压缩拼花和一些非分栏格式的 S3 选择。因此,您希望您的数据湖有压缩拼花文件,这是由 S3 支持的。

在本文的后面,我们将介绍推荐的使用 Parquet 的数据湖框架。

近实时人工智能推理的含义

微批处理中的数据摄取

如果需要接近实时的人工智能推理,那么为您的用例使用正确的火花.trigger()将数据流入数据湖是很重要的。

这个简单的要求可能会产生如下所述的重大后果。

微批量摄取影响—数据压缩

微批处理中的数据摄取可能会产生许多更小的文件。
为了提供每个分区可预测的查询时间,我们应该:

  • 创建具有相似数据大小的分区
  • 确保将小文件中的数据移动到更大的大约 128MB 的文件中。这个过程称为压缩。

压缩过程提高了下游读取吞吐量,尤其是在对象存储(即 S3)方面。

请注意,一些数据湖根本不实现压缩,因为这会增加复杂性,并可能给系统带来额外的延迟。在这种情况下,必须格外小心它们的文件大小和 ETL 流。

作者图片

数据压缩实现策略

  • 依赖商业实现,如数据块
  • 对记录大小可预测的文件使用.option("maxRecordsPerFile", ...)。请注意,对于嵌套数据,只考虑顶层行。
  • 使用aws s3 ls AWS API 对应物评估总分区大小。repartition*() / partitionBy()用所需的文件号为 Spark &配置单元分区设置正确的数量。
  • 仅对文件最近发生更改的分区执行上述操作。每次压缩所有分区会耗费太多的时间和开销—请参见下面的详细信息。

清单文件

当数据被压缩时,新的 Parquet 文件出现在分区中。消费 Spark/红移/雪花查询应该读取哪些文件?我们绝对需要添加一个元数据。有两种方法可以解决这个问题:

  • 保存一个分区清单文件,其中的内容列出了每个分区中的最新文件
  • 使用自动更新这些内容框架。稍后将详细介绍。

否则,我们的工作将是读取陈旧数据或陈旧和最新的数据在一起!

作者图片

酸性框架

ACID 框架支持以下功能:

  • 自动数据压缩(仅在商业版本中有一些)
  • 通过附加元数据缩短查询时间。
  • 分区清单文件的自动生成
  • 对数据湖消费者的 ACID 保证(有些限制适用,见下文)

选项包括:

  • 三角洲湖
  • 商业数据块版本—具有开源版本中没有的缓存和 Z 顺序性能改进
  • 阿帕奇胡迪——两种操作模式
  • Apache Iceberg —大约在 2020 年底,Iceberg 不支持来自精选数据的流。

请注意,一些功能,如 Delta Catalog,需要 Spark 3.0.0+,因此只能在 EMR 中使用,而不能在 Glue 中使用。在撰写本文时,AWS Glue 不支持 spark 3.0.0+。

S3 对火花驱动器数量的限制

由于 S3 不支持原子重命名这一事实,对于

这也意味着在 Spark 之外使用这些框架对于只读访问来说是非常可靠的。

单火花驱动器的含义

S3 限制火花驱动器数量的必然结果:来自几个不同来源的消耗,例如平行的 Kinesis & S3 着陆区必须发生在一个火花驱动器上!即使你没有连接这些火花流之间的数据,也是如此。毕竟,他们正在更新 S3 上相同的元数据位置。

实现这一点的方法可以是:

  • 在单个会话中使用 Apache Livy(我自己没有试过)或者
  • 使用.trigger(once=True)运行 EMR 流步骤
  • .union()不同的火花流,一次写入

数据压缩影响—文件清空

压缩过程和通常的任何数据更新都会创建过时的文件。为了不占用空间/使 S3 列表开销过大,必须将它们移除。除非您使用的是 Databricks commercial Delta lake,否则需要计划和调用此过程。

S3 灾难恢复

最好保留生成的 S3 存储桶的版本,因为它将允许出于灾难恢复目的的跨区域存储桶复制。

S3 清理

必须设置旧版本文件的 S3 生命周期规则来清理对象存储。真空是不够的,它只会导致 S3 删除标记。

(计划或理论的)纲要

模式合并

数据模式在现实生活模式中发展。为了支持向模式中引入新列,在 spark 中使用.option("mergeSchema","true")

活动采购

假设您的数据可以追溯更新。什么是正确的解决方案?

  • 就地更新数据。保存相同数据的单个副本。
  • 引入数据的另一个版本。

大多数基于人工智能的应用程序发布被执行的推理。购买股票,向客户发送电子邮件等。这是一个与业务相关的标准,指导利用事件源,以便人工智能推理可以追溯到推理时可用的数据谱系。

JDBC —对嵌套数据模式设计的影响

有时,我们希望在我们的细粒度数据上启用 BI,也就是说,不是在业务级聚合上。

有时真实世界的数据是嵌套的。请注意,许多 JDBC 工具(如红移光谱)不允许以直接的方式返回嵌套数据。在这种情况下,在将数据保存到数据湖之前使用.explode()会更有效。根据您的数据,这可能是唯一的选择。

S3 访问—附加选项

快速新文件列表—S3—SQS

即使当使用更大的文件时,spark 结构化流也必须列出所有文件,这在大数据湖中可能是很多的。Spark 的 S3-SQS 连接器可以通过保持一个队列监听来自 S3 的新对象通知来改善这一点。

S3 从 VPC 内部访问

为了通过 AWS 网络而不是互联网访问数据湖,使用 S3 VPC 端点。这主要是作为一个安全特征的好处。有时,VPC 端点可以提高性能,但这必须根据地区/使用案例进行测试。

初始 ETL 的着陆区考虑因素

如果您使用的 S3 登陆区有数百万个小文件,则需要将它们导入到策划数据湖中,以便所有历史数据都适合查询。S3 文件列表有很大的开销。列出一百万个文件需要 5 分钟以上的时间。此外,这不应该用 Spark 结构化流来完成,因为驱动程序内存会变得 OOM。Spark 结构化流并不意味着要列出数百万个文件。对于这个用例,最好将文件列在一个本地文件中,然后用 Spark 批处理来分配导入工作,这样每个任务都可以获得它将读取和转换的文件名的一个子集。

摘要

我们已经在接近实时的人工智能推理场景中介绍了数据湖的基础知识。介绍了高级 ACID 框架,以及它们对 S3 的限制。还提出了基本的模式考虑,以及 S3 列出的加速选项。

我希望这可以作为 AWS 中大多数数据湖解决方案的蓝图。

感谢您坚持到本文结束——请告诉我您的想法!也可以通过 LinkedIn 联系我。

构建具有 NLP 功能的实时聊天应用程序

原文:https://towardsdatascience.com/building-a-real-time-chat-application-with-nlp-super-powers-ce800e19cb2b?source=collection_archive---------25-----------------------

一款使用 TensorFlow JS 深度学习 API,IBM Cloud,Node 的带有情绪分析和语气检测的聊天 App。JS、Web Sockets 和 React

沃洛季米尔·赫里先科在 Unsplash 上的照片

在一个人工智能(AI)和机器学习(ML)模型被用来获取实时信息以不断改善客户体验的世界中,我希望发现 ML 在试图理解人类对话时可以证明有多有效,甚至尝试构建我们自己的定制应用程序来实现这项技术。

实践中的对话式机器学习

世界正在迅速适应使用人工智能驱动的应用程序来协助人类的日常工作。Siri 和 Alexa 由基于自然语言处理(NLP)的 ML 模型驱动,这些模型不断训练和迭代,听起来更自然,并通过理解复杂的人类对话提供更多价值。更不用说,谷歌最新的对话技术, LaMDA 。LaMDA 被训练成能够打断更大块的人类对话,并理解多个单词或短语如何相互关联,以获得更多关于输入文本的上下文,特别是针对人类对话。然后,它能够动态地生成一个自然的、类似人类的响应。以下来自谷歌的 AI 博文, LaMDA:我们突破性的对话技术 ,其中简要描述了 LaMDA 所基于的深度学习技术:

[1] LaMDA 的谈话技巧是多年来练就的。像最近的许多语言模型一样,包括 BERT 和 GPT-3,它建立在 Transformer 之上,这是谷歌研究院在 2017 年发明并开源的神经网络架构

这项技术令人印象深刻,并迅速证明了它在我们日常生活中的价值,从为我们预订房间到消除对人力呼叫中心的需求。

机器学习的挑战

然而,并不是所有的彩虹和阳光,在训练和集成 ML 模型到生产应用的过程中,会有许多挑战。我们如何测试这些模型?我们如何开发可靠的模型?我们如何确保 ML 模型中的偏差得到最佳缓解?我们可以多容易地构建使用这些模型的可扩展应用程序?这些都是大规模开发 ML 解决方案时需要考虑的问题。

让我们建立自己的应用程序!

在本文中,我们将构建一个定制的全栈应用程序,该应用程序利用 Google 的 TensorFlowIBM 的云机器学习即服务(MLaaS)平台来发现工程师如何使用基于云的工具开发可维护、可靠和可扩展的全栈 ML 解决方案。

我们将构建的应用程序是一个实时聊天应用程序,能够检测用户消息的语气。正如你所想象的,这方面的用例可以跨越很大的范围,从理解客户与客户服务聊天的交互到理解一个生产人工智能聊天机器人的表现如何。

体系结构

在高层次上,这是应用程序的架构。

高级应用程序架构包括利用 React 和 TypeScript 来构建我们的自定义用户界面。使用节点。JS 和套接字。IO 库,支持最终用户和应用服务器之间的实时双向网络通信。自插座。IO 允许我们进行基于事件的通信,我们可以根据终端用户主机发送的消息异步地对 ML 服务进行网络调用。

后端

至于 ML 服务,我们可以向 IBM 基于云的音调检测模型发出 HTTP 请求(包含在有效负载中发送的聊天消息的内容)。来自 IBM web 服务的响应将是一个 JSON 对象,其中包含模型对该消息进行分类的一组音调,例如

[“Joy”, “Positive”, “Happy”]

异步地,我们的节点。JS web 服务可以向 TensorFlow 的情感 API 发出请求。TensorFlow 的 ML 模型是一种基于卷积神经网络的深度学习架构,它已经在由 IBMD 电影评论组成的 50,000 个带标签的数据点上进行训练,能够预测新引入的输入文本的情感。我们将通过 TensorFlow 的预训练模型发送每条新聊天消息,以获得整个聊天对话的平均情绪得分。

基于事件的功能,根据新的聊天消息运行 ML 服务。

在上面的要点中,您可以看到,在客户端发送新消息时,服务器将调用两个函数,getTone 和 updateSentiment,同时将聊天消息的文本值传递给这些函数。

为对 IBM Cloud Tone Analyzer API 进行 API 调用而创建的 getTone 函数。

创建的更新情感函数使用输入的聊天消息文本运行 TensorFlow ML 模型,以计算平均情感。

使用 TensorFlow JS 框架的预测函数。

上面的预测函数在 update perspective 中调用。该函数通过使用网络获取来加载 TensorFlow 预训练模型,预处理输入的数据,并使用该模型来评估情感得分。这一切都在后台进行,与处理其他后端任务并行。

前端

使用 Socket IO 客户端库与服务器代码进行双向连接的用户界面。

在上面的代码中,我们构建了一个功能性的 React 组件来处理客户端与聊天应用程序的交互。因为我们使用的是功能组件,所以我们可以访问 React 钩子,比如 useState 和 useEffect。消息状态保存当前用户输入文本的值。消息状态保存所有已发送消息的数组。您可以在 useEffect 中看到到 Socket 服务器的连接,每次重新呈现/加载组件时都会调用它。当从服务器发出新消息时,会触发事件,以便 UI 接收新消息并将其呈现给所有在线用户实例。

用户界面的 sendMessage 函数,用于构建要发送给套接字服务器的 messageObject。

从 sendMessage 函数发出的 messageObject 将到达服务器,服务器将解析出 messageObject.body(用户发送的聊天消息的实际值),并通过之前构建的 ML web 服务处理数据。然后,它将构建并返回一个新的对象,该对象包含从 ML 模型的输出中获取的消息、用户名和消息的语气。

客户端 JSX 代码呈现消息并解析出消息发送者的用户名、消息的语气,当然还有消息体。

而最后的结果……TADA!

我们在本文中构建的应用程序的演示。每个聊天气泡包含给定消息的语气标签。(来源:作者)

完整源代码

要查看完整代码,请访问 Github 资源库:

https://github.com/devalparikh/NLP_Chat_App

结论

通过构建这个概念验证项目,我希望展示开发一个定制应用程序是多么无缝,它可以通过利用基于云的 Web 服务来集成机器学习工具和技术,从而实现可伸缩性和可维护性。通过使用 IBM 的云服务和谷歌的 TensorFlow 预训练情绪模型,我们能够建立一个聊天应用程序,可以对每条聊天消息的语气以及对话的整体情绪进行分类。

参考文献

[1] E. Collins,Z. Ghahramani, LaMDA:我们突破性的对话技术 (2021),https://blog.google/technology/ai

构建实时语音到文本反应应用程序

原文:https://towardsdatascience.com/building-a-real-time-speech-to-text-react-application-using-aws-amplify-8befac6aca2c?source=collection_archive---------17-----------------------

使用 AWS Amplify 为 ML/AI 应用供电的演示

图片来自 Unsplash

亚马逊网络服务(AWS)正在不断扩展其在应用开发、机器学习/人工智能和物联网等各个领域的产品。它的一些服务甚至在更高的层次上融合了不同的领域。 AWS Amplify 是一项服务,它提供了使用流行框架(如 React)构建移动/网络应用的能力。最近,Amplify 集成了各种高级 ML 服务,如转录、翻译、理解和重新识别,使开发人员能够轻松地用人工智能驱动他们的应用程序。对于本文,我们将构建一个 React 应用程序,展示 Amplify 通过与 AWS Transcribe 集成提供的语音转文本功能。

注意:对于刚接触 AWS 的人来说,如果你想继续学习,请确保在下面的 链接 中注册账户。然而,要完全理解这篇文章,你需要一些初步的 AWS 知识。我还将提供一个我们将使用的服务列表,以及更深入的定义。如果您已经熟悉了这些服务,可以直接跳到代码演示。

目录

  1. AWS 服务
  2. 设置 AWS 放大器
  3. 安装人工智能服务/预测资源
  4. 构建语音转文本应用程序
  5. 整个代码和结论

1.AWS 服务

AWS Amplify :帮助你构建基于 AWS 的 web 和移动应用。支持 React、Angular、Vue 等各种 web 框架,以及 Android、iOS 等移动平台。

AWS 转录 : Auto-AI 服务,允许没有 ML 经验的开发者在后端集成语音到文本的功能。

身份访问和管理(IAM) :允许您通过权限和角色管理对 AWS 服务的访问。我们将为我们的 Amplify 用户创建一个与各种 AWS 服务合作的角色。

2.设置 AWS 放大器

在我们探索应用程序的 ML 方面之前,我们需要一个传统的 React 应用程序启动并运行。幸运的是,AWS 通过一个叫做 Amplify CLI 的东西让使用 Amplify 变得简单。CLI 将作为我们进入 AWS 的主要界面,并管理我们在应用程序中使用的服务/资源。我们将很快浏览一下具体的安装命令,但是如果你想自己浏览文档进行设置,这里有链接。在安装 CLI 之前,确保您已经安装了 Node.js、npm 和 git,我们将在本教程的后面使用所有这些。要安装 Amplify CLI,请根据您的机器使用以下命令。

放大 CLI 安装

接下来,我们需要用我们特定的 AWS 帐户配置 CLI。为此,您需要创建一个 IAM 用户,它代表使用该帐户的人。为此,运行以下命令,指定您所在的地区,创建用户名,并确保保存/输入 AWS 提供的访问密钥 ID秘密访问密钥,以将 CLI 连接到您的 AWS 帐户。

用 AWS 连接 Amplify CLI

填写完以下所有问题后,您应该会在您的命令行中看到如下所示的图像,以确保您的 CLI 已正确连接到您的帐户。

作者截图

既然已经正确设置了命令行,我们就可以开始创建 React 应用程序了。

创建和启动 React 应用程序

随着传统 React 应用程序的运行,我们现在需要初始化 Amplify,这样我们就可以创建我们的后端来与 ML 服务(如转录)进行交互。

初始化放大器

Amplify init 命令将创建一个 CloudFormation 模板(作为代码的基础设施),以便为 AWS 上的应用程序供应和部署所有资源

3.安装人工智能服务/预测资源

现在我们已经用 Amplify 库设置了一般的 React 应用程序,我们可以添加 Amplify 提供的 预测 特性。该类别具有各种功能和扩展,您可以添加从图像检测、转录、翻译到情感分析的内容。要添加语音到文本和文本到语音功能,运行以下命令并选择转换以选择这两个 ML 选项。

向 React 应用程序添加预测类别

作者截图

选择转换后,您将获得一个选项来添加转录和文本到语音功能。确保对这两个选项重复该过程,或者如果您愿意,进行翻译。对于转录,您将被要求填写一个源语言(我们的应用程序为美国英语),对于文本到语音,您将填写一个说话者声音和源语言。最后,让 Cognito 为您的认证应用提供动力,您应该准备好了。要提供您已下载的新预测功能,请在 CLI 中运行 amplify push 来更新您在云中的资源。

4.构建语音转文本应用程序

随着预测资源的准备就绪,现在只需调整 app.js 代码来包含这些功能。我将使用这个链接提供的放大预测文档的例子。请随意跟随或调整代码,无论如何我都不是一个伟大的 ReactJS 开发人员,我只是想展示他们提供的代码作为开始的例子。要使用转录,我们需要先添加一个麦克风功能,所以请确保安装以下库。

添加麦克风进行转录

接下来,我们想要添加我们将在应用程序中使用的适当的库。

用于导入放大预测的库

接下来,我们需要添加转录功能,这将调用 AWS 转录。录制开始后,转录将开始,并转换为我们的源语言,在这种情况下是英语。

转录功能

接下来,我们需要添加语音到文本的功能来完成我们的应用程序。

文本到语音功能

现在我们在 app.js 文件中有了这两个函数,我们需要正确地返回这两个组件,这样我们就可以看到 ML 在前端工作。

返回 ML 组件

启动 React 应用程序后,我们有了一个全功能的项目,具有转录和文本到语音的功能,您可以根据自己的意愿进行调整和配置!

前端由 ML 提供动力(作者截图)

6.代码/信用和结论

这个项目的完整代码可以在这个链接中找到。源代码的所有功劳归于他们提供的实际 AWS Amplify 示例,我提取并配置了我的转录和文本到语音功能所需的部分。

看到 Auto-AI 已经走了多远,以及在几乎没有理论上的 ML 经验的情况下将 ML/AI 整合到您的应用程序中是多么容易,这令人惊讶。如果你试图用 ML 来驱动你的应用程序,并且没有什么经验或者没有时间来构建一个定制模型,我绝对推荐你使用这个特性。AWS 中还有各种其他的高级人工智能服务,我希望在接下来的文章中讨论。与此同时,如果你想开始了解如何在 AWS 上构建自己的定制模型,请点击这里查看我的文章。我希望这篇文章对任何试图将 ML 集成到他们的应用程序中的人或者从总体上了解更多 AWS 的人有用。请随时在 Linkedln 上与我联系,或者在 Medium 上关注我,了解我的更多写作内容。分享任何想法或反馈,谢谢阅读!

构建一个实时的 Twitter 机器人,可以回复媒体

原文:https://towardsdatascience.com/building-a-real-time-twitter-bot-that-replies-with-media-e353fff1c395?source=collection_archive---------13-----------------------

构建一个实时 Twitter bot,使用 Node.js 上传媒体作为对特定标签的所有 tweets 的回复。

亚历山大·沙托夫Unsplash 上拍摄的照片

源代码:https://github.com/pguduguntla/twitter-bot-reply-media

Twitter 使得构建能够与推文、用户和分析工具交互的机器人变得非常容易,这些工具可以从平台上获取有用的见解。

我想开发一个简单的实时 Twitter 机器人,它可以主动过滤所有包含特定标签的推文,并通过视频/图像直接回复推文。

在本教程中,我将介绍如何设置和构建一个简单的 Twitter 机器人来搜索带有标签#FilterMe的推文。如果这条推文包含一些媒体,那么我们的机器人将回复一个视频,如果它没有附加任何媒体,我们的机器人将回复一条类似于Oops, looks like you didn’t provide a media file!的消息。所以,让我们开始吧!

1.创建 Twitter 开发者账户

为了访问 Twitter 的 API,我们需要首先创建一个开发者帐户。你需要创建一个 Twitter 账户(如果你还没有的话),这个账户可以用来发帖。如果您不希望您的机器人与您的个人帐户相关联,以您的机器人的名字创建一个新的 Twitter 帐户。

然后,你需要通过他们的网站这里申请一个开发者账户。该应用程序会要求您提供一系列详细信息,包括您的联系信息、使用 Twitter API 的原因以及编程经验水平。表单非常标准,但是当被问及您希望使用 API 构建什么类型的项目时,请确保提供足够的信息。您的回答越全面,审批过程就越快。

一旦您完成了审批流程(可能需要 24 小时),您将可以访问您自己的个人开发者门户,如下所示。如你所见,我已经创建了一个应用程序,但我将向你展示如何创建你自己的应用程序。

转到左侧导航栏上的项目和应用部分。转到概述,您应该能够创建一个项目或一个应用程序。项目允许您使用 Twitter 的最新 v2 API,该 API 仍在生产中,因此对于像这样的简单项目,我建议通过单击“创建应用程序”按钮创建一个独立的应用程序。

单击创建应用程序后,系统会要求您在收到 API 密钥之前命名应用程序。

请确保将您的 API 密钥存储在安全的位置,因为这些密钥将用于验证我们的帐户。我们几乎完成了设置!我们只需要再获得一些访问令牌密钥,我们也需要这些密钥来验证我们的帐户。点击左侧导航栏上的应用名称,即可进入应用设置页面。点击密钥和令牌,并点击生成访问令牌和访问令牌密码。

深呼吸…我们完成了设置。现在到了有趣的部分!让我们用一些代码来弄脏我们的手。

2.设置我们的 Node.js 项目

在编写任何代码之前,让我们设置 Node.js 项目。如果你还没有 Node.js,你需要安装它。你可以在这里找到如何操作的说明

一旦你完成了,开始创建并进入你的项目文件夹。转到存储项目的目录,运行以下命令:

mkdir twitter-bot
cd twitter-bot

为了将其初始化为 Node.js 项目运行

npm init

在初始化项目之前,将要求您命名项目并接受所有提示。这将生成一个 package.json 文件,该文件跟踪您的项目细节和所使用的包。

现在,我们将创建三个文件。

touch bot.js
touch config.js
touch .env

首先,bot.js它将存储我们的 Twitter 机器人的主要源代码。文件config.js将存储几个帮助方法,这些方法将帮助我们与 API 交互并简化我们在bot.js中的代码。

.env文件将把我们的 API 键存储为全局变量。在您的.env文件中添加以下代码。替换上面您自己的 API 键获得的“X”。

API_KEY=XXXXXXXXXXXXXXXX
SECRET_KEY=XXXXXXXXXXXXXXXX
ACCESS_TOKEN=XXXXXXXXXXXXXXXX
ACCESS_TOKEN_SECRET=XXXXXXXXXXXXXXXX

最后,让我们在项目中安装一些模块,帮助我们导航 Twitter API 和存储 API 键。

npm install twitter dotenv bluebird --save

twitter 包是一个第三方模块,它使得 Node.js 用户与 Twitter API 的交互更加容易。Dotenv 允许我们加载全局变量(比如我们的 API 键),将它们与我们的项目代码分开。蓝鸟允许我们处理 API 请求承诺。

3.通过标签实时过滤推文

让我们首先在您最喜欢的文本编辑器中打开我们的config.js文件。添加以下代码,用 Twitter API 定义我们的身份验证。

在上面的代码中,我们导入了 Twitter 和 dotenv 包。在 auth 方法中,我们从我们的。环境文件。然后,我们用 secret 对象定义一个新的 Twitter 客户端,并返回该客户端。最后,我们导出 auth 方法,以便可以在 bot.js 中访问它。

在我们的 bot.js 文件中,我们有以下代码:

我们从导入配置文件中定义的 auth 函数开始。然后,我们通过调用 auth 函数来定义我们的 Twitter 客户端。然后,我们使用客户端的 stream()函数来跟踪所有带有文本“#FilterMe”的公共 tweets。我们将一个回调函数传递给接受流对象的 stream()。当实时流检测到 tweet 时,它运行另一个包含 tweet 对象的回调函数。该对象包含关于 tweet 和发布它的用户的详细信息。

现在我们已经收到了一条推文,我们需要检查这条推文是否附有媒体,如果有,就用视频回复!

4.上传媒体至 Tweet 回复

到目前为止,我们能够创建一个 Twitter 客户端,可以实时传输推文,并识别符合特定标准的推文。现在,我们必须与一些媒体一起发布对这条推文的回复。

首先,让我们将一个视频添加到项目文件夹的子目录中。/示例-媒体。确保你的视频是 mp4 格式的。

使用 Twitter API,上传和访问媒体有 3 个步骤:

  1. 初始化媒体上传:在 Twitter 的后端为我们的视频文件分配空间。为该空间检索一个mediaId
  2. 添加媒体文件:mediaId将我们的文件数据添加到 Twitter 后端。
  3. 完成上传:一旦我们上传到文件,我们需要完成上传以确保上传已经安全完成。
  4. 发布媒体对一条推文的回复:发布对原推文的回复,并附上部分文字和我们上传的视频。

我们将在 config.js 文件中添加方法来完成上述步骤。将以下代码添加到文件中:

您需要更新您的导入语句以包含这些模块:

const fs = require('fs');
const Promise = require('bluebird')

您还需要更新文件底部的 module.exports 以包含 postReplyWithMedia:

module.exports = { auth, postReplyWithMedia, postReply };

让我们仔细分析上面的代码,看看每个函数在做什么。

initializeMediaUpload方法接受一个 Twitter 客户端和一个文件的文件路径。在这个函数中,我们定义了视频格式和文件的大小。然后,我们调用 twitter 客户端上的 media/upload 端点来为一个 mp4 视频文件分配空间,该文件的大小与我们的视频相同。initialize 返回一个 Promise 对象,当它被实现时,包含 Twitter 数据库中我们的视频的 mediaId。

appendFileChunk方法接受一个客户机、mediaId 和一个上传文件的路径。这个方法在完成initializeMediaUpload时运行,因此,我们得到一个 mediaId tho,我们将实际的文件数据附加到 Twitter 的后端。我们使用fs.readFileSync(pathToFile)从文件中提取数据,并将其存储在 mediaData 中。再次,我们用命令“APPEND”调用媒体/上传端点,并传递我们的文件。返回一个包含我们的 mediaId 的承诺。

最后,finalizeUploadMethod接受一个客户端和 mediaId,并再次调用 media/upload 来确保我们的文件上传成功。然后,它返回一个带有 mediaId 的承诺。

函数postReplyWithMedia是将从 bot.js 中调用的函数。它接受客户端、mediaFilePath 和 replyTweet,reply Tweet 是我们要回复的 tweet 对象。在这个方法中,我们初始化我们的媒体上传,附加我们的媒体文件,并在发布我们的回复之前完成上传。我们构建了一个statusObj,它将我们的回复消息存储在状态中,将 tweet Id 存储在 in_reply_to_status_id 中,将我们视频的 mediaId 存储在 media_ids 中。然后,我们使用status/update端点发布我们的状态,我们在回调中接收我们新发布的 tweet。

函数postReply获取客户端、消息和 tweet,并以与上述函数类似的方式发布回复。

快好了!现在我们只需要导入并调用 bot.js 中的 postReplyWithMedia 和 postReply 方法。

在我们的 bot.js 文件中,我们只需要添加一个 if 语句来检查原始 tweet 是否包含媒体。我们可以通过检查 tweet 对象是否有 media_url 键来做到这一点。最终的 bot.js 文件应该如下所示:

我们走吧!您应该能够通过运行以下命令来运行您的 bot:

node bot.js

尝试自己或让朋友用标签“#FilterMe”来发布你的机器人,看看你的帐户是否会发布帖子。这可能需要一秒钟的时间,但是如果你按照这些步骤去做,应该会成功!

5.后续步骤

恭喜你。你创建了一个可以实时用视频回复推文的 Twitter 机器人。然而,我们的应用程序目前在本地运行。如果您希望将应用程序部署到云上,可以考虑将项目托管在 Heroku 或 AWS 上。这里有一个很好的免费教程,可以让你在 Heroku 上快速部署你的机器人。

我希望你学到了新的东西!如果您有任何反馈或问题,请随时告诉我。一如既往的感谢阅读!😃)

源代码:https://github.com/pguduguntla/twitter-bot-reply-media

编码快乐!

用 Socket.io 库在 NodeJS Express 中构建实时 web app

原文:https://towardsdatascience.com/building-a-real-time-web-app-in-nodejs-express-with-socket-io-library-d9b50aded6e6?source=collection_archive---------6-----------------------

服务器+客户端代码实现来检索公交车到达时间

用例:我的公交路线可视化网站

为了更深入地了解公共交通通勤者的出行模式,几个月前我接受了一项任务,对一系列公共汽车出行进行出行链分析。虽然我最初在建立了一个公交路线可视化网站,其唯一目的是基于所选的特定始发地-目的地配对导出定制公交路线数据:

作者截图|显示支持选择始发地和目的地公交车站的网站功能

作者截图|选择的始发地公交线路数据可以在 web app 上导出

后来我决定进一步探索和利用数据提供商的公共 API,其中包括返回任何特定公交车站的实时公交到达时间。简而言之,我很好奇 API 在它的实时响应中还包括哪些数据字段🤔

虽然有其他库能够在 web 应用程序中集成实时数据流,但我实现 Socket.io 的主要原因是因为它不仅提供了在服务器+客户端之间建立 Web socket 双向连接的功能,而且两个服务器&客户端代码实现都是用 JavaScript 编写的,因此在编写应用程序的后端和前端代码时,无需在两种语言之间来回切换。

socket . io 的服务器端实现

首先,在 Express NodeJS web 应用程序中,代码的服务器端通常指的是app.js/server.js 文件,即初始化 Express.js 实例的 web 应用程序的入口点。通过npm install socket.io安装 NodeJS Socket.io 库后,服务器端代码实现如下:

因此,在上面的代码片段中应该注意几个关键点:

1。库 socket.io 通过以下方式导入:

const socketio=require("socket.io")

2。默认情况下,任何 web socket 实例都有名称空间disconnect——如果实例已经与前端断开连接(通常是由于与其 web 服务器断开连接)

3。定制名称空间bus_arrivalsget_bus_arrivals_info将随后对应于来自客户端的完全相同的名称空间 (KIV) ,使得在存在多个套接字通道的情况下,web 套接字实例将能够基于名称空间来识别将哪些消息发送到哪些通道。

4*。在从 Express NodeJS 库中创建了 app 实例之后,包装了 app 实例的服务器实例通过以下方式进行初始化:

const server = http.createServer(app)

⚠这一点非常重要,因为应用服务器实例具有完全独立的功能。当 web 应用程序的内容由应用程序实例提供服务时,实际的 web 套接字连接实际上是在服务器实例上运行的,其表示为:

const io = socketio(server)

Socket.io 的客户端实现

从上述实现的第 3 点继续,回想一下命名空间bus_arrivalsget_bus_arrivals_info是为 2 个 web 套接字通道指定的:

作者插图|服务器通过套接字通道【bus _ arrivals】从客户端接收请求,以了解服务器应该检索哪个汽车站信息。然后,服务器继续进行 API 调用,以检索该特定汽车站的汽车到达信息。最后,API 响应通过 web socket 通道【get _ bus _ arrival _ info】返回到前端进行渲染

要初始化 web 套接字的客户端实例,必须包含用于 socket.io 的 JavaScript 浏览器库:

<script type="text/javascript" src="js/socket.io.js"></script>

在实现 Socket.io 的以下代码片段嵌入浏览器的 JavaScript 内容之前:

⚠请注意,服务器端安装的 NPM Socket.io 包和浏览器端导入的 JavaScript 库版本必须兼容。在我的 web 应用中,我使用过的 Socket.io 库的版本有:

  • 服务器端 NPM 包: socket.io v4.1.3
  • 客户端 JavaScript 库: Socket。IO 版本 4.1.3

有关确定您已安装的 NPM 包是否与您在浏览器上导入的 JavaScript 库兼容的更多信息,请参考 Socket.io 的官方网站

最后,在决定了应该显示公交车到站信息的哪些数据字段之后,我决定实现以下布局:

作者截图|左图是从 android 设备上看到的,右图是从平板电脑屏幕上看到的。

这就对了。巴士 ETAs 现在将每 10 秒重新渲染一次(可以定制)以反映最新的更新!🤩

参考消息:完整的源代码请点击my GitHub repo。web 应用程序当前部署在:https://sg-transportation.glitch.me/

希望上面在 NodeJS 中实现 Socket.io 的例子对您有用,非常感谢您的阅读!❤:如果你想阅读我即将发表的应对工作挑战的文章(包括人和技术问题),请跟随我!会非常感激😀

https://geek-cc.medium.com/membership

利用机器学习和计算机视觉构建实时坑洞检测系统

原文:https://towardsdatascience.com/building-a-realtime-pothole-detection-system-using-machine-learning-and-computer-vision-2e5fb2e5e746?source=collection_archive---------13-----------------------

图 1:安装在行驶车辆上的摄像头检测到的坑洞截图。坑洞用具有检测置信度的矩形区域标记(图片由作者提供)

坑洼是由于道路的磨损和风化形成的。它们不仅给市民带来不适,还会因交通事故而导致死亡。美国记录了每年超过 2000 起由于路面坑洼和恶劣路况造成的致命事故。

本文描述了一种建立实时检测系统的方法。

这种检测系统有许多使用案例。例如,市政当局可以检测和定位坑洞,并评估其大小,以便他们可以计划维修。安装在行驶车辆上的摄像头可以实时检测坑洼,帮助司机避开坑洼。

在很高的层次上,步骤如下:

  1. 数据采集和准备
  2. 模型训练和评估
  3. 实时检测的模型部署

1。数据准备

我们需要有监督的机器学习模型的标记图像。我们从互联网上收集了 1000 张坑洞图像,并使用图像注释工具对它们进行了标记。有一些很好的图像标记工具——包括商业的和开源的。我们用的是微软的 VoTT。这是开源的,麻省理工学院许可的,可以在 https://github.com/microsoft/VoTT的 github 上获得。

图 2:使用 VoTT 标记的坑洞图像(图片由作者提供)

如图 2 所示,我们在 VoTT 中加载了图像,并标记了一个标签,例如 pothole。要了解如何使用 VoTT 进行注释,请查看 GitHub 站点上的官方文档。

VoTT 允许以不同的格式导出带注释的图像。我们以名为 TFRecord 的 TensorFlow 兼容格式导出图像。

训练集:我们通常将 80%的标记图像作为训练集。将所有训练 TFRecords 存储在一个目录中,比如说 pothole_training。

测试集:剩余的 20%的标记图像被留出作为测试集。我们将它们存储在一个单独的目录中,比如说 pothole_test。

机器学习模型训练

在将所有图像标记并分成训练集和测试集之后,我们准备好训练我们的模型。我们将使用单镜头多框检测或 SSD 算法来训练对象检测模型。我们选择 SSD 而不是其他对象检测模型,因为与 RCNN 或其变体等其他算法相比,它提供了合理的准确性和更快的速度。YOLO 也提供了很大的准确性和速度,但在这篇文章中,我们坚持固态硬盘。SSD 的另一个优势是它可以检测图像中更小的对象。

我们使用动量人工智能来训练模型。这允许我们训练模型并迭代建模过程,而无需编写一行代码。Momentum SSD 运行在 TensorFlow 执行引擎之上,并提供了一个可扩展的平台来在 CPU 和 GPU 上运行培训。当然,你可以写 TensorFlow 来训练你的模型。

使用其直观的用户界面,很容易在 Momentum 上配置和训练 SSD。

如下图 3 所示,单击“训练新模型”按钮,选择“SSD 对象检测”复选框,填写表格(出于演示目的,可操作的元素以黄色突出显示)。

图 Momentum AI 的 SSD 型号配置页面截图(图片由作者提供)

一些值得注意的配置项目:

training_data_dir:这是包含用于训练的 TFRecord 文件的目录

test_data_dir:这是包含用于测试的 TFRecords 的目录。

label_map_file:这是从 VoTT 导出 TFRecords 时生成的文件。

network_config:从头开始训练模型是一项非常耗时的计算密集型任务。Momentum 提供了使用以下预训练检查点执行迁移学习的选项:

ResNet50/RetinaNet50,输入尺寸 640 x640
resnet 50/retina net 50,输入尺寸 1024 x1024
resnet 101/retina net 101,输入尺寸 640 x640
resnet 101/retina net 101,输入尺寸 1024 x1024
resnet 152/retina net 152,输入尺寸 640 x640
resnet 152/retina net 151

在运行模型之前,我们需要将 TFRecords(训练集和测试集以及 label_map_file)上传到 Momentum。您可以使用 Momentum 的“数据管理”工具将文件上传到相应的目录中(如下图 4 所示)

图 4: Momentum 截图显示使用数据管理工具上传 TFRecords(图片由作者提供)

使用 Momentum 的用户界面运行模型。为此,从左侧菜单中展开 My Models,单击您刚刚配置的 Pothole 模型,然后单击“Run”按钮(在下面的图 5 中突出显示为黄色以进行演示)。

图 5: Momentum 截图——运行 SSD 模型。屏幕还显示了评估和部署模型的按钮(图片由作者提供)。

图 5 显示了“Run”按钮,单击该按钮将触发培训任务。模型完全训练好还需要一段时间。模型所需的时间取决于标记数据的数量、输入图像大小、批次大小和机器的整体容量。

动量在张量流上执行训练。它还允许在安装了 TensorFlow with GPU 的远程服务器/集群上运行模型。

监控模型执行

在训练进行的同时,我们可以通过启动 TensorBoard 来监控模型性能。下图 6 显示了 Tensorboard 屏幕,显示了训练期间的各种模型损失。

图 Tensorboard 上显示的训练损失(图片由作者提供)

当模型被完全训练并且损失被最小化时(如在 Tensorboard 上观察到的),你可以在动量上部署模型。或者,您可以下载 TensorFlow 兼容模型并编写自定义代码来执行坑洞检测。

实时坑洞检测的样本输出

下面的视频显示了一辆以每小时 50 英里的速度行驶的汽车上安装的摄像头对坑洞的检测。这个视频是由乔治梅森大学的一群研究生开发的最终产品,作为 Accure 赞助的他们的顶点项目的一部分。

Momentum 是一个企业人工智能平台,可以免费用于学习和教育目的。你可以在 https://impulse.accure.ai/register/注册一个免费账户。

坑洞探测是 Accure 赞助的顶点项目,我有机会监督和指导乔治梅森大学的研究生团队。

建立食谱推荐系统

原文:https://towardsdatascience.com/building-a-recipe-recommendation-system-297c229dda7b?source=collection_archive---------4-----------------------

使用 Word2Vec、Scikit-Learn 和 Streamlit

艾拉·奥尔森在 Unsplash 上拍摄的照片

首先,如果你想玩完成的应用程序。可以在这里:https://share . streamlit . io/jackmleitch/what scooking-deployment/streamlit . py

作者图片

在之前的一篇博文(使用 Scikit-Learn、NLTK、Docker、Flask 和 Heroku 构建食谱推荐 API)中,我写了我是如何着手构建食谱推荐系统的。总结一下:我首先清理并解析了每个食谱的配料(例如,1 个洋葱丁变成了洋葱),接下来我使用 TF-IDF 对每个食谱配料列表进行了编码。在这里,我应用了一个相似性函数来找出已知 食谱配料和终端用户给出的配料之间的相似性。最后,根据相似度得分,我们可以得到最受推荐的食谱。

作者图片

然而,在使用我的新 API 一段时间后,我想在两个方面进行改进:

  1. 有时推荐中的成分与输入成分不一致,所以我需要一些更好的嵌入。
  2. Flask API 需要一个很好的改造。

输入 Gensim 的 Word2Vec 和 Streamlit。

成分的预处理和解析

为了理解手头的任务,让我们看一个例子。杰米·奥利弗网站上的美味“Gennaro 的经典意面烤面条”食谱要求配料:

  • 3 个大鸡蛋黄
  • 40 克帕尔马干酪,外加上菜
  • 1 块 150 克的高福利咸肉
  • 200 克干意大利面
  • 1 瓣大蒜
  • 特级初榨橄榄油

这里有很多冗余信息;例如,重量和度量不会给菜谱的矢量编码增加价值。如果有什么不同的话,那就是区分不同的食谱变得更加困难。所以我们需要摆脱这些。快速的谷歌搜索把我带到了维基百科的一个页面,包含了一个标准烹饪标准的列表,比如丁香、克、茶匙等等。在我的 ingredient parser 中删除所有这些单词效果非常好。

我们还想从我们的配料中去除停用词。在自然语言处理中,“停用词”指的是一种语言中最常见的词。例如,句子“学习什么是停用词”变成了“学习停用词”。NLTK 为我们提供了一种移除(大部分)这些单词的简单方法。

配料中还有其他对我们没用的词——这些是食谱中很常见的词。例如,油被用在大多数食谱中,并且在食谱之间提供很少或没有区别的能力。此外,大多数人家里都有石油,所以每次使用 API 时都必须编写石油既麻烦又没有意义。有一些先进的 NLP 技术,例如使用条件随机场(一种统计建模),可以计算出一个词是一个成分的概率,而不是围绕成分词的度量、纹理或另一种类型的词。但是,简单地删除最常见的单词似乎非常有效,所以我这样做了。奥卡姆剃刀和所有这些……为了得到最常见的单词,我们可以做以下事情:

然而,我们还有最后一个障碍要克服。当我们试图将这些“垃圾”单词从我们的成分列表中删除时,当同一单词有不同的变体时会发生什么呢?如果我们想删除每一次出现的单词“pound ”,但菜谱成分却说“pounds ”,会发生什么情况?幸运的是,有一个非常简单的解决方法:词汇化和词干化。词干化和词元化都产生词根形式的词尾变化——区别在于词干可能不是一个实际的词,而词元是一个实际的语言词。虽然词汇化通常较慢,但我选择使用这种技术,因为我知道其中的成分将是实际的单词,这对调试和可视化很有用(使用词干化的结果实际上是相同的)。当用户向 API 提供成分时,我们也对这些单词进行词汇化,因为词汇化的单词是具有相应向量的单词。

我们可以将所有这些放在一个函数ingredient_parser中,以及其他一些标准的预处理:去掉标点符号,去掉重音符号,将所有内容都变成小写,去掉 Unicode。

当分析“Gennaro ' s classic spaghetti carbonara”的配料时,我们得到了:蛋黄、帕尔马干酪、培根、意大利面、大蒜。太好了,这太棒了!使用df.apply when 可以轻松解析每个菜谱的配料。

使用 Word2Vec 的单词嵌入

Word2Vec 是一个产生单词嵌入的 2 层神经网络。它接受一个文本语料库作为输入(单个文档的集合),并将每个单词映射到欧几里得空间中的一个向量。最终目标是拥有一个能够捕捉单词之间的分布相似性的文本表示。也就是说,经常出现在相似上下文中的单词被映射到由较短欧几里德距离(L2 范数)分隔的向量。

在食谱成分的上下文中,Word2vec 允许我捕捉经常一起使用的食谱成分之间的相似之处。例如,制作比萨饼时常用的马苏里拉奶酪与其他奶酪和比萨饼相关的配料最相似。

我选择使用 Word2Vec 的连续单词包(CBOW)变体。CBOW 试图学习一种语言模型,该模型试图预测滑动窗口中的中心单词。由于 Word2Vec 试图根据单词的环境来预测单词,因此按字母顺序对成分进行排序至关重要。如果我没有根据一致的标准对配料进行排序,那么模型会将不同顺序的配料解释为具有不同的上下文。

选择的超参数如下:

  • size=100,这是指嵌入的维数。通过尝试 50、100、150,我选定了 100,看看哪个表现最好。
  • sg = 0,这将创建一个 CBOW 模型,而不是 SkipGram 模型。
  • workers = 8,我拥有的 CPU 数量。
  • window = 6,这是预测中心单词的滑动窗口的大小。选择 6 是因为它是每个文档(成分列表)的平均长度。
  • min_count = 1,在训练发生之前,低于 min_count 频率的字被丢弃。选择 1 是因为我希望所有的成分都有嵌入。

Word2Vec 训练代码如下。我使用了流行的 python 库 Gensim。

文档嵌入

为了构建食谱推荐,我需要将每个文档(每个成分列表)表示为一个嵌入。这让我可以计算相应的相似性。那么,我们如何使用我们的单词嵌入来计算整个成分列表的代表向量呢?我尝试了两种不同的方法:一种简单,另一种稍微复杂一些。为此,我跟着这个优秀的教程

平均单词嵌入

这就是它在 tin 上所说的,它直接对每个文档中的所有单词嵌入进行平均。代码改编自这里这里

使用 TF-IDF 来聚合嵌入

这里我们做的和上面一样,但是我们做的是加权平均,并使用逆文档频率(IDF)来缩放每个向量。IDF 衡量一个术语在整个语料库中的重要性。IDF 将对语料库中非常常见的术语(在我们的例子中,如橄榄油、大蒜、黄油等)进行加权。)和衡量罕见的条款。这对我们是有用的,因为它将给予我们更好的区分食谱的能力,因为按比例缩小的配料将是用户倾向于不作为推荐系统的输入给出的配料。

推荐系统

该应用程序仅包含文本数据,并且没有可用的评级类型,因此我们不能使用矩阵分解方法,例如基于 SVD 和相关系数的方法。

我们使用基于内容的过滤,这使我们能够根据用户提供的属性(成分)向人们推荐食谱。为了度量文档之间的相似性,我使用了余弦相似度。我也尝试使用空间和 KNN,但余弦相似性在性能(和易用性)方面胜出。

数学上,余弦相似性度量两个向量之间角度的余弦。从数学角度来看,这与相同向量的内积相同,都归一化为长度为 1。用余弦相似度,角度越小,余弦相似度越高:所以我们在努力最大化这个分数。

值得注意的是,没有评估模型性能的具体方法,所以我必须手动评估这些建议。老实说,这实际上非常有趣…我还发现了一大堆新食谱!令人欣慰的是,当我们放入配料时(当然是在它们被解析之前!)对于我们最爱的 Gennaro 经典意面 carbonara,我们得到了正确的推荐,得分为 1。

现在,我冰箱/橱柜里的几样东西是:番茄酱,意大利面,西葫芦,洋葱,奶酪我们新建立的推荐系统建议我们做:

作者图片

我觉得不错——最好开始做饭吧!正如我们所看到的,这份食谱中我没有输入的所有成分都是非常常见的家居用品。

使用 Streamlit 创建应用程序

最后,我使用 Streamlit 创建并部署了一个应用程序。它非常容易制作,文档也非常容易理解。这个应用程序的代码可以在我的 Github 上找到。

作者图片

感谢阅读,我希望你喜欢它。这里有一些你可能感兴趣的我的其他故事…

用 PyTorch 构建剩余网络

原文:https://towardsdatascience.com/building-a-residual-network-with-pytorch-df2f6937053b?source=collection_archive---------17-----------------------

当网络变得非常深的时候

图片来自 Unsplash。

自动驾驶、人脸检测和许多计算机应用的成功都归功于深度神经网络。然而,许多人可能没有意识到,计算机视觉进步的繁荣是由于一种特定类型的架构:残余网络。事实上,导致这个人工智能主导世界的最先进的结果只有在残余块的发明下才成为可能——这是一个简单而优雅的概念,导致了创建真正“深度”网络的飞跃。

本文深入研究了残差网络背后的直觉和 PyTorch 中的实现,以训练 ResNets 执行图像分类任务。

在变‘深’之前,退化问题是什么?

理论上,具有更多变量的更深的网络对于近似困难的任务(例如图像理解)是更好的函数。然而,经验测试表明,传统的深度网络更难训练,表现甚至比浅网络更差。我们称之为退化问题。

这种现象是不直观的,因为假设我们有两个相同层数的网络,第二个网络在前面增加了 x 层,最坏的情况应该是第一个 x 层输出与原始输入相同的映射,因此具有相同的性能。

据推测,较差的性能是由于与原始输入的相同映射在过程中被遗忘,因此在 21 世纪初,网络(如 VGG-16)最多只有 10-20 层。

残留架构

残差网络是一种简单直接的方法,通过创建一种称为跳过连接的快捷方式来馈送原始输入,并在网络的几个堆叠层之后将其与输出特征相结合,从而解决上述退化问题。

图一。一个简单的剩余块。来源:https://arxiv.org/abs/1512.03385

形式上,如图 1 所示。,给定堆叠层的输入为 x ,网络层为函数 F ,输出 y 如下:

F(x)x 的尺寸不匹配时,可以简单地在跳接过程中进行线性投影来改变 x 的尺寸。

我们将上面的整个管道称为一个剩余块,我们可以有多个剩余块来构建一个更深的网络,而没有原来的退化问题。

计算环境

图书馆

整个程序是通过 PyTorch 库(包括 torchvision)构建的。以下代码导入所有库:

资料组

为了展示残差网络的能力,我们在两个数据集上进行测试:更简单的 MNIST 数据集,包括 6 万张从 0 到 9 的手写数字图像,以及更复杂的 CIFAR-10 数据集。

通常在测试过程中,人们可能会引用多个数据集,无论是出于研究目的还是为了查看哪个模型更通用。因此,当所有数据集被组织到一个平台中时,这是非常方便的。幸运的是,一家名为 Graviti 的年轻初创公司提出在其平台上托管许多臭名昭著的数据集。人们可以简单地直接下载它们来执行进一步的训练和测试。

硬件要求

最好在 GPU 上训练神经网络,因为它们可以显著提高训练速度。但是,如果只有 CPU 可用,您仍然可以测试程序。在我们的例子中,一个更简单的基于残差块的网络(只有几个网络)应该可以在两种类型的设备上运行,而更复杂的模型(如 ResNet-152)将更适合在 GPU 上运行。要让您的程序自己决定硬件,只需使用以下代码:

构建剩余块

本节提供 PyTorch 教程,介绍在输入和输出维数相同的卷积神经网络上可以创建的最简单类型的残差块。

人们可以使用 PyTorch nn 来创建它。模块如下:

使用预先存在的 ResNet 模型

一些利用剩余架构的网络已经在像 ImageNet 这样的大数据集下被证明是成功的。Torchvision 提供了网络的检查点和体系结构,如在其库中预构建的 ResNet-34、ResNet-50 和 ResNet-152。人们可以通过以下方式简单地检索他们的模型:

但是,如果要将网络微调到非 ImageNet 的数据集,则更新 ResNet 的最终图层非常重要,因为最终的独热向量等于数据集的类数。

结果

我们对我们的网络进行了 50 个历元的训练,对于 ResNet-34 和 ResNet-152,我们可以在 MNIST 数据集上轻松实现约 99%的准确率,在 CIFAR-10 数据集上轻松实现 90%的准确率。

基于何等人的原始论文的结果,我们还可以看到,残差架构在 ImageNet 数据集上的性能明显优于和具有相同层数但没有残差架构的网络。

这些结果可以直接从论文 这里 中检索出来。

结论

由何等人创建的剩余结构可以说是近年来计算机视觉神经网络发展中最伟大的发明之一。今天几乎所有的网络,甚至是卷积网络之外的网络,都有类似于更好更深的网络的概念。

这种简单而优雅的方法创造了无数的可能性,推动了机器对人类世界理解的前沿。

感谢您坚持到现在🙏 我会在计算机视觉/深度学习的不同领域发布更多内容。一定要看看我关于计算机视觉方法的其他文章!如果你对 Graviti 平台感兴趣,也可以随时加入 不和谐 频道!

建造石头剪刀布人工智能

原文:https://towardsdatascience.com/building-a-rock-paper-scissors-ai-948ec424132f?source=collection_archive---------13-----------------------

如何集成六个模型来预测和避免可预测性

在本文中,我将向您介绍我构建一个完整的 Python Flask 人工智能项目的过程,该项目能够使用一个定制的评分系统集成六个模型(基于简单逻辑的、决策树、神经网络),在游戏级别和 AWS RDS Cloud SQL 数据库中存储的历史数据上训练,在 60%以上的时间里击败人类用户。

在这里玩游戏

点击这里观看我关于项目的视频介绍,或者按以下章节跳转到视频

概观

视频剪辑此处

石头剪子布引起了我对一个人工智能项目的注意,因为从表面上看,它似乎不可能在游戏中获得优势。如今,很容易假设计算机可以在国际象棋中击败你,因为它可以利用其所有的计算能力来看到所有可能的结果,并选择对它有利的结果。另一方面,石头剪刀布通常被用来代替掷硬币来解决争端,因为赢家似乎是随机的。不过,我的理论是人类实际上不能做出随机的决定,如果人工智能能够学习理解人类在一系列比赛过程中做出选择的方式,即使人类试图随机行事,那么人工智能在猜测球员决定方面的准确率将大大超过 33%。

应用程序中的每个“游戏”都由一系列“回合”组成,玩家和人工智能分别在石头、布或剪刀之间做出选择,并确定获胜者。当玩家或电脑赢得指定回合数时,游戏结束。我的目标是看看我是否能让人工智能足够了解人类行为,从而赢得 55%以上的游戏。

第一次迭代

视频剪辑此处

我一开始只是简单地对我能想到的人类做决定的不同方式进行硬编码:一遍又一遍地选择同样的事情,按照一种模式进行选择,或者尝试做出他们已经有一段时间没有使用过的选择。我建立了模型,如果玩家使用这些方法中的任何一种,这些模型将预测玩家的下一个选择,然后使用基于逻辑的标准,根据前几轮的记录,尝试并决定哪个模型适合玩家的行为。这是项目的第一阶段,在 Jupyter 笔记本上运行,最初玩得很好。然而,它会很容易落入某些模式,并且可以被精明的玩家可靠地欺骗。

在这一点上,我意识到我可以做很多改进,并兴奋地将这个项目具体化。我做了一个 Flask webapp,并把它放在了 T2 的 Heroku 上,这样我就可以和朋友们分享了。然后,我在 AWS 上建立了一个云数据库,以捕捉每次播放的数据,因为我知道这些数据可以给我建立更复杂模型的能力。

我开始分析我的模型的性能并调整它们。我还用一个新的集成系统替换了简单的基于逻辑的模型选择过程,我将在下面进行更详细的介绍。我使用自举 HTML 创建了一个手机友好应用程序,改进了设计以获得更吸引人的用户体验,然后在社交媒体上发布了链接,供我的朋友和家人玩并提供见解。有了这些数据,我开始实现机器学习模型以及基于逻辑的模型,我将在下面更详细地介绍这些模型。此时,随着应用范围的扩大,进度变慢了,我必须解决包依赖、数据质量、后端和模型导出问题。然而,我继续迭代更新应用程序的功能,以响应我正在进行的数据分析和我继续改进它的新想法。这些天,当我和人工智能比赛时,即使知道它如何工作的一切,我也很难打败它。

人工智能如何工作

数据

数据在游戏过程中被记录下来,并保存在一个本地 SQLAlchemy 表中,该表每轮都传递给模型,以帮助它们做出相应的决策。它包括除 game_id 和 ip_address 之外的所有上述列。在每场比赛结束时,数据被发送到 AWS 云托管的数据库,并附加上这两列,可以访问这些数据来评估模型性能和训练 ML 模型。

组装

视频剪辑此处

每一轮,computer_choice 函数选择哪个模型作为 AI 在下一轮的选择。这是通过给定当前游戏记录对每个模型的性能评分来完成的。

这个评分系统是二次的,以便优先考虑最近的模型性能,使其对玩家可能使用的策略做出响应。首先,这允许模型克服玩家可能使用的简单模式,例如不断地玩相同的选择或以重复的模式切换选择。其次,它确保了相同的模型不会不断重复,这将允许玩家弄清楚它是如何工作的,并击败它。如果玩家真的想出了一个模型,它会输,并很快获得一个负分,这是因为二次评分优先考虑最近几轮。最后,它允许更准确地预测玩家思维的模型被更频繁地使用。下面是一轮比赛中后端的一个例子:

天真的模型

视频剪辑此处

每个模型都采用不同的方法来理解玩家将如何做出下一个选择。前四个模型对玩家做出选择的方式做出了非常具体的假设,因此只适用于玩家以给定方式行动的情况。

  • 模式 0 :选择输给或击败玩家先前选择的选项。基于玩家将继续不重复或重复先前选择的假设。
  • 模式一:基于过去三轮的向量选择。基于玩家将使用某种模式(例如石头,布,剪刀,石头,布,剪刀,等等。)
  • 模式 2 :选择击败玩家最近最常选择的选项。基于一个假设,一个玩家有一个他们一直在做的选择。
  • 模式 3 :选择击败玩家最近最少选择的选项。基于玩家会尝试玩他们有一段时间没玩过的游戏的假设。

随着 ensembler 被构建为支持在最近几轮中准确预测的模型,如果人类玩家重复他们的假设所基于的行为足够多次,这些模型最终将在分数上上升,成为计算机选择中的决定性模型。

机器学习模型

最后两个模型更加复杂,一个是决策树,另一个是神经网络,都是在与人工智能比赛的历史数据集上训练的。这些模型需要更长的时间才能进入人工智能的决策过程,因为它们需要分别看到至少 7 轮和 5 轮球员数据,才能作为输入输入到它们的 ML 模型中。这些模型不仅知道玩家在前几轮的选择,还知道计算机的选择,谁是赢家,人工智能用来做出选择的模型,以及每个模型在前几轮的选择。

  • 模型 4 :使用基于历史数据训练的腌 scikit-learn 神经网络模型,根据前 7 轮的数据预测并击败玩家的下一个选择。
  • 模型 5 :使用基于历史数据训练的腌制 scikit-learn 决策树模型,根据前 5 轮的数据预测并击败玩家的下一个选择。

使用天真的模型开始游戏有助于解决冷启动问题,在这种情况下,AI 对它正在开始新游戏的玩家一无所知。(随机数生成器的唯一用途是在第一轮,因为有必要使人工智能不完全可预测,否则随机数在这个应用程序的构建中是完全避免的。)因此,最初的人工智能通过其基于逻辑的模型尽最大努力,直到它在多个回合中更好地理解玩家,并可以打开其更智能的模型。请参见下图,了解在一场有记录的比赛中,模特是如何根据他们的得分被选出的。

集成模型选择可视化

视频剪辑此处

此图像旨在说明一个示例游戏的模型选择过程,而不是代表单个模型的一般功效。

统计数字

视频剪辑此处

我的目标是让人工智能赢得超过 55%的时间。目前,人工智能的胜率为 61.8%。

为了分析模型的表现,我们将查看两个数据集:一个显示模型在每轮中的选择结果与玩家在该轮中实际选择的结果,另一个显示模型在玩家选择该模型的轮中的实际表现。从下面可以看出,所有回合中表现最好的模型(根据赢/输比率判断)是模型 4,它做出了 203 次赢的选择和 168 次输的选择。第二好的是模型 5 的决策树模型,它已经做出了 273 次获胜的选择和 223 次失败的选择。注意:这些模型分数仅针对模型的最近迭代计算,因此模型 4 的神经网络的总计数较低。

只看集合者选择模型的回合,表现最好的模型也是神经网络模型 4,28 胜 16 负,紧随其后的是模型 2,59 胜 37 负。可以看出,天真的模型 0-2 在被选择时比在所有轮次中具有更高的赢/输比率,这意味着总体来说,整体选择了正确的时间来播放模型。比较这两个图,集成者似乎特别有效地使用模型 2,而当集成者选择模型 3 时,模型 3 实际上经历了低得多的赢/输比率,这意味着它没有在正确的时间被选择。

外卖食品

这个人工智能之所以能够超越我的预期,是因为它有两个重要的特征。首先,当玩家陷入简单模式时,它能够用其天真的模型击败他们,当他们可能遵循更复杂但仍然可测量的决策过程时,它能够用其复杂的模型击败他们。其次,它本身很难预测。作为编写它的人,我仍然无法预测当我与它对弈时它会做出什么选择;尤其是在引入机器学习模型之后,这一事实变成了现实。尽管事实上在第一轮后它的决策没有任何随机性,但它仍然远远超出了玩家计算 AI 会选择什么的能力。

为这种人工智能提供动力的模型集合是一个框架示例,可用于实时人工智能决策,其中数据相互之间具有弱相关性,并且最新趋势需要优先于整个数据集的平均值。

未来想法:

改进人工智能的一些想法:

  • 举办竞赛,为培训和验证新想法建立更大的数据集
  • 根据给定的分数,使用模型选择的加权平均值来测试集成器
  • 将玩家行为分类(例如算计、冒险、随机等。)然后将 ML 模型训练到每个聚类
  • 在集成器上构建一个元层,通过强化学习学习制定多轮策略

另一种可能性是将应用程序变成一个平台,数据科学家或学生可以在这个平台上竞争构建游戏人工智能,并试图击败同龄人的人工智能,并在排行榜上排名上升。

希望我在构建这个项目中使用的方法可以为您自己的 ML 项目提供一些灵感,如果您想查看我的任何源代码,请查看该项目的 GitHub repo

在这里玩游戏

本文使用的所有图片均由作者创作并拥有

构建可扩展的高性能大数据系统

原文:https://towardsdatascience.com/building-a-scalable-and-high-performances-big-data-system-221c6b6893eb?source=collection_archive---------16-----------------------

关于选择合适的工具来构建可扩展的大数据分析系统

Robynne Hu 在 Unsplash 上的照片

前一段时间,我有机会从事一个令人着迷的项目。我们需要一种方法来公开关于 Google Analytics 数据的 REST APIs,但是免费的 Google Analytics 版本存在一些大问题。

首先,保留期。在撰写本文时,Google Analytics(免费计划)的保留期为 26 个月。当然,你可以延长保存期,但它也有一些缺点(在这里阅读更多)。

另一个巨大的问题是,谷歌分析报告 API 的免费计划每天每个项目有 50.000 个请求和每秒 10 个查询的限制(每个 IP 地址,来源于此)。

这些问题使得使用报告 API 作为向 Google Analytics 发出请求的标准方式变得不可能,因为它不会在我们达到离散数量的用户时立即扩展。

因此,我们需要一种方法来将这些数据存储在我们的服务器中,并在我们需要时随时提供,没有任何速率和/或保留限制。

我们的限制

我们仍然希望使用谷歌分析作为我们的主要分析系统。过去一年我们一直在使用它,它拥有我们改善用户体验所需的一切。我们只需要做尽可能简单的事情,将这些数据暴露给 Next.js 前端。

因此,我们需要一个简单的计划作业,它调用 Google Analytics,对结果数据进行规范化,并将其存储在我们的服务器上,以便稍后将它们作为聚合数据公开:

需要记住的一点是,我们希望我们的数据尽可能的新鲜。这意味着计划的作业、数据规范化过程和数据库批量更新操作必须尽可能快。

数据标准化

在过去的几个月里,我们改变了 webapp 的一些资源的 URL 结构。这意味着我们需要增加对传统 URL 的支持,例如:

旧 URL:

https://www.example.com/users/AJH829SKLJ29/john-doe

                              ^ old ID

新 URL:

https://www.exampke.com/users/john-doe-0cc175b9c0f1

                                       ^ new ID

正如您所看到的,我们向客户端公开了一个 ID,但是它已经随着时间的推移而发生了变化。因此,在将旧 ID 插入数据库之前,我们还需要将其转换为新 ID。

我们还需要对数据执行其他转换,但这不需要访问我们的主数据库(PostgreSQL DB)。

构建概念证明

我们已经开始用 Node.js (TypeScript)作为主要的脚本语言,用 CouchDB 作为主要的数据库来构建一个概念证明。我们很快意识到需要添加 Redis 作为缓存层,因为调用数据库将旧 ID 转换成新 ID 非常耗时。它对缓存我们的 REST API 响应也很有帮助。

我们最初的基础设施是这样的:

关于我们第一次概念验证的一些想法:

  1. Node.js 非常适合原型化,但是即使使用 TypeScript,它似乎仍然不是密集数据操作的正确选择。免责声明:这是我的个人观点。我仍然喜欢 Node.js,我在日常工作中使用它,但我们真的想为这项工作选择正确的工具
  2. 为了使我们的查询更有效,我们使用 map/reduce 编程模型写下了一些 CouchDB 视图。虽然它使我们的查询非常高效,但写下非常优化的 map/reduce 查询需要一些经验和技能…我们开始非常想念 SQL。
  3. 这个解决方案在垂直方向上可以很好地扩展(为我们的服务器增加更多的能力),但是在水平方向上可以扩展(为我们的集群增加更多的节点)吗?我对 CouchDB 没有怀疑,但是 Node.js 服务器和它的内存缓存(被密集使用)呢?
  4. Node.js 性能够吗?我的意思是,Node.js 的性能绝对出色,但数据规范化过程似乎需要很长时间。为了提高它的性能,我们最终重构了部分代码库,删除了一些高阶函数以支持更命令式的模式,降低了我们的生产力和软件的可维护性。

改变方法

在测试环境中运行该系统一段时间后,我们开始发现我们在概念验证中做出的架构决策中的一些问题。CouchDB 仍然是一个很棒的数据库,但我们意识到,也许我们没有编写非常优化的查询所需的技能和知识。对于这样一个小团队来说,编写 map/reduce 视图变得非常痛苦,他们需要花更多的时间来寻找正确的 StackOverflow 答案,而不是编写实际的代码。我们也没有利用任何最受欢迎的 CouchDB 特性(数据同步、REST APIs 等等)。也就是说,也许 CouchDB 不是我们问题的最佳解决方案。

我们遇到的另一个问题是 Node.js 服务器的性能。让我们研究以下场景:

  1. Node.js 调用谷歌分析报告 API
  2. 报告 API 在大约0.8秒后响应数千条记录
  3. 对于每个报告行(实际上是一个对象数组),我们需要解析数据并调用 Redis/PostgreSQL 将旧的 id 转换成新的 id。
  4. 将规范化的数据插入 CouchDB。如果数据已经存在,我们需要获取它的 CouchDB _rev ID,并使用它来更新数据,而不是插入数据。
  5. 将数据插入 CouchDB 后,我们需要执行一个 CouchDB 查询来更新 PostgreSQL 数据库中的一些数据。

整个过程需要 4 秒左右才能完成,时间很多。我们需要解决所有这些问题,这些问题可以概括为:

  1. 提高数据规范化过程的性能
  2. 使用我们的 NoSQL 数据库提高开发人员的生产力
  3. 去掉所有命令式和低级的类型脚本,写出更好的单元测试和更易维护的软件。

在研究了不同的技术(Go、Python、Cassandra、MongoDB)之后,我们最终得出了一个想法,即我们的软件应该遵守一些重要的规则:

  1. 它必须水平缩放
  2. 它必须用高级语言编写
  3. 我们应该能够轻松地生成单元测试和文档
  4. 如果 Google APIs 需要0.8s来响应,那么规范化并在大约200ms处插入数据会很棒,这样整个过程将需要1s来完成。
  5. 调用 Redis 是可以的,但是如果有一个分布式内存缓存机制来避免调用外部服务来缓存旧 id 和新 ID 之间的关系,那就太棒了。

最终,我们想出了几种技术来帮助我们实现上述目标:长生不老药+卡桑德拉。

为什么是仙丹

Elixir 是一种函数式编程语言,可以编译成 Erlang 字节码。事实上,它运行在著名的 BEAM 虚拟机上,该虚拟机以其可靠性和性能而闻名:

“AXD301 实现了九个九的可靠性(是的,你没看错,99.9999999%)。让我们把它放在上下文中:5 个 9 被认为是好的(5.2 分钟的停机时间/年)。7 个 9 几乎无法实现…但我们做到了 9 个。这是为什么呢?没有共享状态,加上复杂的错误恢复模型。”(乔·阿姆斯特朗,Erlang 编程语言的作者)

一个著名的框架,如 Scala 的 Akka,从 Erlang 的 actor 模型中获得了巨大的灵感来构建大规模可伸缩和弹性的软件。

多亏了长生不老药,我们实际上可以解决我们之前提到的所有问题。

1)它必须水平缩放

长生不老药很快。非常非常快。即使有些功能执行起来要多花一点时间,仙丹代码也很容易并发运行。事实上,Erlang 和 Elixir 在语言本身中内置了一些并发原语。

让我们举一个非常琐碎的例子:

如你所见,我们定义了一个名为Example的模块,用一个名为factorial的方法返回其参数的总和。如果语法让你想起 Ruby...这是因为长生不老药是由前 Ruby On Rails 团队成员 José Valim 发明的!

顺便说一下,我们能够异步生成factorial函数(甚至在不同的机器上!)通过键入:

iex> spawn(Example, :factorial, [10])
#PID<0.114.0>

如您所见,它返回了衍生进程的#PID(进程 ID)...请注意,我有意使用了“进程”一词来代替线程!

“Erlang VM 中的进程是轻量级的,可以跨所有 CPU 运行。虽然它们看起来像本机线程,但它们更简单,而且在一个 Elixir 应用程序中有数千个并发进程并不少见”( source )

2)它必须用高级语言编写

Elixir 就像 Erlang、Java、PHP、Ruby 一样,是一种高级的、垃圾收集的编程语言。它提供了许多有用的结构和高阶函数,在编写复杂算法时非常有用。

再一次,让我们举一个简单的例子来编写一个 C++快速排序(摘自https://www.softwaretestinghelp.com/quick-sort):

以下是用 Elixir 编写的相同算法:

表演呢?嗯,C++更快,对此我并不感到惊讶!但是长生不老药足够快来证明它的用途。

高级语言提高了开发人员的生产力,我们需要找到合适的语言来处理大量的数据。仙丹似乎是那种工作的正确选择!

Elixir 还引入了大量的语法糖,真正帮助我们编写简洁明了的代码。仅以管道运营商为例:

或者匿名函数的简写:

函数会返回布尔值吗?用?字符就可以显式了!

一旦你习惯了这些句法糖,你就再也回不来了。

3)我们应该能够轻松地生成单元测试和文档

这大概是仙丹最牛逼的地方之一。事实上,Elixir 将文档和测试视为一等公民。假设我需要为上面的factorial函数写一些文档:

如你所见,我们正在编写一些看起来像 Javadoc/JSDoc 之类的注释。但与 Java 和 JavaScript 不同,这些注释是 Elixir 语言本身的一部分,我们可以使用 Elixir 团队自己制作的 ex_doc 包轻松生成文档!ex_doc 的另一个优点是它本身支持 markdown,因此您可以像在 repo 中编写 markdown 文件一样编写文档!

但是最好的还在后面。如您所见,我们正在文档中编写一个代码示例:

该代码示例将作为单元测试套件的一部分运行,因此您一定会编写出实际上按预期运行的文档!

4)加快数据规范化进程

正如我们之前说过的,长生不老药本身真的真的很快。但是由于它的并发能力,我们能够轻松地并发运行代码,将我们的数据视为一个流。

今天我们用了很多琐碎的例子,所以这里还有一个。假设我们有一个100000个整数的列表,我们想把每个整数乘以3,过滤掉所有的奇数,把列表中所有剩余的数相加。

还不习惯&的速记吗?下面是扩展的匿名函数表单:

顺便问一下,我们应该怎样把它转换成一个流呢?用Stream关键字代替Enum(可枚举)!

Stream模块支持惰性操作。这意味着一个函数只有在绝对必要时才会被求值。如果您正在处理大量数据,这将非常有用!

此外,为了提高数据规范化的性能,我们已经改变了我们的缓存机制,但我们将在下一段看到它。

5)告别雷迪斯

我知道,Redis 很棒。说真的,这可能是最漂亮的工程之一…但是感谢 Erlang VM,我们不需要它。

事实上,Erlang 的开源发行版附带了开放电信平台(OTP ),它是 Elixir 和 Erlang 可以本地调用的模块和工具的优秀集合。

  • Erlang VM 本身(称为 BEAM)
  • Erlang 编译器
  • 静态分析工具(透析器)
  • Yecc(一个 LALR-1 解析器生成器,类似于 YACC)
  • leex(Erlang 的词法分析器生成器)
  • 观察者(跟踪和调查分布式系统的工具)
  • Mnesia(分布式事务数据库)
  • ETS(一个分布式、键值、内存数据库)

和许多其他有益的、经过战斗考验的模块。

您可以将 BEAM 视为一个操作系统,它允许您使用其内置的工具,如数据库、编译器、词法分析器、HTTP/WebSocket 接口(是的,BEAM 本机支持它们)等等。

顺便说一下,我们想专注于 ETS。如前所述,Erlang 术语存储(ETS)是“Erlang 内置术语存储 BIFs 的一个接口。这些提供了在 Erlang 运行时系统中存储大量数据的能力,并提供了对数据的恒定访问时间。”(来源)。

ETS 可以很容易地用作内置缓存机制(让我们看一个使用 Erlang 内置 int REPL 的例子):

1> T = ets:new(t,[ordered_set]), ets:insert(T, {"555-1234", "John Smith"}).
true

2> ets:match(T,{[$5,$5,$5,$- |'$1'],'$2'}).
[["1234","John Smith"]]

我现在不会深入探究 Erlang 语法,但是我可以向您保证,使用 ETS 用 Elixir 构建一个缓存层非常简单。

是否要将缓存层设为分布式?嗯,Mnesia 实际上包装了 ETS 和 DETS(磁盘 Erlang 术语存储,基本上是 ETS 的磁盘持久性版本),向我们的缓存添加了一个分布式事务层!

想更详细的看看 ETS/Mnesia 和 Redis 的区别?这里有一篇关于这个的精彩文章:https://rollout.io/blog/elixir-ets-vs-redis

数据存储

正如本文开头所说,我们已经使用 CouchDB 作为主数据存储开始了我们的第一次概念验证。虽然它工作得很好,但我们觉得它不是我们团队的最佳解决方案。我们过去有过一些使用 Cassandra 的经验,它的 CQL 查询语言让我们重拾编写类似 SQL 的查询的乐趣。

这不是我们选择卡珊德拉的唯一原因。事实上,我们存储数据的时间间隔是一天,但是我们每隔几秒钟就更新一次数据,以保持数据尽可能的新鲜。使用 CouchDB,为了更新数据,我们需要进行一个查询来检查数据是否已经存在,获取它的_rev id,然后生成一个update查询。技术上不难,但是浪费很多时间。使用 Cassandra,我们可以生成一个insert查询,如果数据已经存在,它将更新它。此外,经过一些基准测试后,Cassandra 的插入似乎比 CouchDB 的要快一点(当然,对于我们正在处理的数据来说)。

另一件我们想了很多的事情是…“我们真的需要 CouchDB 吗”?我的意思是,它拥有我们需要的一切(大数据存储能力、大规模高性能)…但这是正确的选择吗?

  • 我们用的是它内置的 REST APIs 吗?号码
  • 我们在使用它强大的同步功能吗?号码
  • 我们需要一个无模式数据库吗?号码

那么我们需要什么?

  • 水平可伸缩数据库。卡桑德拉·✅
  • 没有单点故障。卡桑德拉·✅
  • 多数据中心复制。卡桑德拉·✅
  • 非无模式数据库。卡桑德拉·✅
  • 类似 SQL 的语法是一个优势。卡桑德拉·✅
  • map/reduce 是加分项。卡桑德拉·✅

因此,选择似乎很明显!在你问之前:是的,CouchDB 是用 Erlang 写的。遗憾的是,它没有任何本地 Erlang 驱动程序,所以我们在连接到其他数据库时有相同的延迟。

另一个明智的问题是:“你为什么不直接用 Mnesia”?嗯,这是个好问题。当然,我们可以使用 Mnesia……也许将来我们会这样做!对于记忆来说,也有一个 Ecto (Elixir ORM)连接器,但我们需要更多的调查,如果这是我们的正确选择。

REST APIs 和 GraphQL 层

我想谈的最后一件事是我们如何处理 REST APIs。在过去的几年中,许多 web 框架诞生了,其中大部分真的改变了生活。

毫无疑问,Ruby on Rails 是最受欢迎的框架之一。我甚至无法说出所有使用(或曾经使用)RoR 作为 web 框架来快速有效地启动服务的初创公司:Twitter、GitHub 和 Basecamp 只是其中的一部分。

Elixir 有自己的 MVC 框架,叫做 Phoenix,它源于 Ruby on Rails,但是它改进了它的性能、可维护性等等。我个人从来没有听说过一个 Elixir Phoenix 开发者抱怨这个框架。

如上所述,Erlang VM 已经支持 HTTP、WebSockets 和 PubSub,但是拥有 MVC 框架将真正帮助我们更容易地编写关键任务,例如请求授权。

鉴于 GraphQL 完全支持这个项目前端,我们还可以用神奇的灵丹妙药苦艾酒:https://github.com/absinthe-graphql/absinthe来添加对该查询语言的支持。

关于那个建筑的一些想法

我个人大约在四年前爱上了仙丹。虽然它还不是一种广泛使用的语言,但我确信在未来几年它会越来越受欢迎。

那是因为互联网场景变化很大,传统技术不够用。看看 Scala 就知道了:我为什么要添加大量的库和框架来添加 Erlang VM 中已经内置的东西,比如 actor 模型?当然,actor 模型很方便,可以解决许多问题,但不是以最初构建 JVM 的方式。

如果我已经有了 Mnesia 和 ETS,为什么还要添加 Redis(这也很棒)作为缓存层呢?如果在 BEAM 中已经有了我需要的所有东西,为什么还要添加 Ejabberd、RabbitMQ 或 Kafka 呢?如果 BEAM 给了我 Yecc 和 Leex,使编译 Erlang 字节码并将其集成到我的应用程序中成为可能,我为什么要用 C/Java/Go/Rust/whatever 编写特定于领域的语言呢?

Erlang 编程语言是在 80 年代诞生的。它仍然在解决现代网络开发的大量问题。

我们只是触及了这个令人敬畏的系统的表面,我可以向您保证,一旦您阅读了为什么 Erlang 能够真正解决您的问题,您将永远不会忘记它。

使用 NLTK 和 Altair 构建情感分析报告

原文:https://towardsdatascience.com/building-a-sentiment-analysis-interactive-report-using-nltk-and-altair-83cb9fcb36fe?source=collection_archive---------8-----------------------

使用 UCI 新闻数据集,我们将计算新闻标题的积极度,将结果可视化,并将它们打包成一个交互式报告

格伦·卡丽在 Unsplash 拍摄的照片

(免责声明:我在 Datapane 担任产品经理)

数据分析通常从结构化数据开始,即已经存储为数字、日期、类别等。然而,如果您使用适当的技术,非结构化数据可以产生重要的见解。在本教程中,我们将对文本数据集进行情感分析,以计算积极/消极情感,并将结果转化为交互式报告。

运行情感分析

假设我们是一名为新闻公司工作的数据科学家,我们试图找出我们的新闻标题与行业相比有多“积极”。我们先从 UCI 新闻聚合数据集 ( CC0:公共领域)【1】开始,它是 2014 年不同出版物的新闻标题集合。这是一个有趣的数据集,因为它有来自各种出版商的文章,并包含有用的元数据。

下载并清理数据后,我们得到以下结果:

作者图片

我们有 8 列和大约 400k 行。我们将使用“标题”进行实际的情感分析,并按照“出版商”、“类别”和“时间戳”对结果进行分组。

分类标题

通过开源的魔力,我们可以在我们的分析中使用其他人来之不易的知识——在这种情况下,一个来自流行的 NLTK 库的名为 Vader 情绪强度分析器的预训练模型。

为了建立这个模型,作者收集了一个常用词的列表,然后要求一组人类测试人员根据化合价(即积极或消极)和强度(即 T21)对每个词进行评级。正如原文所说:

(在剔除不相关的词之后)这给我们留下了超过 7500 个词汇特征,这些特征具有有效的效价分数,表明了情绪极性(积极/消极),以及从-4 到+4 的情绪强度。比如“还好”这个词的正化合价是 0.9,“好”是 1.9,“很棒”是 3.1,而“可怕”是–2.5,皱眉的表情符号“😦“是–2.2,“烂”和“sux”都是–1.5。

为了对一段文本进行分类,该模型计算每个单词的价分数,应用一些语法规则,例如区分“伟大”和“不伟大”,然后总结结果。

有趣的是,与机器学习方法相比,这种简单的基于词典的方法具有相同或更好的准确性,并且速度更快。让我们看看它是如何工作的!

在这段代码中,我们导入库,对数据集中的每个标题进行分类,然后将结果追加到原始数据帧中。我们增加了 4 个新栏目:

  • pos :正分组件
  • neu :中性分数分量
  • 阴性:负分成分
  • 复合:三个得分成分的总和

作为一项健康检查,让我们用熊猫idxmax来看看文中最积极、中立和消极的标题:

negative = df.iloc[df.neg.idxmax()]
neutral = df.iloc[df.neu.idxmax()]
positive = df.iloc[df.pos.idxmax()]print(f'Most negative: {negative.TITLE} ({negative.PUBLISHER})')
print(f'Most neutral: {neutral.TITLE} ({neutral.PUBLISHER})')
print(f'Most positive: {positive.TITLE} ({positive.PUBLISHER})')

运行该代码会产生以下结果:

Most negative: I hate cancer (Las Vegas Review-Journal \(blog\))
Most neutral: Fed's Charles Plosser sees high bar for change in pace of tapering (Livemint)
Most positive: THANK HEAVENS (Daily Beast)

很公平——“谢天谢地”比“我讨厌癌症”要积极得多!

可视化结果

我们的分数分布是什么样的?让我们使用交互式绘图库 Altair 以几种方式来形象化这一点:

这里我们展示了总体分布的直方图,以及按类别分组的 100%堆积条形图。运行该代码,我们得到以下结果:

作者图片

看起来大多数标题都是中性的,健康类的负面文章比其他类别多。

为了更深入地了解我们的模型如何对文章进行分类,我们可以再创建两个图表,一个显示模型如何对特定标题进行分类的示例,另一个显示我们最大的出版商在一段时间内的平均情绪得分:

这就是 Altair 的声明性语法真正出彩的地方——我们只需更改几个关键字,例如将mark_bar改为mark_point,就会得到完全不同但仍然有意义的结果:

通过创建交互式可视化,您可以让查看者直接浏览数据。如果他们能够深入到原始数据点,他们将更有可能相信你的总体结论。

看一下出版商排行榜,似乎《赫芬顿邮报》一直更消极,而 RTT 更积极。嗯,看起来他们有不同的编辑策略…

创建报告

最后一步是将结果打包成交互式报告。作为数据科学家,我们经常忘记有效地传达我们的结果。我经常犯这样的错误:花几个小时分析数据来回答某人的问题,然后发来一张只有一行解释的图表截图。我的观众不理解结果,可能不会用它们来做决定。

规则 1——永远假设看你作品的人没有背景,需要从头开始理解。花额外的时间和精力写下你工作的背景和含义总是值得的。

在本教程中,我们将使用一个名为 Datapane 的库,从这些交互式可视化中创建一个可共享的报告。为此,我们首先需要在 Datapane 上创建一个帐户,将图表包装在 Datapane 块中,然后上传报告。

我们用 Markdown 格式写下大量的文本来给出上下文,穿插着我们实际的情节和数据。您可以在此处看到嵌入的交互式可视化图表:

这是一份最小的报告,你可以与利益相关者(你的老板,你的母亲等)分享,以显示整个媒体领域的整体情绪。从这里,你可以探索跨时间、行业和出版商的比较,目的是为你的组织如何改进提出建议。

结论

我们可以通过三点来总结我们在本教程中学到的内容:

  1. 使用情感分析从非结构化文本中提取价值
  2. 在像 Altair 这样的交互式库中构建图表,这样你的浏览者可以自己探索数据,强化你的总体结论
  3. 花额外的时间和精力将你的结果写在报告中,并附上背景

现在去抓住他们!

[1]利奇曼,M. (2013 年)。http://archive.ics.uci.edu/ml 的 UCI 机器学习库。加州欧文:加州大学信息与计算机科学学院。

使用 Yelp 评论和 ML 集成方法构建情感分析模型

原文:https://towardsdatascience.com/building-a-sentiment-analysis-model-using-yelp-reviews-and-ml-ensemble-methods-80e45db6d0c7?source=collection_archive---------4-----------------------

三星级评审和四星级评审的实际区别是什么?自然语言处理有答案!

图片由亿万富翁Unsplash 上拍摄

如果你曾经通读过 Yelp 评论,你可能会注意到评论者之间有很多不一致的地方。一些评论说这种食物“改变生活”,但只留下三颗星,而另一些评论说这种食物“还行”,只留下五颗星。五星评估系统是有缺陷的,因为没有一个明确的方法来定义五星和四星。然而,如果我们忽略明星的数量,而是通读实际的评论,我们应该更好地了解 Yelp 评论者实际上在说什么。这听起来像是更多的工作,但是通过使用 Python 的自然语言工具包,我们可以让我们的代码做所有的艰苦工作。

第 1 部分:获取 Yelp 评论

你可以用几种不同的方法来做这件事。

  • 很少有 Kaggle 数据集像这个一样有大量内容,但可能没有最新的评论。
  • 还有一些其他的独立数据集,比如来自拥抱脸的这个。人们使用 Yelp 评论进行分析已经很多年了,有很多这样的资源可以帮助你开始。
  • 在我看来,最好的选择是直接从源头获取评论。Yelp 有一个公共数据集,包含超过 800 万条评论,全部存储在一个 JSON 文件中。你应该能够在一个简单的格式中找到各种各样的评论,旧的和新的。

第二部分:清理和准备情绪分析

作者图片

当处理基于文本的数据时,减少单词和字符的数量是有益的,这样你的代码就不用花几个小时来运行。我们希望这样做的同时仍然保留重要的词,这些词的意思是“好”或“坏”,让我们了解评论者的感受。像‘the’,‘or’和‘is’这样的词,也被称为停用词,并不是很重要。没有理由浪费时间和处理能力去处理这些停用词,所以最好是删除它们。Python 的自然语言工具包使这一过程变得简单:

**from** **nltk.corpus** **import** stopwords
**from** **nltk.tokenize** **import** word_tokenize

example_sent = """This is a sample sentence,
                  showing off the stop words filtration."""

stop_words = set(stopwords.words('english'))

word_tokens = word_tokenize(example_sent)

filtered_sentence = [w **for** w **in** word_tokens **if** **not** w.lower() **in** stop_words]

filtered_sentence = []

**for** w **in** word_tokens:
    **if** w **not** **in** stop_words:
        filtered_sentence.append(w)

print(word_tokens)
print(filtered_sentence)

作者图片

你还会注意到我在一些变量中使用了单词“token”。这意味着我把一个句子分解成一系列单词,这个过程被称为标记化。

图片 bt 作者

你可以在这里看到 Yelp 评论平均有 40-45%的停用词。摆脱他们会节省我们很多时间!

现在我们已经过滤掉了停用词,让我们尝试使用一个叫做词干的过程来简化数据集。词干化是将所有形式的单词还原为基本形式的过程。如果你有“非常”、“最棒”和“更棒”这样的词,这些词都会被简化为“很棒”,以便于分组和处理。Python 的自然语言工具包又一次让这个过程变得非常简单:

**import** **nltk**
**from** **nltk.stem.snowball** **import** SnowballStemmer

snowBallStemmer = SnowballStemmer("english")

sentence = yelp_data_unpacked[40]
wordList = nltk.word_tokenize(sentence)

stemWords = [snowBallStemmer.stem(word) **for** word **in** wordList]

stemmed = ' '.join(stemWords)
print(sentence)
print('')
print(stemmed)

作者图片

看起来变化不大,但是如果我们将这些句子标记化并组合在一起,那么唯一的键值对将会更少。

在项目的这一点上,我们已经清理了数据并准备好进行处理。在我们开始建立分类模型之前,我们必须决定如何对它进行分类。

第 3 部分:分类和超参数

在本文的开头,我说过我想通过分析每个评论中的实际内容来改进 Yelp 的五星评级系统。因此,我不是根据星级将评论分为五组,而是根据情绪将它们分为四组。这些组是“阴性”、“轻微阴性”、“轻微阳性”和“阳性”。为了整理我对训练数据集的评论,我使用了 Textblob 的极性得分作为基线。

**from** **textblob** **import** TextBlobyelp_data_s['Polarity'] =
yelp_data_s['Stemmed'].apply(**lambda** x: TextBlob(x).sentiment[0])sentiment = []
**for** i **in** range(len(yelp_data_s)):
    **if** yelp_data_s['Polarity'][i] >= 0.4:
        sentiment.append('Positive')
    **if** yelp_data_s['Polarity'][i] > 0.2 **and** yelp_data_s['Polarity'][i] < 0.4:
        sentiment.append('Slightly Positive')
    **if** yelp_data_s['Polarity'][i] <= 0.2 **and** yelp_data_s['Polarity'][i] > 0:
        sentiment.append('Slightly Negative')
    **if** yelp_data_s['Polarity'][i] < 0:
        sentiment.append('Negative')yelp_data_s['sentiment'] = sentiment

作者图片

不过,我想不仅仅使用这个分数来构建我们的模型,所以我决定看看其他一些特性。

作者图片

对于第二个图表,我使用这个正面情绪词列表来确定什么是“正面词”。

现在我有了一个好主意,知道在构建模型时应该寻找什么样的特征。实际选择模型之前的最后一步是通过使用术语频率逆文档频率矩阵(TFIDF)来查看每个评论中的内容

简单来说,这是一种在评论中寻找最独特、最有冲击力的词的方法。术语频率只是告诉您该单词出现的频率,但是一旦添加了逆文档频率参数,您还可以分析该单词在整个数据集中出现的频率。分析这些独特的词很重要,因为它们比每个评论者使用的常用词能告诉你更多。

为了创建训练数据集,我将这些列用作我的列:

  • 名字:只是餐馆的名字
  • 评论:Yelp 上写的完整评论
  • Polarity:text blob 极性得分
  • 正面单词 P:正面单词的百分比
  • 情感:指定的情感分数
  • TFIDF:每个唯一的单词是一个列,其频率作为其值列出,在这个数据集中会有很多列(这就是为什么我们首先删除停用词并阻止我们的评论)
**from** **sklearn.feature_extraction.text** **import** TfidfVectorizertext = yelp_data_s['Stemmed:Sentence']
Tvectorizer = TfidfVectorizer()
Tvectorizer.fit(text)
Tvector = Tvectorizer.transform(text)voc = Tvectorizer.vocabulary_
df = pd.DataFrame(Tvector.toarray(),columns=voc)

col_name1 ='Name'
col_name2 = 'Review'
col_name3 = 'Polarity'
col_name4 = 'Sentiment'
col_name5 = 'Positive_Words_P'

col1 = yelp_data_s['Name']
col2 = yelp_data_s['Review']
col3 = yelp_data_s['Polarity']
col4 = yelp_data_s['sentiment']
col5 = yelp_data_s['Positive_Words_P']

df.insert(0,col_name1,col1)
df.insert(1,col_name2,col2)
df.insert(2,col_name3,col3)
df.insert(3,col_name4,col4)
df.insert(4,col_name5,col5)

使用这个训练数据集和一个简单的逻辑回归模型来测试它,我得到了 67%准确率的基线分数。我知道我可以通过调整一些超参数来改善这一点,所以我再次查看了 TFIDF 矩阵。

  • 最小词频:虽然查看真正独特的单词很重要,但它可能有助于过度拟合,以提高我们正在处理的单词的阈值。我测试了同一个模型,但是增加了最小词频的超参数,看看它是如何影响准确度的。

作者图片

作者图片

  • n grams 总数:这基本上告诉我们数据是如何被一个字一个字地处理的。如果您将 ngrams 设置为 1,则单词将会像“this”、“is”、“not”、“lame”等那样逐一处理。如果您将 ngrams 设置为 2,您可以处理单词对,例如“this is”、“is not”、“not lame”。您可能会看到这将如何影响准确性,当 ngrams 设置为 1 时,模型只会看到“蹩脚”并将其作为负值处理,而当 ngrams 设置为 2 时,模型会看到“不蹩脚”并将其作为正值处理。这反映在这张精度图上:

有了这两个超参数,我们将基线准确率提高到了 71%!这可能看起来不多,但当我们开始使用其他模型时,知道我们有最佳的超参数是很重要的。

第四部分:选型

最后,是选择模型的时间。对于这个项目,我想尝试许多不同的分类模型,整个过程如下所示:

  • 选择模型类型
  • 定义一个管道,使用 Gridsearch 找到最佳参数
  • 保存模型,这样我们就不必多次运行它
  • 加载模型并运行准确度和 f1 分数
  • 对其他模型重复该过程

我还想将我的模型选择分成两部分,前四部分将分析数字成分(阳性词百分比、极性得分等)。)并且最后两个将分析 TFIDF 矩阵。以下是每个型号的表现:

  • Logistic 回归: F1 值为 71%,lr__C: 0.1
**from** **sklearn.linear_model** **import** LogisticRegression
**from** **sklearn.model_selection** **import** GridSearchCV
**from** **sklearn.metrics** **import** make_scorer, accuracy_score, f1_score
**from** **sklearn.model_selection** **import** train_test_split
**from** **sklearn.pipeline** **import** Pipeline
**from** **sklearn.preprocessing** **import** StandardScalersteps = [('scaler', StandardScaler()), ('lr', LogisticRegression(solver = 'lbfgs'))] 
pipeline = Pipeline(steps)
parameters = {'lr__C':[0.01, 0.1, 1, 10, 100]}

clf = GridSearchCV(pipeline, parameters, cv = 10, scoring="accuracy") 
clf.fit(X_train, y_train)
clf.best_params_
  • 随机森林: F1 值为 66%,最大特征:“sqrt”,n 估计值:50
**from** **sklearn.ensemble** **import** RandomForestClassifiersteps = [('scaler', StandardScaler()), ('rf', RandomForestClassifier())] 
pipeline = Pipeline(steps)parameters = {'rf__n_estimators':[10 , 20, 30, 40, 50], 'rf__max_features':['auto','sqrt']}
clf = GridSearchCV(pipeline, parameters, cv = 10, scoring="accuracy") 
clf.fit(X_train, y_train)
clf.best_params_
  • 支持向量分类(SVC): F1 得分为 70%,svc__C: 0.01
**from** **sklearn.svm** **import** SVC

steps = [('scaler', StandardScaler()), ('svc', SVC(probability=**False**,kernel='linear',gamma='auto'))] 
pipeline = Pipeline(steps) parameters = {'svc__C':[0.01, 0.1, 1]}
clf = GridSearchCV(pipeline, parameters, cv = 3, scoring="accuracy") 
clf.fit(X_train, y_train)

clf.best_params_
  • 梯度增强分类器: F1 值为 72%,学习率为 0.15,n 估计量为 500
**from** **sklearn.ensemble** **import** GradientBoostingClassifier

steps = [('scaler', StandardScaler()), ('gbc', GradientBoostingClassifier(max_features='sqrt'))] 
pipeline = Pipeline(steps) parameters = {'gbc__n_estimators':[10, 50, 100, 200, 500], 'gbc__learning_rate': [0.05, 0.1, 0.15, 0.2, 0.25]}
clf = GridSearchCV(pipeline, parameters, cv = 10, scoring="accuracy") 
clf.fit(X_train, y_train)

steps = [('scaler', StandardScaler()), ('gbc', GradientBoostingClassifier(learning_rate = 0.15, max_features = 'sqrt', n_estimators = 500))]  clf = Pipeline(steps)  clf.fit(X_train, y_train)
  • 带 TFIDF 的朴素贝叶斯: F1 分数为 64%,alpha: 1,min_df: 10
**from** **sklearn.feature_extraction.text** **import** TfidfVectorizer
**from** **sklearn.naive_bayes** **import** MultinomialNB

steps = [('vec', TfidfVectorizer(stop_words = 'english', ngram_range = (1, 2))), ('nb', MultinomialNB())] 
pipeline = Pipeline(steps) parameters = {'vec__min_df':[0.01, 0.1, 1, 10, 100], 'nb__alpha':[0.01, 0.1, 1, 10, 100]}
clf = GridSearchCV(pipeline, parameters, cv = 10, scoring="accuracy") 
clf.fit(X_train, y_train)

clf.best_params_
  • 【TFIDF 梯度增强分类器: F1 值为 57%,学习率为 0.25
steps = [('vec', TfidfVectorizer(stop_words = 'english', ngram_range = (1, 2))), 
         ('gbc', GradientBoostingClassifier(max_features='sqrt',n_estimators=500))] 
pipeline = Pipeline(steps) parameters = {'gbc__learning_rate': [0.05, 0.1, 0.15, 0.2, 0.25]}
clf = GridSearchCV(pipeline, parameters, cv = 3, scoring="accuracy") 
clf.fit(X_train, y_train)

clf.best_params_

不幸的是,这些模型的分数都在 60-70%之间,不是最好的。有一种方法可以从最好的模型中提取性能并组合它们来改善结果,这就是所谓的集成方法。对于这个项目,我采用了性能最好的基于文本的模型(带 TFIDF 的朴素贝叶斯)及其性能作为性能最好的数值模型(梯度增强分类器)的一个特征。这部分有很多步骤,但代码看起来像这样:

# define train/test split X = yelp_data.Review # word tokens
y = yelp_data.Sentiment # assigned sentiment
indices = yelp_data.index

X_train, X_test, y_train, y_test, i_train, i_test = train_test_split(X, y, indices, train_size = 0.8, random_state = 7)# define Naive Bayes TFIDF modelsteps = [('vec', TfidfVectorizer(ngram_range = (1, 2))), ('nb', MultinomialNB())] 
pipeline = Pipeline(steps)
parameters = {'vec__min_df':10, 'nb__alpha':0.1}
clf = GridSearchCV(pipeline, parameters, cv = 10, scoring="accuracy") 
clf.fit(X_train, y_train)# turn model scores into feature in dataframe (prediction probability)Xtrain_proba = pd.DataFrame(clf.predict_proba(X_train), index = i_train) Xtest_proba = pd.DataFrame(clf.predict_proba(X_test), index = i_test)# define new train/test splitX = yelp_data.iloc[0:,4:] # first four columns are text, review, positive word percentage, and polarity
y = yelp_data.Sentiment # assigned sentiment
indices = yelp_data.index

X_train, X_test, y_train, y_test, itrain, itest = train_test_split(X,y,indices,train_size=0.8,random_state=7)# Adding prediction probabilityXtrain_combined = pd.merge(X_train, Xtrain_proba, left_index=**True**, right_index=**True**) Xtest_combined = pd.merge(X_test, Xtest_proba, left_index=**True**, right_index=**True**)# define Gradient Boosted Classifiersteps = [('scaler', StandardScaler()), ('gbc', GradientBoostingClassifier(max_features='sqrt'))] 
pipeline = Pipeline(steps) parameters = {'gbc__n_estimators':[10, 50, 100, 200, 500], 'gbc__learning_rate': [0.05, 0.1, 0.15, 0.2, 0.25]}
clf = GridSearchCV(pipeline, parameters, cv = 10, scoring="accuracy") 
clf.fit(X_train, y_train)# with best featuressteps = [('scaler', StandardScaler()), ('gbc', GradientBoostingClassifier(learning_rate = 0.2, max_features = 'sqrt', n_estimators = 500))] 
clf = Pipeline(steps) 
clf.fit(X_train, y_train)

最后,通过这种堆叠模式,我们的 F1 得分提高了 92%!为了向您展示这有多准确,让我们来看看原始逻辑回归的混淆矩阵(准确率为 71%):

作者图片

对比我们的堆叠模型的混淆矩阵(准确率 92%):

作者图片

如你所见,集合方法对我们的准确性有巨大的影响。定义所有这些模型并将两者结合在一起可能需要一些额外的时间,但对于 21%的准确性提升,我认为这是值得的。我强烈推荐阅读更多关于集成方法的内容,这对你从事的几乎任何机器学习项目都会很有帮助!

第 5 部分:结果

现在让我们来测试我们的模型。我去 Yelp 上找了一家意大利餐厅的随机三星级评论。三星级的评论并不能真正告诉你评论者的感受,我也不想阅读整个评论,所以我让模型做所有的工作。

作者图片

从这个简单的输出中,我可以更好地了解评论者对这家意大利餐厅的感受。情感下面的单词和数字显示了对分数影响最大的 15 个单词,这些单词通常是独特的,接近于情感单词,如“好”或“坏”。从这个结果,我知道这个评论家有一个稍微正面的体验,扇贝可能真的很好。我也知道这个地方可能有点潮湿,这位评论家被餐厅里的一些东西吓坏了。如果我是这家餐厅的老板,我真的会从中受益,因为我可以看到哪些词有助于积极的评论,哪些词有助于消极的评论。

自然语言处理有着广泛的用途,Yelp 评论只是我们可以用来建立情感分析模型的许多基于文本的数据形式之一。我从构建这个模型中学到了很多,类似这样的东西将是对使用 Python 进行 NLP 的很好的介绍。如果你有兴趣了解更多,我强烈建议你通读科尔·霍华德、汉尼斯·哈普克和霍布森·莱恩所著的《自然语言处理实践》一书。

我希望这个项目演练能启发您创建自己的情感分析模型或研究集成方法!感谢您的阅读!

完整项目:【https://github.com/Bench-amblee/yelp_sentiment_analysis

为我的笔记本电脑服务器构建服务器设置配置

原文:https://towardsdatascience.com/building-a-server-settings-configuration-for-my-notebook-server-b0a7258e50f3?source=collection_archive---------36-----------------------

Jockey.jl

使用 Jockey.jl 创建服务器配置

(图片由 Unsplash 上的openclipbart

介绍

最近,我开始为 Julia 开发一个新的 Julia 包,名为 Jockey.jl. Jockey.jl 将会有很多工作,它由一个通用的、基于 Julia 的虚拟会话服务器组成,该服务器将调用返回到 JavaScript 会话中。这种方法的酷之处在于,它允许我使用一些非常棒的 Julian 方法来处理数据,并使用 JSON 作为这两种方法和接口之间的中间媒介。考虑到这一点,Julia 方面的东西仍然需要各种各样的补充,比如身份验证、基于会话的用户帐户、数据格式化(用于保存和加载文件)。)

为了方便创建这些东西,接下来可能需要创建的一个东西是服务器设置。我们不能忘记这些将在一揽子计划的其余部分发挥多大的作用。然而,在此之前,这个存储库中缺少一样东西,它阻止路由器服务于开发中的登录页面。

资产问题

在我们开始构建这个超级酷的配置文件之前,我需要给 Jockey 环境添加一个新的依赖项和一个图标。出于某种原因,精灵要求我们有一个窗口。ico 文件,所以我将使用 get a .ico 文件并把它粘贴在那里。我认为这是我们需要承认的关于精灵的事情。像这样的事情破坏我们的应用程序是很奇怪的,但是不管有多奇怪——确实是这样。

还有一件事,如果你想在 Github 上查看,你可以在这里:

https://github.com/ChifiSource/Jockey.jl

设置类型

为了创建新的设置,我们要做的第一件事是在一个新的部分中创建新的设置类型。

mutable struct JSettings
  mode::Symbol
  Host::Connection
end
mutable struct HostInfo
  server_port::Int64
  server_host::String
  admin_name::String
  admin_password::String
end

这两种新的类型只是作为包的容器,最终用来操作一切。我将在这篇文章旁边适当地记录所有这些,以便重申这些都做了什么。HostInfo 结构保存服务器的核心信息。请注意,所有这些都是在服务器启动时处理的,而且还保存在默认的配置文件中。

会议

现在,在一个新的会话文件中,我将创建另一个名为 session 的类型:

mutable struct JSession
  ID::Int64
  auth::Int64
  KeyBindings::Dict
  Enabled Extensions::Dict
  username::String
  settings::JSettingsend

现在,我们启动服务器的第一个目标是将所有的服务器参数(定义为关键字参数)组装成适当的类型。我将在主要骑师文件中为这两个人添加必要的内容,

include("ServerController/Session.jl")
include("ServerController/Settings.jl")

现在我们正在使用的下一个方法是 runjy()。这是使用关键字参数来控制服务器核心启动的主函数。让我们看一下相应的 doc-string,每当我们测试这段代码时,我们很快就会在终端中看到它:

"""
Usage Functions
### runjy()
The runjy() server begins a Genie server hosting a new Jockey notebook server.
Ultimately, this is the foundation where one will configure server settings and
decide what sort of system they want to run jockey with. The core server settings
are controllable through the key-word arguments to this function.
##### Key-word arguments
- host = 127.0.0.1
IP address one wishes to host this connection on.
- port = 8000
Port which the server should run on.
- mode = :user
Available mode options are :user, :admin, :headless. Admin mode will grant access
 to a user account system, and Jockey authentication systems. Headless mode will
 begin a worker process, which can be further managed using the management
   interface.
- pwd = 123
Password for use at administrator login screen. **You can ignore this if not in
  admin mode!**
"""

所有这些参数都已经在这个函数中提供了,我们只需要将它们放入相应的类型中,然后在环境中定义这些类型——为返回做好准备。这是我们当前的功能:

function runjy(;port = 8000, host = "127.0.0.1",
  mode = :user,
  pwd = 123,
  admin = "admin")
  JockeyPoll("New Jockey Server starting on port ", port)
  run(`./bin/server`)
end

经过一点修改后,我修改了会话以包含一个完整的标识符类型。

mutable struct JSession
  ID::Identifier
  KeyBindings::Dict
  Enabled Extensions::Dict
  username::String
end
mutable struct Identifier
  id::Int64
  auth::Int64
  username::Int64
  status::Int64
end

回到 runjy()函数,我将添加一些新的调用来构造 HostInfo 和全局设置。

function runjy(;port = 8000, host = "127.0.0.1",
  mode = :user,
  pwd = 123,
  admin = "admin")
  HI = HostInfo(port, host, admin, pwd)
  global jsettings = JSettings(mode, HI)

最后,我们需要创建的最后一个组件是会话。

global jsession = JSession(Id, KB, ext, username)

这些在这个环境中被全局定义是有原因的。

汤姆

现在我们已经有了引入新功能的基本方法,我们将使用 TOML.jl 包创建一些基本的 TOML 配置文件。让我们寻找我们的环境并添加这个包。

(图片由作者提供)

这当然就像用 Pkg REPL 激活骑师环境,然后添加 TOML 一样简单。我们将从这个库中使用的主要函数是 parse。我们首先将数据放入字典,然后输出到一个新的 TOML 文件。这当然会回到 runjy()函数中:

function runjy(;port = 8000, host = "127.0.0.1",
  mode = :user,
  pwd = "123",
  admin = "admin")
  HI = HostInfo(port, host, admin, pwd)
  global settings = JSettings(mode, HI)
  setting_dict = Dict("port" => string(port), "host" => host,
  "admin" => admin, "mode" => string(mode))
  open("config/env/settings.toml", "w") do io
           TOML.print(io, setting_dict)
         endJockeyPoll(string("New Jockey Server starting on port ", port))
  run(`./bin/server`)
end

我们的最后一步是编辑环境源文件,这将允许我们非常容易地从加载的配置中更改 IP。

server_sett = TOML.parsefile("config/env/settings.toml")
port = server_sett["port"]
host = server_sett["host"]
print(string("https://", host, ":", port))

然后我们只需在我们的设置常量中替换它:

const config = Settings(
  server_port                     = parse(Int64, port),
  server_host                     = host,
  log_level                       = Logging.Info,
  log_to_file                     = false,
  server_handle_static_files      = true,
  path_build                      = "build",
  format_julia_builds             = true,
  format_html_output              = true
)

现在,经过一些小的调试和调整,我们有了基本的服务器设置加载器,有了一个可以修改的可保存文件。这些设置中有很多不是针对初始连接的,将会在管理面板中提供。

结论

好消息是设置加载部分现在有了一个基础版,让我们现在回到 REPL 来看看我们的工作。

([@v1](http://twitter.com/v1).6) pkg> activate Jockey
  Activating environment at `~/dev/Jockey/Project.toml`shell> cd Jockey
/home/emmac/dev/Jockeyinclude("src/Jockey.jl")

(图片由作者提供)

现在我们可以完全按照上面说的去做,我也要用

using Jockey

对于最终用户来说,他们不需要采购环境或进行这些种类的包含。他们只需要做

using Jockey

让我们使用 runjy()启动一个服务器。或者,我们可以跑?(runjy)为了了解关于此功能的更多信息:

julia> runjy(port = 8054, admin = "Emmy")
[Jockey]  New Jockey Server starting on port 8054

精灵现在将启动,然后砰!我们有一台服务器在运行!

(图片由作者提供)

现在如果我们去

[http://127.0.0.1:8054/](http://127.0.0.1:8054/)

我们可以看到骑师登陆页面:

(图片由作者提供)

有一个图像丢失,按钮图标不直,因为还有工作要做,但让我们看看设置文件:

admin = "Emmy"
host = "127.0.0.1"
mode = "user"
port = "8054"

现在我们有一个简单的方法来访问服务器配置和其他设置——比如扩展,我们可以将它们加载到一个子目录中。未来将包含会话的第一个实现,并为管理会话创建一个后端。另一个重要部分实际上是为会话创建前端部分。有一些很酷的功能,我肯定希望在这方面增加。

感谢您阅读我的文章,我希望这看我的骑师代码很酷!

使用 Google Cloud Run、Pub/Sub、云存储和 Terraform 构建无服务器、容器化的批量预测模型

原文:https://towardsdatascience.com/building-a-serverless-containerized-batch-prediction-model-using-google-cloud-run-and-terraform-82c97ab17515?source=collection_archive---------11-----------------------

这篇文章的目标是建立一个无服务器的基础设施,用代码管理,以异步方式服务于机器学习模型或任何其他轻量级计算的批量预测:Google Cloud Run 服务将通过 pub/sub 消息主题侦听云存储桶中的新文件,触发计算过程并将结果数据放入另一个桶中。你可以在 GitHub 上找到完整代码。该服务将像以下一样简单:

# upload data
gsutil cp dataset.csv gs://input-bucket/dataset.csv# wait a few seconds.. and download predictions
gsutil cp gs://output-bucket/dataset.csv predictions.csv

架构概述—作者使用 draw.io 制作的图像

正如在上一篇中,我们将利用 Terraform 来管理我们的基础设施,包括 Google Cloud Run、Storage 和 Pub/Sub。此外,我们将使用一个简单的时间序列预测脚本作为例子,我们将实际上在飞行中训练,因为拟合时间很短。一般来说,Cloud Run 并不适合执行长时间运行的任务(由于服务超时,稍后会详细介绍),但非常适合以异步方式运行小脚本。

或者,我们可以从预训练的机器学习模型中计算批量预测,该模型从外部存储中加载或从外部 API 提供,例如对图像或文档进行分类。我们也可以运行一个简单的脚本来生成一些图。

我们将利用以下服务:

  • Google Cloud Run 是一种在无服务器基础设施上运行可调用容器的服务。
  • Google Pub/Sub 是一种异步消息服务,允许消息的发送者和接收者分离。
  • 谷歌云存储是一种存储对象的服务。
  • Terraform 是一款基础设施即代码软件。
  • facebook prophet 是一个时间序列预测包。

先决条件

我们用Terraform v0.14.0gcloud(这里:Google Cloud SDK 319.0.0, alpha 2020.11.13, beta 2020.11.13, bq 2.0.62, core 2020.11.13, gsutil 4.55)。

我们需要向谷歌认证,以建立使用 Terraform 的基础设施。我们将使用交互式工作流程:

gcloud auth application-default login

一旦我们通过认证,我们就可以开始地形化,并使用gsutil与谷歌云存储交互,以测试我们的基础设施。在生产环境中,我们应该为 Terraform 创建一个服务帐户。

创建容器化模型

让我们构建一个非常简单的容器化工作流。我们将使用prophet来生成时间序列预测。正如已经提到的,我们实际上将动态地拟合模型并产生批量预测,而不存储实际的模型。这是可行的,因为模型的拟合时间相当低。或者,我们可以使用一个预先训练好的模型,或者是一个外部服务,或者是从外部存储中提取一个简单的模型工件。当模型训练在计算上很昂贵并且将在其他地方完成时,这尤其有用。

我们的模型由以下文件组成,我们将它们放在app子文件夹中:

  • model.py:实际型号代码,包括 fit 和批量预测。
  • main.py:云运行器处理程序,一个处理请求的 Flask 端点
  • Dockerfile:app 容器的 Dockerfile
  • build.sh:构建容器的简单脚本
  • push.sh:将容器推送到 GCR 的简单脚本

model.py将包含使用fbprophet.Prophet进行拟合和预测的功能:

处理程序main.py将使用Flask处理请求并将其转发给我们的模型:

我们将使用以下python:3.8基本映像将所有这些内容放入 Docker:

FROM python:3.8# Allow statements and log messages to immediately appear in the Cloud Run logs
ENV PYTHONUNBUFFERED TrueCOPY requirements.txt .
RUN pip install -r requirements.txtENV APP_HOME /app
WORKDIR $APP_HOME
COPY model.py main.py ./CMD exec gunicorn --bind :$PORT --workers 1 --threads 1 --timeout 0 main:app

build.sh如下图所示:

#!/bin/bash# if required: gcloud auth configure-docker
docker build -t cloud-runner .

最后的push.sh:

#!/bin/bashdocker tag cloud-runner $IMAGE_URI
docker push $IMAGE_URI

创造我们的基础设施。

我们现在可以规划我们的基础设施。正确组织的 Terraform 代码可以在 GitHub 库中找到。

我们必须规划以下服务:

  • 云运行服务处理来自输入桶的文件
  • 云存储通知监听输入桶中的新文件
  • 云存储通知的发布/订阅主题
  • 向云存储通知主题订阅云运行服务的发布/订阅
  • 云运行要使用的应用程序容器

围绕这一点,我们需要定义一些服务帐户和 IAM。

我们从variables.tf开始:

下面的地形代码将被放入main.tf。我们需要定义provider和项目相关的资源。

此外,GCS 桶:

让我们来看看云运行服务。因为只有当映像在 GCR 上可用时,才能构建云运行服务,所以我们将使用null_resource来构建映像,并使其成为依赖项。

最后是存储通知和发布/订阅基础架构:

我们现在可以使用我们的设置脚本:setup.sh来构建我们的基础设施。这将

  • 构建一次容器,使其在缓存中可用
  • 初始化并应用地形

如果你想先看到计划,运行terraform plan而不是terraform apply

#!/bin/bash# build container once to enable caching
(cd app && 
    ./build.sh)# init and apply terraform
(cd terraform && 
    terraform init && 
    terraform apply)

我们将被提示billing_account_nameuser。或者,我们可以准备一个terraform.tfvars文件,并在那里添加值:

billing_account_name = ...
user                 = ...

在要求我们确认terraform apply之前,我们应该会看到类似下面的输出(被截断):

[+] Building 0.8s (10/10) FINISHED                                                                                                                                                        
 => [internal] load build definition from Dockerfile  
...Terraform has been successfully initialized!
...Plan: 15 to add, 0 to change, 0 to destroy.Changes to Outputs:
  + image_uri     = (known after apply)
  + input_bucket  = "cloud-runner-input-bucket"
  + output_bucket = "cloud-runner-output-bucket"
  + project_id    = (known after apply)
  + service_name  = "cloud-runner-service"Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

创建资源大约需要 3 到 5 分钟,这也取决于可用的上传带宽,因为我们需要将图像上传到注册表。完成后,我们应该会看到以下输出(被截断):

random_id.id: Creating...
random_id.id: Creation complete after 0s [id=zg0]
google_project.project: Creating...
google_project.project: Still creating... [10s elapsed]
google_project.project: Still creating... [20s elapsed]
google_project.project: Still creating... [30s elapsed]
google_project.project: Creation complete after 35s [id=projects/cloud-runner-ce0d]
data.google_storage_project_service_account.gcs_account: Reading.
...google_cloud_run_service_iam_member.iam_member: Creation complete after 16s [id=v1/projects/cloud-runner-ce0d/locations/europe-west3/services/cloud-runner-service/roles/run.invoker/serviceAccount:[cloud-runner-service-account@cloud-runner-ce0d.iam.gserviceaccount.com](mailto:cloud-runner-service-account@cloud-runner-ce0d.iam.gserviceaccount.com)]
google_project_iam_binding.project: Still creating... [10s elapsed]
google_project_iam_binding.project: Still creating... [20s elapsed]
google_project_iam_binding.project: Creation complete after 22s [id=cloud-runner-ce0d/roles/iam.serviceAccountTokenCreator]Apply complete! Resources: 15 added, 0 changed, 0 destroyed.Outputs:image_uri = "gcr.io/cloud-runner-ce0d/cloud-runner:latest"
input_bucket = "cloud-runner-input-bucket"
output_bucket = "cloud-runner-output-bucket"
project_id = "cloud-runner-ce0d"
service_name = "cloud-runner-service"

当我们想要测试我们的服务时,这些输出会很有用。例如,我们可以如下获取输入存储桶名称:terraform output -json | jq -r .input_bucket.value

测试基础设施

由于我们的原型包含 facebook 的 prophet 包的一个非常简单的实现,让我们在一个小数据集上运行一个时间序列预测,这个数据集是 hyndsight 数据集。它包含了从 2014 年 4 月 30 日到 2015 年 4 月 29 日,Rob J. Hyndman 博客的每日浏览量。Rob J. Hyndman 是许多流行的 R 预测包(包括预测)的作者,也是许多书籍和研究论文的作者和预测专家。数据集中的时间序列显示了显著的周模式和上升趋势,我们将在下面看到。

我们可以使用gsutil将测试文件app/data/hyndsight.csv上传到 GCS。我们将从terraform output中获取输入和输出桶名,并使用jq提取它们:

INPUT_BUCKET=$(cd terraform && terraform output -json | jq -r .input_bucket.value)
OUTPUT_BUCKET=$(cd terraform && terraform output -json | jq -r .output_bucket.value)gsutil cp app/data/hyndsight.csv gs://${INPUT_BUCKET}/hyndsight.csv

我们可以使用gsutil -q stat gs://${OUTPUT_BUCKET}/hyndsight.csv来检查文件,它应该在 10 到 20 秒后出现。我们可以在云运行控制台中查看日志:

谷歌云运行日志的用户界面——图片由作者制作

一旦文件在那里,我们就可以得到我们的预测。

gsutil cp gs://${OUTPUT_BUCKET}/hyndsight.csv app/data/hyndsight_forecast.csv

并使用 python 绘制它:

import pandas as pdactual = pd.read_csv("app/data/hyndsight.csv")
forecast = pd.read_csv("app/data/hyndsight_forecast.csv")data = pd.concat([actual, forecast])data.plot(x="date", figsize=(12,5))

hyndsight 时间序列和预测图—图片由作者制作

如果我们多次发送上述请求,我们可以激励 Cloud Run 启动更多实例。

INPUT_BUCKET=$(cd terraform && terraform output -json | jq -r .input_bucket.value)for i in {1..100}
do
    echo "Copying: $i"
    gsutil -q cp gs://${INPUT_BUCKET}/hyndsight gs://${INPUT_BUCKET}/dataset_${i}.csv
done

我们可以检查每秒的请求数、每个请求的延迟(我们模型的运行时间)、实例数:

Google 云运行指标的用户界面—图片由作者完成

此外,我们看到容器的内存使用非常低(对于我们的数据集来说),所以如果我们希望输入数据看起来相似,我们可能会使用较小的实例。

Google 云运行指标的用户界面,第 2 部分——图片由作者完成

更新容器

要用新的最新版本手动更新容器,我们可以使用deploy.sh脚本。我们需要重建和推送映像,更新云运行服务以获取和转移流量。

# get project id, image output and service name from terraform output
PROJECT_ID=$(cd terraform && terraform output -json | jq -r .project_id.value)
IMAGE_URI=$(cd terraform && terraform output -json | jq -r .image_uri.value)
SERVICE_NAME=$(cd terraform && terraform output -json | jq -r .service_name.value)# build and push image
(cd app && 
    ./build.sh && 
    IMAGE_URI=$IMAGE_URI ./push.sh)# update image
gcloud --project $PROJECT_ID \
    run services update $SERVICE_NAME \
    --image $IMAGE_URI \
    --platform managed \
    --region europe-west3# send traffic to latest
gcloud --project $PROJECT_ID \
    run services update-traffic $SERVICE_NAME \
    --platform managed \
    --region europe-west3 \
    --to-latest

破坏基础设施

我们可以使用_destroy.sh来清空桶并摧毁通过地形创造的资源。

# get bucket names from terraform output
INPUT_BUCKET=$(cd terraform && terraform output -json | jq -r .input_bucket.value)
OUTPUT_BUCKET=$(cd terraform && terraform output -json | jq -r .output_bucket.value)gsutil rm "gs://${INPUT_BUCKET}/**"
gsutil rm "gs://${OUTPUT_BUCKET}/**"(cd terraform && 
    terraform state rm "google_project_iam_member.project_owner" &&
    terraform destroy)

我们应该会看到类似下面的输出:

...
google_service_account.service_account: Destruction complete after 1s
google_storage_bucket.storage_output_bucket: Destruction complete after 1s
google_pubsub_topic.pubsub_topic: Destruction complete after 2s
google_project_service.cloud_run_service: Still destroying... [id=cloud-runner-ce0d/run.googleapis.com, 10s elapsed]
google_project_service.cloud_run_service: Destruction complete after 13s
google_project.project: Destroying... [id=projects/cloud-runner-ce0d]
google_project.project: Destruction complete after 3s
random_id.id: Destroying... [id=KM8]
random_id.id: Destruction complete after 0sDestroy complete! Resources: 14 destroyed.

更多备注

谷歌服务有一些限制(截至 2021 年 4 月 24 日)。例如,最大超时为 15 分钟,谷歌发布/订阅的最大确认时间为 10 分钟。这使得它对于更耗时的任务毫无用处。您可以使用更大的资源来加快处理时间,尽管我们可以提供的内存也是有限的。我们的脚本一次只能处理一个请求,因此我们将容器的并发性设置为 1。我们可以通过在容器中使用更多的线程来加速这个过程,并允许一些并行化。

在任何情况下,Cloud Run 通过使用多个容器来本机处理多个请求。并行云运行容器的最大数量也是可配置的,默认设置为 1000(!).

我们应该上传某种包含标识符的清单,输入数据的路径,输出数据的预期路径,而不是直接上传数据到存储桶。这将使集成到其他服务变得更加容易。此外,我们还可以向模型传递参数。确保总是使用两个不同的桶进行输入和输出,否则当输出文件存储在输入桶中时会出现连续的循环。

此外,这个项目的一些方面是以非常天真的方式设计的,需要在生产环境中重新审视:云运行映像的版本控制,其中应该使用正确的版本标签。云运行有一个将流量转移到不同版本的机制。

最后,您必须考虑这种设置的成本。上述设置和少量测试运行在自由层内(截至 2021 年 4 月 24 日)。成本与始终可用的最小容器数量、容器资源、请求数量和每个请求的运行时间成比例。你可以使用成本计算器来估算预期成本。如果你要求集装箱一直在那里,或者需要更多的资源,成本就会大幅上升。

结论

将无服务器架构与 Terraform 结合使用,我们可以生成简单的端到端机器学习服务,同时通过代码保持对基础架构的可见性和控制。就个人而言,与使用云控制台和 ui 相比,我更喜欢用代码管理基础设施。在过去,这经常是我使用无服务器基础设施的一个障碍,因为 Terraform 模块经常落后。

如果你使用 Cloud Run,你会得到一些必须的和现成的特性:请求和资源的监控、日志、升级。使用发布/订阅将确保正确处理重试和死信。在需要更通用的设置的情况下,例如没有发布/订阅集成,可以考虑云函数而不是云运行,因为它们在调用部分允许更大的灵活性。

容器化允许我们隔离机器学习代码,并在需要时适当地维护包的依赖性。如果我们将处理程序代码保持在最少,我们就可以仔细测试映像,并确保我们的开发环境非常接近生产基础设施。与此同时,我们并不局限于谷歌技术;理论上,我们可以使用任何其他队列或消息系统,将处理程序部署到我们自己的基础设施中。

然而,我们不能掩盖这样一个事实,我们正在使用专有软件,它满足一些一般的需求,而不是我们的确切用例的需求。我们只能配置服务允许我们做的事情,在我们的情况下,我们不得不接受云运行和发布/订阅的一些限制,例如关于超时、最大运行时间和资源。

最初发表于【https://blog.telsemeyer.com】

使用 AWS Lambda & API Gateway 和 Terraform 构建无服务器、容器化的机器学习模型 API

原文:https://towardsdatascience.com/building-a-serverless-containerized-machine-learning-model-api-using-aws-lambda-api-gateway-and-a73a091ff82e?source=collection_archive---------31-----------------------

Dockerized Lambdas

这篇文章的目标是建立一个无服务器的基础设施,用代码管理,通过 Rest API 提供容器化的机器学习模型的预测,简单如:

$ curl \
$  -X POST \
$  --header "Content-Type: application/json" \
$  --data '{"sepal_length": 5.9, "sepal_width": 3, "petal_length": 5.1, "petal_width": 1.8}' \
$  [https://my-api.execute-api.eu-central-1.amazonaws.com/predict/](https://my-endpoint-id.execute-api.eu-central-1.amazonaws.com/predict/){"prediction": {"label": "virginica", "probability": 0.9997}}

我们将利用 Terraform 来管理我们的基础设施,包括 AWS ECR、S3、Lambda 和 API Gateway。我们将利用 AWS Lambda 来运行模型代码,实际上是在一个容器中,这是一个非常新的特性。我们将使用 AWS API Gateway 通过 Rest API 为模型提供服务。模型人工制品本身将生活在 S3。你可以在这里找到完整的代码。

架构图——作者使用 draw.io 绘制的图像

先决条件

我们用Terraform v0.14.0aws-cli/1.18.206 Python/3.7.9 Darwin/19.6.0 botocore/1.19.46

我们需要向 AWS 认证,以:

  • 使用 Terraform 设置基础设施。
  • 训练模型并在 S3 存储生成的模型工件
  • 使用 AWS CLI 测试基础设施(此处: )

可以使用名为lambda-model的配置文件在凭证文件~/.aws/credentials中设置 AWS 凭证:

[lambda-model]
aws_access_key_id=...
aws_secret_access_key=...
region=eu-central-1

这将允许我们告诉 Terraform 以及 AWS CLI 使用哪个凭证。Lambda 函数本身将使用角色进行身份验证,因此不需要显式凭证。

此外,我们需要定义区域、桶名和一些其他变量,这些也在 Terraform 变量中定义,我们将在后面看到:

export AWS_REGION=$(aws --profile lambda-model configure get region)
export BUCKET_NAME="my-lambda-model-bucket"
export LAMBDA_FUNCTION_NAME="my-lambda-model-function"
export API_NAME="my-lambda-model-api"
export IMAGE_NAME="my-lambda-model"
export IMAGE_TAG="latest"

创建容器化模型

让我们在iris数据集上构建一个非常简单的容器化模型。我们将定义:

  • model.py:实际型号代码
  • utils.py:实用功能
  • train.py:触发模型训练的脚本
  • test.py:生成预测的脚本(用于测试目的)
  • app.py:Lambda 处理器

为了存储模型工件并为模型训练加载数据,我们将定义几个助手函数来与 S3 通信,并从一个utils.py内的公共端点加载带有训练数据的文件:

此外,我们的模型需要一个包装类:

  • 用外部数据训练它
  • 保持状态并保存和加载模型工件
  • 传递有效负载以进行推理

这将在model.py中定义:

为了在没有实际 Lambda 基础设施的情况下进行训练和预测,我们还将设置两个脚本,一个train.py和一个predict.py。训练脚本可以非常简单,我们也可以将其他数据源传递给train方法。

from model import ModelWrapper model_wrapper = ModelWrapper() 
model_wrapper.train()

一个简单的predict.py将预测打印到控制台:

import json
import sysfrom model import ModelWrapper model_wrapper = ModelWrapper()
model_wrapper.load_model()data = json.loads(sys.argv[1])
print(f"Data: {data}")prediction = model_wrapper.predict(data=data)
print(f"Prediction: {prediction}")

最后,我们需要处理程序将数据传递给模型包装器。这就是 Lambda 函数将调用的内容。我们将保持它非常简洁,处理程序将简单地将请求传递给包装器,并将返回的预测转换成 API 网关期望的输出格式:

我们将把所有这些放入 Docker(更确切地说是一个Dockerfile)中,并使用 AWS Lambda 基础映像:

FROM public.ecr.aws/lambda/python:3.8COPY requirements.txt .
RUN pip install -r requirements.txtCOPY app.py utils.py model.py train.py predict.py ./CMD ["app.handler"]

创建 ECR 和 S3 资源

现在让我们通过 Terraform 定义 ECR 存储库和 S3 存储桶。正确组织的 Terraform 代码可以在 GitHub repo 中找到。

我们将一些配置(variableslocals)和 AWS 定义为provider。或者,变量也可以从环境中加载。

此外,S3 和 ECR 知识库:

让我们创建我们的 S3 存储桶和 ECR 存储库:

(cd terraform &&  \
  terraform apply \
  -target=aws_ecr_repository.lambda_model_repository \
  -target=aws_s3_bucket.lambda_model_bucket)

建立和推广 docker 形象

我们现在可以构建 docker 映像并将其推送到 repo(或者,这可以在 Terraform 中的null_resource provisioner中完成)。我们导出注册表 ID 来构建我们想要推送图像的图像 URI:

export REGISTRY_ID=$(aws ecr \
  --profile lambda-model \
  describe-repositories \
  --query 'repositories[?repositoryName == `'$IMAGE_NAME'`].registryId' \
  --output text)
export IMAGE_URI=${REGISTRY_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${IMAGE_NAME}# ecr login
$(aws --profile lambda-model \
  ecr get-login \
  --region $AWS_REGION \
  --registry-ids $REGISTRY_ID \
  --no-include-email)

现在,构建和推动就像:

(cd app && \
  docker build -t $IMAGE_URI . && \
  docker push $IMAGE_URI:$IMAGE_TAG)

训练模型

现在让我们使用新创建的 docker 容器的train.py入口点来训练我们的模型:

docker run \
  -v ~/.aws:/root/.aws \
  -e AWS_PROFILE=lambda-model \
  -e BUCKET_NAME=$BUCKET_NAME \
  --entrypoint=python \
  $IMAGE_URI:$IMAGE_TAG \
  train.py
# Loading data.
# Creating model.
# Fitting model with 150 datapoints.
# Saving model.

测试模型

使用predict.py入口点,我们还可以用一些数据对其进行测试:

docker run \
  -v ~/.aws:/root/.aws \
  -e AWS_PROFILE=lambda-model \
  -e BUCKET_NAME=$BUCKET_NAME \
  --entrypoint=python \
  $IMAGE_URI:$IMAGE_TAG \
  predict.py \
  '{"sepal_length": 5.1, "sepal_width": 3.5, "petal_length": 1.4, "petal_width": 0.2}'
# Loading model.
# Data: {'sepal_length': 5.1, 'sepal_width': 3.5, 'petal_length': 1.4, 'petal_width': 0.2}
# Prediction: ('setosa', 0.9999555689374946)

使用 Terraform 规划我们的主要基础设施

我们现在可以计划基础设施的推理部分,即λ&API 网关设置:

  • Lambda 函数,包括访问 S3 和生成日志的角色和策略,
  • API 网关,包括必要的权限和设置。

我们现在可以再次使用 Terraform CLI 应用它,这大约需要一分钟。

(cd terraform && terraform apply)

测试基础设施

为了测试 Lambda 函数,我们可以使用 AWS CLI 调用它,并将响应存储到response.json:

aws --profile lambda-model \
  lambda \
  invoke \
  --function-name $LAMBDA_FUNCTION_NAME \
  --payload '{"body": {"sepal_length": 5.9, "sepal_width": 3, "petal_length": 5.1, "petal_width": 1.8}}' \
  response.json
# {
#     "StatusCode": 200,
#     "ExecutedVersion": "$LATEST"
# }

response.json将看起来像这样:

{
    "statusCode": 200,
    "body": "{\"prediction\": {\"label\": \"virginica\", \"probability\": 0.9997}}",
    "isBase64Encoded": false
}

我们也可以使用curl或 python 来测试我们的 API。我们需要首先找到我们的端点 URL,例如再次使用 AWS CLI 或 Terraform 输出。

export ENDPOINT_ID=$(aws \
  --profile lambda-model \
  apigateway \
  get-rest-apis \
  --query 'items[?name == `'$API_NAME'`].id' \
  --output text)
export ENDPOINT_URL=[https://${ENDPOINT_ID}.execute-api.${AWS_REGION}.amazonaws.com/predict](https://${ENDPOINT_ID}.execute-api.${AWS_REGION}.amazonaws.com/predict)curl \
  -X POST \
  --header "Content-Type: application/json" \
  --data '{"sepal_length": 5.9, "sepal_width": 3, "petal_length": 5.1, "petal_width": 1.8}' \
  $ENDPOINT_URL
# {"prediction": {"label": "virginica", "probability": 0.9997}}

或者,我们可以用 python 发送 POST 请求:

import requests
import os endpoint_url = os.environ['ENDPOINT_URL']
data = {"sepal_length": 5.9, "sepal_width": 3, "petal_length": 5.1, "petal_width": 1.8}req = requests.post(endpoint_url, json=data)
req.json()

更多备注

要更新容器映像,我们可以再次使用 CLI:

aws --profile lambda-model \
  lambda \
  update-function-code \
  --function-name $LAMBDA_FUNCTION_NAME \
  --image-uri $IMAGE_URI:$IMAGE_TAG

如果我们想要移除我们的基础架构,我们必须先清空我们的存储桶,之后我们可以销毁我们的资源:

aws s3 --profile lambda-model rm s3://${BUCKET_NAME}/model.pkl
(cd terraform && terraform destroy)

结论

有了容器化 Lambdas 的新功能,将机器学习模型部署到 AWS 无服务器领域变得更加容易。有许多 AWS 替代品(ECS、Fargate、Sagemaker),但是 Lambda 提供了许多现成的工具,例如基于请求的日志记录和监控,并且它允许轻松地进行快速原型开发。然而,它也有一些缺点,例如请求延迟开销和使用不完全可定制的专有云服务。

另一个好处是,容器化允许我们隔离机器学习代码,并适当地维护包的依赖性。如果我们将处理程序代码保持在最低限度,我们就可以仔细测试映像,并确保我们的开发环境非常接近生产基础设施。同时,我们不会被 AWS 技术所束缚——我们可以非常容易地用我们自己的 web 框架替换处理程序,并将其部署到 Kubernetes。

最后,我们可以通过远程运行培训(例如使用 ECS)、添加版本控制和 CloudWatch 警报来改进我们的模型基础设施。如果需要,我们可以添加一个过程来保持 Lambda 的温度,因为冷启动需要几秒钟。我们还应该向端点添加身份验证。

原载于https://blog.telsemeyer.com/2021/01/10/building-a-serverless-containerized-machine-learning-model-api-using-terraform-aws-lambda-api-gateway-and/

用 SAYN 构建简单的 ETL

原文:https://towardsdatascience.com/building-a-simple-etl-with-sayn-e08c415b5ea0?source=collection_archive---------25-----------------------

通过一个简单的将笑话翻译成 Yodish 的 ETL 示例来了解 SAYN。

几个月前,我写了一篇文章来介绍 SAYN——我们的开源数据处理框架,针对简单性和灵活性进行了调整。在这篇文章中,我想让你更深入地了解一下 SAYN 是如何工作的,我们目前如何在 ETL / ELT 过程中使用它,以及它的好处。此外,我们将通过一个示例 SAYN 项目来模拟 ETL 过程,并在这个过程中学习一点 Yodish(Yoda 的语言)!

SAYN:ETL 过程的简单性和灵活性

我们创建 SAYN 是因为现有解决方案面临以下挑战:

  • 轻量级设置(如缝合+ DBT)让您快速入门。然而,它们缺乏 Python 支持,如果您需要的比第三方提取器所能提供的更多(例如,缺少数据源),或者如果您想要集成数据科学模型,这可能会成为问题。
  • 更高级的设置(例如气流)为您提供了充分的灵活性,但是设置和维护所需的技术专业知识(由于需要大量的服务)对于没有很多数据工程师的团队来说是一个挑战。

这形成了 SAYN 设计的理念:易于部署、运行和维护,同时支持分析流程的充分灵活性。并进一步转化为以下核心特征:

  • SAYN 有向无环图(DAG)是在 YAML 编写的,使分析团队的任何成员都可以轻松地为管道做出贡献——无论他们是否知道 Python。
  • 通过使用 Jinja 模板和参数,YAML 任务定义和任务代码都可以变成动态的。
  • 所有 SAYN 任务都通过sayn run命令执行。这意味着部署可以简单地通过服务器上的单个 cron 作业(例如 EC2)或使用无服务器选项(例如 GCP 云运行)来完成。因此,您可以在几分钟内部署 SAYN,因为您不需要设置和维护大量的服务!
  • 现成的 SQL 转换任务,以便您可以轻松地将其添加到第三方提取工具之上。
  • Python 任务,这意味着您可以在必要时轻松高效地将自定义摘要和/或数据科学模型集成到您的工作流中。
  • 自动将数据从数据库复制到您的仓库。
  • 还有更多的来了!

我们已经在超过数百个任务的多个 ETL 上使用了 SAYN,效果非常好!由于其特性,它使您能够在构建分析工作流时选择最佳选项,同时保持整体基础架构的维护极其简单。下图显示了我们如何部署 SAYN 基础设施:

使用 SAYN 部署分析基础架构

现在你已经对 SAYN 有了一个很好的概述,让我们来看一个用 SAYN 构建的非常简单的 ETL,这样你就可以感受一下这个框架是如何工作的。

使用 SAYN 的简单 ETL

我们将通过一个简单的 ETL 项目引导您使用 SAYN。你可以在 Github 这里找到这个项目,并使用命令下载它:

**git clone https://github.com/173TECH/sayn_project_example_simple_etl.git**

这个项目实现的 ETL 操作如下:

  1. 从一个 API 收集笑话,然后用另一个 API 翻译成 Yodish。
  2. 在这些原始数据上创建一些数据模型(SQL 转换)。

这两个 API 都是免费的,不需要 API 密钥,所以您可以直接运行项目。但是,每个 API 都有配额(Yoda translation API 限制在每小时 5 次调用),所以您应该避免每小时多次运行提取任务。在运行项目之前,您应该:

  • settings_sample.yaml 文件重命名为 settings.yaml
  • 从项目文件夹的根目录安装它的依赖项(saynrequests包)和pip install -r requirements.txt

项目结构概述

SAYN 项目由以下部分组成:

  • project.yaml:定义 SAYN 项目。它由项目的所有合作者共享
  • settings.yaml:定义个人用户的设置。它对于每个协作者来说都是唯一的,并且永远不应该被推送到 git,因为它将包含凭证。
  • 任务:存储任务文件的文件夹。每个文件被视为一个任务组。
  • python:存储 python 任务脚本的文件夹。
  • sql:存储 sql 和 autosql 任务的 SQL 文件的文件夹。
  • logs:写入 SAYN 日志的文件夹。
  • compile:存储已编译的 SQL 查询的文件夹。在执行之前,SAYN 使用 Jinja 根据项目和设置中定义的参数值编译 SQL 查询。

为了简单起见,我们在这个项目中使用一个 SQLite 数据库。您可以使用 DB Browser for SQLite 来轻松查看创建的表格内容。

该项目由三项任务组成:

  • 用于数据提取和加载的 Python 任务。
  • 计算笑话统计数据的 Autosql 任务。
  • Autosql 任务来比较笑话的长度。

你可以简单地从项目的根目录用命令sayn run运行项目(更多关于所有可用命令的细节在这里)。执行此操作时,您应该会看到以下情况:

示例 SAYN 运行

接下来的部分将一步一步解释当你这样做的时候会发生什么。

数据提取(python 任务)

我们流程的第一步是数据提取和加载。这是由名为extract _ 笑话 _ 翻译的 Python 任务完成的。

这个任务在我们的 base.yaml 任务文件中定义如下:

extract_jokes_translated:
      type: python
      class: extract_jokes_translated.ExtractJokesTranslated
      # those parameters will be accessible in the task
      parameters:
        n_jokes: 5
        translation_type: yoda
      tags:
        - extract

任务执行的代码在python/extract _ 笑话 _translated.py 文件中定义:

# list of free apis
    # https://apipheny.io/free-api/
    import requests
    import json
    import time

    from sayn import PythonTask

    class ExtractJokesTranslated(PythonTask):
        def setup(self):
            self.dst_table = self.parameters["user_prefix"] + "logs_jokes_translated"
            self.n_jokes = self.parameters["n_jokes"]
            self.translation_type = self.parameters["translation_type"]
            self.table_full_refresh = self.run_arguments["full_load"]

            self.url_joke = "https://official-joke-api.appspot.com/random_joke"
            self.url_translation = f"https://api.funtranslations.com/translate/{self.translation_type}.json"

            return self.success()

        def run(self):
            jokes = []

            # get jokes
            self.debug(f"Extracting {str(self.n_jokes)} jokes.")
            for i in range(self.n_jokes):
                r = requests.get(self.url_joke)

                if r.status_code != 200:
                    self.debug("Request not successful!")
                    continue

                content = json.loads(r.content.decode("utf-8"))
                # self.debug(content)

                joke = {
                    "id": content["id"],
                    "type": content["type"],
                    "text": content["setup"] + " | " + content["punchline"]
                }

                jokes.append(joke)

            # get joke translations
            # ATTENTION: the translation API has very low levels of free requests (~5 per hour)
            # re-running the task multiple times might not return the translations and load those as null
            self.debug(f"Translating {len(jokes)} jokes.")
            for j in jokes:
                r = requests.post(self.url_translation, data={"text": j["text"]})

                if r.status_code != 200:
                    self.debug("Request not successful!")
                    continue

                content = json.loads(r.content.decode("utf-8"))
                # self.debug(content)

                j.update({
                    "text_translated": content["contents"]["translated"],
                    "translation_type": self.translation_type
                })

            # load data to database
            self.debug(f"Loading {len(jokes)} jokes translated to DB.")
            db = self.default_db
            db.load_data(self.dst_table, jokes, replace=self.table_full_refresh)

            return self.success()

以下是 Python 任务如何与 SAYN 一起工作:

  • 任务在 YAML 中用类型 python 定义,然后指定需要运行的类。
  • 类本身是在 python 文件夹中的extract _ 笑话 _translated.py 文件中定义的。该类继承自 sayn。PythonTask 对象。该类应该定义一个运行方法(也可以定义一个设置方法,尽管这不是强制性的)。运行和设置(如果已定义)方法需要返回一个状态: self.success()self.fail()
  • 在任务 YAML 定义中,我们定义了一些参数,使我们能够使代码动态化;这些参数通过自身参数在设置阶段使用。
  • 此外,我们还在项目上定义了一个 user_prefix 参数。这首先在 project.yaml (项目的默认值)中定义,然后在 settings.yaml 中默认使用的 dev 配置文件中覆盖。这个参数允许我们在测试期间避免来自多个项目用户的表冲突。虽然在这个项目中没有实现,但是参数也可以用来轻松地区分开发和生产环境(例如,通过基于执行时使用的概要文件分配不同的模式值)。
  • 最后,我们使用 PythonTask 对象的 run_arguments 属性的 full_refresh 值来控制任务是否应该强制表的完全刷新。除非将 -f 标志添加到命令中,否则这将评估为假。

数据建模(autosql 任务)

我们流程的第二步是加载数据的建模。这是通过两个 autosql 任务完成的。这些任务通过将 SELECT 语句转换为表或视图来自动化转换过程。

f _ 笑话 _ 统计

该任务在 base.yaml 中定义如下:

f_jokes_stats:
       type: autosql
       file_name: f_jokes_stats.sql
       materialisation: table
       destination:
         table: "{{user_prefix}}f_jokes_stats"
       parents:
         - extract_jokes_translated
       tags:
         - models

这是定义 autosql 任务的最“冗长”的方式。下一个例子展示了如何显著减少这种情况。该任务执行以下 SQL 代码:

SELECT j.id AS joke_id
         , j.type AS joke_type
         , j.text
         , j.text_translated
         , j.translation_type
         , LENGTH(j.text) AS text_length
         , LENGTH(j.text_translated) AS text_translated_length
         , CASE WHEN LENGTH(j.text_translated) > LENGTH(j.text) THEN 1 ELSE 0 END flag_text_translated_length_longerFROM {{user_prefix}}logs_jokes_translated j

下面是 autosql 任务如何与 SAYN 一起工作:

  • 该任务在 YAML 被定义为类型 autosql
  • 它需要指定以下属性:文件名、物化(表、视图或增量)和目的地。
  • 在这个例子中,我们利用了 user_prefix 参数来使表名动态化。
  • 我们定义任务的父子关系。在这种情况下,任务依赖于提取任务extract _ 笑话 _ 翻译的完成。
  • 我们还将标签 models 添加到这个任务中,这样我们就可以在需要的时候使用 sayn run -t tag:models 命令来执行所有的模型。
  • 该任务指向 sql 文件夹中的f _ 笑话 _ 统计数据. sql 文件。

f _ 笑话 _ 长度 _ 比较

该任务在 base.yaml 中定义如下:

f_jokes_length_comparison:
      preset: models
      parents:
        - f_jokes_stats

为了这个任务。我们利用 SAYN 的预置特性,这使我们能够定义共享相似配置的多个任务(这个概念类似于继承)。型号预置在 base.yaml 中定义如下:

presets:
      models:
        type: autosql
        file_name: "{{task.name}}.sql"
        materialisation: table
        destination:
          table: "{{user_prefix}}{{task.name}}"
        tags:
          - models

因此,该任务将预置型号的所有属性。我们只需要直接在任务上定义一个父级。

运行项目

您可以使用命令 sayn run 运行项目。这将在 SQLite 数据库中创建三个表(每个任务一个表):

  • Python 任务创建的表包含我们的日志(和 Yodish 翻译!).
  • 由任务f _ skins _ stats创建的表对数据进行建模,并添加一些关于笑话在每种语言中的字符长度的统计数据。
  • f _ skins _ length _ comparison创建的表格给出了每种笑话类型中,翻译笑话比英语笑话长的次数比例。看来 Yodish 普遍比英语长!(尽管这可能会根据您从随机笑话 API 中获取的数据而改变)。

一旦您运行了一次项目,使用 sayn run -x tag:extract 命令来避免重新运行提取任务(因为使用的两个 API 都有配额)。

了解更多

那都是乡亲们!本文向您快速介绍了 SAYN 项目是如何工作的。您可以在我们的文档中找到关于 SAYN 的更多详细信息,包括:

  • SAYN 的核心概念和其他可用任务的细节(包括我们在这里没有涉及的复制任务)。
  • 更多充实的教程将让你更深入地了解 SAYN 的所有核心概念。

如果您对 SAYN 或整个项目有任何具体问题,您可以通过 sayn@173tech.com联系我们。快点说!

— — — —

这个故事最初发表于:https://www.173tech.com/insights/sayn-simple-etl-example/

用 Arduino 和 Python 构建声纳传感器阵列

原文:https://towardsdatascience.com/building-a-sonar-sensor-array-with-arduino-and-python-c5b4cf30b945?source=collection_archive---------3-----------------------

实践教程

使用多个低成本超声波传感器估计固体物体的距离和位置。

基于广泛供应的 HC-SR04 传感器的传感器阵列。作者照片

在这篇文章中,我们将从零开始建立一个基于廉价和流行的 HC-SR04 传感器的声纳阵列。我们将使用 Arduino 微控制器来驱动和读取传感器,并使用串行通信与主机通信。这是整个项目的工作代码,不过我建议你按照文章中的步骤来理解它是如何工作的,并根据你的需要进行定制。

HC-SR04 是一款非常受欢迎的超声波传感器,通常用于业余爱好电子产品,构建用于避障或物体检测的廉价距离传感器。它有一个超声波发射器和接收器,用于测量超声波信号在固体物体上反弹的飞行时间。

声纳原理。图片由【Schorsch 博士

如果在 20 摄氏度的室温下,声速大约为 343 米/秒。到物体的距离是超声波从发射器到接收器所需时间的一半:

距离= 343 /(时间/2)

然而,HC-SR04 传感器非常不准确,会给你一个非常粗略和嘈杂的距离估计。温度和湿度等环境因素会影响超声波的速度,固体物体的材料和入射角也会影响距离估计。我们稍后会了解到,有一些方法可以提高原始读数,但一般来说,超声波传感器只能作为避免近距离碰撞或探测低距离分辨率固体物体的最后手段。但是它们不是好的导航或距离估计传感器。为此,我们可以使用更昂贵的传感器,如激光雷达或激光测距仪。

我想用这个声纳阵列来探测我的 Raspberry Pi 机器人 Rover4Wd 前方附近的障碍物(这个项目会在另一篇文章中介绍)。传感器的有效探测角度约为 15 度,因此为了覆盖机器人前方的更大区域,我想使用总共 5 个弧形传感器:

安装在机器人 Rover4WD 前面的声纳阵列。作者图片

这种设置的好处是,我们不仅可以估计机器人前方障碍物的距离,还可以估计物体相对于机器人的位置(大致)。

HC-SR04 传感器只有四个引脚。两个为接地和+5v、 触发 引脚。要使用传感器,我们需要使用 触发器 引脚触发信号,并测量时间,直到通过 Echo 引脚接收到信号。由于我们不同时使用 Echo 和 Trigger 引脚,它们可以共享同一根电缆来连接 Arduino 数字引脚。

对于这个项目,我们将使用一个 Arduino Nano,它很小,很容易买到。还有很多非官方兼容的克隆产品,每台不到 3 美元。

声纳阵列的试验板设置。作者图片

对于这个试验板设置,我们已经将 TrigEcho 引脚连接到 Arduino 中的一个数字引脚。我们将使用 D12、D11、D10、D9 和 D8 引脚来发送和接收信号。这种硬件设置仅受微控制器可用数字引脚的限制,但可以使用多路复用进一步扩展,其中一个引脚可以由多个传感器共享,但一次只能由一个传感器共享。

传统上,这将是我们需要设法逐个轮询传感器的顺序工作流:

  1. 触发一个传感器
  2. 收到回声
  3. 使用之前步骤的持续时间计算距离
  4. 使用串行端口进行测量通信
  5. 处理下一个传感器

然而,我们将使用一个现成的 Arduino 库,名为 NewPing ,它允许您 Ping 多个传感器,从而最小化传感器之间的延迟。这将有助于我们在同一时间(几乎)每秒几次测量所有 5 个传感器的距离。最终的工作流如下所示:

  1. 异步触发和回应所有传感器(但按顺序)
  2. 当传感器完成计算距离时
  3. 当所有传感器完成当前周期时,使用串行端口传送所有传感器的读数
  4. 开始新的传感器读取周期

实现非常简单,并在代码中进行了大量注释。随意看看这里的完整代码。

当所有传感器完成距离测量后,我想特别关注串行通信部分:

void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.

  for (uint8_t i = 0; i < SONAR_NUM; i++) {

     // Sending bytes
        byte reading_high = highByte(cm[i]);
        byte reading_low = lowByte(cm[i]);
        byte packet[]={0x59,0x59,i,reading_high,reading_low};
        Serial.write(packet, sizeof(packet));
  }

}

最初我想通过串行使用字符串发送传感器读数,但是我意识到在项目的主机端消息会很大,很难解析。为了提高速度和降低读取延迟,我决定切换到一个简单的格式,使用一个 5 字节的消息:

字节 1: 字符' Y'
字节 2: 字符' Y'
字节 3: 传感器索引[0–255]
字节 4: 测量距离的高位字节(作为无符号整数)
字节 5: 测量距离的低位字节(作为无符号整数)

字节 1 和 2 只是消息头,决定当我们读取输入的串行字节时,新消息从哪里开始。这种方法与 TF-Luna 激光雷达传感器与主机通信的方式非常相似。

在主机端,我们将使用 Python 3 通过串行端口连接到 Arduino 微控制器,并尽可能快地读取传入的字节。理想的设置是在主机中使用 UART 端口,但只有串行 USB 可以完成这项工作。Python 脚本的完整代码是这里是

有几件有趣的事情需要注意,首先,我们需要在不同的线程上读取序列,这样我们就不会在处理传感器读数或做不同事情时错过任何传入的消息:

def read_serial(serial, sensors): while True:

        # Read by bytes
        counter = serial.in_waiting  # count the number of bytes of the serial port
        bytes_to_read = 5
        if counter > bytes_to_read - 1:
            bytes_serial = serial.read(bytes_to_read)
            # ser.reset_input_buffer()  # reset buffer

            sensor_index, sensor_reading = read_sensor_package(bytes_serial)

            if sensor_index >= 0:
                if sensor_index not in sensors:
                    sensors[sensor_index] = SMA(2)
                if sensor_reading > 0:
                    sensors[sensor_index].append(sensor_reading)

其次,我们需要找到标题为“YY”的消息的开头,以开始读取传感器。由于 Arduino 控制器不会等待主机连接到串行端口,我们可能会连接并读取将被丢弃的部分消息。可能还需要一两秒钟才能与微控制器信息同步。

第三,我们用简单的移动平均来平滑测量结果,以避免一些噪声。在这种情况下,我们只使用两次测量的窗口,因为我们需要快速更新距离,以避免机器人 Rover4WD 撞到近距离障碍物。但是你可以根据你的需要把它调整到一个更大的窗口。较大的窗户更干净,但更换速度慢,较小的窗户更吵,但更换速度快。

下一步是什么?该项目已准备好集成到机器人/电子项目中。在我的例子中,我使用 Ubuntu 20.10 和 Raspberry Pi 4 中的 ROS2 来控制我的机器人 Rover4WD。对我来说,下一步将是构建一个 ROS 包,将测量结果处理为检测到的障碍物,并发布转换消息,这些消息将通过传感器融合整合到更大的导航框架中。

一如既往地让我知道你是否有任何问题或意见,以提高这篇文章的质量。谢谢你,继续享受你的项目!

构建空间模型对全球城市化水平进行分类

原文:https://towardsdatascience.com/building-a-spatial-model-to-classify-global-urbanity-levels-e2fb9da7252?source=collection_archive---------36-----------------------

作者图片

私营和公共部门的决策者正试图理解我们对城市地区的快速变化的使用。我们购物和旅行的方式;我们对生活空间的期望以及我们去办公室的频率(在许多情况下)已经永远改变了——衡量新冠肺炎引起的剧烈变化是否是永久性的,将是企业和政府根据消费者和公民需求制定计划的关键。

举个例子,在美国,有很多关于人们离开城市的宣传,然而(根据美国人口普查局的数据)84%的搬家者仍然住在同一个城市区域;7.5%停留在同一状态;6%的人留在排名前 50 的大都市地区,只有 0.28%的人完全离开了大都市/微型地区。那么,我们如何监测这些趋势,衡量我们在全球看到的新的和不断变化的城市化水平呢?

在这个项目中,我们设计了一个空间模型,它能够以高粒度对全球城市化水平进行分类。作为我们模型的目标地理支持,我们选择了级别 15 中的四键格网,它在赤道上有大约 1x1 公里的像元。

了解如何根据城市化类型对区域进行分类,综合一个国家的人口密度和城市基础设施(道路、灯光)如何变化的信息,在位置智能领域有多种应用。例如,这可以支持物流和快速商务公司优化其供应链运营,或帮助电信公司更好地规划其网络的部署,并根据城市化水平调整蜂窝密度。零售和 CPG 公司也可以根据其商店所在区域的类型来分析其业绩并计算其目标市场。

有几个数据集提供了只关注特定国家的城市化分类,例如由geoly tix(geoly tix GeoData Urbanity 用户指南 2020 )和 A.Alexiou 等人开展的工作。英国的 al ( 来源)和西班牙的 unica 360(来源)。然而,试图遵循一种共同的方法在全球一级建立这种分类似乎不太常见。与我们在本项目中的目标仅在一定程度上相似的全球数据集是来自 OpenStreetMap 的土地利用分类,以及几个基于卫星的土地覆盖数据产品,如 MODIS 土地覆盖气候建模网格(CMG) 和欧洲的 CORINE 土地覆盖

在本文中,我们将介绍我们为构建空间模型而设计的输入数据和方法,展示一些结果和关键指标。

输入数据

对于该模型,我们需要全球可用的高粒度数据集。这包括:

  • 人口镶嵌图( WorldPop ):全球人口数字被投影到一个网格中,网格大小为 1x1 公里。这些数据也可以通过 CARTO 的数据观测站公开获得。
  • 夜间灯光(科罗拉多矿业学院):由每月无云平均辐射网格产生的年度全球 VIIRS 夜间灯光的处理时间序列。图像分辨率为 15 角秒,赤道处约为 500x500m 米。
  • 道路网络( OpenStreetMap ): OSM 提供每个国家的主要道路网络基础设施,以及不同路段的分类。在这项研究中,我们只考虑了一级公路、二级公路、高速公路和主干道(我们发现这些道路在不同国家之间更加一致和可用)。

选择这些数据集背后的基本原理是,夜间灯光和人口数据能够区分城市化地区和农村/偏远地区。几项研究已经检验了这些特征之间的关系,结果是它们彼此非常相关。随着人口的增加,光数据的强度也增加。除了人口之外,使用夜间照明数据的原因是为了更好地覆盖城市中人口突然减少的区域(例如,城市中的大公园)。

然后,我们使用关于道路网络基础设施的数据来区分可到达的区域和孤立的区域。

按作者分类的地图

都市课程

对于这个项目,我们决定考虑 6 个不同的等级或城市化水平,如下所述。分类是在国家级别完成的,这使我们可以单独为每个国家运行分类模型。这是一个重要的考虑因素,主要是因为各国城市地区的结构及其对人口密度分布的影响差异很大;例如,如果我们将美国的纽约市或印度的孟买等城市地区与荷兰的阿姆斯特丹相比,它们在结构上是不同的,特别是如果我们考虑人口密度,而它们都是相应国家的城市地区。

  • 第 1 类—偏远地区:没有人口或人口非常少且不容易通过主要道路网络到达的地区。
  • 第 2 类——农村:人口非常少,但可以通过主要道路基础设施进入的区域。由于“1 级-偏远地区”更容易进入,因此该分类与“1 级-偏远地区”有很大不同,但该分类与土地的农业用途无关。
  • 第 3 类—低密度城市:人口相对稀少的地区,中小型城镇。
  • 第 4 类—中等密度城市:人口密集区和夜间灯光数据,大多数大中城市,或大城市郊区。
  • 第 5 类—高密度城市:人口密集区和夜间照明数据。大城市,进口城市的中心;
  • 第 6 类——非常高密度的城市:大都市地区,每个国家的主要城市的中心,人口非常密集的地区。

方法学

因为我们希望我们的结果数据集聚集在四键网格上,因为它是一个标准的地理支持系统;我们首先需要将输入数据集转换成该格网规范。为此,我们使用了 Google BigQuery 的 CARTO 空间扩展中的一些四键功能。我们将 Worldpop 人口数据转换为每个四键单元的人口密度。对于夜间光线数据,我们基于不同像素和目标网格单元之间的相交区域来丰富四键网格。对于道路网络数据,我们计算每个目标像元内每种道路段的总长度。

我们发现夜间照明数据需要进行预处理,以便为我们的用例做好准备,因为我们在电厂和河流三角洲等与人口密度无关的区域发现了一系列具有高光强度值的异常值。用于检测此类异常值的方法如下:

  • 使用标准化夜间光线数据和人口密度,按照高斯混合模型(GMM) [4]进行聚类(有 8 个聚类);
  • 找出偏离高光和高种群密度基本规则的集群,我们将其标记为“离群值”;
  • 从“非异常值”中建立人口密度和人口密度空间滞后的模型(即三次多项式回归);
  • 使用之前的模型对异常区域进行插值。

我们对夜间照明数据进行校正的结果示例如下:

异常值校正示例,左:原始夜间光照与人口密度,右:校正后夜间光照与人口密度

然后,一旦我们在目标地理支持系统中预处理和聚集了所有输入数据,我们就将夜间光线数据和人口密度数据结合起来,以便创建一个涵盖这两种特征的索引。然后我们用这个指数来代表“城市性”。这是使用主成分分析(PCA) 完成的,只有一个成分;因此,为每个区域创建一个“索引”。这样,对于一个区域,如果人口密度或光强度呈现高值,那么指数也将具有高值。这是基于两篇论文(“香港夜间影像与人口密度之间的关系”&”夜间灯光数据:经济活动的良好替代措施?”),其中作者陈述了夜间光数据和人口密度是相关的。

由于我们使用高分辨率格网,但我们还希望确保分类的连续性,并避免相邻区域城市化水平的剧烈变化(例如,由于相邻像元中人口密度的巨大变化),因此我们需要一种方法来包含空间相关性。例如,我们不希望仅仅因为城市中心的公园的人口和光照强度低于相邻像元,就将其归类为乡村或低密度。

因此,在生成索引后,所有像元的盖蒂斯-Ord 统计量都是使用两层区域作为相邻像元来计算的,如下图所示。现在的目标是生成一个考虑到每个格网像元周围区域的 Z 分值。

网格中最多 4 层相邻层的图示

产生的 Z 得分用作聚类算法(即 KMeans)的输入,其中使用了 6 个不同的聚类,与我们希望作为项目结果获得的城市化水平等级的数量相同。平均人口密度最低的集群位于偏远地区,第二低的集群被归类为农村,依此类推。

下一步,我们将使用每个像元中所有道路长度的 Z 值(即 GetisOrd 统计值,如上所述)进一步对生成的偏远地区和农村地区进行聚类。这次我们用 4 层相邻像元计算 Z 值(见上图)。然后,我们将道路长度最短的聚类标记为偏远地区,其余的标记为农村地区。

在该过程的最后,我们对标签进行最后的细化,以便校正一些伪单元,这些伪单元与它们的所有第一层邻居相比具有不同的标签。对于每个像元,将检查相邻像元的标注,如果所有像元都是相同的城市化等级,但对于目标像元却不同,则目标像元的标注将更改为其周围像元的标注。

结果

在下面的地图中,我们展示了几个示例性国家的城市化模型的结果。值得注意的是,为了构建这些可视化,考虑到数据量,我们使用了 CARTO 的 BigQuery Tiler

作者图片

日本地图

作者图片

西班牙的地图

作者图片

英国的地图

我们在 251 个国家运行该模型,遵循在ISO 3166–1 Alpha-3中定义的国家代码。下面的表格总结了在不同城市化水平下划分的网格单元百分比的一些结果。可以看出,全球 42%的人口至少居住在低密度城市地区。大多数人口生活在农村地区。这主要是因为中国、俄罗斯等大国的人口分布。

从各大洲不同的城市化水平来看,我们发现亚洲和北美的偏远地区比例最大,这主要是因为俄罗斯和加拿大的北部地区不适合居住。欧洲似乎在更高密度的城市化水平中具有更大百分比的细胞。

仔细观察某些地区,西欧似乎是高密度城市化地区比例较高的地区;加拿大和东欧被列为偏远地区的比例较高。

在下面的可视化中,您可以探索我们的模型在欧洲所有国家的结果,再次展示我们的 BigQuery Tiler 在使用大量数据构建可视化方面的能力。

作者图片

欧洲地图

即将在 CARTO 空间要素中提供

2020 年末,CARTO 推出了我们的第一个衍生数据产品,名为“ CARTO 空间特征”。该数据集旨在使数据科学家能够创建空间模型,以标准化格式提供一组覆盖全球的空间要素。在接下来的几周内,我们将发布新版本的空间要素数据,其中我们将城市化水平作为新的可用要素之一。

原载于 2021 年 6 月 10 日 https://carto.com**

用 Python 构建语音情感识别器

原文:https://towardsdatascience.com/building-a-speech-emotion-recognizer-using-python-4c1c7c89d713?source=collection_archive---------15-----------------------

用 MLP 人工神经网络逐步指导语音情感识别

Unsplash 上 Soundtrap 拍摄的照片

在这篇文章中,我将向你展示如何从预先录制的录音中识别不同的情绪。我们知道,语音控制的个人助理,如亚马逊 Alexa、苹果 Siri 和谷歌助理等,已经变得更加强大,并且仍在不断发展。我们开始看到它们被集成到手机、笔记本电脑、厨房用具、汽车中,基本上在我们日常使用的任何东西上。我认为易用性是这个领域发展壮大的主要因素。

当我发现 Kaggle 上使用 RAVDESS 情感语音音频数据集的语音情感识别项目时,我决定自己动手,然后作为书面教程分享。我认为这是一个令人兴奋和有趣的项目。随着我们使用更多的语音控制设备,我相信情感识别将在未来几年成为这些设备的一部分。这些设备背后的人工智能将足够智能,能够理解我们对它们说话时的情绪,并给出更个性化的回应。

例如,在上路之前,我要求 Siri“从音乐应用程序播放音乐”,然后它就开始播放我的 broad mix。但是想象一下,如果我们在命令中加入情感识别能力。这样,它会根据我的心情播放各种音乐。许多音乐应用程序已经给出了不同需求的类别,那么为什么不通过一个简单的“播放音乐”命令来播放这些音乐呢?

我喜欢从事像这样的与语音识别相关的项目。我已经发表了一些与这个话题相关的文章。我会在本文末尾添加它们。如果你想在这个领域有所发展,请随意查阅。

如果你准备好了,让我们开始工作吧。这是我们将在本文中遵循的结构。

目录

  • 第一步——库
  • 步骤 2——了解 RAVDESS 数据
  • 步骤 3 —从录音中提取特征
  • 步骤 4 —加载并准备数据
  • 最后一步——MLP 分类器预测模型
  • 结论

步骤 1 —库

首先,让我们安装我们需要的库。我们可以使用 PIP install,这是一个 python 库管理工具。我们可以在一行中安装多个库,如下所示:

pip install soundfile librosa numpy sklearn

安装过程完成后,我们可以继续打开一个新的文本编辑器。我在大部分项目中使用 Jupyter Notebook,它在机器学习和数据科学项目中非常好用。

然后,我将导入我们在这个项目中需要的模块。我们可以在导入后使用“as”来重命名库。这使得它们更容易调用和使用。

import librosa as lb
import soundfile as sf
import numpy as np
import os, glob, picklefrom sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import accuracy_score

我将为每个库添加官方文档页面以供参考。这是了解更多模块及其使用方法的好地方:

步骤 2—了解 RAVDESS 数据

让我先分享一下 RAVDESS 代表什么瑞尔森情感语音和歌曲视听资料库。这是一个大型数据集将音频和视频数据库。该数据的原始大小约为 24Gb。但是我们将使用它的一小部分,而不是整个数据集。这将有助于我们保持专注,更快地训练我们的模型,并保持事情简单。数据集的一小部分可以在 Kaggle 上的这里找到。

关于数据的一点背景信息

RAVDESS 的这一部分包含 1440 个文件:每个演员 60 次审判 x 24 个演员= 1440。该数据包含 24 名职业演员:12 名女性和 12 名男性。言语情绪包括平静、快乐、悲伤、愤怒、恐惧、惊讶和厌恶的表情。你可以在 Kaggle 网站上了解更多信息。

文件名按照特定的模式重命名。这个模式由 7 部分组成。这些部分分为以下几个部分:情态,声道,情感,情感强度,陈述,重复,演员。每个信息也有它的子部分。所有这些信息都有标签;你可以在 Kaggle 网站上找到更多关于这些的信息。

以下是数据集中 Actor_1 文件夹的屏幕截图:

作者图片

情感标签

以下是情感类别的标签。我们将创建这个字典,以便在训练机器学习模型时使用。在标签之后,我们正在创建一个情绪列表,我们希望在这个项目中关注这些情绪。很难使用所有的情绪来做预测,因为讲话可能同时用多种情绪来听,这将影响我们的预测分数。这就是为什么我选择了三种主要情绪,快乐、悲伤和愤怒。随意尝试不同的情绪。

emotion_labels = {
  '01':'neutral',
  '02':'calm',
  '03':'happy',
  '04':'sad',
  '05':'angry',
  '06':'fearful',
  '07':'disgust',
  '08':'surprised'
} focused_emotion_labels = ['happy', 'sad', 'angry']

步骤 3—从录音中提取特征

在这一步,我们将定义一个函数。这个函数将提取音频记录,并使用 numpy hstack 方法将它们作为堆栈数组按顺序水平返回。

音频文件有许多功能。其中一些是 MFCC,色度和梅尔。这里的是 Joel 写的一篇好文章,发表在 TDS publication 上。我喜欢作者解释每个音频特性在训练模型时如何产生影响的方式。

def audio_features(file_title, mfcc, chroma, mel):
    with sf.SoundFile(file_title) as audio_recording:
        audio = audio_recording.read(dtype="float32")
        sample_rate = audio_recording.samplerate

        if chroma:
            stft=np.abs(lb.stft(audio))
            result=np.array([])
        if mfcc:
            mfccs=np.mean(lb.feature.mfcc(y=audio, sr=sample_rate, n_mfcc=40).T, axis=0)
            result=np.hstack((result, mfccs))
        if chroma:
            chroma=np.mean(lb.feature.chroma_stft(S=stft, sr=sample_rate).T,axis=0)
            result=np.hstack((result, chroma))
        if mel:
            mel=np.mean(lb.feature.melspectrogram(audio, sr=sample_rate).T,axis=0)
            result=np.hstack((result, mel))
        return result

步骤 4 —加载和准备数据

在这一步中,我们将定义一个函数来加载数据集。首先,我们加载数据,然后使用上一步中定义的函数提取特征。在提取特征的同时,我们给特征加上情感标签。你可以把特征想象成我们的输入(x),把被标记的情感想象成输出(y)。这是一个众所周知的机器学习模型,也被称为监督学习

然后,我们将使用 train_test_split() 函数分割已标记的数据集。这是 Scikit-learn 模块的一个众所周知的拆分功能。它将数据集分成四个块。我们可以定义数据集的多少用于训练,多少用于测试。您可以调整这些值,看看它如何影响预测。没有放之四海而皆准的规则;这通常取决于数据集。但是在大多数情况下,应用 0.25 的测试大小。这意味着数据集的 3/4 用于训练,1/4 用于测试。

def loading_audio_data():
    x = []
    y = [] for file in glob.glob("data//Actor_*//*.wav"): file_path=os.path.basename(file)
        emotion = emotion_labels[file_path.split("-")[2]] if emotion not in focused_emotion_labels:
            continue
        feature = audio_features(file, mfcc=True, chroma=True, mel=True)

        x.append(feature)
        y.append(emotion) final_dataset = train_test_split(np.array(x), y, test_size=0.1, random_state=9) return final_dataset

最后一步— MLP 分类器预测模型

我们差不多完成了。这是最后一步,将开始调用我们之前定义的函数,并从语音音频记录中识别情绪。

加载并拆分数据

让我们从运行 loading_audio_data() 函数开始。这个函数将返回四个列表。也就是说,我们将为每个列表使用四个不同的变量,顺序很重要。您应该熟悉这种拆分方法,尤其是如果您正在处理机器学习项目。

X_train, X_test, y_train, y_test = loading_audio_data()

定义模型

MLP 分类器是多层感知器分类器。它使用神经网络模型,通过有限记忆 BFGS 或随机梯度下降来优化对数损失函数。

这里的是 MLP 分类器模型的官方文档页面。您可以了解更多有关其参数以及它们如何影响训练过程的信息。

model = MLPClassifier(hidden_layer_sizes=(200,), learning_rate='adaptive', max_iter=400)

拟合模型

model.fit(X_train,y_train)

模型预测准确度分数

在我们的模型拟合之后,我们可以进入预测步骤。我们将把预测值赋给一个名为 y_pred 的新变量。这样,我们就可以计算预测的准确度分数。精度得分函数检查有多少预测值与原始标注数据相匹配。下面是代码,我将在它下面添加一个结果截图。

y_pred = model.predict(X_test)accuracy = accuracy_score(y_true=y_test, y_pred=y_pred)print("Accuracy of the Recognizer is: {:.1f}%".format(accuracy*100))

作者图片

结论

我们的准确率是 79.3,这是非常令人印象深刻的。我一般都是多次拟合模型后得到一个差不多的分数。我确实认为,对于通过录音训练的情感识别模型来说,这是一个令人满意的分数。感谢机器学习和人工智能模型开发者。

恭喜你。我们使用 python 创建了一个语音情感识别器。正如我前面提到的,这个领域发展如此迅速,越来越成为我们日常生活的一部分。这些类型的项目将帮助你找到新的想法来实施。如果你今天学到了新东西,我很高兴。从事动手编程项目是提高编码技能的最佳方式。如果您在执行代码时有任何问题,请随时联系我。我尽最大努力回复大家。

我们来连线。查看我的博客youtube 来获得灵感。谢谢你,

更多语音识别相关的机器学习项目

本文提到的 RAVDESS 数据集参考资料:Livingstone & Russo 的《Ryerson 情感语音和歌曲视听数据库(RAVDESS)》在 CC BY-NA-SC 4.0 下授权。

从头开始构建统计分析包

原文:https://towardsdatascience.com/building-a-statistical-analysis-package-from-scratch-7e9ba0508a53?source=collection_archive---------37-----------------------

Python 中的面向对象编程

詹姆斯·哈里逊在 Unsplash 上拍摄的照片

Pandas、NumPy 和 scikit-learn 都是数据科学工具包的重要组成部分。如果您在一个以数据为中心的项目中使用过 Python,那么您可能会熟悉如何使用至少一个(如果不是全部三个)上述包。

然而,您可能不太熟悉这些包在后端如何工作的细节:所谓的“幕后”机制。

本文将介绍从头构建 Python 包的过程,以提供一些指导,说明我们每天使用的工具中有多少实际上可以工作,以及如何使用面向对象编程(OOP)来创建新的工具。

作为一个演示工具,我们的目标是构建一个简单的统计分析包,我们称之为概率。一旦完成,我们的包应该能够从数据文件中创建随机变量的实例,以执行诸如输出统计属性、绘制分布和计算概率等操作。

使用面向对象的方法将允许我们编写模块,这些模块可以将来自推断统计理论的多种分布模型应用于不同形式的数据集。

建造过程将遵循三个主要步骤:

  1. 我们将从为包的类编写模块化的基本代码开始:我们的包最终将执行的操作的关键
  2. 然后,我们将在一个虚拟的本地环境中安装这个包,并运行一些单元测试来确保它能够工作
  3. 最后,我们将把这个包上传到 PyPI,让它可以公开使用

第一步:编写模块化的基础代码

OOP 概念背后的基本思想是将代码组织成“对象”:以属性形式存储数据并执行操作以产生输出的字段。

在 Python 中,这转化为将代码编写到类中,我们最终可以将数据读入这些类,并调用的方法来完成期望的目标。

在我们示例的上下文中,每个分布模型将被编程为一个单独的对象,这意味着我们的包将能够处理的高斯、二项式和泊松分布都需要一个类。

术语“模块化代码”是指将代码组织成单独的文件(模块),然后这些文件可以一起存储在一个目录中。这种方法的好处是使代码更容易管理、维护和最终共享。

在我们深入编程的具体细节之前,让我们先来看看 OOP 的另一个支柱:继承

继承是指创建一个支配性的“父”对象(或多个对象),然后单个“子”对象可以从该对象继承属性和方法。

这本质上是一种创建多个具有相似性的对象的方法,而不必一遍又一遍地重复代码。

记住这一点,作为我们的包的第一个对象,让我们创建一个通用的分发父类,我们的单个分发模型将能够继承它。

一般分发类别(父对象)

class Distribution():

    def __init__(self, mu=0, sigma=1):

        """Generic distribution class for analysing a probability distribution.

        Attributes:
            mean (float) representing the mean value of the distribution
            stdev (float) representing the standard deviation of the distribution
            data_list (list of floats) a list of floats extracted from the data file
        """

        self.mean = mu
        self.stdev = sigma
        self.data = []

每个对象的第一个方法应该是 instantiate ( __init__())函数:这个函数定义了创建对象实例的过程。

我们的父 distribution 类的 instantiate 方法将被后续的子类继承,并将创建实例,其分布的均值标准差的属性分别设置为默认值 0 和 1,以及一个空的数据属性。

不熟悉 OOP 的读者可能会对包含一个 self 参数感到困惑。这将是我们的包中每个方法的一个特性,本质上是用来引用对象在它自己的方法中的实例。例如,该方法中的self.mean = mu指示对象将自己的 mean 属性设置为 mu 的值。

请注意,该方法包含一个 docstring。在编写程序时,建议在每个函数/方法中包含一个 docstring,以便将来的用户和代码贡献者清楚每个组件是如何工作的。实例化函数的 docstring 应该描述对象的属性。

对于我们的通用分布类的下一个方法,让我们考虑我们的每个后续类应该共享的另一个函数:从文件读入数据的能力。因此,我们可以将它作为一个方法包含在父对象中。

def read_data(self, file_name):

        """Function to read in data from a .txt file.
        File should contain one float per line.

        Args:
            file_name (string): file to read data from

        Returns:
            None

        """

        with open(file_name) as file:
            data_list = []
            line = file.readline()
            while line:
                data_list.append(float(line))
                line = file.readline()
        file.close()

        self.data = data_list
        self.calculate_mean()
        self.calculate_stdev()

调用该方法将从指定文件中读取数据,并将其存储在对象的数据属性中。它还将计算所提供数据的平均值和标准差,并更新模型的其他属性。这些方法必须写在我们随后的子对象中,因为计算根据分布模型而不同。

注意,这个方法的 docstring 与第一个略有不同,因为它包含了用于 ArgsReturns 的部分。这是为了描述应该提供给函数的参数(在这种情况下是要从中读取数据的文件的名称),以及我们期望函数返回的内容(在这种情况下什么也不返回,因为该方法只更新对象的属性)。

这对我们的父对象中包含的方法来说应该足够了。遵循模块化编码的概念,我们可以将类作为一个名为Generaldistribution.py 的文件保存在一个名为probabilipy/的目录中,然后继续为我们各自的分布模型创建对象。

高斯、二项式和泊松分布类(子对象)

由于这些对象将包括执行诸如执行计算和绘制分布图等操作的方法,我们的第一步应该是导入几个包来帮助我们完成这些过程:即 python-mathmatplotlib

(更顽固的读者可能会在这里争辩说,使用预先存在的包与从头创建一个新包的概念相矛盾。然而,由于构建可视化绘图仪超出了本文的范围,我不得不在这方面做出一些让步。

我们还需要导入我们的 General distribution 类,因为我们希望子对象继承它的特性。这突出了将我们包中的每个模块存储在同一个目录中的需要。

import math
import matplotlib.pyplot as plt
from .Generaldistribution import Distribution

我们现在可以开始编写我们的第一个分发模型了。如前所述,对象的第一个方法应该是实例化函数。

class Gaussian(Distribution):

    """Gaussian distribution class for analysing a Gaussian probability distribution.

    Attributes:
        mean (float) representing the mean value of the distribution
        stdev (float) representing the standard deviation of the distribution
        data_list (list of floats) a list of floats extracted from the data file
    """

    def __init__(self, mu=0, sigma=1):
        Distribution.__init__(self, mu, sigma)

我们可以在新类的开头指定这个对象是我们的通用分布类的后代。对于新对象的实例化函数,我们可以简单地使用父对象中定义的方法。

现在让我们开始编写特定于每个分布模型对象的方法。例如,在父对象中定义的read_data() 方法之后,可以调用下面的方法来计算所提供数据的平均值,并相应地更新对象的 mean 属性。

def calculate_mean(self):

        """Function to calculate the mean of the data set.

        Args:
            None

        Returns:
            float: mean of the data set

        """

        mean = float(sum(self.data)) / len(self.data)
        self.mean = mean
        return self.mean

我不会在本文中包含所有包的类的每个方法的代码,因为这样做会使阅读变得相当长(也许很费力)。然而,有兴趣探索全部代码的读者可以在我的 Github 的这个库中找到它。

一旦我们完成了每个高斯、二项式和泊松分布类的方法,我们就可以进入安装和测试步骤。

步骤二:在本地安装软件包并执行单元测试

设置

要在本地环境中安装我们的包,除了基本代码之外,我们还需要创建几个文件。

第一个是位于probabilipy/目录中的__init__.py文件。这实质上提供了关于在包的实例化时要执行的步骤的指令。如果这个文件只是空白,安装仍然可以工作,但是在这种情况下,我们将指示环境从这三个文件中的每一个导入类,以避免在使用时必须完整地键入它们。

from .Gaussiandistribution import Gaussian
from .Binomialdistribution import Binomial
from .Poissondistribution import Poisson

第二份是一份setup.py文件。这应该在probabilipy/目录之外,但是在它的下一级目录之内。我们可以称这个目录为probabilipy_package/。安装文件指示环境可以在哪个目录中找到包的文件,并且可以选择性地用于提供关于安装的其他信息。

from setuptools import setupsetup(name='probabilipy',
      version='1.0',
      description='Probability distributions analysis package',
      packages=['probabilipy'],
      zip_safe=False)

测试

添加实例化和安装文件就足以让我们在本地安装这个包了。然而,因为我们还计划运行一些单元测试来确保代码工作,所以让我们也创建一个test.py文件。

对于这个文件,我们可以利用 python 的 unittest 包。我们还需要将我们的每个类导入到测试文件中。

import unittestfrom probabilipy import Gaussian, Binomial, Poisson

然后,我们可以为每个分发类定义一个测试类,并为该类包含的每个方法编写一个单元测试。例如,下面的代码首先创建一个二项式类的实例,然后从一个随机生成的二进制数的文件中读入数据(数据文件应该存储在与test.py相同的目录中)。第一个测试断言 class' calculate_mean()方法返回预先计算的答案 9。

class TestBinomialClass(unittest.TestCase):
    def setUp(self):
        self.binomial = Binomial()
        self.binomial.read_data('binomial_test.txt')

    def test_calculatemean(self):
        mean = self.binomial.calculate_mean()
        self.assertEqual(mean, 9)

现在一切就绪,我们可以继续在本地环境中安装这个包了(建议使用一个虚拟环境以避免干扰机器现有的 Python 安装)。为此,我们只需在命令行上导航到probabilipy_package/目录,并输入以下命令:

pip install .

一旦运行完成,我们就可以运行我们的单元测试了。因为我们仍然在probabilipy_package/目录中,所以我们需要做的就是启动一个 Python 解释器并运行文件:

python test.py

单元测试的结果应该能够发现代码中的任何错误。例如,下面强调了泊松分布类中累积密度函数的计算方法问题。

这表明我们需要审查基本代码,并纠正任何单元测试失败的方法。一旦我们检查完毕,我们就可以重新安装该软件包:

pip install --upgrade .

并再次运行测试文件。应该重复这个过程,直到所有的单元测试都通过,就像这样:

一旦我们的包通过了测试,我们知道它是有效的,它就准备好与世界分享(或者至少与那些对统计分析感兴趣的人分享)!

第三步:将包上传到 PyPI

创建必要的上传文件

为了准备我们的 PyPI 上传包,我们还需要在probabilipy/目录中创建一些额外的文件。

第一个是一个README.md文件。这对于上传来说并不是绝对必要的,但是包含它总是一个好的实践,因为它为软件包的未来用户提供了一种理解其功能的方式。

第二份是一份license.txt文件。这应该是一个包含软件包版权信息的文本文件。可用于创建该文件的模板示例是 MIT 许可证

最后,我们需要添加一个setup.cfg文件。这应该只包含一些关于包的元数据,PyPI 可以在配置上传时读取这些元数据。下面是一个可以包含哪些内容的示例:

[metadata]
name = 'probabilipy'
version = 1.0
description-file = README.md

一旦我们在probabilipy/目录中放置好这三个文件,我们的包应该准备好上传到 PyPI

上传

注意: 建议先上传一个包到 测试 PyPI 网站,确认运行正常后再上传到工作索引。此外,需要在测试 PyPI 和 PyPI 网站上创建单独的帐户来执行上传。

上传包的第一步是在命令行中导航到probabilipy_package/目录并输入命令:

python setup.py sdist

该命令使用我们在前面定义的setup.py文件来创建一个源分发目录,将上传所需的所有文件打包并压缩到一个tar.gz文件中。

接下来,我们需要安装 twine :一个在 PyPI 上发布包的实用程序。这可以用通常的方法来完成:

pip install twine

最后,我们可以输入命令:

twine upload dist/*

将我们的源代码分发目录上传到 PyPI 网站。这个命令应该提示输入用户名和密码,然后应该成功上传我们的包。

结束语

太好了!看起来我们的包裹在 PyPI 网站上直播了。让我们在本地安装它:

pip install probabilipy

并在 Jupyter 笔记本上测试它的一些功能:

这样,我们就有了一个从头开始构建的工作统计分析包。

如前所述,有兴趣探索创建这个包的完整代码的读者可以在我的 Github 的 this repository 中找到它。随时欢迎反馈、建议和问题。

使用带有 Google 数据流的 SQL 构建流管道

原文:https://towardsdatascience.com/building-a-streaming-pipeline-using-sql-with-google-dataflow-726564caf92?source=collection_archive---------11-----------------------

大家都在说实时数据。没有人知道如何做这件事。每个人都认为其他人都在做,所以每个人都声称自己在做。JK!

约书亚·索蒂诺在 Unsplash 上拍摄的照片

什么是实时数据

实时数据是指在收集数据时交付的数据。这使您能够处理和查询这些数据,为决策提供信息或推动数据应用。有一些术语,如实时、近实时和批处理。这三者之间的区别没有明确定义,但您可以大致使用以下指南(IMHO)。

  • 实时:亚秒/分钟延迟,精度最差。
  • 接近实时:1–5 分钟延迟,更高精度。
  • 批次:从 1 小时、1 天到 1 周的任何时间,潜伏期在 5 分钟以上,精确度最高。

除非您需要处理金融交易,否则大多数流分析用例将属于近实时类别。例如,如果您开展促销活动,您将需要向客户发送一条消息,说明他们的购买是否符合特定标准。在这种情况下,你可以在购买发生后几分钟内完成。

实时数据的价值

实时访问数据对许多企业都有好处,因为数据是当今许多企业的命脉。您可以访问最新的信息来做出更好的决策,而不是依赖过时的、更新缓慢的信息。大多数现代数据仓库和 BI 工具都支持流式插入和查询,因此您的公司可以访问实时指标。

更好的是,许多决策可以使用流管道和一些业务逻辑自主做出。例如,您可以在将产品添加到购物车但未在最后 30 分钟内结帐后通知客户。

使用 SQL 构建流式管道

过去,资金雄厚的科技初创公司或拥有数百万美元预算的公司可以访问实时数据。你通常还需要一个数据工程师团队来构建和维护流管道。然而,随着云计算和开源数据社区的进步,许多这些功能正在向我们所有人开放。

商业案例

假设你是一家电子商务公司,有一个营销活动,奖励任何消费超过 5000 美元并进行新购买的客户。当这些顾客购买新商品时,你想发送一条应用程序推送来祝贺他们。您还需要一个实时仪表板来跟踪活动的进展情况。开发团队说他们已经满负荷了,不会在这个活动中帮助你,所以你只能靠自己了。

像这样的任务通常需要两个数据源并将它们组合起来。您需要查询您的数据仓库来获取所有消费超过$ 5000 的客户。您还需要实时数据来捕获今天的新交易。这也被称为 lambda 架构,其中有一个每天至少运行一次的批处理层和一个实时流数据的速度层。

λ建筑—图片来源:维基百科

建筑

假设您的开发团队能够构建订单和客户数据的流源(这实际上是一个先决条件),我们的架构将如下所示。

作者图表

在这种架构中,新订单(一天之内)被流式传输到发布/订阅。数据流创建的管道将检查每一笔新的购买,以查看该客户是否在花费超过 5000 美元的客户列表中。结果将被写入两个目的地。BigQuery 的结果将用于带有可视化工具的实时仪表板。写入发布/订阅的结果将用于向获胜的客户发送推送通知。

入门指南

以下是一些入门的先决条件:

  • 谷歌云账户
  • 一个有效的付费账户(你可以注册 300 美元的免费试用)
  • 谷歌云项目

激活云壳—作者 GIF

https://github.com/tuanchris/dataflow-sql

通过运行以下命令将此存储库克隆到 Cloudshell:

# Clone the repo locally
git clone [https://github.com/tuanchris/dataflow-sql](https://github.com/tuanchris/dataflow-sql)
cd dataflow-sql# Install requirements
pip3 install -r requirements.txt

创建数据源

我们的流管道需要两个数据源,如下所示:

1。一个大查询批量源——所有订单和客户信息,每天更新

# This script will create 100 customers with 1000 orders
python3 generate_data.py batch \
 --customer_count=100 \
 --order_count=1000 \
 --project_id=$DEVSHELL_PROJECT_ID
# Replace the project_id varaible if you are running locally

当云壳要求验证您的请求时,选择“授权”。

生成的客户表-按作者分类的图像

生成的订单表-按作者排序的图像

2。名为 **orders**的发布/订阅主题——通过订阅发布/订阅主题获得的订单数据流

# Create a Pub/Sub topic
gcloud pubsub topics create orders# Generate a stream of order data to Pub/Sub
python3 generate_data.py stream \
 --customer_range 100 \
 --project_id $DEVSHELL_PROJECT_ID

实时流向发布/订阅的模拟订单—图片由作者提供

将发布/订阅源添加到 BigQuery

要将发布/订阅源添加到 BigQuery,请执行以下步骤:

  1. 将 BigQuery 中的查询引擎改为云数据流引擎

更改查询设置-按作者排序的图像

将查询引擎更改为云数据流—图片由作者提供

2。从 BigQuery UI 中,选择添加数据并选择云数据流源

添加云数据流源—图片由作者提供

3。添加发布/订阅主题源

选择项目和发布/订阅主题—按作者分类的图像

4。为订单主题添加一个模式

选择“添加的订单”主题,然后单击“编辑模式——按作者排序的图像”

切换编辑为文本并粘贴以下值-按作者排序的图像

[
    {
        "name": "event_timestamp",
        "description": "",
        "mode": "REQUIRED",
        "type": "TIMESTAMP"
    },
    {
        "name": "customer_id",
        "description": "",
        "mode": "NULLABLE",
        "type": "INT64"
    },
    {
        "name": "amount",
        "description": "",
        "mode": "NULLABLE",
        "type": "FLOAT64"
    },
    {
        "name": "order_status",
        "description": "",
        "mode": "NULLABLE",
        "type": "STRING"
    },
    {
        "name": "order_datetime",
        "description": "",
        "mode": "NULLABLE",
        "type": "STRING"
    }
]

写一个 SQL 查询

下面是一个简单的 SQL 查询,它将回答我们的业务问题。

WITH
  eligible_customers AS (
  SELECT
    o.customer_id,
    SUM(o.amount) AS total_spent
  FROM
    bigquery.table.`demobox-313313`.ecommerce.orders o
  WHERE
    o.order_status = 'Closed'
  GROUP BY
    1
  HAVING
    total_spent >= 5000)
SELECT
  o.*,
  ec.total_spent
FROM
  pubsub.topic.`demobox-313313`.orders o
INNER JOIN
  eligible_customers ec
USING
  (customer_id)
WHERE
  o.order_status != 'Cancelled'

我们首先从 orders 表中选择数据,只筛选出“已完成”的订单,然后按客户分组,计算总支出,并筛选出购买了$5,000 或更多的客户。然后,我们将符合条件的客户列表加入到任何新的交易中,过滤掉状态为Cancelled的交易。

您可以看到,像上面这样编写 SQL 很容易,任何分析师都可以做到。尝试时,请确保替换您的 project_id。

创建数据流作业

查询准备好并得到验证后,您可以从 BigQuery UI 中选择Create Dataflow job。按照下图配置两个目的地。您可以将其他值保留为默认值。

配置大查询目标和发布/订阅目标—按作者分类的图像

创建数据流作业后,您可以看到下面的结果。按照作业 ID 中的链接查看您的数据流作业及其状态。

数据流创建结果-作者图片

数据流作业可能需要 3-5 分钟才能启动。之后,您应该能够像下面这样处理管道。

数据流 SQL 管道—作者图片

验证结果

在数据流作业成功启动和运行之后,您可以进入 BigQuery 和 Pub/Sub 来验证我们的管道是否按预期工作。

购买金额超过 5000 美元且有新交易的客户列表-按作者分类的图片

通过运行数据流作业,我们可以看到关于管道的各种作业指标。比如数据流处理数据需要 11 秒,还不错!

数据新鲜度报告-按作者分类的图像

打扫

确保取消数据流管道,删除发布/订阅主题,并删除 BigQuery 数据集,以避免产生成本。

取消数据流作业-按作者分类的图像

结论

实时数据过去非常昂贵,而且只为最熟练的数据工程师保留。它仍然很贵,而且需要相当多的技术知识。然而,有了 SQL Dataflow 这样的托管工具或 Kafka 的 KSQL 和 Spark SQL 这样的开源替代工具,流式分析有望大众化,更容易获得。

快乐学习!

模拟一场网球比赛

原文:https://towardsdatascience.com/building-a-tennis-match-simulator-in-python-3add9af6bebe?source=collection_archive---------15-----------------------

照片由莫伊斯·阿历克斯Unsplash 上拍摄

使用 Python 验证网球比赛基于点的建模背后的数学原理

网球,像其他球拍类运动(和排球)一样,有一个特定的得分系统,包括将得分分为子集,这些子集是对整体比赛重要的,而不是每个单独的点。这就引出了一个自然的问题:

“给定得分的胜算概率与网球比赛的胜算概率有什么关系?”

希望是积极的,否则技能不会得到奖励。以下是我关于如何使用“基于点的模型”对网球比赛进行建模的笔记,作为构建网球比赛模拟器的一部分,以便回答一些有趣的问题,这些问题围绕着改变比赛的各种规则(如取消二发或减少平手到猝死)的影响。

目的是:

  • 贯穿基于点的模型的思想
  • 推导出服务器赢得游戏的概率公式
  • 使用模块tennisim中的 python 模拟来测试这种推导

只有一个变量,p

为了简单起见,我们将假设一个点可以完全由一个变量来描述,p:服务器在游戏中赢得给定点的概率。围绕这一点的假设是:

  • 这个概率可以在玩游戏之前以合理的准确度进行估算
  • 这个概率在整个游戏中是不变的
  • 每个点都是独立的:前一个点(或前一个点的集合)的结果不会影响该点的概率

如何在一场网球比赛中得分

网球之所以有趣,是因为并非每一点都同样重要。这场比赛不仅仅是一场 150 分左右的比赛,大数法则(LLN)将开始发挥作用,因此很少有冷门。

取而代之的是,分数被细分为游戏,每场游戏都有一名玩家获得优势——他们可以随心所欲地通过第一枪就开始得分。

基于点的建模基础

这被称为基于点的建模,因为为了得到游戏、集合和比赛的结果,我们依赖于计算所有组成点的结果。尽管这可能不是模拟比赛总体结果的最具预测性的模型(它似乎是 ELO 的修改版),但它非常有用,因为它产生了大量的赛内信息,从而为制定“比赛中的赔率”提供了基础。

鉴于:

  • p:发球方得分的概率
  • (1-p):返回者赢得分数的概率(假设没有其他人可以赢得分数)

然后,我们可以生成以下网球比赛进程的“流程图”:

图片由作者使用https://app.diagrams.net/

所以简单描述一下上面的内容:

  • 我们从 0-0 开始
  • 以概率p服务器赢得了这一点,我们在图表上“向上”移动
  • 反之亦然,概率为(1-p) -我们在图表中“下移”
  • 如果我们打成平手,我们在最后会有某种循环行为,如果一名球员没有连续赢得 2 分,那么我们会反弹到平手(这与 30-30 相同,因为在这一点上,两名球员需要连续赢得 2 分才能结束比赛)

我们可以用这个图表来直观地展示如何以方程式的形式为游戏建模。比如,我们可以看到,一场比赛要想赢得爱情,只有一个办法:连赢 4 分。如果你是服务器,那么发生这种情况的概率是(p x p x p x p)。对于回球者来说,反过来也是正确的,他用所有其他可能的路线来打破发球,以结束由图表中间的路径描述的比赛。

对于游戏的每一个可能的最终结果,为了得到它发生的概率,我们需要:

  • 计算游戏以某个分数结束的概率,例如:爱赢了
  • 用达到最终分数的方式的数量乘以这个数,例如,1 代表爱

例如,有多种方式可以结束游戏,服务器获胜,返回者在游戏结束时有 15 分,因为返回者可能在整个游戏的不同情况下赢得该分。假设我们将每个点视为一个伯努利变量,即只有两个互斥的结果,那么我们可以将一组点视为一个遵循二项式分布的二项式变量

然后,我们可以写出下面的内容——如果我们玩n点,服务器将赢得其中的x点的概率P是:

作者图片

这里我们还定义了‘二项式系数’:

作者图片

写出给定游戏的方程式

我们需要小心的最后一件事是不要重复计算结果——这可以通过一个例子得到最好的说明。对于服务器来说,要赢得一场比赛,他们需要赢得 4 分,他们的对手赢得 1 分。在上面的例子中,服务器赢了x=4,就可以玩n=5点游戏。上面的等式(二项式系数)告诉我们有 5 种方式可以做到这一点。然而,这并不完全正确,因为它是在计算服务器赢得前 4 分,返回者赢得最后一分的结果-但这是不可能的,因为游戏已经结束了(服务器将赢得爱情)。

为了绕过这一点,我们可以应用包含-排除原则——为了得到上述可能发生的方式的数量,我们需要减去服务器可以赢得爱的方式的数量。

现在,让我们写下以下作为服务器赢得一场比赛的概率:

作者图片

换句话说,服务器赢得游戏的概率是:

  • 他们赢得爱情的概率
  • 他们获胜的概率为 15
  • 他们获胜的概率为 30
  • 他们进入“平手”然后设法(在某个时候)连续赢得 2 分的概率

在深入最后一点之前,我们可以先解决前几个问题,因为它们比较简单。

作者图片

现在我们可以把最后一部分分成:

  • 当我们玩 6 分游戏时,每个玩家赢 3 分的概率(简单)
  • 最终服务器将设法赢得 2 个连续点的概率(硬)

第一位可以简单地写成:

作者图片

这里我们不需要担心重复计算,因为没有人得到 4 分,所以比赛不会结束。现在是棘手的部分——让我们首先计算出服务器赢得n+2积分的任何n的概率。我们可以认为这是以下各项的总和:

  • 发球方直接赢得 2 分(从平手)
  • 发球方赢 1,然后回球方赢 1,然后发球方赢 2
  • 返回者赢 1,然后服务器赢 1,然后服务器赢 2 获胜
  • 服务器赢,返回者赢,服务器赢,返回者赢,服务器赢 2 胜
  • 等等。等等。等等。

我们可以用数学方法表示为:

作者图片

其中:

  • p(1-p)是发球胜分的结果,然后是回发球
  • (1-p)p是回球者赢分,然后是发球者的结果
  • 然后服务器会赢得下一个 2 分吗

然后,我们可以将其简化为:

作者图片

我们把所有不依赖于j的东西都去掉了。剩下的是二项式系数的和,即:

作者图片

现在我们把它代入原始表达式,得到:

作者图片

最后,把括号外的p^2去掉,然后对无限几何级数求和,我们得到了拼图的最后一块:

作者图片

将这一点与上面的结合起来,我们得到了下面的表达式,即一个发球者赢得一场比赛的概率,只是根据他们在发球时赢得一分的概率:

作者图片

使用模拟来检查

现在我们有:

  • 封闭形式的解
  • python 由我们支配

我们不妨运行一些模拟来验证我们所期望的服务器赢得游戏的概率,给定他们将赢得任何给定分数的概率,对应于我们在模拟时所看到的平均值。

我已经将下面的内容打包成了tennisim,只需使用pip install tennisim就可以在 PyPI 上获得,但是为了完整起见,下面是来自tennisim的代码,用来模拟一个游戏以及一些用于制图的导入:

我们可以首先看一下服务器赢得游戏的概率如何随着服务器赢得任何给定点的概率而变化:

作者图片

现在让我们检查一下,如果我们模拟网球比赛,我们的方程是否与数据相符。我们将:

  • 模拟 1000 组 100 个游戏,服务器以不同的概率赢得给定的分数
  • 将这些组的分布与使用上面推导的公式计算的预期概率进行比较

作者图片

因此,看起来模拟是在支持这种推导——模拟的每个分布都围绕着理论上的获胜概率(红线)。

有趣的是,前面的线形图显示,服务器赢得一分的概率每增加 1%,赢得游戏的概率就会增加 1%以上。这只在上面图表的特定范围内是正确的,但考虑到大多数职业选手坐在 60-80%左右,这表明提高你的发球有多重要,因为它比线性增加了你保持发球比赛的机会。

结论

一旦我们假设一场网球比赛可以简化为一系列独立的点,并且发球方以固定的概率赢得每一个点,我们已经证明了发球方赢得比赛的概率可以用封闭的形式来描述。通过一系列模拟来验证这一点,表明模拟简单的概率设置是多么有用,模拟可用于以下文章:

  • 调查改变p对游戏的预期长度(以点为单位)的影响
  • 调查改变p对集合分数(6–4、7–5、6–2 等)预期分布的影响

在 Excel 中构建一元 GARCH 模型

原文:https://towardsdatascience.com/building-a-univariate-garch-model-in-excel-dfb4c671eff7?source=collection_archive---------13-----------------------

用 Python 和 PyXLL 在 Excel 中使用 GARCH 进行波动率预测

用 Python 和 PyXLL 在 Excel 中进行波动率建模。图片为作者本人。

在本文中,我们将在 Excel 中构建一个单变量 Garch 模型。Garch 模型用于估计金融资产的波动性。

本文最早出现在 PyXLL 博客这里:https://www . PyXLL . com/blog/building-a-univariate-GARCH-model-in-excel/

在 VBA 建立这个模型将是一项极其艰巨的任务,即使对于非常了解 VBA 的人来说也是如此。估计单变量 Garch 参数需要我们利用最大对数似然法。特别是,Excel 中没有内置的包来执行这样的任务。

然而,用 Python 构建这样的模型非常简单,使用 PyXLL,我们可以在 Excel 中使用 Python 模型。

更喜欢看?这篇文章附有这段视频。视频为作者本人。

用 Python 构建 Garch 模型

我们首先需要编写 Python 代码来估计 Garch 模型的参数。完成这项工作的代码如下:

下面描述了编写此代码所涉及的步骤:

安装所需的依赖项

我们需要使用 Pip 安装两个必需的包。

  • 首先是 arch 包,它将帮助我们估计 Garch 参数。我们可以通过运行“pip install arch”来安装它。这个 arch 包的文档可以在这里找到【https://arch.readthedocs.io/en/latest/
  • 第二个包是熊猫,它帮助我们组织我们的数据框架。如果你还没有安装熊猫,你可以通过运行“pip 安装熊猫”来完成。熊猫的资料在这里【https://pandas.pydata.org/

编写 garch_parameters 函数

我们函数的名字叫“garch_parameters”。该函数将接受一个数字列表,并返回一个包含估计模型参数的 pandas 数据帧。Garch 模型通常会从一项金融资产(如股票或指数)获取一系列回报。

  1. 我们创建一个名为“am”的变量,它从 arch 包中调用 arch_model 库。
  2. 我们创建另一个名为“res”的变量。这个“res”变量将从 arch 包的 arch_model 库中调用函数 fit()。
  3. 现在,这个“res”变量存储了与我们的 Garch 模型相关的所有信息。这包括模型参数、预测值、预测值等
  4. 在这种情况下,我们只需要参数信息。因此,我们创建了另一个名为“parameters”的变量,并将其设置为“res”对象的“params”属性。“res.params”对象是熊猫系列。
  5. 之后,我们创建一个新的 pandas 数据框架,它有一个“Parameters”列,用模型中的参数填充。
  6. 最后,我们必须从“garch_parameters”函数返回 DataFrame。

测试我们的功能

我们想测试我们的功能,以确保它确实如预期的那样工作。

我们可以通过向“garch_parameters”函数传递一个从 1 到 9 的数字列表来实现。这些数字没有意义,但现在可以用来测试我们的功能。之后,我们想打印出函数的结果。

这样做的结果如下。第一部分是拟合模型时的日志输出,最后一部分是我们返回的数据帧。

从 Excel 调用 Garch 模型

既然我们知道 Python 函数可以工作,那么我们如何在 Excel 环境中使用这个函数呢?这就是 PyXLL 发挥作用的地方。PyXLL 是一个 Excel 插件,允许我们直接从 Excel 调用 Python 函数。

如果你不熟悉 PyXLL,请访问 https://www.pyxll.com。在那里可以找到更多关于 PyXLL 的信息,包括如何安装和配置插件。

我们将使用 PyXLL 的 xl_func 装饰器。 xl_func decorator 指示 PyXLL 插件将该函数作为工作表函数公开给 Excel。PyXLL 会将这个函数导出到 Excel,这样我们就可以从 Excel 工作表中调用它。

视频https://www.pyxll.com/docs/videos/worksheet-functions.html很好地介绍了使用 PyXLL 用 Python 编写 Excel 工作表函数。如果您之前没有使用 PyXLL 编写过工作表函数,这个视频是一个很好的起点。

向 Excel 公开 Python 函数

为了将我们的“garch_parameters”函数公开给 Excel,我们只需要将 xl_func decorator 应用于该函数。我们还必须将 Python 模块添加到“pyxll.cfg”配置文件的“模块”列表中(没有。py 扩展名)。您可能还需要将源文件夹添加到“pythonpath”设置中。源文件夹是保存 Python 模块的文件夹。

xl_func decorator 接受一个字符串,该字符串告诉 PyXLL 函数期望什么参数,以及它返回什么。PyXLL 使用它将 Excel 函数输入转换为 Python 参数。如果我们不指定任何东西,PyXLL 将应用一些默认转换,但是在这种情况下,我们希望是显式的。

我们的修饰函数如下所示:

我们的 Excel 函数接受一个数字数组,并将一个 2d 数据数组返回给 Excel。这是通过传递给 xl_func 装饰器的函数签名字符串来实现的。“float[]”参数意味着该函数将从 Excel 中接受一个一维数组,并将其作为一个浮点数列表传递给我们的函数。在冒号之后,我们指定函数返回类型,这告诉 PyXLL 如何将我们的返回值转换成 Excel 可以处理的东西。我们希望 PyXLL 将返回的数据帧(包括索引)转换为 Excel 中的一系列值,因此我们使用“dataframe < index=True >作为返回类型。

你可以在 https://www.pyxll.com/docs/userguide/udfs/argtypes.html的用户指南中找到更多关于 PyXLL 如何处理参数和返回类型的信息。

从 Excel 调用 Python 函数

现在我们可以在 Excel 中测试这个函数了。如果打开 excel,该功能将在 Excel 中自动可用。如果已经打开了 Excel,则需要重新加载 PyXLL 加载项。重新加载 PyXLL 将会加载您在 pyxll.cfg 文件中配置的 Python 模块。

Python 代码无需重启 Excel 即可重新加载。图片为作者本人。

通过 PyXLL 功能区重新加载。您的功能区可能看起来不同,并且可以通过 ribbon.xml 文件进行自定义。

为了从 Excel 中调用这个函数,我们输入“=garch_parameters(…)”,并向它传递一个数字数组。使用相同的数字数组,我们调用 Python 函数,在 Excel 中得到相同的结果。

在 Excel 中调用 garch_parameters Python 函数。图片为作者本人。

注意:如果你使用的是旧版本的 Excel,你可能会发现数组不会自动扩展。动态数组是 Office 365 中的新功能。要在旧版本中自动扩展数组,请将“auto_expand=True”传递给 xl_func 装饰器。关于数组函数的更多细节见https://www.pyxll.com/docs/userguide/udfs/arrayfuncs.html

使用 Jupyter 笔记本进行 Python 开发

该过程的下一步是加载真实数据,并基于该数据估计 garch 模型。我们将使用 PyXLL-Jupyter 包在 Jupyter 笔记本中完成这项工作。

使用 Jupyter 笔记本可以让我们直接在 Excel 中快速编写 Python 代码。使用 Jupyter 笔记本的一个缺点是启动 Excel 时它不会自动加载。Jupyter 笔记本必须运行,我们的代码才能在 Excel 中可用。这对于开发很有用,因为我们可以快速迭代,但是对于部署来说,将代码移动到 Python 模块通常更好。

在 Excel 中使用 Jupyter 笔记本之前,我们需要安装 PyXLL-Jupyter 包,这可以通过运行以下命令来完成:

安装后,重新加载 PyXLL,您将在 PyXLL 功能区中看到 Jupyter 按钮。

在 Microsoft Excel 中打开 Jupyter 的按钮。图片为作者本人。

单击 Jupyter 按钮将在 Excel 中打开 Jupyter 笔记本应用程序。有关如何使用 PyXLL-Jupyter 包的更多详细信息,请参见https://www . PyXLL . com/blog/python-Jupyter-notebooks-in-excel/

Jupyter 笔记本在微软 Excel 中运行。图片为作者本人。

将 Garch 模型与真实数据结合使用

从 Yahoo Finance 获取返回数据

我们已经用一些测试数据测试了“garch_parameters”函数。然而,为了有用,我们需要一些真实的数据,我们可以使用“pandas_datareader”包从 Yahoo Finance 加载这些数据。

我们需要的另外两个包是日期时间熊猫 _ 数据阅读器。pandas_datareader 包用于从 Yahoo Finance 加载数据。datetime 包用于指定我们加载数据的开始和结束日期(ed:这些日期可以传递到我们的函数中,而不是硬编码在函数中)。

我们的新函数 data_load 接受一个字符串作为参数,并返回一个 DataFrame。这种情况下的字符串参数是股票的符号,例如:AAPL、IBM 等。返回的数据帧包含该符号的返回。

笔记本上写的“data _ load”Python 函数可以从 Excel 中调用。图片为作者本人。

不要忘记“运行”Jupyter 笔记本中的单元格来运行 Python 代码!

在 Jupyter 笔记本中输入代码并运行单元后,我们新的“data_load”函数就可以从 Excel 中调用了。

拟合模型参数

我们在 Excel 中已经有了“garch_parameters”函数。我们可以使用刚才加载的返回来调用它!

用调用“garch_parameters”函数会返回数据。图片为作者本人。

从模型中获取条件波动率

除了模型参数之外,Garch 模型还可以返回条件波动率。要访问这些,我们可以写一个类似于 garch_parameters 函数的函数,但是从模型中获取条件波动率。

这里我们不使用“res.params”,而是使用“res.conditional_volatility”。这个函数采用与 garch_parameters 函数相同的返回数组,我们可以使用加载的返回数据从 Excel 中调用它。

模型的条件波动率。图片为作者本人。

绘制结果

熊猫有出色的绘图能力。使用 pyxll.plot() 函数,我们可以在 Excel 中显示用熊猫绘制的图。以下函数采用一组数字,并使用熊猫来绘制一个简单的线图:

最后一行“plot()”(从 pyxll 包导入)显示 Excel 中的熊猫图,下面是调用函数的地方。

使用熊猫创建的波动图。图片为作者本人。

当我们更改模型的输入时,输出会自动重新计算,并且绘图会更新。

后续步骤…

在本文中,我们看到了如何使用 Python 包“arch”拟合 Garch 模型。我们还看到了如何从 Excel 中调用 Python 模型、加载数据以及从模型中提取结果。

Garch 模型通常用于预测未来的波动性,作为交易策略的一部分。本博客中使用的方法可以扩展到基于 Excel 中的输入进行预测。使用 Excel 作为模型的前端意味着我们可以非常容易地与它进行交互。对输入的任何更改都会导致计算自动重新计算,并且结果会实时更新。

由于代码是普通的 Python 代码,因此可以在 Excel 之外使用,例如用于单元测试或作为批处理的一部分。我们的 Python 代码利用了复杂的 Python 包,我们的 Excel 电子表格只需调用相同的 Python 代码。

通过向我们的 Python 模块添加更多的 Garch 函数,我们可以在 Excel 中构建一个完整的 Garch 函数工具包。这可以用来直接在 Excel 中执行分析,甚至构建一个交易应用程序,其中所有的输入和输出都可供 Excel 用户使用。使用 pyxll.plot 函数允许我们在 Excel 应用程序中构建类似仪表板的特性。

参考

构建用户事件数据管道

原文:https://towardsdatascience.com/building-a-user-event-data-pipeline-f57ca088e766?source=collection_archive---------22-----------------------

使用定制数据管道控制您的数据从未如此简单

Unsplash科学高清拍摄的照片

如果您只能为您的企业存储一种类型的分析数据,那么应该是用户事件——他们查看了什么页面,他们点击了什么按钮,他们提交了什么表单,他们购买了什么,等等。这个基本的事件流是大多数数据分析的基础。

公司通常从像谷歌分析这样的一体化平台开始,但最终需要更加定制和灵活的东西。过去,构建定制数据管道需要大量的数据和工程资源,但最近托管服务和开源工具的爆炸式增长大大降低了障碍。现在,大多数公司都可以实现定制数据管道。

用户事件数据管道由几个部分组成。有数据仓库、事件跟踪系统、数据建模层和报告/分析工具。下面的部分将详细介绍每一个选项,并链接到一些流行的商业和开源选项。

数据仓库

典型的应用程序数据库(MySQL、Postgres、MSSQL)针对读写混合查询进行了优化,这些查询一次插入/选择少量的行,可以相当好地处理高达 1TB 的数据。像 MongoDB 这样的非关系数据库更具可伸缩性,但是缺乏 SQL 支持对于大多数分析用例来说是一个障碍。另一方面,数据仓库为您提供了巨大的可伸缩性和完整的 SQL 支持。它们针对读取量大的工作负载进行了优化,这些工作负载会在大量的行中扫描少量的列,并且可以轻松扩展到数 Pb 的数据。

这个空间的主要玩家有 亚马逊红移Google biqquery雪花 。当您的数据工程师希望控制基础设施成本和调优时,Redshift 是最佳选择。当您的工作负载非常大时,BigQuery 是最好的。当你有一个更连续的使用模式时,雪花是最好的。Elvin Li 提供了一个很棒的深度对比如果你想了解更多细节,你应该去看看。

如果你更喜欢开源解决方案,还有 ClickHouse 。它是由俄罗斯搜索引擎 Yandex 创建的,并迅速受到欢迎。

事件跟踪系统

理论上,当用户在你的应用程序或网站上做事情时,你可以实时地直接插入到你的数据仓库中,但这种方法不能很好地扩展,也不能容错。相反,您确实需要将事件排队并定期批量插入它们。自己做起来可能相当复杂,但幸运的是有许多托管服务。 是最受欢迎的选项,但也有一些缺点。它非常昂贵,容易受到广告拦截器的影响,一两个小时才同步一次数据,并且在它生成的模式中缺少一些关键字段(特别是会话和页面 id)。Freshpaint 是一种较新的商业替代品,旨在解决其中一些问题。

除了 Segment 和 Freshpaint 之外,还有许多开源选项(如果您不想自己托管,每个选项都有一个托管服务)。 扫雪机 是最老最受欢迎的,但是需要一段时间进行设置和配置。 舵栈 是一款功能齐全的分段替代。Jitsu 是一个精简的事件跟踪库,专注于让事件尽可能快地进入你的仓库。

数据建模层

原始事件流数据有时很难处理。数据建模就是将原始数据转换成更加用户友好的东西。当你第一次开始时,这一层并不是必需的,但是你肯定会想要添加,所以很高兴知道它的存在。这个领域实际上只有两个主要参与者,都是提供托管服务的开源工具。

Airflow 类似于 Unix cron 实用程序——你用 Python 编写脚本,调度它们每 X 分钟运行一次。Airflow 可用于任何类型的调度任务,但通常用于数据建模。天文学家提供有管理的气流服务。

dbt 则是专门为数据建模而建的。您用 SQL 而不是 Python 来编写转换,并且有对 CI/CD 管道的内置支持来测试您的模型,并在提交到产品之前对它们进行准备。

报告/分析工具

这就是从一体化平台中脱离出来的巨大回报所在。一旦数据进入仓库,有数百种令人惊叹的工具可以与数据进行交互,您可以使用任意多或任意少的工具,而不用担心被供应商锁定。

有许多 SQL 报告生成器,您可以在其中编写 SQL 并创建可以共享的数据图表和图形。 LookerModePopSQLGoodData 是流行的商业选项, Redash 是一个很好的开源替代方案。

还有一些不需要 SQL 知识的自助式拖放工具。有商业选项【Tableau】power bi指示性 以及开源 Apache 超集元数据库

如果你有一个数据科学团队,他们可能会使用 Jupyter 笔记本 直接与仓库交互。在需要时深入原始数据的灵活性对于在您的公司建立强大的数据文化是绝对重要的。

此外,还有一大堆专门的工具。 DataFold 监控您的仓库,并在出现任何异常时向您发出警报(例如,如果在部署后结账转换率突然下降)。 Hightouch 可让您将数据从仓库同步到营销和销售平台。 Whale 是一个开源工具,可以记录和编目你的数据。 重组 允许您将仓库数据集成到您的内部管理工具中。

最后,是时候来个无耻的插播了。使用用户事件数据的最令人兴奋的方式之一是用于 A/B 测试。我一直在开发一个名为 Growth Book 的开源平台,它可以插入你的数据仓库,处理健壮的 A/B 测试分析所需的所有复杂的查询和统计。如果你认为这是你可能会想用的东西,那就去看看,并在 GitHub 上给它一颗星。

结论

现在是构建用户事件数据管道的最佳时机。近年来,托管服务和开源工具的数量呈爆炸式增长,这使得任何公司都可以轻松地在一天内完成一些工作。不再有任何借口不控制您的数据并使用它来推动业务决策。

用 Streamlit 建造 VAE 游乐场

原文:https://towardsdatascience.com/building-a-vae-playground-with-streamlit-aa88a3394c04?source=collection_archive---------22-----------------------

借助 Streamlit,创建和部署 web 应用程序变得非常简单!

这篇博客文章是一个迷你系列的一部分,该系列讨论了使用可变自动编码器构建 PyTorch 深度学习项目的不同方面。

MNIST 数据集上的 Streamlit 应用

第一部分 :数学基础与实现 第二部分 :用 py torch Lightning 增压第三部分 :卷积 VAE、继承与单元测试 第四部分 :部署

在前面的章节中,我们学习了如何使用 PyTorch Lightning 训练两种不同类型的变分自动编码器。第一种是使用线性层的普通 VAE,而第二种是使用卷积层进行特征提取和数据生成的卷积 VAE。

在这一节中,我们将看看如何使用 Docker 和 Streamlit 来创建这个 web 应用程序,在这里我们可以直接与模型进行交互。通过与模型交互并获得即时预测,我们有望更好地了解如何调整 VAEs。

流线型

https://streamlit.io/

Streamlit 是任何数据科学应用程序的绝佳工具。有了它,你可以使用纯 Python 创建漂亮的网络应用,而不需要任何 HTML、CSS 或 JavaScript。Streamlit 最棒的地方在于它的代码非常直观和 pythonic 化。Streamlit 可以帮助创建令人印象深刻的演示,并且是帮助您的项目实现的一个很好的工具!

设计应用

这个应用程序将非常简单,有两个功能重建插值

对于重建,我们只需通过 VAE 传递一个图像,然后查看输出。由此,我们可以从图像重建的质量来评估 VAE。

插值更有趣一点。通过执行插值,我们可以探索 VAE 的潜在空间。首先,我们从数据集中提取两幅图像并进行编码。对于 VAE,这意味着获取μ和 log(σ)向量,并从分布中抽取样本。这个样本给了我们数据的潜在概率分布中的一个点。我们对第二幅图像做同样的处理,得到另一个点。

这里,我们在潜在概率分布中取等间距的点,并在这些点上运行解码器。这允许我们观察潜在的概率分布,并想象这些点是如何被绘制的。理想情况下,我们希望两个数据点之间平滑过渡。

我们可以在 VAE 类中用函数的形式来写这个

VAE 类的插值函数

Conv_VAE类也将继承这个函数,我们不必再重写它

Streamlit 可绘制画布

现在让用户与模型互动。让我们创建一个应用程序,用户可以直接在应用程序上绘图来创建一个全新的数据点,而不是上传图像或从 MNIST 数据集中选择图像!

幸运的是,包streamlit-drawable-canvas已经为我们做了!我们可以使用它来创建一个区域,用户可以使用鼠标来创建一个绘图,我们可以使用它作为模型的输入

https://github.com/andfanilo/streamlit-drawable-canvas

有了这个包,我们可以在任何我们想要的地方创建一个可绘制的画布。所有我们需要做的是设置一些参数,如高度,重量,填充颜色等。我们我们完了。我们可以在应用程序中使用这个组件,然后将用户的绘图保存为 numpy 数组。

实例化 Streamlit 可绘制画布

除此之外,我们还需要一些预处理功能。需要注意的一点是,MNIST 数据集图像只有 28 x 28,这对我们来说太小了,无法绘制。下面是我们的预处理函数要做的事情

1.移除 Alpha(透明)通道
2。转换为黑白
3。缩放至[-1,1]
4。将其转换为具有正确形状的张量
5。调整张量的大小

预处理功能

我们可以将所有这些放入app_utils.py的一个函数中,让我们的 Streamlit 应用程序使用它。

模型加载

现在我们有了生成数据点的方法,我们只剩下加载模型了!

vae_models是一个将类似”conv-vae”的字符串映射到类对象Conv_VAE的字典。我们加载模型并将其设置为eval模式,然后将其返回。

模型加载功能

剩下的就是写一些代码来创建运行插值的按钮,信不信由你,我们已经完成了!剩下的就是在命令行中运行streamlit run app.py,然后进入localhost:8501/访问应用程序。

使用 Streamlit,我们可以使用我们非常熟悉的工具创建非常专业的 web 应用程序,并在很短的时间内完成。让我们花些时间来探索这款应用

saved_models/目录中有 6 种不同的模型,你可以用不同的α值来玩。概括地说,我们的损失函数是MSELoss * alpha + kl_loss,这意味着α值越高,模型优先考虑图像重建质量而不是潜在空间规律性。

太好了,现在我们的应用程序工作了,让我们在网络上分享它。为此,我们将使用 Docker 来封装应用程序,并将其部署在 Heroku dyno 上。

Docker 是什么?

Docker 是一个集装箱工具。通过拍摄当前环境的快照并创建一个隔离的环境来运行应用程序,实现了可再现性。这使得我们可以在任何安装了 docker 的设备上发布和运行我们的代码。除了容器化应用程序,我们甚至可以使用 Docker 来创建可配置和可复制的开发人员环境。Docker 的安装说明可在以下链接中找到:

https://www.docker.com/get-started

我们需要做的是创建一个Dockerfile,它包含 Docker 创建容器所需的所有指令。这个容器将包含我们需要的所有文件,也与我们运行应用程序的环境相同。

对于这样一个简单的 Python 应用程序,有 4 个主要组件。

1.来自 python:3.8-slim-buster

Docker 映像是使用层构建的,这允许 Docker 从现有映像快速构建映像,而不必从头开始构建。从一个 python 映像开始,我们得到的是一个 Linux Ubuntu 发行版,它包含一些重要的 Python 包并安装了 Python 3。

2.工作目录和副本

WORKDIR命令为容器创建一个工作目录。这将作为./路径,防止容器过于混乱。COPY命令只是将所有必要的文件复制到映像中。类似于。gitignore 我们可以创建一个. dockerignore 来指定任何我们不想复制的文件,比如我们正在使用的数据集。

3.运行 pip 3 install-r requirements . txt

RUN允许 docker 运行项目所需的任何终端命令。我们可以运行 pip install 来安装项目所需的软件包。需要注意的一点是,我们为 PyTorch 安装了 CPU 专用版本。这避免了安装额外的 CUDA 驱动程序的需要,并保持容器较小。

  1. CMD

开始运行应用程序的最后一个命令。这基本上是用于在本地环境中运行 Streamlit 的终端命令

首先,在命令行中运行docker build -t <name_of_image> .。这告诉 Docker 在当前目录中查找 Docker 文件,并使用它构建一个映像。这一步需要相当长的时间,因为 PyTorch 是一个相当大的包

一旦建立了映像,我们可以使用命令docker run创建一个容器

默认情况下,容器与外部环境完全隔离,要访问我们的应用程序,我们必须使用-p标志打开一个端口。完成这项工作的完整命令是docker run -p 8501:8501 <name_of_image>,我们可以在localhost:8501/看到这个应用程序

这可能看起来有点罗嗦,但是将我们的应用程序归档的好处是,我们可以毫无问题地与其他人共享它。我们可以将图像推送到 Docker hub(Docker Images 的 Github ),任何人都可以毫无问题地运行这个应用程序。除此之外,容器化在部署应用程序时也会有所帮助。

部署

很好,现在可以将最后一部分部署到网络上了。为此,我们将使用 Heroku a PaaS(平台即服务),它允许我们部署 web 应用程序,而不必担心维护基础设施。这真的很容易使用,免费层通常是足够的个人项目。有几种方法可以部署到 Heroku,但是我们将使用容器方法。

登录 Heroku 账号后,我们首先需要创建一个 app。我们可以通过给应用程序命名并设置区域,非常容易地从仪表板创建应用程序。记住应用程序名称,因为我们将在部署中使用它。

使用 Heroku 的一个重要注意事项是,端口是随机分配给不同的应用程序的。Heroku 提供给 app 的端口是不固定的,但它将作为环境变量$PORT给出。因此,我们必须对之前的 docker 文件做一个小小的修改。

Heroku 部署的 Dockerfile

这样做的目的是更改最终命令,使其使用$PORT环境变量,而不是分配默认端口 8501。

最终部署步骤

第一步是登录 Heroku

heroku login

然后,我们指定用于 Heroku 构建的 docker 映像

heroku container:push -a <app_name> web

这个命令成功后,剩下唯一要做的就是释放应用程序。

heroku container:release -a <app_name> web

就是这样!该应用程序现在在 Heroku 提供的 URL 上运行。

希望这篇文章向您展示了如何使用 Streamlit 以及部署 web 应用程序所需的一些步骤来轻松构建 web 应用程序!

请随意查看 GitHub 上的完整代码,非常感谢您的任何反馈!

Github:https://github.com/reoneo97/vae-playground
LinkedIn:https://www.linkedin.com/in/reo-neo/

从头开始构建一个普通的人工神经网络

原文:https://towardsdatascience.com/building-a-vanilla-artificial-neural-network-from-scratch-in-r-5f03dfec628b?source=collection_archive---------8-----------------------

从基础到实际实施

什么是神经网络?

人工神经网络(ANN)是一种现代机器学习方法,它试图模仿人脑学习和处理信息的方式。

来源:https://pix abay . com/插图/人工神经网络-ann-3501528/

如今,人工神经网络广泛用于开发人工智能驱动的产品,对于计算机视觉(CV)和自然语言处理(NLP)中的不同应用,存在许多不同的神经网络架构:

  • 面部识别
  • 语言翻译
  • 目标检测
  • 语音识别
  • 自动更正文本
  • 创造艺术

可能性是无穷无尽的,清单还在继续…

它们是如何工作的?

通过将人工神经网络分解为基本组件,可以更好地理解人工神经网络:

  • 前馈机制
  • 重量优化

前馈机制

该组件负责使我们的模型能够进行预测。在其最简单的形式中,前馈机制首先将线性函数应用于给定的输入,然后使用称为“激活”的非线性函数将结果转换为期望的输出。

让我们通过考虑由一组输入、一个隐藏神经元和一个输出神经元组成的简单模型来可视化这些操作:

  • x:输入的矩阵集合(预测器)。
  • w:一些可以被视为输入和输出之间关系的斜率/变化率的矩阵,称为权重
  • b:类似于“y 轴截距”的常数,称为偏差
  • g(a): 应用于线性输出‘a’的非线性‘激活’函数(一些最流行的激活函数的例子):
    -整流线性单位(ReLU): max{0,x }
    -Sigmoid:1/(1+exp {-x })
    -双曲正切(tanh): sinh(x) / cosh(x)

当处理由几个预测值组成的数据时,我们通常需要更多的隐藏层和神经元,但我们仍然应用与上述相同的操作顺序。唯一的区别是,我们的模型变得明显更加复杂,使得最终训练我们的模型变得更加困难。

重量优化

我们如何知道前馈机制做出的预测实际上是正确的?

人工神经网络通过优化与预测器相关的权重矩阵来学习更好地逼近目标变量。与前馈组件相比,优化模型权重是一个不太直观的过程,因此无需深入研究所需的严格数学,我将给出继续本教程所需的概念性理解。

反向传播是一种先进的数学算法,结合了链式法则和相应变量的偏导数,计算权重矩阵的梯度。

那么,既然有了梯度,我们如何优化权重呢?

随机梯度下降 ( SGD ),通过在选定数量的训练迭代(时期)上以指定的收敛速率(学习速率)最小化成本函数,利用反向传播算法来调整模型权重。由于梯度是一个常数,在每个时期,我们调整权重,直到收敛到全局最优值。

希望这个图表可以帮助我们了解 SGD 在每个时期的目标。

在 R 中构建模型

现在我们有了所需的基础知识,我们终于可以开始构建模型了!!!

我将通过一个简单的指南从头开始构建一个“香草”人工神经网络(不使用任何内置模块)。我们将建立的模型类型将是一个回归变量,因为预测变量和响应变量都是数字。

为什么从零开始?

我也曾经问过自己同样的问题,但是一旦我被迫从头开始编写自己的代码,我注意到我开始在更深的层次上理解底层的概念(及其乐趣)。

模型架构

我们将要构建的人工神经网络将由一组输入、一个包含 5 个神经元的隐藏层和一个最终输出层组成。让我们来看看组装模型所必需的构件:

  • 输入数据( X ):来自区间[-2,2 ]上连续均匀分布的 60 个模拟随机变量。
  • 响应(Y):X 的某三角函数,( f(X) ) = cos(2x +1)
  • 激活功能:乙状结肠
  • 权重矩阵( w1,w2 ):大小为{N * (p + 1),Q * (N +1)},其中 N 是每层中隐藏神经元的数量,p 是不同预测器的数量,Q 是输出(1)的维数。最初,随机模拟模型权重,然后通过我们的随机梯度下降算法进行优化。
  • 成本函数:使用误差平方和( SSE )来评估我们模型的预测质量,因此我们将使用二次成本

让我们看看我们如何在 R 中定义这些变量:

前馈机制

现在我们已经有了变量,我们定义我们自己的函数,我们将用它来预测我们的输入向量。

反向传播

首先,我们必须定义激活函数的导数,因为它是通过网络反向传播时的关键特征:

让我们仔细看看为了执行反向传播我们需要概述的必要操作。

分解代码:

  • preds :最小化成本函数所需的模型预测
  • derivCost :由于我们使用上证综指作为模型误差的衡量标准(二次成本),对预测值求导会产生上述结果
  • (dW1,dW2) :最初,我们用来存储权重矩阵梯度的空矩阵。

理解代码块的其余部分需要对反向传播算法有更深入的理解。这个视频应该可以达到目的:

执行反向传播很不直观,而且这些只是对通过隐藏层的一组输入的计算。随着更多的层被添加到网络中,计算梯度在计算上变得昂贵。

模特培训

如果你已经注意到了,我们还没有真正使用我们在代码块中定义的任何函数。在这里,我们通过调用所有前面的函数来执行模型训练,从而将所有东西联系在一起。

我们定义了随机梯度下降函数来优化我们的权重和跟踪训练误差。

本质上,我们将在每次迭代时通过选择的学习率(通常是从 0 到 1 的浮点数)来调整权重矩阵,同时我们将在每个时期将 SSE 值存储在一个空矩阵中。

最后,我们的模型参数通过调用我们的 SGD 函数获得…(我选择 200 个历元,因为通过反复试验,它给出了最好的结果)。

模型评估图

训练误差

这是我们的训练误差在历元数(200)上的图,我们看到性能在开始时有很大提高,随后在每次连续迭代后模型误差稳步下降。

***注意:我们省略测试误差图的原因是我们实际上没有测试集,因为我们的预测值是从随机均匀分布模拟的,而不是从实际数据集模拟的。

实际值与预测值

让我们看看我们的模型如何通过绘制原始响应值与预测值来预测目标变量:

还不错!我们的模型在解释响应变量方面做得很好,性能似乎偏向右尾,但没有过度拟合的迹象。

最后的想法

神经网络负责为我们今天看到的最先进的人工智能技术提供动力。我们从头开始浏览了构建简单的香草人工神经网络架构的指南。

现在,您已经对神经网络如何工作有了基本的了解,我鼓励您探索更高级的模型架构,这些架构支持我们今天拥有的一些最好的人工智能产品/服务。

这里是一个开始的好地方:

我真的希望你喜欢这个小教程!如果你觉得有用或有趣,请随意评论,并订阅关于机器学习和其他技术主题的未来文章:)

***获取完整 R 脚本:

https://github.com/tristanoprofetto/neural-networks/tree/main/ANN/Regressor

构建一个计算科恩 Kappa 系数的 Web 应用程序

原文:https://towardsdatascience.com/building-a-web-app-to-calculate-cohens-kappa-coefficient-39781fda0cf?source=collection_archive---------40-----------------------

混合使用 streamlit 和 scikit-learn

图片来自 Unsplash

介绍

在医疗保健研究中,经常有多个小组或个人在研究同一种情况或变量。他们独立地收集数据,但是期望,并且经常需要,报告发现的人之间的一致性。因此,设计良好的程序必须包括各种数据收集者之间的系统测量协议。数据收集者之间的一致程度被称为 评分者信度

从历史上看,衡量两个评分者之间的可靠性是通过简单的百分比一致度来实现的,该百分比表示分数总数中一致度的总数。然而,这并不能控制两个计分员无意中达成一致的可能性。

因此,Cohen 的 Kappa 系数被开发出来以调整这种可能性。

简而言之,科恩的 Kappa 是一种衡量两个评分者(法官、观察员)之间可靠性的方法,修正了偶然发生一致的概率。

更多关于科恩卡帕系数的阅读,请查看以下内容:

https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3900052/

构建一个简单的 Kappa 统计应用程序

我希望这个应用程序能够创建一个简单的方法来输入数据,以计算 Cohen 的 Kappa 系数。为此,我使用了 streamlit ,这是一个使用纯 python 快速创建数据科学应用的开源框架,以及 scikit-learn ,这是一个用于机器学习和数据分析的开源库。

https://streamlit.io/ https://scikit-learn.org/stable/

以下是使用 streamlit 和 scikit-learn 构建简单 kappa 统计应用程序的教程。

搭建舞台

让我们从导入我们需要的库开始。最重要的是,我们将 scikit-learn (sklearn)用于我们的功能,将 streamlit 用于我们的用户界面。

import pandas as pd
import streamlit as st
import sklearn
from sklearn import metrics
import os
import numpy as np

from urllib.error import URLError
import matplotlib.pyplot as plt

import base64

标题和文本

Streamlit 让在我们的应用程序中添加文本变得简单。

为此,我们使用 streamlit.titlestreamlit.text. 我们使用 streamlit.sidebar. 向我们的侧边栏添加额外的文本

st.title("Kappa Stat Calculator")
st.text("Measuring interrater reliability")
st.sidebar.header("About")
st.sidebar.text("""The kappa stat calculator uses the
power of scikit-learn to quickly
calculate cohen's kappa statistic
between two raters.Upload a csv file with columns
specifying your raters names or ids.
""")

标题和文本

文件上传

接下来,我们可以使用 streamlit.file_uploader 将文件上传到我们的应用程序中。

df = st.file_uploader("Choose a file")

文件上传

拆分成列

对于下一部分,我们将屏幕分成两列,以保持易用性和交互性。这可以通过 streamlit.beta_columns 来完成。

col1, col2 = st.beta_columns(2)

左列

左栏将显示我们的数据框,使用 pandas 处理我们的数据。我们使用 streamlit.dataframe 并添加 df.style.highlight 以使探索数据更容易,从而暴露潜在的差异。

with col1:
   st.dataframe(df.style.highlight_max(axis=0)) 

包含评分者列的数据框架

右列

右栏将显示一个图表,以便进一步浏览数据。我们可以用 streamlit.linechart 查看折线图。

with col2:
   st.linechart(df)

显示数据帧的牛郎星线图

输入字段

接下来,我们创建文本输入字段来指定数据帧中的列。在这种情况下,我们的数据有两个名为人员 1人员 2 的评价人。

person1 = st.sidebar.text_input("Enter column name for person 1")
person2 = st.sidebar.text_input("Enter column name for person 2")

文本输入字段

功能

为了使用 scikit-learn 的 cohen's kappa 统计计算器,我们使用了sk learn . metrics . Cohen _ kappa _ score并显示了一个带有 streamlit.button. 的按钮

kap = sklearn.metrics.cohen_kappa_score(y1, y2,labels=None, weights=None, sample_weight=None)

具有 sckit-learn 功能的 Streamlit 按钮

结果和庆祝!

我们的函数将使用 streamlit.write 在按钮下方显示 Cohen's Kappa 统计数据。

st.sidebar.write('Result: %s' % kap)

卡帕统计量

然后我们用流线型气球庆祝!!!

外卖食品

本文简要概述了如何为一个通用的医疗保健研究指标创建工具。我希望您对 Cohen 的 Kappa、streamlit 和 scikit-learn 有了更好的理解。

这个项目的源代码可以在这里找到

更多来自作者的故事:

感谢您的阅读!!

用 Valohai 和 Superb AI 构建 YOLOv3 管道

原文:https://towardsdatascience.com/building-a-yolov3-pipeline-with-valohai-and-superb-ai-45275aa5ebde?source=collection_archive---------44-----------------------

每次训练模型时,建立管道的价值都会增加

作者图片

本文展示了一个管道示例,该管道集成了 Valohai 和 Superb AI,使用预训练的权重和转移学习来训练计算机视觉模型。对于该模型,我们使用 YOLOv3,它是为实时对象检测而构建的。

在这个例子中,Superb AI 用于管理训练数据,并产生可用于训练的标记数据集。另一方面,Valohai 接收这些数据,并通过训练步骤和批量推理步骤来运行流水线。我们在这里写了一个关于这些平台如何互补的更全面的分析。

  • Superb AI 是一个 ML DataOps 平台,帮助计算机视觉团队自动化和管理整个数据管道:从摄取和标记到数据质量评估和交付。
  • Valohai 是一个 MLOps 平台,帮助在任何云或本地硬件上构建和运行全自动培训管道。非常适合计算机视觉和深度学习。

项目详情

  • 储存库:https://github.com/valohai/yolov3-tf2
  • 型号: YOLOv3-416 ( 重量)
  • 框架: Tensorflow 2.4.0 + OpenCV 4.1
  • 模式:迁移学习
  • 数据集: ~3000 张图像(COCO 2017 验证集)
  • 类:人,车,椅子,书,瓶子

注意:管道是通用的,这意味着使用 Superb.ai 平台上的任何数据集和任何种类的类,使用符合 YOLOv3 模型的任何权重进行训练都是微不足道的。这里列出的只是我们使用的默认值。

在高超的人工智能中准备数据

首先,我们需要在高超的人工智能平台上创建一个新项目。选择任何名称和描述。对于这个例子,数据类型将是图像和注释类型框。

作者图片

然后添加五个类(人,车,椅子,书,瓶子)来匹配我们的 COCO 数据集,我们会上传到平台。

作者图片

人们也可以利用高超的人工智能的自动标记功能,但在这个例子中,我们将在 COCO 数据集中已经有了标签。现在我们已经在平台中准备好了项目和数据集模板,是时候使用高超的 AI SDK 和 CLI 来转换和上传实际的数据+标签了。遵循这个示例存储库中的说明。

一旦转换和上传完成,该项目应该包含 3000 多张图片,随时可供瓦罗海的培训管道使用。

作者图片

瓦罗海训练管道

在瓦罗海,培训渠道是任何成功项目的关键组成部分。我们的示例管道由四个步骤组成。

作者图片

convert-superbai步骤从 Superb.ai 中提取数据,根据 Superb.ai 标记拆分训练集和验证集,最后将这两个集转换为。模型的 tfrecord 文件。

weights步骤从 Joseph Redmon 的网站下载预训练的权重,将它们转换为 Tensorflow 检查点,最后通过对单幅图像运行推理来验证它们是否正确工作。

train步骤基于超参数在 GPU 环境(其他步骤默认为 CPU)中训练模型。

最后,detect步骤对作为该步骤输入给出的一组图像的新训练模型进行推理。这一步的输出是图像的新版本,边界框和标签呈现在原始图像之上。

每个步骤(通常)都是一个 Python 文件。这里是我们的weights步骤的 weights.py 的源代码。它有一个参数weights_num_classes(预训练模型使用了多少个类别)和一个输入weights(实际预训练权重)。

参数和输入被提供给对 Valohai SDK 的valohai.prepare()调用。Valohai CLI 可以解析这个调用,以自动生成参数化该步骤所需的配置。

管道本身在 pipeline.py 中定义,它也使用新的 SDK。

在瓦罗海建立管道

首先,在 Valohai 中创建一个新项目,并从项目设置中链接 GitHub 示例存储库

作者图片

现在,您可以从 pipelines 选项卡创建一个新的管道,并从蓝图下拉列表中选择train-superbai

与卓越的人工智能相结合

在运行管道之前,您需要告诉它从哪里获取数据。图像和标签是两个独立的 URL,这意味着从 Superb.ai 到 Valohai 的两次复制粘贴。

图片:设置>通用(Superb.ai)

作者图片

标签:导出>导出历史(Superb.ai)

作者图片

管道输入(Valohai)

作者图片

运行管道

现在,我们已经在卓越的人工智能平台中集成了我们的数据集,我们的管道已经准备就绪!

Valohai 记录了管道每一步的所有输入、参数、日志和指标。这些是输入、参数、Docker 图像、环境和执行train步骤的其余信息:

作者图片

这是训练代码打印出的所有日志的一部分。

作者图片

这些是由培训代码打印出来的指标。Valohai 将所有打印的 JSON 解析为一个度量(在 Valohai 中称为元数据)。

作者图片

最后,在detect步骤的输出选项卡中,我们可以用一些实际的图像来检查模型的执行情况。

作者图片

对标签进行迭代

作者图片

一旦您知道您的模型需要优化的地方,因为它与数据有关,您可以通过他们的 SDK 将您的模型输出快速发送回 Superb AI 套件以进行模型辅助标记,从而快速启动您的下一次迭代。

为什么为您的 YOLOv3 模型建立一个端到端的管道是显而易见的

在本文中,端到端管道建立在两个专门构建的工具之上:用于数据管理的 Superb AI 和用于模型生命周期管理的 Valohai。这个示例中的整个设置可以在几个小时内完成,但是每次训练模型时,前期工作的价值都会增加。

训练数据集随着时间的推移而发展,它可以独立于训练管道被重新标记和改变。类似地,训练管道中的代码可以被迭代,同时保持端到端管道的完整性以用于连续操作。此外,随着训练数据集和建模复杂性的增长,Valohai 上的训练管道可以轻松扩展到更强大的 GPU 实例。

最初发表于https://valohai.com

在组织中建立人工智能文化

原文:https://towardsdatascience.com/building-ai-culture-in-organisations-11d660b04768?source=collection_archive---------32-----------------------

如何建立大型人工智能驱动的工程团队

图片来自 pixabay

我们在这里谈论什么?

围绕人工智能的炒作可能非常真实,但公平地说,任何有能力改变世界的技术都必须如此。坐下来想想过去几天,你可能会在社交媒体上找到一些关于人工智能将如何改变我们生活方式的参考资料,特别是在医疗保健、金融、娱乐或旅游领域。任何关注科技新闻或与数字化转型有某种关联的人,肯定已经了解智能机器。他们中的一些人可能会不经意地认为它只是机器人技术的另一个花哨的词,或者它将如何在某一天夺走他们的工作,但它有这么多必须谈论的东西。人工智能乐观主义者认为,这只是一场革命的开始,这场革命有能力改变我们所知的世界的一切。

这导致了一些组织采用人工智能策略来构建解决方案,并为他们的业务增加更多价值。有许多关于如何成为人工智能驱动的组织的猜测,但它们往往无法融合,因为有多个维度来理解人工智能。作为一名企业主,重要的是要知道采取什么途径来拥抱人工智能,吸收组织的文化,同时将风险降至最低,并小心行事。

文化需要不断的培养和关注。它需要一段时间的演变,需要不断的努力。一个人如何开始在一个组织内的不同团队之间建立正确的文化?考虑到它是昂贵的,难以理解的,甚至更难正确实施,如何进行呢?谨慎的做法是为人工智能战略创建一个框架,以建立与组织愿景一致的正确文化,从而提供切实的好处。使用人工智能的创新文化…

双击 AI 路径

一个组织面临的最大挑战是弄清楚从哪里开始。确定人工智能需要解决的重要业务用例。下面的框架可以用来创建一个组织范围的人工智能策略,可以被不同的团队采用。

作者图片

  1. 制定正确的期望并设定目标

不管一个组织如何看待它对人工智能的最新认识,就人工智能实际上是什么以及它如何与他们的业务相关进行头脑风暴并形成观点是极其重要的。获得对人工智能及其工作原理的基本理解需要时间和努力。对于跨职能团队来说,坐下来讨论这对他们意味着什么是非常重要的。这并不意味着温习数学技能并开始解复杂的方程,而是要知道人工智能有多强大,以及如何使用它。在进行任何巨额投资之前,该组织真的能从中受益吗?它解决什么样的问题?

这可能需要广泛的阅读和讨论,从会议中收集见解。从其他已经过了这个阶段的人的工作中获得灵感总是有帮助的。通常很难鼓励人们走出舒适区,收集如何与他们的业务相关的想法。但是这个阶段对于在团队中引入正确的文化非常重要。一种有足够自由的文化,有利于创新和对新兴技术的积极氛围。远离悲观主义者总是有帮助的,悲观主义者相信“这也会像其他人一样随着时间的推移而消失,所以为什么要学习它呢”。人工智能不是一个工具或一个库或一项技术,但它是一种范式转变,一种前所未有的高效解决复杂问题的方式。它会留在这里,所以跳上来..

2。探索未知

弄脏你的手。可以挑选一些流行的用例来加深对人工智能实际工作方式的理解。找出其他人喜欢的各种工具、框架和库,并学习它们来开发 AI 解决方案。一个问题如何解决或者通常由行业内的其他人来解决。学习一些基本的机器学习技术。确定回归与分类问题、数据清理需求、基础设施需求等。找到一种方法来比较使用两种不同算法的结果。弄清楚聊天机器人是如何开发的,计算机视觉问题是如何解决的,预测解决方案是如何建立的。训练数据集高度偏斜怎么办?如何设置数据和 ML 管道?达到更容易提供基于人工智能的商业问题解决方案的阶段,或者至少对何时使用哪种算法有一个看法。

必须了解人工智能解决方案在生产中是如何部署的。如果生产中的真实数据与培训中使用的数据相差很大怎么办?这可以通过在生产运行时重新训练人工智能模型来解决吗?还是需要离线分析和训练?多少数据足够用于训练目的?它会对精确度产生什么样的影响?

实验-分析-讨论-重复。

3。就这么做——开发多个用例

在这一阶段,团队应该渴望开发小的解决方案来解决一些与组织业务相关的实际问题。构思想法、进行多次概念验证、演示、收集反馈、集思广益和改进。这是团队真正需要合作的阶段,以展示他们在人工智能领域可以做什么,以及它如何帮助业务。这个阶段是最重要的,因为它给了决策者对团队开发的能力的信心。在这一阶段需要做出许多决定,如团队成员的资金、基础设施等。确定人工智能与组织的确切相关程度。这个阶段应该提供足够的清晰度来决定在这个过程中应该进行多少投资。获得启发,看看是从头开始做“人工智能研究”有意义,还是只是用可用的东西做“应用人工智能”,或者两者兼而有之。

4。成长和即兴创作

基于人工智能的解决方案需要持续的关注和监控。总是在寻找新出现的和可用的东西。人工智能是一个如此快节奏的领域,每天都有新的研究发表。设定了新的基准,在准确性、性能和效率方面对过去的人工智能模型进行了改进。不断完善解决方案,让它们变得更好。最终,这导致团队即兴发挥并提出新的创新解决方案的阶段。人们可以找到以前从未探索过的道路,并取得重大突破。这以组织的名义建立了专有的解决方案或专利,并提供了超越竞争对手的优势。

围绕人工智能治理建立指导方针。解决方案的精确度应该是多少,才能被组织和客户所接受?如何最小化人类的偏见?谁领导负责人工智能工程的团队?定义组织内的角色和职责,以建立清晰的问责制。

5。培训和传播意识

当务之急是帮助组织内的其他团队理解人工智能,并传播对所开发的解决方案的认识。一个组织对基于人工智能的计划了解得越多,超越他人的机会就越大。这可能需要提供培训课程、发布白皮书、时事通讯、演示等。其他的就不用从头开始了。团队应该互相帮助学习、激励和提高。有时,一个想法可能会通过这些会议转化为有用的业务用例。

当涉及到像人工智能这样复杂的事情时,合作是关键。此外,任何基于人工智能的系统都是为了解决由产品团队确定的真实业务问题,由销售团队出售,并由营销团队打上品牌。他们都需要知道它是如何工作的,具体是做什么的。因此,人工智能的学习路径需要被各个团队一起采用。正如 IT 界的一句谚语所说,不管怎样,隐居的工作不会有好结果。

需要说的话

很明显,朝着正确方向迈出的一小步真的可以推动整个组织拥抱创新文化。这是一个不断努力的过程,本质上,这就是目标本身。避免不必要的不和谐,继续前进。

许多人相信人工智能将来会做大事。在未来,人工智能将使我们更有效率,更有生产力。在未来,人工智能掌握着大规模解决全球问题的关键。人工智能帮助我们做出更好决策的未来。一个超越人类的未来。

但是有些人相信,未来已经到来..

构建人工智能概念验证

原文:https://towardsdatascience.com/building-an-ai-poc-b7b1077e492e?source=collection_archive---------32-----------------------

开始到结束/迭代原型/工作流

在云中建立原型,并部署在插入信用卡大小的计算机中的神经网络加速器上

我个人项目的主要要求是:

一种可充电的电池供电的小型设备,连接有超广角摄像头,能够在不同的照明条件下检测部分遮挡的移动人类,而无需任何互联网接入。

这篇文章是一个从头到尾的演练——从研究、迭代原型到设置和部署功能代码。

英特尔 DevCloud for Edge (免费):浏览器中的快速迭代原型制作
英特尔 OpenVINO 工具包 (免费):预先训练好的模型动物园和推理 API
NCS 2(75 美元):神经网络加速器硬件
树莓 Pi 4 ($美元)

还可以选择直接在 Raspberry Pi 上运行 TFLite,利用板载计算资源,为主应用程序留出很少的空间。本文中推理硬件和软件的工作流程和选择是快速建立原型的更灵活的选择之一。你可能会发现这种方法对你下一个需要人工智能的伟大想法很有用。

1.在线搜索可用的预训练模型

OpenVINO Model Zoo 网页是一个很好的资源,可以找到英特尔和公共的预训练模型,这些模型带有随时可用的视觉截图。

选择符合要求的型号。例如,在我的情况下,前置摄像头的放置——同时在准确性(精度)与复杂性 (GFlops) 之间取得平衡。行人检测 adas-0002 预训练模型似乎是我的应用程序的一个很好的候选对象。

对于像我之前的帖子这样的定制培训工作流,在开始之前,从基准测试网页提前获得对目标硬件上的模型性能的粗略估计将会很有帮助。

2.面向 Edge 的英特尔 DevCloud 原型

在投入时间进行安装之前,让我们对该解决方案在目标设置中的表现有所了解,例如特定 fps 下的鱼眼镜头失真、环境照明和分辨率。

新的 Jupyter 实验室界面带有示例,可以非常方便地在 CPU 上借用代码灵感、调试和推理,这些 CPU 包括英特尔凌动、酷睿 i5、i7、i9、至强、iGPU、NCS2 (1 个 VPU)、Mustang (8 个 VPU)和 FPGA。

2.a .从模型动物园下载模型

“我的笔记本”目录下创建一个新的笔记本,并通过从 OpenVINO 模型动物园发现中指定确切的 名称来下载感兴趣的预训练模型。

!/opt/intel/openvino/deployment_tools/tools/model_downloader/downloader.py --name pedestrian-detection-adas-0002 -o models

2.b .在 CPU 上快速测试,快速失败

通过直接连接鱼眼镜头摄像机,使用默认的 Windows 10 摄像机应用程序在目标位置录制一个 "test.mp4" 片段。使用 IntelliSense 与 TAB 键的组合以及来自示例笔记本的代码灵感来学习 OpenVINO API 流程并进行非常快速的测试。

没什么特别的(例如,异步代码、多请求...)只是快速编码!
SHIFT + ENTER 在新的笔记本单元格中运行下面的代码。

from openvino.inference_engine import IECore
from matplotlib import pyplot as plt
import cv2, datetime# Plugin Initialization
ie = IECore()
net = ie.read_network(model="./models/intel/pedestrian-detection-adas-0002/FP16/pedestrian-detection-adas-0002.xml", \
                      weights="./models/intel/pedestrian-detection-adas-0002/FP16/pedestrian-detection-adas-0002.bin")# Input/Output Preparation
input_blob = next(iter(net.input_info))
output_blob = next(iter(net.outputs))
n, c, h, w = net.input_info[input_blob].input_data.shape# Load the network
exec_net = ie.load_network(network=net, device_name="CPU")cap = cv2.VideoCapture("test.mp4")while (cap.isOpened()):
    has_frame, orig_frame = cap.read()

    if not has_frame:
        break

    in_frame = cv2.resize(orig_frame, (w, h))
    in_frame = in_frame.transpose((2, 0, 1))
    in_frame = in_frame.reshape((n, c, h, w))

    results = exec_net.infer(inputs={input_blob: in_frame})

    detections = results[output_blob][0][0]
    for detection in detections:
        if detection[2] > 0.50: # threshold
            xmin = int(detection[3] * orig_frame.shape[1]) # 1:w
            ymin = int(detection[4] * orig_frame.shape[0]) # 0:h
            xmax = int(detection[5] * orig_frame.shape[1])
            ymax = int(detection[6] * orig_frame.shape[0])
            cv2.rectangle(orig_frame, (xmin, ymin), (xmax, ymax), (0, 125, 255), 3)

    # display result
    orig_frame = cv2.cvtColor(orig_frame, cv2.COLOR_BGR2RGB)
    plt.imshow(orig_frame)
    plt.show()cap.release()
cv2.destroyAllWindows()

代码是功能性的!点击停止以防止单元随着每一帧结果无限扩大。

2.c .提交 NCS2 的作业

将目标设备从 CPU 更换为万千

exec_net = ie.load_network(network=net, device_name="MYRIAD")

此外,测量在 NCS2 上执行的时间。在本地设置真实设备之前,预先在 DevCloud 上验证非常有用。

start_time = datetime.datetime.now()
results = exec_net.infer(inputs={input_blob: in_frame})
end_time = datetime.datetime.now()

由于我们无法直观地看到 NCS2 作业的结果,通过用以下代码替换显示结果代码段,将结果保存到文件中。

# Write single image to file and exit
duration = round((end_time - start_time).total_seconds() * 1000)
time_st = 'NCS2 Inference time: {:.2f} ms'.format((duration), 2)cv2.putText(orig_frame,time_st, (10,60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 6)cv2.imwrite("result.png", orig_frame)
    break

要提交具有上述更改的 NCS2 作业,通过在开头添加 magic 命令并再次运行单元,将其写出到 python 文件中。

%%writefile test_code.py

在新单元中,创建作业脚本以运行 python 代码文件。

%%writefile test_job.sh
cd $PBS_O_WORKDIR # required for running remote job
python3 test_code.py

最后,通过在新的单元格中运行下面的代码来运行作业。

job_id_ncs2 = !qsub test_job.sh -l nodes=1:idc004nc2
print(job_id_ncs2[0])

您将在几秒钟内看到生成的图像和额外的作业信息文件。这些文件对于运行时调试任何错误都很有用。在多次运行的情况下,
文件名将包含打印在下面的 ID
点击目录 刷新按钮如果一段时间后你没有看到任何变化。

此时,我们可以开始在本地进行真正的设置。

3.在 RaspbianOS 上设置 OpenVINO 和 NCS2

以下是官方文档中经过简化和验证的步骤。

3.a .树莓 Pi 上的 OpenVINO 安装

  • 导航到软件包存储库以获得适当的最新版本。
  • 寻找l _ open vino _ toolkit _ runtime _ raspbian _ p _<版本>。tgz 右键“复制链接地址”获取文件路径。

在一个新的终端窗口中,如果你不在乎获取最新的版本,你可以盲目地按顺序运行下面的命令。

cd ~/Downloads/wget [https://storage.openvinotoolkit.org/repositories/openvino/packages/2021.2/l_openvino_toolkit_runtime_raspbian_p_2021.2.185.tgz](https://storage.openvinotoolkit.org/repositories/openvino/packages/2021.2/l_openvino_toolkit_runtime_raspbian_p_2021.2.185.tgz)sudo mkdir -p /opt/intel/openvinosudo tar -xf l_openvino_toolkit_runtime_raspbian_p_2021.2.185.tgz --strip 1 -C /opt/intel/openvinosudo apt install cmakeecho "source /opt/intel/openvino/bin/setupvars.sh" >> ~/.bashrc

搞定了。此时,关闭所有终端并重新打开一个新终端。

3.b .设置 NCS2 设备

sudo usermod -a -G users “$(whoami)”

注销系统,重新登录以使更改生效,并运行以下命令来安装 USB 规则。您应该得到一个类似“Udev 规则已经成功安装”的确认消息。

sh topt/intel/openvino/install_dependencies/install_NCS_udev_rules.sh

3.c .将 NCS2 插入 Raspberry Pi 运行

假设只插入了一个相机设备,在 OpenCV 代码中用相机 0 替换 test.mp4。

cap = cv2.VideoCapture(0)

用下面的 OpenCV imshow 代码替换显示结果代码部分,并注释掉 matplotlib 导入代码。

cv2.imshow(“Output “, orig_frame)
if cv2.waitKey(25) & 0xFF == ord(‘q’):
   break

满足基本要求!
继续与 PoC 的其余部分集成。

结论

  • 虽然 OpenVINO model zoo 并不能解决世界上所有的人工智能问题,但它确实包含了各种各样预先训练好的优化模型,用于快速原型制作。
  • 像 Google Colab 一样,DevCloud for Edge 可以方便地进行快速原型开发,还可以在云中的各种英特尔设备上进行测试。
  • 对于像 Raspberry Pi 这样的低功耗和计算设备,NCS2 是一个很好的附件,可以快速启动 AI PoC。

建立一个异常检测系统?它必须满足的 5 个要求

原文:https://towardsdatascience.com/building-an-anomaly-detection-system-5-requirements-it-must-meet-23c9527e7760?source=collection_archive---------33-----------------------

成功解决方案的建议——从信号分析到大规模分享见解

阿里·哈坚Unsplash 上的照片

介绍

如果您已经找到了自己的路,那么您的企业很可能已经将异常检测确定为大幅降低成本或寻找新增长机会的一种方式,并且您正处于规划解决方案的早期阶段。

构建自己的异常检测系统是完全可能的——但是要想成功,你需要满足这五个要求。

这五个测试不仅仅会节省你的时间和精力,它们是人们实际使用你的系统和看一次就把它和其他听起来不错但在现实生活中不起作用的技术解决方案一起扔进垃圾箱的区别。

因此,如果你只是为了乐趣而从事一个数据科学项目,并且你享受这个过程,就像达到最终目标一样——无论如何,请随意跳过这篇文章,继续探索你能做什么。

但是,如果你真的想建立一个使用时间序列数据的最先进的系统——从信号分析到大规模呈现输出——请继续阅读。

(还不熟悉异常检测?这里有几个初级读本):

要求 1——您的系统需要能够处理现实生活数据的复杂性

克里斯·利维拉尼在 Unsplash 上的照片

如果用户没有通过“嗅觉测试”,他们会发现很难相信系统的输出。直觉对用户很重要。如果他们看不到某些东西是如何组合在一起的,他们就不会相信这些东西——例如,为什么会标记异常,趋势和季节性是否被正确计算?特别是对于被认为是异常的数据点,这有助于建立对系统能力的信心。

一个好的方法是将信号分解成关键部分:趋势、季节性、残差(参见 Hyndman 等人的快速提示)。对残差执行检测。这就是“噪音”。这不一定是特定的分布。现实生活并不总是那么简单!

此外,很少有商业数据集预先标记了异常,历史异常不太可能已经被识别出来!

推荐:

  1. 总是分解你的信号成分并验证它们——这样做是为了安心,但也是为了对照你的直觉和你的用户的直觉。给他们看一些他们能解释的东西,并确保当你拆开它时,它仍然有意义。
  2. 为非参数检测方法设置一些合理的阈值。(注意—您需要为研发投入额外的时间/资源。让用户选择阈值—对一个人来说是异常的,对另一个人来说可能不是。
  3. 防止出现问题,因为您假设数据是预先标记的,而不是假设您的数据是未标记的。没有人有时间回去用他们认为异常的点来标记数百甚至数千个时间序列图表

要求 2——您的用户不会停留在一个指标上。它需要在规模上可访问

Miguel Henriques 在 Unsplash 上拍摄的照片

你从头开始——通过构建核心算法。但是用例几乎总是很快变得更加复杂,因为人们看到了它在一个特定例子中工作的价值。例如,一个分析团队可能正在跟踪整体销售指标的收入,发现一些有趣的异常情况。消息传到其他利益相关者那里,很快,人们开始要求在更精细的层面(例如,按国家、产品类别或收购渠道划分的收入)进行跟踪,而不仅仅是跟踪一个顶线指标,从而迅速产生数百或数千个新的时间序列。

拥有一个他们无法解释的异常检测系统是没有意义的。这些用户不会费力地浏览那么多时间序列图表。即使他们知道怎么做,他们也不可能有时间。

推荐:

  • 理论上来说,运行这些是可能的(技术/基础设施资源除外),但是以一种不会给用户带来过多信息的方式呈现输出是绝对必要的。
  • 仔细想想你的系统如何只共享与某个用户相关的异常。否则,任何潜在的有价值的信号都将淹没在噪声中。

要求 3——你需要尽量减少误报。比你想象的要快

无论你的算法有多好,任何异常检测器都无法提供 100%正确的是/否答案。假阳性和假阴性永远存在,两者之间有取舍。

人类操作员将不得不做出决定,即使在同一个团队中,对于什么构成异常也可能有不同意见。

在最初的构建过程中很容易忽略这一点,但不预先解决这一问题会带来一些风险,异常检测系统可能会向用户发出警报“风暴”,对于没有数据流背景的业务用户来说,这可能会感觉系统没有充分管理通知。

误报有两种形式:

1.数据在一段时间内意外或莫名其妙地丢失/不完整。

2.数据是完整的,但检测错误地标记了异常。

推荐:

  1. 如果数据缺失/不完整/迟交,请等待数据完整。但是您需要等待多长时间将取决于该指标刷新的频率——有不同的方法可以解决这个问题,可以是手动的,也可以是编程的。前者靠的是“直觉”和历史知识,不太可能规模化。
  2. 如果数据是完整的,但你仍然得到假阳性——检查分解结果和残差计算——这对人类有意义吗?否则,这可能会导致用户不信任输出。(我们在需求 1 中谈到了通过嗅探测试的重要性)。在这里,确保有一种方法可以根据您的发现来调整/调整您的算法,或者更好的是,允许用户挑出这些数据点供您研究!

警告:在极端情况下,用户将简单地关闭异常检测系统,以避免被虚假警报淹没,所有构建该系统的良好工作都将付诸东流

要求 4——您的系统需要考虑事件和“已知”异常

照片由贝内迪克特·盖耶Unsplash 拍摄

商业数据上的异常检测算法通常会发现提前已知的“大”事件,例如黑色星期五、圣诞节、复活节、企业促销。这些对用户来说并不奇怪,他们会预料到,并希望异常检测也能这样做。

推荐:

考虑这些事件有两种方式:

  1. 如果异常与已知事件一致,则抑制任何通知,或提供背景叙述;
  2. 使用基于历史观察的估计值,修改具有已知事件的时间范围的期望值。例如,如果我们知道黑色星期五通常会出现 80%的销售额激增,那么下次我们遇到黑色星期五并看到销售额激增时,在考虑异常现象是否值得注意时,应该考虑预期的峰值。

要求 5——让用户能够轻松地与其他利益相关者分享见解,并找出原因

马库斯·温克勒在 Unsplash 上拍摄的照片

经过所有这些艰苦的工作,终于到了在 IT / BI 团队之外分享这些异常现象的时候了!这是你一直努力的方向。

这一部分需要仔细计划和执行。有一些重要的驱动因素:

  1. 多个用户想要访问同一个被跟踪的指标(并且他们不想单独创建它们);
  2. 根据用户的要求,需要跟踪成百上千的指标;
  3. 并不是每个指标都会引发异常——您需要引导用户只关注最近发生的异常活动,以避免他们淹没在数据中;
  4. 用户将希望得到一个易于理解的、简明的消息,显示已经识别出了什么异常情况(如果可能的话,还有为什么!)

推荐:

所有这些都需要前端和后端协同工作,而不仅仅是一个数据库(对于大多数用户来说,从可访问性的角度来看,数据库至少要走几步)。像 PowerBI、Tableau 或 Looker 这样的传统仪表板可能不会在这里出现——它们不是为这种类型的用例设计的。

房间里的大象:

在发现异常(例如,英国的收入异常低)后,用户会很快想找出原因——这可能很难回答。这就是根本原因分析可以发挥作用的地方——请在以后的文章中注意这一点!

总而言之

让一个生产就绪的异常检测系统为业务用户正常工作不仅仅是在数据集上设置一个松散的算法。如果你是一个动手的数据科学家,我鼓励你尝试一下上面的技巧。

构建一个帮助你钓更多鱼的应用程序

原文:https://towardsdatascience.com/building-an-app-that-helps-you-catch-more-fish-b2eb76b885d4?source=collection_archive---------52-----------------------

一个警报系统使用数据通知你何时何地捕鱼

凯利·西克玛在 Unsplash 上的照片

我最近开始涉足淡水捕鱼。任何一直在钓鱼的人都知道,这可能是命中或错过,特别是如果你是这项运动的新手或在一个不熟悉的地方钓鱼。没有人想得到【一败涂地】。幸运的是,养鱼使得这种情况更容易避免。

鱼类放养是指在孵化场饲养鱼类,并将其放入水体,以帮助补充现有种群或在没有种群的地方创造新的种群。放养通常由国家部门完成,它们也有助于休闲渔业,提供更丰富的鱼类种群。

在美国,州保护或环境部门经常在网上发布库存更新。通常,一旦人们看到他们已经被放养,他们就会聚集到这些地方,在接下来的几天里,这些地方会被大量捕捞。

这让我开始思考。如果我开发一个应用程序,可以抓取网站,并在库存更新时提醒我,会怎么样?

考虑到这一点,我决定构建一个 Python 脚本,并将其部署在 Heroku 上,以便在发现新的库存更新时通过电子邮件自动通知我。我的目标不一定是第一个尽快耗尽所有湖中的鱼,而只是意识到任何更新,而不是必须记住检查它。这样,如果我外出并得到通知,我可以顺便去钓鱼,享受一天中的时光!

下面,我将带您了解如何构建这个应用程序,以及它是如何工作的,以便您可以构建类似的应用程序。

目标数据

我将收集的更新是康涅狄格州能源和环境保护部(DEEP)发布的康涅狄格州鳟鱼放养报告。该报告存储在 PDF 格式的表格中,并放在他们的网站上。

CT DEEP 鳟鱼放养报告第 1 页。注:根据政策提取数据允许 CT 政府网站

报告顶部列出的日期将作为我们的指示器,指示自我们上次抓取 PDF 以来报告是否已更新。在此之下,每个页面都有一个长期运行的表,其中列出了所有特定的水体、它们的位置以及它们最后一次储存的详细信息。

读入 PDF 数据

我们要做的第一件事是创建一个单行文本文件last_stocked_date.txt,存储 PDF 的最后更新日期。首先,我们可以在文件中设置日期5/1/2021。这将允许我们读入数据,并将其存储到主程序的变量LAST_STOCK_DATE中。

接下来,我们要从网站下载并存储当前的 PDF。为了检查 PDF 文件是否已经更新,我们将使用pdfplumber打开文件,并仅从第一页提取所有文本。使用一些字符串操作,我们将基于子字符串“STOCKING UPDATE from”从该文本中提取日期。

检查最近的更新

在这里,我们将启动我们的主程序,并检查 PDF 中的日期是否与我们抓取并存储的上一个日期不同。如果是这样,程序将从前 8 页的表格中提取数据,并将其存储到数据帧中。我们只需要提取前 8 页,因为它们给出了库存的所有位置(任何超出的都是重复数据)。

接下来,我们将在 dataframe last_update中创建一个新列,该列只提取某个特定位置的最后库存时间,并将其转换为datetime类型。例如,我们可以通过过去 3 天的库存位置来过滤数据框。

此外,我们希望记得更新存储上次库存日期的文本文件。这将确保我们的脚本下次运行时,只有在确定了新日期的情况下才会继续处理。

发送电子邮件警报

接下来要做的是发送一封电子邮件来提醒我们鱼已经被放养了,以及它们被放养在哪里。

为此,我们需要首先设置环境变量来收集我们的 Gmail 帐户、凭据和收件人详细信息。由于发送电子邮件需要提供凭证,我们不想直接在我们的脚本中存储这样的敏感数据。相反,我们将创建一个环境文件来存储这些数据。这对于在本地运行脚本是可行的,但是当使用 Heroku 这样的云解决方案进行实时部署时,我们还需要将这些环境变量定义为Config Vars

接下来,我们可以加载所需的环境变量。

我们还希望将之前存储位置的过滤数据框转换为字符串,以便我们可以将它包含在电子邮件的消息或正文中。之后,我们可以把邮件的所有内容拼凑起来,选择我们想要的邮件主题。

有了这个设置,我们应该能够运行脚本并收到类似这样的电子邮件!注意——使用谷歌的 Gmail 时,您可能会在第一时间收到安全通知,并且可能需要并允许 不太安全的应用 使用您的凭据发送电子邮件。

程序成功发送电子邮件提醒的示例(由作者提供)

把所有东西放在一起

我们现在有一个完整的预警系统来跟踪鱼类资源的更新!完整的代码将包括错误处理,以及捕捉任何通知我们可能发生的任何潜在问题,如果 PDF 文件格式或数据以某种方式改变,不能再由程序的代码捕获。

自动化脚本

从这里开始,最后一步是自动运行警报系统。有许多方法可以做到这一点,但主要有两种方法:

  1. 在本地运行,通过Task Scheduler (Windows)或cron (Mac 或 Linux)等软件进行调度。
  2. 将程序部署到供应商的云平台,如HerokuAWS,并使用他们的工具对其进行调度。

第一种方法很容易设置,而且是免费的,但是需要启动机器才能运行脚本。第二种方法是托管在云中的服务器上,因此可以随时运行,但可能更复杂,并且可能需要花费资金来设置。

出于我们的目的,我已经使用免费会员在 Heroku 上部署了该应用程序,并安排脚本每小时运行一次。这足够每月免费运行,不需要超过 Heroku 为其基本会员提供的免费时间或积分。在 Heroku 上部署将需要我们的主程序中一些额外的步骤,以及额外的文件,如requirements.txtruntime.txt文件。

如果你更喜欢在本地运行程序,有很多很棒的教程教你如何使用像任务调度器这样的工具。

我希望你觉得这个教程是有用的,令人愉快的。如果您有任何问题或反馈,请联系我们。如果您对 Heroku 上更深入的部署指南感兴趣,请随时在下面发表评论!

这个项目的所有代码都可以在这个 Github 资源库 中找到,您可以下载并立即开始运行,无论是在本地还是在 Heroku(如果您有帐户的话)。

使用 Streamlit 上的调查数据构建应用程序

原文:https://towardsdatascience.com/building-an-application-with-survey-data-on-streamlit-5e7628597f31?source=collection_archive---------47-----------------------

乔里斯·贝特洛在 Unsplash 上的照片

在过去的几个月里,我一直在玩 Streamlit,因为它是一种仅用一个 Python 脚本就能生成数据科学 web 应用程序的非常棒的方式。

这项技术的美妙之处在于,它消除了对前端技术进行编程的要求,让您专注于好东西——讲述一个引人入胜的数据故事。

我处理大量的调查信息,我认为用我们从基于滑雪的调查中收集的数据构建一个应用程序会很有趣。

我用 Streamlit 开发这款应用的动机有几个原因:

  • 可共享性——将应用程序投入生产非常容易,它将位于 Streamlit 云上,并且为您提供了一个唯一的 url,您可以共享它,这使得它非常容易访问。它也是移动优先的,这对于跨设备兼容性非常好。
  • 互动性——我希望我的品牌合作伙伴和同事能够与应用程序互动和互动,通过调整输入参数产生不同的结果,从而提供更多价值。

Alex Lange 在 Unsplash 上拍摄的照片

本文将介绍如何在高层次上构建该应用程序,还有许多其他关于 Streamlit 复杂性的优秀文章。

数据清理

当调查数据从另一端出来时,通常会非常混乱——这是因为调查的问题和答案格式通常不会转换成清晰的格式化数据集。话虽如此,随着时间的推移,我利用我的经验来调整调查的问题结构,以使数据格式化过程更有效。

第一个目的地是将数据输入到 Jupyter 笔记本中,这样 Pandas 就可以用来将数据框格式化成我可以进行分析的东西。

在这里,我删除了包含调查问题信息的行,这样就只剩下了用户数据,并格式化了列,使它们易于使用——缩短名称、小写、无空格等。

数据工程

一旦我得到了我想要的信息,我就运行一些数据可视化来更好地理解数据,这让我可以开始构建我的故事。

探索性数据可视化

我想展示我们的观众根据他们一年滑雪的次数和他们喜欢的滑雪方式购买的品牌。

为了测试这一点,我在笔记本中构建了一个函数,然后调用该函数来查看输出。

简化 Python 脚本

一旦我从工程的角度理解了应用程序将如何运行,我就开始在一个. py 文件中构建应用程序。

如上所述,交互性对这个项目非常重要,我希望应用程序的用户能够选择输入数据,然后直接输入到脚本的核心功能中,然后产生输出数据和关键可视化。

选择框示例

我使用了 Streamlit 的 selectbox,它将选择的数据保存为变量,然后输入到核心函数并生成柱状图。

输出柱状图

结论

Streamlit 与我在 Python 中的数据分析技能相结合,使我能够创建一个交互式网络应用,将行人调查数据转化为一个工具,允许没有分析技能的用户提取大量价值。我很高兴看到技术的进步,我将继续探索 Streamlit 可以创造什么。

如果你想了解关于这个项目的更多信息,请在 LinkedIn 上与我联系,我将很乐意接受对话,该项目的源代码也可在 my GitHub 上获得。

用一行代码构建一个人工神经网络

原文:https://towardsdatascience.com/building-an-artificial-neural-network-in-one-line-of-code-9addc414c5e9?source=collection_archive---------17-----------------------

TensorFlow 2 最简单的神经网络

图片由维基媒体上的 mikemacmarketing 提供

关于人工神经网络的解剖和数学有大量的理论文章,所以我将采用另一种方法来撰写和教授这个主题。在这篇文章中,我们要马上动手了!

让我们直接开始吧。如果您想跳过安装部分,可以选择下面的部分。

安装
选项 1
选项 2
数据
模型
为什么要 TensorFlow?

装置

如果您已经安装了需求,那么您可以跳过这一节。

选项 1

我们需要做的第一件事是确保我们已经安装了 Python 编程语言,如果你还没有,那么就在这里安装它

请注意,如果在安装过程中询问您是否要将 Python 添加到 PATH 变量中,请务必同意。接下来要做的是打开终端或 CMD,这取决于您的操作系统。

如果您使用的是 windows,请按 Windows 按钮并键入“cmd”。然后双击结果顶部显示“命令提示符”的黑色图标。

现在只需输入:

pip install numpy
pip install matplotlib

pip install tensorflow

请注意,如果您在 Mac 或 Linux 上,您可能必须键入“pip3”而不是“pip”。

接下来你需要做的就是打开某种文本编辑器或 IDE,比如 nodepad、Pycharm、VSCode、Sublime 或其他编辑器。

选项 2

在你的谷歌硬盘中安装谷歌的合作实验室。你可以在网站上获得这样做所需的所有信息。

https://colab.research.google.com/notebooks/intro.ipynb#recent=true

Google Colab 的一个好处是你可以免费使用大量的计算能力。具体来说,你可以在云中的 GPU 上训练你的模型,这使得它成为一个很好的研究框架。

数据

当我们训练有监督的机器学习算法时,我们需要标记的数据。也就是说,我们需要一个数据集,其中对于每个示例 x 我们需要一个标签 y ,模型应该预测它何时被馈送 x

在本文中,我们将尽可能做最简单的事情。我们不会考虑测试,所以这是关于最佳实践的而不是!我们将简单地考虑一种线性关系,并通过在谷歌的机器学习库 TensorFlow 中建立一个只有一个神经元的神经网络来尝试拟合该模型。

让我们打开我们选择的编辑器,输入

这段代码确保加载了所有相关的库。对于某些 x ≥ 0 的情况,您可能希望 TensorFlow 的版本是 2.x,所以尝试一个简单的

print(tf.__version__)

您应该会看到类似 2.5.0 的内容。

让我们创建数据。我们将创建自己的数据。简单地像这样自己创造一个线性关系。

作为一个聪明的人,你可能已经注意到了这个模式。

如果你猜对了 f(x) = 1/2 + x/2 ,你就猜对了。

模型

想法是这样的:我们将显示来自 xs 数组的网络值,并以 ys 数组的形式告诉模型正确的答案,以便对于 x 的每个值,模型将做出猜测,并通过查看真实的对应 y 值来纠正自己。

然后,该模型将通过称为反向传播的东西来调整自己(我们将使用随机梯度下降),并且对于每个示例,该模型将会改进。

我们没有太多的数据,所以这当然会限制模型的准确性,但本文的唯一目标是捕捉神经网络的思想,并了解张量流的一些简单语法。

我们将在一行代码中创建单个节点的人工神经网络,即:

现在我们已经建立了网络,让我们来训练它。

优化器确保网络改进其猜测,并且损失函数测量单个猜测的好坏。

现在我们来做个预测。

我们大约得到了 4.12 。现在让我们策划一些预测。

我们得到的输出是下图,绿色显示地面实况,红色显示模型预测。

作者图片

请注意,这是而不是线性回归,因为这与“最佳拟合”没有任何关系,而是每次尝试都试图自我修正的模型的结果。数据的缺乏和模型的简单很能说明问题,但我们仍然设法在这个简单的任务中捕捉到了神经网络的本质。

为了充分理解这一点,请尝试再次运行此代码。你不会得到完全相同的预测,因为这是一个新模型,而机器学习模型本质上是概率性的。

例如,当我第二次运行它时,当我给模型输入数字 7 时,我得到了一个新的预测。我大概弄了 4.08 。你会得到与我不同的东西!

您可以尝试使用这段代码来熟悉(hyper)参数的语法和效果。

例如,尝试将纪元设置为 200 或 1000。试试其他线性关系。

为什么是 TensorFlow?

如果你想学习如何建立机器学习模型,TensorFlow 是一个非常好的选择,有几个原因。

TensorFlow 是当今最受欢迎的深度学习框架之一。

它是一个非常成熟的库,因为它是由 Google 构建的,并且它可以与 Python 一起使用,这是两个重要的原因,但是我们为什么不看看一些使用它的公司,感受一下它在行业中的重要性。

使用 TensorFlow 的公司包括

  • 爱彼迎(美国短租平台)
  • 空中巴士
  • 可口可乐
  • 谷歌
  • 美国英特尔公司(财富 500 强公司之一ˌ以生产 CPU 芯片著称)
  • 联想(电脑的品牌名)
  • 贝宝
  • Spotify
  • 推特

这样的例子不胜枚举…

所以 TensorFlow 将会一直存在,如果你想在未来成为一名数据科学家或 ML 工程师,有很多公司会雇佣 TensorFlow 开发人员,所以学习这个伟大的框架绝对值得你花时间。

我们到了这个关于张量流和神经网络的小而简单的介绍的结尾。

在未来,我会发布越来越多的高级机器学习帖子,但我们需要从简单开始。

如果您有任何问题、意见或顾虑,请联系 LinkedIn。

https://www.linkedin.com/in/kasper-müller-96ba95169/

下次见。

构建情绪检测应用程序

原文:https://towardsdatascience.com/building-an-emotion-detection-application-54697de9ae01?source=collection_archive---------32-----------------------

使用 AWS Rekognition 用不到 50 行 Python 代码构建计算机视觉项目

图片来自 Unsplash

计算机视觉(CV)可能是一个非常理论化和紧张的领域,需要大量的 ML 和数学知识来解开和理解为对象检测、面部识别和对象跟踪等主题提供动力的算法。如果你在理论上没有必要的经验,或者没有时间来构建一个定制的 ML/CV 模型, AWS Rekognition 可以让你通过 API 调用来构建强大的 CV 应用。AWS Rekognition 是 AWS 提供的众多自动人工智能服务之一。这些服务是为那些ML 中没有太多背景的开发人员,或者时间少的数据科学家快速构建强大的 ML 应用程序,或者根据你可能正在开发的定制模型进行性能基准测试。AWS Rekognition 是 AWS 上用于计算机视觉的事实上的自动人工智能服务。如果您对构建定制模型感兴趣,请查看关于如何在那里部署定制 TensorFlow 模型的 AWS SageMaker 和我的文章。对于本文,我们将构建一个 Streamlit 应用程序,它接受一幅图像,并使用 Rekognition 返回图像中检测到的主要情感。

注意:对于 AWS 的新手来说(有一些经验来完全理解这篇文章是很好的),如果你想继续下去,请确保在下面的 链接 中做一个记录。我还将提供一个我们将使用的服务列表,以及更深入的定义。如果您已经熟悉了这些服务,可以直接跳到代码演示。

目录

  1. AWS 服务
  2. 设置简化应用程序
  3. 集成认知
  4. 整个代码和结论

AWS 服务

AWS Rekognition:AWS 主要的 Auto-AI 计算机视觉服务。有大量的功能,从人脸检测,文本检测,到物体跟踪。

AWS S3 :亚马逊的主要存储服务,我们将使用该服务来存储我们的训练数据模型工件/信息。

Boto3 :针对 Python 开发者的 AWS 软件开发包( SDK ),可以用这个来配合 AWS 服务。在这个用例中,我们将使用 Boto3 与 S3 一起访问我们的图像并调用 Rekognition。

身份访问和管理(IAM) :通过权限和角色管理 AWS 服务的访问。在使用我的代码时,您可能希望通过 AWS CLI 对用户进行身份验证。这里有一篇文章详细介绍了设置过程,如果你需要帮助的话。

设置简化应用程序

在我们开始处理 Rekognition 部分之前,我们需要设置我们的 web 应用程序。我们希望我们的应用程序能够上传一个文件,然后我们可以使用 Rekognition 在后端处理它。Streamlit 有一个简洁的文件上传特性,我们可以在这个用例中使用。我已经为样本图像创建了一个小的目录,我们可以调用它进行分析。

将文件上传到 S3

我们从样本图像目录中捕获文件。然后,我们使用 Boto3 与 S3 合作,将我们的本地图像存储在我们创建的 S3 存储桶中。要创建 S3 存储桶,您可以转到 AWS 控制台手动创建,或者如果您有 AWS CLI 设置,您可以简单地运行AWS MB unique-bucket-name来创建您的存储桶。我们需要我们在 S3 的数据,因为 Rekognition 直接与 S3 集成,用于其 API 调用,从而将我们的图像上传到 S3 的代码。

文件上传到 S3(作者截图)

Streamlit 应用程序设置(作者截图)

我们现在有了一个 Streamlit 应用程序集,可以接受图像并将其推送到 S3,以便与 Rekognition 一起使用。

集成认知

我们现在可以专注于对样本图像进行情感检测。Rekognition 在 detect_faces 中有一个 API 调用,它获取输入图像并返回各种参数,例如:年龄范围、性别、眼睛睁开情况、情绪等等。出于这一应用的目的,我们将关注于情绪参数。我们首先需要为 Rekognition 创建一个 boto3 客户端,就像我们对 S3 所做的那样。

识别客户端

我们现在有了客户机,现在可以向 detect_faces API 调用输入适当的数据了。

重新确认 API 调用

现在我们已经得到了 API 响应,我们希望解析输出,将注意力集中在面部表情上。我们为演示上传的示例图像如下所示。

图片来自 Unsplash

我们现在解析响应,以显示检测到的多数情绪和所有其他情绪,以及 Rekognition 在该情绪中的置信度得分。

解析 Rekognition 输出

现在,如果我们使用streamlit run filename . py运行我们的 streamlit 应用程序,我们应该会看到我们的应用程序成功运行。

显示重新识别结果(作者截图)

我们看到大多数情绪以及 Rekognition 检测到的所有情绪,为了清理 UI,您还可以添加一个 CV 库,如 PIL 来显示您正在上传的样本图像或文件。

整个代码和结论

https://github.com/RamVegiraju/MoodDetectionApp

要访问该项目的完整代码,请单击上方的链接。Auto-AI 正在快速扩张,AWS、Azure 和 GCP 等云提供商也在增长,并提供各种尖端服务,如 Rekognition,使您能够以简单的方式使用 ML 来支持应用程序。对于数据科学家和那些没有 ML 背景的人来说,Rekognition 对于快速启动和运行计算机视觉应用程序非常有用。在这些博客中查看一些更酷的 AWS 重新识别用例。

我希望这篇文章对那些从事计算机视觉项目或探索 AWS 的人有用。请随时在 LinkedIn 上与我联系,或者在 T2 媒体上关注我,了解我更多的写作内容。分享任何想法或反馈,谢谢阅读!

在 Power BI 中构建端到端分析解决方案:第 1 部分—理解业务问题

原文:https://towardsdatascience.com/building-an-end-to-end-analytic-solution-in-power-bi-part-1-understanding-the-business-problem-85db9e2d745b?source=collection_archive---------24-----------------------

当我与不深入 Power BI 世界的人交谈时,我经常得到的印象是,他们认为 Power BI 只是一个可视化工具。在这一系列文章中,我将向您展示如何使用 Power BI 来创建一个成熟的分析解决方案。

在第一部分中,我们通过定义构建成功的分析解决方案的所有阶段来搭建舞台!

https://unsplash.com/photos/qwtCeJ5cLYs

当我与不了解 Power BI 世界的人交谈时,我经常得到的印象是,他们认为 Power BI 只是一个可视化工具。虽然这在一定程度上是对的,但在我看来,他们没有看到更大的图景,或者更好的说法是,他们看到的只是冰山一角!这个冰山一角是那些闪亮的仪表盘,KPI 箭头,花哨的人工智能东西,等等。

然而,事情远不止如此,因为真实的事情隐藏在表面之下……

在这一系列文章中,我将向您展示如何使用 Power BI 来创建成熟的解析解决方案 。从不提供任何有用信息的原始数据开始,构建不仅仅是好看的可视化,而是提取可用于定义适当行动的洞察力——我们称之为知情决策。

当我与不深入 Power BI 世界的人交谈时,我经常得到的印象是,他们认为 Power BI 只是一个可视化工具。虽然这在一定程度上是对的,但在我看来,他们没有看到更大的图景,或者更好的说法是,他们看到的只是冰山一角!这个冰山一角是那些闪亮的仪表盘,KPI 箭头,花哨的人工智能东西,等等。

然而,事情远不止如此,因为真实的东西就在表面之下…

作者使用 PowerPoint 的插图

这下面的部分,由多个单独的,但有凝聚力的部分组成,使表面上的作品闪闪发光!

在这一系列文章中,我将向您展示如何使用 Power BI 来创建一个成熟的解析解决方案。从不提供任何有用信息的原始数据开始,构建不仅仅是好看的可视化,而是提取可用于定义适当行动的洞察力——我们称之为知情决策。

搭建舞台

在这一系列文章中,我将使用一个包含纽约市汽车碰撞数据的开放数据集,可以在这里找到。这个数据集包含大约 180 万行。每一行代表纽约市发生的一起事故,至少有一人受伤/死亡,或者总损失至少为 1000 美元。数据来自 CSV 文件,包含 29 列。

晋振伟在 Unsplash 拍摄的照片

现在,在我们开始构建我们的解决方案之前,我们需要定义工作流并确定流程中的特定阶段。因此,第一个也是最重要的任务是设定创造最终结果的必要步骤。以下是我的清单:

  1. 了解业务问题 —这是起点,因为不了解业务问题,我们的解决方案就无法解决业务需求。我想增加销售额吗?留住客户是我的主要目标吗?如果我在下一季度放弃一些服务,会发生什么?这些是需要使用数据洞察来回答的业务问题的一些典型示例。在这个例子中,我们的“业务”问题是识别碰撞的关键位置,并试图防止将来发生事故
  2. 数据准备 —在这一阶段,我们需要执行一些步骤来使我们的数据为进一步的消化做好准备。从数据剖析开始,这样我们可以识别可能的异常值和异常,然后应用各种数据整形技术在数据成为我们数据模型的一部分之前准备数据
  3. 数据建模 —当我们构建一个解析解决方案时,数据模型必须满足(或者至少应该满足)一些与数据建模相关的一般假设。对于大多数分析系统,包括 Power BI,维度建模是必经之路——因此,我们需要分解原始的宽事实表,并利用星型模式概念来建立适当的数据模型
  4. 数据可视化 —这是文章开头的人最喜欢的阶段:)…是时候用数字来取悦我们的眼睛,并使用方便的 Power BI 视觉效果来显示它们了
  5. 数据分析——有一个好看的视觉是好的,但它需要给一个看着它的人提供一些洞察力。因此,这一阶段的主要目的是提供洞察力——例如,纽约市车祸的高峰时间是什么时候?最危险的地点是哪里?皇后区有多少行人受伤?等等…
  6. 明智的业务决策 —这是一个可选阶段,可以从该解决方案中排除,完全留给业务利益相关者。但是,嘿,让我们一直扮演我们的数据分析师角色,并根据我们在前一阶段获得的见解给出一些建议!

作者使用 PowerPoint 的插图

1.理解业务问题

构建您的(成功的)分析解决方案的第一步也是最重要的一步,为了达到其目的并被用户采用,就是给出关键业务问题的答案。没有人需要漂亮的仪表板和酷炫的视觉效果,如果它们不能提供洞察力并帮助决策者理解正在发生的事情及其原因。

我如何能增加我的销售?为什么上个季度那么多客户离开我们?我能做些什么来改善交付流程?什么时候是针对市场进行促销的最佳时期?

这些只是商业利益相关者最常问的几个问题。不仅如此——也许对底层数据的洞察可以帮助用户识别全新的模式并提出一个问题: 我们正在解决正确的问题吗?

斯蒂芬·道森在 Unsplash 上拍摄的照片

因此,在一开始就确定关键问题是极其重要的,这样我们就可以对我们的数据进行塑造和建模,以最有效的方式来回答这些问题。

对于我们的数据集,我们不必处理“经典”的业务问题——因为没有销售、产品、促销……然而,这并没有降低它的“价值”,更不用说允许我们跳过上面定义的一些步骤。我们的一些“业务”问题可能是:

  • 这个城市最危险的地方是哪里?
  • 一天中的哪个时间最关键?
  • 行人占所有受伤者的百分比是多少?
  • 哪个行政区的事故率最高?
  • 什么类型的汽车最容易发生事故?

找到这些问题的答案的最终目标是确定导致碰撞的关键指标(数据分析阶段),并设法采取行动,防止未来的事故,或至少减少事故数量(做出明智的决策)。

结论

Power BI 不仅仅是一个可视化工具!不断重复这句话,不要忘了开头的冰山插图。

在本文中,我们奠定了理论背景,并解释了每个成功的分析解决方案的关键支柱的概念。在下一部分中,我们将开始探索我们的数据集,尝试识别可能的异常,检查数据集的某些部分是否需要增强或重构,并最终将数据塑造成能够让我们为流程中的后续阶段构建高效数据模型的形式。

感谢阅读!

成为会员,阅读 Medium 上的每一个故事!

在 Power BI 中构建端到端分析解决方案:第 3 部分——提高数据建模水平!

原文:https://towardsdatascience.com/building-an-end-to-end-analytic-solution-in-power-bi-part-3-level-up-with-data-modeling-cfbf3e4e2cd?source=collection_archive---------20-----------------------

在我们清理和塑造了我们的数据之后,是时候升级游戏了!了解为什么星型模式和 Power BI 是天作之合,以及如何在 Power BI 中直接构建它!

福克斯在 pexels.com 拍摄的图片

当我与不深入 Power BI 世界的人交谈时,我经常得到的印象是,他们认为 Power BI 只是一个可视化工具。虽然这在一定程度上是对的,但在我看来,他们没有看到更大的图景,或者更好的说法是,他们看到的只是冰山一角!这个冰山一角是那些闪亮的仪表盘,KPI 箭头,花哨的人工智能东西,等等。

然而,事情远不止如此,因为真实的东西就在表面之下…

在这一系列文章中,我将向您展示如何使用 Power BI 来创建一个成熟的分析解决方案。从不提供任何有用信息的原始数据开始,构建不仅仅是好看的可视化,而是提取可用于定义适当行动的洞察力——我们称之为知情决策。

作者图片

在我们奠定了构建端到端分析解决方案流程背后的一些理论背景,并解释了为什么在构建解决方案之前理解业务问题至关重要,并应用了一些基本的数据分析和数据转换之后,现在是时候升级我们的游戏并花些时间来阐述我们的分析解决方案的最佳数据模型了。提醒一下,我们使用了一个关于纽约机动车碰撞的公开数据集,可以在这里找到。

简而言之,数据建模

当您构建一个分析解决方案时,创建一个 高效 解决方案的关键先决条件之一是拥有一个合适的数据模型。我不会深入解释如何构建企业数据仓库、OLTP 和 OLAP 模型设计之间的区别、谈论规范化等等,因为这些都是您需要掌握的极其广泛和重要的主题,尽管您使用的是 Power BI 或其他开发工具。

解析解决方案中最常见的数据建模方法是维度建模。本质上,这个概念假设所有的表都应该被定义为事实表或维度表。事实表存储事件或观察结果,如销售交易、汇率、温度等。另一方面,维度表是描述性的—它们包含关于实体的数据—产品、客户、位置、日期…

请务必记住,这一概念并不仅仅与 Power BI 相关,它是一个通用概念,已经在各种数据解决方案中使用了几十年!

如果你真的想从事数据领域的工作(不一定是 Power BI),我强烈推荐阅读这本书: 《数据仓库工具包:维度建模权威指南 ,作者 Ralph Kimball 和 Margy Ross。这是所谓的维度建模的“圣经”,并彻底解释了在构建解析解决方案中使用维度建模的整个过程和好处。

星象图和权力 BI——天作之合!

现在,事情变得越来越有趣了!对立双方之间正在进行讨论——是使用包含所有数据的单一平面表更好(就像我们目前在纽约碰撞数据集中使用的那样),还是规范化这个“胖”表并创建一个维度模型(称为星型模式)更有意义?

作者图片

在上图中,你可以看到一个典型的维度建模的例子,叫做星型模式。我想我不需要向你解释它为什么被这样称呼:)你可以在 Power BI 这里阅读更多关于星型模式相关性的内容。有一个有趣的讨论,星形模式是否是比在数据模型中只有一个表更有效的解决方案——星形模式反对者的主要论点是性能——在他们看来,如果没有连接、关系等,Power BI 应该工作得更快。

然后, Amir Netz ,微软分析公司的首席技术官和负责构建 VertiPaq 引擎的人员之一,在 Twitter 上澄清了所有的不确定性:

作者截图

如果你不相信一个完全知道事情如何在引擎盖下工作的人,那么也有一些由经验证的专家提供的额外的精彩解释,为什么星型模式应该是你在 Power BI 中建模数据的首选方式,例如【Patrick(立方体中的家伙)的这个视频,或者 Alberto Ferrari (SQL BI) 的这个视频。

而且,这不仅仅关乎效率,还关乎在您的报告中获得准确的结果!在这篇文章中,Alberto 展示了在一个平面表上编写 DAX 计算如何会导致意想不到的(或者说不准确的)结果。

不用深入解释为什么应该使用星型模式,让我向您展示使用一个平面表会产生不正确的数字,即使是一些琐碎的计算!

作者图片

这是我的平面表,其中包含一些关于销售的虚拟数据。假设业务请求是找出客户的平均年龄。如果有人问你顾客的平均年龄是多少,你会怎么回答?30,对吗?我们有一个 20 岁、30 岁和 40 岁的客户,所以平均年龄是 30 岁,对吗?来看看实力 BI 怎么说…

AVG Customer Age = AVERAGE(Table1[Customer Age])

作者图片

这怎么可能呢?!32 真的吗?!让我们看看我们是如何得到这个意外的(不正确的)数字的…如果我们将所有客户年龄值相加,我们将得到 320…320 除以 10(这是销售数字),瞧!好了,这是你的 32 个普通顾客的年龄!

现在,我将开始构建一个维度模型,并将客户数据放入一个单独的维度表中,删除重复的数据并保留 customers 维度中的唯一值:

作者图片

我还从原始销售表中删除了客户年龄,并在客户键列中建立了这两者之间的关系:

作者图片

最后,我只需要重写我的度量来引用新创建的维度表:

AVG Customer Age = AVERAGE(Customers[Customer Age])

作者图片

当然,有一种方法可以编写更复杂的 DAX,甚至可以用一个平面表来检索正确的结果。但是,为什么要这样做呢?我相信我们会同意,最直观的方法是像我一样编写一个度量,并用一个简单的 DAX 语句返回一个适当的数字。

所以,不仅仅是效率的问题,还有准确性的问题!因此,这里的关键要点是: 尽可能将您的数据建模为星型模式!

为 NYC 碰撞数据集构建星型模式

既然我们已经得出结论,星型模式是可行的,那么让我们开始为数据集构建最佳数据模型。第一步是去掉缺失值超过 90%的列,因为我们无法从中提取任何信息。我已经删除了 9 列,现在还剩下 20 列。

乍一看,我有 5 个潜在的维度表要创建:

  • 日期维度
  • 时间限度
  • 位置维度(区+邮政编码)
  • 促成因素维度
  • 车辆类型尺寸

但是,在我们继续创建它们之前,我想对我的崩溃时间列应用一个额外的转换。因为我们不需要在分钟级别上分析数据(要求的是小时级别的粒度),所以我将值四舍五入到起始小时:

作者图片

我现在将复制我的原始平面表 4 次(对于所需的每个维度,除了日期维度,因为我想使用一组更复杂的属性,例如星期几)。不要担心,因为我们将只保留每个维度中的相关列,并删除所有其他列。以下是位置维度的一个示例:

作者图片

下一个重要步骤是确保我们在每个维度中都有唯一的值,这样我们就可以在维度和事实表之间建立适当的 1-M 关系。我现在将选择我的所有维度列并删除重复项:

作者图片

我们需要对数据模型中的每个维度都这样做!从这里开始,由于我们在原始表中没有“经典的”键列(例如,在前面的例子中,当我们计算平均客户年龄时,我们在原始平面表中有 Customer 键列),有两种可能的方法:更简单的方法假设在文本列上建立关系——这“本身”没有问题,但是它可能对大型模型中的数据模型大小有影响。

因此,我们将走另一条路,为我们的每个维度创建一个代理键列。按照维度建模中的定义,代理键不具有任何业务意义——它只是一个简单的整数(或 bigint)值,该值按顺序递增并唯一地标识表中的行。

使用索引列转换在 Power Query 中创建代理键非常简单。

作者图片

这里只需要注意一点:默认情况下,使用索引列转换将中断查询折叠。然而,由于我们处理的是根本不支持查询折叠的 CSV 文件,我们可以安全地应用索引列转换。

下一步是将这个整数列添加到事实表中,并将其用作维度表的外键,而不是文本值。如何才能实现这一点?我将简单地将位置维度与我的碰撞事实表合并:

作者图片

出现提示后,我将对唯一标识维度表中一行的列执行合并操作(在本例中,是行政区和邮政编码的组合键):

作者图片

在 Power Query 应用这种转换之后,我将能够展开合并后的位置表,并从那里获取索引列:

作者图片

现在,我可以使用这一个整数列作为 Location 维度表的外键,只需删除两个属性列 BOROUGH 和 ZIP CODE——这样,我的表不仅更加整洁,而且还需要更少的内存空间——我们现在有一个整数列,而不是两个文本列!

作者图片

我将对其他维度(除了时间维度)应用相同的逻辑—包括索引列作为外键,并删除原始文本属性。

用日期维度和关系增强数据模型

现在,我们已经完成了 Power Query editor 中的数据建模,并准备好进入 Power BI,通过使用 DAX 创建一个日期维度来增强我们的数据模型。我们也可以在 Power Query 中使用 M 来完成,但是我有意将它留给 DAX,只是为了向您展示 Power BI 中数据建模的多种不同功能。

为了使 DAX 时间智能功能以正确的方式工作,设置正确的日期/日历维度至关重要。

为了创建一个日期维度,我使用了由 SQL BI 人员提供的这个脚本。

Date =
VAR MinYear = YEAR ( MIN ( Collisions[CRASH DATE] ) )
VAR MaxYear = YEAR ( MAX ( Collisions[CRASH DATE] ) )
RETURN
ADDCOLUMNS (
    FILTER (
        CALENDARAUTO( ),
        AND ( YEAR ( [Date] ) >= MinYear, YEAR ( [Date] ) <= MaxYear )
    ),
    "Calendar Year", "CY " & YEAR ( [Date] ),
    "Month Name", FORMAT ( [Date], "mmmm" ),
    "Month Number", MONTH ( [Date] ),
    "Weekday", FORMAT ( [Date], "dddd" ),
    "Weekday number", WEEKDAY( [Date] ),
    "Quarter", "Q" & TRUNC ( ( MONTH ( [Date] ) - 1 ) / 3 ) + 1
i

在我将这个表标记为数据表之后,就该构建我们的星型模式模型了。我将切换到模型视图并建立表之间的关系:

作者图片

这让你想起什么了吗?没错,看起来就像上面的星形插图。因此,我们遵循 Power BI 中关于数据建模的最佳实践,构建了一个星型模式模型。不要忘记,我们能够在不离开 Power BI 桌面环境的情况下做到这一点,只使用 Power Query Editor,并且不编写任何代码!我听到了,我听到了,但是日期维度的 DAX 代码不算:)

结论

我们的分析解决方案正在慢慢改进。在我们执行必要的数据清理和整形后,我们通过构建星型模式模型达到了更高的水平,这将使我们的 Power BI 分析解决方案能够高效地执行并提高整体可用性——既消除了不必要的复杂性,又能够为不同的计算编写更简单的 DAX 代码。

正如您所看到的,我们再次证明了 Power BI 不仅仅是一个可视化工具!

在本系列的下一部分,我们将最终移动到球场的那一边,开始构建一些很酷的视觉效果,利用我们在后台创建的数据模型的功能。

感谢阅读!

成为会员,阅读 Medium 上的每一个故事!

在 Power BI 中构建端到端分析解决方案:第 4 部分——从图表到洞察!

原文:https://towardsdatascience.com/building-an-end-to-end-analytic-solution-in-power-bi-part-4-from-chart-to-insight-56a543861477?source=collection_archive---------31-----------------------

准备好一些很酷的数据可视化了吗?在这一部分,我们将根据一些最佳的数据 viz 实践来构建我们的报告!

拉胡尔·潘迪特关于 pexels.com 的图片

当我与不了解 Power BI 世界的人交谈时,我经常得到的印象是,他们认为 Power BI 只是一个可视化工具。虽然这在一定程度上是对的,但在我看来,他们没有看到更大的图景,或者更好的说法是,他们看到的只是冰山一角!这个冰山一角是那些闪亮的仪表盘,KPI 箭头,花哨的人工智能东西,等等。

然而,事情远不止如此,因为真实的事情隐藏在表面之下……

在这一系列文章中,我将向您展示如何使用 Power BI 来创建成熟的解析解决方案 。从不提供任何有用信息的原始数据开始,构建不仅仅是好看的可视化,而是提取可用于定义适当行动的洞察力——我们称之为知情决策。

作者插图

好消息,伙计们-缓慢但稳步地,我们正在接近我们的目标-仅使用 Power BI 构建高效的端到端分析解决方案!我们强调了在创建解决方案之前理解业务问题的重要性,执行了一些简单的数据清理和转换,在前面的部分中,我们了解了为什么 Star schema 和 Power BI 是天造地设的一对,以及为什么您应该始终努力以这种方式对数据建模。

现在,是时候构建一些引人注目的可视化工具了,它们将帮助我们以最有效的方式讲述数据故事,并为业务决策者提供见解-最终,基于这些见解,他们将能够做出明智的决策-基于数据的决策,而不是基于个人的预感或直觉!

免责声明: 我认为自己不是一个有审美天赋的人,所以我的数据可视化解决方案大多基于我在书中读到的最佳实践(例如这一个)、博客,并受到一些了不起的社区成员的启发,例如 Armand Van Amersfoort、Daniel Marsh-Patrick、Kerry Kolosko、Ried Havens、Andrej Lapajne ( Zebra BI )或来自 powerbi.tips

数据可视化——我的首选

在我们卷起袖子开始可视化我们的数据之前,我想指出一些我一路收集的关于数据可视化的最佳实践。

1。一个仪表盘来统治所有人

这一条不仅仅适用于数据可视化,它更像是一条通用规则。没有单一的解决方案可以满足每一项业务需求!句号!首先,您应该确定仪表板的用途— 操作仪表板 为消费者提供时间关键型数据。我喜欢把操作仪表板想象成汽车或飞机的驾驶舱……另一方面, 分析仪表板 更侧重于从历史数据中识别趋势和模式,从而更好地做出中长期决策。

在我们的这个博客系列中,我们正在构建一个分析仪表板。

2。挑选合适的可视化类型

呃,这个可能是最难定义的了。从字面上看,有数百篇来自知名作者的博客文章、书籍和视频,解释了使用哪种可视化类型来表示特定的数据。基于您想要提供哪种洞察—例如,两个数据点之间的比较、特定值的分布、不同数据之间的关系、随时间的变化、整体的部分,等等—应该使用的某些视觉类型。

作者插图

我故意用了“应该”这个词,因为没人能禁止你在仪表盘上使用仪表图、饼状图、三维图,尽管很多公认的专家都反对这样做——只是要小心谨慎,注意在什么场景下使用什么视觉类型。

3。定义最重要的数据点

显然,一些数据点比其他数据点更重要。如果你的总收入比上个月低 50%,这肯定比看图表显示每种产品颜色的个别数字要重要得多。考虑到这一点,试着将所有关键数据点放在左上角,因为我们星球上的大多数人都是从左到右,从上到下阅读(想象一下阅读一本书,或报纸),这个位置自然会立刻引起他们的注意。

作者插图

4。保持一致!

这是需要记住的关键事情之一!一致性是什么意思?例如,坚持使用已定义的布局和设计,将相关信息放在一起,或者对类似类型的信息使用类似的视觉类型—您不希望在一个仪表板部件中使用饼图按区域显示销售额,然后使用柱形图按区域显示订单总数。

5。移开注意力

我已经写了一个关于从 Power BI 报告中排除干扰的具体案例。在你的仪表板上有很多可能的干扰物。让我们从字体开始:倾向于使用标准字体而不是艺术字体,因为它们更容易消费:

作者插图

上图展示了左侧卡片的可读性,它使用了一种标准字体(Calibri)。它还展示了另一个需要考虑的问题——缩短数字也是一种从你的仪表盘上消除干扰的好方法。

此外,注意适当的对齐,给你的视觉效果留出一些空间:

视觉效果之间适当的对齐和空间将提高清晰度 —作者插图

我想我们都同意上图中的仪表板比下图更易读:

作者插图

谈到数据可视化,还有更多最佳实践、技巧和建议。正如我已经强调的,我不认为自己是一个“数据 viz”向导,但是我仍然试图坚持本文前面部分提到的一些通用规则。

最后,尽管对于许多仪表板创建者来说,第一步是设置总体仪表板设计,然后将数据元素放入预定义的模板中,但我更喜欢反其道而行之:首先,我创建所有数据元素,然后基于我想用这些元素“讲述”的故事,我正在构建最终的解决方案…

可视化车辆碰撞数据

好了,现在我们已经确定了一些通用的数据可视化最佳实践,是时候动手使用 Power BI 来讲述纽约市的车辆碰撞事件了。

作者图片

这是我的报告的样子。在这一部分,我们不会深入每个视觉细节,但让我简单介绍一下整体概念。有两个页面——主页包含最重要的数据点,如碰撞、死亡和受伤的数量。还有一些“经典”的视觉效果,如折线图和柱形图,这将帮助我们从不同的角度提取对数据的见解。多行卡视觉快速说明谁是交通中最危险的。

一天中的时间是我们的关键分析类别之一,因此报告用户可以充分灵活地在同一视觉效果(碰撞、死亡、受伤)的不同指标之间切换,密切关注动态标题,这增强了整体用户体验!

请记住,我们在这里定义了一组问题,我们将尝试使用此报告来回答这些问题。可以使用日期切片器从日历的角度对数据进行切片。

详细信息页面提供了深入了解事故细节的可能性——介绍了针对行政区和邮政编码的附加切片器。小倍数视觉很好地将数字分为两类——人的类型和区,而其他元素扩展了主页的逻辑。

结论

在本系列的这一部分中,我们已经介绍了很多内容。这并不是说我们只是构建了自己的报告来可视化来自原始数据集的数据,我还与您分享了一些关于数据可视化的一般最佳实践,以及来自该主题的成熟专家的建议。

我再重复一遍:我认为自己远没有成为一名“设计师”的天赋,我相信你们中的许多人可以创造出一份更好看的 Power BI 报告。然而,最终目标是将关键数据点有效地传达给报告消费者,并使他们能够根据这种传达所提供的见解做出决策。

考虑到这一点,我相信我们已经为在本系列的最后部分总结所有内容打下了坚实的基础——我们将尝试从我们刚刚创建的报告中提取一些有意义的信息,并根据这些发现建议某些行动。

感谢阅读!

成为会员,阅读媒体上的每一个故事!

在 Power BI 中构建端到端分析解决方案:第 5 部分——请行动起来!

原文:https://towardsdatascience.com/building-an-end-to-end-analytic-solution-in-power-bi-part-5-action-please-a60dd23802a3?source=collection_archive---------31-----------------------

在最后一部分,我们将把我们的分析技能提升到另一个层次!不仅如此——基于所获得的见解,我们将推荐某些行动!

作者图片

当我和那些没有深入了解 Power BI 世界的人交谈时,我经常得到的印象是,他们认为 Power BI 只是一个可视化工具。虽然这在一定程度上是对的,但在我看来,他们没有看到更大的图景,或者更好的说法是,他们看到的只是冰山一角!这个冰山一角是那些闪亮的仪表盘,KPI 箭头,花哨的人工智能东西,等等。

然而,事情远不止如此,因为真实的东西隐藏在表面之下……

在这一系列文章中,我将向您展示如何使用 Power BI 来创建成熟的解析解决方案 。从不提供任何有用信息的原始数据开始,构建不仅仅是好看的可视化,而是提取可用于定义适当行动的洞察力——我们称之为知情决策。

作者插图

在这里,我们以 CSV 文件的形式获取原始数据,定义一组需要使用该数据回答的业务问题,然后清理和塑造原始数据集并构建高效的数据模型(星型架构),在前面的部分中,我们创建了引人注目的可视化,为业务决策者提供不同的见解。现在,是时候分析见解,并根据我们从这些见解中提取的信息,推荐一些行动了!

提取洞察力

先来分析一下碰撞造成的死亡。如果我们排除在车内的人,我们可以看到行人是最危险的交通参与者——与骑自行车的人相比,几乎多 8 倍的行人被杀!

作者图片

我们可以得出的下一个结论是,碰撞的主要原因是司机不注意/分心!如果我们看一下前 5 大冲突原因,您会发现所有其他原因加起来都低于前一个原因。

作者图片

继续,我们可以发现的下一个模式是下午早些时候,特别是下午 4 点和 5 点的碰撞高峰。这是有道理的,因为很多人在那段时间从办公室开车回家:

作者图片

这大约比早上(上午 8-9 点)高 30%,而在早上,交通参与者在辛苦工作一天后可能不会感到疲劳和分心。

让我们继续详细概述事故,并努力找出城市中的“黑点”。乍一看,大多数人是在布鲁克林被杀的,或多或少,所有其他区都遵循不同交通参与者之间的“死亡分布”模式,除了曼哈顿,那里骑自行车的人比开车的人被杀的多。

如果我们分析受伤的百分比,趋势与死亡率有很大不同:现在,司机是最危险的(同样,不包括车上的人)——司机受伤的人数几乎是行人的 4 倍!

作者图片

再往下,冲突最频繁的邮政编码是 11207 和 11101(一个在布鲁克林,另一个在皇后区)。如果我们关注具体的街道,我们可以看到百老汇(曼哈顿)和大西洋大道(布鲁克林,邮编 11207)是纽约市最关键的景点!

作者图片

请开拍!

好了,现在我们有了更多的信息来支持我们的业务决策。而且,因为我们已经定义了需要回答的一系列问题,所以让我们专注于提供适当的行动建议!

这个想法是以工具提示的形式显示建议——当有人将鼠标悬停在特定的视觉对象上时,相应的操作应该会显示出来!我已经写了如何使用工具提示页面增强你的报告,这里我们将遵循类似的方法:

作者图片

因此,当我将鼠标悬停在显示 5 大碰撞原因的画面上时,将会推荐一些行动:

  • 对违法者的更高处罚
  • 针对驾驶员的附加培训

同样,如果您想根据大多数碰撞发生的时间采取行动,只需将鼠标悬停在该画面上,您就会看到在这些高峰时段增加交通官员数量的建议:

作者图片

此外,为了能够减少特定位置的碰撞和伤亡数量,我们强调了增设交通灯和在“交通黑点”指派更多交通官员的重要性:

作者图片

结论

伙计们,收工了!提醒你一下,这是我们开始的地方:

作者图片

这是我们结束的地方:

作者图片

在这一过程中,我们清理和转换了我们的数据,使用星型模式构建了合适的数据模型,并可视化了关键数据点。你猜怎么着— 我们使用一个工具完成了所有这些:Power BI! 这就是我将这一系列博客文章命名为:用 Power BI 构建端到端分析解决方案的原因——我相信我们会同意这些文章毫不夸张地证明了这一点。

所以,下次当你听到“Power BI 只是一个可视化工具”时,请记住我们专门使用这个工具能够实现什么,并自己得出结论!

感谢阅读整个系列!

成为会员,阅读 Medium 上的每一个故事!

构建端到端的开源现代数据平台

原文:https://towardsdatascience.com/building-an-end-to-end-open-source-modern-data-platform-c906be2f31bd?source=collection_archive---------4-----------------------

帮助您浏览现代数据堆栈并使用开源技术构建自己的平台的详细指南。

克里斯多夫·伯恩斯在 Unsplash 上拍摄的照片

在过去几年中,数据工程领域的重要性迅速上升,为加速创新和进步打开了大门——因为今天比以往任何时候都有更多的人在思考数据资源以及如何更好地利用它们。这种进步反过来导致了第三次数据技术的浪潮

第一波由 ETL、OLAP 和关系数据仓库组成,它们是商业智能(BI)生态系统的基石,无法应对大数据的四个 v的指数级增长。由于双向堆栈的潜力有限,我们随后见证了第二波:这是一个存储和计算可扩展性的时代,这要归功于 Hadoop 生态系统(允许公司横向扩展其数据平台)和 Apache Spark(为大规模高效内存数据处理打开了大门)。********

我们称之为“ 第三次浪潮 ”的时代是我们不再担心可扩展性或分布式存储的时代。相反,我们正在成熟的分布式数据平台上构建砖块和新功能。我们现在有可能考虑元数据管理、大规模数据发现和数据可靠性等主题。我们正处于可互换的 SaaS 模块、基于云的平台、ELT 和民主化数据访问的时代。欢迎来到 现代数据栈 浪潮。

在本文中,我们将从头开始构建一个端到端的现代数据平台,仅仅依靠开源技术和云提供商提供的资源。本文还附有一个 GitHub repo,其中包含构建平台所需的必要代码和基础设施代码(IaC)脚本。

**https://github.com/mahdiqb/modern_data_platform

该平台将由以下组件组成:

  • 数据仓库:这是我们设计中最重要的部分,因为不管其他部分有多复杂,低效的数据仓库都会给我们带来问题。从根本上说,数据仓库背后 40 年的概念和范例至今仍然适用,但与来自、【第二波】、的水平可伸缩性相结合,实现了高效的 ELT 架构。
  • 数据集成:不出所料,我们实际上需要将数据放入我们的平台。由于现代数据堆栈,以前配置和实现连接器的繁琐任务现在已经解决了。
  • 数据转换:一旦我们将数据放入我们的仓库(因此我们完成了 ELT 架构的 EL 部分),我们将需要在它上面构建管道来 转换 它,以便我们可以直接消费它,并从中提取价值和见解——这个过程是我们 ELT 中的 T,直到最近,它通常由管理不善的大型 SQL 查询或复杂的 Spark 脚本组成。 但是,在这个“第三次浪潮”中,我们现在拥有了更好地管理数据转换的必要工具。
  • 编排(可选——目前):我们仍然需要编排管道的执行,以确保数据尽快可用,并且数据生命周期从一个组件平稳地运行到下一个组件。这被标记为可选的,因为我们将使用的一些工具提供了开箱即用的调度功能,因此在平台生命周期的第一阶段,您不应该真正需要专用的编排组件(这会增加不必要的复杂性)。尽管如此,我们仍将在本文中讨论编排选项,因为您最终需要在您的平台上添加一个。
  • 数据监控(可选—目前):更多的数据意味着更多潜在的质量问题。为了能够信任我们的数据,我们需要监控它,并确保我们基于它生成准确的见解。这被标记为可选的,因为在开始时,最有效的选择是利用其他组件的数据测试功能,但是我们将在本文中讨论数据监控工具。
  • 数据可视化:这是我们实际探索数据并以不同数据产品的形式从中产生价值的地方,比如仪表板和报告。这个时代的主要优势之一是,我们现在拥有成熟的开源数据可视化平台,可以以简化的方式进行部署。
  • 元数据管理:我们平台的大部分功能(如数据发现和数据治理)都依赖于元数据,因此我们需要确保元数据在整个平台中得到集中和利用。

平台的架构(图片由作者提供)

最后,请记住,尽管我们将讨论的技术和工具是开源的,但我们将在云环境中构建平台,因此我们将使用的资源(用于计算、存储等)。)本身并不免费,但我们不会超过GCP 免费试用版提供的 300 美元预算。

如果您想避免建立云环境,您仍然可以在本地试验不同的工具,您只需要用一个开源的替代方案(像 PostgreSQL 这样的 RDBMS)替换数据仓库(在我们的例子中是 BigQuery)。

现在,事不宜迟,让我们建立我们的现代数据平台。**

首先,我们来谈谈数据

要构建一个样本数据平台,流程的第一步是挑选一个或多个数据集进行处理。这是一个探索在线可用的多个开放数据集之一的机会,我建议搜索一个你个人感兴趣的数据集-这将使这个过程更加愉快,因为你会对这些数据真正感兴趣。如果您想要一些灵感,请从以下数据集之一开始:

  • 一级方程式世界锦标赛(1950–2021):你可以从 Kaggle 下载或直接从er gast HTTP API检索的这个数据集包含了从 1950 年到 2021 年的一级方程式比赛、车手、制造商、排位赛、赛道、圈速、进站和锦标赛的所有可用数据点。如果你像我一样是 F1 粉丝,这个数据集可以给你许多关于这项运动的有趣见解。
  • 世界发展指标(1960–2020):这个由世界银行提供的数据集无疑是你能在网上找到的最丰富的开放数据集之一。它包含大约 1500 个发展指标,你可能会迷失其中。

数据仓库:BigQuery

如上所述,为您的用例选择正确的数据仓库是我们难题中最重要的一块。主要的三个选项是雪花大查询红移——是的,它们都不是开源的,但它们都提供了一个 无服务器 选项。这意味着我们可以利用复杂的现代数据仓库的功能,同时只需为我们在存储和计算方面消耗的资源付费。

好消息是,无服务器选项正是我们在这个阶段寻找的,即使该产品不是开源的。这是因为我们希望能够在存储和查询性能方面进行扩展,而不需要专门的维护工作。因此,入门时的理想选择是无服务器托管产品——这适用于我们所有需要弹性的组件,而不仅仅是数据仓库。

出于各种原因,BigQuery 非常适合这一需求,其中我们可以提到以下两点:

  • 首先,它本质上是无服务器的。其背后的设计由于存储和计算的分离,允许提高效率,使其成为所有类型使用情形的非常可靠的选择。另一方面,Redshift 的无服务器产品仍处于测试阶段。
  • 其次,它是云提供商产品的一部分,因此已经与 GCP 生态系统的所有组件实现了无缝集成。这进一步简化了我们的架构,因为它最小化了配置工作。

因此,对于我们来说,利用 BigQuery 作为这个平台的数据仓库是有意义的,但这并不能概括这个选择,因为在其他场景中,选择另一个选项可能更有意思。在选择数据仓库时,您应该考虑定价、可伸缩性和性能等因素,然后选择最适合您的用例的选项。

为了开始,我们只需要创建一个数据集,但是请随意熟悉 BigQuery 的一些更高级的概念,比如分区物化视图

在 ELT 架构中,数据仓库用于存储我们所有的数据层。这意味着我们不仅仅使用它来存储数据或查询分析用例,我们还将利用它作为不同转换的执行引擎。

现在我们已经选择了我们的数据仓库,架构看起来如下:

架构的当前状态(图片由作者提供)

在我们进入下一个组件之前,让我们将 BigQuery 审计日志存储在一个专用的数据集 ( 附加指令),因为当我们设置元数据管理组件时,这些信息将会派上用场。

获取数据:Airbyte

当考虑现代数据堆栈中的数据集成产品时,您会发现少数公司(使用闭源产品)竞相在最短的时间内添加最多的连接器。遗憾的是,这意味着更慢的创新(因为对每个产品做出贡献的人更少)和定制现有解决方案的可能性更小。

异常的亮点肯定是 Airbyte,这是这个领域中唯一一家从一开始就选择开源其核心产品的大公司。这使得它在成立不到一年的时间里迅速发展成一个大型贡献者社区,并提供了 120 多个连接器。

部署 Airbyte 对所有云提供商来说都是轻而易举的事情。在 GCP 上,我们将使用具有足够资源的计算引擎实例。理想情况下,您会希望通过 IaC 配置您的部署,这将使管理版本和自动化过程更加容易。(随附的报告中提供了 Terraform 配置示例。)

一旦启动并运行,我们只需通过定义以下内容来添加连接:

  • ****源:您可以使用 UI 选择“文件”源类型,然后根据您的数据集和您上传数据的位置对其进行配置,或者如果您更喜欢冒险,您可以利用 Airbyte 的 Python CDK 构建一个新的 HTTP API 源,从您想要使用的 API 中获取数据。
  • A destination :这里您只需要指定与数据仓库交互所需的设置(在我们的例子中为 BigQuery )。

样本 Airbyte 连接(图片由作者提供)

值得注意的是,Airbyte——就目前而言——仅仅是为批量数据摄取而设计的(ELT 中的 EL ),所以很遗憾,如果您正在构建一个事件驱动的平台,它不在您的选择之列。如果你有这样的用例,那么你的最佳选择将是柔术细分的开源替代方案。

现在,我们已经启动并运行了 Airbyte,数据接收也已完成,我们的平台如下所示:

架构的当前状态(图片由作者提供)

管理我们英语教学中的 T: dbt

当我们想到现代数据堆栈时,dbt 可能是第一个想到的工具。这个始于 2016 年的项目(从一开始就是开源的)解决了当时一个普遍存在的问题:数据管道的版本很差,文档记录很差,并且没有遵循软件工程的最佳实践。

dbt 是第三次数据技术浪潮的理想代表,因为它代表了这一浪潮背后的主要目标:添加特性和功能,以更轻松地管理现有的数据平台,并从底层数据中获取更多价值。得益于 dbt,数据管道(我们 ELT 中的 T)可以划分为一组SELECT查询(称为“ 模型 ”),这些查询可以由数据分析师或分析工程师直接编写。这种能力为多种特性打开了大门,比如数据沿袭、版本控制、数据测试和文档。

设置 dbt 环境有两种不同的方式:

  • dbt Cloud :这是 dbt 实验室托管的基于 web 的集成开发环境(IDE)。这是一个需要最少工作的选项,但提供了更多功能,如计划作业、CI/CD 和警报。锦上添花的是,通过开发者计划,它实际上是免费的。
  • dbt CLI :该选项允许您直接与 dbt Core 交互,无论是通过使用pip在本地安装它,还是像我们之前部署的 Airbyte 一样在 Google Compute Engine 上运行 docker 映像。通过使用 CLI,您可以体验不同的 dbt 命令,并在您选择的 IDE 中工作。

为了允许 dbt 与您的 BigQuery 数据仓库进行交互,您需要生成所需的凭证(您可以创建一个具有必要角色的服务帐户),然后在您的profiles.yml文件中指明特定于项目的信息。这在 dbt Labs 的“入门”教程中有很好的解释,它介绍了你需要熟悉的所有概念。

运行 dbt 调试后的预期输出(图片由作者提供)

在最初的努力之后,现在是您享受数据的时候了:您可以使用 dbt 来定义模型以及它们之间的依赖关系。例如,对于 F1 数据集,您可以生成一个包含冠军得主数据的championship_winners模型(总积分、每场比赛的平均进站时间、整个赛季的最快圈数、平均排位等。)对于您正在处理的任何数据集,当涉及到数据可以回答的问题时,您会发现可能性的数量令人难以置信——这是一个很好的练习,会让您在处理新数据集时更有信心。

在处理完您的模型之后,您可以执行命令dbt docs generate来生成我们项目的文档(目录和清单文件)。

在这个阶段,在设置好 dbt 之后,我们现在有了可以处理 ELT 流程的三个步骤的组件,架构如下所示:

架构的当前状态(图片由作者提供)

当我们第一次介绍该架构时,我们说过编排和数据监控/测试现在都可以由另一个组件来处理——您可能已经猜到该组件是 dbt。借助 dbt Cloud,我们可以管理我们的管道的调度,并定义不同的执行触发器(例如通过 web hooks 定义),同时 dbt 还有一个强大的基于 SQL 的测试功能,我们可以利用它来确保数据质量问题不会被检测到。

运行 dbt 测试后的示例输出(图片由作者提供)

神奇的地方:Apache 超集

既然我们已经处理了我们的数据,并生成了不同的视图和表格来提供见解,那么是时候通过一组 数据产品 来实际可视化这些见解了。(如果你对这个术语不熟悉,Simon O ' Regan的这篇文章详尽地概述了不同类型的数据产品。)

我们在这一阶段的目标是构建最终用户可以直接访问的仪表盘和图表(无论是用于分析还是监控,取决于您的数据集),就像过去的商业智能(BI)一样。

BI 是少数几个没有被数据技术的“第二波”破坏的领域之一,这主要是因为 Hadoop 生态系统专注于大规模处理数据,而不影响最终用户消费数据的方式。这意味着在很长一段时间内,BI 和数据可视化领域由专有工具(Tableau、PowerBI 和最近的 Looker)主导,只有少数缺乏开源项目的利基用例。

然后出现了 Apache Superset。当它在 2016 年首次由 Airbnb 开源时,它代表了第一个真正替代现有 BI 工具的开源工具,提供了企业级所需的所有功能。今天,由于其庞大的开源社区,它是第三次浪潮的领先技术之一。

生产超集部署由多个组件组成(如专用元数据数据库、缓存层、身份验证和潜在的异步查询支持),因此为了简单起见,我们将依赖一个非常基本的设置。

我们将再次利用 Google Compute Engine 来构建一个超集实例,我们将通过 Docker Compose 在其上运行一个容器。本文附带的报告中提供了必要的 Terraform 和 init 脚本。

一旦超集启动并运行,就可以通过以下命令连接到实例:

**gcloud --project=your-project-id beta compute ssh superset-instance -- -L 8088:localhost:8088 -N**

在登录到超集实例(通过官方文档中提供的步骤之后,您只需要将它连接到 BigQuery ,这样它就可以开始与您的不同数据集进行交互。

添加 BigQuery 连接后的预期结果(图片由作者提供)

建立连接后,您可以试验不同的图表类型,构建仪表板,甚至利用内置的 SQL 编辑器向 BigQuery 实例提交查询。

通过 SQL 编辑器查询 BigQuery 数据(作者图片)

现在,我们可以让最终用户通过超集直接访问数据,我们的数据平台如下所示:

架构的当前状态(图片由作者提供)

当谈到超集的功能时,您会很高兴地知道我们只是触及了表面。你可以管理访问角色,利用缓存构建自己的定制 viz 插件,使用丰富的 API,甚至执行行级访问策略。此外,通过预设,您可以选择一个托管版本,让您不必考虑部署。

堆栈的基石:OpenMetadata

元数据管理可能是数据社区中对如何处理分歧最大的领域。这是一个非常分散的空间( 25 种工具和计数),不同的工具在如何解决这个问题上采取了截然不同的方法。

在我个人看来,我坚信优步数据平台团队开源的产品 OpenMetadata 在这个领域采取了正确的方法。通过专注于提供水平元数据产品,而不仅仅是架构中的一块砖,它使拥有集中式元数据存储成为一个可实现的目标。它有非常丰富的 API,执行元数据模式,并且已经有一长串连接器

其他产品正在实现他们自己的管理元数据的方式,并且是在闭门造车的情况下进行的,这将导致在将它们添加到我们的平台时产生不必要的开销,而 OpenMetadata 专注于提供元数据的单一来源,其他产品可以通过其 API 与之交互。通过将它添加到体系结构中,数据发现和治理就成为了一种必然,因为它已经具备了实现这些目标的所有必要特性。如果你想在将它添加到我们的平台之前见证它的能力,你可以首先探索它的沙箱

像 Airbyte 和 Superset 一样,我们将通过 Google Compute Engine 实例部署 OpenMetadata(像往常一样,Terraform 和 init 脚本在附带的 repo 中提供)。部署完成后,您会注意到实际上有四个容器在虚拟机上运行,用于以下目的:

  • 在 MySQL 上存储元数据目录
  • 通过 Elasticsearch 维护元数据索引
  • 通过气流编排元数据摄取
  • 运行 OpenMetadata UI 和 API 服务器

启动 OpenMetadata 后的预期输出(图片由作者提供)

OpenMetadata 在后台尽职尽责地管理这些组件,无需您进行任何必要的配置,因此我们可以立即开始像利用任何其他产品一样利用它。启动并运行后,您可以首先通过以下命令连接到 Airflow 端口:

**gcloud --project=your-project beta compute ssh openmetadata-instance -- -L 8080:localhost:8080 -N**

然后在http://localhost:8080/(用户名:admin,密码:admin)进入气流 UI。您会注意到一些 Dag 已经运行来加载和索引一些样本数据。之后,让我们通过以下命令连接到 OpenMetadata UI(然后可以在[http://localhost:8585/](http://localhost:8080/)访问该 UI):

**gcloud --project=your-project beta compute ssh openmetadata-instance -- -L 8585:localhost:8585 -N**

现在,您只需通过 SSH 登录 GCE 实例,并将 OpenMetadata 连接到 BigQueryBigQuery 使用数据dbt超集。之后,您可以探索其不同的特性和功能,如数据发现和沿袭。

连接到 BigQuery 后打开元数据 UI(图片由作者提供)

既然我们已经将 OpenMetadata 添加到平台中,让我们来看看我们最终确定的架构:

最终确定的平台架构(图片由作者提供)

更上一层楼:可选组件

在本文的开始,我们提到了两个可选组件:编排和数据监控。在理论层面上,这是我们的数据平台的两个非常重要的功能,但是正如我们所看到的,dbt 在这个阶段可以很好地实现这两个功能。尽管如此,让我们讨论一下这两个组件在需要时如何集成。

编排我们的管道:阿帕奇气流

当平台进一步成熟,我们开始集成新的工具和编排复杂的工作流时,dbt 调度最终会变得不足以满足我们的用例。一个简单的场景是当特定的 dbt 模型更新时超集缓存失效——这是我们无法单独通过 dbt Cloud 的调度实现的。

自 2015 年由 Airbnb 开源以来,Airflow 一直是数据工作流编排领域的首选工具。这使得它成为多家科技公司大型数据平台不可或缺的一部分,确保了围绕它的一个庞大而非常活跃的开源社区——这反过来又帮助它在编排方面保持标准,即使在“第三次浪潮”中也是如此。

您应该推迟考虑气流(或其替代品)的原因是专用编排工具带来的额外复杂性。Airflow 以自己的方式看待世界,为了能够充分利用它,您需要做出妥协并调整您的工作流程以匹配其特性。

在集成编排工具时,您还应该考虑如何触发您的管道/工作流。Airflow 确实支持基于事件的触发(通过传感器,但是问题可能会很快出现,让你仅仅因为工具而适应你的需求——而不是让工具帮助你满足你的需求。

帮助我们晚上睡得更好:Soda SQL

就像编排一样,数据监控(最终将允许我们考虑数据的可观察性)是一种需求,dbt 最终将不再为我们的平台充分处理这种需求。

我们不只是验证 dbt 模型的数据,而是希望跟踪整个平台的数据问题,以便我们可以立即确定特定问题的来源并相应地修复它。

像数据集成一样,数据可观察性是公司仍然采用闭源方法的领域,这将不可避免地减缓创新和进步。另一方面,有两个开源产品可以满足我们的大部分需求: Soda SQLGreat Expectations

Soda SQL 是一个很好的起点,因为它不需要太多的投资,并且提供了多种方便的特性。你只需要几个 YAML 文件就可以启动并运行,然后你就可以定义定制测试协调扫描

接下来是什么?

这是一段漫长的旅程。我们经历了不同的技术——其中一些是我们正在见证的“第三次浪潮的产品,其他的是经过时间考验的“第二次浪潮的老手。在这一点上,主要的收获是,构建一个功能齐全的数据平台比以往任何时候都更容易—如果您遵循实施过程,您会发现自己在不到一个小时的时间内就构建了一个随时可用的现代数据平台。

当然,现代数据堆栈仍然是支离破碎的,在我们讨论的一些技术上下注可能是一个冒险的决定。除了 dbt 之外,没有任何现代数据堆栈工具在它所做的事情上是明显的赢家,因此生态系统将在未来几年通过整合和竞争不断变化。不过,可以肯定的是,激动人心的时刻就在我们面前。

要了解更多数据工程内容,您可以订阅我的双周刊时事通讯 Data Espresso,我将在其中讨论与数据工程和技术相关的各种主题:

**https://dataespresso.substack.com/ **

用 Keras 建立图像字幕模型

原文:https://towardsdatascience.com/building-an-image-captioning-model-with-keras-ebccaadb98b9?source=collection_archive---------54-----------------------

如何用 Python 构建 CNN-LSTM 架构

照片由海伦娜·赫兹Unsplash 上拍摄

我一直在做一个探索性的项目,以建立一个概念描述模型,为艺术品生成解释。首先,我开始使用 CNN-LSTM 架构,它可以作为一个简单的字幕生成器。在这篇文章中,我将描述如何构建一个基本的 CNN-LSTM 架构来创建一个可以基于图像输出文本标题的模型。请稍后继续关注我的项目。

CNN LSTM 频道

这种图像字幕的主要方法分为三个部分:1 .使用预先训练的对象识别网络从图像中获取特征;为了将这些提取的特征嵌入映射到文本序列,最后 3 .在给定特征图和文本序列的情况下,使用长-短时记忆(LSTM)来预测序列后面的单词。

数据

这是一个监督网络,我们将图像映射到一组特定的标题。所以我们需要一组有图片和说明的数据。这里有一些公开的数据集可供探索。

  • Flickr30K 数据集: Bryan Plummer 及其同事对来自 Flickr 的 3 万张图片以及多个对应描述的工作。
  • 概念说明 数据集: Google AI 从网络上收集概念说明的努力。它包含 300 多万张图片的标题和 URL 链接。

我不会在这里详细介绍如何下载或调整图片大小。我已经调整了所有图片的大小,使其适合 500x500 像素,并且是 jpg 格式。每个文件名都应该是将文件链接到图像描述的标识 ID。

特征抽出

第一步是使用预先训练的网络提取特征。该代码获取包含 jpg 文件的本地目录,并输出引用字典,该字典以图像 ID 作为键,以特征嵌入作为值。

这个过程可能需要一段时间,所以我添加了一段代码,让您可以在每 1000 次迭代时将进度转储到本地驱动器上。

描述预处理

附带的字幕需要预处理。该函数假设描述集采用具有嵌套元组(id, description)的列表格式。一些图像可能有多个相关联的描述,每一对都应该表示为一个单独的元组。在这一步中,我们还在每个句子中添加特殊的单词来标记序列的开始和结束(塞奇尼塞格芬)。

[(id1, 'description1-1'), (id1, 'description1-2'), (id2, 'description2-1') ... ]

此外,我添加了一个随机选择描述数量的功能,这样我就可以设置最大的标题数量,以防每张图片有太多的标题。

此函数将描述元组列表转换为预处理描述的字典,格式如下:

{ 'id1': ['description1-1', 'description1-2', ...], 'id2': ... } 
# or
{ 'id1': 'description1', 'id2': 'description2 }

交叉验证

现在我们有了数据集,让我们把它们分成训练集、验证集、测试集(这里我把它分成 7:1.5:1.5)。

**from** sklearn.model_selection **import** train_test_split
train_list, test_list = **train_test_split**(list(descriptions.keys()), test_size = 0.3)
val_list, test_list = **train_test_split**(test_list, test_size = 0.5)

序列发生器

概括地说,现在我们有三个 id 列表,分别用于训练集、测试集和验证集。我们还有描述词典和特征词典。现在我们需要将描述转换成一个序列。比如说一个 id 为 1234 的图片,有一个描述说“狗在跑”。这需要分解成如下的输入和输出集:

  • 1234 : [ 塞奇尼→[ ]
  • 1234 : [ 塞奇尼 ][ ] → [ ]
  • 1234 : [ 塞奇尼 ][ ][ ] → [ 跑步
  • 1234 : [ 塞奇尼 ][ ][ ][ 奔跑 ] → [ 塞奇尼】

但是我们不仅需要将句子标记成文本序列,还需要将它们映射成整数标签。例如,假设我们的整个语料库都有这些独特的单词:[ seqini,fast,dog,is,running,seqfin ]。我们可以把这些映射成一个整数映射:[0,1,2,3,4,5]。这将产生以下集合:

  • 1234 : [0] → [2]
  • 1234 : [0,2] → [3]
  • 1234 : [0,2,3] → [4]
  • 1234 : [0,2,3,4] → [5]

因此,逻辑是将整个训练描述集中的唯一单词分配给唯一索引,以创建文本到序列映射。然后我们遍历每个描述,对它们进行符号化,创建序列开发的子集(输入→输出),然后将它们转换成整数序列。因为我们使用在训练集期间创建的几个变量来处理测试集,所以我将它们全部放入一个序列生成器对象类中。

这将为每个训练集和验证集返回两组输入和一组输出。

休息一下…马特·霍夫曼在 Unsplash 上拍摄的照片

模特培训

现在让我们使用 Keras 训练模型。正如该方法中所提到的,其思想是通过 LSTM 层训练单词序列,以便它可以导出遵循该序列的最佳可能单词(实际上是分配给单词的数字)。

预言;预测;预告

预测测试图像的步骤与上述步骤相反。您计算测试图像的特征嵌入,并将其与初始序列一起输入到模型中,初始序列是起始单词' seqini' 的整数表示。然后,您获取预测,将其添加到序列中,并再次将其输入到模型中,并重复进行,直到模型预测出结尾单词' seqfin' 的整数序列。然后使用标记器,我们将整数转换回映射的词汇表。下面的函数将在给定图像 id 的情况下进行预测。

估价

评估机器生成的字幕并不像我们想象的那样简单。相反,我们可以看看预测的 n-grams 与参考标题的匹配程度。这个衡量标准被称为 BLEU(双语评估替角)分数。这个想法是取在机器生成的标题中找到的参考描述中 1-4 克的百分比的平均值,然后对可能夸大百分比的文本应用惩罚。

**from** nltk.translate.bleu_score **import** corpus_bleubleu_1 = **corpus_bleu**(references, # list (or next list)
                     predictions, # list 
                     weights = (1, 0, 0, 0)) # 1-4 grams weights 

我们研究了如何使用 CNN-LSTM 架构创建图像字幕模型。对于人类来说,描述视觉场景涉及不同层次的语言表达和感知,这取决于一个人过去的经验和当前的背景。此外,在人类认知中开发句子序列可能实际上不是“连续的”,因为句法并不直接匹配视觉显著性。因此,有一些重要的区别可以考虑,以推动这个模型进一步取得更成功和更像人类的表现。

快乐学习!

照片由杰米街Unsplash 拍摄

使用 Python 和机器学习构建图像分类器,从相册中过滤掉未使用的图像

原文:https://towardsdatascience.com/building-an-image-classifier-to-filter-out-unused-images-from-your-photo-album-with-python-and-6bc574ae57de?source=collection_archive---------22-----------------------

照片由 Soragrit WongsaUnsplash 上拍摄

使用 Keras 将我的相册图像分类为“保留”或“不保留”

浏览文件夹中的一堆图片,试图找出哪些应该保留,可能会很麻烦。为了解决这个问题,我决定通过构建一个图像分类器来自动化这个过程,该分类器根据我是否想要保留照片来对照片进行分类。

在本文中,我们将使用 Keras 实现一个简单的二进制分类器,将照片分类为“保留”或“不保留”,以自动过滤掉您的个人相册。

如果你愿意,你可以在这里查看我的 Youtube 视频:

台阶

做到这一点的步骤将是:

  • 设置和安装
  • 创建数据集
  • 创建训练/测试文件夹
  • 训练模型
  • 运行 app

如果你想跳过这篇文章直接看代码,可以在这里找到。现在,让我们来看一下这些步骤。

设置和安装

首先,我们将使用 conda 创建一个环境,并安装必要的包(kerasmatplotlibstreamlit):

conda create -n photo_album_sorter_mlpip install -r requirements.txt

创建数据集

我们将采取的第一步是按照创建时间对图像进行分类,并将它们移动到一个名为files_with_dates,的文件夹中,以保持图像相对有序:

在这个脚本中,我们简单地遍历用户提供的文件夹,将图像移动到files_with_dates文件夹,同时在文件名中添加创建时间。

要运行此命令,请在终端中键入:

python sort_creation_time.py — path ./path/to/your/images/folder

现在,我们可以为数据集创建文件夹,我们将标记图像来训练分类器。

这里,我们只是为数据集创建数据文件夹,并使用 matplotlib 建立一个简单的循环,将图像分类为“保留”或“不保留”。要运行此程序,请执行以下操作:

python create_dataset.py

现在,我们将文件拆分到 train 和 test 文件夹中。

在这里,我们只是将图像分割为 80%用于训练,20%用于测试。要运行 do:

python create_train_test.py

训练模型

我们将训练两种类型的分类器,从一个经典 CNN 的简单 Keras 实现开始,它是从 Fran ois Chollet 的博客文章中借来的。

要运行:

python train.py — epochs 10 — batch_size 16

注意你的图片的大小,在这个实现中,我们根据博客文章中关于猫和狗的例子将所有图片的大小调整为 150x150。

尽管这个模型的性能不是很好(在我的示例数据集上大约是 58%),我还是把它作为问题的基线。

我们还使用取自 Keras 文档的模板代码来训练预训练的 inception v3 模型。

在这里,我们只是按照一个基本的设置来微调一个 inception v3 模型,并添加一个小的 CLI 工具来使它易于运行:

python train_pretrained.py — epochs 10 — batch_size 16

这个模型产生了一些非常令人印象深刻的结果,没有过度拟合,在测试集上达到了 93%的性能!

这是一个好消息,但由于每个人都将使用自己的数据集,因此应该会有不同的表现,这取决于一系列因素,如图像的性质或您想从相册中排除的照片类型。

运行 app

现在,在训练之后,为了查看分类器的运行情况,我们将编写一个简单的 streamlit 应用程序来包装我们的模型:

要运行,请键入:

streamlit run app.py

您可以使用 streamlit 的文件上传程序加载图像,分类将写在图像下方。

关于使用 ML 过滤个人照片的最终想法

鉴于机器学习模型的插值性质,我们总是冒着模型将图像错误分类的风险,这可能最终导致我们丢失我们关心的重要照片,所以我的想法是将这作为一种清除杂乱图像的第一种方法,但在完全删除图像之前,总是先进行粗略的查看。

本文的源代码

如果你喜欢这篇文章,加入媒体关注订阅我的简讯。还有,订阅我的 youtube 频道Tiktok推特LinkedInInstagram 上和我联系!谢谢,下次再见!😃

如果你对机器学习设备感兴趣,这里有一个来自 MSI 的 3070 GPU 的附属链接:

https://www.amazon.com/gp/product/B097MYTZMW/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B097MYTZMW&linkCode=as2&tag=lucassoare079-20&linkId=1fd3f206c6077e5372d08c4518764124

这是一个附属链接,如果你购买的产品,我得到一小笔佣金,干杯!😃

参考

使用 Python 构建图像颜色分析器

原文:https://towardsdatascience.com/building-an-image-color-analyzer-using-python-12de6b0acf74?source=collection_archive---------8-----------------------

使用 Scikit-learn 和 OpenCV 的机器学习项目

埃里克·麦克林的照片|作者设计

在这篇文章中,我将向你展示如何创建一个程序来检测颜色,然后计算图像中颜色的权重。这将是一个有趣和简单的基于机器学习的计算机视觉项目,其中我们将使用 Scikit-learn 和 OpenCV 作为我们的主要模块。特别是,平面设计师和网页设计师会发现这个程序非常有帮助。不仅可以检测颜色,还可以在图像中看到它们的音量,这是一个非常好的功能。

作为一名技术和艺术爱好者,我喜欢从事与这两个领域都密切相关的项目。这就是我喜欢编程的原因。你的极限是你的想象力!

如果你对艺术/编程感兴趣,你可以在我的博客上找到很多这样的动手项目。抓紧时间,让我们开始工作吧!

目录

  • 入门
  • 读取图像
  • 功能
  • 图像颜色分析仪在工作
  • 结论

入门指南

在这个色彩分析项目中,我们将使用两个主要模块。它们是 Scikit-learn 和 OpenCV。Scikit-learn 是一个著名的人工智能和机器学习模块。而 OpenCV 是必备的计算机视觉模块。下面是 OpenCV 的一个简短定义。

OpenCV(开源计算机视觉库)是一个开源的计算机视觉和机器学习软件库。OpenCV 旨在为计算机视觉应用提供一个公共基础设施,并加速商业产品中的机器感知。

参考:https://opencv.org

图书馆

首先,让我给你介绍一下图书馆。这个项目我们需要五个图书馆。而这些库可以列举如下: OpenCV,Scikit-learn,NumPy,Matplotlib 和 Collections

现在,让我们使用 pip 来安装它们,pip 是一个 python 库管理器。顺便说一下,我们不需要安装 ccollections;Python 默认自带。

pip install opencv-python scikit-learn numpy matplotlib 

安装完成后,我们可以继续导入它们。顺便说一下,这个项目我会用 Jupyter 笔记本。这是记录过程时间线的好方法。

from collections import Counter
from sklearn.cluster import KMeans
from matplotlib import colors
import matplotlib.pyplot as plt
import numpy as np
import cv2

这里是每个图书馆的官方链接。请随意查看,了解更多信息。

读取图像

我们需要选择一个图像来开始。这是我将在这个项目中使用的图像。

照片由埃里克·麦克林Pexels 拍摄

image = cv2.imread('test_image.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)plt.imshow(image)

我们使用 OpenCV 的 imread 方法来读取图像。然后,我们使用 cvtColor 将颜色格式从 BGR 转换成 RGB。我们在设备上看到的日常图像是 RGB 格式的。

作者图片

功能

在这一步,正如你从标题中可以理解的,我们将编写函数。我将定义三个对我们有用的函数。函数也是简化程序的好方法。

以下是这些函数及其定义。

rgb_to_hex

def rgb_to_hex(rgb_color):
    hex_color = "#"
    for i in rgb_color:
        i = int(i)
        hex_color += ("{:02x}".format(i))
    return hex_color

在这个函数中,我们将 RGB 颜色转换为十六进制颜色格式。这个函数将有助于最终可视化我们的分析结果。我们将有一个输出:十六进制值,而不是三个不同的值(红、绿、蓝)。

准备 _ 图像

def prep_image(raw_img):
    modified_img = cv2.resize(raw_img, (900, 600), interpolation = cv2.INTER_AREA)
    modified_img = modified_img.reshape(modified_img.shape[0]*modified_img.shape[1], 3)
    return modified_img

这个函数主要完成图像的预处理。如果您想在分析颜色之前对图片进行任何更改,这是您可以使用的功能。在这一步中,我们将调整图像的大小和形状。调整大小是可选的,但是为了使颜色分析模型正确工作,需要进行整形。我们将在下面的函数中看到它。

颜色分析

这就是奇迹发生的地方。我将重点介绍函数中发生的事情。

def color_analysis(img):
    clf = KMeans(n_clusters = 5)
    color_labels = clf.fit_predict(img)
    center_colors = clf.cluster_centers_ counts = Counter(color_labels)
    ordered_colors = [center_colors[i] for i in counts.keys()]
    hex_colors = [rgb_to_hex(ordered_colors[i]) for i in counts.keys()] plt.figure(figsize = (12, 8))
    plt.pie(counts.values(), color_labels = hex_colors, colors = hex_colors)
    plt.savefig("color_analysis_report.png") print(hex_colors)
  • 首先,我们使用 k-Means 聚类顶部的颜色。在函数内部,我们传递我们想要划分多少个集群的值。这里的是 K 均值聚类的文档。聚类之后,我们预测权重最大的颜色,这意味着在图像上获得最大的面积。
  • 其次,我们调用计数器函数。Counter 为作为字典键的元素创建一个容器,它们的容量作为字典值存储。如果您不熟悉字典,它们将数据存储在键:值对中。它们就像函数,当你传入“key”时,你可以“value”作为返回。然后我们根据颜色排序。
  • 第三,我们在 rgb_to_hex 函数中传递这些颜色,这样我们就可以得到这些颜色的十六进制值。
  • 最后,结果的可视化。我决定用饼状图,这样会有助于了解整张图片中每种颜色的权重。绘制完图形后,我也使用 savefig 方法将其保存到计算机中。这样,我们就有了结果的记录。

在我们进入最后一步之前,我想分享一篇与我们的计算机视觉项目相关的引人注目的文章:Salma Ghoneim使用 Python 通过基于颜色的图像分割进行对象检测。

运行中的图像颜色分析器

快好了!我们准备好了幕后场景。现在我们可以开始行动了。我们有前面定义的图像,并将其分配给“image”变量。我们将调用 prep_image 函数对图像进行预处理。

modified_image = prep_image(image)color_analysis(modified_image)

作者图片

结论

恭喜你!我们已经创建了一个程序来分析图像并以绘图的形式返回彩色报告。一个令人兴奋的特性是,我们可以定义我们想要将颜色分成多少组。我使用了五个集群,但是可以随意使用不同的值来尝试这个模型。剩下的用 Scikit-learn K-means 模型预测和 OpenCV 来完成。

最终结果出来了:

作者图片

希望你喜欢读这篇文章,并在今天学到一些新的东西。从事动手编程项目是提高编码技能的最佳方式。如果您在执行代码时有任何问题,请随时联系我

我们来连线。查看我的博客youtube 以获得灵感。谢谢你,

ML/人工智能项目

从头开始构建智能语音助手

原文:https://towardsdatascience.com/building-an-intelligent-voice-assistant-from-scratch-3d5749f4af07?source=collection_archive---------6-----------------------

在 RaspberryPi 和 Arduino Nano 33 BLE 上模拟谷歌助手

图片由穆罕默德·哈桑拍摄,来自皮克斯拜

在我的文章用 Alexa 实现家庭自动化中,我们学习了如何模拟物联网设备,并使用语音助理设备远程控制它们。在那里,我们使用了一个 Echo-Dot,每当 Alexa 这个词被发现时,它就会“醒来”。

但是,语音助手是如何工作的呢?

我们将在这个项目中尝试回答这个问题,使用 RaspberryPi 和 Arduino Nano 模拟谷歌助手。

介绍

首先,有必要认识到,市场上的语音助手,如 Google Home 或亚马逊 Echo-Dot,只有在被特定关键词“唤醒”时才会对人类做出反应,第一个关键词是“嘿谷歌”,第二个关键词是“Alexa”。

作者创造的形象

换句话说,识别语音命令的整个过程基于多阶段模型或级联检测。

第一阶段:Echo-Dot 或 Google Home 内部的一个更小的微处理器持续监听声音,等待关键词被发现。对于这种检测,在边缘使用 TinyML 模型。

阶段 2: 只有在被触发时,数据才会被发送到云端,并在更大的模型上进行处理。

TinyML是一个极好的概念,让机器智能就在物理世界旁边;此外,在微处理器级别运行机器学习模型(ML)可以避免延迟、功耗和安全性等问题。

对于这个项目的第一阶段(KWS 或关键词识别),我们将使用一个 Arduino Nano 33 BLE 感知微控制器。在几个集成的传感器中,它有一个数字麦克风,将用于识别关键词。对于第二阶段,RaspberryPi 将用于联系云端上的 Google 服务,以执行由 Arduino 触发的更复杂的任务。

“级联检测”:多阶段模型(改编自 TinyML 教程— HarvardX )

该项目将分为两部分:

第 1 部分:在 RPi 上模拟 Google Assistant

第 2 部分:在 Arduino Nano 上实现 KWS

在这里你可以对最终项目有一个概念:

第 1 部分—在 RPi 上模拟 Google Assistant

除了允许 RPi 模拟谷歌助手的软件之外,一些额外的硬件也是必要的。您可以安装外部麦克风和扬声器,或者为了简单起见使用帽子。在这个项目中,我们将使用一顶帽子,即 ReSpeaker 2-Mics Pi 帽子。

再代言人 2-Mics Pi 帽子

这是帽子的示意图。

图片来自https://wiki.seeedstudio.com/ReSpeaker_2_Mics_Pi_HAT/

它的安装非常简单:

将 ReSpeaker 2-Mics Pi HAT 连接到 Raspberry Pi

图片来自https://wiki.seeedstudio.com/ReSpeaker_2_Mics_Pi_HAT/

在 Raspberry Pi 上设置驱动程序

sudo apt-get update
sudo apt-get upgrade
git clone https://github.com/respeaker/seeed-voicecard.git
cd seeed-voicecard
sudo ./install.sh
reboot

检查安装在 RPi 上的声卡

作者终端打印屏幕

所以,在我的例子中,声卡是:

  • 卡 0: RPi HDMI
  • 卡 1: RPi 耳机音频插孔
  • 卡片 2:2-麦克风皮帽子

卡 2 应该是默认的,您可以在 Pi 首选项/音频设备设置中验证它:

作者打印屏幕

在我的例子中,ReSpeaker 2-Mics Pi HAT(音频插孔)上的输出无法正常工作,所以我将卡 2 定义为输入(ReSpeaker 上的 Mics),将标准 Rpi 音频插孔(卡 1)作为输出。

这种配置是通过编辑。作为/home/pi 文件夹中的 undrc 文件。要编辑该文件,请执行以下终端命令:

sudo nano /home/pi/.asoundrc

并将 pcm.output 从卡 2 更改为卡 1:

作者终端打印屏幕

每当 Pi 首选项/音频设备设置发生变化时,必须检查上述文件。此外,可以在声卡 1 —耳机(RPi 音频插孔)的同一菜单中更改输出音量。

此时,可以进行一些测试:

测试音频输出:

speaker-test -t wav

作者终端打印屏幕

你应该听扬声器里重复的“前”和“左”。按[CTRL]+[C]退出。

测试音频输入:

首先,安装 Python 库 pyaudio,用于在 RPi 上播放和录制音频:

sudo pip install pyaudio

在 puAudio 的网页上,http://people.csail.mit.edu/hubert/pyaudio/,你可以找到如何使用该库的信息和示例。

使用下面的脚本,录制几秒钟(5s)的音频:

import pyaudio
import waveRESPEAKER_INDEX = 2 # refer to input device id (card 2)
RESPEAKER_RATE = 16000
RESPEAKER_CHANNELS = 2
RESPEAKER_WIDTH = 2
CHUNK = 1024
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "record_test.wav"p = pyaudio.PyAudio()
stream = p.open(
    rate=RESPEAKER_RATE,
    format=p.get_format_from_width(RESPEAKER_WIDTH),
    channels=RESPEAKER_CHANNELS,
    input=True,
    input_device_index=RESPEAKER_INDEX,)
print("* recording")frames = []
for i in range(0, int(RESPEAKER_RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)
print("* done recording")stream.stop_stream()
stream.close()
p.terminate()wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(RESPEAKER_CHANNELS)
wf.setsampwidth(p.get_sample_size(p.get_format_from_width(RESPEAKER_WIDTH)))
wf.setframerate(RESPEAKER_RATE)
wf.writeframes(b''.join(frames))
wf.close()

名为“record_test.wav”的文件应该出现在执行脚本的文件夹中。

要验证录制的音频,请执行以下脚本:

import pyaudio
import waveCHUNK = 1024
WAVE_INPUT_FILENAME = "record_test.wav"print("Playing a wave file: {}".format(WAVE_INPUT_FILENAME))
wf = wave.open(WAVE_INPUT_FILENAME, 'rb')
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
    channels=wf.getnchannels(),
    rate=wf.getframerate(),
    output=True)data = wf.readframes(CHUNK)
while data != b'':
    stream.write(data)
    data = wf.readframes(CHUNK)stream.stop_stream()
stream.close()
p.terminate()

如果你听你录的,太好了!我们在出差!

在开始准备我们的 RPi 来模拟 Google Assistant 之前,让我们先来看看安装在 ReSpeaker 2-Mics Pi 帽子上的按钮和 RGB LEDs:

按钮

有一个板载用户按钮连接到 GPIO17,如下图所示。

ReSpeaker 2-Mics Pi HAT 原理图的一部分—参见

现在我们将尝试使用 python 和 RPi.GPIO 来检测它。

首先,安装 RPi。GPIO 库

sudo pip install rpi.gpio

接下来,您可以执行下面的脚本来测试按钮:

import RPi.GPIO as GPIO
import timeBUTTON = 17GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON, GPIO.IN)while True:
    try:
        state = GPIO.input(BUTTON)
        if state:
            print("off")
        else:
            print("on")
        time.sleep(1)
    except KeyboardInterrupt:
        break

在终端上,您将验证按钮何时被按下。

作者终端打印屏幕

车载 RGB 发光二极管(APA102)

ReSpeaker 2-Mics Pi HAT 原理图的一部分—参见

三个板载 APA102 RGB LEDs 各有一个额外的驱动芯片。驱动芯片负责通过其输入线接收所需的颜色,然后保持该颜色,直到接收到新的命令。

安装 spidev 库:

sudo pip install spidev

并克隆以下文件:

git clone [https://github.com/respeaker/mic_hat.git](https://github.com/respeaker/mic_hat.git)

在 mic_hat 子文件夹中,执行 pixels.py 脚本,该脚本将对所有 led 执行测试。使用[CTRL]+[C]键关闭指示灯

python3 pixels.py

像素类有几个准备好的函数:

  • pixels.wakeup():打开所有 LEDS
  • pixels.off():关闭所有发光二极管
  • pixels.think():逐个打开 led,变换颜色
  • pixels.speak():打开所有发光二极管,改变其亮度

要在最终代码中有效地使用该函数,请将文件 apa102.py 和 pixels.py 放在同一个目录中。这样,您可以使用类似下面的简单代码来访问 led:

from pixels import Pixelspixels = Pixels()pixels.wakeup()
pixels.off()
pixels.think()
pixels.off()
pixels.speak()
pixels.off()

谷歌语音服务

此时,所有硬件都正常工作:

  • 音频输入
  • 音频输出
  • 纽扣
  • 发光二极管

是时候在我们的 RaspberryPi 上安装谷歌语音服务了。为此,我们将听取优秀教程http://www.makerspace-uk.co.uk/respeaker-2-mics-pi-hat/.的建议

安装谷歌助手 API

转到 Rpi 主目录,在子目录/voice-recognizer-raspi 下克隆 VoiceKit GitHub

cd ~
git clone -b voicekit https://github.com/google/aiyprojects-raspbian.git ~/voice-recognizer-raspi

转到这个创建的子目录,运行脚本来安装文件:

cd ~/voice-recognizer-raspi
scripts/install-deps.sh

要使用谷歌 Voicekit,必须有 picotts ,这是一个文本到语音的平台,它使用离线 pico 文本到语音引擎以自然的声音阅读文本。要在系统(通常是 Debian)上安装 pico TTS 库,请执行以下操作:

sudo apt-get install libttspico-utils

在一些 Raspbian 版本中,这个包是缺失的,但是你可以从 Debian 复制 arm deb 包。例如,在 Debian Buster 上,软件包丢失了,所以使用下面的命令来安装它:

wget http://ftp.us.debian.org/debian/pool/non-free/s/svox/libttspico0_1.0+git20130326-9_armhf.debwget http://ftp.us.debian.org/debian/pool/non-free/s/svox/libttspico-utils_1.0+git20130326-9_armhf.debsudo apt-get install -f ./libttspico0_1.0+git20130326-9_armhf.deb ./libttspico-utils_1.0+git20130326-9_armhf.deb

安装 gRPC(远程过程调用)

我为什么要使用 gRPC

主要使用场景:

  • 低延迟、高度可扩展的分布式系统。
  • 开发与云服务器通信的移动客户端。
  • 设计一种新的协议,它需要准确、高效且独立于语言。
  • 支持扩展的分层设计,例如身份验证、负载平衡、日志记录和监控等。
sudo pip install grpcio
sudo pip install grpcio-tools

现在,该安装 Google API 和 Google Assistant 库了:

sudo pip install --upgrade google-api-python-client
sudo pip install --upgrade google-assistant-library==1.0.1
sudo pip install --upgrade google-assistant-sdk[samples]==0.5.1

此时,安装了主要的软件包,重新启动系统:

reboot

原始谷歌语音工具包需要更改:

打开文件:

/home/pi/voice-recognizer-raspi/src/aiy/_apis/_speech.py

并注释以下几行:

#try:
# from google.cloud import speech
# from google.cloud.speech import enums
# from google.cloud.speech import types
#except ImportError:
# print("Failed to import google.cloud.speech. Try:")
# print(" env/bin/pip install -r requirements.txt")
# sys.exit(1)

现在,打开文件:

/home/pi/voice-recognizer-raspi/src/aiy/voicehat.py

并将按钮 GPIO(应该显示为 23)更改为在 ReSpeaker 2-Mics Pi HAT 上使用的按钮(应该为 17)

_GPIO_BUTTON = 17

此时,所有硬件和软件都应完成。缺少的部分是从 Google 获得在我们的树莓上运行语音工具包的凭证。

启用谷歌助手 API

启用 API 的所有步骤都可以在谷歌 AIY 语音工具包网站的“获取凭证”部分找到。

作者打印屏幕

这个部分位于页面的最下方(大约是一个长网站的一半)。你应该打开第二页的https://console.cloud.google.com/(谷歌云平台),然后按照第一页的指示去做。如果一切都正确,您的计算机上应该已经下载了一个 JSON 文件。这些说明还解释了如何创建一个 file assistant.json,其中必须保存此类下载文件的内容。该文件必须保存在您的 RPi 主目录中:

作者终端打印屏幕

除了上述说明之外,我还使用 OAuth 同意屏幕页面上的+添加用户选项,将我的电子邮件作为“测试用户”包括在内:

作者打印屏幕

就是这样!考验我们语音助手的时候到了!

测试语音助手

转到安装语音工具包的子文件夹:

cd ~/voice-recognizer-raspi

并运行位于/src 子文件夹中的演示程序:

python3 src/assistant_grpc_demo.py

如果一切正常,您应该在终端上看到以下消息:

作者终端打印屏幕

语音助手正在等待您按下按钮开始对话:

比如我按了按钮,出现了“正在收听…”的信息。我问:“现在几点了?”那也出现在终端上。同时,助理会说出答案。

作者终端打印屏幕

下面的视频更好地说明了一个真实的对话:

作为项目的最后一部分,让我们在上面的代码中包含帽子上可用的 led,如下所示:

将两个文件 apa102.py 和 pixels.py 复制到同一个目录中,在该目录中运行以下代码(在本例中为:“voice-recognizer-raspi/src ”)

import time
import aiy.assistant.grpc
import aiy.audio
import aiy.voicehat
from pixels import Pixels
import loggingpixels = Pixels()
pixels.off()logging.basicConfig(
    level=logging.INFO,
    format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s"
)def wakeup_assistant():
    pixels.wakeup()
    pixels.think()
    time.sleep(3)
    pixels.speak()
    time.sleep(3)
    pixels.off()def main():
    wakeup_assistant()
    status_ui = aiy.voicehat.get_status_ui()
    status_ui.status('starting')
    assistant = aiy.assistant.grpc.get_assistant()
    button = aiy.voicehat.get_button() with aiy.audio.get_recorder():
        while True:
            pixels.off()
            status_ui.status('ready')
            print('Press the button and speak')
            button.wait_for_press()
            status_ui.status('listening')
            print('Listening...')
            pixels.think()
            text, audio = assistant.recognize()
            if text:
                if text == 'goodbye':
                    status_ui.status('stopping')
                    print('Bye!')
                    pixels.off()
                    time.sleep(1)
                    break
                print('You said "', text, '"')
            if audio:
                pixels.speak()
                aiy.audio.play_audio(audio)
                pixels.off()
    pixels.off()if __name__ == '__main__':
main()

现在,一种“唤醒 LED 显示”将在启动过程中增加(一次)。此外,每次按下按钮时,语音助手都会“思考”等待我们的问题,为此我们将使用 pixels.think()函数强制 led 滚动。当助手“说话”时也是如此,led 将保持其 RGB 颜色,但会“褪色”。

注意,如果你说“再见”,助手将被关闭。

玩 GPIOs

在 RPi 上模拟 Google Assistant 的一个显著优势是,我们可以使用它的 GPIOs 来控制现实世界中的外部事物。我们已经使用 ReSpeaker 2-Mics Pi HAT 内置 led 和按钮实现了这一点。HAT 通过 Grove 连接器留有 2 个可用的 gpio(12 和 13),如其电路图所示:

ReSpeaker 2-Mics Pi HAT 原理图的一部分—参见

现在,我们在 RPI GPIO 13 上安装一个外部按钮,在 GPIO 12 上安装一个 LED,如下图所示:

作者创建的图像

我们把之前用来测试帽子按钮的脚本改成现在,测试外接按钮和 LED。每次按下按钮时,LED 都会亮起:

import RPi.GPIO as GPIO
import timeBUTTON = 13
LED = 12GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON, GPIO.IN)
GPIO.setup(LED, GPIO.OUT)
GPIO.output(LED, GPIO.LOW)while True:
    try:
        state = GPIO.input(BUTTON)
        if state:
            GPIO.output(LED,GPIO.LOW)
            print("off")
        else:
            GPIO.output(LED,GPIO.HIGH)
            print("on")
        time.sleep(1)
    except KeyboardInterrupt:
        GPIO.cleanup()
        breakprint("clean up")
GPIO.cleanup() # cleanup all GPIO

视频展示了结果:

使用外部按钮唤醒语音助手

唯一需要做的就是改变助手的按钮 GPIO。打开文件:

/home/pi/voice-recognizer-raspi/src/aiy/voicehat.py

并将按钮 GPIO(应该显示为 17)更改为我们的外部按钮(13)所使用的按钮

_GPIO_BUTTON = 13

从现在开始,只要按下外部按钮,语音助手就会“醒来”。

用语音控制外部设备:

让我们也改变之前使用的完整代码,以纳入 LED,这应该接收一些语音控制:

  • 发动
  • 关掉
  • 眨眼

完整的代码如下:

import time
import aiy.assistant.grpc
import aiy.audio
import aiy.voicehat
from pixels import Pixels
import logging
import RPi.GPIO as GPIOLED = 12
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED, GPIO.OUT)
GPIO.output(LED, GPIO.LOW)pixels = Pixels()
pixels.off()logging.basicConfig(
    level=logging.INFO,
    format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s"
)def led_blink():
    for i in range (0,6):
    GPIO.output(LED,GPIO.HIGH)
    time.sleep(0.25)
    GPIO.output(LED,GPIO.LOW)
    time.sleep(0.25)def wakeup_assistant():
    pixels.wakeup()
    pixels.think()
    time.sleep(3)
    pixels.speak()
    time.sleep(3)
    pixels.off()def main():
    wakeup_assistant()
    status_ui = aiy.voicehat.get_status_ui()
    status_ui.status('starting')
    assistant = aiy.assistant.grpc.get_assistant()
    button = aiy.voicehat.get_button() with aiy.audio.get_recorder():
        while True:
            play_audio = True
            pixels.off()
            status_ui.status('ready')
            print('Press the button and speak')
            button.wait_for_press()
            status_ui.status('listening')
            print('Listening...')
            pixels.think()
            text, audio = assistant.recognize() if text:
                if text == 'goodbye':
                    status_ui.status('stopping')
                    print('Bye!')
                    pixels.off()
                    time.sleep(1)
                    break
                if 'turn on' in text:
                    pixels.off()
                    GPIO.output(LED,GPIO.HIGH)
                    play_audio = False
                if 'turn off' in text:
                    pixels.off()
                    GPIO.output(LED,GPIO.LOW)
                    play_audio = False
                if 'blink' in text:
                    pixels.off()
                    led_blink()
                    play_audio = False
                print('You said "', text, '"') if play_audio:
                if audio:
                    pixels.speak()
                    aiy.audio.play_audio(audio)
                    pixels.off()
    pixels.off()if __name__ == '__main__':
main()

结果在这里:

第 2 部分使用关键词识别(KWS)

到目前为止,在我们的语音助手上,用来唤醒它的方法是使用一个物理按钮,但正如在介绍中讨论的那样,语音助手,像 Google Home,应该在特定关键字被用作“嘿 Google”时做出反应。

该项目将使用一种被称为 KWS 或关键字识别的机制,用“虚拟按钮”取代物理按钮。我们将使用一个 Arduino Nano 33 BLE Sense ,这是一个集成了数字麦克风的微控制器,将用于识别关键词。

作者照片

为了简化(曾经这个项目的主要对象不是神经网络模型的开发),让我们重新使用 Google incorporated 在 Arduino IDE 上开发的一个代码,使用 TensorFlowLite 创建,命名为“micro_speech”。这幅草图包含了一个模型,它可以识别两个词:是,不是,除了未知和沉默。您可以从示例选项卡中获取,如下所示:

作者打印屏幕

为了测试,你可以把代码上传到你的 Arduino Nano 上,然后通过说“是”或“否”来测试。发现时,内部 RGB LED 应亮起(是:绿色,否:红色)。

快速回顾语音识别在微处理器上的工作原理

作者图片

Arduino 将在使用 TensorFlow 开发的预训练模型中执行推理。卷积神经网络模型(tiny_conv)用+100,000 个每秒(或更少)的记录样本来训练。wave 格式)的 35 个不同音素(谷歌语音命令数据集)。TensorFlowLite 将训练好的模型转换为 C 字节数组,以在小型微处理器上用作 Nano(最终模型的准确度超过 90%,大小仅为 19K 字节)。

观察原始数据(声音输入。波形格式)不能直接用于 CNN 模型。首先,声音数据应该转换成图像(40x49 像素),这是使用 MFCC 特征转换器完成的,如下所示:

作者图片

Mel-频率倒谱系数(MFCC)是共同构成 MFC 的系数,也就是说,它是声音的短期功率谱的表示,基于对数功率谱在非线性 Mel 频率标度上的线性余弦变换。

让我们看看代码一般是如何工作的:

1.Arduino 应该会持续聆听周围的声音。麦克风采集音频样本(1 秒),将其转换为 16 位数据(脉冲编码调制——PCM)。音频提供模块完成这项任务。

2.PCM 数据在用作推断之前应该进行预处理。在模块特征提供程序中,MFCC 特征转换器将原始数据转换为图像。每个样本将是单色图像(或大小为:[1,49,40,1]的张量)

3.TFLite 解释器运行推理,或者更好地说,将输入张量分为四个不同的类别。输出将是维数为[1,4]的张量,其中的值是输入声音为无声、未知、是或否的概率。

4.基于这些概率,模块命令识别器和响应器将使用 TFLite 解释器输出来决定是否听到命令并采取适当的行动。例如,如果声音是“是”的概率较高,内部绿色 RGB LED 将打开,如果是“否”,则打开红色 LED,最后,对于任何其他可能的单词,打开蓝色 LED。该模型被量化为 8 位整数,因此概率从 0 到 255。如果概率大于 200(80%左右),则执行该命令。

下图恢复了该过程:

作者图片

修改硬件

我们将安装两个外部 LED,复制 Nano 内部 RGB LED 的功能。绿色发光二极管将连接到纳米输出 D2 和红色的 D4。纳米输出 D3(与 GND 一起)将取代连接到 RPi GPIO13 的外部物理按钮。

作者图片

修改代码

我们必须修改代码,以便每次发现单词 YES(我们的唤醒词)时,外部绿色 LED 就会亮起,并向 RPi 发送一个脉冲,模拟按下一个按钮。

如您所见,唯一应该更改的模块是命令识别器& Responder 那会让事情发生的!这段代码在选项卡上:arduino_command_responder.cpp(这个选项卡在之前显示的 Arduino IDE 图像上高亮显示)。

下面是应该添加到 arduino_command_responder.cpp 中的新代码部分:

...#define GREEN_LED_PIN 2
#define SIM_BUT_PIN 3
#define RED_LED_PIN 4// Create a function to simulate a button pressed for 500msvoid buttonSimulator(){
  pinMode(SIM_BUT_PIN, OUTPUT);
  digitalWrite(SIM_BUT_PIN, LOW);
  delay(500);
  pinMode(SIM_BUT_PIN, INPUT);
}...pinMode(GREEN_LED_PIN, OUTPUT);
pinMode(RED_LED_PIN, OUTPUT);
pinMode(SIM_BUT_PIN, INPUT); // Open state...// If we hear a command, light up the appropriate LEDs and send signal to RPi
    if (found_command[0] == 'y') {
      last_command_time = current_time;
      digitalWrite(LEDG, LOW);  // Green for yes
      digitalWrite(GREEN_LED_PIN, HIGH);  // HIGH for yes
      buttonSimulator(); // Simulate button 
    } if (found_command[0] == 'n') {
      last_command_time = current_time;
      digitalWrite(LEDR, LOW);  // Red for no
      digitalWrite(RED_LED_PIN, HIGH);  // HIGH for yes
    }...// If last_command_time is non-zero but was >3 seconds ago, zero it
  // and switch off the LED.
  if (last_command_time != 0) {
    if (last_command_time < (current_time - 3000)) {
      last_command_time = 0;
      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(GREEN_LED_PIN, LOW);
      digitalWrite(RED_LED_PIN, LOW);
      digitalWrite(LEDR, HIGH);
      digitalWrite(LEDG, HIGH);
      digitalWrite(LEDB, HIGH);
    }...

要了解更多关于 TinyML 和原始代码是如何开发的,我强烈建议阅读由彼得·沃顿丹尼尔·斯图纳亚克TinyML 的伟大著作:在 Arduino 和超低功耗微控制器上使用 TensorFlow Lite 进行机器学习

图书封面

就是这样!

结果可以在简介中的视频和我的 GitHub 中完整修改的 Arduino 代码上得到验证。

结论

一如既往地希望这个项目能帮助其他人在 AI、电子和 IoT 的激动人心的世界中找到自己的路!

请访问我的 GitHub 获取更新文件:智能语音助手

更多项目,请访问我的博客:MJRoBot.org

来自世界南部的 Saludos!

我的下一篇文章再见!

谢谢你

马塞洛

在 Jupyter Notebook 中构建交互式注释工具

原文:https://towardsdatascience.com/building-an-interactive-annotation-tool-inside-jupyter-notebook-f3d92570ee16?source=collection_archive---------10-----------------------

朱庇特笔记本是❤️️的

来自的修改图像

在这篇博客中,我将讨论如何使用 ipywidgets 模块,并在你自己的 Jupyter 笔记本中构建一个交互式注释工具。所有现在或曾经在任何初创公司担任数据科学家的人都知道他们需要做的工作范围。其中,构建任何类型的接口(用于展示 API 功能、注释等)都很常见,由他们来设计和开发。这种用户界面从来不会出现在公众面前,而是季节性地用于内部目的和开发。

在这篇博客中,我们将会看到如何轻松地构建一个注释工具,并利用 Jupyter 笔记本来完成同样的任务。我假设您已经熟悉 Jupyter 笔记本,但是,如果我不得不写一行关于它的话,它是一个基于浏览器的交互式编码环境具有许多令人惊叹的功能,如就地图形渲染、将代码导出为文档 (latex、pdf 等)等等。

我们将专注于为构建一个非常简单的注释工具奠定基础,该工具用于注释句子分类任务的数据,例如情感分类、意图分类等等。这同样可以扩展到图像。同样的也可以扩展到图像。下面的代码片段显示了我们将要构建的句子注释器工具的最终产品

使用 ipywidgets 在 Jupyter 笔记本中进行交互式注释|作者图片

我们首先从构建工具的描述部分开始。正如在下面的代码中可以看到的,我们从应该被注释的句子列表中读取输入,但是合并从文件系统中读取也不难,可以使用 glob 模块遍历文件,这将返回给定文件夹中所有文件的路径列表。

我们要做的下一件事是创建一个长度等于要注释的句子数量的空数据帧。然后,我们使用 HTML 小部件在我们的笔记本中呈现 HTML 样式的内容。这样,我们定义了可能需要的标题、任何指令等,帮助注释者顺利完成工作。

# data for text classification annotation  
 sentences = ["i like to eat food", "i like to play hockey", "food is the best thing that can be on earth", "do you know how to play chess"]  
 ####################################################################################################  
 # Instead of list you can take input from your LFS or Drive and transform data in the list format  
 ####################################################################################################  
 #to be shown at a time  
 BATCH = 10  
 # output dataframe  
 cols = ['sentence', 'label']  
 df = pd.DataFrame(columns=cols, index=range(len(sentences)))  
 title_widget = widgets.HTML(  
   value="""<h1>Welcome to the <font color='maroon'> Sentence Annotator</font></h1>  
   <p>It's an in-line annotation tool that let's you annotate sentences with their respective tags</p>  
   <p>Below are the set of instructions for the annotator to follow - </p>  
   <ol>  
    <li>Select sentence from the <b>sentences</b> area shown in the annotation area</li>  
    <li>You can select multiple sentences by pressing ctl+mouseclick</li>  
    <li><b>Label</b> area where you type the tags that are relevant for the given sentence</li>  
    <li>Progress let's you track the progress made so far in the annotation cycle</li>  
   </ol>  
   <p><font color='green'>P.S. Incase of multiple labels for any sentence. Use comma (,) as a seperator</font></p>""",  
 )  
 display(title_widget)

我们关注的下一件事是构建文本选择片段,在这方面,我们计划提供多选功能,因为这将加快进程,并帮助注释者一次选择多个句子并一次性注释它们。我们使用 SelectMultiple 小部件来实现这一点。我们还传入一些必要的参数,比如句子、批处理(一次显示多少)、段的描述以及要显示的宽度。

# sentence placeholder  
 sentence_widget = widgets.SelectMultiple(  
   options=sentences,  
   rows=BATCH,  
   description='Sentences',  
   disabled=False,  
   layout= widgets.Layout(width='50%')  
 )  
 display(sentence_widget)

接下来,我们研究如何制作标签、按钮和进度部分。我们使用文本小部件,它为我们提供了一个输入类标签的文本输入空间。我们还使用一个按钮小部件来冻结到目前为止为一个给定的批处理完成的注释,并用相关的字段进行初始化,比如描述、样式和工具提示。我们还使用 IntProgress 小部件制作了一个进度条,它为我们制作的每个注释更新一个单位的进度条。我们用最小值和最大值分别作为 0 和句子总数来初始化它。

# class placeholder  
 label = widgets.Text(description="Label", value='')  
 display(label)  
 # button placeholder  
 button = widgets.Button(description="Annotate", disabled=False, button_style="success", tooltip="Annotate")  
 output = widgets.Output()  
 display(button, output)  
 # progress bar placeholder  
 progress = widgets.IntProgress(  
   min=0,  
   max=len(sentences),  
   step=1,  
   description='Progress:',  
   orientation='horizontal',  
   layout= widgets.Layout(width='20%')  
 )  
 display(progress)

到目前为止,我们已经介绍了该工具的外观和感觉,现在我们继续编写相同的后端功能。我们的函数 annotate 负责所有这些事情,单击 annotate 按钮调用它。我们检查标签和句子小部件下的值,并通过某些强制检查来正确地获取它们。然后,我们遍历句子,将它们一个接一个地添加到我们之前创建的空数据框中。

counter = 0 #keep count of progress in dataframe  
 def annotate(_):  

   global counter  

   with output:  
     label_value = label.value  
     selected_sentence = sentence_widget.value  

     if not len(selected_sentence):  
       print("No sentence selected!")  
       return  
     if not label_value:  
       print("No class name selected!")  
       return  

     progress.value += len(selected_sentence)  

     for i in selected_sentence:  
      df.loc[counter].sentence = i  
      df.loc[counter].label = label_value  
      counter += 1  

 button.on_click(annotate)

这篇博客到此为止。随意访问 Colab 笔记本 ,也可以查看这个牛逼库的 官方自述

Jupyter 笔记本中的句子注释演示|图片由作者提供

注:如果 collab 笔记本无法使用,请考虑将笔记本下载到您的系统中,并在本地启动 Jupyter。

我希望这本书值得你花时间阅读。谢谢大家!

使用 SQL 和 Datapane 构建交互式 Python 仪表板

原文:https://towardsdatascience.com/building-an-interactive-python-dashboard-using-sql-and-datapane-46bd92294fd3?source=collection_archive---------4-----------------------

使用开源工具构建商业智能应用原型

介绍

数据分析最重要的技能之一是与数据库交互。大多数组织将他们的业务关键数据存储在类似 Postgres 或 MySQL 的关系数据库中,你需要知道 T2 的结构化语言来访问或更新存储在那里的数据。

Stephen Dawson 在 Unsplash 上拍摄的照片

SQL 是一种令人难以置信的语言——它发明于 20 世纪 70 年代,大多数新的数据库项目(如 Redshift、Snowflake、CockroachDB)仍然选择它作为基础,因为它功能强大且相对简单(至少在开始时是这样)。虽然它擅长检索数据,但您通常需要像 Tableau 或 Looker 这样的企业商业智能平台来可视化结果。

在本文中,我将向您展示如何结合 SQL 和开源 Python 库来构建一个 web 上的交互式仪表盘——点击这里查看实时版本和 Github 上的代码。这是一项使用数据库快速构建应用程序原型的伟大技术。

数据集

我们将使用一个著名的开源数据集,名为 Chinook ,它存储了一家小型音乐商店几年来的购买数据。这些数据作为一个 SQLite 数据库存储在一个文件中,所以我们可以直接从本地 Python 环境中查询它,而不需要访问凭证。

下面是显示数据库模式的快速表格:

图片由作者提供,灵感来自 arjunchndr

如果你来自熊猫,不熟悉数据库模式,这里有一些提示:

  • 数据库被分割成单独的,它们代表不同的逻辑对象。例如,所有客户都在客户数据库中。这与传统的熊猫数据框架不同,后者通常只有一张表。
  • 每个表都有一组字段、定义表的属性,还有行、存储实际数据。这些就像 Excel 中的列和行一样。
  • 表之间的关系由称为外键的特殊字段表示。例如,每首曲目都有一个 album_id,它链接到专辑表,这意味着每首曲目都是专辑的一部分。当我们查询数据库时,我们通常会根据外键将不同的表连接在一起。

连接到数据库

我们将从定义一些连接到数据库的帮助函数开始:

如您所见,我们将 SQL 查询写成字符串,然后在 Python 函数中执行它。像这样将两种不同的语言混合在一起有点尴尬,但是一旦你掌握了窍门,它会出奇地好!运行上面的代码会给出数据库中所有不同的表名以及每个表中的行数:

作者图片

构建仪表板

假设你刚开始在 Chinook 做数据科学家,你的老板想知道最畅销的曲目,这样他们就可以在网站上推广它们。要回答这个问题,我们需要编写如下查询:

我们首先选择希望在输出中看到的列。因为这些来自四个不同的表(track、album、artist、invoice_line),所以我们需要根据外键关系连接这些表—检查模式,看看有什么可能。接下来,我们按曲目名称分组,按购买次数最多的顺序排序,只选择前 10 个结果。

运行查询给我们一个熊猫数据帧,然后我们将它包装在一个数据表块中,并发布给Datapane.com

这将生成一个交互式表格,用户可以对其进行过滤和排序。看起来吉米·亨德里克斯用十大曲目中的五首摇滚起来了!

更复杂的查询

随着我们最近的成功,老板问了我们一个更复杂的问题——“谁是我们表现最好的销售员工,他们什么时候销售额最高?”

我们可以使用像 Plotly 这样的 Python 可视化库来构建更令人满意的交互式图表,而不是用表格来回答这个问题:

这个查询比前一个查询复杂得多:

  • 我们使用 strftime 来截断时间戳,这样我们就可以按月分组。当我们绘制数据时,这使得数据看起来更好。
  • 我们使用子查询(也称为公用表表达式)来计算中间表(customer_support_rep_sales)。然后,我们在最终查询中调用这个表。
  • 有些操作既可以在 pandas 中完成,也可以在 SQL 中完成——例如,我们在 Pandas 中做了一个 groupby 来删除第二个图表中的“月”列。我更喜欢用 SQL 做最复杂的连接和分组,如果必要的话,只使用 Python 来格式化结果。

运行上面的代码会得到以下结果:

看起来月度表现相当不稳定,没有明显的季节性影响。简是销售业绩最好的人,领先史蒂夫约 20%。

完整仪表板

从现在开始,世界就是你的了。您可以编写超级复杂的 SQL 查询,并用任何 Python 库可视化它们。在仪表盘的完整版本中,我添加了一些额外的图表和可视化效果:

  • 总客户、员工和销售曲目的汇总统计数据
  • 按流派销售
  • 按国家/地区列出的销售和客户
  • 平均订单百分比差异与国家平均值
  • 客户终身价值

你可以在 Github 上看到这个教程的完整代码。

最后

在本教程中,您已经看到了如何通过在 Python 中编写 SQL 语句、用 Plotly 绘制结果并与 Datapane 共享它们来构建交互式仪表板。

这是一个很好的方法,可以快速建立想法的原型,或者构建标准 BI 平台中没有的更复杂的可视化。

构建 M&M 颜色分类器

原文:https://towardsdatascience.com/building-an-m-m-colour-classifier-19a78f28ee8a?source=collection_archive---------41-----------------------

我第三年的电子和电气工程项目之一是建造一台可以根据颜色对 M & Ms 进行分类的机器。最终版本可以每分钟分拣大约 47 颗糖果,并为我们的团队赢得了几瓶啤酒。

演示当天的色选机(视频由作者提供)

也许有一天我会写一篇文章详细介绍这个过程,但我今天想谈的是颜色分类;它最初是如何对甜食进行分类的,两年后,用我新发现的数据科学知识解决了这个问题。当我学习机器学习技术时,我一直将测试数据作为试验各种机器学习技术的试验场,所以这篇博客旨在记录我的学习过程。

M&M 彩色数据(图片由作者提供)

通过机器运行 M&Ms 收集数据,记下颜色传感器返回的红色、绿色和蓝色值,并记录糖果的颜色。确实是一个漫长而乏味的过程。分类过程完全是手动的;我检查了群集的位置,并设置了包围盒来分类落入其中的糖果。

使用边框分类(按作者分类的图像)

这对于一个电子项目来说已经足够了(也足够赢得啤酒了),但是它伴随着一系列的问题。

首先,机器不知道如何处理异常值——它会摇晃糖果并重新扫描它们,如果不起作用,它会把它们扔进垃圾箱。也没有考虑分布的形状和方向。这成为一个问题,尤其是红色和橙色糖果,因为它们的边界框相交。如果一个糖果落在交叉区域,机器会摇晃并重新扫描,直到它落入专用的红色或橙色盒子中(红色盒子在本演示中获胜)。该机器还对糖果进行硬分类,这导致了许多红色/橙色混淆。让我们看看这种技术的混淆矩阵。

(图片由作者提供)

哦,看起来分类器甚至很难对很多糖果进行分类。也许我们可以用一种不同的技术来改进这一点。我们将通过直接估计六个高斯分布来解决这个问题。这很容易;我们只是计算每种颜色的均值和协方差矩阵。让我们来看看原始数据的分布情况。

模拟高斯分布(图片由作者提供)

我们可以通过获取给定糖果属于每个分布的可能性来评估该模型的表现。我们通过将其 RGB 值分成六个概率密度函数并根据最高似然性对其进行分类来做到这一点。让我们看看新的混淆矩阵。

(图片由作者提供)

好多了。由于每种甜味都位于每种高斯色的某个地方,因此它们都属于颜色类别之一。有了这个解决方案,我们在红色和橙色之间只有一个错误的分类!如果我们只想对超过一定置信度的糖果进行分类,也可以设置可能性阈值。

谢谢你给我读这个!我知道有潜在的过度拟合问题,因为我们的火车和测试集是相同的,每种颜色的糖果数量不统一,但这个问题似乎有点无关痛痒。虽然我确实计划使用这个 homeade 数据集来测试各种 ML 算法,但今天更多的是一个介绍,(并掌握平台)。

您可以在下面的 GitHub repo 中找到今天使用的所有代码:https://github.com/LMurphy99/M-M-Colour-Sorter

在 Azure DevOps 中使用多级管道构建和部署 C# Azure 函数

原文:https://towardsdatascience.com/building-and-deploying-c-azure-functions-using-multi-stage-pipelines-in-azure-devops-993239e4d41c?source=collection_archive---------12-----------------------

实践教程

使用 YAML 构建管道,我们可以在一个文件中定义整个构建和发布管道!

我们可以在一个 YAML 文件中定义我们的构建、测试和部署任务!

介绍

作为我个人发展的一部分,我创建了一个个人健康平台,它使用各种不同的微服务(使用 Azure 函数构建),这些微服务从我的 Fitbit 帐户中提取数据,并将它们存储在 Azure Cosmos DB 数据库中。我还有其他的微服务,通过 Azure Service Bus 在不同的服务之间传递消息。

对于这个项目,我使用 Azure DevOps 来构建我的工件,运行我的单元测试,并将我的微服务部署到 Azure。DevOps 的伟大之处在于,我们可以在 YAML 管道中完成所有这些工作。

是的,我说 YAML。老实说,我不知道有什么大惊小怪的😂

在之前的一篇文章中,我谈到了我们如何使用 YAML 管道将 NuGet 包部署到 Azure 工件中的私有 feed。如果你还没看过那个帖子,可以看看下面!

用 YAML 构建文件将 NuGet 包发布到一个私有 Azure 工件 feed 上

在本文中,我们将把注意力转向使用单个构建文件来构建和部署 C# Azure 函数。

我们将涵盖的内容

我们有相当多的内容要介绍,所以我将分解我的 YAML 文件,并按以下顺序讨论每个阶段:

  • 触发构建👷‍♂️👷‍♀️
  • 在管道中使用用户定义的变量👨‍🔬👩‍🔬
  • 定义阶段💻
  • 构建我们的项目🔨
  • 运行我们的测试🧪
  • 获得代码覆盖率🧾
  • 生产构建工件🏠
  • 使用密钥库中的秘密🔑
  • 将我们的功能部署到 Azure ⚡
  • 运行我们的构建管道🚀

触发构建👷‍♂️👷‍♀️

在我们的构建管道中,我们可以使用触发器来运行管道。我们可以使用不同类型的触发器,从当我们将代码推到一个定义的分支时触发构建,到基于 CRON 调度的调度触发器。

对于这个项目,我只是在每次推进到主分支时触发我的构建。为此,我在我的 YAML 文件中这样定义它:

trigger:
  - main

现在,如果我想正确地做到这一点,我们可以定义多个分支名称来触发构建,如下所示:

trigger:
  - feature/*
  - bugfix/*

这将在我们将代码推送到我们的功能或 bugfix 分支时触发构建。当我们在 DevOps 中提出 Pull 请求时,我们可以在 PR 上创建策略,只有在构建成功的情况下才有资格合并回我们的主分支。

这有助于我们增强信心,相信我们正在合并(和部署)的代码是高质量的,特别是如果我们将测试作为构建管道的一部分来运行的话。

要在您的分支策略上启用构建验证,请查看这个文档

在管道中使用用户定义的变量👨‍🔬👩‍🔬

我们可以在 YAML 文件中使用用户定义的变量,以便在整个管道中使用。这样做给了我们在管道的不同阶段和任务中重用公共值的好处,并且它允许我们使用版本控制来跟踪它们随时间的变化。

我们可以在 out 文件中用以下范围定义变量:

  • 在根层,使它对我们管道中的所有工作都可用。
  • 在阶段级别,使其可用于我们管道中的特定阶段。
  • 在作业级别,使其可用于我们管道中的特定作业。

在我的例子中,我将在整个管道中重用这些变量,所以我在根级别定义它们。

variables:
  buildConfiguration: 'Release'
  vmImageName: 'vs2017-win2016'
  functionAppName: 'famyhealthfitbitbody'
  azureSubscription: '<azureSubscription-id-or-name>'
  workingDirectory: '$(System.DefaultWorkingDirectory)/MyHealth.Fitbit.Body'
  projectName: 'MyHealth.Fitbit.Body'

我们不仅仅局限于 YAML 管道中的用户定义变量!我们也可以使用系统和环境变量。要了解更多关于在 YAML 管道中定义变量的信息,请查看这篇文章

定义阶段💻

在我们的 YAML 管道中,我们可以将我们的工作分成几个阶段。这些将我们的渠道分为逻辑…嗯,执行特定任务的阶段,例如“构建应用程序”、“部署到生产”。

在本例中,我只有一个阶段和部署阶段。即使我们没有定义,每个 YAML 管道都至少有一个阶段。正如我在文件中所做的那样,我们还可以根据前一个阶段是否成功来运行阶段,如下所示:

stages:
  - stage: Build
    displayName: Build Stage jobs:
      - job: Build
        displayName: Build MyHealth.Fitbit.Body
        pool:
          vmImage: $(vmImageName)

使用 YAML 管道,我们可以定义管道的多个阶段,并将其存储为代码。如果你想了解更多关于 YAML 管道中阶段的工作方式,请查阅文档

构建我们的项目🔨

让我们把注意力转向我们的函数。首先,我想恢复和建立我的。csproj 文件。在我们 YAML 的管道里,我们可以唱歌。NET 核心任务来对我们的工件运行 dotnet 命令。为了构建我的项目,我将恢复构建

我正在使用 Azure 工件上托管的自定义 NuGet 提要,所以在恢复时我需要指向这个提要。

对于构建任务,我想构建一个发布包,所以在运行 build 命令时,我将传入 buildConfiguration 变量作为参数。

对于这两个命令,我将指向 all。我的存储库中的 csproj 文件。

steps:
- task: DotNetCoreCLI@2
  displayName: Restore
  inputs:
   command: 'restore'
   feedsToUse: 'select'
   vstsFeed: '<feed-id>'
   projects: '**/*.csproj'- task: DotNetCoreCLI@2
  displayName: Build
  inputs:
   command: 'build'
   projects: '**/*.csproj'
   arguments: --configuration $(buildConfiguration)

运行我们的测试🧪

除了我的函数代码,我还有一个单元测试项目。作为构建的一部分,我想运行我的单元测试,以确保我的更改没有破坏我们的任何测试,并且它们仍然通过。如果我的任何测试失败,我希望构建失败。

为了运行我们的测试,我们可以使用一个运行测试命令的. NET 核心任务,并将任务指向我们的单元测试。csproj 文件。

我还想用 Coverlet 收集代码覆盖率指标。床罩是。NET 工具,它允许我们获得行、分支和方法覆盖的单元测试覆盖。在我们的 arguments 参数中,我告诉我的任务运行 Coverlet 来获取代码覆盖率,然后将测试结果发布到我的构建代理上的*/TestResults/Coverage 文件夹中:

- task: DotNetCoreCLI@2
  displayName: Run Unit Tests
  inputs:
   command: 'test'
   projects: '**/*UnitTests/*.csproj'
   arguments: '--configuration $(buildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$(Build.SourcesDirectory)/TestResults/Coverage/'
   publishTestResults: true

获得代码覆盖率🧾

一旦我们生成了覆盖报告,我们就可以发布它来查看结果。我有两个任务要完成。

首先,我使用 bash 脚本任务将报告生成器安装到构建代理上。安装完成后,我将在代理上的 TestResults/Coverage 文件夹中创建 xml 报告。我们还可以指定想要生成的报告类型,但是对于本教程,我只是生成一个内嵌的 HTML 报告。

如果您想为此使用一个任务,而不是运行一个内联脚本,您可以尝试将下面的任务安装到您的 DevOps 组织中。

一旦我们生成了报告,我还有第二个任务,发布代码覆盖报告。

- script: |
    dotnet tool install -g dotnet-reportgenerator-globaltool
    reportgenerator -reports:$(Build.SourcesDirectory)/TestResults/Coverage/coverage.cobertura.xml -targetdir:$(Build.SourcesDirectory)/CodeCoverage -reporttypes:HtmlInline_AzurePipelines;Cobertura
    displayName: Create Code coverage report- task: PublishCodeCoverageResults@1
  displayName: 'Publish Code Coverage'
  inputs:
    codeCoverageTool: Cobertura
    summaryFileLocation: '$(Build.SourcesDirectory)/**/coverage.cobertura.xml'
    reportDirectory: '$(Build.SourcesDirectory)/TestResults/Coverage/'

当我们的构建完成时,我们可以在 DevOps 中查看我们的代码覆盖率报告!它应该看起来像这样:

我们可以生成一个测试报告,为我们提供行、分支和方法级别的覆盖细节

生产构建工件🏠

我们已经构建了我们的项目,并且通过了测试!我们现在需要生产一个构建工件,我们将把它作为我们的功能来部署。

从发布开始,这里我们需要的是一个. NET 核心任务,它运行 publish 命令,将我们的项目发布为“发布”包,压缩它,然后将其发布到我们的构建代理上的工件暂存目录。

然后,我们使用一个发布构建工件任务将一个名为‘drop’的工件发布到我们的暂存目录中。

- task: DotNetCoreCLI@2
  displayName: Publish
  inputs:
    command: 'publish'
    publishWebProjects: false
    projects: '**/*.csproj'
    arguments: '--configuration $(buildConfiguration) --output $(build.artifactstagingdirectory)'
    zipAfterPublish: True- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'

在我们开始部署之前,简单回顾一下。在构建阶段,我们有:

  • 建造了我们的。净项目
  • 运行我们的单元测试以确保我们的构建是一个高质量的构建
  • 生成并发布代码测试覆盖报告。
  • 发布一个构建工件以部署到 Azure。

完成后,我们现在准备进入部署阶段!

展开我们的功能阶段

对于我们的部署阶段,我们需要在 YAML 文件中创建一个新的阶段。

在这种情况下,我已经向我们的 Stage YAML 块添加了一个条件依赖属性。在 YAML 文件中,我说“部署”阶段依赖于我们的“构建”阶段,并且“部署”阶段将仅在“构建”阶段成功的条件下运行。

- stage: Deploy
    displayName: 'Deploy MyHealth.Fitbit.Body'
    dependsOn: Build
    condition: succeeded() jobs:
      - deployment: Deploy
        displayName: Deploy MyHealth.Fitbit.Body
        environment: Production
        pool:
          vmImage: $(vmImageName)

当我们在一个管道中使用多个阶段时,它们将按照我们在 YAML 文件中定义的顺序运行。我们可以使用 dependsOn 参数向我们的阶段添加依赖关系。

我们可以通过指定哪个阶段的条件来控制该阶段的运行。在我的例子中,我声明“部署”阶段只有在“构建”阶段成功运行的情况下才会运行。

要了解更多关于 YAML 管道条件的工作原理,请查阅以下文档

使用密钥库中的秘密🔑

在我的函数中,我执行各种任务,比如向服务总线队列和主题发送消息,使用访问令牌调用 API 等。等等。

为了进行这些操作,我需要使用我存储在 Azure Key Vault 中的连接字符串和秘密。因为这些是秘密,我不想暴露它们,所以我需要在我的管道中使用 Azure Key Vault 任务。

为此,我可以使用 Azure Key Vault 任务来下载我需要的秘密。

作为这项任务的先决条件,我需要创建一个链接到我的 Azure 订阅的 Azure 资源管理器服务连接,并且我需要一个包含我的秘密的密钥库。

一旦我有了这个设置,我就可以在我的管道中使用下面的代码片段:

steps:
  - task: AzureKeyVault@1
    inputs:
      azureSubscription: '$(azureSubscription)'
      KeyVaultName: '<key-vault-name>'
      SecretsFilter: '*'
      RunAsPreJob: false

在这里,我们用我们的秘密定义包含我们的密钥库的订阅,并且我们在我们的密钥库中检索所有的秘密。我们可以过滤掉这些内容,使用逗号分隔的我们想要下载的秘密名称列表,但是现在我只是下载所有内容。

将我们的功能部署到 Azure ⚡

我们终于准备好部署我们的功能了!⚡

为此,我将使用一个 Azure 应用服务部署任务

我们可以使用这个任务来部署各种不同的应用服务类型,但是在我的 YAML 代码片段中,我将指定 functionApp 作为我们的类型。

作为这项任务先决条件,您需要一个应用服务实例来部署您的代码。

我还将传递我们之前构建的包作为我们的,使用 $functionAppName 变量作为我们函数的名称,然后为我们的应用程序设置传入键值。我可以传入我的函数需要的秘密,因为我们在密钥库任务中下载了它们。

- task: AzureRmWebAppDeployment@4
  displayName: 'Deploy Azure Function'
  inputs:
    azureSubscription: '$(azureSubscription)'
    appType: functionApp
    WebAppName: $(functionAppName)                   
    package: '$(Pipeline.Workspace)/drop/MyHealth.Fitbit.Body.zip'
    appSettings: '-FUNCTIONS_WORKER_RUNTIME "dotnet" -FUNCTIONS_EXTENSION_VERSION "~3" -KeyVaultName "<key-vault-name>" -AccessTokenName "<secret-name>" -ServiceBusConnectionString "$(<secret-value>)" -APPINSIGHTS_INSTRUMENTATIONKEY "<some-key>" -ExceptionQueue "myhealthexceptionqueue" -BodyTopic "myhealthbodytopic" -WEBSITE_TIME_ZONE "New Zealand Standard Time"'
    enableCustomDeployment: true
    RemoveAdditionalFilesFlag: true

我们完整的 YAML 档案

在我们结束之前,这里是我的完整的 YAML 建设管道:

trigger:
  - mainvariables:
  buildConfiguration: 'Release'
  vmImageName: 'vs2017-win2016'
  functionAppName: 'famyhealthfitbitbody'
  azureSubscription: '<azureSubscription-id-or-name>'
  workingDirectory: '$(System.DefaultWorkingDirectory)/MyHealth.Fitbit.Body'
  projectName: 'MyHealth.Fitbit.Body'stages:
  - stage: Build
    displayName: Build Stage jobs:
      - job: Build
        displayName: Build MyHealth.Fitbit.Body
        pool:
          vmImage: $(vmImageName) steps:
          - task: DotNetCoreCLI@2
            displayName: Restore
            inputs:
              command: 'restore'
              feedsToUse: 'select'
              vstsFeed: '<artifact-feed-id>'
              projects: '**/*.csproj' - task: DotNetCoreCLI@2
            displayName: Build
            inputs:
              command: 'build'
              projects: '**/*.csproj'
              arguments: --configuration $(buildConfiguration) - task: DotNetCoreCLI@2
            displayName: Run Unit Tests
            inputs:
              command: 'test'
              projects: '**/*UnitTests/*.csproj'
              arguments: '--configuration $(buildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$(Build.SourcesDirectory)/TestResults/Coverage/'
              publishTestResults: true - script: |
              dotnet tool install -g dotnet-reportgenerator-globaltool
              reportgenerator -reports:$(Build.SourcesDirectory)/TestResults/Coverage/coverage.cobertura.xml -targetdir:$(Build.SourcesDirectory)/CodeCoverage -reporttypes:HtmlInline_AzurePipelines;Cobertura
            displayName: Create Code coverage report - task: PublishCodeCoverageResults@1
            displayName: 'Publish Code Coverage'
            inputs:
              codeCoverageTool: Cobertura
              summaryFileLocation: '$(Build.SourcesDirectory)/**/coverage.cobertura.xml'
              reportDirectory: '$(Build.SourcesDirectory)/TestResults/Coverage/' - task: DotNetCoreCLI@2
            displayName: Publish
            inputs:
              command: 'publish'
              publishWebProjects: false
              projects: '**/*.csproj'
              arguments: '--configuration $(buildConfiguration) --output $(build.artifactstagingdirectory)'
              zipAfterPublish: True - task: PublishBuildArtifacts@1
            displayName: 'Publish Artifact'
            inputs:
              PathtoPublish: '$(build.artifactstagingdirectory)' - stage: Deploy
    displayName: 'Deploy MyHealth.Fitbit.Body'
    dependsOn: Build
    condition: succeeded() jobs:
      - deployment: Deploy
        displayName: Deploy MyHealth.Fitbit.Body
        environment: Production
        pool:
          vmImage: $(vmImageName) strategy:
          runOnce:
            deploy: steps:
                - task: AzureKeyVault@1
                  inputs:
                    azureSubscription: '$(azureSubscription)'
                    KeyVaultName: '<key-vault-name>'
                    SecretsFilter: '*'
                    RunAsPreJob: false - task: AzureRmWebAppDeployment@4
                  displayName: 'Deploy Azure Function'
                  inputs:
                    azureSubscription: '$(azureSubscription)'
                    appType: functionApp
                    WebAppName: $(functionAppName)                   
                    package: '$(Pipeline.Workspace)/drop/MyHealth.Fitbit.Body.zip'
                    appSettings: '-FUNCTIONS_WORKER_RUNTIME "dotnet" -FUNCTIONS_EXTENSION_VERSION "~3" -KeyVaultName "<key-vault-name>" -AccessTokenName "<secret-name>" -ServiceBusConnectionString "$(<secret-value>)" -APPINSIGHTS_INSTRUMENTATIONKEY "<some-key>" -ExceptionQueue "myhealthexceptionqueue" -BodyTopic "myhealthbodytopic" -WEBSITE_TIME_ZONE "New Zealand Standard Time"'
                    enableCustomDeployment: true
                    RemoveAdditionalFilesFlag: true

运行我们的构建管道🚀

我们已经在 YAML 成功地创建了一个构建管道,每次我们推进到我们的主分支时都会触发这个管道。我们可以在 Azure DevOps 中查看我们的构建状态,如下所示:

我们可以在 DevOps 中查看我们构建的摘要,如果需要,还可以运行特定的阶段。

正如您在图片底部看到的,我们可以看到管道中每个阶段的结果。如果一个特定的阶段失败了,我们可以用它来重新运行一个特定的阶段,而不是不得不将我们的代码再次推送到 main

包扎

多阶段构建管道非常适合在同一个文件中定义我们的构建和发布过程。通过使用源代码控制,我们可以跟踪构建过程随时间的变化。我们还可以做一些有用的事情,比如生成和发布代码覆盖率报告,从 key vault 下载秘密,以及在一个文件中部署应用程序!

希望这篇文章对你有用!一如既往,如果你有任何问题,欢迎在下面评论或在 Twitter 上问我!

编码快乐!💻👨‍💻👩‍💻

构建和评估您的贝叶斯统计模型

原文:https://towardsdatascience.com/building-and-evaluating-your-bayesian-statistical-model-3ab703fc4ea8?source=collection_archive---------21-----------------------

第 2 部分,共 5 部分:关于如何执行贝叶斯预测并评估其性能的实践编程练习。

即使对于非数据科学家来说,贝叶斯统计这个术语也很流行。你可能在大学期间学过必修课,但没有意识到贝叶斯统计有多重要。事实上,贝叶斯统计不仅仅是一种特定的方法甚至是一类方法;这是一种完全不同的统计分析范式。

作者图片

为什么是贝叶斯统计?

贝叶斯统计为您提供了更新您对新数据证据的信念的工具,这是一个在许多现实世界场景中常见的概念,例如用于跟踪流行病、预测经济趋势或预测气候变化。它们也是许多更著名的统计模型的支柱,如高斯过程。

[## 用简单的英语介绍高斯过程编程

towardsdatascience.com](/introduction-to-gaussian-process-programming-in-plain-english-8dd7a94cb18d)

更重要的是,学习贝叶斯统计的原则对于作为数据科学家的您来说是一笔宝贵的财富,因为它为您提供了一个全新的视角来解决现实世界数据的动态来源的新问题。

注意:这是的第二篇文章,是涵盖贝叶斯统计编程主题的 5 篇系列文章中的第二篇。

  1. 的第一篇帖子涵盖了贝叶斯统计的基本理论以及如何用 Python 实现一个简单的贝叶斯统计。

[## 贝叶斯统计程序设计:导论

towardsdatascience.com](/bayesian-statistical-programming-an-introduction-4ca3e2ddae76)

2.这个将向你介绍贝叶斯推理以及如何执行基本的模型评估。

3.第三部分将涵盖一种特殊类型的贝叶斯算法,称为蒙特卡罗马尔可夫链(MCMC)。

[## 马尔可夫链编程导论

towardsdatascience.com](/introduction-to-markov-chain-programming-8ddbe0ac1c84)

4.第四部分将基于之前的文章构建一个更复杂的贝叶斯模型。

5.第五部分将向您介绍贝叶斯模型检查和评估的高级概念。

目录:

  1. 概述
  2. 推理和预测
  3. 模型评估
  4. 敏感性分析

事不宜迟,让我们开始介绍贝叶斯统计编程帖子。

概述

在第一篇文章这里,我已经讨论了贝叶斯统计的基本原理,关键术语,以及如何使用 PyMC3 实现一个简单的模型。我们使用氡浓度(有毒气体)的例子来说明贝叶斯编程在现实世界中是如何工作的。

我们将从我们停止的地方让你跟上速度。所以,如果你想更详细地遵循这些步骤,请在继续下一步之前参考我的第一篇文章。

  1. 安装依赖项(建议使用 conda)
conda install -c conda-forge pymc3

2.下载我们的数据

!wget "https://raw.githubusercontent.com/fonnesbeck/mcmc_pydata_london_2019/master/data/radon.csv"

3.得到感兴趣的列( log_radon

import pandas as pdradon = pd.read_csv('./radon.csv', index_col=0)
anoka_radon = radon.query('county=="ANOKA"').log_radon

4.建立一个简单的贝叶斯模型

from pymc3 import Model, Normal, Uniformwith Model() as radon_model:
    μ = Normal(’μ’, mu=0, sd=10)
    σ = Uniform(’σ’, 0, 10)

5.编译和训练模型

with radon_model:
    dist = Normal('dist', mu=μ, sd=σ, observed=anoka_radon)

6.从训练好的贝叶斯模型中抽取一些随机样本

from pymc3 import sample

with radon_model:
    samples = sample(1000, tune=1000, cores=2, random_seed=12)

既然你已经赶上了这些步骤,让我们继续这篇文章的主题:贝叶斯推理和评估

推理和预测

鉴于我们训练有素的贝叶斯模型,我们可以尝试作出预测或推断。假设我们有兴趣找出美国任何家庭暴露于对数氡浓度高于 1.1(即 p(对数氡> 1.1))。

我们可以执行一个后验概率预测。还记得我们之前帖子里的这个人吗?

后验分布

但是,我们不是从我们的可观测数据 y 中估计一个参数θ(读作:theta),而是推断对数氡浓度( z ) 如下

后验预测分布

而类似于贝叶斯公式,我们可以通过下面的公式求出给定所有观测值的 zy、的概率。

后验预测分布公式

对于所有可能的θ值,后验预测公式将对给定θ 参数的 z 的概率乘以给定所有观测值的所有θ的概率 y 进行求和

使用 PyMC3,我们首先对后验分布进行 1000 次采样,以获得 1000 个 z (log-radon)值。

from pymc3 import sample_posterior_predictive

with radon_model:
    pp_samples = sample_posterior_predictive(samples, 1000)

然后,我们可以找到平均值来检索概率。

radon_thres = 1.1(pp_samples['dist'] > radon_thres).mean()
>>> 0.39105769230769233

阿诺卡的美国家庭氡对数浓度高于 1.1 的概率约为 39.11%。

模型评估

但是我们如何知道我们的贝叶斯模型是否有任何好处呢?

一种基本的评估方法是将我们的预测与可观测的数据进行比较。您可以从大量的统计检验中进行选择,如 t 检验或 f 检验,来比较两个“群体”之间的相似性。

对于我们目前的用例,让我们使用一个图形可视化来比较我们的预测与经验值之间的差异。

首先,让我们找到一组超过我们的对数氡浓度阈值 1.1 的样本:

import seaborn as sns
import matplotlib.pyplot as pltp_thresh = [(sample>1.1).mean() for sample in pp_samples['dist']]

然后我们用经验值绘制这些样本的分布。

ax = sns.distplot(p_thresh)
plt.vlines((anoka_radon>1.1).mean(), *ax.set_ylim(), color='g')

预测值与经验值的分布(图片由作者提供)

绿色垂直线说明了 ANOKA 一户家庭的对数氡暴露浓度高于 1.1 的平均经验概率,而直方图代表了来自训练贝叶斯模型的采样分布。

该图表明,我们最初的假设并不坏,但仍有改进的余地,以使分布收敛到真实的经验值。可以通过以下方式进行进一步微调:

  1. 改变我们对参数分布的假设,
  2. 为我们的贝叶斯模型尝试不同的初始值

先验灵敏度

在建立模型时,检查我们先前选择的先验的敏感性也很重要。

这可以通过构建相同的模型,但如下改变先验分布来实现。

from pymc3 import Flat, HalfCauchy, plot_posterior

with Model() as sensitivity_check:

    μ = Flat('μ')
    σ = HalfCauchy('σ', 5)

    dist = Normal('dist', mu=μ, sd=σ, observed=anoka_radon)

    sensitivity_samples = sample(1000, cores=2)

然后绘制分布图。

# Sensitivity evaluation distribution
plot_posterior(sensitivity_samples, var_names=['μ'], ref_val=1.1)

通过改变我们的初始先验的后验分布

并将它与原件进行比较。

# Original distribution
plot_posterior(samples, var_names=['μ'], ref_val=1.1)

初始后验分布(图片由作者提供)

比较这两个图,我们的先验似乎对变异不敏感(即相当稳健),强调我们离实现目标又近了一步!剩下唯一要做的就是通过不断试验不同的先验或初始值来进一步调整我们的模型。

离别的思绪

我们已经讨论了如何进行推理和评估我们的贝叶斯模型。在下一篇文章中,我将介绍管理贝叶斯统计编程的底层过程,比如帮助我们执行采样的蒙特卡罗马尔可夫链(MCMC)算法。敬请期待!

做订阅我的邮件简讯:【https://tinyurl.com/2npw2fnz】在这里我定期用通俗易懂的语言和漂亮的可视化总结 AI 研究论文。

在 Jupyter 笔记本中构建和导出 Python 日志

原文:https://towardsdatascience.com/building-and-exporting-python-logs-in-jupyter-notebooks-87b6d7a86c4?source=collection_archive---------5-----------------------

捕获和导出日志文件的操作指南

Radek Grzybowski 在 Unsplash 上的照片

日志记录是 Python 中监控代码健康状况的一项重要功能。在某种程度上,日志文件与调试器有很多相同的概念。我们可以使用日志在代码中放置面包屑,以帮助确定内部发生了什么。这在我们的脚本由于未知原因崩溃时特别有用——如果我们留下足够多的面包屑,我们可以跟踪代码所走的路径,并且我们可以将注意力集中在那里。通常,当我们第一次测试代码时,python 调试器是有用的,但是在某些时候,在我们测试了所有可能的输入情况之前,我们认为我们的代码是“工作的”。如果我们在后台使用日志记录,如果路上有什么东西坏了,我们会很清楚哪里出了问题。特别是,如果我们正确使用日志记录,我们可以看到破坏我们“工作”代码的确切的独特情况。

当其他人使用我们的代码时,日志变得更加重要。当一个脚本在另一个用户的机器上失败时,复制错误可能是一个挑战,但是日志可以引导我们沿着脚本在用户的系统上失败之前所遵循的路径前进。这在创建管理所有“边缘”情况的代码时特别有用(你认为为什么软件在安装时总是请求允许发送崩溃数据?!)

最后,日志还有另一个很棒的用途——作为代码开发周期的跟踪器。想象一下,在向其他用户发布的第一周内,您的 python 脚本生成了 200 个错误、500 个警告和各种其他日志标记。随着代码的细化和通过迭代变得更加健壮,我们可以看到不同问题的发生率随着时间的推移而降低。这让我们知道我们在开发周期中的位置,以及通过首先处理最常见的错误来集中我们未来的努力。让我们开始吧:

Python 日志记录基础

从命令行运行脚本时登录 Python 已经有了很好的记录,但是在深入研究我们可以使用的技巧和工具之前,我们需要从基础开始。首先,当我们向日志记录器发送消息时,我们选择信息属于哪个类别。这些问题按照严重性从“未设置”到“严重”的递增顺序进行组织,如下所示。这个层次结构的强大之处在于,当我们输出日志数据时,我们可以选择报告哪个级别。在这种情况下,记录器将捕获该级别及更高级别的所有内容。例如,如果我们选择一个警告级别,那么记录器将捕获所有警告、错误和关键消息。关于何时使用每个级别的标准的完整文档可在这里找到。

作者照片—记录级别

要在 Python 中构建这一点,并将日志记录消息发送到控制台,看起来像这样:

import logging#create a logger
logger = logging.getLogger()# to control the reporting level
logger.setLevel(logging.WARNING)#send two messages to the logger
logging.info("This is an INFO message")
logging.warning("This is a WARNING message")

由于级别设置为logging.WARNING,我们将看不到info级别的消息。设置级别很有用,因为在第一次编码时,我们会在DEBUGINFO中发送面包屑,以确保我们做得正确。然后,当我们认为不再需要面包屑时,我们可以将它们从日志中删除,并专注于警告、错误和关键的功能问题。这可以与调试器协同工作。

为了输出到一个实际的日志文件而不是命令行,我们需要使用basicConfig()来设置日志记录器,在这里我们也可以设置级别,就像这样:

import logging
logging.basicConfig(filename='my_first_log.log', level=logging.INFO)

遗憾的是,这种方法在 Jupyter 笔记本上操作时行不通。一点都不。问题在于,在启动时,Jupyter 笔记本启动一个已经启动日志记录的 IPython 会话。结果,logging.basicConfig()就不行了。

在 Jupyter 笔记本中登录

日志在 Jupyter 笔记本中也特别有用,因为调试器可能会有一些严重的功能问题。通过使用 JupyterLab 中的增强调试器可以避免这些调试器问题,但是如果您受限于 Jupyter 笔记本,那么日志记录可以为您提供处理更广泛的调试任务所需的灵活性。

将日志保存到文件

要将日志消息导出到 Jupyter 中的外部日志文件,我们需要设置一个 FileHandler 并将其附加到日志记录器:

import logging
logger = logging.getLogger()
fhandler = logging.FileHandler(filename='test_log.log', mode='a')
logger.addHandler(fhandler)
logging.warning('This is a warning message')

请务必注意 FileHandler 设置中的模式选择:

  • ‘a’—追加。所有新消息都被附加在日志文件的末尾
  • w' —写。每次运行 python 脚本时,日志文件都会被清除并重新开始

如果一切顺利,我们应该在 Jupyter 笔记本的同一目录下有一个新的“test_log.log”文件。

格式化输出

我们还可以改进和定制我们的日志输出,以包含比我们在日志消息中指定的文本更多的内容。通过使用logging.Formatter(),我们可以添加许多字段来帮助我们理解更多关于消息的信息,比如消息是什么时候生成的,是由代码中的哪一行生成的。以下是我最喜欢的一些,完整的列表在这里:

  • %(asctime)s —条目的日期/时间
  • %(levelname)s —日志记录级别(因此您不必在错误中详细说明)
  • %(name)s —所用记录器的名称(如生成此消息的文件)
  • %(lineno)s —生成消息的行号
  • %(message)s —当然!消息本身!

为了将我们的格式附加到记录器,我们将它添加到文件处理程序,如下所示:

formatter = logging.Formatter('%(asctime)s - %(name)s - %(lineno)s - %(levelname)s - %(message)s')
fhandler.setFormatter(formatter)

将格式化输出导出到控制台

我们还可以添加另一个处理程序来在控制台中显示这种格式。这里,我们使用sys.stdout通过StreamHandler()访问控制台,并将其连接到记录器:

import sys
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(formatter)
logger.addHandler(consoleHandler)

更棒的是。我们也可以独立调节每个处理器输出的电平。例如,我们可以将我们的控制台设置为向下报告调试级别,如下所示:consoleHandler.setLevel(logging.DEBUG)

重要提示 —主记录器级别 必须等于或低于赋予处理者的 级别,否则不起作用,因为高级记录器级别设置了发言权。

可变值

我们还可以向我们的日志记录器传递静态消息之外的信息。通常,如果我们的代码返回警告或错误,我们会想知道是什么用户值触发了事件。幸运的是,我们可以使用.format()简单地将变量值解析成我们的消息,就像普通字符串一样。

var1 = 1
var2 = 'cat'
logging.debug('var1: {}; var2: {}'.format(var1, var2))

把所有的放在一起

根据目前所学,我们可以在 Jupyter 笔记本中启动一个新的记录器,调整报告级别,调整格式,输出到文件,输出到控制台,并调整每个输出的级别。下面是它实际运行时的简单快照,控制台位于 DEBUG,导出文件位于 INFO:

登录 Jupyter 笔记本

下面是我们在 file_out.log 文件中看到的内容:

输出日志文件,仅显示信息及以上内容

虽然能够将日志导出到文件中很好,但有时我们想变得懒惰一点,不要切换到文本编辑器来读取我们的输出文件。要在 Jupyter 笔记本中查看日志文件,我们可以像这样读取并打印内容:

with open("file_out.log") as log:
    print(log.read())

提示和技巧:

因为当我们启动一个笔记本时,logger 是作为 IPython 的一部分自动设置的,所以某些配置与在控制台中运行的 Python 文件的某些功能相冲突。其中一个特别之处是使用了getLogger(__name__)功能。当我们的 python 脚本变得更加复杂时,我们通常会将一些函数分解成单独的脚本文件,这些文件稍后会作为单独的模块导入。我们可以将所有日志消息传递到一个公共日志文件,由%(name)s格式化程序告诉我们是哪个 python 脚本生成了消息。甚至有一个关于如何从控制台运行 python 来做这件事的教程。不幸的是,Jupyter 笔记本不能立即兼容这一功能。我还没有找到解决方案…但是现在我知道使用__name__将会阻止任何东西被打印到日志文件或者格式化的控制台处理程序中。

随着您对 python 日志的深入研究,您会发现我们甚至可以通过电子邮件导出日志文件。这是非常有利的——在我们的代码部署后,我们可以从远处监控它的健康状况。更好的是,添加SMTPHandler只需要几行代码。示例代码可以在这里找到。

此外,由于能够为每个处理程序设置级别,我们可以同时创建多个日志输出来报告不同的级别。例如,我们可能需要一个日志文件来捕获调试级别的每个事件,但是我们也可能需要一个经过过滤的日志文件来只报告警告及以上级别的事件——这为我们提供了一个简单的文件来监视主要问题,以及一个单独的日志文件来记录所有事件,以备我们深入研究时使用。

结论

日志为维护代码的质量和功能提供了一个很好的方法,尤其是当我们发布 python 脚本供他人使用时。当我们的代码意外运行时,它可以帮助标记,并留下痕迹来显示事情是如何以及为什么发生的。在开发过程中,预测我们的脚本将要接收的 每个 用例以及 每个 用户输入是非常具有挑战性的——日志记录为我们提供了一种不断迭代和提高代码健壮性的方法。

在 Jupyter 笔记本中实现日志时有一些不同,但是一旦你理解了修改,你就可以成功地生成真正有用的日志。感谢您的阅读,和往常一样,上面显示的所有代码都可以在我的 Github 这里访问。

使用 Python 构建和共享大规模报表

原文:https://towardsdatascience.com/building-and-sharing-reports-at-scale-with-python-49dfdf9fa133?source=collection_archive---------28-----------------------

📸—作者图片

我们如何构建我们的内部报告系统来大规模共享报告

报告对于任何足够大的数据驱动型公司的运营都至关重要,HousingAnywhere 也不例外。我们所有部门每天都在运行各种各样的报告,其中大多数都是使用模式分析运行的。虽然 Mode 是满足我们大部分报告需求的强大工具,但它(像许多 SaaS 产品一样)有我们内部无法克服的局限性。为了适应我们的快速增长,我们发现,如果我们想提高报告水平,我们需要一个更加灵活的额外工具。

问题

在 HousingAnywhere 进行报告的一个最重要的方面是共享单个城市级别的报告。作为一个专注于 3-12 个月住宿的住宿租赁平台,我们在欧洲多个城市提供服务,负责每个城市的团队需要能够了解该城市的具体情况。因此,我们有大量连续运行多次的报告,但每次都是针对不同的城市。在小范围内,这很好,但是每次都从头开始构建报告不是一个可扩展的解决方案。2021 年,我们的重点城市数量从 15 个增加到 32 个,增加了一倍多(T7),这意味着我们现在有 32 个城市需要构建这些报告(我们的目标是在未来几年增加这个数字)。因此,我们的旧系统被证明效率太低,成本太高。

在旧系统中,每次我们想要构建报告时,都必须运行所有 n 个查询。图片作者。

在一个例子中,我们发现我们在雪花(我们的数据仓库)上为一份报告每月支付超过 50€;当我们在 2021 年初增加新的重点城市时,这一成本会进一步增加。仅一份报告每年在数据仓库上就要花费数百欧元?像这样的管理费用是不可能快速增长的。构建我们自己的系统也将使我们在需要安装和管理的任何包或集成上有充分的灵活性。

我们遇到的另一个问题涉及到对外共享我们的报告(例如,对我们的股东)。我们需要能够轻松地与组织外部的各方共享报告,如果报告系统不能处理这样的任务,这可能会很棘手。

解决方案

我们想要一个可以“缓存”数据的系统,这意味着我们可以运行一次查询,然后使用结果数据创建任意多的报告。这将允许我们建立大量的报告,但成本大大降低。我们只运行一次,而不是每个查询运行 32 次以上;将雪花的负荷减少到原来的一小部分。每当我们想要构建一个报告时,就会加载这些缓存数据,并可以根据一组给定的参数对其进行过滤。

新系统:所有查询只运行一次,然后在运行时过滤。数据仓库的负载显著降低。图片作者。

最终完成的报告可以以 PDF 格式共享到电子邮件地址、Slack 频道、Google Drive 文件夹或其他任何使用 Python 实现的地方。它还必须易于与我们当前的技术体系集成,因此将其实现为 API 是最有意义的:一个端点触发对报告的查询,一个端点触发报告本身的运行。这将使自动化调度过程变得容易,同时也使构建能够管理系统的 web UI 变得简单。它灵活高效,让我们在构建报告时有更多选择。

我们创建一个报告只需要几个文件:

  • 一组查询。收集数据的 sql 文件
  • 包含描述如何过滤数据的函数的 Python 文件
  • 一个 Python 文件,包含用于绘制过滤数据的函数
  • 存储报表布局的文本文件

必须指出的是,与使用 Mode 或 Tableau 等传统工具构建报告相比,这一过程的用户友好性较差。这增加了创建报告所需的时间,使得将该系统视为此类工具的替代品变得不合理。我们的目标是将它们串联使用,使用我们的内部系统来处理需要额外 TLC 的报告。

实施

新系统概述。作者图片

该系统本身由打包在 Docker 容器中的 Flask API 组成,该容器部署在 Google Kubernetes 引擎上。我们的大部分技术已经部署在 GCP,所以这是最简单的快速部署方法。

如果进行 API 调用来运行特定报告的查询,则每个。使用雪花连接器收集并运行与报告对应的 sql 文件。结果在本地保存为。csv 文件,可以在构建报告时引用。

示例代码展示了如何使用 Python 连接器查询雪花,并将每个结果保存为 CSV 格式

为了共享报告,API 调用包括报告的参数和目的地,例如“将柏林日报发送到# team-BerlinSlack channel”。然后,系统使用这些参数构建报告,并将其发送给接收人。要构建报告本身,这个过程并不复杂。

数据过滤非常简单,由加载。csv 文件,并使用 Pandas 过滤它们。输入参数采用字典的形式,允许使用任意多的过滤器。过滤后的数据被保存到将用于图表的数据帧字典中

一个基本过滤函数的示例,根据 API 调用中给定的参数过滤数据。对这些函数中的每一个进行迭代,并在图表中使用生成的数据框

这些图形遵循类似的格式:一系列 Python 函数接受前面提到的字典,创建图形并将这些图形保存为。svg 图像。这为我们选择图形库(如 Plotly、Matplotlib、Altair)提供了很大的灵活性,因为我们可以使用任何允许我们将图形保存到图像的库。

一个基本图形函数的例子。graph_data 是使用过滤函数中的数据填充的。然后可以在 HTML 模板中链接这些图像

一旦这些图像被保存,它们可以在一个 HTML 文件中被链接。为了给每个图片添加特定的链接,我们使用 Jinja 用图片填充一个基本的 HTML 模板。为了获得正确的顺序,我们使用一个简单的“layout.txt”文件来记录报告的布局。在这里,我们可以添加图形名称、标题、分页符等。

一页报表的 layout.txt 示例。显示一个标题、三个图表和一个分页符

在本例中,我们有三个图形图像 bookings_kpis.svgbookings_bar.svgbookings_forecast.svg ,它们与部分标题一起添加,后面是分页符。这些被提取并解析,以允许 Jinja 注入相应的 HTML。格式文件的每一行描述了最终 HTML 报告中的一个元素。HTML 文件完成后,使用 PDFKit 将其转换为 PDF。

HTML 模板的简化版本

使用 Jinja 填充 HTML 模板的示例代码

从那里,我们可以发送 PDF 到 Slack,电子邮件,谷歌驱动器或任何必要的地方。这意味着我们还能够为外部电子邮件添加一个白名单,让我们有机会在住宅之外的任何地方指定电子邮件地址,以便与他们共享报告。

我们使用一个非常基本的定制气流操作器来安排我们的报告。我们在气流方面的工作已经在以前的文章中提到过,在那里我们详细介绍了我们使用 Selenium 的网络抓取或我们的 CI/CD 设置,这是一个我们经常使用的工具,因此简单的集成就可以将我们的报告系统和气流连接起来,这非常有帮助。它使我们能够以一种简洁的方式轻松安排和共享报告,而不必偏离我们当前的技术堆栈。

该项目的目标是授予数据团队扩展能力,同时继续为每个城市提供所需的支持。在 API 发布之前,我们努力在不花费大量成本的情况下,高效地构建 15 个重点城市的报告。自从我们部署了这个系统,我们就能够以很低的成本定期分享高质量的报告。我们可以继续为每个城市提供这样的报告,不管未来几年我们支持多少个城市。

感谢 Julian SmidekDuc Anh Bui 在整个项目和本文中给予的支持和建议。

在时间和空间中模拟生物系统

原文:https://towardsdatascience.com/building-bespoke-stochastic-process-models-using-rcpp-49dae153c34a?source=collection_archive---------15-----------------------

思想和理论

使用 Rcpp 在 R 中构建高级模型

科学文献包含了一个巨大的“动物园”,里面有用于分析复杂生物系统的优雅的数学模型。用 R 或 Python 实现它们会带来一些有趣的,甚至是意想不到的数值挑战。

图一。使用 Rcpp 估计的空间(1-D)逻辑增长模型。最初的申请是由于 r . a . Fisher(1937 年)提出的有利等位基因在景观中的空间分布(详见正文)。图片作者。

1.马尔萨斯增长模型(1798)和朋友们

复杂生物系统的建模有着悠久的历史。1798 年提出了一个指数人口增长模型(马尔萨斯增长),许多历史上著名的科学家将他们自己的模型添加到文献中,这当然延续到今天。这些模型涵盖了一切,从遗传和基因进化——费希尔和他在 1937 年提出的优势等位基因波的模型——到传染病传播的模型(不胜枚举,参见新冠肺炎文献),直到只有最新技术进步才有可能做出的贡献,例如,基因组测序技术使得人类微生物种群的捕食者-猎物模型的开发成为可能。

这些模型中的许多在数学上是优雅的,并且形成高度复杂过程的简明描述,并且通常集中于少数关键参数或特征。令人印象深刻的是,“经典”模型(可能稍加修改)如今仍在实际应用中使用。这表明这种模型继续捕捉着我们周围复杂生物系统的本质——至少是我们目前所理解的。例如,即使像逻辑增长这样看似简单的模型,可以追溯到大约 1838 年(由 Verhulst 发现),也经常出现在最近(2020)同行评审的关于新冠肺炎传播的科学期刊文章中。

在我们进入这篇文章的真正内容之前,先快速地回顾一下副标题中“高级模型构建”的用法。以下示例中使用的模型需要一些定制的数值实现,这可以说是初学者的话题。也就是说,没有任何编码或数学是先进的,所有运行模型和生成图的代码都是独立的,可以在 GitHub 这里获得

2.模型、软件、数据拟合

我们在这里考虑的两个模型通常被称为数学模型(相对于回归/统计模型),但我们的最终目的是统计—数据科学—从真实数据中进行参数估计和预测。一个有用的类比是 PK/PD 建模,其中系统部分——随着时间的推移生物系统的期望值——使用数学模型定义,该模型嵌套在统计模型中,给出非线性混合效应模型公式。同样的概念也适用于此,但我们不仅仅考虑时间。

我们研究的两个模型描述了一个生物系统的进化跨越 两个连续的维度——在这里的例子中,时间空间,以及时间概率。这些模型定义如下,是科学文献中的经典模型。每个模型都用偏微分方程(PDE)来表示。使用偏微分方程是因为这些模型描述了一个动态系统在两个连续维度上的演化。偏微分方程被广泛用于此目的,另一个主要的生物学应用是跨时间年龄的建模。后者对于任何以年龄为驱动因素的过程都特别重要,例如传染病建模痴呆症发病人口统计学建模或者实际上任何生物生长过程。

图二。用 Rcpp 估计随机逻辑增长模型。表面是随机增长过程从初始点源随时间演变的概率密度。图片作者。

2.1 型号

模型 1 —空间逻辑增长

第一个模型——图 1——是扩展到一个空间维度的经典逻辑增长的扩展,通常被称为“费雪方程”,定义为:

第一个方程定义了过程在空间和时间上的演化,下面三个方程定义了解方程所需的必要边界和初始条件。n0(x)是系统在时间 0 时的初始初始值。图片作者。

这个模型定义了某种生物体或种群在空间和时间上的生长(或扩散),其中 n(x,t) 是生物体在位置 x 和时间 t 的密度,这里的空间是一维的,所以扩散是沿着单轴进行的。在图 1 中,初始源在位置 x=40,传播轴被限制在从 x=0 到 x=100,t=0 到 150 个时间单位。

按照经典的逻辑增长,该模型是非线性的并且依赖于密度,其中增长速度取决于种群大小,并且具有三个参数,r =增长率,K =种群的承载能力,D =扩散系数。K 决定了 n(x,t) 的最大高度,在图 1 中这是 K=50,D 决定了空间展宽有多宽,图 1 中 D=1,r=0.2。

模型 2——随机逻辑增长

第二个模型——图 2——也是经典逻辑增长的扩展,但它不是扩展为在空间维度上进化,而是扩展为随时间随机进化。该模型在数学上更复杂,定义如下:

第一个方程定义了模型——参见逻辑增长——然后是布朗运动扩散项(dW)来增加随机性。第二个方程是从第一个方程推导出来的 Fokker-Planck 方程,第三和第四个方程是初始和边界条件,L_l 和 L_u,n 的下限和上限,初始条件——最后一个方程——是 Dirac delta 函数,这个特别有问题(见正文)。图片作者。

古典逻辑增长的随机版本有许多不同的可能变量(见这里的讨论),这是一个更简单的模型。第二个方程是从第一个方程中推导出来的(很容易,只是在术语上有所下降——见这里的),描述了 f(n,t)=人口规模随时间的概率分布。这是我们希望解决的方程。这个模型的边界条件也更复杂。

为了帮助澄清模型 1 和模型 2 在目的和解释上的差异:

  • 模型 1 回答了这样的问题:"在从初始源进化 10 个时间单位之后,在空间位置 x=10 和 x=20 之间的种群中存在多少生物体?
  • 模型 2 回答了这个问题:“从一个初始源进化 100 个时间单位后,群体规模大于 80 的概率是多少?”

2.2 软件 Rcpp 的数值工作

为了首先给出统计/经验背景,对于给定的参数选择和初始条件,模型 1 的解可以被用作跨空间和时间的非线性回归模型(例如,具有高斯误差)中的平均轨迹。对于任何给定的参数集,PDE 的解只是 x 和 t 的非线性函数。复杂的是,由于我们无法解析地求解该 PDE,我们无法以封闭形式写出该(解)函数,因此需要对每组参数选择进行数值计算。例如,在拟合算法(例如非线性最小二乘法)中,该算法需要在每次搜索更好的拟合参数估计时调用求解 PDE 的函数。

模型 2 已经是具有似然函数的随机模型,并且可以(在理论上)在给定合适的优化程序(例如,最大似然估计)的情况下直接适合可用数据。一种替代方法是将 PDE 的解(概率分布)提供给马尔可夫链蒙特卡罗(MCMC)采样引擎(例如, r-nimble )进行贝叶斯分析。但是概念与模型 1 相同;在拟合数据过程(最大似然法或贝叶斯法)的每一步,对于任何给定的一组参数和初始条件,都需要相关 PDE 的解。

Rcpp

图片作者。

有很多数值求解偏微分方程的方法,可以说最容易实现的是线 (MOL)的 方法,这是我们在这里使用的,这是使用 Rcpp 实现的。MOL 方法通过对空间导数(在我们的例子中分别是“x”和“n”维)使用有限差分近似将 PDE 离散成一个常微分方程系统。关键的编程任务是准备粗糙的 2-d 向量,其将包含系数的适当重复模式。这对于设置来说不是特别费力,但是它有助于首先在纸上写出长的笔迹。二维向量中“行”的数量取决于所需的网格大小(这是 MOL 中决定精度的参数)。

需要特别注意的一个方面是边界条件的编码。边界条件是有限差分方案中的第一个和最后一个条目,需要根据模型中的边界条件类型进行调整。关于如何创建有限差分方案,尤其是如何计算复杂边界条件所需的项,这里有很好的指导。

MOL 中需要的最后一个部分是 ODE 解算器,理想情况下是具有自适应误差控制/步长大小的快速解算器。在这些示例中,使用了来自 Boost 库odeint 解算器,对 odeint 文档中的现有示例进行了最小的修改。

Rcpp 库用于实现 MOL 解算器,这是一个很好的选择,因为已经有一个用于 Rcpp 的 boost 包,名为 BH ,并且有限差分方案的实际编码很简单,即使只有很少的 C++知识。出于性能原因,使用编译语言在这里是很重要的,如果这些模型要拟合数据,那么 MOL 求解器可能需要调用很多次。

2.3 代码片段

模型和情节的完整代码可在 GitHub 的这里获得。为了给出所需编码的味道,下面是两个要点。第一个示例说明了实现有限差分方案的一种方式,这实际上涉及将一组重复的系数滚动到向量中。这些向量随后在定义要求解的常微分方程时使用。这是第二个要点。

下面的要点从数字上定义了模型 2——对应于模型 2 的偏微分方程的常微分方程系统。注意向量vec_2d_vec_2dh_是与上述要点类似地创建的向量,并且定义了有限差分方案的系数。特别值得注意的是上边界条件——代码的最后一行——它是手工编码的,以满足模型定义的数学要求。

2.4 建模和数值挑战

下面是另外两个图,分别来自模型 1 和模型 2,显示了每个模型的数值解是如何随时间和空间/概率变化的。这些解决方案看起来很流畅,直观上也很合理——而且确实已经过 Mathematica 的 PDE 求解器的检验。然而,早期的尝试并不成功,要获得这些正确的解决方案还需要一些工作。

图 3。模型 1——Fisher 方程——如图 1 所示,但现在只有 t=50 个时间单位,r=0.1,显示了跨距离轴的人口增长的早期阶段。图片作者。

有限差分格式被广泛使用,并且被认为是可靠和精确的(假设使用了足够细的网格)。这也是这里的经历,但是有三个意想不到的领域——尽管事后看来也许应该说是预料之中的——困难领域:1 .初始条件;2.边界条件;第三。理解模型的实际属性。

图 4。模型 2——随机逻辑增长模型——如图 2。但是从时间 t=0 向前看的观点不同。图片作者。

1.输入条件

  • PDEs 描述平滑函数,因此初始条件(t=0 时)必须在第二维上是平滑的,即在时间 t=0 时在空间轴上是平滑函数。这意味着从 t=0 的点源进化严格来说是不可能的。相反,应该使用窄的平滑函数,例如方差非常小的高斯密度。这里的实际挑战是选择这个密度/函数。如果它太窄,那么有限差分方案将不会给出可靠的结果,而如果它太宽,那么被模拟的场景就不是从一个点源进化而来。这在模型 2 中尤其成问题,因为当将这些模型拟合到数据时,它们是从已知的初始观察值发展而来的——因此将狄拉克δ函数作为初始条件。

2.边界条件

  • 数值误差会从边界条件开始传播,导致整个有限差分格式的结果不可靠。这不会影响简单的边界条件(如模型 1),但肯定会影响边界条件,如模型 2 中的上边界。例如,在模型 2 中,上边界条件是正确的,但是有限差分方案给出了无意义的结果。这是通过代数简化边界条件解决的——表达式的正确性没有改变。这是一个微妙的问题,因为原始表达式在数值上看起来没有问题,但似乎破坏了有限差分格式的稳定性。

3.模型属性

  • 在图 2 中,使用的参数是α= 0.1,β= 100,因此从长期来看,我们预计 n 的平均值约为 100。当初始点源是以 n(0)=10 为中心的窄高斯分布时,情况确实如此。然而,如果这个相同的高斯分布被移动到以 n(0)=4 为中心,那么对于这些相同的参数选择,有限差分方案的结果变得无意义。把它从原点移开一点,一切又恢复正常。当使用 Mathematica 的 PDE 求解器时,也会出现同样的情况。通过一些调查,这在阅读相关文献时并不令人惊讶。这个模型在零以下有界——n(t)的值不能小于零,这意味着下边界条件是 f(n=0,t) = 0,即在 n=0 时没有概率可以累加。因此,在实践中,这种模型不适用于模拟小群体或处于生长/扩散早期阶段的群体/有机体,因为在这些情况下,灭绝(或 n 接近零)可能是现实的可能性。对于给定的一组参数和初始条件,提前确定这种情况何时可能发生是实际的挑战。

3.数据拟合和结束语

最终目标是能够在附加的统计模型(非线性混合模型等)内将这些模型拟合到真实数据集。就形状和灵活性而言,PDE 模型显然非常丰富,我们只研究了科学文献中跨空间和时间以及空间和概率的众多模型中的两个。使用偏微分方程时,确实存在一些数值上的挑战。

最大的障碍之一是如何鲁棒地自动化求解偏微分方程的过程,以便它可以嵌入到数据拟合算法中,如最大似然或 MCMC。我们只为几组参数值和初始条件求解了模型 1 和模型 2 的偏微分方程,这需要一些反复试验和一些人工决策。挑战在于如何设计一种算法来做到这一点——在面对不可靠的结果时做出明智的选择,以及如何首先确定产生的结果是不可靠的。

从积极的一面来看,模型 1 在接下来的步骤方面看起来相对容易处理,这可能与其他 PDE 类似,例如那些具有时间和年龄维度的 PDE。更复杂的模型——特别是那些描述时间和概率的模型——过程的概率演化,如模型 2,确实显得更加困难。

建筑偏执狂

原文:https://towardsdatascience.com/building-bigots-81da1021f8eb?source=collection_archive---------24-----------------------

为什么人工智能需要社会心理学,以及它可能是什么样子

图片由皮克斯拜的 Gerd Altmann 提供

见过微软的朋友 Tay 吗?为了你好,我希望不会。

2016 年,微软在 Twitter 平台发布了一款名为 Tay 的聊天机器人。Tay 代表“思考你”,旨在代表一名 19 岁的美国女孩,她将通过 Twitter 帖子与人类互动,学习如何与人类互动。

结果呢?一些用户教机器人使用种族主义和性指控的推文与其他人互动。换句话说,泰学会了成为一个偏执狂。

Tay 并不孤单。Tay 是一类被称为生成模型的模型的一部分,这些模型从学习到的输入中生成新的输出。基于各种现有互联网数据训练的生成模型显示,它们也学习偏见。事实上,最近由 OpenAI 发布的大型语言模型 GPT-3 也被发现说了一些关于穆斯林的非常负面的事情。

使用互联网的生成模型并不是唯一有偏见的。事实上,越来越多的例子证明机器学习模型的输出是有偏差的。@Terence Shin 在这里讲述了几个例子,展示了人工智能在医疗保健、犯罪和招聘实践中的偏见。

但是理解偏见如何渗入我们的数据科学实践只是硬币的一面。除此之外,AI 本身还能进一步偏向我们。事实上,我们看到信息攻击,人工智能利用人们自己的确认偏见来进一步传播阴谋论和错误信息。

这些机器学习成为偏执狂或进一步煽动我们内心的偏执狂的例子,如果它们只影响少数人,就不会有什么大不了的。但事实并非如此。吴恩达曾经指出人工智能是新的电力,我们目前正在见证它的无处不在。

这一切意味着,人工智能正在以越来越成问题的方式扩大我们人类的偏见。正是因为这些原因,我们需要激励新一代的数据科学家来解决这些偏见,并寻找克服它们的方法。

幸运的是,人们有偏见的想法并不新鲜。事实上,有一个完整的学术学科致力于人类偏见的研究,心理学。由 WomeninAI 撰写的一篇论文以支持心理学在理解人工智能潜在影响的全部广度中的作用开始了这场对话。

我想更进一步,更具体地说,社会心理学家花了几十年的时间来研究和理解人类偏见。有大量的理论帮助我们解释偏见是如何产生的,什么因素加剧了偏见,以及当偏见被应用时会有什么后果。

它不仅仅停留在理解人类的偏见上。

为此,我提出了人工智能的社会心理学,并探索潜在的主题,以弥合社会心理学理论与人工智能应用的现实。是时候打破偏执狂的建筑,建立比我们当前的轨迹更强大、更道德的机器。

为什么数据科学和人工智能需要社会心理学?

当大多数人想到社会心理学时,他们想到的是一个研究人们在社会情境中影响我们的方式的领域。但是社会心理学有一个更广泛的定义:

社会心理学是理解和解释个人的思想、感觉和行为如何受到他人的实际、想象或暗示的影响的科学尝试(奥尔波特,1954)

注意这个定义是如何包括他人想象的和隐含的存在的。有了这个定义,首先就很难考虑我们的心理学为什么不是天生的社会性。即使当我们发现自己孤独的时候,我们仍然会受到他人的影响。

但 AI 并不是我们经常说的字面意义上的“他者”。它没有生命,没有呼吸,没有感觉。那么,我们为什么要假设在处理人工智能时也适用类似的原则呢?

人们不仅会在他们不在的时候影响我们,“他们”也不需要成为人。更确切地说,我们有一种强烈的倾向,认为无生命的事物具有能动性。你们中有多少人因为加载应用程序花费太长时间而对着电脑大喊大叫?或者你用性别代词来描述你的车?将社会特征归因于无生命的物体是如此普遍,许多心理学家认为这是自然的

这种趋势也有一个很好的解释。从进化的角度来看,对我们来说,假设灌木丛中的沙沙声是因为熊或其他具有威胁性的生物的存在,比假设这是风要安全得多。后者确保了我们的生存。

因为人工智能技术背后的整个要点是将类似人类的智能构建到应用程序和物理对象中,这些相同的技术甚至更有可能在做一些事情,让我们“愚弄”他们认为他们是活着的。因此,我们需要人工智能的社会心理学,因为人工智能正在以新的复杂的方式扩展我们的社会世界。

AI 的一个社会心理学应该涵盖什么?

如果你仍然不相信,也许列出一些关于内容的想法将有助于进一步证明社会心理学如何有助于我们理解不断发展的人工智能技术。前面,我列出了围绕两个主题的一些初步想法。

第一个主题是更明显的主题,专注于解决我们的社会心理如何影响我们构建人工智能技术的方式的主题。这个主题特别解决了人类偏见的问题,以及这种偏见是如何被人工智能技术放大的。它还包括解决社会心理学理论如何告知我们如何着手在我们的人工智能中建立新的能力。

第二个主题不太明显,但鉴于人工智能越来越多地融入我们的日常生活,它仍然同样重要。这个主题聚焦于社会心理学中的核心话题,解决人工智能如何影响我们自己的思想、感觉和行为。换句话说,这不仅仅是因为我们没有理解人类的偏见是如何进入人工智能解决方案的,而是因为这些解决方案与其他人类互动,因此应该也会影响这些人。

作者图片

主题 1:我们的社会心理如何影响人工智能

主题 1:模型偏差

这篇文章的例子清楚地表明,我们的人工智能模型正在学习我们人类的偏见。社会心理学家被训练去理解像数据收集这样的人类活动是如何充满偏见的。简单地决定一个问题首先需要一个模型是人类偏见的一种形式。因此,理解这些偏差及其潜在来源需要数据科学领域的更多多样性。社会心理学家可以帮助数据科学家理解我们的人类倾向是如何使我们收集的数据产生偏差的,并且还可以找出克服这些偏差的策略。

模型偏差现在是数据科学行业的一个非常热门的话题,像麻省理工学院的 David Sontag 这样的计算机科学家的工作正在帮助我们理解如何用数学方法检测这种偏差。但这些方法无法解决数据收集过程中的基本偏见,因此也需要社会心理学理论来更全面地捕捉问题的严重性。

相关的社会心理学概念包括研究方法中的理解偏差、偏见和歧视理论以及多样性。

主题 2:群体间的冲突

建立有偏见的模型,当应用时,可以迅速影响数百万人,这通常是无意的。建立模型来做出故意伤害数百万人的决定,是对人类偏见更有意识的应用。制造人工智能来故意伤害也不是科幻小说,只要看看无人机在我们最近的一些冲突中的使用就知道了。

社会心理学家长期以来一直在研究群体间冲突,诸如现实冲突理论、社会主导理论和社会认同理论等理论可以帮助我们理解设计人工智能来帮助管理社会群体互动的潜在影响。

主题 3:人工社会学习

超越人工智能趋势的当前状态,社会心理学家也可能能够为更多未来状态的人工智能发展做出贡献。我们已经知道,研究人员已经利用强化学习,基于经典和操作性条件反射的基本概念建立了模型。展望未来,数学的进步也许可以从社会学习理论中学习,如阿尔伯特·班杜拉、利维·维果斯基和卡罗尔·德韦克发展的理论。换句话说,当我们教机器通过观察向其他人或其他机器学习时,我们应该考虑什么?社会心理学可以帮助回答这个问题。

话题 4:人工情感

与社会学习类似,研究人员也对理解机器如何学习解释人类情感有相当大的兴趣。在基本意义上,自然语言处理领域的情感分析已经致力于开发这种能力。更复杂的媒介也正在被开发,以帮助解释视频信号和声音中的人类情感。

情绪的社会心理学帮助我们欣赏和理解规范、群体成员和文化在我们的情绪表达中扮演的重要角色。因此,社会心理学承诺更完整地看待开发理解人类情感的机器意味着什么。

主题 2:人工智能如何影响我们的社会心理

但影响人工智能如何发展的不仅仅是我们。AI 也可以影响我们如何发展。人工智能越来越多地出现在我们的生活中,使得这个较少研究的领域变得同样重要。社会心理学在帮助我们更好地理解这些影响方面有很多贡献。

主题 1:生存威胁

我所经历的人工智能对人类影响的最直接的方式之一,是作为一种生存威胁。我指的不是终结者天网描绘的那种生存威胁,也不是像埃隆·马斯克这样的有影响力的人对人工智能“可能”变成什么样子发表的可怕警告。不,我指的是更直接的生存威胁,即当人们看到人工智能自动让他们失业时,他们所经历的威胁。

这种威胁是真实的,尽管可能被夸大了一点,社会心理学家可能能够帮助确定如何管理这种威胁。例如,恐怖管理理论解释了人们在面临生计威胁时如何应对。因此,TMT 建议我们利用自尊和文化世界观来保护自己免受这种生存威胁。随着人工智能致力于让更多人自动完成那些有助于赋予他们生活意义的活动,我们应该期待新的世界观形成,甚至可能是对人类意义的新定义。

话题 2:人造关系

除了存在的威胁,更积极的是,人工智能还为人类引入了新的方式来建立关系,无论是通过增强现实还是直接与人工生命发展关系。例如,在电影中,她的 Juaquin Phoenix 扮演一个与 AI 语音助手发展关系的男人。两人一起探索人类情感的边界,这可能是男人因为社交焦虑和不安全感而永远无法触及的。

社会心理学家理解关系,依恋理论、社会交换理论和相互依赖理论等理论都可以帮助我们理解如何、为什么以及是否应该使用人工智能来形成关系

话题三:情感

与人际关系密切相关的是情绪的概念。正如理解情绪对于开发可以检测和理解人类情绪的人工智能模型很重要一样,理解人工智能如何塑造我们的情绪也很重要。回想一下泰伊和 GPT-3 关于弱势社会群体的人工智能反应。现在考虑一下,实际上有数十亿人代表这些社会群体,他们中的许多人无疑会读到这些实验及其结果。这些人如何看待这些实验,他们如何对结果进行归因,无疑会影响他们对自己的感觉。

主题 4:偏见与歧视

偏执的机器人不仅有可能伤害人们的感情,而且有可能进一步证明其他人对这些群体成员的偏见。社会心理学家可以帮助我们回答人工智能输出的感知合法性问题。

此外,随着人工智能的进步,我们作为人是否开始摆脱我们对它们的偏见,因为毕竟它们只是机器?自由表达偏见的后果,甚至是对无生命物体的偏见,可能会对我们彼此之间的关系产生深远的影响。

结论

总结一下,这篇文章是个开始。号召数据科学家和社会心理学家联合起来,共同努力,在不同领域分享知识。以一种对人工智能的未来负责并最终更加强大的方式,解决我们今天面临的一些最紧迫的伦理、社会、经济和环境挑战。

比如参与学习数据科学、职业发展或糟糕的商业决策?加入我

构建 Coco 格式的计算机视觉数据集

原文:https://towardsdatascience.com/building-computer-vision-datasets-in-coco-format-56593d5e3520?source=collection_archive---------30-----------------------

构建自定义计算机视觉数据集的综合教程

照片由抢笑Unsplash

计算机视觉是机器学习的最大学科之一,具有广泛的用途和巨大的潜力。它的目的是复制大脑令人难以置信的视觉能力。计算机视觉的算法并不神奇。它们需要信息来执行,它们的力量取决于你提供的信息。基于项目,有各种来源来获得适当的数据。

最著名的对象检测数据集是上下文数据集中的公共对象(COCO)。这通常用于评估计算机视觉算法的效率。COCO 数据集被标记,为训练受监督的计算机视觉系统提供信息,这些系统可以识别数据集的典型元素。当然,这些系统是完美无瑕的,因此 COCO 数据集作为计算机视觉研究的结果,作为评估系统随时间进展的基线。

在本文中,我们讨论了 Coco 文件格式,这是一种用于构建计算机视觉数据集、对象检测和图像检测方法的标准。

为什么神经网络对计算机视觉非常有效?

人工神经网络被认为是构成深度学习技术核心的 ML 的主要子类。它们的起源和架构与人类的大脑相同,它们像真正的神经元一样工作。

由于图片并不总是有标签,部分和元素的子标签必须被删除或巧妙地减少,神经网络对于计算机视觉来说是有效的。神经网络使用训练信息进行训练,并根据经验提高其效率。但是,一旦这些学习技术被精确调整,它们就成为计算机技术和人工智能中令人生畏的资源,让我们能够快速分类和组织数据。

与由有经验的科学家进行的传统分类相比,语音识别或图像识别中的活动可能只需要几分钟而不是几个小时。谷歌的技术是最著名的神经网络之一。

为什么仍然需要创建自定义数据集

迁移学习是一种特定的机器学习技术,其中为一项工作创建的模型被应用为不同任务的模型的基础。考虑到在这些问题上建立神经网络系统所需的巨大计算和时间资源基础,以及它们在类似问题上提供的专业知识的巨大飞跃,在机器学习中使用预训练系统作为自然语言数据处理的初步步骤是一种常见的策略。

我们可以使用迁移学习来处理这些情况,迁移学习使用以前从一个可比较的任务或主题中标记的数据。

照片由neon brandUnsplash

Coco 文件格式是建立计算机视觉数据集的标准

照片由 艾琳·克雷登茨*拍下*

分析视觉环境是计算机视觉的一个主要目标;它包括检测有哪些项目,在 2D 和 3D 中定位它们,识别它们的属性,并描述它们的关系。因此,数据集可用于训练物品识别和分类方法。COCO 经常用于测试实时对象识别技术的效率。现代神经网络模块可以理解 COCO 数据集的结构。

当代人工智能驱动的替代方法不太善于在发现中创建完全精确的结果,这导致了一个事实,即 COCO 数据集是 CV 训练、测试、润色和精炼模型的重要参考点,以更快地扩展注释管道。

COCO 标准规定了在实际阶段如何将注释和图片元数据保存在光盘上。此外,COCO 数据集是迁移学习的补充,其中用于一个模型的材料被用于开始另一个模型。

使用 Datatorch 构建计算机视觉数据集的教程

Anuj Syal 建立 Coco 格式的计算机视觉数据集

Datatorch 是基于云的免费注释工具之一。这是一个基于网络的平台,你可以直接进入并快速开始注释数据集

步骤 0:发现数据

解决任何机器学习问题首先从数据开始。第一个问题是你想解决什么问题。那么接下来的问题就是我能从哪里得到这些数据。

在我的情况下(假设),我想建立一个从照片中检测不同动物的 ML 模型。我正在寻找这些图片的来源谷歌的开放图片(一个数据集的庞然大物)。我只收集了狗的一个子集,并把它们与相应的

数据集许可 注释由 Google LLC 根据 CC BY 4.0 许可进行许可。这些图像被列为具有 2.0 许可证的 CC。在知识共享署名(CC-BY)许可下,任何感兴趣的人都可以使用开放图像。

第一步:创建新项目

登录后,您将看到显示您的项目和组织的仪表板主屏幕。当您试图跨不同团队处理多个项目时,这将是一个好方法。现在在标题栏的右上角,点击+并创建一个新项目

来自作者的截图

第二步:车载数据

然后从左侧导航栏转到Dataset选项卡,单击+创建一个名为dogtypes的新数据集。之后,您可以轻松地删除图像

来自作者的截图

或者还有另一种选择,直接连接到云提供商存储(AWS、Google、Azure)

第三步:开始注释

如果您单击数据集中的任何图像,它将直接将您带到注释工具

图片来自作者

  • ****注释工具左侧有您可以在中间的可视化工具窗口上使用的注释工具
  • ****数据集:所有图像的列表,点击进行标注
  • ****更改/创建标签:点击以更改与标注相关的标签
  • ****注释详情:在图像中完成一些注释后,您将在此处看到详情
  • ****工具详情/配置:当您选择一个注释工具时,详情/配置出现在此。例如,如果您选择画笔工具,您可以在此处更改其大小

要开始注释,您可以从选项中选择一个注释工具,这也取决于您要构建的模型的类型。对于对象检测模型,像边界框或圆形工具这样的工具很好使用,否则对于分割模型,您可以使用画笔工具或基于人工智能的超像素工具来突出显示相关像素。例如,我只是用了一个简单的笔刷工具(增加了大小)来突出狗。

来自作者的截图

此外,最好通过尝试来发现注释,或者你可以在我的 youtube 频道上观看教程。

来自作者的截图

  • 第四步:将带注释的数据导出为 Coco 格式

来自作者的截图

完成注释后,您可以转到 exports 并以 COCO 格式导出此注释数据集。

Coco 格式输出

注释活动的输出现在以 COCO 格式表示,它包含 5 个主要部分
-信息
-许可
-类别(标签)
-图像
-注释

有关详细信息,您可以在下面看到一个示例输出

结论

如果你对物体检测没有经验,需要创建一个全新的数据集,COCO 格式是一个很好的选择,因为它结构简单,用途广泛。COCO 数据集结构已经被研究用于最常见的任务:对象识别和分割。像 Datatorch 这样的工具有助于快速建立这些数据集。COCO 数据集是大规模数据集,适用于初级项目、生产环境和尖端研究。

参考

数据集链接:https://storage.googleapis.com/openimages/web/index.html

数据集许可:注释由 Google LLC 根据 4.0 版许可协议 CC 许可。这些图像被列为具有 2.0 许可证的 CC。

原载于https://anujsyal.com**

在管道中构建自定义列转换器

原文:https://towardsdatascience.com/building-custom-column-transformers-in-a-pipeline-9147a88d6b4?source=collection_archive---------23-----------------------

向现有管道添加自定义转换。

维克多Unsplash 上的照片

当标准变换不够时

标准的 scikit-learn 库提供了许多不同的功能。然而,许多转换、修改和变更数据的常用函数已经存在,并且很容易与管道兼容。

这篇文章将讨论如何为管道构建定制的转换器。有几个代码块可供复制。最终的变压器具有您选择的超参数优化方法的优化参数。

Scikit-learn 并没有完全涵盖数据科学家需要的所有内容,大多数问题都需要根据手头的问题进行定制。幸运的是,有专门为此定制的变压器。

您可能会有一个直接的问题,为什么定制转换需要作为管道的一部分。或者,您可以在通过管道推送数据之前手动转换数据。然而,将转换合并到您的管道中有几个好处。

  • 管道是可重复和可扩展的。从原始数据进行转换所执行的操作可以在另一台机器上从原始数据中以平稳的流程轻松重现。因此,您可以将工作负载分散到多台机器上,并分配计算负载。
  • 管道内的参数是可优化的。虽然不是所有的转换都需要参数,但其他转换可能需要参数。例如,假设您想要测试某个要素的平方值或立方值在模型中的表现是否更好。然后,指数可以被参数化和优化,以确定最佳配置。

定制变压器需要什么

创建自定义转换有几个考虑因素。第一,转换器应该被定义为一个类。这种设计创建了易于整合到管道中的框架。

该类继承自 BaseEstimator 和 TransformerMixin 类。这些类为自定义转换类提供一些基本功能,并确保与 sklearn 管道的兼容性。下一步是定义三个基本方法,一个 init() 方法、一个 fit() 方法和一个 transform() 方法。需要使用 init() 方法来初始化类,在管道拟合时调用 fit() 方法,在管道上调用 transform 或 fit 时调用 transform() 方法。

问题建构

定制转换器的实验使用乳腺癌数据集。代码和转换很容易根据不同的用例进行调整,以满足您的问题的需要。数据被分成训练集、测试集和用于分类问题的“ROC_AUC”度量。

转换后,整个管道将进行随机超参数搜索。该搜索允许通过选择超参数搜索来有效地优化变换中的参数。关于不同的超参数搜索的更多细节,请参考我关于这个主题的帖子:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, RandomizedSearchCV
from sklearn.metrics import roc_auc_score
from sklearn.pipeline import make_pipeline
from sklearn.pipeline import Pipeline
from sklearn.datasets import load_breast_cancer
from sklearn.tree import DecisionTreeClassifier
from scipy.stats import randintTEST_SIZE = 0.1
RANDOM_STATE = 10
data = load_breast_cancer()
df = pd.DataFrame(data.data, columns=data.feature_names)
df['target'] = data.target
X = df.drop(['target'], axis=1)
y = df['target'].astype(float)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE, stratify=y)

定义自定义变换

下面的代码块中定义的 CustomTransformer 类进行了一些修改,以提供高度的灵活性。应用了三种不同的变换,幂、对数和根。幂变换要求指定指数的次数。

对于这些转换中的每一个,保持原始特征列。这种构造有潜在的问题,因为转换后的特征和原始特征是相互依赖的。或者,您可以调整代码,用一个转换覆盖原始列,以消除这些依赖性。

要转换的列通过转换器中的“feature_names”参数确定。电力变压器的指数由“电力”参数决定。将您想要优化的参数定义为类的属性是至关重要的。在超参数搜索和随后的优化过程中,只能修改类别的属性。关于不同管道参数定义的更多细节,请参考我在完整 sklearn 管道上的帖子:

from sklearn.base import BaseEstimator, TransformerMixinclass CustomTransformer(BaseEstimator, TransformerMixin):
    # List of features in 'feature_names' and the 'power' of the exponent transformation
    def __init__(self, feature_names, power):
        self.feature_names = feature_names
        self.power = power def fit(self, X, y=None):
        return self def transform(self, X, y=None):
        X_copy = X.copy()
        for feat in self.feature_names:
            X_copy[feat + '_power' + str(self.power)] = self.power_transformation(X_copy[feat])
            X_copy[feat + '_log'] = self.log_transformation(X_copy[feat])
            X_copy[feat + '_root'] = self.power_transformation(X_copy[feat])
        return X_copy

    def power_transformation(self, x_col):
        return np.power(x_col, self.power) def log_transformation(self, x_col):
        return np.log(x_col +0.0001) def root_transformation(self, x_col):
        return np.root( x_col)

在管道中使用变压器

为流水线初始化几个元参数。这些包括折叠数、评分、指标、详细信息和并行化作业。请根据需要随时更新这些内容;然而,它们被初始化为以有限的计算能力运行。流水线是用决策树分类器和决策树的几个超参数分布建立的。

此外,我还包括了定制转换器的参数。首先是功率参数的随机分布,如前所述。接下来是一组不同特性名称的集合。该设置仅允许对特征子集进行转换,而不是对所有特征进行转换。由于使用的优化技术是随机超参数搜索,这三个特性列表将被随机选择并用于优化。

N_ITER = 5
K_FOLDS = 5
SCORING_METRIC = 'roc_auc'
VERBOSE = 1
N_JOBS = 1hyperparameter_dict = {
    'custom_transformer__power': randint(1,4),
    'custom_transformer__feature_names': [
        ['mean texture', 'mean perimeter', 'mean area'],
        ['smoothness error', 'compactness error', 'concavity error'],
        ['worst concave points', 'worst symmetry', 'worst fractal dimension'],
    ],
    'model__max_depth': randint(3,10),
    'model__max_features': ['sqrt'],
    'model__min_samples_split': randint(2,20),
}pipe = Pipeline(steps=[
    ('custom_transformer', CustomTransformer(feature_names=list(X.columns), power=2)),
    ('model', DecisionTreeClassifier())
])
optimal_model = RandomizedSearchCV(
    pipe, hyperparameter_dict, n_iter = N_ITER, cv=K_FOLDS,
    scoring=SCORING_METRIC, n_jobs = N_JOBS,
    return_train_score=True, verbose = VERBOSE
)
optimal_model.fit(X_train, y_train)
print(
    optimal_model.score(X_test, y_test),
    optimal_model.best_params_
)

结论

这篇文章讨论了如何创建一个与 sklearn 管道兼容的自定义转换函数。此外,这些变压器结合了优化参数

最终,标准 sklearn 包和函数中已经包含了许多功能。然而,肯定不是一切。可以有效地利用自定义转换来为现有管道增加额外的灵活性,并添加自定义功能。

如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。

如果你对我的写作感兴趣,并想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。

https://zjwarnes.medium.com/membership

在 Dash 中构建仪表板

原文:https://towardsdatascience.com/building-dashboards-in-dash-591a6223efd3?source=collection_archive---------9-----------------------

在 Dash 中创建仪表板,从您的分析中获得价值。

交互式 Dash 仪表板(作者提供的 GIF)

ashboards 是一种快速有效的可视化和监控数据的方式。有了 Plotly 和 Dash,用 Python 构建仪表板变得前所未有的简单。

本文将讨论为什么仪表板是有用的,并展示如何使用 Dash、Plotly 和 Python 生成基本的仪表板。可以使用 CSS 进一步定制布局。

本文中用于仪表板的数据是使用 Alpha Vantage API 收集的几家汽车公司调整后的公开股票价格。

可视化数据就是从信息中提取价值。然而,这个故事可能是隐藏的,不清楚的,或难以理解的大量数据。因此,分析师利用可视化和仪表板工具来查明数据的关键方面并揭示价值。

互动数据

因为可视化是数据快照,分析师和数据科学家必须对他们选择显示的数据子集进行选择。这个问题在静态可视化中很突出,在静态可视化中,图形的尺寸是在设计阶段选择的,并且保持不变。

为了解决这个问题,可视化工具,如 Plotly,结合了动态可视化。例如,默认情况下,Plotly 允许用户浏览图表、放大/缩小以及添加/删除轨迹。这种灵活性增加了可视化的有效性,并增加了查看图表的人的参与度。

仪表盘

每年,公司和组织都会受到越来越多的数据轰炸。然而,如果没有有效的方法来解析和提取决定性的见解,这些信息就相对没有意义。

目标是使用数据来驱动行动,这就是仪表板的用武之地。

约翰·施诺布里奇在 Unsplash 上拍摄的照片

仪表板充当收集的数据和决策者之间的渠道。仪表板旨在以易于理解的方式从数据中快速提供可操作的见解。

用户应该能够拉起一个仪表板,提出一个问题,并回答问题。
这种用户参与对传递信息至关重要,并确保用户恰当地吸收信息。

这就是破折号的用武之地。

因为 Dash 建立在 Plotly 之上,所以交互功能已经存在。此外,它与 Python、R 和 Scala 兼容,这使得它可用于许多不同的。

仪表板设计

Dash 的设置是高度用户友好的。如果您已经有了使用 Plotly 的经验,您将能够轻松地构建 dash 应用程序。

任何 dash 应用程序的基本组件是布局、绘图和仪表板交互。

Dash 应用程序由几个不同的组件构建而成。然而,大多数功能来自 dash 核心组件(DCC)、html 组件和任何引导程序主题。

为仪表板开发过滤器时,第一步是为用户生成一个选项列表。然后,这些被传递给一个下拉组件。

这个仪表板的数据是五家最大汽车公司的股票数据。这个基本的仪表板允许用户选择哪些股票在主图中可见。

导入仪表板组件、加载数据和生成选项(由作者编写代码)

成分

布局基于 HTML 标签。如果您熟悉 HTML,dash 组件应该是标准的。每个 Dash 组件都基于一个 HTML 标签,但是具有专门为 Dash 设计的定制功能。

这意味着你可以从简单的开始,从你知道的开始。然后慢慢地将你的仪表板构建成越来越复杂的东西。

接下来是 dash 核心部件。其中包括一个接受绘图图形和其他绘图对象的图形组件。这些核心组件还包括一些小部件,比如用于这个仪表板的下拉菜单。

这些核心组件非常适合快速生产高质量的仪表板。一些流行的组件是滑块、清单或日期选择器。你可以在这里查看可用组件:https://dash.plotly.com/dash-core-components

仪表板的设计布局(由作者编写代码)

复试

使用目标图表设计布局后,剩下的就是添加交互了。虽然这些图已经有了一些基本的交互级别,但 Dash 允许用户动态地更改仪表板中的数据,更新图表和一些导航功能。

动态 Dash 应用的核心是回调函数。

回调函数是在函数定义之前使用 Python decorators 定义的。
输入、输出和函数参数遵循严格的格式。

向 Dash 添加交互式回调(由作者编写代码)

输入通常来自 dash 核心组件,比如本例中的下拉选择器。第一个参数是指定数据源的元素的 id。第二个参数是组件的属性。

输出遵循与输入相同的格式,但是数据被发送到指定的仪表板部件。

根据指定的输入和输出,您创建的函数需要相同数量的输入参数和与预期输出类型相匹配的输出数据类型。

对于多个输入,函数参数对应于输入列表中的每个元素。

定制和 CSS

仪表板的基本功能设置好之后,剩下的就是添加一些定制了怎么办。

对于这个仪表板,我保留了主应用程序本身的样式。因此,将这些细节作为字典添加,然后添加到每个 Dash HTML 组件的样式属性中。

或者,您可以将资源文件夹和 CSS 文件添加到应用程序中。这个结构的定义和你对任何 CSS 网页的定义是一样的。匹配类和 id,并直接改变您的仪表板。

向仪表板添加样式(由作者编写代码)

部署

根据您的需求,Dash 应用程序的部署可能会有很大不同。例如,在本地服务器上托管仪表板只需要使用 Python 运行仪表板。但是,在本地网络中访问可能需要独特的网络规范。

如果本地主机不是你仪表板的目标,考虑一个服务,比如 Heroku。Heroku 的免费层是可用的。

使用“Python app.py”运行 Dash 应用程序(由作者编写代码)

仪表板——汽车公司,调整后的股票价格(图片由作者提供)

总结

仪表板是监控业务目标、跟踪进度和分析数据的绝佳工具。

花费数小时开发一个完全交互式的仪表板的日子已经一去不复返了。相反,您可以通过 Dash 快速生成仪表板,为自己节省大量时间。

本文讨论了设置和运行 Dash 应用程序的几个方面。只需最少的努力,您就可以轻松创建您的仪表板。

如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 medium 上关注我。我总是在我的文章中包含代码,您可以将其应用到您的工作中!

如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。

https://zjwarnes.medium.com/membership

使用 R 构建数据管道

原文:https://towardsdatascience.com/building-data-pipelines-using-r-d9883cbc15c6?source=collection_archive---------24-----------------------

一个如何使用数据管道方法在 R 中使用数据文件的例子

照片由负空间发自 StockSnap

如果你是一名数据分析师,你很有可能会遇到一个数据集,因为它的大小或复杂性而给你带来很多麻烦。如今,大多数数据分析师依赖于几种可视化和电子表格工具的组合,这些工具可以帮助他们理解周围的数据,但“分散文件的诅咒”仍然存在,尤其是在大公司。

但是,随着我们离开新千年的前二十年,我们目睹了新数据源创建的巨大增长——不仅数据分析师需要理解组织内部产生的数据(随着组织试图更加精通数据,产生和存储的数据量呈指数级增长),而且有时他们还需要理解与公司无关的外部数据。这种多样性要求用新的方法来解决旧工具无法解决的新问题。

当然,由于其民主化和可用性,Microsoft Excel 是分析数据的最佳工具之一,但是一旦您传递了一定数量的行,您收集见解和理解原始数据的能力就会变得非常有限。用 Excel 分析大文件有两个主要问题:

这并不是说 Excel 是一个不好的工具(我真的认为它很棒),只是它不适合大文件——然而,大多数人,尤其是大公司的人,仍然依赖它来完成各种数据任务。数据可视化和自助服务商业智能工具已经在某种程度上解决了这个问题— 但是要获得这些工具,你需要过度依赖预算或政治。

幸运的是,开源工具的采用在过去十年中激增(特别是在 R 和 Python 大放异彩的数据分析领域)因为,尽管有一个巨大的社区,它们有一个平滑的学习曲线,并且对大多数人来说都很容易获得。

能够在这些系统中编码可能使分析师能够提高他们的整体生产力和分析数据的能力——但是,有时当他们不能正确地将电子表格文件加载到 R 或 Python 中时,他们会感到沮丧,最终坚持使用电子表格软件。

在这篇文章中,我们将探索如何构建和思考准备电子表格文件以供分析的函数——流水线的流程与我在 UdemyT5 上的 R 编程课程中教授的流程相同

数据集

我们将使用联邦调查局的犯罪数据集,它有一个大概的样子:

我们示例数据集的电子表格外观

正如我们所看到的,我们有几个栏目传达了几乎相同的信息,如名义价值和利率。如果我们试图将这些数据直接导入 R 中,我们可能会得到一些奇怪的东西,因为我们在列中有一些额外的信息(例如,引用),因为任何工具都很难找到这个电子表格中的“真实数据”(请记住,Excel 应该有这些信息,因为它是面向用户的工具)。

例如,脚注可能会作为一行包含在您的数据中——这使得您的数据很难分析— ,但是您可以通过一些数据争论技巧来解决这些问题!

将其导入 R

要将这个 Excel 文件加载到 R 中,我们将依靠 tidyverse 包的readxl(https://readxl.tidyverse.org/)R 库:

*library(readxl)
# Load the Data
crime_data <- read_xls("./data/FBI Crime Data.xls")*

查看我们刚刚加载的文件头:

加载到 R 中的 excel 文件头

啊,看那个!我们的前两行可能是无用的,第三行包含我们的列名。我们也有一些年份的问题(看看 20015 年的第 8 行索引——这是因为上标 5 被读成了一个正常的数字)。

桌子的底部也不好看:

加载到 R 中的 excel 文件底部

我们在 excel 工作表中的一些描述和元数据最终被读取为行——这些元数据对于查看 Excel 文件的人来说很有用,但对于试图在数据分析工具上持续分析这些数据的人来说却不太有用。

这些是数据科学家和分析师每次想要分析新数据集(尤其是来自结构化程度较低的来源的数据集)时都会遇到的常见数据争论问题。

我们手头有些工作,所以让我们把它做完吧!

从列名开始

这个很简单——我们的列名在第三行,所以我们可以使用 colnames 函数来设置它们:

*colnames(crime_data) <- crime_data[3,]*

我们的普通桌子是这样的:

带列的表格

自动过滤

为了建立有趣和健壮的数据管道,我们必须想出系统的规则,能够传达我们将通过管道传递的可能文件的未来变化。

我们肯定可以通过使用向量对数据集中的第一列进行子集化来对年份进行子集化,并查看值 1997、1998… 2016(我们在该文件中拥有的最新年份)但是如果有人给我们一个包含直到 2017 年的数据的文件呢?还是包含 1996 年的文件?

如果我们将我们的年份硬编码到管道中,我们将建立硬编码的规则——这些从来都不是一个好的选择,因为它们只适用于这个文件并且只适用于这个文件(或者具有完全相同结构的文件)。

对于一个包含 20 多年数据的新文件(我们表中可用的数据),您的管道将无法过滤它们— 因此,通过查看下面的文件,您是否可以提出一些规则来对表进行子集化,而不管包含年度信息的行数是多少?

我们能想到的一个很好的规则是,只获取第一列中值可以转换为数字的行。这是一个很好的“数据管道规则”的例子,因为它可以防止将来的错误或信息丢失。

如果我们尝试将该数据集的第一列转换为数字类型,非数字的元素将作为 NA 的(不可用)返回—然后我们可以过滤掉那些 NA 的,有效地保留我们感兴趣的行— 我们将依赖 sapply 将我们的第一列转换为数字—我们将创建一个新列:

*crime_data[‘converted_index’] = sapply(crime_data[,1], as.numeric)*

我们新的 converted_index 列将具有如下外观:

注意当 R 不能将我们的列转换成数字时, NA 的是如何被强制引入的。

过滤掉这些行将得到下表—前 11 行和前 9 列的简短摘要:

我们如何过滤掉这些 NA?我们能够用下面的代码实现这个目标:

*crime_data_filter = ( 
 crime_data[!is.na( 
  crime_data[,ncol(crime_data)] 
 ),]
)*

使用此规则,我们选择数据帧中最后一列不是NA——的每一行,因为我们的 converted_index 列是在管道中创建的,所以执行以下操作也是安全的(会产生相同的结果):

*crime_data_filter = ( 
 crime_data[!is.na( 
  crime_data[,'converted_index'] 
 ),]
)*

在这种情况下,对列 converted_index 进行硬编码不会有问题— 因为转换后的索引是在我们的管道内部创建的,并且创建该列的规则对于输入是灵活的,所以风险较小。

更正年份列

我们仍然需要去掉像 20015 这样奇怪的值——这是因为 R 将指向 excel 文件中引用的上标 5 读成了一个数字(在那个系统中这是有意义的)。

幸运的是,Year 列仍然是一个字符,所以我们能够直接应用 substring,并且只检索每年的前 4 个“字母”(它们是数字,但是由于数据的类型,R 将它们视为字符串):

*crime_data_filter$Year = substr(crime_data_filter$Year, 1,4)*

请注意我是如何重写 Year 列的,只使用每年的前 4 位数字——R 错误地认为是年份的一部分的额外数字按照我们的要求被删除了。

我们能够得到以下数据帧:

自动化列选择

正如我们所看到的,列传递相同的信息(rate 只是原始列除以一百万居民),正如我们对行过滤所做的那样,我们也可以进行一些自动化的列过滤。您能想出一个不依赖硬编码规则就能选择表中非费率列的规则吗?

让我们用以下命令来检查我们的列名:

*names(crime_data_filter)*

这是输出:

数据框的列名

仔细观察,名称中有 rate 的每一列都应该从我们的表中删除。我们可以依赖 grepl 函数,而不是硬编码列的名称或索引。使用:

*grepl( “rate” , names(crime_data_filter))*

该函数将返回一个包含 TRUE 和 FALSE 的向量—在列名包含“rate”的索引中为 TRUE,否则为 FALSE:

我们现在可以依靠这个向量来过滤掉数据框中的这些列——使用索引器。我们还将重写我们的原始对象:

*crime_data_filter = crime_data_filter[,!grepl( “rate” , names(crime_data_filter))]*

将我们的数据转换成数字

我们快完成了!让我们看看我们的 crime_data_filter 结构:

我们的大多数列仍然是字符(这个问题从流水线开始就一直存在,因为我们在 excel 中有空白单元格,使得 R 认为这是一个字符列)即使我们在其中只看到数字!**

让我们将这些列转换成数字— 我们不能将 as.numeric 直接应用于我们的对象(我们只能对向量、矩阵或数组这样做)—我们需要依靠我们的 apply 函数族!

*sapply(crime_data_filter, as.numeric)*

由于 sapply 返回一个列表,我们将把这个函数包装在 data.frame 函数上以获得一个数据帧。

*pipeline_table <- data.frame(sapply(crime_data_filter, as.numeric))*

结论

现在我们有了一个真正干净的表,并且能够被分析——我们可以将我们所做的每一条指令封装在一个可以重用的函数中:

总之,了解如何构建数据管道是在依赖代码的系统中分析数据的一项基本任务——特别是在越来越多的专业人员使用 R 和 Python 访问数据的世界中,了解如何在读取数据文件时构建防错规则非常重要。

本讲座摘自我在 Udemy 平台 上的 R 编程课程——该课程适合初学者和想学习 R 编程基础的人。该课程还包含 50 多个编码练习,使您能够在学习新概念的同时进行练习。

使用 PySimpleGUI 构建数据科学 GUI 应用程序

原文:https://towardsdatascience.com/building-data-science-gui-apps-with-pysimplegui-179db54a9a15?source=collection_archive---------5-----------------------

如何遵循最短的学习曲线构建简单的数据科学 Windows/GUI 应用程序?

图片来源: Unsplash

为什么选择桌面/Windows 应用?

Jupyter 笔记本上的数据科学很棒。但是您想更进一步,将您的项目/模型部署在云服务器上。有许多优秀的解决方案——使用 Flask、Django 或 Streamlit 等库。

参见我关于使用 Streamlit 构建数据科学应用的文章。

虽然云部署的解决方案仍然是最受欢迎的选择,但您可能经常希望为您的数据科学和机器学习项目构建一个快速的 GUI 应用程序。举个例子,

  • 用各种数据集测试 ML 模型。您可能只想将 CSV 文件拖放到模型上,并绘制 AUC/ROC 曲线。一个 GUI 应用程序会很好,不是吗?
  • 绘制给定范围内的随机变量或统计分布,并使用 GUI 动态控制参数
  • 通过 GUI 在数据集上快速运行一些数据争论/预处理任务(而不是编写一堆重复的代码)

在本文中,我们将展示如何遵循最小的学习曲线,用直观的 Python 代码构建这样一个 GUI。

什么是“PySimpleGUI”?

Python 生态系统中有一些非常流行的 GUI 框架,如 Tkinter、PyQt 等。但通常,它们有些臃肿,对于数据科学家来说很难学习,他们可能希望用最少的代码构建简单的应用程序,而不是专注于构建大型企业级 GUI 程序。

具有简单学习曲线的包装器

根据他们的网站,PySimpleGUI 是一个“人类的 Python GUI 将 Tkinter、Qt、Remi、WxPython 转换成可移植的友好的 Python 接口”。基本上,它将所有这些流行的、成熟的 GUI 框架打包到一个库中,学习和构建应用程序非常简单。

基本上,只要花一个下午的时间,并且对 Python 有一个基本的(不是高级的)熟悉,就可以使用这个库开始制作功能(和有用的)GUI 应用程序。您甚至不必编写一个单独的类定义来生成一个 GUI 应用程序!

通常,数据科学家并没有丰富的软件工程经验。通过学习和使用一种工具,他们可能会受益匪浅,这种工具使他们能够开发小型的、有针对性的 GUI 应用程序,用于探索数据、分析和试验 ML 模型等。

因此,我开始了下面的 repo,目的是用简短而集中的 Python 脚本来填充它,这些脚本在运行时将生成桌面应用程序。

https://github.com/tirthajyoti/DS-with-PySimpleGUI

互联网上已经有一些关于 PySimpleGUI 的高质量教程。然而,在这个报告中,我特别关注使用这个强大的 GUI 构建工具创建与数据科学相关的简单演示程序(简单分析、统计建模、可视化和基本机器学习)。

…它们有些臃肿,对于数据科学家来说很难学习,他们可能希望用最少的代码构建简单的应用程序,而不是专注于构建大型企业级 GUI 程序

惊人的优势

  • 不需要回调函数
  • 它利用 Python 构造来缩短代码量。例如,小部件是就地配置的,而不是相隔几行代码。
  • 单一软件包依赖性—包装 Tkinter,不需要安装任何其他软件包。
  • 同一个 GUI 程序可以在多个 GUI 平台(包括 web 浏览器)上执行,而不需要更改源代码(除了 import 语句)。
  • 能够为多种操作系统平台——Windows、Linux、Raspberry Pi 和 Android (PyDroid3)创建 GUI,只需做很小的改动。

图片来源:作者根据免费图片创作的拼贴画

基本上,只要花一个下午的时间,并且对 Python 有一个基本的(不是高级的)熟悉,就可以使用这个库开始制作功能(和有用的)GUI 应用程序。

应用示例

安装库,

pip install pysimplegui

您还需要以下内容来运行本文中显示的示例,

  • Numpy
  • 熊猫
  • Matplotlib
  • sci kit-学习
  • 海生的

(数据科学)“Hello World”

PySimpleGUI 中最简单的程序可以在一个小窗口上打印一个“ Hello World ”。但是,本着数据科学的精神,让我们让我们的介绍性程序变得更复杂、更有用,好吗?

下面是一个 脚本 。姑且称之为‘gen random . py’吧。

转到这个脚本所在的目录并运行,

python GenRandom.py

您将看到一个简单的窗口弹出,您可以点击一个按钮调用update函数(见上面的代码),次数不限,只要您想生成一个 1 到 99 之间的随机整数。注意这个无限循环动作的代码中的while True循环。

尽管这是一个非常简单的脚本,

  • 布局(带有样式参数,例如sizefont)和一个窗口
  • 调用外部函数(事件)的按钮元素
  • 该函数更新窗口对象的文本元素

我们基本上可以遵循相同的路径,并添加更多的布局、事件、逻辑和小部件层,以制作强大的数据科学应用程序。

其他小部件

这是另一个演示其他小部件的脚本。只需运行python FontUpdate.py命令,你会看到这个窗口弹出,你可以动态更新文本的字体。这是演示视频,

用方程求解器把它刻出来

运行python QuadraticEquation.py脚本命令,你会看到这个窗口弹出,在这里你可以输入一个二次方程的系数并得到解(即使根是复数!)

熊猫数据帧分析仪

在这个例子中,我们展示了创建一个与数据科学家广泛使用的对象(如熊猫数据框架)进行交互的 GUI 是多么容易。像往常一样,你通过启动 脚本

python SimpleDataFrame.py

开始时,它会要求您提供一个数据集文件(CSV)。

当你点击“浏览”按钮时,它将首先显示一个文件浏览器对话框。确保您从data目录下为这个演示选择了正确的数据集。

选择cars.csv后,您会看到弹出的其他提示。

如果您在最后一个提示上单击“Yes ”,您将在新窗口中看到读取的数据集,

关闭该窗口后,一个新的弹出窗口将询问您是否想要查看关于该数据集的描述性统计数据。如果你点击“是”,你会看到这样的内容,

关闭该窗口后,另一个弹出窗口将询问您是否想查看样本图。如果你点击“是”,你会看到这样的内容,

随机散点图生成器

这个应用程序是为了展示创造一个与用户互动的动态情节的能力。剧本在这里是https://github.com/tirthajyoti/DS-with-PySimpleGUI/blob/main/DrawRandom.py。当你运行它时,会弹出一个窗口,有一个简单的按钮,你可以想按多少次就按多少次,每次都会生成一个随机散点图。当然,它在后台使用 Numpy 和 Matplotlib。

曲线拟合应用程序

数据科学家和分析师总是在为一些数据拟合曲线或分析函数。创建一个简单的应用程序并使用 PySimpleGUI 进行演示是很容易的。

这里的 是剧本。当您运行它时,将弹出一个窗口,其中包含用于生成和拟合二次多项式函数的按钮。此外,我们还放了一个小滑块来调整添加到数据中的高斯噪声水平。简而言之,这个例子向您展示了如何在一个轻量级 GUI 中集成数据拟合的基本特性。

Scikit-learn 模型拟合示例

最后,我们归结到一个真实的机器学习例子。我们展示了如何构建一个简单的应用程序,让您加载皮马印第安人糖尿病数据集,并在后台使用 Scikit-learn 将随机森林模型拟合到该数据。

剧本这里是 这里是 。下图说明了这个 GUI 程序的运行。请注意,它涵盖了机器学习程序的标准流程。

  • 加载数据集
  • 用于删除 NaN 值和指示列是否有标题的选项
  • 显示数据集
  • 显示描述性统计数据
  • 从加载数据集时自动填充的列表框中选择输出列
  • 用于输出列的简单错误检查器
  • 在后台运行机器学习分类算法,并在 GUI 上显示准确度

摘要

我们描述了一个用于构建 GUI 程序的简单而强大的 Python 库,并讨论了它与更成熟的库相比的优势。许多优秀的教程都是关于用 Python 进行 GUI 编程的,但是在本文中,我们展示了与数据科学和数学编程相关的示例,这是传统教程中所没有的。

这是图书馆的官方食谱。

**https://pysimplegui.readthedocs.io/en/latest/cookbook/

在本文中,我们展示了涵盖以下内容的示例

  • 用于用户控制的各种类型的小部件
  • 数据输入和输出—文件读取和绘图生成
  • 传统的数据科学库,如 Numpy、Pandas、Matplotlib 和 Scikit-learn。

显然,我们可以在这些例子的基础上构建更多直观的数据科学 GUI 应用程序。我计划继续在我的 Github repo 中添加这样的例子,如果你喜欢,你可以叉或星。**

喜欢这篇文章吗?成为 中等会员 继续 无限制学习 。如果您使用下面的链接, ,我会收到您的一部分会员费,而不会对您产生额外的费用

**https://medium.com/@tirthajyoti/membership **

使用 Python 构建数据可视化 web 应用程序

原文:https://towardsdatascience.com/building-data-visualization-webapps-using-python-769bc13fe12?source=collection_archive---------10-----------------------

使用 DStack 轻松创建交互式 web 应用程序

来源:作者

数据可视化是理解数据的一个重要方面。它揭示了数据点之间任何隐藏的模式或关联。有不同的 Python 库可用于可视化,但如果我们可以创建一个 web 应用程序来显示不同数据点的可视化,并包含不同的小部件,如下拉列表、复选框等,这不是很有趣吗?

类似地,创建机器学习模型并在 web 应用程序中使用它来生成预测可能是有用的,但通常有点困难。如果我们可以开发 ML 模型并轻松地在 web 应用程序中使用它们,这不是很好吗?

DStack 是一个开源 Python 库,用于构建 web 应用程序,不仅用于数据可视化,还用于机器学习实验。它允许我们用最少的代码创建 web 应用程序,并且易于使用。

在本文中,我们将探索 DStack 并创建一个用于数据可视化的基本应用程序,还将向您展示如何将机器学习模型推送到 DStack。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装来安装 DStack 开始。下面给出的命令将使用 pip 安装 DStack。

pip install dstack

导入所需的库

在此步骤中,我们将导入加载数据集、创建数据可视化以及使用 DStack 为这些可视化创建 web 应用程序所需的所有库。

import dstack as ds
import plotly.express as px
import seaborn as sns

加载数据集和创建可视化

在创建可视化之前,我们需要创建一个应用程序的实例,我们将在该实例下编写所有代码。在这里,我们将编写用于加载数据、创建可视化并在 web 应用程序中呈现它们的代码。

app = ds.app() def get_data():
    df = sns.load_dataset('tips')
    return df visual = app.select(items=get_data().columns.tolist())def output_handler(self, visual):
    self.data = px.box(get_data(), x="time", y=visual.value()) 
app.output(handler=output_handler, depends=[visual])# deploy the application with the name "stocks" and print its URL 
url = app.deploy("visual")
print(url)

一旦我们运行这段代码,应用程序将在输出的 URL 上呈现。下面给出了应用程序主页。

网络应用(来源:作者)

在这个 web 应用程序中,我们可以清楚地看到我们在上面的代码中创建的盒状图,以及选择不同列来创建它们的盒状图的下拉列表。

继续尝试不同的数据集,创建不同的可视化效果,并让我知道您在回复部分的评论。

本文是与 Piyush Ingale 合作完成的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

构建深度神经网络的简单方法|感知实验室

原文:https://towardsdatascience.com/building-deep-neural-networks-the-easy-way-perceptilabs-bd065c9544c4?source=collection_archive---------30-----------------------

一种构建深度学习神经网络的可视化方法

马里乌斯·马萨拉尔在 Unsplash 上的照片

PerceptiLabs 的视觉模拟模型提供了一个图形用户界面,用于创建、学习和评估设计,并允许进一步的编程修改。你可以得到快速的重复和更容易描述的改进的解决方案。

可感知的框架允许用户创建修改的模型配置,而不需要科学知识以及端到端模拟技术,这使得用户能够以完全清晰的方式感知和分析模型,从而提高意识并允许错误检测。

什么是感知实验室?

这实际上是 TensorFlow 的用户界面,具有先进的机器学习平台和图形建模过程,结合了编程的自由和拖放界面的便利,这将是 TensorFlow 之上的可视化设计。这可以使建模创建更简单、更快速,并且对更广泛的人群更有效。

它还包括各种学科的预建算法,可以由个人转移到工作场所,使他们能够在自己的数据集上修改和学习这些算法。税务欺诈识别、用于模式识别的对象分类以及其他应用都是该系统的使用应用。

感知实验室和机器学习

PerceptiLabs 成立的目标是让各种规模的企业更容易地进行机器学习建模。机器学习在我们的发展中可能有一个至关重要的方面,PerceptiLabs 现在正在努力让各种规模的企业在这个特定的行业中起步。

它分析当今可访问的不断增长的数据量,帮助企业识别信息的趋势,并根据这些趋势提供估计。每个企业都有一系列的应用,例如使用对象识别来预测哪些杂货店的库存越来越少,或者利用图片识别来识别拥挤的场地中的人。

用户可以通过 PerceptiLab 的可视化建模解决方案,轻松地为任何类型的业务创建机器学习算法。它使用户能够点击和拖动项目和连接元素,然后在软件立即编写程序之前配置变量。用户可以快速训练和微调他们的机器学习模型,并观察其性能。

感知实验室的工作流建模

照片由 托比亚斯·卡尔松 Unsplash

预制元素封装 TensorFlow 数据,并将其简化为可见的组件,同时仍然支持定制的代码更新。这个图形界面使您能够将这些元素移动到描述系统设计的结构中。这种用户界面使得实现额外的功能变得简单,例如一键编码和厚分层。

当您更改 PerceptiLabs 中的设计时,每个元素还会提供关于它如何转换数据集的图形信息。这种即时概览减少了在查看结果之前执行整个模拟的要求,使您可以更快地进行更改。

每当你将 PerceptiLabs 与任何其他平台进行比较时,你会发现图片可视化和信息分类要容易得多。您还可以观察每个元素如何改变信息,以及这些改变如何促成最终的分类。

在建模期间,PerceptiLabs 检索并利用可访问数据集的初始部分,并在您实施调整时重新运行系统,您将立即看到您的修改如何影响您的结果。这个有用的工具允许您检查结果,而不必对整个样本执行算法。

在感知实验室上建立你的第一个深度学习模型

如果你对更全面的视频教程感兴趣,可以看看下面我的 youtube 视频

用简单的方法建造 DNN

第一步:在本地 Open 终端上安装并运行 Perceptilabs,使用 pip 在本地安装并运行该工具(确保拥有 python 版本< 3.9

pip install perceptilabs 
perceptilabs

安装完成后,该工具在 localhost:8080 上启动并运行

第二步:理解数据集我使用的是 Perceptilabs 中提供的默认样本数据集X-Ray scans of patients。数据集具有带 3 个标签的 x 射线扫描- NormalViral PneumoniaCovid

作者截图

要在 Perceptilabs 中导入这个数据集,你需要正确的格式,它在data.csv文件中,包含带有相应标签的文件路径

步骤 3:转到模型中心(左边第一个选项卡),点击创建模型并导入数据集 **data.csv**

作者截图

选择 URL 作为输入要素,选择标签作为目标保持数据分区为默认[70%训练,20%验证,10%测试]

选择训练设置

作者截图

提供Model NameEpochsBatch SizeLoss FunctionLearning Rate等详细信息,点击定制,进入建模窗口

在建模窗口中,您将看到神经网络的所有层都按照建模工具的推断进行布局,看起来应该类似于下面的屏幕截图

默认情况下,它包含一个连接到输入图像的卷积图层和两个使用 softmax 将其转换为最终标签输出的密集图层

第四步:使用工具和多层你可以添加更多的深度学习组件作为建模工具的一部分,或者你可以轻松地为另一层编写一个定制的 Keras 函数

作者截图

构建任何深度学习模型都需要大量的迭代,因此可视化方法非常方便,我们可以即插即用并查看迭代结果

步骤 5:开始训练并查看实时统计数据(统计数据视图)单击顶栏上的“使用当前设置运行”开始训练模型,按照前面的讨论传入模型设置,对于分类用例,交叉熵损失函数更有意义。

作者截图

开始建模后,您将被重定向到统计视图,以查看模型在接受训练时的实时统计数据,您应该能够看到正在接受训练的数据集的每一行的权重输出、损失和准确性。所有这些分析都可以一层一层地进行

作者截图

您还应该能够看到精确度随着纪元在全球范围内的推移而提高

作者截图

步骤 6:在测试数据集上运行验证转到测试视图并运行测试,以获得模型度量和标签的混淆矩阵

作者截图

完成后,您应该能够看到您使用这些测试指标(如Model AccuracyPrecisionRecall)构建的模型的质量

作者截图

为什么像感知实验室这样的东西有意义?

数据分析师可以使用这种技术来更有效地执行机器学习技术,并很好地理解它们。

帮助您获取实时信息

每个建模元素数据的实时度量和详细摘要都是可用的。您可以简单地跟踪和分析变量的行为,实时排除故障,并确定您的系统可以改进的地方。

帮助您在 GitHub 上分享它们

PerceptiLabs 允许您维护许多模拟,评估它们,并快速有效地与您的团队交流发现。将数据导出为 TensorFlow 框架。

帮你克服兼容性问题

当一家公司的研究人员创建模型并将其投入运行时,他们必须都使用同一个模型。否则,就会出现问题。根据一些专家的说法,如果公司里的每个人都使用 PerceptiLabs 的技术,这个问题就可以避免。帮你导出模型

Perceptilabs 允许您检查和解释程序如何运行和执行,以及为什么会产生特定的结果。您也可以在同意后将数据导出为训练 TensorFlow 版本。

使用感知器的优势

这个工具提供了广泛的好处。有些是;

  • 快速建模—包括简单的拖放式用户界面,有助于简化系统设计的创建和分析。
  • 可见性——它可以用来开始理解你的策略是如何执行的,以便对其进行解释。
  • 多功能性—作为一个基于 TensorFlow 的图形 API,这允许程序员使用 TensorFlow 的低级接口,同时也允许他们使用其他 Python 库。

结论

如果企业要接受机器学习,开发算法的程序必须简化。PerceptiLabs 提供图形化机器学习建模解决方案,帮助企业实施计算机学习。它不仅能让你快速开发计算机学习网络,还能给你一个模型如何运行的图形表示,并能让你彼此交换信息。

最初发表于https://anujsyal.com

将机器学习模型产品化

原文:https://towardsdatascience.com/building-end-to-end-machine-learning-powered-applications-673ea9e9c6d3?source=collection_archive---------10-----------------------

如何构建基于机器学习的端到端应用

构建利用机器学习的端到端应用程序需要大量的工程工作——处理 Flask 应用程序以服务于模型;设置复杂的基础设施(如 Docker 和 Kubernetes)以进行适当的扩展;一个完全独立的产品工程工作流,用于集成到现有系统中;和前端开发来构建新的界面。

大多数机器学习从业者要么必须学习这些技能,要么依赖他们的工程合作伙伴的帮助。因此,用机器学习从零到一地解决真正的问题是极其昂贵的;解决这一系列问题的工具是不存在的,或者充其量是粗糙的。

将机器学习产品化很难

将现有模型产品化的步骤| Image credit: BaseTen

通常,将现有模型产品化有三个不同但相互关联的步骤:

  1. 为模特服务
  2. 编写应用程序的业务逻辑,并在 API 背后为其服务
  3. 构建与上述 API 交互的用户界面

如今,前两步需要开发运维与后端工程技能的结合(例如,“Dockerizing”代码、在需要时运行 Kubernetes 集群、建立 web 服务……)。最后一步——构建一个最终用户可以实际交互的界面——需要前端工程技能。必要技能的范围意味着反馈回路几乎不可能建立,并且将机器学习应用到可用产品中需要太多时间。

简化流程

我们的团队作为数据科学家和工程师亲身经历了这种痛苦;所以,我们建造了 BaseTen

BaseTen 是一个应用构建器,允许用户部署机器学习模型,服务 API,构建前端 UI,而不必担心基础设施,部署或学习反应。

在本帖中,我们将通过一个常见的用例来介绍 BaseTen 的主要构建模块:

作为一名数据科学家,我经常想把我的模型从笔记本电脑中拿出来,交给其他利益相关者或朋友,这样他们就可以用动态输入来玩模型了。这一点很重要,因为如果没有用不同的输入来查询模型以查看输出如何变化的第一手经验,就很难衡量模型是如何工作的。

为了这个演示的目的,我们将使用众所周知的神经风格转移模型,我们将最终得到一个可以与外部观众共享的可用应用程序。

1。部署模型

如上所述,第一步是部署模型。BaseTen 允许通过从命令行工具(使用 pip 安装)调用baseten.deploy来部署 scikit-learn、Tensorflow 和 PyTorch 模型。如果模型更加定制,可以上传一个定制模型,只需要一个loadpredict方法(这里有一个例子)。或者,可以从模型动物园部署预先训练的模型。

在下面的例子中,我们部署了来自 TensorFlow Hub 的深度学习模型,该模型以另一幅图像的风格组成一幅图像。

BaseTen 客户端支持单行模型部署。|图片来源:BaseTen

一旦模型被部署,转到模型管理页面来查看关于模型的可编辑元数据,它的部署状态,版本,以及如何从其他服务调用它。

2。用预处理和后处理代码包装模型,并在一个 API 后面提供它

通常,服务模型需要的不仅仅是将其称为 API。例如,可能有预处理和/或后处理步骤,或者可能需要在模型被调用后执行业务逻辑。

要做到这一点,用户可以用 BaseTen 编写 Python 代码,它将被包装在一个 API 中提供服务——无需担心 Kubernetes、Docker 和 Flask。Python 环境可以完全定制(例如安装 pip 包),并且包括 Postgres 数据存储。

所有这些都被包装在一个工作包中,在 BaseTen 中描述为一个由不同类型的节点组成的推理图。 Worklets 允许用户根据应用程序的业务逻辑和整体工作流程进行思考。在创建了一个 worklet 之后,可以通过一个自动生成的 API 端点、一个 cron 作业或者通过将它连接到一个流数据源来调用它。

使用“工作件”为模型提供丰富的 API

在第一个 worklet 示例中,我们添加了预处理代码来从请求中提取模型输入,称为模型,然后将模型输出转换成我们期望的格式。在这种情况下,请求包含要传输的样式和将由模型修改的图像的源。后处理步骤只是将一些元数据添加到模型生成的图像中。

3。构建 UI(当你不是前端工程师时)

当我们自己训练机器学习模型时,我们经常希望构建有状态的用户界面,或者利用我们的模型,或者根据我们的模型的输出进行操作。在 BaseTen 中,这些被称为视图

使用 BaseTen 中的拖放 UI,很容易添加和排列组件来构建视图,包括文本输入、文件选择器、表单、表格、PDF 查看器和数据可视化。BaseTen 还包括许多实用程序,可以轻松地收集和显示数据,对用户输入做出反应,并调用内部和外部 API。视图可以相互链接以构建多页面应用程序。与基于笔记本的应用构建器不同,用户状态是一个一级概念。这意味着 BaseTen 可以为复杂的人在回路应用提供动力。最后,视图可以公开共享或嵌入,并在需要时支持基于角色的访问控制。

在下面这个简单的例子中,我们构建了一个视图来与上面构建的部署模型和 API 进行交互。最终用户可以提供样式和内容图像的 URL,查看预览,单击按钮,并查看结果图像,将第一个图像的样式与第二个图像的内容相结合。

在 BaseTen 视图中运行风格转换模型| Image credit: BaseTen

虽然这个用例非常简单,但是在不到五分钟的时间里,我们就能够为样式转换模型部署一个活动的 API,并创建一个用户界面来测试这个模型。使用相同的构建模块,早期用户已经为用户建立了交互式工具,以提供对模型预测的反馈,内置学习的数据标签应用程序,以及人在回路中的决策流程。

用你自己的模型开始建造

数据科学家和机器学习工程师应该能够以真实产品的形式表达他们模型的力量,同时避免部署问题和不得不将 API 和接口拼凑在一起。

我们很高兴向早期用户开放对 BaseTen 的免费访问,以帮助塑造我们的产品路线图。我们希望从您那里得到的只是您的反馈。我们迫不及待地想看看你会做什么。

构建人工智能系统的弹性

原文:https://towardsdatascience.com/building-for-resiliency-in-ai-systems-24eed076d3d6?source=collection_archive---------23-----------------------

照片由 Karim MANJRA 在 Unsplash 上拍摄

到目前为止,我们已经遇到了大量人工智能系统的失败,在报告和研究工作中一次又一次地普及,我希望我不需要证明我们需要将弹性视为构建道德、安全和包容的人工智能系统的积极组成部分。

(如果你不相信,看一看人工智能伦理报告的状态:第 4 卷展示了其中的一些内容!)

但是,这里的关键问题是,当我们想要建立这样的弹性系统时,我们应该考虑什么?我建议将以下几点作为构建更具弹性的人工智能系统的关键考虑因素:

  1. 对立的例子
  2. 系统的临界性
  3. 故障转移机制
  4. “意大利面条”因素

我向阅读本文的人推荐的关键要点是:弹性是整个系统的属性,因此构建弹性的方法应该采用系统级的方法。

1.对立的例子

没有对对立例子的讨论,关于人工智能系统的健壮性和弹性的讨论就不完整。这些是对人工智能系统的精心制作的输入,旨在触发人工智能系统对其他不受欢迎的行为的错误分类。在这个领域有很多研究,特别是 NSCAI 也把它作为他们以负责任的方式部署人工智能系统的建议的重要部分。虽然对对立例子的全面讨论超出了本文的范围,但我鼓励你在设计你的 AI 系统时把它们放在最前面。特别是,我鼓励你跟上该领域的最新文献,并进行一个简单的练习:我对这个人工智能系统的输入可能产生的最坏结果是什么?你从它那里得到的答案是可能的,并通过训练生命周期中更强大的防御来防止触发这些行为,更好的模型选择,以及应用下面提到的一些要点,将有助于向更具弹性的人工智能系统迈进。

2.系统的临界性

我们建造的一些东西最终比其他的更重要。想想管理客户支付历史数据和在你的网络应用中添加表情符号功能。然而,更严重的是,有许多系统对于向客户和用户提供服务至关重要,它们几乎没有停机时间或性能下降的余地。

这种系统需要特别小心对待,本文提出的建议应该优先考虑立即或最坏情况下的近期应用,而不是推迟应用。虽然看起来很明显,但这一直以技术债务积累的形式发生,技术债务也有不同的形式。我们在关键系统中讨论的那种是最糟糕的,因为如果长时间不处理,它会非常严重。

与团队中的其他工程师和利益相关者合作,对系统的关键程度有所了解,这对于在产品路线图上正确地对这些度量进行优先级排序是至关重要的。

3.故障转移机制

系统会失灵!

是的,再读一遍——系统会失败!这并不是对你所拥有的软件开发人员、数据科学家和机器学习工程师的质量的控诉。这只是这些系统所呈现的复杂程度的一个函数,提出了不可预见的挑战。为系统故障做计划是比希望它们不会发生更好的方法。任何人告诉你,否则要么没有真正的经验建设系统,或试图欺骗你,卖给你的东西将是过度承诺和交付不足。你已经被警告了!

正如我最喜欢的一句名言所说:“希望不是策略。”——本·斯洛斯,SRE,谷歌。

那么,既然我们已经解决了这个问题,那么通过使用故障转移机制来建立弹性的最佳方法是什么呢?首先,故障转移机制是一种替代途径,在通常执行系统的模块或子系统由于某种原因失败的情况下,它将接管系统的主要功能的性能。故障转移机制的目标是为员工提供一个喘息的机会来找出问题所在,并给他们足够的时间来修复原来的子系统。与此同时,系统的客户和用户有望只看到服务质量的最低限度的中断。

在构建道德、安全和包容的人工智能系统的情况下,我们有机会使用这些机制来保证服务,特别是那些真正依赖系统的服务,在出现问题时继续存在。此外,当表现不良的系统需要离线时,更简单、确定性的故障转移机制可以接管以继续提供服务,而不会因为表现不良的系统而进一步恶化客户和用户的体验。

4.“意大利面条”因素

哦耶!嗯,这里会有一些关于食物的讨论,鉴于我们在软件开发中接触到食物的所有隐喻,我想为什么不使用其中一个来描述我们在复杂的人工智能系统中经常面临的问题。

“意大利面条”因素指的是当您的代码交错通过许多不同的系统时出现的问题,既有间接通过 API 调用(希望是松散解耦的!)并直接通过与上游数据处理元件交互。在这些管道中,系统的下游功能变得高度依赖于上游服务的正常运行,这使得平稳运行成为一个挑战。这将严重影响系统的弹性,因为对上游代码的微小更新会对下游的其他代码造成严重破坏。遵循一些好的架构设计模式和坚实的原则实际上可以让你走得更远!

更重要的是,在设计系统时,一定要列出尽可能多的间接和直接的依赖关系,以全面了解情况,既要考虑什么会影响系统的“智能”组件,也要考虑它会如何影响系统的其余部分。

有关如何构建道德、安全和包容的人工智能系统的更多见解,请订阅来自蒙特利尔人工智能伦理研究所 人工智能伦理简介

建造重型集装箱

原文:https://towardsdatascience.com/building-heavy-duty-containers-204354a67036?source=collection_archive---------31-----------------------

重新启动标志、初始化和管理进程

帕特·惠伦Unsplash 拍摄的照片

有些情况下,软件在极少数情况下会失败,这种情况本质上是暂时的。虽然知道这些情况何时出现很重要,但通常至少尽快恢复服务也同样重要。

当容器中的所有进程都已退出时,该容器将进入 exited 状态。Docker 容器可以处于以下四种状态之一:

  • 运转
  • 暂停
  • 重新启动
  • Exited(如果容器从未启动过,也可以使用)

从临时故障中恢复的一个基本策略是,当一个进程退出或失败时,它将自动重新启动。Docker 提供了一些监控和重启容器的选项。

自动重启容器

Docker 通过重启策略提供了对这一特性的支持。在创建容器时使用—- restart标志,您可以告诉 Docker 执行以下任一操作:

  • 从不重启(默认)
  • 检测到故障时尝试重启
  • 当检测到故障时,尝试重新启动一段预定时间
  • 无论情况如何,都要重启容器

Docker 并不总是试图立即重启容器。如果是这样的话,它将引发更多的问题,而不是解决问题。想象一个容器,它什么也不做,只是打印时间,然后退出。如果容器被配置为总是重启,而 Docker 总是立即重启,那么系统不会执行任何操作,只会重启容器。相反,Docker 使用指数补偿策略来计时重启尝试。

退避策略决定了连续重启尝试之间应该经过多长时间。指数退避策略将使等待每次连续尝试的时间加倍。例如,如果容器第一次需要重新启动,Docker 等待 1 秒,然后在第二次尝试时,它将等待 2 秒,第三次尝试将等待 4 秒,第四次将等待 8 秒,以此类推。初始等待时间较短的指数退避策略是一种常见的服务恢复技术。您可以看到 Docker 本身采用了这种策略,构建了一个总是重启并只打印时间的容器

docker run -d —-name backoff-sample --restart always busybox date

几秒钟后,查看日志,观察它的后退和重启

docker logs -f backoff-sample

您可能不希望直接采用该特性的唯一原因是容器在回退期间没有运行。等待重新启动的容器处于重新启动状态。为了进行演示,请尝试在回退示例容器中运行另一个进程

docker exec backoff-sample echo testing

运行该命令应该会导致一条错误消息

Error response from daemon: Container 4affc02f445dd426c0b7daf79efc31f83b1e6e3c7397323bd235a8cd80453bb1 is restarting, wait until the container is running

这意味着您不能执行任何需要容器运行的操作,例如在容器中执行其他命令。如果您需要在损坏的容器中运行诊断,这可能是一个问题。更完整的策略是使用运行 init 或 supervisor 进程的容器。

管理程序和启动程序

管理程序或初始化程序是用于启动和保持其他程序状态的程序。在 Linux 系统上,PID#1 是一个初始化过程。它启动所有其他系统进程,并在它们意外失败时重新启动它们。使用类似的模式来启动和管理容器中的流程是一种常见的做法。

如果目标进程(比如 web 服务器)失败并重启,在容器内部使用一个监管器将保持容器运行。容器中可以使用几个程序。最受欢迎的包括 init、systemd、runit、upstart 和 supervisord。

DockerHub 中有许多 Docker 映像,它们在一个容器中生成一个完整的 LAMP (Linux、Apache、MySQL PHP)堆栈。以这种方式创建的容器使用 supervisord 来确保所有相关的进程保持运行。启动一个示例容器

docker run -d -p 80:80 --name lamp-test mattrayner/lamp

您可以通过使用docker top命令来查看这个容器中正在运行的进程

docker top lamp-testPID                 USER                TIME                COMMAND5833                root                0:00                {supervisord} /usr/bin/python3 /usr/local/bin/supervisord -n6462                root                0:00                apache2 -D FOREGROUND6463                root                0:00                {pidproxy} /usr/bin/python3 /usr/local/bin/pidproxy /var/run/mysqld/mysqld.pid /usr/bin/mysqld_safe6464                1000                0:00                apache2 -D FOREGROUND6465                1000                0:00                apache2 -D FOREGROUND6466                1000                0:00                apache2 -D FOREGROUND6467                1000                0:00                apache2 -D FOREGROUND6468                1000                0:00                apache2 -D FOREGROUND6469                root                0:00                {mysqld_safe} /bin/sh /usr/bin/mysqld_safe6874                1000                0:00                /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=www-data --log-error=/var/log/mysql/error.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/run/mysqld/mysqld.sock --port=3306 --log-syslog=1 --log-syslog-facility=daemon --log-syslog-tag=

top 子命令将显示容器中每个进程的主机 PID。你会在运行程序列表中看到 supervisord,mysql,apache。现在容器正在运行,您可以通过手动停止容器中的一个进程来测试 supervisord 重启功能。

首先,让我们得到每个进程的 PID

docker exec lamp-test psPID TTY          TIME CMD1 ?        00:00:00 supervisord503 ?        00:00:00 apache2504 ?        00:00:00 pidproxy510 ?        00:00:00 mysqld_safe943 ?        00:00:00 ps

让我们终止apache2进程

docker exec lamp-test kill 503

运行这个命令将运行 lamp-test 容器中的 Linux kill 程序,并告诉 apache2 进程关闭。当 apache2 停止时,supervisord 进程将记录该事件并重新启动该进程。容器日志将清楚地显示这些事件:

docker logs lamp-testUpdating for PHP 7.4---------2021-02-16 12:58:42,878 INFO supervisord started with pid 1**2021-02-16 12:58:43,882 INFO spawned: 'apache2' with pid 503**2021-02-16 12:58:43,885 INFO spawned: 'mysqld' with pid 5042021-02-16 12:58:45,332 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)2021-02-16 12:58:45,332 INFO success: mysqld entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)**2021-02-16 13:08:42,334 INFO exited: apache2 (exit status 0; expected)****2021-02-16 13:08:43,345 INFO spawned: 'apache2' with pid 956****2021-02-16 13:08:44,385 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)**

使用 init 或 supervisor 程序的一个常见替代方法是使用启动脚本,该脚本至少检查成功启动所包含软件的先决条件。这些有时被用作容器的默认命令。Docker 容器在执行命令之前运行一个叫做入口点的东西。入口点是放置验证容器先决条件的代码的理想位置。

启动脚本是构建持久容器的重要组成部分,并且总是可以与 Docker 重启策略相结合,以利用各自的优势。

竣工清理

易于清理是使用容器和 Docker 的最重要的原因之一。容器提供的隔离简化了停止进程和删除文件所需的所有步骤。使用 Docker,整个清理过程被简化为几个简单命令中的一个。在任何清理任务中,您必须首先确定要停止和/或删除哪个容器。

让我们先列出所有的集装箱

docker ps -a

由于不再使用为本文中的示例创建的容器,您应该能够安全地停止和删除所有列出的容器。如果您为您的活动创建了一个容器,请确保注意要清理的容器。

所有容器都使用硬盘空间来存储日志、容器元数据和已写入容器文件系统的文件。所有容器还消耗全局名称空间中的资源,例如容器名称和主机端口映射。在大多数情况下,不再使用的容器应该被删除。

让我们删除lamp-test容器:

docker rm -f lamp-test

由于这个容器正在运行,如果我们试图运行没有-f标志的前一个命令,Docker 将抛出一个错误。码头集装箱需要停止之前,试图删除它们。您可以通过运行docker stop命令来实现,或者不运行两个命令,而是在 remove 命令中添加 force 标志。

从源代码构建 Keras:后续指南

原文:https://towardsdatascience.com/building-keras-from-source-a-follow-along-guide-2bcc4cea3aec?source=collection_archive---------20-----------------------

构建 Keras 的分步指南。

照片由劳拉·奥克

前奏:

Keras 最近通过将代码库托管在一个单独的存储库中,朝着改善开发者体验迈出了一大步。正如在 RFC 中提到的,主要目标之一是消除由于核心 TensorFlow 库的长构建时间而导致的冗长反馈循环。由于这一变化,现在可以在非常可行的时间内运行测试。

这篇博文旨在成为 Keras 构建和测试过程的实践指南。让我们开始吧!

从源构建:

对于这里所有的新手,我想花点时间解释一下“从源代码构建”到底是什么意思。这可能意味着很多事情(在这里最好的解释是这里是),但是在我们的例子中,它意味着以下内容:

将源代码编译成可安装包,并将所有模块链接到各自的端点。[1]"

注意,即使在这次迁移之后,仍然可以通过调用from tensorflow import keras来访问 Keras。这是由黄金 API 实现的。这些是 Keras 库为 TensorFlow 库提供的端点。因此,即使 Keras 是单独开发的,对于用户来说,它仍然停留在tf.keras。你可以在这篇帖子中了解到这一点。实现这一点的代码可在这里获得。

我假设您是在 Linux 机器上这样做的。额外的好处是,这可以与支持 TPU 的云虚拟机完美配合。

以下所有命令都是直接采用或受官方 Keras 贡献的指南的启发。请在打开 PR 之前进行同样的操作。

我还创建了一个 Colab 笔记本,你可以用它来轻松地构建和测试代码!

第 1 部分:设置环境

就像 TensorFlow 一样,Keras 使用了Bazel【2】,一个基于图形的构建管理系统。这意味着您可以构建一次 Keras,后续的构建将重用自上一次构建以来没有更改的部分。因此,重建所需的时间大大减少。下面是我们设置环境的方法:

安装巴泽尔。

接下来,我们建立一个虚拟 python 环境。如果您在开发机器上工作,建议这样做。在 Colab 中,在基础环境中重新安装 Keras 就可以了。

设置虚拟环境。

接下来,我们克隆我们的开发分支。我们还安装了 TensorFlow 的夜间版本,这确保了我们与主 TensorFlow repo 保持同步。

克隆存储库并更新环境。

第 2 部分:更新 golden APIs(如果有的话)

需要更新的文件的文件结构。

这部分仅适用于您添加了一些新文件的情况。您需要在以下文件中添加它们的名称。这确保您的模块将被构建,并在以后可供用户访问。

第 3 部分:构建和安装

现在是过程的关键。在这里,我们构建并安装我们的 Keras 版本。为此,请使用以下命令:

使用 Bazel 构建。

执行上述命令后,Keras 将根据您的更改重新安装。

如果你只想进行测试,那么你可以用bazel test代替bazel build。在这种情况下,您可以修改代码并再次运行bazel test。您不需要像我们使用bazel build那样手动安装软件包。

示例:

bazel test keras/layers/convolutional_test

在这里,您可以运行任意多的测试。您可以使用以下命令运行所有测试:

bazel test — test_timeout 300,450,1200,3600 — test_output=errors — keep_going — define=use_fast_cpp_protos=false — build_tests_only — build_tag_filters=-no_oss — test_tag_filters=-no_oss keras/…

常见错误:

ERROR: /home/jupyter/.cache/bazel/_bazel_jupyter/ebc81b3ee71ff9bb69270887ebdc0d7b/external/bazel_skylib/lib/unittest.bzl:203:27: name ‘analysis_test_transition’ is not defined# OR ERROR: error loading package ‘’: Extension ‘lib/unittest.bzl’ has errors
ERROR: error loading package ‘’: Extension ‘lib/unittest.bzl’ has errors
INFO: Elapsed time: 3.557s
INFO: 0 processes.
FAILED: Build did NOT complete successfully (0 packages loaded)

重新启动虚拟机。这种情况发生在安装之后,因为 path 不会在整个系统中更新。

ImportError: cannot import name ‘saved_metadata_pb2’ from ‘keras.protobuf’ (unknown location)

请更改目录,然后重试。这是由于本地和全球环境的混合造成的。

承认

我感谢 TPU 研究云(TRC)[3]对这个项目的支持。TRC 在该项目期间允许 TPU 进入。谷歌通过提供谷歌云信用来支持这项工作。感谢 Keras 团队的 Scott Zhu 在整个过程中对我的指导。

离别的思绪

Keras 是一个用于深度学习的通用而灵活的库。它被成千上万的开发者使用,是一个巨大的开源项目。如果你发现了一个 bug 或者想要在 Keras 中实现一个特性,自己动手吧!没有什么比看着自己的代码被无数人使用更令人高兴的了。随着能够轻松构建 Keras,每个人都有能力改进代码库,让 Keras 成为更好的产品。

参考

【1】Greg Mattes 关于 StackOverflow 的回答()https://stack overflow . com/questions/1622506/programming-definitions-what-just-is-building)

[2]“Bazel——一个快速、可伸缩、多语言和可扩展的构建系统”(https://bazel.build/)

[3] TPU 研究云(https://sites.research.google/trc/about/)

建立基于 LSTM 的太阳能预测模型

原文:https://towardsdatascience.com/building-lstm-based-model-for-solar-energy-forecasting-8010052f0f5a?source=collection_archive---------16-----------------------

处理 LSTM 的一些设计问题

图片来源:https://unsplash.com/photos/mG8sgwkMhCY

太阳能是清洁和可再生能源替代来源的最重要组成部分之一。太阳能发电的预测对于下游应用和与传统电网的整合至关重要。不是测量太阳能电池的光电输出,而是经常估计从太阳接收的辐射作为太阳能发电的替代。用于测量的量称为总水平辐照度(GHI ),它包括直接辐射和散射辐射。

预测的方法可以大致分为以下几种

图 1:预测模型的类型 a)基于方法 b)基于预测窗口 c)基于变量数量。(图片来源:作者)

不同的模型是物理模型(NWP)、统计模型(ARIMA、GARCH)、机器学习模型(随机森林、Boosting)和基于深度学习的模型(RNN、LSTM、GRU)。基于预测窗口,如果少于 30 分钟,则是非常短期的预测,如果多于 30 分钟,则是短期的预测。短期预测现在更适合印度的情况。如果你想开始了解 LSTM,你应该浏览阅读量最大的博客

而我们希望基于理解复杂和非线性模式的能力来使用 LSTM。我们浏览了很多博客和论文,有一些事情我们不确定。我们计划系统地检查它们。这些数据来自 2016 年,分别与 Chennai、Howrah 和 Ajmer 的三个太阳能发电站有关。对于每个站点,我们从两个季节获取数据,即雨季(由于云层覆盖,最不稳定)和冬季(最不稳定)。还需要指出的是,我们分别讨论了“湿热”和“干热”气候带。对于每个问题,都进行了实验并分析了结果。如下图所示,LSTM 类型用三维形状对数据进行建模。

图 2a:LSTM 型模型的输入数据形状。(图片来源:作者)

数字输入特性:这简单地告诉我们,有多少变量用于预测。除了使用过去的 GHI 值,我们还可以使用其他气象变量,如温度、湿度等。

时间步数:这通常被称为输入窗口大小,即我们用于预测的序列的过去值的数量。例如,如果我们打算预测上午 10:00 的值,我们可以考虑上午 09:55、09:50、09:45、09:40 以及 09: 35 和 09: 30 的值。在这种情况下,窗口大小为 6。

批量:我们知道,对于所有的 ML/DL 模型,我们都试图使用梯度下降法找到模型的最佳参数。我们还知道,与其在整个训练数据上寻找梯度,不如在较小的批次上寻找梯度通常更有效。批处理大小参数负责处理这个问题。

还有一个输出窗口大小的概念,它基于我们是只对下一个观察感兴趣还是对几个后续观察感兴趣。这显示在下图中。如果只有一个观察,我们将有一个单一的输出节点,否则超过一个输出节点。

图 2b:具有输出窗口的 LSTM 网络

D 设计问题 1:LSTM 的好处之一似乎是不需要时间序列相关的预处理,如去除趋势和季节性,然而研究界似乎正在应用预处理。所以我们想研究是否需要预处理。

实验装置很简单。我们通过应用 a)无预处理和 b)有预处理(去除季节性,数据中没有趋势)来比较性能。结果如下图所示。

图 3:用原始数据和预处理数据比较模型(图片来源:作者)

很明显,LSTM 在原始时间序列上的训练给出了更好的结果。性能是根据标准化 RMSE 和解释方差得分来衡量的,它们是时间序列预测任务的标准度量。

设计问题 2:许多从业者似乎也在非时间序列设置中使用 LSTM,也就是说,他们使用感兴趣变量的先前值,但将它们视为不同的自变量。有意义吗?

实验装置简单而琐碎。在设置 1 中,数据形状为(72,1,30),30 个特征,窗口大小为 1。在设置 2 中,数据形状取为(72,30,1),一个特征,窗口大小为 30。

图 4:基于非时间序列和时间序列设置的模型比较(图片来源:作者)

看到相当多的博客和研究论文将时间步长作为独立的特征,我们真的很困惑,幸运的是,结果显示时间序列设置的结果要好得多。

D 设计问题 3:一个普遍的直觉是,当我们增加节点或层时,性能应该总是增加的。但是随之而来的是训练时间以及对训练数据的需求的增加。问题是这种直觉有多真实,在哪里停止?

这里,我们使用了一个非常简单的想法。如果给他们更难的问题,任何学习者都需要学得更多。根据同样的类比,如果数据更难处理,任何网络都将需要更大的容量(在层、节点等方面)。一个明显的后续问题是,我们如何衡量这一点?我们认为输入数据显示的可变性越大,预测就越困难。因此,我们首先测量每个站点的 GHI 的可变性,然后针对不同数量的节点进行训练和评估。结果如下所示。

图 5:我们应该继续增加网络的复杂性吗

对于变化率在 50 左右或小于 50 的站点-季节组合,我们需要尽可能多的节点,当变化率超过这个范围时,我们需要大约 100 个节点来达到最佳预测。下图是上表的复制。

图 6:节点数量和性能

结论:

LSTM 可以是一个很好的太阳预测模型,建议使用原始时间序列,它们应该被视为时间序列数据,而不是将每个时间步长视为一个单独的属性。更多的节点不一定意味着最好的性能,更复杂的场景将需要更复杂的结构,并且对于简单和复杂的场景,在一定数量的节点之后,学习饱和(可能过度适应)

致谢:

这是 Sourav Malakar 作为加尔各答大学数据科学实验室(由 A . k . choudh URY IT 学院和统计系设立)的博士学者的工作成果。与 Amlan Chakrabarti 教授和 Bhaswati Ganguli 教授的多轮讨论帮助很大。我们也感谢国家风能研究所(NIWE)的领域知识,最后但并非最不重要的是 LISA(https://sites.google.com/site/lisa2020network/about跨学科统计分析实验室)项目,该项目实际上使团队更具凝聚力。rested 的读者可以在这里阅读发表在 Springer Nature Applied Science上的完整文章。

使用 KNIME 中的树集成学习器构建用于领导决策的机器学习模型

原文:https://towardsdatascience.com/building-machine-learning-model-for-lead-decision-using-tree-ensemble-learner-in-knime-1217bb17ffcc?source=collection_archive---------25-----------------------

为 KNIME 平台中的销售线索决策构建基于分类的预测模型的实用指南

作者图片

有机会在线索生成领域利用机器学习算法,我遇到了设计和实现各种线索评分和线索决策预测模型的可能性。之前,在讨论将基于 Python 的 Scikit-learn 模型集成到微软。NET 生态系统,我还介绍了这种线索评分解决方案的概念、潜力和好处。在参考文章的“进一步应用”一节中,我还提到了使用基于分类的算法开发销售线索决策集成模块。假设集成方法遵循已经描述的步骤,在本文中,我将更多地关注由 KNIME 平台支持的 lead decision 模型设计。因此,我将强调构建系统方法,包括导入、标准化、准备和应用数据以训练、测试、评估和优化决策模型的核心节点。

*注意:本文中介绍的解决方案设计仅用于演示目的——简化到强调核心基础和构建模块的程度,但它也完全适用于在真实测试或生产部署系统中构建和导出基于预测决策的模型。

**注意:我不打算详细介绍树集成机器学习算法的本质或工作方式,以及与其配置参数相关的实际意义和各种可能性。深入了解每个配置属性的过程和详细说明是不同的综合性主题,需要特别注意和描述。更多信息可以在文章中提到的参考文献和文档中找到,也可以在官方图书馆的文档中找到。

什么是领导决策?

Lead Decision 遵循我在上一篇文章中定义的几乎相同的定义结构。唯一的区别只是向公司的销售线索数据库分配具体决策的技术,以指导营销和销售团队向最终客户转化。这种差异直接源于处理模型输出的技术方法,直接分配决策(不包括相关概率的计算)。虽然这看起来像是一个更一般化的方案,但它被认为是一个全面而有益的调整战略和提高营销和销售团队绩效和效率的过程

导入数据

正如在构建线索评分原型的参考文章中提到的,我还使用了 Kaggle 上公开的相同的数据集。考虑到初始数据概述、探索性数据分析(EDA)的过程和数据预处理超出了本文的范围,我将直接介绍经过处理的数据结构概述,并将其导入到 KNIME 平台。在这方面,我使用了Jupyter Notebook environmentNumPypandas 等数据分析和辩论库的优势,其次是 Matplotlibseaborn 等统计数据可视化库的支持。

生成的数据集维度、属性及其在本地系统路径上的存储过程如下所示(数据文件以逗号分隔值格式保存)。

作者图片

在这个场景中,我不会考虑应用额外的特性工程和维度缩减,而是将所有特性(作为数据分析和处理的结果而检索到的)直接导入到 KNIME 平台中。

作者图片

数据过滤和标准化

考虑到数据最初是在 Jupyter Notebook workspace 中探索和处理的,我将继续解释过滤和标准化数据模块的设计,如下图所示。

作者图片

我使用用于手动配置的列过滤器设置数据过滤,它提供了删除一个额外的自动生成的存储记录的增量 id 值的列的功能。该节点还可以用于数据预处理过程中更高级的过滤场景,支持通配符和类型选择过滤模式。

作者图片

在数据过滤过程之后,我添加了标准的混洗节点操作器,用于实现随机记录顺序(应用默认配置)。随后结合规格化器节点,用于基于高斯(0,1)分布使用 Z 分数线性规格化规格化数字特征(在本例中为‘总访问量’‘网站总花费时间’‘每次访问的页面浏览量’)。

作者图片

更进一步,我还将标准化数据的输出连接到 Cronbach Alpha 节点中,用于比较各个列的方差和所有列之和的方差。一般来说,它代表一个可靠性系数,分别作为内部一致性和特征相关性的度量。系数的解释超出了本文的范围。

我将使用字符串节点的编号来结束此模块,以便将目标属性‘已转换’类型转换为字符串(以下模块需要该格式来准备数据和构建机器学习模型)。

作者图片

数据划分

该模块代表实际建模程序之前的阶段。因此,我使用分割节点和两对表格视图节点将数据分割成训练和测试子集——这是继续使用监督机器学习方法的先决条件。

作者图片

我想提一下,我决定相对分割数据集,将 70%的数据分配给作为训练数据,30%作为测试数据,并配置它使用明确指定的随机种子随机抽取。这个过程有助于在多个不同的流执行中保持执行结果的一致性。在这种情况下,它可以确保数据集总是被完全相同地划分。插入表视图只是为了将数据传输到后面的模块,并改进流结构和可读性。

作者图片

模型建立和优化

通常,我决定使用树集成学习器树集成预测器节点来实现监督机器学习模型。根据简介中引用的文章,构建线索决策系统意味着实施机器学习算法进行分类,而不是基于线索评分和逻辑回归的解决方案。由于我也提到了随机森林分类器,我想强调的是,系综树学习器代表了一个决策树系综(就像随机森林变量的情况一样)。KNIME 中还有随机森林学习器随机森林预测器节点。尽管如此,我还是选择了系综树实现,因为结果解释过程中需要丰富的配置可能性和简化的属性统计——结果解释(特性重要性)超出了本文的范围。树集合节点被提供超参数优化/调整参数优化循环开始参数优化循环结束节点所包围——执行过程如下图所示。

作者图片

参数优化循环开始节点基于先前提供的配置开始参数优化循环。在这方面,它利用了 KNIME 中的流变量的概念,确保每个参数值将作为特定的流变量传递。我使用标准设置方法将‘模型数量’、【最大级别】、【最小节点大小】配置为树集成算法参数。利用值区间和步长,该循环提供了不同分类模型的构建和评估。

作者图片

同时,参数优化循环结束节点从流变量收集目标函数值,并将控制转移回相应的循环周期。它还提供了最佳参数输出端口,我从这里检索最佳参数组合,以获得最大化的配置精度。

作者图片

应通过使用计分器节点来支持这种设计方法,以在先前定义的测试数据集上提供循环结果模型预测。因此,为了实现这个流程,我将系综树预测器节点(默认配置)与评分机制连接起来,并将其包裹在优化循环周围。

不过,值得一提的是树集合学习者节点配置。在属性选择区中,需要配置的一切都是目标列属性,即“已转换”的数据集特性。

作者图片

更进一步,在树选项区域中,我将信息增益比率配置为算法分割标准,用于根据属性拥有的熵来标准化属性的信息增益。

作者图片

在配置窗口的底部可以看到,明确提到【max levels】【minNodeSize】【NR models】由变量控制。这些是作为循环过程结果的输入流变量,我之前解释过了。因此,在这种情况下,每个创建的模型都将经历不同的配置参数——参数调整。考虑到需要显式的流变量匹配,我在流变量屏幕中映射了具体的名称。

作者图片

另一方面,我通过查看集合配置将数据采样设置为随机模式。我配置了 sample(平方根)属性采样,并使用了每个树节点的不同属性集。如前所述,我还分配了一个特定的静态随机种子值。

作者图片

参数优化回路末端节点提供两个输出端口,最佳参数所有参数。我使用所有参数概述来分析基于不同参数组合的销售线索决策分类的性能。这被认为是初步理解模型如何工作的良好实践,以及如何进一步优化它的指标,这些技术超出了本文的范围。

作者图片

在本模块的最后,我使用了表写入器节点来保存本地系统路径上存储的表中的最佳参数记录。

作者图片

作者图片

领导决策模型提取

最后的模块表示使用单独的树集成学习器和预测器节点的优化的机器学习分类器提取。我在这里使用的技术是前一个模块的后续,在那里我存储了从算法优化过程中检索到的最佳参数。通常,我使用表读取器节点从先前定义的系统位置读取表,并利用表行到变量节点的优势将表记录转换为变量格式。因此,变量转换配置,过滤精度值参数,如下图所示。

作者图片

作者图片

按照流变量输入的相同方法,我在树集成学习器上将变量参数配置为树集成算法参数。我必须在这里强调的是在提取最佳性能领导决策模型时,来自构建和优化的训练数据集应该是相同的。这同样适用于测试数据。这是使用在前一模块中解释的特定随机种子值实现的。此外,在树集成学习器的集成配置中配置的静态随机种子也应该在建立和优化以及提取最终模型的模块中被识别。

最后,我插入了一个计分器节点(JavaScript) ,用于分析提取的线索决策模型的性能。在这种情况下,我选择了支持 Java 脚本视图的 scorer 来生成更具洞察力和交互性的摘要。测试数据预测,包括混淆矩阵、类别和总体统计在下面的截图中显示。

作者图片

因此,类 0 代表【未转换】 导联,而类 1 代表【已转换】导联。该列也可以在数据处理过程中作为分类列对齐,这样就可以进行分类描述,而不是处理整数(转换成字符串)。

*注:根据对提取的销售线索决策模型的评估检索结果摘要。额外优化、结果解释和生成特征重要性的过程不属于本主题。但是,考虑到所需的场景目标和达到的 80%以上的总体准确性,这种模型构建结果是令人满意和可接受的。

最后的话

在本文中,我介绍了使用 KNIME 平台开发完整的销售线索决策系统的逐步设计过程。在这种情况下,我讨论了在建立工作基础设施方面实现的核心节点的使用,以便为先前分析和处理的数据提供主要决策。这种方法是最广泛的系统化方法的一部分处理和解释营销和销售数据,以建立更具洞察力和实用性的销售线索挖掘流程

这个解决方案完全是使用 KNIME 设计和开发的,KNIME 是一个开源的数据分析、报告和集成平台,为机器学习提供了一组不同的组件。这是一个令人兴奋的环境,能够建立机器学习模型,同时以非常直观的视觉方式呈现它。除此之外,我认为它是一个快速建模的优秀平台,特别是在有尝试和分析多种不同机器学习算法的特定需求的情况下。同时,没有编码背景的研究人员或专业人员可以非常容易地使用它。它有一个非常简单的界面和集成的文档,用于构建不同的机器学习管道、流程和模型。

— — — — — — — — — — — —

感谢您花时间阅读本文。我相信它很有见地,给了你灵感。

欢迎分享你的想法,我会很感激你的建议和观点。

最初发表于【https://www.linkedin.com】

使用雪花和 Dask 构建机器学习管道

原文:https://towardsdatascience.com/building-machine-learning-pipelines-using-snowflake-and-dask-10ae5e7fff0f?source=collection_archive---------9-----------------------

弗雷德里克·菲利克斯在 Unsplash 上的照片

理解大数据

介绍

最近,作为一名数据科学家,我一直在努力寻找更好的方法来改善我的工作流程。我倾向于在工作中花费大量时间建模和构建 ETL。这意味着我越来越需要依赖工具来可靠、高效地处理大型数据集。我很快意识到,用熊猫来操纵这些数据集并不总是一个好方法,这促使我寻找其他替代方法。

在这篇文章中,我想分享我最近探索的一些工具,并向你展示我如何使用它们,以及它们如何帮助我提高工作流程的效率。我将特别谈到的两个是雪花和 Dask。两个非常不同的工具,但是可以很好地互补,尤其是作为 ML 生命周期的一部分。我希望在读完这篇文章后,你能很好地理解什么是雪花和 Dask,如何有效地使用它们,并且能够使用你自己的用例。

更具体地说,我想向您展示如何使用雪花和 Python 构建 ETL 管道,为机器学习任务生成训练数据。然后,我想介绍 Dask 和 Saturn Cloud ,并向您展示如何利用云中的并行处理来真正加快 ML 培训过程,从而提高您作为数据科学家的工作效率。

用雪花和 Python 构建 ETL

在我们开始编码之前,我最好简单解释一下雪花是什么。这是我最近在我的团队决定开始使用它时问的问题。在高层次上,它是云中的数据仓库。玩了一会儿后,我意识到它有多强大。我认为对我来说,最有用的功能之一是你可以使用的虚拟仓库。虚拟仓库让您可以访问相同的数据,但完全独立于其他虚拟仓库,因此计算资源不会在团队之间共享。事实证明这非常有用,因为它消除了其他用户全天执行查询所导致的任何潜在性能问题。这减少了等待查询运行时的挫败感和时间浪费。

由于我们将使用雪花,我将简要概述如何设置它,并开始自己试验。我们需要做到以下几点:

  • 获得雪花账户设置
  • 把我们的数据变成雪花
  • 使用 SQL 和雪花 UI 编写并测试我们的查询
  • 编写一个 Python 类,它可以执行我们的查询来生成我们的最终数据集用于建模

建立一个账户就像在他们的网站上注册免费试用一样简单。一旦你完成了,你可以在这里下载 snowsql CLI。这将使向雪花添加数据变得简单。按照这些步骤,我们可以尝试使用我们的凭证和命令行连接到雪花。

snowsql -a <account_name> -u <user_name>

登录雪花 UI 可以在网址中找到自己的账户名。它看起来应该是这样的:xxxxx.europe-west2.gcp。好了,让我们进入下一步,将我们的数据放入雪花中。这里我们需要遵循几个步骤,即:

  • 创建我们的虚拟仓库
  • 创建数据库
  • 定义并创建我们的表格
  • 为我们的 CSV 文件创建暂存表
  • 将数据复制到我们的表格中

幸运的是,这并不太难,我们完全可以使用 snowsql CLI 来完成。对于这个项目,我将使用一个比我想要的更小的数据集,但不幸的是,我不能使用我公司的任何数据,而且很难在网上找到合适的大型数据集。不过,我确实从 Dunnhumby 找到了一些交易数据,这些数据可以在 Kaggle 上免费获得。只是为了好玩,我使用这些数据创建了一个更大的合成数据集来测试 Dask 与 sklearn 相比处理挑战的能力。

首先,我们需要在雪花 UI 中使用以下命令建立一个虚拟仓库和一个数据库。

创建
warehouse _ size = " X-SMALL "
auto _ suspend = 180
auto _ resume = true
initially _ suspended = true;

创建 替换 数据库dunhumby;

我们的数据由 6 个 CSV 组成,我们将把它们转换成 6 个表。我不会花太多时间浏览数据集,因为这篇文章更多的是关于使用雪花和 Dask,而不是解释数据。

下面是我们可以用来创建表格的命令。您需要预先知道的是您将使用什么列和数据类型。

**create** **or** **replace** **table** campaign_desc ( 
description **string**, 
campaign number,
start_day number,
end_day number );**create** **or** **replace** **table** campaign_table ( 
description **string**, 
Household_key number, 
campaign number );**create** **or** **replace** **table** coupon ( 
COUPON_UPC number, 
product_id number, 
campaign number );**create** **or** **replace** **table** coupon_redempt ( 
household_key number, 
**day** number, 
coupon_upc number, 
campaign number );**create** **or** **replace** **table** transactions ( 
household_key number, 
BASKET_ID number, 
**day** number, 
product_id number, 
quantity number, 
sales_value number, 
store_id number, 
retail_disc decimal, 
trans_time number, 
week_no number, 
coupon_disc decimal, 
coupon_match_disc decimal );**create** **or** **replace** **table** demographic_data ( 
age_dec **string**, 
marital_status_code **string**, 
income_desc **string**, 
homeowner_desc **string**, 
hh_comp_desc **string**, 
household_size_desc string, 
kid_category_desc **string**, 
Household_key number);

现在我们已经创建了表,我们可以开始考虑如何将数据放入其中。为此,我们需要存放 CSV 文件。这基本上只是一个中间步骤,因此雪花可以直接将文件从我们的阶段加载到我们的表中。我们可以使用 PUT 命令将本地文件放到我们的 stage 中,然后使用 COPY INTO 命令来指示雪花将这些数据放在哪里。

use database dunnhumby;**create** **or** **replace** stage dunnhumby_stage;PUT file://campaigns_table.csv @dunnhumby.public.dunnhumby_stage;PUT file://campaigns_desc.csv @dunnhumby.public.dunnhumby_stage;PUT file://coupon.csv @dunnhumby.public.dunnhumby_stage;PUT file://coupon_d=redempt.csv @dunnhumby.public.dunnhumby_stage; 
PUT file://transaction_data.csv @dunnhumby.public.dunnhumby_stage; 
PUT file://demographics.csv @dunnhumby.public.dunnhumby_stage;

作为快速检查,您可以运行此命令来检查临时区域中有什么。

ls @dunnhumby.public.dunnhumby_stage;

现在我们只需要使用下面的查询将数据复制到我们的表中。您可以在登录 Snowflake 后,在 Snowflake UI 或命令行中执行这些操作。

copy into campaign_table 
from @dunnhumby.public.dunnhumby_stage/campaigns_table.csv.gz 
file_format = ( type = csv
skip_header=1 
error_on_column_count_mismatch = false 
field_optionally_enclosed_by=’”’);copy into campaign_desc 
from @dunnhumby.public.dunnhumby_stage/campaign_desc.csv.gz 
file_format = ( type = csv
skip_header=1 
error_on_column_count_mismatch = false 
field_optionally_enclosed_by=’”’);copy into coupon 
from @dunnhumby.public.dunnhumby_stage/coupon.csv.gz 
file_format = ( type = csv
skip_header=1 
error_on_column_count_mismatch = false 
field_optionally_enclosed_by=’”’);copy into coupon_redempt 
from @dunnhumby.public.dunnhumby_stage/coupon_redempt.csv.gz 
file_format = ( type = csv
skip_header=1 
error_on_column_count_mismatch = false 
field_optionally_enclosed_by=’”’);copy into transactions 
from @dunnhumby.public.dunnhumby_stage/transaction_data.csv.gz 
file_format = ( type = csv
skip_header=1 
error_on_column_count_mismatch = false 
field_optionally_enclosed_by=’”’);copy into demographic_data 
from @dunnhumby.public.dunnhumby_stage/demographics.csv.gz 
file_format = ( type = csv skip_header=1 
error_on_column_count_mismatch = false 
field_optionally_enclosed_by=’”’);

好极了,如果运气好的话,我们第一次尝试就有数据了。哦,要是有那么简单就好了,整个过程我试了几次才弄对(小心拼写错误)。希望你能跟上这一步,做好准备。我们离有趣的东西越来越近了,但是上面的步骤是这个过程中至关重要的一部分,所以要确保你理解了每一个步骤。

用 SQL 编写我们的管道

在下一步中,我们将编写查询来生成我们的目标和功能,然后最终生成一个训练数据集。创建用于建模的数据集的一种方法是将这些数据读入内存,然后使用 pandas 创建新要素并将所有数据框连接在一起。这是你在 Kaggle 和其他在线教程中看到的典型方法。这样做的问题是效率不是很高,尤其是当您处理任何合理大小的数据集时。出于这个原因,将繁重的工作外包给 Snowflake 是一个更好的主意,它可以非常好地处理大量数据集,并可能为您节省大量时间。在这里,我不会花太多时间深入研究我们数据集的细节,因为它对我要展示的内容并不重要。不过,一般来说,在开始建模之前,您会希望花大量的时间来探索和理解您的数据。这些查询的目标是对数据进行预处理,并创建一些简单的特征,我们稍后可以在我们的模型中使用它们。

目标定义

显然,监督机器学习的一个重要组成部分是定义一个合适的预测目标。对于我们的用例,我们将通过计算用户是否在截止周之后的两周内再次访问来预测流失。2 周的选择是相当随意的,将取决于我们试图解决的具体问题,但让我们假设它对这个项目来说是好的。一般来说,你需要仔细分析你的客户,以了解访问间隔的分布情况,从而得出一个合适的客户流失定义。

这里的主要思想是,对于每个表,我们希望每个 household_key 有一行包含我们的每个特性的值。

活动特征

交易特征

下面我们根据总体统计数据创建一些简单的指标,如平均值、最大值和标准差。

人口特征

这个数据集有很多缺失数据,所以我决定在这里使用插补。有大量的技术可以处理缺失数据,从丢弃缺失数据到先进的插补方法。在这里,我让自己的生活变得简单,并用模式替换了缺失的值。我一般不推荐采用这种方法,因为理解为什么数据丢失对于决定如何处理它非常重要,但是对于这个例子来说,我将继续采用简单的方法。我们首先计算每个特征的模式,然后使用 coalesce 在数据丢失时用模式替换每一行。

培训用数据

最后,我们通过将我们的主表连接在一起为我们的训练数据构建一个查询,最终得到一个包含我们的目标、我们的活动、交易和人口统计特征的表,我们可以用它来构建一个模型。

作为一个简短的旁白,对于那些有兴趣了解更多关于雪花的特征和细微差别的人,我推荐以下这本书: 雪花食谱 。我开始读这本书,它充满了关于如何使用雪花的真正有用的信息,并且比我在这里做的更详细。

用于 ETL 的 Python 代码

我们需要这个 ETL 的最后一部分是编写一个脚本来执行它。现在,只有当您计划定期运行这样的 ETL 时,才真正需要这样做,但这是一个很好的实践,并且在需要时运行 ETL 会容易得多。

让我们简单讨论一下 EtlTraining 类的主要组件。我们班有一个输入,就是截止周。这是由于我们的数据集中定义数据的方式,但通常情况下,这将是一种日期格式,对应于我们希望选择的生成训练数据的截止日期。

我们初始化了一个查询列表,这样我们就可以轻松地遍历并执行它们。我们还创建了一个字典,其中包含我们传递给雪花连接的参数。这里我们使用我们在土星云中设置的环境变量。这里的是如何做到这一点的指南。连接到雪花并不太难,我们需要做的就是使用雪花连接器并传入我们的凭证字典。我们在雪花连接方法中实现了这一点,并将该连接作为属性返回。

为了使这些查询更容易运行,我将每个查询作为 python 字符串变量保存在 ml_query_pipeline.py 文件中。execute_etl 方法完全按照它在 tin 上所说的去做。我们遍历每个查询,格式化它,执行它,最后关闭雪花连接。

要运行这个 ETL,我们只需在终端中输入下面的命令。(其中 ml_pipeline 是上面脚本的名称。)

python -m ml_pipeline -w 102 -j ‘train’

简单地说,您可能希望定期运行这样的 ETL。例如,如果您想要进行每日预测,那么您需要每天生成一个这样的数据集,并传递到您的模型中,这样您就可以确定哪些客户可能会流失。我不会在这里详细讨论这个,但是在我的工作中,我们使用气流来编排我们的 ETL,所以如果你感兴趣,我建议你去看看。事实上,我最近买了一本名为《使用 Apache Airflow 的数据管道的书,我认为这本书很棒,它给出了一些关于如何使用 Airflow 的可靠例子和建议。

Dask 和建模

现在我们已经建立了数据管道,我们可以开始考虑建模了。我写这篇文章的另一个主要目的是强调在 ML 开发过程中使用 Dask 的优势,并向你们展示它的易用性。

对于项目的这一部分,我还使用了 Saturn Cloud ,这是我最近遇到的一个非常好的工具,它允许我们在云中的计算机集群上利用 Dask 的能力。对我来说,使用 Saturn 的主要优势是,分享您的工作非常容易,在您需要时扩展您的计算非常简单,并且它有一个免费的层选项。一般来说,模型开发对于 Dask 来说是一个非常好的用例,因为我们通常想要训练一堆不同的模型,看看什么最有效。我们做得越快越好,因为我们有更多的时间关注模型开发的其他重要方面。与雪花类似,你只需要在这里注册,你就可以非常快速地建立一个 Jupyter 实验室的实例,并开始自己进行实验。

现在,我意识到在这一点上我提到过几次 Dask,但从未真正解释过它是什么。所以让我花一点时间给你一个非常高层次的概述 Dask 和为什么我认为它是可怕的。非常简单,Dask 是一个 python 库,它利用并行计算来允许您在非常大的数据集上处理和执行操作。最好的部分是,如果你已经熟悉 Python,那么 Dask 应该非常简单,因为语法非常相似。

下图突出显示了 Dask 的主要组件。

来源: Dask 文件

集合允许我们创建一个可以在多台计算机上执行的任务图。其中一些数据结构可能听起来很熟悉,比如数组和数据框,它们与 python 中的数据结构相似,但有一些重要的区别。例如,您可以将 Dask 数据帧想象为一组 pandas 数据帧,它们的构建方式允许我们并行执行操作。

从集合开始,我们有了调度器。一旦我们创建了任务图,调度程序就会为我们处理剩下的工作。它管理工作流,并将这些任务发送到单台机器或分布到整个集群。希望这能让你对 Dask 的工作原理有一个简单的了解。要了解更多信息,我建议查看一下文档或者这本。两者都是深入探讨这个主题的很好的资源。

用于建模的 Python 代码

建模时,我倾向于先尝试少量的算法。这通常会给我一个好主意,什么可能适合我的具体问题。这些模型是逻辑回归、随机森林和梯度推进。根据我的经验,当处理表格数据时,这些算法通常会给你很好的结果。下面我们用这三个模型建立一个 sklearn 模型管道。我们在这里使用的确切模型并不重要,因为管道应该适用于任何 sklearn 分类模型,这只是我的偏好。

事不宜迟,让我们深入研究代码。幸运的是,我们将大部分预处理外包给了雪花,因此我们不必在这里过多地摆弄我们的训练数据,但我们将使用 sklearn 管道添加一些额外的步骤。

下面的第一段代码展示了使用 sklearn 时的管道。请注意,我们的数据集是一个普通的旧 pandas 数据帧,我们的预处理步骤都是使用 sklearn 方法执行的。这里没有什么特别不寻常的事情。我们从雪花 ETL 生成的表中读入数据,并将其传递给 sklearn 管道。通常的建模步骤在这里适用。我们将数据集分为训练和测试,并做一些预处理,即使用中位数估算缺失值,缩放数据并一次性编码我们的分类数据。我是 sklearn 管道的忠实粉丝,现在每当我开发模型时,基本上都使用它们,它们确实有助于代码简洁明了。

这个管道在大约有 200 万行的数据集上表现如何?在没有任何超参数调整的情况下运行这个模型大约需要 34 分钟。哎哟,有点慢。你可以想象,如果我们想要进行任何类型的超参数调整,这将需要多长时间。好吧,不太理想,但让我们看看 Dask 是如何应对挑战的。

Dask ML Python 代码

我们的目标是看看我们是否能打败上面的 sklearn 管道,剧透一下,我们肯定能。Dask 很酷的一点是,当你已经熟悉 python 时,入门的门槛相当低。我们可以在 Dask 中建立并运行这条管道,只需做一些更改。

你可能会注意到的第一个变化是我们有了一些不同的进口。这条管道与前一条管道的主要区别之一是,我们将使用 Dask 数据框架而不是 pandas 数据框架来训练我们的模型。你可以把 Dask 数据帧想象成一堆熊猫数据帧,我们可以同时对每个数据帧进行计算。这是 Dask 并行性的核心,也是减少该管道培训时间的原因。

注意我们使用 @dask.delayed 作为我们的load _ training _ data函数的装饰器。这指示 Dask 为我们并行这个功能。

我们还将从 Dask 导入一些预处理和管道方法,最重要的是,我们将需要导入 SaturnCluster,这将允许我们创建一个用于训练模型的集群。这段代码的另一个关键区别是,在我们的训练测试分割之后,我们使用了 dask.persist 。在这之前,由于 Dask 的懒惰计算,我们的函数实际上没有被计算过。一旦我们使用了 persist 方法,我们就告诉 Dask 将我们的数据发送给 workers,并执行到目前为止我们已经创建的任务,并将这些对象留在集群上。

最后,我们使用延迟方法训练我们的模型。同样,这使我们能够以一种懒惰的方式创建我们的管道。在我们到达以下代码之前,管道不会被执行:

fit_pipelines = dask.compute(*pipelines_)

这一次,我们只花了大约 10 分钟就在完全相同的数据集上运行了这条管道。这是 3.4 倍的加速,不算太差。现在,如果我们想的话,我们可以通过在土星上按一下按钮来扩大我们的计算资源,从而进一步加快速度。

部署我们的管道

我之前提到过,你可能希望使用类似气流这样的东西,定期运行这样的管道。碰巧的是,如果你不想为气流设置一切的最初麻烦,土星云提供了一个简单的替代工作。作业允许我们打包代码,并定期或根据需要运行它。您只需转到一个现有项目,然后单击 create a job。一旦我们这样做了,它应该看起来如下:

来源:土星

从这里开始,我们需要做的就是确保我们上面的 python 文件在图像中的目录中,并且我们可以输入上面的 python 命令

python -m ml_pipeline -w 102 -j 'train'

如果愿意,我们还可以使用 cron 语法设置一个时间表,每天运行 ETL。对于那些感兴趣的人来说,这里有一个教程,可以深入到所有的细节。

结论和要点

好了,我们现在已经到了项目的尾声。显然,我已经忽略了 ML 开发周期中的一些关键部分,例如超参数调整和部署我们的模型,但也许我会留待以后再说。我觉得你应该试试达斯克吗?我绝不是专家,但就我目前所见,它确实非常有用,作为一名数据科学家,我非常兴奋能够对它进行更多的实验,并找到更多的机会将其融入我的日常工作中。希望您发现这很有用,并且您也可以看到雪花和 Dask 的一些优点,并且您将开始自己尝试它们。

资源

我的其他一些帖子你可能会感兴趣

注意:这篇文章中的一些链接是附属链接。

从数据质量开发平台构建机器学习工作流

原文:https://towardsdatascience.com/building-machine-learning-workflows-from-the-development-platform-for-data-quality-3eed4476b9a2?source=collection_archive---------17-----------------------

直接从 YData 开发平台集成 AzureML Studio 的指南

照片由记者拍摄于 Freepik

数据在开发机器学习管道中具有很高的风险,采用一种获得高质量数据的方法至关重要。有意义的数据不仅稀缺且嘈杂,而且获取成本高昂。

像吴恩达这样的专家认为,机器学习目前达到的门槛只能通过提高数据的质量和数量来突破

随着机器学习变得越来越普遍,人工智能公司显然面临新的挑战,对此,以模型为中心的方法可能没有所有的解决方案。我们 YData 提倡以数据为中心的方法——因为一切都始于数据,也止于数据。

YData 是首个提高数据质量的数据开发平台。它提供的工具不仅可以理解数据质量及其对 ML 模型的影响,还可以提供更高质量的数据准备。我们相信互操作性是优化业务体验的关键——正是出于这一目的,我们将 YData 设计为与许多其他 MLOps 平台高度集成。

微软 Azure 是一个广泛用于各种部署的服务平台,包括在 MLOps 中——它具有成本效益,易于使用,并为任何新手开始部署提供了出色的文档。

我们很高兴分享 YData 和 Azure 之间的新集成!

作者创造的形象

本文将深入探讨我们如何集成这两个强大的机器学习平台,以提高用于训练 ML 模型的数据质量,并使它们能够在部署后提供有价值的见解。

为什么要集成 YData 和 Azure?

我们理解构建最佳性能模型的重要性。我们也意识到高质量的数据对构建这一平台至关重要。许多人忘记的是,在商业环境中,构建解决方案所花费的时间也同样重要。

虽然公司关注数据质量和训练有素的模型,但为数据科学团队提供易于使用的开发平台也至关重要。结合 YData 和 Azure 将提高数据科学团队的生产力,改善 ML 模型提供的价值,并为在生产环境中轻松部署可扩展的解决方案铺平道路。

以下是使用 YData 作为开发平台的一些优势:

简而言之,YData 允许与 Azure(和其他流行的云平台)无缝集成,使公司能够快速、可扩展和良好监控地将其数据优化训练模型部署到生产中。

既然我们已经了解了为什么要进行集成的背景,我们将把重点放在您可以遵循的集成步骤上(剧透:这比您想象的要简单得多。)我们将使用电信客户流失数据集,其中我们的目标是根据历史模式预测客户是否会在短期内流失。

我们鼓励您从我们的 GitHub 资源库中找到这个相关的 Jupyter 笔记本,并继续关注。

设置 AzureML

AzureML 允许为您的部署提供“点击创建”工作区,这将在一个地方存储您的模型、服务端点和用于服务它们的计算实例。

在“类别”中选择人工智能和机器学习,然后单击“创建”获得“机器学习”

AzureML 工作区供应(所有剩余截图由作者提供)

我们使用您的 AzureML 工作区中的 config.json 文件从 YData 连接和操作它。

从 YData 的实验室连接到您的 AzureML 工作区

azureml python SDK 创建了一个 API,它调用函数来远程创建、操作和删除云工作区上的资源。

创建模型

我们选择实现逻辑回归,因为它没有对特征空间中类的分布做任何假设。它可以很容易地扩展到多个类别,如软搅棒、硬搅棒,具有类别预测的自然概率视图。

但是,您可以尝试其他算法,如 XGBoost 和 Random Forests,并检查模型性能。

部署为 Web 服务

AzureML 部署遵循任何容器化部署的标准流程:

  • 定义环境
  • 配置依赖关系
  • 插入代码并部署

评分脚本将模型加载到容器中,也作为要预测的数据样本的加载点。

在 ACI (Azure 容器实例)内部执行预测的代码

部署环境配置是在容器中安装所需的 python 包。

容器——预装了 python 包和要运行的“score.py”代码——现在将在 Azure 上部署和运行。

Azure 容器实例很容易在控制台上部署和监控。

微软 Azure 机器学习工作室端点。

一旦端点被部署并运行,我们就使用测试数据对其进行测试。

根据测试数据进行预测

这个想法是将测试数据集输入到模型中以获得预测。

这里,我们将数据作为 pandas dataframe 发送到 ACI 中托管的 web 服务。然后,我们使用 SDK 的“运行”API 来调用服务。您还可以使用任何 HTTP 工具(如 curl)进行原始调用。

通过 HTTP 请求进行预测

您还可以发送原始 HTTP 请求来测试 web 服务。一个样本代码,其中随机选择一个客户,并预测他们是否会流失。

因此,在部署时,您的模型可以通过发送 HTTP 请求来发送预测。当您的模型集成到需要实时预测的用户友好的 web/移动应用程序中时,这是一个常见的应用程序。

可能性是无限的

数据科学和人工智能超越了任何特定的工具或技术。作为数据科学家,我们应该学会如何利用最好的工具来实现各种目的。学习适应更新的工具并组合它们以充分利用它们是建立高效和多产的数据科学团队的必备技能。

因此,本文展示了如何利用 YData 平台和 Microsoft Azure。

我们从创建 AzureML studio 开始,使用 YData 的数据源连接器加载数据,构建模型,直接从 YData 的实验室设置 azure 环境,部署和服务于实时预测——我们已经完成了所有工作。

虽然这看起来很难理解——但这是再简单不过的了。请参考我们资料库中的本 Jupyter 笔记本了解更多技术细节和代码。通过这种集成,您可以同时拥有 Azure 和 YData 平台的优势。

你知道我们有一个友好的 slack 社区吗?我们的开发人员在那里帮助你从你的人工智能项目中获得最大的利益,并获得你的宝贵反馈。加入我们吧!

构建内存高效的元混合推荐引擎:从后到前(第 1 部分)

原文:https://towardsdatascience.com/building-memory-efficient-meta-hybrid-recommender-engine-back-to-front-part-1-7be279ca92a6?source=collection_archive---------22-----------------------

如何从头开始构建一个推荐器,在保持简单的同时提高其准确性

你会推荐什么?

2020 年至 2021 年的环境使得越来越多的企业主考虑将与客户的主要通信转移到网上。你可能已经注意到,预测、引导和购买的在线活动(甚至是线下活动)的数量最近发生了多么大的变化?似乎任何互联网企业都尽最大努力与客户保持无休止的对话。在这样的对话中,客户期望从卖家那里接收至少相关的个人报价,以便更快地做出选择。

面向客户的个人报价是由所谓的推荐系统(recsys)产生的。Recsys 是机器学习算法的一个子类,用于获得用户可能偏好的物品的排序列表。

整个 recsys 的种类可以分为几类(由 Rocca,2019 ):

图片作者:Baptiste Rocca

在这一系列出版物中,我们将浏览:

  • 基于记忆的推荐系统的机制
  • 构建你自己的基于用户的协同过滤推荐器
  • 应用来自流行 python 模块的“开箱即用”推荐器
  • 评价推荐者效率和准确性的技巧

沿着这条路,我们将分享我们在设计所谓的元混合推荐引擎以解决实际业务问题方面的经验。

推荐引擎是如何工作的?

数据介绍

在该出版物中,我们将使用数据集

除了用户的评级,数据集还包含关于电影本身的描述性信息(如上映年份、类型、内容标签),我们将在第二部分使用这些信息来提高推荐者预测的准确性。

为了理解推荐器是如何工作的,让我们通过几个步骤来创建一个微数据集:

  • 从主数据集中随机选择几个用户
  • 编辑一个电影列表,上面列表中的每部电影都有 3 个或更多的用户看过
  • 从前面的列表中随机选择几部电影
  • 从随机选择的用户和电影的交集上的所有用户-电影对构建评级矩阵。

设计定制推荐引擎

由此产生的评级矩阵代表了 recsys 表现的典型背景:一些用户可以从我们的微库中收到他们以前没有看过的电影的推荐;推荐者必须对个人推荐进行排名,以保持用户对未看过电影的喜爱。

解决这些任务所需的最少信息在评级的微矩阵本身中,即用户与所看电影的交互历史(即除了我们的协同过滤推荐器的“记忆”之外的所有信息)。

基于记忆的推荐器简单地基于由另一组{A…X}用户分配给那个 Z 电影的评级来预测 Y 用户对一部未看过的 Z 电影的评级,所述另一组用户的电影偏好与 Y 用户的相似。

在最简单的情况下,Y-Z 对的评级预测被计算为 Z-movie 的一组可用评级的加权平均值,取决于 Y-user 与每个{A…X}用户的“相似度”。

“相似度”是两个用户的评级向量之间的距离,通过减去平均值来标准化(缩放)。因此,分级评级向量的平均值为零,这允许我们用零安全地填充所有缺失的值(即特定用户对未看过的电影的评级)。

用户评级的标准化向量之间的余弦距离矩阵。

正如所料,矩阵主对角线的所有元素都等于零(用户到自己的距离)。

去掉主对角线后,我们将得到每个用户到系统中所有其他用户的距离向量。此外,在推荐引擎中,这些距离将被转换为“逆”权重,以加权平均值的形式计算评级。

换句话说,我们的定制推荐器迭代地预测每个用户电影对(包括用户未看过的电影!成对)作为特定电影的可用评级的向量和与从特定用户到其评级被考虑的其他用户的距离成反比的权重向量的乘积。

尽管很简单,但我们的定制推荐器可以处理缺少实际用户评级的情况(即评级矩阵中缺少单元)以及用户“相反”电影偏好的情况(即双向分级评级向量)。

我们的客户推荐器的平均绝对百分比误差(MAPE)大约是 15.5%

生产就绪型推荐器

我们已经建立了一个推荐器,它可以预测评分,并可以产生一个排名推荐列表——这太棒了,哇!

然而,我们的“原样”推荐器有相当多的缺点:

  • 它不允许从基于用户的协同过滤切换到基于项目的协同过滤
  • 它不允许在计算向量乘积时微调要考虑的用户数量
  • 它不适用于具有高级预测算法的实验
  • 最后,它需要优化来处理大型数据集

所有这些缺点,对于用 惊喜 这样的 python 模块搭建的推荐器来说,都是无关紧要的。

例如,将来自 surprise 家族(即 [KNNWithMeans](https://surprise.readthedocs.io/en/stable/knn_inspired.html# surprise.prediction_algorithms.knns.KNNWithMeans) )的稍微更高级(但大体上接近于上面描述的那个)的预测算法应用于相同的“非常评级”微矩阵“开箱即用”推荐器,您会立即将 MAPE 从 15.5%降低到 11.4%:

两个演示推荐器的预测结果显示在可视化界面上:

有价值的推荐:小心对推荐人的评价

我们通常不使用 MAPE /梅/ RMSE 来比较推荐者的准确性,而是使用高于指定阈值的估计评分的项目列表的准确性和召回率。

请注意,如果我们决定将我们的电影微库中推荐的电影的最低评级设置为 3.5 或 4.0,对相同用户的推荐将如何变化?

在本出版物的下一部分,我们将展示如何使用适当的指标并提高“开箱即用” SVD 预测算法(来自惊喜模块)的效率,该算法被称为网飞奖获得者

使用 TensorFlow 从头构建 MobileNet

原文:https://towardsdatascience.com/building-mobilenet-from-scratch-using-tensorflow-ad009c5dd42c?source=collection_archive---------11-----------------------

在 TensorFlow 中从头开始创建 MobileNet 架构

图一。(来源:安德里亚·德·森蒂斯峰在 Unsplash 上拍摄的照片)

之前我已经讨论了 MobileNet 的架构和它最重要的层“ 深度方向可分离卷积 ”,在故事中— 理解深度方向可分离卷积和 MobileNet 的效率

接下来,我们将看到如何使用 TensorFlow 从头开始实现这个架构。

实施:

图二。MobileNet 架构(来源:图片来自原论文)

图 2 显示了我们将用代码实现的 MobileNet 架构。网络从 Vonv、BatchNorm、ReLU 块开始,然后是多个 MobileNet 块。它最终以一个平均池和一个完全连接的层结束,具有一个 Softmax 激活。

我们看到这个架构有这样的模式——conv dw/S1,然后是 Conv/s1,等等。这里的 dw 是深度层的步数,后面是 Conv 层的步数。这两行是 MobileNet 块。

“过滤器形状”列给出了内核大小和要使用的过滤器数量的详细信息。该列的最后一个数字给出了过滤器的数量。我们看到过滤器数量逐渐从 32 增加到 64,从 64 增加到 128,从 128 增加到 256,等等。

最后一列显示了随着我们深入网络,图像的大小是如何变化的。输入尺寸选择为 224*224 像素,具有 3 个通道,输出层分类 1000 个类。

图 3。普通 CNN 架构(左)与 MobileNet 架构(右)之间的差异(来源:图片来自原始论文)

构建网络时需要记住的几件事:

  1. 所有层之后是批量归一化和 ReLU 非线性。
  2. 与具有 Conv2D 层的普通 CNN 模型不同,MobileNet 具有深度方向的 Conv 层,如图 3 所示。要更好地理解这一层,请参考— 深度方向卷积块

工作流程:

  1. 从 TensorFlow 库中导入所有必需的图层
  2. 为 MobileNet 块编写一个助手函数
  3. 构建模型的主干
  4. 使用辅助函数来构建模型的主要部分

导入图层

**import tensorflow as tf**#import all necessary layers**from tensorflow.keras.layers import Input, DepthwiseConv2D
from tensorflow.keras.layers import Conv2D, BatchNormalization
from tensorflow.keras.layers import ReLU, AvgPool2D, Flatten, Dense****from tensorflow.keras import Model**

Keras 已经内置了一个 DepthwiseConv 层,所以我们不需要从头开始创建它。

MobileNet 模块

图 4。MobileNet 块的表示(来源:图片来自原始论文)

为了创建 MobileNet 块的函数,我们需要以下步骤:

  1. 函数的输入:

a .一个张量(x)

b .卷积层的滤波器数量(滤波器)

c .深度方向卷积层的步距(步距)

2.运行(图 3 —右侧图像):

a .应用具有步长的 3×3 去 hwise 卷积层,之后是批量归一化层和 ReLU 激活

b .应用带有滤波器的 1x1 卷积层,之后是批量归一化层和 ReLU 激活

3.返回张量(输出)

这 3 个步骤在下面的代码块中实现。

# MobileNet block**def mobilnet_block (x, filters, strides):

    x = DepthwiseConv2D(kernel_size = 3, strides = strides, padding = 'same')(x)
    x = BatchNormalization()(x)
    x = ReLU()(x)

    x = Conv2D(filters = filters, kernel_size = 1, strides = 1)(x)
    x = BatchNormalization()(x)
    x = ReLU()(x)

    return x**

建立模型的主干

如图 2 所示,第一层是 Conv/s2,过滤器形状为 3x3x3x32。

图 5。模型的主干(来源:图片来自原论文)

#stem of the model**input = Input(shape = (224,224,3))****x = Conv2D(filters = 32, kernel_size = 3, strides = 2, padding = 'same')(input)
x = BatchNormalization()(x)
x = ReLU()(x)**

模型的主要部分

图 6。模型的主体部分(来源:图片来自原论文)

# main part of the model**x = mobilnet_block(x, filters = 64, strides = 1)
x = mobilnet_block(x, filters = 128, strides = 2)
x = mobilnet_block(x, filters = 128, strides = 1)
x = mobilnet_block(x, filters = 256, strides = 2)
x = mobilnet_block(x, filters = 256, strides = 1)
x = mobilnet_block(x, filters = 512, strides = 2)****for _ in range (5):
     x = mobilnet_block(x, filters = 512, strides = 1)****x = mobilnet_block(x, filters = 1024, strides = 2)
x = mobilnet_block(x, filters = 1024, strides = 1)****x = AvgPool2D (pool_size = 7, strides = 1, data_format='channels_first')(x)
output = Dense (units = 1000, activation = 'softmax')(x)****model = Model(inputs=input, outputs=output)
model.summary()**

图 7。模型摘要的片段

绘制模型

#plot the model**tf.keras.utils.plot_model(model, to_file='model.png', show_shapes=True, show_dtype=False,show_layer_names=True, rankdir='TB', expand_nested=False, dpi=96)**

图 8:模型图的一个片段

使用 TensorFlow 的整个 MobileNet 模型实现:

**import tensorflow as tf**#import all necessary layers**from tensorflow.keras.layers import Input, DepthwiseConv2D
from tensorflow.keras.layers import Conv2D, BatchNormalization
from tensorflow.keras.layers import ReLU, AvgPool2D, Flatten, Dense****from tensorflow.keras import Model**# MobileNet block**def mobilnet_block (x, filters, strides):

    x = DepthwiseConv2D(kernel_size = 3, strides = strides, padding = 'same')(x)
    x = BatchNormalization()(x)
    x = ReLU()(x)

    x = Conv2D(filters = filters, kernel_size = 1, strides = 1)(x)
    x = BatchNormalization()(x)
    x = ReLU()(x)

    return x**#stem of the model**input = Input(shape = (224,224,3))****x = Conv2D(filters = 32, kernel_size = 3, strides = 2, padding = 'same')(input)
x = BatchNormalization()(x)
x = ReLU()(x)**# main part of the model**x = mobilnet_block(x, filters = 64, strides = 1)
x = mobilnet_block(x, filters = 128, strides = 2)
x = mobilnet_block(x, filters = 128, strides = 1)
x = mobilnet_block(x, filters = 256, strides = 2)
x = mobilnet_block(x, filters = 256, strides = 1)
x = mobilnet_block(x, filters = 512, strides = 2)****for _ in range (5):
     x = mobilnet_block(x, filters = 512, strides = 1)****x = mobilnet_block(x, filters = 1024, strides = 2)
x = mobilnet_block(x, filters = 1024, strides = 1)****x = AvgPool2D (pool_size = 7, strides = 1, data_format='channels_first')(x)
output = Dense (units = 1000, activation = 'softmax')(x)****model = Model(inputs=input, outputs=output)
model.summary()**#plot the model**tf.keras.utils.plot_model(model, to_file='model.png', show_shapes=True, show_dtype=False,show_layer_names=True, rankdir='TB', expand_nested=False, dpi=96)** 

结论

MobileNet 是最小的深度神经网络之一,快速高效,可以在没有高端 GPU 的设备上运行。当使用 Keras(tensor flow 上)这样的框架时,这些网络的实现非常简单。

相关文章

要了解如何使用 TensorFlow 实现其他著名的 CNN 架构,请访问以下链接-

  1. 异常
  2. ResNet
  3. VGG
  4. DenseNet

参考资料:

Howard,A.G .,Zhu,m .,Chen,b .,Kalenichenko,d .,Wang,w .,Weyand,t .,Andreetto,m .,& Adam,H. (2017)。MobileNets:用于移动视觉应用的高效卷积神经网络。 ArXiv,abs/1704.04861

用 HTML 构建现代轻量级 NLP Python 接口

原文:https://towardsdatascience.com/building-modern-and-lightweight-nlp-python-interfaces-with-html-css-db2528700306?source=collection_archive---------11-----------------------

为什么是鳗鱼?继续读!(戴维·克洛德博士讲解 Unsplash

如何将 Python 和 Web 设计结合起来,立即创建漂亮而强大的数据科学图形用户界面

为什么?

众所周知, Python 是当今实现自然语言处理管道的流行编程语言。虽然用 Python 编写一个简单的 GUI 框架并不是一件很困难的任务,但是构建一个现代而漂亮的界面却是一个真正的噩梦,涉及到外部库、繁重的设计工具和陡峭的学习曲线。

例如,像 Tkinter 这样的框架,唯一一个内置到 Python 标准库中的框架,提供了创建 GUI 应用程序的快速而简单的方法,但涉及大量的样板代码,并且根本不是为了呈现好看的现代界面而设计的。

真的吗?这是 1995 年吗?(图片由作者提供)

也就是说,Tkinter 可以用于管理开发的早期阶段,并创建简单的仪表板来监控或调整我们的模型参数。对于其他一切,人们可能应该去别处看看。

然而,在这种情况下寻找其他地方意味着登陆软件,这些软件通常是专有的,并且总是难以消化。最流行的 Tkinter 替代品之一是 Qt ,这是一个用于创建生产质量图形界面和跨平台应用程序的小部件工具包。使用这个框架可以开启 无限的机会,但也有代价:你需要安装一个全新的环境,学习如何使用 Python 绑定,掌握复杂的设计接口等等。结果会很棒,但是……值得吗? 如果你对这个问题的回答是,那么这篇文章就是给你的。

是的,我们需要找到一种方法来提供漂亮的图形用户界面,但是整个 3 GB 的设计套件看起来有点大材小用。(图片作者提供)

这篇博文旨在提供一个简单且易于管理的环境,通过现代且设计良好的用户界面在本地展示数据科学模型。通过将 Python 与 HTML、CSS 绑定,将 Javascript Eel (一个用于制作简单电子类应用程序的小 Python 库),熟悉 web 设计的人可以轻松扩展这个环境,在几个小时内构建出令人惊叹的 web 应用程序,几乎不需要额外的努力。

带着这个目标,我决定实现一个问答(QA)机器人,名为“问我任何事情(AMA)机器人”,基于 Deepset 的 RoBERTa 实现,托管在 Huggingface 上,并在 SQuAD 2.0 上接受训练以进行提取 QA。使用 NLP,我设计了这个项目来托管和显示 Huggingface 的模型,但是完全相同的环境可以扩展到任何 Python 管道来满足您的需求。

怎么会?

最酷的部分来了。用 Eel 构建一个基于 web 的 python GUI 是很容易的事情。Eel 是一个轻量级 Python 库,用于制作简单的离线 web 应用程序,可以完全访问 Python 功能和库。它托管本地 web 服务器,然后让您用 Python 注释函数,以便可以从 Javascript 调用它们,反之亦然。
换句话说,如果你知道 Python 并且熟悉前端 web 开发,你就可以开始了

Eel 提供了 Python 和 Javascript 之间的双向绑定。(图片由作者提供)

构建应用

除了安装 Python 之外,构建这些应用程序没有特别的先决条件。它们只依赖于 Eel 模块,它可以像任何其他 Python 模块一样通过 pip -install 加载到您的虚拟环境中。当然,同一个环境应该包括项目所需的所有其他依赖项。在我的例子中,我也需要 Transformer 库。

一旦你的环境准备好了,像往常一样编写你的 Python 代码,用 @eel.expose 修饰你想要公开给 Javascript 端的函数。这里有一个 AMA 机器人 python 代码的例子:

从 Javascript 方面来说,现在可以通过 Eel 对象访问 Python 功能。

对于 web 应用程序的外观,规则与任何其他 web 应用程序相同:创建 HTML 文件,用 CSS 样式化它们,使之与 Javascript 交互。为了使它更容易,你可以使用 Bootstrap 或者任何你喜欢的框架。

以下是最终结果:

来自 AMA 机器人网络应用的屏幕截图。(图片由作者提供)

如果您需要关于如何实现 Eel 应用程序的更多细节,请查看作者资源库中的文档

结论

Eel 是数据科学家和机器学习研究人员的游戏规则改变者,他们需要立即用干净和现代的仪表板显示他们的结果。这个轻量级的绑定器填补了玩具级图形用户界面和产品级图形用户界面之间的空白,提供了一种巧妙的方式来获得兼顾 Python 和 HTML/CSS/JS 的中级图形用户界面。

作为一个在医学信息学领域工作的人,每当我需要向临床医生和同事展示 ML 演示时,我发现这特别有用。在不损失太多时间的情况下,我们可以交付真实且引人注目的应用程序,帮助利益相关者理解我们工作的潜力

在这里你可以找到这个项目的 GitHub 库。请随意使用 eel 来创建令人惊奇的 NLP 应用程序和更多!

https://github.com/detsutut/ama-bot

我希望这篇文章对你有用!如果你喜欢我的工作,现在你也可以给我买一瓶啤酒!🍺

https://www.linkedin.com/in/tbuonocore

使用金属着色器在 Swift 中构建神经网络

原文:https://towardsdatascience.com/building-neural-network-in-swift-using-metal-shaders-aa1fd75d715b?source=collection_archive---------12-----------------------

使用金属性能着色器框架构建神经网络

克里希纳·潘迪在 Unsplash 上拍摄的照片

介绍

上一篇文章中,我从零开始实现了神经网络框架。它支持 CPU 多线程,但不支持 GPU 计算。在这篇文章中,我将实现类似的框架,但使用金属性能着色器WWDC19 session 614 启发我写这篇文章。

Metal 性能着色器框架包含一组高度优化的计算和图形着色器,旨在轻松高效地集成到您的 Metal 应用程序中。这些数据并行原语经过专门调整,以利用每个 GPU 系列的独特硬件特征来确保最佳性能。

金属性能着色器提供了高度灵活的神经网络编程。

神经网络数据模型

数据模型。图片由 Yauheni Stsefankou 提供。

我们的神经网络模型由模型的层、图和参数组成。

神经网络的参数。图片由 Yauheni Stsefankou 提供。

参数是批量大小和每次训练的时期数。

神经网络图。图片由 Yauheni Stsefankou 提供。

在我们的模型中有两个图:训练图和推理图。两者重量相同。

我们的神经网络框架将有很多层,如密集,下降,平坦,卷积 2D,汇集最大值和平均值,Sigmoid 和 ReLU 激活。

为了方便起见,你可以在我的 GitHub 库中找到所有代码。

不可训练层

这些层的实现非常简单,因为它们没有权重。他们在不改变策略的情况下不断转换输入。

基本图层类为空,因为所有图层没有共同点。

池层有填充和池模式、过滤器大小和步幅。

漏失层非常简单,它只有一个保持输入值的概率。

展平图层也很简单。我们必须提供展平宽度(输入尺寸)。

激活层不需要存储任何数据,所以它们会像基本层类一样为空。

只剩下两个未实现的层:密集和卷积 2D。对于它们,我们需要实现数据源类。它包括神经元的权重、偏差和层参数。

卷积和密集图层的数据源

我们必须在特定的金属向量中存储重量、偏差及其速度和动量。此外,我们在这些向量和优化器的参数上保留指针。

MPSCNNConvolutionDataSource 协议正在强制我们实现一些功能。

第一个函数返回权重的数据类型。我们将保持权重值为 32 位浮点数。

第二个函数返回卷积描述符,它是在类初始化时用给定的参数创建的。

这些函数返回指向带有层权重和偏差的向量的指针。

该方法加载权重和偏差。

这两个函数是插头,因为它们对于我们的任务是不必要的。

而这是ConvDataSource类中的最后一个函数。它返回数据源的标签。

卷积和密集层的权重使用公共卷积参数初始化,例如内核大小、输入通道和滤波器的数量、步幅和学习速率。

这里最基本的东西是优化器和卷积描述符。它们存储我们的层的主要参数,并在用它们训练时更新权重。

在初始化权重和偏差向量之前,我们必须计算它们的长度并为它们创建描述符。

现在,当我们有了描述符,我们可以初始化重量,速度和动量的向量。

然后,我们对偏差向量做同样的处理。

我们使用内核的 glorot 初始化。这意味着我们在-limit 到 limit 的范围内随机生成内核权重,其中 limit 是 sqrt(6/(inputFeatureChannels+outputFeatureChannels))

内核生成后,我们初始化权重和偏差状态和命令缓冲区,所有的初始化都将在这里执行。

然后,我们运行命令完成,并等待它完成。

卷积和密集层

密集层就大不一样了,不需要填充。

图形生成

为了从层中创建图形,我们需要实现函数。

图形是在将节点修补到其他节点时创建的。我们需要存储最后一个节点的结果图像作为新节点的源。

在 switch-case 语句中,我们将为层创建节点。每个节点在初始化时都需要源。

卷积节点需要权重的数据源和填充策略。

激活函数不需要任何参数。

展平图层需要平面输入大小(您可以通过运行 getOutputSize 方法而无需展平和下一个图层来获得)。该层将输入转换为 1x1 矩阵,其通道数等于平面输入大小。

脱落节点仅包含在训练图中。它需要保值的概率。

密集层结构类似于卷积层,但不需要填充策略。

最后一种情况是默认的,所以如果当前图层不是图层类的子类,那么我们就不会在图中包含任何节点。

我们的神经网络框架将仅支持神经网络模型末端的 softmax 激活函数。我们将 softmax 的损失节点添加到训练图中,并将 softmax 节点添加到推理图中。

神经网络模型初始化

在我们实现了为我们的模型创建节点的方法之后,我们可以实现我们的 NN 模型的初始化。

那么,我们需要什么来初始化模型呢?首先,我们需要MTLDevice

MTLDevice协议定义了 GPU 的接口。你可以向MTLDevice查询它为你的金属应用提供的独特功能,并使用MTLDevice发布你所有的金属命令。

我们需要的第二样东西是来自我们MTLDeviceMTLCommandQueue

一个MTLCommandQueue对象将命令缓冲区的有序列表排队等待[MTLDevice](https://developer.apple.com/documentation/metal/mtldevice)执行。命令队列是线程安全的,允许多个未完成的命令缓冲区同时编码。

第三个是层数组,我们将在createNodes()函数中使用它来构建我们的图表。

最后两个参数是基本的模型参数:时期数和批量大小。

首先,我们将初始化的参数复制到模型的本地存储中。

为了得到最终节点,我们运行createNodes()方法。但是在方法运行之后,我们得到了没有丢失节点的节点(除了 softmax 丢失节点)。

为了创建训练图,我们需要添加损失节点并获得损失出口,因此我们运行trainingGraph方法。它返回图形的亏损退出点。在我们的例子中,它必须只包含一个止损点。

在得到损失退出点后,我们可以用它来创建训练图。

推理图初始化类似于训练图。这种初始化更容易,因为我们不必创建丢失节点。

创建推理图与创建训练图非常相似。

数据集实现

我们的数据集支持两种类型的数据:图像和字节。

数据集包括样本数组、图像大小参数(如果数据类型是图像)、类别标签(我们的神经网络模型应该是分类器)。

为了方便使用,数据示例复制了数据类型。此外,它将标签索引存储在数据集中的classLabels数组中。样本的主体取决于数据类型。如果数据类型是图像,那么样本存储CGImage及其MTLTexture

在数据样本初始化之前,我们需要创建从 CGImage 到 MTLTexture 的 convert 方法。

我将 convert 方法实现为一个可计算的变量。

正因为如此,我不得不再次得到 default MTLDevice。金属编码中最常见的事情就是使用描述符。我们需要创建纹理描述符。我们纹理的像素格式是r8Unorm。这意味着这里只有红色通道(灰度),值表示为无符号的 8 位规范化整数。此外,我们将 CGImage 的宽度和高度复制到描述符中。我们的纹理区域的原点为零,大小等于 CGImage 的大小。

我们颜色空间使用每个分量 8 位,每个像素一个分量(红色通道)。另外,我们的颜色空间不使用 alpha 通道。

我们使用加速框架使图像符合我们的纹理格式。之后,我们使用图像来获取可以写入纹理的数据。

这种方法有助于我们更容易地创建数据样本。数据样本的初始化是定义类型,从实参中复制参数并获取纹理(如果类型是图像)。

但是我们不能用我们的数据样本来构建模型。所以,我们必须实现向MPSImage的转换。

MPSImage可以用纹理轻松初始化。当数据类型是字节时,我们用描述符创建平面MPSImage,并向其中写入字节。

好的。我们实现了数据样本类。现在我们必须实现数据集初始化。

用字节初始化数据集非常简单。我们所要做的就是为每个样本提供带有字节数组和标签的初始化器。

此外,我们将从包含图像的子文件夹的文件夹中编写初始化程序。要处理文件夹和文件,我们必须使用默认的FileManager

然后,我们实现我们的文件结构。首先,我们在给定的文件夹中寻找子文件夹。每个子文件夹代表一个唯一的类。然后,我们在每个子文件夹中寻找文件。

之后,我们尝试从每个文件中读取图像。如果我们成功读取图像,那么我们可以使用CGContext将图像调整到格式。最后一件事是从图像中创建DataSample并将其添加到 samples 数组中。

对于这种情况,当我们只有一个数据集,并希望将其分为训练集和测试集时,我们必须编写一个适当的方法。它复制所有的公共参数,如类标签数组、图像大小和数据类型。

之后,它使用Dictionary按类划分样本。

然后,它使用给定的测试集百分比划分样本的所有类别。

培养

我们的训练过程分为几个时期。在开始新的纪元之前,我们必须等到前一个纪元完成。我们在训练之前和每个时期之后评估我们的模型。

在每一个时期,我们都把所有的样本分批送去训练。

但是在实现trainIteration方法之前,我们必须实现从数据集获取训练批次。

获取训练批次并不难,因为我们实现了从样本中获取MPSImage。Batch 是这些图像的数组。我们还必须用标签改变损失状态批次。

丢失数据是 float 类型的数组,其中除了正确的变量之外,所有变量都等于 0。

得到训练批次后,我们必须将其编码为MTLCommandBuffer

在训练迭代中,我们得到训练批次及其期望值。使用双缓冲信号量导致永久的 100% GPU 负载。

我们必须将完整的处理程序添加到命令缓冲区中。训练迭代结束后,统计训练损失并输出到终端。我们使用fflush来替换先前的迭代状态。

为了得到训练损失,我们将一个批次中的所有损失相加,然后除以批次大小。

最后,我们用命令缓冲区同步批处理,启动缓冲区中的命令并返回它。

估价

在评估时,我们计算正确答案并除以测试集中的样本数。然后,我们从数据源重新加载推理图,因为在训练过程中权重只在训练图中改变,而不在推理图中改变。

评估也将有双缓冲信号量。

批量备考甚至比在培训中还要容易。我们只需要一组数据样本。

然后我们将使用predict方法,因为我们需要实现它。它返回一个标签预测数组。我们将预期与预测进行比较,并评估模型。

为了预测,我们必须准备数据样本。我们将它们转换成 MPSImages 并编码到命令缓冲区。

将推理批次编码到命令缓冲区非常类似于将训练批次编码。唯一的区别是,我们对推理图进行批量编码,而不是训练。

当 GPU 上的操作完成后,我们可以检查批处理中每个项目的输出。

然后,我们读取批处理中每一项的输出,并通过最大值的索引追加一组答案。这就是分类器的工作方式。

例子

我尝试了使用 ETL 数据集的平假名分类和使用 MNIST 的数字分类。经过 10 分钟的训练,平假名分类器的准确率达到 75%,数字分类器的准确率达到 98%。

结论

这个神经网络框架比我们之前做的版本快多了。然而,我们的实现只支持分类器。如果你真的对用金属性能着色器构建其他神经网络模型感兴趣,我们的框架很灵活,你也可以修改它。保存模型是一件很平常的事情,这就是为什么我在这篇文章中没有考虑它。你可以在我的 GitHub 库中找到保存有模型的源代码。

感谢阅读。如果你有任何建议或者你在这篇文章中发现了错误,请在评论中留下你的反馈。我已经准备好改善我的读者的体验。

使用 Gradio 和拥抱面部变形金刚构建 NLP Web 应用程序

原文:https://towardsdatascience.com/building-nlp-web-apps-with-gradio-and-hugging-face-transformers-59ce8ab4a319?source=collection_archive---------17-----------------------

向同事和客户展示你的 NLP/ML 解决方案时,web 应用是必不可少的。但是构建和部署一个有时会是一场噩梦。输入 Gradio。

蔡钦汉的情绪分析网络应用的 Gif。

Web 应用程序设计和部署可以说是数据科学家和分析师最容易忽视的技能之一。然而,如果你需要向同事或客户展示你的 NLP 或机器学习解决方案,这些技能是必不可少的。

虽然一个好的演示会有很长的路要走,但没有什么比拥有一个原型更好的了,在这个原型中,非技术用户可以自己测试提议的解决方案。如果你最近几年尝试过部署一个 ML web 应用,你就会知道大多数托管服务对于那些前端开发经验有限的人来说并不容易。

相比之下,Gradio 是一个相对较新的库,它使 ML 和 NLP web 应用程序的创建和共享变得轻而易举。只需几行代码,您就可以将您的模型放在许多标准模板中,这样就不必创建单独的 HTML 模板,也不必考虑 UI、按钮的颜色和大小等问题。

可以肯定的是,Gradio 模板非常简约。但是坦率地说,在测试和开发的早期阶段,这就是你所需要的全部,那时的目标仅仅是快速测试和快速迭代。Gradio 的与抱抱脸的 变形金刚库和模型中枢的紧密集成使其成为一个更加强大的工具。

当然,Gradio 不是唯一可以用来快速开发 web 应用程序的库。 StreamlitPlotly 是这一领域的另外两个著名名字,各有所长。但是我要说 Gradio 是迄今为止最用户友好的,并且是早期 NLP/ML 解决方案开发的游戏改变者。

通过几个 Jupyter 笔记本,我将分享我如何使用 Gradio 构建独立的和“链式链接”的 NLP 应用程序的例子,这些应用程序结合了不同的功能和 transformer 模型。

回购、文件和项目范围

我为这个项目准备的 repo 包含了运行本文中的例子所需的所有文件: 5 个 Jupyter 笔记本2 个音频文件和一个腌制的逻辑回归模型(演示 Gradio 在 transformer 模型之外的用法)。

这里的演示更适合新手,以及那些处于 NLP/ML 项目早期探索阶段的人。Gradio 提供了托管和私有部署的选项,但是这已经超出了本文的范围。

除了定义 NLP/ML 模型的输入和输出之外,只需几行代码就可以启动并运行 Gradio 应用程序。如果你使用拥抱脸的公共推理 API ,这个过程就更简单了。但我不会在我的例子中采用这种方法,因为我发现 Hugging Face 的公共/免费推理 API 相对较慢,如果你试图一次加载太多 transformer 模型,你的应用程序可能会崩溃。

因此,我编写了在本地机器上运行的演示程序。要公开分享 app,只需要在 Gradio 界面更改一个参数即可。

1.独立的情绪分析应用

让我们从一个最简单的例子开始——使用 Hugging Face 的管道 API 构建一个用于情感分析的 web 应用。情感分析管道中的默认蒸馏模型返回两个值—一个标签(正或负)和一个分数(浮点)。

Gradio 消除了从零开始设计 web 应用程序的痛苦,并解决了如何正确标记两个输出的问题。下面的屏幕截图展示了如何通过在 Gradio 中更改一些参数来轻松调整应用程序的外观:

屏幕截图:蔡振汉

由于 Gradio 和 transformers 库之间的紧密集成,只需几分钟就可以调整 notebook1.0 中的代码,将情感分析 web 应用程序转变为一个用于翻译、摘要或零镜头分类的应用程序。

2.独立的 TROLL TWEET 探测器应用程序

通过 Scikit-learn 等标准机器学习库,Gradio 可以很好地处理酸洗模型。在笔记本 1 中。 1,我加载了我在之前的项目中为巨魔推文构建的逻辑回归分类器,Gradio 应用程序很快就启动并运行了:

屏幕截图:蔡振汉

Gradio 模板是准系统,毫无疑问。但这就是我在早期阶段所需要的,以查看模型是否如预期的那样工作,以及解决方案是否对非技术观众来说是清楚的。

3.“平行”中的梯度—比较两种汇总模型

最近,几乎不可能跟上各种 NLP 任务可用的新 transformer 模型的数量。例如,如果你正在做一个文本摘要项目,你如何展示拥抱脸的模型中枢上可用的 248 个模型中哪一个更适合你的用例?或者,您如何证明您自己的微调模型比其他模型表现得更好?

Gradio 提供了一个简洁的解决方案,允许在同一个应用程序中“并行”加载 transformer 模型。这样,您可以直接比较一个输入的不同结果:

屏幕截图:蔡振汉

notebook2.0 中,我开发了一个快速网络应用程序来比较两种不同模型的摘要能力:FB 的 Bart 和 Google 的 Pegasus。这是一个直接比较多个模型的结果的好方法,而不必复制不同应用程序的结果,或者在两个模型之间来回切换屏幕。

这也是比较文本生成或翻译模型性能的一个很好的方法,在这种情况下,不同模型的结果会有很大的不同。Gradio 没有说明一次可以并行加载的模型的最大数量,所以根据需要应用一些常识性的限制。

4.“系列”中的 GRADIO 结合两种变压器模型进行翻译和总结

另一种利用大量变形金刚模型的方法是将它们“串联”起来,即在一个 Gradio 应用程序下连接不同功能的模型。

Notebook3.0 演示了如何构建一个翻译摘要器,它接收中文文本并生成英文翻译摘要:

屏幕截图:蔡振汉

正如上面的截屏图所示,最终结果并不令人印象深刻。这很好地提醒了约束在这些 NLP/ML 项目中的重要性——仅仅因为一些东西在技术上可行并不意味着结果会有任何好处。

虽然链接不同功能的多个 transformer 模型的能力是一个非常受欢迎的能力,但要找到一个有效的组合并交付良好的结果还需要付出相当多的努力。

5.具有音频输入和文本输出的语音到文本“混合媒体”应用程序

我的最后一个例子,在 notebook4.0 中,演示了一种使用humping Face 对脸书的 Wav2Vec2 模型的实现来构建简单的语音到文本网络应用的快速方法。

使用最新版本的 Gradio,您可以轻松配置混合媒体应用程序,这些应用程序采用一种特定的输入格式,例如音频或视频,并以另一种格式输出,例如文本或数字。为了简化演示,我选择了一款语音转文本应用,它可以接收音频剪辑并返回文本文本:

屏幕截图:蔡振汉

一个新人使用 Flask 和 HTML 模板创建一个类似的语音到文本的应用程序可能需要几个小时,如果不是几天的话,更不用说在正确部署到托管提供商的过程中还要经历额外的考验。

对于 Gradio,这个特殊示例的挑战主要在于定义一个函数来处理较长的音频文件,而不会出现会导致本地计算机崩溃的内存不足问题:

创建应用程序界面实际上只需要一行代码:

我已经在 repo 中包含了两个音频文件,你可以尝试一下语音转文本应用程序——美国总统约翰·肯尼迪在 1961 年的著名就职演说,以及青年诗人阿曼达·戈尔曼在 2021 年美国总统乔·拜登就职典礼上的诗。

结束注释

坦率地说,数据专业人员高效工作所需的技能越来越多,这是非常荒谬的。很少有人(如果有的话)会有时间学习与数据相关的编码和分析技能,以及前端开发。

像 Gradio 这样的库有助于将所需技能“压缩”成更易于管理的东西,让数据科学家和分析师不必为了一个简单的演示而花费数小时摆弄 Flask 和 HTML。

从长远来看,我认为这有助于促进机器学习的更大透明度和问责制,因为数据专业人员不再有任何借口说他们不能快速构建应用程序来让其他人尝试提议的解决方案。

随着越来越多的人开始在早期阶段测试此类应用,希望深埋在特定解决方案的训练数据和设计中的偏见和道德问题将更容易被发现。

和往常一样,如果你在这篇文章或我之前的文章中发现了错误,请联系我:

  • 推特:蔡锦鸿
  • 领英:【www.linkedin.com/in/chuachinhon

用 Apache Kafka 构建 Python 微服务:一分耕耘一分收获

原文:https://towardsdatascience.com/building-python-microservices-with-apache-kafka-all-gain-no-pain-1435836a3054?source=collection_archive---------6-----------------------

图片来自 freepikmrjo_7

工程师在日常工作中经常使用阿帕奇卡夫卡。Kafka 执行的主要任务是:阅读消息、处理消息、将消息写到一个主题,或者在一定时间内聚合消息。窗口可以是固定的(例如每小时聚合)或滑动的(例如从某个时间点开始的每小时聚合)。

鉴于 Kafka 作品的复杂性,我不建议您尝试从头构建自己的解决方案。微调、测试和支持将非常困难。幸运的是,有现成的实现,比如 Kafka Streams for Java 和 Kafka Streams for Python——由 Robinhood 编写的 Python Faust 。该团队还有一个社区支持的分支— 浮士德流媒体

本文分享了我在 Provectus 使用 Apache Kafka 构建异步 Python 微服务进行“通信”的经验。 Faust ,一个将 Kafka 流的思想移植到 Python 的流处理库,被用作微服务基础。Faust 还为间隔任务和调度任务提供了一个 HTTP 服务器和一个调度程序。在一个测试实现中,我将使用 FastAPI、Grafana 和 Prometheus 等工具和库。

浮士德

浮士德是卡夫卡流在 Python 上的实现。它最初由 Robinhood 开发,现在仍被用作高性能分布式系统和实时数据管道的默认库。

该库适用于 Python 3.6+和 Kafka 0.10.1+,并支持各种数据存储、数据收集和加速模块。Faust 使您能够利用常见的 Python 库,如 NumPy、SciPy、TensorFlow、SQLAlchemy 等。

项目架构

我相信要真正学会如何做一件事,你应该一步一步地去做。下面是我们将要构建的一个简单测试项目的架构图。

作者图片

测试数据将在演示服务器微服务中编译,而数据请求者微服务将每秒请求数据。数据请求者是我们 Faust 系统中的第一个微服务。一旦数据被请求,data _ requestor会将回复推送给 Kafka。然后,这个消息被 data_processor 读取、处理并推回给 Kafka。随后,它被 data_aggregatordb_loader 读取,其中第一个微服务计算平均值,第二个微服务将它们加载到数据库中。 db_loader 还加载由 data_aggregator 生成的消息。同时,当用户请求时, api_gateway 可以从数据库中提取数据。使用 Prometheus 监控所有活动,并可在 Grafana 中可视化。该项目和附加服务在 docker-compose 推出。

第一步。基础设施设置

因为我们将使用 docker-compose 加速项目,所以描述所有第三方服务是有意义的。我们将需要 Apache Kafka,一个数据库,一个管理仪表板来管理它,以及几个监控服务 (Prometheus 和 Grafana)。让我们使用 Postgres 作为我们的数据库,使用 PgAdmin 作为它的管理和监控组件。

在这个阶段,我们的 docker-compose.yml 看起来是这样的:

docker-compose,与基础设施、配置和附加脚本一起,存储在存储库的单独文件夹中。

微服务的常见组件

尽管每个服务都有自己的任务,并使用两个不同的库(FastAPI 和 Faust)编写,但它们有几个共同的组件。

首先是基于配置加载器库的配置加载器。它使您能够使用 yaml 文件加载配置,并通过可变的环境重新定义它们的值。这在需要在 docker 容器中重新定义特定值的情况下非常有用。

其次是普罗米修斯出口商。您可以使用它来导出数据和指标,并在 Grafana 中显示它们。请记住,它在 FastAPI 和 Faust 中的实现略有不同。

第二步。数据仿真微服务

为了测试和演示该系统,我们将使用一个简单的服务,以 JSON 格式返回货币对的值。为此,我们也将使用 FastAPI 库。这项服务和 Flask 一样容易使用,但是它自带了 async 和 Swagger UI 文档。可以在这里找到:http://127 . 0 . 0 . 1:8002/docs

我们将只为服务指定一个请求:

从上面的代码中可以看出,每个请求都返回一个 JSON,其中包含两对随机生成的值。回复可能是这样的:

{
 “USDRUB”: 85.33,
 “EURRUB”: 65.03
}

要监控这些值,请将 Prometheus 添加到系统中。它应该作为中间件添加,并有单独的指定路径。

您可以在浏览器中查看您的值的指标:http://127 . 0 . 0 . 1:8002/metrics

第三步。数据请求者微服务

在 Faust 的帮助下,API _ requestor微服务请求来自演示服务器的数据。因为 Faust 是异步的,我们可以简单地使用 aiohttp 客户端来请求测试数据。

首先,让我们创建一个 Faust 应用程序。

创建应用程序时,请确保指定了它的名称,这是一个必需的参数。如果我们启动几个同名的服务版本,Kafka 将在它们之间分配分区,使我们能够横向扩展我们的系统。接下来,我们需要在 value_serializer 中指定消息序列化的方法。在这个例子中,我们可以照原样读取原始的消息,以便随后序列化接收到的消息。我们还应该定义访问 Faust 托管的 HTTP 服务器的地址和端口。

接下来,我们需要定义将要接收来自 demo_server 的回复的主题。

第一个参数是主题名;这是强制性的。然后,您可以指定分区的数量(可选)。请记住,分区的数量必须与 Kafka 中主题分区的数量相似(在创建主题时指定)。

请注意,data _ requestor服务并不从主题中读取消息,而是不断地将请求推送到数据模拟器,然后处理回复。要实现这一点,您需要编写一个实时时钟函数,该函数每秒触发一次,或者在指定的时间间隔触发。

我们可以看到该功能是由 @app.timer decorator 周期性执行的。它接收每秒间隔作为参数。然后,该函数为 DataProvider 生成一个类实例,负责提供对请求的回复。在每一个随后的请求之后,普罗米修斯计时器的值增加。如果数据是按请求接收的,它将被发送到一个主题。因为 Kafka 使用特定的键和字节内消息,所以我们需要在将数据推送到主题之前对其进行序列化。

在启动应用程序时,您还需要初始化 Prometheus。为此,您可以简单地使用启动应用程序时调用的函数。

请记住,函数是由 @app.task decorator 分配和定义的。Prometheus 使用自己的端口作为独立的服务器启动,它与 Faust 的 HTTP 服务器并行工作。

给你!每秒向 Kafka 发出请求和写入数据并不困难。添加监控组件也可以很快完成。

第四步。数据处理微服务

我们的下一个微服务——数据处理器——处理由 api 请求者微服务接收的数据对。应用程序初始化和数据监控的代码与我们用来管理data _ requestor的代码相同。然而,在 data_processor 的情况下,服务从主题接收消息来处理它们。可以用函数来完成。

该函数基于@ app . agent(src _ data _ topic)装饰器,该装饰器告诉该函数处理 src_data_topic 中的消息。从 stream.items() 的 msg_key,msg_value 的异步读取消息。

然后,我们需要序列化接收到的消息,并提取货币对及其值。每一对都应该分别写一个相应的主题。

第五步。数据聚合微服务

请求和处理数据的微服务以流的形式在 Kafka 中读写数据。每个新消息都独立于以前的消息进行处理。但是,偶尔您可能需要同时处理一定数量的消息。假设您需要找到最后十对值的平均值。为此,你的系统应该能够在某个地方存储这 10 对。您不能在本地存储数据:如果您触发了聚合服务的多个版本,每个版本都将只在本地存储其值,这将导致平均值计算不正确。这里是你可以利用浮士德表的地方。

这些表将值存储在 changelog 主题和本地——rocks db 中。这允许服务的所有版本同步工作。重启后,它从本地数据库恢复状态,当读取可用的变更日志时,它继续工作。

表的主题名是这样分配的: - -changelog。在我们的系统中,名称是:data-aggregator-average-changelog。

在表中处理和存储新消息非常简单:

从上面的代码可以看出,您需要定义函数如何处理主题中的消息。收到的每个新值都应存储在表中,以计算平均值。您可以以类似于标准 Python 字典的方式使用该表。

第六步。数据库加载器微服务

db_loader 微服务一次读取两个主题——data-aggregator-average-changelogprocessed _ data——两个。它将消息从 data_aggregator 写入第一个主题,从 data_processor 写入第二个主题。这就是为什么我们需要描述消息处理的两个函数。

与其他服务类似,您需要:读取消息,将其存储在数据库中,更新指标。为了管理数据库,我们将使用 ORM SQLAlchemy。请注意,您应该将其设置为异步工作。为此,定义所需的依赖关系。

asyncpg==0.23.0
SQLAlchemy==1.4.0

在配置中指定 DB URI

DB_URI: “postgresql+asyncpg://postgres:postgres@127.0.0.1:5432/currencies”

在数据库管理代码中使用异步会话。

第七步。结果请求者微服务

最后,让我们使用 FastAPI 创建一个简单的服务,从数据库中请求结果。它将从数据库中读取结果,并将它们推送到 JSON。要管理数据库,可以使用 ORM(就像我们之前做的那样)。至于 FastAPI,说明类似于步骤 2。数据仿真微服务。

结论

在 Python 上用 Apache Kafka 构建微服务相当简单。你可以把处理和管理卡夫卡的几乎所有工作都交给浮士德。然后,只需描述和定义函数,就能看到它们实时处理您的消息。

我希望这篇教程能帮助你更好地理解如何将微服务、Apache Kafka 和 Python 结合起来。如果您对 Apache Kafka 中的集群监控和管理感兴趣,我建议您也查看一下本文。

有什么问题吗?请在评论区联系我进行讨论。

构建可复制的机器学习管道

原文:https://towardsdatascience.com/building-reproducible-machine-learning-pipelines-c80407c4319f?source=collection_archive---------23-----------------------

如何安全地部署机器学习模型

照片由 JJ 英Unsplash

可重复性是企业进一步理解和信任机器学习在我们日常生活中的应用所需的责任。

随着机器学习变得更加生产化,许多企业和研究人员可能会感到不得不匆忙采取行动,这不利于充分理解实现某些方法所涉及的复杂性,或者在没有正确程序的情况下匆忙完成过程会牺牲什么,所有这些都是为了更快地获得结果。

随着信息唾手可得,机器学习失败成为头条新闻,就像微软的 Twitter 聊天机器人的情况一样,公众的怀疑态度增加了,因此强调了任何方法中可重复性的必要性和重要性。

:本文中的内容摘自我在 Udemy 上的机器学习模型部署课程的笔记。

什么是再现性?

在机器学习环境中,再现性是指精确复制模型的能力,使得当模型被传递相同的输入数据时,复制的模型将返回相同的输出。

未能事先考虑再现性可能会在开发过程中产生一些后果。一个典型的例子是从金融的角度。如果一个人在研究环境中对模型开发投入了大量资源,但在生产中却无法重现模型,那么模型及其预测基本上是无用的。这浪费了时间、精力和资金,全都付诸东流。

此外,再现性在允许我们对照以前的解决方案检查我们的机器学习模型方面起着关键作用。如果不能再现以前的结果,我们就无法准确区分新模型是否超过了以前模型的性能。

再现性的挑战

在创建和构建机器学习模型时,从业者将在整个过程中在多个环境中工作——一个环境描述了软件(或其他产品)被开发或投入运行的计算机的状态。开发机器学习模型通常涉及三种环境:

  1. 研究环境 —在研究环境中,数据科学家将执行数据分析以了解数据,构建模型,并对其进行评估,以更好地了解模型正在做出什么决策,以及它是否符合项目预期结果的标准。
  2. 开发环境 —在开发环境中,机器学习工程师寻求重现在研究环境中开发的机器学习流水线。该环境还结合了软件工程最佳实践,以确保管道可以作为一个适当的软件系统运行。
  3. 生产环境— 在生产环境中,模型能够服务于其他软件系统和/或客户。

研究环境之外的每个环境都试图复制管道开发的研究。但是,每个环境达到所需状态的步骤是不同的。从数据采集到从模型获得预测,这几乎在流水线的每一个单独步骤中都给再现性带来了许多潜在的障碍和挑战。

数据收集的再现性

永远记住数据先于科学;没有数据,机器学习模型是没有意义的。数据采集是再现性主题中最重要也是最难解决的问题之一。

“一个模型永远不会完全一样,除非用完全相同的数据和过程来训练它。”——索勒达德·加利博士。机器学习模型部署(Udemy)讲师

当在研究环境中工作时,数据科学家可能可以访问一个版本的训练数据,然而,当机器学习工程师必须在生产中再现流水线时,数据可能已经改变。这取决于一些数据库的工作方式。他们可能会不断地用更新的版本覆盖旧版本的数据,从而随着时间的推移改变训练数据。此外,如果数据科学家使用 SQL 查询数据,则会引入随机性,因为 SQL 会随机地将数据加载到内存中。

虽然没有一种方法在所有情况下都是绝对可靠的,但是有很多方法可以解决这些问题。例如,一个解决方案可能是确保数据科学家保存用于建立模型的训练数据的快照。当数据非常大时,如果它妨碍团队遵守数据法规,这种方法就会失败。

另一种方法,也可能是更理想的方法,是向数据源添加准确的时间戳,这可以在以后用于识别哪些数据用于训练模型。但是,请务必注意,如果在进行更新时数据不断被替换,这种方法不能解决问题。进一步补充一下,如果数据库不是为跟踪时间戳而设计的,那么可能需要很大的努力来集成这一功能。

特征工程中的再现性

如果我们在数据采集阶段的再现性方面出错,那么在试图再现管道的特征工程阶段时,可能会出现问题。

“如果两种环境中的数据不相同,从数据中得出的参数将会改变”——Solledad Galli 博士。机器学习模型部署(Udemy)讲师

假设数据中有缺失值,而数据科学家选择通过输入要素的平均值来填充这些值。如果研究和生产环境中的训练数据之间存在差异,那么特定功能的平均值也可能存在差异。当然,如果来自研究环境的训练数据可以被复制,那么这个问题就消失了。

在特征工程阶段,可能阻碍再现性的其他因素包括:

  • 复杂的提取方法(问题与研究环境中数据缺乏可重复性有关)
  • 不保持超参数不变(它们必须在不同环境之间保持不变)
  • 依赖于随机采样的特征生成方法(设置种子参数可确保生成相同的样本)

利用版本控制的力量来跟踪所有的差异可以解决与再现特征工程阶段相关的问题——如果它们不是源于不能再现数据获取阶段的话。

建模中的再现性

一些机器学习模型在训练过程中引入了随机性,这给再现性带来了挑战。这种现象的一个主要例子是树集合(随机森林,梯度增强等。)和神经网络。

例如,随机森林模型在构建每一棵树时使用装袋和特征随机性来创建不相关的森林。并且,神经网络在权重初始化期间引入了随机性。这种随机性会导致模型之间的不一致,无论它们是否基于相同的训练数据。

与特征工程类似,应对这种再现性威胁的简单解决方案是在需要时设置种子和跟踪超参数。

部署中的再现性

在机器学习工作流的部署阶段,再现性的挑战围绕着将模型集成到其他系统的失败。

部署中再现性失败的一个主要例子是,用于训练模型的群体不能代表真实环境中的群体。这可能是由于在实际或研究环境中使用了在建模时未被检测到的过滤器,或者构建模型的数据科学家没有完全理解模型在生产中的使用方式。

另一种情况发生在编程语言在不同环境之间变化的时候。机器学习通常用 Python 或 R 来完成,而应用程序通常使用 C++或 Java。这可能会激励团队用另一种语言再现研究环境,从而显著增加 1)人为错误和 2)部署错误的可能性。使用一种编程语言是克服这一挑战的最佳方式。

最后,软件版本的改变可能妨碍在部署中再现机器学习流水线的能力,因为每个改变可能导致流水线内的差异。这个问题不太常见,然而,它可能是最难解决的,因此确保所有软件环境在整个过程中是相同的是至关重要的。

包裹

数据科学家和机器学习工程师在试图确保机器学习工作流的可重复性时,往往会面临几个挑战。虽然有些问题需要重大变革才能克服,但其他问题可能相当简单(例如,埋下种子)。要点是,必须解决所有潜在的再现性障碍,以获得真正的再现性。

感谢您的阅读!

如果你喜欢这篇文章,请通过订阅我的每周简讯与我联系。不要错过我写的关于人工智能、数据科学和自由职业的帖子。

相关文章

**https://medium.datadriveninvestor.com/machine-learning-model-deployment-b1eaf7ca96cd [## 机器学习工作流程

towardsdatascience.com](/the-machine-learning-workflow-1d168cf93dea) https://medium.datadriveninvestor.com/machine-learning-engineers-must-read-these-5-books-583e81922b84 **

使用 PyTorch 为时间序列构建 RNN、LSTM 和 GRU

原文:https://towardsdatascience.com/building-rnn-lstm-and-gru-for-time-series-using-pytorch-a46e5b094e7b?source=collection_archive---------1-----------------------

照片由恩库鲁列科乔纳斯拍摄。

用新的工具包重新审视十年之久的问题

从历史上看,时间序列预测一直由线性和集成方法主导,因为在特征工程的支持下,它们在各种问题上得到很好的理解和高度有效。部分由于这个原因,深度学习在某种程度上被忽视了;换句话说,与图像识别、语音识别和 NLP 等其他领域相比,它对时间序列预测的影响较小。

随着 80 年代递归神经网络(RNN) 的出现,随后是更复杂的 RNN 结构,即 1997 年的长短期记忆(LSTM) ,以及最近 2014 年的门控递归单元(GRU) ,深度学习技术使得能够通过有限的特征工程来学习顺序输入和输出之间的复杂关系。简而言之,这些 RNN 技术和类似的技术在以以前不实用的方式分析大规模时间序列方面具有巨大的潜力。

在这篇文章中,我想给你介绍一些 RNN 结构,如 RNN、LSTM 和 GRU,并帮助你开始建立时间序列预测的深度学习模型。虽然这不是本文的重点,但我将提供一些广泛应用于时间序列预测的特征工程技术,比如一次性编码、滞后和周期性时间特征。我将使用 Scikit-learnPandasPyTorch ,这是一个主要由脸书人工智能研究实验室开发的开源机器学习库。虽然前两者长期以来一直是数据科学家和机器学习实践者的最爱,但 PyTorch 相对较新,但越来越受欢迎。然而,由于它的新近性,我从一开始就很难找到相关的信息和代码样本,对于已经存在一段时间的框架来说,比如说 TensorFlow ,这通常要容易一些。所以,我决定把我想早点知道的事情整理一下。少说多做:我们从哪里开始?

数据在哪里?

嗯,我想我们需要一些时间序列数据作为开始。无论是支付交易还是股票交易数据,时间序列数据无处不在。一个这样的公共数据集是 PJM 的每小时能源消耗数据,这是一个从美国不同地区收集的 10 多年每小时观测数据的单变量时间序列数据集。我将使用 PJM 东部地区的数据,该数据最初包含 2001 年至 2018 年的每小时能耗数据,但链接中提供的任何数据集都应该可用。

鉴于有大量关于数据可视化的博客,我将把探索性数据分析(EDA)部分写得很短。对于感兴趣的人,我可以推荐使用 Plotly 来创建交互式图形。以下方法将绘制一个简单的交互式图形,该图形允许您交互式地处理数据集。

2012 年至 2018 年 PJME 地区的估计能耗(MW)

预计 2017 年 PJME 地区的能源消耗(MW)

2017 年 7 月至 2017 年 9 月 PJME 地区的估计能耗(MW)

下一步是生成要素列,将单变量数据集转换为多变量数据集。如果你愿意,我们将把这个时间序列转换成一个监督学习问题。在某些数据集中,每小时的温度、湿度或降雨量等要素都很容易获得。然而,在我们的数据集中,没有额外的信息可以帮助我们预测给定的能耗。因此,创建这样的预测器,即特征列,就落到了我们的肩上。

我将向您展示两种生成要素的流行方法:将滞后观测值作为要素传递,以及根据日期时间索引创建日期时间要素。这两种方法各有优缺点,根据手头的任务,每种方法可能更有用。

使用滞后观测值作为特征

让我们从使用时间步长作为特征开始。换句话说,我们试图从先前的 n 个观察值 Xt,X+1,…,X(t+n-1)中预测下一个值 X(t+n),。然后,我们需要做的只是用前面的观察创建 n 列。幸运的是,Pandas 提供了方法 shift() 来移动列中的值。因此,我们可以编写一个 for 循环,通过将一列中的值移动 n 次并删除前 n 列来创建这样的滞后观察值。滞后是一个简单但很好的起点,尤其是如果您在开始时没有很多功能可以使用的话。

在将输入特征(即滞后观测值)的数量设置为 100 后,我们得到以下具有 101 列的数据帧,一列用于实际值,其余用于每行的前 100 个观测值。

从时间戳生成要素

尽管它的名字,特征工程通常是艺术多于科学。尽管如此,一些经验法则可以指导数据科学家之类的人。在这一节中,我的目标不是在这里介绍所有这些实践,而是演示其中的一些实践,让您自己进行试验。实际上,特征工程在很大程度上依赖于您正在工作的领域,可能需要为手头的任务创建一组不同的特征。

有了单变量时间序列数据集,生成日期和时间特征似乎是合乎逻辑的。由于我们已经将其索引转换为 Pandas 的 DatetimeIndex 类型,即一系列 DateTime 对象,因此我们可以轻松地从索引值创建新的特性,如一天中的小时、一个月中的天、一个月、一周中的天以及一年中的星期,如下所示。

尽管将日期和时间功能无任何接触地传递给模型在实践中可能行得通,但是模型很难了解这些功能之间的相互依赖关系。对我们人类来说,很容易看到小时、天、周和月遵循某种循环模式。虽然说 12 月之后是 1 月对我们来说是微不足道的,但理解一年中第一个月的算法出现在 12 月之后可能并不明显。就此而言,人们可以很容易地举出更多的例子。这使得良好的特征工程对于构建深度学习模型至关重要,对于传统的机器学习模型更是如此。

一键编码

对日期时间特性进行编码的一种方法是将它们视为分类变量,并为每个唯一值添加一个新的二进制变量,这就是众所周知的一次性编码。假设您对 month 列应用了 one-hot 编码,范围从 1 到 12。在这种情况下,创建了 12 个新的月份列,比如[Jan,Feb,… Dec],其中只有一个列的值为 1,而其余的都为零。例如,二月的一些日期时间值应该将这些编码列的第二列设为 1,如 [0,1,… 0]

使用 Pandas 的 get_dummies 方法,我们可以从给定的数据集中快速创建一个热编码列。

或者,您可能希望使用 Scikit-learn 的 OneHotEncoder 通过 ColumnTransformer 类对数据帧中的列进行编码。与 Pandas 方式不同,ColumnTranformer 在被调用以适应数据帧时输出一个 Numpy 数组。

尽管对分类特征编码非常有用,但一键编码并不能完全捕获日期时间特征中的循环模式。如果您愿意,它只是创建分类桶,并让模型从这些看似独立的特征中学习。例如,类似地对星期几进行编码,会丢失星期一比星期三更接近星期二的信息。

对于一些用例来说,这可能并不太重要。事实上,通过足够的数据、训练时间和模型复杂性,模型可以独立地学习这些特征之间的关系。但是还有另一种方法。

生成循环时间特征

与我们迄今为止处理的所有数据一样,一些数据具有内在的周期性。无论是几小时、几天、几周还是几个月,它们都遵循着周期性的循环。同样,这对我们来说是微不足道的,但对机器学习模型来说就不那么重要了。我们如何告诉算法 23 小时和 0 小时像 1 小时和 2 小时一样接近?

要点是创建两个新的循环特性,计算给定日期时间特性(比如一天中的某个小时)的正弦和余弦变换。模型不再使用小时的原始值,而是使用正弦变换,保持其周期性。要了解它是如何工作的以及为什么工作,请随意参考皮埃尔-路易或大卫的博客文章,这篇文章更详细地解释了这个概念。

一个很好的思考练习可能是思考如何在基于决策树的模型(随机森林、梯度增强树和 XGBoost)中将一个时间要素分成两个时间要素。这些特征一次根据一个特征形成它们的分裂,这意味着它将不能同时使用两次特征,例如正弦和余弦变换。通常,这些模型足够健壮来处理这样的分裂,但是它确实值得思考。

其他功能呢?

考虑到我们现在正在处理能源消耗数据,有人可能会问,一年中的假期是否会影响能源消耗模式。的确,很有可能。对于这样的二进制变量,即 0 或 1,我们可以生成具有二进制值的额外列来表示给定日期是否实际上是假日。至少可以说,记住所有的假日或者手动定义它们是一项单调乏味的任务。幸运的是,一个名为假期的套餐实现了它的承诺。

在特征工程中,可能性似乎是无限的,当然也有实验和创造的空间。好消息是已经有相当多的软件包为我们完成了这项工作,比如用于历史天气数据的 meteostat 或者用于股票市场数据的 yfinance 。不好的一点是,在没有实际尝试的情况下,对于哪些附加特性可以提高模型性能,通常没有明确的答案。

仅仅是一个想法,人们也可以尝试包括天气数据,例如温度、湿度、降水、风、雨、雪等等,以了解天气如何影响给定小时、天、周和月的能量消耗。

将数据分为训练集、验证集和测试集

在创建了特征列(无论是延时观测还是日期/时间特征)之后,我们将数据集分成三个不同的数据集:训练集、验证集和测试集。因为我们处理的是与时间相关的数据,所以保持时间序列的完整性是至关重要的,如果你愿意的话,也可以说是不混乱的。通过将参数 shuffle 设置为 false,避免在分成组时进行洗牌,您可以很容易地做到这一点。

对于神经网络,缩放数据集中的值是一种强烈推荐的做法,对于其他机器学习技术也是如此。它通过使模型更容易更新权重来加速学习。您可以通过使用 Scikit-learn 的 Scaler、MinMaxScaler、RobustScaler、Standard Scaler 等工具轻松实现这一点。关于每个缩放器效果的更多信息,请参考官方文档

如果您正在寻找一种快速切换缩放器的方法,这里有一个很酷的技巧。让自己适应切换器功能;我们以后可能还会用到它。

将数据集加载到数据加载器中

将数据标准化后,通常就万事大吉了。这次没那么快。在花了相当多的时间使用 PyTorch 并浏览了互联网上其他人的代码后,我注意到大多数人最终都在为小批量训练做矩阵运算,即使用 NumPy 将数据分割成更小的批量。你可能认为 NumPy 就是干这个的;我明白了。但是还有一种更优雅的 PyTorch 方式,在我看来,这种方式得到的关注肯定要少得多。

PyTorch 的 DataLoader 类,一个可在 Dataset 上迭代的 Python,加载数据并将它们分成批,供您进行小批训练。DataLoader 构造函数最重要的参数是 dataset,它指示要从中加载数据的 Dataset 对象。主要有两种类型的数据集:地图样式的数据集和可迭代样式的数据集。

我将在本教程中使用后者,但也可以在官方文档中查看它们。也可以根据自己的需求编写自己的数据集或数据加载器类,但这肯定超出了本文的范围,因为内置的构造函数已经足够了。但是这里有一个链接指向关于这个话题的官方教程

现在,我将使用名为 TensorDataset 的类,一个包装张量的数据集类。由于 Scikit-learn 的 scalers 输出 NumPy 数组,所以我需要将它们转换成 Torch 张量,以便加载到 TensorDatasets 中。在为每个数据集创建张量数据集之后,我将使用它们来创建我的数据加载器。

您可能会注意到一个批量为 1 的额外数据加载器,并想知道我们到底为什么需要它。简而言之,它不是必须拥有的,而是必须拥有的。像小批量训练一样,您也可以进行小批量测试来评估模型的性能,由于张量运算,这可能会快得多。但是,这样做将会丢弃无法组成批处理的最后时间步骤,从而导致丢失这些数据点。这不太可能导致误差指标的显著变化,除非您的批量很大。

从美学的角度来看,如果有人对预测未来感兴趣,丢弃最后的时间步骤可能会导致从测试集到预测值的不连续。至于训练和验证数据加载器,这种影响是可以容忍的,因为批处理在训练中提供了显著的性能改进,并且这种减少的时间步骤不太明显。

建立循环神经网络(RNN)

如果我试图在这里用几句话解释他们如何工作的本质,我不认为我能公正地对待 rnn。幸运的是,对于那些正在寻找起点的人来说,有几篇关于这些网络的写得很好的文章,安德烈·卡帕西的循环神经网络的不合理的有效性,克里斯·奥拉的理解 LSTM 网络,以及迈克尔·皮的《LSTM 和 GRU 的图解指南:一步一步的解释是我想到的几篇。

如果你看过电影《记忆碎片》——顺便说一句,这绝对是一部很棒的电影——你可能已经知道在记忆丧失的情况下做预测有多难了。当你的记忆每隔几分钟就被重置时,你很容易就无法说出发生了什么,你要去哪里,或者为什么——更不用说追踪杀害你妻子的凶手了。这同样适用于处理序列数据,无论是单词还是零售数据。一般来说,拥有前面的数据点有助于你理解模式,建立一个完整的画面,并做出更好的预测。

然而,传统的神经网络做不到这一点,每次给它们一个任务,它们就从零开始,很像伦纳德,你看。RNN 解决了这个缺点。为了使总体简单化,他们通过将信息从网络的一个步骤循环到下一个步骤,允许信息在网络中持续存在。这使得它们成为解决涉及序列数据的各种问题的强有力候选,例如语音识别、语言翻译或时间序列预测,我们稍后将会看到。

香草 RNN

通过扩展 PyTorch 的 nn。模块,所有神经网络模块的基类,我们如下定义我们的 RNN 模块。我们的 RNN 模块将有一个或多个由全连接层连接的 RNN 层,以将 RNN 输出转换为所需的输出形状。我们还需要将正向传播函数定义为一个类方法,称为 forward() 。这个方法按顺序执行,传递输入和零初始化的隐藏状态。尽管如此,PyTorch 会自动创建并计算反向传播函数 backward()

不过,香草 RNN 有一个缺点。简单的 RNNs 可以将以前的信息连接到当前的信息,其中相关的过去信息和当前信息之间的时间间隔很小。随着这一差距的扩大,rnn 学习长期依赖性的能力越来越弱。这就是 LSTM 寻求帮助的地方。

长短期记忆(LSTM)

长短期记忆,简称 LSTM,是一种特殊类型的循环网络,能够学习长期依赖性,在各种各样的任务中往往比标准版本好得多。可以说是服用类固醇的 RNNs。

标准版本的主要区别在于,除了隐藏状态之外,LSTMs 还有单元状态,它就像一条传送带,将相关信息从前面的步骤传送到后面的步骤。在这个过程中,新信息通过输入和遗忘门被添加到细胞状态或从细胞状态中删除,这两个神经网络确定哪些信息是相关的。

从实现的角度来看,您真的不必为这些细节费心。您只需要在您的 forward() 方法中添加一个单元格状态。

门控循环单元(GRU)

门控循环单元(GRU)是一个稍微精简的变体,它提供了相当的性能和相当快的计算速度。与 LSTMs 一样,它们也能捕捉长期依赖关系,但它们是通过使用没有任何单元状态的复位和更新门来实现的。

更新门决定需要保留多少过去的信息,而重置门决定要忘记多少过去的信息。gru 比 LSTMs 执行更少的张量运算,通常速度更快,需要的内存更少。正如你在下面看到的,它的模型级几乎和 RNN 的一模一样。

类似于我们对定标器使用的技巧,我们也可以轻松地在我们刚刚创建的这些模型之间切换。

现在,似乎我们已经做好了训练 RNN 模特的一切准备。但是我们从哪里开始呢?

训练模型

让我们从创建用于训练模型的主要框架开始。可能有很多方法可以做到这一点,其中之一是使用一个帮助器,或者包装器,保存训练、验证和评估方法的类。首先,我们需要一个模型类、一个计算损失的损失函数和一个更新网络权重的优化器。

如果你熟悉神经网络,你已经知道训练它们是一个相当重复的过程,在向前推进和向后推进之间来回循环。我发现用一个抽象层次,一个训练步骤函数或包装器来组合这些重复的步骤是很有用的。

在定义了一个合适的训练步骤后,我们现在可以开始编写训练循环,在每个时期都会调用这个步骤函数。在训练的每个时期,有两个阶段:训练和验证。在每一个训练步骤之后,网络的权值被调整一点以最小化损失函数。然后,验证步骤将评估模型的当前状态,以查看在最近一次更新之后是否有任何改进。

我将使用小批量训练,这是一种每次只使用一部分数据的训练技术。给定足够大的批量,模型可以通过仅学习数据样本来更有效地学习和更新其权重。这通常需要将每个批次张量重新整形为正确的输入维度,以便网络可以将其用作输入。为了获得张量运算的计算优势,我之前定义了我们的 RNN 模型来处理 3D 输入张量,除非你还没有注意到。因此,您可以将每一批看作数据包,就像仓库中的盒子,具有批大小、序列长度和 input_dim 的维度。

每个阶段也有两个 for 循环,其中模型被逐批训练和验证。重要的是在训练期间激活训练()模式,在验证期间激活评估()模式。虽然 train() 模式允许更新网络的权重,但是 eval() 模式向模型发出信号,表示不需要计算梯度。因此,权重会根据操作进行更新或保持不变。

现在,我们终于可以训练我们的模型了。然而,如果不使用单独的测试集(即保留集)来评估这些模型,就不可能知道该模型与我们正在构建的其他模型相比表现如何。与 train() 方法中的验证循环非常相似,我们将定义一个测试方法来评估我们的模型,如下所示。

在训练期间,损失函数输出通常是模型是学习、过拟合还是欠拟合的良好指标。为此,我们将使用以下方法绘制简单的损失数字。

培养

到目前为止,我们已经准备好了数据集,定义了模型类和包装类。我们需要把它们放在一起。您可以在下面的代码片段中找到一些定义的超参数,我鼓励您随意使用它们。下面的代码将使用我们之前定义的模块构建一个 LSTM 模型。您还可以通过将函数 get_model 的输入从lstm快速更改为您选择的模型来构建 RNN 或 GRU 模型。事不宜迟,让我们开始训练我们的模型。

您可能还记得,我们用标准化的输入来训练我们的网络;因此,模型的所有预测也会被缩放。此外,在我们的评估方法中使用批处理后,我们所有的预测现在都是批处理的。为了计算误差指标并绘制这些预测,我们需要首先将这些多维张量简化为一维向量,即展平,然后应用 inverse_transform() 获得预测的真实值。

在拉平和缩小数值后,我们现在可以计算误差指标,如平均绝对误差(MAE)、均方误差(MSE)和均方根误差(RMSE)。

0.64 的 R2 分数……不算好,也不算糟糕。正如您在下一节中看到的,还有改进的空间,您可以通过设计更好的功能和尝试不同的超参数来实现。我把这个挑战留给你。

生成基线预测

拥有某种基线模型有助于我们比较我们的模型在预测中的实际表现。对于这个任务,我选择了好的老式线性回归,它足以生成一个合理的基线,但也足够简单,可以快速完成。

可视化预测

最后但并非最不重要的一点是,可视化结果有助于您更好地了解模型的性能,并添加可能会改进模型的功能。我将再次使用 Plotly,但请随意使用您更喜欢的软件包。

最后的话

我想说这就是全部,但肯定还会有更多。深度学习是机器学习中最有成果的研究领域之一。对顺序深度学习模型的研究正在增长,并且在未来可能会保持增长。你可以把这篇文章看作是探索这些技术为时间序列预测提供什么的第一步。对于那些喜欢这篇文章并对使用这些算法预测未来价值感兴趣的人,我最近发表了另一篇关于这个主题的文章。

这里有一个链接到这篇文章的 Google Colab 笔记本,如果你想看看完整的笔记本并玩玩它。如果有不合理的地方或者你不同意,请联系我或者在评论中告诉我。这也适用于你可能有的各种反馈。

我还想写几个主题,比如使用时滞和日期时间特征预测未来的时间步长,正则化技术,其中一些我们已经在本文中使用过,以及更高级的时间序列深度学习架构。这样的例子不胜枚举。让我们希望我的动机不辜负这样的雄心壮志。

但是,现在,这是一个总结。

机器学习沙堡

原文:https://towardsdatascience.com/building-sandcastles-ab466403afa8?source=collection_archive---------47-----------------------

思考为什么我们需要一个主导的设计,而不是另一个建立机器学习平台的创业公司

Unsplash 上由考特尼·霍尔拍摄的照片

在大多数组织机器学习(ML)代表了任务和工具的不同组合,数据工程师负责数据管道,数据科学家负责数据分析、模型训练、验证和测试,硬件工程师负责计算配置,软件工程师负责部署。任务和工具如此分离导致了机器学习项目的高总体失败率,并限制了 ML 项目吞吐量的质量和数量。

这导致了 ML 平台的发展。当我提到 ML 平台时,我指的是用于数据和模型开发、跨多台机器扩展实验、跟踪和版本控制模型、部署模型以及监控性能的一体化产品。

这些一体化平台的前景仍然不发达,虽然这可能听起来对那些有工程和创业愿望的人有吸引力,但需要谨慎。

备注: Gartner:数据科学和机器学习(ML)平台

从数据科学的角度看流程

数据挖掘的跨行业标准流程 CRISP-DM 是开放标准流程模型的一个例子,它描述了许多常见的数据科学任务,这些任务如今通常构成 ML 生命周期的一部分。

CRISP-DM 参考模型的一般任务(粗体)和输出(斜体)。来源

现在,拥有 ML 能力的组织让一个人拥有整个生命周期变得越来越普遍。除了其他事情之外,这个人监督人员方面,建立和管理一个有凝聚力的团队,以及过程方面,确保整个生命周期中任务的集成和执行。

不同的音调象征着个人或团队可能执行的不同任务。a .将不同类型的任务分开,专家可以处理比一个人更多的情况;数字相加。显示的是两个专家可以做一个专家两倍的工作。例如,如果每个人可以做 10,000 个任务,他们一起可以做 20,000 个。b .团队可以处理更多不同的情况,因为数量会成倍增加。对于两人团队来说,这将是 10,000 x 10,000 = 100,000,000。来源

备注: ML 工程最佳实践

把 ML 当成工程问题是个问题

虽然将 ML 作为一个工程问题来对待可能很诱人,但是那些确实忽视了对过程至关重要并且不是工程师的广大用户。例如,主题专家经常提供从数据标记和特征工程到模型评估的各种输入。主题专家有必要有效地参与到这个过程中,同时记住许多人并不精通编程。对于这些用户来说,设想一个低代码环境是合理的。为了支持这些低代码用户,需要有抽象层,每一层都定义良好。对于大多数主题专家来说,最高级别的抽象——用户界面(UI)驱动的 ML——还没有实现,但是暂时想象一下,我们在市场上出现了许多为这些用户提供 UI 驱动能力的 ML 平台。毫无疑问,每个平台的运作方式都不同。几乎每个人都知道如何操作微软 Office,因为它是主导设计——在市场上占主导地位的设计,远远超过类似的产品。以微软 Office 为例,无论你是在家、在办公室还是在学术机构,都是同样的设计。没有主导的设计,就没有跨组织、领域和工具的一致和简化的用户体验。

快速迭代,其中 ML 代码只是一小部分

像通用软件系统这样的 ML 平台需要是可靠的、可扩展的和可维护的,此外还要具有适应性,因为它们是从数据中学习的系统——这些数据可能会频繁地改变,从而需要快速的开发和部署周期。此外,目前 ML 通常是一个固有的经验过程,其成功部分与实验产量成比例,需要快速迭代。然而,与传统系统不同,在传统系统中编程是最难的部分,在 ML 中编程只是全部工作的一小部分,并且处理从所有不同组件引入的技术债务是对吞吐量的重大限制。

机器学习系统中隐藏的技术债务。来源

备注:
深度学习系统中真实故障的分类

框架和 API

部署在野外的 ML 可以类似于模型和算法的九头蛇。部署可以包括主成分分析梯度增强神经网络的集合。就 ML 平台而言,支持框架和库的决定受到深度学习的严重影响,尽管仅支持深度学习是完全不够的。

支持主要的深度学习框架和库,如 PyTorchTensorFlow ,将 API 的带入画面。考虑到没有总体标准或主导设计的恶劣环境,有太多开发和维护成本高昂的 API。API 需要开源,以确保架构保持开放,组织不会被迫使用专有技术栈。此外,需要开发和访问作为单一接口的数据编排规则和 API,以支持跨分布式环境的部署 ML(参见 ModelOps)。这表明需要一个更加通用的平台,减少多样化。

重新思考建筑

我们需要重新思考支持 ML 的生态系统的设计,特别是在数据方面——这就是现在所说的“以数据为中心”的 ML 方法。

是追求面向数据的架构(DOA)还是微服务架构是需要在这方面进行的重要讨论。DOA 方法本质上是一种基于流的体系结构,它使业务逻辑元素之间的数据流动更加明确和可访问,从而简化了数据发现、收集和标记等任务。然而,微服务架构由于其可扩展性而非常普遍。

备注: 现代面向数据编程米兰:面向数据编程的一次进化面向数据架构

开源作为一种标准

虽然没有针对 ML 平台的主流设计,但是开源已经成为标准方法。这有很多原因,在初创公司的情况下,组织经常需要这样做,以便在初创公司失败的情况下,他们可以访问源代码。追求开源也意味着初创公司现在要与现有的开源工具竞争,必须确定一个可行的商业模式,其中包括专有和开源功能的某种混合。对于一家初创公司来说,这绝非易事。例如,如果你是一个像谷歌这样的大型组织,你可以从业务的盈利部分引导资金来支持 TensorFlow 上的开源工作,以创建一个具有网络效应良性循环的生态系统——使用该框架的人越多,了解它的人越多,反过来又会带来更多的用户——从而形成一个大型的可持续生态系统,其中有机会将谷歌云平台等专有工具和服务货币化。据传,谷歌的 TensorFlow 团队有近 1000 人。

就 ML 平台而言,我还没有看到很多机会 1)围绕特定工具建立一个大型开源用户社区,以及 2)从其他来源获得收入的机会,这些机会可以为建立这样一个社区提供长期资金。

备注: Linux 基础 AI 与数据ml flowH2O

关注一个狭窄的用例

许多初创公司现在正试图开发服务于特定领域的 ML 平台,这将初创公司局限于较小的市场和用户群。我的论点是,任何 ML 平台必须对用例不可知,因为核心底层技术不是特定于领域的。由于基础技术的应用将不会局限于单个领域,人们将会发现,建立一个持久的护城河来防止其他人(因为他们服务于更大的市场而拥有更大的基础)侵犯狭窄的用例的能力是不够的。

注释: 告别“发现药物的沃森”

关注工作流程中的一小步

一个 ML 工具(我称之为“工具”,因为它不是一个一体化的产品)只支持 ML 生命周期的一部分,比如模型训练和评估,不可避免地需要一个组织将多个工具缝合在一起。由于 ML 堆栈中的产品在不断发展,并且没有通用的接口行业标准,开发和维护跨 ML 工作流的必要集成的成本是不小的。除了所有令人头疼的集成问题之外,用户必须熟悉使用多种工具和用户界面所带来的问题也阻碍了它的采用。

对于一个大型技术组织来说,ML 是产品和服务的核心组成部分,在缺乏主导设计的情况下,将工具缝合在一起以创建 ML 平台是当前的方法。这些组织(与大多数不同)拥有必要的技能、专业知识、经验和资源来投入这项工作。这样的组织通常将重点放在互操作性上,以构建跨越整个工作流的集成解决方案,对于他们来说,平台只处理组织所支持的产品和服务的用例就足够了。

备注: 遇见米开朗基罗:优步的机器学习平台用 Twitter 上的工作流制作 MLTFX:一个基于 TensorFlow 的量产级机器学习平台引入 FBLearner Flow:脸书的 AI 骨干

紧密耦合的组件

ML 开发和部署环境在组织间是异构的,与上游和下游软件组件耦合过紧的 ML 平台将限制其可移植性。类似地,如果 ML 平台与特定的硬件加速器过于紧密地耦合,那么它本身就会受限于对该硬件的采用。在这种情况下,初创公司需要小心谨慎,以确保它不是在为其市场的未来押注于采用特定的硬件或软件。一个 ML 平台需要在尽可能多的环境中工作,并且在尽可能多的硬件配置上工作,这给我们带来了模型操作和领域特定的架构。

进入 ModelOps

为了避免与生产中隐藏的技术债务相关的问题的出现,模型操作( ModelOps )关注用于在现实世界生产中测试、部署、管理和监控 ML 模型的最佳实践和工具。ModelOps 尤其适用于管理跨组织运行的底层异构软件和基础设施堆栈环境中的模型演变和数据变更。

随着组织转向云,主要的云提供商现在正在寻求将 ModelOps 与组织基础设施的其余部分相集成,这推动了对跨各种 ML 工具和服务的开放集成的重新关注。然而,主要云提供商的这种方法说起来容易做起来难,因为大多数人已经花了几年时间围绕他们的产品和服务建立专有墙。在这些平台真正开放之前,这些产品是否会成为 ML 平台的主流设计是有疑问的。

输入特定领域的架构

特定领域架构(DSA)通常称为加速器,是一类为特定领域定制的处理器。这种以硬件为中心的方法是由性能和效率增益驱动的,因为它们是根据应用的需求定制的。DSA 的例子包括张量处理单元 (TPU 的),以及图形处理单元 (GPU 的)。DSA 使用领域特定语言(DSL)来利用内存访问、并行性并改善应用程序到领域特定处理器的映射。DSL 是一个挑战,虽然是为特定的架构设计的,但是软件需要可移植到不同的环境。

DSA 的硬件/软件协同设计的垂直集成也支持开放式体系结构,因为这增加了用户数量并提高了安全性。

Python 这样的编程语言在 ML 环境下会发生什么,这个问题仍然悬而未决。构建一门语言是一项堆积如山的工作,以 ML 的发展速度来看,这需要的时间太长了。看看现有的,最好的选择似乎是朱莉娅或斯威夫特。目前,Swift 在 ML 生态系统中的存在不多,主要用于 iOS 应用程序,但近年来,苹果和谷歌都在朝着类似的方向发展,谷歌方面有 S4TF —用于 TensorFlow 的 Swift。

注意: Graphcore 杨树大脑机器学习系统都陷入了墨守成规手电筒:快速灵活的机器学习在 C++中

不了解要求

ML 平台缺乏主导设计导致许多人对最终需求理解不足——ML 平台的构建者经常不知道他们不知道什么。这导致 1)组织严重低估了任务的范围和复杂性,以及 2)决策是在可疑的基础上做出的(并且是合理的)。初创公司认为,只要有几个工程师,他们就能让一些东西运转起来。行业中的非软件技术公司认为这可以归结为是构建还是购买。在外部资助机构的帮助和支持下,学术机构自欺欺人地认为开发一个人工智能平台是他们研究工作的一部分,是对资源的一种很好的利用。

除了无知、政治和封地建设,建造偏见的一个主要因素来自人们对自己作品的喜爱——尽管它可能很糟糕,但建造它的人赋予它更多的价值。现实是,大多数公司都严重缺乏资源来实现卓越的执行力,以对抗像 PalantirC3.aiDatabricks 等已经有了几年的跑道并为此投入了大量资源的公司,这些公司可能无法成功成为盈利的独立企业。

自动化。来源

对于大多数组织来说,ML 的价值在于应用,而不在于构建和维护 ML 平台,这似乎是显而易见的,然而缺乏主导设计和对需求的理解导致许多人做出糟糕的购买决策。最终,这为创业公司提供了一个围绕特定组织需求提供专业服务的机会,然而,与那些构建工具和平台相比,这一领域的创业活动和牵引力要少得多。

结论

最终,市场将解决关于 ML 平台的任何主导设计的争论。这一过程的一部分将是金融状况的演变。处于 4000 年最低点的利率误导了资本,促进了投机,并延续了不可持续企业的非自然生命。当资本最终被重新定价时,ML 市场中许多大小厂商的消亡,以及行业最终成熟的顶点将导致整合的机会,并鼓励某种主导设计的发展。

在此期间,ML 平台的提供商和用户应该更战略性地考虑所提出的问题,以实现持久的价值创造解决方案。

附加资源: 即将到来的 ML 系统浪潮斯坦福 MLSys 研讨会系列全栈深度学习芯片虎眼

使用 spaCy 3.0 转换器构建情感分类器

原文:https://towardsdatascience.com/building-sentiment-classifier-using-spacy-3-0-transformers-c744bfc767b?source=collection_archive---------9-----------------------

使用 spaCy 3.0 构建文本分类模型

图片来自 Pixabay卡洛琳·许梅尔斯

我使用 spaCy 已经有一段时间了,因为它在生产中易于使用,而且 API 简洁、用户友好。该库由 Matthew Honnibal 和 Ines Montani 开发,他们是 Explosion.ai 公司的创始人。他们在 2021 年 2 月 1 日发布了 spaCy 3.0 版本,并添加了最先进的基于变压器的管道。此外,3.0 版还提供了新的配置系统和培训工作流程。在本文中,我展示了使用 spaCy version 3.0 和 Transformer 模型,用很少的几行代码构建一个情感分类器是多么简单。

我从 Kaggle 获取了财经新闻数据集,构建了一个情感分类器,并使用了 Google Colab。

装置

*# Installing Spacy library*

!pip install spacy==3.1.1
!pip install spacy-transformers

接下来,下载预先训练好的 transformer 模型。这里,模型是使用 BERT-base 架构的 Roberta-base。更多详情,请查看此处

*# Downloading the spaCy Transformer model "en_core_web_trf"*
!python -m spacy download en_core_web_trf

导入必要的库

*# Importing libraries*

import pandas as pd
from datetime import datetime
import spacy
import spacy_transformers

*# Storing docs in binary format*
from spacy.tokens import DocBin

读取数据集

*# Reading the dataset*
df = pd.read_csv("Data1.csv", encoding='latin-1')
df.head()

这个数据集是关于金融新闻及其相应的情绪。数据有三个标签,正面,负面,中性。让我们读一些随机文本

df[‘Text’][2]

上述文字被归类为“负面”。让我们读一篇正面的课文

df['Text'][3]

以上文字归类为“正面”。

检查数据集的形状

df.shape

该数据有 4846 个观察值。由于训练时间的原因,我在本文中选择了一个小数据集。

分割数据集

将数据集拆分为 80:20 比例的训练和测试

*#Splitting the dataset into train and test*train = df.sample(frac = 0.8, random_state = 25)
test = df.drop(train.index)

检查形状

*# Checking the shape*

print(train.shape, test.shape)

输出

将变压器模型加载到空间管道

**import** **spacy**
nlp=spacy.load("en_core_web_trf") 

训练数据集

在 3.0 版中,我们需要创建二进制格式的训练数据集来训练模型。第一步是创建元组,元组是带有情感的文本对。为训练和测试数据集创建元组。

#Creating tuplestrain['tuples'] = train.apply(**lambda** row (row['Text'],row['Sentiment']), axis=1)train = train['tuples'].tolist()test['tuples'] = test.apply(**lambda** row: (row['Text'],row['Sentiment']), axis=1)
test = test['tuples'].tolist()train[0]

第二步是在 transformer 模型(en_core_web_trf)的帮助下,使用名为nlp的空间管道为训练和测试数据集中的每个元组创建一个空间文档。每个元组只不过是文本和它的情感。

# User function for converting the train and test dataset into spaCy document**def** document(data):
#Creating empty list called "text" text = []
  **for** doc, label **in** nlp.pipe(data, as_tuples = **True**):
    **if** (label=='positive'):
      doc.cats['positive'] = 1
      doc.cats['negative'] = 0
      doc.cats['neutral']  = 0
    **elif** (label=='negative'):
      doc.cats['positive'] = 0
      doc.cats['negative'] = 1
      doc.cats['neutral']  = 0
    **else**:
      doc.cats['positive'] = 0
      doc.cats['negative'] = 0
      doc.cats['neutral']  = 1
#Adding the doc into the list 'text'
      text.append(doc)
  **return**(text)

创建了上面这个名为document的用户自定义函数。在这里,处理文本并添加到空间文档,并为每个情感添加类别。如果文本具有正面情感,那么它被分配为‘1’,并且对于中性和负面都是相同的。然后每个doc被添加到名为text的列表中。最后的text是文本的内部空间表示。

将训练和测试数据集转换为二进制格式

train数据集传递给document函数,并保存为train_docs对象。然后使用DocBin spaCy 函数将文本转换成二进制对象,并将训练数据集二进制对象保存为train.spacy

*# Calculate the time for converting into binary document for train dataset*

start_time = datetime.now()

*#passing the train dataset into function 'document'*
train_docs = document(train)

*#Creating binary document using DocBin function in spaCy*
doc_bin = DocBin(docs = train_docs)

*#Saving the binary document as train.spacy*
doc_bin.to_disk("train.spacy")
end_time = datetime.now()

*#Printing the time duration for train dataset*
print('Duration: **{}**'.format(end_time - start_time))

在 Google Colab 中将训练数据集转换为二进制对象花费了将近 7 分钟。

我们必须对测试数据集做同样的事情。将test数据集传递给document函数,并将其保存为test_docs对象。然后使用DocBin spaCy 函数将文本转换成二进制对象,并将测试数据集二进制对象保存为test.spacy

*# Calculate the time for converting into binary document for test dataset*

start_time = datetime.now()

*#passing the test dataset into function 'document'*
test_docs = document(test)
doc_bin = DocBin(docs = test_docs)
doc_bin.to_disk("valid.spacy")
end_time = datetime.now()

*#Printing the time duration for test dataset*
print('Duration: **{}**'.format(end_time - start_time))

在 Google Colab 中将测试数据集转换成二进制对象需要 1.40 分钟。现在,我们已经按照所需的空间格式将数据输入到二进制对象中。

训练模型

下一步,训练模型。在 3.0 版本中,spaCy 提供了一个命令行界面来执行培训。为此,我们需要从这个站点下载基本配置文件。在下载之前,我们需要选择组件下的textcat,因为这是一个分类问题。我选择了硬件GPU,就像我使用 google colab 和选择accuracy一样。

作者图片

我们可以在记事本中打开基本配置文件,并需要为配置文件的train = “train.spacy"dev = "test.spacy".截图指定路径,如下所示

作者图片

下一步是使用基本配置,并使用下面的代码将其转换为我们分类的完整配置。以下代码可从 spaCy 网站获得。完整的配置文件将作为config.cfg保存在您的路径文件夹中

*#Converting base configuration into full config file*

!python -m spacy init fill-config ./base_config.cfg ./config.cfg

配置文件具有用于训练分类的所有模型参数。我在本文中使用了默认参数并训练了分类。现在,我们需要使用下面的代码来训练我们的模型。同样,代码也可以在 spaCy 网站上找到。我通过添加--gpu-id 0启用了 GPU,模型输出保存在一个名为output_updated.的文件夹中

#Calculating the time for training the model
start_time = datetime.now()# To train the model. Enabled GPU and storing the model output in folder called output_updated
!python -m spacy train config.cfg --verbose  --gpu-id 0 --output ./output_updated

end_time = datetime.now()#Printing the time taken for training the model
print('Duration: **{}**'.format(end_time - start_time))

输出

在 GPU 下的 Google Colab 中训练模型花了 37 分钟。上面的输出显示了每个训练步骤的损失和准确性。我可以看到这个模型的精确度是 0.85。训练后,模型被保存在output_updated/model-last.文件夹中

测试模型

现在我们的模型准备好了。让我们用一些随机文本进行测试

text = “Australia’s largest airline temporarily lays off 2,500 employees”*# Loading the best model from output_updated folder*
nlp = spacy.load("output_updated/model-best")
demo = nlp(text)
print(demo.cats)

输出

负分很高,它被正确地归类为阴性。让我们试着用一些正面的文字

text1 = “Apple earnings: Huge iPhone 12 sales beat analyst expectations”
demo = nlp(text1) 
print(demo.cats)

输出

是的,文本的情绪是积极的,因为积极的分数很高。型号分类正确。

本文的目的是演示如何使用 spaCy transformers 3.0 进行文本分类。我们可以更改配置文件中的参数来提高模型性能。

你可以在我的 GitHub repo 中找到完整的代码和数据。

你可能也喜欢我以前的文章spaCy 自然语言处理——步骤和例子

感谢阅读。

构建小型服务,部署在 Kubernetes 上,并与 API Gateway 集成

原文:https://towardsdatascience.com/building-small-services-deploying-on-kubernetes-and-integrating-with-api-gateway-4909db4e5282?source=collection_archive---------11-----------------------

用 Python 和 Redis 抽象后端 API 认证

亚历杭德罗·埃斯卡米拉在 Unsplash 上的照片

最近,我正致力于后端系统与 API 网关的集成。后端系统有自己的 API,但没有身份验证。或者我应该说,它有认证,但只适用于单个用户。也就是说,所有客户端将使用相同的用户名和密码来获取后端系统提供的令牌,并使用该令牌向后端发送 API 请求。这当然不理想,所有的 API 用户都使用同一个帐户。应该考虑到后端系统根本没有认证。

为了应对这种情况,我们希望将后端与 API 网关集成在一起,并将身份验证卸载到 API 网关。特别是,所有 API 用户都将拥有由 API 网关提供的自己的帐户和 API 密钥。当他们向 API 网关发送 API 请求时,API 网关用这个帐户向后端系统发送请求。因此认证功能是在 API 网关上执行的。

我们需要解决两个主要问题。

第一个是如何对 API 用户隐藏后端系统的令牌获取过程。我们不希望 API 用户知道任何关于后端系统认证的事情。所有的认证(使用 API 密钥或 OAuth 或任何其他认证方法)都应该由 API 网关来处理。API 用户仅使用 API 网关进行身份验证。

第二个是我们如何存储后端返回的令牌,并让 API 网关在令牌过期之前为将来的请求使用相同的令牌。我们不希望 API 网关每次收到新请求时都从后端系统生成新令牌,因为这可能会增加服务器负载。

API 网关为所有客户端提供单一入口点。它有一个名为 Mashups 的功能,可以组织和编排多个 API,并将它们作为单个 API 公开。当客户端发送一个 API 请求时,API 网关首先从我们新构建的令牌服务中获取一个令牌,捕获返回的令牌,然后使用该令牌调用后端 API。下图说明了流程。

新 API 请求的基本流程(图片由作者提供)

服务工作流程

我们新建的令牌服务工作流程如下:

  1. 当一个新的请求到来时,API gateway 调用令牌服务
  2. 令牌服务检查 Redis 是否包含有效令牌
  3. 如果 Redis 有令牌值,它返回
  4. 如果没有,令牌服务将向后端系统发送令牌请求
  5. 后端系统返回一个新生成的带有到期日期的令牌
  6. 令牌服务设置一个密钥来保存具有相关超时值的令牌值
  7. 令牌服务返回令牌(从 Redis 或后端系统)
  8. API 网关将带有收到的令牌的原始请求发送到原始后端 API 端点

我们新建的令牌服务工作流程(图片由作者提供)

设置 Redis 和 RedisInsight

为了继续上面的工作流程,我们在 Kubernetes 上安装并设置了一个 Redis 数据库。为了监控 Redis,我们使用了 RedisInsight。在 Kubernetes 上设置 Redis 最简单的方法是通过 Bitnami 的图表:

helm repo add bitnami [https://charts.bitnami.com/bitnami](https://charts.bitnami.com/bitnami)
helm install my-release bitnami/redis

所有 pod 运行后,您可以通过集群中以下 DNS 名称上的端口 6379 访问 Redis:

my-release-redis-master.default.svc.cluster.local for read/write operations
my-release-redis-slave.default.svc.cluster.local for read-only operations

要访问 Kubernetes 集群外部的 Redis,需要将 helm chart 值中的主服务器的服务类型设置为 LoadBalancer:

master:
  service:
    type: LoadBalancer

通过kubectl get svc -n redis,可以获得 Redis 的外部访问 IP。回应会是这样的:

# kubectl get svc -n redisNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-headless ClusterIP None <none> 6379/TCP 187d
redis-master LoadBalancer 10.233.50.103 172.16.100.223 6379:31808/TCP 187d
redis-slave ClusterIP 10.233.23.109 <none> 6379/TCP 187d

https://redislabs.com/redis-enterprise/redis-insight/

要使用 GUI 监控和管理 Redis,可以在 macOS、Linux 或 Windows 上安装 RedisInsight。安装后可以通过 http://localhost:8001/ 访问 UI。连接到 Redis 实例后,您应该会看到以下页面:

RedisInsight 的 GUI 视图(图片由作者提供)

其中,您可以监控您的 Redis 状态,通过 CLI 通信 Redis,最重要的是,您可以在浏览器中检查您的令牌。

将 Python 客户端连接到 Redis

有一个很好的 Python 包叫做 redis-py。它提供了从 python 代码到 Redis 实例的接口。以下代码片段将我们的 Python 应用程序连接到 Redis:

import redis
import sys
import osdef redis_connect() -> redis.client.Redis:
    REDIS_HOST = os.getenv("REDIS_HOST")
    REDIS_PW = os.getenv("REDIS_PW") try:
        client = redis.Redis(
            host=REDIS_HOST,
            port=6379,
            password=REDIS_PW,
            db=0,
            socket_timeout=5,
        )
        ping = client.ping()
        if ping is True:
            return client
    except redis.AuthenticationError:
        print(“AuthenticationError”)
        sys.exit(1)

注意,我通过 OS 环境提供了 Redis 的主机和密码,稍后当我们的服务部署在 Kubernetes 上时,将由 ConfigMap 提供。我把上面的代码片段放在了redis_client.py中,这样我就可以在其他文件中导入redis_connect函数。

从后端 API 获取令牌

下面的函数从后端系统获取令牌。

import requestsdef get_token_from_api() -> str:
    """Token from backend API.""" with requests.Session() as session:
        base_url = os.getenv("BASE_URL")
        api_key = os.getenv("API_KEY") url = f"{base_url}/token session.headers.update({"backend-APIKey": api_key}) response = session.get(url)
        token = response.json()["token"] return token

base_url是后端 API 的基本 URL,url添加了获取令牌的端点。我们还需要在头中提供后端系统用来认证的 API 密钥。后端系统将返回一个有效的令牌。

如果你没有这样的后台系统,但你仍然想跟进,我建议你把网址改为http://www.httpbin.org/uuid。它将返回一个 UUID,你可以把它当作一个令牌。而且你还需要把对应的行改成response.json()[“uuid”]才能得到结果。

从 Redis 数据库中检索和设置令牌

通过下面简单的逻辑函数,我们可以检查令牌是否存在,如果存在,就从 Redis 中检索令牌。如果它不存在,我们从前面的函数中获取令牌,并将令牌设置为 Redis,超时值略小于原始到期日期。超时后,令牌将在 Redis 中自动删除,这将触发我们的服务直接从后端系统获取令牌。

def return_token():
    if client.exists("token"):
        token = client.get("token")
    else:
        token = get_token_from_api()
        result = client.setex(
            "token",
            timedelta(minutes=30),
            value=token
            )
        print(result) return { "token": token }

作为 API 公开

我们的令牌服务的所有构件都已经准备好了,下一步是将它们公开为一个 API。我用 FastAPI 来构建 API。顾名思义,就是快!就性能而言,还有快!就编码时间而言,和一样快!在学习时间方面。

https://fastapi.tiangolo.com/

from fastapi import FastAPIapp = FastAPI()@app.get("/token")
def return_token():
…

正如我们在上面看到的,你只需要用 app.get (HTTP 方法)包装你的函数,你就已经有了一个可用的 API 端点。

把所有的放在一起

import requests
from datetime import timedelta
from fastapi import FastAPI
from redis_client import redis_connectclient = redis_connect()app = FastAPI()def get_token_from_api() -> str:
    """Token from backend API.""" with requests.Session() as session:
        base_url = os.getenv("BASE_URL")
        api_key = os.getenv("API_KEY") url = f"{base_url}/token session.headers.update({"backend-APIKey": api_key}) response = session.get(url)
        token = response.json()["token"] return token @app.get("/token")
def return_token():
    if client.exists("token"):
        token = client.get("token")
    else:
        token = get_token_from_api()
        result = client.setex(
            "token",
            timedelta(minutes=30),
            value=token
            )
        print(result)return { "token": token }

我们完了!让我们在 localhost 中试试我们的应用程序吧!

FastAPI 的安装很容易,用pip install fastapi安装 FastAPI 本身,然后用pip install uvicorn安装 ASGI 服务器。之后,使用uvicorn main:app –reload运行服务器

INFO: Uvicorn running on [http://127.0.0.1:8000](http://127.0.0.1:8000) (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.

我们去参观的时候 127.0.0.1:8000/token。嘿,我们拿到代币了!

服务传回令牌(作者图片)

转到 RedisInsight,在浏览器页面中,我们还应该看到您的令牌在那里。

令牌存储在 Redis(作者图片)中

好吧!我们的应用程序完成了。我们接下来要做的是在 Kubernetes 上部署服务。首先,我们需要建立自己的码头工人形象。在您的 docker 文件中,使用基本映像和要求

FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7COPY ./app /appRUN pip install -r requirements.txt

目录结构应该如下所示:

.
├── Dockerfile
├── app
│   ├── main.py
│   ├── redis_client.py
│   └── requirements.txt

使用docker build –t tokenservice ./建立自己的形象,然后推送到 Docker Hub 或者自己的私人注册处。如果您将您的图像推送到 Docker Hub,您应该使用docker login登录您的 Docker Hub 帐户,然后使用docker tag tokenservice <yourdockerhubaccount>/<yourrepository>:tokenservice标记您的图像。最后你用docker push <yourdockerhubaccount>/<yourrepository>:tokenservice推送你的图片。

在 Kubernetes 部署

接下来,我们需要准备我们的 Kubernetes YAML 文件,以便将我们的服务部署到 Kubernetes。我们将为这个服务的环境变量部署一个部署、一个服务和一个配置映射。

配置图

将所有环境变量(Redis 主机和密码、后端 URL 和 API-Key)放在。env 文件,并使用以下命令创建一个配置映射:kubectl create configmap tokenservice-env-file --from-env-file=.env

部署

之后,我们使用以下 YAML 文件配置 pod 以使用配置映射:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tokenservice
  labels:
    app: tokenservice
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tokenservice
  template:
    metadata:
      labels:
        app: tokenservice
    spec:
      containers:
      - name: tokenservice
        image: <yourdockerhubaccount>/<yourrepository>:tokenservice
        ports:
        - containerPort: 80
        envFrom:
        - configMapRef:
          name: tokenservice-env

您可以根据需要设置任意数量的副本。点击此链接了解更多信息:

https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/

过一会儿,您会看到所有的 pod(在本例中是 3 个)都在运行。

令牌服务的 pod 正在运行!(图片由作者提供)

服务

下一步是使用 Kubernetes 服务公开我们的应用程序。我们将使用 LoadBalancer 公开我们的应用程序。记住将您的选择器与您在部署中指定的标签相匹配。

apiVersion: v1
kind: Service
metadata:
  name: tokenservice
spec:
  selector:
    app: tokenservice
  ports:
    - protocol: TCP
      port: 80
  type: LoadBalancer

与 API 网关集成

根据您使用的 API 网关的不同,API 网关上的 API 创建可能会有所不同,但一般过程几乎是相同的。我们可以使用 swagger 文件导入我们的 API,或者从头开始创建它。

好消息是,FastAPI 已经为我们生成了 OpenAPI 文件。去http://127 . 0 . 0 . 1:8000/docs可以找到 openapi.json 链接。

你可以在 127.0.0.1:8000/docs 中查看你的 API 规范(图片由作者提供)

FastAPI 已经生成了 OpenAPI 规范。(图片由作者提供)

虽然它只是一个简单的 OpenAPI 文件,没有太多关于 API 的描述和信息,但它足以让我们将它导入 API 网关并公开我们的服务。在 webMethods API Gateway 中,我们可以通过导入 OpenAPI 文件来轻松创建我们的 API。

从文件导入 API(图片由作者提供)

我们只需要将端点 URI 更改为上一步中获得的负载平衡器 IP。

更改为将端点 URI 路由到我们服务的负载平衡器 IP(图片由作者提供)

然后,我们可以使用 Mashups 创建一个新的 API 来实现我们在开始时看到的流程。也就是先从令牌服务获取令牌,然后调用原来的 API。在下图中, getToken 流程从我们刚刚创建的 tokenservice API 获取令牌,然后将响应有效负载传递给下一步 callFlow ,这是原始的后端服务。

我们新 API 的混搭流(图片由作者提供)

正如您在上面的图片中看到的,我们将得到的令牌添加到第二个调用的头部,并透明地传递来自最终用户的所有有效负载。

最后,我们用 Python 和 Redis 实现了抽象后端 API 认证的服务。

结论

在本文中,我演示了构建一个与后端系统一起工作的小服务、将其部署在 Kubernetes 上,以及将该服务与 API 网关集成以便其他人可以轻松地向后端系统发送 HTTP 请求的设计流程。这个项目涉及广泛的技术堆栈,我真的很喜欢这个开发过程。希望我能与你分享更多的开发经验。

如果你想知道更多关于我们在 Kubernetes 上能做什么,请查看这篇文章。在那篇文章中,我展示了如何在本地 Kubernetes 集群上部署 Apache Airflow。

从语音到文本的单词时间戳构建字幕文本

原文:https://towardsdatascience.com/building-subtitle-text-from-speech-to-texts-word-timestamps-27a133e2a89e?source=collection_archive---------14-----------------------

一个适用于所有语言的简单技巧

照片由伊莫·威格曼Unsplash 上拍摄

语音到文本功能最近发展势头强劲,因为它为用户提供了全新的用户体验。它被市场上的公司广泛采用,尤其是在客户服务行业。事实上,像谷歌和微软这样的大公司提供了他们自己的语音转文本 API 作为他们技术的一部分。

供您参考,大多数高级语音到文本 API 都带有单词级时间戳。

谷歌的语音转文本 API

例如,当运行谷歌的语音转文本 API 时,您会得到以下输出:

[
    {
        "startTime": "1.400s",
        "endTime": "1.800s",
        "word": "okay"
    },
    {
        "startTime": "1.800s",
        "endTime": "2.300s",
        "word": "so"
    },
    ...
]

Azure 的语音转文本 API

另一方面,微软有自己的 Azure 的语音转文本服务,它返回以下结果:

[
    {
        "Duration": 5500000,
        "Offset": 7800000,
        "Word": "seven"
    },
    {
        "Duration": 2700000,
        "Offset": 13400000,
        "Word": "three"
    },
    ...
]

这两个 API 表面上看起来都很有前途,但如果你打算使用输出来构建字幕,那就有一个大问题,那就是将它们组合成不太短也不太长的句子。如果最终文本是英文,您仍然可以根据某些标点符号进行后处理和拆分,例如:

[',', '.', '!', '?']

在 Azure 的情况下,这是不可能的,因为单词级时间戳中的文本是基于词法的(没有大写和标点)。此外,转录后的显示文本处于听写模式,这不同于单词级时间戳中的文本。例如,显示文本:

007 James Bond

将具有以下单词级时间戳:

[
    {
        "Duration": 2700000,
        "Offset": 35600000,
        "Word": "double"
    },
    {
        "Duration": 700000,
        "Offset": 38400000,
        "Word": "oh"
    },
    {
        "Duration": 4900000,
        "Offset": 39200000,
        "Word": "seven"
    },
    {
         "Duration": 3900000,
         "Offset": 44400000,
         "Word": "james"
    },
    {
         "Duration": 3300000,
         "Offset": 48400000,
         "Word": "bond"
    }
]

因此,您没有办法基于数组映射结果,因为长度和文本在某些地方是不同的。在撰写本文时,开发人员已经澄清在单词级时间戳中不支持听写和标点符号模式。

如果你打算支持多种语言,事情会复杂得多。这主要是因为每种语言都有自己的标点符号,某些语言不能用空格来标记。

使用时间戳将单词拆分成句子

经过几轮实验,我找到了一个简单的窍门,把输出的单词拆分成句子。这种方法对大多数语言来说都很有效,因为它不依赖于输出文本。要点是浏览整个列表,并计算它们之间的空白间隙的长度。如果长度超过给定的阈值,则将其视为断句。

请看下图作为参考:

作者图片

在这种情况下,你会以两句话结束:

  • 据报道
  • 五人受伤

除了与语言无关之外,您还可以根据自己的偏好微调阈值,以便获得最佳的分割效果。

让我们继续下一部分,开始写一些代码。

履行

本教程将使用 Azure 语音转文本的输出作为后处理的参考。此外,为了简单起见,代码将以 Python 呈现。话虽如此,你可以很容易地将其转换成其他编程语言,因为不涉及任何外部包。

初始化

在工作目录中创建一个新的 Python 文件,并使用以下变量对其进行初始化:

将纳秒转换为秒

到现在为止,你应该已经注意到OffsetDuration都是以纳秒为单位的。让我们创建一个函数,将输入的纳秒转换为两位小数的秒:

def get_seconds(nanoseconds):
    return round(nanoseconds / 10000000, 2)

把单词组成句子

我们将需要一个功能来连接成一个句子的话。为了支持多种语言,您可以设置一个条件语句来确定输入语言,并使用适当的分隔符连接单词。例如:

def join_words(words, lang):
    if lang == 'ja-JP' or lang == 'th-TH':
        return ''.join(words) return ' '.join(words)

在这种情况下,泰语和日语没有空格,而其他语言由空格分隔。根据自己的喜好做相应的修改。

检查差异

下一步是实现后处理功能。在此之前,让我们根据列表的长度遍历列表,并计算每个单词之间的间隔长度的差异。

循环将从 0 开始,到列表总长度减 1 结束。这主要是因为差异的计算如下:

Offset of next word - (Offset + Duration of current word)

您应该在控制台上看到以下输出(没有箭头标记):

0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.25  <--
0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.41  <--
0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.01
0.01

造句

有两个持续时间超过给定阈值 0.1 的实例。注释掉print语句,并将循环修改如下:

代码的工作方式如下:

  • 计算差异
  • 如果令牌为空,则设置start,表示句子开始
  • 如果差异超过阈值,则构建句子,将信息作为字典添加到timestamp变量中,清除tokens并将start设置为下一个Offset
  • 如果到了倒数第二个字,加入最后一个字并退出循环

请注意,上面的实现使用Offset + Duration作为end时间。根据自己的喜好做相应的修改。

可能有这样的情况,它只返回列表中的一个条目。在这种情况下,循环将退出并返回一个空列表。您可以通过添加如下条件检查语句来轻松处理这一问题:

if len(data) == 1:
    timestamp.append({'segment': data[0]['Word'], 'start': get_seconds(data[0]['Offset']), 'end': get_seconds(data[0]['Offset'] + data[0]['Duration'])})
else:
    # the rest of the code (loop)
    ...

你可以在下面的要点找到完整的代码:

测试和输出

按如下方式运行它:

python script.py

您应该得到以下输出:

[{'segment': 'average household income is up ten percent from four years ago', 'start': 5.11, 'end': 8.52}, {'segment': 'and our customers are spending twenty percent more per transaction', 'start': 8.77, 'end': 12.12}, {'segment': 'nearly everyone surveyed is employed in a professional or managerial occupation', 'start': 12.53, 'end': 16.8}]

您可以使用输出列表来构建自己的字幕文件,无论是 SRT 还是 VTT 格式。例如,转换后的 SRT 文件应该如下所示:

1
00:00:05,110 --> 00:00:08,520
average household income is up ten percent from four years ago2
00:00:08,770 --> 00:00:12,120
and our customers are spending twenty percent more per transaction3
00:00:12,530 --> 00:00:16,800
nearly everyone surveyed is employed in a professional or managerial occupation

对于 VTT,输出应该如下所示:

WEBVTT00:00:05.110 --> 00:00:08.520
average household income is up ten percent from four years ago00:00:08.770 --> 00:00:12.120
and our customers are spending twenty percent more per transaction00:00:12.530 --> 00:00:16.800
nearly everyone surveyed is employed in a professional or managerial occupation

结论

让我们回顾一下你今天所学的内容。

本文首先简要解释了语音到文本,以及开发人员在使用语音到文本 API 输出的单词级时间戳时面临的问题。

然后,它提出了一个独立于语言的工作解决方案,即根据每个单词之间的空白进行拆分。

它继续解释了使用 Azure 的语音转文本 API 作为参考输出的实现全过程。最后,您应该会看到一个字典列表,可以用来创建相应的 SRT 或 VTT 格式的字幕文件。

感谢你阅读这篇文章。请随意查看我的其他文章。祝你有美好的一天!

参考

  1. 谷歌语音转文本——获取单词时间戳
  2. Azure 文档—语音转文本快速入门

从机器人应用程序的源代码构建 Tensorflow 1.x C++ API

原文:https://towardsdatascience.com/building-tensorflow-1-x-c-api-from-source-8f22592f183f?source=collection_archive---------24-----------------------

为您的模型构建更加通用的部署

路易·里德Unsplash 上修改的图像。

W 当谈到机器学习时,Tensorflow 是一个无处不在的工具,它简化了你的整个工作流程,允许任何人在短短几分钟内建立和训练一个基本模型。主要是为了集成到 Python 中而开发的,它将复杂的函数和操作与 Python 提供的便利性结合在一起。

然而,我们都知道便利是以牺牲性能为代价的。像 C++或 Java 这样的静态类型语言在编译时检查变量类型是否不变,这样就省去了任何运行时检查。另一方面,Python 是一种动态类型语言,这意味着您可以在运行时更改变量和方法。这引入了运行时检查来最小化任何错误,这就是为什么大多数熟悉静态类型语言的人经常抱怨 Python 很慢。

C++和 Python 用排序算法的时间比较[1]。

事实上,由于大量的变量和函数构成了一个相当大的机器学习模型,Python 的迟缓对训练和推理都是有害的。虽然这种速度上的差异对于一般用途来说很难察觉,但在某些使用情况下却很重要,比如机器人的协同同步定位和地图绘制(CSLAM)。

简而言之,CSLAM 旨在利用一组机器人有效地探索未知环境,同时确定它们在任何时间点的精确位置,并以地图的形式生成它们环境的准确描述。点击阅读更多关于 CSLAM 的内容。

CSLAM 的可视化[2]。

对于执行 CSLAM 的机器人来说,它们需要经历一系列阶段,其中包括利用深度学习模型进行特征检测和位置识别。这有助于他们更好地了解周围环境,并对自己的准确位置更有信心。由于机器人不断移动和收集数据,因此 CSLAM 的实时运行至关重要,以免进度受到阻碍。因此,广泛使用的机器人操作系统(ROS)代码通常用 C++编写,以提高性能。因此,它还将提高使用 Tensorflow C++ API 对深度学习模型进行推理的速度。

顶尖研究人员开发的最先进的深度学习模型倾向于使用更老的 Tensorflow 1.x,而不是更健壮的 2.x ( 讽刺,我知道)。从源代码安装 2.x 非常简单,但是 1.x 几乎没有任何说明,有些链接是断开的。因此,我打算通过编写一个单步脚本来解决这些问题。

先决条件

该脚本假设默认发行版为 Ubuntu 18.04,依赖版本(如 GCC)取决于您使用的发行版。根据您的操作系统随意修改脚本。

CUDA 也是强烈推荐的(但不是必须的)。安装最新版本的说明可以在这里找到。

第一步是安装运行未来命令所需的库:

sudo apt-get update
sudo apt-get install -y build-essential curl git cmake unzip autoconf autogen automake libtool mlocate zlib1g-dev gcc-7 g++-7 wget
sudo apt-get install -y python python3 python3-numpy python3-dev python3-pip python3-wheel
sudo apt-get install -y python3.6 python3.6-dev
sudo updatedb# Set GCC-7 as default
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 100

从源构建张量流

我们使用一个构建工具 Bazel 来安装 Tensorflow。该脚本基于 Tensorflow 的单一版本,具体来说是 Tensorflow 1.14.0。如果您打算安装任何其他版本,请注意 Bazel 的版本也需要更新。要获得 Tensorflow 版本及其依赖项的完整列表,请查看此链接

以下脚本检查 Bazel 的现有版本,并更新到指定版本:

*###--- BAZEL 0.24.1 ---###* BAZEL_VER=`bazel version | grep "Build label" | awk '{print $3}'`
if [[ $BAZEL_VER != "0.24.1" ]]; then
    if [ ! -f bazel-0.24.1-installer-linux-x86_64.sh ]; then
        wget [https://github.com/bazelbuild/bazel/releases/download/0.24.1/bazel-0.24.1-installer-linux-x86_64.sh](https://github.com/bazelbuild/bazel/releases/download/0.24.1/bazel-0.24.1-installer-linux-x86_64.sh)
    fichmod u+x bazel-0.24.1-installer-linux-x86_64.sh
    ./bazel-0.24.1-installer-linux-x86_64.sh
fibazel version

接下来是克隆 Tensorflow GitHub repo:

*###--- TF 1.14.0 ---###* if [ ! -d tensorflow ]; then
    git clone [https://github.com/tensorflow/tensorflow.git](https://github.com/tensorflow/tensorflow.git)
ficd tensorflow
git checkout v1.14.0

如果您尝试运行构建脚本,您很可能会遇到一系列错误,其中之一就是无法下载 Eigen。这是因为原始构建脚本中的镜像链接被破坏了,所以我们需要找到一个替代镜像。

echo "Replacing broken Eigen URLs..."find . -type f -exec sed -i 's/http.*bitbucket.org\/eigen\/eigen\/get/https:\/\/storage.googleapis.com\/mirror.tensorflow.org\/bitbucket.org\/eigen\/eigen\/get/g' {} \;EIGEN_COUNT=`grep -nr "https://storage.googleapis.com/mirror.tensorflow.org/bitbucket.org/eigen/eigen/get/" | wc -l`if [ $EIGEN_COUNT -ne 6 ]; then
    echo "Eigen URLs not updated!"
    echo "Please manually replace all occurrences of"
    echo "http.*bitbucket.org/eigen/eigen/get"
    echo "with"
    echo "https://storage.googleapis.com/mirror.tensorflow.org/bitbucket.org/eigen/eigen/get"
    exit 1
fi

然后,我们可以通过运行脚本下载 Tensorflow 所需的外部库:

chmod u+x tensorflow/contrib/makefile/download_dependencies.sh
./tensorflow/contrib/makefile/download_dependencies.sh

最后一个预处理步骤是将 Protobuf 头文件安装到您的/usr/local/目录中:

*###--- PROTOBUF 3.7.1 ---###* cd tensorflow/contrib/makefile/downloads/protobufgit submodule update --init --recursive
./autogen.sh
./configure
make -j$(nproc)
make check -j$(nproc)sudo make install
sudo ldconfig

终于可以开始编译 Tensorflow 了!在主 Tensorflow 目录中,运行以下命令:

# Configures dependencies versions and what is going to be built
# Customise to your own needs
./configurebazel build --config=opt //tensorflow:libtensorflow_cc.so //tensorflow:install_headers

这个步骤可能需要一个小时,这取决于您的 CPU 可以运行多少个线程,所以喝杯咖啡或去散散步,让您从所有的脚本中清醒过来!

安装顶盖

如果构建没有任何错误的完成,这意味着你已经成功了!剩下要做的就是将相关的头文件安装到您的/usr/local/目录中,这样无论您的项目在哪里,您都可以调用它们:

sudo mkdir /usr/local/tensorflow
sudo cp -r bazel-genfiles/tensorflow/include/ /usr/local/tensorflow/
sudo cp -r /usr/local/include/google/ /usr/local/tensorflow/include/
sudo mkdir /usr/local/tensorflow/lib
sudo cp -r bazel-bin/tensorflow/* /usr/local/tensorflow/lib

测试

如果您想仔细检查是否可以包含没有任何问题的标题,请尝试在 Tensorflow 中运行 Hello World 等效程序:

Tensorflow 中的 Hello World

完整的脚本可以在这里找到。您所需要做的就是运行这个脚本,它将执行所有上述步骤,甚至执行一些自动配置。如果您确实发现了任何错误,请提交问题或请求,并让我知道!

如果你想分享任何想法或观点,请在下面留下评论,或者在 LinkedIn 上给我留言。

参考

[1] F. Zehra,M. Javed,D. Khan,M. Pasha,c++和 Python 在内存和时间方面的比较分析 (2020),Preprints 2020,2020 12 05 16(doi:10.20944/Preprints 202012.0516 . v1)。

[2] R. Dubé,A. Gawel,H. Sommer,J. Nieto,R. Siegwart,C. Cadena,一种用于 3D 激光雷达的在线多机器人 SLAM 系统 (2017),IEEE/RSJ 智能机器人与系统国际会议(IROS)。

最大间隔分类器是优化问题的解决方案

原文:https://towardsdatascience.com/building-the-optimization-problem-of-maximum-margin-classifiers-8da3d2c87369?source=collection_archive---------30-----------------------

背景

人们可以从优化和概率两个角度来看待机器学习问题。这并不令人费解。例如,任何线性回归问题的解决方案通常被认为是通过一组数据点的最佳拟合线。但是你也可以将线上的单个点确定为解释变量的期望值。前者是一个优化视图,而后者展示了一个概率图。最大间隔分类器是支持向量机的基础,也是优化问题的解决方案。在这篇文章中,我们讨论如何。(关于回归的详细概率观点,请查看我的另一篇文章-https://towardsdatascience . com/why-we-use-the-least-square-method-in-regression-analysis-b 7873 e 03 b 253)

1)建立优化问题

我们从一个基本的分类问题开始,逐渐进入一些复杂的问题。考虑下图,一个提供的训练数据的图表。数据点被分成两类——蓝色和粉红色。他们之间有一个明显的,可辨别的分离,一片荒芜的领土,两边各有一点。

用 python 创建

两个组之间的特定线有助于分类。根据它们所处的位置,测试数据点将被分类为蓝色或粉红色。我们的工作是挖掘这条线,一个线性分类器。让我们看看怎么做。(在本文中,我交替使用直线、线性分类器和分类器)

1.1)入门-分类器、区域和边界

在我们继续之前,有一些事情需要解决。首先,分类器必须使得来自训练数据的相似色点必须位于同一侧。第二,许多行都在争夺分类器的位置。在下图中,黑线就是其中的几条。在这些线周围还有一片被遗弃的灰色阴影。这是任何训练观察的禁区,对每个参赛者来说都是独一无二的。姑且称之为量词的 领地

灰色的废弃区域(用 python 创建)

现在,根据上面的图像,您如何定义一个区域的范围?利用界限。在每一侧找到与竞争分类器最近的点。通过这些点平行于分类器绘制的线称为边界。根据对训练观察施加的约束,所有相似的彩色点位于它们各自的 边界 的同一侧。

1.2)分配空白区域

任何分类器的功能都是在训练数据集上学习分类,然后准确地对测试数据点进行分类。他们如何做到这一点,更重要的是,我们如何找到最好的分类器?(注意:训练观察不是分类器领域的一部分。但是,这不适用于测试数据点。)

一个分类器将它的一部分区域分配给每个组。然后,他们对占据其各自区域的所有测试点拥有所有权。让分类器更接近特定的组会导致错误分类。例如,考虑下图。由于新的数据点(十字)更接近蓝色,它可能属于他们。然而,由于它与分类器的相对位置,它被涂成粉红色。为了避免这样的错误,我们必须确保分类器将最大可能区域赋予每组。为什么

用 python 创建

将最大区域授予一个组意味着选择具有最大领域的分类器。该条件还要求两个群体获得相等的份额,并且分类器位于其领域的中间。为什么?如果没有,我们再次引入上面讨论的麻烦。

现在,为了找到分类器的方程,我们需要一个常数。

1.3)支持向量

(用 python 创建)

让我们重温一下 1.1 中定义的边界。我们讨论过它们通过一些特殊的点。这些被称为支持向量。根据边界线的斜率,每一边可能有多个支持向量。也就是说,任一边界都可以通过两个或更多的点。然而,这些点中的一个必须是每侧离分类器最近的点。为什么?否则,我们与训练观测值(1.1)的条件相矛盾

我们知道,对新点进行充分分类需要一个具有最大范围的分类器。它的大小是分类器和它的边界之间的垂直距离(D)的量度。如果你不明白为什么,请记住,边界决定了领土的范围。注意,也可以通过计算支持向量和预期分类器之间的垂直距离来获得 D。为什么因为所有的边界线都经过支持向量。

1.4)引入方程式

好吧,我对我们要设计的东西已经考虑得够多了。让我们从数学上来解读以上所有观点。假设一个方程用于形式为 ax+by+c=0 的分型线(2D 平面中的一条线的方程)。

记住,边界线与分类器的距离相等,并与其平行。我们可以通过在后者的方程中加入一个常数项来把它们的方程连根拔起。本质上,在两个方向上移动一些 C 单位的线产生边界。(C 的符号不重要。数学会照顾到它)

用 C 除所有三个方程,我们得到

我们现在可以进行优化。如前所述,我们选择了离支持向量最大垂直距离的分类器,也称为 、边缘、 。根据坐标几何,计算如下:

距离项的分子很容易计算。因为支持向量位于边界上,所以它必须等于 1。

我们的优化问题现在需要约束。将分类器的方程视为函数 f。将任何蓝点传递给 f 都会产生大于或等于 1 的值。为什么?我们知道,f 在支持向量上的值为 1。因此,对于蓝色支持向量左侧的点,f 超过 1。该约束确保所有蓝点位于同一侧。类似地,对于粉色点,f 将小于或等于-1。

如果我们从数字上将蓝色归类为 1,将粉色归类为-1,并将 f 乘以它们的数字标识,我们得到:

我们的优化问题本质上可以分解为:

该解决方案产生了 最大边际分类器(MMC)

2)修改优化问题

2.1)引入并发症

示例问题对我们很友好。在大多数情况下,就像图中显示的那样,数据点不容易分离。让我们突出这些问题。

用 python 创建

在上述情况下,很少有不同颜色的数据点过于接近,无法进行令人满意的分类。在这种情况下,利润可能非常有限。由于它可以被认为是衡量模型可靠性的一个参数,较小的裕度可能会给出不准确的分类。在其他情况下,如下所示,向训练观察值添加单个点可能会显著修改原本适当的最大余量,从而使模型容易过度拟合。

用 python 创建

解决的办法是错误地分类特定的点。这样做会降低训练数据的分类精度。然而,平均而言,该模型在测试数据上表现更好。这种情况下找到的分隔线称为 支持向量分类器(SVC)

2.2)查找 SVC

我们不需要从根本上构建 SVC。它的思想与 MMC 的思想相同,只是有一处修改,即对点的错误分类。因此,让我们从我们离开的地方继续优化的故事。再一次,搜索的是提供蓝色和粉红色之间的最佳可能分离的分类器。因此,它的假设方程和最大化参数(M)没有变化。然而,这些限制确实发生了变化。

指导这些修改的逻辑是什么?由于分类错误,点可能会落在其边界的错误一侧。一个组甚至可能有几个位于分类器的错误一侧。因此,对于这样的点,函数 f 产生小于 1 的值。松弛变量说明了这一点。你可以把它们解释为每个数据点的错误分类的参数。因此,有三种可能性:

  1. e = 0;数据点位于页边距的右侧
  2. 10;数据点位于边界和分类器之间。边界的错误一边
  3. e > 1;数据点位于分类器的错误一侧

用 python 创建

c 是总误差的量度。因为它是所有误差的总和,所以它的值不能为负。你可能会认为这是一个拨号控制的错误分类。从 0 度开始转动刻度盘会增加错误分类。接下来的问题是如何给 C 赋予它最好的价值。像任何机器学习算法一样,没有具体的方法。你为不同的 C 值建立模型并交叉验证它们。

结论

等等,我们就此结束?而不用解最优化方程?是的,这样做很累人,需要一些高级优化技术的知识。我可能会在另一篇文章中介绍它们。我在这里的目的是直观地解释 MMC 和 SVC。当数据点不是线性可分时,这些算法会失败。然后我们使用支持向量机(SVM)。它借用了所有讨论过的想法,但有一些引人注目的补充。

参考文献:统计学习导论——丹妮拉·威滕

构建世界上最大的 AI4Good Python 库

原文:https://towardsdatascience.com/building-the-worlds-largest-ai4good-python-library-ad0256c35271?source=collection_archive---------34-----------------------

由全球人工智能社区合作构建和维护

图片来自 Canva Pro,授权给 Omdena

想象一下一个开源 Python 库,它允许您在几天之内构建一个可用于生产的端到端数据科学管道!此外,该库不仅是一个代码库,还是一个知识源,在开发的每个阶段都有帮助,同时解决一些世界上最具挑战性的问题。

听起来是虚构的,对吧?但这正是 OmdenaLore 的含义。

OmdenaLore 是由社区开发的

我们的任务是构建 OmdenaLore,这是一个开源的数据科学包,提供全面且随时可用的 Python 类和函数,以加速的方式解决几乎任何机器学习问题。我们希望这是一个一站式图书馆,主要侧重于帮助开发人员建立现实世界的解决方案。此外,这个 Python 库是由全球人工智能社区协作构建和维护的,因此使它的开发更具包容性和道德性。

让我们更深入地了解 OmdenaLore 所提供的内容!

如何使用这个 Python 库?

你可以访问图书馆https://omdenaai.github.io/

我们确保 OmdenaLore 易于所有人使用。一些主要特征是:

直观的文档

老实说,我们经常会花几个小时在谷歌上搜索解决方案来修复错误,而不是花足够的时间在文档上。我们理解文档有时不直观,可能感觉不完整。因此,我们设计了 OmdenaLore 文档,它类似于维基百科的结构,带有标准 Python 库的文档主题,让您有宾至如归的感觉。但是什么是真正新的呢?不仅仅是外观,文档是合作者提供的,所以你可以向面临同样挑战的合作者学习。使用 OmdenaLore 文档,您还可以访问 Omdena 的公开知识库。使用内置的搜索功能对您的兴趣进行分类,您将进入充满知识的领域。有了结构化的知识库和文章,这个资源列表可能会“解决”你所有的问题。

在 OmdenaLore 文档中使用搜索—来源:Omdena

结构化知识库

该存储库提供了来自合作者的代码库、文档和知识库的组合。OmdenaLore 遵循基于机器学习和数据处理领域的结构化方法。浏览 components 文件夹,找到您感兴趣的代码库。感到失落?前往 samples 文件夹并运行笔记本,了解更多关于代码如何从加载数据到应用模型的工作原理。

当你成为奥姆德纳罗的一员时,我们会全程指导你的贡献。

你如何能有所贡献?

当你通过链接申请时,你将被允许访问知识库和我们的 slack 频道。

我们的贡献范围真的很广。本质上,只要不违反任何 IP,你可以贡献任何数据科学代码块。既然您有了推送访问权,那么您就可以克隆存储库并创建一个新的分支。此时,您还会发现我们的 Slack 小组与来自世界各地的其他变革者在一起,您可以在这里讨论和集思广益编码想法,并提出任何问题。OmdenaLore 并不一定要求深厚的专业知识,而是寻找那些希望做出贡献、成长和产生影响的积极的个人。

OmdenaLore 代码组件—来源:Omdena

我们独特的协作流程

问题部分

我们的 DAGsHub 存储库使用问题将添加更多功能的任务组合在一起。任何对某个问题感兴趣的贡献者都可以在他们的 Pull 请求中使用 Issue 链接。我们尽最大努力用编号的任务列表保持问题的简洁和离散。这鼓励了更细粒度的协作实践,因为每个提交的拉请求都添加了不同的新特性。

在 OmdenaLore 上制造问题——资料来源:Omdena

拉式请求

OmdenaLore 中的任何贡献都是通过 Pull 请求完成的。为了做出贡献,贡献者从 main 创建一个新的分支,在那里添加他们的更改,并发出一个 Pull 请求。我们的拉动式请求审查和合并速度非常快,平均时间为 2-3 小时。偶尔,我们会要求 PR 作者在合并 PR 之前做一些小的改动。有关贡献指南的更多信息,请参考https://omdenaai.github.io/guideline.html

OmdenaLore 中的拉取请求—来源:Omdena

短距离赛跑

当你和别人一起做的时候,编码更有趣!每周,我们都试图在我们的 Discord 服务器上主持至少三次编码冲刺。短跑没有先决条件,任何希望参加的人都可以加入语音呼叫。在新贡献者的简短介绍后,每个人都开始编写他们想贡献的问题。问答贯穿于整个 sprint,有时甚至在不同的语音通道中进行,以不打扰人们编码(我们还会一起听有趣的音乐:)。

疑问或问题解决——除了编码冲刺之外,我们在 Omdena 社区中还有一个活跃的 slack 频道,在这里我们可以讨论代码、交换关于 OmdenaLore 新特性的建议并分享反馈。我们还有一个 Airtable 表格,可以通过它直接与我们分享反馈。

专家

当然,没有人能成为所有人的专家。根据我们正在进行的编码冲刺的主题(计算机视觉卫星图像自然语言处理等)。),我们邀请我们的社区成员申请成为 sprint 的专家,以及 slack 频道中的一般主题的专家。这允许贡献者就他们试图贡献给存储库的代码提出他们的问题,以确保它对其他用户来说运行良好且可靠。

有助于在伦理上和包容性上建设人工智能的未来

OmdenaLore 不是 TensorFlow 和 PyTorch 等传统软件包的替代品。它用于构建与其他包相同的管道,但是时间跨度要短得多。此外,OmdenaLore 的目标是培育一个强大的开源社区,在这里可以不断添加新的功能和特性。我们希望全球所有数据科学家都能参与这项计划,无论他们是否希望成为贡献者。记住这一点,我们将很快在 PyPi 上发布 OmdenaLore,作为一个可安装的 Python 数据科学包。因为它是一个以项目为中心的 Python 库,所以您可以对 OmdenaLore 支持的多个实时项目产生影响。

通过链接填写表格,开始投稿吧!

欣赏 OmdenaLore 演示

OmdenaLore 和你一起,将成为好 Python 库最大的 AI!

感谢所有贡献者:马马杜·布索、安珠·麦西亚、西朱阿德·奥贡塔约、普雷西奥·加布里埃洛、普拉哈尔·拉蒂、戈塔米·乌达鲁、尤迪耶什·拉温德拉纳特、马克·西拉、克莱夫·费尔南德斯、塞缪尔·提阿非罗、威尔默·冈萨雷斯、马尼夫·塞加尔、赛·尼基莱什·雷迪和舒巴姆·甘地。特别感谢 Kaushal BhavsarRamansh Sharma 驾驶这辆车。

(本文由 Kaushal Bhavsar 和 Ramansh Sharma 撰写,最初发表于https://om dena . com/blog/worlds-largest-ai 4 good-python-library-omdenalore/)

在 Julia 中构建您的第一个分类管道

原文:https://towardsdatascience.com/building-your-first-classification-pipeline-in-julia-47e661c097d7?source=collection_archive---------31-----------------------

用 Julia 语言创建分类管道的快速概述

(src =https://pixabay.com/images/id-1566044/

介绍

C 分类是机器学习的一种形式,使用统计分析和概率论来预测类别集。这在机器学习领域是一项非常常见的任务,但 Julian 生态系统尚未对这一技术提供显著支持。虽然这并不是说在 Julia 编程语言中没有分类模型,但是您可能会很快发现它们非常稀少并且很难得到。再者,生态系统中的包彼此并不一致,更不用说 Julia 周围的其他语言的生态系统了。

当然,乍一看,有些人可能会将这些不一致归因于 Julia 所在的编程范例。像大多数其他现代编程语言一样,Julia 是多范型的,并具有许多通用编程概念,这使得该语言更易于使用。然而,我认为 Julia 已经构建了一个全新的范例,我(以及 Julia Computing)喜欢称之为多分派范例。

使用多分派范例,语法对于任何其他语言都是非常独特的,或者与另一种语言完全相同。例如,如果我们考虑 Python,它当然是统计学、机器学习和数据科学最流行的语言,我们可以通过使用构造函数和多重分派来模仿该语言在 Julia 中的能力。这正是我们今天将要使用的软件,车床,所做的事情,目的是让 Pythonic 的科学家们非常容易地开始学习 Julia 语言——而不必学习大量新的语法规则。如果您想了解更多关于车床的信息,您可以访问车床网站:

对于这个项目,我也有一个笔记本,您可以查看它,以便更好地掌握我将要查看的代码:

https://github.com/emmettgb/Emmetts-DS-NoteBooks/blob/master/Julia/Baltimore Crime Classification.ipynb

数据

对于这个项目,我基本上决定选择我能找到的任何有类的数据。我并不太关心特性的统计意义,因为这意味着更多的是对车床软件包内部建模能力的演示,以及在 Julia 中使用数据的小教程。记住这一点,我们要做的第一件事就是用 CSV.jl 和 DataFrames.jl 包读入我们的数据。为了做到这一点,我们需要使用一个 sink 参数,就像这样:

using CSV
using DataFrames
using DataFrames; df = CSV.read("baltimore_crime.csv", DataFrame)

如果你想了解更多关于什么是 sink 参数,以及它是如何工作的,那么你可以查看我在这里写的关于它的概述:

DataFrames.jl 的显示输出相当恐怖,这是我一直讨厌这个包的地方。实际上,我确实派生了这个包,并试图修改显示,但由于 DataFrames.jl 如此依赖于其他生态系统包,如 PrettyTables.jl,我们决定等待 PrettyTables.jl 的下一个版本发布会更有意义。这当然是有意义的,但是在一段时间内使用这个包会有负面影响。渐渐地,我放弃了我不想要的列,因为它们变得可见。我是通过使用 select!()方法和 Not()方法——这当然是从数据帧中删除列的一种非常谨慎的方法。:

df = select!(df, Not([:CrimeDate, :CrimeTime]))

这样做了一次后,我厌倦了,决定打印所有的名字,去掉我认为不合适的名字。这样做的一个很大的缺点是我看不到每一列的数据类型,甚至看不到特性是什么样子。你也可以做

show(df, allcols = true)

但是输出也很难辨认。

for name in names(df)
    println(name)
end
df = select!(df, Not([:Description, 
            Symbol("Inside/Outside"), :Weapon, :Post,
            Symbol("Location 1"), Symbol("Total Incidents")]))

现在我们有了所有不需要的列,我们可以从数据框架中删除缺失的列:

df = dropmissing(df)

因为在一个有 284,000 行的数据帧中只有大约 1,000 个缺失,所以我认为这比尝试填充这些值更有意义。然而,填充这些值的一个有趣的方法是使用 Lathe 的多数类基线遍历它们,例如:

using Lathe.models: ClassBaseline
model = ClassBaseline(Array(df[!, :CrimeCode]))
for val in df[!, CrimeCode]
    val = model.predict([val])[1]
end

接下来,我选择了以下内容作为我的功能和目标:

feature = :CrimeCode
target = :District

建模

例如,区列是表示区的数据,[东北、西、东南]。犯罪法典是某种专有系统,地方政府或联邦政府用来对不同类型的犯罪活动进行分类。接下来,我使用车床的火车测试分裂功能,以分裂我的数据:

using Lathe.preprocess: TrainTestSplit
train, test = TrainTestSplit(df)

然后,我相应地调用每个数据帧的列,以便将新数据放入一维数组。

trainX = train[!, feature]
trainy = train[!, target]
testX = test[!, feature]
testy = test[!, target]

我们需要做的最后一件事是找到某种方式来编码我们的数据。对于这个任务,我决定使用顺序编码器。这可以在车床的预处理模块中找到:

using Lathe.preprocess: OrdinalEncoder
encoder = OrdinalEncoder(trainX)

最后,我对编码器使用预测函数,以便将数据转换成普通的编码形式:

trainX_encoded = encoder.predict(trainX)

最后,我们将从车床导入并安装随机森林分类器。模型:

using Lathe.models: RandomForestClassifier
model = RandomForestClassifier(Array(trainX_encoded), Array(trainy))

请注意,我必须将数组类型转换为我的两个数组,这是因为 DataFrames.jl 从. 24 版本开始就在 PooledArrays 中存储数据,而 Lathe 的调度不是针对 AbstractArrays,而是只针对数组。如果你想学习更多关于 Julia 语言中类型抽象的知识,我有另外一篇文章你也可以阅读:

接下来,我将 testX 转换成数组类型:

testX = Array(testX)

最后,我建造了我的管道。在 Lathe 中,我们可以使用 Julia 的基本加法运算符来实现这一点。可以用减法运算符删除步骤,我认为这是一种非常酷的语法。另一件很酷的事情是,我们甚至不需要导入管道类型来使用它!

pipe = encoder + model

我实际上写了一篇关于如何做到这一点的文章,如果你不熟悉 Julia,我肯定认为它不值得一读:

最后,我们可以在新管道上调用 predict()函数,该函数将对我们的值进行编码,然后将其传递给模型:

yhat = pipe.predict(testX)

最后,我们可以使用 Lathe.stats 中的 catacc()方法来评估精度:

using Lathe.stats: catacc
println("Accuracy: ", catacc(testy, yhat) * 100)

由作者制作的图像

这太残忍了。

结论

尽管这些特性之间缺乏统计意义,但很难否认 Lathe.jl 包中提供的很酷的语法和方法。我认为这些管道特别酷,我很高兴能继续深入研究它们。如果您对该模型与其他地方的实现相比如何感到好奇,您可以随时查看我对该模型和 SkLearn 之间的性能和准确性进行的比较,这无疑是很有启发性的:

非常感谢您的阅读,我希望这篇文章对您有所帮助,让您在 Julia 中成为一名更好的程序员!

为深度学习构建自己的数据科学基础设施

原文:https://towardsdatascience.com/building-your-own-data-science-infrastructure-for-deep-learning-99ba17407af2?source=collection_archive---------12-----------------------

入门|数据科学基础设施| KNIME 分析平台

构建自己的机器并安装 KNIME、Jupyter-Notebook 和 Tableau,为所有数据科学和深度学习任务做好充分准备

图 1:构建自己的机器(图片由作者提供)

自制或购买

你想开始学习数据科学,但缺乏适当的基础设施,或者你已经是一名专业人士,但在深度学习方面仍有知识差距?

那么你有两个选择 :
1。 从亚马逊、微软 Azure、谷歌云或类似的云提供商那里租用虚拟机

图 2:选择合适的云平台(图片由作者提供)。

2。构建自己的物理机器 并安装合适的软件

图 3:我的数据科学“怪兽电脑”(图片由作者提供)。

我尝试了两种选择,但最终决定建造自己的钻机是更好的选择,原因如下:

  1. 节省成本
    如果您需要一个具有强大显卡(GPU)、快速处理器(CPU)和大量内存的系统,那么从长远来看,构建一台机器实际上可以为您节省资金!根据云服务的不同,不同提供商的价格相差很大,但最终你可以用那个价格建造自己的机器并永久保存。而如果你需要 Windows 作为你的操作系统(OS),你肯定会省钱。相信我:你最终会需要窗户的!
  2. 更多的能力和资源 来自 Bizon-Tech 的一项研究表明,与基于网络的服务相比,使用 1 个 GPU 的预构建在 1 年内最多便宜 10 倍,使用 4 个 GPU 的最多便宜 21 倍。当谈到存储容量时,网络服务的价格会超过一定的规模。
  3. 你的机器还可以用于其他任务 最后,你可以用你的电脑进行其他任务,比如电影剪辑或者 PC 游戏,并且永远保留它。

第 1 部分:选择正确的系统和软件

为了构建我们的系统,我们需要提前考虑几个问题。
其中一个关键点是选择合适的操作系统。
我们可以在 Windows 10 Pro、Linux 和 Mac OS X 之间进行选择。
但是哪个系统符合我们的所有要求呢?

让我们先列出我们的必要要求:

  1. 深度学习能力 我们要计算深度学习模型。目前最好的选择仍然是使用NVIDIAGPU 来完成这个任务。两个最先进的深度学习框架 TensorFlowKeras 都需要 nvidia 显卡。苹果的 Mac OS X 已经停止支持 nvidia,即使有了 Hackintosh(一款用 PC 组件构建的定制 Mac ),也不再可能让 nvidia GPU 工作。
    在 Windows 和 Linux 系统上,nvidia GPU 工作正常,你也可以找到必要的驱动程序。
    • 结果:Windows 和 Linux 并列

  2. Jupyter-Notebook 我们想用 Python 安装Jupyter-Notebook。Jupyter 是数据科学家的首选计算笔记本,我们绝对不想错过它。Anaconda 为所有操作系统提供了相应的简单安装,所以我们也已经安装了 Python。
    • 结果:Windows、Linux 和 Mac OS X 打成平手。

  3. 正确的数据混合和 ETL 工具 最好的数据混合和 ETL 工具在我看来是 KNIME 。关于这个 我已经在这里 写了一篇文章,在这里你可以读到原因。
    这里 有所有三个操作系统 [**的 KNIME 安装包。
  4. 一个好的可视化工具
    你不会相信找到一个免费且提供所有你需要的功能的可视化工具有多难。
    画面公 就是这里正确的选择。但是您需要知道一些变通方法,以便能够在生产模式下使用它。但无论如何这仍然是目前最好的选择。安装包仅适用于 Windows 和 Mac OS X.
    • 结果:Windows 和 Mac OS X 打成平手。

  5. 用于存储的数据库 为了简单起见,我们将从 SQLite 作为数据库解决方案开始。它并不像 Oracle、MySQL 或 Teradata 那样是一个真正复杂的数据库,但你可以用它来使用大多数 SQL 命令,并且与 KNIME 结合使用效果很好。在我看来,SQLite 完全被低估了。所有三个操作系统都有安装包。
    (如果已经安装了 KNIME,不需要安装任何额外的 SQLite 包)
    • 结果:Windows、Linux、Mac OS X 并列。

  6. 来自其他笔记本电脑/平板电脑的远程桌面例如,我们希望能够从笔记本电脑或平板电脑远程登录我们的机器并在其上工作。我已经尝试了从 VNC 到 Teamviewer 的各种工具。但目前为止我用 Windows 远程桌面 app 获得了最好的体验。
    通过平板电脑也能达到最佳效果,它总能提供合适的屏幕分辨率,让你感觉就像坐在电脑前一样。要在 Windows 上启用远程桌面,您必须从家庭版升级到专业版
    • 结果:Windows

那么,最终,哪个操作系统最能满足我们所有的需求呢?
也许你会感到惊讶,但获胜者是: Windows 10 Pro

第 2 部分:构建机器

现在我们必须制造我们的机器,我们必须选择正确的组件。PC 版本由以下组件组成:

  • 中央处理器
  • 母板
  • 电脑机箱
  • 随机存取存储
  • 冷却
  • 硬盘
  • 图形处理器(图形卡)*
  • PSU(电源)

如果你正在处理千兆字节大小的数据,如果你需要进行大量的查询,我建议你购买一个好的 CPU。
CPU 主要用于深度学习中的数据加载。CPU 上的线程越多,意味着您可以并行加载更多数据,以提供给模型进行训练。
英特尔和 AMD 在市场上为最佳性能和价格展开了一场大战。但现在,我会选择 AMD Ryzenz 的 CPU。他们每年都会发布价格相对低廉的多线程处理器。
对于我的 PC,我甚至从一个老游戏玩家那里买了一个二手的 AMD 锐龙 7 2700X (3.70GHz)。它已经有几年的历史了,但是如果你够幸运的话,你可以通过像易贝这样的网上拍卖便宜地买到它。
要获得最佳的 CPU 多核(非单核)性能,请查看 Geekbench 基准测试网站。

图 4: CPU 多核基准测试成绩(图片来自 Geekbench )。

主板 确保主板与你的 CPU 和 RAM 兼容。把主板和 CPU 一起买在一个包装里总是一个不错的选择。选择主板时,确保它有足够的 PCIe 插槽来容纳你想要的 GPU 数量。这里的规则是一个 GPU 将占用 2 个 PCIe 插槽的空间。
另一点是外形因素。在这里,我肯定会选择经典的 ATX 主板,因为我们的目标不是构建小尺寸 PC,而是高性能数据科学解决方案。

PC-Case
对于 PC-Case 我选择了Corsair Carbide Air 540
它为所有部件提供了足够的空间,易于组装且通风良好。并时刻关注温度。如果你需要计算一个复杂的深度学习模型,机器的温度可能会随着时间的推移而急剧上升。

RAM
获得正确的 RAM 规格背后有一整套科学。但最重要的一点还是 RAM 的数量(越多=越好)。
如果您正在处理大型数据集,如图像或日志数据,您的数据可以完全存储在内存中,这可以显著加快处理时间。
对于我的钻机,我去了 32 GB 内存的海盗船

冷却器 坚固的冷却器对于保持系统低温非常重要。水冷装置具有高性能并降低了噪音。但并不总是如此。我过去尝试过不同的设置,不得不说,即使是一个好的 空气冷却器也可能很安静 。最肯定的是,它通常占用更少的空间,也更容易安装。AMD 锐龙 CPU 的优势来了。它的升温速度比英特尔 CPU 慢。

存储 这同样适用于硬盘和 RAM。更多=更好。但不仅仅是!
如果你想优化数据加载速度,你需要更快的固态硬盘存储速度( SSD )。固态硬盘比标准硬盘更贵,但这不应成为购买标准。
我建议为操作系统和安装的软件安装一块固态硬盘(大小为 500 GB),为数据安装一块固态硬盘(大小为 1 到 2 TB)。
我喜欢三星的 SSD。但是其他任何品牌也会这么做。

GPU(显卡) 实际上,即使只有强大的 CPU,也可以计算(一些)深度学习模型。但是你需要时间…很多时间!
GPU 在计算深度学习模型方面速度超快,因为与计算核心数量相对较少的 CPU 不同,GPU 拥有数百或数千个简单的核心,在矩阵乘法方面速度超快。
正如我之前所说的,我们应该大力支持 nvidia 显卡,因为所有当前最先进的框架(无论是 Keras、TensorFlow、PyTorch 还是任何其他库)都完全支持 nvidia 的 CUDA SDK,这是一个用于连接 GPU 的软件库。
另一个重点是张量核。张量核加速矩阵运算,这是深度学习的基础,并在单次运算中执行混合精度矩阵乘法和累加计算。

图 5:张量核心概述(nvidia 视频)。

张量核可以在 英伟达 RTX GPU 型号中找到。我选择了相对便宜的来自微星的Geforce RTX 2070 8G。有了 RTX 2070 和 8 GB RAM,你可以训练大多数 SOTA(最先进的)深度学习模型,而仍然不必支付太多费用。
另请参见 Lamba-Labs 网站上的所有 GPU 列表。

图 6:深度学习的平价 GPU。

PSU(电源) 现在我们几乎拥有了所有的组件。现在的问题是:我们需要多少电力?
计算所需功率有不同的 PSU 计算器
对于我的系统,我需要一个 360 W 左右的 PSU。
为了将来有足够的功率,当我添加第二个显卡时,我选择了一个 750W 绰绰有余的 GX-750。

图 7:PSU 所需功率的计算(图片由 bequiet 提供)。

这套系统总共花了我大约 1500 美元:

****组件:
CPU+主板+32GB RAM: $299
SSD1 带 500GB: \(98 SSD2 带 1TB:\) 135
PC-Case:$ 138
GPU:$ 707

一年前,我尝试了一种最便宜但仍然非常划算的云服务,不得不为一台没有专用显卡的物理机支付一年 700 美元。

对于您的定制系统,在构建装备时使用 PC 零件拾取器

第 3 部分:软件的安装

组装好整个系统后,我们需要安装一个操作系统。我们已经选择了 Windows,因为它符合我们的需求。

Windows(安装) 第一步是下载 Windows 和 创建一个安装介质 。我们将把安装文件复制到 u 盘上。

图 8:创建 Windows 安装介质(微软视频)。

nvidia 和 CUDA-驱动程序(安装) 要充分利用你的显卡,你需要合适的 nvidia 驱动程序
除了正常的 GPU 驱动,还必须安装 Cuda 工具包
下一步,我们将在 Keras 和 TensorFlow 集成中安装 KNIME。但更多的是后来。

图 9:在 Windows 上安装 CUDA(视频由 nvidia 提供)。

Jupyter-Notebook by Anaconda(安装) 要安装 Jupyter-Notebook 和 Python 最简单的方法就是通过安装 Anaconda 。安装完成后,您可以从相应的磁贴中启动 Jupyter-Notebook(见下图中的红色箭头)

图 10:从 Anaconda 启动 Jupyter-Notebook(图片由作者提供)。

现在,您可以在本地计算机的浏览器中从以下地址使用 Jupyter:http://localhost:8888/tree

图 11:浏览器上的 Jupyter-Notebook(图片由作者提供)。

KNIME 和深度学习集成(安装) KNIME 是我们数据科学基础设施的核心,因为它将协调从数据混合到机器学习和深度学习到可视化准备的一切。

图 12:安装 KNIME(由 KNIME 制作的视频)。

除了 KNIME 我们还需要安装名为 KNIME 深度学习— Keras 集成 的“深度学习扩展”。它提供了 Keras 库的基于 GUI 的无代码集成,同时使用 TensorFlow 作为其后端。

需要执行以下步骤:
-安装深度学习 KNIME 扩展(Keras 和 TensorFlow)
-创建 Conda 环境

深度学习 KNIME 扩展的安装
您可以在 KNIME Analytics 平台中安装扩展,方法是从顶部菜单中单击“文件”,然后选择“安装 KNIME 扩展…”。这将打开图 13 所示的对话框。

**要安装 Keras 和 TensorFlow 节点,需要选择:

  • KNIME 深度学习- Keras 集成
  • KNIME 深度学习- TensorFlow 集成**

图 13:安装 KNIME 深度学习集成(图片由 KNIME 提供)。

现在,您的节点存储库中应该有了 Keras 和 TensorFlow 节点,如图 14 所示。

图 14:节点库中已安装的深度学习节点(图片由 KNIME 提供)。

KNIME Keras 集成和 KNIME TensorFlow 集成依赖于现有的 Python 安装,这需要安装某些 Python 依赖项。KNIME 深度学习集成使用 Anaconda 来管理 Python 环境。如果您还没有安装 Anaconda(见上文),现在就安装它。

创建 Conda 环境
接下来,我们需要创建一个安装了正确库的环境。要在 KNIME Analytics Platform 中这样做,从顶部菜单中选择 File - > Preferences。这将打开一个新的对话框,左边有一个列表。从对话框中选择 KNIME - > Python 深度学习。

图 15: KNIME Python 深度学习偏好页面(图片由作者提供)。

在此页面中,创建一些 Conda 环境,并为 Keras 或 TensorFlow 2 安装正确的包。目前,为 Keras 建立一个环境就足够了。要创建和设置新环境,请启用“使用特殊深度学习配置”,并将 Keras 设置为 Python 中用于深度学习的库。接下来,启用 Conda 并提供 Conda 安装目录的路径。此外,要为 Keras 创建新环境,请单击 Keras 框架中的“新环境…”按钮。

图 16:设置新 GPU 环境名称的对话框(图片由作者提供)。

既然我们已经安装了 GPU,我们应该创建一个新的 GPU 环境,以便从图形卡的所有功能中受益。
现在我们已经准备好处理深度学习模型了。

在我的下一篇文章中,我将向您详细介绍如何通过几次点击来创建深度学习模型。与此同时,我建议你看看这个关于 KNIME 无代码深度学习的很好的介绍视频。

图 17:KNIME 无代码深度学习介绍(KNIME 的视频)。

我也强烈推荐《无代码深度学习 》这本书,轻松介绍题目。

图 18:由 Rosaria SilipoKathrin Melcher 合著的《无代码深度学习》一书。

Tableau Public(安装) 要获得 Tableau Public,你需要在这里注册一个免费的简介。但这绝对是值得的,因为你可以在网上任何地方分享你的 Tableau 仪表盘。

图 19:在 Tableau Public 注册(图片由 Tableau 提供)。

如果你不熟悉 Tableau,推荐你在这里过一遍这个教程
我在下面的视频和文章中描述了一个很好的例子,你可以用 KNIME & Jupyter & Tableau 的组合来做什么:

数据科学以 KNIME、Jupyter、Tableau 使用新冠肺炎投影为例

图 20: 使用 KNIME、Jupyter 和 Tableau 的数据科学(作者提供的视频)。

现在是最简单的部分:如果您已经安装了 KNIME,那么不需要再安装任何东西。您已经可以创建、读取和编写自己的 SQLite 数据库。
我将通过以下 KNIME 工作流程向您展示这一点:

1.我将虹膜数据的路径放在 CSV 阅读器节点中。2。然后我将 test.sqlite 数据库的位置写在 SQLite 连接器节点中。
3。使用 DB Writer 节点,我将 Iris 数据集写入 SQLite 数据库。
4。然后,我在 DB 查询阅读器节点中使用 SQL 查询 sepal.length 大于 5 的所有行。
5。最后,我用一个
交互表节点输出结果。

图 21:用 KNIME 创建和查询一个 SQLite 数据库。

在下一篇文章中,我将向您展示 SQLite 与 KNIME 结合还能做些什么。

从其他笔记本电脑/平板电脑远程桌面 要设置您的电脑启用远程连接,您必须升级到 Windows Pro,然后您才可以打开 启用远程桌面

图 22:在 Windows 10 Pro 上启用远程桌面(图片由作者提供)。

最后,在您的 Windows、Android、iOS 或 Mac OS X 设备 :
上打开远程桌面应用程序(可从微软商店、Google Play 和 Mac 应用程序商店免费获得),并添加您想要连接的 PC 的名称。选择您添加的远程电脑名称,然后等待连接完成。

我现在甚至能够在我的智能手机上创建和编辑 KNIME 工作流(或多或少:-)。

图 24:口袋中的数据科学基础设施(图片由作者提供)。

现在你应该准备好进入数据科学,甚至开始构建深度学习模型。往前走,然后…

感谢阅读! 欢迎在评论中分享你的想法或阅读技巧。

**https://medium.com/@deganza11/membership

跟我上 LinkedInTwitter 跟我上脸书群 数据科学跟 yo dime**

用 Plotly Dash 构建自己的谷歌翻译应用程序

原文:https://towardsdatascience.com/building-your-own-google-translate-app-on-plotly-dash-150297dbb8b1?source=collection_archive---------24-----------------------

语言不分国界!

Artem BeliaikinUnsplash 上拍照

动机

我喜欢探索!我一直对世界各地的不同语言很感兴趣。我来自一个使用多种语言的国家,我可以证明,掌握多种语言肯定会打开你的世界,因为你可以很容易地与他人联系。虽然谷歌翻译确实让我们的生活变得更加轻松,语言不再是障碍,但我认为如果我能在一次搜索中获得所有语言中一个单词的翻译,而则是惊人的。不仅如此,作为一个视觉学习者,将这些翻译的单词映射到地图上各自的国家有助于让我的学习更容易,幸运的是,Plotly Dash 使这成为可能!

先睹为快

这是该应用程序的最终产品,当你在一个国家徘徊时,翻译的文本就会出现。很想创造一个吗?让我们开始吧!

图书馆

以下库将用于构建此应用程序。

  1. googletrans :实现 Google Translate API 的 python 库
  2. 一个交互式的开源绘图/可视化库
  3. dash :用于构建 web 分析应用程序的高效 Python 框架
  4. pycountry :提供语言&国家的 ISO 数据库
  5. 熊猫:提供快速、灵活和富于表现力的数据结构的包
pip install googletrans==3.1.0a0
pip install dash
pip install pycountry
pip install pandas

我已经安装了 alpha 版本googletrans==3.1.0a0,因为由于谷歌翻译 API 的变化,其他版本中出现了一些问题。

数据集的预览

数据集可以在我的 GitHub 库中找到。

Googletrans

谷歌翻译 API 支持多种语言。要列出它们,只需运行下面的代码。

import googletrans
from pprint import pprintpprint(googletrans.LANGUAGES)

现在,让我们看看翻译器是如何工作的。首先需要从googletrans模块导入 Translator 并创建一个Translator类的对象,然后将文本作为参数传递给Translator类对象的translate()方法。默认情况下,translate()方法返回传递给它的文本的英语翻译,因此您需要使用dest属性指定目标语言。这里我们用‘fr'初始化了dest,这意味着translate()方法会将文本从英语转换成法语。

result = translator.translate("hello world", dest="fr").text

由于我们处理的是 pandas DataFrame,而dest因国家而异,所以我使用了.apply()方法来传递函数,并将其应用于 Panda 系列ISO_lang的每个值。

df["transl"] = df["ISO_lang"].apply(lambda x: translator.translate(text, src=lang, dest = x).text)

现在我们有了一个包含翻译文本的新列transl

Plotly Express

为了可视化我们翻译的文本,我将使用 Plotly Express,这是一个新的高级 Python 可视化库,也是 Plotly.py 的包装器,允许使用复杂图表的简单语法。Plotly 是最好的可视化库之一,因为它允许交互式 T21 可视化。但最重要的是,它可以部署在 Dash 应用上,这才是本文的主旨!

在我们的可视化中使用的图是一个choropleth地图,它允许我们通过根据值着色的区域&呈现数据。数据帧中的每一行被表示为 choropleth 的一个区域。

color参数本质上是我们想要用于颜色编码的数据帧的列。在这里,我使用了population列,这样我们的 choropleth 地图也允许我们按照国家来可视化世界人口。

破折号

现在进入激动人心的部分,让我们把所有东西放在一起,构建我们的 dash 应用程序!Dash 是 Plotly 的开源框架,用于构建分析性 web 应用程序和以 Plotly 图表为特色的仪表盘。这是一个 web 应用框架,围绕 HTML、CSS 和 JavaScript 提供抽象,因为它构建在 Flask、React.js 和 Plotly.js 之上。

让我们首先导入 dash 库。

Dash 应用由两部分组成:布局和交互两部分。****

一、布局

布局使用两个库,分别是dash_html_componentsdash_core_componentsdash_html_components为所有的 HTML 标签提供了类,关键字参数描述了 HTML 属性,如styleclassNameid。它允许我们设计应用程序的外观。简而言之,dash 允许我们使用 Python 结构和 dash 组件库来构建布局,而不是编写 HTML,dash 组件库使用 Div 类转换 Python 类来创建 HTMLDiv。另一方面,dash_core_components库生成更高级别的组件,如控件和图形。dcc.Graph类允许我们在布局中创建一个图表。在幕后,Dash 使用 Plotly.js 创建交互式图形,其中的dcc.Graph组件需要一个包含绘图数据和布局的图形对象或 Python 字典。同时,dcc.Input接受用户输入(要翻译的文本)并将其作为参数传递给 Dash 回调中的update_output函数。

二世。回调

回调函数本质上是 Python 函数,每当输入组件的属性发生变化时,dash 就会自动调用这些函数,因此允许 Dash 应用程序中的交互。为了做到这一点,我们需要从dash.dependencies导入Input, Output & State

每一个state & input都需要表示为回调函数内部的参数。inputstate的区别在于,每当输入的component_property发生变化时,自动触发回调。然而,当状态的component_property改变时,它不会被触发。从长远来看,每当用户在文本框中输入时,图表不会更新。当用户点击“翻译”按钮时,只有这时图形才会更新。

[dash.dependencies.Input(component_id='submit_button', component_property='n_clicks')],     [dash.dependencies.State(component_id='input_state', component_property='value')]

让我们了解一下依赖关系是如何工作的。回调函数中的component_id=’submit_button’基本上与之前在app.layout中初始化的html.Button(id=’submit_button’, n_clicks=0, children=’Submit’)参数进行交互。这意味着当我们的应用程序界面中的提交按钮被点击时,它触发回调函数执行update_output函数,在这里它作为num_clicks参数被传递。回调函数将数据返回给outputcomponent_property='figure',这是 choropleth 映射。

参数的顺序对于应用程序的运行至关重要,即输出→输入→状态,我们的update_output函数中的参数对应于回调函数中的inputstate参数,顺序相同。例如,第一参数num_clicks与输入component_property='n_clicks'相关联,第二参数value与状态component_property='value'相关联。

在某些情况下,当您不想更新回调输出时,您可以像我一样在回调函数中引发一个PreventUpdate异常。

最后,插入我们之前的代码片段,在update_output函数中创建 choropleth 映射。为了查看我们的可视化,我们需要运行我们的 web 服务器,就像在 Flask 中使用app.run_server(debug=False)一样。如果你在 Jupyter 笔记本上运行,记得禁用调试模式和。我们的 dash 应用程序现在可以运行了!

结论

恭喜你!在本文中,你已经学习了破折号布局和回调,这两者对于构建你的第一个 web 应用程序都是必不可少的。Dash 创建交互式 dashboard 的能力超乎想象,所以去创建一些有趣的东西并与世界分享吧!

我应该注意到,应用程序加载时间与数据集中的国家数量相对应,这是因为googletrans在生成输出之前必须逐行翻译。

完整的代码可以在我的 GitHub 库:)中找到

资源:

  1. Plotly Express — Choropleth 文档

2.仪表板组件库

  1. Googletrans 文档

我总是乐于接受反馈和建设性的批评。此外,请随时与我分享你的工作,我也期待着向你学习!你可以在 Linkedin 上找到我。😃

倦怠——进步的祸根

原文:https://towardsdatascience.com/burnout-the-bane-of-progress-3ad7585afb08?source=collection_archive---------24-----------------------

作为一名人工智能开发人员、黑客和研究人员,我是如何陷入低谷的

来自保罗·布莱在 Unsplash

无奈。恐慌。绝望

我描述倦怠的最佳尝试。对于程序员、开发人员和研究人员来说,精疲力尽是一种非常常见的经历,它可以完全停止生产力并破坏精神状态。如果已知来源,传统问题可以得到解决。作为程序员,我们都知道,如果我们理解为什么我们的代码会抛出错误,我们就可以快速修复它们。然而,在精疲力竭的情况下,即使你确切地知道你是如何到达那里的,恢复仍然是一项极具挑战性的任务。对我个人来说,我是一个以工作为导向的人,所以很难接受“没有生产力”(腾出空闲时间)。

作为一个超级科技迷,我的目标是成为一个永远不需要休息的机器人,但这对任何人来说都是不可行的

作为一名有抱负的研究人员、黑客和开发人员,我有过相当多的疲惫。我认识到研究是一个令人沮丧的过程;提出的方法不仅需要在理论上是一致的,而且结果必须证实这些方法。因此,如果结果不像预期的那样,罪魁祸首可能是错误的代码或概念上的错误表述,这使得回溯这些问题成为一条穿过混乱、交织的迷宫的道路。无论是讨厌的代码错误,还是整天编写机器学习脚本的单调工作(我指的是每天14小时,我都很快意识到为什么我会这么累。只是开发解决方案花了很长时间。

在这篇文章中,我想谈谈我在追求人工智能和计算机科学时最糟糕的时期,为什么会发生,以及我如何重塑我的工作方法来防止它们。希望你能从我的建议中吸取教训,防止你自己在 AI 和 CS 中耗尽精力。

第一个

2020 年对我来说是重要的一年。在过去的两年里,我已经完全重塑了我的职业道德,以至于我可以比我的同龄人更快更有效地完成任务和任务。所以那年春天,特别是 4 月份,我决定超负荷安排我的日程,安排连续的周末黑客马拉松。第一个周末开始还不错,但结束后,我马上就精疲力尽了,在接下来的两天里,我被绑在床上,什么都不做。

接下来的周末,一切都崩溃了。大约 10 个小时后,我开始对感到恐慌,我不知道为什么。在活动开始前的几天,我失眠了,还做噩梦,梦见自己没有完成分配给自己的工作,我害怕失败。更让我恐慌的是,当时我也在修行斋月,这并没有让我的日子好过。我的精神状态变得如此糟糕,以至于我开始质疑我对 CS 和 AI 的职业选择,因为我失去了很多自信,不知道该做什么。我对 束手无策;我感到被遏制了。曾经充满希望的一年很快变得暗淡和悲惨。我的火花在闪烁。

作者罗迪翁·库斯塔耶夫

幸运的是,春假就要到了,所以我可以在那一周放松自己,和朋友家人在一起。这是我唯一做对的一件事,虽然这绝对是明智之举,但我应该做得更多。这只是我第一次忍受真正的倦怠,所以我天真地没有反思或吸取教训。因此,我随后的飙升和下跌一样快,由于我在几周内表现良好,我完全忘记了发生了什么。

第二

我没有吸取教训。我继续增加我的工作量,到 7 月份,我同时在做两个研究项目、一个夏季项目和两周一次的黑客马拉松。我觉得自己很有成就,并被一种我认为可以实现的伟大理念所驱动。我刚刚接受了两个新的实习,都与 AI 有关,我从来没有感觉更好。我不想让那些指望我的人失望,所以我每天都在学习和完成作业。然而,这种对成就的追逐被另一个慢慢升起的红色火焰所中止。

与其说是恐慌或无助,不如说是发现自己无望而疲惫。我写了这么多代码,很多人会争论太多。我被对出版物和 Github 影响力的追求所推动,并在此过程中忽略了自己的健康。所以就在七月初,我遇到了前所未有的压力。 万念俱灰 来袭。我失去了对编程和研究的所有热情。我再次质疑自己对编程的兴趣,因为编程既枯燥又毫无意义。我质疑为什么我认为我可以成为一名研究人员,当有这么多我不知道的时候。我怀疑我是否能继续做下去。**

我在 6 月和 7 月的 Github 贡献图——仅在 7 月就有 442 次提交

这种倦怠持续的时间比第一次持续的时间要长得多。这持续了整个 7 月。因此,通过努力完成并继续我的每日承诺,完成我的微软任务板上的任务,并向我的导师提交更新,我耗尽了所有的精力。我只是点燃了熊熊的火焰。我几乎要放弃,把我所有的进步都留在桌面上。这种倦怠真的是我的克星。

实现

直接的解决方案

虽然这听起来很简单,但我的解决方案是简单地停止编码。我决定冒一次险——我知道如果我停止编码几天,我可能会很快落后于我需要完成的所有工作。但是我也评估了我的效率因为试图克服倦怠而受到的损害,我最终决定净生产率并不重要。我需要冷静下来,无论我会失去多少进步,我都不能再这样下去了。对于我的团队项目,幸运的是,我有很好的朋友和队友,他们理解我不断恶化的精神状态,并支持我收拾我的烂摊子,让我花更多的时间在自己身上。**

个人的改变

与此同时,我决定追求其他我认为有益的爱好。这包括在媒体上写作,在 Youtube 上听播客,练习驾驶。我过去和现在都痴迷于生产力,所以我不能让自己无所事事。然而,如果我说我没有找到更多的方式来享受生活,比如和朋友出去玩,玩电子游戏,到处看电影,那我就是在撒谎。我专门分配了纯粹为了享受的时间,让我重新获得了前一年的许多乐趣。我建议你在一天中尝试参加一些休闲活动,尤其是和你亲近的人一起,以防止自己过热,因为你周围的人可以帮助你更好地评估自己。

在这段时间里,我更加关注自己的心理健康和恢复,为自己提供所需的一切。我知道我需要休假和自我反省来逃避,但给自己这些需要很大的意志力和牺牲。然而,通过这样做,我可以立即进入状态,尤其是考虑到我的会议期限即将到来。

长期变化无疑是最重要的。在紧张的时间窗口中,完全休息可能是不可行的,我已经开始改变思维通风的优先顺序。在 PyTorch 中实现了 10 个小时的架构之后,为了避免过热,我将转而继续查阅文献或设计模型原理图。这种任务转换极大地提高了我对项目的理解,因为通过处理一个不太严格的任务,我可以用一种全新的思维全面地分析和比较我的方法和其他方法,最终产生一个更精炼的手稿。即使在压力小的时候,遵循这种方法也帮助我提高了效率,防止了灾难性的疲劳。不知何故,我忽略了一个显而易见的事实,即研究和编程需要充分发挥大脑的能力,而且总是以 50%的能力工作而不充电,我限制了我的全部能力。

目标设定

永远向星星射击。即使在精疲力尽的时候。

通常,人们认为设定过于雄心勃勃的目标是倦怠的一个原因,但事实未必如此。如果效率是一个挑战,那么也许减轻你的负担。但就我而言,我学到的是,试图在同一个月内完成两个会议的两篇论文是非常困难的,而且总体上降低了两篇论文的质量。更理想的决定是花更长的时间在 NeurIPS 或 CVPR 提交上。由于我所有的时间都将投入到一个非常长期的项目中,结果和回报会高得多。因此,如果你是一名有抱负的研究人员,永远要志存高远,但要注重质量而不是数量。

简而言之,如果你快累垮了,不要停止追逐星星——只需关注不同的星星,那些更大、更有回报的星星。

由杰瑞米·托马斯在 Unsplash

最后一点

在 AI 和 CS 工作很累人。有各种各样的挑战和障碍需要我们去克服,试图用蛮力去克服它们并不是答案。我们都试图体现人工智能,并假装我们是永远不需要休息的机器人,尽管我们可能会不时地接近它们的效率,但我们都需要休息,以便充电和恢复活力。然后,我们可以成为比我们希望成为的机器人更好的 T2——最好的自己。

提升你影响力的商业和个人技能

原文:https://towardsdatascience.com/business-and-personal-skills-to-supercharge-your-impact-22fbd43e32e9?source=collection_archive---------24-----------------------

办公时间

机器学习中人类的一面

埃罗尔·艾哈迈德Unsplash 上拍摄的照片

无论你在处理数字和编写代码方面多么有天赋,如果你追逐实际上对你的公司没有帮助的问题,或者你不能让任何人采纳你的分析结果,那么你作为数据科学家的效率是有限的。同样,你如何在一个不断发展的领域保持动力和相关性?

在本帖中,我们将概述将你的技术技能转化为影响力所需的 业务个人 技能。

但是当然,免责声明:到目前为止,我的数据科学职业生涯都是在员工少于 100 人的公司度过的。如果我在过去的五年里是甲骨文 135,000 名员工中的一员,这篇文章看起来可能会有所不同!我也从未在政府或非盈利部门工作过。

无论如何,我已经尽了最大努力来减少这种偏见,并写了一篇适用于任何规模和类型的组织的数据科学家的帖子。

理解商业意识

数据科学充满了诱人的兔子洞。我们的代码工作得很好,但是如果我们添加一种自动调优模型超参数的方法会怎么样呢?如果我们建立一种更好的方法来可视化我们的 NLP 模型的高维向量空间,可能利益相关者会更积极地参与进来。没有人要求这样做,但是如果我们为我们的数据质量输出建立一个光滑的仪表板,这样您就可以点击按钮,而不需要编写 SQL,会怎么样?

令人困惑的是,虽然兔子洞的尽头通常有一些商业价值,但通常不值得追求。当然,一个更准确或更容易理解的模型可能会在某种程度上帮助你的公司。

但是,这是对你的时间的最有效利用吗?

你能理解你同事的需求并与他们交流这个项目将如何增强他们的能力吗?

这个项目解决的是贵公司市场中未被满足的需求,还是“值得拥有”的需求?

我们将在本节的剩余部分探讨这些想法。

优化资源配置

这是一个数据科学家可能面临的两难境地的例子。贵公司要求您预测下个季度在纽约的销售额。一个月后,你展示你目前拥有的东西——一辆 ARIMA 型号和一辆 RMSE 大约 5000 英镑。虽然这很好,但是您已经确定了两个额外的外生变量,您认为它们可以将误差降低到 2000!你用一个探索和整合这些变量的攻击计划来结束你的演讲。

令你惊讶的是,你的老板说没有。他们说,模型的准确性是可以接受的,不值得花时间(和风险)去进一步探索。你有一周的时间将你的模型产品化,之后你将开始一个新项目。

你很困惑,确信你的老板犯了一个错误。仅仅两个星期就有可能将模型误差减半,这怎么可能不值得呢?使用不太准确的预测,你的公司将付出真正的代价!

要理解贵公司的观点,考虑其无时无刻不在的优化资源配置的需求。是的,一个不太准确的模型意味着你的公司使用了更糟糕的预测,这可能会导致不太准确的决策。然而,这种不准确性的成本很可能低于你没有从事不同业务需求的 机会成本

在公司需求的背景下,也许到目前为止投入到模型中的努力代表了 OK 努力与下图中的产出比的结束,或者甚至只是绿色区域的结束。

换句话说,如果这意味着避免更大的成本比如客户因订单错误而流失,你的公司愿意支付更差型号的成本。对你的公司来说,停止你的预测工作,转而关注数据质量会更有价值。

努力与产出。图片作者。

在一个项目上被打断很容易让人感到沮丧,尤其是如果你已经投入了时间或者最终积累了动力。然而,重要的是要把你对一个项目的感觉和你对它是否值得追求的判断分开。

专注于你如何能最好地造福于你的公司,而不仅仅是追求你自己觉得有趣的问题,会让你成为一个更有效率的员工。[1]贵公司的关键绩效指标路线图将帮助您了解贵公司领导层认为哪些是有价值的。

接下来的章节将涵盖如何通过授权给同事了解市场来最好地帮助你的公司。对这一点的深刻理解将有助于与你的老板、产品经理或其他内部部门进行更有成效的对话。这还将有助于建立对您可能提出的数据科学计划的信任,因为您将能够更好地交流它们将如何帮助公司。

授权给同事

让我们先把事情说清楚:授权给同事的最好方式是问问他们需要什么。通过从源头上了解同事的需求,而不是猜测他们想要什么,你会节省很多时间和精力。如果你的圆滑且信息丰富的仪表板回答了你的同事实际上没有问的问题,那就没关系了。

你的非技术同事通常不需要复杂的机器学习来提高效率。对于不以编程为生的人来说,他们的主要痛点更可能是:

  1. 他们花费在四处点击以收集或移动数据上的时间
  2. 对他们负责的问题缺乏了解(例如数据质量)

幸运的是,这些领域可以直接自动化,并能极大地帮助你的同事。例如,你可以通过创建每晚运行的 Python 脚本,从各种来源提取数据,并输出一个 CSV,该 CSV 可以自动提取到 Google Sheets 或作为电子邮件发送。2

但是让我们假设你正在满足的需求是更技术性的,比如一个检测异常或预测销售的模型。对于这些更复杂的产品,**最重要的是你的产品高度可靠且易于理解,**尤其是如果你的用户是面向客户的角色。

设身处地为你的同事着想:想象一下使用一些古怪的 Flask 应用程序与不耐烦的客户开会的噩梦,当客户盯着你时应用程序崩溃,然后不知道如何重启应用程序。你的不耐烦的顾客现在没有得到他们支付的服务,现在你需要尴尬而抱歉地收拾残局,说服他们继续做你的顾客。

“是啊,嗯……所以一小时前还有效。”由间隔拍摄

避免这样的头痛,以及学习使用新工具时效率低下的烦恼,会让同事对使用你的产品犹豫不决。这是事实,即使他们在理论上同意你的产品应该使他们更有生产力!

这里的关键是建立对你产品的信任。 在你计划和构建产品的时候,尽可能经常地与你的利益相关者沟通。一旦产品“完成”,预计要花大量的时间写文档,培训同事,回答他们的问题,并纳入他们的反馈。

如果可以的话,观察你的同事们实际上如何现场使用你的产品——这是对你是否完成了帮助他们的目标的最终测试。并时刻提醒他们这个产品的意义在于帮助他们;如果它需要改变才能真正有用,那只是工作流程的一部分。

了解市场

你的公司不存在于真空中。在你办公室的墙外是客户、竞争对手、投资者、T21 和监管者,他们都以不同的方式影响着你的业务。他们关心什么,随着时间的推移会有什么变化,这对你来说意味着什么?贵公司的核心产品是什么,它满足了市场的什么需求?

了解你的公司所处的生态系统就像下十维国际象棋。由哈桑·帕夏Unsplash 拍摄的照片

这些是你的销售、营销和领导团队通常花一整天时间思考的难题,所以不要因为不是专家而感到难过。但是为了极大地提高你能给公司带来的价值,**努力去理解你公司所处的环境**

问题的正确答案:“为我们的客户建立一个支出预测器是否值得?”例如,取决于你公司外部的很多因素。在与贵公司互动时,客户是否一直有此要求?竞争对手提供这种服务吗(如果提供,你能便宜点吗)?你的销售团队是否无意中听到行业领导者抱怨难以规划他们的财务?这些问题的答案因行业和时间的不同而不同,所以你需要关注它们,以确保你交付的产品是人们真正会使用的。

但是创新呢?创新包括为现有问题创造新的解决方案,或将现有问题重新定义为我们能够解决的问题。[3]在过去的十年里,随着机器学习的迅猛发展,我们已经在许多行业看到了这种情况。难道我们不能创建一个客观上有用的数据科学模型或应用程序,一个推动市场变化而不是跟随市场变化的模型或应用程序吗?

不幸的是,事实并非如此。问题是创新是回答问题的一种方法,而真正包含商业价值的是问题本身。创新本身并不包含商业背景——你可以很容易地“创新”出别人没有的问题解决方案!

机器学习改变了从农业到生态的工业,因为它回答了人们关心的问题。有一个潜在的需求是机器学习能够解决的,但它没有创造出这个需求。为了让你的工作有影响力,你需要能够识别这些高价值的需求。[4]

self参数

前一节涵盖了数据科学的业务方面:了解你的公司和同事的观点,以及更广泛的市场背景。我们现在将向内转移,专注于你最大限度地发挥你的潜力并持续交付出色工作所需的心态和习惯。

CI:持续改进

当你开始学习一项技能时,很容易开始感到难以置信的自信。从经验来说,沿着阻力最小的路径学习可能很有诱惑力,只要坚持巩固现有知识的项目,而不是通过深入研究或拓展业务来真正挑战自己。

这种过度膨胀的自信有一个名字,叫做邓宁-克鲁格效应如果你在一个话题上夸夸其谈自己的知识,然后在别人依赖你的时候却不能真正实现它,这可能会导致令人讨厌的惊喜。了解邓宁-克鲁格效应将有助于避免这种情况,让你成为更成熟的学习者。

邓宁-克鲁格效应。图片作者。

我们如何真正变得有知识,避免陷入过度自信的陷阱?对我有效的一种心态是拥抱攀登。我喜欢把学习想象成爬山:它很慢,需要付出艰苦的努力,而且抬头看看还有多远就很容易气馁。

很容易让人想到,一旦你到达山顶,你就“成功了”,终于可以放松了。但是每当我到达一个顶峰时,我总是发现还有更多需要攀登。

如果你想成为真正的知识分子,你只需要接受永远有更多东西要学的事实…并且不断学习!我每天都努力学习,至少学一点点。通过让学习成为一种习惯,我不必依赖断断续续的意志力。[5]那些火花太不频繁了,高级的话题需要反复接触才能真正理解。

同样重要的是要记住,总会有人比你更了解某个话题……这没关系。聪明人的存在不会贬低你知道多少。

最后,数据科学在不断发展。今天最流行的语言和框架很可能与十年前不同。Python 现在占据了统治地位,但是 Julia 正在获得牵引力。Tensorflow 六年前还不存在,但当它到来时,立即统治了机器学习领域。持续学习对于保持相关性至关重要。(或者,就像 COBOL 牛仔一样,等几十年,市场会回到你身边!)

一个科堡牛仔在他们的游艇上放松。伊万·班杜拉在 Unsplash 上的照片

专注于终点线

数据科学跨越了广泛的领域,从统计分析软件工程和商业智能。这个范围如此之广,是因为从数据中提取见解的任务和将这些见解传达给其他人的任务并不完全属于一个技能类别——您的模型检测到的异常可能需要保存在某个数据库中,然后它们应该填充一个对利益相关者来说直观的仪表板,然后您应该引入更高级的统计数据来提高模型的准确性,等等。

除非你在一家大公司,有足够的资源将这些步骤分配给不同的专家,否则你可能会被期望完成所有的步骤。这可能会让你觉得工作堆积如山,超出了你的工作描述——当你的招聘人员只提到用 Python 分析数据时,你真的应该只是拿起 SparkTerraform 或建立数据库或创建仪表板吗?

我认为谦逊和灵活性对于一名数据科学家来说非常重要,尤其是在你职业生涯的早期。从机器学习中提供实际的商业价值涉及的步骤比你开始之前看起来要多得多!关键决策者可能想要一个简单的方法来检查他们自己的结果,而不是一个笔记本;一家软件公司可能希望你的模型集成到产品中,而不是 S3 的随机 R 脚本。

关注可交付成果:能让消费者真正受益的东西。尽一切努力做到这一点,无论是学习额外的技能、亲自与最终用户交谈,还是重做工作以纳入反馈。

通过关注终点线,你采用了基于解决方案的方法,而不是基于工具的方法。问题变成了“完成这项工作需要什么?”而不是“我能用 Python 做什么?”这就是为什么我觉得 R 与 Python 的辩论很愚蠢——学习适合工作的工具。

总结想法

当考虑投资什么技能时,很容易跳到最新的闪亮的深度学习包,而不是屡试不爽的个人和人际交往技能。同样,如果没有积累一些特定领域的知识,你也只能走到这一步。特定领域的知识是帮助你确定应该追求的正确问题的 T2 背景。也许是因为这些技能难以量化,或者它们不适合放在简历上。

但是了解如何最好地应用你的技术技能来真正交付商业价值,对于成为一名高效的数据科学家来说是至关重要的。在这里投入时间,你会惊讶地发现你的工作会变得更加有意义和有趣。

最好,
哑光

脚注

1.优化资源配置

这听起来像是这一部分在争论你想做的工作对公司最有利的事情是两个独立且不可调和的世界,但事实并非如此。如果你专注于交付商业价值,即做真正推动公司积极变革的工作,那么这两个世界将会完全重叠。

问题是,如果你想构建机器学习模型,而没有围绕模型的任何步骤,例如清理数据、构建管道、征求并整合用户反馈。将你的目标从做“酷数据科学”转移到做“有影响力的数据科学”将有助于你的目标与公司的目标保持一致。**

但是你也不应该期望你的工作在专业上完全满足你,在个人方面更是如此。离开学术界后,当我没有得到我想要的那么多教学时,一位前老板向我介绍了三部曲编码训练营,我现在很高兴地在那里做家教。的确,卡比尔·塞加尔在《哈佛商业评论》上发表的这篇文章认为,每个人都应该至少有两种职业。),因为这能让你享受不同的工作。

2.授权给同事

必须注意的是:当你的同事反馈进来时,很容易用一次性脚本引入大量的范围蔓延。尽你所能,试着在前面建立范围,定义反馈被视为具有较慢周转时间的特性请求的点。类似地,为了避免承担太多的技术债务,在某些时候模块化代码以使修改更容易和更安全是很重要的。

3.了解市场

这两种形式的创新来自 LinkedIn 数据科学经理潘武的一篇有趣的文章。

4.了解市场

当我读本科的时候,我的一位导师说她攻读博士学位是为了学习如何提出更好的问题。我发现这种专注于理解什么,而不是如何回答任何问题的方式,非常有见地。

5.CI:持续改进

习惯研究者 James Clear 认为最有效率的人是那些最不努力控制自己的人。这是一个违反直觉的想法,改变了我的视角。

他说,关键是构建你的环境,使你不得不进行的自我控制最小化。如果你想减肥,把饼干埋在高架子后面。如果你想读更多的书,把一本书放在你的枕头上,这样当你上床睡觉的时候会被提醒。清奇的书 原子习惯 中充满了类似这些有用的提示。

商业智能、数据科学及其对公共安全力量的影响

原文:https://towardsdatascience.com/business-intelligence-data-science-and-its-impacts-on-public-security-forces-56c330457a80?source=collection_archive---------29-----------------------

数据科学是如何被用来打击犯罪的?

卢克·切瑟在 Unsplash 上的照片

毫无疑问,在过去的二十年里,人类获取信息的方式发生了巨大的变化。直到 2000 年代,数据生成的主要负责人是公司、机构和公共服务部门,尽管如此,它们还是在内部进行,只有这个小宇宙来获取有用的知识,即使如此,它们也没有必要的技术来广泛探索它。仍在扩张的互联网还通过提供数据共享进行合作,特别是索引程序的创建(Altavista、雅虎、谷歌和不太知名的 Cadê是一些很好的例子),允许在全球范围内进行搜索,这在历史上任何时候都被认为是不可能的。

但真正加强信息时代的是社交网络行为概念的计算实现。这些技术极大地改变了人类处理自己设备上生成的内容的方式,因为他们的创造不再局限于专业手段,每个人都开始自愿成为数据生成者。所有类型的媒体开始不间断地被分享,其数量和速度前所未有。照片、音频、文本或视频,每个用户的生活和习惯开始暴露在一个虚拟的陈列柜中,供任何想“看一看”的人使用。

以前不属于词汇或只是指未来科幻作品的词已经渗透到普通公民的生活中。商业智能大数据、数据科学、数据湖已经成为商业价值创造、行为、预测分析和标准创建的代名词。新的商业模式开始出现,不是基于汽车、房子或电脑等实物产品的价值,而是基于短暂的价值,即从信息中产生知识的价值。根据购买档案对购买的产品提出建议,对推荐电影的流媒体服务的用户进行行为分析,以及使用机器学习来帮助商业决策,这些都是这些公司的重点,然后他们发现了一个具有巨大探索能力的市场利基。

加纳外交官科菲·安南的名言“知识就是力量,信息正在解放”被那些将数据作为工作来源的人的指数增长所证明是具体的。更多的“经典”公司(考虑到相对较短的时间线)如谷歌、脸书和 Twitter 是基于分析和出售信息开始其职业生涯的,而服务提供商如优步和 Airbnb 分别被认为是其行动领域中最大的一些公司。然而,要达到这些水平,这些公司已经掌握了数据分析和机器学习技术的使用。

需要澄清与获取信息相关的两个主要概念(商业智能和数据科学)之间的差异,以便发掘公共安全所拥有的数据的最大价值。商业智能是指收集、组织、分析、共享和监控支持商业管理的信息的过程。它是一套技术和工具,用于帮助将原始数据转换为有意义和有用的信息,轻松解释大量数据,识别新的机会,并根据生成的信息实施有效的战略,以促进业务在市场中的竞争优势和长期稳定性。这个概念是第一个定义信息时代最复杂分析的概念之一,是它在关系数据库和数据仓库中注册的第一个应用。然而,随着大数据的出现,技术需要发展,商业智能只是更复杂的数据探索机制中的一个齿轮。

根据 Gartner Research 的研究,大数据一词已成为全球信息技术中使用最多的术语之一,指的是公司需要处理的大量信息。数据管理主要围绕两个基本问题发展:容量和处理能力。然而,挑战已经发生了变化,这不再是一个存储甚至处理能力的问题,而是随着数据变得更加复杂,有了各种各样的新来源,数据的收集速度达到了创纪录的水平;这就形成了一个维度树,可以定义为:“一组高容量、高速度和多样性的信息,需要创新的信息处理方式来改进想法和经济决策”(其主要概念如下图所示),深化了数据分析的复杂性,并导致了数据科学的自然发展。

数据科学是一个跨学科领域,使用科学方法、流程、算法和系统从各种形式的数据中提取知识。该领域利用统计学、人工智能、数据库和科学可视化来成功实现其目标,即从存储的数据中提取最大可能的价值。根据这一知识,可以说,虽然商业智能已经以更结构化的方式处理和提供数据,但数据科学也以非结构化或半结构化的方式处理数据,鉴于其存储的数据可能具有特殊性(不同于其前身更肤浅和通用的方法),在机构中应用商业智能需要更长的时间。

随着在公司内部探索大数据概念的可能性,存储数据的速度、数量和种类呈指数级增长,从而允许应用确保发现信息的技术,这在此技术之前是不可能的。然而,一个机构可能有几个大数据来源和极其不同的数据类型,例如来自社交网络和传感器网络的数据。因此,自然进化从这些条件中扩展开来,其中之一就是数据湖。从更广泛的角度来看,这些可以被描述为覆盖一系列异构主题和业务领域的巨大数据仓库。需要有效地组织这样的存储库,以便从中获得价值;它们需要应用各种技术来提取信息和知识,从而防止它们成为一组无用的数据(数据 Swamps)⁠.从更具体的角度来看,数据湖通常被认为是组织、公司或机构中的中央存储位置,任何类型、任何大小的数据都可以以任何数据速率、使用任何导入方法(初始、批处理、流)以其原始格式(本机、原始)进行复制。例如,由微软作为服务实现的 Azure 数据湖模型:该技术最初收集数据(1),使用 Hadoop 或 Spark 处理数据(2),以不同方式组合数据(3),为分析执行转换(4),为可视化和发布做准备,生成信息(5),最后按需分发数据以供使用(6)。

但是,这些技术中的每一项意味着什么,最重要的是,它们对公共安全有什么影响?例如,一旦它们得到充分实施和掌握,下图显示了是否有可能通过数据分析指导下的警察行动来分析可疑模式并预测或预防某些犯罪行为?通过几个政府单独使用算法,如意大利的犯罪预测算法和国际刑警组织的语音生物识别系统,这个问题的答案已经是肯定的,因为近年来,各国政府已将部分重点放在收集、分析和合并输入其系统的数据上,旨在找到有助于改善其服务提供的标准。但是,公共机构拥有哪些数据,以及如何以最佳方式使用这些数据?

为了展示实用性,考虑来自公共安全部队的数据:文档、警方报告、警方行动和车辆数据是一些已知的存储。还有一些关于监狱系统的数据,以及在那里登记的所有人的健康状况。就其本身而言,仅通过来自该机构本身的数据(例如,文件、车辆和盗窃之间的关系),就已经有可能识别出无数的模式。如果将这些数据整合到一个单一的数据湖中,加上来自开放来源(如社交网络)的数据,并由一组数据科学家负责实施和应用特定的算法来发现模式,这可能会改变整个警方调查系统的影响,因为这只是这一行动的反映。例如,考虑一名囚犯的越狱。有了相互关联的数据,就可以创建预测性分析,以找出被拘留者的健康状况(以及根据地区他可能需要去哪里取药)、他们的相互关系、根据以前的犯罪可能实施的犯罪、可能的休息点(家人和朋友)或可用于逃跑的车辆,以及根据他的行为对他将采取什么行动的百分比预测。这项技术将允许代理人将他们的努力集中在某些行动上,节省不必要的旅行,并为个体的重新捕获提供一个坚实的“起点”。而这只是可能的应用之一。

总之,数据分析技术有能力为公共安全服务(以及许多其他服务)增加巨大价值,从而允许代理人与支持其工作的可靠技术进行更大程度的集成,这将提高效率、降低风险并节省公共资金。对于那些认为汤姆·克鲁斯的《少数派报告》(警察在罪犯犯罪前将其抓获)只是幻想的人来说,这是因为他们没有考虑到可以在关于一个人的数据集中找到的模式的可能性以及回归或分类分析的力量。未来的警察不再是科幻情节,而是现实。

参考

Alserafi、t . Calders、a . Abello 和 o . Romero(2017 年)。DS-Prox:用于治理数据湖的数据集邻近挖掘。第 8199 卷,第 284-299 页。

BBC 新闻(2018)。我们能预测何时何地会发生犯罪吗?网址:https://www.bbc.com/news/business-46017239.

Beyer,m .和 Laney,D. (2012)。“大数据:定义”的重要性。高德纳。URL:https://www . Gartner . com/en/documents/2057415/the-importance-of-big-data-a-definition #:~:text = % 22 big % 20 data % 22% 20 warrants % 20 innovative % 20 processing,to % 20 business % 20 goals % 20 and % 20 objectives。

b .卡森(2018)。老独角兽,新花样:Airbnb 估值天价。这是它赚取利润的大胆计划。福布斯。网址:https://www . Forbes . com/sites/biz Carson/2018/10/03/old-unicorn-new-tricks-Airbnb-has-a-sky-high-evaluation-heres-its-audacious-plan-to-earn-it/?sh=78f39ee6fa30

陈(2015)。优步想要征服世界,但是这些公司正在反击。福布斯。网址:https://www . Forbes . com/sites/陈丽岩/2015/09/09/Uber-wants-to-conquet-the-world-but-these-companies-is-fighting-back-map/?sh=436feeae4fe1

达尔,V. (2013 年)。数据科学和预测。Commun。美国计算机学会,56(12):64-73。

考夫曼(2018)。国际刑警组织推出国际语音识别数据库,使用来自 192 个执法机构的样本。拦截。网址:https://the intercept . com/2018/06/25/INTERPOL-voice-identificati on-database/

道德和发展司,O. P. (2009 年)。商业智能成功因素:在全球经济中调整业务的工具。威利,第一版。

使用 Prophet 用 Python 预测业务 KPIs 第 1 部分

原文:https://towardsdatascience.com/business-kpis-forecasting-with-python-using-prophet-part-1-1b8a97d45e3c?source=collection_archive---------18-----------------------

预测 | 巨蟒 | 办公时间

了解如何通过使用 Prophet 预测未来绩效来为您的企业增值。

弗兰克·布施在 Unsplash 上拍摄的照片

更新:你们中的许多人联系我,要求提供有价值的资源,以了解更多关于使用 Python进行时间序列预测的信息。下面我分享两个我亲自参加的课程,强烈建议你扩展这方面的知识:

* 使用代码 JULY75 在 UDACITY 球场享受 75%的折扣 *

希望你也会发现它们有用!现在欣赏:D 的文章

介绍

想象一下:你是一名 数据分析师商业智能分析师 ,拥有构建 KPI、报告和提取这些指标的洞察力的经验,但在预测模型方面几乎没有经验。与此同时,你的公司不仅愿意追溯跟踪业绩,还需要战略或动态预测,但事实证明,没有具有类似背景的数据科学家。

您的经理找到您,声称您非常适合这份工作,因为您正好具备创建预测业务 KPI 的简单模型的背景和技能,并提醒您预测将在一周内完成…

这种场景在快节奏的公司里不常见吗?

该不该慌? 不,保持一致:如果您熟悉 Python 或 R,那么 FB Prophet 可以帮助您和您的团队实现更简单的时间序列建模 方法,能够为您的业务规划和目标设定提供可靠的预测。

更详细地说,在其开源项目网页上,脸书声明:“ Prophet 是一个基于 加法模型 预测时间序列数据的程序,其中非线性趋势符合每年、每周和每天的季节性,加上 假日效应 。它最适用于具有 强季节性影响 和几个季节的历史数据的时间序列。Prophet 对缺失数据和趋势变化非常稳健,通常能够很好地处理异常值。

听起来这个工具是万能药!然后,让我们学习如何在真实的商业环境中用 Prophet 创造价值。

教程的组织

在本教程中,我们将通过实现一个模型来预测以下两个 KPI,从而对 Prophet 进行测试:

  • 日销售额: 虚构的商家每天处理的总销售额。我选择了“销售”作为 KPI,但是您可能会选择“订单”“交易”,这取决于您公司提供的产品或服务的类型。选择此指标进行预测是因为它显示每周、每月和每年的季节性,并且可以从其预测中得出其他指标。
  • 日销售额(): 每天处理的销售额,计算为日销售额平均价格。该指标表现出非常相似的季节性,但无法通过预测第一个 KPI 来准确得出。此外,每日销售额可用于得出每日收入( )以及估计平均销售额销售额 ( 每日销售额()/每日销售额)。*

本教程将分为三个部分:

第一部分(本文)关注于如何构建初始数据集,该数据集不仅包括要预测的 KPI,还包括从业务知识中获得的日期标志,这些日期标志将用于改进第二部分中的预测。然后,我将展示如何用几行代码在 Prophet 中构建简单的模型。本文还将展示如何通过结合使用matplotlibfbprophet内置绘图功能,高效、灵活地可视化您的预测。

第二部分 将致力于通过添加定制的季节性、节假日和通过修改一些更高级的参数来改进原始预测模型。特别是,我将展示如何以编程方式使用原始数据集中的日期标志来创建“假日”数据帧,作为模型的输入,并详细说明如何明智地调整傅立叶顺序来提高预测的准确性。

*

第三部分将是本教程的最后一篇,我将描述如何使用numpy进行快速模型评估,或者使用statsmodels中的评估方法或fbprophet包中固有的cross validation模块进行更高级的评估。

在本系列结束时,您将彻底了解如何使用 Prophet 来预测任何关键绩效指标,这些技能将帮助您为企业增加更多价值。有了这些前提,现在终于是开始编码的时候了!

1.导入包和数据集

第一部分的完整笔记本和数据集可在这里获得。首先让我们导入将要使用的包。这里假设fbprophet已经成功安装在您的首选环境中:

由于这篇文章也将关注如何正确地可视化预测,我将使用matplotlib“seaborn”风格,因为我发现它相当简洁。如果您希望使用不同的样式,请运行以下命令,显示可用样式的完整列表:

print(plt.style.available)

包含我们希望预测的 KPI 的数据集已经使用 SQL 查询获得,该查询在每日级别聚合两个感兴趣的指标(sales_numsales_value_gbp),然后生成四个日期标志(fl_last_working_dayfl_first_working_dayfl_last_fridayfl_new_year)。观察到的指标适用于从2017–01–012020–11–30的时间段,但数据集还包括我们希望预测的整个时间段的日期(运行到2021–12–31)。显示前 5 行导致以下结果:

如您所见,所有四个日期标志都是二进制变量,可以取值 0 或 1。例如,fl_new_year在每年的第一天等于 1,在其他地方等于 0,而fl_last_friday在每个月的最后一个星期五等于 1,在其他地方等于 0,依此类推,还有其他标志……
这些标志将用于引入特定的季节效应,以提高我们在 第二部分 中的模型的准确性,但现在让我们只绘制我们的两个 KPI,看看它们看起来像什么:

很明显,sales_numsales_value_gbp在过去三年中一直稳步增长,并且在圣诞节期间呈现出明显的季节性效应(尽管其对销售额()的影响不太明显)。如果我们随后放大并绘制 2019 年的sales_num,显然需要考虑多个季节性因素:

现在我们对这两个指标有了更好的理解,让我们看看如何预测它们在2021–12–31之前的每日价值。

2。拟合先知模型

首先,定义一些我们将在预测练习中广泛使用的日期是很方便的:

cutoff_date是将用于训练模型(2017–01–012020–10–31)的周期的最后日期,而test_end_date是将用于评估模型准确性(2020–11–012020–11–30)的周期的最后日期。
实际上,正如你可能已经注意到的,测试期从一开始就与实际预测重叠(将在2020–11–012021–12–31之间运行),这将允许我们将实际值与预测值进行比较。最后要定义的是我们希望预测的未来天数(days_to_forecast),这可以通过将forecast_end_dateforecast_start_date传递给pd.timedelta().days来轻松实现。

接下来,是时候将我们希望预测的指标包括在列表中了:

kpis = [‘sales_num’, ‘sales_value_gbp’]

然后创建一个数据集,为kpis列表中的每个 KPI 训练我们的模型。请注意,df_train应仅包括两列(观察日期和由 for loop 在任何给定时间从列表中选择的单个 KPI),并且nan值应被过滤掉或替换为零,这取决于具体的使用情况。此外,fbprophet要求根据观察日期变为ds并且模型度量变为y的约定来重命名训练数据集中的列:

现在,创建我们的模型并使用训练数据集对其进行拟合的一切都已就绪。这可以通过在循环中添加以下代码来轻松实现:

如果这是您第一次使用 Prophet,您可能想知道模型中指定的参数的含义。为了理解如何正确使用它们,重要的是要强调Prophet()预测函数已经带有以下默认参数(在 Jupyter 笔记本中,它们可以通过将光标放在括号中间,然后键入 shift + tab + tab来显示):

使用 Shift + Tab 显示的默认参数

这意味着,使用 数据探索业务知识 的组合,我们能够评估我们的模型构建应考虑:

  • 两个 KPI 的潜在趋势的线性增长:这很容易通过简单的绘制数据来理解。如果趋势持续增长,没有任何饱和迹象,那么您应该将参数设置为“线性”(或者是逻辑)。
  • 两个 KPI 的乘法季节性模式:当季节性因素的重要性随着时间的推移而增加,而不是在整个期间保持不变时,应首选乘法参数,而不是默认的“加法”参数。
  • 是否存在年季节性:由于数据有每日粒度,daily_seasonality被设置为False,而weekly_seasonalityyearly_seasonality都被设置为True
    (默认值为auto)。但是,如果我们希望添加更多的季节性因素(例如一个月的成分),该怎么办呢?在这种情况下(我们将在第二部分中学习),解决方案是使用add_seasonality()方法,指定一个定制组件。暂时让我们坚持由Prophet()预测者提供的默认选项。
  • 一个0.95的不确定性区间宽度:我们马上会看到,Prophet 模型将输出一个预测值以及不确定性(或置信)区间的下限和上限。interval_width的默认值为 0.80,这意味着不确定性区间将只覆盖由蒙特卡洛模拟产生的 80%的样本(默认为 1000 个样本)。为了提高间隔的准确性,最好将阈值提高到 95%。也让我们记住,这个区间只会跟踪趋势 中的 不确定性,然后忽略季节成分中嵌入的波动性。**

既然我们知道了如何调整基本参数,我们最终可以预测 KPI 的未来值。为了做到这一点,第一步是创建一个包括观测数据和未来日期的数据集。在我们的例子中,days_to_forecast对应于未来的 426 天:

future_data = model.make_future_dataframe(periods=days_to_forecast)

然后是在future_data上运行model.predict()以获得最终预测的时候了。可以看到,我们只选择了四个最相关的列(即观察日期 ds预测值 yhat不确定区间下限 yhat_lower上限 yhat_upper 界限和底层trend):

forecast = model.predict(future_data)[[‘ds’,’yhat_lower’, ‘yhat’,’yhat_upper’, ‘trend’]]forecast.tail()

显示时,sales_numforecast数据集的第一行和最后五行看起来像 :

销售编号的预测数据框架的标题

销售编号的预测数据框架的尾部

*请注意,在使用循环预测多个 KPI 时,该数据集中可用的最后一个预测将是为 *kpis* 列表中的最后一个指标计算的预测。

你可能已经注意到 Prophet 提供了观测日期和未来日期的估计值,这意味着forecast包括从2017–01–012021–12–31的每一天的预测。这是一个需要记住的非常重要的细节,尤其是在下一节中,我们将可视化预测。
目前,我们希望保留df数据框中的原始观察值,并用预测值替换NaN值。这可以通过下面这行代码来实现:

3.可视化预测结果

在这一节中,我将介绍三种我认为在评估 Prophet 内置模型的性能时特别有用的可视化方法。实际上,绘制 观察值预测值 使得比较模型(使用不同的参数)更加直接和直观。

即 1:一段时间内的趋势变化点

使用fbprophet时,您可以通过运行以下命令简单地绘制预测:

model.plot(forecast)

尽管嵌入在包中的绘图工具对于一个非常高层次的分析可能工作得很好,但是它非常简单并且很难调整。这些限制使得它很难在工作场所销售。然而,您可以直接使用 Prophet 构建一个有趣的图表,该图表显示一段时间内的 趋势变化点 :

将趋势变点添加到预测值图中

在上图中,黑点表示观察值,而蓝线表示预测值。如上所述,当运行model.predict(future)数据时,会计算整个数据集的预测值。
显示的变点数量和分段潜在趋势的形状将根据分配给changepoint_range(默认值为 0.8)和changepoint_prior_scale(默认值为 0.05)参数的值而变化,因为它们直接影响模型对趋势变点的灵活性。

即 2:预测与实际重叠

将预测值与实际值(观察值)进行比较的一种更直观的方法是使用不同的颜色和不透明度来重叠两个时间序列。为此,我们需要一个数据框架,其中实际值和预测值保存在不同的列中:

# Join Original Dataset With Forecast
combined_df = df.join(forecast, how = ‘outer’)combined_df[['observation_date', 'sales_num', 'yhat_lower' , 'yhat', 'yhat_upper' ,'trend']].tail()

相关字段的组合 _df 的尾部

这意味着在用 **df** 中未来日期的预测值替换 **NaN** 值之前,应创建**combined_df** ,该预测值之前已获得,如下所示 :

df.loc[(df[‘observation_date’]>cutoff_date ),kpi]=forecast[‘yhat’]

这是因为我们将使用matplotlib来重叠两个不同的列,如下所示:

实际值与预测值重叠,以直观地评估绩效

我们现在可以清楚地看到,尽管当前的模型能够很好地适应潜在的趋势,但它在高峰日或特定假日(如圣诞节期间)仍然表现不佳。在第二部分中,我们将学习如何实现包含假期的模型,使其更加精确。

即 3:分别显示预测和实际

在某种程度上,您可能希望向您的同事展示这个模型,而上面的可视化对于不太懂技术的观众来说可能仍然很混乱。最好将两个时间序列完全分开,先显示实际值,后显示预测值,包括不确定性区间:

实际值和预测值分别绘制

必须强调的是,在2020–11–012020–11–30之间,实际值和预测值仍然存在重叠,您应该记得,这是为了测试模型的准确性而选择的一个月时间。

4.快速模型评估

在本教程的最后一节,我们将使用平均绝对百分比误差(MAPE) 来计算单个值的模型性能。还有许多其他指标可用于评估预测模型的质量(第三部分将深入探讨该主题),但目前单一指标可能更直观。为了计算 MAPE,我们首先创建一个使用combined_df作为输入的combined_df_test,但是只针对 2020 年 11 月。然后我们用numpymape写我们自己的公式:

Output:
MAPE: 6.73587980896684

运行上面的代码,我们得到的 MAPE 为 6.73% ,表明在所有预测点上,预测值与实际值的平均偏差为 6.73% 。对于一个半开箱即用的模型来说,这已经是一个相当不错的结果了,但是我们会在第二部 的 中尝试显著降低 MAPE。

结论

关于 用预言家 预测业务 KPI 的第一个教程到此结束,希望你已经喜欢了!如果你跟着做,你应该有足够的材料开始通过建立一个模型来预测未来的表现,为你的企业创造价值。

但是我们这里还没有完成:在第二部分 中,您将学习如何使用您的业务知识构建一个更复杂的模型,将特殊事件或季节性因素作为模型变量传递,而在 第三部分 中,您将学习如何使用 交叉验证 和其他 评估指标 来所以我看到你在那里,继续学习!

给读者的一个提示:这篇文章包括附属链接,如果你购买的话,我可以免费给你一点佣金。

你可能也会喜欢

* https://medium.com/analytics-vidhya/connect-to-databases-using-python-and-hide-secret-keys-with-env-variables-a-brief-tutorial-4f68e33a6dc6 </7-fundamental-sql-concepts-you-will-be-challenged-with-in-faang-interviews-d26097a8d867> 💔-ways-to-compute-a-weighted-average-in-python-4e066de7a719> **

posted @ 2024-10-16 09:06  绝不原创的飞龙  阅读(207)  评论(0)    收藏  举报