TowardsDataScience-博客中文翻译-2020-四十一-

TowardsDataScience 博客中文翻译 2020(四十一)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

将 Streamlit 应用部署到 GCP

原文:https://towardsdatascience.com/deploying-streamlit-apps-to-gcp-79ad5933013e?source=collection_archive---------16-----------------------

来自 Unsplash 的 Rene b hmer 的照片。

什么是 Streamlit?

如果您熟悉 Python 中的数据科学软件生态系统,您可能会遇到一些广泛使用的仪表板和数据可视化工具,这些工具是为编程用途而设计的(例如,嵌入笔记本电脑或作为独立的 web 应用程序)。在过去的几年里,像 DashBokehVoila 这样的公司已经成为这个领域中最大的开源公司之一。在 R 的世界里,还有仪表板工具的长期冠军:闪亮

有了这个相对成熟的生态系统,你可能会质疑是否需要一个又一个框架来加入这个群体。但这正是 Streamlit 的团队正在做的事情:引入一个全新的框架来构建数据应用程序。更重要的是,他们也为他们的项目制造了不少轰动,以至于他们最*结束了一轮 2100 万美元的首轮融资,以允许他们继续开发他们的框架。

[## 宣布推出价值 2100 万美元的 Streamlit A 系列产品

为数据科学界开发新的超级能力。

medium.com](https://medium.com/streamlit/announcing-streamlits-21m-series-a-ae05daa6c885)

那么是什么让人们对 Streamlit 如此兴奋呢?

Streamlit 中实时计算机视觉可视化。照片来自 Streamlit

首先,这是你可能遇到的最简单的工具之一。没有样板文件,也没有什么特定于框架的概念需要记住。感觉设计的非常好。总的来说,这种简单性使得在几秒钟内构建一个应用程序变得非常快速和容易。

这种极简主义有助于第二个要点:事件管理轻而易举。这听起来可能很无聊,但在这种情况下这是一件大事。在 Streamlit 中管理事件不需要特定于框架的设计模式/回调。例如,假设您想通过点击一个按钮来运行一些代码,您可以在 Streamlit 中用以下代码来捕获:

import streamlit as stif st.button("Click Me"):
 print("Clicked")

每当按下Click Me按钮时,其下的程序块将被执行。相同的概念以几乎相同的方式应用于他们所有的交互组件。它在幕后做了一些聪明的把戏来实现这一点,但最终效果是一样的:你可以快速简单地编写具有复杂行为的应用程序,只需对底层代码做很少的更改。与 Fire 让为现有代码创建 CLIs 变得异常容易一样,Streamlit 让从现有代码创建交互式应用变得异常容易。正如他们所说:它被设计成“洒”在你的代码上。

最后,Streamlit 与现有的数据可视化工具集成起来也非常容易,并且非常容易部署启动——它与现代部署工具和技术配合得非常好。你可以随心所欲地将你的matplotlib图表嵌入到你的dash图中,然后将其打包,随时准备部署。总而言之,这些特性共同使 Streamlit 成为目前最具生产力的现代数据可视化工具之一。

创建您的应用

虽然 Streamlit 的文档对入门很有帮助,但是没有太多关于部署应用的内容。本文旨在强调将 Streamlit 应用部署为一个面向公众的实时网站是多么简单。它将使用 Streamlit 提供的一个“标准”演示应用程序:一个按一天中的时间在纽约市的优步皮卡的可视化。但是,您可以随意创建自己的应用程序并进行部署(您将使用的模板无需更改!).

你需要什么

开始之前,你需要确定你已经准备好了一些东西。您将使用 Google App Engine 部署您的应用程序,因此这意味着您需要注册一个 Google Cloud 帐户(注册时还有 300 美元的信用点数!)然后安装他们的gcloud命令行工具。你可以在这里注册一个账户(不是代销商链接,不用担心!):

[## GCP 免费等级免费扩展试用和永远免费|谷歌云

GCP 自由层以两种方式扩展我们的免费计划。3 个月免费试用的 300 美元积分和 20 多种免费产品…

cloud.google.com](https://cloud.google.com/free)

谷歌云也为安装gcloud提供了很好的“入门”指南。

[## gcloud 命令行工具概述| Cloud SDK 文档

本页包含 gcloud 命令行工具及其常用命令模式和功能的概述。的…

cloud.google.com](https://cloud.google.com/sdk/gcloud)

完成后,确保你已经安装了Docker并且正在运行。你不需要与 Docker 互动来跟进这篇文章,但你需要它运行!您还需要拥有 Python 3.6 或更高版本的有效版本。为项目设置并激活一个 Python 虚拟环境也是一个好主意。

编码时间到了

所以,首先要做的是。您需要从 GitHub 克隆部署就绪的 Streamlit 项目模板。在您的终端中,运行:

git clone [https://github.com/markdouthwaite/streamlit-project](https://github.com/markdouthwaite/streamlit-project)

导航到新的streamlit-project目录并运行:

pip install -r requirements.txt

正如您所料,这将安装运行此应用程序所需的软件包。有了这个设置,是时候测试你的应用了!您可以通过以下方式做到这一点:

make run-container

将您的应用程序构建到 Docker 映像中,并在http://0.0.0.0:8080启动运行您的应用程序的新容器。它会自动打开一个新的浏览器选项卡并加载你的应用程序。您应该会看到这样一个可爱的可视化效果:

照片来自 Streamlit

你可以随意编辑这个应用程序。了解 Streamlit 的强大功能是值得的。当你完成后,只要确保make run仍然在http://0.0.0.0:8080成功启动你的应用,然后你就可以开始部署了。

部署您的应用

您将使用谷歌应用程序引擎来部署应用程序。这是由 Google Cloud 提供的托管服务,可以帮助您超级轻松地部署和扩展您的应用。谷歌将为你管理缩放、服务器设置和其他零碎的东西。您所需要的只是一个正确配置的 Docker 映像,而且您已经很接*了。转到您的谷歌云控制台,前往左侧导航菜单中的 App Engine,检查您的 App Engine API 是否处于活动状态。您现在应该能够运行:

make gcloud-deploy

这将建立你的图像,存储在谷歌容器注册(GCR),然后配置和启动你的应用程序。完成后它会告诉你的。您应该会看到类似这样的内容(其中{{YOUR-URL}}将是您部署的应用程序的 URL):

Deployed service [default] to [{{YOUR-URL}}]

导航到所提供的 URL,查看您的应用程序的所有优点!

后续步骤

完成后,你的应用程序现在是公开可见的,可以与你希望的任何人共享。您现在还可以使用make gcloud-deploy自由编辑和重新部署您的应用程序。你甚至可以考虑用 GitHub Actions 构建一个持续集成和持续交付 (CI/CD)管道,以便在每次你向 GitHub 推送更改时自动重新部署你的应用。不过这取决于你!

解决纷争

如果你在上述步骤中遇到任何问题,App Engine 的文档非常好,值得一看:

如果你还在挣扎,请随时在 Twitter 上联系我。

收尾工作

差不多就是这样了。以可扩展、安全的方式部署新的 Streamlit 应用。简单,嗯?当您深入研究 Streamlit 时,您会注意到它在几个方面仍然有点受限:例如,布局和样式在默认情况下是高度受限的。然而,他们最*的几轮融资给了他们很多开发一些很酷的新功能的机会,这些东西在他们的功能路线图上,所以他们的到来只是时间问题。如果你对数据可视化感兴趣,Streamlit 绝对值得一看。

使用简化 it 共享部署简化 it 应用

原文:https://towardsdatascience.com/deploying-streamlit-apps-using-streamlit-sharing-16105d257852?source=collection_archive---------29-----------------------

先睹为快 Streamlit 的新部署*台

作者图片

在过去的几周里,我一直在玩一个名为 Streamlit sharing 的新 Streamlit 功能,它使部署您的定制应用程序变得非常简单。我将首先介绍一些背景知识,因此如果您想查看 Streamlit 共享的文档,您可以在这里找到它们。

流线型背景

简单介绍一下背景,Streamlit 是一个框架,它可以让您快速而自信地将 python 脚本转换为 web 应用程序,对于需要快速共享模型或交互式分析的团队中的数据科学家来说,或者对于从事希望向世界展示的个人项目的数据科学家来说,它是一个不可思议的工具。如果你想尝试一下,这里有一个 Streamlit 初学者教程

在过去的大约 6 个月里,我一直在使用 Streamlit,它一直非常有用。以前,如果我知道我想在项目结束时制作一个 web 应用程序,我总是会选择切换到 R 来获得精彩的 R shiny 框架,即使我是一个比 R 好得多的 python 程序员。经历 Django 或 flask 是如此多的开发摩擦,以至于对于个人项目来说很少是值得的,并且对于工作中的任何事情来说总是花费太多时间。但是在使用 Streamlit 之后,我现在不仅有了选择,而且发现自己更喜欢 python+Streamlit 而不是 R+shiny。

简化共享

这让我想起了几个月前。我启动了一个 DS 项目,专注于使用来自 Goodreads 应用的数据分析阅读习惯。我决定尝试一下 Streamlit,它将一个 Django/flask 应用程序在本地正常运行的多日过程变成了一个在本地使用 Streamlit 大约需要半小时的过程。这真的很简单,只要你想在应用程序上放一个图表、小部件或文本解释器,就可以把你的分析放到一个脚本中,并调用 Streamlit 函数。

然而,Streamlit 上最烦人的流程是部署和管理流程。我跟着学的教程很简单,没花多少时间,但是相当广泛。它需要启动一个 ec2 实例,配置 SSH,使用 tmux,并在每次想要更改 web 应用程序时返回到这个终端。这是可行的,但令人讨厌。

作者图片

几周前,Streamlit 看到了我的 Goodreads 应用程序,问我是否想测试一下他们的 Streamlit 共享测试版,该测试版应该可以消除上面解释的摩擦。很明显,我尝试过了。

我所要做的就是:

  1. 将我的应用程序推送到 Github 回购
  2. 添加一个 requirements.txt 文件,列出我使用的所有 python 库
  3. 通过指向存储库的链接将 Streamlit 指向我的应用程序
  4. 单击部署

这真的是那么容易弄清楚。我花了几个小时来解决这个问题,因为我预计会出现各种各样的错误(这是测试版!),但我只用了不到 10 分钟就让它启动并运行了。

我目前正在运行三个应用程序,一个是测试应用程序,第二个是我之前提到的 Goodreads 图书推荐应用程序,第三个是我在大约一个半小时内完成的一项技术调查的交互分析(从想法到运行和部署 web 应用程序)。

切换到 Streamlit 共享还为我节省了每月约 5 美元的 AWS 账单,我很乐意为这项功能支付这笔费用,仅仅是因为节省了部署时间。

作者图片

如果我想尝试一个新的应用程序,我只需点击新的应用程序按钮,将其指向我的回购,他们就会处理其他一切。

作者图片

如果您的 Streamlit 应用程序使用任何其他包,请确保在您的 repo 中包含 requirements.txt 文件,否则您会在部署时立即得到一个错误。你可以使用像 pip freeze 这样的东西来获取需求,但是这会给你环境中的所有包,包括那些你在当前项目中不使用的包。这将降低您的应用程序部署速度!所以我建议使用像 pipreqs 这样的东西来保持你的应用程序的核心需求。

pip install pipreqs
pipreqs /home/project/location

如果对 apt-get 有要求,添加到packages.txt -,一行一个包。

结论

总而言之,Streamlit sharing 在节省开发时间和托管成本方面为我节省了美元(对使这一切成为可能的风险投资基金大喊一声),使我的个人项目更具互动性和更漂亮,并消除了部署快速模型或分析的头痛。难怪我是细流迷。

想看更多这方面的内容?你可以在 TwitterSubstack我的作品集网站上找到我。

快乐的小溪!

部署晦涩的 Python 脚本:肖像图片的神经造型

原文:https://towardsdatascience.com/deploying-the-obscure-python-script-neuro-styling-of-portrait-pictures-49fa99b5dc8c?source=collection_archive---------49-----------------------

Python 脚本的快速部署

作者 Rosaria Silipo 和 Mykhailo Lisovyi,KNIME

今天的款式是什么?

当今风格:卡拉瓦乔还是毕加索?

几个月前在网上冲浪时,我们看到了这项研究[i],它承诺训练一个神经网络来根据你喜欢的画家的风格改变任何图像。这类研究释放了你的想象力(或者至少是我们的想象力)。

如何改变我目前的肖像图片,给它一个著名的卡拉瓦乔画美杜莎触摸?那位同事的肖像照得更像毕加索的风格不是更好看吗?或者把梵高的《星夜》作为另一个梦幻同事的背景?给我们当中最喜欢冒险的人一点伊卡洛斯蓝?如果你对艺术有一点了解,你可以给自己的肖像赋予无穷无尽的细微差别。

好消息是这项研究附带了一个 Python 脚本,可以下载并重复使用。[二]

坏消息是,我们大多数人没有足够的 Python 知识来部署解决方案或使其适应我们的图像集。事实上,我们大多数人甚至没有足够的关于算法本身的知识。但事实证明我们不需要。我们不需要了解 Python,也不需要了解算法细节来根据一幅选定的画生成神经风格的图像。我们实际需要做的是:

  • 上传人像图片,选择喜欢的风格(梵高的夜星,伊卡洛斯蓝,卡拉瓦乔的美杜莎等。).
  • 稍等片刻,等待奇迹发生。
  • 最后,下载神经风格的肖像图像。

这确实是最终用户需要做的所有事情。关于算法的细节是不必要的,因为底层 Python 脚本的全部知识也是不必要的。最终用户也不需要安装任何额外的软件,应该能够通过任何 web 浏览器与应用程序进行简单的交互。

你知道卡拉瓦乔画的美杜莎吗?这是他著名的自画像。注意美杜莎头上的蛇(图 1b)。图 1a 显示了本文作者之一 Rosaria 的肖像。如果我们根据卡拉瓦乔的美杜莎(图 1c)重新设计罗萨莉亚的肖像,会发生什么?

为了查看神经样式化的结果,我们将 Python 脚本(用于对图像进行神经样式化)集成到一个应用程序中,该应用程序可通过网络访问,与算法无关,不支持脚本,并且具有完全根据最终用户的请求定制的用户界面。

来自网络浏览器的图像神经造型

图二。对图像进行神经样式化所需的三个步骤:1)上传图像文件并选择艺术样式。2)等待网络找出神经样式。3)欣赏你的新肖像,它具有你喜欢的绘画的艺术风格。

从电脑、*板电脑或智能手机上的网络浏览器,该应用程序以最经典的方式启动,上传图像文件。让我们上传两位作者 Misha 和 Rosaria 的肖像图片。

之后,我们被要求选择绘画风格。罗萨莉亚是卡拉瓦乔绘画的忠实粉丝,所以她选择了《美杜莎》。米沙更喜欢毕加索的立体派,选择了他的《多拉·玛尔画像》

此时,网络开始处理数据:在我自己的笔记本电脑上用了 35 分钟,只用了我的 CPU 在更强大的机器上 35 秒[iv]带 GPU 加速。

现在,我们进入应用程序的最终网页。让我们看看网络提出的重新设计(图 3-4)。

神经风格图像在下面的图 3 和图 4 中示出。请注意,输入图像没有发生很大的变化。他们只是从艺术杰作中获得了一些颜色和图案,比如罗莎丽亚的美杜莎式头发或米莎照片中的背景墙。免责声明:尽管这些照片很有趣,但它们可能还不能用于你的护照!

三个简单的步骤从原始图像到相同的图像,由大师设计!不需要脚本和底层算法的调整。您只需要知道图像文件的位置和要应用的艺术风格。如果你改变主意,你可以随时回去改变绘画风格或输入图像。

实现图像神经造型应用

为了组装这个应用程序,我们只需要我们工具中的一些特性。

  1. 与 Python 的集成
  2. 图像处理功能
  3. web 部署选项

Python 集成

这里的任务是集成由牛津大学视觉几何小组开发的 VGG19 神经网络,该神经网络可以从 Keras Documentation pageii 下载 Python 脚本来设计任意肖像图片。因此,我们需要一个 Python 集成。

开源分析*台的核心安装【v】中提供了与 Python 的集成。你只需要安装带有核心扩展的分析*台和带有 Keras 包的 Python。两个都安装好之后,您需要通过 File->Preferences->Python 页面将分析*台指向 Python 安装。如果你对下一步该做什么有疑问,请遵循 Python 集成安装指南和深入

学习集成安装指南

安装后,您应该在节点库面板中看到一个 Python 类别,包括免费脚本、模型训练、模型预测器、绘图和更多 Python 函数(图 5)。所有 Python 节点都包括一个语法突出显示的脚本编辑器、两个用于脚本测试和调试的按钮、一个工作区监视器和一个显示可能错误的控制台。

注意,类似的集成也适用于 R、Java 和 JavaScript。这整个集成环境也使您能够协作和共享同事的代码和脚本。

图 5。在 KNIME 分析*台中提供 Python 函数的 Python 节点

图像处理扩展

图像处理功能在图像处理社区扩展中可用。安装后,您将在节点存储库中看到图像处理功能,在类别 Community Nodes/Image Processing 中。您可以使用它们来处理图像、提取特征、标注、过滤噪声、处理尺寸以及变换图像本身。

Web 部署选项

web 组件由 WebPortal 提供。所有小部件节点在封装到组件中时,都将其图形视图显示为网页的一个元素。图 2 所示的两个网页是通过将多个小部件节点组合成一个组件而构建的。

最终工作流程

实现上述 web 应用程序的最终工作流程如图 6 所示,可从中心下载,或从示例服务器的分析*台中,在 50 _ Applications/56 _ Restyling _ Images _ using _ Deep _ Learning 下下载。

图 6 中的工作流程开始于读取输入肖像图像和艺术风格图像(名为“上传输入图像”的组件)。然后,输入图像被调整大小、归一化,并且其颜色通道被重新排序。此时,Python 脚本(执行附录中所述的神经造型,并封装在名为“Python 中的样式转换”的组件中)接管并使用新的输入图像和选定的艺术样式重新训练神经网络。然后,对生成的图像进行反规格化,并将颜色通道恢复到原始顺序。最后一个节点称为“显示样式图像”,在最终的 web 页面上显示结果图像。

请注意,没有必要修改 Python 代码。将原始代码复制并粘贴到 Python 节点编辑器中,只需进行一些调整(例如,参数化训练设置)就足够了。

在更高的层面上,当终端用户从他们的 web 浏览器运行应用程序时,他们将看不到任何底层的 Python 脚本、神经网络架构,甚至是训练参数。这是向最终用户隐藏晦涩的脚本和算法复杂性的完美伪装。

图 6。工作流 01_Image_ReStyling_WebPortal 实现基于网络的应用程序,该应用程序执行输入图像的神经造型,并可在 50 _ Applications/56 _ ReStyling _ Images _ using _ Deep _ Learning 下的示例服务器上或在 KNIME Hub 上获得。

Python 代码作为可重用组件

现在,Python 脚本似乎工作得相当好,我们大多数不了解 Python 的人也可能喜欢使用它。“Python 中的样式转换”组件中的 Python 代码对我们来说工作得很好,但对其他人来说很难回收。

为了提高其他用户对 Python 脚本的可重用性,我们将这个组件转换为一个模板,并将其存储在一个中心位置。现在,新用户只需拖放模板,就可以在其工作流程中生成一个链接组件。

已经为图像处理组件创建了类似的模板。您可以通过灰色节点左下角的绿色箭头来识别此类模板的链接实例。

一键部署图像神经造型应用

最后一步是部署。换句话说,如何将我们新开发的工作流转化为一个可从 web 浏览器访问的高效应用程序,并处理当前数据。

我们需要做的只是将神经造型工作流从分析*台的本地工作区拖放到一个工作区。然后,可以通过服务器的 web 门户从任何 web 浏览器调用工作流。此外,如果使用了任何小部件节点,那么在 WebPortal 上执行工作流将会产生一系列交互式网页和仪表板。

请注意,这种一键式部署过程适用于任何 Python 脚本的部署,使其在生产环境中更易于使用。

总结

以玩 Rosaria 和 Misha 及其同事的神经风格肖像为借口,我们已经展示了导入、集成和部署一个晦涩的 Python 脚本是多么容易——而不需要了解 Python。

我们还展示了如何配置应用程序,使其可以在任何 web 浏览器上运行,我们只要求最终用户提供最少的必要信息,并隐藏所有其他不必要的细节。

为了使 Python 脚本和应用程序的其他部分可以被其他人重用,我们将一些部分打包为模板,并将其作为链接组件插入到许多其他不同的应用程序中。

附录:神经式转移

神经风格转移是一种使用神经网络从一幅图像中提取绘画风格并将其应用于另一幅图像的技术。它最早是在《艺术风格的神经算法 I》中提出的

主要思想是利用这样一个事实,即卷积神经网络(CNN)【VI】在不同的层中捕捉不同的复杂程度。第一个卷积层可以作为低级边缘检测器,而最后一个卷积层可以捕获对象。由于我们只对通用对象检测器感兴趣,所以我们不需要为了风格转换而训练专用网络。相反,我们可以使用任何现有的预训练多层 CNN。在本文中,我们使用了由牛津大学视觉几何小组开发的 VGG19 神经网络,该网络以 Python 脚本的形式提供,可从 Keras 文档页面[ii]下载。

样式化过程被定义为自定义函数的优化。该功能有几个部分:

  • 一个术语确保结果图像类似于原始图像中的高级对象。这是通过输入和输出图像之间的差异实现的,其中输出图像是最后一个卷积层中的网络响应。
  • 第二学期旨在捕捉艺术绘画的风格。首先,样式被表示为层内跨通道的相关性。接下来,从第一层到最后一层,跨 CNN 层计算样式表示的差异。
  • 最后一个术语加强了生成的风格化图像的*滑度,并在“通过反转图像来理解深层图像表示”中得到提倡

最后,使用由 Keras 提供的自动微分功能迭代地执行该定制函数的优化。自定义函数需要针对每个新的输入图像进行优化。这意味着,对于每一个新的肖像,我们需要在预先训练好的 CNN 上再次运行优化程序。

[i] L. Gatys 等,艺术风格的神经算法,[arXiv:1508.06576]

[ii] Keras 神经传递样式示例,Keras 文档页面

[iii]笔记本电脑规格:CPU Intel i7–8550 u,4 核,多线程;16 GB 内存

【四】GPU 机器规格:CPU Intel i7–6700,4 核,带多线程;32 GB 内存;配备 8GB VRAM 的 NVIDIA GeForce GTX 1080

[v] Aravindh Mahendran,Andrea Vedaldi,通过反转理解深层图像表示,[arXiv:1412.0035]

[vi] 卷积神经网络YouTube 上的视频系列,Deeplearning.ai,2017

如首次发表于data versity

在 AWS Fargate 中部署 Docker 容器

原文:https://towardsdatascience.com/deploying-web-applications-with-docker-in-aws-fargate-bb942de733a4?source=collection_archive---------10-----------------------

使用 Fargate 和 Cloud Formation 在 AWS 中部署容器化 web 应用程序的分步指南

照片由维达尔·诺德里-马西森Unsplash 拍摄

动机

Docker 是一个非常棒的工具,可以用一种简单且可扩展的方式封装和部署应用程序。事实上,我发现自己经常做的事情是将 Python 库封装到 Docker 映像中,以便以后可以用作项目的样板。

在本文中,我将说明如何在容器注册表中注册 Docker 映像,以及如何使用 Fargate 在 AWS 中部署容器,Fargate 是一个无服务器计算引擎,旨在运行容器化的应用程序。此外,我们将使用云形成以编程方式部署我们的堆栈。我们开始吧!

在容器注册表中注册您的图像

容器注册对于 Docker 图像就像代码库对于编码一样。在 registry 中,您可以创建映像存储库来推送和注册您的本地映像,您可以存储同一映像的不同版本,如果其他用户有权访问存储库,他们可以推送和更新映像。

现在,假设您已经在本地开发了一个映像,并希望将其部署到云中。为此,我们需要将本地映像存储在一个容器注册表中,可以从该注册表中提取和部署映像。在本文中,我将使用一个相当简单的图像,在端口 80 上启动一个 web Python-Dash 应用程序。

我们将使用 ECR (弹性容器注册表)来注册我们的图像。ECR 是一个 AWS 服务,非常类似于 DockerHub,用于存储 Docker 图像。我们要做的第一件事是在 ECR 中创建一个存储库,我们可以按如下方式使用 AWS CLI:

aws ecr create-repository \
--repository-name dash-app\
--image-scanning-configuration scanOnPush=true \     
--region eu-central-1

您应该能够在 AWS 管理控制台中看到存储库

要将本地图像推送到我们的 ECR 存储库,我们需要在 AWS 中验证我们的本地 Docker CLI:

aws ecr get-login-password --region **region** | docker login --username AWS --password-stdin **acccount_id**.dkr.ecr.**region**.amazonaws.com

适当更换aws_account_idregion即可。您应该会在终端中看到消息Login Succeeded,这意味着我们的本地 Docker CLI 已经过身份验证,可以与 ECR 交互。

现在,让我们将本地图像推送到我们全新的存储库中。为此,我们必须标记我们的映像以指向 ECR 存储库:

docker tag **image_id** **account_id**.dkr.ecr.eu-central-1.amazonaws.com/dash-app:latest

现在我们只需要把它推到集控室:

docker push **account_id**.dkr.ecr.eu-central-1.amazonaws.com/dash-app:latest

您应该会在 AWS 控制台中看到推送的图像:

现在我们到了本节的结尾,让我们总结一下:(I)我们已经在 ECR 中创建了一个名为 dash-app 的映像存储库,(ii)我们已经授权我们的本地 Docker CLI 连接到 AWS,以及(iii)我们已经将一个映像推送到该存储库。在下一节中,我们将介绍如何在 AWS 中部署这个映像。

在 AWS 中部署 Docker 容器

撇开 Kubernetes 不谈,AWS 提供了几种部署容器化应用程序的选项:

  1. 在 EC2 上部署容器,通常是在一组自动扩展的实例中。在这个场景中,我们负责修补、保护、监控和扩展 EC2 实例。
  2. 在 AWS Fargate 上部署容器。因为 Fargate 是无服务器的,所以不需要管理或提供 EC2 实例。Fargate 管理我们的任务的执行,提供适当的计算能力(在这个上下文中,任务指的是作为应用程序一起工作的一组容器)。

在本节中,我们将关注第二个选项,说明如何在 AWS Fargate 上部署我们的 web 应用程序。此外,我们将为 AWS 云的形成分配所有必要的资源。

云的形成

云形成是一种以编程方式提供和部署资源的 AWS 服务,这种技术通常被称为代码或 IaC 基础设施。在 IaC 中,我们不是通过管理控制台手动分配资源,而是在 JSON 或 YAML 文件中定义堆栈。然后,该文件被提交给 Cloud Formation,它会自动部署文件中指定的所有资源。这有两个主要优势:(I)它使自动化资源供应和部署变得容易,以及(ii)这些文件有助于作为我们的云基础架构的文档。

尽管在 JSON/YAML 文件中定义我们的堆栈需要经历一个学习过程,并且忘记 AWS 管理控制台及其真正易于使用的向导,但从长远来看,这绝对是值得的。随着基础设施的增长,将所有的栈保持为代码将对有效地扩展非常有帮助。

堆栈

现在,让我们列出运行应用程序所需的资源:

  1. 任务 : 它描述了塑造我们的应用程序的一组 Docker 容器。在我们的例子中,我们只有一个图像。
  2. ECS 服务 : 它负责运行和维护所需数量的任务实例。例如,如果任务失败或停止,ECS 服务可以自动启动一个新实例,以保持所需数量的任务处于服务状态。
  3. Fargate:一个用于容器的无服务器计算引擎。使用 Fargate,无需预订和管理服务器。它会自动提供计算能力来运行我们的任务。
  4. 网络资源:我们还需要一个 VPC,一个通过路由表连接到互联网网关的公共子网(别忘了我们正在部署一个应该可以从互联网到达的 web 应用程序),以及一个安全组来安全地运行我们的容器。如果已经有了网络配置,就不需要设置这些资源,尽管我在云形成脚本中包含了它们。

现在,事不宜迟,让我们进入堆栈。下面的要点包含所有需要的资源。我们来详细解释一下:

  1. 这是 VPC。启用 DNS 支持和 DNS 主机名以访问 ECR 并提取映像非常重要。
  2. INT-GATEWAY:这是一个互联网网关,需要将子网暴露给互联网。
  3. ATTACH-IG:连接互联网网关到 VPC。
  4. ROUTE-TABLE:这是一个路由表,我们将在其中添加规则,以将子网暴露给互联网网关。
  5. ROUTE:这为之前描述的路由表添加了一条规则。它将流量转发到互联网网关。
  6. SUBNETFARGATE:这是托管我们服务的子网。我们定义了可用性区域及其所属的 VPC。
  7. SUBNETROUTE:将路由表关联到子网。
  8. SGFARGATE:这是应用于我们服务的安全组。它允许端口 443 和 80 上的流量通过 HTTPS 和 HTTP 协议。
  9. FARGATECLUSTER:它定义了 Fargate 集群来托管我们的服务。
  10. ECSTASK:决定要执行的任务。它包括构成任务的 Docker 图像列表。对于每个容器,它注册端口映射、启动命令和日志选项。图像是从之前设置的 ECR 存储库中提取的。
  11. SERVICE:定义将启动和维护我们的任务的 ECS 服务。如果您已经有了网络配置,并且不需要创建新的子网和安全组,只需参考 ECS 服务的NetworkConfiguration部分中的现有资源。

一旦您的文件准备就绪,将其上传到 Cloud Formation 以创建您的堆栈:

按照管理控制台中的步骤启动堆栈。一旦完成,云形成将自动开始提供服务。您可以在“事件”选项卡中跟踪其进度:

更重要的是,准备就绪后,您可以在分配给正在运行的任务的公共 IP 地址访问您的 web 应用程序!

关于用户策略的说明

如果您遵循最佳实践,您就不会使用 AWS root 帐户创建资源。相反,您应该使用非根用户。但是,您应该注意,要将角色传递给服务,AWS 要求创建服务的用户拥有“传递角色”权限。在我们的例子中,我们需要我们的用户将角色ecsTaskExecutionRole传递给TaskDefinition服务,因此我们必须授予用户这样做的权限。这可以通过 IAM 中的 root 帐户或任何具有 IAM 权限的帐户来完成。只需添加下面的策略,并将其附加到将分配所有资源的用户。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "arn:aws:iam::account_id:role/ecsTaskExecutionRole"
        }
    ]
}

结论

我们在这篇文章中已经讨论了很多。我们已经看到了如何创建 ECR 存储库以及如何将 Docker 映像推送到其中。我们还简要介绍了云形成和 IaC。我想重申将您的基础设施和堆栈指定为代码的重要性。随着您的基础设施的增长,在 JSON 或 YAML 文件中定义堆栈将使自动化部署更容易,以高效的方式扩展,并将提供关于您的基础设施的某些文档。最后,我们使用 AWS Fargate 以一种无服务器的方式部署 docker 容器,这让我们免去了供应和管理服务器的负担。

希望这篇文章对您有所帮助,感谢您的阅读。

参考

  1. 使用 AWS CLI 开始使用亚马逊 ECR

在 2021 年部署你的机器学习应用

原文:https://towardsdatascience.com/deploying-your-machine-learning-apps-in-2021-a3471c049507?source=collection_archive---------35-----------------------

实践教程

Streamlit 分享来了,很牛逼。

这是今天早上的我。(布鲁克·卡吉尔在 Unsplash 上拍照)

现在还是 2020 年。我醒来时发现收件箱里有些东西让我大吃一惊。如果这个承诺是真的,它将彻底改变我今后构建和部署机器学习应用的方式。

给你一点背景,我最*在做一个非常基础的项目,基于诊断方法预测糖尿病的发病。当我构建任何东西时,最终目标是让最终用户可以访问它。永远。在有了一些设计、开发和部署多个 ML 应用程序的经验之后,我或多或少地知道了这个过程。一旦模型开发完成,我首先构建一个包装模型的应用,然后将应用文档化,最后将它部署到任何云服务提供商。

但我不知道的是,Streamlit 的优秀团队另有打算。今天早上我的收件箱里收到了一封邮件。相信我,这改变了模型部署的一切。现在还是 2020 年,但我可以预见 2021 年将会发生什么。

这封邮件是对新推出的简化应用程序部署的 Streamlit 共享*台的邀请。虽然仍处于测试阶段,但我忍不住对 2021 年的到来感到兴奋。(作者截图)

简化共享和承诺

如果你还没有听说过 Streamlit ,它是一个 python 库,可以让构建 ML 应用变得快速而简单。当我说构建任何机器学习应用程序只需要几个小时时,我并没有夸大其词。 Streamlit 分享是一个新推出的分享 Streamlit 应用的*台。现在已经存在类似的*台,如 Heroku 和 Netlify,以便于部署,但当使用 Streamlit 构建时,这个新*台可能是您的最佳选择。Streamlit 称其为“机器学习代码的简单、可共享的播放按钮。”让我们来了解一下?

对我们这些数据科学家来说,这个承诺非常简单。将您的代码推送到 GitHub,将 Streamlit 指向您的存储库并免费部署您的应用程序。那么有什么问题呢?目前,共享仅支持公共和开源应用。如果你需要为私有/内部用例部署应用,你需要等待 Streamlit 团队,目前处于测试开发阶段。

现在我们已经了解了这个工具,我非常兴奋能够接触到这个*台。

如何部署机器学习应用程序

正如我之前提到的,我们将在这里使用的例子是使用 Streamlit 构建的糖尿病预测应用程序。请参考这个 GitHub 库获取应用的完整代码。确保添加 requirements.txt 文件。需求文件只不过是应用程序使用的 python 包及其版本的列表。在你的终端上一个简单的pip freeze命令会给你精确的细节。在幕后,该文件有助于简化 it 安装部署所需的所有依赖项。

现在我们的存储库已经准备好了,我登录了 Streamlit 共享*台。出现提示时,我授权 Streamlit 访问我的 Github 帐户。我填写了详细信息,然后单击了 Deploy。

简单的部署过程。(作者截图)

等等……就这样?我的应用被部署给全世界看。这个过程变得如此简单,让我惊叹不已。

整个部署过程大约需要 5 分钟。每当我更新应用程序并将代码推送到我的 GitHub 库时,部署的应用程序也会更新。这太疯狂了。

已部署应用的截屏(按作者)

然而,由于该*台仍处于测试阶段,因此存在一些资源限制,例如每个用户帐户 3 个应用程序,以及一些已知的限制官方文档很好地概括了更多信息,社区总是很有帮助。

我坚信,到 2021 年,由于 Streamlit,这将成为常态。您可以使用 Streamlit 快速原型化您的 ML 应用程序,并使用 Streamlit 共享在几个小时内部署它们。老实说,我迫不及待地想看到更多的特性被添加到 Streamlit!

现在轮到你了

我明白了。既然你已经阅读了这篇文章,你会喜欢开发和部署你自己的机器学习应用程序。这里有一个你也可以做到的回顾。

  1. 构建您常用的 ML 模型,并快速将它们打包到一个 Streamlit 应用程序中。
  2. 将您的代码推送到 GitHub。确保包含 requirements.txt 文件。
  3. 请求邀请共享 Streamlit。(在我写这篇文章的时候还在测试阶段——应该很快就会推出)
  4. 登录您的 Streamlit 共享账户并授权其访问 GitHub。
  5. 选择要部署的存储库、分支和代码。点击部署!
  6. (可选)在此分享你的应用链接。我也很想看到并分享它。
This article is a part of my series on **Machine Learning in Production**:
- [How I Build Machine Learning Apps in Hours](https://medium.com/towards-artificial-intelligence/how-i-build-machine-learning-apps-in-hours-a1b1eaa642ed)
- [How to Dockerize Any Machine Learning Application](/how-to-dockerize-any-machine-learning-application-f78db654c601)
- [Deploying Your Machine Learning Apps in 2021](/deploying-your-machine-learning-apps-in-2021-a3471c049507)

我希望你喜欢阅读,就像我喜欢为你写这篇文章一样。我在这里的 媒体 中广泛地写了我在数据科学方面的经历。欢迎在LinkedIn上与我联系,我很乐意听到各种反馈。

从顶点到最低点的机器学习模型的部署和生产— I

原文:https://towardsdatascience.com/deployment-and-productionization-of-machine-learning-models-from-acme-to-nadir-i-cdb5de1b098d?source=collection_archive---------55-----------------------

了解从数据采集到模型部署的全过程。

数据科学——商业事务

构建机器学习模型的典型过程涉及数据收集:用于从数据库(ETL)或任何其他来源获取数据的过程,然后分析数据,从数据中设计和选择特征,以在数据上构建模型,最后分析模型结果。但是一旦你建立了模型,你会怎么做呢?在哪里以及如何利用它来获取利益?

碎成碎片

有收集数据的方法,或者我应该说有许多数据来源。有时需要经过一个漫长的过程(ETL、数据库)才能获得与业务问题相关的所需数据,有时客户会以 excel、CSV 或任何其他文件格式向您提供数据,但后者的可能性很小。大多数情况下,您需要连接到数据库,或者遵循一个完整的 DBM 过程,将数据发送到仓库,然后进行分析并构建模型。我会在另一篇文章中详细讲述这个过程。

一旦你清理好数据并准备好。我们从分析数据开始,通常从发现基本的见解和一些健全性检查(数据类型、汇总统计等)开始。在数据科学中,这个术语叫做探索性数据分析(EDA)。这可以在获取数据时完成,即在作为数据源的系统中完成,也可以通过 Python、R 等工具完成。我更喜欢 Python。

从这里开始,我们走向流程的业务端。从特征工程开始,涉及缺失值插补、离群点检测、变量变换等。特征选择是从数据集中的所有给定特征(特征=变量)中选择最相关的特征,也是该过程的关键部分。这两个过程给了我们所谓的“特征化”数据。特征工程和特征选择是一个很大且费时的话题,因此,集中讨论过程是很重要的。

点睛之笔

我们漫步到模型建立和评估阶段,已经获得了“特征化”的数据,这仅涉及建立不同的机器学习模型并选择给出最佳结果的模型。(培训和测试阶段)。一旦我们得到了模型,之后你会做什么?

你已经有了团队认可的最终模型,现在你需要生产这个模型。生产化是什么意思?这意味着将模型部署到生产系统中,部署到实时场景中。在研究阶段已经完成了所有必要的测试。我们需要部署这个模型来应用我们的研究。

给定数据,我们离线训练我们的模型。该模型部署在实时场景中,它从现实世界中获取连续输入,并根据模型类型(回归、分类等)给出连续输出。

在这一点上,我认为我们讨论机器学习管道和机器学习模型之间的区别是很重要的,因为我们不仅部署模型,而且部署整个管道。

机器学习管道包含了从数据中获得预测所需的所有步骤(我上面提到的步骤)。然而,机器学习模型只是这个管道的一部分(模型构建部分)。虽然模型描述了使用数据中的模式来生成预测的特定算法或方法,但管道概述了机器学习过程中涉及的所有步骤,从收集数据到获取预测。

你如何把你的模型放到一个生产环境中,所有必要的细节将在后续的文章中讨论。

机器学习模型的部署和生产—从顶点到最低点— II

原文:https://towardsdatascience.com/deployment-and-productionization-of-machine-learning-models-from-acme-to-nadir-ii-fd2ad0ab7223?source=collection_archive---------51-----------------------

建造机器学习家园的砖块和混凝土:系统和架构

机器学习系统是一个包括整个基础设施(包括从 RAM 到正常*台构建设备的所有硬件的基础设施)的实体,然后它包括一个操作系统,该操作系统为我们的机器学习任务提供动力,并通过提供一个强大的背景使它变得更简单。它还包括所有的应用程序、软件和工具。它渗透到所有的配置方面,如兼容性,以及数据和一点一点地记录工作流程等部分。

机器基础设施包含了机器学习工作流程的几乎每个阶段。为了训练、测试和部署机器学习模型,您需要来自数据科学家、数据工程师、软件编程工程师和 DevOps 工程师的服务。该基础设施允许来自所有这些领域的人员进行协作,并使他们能够为项目的端到端执行进行关联。

工具和*台的一些例子是 AWS(亚马逊网络服务,谷歌云,微软 Azure 机器学习工作室,kube flow:Kubernetes 的机器学习工具包。

架构处理这些组件的安排(上面讨论过的事情),并且还处理它们必须如何与它们交互。可以把它想象成建造一个机器学习之家,砖块、混凝土、铁是基础设施、应用程序等不可或缺的组成部分。建筑通过使用这些材料来塑造我们的家。类似地,这里的架构提供了这些组件之间的交互。

版本化和再现性:“IT”IT 术语

我们先来了解一下什么是版本化和可复制性。

版本控制:

这是常见的软件和 It 实践,您创建和管理一个产品的多个版本,所有这些版本具有相同的一般功能,但是经过改进、升级或定制。

在机器学习中,为给定的数据建立不同的模型,我们通过版本控制工具如 DVCGit 来跟踪。版本控制将跟踪在每个阶段对模型所做的变更,并保留一个存储库。

再现性:

在研究阶段,我们建立机器学习模型的阶段。一旦模型被测试,然后才被部署。部署后,该模型被假定用于构建该模型的相同数据,并预期给出相同的结果。我们部署整个模型管道,而不仅仅是算法。可再现性确保了复制模型的能力,使得给定相同的原始数据作为输入,两个模型返回相同的输出(相同的数据意味着相同的特征等)。

让我来解释一下是什么影响了再现性,这样可以帮助你更好地理解。假设你之前建立的模型给出了 20%的误差。假设您的数据库已经更改,并且当您尝试再次构建模型时,您不知道数据库正在向模型中注入额外的定型数据,因此导致了额外的错误。

有很多因素会影响再现性。因此,这种版本化和版本控制有助于我们跟踪它。大多数情况下,它是在模型改进过程中出现的。

从再现性到配置问题到数据问题,还有各种其他系统挑战。在体系结构中,有一些关键点,如可再现性、可伸缩性:模型为许多人服务的能力,以及其他必须牢记在心的点。

因此,撰写本文主要是为了让您深入了解部署中使用的基本术语。我希望你喜欢这篇文章。

部署可能很容易——使用 Amazon ec2 部署图像检测 FastAPI API 的数据科学家指南

原文:https://towardsdatascience.com/deployment-could-be-easy-a-data-scientists-guide-to-deploy-an-image-detection-fastapi-api-using-329cdd80400?source=collection_archive---------11-----------------------

科迪·布莱克在 Unsplash 上的照片

使用亚马逊 EC2+Pytorch+Fastapi 和 Docker

就在最*,我写了一篇关于 FastAPI 的简单的教程,内容是关于简化和理解 API 如何工作,以及使用框架创建一个简单的 API。

那个帖子得到了相当好的回应,但是被问得最多的问题是 如何在 ec2 上部署 FastAPI API,以及如何使用图像数据而不是简单的字符串、整数和浮点数作为 API 的输入。

我在网上搜索了一下,但是我能找到的只是一些不太熟悉的文档和人们使用 NGINX 或 ECS 进行部署的许多不同方式。对我来说,这些都不是特别伟大或完整的。

所以,我试着在 FastAPI 文档的帮助下自己做这件事。在本帖中,我们将主要关注四件事:

  • 设置 Amazon 实例
  • 创建用于对象检测的 FastAPI API
  • 使用 Docker 部署 FastAPI
  • 带有用户界面的端到端应用

那么,事不宜迟,我们开始吧。

你可以跳过任何你认为你精通的部分,尽管我希望你浏览整篇文章,尽管它可能很长,因为概念之间有很多相互联系。

1.设置 Amazon 实例

在开始使用 Amazon ec2 实例之前,我们需要设置一个实例。你可能需要用你的电子邮件 ID 注册,并在 AWS 网站上设置支付信息。就像单点登录一样工作。从这里开始,我将假设您有一个 AWS 帐户,因此我将解释接下来的重要部分,以便您可以继续操作。

  • 使用https://us-west-2.console.aws.amazon.com/console进入 AWS 管理控制台。
  • 在 AWS 管理控制台上,您可以选择“启动虚拟机”在这里,我们试图设置一台机器,在那里我们将部署我们的 FastAPI API。
  • 第一步,您需要为机器选择 AMI 模板。我选的是 Ubuntu 以来的 18.04 Ubuntu 服务器。

  • 在第二步中,我选择了t2.xlarge机器,它有 4 个 CPU 和 16GB RAM,而不是空闲层,因为我想使用对象检测模型,并且需要一些资源。

  • 继续按下一步,直到你到达“6。配置安全组”选项卡。这是最关键的一步。您需要添加一个类型为“HTTP”且端口范围为 80 的规则。

  • 您可以单击“查看并启动”,最后单击“启动”按钮来启动实例。单击启动后,您可能需要创建一个新的密钥对。这里我创建了一个名为fastapi的新密钥对,并使用“Download Key Pair”按钮下载它。请妥善保管此密钥,因为每次您需要登录到此特定机器时都会用到它。下载密钥对后,单击“启动实例”

  • 现在,您可以转到您的实例,查看您的实例是否已经启动。提示:查看实例状态;它应该显示“运行”

  • 另外,这里要注意的是公共 DNS(IPv4)地址和 IPv4 公共 IP。我们将需要它来连接到这台机器。对我来说,它们是:
Public DNS (IPv4): ec2-18-237-28-174.us-west-2.compute.amazonaws.comIPv4 Public IP: 18.237.28.174
  • 一旦你在文件夹中运行了下面的命令,你就保存了fastapi.pem文件。如果文件被命名为fastapi.txt,你可能需要将其重命名为fastapi.pem.
# run fist command if fastapi.txt gets downloaded.
# mv fastapi.txt fastapi.pemchmod 400 fastapi.pem
ssh -i "fastapi.pem" ubuntu@<Your Public DNS(IPv4) Address>

现在我们已经启动并运行了 Amazon 实例。我们可以在这里继续讨论帖子的真实部分。

2.创建用于对象检测的 FastAPI API

在我们部署 API 之前,我们需要有一个 API,对吗?在我最*的一篇文章中,我写了一个简单的教程来理解 FastAPI 和 API 基础。如果你想了解 FastAPI 的基础知识,请阅读这篇文章。

因此,这里我将尝试创建一个图像检测 API。至于如何把图像数据传递给 API?想法是——除了字符串,什么是图像? 一个图像只是由字节组成,我们可以把这些字节编码成一个字符串。我们将使用 base64 字符串表示法,这是一种将二进制数据转换为 ASCII 字符的流行方法。并且,我们将传递这个字符串表示来给我们的 API 一个图像。

A.一些图像基础知识:什么是图像,但一个字符串?

所以,让我们先看看如何将图像转换成字符串。我们使用‘rb’ 标志从图像文件中读取二进制数据,并使用base64.b64encode函数将其转换为 base64 编码的数据表示。然后,我们使用decodeutf-8函数将基本编码数据转换成人类可读的字符。如果现在还没什么意义,也不用担心。 只要明白任何数据都是二进制的,我们可以使用一系列步骤将二进制数据转换为其字符串表示。

举个简单的例子,如果我有一个像下面这样的简单图像,我们可以用下面的方法把它转换成一个字符串:

狗 _ 带 _ 球. jpg

import base64with open("sample_images/dog_with_ball.jpg", "rb") as image_file:
    base64str = base64.b64encode(image_file.read()).decode("utf-8")

我们可以得到任何图像的字符串表示

在我的笔记本电脑上,这里有一个名为dog_with_ball.png的文件的字符串表示。

很好,我们现在有了图像的字符串表示。并且,我们可以将这个字符串表示发送给我们的 FastAPI。但是我们还需要有一种方法从图像的字符串表示中读回图像。毕竟,我们使用 PyTorch 和任何其他包的图像检测 API 需要有一个可以预测的图像对象,这些方法不能在字符串上工作。

这里有一种从图像的 base64 字符串创建 PIL 图像的方法。大多数情况下,我们只是以同样的顺序做相反的步骤。我们使用.encode.‘utf-8’中编码,然后使用base64.b64decode解码成字节。我们使用这些字节通过io.BytesIO创建一个 bytes 对象,并使用Image.open将这个 bytes IO 对象作为 PIL 图像打开,这可以很容易地用作我的 PyTorch 预测代码的输入。 再简单一点,它只是将 ***base64*** 图像串转换为实际图像的一种方式。

import base64
import io
from PIL import Imagedef base64str_to_PILImage(base64str):
   base64_img_bytes = base64str.encode('utf-8')
   base64bytes = base64.b64decode(base64_img_bytes)
   bytesObj = io.BytesIO(base64bytes)
   img = Image.open(bytesObj) 
   return img

那么这个功能起作用吗?我们自己看吧。我们可以只使用字符串来获取图像。

我们的快乐狗狗又回来了。比绳子好看。

B.编写实际的 FastAPI 代码

因此,现在我们知道我们的 API 可以从我们的用户那里获得一个字符串形式的图像,让我们创建一个对象检测 API,它使用这个字符串形式的图像,并输出带有对象类的对象的边界框。

在这里,我将使用来自torchvision.models的 Pytorch 预训练fasterrcnn_resnet50_fpn检测模型进行对象检测,该模型是在 COCO 数据集上训练的,以保持代码简单,但可以使用任何模型。如果你想用 Pytorch 训练你的自定义图像分类或者图像检测模型,可以看看这些帖子。

下面是 FastAPI 的完整代码。虽然它看起来很长,但我们已经知道了所有的部分。在这段代码中,我们主要执行以下步骤:

  • 使用 FastAPI()构造函数创建我们的 fast API 应用程序。
  • 加载我们的模型和它被训练的类。我从 PyTorch 文档中获得了课程列表。
  • 我们还定义了一个新的类Input,它使用一个名为pydantic的库来验证我们将从 API 最终用户那里获得的输入数据类型。在这里,终端用户给出base64str和一些用于目标检测预测的分数threshold
  • 我们添加了一个名为base64str_to_PILImage的函数,正如它的名字一样。
  • 我们编写了一个名为get_predictionbase64的预测函数,它使用图像的 base64 字符串表示和一个阈值作为输入,返回边界框和类的字典。我们还在这个函数的顶部添加了[@app](http://twitter.com/app).put(“/predict”)来定义我们的端点。如果你需要理解 put 和 endpoint,请参考我之前在 FastAPI 上发表的文章。

C.先本地后全局:在本地测试 FastAPI 代码

在我们转向 AWS 之前,让我们检查一下代码是否在我们的本地机器上工作。我们可以使用以下命令在笔记本电脑上启动 API:

uvicorn fastapiapp:app --reload

以上意味着您的 API 现在正在您的本地服务器上运行,--reload标志表示当您更改fastapiapp.py文件时,API 会自动更新。这在开发和测试时非常有用,但是当您将 API 投入生产时,您应该删除这个--reload标志。

您应该会看到类似这样的内容:

现在,您可以尝试使用请求模块来访问这个 API 并查看它是否工作:

import requests,jsonpayload = json.dumps({
  "base64str": base64str,
  "threshold": 0.5
})response = requests.put("[http://127.0.0.1:8000/predict](http://127.0.0.1:8000/predict)",data = payload)
data_dict = response.json()

所以我们使用 API 得到我们的结果。这个图像包含一只狗和一个运动球。我们也有边界框的角 1 ( x1,y1)和角 2 ( x2,y2)坐标。

D.让我们想象一下

虽然并非绝对必要,但我们可以在 Jupyter 笔记本中想象结果:

以下是输出:

这里你会注意到,我从本地文件系统中获取了图像,这可以被认为是欺骗,因为我们不想保存用户通过 web UI 发送给我们的每个文件。我们应该能够使用相同的base64string对象,我们也必须创建这个图像。对吗?

别担心,我们也能做到。还记得我们的base64str_to_PILImage 功能吗?我们也可以用这个。

img = base64str_to_PILImage(base64str)
drawboundingbox(img, data_dict['boxes'], data_dict['classes'])

看起来很棒。我们有工作的 FastAPI,也有 amazon 实例。我们现在可以开始部署了。

3.在 Amazon ec2 上部署

到目前为止,我们已经创建了一个 AWS 实例,还创建了一个 FastAPI,它将图像的 base64 字符串表示作为输入,并返回边界框和相关的类。但是所有的 FastAPI 代码仍然驻留在我们的本地机器上。 我们怎么把它放到 ec2 服务器上?并在云上运行预测。

A.安装 Docker

我们将使用 docker 部署我们的应用程序,正如fastAPI创建者自己所建议的那样。我会试着解释 docker 是如何工作的。下面的部分可能看起来令人生畏,但它只是一系列的命令和步骤。所以和我在一起。

我们可以从安装 docker 开始,使用:

sudo apt-get update
sudo apt install docker.io

然后,我们使用以下命令启动 docker 服务:

sudo service docker start

B.为 docker 创建文件夹结构

└── dockerfastapi
    ├── Dockerfile
    ├── app
    │   └── main.py
    └── requirements.txt

这里dockerfastapi是我们项目的主文件夹。这是这个文件夹中的不同文件:

一、 **requirements.txt** : Docker 需要一个文件,这个文件告诉它我们的 app 运行需要哪些所有的库。这里我列出了我在 Fastapi API 中使用的所有库。

numpy
opencv-python
matplotlib
torchvision
torch
fastapi
pydantic

二。 **Dockerfile** : 第二个文件是 Dockerfile。

FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7COPY ./app /app
COPY requirements.txt .
RUN pip --no-cache-dir install -r requirements.txt

Docker 是如何工作的?: 你可以跳过这一节,但这将有助于了解 docker 是如何工作的。

可以把dockerfile想成类似于sh file,的东西,它包含创建可以在容器中运行的 docker 映像的命令。人们可以把 docker 映像想象成一个安装了 Python 和 Python 库等所有东西的环境。容器是一个单元,它只是我们系统中一个使用 docker image的孤立盒子。使用 docker 的好处是,我们可以创建多个 docker 映像,并在多个容器中使用它们。例如,一个图像可能包含 python36,而另一个图像可能包含 python37。我们可以在一台 Linux 服务器上生成多个容器。

我们的Dockerfile包含了几样东西:

  • FROM命令:这里第一行FROM指定我们从tiangolo’s (FastAPI creator) Docker 镜像开始。根据他的网站:“这个图像有一个“自动调整”机制,这样你就可以添加你的代码,自动获得同样的高性能。【不作牺牲】。我们所做的只是从一个镜像开始,它为我们安装了 python3.7 和,并自动为uvicorngunicorn ASGI 服务器添加了一些配置和一个用于 ASGI 服务器的start.sh文件。对于喜欢冒险的人来说,特别是[commandset](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker/blob/master/docker-images/python3.7.dockerfile)1[commandset2](https://github.com/tiangolo/uvicorn-gunicorn-docker/blob/master/docker-images/python3.7.dockerfile)通过一种命令菊花链的方式被执行。
  • COPY命令:我们可以把 docker 镜像看作一个包含文件等的文件夹。在这里,我们将之前创建的app文件夹和requirements.txt文件复制到 docker 映像中。
  • RUN命令:我们运行 pip install 命令,使用 docker 映像上的requirements.txt 文件安装所有 python 依赖项。

三。main.py: 这个文件包含了我们之前创建的fastapiapp.py代码。记住只保留文件名main.py

C.码头工人建造

我们已经得到了所需结构的所有文件,但是我们还没有使用任何 docker 命令。我们首先需要使用 Dockerfile 构建一个包含所有依赖项的映像。

我们可以简单地通过以下方式做到这一点:

sudo docker build -t myimage .

这将从tiangolo’s映像下载、复制和安装一些文件和库,并创建一个名为myimage.的映像。这个myimage有 python37 和一些由requirements.txt 文件指定的 python 包。

然后我们只需要启动一个运行这个图像的容器。我们可以通过以下方式做到这一点:

sudo docker run -d --name mycontainer -p 80:80 myimage

这将创建一个名为mycontainer的容器,它运行我们的 docker 映像myimage。部分80:80将我们的 docker 容器端口 80 连接到我们的 Linux 机器端口 80。

事实上就是这样。此时,您应该能够在浏览器中打开下面的 URL。

# <IPV4 public IP>/docs
URL: 18.237.28.174/docs

我们可以通过编程来检查我们的应用程序,使用:

payload = json.dumps({
  "base64str": base64str,
  "threshold": 0.5
})response = requests.put("[http://18.237.28.174/predict](http://18.237.28.174/predict)",data = payload)
data_dict = response.json()
print(data_dict)

是的,我们的 API 终于部署好了。

D.故障排除,因为现实世界并不完美

来源:因为这就是真实世界部署的样子。

以上所述都是好的,如果你严格按照说明去做,它们会立即发挥作用,但是现实世界并不是这样的。在这个过程中,您肯定会遇到一些错误,并且需要调试您的代码。因此,为了帮助您,一些 docker 命令可能会派上用场:

  • 日志:当我们使用sudo docker run运行我们的容器时,我们没有得到很多信息,这是调试时的一个大问题。您可以使用下面的命令查看实时日志。如果您在这里看到一个错误,您将需要更改您的代码并重新构建映像。
sudo docker logs -f mycontainer

  • 启动和停止 Docker: 有时候,重启 Docker 可能会有帮助。在这种情况下,您可以使用:
sudo service docker stop
sudo service docker start
  • 列出图像和容器:使用 docker,您将最终创建图像和容器,但是您将无法在工作目录中看到它们。您可以使用以下方式列出图像和容器:
sudo docker container ls
sudo docker image ls

  • 删除未使用的 docker 图像或容器:您可能需要删除一些图像或容器,因为它们会占用系统的大量空间。这是你如何做的。
# the prune command removes the unused containers and images
sudo docker system prune# delete a particular container
sudo docker rm mycontainer# remove myimage
sudo docker image rm myimage# remove all images
sudo docker image prune — all
  • 检查 localhost:Linux 服务器没有浏览器,但是我们仍然可以看到浏览器的输出,虽然有点难看:
curl localhost

  • 开发时不需要一次又一次地重新加载映像:对于开发来说,只需在我们的机器上更改代码内容并进行现场测试,而不必每次都构建映像,这是非常有用的。在这种情况下,在每次代码更改时自动运行带有实时自动重载的服务器也是很有用的。这里,我们使用 Linux 机器上的应用程序目录,在开发过程中,我们用开发选项/start-reload.sh替换缺省值(/start.sh)。一切正常后,我们可以再次构建我们的映像,并在容器中运行它。
sudo docker run -d -p 80:80 -v $(pwd):/app myimage /start-reload.sh

如果这还不够,在这里添加一个包含有用的 docker 命令的 docker 备忘单:

来源

4.带有用户界面的端到端应用

我们已经完成了 API 的创建,但是我们还可以使用 FastAPI 创建一个基于 UI 的应用程序。这不是你在生产环境中要做的事情(在生产环境中,你可能让开发人员使用 react、node.js 或 javascript 来制作应用程序),但这里主要是检查如何使用图像 API 的端到端流程。我将在本地而不是 ec2 服务器上托管这个准系统 Streamlit 应用程序,它将从托管在 ec2 上的 FastAPI API 获取边界框信息和类。

如果你需要了解更多关于 streamlit 是如何工作的,你可以看看这篇帖子。此外,如果您想将这个 streamlit 应用程序也部署到 ec2,这里还有一个教程

下面是 ec2 上带有 UI 和 FastAPI API 的整个 app 的流程:

项目架构

在我们的 streamlit 应用中,我们需要解决的最重要的问题是:

如何使用 Streamlit 从用户处获取图像文件?

答:使用文件上传器:我们可以通过以下方式使用文件上传器:

bytesObj = st.file_uploader(“Choose an image file”)

下一个问题是,我们从 streamlit 文件上传者那里得到的这个 bytesObj 是什么?在 streamlit 中,我们将从file_uploader中获得一个bytesIO对象,我们需要将它转换为 base64str,用于我们的 FastAPI 应用程序输入。这可以通过以下方式实现:

def bytesioObj_to_base64str(bytesObj):
   return base64.b64encode(bytesObj.read()).decode("utf-8")base64str = bytesioObj_to_base64str(bytesObj)

B .使用 URL: 我们也可以使用text_input从用户那里获得一个图片 URL。

url = st.text_input(‘Enter URL’)

然后,我们可以使用请求模块和 base64 编码和utf-8解码从 URL 获取 base64 字符串格式的图像:

def ImgURL_to_base64str(url):
    return base64.b64encode(requests.get(url).content).decode("utf-8")base64str = ImgURL_to_base64str(url)

这是我们的 Streamlit 应用程序的完整代码。你已经看到了这篇文章中的大部分代码。

我们可以使用以下方式在本地运行这个 streamlit 应用程序:

streamlit run streamlitapp.py

我们可以看到在我们的localhost:8501.上运行的应用程序可以很好地处理用户上传的图像以及基于 URL 的图像。这里有一张猫的图片,也给你们中的一些猫爱好者。

我们使用所有组件— Streamlit、FastAPI 和 Docker 的最终结果。

原来如此。我们在这里创建了一个完整的工作流,通过 FastAPI 在 ec2 上部署图像检测模型,并在 Streamlit 中利用这些结果。我希望这能帮助您解决在生产中部署模型的问题。你可以在我的 GitHub 库找到这篇文章的代码以及我所有的文章。

让我知道你是否喜欢这篇文章,以及你是否愿意在你的日常部署需求中包含 Docker 或 FastAPI 或 Streamlit。我也希望在 Docker 上创建一个更详细的帖子,请关注我,关注我的写作。详情如下。

继续学习

如果你想了解更多关于建立机器学习模型并将其投入生产的知识,AWS 上的这个课程可以满足你的要求。

谢谢你的阅读。将来我也会写更多初学者友好的帖子。在 Medium 上关注我或者订阅我的博客来了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @mlwhiz 联系

此外,一个小小的免责声明——这篇文章中可能会有一些相关资源的附属链接,因为分享知识从来都不是一个坏主意。

部署策略

原文:https://towardsdatascience.com/deployment-strategies-a4fe6f743e08?source=collection_archive---------30-----------------------

如何选择正确的策略来满足您的应用需求

每个应用程序的部署都有一个时间点。我们可以将这个活动委托给一个自动化的任务或者手动完成,但是我们需要在幕后有一个部署策略。我读过许多关于部署的指南,其中大部分都很好地解释了如何实现给定的解决方案。与现实世界的缺失环节是将实施与需求相匹配。简而言之,在应用解决方案之前,您必须了解您的需求。这就是为什么我想把重点放在场景和策略上。

foto diFree-PhotosdaPixabay

为什么我们需要权衡

您将在下一段中发现,每种部署策略都满足不同的需求。识别您的用例对于选择正确的工具是至关重要的。每个解决方案都必须与应用程序要求兼容,这也包括列表中的预算变量。

你是对的;它带有权衡威胁的味道。但事实就是如此。你不能用火箭筒射杀一只苍蝇。

询问您的客户是否更喜欢不会使其服务离线的部署策略。我觉得很容易猜到它的答案。

如果可能的话,我们需要在部署过程中保持服务的活力。对于一个用户很少的简单应用程序来说,这看起来有点大材小用,但是用同样的努力实现零停机 DevOps 过程通常是可能的。因此,零停机时间可能是我们应该始终考虑的因素。

在许多情况下,我们需要同时维护两个版本(旧的和新的,有和没有新的特性,等等。).如果您考虑您的自动化部署服务,这个解决方案相对容易实现,可能需要一个基础设施创建阶段。重要的是成本。运行同一个应用程序的两个实例通常是链接运行两个简单的虚拟机。对于一个庞大的系统来说,运行一个应用程序的两个并行版本所需的基础设施翻倍的成本可能会令人望而却步。因此,保持多个系统同时可用可能是一个问题。

我可以继续举其他例子,但问题很简单。我们需要根据应用程序的实际需求来调整我们的解决方案。

过于简化会导致某些东西今天有效,明天就会失效。过于远视会让你睡得很香,但可能会影响你的预算。

部署策略

再创造

旧版本关闭;然后,新的被激活。当您有一个简单的服务器,并且您更新您的网站时,这个过程就会发生。

我和❤️一起做的

优点:

  • 易于实施

缺点:

  • 需要很短的停机时间。
  • 在某些错误的情况下,开关是硬的。

倾斜的

部署新版本并逐步交付给用户。当您发布一个新的应用程序,并且希望调整性能或某些关键特性时,建议使用这个解决方案。如果你打算在大规模发布之前收集用户的反馈并调整你的应用程序,这也是一个不错的选择。

我和❤️一起做的

优点:

  • 进步分子

缺点:

  • 达到完全部署需要很长时间
  • 昂贵(如果您将此解决方案应用于现有应用程序,您将有两个运行环境)

蓝色\绿色

新版本与另一个版本一起部署;然后,流量被切换到新的服务器。只有当新版本上线并经过测试时,切换才会发生,因此操作是即时且安全的。

我和❤️一起做的

优点:

  • 安全的
  • 无停机时间

缺点:

  • 难以实现
  • 暂时需要两个运行环境(昂贵)
  • 许多 web 服务器在内部实现了蓝/绿机制,因此您可以开箱即用。

A/B 测试

两个版本,新的和旧的,一起工作。一些目标用户登陆新网站,这样你就可以得到反馈

我和❤️一起做的

优点:

  • 您可以比较这两个*台并获得反馈

缺点:

  • 昂贵的
  • 很难在完整的应用程序上实现,因为您需要在同一个数据库上运行两个应用程序

阴影

新版本的应用程序通过旧*台接收流量,并向呼叫者提供复古兼容的响应。

我和❤️一起做的

优点:

  • 确保追溯兼容性
  • 对用户透明

缺点:

  • 很难在完整的 web 应用程序上实现
  • 给你的限制,以符合旧的应用程序永远。

选择正确的策略。

嗯,这取决于需求和预算。这第一句话是无可挑剔的,但完全没有用😅。因此,我将尝试为每种情况绘制正确的解决方案,以便您可以选择正确的解决方案。

新的应用土地推向市场

当一个新的应用程序投入生产时,没有什么可破坏的,所以一切都更容易。在上线之前,您可以使用重新创建或绿/蓝方法激活新的应用程序。这个提议唯一的遗憾是,你将有一个完整的开关。在发布日,所有用户将一起进入您的 web 应用程序。在没有任何 bug、分析漏洞或性能问题的理想世界中,这不是问题。在现实世界中,交钥匙总是一个赌注,即使您已经做了最好的分析,您测试了所有的东西两次,并且运行了性能测试。我的建议是尽可能进行倾斜部署。从有限数量的用户开始,让您收集反馈并解决问题,而不会出现紧急情况。

现有应用程序的更新

当一个应用程序运行时,我觉得很难逐步部署一个新版本或者在应用程序级别进行 A/B 测试。最大的问题是,您需要运行两个不同的应用程序,费用加倍,并且两个应用程序必须共享同一个数据库。但是还有一个实际的限制。谁了解用户?谁来决定哪个客户有资格购买 A 或 B 版本?答案很简单:商业逻辑。因此,更容易管理的地方是应用程序内部,也就是业务逻辑所在的地方。要解决不同功能之间的*衡需求,更简单的解决方案是在应用程序级别进行操作。您可以简单地部署一个具有两个用户可以激活的特性的应用程序。在微服务时代,添加或删除部件并应用一些业务逻辑是相对容易的。为什么不呢?

一旦您能够管理 A/B 测试或应用程序内部新特性的激活,您将需要一个不会破坏任何东西的部署。蓝/绿部署就可以了。

您想要替换一个遗留的 web 服务。

当您有成千上万用户使用的遗留 API 时,替换它总是一团糟。问题可能来自使用 IP 地址而不是 DNS 的用户,或者防火墙问题。任何微小的改变都可能引发问题,所以我们要超级保守。影子版本部署是正确的解决方案。嘲笑所有的回应,打电话的人可以继续像往常一样,而你启动了新的系统。然后,您可以要求用户切换并监控旧 API 的使用,但不要着急。最后可以关闭老界面,不用担心会切走一部分用户。最大的问题是维护两个不同系统并使它们保持一致的成本,几乎是在与用户的界面上(如果您在真实服务上做了一些更改,模拟需要保持与初始定义的一致性)。此外,您必须在模拟接口上支持旧的 API 接口的事实可能会在某种程度上限制您的能力。

您希望向现有产品添加新功能。

当您在现有项目上添加一个特性,并且希望在完全注册之前进行正确的测试时,A/B 或渐变部署会很有用。第一个让您比较两个应用程序对用户的影响,但是第二个逐渐引入了一个新特性。这两种方法都是提高用户参与度的有趣且有用的方法,但很难针对每个功能实现。主要问题是保持应用程序的两个并发版本一起运行。这意味着双倍的基础设施成本、双倍的维护成本,需要保持数据库与两个正在运行的应用程序兼容。对于所有这些问题,在大多数情况下,您可以在应用程序级别管理逐步部署。这种方法还有一个优点,就是您可以在用户范围内非常容易地为每个用户定义一个定制策略。

带什么回家

部署应用程序是 DevOps 的一个棘手的方面,必须考虑一些业务需求才能有效。像往常一样,有很多选择。很多都管用,但是你可以挑最适合你的。

被认为有害的深度?

原文:https://towardsdatascience.com/depth-considered-harmful-1a022f3abbac?source=collection_archive---------55-----------------------

我们需要深度图神经网络吗?

迈克尔布朗斯坦 — 9 分钟阅读

深度学习的标志之一是使用数十层甚至数百层的神经网络。与之形成鲜明对比的是,图形深度学习中使用的大多数架构都很浅,只有少数几层。在这篇文章中,我提出了一个异端的问题:图神经网络架构中的深度带来任何优势吗?

刘易斯·恩古吉在 Unsplash 上拍摄的照片

有抱负的数据科学家的 5 个典型思维错误

孙铁麟迈斯特 — 6 分钟读取

在过去的几年里,我和 500 多名有抱负的数据科学家一起工作过,我看到了他们容易犯的一些典型的思维错误。在这篇文章中,我想分享其中的五个。

基于歌词的歌曲推荐,带有 Doc2Vec 嵌入和 Spotify 的 API

由亚当·里维斯曼 — 5 分钟阅读

单词嵌入对于自然语言处理来说是一个非常有用的工具。它们通常作为神经网络的参数被学习,并允许我们将单词映射到数字。更具体地说,它们允许我们将单词映射到高维向量。

照片由 Riho Kroll 在 Unsplash 上拍摄

方差注入式思维

通过饶彤彤 — 8 分钟读取

历史看起来是确定的,而且经常被这样解释。本世纪初的科技泡沫显然是一个泡沫,正如所有泡沫都会发生的那样,它最终破裂了。20 世纪 80 年代的日本房地产,2008 年的美国房地产,20000 美元的比特币,杂草股等等也是如此。在崩盘后的几年里,历史学家关注的是风险有多明显,最终的内爆有多不可避免。

Kubernetes 上的气流之旅

由马塞洛·拉韦略·罗西 — 12 分钟读完

我对 Apache Airflow 的拙见:基本上,如果您有多个自动化任务要调度,并且您正在摆弄 cron 任务,即使它们的一些依赖项失败了,您也应该尝试一下。

深度估计:基础和直觉

原文:https://towardsdatascience.com/depth-estimation-1-basics-and-intuition-86f2c9538cd1?source=collection_archive---------0-----------------------

Unsplash 上由 Shea Rouda 拍摄的照片

深度对于 3D 视觉至关重要

测量相对于相机的距离仍然很困难,但绝对是开启自动驾驶、3D 场景重建和 AR 等激动人心的应用的关键。在机器人技术中,深度是执行感知、导航和规划等多种任务的关键先决条件。

创建 3D 地图将是另一个有趣的应用,计算深度允许我们将从多个视图捕获的图像投影到 3D 中。然后,对所有的点进行配准和匹配,就可以完美地重构场景。

来源:3D 重建场景

需要解决的一些挑战性问题包括对应匹配、由于诸如纹理、遮挡、非朗伯表面等原因而变得困难、解决不明确的解决方案、其中许多 3D 场景实际上可以在图像*面上给出相同的图片,即预测的深度不是唯一的。

从相机获取距离信息因其相对低廉的生产成本和密集的表现形式而极具吸引力。将这项技术带给大众就像拥有一台现成的照相机一样简单。目前,检索深度的最佳替代方法是使用激光雷达等主动测距传感器。它们是天然高保真传感器,提供高度精确的深度信息。

由于各种原因,如遮挡、场景中的动态对象和不完美的立体对应,在深度估计方面进行工作,特别是在自主车辆的应用中,确实具有挑战性。对于立体匹配算法来说,反光、透明、镜面是最大的敌人。例如,汽车的挡风玻璃通常会降低匹配性能,从而降低估计性能。因此,大多数公司仍然依赖激光雷达来可靠地提取距离。然而,自动驾驶汽车感知堆栈的当前趋势是转向传感器融合,因为每个传感器在其提取的特征方面都有其优势。尽管如此,自深度学习出现以来,该领域已经获得了很大的牵引力并取得了显著的成果。许多研究致力于解决这些问题。

在计算机视觉中,深度是从两种流行的方法中提取的。即,来自单目图像(静态或连续)的深度或来自立体图像深度。这篇文章将重点给读者一个深度估计的背景和与之相关的问题。需要对相机射影几何有充分的理解。

通过阅读这篇文章,我希望你能从总体上对深度知觉有一个直观的理解。此外,概述了深度估计研究的趋势和方向。然后我们将讨论一些(许多)相关的问题。

各种深度估计算法将在后续帖子中详细阐述,以免过多的细节淹没您!

我们如何看待这个世界

图二。投射到视网膜上(左)。投影到像*面(右)

让我们从我们人类一般如何感知深度开始。这将给我们一些关于深度估计的有价值的见解,因为这些方法中的许多是从我们的人类视觉系统中得到的。机器视觉和人类视觉在图像形成方式上有相似之处(图 2)。从理论上讲,当来自光源的光线击中表面时,它会反射并射向我们视网膜的背面,投射出去,我们的眼睛将它们作为 2D [1]进行处理,就像图像在图像*面上形成一样。

那么,当投影场景在 2D 时,我们如何在 3D 中测量距离和理解我们的环境呢?例如,假设有人要给你一拳,你本能地知道你什么时候会被击中,当他/她的拳头靠得太*时,你会躲开它!或者当你开车时,你可以通过某种方式判断何时踩油门或踩刹车,以便与其他司机和行人保持安全距离。

这里的工作机制是,我们的大脑开始通过识别模式来推理传入的视觉信号,如大小、纹理和场景的运动,称为深度线索。没有关于图像的距离信息,但是我们可以毫不费力地解释和恢复深度信息。我们感知到场景的哪一面离我们*,哪一面离我们远。此外,这些线索让我们能够将*面图像上的物体和表面视为 3D [1]。

如何破坏深度(不是人类/计算机视觉)

只是为了强调一个有趣的事实,解释这些深度线索始于场景如何在人类和摄像机视觉中被投射到透视图。另一方面,正视图或侧视图的正交投影会破坏所有深度信息。

考虑图 3,观察者可以分辨出房子的哪个方面离他/她更*,如左图所示。然而,完全不可能从正确的图像中区分相对距离。甚至背景也可能和房子在同一*面上。

图 3。透视投影(左)。正投影(右)

利用线索判断深度

基本上有 4 类深度线索:静态单眼、运动深度、双目和生理线索2。我们下意识地利用这些信号来非常好地感知深度。

图像深度线索

我们从单一静止图像中感知深度的能力取决于场景中事物的空间排列。下面,我总结了一些提示,让我们能够推理不同物体的距离。从你与地球母亲的日常互动中,你可能已经感觉很自然了。希望不要花太多心思去计算各种线索。

蜜桃红·坎普斯·菲利佩Unsplash 上拍摄的照片

加州大学伯克利分校进行了一项有趣的研究,他们通过实验表明,当视界可见时,我们有一种压倒性的倾向来利用这一特性快速感知深度。当你看到上面的图片时,你会这样想吗?

来自运动的深度线索(运动视差)

图五。运动视差

你也不应该对此感到惊讶。作为一个观察者,当你在运动时,你周围的物体比远处的物体经过得快。某样东西出现得越远,它离开观察者的速度似乎就越慢。

来自立体视觉的深度线索(双目视差)

视网膜差异:又一个有趣的现象,让我们能够识别深度,这可以从一个简单的实验中直观地理解。

图六。来源

闭上一只眼睛,将食指放在面前,尽可能靠*你的脸。现在,反复关闭一个,打开另一个。注意到你的手指在动!你的左右眼观察到的视野差异被称为视网膜差异。现在伸出一臂长的手指,做同样的动作。你应该注意到手指位置的变化变得不那么明显了。这应该给你一些关于立体视觉如何工作的线索。

这种现象被称为****;由于对世界的两种不同视角而感知深度的能力。通过比较两只眼睛视网膜的图像,大脑计算距离。差距越大,事情离你越*。

计算机视觉中的深度估计

深度估计的目标是获得场景的空间结构的表示,恢复图像中物体的三维形状和外观。这也被称为逆问题[3],在这种情况下,我们试图在信息不足以完全确定解决方案的情况下恢复一些未知数。这意味着 2D 视图和 3D 视图之间的映射不是唯一的(图 12 ),我将在这一部分介绍经典的立体方法和深度学习方法。

那么机器实际上是如何感知深度的呢?我们能否以某种方式转移上面讨论的一些想法?具有令人印象深刻的结果的最早算法始于 90 年代使用立体视觉的深度估计。密集立体对应算法取得了很多进展[4] [5] [6]。研究人员能够利用几何学从数学上限制和复制立体视觉的概念,同时实时运行。本文对所有这些观点进行了总结[7]。

至于单目深度估计,它最*开始通过使用神经网络来学习直接提取深度的表示而受到欢迎[8]。其中通过基于梯度的方法隐含地学习深度线索。除此之外,在自我监督的深度估计方面已经有了很大的进步[9][10][11]。这是特别令人兴奋和开创性的!在这种方法中,模型被训练成通过优化代理信号来预测深度。训练过程中不需要地面真相标签。大多数研究要么利用几何线索,如多视图几何或核几何来学习深度。我们稍后会谈到这一点。

来自立体视觉的深度估计

图 7。极线几何(左)。校正后的图像(右)

使用立体相机解决深度的主要思想涉及到三角测量立体匹配的概念。形式依赖于良好的校准和校正来约束问题,以便它可以在被称为核*面的 2D *面上建模,这极大地将后者简化为沿着核线**(图 7) 的线搜索。关于极线几何的更多技术细节将在以后的帖子中讨论。**

类似于双目视差,一旦我们能够匹配两个视图之间的像素对应,下一个任务是获得编码差异的表示。这种表示被称为视差,d.** 为了从视差中获得深度,可以从相似的三角形中计算出公式(图 8)**

图 8。立体几何

这些步骤如下

  • 从特征描述符中识别相似点。
  • 使用匹配成本函数匹配特征对应。
  • 使用极线几何,找到并匹配一个画框与另一个画框的对应关系。匹配成本函数[6]用于测量像素相异度
  • 根据已知的对应关系d = x1 — x2计算视差,如图 8 所示。
  • 根据已知视差计算深度z = (f*b)/d

图九。来自 Kitti 的差异表示

深度学习时代

深度学习擅长高级感知和认知任务,如识别、检测和场景理解。深度知觉属于这一类,同样应该是一种自然的前进方式。目前有 3 个广泛的框架来学习深度:

****监督学习:直接从单目图像估计深度的开创性工作始于 sa xena【8】。他们通过监督学习,通过最小化回归损失,学会了直接从 2D 图像中的单眼线索回归深度。从那以后,许多不同的方法被提出来,通过提出新的体系结构或损失函数来改善表征学习

****使用 SFM 框架的自监督深度估计:该方法将问题框架化为学习从视频序列生成新视图。神经网络的任务是通过在不同的时间步长I_t-1, I_t+1拍摄图像并应用从姿态网络学习的变换来执行图像扭曲,从源视图生成目标视图I_t。通过使用空间变换网络[14]以可区分的方式将扭曲视图合成视为监督,训练成为可能。在推断时间,深度 CNN 将从单视图 RGB 图像预测深度(图 10)。我建议您阅读这篇文章以了解更多信息。请注意,这种方法确实有一些缺点,如无法确定比例和模拟下一节中描述的移动对象。

图 10。无监督单目深度估计

****使用立体图的自我监督单目深度估计:又一个有趣的方法。这里(图 11),代替将图像序列作为输入,该模型将仅从左侧 RGB 预测视差d_l, d_rI_l。与上述方法类似,空间转换器网络使用视差扭曲 RGB 图像对I_l, I_r。回想一下x2 = x1 — d。因此可以合成成对视图,并且使用重建视图I_pred_l, I_pred_r和目标视图I_l, I_r之间的重建损失来监督训练。

为了使这种方法有效,假设基线必须是水*的和已知的。必须对图像对进行校正,以便通过视差进行准确的变换。从而计算结果d = x1 — x2如图 8 所示。

图 11。使用立体的自我监督单目深度估计

CNN 深度线索和偏差学习

理解和破译黑盒一直是可解释机器学习中正在进行的研究。在深度估计的背景下,一些工作已经开始研究神经网络依赖于什么样的深度线索或者从特定数据集学习的归纳偏差。

汤姆等人的开创性工作中,ICCV 2019 ,他们进行了几个简单的测试,通过实验找到了估计深度和场景结构之间的关系。请注意,这是在 Kitti 数据集上完成的,Kitti 数据集是一个室外道路场景,具有固定的相机位置,并且具有某种程度上可见的消失点和地*线。

来源

****物体相对于地面接触点的位置提供了强大的上下文信息:对于道路上的物体,通过增加汽车在垂直方向上的位置。我们看到,当模型离地面较远时,它不能很好地估计深度。

****

:物体下面的阴影作为深度估计的强特征

****形状不重要,但阴影重要:在另一个实验中,通过放置一个带有人工投射阴影的任意对象,即使在训练期间无法获得深度,模型也可以合理地估计深度。

Rene 等人完成了有趣的工作,他们在由室内和室外场景组成的相对较大规模的数据集上训练了一个深度模型。从观察来看,有一个自然的偏差,图像的下半部分总是靠*相机。这可以被视为下图右上角示例中的一种故障模式。此外,深度模型倾向于预测内容,而不是在左下角的情况下识别为镜子中的反射。在论文中还可以发现许多其他有趣的发现。

来源

进行的研究仍然相当有限。要提供更多的结论性发现,还需要做大量的工作。

为什么测量深度这么难?

最后,让我们试着理解深度估计的一些基本问题。主要原因在于 3D 视图到 2D 图像的投影丢失了深度信息。当有运动和移动物体时,另一个问题就根深蒂固了。我们将在本节中详细介绍它们。

深度估计是不适定的

通常在进行单目深度估计的研究时,许多作者会提到从单幅 RGB 图像估计深度的问题是不适定的逆问题。这意味着世界上观察到的许多 3D 场景确实可以对应于同一个 2D *面(图 11 和 12)。

图 12。来源

不适定:单目深度估计的尺度模糊

回想一下,调整焦距将按比例缩放图像*面上的点。现在,假设我们以某个因子k缩放整个场景 X,同时以因子1/k缩放相机矩阵 P,图像中场景点的投影保持完全相同

x = PX = (1/k)P * (kX) = x

也就是说,我们永远无法仅从图像中恢复实际场景的精确比例!

请注意,单目基础技术存在此问题,因为可以通过已知基线恢复立体装备的比例。

不适定:投影模糊

假设我们对场景进行几何变换,有可能变换后,这些点会映射到*面上的同一个位置。又一次给我们留下了同样的困难。见下图

图十三。变换后物体的投影映射到*面上的同一点

降低匹配的属性

对于需要三角测量的基于立体或多视角的深度估计,通常涉及 检测-描述-匹配 的流水线。当场景是从非常不同的视点拍摄的或者图像之间的光照变化很大时,匹配变得非常困难。下图给出了一个极端情况,其中描述符无法区分特征。这些有问题的案例包括:

一个非常困难的场景,有很大的视角差异和不同的人群。

移动物体违反了 SFM 方法的静态假设

场景中的动态对象进一步使估计过程复杂化。从运动中通过结构进行深度估计涉及移动的摄像机和连续的静态场景。这个假设必须适用于匹配和对齐像素。当场景中有移动的对象时,这个假设就不成立了。为此,许多研究人员研究了几种方法来模拟场景中的移动对象,包括使用光流[12]合并速度信息,或使用实例分割遮罩来模拟对象从一帧到另一帧的运动[13]。

下一步是什么

我希望你已经从这篇介绍性的文章中获得了一些关于深度估计的有价值的见解,为什么它是一个具有挑战性但又极其重要的任务,以及该技术的当前状态是什么。我坚信深度可以用相机和视觉来解决。我对此很乐观。因为我们自己仅仅依靠单眼或双眼视觉来与我们的环境互动。

感谢您阅读这篇文章。希望它给你一些好的见解!点击查看更多关于计算机视觉和机器学习的帖子。欢迎留下任何反馈:)

** [## 深度估计的不确定性

你对你预测的深度有把握吗?

towardsdatascience.com](/uncertainty-in-depth-estimation-c3f04f44f9) [## 自我监督的深度估计:打破观念

在这篇文章中,我想通过自我监督学习来分解各种各样的深度估计的想法。对于…

towardsdatascience.com](/self-supervised-depth-estimation-breaking-down-the-ideas-f212e4f05ffa) [## 逆投影变换

深度和反向投影

towardsdatascience.com](/inverse-projection-transformation-c866ccedef1c)

参考

[1] 视觉科学导论,戴维·l·安德森

2双目和 3d 显示器的视觉舒适性,Frank L. Kooi,Alexander Toet,在 SPIE 国际光学工程学会会议录25(2):99–108,2004 年 8 月

[3]计算机视觉:算法和应用,Richard Szeliski

[4]m .奥托米和 t .卡纳德(1993 年)。多基线立体声。 IEEE 模式分析与机器智能汇刊,15(4):353–363。

[5]博伊科夫、维克斯列尔和扎比赫(1998 年)。早期视觉的可变窗口方法。 IEEE 模式分析与机器智能汇刊,20(12):1283–1294。

[6]伯奇菲尔德和托马西(1999 年)。像素到像素立体的深度不连续性。《国际计算机视觉杂志》,35(3):269–293。

[7]Scharstein d .和 Szeliski r .(2002 年)。稠密两帧立体对应算法的分类和评价。国际计算机视觉杂志,47(1):7–42。

[8] D. Eigen、C. Puhrsch 和 R. Fergus。使用多尺度深度网络从单幅图像预测深度图。NIPS,2014。

[9] R .加尔格、g .卡内罗和 I .里德。用于单视图深度估计的无监督 cnn:几何学拯救。ECCV,2016。

[10] T .周、m .布朗、n .斯奈夫利和 d .洛来自视频的深度和自我运动的无监督学习。CVPR,2017。

[11]戈达尔、奥达和布罗斯托。具有左右一致性的无监督单目深度估计。CVPR,2017。

[12] Z. Yang,P. Wang,Y. Wang,W. Xu 和 R. Nevatia .每一个像素都很重要:具有整体 3d 运动理解的无监督几何学习。arxiv.org/pdf/1806.10556, 2018。

[13] R. Mahjourian、M. Wicke 和 A. Angelova。使用 3d 几何约束从单目视频无监督学习深度和自我运动。IEEE 计算机视觉和模式识别会议论文集,第 5667-5675 页,2018 年。

[14]贾德尔伯格先生、西蒙扬先生、齐塞尔曼先生和卡武克库奥卢先生。空间变压器网络。在日本,2015 年。**

费希尔信息的推导

原文:https://towardsdatascience.com/derivations-of-the-fisher-information-bc81c82f12f6?source=collection_archive---------32-----------------------

一些理论,一些例子,和一些见解

背景和动机

Fisher 信息是数理统计中的一个重要量,在极大似然估计(MLE)的渐*理论和 cramér–Rao 下界的规范中起着重要作用。

让我们看看费希尔信息的定义:

上面的描述似乎很公*。费雪信息是分数的方差。简单,容易,太棒了!

教科书经常陈述(有时没有证明)在正则条件下,以下三个量都等于费雪信息:

当我在大学第一次遇到这个材料时,我不清楚这三个量是如何相等的?在 Medium 上快速搜索发现了关于这个话题的大量报道。我觉得下面的证明值得了解。这些证明中使用的一些技术在概率论和数理统计的其他地方也是有用的。所以让我们开始吧。

1)费希尔信息=得分函数的二阶矩

2)费希尔信息=得分函数的梯度的负期望值

示例:伯努利随机变量的费希尔信息,以及与方差的关系

利用我们在上面学到的知识,我们来做一个快速练习。

最后的想法

希望以上有见地。正如我在以前的一些文章中提到的,我认为没有足够的人花时间去做这些类型的练习。对我来说,这种基于理论的洞察力让我在实践中更容易使用方法。我个人的目标是鼓励该领域的其他人采取类似的方法。我打算在未来写一些基础作品,所以请随时在【LinkedIn】上与我联系,并在 Medium 上关注我的更新!

从第一原理导出卷积

原文:https://towardsdatascience.com/deriving-convolution-from-first-principles-4ff124888028?source=collection_archive---------5-----------------------

深度学习的基础

你有没有想过卷积有什么特别之处?在这篇文章中,我从第一原理推导出卷积,并表明它自然地出现在*移对称中。

某些原则的内涵为某些事实的内涵提供了便利。(克劳德·阿德里安·赫尔维蒂乌斯)

D 在我的本科学习期间,我在以色列理工学院学习电子工程,我总是对卷积这样一个重要的概念突然出现感到震惊。这个看似武断的定义像眼里的一粒沙子一样扰乱了信号处理世界原本美好的画面。让卷积从第一原理中产生,而不是让它成为假设,那该多好啊!正如我将在本文中展示的,这些首要原则是*移不变性或对称性的概念。

让我从基础信号处理课程中教授的公式开始,该公式定义了两个 n 维向量 xw 的离散卷积:

这里,为了方便起见,我假设所有的索引都从零运行到n1,并且取模n;把向量想象成定义在圆上是很方便的。将上面的公式写成矩阵-向量乘法会产生一个非常特殊的矩阵,称为循环矩阵:

循环矩阵具有多对角线结构,每条对角线上的元素具有相同的值。它可以通过将向量 w [3】的移位(模 n )版本堆叠在一起而形成;为此,我使用符号 C ( w )来指代由向量 w 形成的循环矩阵。由于任何卷积xw都可以被等价地表示为循环矩阵C(w)x*的乘法,所以我将这两个术语互换使用。*

O 线性代数中我们最先学到的一点就是矩阵乘法是不可交换的,也就是一般情况下,ABBA。然而,循环矩阵是非常特殊的例外:

循环矩阵交换,

或者换句话说,C(w)C(u)=C(u)C(w)。对于任何循环矩阵,或者任何选择的 uw 都是如此。等价地,我们可以说卷积是一个交换运算,xw=wx

特别选择 w =[0,1,0…,0]会产生一个特殊的循环矩阵,将向量向右移动一个位置。这个矩阵被称为(右)移位算子【4】,用 S 表示。右移位运算符的转置是左移位运算符。显然,先左移再右移(反之亦然)没有任何作用,这意味着 S 是一个正交矩阵:

循环矩阵可以用它们的交换性来刻画。仅证明移位的交换性似乎就足够了(文献[5]中的引理 3.1):

矩阵是循环的当且仅当它随移位交换。

这个“当且仅当”语句的第一个方向导致了一个非常重要的性质,称为*移移位等方差【6】:卷积与移位的可交换性意味着,不管我们是先移位一个向量然后卷积它,还是先卷积然后移位,结果都是一样的。

第二个方向允许我们卷积定义为移位等变线性运算:为了移位交换,矩阵必须具有循环结构。这正是我们从一开始就渴望的,从*移对称的第一原理中产生卷积[7]。我们可以从移位等方差的要求出发,得出卷积的公式,作为满足它的唯一可能的线性运算,而不是像信号处理书籍中通常做的那样,给出卷积的公式并证明它的移位等方差性质。

作为移位和模糊操作可互换性的移位等变图解。

信号处理课程中教授的另一个重要事实是卷积和傅立叶变换之间的联系。在这里,傅里叶变换也是出人意料地出现,然后显示出它将卷积运算对角化,允许在频域中执行两个矢量的卷积,作为它们的傅里叶变换的逐元素乘积。从来没有人解释过这些正弦和余弦来自哪里,它们有什么特别之处。

为了追根究底,回想一下线性代数中的一个事实:

交换矩阵可联合对角化。

换句话说,两个满足 AB = BA 的矩阵将具有相同的特征向量(但可能是不同的特征值)[9]。由于所有循环矩阵都交换,我们可以选择其中的一个并计算其特征向量——上述定理确保这些也将是所有循环矩阵的特征向量。

方便选择换班操作符 S 。由于 S 是正交矩阵,我们期望它的特征向量是正交的[10]。一个简单的计算(见[5]中的第 4.1 节)得出如下结论

傅里叶变换将移位算子对角化。

我希望此时你已经有了今天的第二个“啊哈”时刻:这就是正弦和余弦的来源!它们是移位算子的特征向量;我将它们表示为矩阵φ的列。注意特征向量是复数,所以我们在转置φ时需要取复数共轭。乘以φ(从左起)称为傅立叶变换,乘以φ称为傅立叶逆变换。*

因为所有循环矩阵都是可联合对角化的,所以它们也可以通过傅立叶变换来对角化[11]。它们只是在特征值上有所不同。最后缺失的一点是意识到

C( w )的特征值是 w 的傅里叶变换。

我们现在可以把这个难题的所有部分放入一个被称为卷积定理的陈述中:卷积xw可以作为循环矩阵 C ( w )应用于原始坐标系中的 x (有时这被称为“空间域”卷积),或者通过首先计算的傅里叶变换,在傅里叶基(“谱域”)中计算

因为φ具有特殊的冗余结构,所以利用[快速傅立叶变换](https://en.wikipedia.org/wiki/Fast_Fourier_transform#:~:text=A fast Fourier transform (FFT,frequency domain and vice versa.) (FFT)算法,可以用𝒪( n log n 复杂度来计算乘积**φ xφx**。*

为什么卷积的这种定义很重要,并且应该这样教?我在这里重复一下我在这篇文章开始时引用的赫尔维·提乌斯的话:“对某些原则的了解很容易弥补对某些事实的了解的不足”。在卷积的情况下,它从第一原理的推导允许容易地推广到其他领域。在下一篇文章中,我将展示如何在图上定义卷积,以产生图形深度学习架构的关键构建块。

[1] A. Dominquez-Torres,卷积的历史和起源对卷积运算的概念和符号的历史发展进行了有趣的探究。卷积积分第一次出现在 J. B. D'Alembert 的《世界体系的不同要点的研究》( 1754)中泰勒定理的推导中。这一优先权常常被错误地认为是 P.-S. de Laplace 的著作,载于《关于土地和功能的数字》(1773 年)。巴黎皇家科学院院士,学者与外国人 7:503–540,尽管该出版物不包含任何卷积的痕迹。拉普拉斯在他后来写于 1778 年并于 1781 年出版的概率回忆录中确实使用了卷积。早期的命名尝试包括 résultante (法语“合成”的意思,查尔斯·卡勒于 1899 年首次使用) composizione (意大利语“合成”的意思,维托·沃尔泰拉于 1910 年使用),以及 faltung (在德语中字面意思是“折叠”,古斯塔夫·多伊奇于 1923 年使用);后者主宰了 20 世纪初的德国文学。英文名 convolution 来源于拉丁语 con (“在一起”)和 volvere (“卷起”),是德语 faltung、的直译,俄语变体 свёртка 也是如此。这个英语术语的首次使用可以追溯到 1934 年 Aurel Friedrich Wintner 的论文;它后来被多奇(1937)和加德纳和巴恩斯(1942)的权威著作巩固在文学作品中。1910 年,沃尔泰拉首次使用了星形符号,尽管形式有所不同。珀西·约翰·丹尼尔使用了点符号。卷积的第一个现代符号为fg,这是两者的组合,这是由于 Doetsch (1923)。

【2】从技术上来说,我这里定义的是循环卷积

[3]注意, C ( w )的行具有被转置的矢量 w ,导致出现在卷积公式中的反射,并将其与相关性的相关概念区分开来。注意边界条件(右上角和左下角的 C 的元素)。

[4]我交替使用术语运算符矩阵

[5] B. Bamieh,发现变换:关于循环矩阵、循环卷积和离散傅立叶变换的教程 (2018)。arXiv:1805.05533 提供了我在这篇文章中讨论的推导的细节。

[6]有些经常混淆不变性(拉丁文中“不变”的意思)和等变(“同变”),很多信号处理书籍都把我这里讨论的性质称为“移位不变性”。一个功能是换挡同变iff(Sx)=Sf(x)换句话说,我们是否先换档,然后再 f 都没有关系,反之亦然。不同的是,*移不变性是不受*移影响的性质:函数f(Sx)=f(x)是*移不变性。*移不变性是物理学中的一个基本概念(在这里它经常以“*移对称”的名义出现),表明物理定律不依赖于空间中的位置。在经典力学的变分公式中,通过 Noether 定理从位移不变性中得出动量守恒这样的基本定律。

[7]等方差的概念是更一般的,可以用群论形式来扩展。T. Cohen 和 M. Welling, Group equivariant 卷积网络 (2016)中使用了这个框架。继续。ICML,将细胞神经网络卷积层的移位等方差扩展到更一般的操作,如旋转。假设 f : X→Y,其中 x 和 y 是一些不同的空间,对应的运算群𝒢和𝒢'分别定义在 x 和 y 的元素上,群等方差表示为f(𝔤(x))=𝔤'(f(x))其中𝔤∈𝒢和𝔤'∈𝒢'.请注意,𝔤'不一定等于𝔤,因为输出空间 y 的结构和偶数维可以不同于输入空间 x 的结构和偶数维。本文中讨论的标准卷积是一种特殊情况,X=Y 是 n 维向量的空间,𝒢=𝒢'是*移组,𝔤=𝔤'是移位运算符。

[8]由于我们处理的是有限维向量,所以术语“傅立叶变换”在这里指的是离散傅立叶变换 (DFT)。

[9]更准确地说,联合对角化意味着两个交换矩阵具有相同的特征空间,因为在一般情况下,特征值可以具有非*凡的多重性。因为在我这里讨论的例子中,所有的特征值都是简单的,我们可以讨论一个公共的特征基。

[10]但是,由于 S 是非对称的,所以它不具有实特征值(对称实矩阵具有实特征值)。 S 的特征值恰好是单位根的复根

[11]当我说矩阵 C 被傅立叶变换“对角化”时,我的意思是矩阵**φ是对角的。由于傅立叶变换是一个正交矩阵(φφ=I**),从几何角度来说,它相当于坐标系统的一个变化,相当于一个 n 维旋转。在这个坐标系中, C 的动作变成了元素的乘积。

[12]在信号处理中,通常在频域中设计滤波器,因此从不明确计算 w 的傅里叶变换。

关于图形深度学习的其他文章,请参见我的博客*【迈向数据科学】* 订阅 到我的帖子,获取 中级会员 ,或者关注我的 推特 **

从头开始推导反向传播方程(第一部分)

原文:https://towardsdatascience.com/deriving-the-backpropagation-equations-from-scratch-part-1-343b300c585a?source=collection_archive---------3-----------------------

深入了解神经网络的训练方式

在这一系列简短的两篇文章中,我们将从头开始推导全连接(密集)层的三个著名反向传播方程:

以下所有解释都假设我们只向网络提供一个训练样本。如何将公式扩展到小批量将在这篇文章的最后解释。

正向传播

我们首先简要回顾一下单层的正向传播(以矩阵形式):

图层𝑙的输入是矢量(通常称为特征矢量):

方括号中的值(上标中)表示网络层。我们用变量 n 来表示一层中的节点数。定义图层𝑙行为的系数(权重和偏差)为:

中介价值:

被称为 的加权输入 是通过:

加权输入以元素方式馈入激活函数(也称为非线性):

要获得输出:

常见的激活功能有 ReLU、leaky ReLU、tanh、sigmoid、Swish 等。如上标所示,理论上每层可以具有不同的激活函数。

获得直觉

在不知道反向传播是什么的情况下推导反向传播方程是没什么用的。为此,我们首先将上一节定义的单个层链接成一个𝐿层网络。

(图片由作者提供)

训练神经网络的目标是提高其在给定任务上的性能,例如分类、回归。通过损失函数𝓛来评估性能,该损失函数在训练期间被添加为链的最后一个块。对于每个样本,损失函数将网络的输出与地面真实值𝒚进行比较,并输出单个实值(!idspnonenote)信号。)号。通常,较小的数字表示性能良好,而较大的数字表示性能不佳。

接下来,我们输入一个具体的样本到我们的网络中,例如

并通过各层连续向前传播。我们在图层𝑙停下来,看看计算出的加权输入,比如说:

然后,我们继续传播以获得损失函数值,例如𝓛 = 0.3247。

现在,我们回到𝑙层,并增加其第一个节点的值:

微小的价值:

同时保持所有其他节点不变。从𝑙层开始,我们向前传播改变后的加权输入:

通过网络并获得损失函数𝓛 = 0.3242 的微小变化值。

由于网络的分级性质,微小的推动δ导致了后面层𝑙 + 1、𝑙 + 2 等的所有激活。稍微更改它们的值,如下图所示:

绿色箭头表示增加,红色箭头表示减少(图片来自作者)

在我们设计的例子中,当我们增加𝑙.层中第一个节点的值时,损失函数的值减少了
δ𝓛=-0.0005 一般来说,对于一些节点,损失函数将减小,而对于其他节点,损失函数将增大。这完全取决于网络的权重和偏差。

上述两个三角形之比就是所谓的“斜率三角形”:

这个斜率三角形当然可以对所有节点和所有层进行计算。它是下列偏导数的*似值:

在文献中,这种偏导数通常被称为误差,我们将随后使用这个术语。误差正是从最后一层𝐿开始,通过网络反向传播的量。

通过使用第一反向传播方程,我们可以将层𝑙的误差向后传播一步到其前一层𝑙 -1:

重复应用该等式允许我们获得所有层的误差

让我们简短地总结一下反向传播的机理:

训练神经网络的过程包括通过调整网络的权重和偏差来最小化损失函数。使用梯度下降或其变体来完成自适应。事实证明,偏置的梯度与误差完全匹配:

权重的梯度也可以通过外积直接从误差中获得:

扩展到多个样本

要计算小批量样品的重量和偏差梯度,我们只需独立执行上述步骤(!)对于小批量的所有样品,随后*均梯度:

其中,𝑚表示小批量样品的数量,圆括号中的数值表示样品编号。

请注意,在计算效率极高的反向传播“矢量化版本”中,针对单个样本独立计算误差。然而,计算是并行进行的。

链式法则

学校里教的基本链式法则允许我们计算嵌套函数的导数:

𝑔(.在哪里)和𝑓(.称之为“外层功能”)的“内在功能”。导数是:

也可以写成这样:

为了推导反向传播方程,我们需要对基本的链式法则稍加扩展。首先,我们扩展𝑔和𝑓函数,以接受多个变量。我们选择外部函数𝑔取三个实变量并输出一个实数:

因为𝑔现在接受三个变量,我们也需要三个不同的内部函数𝑓s,用于每个变量。假设每个𝑓s 接受两个实数变量并输出一个实数:

接下来,我们将内部函数插入外部函数,得到:

请注意,得到的函数只是两个(!idspnonenote)的函数。)实变量。现在,我们想获得下面的偏导数:

与上述基本链规则一样,我们首先获取外部函数𝑔相对于其第一个变量的偏导数,并将其乘以第一个内部函数的偏导数:

请注意,我们首先取外部函数𝑔的偏导数,就好像内部函数不存在一样。只是随后我们将内部函数插入到变量中,用垂直线表示。

然而,我们还没有完成,因为外部函数不仅仅依赖于一个变量。幸运的是,扩展链规则具有非常清晰的结构,因此我们接下来对第二个和第三个变量执行完全相同的步骤。随后,将所有步骤加在一起:

更一般地说,对于任意外函数和𝑛任意内函数:

链式法则是:

为了清楚起见,我们去掉了在具体值

同样的程序适用于其他变量的导数。

在本系列的第二部分中,我们将使用扩展链规则来推导反向传播方程。

降序:Python 中线性回归的一种尝试

原文:https://towardsdatascience.com/descending-a-shakedown-of-linear-regression-with-in-python-a9aec054c860?source=collection_archive---------86-----------------------

线性回归快速指南以及如何使用梯度下降在 Python 中实现它。

克里斯·利维拉尼在 Unsplash 上的照片

这个项目的所有示例代码都可以在 这里 找到

在几乎每个人一生中的某个时刻,都有那么一刻,他们希望自己能预知未来。无论是通过使用臭名昭著的水晶球,还是通过在德洛里安跳跃到未来,未来仍然是一个不可能知道或预测的概念。

除非你从事数据科学。

使用原始数据并利用计算机科学和统计学创建模型的众多好处之一是,数据科学家可以根据现有数据和可观察到的趋势预测结果。

线性回归是一种技术,试图“通过将一个线性方程 T10 与观测数据 T11 拟合来模拟两个变量之间的关系”——耶鲁大学

这个线性方程给了我们一组数据点的最佳拟合线。使用这条线,既可以用肉眼看到,也可以作为其他预测模型的起点,我们能够以一定的准确度预测未来/增加的数据点。

随机散点图— Aleia Knight

取 1.0-10.0 之间的这组随机点,并将其绘制在散点图上。

有了这一组点,几乎立刻就能看出一个趋势。

正线性。

但是准确地知道直线的值,它的斜率和它的截距并不是仅仅通过查看原始图就可以得到的值。

最适合的系列——Aleia Knight

应用线性回归,我们可以看到最佳拟合的实际线。从这里,我们可以向前延伸线,并能够大致看到超过 10.0 和小于 1.0 的数据点可以预测到哪里。

足够简单,但数据很少会如此干净、简洁或直接。

如果我们使用像 Spotify 歌曲属性数据集这样的数据,并从中绘制一些数据,会怎么样..

Spotify 数据:能量与可跳舞性——Aleia Knight

有许多模型和方法可以找出最适合无法直观解释的数据的线。

我们将使用线性回归的两种主要方法来寻找最佳拟合线。

  1. 均方误差
  2. 梯度下降

设置

总是从加载必要的导入并创建数据和变量开始

import pandas as pd     #For data handling
import matplotlib.pyplot as plt    #For data visualization
import numpy as np       #For calculationsdata = pd.read_csv('data.csv')  #Spotify data
x = data['danceability']
y = data['energy']

展望未来,统计和微积分中有许多复杂的数学公式和技术。访问 偏导数简介 *和*线性回归 n 快速复习概念和公式。

使用渐变下降

这种技术可以被认为是一种优化的方法,通过寻找与理想值的最小误差来找到最佳拟合线。

giphy.com

这个过程的第一步是找到我们的最佳斜率和截距。也就是后来所知的“权重”,只要我们的 x 和 y 数据保持不变,这些值在这些计算中将保持不变。

为了计算斜率和截距,我们需要以下公式来计算权重的均方误差, w1w0。

**

公式— Aleia Knight

左侧图像显示了数学符号到相关变量的转换。右侧是用于计算【w1(斜率)* 和 w0(截距) 的公式。这个过程如果手工完成,需要深入的微积分知识,特别是解多变量方程,求偏导数。*

查找资源:

求解多变量方程

寻找偏导数

一旦我们找到 w1 和 w0 的值,我们就可以使用这些公式来求解 w1w0 的实际值。

这是一个漫长的过程,但是有了 numpy 库,我们能够简化这个过程。

这将打印出语句(对于特定的示例)。

*Slope is / Weight 1 : 0.05034768176424329
Intercept / Weight 2 is: 0.6504410345649969 

(0.05034768176424329, 0.6504410345649969)*

坚持这两个价值观!

理解y_pred=w1*x+w0的一个更简单的方法是把它想成更熟悉的形式y=mx+by_pred是基于我们之前找到的 w1w0 的预测线。

绘制这条线,我们看到:

Spotify 数据:能量与可跳舞性——梯度下降——Aleia Knight

直觉上,这似乎有点奇怪,但当我们看聚类(另一种分析风格)时,这确实是有意义的,并且我们的数据似乎确实有较低的正趋势。

我们可以用均方差来分析这条线的有效性。

均方误差

这个概念很简单,因为我们看到的是实际点和预测点之间的差异。

*actual = 1
predicted = 3
error = 2*

这是在所有数据点上完成的(求和),除以点的数量(*均值),并找到*方(*方)以消除任何负数。值 0 是不可能的,但是越接*零越好。这反映在代码中。

MSE via my calculations is: 0.04412711932424555

非常接*零,这太棒了!这告诉我们,误差值非常低,所以我们的线是相当准确的。

giphy.com

这种算法和许多其他算法一样,可以用于计算机科学、数据科学和技术涉及的任何领域。

正是通过使用这些能力,我们能够更快、更有效地处理数据,并利用它来帮助我们走向未来。

下降法——最速下降法和共轭梯度法

原文:https://towardsdatascience.com/descent-method-steepest-descent-and-conjugate-gradient-math-explained-78601d8df3ce?source=collection_archive---------16-----------------------

数学解释

[## 下降法 Python 中的最速下降和共轭梯度

让我们从这个方程开始,我们想解出 x:

medium.com](https://medium.com/@msdata/descent-method-steepest-descent-and-conjugate-gradient-in-python-85aa4c4aac7b)

让我们从这个方程开始,我们想解出 x:

当 A 是对称正定时,解 x 最小化下面的函数(否则,x 可能是最大值)。这是因为 f(x)的梯度,∇f(x) = Ax- b .而当 Ax=b 时,∇f(x)=0 因而 x 是函数的最小值。

在这篇文章中,我将向你展示两种求 x 的方法——最速下降法和共轭梯度法。

最速下降法

下降法的主要思想是,我们从 x 的起点开始,试图找到下一个更接*解的点,迭代这个过程,直到找到最终解。

例如,在步骤 k,我们在点𝑥(𝑘).我们如何决定下一步去哪里?我们应该往哪个方向走?我们应该去多少?

让我们假设我们决定去的方向是 p(k ),我们沿着这个方向走多远是𝛼.那么下一个数据点可以写成:

对于每一步,最速下降法都希望朝着最陡的斜坡下降,在那里最有效(这里 r 表示残差):

一旦我们决定了前进的方向,我们要确保在这个方向上最小化函数:

现在我们可以计算下一个数据点的 x 和残差:

这基本上是最速下降法背后的数学原理。通常我们会给残差一个停止准则,然后我们迭代这个过程,直到到达停止点。

对于 Python 实现,请查看:

[## 下降法 Python 中的最速下降和共轭梯度

让我们从这个方程开始,我们想解出 x:

medium.com](https://medium.com/@msdata/descent-method-steepest-descent-and-conjugate-gradient-in-python-85aa4c4aac7b)

共轭梯度法

最速下降法是伟大的,我们在每一步的方向上最小化函数。但这并不能保证,我们要最小化的方向,来自于所有之前的方向。这里我们引入一个非常重要的术语共轭方向。方向 p 是共轭方向,如果它们具有下列性质(注 A 是对称正定的):

只有当前方向 p 与所有先前方向共轭时,下一个数据点才会在所有先前方向的跨度内最小化函数。

问题是,当 p 必须是共轭时,我们如何计算搜索方向 p?

记住最陡下降选择了最陡斜率,也就是每步的残差(r)。我们知道这是一个好的选择。不如我们找一个最接*最陡下降方向的 A 共轭方向,也就是说,我们最小化向量(r-p)的 2 范数。

通过计算,我们知道当前方向是当前残差和上一个方向的组合。

因为α-共轭方向的性质:

然后我们可以计算𝛾_𝑘:

总之,共轭梯度法如下:

同样,对于 Python 实现,请查看:

[## 下降法 Python 中的最速下降和共轭梯度

让我们从这个方程开始,我们想解出 x:

medium.com](https://medium.com/@msdata/descent-method-steepest-descent-and-conjugate-gradient-in-python-85aa4c4aac7b)

现在你知道如何用最速下降法和共轭梯度法解线性方程组了!尽情享受吧!

参考:

[## ALAFF 技术细节

这一单元可能是这门课程中技术难度最大的单元。为了完整起见,我们在这里给出了细节,但是…

www.cs.utexas.edu](https://www.cs.utexas.edu/users/flame/laff/alaff/chapter08-important-observations.html)

描述和推断统计

原文:https://towardsdatascience.com/descriptive-and-inferential-statistics-862b70ddc7a7?source=collection_archive---------35-----------------------

来源: Unsplash

如果你是数据科学领域的新手,你会知道缺乏统计知识有时会非常令人沮丧并阻碍进步。至少了解统计学的基础知识变得非常重要。在这篇文章中,我们将回到基础。我们将探讨两种主要的统计类型——描述性统计和推断性统计。你可能从名字就能看出这两种类型代表什么。但是我们还是会明白他们的意思。我们先从描述性统计开始。

描述统计学

描述性统计用于将大量数据描述为摘要。想象一下,你正在研制一种护发产品,据说可以减少男性秃顶。所以你想知道男性秃顶的首要原因是什么。但是你不能到处去问现在地球上每一个秃顶的人是什么导致了他们的秃顶,这是不切实际的。所以你在你的当地社区,或者扩展社区,选择一群秃顶的男人。为此你总共有 500 个人。你对这些人做了一项调查,大致了解了秃顶的各种原因。然后举一反三,可以说,适用于整个地球的秃子人口。你调查的一小部分人被称为样本。无论您收集了什么数据,都将进行汇总,汇总结果可能如下所示:

如你所见,即使你收集了 500 个答案,你也只总结了四行。这是描述性统计。这个统计数字代表了全部人口。但这并没有停止。你可以得到更多的信息。你可以计算你收集的数据的*均值、中间值、最大值和最小值。或者甚至可以绘制峰度图来更好地理解传播。可以看看偏斜度。你可以利用现有的数据做很多事情,这些数据可以描述你正在处理的问题。

这是描述性统计。我希望这是足够的描述。🙂

推断统计学

顾名思义,推断统计学是用来从我们所拥有的数据中推断或推出信息或结论的。我们将继续前面的男性秃顶的例子。在前面的章节中,我们从我们得出的描述性统计数据中看到,根据这些人的说法,秃顶的主要原因是遗传的。那是没有药可治的。所以我们会看到下一个主要原因,那就是水质。我们可以推断,如果我们改善人们淋浴用水的质量,我们可能会减少男性秃顶。我们可以带一些药物来减少水中的污染物,或者向水中添加矿物质来改善水质,这可能有助于减少脱发。

我希望你明白我的意思。任何时候你使用数据或统计来得出一个关于假设的结论,或者根据描述性统计的早期阶段来做预测,你都是在做推断统计。

原载于 2020 年 1 月 30 日 我的个人博客

手工描述性统计

原文:https://towardsdatascience.com/descriptive-statistics-by-hand-a055d299c34?source=collection_archive---------31-----------------------

照片由 Pop &斑马拍摄

介绍

T 他的文章解释了如何手工计算主要的描述性统计数据以及如何解释它们。要了解如何在 R 中计算这些度量,请阅读文章“R中的描述性统计”。

描述统计学(广义上)是统计学的一个分支,旨在总结、描述和呈现一系列数值或数据集。由于难以识别数据中的任何模式,没有任何准备或没有任何汇总措施的长系列值通常不能提供信息。下面是一个 100 个成年人的身高(单位为厘米)的例子:

188.7169.4178.6181.3179173.9171.9157.2173.3187.1194170.7 177.1171.4182.6167.7161.3179.3 ,, 171.3176.9180.8189167.7188【、 【t160.1】、【t1163.6】、、【165】、、【167】、【t168.1】【t1169.1】、【t170.1】【、【t176.0】**

面对这一系列,任何人都很难(甚至不可能)理解这些数据,并在合理的时间内对这些成年人的规模有一个清晰的看法。描述性统计允许进行总结,从而对数据有更好的了解。当然,通过一项或几项措施汇总数据,难免会丢失一些信息。然而,在许多情况下,丢失一些信息通常更好,但反过来获得一个概述。

描述性统计通常是任何统计分析的第一步,也是重要的一部分。它允许通过检测潜在的异常值(即看起来与其余数据分离的数据点)、收集或编码错误来检查数据质量。它也有助于“理解”数据,如果描述性统计数据表现良好,它已经是进一步分析的良好起点。

位置与离差度量

几种不同的方法(如果我们正在分析一个样本,称为统计)被用来总结数据。其中一些给出了关于数据位置的理解,另一些给出了关于数据分散的理解。在实践中,为了以最简洁但完整的方式总结数据,这两种类型的衡量标准经常一起使用。我们用下面的图来说明这一点,图中代表了分成两组(每组 50 人)的 100 个人的身高(以厘米为单位):

黑线对应的是*均值。两组的*均身高(厘米)相似。然而,很明显,这两个组的高度离散度非常不同。因此,如果单独呈现位置或分散测量,通常是不够的,呈现两种类型测量的多个统计数据是一种好的做法。

在接下来的章节中,我们将详细介绍最常见的位置和离差测量,并举例说明。

位置

位置测量允许查看数据的“位置”和周围的值。换句话说,位置测量给出了对什么是中心趋势,即数据作为一个整体的“位置”的理解。它包括以下统计数据(其他数据也存在,但我们只关注最常见的数据):

  • 最低限度
  • 最高的
  • 意思是
  • 中位数
  • 第一四分位数
  • 第三个四分位数
  • 方式

在接下来的章节中,我们将详细介绍并手动计算它们。

最小值和最大值

最小值(min)和最大值(max)分别是最小值和最大值。给定 6 个成人样本的身高(以厘米为单位):

188.7169.4178.6181.3179173.9

最小 169.4 cm,最大 188.7 cm。这两个基本统计数据清楚地显示了这 6 个成年人的最小和最高的尺寸。

*均

均值,也称为*均值,可能是最常见的统计数据。它给出了*均值的概念,即数据的中心值,或者说重心。通过将所有值相加并将该和除以观察次数(表示为 nn)来得到*均值:

下面是*均值的直观表示:

卑鄙。资料来源:加州大学卢万分校 LFSAB1105

给定上述 6 名成人样本,*均值为:

总之,*均尺寸,即 6 名成人样本的*均尺寸为 178.48 厘米(四舍五入到小数点后两位)。

中位数

中位数是位置的另一种度量,因此它也给出了关于数据集中趋势的想法。对中位数的解释是,中位数以下的观察值与中位数以上的一样多。换句话说,50%的观察值低于中位数,50%的观察值高于中位数。中间值的直观表示如下:

中位数。资料来源:加州大学卢万分校 LFSAB1105

计算中值的最简单方法是首先将数据从最低到最高排序(即按升序),然后取中间点作为中值。从排序后的值中,对于奇数个观察值,中间点很容易找到:它是下面的观察值与上面的一样多的值。仍然从排序的值来看,对于偶数个观察值,中点正好在两个中间值之间。形式上,排序后,中位数是:

其中 x 的下标表示排序数据的编号。公式看起来比实际要难,所以让我们看两个具体的例子。

奇数个观察值

给定从引言中呈现的 100 个成人中选取的 7 个成人的样本的身高:

188.9163.9166.4163.7160.4175.8181.5

我们首先从低到高排序:

160.4163.7163.9166.4175.8181.5188.9

假设观察数 nn 为奇数(因为 n=7),中值为

所以我们从排序后的值中取第四个值,对应于 166.4。总之,这 7 个成年人的*均尺寸是 166.4 厘米。可以看到,166.4 以下有 3 个观测值,166.4 cm 以上有 3 个观测值。

偶数个观察值

现在让我们来看看观察次数为偶数时的情况,这比观察次数为奇数时的情况稍微复杂一些。给定 6 个成人样本的身高:

188.7169.4178.6181.3179173.9

我们按升序对值进行排序:

169.4173.9178.6179181.3188.7

假设观察数量 nn 为偶数(因为 n=6),则中位数为

因此,我们将排序后的值中的第三个和第四个值相加,并将这个和除以 2(这相当于取这两个中间值的*均值):

总之,这 6 个成年人的*均尺寸是 178.8 厘米。再次注意,下面的观察值与上面的 178.8 厘米一样多。

*均值与中值

虽然*均值和中间值经常彼此相对接*,但是它们不应该混淆,因为它们在不同的环境中都有优点和缺点。除了几乎每个人都知道(或至少听说过)*均值这一事实之外,它还有一个优点,即它为每个不同的数据系列提供了一个独特的图像。然而,它的缺点是均值对异常值(即极值)敏感。另一方面,中位数的优势在于它可以抵抗异常值,而不方便的是,对于非常不同的数据系列,它可能是完全相同的值(因此对于数据来说不是唯一的)。

为了说明“对局外人来说是明智的”这个论点,考虑一下酒吧里的三个朋友比较他们的工资。他们的工资分别为 180020002100 €,*均工资为 1967 €。他们的一个朋友(碰巧也是比尔·盖茨的朋友)加入了他们的酒吧。他们现在的工资分别是 1800200021001000000 €。这四个朋友的*均工资现在是 251475€,相比之下,1967 年没有这位富有朋友的€的*均工资是 30。虽然说这四个朋友的*均工资是 251475 €在统计学上是正确的,但是你会承认这个标准并不能代表这四个朋友的真实工资,因为他们中的三个挣得比*均工资少得多。正如我们刚刚看到的,*均值对异常值是敏感的。另一方面,如果我们报告中位数,我们看到 3 个第一朋友的中位数工资是 2000 €,4 个朋友的中位数工资是 2050 €。正如您在本例中看到的,中位数对异常值不敏感,对于具有这种极值的系列,中位数比*均值更合适,因为它通常能更好地表示数据。(注:这个例子也说明了绝大多数人的收入是如何低于新闻报道的*均工资的。然而,这超出了本文的范围。)

给定前面的例子,然后可以选择总是使用中间值而不是*均值。然而,中位数有它自己的不便之处,而这是*均数所没有的:与*均数相比,中位数不那么独特,也不那么具体。考虑以下数据,代表参加统计和经济学考试的 5 名学生的成绩:

经济学和统计学的成绩中位数是一样的(中位数= 10 )。因此,如果我们只计算中位数,我们可以得出结论,学生在经济学和统计学方面表现一样好。然而,尽管两个班级的中位数完全相同,但很明显,学生在经济学方面的表现要比统计学好。事实上,经济学的*均成绩是 13.6 ,统计学的*均成绩是 8.6 。我们刚刚在这里展示的是,中位数仅基于一个单一值,即中间值,或者如果有偶数个观察值,则基于两个中间值,而*均值基于所有值(因此包含更多信息)。因此,中值对于异常值是不敏感的,但是对于不同的数据系列,它也不是唯一的(即,不特定的),而对于不同的数据系列,*均值更可能是不同的和唯一的。这两种测量之间在特异性和唯一性方面的差异可能使*均值对没有异常值的数据更有用。

总之,根据上下文和数据,报告*均值或中值,或者两者都报告通常更有意思。关于两个最重要的位置测量值之间的比较,最后一点需要注意的是,当*均值和中值相等时,数据的分布通常可被视为遵循正态分布(也称为高斯分布)。

第一和第三四分位数

第一个和第三个四分位数在某种意义上类似于中位数,它们也将观察值分为两部分,只是这两部分不相等。提醒一下,中位数是把数据分成相等的两部分(50%的观测值在中位数以下,50%在中位数以上)。第一个四分位数对观测值进行分割,使得在第一个四分位数的下方有 25%的观测值,而在上方有 75%的观测值。第三个四分位数,正如你现在已经猜到的,代表 75%的观察值在它下面,因此 25%的观察值在它上面。有几种方法可以计算第一个和第三个四分位数(有时会有细微的差别,例如 R 使用了不同的方法),但我认为手动计算这些统计数据时最简单的方法是:

  1. 按升序对数据进行排序
  2. 计算 0.25⋅n 和 0.75⋅n(即观察次数的 0.25 和 0.75 倍)
  3. 将这两个数字四舍五入到下一个整数
  4. 这两个数字分别代表第一个和第三个四分位数的等级(在已排序的序列中)

奇数和偶数观测值的步骤相同。以下是以下系列的一个示例,代表 9 个成年人的身高(以厘米为单位):

170.2181.5188.9163.9166.4163.7160.4175.8181.5

我们先从最低到最高排序:

160.4163.7163.9166.4170.2175.8181.5181.5188.9

有 9 个观察值,所以

向上取整得到 3 和 7,分别代表第一个和第三个四分位数的等级。因此,第一个四分位数是 163.9 厘米,第三个四分位数是 181.5 厘米。

总之,25%的成年人身高低于 163.9 厘米(因此他们中的 75%高于 163.9 厘米),而 75%的成年人身高低于 181.5 厘米(因此他们中的 25%高于 181.5 厘米)。

q0.25、q0.75 和 q0.5

请注意,第一个四分位数表示为 q0.25,第三个四分位数表示为 q0.75(其中 q 代表四分位数)。如您所见,中位数实际上是第二个四分位数,因此有时也表示为 q0.5。

关于十分位数和百分位数的注记

十分位数和百分位数类似于四分位数,只是它们将数据分成 10 和 100 等份。例如,第四个十分位数(q0.4)是这样一个值,它下面有 40%的观察值,因此上面有 60%的观察值。此外,第 98 百分位(q0.98,有时也表示为 P98)是这样的值,即有 98%的观察值低于它,因此有 2%的观察值高于它。百分位数通常用于婴儿的体重和身高,为父母提供关于他们的孩子与同年龄的其他孩子相比的准确信息。

方式

数列的众数是最常出现的数值。换句话说,它是出现次数最多的值。考虑到 9 个成年人的身高:

170168171170182165170189167

模式为 170,因为它是最常见的值,出现 3 次。所有其他值只出现一次。总之,这个样本的大多数成年人身高都是 170 cm。请注意,一个系列可能没有模式(例如, 47210 )或一个以上的模式(例如, 42281111 )。

具有两种模式的数据通常被称为双峰数据,具有两种以上模式的数据通常被称为多峰数据,这与具有一种模式的序列被称为单峰数据相反。

定性变量模式

与一些只能计算定量变量(例如*均值)的描述性统计不同,可以计算定量定性变量的模式(如果您不记得区别,请参见不同类型变量的概述)。

给定上述 9 名成人的眼睛颜色:

棕色棕色棕色棕色蓝色蓝色蓝色棕色绿色

众数是棕色的,所以这个样本的大部分成年人眼睛都是棕色的。

散布

所有以前的描述性统计有助于了解数据的位置和方位。我们现在介绍最常见的离差度量,这有助于了解数据的离差和可变性(分布被压缩或拉伸的程度):

  • 范围
  • 标准偏差
  • 差异
  • 四分位差
  • 变异系数

至于位置测量,我们逐个手工详细计算这些统计数据。

范围

范围是最大值和最小值之间的差值:

范围=最大最小

给定我们的 6 名成人样本的身高(厘米):

188.7169.4178.6181.3179173.9

范围是 188.7-169.4 = 19.3 厘米。该范围的优点是计算起来非常容易,并且它给出了数据中可能值的精确概念。缺点是它只依赖于两个最极端的值。

标准偏差

标准差是统计学中最常见的离差度量。像位置测量的*均值一样,如果我们必须给出一个统计量来概括数据的分布,它通常是标准差。顾名思义,标准差告诉我们什么是数据的“正常”偏差。它实际上是计算与*均值的*均偏差。标准差越大,数据越分散。相反,标准差越小,数据越集中在*均值附*。下面是标准差的直观表示:

标准差。资料来源:加州大学卢万分校 LFSAB1105

标准差比之前的统计数据要复杂一些,因为有两个公式取决于我们面对的是样本还是总体。总体包括来自特定组的所有成员、所有可能的结果或感兴趣的度量。样本由从总体中抽取的一些观察值组成,即总体的一部分或子集。例如,人口可能是“所有居住在比利时的人”,样本可能是“一些居住在比利时的人”。如果你想了解更多,请阅读这篇关于总体和样本的差异的文章。

总体的标准偏差

总体的标准差,用σ表示,为:

从公式中可以看出,标准差实际上是数据与其均值μμ的*均偏差。注意观察值和*均值之间的差的*方,以避免负差被正差补偿。

为了简单起见,假设一个只有 3 个成年人的群体(步骤与大群体相同,只是计算时间更长)。低于他们的身高(厘米):

160.4175.8181.5

*均值为 172.6(四舍五入到 1 位小数)。因此,标准偏差为:

总之,这三个成年人身高的标准偏差是 8.91 厘米。这意味着,*均而言,该人群中成年人的身高偏离*均值 8.91 厘米。

样本的标准偏差

样本的标准差类似于总体的标准差,只是我们用 n1n 1 而不是 nn 来除,用 s 表示:

现在想象一下,上一节中出现的 3 个成年人是一个样本,而不是一个群体:

160.4175.8181.5

*均值仍然是 172.6(四舍五入到 1 位小数),因为无论是总体还是样本,*均值都是一样的。标准偏差现在是:

总之,这三个成年人身高的标准偏差是 10.92 厘米。对人口的解释是一样的。

差异

方差就是标准差的*方。换句话说,标准差是方差的*方根。我们也区分总体和样本的方差。

总体方差

用σ^2 表示的总体方差为:

如您所见,方差公式与标准差公式相同,只是方差的*方根被去掉了。记住我们三个成年人的身高:

160.4175.8181.5

标准偏差是 8.91 厘米,所以这些成年人身高的方差是 8.91^2 = 79.39 cm^2(见下文为什么方差的单位是 unit^2).

样本的方差

同样,样本的方差类似于总体的方差,只是我们除以 n1 而不是 n,它表示为 s^2:

再次假设上一节中的 3 个成年人是一个样本,而不是一个群体:

160.4175.8181.5

该样本的标准偏差为 10.92 厘米,因此这些成人身高的方差为 119.14 cm^2.

标准差与方差

标准差和方差通常可以互换使用,它们都通过测量观察值与*均值的距离来量化给定数据集的分布。但是,标准差可以更容易地解释,因为标准差的单位与数据的测量单位相同(虽然它是方差的 unit^2)。按照我们以厘米为单位的成人身高示例,标准偏差以厘米为单位测量,而方差以 cm^2.为单位测量事实上,标准偏差与初始测量单位保持相同的单位,这使得它更容易解释,因此在实践中更常用。

记号

为完整起见,在下表中显示了总体和样本的方差和标准差的不同符号:

四分位间距

还记得前面提出的第一个 q0.25 和第三个四分位数 q0.75 吗?四分位距是使用四分位来衡量数据离差的另一种方法。这是第三个四分位数和第一个四分位数之间的差异:

IQR = q 0.75 q 0.25

考虑到第一个和第三个四分位数部分给出的 9 名成人的身高:

170.2181.5188.9163.9166.4163.7160.4175.8181.5

第一个四分位数为 163.9 厘米,第三个四分位数为 181.5 厘米。IQR 是这样的:

IQR = 181.5-163.9 = 17.6

总之,四分位距是 17.6 厘米。四分位范围实际上是中间数据的范围(因为它是较高值和较低值之间的差值)。下图可能有助于更好地理解 IQR 和四分位数:

IQR,第一和第三季度。资料来源:加州大学卢万分校 LFSAB1105

变异系数

最后一个离差度量是变异系数。变异系数表示为 CV,是标准偏差除以*均值。形式上:

考虑 4 个成人样本的身高:

163.7160.4175.8181.5

*均值为 170.35 厘米,标准偏差为 9.95 厘米。(找到相同的价值观作为练习!)变异系数为

综上,变异系数为 5.8%。注意,根据经验,变异系数大于 15%通常意味着数据是异质的,而变异系数等于或小于 15%意味着数据是同质的。假设在这种情况下变异系数等于 5.8%,我们可以得出结论,这 4 个成年人在身高方面是同质的。

变异系数与标准偏差

虽然变异系数不为公众所知,但事实上,在进行描述性统计时,它是值得提出的。

标准偏差应始终在数据*均值的背景下理解,并取决于其单位。标准偏差的优点是,它可以告诉我们*均数据与测量数据的单位*均值相差多远。当考虑具有相同单位和*似相同*均值的变量时,标准差是有用的。然而,当用不同的单位或相差很大的*均值来比较变量时,标准差就没那么有用了。例如,一个标准偏差为 10 厘米的变量不能与一个标准偏差为 10€的变量进行比较,从而得出哪一个变量最分散的结论。

变异系数是具有相同单位的两个统计值的比率。因此,它没有单位,与测量数据的单位无关。由于是无单位的,所以可以比较对具有不同单位或差异很大的*均值的数据集或变量计算的变异系数,以最终得出哪个数据或变量更分散(或更不分散)的结论。例如,考虑 10 名女性的样本,她们的身高为厘米,工资在€。身高和工资的变异系数分别为 0.032 和 0.061。我们可以得出结论,相对于她们各自的*均值,这些女性的工资变化大于身高变化(因为工资的变异系数大于身高的变异系数)。

这就结束了一篇比较长的文章,感谢阅读!我希望这篇文章能帮助你理解和手工计算不同的描述性统计。如果您想了解如何在 R 中计算这些度量,请阅读文章“R中的描述性统计”。

和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。

相关文章:

原载于 2020 年 1 月 18 日 https://statsandr.com

R 中的描述统计

原文:https://towardsdatascience.com/descriptive-statistics-in-r-8e1cad20bf3a?source=collection_archive---------7-----------------------

本文解释了如何计算 R 中的主要描述性统计数据,以及如何以图形方式呈现它们。

照片由鲁特森·齐默曼拍摄

介绍

这篇文章解释了如何计算 R 中的主要描述性统计数据,以及如何用图表的方式展示它们。要了解每个描述性统计背后的推理,如何手工计算它们以及如何解释它们,请阅读文章“手工描述性统计”。

简要回顾一下那篇文章中所说的内容,描述统计学(广义上的)是统计学的一个分支,旨在总结、描述和呈现一系列值或数据集。描述性统计通常是任何统计分析的第一步和重要部分。它允许检查数据的质量,并有助于通过对数据有一个清晰的概述来“理解”数据。如果表述得好,描述性统计已经是进一步分析的良好起点。有许多方法可以总结一个数据集。它们分为两种类型:

  1. 位置测量和
  2. 分散测量

位置测量提供了对数据集中趋势的理解,而分散测量提供了对数据扩散的理解。在本文中,我们只关注 R 中最常见的描述性统计及其可视化的实现(如果认为合适的话)。有关每项措施的目的和用法的更多信息,请参见在线或上述文章中的

数据

我们在整篇文章中使用数据集iris。这个数据集在 R 中是默认导入的,你只需要通过运行iris来加载它:

dat <- iris # load the iris dataset and renamed it dat

下面是该数据集及其结构的预览:

head(dat) # first 6 observations##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosastr(dat) # structure of dataset## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

该数据集包含 150 个观察值和 5 个变量,代表萼片和花瓣的长度和宽度以及 150 种花的种类。萼片和花瓣的长度和宽度是数值变量,物种是一个有 3 个水*的因子(在变量名称后用numFactor w/ 3 levels表示)。如果需要刷新,请参见 R 中的不同变量类型。

关于图,我们给出了默认的图和著名的{ggplot2}包中的图。来自{ggplot2}包的图形通常具有更好的外观,但是它需要更高级的编码技能(参见文章“R 中的图形与 ggplot2 ”以了解更多信息)。如果你需要发布或分享你的图表,我建议如果可以的话使用{ggplot2},否则默认的图表就可以了。

提示:我最*从 **{esquisse}** 插件中发现了 ggplot2 构建器。看看你如何从 [**{ggplot2}**](https://www.statsandr.com/blog/rstudio-addins-or-how-to-make-your-coding-life-easier/) 中轻松地 画出图形,而不必自己编码。

本文中显示的所有图都可以定制。例如,可以编辑标题、x 和 y 轴标签、颜色等。然而,定制图超出了本文的范围,所以所有的图都没有任何定制。感兴趣的读者可以在网上找到大量的资源。

最小值和最大值

通过min()max()功能可以找到最小值和最大值:

min(dat$Sepal.Length)## [1] 4.3max(dat$Sepal.Length)## [1] 7.9

或者是range()功能:

rng <- range(dat$Sepal.Length)
rng## [1] 4.3 7.9

直接给出最小值和最大值。注意,range()函数的输出实际上是一个包含最小值和最大值的对象(按照这个顺序)。这意味着您实际上可以通过以下方式获得最小值:

rng[1] # rng = name of the object specified above## [1] 4.3

最大值为:

rng[2]## [1] 7.9

这提醒我们,在 R 中,通常有几种方法可以达到相同的结果。使用最短代码段的方法通常是首选,因为较短的代码段不容易出现编码错误,并且可读性更好。

范围

正如您所猜测的,通过从最大值中减去最小值,可以很容易地计算出范围:

max(dat$Sepal.Length) - min(dat$Sepal.Length)## [1] 3.6

据我所知,没有默认的函数来计算范围。但是,如果您熟悉用 R 编写函数,您可以创建自己的函数来计算范围:

range2 <- function(x) {
  range <- max(x) - min(x)
  return(range)
}range2(dat$Sepal.Length)## [1] 3.6

这相当于上面给出的最大最小值。

*均

*均值可以用mean()函数计算:

mean(dat$Sepal.Length)## [1] 5.843333

温馨提示:

  • 如果数据集中至少有一个缺失值,使用mean(dat$Sepal.Length, na.rm = TRUE)计算排除 NA 后的*均值。该参数可用于本文中介绍的大多数函数,而不仅仅是*均值
  • 对于截断的*均值,使用mean(dat$Sepal.Length, trim = 0.10)并根据您的需要更改trim参数

中位数

通过median()函数可以计算出中值:

median(dat$Sepal.Length)## [1] 5.8

或者使用quantile()功能:

quantile(dat$Sepal.Length, 0.5)## 50% 
## 5.8

因为 0.5 阶的分位数(q0.5)对应于中值。

第一和第三四分位数

由于使用了quantile()函数,并通过将第二个参数设置为 0.25 或 0.75,可以计算出第一个和第三个四分位数的中值:

quantile(dat$Sepal.Length, 0.25) # first quartile## 25% 
## 5.1quantile(dat$Sepal.Length, 0.75) # third quartile## 75% 
## 6.4

您可能已经看到,上面的结果与您手工计算第一个和第三个四分位数的结果略有不同。这是正常的,有许多方法来计算它们(R 实际上有 7 种方法来计算分位数!).然而,这里和文章“手工描述性统计”中介绍的方法是最简单和最“标准”的方法。此外,两种方法之间的结果没有显著变化。

其他分位数

正如您已经猜到的,任何分位数也可以用quantile()函数来计算。例如,第四个十分位数或第 98 个百分位数:

quantile(dat$Sepal.Length, 0.4) # 4th decile## 40% 
## 5.6quantile(dat$Sepal.Length, 0.98) # 98th percentile## 98% 
## 7.7

四分位间距

四分位数间距(即第一个四分位数和第三个四分位数之间的差值)可以用IQR()函数计算:

IQR(dat$Sepal.Length)## [1] 1.3

或者再次使用quantile()功能:

quantile(dat$Sepal.Length, 0.75) - quantile(dat$Sepal.Length, 0.25)## 75% 
## 1.3

如前所述,如果可能的话,通常建议使用最短的代码来获得结果。因此,最好使用IQR()函数来计算四分位数范围。

标准偏差和方差

使用sd()var()函数计算标准偏差和方差:

sd(dat$Sepal.Length) # standard deviation## [1] 0.8280661var(dat$Sepal.Length) # variance## [1] 0.6856935

请记住文章手动描述性统计中的内容,无论是计算样本还是总体,标准差和方差都是不同的(参见样本和总体之间的差异)。在 R 中,计算标准差和方差时,假设数据代表一个样本(因此分母为 n-1,其中 n 为观察次数)。据我所知,R 中默认没有计算总体的标准差或方差的函数。

提示:要同时计算多个变量的标准差(或方差),使用lapply()和适当的统计数据作为第二个参数:

lapply(dat[, 1:4], sd)## $Sepal.Length
## [1] 0.8280661
## 
## $Sepal.Width
## [1] 0.4358663
## 
## $Petal.Length
## [1] 1.765298
## 
## $Petal.Width
## [1] 0.7622377

命令dat[, 1:4]选择变量 1 至 4,因为第五个变量是一个定性变量,不能对这类变量计算标准偏差。如有必要,参见 R 中不同数据类型的概述。

摘要

您可以使用summary()一次计算数据集所有数值变量的最小值、第一四分位数、中值、*均值、第三四分位数和最大值:

summary(dat)##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
##  1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
##  Median :5.800   Median :3.000   Median :4.350   Median :1.300  
##  Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
##  3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
##  Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
##        Species  
##  setosa    :50  
##  versicolor:50  
##  virginica :50  
##                 
##                 
##

提示:如果您需要这些分组描述性统计数据,请使用by()功能:

by(dat, dat$Species, summary)## dat$Species: setosa
##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.300   Min.   :2.300   Min.   :1.000   Min.   :0.100  
##  1st Qu.:4.800   1st Qu.:3.200   1st Qu.:1.400   1st Qu.:0.200  
##  Median :5.000   Median :3.400   Median :1.500   Median :0.200  
##  Mean   :5.006   Mean   :3.428   Mean   :1.462   Mean   :0.246  
##  3rd Qu.:5.200   3rd Qu.:3.675   3rd Qu.:1.575   3rd Qu.:0.300  
##  Max.   :5.800   Max.   :4.400   Max.   :1.900   Max.   :0.600  
##        Species  
##  setosa    :50  
##  versicolor: 0  
##  virginica : 0  
##                 
##                 
##                 
## ------------------------------------------------------------ 
## dat$Species: versicolor
##   Sepal.Length    Sepal.Width     Petal.Length   Petal.Width          Species  
##  Min.   :4.900   Min.   :2.000   Min.   :3.00   Min.   :1.000   setosa    : 0  
##  1st Qu.:5.600   1st Qu.:2.525   1st Qu.:4.00   1st Qu.:1.200   versicolor:50  
##  Median :5.900   Median :2.800   Median :4.35   Median :1.300   virginica : 0  
##  Mean   :5.936   Mean   :2.770   Mean   :4.26   Mean   :1.326                  
##  3rd Qu.:6.300   3rd Qu.:3.000   3rd Qu.:4.60   3rd Qu.:1.500                  
##  Max.   :7.000   Max.   :3.400   Max.   :5.10   Max.   :1.800                  
## ------------------------------------------------------------ 
## dat$Species: virginica
##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.900   Min.   :2.200   Min.   :4.500   Min.   :1.400  
##  1st Qu.:6.225   1st Qu.:2.800   1st Qu.:5.100   1st Qu.:1.800  
##  Median :6.500   Median :3.000   Median :5.550   Median :2.000  
##  Mean   :6.588   Mean   :2.974   Mean   :5.552   Mean   :2.026  
##  3rd Qu.:6.900   3rd Qu.:3.175   3rd Qu.:5.875   3rd Qu.:2.300  
##  Max.   :7.900   Max.   :3.800   Max.   :6.900   Max.   :2.500  
##        Species  
##  setosa    : 0  
##  versicolor: 0  
##  virginica :50  
##                 
##                 
##

其中参数是数据集、分组变量和汇总函数的名称。请遵循此顺序,如果不遵循此顺序,请指定参数的名称。

如果您需要更多的描述性统计数据,请使用{pastecs}包中的stat.desc():

library(pastecs)
stat.desc(dat)##              Sepal.Length  Sepal.Width Petal.Length  Petal.Width Species
## nbr.val      150.00000000 150.00000000  150.0000000 150.00000000      NA
## nbr.null       0.00000000   0.00000000    0.0000000   0.00000000      NA
## nbr.na         0.00000000   0.00000000    0.0000000   0.00000000      NA
## min            4.30000000   2.00000000    1.0000000   0.10000000      NA
## max            7.90000000   4.40000000    6.9000000   2.50000000      NA
## range          3.60000000   2.40000000    5.9000000   2.40000000      NA
## sum          876.50000000 458.60000000  563.7000000 179.90000000      NA
## median         5.80000000   3.00000000    4.3500000   1.30000000      NA
## mean           5.84333333   3.05733333    3.7580000   1.19933333      NA
## SE.mean        0.06761132   0.03558833    0.1441360   0.06223645      NA
## CI.mean.0.95   0.13360085   0.07032302    0.2848146   0.12298004      NA
## var            0.68569351   0.18997942    3.1162779   0.58100626      NA
## std.dev        0.82806613   0.43586628    1.7652982   0.76223767      NA
## coef.var       0.14171126   0.14256420    0.4697441   0.63555114      NA

通过在前面的函数中添加参数norm = TRUE,您可以获得更多的统计数据(即偏度、峰度和正态性检验)。请注意,变量Species不是数字,因此无法计算该变量的描述性统计数据,并显示 NA。

变异系数

变异系数可以通过stat.desc()(见上表中的coef.var线)或手动计算得到(记住变异系数是标准偏差除以*均值):

sd(dat$Sepal.Length) / mean(dat$Sepal.Length)## [1] 0.1417113

方式

据我所知,没有找到变量模式的函数。然而,由于函数table()sort(),我们可以很容易地找到它:

tab <- table(dat$Sepal.Length) # number of occurrences for each unique value
sort(tab, decreasing = TRUE) # sort highest to lowest## 
##   5 5.1 6.3 5.7 6.7 5.5 5.8 6.4 4.9 5.4 5.6   6 6.1 4.8 6.5 4.6 5.2 6.2 6.9 7.7 
##  10   9   9   8   8   7   7   7   6   6   6   6   6   5   5   4   4   4   4   4 
## 4.4 5.9 6.8 7.2 4.7 6.6 4.3 4.5 5.3   7 7.1 7.3 7.4 7.6 7.9 
##   3   3   3   3   2   2   1   1   1   1   1   1   1   1   1

table()给出每个唯一值出现的次数,然后sort()和参数decreasing = TRUE从最高到最低显示出现的次数。因此变量Sepal.Length的模式是 5。此代码查找模式也可应用于定性变量,如Species:

sort(table(dat$Species), decreasing = TRUE)## 
##     setosa versicolor  virginica 
##         50         50         50

或者:

summary(dat$Species)##     setosa versicolor  virginica 
##         50         50         50

相互关系

另一个描述性统计是相关系数。相关性衡量两个变量之间的线性关系。

计算 R 中的相关性需要一个详细的解释,所以我写了一篇文章,涵盖了相关性和相关性测试

相依表

table()上面介绍的也可以用在两个定性变量上来创建一个列联表。数据集iris只有一个定性变量,因此我们为这个例子创建一个新的定性变量。我们创建变量size,如果花瓣的长度小于所有花的中值,则对应于small,否则对应于big:

dat$size <- ifelse(dat$Sepal.Length < median(dat$Sepal.Length),
  "small", "big"
)

以下是按大小排列的事件摘要:

table(dat$size)## 
##   big small 
##    77    73

我们现在用table()函数创建两个变量Speciessize的列联表:

table(dat$Species, dat$size)##             
##              big small
##   setosa       1    49
##   versicolor  29    21
##   virginica   47     3

或者用xtabs()功能:

xtabs(~ dat$Species + dat$size)##             dat$size
## dat$Species  big small
##   setosa       1    49
##   versicolor  29    21
##   virginica   47     3

列联表给出了每个分组的病例数。例如,只有一朵大刚毛藻花,而数据集中有 49 朵小刚毛藻花。

更进一步,我们可以从表中看出,setosa 花的尺寸似乎比 virginica 花大。为了检查大小是否与物种显著相关,我们可以进行独立性的卡方检验,因为两个变量都是分类变量。参见如何用手和 R 中的进行该测试

请注意,Species在行中,size在列中,因为我们在table()中指定了Species,然后又指定了size。如果要切换两个变量,请更改顺序。

代替具有频率(即..病例数)您还可以通过在prop.table()函数中添加table()函数来获得每个子组中的相对频率(即比例):

prop.table(table(dat$Species, dat$size))##             
##                      big       small
##   setosa     0.006666667 0.326666667
##   versicolor 0.193333333 0.140000000
##   virginica  0.313333333 0.020000000

注意,您也可以通过向prop.table()函数添加第二个参数来按行或按列计算百分比:1表示行,或者2表示列:

# percentages by row:
round(prop.table(table(dat$Species, dat$size), 1), 2) # round to 2 digits with round()##             
##               big small
##   setosa     0.02  0.98
##   versicolor 0.58  0.42
##   virginica  0.94  0.06# percentages by column:
round(prop.table(table(dat$Species, dat$size), 2), 2) # round to 2 digits with round()##             
##               big small
##   setosa     0.01  0.67
##   versicolor 0.38  0.29
##   virginica  0.61  0.04

更多高级列联表见高级描述统计部分。

马赛克图

镶嵌图允许可视化两个定性变量的列联表:

mosaicplot(table(dat$Species, dat$size),
  color = TRUE,
  xlab = "Species", # label for x-axis
  ylab = "Size" # label for y-axis
)

镶嵌图显示,对于我们的样本,大小花的比例在三个物种之间明显不同。特别是,海滨锦鸡儿属物种是最大的,而 setosa 属物种是三个物种中最小的(就萼片长度而言,因为变量size是基于变量Sepal.Length)。

供您参考,镶嵌图也可以通过{vcd}包中的mosaic()功能完成:

library(vcd)mosaic(~ Species + size,
       data = dat,
       direction = c("v", "h"))

条形图

柱状图只能在定性变量上完成(参见定量变量的差异这里)。柱状图是一种可视化定性变量分布的工具。我们绘制了定性变量size的柱状图:

barplot(table(dat$size)) # table() is mandatory

您也可以像我们之前做的那样,通过添加prop.table()来绘制相对频率而不是频率的柱状图:

barplot(prop.table(table(dat$size)))

{ggplot2}中:

library(ggplot2) # needed each time you open RStudio
# The package ggplot2 must be installed firstggplot(dat) +
  aes(x = size) +
  geom_bar()

柱状图

直方图给出了定量变量分布的概念。这个想法是将值的范围分成区间,并计算每个区间内有多少个观察值。直方图有点类似于柱状图,但是直方图用于定量变量,而柱状图用于定性变量。要在 R 中绘制直方图,使用hist():

hist(dat$Sepal.Length)

如果您想要更改容器的数量,请在hist()函数中添加参数breaks =。一个经验法则(称为斯特奇斯定律)是,仓的数量应该是观察数量的*方根的舍入值。数据集包括 150 个观察值,因此在这种情况下,箱的数量可以设置为 12。

{ggplot2}:

ggplot(dat) +
  aes(x = Sepal.Length) +
  geom_histogram()

默认情况下,箱子的数量为 30。例如,您可以使用geom_histogram(bins = 12)更改该值。

箱线图

箱线图在描述性统计中非常有用,但往往没有得到充分利用(主要是因为公众没有很好地理解它)。箱线图通过直观显示五个常见位置汇总(最小值、中值、第一/第三四分位数和最大值)以及使用四分位数间距(IQR)标准分类为可疑异常值的任何观察值,以图形方式表示定量变量的分布。IQR 标准意味着 q0.75+1.5⋅IQR 以上和 q0.25−1.5⋅IQR 以下的所有观测值(其中 q0.25 和 q0.75 分别对应于第一和第三四分位数)都被 r 视为潜在异常值。箱线图中的最小值和最大值表示为没有这些可疑异常值。在同一个图上看到所有这些信息有助于对数据的分散和位置有一个良好的初步了解。在绘制数据的箱线图之前,请参见下图,该图解释了箱线图上的信息:

详细箱线图。资料来源:加州大学卢万分校 LFSAB1105

现在我们的数据集有一个例子:

boxplot(dat$Sepal.Length)

为了比较和对比两个或更多组的分布情况,并排显示的箱线图提供的信息甚至更多。例如,我们比较不同物种的萼片长度:

boxplot(dat$Sepal.Length ~ dat$Species)

{ggplot2}:

ggplot(dat) +
  aes(x = Species, y = Sepal.Length) +
  geom_boxplot()

点图

点状图或多或少类似于箱线图,只是观察值以点表示,并且图上没有汇总统计数据:

library(lattice)dotplot(dat$Sepal.Length ~ dat$Species)

散点图

散点图允许检查两个定量变量之间是否有潜在的联系。出于这个原因,散点图经常被用来可视化两个变量之间的潜在关联。例如,当绘制萼片长度和花瓣长度的散点图时:

plot(dat$Sepal.Length, dat$Petal.Length)

这两个变量之间似乎有正相关。

{ggplot2}中:

ggplot(dat) +
  aes(x = Sepal.Length, y = Petal.Length) +
  geom_point()

作为箱线图,散点图在根据因子区分点时提供的信息甚至更多,在这种情况下,物种:

ggplot(dat) +
  aes(x = Sepal.Length, y = Petal.Length, colour = Species) +
  geom_point() +
  scale_color_hue()

QQ 图

对于单个变量

为了检查变量的正态性假设(正态性是指数据遵循正态分布,也称为高斯分布),我们通常使用直方图和/或 QQ 图。 1 如果您需要更新相关内容,请参阅讨论正态分布以及如何评估 R 中的正态假设的文章。直方图前面已经介绍过了,下面是如何绘制 QQ 图:

# Draw points on the qq-plot:
qqnorm(dat$Sepal.Length)
# Draw the reference line:
qqline(dat$Sepal.Length)

或者使用{car}包中的qqPlot()函数绘制带置信带的 QQ 图:

library(car) # package must be installed first
qqPlot(dat$Sepal.Length)

## [1] 132 118

如果点靠*参考线(有时称为亨利线)并在置信带内,则可以认为满足正态性假设。点和参考线之间的偏差越大,并且它们越位于置信带之外,满足正态条件的可能性就越小。变量Sepal.Length似乎不遵循正态分布,因为有几个点位于置信带之外。当面对非正态分布时,第一步通常是对数据应用对数变换,并重新检查经过对数变换的数据是否正态分布。应用对数变换可以通过log()功能完成。

{ggpubr}:

library(ggpubr)
ggqqplot(dat$Sepal.Length)

按组

对于一些统计检验,所有组都需要正态假设。一种解决方案是通过手动将数据集分成不同的组来为每个组绘制 QQ 图,然后为每个数据子集绘制 QQ 图(使用上面所示的方法)。另一个(更简单的)解决方案是用{car}包中函数qqPlot()中的参数groups =为每个组自动绘制一个 QQ 图:

qqPlot(dat$Sepal.Length, groups = dat$size)

{ggplot2}中:

qplot(
  sample = Sepal.Length, data = dat,
  col = size, shape = size
)

也可以仅通过形状或颜色来区分组。为此,删除上述qplot()函数中的参数colshape之一。

密度图

密度图是直方图的*滑版本,用于相同的概念,即表示数值变量的分布。函数plot()density()一起用于绘制密度图:

plot(density(dat$Sepal.Length))

{ggplot2}中:

ggplot(dat) +
  aes(x = Sepal.Length) +
  geom_density()

相关图

最后一种描述图是相关图,也称为相关图。这种类型的图表比上面给出的图表更复杂,因此将在另一篇文章中详细介绍。参见如何绘制相关图以突出显示数据集中最相关的变量

高级描述统计学

我们讨论了计算最常见和最基本的描述性统计数据的主要函数。然而,r 中有更多的函数和包来执行更高级的描述性统计。在本节中,我将介绍其中一些函数和包在我们的数据集上的应用。

{summarytools}套餐

我在 R 语言项目中经常使用的一个描述性统计软件包是[{summarytools}](https://cran.r-project.org/web/packages/summarytools/index.html)软件包。该包围绕 4 个功能展开:

  1. freq()对于频率表
  2. ctable()用于交叉制表
  3. descr()用于描述性统计
  4. dfSummary()对于数据帧摘要

对于大多数描述性分析来说,这 4 个功能的组合通常已经足够了。此外,这个包在构建时考虑到了 R Markdown ,这意味着输出在 HTML 报告中表现良好。对于非英语使用者,内置了法语、葡萄牙语、西班牙语、俄语和土耳其语翻译。

在接下来的几节中,我将分别阐述这四个函数。随后的输出在 R Markdown 报告中显示得更好,但在本文中,我将自己限制在原始输出上,因为目标是展示函数如何工作,而不是如何使它们呈现得更好。如果您想在 R Markdown 中以漂亮的方式打印输出,请参见包装的插图中的设置设置。 2

freq()的频率表

freq()功能生成频率表,其中包含频率、比例以及缺失数据信息。

library(summarytools)
freq(dat$Species)## Frequencies  
## dat$Species  
## Type: Factor  
## 
##                    Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ---------------- ------ --------- -------------- --------- --------------
##           setosa     50     33.33          33.33     33.33          33.33
##       versicolor     50     33.33          66.67     33.33          66.67
##        virginica     50     33.33         100.00     33.33         100.00
##             <NA>      0                               0.00         100.00
##            Total    150    100.00         100.00    100.00         100.00

如果不需要关于缺失值的信息,添加report.nas = FALSE参数:

freq(dat$Species,
     report.nas = FALSE) # remove NA information## Frequencies  
## dat$Species  
## Type: Factor  
## 
##                    Freq        %   % Cum.
## ---------------- ------ -------- --------
##           setosa     50    33.33    33.33
##       versicolor     50    33.33    66.67
##        virginica     50    33.33   100.00
##            Total    150   100.00   100.00

对于只有计数和比例的极简输出:

freq(dat$Species,
     report.nas = FALSE, # remove NA information
     totals = FALSE, # remove totals
     cumul = FALSE, # remove cumuls
     headings = FALSE) # remove headings## 
##                    Freq       %
## ---------------- ------ -------
##           setosa     50   33.33
##       versicolor     50   33.33
##        virginica     50   33.33

ctable()交叉列表

ctable()函数为分类变量对生成交叉表(也称为列联表)。使用数据集中的两个分类变量:

ctable(x = dat$Species,
       y = dat$size)## Cross-Tabulation, Row Proportions  
## Species * size  
## Data Frame: dat  
## 
## ------------ ------ ------------ ------------ --------------
##                size          big        small          Total
##      Species                                                
##       setosa           1 ( 2.0%)   49 (98.0%)    50 (100.0%)
##   versicolor          29 (58.0%)   21 (42.0%)    50 (100.0%)
##    virginica          47 (94.0%)    3 ( 6.0%)    50 (100.0%)
##        Total          77 (51.3%)   73 (48.7%)   150 (100.0%)
## ------------ ------ ------------ ------------ --------------

默认情况下显示行比例。要显示列或总比例,分别添加prop = "c"prop = "t"参数:

ctable(x = dat$Species,
       y = dat$size,
       prop = "t") # total proportions## Cross-Tabulation, Total Proportions  
## Species * size  
## Data Frame: dat  
## 
## ------------ ------ ------------ ------------ --------------
##                size          big        small          Total
##      Species                                                
##       setosa           1 ( 0.7%)   49 (32.7%)    50 ( 33.3%)
##   versicolor          29 (19.3%)   21 (14.0%)    50 ( 33.3%)
##    virginica          47 (31.3%)    3 ( 2.0%)    50 ( 33.3%)
##        Total          77 (51.3%)   73 (48.7%)   150 (100.0%)
## ------------ ------ ------------ ------------ --------------

要完全删除比例,请添加参数prop = "n"。此外,为了只显示最低限度,添加totals = FALSEheadings = FALSE参数:

ctable(x = dat$Species,
       y = dat$size,
       prop = "n", # remove proportions
       totals = FALSE, # remove totals
       headings = FALSE) # remove headings## 
## ------------ ------ ----- -------
##                size   big   small
##      Species                     
##       setosa            1      49
##   versicolor           29      21
##    virginica           47       3
## ------------ ------ ----- -------

这相当于在列联表中执行的table(dat$Species, dat$size)xtabs(~ dat$Species + dat$size)

为了显示卡方独立性检验的结果,添加chisq = TRUE参数: 3

ctable(x = dat$Species,
       y = dat$size,
       chisq = TRUE, # display results of Chi-square test of independence
       headings = FALSE) # remove headings## 
## ------------ ------ ------------ ------------ --------------
##                size          big        small          Total
##      Species                                                
##       setosa           1 ( 2.0%)   49 (98.0%)    50 (100.0%)
##   versicolor          29 (58.0%)   21 (42.0%)    50 (100.0%)
##    virginica          47 (94.0%)    3 ( 6.0%)    50 (100.0%)
##        Total          77 (51.3%)   73 (48.7%)   150 (100.0%)
## ------------ ------ ------------ ------------ --------------
## 
## ----------------------------
##  Chi.squared   df   p.value 
## ------------- ---- ---------
##     86.03      2       0    
## ----------------------------

p 值接*于 0,所以我们拒绝两个变量之间独立性的零假设。在我们的上下文中,这表明物种和大小是相互依赖的,并且这两个变量之间存在显著的关系。

由于结合了stby()ctable()函数,还可以为第三分类变量的每个级别创建一个列联表。我们的数据集中只有 2 个分类变量,所以让我们使用有 4 个分类变量(即性别、年龄组、吸烟者、患病者)的tabacco数据集。对于这个例子,我们想要创建一个变量smokerdiseased的列联表,并且对于每个gender:

stby(list(x = tobacco$smoker, # smoker and diseased
          y = tobacco$diseased), 
     INDICES = tobacco$gender, # for each gender
     FUN = ctable) # ctable for cross-tabulation## Cross-Tabulation, Row Proportions  
## smoker * diseased  
## Data Frame: tobacco  
## Group: gender = F  
## 
## -------- ---------- ------------- ------------- --------------
##            diseased           Yes            No          Total
##   smoker                                                      
##      Yes               62 (42.2%)    85 (57.8%)   147 (100.0%)
##       No               49 (14.3%)   293 (85.7%)   342 (100.0%)
##    Total              111 (22.7%)   378 (77.3%)   489 (100.0%)
## -------- ---------- ------------- ------------- --------------
## 
## Group: gender = M  
## 
## -------- ---------- ------------- ------------- --------------
##            diseased           Yes            No          Total
##   smoker                                                      
##      Yes               63 (44.1%)    80 (55.9%)   143 (100.0%)
##       No               47 (13.6%)   299 (86.4%)   346 (100.0%)
##    Total              110 (22.5%)   379 (77.5%)   489 (100.0%)
## -------- ---------- ------------- ------------- --------------

descr()描述性统计

descr()函数生成描述性(单变量)统计数据,其中包含常见的集中趋势统计数据和离差测量值。(如果您需要提醒,请参见集中趋势和分散程度之间的差异。)

该函数的一个主要优点是它接受单个矢量和数据帧。如果提供了数据框,则会忽略所有非数字列,因此您不必在运行函数之前亲自移除它们。

descr()功能允许显示:

  • 只有一个你选择的描述性统计的选择,以*均值和标准差的stats = c("mean", "sd")参数为例
  • 使用stats = "fivenum"的最小值、第一个四分位数、中间值、第三个四分位数和最大值
  • 最常见的描述性统计(均值、标准差、最小值、中值、最大值、有效观察值的数量和百分比),用stats = "common":
descr(dat,
      headings = FALSE, # remove headings
      stats = "common") # most common descriptive statistics## 
##                   Petal.Length   Petal.Width   Sepal.Length   Sepal.Width
## --------------- -------------- ------------- -------------- -------------
##            Mean           3.76          1.20           5.84          3.06
##         Std.Dev           1.77          0.76           0.83          0.44
##             Min           1.00          0.10           4.30          2.00
##          Median           4.35          1.30           5.80          3.00
##             Max           6.90          2.50           7.90          4.40
##         N.Valid         150.00        150.00         150.00        150.00
##       Pct.Valid         100.00        100.00         100.00        100.00

提示:如果你有大量的变量,添加transpose = TRUE参数以获得更好的显示效果。

为了按组计算这些描述性统计数据(例如,我们数据集中的Species),请将descr()函数与stby()函数结合使用:

stby(data = dat,
     INDICES = dat$Species, # by Species
     FUN = descr, # descriptive statistics
     stats = "common") # most common descr. stats## Descriptive Statistics  
## dat  
## Group: Species = setosa  
## N: 50  
## 
##                   Petal.Length   Petal.Width   Sepal.Length   Sepal.Width
## --------------- -------------- ------------- -------------- -------------
##            Mean           1.46          0.25           5.01          3.43
##         Std.Dev           0.17          0.11           0.35          0.38
##             Min           1.00          0.10           4.30          2.30
##          Median           1.50          0.20           5.00          3.40
##             Max           1.90          0.60           5.80          4.40
##         N.Valid          50.00         50.00          50.00         50.00
##       Pct.Valid         100.00        100.00         100.00        100.00
## 
## Group: Species = versicolor  
## N: 50  
## 
##                   Petal.Length   Petal.Width   Sepal.Length   Sepal.Width
## --------------- -------------- ------------- -------------- -------------
##            Mean           4.26          1.33           5.94          2.77
##         Std.Dev           0.47          0.20           0.52          0.31
##             Min           3.00          1.00           4.90          2.00
##          Median           4.35          1.30           5.90          2.80
##             Max           5.10          1.80           7.00          3.40
##         N.Valid          50.00         50.00          50.00         50.00
##       Pct.Valid         100.00        100.00         100.00        100.00
## 
## Group: Species = virginica  
## N: 50  
## 
##                   Petal.Length   Petal.Width   Sepal.Length   Sepal.Width
## --------------- -------------- ------------- -------------- -------------
##            Mean           5.55          2.03           6.59          2.97
##         Std.Dev           0.55          0.27           0.64          0.32
##             Min           4.50          1.40           4.90          2.20
##          Median           5.55          2.00           6.50          3.00
##             Max           6.90          2.50           7.90          3.80
##         N.Valid          50.00         50.00          50.00         50.00
##       Pct.Valid         100.00        100.00         100.00        100.00

使用dfSummary()的数据帧摘要

dfSummary()函数生成一个汇总表,其中包含数据集中所有变量的统计数据、频率和图表。显示的信息取决于变量的类型(字符、因子、数字、日期),也根据不同值的数量而变化。

dfSummary(dat)## Data Frame Summary  
## dat  
## Dimensions: 150 x 6  
## Duplicates: 1  
## 
## ----------------------------------------------------------------------------------------------------------------------
## No   Variable        Stats / Values           Freqs (% of Valid)   Graph                            Valid    Missing  
## ---- --------------- ------------------------ -------------------- -------------------------------- -------- ---------
## 1    Sepal.Length    Mean (sd) : 5.8 (0.8)    35 distinct values     . . : :                        150      0        
##      [numeric]       min < med < max:                                : : : :                        (100%)   (0%)     
##                      4.3 < 5.8 < 7.9                                 : : : : :                                        
##                      IQR (CV) : 1.3 (0.1)                            : : : : :                                        
##                                                                    : : : : : : : :                                    
## 
## 2    Sepal.Width     Mean (sd) : 3.1 (0.4)    23 distinct values           :                        150      0        
##      [numeric]       min < med < max:                                      :                        (100%)   (0%)     
##                      2 < 3 < 4.4                                         . :                                          
##                      IQR (CV) : 0.5 (0.1)                              : : : :                                        
##                                                                    . . : : : : : :                                    
## 
## 3    Petal.Length    Mean (sd) : 3.8 (1.8)    43 distinct values   :                                150      0        
##      [numeric]       min < med < max:                              :         . :                    (100%)   (0%)     
##                      1 < 4.3 < 6.9                                 :         : : .                                    
##                      IQR (CV) : 3.5 (0.5)                          : :       : : : .                                  
##                                                                    : :   . : : : : : .                                
## 
## 4    Petal.Width     Mean (sd) : 1.2 (0.8)    22 distinct values   :                                150      0        
##      [numeric]       min < med < max:                              :                                (100%)   (0%)     
##                      0.1 < 1.3 < 2.5                               :       . .   :                                    
##                      IQR (CV) : 1.5 (0.6)                          :       : :   :   .                                
##                                                                    : :   : : : . : : :                                
## 
## 5    Species         1\. setosa                50 (33.3%)           IIIIII                           150      0        
##      [factor]        2\. versicolor            50 (33.3%)           IIIIII                           (100%)   (0%)     
##                      3\. virginica             50 (33.3%)           IIIIII                                             
## 
## 6    size            1\. big                   77 (51.3%)           IIIIIIIIII                       150      0        
##      [character]     2\. small                 73 (48.7%)           IIIIIIIII                        (100%)   (0%)     
## ----------------------------------------------------------------------------------------------------------------------

describeBy()来自{psych}

{psych}包中的describeBy()函数允许按分组变量报告多个汇总统计数据(即有效病例数、*均值、标准偏差、中值、修整*均值、mad:中值绝对偏差(与中值的偏差)、最小值、最大值、范围、偏斜度和峰度)。

library(psych)
describeBy(dat,
           dat$Species) # grouping variable## 
##  Descriptive statistics by group 
## group: setosa
##              vars  n mean   sd median trimmed  mad min  max range skew kurtosis
## Sepal.Length    1 50 5.01 0.35    5.0    5.00 0.30 4.3  5.8   1.5 0.11    -0.45
## Sepal.Width     2 50 3.43 0.38    3.4    3.42 0.37 2.3  4.4   2.1 0.04     0.60
## Petal.Length    3 50 1.46 0.17    1.5    1.46 0.15 1.0  1.9   0.9 0.10     0.65
## Petal.Width     4 50 0.25 0.11    0.2    0.24 0.00 0.1  0.6   0.5 1.18     1.26
## Species*        5 50 1.00 0.00    1.0    1.00 0.00 1.0  1.0   0.0  NaN      NaN
## size*           6 50  NaN   NA     NA     NaN   NA Inf -Inf  -Inf   NA       NA
##                se
## Sepal.Length 0.05
## Sepal.Width  0.05
## Petal.Length 0.02
## Petal.Width  0.01
## Species*     0.00
## size*          NA
## ------------------------------------------------------------ 
## group: versicolor
##              vars  n mean   sd median trimmed  mad min  max range  skew
## Sepal.Length    1 50 5.94 0.52   5.90    5.94 0.52 4.9  7.0   2.1  0.10
## Sepal.Width     2 50 2.77 0.31   2.80    2.78 0.30 2.0  3.4   1.4 -0.34
## Petal.Length    3 50 4.26 0.47   4.35    4.29 0.52 3.0  5.1   2.1 -0.57
## Petal.Width     4 50 1.33 0.20   1.30    1.32 0.22 1.0  1.8   0.8 -0.03
## Species*        5 50 2.00 0.00   2.00    2.00 0.00 2.0  2.0   0.0   NaN
## size*           6 50  NaN   NA     NA     NaN   NA Inf -Inf  -Inf    NA
##              kurtosis   se
## Sepal.Length    -0.69 0.07
## Sepal.Width     -0.55 0.04
## Petal.Length    -0.19 0.07
## Petal.Width     -0.59 0.03
## Species*          NaN 0.00
## size*              NA   NA
## ------------------------------------------------------------ 
## group: virginica
##              vars  n mean   sd median trimmed  mad min  max range  skew
## Sepal.Length    1 50 6.59 0.64   6.50    6.57 0.59 4.9  7.9   3.0  0.11
## Sepal.Width     2 50 2.97 0.32   3.00    2.96 0.30 2.2  3.8   1.6  0.34
## Petal.Length    3 50 5.55 0.55   5.55    5.51 0.67 4.5  6.9   2.4  0.52
## Petal.Width     4 50 2.03 0.27   2.00    2.03 0.30 1.4  2.5   1.1 -0.12
## Species*        5 50 3.00 0.00   3.00    3.00 0.00 3.0  3.0   0.0   NaN
## size*           6 50  NaN   NA     NA     NaN   NA Inf -Inf  -Inf    NA
##              kurtosis   se
## Sepal.Length    -0.20 0.09
## Sepal.Width      0.38 0.05
## Petal.Length    -0.37 0.08
## Petal.Width     -0.75 0.04
## Species*          NaN 0.00
## size*              NA   NA

aggregate()功能

aggregate()函数允许将数据分成子集,然后计算每个子集的汇总统计数据。例如,如果我们想通过SpeciesSize计算变量Sepal.LengthSepal.Width的*均值:

aggregate(cbind(Sepal.Length, Sepal.Width) ~ Species + size,
          data = dat,
          mean)##      Species  size Sepal.Length Sepal.Width
## 1     setosa   big     5.800000    4.000000
## 2 versicolor   big     6.282759    2.868966
## 3  virginica   big     6.663830    2.997872
## 4     setosa small     4.989796    3.416327
## 5 versicolor small     5.457143    2.633333
## 6  virginica small     5.400000    2.600000

感谢阅读。我希望这篇文章能帮助你在 r 中做描述性统计。如果你想手工做同样的事情或理解这些统计代表什么,我邀请你阅读文章"手工描述性统计"。

和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。

相关文章:

  1. 正态性检验,如夏皮罗-维尔克或科尔莫戈罗夫-斯米尔诺夫检验,也可以用来检验数据是否遵循正态分布。然而,在实践中,正态性检验通常被认为过于保守,因为对于大样本量,与正态性的微小偏差都可能导致违反正态性条件。由于这个原因,通常情况下,正态性条件是基于视觉检查(直方图和 QQ 图)和形式检验(例如夏皮罗-维尔克检验)的组合来验证的。
  2. 注意这个包需要plain.asciistyle参数。在我们的例子中,这些参数被添加到每个块的设置中,所以它们是不可见的。
  3. 注意,也可以计算比值比和风险比。关于这个问题的更多信息,请参见软件包的简介,因为这些比率超出了本文的范围。

原载于 2020 年 1 月 22 日 https://statsandr.com**

数据科学项目的设计和结构

原文:https://towardsdatascience.com/design-and-the-structure-of-data-science-projects-c1bc5f745d17?source=collection_archive---------19-----------------------

作为数据科学家,我们必须学会处理不确定性。我们可以借用其他学科的技术来帮助我们做到这一点。

信不信由你,这些不是设计师的首选工具。

与和你完全不同的人一起工作会是一次非常有益的经历。如果你幸运的话,你最终会改变对世界的看法,并因此成为一个更好的人。对我来说,这种改变发生在第一次与 设计师 合作的时候。

“设计师”,我听到你语无伦次!“他们对数据科学项目了解多少?他们不就是给东西上色吗?”

部分原因是,当他们大三刚开始的时候。然而,好的人会设法把他们的蜡笔留在线内【1】。在这一点上,他们被提升为高级设计师,必须做一大堆我们称之为 真正的设计 的东西。我认为这种 真实设计 的过程在数据科学项目中非常有用。

我保证,过一会儿我会回到这个设计过程。然而,独立于实现它们的人的流程是我最讨厌的事情之一。对不起 Scrum/敏捷/prince 2/看板的人。首先,让我们思考一下这种心态,它来自哪里,以及它与科学家和工程师通常接受的培训方式有何不同。

设计思维的根源

“一个物体是由其性质定义的。为了使它正常工作,我们必须首先研究它的性质。为了使它完美地服务于其目的,它必须以实际的方式履行其职能。” 瓦尔特·格罗皮乌斯,包豪斯的创始人

包豪斯思维无处不在。

包豪斯是现代设计的发源地,在德国蓬勃发展,直到邪恶的纳粹将其关闭。历史上积累的垃圾将被扔掉,物品将按照其本质核心进行制作。还记得米开朗基罗对教皇说,为了创作他的雕塑杰作,“他只是移走了所有不是大卫的东西”吗?这是第一次艺术感受被应用到日常生活中。从这里开始的智力思维延伸到了 iPhone 的设计。【2】

我们已经可以看到我所说的不同的思考方式。作为科学家或工程师,我们被训练来提供解决方案。通常在计划中,我们会抓住一个问题并立即开始解决它。但是考虑一下格罗皮乌斯的引用。设计师要做的第一件事就是理解这个东西的功能和目的。他们最终会找出问题所在,然后才知道如何解决。

现在,您参与过多少数据科学项目,因为解决了一个并不符合客户需求的问题而放弃了大量工作?有办法避免这种情况吗?在这之前,我们必须离开关于“事物本质”的神秘陈述,转而…

实用主义在美国

在 30 年代,设计运动跨越了大西洋——那是在美国建墙之前的日子。瓦尔特·格罗皮乌斯最终成为了哈佛大学的教授。一个新的包豪斯在芝加哥开张了。

在美国,围绕设计的思考变得不那么神秘了,设计师们开始制作对我们其他人有用的工具包。像“设计科学”这样的短语开始被使用。斯坦福大学的 D-School 成立了,他们围绕自己创造的设计流程,推出了一家咨询公司 IDEO。我发现这个过程在数据科学项目中非常有用。设计师们非常习惯走进一个定义不清的项目,拼命想弄清楚这些人到底想要什么,然后想出一些让他们的客户满意的方法。

听起来熟悉吗?“就给我数据科学。它必须有效,其他所有人都在这么做……”

数据科学和设计过程

我在设计师的工具箱里找到的最有用的东西,是英国设计委员会称之为双钻石的东西。据我所知,这似乎与斯坦福大学 D-School 的设计过程密切相关。

图片来自英国设计协会

时间在左右轴上。上下轴,即钻石的高度,应该代表你对这个项目的确定性。因此,当你从左向右移动时(即随着时间的推移),你会逐渐变得不确定,然后变得更确定,然后变得不确定,最后在项目结束时又变得确定。运气好的话。

基本思想是,在第一个菱形中,你要找出问题,在第二个菱形中,你要找出答案。即使在这个高层次上,我们也能看到设计师的训练方式和我作为科学家的训练方式之间的差异。首先,不确定性被认为是这个过程中不可避免和令人满意的一部分!乏味的中年男人——我可以这么说,我就是一个——对事情发表意见是坚决不鼓励的。其次,我们的科学训练是这样的,“这里有一个假设,现在做所有这些详细而仔细的工作,最好是用复杂而巧妙的方法,并找出假设是否正确”。大部分时间都花在了细致和仔细的工作上,因为这是理性和聪明的。假设本身被认为是凭空变出来的,好像我们都为灵感过程的不合理性感到尴尬。另一方面,设计师已经仔细考虑了这个过程,虽然灵感不能保证,但你可以积累对你有利的机会。

记住这一点,让我们来看看这个过程的四个阶段。

1。发现

凭借在工业界和学术界 20 年的数据科学经验,我可以有把握地说,对于一个被培养成科学家的人来说,这是最令人沮丧的阶段。然而,这也是最必要的,尤其是在处理许多不同的利益时。每个人,我是说每个人,都会对这个项目有看法。这一阶段的想法是梳理出问题的统一“本质”——还记得包豪斯吗?你将会参加很多会议。很多人都会议论纷纷。如果你是某种类型的人,你可能会对人们不同的方向感到不知所措和困惑。如果你是另一种人,你可能会觉得其他人都是白痴,应该马上停止说话。如果你是第一种人,那就不用担心。如果你是第二个,那么冷静下来。记住这是钻石的加宽阶段。我们在这里是为了得到关于问题是什么的许多观点,而那些观点将会是矛盾的和不完整的,因为,嗯…人类。

2。定义

但是你不能永远困惑下去。在这个过程中的某个时刻,应该开始形成一系列的想法。你应该能够看到一些你可以做的有用的事情。关于这一点,你应该开始感到兴奋,因为你开始看到(a)这些人想从你这里得到什么,以及(b)你可以帮助他们的所有很酷的数据科学。这太棒了。请记住,回到您的最终用户身边,检查您认为他们真正想要的是什么。如果你正确地完成了第一步,应该没问题。对吗?

3。开发

没错。现在你已经弄清楚了你应该做什么,是时候开始着手做了。厉害!在这一点上,你可能会感觉如释重负。然而,你也会撞向现实。你先试的方法行不通。会有你没有想到的外在因素。数据会被弄乱(总是这样)。你可能开始认为这个白痴可能不是阶段 1 中的任何人。那个白痴可能住得离家*一点。幸运的是,这是你的训练和经验发挥作用的地方。相信我,你会没事的。

4。交付

嗬哼。这一期限即将到来。如果运气好的话,一些清晰的东西将会形成,并且你已经解决了这个问题——至少在某种程度上你的解决方案足够好。你可能只是希望这一切早点发生。你可能也有一个满脑子想做的很酷的事情。小心点。这是个陷阱。先找出可行的解决方案。

这就是英国设计委员会的四个阶段。作为一名数据科学家,我会增加第五个。

5。展开

现在只需“直播”您的解决方案。

哈哈哈哈哈哈哈。

在地球上,你的解决方案可能是一堆 SQL、python 脚本和 Jupyter 笔记本,用信念粘在一起。现在,你需要努力将所有这些变成类似专业产品的东西。在这个阶段,你现在会 100%确定地意识到那个白痴实际上就是你,你会乞求这一切结束。我打赌你现在希望使用源代码控制,嗯?

我对此有点厚脸皮的原因是,“部署”是一个至少和其他阶段加起来一样长和复杂的阶段。制作一个真正的实时系统包括代码和科学的同行评审,测试,集成,更多的测试,部署,甚至更多的测试,监控以及模型本身的持续改进。这不是一件小事,我们将在晚些时候回到这个主题。

这就是设计过程:找出问题,然后找出解决方案。如你所知,我真的很喜欢和设计师一起工作。当然,这可能会有些过头。以设计为导向的思维很容易变成只有设计师的思维,其他人只是执行一个自称为“创意的想法。呕吐。设计师有他们自己的一套偏见,所以你最终只能得到一个漂亮但成本低,几乎不起作用的原型,不可能投入生产。

但是你怎么看?认识这些阶段吗?你的应对策略是什么?请在评论中告诉我们!

脚注

【1】明确一点,对于我亲爱的做设计师的朋友们,这是一个笑话。我也见过你们用钢笔。**

【2】https://www . Smithsonian mag . com/arts-culture/how-Steve-jobs-love-of-simplicity-fueled-a-design-revolution-23868877/

【3】参见例如:司马贺的《人工科学》

为我的家乡州创建 COVID 仪表板的设计决策

原文:https://towardsdatascience.com/design-decisions-in-creating-a-covid-dashboard-for-my-home-state-545a24238952?source=collection_archive---------71-----------------------

最*,我利用业余时间为我的家乡澳大利亚新南威尔士州开发了一个新冠肺炎仪表板。这样做的主要动机是因为我感兴趣的某些数据要么不可用,要么在日常粒度上不可用,要么没有以我认为有价值的方式呈现。仪表板可在此处找到:

设计仪表板是一个数据项目,也是一个设计决策。需要做出的决策包括:需要哪些指标,最终用户将如何使用该工具,如何添加适合于指标的上下文,如何在仪表板中导航或添加“流程”元素以增强用户体验。在本文中,我将在创建新冠肺炎仪表板时讨论其中的一些选择。

我应该做一个仪表板吗?

我需要做的第一个编辑决定是是否要做一个仪表板。由于对新冠肺炎知之甚少,而且许多数据来源不完整,我认为,如果使用一个检测能力不足的国家报告的数字,这项工作将是徒劳的。幸运的是,澳大利亚和新南威尔士州拥有一些世界领先的人均检测数据,因此它可以有一定程度的信心说,它正在识别社区内的绝大多数 Covid 病例。

事实上,全国领先的传染病研究中心之一在他们的研究中表明,大多数有症状的病例都有可能被检测出来,其中新南威尔士州在检测覆盖面方面表现尤为突出。(https://www . Doherty . edu . au/uploads/content _ doc/Estimating _ changes _ in _ the _ transmission _ of _ 新冠肺炎 _April14-public-release.pdf )

鉴于这种强有力的测试立场,以及对州当局捕获和报告的数据点在识别病例的能力方面可能是全面的高度信心,我认为,由于数据的潜在准确性和完整性,制作仪表板是可行的。此外,我决定只关注新南威尔士州(澳大利亚人口最多的州,也是我居住的州)。原因很简单,各州的数据各不相同(https://the conversation . com/how-much-have-much-much-much-much-much-much-much-much-u-we-keep-better-records-we-don-know-136252)为了 Covid 的目的,澳大利亚的 6 个州可以被视为独立的民族国家,因为它们的地理位置(和面积)以及在州一级政策实施方面的差异。

我应该使用什么工具来构建控制面板?

基本上,我把范围缩小到了 3 个比较有名的可视化工具,它们要么是免费的,要么有一个免费增值服务选项来满足我的目的:Tableau、微软的 Power BI (PBI)和谷歌数据工作室(GDS)。我还对专门针对数据新闻的工具做了一些研究,比如 fluore 和 DataWrapper。然而,尽管它们显示了很大的潜力,我还是决定在未来的项目中使用它们,因为我是一个新手,可能会面临更陡峭的学习曲线,这会消耗我的执行时间。

三名候选人各有弱点。虽然我喜欢使用 PBI 进行快速和肮脏的分析,它有一些最好的开箱即用的可视化以及最强大的开发者附加软件生态系统,但我并不热衷于他们用于公开共享工作的云*台。另一方面,GDS 在实际获取该工具所需的数据量方面存在限制,因为他们更喜欢用户使用 google sheets,google sheet 随后在表格尺寸方面存在限制,并且与其他两种工具相比,缺乏其他服务的数据连接器。

这让我有了 Tableau,我很高兴使用它,因为我对这个软件最有经验,我知道我设想的报告应该包含的内容(见下文)在 Tableau 中很容易执行,不需要太多的修改或代码繁重的工作区。在 Tableau 中,我需要做的最复杂的事情是一个大约 15 行的 case 语句,用于按州按年龄组对人口细分进行编码。在一个理想的世界里,我可能会选择 GDS,因为我觉得它在风格上是最强的,特别是当谈到他们的发布*台和分享工作的能力时,然而 Tableau Public 虽然不太引人注目,但却有强大的产品和大量的观众,以及允许我及时执行的所有必要功能。

报告应该包括什么

下一个问题是仪表板中应该包括哪些措施。在项目开始的时候,我对我想看的东西有一个很好的看法。这在一定程度上是因为我做仪表板的动机是因为我很难找到定期发布的信息,如同期病例增长率,或检测阳性百分比,或者如果它们被发布,信息在每天的粒度上是不可用的(医院/ ICU 入院的情况)。

除了我希望看到的措施之外,我还希望报告保留一些关于 Covid 管理的关键领域的结构(或者至少是具有可靠的公开可用数据的关键领域——联系人追踪除外),如测试、社交距离实践等。这就产生了最初设计的想法,为每个领域(以及案例和“主页”)设计一个工作表,以便用户可以在工作簿中简单地导航,找到他们需要的信息。这些部分可以在我创建的导航“功能区”中找到,每个部分都指向这些特定指标的指定控制面板。

一旦我对类别有了清晰的认识,接下来的问题就是找到合适的度量来跟踪,以及这些度量的可视化。这些决定中的大部分是由获得这些信息所获得的效用以及它们与市场上其他可视化的区别所驱动的。这使我能够确定一些主要的与众不同的特征,包括:

a)通过使用从州卫生当局的每日媒体发布中收集的公开可用信息,绘制住院人数、ICU 住院人数和使用呼吸机的患者人数的图表,实现“拉*曲线”可视化。然后,根据已知和假设的容量进行映射(假设来源于建议澳大利亚政府响应的主要建模者,他们在规划资源时使用 50%的床位专用于非 covid 患者假设)。

b)我在图表上覆盖了新南威尔士州的人口分布,这些图表用于跟踪按年龄段划分的病例(和测试)分布,以便快速识别代表过多/不足的人口。这解决了不断回顾和查看人口普查数据的需要,以了解年龄分层的传播是如何在社区内表现出来的。

c)我使用运动图来显示当地政府区域随时间的传播情况,以便于显示疫情和“热点”。数据也按传播源进行了删减,以表明相对于从海外司法管辖区传入的传播,有多少是在社区内发生的(新南威尔士州和全澳大利亚的大多数病例都是如此)。

d)最后,我覆盖了最*发布的 IOS 数据,这些数据显示了苹果地图用户选择使用案例后移动数据的变化。查看同一 IOS 数据集按星期几的移动性变化,加上不同时间段的变化,以及所提供的三类变量(步行、驾驶和交通)的行为差异

苹果 IOS 数据强调移动性的变化和社交距离措施的地面流动效应

我还花了一些时间反复思考报告中不应该包含的特性,或者因为无法扩展而不实用的特性。例如,这导致决定按地理位置绘制病例爆发的热图,而不是像著名的约翰·霍普斯金仪表板那样的气泡图,因为这将更有效地扩展。尽管 JH 的仪表盘上会有大量难以辨认的相互重叠的圆圈,但热图可以使用彩色阴影来显示每个邮编案件数量之间的相对差异。这种可视化比气泡图更有效,如果案例数是 500 或 5000,也同样有用。

使用仪表板使我能够遵循我感兴趣的指标,并以可消费的方式组织公开可用的数据。一旦 Covid 通过,我希望做更多的工作,并为其他健康指标重新调整该模板。Covid 疫情带来的对数据的兴趣可以转化为对更多仪表板的需求,将数据融入背景并提供给乐于接受和感兴趣的公众,仪表板是数据重要性和可见性持续增长的最明显表现。

在这里可以找到【https://datandi.com/projects】并每日更新

有用的资源

我发现并参考的其他有用的可视化报告工具包括:

https://www.covid19data.com.au/

每日联邦政府仪表板https://www . health . Gov . au/resources/publications/coronavirus-新冠肺炎一览

流行病计算器:【https://gabgoh.github.io/COVID/index.html (哇,这个做得很好,向开发者致敬!)

《悉尼先驱晨报》最*公布的数据 viz 工具https://www . smh . com . au/national/新冠肺炎-data-centre-coronavirus-by-the-numbers-2020 04 01-p54g 4 w . html

实验基础的设计:如果你建造了它们,它们就会出现

原文:https://towardsdatascience.com/design-of-experiment-basics-if-you-build-them-they-will-come-cc6a227a0543?source=collection_archive---------22-----------------------

入门

用 Python 蒙特卡罗模拟从基本概率论解释实验概念的设计

作者图片

网上已经有成千上万的来源解释 p 值和与统计显著性检验相关的概念。为什么要再写一个?我一次又一次地看到统计测试被用作获取 p 值和应用“黄金法则”的“黑箱”:如果 p 值小于 0.05,那么结果是显著的。通常,这是盲目进行的,没有真正理解 p 值实际显示了什么,没有显示什么,以及如何正确设计和解释实验。我写这篇文章的目的不是提供一个解决具体问题的方法,而是描述与假设检验相关的基本概念以及我们如何得到它们。

我相信,任何概念只有在以下情况下才能被学习和理解:(1)这些概念与我们已经非常熟悉和非常了解的其他概念有着直观的联系(2)当我们在实践中尝试这些新概念时。

在这篇博文中,我将只使用基本的概率论来回顾统计显著性测试和实验设计的主要原则。我们将不使用任何统计测试,相反,我们将从概率基础一步一步地建立一个统计显著性测试过程:从基础到概念,如统计测试、p 值、显著性水*、最小可检测效应、I/II 型错误、测试的功效和实验基础的设计。

为了说明实践中的所有概念,我将在整篇文章中使用抛硬币的例子,并将蒙特卡洛模拟应用于一个问题:如何测试硬币是公*的还是有偏见的?这是顶级科技公司在面试中经常问的一个著名问题。它也足够出名,甚至有自己的维基百科页面。抛硬币实验和二项分布是任何人都明白的安全起点。让我们开始吧。

简单硬币示例和 p 值

假设我们有一枚硬币,正面概率 P(正面)= 0.5。假设我们翻转 20 次,得到 13 个正面和 7 个反面。我们应该断定硬币是有重量的还是有偏差的?有没有一种方法可以估计这种结果发生的可能性有多大?为了解决上面的问题,我们需要计算我们的结果的概率,即观察 20 次投掷中的 13 次正面。它由二项式分布给出(等式。1,也是我们在这篇文章中需要用到的唯一等式):

等式 1。在中观察头数 H 的概率 n 在次独立试验中,给定头数 P(头数)= p 的概率。

将这些数字代入等式,我们可以计算出我们观察到的结果的概率为Bin(H=13n toses= 20, p = 0.5) = 0.074。仅仅是结果的概率不足以评估我们的结果有多不可能。例如,从 52 副牌中抽取任意一张特定随机牌的概率约为 0.019,但所有可能的结果都是同样可能的。除非我们考虑所有可能的结果及其相应的概率,否则我们无法回答某一特定观察的可能性有多大。

计算特定观察结果不太可能的一种方法是计算看到任何同样可能或不太可能的结果的总概率。回到我们的硬币例子,我们需要计算 20 次抛硬币的所有可能结果的概率(图 1)。接下来,我们计算获得相同或不太可能的结果的几率(图 1 中概率分布的红色区域),得出 0.19:

图一。假设硬币是公*的,P(正面)= 0.5,20 次抛硬币的所有可能结果的概率分布。函数由等式表示。1 带参数 Bin ( Hn toses= 20, p = 0.5)。红色区域对应于观察到同等或不太可能结果的总概率,称为 p 值。

我们刚刚计算的值叫做 p 值。更正式的定义:给定一个观察值(在我们的例子中是掷硬币系列的结果),以及一个关于系统属性的基本假设(也称为零假设,在我们的例子中我们假设硬币是公*的),p 值是看到相同或不太可能的观察值的总概率。例如,在一副牌的例子中,观察任何特定牌的 p 值是 1,假设该副牌被洗牌。

我们总结一下。仅使用基本的概率理论,我们刚刚推导出一个硬币的统计测试。这基本上是所有统计测试所做的事情:给定关于系统的观察和基本假设(假设没有影响),提供 p 值——获得与实际观察到的结果同样可能或更不可能的结果的概率。

显著性水*,I 类误差

既然我们知道 p 值是什么,并且我们已经推导出硬币公*性的统计测试,让我们做一个计算实验。让我们想象一下,我们有 1000 枚公*硬币,我们将每枚硬币抛 1000 次。在完成一系列硬币投掷后,我们将使用上述方法计算每枚硬币的 p 值。接下来,我们将所有 1000 个获得的 p 值绘制成直方图:

图二。1000 枚金币的 p 值分布。计算出的 p 值形成均匀分布(在我们的硬币示例中,连续值完全均匀,接*均匀)。

从直方图中可以看出,当零假设为真时(所有测试的 1000 枚硬币实际上都是公*的),实验的 p 值本质上是一个随机变量,它描述了观察结果的不相似性。在上面的例子中,当硬币是公*的 p 值导致接*均匀分布。

假设将来我们想测试一个未知硬币是否公*。我们可以为 p 值选择一个阈值,低于这个阈值,我们将拒绝硬币是公*的假设。但这样的阈值也有一个权衡:由于公*硬币的 p 值是均匀分布的,选择 0.05 作为阈值将导致 5%的机会得出公*硬币有偏差的结论(图 2,红色区域)。在我们有 1000 枚公*硬币的模拟示例中,我们会错误地得出 56 枚硬币有偏差的结论(大约占测试硬币总数的 5%)。

p 值的选定阈值称为显著性水*,通常表示为𝛂.现在应该清楚的是,𝛂对应于我们错误地拒绝零假设的频率,并得出结论,当我们获得的观察结果实际上是由于随机机会时,我们有影响。这种类型的误差称为I 型误差

最小可检测效应(MDE)和 II 型误差

现在让我们考虑一个问题,我们有一袋硬币,但我们不知道哪些硬币是公*的 P(人头)= 0.5 或有偏见的 P(人头)≠ 0.5。我们如何从统计学的角度来处理这个问题呢?让我们设计一个实验来测试硬币的公*性。

首先,我们需要定义什么是有偏见的硬币。我们需要设置一个阈值,来衡量我们认为硬币有偏差的概率应该与 0.5 有多大的不同。为了便于说明,假设我们只考虑 P(正面)> 0.6 或 P(正面)< 0.4, in other words, if the heads probability differs from the fair coin by 20% or more (this value is called 最小可检测效应MDE 的硬币有偏差。为了测试硬币,让我们将每枚硬币投掷 Ntosses = 100 次,并数出总数。我们可以在 20%的选定最小可检测水*下,为公*硬币和有偏差硬币绘制 100 次投掷中正面总数的预期分布图(图 3)。请注意,有两个铃铛,因为一个有偏向的硬币可以有两种偏向。

图 3。公*硬币(顶部)和有偏差硬币(底部)的 100 次投掷中正面总数的概率分布。红色填充区域对应于 I 类错误率;蓝色填充区域对应于第二类错误率。

接下来我们需要选择一个显著性水*,𝛂——称一枚公*的硬币有偏见的可接受几率是多少?为了说明的目的,在这个例子中,我们将𝛂 =0.1。现在,我们有了足够的信息来确定我们需要获得的 100 次投掷中正面总数的范围,以得出硬币是公*的结论,或者拒绝硬币是公*的无效假设并得出硬币是有偏差的结论。公*硬币概率分布的这些边界之外的区域应该等于 0.1(图 3,顶部图形的红色区域),这给出了一个范围42,58。如果投掷 100 次后,硬币的正面少于 42 或多于 58(换句话说,p 值小于𝛂),我们将拒绝零假设,并得出硬币有偏差的结论。

很简单吧?然而,我们能用这种方法正确识别所有真正有偏差的硬币吗?一枚有偏向的硬币经过 100 次试验后,最终正面总数在 42 到 58 之间的几率有多大?要回答这个问题,我们需要看看有偏差硬币的预期概率分布(图 3,下图)。42 和 58 之间的蓝色区域是 0.38,这意味着在 38%的情况下,一枚有偏见的硬币实际上会被称为公*的。这被称为第二类误差,其概率通常被表示为𝛃.让我们用一个实际的模拟来说明所有这些概念。

实验的功效,错误发现率

让我们从一袋 1000 枚硬币开始,其中 500 枚硬币是公*的,500 枚硬币是有偏差的(最低可检测水*为 20%)。假设我们不知道哪些硬币是公*的和有偏见的,我们想执行我们的统计测试来找出它。为了测试,现在让我们将每个硬币投掷 100 次,计算 p 值,将其与我们选择的显著性水*𝛂 = 0.1 进行比较,并决定该硬币是否有偏差。这种实验的结果如图 4 所示。

图 4。1000 枚硬币公*性测试的随机模拟结果。每枚硬币被翻转n 次 = 100 次,将获得的 p 值与显著性水*𝛂 = 0.1 进行比较,以得出硬币是有偏差还是公*的结论。

只有在 62%的情况下(1- 𝛃),我们能够正确地得出结论,一个真正有偏见的硬币是有偏见的。这个值称为测试的功率。我们还可以注意到,在所有 310 + 56 = 366 个识别出的有偏见的硬币中,只有 310 个实际上是有偏见的,56 个实际上是公*的硬币。不正确发现的有偏向硬币的数量与总发现的有偏向硬币的数量之比称为错误发现率,在上面的例子中是 15%。如图 5 所示,如果我们获得更多的数据,我们可以提高测试的功效。

图 5。投掷硬币的次数如何影响统计测试的功效。在每种情况下,选择最小可检测效应 MDE = 10%,显著性水*为𝛂 =0.05。

非常重要的是要明白,得到统计上无关紧要的结果并不意味着我们没有效果,或者换句话说,它没有证明我们的零假设。我们的测试可能只是低功率和数据不足以拒绝零假设。

在 A/B 测试中经常看到的另一个常见错误是运行实验,直到 p 值变得低于显著性水*,而不是等待预先确定的观察次数(除非你知道你在做什么,并执行顺序或贝叶斯测试)。这种“随走随看”的方法极大地增加了 I 型错误率以及错误发现率。为了说明这一点,我们可以重复图 4 中的计算实验,其中我们需要测试 1000 枚硬币的偏差,但这次我们将检查“我们进行的”显著性,在每次翻转后计算 p 值。如果满足两个条件中的一个,我们就停止实验:p 值小于𝛂(并断定硬币有偏差)或达到最大翻转次数n 次数(断定硬币是公*的)。图 6(红色数据)显示了 I 型错误率和错误发现率与t 损失的函数关系。

图 6。与图 4 中的实验相同,但 p 值是在“进行中”计算的(红色数据)。选择显著性水*𝛂 = 0.1。

如果仅在收集预定数量的观察值后进行测试,I 型错误率保持不变,并且接*选定的显著性水*𝛂,与观察值长度无关(图 6,蓝线)。当我们“在进行中”计算 p 值时,这是非常不同的,当我们继续观察时,I 型错误率急剧增加。这个模拟演示了在 A/B 测试过程中得出结论时常见的陷阱。

汇总在一起进行统计实验设计

在实践中,我们经常从定义期望的显著性水*𝛂、最小可检测效应和功效(对我们来说不遗漏效应是多么重要)开始。例如,在 A/B 测试的设计过程中,每个实验通常从以下问题开始:

1)我们希望能够可靠地检测到的影响有多小(这将给我们最小的可检测影响)?

2)我们在生产中实施实际上没有效果的变更的可能性有多大?这是显著性水*𝛂或 I 型错误率。

3)我们检测不到实际有用的变化的可能性有多大?这给了我们第二类错误率𝛃.

图 7。对于任何假设检验实验,图上的四个值总是相互关联的。这意味着,对于一个给定的测试和关于被测系统的基本假设(零假设),如果给定四个值中的任何三个值,您总是可以计算出第四个值。

有了这三个值,我们就可以计算测试所需的观察次数(图 7)。非常重要的是,我们需要在停止实验和做出结论之前收集所有需要的观察结果,否则我们可能会增加错误发现率(图 6)。或者,我们可以使用收集的数据(已知的观察值)、固定的显著性水*和功效,来计算在我们选定的功效下我们可以检测到的最小真实效应大小。任何统计检验的一个重要的普遍概念是,如果我们知道四个值中的三个:显著性水*、功效、观察次数和最小可检测效应,我们就可以计算第四个值。

结论

最后,我想再次强调,这篇文章不是任何特定统计测试或实际应用的秘诀。我的目标是描述与假设检验相关的基本概念,以及我们如何得到它们。本质上,这是我自学假设检验的方法。理解了基本原理之后,你可以阅读许多实用的指南,但是要有概念背后的直觉,而不是把它们当作“黑箱”。记住:

"如果你需要统计数据来证明什么,那很可能不是真的."

(引自 wpi.edu)。

链接 Github

【领英:https://www.linkedin.com/in/anatoly-zaytsev/

推特:https://twitter.com/zaytsev_anatoly

设计优化:结合进化算法和张拉整体

原文:https://towardsdatascience.com/design-optimization-combining-evolutionary-algorithms-and-tensegrity-e7ec0ac5e7fb?source=collection_archive---------27-----------------------

图片编辑自 Steve Collis 的照片 Kurilpa 桥。

实践教程

如何使用 Python 和物理引擎来寻找张拉整体结构的最佳设计

一切都始于几周前,当时我无意中发现了一个张拉整体表格的视频。一个看似不可能的结构,却完全真实可行。

图片由作者提供。

在这里,结构的中央绳索支撑着所有的重量,而侧面的绳索作为悬挂绳索提供*衡。

这种原理被称为tense integrity或 tensional integrity,基于张力和压缩的组合来产生机械稳定性。

图片由作者提供。

这个术语是由巴克明斯特·富勒在 20 世纪 60 年代创造的,这个概念经常被应用在艺术装置中,但偶尔也会出现在建筑中。一个值得注意的例子是澳大利亚布里斯班的 Kurilpa 桥。

我很惊讶,并决定尝试建立一个自己的小张拉整体表。

当我开始思考创作过程时,我心中的工程师开始提出这样的问题:

  • 可以使用的最小电缆数量是多少?
  • 提高稳定性的最佳比例是多少?
  • 我如何对不同的配置进行基准测试并找到最佳配置?

和往常一样,Python 是我寻找所有这些答案所需要的工具。然而,由于没有专门用来模拟张拉整体结构的库,我不得不从头开始。

我搜索了允许在 Python 中执行物理模拟的库,并选择了 PyChrono,这是一个可以模拟几乎任何东西的物理引擎库。

机电系统、有限元分析和流体固体相互作用只是可以用这个库建模的一些事情。

在 PyChrono 中构建张拉整体表

第一步是使用 PyChrono 构建一个 tensegrity 表,从现在开始我称它为 tensortable。为了简单起见,我选择了一个长方体结构,将*行六面体连接在一起来构建刚性组件。

添加电缆有点困难,需要 pychrono.fea 模块。该模块使用有限元分析来模拟柔性部件,如电缆、电线、轮胎、气囊甚至生物力学组织。

构建过程:每个组件必须按程序设计,指定位置和尺寸(图片由作者提供)。

tensortable 是以编程方式实现的。给定一些输入参数,一个函数生成每个块的位置和尺寸。这在以后会非常方便,因为它允许轻松地部署不同的配置。

可以配置的参数有:

  • x_basez_base :基座*行六面体的宽度和深度。
  • x_topz_top :顶部*行六面体的宽度和深度。
  • y_pole :垂直杆的高度。
  • x_beam :立柱后水*横梁的长度(第二根横梁为 x_base 和 x_beam 之差)

tensortable 的不同配置(图片由作者提供)。

创建稳定性测试

唯一缺少的是评估这些十种分类的稳定性的方法。在模拟中加入地震是一种简单而有趣的方法。

PyChrono 的一场地震和一些立方体(图片由作者提供)。

一个简单的地震可以用作用在地板上的正弦函数来模拟。这个正弦函数的参数是:

  • 频率:我们每秒钟有多少次振荡。
  • 振幅:振荡的振幅。
  • 方向:x 轴、z 轴或两者的组合。

我们将使用这些参数来调整地震的强度。

测试不同的配置

到目前为止,已经有可能意识到物理引擎正在正确地工作。

图片由作者提供。

如果没有施加力,只有三根缆索的张力腿*台能够站立,但是一旦有小的摆动,*衡就失去了。

图片由作者提供。

相反,有了五根电缆,即使施加外力,它也能够站立。

寻找最佳设计

此时,我本可以手动模拟十几种配置,找出最佳配置,然后就此收工。但是由于模拟器运行良好,我决定更进一步,创建一个搜索算法,它可以以智能和自主的方式找到最佳配置。

这似乎是使用进化算法将十种物品进化到最佳形状的绝佳时机。

进化算法简介

进化算法是一类受生物进化启发的优化算法。正如在物种的生物进化中一样,像选择、繁殖和突变这样的概念是这些算法的基石。

这个想法非常直观:十个可排序的群体将被测试稳定性,最好的将存活下来并被用作新世代的父母,然后这个过程被迭代。

进化过程图:只有最优秀的个体才会把自己的特征传递给下一代。在进化算法中,并不强制父母双方都要生育后代。

实际上,进化算法的步骤如下:

  • 随机化: 我们从第 1 代开始进化过程,这是一个由 100 个随机的十个可排序的群体。
  • 体能评估:
    我们对人群进行体能测试,这个测试将评估每个个体的好坏。在这种情况下,测试将经受住一系列逐渐增强的地震。每个十个可排序表保持稳定的时间越长,其适合度得分就越高。
    首先,我们计算上半部分的实际位置和目标位置之间的偏差(在完全*衡的情况下,目标位置应该在哪里)。那么稳定性分数可以定义为:

  • 选择:
    只有最优秀的十种被选择出来,把它们的特性传给后代。十个可排序的项目按体能分数排序,100 个中最好的 10 个被选中。这些个体会自动延续到下一代,除此之外,它们还会被用来产生后代。

  • 突变和重组 :
    突变和重组用于使种群向更好的配置进化。突变在于对双亲的参数应用一个变量。重组指将两个或两个以上亲本的参数组合起来,生成新的亲本。

    在这种情况下,只使用突变就足够了:每个父代将被用于创建 9 个新的 tensortables。将高斯随机样本添加到父母的参数中,获得孩子的参数:

每次更新后,所有参数都被限制在最小值和最大值之间,从而避免负面措施。

此时该过程可以迭代,简单地重复适应度评估、选择和变异的步骤。每一代都将仅仅基于上一代中最优秀的个体,逐渐进化到更好的稳定性。

我们现在可以让程序运行并收集结果了!

结果呢

在这里,我使用了有五根电缆的模型。它已经站得很好,但我想看看什么是最佳比例。

我们可以看到进化向十个短且基数大的可排序对象收敛,这在稳定性方面是完全有意义的。

进化过程:最佳个体的得分和群体的*均值(图片由作者提供)。

收敛很快就实现了,这也是我们从这个问题的适度复杂性中所能期待的。

在这里,我们可以享受到在更强烈的地震面前,最终结构的稳定性增加,上半部分几乎不动。

图片由作者提供。

所以现在我们有了它:一种能够以自主方式找到最佳配置的算法。

最后…

我也造了一个实体的。

图片由作者提供。

一些木头,螺丝,一点耐心来校准电缆和结构是站起来的。具有讽刺意味的是,在完成所有这些工作后,我仍然选择了我脑海中的最初设计:对称的五根电缆。*衡感很好,但也很悦目。

最终,好的设计不仅仅是功能性的,还包括优雅和外观。

我相信数据科学也是如此。

我一直有意忽略数学和代码,但是如果你对技术方面感兴趣的话,不要担心,我会添加一个代码链接(只要我清理干净!).

有问题吗?随时联系!

用 Python 中的 Ax 进行设计优化

原文:https://towardsdatascience.com/design-optimization-with-ax-in-python-957b1fec776f?source=collection_archive---------10-----------------------

人类在联合优化非线性、高维函数方面很糟糕。这是事实。在机器学习的时代,计算机可以为我们做决定,有工具可以触及如此多的工程领域。在本教程中,我将重点介绍脸书的工具 Ax ,它将使用贝叶斯优化来优化用户定义的高维非线性目标。Ax,自适应实验*台,是脸书的一个开源工具,用于优化复杂的非线性实验。这真的很尖锐,让我们开始吧。

来源—作者。

数学总结

该代码使用贝叶斯优化来迭代地探索状态空间,并将高斯过程拟合到底层模型(实验)。如果你只是想看代码结构,跳过这一部分。注意— Ax 可以使用其他模型和方法,但是我只关注最适合我的问题的工具

高斯过程—建模

高斯过程(GP)是一种非线性*似工具。这是跨函数空间的回归。它所做的是获取一个特征向量(x)和一组结果 f(x ),并在两者之间拟合一个连续函数。利用这样的分布,预测是在对特征进行调节的情况下完成的。但是它的名字高斯过程是怎么来的呢?

“高斯过程是高斯概率分布的推广”——卡尔·爱德华·拉斯姆森。

公式是回归问题的概率估计。不确定性估计仍然在这里—现在函数 f(x) 被一个 GP(m(x),k(x,x'))均值 (m(x)=E[f(x)])和协方差 (k(x,x '))函数捕获。用于映射两个变量之间的协方差的函数(在高斯分布中,这只是一个数字),是它正在建模的概率分布。美妙之处在于,通过智能选择插值函数,您可以从有限采样中获得状态空间中所有潜在点的*滑*似值

推荐阅读—拉斯姆森,卡尔·爱德华。"机器学习中的高斯过程."关于机器学习的暑期学校。施普林格,柏林,海德堡,2003。

贝叶斯优化—学习

贝叶斯优化(BO)是一种优化非线性问题的工具。它会给你一组设计参数,让你在下一次迭代中尝试。

它是怎么做到的?有两个关键点:1)它迭代地训练一个 GP 模型,2)它使用一个采集函数对一组点采样的潜在增益进行建模。最常用的获取函数(抽样函数)是期望改善(EI)。

该函数基于预期比当前最佳值( x* )提高最多的参数,对下一组参数( x )进行采样。最终发生的是,EI 将在高不确定性(潜在高回报)区域的勘探与回报接*最优的微调区域之间取得*衡。 BO 将在每次迭代中训练一个新的模型,看看哪里有改进的潜力,评估模型(功能),然后重新训练。

推荐阅读——Shahriari,Bobak 等人的《把人带出循环:贝叶斯优化综述》IEEE 会议录 104.1(2015):148–175。

来自作者的 BO 的简单说明。

Python 教程

本教程基于设计一个微机电系统(MEMs)跳跃机器人,我的代码可以在这里找到。这个项目有两个方面:

  1. 根据一组约束方程优化设计——一个从第一原理导出的分析模型——可能与非线性交织在一起。在 sim.py 中找到,教程对此进行了解释。
  2. 通过拟合真实世界中发生的事情的模型来改进实验建模和设计效率。真实世界的实验数据显示在 example.py. 中,可以对其进行改进,以给出实验数据符合分析模型的概率可能性。

[## natolambert/mems-bo

微机电系统设计的贝叶斯优化。在 GitHub 上创建一个帐户,为 natolambert/mems-bo 开发做出贡献。

github.com](https://github.com/natolambert/mems-bo)

代码

现在我将介绍如何用 python 实现这种优化。请打开这个文件并跟随:https://github.com/natolambert/mems-bo/blob/master/sim.py(注意,代码可能比教程更新得更快,但核心元素仍然保留)。

属国

我的例子利用了脸书的两个工具,python ≥3.7。

  1. Ax,适应性实验*台(https://ax.dev/)。这将为我们处理所有的数学问题,优化一个复杂的函数并将结果可视化。
  2. Hydra,一个优雅地配置复杂应用的框架(https://hydra.cc/)。这将通过改变一个简单的配置文件来处理任何设计问题。

这是 python 文件头的样子——没有太多的依赖关系。

from ax import *
import numpy as np
import pandas as pd

from models import jumper

import os
import sys
import hydra
import logging

# A couple requirements for running Hydra 
sys.path.append(os.getcwd())
log = logging.getLogger(__name__)

定义优化问题

优化问题必须采取特定的形式,并且是每个新项目需要编写的唯一代码。我们需要的是一个模型,它接受一个字典的参数,并返回一个字典的度量,其中的项目是试验的*均值和标准误差度量。注意— 标准误差是可选的,只是很好地融入支持建模的不确定性估计。下面是跳跃机器人的一个例子,它设置了 3 个设计参数 w,N,L(w:弹簧宽度, N :弹簧折叠数, L :弹簧长度),它返回 3 个指标: 储能,,以及**

**def jumper(parameters):
    rho = 2300
    E = 170e9
    T = 550e-6
    lamb = 13.75
    w = parameters["w"]
    x_max = 5e-3
    N = parameters["N"]
    L = parameters["L"]

    k = 8 * (E * w ** 3 * T) / (N * L ** 3)
    x = x_max
    x_cant = x / (4 * N)
    F_required = k * x
    strain = (3 / 2) * (x_cant) * w / (L / 4) ** 2
    U_stored = 0.5 * k * x ** 2

    return {"Energy": (U_stored, 0.0),
            "Strain": (strain, 0.0),
            "Force": (F_required, 0.0)}**

程序化地生成状态空间

这是我们利用九头蛇的地方。Hydra 将为我们加载这个 config.yaml,并从命令行将其与主要的实验配置交织在一起,因此我们可以轻松地更改我们的问题、搜索空间或约束。

优化问题由三部分定义:

  1. ****状态空间:状态空间可以在变量范围、固定设计变量或离散选择变量上定义。对数比例和数据类型工具通过投影到更均匀的空间来帮助模型拟合。
  2. 约束: Ax 支持两种类型的约束——结果约束和参数约束。结果约束(如下所示)将结果限制在某个值之上或之下,在本例中,力和应变受到约束,因此物理设备可以运行而不会破碎。可添加参数约束以确保设计变量在相互关系内。**
  3. ****目标度量:度量决定了模型中要优化的目标(最大或最小)。Ax 可以处理联合优化。

这里是 jumper.yaml

**problem:
  space:
    N:
      type: range
      bounds: [1,6]
      value_type: int
      log_scale: false
    L:
      type: range
      bounds: [5e-4, 1.9e-3]
      value_type: float
      log_scale: true
    w:
      type: range
      bounds: [4.0e-5, 4.0e-4]
      value_type: float
      log_scale: false
  constraints:
    Strain:
      type: LEQ
      value: 0.5e-2
    Force:
      type: LEQ
      value: 15.0e-3
  metric:
    name: Energy
    minimize: false**

git 上有用于将配置转换成 Ax 对象的函数。Ax 的框架然后使用一个实验性的 API,该 API 将用于其余的代码——所有的优化过程都浓缩到这个对象中。

**exp = SimpleExperiment(
    name="MEMS Optimization",
    search_space=SearchSpace(search_space),
    evaluation_function=jumper,
    objective_name="Energy",
    minimize=False,
    outcome_constraints=outcome_con,
)**

优化循环

这里有两个重要的参与者:

  1. SOBOL:这是一个用于准随机搜索的搜索范例,它比纯粹的随机搜索产生更均匀的覆盖范围。
  2. GPEI:这是贝叶斯优化器的高斯过程模型,内置了预期改善获取功能。

优化循环运行一个搜索阶段,以确保模型的均匀覆盖,然后 GPEI 将快速优化模型参数到最佳值。

进行搜索。

**sobol = Models.SOBOL(exp.search_space)
num_search = cfg.bo.random
for i in range(num_search):
    exp.new_trial(generator_run=sobol.gen(1))
    exp.trials[len(exp.trials) - 1].run()**

训练一个模特。

**# data = exp.fetch_data()
gpei = Models.BOTORCH(experiment=exp, data=exp.eval())**

迭代改进。

**num_opt = cfg.bo.optimized
for i in range(num_opt):
    print(f"Running GP+EI optimization trial {i + 1}/{num_opt}...")
    # Reinitialize GP+EI model at each step with updated data.
    batch = exp.new_trial(generator_run=gpei.gen(1))
    gpei = Models.BOTORCH(experiment=exp, data=exp.eval())**

结果呢

高斯过程之上的贝叶斯优化产生了奇妙的、可解释的结果。在这里,我们将展示模型如何覆盖设计空间,以及优化器如何改进目标。

设计空间

通过一个简单的函数,Ax 可以可视化多个变量中 GP 的先验。这给了我们一个可视化设计权衡的好方法。

**plot_contour(model=gpei,
                    param_x="N",
                    param_y="w",
                    metric_name="Energy",
                    lower_is_better=cfg.metric.minimize)**

下面我们将看到的是显示不同空间的 GP 均值和协方差的图。直观地说,*均值是目标的估计值(在这种情况下是能量)。标准误差是协方差估计值——不确定性估计值,它与预期改善的抽样有关。

春季褶皱宽度与褶皱数量模型景观。左边是预测储存能量的*均值,右边是模型的不确定性。

****

左:N 对 L 模型景观。右:左对右模型景观。

曲线显示,NvL 和 LvW 空间中有非常特定的区域可以创建功能性设备。这对应于物理约束。检查模型在探索过程中如何演变并向最终景观收敛也很有用,这可以通过将相同的绘图代码添加到学习循环中来完成。

学习曲线

迭代解决问题最重要的部分是改进。如果工具除了随机抽样之外没有显示进展,那还有什么意义呢?有了 Ax,我们可以很容易地观察到学习进度随时间的变化,方法单一。

**optimization_trace_single_method(
    y=objective_means.T, ylabel=cfg.metric.name,
    model_transitions=[cfg.bo.random], trace_color=(114, 110, 180),
)**

下面是迭代与储存能量的关系图(通过机器人质量标准化以最大化跳跃高度)。垂直虚线的左边是随机 SOBOL 迭代,右边是 GPEI 迭代。很明显,系统正在学习,最终,在最优区域的预期改善如此之低,以至于回报下降(它正在探索状态空间的其他不确定区域。)

结论

希望您能看到这个工具的威力,以及将它应用于各种问题是多么容易。Ax 框架非常强大,我已经在多个项目中使用它(学习机器人控制器是 MEMs 设计的另一个方面)。

有人可能会问,为什么我们不能用当今最流行的回归工具——神经网络来做这样的迭代更新呢?答案在于*似*滑度和数据覆盖范围。GPs 的强大之处在于,该模型在测量点之间拟合出*滑的*似值,从而在标记的训练集之外给出惊人、稳定的预测。试图用神经网络来做这件事是非常危险的,因为神经网络在训练分布之外发散。这又是何时使用哪种机器学习模型的另一个例子。****

****当正确的工具应用于结构化问题时,机器学习效果最佳——而不是当任意工具被扔向任何问题时。

更多?订阅我关于机器人、人工智能和社会的时事通讯!

** [## 自动化大众化

一个关于机器人和人工智能的博客,让它们对每个人都有益,以及即将到来的自动化浪潮…

robotic.substack.com](https://robotic.substack.com/)**

机器学习培训工作流程的设计模式

原文:https://towardsdatascience.com/design-pattern-for-machine-learning-training-work-flow-1945da4d3b05?source=collection_archive---------40-----------------------

作为一名数据科学家,我做很多快速实验。在这篇文章中,我解释了如何使用高阶函数和装饰器来管理我的 Python 实验。

来自爆发莎拉·普弗卢格的照片

我相信我所有的读者都会在他们的数据集上尝试多种训练算法,以找到性能最佳的模型。我已经多次这样做了,在整个练习结束时,我的工作空间会是这样的—

经过几轮实验后,我的工作区

最终,我会忘记我在每个文件中做了什么,甚至为了记住最佳型号,我将不得不浏览每个笔记本文件来检查性能。当我邀请合作者参与这个项目时,系统变得更加复杂。我和我的合作者将有我们自己的训练代码,我们每个人都将用他们自己的代码创建一个 Python 文件/笔记本。这整个设置变成了一个令人头疼的维护问题。

我已经学会了通过实现一个叫做“策略”的设计模式来降低复杂性。我一启动项目就设置了这种模式,并提高了项目代码的可维护性和可重用性。

在阐述策略之前,我需要引入高阶函数和装饰器的概念。如果您已经了解了这一点,请跳过接下来的两个部分。

高阶函数

Python 将函数视为一级对象。这个想法很深刻,很细致。在这篇文章中,我无法公正地对待这个复杂的话题。相反,我将敦促你们所有人向那些写了多篇关于“一流”文章的大师们学习。相反,我将展示两个将函数视为一级对象的例子。

在这个例子中,我们创建了一个函数来计算阶乘,Python 解释器在0x103d6b430注册了这个函数。第一类自然允许我-

  1. 将阶乘赋值给一个名为fact的新变量,并使用该变量计算阶乘。而且,
  2. factorial作为参数传递给函数accumulate

函数accumulate是一个高阶函数,因为它将一个函数作为输入。高阶函数在数据科学(以及整个 Python)中很流行。我确信所有的数据科学家都使用过像df.apply(np.mean)这样的模式来构建他们的熊猫数据框架。np.mean是一个函数,由于apply将其作为输入,apply是一个高阶函数。

装修工

装饰器也是高阶函数,它接受另一个函数(称为装饰函数)作为参数,并返回或替换该函数。我将集中讨论一个最简单的装潢师的例子。

def decorator(func):
	'''do something'''
	return func@decorate
def my_function():
	'''Interesting code'''# The above is equivalent to - 
decorate(my_function)

装饰者利用 Python 中函数的一级性质。

战略设计模式

设计模式描述了一个具有模式的问题,然后提出了该问题的解决方案。在我的情况下,问题是在合作进行机器学习的快速实验时减少混乱。

引用维基百科-

计算机编程中,策略模式(也称为策略模式)是一种行为 软件设计模式,能够在运行时选择算法。代码不是直接实现单个算法,而是接收运行时指令,以决定使用哪一组算法。【1】

我使用的策略模式包括使用装饰器来跟踪和获取模型。实现如下图所示。

模型训练代码的脚手架

  1. 我已经初始化了一个空列表来存储我感兴趣的所有模型。
  2. 我创建了一个register装饰函数来注册我的模型。装饰器接受任何函数,并将该函数添加到列表中models
  3. 我使用@register关键字来注册我的模型
  4. 我将每个模型训练代码作为一个独立的函数来编写。但是它们都实现了标准的返回类型。在这个例子中是 F1 分数和训练模型。
  5. 现在best_model(data)获取所有注册的模型,并返回性能最好的模型。

每当我的合作者添加一个新的模型训练函数时,她都会用关键字@register来修饰这个函数,新的模型就会被集成到我的训练运行中。

这种模式允许我们以灵活和简单的方式开发 ML 模型。该模式在运行时选择最佳模型。我可以添加一个新的模型训练代码,并且可以运行模型训练功能的全部或特定子集。要移除任何函数(模型训练代码),我可以只注释掉@register装饰器。

结论

随着许多人尝试不同的技巧,协作机器学习变得复杂和混乱,您的开发环境变成了陈旧代码和笔记本文件的复杂混乱。我推荐的模式可以帮助开发人员灵活地设计新代码,并允许维护人员保持代码库的整洁。该策略在开发人员中强制执行纪律,以编写标准的可重用代码。这个策略帮助我和我的团队缩短了代码开发时间,减少了代码中的错误。

MongoDB 的设计模式

原文:https://towardsdatascience.com/design-patterns-for-mongodb-894767315905?source=collection_archive---------6-----------------------

每个全栈开发人员在构建 MongoDB 模式时需要做出的设计决策

自从计算出现以来,数据一直在增长,这对存储、处理和分析技术的需求产生了直接影响。在过去的十年中,开发人员已经从 SQL 数据库转移到 NoSQL 数据库,MongoDB 作为企业应用程序世界中的运营数据存储库,在受欢迎程度方面占据了主导地位。

如果你读过我最*的文章或者亲自了解我,你可能会意识到我是多么重视软件架构和模式。大多数人认为它们只适用于服务器端。我真的相信后端设计不应该是事后的想法,而是架构的关键部分。糟糕的设计选择明显影响了解决方案的可伸缩性和性能。

因此,今天我将向您介绍一些实用的 MongoDB 设计模式,任何全栈开发人员在使用 MEAN 均值技术集合时都应该了解这些模式:

❗️**Assumption:** Basic familiarity with MongoDB is necessary, so is some understanding of relational modelling (because we will refer to SQL as a contrasting approach).

宏伟的计划(或模式😄)的东西

通常,我们认为 MongoDB 是一个无模式数据库,但这并不完全正确!它确实有模式,但是它是动态的,也就是说,该模式不在相同集合的文档上实施,相反,它具有改变和变形的能力;这就是为什么它被称为多态模式。这意味着不同的数据集可以存储在一起,这是蓬勃发展的非结构化大数据的竞争优势。

遗传和多态性

特别是当涉及到面向对象编程(OOP)和继承时,MongoDB 的多态功能变得非常方便,因为开发人员可以将同一层次结构(父子)的不同类的实例序列化到同一集合中,然后将它们反序列化为对象。

这在关系数据库中不是很直接,因为表有固定的模式。例如,考虑一个交易系统:一个Security基类可以派生为StockEquityOption等。

在 MongoDB 中,我们可以将派生类型存储在一个名为Security的集合中,并在每个文档上添加一个鉴别器(_t),而在关系数据库中,我们有以下建模选择:

  • 包含StockEquityOption字段联合的单个表,产生一个稀疏填充的模式。
  • 三个表,分别对应StockEquityOption的具体实现,导致冗余(因为Security属性有重复的基础信息),以及检索所有类型证券的复杂查询
  • 一个表用于Security的公共内容,三个表用于StockEquityOption,它们将有一个SecurityID,并且将只包含各自的属性。这个选项解决了冗余问题,但是查询仍然会变得复杂。

如您所见,这里包含的代码比多态 MongoDb 集合中的多得多!

图式进化

生活中唯一不变的事情就是变化——这当然适用于数据库模式,当涉及到传统的关系数据库系统时,它经常会带来挑战和一些麻烦。一个表格模式的致命弱点是,对一个表的小改动会引起整个数据库的连锁反应,并且会影响到服务器端的应用程序代码。

典型的方法是停止应用程序,进行备份,运行复杂的迁移脚本以支持新模式,发布新版本的应用程序以支持新模式,然后重启应用程序。由于持续部署(CD)负责该版本的应用程序方面,需要长时间停机的最耗时任务被限制在数据库迁移上。一些在大表上执行的ALTER命令甚至需要几天才能完成…

然而,在 MongoDB 中,向后兼容性是现成的,所以开发人员在服务器端代码本身中考虑这些变化。一旦应用程序被更新以处理缺少字段的情况,我们就可以在后台迁移正在讨论的集合,同时应用程序还在运行(假设涉及不止一个节点)。当整个集合被迁移时,我们可以替换我们的应用程序代码来真正忘记旧字段。

数据库设计不是一成不变的,在遗留的表格数据库中,模式更改可能会令人烦恼(如果不是瘫痪的话),所以 MongoDB 的多态特性确实非常强大。

嵌入还是不嵌入:这是个问题!

如果你有任何 OOP 经验,你一定在你的职业生涯中遇到过 Eric Evan 的经典著作领域驱动设计,它介绍了集合模型。聚合是我们作为一个单元进行交互的数据集合,通常比传统的行/记录具有更复杂的结构,即它可以包含嵌套列表、字典或其他复合类型。

仅在单个聚合的内容中支持原子性;换句话说,聚集形成了一个 ACID 操作的边界(阅读 MongoDB 手册中的)。处理聚合间的关系比聚合内的关系更困难:连接在内核中不被直接支持,而是在应用程序代码中或者用有点复杂的聚合管道框架来管理。

本质上,在是否将相关对象嵌入另一个相关对象或者通过 ID 引用相关对象上有一个很好的*衡,并且作为建模中的大多数事情,没有关于如何做出这个决定的一站式解决方案。它在很大程度上是特定于上下文的,因为它取决于应用程序如何与数据交互。

在我们继续之前,我们需要了解嵌入的优势是什么:

🔴 The main reason for embedding documents is read performance which is connected to the very nature of the way **computer disks** are built: when looking for a particular record, they may take a while to locate it (high latency); but once they do, accessing any additional bytes happens fast (high bandwidth). So collocating related information makes sense as it can be retrieved in one go.🔴 Another aspect is that it reduces the **round trips** to the database that we had to program in order to query separate collections.

现在,让我们根据两个实体之间的关系类型,探讨一些在设计 MongoDB 模式时需要考虑的问题:

1:1

一对一关系是一种描述两个实体之间关系的基数类型,其中实体 A 中的一条记录与实体 b 中的一条记录相关联。它可以通过两种方式建模:将关系嵌入为子文档,或者链接到单独集合中的文档(没有强制外键约束,因此关系只存在于应用程序级架构中)。这完全取决于应用程序访问数据的方式、频率以及数据集的生命周期(例如,如果实体 A 被删除,实体 B 是否仍然存在?)

**Golden Rule #1:** If an object B needs to be accessed on its own  (i.e. outside the context of the parent object A) then use reference, otherwise embed.

1:N

一对多关系是指两个实体 A 和 B 之间的关系,其中一方可以有一个或多个到另一方的链接,而相反的是单边的。像 1:1 关系一样,它也可以通过利用嵌入或引用来建模。
以下是需要考虑的主要因素:

如果对象的嵌套数组将不受控制地增加,则不建议嵌入,因为:

  • 每个文档不能超过 16MB。
  • 需要为不断增长的文档分配新的空间,还需要更新索引,这会影响写入性能。

在这种情况下,引用是优选的,并且实体 A 和 B 被建模为独立的集合。然而,一个代价是我们需要执行第二次查询来获得实体 B 的细节,因此读取性能可能会受到影响。一个应用级连接来拯救我们:通过正确的索引(用于内存优化)和使用投影(用于减少网络带宽),服务器端连接比推送到 DB 引擎的连接稍微贵一些。应该很少需要$lookup操作符。如果我们需要它很多,有一个模式气味!

另一种选择是使用预聚合集合(充当 OLAP 立方体)来简化其中一些连接。

**Golden Rule # 2:** Arrays should not grow without bound.
- If there are less than a couple of hundred narrow documents on the B side, it is safe to embed them;
— If there are more than a couple of hundred documents on the B side, we don’t embed the whole document; we link them by having an array of B objectID references;
— If there are more than a few thousand documents on the B side, we use a parent-reference to the A-side in the B objects.

**Golden Rule # 3:** Application-level joins are common practice and not to be frowned upon; in these cases indexing selection makes or breaks the querying performance.

❗️Denormalisation: 使我们的文档非规范化的两个因素是:

  • 更新将不再是原子性的;
  • 高读写比(即经常被读取且很少被更新的字段是反规范化的良好候选)。

男:男

多对多关系是指两个实体 A 和 B 之间的关系,其中双方可以有一个或多个到另一方的链接。在关系数据库中,这些情况用连接表建模,然而在 MongoDB 中我们可以使用双向嵌入,所以我们查询 A 来搜索 B 对象的嵌入引用,然后用$in操作符查询 B 来找到这些返回的引用(反过来也是可能的)。反之亦然。

这里的复杂性来自于在 A 和 B 之间建立一个*衡,因为 16MB 的阈值也可能被打破。在这些情况下,建议使用单向嵌入。

推荐阅读

收场白

所有这些的结果是,MongoDB 使我们能够设计我们的模式来满足我们的应用程序的需求,这样我们就可以充分利用它们。这种灵活性非常强大,但是这种力量需要根据我们在应用程序中使用的模式来加以利用。—我们需要记住,性能问题通常是由糟糕的模式设计引起的,因此,第一次就把它做好是至关重要的。

感谢阅读!

我经常在媒体上写关于领导力、技术&的数据——如果你想阅读我未来的帖子,请‘关注’我

医疗环境中数据可视化的设计原则

原文:https://towardsdatascience.com/design-principles-for-data-visualisation-in-a-healthcare-setting-ef9bf2954a58?source=collection_archive---------37-----------------------

向更广泛的受众展示医疗保健数据时,需要以用户为中心的迭代设计

医疗保健产生了大量的数据和数据分析的潜力。在进行任何分析或比较之前,充分理解数据以及如何使用数据是很重要的。作为由健康基金会资助的数据可视化项目的一部分,东北质量观察站制定了七个设计原则。

虽然项目的重点是将*面文件格式转换成交互式工具,但我们有大量的变化;包括数据来源和输出类型。在项目过程中,我们发现起草一些指导方针来帮助工具的开发是有益的。作为项目的一部分,在简短的文献回顾和与临床医生的互动之后,这些被进一步发展以产生七个设计原则:

  1. 临床医生参与了整个过程的每一步
  2. 用正确的临床问题引导
  3. 使数据及时和相关
  4. 用户没有学习曲线
  5. 没有必要重新发明轮子
  6. 数据是灵活的和可共享的
  7. 适合这项工作的工具

设计原则 1。临床医生全程参与

最终用户(临床医生)在设计阶段的参与对于获得适合他们的交互式数据可视化(DV)工具/仪表板的功能并确保可接受性至关重要。

对于用于通知质量改进的 DV 工具/仪表板,它需要被最终用户(在这种情况下是临床医生)接受。如果用户参与设计阶段,可接受性会增加。让临床医生参与设计阶段可以探索他们或他们团队的成员将如何使用 DV 工具/仪表板,因此在功能上不基于开发团队的假设。由于相互竞争的优先事项和临床承诺,与临床医生的接触必须适应临床模式。

临床医生对数据可视化工具的要求和关键组件

这一原则是针对医疗保健项目制定的,但也适用于许多领域——最终用户应该参与设计流程的每一步,因为这将确保工具中的功能如预期的那样存在,并且工具的使用是有效的。设计一个不适合目的的工具是对资源的滥用,因此不经常使用。

设计原则 2。以正确的临床问题开始

明确最终用户的主要临床问题,并据此设计 DV 工具/仪表板。

当处理大型数据集时,有一种尝试和回答没有被问到的问题的诱惑。这可能导致数据过载,有可能导致关键信息丢失。仪表板或数据可视化工具应该“过滤噪音”,以便在所有信息中更容易找到关键的“信号”。

最终,如果必要,一个临床问题可以集中在一些后续问题上。当最终用户希望对其临床单位有一个总体了解时,他们会问一组不同的问题,而不是在浏览数据以找到关于质量不同方面的深入信息时。因此,理想情况下,家庭暴力工具/仪表板的设计应考虑到根据所提问题的不同详细程度;应该可以获得一个部门或医院如何运作的概况,以及回答对实际护理质量的不同方面的深入询问。

设计原则 3。使数据及时相关

数据应尽可能更新(并考虑排除太旧而无法回答问题的数据)。

如果数据“陈旧”,它可能会失去一些功能,变得无关紧要。关于护理质量的决定应该基于被认为有用的最新可用数据。排除基于临床医生认为太旧而无法提供有用见解的基础数据的指标可能是值得的。这是一种理想化的情况。本项目中使用的数据基于公开的国家审计。进行这些审计需要时间来收集、清理和分析数据,因此自然会有延迟。现有的最新数据可能在某种程度上已经过时。在临床设置中,可以收集实时数据,但是在这种情况下,很少有或没有机会进行数据清理或聚合,因此可能会妨碍临床单位或护理质量的比较。

设计原则 4。用户没有学习曲线

确保 DV 工具/仪表板对最终用户来说一目了然,易于使用和导航。

最终用户应该不需要很高的 IT 技能就能使用该工具或仪表盘。最终用户学习如何使用新工具的时间有限。为了最大限度地利用,这些工具及其导航需要一目了然,并且不需要 IT/计算方面的资格认证,以便能够在很短的准备时间内与数据进行交互。应该不需要传统的用户手册就能够与数据进行交互。为了帮助使用仪表板,在这个项目中,我们能够在可视化中加入详细的“如何做”部分。这些说明了该工具如何在不妨碍显示的情况下工作,并同样增强了 DV 工具/仪表板的易用性。使用浮动的“how to”也可以用来提供说明文字;解释数据显示了什么以及如何最好地解释它。

在 DV 工具中导航是直观的,这一点很重要。指标的顺序和流程应该对临床医生有意义。任何链接的目的地都应该是预期的。最终用户在设计阶段的参与应该有助于这个导航过程,给出一个用户如何接*产品的指示。重要的是,用户能够将他们的时间集中在数据和它所讲述的故事上,而不是试图浏览 DV 工具/仪表板。

设计原则 5。没有必要重新发明轮子

了解公认的视觉设计原则。在需要解释的地方加入解释性的叙述,确保你避免“忙碌”的视觉效果和信息超载。

布局和格式很重要——需要在视觉复杂性和信息实用性之间取得*衡。如果整个 DV 工具/仪表板不一致,那么用户可能会不知所措。同样,颜色需要在视觉上吸引人,适合色觉缺陷(CVD ),并且没有意想不到的含义;例如,使用红色和绿色,但不要在低俗的情况下使用。导航元素应该是一致的(相同的地方,看起来一样,清晰的标签),它们应该看起来像是相关的或者是集合的一部分。一旦在一个 viz(vizualization)上设置了功能,用户希望所有其他 viz 都具有相同的功能和感觉。

仪表板/DV 工具的开发人员应了解 PARC 原则(接*、对齐、重复和对比)和格式塔原则;不管模式存在与否,寻找模式是人的天性。如果两个项目看起来相似,就会认为它们的功能相似。当创建显示多个指标和图表的仪表板时,人的本性决定了那些靠*的将是关联的指标。

当感觉需要解释性叙述时,这需要足够有帮助并提供答案,而不会使观想过于复杂而无法提供问题的简单答案。重要的是,任何仪表板上的可视化是清晰的,而不是杂乱的不必要的文本。

设计原则 6。数据灵活且可共享

确保 DV 工具/仪表板能够提取输出内容,以纳入用户自己的报告和演示。

数据召回的概念是早期设计原则((设计原则 4)(设计原则 5) )中提到的导航的基础。DV 工具/仪表板的一个关键特性是,工具首次使用时所做的任何选择都会保留在整个产品中。这改进了导航并确保可视化被正确解释。

为了最大限度地提高交互式仪表板和最终用户的工作效率,用户应该能够设置自己对软件中保存的数据的查询。然后可以定期共享或重新运行。能够保存查询确保了在下一个时间点被询问的问题没有变化,并且这将有助于验证结果和突出任何问题(例如,作为异常值)。

重要的是,数据和数据可视化可以共享,这也提供了一种提高护理质量的方法,其中数据可以突出任何问题或加强任何积极的改进。因此,重要的是,任何产品都必须能够提取输出内容,以包含在用户自己的报告和演示中。应该可以保存单个图表,并且图表的布局有利于提取(即任何解释文本都不会与图表重叠)。然后,图表应该以允许共享的格式保存,无论是通过电子邮件还是通过将它们插入不同的文档或演示文稿。

设计原则 7。适合工作的工具

静态和交互式仪表板都很有用,因为可能仍然需要静态报告来提供护理质量的概述,并且可能需要交互式 DV 工具/仪表板来实现数据的“深度挖掘”。

交互式数据可视化工具的产生并不意味着不再需要静态产品。两种类型的报告(静态的和交互式的)都有不同的作用,这对临床医生都有好处。虽然静态报告的内容有限,因为提问的问题是预先确定的,不能更改,但它们提供的内容实际上掌握在最终用户手中。由于可能在国民医疗服务体系(NHS)内运行的过时/受限的 IT 系统,一些临床医生似乎不愿意使用在线工具,并准备为了稳定性和可靠性而牺牲 DV 工具的交互性。

所使用的互动软件还应在输出方面提供稳定性和可靠性,但也应允许对数据提出的问题进行讨论和变化。假设底层计算机硬件和网络供应,为正确的工作选择正确的工具将是有益的;静态报告提供数据和高级分析的概述,以及允许进一步调查更具体问题的交互式工具。

结论

这些设计原则是作为一个项目的一部分制定的,该项目旨在调查交互式数据可视化是否有助于临床医生改善患者护理。虽然它们旨在与家庭暴力工具和仪表板相关,但总体原则可以推广到任何报告系统。类似地,设计原则可以应用于医疗保健之外的其他领域,在这些领域中,客户的参与将有利于测量结果的工具的设计。

采用这些设计原则可能会鼓励对产品的吸收;最终用户的指导和他们在设计阶段的参与可能会使产品更具吸引力,因为它更“切合目的”。最终,这些原则应该支持和加强一个有用的产品的设计,这个产品需要很少的交付时间,并且像预期的那样运行。

人工智能项目的设计思维

原文:https://towardsdatascience.com/design-thinking-for-artificial-intelligence-projects-87c4bc920c03?source=collection_archive---------30-----------------------

Daria Nepriakhina 在 Unsplash 上拍摄的照片

IBM 如何采用设计思维原则来构建人工智能项目的工作流程

为什么要看这篇文章?

IBM 为人工智能项目使用了一个有趣的工作流程,该流程基于设计思维原则,在 Coursera 的专题中有详细展示。这是一个很长的 MOOC,它深入研究了实现人工智能应用程序的细节,如果你有时间和技术知识,这是值得一读的。如果你只对学习工作流以及如何在 AI 项目上实现感兴趣,这篇文章可以帮助你。

什么是设计思维?

设计思维是一种在开发设计概念时使用的思维类型(例如在设计新建筑或技术产品时),它试图从最终用户的角度理解产品。这不仅是通过与用户产生共鸣,也是通过在头脑风暴会议中产生多个想法、原型,然后测试这些想法。因此,这是一个迭代和实践的方法。该过程的主要阶段有:感同身受定义构思原型测试。我不会进入产品创造的设计思维的细节,而是将重点放在这个过程如何适应人工智能项目。

工作流程

IBM 为 AI 项目呈现的工作流如下,在设计思维中有相应的名称:

  • 数据收集 ( 感同身受)
  • 探索性分析 ( 定义)
  • 转化 ( 构思)
  • 造型 ( 原型)
  • 测试 ( 测试)

现在,让我们进一步了解这些步骤的细节。

数据收集

这是数据科学家与最接*数据的人交谈的地方,以阐明业务机会并将其转化为可测试的假设。它包括定义时间表、成本、可行性等。最后,您继续为项目收集数据。

  1. 尽可能接*数据的来源,通常是通过采访相关人员
  2. 识别业务问题
  3. 阐明业务问题,列举可能的问题,并根据领域知识、可行性和影响确定优先顺序(影响可以使用背面的 ROI 计算来衡量)。
  4. 获取所有相关的数据
  5. 将业务问题转化为一个或多个可测试的假设

探索性数据分析

此时,您尝试可视化您的数据,检查丢失的值(并决定如何处理它们),并可能测试假设。这部分由数据可视化假设检验组成。

在构建完整的数据摄取管道之前,从简单的 csv 文件开始分析,以确保您的模型有价值。

数据可视化

检查缺失的数据,了解哪些特征和观察值有缺失值,以及原因(返回“移情”并与客户交谈)

与其他观察值相比,看看缺失的观察值如何表现:

  • MCAR(完全随机缺失):就特征矩阵而言,缺失病例*均来说与非缺失病例相同。完整的病例分析(从数据集中移除那些观察值)将降低分析的功效,但不会影响偏倚
  • MAR(随机缺失):缺失数据通常对测量值有一定的依赖性,模型可用于帮助估算可能的数据。例如,在 MLB 的一项调查中,在回答所有问题时可能存在性别偏见
  • MNAR(非随机缺失):缺失数据依赖于未测量或未知变量。没有可用的信息来解释这一缺失。

如果需要,尝试一些不同的插补方法,但一定要在建模阶段回来重新评估它们,知道哪种方法产生的结果最好。尝试不同插补方法的过程称为多重插补。

  • 单变量插补:缺失特征的*均值或中值
  • 多变量插补:使用其他变量预测缺失特征

创建可视化摘要,详细说明数据,包括缺失值、异常值、不*衡问题分类,并尝试确定对您的特定业务问题有用的因素,并开始制定假设。

使用图表和表格创建第一个演示文稿或报告,讲述与您的业务问题相关的故事(确保所有内容至少有一两行解释主要观点/结论)。最后是结论和对后续步骤的建议。

转换

其目标是转换您的数据,使其可供模型使用。这是所有特性工程魔法发生的地方。

造型

在这一点上,您定义了一个评估标准,并针对您的问题比较了不同的模型。从简单的模型开始,然后逐步建立。

测试测试

这里的目标不仅仅是对你的代码进行单元测试,还包括对你之前所做的选择进行批评,如果需要的话再回头看(通常是这样的)。它以所选解决方案的部署而告终,这也要经过测试:即使是运行的模型也要经过审查和持续的性能测试。

如果您有兴趣了解有关数据科学项目的工作流和项目管理工具的更多信息,您可能也会喜欢这篇文章:每个数据科学家都应该知道的项目管理工作流

设计 3D 医疗保健网络图

原文:https://towardsdatascience.com/designing-a-3d-healthcare-network-graph-291e4f75e9a5?source=collection_archive---------62-----------------------

使用 TigerGraph、Python 和 JavaScript 对医疗保健数据建模的一种很酷的方式

三维力导向网络图

介绍

正如我们所知,图形数据库已经彻底改变了世界。在过去的十年里,他们已经在大量的案例中证明了他们的有用性,从社交媒体网络到欺诈检测再到推荐引擎。图形数据库的真正优势是能够有效地表示信息片段之间的关系。这尤其适用于高度关联的数据,如医院记录。

在这篇博客中,我将介绍一个例子,说明我们如何将存储在图形数据库中的医疗保健数据以 3D 形式直观地展示出来。由于大量的连接,2D 网络图可能很快变得混乱和不可读;然而,这些问题可以通过改变我们的视角来解决。在 2D 选项失败的情况下,3D 图形提供了更容易看到的数据的扩展视图。

因为数据存储在图形数据库中,所以用图形可视化才有意义。这样,我们所要做的就是将数据库中已经存在的连接转换成可见的东西。

有了这样的背景,让我们开始制作我们的 3D 图形杰作吧!

这个博客的完整代码可以在我的 Github 上找到。

设计图形数据库模式

我在这个项目中使用的图形数据库是建立在 TigerGraph 的基础上的,使用的是由一个叫做 Synthea 的整洁的开源程序生成的合成病人数据。如果你对 Synthea 不熟悉,可以看看我写的这个短博客或者看看他们的网站

如果你有兴趣看看我用来设计这个医疗网络的过程,可以看看我的 上一篇博文

否则,请随意设计您自己的图表或使用预制的图表。TigerGraph 有大量的教程和例子可以帮助你设计自己的图形。或者,你可以参考我写的一篇文章,这篇文章将带你了解一般的图形设计过程。

从这一点开始,我提到的一切都可以用任何图形来完成。

访问图表

为了访问我们的图表,我们将使用由 Parker Erickson 创建的 pyTigerGraph Python 连接器。安装并导入软件包后,您可以使用以下代码连接到您的图形服务器:

连接到 TigerGraph

如果您没有令牌,您可以创建一个带有密码的令牌。

接下来,运行一个已安装的查询来从图表中获取数据。

运行 GSQL 查询

以下是查询。它会抓取所有患者以及与这些患者直接相关的所有边和顶点。

CREATE QUERY grab_All_3d_demo() FOR GRAPH MyGraph { 

 ListAccum<EDGE> @@edgeList;

 Seed = {Patient.*}; data = SELECT s FROM Seed:s -(ANY:e)-ANY:t ACCUM @@edgeList +=e;
 other = SELECT t FROM Seed:s -(ANY:e)-ANY:t;

 print data;
 print other;
 print @@edgeList;
}

格式化数据

当我们运行查询时,它会返回大量信息。我们可以尝试绘制所有进来的数据(本质上是绘制这些患者的大多数医疗保健接触点),但我们的图表最终会看起来非常混乱。因此,我们将只获取数据的一部分。

我选择了这些病人,他们的地址,以及他们一生中的任何过敏反应或影像学研究。

解析传入数据

这段代码可能有些混乱,所以让我们仔细分析一下到底是怎么回事。

  1. 首先,提取与 GSQL 查询中的 3 个 print 语句相对应的 3 个列表。
  2. 接下来,创建两个名为节点链接的列表。这些将包含我们的三维图形的顶点和边。
  3. 现在,抓取代表患者、地址、过敏或成像研究的所有节点。对于每个节点,我们添加三个属性: id描述id 是图形用来建立连接的标识符。描述是当鼠标悬停在节点上时出现的文本,而用于给节点着色。
  4. 对于每个环节,我们也有三个属性:目标属性再次对应于着色。目标属性对应于该边的源和目标顶点的 id。
  5. 最后,将这两个列表添加到 JSON 格式的字典中。这一步非常关键,因为我们的 JavaScript 函数无法识别其他格式的数据。

这样,数据现在就可以使用了!

用 Flask 传递数据

为了让我们的 JavaScript 函数实时接收来自 Python 的图形数据,我们需要设置一个服务器。我们将使用烧瓶来完成。我们所要做的就是将我们已经创建的函数包装在 Flask web 服务器结构中。完整的 Python 代码现在看起来应该是这样的:

最终 python 代码

这个项目的 python 部分现在已经完成了!

创建图表

这个可视化的核心是 3D 力图包。这个包建立在 ThreeJS 和 WebGL 之上,使得生成力定向图变得非常简单。

像大多数 web 应用程序一样,这个网络图可视化是使用 HTML、JavaScript 和 CSS 构建的。让我们分别看一下这些组件。

超文本标记语言

这个项目的 HTML 非常简单。

网站的 HTML

关键部件:

—三维力图包

— CSS 样式表

— JavaScript 代码(dataset-loader . js)

半铸钢ˌ钢性铸铁(Cast Semi-Steel)

这里没什么特别的。

网站的 CSS 文件

Java Script 语言

生成图表的 JavaScript 代码

让我们再次将这段代码分解成更小的步骤。

  1. 使用 fetch 语句从我们的 Flask 服务器获取数据
  2. 使用 3D-Force-Graph 软件包生成我们的图形
  3. 指定图形属性(即按组着色,将悬停数据设置为“描述”)
  4. 创建一个循环,使图形旋转。为什么?因为旋转图太牛逼了!

CORS 问题

如果您试图按原样运行这段代码,很可能会遇到 CORS 错误。

CORS 误差

你可以在这里阅读关于 CORS 问题的文章。要解决这个问题,您需要指定允许数据流动的响应头。我用谷歌浏览器的 Moesif Origin 和 CORS 转换器扩展解决了这个问题。如果您在本地运行该程序,这将非常有用。然而,如果您想要部署该图,您将需要在 FlaskJavaScript 上配置适当的设置。

有趣的东西

这是所有的代码。现在,我们剩下要做的就是运行服务器,欣赏它的辉煌。

结论

通过不多的代码,我们收集了存储在图形数据库中的大量数据,并创建了一个令人惊叹的 3D 可视化来显示这些数据。我们使用 TigerGraph 来存储医疗保健信息,使用 Python 来提取和处理我们的数据,使用 JavaScript 和 HTML 来创建 3D 视图。这个过程并不复杂,但会产生非常酷的结果。这篇博客中展示的方法也可以用在医疗行业之外。任何处理高度关联数据的领域都可以从图形中受益,利用图形数据库存储信息的能力和 3D 网络图显示信息的能力。

我希望你喜欢阅读这个博客,并学到一些新的东西!让我知道你的想法,并在 LinkedIn 上与我联系。

[## 阿卡什·考尔-数据科学实习生-未来学家学院| LinkedIn

查看阿卡什·考尔在全球最大的职业社区 LinkedIn 上的个人资料。阿卡什有 5 个工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/akash-kaul-6a8063194/) [## akash-kaul/3d 网络图可视化

在 GitHub 上创建一个帐户,为 akash-kaul/3d 网络图可视化开发做出贡献。

github.com](https://github.com/akash-kaul/3d-network-graph-visualization.git)

使用 Python 设计聊天机器人:一种改进的方法

原文:https://towardsdatascience.com/designing-a-chatbot-using-python-a-modified-approach-96f09fd89c6d?source=collection_archive---------20-----------------------

亚历山大·奈特Unsplash 上拍照

机器如何解释人类语言?

在当今时代,聊天机器人已经变得非常流行。高度发达的聊天机器人,如 Siri、Cortana 和 Alexa,已经让人们对其智能和能力感到惊讶。聊天机器人实际上被定义为:

聊天机器人可以像简单的程序一样简单,用一行响应回答简单的查询,也可以像数字助理一样复杂,在收集和处理信息的过程中学习和发展,以提供越来越高的个性化水*。

在很多文章中,我看到过一个基本的评论-回复模型。我的尝试是看看我们是否可以更进一步,在更广泛的基础上修改用户评论,并可能使用简单的 web 请求、自动化和抓取为聊天机器人提供其他功能。

在我们开始之前,我想让你知道一些事情,我们在看什么。我们不会看到像 Siri 这样超级智能的聊天机器人,因为它需要丰富的经验和专业知识。现在,如果我们认为,如果我们的聊天机器人可以帮助我们预订酒店,为我们播放歌曲,告诉我们天气预报,等等,这将是非常酷的。我们将尝试在我们的聊天机器人中使用一些基本的 python web 处理库来实现所有这些功能。我们将使用 NLTK 或 Python 的自然语言工具包库。那么,我们开始吧。

聊天机器人根据其设计主要有两种类型

  1. 基于规则
  2. 自学的

我们将使用两者的组合版本。通常,在基于规则的方法中,设置了一组基本规则,聊天机器人只能以受限的方式对这些规则进行操作。对于自学版本,神经网络用于训练聊天机器人根据一些交互训练集来回复用户。对于任务部分,我们将使用基于规则的方法,对于一般的交互,我们将使用自学的方法。我发现这种结合的方法比完全自学的方法更有效。

NLTK 图书馆的工作

在进入应用程序之前,让我们看看 NLTK 是如何工作的,以及它是如何在自然语言处理中使用的。自然语言处理有 5 个主要组成部分。它们是:

  • 词法和词汇分析
  • 语法分析
  • 语义分析
  • 话语整合
  • 语用分析

词法和词法分析:词法分析描绘了对单词结构的分析、识别和描述。它包括将文本分成段落、单词和句子。

句法分析:单词通常被认为是最小的句法单位。句法是指支配任何一种语言的句子结构的原则和规则。句法关注单词的正确顺序,这可能会影响其含义。

语义分析:该组件将单词的线性序列转换成结构。它显示了单词之间的联系。语义学只关注单词、短语和句子的字面意义。

语篇整合:指对语境的感知。任何一个句子的意思取决于这些句子。它还考虑了下面这句话的含义。

语用分析:语用分析研究整体的交际和社会内容及其对口译的影响。它意味着抽象或推导出语言在各种情况下的有意义的用法。

现在,让我们来谈谈用于实现这五个组件的方法或函数:

标记化:标记化是将大量文本分割成称为标记的较小部分的过程。它接受一个句子,并将其分解成最小的可提取单元或单词。

词性标注:在自然语言处理中是非常有用的工具。我们知道,各种词类,如动词、名词、形容词等等。现在,如果能标记出一个单词属于哪个词类,我们就很容易理解句子的上下文了。

词汇化:这个操作是 NLP 的另一个非常有用的工具。使用这种操作,具有相同含义但根据上下文或句子有一些变化的单词被带到它们的词根。这对模式匹配和基于规则的方法非常重要。

所有这些工具都是由 python 的 NLTK 库提供的。现在,让我们来看看自学习算法是如何工作的。

自学习算法的工作原理

我们使用单词包算法来训练我们的模型。我们有一个包含所有意图和输入模式的文件。看起来像是:

我们可以看到,这里有一个“标记”字段,它实际上描述了意图。意图通常是术语,是给定句子背后的实际主题或动机。例如,这里有像“介绍”、“感谢”、“问候”和“再见”这样的意图,它们基本上是动机。其次,我们有一个“模式”字段,它实际上描述了具有相应动机的句子的模式或类型。然后我们有 responses 字段,其中包含一些响应,如果检测到相应的动机,这些响应可能是机器人的响应。例如,对于“标记”或意图的“问候”模式,检测到的可以是“你好”,“你好”,相应的回应可以是“你好”,“你好”。

现在,我们从模式中一个接一个地挑选出所有独特的单词,将它们词条化,转换成小写,然后附加到它以创建一个单词列表。这个列表看起来会像这样:

【‘嗨’,‘那里’,‘怎么样’,‘是’,‘你’,…………………】。什么','能','做']

这将是我们模型训练的词汇包。现在,我们需要对列表进行一次性编码,以创建编码向量,然后将这些向量作为训练集拟合到模型中。

然后,我们有标签,也放在一个列表中。看起来是这样的:

['问候','再见','谢谢'……………………]

这也是一个创建列表的热编码,该列表将作为我们训练模型的目标数据。现在,我们该怎么做呢?

首先,我们获得过滤的单词列表包。在我们的例子中,单词列表的长度是 47。现在,我们创建一个大小为 47 的列表,并用 0 标记所有的索引。然后,我们将对应于输入句子中出现的单词的索引标记为 1。例如,输入句子是“你好”。那么列表就变成了:

[1,1,0,0,0,…………….]

只有对应于“hi”和“there”的索引是 1,而所有其他的都是 0。这些编码的向量是从我们批处理中的所有输入语句中获得的。因此,如果批量大小为 n,我们有 n x 47 个列表,它是训练集的 X 值的输入维度。

同样,我们也设定了目标。我们有 7 个标签。因此,我们创建一个大小为 1 的列表。对应于由输入语句表示的标签的标签索引是 1,而所有其他的都是 0。例如,在我们的训练数据集中,“你好”的标签是“问候”。因此,对应于问候标签的索引是 1,所有其他的索引是 0。因此,如果批量大小为 n,我们有 n x 7 个列表,它是 Y 值的输入维度或训练集的目标值。

所有意图模式中出现的每个句子构成了我们的总数据集。在这些数据集的基础上训练该模型。

用途:现在当用户输入一个句子或语句时,它也被标记化,词条化,转换成小写。然后,在对来自用户的数据进行预处理之后,我们使用我们的词汇表对用户数据进行编码,并形成 47 长度的编码向量。我们用这个向量来拟合我们的模型,这给了我们用户语句的预测标签。然后,我们从响应列表中找到对用户声明的随机响应。

应用

让我们直接进入代码:

from nltk.tokenize import word_tokenize
import nltk
from nltk.stem import  WordNetLemmatizer
import re
lem = WordNetLemmatizer()def filter_command(phrase):
 tokens=[]
 tok=word_tokenize(phrase)
 for t in tok:
  tokens.append(tok.lower())
 tags = nltk.pos_tag(tokens)work=[]
 work_f=[]
 subject=[]
 number=[]
 adj=[]
 query=[]
 name=0
 for tup in tags:
  if "VB" in tup[1]:
   work.append(tup[0])
  if "CD" in tup[1]:
   number.append(tup[0])
  if "JJ" in tup[1]:
   adj.append(tup[0])
  if "NN" in tup[1]:
   subject.append(tup[0])
  if "W" in tup[1] and "that" not in tup[0]:
   query.append(tup[0]) 
 for w in work:
  work_f.append(lem.lemmatize(w.lower()))
 if query:
  if "you" in tokens or "your" in tokens:
   task=0
  elif 'weather' not in tokens or 'news' not in tokens or 'headlines' not in tokens: 
   task=1
 elif 'play' in work_f or 'song' in subject or 'play' in subject:
  task=2
 elif 'book' in work_f or 'book' in tokens[0]:
  task=3
 elif 'weather' in subject:
  task=4
 elif 'news' in subject or 'headlines' in subject:
  task=5
 else:

  if '?' in tokens and 'you' not in tokens and 'your' not in tokens:
   task=1
  else:
   task=0 

 return task,work_f,subject,number,adj,query

这是我们的主库代码,它是我们基于规则的学习和自学之间的融合区域。用户发送一条消息,该消息被该代码接收,并且该代码对该消息进行分类。换句话说,它告诉我们该语句是分配了一些任务,还是只是一个普通的随意对话。

这里我们将首先标记语句,然后标记词性。现在,如果它是一个问题,就会有一个问号,或者有一个‘wh’术语。如果检测到这些特征,则该语句被分类为查询,并采取相应的动作。同样,如果我们想要天气或新闻,这些术语将作为语句的主题出现。如果语句不是已定义的查询或任务,则任务被赋值为 0,并由我们的自学者模型接管,该模型现在将尝试对语句进行分类。

from create_response import responseflag=0
while(flag==0):
        user_response = input()
        flag=response(user_response)

这是我们的呼叫模块。它在 while 循环中运行,直到响应函数将标志定义为 1。

import json
from preprocess_predicted import predict_c
from lib import filter_command
import random
from support import search_2,play,book,get_weather,get_news_update,scrapedef get_res(res):
 with open('intents.json') as file:
  intents=json.load(file)
 tag = res[0]['intent']
 all_tags = intents['intents']
 for tags in all_tags:
  if(tags['tag']== tag):
   result = random.choice(tags['responses'])
   break
 return result,tagdef response(phrase):
 flag_1=0
 task,work_f,subject,number,adj,query=filter_command(phrase)
 if task==0:
  res_1=predict_c(phrase)
  result,tag=get_res(res_1)
  if tag=="noanswer":
   results="Here are some google search results"
   search_2(subject,phrase)
  if tag=='goodbye':
   flag_1=1elif task==1:
  scrape(phrase)
  result="Here are some results"elif task==2:
  play(phrase,subject)
  result="Here you go"elif task==3:
  book(phrase)
  result="Here are some results"

 elif task==4:
  get_weather()
  result="Here are the results"elif task==5:
  get_news_update()
  result="Here are the results"else:
  result="Sorry, I don't think i understand"
 print(result)
 return flag_1

这是我们的驱动响应创建器代码。它从调用者那里接收用户语句。然后调用 filter_command()返回是否检测到任何分类任务。这里我们有 6 个任务(0-5)。0 表示未检测到任务。任何带有“?”的“wh”查询或语句由 scrape()代码段处理。类似地,任务 2 是播放 youtube 视频,任务 3 是预订机票或房间,任务 4 是天气新闻。最后,5 是新闻更新。0 调用自学习模型。

所有任务处理程序都在支持文件中定义。他们主要使用 Selenium automation 和 web scraping。让我展示其中的三个。

def play(message,subject):
    result=message
    ext="[https://www.youtube.com/results?search_query=](https://www.youtube.com/results?search_query=)"
    messg=result.replace(" ","+")
    msg=ext+messgdriver = webdriver.Chrome()
    wait = WebDriverWait(driver, 3)
    presence = EC.presence_of_element_located
    visible = EC.visibility_of_element_locateddriver.get(msg)
    wait.until(visible((By.ID, "video-title")))
    names=driver.find_elements_by_id("video-title")
    i=0
    for name in names:
        print(name.text)
        if len(subject)==2:
         s=subject[1]
        else:
         s=subject[0]
        if s not in name.text.lower():
            i+=1
            continue
        else:
            break#driver.quit()
    print(i)
    driver.find_elements_by_id("video-title")[i].click()
    url = driver.current_url
    time_prev= int(round(time.time()))
    #video=pafy.new(url)
    #print((driver.find_elements_by_xpath("//span[[@class](http://twitter.com/class)='ytp-time-duration']")[0]).text)
    s=driver.find_elements_by_xpath("//html/body/ytd-app/div/ytd-page-manager/ytd-search/div[1]/ytd-two-column-search-results-renderer/div/ytd-section-list-renderer/div[2]/ytd-item-section-renderer/div[3]/ytd-video-renderer[1]/div[1]/ytd-thumbnail/a/div[1]/ytd-thumbnail-overlay-time-status-renderer/span")[0].text
    #s="10:00"
    time_k=int(s.split(':')[0])*60+int(s.split(':')[1])
    boo=True
    while boo:
        time_now=int(round(time.time()))
        if time_now-time_prev==int(time_k+2):
            driver.quit()
            boo=False

这是 youtube 自动化。它搜索视频,并挑选视频标题。它在标题中搜索邮件的主题。这样做是为了避免广告视频出现在推荐视频列表的顶部。因此,我们需要注意在语句中提供正确的名称。另一个问题是“s”值。这应该使用 Xpath 来保留视频长度,以便我们可以在视频结束后关闭驱动程序。但是由于 Youtube 经常改变其源代码,这有时会产生错误。它可以通过 API 解决,但是我不喜欢使用它们。

下一个是新闻刮刀:

def get_news_update():
    url="[https://www.telegraphindia.com/](https://www.telegraphindia.com/)"
    news = requests.get(url)
    news_c = news.content
    soup = BeautifulSoup(news_c, 'html5lib')
    headline_1 = soup.find_all('h2', class_="fs-32 uk-text-1D noto-bold uk-margin-small-bottom ellipsis_data_2 firstWord")headline_2 = soup.find_all('h2',class_="fs-20 pd-top-5 noto-bold uk-text-1D uk-margin-small-bottom ellipsis_data_2")headlines=[]
    for i in headline_1:
        h=i.get_text()[1:]
        headlines.append(h)
    for i in headline_2:
        h=i.get_text()[1:]
        headlines.append(h)
    for i in headlines:
        l=i.split()
        new_string = " ".join(l)
        print(new_string)

这是头条新闻刮板代码。我们用《电讯报》作为我们新闻标题的来源。它有两种类型的标题,以两类为标志。我们把两者都刮了下来,在汤的帮助下,我们提取出了代码。

接下来,最后,让我们看看查询应答器代码。也是刮刀的一种。

def scrape(phrase):
    flag=0
    ext="[https://www.google.com/search?q=](https://www.google.com/search?q=)"
    links=search(phrase, num=5, stop=5, pause=2)
    msg=phrase.replace(" ","+")
    url=ext+msg
    i=0
    for link in links:
        i+=1
        if 'wikipedia' in link:
            flag=1
            l=link
            breakif flag==1:
        wiki = requests.get(l)wiki_c = wiki.content
        soup = BeautifulSoup(wiki_c, 'html.parser')
        data=soup.find_all('p')
        print("Source:wikipedia")print(data[0].get_text())print(data[1].get_text())
        print(data[2].get_text())
        print(data[3].get_text())

    else:
        print("wikipedia Source not available")
    print("Providing searanch results")
    webbrowser.open(url,new=1)
    time.sleep(3)

在这里,我们从 google 搜索中获得结果选项,如果维基百科页面在搜索结果中,我们抓取它以提供该页面的前 4 段。如果找不到维基链接,我们只需进行基本的谷歌搜索。

现在,让我们转到自学模型部分。

这里,首先是数据预处理部分:

import nltk
from nltk.stem import WordNetLemmatizer
lem = WordNetLemmatizer()
import json
import pickledef preprocess():
 words=[]
 words_f=[]
 tags=[]
 docs=[]
 ignore_words = ['?', '!',',','.']
 with open('intents.json') as file:
  intents=json.load(file)for i in intents["intents"]:
  for pattern in i['patterns']:
   w=nltk.word_tokenize(pattern)
   words.extend(w)docs.append((w, i['tag']))if i['tag'] not in tags:
    tags.append(i['tag'])for w in words:
  if w in ignore_words:
   continue
  else:
   w_1=lem.lemmatize(w.lower())
   words_f.append(w_1)
 words_f = sorted(list(set(words_f)))pickle.dump(words_f,open('words.pkl','wb'))
 pickle.dump(tags,open('tags.pkl','wb'))
 return words_f,tags,docs

此代码用于预处理。众所周知,在所有标签下检测到的 all_patterns 中的所有模式都被标记化了。将标记化后的单词放入一个列表中。所以,这些列表有重复的值。相应的标签也保存在“标签”列表中。文档列表正在以(tokenized_words,tag)格式保存元组。所以,它被保存为例如(['hi ',' there'],' greeting ')。

现在,word_f 列表是一个更纯粹的列表版本,没有重复的单词。

from preprocessing import preprocess
from nltk.stem import WordNetLemmatizer
lem = WordNetLemmatizer()
import numpy as np
import randomdef data_creator():
 words,tags,docs=preprocess()out_array=[0] * len(tags)
 train=[]for doc in docs:bag_of_words=[]
  patt=doc[0]
  patt_f=[]
  ## Accessing the first part of a tuple (word,tag)for pat in patt:
   p=lem.lemmatize(pat.lower())
   patt_f.append(p)for word in words:
   if word in patt_f:
    bag_of_words.append(1)else:
    bag_of_words.append(0)# Creating vector of wordsoutput_req=list(out_array)
  output_req[tags.index(doc[1])] = 1
  #print(len(bag_of_words))
  #print(len(output_req))
  train.append([bag_of_words, output_req])
 random.shuffle(train)
 train=np.array(train)
 X_train=list(train[:,0])
 Y_train=list(train[:,1]) 
 print("1")
 np.save('X_train.npy',X_train)
 np.save('Y_train.npy',Y_train)

这里,形成了单词或编码向量的包。这个片段在我们的文档中挑选单词标记化的部分来创建编码的向量,这些向量是我们形成的 X 训练集的一部分,并且它们相应的标签也被编码以形成我们训练集的 Y 训练或目标值。

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation, Dropout
from tensorflow.keras.optimizers import Adam
import numpy as np
from training_data_creation import data_creator
def model_c():
 data_creator()
 X=np.load('X_train.npy')
 Y=np.load('Y_train.npy')
 model = Sequential()
 model.add(Dense(32, input_shape=(len(X[0]),), activation='relu'))
 model.add(Dropout(0.2))
 model.add(Dense(64,activation='relu'))
 model.add(Dropout(0.3))
 model.add(Dense(128, activation='relu'))
 model.add(Dropout(0.3))
 model.add(Dense(len(Y[0]), activation='softmax'))adam=Adam(lr=0.001)
 model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['accuracy'])
 return model,X,Y

我们的模型以及训练数据的训练(X)和目标(Y)集由函数返回。我们的模型有两个隐藏层。它使用分类交叉熵作为损失函数,并在最后一层激活 Softmax。我们在这里使用了“亚当”优化器。

import tensorflow as tf
from model import model_cdef train():
 callback=tf.keras.callbacks.ModelCheckpoint(filepath='chatbot_model.h5',
                                           monitor='loss',
                                           verbose=1,
                                           save_best_only=True,
                                           save_weights_only=False,
                                           mode='auto')
 model,X,Y=model_c()
 model.fit(X, Y, epochs=500, batch_size=16,callbacks=[callback])train()

我们的模型在 500 个历元时被训练,只保存最佳权重。

import nltk
from nltk.stem import WordNetLemmatizer
lem = WordNetLemmatizer()
import numpy as np
import pickle
import tensorflow as tf
import randomdef preprocess(phrase):
 words=nltk.word_tokenize(phrase)
 words_f=[]
 for word in words:
   w=lem.lemmatize(word.lower())
   words_f.append(w)
 #print("****************")
 #print(words_f)return words_fdef bag_of_words(phrase,words):
 obt_words=preprocess(phrase)bag_of_words=[0]*len(words)for o in obt_words:
  for w in words:
   #print(o)
   #print(w)
   if o==w:
    #print("A")
    bag_of_words[words.index(w)]=1b_n=np.array(bag_of_words)
 return b_ndef predict_c(phrase):
 model=tf.keras.models.load_model('chatbot_model.h5')
 words = []
 with (open("words.pkl", "rb")) as openfile:
  while True:
   try:
    words.append(pickle.load(openfile))
   except EOFError:
    break
 tags = []
 with (open("tags.pkl", "rb")) as openfile:
  while True:
   try:
    tags.append(pickle.load(openfile))
   except EOFError:
    break
 #print(words)
 #print(tags)
 #print(phrase)
 to_pred=bag_of_words(phrase,words[0])
 #print(to_pred)
 pred=model.predict(np.array([to_pred]))[0]
 threshold=0.25
 results = [[i,r] for i,r in enumerate(pred) if r>threshold]
 results.sort(key=lambda x: x[1], reverse=True)
 return_list = []
 for r in results:
  return_list.append({"intent": tags[0][r[0]], "prob": str(r[1])})
 return return_list

上述代码用于模型预测的新用户语句的预处理。它涉及到转换成小写和词汇化。然后,使用我们的词汇形成编码向量,并将其发送到模型进行预测。机器人响应取决于预测的标签。

这就是我们 Bot 运作的整体流程。

结果

短片展示了我们的机器人的使用和动作。我想我的设备中的 CUDA 存在一些版本问题。所以,我收到了一些警告,但我认为这没什么好担心的。

挑战

该领域存在一些缺点和挑战。例如,词性标注,在标注‘玩’字的同时,有时标注为名词,有时标注为动词。类似地,这个问题也存在于“书”的问题中,这里我已经处理了异常,但是在真实世界的大场景中,这些事情会很重要。如果我们使用自我学习模型,情况不会太糟。自学模型面临的挑战是,它们需要一个庞大的训练集,需要手动设计。所以,这就是为什么聊天机器人通常是为特定目的服务的,比如处理前台客户的投诉和互动,并记录问题。但是,目前它们正以非常快的速度发展。希望,不久我们将会看到更多进化的机器人。

结论

在这篇文章中,我们谈到了一种方法,一个基本的计划聊天机器人可以被赋予一些功能。我希望这有所帮助。

这里是 Github 链接

设计数据科学竞赛是一种很好的学习方式

原文:https://towardsdatascience.com/designing-a-data-science-competition-is-an-excellent-way-to-learn-69e6fd582702?source=collection_archive---------51-----------------------

意见

我们让学生们创造 ML 挑战,这就是他们所学到的

作者图片

在过去的几年里,作为国际合作的一部分,我们探索了让学生参与组织和参与挑战作为一种教学工具的好处。参与竞赛的设计和解决可以被视为学习适当的实验设计和分析以及更深入地理解机器学习的其他方面的动手手段。南巴黎大学(法国巴黎)的研究生参与的班级项目,创建端到端的挑战,从定义研究问题、收集或格式化数据、创建启动工具包,到实现和测试网站。数据的应用领域和类型极其多样:医学、生态学、市场营销、计算机视觉、推荐、文本处理等。由此产生的挑战然后被用作本科生的课堂项目,他们必须解决这些问题,无论是在南巴黎大学还是在伦斯勒理工学院(RPI,美国纽约),以提供大规模的丰富学习体验。今年,学生们参与了由“AI for good”激发的挑战,并将创建可重复使用的模板来激励其他人为了人类的利益而创造挑战。

教学动机

在过去的几年里,挑战在教学中变得无处不在。例如,ka ggle“in class”有数百场比赛。在教学中使用竞赛的好处包括激励学生和促进评分。然而,到目前为止,很少让学生参与竞赛的设计和实施。显然,这是一项更加困难的任务,最复杂的挑战可能需要几年的成熟和成熟研究人员的参与。然而,相对简单的竞赛,其难度水*可用于训练本科生,研究生可以很容易地设计和实施,作为课堂项目的一部分(通常是分类和回归问题,偶尔也解决推荐和强化学习问题)。

这使他们能够获得实验设计的实际操作,并通过定义油井任务和指标、收集和准备数据(确保有足够的样本且不存在偏差或数据泄漏)、准备基线方法,以及提出他们的挑战以吸引尽可能多的参与者来解决这些问题,来克服这些困难。

在这个过程中,学生还学习团队工作,满足严格的截止日期,并获得 Python 的编程技能,包括掌握 scikit-learn 和 Keras 等工具包,以及良好的编码实践,包括使用 Github 进行版本控制和使用 dockers。重点放在创建一个完全工作的端到端“产品”(一个挑战),然后由真正的“客户”(本科生)使用。通过让研究生制作一个简短的广告视频,并在课堂上向本科生展示他们的挑战,本科生可以选择其中一个作为他们的项目,也强调了沟通的质量。

作者图片

自 2016 年以来,我们一直在开展这种类型的教育项目。每年有 30 至 40 名研究生在数据科学硕士项目中提出挑战,约 100 名二年级本科生在 12 周的项目期内解决这些挑战。因此,我们已经通过这个项目培训了 500 多名学生。我们已经招募了几位校友作为更大研究挑战的共同组织者,这些挑战被选为 NeurIPS 竞赛计划的一部分,如 TrackML 粒子物理挑战AutoDL 挑战

作者图片

社区影响

让研究生参与挑战的设计具有重要而深远的影响。随着当前人工智能研究和应用的快速增长,既有前所未有的机遇,也有对其潜在滥用的合理担忧。在这种情况下,提高学生对与研究设计和建模相关的良好数据科学方法的认识非常重要。认识到没有好的数据就没有好的数据科学,我们希望教育他们进行适当的数据收集和准备。我们的目标是灌输良好的实践,以减少因数据偏差或因缺乏数据导致的不可再现结果而导致的问题。我们还鼓励通过使用软件用真实的合成数据代替真实数据来保护数据的机密性或隐私。这有助于拓宽本科生接触具有商业价值或可能伤害个人的机密或私人数据的渠道。

codalab.lri.fr 和【codalab.lri.fr】的学生竞赛

今年,我们教育项目的一个新的补充方面是使用占位符数据(例如,如上所述的合成数据),将已设计的挑战转化为简化的模板,并包括现成的入门解决方案。这种模板将展示各种各样的数据驱动的人工智能应用,以引发全球研究人员的想象力,而无需特定的人工智能专业知识。通过简单地克隆模板和替换数据,组织可以立即获得基线结果,并最终通过将挑战作为内部或外部竞赛来完善它们。为了促进这一进程,我们将免费提供我们的开源挑战*台 Codalab ,并将根据挑战组织者的优点和需求,在该*台上提供额外的计算资源。

除了便于其他讲师重复使用我们的挑战,传播我们的挑战模板也将有利于渴望将人工智能解决方案引入新领域的低预算企业家。最后,想要为“AI for good”做贡献的志愿者将有一个*台,通过克隆挑战模板来快速整合应用程序。我们相信这将是对 AI 民主化的重要贡献。

结论

教学生组织和参与机器学习竞赛,为他们成为数据科学家做好准备,同时帮助我们培养一个具有良好实践的挑战组织者社区,并传播挑战模板,这可以有助于传播 AI for all 和 AI for good。

承认

许多人参加了这个项目。伊莎贝尔·盖恩和克里斯汀·贝内特担任教师;迪维扬·卡兰塔恩和李生·孙·霍索亚为助教。我们非常感谢 Eric Carmichael 和 Tyler Thomas 开发和维护挑战*台 Codalab 以及教学工具 ChaLab 和 Chagrade,并感谢助教刘正英和巴尔萨扎·多农以及包括 Magali Richard、Guillaume Charpiat 和 Antoine Marot 在内的班级导师。该项目由 ChaLearn、Isabelle Guyon 的巴黎萨克莱大学“大数据”主席、欧盟 HADACA 项目(EIT Health)和联合卫生基金会(煽动项目,RPI,纽约)提供部分资助。

a .帕瓦奥、d .卡兰塔恩、l .孙-霍索亚、k .贝内特和 I .盖永。实验设计与分析:教学中的挑战方法。 CiML 工作坊,NeurIPS 2019。

用 Python 设计要素选择管道

原文:https://towardsdatascience.com/designing-a-feature-selection-pipeline-in-python-859fec4d1b12?source=collection_archive---------9-----------------------

用 PYTHON 进行机器学习

如此强大,以至于你的奶奶会试着用它来代替她那经验丰富的铸铁锅

汉斯·维维克在 Unsplash上的照片

目的:用 Python 设计开发特征选择流水线。

材料和方法:使用 Scikit-learn,我们为一个分类任务生成一个 Madelon 样的数据集。我们的工作流程的主要组成部分可以总结如下:(1)生成数据集(2)创建训练集和测试集。(3)应用特征选择算法来减少特征的数量。

硬件:我们在配备英特尔酷睿 i7–8700 处理器(12 个 CPU,3.70 Ghz)和英伟达 GeForce RTX 2080 的工作站上训练和评估我们的模型。

注意:如果你是从零开始,我会建议你按照这篇文章安装所有必要的库。最后,假设读者熟悉 Python、 PandasScikit-learn 。这篇文章的全部内容可以在我的 GitHub 上找到。欢迎你来叉它。我不得不提到一些特征选择方法是从 Will Koehrsen 的文章中得到启发的。

符号:粗体文本将用于表示 Python 对象,例如列表、字典、元组、数据帧,或者将引用一个图形或脚本。This notation will be used to represent classes and function parameters as well as Python packages.

特征选择

特征选择是从更大的群体中识别特征的代表性子集的过程。用户可以选择手动选择功能,也可以应用多种自动方法中的一种。手动选择特征的困难在于它需要关于手边数据的专业知识。例如,在放射肿瘤学中,放射治疗计划(其中每个体素代表一个特征的 3D 图像)被简化为一系列手工制作的特征,并且被几十年的放射治疗研究和合作临床调查所支持。这些特征中的每一个都量化了放射治疗计划的具体特征,这些特征已经被证明与患者的临床结果相关。令人欣慰的是,用于特征选择的自动化方法已经被开发出来,并且可以很容易地用于减轻这项任务;然而,我们必须有保留地应用这些自动化方法,因为它们可能会导致错误的结论。根据我的经验,我认为应用特性选择方法的最佳方式是使用领域知识和自动化方法来确定一个有代表性的特性子集。

在机器学习的背景下,人们从特征选择中获得的优势是很多的。例如,找到最具描述性的特征可以降低模型的复杂性,使找到最佳解决方案变得更容易,最重要的是,它减少了训练模型所需的时间。此外,如果你理解了典型特征的含义,你将对你所面临的问题有更深的理解。在某些情况下,可以获得轻微的性能提升。必须注意的是,通过从系统中删除特性,您的模型的性能可能会稍微差一些(因为您试图用更少的信息进行预测)。

通常情况下,我们没有多余的时间来对我们的数据进行彻底的研究,以确定要制作什么功能以及如何使用它们。面对超过 1000 个特征的数据集,确定特征的代表性子集的任务似乎令人生畏,但幸运的是,冗余是我们的数据可以成为我们的朋友。通常,当面对具有+1000 个特征的数据集时,您会注意到很大一部分特征高度相关(冗余),与结果无关,或者只是噪声。从开始的+1000 个特征中,您可能最终会有 10 个特征“充分地”代表了整个数据集。

在本文中,我们将讨论以下特征选择算法及其局限性:

  • 一种过滤方法,可移除可变性很小的要素
  • 移除高度相关要素的过滤方法
  • 递归特征消除(RFE ),用于确定最大化模型性能所需的特征子集
  • 确定与结果相关的特征子集的 Boruta 方法

安装必要的软件包

在深入本文之前,让我们安装必要的包。我们将假设读者已经安装了以下包的 Anaconda:NumpySeabornMatplotlibPandasSklearn

你可能遗漏的唯一一个包是BorutaPy,所以让我们来处理它。打开您的终端(如果您在 Mac 上)或 Anaconda 提示符(如果您在 Windows 机器上)。激活您的环境并运行以下命令:

conda install -c saravji boruta

用 Mac 终端在名为 PythonFinance 的 Anaconda 环境中安装 BorutaPy。

你需要访问我的 GitHub 这里并下载工具文件夹。本文的全部内容都在名为 FeatureSelectionPipe.py 的文件中

把 tools 文件夹放在你的工作目录下,你就设置好了。

所以在我们开始之前,让我们导入所有的包。

脚本 1 —导入所有必需的包。

数据

我们将创建多组合成特征,以探索不同特征选择算法的性能和有效性。首先,我们将生成一个类似 Madelon 的合成数据集。Madelon 数据集(我们不会使用)是一个人工数据集,它包含放置在边长为 1 的五维超立方体顶点上的 32 个簇。聚类被随机标记为 0 或 1 (2 类)。我们将生成的类似马德隆的数据集将包含 100 个特征,其中 10 个特征将提供信息,50 个将是冗余的(但提供信息),25 个将重复,15 个将是无用的,因为它们将充满随机噪声。总共,我们将有 1000 个样品。为了给数据增加一点噪声,我们将随机翻转 5%的标签。第二组功能将包含 3 个关键的重要功能。通过自动特征选择算法来选择设计的关键重要特征应该是具有挑战性的。最后,最后一组特性只是将类似 Madelon 的特性和关键特性添加到一个更大的数据集中。

我们现在准备创建类似 Madelon 的数据。在脚本 2a 的第 4–9 行,我们定义了我们希望从每种类型中获得的特征数量(信息性的、冗余的、重复的、无用的)。之后,在第 12–16 行,我们创建列标签。从第 19–23 行开始,我们创建数据和标签。在第 27 行,我们将 numpy 数组转换成 pandas 数据帧。

脚本 2a —创建类似 Madelon 的数据集。

接下来,我们将创建我们至关重要的特性。这里,我们将假设经过几十年的理论、数值和经验研究,这三个特征已经被确定为对分类过程特别重要。为了更清楚地说明这一点,让我给你举个例子。在放射肿瘤学中,传递到器官的最大辐射可以与接受放射疗法治疗的患者所经历的毒性相关联。因此,为了确保对患者的安全治疗,考虑传送到每个器官的最大辐射量是至关重要的。为了便于说明,让我们假设在患者开始出现中毒症状之前,可以传递到膀胱的最大辐射可以是 100。所以我们的数据可能看起来像这样:

表 1 —输送到膀胱的最大剂量。

因为医生知道对膀胱的大量辐射会导致并发症,所以产生的大多数辐射治疗计划将满足建立的最大辐射标准。然而,在表 1 中,6 号患者未能满足膀胱接受少于 100 次辐射的标准。换句话说,95%的数据符合标准,只有 5%不符合。因此,如果您要实现一种自动选择功能的方法,如果您不采取适当的预防措施,这种方法很可能无法识别膀胱的最大剂量至关重要。尽管如此,我们知道这样的特征是非常重要的,为了病人的安全,应该总是考虑到。因此,将极其重要的特征引入我们的数据集中以测试自动特征选择方法的效率的动机。

为了创建 3 个关键的重要特征,将从三个不同的高斯分布中提取,每个分布以不同的值为中心。这些特征将由我在 StackOverFlow 中找到的以下辅助函数生成:

脚本 2b :生成关键重要特征的辅助函数。

脚本 2c 的第 5–10 行,我们设置了关键特性分布的参数。然后在第 13–25 行,我们运行一个 for 循环,创建三个关键特性,然后存储在一个列表中(第 25 行)。我想指出的是,在第 15 行,我们修复了种子,这样我们就可以使用相同的发行版。

脚本 2c :创建三个关键特征。

在我们将这些关键特性添加到数据集之前,我们需要定义 y_critical 目标。在脚本 2d 的第 5–7 行中,我们通过设置阈值来确定真假情况,从而为每个关键特性定义一个目标。选择这些阈值,使得每个关键特征包含 95%的阳性病例和 5%的阴性病例。最后,在第 10 行,我们通过乘以关键特性的目标来定义 y_critical

脚本 2d :创建每个关键特征的标签和 y_critical 标签。 y_critical 应该有 74 个阳性病例。

作为健全性检查,让我们可视化关键特性的分布。

脚本 2e :可视化关键特征。

图 1 —关键特征分布。绿色区域代表阳性类别,红色区域代表阴性类别。

图 1 中,您会注意到有三种不同的高斯分布。最左边的分布代表第一关键特征,最中间的分布代表第二关键特征,最右边的分布代表第三关键特征。标记为绿色的区域表示每个要素中的阳性类别,标记为红色的区域表示阴性类别。

我们现在准备把所有东西放在一起。在脚本 2f 的第 12 行,我们连接了 X_madelonX_critical 。然后在第 15–16 行,目标 y_all 被定义为 y_madelony_critical 的逐元素乘法。

脚本 2f :加入 X_madelonX_critica l 创建 X_all 和创建 y_all

在我们继续之前,让我们回顾一下我们已经创建的一组功能:

X_madelon: 这是一组使用make_classification()类创建的合成特征。原则上,从该组中选择的最佳特征数量应该是信息特征(总共 10 个)。

X_critical: 关键特性一共 3 个。每个都具有不同*均值的高斯分布。每个关键特征包含 90 %的肯定案例和 10 %的错误案例。通过构造,这些特征可能很难通过自动化方法来选择;然而,对于一个对手头数据有领域知识的人来说,这些数据很容易被确定为对结果很重要。

X_all: 这是一组包含了 X_madelonX_critical 特性的特性。该数据集的列将按如下顺序排列:

  1. 信息特征—第 1–10 列:这些特征与结果高度相关,理想情况下应该是您选择的特征。
  2. 冗余特征—第 11–60 列:这些特征通过线性组合具有不同随机权重的信息特征而形成。您可以将这些视为工程特性。
  3. 重复特征—第 61–85 列:这些特征是从信息特征或冗余特征中随机抽取的。
  4. 无用特征—列 86–100:这些特征充满了随机噪声。
  5. 关键重要特征—101–103 列:这些特征具有高斯分布,我们将要求它们绝对需要包含在所选特征中。

在我们做任何其他事情之前,让我们分割我们的数据。对于每组功能,我们将使用 70/30 分割创建一个训练和测试集。

脚本 2g —将数据分割成 70 个训练/ 30 个测试分割。随机状态/种子被设置为 42。

探索性数据分析

在本节中,我们将可视化数据,以确认我们已经知道的内容。我们将从探索我们特征之间的相关性开始。在脚本 3a 中,我们首先计算斯皮尔曼相关矩阵,其值在-1 到 1 的范围内(第 5 行)。值 1 表示强正相关,值-1 表示强负相关。当相关值接*零时,这意味着特征之间不存在相关性。由于负相关和正相关只是相关,我们然后取相关矩阵的绝对值(第 5 行)并使用seaborn包创建热图(第 14 行),参见图 2

脚本 3a—可视化 Spearman 相关矩阵。

图 2 —斯皮尔曼相关矩阵可视化为热图。注释是用 PowerPoint 添加的。

图 2 中,浅色表示低相关性,深蓝色表示高相关性。请注意,信息特征之间的相关性很低(左上角)。冗余特征开始显示更高的相关性(热图在该区域变得更蓝),就像我们预期的那样。此外,有些重复与我们预期的其他特征高度相关。最后,无用特征和关键特征与其他特征不相关。我们知道无用的特征充满了随机噪声,不应该与结果相关联。另一方面,关键特征与结果相关,尽管它们与其他特征没有相关性。

接下来,让我们使用箱线图来可视化每个特征的分布。箱线图显示了数据集的四分位数,并允许我们确定数据中的任何异常和异常值。在脚本 3b 中,我们首先设置图形样式,这样我们的图形(第 5–8 行)就不会有难看的灰色默认seaborn背景。然后,我们为特性 X_all_ 系列创建一个方框图(第 14 行)。

脚本 3b —用箱线图可视化特征分布。

图 3 —特征矩阵方框图。

图 3 中,我们可以看到大多数特征都包含离群值。此外,所有类似马德隆的特征都以零为中心,并且大多数似乎具有高斯分布。关键特征以不同的*均值为中心,就像我们之前在图 1 中展示的那样。

特征选择

在本节中,我们将使用FeatureSelector,这是一个应用以下四种特征选择方法的工具:

  1. 一种过滤方法,可移除具有给定比例重复值的要素。
  2. 一种基于皮尔逊或斯皮尔曼系数移除相关要素的过滤方法。
  3. 一种带有交叉验证的递归要素消除算法,用于对要素进行排序并确定最大化模型性能的要素。
  4. 选择与结果相关的特征的 Boruta 方法。

该工具设计用于在给定的序列中应用不同的特征选择方法。例如,您可以首先移除相关要素,然后使用递归要素消除来进一步减少所选要素的数量。

移除大部分常数值的特征

有人可能会说,当你改变样本时,一个特性表现出的变化很小或者没有变化,对于一个模型来说是不太有用的。

表 2 —特征 3 显示可变性很小的样本数据集。

例如,如果您的数据看起来像右侧的表,则选择要素 1、要素 2、要素 4 并删除要素 3 是合理的。这是因为特征 3 的值在不同的样本之间变化不大。保留特性 3 会增加模型的复杂性,并且保留它很可能不会观察到任何预测性能。然而,最后一种说法需要经验验证。要建立阈值来标记包含大量常数值的要素,以便移除它们,您需要进行实验。仅仅因为一个特性在 90%的时间里包含相同的值,并不意味着它对一个模型没有用。

脚本 4a 中,我们从导入特征选择工具开始。在第 7 行,我们定义了一个名为 step1 的字典,其中我们指定了要应用的特性选择方法及其参数。例如,要删除具有大部分常量值(95 %或更多)的特性,我们将键设置为'Constant Features',将值设置为{'frac_constant_values': 0.95}。在第 10 行,我们将步骤 1 保存在一个名为步骤的列表中,然后我们启动一个FeatureSelector的实例(第 13 行)。FeatureSelector有一个fit()transform()方法,很像 Sklearn transformer。fit()方法学习从训练集中选择哪些特征(第 16 行),而transform()方法将数据集减少到仅选择的特征(第 19 行)。fit()方法将以下内容作为输入:

  • X_all_train :熊猫数据帧
  • y_all_train :一个 numpy 数组
  • 步骤:字典列表

transform()方法将以下内容作为输入:

  • 一个熊猫的数据帧

脚本 4a —移除大部分常数值的特征。

图 4 —在 IPython 控制台中执行的脚本 4a。执行时间不到一秒钟。

fit的输出将被打印到被移除特征的控制台上。在这种情况下,您可以看到显示一个空列表,这表示在此步骤中没有删除任何功能。

移除相关特征

让我们假设,如果一组特征高度相关,我们可以随机选择其中一个,丢弃其余的,而不会丢失太多信息。为了衡量特征之间的相关性,我们将使用 Spearman 的相关系数。为了移除相关特征,我们将再次使用FeatureSelector。在脚本 4b 中,我们首先定义一个描述特征选择方法及其参数的字典。例如,在这种情况下,我们将键设置为'Correlated Features',将值设置为{'correlation_threshold': 0.95}。该算法将对相关值大于或等于 0.95 的要素进行分组。然后,对于每组相关的特征,选择一个特征,其余的被丢弃。在第 8 行,我们将步骤 1 保存在一个列表中,然后初始化FeatureSelector的一个实例(第 11 行)。最后,我们拟合FeatureSelector,并转换我们的数据。

脚本 4b —移除高度相关的特征。

图 5 —在 IPython 控制台中执行的脚本 4b。执行时间不到一秒钟。

注意fit()的输出显示所有的重复特征被移除。在我们继续之前,让我们通过检查X_selected中的特征类型来结束这一部分。

图 6——从 X_all_train 中去除高度相关特征后所选特征的条形图。

在图 6 的中,请注意没有删除任何多余或无用的功能。换句话说,如果您仅从群组中移除相关特征,预计仍会有冗余和无用的特征。从积极的方面来看,我们看到 10 个信息性特征和 3 个关键性特征是所选特征的一部分。

确定相关特征

我们已经表明,简单的特征选择方法可以快速执行,并可以从我们的队列中删除大部分特征;然而,其余的特征不一定与结果相关或者可能是多余的(见图 6 )。为了克服这个限制,开发了 BorutaPy 算法。简而言之,它使用基于树的模型的要素重要性属性来确定携带可用于预测的信息的要素。然而, Terrence Parr 和其他人对基于树的模型的特征重要性属性的有效性提出了关注。

为了选择相关特征,我们首先定义一个基于树的 Sklearn 估计器(一个具有feature_importances_属性的随机森林分类器额外树分类器梯度提升分类器)。在我们的例子中,我们将使用随机森林分类器,参见脚本 4c 中的第 5–7 行。接下来,在第 10–15 行,我们定义了一个名为 step1 的字典,带有一个键'Relevant Features''Relevant Features'的键值是一个字典,指定交叉验证结果的次数(第 10 行)和 BorutaPy 参数。对于每个训练文件夹,建立相关的特征。然后,在每个训练文件夹中被认为相关的特征被选择作为训练集中的相关特征。在第 15 行,我们修复了random_state,以便获得确定性的结果。至此,脚本的其余部分应该不言自明了。

脚本 4c —确定与结果相关的特征。

图 7 —在 IPython 控制台中执行的脚本 4c。执行大约需要 5 分钟。

脚本 4c ,大约花了 5 分钟执行。如果你要增加cvn_estimatorsmax_iter,期待时间的增加。此外,包含更多样本或特征的大型数据集将增加找出相关特征所需的时间。您在图 7 的中看到的进度条将跟踪每次在训练文件夹中确定相关特征时的进度。所以,如果你一开始没有看到它填满,请耐心等待。

我们准备检查所选特性的内容。

图 8——在 X_all_train 中确定相关特征后所选特征的条形图。在这种情况下,估计量是随机森林分类器。

在图 8 的所示的条形图中,注意所有无用的功能都被删除了。这就是我们对 Boruta 算法的期望。尽管如此,我们仍然有 20 个冗余、9 个重复、5 个信息性和 2 个关键特征。这意味着我们的 Boruta 算法的实现不能去除所有冗余的特征,保留一些重复的特征,去除一半的信息特征,并丢弃一个关键特征。图 8** 表明我们不能盲目相信自动化特征选择方法的结果。记住,我们要求所有三个关键特性都必须包含在我们选择的特性中。失去其中一个会导致致命的预言!此外,如果我们使用不同的估计器,例如额外的树分类器,所选择的特征将会不同(见图 9 )。**

图 9 —使用额外树分类器和 Boruta 算法确定相关特征后,所选特征的条形图。

当使用 Boruta 算法选择特征时,重要的是要记住被选择为相关的特征只对被检查的特定模型有意义。此外,当用于对特征进行排序的模型具有过度拟合的能力时,很可能特征的排序是误导的。为了演示过拟合随机森林的缺陷,我们训练了一个模型,并评估了它在训练集和测试集中的性能,参见脚本 4d

脚本 4d —训练一个过度适应的随机森林。

脚本 4d 的输出

这里我们可以观察到,训练集中随机森林的训练准确率为 100%。当评估测试集中的性能时,我们看到准确率下降到 80 %(显然我们过度拟合)。检查过拟合随机森林的特征重要性,发现许多无用特征(随机噪声)的等级高于有用和冗余特征,见图 10 。理想情况下,无用的功能应该排在最低的位置。

图 10 —一个过度生长的随机森林的特征重要性。

鉴于过度拟合模型的排名特征不可靠,我建议首先调整您的模型,交叉验证结果,并评估其在训练和测试集中的性能,参见脚本 4e 。最小化过度拟合后,使用模型选择特征。

脚本 4e —调整分类器。要将 GridSearchCV 使用的折叠数更改为 10,请在第 19 行设置 cv = 10。同样,你也可以改变得分。执行大约需要 6 分钟。

脚本 4e 的输出

结果表明,训练集的准确率为 96%,测试集的准确率为 81%。他妈的,我们还是太合适了!让我们检查一下调整后的随机森林是如何排列特性的,参见图 11

图 11 —显示了调整后的随机森林的重要性。

有意思!我们得到了比预期好得多的结果。尽管调整后的随机森林过度拟合,但它在排列特性方面做得更好。例如,我们可以看到,关键的功能排名很高,而大多数无用的功能排名垫底。

要确定已调优随机森林的相关特性,请运行脚本 4f

脚本 4f —确定与优化随机森林的结果相关的功能。执行大约需要 5 分钟。

图 12 —用调整随机森林的 Boruta 算法确定的相关特征的条形图。

图 12 中,我们可以看到所选特征包含了对我们非常重要的三个关键特征。此外,请注意,与使用失调随机森林获得的结果相比,您可以更信任这些结果。

现在,我们将只使用选定的功能来训练一个随机森林,参见脚本 4g 。我们将随机森林的参数设置为之前在脚本 4e 中确定的参数。让我提一下,使用选择的特性来调整随机森林是一个好主意。记得当我们在脚本 4e 中调整随机森林时,我们使用了所有 103 个特性。现在选的特征大概有 35 个。然而,我们将跳过这一步,但你应该这样做。最后,我们将评估它在训练集和测试集中的性能。

脚本 4g —使用所选功能评估模型的性能。

脚本 4g 的输出

在我们讨论结果之前,让我提醒你我们开始的内容。当训练具有所有特征的失调随机森林时,我们在训练集中获得了 100 %的准确度,在测试集中获得了 80 %的准确度。让我们称之为我们的基线。在“调优”随机森林(使特征排序更加可靠),用 Boruta 算法选择特征,然后用选择的特征训练随机森林之后,我们在训练集中获得了 94%的准确率,在测试集中获得了 83%的准确率(见上面的脚本 4g 的输出)。我们可以从这些结果中得出几个结论:

  • 调整你的模型以减少过度拟合。
  • 经过优化的模型可以更准确地对功能进行排序。
  • 应用特征选择方法有助于减少过度拟合并提高模型的性能。

尽管我们仍然有相当多的过度拟合,但我们已经在性能上取得了一些进展,我们减少了过度拟合,并且降低了模型的复杂性。我会说这是一场胜利,但还不够好。

确定最大化模型性能的特征

我们还可以通过应用递归特征消除(RFE)算法来选择特征。RFE 方法确定最大化模型性能所需的最小要素子集。然而,你冒着丢掉有意义的特性的风险——所以记住这一点。因此,如果您的任务是确定对结果重要的相关特征,那么使用 RFE 可能不合适。算法基本上是这样工作的。首先,训练一个可以使用数据集中所有可用要素对要素进行分级的模型。其次,衡量模型的性能。第三,对特征进行排序,并移除排序最低的特征。重复步骤 1 至步骤 3,直到所有功能都用尽。通过在跟踪模型性能的同时迭代移除特征,您可以确定实现最高性能所需的特征数量。

为了确定将最大化模型性能的特征,我们首先定义一个基于树的 Sklearn 估计器(一个随机森林分类器额外树分类器梯度提升分类器),具有feature_importances_coef_属性。确保您的基本估计值不会过度拟合您的数据。在我们的例子中,我们将使用一个随机森林分类器,带有在脚本 4e 中找到的调整参数,参见脚本 4h 中的第 5–8 行。接下来,在第 11–15 行,我们定义了一个名为 step1 的字典,其中包含一个关键字'RFECV Features''RFECV Features'的键值是一个字典,指定交叉验证结果的次数(第 11 行)和其他 RFECV 参数。RFECV 对象是 RFE 方法的 Sklearn 实现,其中结果被交叉验证。至此,脚本的其余部分应该不言自明了。

脚本 4h —确定最大化分类器性能的特征。这将需要大约 5 分钟来运行。

图 13 —使用递归消除算法确定的最大化随机森林分类器性能的选定特征的条形图。结果是交叉验证的。

图 13 显示了由 Sklean RFECV 方法确定的选定特征。不幸的是,我们仍然有很多冗余和重复的功能。FeatureSelector类有一个rfecv属性,保存适合的 RFECV Sklearn 对象。通过检查拟合的 RFECV 对象的内容,可以更深入地了解 RFE 特征的结果。

脚本 4f —可视化 RFECV 的结果。所有这些代码都是为了做一个图形。呸!如果更改数据集或基本估计量,可能需要调整 xlim()、ylim()和 ax.axhline()。

图 14 —作为特征数量函数的精度。该模型的性能峰值约为 40 个特征。

图 14 中,显示了模型的性能与多个特征的函数关系。如您所见,性能峰值约为 40 个特征,精度约为 0.80。由于所选特征的数量约为 50(见图 13 ),我们可以得出结论,RFECV Sklearn 对象高估了我们最大化模型性能所需的最小特征数量。在我看来,如果你简单地选择排名前 13 位的特征,模型的准确率大约为 79%,你会更好。然而,RFECV Skelarn 对象确实为您提供了这些信息。如果你急于知道排名前 13 位的特性是什么,你将需要编写你自己版本的 RFE 算法。

构建特征选择管道

在上一节中,我们了解到我们需要谨慎和警惕自动特征选择方法的危险。通过应用它们,然后盲目地相信结果,你可能最终会犯下可怕的错误。此外,没有一个单一的特征选择算法产生了我们想要的结果——只选择了信息和关键的特征。

为了改进我们的特征选择,我们可以将特征选择算法作为一系列步骤来应用。例如,我们可以首先移除中度到高度相关的特征(第 11 行),然后应用 RFE 方法,如脚本 5a 所示。

脚本 5a —特征选择管道。首先,移除中度到高度相关的特征。然后,确定最大化模型性能的特征。

图 15 —使用递归消除算法确定的最大化随机森林分类器性能的选定特征的条形图。这一次,我们首先移除中度到高度相关的特征,然后应用 RFE 方法。

这一次,在所选功能中,我们有 8 个信息性功能、所有 3 个关键功能和 20 个冗余功能。这些是迄今为止我们得到的最好的结果,但是让我们再深入研究一下。请记住,FeatureSelector对象将适配的 RFECV 对象保存在其rfecv属性中。

图 16 — 作为特征数量函数的精度。该模型的性能峰值约为 20 个特征。

因此,我们已经可以从性能曲线中看到,模型的性能在 20 个特性附*达到峰值。此外,我们可以得出结论,15 个特性将足以获得高性能。现在,我们使用脚本 5b 中的选定功能来评估模型的性能。

脚本 5b —具有选定特征的模型评估。

脚本 5b 的输出

脚本 5b 的输出中,我们可以看到我们将训练集中的准确率提高到了 84%。我们缓慢但确实取得了进展。您可以使用脚本 4e 再次调优该模型,看看您是否能获得更多的性能增益。

结束语

那么,我们究竟如何设计一个特征选择管道,以产生所有的信息和关键特征,而没有多余或无用的特征呢?嗯,简单的回答是我不知道。如果你想解决这个问题,你可以把你的算法带到银行去。你应该问的问题是,“我真的需要确定最有用的特征,还是我想用最小的特征子集来训练模型?”如果你的答案是“确定最有用的特性”,那么这里介绍的方法将有助于你寻找最佳特性。然而,如果你只关心用较小的特征子集训练最好的可能模型,这里给出的特征选择算法将完成这项工作。

如果您想使用特征选择工具,请确保您的工作目录中有该工具,如下所示:

my Github 下载功能选择工具。

在使用它选择特征之前,请确保满足以下条件:

  • 加载数据并对所有分类变量进行编码。
  • 注意任何缺失值或异常值。如果不这样做,您可能会得到一个严重的错误。
  • 将特征矩阵 X 存储到 pandas DataFrame 对象中。目标变量 y 应该是一个 numpy 数组。

准备好数据后,您可以使用脚本 6a 来指导您的特性选择过程。您将需要试验来确定应用什么特征选择算法。在脚本 6a 中,我们首先调整我们的模型(第 5–29 行),然后我们定义四种特征选择方法并应用它们(第 32–56 行)。然后,我们使用选定的特征来训练模型并评估其性能(第 59–75 行)。

脚本 6a —模型调整、特征选择、模型训练和评估。

LinkedIn 找到我。下次见!小心每天编码!

[## 弗兰克·塞瓦洛斯

图表

www.frank-ceballos.com](https://www.frank-ceballos.com/) [## Frank Ceballos -威斯康星医学院博士后| LinkedIn

我是威斯康星医学院的博士后研究员,在那里我分析高维复杂的临床数据…

www.linkedin.com](https://www.linkedin.com/in/frank-ceballos) [## 弗兰克-塞瓦洛斯-概述

在 GitHub 上注册你自己的个人资料,这是托管代码、管理项目和构建软件的最佳地方…

github.com](https://github.com/frank-ceballos)

设计医疗保健机器学习工作流程

原文:https://towardsdatascience.com/designing-a-healthcare-machine-learning-workflow-2f95852a8b80?source=collection_archive---------28-----------------------

图片来自格鲍尔公司

只需 5 个步骤即可构建和运行机器学习项目

随着机器学习、云计算和机器人流程自动化等创新在医疗领域不断产生影响,结构化(即电子医疗记录)和非结构化(即医学图像、生物信号等)的需求不断增加。)公众可访问的医疗保健数据。由于工业界和学术界的许多个人和组织都在尝试创建学习模型,因此了解如何设计一个适合您正在处理的数据和问题类型的合适的机器学习工作流至关重要。这导致一个有组织的,有效的产品,产生预期的结果。

第一步:理解问题

在争论数据和构建模型之前,定义问题是很重要的。大多数缺乏经验的数据科学家希望快速获得数据,执行一些基本的 EDA,然后解决他们想要解决的问题。在行业和学术环境中,明确定义的问题和操作计划为项目的其余部分奠定了基础。为了知道你是否应该处理*衡的数据或者寻找异常值,拥有一些领域的专业知识是很重要的。

[## 贝叶斯决策理论简介

机器学习的统计方法

towardsdatascience.com](/introduction-to-bayesian-decision-theory-1532376ef986)

医疗保健领域的机器学习问题有三个主要类别:诊断、预测和建议。虽然机器学习中有许多类型的问题,但这三个问题包含了医疗保健中的大多数问题。

诊断

医疗保健 ML 中最常见的应用是诊断,也称为分类。这种受监督的学习方法能够在给定一组描述其症状的特征的情况下,确定患者是否患有特定疾病。这些特征可以以表格数据、医学图像、文本或信号的形式呈现。在某些情况下,目标是在两个类别之间进行诊断(即二元分类);然而,有时需要考虑多个类别(即多类别分类)。

预言;预测;预告

另一种监督学习方法,预测寻求回答与数量、可能性和任何其他连续结果相关的问题。与如何进行诊断类似,预测会尝试拟合训练数据,以确定最佳可能答案。这一类别可以进一步扩展到生存分析、线性回归和时间序列预测等主题。

推荐

这一类别*年来越来越受欢迎。它利用组合学的力量向给定系统的用户推荐感兴趣的项目。健康推荐系统能够根据患者的症状和情况提出最佳的行动计划。建议的范围可以包括服用何种药物、去看医生或去哪家医院。这是一个非常强大的工具,但它没有与上述类别相同的评估标准。

图片由 ScienceSoft

第二步:收集数据

一旦问题确定下来,计划开始实施,就该讨论适当的数据了。医疗保健行业每天都会产生大量的数据。临床数据是大多数健康和医学研究的主要资源。它要么是在持续的患者护理过程中收集的,要么是正式临床试验计划的一部分。最常见的例子是电子健康记录(EHR),它从多个来源收集有关患者健康的信息。EHR 包括测试结果、临床观察、诊断、当前健康问题、患者服用的药物、他们经历的程序。同样,文本和图像数据也开始在深度学习应用中发挥深远的作用。例子包括医学图像、手写处方和医生笔记。

由于医疗保健数据生态系统极其复杂和强大,无论您决定使用什么数据,都可能会有很高的存储要求。在你简单地从网站上下载一个随机的 CSV 文件之前,一定要检查你正在使用的文件的大小。聪明的方法是利用云。有许多公司提供廉价、用户友好的软件即服务(SaaS ),可以部署云数据库。现在,您所要做的就是从您正在使用的 IDE 中提取信息。

步骤 3:探索性数据分析(EDA)和预处理

数据清理

由于许多 EHR 系统仍然是手动创建和更新的,因此存在人为错误和数据质量问题。花时间清理您的数据将最终为您节省大量处理、培训、测试和评估问题的时间。正确的数据清理管道包括通过删除或修改不正确、不完整、不相关、重复或格式不正确的数据来为分析准备数据。许多初级数据科学家只是删除不干净的数据。相反,尝试操纵和扩充数据,以尽可能多地保存数据。

电子设计自动化(Electronic Design Automation)

在开始构建 ML 模型之前,创建信息可视化、统计测试和针对数据和手头问题的关系矩阵是很重要的。EDA 是了解关键特征的一个窗口,如类不*衡、特征分布和相关系数。虽然有些人认为这是浪费时间,但成功的工作流具有支持模型输出的可视化。

相关矩阵

特征抽出

既然您已经了解了要素之间以及要素与目标要素之间的关系,那么就应该选择能够最好地包含数据中的差异而又不会显著增加模型复杂性的要素。有许多方法可以选择最佳特性,但这超出了本文的范围。

步骤 4:构建和培训

决定采用哪种模式并不是一个容易的决定,它需要大量的试验和错误。每个模型都是独一无二的,需要在复杂性和效率之间取得*衡。根据没有免费的午餐定理,没有一个模型对所有可能的情况都是最好的,所以最好尽可能多的测试。

“没有一种模式能适用于所有可能的情况”

即使某个模型适用于您以前的项目,也并不意味着相同的模型将是您当前项目的最佳选择。最重要的是,数据科学家首先是科学家。因此,尝试各种可能的方法是我们工作的一部分。一旦你对自己的选择有了信心,就该在测试集上运行它了。

监督学习

到目前为止,监督学习(SL)模型是最常见的类别,它使用带有精确标签的先验数据进行训练。因此,模型应该理解底层的类条件特征空间。一些常见的 SL 算法包括逻辑回归、K-最*邻、支持向量机和随机森林。

无监督学习

使用未标记的数据,无监督学习(UL)模型被迫寻找数据中的自然关联。这消除了对训练阶段的需要,而是使用数学过程来推导分组、不同的表示和层次。常见的 UL 算法包括 K 均值、降维、层次聚类和基于密度的聚类。

半监督学习

灰色区域与之前的类别相比,半监督学习(SSL)模型使用标记和未标记数据的混合来进行分类或预测。这是因为模型需要正确理解已标记数据的结构,以理解未标记数据。SSL 方法的一个常见应用是欺诈检测。由于欺诈很难发现,而且我们不知道谁是欺诈性的,因此模型需要了解非欺诈实体的复杂性,以便发现异常实体。

步骤 5:评估模型

根据您要解决的问题的类型,可以使用特定的评估指标来深入了解您的模型的运行情况以及可能需要调整的超参数。评估一个模型是一个整体的方法,并不仅仅基于高准确性。根据您在步骤 1 和 2 中定义的问题和执行的分析,可能还有其他更重要的指标。

分类指标

  • 准确性:在我所有的预测中,有多少是正确的?
  • 精确度:在我对某个类所做的所有预测中,有多少是正确的?
  • 回忆:正确识别某一类的比例是多少?
  • 受试者工作特征(ROC)曲线:显示不同分类阈值下模型性能的图。曲线下面积(AUC)代表模型整体性能。

具有 AUC 值的 ROC 曲线

回归度量

  • 均方差(MSE):预测值和实际值之间的*方差
  • 均方根误差(RMSE):MSE 的*方根
  • *均绝对误差(MAE):预测值和实际值之差的绝对值

排名指标

  • *均倒数排名(MRR):基于第一个相关项目位置的*均值
  • *均精度(MAP):对于每个相关项目,根据该项目的位置计算精度,然后对所有用户进行*均
  • 标准化贴现累积收益(NDCG):假设一些项目比其他项目更相关,计算加权*均值。

结论

为医疗保健环境开发和实现机器学习不是一个快速的过程,但我希望这篇文章为您了解可能会遇到的障碍奠定了基础。请记住,即使您构建了模型并且运行良好,您仍然需要部署它。虽然部署机器学习系统在实践中非常简单,但医疗法规和控制要求您采取某些措施来确保标准化和质量保证。

相关文章

[## 检测医疗欺诈(第一部分)——数据采集和预处理

了解医疗事故的特点以及需要什么技术来检测欺诈的医生

medium.com](https://medium.com/swlh/detecting-medical-fraud-part-1-data-acquisition-preprocessing-e8f3206b9bac) [## 检测医疗欺诈(第 2 部分)—在 PyTorch 中构建自动编码器

学习如何使用神经网络发现腐败的医生

medium.com](https://medium.com/swlh/detecting-medical-fraud-part-2-building-an-autoencoder-in-pytorch-5ef64b7979ef)

设计实用且引人注目的数据可视化

原文:https://towardsdatascience.com/designing-a-practical-and-compelling-data-visualization-dbf2446ba083?source=collection_archive---------48-----------------------

现实世界中的数据科学

你不需要成为 Tableau 或 PowerPoint 超级用户。

数据可视化是向技术和非技术受众传达数据的最有力的方式。这也是分析中最“理所当然”的部分。很少有分析师接受过数据可视化最佳实践的正式培训。

更糟糕的是,像 PowerPoint 和 Excel 这样的应用程序的默认选项设计得很差;当它们应该被视为一个起点时,它们被视为可接受的或首选的。

数据可视化的目的是让查看者快速和轻松地从数据中提取最重要的信息。我发现很难找到一个非教科书式的资源,专注于利用心理学和人类行为知识的数据可视化的实用的、以业务为中心的最佳实践。大部分内容都是*面设计或者是为口头表达而设计的。

然而,对于当今的分析专业人员来说,这种差距就是大多数演示文稿存在的地方——您的内容需要做的不仅仅是“看起来不错”,必须足够直观,能够在幻灯片或仪表板中独立存在,并且应该足够清晰,能够快速提取出正确的信息。

我最*完成了我的商业分析硕士项目中的一门课程,重点是视觉影响。其目的是弥合上述差距。它是关于如何通过设计获得关注,并将其应用到商业展示中。

为了说明最佳实践,我将从默认的 PowerPoint 图表和表格开始,回答一个简单的问题:2019 年世界上哪个地区最幸福?

删除默认设置的所有内容

你曾经(或通常)见过类似这样的幻灯片吗?

默认 PowerPoint 图表和表格

图表和表格包含了回答问题所需的所有信息,但什么也没有弹出。有一个*淡无奇的条形图,不伦不类的标题,和文本表格。为了回答哪个地区最幸福,我需要直观地比较澳大利亚、北美和西欧,然后参考右边的表格来比较数值。

让我们也考虑几个其他项目:

  • 为什么我们需要一个标有每个数字的 y 轴?没有数字低于 4,我们在右边有数字值。
  • 既然我们只有一组值,我们还需要默认添加的颜色图例吗?
  • 倾斜区域值呢?对于第一次看图表的人来说,这是一个很高的认知负荷。
  • 为什么值按字母顺序排列?
  • 背景网格线是有帮助还是分散注意力?

几个简单的清理步骤解决了上述问题,并开始改进图表设计。

y 轴被移除,并且值被添加到每个条的顶部。通过在顶部添加标签,我们可以删除右边的表格,增加的空间允许我们加宽图表并删除倾斜的部分,而不减小字体大小。图例也被删除,图表标题也有所改进。总之,除了酒吧本身和国名,所有东西都被拿走了。

现在回答我们的问题更容易了,但并不容易。

减少认知负荷

收集正确的数据和选择正确的图表是交流数据的关键步骤,但我们可以做得更多。我们将添加预先注意属性,这是我们可以对可视化进行的微妙改变,以使我们最重要的信息“流行”。我们还将调整图表,使其具有反映我们思维方式的更传统的顺序,即从左到右。

注意使用的预先注意的属性:颜色/阴影、粗体、文本大小

上图有几个重要的变化:

  • 对于色觉缺陷的人来说,蓝色的默认颜色是具有挑战性的。包容性设计意味着我们应该假设至少有一个观众会受到影响。如果你公司的品牌指导方针允许的话,宁可选择非蓝色。
  • 我们通过颜色的预先注意属性将注意力吸引到最高*均分上。就我个人而言,我觉得一种颜色在灰色值的映衬下会很流行。还要注意,除了澳大利亚以外,数据标签的颜色都是灰色的。
  • 接下来,仍然在标签上,澳大利亚的数据标签的大小已经增加,以显示除了粗体以外的层次结构,以吸引对值的进一步注意。

查看图表的观众知道应该看哪里,即使他们还不知道正在回答的问题。

把它带到终点线

信息弹出,我们已经创建了一个逻辑顺序。最后,请记住,我们试图告诉某人 2019 年哪个地区最幸福。这不是一个盛大的信息发布会,所以当我们可以把信息和数据一起给他们时,我们为什么要依赖他们来回答这个问题呢?

我们可以给出一个信息性的标题,而不是描述性的图表标题。对于标题,这意味着数值代表*均幸福分数,所以我们可以删除图表标题。我还将除澳大利亚和新西兰之外的所有地区都变灰了,因为我们对哪个地区是第二、第三等等不感兴趣。

你可能会问,如果我们给出了答案,为什么还要包括其余的数据,这是公*的。它为澳大利亚的价值提供了背景,当信息呈现在观众面前时,观众往往会对答案感到更舒服,而不是认为你给出的答案是理所当然的。

我在底部添加了一个来源,因为我们并不总是知道谁会收到我们的数据,以及他们想用这些数据做什么;添加源减少了您以后可能会收到的额外问题。即使对于内部演示文稿和数据,从何处收集信息也可以帮助您的受众(也可以帮助您在将来的某个时候再次引用这些数据)。

把它放在一起

之前和之后

这个例子既戏剧化又非常真实。看看你最*看过的演示文稿。它看起来更像顶部视觉还是底部?你会对你最*看过的视频做哪两项改进?

我能给的最重要的建议是删除默认添加到视觉效果中的每一条额外的信息和图表设计,并添加最少量的信息来传达你的信息。然后,使用颜色、大小、粗体、间距和其他预先注意的属性来增强你的信息。

仔细检查你创造的每一个视觉效果是需要努力的,但是看到它所产生的改进的讨论和你工作的改进的结果也是非常令人满意的。

对数据可视化感兴趣?你有什么想法要分享吗?欢迎在 LinkedIn 上与我联系,或者在 jordan@jordanbean.com 给我发邮件。

设计关系数据库并创建实体关系图

原文:https://towardsdatascience.com/designing-a-relational-database-and-creating-an-entity-relationship-diagram-89c1c19320b2?source=collection_archive---------1-----------------------

【Craig Dickson 的 SQL 教程

学习使用 SQL 和免费开源软件创建、更新和查询您自己的全功能关系数据库—第 1 部分

图片由麦克默里朱莉皮克斯拜 | 领证

这是由 3 部分组成的系列文章的第 1 部分,从零开始,带您了解设计、编码、实现和查询关系数据库的过程。参见第 2 部分(使用 MySQL 编码和实现关系数据库) 此处 ,以及第 3 部分(MySQL 中的数据分析—关系数据库中的运算符、连接等) 此处

本教程的所有代码和信息都可以在相关的 GitHub 资源库 中找到。我使用了lucid chart来制作文章中显示的图表。

当我第一次开始在工作中使用数据库和编写 SQL 查询时,我总是有点害怕会不小心删除我公司所依赖的所有生产数据。因此,我对自己做了哪些查询和做了什么非常犹豫。随着时间的推移,我学到了更多关于如何使用不同的风格的结构化查询语言 (SQL 对它的朋友来说)。

在这一系列文章中,我将分享我所学到的知识,从头开始讲述使用 MySQL(和 MySQL 服务器)创建关系数据库的过程,并希望在开始构建自己的数据库的过程中能够充分阐明一些事情,并确信不会意外删除所有数据!

我们首先来看看关系数据库到底是什么以及它是如何工作的,然后浏览构建一个关系数据库的过程,从思考我们希望数据库做什么(或者从同事或客户那里收到解释他们希望它做什么的需求),到规划表及其关系,到编写 SQL 代码来创建和填充数据库本身。最后,我们将在编写查询时获得一些乐趣!

什么是关系数据库?

根据甲骨文的说法,关系数据库是“一种数据库,它存储并提供对彼此相关的数据点的访问”。好,听起来不错!

我们可以使用关系数据库管理系统( RDBMS )在我们的关系数据库中创建、读取、更新和删除(任何数据库的基本功能)信息。RDBMSs 例子包括 Oracle微软 SQl ServerMySQLPostgreSQL 等等。每一种都有其优点和缺点(就像任何与编码相关的东西一样,它们的在线超级支持者),并且 SQL 在每一种中的实现方式都不完全相同。概念是相同的,但是语法关键字可能略有不同,因此通常不太可能在不做一些修改的情况下使用为 Microsoft SQL Server 中的 PostgreSQL 编写的 SQL 代码。

我们将使用 MySQL 社区服务器,因为它是免费的、强大的和开源的,但是其他的也是不错的选择。

在关系数据库中,记录存储在表格中(如果你熟悉 Excel 电子表格的话,可以想一想),其中每一列是一个属性(如产品名称、购买成本、零售价格),每一行代表一个记录(T21)。

例如,类似这样的事情

在这个非常简单的商店示例中,“product_id”、“brand”、“product_name”、“unit_cost”和“unit_sales_price”都是属性,每一行都是特定产品的记录(“酷品牌Luft Extreme 运动鞋”、“竞争品牌Aero Maxima 运动鞋”等)。****

主关键字

这里的每个产品都有一个“产品 id”字段,在上图中显示为红色。这就是所谓的“主键”。数据库中每个表中的每条记录都必须有一个唯一标识它的属性(或属性组合),这就是所谓的主键。

在我们的例子中,一个任意的“product_id”被分配给每个记录。还可以使用由例如“产品名称”和“产品类型”属性组成的“组合键,假设这些属性唯一地标识一个产品(即,酷品牌等从不发布另一个同名产品)。使用哪一个取决于数据的性质——重要的是每个表都有一个主键,它必须是唯一的,并且不能为空。

让关系数据库成为关系数据库的是,您可能不会惊讶地了解到,存储在表中的数据之间的关系。例如,连接到我们上面的产品表,我们可能有一个进一步的表,其中包含我们商店中销售的所有品牌的所有详细信息。****

现在我们有两个表,每个表对应一个特定的实体——我们店里销售的产品,以及生产这些产品的品牌。在我们的品牌表中,品牌名称是主键——每条记录的唯一标识符。

外键

我们可以通过将品牌数据库中的主键作为“外键”包含在产品数据库中来表达这些实体之间的关系(在这种情况下,品牌是产品的生产者)。这意味着每个产品都可以与我们数据库中的适当品牌相关联。

这非常有用,因为这意味着这些表格以一种有意义的方式联系在一起,例如,我们可以很容易地找到负责“Luft Extreme 运动鞋”的联系人的姓名。在本系列的后面,我们将看看如何使用 SQL 代码来实现这一点。

在我们的示例中,我们可以让 products 表中的 brand 属性作为外键来存储这两个表之间的关系。

在这种情况下,有可能(事实上很有可能)每个品牌都有多个相关产品。也有可能每个产品都与一个和一个品牌相关联(这里我们将忽略跨品牌协作)。这意味着我们在这些实体之间有 1 对 N 的关系——一个品牌可能有 N 个产品与之相关联(N 只是表示任何数字),一个产品可能有 1 个品牌与之相关联。**

关系的这个属性,一个实体可以与多少个其他实体有关系,被称为关系的基数。其他关系还有 1 对 1N 对 M (多对多)。我们稍后将讨论这些。

因为每个产品可以有且只有一个品牌,所以将该品牌的唯一标识符(在我们的例子中,品牌名称)存储为该产品的属性是非常合理的。这意味着当我们想要查找存储在品牌表中与特定产品相关的信息时,我们可以很容易地使用品牌列(Cool Brand、Rival Brand 等)的值来“查找”品牌表中的相关信息。

通过这种方式,product 表中的 brand 列可以说是打开其他(“foreign”)表中信息的“钥匙”。

如果我们试图将产品的键存储在 brand 表上,我们必须为每个产品都有一条记录——这使得数据分离毫无意义,并在数据库中产生了不必要的冗余。这就是我们将外键存储在 1 对 N 关系的 N 端的表上的原因。

我们的数据库可能会变得非常复杂,因为我们开始拥有多个彼此具有不同关系的表,但是这里需要关注的基本原则是:

  • 每个表都有一个唯一标识表中每个记录的主键,并且不能为空。
  • 对于表 A 与另一个表的每个关系,它需要一个外键作为表 A 中的属性来定义该关系。

这就是我们如何定义关系数据库中 1 对 N 关系中的数据之间的关系。

设计数据库

一如既往,它将帮助我们在这里浏览一个真实的例子。让我们根据自己的需求设计一个数据库吧!

定义需求

创建数据库时首先要考虑的是我们想要它做什么。这似乎是显而易见的,但值得明确说明。不同的需求将导致不同的信息结构、关系、设计和实现。

同样重要的是要注意,相同的需求可以通过不同的设计和实现来成功地满足,并且不总是有一个最佳的实现来解决特定的问题。肯定有比其他解决方案更好和更差的解决方案,但是我将把这些争论留给堆栈溢出上的线程!

那么我们的用例是什么呢?我们将为德国柏林的一所语言学校创建一个相对简单的数据库。我在柏林当了一段时间的英语教师,所以这是一个让我很感兴趣的例子。而且你知道他们说什么, 写你知道的

写下您的需求是一个好主意,或者如果您正在为客户工作或创建一个数据库供公司的另一个部门使用,请从数据库的最终用户那里获得书面形式的需求。

他们想存储什么信息?我们需要为哪些类型的实体创建表(客户、订单、产品、课程、网站点击、数据下载等)?正如任何利用数据的事情一样,为了使我们的工作最有效,我们需要考虑用例是什么,我们的用户在寻找什么。

下面是我们的示例数据库的要求:

国际语言学校是一所语言培训学校。

它为公司客户提供语言课程,可以根据客户的喜好在学校或办公室进行。学校雇佣教师,每个教师可以教授多门课程。

学校有客户,每个客户都可以通过学校提供多门课程。客户向他们的员工提供课程,员工可以选择参加。

每个课程由一个客户提供。每门课在任何时候都有一个老师。

课程的参与者是客户公司的雇员,即他们为客户公司工作。每个参与者一次只能被一家公司雇用。参与者可以注册一门以上的课程。

请记住,真正的需求文档可能会比这更长更复杂,但这份文档将为我们提供构建示例数据库所需的信息。

根据需求制定计划

首先要做的是仔细阅读需求文档,记下可能成为我们数据库中实体的东西,以及它们之间可能的关系。

在这个阶段,提出问题以阐明需求是很重要的。对于每天与某些东西打交道的人来说,很自然地会认为某些事情是“常识”或显而易见的,而对于来自工作领域之外的人来说,这些事情可能并不明显。此外,人们有时可能不习惯以创建数据库所必需的严谨性来考虑他们工作的这些方面。

这就是我们软技能的用武之地,促进技术型和非技术型员工之间清晰沟通的能力是最有价值的。我们真的不想花很多时间设计、编码和实现一个巨大的数据库,却发现我们假设每个参与者只能选一门课,而事实上他们可以选多门课。规划很重要!**

在获取需求和用 SQL 实现我们的数据库之间的一个非常有用的中间步骤是创建一个实体关系图 (ERD)。正如您所预料的,这是一个图表,它映射了我们将构建到数据库中的实体之间的关系。将此图表放在一起的过程可以帮助我们理顺关系,并在过程中识别重要的见解或冗余属性。

有些人可能会跳过这一步,直接进行编码,但是创建一个 ERD 来确保我们在构建数据库本身之前已经计划好了一切,这是最佳实践,也是强烈推荐的。

识别实体

让我们检查一下需求,看看我们是否能够识别我们的实体。这些通常是人、事物、事件或地点。

只要看一下需求文档的第一段,我们就可以看到客户、办公地点、教师和课程是我们数据库的可能实体。文件的其余部分向我们提供了关于这些实体之间关系的各种信息,还提到了参与者(客户的雇员,但从学校的角度来看,这些是语言课程的参与者)。

所以我们有候选实体:

  • 客户
  • 办公地点
  • 教师
  • 课程
  • 参与者

这些都很重要,我们必须在数据库中处理每一个。出于本文的考虑,我将做一个简化的假设,即每个客户有一个办公室,课程在那里进行(如果它们不在学校本身进行)。在现实生活中,一个客户可能有多个办公室,或者他们可能有一个大型设施,在多个地点开设不同的课程。我们可以使用 RDBMS 轻松地处理这个问题,但是为了降低复杂性,我们将假设每个客户端都有一个存放它们的类的位置。

这意味着我们将为以下实体创建表格:客户、教师、课程和参与者。好东西!

我们想要存储哪些属性?

我们的下一步是考虑我们希望为每个实体存储哪些属性。这可能会在我们的需求文档中详细说明,或者可能需要数据库开发人员更加谨慎。

先说教师实体。我们将希望存储教师的姓名,可能是他们的出生日期,他们的联系信息,税收或法律信息,以及—因为这是一所语言学校—他们教授的语言。这可能会给我们一个这样的开始。

一个简单的实体,详细描述了我们希望为 ERD 的教师存储的数据

在现实生活中,我们可能会存储更多的详细信息(例如,教师的地址、他们在学校的开始日期、他们的教学支付率等),但对于我们的目的来说,这就足够了。

请注意,我们在这里创建了一个任意的‘teacher _ id’作为我们的主键。我们可以尝试使用名和姓的组合来获得一个自然键,但是如果我们的学校将来雇佣了两个同名的老师,该怎么办呢?或许不太可能,但绝对不是不可能。这些是我们在计划阶段需要考虑的事情。

我们对每个实体重复这个过程,考虑哪些信息是相关的。在这个过程中,我们经常会发现,我们所认为的属性可能更好地表示为它自己的表,或者我们可能会注意到相同的信息被冗余地存储在两个表中。这些都是通过在数据库构建过程中创建 ERD 而获得的见解,通过尽早发现可能的问题,为我们节省了时间。

让我们对剩下的实体也这样做,从客户端实体开始。

我们 ERD 所代表的客户实体

这里,我们存储了客户名称、地址和行业属性,以及唯一的客户 id。

现在对于课程实体:

我们的 ERD 所代表的课程实体

这里,我们再次使用 course_id 作为任意主键,同时使用一些非常重要的属性,如课程名称、语言和级别、开始日期和持续时间、课程教师、客户,以及课程是在学校还是在客户的办公室进行。

现在请注意,这里有一个教师字段和一个客户字段。我们也有教师和客户的实体。这就是我们的关系数据库变得相关的地方!

我们想要做的是将实体(以及数据库中相应的表)相互连接起来,我们可以使用这些属性作为外键来实现这一点。为了更清楚地理解这一点,让我们更详细地看看教师课程关系。

映射关系

在我们的需求文档中,说明了每门课程一次只能有一个老师,这在这种情况下是有意义的。还澄清了一名教师可能教授多门课程(这也是有道理的,一名教师很难支付每周只教一门课的费用)。所以我们这里有一个 1 对 N 的关系!

我们可以在我们的 ERD 中这样建模:

教师和课程实体之间的关系,如我们的 ERD 中所模拟的

在 ERD,我们通过关系将这些联系起来。这通常(但不总是)用动词来建模。在我们的例子中,我们可以说老师教一门课,或者反过来说,一门课是由老师教的。把这种关系想象成基于动词‘teachers’是有道理的。请注意,图中的“教师”字段现在是绿色的,以提醒我们该属性是一个外键,它引用教师实体中的 teacher_id 属性。

这里的单线和双线是指关系中实体的参与级别。双线表示完全参与,这意味着表中的每个实体都必须参与到关系中——在我们的例子中,这意味着每门课程都必须有一名教师。单线表示部分参与,因此在我们的例子中,可能存在一些教师,他们还没有或目前没有教授任何课程。这里的是对这种区别的一个稍微长一点的解释,如果你想读更多的话。

我们可以做同样的事情来模拟客户和课程之间的关系。每个客户可以在整个学校提供多门课程,但是每门课程最多只能与一个客户相关联,所以我们还是有一对多的关系。

客户和课程实体之间的关系,在我们的 ERD 中建模

这种关系两边的实体有双线,表示这种关系两边的全部参与。这是有意义的,因为国际语言学校只代表客户公司向那些客户的员工提供课程。因此,每个课程必须与一个客户相关联,并且每个客户必须与至少一个课程相关联是有意义的。

我们要建模的最后一个实体是我们的参与者表,其中存储了参与者的姓名、电话号码、作为主键的 participant_id 以及雇佣该参与者的客户的姓名:

我们的 ERD 所代表的参与实体

你可以看到客户端是绿色的,希望你现在知道为什么了。如果您说“因为客户字段被用作外键来存储客户和参与者之间的关系”,那么您就赢了!(奖品是你从学习中获得的温暖感)。

同样,这是一个 1 对 N 的关系——客户机可能雇用多个参与者,参与者可能只为一个客户机工作——由于每个参与者只能为一个客户机工作,所以外键存储在参与者表中。

如果我们将所有这些放在一起,再加上一点点工作(我们将马上完成),我们就可以创建最终的、完整的实体关系图:

凝视它!漫威!

请注意,参与者实体和课程实体之间的关系,这里建模为“takes”(即参与者参加课程,课程由参与者参加),是多对多或 N 对 M 的关系。N-to-M 关系不能简单地通过使用外键来处理,而是需要我们在数据库模式中构建一个单独的表。我们将在第 2 部分中详细讨论这一点。

在本文中,我们介绍了什么是关系数据库以及它如何工作的基本概念,讨论了一些不同的可用 RDBMS 包,并经历了创建实体关系图来描述我们想要基于需求文档构建的数据库的整个过程。太多了!

在本系列的下一部分使用 MySQL 编码和实现关系数据库、中,我们将更进一步,实际上使用 MySQL 社区服务器完全实现这个数据库。那里见!

非常感谢您抽出时间陪我踏上这段旅程。我随时欢迎您的反馈——请通过我的网站与我联系,让我知道我该如何更有效地做这件事!我总是乐于接受建设性的批评,或者你的任何意见。

下次见!

更像这样?访问craigdoedata . de

用线性规划设计能源套利策略

原文:https://towardsdatascience.com/designing-an-energy-arbitrage-strategy-with-linear-programming-f60734fe9888?source=collection_archive---------43-----------------------

如何利用 Python 中的真实数据和开源工具(包括 PuLP 和 pandas ),使用经典的数学优化技术来指导并网电池的运行并实现利润最大化。

电力线,照片由 Pexels 的 Pok Rie 拍摄

能源的价格每小时都在变化,这为时间套利提供了可能性:低价购买能源,储存起来,然后以更高的价格出售。要成功执行任何时间套利策略,需要对未来价格有一定的信心,才能期望获利。在能量套利的情况下,还必须考虑能量存储系统的约束。例如,电池具有有限的容量、有限的充电速率,并且不是 100%有效的,因为不是所有用于对电池充电的能量都可以在以后用于放电。

本文的目的是说明在已知未来价格的假设下,如何使用线性规划的数学优化技术,在给定一组操作约束的情况下,为并网电池设计操作策略。所有这些都将使用真实世界的能源价格数据和 Python 中的开源工具来完成。Jupyter 笔记本可在此处获得

问题和方法

任务是为并网电池系统制定运营策略,在纽约独立系统运营商(NYISO)日前市场进行能源套利。什么是尼索?根据他们的网站

ny iso 是纽约独立系统运营商,负责管理纽约电网及其竞争激烈的电力批发市场。

纽约国际标准化组织每天上午 11 点公布第二天的每小时能源价格(纽约 ISO 2019,参考资料见下页)。我们在这里设计的电池系统将利用这些信息安排接下来 24 小时的电池工作(当天中午到第二天上午 11 点)。我们将假设在 NYISO 发布每日价格公告后,接下来 36 小时的价格信息是可用的:当天剩余 12 小时的价格,以及第二天 24 小时的价格。因此,优化时间范围将是 36 小时,以利用所有可用的未来价格信息。

由于每天都会重复运行时间表,因此 36 小时策略的最后 12 小时将始终被忽略。这是因为新的价格信息将在第二天上午 11 点提供,我们可以利用这一点。然而,这些“额外的 12 小时”的数据并没有被浪费;我在最初的实验中确定,36 小时的时间范围比更短的时间范围更有利可图。这具有直观的意义,因为我们能够纳入套利策略的未来信息越多,就应该越有利可图。您可以使用下面的代码尝试不同的时间范围,尽管这里假设时间范围至少为 24 小时。该计划可以想象如下:

电池被称为价格接受者,这意味着它的活动不会影响能源的价格。为电池充电而支付的电力价格和放电收入是基于位置的边际价格(LBMP),它考虑了系统边际价格、阻塞部分和边际损耗部分(PJM 互联有限责任公司)。目标是在给定日前价格和电池系统参数的情况下,实现利润最大化。

在这种情况下,未来价格已知,电池系统是价格接受者,设计运营策略的问题可以通过线性规划来解决(Salles et al. 2017,Sioshansi et al. 2009,Wang and Zhang 2018)。简而言之,线性规划是一种众所周知的技术,用于最大化或最小化某些目标。在这种情况下,我们希望利润最大化。只要描述目标的数学函数,即所谓的目标函数,以及系统的约束,都可以描述为定义操作策略的决策变量的线性组合,就可以使用线性规划来优化系统。

纸浆中线性规划问题的建立

大致遵循 Sioshansi 等人(2009 年)的符号,这里我们将列出决策变量,并将约束添加到 PuLP 中的线性规划模型。从下一个单元格中的类定义开始,本节中的 markdown 代码片段应该放在一起定义一个类,该类描述了我们的电池系统(请参见笔记本进行确认)。这种系统模型将有助于模拟电池的运行,以每天一次的增量逐步通过时间。

在继续之前,让我们导入本练习所需的包。

*#Load packages* import pulp
import os
import numpy **as** np
import pandas **as** pd
import matplotlib **as** mpl
import matplotlib.pyplot **as** plt
import time
**%**matplotlib inline

每天,在上午 11 点到下午 12 点之间需要解决一个优化问题,这将提供足够的信息来指导电池在接下来的 36 个小时内的运行。为了指导电池的运行,我们需要确定时间范围内每个离散时间步长的能量流。能量流,也称为电能,可以流入或流出电池。因此,我们将在时间 t 创建两个决策变量, c_td_t,分别作为充电和放电功率流(kW),这将是一个小时的时间步长。对于所有时间步长,充电或放电速率是连续变量,并且被限制在电池的工作极限内:

其中 κ (kW)是最大充电和放电功率容量,这里我们假设它们相等。

我们需要在优化的时间范围内为每个时间步长指定流量变量。PuLP 提供了一个LpVariable类的便捷方法dicts,我们可以用它来一次为所有时间步骤创建充电和放电流。我们将开始定义一个类来保存管理电池运行的所有信息。输入time_horizon是一个整数,指定优化范围内的小时数,这里假设至少为 24,其他输入如上所述:

**class** **Battery**():

    **def** **__init__**(self,
                 time_horizon,
                 max_discharge_power_capacity,
                 max_charge_power_capacity):
        *#Set up decision variables for optimization.
*        *#These are the hourly charge and discharge flows for
*        *#the optimization horizon, with their limitations.
*        self**.**time_horizon **=** time_horizon

        self**.**charge **=** \
        pulp**.**LpVariable**.**dicts(
            "charging_power",
            ('c_t_' **+** str(i) **for** i **in** range(0,time_horizon)),
            lowBound**=**0, upBound**=**max_charge_power_capacity,
            cat**=**'Continuous')

        self**.**discharge **=** \
        pulp**.**LpVariable**.**dicts(
            "discharging_power",
            ('d_t_' **+** str(i) **for** i **in** range(0,time_horizon)),
            lowBound**=**0, upBound**=**max_discharge_power_capacity,
            cat**=**'Continuous')

设置好所有的决策变量后,就该定义纸浆将为我们解决的优化问题了。我们的目标是在优化时间范围内最大化利润 P ,可使用电荷流和能源价格定义如下:

其中 p_t 是时间 t 时的 LBMP ($/MWh)。就单位而言,因为 t 是一个小时时间步长,它有效地取消了 LBMP 单位的每小时部分。目标函数除以 1000 以说明单位(MW/kW)的差异,因此最终利润的目标将以美元为单位。我们将在运行模拟后进行这个单元修正,所以它不会反映在这里的代码中。

目标函数是通过将决策变量添加到纸浆中的模型对象来指定的,将每个决策变量乘以适当的成本或收入,该成本或收入将来自充入或释放该量的能量。决策变量与价格的相乘是使用LpAffineExpression完成的。prices由 LBMP 决定,我们将在运行模拟时选择相关的时间段。例如,对于 36 小时的时间范围,这将是当天中午到第二天晚上 11 点。

 **def** **set_objective**(self, prices):
        *#Create a model and objective function.
*        *#This uses price data, which must have one price
*        *#for each point in the time horizon.
*        **try**:
            **assert** len(prices) **==** self**.**time_horizon
        **except**:
            **print**('Error: need one price for each hour in time horizon')

        *#Instantiate linear programming model to maximize the objective
*        self**.**model **=** pulp**.**LpProblem("Energy arbitrage", pulp**.**LpMaximize)

        *#Objective is profit
*        *#This formula gives the daily profit from charging/discharging
*        *#activities. Charging is a cost, discharging is a revenue
*        self**.**model **+=** \
        pulp**.**LpAffineExpression(
            [(self**.**charge['c_t_' **+** str(i)],
              **-**1*****prices[i]) **for** i **in** range(0,self**.**time_horizon)]) **+**\
        pulp**.**LpAffineExpression(
            [(self**.**discharge['d_t_' **+** str(i)],
              prices[i]) **for** i **in** range(0,self**.**time_horizon)])

已经定义了模型和目标,现在我们需要添加电池的操作约束。电池容量有限,因此优化受电池存储限制:

其中 t_f =从当天下午 1 点到第二天晚上 11 点的每个小时, s_i 是 36 小时优化期开始时电池的能量状态(kWh)η是电池的往返效率。该约束要求电池的能量状态(初始状态和每小时功率流的总和)在零(假设电池具有完全深度的放电能力)和电池在优化范围内每小时的放电能量容量之间。在此约束条件下,功率流(kW)被理解为通过乘以一小时时间步长转换为能量单位(kWh)。

在 PuLP 中,约束可以像目标函数一样添加到模型中:使用加法语法。我们可以通过使用lpSum将放电流量相加来表达这些约束,如果充电流量需要乘以效率,则再次使用LpAffineExpression

 **def** **add_storage_constraints**(self,
                                efficiency,
                                min_capacity,
                                discharge_energy_capacity,
                                initial_level):
        *#Storage level constraint 1
*        *#This says the battery cannot have less than zero energy, at
*        *#any hour in the horizon
*        *#Note this is a place where round-trip efficiency is factored in.
*        *#The energy available for discharge is the round-trip efficiency
*        *#times the energy that was charged.       
*        **for** hour_of_sim **in** range(1,self**.**time_horizon**+**1):     
            self**.**model **+=** \
            initial_level \
            **+** pulp**.**LpAffineExpression(
                [(self**.**charge['c_t_' **+** str(i)], efficiency)
                 **for** i **in** range(0,hour_of_sim)]) \
            **-** pulp**.**lpSum(
                self**.**discharge[index]
                **for** index **in**('d_t_' **+** str(i)
                             **for** i **in** range(0,hour_of_sim)))\
            **>=** min_capacity

        *#Storage level constraint 2
*        *#Similar to 1
*        *#This says the battery cannot have more than the
*        *#discharge energy capacity
*        **for** hour_of_sim **in** range(1,self**.**time_horizon**+**1):
            self**.**model **+=** \
            initial_level \
            **+** pulp**.**LpAffineExpression(
                [(self**.**charge['c_t_' **+** str(i)], efficiency)
                 **for** i **in** range(0,hour_of_sim)]) \
            **-** pulp**.**lpSum(
                self**.**discharge[index]
                **for** index **in** ('d_t_' **+** str(i)
                              **for** i **in** range(0,hour_of_sim)))\
            **<=** discharge_energy_capacity

最大日放电吞吐量 τ (kWh)也受到限制,这限制了在给定的一天内可以流过电池的能量。我们对此进行了设置,以便时间范围的第一天受 24 小时约束,而超出该时间范围的任何部分都受部分约束。例如,在我们的 36 小时范围内,约束条件是:

 **def** **add_throughput_constraints**(self,
                                   max_daily_discharged_throughput):
        *#Maximum discharge throughput constraint
*        *#The sum of all discharge flow within a day cannot exceed this
*        *#Include portion of the next day according to time horizon
*        *#Assumes the time horizon is at least 24 hours
*        
        self**.**model **+=** \
        pulp**.**lpSum(
            self**.**discharge[index] **for** index **in** (
                'd_t_' **+** str(i) **for** i **in** range(0,24))) \
        **<=** max_daily_discharged_throughput

        self**.**model **+=** \
        pulp**.**lpSum(
            self**.**discharge[index] **for** index **in** (
                'd_t_' **+** str(i) **for** i **in** range(25,self**.**time_horizon))) \
        **<=** max_daily_discharged_throughput \
        *****float(self**.**time_horizon**-**24)**/**24

既然我们已经建立了具有目标函数和所有约束的模型,我们包括解决问题的方法,并报告结果,即在时间范围内每小时的最佳充电和放电流量。只要我们提出的问题在我们指出的约束条件下是可行的,线性规划就应该工作,因为它会找到一个最优解,使利润最大化。然而,如果没有,我们将返回一条消息指出这一点。

 **def** **solve_model**(self):
        *#Solve the optimization problem
*        self**.**model**.**solve()

        *#Show a warning if an optimal solution was not found
*        **if** pulp**.**LpStatus[self**.**model**.**status] **!=** 'Optimal':
            **print**('Warning: ' **+** pulp**.**LpStatus[self**.**model**.**status])

    **def** **collect_output**(self):  
        *#Collect hourly charging and discharging rates within the
*        *#time horizon
*        hourly_charges **=**\
            np**.**array(
                [self**.**charge[index]**.**varValue **for**
                 index **in** ('c_t_' **+** str(i) **for** i **in** range(0,24))])
        hourly_discharges **=**\
            np**.**array(
                [self**.**discharge[index]**.**varValue **for**
                 index **in** ('d_t_' **+** str(i) **for** i **in** range(0,24))])

        **return** hourly_charges, hourly_discharges

这就完成了Battery课。我们现在准备接收数据,并继续模拟电池工作。

导入价格数据

我们获得了一年的 LBMPs 值,因此我们可以模拟电池在这段时间内的运行情况。这些数据可作为几个区域的 LBMPs,以每小时为时间步长。这里我们加载 CSV 文件(每天一个)并将它们连接到一个DataFrame。您可以从这篇博文附带的 git repo 中获得这些数据。数据于 2020 年 5 月 2 日从这里下载,作为 CSV 文件的压缩目录(定价数据、LBMP 日前市场(DAM)、区域 P-2A)。

*#Directory of data* data_dir **=** './data_2019_2020_from_web/'dir_list **=** os**.**listdir(data_dir)
dir_list**.**sort()
dir_list['.DS_Store',
 '20190501damlbmp_zone_csv',
 '20190601damlbmp_zone_csv',
 '20190701damlbmp_zone_csv',
 '20190801damlbmp_zone_csv',
 '20190901damlbmp_zone_csv',
 '20191001damlbmp_zone_csv',
 '20191101damlbmp_zone_csv',
 '20191201damlbmp_zone_csv',
 '20200101damlbmp_zone_csv',
 '20200201damlbmp_zone_csv',
 '20200301damlbmp_zone_csv',
 '20200401damlbmp_zone_csv']*#Remove invisible files (i.e. .DS_Store used by Mac OS)* **for** this_item **in** dir_list:
    **if** this_item[0] **==** '.':
        dir_list**.**remove(this_item)

遍历所有子目录,加载所有 CSV 文件。

tic **=** time**.**time()
*#count loaded files* file_counter **=** 0

*#For each subdirectory in the parent directory* **for** this_sub_dir **in** dir_list:
    *#List the files
*    this_sub_dir_list **=** os**.**listdir(data_dir **+** '/' **+** this_sub_dir)
    *#Sort the list
*    this_sub_dir_list**.**sort()
    *#Delete invisible files (that start with '.')
*    **for** this_item **in** this_sub_dir_list:
        **if** this_item[0] **==** '.':
            this_sub_dir_list**.**remove(this_item)
    *#For each file in the subdirectory
*    **for** this_file **in** this_sub_dir_list:
        *#Load the contents into a DataFrame
*        this_df **=** pd**.**read_csv(data_dir **+** '/' **+** this_sub_dir **+** '/' **+** this_file)
        *#Concatenate with existing data if past first file
*        **if** file_counter **==** 0:
            all_data **=** this_df**.**copy()
        **else**:
            all_data **=** pd**.**concat([all_data, this_df])

        file_counter **+=** 1
toc **=** time**.**time()
**print**(str(toc**-**tic) **+** ' seconds run time')2.1731250286102295 seconds run time

检查数据

all_data**.**info()<class 'pandas.core.frame.DataFrame'>
Int64Index: 131760 entries, 0 to 359
Data columns (total 6 columns):
 #   Column                             Non-Null Count   Dtype  
---  ------                             --------------   -----  
 0   Time Stamp                         131760 non-null  object 
 1   Name                               131760 non-null  object 
 2   PTID                               131760 non-null  int64  
 3   LBMP ($/MWHr)                      131760 non-null  float64
 4   Marginal Cost Losses ($/MWHr)      131760 non-null  float64
 5   Marginal Cost Congestion ($/MWHr)  131760 non-null  float64
dtypes: float64(3), int64(1), object(2)
memory usage: 7.0+ MBall_data**.**head()

对数据进行健全性检查。考虑到我们有 12 个月的数据,包括闰年的 2 月 29 日,是否加载了 366 天的数据?

**assert** file_counter **==** 366

有多少个区域,它们是什么?

unique_names **=** all_data['Name']**.**unique()
**print**(len(unique_names))
unique_names15

array(['CAPITL', 'CENTRL', 'DUNWOD', 'GENESE', 'H Q', 'HUD VL', 'LONGIL',
       'MHK VL', 'MILLWD', 'N.Y.C.', 'NORTH', 'NPX', 'O H', 'PJM', 'WEST'],
      dtype=object)

有多少排?

all_data**.**shape(131760, 6)

检查行数=区域数乘以一天 24 小时乘以一年 366 天:

**assert** 15*****24*****366 **==** all_data**.**shape[0]

对于这个例子,我们只关心纽约市。选择感兴趣的数据(特定区域):

zone_of_interest **=** 'N.Y.C.'
all_data **=** all_data**.**loc[all_data['Name']**.**isin([zone_of_interest]),:]all_data**.**shape(8784, 6)

有了DatetimeIndexDataFrame会更容易使用。将索引重置为时间戳:

all_data **=** all_data**.**set_index(['Time Stamp'])

扮成datetime:

all_data**.**index **=** pd**.**to_datetime(all_data**.**index, format**=**'%m/%d/%Y %H:%M')

让我们看看夏令时前后的数据:

start_time **=** pd**.**Timestamp(year**=**2019, month**=**11, day**=**2, hour**=**23)
end_time **=** pd**.**Timestamp(year**=**2019, month**=**11, day**=**3, hour**=**3)time_test_1 **=** all_data[start_time:end_time]
time_test_1

我们可以看到凌晨 1 点有两个条目,其中第二个条目是时钟“倒转”的结果。为了用这个DatetimeIndex做算术,我们需要让它知道时区。Pandas 简化了这一过程,并适当地处理了重复的 1am 行:

all_data**.**index **=** \
all_data**.**index**.**tz_localize('America/New_York', ambiguous**=**'infer')time_test_2 **=** all_data[start_time:end_time]
time_test_2

现在我们可以看到,相对于 UTC 的偏移量已显示出来。在继续之前,让我们仔细检查一下数据的开头和结尾。

all_data**.**head()

all_data**.**tail()

看起来数据像预期的那样,从 2019 年 5 月 1 日到 2020 年 4 月底跨越了一年。

运行模拟

在本节中,我们将定义一个函数simulate_battery,它模拟电池在一年中的能量套利操作。以下是该函数的输入:

  • initial_level,模拟开始时电池充电的初始水*(kWh)
  • price_data、每小时 LBMP 的DataFrame($/MWh)
  • max_discharge_power_capacityκ (千瓦)
  • max_charge_power_capacity,亦作 κ (kW)
  • discharge_energy_capacity(千瓦小时)
  • efficiency、交-交往返效率、、η (无单位)
  • max_daily_discharged_throughputτ (千瓦时)
  • time_horizon,优化时间范围(h),这里假设大于等于 24。
  • start_day,一只熊猫Timestamp在第一个模拟日的中午

该函数返回几个可用于检查系统操作的输出:

  • all_hourly_chargesall_hourly_dischargesall_hourly_state_of_energy、充电和放电活动以及能量状态,以每小时为时间步长(kWh)
  • all_daily_discharge_throughput、每日时间步长的排放吞吐量(kWh)
**def** **simulate_battery**(initial_level,
                     price_data,
                     max_discharge_power_capacity,
                     max_charge_power_capacity,
                     discharge_energy_capacity,
                     efficiency,
                     max_daily_discharged_throughput,
                     time_horizon,
                     start_day):
    *#Track simulation time
*    tic **=** time**.**time()

    *#Initialize output variables
*    all_hourly_charges **=** np**.**empty(0)
    all_hourly_discharges **=** np**.**empty(0)
    all_hourly_state_of_energy **=** np**.**empty(0)
    all_daily_discharge_throughput **=** np**.**empty(0)

    *#Set up decision variables for optimization by
*    *#instantiating the Battery class
*    battery **=** Battery(
        time_horizon**=**time_horizon,
        max_discharge_power_capacity**=**max_discharge_power_capacity,
        max_charge_power_capacity**=**max_charge_power_capacity)

    *#############################################
*    *#Run the optimization for each day of the year.
*    *#############################################
*    
    *#There are 365 24-hour periods (noon to noon) in the simulation,
*    *#contained within 366 days
*    **for** day_count **in** range(365):
        *#print('Trying day {}'.format(day_count))
*        
        *#############################################
*        *### Select data and simulate daily operation
*        *#############################################
*        
        *#Set up the 36 hour optimization horizon for this day by
*        *#adding to the first day/time of the simulation
*        start_time **=** start_day \
        **+** pd**.**Timedelta(day_count, unit**=**'days')
        end_time **=** start_time **+** pd**.**Timedelta(time_horizon**-**1, unit**=**'hours')
        *#print(start_time, end_time)
*    
        *#Retrieve the price data that will be used to calculate the
*        *#objective
*        prices **=** \
        price_data[start_time:end_time]['LBMP ($/MWHr)']**.**values

        *#Create model and objective
*        battery**.**set_objective(prices)

        *#Set storage constraints
*        battery**.**add_storage_constraints(
            efficiency**=**efficiency,
            min_capacity**=**0,
            discharge_energy_capacity**=**discharge_energy_capacity,
            initial_level**=**initial_level)

        *#Set maximum discharge throughput constraint
*        battery**.**add_throughput_constraints(
            max_daily_discharged_throughput**=**
            max_daily_discharged_throughput)

        *#Solve the optimization problem and collect output
*        battery**.**solve_model()
        hourly_charges, hourly_discharges **=** battery**.**collect_output()

        *#############################################
*        *### Manipulate daily output for data analysis
*        *#############################################
*        
        *#Collect daily discharge throughput
*        daily_discharge_throughput **=** sum(hourly_discharges)
        *#Calculate net hourly power flow (kW), needed for state of energy.
*        *#Charging needs to factor in efficiency, as not all charged power
*        *#is available for discharge.
*        net_hourly_activity **=** (hourly_charges*****efficiency) \
        **-** hourly_discharges
        *#Cumulative changes in energy over time (kWh) from some baseline
*        cumulative_hourly_activity **=** np**.**cumsum(net_hourly_activity)
        *#Add the baseline for hourly state of energy during the next
*        *#time step (t2)
*        state_of_energy_from_t2 **=** initial_level \
        **+** cumulative_hourly_activity

        *#Append output
*        all_hourly_charges **=** np**.**append(all_hourly_charges, hourly_charges)
        all_hourly_discharges **=** np**.**append(
            all_hourly_discharges, hourly_discharges)
        all_hourly_state_of_energy **=** \
        np**.**append(all_hourly_state_of_energy, state_of_energy_from_t2)
        all_daily_discharge_throughput **=** \
        np**.**append(
            all_daily_discharge_throughput, daily_discharge_throughput)

        *#############################################
*        *### Set up the next day
*        *#############################################
*        
        *#Initial level for next period is the end point of current period
*        initial_level **=** state_of_energy_from_t2[**-**1]

    toc **=** time**.**time()

    **print**('Total simulation time: ' **+** str(toc**-**tic) **+** ' seconds')

    **return** all_hourly_charges, all_hourly_discharges, \
        all_hourly_state_of_energy,\
        all_daily_discharge_throughput

现在,我们将全年运行我们的模拟,使用以下电池参数的说明性值。

max_discharge_power_capacity **=** 100 *#(kW)* max_charge_power_capacity **=** 100 *#(kW)* discharge_energy_capacity **=** 200 *#(kWh)* efficiency **=** 0.85 *#unitless* max_daily_discharged_throughput **=** 200  *#(kWh)*

首先,我们假设电池充电到一半就可以启动。

initial_level **=** discharge_energy_capacity**/**2
initial_level100.0all_hourly_charges, all_hourly_discharges, all_hourly_state_of_energy,\
all_daily_discharge_throughput **=** \
simulate_battery(initial_level**=**initial_level,
                 price_data**=**all_data,
                 max_discharge_power_capacity
                     **=**max_discharge_power_capacity,
                 max_charge_power_capacity
                     **=**max_charge_power_capacity,
                 discharge_energy_capacity**=**discharge_energy_capacity,
                 efficiency**=**efficiency,
                 max_daily_discharged_throughput
                     **=**max_daily_discharged_throughput,
                 time_horizon**=**36,
                 start_day**=**pd**.**Timestamp(
                     year**=**2019, month**=**5, day**=**1, hour**=**12,
                     tz**=**'America/New_York'))Total simulation time: 20.976715087890625 seconds

健全性检查:模拟小时数应为:

**assert** 24*****365 **==** len(all_hourly_discharges)

分析电池运行

现在我们来看一组电池如何工作的指标。我们可以检查是否满足了所有的约束,并分析我们系统的财务影响。

功率输出

定义放电为正,充电为负的功率输出。

mpl**.**rcParams["figure.figsize"] **=** [5,3]
mpl**.**rcParams["figure.dpi"] **=** 100
mpl**.**rcParams**.**update({"font.size":12})plt**.**hist(all_hourly_discharges **-** all_hourly_charges)
plt**.**xlabel('kW')
plt**.**title('Hourly power output')Text(0.5, 1.0, 'Hourly power output')

这表明在一年中的大部分时间里,电力接*于零。换句话说,电池既不充电也不放电。然而,电池在其范围[-100,100] kW 的极限下运行也是常见的。

能量状态

在任何时候,电池的能量状态应不小于零,且不大于放电能量容量:[0,200] kWh。

plt**.**hist(all_hourly_state_of_energy)
plt**.**xlabel('kWh')
plt**.**title('Hourly state of energy')Text(0.5, 1.0, 'Hourly state of energy')

结果表明电池在规定的能量状态范围内工作。

收入、成本和利润

我们将分析以下财务指标:

  • 年收入总额(美元)
  • 年度总收费成本(美元)

稍后,我们还将了解总的年排放吞吐量(kWh)。为了检查所有这些,将数据放在一个DataFrame中是很方便的。

根据模拟的时间范围选择一个新的DataFrame,以报告进一步的结果:

all_data_sim_time **=** all_data[
    pd**.**Timestamp(year**=**2019, month**=**5, day**=**1, hour**=**12, tz**=**'America/New_York'):
    pd**.**Timestamp(year**=**2020, month**=**4, day**=**30, hour**=**11, tz**=**'America/New_York')]**.**copy()

检查行数是否正确:

all_data_sim_time**.**shape(8760, 5)**assert** all_data_sim_time**.**shape[0] **==** len(all_hourly_discharges)

附加模拟结果

*#These indicate flows during the hour of the datetime index* all_data_sim_time['Charging power (kW)'] **=** all_hourly_charges
all_data_sim_time['Discharging power (kW)'] **=** all_hourly_discharges
all_data_sim_time['Power output (kW)'] **=** \
    all_hourly_discharges **-** all_hourly_charges
*#This is the state of power at the beginning of the hour of the datetime index* all_data_sim_time['State of Energy (kWh)'] **=** \
    np**.**append(initial_level, all_hourly_state_of_energy[0:**-**1])

收入和成本的单位是

所以除以 1000 调整为美元:

all_data_sim_time['Revenue generation ($)'] **=** \
all_data_sim_time['Discharging power (kW)'] \
***** all_data_sim_time['LBMP ($/MWHr)'] **/** 1000all_data_sim_time['Charging cost ($)'] **=** \
all_data_sim_time['Charging power (kW)'] \
***** all_data_sim_time['LBMP ($/MWHr)'] **/** 1000all_data_sim_time['Profit ($)'] **=** all_data_sim_time['Revenue generation ($)'] \
**-** all_data_sim_time['Charging cost ($)']

年总收入是多少?

all_data_sim_time['Revenue generation ($)']**.**sum()2354.6574498602467

每年总充电成本?

all_data_sim_time['Charging cost ($)']**.**sum()1391.6754123382877

计算利润

all_data_sim_time['Profit ($)']**.**sum()962.9820375219592

因此,我们可以通过执行能源套利获得* 963 美元的利润。

总年排放吞吐量

一年中有多少能量流过这个电池?在某些情况下,每天的排放总量限制在 200 千瓦时/天。如果电池在 365 天的模拟过程中每天都释放其最大可能能量,则总放电量为:

365*****200
*#kWh*73000

事实上它是:

sum(all_daily_discharge_throughput)72955.00000394997

这意味着系统在大多数日子里达到了最大排出吞吐量限制。我们可以通过对日吞吐量的Series进行value_counts()来检查这一点。

pd**.**Series(all_daily_discharge_throughput**.**round(0))**.**value_counts()200.0    364
155.0      1
dtype: int64

除了一天之外,电池一直以最大生产能力运行。

找到最赚钱的一周

按周对利润列进行分组,并找到最大值:

max_profit_week **=** (all_data_sim_time['Profit ($)']**.**resample('W')**.**sum() **==** \
all_data_sim_time['Profit ($)']**.**resample('W')**.**sum()**.**max())**.**valuesall_data_sim_time['Profit ($)']**.**resample('W')**.**sum()[max_profit_week]Time Stamp
2019-07-21 00:00:00-04:00    51.015471
Freq: W-SUN, Name: Profit ($), dtype: float64

7 月的一周是能源套利最有利可图的一周。本周,让我们制作一个每小时电池能量状态和每小时 LBMP 的图表。

mpl**.**rcParams["figure.figsize"] **=** [8,6]
mpl**.**rcParams["figure.dpi"] **=** 150
mpl**.**rcParams**.**update({"font.size":14})most_profit_week_start **=** pd**.**Timestamp(
    year**=**2019, month**=**7, day**=**21, tz**=**'America/New_York')
ax **=** all_data_sim_time[
    most_profit_week_start:most_profit_week_start**+**pd**.**Timedelta(weeks**=**1)]\
[['State of Energy (kWh)', 'LBMP ($/MWHr)']]\
**.**plot(secondary_y**=**'LBMP ($/MWHr)', mark_right**=**False)

ax**.**set_ylabel('State of energy (kWh)')
ax**.**right_ax**.**set_ylabel('LBMP ($/MWh)')
ax**.**get_legend()**.**set_bbox_to_anchor((0.3, 1))

电池似乎遵循“低买高卖”的一般套利策略,或者在这种情况下,“便宜充电,谨慎放电”,以利用未来的价格变化。可能是在这一周,纽约市相当温暖,导致空调电力需求高,昼夜价格波动大,也是我们的电池系统赚钱的好机会。

月收入

mpl**.**rcParams["figure.figsize"] **=** [6,4]
mpl**.**rcParams["figure.dpi"] **=** 100
mpl**.**rcParams**.**update({"font.size":12})all_data_sim_time['Profit ($)']**.**resample('M')**.**sum()**.**plot()
plt**.**ylabel('Total monthly profit ($)')Text(0, 0.5, 'Total monthly profit ($)')

夏季的利润通常高于冬季,但 1 月和 12 月的利润也很高。LBMP 全年的一幅图对此有所启发:

all_data_sim_time['LBMP ($/MWHr)']**.**plot()
plt**.**ylabel('LBMP ($/MWHr)')Text(0, 0.5, 'LBMP ($/MWHr)')

价格的变化使得套利策略能够获利。一般来说,大多数较大的价格波动发生在夏季,这可能反映了炎热夏季空调使用量的增加。但是 11 月、12 月和 1 月的价格变化很大。这可能是由于纽约市在假日期间的旅游业或寒冷的天气增加了对取暖用电的需求。

结论

我们发现,一个并网电池的能源套利策略可以使用线性规划来制定,假设未来价格在一定时间范围内是已知的。我们表明,当在一组说明性的系统参数下运行并使用真实世界的能源价格数据时,这样一个系统每年可以产生 963 美元的利润。

如果价格能够在这里使用的 36 小时优化范围之外准确预测,则可能会进一步优化以增加利润。NYISO 价格的确定涉及一个负荷预测模型,该模型取决于经济和天气因素。有可能在价格预测模型中包括这些因素,以估计尚未公开的未来一天的市场价格。在另一个有趣的方向上,王和张(2018)表明,使用历史价格数据的强化学习可以比最大化瞬时利润带来更高的利润,这表明了从能源套利中最大化利润的其他可能方法。

我希望这篇文章有助于你理解在未来价格已知的情况下,如何使用线性规划来制定最优套利策略。

参考

所有引用都是在 2020 年 5 月 2 日访问的。

尼索。日前调度手册

PJM 互联有限责任公司。区位边际定价成分

Salles,Mauricio B. C .等人,2017 年。PJM 储能系统潜在套利收益。能量 10:8。

Sioshansi,Ramteen 等人,2009 年。估算 PJM 电力储存的价值:套利和一些福利效应。能源经济学 31:2,269–277。

王,郝,张,2018。通过强化学习在实时市场中进行储能套利。IEEE PES 大会。

我发现这本由 Ben Alex Keen 撰写的指南非常有帮助。

原载于 2020 年 5 月 3 日 https://www.steveklosterman.com

用弹性搜索设计最佳多语言搜索引擎

原文:https://towardsdatascience.com/designing-an-optimal-multi-language-search-engine-with-elasticsearch-3d2de1b9636d?source=collection_archive---------13-----------------------

设计多语言弹性搜索索引的四种不同方法

乔尔·那仁在 Unsplash 上拍摄的照片

当我为 NewsCatcherAPI 设计 Elasticsearch index 时,我遇到的最大问题之一是处理多语言新闻文章。

我知道 Elasticsearch 为最流行的语言预建了分析器。问题是“我如何管理不同语言的文档,以便可以一起搜索(如果需要的话)?”

重要提示:在我们的例子中,我们已经用正确的语言标记了每个文档。尽管如此,这并不是本帖中描述的所有方法都必须的。

同样,对于这个帖子设置,让我们假设每个文档(新闻文章)只有两个字段:**title****language**。其中**language**是标题的语言。为了简单起见,假设只能有两种不同的语言:英语(**en**)和法语(**fr**)。

为什么要关心语言呢?

每种语言在很多方面都不同(我会说 4 种语言,所以给我一些学分)。词汇化词干化停用词。所有这些在每种语言的基础上都是独一无二的。

所以,如果你想让 Elasticsearch 明白“dogs”只是“dog”的复数形式,或者“different”和“different”同根同源——你必须使用语言特定的分析器。(甚至对于英语来说!)

首先,我将描述我在网上找到的两种方法,并解释为什么我不喜欢它们。然后,我将提出我的解决方案,我们曾在新闻发布会上使用过。最后,我会留下一个链接,链接到一个非常先进的方法,可以自动检测语言。

方法 1。多领域

这种方法的思想是使用[**fields**](https://www.elastic.co/guide/en/elasticsearch/reference/7.x/multi-fields.html)参数多次索引文本字段。

例如,如果我们想创建一个索引,用标准、英语和法语分析器索引同一个文本字段:

PUT your_index_name_here
{
  "mappings": {
    "properties": {
      "title": { 
        "type": "text",
        "fields": {
          "en": { 
            "type":     "text",
            "analyzer": "english"
          },
          "fr": { 
            "type":     "text",
            "analyzer": "french"
          }
        }
      }
    }
  }
}

因此,**title**变量被索引 3 次。现在,要搜索所有语言,您必须执行多匹配搜索。例如:

GET your_index_name_here/_search
{
  "query": {
    "multi_match": {
      "query": "ce n'est pas une méthode optimale",
      "fields": [ 
        "title",
        "title.en",
        "title.fr"
      ],
      "type": "most_fields" 
    }
  }
}

多字段方法的优势

  1. 易于实施
  2. 即使数据没有标注语言,也能正常工作

多字段方法的缺点

当你只有两种语言时,这是可以接受的,但是假设你有 10 种语言(就像我们一样)。

  1. 索引时间较慢。每种语言的索引
  2. 更多存储空间。每个语言索引占用存储空间
  3. 昂贵的查询。在阅读更多关于我的另一篇文章

前两点可能没那么糟,然而,第三点就糟了。假设你有 10 种语言。要搜索整个数据库,您必须编写一个多匹配查询,该查询必须同时搜索 10 个不同索引的字段(加上索引碎片的数量)。

综上所述,对于 2-3 种语言的索引(和宽松的预算),这可能是一个可接受的选择。

方法二。多指数

在 Stackoverflow 上可以得到的最流行的答案(假设每个文档的语言在索引前是已知的)。

为每种语言创建单独的索引。例如,一个英文文本的索引我们称之为,法文文本的索引为。

然后,如果你知道搜索的语言,你可以把它导向正确的索引。

多指数方法的优势

  1. 不会多次存储相同的信息

多指数方法的缺点

  1. 管理多个指数。另外,不同语言的文档不会遵循统一的分布
  2. 从集群的角度来看,索引并不是免费的,因为每个索引都有一定程度的资源开销。
  3. 需要通过所有索引来搜索公共字段。

关于最后一点。假设我们有一个时间戳字段,我们想检索本周发表的所有文章。为此,您必须在所有索引上按发布的日期时间字段进行筛选。从技术上讲,这根本不是问题,只需通过通配符从多个索引中搜索你的字段。

例如,如果我们想同时搜索和,只需使用。

但是,这并不比使用多匹配搜索更好。现在是多索引搜索。

方法三。使用摄取处理器识别正确的字段

我的策略如下:

  1. 创建一个索引
  2. 对于每种语言,创建它自己单独的字段(不是子字段)
  3. 设置摄取处理器,根据语言参数值设置**title_{lang}**字段

每种语言都有一个单独的字段

PUT your_index_name_here
{
  "mappings": {
    "properties" : {
        "language" : {
          "type" : "keyword"
        }, 
        "title" : {
          "type" : "text"
        },   
        "title_en" : {
          "type" : "text",
          "analyzer" : "english"
        },  
        "title_fr" : {
          "type" : "text",
          "analyzer" : "french"
        }
      }
    }
}

我们的源数据没有 nor 字段。因此,我们必须设置摄取节点的管道来解决这个问题。

摄取节点

根据官方文件:

在实际的文档索引发生之前,使用摄取节点预处理文档。摄取节点拦截批量和索引请求,应用转换,然后将文档传递回索引或批量 API。

我们将使用一个设置处理器根据**language**值将**title**值“复制”到**title_en****title_fr**

我们必须编写一个简单的无痛脚本来使 set 处理器有条件。

我们创建了一个名为" langdetect "的接收管道

PUT _ingest/pipeline/langdetect
{
  "description": "copies the text data into a specific field depending on the language field",
  "processors": [
		{
      "set": {
        "if": "ctx.language == 'en'",
        "field": "title_en",
        "value": "{{title}}"
      }
    },
	{
      "set": {
        "if": "ctx.language == 'fr'",
        "field": "title_fr",
        "value": "{{title}}"
      }
    }
   ]
}

它有 2 个处理器,将根据**language**字段的值设置**title_en****title_fr**字段。

根据我们的流水线,如果**language**字段的值等于“en ”,那么将**title_en**字段设置为**title**字段中的值。因此,英语文本将由标准分析器(**title**字段)和英语分析器(**title_en**字段)进行分析。

现在,当创建管道时,我们必须将它“附加”到索引上。因此,让我们更新我们的索引设置:

PUT /your_index_name_here/_settings
{
    "default_pipeline" : "langdetect"
}

优势

  1. 支持多语言的单一索引

缺点

  1. 较慢的索引时间
  2. 仅在语言已知时有效

对于 NewsCatcherAPI 的例子,当用户想要用英语搜索时,她必须在我们的 API 中将语言参数设置为**en**。我们,在后端,将通过**title_** + **{lang}**进行搜索,在**en**的情况下是**title_en**。这比那要复杂一点,但应该足以解释这篇博文。

方法 4。检测 Elasticsearch 中的语言,然后进行适当的索引

在 Elasticsearch 中使用语言识别的多语言搜索

结论

当我意识到用 Elasticsearch 管理多语言搜索索引并不容易且显而易见时,有点惊讶。我不得不花很多时间来找出我们用例的最佳情况。

希望这份“小抄”能为你节省一点时间!

如果有不清楚的地方,请在评论中提问。

顺便说一下,如果你需要帮助你的 Elasticsearch 集群/索引/设置,我会提供咨询。

artem[at]news catcher API[dot]com

原载于https://codarium.substack.com

基于遮挡的人脸检测器的设计与开发

原文:https://towardsdatascience.com/designing-and-developing-an-occlusion-based-face-detector-cc4ce8d9aff3?source=collection_archive---------60-----------------------

“增强安全性的最佳方式是通过面部识别——它很快就会成为标准。”—凯莎·威廉姆斯

嗨,大家好,我又带来了另一篇文章,但这次它不是基于任何理论,而是关于开发一个现实世界问题的应用程序。

来源:斯科特·韦伯拍摄的 Pexels 图片

所以,我希望你们都感到兴奋,因为今天我们将学习开发一个成熟的人脸检测系统,它可以处理遮挡的人脸以及其他场景。但是等等,等等…被遮挡的脸是什么意思?被遮挡的脸是指不完全可见的脸,我的意思是它的一部分被一些东西覆盖着,如面具或相机由于遮挡或其他原因无法捕捉到脸部的镜头。

我们为什么需要这个?嗯,这可以在捕捉某人进行一些邪恶的活动或其他事情时找到很多应用。

所以我们的要求是:

  1. 计算机编程语言
  2. 打开简历
  3. 人脸识别模块。

我相信你们都非常熟悉前两个,并且随着我们的深入了解第三个。

这是我们的文章提纲。

  1. 我们将与图像一起使用的文件
  2. 正在生成编码。
  3. 使用人脸检测模型检测人脸[图像+视频]
  4. 结论。

来源:负空间 Pexel

要使用的文件和图像

我们将维护两个名为 gen_encoding.py 的文件,用于生成编码和检测人脸的人脸识别。

我们将使用我们想要检测其面部的人的图像。如果能给我们几张照片就更好了。我们将把这些人的图像存储在一个单独的文件夹中,该文件夹以图像所属的人的名字命名。

生成编码。

import opencv
import face_recognition
import pickle
import cv2for i,image_p in enumerate("image directory path"): 
    image =cv2.imread(image_p))
    name = image_p.split(".")[0]

在上面的代码片段中,我们在顶部导入所需的库,并使用 for 循环从图像目录中串行读取图像,并通过分割图像扩展名来获取图像的名称。

rgb = cv2.cvtColor(image,cv2.COLOR_BGR2RGB) 
boxes = face_recognition.face_locations(rgb,model="cnn")
encodings = face_recognition.face_encodings(rgb,boxes)

在上面的代码片段中,我们根据 face_recognition 库中的模型来转换图像的颜色。

在第二行中,我们从 face_location 函数中获取图像的位置,该函数返回维数的*方。

进一步使用这些位置,我们裁剪出面部区域,并使用 face_recognition 的 face_encodings 功能生成图像编码,该功能使用了特定的神经网络模型来完成一些工作,但我不会详细介绍它,因为它与上下文无关。

encodings=[], known_names= []
for encoding in encodings:
  #Processsing the encodings  known
  encodings.append(encoding)
  known_names.append(name)

在上面的代码中,我们将图像的编码和名称存储在一个列表中,并将它们存储在一个 pickle 文件中,如下所示。

data = {"encoding": known_encodings, "names":known_names}
f =open("encoding file name","wb"):
    f.write(pickle.dumps(data))

使用人脸检测模型检测人脸。

现在编码部分已经足够了。现在,我们将与检测脸的真实切片一起工作。

为了编写我们的代码,我们将使用 face_recognition.py 命名文件。

在下面的代码中,我们将打开如上生成的编码文件,并将其存储在数据变量中。

data = pickle.loads(open(args["encoding"],"rb").read())

用图像检测

在本节中,我们将在提供的图像中进行人脸检测。因此,首先我们将加载图像,并将其转换为标准的颜色格式,我们将生成它的编码进行比较。

image = cv2.imread(os.path.join("image_path"))
rgb = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
boxes= face_recognition.face_locations(rgb,model= "cnn")
encodings = face_recognition.face_encodings(rgb,boxes)*Detection with vidoes*

现在,在下面的代码片段中,我将图像生成的编码与所有已经存储的人脸编码进行比较。如果它们之间的差异低于阈值,我们将其作为相应人脸的编码并用 imshow()函数显示。

for encoding in encodings:
   matches=face_recognition.compare_faces(data,encoding) 
   name = "Unknown"
   if True in matches:
      match_idx = [i for (i,b) in    enumerate(matches) if b]
      counts= {}
      for i in match_idx:
         name = data["names"][i]
         counts[name] =counts.get(name,0)+1
      name = max(counts, key= counts.get)
   names.append(name)
for ((top,right,bottom,left),name) in zip(boxes,names): 
     cv2.rectangle(image,(left,top),(right,bottom),(0,255,0),2)
     y = top-15 if top-15>15 else top+15
     cv2.putText(image,name,(left,y),cv2.FONT_HERSHEY_SIMPLEX,0.45,
     (0,255,0),2)
cv2.imshow("Image",image)

视频帧中的检测

现在重复几乎相同的过程,现在是视频帧而不是图像。

在下面的代码中,我们正在初始化我们电脑的网络摄像头。

vs= VideoStream(src=0).start()

在下面给出的代码中,我们只是读取每一帧,并根据 face_recognition 库中的模型将其转换为标准颜色格式。

现在,我们使用 face_location 函数检测视频帧中的人脸位置,并在代码的最后一行生成其编码。

while True: 
    frame = vs.read()
    rgb = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
    rgb = imutils.resize(rgb,width=750)
    r =frame.shape[1]/float(rgb.shape[1])
    boxes= face_recognition.face_locations(rgb,model="cnn") 
    encodings =face_recognition.face_encodings(rgb,boxes) 
    names=[]

现在,在下面的代码中,我们将帧的编码与已经存储的人脸编码进行比较,如果我们发现差异低于某个阈值,则认为该帧包含编码已经存储的人的人脸。

for encoding in encodings:
    matches=
    face_recognition.compare_faces("encoding.pickle",encoding)       
    name="Unknown"  print(matches)
    if True in matches:
       matchesIdx =[i for (i,b) in matches if b] 
       counts={}
       for i in matchesIdx: 
           name = data["names"][i]
           counts[name]= counts.get(name,0)+1 
       name =max(counts,key= count.get)
   names.append(name)

现在,在下面的代码中,我们只是在脸部周围画一些方框,并在上面显示这个人的名字。

for((top,right,bottom,left),name) in zip(boxes,names):  
    top=int(top*r)
    right=int(right*r) 
    bottom=int(bottom*r)  
    left=int(left*r)  
    cv2.rectangle(frame,(left, top),(right, bottom),(0,255,0),2) 
    y=top-15 if top-15>15 else top+15  
    cv2.putText(frame,name ,(left,y),cv2.FONT_HERSHEY_SIMPLEX,0.75,
    ((0,255,0),2) 
cv2.destroyAllWindows()vs.stop()

万岁…你做到了。恭喜你开发出第一个高级人脸识别模型。

结论:

虽然代码乍一看似乎很复杂,但整个代码背后的概念非常简单。好吧,让我给你简单介绍一下我们所做的一切。首先,我们为所有可用的图像生成了编码。现在,在检测时,我们只是将正在检测的人的编码与已经存储的人的编码进行比较。所以很明显同一个人会表现出较少的差异。如果差异没有超过阈值,我们会将该人脸标记为未知人。简单!!

完整代码可以访问我的 Github 简介

如果你喜欢的内容,并希望更多这样的,跟着我一样。

谢谢你

设计数据密集型应用程序

原文:https://towardsdatascience.com/designing-data-intensive-applications-book-review-cc34ba1f90a7?source=collection_archive---------14-----------------------

数据库和分布式系统用户的现代经典

意识到自己对某件事知之甚少可能是一次令人沮丧的经历。然而,这本书设法使它振奋人心,引人入胜。在设计数据密集型应用中,Martin Kleppmann 首先解释了简单数据库的工作原理,然后介绍了分布式环境中多个系统的交互方式。在这一过程中,他采用了许多我认为我理解的概念,并展示了我从来不知道的深度和复杂性,以提供更彻底的理解。

作者图片

例如,数据库中的 ACID (原子性、一致性、隔离性、持久性)事务(在第七章中介绍)。我已经看过这个缩写一百万次了,我想我已经很好地理解了它。我以为数据库要么提供要么不提供,但你知道吗,它实际上是令人惊讶的模糊?克莱普曼甚至称它主要是一个营销术语。你知道一致性不属于其他人吗?这种隔离实际上可以通过许多不同的严格程度来实现?Kleppmann 在第 7 章中以清晰和吸引人的方式解释了这一切。我觉得我得到了关于数据库如何真正运行的内部消息。

书籍内容

这本书有 12 章,分成 3 个部分。

  1. 数据系统的基础:数据库实际上如何存储数据,索引和它们如何更新,使用的文件类型。
  2. 分布式数据:跨多个节点的数据复制、分区、事务的实际执行方式。
  3. 派生数据:批处理(包括 MapReduce)和流处理。

这些章节是建立在彼此的基础上的,但是你可以浏览你特别感兴趣的章节。如果他提到了书中以前的主题,他会附上更多信息的页码,这样你就不会感到失落。

每一章都以像这样的古怪地图开始。图片作者。

这本书里没有练习,只有几个代码示例。它描述了问题以及如何实现解决方案,但是你不会获得任何解决这些问题的经验。只期望提高你的意识,增加你的理解。

他引用了从 20 世纪 70 年代到 2016 年的数据库和计算历史的大量资料(在某些章节中超过 100 篇)。它们来自书籍和论文,但也有博客文章,甚至黑客新闻聊天讨论(参考第 11 章的 61)。这种多样性,以及它们不都是学术参考,有助于增强你了解全貌的信心。

一路上有一些有趣的花絮。就像 MapReduce 作业中的每个子任务在每一步之间都会写入磁盘,这看起来就像最初开发它的 Google 设计人员过度担心硬件故障一样。但是,如果您知道它的初衷是在有空闲资源时在后台运行作业,这就更有意义了。显然,一个小时长的 MapReduce 任务有 50%的机会被终止,因此计算资源可以被更高优先级的作业使用。

不好的地方

关于这本书,我要说的唯一不好的一点是,它最初是在 2017 年初出版的,年龄开始显示出来了。VoltDB 和 Riak 是两个获得最频繁引用的数据库,但我从未听说过它们。从谷歌趋势来看,自 2015 年以来,它们的受欢迎程度一直在下降(已经是小众的了)。

这本书从 2010 年开始引用了很多关于分布式数据库、批处理和流处理的有趣内容,但这些内容在 2016 年停止了。我很想知道他在过去 4 年中会包括什么,因为这是一个发展迅速的领域。

谁应该读它?

我建议有一些数据库或软件开发的经验,以便看到材料的相关性。这是一本相当厚的书(550 页左右),我花了 45 个小时才读完,所以你需要愿意花一些时间来读完它。也就是说,我相信这绝对是值得的时间投资。

结论

你会从阅读中受益吗?我做得很快。这篇关于 Google Spanner 分布式数据库的中型文章最*出现在我的 feed 中。它提到了故障切换、事务、一致性、防止过时读取、跨区域复制等内容。在读这本书之前,我要么不知道这些概念是什么,要么不理解它们的复杂性。所以现在我受益于能够更好地理解和消化这样的帖子。

评级:🦅🦅🦅🦅🦅

5 鹰是这本书唯一合适的评级。它以全新的视角向你展示一个熟悉的世界的能力,只有 5 只老鹰把你从椅子上拉起来,带你在你的城市上空翱翔才能与之媲美。

数据产品和客户

原文:https://towardsdatascience.com/designing-data-products-from-a-customer-viewpoint-8e9f622ec27b?source=collection_archive---------30-----------------------

从客户的角度出发,通过逆向工作提高影响力

Mike Akeroyd(作者)在 Blender 中渲染的抽象背景图像。

在过去的 10 年里,根据谷歌趋势数据,“机器学习”和“数据科学”的搜索量增加了 12 倍。随着流行,可能会出现一种非理性的兴奋,公司可能会为了进行机器学习而想要进行机器学习。构建由机器学习驱动的产品需要一种微妙的*衡,既要提供早期的增量价值来满足业务合作伙伴,又不能通过在模型中使用太少的数据或功能来淡化影响。作为产品经理、科学经理或科学家,我们需要管理内部期望,同时保持对 ML 计划的支持势头。要做到这一点,我们应该关注客户需求,而不是只关注科学成果。

但是谁是科学产品的客户呢?如果我们正在开发一个客户流失倾向模型,那么客户可能是一个保留营销团队。如果我们正在建立一个价格弹性模型,那么客户可能是一个产品价格策略团队。在另一个例子中,如果我们推出一个网站聊天机器人,那么客户可能是一个数字支持团队。然而,在所有这些情况下,这些机器学习模型的“客户”也可能是最终的商业客户:保留促销的接收者,愿意为产品支付价格的人,或者向聊天机器人提问的用户。微妙的区别在于特定机器学习模型或数据产品与最终商业客户的直接互动水*。数据产品的早期版本可以产生建议,并且内部用户可以实施该建议。一个更高的版本可以完全自动地与最终的商业客户进行交互。然而,仅仅因为一个数据产品最初的范围是支持内部用户,未来的发展可能会产生一个直接与最终业务客户交互的数据产品。因此,我们应该始终从最终客户“向后工作”。

有几篇文章提供了如何思考数据产品或任何使用数据来传递其核心价值主张的产品的想法。根据这个定义,任何使用机器学习的产品都可以被认为是数据产品。一篇文章 [1]将数据产品分为三种类型:数据即服务、数据即洞察和数据增强产品。另一个【2】也将数据产品分为三种:标杆数据、预测数据、推荐系统数据。另一个文档【3】将数据产品分为:原始数据、派生数据、算法、决策支持和自动化决策。在每一种情况下,数据产品都根据产品的产出进行分类。本文将介绍一个新的基于客户的数据产品分类框架,而不是关注输出。这个框架允许我们更容易地考虑与数据产品开发相关的技术和组织约束。

从客户开始向后工作有助于我们考虑基于客户需求的增量开发。它还允许我们设定价值主张的期望值。

在我们开始之前,这里有一个框架概述。

离顾客三度…

"三级数据产品"通过两层或更多层的人类互动或其他科学驱动的输入与最终客户分离。客户聚类、离线欺诈评分、产品评论情绪或保留概率模型的输出都是三级数据产品的示例。这种类型的数据产品以数据集、科学笔记本或可视化的形式存在。这是从数据中获得洞察力的核心。没有这些被科学家和分析师消费的数据产品,就不可能有任何已实现的未来价值。作为一个科学团队,第三度数据产品通常是最令人兴奋的讨论(“我们要预测 x!”)但从业务角度来看,提供支持可能会很困难。这是因为通常很难衡量这类产品带来的直接财务影响。然而,第三度数据产品提供了真正的选择价值。这种真正的选择是扩展到具有可测量价值的一级或二级数据产品的潜力。通常,实物期权的价值非常重要,因为一个三级数据产品可以支持许多领域。例如,客户终身价值模型可以支持用于市场细分、促销目标或客户支持队列优先级排序的附加数据产品。

与顾客相距两度……

二度数据产品”与终端客户之间隔着一层人机交互。这些产品通常由内部业务团队使用,可以包括包含预测和优化的 ui。二度数据产品不仅仅是见解,而是建议。这些建议还可以包括具有敏感性分析的替代方案。有时,这些产品可以开发为原型或第一个版本,随后会产生第一级数据产品。在其他情况下,我们可能永远无法获取做出整体决策所必需的适当数据,因此始终需要对基于科学的建议施加“人为影响”。在另外一些情况下,如果产品支持的决策很少被做出,并且影响相当大,那么让产品变得更不干涉可能会有很大的风险。与二级数据产品相关的量化值可能是模糊的。这是因为人们需要回答这样一个问题:做出更明智决策的价值是什么?该值是与科学建议和人类决策相关的影响的混合。二级数据产品的主要风险是缺乏采用。如果推荐的决策无法解释,不直观,或者需要大量的人工干预,那么产品很可能会被弃用。

离客户 1 度…

我们可以将机器学习模型的输出直接与最终客户接触的产品分类为“一级数据产品”。这意味着 ML 输出与用户仅相差一度。这些数据产品的例子包括个性化用户体验、产品推荐、聊天机器人和驾驶员导航。有了这些类型的数据产品,我们可以通过 AB 测试来评估客户影响和衡量业务价值。从业务角度来看,量化价值的能力使这些类型的数据产品更容易划分优先级。然而,由于这些产品与客户互动,总会有损害客户信任的风险。例如,第一级数据产品可能提供不相关的建议、不正确的驾驶方向、极端的价格变化,或者在 IBM 的 Watson 的情况下,向医生提供错误的癌症治疗建议。推出一级数据产品需要工程支持,并且必然存在许多依赖关系。通常,需要一个适应性强的 UX 来支持实验和自动数据收集。对于这些数据产品,我们可以使用业务规则引导早期实验,收集的数据稍后用于支持模型训练和增强。随着时间的推移,随着该产品从客户那里收集直接反馈,机器学习模型可以提供更相关的输出。

区分数据产品和科学模型……

让我们快速浏览一个例子,看看这个框架在实践中是如何工作的。在这个例子中,我们为一家处于分析之旅早期的公司工作,我们的任务是使用机器学习来减少客户流失。最终的第一级数据产品的“最终客户”是可能流失的客户。这种产品可以是一个系统,它可以自动识别具有高流失倾向的客户,并向他们发送有针对性的促销优惠。达到这一点不仅需要科学工作,也需要工程工作。因此,实现产品的价值需要时间,如果有任何开发延迟,这可能会增加失去管理层支持的风险。当我们建立客户级别的保留概率模型来驱动这个一级数据产品时,我们也可以提供二级数据产品。这种二级数据产品可以是“防止流失目标工具”,营销人员可以使用它来识别具有高流失可能性分数的客户。有了这些信息,营销团队可以手动提供促销以降低流失风险。通过分解交付,组织可以更快地实现价值,并可能通过实验来确定客户流失预测的有效性。最后,第三度数据产品是客户流失科学模型的输出。该输出不仅可以支持我们减少客户流失的目标,还可以作为其他科学模型的输入。例如,客户流失或保留概率模型可以是客户终身价值模型的输入。

示例数据产品分类

所以,概括一下:

一级数据产品直接向客户提供基于科学的输出,供他们采取行动。

二级数据产品向企业提供基于科学的输出,供员工采取行动,然后提供给客户。

第三度数据产品向第二度数据产品提供基于科学的输出。第三级数据产品也可以向分析师或科学家提供见解,而不提供建议。

从数据产品中实现价值有时可能是一个漫长的旅程:对客户和企业都是如此。照片来自 Pexelsflo·马德雷纳拍摄

最后一点要注意的是,我们可以进一步扩展这个框架,以包括多一种数据产品类型:“零度数据产品”。零度数据产品使用其基于科学的输出来代表客户采取行动。这不同于第一级数据产品,第一级数据产品要求客户仍然自己行动。零度数据产品的例子包括无人驾驶汽车、无人驾驶飞机或其他自主机械。这种类型的数据产品与提到的其他三种产品之间有一个关键的技术差异。零度数据产品往往是用深度学习构建的。相比之下,我们通常使用机器学习算法来构建其他三类数据产品。

总之,当开发一个人工智能战略或建立一个 ML 项目路线图时,很容易变得过于雄心勃勃。在讨论 ML 解决方案时,组织通常会设想一级数据产品。实际上,许多数据产品需要从三级数据产品开始,并逐渐变得更加复杂。这种以客户为中心的数据框架不是保证高质量科学产品的灵丹妙药,但它可以帮助我们定义产品。它还帮助我们理解如何从敏捷开发的角度来思考。这样做,我们可以最小化范围蔓延,同时首先向内部业务合作伙伴提供价值,然后向外部客户提供增量交付。

参考文献:

[1]https://www . mind the product . com/fundamentals-building-better-data-products/

[2]https://www . Forbes . com/sites/Lutz finger/2014/08/19/3-data-products-you-need-to-know/# 498 a 770366 F6

[3]https://towards data science . com/designing-data-products-b 6 b 93 EDF 3d 23

设计数据库存储和检索

原文:https://towardsdatascience.com/designing-database-storage-and-retrieval-14cf5ab2bca?source=collection_archive---------75-----------------------

关于数据库存储、索引和数据检索,您需要知道的一切

照片来自https://unsplash.com/

数据库是任何应用程序设计中不可或缺的一部分,进程在其中存储和管理数据。虽然,您可能永远不需要从头开始设计数据库,但是了解其设计以及不同数据库处理数据的方式将有助于您选择最合适的数据存储,从而提供所需的可伸缩性和性能。例如,适合处理事务性数据的数据库可能不适合数据仓库。

让我们开始设计一个数据库。我们将从简单开始,然后优化它,直到它变得可怕。

最简单的方法是将键值对保存在一个文件中。写入记录只会将记录附加到文件末尾。如果某个段(或文件)的大小超过了最大可能大小,则开始写入下一个段。作为后台进程,这些段被合并以移除重复的条目并保留关键字的最新值。这个过程叫做压实。这种方法的唯一问题是,read 必须解析整个段才能找到用那个键写入的最后一个值。这些可能进一步涉及在多个段中搜索,导致读取时间增加。让我们试着解决这个问题。一种方法是在键上建立索引。

哈希索引

创建索引的一个简单方法是使用哈希映射。你可以有一个内存中的哈希表来存储键和字节偏移量,即它在该段中的位置。每个数据段都有自己的内存哈希映射。

在散列索引中查找

写操作将在哈希表中创建一个条目,并将记录追加到最新的段中。读取将涉及到遍历散列表,以找到要读取的记录的位置。

这种方法有一些缺点:
1。索引保存在内存中。当键的数量很大并且超过可用的内存时,这是没有用的。
2。它不是为范围查询而优化的。

桌子和 LSM 树

排序字符串表(SSTables)包含按键排序的数据,一个键在一个段中只出现一次。有了有序排列的键,就不需要在哈希表中索引每个键,只需要索引少数记录的偏移量。使用排序数据段的其他好处是,它允许在写入前压缩数据块,并且使压缩过程更容易。可以使用简单的合并排序算法来合并段。

表中的索引和压缩

下一个问题是如何在 segment 中保持键的排序顺序?使用像 AVL 这样的自*衡树,在内存中存储排序结构要容易得多。

  1. 当写入到来时,将其添加到内存*衡树(称为 memtable )。
  2. 随着内存的增长,从 memtable 中读取值并将其写入磁盘。因为它已经排序,段将有排序的关键字。
  3. 在读取期间,首先检查 memtable,然后检查最*的段。

但是如果我们的系统在将 memtable 写到磁盘之前崩溃了呢?要解决这个问题,请使用日志。为磁盘中的每次写入保留一个日志。如果系统崩溃,这些可以用来构建段。

日志结构树或 LSM 树是一种数据结构,旨在为长期经历高插入(和删除)率的文件提供低成本索引。它基于在后台合并的表的思想。不同的段可能包含相同关键字的值。这些数据段在后台进行压缩,以删除重复数据并节省空间和读取时间。

b 树

B-tree 是一种自*衡的树形数据结构,用于维护已排序的数据。在大多数其他自*衡搜索树(如 AVL 树和红黑树)中,假设所有东西都在主存中。为了理解 B 树的使用,想象一下在主存中容纳不下的大量数据。当键的数量很大时,数据以块的形式从磁盘中读取。与主内存访问时间相比,磁盘访问时间非常长。使用 B 树的主要思想是减少磁盘访问的次数。对数时间内的 b 树搜索、顺序访问、插入和删除。你可以在这里阅读更多关于 B 树的内容。

像表一样,树也保持键的顺序。唯一的区别在于设计理念。LSM 树是将数据写入不同段的日志结构索引,而 B 树是一次仅在一个页面(或磁盘块)中读取或写入的页面结构索引。它将数据存储分为固定大小的块或页面。叶节点可以包含键的实际值,或者指向存储该值的引用。下面的图片将帮助你理解 B 树是如何工作的。

在 B 树中查找 key = 272

读取时,需要遍历树,找到存储块的位置。在写入时,它首先需要找到需要写入值的页面,然后写入。如果块中没有足够的空间,可能会导致块分割和对父节点的更新。

为了使写入对崩溃具有弹性,它使用日志。在任何写操作之前,首先将它记录在磁盘中,然后将其插入到 B 树中。

比较

  1. 读/写性能:像 LSM 树这样的日志结构索引允许更快的写入,而像 B 树这样的页面结构索引允许更快的读取。LSM 中的读取相对较慢,因为它们需要根据压缩级别检查多个数据结构和表。
  2. 冗余:对于 B 树,每个键只存储在一个地方,而对于日志结构,它存储在多个段中。
  3. 存储 : B 树由于碎片化 ie 可能会留下一些磁盘空间。当前行无法放入可用页面空间时。LSM 树的压实过程减少了碎片。
  4. LSM 需要优化的压缩策略来合并数据段,以获得更好的读取性能。压缩策略不应影响正在进行的读/写操作。当写入吞吐量较高,并且正在进行的写入和执行压缩的线程之间共享有限的磁盘带宽时,这可能会导致问题。

b 树更受欢迎,用于维护索引。

所有其他索引,如二级索引、多列索引等都扩展了上述方法。唯一的区别是这些索引的键不是唯一的。每个关键字可以有多条相关记录。

结论

提供了关于数据库如何存储和检索数据的见解。对于存储大量数据用于分析的数据仓库,上述所有方法可能都不是最佳的。为下一篇文章保留数据仓库的存储和检索过程!

要阅读更多关于数据库和应用程序设计的内容,我强烈推荐阅读马丁·克莱曼的《设计数据密集型应用程序》。

希望你喜欢这篇文章!

数据科学中的实验设计

原文:https://towardsdatascience.com/designing-experiments-in-data-science-23360d2ddf84?source=collection_archive---------11-----------------------

约翰·霍普斯金 DS 专业化系列

数据科学中的实验需要适当的规划和设计来最好地回答它的问题

UnsplashGreg Rakozy 拍摄的照片

[Full series](https://towardsdatascience.com/tagged/ds-toolbox)[**Part 1**](/the-data-scientists-toolbox-part-1-c214adcc859f) - What is Data Science, Big data and the Data Science process[**Part 2**](/how-to-learn-r-for-data-science-3a7c8326f969) - The origin of R, why use R, R vs Python and resources to learn[**Part 3**](/a-crash-course-on-version-control-and-git-github-5d04e7933070) - Version Control, Git & GitHub and best practices for sharing code.[**Part 4**](/the-six-types-of-data-analysis-75517ba7ea61) - The 6 types of Data Analysis[**Part 5**](/designing-experiments-in-data-science-23360d2ddf84) - The ability to design experiments to answer your Ds questions[**Part 6**](/what-is-a-p-value-2cd0b1898e6f) - P-value & P-hacking [**Part 7**](/big-data-its-benefits-challenges-and-future-6fddd69ab927) - Big Data, it's benefits, challenges, and future

本系列基于约翰·霍普斯金大学在 Coursera 上提供的 数据科学专业 。本系列中的文章是基于课程的笔记,以及出于我自己学习目的的额外研究和主题。第一门课, 数据科学家工具箱 ,笔记会分成 7 个部分。关于这个系列的注释还可以在这里找到

介绍

在解决问题之前问正确的问题是一个很好的开始,它在复杂中为你指明了正确的方向。但是要真正有效地解决你的问题,你还需要适当的规划和良好的实验设计。类似于用科学方法进行实验,这需要遵循一系列简洁的步骤来进行安全实验,即设备的名称和某些东西的测量,您还必须设计您的数据科学实验。只有这样,才能铺出一条清晰的道路,用正确的方法一部分一部分地、一丝不苟地解决你的问题。以下是更多关于实验设计的内容。

什么是实验设计?

照片由艾萨克·史密斯Unsplash 拍摄

这通常意味着组织一个实验以便你有正确的数据有效地回答你的 DS 问题。

在开始解决 DS 问题之前,可能会出现一些问题。

  • 回答这个问题的最好方法是什么?
  • 你在衡量什么,如何衡量?
  • 什么是正确的数据?
  • 我如何收集这些数据?
  • 我使用什么工具和库?
  • 等等…

所有这些问题都是 DS 实验的关键部分,必须从一开始就回答。如果没有适当的规划和设计,您将在整个工作流程中面临许多这样的问题,从而使工作效率低下。

那么在一个实验中什么是正确的流程呢?

实验设计流程

1.提出问题

2.设计实验

3.识别问题和错误来源

4.收集数据

这个过程开始于在任何数据收集之前明确地制定你的问题,然后设计尽可能好的设置来收集数据以回答你的问题,识别的问题或你设计中的错误来源,然后收集数据

重要

坏数据→错误分析→错误结论

  • 错误的结论可能会产生涓滴效应(论文中的引用最终会应用于真实的医学案例)
  • 对于高风险的研究,如确定癌症患者的治疗计划,实验设计至关重要。
  • 数据不好、结论错误的论文会被撤稿,名声不好。

实验设计原则

照片由摩根·豪斯Unsplash 上拍摄

1.独立变量(x 轴)

  • 被操纵的变量,不依赖于其它变量

2.因变量(y 轴)

  • 预期因自变量变化而变化的变量

3.假设

  • 对变量和实验结果之间关系的有根据的猜测

例子

这里有一个实验设计的例子,用来测试阅读书籍和读写能力之间的关系。

  • 假设:随着书籍阅读量的增加,读写能力也会提高
  • X 轴:阅读的书籍
  • Y 轴:识字
  • 实验设置:我假设文化水*取决于阅读的书籍
  • 实验设计— 测量 100 个人的书籍阅读和读写能力
  • 样本量(n) — 实验中包含的实验对象数量

在收集数据来测试你的假设之前,你首先要考虑可能导致你的结果出错的问题,其中之一就是混杂因素。

什么是混杂因素?

  • 可能影响因变量和自变量之间关系的外来变量

对于这个例子,混杂因素可以是年龄变量,因为它既可以影响阅读的书籍数量,也可以影响识字率。读的书和识字的任何关系都可能是年龄造成的。

假设:读书→识字

混杂因素:读过的书←年龄→识字

记住混杂因素,设计控制这些混杂因素的实验是至关重要的,这样它就不会影响你的结果,并且你正在正确地设计你的实验。

有三种方法可以处理混杂因素:

  1. 控制
  2. 随机化
  3. 复制

1.控制

回到读书识字实验,为了控制年龄对结果的影响,我们可以测量每个人的年龄以考虑年龄对识字的影响。

这将在您的研究中创建两个组:

(1) 对照组 & (2) 治疗组,其中:

  • 对照组→固定年龄的参与者
  • 治疗组→各年龄段的参与者。
  • 比较结果,了解固定年龄组与不同年龄组的识字能力是否不同。

另一个常见的例子是药物测试,为了测试药物对患者的效果,对照组不接受药物,而治疗组接受药物,并比较效果。

安慰剂效应

这是一种偏见,一个人在心理上认为某种治疗对他们有积极影响,即使根本没有治疗。这在医学上很常见,安慰剂药物可以替代真正药物的作用。

为了解决这种偏见,受试者将被蒙住双眼,这意味着他们不知道自己被分到哪一组:

  • 对照组与模拟治疗(糖丸,但告诉药物)
  • 治疗组采用实际治疗
  • 如果存在安慰剂,两组患者的感受是一样的

2.随机选择

随机化基本上是将个体随机分配到不同的组,这是很好的,有两个原因,(1)你不知道混杂变量,和(2)它减少了偏向一个组以丰富混杂变量的风险

以药物测试为例

  • 对许多受试者取样,进行随机化
  • 将参与者分配到两个主要组,一个混杂组,另一个随机,每个组都有自己的对照组和治疗组
  • 从随机分组中,你可以看出是否存在偏见。

3.分身术

复制基本上是重复你的实验,但这次是用不同的对象,这很重要,因为它显示了你的实验的可重复性。

复制也是必要的,主要是因为只进行一个实验可能是偶然的,这是许多因素的结果,例如:

  • 混杂因素分布不均匀
  • 数据收集中的系统误差
  • 极端值

如果复制完成了(用一组新的数据)并且产生了相同的结论,这表明该实验是强有力的,并且具有良好的设计。

此外,复制的核心是数据的可变性,这与 P 值有关,P 值有一个黄金法则( P0.05 ),这是许多人在统计假设检验中努力追求的。在下一篇文章中会有更多的介绍

摘要

照片由兵浩Unsplash 上拍摄

建设一个像纽约这样的城市需要蓝图和非常精确的规划,这创造了你今天所看到的。在数据科学中设计实验也应该如此。

这是实验设计的基础,从根本上讲是关于精确的计划和设计,以确保您的分析或研究有适当的数据和设计,从而防止错误的结论。

流程的一个很酷的助记符是QDPC-Qu 问题DATAPLANCare fully

制定问题→设计实验→识别问题和错误→收集数据。

错误的结论会产生涓滴效应,因为它们在现实生活中被引用和使用,特别是在医学上。

原理:

  • 独立变量 (x 轴)——被操纵且不受其他变量影响
  • 因变量 (y 轴)—x 的变化导致 y 的变化
  • 假设 —关于 X 和 Y 之间关系的有根据的猜测

实验设计

  • 混杂因素——影响自变量和因变量之间关系的外来变量
  • 控制——在实验中固定混杂因素或考虑和测量
  • 对照组——一组测量了独立变量但未接受治疗的受试者。作为实验的对照,比较变化和效果
  • 盲法受试者 —将受试者盲法分组,以测试安慰剂效应
  • 安慰剂效应 —一个人对安慰剂治疗产生的效应的信念
  • 随机化 — 随机分配参与者,以呈现偏倚和混杂效应
  • 复制— 重复实验到强化结果的结论

参考

如果您对学习数据科学感兴趣,请查看“超学习”数据科学系列!

* [## 如何“超级学习”数据科学—第 1 部分

这是一个简短的指南,基于《超学习》一书,应用于数据科学

medium.com](https://medium.com/better-programming/how-to-ultralearn-data-science-part-1-92e143b7257b)

查看这些关于数据科学资源的文章。

[## 2020 年你应该订阅的 25 大数据科学 YouTube 频道

以下是你应该关注的学习编程、机器学习和人工智能、数学和数据的最佳 YouTubers

towardsdatascience.com](/top-20-youtube-channels-for-data-science-in-2020-2ef4fb0d3d5) [## 互联网上 20 大免费数据科学、ML 和 AI MOOCs

以下是关于数据科学、机器学习、深度学习和人工智能的最佳在线课程列表

towardsdatascience.com](/top-20-free-data-science-ml-and-ai-moocs-on-the-internet-4036bd0aac12) [## 机器学习和数据科学的 20 大网站

这里是我列出的最好的 ML 和数据科学网站,可以提供有价值的资源和新闻。

medium.com](https://medium.com/swlh/top-20-websites-for-machine-learning-and-data-science-d0b113130068) [## 开始数据科学之旅的最佳书籍

这是你从头开始学习数据科学应该读的书。

towardsdatascience.com](/the-best-book-to-start-your-data-science-journey-f457b0994160)

联系人

如果你想了解我的最新文章,请通过媒体关注我。

也关注我的其他社交资料!

请关注我的下一篇文章,记得注意安全!*

为数字双胞胎设计

原文:https://towardsdatascience.com/designing-for-digital-twins-e2b3e07a5d1e?source=collection_archive---------31-----------------------

法耶·康尼什在 Unsplash 上的照片

数字双胞胎的未来是多样化的——在意义和设置上都是如此。忽视这一现实将阻碍数字双胞胎的成功。

这里,重点是在分散的服务和数据环境中成功实施数字双胞胎的设置和设计考虑因素(因此这里不包括物联网摄取和数据模型部分)。呈现了初始技术映射。

数码双胞胎

什么被视为数字孪生取决于它的目标。一个例子是现实生活中的数字孪生资产,比如一个车队。基于车队的状态,将实时做出关于路线、驾驶员刹车等的决策。这些系统还将依赖于外部数据,如交通信息和环境条件,如天气。由于决策将逐渐基于先进的算法,历史事件的模式将变得重要,并将逐渐包括更加多样和丰富的数据。数字版本变得越来越丰富,足以建立对重要角色互动的理解。有了这种理解,就可以构建模拟,并且可以根据模拟运行的结果通过选择过程做出自动决策。换句话说,一个人正在构建一个数字真相,以及围绕它所关注的资产的*行未来可能性。

怀着另一个目标,另一种类型的数字孪生将被建立。例如,如果一个人在不断变化的气候中寻求缓解措施,那么数据、算法、模拟、考虑的时间间隔会有很大的不同。导致数字双胞胎之间的决策或建议不同——即使它们部分涉及相同的对象。数字双胞胎的决策取决于他们的 KPI(关键绩效指标)是否符合他们的目标和方法。数字双胞胎将有助于优化运营,但也将有助于解决社会问题,尽管潜在的社会、经济、道德、责任和环境考虑因素应在更广泛的受众中*行进行,因为这将影响数字双胞胎设计的 KPI。

分散风景

数字双胞胎有三个共同的组成部分——数据、计算、算法——但每个组成部分的用途及其驻留位置在数字双胞胎之间会有很大的不同。很可能来自自有资产的数据将直接流向自有的受控计算环境(本地、公共或私有云中)。然而,在其他情况下,通过本地超级计算机生成的大量气候数据甚至可以在磁带上“锁定”多年,在这种情况下,获取和下载数据将成为一项艰巨的任务。由于没有任何组织能够或愿意将所有数据集中在一个地方,数字双胞胎的未来是一个分散的景观,原始数据驻留在许多不同的位置。类似地,算法和应用程序将被创建,并由不同的组织提供,并在有意义的地方运行,因此通常接*数据。换句话说,数字双胞胎的未来将在很大程度上基于松散耦合的类似网格计算的环境。

适应网格计算

数字双胞胎环境中的网格计算使得数据提取、数据转换和算法应用以复杂和地理上分散的方式链接起来。本质上,网格计算的用户对整个链的控制程度较低,网格计算的成功,以及许多数字双胞胎的成功,将依赖于这些链服务的可访问性、可靠性和透明性。因此,为数字双胞胎设计服务的使用和吸收需要考虑几个网格计算问题。设计原则需要在数字双胞胎的两个层面上考虑,即'云'、和'间的交互。**

云内交互

内部云是数字孪生提供商运营数字孪生服务或应用的云环境,它只是提供商选择的位置,因此可以位于公共云中,也可以位于私有云或内部环境中。

数字孪生可以纯粹基于提供商在这个(内部)云环境中收集和汇集的数据和处理能力。要让这对双胞胎正常工作,需要遵循几个原则。从存储到计算内存的数据传输应仅限于所需的数据。因此,数据应该以云优化的方式进行格式化、分区和索引。只有在主动请求时,数据才会被传输到计算内存。因此,实现了遵循懒惰计算原则的高效数据传输。数字孪生应用请求数据或激活处理服务,这些数据或服务可通过访问层(可能通过 API)获得。

在数字孪生提供商运行其数字孪生的相同云环境中,可以存在其他服务提供商,它们为数字孪生提供数据和有价值的数据服务。最常见的是云提供商本身,但也可能是第三方。关于可访问性和数据传输的相同原则可以适用于这些方提供的服务。云提供商可以将数据集直接“安装”到 Digital Twin 提供商的计算引擎,而无需复制活动。随着链接来自多个提供商的服务变得越来越复杂,出现了对控制链的数字孪生编排者的需求。

一个云环境中的数字孪生设置:云内交互(图片由作者提供)

云间交互

如上所述,数据所有者将使他们的数据可从各种位置和环境(本地、私有云、一个或多个公共云)访问,而许多数据集太大,无法及时传输到另一个环境。数字双胞胎必须应对跨云交互。因为需要将数据从一个云传输到另一个云,所以保持数据集尽可能小就更加重要了。因此,建议数据所有者使用一组丰富的 API,遵循云内交互中描述的关于数据访问、提取和传输效率的相同原则。如果数据所有者不遵循这些原则,Digital Twin 所有者应考虑在其他云环境中运行他们的部分计算,然后将最少的数据传输到他们自己的环境中(例如通过数据聚合或 ML 推理来整合数据)。为了降低这里的复杂性,Digital Twin 所有者可以选择对多个云环境应用相同的数据存储、计算引擎和访问层设置。从开发人员和研究人员的角度来看,如果可以建立一个开发经验来建立基础设施,以及将智能构建到计算引擎中,他们的生产力将会提高。

与云内交互相比,更需要一种基于服务的工作流方法来克服分布式环境特有的挑战。数据传输、工作流控制和异常处理的复杂性使得很难定义、协调和保证流程。Digital Twin orchestrator 应该适应这些工作流程协调。

多云环境中的数字孪生设置:云间相互作用(图片由作者提供)

初始技术映射*

考虑到最终用户,数字双胞胎可以用于多种责任和角色。数字孪生应用可以针对他们的特定需求进行设计,从面向决策者的仪表盘(包括地图)到面向资产运营商或政策制定者的增强现实等沉浸式体验。用于分布式环境的基于服务的编排器需要进一步关注潜在技术的映射。服务访问层的一项常见技术是使用 API。大规模分析大多以批处理方式运行,不一定是实时的,这使得分布式和并行计算引擎成为数字双胞胎的候选,这些引擎可以是基于 Spark 的(分布式)或基于 Dask /python 的(并行)——这两种方法都得到大型动态开源社区的支持,这些社区在数据科学、机器学习和其他算法方法方面进展迅速。从地球/海洋/气候研究人员开始, Pangeo 项目就是一个基于 Dask 的例子。研究人员和开发人员的开发体验可以基于笔记本技术。实时处理需要通过流技术来实现,数据接收和存储应支持快速写入。为 Digital Twin 应用程序准备的数据需要符合该应用程序和用户体验的需求,如 AR 应用程序的快速查询和服务功能。数据提供者,无论是作为数字双胞胎的一部分还是作为数据所有者,都应该促进快速的数据提取和交付,可以通过使用云原生格式(如地理空间数据的 COG、Zarr)。

结论

数字双胞胎的未来是分散的:数据将可以从许多不同的环境中以许多不同的数据格式和访问方法获得。为了将所有这些整合在一起,并得出可行的见解,数字双胞胎需要针对这一现实进行设计。需要关注云间和云内环境交互的内在复杂性,并尽可能努力降低成功使用数字双胞胎的复杂性。

*** Azure *台和 Planetary Computer 的技术映射可在此处阅读:与 Dask 和 Pangeo 一起走向 Azure 中的环境数字双胞胎| Remko de Lange 著| 2021 年 4 月|走向数据科学**

这里的意见是我的。

设计智能 Python 词典

原文:https://towardsdatascience.com/designing-intelligent-python-dictionaries-cc138ac3f197?source=collection_archive---------13-----------------------

设计智能、用户友好的 Python 词典的快速指南

照片由 Aaron BurdenUnsplash 上拍摄

上周在做一个业余爱好项目时,我遇到了一个非常有趣的设计问题:

你如何处理错误的用户输入?

让我解释一下。

Python 字典示例。来源:作者

Python 中的 字典 表示成对的。例如:

student_grades = {'John': 'A', 'Mary': 'C', 'Rob': 'B'}# To check grade of John, we call
print(student_grades['John'])
# Output: A

当您试图访问一个不存在的键时会发生什么?

print(student_grades['Maple'])
# Output: 
KeyError                         Traceback (most recent call last)
<ipython-input-6-51fec14f477a> in <module>
----> print(student_grades['Maple'])

KeyError: 'Maple'

你收到一个 键错误

每当dict()对象被请求字典中不存在的key的值时,就会发生 KeyError。

当您接受用户输入时,这个错误变得极其常见。例如:

student_name = input("Please enter student name: ")
print(student_grades[student_name]) 

本教程提供了几种方法来处理 Python 字典中的关键错误。

我们将努力构建一个智能 python 字典,它可以处理用户输入中的各种错别字。

来源: Imgur

设置默认值

一个非常懒惰的方法是每当请求的键不存在时返回一个默认值。这可以使用get()方法来完成:

default_grade = 'Not Available'
print(student_grades.get('Maple',default_grade))# Output:
# Not Available

你可以在这里阅读更多关于get()方法的内容。

处理信件案件

让我们假设您有一本包含特定国家人口数据的字典。该代码将要求用户输入一个国家名称,并打印其人口。

# Output
Please enter Country Name: France
65

但是,让我们假设用户键入输入为‘france’目前,在我们的字典中,所有键的首字母都是大写的。输出会是什么?

Please enter Country Name: france-----------------------------------------------------------------KeyError                         Traceback (most recent call last)
<ipython-input-6-51fec14f477a> in <module>
      2 Country_Name = input('Please enter Country Name: ')
      3 
----> 4 print(population_dict[Country_Name])

KeyError: 'france'

由于‘france’不是字典中的一个键,我们收到一个错误。

一个简单的变通方法:用小写字母存储所有国家的名称。

此外,将用户输入的任何内容转换成小写。

Please enter Country Name: france
65

处理错别字

但是,现在假设用户输入的是‘Frrance’而不是‘France’。我们该如何处理这件事?

来源:吉菲

一种方法是使用 条件语句

我们检查给定的 user_input 是否可以作为键使用。如果它不可用,那么我们打印一条消息。

最好将它放在一个循环中,并在一个特殊的标志输入(如 exit)上中断。

循环将继续运行,直到用户输入exit

输出。来源:作者

更好的方法

虽然上述方法‘有效’,但它不是我们在介绍中承诺的‘智能方法’

来源: Giphy

我们希望我们的程序是健壮的,并检测简单的错别字,如frrancechhina(非常类似于谷歌搜索)。

经过一番研究,我找到了几个符合我们需求的库。我最喜欢的是标准 python 库: difflib

difflib 可用于比较文件、字符串、列表等,并产生各种格式的差异信息。

该模块提供了各种用于比较序列的类和函数。

我们将使用 difflib 中的两个特性:sequence matcherget _ close _ matches

让我们简单看一下他们两个。如果您只是对应用程序感到好奇,可以跳到下一节。

#序列匹配器

SequenceMatcher 类用于比较两个序列。我们将其对象定义如下:

difflib.SequenceMatcher(isjunk=None, a='', b='', autojunk=True)
  • isjunk:用于指定junk 元素(空格、换行符等)。)是我们在比较两个文本块时希望忽略的。我们在这里通过None
  • ab:我们希望比较的字符串。
  • autojunk:自动将某些序列项目视为垃圾的启发式。

让我们用 SequenceMatcher 来比较两个字符串chinnachina:

在上面的代码中,我们使用了ratio()方法。

ratio 返回序列相似性的度量,作为范围[0,1] 中的浮点数。

里卡多·戈麦斯·安吉尔在 Unsplash 上拍摄的照片

#获取 _ 关闭 _ 匹配

现在,我们有了一种基于相似度比较两个字符串的方法。

但是,如果我们希望找到与特定字符串相似的所有字符串(存储在数据库中),会发生什么呢?

get_close_matches() 从可能性列表中返回包含最佳匹配的列表。

difflib.get_close_matches(word, possibilities, n=3, cutoff=0.6) 
  • word:需要匹配的字符串。
  • possibilities:与word匹配的字符串列表。
  • 可选n:返回的最大相*匹配数。默认情况下,3;必须大于 0
  • 可选cutoff:相似率必须大于该值。默认情况下, 0.6

可能性中的最佳 n 匹配在一个列表中返回,按相似性得分排序,最相似的排在最前面。

让我们来看一个例子:

把所有的放在一起

现在我们已经有了 difflib,让我们把所有的东西放在一起,构建一个防输入错误的 python 字典。

我们必须关注用户给出的Country_namepopulation_dict.keys()中不存在的情况。在这种情况下,我们尝试找到一个与用户输入名称相似的国家,并输出其人口。

# pass country_name in word and dict keys in possibilities
maybe_country = get_close_matches(Country_Name, population_dict.keys())# Then we pick the first(most similar) string from the returned list
print(population_dict[maybe_country[0]])

最终的代码将需要考虑一些其他情况。例如,如果没有相似的字符串,或者用户确认这是否是他们需要的字符串。看一看:

输出:

Inida 被理解为印度。来源:作者

结论

本教程的目标是为您提供一个构建对用户输入健壮的字典的指南。

我们研究了处理各种错误的方法,比如大小写错误和小的错别字。

我们可以在此基础上进一步研究各种其他应用。示例:使用 NLPs 更好地理解用户输入,并在搜索引擎中带来附*的结果。

希望你觉得这个教程有用!

重要链接

为初创公司设计 ML 流程编排系统

原文:https://towardsdatascience.com/designing-ml-orchestration-systems-for-startups-202e527d7897?source=collection_archive---------13-----------------------

办公时间

构建轻量级生产级 ML 编排系统的案例研究

照片由艾米尔·吉耶莫Unsplash 拍摄

我最*有机会在一家医疗保健初创公司建立了一个机器学习*台。

本文涵盖了架构设计之旅、技术权衡、实现细节和经验教训,作为关于为初创公司设计机器学习编排*台的案例研究。

随着机器学习工具生态系统的不断成熟和扩展,为生产数据科学管道构建机器学习编排层的选项并不短缺。更相关的挑战是能够确定哪些工具适合您组织的需求案例。

宝贵的经验是使用数据科学家已经熟悉的工具来构建源代码控制过程。

我们最终得到的工具集是:

  • 版本控制的 SQL 脚本支持源数据集提取
  • 预处理由 Docker 容器中执行的 Python runner 脚本抽象的代码,访问数据湖中的静态检查点数据。
  • 在一个 Python 模型类中抽象的模型训练代码,该模型类自包含用于加载数据、工件序列化/反序列化、训练代码和预测逻辑的函数。
  • 样板瓶 API 端点包装器,用于执行健康检查并返回推理请求。

端到端的构建和转换模型管道。[来源:图片由作者提供]

以下部分涵盖了最终产品所需的思考过程和实现细节。具体的系统架构可能无法推广到所有的组织,但这个案例研究可以提供一个有用的思考练习,告诉我们如何通过选择正确的工具比较架构权衡

构建该*台的设计流程始于建立正确的引导性问题,引导架构讨论。这有助于在技术构建过程中形成有利于权衡的框架。

指导性问题

  • 服务的目标用户是谁?他们目前使用什么技术技能,他们愿意学习什么技能?
  • 用户需要什么样的数据访问模式,会产生什么类型的推论?数据 ETL 是如何在组织内部发生的?
  • 数据流的新鲜度要求是什么?
  • 哪些组件需要监控?哪些指标有用?
  • 模型版本多久升级一次?

在提出一个架构决策记录(ADR)提案后,该提案列出了问题范围和初始架构,团队和我就如何实现 POC 达成了一个粗略的计划。

关键决策

  • 我们需要一个源代码控制过程来规范模型部署模式。
  • Docker 图像应作为便携性、再现性和缩放模型解决方案的常见选择
  • AWS Sagemaker 将成为虚拟化资源管理的编排支柱,用于部署 API、管理批量转换作业、身份验证、管道可观察性和负载*衡推理流量。
  • Airflow 将充当任务编排系统,而 Sagemaker 负责资源分配——调度和执行是分离的。
  • 我们需要一个共享状态控制器应用程序来协调和管理 Sagemaker 操作。
  • SQLAlchemy ORMs 可以构建数据模型,结合了用于资源状态转换的有限状态机清晰地分离了机器学习模型生命周期的步骤,并限制了重复的 Sagemaker 操作。
  • 对于用户来说,管道的配置和执行应该尽可能接*一键部署

确定了关于工具和关键特性的更高层次的问题后,我花了几个月的时间在这个框架上提炼一个最小可行的产品。这是我第一次从零开始构建机器学习*台,因此出现了许多意想不到的实现挑战,需要在整个编码过程中做出一些决策。

机器学习编排概念验证系统的架构设计。[来源:图片由作者提供]

“完成”是什么样子的?

  • 保持第一个模型简单,并获得正确的基础设施。
  • 一个好的选择是以“中立的第一次启动”为目标,明确降低机器学习收益的优先级。

第一步是确定我们如何知道我们什么时候完成了。为了奠定最初的基础设施和集成测试,我们设定了一个目标,即部署一个中立的首次发布,而不考虑机器学习模型的性能。我们的想法是保持第一个模型简单,并获得正确的基础设施。这个想法的灵感来自于谷歌将有效的机器学习框架形式化的规则。

最初部署的几个模型可能是高价值、易实现的成果,不需要复杂和花哨的功能来进行培训和部署。

重点应该是:

  • 数据存储和计算是如何协调的?
  • 确定系统的成功和失败状态。
  • 将模型集成到您的框架中——如何触发离线批处理计算,以及如何部署和关闭实时 API 端点?

目标是从简单的功能开始:

  • 确认训练数据被正确地接收、转换并适合模型。
  • 模型重量分布看起来很合理。
  • 特征数据可以正确访问离线和在线模型进行推理。

测试

  • 测试基础设施独立于机器学习
  • 在 CI/CD 中对机器学习模型进行单元测试既困难又浪费精力— 使用测试数据夹具为 docker 镜像编写集成测试。
  • 在导出模型之前检测问题

确保基础设施具有单元测试和集成测试,并且系统的学习部分被封装以允许 fixtures 和 stubs 模拟运行时条件。

具体来说:

  1. 测试将数据输入算法。理想情况下,通过定义数据质量的可接受性阈值来检查缺失的要素列。
  2. 如果隐私政策允许,对训练算法的输入进行手动检查可能是一个很好的健全检查。
  3. 关于训练数据和服务数据分布的统计数据是对抗概念漂移的一个有价值的监视器。
  4. 测试算法产生的模型工件。经过训练的模型应该是可再现的,并且在相同的数据上与服务模型具有同等的性能。

配置

  • 配置应尽可能集中在上游。采购配置的选项可以通过数据库表配置,也可以通过受源代码控制的 YAML 文件。
  • 配置灵活性应根据用户变更的预期频率以及管道稳定性需求来确定。配置可以在源代码控制之外更改吗?一个 ML 服务能容忍一个坏的配置造成的中断吗?

启用和管理机器学习计划是一项概率性工作。很难预测哪些问题容易或难以解决,以及哪些方法和模型配置将产生最佳模型。开发一个好的模型经常需要许多次优的迭代,开发的速度是非线性的。由于不同的背景、开发风格和价值观,机器学习和工程团队之间可能存在文化差距。

这些项目成功的一个关键衡量标准是减少对部署到产品中的模型数量的关注,而更多地关注测试模型被执行的迭代次数。在机器学习产品领域,实现快速、轻量级的实验比构建复杂、功能繁多的研发模型更有价值。

因此,简单、轻量级 ML 模型的模型可移植性和易于配置是比投资复杂、高强度的 R&D 算法支持(如 Tensorflow、Pytorch 或 Spark 框架)更有价值的初始目标。

任务编排

  • **Dag 工作流应该在工作流开始时实例化一次运行时参数,并将参数推送到任务。
  • 存储成本低廉 —在数据提取、预处理和训练过程中,只要有可能,检查点和持久化数据计算会更安全。
  • 确保你像发球一样训练的最好方法是保存发球时使用的功能集,然后将这些功能传送到日志中,以便在训练时使用。

API 端点

  • **共享状态控制器应用程序跨部署正确地对 Sagemaker Sagemaker 型号进行版本控制,以支持蓝绿色部署和金丝雀型号。
  • **不同 Sagemaker API 有效负载字典的注册表为操作调用定义默认参数,在运行时调用时注入定制配置。
  • **S3 是我们选择的工件存储框架。我们需要一组实用函数来标准化跨推理、训练、序列化和墓碑文件的 S3·URI 命名空间的构造。

将模型部署为用于实时推理的 API web 服务的关键步骤:

  • 调用模型:为模型编写一个轻量级 API 来处理推理请求,并返回预测、输入数据、模型元数据属性,以及附加唯一的事务 id 来构建审计跟踪。
  • 虚拟化:用适当网络覆盖、认证协议和应用程序路由将 API 对接并部署到集群。
  • 水*可伸缩性:配置自动伸缩、负载*衡、日志、认证协议和任何其他需要的基础设施。

除了简单地建立一个 ML API 端点所需的工作之外,还需要考虑如何在构建新模型时提高开发人员的工作效率。

  • API 推理访问模式在部署的模型中是相当统一的吗?也许这些轻量级端点中的大多数都可以通过样板代码抽象出来。
  • 什么类型的推理请求最常见?如果吞吐量比延迟更有价值,那么用输入文件构建批量预测功能可能比启用实时 API 点推断更优先。
  • 用于培训和服务的数据 ETL 是主要来自几个不同的数据存储库,还是有一组高度多样化的管道输入?这些输入多久改变一次?自助式数据 ETL 可以由数据库表配置快速驱动,或者通过在源代码控制存储库中配置 YAML 文件来稳定,但灵活性较低。

监控

  • **你们型号的性能退化率是多少?一天中准确性指标损失的百分比是多少?一个月?四分之一?通过计算这一退化率,您可以确定模型的重新训练新鲜度要求的优先级。
  • **在持久化工件和部署到生产之前投资测试。鉴于 CI/CD 文化和通过测试而不是监控来捕捉错误的最佳实践,这似乎是不言而喻的,但机器学习模型除了对推理管道上的数据流进行集成测试之外,还需要对模型权重分布和推理准确性进行回归测试。

有三个典型的问题会降低已部署的 ML 模型的性能。

  • 概念漂移:随着时间的推移,由于训练数据和真实世界服务数据之间的数据分布漂移越来越大,生产模型的准确性会降低。现有的客户偏好可能会改变。
  • 地区:在给定背景(即地理、人口统计、行业)下训练的模型在外推至新群体时表现更差。随着新用户加入模型,新客户可能会对数据集引入新的偏好。
  • 数据质量 : ML 模型对无声数据故障特别敏感,例如,陈旧的引用表、事件流中特定列的中断、上游数据集的新词汇或模式,或者进入数据集的畸形数据。

一路走来的经验教训

  • 仅在适当的时候添加流程 —机器学习编排框架的成功不是你成功地将多少模型部署到生产中,而是启用的实验的数量。
  • 不依赖于框架。围绕工具的决策过程应由 ML 服务需求、数据科学产品用户的规模和专业知识、云供应商和行业隐私政策等组织因素以及内部数据*台的成熟度来驱动。
  • **向抽象方向构建。数据科学管道中可以抽象出来的部分越多,测试每个组件和从检查点重启失败的管道就越容易。
  • **瞄准中立的首发。这消除了展示已部署的 ML 模型的直接价值的压力,并允许将空间集中在获得基础设施、许可和胶水上,以使架构可操作。

在我探索 ML 资源和框架的过程中,我遇到了这些惊人的博客、文章和演示文稿,它们帮助指导了我的旅程。我把它们列在这里,是为了方便那些希望更深入地编写和建模机器学习管道的人:

欢迎在 LinkedInTwitterGithubMedium 上与我联系!

基于预训练模型集成的破坏性图像分类

原文:https://towardsdatascience.com/destroy-image-classification-by-ensemble-of-pre-trained-models-f287513b7687?source=collection_archive---------24-----------------------

通过在 Tensorflow 中制作预训练网络(如 InceptionV3、MobileNetV2 和 Xception)的集成堆叠集成模型,消除图像分类任务

杆长Unsplash 上拍照

预先训练的网络非常酷。它们提供了很高的精确度,并且不需要花很多时间来训练。那么有什么能比预先训练好的网络更好呢?用其中的两个。最好用三个。或者事实上,使用多少你想要在一起作为一个系综模型和破坏图像分类任务。

要求

如果你想编码,你需要 Tensorflow 和 OpenCV。你也可以像我一样使用 Google Colab,它会预装我们任务所需的所有软件包,还提供免费的 GPU。

加载数据集

被选择消灭的数据集是经典的猫对狗数据集。由于它是一个小数据集,我们将把它完全加载到内存中,以便它训练得更快。

import tensorflow as tf
import os
import numpy as np
import matplotlib.pyplot as plt
import re
import random
import cv2_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')train_cats_dir = os.path.join(train_dir, 'cats')
train_dogs_dir = os.path.join(train_dir, 'dogs')
validation_cats_dir = os.path.join(validation_dir, 'cats')
validation_dogs_dir = os.path.join(validation_dir, 'dogs')cats_tr = os.listdir(train_cats_dir)
dogs_tr = os.listdir(train_dogs_dir)
cats_val = os.listdir(validation_cats_dir)
dogs_val = os.listdir(validation_dogs_dir)cats_tr = [os.path.join(train_cats_dir, x) for x in cats_tr]
dogs_tr = [os.path.join(train_dogs_dir, x) for x in dogs_tr]
cats_val = [os.path.join(validation_cats_dir, x) for x in cats_val]
dogs_val = [os.path.join(validation_dogs_dir, x) for x in dogs_val]total_train = cats_tr + dogs_tr
total_val = cats_val + dogs_val

所有训练和验证(在本例中为测试)图像的路径都存储在 total_train 和 total_val 中。我们将使用 OpenCV 来读取图像,并将它们存储在具有维度(图像数量 x 图像形状 x 通道)的 NumPy 数组中。它们对应的标签也将存储在一维 NumPy 数组中。

def data_to_array(total):
    random.shuffle(total)
    X = np.zeros((len(total_train), 224, 224, 3)).astype('float')
    y = []
    for i, img_path in enumerate(total):
        img = cv2.imread(img_path)
        img = cv2.resize(img, (224, 224))
        X[i] = img
        if len(re.findall('dog', img_path)) == 3:
            y.append(0)
        else:
            y.append(1)
    y = np.array(y)
    return X, yX_train, y_train = data_to_array(total_train)
X_test, y_test = data_to_array(total_val)

创建集合模型

要遵循的步骤

训练单个模型并保存它们

我们的第一个任务是创建所有单独的模型。我将使用 MobileNetV2、InceptionV3 和 Xception 创建三个不同的模型。在 Tensorflow 中,使用预先训练的网络创建模型非常容易。我们需要加载权重,决定是冻结还是解冻加载的权重,最后添加密集层,使输出达到我们想要的效果。我将为我的模型使用的基本结构:

def create_model(base_model):
    base_model.trainable = True
    global_average_layer = tf.keras.layers.GlobalAveragePooling2D()(base_model.output)
    prediction_layer = tf.keras.layers.Dense(1, activation='sigmoid')(global_average_layer)
    model = tf.keras.models.Model(inputs=base_model.input, outputs=prediction_layer)
    model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.0001), loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), metrics=["accuracy"])
    return model

在创建我们的模型之后,我们需要将它们与我们的训练数据进行一些时期的拟合。

batch_size = 32
epochs = 20def fit_model(model):
    history = model.fit(X_train, y_train,
                        batch_size=batch_size,
                      steps_per_epoch=len(total_train)//batch_size, 
                        epochs=epochs, 
                        validation_data=(X_test, y_test), 
                        validation_steps=len(total_val)//batch_size)
    return historyIMG_SHAPE = (224, 224, 3)
base_model1 = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
base_model2 = tf.keras.applications.InceptionV3(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")
base_model3 = tf.keras.applications.Xception(input_shape=IMG_SHAPE, include_top=False, weights="imagenet")model1 = create_model(base_model1)
model2 = create_model(base_model2)
model3 = create_model(base_model3)history1 = fit_model(model1)
model1.save('models/model1.h5')history2 = fit_model(model2)
model2.save('models/model2.h5')history3 = fit_model(model3)
model3.save('models/model3.h5')

让我们看看我们的模特们自己的表现。

MobileNetV2 的结果

InceptionV3 的结果

例外的结果

结果一点也不差,但我们仍将改进它们。

加载模型并冻结其图层

我们的下一步是加载我们刚刚在上面创建的模型,并冻结它们的层,这样当我们在它们上面安装我们的集合模型时,它们的权重不会改变。

def load_all_models():
    all_models = []
    model_names = ['model1.h5', 'model2.h5', 'model3.h5']
    for model_name in model_names:
        filename = os.path.join('models', model_name)
        model = tf.keras.models.load_model(filename)
        all_models.append(model)
        print('loaded:', filename)
    return all_modelsmodels = load_all_models()
for i, model in enumerate(models):
    for layer in model.layers:
        layer.trainable = False

连接它们的输出并添加密集层

将所有模型的输出放入一个连接层。然后添加具有一些单元的密集层,接着是具有单个输出和激活等于“sigmoid”的密集层,因为我们的任务是二进制分类。这可以被认为是一个人工神经网络,其中所有模型的预测作为输入,并提供一个输出。

ensemble_visible = [model.input for model in models]
ensemble_outputs = [model.output for model in models]
merge = tf.keras.layers.concatenate(ensemble_outputs)
merge = tf.keras.layers.Dense(10, activation='relu')(merge)
output = tf.keras.layers.Dense(1, activation='sigmoid')(merge)
model = tf.keras.models.Model(inputs=ensemble_visible, outputs=output)

编译和训练集合模型

我使用了经典的“Adam”优化器,学习率略高,为 10x-3,来编译模型。

model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001), loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), metrics=["accuracy"])

让我们看看我们的模型现在是什么样子。

集合模型

我们能像训练我们的个体模型一样,通过传递数据集来训练它吗?不要!在三个地方需要输入,而只产生一个输出。所以我们需要像这样配置我们的 X 值。

X_train = [X_train for _ in range(len(model.input))]
X_test = [X_test for _ in range(len(model.input))]

现在我们可以像以前一样拟合模型了。

history = model.fit(X, y_train,
                    batch_size=batch_size,
                    steps_per_epoch=len(total_train) // batch_size,
                    epochs=epochs, 
                    validation_data=(X_1, y_test),
                    validation_steps=len(total_val) // batch_size)

结果

首先,让我们为系综模型绘制图表。

集合模型的结果

我只对它进行了 20 个时期的训练,但看一下损失曲线就可以看出,曲线仍在下降,模型可以再训练一些时期。让我们看看这些模型在它们最后的时代给出了什么样的验证精度。

MobileNetV2 acc: 0.9788306355476379
InceptionV3 acc: 0.9778226017951965
Xception acc: 0.9788306355476379
**Ensemble acc: 0.9828628897666931**

总体精度几乎提高了 0.5%,如果考虑到之前的精度为 97.8%,这是一个巨大的提高。

以这种方式创建集合模型是一个非常长的过程。它需要比单一模型多四倍的努力,然而,它可以帮助获得多一点的准确性,这是很难获得的,一旦我们达到 90 以上的准确性。下面你可以找到完整的代码。

在结束之前,我想对这篇文章给予一些肯定,它帮助我完成了这篇文章。

使用检测器 2 对象检测和分类跟踪来检测和跟踪棒球

原文:https://towardsdatascience.com/detect-and-track-baseball-using-detectron2-and-sort-6dd92a46e6f2?source=collection_archive---------19-----------------------

当视频中有多个棒球时,我如何跟踪棒球。

棒球检测和跟踪。

介绍

在我的上一篇文章中,我使用 Detectron2 训练并构建了一个模型来检测视频中的棒球。

[## 如何使用 Detectron2 构建棒球检测器

使用自定义数据集的 Train Detectron2 对象检测。

towardsdatascience.com](/how-to-build-a-baseball-detector-using-detectron2-50b44edec6b7)

使用探测器 2 的棒球探测。(来自我之前的帖子)

它工作得很好,能够在大多数画面中捕捉到球。然而,将该模型应用于真实棒球练习视频的一个潜在问题是,视频中可能有不止一个棒球,如第一幅图所示。这个问题使得很难提取精确球的信息,例如球的速度和飞行角度。

解决这个问题的一个可能的方法是跟踪球并给它们分配唯一的 id,然后我可以计算每个球的信息并选择我想要的球。

有几种方法来跟踪物体,我决定使用亚历克斯·比雷的排序(简单的在线和实时跟踪)。详细介绍和论文可以在作者的报告中找到。我将在这篇文章中重点讨论实现。

[## abewley/排序

视频序列中 2D 多目标跟踪的简单在线实时跟踪算法。查看示例…

github.com](https://github.com/abewley/sort)

棒球追踪——排序

我使用了 Google Colab,所以我首先安装了我的 Google Drive,并将 sort.py 复制到这个文件夹中。然后我安装了排序和导入的需求。

!cp "gdrive/My Drive/Colab Notebooks/object_tracking/sort.py" .
!pip install filterpyfrom sort import *

然后我调用了排序对象

mot_tracker1 = Sort(max_age=3, min_hits=1, iou_threshold=0.15)

max_age、min_hist 和 iou_threshold 是可以根据要求进行调整的参数。

然后,我通过每帧更新跟踪器,将分类跟踪器集成到对象检测循环中。

track_bbs_ids = mot_tracker1.update(dets)

dets 是一个 numpy 检测数组,格式为[[x1,y1,x2,y2,score],[x1,y1,x2,y2,score],…]。

它将返回一个数组[[x1,y1,x2,y2,ID],[x1,y1,x2,y2,ID],…]。ID 是由 SORT 分配的唯一焊球 ID。

必须注意的是,即使在检测到空帧的情况下,也必须对每一帧调用该函数。无检测时使用 np.empty((0,5))。

然后我通过绘制边界框和 id 来可视化它。

球跟踪。

结果挺好的。地面上的球被检测到并被分配了 id。然而,快速移动的球并没有通过排序分配给任何 ID。这可能是由于框架之间的球的距离太大,球的尺寸太小。框架之间的边界框没有重叠,因此排序将它们视为不同的球。

我试验了上面显示的排序参数,并做了一些变通来解决这个问题。

为了进行排序,我手动将边界框变大,因此帧之间的重叠变大。

球跟踪。

现在飞球可以被捕获并分配到一个唯一的 ID。

最后,我可以反转并可视化真实的边界框。我把盒子转换成圆形,这样更适合球形的球。我还为球添加了一个尾巴来显示轨迹。

球跟踪

看起来不错!在这一点上,我有每一帧的球检测 ID。在探测循环期间,我存储在一个列表中,并将其转换为 pandas dataframe 以供进一步分析。

熊猫数据框中的球检测细节。

接下来:

  1. 检测效果不是很好,一些球没有被识别出来,还有一些噪音,比如白手套,鞋子等等。被鉴定为鲍尔。我需要扩展训练数据集并改进检测模型。
  2. 检测速度有点慢,也许可以尝试不同的架构。
  3. 从侧面拍摄视频,这样我就可以在不考虑失真的情况下计算速度和角度。

感谢阅读,欢迎反馈和建议!

在这里支持我:https://medium.com/@c.kuan/membership

检测后院的动物——深度学习的实际应用。

原文:https://towardsdatascience.com/detecting-animals-in-the-backyard-practical-application-of-deep-learning-c030d3263ba8?source=collection_archive---------3-----------------------

这篇文章基于我在真实(和农村)生活情况中应用现有深度学习技术的经验。

我将展示如何将深度学习技术应用到实践中,并从中获得乐趣。

您可以从 my Github repo 获得完整代码。

后院发现浣熊

动机

你可能已经从我以前的帖子中了解到,我是一个“自然爱好者”,当我们不在的时候,我总是想知道我们的乡间别墅后院发生了什么。狐狸到处游荡或浣熊在屋顶上行走的谣言是真实的还是只是故事?

牢记这一点,我安装了夜视运动启动摄像机对准我们的后院,并开始捕捉拜访我们的夜间物种。

首先,我在回顾自己的录音,发现即使每个人都睡着了,那里的生活仍在继续。相机证明,狐狸和浣熊是相当频繁的访客,知道我想保持跟踪他们。但是我不能每晚都录自己的节目,只挑选有趣的。

一台摄像机拍摄半年视频。因为树的移动导致了大量的误报。

因此,我需要一个自动化系统来区分由于风或快速光照条件变化而导致的树木移动的假阳性和真实的动物移动。

我已经决定检验一下是否有可能从现有的开源技术中获得优势,而不需要成为这方面的专家,也不需要在任何云解决方案和硬件上花费大量金钱。

这些动物来自哪里?

大约三分之一的勃兰登堡州被 15 个自然保护区占据(1 个国家公园、3 个生物圈保护区和 11 个自然公园)

的 Brandeburgs iNaturalist 页面上,你可以数出 23 种不同的哺乳动物,其中至少有 5 种是我在自家后院捕捉到的。

苍鹭落在后院。

其中至少有一只是松鼠。还是两者都有?

它是如何工作的?

  1. 捕捉: IP 户外摄像机捕捉运动并保存视频
  2. Store: 运行在 Raspberry Pi 3 上的 Small bash 通过 FTP 下载所有新视频,并保存到 NAS 存储中
  3. 分析:使用 GPU 加速 Tensorflow 的 Python 应用程序对传入的视频文件进行推理,并在有检测的情况下生成新视频
  4. 分享: Python 应用更新 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 bot,发送新的检测视频

在接下来的部分中,我将经历每一步,并与你分享我的发现。

捕获

为了捕捉运动,我使用了两个小米/小米户外相机,通过黑客固件扩展了相机功能。这是一款非常可爱又实惠的相机,你可以在户外使用,不用担心会摔坏。

摄像头指向后院

被黑版本的固件增加了所需的功能,如 FTP 服务器和 RTSP 流,以便与家庭助理等软件集成

商店

这是一个简单的部分。

在我的本地 Raspberry Pi 上,我已经向 cron 添加了一个小型 bash 脚本,用于下载所有新的视频文件,并将它们存储到 USB“Lots-Of-TBs”驱动器中。

我根据这里的说明改编了一个脚本:https://askubuntu . com/questions/758640/how-to-automatically-sync-the-contents-of-a-local-folder-with-the-contents-of-a

用于从摄像机中提取视频的 Cron 脚本

分析

所有收到的文件都通过 OpenCV 进行处理,并使用 Tensorflow 进行分析

这是需要根据硬件对软件进行适当调整的部分。正如你可能理解的那样,在乡下,你不会让庞大的服务器保持运行,所以你需要从你负担得起的设备中获取最大的收益。

旅程的开始

  1. 安装 OpenCV
  2. 多重处理视频阅读器
  3. 张量流模型兆探测器
  4. 一批
  5. 可能的优化:图形优化,TensorRT

由于我没有数据、资源和时间来训练我自己的动物检测神经网络,我在网上搜索今天可用的内容。我发现,即使有最先进的神经网络和从世界各地收集的数据,这项任务也不像看起来那么简单。

当然也有做动物检测的产品和研究。尽管如此,与我所寻找的有一个主要区别——他们从照片相机或智能手机相机中检测生物,这样的照片在颜色、形状和质量上与你用运动检测相机获得的照片不同。

但是,不管怎样。仍然有一些项目和我的目标一样。我的搜索把我带到了微软的 CameraTraps 项目。据我所知,他们正在使用从世界各地不同的野生动物摄像机收集的数据构建图像识别 API。因此,他们开源了预先训练的模型,用于检测图像上是否出现“动物”或“人”,称为“ MegaDetector

该模型的主要限制来自模型的名称。它只是一个“探测器”,而不是一个“分类器”

微软关于检测器和分类器的声明

即使考虑到这样的限制,这样的方法确实非常适合我。

该模型被训练成检测三种不同的类别:

  1. 动物
  2. 车辆

浣熊被认定为“动物”类

在大多数情况下,当谈到视频对象检测时,您会在各种博客帖子中找到实时视频。我的情况有点不同——作为输入,我有一大堆由摄像机产生的视频文件,作为输出,我也想要视频文件。

用于在 Python 中读写视频文件——事实上被认为是 OpenCV 库。我也发现它是我最喜欢的图像处理包。

对视频文件进行推理的逻辑非常简单:

  1. 阅读:从视频中获取一帧
  2. 检测:对图像进行推断
  3. 写:如果有检测,保存一帧视频到新文件。
  4. 重复:运行步骤 1-3,直到视频结束

它可以用这个代码示例来实现

使用 OpenCV VideoReader 进行 Tensorflow 对象检测

尽管这种简单的方法在同一个线程读写时有几个瓶颈,但它是有效的。因此,如果你正在寻找一个代码来在视频上尝试你的模型,检查那个脚本

我花了大约 10 分钟来处理一个全高清 1 分钟 10 FPS 的视频文件。

Detection took 9 minutes and 18.18 seconds. Average detection time per frame: 0.93 seconds

但是你可以找到很多这样的教程——告诉你如何运行一个普通的 OpenCV/Tensorflow 推理。具有挑战性的部分是如何让代码持续运行并具有良好的性能。

输入/输出块

根据提供的代码,读取帧、检测和写回都在同一个循环中发生,这意味着迟早有一个操作会成为瓶颈,例如,从“不太稳定”的网络存储中读取视频文件。

为了去掉这一部分,我使用了来自一个出色的计算机视觉博客 Adrian Rosebrock 和他的库 imutils 的指令。他提供了将读取帧和处理帧分割成多个线程的方法,这种方法为我提供了一个预先填充好的帧队列,准备进行处理。

Adrian rose Brock 修改的文件视频流

它不会对推断时间产生太大影响,但它有助于慢速驱动器,这些驱动器通常用于视频存储。

优化:图形分析

我听说的另一部分是优化部署模型。我遵循了一个在这里发现的指南:https://towards data science . com/optimize-NVIDIA-gpu-performance-for-efficient-model-inference-F3 e 9874 e 9 FDC并通过分配非 GPU 支持的层在 CPU 上处理来实现一些改进。

[INFO] :: Detection took 8 minutes and 39.91 seconds. Average detection time per frame: 0.86 seconds

批量推断

根据我以前的经验,深度学习训练的瓶颈之一是从磁盘到 GPU 的数据传输,为了最大限度地减少时间,当 GPU 一次获得几个图像时,会使用所谓的“批处理”。

我想知道是否有可能对推理进行同样的批处理。幸运的是,根据 StackOverflow 的回答,这是可能的。

我只需要找到最大可接受的批量大小,并传递数组或帧进行推断。为此,我用批处理功能扩展了FileVideoStream

[INFO] :: Detection took 8 minutes and 1.12 second. Average detection time per frame: 0.8 seconds

优化:从源代码编译

当我们谈论运行繁重、耗时的计算时,另一个重要部分是从硬件中获取最大收益。

最直接的方法之一是使用机器类型的优化包。每位 Tensorflow 用户都看到过的信息:

tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2

这意味着 Tensorflow 由于忽略内置 CPU 优化而没有充分利用硬件。原因是安装了通用包,它可以在任何类型的 x86 机器上工作。

提高其性能的一种方法是安装来自第三方的优化包,如https://github.com/lakshayg/tensorflow-buildhttps://github.com/mind/wheelshttps://github . com/yaroslavvb/tensor flow-community-wheels/issues

另一种方法是按照谷歌的指示,从源码https://www.tensorflow.org/install/source#tensorflow_1x编译这个包。但是考虑到,如果你以前没有经验,这可能有点困难,而且这是一个相当耗时耗内存的过程(上次在我的六核 CPU 上花了 3.5 小时)。

OpenCV 也是如此,但这是一个更复杂的主题,所以我不在这里讨论。Adrian Rosebrock 提供了一些方便的指南,如果你对这个话题感兴趣,请跟随他们。

分享

小 Python 应用程序等待带有检测的输入视频。当视频到达时,它更新了我的电报频道。我已经使用了我的以前的项目,它将传入的视频重新发送到我的电报频道。

该应用程序是这样配置的,并使用看门狗库持续监控文件夹中的新文件

{
    "xiaomi_video_watch_dir" : PATH_TO_WATCH,
    "xiaomi_video_temp_dir" : PATH_TO_STORE_TEMP_FILES,
    "xiaomi_video_gif_dir" : PATH_WITH_OUTPUT_GIFS,
    "tg_key" : 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨_KEY
}

初始电报组版本

什么没成功?

这个项目给我带来了很多新的知识,即使我已经设法达到了我的最终目标,我也经历了一些失败的尝试。我认为这是每个项目最重要的部分之一。

图像增强

在我的研究过程中,我看到了几份来自 iWildCam Kaggle 竞赛参与者的报告。他们经常提到将 CLAHE 算法应用于直方图均衡化的输入图像。我已经尝试了上述算法和其他几种算法,但没有成功。应用图像修改降低了成功检测的数量。但说实话,夜间摄像头的图像看起来更清晰。

**def** enchance_image(frame):
   temp_img = frame
   img_wb = wb.balanceWhite(temp_img)
   img_lab = cv.cvtColor(img_wb, cv.COLOR_BGR2Lab)
   l, a, b = cv.split(img_lab)
   img_l = clahe.apply(l)
   img_clahe = cv.merge((img_l, a, b))
   return cv.cvtColor(img_clahe, cv.COLOR_Lab2BGR)

左图:CLAHE 应用版。右图:未增强

优化:TensorRT

出于某种原因,我无法遵循构建 tensort 引擎的指南,但是普通的 TF-tensort 文档工作得很好。

TF-TRT 模型优化

即使成功结束了优化,也没有发生推理加速。

[INFO] :: Detection took 8 minutes and 59.68 seconds. Average detection time per frame: 0.9 seconds

我的想法是,模型架构对于自动 TensorRT 引擎构建来说太深奥了。但是谁知道呢?

神奇加速

我有很多期望的另一个想法是从模型和图形优化中获得显著的加速。我期望得到接*文档和 YouTube 说明的结果(3-4 倍加速),但我只得到大约 1.3-1.5 倍,这当然比什么都没有好得多。

我对为什么加速没有如此戏剧性的想法如下:

  1. GPU 是一个瓶颈——没有足够的 VRAM 不会给快速计算留下太多空间。
  2. 用于 MegaDetector 的模型架构非常复杂(更快的 RCNN ),不适合自动优化
  3. 我做了错事,_(ツ)_/。但至少,我试过了。

充分利用 CPU 和 GPU

我不太喜欢的另一部分是 CPU 利用率。当 GPU 被计算堵塞时,CPU 消耗大约为 30%。我已经尝试给它一些额外的工作来预取视频帧,但它仍然没有在推理过程中发挥重要作用。

我希望从 Tensorflow 库中获得一些并行计算,但这似乎是我所能达到的最大程度。

我有一个想法,有两个并行的 Tensorflow 会话——一个用于 GPU,一个用于 CPU,但这有太多的工作要做。

未来计划

  1. 用神经网络发布 Docker 图像
  2. 与微软团队分享关于误报的发现
  3. 将代码打包到 python 包中

捕捉到的视频令人惊叹

这里给读完的读者一点小奖励:)

捕获和检测到的香料示例。

使用半空间树检测数据流中的异常

原文:https://towardsdatascience.com/detecting-anomalies-in-data-streams-2daedbdaa436?source=collection_archive---------29-----------------------

scikit-multiflow 简介和一种有前途的异常检测技术。

如今,许多领域都可以访问连续的数据流。如果没有一定程度的自动化,个人或团队通常很难管理这些信息。在展示流学习领域中一些令人兴奋的新发展之前,我想先从几个定义开始。

数据流: 一个*乎连续的数据源。例如传感器数据或遥测数据。

流学习: 机器学习的子领域专注于开发专门从数据流中学习的技术。

既然我们在同一页上,我想介绍一下工具包!我将使用新的(ish) python 库 scikit-multiflow

连续数据流正迅速成为许多机器学习应用的标准。像 scikit-multiflow 这样的专用库为流式数据提供了一个熟悉的用户界面。图片来自 Unsplash (Joshua Sortino)

为了这篇短文的目的,我将使用 skmultiflow 的内置数据生成器来创建数据流。

这里我使用 AnomalySineGenerator 类来生成一个包含异常点的数据集。

stream = AnomalySineGenerator(n_samples=1000, n_anomalies=250)

该发生器对正弦和余弦函数进行随机采样,以生成应在给定范围+-一些噪声内的数据。

为了让大家了解数据集的样子,我在下面用橙色突出显示了异常情况。

生成的数据集的绘图。异常点用橙色突出显示。图片作者。

现在,我们可以使用 skmultiflow 的流式半空间树异常检测器,并评估它在我们的数据集中检测异常的能力。

half_space_trees = HalfSpaceTrees()

在[ 1 中介绍了 skmultiflow 中使用的 HS-Tree 异常检测技术。尽管将 HS-Trees 与流数据耦合起来并不简单,但从概念上讲,该算法以一种简单的方式工作。

通过 HS-Trees 进行数据分区的示例(图片来自[ 1 ])

每个 HS-Tree 将数据空间划分成几个窗口,并根据每个窗口中的数据点数量进行预测。对于异常检测,大多数点应该落在相同的窗口内,那些不在窗口内的点被预测为异常。当然,在现实中,该算法是一种集成算法,这意味着生成许多 HS-树,并且预测是这些树的多数投票。

既然我们对算法的作用有了更好的了解,我们可以继续进行预测。在下面的代码中,我们遍历流并进行预测,同时通过对每个新样本调用 partial_fit()来不断更新模型。

max_samples = 1000
n_samples = 0
true_positives = 0
detected_anomalies = 0
preds = []
target = []stream.restart()
while n_samples < max_samples and stream.has_more_samples():
    X, y = stream.next_sample()
    target.append(y[0])
    y_pred = half_space_trees.predict(X)
    preds.append(y_pred)
    if y[0] == 1:
        true_positives += 1
        if y_pred[0] == 1:
            detected_anomalies += 1
    half_space_trees.partial_fit(X, y)
    n_samples += 1

最终,流学习算法正确地预测了它负责识别的 221 个异常中的 165 个!

检查这些预测,很明显这个模型忽略了数据流早期的异常。这很直观,因为 it 没有太多时间来了解数据的底层分布。此外,在这种特定情况下,“异常数据”占整个数据集的很大一部分,这可能使决策树在早期面临挑战。

好吧,我希望你们都喜欢学习一些关于流学习的知识!Scikit-Multiflow 拥有一个充满活力的开发人员社区,非常受欢迎。如果你正在寻找一个好的开源项目,我强烈建议你参与!

参考文献:

[ 1 ] S.C.Tan,K.M.Ting,和 T.F.Liu,“流数据的快速异常检测”,载于 ij Cai Proceedings-International Joint Conference on Artificial Intelligence,2011,vol. 22,no. 1,PP . 1511–1516。

用计算机视觉检测儿童孤独症谱系障碍

原文:https://towardsdatascience.com/detecting-autism-spectrum-disorder-in-children-with-computer-vision-8abd7fc9b40a?source=collection_archive---------25-----------------------

凯利·西克玛在 Unsplash 上的照片

调整面部识别模型以检测自闭症谱系障碍

计算机视觉(CV)已经帮助医疗领域诊断骨折血栓,甚至癌瘤。它还可以用来帮助专家诊断自闭症。

自闭症谱系障碍(ASD) 是一种神经和发育障碍,始于儿童早期,持续人的一生。专家认为,患有 ASD 的人有独特的面部特征,这可以用来帮助诊断他们的 ASD ,甚至与 ASD 的严重程度相关。这种相关性可用于训练 CV 模型,以使用那些独特的面部特征来检测 ASD。

目标是提供一个免费的初步诊断工具,可以帮助父母决定进行进一步的 ASD 测试。对于具有重大现实影响的模型来说,负责任地表示它们的结果并使用贝叶斯统计来解释它们的意义是很重要的。

为什么这很重要

大约 25% 的自闭症儿童未被确诊。诊断自闭症是一个复杂的 T21 和昂贵的过程,不是每个家庭都能经历的。让合适的孩子去看合适的专家对于减少未确诊儿童的数量和家庭负担至关重要。

我想强调的是,我的目标不是诊断 ASD。相反,我想利用 CV 的力量和贝叶斯统计的基本原理来帮助父母决定他们是否应该带他们的孩子去看自闭症专家。

履行

所有的代码都可以在 GitHub 上获得,数据可以在 Kaggle 上获得。

[## mm 909/ka ggle-自闭症

用计算机视觉检测儿童自闭症谱系障碍——采用面部识别模型检测…

github.com](https://github.com/mm909/Kaggle-Autism) [## 自闭症儿童数据集

训练模型以从面部图像中检测儿童自闭症的数据集

www.kaggle.com](https://www.kaggle.com/gpiosenka/autistic-children-data-set-traintestvalidate/version/5)

数据

Kaggle 数据集的第 5 版有 2940 幅图像,*均分为两类:自闭症和非自闭症。这些图像大小不一,但已经被裁剪成只显示孩子的脸。

资料来源:Kaggle,自闭症儿童数据集 v5

年龄

该数据集的年龄分布大约为 2 岁到 14 岁,但大多数照片来自 2 岁到 8 岁的儿童。

资料来源:Kaggle,自闭症儿童数据集 v5

性别

性别比例接*各自人口。男性被诊断为自闭症的人数是女性的 3 倍。因此,自闭症班级中男女比例接* 3:1。在非自闭症班级中,这一比例更接* 1:1。

资料来源:Kaggle,自闭症儿童数据集 v5

人种

白人儿童与有色人种儿童的比例是 10:1。这和美国的真实分布接* 7:1

资料来源:Kaggle,自闭症儿童数据集 v5

模型

该模型将基于 VGG 人脸牛津深度面部识别模型。****

迁移学习

为了提取检测自闭症所需的面部特征,新模型将使用与 VGG 人脸相同的架构和权重。这是特征表征迁移学习的一个例子。当源域和目标域寻找相似的特征,但基于这些特征做出不同的推断时,使用这种类型的迁移学习。

特征-表征迁移学习,来源:作者与 Lucidchart

牛津模型被训练来识别潜在的面部特征,以识别独特的面孔。新模型还想识别潜在的面部特征,但要检测自闭症。

结果

尽管在训练过程中使用准确性来衡量模型性能,但对于贝叶斯预测来说,灵敏度和特异性是更重要的考虑因素。

学习曲线

该模型在 44 个时期后在验证集上达到 85%的准确度。该模型在纪元 60 左右开始过度拟合。

最佳模型的学习曲线,来源:作者

混淆矩阵

编辑 2020 年 8 月:此表有误。假阴性应该有假阳性值,假阳性应该有假阴性值。接下来的一切仍然是正确的信息,但数字不正确。

最佳模型的混淆矩阵,来源:作者

灵敏度和特异性

灵敏度和特异性用于量化模型预测假阴性和假阳性的频率。

敏感性是真正的阳性率。它衡量一个积极的预测正确的频率。

来源:作者用代码编码

特异性是真正的阴性率。它衡量一个负面预测正确的频率。

来源:作者用代码编码

该模型实现了 76%的灵敏度和 85%的特异性。

影响:贝叶斯规则

贝叶斯规则对于理解任何机器学习(ML)模型产生的结果都是至关重要的。

贝叶斯法则,来源挪威创造

模型可能是错误的

重要的是要记住模型是会出错的。模型的正面结果并不意味着现实世界的正面结果。相反,这个新的信息,就像一个积极的预测,应该用来更新我们之前对该事件的了解。

贝叶斯计算

随机选择的男性患自闭症的概率非常低,约为 2.7%。这是男性在知道任何其他信息之前患有自闭症的概率。因此,它被称为先验概率。

模型预测提供了新的信息,在做出决策时,应结合现有知识考虑这些信息。

贝叶斯定理可用于量化这种新信息对先验概率的影响程度。这个更新的概率称为后验概率。

利用模型的敏感性和特异性,可以计算出阳性预测的后验概率。对于男性来说,阳性结果会使患自闭症的概率从 2.70%增加到 12.34%。对于女性,概率从 0.66%增加到 3.27%。

贝叶斯规则的结果,来源:作者

限制

真实地展示模型的不足之处,可以让开源软件做出更好的贡献,也可以让数据科学整体变得更好。

一如既往:更好的数据,更好的模型。

年龄

这个模型是在 2 岁到 8 岁的儿童图像上训练的。因此,在该范围之外对儿童进行测试将给出不太准确的结果。

人种

白人儿童与有色人种儿童的比例是 10:1。缺乏有色人种儿童的训练数据意味着结果对他们来说不太准确。

结论

诊断自闭症是一个困难且昂贵的过程。幸运的是,面部特征和自闭症之间的相关性意味着可以训练一个 CV 模型来检测它。使用贝叶斯统计,可以负责任地报告该模型的结果,父母可以对孩子的健康做出更明智的决定。

项目存储库

** [## mm 909/ka ggle-自闭症

用计算机视觉检测儿童孤独症谱系障碍——采用面部识别模型检测

github.com](https://github.com/mm909/Kaggle-Autism)**

用贝叶斯模型检测新冠肺炎病例的变化

原文:https://towardsdatascience.com/detecting-changes-in-covid-19-cases-with-bayesian-models-1b628214e8b1?source=collection_archive---------30-----------------------

贝叶斯变点模型,以估计不同国家的新新冠肺炎病例数开始变*的日期。

弗洛里安·奥利佛在 Unsplash 上拍摄的照片

问题

当前全球疫情及其相关资源(数据、分析等)。),一段时间以来,我一直试图提出一个有趣的新冠肺炎问题,用统计数据来攻击。在查看了一些县的确诊病例数后,很明显在某个日期,新增病例数不再呈指数增长,其分布也发生了变化。然而,这个日期对每个国家来说是不同的(很明显)。这篇文章介绍并讨论了一个贝叶斯模型,用于估计特定国家新新冠肺炎病例分布变化的日期。模型系数是可解释的,可用于未来分析不同国家采取的社会距离措施的有效性。

在我们深入研究之前,有一个重要的提醒是,所有的模型都是错误的,但有些是有用的。这个模型对于估计变革的日期是有用的,但对于预测新冠肺炎将会发生什么是没用的。它不应该被误认为是一个惊人的流行病学模型,它会告诉我们隔离何时结束,而是一种用概率分布描述我们已经观察到的情况的方式。

这篇文章的所有代码可以在这里找到,你可以在这里阅读这篇文章的原始版本。

模型

我们想要描述 y ,特定国家每天新增新冠肺炎病例数的对数,作为 t 的函数,即该病毒在该国开始传播的天数。我们将使用分段回归模型来实现这一点。we 分段的点将由学习参数τ确定,如下所述:

换句话说, y 将被建模为 w ₁ + b ₁,直到第τ天。在那之后,它将被模仿成₂+₂.

这个模型是用 Pyro 编写的,这是一种基于 PyTorch 的概率编程语言。这篇文章中包含了大量代码,但是大部分代码都在的笔记本中。

数据

使用的数据是从 Kaggle 下载的。我们掌握的是每个国家每日确诊病例的数量,下图显示了意大利的这一数据。很明显,在如何报告数据方面存在一些不一致,例如,在意大利,3 月 12 日没有新增确诊病例,但 3 月 13 日的预期病例增加了*一倍。在这种情况下,数据被分成两天。

这种病毒在不同的国家不同的时间开始传播。因为我们有一个回归模型,所以在病毒出现在某个特定国家之前包含数据是不合适的。这一日期是根据新病例的进展情况为每个国家人工选择的,决不是记录第一个患者的日期。“开始”日期最好解释为病毒开始持续增长的日期,而不是记录患者 0 的日期。

先前规格

病毒的增长对各个国家的人口动态很敏感,而我们可用的数据量有限,因此事先说明在这里非常重要。

w ₁和 w ₂开始,这些参数可以大致解释为日期变更前后病毒的增长率。我们知道,增长在开始时将是正的,不可能大于 1(毕竟, w ₁是一个梯度)。有了这些假设, w ₁ ~ N(0.5,0.25)是一个合适的先验。我们将对 p(w ₂ ) 使用类似的逻辑,但是要记住灵活性。如果没有足够灵活的先验,在数据中没有真正的变化点的情况下,模型不会做得很好。在这些情况下, w ₂ ≈ w ₁,我们将在结果部分看到这个例子。现在,我们希望 p(w) 关于 0 对称,大多数值位于(-0.5,0.5)之间。我们将使用 w ₂ ~ N(0,0.25)。

接下来是偏向项, b ₁和 b ₂.这些参数的先验对国家特征特别敏感。新冠肺炎暴露程度较高的国家(无论出于何种原因)在高峰期的确诊病例将多于暴露程度较低的国家。这将直接影响 b ₂的后验分布(这是第二次回归的偏差项)。为了使该参数自动适应不同的国家,我们分别使用 y 的第一个和第四个四分位数的*均值作为 b ₁和 b ₂ 的先验*均值。 b ₁的标准差取为 1,这使得 p(b) 成为一个相对*坦的先验。将 p(b) 的标准差取为其先验均值的四分之一,这样先验均值越大。

至于τ,由于此时我们无法访问所有数据(病毒正在传播),我们无法获得完全*坦的先验并让模型对其进行估计。相反,假设变化更可能发生在手头日期范围的后半部分,因此我们使用τ ~ Beta(4,3)。

下面是用 Pyro 写的模型。

class COVID_change(PyroModule):
    def __init__(self, in_features, out_features, b1_mu, b2_mu):
        super().__init__()
        self.linear1 = PyroModule[nn.Linear](in_features, out_features, bias = False)
        self.linear1.weight = PyroSample(dist.Normal(0.5, 0.25).expand([1, 1]).to_event(1))
        self.linear1.bias = PyroSample(dist.Normal(b1_mu, 1.))
        self.linear2 = PyroModule[nn.Linear](in_features, out_features, bias = False)
        self.linear2.weight = PyroSample(dist.Normal(0., 0.25).expand([1, 1])) #.to_event(1))
        self.linear2.bias = PyroSample(dist.Normal(b2_mu, b2_mu/4)) def forward(self, x, y=None):
        tau = pyro.sample(“tau”, dist.Beta(4, 3))
        sigma = pyro.sample(“sigma”, dist.Uniform(0., 3.))
        # fit lm’s to data based on tau
        sep = int(np.ceil(tau.detach().numpy() * len(x)))
        mean1 = self.linear1(x[:sep]).squeeze(-1)
        mean2 = self.linear2(x[sep:]).squeeze(-1)
        mean = torch.cat((mean1, mean2))
        obs = pyro.sample(“obs”, dist.Normal(mean, sigma), obs=y)
        return mean

哈密顿蒙特卡罗用于后验采样。这方面的代码如下所示。

model = COVID_change(1, 1,
                     b1_mu = bias_1_mean,
                     b2_mu = bias_2_mean)num_samples = 800
# mcmc
nuts_kernel = NUTS(model)
mcmc = MCMC(nuts_kernel,
            num_samples=num_samples,
            warmup_steps = 100,
            num_chains = 4)
mcmc.run(x_data, y_data)
samples = mcmc.get_samples()

结果

因为我住在加拿大,接触到预防措施开始的日期,所以建模将从这里开始。我们将 2 月 27 日作为病毒“开始”的日期。

前科:

后验分布:

从₁的 w 和₂的 w 的后验概率开始,如果数据没有变化,我们预计会看到这两个分布彼此接*,因为它们控制着病毒的增长率。这些分布以及₁和₂的后验概率没有重叠,这是一个好现象。这证明了我们的模型估计的变化点是真实的。

这个变化点估计为:2020–03–28

作为补充说明(警告:不科学)我的公司在 3 月 16 日发布了一项在家工作的强制性政策。大约在这一天,多伦多的大多数公司都会发布强制性在家工作政策。假设报告的病毒潜伏期长达 14 天,这一估计日期的变化是合理的,因为它是在广泛的社会距离措施开始后的 12 天!

在下图中可以看到模型拟合以及 90%可信区间带。左边是每日案例数的日志,这是我们用来拟合模型的,右边是每日案例的真实数量。单纯看日例数很难直观确定一个变化点,看确诊总例数更难。

评估趋同

运行这些实验时,最重要的步骤是诊断 MCMC 的收敛性。我通过观察链的混合和*稳性以及 R_hat 来采用 3 种方法评估该模型的收敛性。R_hat 是当样本数趋于无穷大时,每个后验分布将减少的因子。理想的 R_hat 值是 1,但是小于 1.1 的值是收敛的强指示。我们观察马尔可夫链的混合和*稳性,以便知道 HMC 是否产生合适的后验样本。

下面是每个参数的轨迹图。每条链都是固定的,混合良好。此外,所有 R_hat 值都小于 1.1。

收敛之后,在继续其他示例之前,最后要检查的是模型对数据的适合程度。和之前做的假设一致吗?为了测试这一点,我们将使用残差图和 QQ 图,如下所示。
我已经列出了估计的变化点,以便比较变化前后的残差来检验同质性。残差服从均值为零的正态分布,在变化日期之前和之后都不依赖于时间。

没有变化呢?

啊哈!如果新病例的数量还没有开始变*呢?!为了测试该模型对这种情况的稳健性,我们将查看加拿大截至 3 月 28 日的数据。这是模型估计曲线在加拿大开始变*的日子。

没有真实的更改日期并不意味着模型会输出“无更改”(lol)。我们将不得不使用后验分布来推断模型提供的变化日期是不合适的,因此数据中没有变化。

前科:

后验分布:

w ₁和 w ₂的后验概率有明显重叠,表明病毒的增长率没有明显变化。₁b和₂b的后验概率也是重叠的。这些表明模型很难估计一个合理的τ,这对我们来说是一个很好的验证,先验并不太强。

尽管我们已经得出结论,该数据没有更改日期,但出于好奇,我们仍将绘制该模型。

与前面的例子相似,MCMC 已经收敛。下面的轨迹图显示了链的充分混合和稳定性,并且大多数 R_hat 值小于 1.1。

后续步骤和未决问题

该模型能够很好地描述数据,足以产生曲线开始变*的日期的可靠估计。一个有用的副产品是第二条回归线的系数项, w ₂.通过计算不同国家的₂和₂,我们可以比较他们的社交距离措施的有效性。这一分析和更多内容可能会在随后的文章中发布。

请关注我的个人博客上的相关帖子!

感谢您的阅读,如果您有任何建议或推荐,请通过电子邮件或其他方式联系我,甚至只是聊天!

检测在线文章评论中的建设性

原文:https://towardsdatascience.com/detecting-constructiveness-in-online-article-comments-477bf4b4bd8?source=collection_archive---------79-----------------------

使用带 ktrain 的 Distilbert 的端到端分类教程

马修·施瓦茨在 Unsplash 上的照片

促进在线评论区的建设性是让互联网成为一个更有生产力的地方的重要一步。除了通过简单地指出错误或试图伤害来给出反馈,建设性可以通过论证和尊重的话语技巧来使用,以便利用这些过去的错误来进行未来的改进。

类似于情感分析或毒性检测,可以使用深度学习技术来建模建设性和分类文章评论。当前最先进的模型使用 transformer 架构,在并行处理输入序列时,它比通常的递归单元(LSTM、GRU……)更有效。在这篇文章中,我们将使用由 HuggingFace 创建的 Distilbert (Sanh 等人,2019)。该模型是 BERT (Devlin 等人,2018 年)的精华版本,本质上意味着一个轻得多的模型,几乎达到类似的性能。我们将使用 ktrain Python 库(Maiya,2020),它允许在 Tensorflow Keras 中非常容易地实现最先进的模型。关于 ktrain 实现的更多信息,本教程官方文档可以帮到你!

对于建设性来说,标记数据的数量相当有限,所以我们将使用最大和最新的一个,建设性评论语料库(C3),可在 Kaggle 上获得,并在 Kolhatkar 等人(2020)中详细描述。该数据集由 12000 条新闻评论组成,包含几个建设性和毒性标签,但我们将使用的唯一标签是 constructive_binary

数据处理

像往常一样,第一步是导入项目所需的所有库。您将需要安装 ktrain ,根据您的设置,这可能会很棘手,然后导入它。我们还从 scikit-learn 导入了基本的三重奏熊猫numpymatplotlib ,以及一些度量和拆分工具。

让我们从读取熊猫数据帧中的数据集文件开始。我们还应该看看我们感兴趣的列, comment_textconstructive_binary

C3 数据帧头

我们很快就需要知道我们想要允许的最大输入长度,所以了解一下注释长度是很有用的。运行以下代码以显示 DataFrame comment 列的描述。

结果显示长度*均值为 71 个标记,第 90 个和第 99 个百分点分别对应于 157 和 362 个标记,因此将 MAXLEN 设置在 150 到 200 个标记之间似乎是个好主意。为了节省一些内存空间,就说 150 吧。

接下来,我们应该定义几个全局变量,包括最大输入长度、数据集的路径和保存训练模型路径、目标标签名称和我们想要使用的 HuggingFace 模型,在我们的例子中是 bert-base-uncased ,它只使用小写输入。

现在让我们看一下输出类分布,以检查数据集是否*衡:

目标类别分布

建设性的评论比非建设性的评论多,所以数据集略有不*衡。在验证和测试步骤中,我们希望保持输出类的良好代表性,这意味着我们希望目标类分布在所有 train/val/test 集中是相同的。为此,我们将使用 scikit-learn 实现的分层分裂。让我们从划分训练集(我们称之为中间集)和测试集开始,将完整集的 20%放在一边。为了更加方便,数据帧的索引可以在以后重新设置。

将另外 10%到 20%的训练数据设置为验证目的是一种好的做法,此外,在 ktrain 中使用验证集是可能的,因此我们再次使用分层分裂,并将 10%设置为备用。再次重置每个数据帧的索引。

完美!我们现在已经准备好使用三个数据集,所以让我们将输入和输出分开,以馈入我们的机器学习模型。您可以将输入列(X)读入一个 numpy 数组,并将输出(y)转换为一个小 int。

分类

现在是时候通过加载一个 Transformer 对象来初始化 ktrain 模块了,该对象采用前面定义的 MODEL_NAMEMAXLEN标签。最先进的体系结构不一定需要特殊的预处理,如停用词删除、标点符号删除等。相反,他们使用一种特殊的无监督标记化方法,优化了称为 WordPiece 的词汇外(OOV)的数量。由于这一点,并且因为我们的数据集不是很嘈杂,我们简单地使用 ktrain 预处理器。最后,您可以获得一个分类器对象,然后获得一个采用 batch_size 超参数的学习器对象。这个超参数在逻辑上可以根据您的需要进行调整(就像 MAXLEN 一样),但是在增加它时要注意内存问题。

以下代码为您完成了所有这些工作:

就在训练模型之前,您可以选择使用学习率查找器(Smith,2018)轻松优化学习率调整过程,它基本上在短期内训练模型,同时以指数方式提高学习率:

学习率查找图表

一个可供选择的学习率值位于第一个显著下降的斜坡上,比第一个*坦区域稍靠前一点,红色箭头指向的位置。在这种情况下,合适的值是 0.00001。让我们现在最后训练模型。我们使用循环训练政策(Smith,2017)来连续增加和减少学习率,但如果您想改变,也可以使用其他政策! 4 个时期对于模型收敛来说肯定是足够的,但是这也可以根据您的方便进行调整(训练这样大的模型需要大量的时间和资源!).

详细培训

一旦训练结束,您可以使用学习者对象的 validate 方法进行验证,但是为了简短起见,我们将跳过这一部分。

ktrain 的预测器对象允许对新数据进行预测。运行下面的代码对整个测试集进行预处理和分类。它还打印了几个常用的指标来帮助您解释结果。

测试集上的构造性分类结果

我们达到了 0.94 加权 F1 和 0.94 的精度,非常好,干得好!您的 Distilbert 模型现在适合检测建设性的新闻文章评论。您可以用下面的代码行保存模型,但是要注意,它相当重(~300MB)。

现在由您来调整超参数,使用更高级的机器学习方法或更重的模型(BERT、XLNet 等)。)去尝试,去取得更好的成绩!

感谢阅读! 我希望这对你来说是有益的,对我来说也是有趣的

参考

德夫林、雅各布、张明蔚、肯顿·李和克里斯蒂娜·图塔诺瓦(2018)。“BERT:用于语言理解的深度双向转换器的预训练”。 arXiv 预印本 arXiv:1810.04805

Kolhatkar、Varada、Nithum Thain、Jeffrey Sorensen、Lucas Dixon 和 Maite Taboada(2020)。《C3:建设性评论文集》。竖锯和西蒙·弗雷泽大学”。d O I:10.25314/ea 49062 a-5c F6–4403–9918–539 e 15 FD 7b 52

马亚,阿伦 S (2020)。“ktrain:用于增强机器学习的低代码库”。 arXiv 预印本 arXiv:2004.10703

莱斯利·史密斯(2017)。“训练神经网络的循环学习率”。2017 年 IEEE 计算机视觉应用冬季会议。 IEEE,第 464–472 页

莱斯利·N·史密斯(2018)。“神经网络超参数的训练方法:第 1 部分-学习速率、批量大小、动量和权重衰减”。 arXiv 预印本 arXiv:1803.09820

用迁移学习从胸部 X 射线检测新冠肺炎诱发的肺炎:在 Tensorflow 和 Keras 中的实现。

原文:https://towardsdatascience.com/detecting-covid-19-induced-pneumonia-from-chest-x-rays-with-transfer-learning-an-implementation-311484e6afc1?source=collection_archive---------3-----------------------

深度学习正在向新型冠状病毒进军。

介绍

新型冠状病毒(SARS-COV-2)已经成为人类面临的最紧迫的问题。新冠肺炎病像野火一样席卷全球,仅在三个月内就改变了全球面貌。高繁殖率和更高的并发症几率导致了边境关闭、空无一人的街道、猖獗的囤积、大规模的自我隔离政策、经济衰退和文化转向不信任。世界进入了一场新的世界大战,由一个看不见的敌人发动了闪电战。

随着发达国家的病例数量不断增加,各国政府正在慢慢意识到这个问题的严重性,人们希望看到全世界团结起来应对这一威胁。然而,无论是在 T2、国家还是个人层面,我们仍然可以观察到分歧和不信任。关于种族主义袭击盗窃不负责任行为的报道十分猖獗。医生呼吁公众认真对待这种情况,并在避免所有非必要旅行的同时就地躲避。

选定国家的 COVID 病例数 19。(图片来源:路透社)

三月前抗击病毒的策略主要围绕遏制和追踪——在疾病发展之前发现和隔离可能的病例。然而,随着病例的指数增长,世界各地的医院已经迅速变得不堪重负,政府政策已经转向缓解甚至接受。受影响国家缺乏检测能力进一步加剧了这一令人沮丧的过程,导致确诊病例数落后于真实值。这导致中国卫生当局暂时转而根据症状和胸部 x 光/CT 进行诊断。然而,这种解决方案仍然存在与其他肺炎原因重叠的风险,它们导致了许多混乱,国家又回到了基于 PCR(聚合酶链式反应)的测试。

基于人工智能的解决方案最*已被广泛探索用于 研究 中的肺炎检测,此类方法也已在本次疫情期间提出。据报道,定制模型的灵敏度和特异性接* 90%。然而,它们在确定肺炎病因方面的特异性,特别是对其他病毒性疾病(如流感)的特异性,仍在激烈辩论中。它们固有的实验性质要求同时使用确认方法,作为多学科诊断方法的一部分。

在本文中,我们将探讨使用相对简单的迁移学习过程和受约束的数据集,构建一个能够在胸部 X 射线中检测各种肺炎原因的系统的可行性和困难。当然,这里描述的方法和内容仅用于教育目的。这不是一项科学严谨的研究,不应用于医学目的。

履行

我们已经在以前的文章中详细介绍了 迁移学习 卷积神经网络 ,强烈推荐我们的读者参考它们以获得更全面的考虑。

为了解决手头的问题,我们收集了自己的数据集,将蒙特利尔大学的约瑟夫·保罗·寇恩博士收集的 Kaggle 胸部 x 光数据集COVID19 胸部 x 光数据集结合起来。这两个数据集都由肺炎患者的后前胸图像组成。随着更多案例的发布,COVID19 数据集每天都在更新,因此我们访问了 2020 年 3 月 18 日可用的实例。我们的数据集分为 4 个不同的类别,每类 9 张图像用作测试集。

  • 健康:79 张图片
  • 肺炎(病毒性):79 张图片
  • 肺炎(细菌性):79 张图片
  • 肺炎(新冠肺炎):69 张图片

让我们看一些例子来强调不同原因之间的细微差别。特别是,如果没有广泛的放射培训 ,病毒性病例和新冠肺炎病例之间的差异是无法区分的 ,这加剧了一线医护人员面临的困难

入院病人的胸透。从左至右:健康、细菌、病毒、COVID19。

我们的代码是用 Keras 和 Tensorflow 编写的,并在一个支持 GPU 的 Google 协同实验室笔记本实例中运行。所有代码都可以在 GradientCrescent 库上获得。

二进制案件

让我们从二元案例开始——比较健康的肺和那些表现出由 SARS-COV-2 病毒引起的肺炎的肺。这在covid 19 _ GradientCrescent _ Binary笔记本中有所涉及。

首先,让我们从 GradientCrescent Google Drive 导入数据集。

!gdown [https://drive.google.com/uc?id=1coM7x3378f-Ou2l6Pg2wldaOI7Dntu1a](https://drive.google.com/uc?id=1coM7x3378f-Ou2l6Pg2wldaOI7Dntu1a)!unzip Covid_Data_GradientCrescent.zip

接下来,我们将导入一些必要的库,并定义数据集路径和网络的一些参数。因为我们是迁移学习,我们将保持我们的学习率在 5e-4 的低值。

import numpy as npimport tensorflow as tfDATASET_PATH = ‘/content/two/train’test_dir = ‘/content/two/test’IMAGE_SIZE = (150, 150)NUM_CLASSES = len(data_list)BATCH_SIZE = 10 # try reducing batch size or freeze more layers if your GPU runs out of memoryNUM_EPOCHS = 20LEARNING_RATE =0.0005 

接下来,让我们使用 ImageDataGenerator 类来设置相应的训练和验证预处理以及批处理图像准备函数,对于这种情况,将我们的 class_mode 参数指定为“binary”。

#Train datagen here is a preprocessor
train_datagen = ImageDataGenerator(rescale=1./255,
 rotation_range=50,
 featurewise_center = True,
 featurewise_std_normalization = True,
 width_shift_range=0.2,
 height_shift_range=0.2,
 shear_range=0.25,
 zoom_range=0.1,
 zca_whitening = True,
 channel_shift_range = 20,
 horizontal_flip = True ,
 vertical_flip = True ,
 validation_split = 0.2,
 fill_mode=’constant’)train_batches = train_datagen.flow_from_directory(DATASET_PATH,
 target_size=IMAGE_SIZE,
 shuffle=True,
 batch_size=BATCH_SIZE,
 subset = “training”,
 seed=42,
 class_mode=”binary”,

 )valid_batches = train_datagen.flow_from_directory(DATASET_PATH,
 target_size=IMAGE_SIZE,
 shuffle=True,
 batch_size=BATCH_SIZE,
 subset = “validation”,
 seed=42,
 class_mode=”binary”,

 )

完成所有这些后,让我们来定义我们的网络,它在我们的两台笔记本电脑之间共享。我们采用预训练的 VGG16 网络,并将其与我们自己的一系列密集连接的层相适应,我们的输出层具有针对二进制分类情况的 sigmoid 激活函数。我们将编译我们的网络,并将 ADAM 优化器附加到它上面。

from keras import models
from keras import layers
from keras.applications import VGG16
from keras import optimizers
from keras.layers.core import Flatten, Dense, Dropout, Lambdaconv_base = VGG16(weights=’imagenet’,
 include_top=False,
 input_shape=(150, 150, 3))conv_base.trainable = Falsemodel = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation=’relu’))
model.add(layers.Dense(1, activation=’sigmoid’))model.compile(loss=’binary_crossentropy’,

 optimizer=optimizers.Adam(lr=LEARNING_RATE),
 metrics=[‘acc’])

定义好我们的网络后,让我们开始 20 个纪元的训练。

STEP_SIZE_TRAIN=train_batches.n//train_batches.batch_size
STEP_SIZE_VALID=valid_batches.n//valid_batches.batch_sizeresult=model.fit_generator(train_batches,
 steps_per_epoch =STEP_SIZE_TRAIN,
 validation_data = valid_batches,
 validation_steps = STEP_SIZE_VALID,
 epochs= NUM_EPOCHS,
 )

您应该会发现,我们的验证准确性收敛速度相对较快,超过了 80%。有了更大的数据集,我们将能够提供更多的验证示例来减少不同时期之间的差异,但结果对于演示目的来说是令人满意的。

二进制情况的最后 3 个时期的精度和损失。

最后,我们将使用 matplotlib 库来绘制我们的精度和损失参数,作为我们训练时期的一个因素。

import matplotlib.pyplot as pltdef plot_acc_loss(result, epochs):
 acc = result.history[‘acc’]
 loss = result.history[‘loss’]
 val_acc = result.history[‘val_acc’]
 val_loss = result.history[‘val_loss’]
 plt.figure(figsize=(15, 5))
 plt.subplot(121)
 plt.plot(range(1,epochs), acc[1:], label=’Train_acc’)
 plt.plot(range(1,epochs), val_acc[1:], label=’Test_acc’)
 plt.title(‘Accuracy over ‘ + str(epochs) + ‘ Epochs’, size=15)
 plt.legend()
 plt.grid(True)
 plt.subplot(122)
 plt.plot(range(1,epochs), loss[1:], label=’Train_loss’)
 plt.plot(range(1,epochs), val_loss[1:], label=’Test_loss’)
 plt.title(‘Loss over ‘ + str(epochs) + ‘ Epochs’, size=15)
 plt.legend()
 plt.grid(True)
 plt.show()

plot_acc_loss(result, 20)

对于二进制情况,取 20 个时期的精度和损耗参数。

为了确认我们的结果,我们将在测试数据集上测试我们的模型,每个类包含 9 个图像。请注意,您需要将随机播放参数设置为以获得准确的结果。

test_datagen = ImageDataGenerator(rescale=1\. / 255)eval_generator = test_datagen.flow_from_directory(
 test_dir,target_size=IMAGE_SIZE,
 batch_size=1,
 shuffle=False,
 seed=42,

 class_mode=”binary”)
eval_generator.reset()x = model.evaluate_generator(eval_generator,
 steps = np.ceil(len(eval_generator) / BATCH_SIZE),
 use_multiprocessing = False,
 verbose = 1,
 workers=1
 )print(‘Test loss:’ , x[0])
print(‘Test accuracy:’,x[1])

虽然看起来我们的模型在这个任务中表现得很完美,但是考虑到一个大得多的测试数据集,我们希望这个值与我们的验证精度相匹配。最后,让我们使用 cv2 图像处理类和 Keras 的 predict_generator() 方法绘制一些测试图像以及它们各自的预测。注意,要复制这一点,您需要将 evaluation_generator 的 shuffle 参数设置为 False ,以避免类索引混乱。

eval_generator.reset() 
pred = model.predict_generator(eval_generator,1000,verbose=1)
print(“Predictions finished”)import cv2import matplotlib.image as mpimg
for index, probability in enumerate(pred):
 image_path = test_dir + “/” +eval_generator.filenames[index]
 image = mpimg.imread(image_path)
 #BGR TO RGB conversion using CV2
 image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)pixels = np.array(image)
 plt.imshow(pixels)

 print(eval_generator.filenames[index])
 if probability > 0.5:
 plt.title(“%.2f” % (probability[0]*100) + “% Normal”)
 else:
 plt.title(“%.2f” % ((1-probability[0])*100) + “% COVID19 Pneumonia”)
 plt.show()

COVID19(左)和健康(右)测试集图像的预测概率。

我们的网络成功地发现了两个案例之间的差异。但这是肤浅的,让我们把赌注提高一个档次,试着区分不同类型的肺炎。我们将切换到第二本 Jupyter 笔记本,covid 19 _ GradientCrescent _ multi . ipynb .

多级案件

在这种情况下,我们不仅试图将健康的肺与感染肺炎的肺分开,还试图区分肺炎的不同原因,无论它们是由细菌、新型冠状病毒病毒还是其他病毒引起的。

我们的大部分代码与二进制代码是相同的。为了避免重复,我们来强调一下主要区别:

  • 我们的 ImageDataGenerator 类中的 class_mode 参数被设置为“分类”。
  • 现在,我们最终密集连接层中的神经元数量对应于所考虑的类的数量,并附带了一个 softmax 激活函数。这将允许我们给出每个类别的概率输出,并取最大值作为我们的最终预测输出。
  • 该模型现在用分类 _ 交叉熵损失函数编译。
  • 训练时期的数量增加,以适应增加的情况复杂性。同样的,学习率也降到了 1E-4。

让我们在考虑三个类别(健康、新冠肺炎、细菌)时,在以 5E-4 的学习速率训练 100 个时代之后,查看训练结果。

三级情况下,100 个时期内的精度和损耗参数。

虽然我们的模型的性能到目前为止是令人满意的,达到 80%以上,但让我们来看看合并了其他病毒性肺炎原因的四级情况。

四级情况下,100 个时期内的精度和损耗参数。

正如可以观察到的,三级病毒性肺炎类别的引入使准确性显著下降到 60%以上。这是可以理解的,因为新冠肺炎本身是由 SARS-COV-2 病毒引起的,因此我们可以预期这两个类别之间的特征域有很大的重叠。随着更细观的模型、更高的数据可用性和更长的微调过程,我们预计精确度会提高。

我们的结果增加了单独使用 CT/X 射线诊断 COVD-19 的难度,并有助于部分解释为什么中国卫生当局放弃了这种方法,转而使用基于 PCR 的测试:由于所有其他冬季病菌都在传播,确定个别病例中肺炎的原因变得非常困难。甚至可能有几种并行的肺炎原因,进一步使临床诊断复杂化。

我们希望你喜欢这篇文章,并希望你查看 GradientCrescent 上的许多其他文章,涵盖人工智能的应用和理论方面。要了解关于 GradientCrescent 的最新更新,请考虑关注该出版物并关注我们的 Github 资源库。

记得保持安全,洗手,并互相照顾。正如古代诗人长谷所言——“虽然我们生活在不同的地方,但我们共享一片天空”。

通过废水监测检测新冠肺炎疫情

原文:https://towardsdatascience.com/detecting-covid-19-outbreaks-through-wastewater-monitoring-f97bace1eb57?source=collection_archive---------40-----------------------

通过废水监测检测新冠肺炎疫情

来源:作者

试图监控新冠肺炎疫情的政府通常不得不做出艰难的权衡。

大规模测试人口中的个体成员既昂贵又困难:有限的实验室设备和医疗设施使得测试整个国家的人口几乎是不可能的。一个更便宜且逻辑上更简单的策略是分析污水。因为可以在人类排泄物中检测到新冠肺炎病毒和其他病毒,所以废水处理厂提供了综合信息。

目前,与单独测试相比,废水监测在 T2 更慢,在 T4 更不准确:需要更长的时间才能得到结果,而且更难确定爆发的确切地点。

但是,我们几乎已经掌握了让废水监测更快、更准确所需的所有知识。我们可以通过以下方式更有效地检测和应对新冠肺炎(和其他病毒)疫情:

  • 驱动一套开放标准
  • 开发小型化设备;和
  • 创建互操作数据*台

我们最*概述了一个由五部分组成的解决方案,该方案可以扩展到在整个大陆甚至全球范围内监测新冠肺炎。因为我们相信许多人、国家和组织可以从这些建议中受益,所以这里有一个我们发现的潜力的总结。

废水监测的工作原理

世界各地的污水处理系统都是类似的。水从单个的房子被倒入一个更大的集中管道系统。然后污水流向中央水处理厂。

病毒通常可以在受感染者的粪便中检测到。这就是为什么查看在特定水处理厂检测到的病毒浓度可以让我们估计该厂服务区域内的感染人数。

但是废水可能需要几天或几周的时间才能到达一个集中处理厂,因为在这个过程中经常有中间的清洁步骤。因此,监测工厂的废水通常意味着,虽然我们知道爆发发生了,我们知道它有多大,但我们不知道它发生在集水区的确切时间或地点(专家称之为空间分辨率和时间分辨率)。

因此,废水监测作为检测病毒爆发的潜在解决方案经常被忽视。

这将需要大规模的协调努力,以改善目前的技术和废水监测过程。但是考虑到确定新病毒爆发的价值,并与扩大个体测试所需的成本和努力相比,很明显这项工作需要完成。

我们改进废水监测的五部分解决方案

我们的五部分解决方案包括:1)监控指导,2)参考样本,3)小型化设备,4)可互操作的数据*台,以及 5)机器学习分析。来源:作者

我们提议的改善和扩展废水监控的五部分解决方案包括:

  1. 关于如何设置监测设备和取样的标准化指南:所有各方都需要同意这套标准,因为为了获得可比较的数据,每个人都必须以相同的方式进行。
  2. 用于制备样品和量化病毒的参考方法:即使有关于设置监测设备的标准指南,每个人还需要就如何在实验室制备样品以及如何测量废水中特定病毒的浓度达成一致。
  3. 小型化仪器在更靠*源头的地方测量废水:我们需要制造小型的某些监测设备。
  4. 跨部门和国家共享数据的互操作数据*台:这些都需要开发。
  5. 机器学习预测分析:这将使我们能够尽早发现新病毒或已知病毒的新爆发,以协调适当的应对措施。

其中一些组件已经存在或正在开发中。我们详细查看这五项建议中的每一项,以显示我们所处的和我们可能达到的(在 3-24 个月的时间内)。

解决方案 1:监控指南

为处理厂制定一套关于如何提取样本和优化监测流程的指南,将有助于确保所有后续步骤中的数据一致。

我们在哪里:

  • 我们已经使用废水监测来回顾性地分析和描述疫情。不同城市的做法略有不同,很多步骤都是手动完成的。比如污水采样有两种不同的方法:
    抓样:在单个时间点取单个样本;
    复合取样:在 24 小时内收集和组合样本。
  • 目前的工艺通常需要在每个处理厂现场训练有素的专家。
  • 可能需要数周才能得到有用的结果,而且不同工厂或国家之间的数据并不总是可比的。

我们可能在哪里:

  • 随着监测设备和过程的改进,我们可以主动分析废水来预测即将到来的疾病爆发。
  • 通过自动化尽可能多的步骤,标准化设备和协议,并确保工厂和国家之间的一致性,我们可以降低成本并提高监测质量。

解决方案 2:制备样品和定量病毒的参考方法

为实验室创建参考样品和方案将确保样品制备和浓度测量的一致性。

我们在哪里:

  • 我们知道我们可以在废水中检测病毒,包括 SARS 和新型冠状病毒病毒,但有几种方法可以测量样本和量化病毒浓度。
  • “正常”是什么并不总是很清楚。
  • 样品可能以不同的方式制备,这可能会影响结果,并使不同实验室之间的数据比较变得困难。

我们可能在哪里:

  • 通过创建用于制备样品和量化病毒的标准化方案,以及就一组参考样品达成一致,不同国家的不同实验室可以共享和比较数据。这种标准化将使更快更灵敏的分析成为可能——这两个因素都很重要,尤其是对早期预警系统而言。

解决方案 3:收集和标准化粪便样本的小型化仪器

制造适用于大型污水处理厂的小型监测设备,将有助于我们更准确、更经济地查明疫情。

我们在哪里:

  • 废水处理厂测量整个集水区的*均信息。由于一些设备是为大型处理厂设计的,因此在更精细的层面上复制这种取样过程存在后勤方面的挑战。
  • 这意味着特定集水区的较小部分中的爆发可能被较大区域的*均值“抹*”,从而难以检测到爆发。

我们可能在哪里:

  • 开发小型化的取样设备将使我们能够进行更详细的测量。
  • 更详细的测量可以告诉我们疾病爆发的确切位置——精确到一个街区,甚至一座特定的建筑。
  • 通过不等待废水到达一个集中的工厂,我们也可以更快地获得这些测量值,给我们更好的空间和时间分辨率——也就是说,允许我们采取行动来遏制甚至防止疾病爆发。

解决方案 4:开发一个可互操作的*台来整合环境和健康数据

跨部门、跨角色和跨城市使用的单一数据*台将让所有人都在同一页面上。

我们在哪里:

  • 许多部门和国家已经在更广泛地共享他们的数据。这允许其他国家和部门之间的一些合作,甚至让公众成员直接获得信息。
  • 卫生部门和水管理部门并不总是有效合作,有时很难利用废水管理的见解来推动与健康相关的决策。
  • 各国共享数据仍然很困难。

我们可能在哪里:

  • 建立一个可互操作的数据*台来处理和组合来自水管理部门(如病毒浓度激增)和卫生部门(如感染率和住院率)的指标,将有助于我们做出更有效的决策。
  • 通过鼓励多个城市采用相同的*台,我们可以很容易地看到从“鸟瞰”到特定邮政编码爆发的一切。
  • 研究人员、工程师、政治家和决策者都可以从一个可靠的、集中的“真理来源”获得数据。

解决方案 5:预测分析

我们可以使用机器学习来自动预测何时何地爆发。

我们在哪里:

  • 废水监测目前太慢,无法用于预警系统。
  • 即使实现了上述所有解决方案,仍然需要时间来收集和分析我们需要的样本和数据。
  • 我们目前主要使用这些数据进行回顾分析。

我们可能在哪里:

  • 通过使用先进的机器学习,我们可以在废水中发现指示疾病爆发的新模式——甚至在患者首次报告症状之前。
  • 我们可以使用机器学习来纠正使我们的测量产生偏差的因素,例如一天中的时间、一周中的哪一天,甚至是天气,所有这些因素都会影响任何给定时间集水区内的人数。
  • 宏基因组分析也将帮助我们检测新病毒。我们可以监测以前在废水中没有检测到的新病毒 DNA,并将其与已知病毒进行映射,以识别新突变的潜在危险爆发。

有前途的废水监测项目实例

你想把这项技术带到你的城市吗?

如果您参与水资源管理或病毒爆发监测,并希望讨论将这项技术引入您的城市,我们很乐意与您交谈。如果你是一名居民,你的城市采用这种技术会使你受益,请与你的代表分享这篇文章。

如果您想讨论使用机器学习进行健康监测,请与我们的首席执行官预约通话。

使用深度学习检测新冠肺炎

原文:https://towardsdatascience.com/detecting-covid-19-using-deep-learning-262956b6f981?source=collection_archive---------13-----------------------

一个实用的方法来帮助医生帮助我们对抗新冠肺炎

“冠状病毒病 2019 ( 新冠肺炎)是由严重急性呼吸综合征冠状病毒 2”引起的高度传染性疾病。

“这种疾病于 2019 年 12 月首次起源于中国武汉,自那以来,它已经在全球范围内传播,影响了超过 200 个国家。影响如此之大,以至于 世界卫生组织(世卫组织) 已经宣布新冠肺炎正在发生的疫情为国际关注的突发公共卫生事件。”

截至 4 月 29 日,全世界 200 多个国家共有 31,30,191 例病例,2,17,674 例死亡。(来源:必应新冠肺炎追踪器)。

因此,在这个特定的场景中,需要做的一件主要事情是手动测试,并且大多数国家已经开始做这件事情,以便能够了解真实情况并做出适当的决定。

但是人工检测的缺点包括检测试剂盒的可获得性差,血液检测成本高且效率低;验血大约需要 5-6 个小时才能得出结果。

因此,我们的想法是利用深度学习技术来克服这些情况,以获得更好、更有效的治疗。由于这种疾病具有高度传染性,因此我们越早得出结果,城市中的病例就越少,这就是为什么我们可以使用卷积神经网络来完成我们的工作。

如果没有贴标签,你能区分两张 x 光片吗?我打赌你不能,但是 CNN 可以。

该问题是一个二元分类问题,其中我们对正常和新冠肺炎病例进行分类。

使用深度学习来解决这种情况有几个利弊:

  1. 优点:更节省时间;不太贵;易操作的
  2. 反对意见:实际上我们需要 100%的准确性,因为我们不能错误地识别患者,因为这可能导致疾病的进一步传播,这是非常不鼓励的。

但是,这个模型仍然可以返回良好的准确性,并可以进一步得到加强。

数据准备

机器学习需要大量的数据来训练;对于这种类型的问题,我们需要的数据是 COVID 受影响和健康患者的胸部 x 光片。

  1. 约瑟夫 博士最*开源了一个 数据库 包含患有新冠肺炎病患者的胸部 x 光照片。所使用的数据集是一个开源数据集,包括来自公开研究的新冠肺炎图像,以及不同肺炎致病疾病(如 SARS、链球菌和肺囊虫)的肺部图像。
  2. 我还使用了 Kaggle 的胸部 X 射线 竞赛数据集来提取健康患者的 X 射线,并对 100 幅图像进行了采样,以与新冠肺炎可用图像进行*衡。

所以,数据集由新冠肺炎 X 射线扫描图像组成。事实证明,最常用的视图是后前视图,我在分析中考虑了新冠肺炎 PA 视图 X 射线扫描。

为了对我们的数据进行分层,我们将获取相同数量的图像,并将它们混合,稍后将分为测试和训练数据。

模型部署

由于我们已经准备好了数据,这是这个项目中最繁琐的部分,让我们进入下一步,我们将创建一个深度学习模型,该模型将学习正常 X 射线和新冠肺炎影响 X 射线之间的差异。

我假设你们都知道 CNN 架构的基础知识,如果没有,我强烈推荐你们关注:-CNN 基础知识

模型架构

我倾向于有3 个隐藏层,** 你可以试验更多或更少的层,这取决于你。我将模仿增加神经元的传统路线,因为我们越深入层内,学习的特征就越多。**

我将有 (224,224,3) 个输入神经元,我们正在将数据调整为具有 3 个通道 的 224224,因为它被认为是理想的大小。*

最后,我将展*我们的特征,并将使用 sigmoid 作为激活函数,因为我们有二进制分类问题,因此我们的输出将只包含一个单元格, adam 作为优化器配合得非常好,因此除了 交叉二进制熵之外,还使用它们来编译模型。

因素

你可能想知道为什么我不直接部署 VGG16 或任何预定义的模型,但为此,你必须知道 VGG16 的架构,它包含大约1.4 亿个参数*** ,另一方面,我们的模型包含大约570 万个参数 ,所以使用定制的模型比在迁移学习上训练几个小时更好,更优化,特别是对于这样的小数据集。***

培训用数据

因为我们已经定义了我们的模型,我们剩下的下一个任务是在定义的模型上训练我们的数据。

我试着在不进行剪切、缩放和水*移动的情况下训练数据,所以我得到的准确率约为 50%,对于像这样的实时项目来说,这是相当低的。

由于数据没有成型,接收信号较少,因此准确性较低

因此,为了更好地接收特征,最好对数据进行建模,因此,我们对训练数据执行剪切、缩放和水*旋转。

一旦图像被增强,我们可以在输入形状中对它们进行整形,即224 * 224,批量大小为 32 的 ,并且可以训练我们的训练集。**

准备培训数据

在我的训练过程中,我用 10 个周期,每个周期 8 步 ,再次自由试验超参数,也许会产生更好的结果。

训练模型

总结模型

此外,我们可以绘制损耗和精度图,以便更好地理解所需的超参数。

定义的超参数产生 96.4%的准确性,这并不坏,但仍可以提高,因为如果我们在真实场景中部署一个准确率约为 96.4%的模型,错误识别的患者仍可能传播疾病,我们的高效方法目标将无法实现。

同样,如果你想节省训练的时间,你可以从我的 Github 库 下载训练好的模型。

混淆矩阵

为了以更容易理解的方式可视化结果,我们将实现一个混淆矩阵。

混淆矩阵的原型如下

我们得到的混淆矩阵如下

********

解码混淆矩阵,在 30 名 COVID 受影响的患者中,我们得到了 30 人我们得到了 0 名被错误分类的患者,在 2 名 8 名正常患者中,我们得到了 28 名患者被正确分类, 2 名被错误分类。

我们得到的结果是好的,但仍然可以提高精度,以实现我们的意图。

如果你喜欢这篇文章,请考虑订阅我的简讯: 达克什·特雷汉每周简讯

源代码

完整的源代码以及数据集和训练好的模型可以在我的 Github 存储库中找到:- 新冠肺炎检测

结论

因此,作为总结,我想再次思考这样一个事实,即分析是在有限的数据集上进行的,结果是探索性的,不能从中推断出任何结论性的东西。该方法尚未经过医学验证。

我计划改进这个模型,用更多的 X 射线扫描来增加我的模型的韧性,这样这个模型就可以推广了。此外,我鼓励读者对模型进行实验,以使其更加精确。

一如既往,非常感谢你的阅读,如果你觉得这篇文章有用,请分享!

待在家里,注意安全!

请随意连接:

在 www.dakshtrehan.com 和我一起

**LinkedIN ~https://www.linkedin.com/in/dakshtrehan/

**Instagram ~https://www.instagram.com/daksh_trehan/

**Github ~https://github.com/dakshtrehan

阅读我的其他文章:-

逻辑回归解释

线性回归解释

确定最适合您的 ML 模型

将机器学习技术与现实生活联系起来

为新手提供数据科学服务

关注更多机器学习/深度学习博客。

**中等~https://medium.com/@dakshtrehan

干杯。

封面模板和混淆矩阵模板是我在www.canva.com 上做的。x 射线图像是 github 和 kaggle 上可用的开源数据集的一部分。其余图片来自我的 Jupyter 笔记本。如果您想获得使用许可,请联系我。

另外,我还要感谢 Prateek bhaiyaa 和编码模块,他们通过他们的数据科学会议帮助我更好地理解了这些模型。

以 97%的准确率检测新冠肺炎:小心人工智能炒作!

原文:https://towardsdatascience.com/detecting-covid-19-with-97-accuracy-beware-of-the-ai-hype-9074248af3e1?source=collection_archive---------14-----------------------

当病毒式营销走得太远时

疾控中心Unsplash 拍摄的照片

一名 n 澳大利亚人工智能博士生最*在 LinkedIn 上发了一篇帖子关于他对新型冠状病毒的研究。这个帖子收集了成千上万的观点、赞和分享。

AI 很棒

他建立了一个深度学习模型,能够从胸片中预测病人是否感染新冠肺炎病毒,准确率为 97.5%。

目前,该项目的特点是:

  • 受过训练的 PyTorch 模型
  • 集装箱化应用代码
  • 翻译成 8 种语言的 GitHub
  • 开发中的 web 应用程序
  • 开发中的移动应用程序
  • AWS 中用于托管模型的无服务器架构的蓝图
  • 在营销和赞助方面付出了很多努力

上面的一切都是在大约一周内建成的。

医疗诊断中的深度学习

深度卷积网络对于疾病诊断和治疗具有潜在的益处。*年来出现了许多科学出版物[1],下面是其中的一些:

  • 2016 年,一组伦敦研究人员发表了一种诊断糖尿病视网膜病变的方法,准确率为 86%,在 8 万张眼底照片的数据集上进行训练2
  • 同年,乌干达研究人员使用 10,000 个对象的数据集评估了 CNN 在显微血涂片上的性能[3]。
  • 两名日本研究人员在 550,000 个 CT 扫描数据集上领导了一项对肺结节进行分类的工作[4]。

但在这里,快速浏览一下 GitHub 知识库,往好了说,描绘了对深度学习和人工智能的严重缺乏理解,往坏了说,描绘了在利用疫情的同时进行自我宣传的恶意尝试。原因如下。

糟糕的工程

这个解决方案有几个问题,其中大部分在下面的 Reddit 线程中被揭穿。

首先,这些网络的潜在神经表示非常复杂,因此它们需要大量的训练样本,如前述研究中所述。

但截至目前,新冠肺炎探测器是在… 50 张图像 的数据集上训练的!

图 1:模型从胸部 x 光片中学习。来自 NIH 胸部 x 光数据集的图像

对于一个拥有超过 150 层和超过 2000 万个参数的网络来说,这完全是荒谬的。

此外,还存在巨大的数据偏差。这 50 张图片并不是根据一个人是否携带病毒来标记的,而是根据新冠肺炎急性病例的肺部损伤来标记的。除非你的肺已经被病毒破坏了,否则这个模型无法检测到感染。在一个人出现肺炎症状的情况下,如果这些症状不是急性的,则该模型的准确性未经证实。

最后,COVID 模型基于一个流行的基线网络 ResNet-50[5]。虽然这是图像识别和分类的常用方法,但 ResNet 是使用日常物体的照片进行预训练的。因此,其隐藏层的内部表现被几何形状和彩色图案激活(2)。

图 ResNet 特征的可视化[6]

这种模式在 x 光照片中是找不到的。这就是为什么大多数医学神经网络都是从零开始制作的。

当我们仔细查看代码库时,会出现许多其他问题。训练、验证和测试数据集包含重复图像;大部分的训练过程都是从 PyTorch 教程中截取的,用不必要的代码混淆;Github 的问题是荒谬的…

很明显,那篇文章注定会有成千上万的赞、分享和观点,不管标题背后的内容是什么。

宣传作为商业竞争的一种手段,给发明者带来了机会,也极大地刺激了科学家的研究。

爱德华·伯奈斯

尼日利亚王子的蛇油

然而,作者在面对事实时并不绝望,经常提出以下答案:

你好 xxx ,在加拿大一家研究机构放射学家的支持下,我们已经策划了 5000 例

我不知道这个大胆的答案中的部分真理,但如果这样的模型被用于医学应用,它可能是非常危险的。

作者甚至创建了一个拥有多个渠道的 Slack group 。不用说,它引起了很多人的兴趣。

#数据科学家频道没有太多严肃的内容,被满怀希望但经验不足的热情新人打断。同样,在#医生频道中唯一的有形内容来自解决医疗问题的专业人士,例如,胸部 x 光检查不是新冠肺炎诊断的推荐方法。最后,#研究人员频道几乎空无一人。

另一方面,UI/UX 频道正在生成大量内容。该倡议现在有 5 个不同的标志和一个手机和网络界面的模型。

甚至还有一个#营销频道来寻找加强沟通和筹集资金的方法,还有一个#赞助商频道,潜在投资者询问投资回报的未来前景。

自己看

当心炒作

深度学习不是银弹解决方案。许多没有做好准备的公司试图将其内部化为数据团队,当他们看到成本上升而很少或根本没有投入生产时,他们变得疯狂了。

尽管如此,如今人工智能的进步是开创性的。完全忽视它们的人是疯狂的。

这并不意味着直接跳入池中,在水中扑腾着呼吸空气。因此,拥有 AI / ML、数据操作、架构、开发和许多其他主题的横向技能的坚如磐石的团队非常重要。

安托万冠军,2020 年 3 月 23 日

参考

[1]医学图像处理的深度学习:概述、挑战和未来,Muhammad Imran Razzak,Saeeda Naz,Ahmad Zaib,2017。

2哈里·普拉特、弗兰斯·科恩、黛博拉·M·布罗德本特、西蒙·P·哈丁和郑亚林。糖尿病视网膜病变的卷积神经网络,2016 年。

[3]John A . Quinn、Rose Nakasi、Pius KB Mugagga、Patrick Byanyima、William Lubega 和 Alfred Andama。基于显微镜的护理点诊断的深度卷积神经网络,2016 年。

[4]坂本雅治和中野博树。具有选择性分类器的级联神经网络及其使用肺部 x 射线 ct 图像的评估,2016。

[5]深度残差学习在图像识别中的应用,何,孙,2015 .

[6],戴伦·杨,拉维·塔迪纳达。可视化剩余网络,2017。

用 Python 中的自动编码器检测信用卡欺诈

原文:https://towardsdatascience.com/detecting-credit-card-fraud-with-autoencoders-in-python-98391cace8a3?source=collection_archive---------25-----------------------

使用 Tensorflow 和 Keras 的两种方法

粘土银行Unsplash 拍摄的照片

在本文中,我们将演示两种不同的使用自动编码器的方法。特别是,我们将尝试使用自动编码器将信用卡交易分为欺诈性和非欺诈性。我们将要使用的数据集是“信用卡欺诈检测”数据集,可以在 Kaggle 中找到。完整代码可在 GitHub 上获得。其中有一个在 Colab 中打开和执行代码的链接,所以请随意尝试。代码是用 Python 写的,用了 Tensorflow 和 Keras。

该数据集包含欧洲持卡人的 284,807 笔信用卡交易。出于安全原因,数据集的原始特征不可用。可用的是 28 个特征,它们是原始特征的 PCA 的结果。还有,每笔交易的金额和“时间”一栏。最后一个函数计算每个事务和集合中第一个事务之间的秒数。最后,每个交易的类型在“类”列中。欺诈交易用 1 表示,非欺诈交易用 0 表示。该数据集高度不*衡,非欺诈交易占总数的 99.8%。因此,我们的分类问题也可以被视为异常值检测问题,欺诈性交易被视为异常值。

284,807 笔交易中只有 492 笔是欺诈

对于我们的例子,我们将忽略“时间”列。训练和测试数据集中的标准分割方法将用于评估每种方法。因为一个类的情况太少,我们将把数据集分成两半,而不是通常的 70%-30%。

如开始所述,我们将使用自动编码器来完成分类任务。根据维基百科:

自动编码器是一种人工神经网络,用于以无监督的方式学习有效的数据编码。

简而言之,自动编码器是一个神经网络,它被训练来重新创建作为输入的任何内容。在输入层和输出层之间有一堆隐藏层。在正中间有一层,包含的神经元比输入少。这一层的输出是自动编码器的所谓编码器部分的结果。

一个自动编码器的表示(作者:切尔文斯基来源:维基百科

使用自动编码器的理由是,隐藏层将以一种良好的方式将输入映射到向量空间(无论“良好”可能意味着什么)。通过使用具有很少神经元的层的结果,我们将我们的输入从高维空间映射到更低维的空间。

第一种方法:使用重建误差

我们的第一个方法是创建一个自动编码器,只在非欺诈交易上训练它。合乎逻辑的是,预期欺诈情况下该自动编码器的重构误差将高于非欺诈情况下的重构误差。我在 Venelin Valkok 的优秀媒体文章中读到过这种技术。我建议你学习它,因为在它里面,这个方法以一种非常详细和容易理解的方式被解释。

[## 使用 Keras 中的自动编码器检测信用卡欺诈——面向黑客的 TensorFlow(第七部分)

信用卡交易中的异常检测是如何工作的?

medium.com](https://medium.com/@curiousily/credit-card-fraud-detection-using-autoencoders-in-keras-tensorflow-for-hackers-part-vii-20e0c85301bd)

出于演示的原因,我们将创建一个简单的由三层组成的自动编码器。输入层、一个隐藏层和输出层。隐藏层将有 12 个神经元。

第一种方法中使用的简单自动编码器的表示

如前所述,网络仅使用训练集的非欺诈案例进行训练。在 100 个时期之后,我们获得了一个网络,我们用所有的训练集案例来喂养这个网络。然后,我们可以计算输入和输出之间的误差(重建误差)。结果如下表所示。

+----------------+--------------------+--------------------+
|     Class      | Mean Squared Error | Standard Deviation |
+----------------+--------------------+--------------------+
| Non-Fraudulent |      0.767519      |       3.439808     |
|    Fraudulent  |     29.855354      |      43.107802     |
+----------------+--------------------+--------------------+

基于这些结果,在测试数据集中,如果实例的重构误差大于*均值的标准偏差的三倍,即大于 0.767519+3*3.439808=11.078922,则我们将该实例描述为欺诈性实例。当然,阈值的选择是我们的模型的超参数,在实际应用中,它应该被微调。

我们可以看到,我们的模型在测试数据集的 243 个(46.5%)欺诈案例中检测到了 113 个。此外,142161 个非欺诈案件中有 771 个(0.5%)被归类为欺诈案件。

第一种方法的混淆矩阵

第二种方法:编码器和 k-NN

在我们的第二种方法中,我们将使用自动编码器的编码器部分。编码器将把实例映射到低维空间,并且 k-最*邻(k-NN)将用于分类。在这种方法中,欺诈性和非欺诈性交易都将用于训练编码器。可以说,编码器将用于降维,从而加速 k-NN 的执行。

我们将使用与第一种方法相同的模型。输入层和具有 12 个神经元的内部隐藏层将是编码器部分。

编码器由自动编码器的前两层组成

对于分类部分,所有实例(来自训练集和测试集)将通过编码器映射到 12 维空间。对于测试集中的每个实例,训练集的三个最接*的相邻案例将决定它是否是欺诈性的。

第二种方法从测试数据集的 243 个欺诈案例中检测出 184 个(75.7%)。此外,142161 个非欺诈案件中有 12 个(0.008%)被归类为欺诈案件。

第二种方法的混淆矩阵

结束语

我们很快看到了两种使用自动编码器进行分类的方法。欢迎您尝试使用 Colab 代码。可以尝试的事情有:

  • 在第一种方法中改变误差阈值
  • 向自动编码器添加更多层
  • 改变编码器最后一层的神经元数量

进一步阅读

侦查房地产投资犯罪

原文:https://towardsdatascience.com/detecting-criminal-investment-in-real-estate-5311d5a91ac8?source=collection_archive---------33-----------------------

将半监督机器学习应用于德克萨斯州贝克萨尔县的房产数据

蒂亚戈·罗德里格兹在 Unsplash 上的照片

背景

腐败的墨西哥政客和贩毒集团经常在美国,尤其是德克萨斯州的住宅房地产中洗钱。在美国,利用房地产清洗非法所得有几个好处:价格通常稳定,有可能升值,资产具有功能性。此外,全现金购买是一种有效的方式来避免获得抵押贷款所涉及的银行审查,有限责任公司可以为真正的买家提供匿名。因此,房地产为非法资金融入合法金融体系提供了一个简单而直接的途径。

由于目前 20%的房地产购买不涉及融资,这种通过住宅房地产进行的洗钱活动已成为美国财政部金融犯罪执法网络(FinCEN)的一个重要关注点。作为这一重点的一部分,FinCEN 于 2016 年 1 月开始发布地理目标指令。这些 GTO 在法律上要求产权保险公司报告符合特定标准的房地产交易。在县一级应用,它们主要覆盖门户城市,如迈阿密、纽约和洛杉矶。一个被 GTO 覆盖的县一直让我印象深刻,那就是德克萨斯州的贝克萨尔县,圣安东尼奥周围的那个县。

直到 1836 年,贝克萨尔县一直是墨西哥的一部分,至今仍与该国北部保持着密切的文化联系,周末通勤是家常便饭。根据 2016 年 7 月以来的一项 GTO,该县最*发生了几起墨西哥政客和白领罪犯在圣安东尼奥周围的房地产中藏匿不义之财的高调事件。⁴ ⁵作为一名前调查分析师,我经历过一些这样的案例,但还有很多比我最初意识到的更多。

因此,我使用了来自贝克萨尔县财产评估员和德克萨斯州的公开可用数据来建立一个能够检测该县住宅房地产犯罪投资的模型。[结果的 TLDR:我标记了一小部分数据,半监督方法将 F1 分数从 0.667 提高到 0.8]

数据

贝克萨尔县评估区提供(实体光盘!)以象征性的费用购买其年度评估数据。由于该县的一些洗钱事件发生在数年前,我获得了 2015 年至 2019 年四年的数据。每个都有超过 600,000 个属性的多个数据集,我使用的特定数据集包含 408 个特征,我在几次迭代中对其进行了精简。

为了设计关于财产所有权的潜在有用特性,我从德克萨斯州公共账户审计员那里获得了几个数据集,这需要直接接触他们的开放记录部分。

我选择了一个包含活跃企业纳税人的数据集和另一个提供这些公司官员和董事信息的数据集。我将这两者合并,创建了一个包含公司董事信息的数据集。

为了将公司数据与 Bexar 县的财产数据结合起来,在执行了一些基本的文本清理之后,我合并了一个完全匹配的名称。

特征工程

荷兰的一项研究在很大程度上启发了这个项目,该研究发现,识别荷兰引人注目的房产的三个最佳指标是外国所有权、所有者是一家刚刚成立的公司以及不寻常的价格波动。⁶因此,创造相似的特征是至关重要的。我能够通过从财产契约日期中减去公司执照日期来复制刚刚成立的公司。

根据荷兰的调查结果和我调查洗钱的经验,我做了几个不同的二元特征来表明财产的所有者是公司还是信托。例如,如果包括纳税人姓名,这是一个法人,而不是一个公司。或者,如果名称包含几个公司术语或后缀中的一个,那么它可能是一家公司。

为了*似一个不寻常的价格波动特征,我计算了每套房产从 2015 年开始的市值同比变化百分比。

我还为房产是否满足 Bexar County 的两个 GTO 标准创建了一个显式特性:房产价值大于 300,000 美元,所有者是一家公司。

标记一小部分数据

因为我获得的公共记录数据没有欺诈活动的标签,所以我创建了一个小的标签数据集来验证我的方法。虽然*年来在无监督机器学习方面取得了很多进展,但当标记一个小的子集是可行的时,半监督方法已经显示出巨大的前景。⁷因此,我必须为涉及刑事诉讼的财产创建积极的类别标签。通过使用当地报纸和法庭文件,我能够找到 59 处大致符合这些标准的房产。

圣安东尼奥的 1115 Links Cv 就是这些物业的一个例子,该物业由 Red Kaizen Investments LLC 所有。Red Kaizen Investments LLC 是墨西哥金融家 Rafael Olvera Amezcua 被指控经营虚假储蓄和贷款业务,诈骗储户超过 1.6 亿美元的法庭案件中被列为被告的数十家公司之一。⁸

在 GTO 覆盖的辖区内,有 1,082 笔交易符合高风险可疑活动报告(SARs ),占符合报告要求的所有交易的 17%。⁹ ⁰通过粗略计算,我预计这将转化为大约 700 处符合贝克萨尔县数据中这些标准的房产。必须注意的是,并非所有标记为犯罪的属性实际上都符合 GTO 要求,因此这不应被视为一个精确的指标。

尽管如此,我有一个非常强的积极的犯罪财产类别,但超过 600,000 个财产,虽然可能是非犯罪的,但没有标记。因此,存在着巨大的阶级不*衡和标签挑战。为了解决班级不*衡的问题,我依靠精确、回忆和混淆矩阵,而不是准确度。如果只有 0.1%的交易是欺诈性的,一种算法总是可以预测交易是非犯罪的,并且在 99.9%的时间里是正确的。精度和召回允许捕获假阳性(精度)和假阴性(召回)的比率。

作为标记未标记财产的相当大的子集的快速第一步,我将数据中最常见的 30 个财产所有者(即,拥有最多财产的 30 个所有者)所拥有的财产标记为非犯罪财产。我有信心将这些房产归为非犯罪类,因为房主是大型建筑公司以及州政府和市政府。然而,应该指出的是,这并不能产生一个真正有代表性的样本,因为它偏向于大业主。

在过滤掉异常属性并匹配我手动标记的犯罪属性后,我在数据集中有 5516 个非犯罪属性和 47 个具有强标签的犯罪属性。

数据伪标记

我的半监督欺诈检测方法的下一步是对我的大型未标记数据集的剩余部分的 15%进行伪标记。首先,我用手工标记的小数据子集上的表格数据训练了几个适合分类任务的基线模型:支持向量机、XGBoost、随机森林和梯度增强。梯度增强在测试数据上具有最强的性能,XGBoost 次之。

梯度提升使用一系列决策树来迭代上一个决策树的残差。这 100 个弱学习者集合起来形成一个强模型。通常,我发现梯度提升是一个很好的基础模型,因为它是一个性能更高的决策树,训练起来相对较快。此外,决策树是一种更容易解释的机器学习模型,这对于我确定哪些特征对欺诈分类最有帮助至关重要。

因此,我使用基于原始训练数据训练的超参数优化梯度推进模型来预测 86,708 个属性的标签。接下来,我将这个伪标记数据与标记数据相结合,并进行新的超参数搜索,现在我在这个更大的数据集上训练了一个新的梯度提升分类器。

结果

这个新模型在召回率、精确度和 F1 分数方面都优于基线模型。

我很高兴召回率如此之高,同时仍然保持较低的误报率。在这种情况下,当务之急是减少误报,但是误报越多,法规遵从性分析师需要做的手动工作就越多。

此外,该模型发现的对预测最重要的特征与荷兰的研究吻合得很好。

我的模型的最重要的特征是,房产由一家在房产购买日 365 天内成立的公司拥有。前面提到的荷兰研究与他们的第二强指标具有相同的特征。

我的模型依赖于多年来的年度价格差异作为最重要的特征之一。这大致反映了荷兰的研究如何将不寻常的价格波动作为其首要指标。⁴

拥有多处房产的业主符合我在资产追踪方面的经验,也符合荷兰研究的第二层指标之一。

结论

我的方法验证了检测犯罪投资的伪标记方法,表明一小部分标记数据可以用来对抗现有技术。这进一步证实了这种方法在新应用中的可行性,并提出了在这种应用中的可行途径,在这种应用中,访问完全标记的数据集是禁止的。以下是一些有趣的后续内容:

  • 使用主动学习来找出哪些额外的数据点需要标记。
  • 根据地理定位命令在其他县采用这种方法。
  • 合并更多数据集(如邻域数据)以构建更多要素。

感谢 妮娜·洛帕蒂娜 ,感谢所有在这方面的帮助。如果你对 NER 感兴趣,一定要看看她做的所有很酷的工作。

这个项目的资源库可以在 这里找到

[1]https://home . treasury . gov/system/files/136/National-Strategy-to-Counter-Illicit-finance v2 . pdf,第 18 页。

[2]https://www . fin cen . gov/sites/default/files/shared/Real _ Estate _ GTO-mia . pdf

[3]标准是:购买为全现金,购买者为公司,购买价格为 30 万美元或以上(根据最新 GTO)。

[4]https://www . express news . com/news/local/article/Coahuila-corruption-and-drug-ties-spread-5665058 . PHP #/0

[5]https://translate.google.com/translate?hl=en&sl = es&u = https://www . elfinanciero . com . MX/opinion/raymundo-Riva-Palacio/El-imperio-de-los-Medina&prev = search

[6]https://www . politieacademie . nl/kennisonderzoek/kennis/media theek/PDF/86218 . PDF

https://arxiv.org/abs/1805.03620

[8]https://www . document cloud . org/documents/6248702-Agreed-Final-judgment . html

[9]风险较高的可疑交易报告由金融机构提交给 FinCEN,fin cen 随后对交易进行调查。财政部上下文中的高风险 sar 是指那些由于涉及高风险外国管辖区、毒品洗钱和跨国犯罪的活动而提交的 sar。

[10]https://home . treasury . gov/system/files/136/National-Strategy-to-Counter-Illicit-finance v2 . pdf,第 18 页。

[11]我的数据集中有 21,131 处房产符合价格和公司所有的 GTO 要求。全国*均有 20%的房产是在没有贷款的情况下购买的,有 4226 处房产符合这三个标准;其中的 17%是 718。

[12]我为此遵循的实现是:https://datawhatnow . com/pseudo-labeling-semi-supervised-learning/

[13]https://www . police academy . cn/知识调查/媒体中心/PDF/86218.pdf】第 231 页。

[14]https://www . police academy . cn/知识调查/知识/媒体中心/pdf/86218.pdf第 231 页。

检测链表中的循环

原文:https://towardsdatascience.com/detecting-cycles-in-linked-lists-an-analogy-559c3639ef43?source=collection_archive---------51-----------------------

用类比理解龟兔算法

(图片由作者提供)用野兔和乌龟探测周期

当我们开始用算法思考时,链表是我们首先遇到的一些数据结构。在这个主题上经常遇到的问题是检测链表中的循环。

在这篇文章中,让我们来解决这个问题。但是在那之前...

什么是链表?

想象一个狭窄的隧道。隧道里的每一个点都指向前方的一个点。你知道这个隧道的入口。一旦踏入隧道,里面完全是漆黑一片,其他什么都看不到。但是还是有希望的。如果你在 X 点,那么你前面的 Y 点会出现一道光,所以你现在可以移动到 Y 点。

(图片由作者提供)正前方的聚光灯亮起

灯在你前面的台阶上一直亮着,当你一到达那里就消失了。所以你只能一步一步地前进(不知道后面是什么,也不知道前面还有什么)

如果隧道到了尽头,你就能看到前方的阳光。所以一旦你踏上“最后一步”,你就会知道隧道已经结束了。隧道就是你的链表

什么是循环?

想象你在这样一个隧道前面。但是你被警告隧道可能有一个周期,即“隧道的尽头”可能链接回隧道中间的某个地方。所以事实上隧道没有尽头。例如,想象一个 9 字形的隧道。

(图片由作者提供)陷入噩梦循环

如果隧道没有周期,它有一个实际的终点,从那里你可以看到阳光,知道你已经到达了终点。如果你最终走过一个有循环的隧道,你会一直循环下去,永远被困在黑暗中,不知道隧道的尽头是否有光明,或者你是否被困在一个噩梦般的循环中。

问题出在哪里?

你的工作是想出一个策略,让你能检测出你面前的这个隧道是否有循环,也就是你能检测出你的链表是否有循环?假设你在隧道里,你意识到隧道有一个循环,你可以用无线电发出求救信号,有人会来救你。

很酷的策略!

你邀请你的两个爱冒险的朋友过来。他们将被送进装有无线电的隧道。他们同时进入隧道,但其中一人会以比另一人慢的速度行走。

如果隧道没有循环,一切都很好,两个朋友都将退出隧道(当然,更快的一个会更快退出)。

如果隧道确实有周期怎么办?嗯,速度快的会先陷入循环。他一直跑来跑去。较慢的一个也将在稍后陷入循环。他也不停的跑来跑去。但最终…这两个人会相遇!!

他们为什么会相遇?这看起来很直观,但是我们需要证据。一个明智的朋友低声说“想想相对速度”

(图片由作者提供)一个证明的想法!

从慢一点的人的角度想想。他相对于自己是静止的,而较快的人以非零速度运动。当你站在环形轨道上不动,而你的朋友在绕着它跑,会发生什么?他撞到了你。瞧啊。

总结

因此,在我们的隧道(也称为链表)中检测循环的策略是——使用两个装有无线电(指针)的朋友,一个慢一个快来遍历隧道。如果他们中的任何一个离开隧道,他们会用无线电通知你,你知道隧道没有循环。否则,如果隧道确实有一个循环,他们将会相遇,一旦他们相遇,将会用无线电通知你,你将会知道确实有一个循环。

名字是…

毫不奇怪,这种算法的一个名字显然是龟兔赛跑算法

我们来编码吧!

让我们将我们的策略翻译成 python 代码。

class ListNode:
    def __init__(self, x=None):
         self.val = x
         self.next = Nonedef hasCycle(head: ListNode) -> bool:
    ''' Return True if linked list has a cycle, else false'''

    #Base case : If linked list has <= 1 element, no cycle
    if head is None or head.next is None:
         return False #Position slow and fast pointers at start and start+1 position
    slow_pointer = head
    fast_pointer = head.next #Traverse linked list while fast_pointer is not at end of list
    while(fast_pointer is not None):
        #If pointers meet, return True
        if slow_pointer == fast_pointer:
            return True
        #if fast pointer is 1 step before end of list, return False
        elif fast_pointer.next is None:
            return False
        #else move fast_pointer up by 2 steps, slow_pointer by 1
        else:
            slow_pointer = slow_pointer.next
            fast_pointer = fast_pointer.next.next #Fast_pointer has reached end of list, return False
    return False

使用 NANs/复数检测机器学习流水线中的泄漏

原文:https://towardsdatascience.com/detecting-data-leakage-in-ml-pipelines-using-nans-and-complex-numbers-66a066116b40?source=collection_archive---------31-----------------------

检测数据泄漏的简单而精确的方法

机器学习管道中的数据泄漏可能会对您的模型造成严重破坏。在这篇文章中,我将分享一个非常简单的方法,使用 nan 和复数来检测数据泄漏,同时将 ML 管道视为一个黑盒。我将非常简单地谈谈什么是数据泄露。我还会谈到leak-detect,我发布的 python 包可以在一行代码中完成所有这些。

数据泄露快速介绍

描述数据泄漏最精确的方式可能是这样的:

当在训练期间用于创建预测变量的数据在推断时不可用时,在 ML 模型中发生数据泄漏。

显然,在训练期间使用推断时不可用的数据(特征)会导致模型在生产中表现不佳。根据您公司的规模,这种低性能可能意味着数百万美元的损失!

泄漏的一个例子

特征创建管线会通过哪些方式引入数据泄漏?

  1. 使用用于创建特征工程目标的目标或数据。
  2. 使用未来期间的数据进行特征工程。

首先通常更容易检测和跟踪。所以,让我们试着用一个例子来理解第二个。假设您正试图预测一家公司 5 天后的股价。我们的数据包含日期和每日开盘价。

## target (to be predicted): Open price after 5 days.
data['target'] = data['open_price'].shift(-5)

我们希望为这项任务创建各种手工制作的功能。比如说,我们想要的一个特性是“前一天的价格”。

data['price_previous_day'] = data['open_price']**.shift(1)**
# .shift(1) gives value from previous row

但是我们没有做.shift(1),假设我们错误地做了.shift(-1),并使用开盘价下一行的值作为特征。我们只是创建了“第二天的价格”。这是一个漏洞,因为它使用了未来时期的数据。

有许多避免泄漏的最佳实践可以遵循,但是没有一个可以让你 100%确定你的管道没有泄漏。这就是 NANs 和复数的用武之地!这种方法可以看作是数据泄漏的单元测试。

方法论

在进入方法论之前,我们先做个类比:)。

比方说,你有两个水箱通过一根封闭的管道相连。不检查管道,怎么能检测出这个管道确实是封闭的,没有漏水呢?您可以向一个水箱添加颜色,并检查另一个水箱是否也有该颜色。就像水彩画一样,NANs 和复数非常适合于泄漏检测任务,因为它们具有在实数的任何操作之后持续存在的能力。实数与 NAN 或复数之间的加法、减法等运算分别产生 NAN 或复数。当然,这也有例外,我们稍后会谈到。

在股票价格示例中,假设我们将特定日期 D 的开盘价设置为 NAN,并使用该数据创建我们的特性。第二天的价格(泄漏特征)将具有第 D-1 天的 NAN 值,而“前一天的价格”(非泄漏)将具有第 D+1 天的 NAN 值。

因此,对于泄漏特性,我们将在 D 日之前的特性中观察到额外的 NAN。本质上,如果 D 日的开盘价用于创建 D 日之前的特性(这是泄漏),我们将在 D 日之前的特性中看到额外的 NAN。如果在一个输入为 NAN 时使用任何产生 NAN 的操作来创建特性,则情况确实如此。

如果我们想检查 D+1 日、D+2 日等的数据是否用于创建 D 日之前的要素,该怎么办?嗯,我们把它们都设置为 NAN,并且只在 d 日之前的最终特征中计算 NAN。

该方法可以总结为 4 个简单的步骤:

1.定义一个假想的泄漏分区,将数据分成上下两半。在我们的例子中,我们不希望下半部分数据(未来)用于创建上半部分数据(过去)的特征。

2.对原始数据运行数据创建管道,并计算上半部分所有要素中的 nan 数量。我们的数据创建管道创建了上面描述的泄漏和非泄漏特性。我们的非泄漏特征(前一天的价格)有 1 个 NAN,因为我们的数据从 2020 年 1 月 1 日开始,而泄漏特征(第二天的价格)有 0 个 NAN。

3.现在,将原始数据中用于创建要素的所有列设置为渗漏分区下的 NAN。

4.用 NANs 在这个原始数据上运行数据创建管道。再次计算分区上方的 NANs 的数量。对于我们的漏功能,有一个额外的南!

非泄漏特性的上半部分中的 nan 数量保持不变,但泄漏特性增加了 1 个。这个多余的 NAN 是哪里来的?它唯一能来自的地方是全是南的下半部。我们刚刚在我们的泄漏特征中检测到泄漏!这种方法适用于任何特性,因为它不依赖于特性的定义。

通过增加一个虚部而不是用 NAN 代替,并计算具有虚部的行数,可以重复上述相同的过程。Pandas 和 numpy 已经支持所有 nan 和复数运算。所以,你根本不用修改代码!此外,这只能检测管道中的泄漏,而不能检测原始数据中可能已经存在的泄漏。

为什么同时使用 NANs 和复数?

用 NANs 和复数运行这个测试很重要,因为您的管道可能会用一个值替换 NANs。或者 numpy 把复数转换成实数进行一些运算。我测试了它的不同功能,包括加法、乘法、最大、最小运算和泄漏检测功能。尽管如此,留意特殊情况还是很重要的。

Python 包

我还发布了一个 python 包:[**leak-detect**](https://github.com/abhayspawar/leak-detect)用一行代码完成所有这些![leak-detect](https://github.com/abhayspawar/leak-detect)可以检测由于错误代码而发生的水*(从目标到特性)和垂直(从未来到过去)泄漏。在下面的示例中,我们创建了两个使用未来数据的渗漏特征:“return_2day_leaky”和“open_10day_before_leaky”。两者都被检测到具有垂直泄漏。它还打印出数据漏入的先前行数。对于第一个特性,它是 2,因为它使用 2 天后的价格。

使用泄漏检测的示例

回购中的检漏示例. ipynb 笔记本列举了更多这样的例子。你可以通过pip install leak-detect来安装这个包。下面是 github 回购

其他类型的数据创建管道呢?

泄漏检测只对类似于股票价格数据的数据有效。在您的情况下,您可以使用多个数据集来创建要素,甚至可以使用 SQL。无论你的管道是什么,想法仍然是一样的。您必须编写自己的自定义函数,通过查看泄漏检测代码来复制这些函数。

希望这是对你有用的东西。如果你有什么想法,请在评论中告诉我!你也可以通过 abhayspawar 在 TwitterLinkedin 和 Gmail 上联系我。非常感谢你的阅读。注意安全!

用 Doc2vec 检测文档相似度

原文:https://towardsdatascience.com/detecting-document-similarity-with-doc2vec-f8289a9a7db7?source=collection_archive---------7-----------------------

Python 的分步实践介绍

“什锦浆果”由威廉·费尔克Unsplash 上演唱

我们可以用很多方法来分析和理解文本数据。这种方法通常处理称为自然语言处理(NLP)的人工智能领域。

NLP 允许我们执行大量的任务,其中我们的数据由文本或语音组成。情感分析、机器翻译和信息检索只是我们日常使用的 NLP 应用的几个例子。今天,通过结合使用 NLP 和机器学习技术,这些任务中的许多都可以很成功地解决。

在这篇文章中,我想举例说明一个这样的方法,doc2vec,并希望提供一些关于它如何工作以及如何实现它的基本见解。

任务

简而言之,给定大量的文本文档,我们希望能够:

  1. 衡量文档在语义上的相似程度。
  2. 使用此信息根据相似性对文档进行聚类。

我们将涵盖的内容

我知道这是一个较长的职位。因此,在我们开始之前,这里有一个我们将涵盖的所有内容的大纲:

  1. 数据集介绍
  2. doc2vec 和矢量表示概述
  3. 训练 doc2vec 模型
  4. 可视化生成的文档向量
  5. 评估模型

你可以随意阅读,以你觉得舒服的速度。我甚至鼓励你把它分成几部分,在你认为合适的时候反复阅读,以保持专注。

数据

为了训练和测试我们的模型,我们将使用20 个新闻组数据集。这个数据集由 20 个不同主题的大约 18000 个新闻组帖子组成:

20 个新闻组数据集的结构

为了加快训练速度,也为了让我们以后的评估更加清晰,我们把自己限制在四个类别。此外,为了确保这些类别尽可能不同,这四个类别被选择为不属于同一个分区。

例如,这意味着我们可能想用例如 soc.religion.christian 替换其中一个,而不是选择 rec.sport.baseballrec.sport.hockey 。在这里,我决定使用类别足球.宗教.基督教科学.空间谈话.政治.中东,以及娱乐.体育.棒球

选择类别后,他们的文档被分成训练集和测试集,同时跟踪哪些文档属于哪个类别,以便以后更容易判断模型的性能。

在 Python 中,我们可以使用 sklearn 来获取数据:

按类别组织培训和测试数据

基本上,我们正在做的是创建两个字典,每个字典有 4 个关键字(即 4 个类别)。每个键包含属于该类别的所有文档作为其值,其中一个字典包含训练文档,另一个包含测试文档。此外,参数remove=('headers', 'footers', 'quotes')从文档中移除元数据,如页眉、页脚和引用,以防止我们的模型过度适应它们的

生成向量

现在我们有了数据,让我们重新审视我们的任务。请记住,我们首先要弄清楚我们的文档以及它们的上下文是如何相互关联的。

我们希望能够衡量文档在语义上的相似程度

换句话说,我们想要做的是将我们的文本文档转换成数字的、矢量化的形式,稍后聚类算法可以使用这种形式将相似的文档分组在一起。

Doc2vec

产生这种载体的一种算法是 doc2vec [1]。在 Gidi Shperber 的文章中可以找到对这个概念的很好的介绍。本质上,doc2vec 使用神经网络方法来创建可变长度文本片段的向量表示,例如句子、段落或文档。这些矢量表示的优点在于,它们捕捉了输入文本的语义,即含义。这意味着在向量空间中,意义或上下文相似的文本比不一定相关的文本彼此更接*。

Doc2vec 建立在另一种叫做 word2vec 的算法之上2。正如您可能已经从名称中猜到的那样,word2vec 的功能与 doc2vec 非常相似,除了我们得到的不是文档向量,而是单词向量。例如,这意味着像“fast”和“quick”这样的词在向量空间中比“London”彼此更接*。不仅如此,这些向量表示还可以用来执行简单的向量运算。例如,vector("King") - vector("Man") + vector("Woman")产生与“Queen”的矢量表示最相似的矢量。

关于 word2vec 的更深入的介绍,我推荐看看这篇由 Kung-Hsiang,Huang (Steeve) 撰写的文章

显示向量空间中单词之间的关系— TensorFlow

培养

现在我们对 doc2vec 的作用有了一个概念,让我们看看如何在我们的数据上训练一个 doc2vec 模型。下面的实现很大程度上受到了这个教程的启发,我强烈推荐你去看看。

首先,我们需要稍微调整一下原始数据,为训练做准备。

组织和预处理培训和测试文档

同样,我们使用字典来跟踪哪些文档属于哪个类别。为了训练 doc2vec 模型,训练文档需要采用 TaggedDocument 的形式,这基本上意味着每个文档接收一个惟一的 id,由变量offset提供。

此外,函数tokenize()将文档从一个字符串转换成由文档单词组成的字符串列表。它还允许选择停用词以及超过一定长度的词进行删除。

停用词通常是对一段文本没有上下文意义的常用词,因此会被删除。你会注意到,在这里,我选择不删除任何停用词,因为这样做性能似乎会稍微好一点。

通常,停用词的移除高度依赖于手头的任务,并且找出要移除的停用词(如果有的话)并不总是简单明了的。

我们最后得到的是以下变量:

  • train_corpus:培训就绪文档列表
  • cat_dict_test_clean:包含按类别组织的标记化测试文档

请注意,只有实际用于培训的文档才需要标记。

准备好培训文档后,我们现在可以开始培训我们的模型了。

训练模型

我们首先创建一个 doc2vec 对象,它将作为我们的模型,并用不同的超参数值初始化它。

epochs的值决定了训练过程中使用训练语料的次数。vector_size决定了生成的文档向量有多大。此外,任何出现频率低于min_count的单词都将被丢弃。在不涉及太多细节的情况下,window在训练中用于确定在检查给定单词的上下文时要包含多少个单词。更多信息请参见第 2.2 节。[1]的。

当从头开始训练这样的模型时,这些参数的最佳值通过称为 超参数调整 的过程找到。

我在这里使用的价值观绝不是最佳的,也不是一成不变的。请随意使用不同的超参数集来试验训练不同的模型。

然后我们构建词汇表,它基本上是一个字典,包含训练语料库中所有唯一单词的出现次数。最后,对模型进行训练。

我们现在可以从测试集中推断出未知文档的新向量,并使用它们来评估我们的模型。这就是跟踪我们的文档属于哪个类别的用处。

推断测试文档的文档向量,并组织它们以保存到文件中

我们在inferred_vectors_test中按类别保存这些向量。同时,我们初始化另一个字典metadata,它将每个类别映射到一个整数,该整数对应于该类别的推断向量的数量。如果这看起来很奇怪,一会儿就会明白了。这两个变量现在可以用来创建两个文件,如下所示:

将向量和元数据写入文件

两个文件中的第一个文件doc2vec_20Newsgroups_vectors.csv,每行包含一个推断的文档向量,用制表符分隔的值表示,向量按类别排序。

第二个文件doc2vec_20Newsgroups_vectors_metadata.csv,每行包含第一个文件中相应向量的类别。这可能看起来像这样:

talk.politics.mideast
talk.politics.mideast
.
.
.
talk.politics.mideast
rec.sport.baseball
rec.sport.baseball
.
.
.
rec.sport.baseball
sci.space
sci.space
.
.
.
sci.space
soc.religion.christian
soc.religion.christian
.
.
.
soc.religion.christian

形象化

那么我们为什么要把向量和它们的元数据保存到文件中呢?好了,我们现在可以使用这两个文件,使用 TensorFlow 的投影工具来可视化我们文档之间的相似之处。在投影仪工具中,您可以选择不同的降维方法,即 t-SNE、PCA 和自定义轴标记,来表示 2D 或 3D 空间中的矢量。

投影仪尝试对数据点进行聚类,以便相似的点彼此更接*。每种方法都将表示数据点之间的关系,也就是说,以不同的方式分配数据点。例如,一种方法将更侧重于表示各个点之间的局部相似性,而另一种方法可能侧重于保持数据集的整体结构。

用 2D t-SNE 图可视化文档向量

除了看起来非常酷之外,我们可以用这些可视化来判断矢量的质量。通过搜索元数据文件中每个向量的类别名称,我们可以看到图上每个点属于哪个类别。

然而,你会注意到,你可能有很多点位于中间的某个地方,并不真正属于任何集群。一个原因可能是你选择的降维方法;特别是对于 t-SNE,使用的参数值对数据点的分布有很大的影响。

此外,不能忽视的事实是,一些文件可能只是在上下文中含糊不清。例如,来自一个类别的特定文档可能使用大量在来自另一个类别的文档中大量使用的术语,因此它们的向量彼此之间可能比它们自己类别的向量更相似。

多次显示相同的数据点分布,突出显示每个类别的点

你可以通过点击这个链接,使用上面例子中使用的矢量和元数据自己尝试投影仪。

为了从数字上检查文档之间的关系,我们可以通过使用similarity_unseen_docs()函数来计算它们的推断向量之间的余弦距离。

这个函数将我们刚刚训练的 doc2vec 模型和要比较的两个文档作为其参数。作为文档相似性的度量,该函数返回一个介于 0 和 1 之间的值,该值越大,文档越相似。

如果我们想要比较单个文档,这是非常有用的,但是如果我们需要评估我们的模型的性能,我们将不得不扩展它,不仅包括单个文档,还包括我们数据集的一部分。

评估我们的模型

直观上,人们会期望属于同一类别的文档比属于其他类别的文档彼此更相似。这正是我们用来判断模型的标准。一个好的模型应该为同一类别的文档给出比跨类别文档更高的相似性值。因此,在深入了解代码的本质之前,让我们先来看看如何构建比较。

我们要做的第一件事是为所有类别创建文档对集。更具体地说,给定我们的四个类别,我们用 C₁来表示,..,C₄,其中每个类别是一组文档,我们得到以下类别对:

  • (C₁、C₁)、(C₁、C₂)、(C₁、C₃)、(C₁、C₄)
  • (C₂、C₂)、(C₂、C₃)、(C₂、C₄)
  • (C₃、C₃),(C₃、C₄)
  • (c₄c₄)

注意,当测量余弦相似性时,像(such)和(such)这样的对是等价的,因此为了避免冗余,只考虑两个组合中的一个。

对(Ca,Cb)对应于包含类别 a 中所有文档的集合和包含类别 b 中所有文档的集合的笛卡尔积。更正式地说:

现在,对于每个文档对,我们计算文档的相似度。对于每个类别对,这会产生一个介于 0 和 1 之间的值的矩阵(每个文档对一个值)。

可能的相似度矩阵假设有两类 a b 分别包含 m 文档。

因为我们使用这些矩阵来判断两个类别中的文档总体上有多相似,所以将一个矩阵中的所有值浓缩成一个值作为相似性的度量无疑会使我们的工作容易得多。因此,我们将对每个矩阵做的是将矩阵中的所有值相加,得到一个值,我们称之为相似度总计,然后将这个值除以矩阵中的元素总数,得到一个*均相似度值。

请记住,我们判断我们的模型不是根据它告诉我们来自相同类别的文档有多相似,而是根据这些相同类别的文档彼此之间比来自其他类别的文档有多相似。因此,我们真正追求的价值不仅仅是(C₃,C₃)的*均相似度(T30)有多高,而是相对于(C₁,C₃),(C₂,C₃)和(C₃,C₄).)的*均相似度有多高

因此给定我们的四个类别,这留给我们每个类别四个*均相似度;一个用于同类文档,三个用于跨类文档。

下面是我们要为每个类别做的事情。使用每个类别的四个*均相似度值,我们将计算跨类别*均相似度和同类别*均相似度之间的*均相似度差异。更正式地说:

计算类别 3 的*均相似性差异。s()表示两个类别的余弦相似性。请注意 j=3 是如何被跳过的,因为由此产生的减法是多余的。

较高的*均差异告诉我们,该模型能够识别某个类别的文档与其他类别的文档更加不同。当然,如果一个类别的文档确实与另一个类别的文档相似,情况可能并不总是如此。例如,这在诸如 comp.os.ms-windows.misccomp.windows.x 的类别中可能比在comp . OS . ms-windows . miscsoc.religion.christian 中更容易识别。

评估结果可总结如下:

显示的*均相似度是同类文档的*均相似度。一个好的模型应该是给出高的*均差和*均相似度 的模型。

以如此紧凑的形式表示结果使得用不同的超参数训练多个模型并比较它们的性能更加有效。

现在,让我们来看看如何对此进行编码。首先,我们创建一个字典,将文档对列表映射到它们所属的类别对。考虑到结果对的数量很大,我们需要限制这个数量,以便在合理的时间内执行我们的评估。为此,我们从每个字典条目中随机抽取 500 个文档对,并计算每个文档对的余弦相似度。

注意 500 是任意选择。理想情况下,样本越大,表示越准确。

这就产生了类似于我们之前看到的相似矩阵。最后,我们将这些矩阵作为列表保存在一个新的字典中,每个列表都被映射到它所代表的类别对。

生成相似性矩阵

下一步是使用这些相似性值来计算我们上面讨论的紧凑表示。我们首先检查所有的类别对。如果我们找到一个相同类别的配对,我们保存它的*均相似度,以备以后计算*均差异时使用。对于跨类别对,我们简单地将它们的*均相似度保存在一个列表中。

最后一步是使用*均相似度列表和之前保存的同类*均相似度计算*均差异。这个数字,加上同类的*均相似度,作为模型描述这个类别的一个度量。然后对每个类别重复这一过程。

摘要

所以可能需要消化很多东西。以下是我们在本文中讨论的所有内容的总结:

  • 我们看了一下 doc2vec 这是一种常用于生成文本文档的向量表示的方法。
  • 我们看到了如何使用 Gensim 在 Python 中准备数据和训练 doc2vec 模型。
  • 我们看到了使用 TensorFlow 的投影仪来可视化我们的矢量是多么有用。
  • 最后,我们讨论了一种评估 doc2vec 模型的可能方法,它允许对多个模型进行有效的比较。

谢谢你留下来!希望听到您的反馈,并回答您的任何问题。

参考

[1] Q. V. Le 和 T. Mikolov,句子和文档的分布式表示(2014)
【2】t . miko lov,K. Chen,G. Corrado 和 J. Dean,向量空间中单词表示的有效估计,【2013】

利用迁移学习从声音中识别情感

原文:https://towardsdatascience.com/detecting-emotions-from-voice-clips-f1f7cc5d4827?source=collection_archive---------22-----------------------

使用迁移学习训练神经网络从语音剪辑中识别情绪。

一个快乐的人的声音片段的声谱图

在经典情景喜剧《生活大爆炸》中题为“情感检测自动化”的一集里,霍华德设法获得了一个设备,可以帮助谢尔顿(他很难读懂别人的情感暗示)通过将设备指向周围的人来理解他们的感受…

人类不仅倾向于用口语来传达信息,还会用音调、肢体语言和表情来传达信息。同样的信息以两种不同的方式说出来,可能会有非常不同的含义。因此,牢记这一点,我考虑着手一个项目,利用音调、响度和各种其他因素来识别语音剪辑中的情绪,以确定说话者的感受。

这篇文章基本上是一个简短但完整的教程,它解释了如何训练一个神经网络来预测一个人的情绪。该过程将分为 3 个步骤:

  1. 理解数据
  2. 数据预处理
  3. 训练神经网络

我们将需要以下库。fastai
2。numpy
3。matplotlib
4。天秤座
5。pytorch

您还需要一个 jupyter 笔记本电脑环境。

理解数据

我们将一起使用两个数据集来训练神经网络:

RAVDESS 数据集

RAVDESS 数据集是 24 个演员用 8 种不同的情绪(中性、*静、快乐、悲伤、愤怒、恐惧、厌恶、惊讶)说同样的两句台词的音频和视频剪辑的集合。在本教程中,我们将只使用音频剪辑。您可以从这里的获取数据集。

TESS 数据集

TESS 数据集是两个女人表达 7 种不同情绪(愤怒、厌恶、恐惧、快乐、惊喜、悲伤和中性)的音频剪辑的集合。你可以从这里获取数据集。

我们将声音剪辑转换成图形格式,然后将两个数据集合并成一个,然后我们将把它分成 8 个不同的文件夹,每个文件夹对应 RAVDESS 数据集部分中提到的一种情绪(我们将把惊讶和惊喜合并成一个组件)。

数据预处理

我们将把声音剪辑转换成图形数据,这样它就可以用于神经网络的训练。为此,请查看下面的代码:

上面的笔记本显示了如何将声音文件转换为图形数据,以便神经网络可以解释它。我们正在使用名为 librosa 的库来做这件事。我们正在用 MEL 标度将声音数据转换成频谱图,因为这个标度的设计是为了使它更容易解释。这个笔记本包含应用于一个声音文件的代码。包含将初始数据集转换为最终输入数据的全部代码的笔记本可以在这里找到。

因此,在运行上面笔记本中给出的每个声音文件的代码,然后根据需要划分文件后,你应该有 8 个单独的文件夹,分别标有相应的情绪。每个文件夹应该包含所有声音剪辑的图形输出,这些声音剪辑表达了文件夹所标注的情感。

训练神经网络

我们现在将开始训练神经网络,通过观察声音片段产生的频谱来识别情绪。我们将使用 fastai 库训练神经网络。我们将使用一个预训练的 CNN ( resnet34),然后在我们的数据上训练它。
我们将要做的如下:

1.制作具有适当数据扩充的数据加载器,以输入到神经网络。每幅图像的大小为 432×288。

2.我们将使用在 imagenet 数据集上预先训练的神经网络(resnet34)。然后,我们将通过适当的裁剪将我们的图像缩小到 144 乘 144 的大小,然后在该数据集上训练我们的神经网络。

3.然后,我们将在尺寸为 288×288 的图像上再次训练神经网络。

4.然后,我们将分析神经网络在验证集上的性能。

5.瞧啊。训练过程将会完成,你将拥有一个可以从声音片段中识别情绪的神经网络。

开始训练吧!

在上面的部分中,我们已经使用我们的数据创建了一个数据加载器。我们对图像进行了适当的变换,以减少过度拟合,并将其缩小到 144 乘 144 的大小。我们还将其分为验证集和训练集,并根据文件夹名称标记数据。如您所见,数据有 8 个类别,因此这是一个简单的影像数据集分类问题。

在上面的部分中,我们使用了一个预训练的神经网络,然后在大小为 144×144 的图像上训练它来识别情绪。在训练结束时,我们的准确率达到了 80.1 %。
现在我们有了一个神经网络,它非常擅长通过查看 144×144 大小的图像来识别情绪。因此,现在我们将使用相同的神经网络,并训练它通过查看 288×288 大小的图像来识别情绪(它应该已经很擅长了)。

在上面的部分中,我们在 288×288 大小的图像上训练神经网络(我们已经在 144×144 大小的图像上训练过)。瞧,瞧!它现在可以从声音片段中识别情绪,而不管语音的内容如何,准确率为 83.1 %(在验证集上)。
在下一节中,我们将使用混淆矩阵分析神经网络的结果。

上面的部分包含了我们数据集的混淆矩阵。

完整的培训用笔记本可以在这里找到,从预处理到培训的所有笔记本都可以在这里找到。

感谢你阅读这篇文章,希望你喜欢!

引文

RAVDESS: living stone SR,Russo FA (2018)瑞尔森情感语音和歌曲视听数据库(rav dess):北美英语中一组动态、多模态的面部和声音表情。PLoS ONE 13(5): e0196391。https://doi.org/10.1371/journal.pone.0196391

多伦多情感演讲集(苔丝): 皮乔拉-富勒,m .凯思琳;杜普斯,凯特,2020,《多伦多情感演讲集(TESS)》,https://doi.org/10.5683/SP2/E8H2MF,学者门户网站 Dataverse,V1

使用 JavaScript 检测人脸特征并应用滤镜

原文:https://towardsdatascience.com/detecting-face-features-and-applying-filters-with-javascript-34a2081daebb?source=collection_archive---------67-----------------------

使用 JavaScript 构建类似 Snapchat 的过滤器

从应用程序中截取—背景照片由 Théo rqlUnsplash 上拍摄

几天前我发表了一篇关于“用 Python 检测面部特征”的文章,我在 Twitter上收到了很多关于如何用 JavaScript 做这件事的问题。今天我们将回答这个问题,我们将添加一些额外的东西,比如用蜘蛛侠滤镜或者经典的狗滤镜来遮盖你的脸。参与这个项目非常有趣,我希望你会喜欢。

本文将涵盖两个主要主题:

  • 人脸特征识别
  • 添加过滤器

如何检测面部特征?

类似于 DLib 的工作方式,对于 JavaScript,我们有一个名为 clmtrackr 的库,它将完成检测人脸在图像上的位置的繁重工作,并且还将识别人脸特征,如鼻子、嘴、眼睛等。

该库提供了一些通用模型,这些模型已经过预训练,可以按照如下特征编号使用:

点地图

当我们用这个库处理一个图像时,它将为地图上的每个点返回一个数组,其中每个点由它在xy轴上的位置来标识。当我们构建过滤器时,这将变得非常重要。你可能已经猜到了,如果我们想要画一些东西来代替人的鼻子,我们可以使用鼻子的中心点62

不过,说够了,让我们开始研究一些很酷的东西吧!

我们在建造什么?

在本文中,我们将利用clmtrackr来识别视频流中的人脸(在我们的例子中是网络摄像头或摄像机),并应用可以通过屏幕上的下拉菜单选择的自定义过滤器。这是 codepen 上的应用程序演示(请确保您在浏览器中允许应用程序访问相机,否则它将无法工作):

厉害!它可能不完美,但看起来很神奇!

让我们分解代码并解释我们正在做什么。

基本代码结构

为了构建应用程序,我们使用了 p5.js 库,这是一个 JavaScript 库,主要用于处理 canvas,非常适合我们的用例。P5JS 不是你传统的 UI 库,它使用事件来定义什么时候构建 UI,什么时候更新 UI。类似于一些游戏引擎。

我想介绍 p5 的 3 个主要事件:

  • preload:在库加载之后,构建任何 UI 或在屏幕上绘制任何东西之前执行。这使得加载资产变得非常完美。
  • setup:也是在preload之后执行一次,我们在这里准备一切并构建初始 UI
  • draw:循环调用的函数,每次系统需要渲染屏幕时执行。

事先装好

根据定义,我们将使用preload事件来加载我们将在后面的代码中使用的图像,如下所示:

function preload() {
    // Spiderman Mask Filter asset
    imgSpidermanMask = loadImage("https://i.ibb.co/9HB2sSv/spiderman-mask-1.png");

    // Dog Face Filter assets
    imgDogEarRight = loadImage("https://i.ibb.co/bFJf33z/dog-ear-right.png");
    imgDogEarLeft = loadImage("https://i.ibb.co/dggwZ1q/dog-ear-left.png");
    imgDogNose = loadImage("https://i.ibb.co/PWYGkw1/dog-nose.png");
}

很简单。如您所料,p5 中的函数loadImage将加载图像并使其作为 P5 图像对象可用。

设置

这里的事情变得更有趣了,因为它是我们加载 UI 的地方。我们将把在这个事件中执行的代码分成 4 个部分

创建画布

因为我们希望我们的代码具有响应性,所以我们的画布将具有动态大小,该大小将根据窗口大小并使用 4:3 的纵横比来计算。在代码中使用这样的纵横比并不理想,但是我们会做一些假设,以保持代码简洁,便于演示。在我们知道画布的尺寸后,我们可以用 P5 函数createCanvas创建一个,如下所示。

const maxWidth = Math.min(windowWidth, windowHeight);
pixelDensity(1);
outputWidth = maxWidth;
outputHeight = maxWidth * 0.75; // 4:3createCanvas(outputWidth, outputHeight);

捕获视频流

在我们的画布工作后,我们需要从网络摄像头或摄像机捕捉视频流,并将其放入画布,幸运的是 P5 通过videoCapture函数可以很容易地做到这一点。

// webcam capture
videoInput = createCapture(VIDEO);
videoInput.size(outputWidth, outputHeight);
videoInput.hide();

构建过滤器选择器

我们的应用程序很棒,可以为多个过滤器提供选项,所以我们需要建立一种方法来选择我们想要激活的过滤器。同样…我们可以在这里变得非常有趣,然而,为了简单起见,我们将使用一个简单的下拉菜单,我们可以使用 P5 createSelect()函数来创建它。

// select filter
const sel = createSelect();
const selectList = ['Spiderman Mask', 'Dog Filter']; // list of filters
sel.option('Select Filter', -1); // Default no filter
for (let i = 0; i < selectList.length; i++)
{
    sel.option(selectList[i], i);
}
sel.changed(applyFilter);

创建图像跟踪器

图像跟踪器是一个可以附加到视频馈送的对象,它将为每一帧识别所有的脸及其特征。对于给定的视频源,跟踪器需要设置一次。

// tracker
faceTracker = new clm.tracker();
faceTracker.init();
faceTracker.start(videoInput.elt);

绘制视频和滤镜

现在一切都设置好了,我们需要从 P5 更新我们的draw事件,将视频源输出到画布,并应用任何选中的过滤器。在我们的例子中,draw函数将非常简单,将复杂性推到每个过滤器定义中。

function draw() {
  image(videoInput, 0, 0, outputWidth, outputHeight); // render video from webcam // apply filter based on choice
  switch(selected)
  {
    case '-1': break;
    case '0': drawSpidermanMask(); break;
    case '1': drawDogFace(); break;
  }
}

建立蜘蛛侠面具过滤器

蜘蛛侠面具滤镜

构建过滤器可能是一项简单或非常复杂的任务。这将取决于过滤器应该做什么。对于蜘蛛侠的面具,我们只需要将蜘蛛侠的面具图像放在屏幕的中央。为此,我们首先通过使用faceTraker.getCurrentPosition()来确保我们的 faceTracker 对象确实检测到了人脸。

一旦我们检测到我们的面部,我们使用 P5 来使用面部点 62 渲染图像,面部点 62 是作为图像中心的鼻子的中心,并且具有如下表示面部大小的宽度和高度。

const positions = faceTracker.getCurrentPosition();
if (positions !== false)
{
    push();
    const wx = Math.abs(positions[13][0] - positions[1][0]) * 1.2; // The width is given by the face width, based on the geometry
    const wy = Math.abs(positions[7][1] - Math.min(positions[16][1], positions[20][1])) * 1.2; // The height is given by the distance from nose to chin, times 2
    translate(-wx/2, -wy/2);
    image(imgSpidermanMask, positions[62][0], positions[62][1], wx, wy); // Show the mask at the center of the face
    pop();
}

很酷吧?

现在狗过滤器以同样的方式工作,但是使用三张图片而不是一张,每只耳朵一张,鼻子一张。我不会用更多相同的代码来烦你,但是如果你想检查它,回顾一下 codepen ,它包含了演示的完整代码。

结论

在 JavaScript 库的帮助下,识别面部特征并开始构建自己的过滤器是非常容易的。不过,还有一些我们在本教程中没有涉及到的注意事项。比如脸不直对着镜头会怎么样?我们如何扭曲我们的过滤器,使它们符合面部的曲率?或者,如果我想添加 3d 对象而不是 2d 滤镜,该怎么办?

我知道你们中的很多人会用它来做一些很酷的东西,我很想听听你们做了什么,如果你们也能和我分享你们的例子。你可以在推特上找到我。

感谢阅读!

用 Python 检测人脸特征

原文:https://towardsdatascience.com/detecting-face-features-with-python-30385aee4a8e?source=collection_archive---------3-----------------------

计算机视觉

使用 OpenCV 和 DLib 识别人脸并提取最多 6 个面部特征

作者的形象

今天我们将学习如何使用图像来检测人脸并提取面部特征,如眼睛、鼻子、嘴巴等。我们可以做许多令人难以置信的事情,将这些信息作为预处理步骤,如捕捉人脸以标记照片中的人(手动或通过机器学习),创建效果以“增强”我们的图像(类似于 Snapchat 等应用程序中的那些),对人脸进行情感分析等等。

过去,我们已经介绍过如何使用 OpenCV 来检测图像中的形状,但今天我们将通过引入 DLib 和从图像中提取人脸特征来将它提升到一个新的水*。

[## 帮助您开始学习计算机视觉的基本 OpenCV 函数

了解常见的 OpenCV 函数及其应用,帮助您开始学习计算机视觉。

towardsdatascience.com](/essential-opencv-functions-to-get-you-started-into-computer-vision-743df932e60)

Dlib 是一个先进的机器学习库,旨在解决复杂的现实世界问题。这个库是使用 C++编程语言创建的,它可以与 C/C++、Python 和 Java 一起工作。

值得注意的是,本教程可能需要对 OpenCV 库有一些了解,比如如何处理图像、打开相机、图像处理和一些小技巧。

它是如何工作的?

我们的脸有几个可以被识别的特征,像我们的眼睛、嘴巴、鼻子等等。当我们使用 DLib 算法来检测这些特征时,我们实际上获得了围绕每个特征的点的地图。

这张由 67 个点(称为地标点)组成的地图可以识别以下特征:

点地图

  • 颌点= 0–16
  • 右眉点数= 17–21
  • 左眉点数= 22–26
  • 鼻点= 27–35°
  • 右眼点数= 36–41
  • 左眼点数= 42–47
  • 嘴部点数= 48–60
  • 嘴唇点数= 61–67

现在我们已经知道了一些我们计划如何提取特性,让我们开始编码吧。

安装要求

像往常一样,本文将提供带有代码的示例,我将一步一步地指导您实现一个完整的人脸特征识别示例。但是在我们开始之前,您需要启动一个新的 Python 项目并安装 3 个不同的库:

  • opencv-python
  • dlib

如果你像我一样使用pipenv,你可以用下面的命令安装它们:

pipenv install opencv-python, dlib

如果你在 Mac 和某些版本的 Linux 上工作,你可能会在安装 dlib 时遇到一些问题,如果你在安装过程中遇到编译错误,请确保检查你正在使用的 CMake 库版本。在 Mac 中,要确保您有 CMake 可用并且版本正确,您可以运行:

brew install cmake

对于其他操作系统,请在线查看具体支持。

步骤 1:加载并显示图像

我们将从小处着手,构建代码,直到我们有一个完整的工作示例。

通常我喜欢使用绘图来渲染图像,但是因为我们在帖子的后面准备了一些很酷的东西,我们将做一些不同的事情,我们将创建一个窗口来显示我们的工作结果。

让我们直接进入代码

import cv2# read the image
img = cv2.imread("face.jpg")# show the image
cv2.imshow(winname="Face", mat=img)# Wait for a key press to exit
cv2.waitKey(delay=0)# Close all windows
cv2.destroyAllWindows()

很简单,对吧?我们只是用imread加载图像,然后告诉 OpenCV 在winname中显示图像,这将打开窗口并给它一个标题。

之后,我们需要暂停执行,因为当脚本停止时窗口会被破坏,所以我们使用cv2.waitKey按住窗口直到按下一个键,之后,我们破坏窗口并退出脚本。

如果您使用代码并将名为face.jpg的图像添加到代码目录中,您应该会得到如下所示的内容:

原象

第二步:面部识别

到目前为止,我们还没有对图像做任何事情,除了将它显示在一个窗口中,相当无聊,但是现在我们将开始编码好的东西,我们将从识别图像中哪里有人脸开始。

为此,我们将使用名为get_frontal_face_detector()的 Dlib 函数,相当直观。不过有一个警告,这个函数只适用于灰度图像,所以我们必须先用 OpenCV 来实现。

get_frontal_face_detector()将返回一个detector,这是一个我们可以用来检索人脸信息的函数。每个面都是一个对象,包含可以找到图像的点。

但是让我们更好地在代码上看到它:

import cv2
import dlib# Load the detector
detector = dlib.get_frontal_face_detector()# read the image
img = cv2.imread("face.jpg")# Convert image into grayscale
gray = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2GRAY)# Use detector to find landmarks
faces = detector(gray)for face in faces:
    x1 = face.left() # left point
    y1 = face.top() # top point
    x2 = face.right() # right point
    y2 = face.bottom() # bottom point
    # Draw a rectangle
    cv2.rectangle(img=img, pt1=(x1, y1), pt2=(x2, y2), color=(0, 255, 0), thickness=4)# show the image
cv2.imshow(winname="Face", mat=img)# Wait for a key press to exit
cv2.waitKey(delay=0)# Close all windows
cv2.destroyAllWindows()

上面的代码将从图像中检索所有的面,并在每个面上呈现一个矩形,生成如下所示的图像:

到目前为止,我们在寻找人脸方面做得很好,但我们仍然需要一些工作来提取所有的特征(标志)。接下来让我们继续。

第三步:识别面部特征

你喜欢魔术吗?到目前为止,DLib 的工作方式非常神奇,只用几行代码我们就可以完成很多工作,现在我们有了一个全新的问题,它会继续这么简单吗?

简短的回答是肯定的!原来 DLib 提供了一个名为shape_predictor()的函数,它将为我们完成所有的魔法,但有一个警告,它需要一个预先训练好的模型才能工作。

有几个型号可以与shape_predictor一起工作,我正在使用的型号可以在这里下载,但也可以尝试其他型号。

让我们看看新代码现在是什么样子

import cv2
import dlib# Load the detector
detector = dlib.get_frontal_face_detector()# Load the predictor
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")# read the image
img = cv2.imread("face.jpg")# Convert image into grayscale
gray = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2GRAY)# Use detector to find landmarks
faces = detector(gray)for face in faces:
    x1 = face.left() # left point
    y1 = face.top() # top point
    x2 = face.right() # right point
    y2 = face.bottom() # bottom point # Look for the landmarks
    landmarks = predictor(image=gray, box=face)
    x = landmarks.part(27).x
    y = landmarks.part(27).y # Draw a circle
    cv2.circle(img=img, center=(x, y), radius=5, color=(0, 255, 0), thickness=-1)# show the image
cv2.imshow(winname="Face", mat=img)# Wait for a key press to exit
cv2.waitKey(delay=0)# Close all windows
cv2.destroyAllWindows()

像以前一样,我们总是建立在相同的代码上,现在对每张脸使用我们的预测函数来找到界标。现在我仍然在做一些奇怪的事情,比如 27 号在那里做什么?

landmarks = predictor(image=gray, box=face)
x = landmarks.part(27).x
y = landmarks.part(27).y

我们的预测函数将返回一个对象,该对象包含所有 68 个点,根据我们之前看到的图表,这些点符合一张脸,如果您注意它,点 27 正好在两眼之间,因此如果计算正确,您应该会在脸的两眼之间看到一个绿点,如下所示:

我们越来越接*了,现在让我们渲染所有的点,而不仅仅是一个点:

import cv2
import numpy as np
import dlib# Load the detector
detector = dlib.get_frontal_face_detector()# Load the predictor
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")# read the image
img = cv2.imread("face.jpg")# Convert image into grayscale
gray = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2GRAY)# Use detector to find landmarks
faces = detector(gray)
for face in faces:
    x1 = face.left() # left point
    y1 = face.top() # top point
    x2 = face.right() # right point
    y2 = face.bottom() # bottom point # Create landmark object
    landmarks = predictor(image=gray, box=face) # Loop through all the points
    for n in range(0, 68):
        x = landmarks.part(n).x
        y = landmarks.part(n).y # Draw a circle
        cv2.circle(img=img, center=(x, y), radius=3, color=(0, 255, 0), thickness=-1)# show the image
cv2.imshow(winname="Face", mat=img)# Delay between every fram
cv2.waitKey(delay=0)# Close all windows
cv2.destroyAllWindows()

Tada!魔力:

但是如果你对所有的点都不感兴趣呢?嗯……你实际上可以调整你的range间隔来获得上面词汇表中指定的任何特性,就像我在这里做的那样:

太棒了,但我们能做些更酷的吗?

步骤 4:实时检测

是的,你没看错!是的,这可能就是你所想的!下一步是连接我们的网络摄像头,从您的视频流中进行实时地标识别。

你可以通过相机或使用视频文件遍历视频帧,在你的脸上进行实时面部标志检测。参考下面的代码,如果你想使用自己的摄像头,但对于视频文件,请确保将数字 0 改为视频路径。

如果您想结束窗口,请按键盘上的 ESC 键:

import cv2
import dlib

# Load the detector
detector = dlib.get_frontal_face_detector()

# Load the predictor
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

# read the image
cap = cv2.VideoCapture(0)

while True:
    _, frame = cap.read()
    # Convert image into grayscale
    gray = cv2.cvtColor(src=frame, code=cv2.COLOR_BGR2GRAY)

    # Use detector to find landmarks
    faces = detector(gray)

    for face in faces:
        x1 = face.left()  # left point
        y1 = face.top()  # top point
        x2 = face.right()  # right point
        y2 = face.bottom()  # bottom point

        # Create landmark object
        landmarks = predictor(image=gray, box=face)

        # Loop through all the points
        for n in range(0, 68):
            x = landmarks.part(n).x
            y = landmarks.part(n).y

            # Draw a circle
            cv2.circle(img=frame, center=(x, y), radius=3, color=(0, 255, 0), thickness=-1)

    # show the image
    cv2.imshow(winname="Face", mat=frame)

    # Exit when escape is pressed
    if cv2.waitKey(delay=1) == 27:
        break

# When everything done, release the video capture and video write objects
cap.release()

# Close all windows
cv2.destroyAllWindows()

最后的结果在这里:

根据原始视频创建的 GIF,我必须剪切帧以使 GIF 具有合适的大小。

即使在光线较弱的情况下,结果也相当准确,尽管上面的图像有一些误差,但光线较好的情况下效果很好。

结论

OpenCV 和 DLib 是强大的库,简化了 ML 和计算机视觉的工作。今天我们只触及最基本的内容,还有很多东西要向他们学习。

非常感谢你的阅读!

检测有代码和无代码的假新闻

原文:https://towardsdatascience.com/detecting-fake-news-with-and-without-code-dd330ed449d9?source=collection_archive---------1-----------------------

使用 Python 和其他工具比较不同的 NLP 技术和方法来检测假新闻。

Héizel Vázquez 插图

这些推文到底是真是假?

他们确实是。7 月 15 日(昨天当我写这篇文章时),Twitter 出现了一个重大问题,大账户被黑客攻击,要求比特币捐款,承诺将汇款金额翻倍。因此,即使这些推文是真实的,它们也包含了虚假信息。

该公司在推特上写道:

这不是第一次发生这种情况,也可能不是最后一次。但是,我们能防止这种情况吗?我们能阻止这一切发生吗?

问题是

问题不仅仅是黑客,进入账户,发送虚假信息。这里更大的问题是我们所说的“假新闻”。假新闻是那些虚假的新闻故事:故事本身是捏造的,没有可证实的事实、来源或引用。

当某人(或类似于机器人的东西)冒充某人或可靠来源传播虚假信息时,也可以被认为是假新闻。在大多数情况下,制造这种虚假信息的人有一个议程,可以是政治的、经济的或改变行为或对某个话题的想法。

现在假新闻的来源数不胜数,大多来自编程好的机器人,它们乐此不疲(它们是机器呵呵),全天候持续传播虚假信息。

引言中的推文只是这个问题的基本例子,但在过去 5 年中更严肃的研究表明,虚假信息的传播与选举、关于不同主题的流行观点或感受之间有很大的相关性。

这个问题是真实的,而且很难解决,因为机器人正在变得更好,正在欺骗我们。要一直检测信息的真假并不容易,因此我们需要更好的系统来帮助我们了解假新闻的模式,以改善我们的社交媒体和沟通,并防止世界陷入混乱。

目的

在这篇短文中,我将解释几种使用从不同文章中收集的数据来检测假新闻的方法。但是相同的技术可以应用于不同的场景。

我会用两种方式来做:

  • 对于编码人员和专家,我将解释加载、清理和分析数据的 Python 代码。然后我们会做一些机器学习模型来执行一个分类任务(假的还是假的)
  • 对于非技术人员,我将在 Analyttica 的一个名为 TreasureHunt LEAPS 的系统中使用点击模式,这将允许我们做几乎所有我们用 Python 做的事情,但不需要编程,并且自动查看生成的代码。注意:你点击的 LEAPS 的链接会把你从我的推荐中引导到我的网站,这是一个免费的*台,但是如果你也分享你的链接,你可以赢得积分!

数据

数据来自 Kaggle,你可以在这里下载:

[## 真假新闻数据集

新闻分类

www.kaggle.com](https://www.kaggle.com/clmentbisaillon/fake-and-real-news-dataset)

有两个文件,一个是真实新闻,一个是虚假新闻(都是英文的),共有 23481 条“虚假”推文和 21417 条“真实”文章。

所有数据和代码都可以在这个 GitHub repo 中找到:

[## FavioVazquez/假新闻

假新闻检测。在 GitHub 上创建一个帐户,为 FavioVazquez/假新闻的发展做出贡献。

github.com](https://github.com/FavioVazquez/fake-news)

用 Python 解决问题

数据读取和连接:

首先,我们将数据加载到 Python 中:

fake = pd.read_csv("data/Fake.csv")
true = pd.read_csv("data/True.csv")

然后我们添加一个标志来跟踪假的和真的:

fake['target'] = 'fake'
true['target'] = 'true'

现在让我们连接数据帧:

data = pd.concat([fake, true]).reset_index(drop = True)

我们将打乱数据以防止偏差:

from sklearn.utils import shuffle
data = shuffle(data)
data = data.reset_index(drop=True)

数据清理

删除日期(我们不会将它用于分析):

data.drop(["date"],axis=1,inplace=True)

删除标题(我们将只使用文本):

data.drop(["title"],axis=1,inplace=True)

将文本转换为小写:

data['text'] = data['text'].apply(lambda x: x.lower())

删除标点符号:

import stringdef punctuation_removal(text):
    all_list = [char for char in text if char not in string.punctuation]
    clean_str = ''.join(all_list)
    return clean_strdata['text'] = data['text'].apply(punctuation_removal)

删除停用词:

import nltk
nltk.download('stopwords')
from nltk.corpus import stopwords
stop = stopwords.words('english')data['text'] = data['text'].apply(lambda x: ' '.join([word for word in x.split() if word not in (stop)]))

数据探索

每个主题有多少篇文章?

print(data.groupby(['subject'])['text'].count())
data.groupby(['subject'])['text'].count().plot(kind="bar")
plt.show()

有多少假货和真货?

print(data.groupby([‘target’])[‘text’].count())
data.groupby([‘target’])[‘text’].count().plot(kind=”bar”)
plt.show()

假新闻的词云:

from wordcloud import WordCloudfake_data = data[data["target"] == "fake"]
all_words = ' '.join([text for text in fake_data.text])wordcloud = WordCloud(width= 800, height= 500,
                          max_font_size = 110,
                          collocations = False).generate(all_words)plt.figure(figsize=(10,7))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.show()

真实新闻的文字云:

from wordcloud import WordCloudreal_data = data[data[“target”] == “true”]
all_words = ‘ ‘.join([text for text in fake_data.text])wordcloud = WordCloud(width= 800, height= 500, max_font_size = 110,
 collocations = False).generate(all_words)plt.figure(figsize=(10,7))
plt.imshow(wordcloud, interpolation=’bilinear’)
plt.axis(“off”)
plt.show()

最常用词功能:

# Most frequent words counter (Code adapted from [https://www.kaggle.com/rodolfoluna/fake-news-detector](https://www.kaggle.com/rodolfoluna/fake-news-detector))   
from nltk import tokenizetoken_space = tokenize.WhitespaceTokenizer()def counter(text, column_text, quantity):
    all_words = ' '.join([text for text in text[column_text]])
    token_phrase = token_space.tokenize(all_words)
    frequency = nltk.FreqDist(token_phrase)
    df_frequency = pd.DataFrame({"Word": list(frequency.keys()),
                                   "Frequency": list(frequency.values())})
    df_frequency = df_frequency.nlargest(columns = "Frequency", n = quantity)
    plt.figure(figsize=(12,8))
    ax = sns.barplot(data = df_frequency, x = "Word", y = "Frequency", color = 'blue')
    ax.set(ylabel = "Count")
    plt.xticks(rotation='vertical')
    plt.show()

假新闻中出现频率最高的词:

counter(data[data[“target”] == “fake”], “text”, 20)

真实新闻中最常见的词:

counter(data[data[“target”] == “true”], “text”, 20)

建模

建模过程将包括对存储在“文本”列中的语料库进行矢量化,然后应用 TF-IDF ,最后是分类机器学习算法。相当标准的文本分析和自然语言处理。

对于建模,我们有这个函数来绘制模型的混淆矩阵:

# Function to plot the confusion matrix (code from [https://scikit-learn.org/stable/auto_examples/model_selection/plot_confusion_matrix.html](https://scikit-learn.org/stable/auto_examples/model_selection/plot_confusion_matrix.html))
from sklearn import metrics
import itertoolsdef plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):

    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
        print("Normalized confusion matrix")
    else:
        print('Confusion matrix, without normalization')thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, cm[i, j],
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

拆分数据:

X_train,X_test,y_train,y_test = train_test_split(data['text'], data.target, test_size=0.2, random_state=42)

逻辑回归:

# Vectorizing and applying TF-IDF
from sklearn.linear_model import LogisticRegressionpipe = Pipeline([('vect', CountVectorizer()),
                 ('tfidf', TfidfTransformer()),
                 ('model', LogisticRegression())])# Fitting the model
model = pipe.fit(X_train, y_train)# Accuracy
prediction = model.predict(X_test)
print("accuracy: {}%".format(round(accuracy_score(y_test, prediction)*100,2)))

我得到了 98.76%的准确率。混乱矩阵:

cm = metrics.confusion_matrix(y_test, prediction)
plot_confusion_matrix(cm, classes=['Fake', 'Real'])

决策树分类器:

from sklearn.tree import DecisionTreeClassifier# Vectorizing and applying TF-IDF
pipe = Pipeline([('vect', CountVectorizer()),
                 ('tfidf', TfidfTransformer()),
                 ('model', DecisionTreeClassifier(criterion= 'entropy',
                                           max_depth = 20, 
                                           splitter='best', 
                                           random_state=42))])
# Fitting the model
model = pipe.fit(X_train, y_train)# Accuracy
prediction = model.predict(X_test)
print("accuracy: {}%".format(round(accuracy_score(y_test, prediction)*100,2)))

我得到了 99.71 %的准确率。混乱矩阵:

cm = metrics.confusion_matrix(y_test, prediction)
plot_confusion_matrix(cm, classes=['Fake', 'Real'])

随机森林分类器:

from sklearn.ensemble import RandomForestClassifierpipe = Pipeline([('vect', CountVectorizer()),
                 ('tfidf', TfidfTransformer()),
                 ('model', RandomForestClassifier(n_estimators=50, criterion="entropy"))])model = pipe.fit(X_train, y_train)
prediction = model.predict(X_test)
print("accuracy: {}%".format(round(accuracy_score(y_test, prediction)*100,2)))

我得到了 98.98 %的准确率。混乱矩阵:

cm = metrics.confusion_matrix(y_test, prediction)
plot_confusion_matrix(cm, classes=['Fake', 'Real'])

不用编码解决问题

我们有一个很好的 Python 模型。现在是时候不用编码做同样的事情(或者尽可能多的事情)了。同样,我们将为此使用一个名为 LEAPS 的系统。有很多事情要做,我也不想复制 15 张截图来说明怎么做。所以我只放最重要的部分。

重要提示:为了能够使用某些函数,您需要选择数据集的至少一列。如果你想了解更多关于如何使用*台查看他们的免费课程 这里

以下是如何做到这一点:

  • 创建一个免费帐户
  • 创建新项目
  • 上传数据:您必须分别上传每个数据集,然后将“fake.csv”重命名为 fake,将“true.csv”重命名为 true。在*台中这是一个简单的过程。
  • 在假数据集和真数据集中创建一个名为“target”的列。对于假的,它应该是一个常量值 0 ,对于真的,它应该是一个常量值 1。进入功能- >数据管理- >列操作- >生成常量列(Py)。注意:要执行此操作,您必须选择数据集中的所有列。创建列后,您必须将其重命名为“目标”。
  • 追加两个表,并用真假 tweets 创建一个完整的表。确保在执行追加之前选择所有列。你可以在函数->数据管理->表操作->追加表中找到追加操作。将新表重命名为“All”。注意:您必须从两个数据集中选择所有列来执行追加表操作。
  • 删除“日期”和“标题”列。首先选择它们,然后进入功能->数据管理->列操作->删除列:

  • 最后一步创建了一个新表,在我的例子中命名为“Table_4”。我们将暂时在那张桌子上工作。现在,我们将把列“text”全部转换为小写。为此,我们选择列,然后进入函数->文本分析->文本预处理->小写。你应该有这个:

  • 我们现在将删除标点符号。要做到这一点,进入功能->文本分析->文本预处理->删除标点符号。你应该会看到这个:

  • 让我们创建一个语料库来进行下一步工作。要做到这一点,进入功能->文本分析->文本预处理->建立语料库。让我们也将最后一列重命名为“语料库”。
  • 最后,让我们删除停用词(在“语料库”列)。要做到这一点,进入功能->文本分析->文本预处理->删除单词。这将删除基于一些 Python 和 R 库的单词,但是您可以在这里定义更多要删除的单词。这是你现在应该有的:

  • 让我们从 Python 部分复制一些图表和统计数据。第一:每科多少篇?我们必须选择“主题”列,然后转到函数->数据可视化->分布图->按组绘制密度图(Py)。这是我能得到的最相似的图表。结果是:

  • 现在让我们看看一个图表中有多少“假”和“真”的文章。为此,请转到函数->数据可视化->分布图->直方图。这是我得到的:

  • 让我们现在建立单词云。为此,我必须首先再次分离“假”和“真”文章的数据。要做到这一点(选择“目标”列),进入功能->数据管理->数据采样/子集->过滤分类。我为“假的”创建了一个名为“Fake_Clean”的表,然后为“真的”创建了一个名为“True_Clean”的表。然后我为两个语料库(语料库的复数)都创建了单词 cloud。要创建词云,请进入功能->文本分析->信息检索->词云,选择“语料库”栏。注:最后我按类用了云这个词,选了“目标”作为类。结果是一样的。

这是我从“假”文章中得到的信息:

这是“真实”的文章:

非常类似于 Python 的结果。

  • 然后我画出了“假”和“真”文章中最常见的词。为此,请进入功能->文本分析->信息检索->常用术语。对于我得到的“真实”文章:

对于我得到的“假”文章:

再次非常类似于我们在 Python 部分得到的。

  • 对于 ML 部分,让我们从随机森林分类器开始。我进入函数->文本分析->文本分类->随机森林分类(Py)配置(选择“目标”和“语料库”变量):

这将标记化,然后使用 TF-IDF 作为加权度量。这是结果:

您将获得一个新列,其中包含您的模型的结果。很简单。如果您想获得 Python 或其他地方的指标,现在可以下载带有模型的最终数据集。同样的过程也可用于其他型号,如:

  • 决策树分类
  • SVM 分类
  • 高斯朴素贝叶斯分类

还有更多!您甚至可以将这些模型与比较文本分类模型进行比较。此外,您可以测试其他模型,如情感分析、文本聚类、Word2Vec 等等。

结论

文本分析和自然语言处理可以用来解决假新闻这个非常重要的问题。我们已经看到了它们对人们的观点以及这个世界思考或看待一个话题的方式所能产生的巨大影响。

我们使用样本数据建立了一个机器学习模型来检测虚假文章,但这个过程与检测虚假推文或类似的事情非常相似。你首先需要收集数据,如果你对如何用 twitter 做这件事感兴趣,我去年写了一篇文章:

[## 使用 Spark、Optimus 和 Twint 在几分钟内使用 NLP 分析推文

社交媒体是研究人们交流和行为方式的黄金,在这篇文章中,我将向你展示…

towardsdatascience.com](/analyzing-tweets-with-nlp-in-minutes-with-spark-optimus-and-twint-a0c96084995f)

我们还看到,用 Python 构建模型很简单,如果你知道如何编码,我认为我们都应该学习,但如果你不知道,像 TreasureHunt LEAPS 这样的*台可以帮助你不费吹灰之力就解决问题,而且还是免费的!您甚至可以与他人分享您解决的问题和内置代码,进行协作、学习等等

感谢您阅读本文,希望它能对您当前的工作或调查以及对数据科学的理解有所帮助。

用深度学习检测假新闻

原文:https://towardsdatascience.com/detecting-fake-news-with-deep-learning-7505874d6ac5?source=collection_archive---------37-----------------------

用 Keras 实现简单的 LSTM

图片来自 Pixabaymemyselfaneye

我一直想做一个涉及文本分类的小项目,并决定尝试一种我以前没有使用过的架构:长短期记忆(LSTM)。简而言之:LSTM 氏症是一种循环神经网络(RNN),能够长时间记忆信息(这是一种优于香草 RNN 的优势)。如果你想了解更多的细节:这里有一个关于 LSTM 建筑的精彩而详尽的解释。

好吧,让我们开始吧!

我在 Kaggle 上找到了一个真假新闻的数据集:真假新闻数据集。我试着在 Jupyter 笔记本上本地做这件事,但是一旦我到了训练部分,我的电脑几乎爆炸了——一个时期的 ETA 至少是 2 个小时。我把东西转移到一个 GPU 加速的 Google Colab 实例中,事情变得更加顺利。这里是查看笔记本的链接。

# load datasets into a panda's dataframe
real = pd.read_csv('data/True.csv')
fake = pd.read_csv('data/Fake.csv')

现在让我们看看数据是什么样子的。

“真实”数据集

“假新闻”数据集

real.head()fake.head()

我立即注意到的一件事是真实新闻文章中的“(路透社)”标签。事实证明,几乎所有的真实故事都来自路透社,几乎没有任何假新闻包含这个词。我想最终比较有单词和没有单词的模型。

real.loc[real.text.str.contains('Reuters')].count()/real.count()
> title      0.998179
> text       0.998179
> subject    0.998179
> date       0.998179fake.loc[fake.text.str.contains('Reuters')].count()/fake.count()
> title      0.013247
> text       0.013247
> subject    0.013247
> date       0.013247

现在,让我们给出数据标签,并将它们组合成一个数据集进行训练,然后对它们进行训练/测试拆分。

# Give labels to data before combining
fake['fake'] = 1
real['fake'] = 0
combined = pd.concat([fake, real])## train/test split the text data and labels
features = combined['text']
labels = combined['fake']X_train, X_test, y_train, y_test = train_test_split(features, labels, random_state = 42)

现在我们用 Keras 中的 Tokenizer 对象处理文本数据。我们不会删除停用词,因为每个词的上下文以及句子和段落的构成都很重要。我认为这两个班级的写作质量存在潜在的差异。路透社的记者居然有文字编辑!

# the model will remember only the top 2000 most common words
max_words = 2000
max_len = 400token = Tokenizer(num_words=max_words, lower=True, split=' ')
token.fit_on_texts(X_train.values)
sequences = token.texts_to_sequences(X_train.values)
train_sequences_padded = pad_sequences(sequences, maxlen=max_len)

现在让我们建立模型!

embed_dim = 50
lstm_out = 64
batch_size = 32model = Sequential()
model.add(Embedding(max_words, embed_dim, input_length = max_len))
model.add(LSTM(lstm_out))
model.add(Dense(256))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1, name='out_layer'))
model.add(Activation('sigmoid'))model.compile(loss = 'binary_crossentropy', optimizer='adam',\
               metrics = ['accuracy'])print(model.summary())

现在我们来训练模型。

model.fit(train_sequences_padded, y_train, batch_size=batch_size, epochs = 5, validation_split=0.2)

基于训练数据的 LSTM 模型训练进展

现在让我们评估一下测试/维持集。

test_sequences = token.texts_to_sequences(X_test)test_sequences_padded = pad_sequences(test_sequences,\ 
                                       maxlen=max_len)

非常非常好。

绘制模型的准确性和损失表明,它可能仍然需要更多的训练,因为没有过度拟合的证据。

99%是一个很好的结果,但是,记住所有的真实新闻都有“路透社”在里面?假设它只是一个单词,我想看看从文本中删除它会如何影响模型的性能(如果有的话)。我认为在单词选择和编辑方面一定有很多其他潜在的模式,可能会使模型的分类变得容易。

从所有新闻文本中删除“Reuters”后,最终模型的测试集评估准确率为 98.5%。因此,其预测能力略有下降(0.6%的差异)。我还以为会更多。

获得这样一个几乎现成的好结果应该会让您更多地考虑底层数据。如果它好得令人难以置信,它很可能就是真的!路透社的新闻故事依赖于风格指南,并经过严格编辑,我不能说假新闻也是如此。这些潜在的模式可能允许模型从这个特定的数据集学习,但是它如何推广到从不同来源在野外发现的新闻呢

我在 2019 年脸书上查看最多的假新闻文章上找到了一篇商业内幕文章。很难找到其中一些例子的全文。

对于第五个名为“奥马尔与恐怖组织伊斯兰团体举行秘密筹款活动”的分享故事,该模型预测其为真实

对于标题为“的#1 分享故事,特朗普的祖父是一名皮条客和逃税者;他的父亲是三 k 党成员,模型预测它为假新闻

我还在 CNN 上抢到了当前的头条新闻,“ 特朗普将联邦社交距离准则延长至 4 月 30 日 ”,模型预测为真实

结论

该模型似乎是训练和测试数据集上的一个非常强大的预测器,但是它可能不会在此之外进行很好的推广。当出现一个不符合设定的假新闻故事时,模型是 1 对 2。这个样本规模很小,我想尝试追踪更多数据集之外的假新闻,看看它的表现如何。我也想尝试更多的艺术模式(埃尔莫/伯特)。希望你喜欢阅读!

在 Luckin Coffee 的收益电话会议记录中发现欺诈

原文:https://towardsdatascience.com/detecting-fraud-in-luckin-coffees-earnings-call-transcripts-7940b1f133df?source=collection_archive---------61-----------------------

本文使用自然语言处理技术来检测受会计丑闻困扰的中国咖啡连锁店的欺诈行为。

Ashkan Forouzani 在 Unsplash 上的照片

2020 年初,Luckin Coffee 在首席执行官承认在公司 2019 年的盈利报告中夸大会计数字后,从纳斯达克证券交易所退市。

Luckin Coffee 曾被誉为星巴克在中国咖啡市场的最大竞争对手,被指控在 2019 年捏造销售收入。尽管丑闻花了一些时间才被曝光,但它启发我开始思考通过文字检测欺诈的可能性。

本文重点介绍了将自然语言处理技术应用于 2019 年第二季度和第三季度的 Luckin Coffee 收入电话。我们将努力寻找有价值的花絮并回答这些问题

我们能在管理层的言辞和语气中找到欺诈的暗示吗?

通过文本挖掘技术,我们是否也能快速有效地发现某个商业模式陷入困境或不可持续?

关于数据集

我通过 Luckin Coffee 的官网下载了它的收入通话记录。机器人流程自动化工具用于将 pdf 文本提取到 r。

本文中用于分析的 CSV 文件的快照

清理和浏览数据集

像任何数据科学项目一样,我们需要了解我们的数据集并清理它。由于这是一个相对较小的数据集,我只删除了常见的停用词,所以我们仍然有足够的数据用于分析。

删除停用词前后的字数

Luckin Coffee 的赚话费谁说的最多?

首先,我们来看一下 Luckin Coffee 财报电话会议中与会者的发言字数。正如预期的那样,首席财务官和首席执行官在电话会议上与观众分享了最多的内容。

在 Luckin Coffee 收入电话中发言字数排名前 10 位的参与者

想象每个参与者的极性

情感分析帮助我们提取一个人对某个主题的观点,无论是积极的还是消极的。在这一部分中,我们试图找出 Luckin Coffee 的收入电话中每个参与者的情绪。

下面的图表通过持续时间和频率显示了每个参与者的极性。消极词汇被分配较低的分数(消极分数),反之,积极词汇获得较高的极性分数。

请注意,下面的第二张图表显示,Luckin Coffee 的首席执行官、首席财务官和董事长在收入电话会议中使用了许多积极的词语。

Luckin Coffee 收入电话中每个人的极性。

咖啡还是茶?—分析 Luckin Coffee 收入电话中最常用的单词/短语

最流行的文本挖掘技术之一是找出特定单词在数据集中出现的频率。在本节中,我们将使用词频来分析 Luckin Coffee 的商业模式。

基于 Luckin Coffee 收入呼叫的二元条形图

根据上面的双字频率条形图,我们可以对该公司的业务模式做出一些假设:

  • 咖啡和茶为主要产品 : Luckin Coffee 一直标榜自己是星巴克在中国咖啡市场的竞争对手。除了咖啡产品,该公司还积极尝试渗透到中国的茶叶市场。
  • 注重赢得顾客的忠诚度:“保留率”和“营销费用”这两个词表明,Luckin coffee 正在花费大量的营销费用来赢得中国饮料市场份额。
  • 向中国特定城市扩张:中国有一个城市等级体系,每个城市属于一个特定的等级。例如,北京和上海是一线城市。我们可以假设 Luckin Coffee 正在将其商店网点扩展到特定级别的城市。
  • 利用合作模式获得更多客户:有趣的是,“合作模式”一词成为收入电话中最热门的双字母词之一。我们还可以假设 Luckin Coffee(计划)通过合作关系发展业务,以获得更多客户和/或扩大其商店的位置。

词频让我们了解一个主题的主题。接下来我们看单词网络图来看构成本题内容的单词。

词网络图:Luckin Coffee 的价值主张和通过合作模式增加的增长

下图显示了在收入电话中经常一起出现在一个句子中的单词。下图突出了三个主题。

词网络图——句内共现

  1. Luckin Coffee 的价值定位主要集中在以实惠/有效的价格销售,同时在便利的位置保持其质量
  2. 为了实现这一价值主张,Luckin Coffee 瞄准中国租金可能更低的低线城市是有意义的
  3. 在公司内部建立伙伴关系模式的目标是在不同的地点获得更多的客户

通过以上发现,我们可以怀疑 Luckin Coffee 的收入报告中捏造的销售数字可能是由于其与其他方的合作关系管理不善。

快速开设新店——分析最常用的情感词汇/短语

除了找出每个参与者在赚钱电话中的极性,我们还可以将单词标记为特定的情绪,然后进行单词计数。在我们的例子中,我们将查看 Luckin Coffee 的首席执行官(在捏造的销售调查中终止)和首席财务官的情绪词频。

总的来说,这位首席执行官在两次盈利电话中使用了“商店”一词约 25 次(在积极和预期类别中)。第二和第三个经常提到的词是‘伙伴关系’(约 6 次),和‘需求’(约 5 次)。注意第一个单词和第二个单词之间有很大的差距。这可能是一个信号,表明 Luckin Coffee 如此专注于其扩张计划,以至于该公司忽视了客户想要的产品吗?

情感词频柱状图——luck in Coffee 的 CEO

至于首席财务官和首席社会官,“商店”一词也被提到了* 40 次,负面和悲伤类别中的“较低”也被提到了约 15 次。这些发现可能表明,2019 年的大部分金融行动都是为了在中国扩张门店。

情感词频柱状图——luck in Coffee 的 CFO & CSO

接下来,我们还可以通过 CFO & CSO 所说的话来看看出现在“lower”前后的单词。

出现在“下级”前后的词— CFO 和 CSO

我们注意到“低”这个词与城市等级和租金相关。低线城市的人口规模和收入水*通常较低。因此,这些城市的租金也低于北京等一二线城市。这些发现表明,Luckin Coffee 的目标是在中国的低线城市开设更多门店。

自动售货机和中东咖啡市场——从盈利电话中提取关键词。

另一种流行的文本挖掘技术是通过数据科学的视角从文档中提取关键词。在我们的例子中,我使用udpipe R 包中的 RAPID 和 PMI 函数从收入调用中获得关键字。

快速是指快速自动提取关键词。RAPID 算法试图通过分析单词的频率和共现来确定文本数据中的关键短语。

RAKE 方法确定的关键字条形图

PMI 指的是逐点互信息,寻找成对的词的搭配顺序。该算法将尝试识别比预期更频繁地同现的单词序列。

通过 PMI 方法识别的关键字条形图

RAKE 关键字提取方法产生类似于词频技术的结果。另一方面,PMI 方法提供了更多见解,包括:

  • Luckin Coffee 与其他方有风险投资协议(也许是 Louis Dreyfus?)
  • 除了打入中国的咖啡市场,Luckin Coffee 也在关注中东市场。
  • Luckin Coffee 已经/可能计划通过自动售货机出售他们的饮料。

结论

简而言之,我们能够通过文本分析探索 Luckin Coffee 的商业模式。有几点可能暗示该公司存在欺诈行为。

首先,管理层极度关注供应方面——开设新店。虽然该公司解释了其需求战略——通过合作模式留住客户,但在财报电话会议上并没有过多提及“需求”、“客户偏好”等词。

第二,Luckin Coffee 盈利报告中捏造的销售数字可能是因为该公司对外部零售方的管理不善。自 2019 年年中/年底以来,Luckin Coffee 一直在中国日报开设新店。雷鸣般的扩张速度可能导致管理层失去了管理和与合作伙伴合作的能力。

最后,Luckin Coffee 计划渗透到中国的咖啡和茶市场。看看捏造的销售是否与其新推出的茶产品有关,这将是很有趣的。

用机器学习探测系外行星的可居住性

原文:https://towardsdatascience.com/detecting-habitability-of-exoplanets-with-machine-learning-b28c2d825760?source=collection_archive---------29-----------------------

“宇宙是一个相当大的地方。如果只有我们,这似乎是对空间的极大浪费。”卡尔·萨甘

山姆拍摄的照片🐷 on Unsplash

我们大多数人都想知道在我们的星球之外有生命吗?对我们的祖先来说,我们似乎首先是孤独的,但当我们检查星星时,我们意识到这是一个相当大的宇宙。然后我们开始问地外文明是否存在,它们在哪里?我们把这个问题称为费米悖论。它陈述了缺乏地外文明证据和对其概率的各种高估计之间的矛盾。

但是,正如卡尔·萨根所说:“缺乏证据并不是不存在的证据。”所以我们正在寻找外星人在哪里,或者他们是否存在的问题。
系外行星研究的主要工作领域之一就是找到这个问题的答案。在不同的恒星系统中寻找可能适合居住的行星是系外行星研究的主要目标之一。到目前为止,我们已经发现了 60 颗可居住的系外行星,我们将继续寻找更多的系外行星。

照片由 Alazar KassahunUnsplash 上拍摄

所以,我决定开发一个机器学习项目来预测这些可居住的行星。通过进入这个项目,我提取了两个数据集:美国宇航局系外行星档案和 PHL 的可居住系外行星目录。

数据知识

因此,有两个数据集需要处理: Nasa 系外行星档案和 PL 数据,其中包含可居住性情况。我从美国宇航局获得的数据集是我的中心数据集,因为它有更多的恒星和行星的特征,例如;行星半径、恒星温度、轨道周期等等。我需要 PHL 的数据来使用可居住性功能。下图显示了目标特征的分布,这意味着可居住性。如您所见,我有一个不*衡的数据集,我将在下面的部分中处理它。

目标特征的分布。作者图片

方法学

本项目遵循的方法是:

  1. 预处理和数据合并
  2. 处理缺失数据
  3. 探索性数据分析
  4. 机器学习模型的数据准备
  5. 定义模型
  6. 评估和优化

天文数据集通常会有很多缺失值,我的情况也是如此。因此,我从清除这些丢失的值开始。

作者图片

这张图片显示了我丢失了多少价值。很明显,是很多。所以,我按照以下步骤来解决我的问题:

  • 我删除了丢失数据超过 40%的列。
# remove columns with more than 40% missing data
def remove_missing(f):
    count = len(planets[planets[f].isnull()])
    if count/len(planets) > 0.4:
        return 1
    else:
        return 0

missing_values = [x for x in planets.columns if remove_missing(x)]
planets = planets.drop(missing_values, axis=1)
  • 我删除了具有十个以上唯一值的分类特征。
# remove categorical features with more than 10 unique values
cols = [x for x in planets.columns if x not in planets._get_numeric_data().columns]
for i in cols:
    if(len(planets[i].unique()) > 10):
        planets = planets.drop(i, axis=1)
  • 对剩余分类特征的处理。
  • 数值的迭代计算。
# IterativeImputer
# get only numeric values
numeric_values = planets[planets._get_numeric_data().columns]
imp = IterativeImputer(RandomForestRegressor(), max_iter=10, random_state=76)
numeric_values = pd.DataFrame(imp.fit_transform(numeric_values), columns=numeric_values.columns)
numeric_values.to_csv('Imputed Data.csv', index='rowid')

在下面的步骤之后,我得到了一个包含 131 个条目的干净数据集,并继续进行合并过程。

合并数据集

正如我之前所说的,我有两个项目数据集,所以我需要将它们结合起来,以便在机器学习模型中使用。除了可居住性,我的所有特征都在美国宇航局的系外行星档案中。因此,我把它从 PHL 数据集中拿了出来,放在中央数据集中。

#drop not-habitable planets
phl = phl[phl.P_HABITABLE != 0]#create habitable column for planets data with the help of phl #dataframe
#get names of planets
habitable_planets = phl.P_NAME.values
planets['habitable'] = planets['pl_name'].isin(habitable_planets

质量-温度-可居住性关系。作者图片

走向机器学习

我完成了清理和合并过程,但仍有工作要做。我应该做一些准备步骤,为机器学习模型准备数据。我仍然有这么多的功能,我不想从模型中得到过度拟合的结果。此外,我必须解决不*衡的问题。因此,我按照以下步骤编写了一些数据准备方法:

  • 丢弃低相关性要素&为模型数据集选择高相关性要素。
  • 经过一些研究,我决定将这些特征添加到模型的数据集中:行星质量、行星径向速度振幅[m/s]、*衡温度[K]、行星半径[地球半径]和轨道周期[天]。但是,由于缺失值问题,我只有行星半径和轨道周期。
  • 标准化和对数变换。
  • SMOTE —过采样。
#Selecting highly correlated features
unrelevant_features = corr_df[corr_df['habitable'] <= 0.09]to_drop = [column for column in unrelevant_features.index]
planets_c.drop(planets_c[to_drop[:97]], axis=1, inplace=True)planets_c[['pl_rade', 'pl_orbper']] = planets[['pl_rade', 'pl_orbper']]# log transformation to decrease the effect of the outliers
log_cols = ['gaia_plx', 'st_pm', 'gaia_pm', 'st_teff', 'pl_rade', 'pl_orbper']
planets_c[log_cols] = (planets_c[log_cols]+1).transform(np.log)
norm_cols = ['st_pmdec', 'gaia_pmdec']
planets_c[norm_cols] = preprocessing.normalize(planets_c[norm_cols])

嗯,我现在可以开始定义分类模型了。我从探索基本模型开始:KNN、逻辑回归、朴素贝叶斯、线性 SVC 和决策树。然后,集合模型就像:随机森林、AdaBoost、GradientBoosting 和 XGBoost。结果如下:

图片作者。

首先,行星半径和轨道周期特征不在模型数据集中。没有这些功能,我得到的最好的 F1 分数只有 54%,所以他们对结果做出了相当大的贡献。从特征重要度表也可以看出。

图片作者。

线性 SVC 是召回分数方面第二成功的模型。因此,我想比较他们的混淆矩阵:

作者图片。

最后的想法

  • 像行星半径、轨道天数、恒星表面重力和恒星表面温度这样的特征对模型有重大影响。
  • 机器学习算法在寻找可能的宜居行星方面做得很好,即使没有化学性质。
  • XGBoost 在任务上真的很成功。这个模型预测了所有的系外行星,除了一个。
  • 作为进一步的工作,我的目标是通过在学术论文上的 NLP 工作找到可居住性的相关特征。我还打算开发一个 flask 应用程序。

“以非常不同的方式,宇宙充满生命的可能性和我们完全孤独的相反可能性同样令人兴奋。不管怎样,对我来说,想更多地了解宇宙的欲望是不可抗拒的,我无法想象任何真正富有诗意的人会不同意。”理查德·道金斯

此外,如果你想了解更多,也可以看看我的 Github 简介!

用 CNN 检测白血病

原文:https://towardsdatascience.com/detecting-leukemia-with-a-cnn-af699b19ab99?source=collection_archive---------51-----------------------

机器学习

CNN 能可靠地识别癌细胞吗?

急性淋巴细胞白血病(ALL)是最常见的儿童癌症,也是 20 岁前癌症死亡的最常见原因。在 20 世纪 60 年代,所有人的存活率只有 10%,但诊断测试的进步和化疗的改进已经将发达国家的存活率提高到 90%。[ 1

图片承蒙波维切维斯基昂斯佩什

研究人员正在尝试各种个性化的方法,主要是利用表观遗传学筛查和全基因组关联研究(GWAS)来确定潜在的抑制目标,以进一步提高存活率。[ 23 ]大约 80%的病例是儿童,但是,正如 Terwilliger 和 Abdul-Hay 所指出的,50 岁是所有发病率的另一个高峰,老年患者的长期缓解率低于儿童,约为 30-40%。[ 3

ALL 被描述为骨髓中淋巴细胞的增殖和分化。重要的细胞过程,如淋巴细胞分化的调节、细胞周期调节、生长因子和肿瘤抑制受体信号传导以及表观遗传修饰,被扰乱。此外,约三分之一的病例存在染色体易位。这可以通过将癌基因重新定位到活跃转录区域而导致癌基因的过度表达,或者通过将肿瘤抑制基因重新定位到基因组的非转录区域而导致肿瘤抑制基因的低表达。[ 13 ] ALL 通常是多克隆的,这进一步使治疗复杂化,因为许多亚群将可能对任何一种治疗产生抗性。 1

所有细胞形态

所有的都可以分成 3 个不同的亚型,这使得鉴别变得困难,即使对于有经验的从业者也是如此。L1 小而均一,圆形,无裂口,无明显的核仁或液泡。这些细胞最有可能成为正常的淋巴母细胞。L2 较大且不均匀,形状不规则,常开裂,并有明确的核仁和液泡。L3 具有 L1 的形状,但有明显的核仁和液泡。[ 45

照片由詹姆斯·格雷利尔在维基媒体上发布— CC BY-SA 3.0

数据收集

该数据由 10,000 多张单细胞显微术急性淋巴母细胞白血病和正常淋巴母细胞的图像组成,分类失衡约为 2:1,全部正常。在没有使用所有图像的情况下,有了足够的图像和计算资源,我决定对正的所有类进行下采样,以管理类不*衡。因此,用 4000 幅图像以 57:43 的类别不*衡完成了训练。

图像是存储为的 450x450 RGB 图像。bmp 文件,一种光栅图形位图,将图像存储为 2D 矩阵。

数据可以在这里找到。它来源于阿肯色医学科学大学(UAMS)对所有显微镜的研究。

探索性数据分析

这是我们组中的一些正常细胞。我们看到球形、未分裂的细胞,染色质均一,几乎没有液泡。

作者照片。

这是我们集合中一些 ALL 细胞。我们看到不规则形状的分裂细胞,有异质的染色质和多个核仁和液泡。

作者照片。

*均图像

查看每一类的*均图像,我们看到细胞内部有太多的变化,无法识别有意义的差异,但我们清楚地看到,所有细胞*均比正常细胞大得多。这并不奇怪,因为癌细胞的生长不受控制。

作者照片。

建模

用 Paul Breton 的这个 post 和对应的 GitHubrepo来指导 Sagemaker 使用 Keras。

我在 AWS Sagemaker 中使用了 Keras 框架,在 Model_Scripts 目录中的一个单独的 Python 脚本中指定了神经网络架构和编译超参数。训练是在 time 大型笔记本实例中完成的,允许在易处理的训练时间内完成数百个时期。

我采用了基于 CRISP-DM 过程的迭代方法来建模。预测多数类的虚拟分类器具有 57%的准确度。我创建了一个普通的模型,有一个 Conv2D 层和一个致密层,准确率为 68%,已经比虚拟模型好了。然后,我通过添加额外的 Conv2D 层和由 MaxPooling 层分隔的层块,创建了更大、更复杂的体系结构。

最复杂的模型在 3 层的 3 个块中有 9 个卷积,但这不是最成功的模型,因为它似乎过度拟合了我们的训练数据。很明显,深而窄的块比宽的块获得了更高的指标。最好的模型是一个 2x2x1x1 结构,总共有 6 个回旋。在 MaxPooling 和 Dense 图层之后添加了 MaxPooling 图层和 Batch Normalization 图层,以防止过度拟合,但最终模型中没有这些图层。

我尝试使用召回率作为模型选择的辅助指标,但是这将模型推至总是选择所有图像,并将模型精度推至虚拟分类器。因此,我决定放弃回忆,专注于准确性。由于召回率如此之高且牺牲了准确性,该模型作为一种工具将毫无用处,因为无论如何,所有图像都必须由人类医生进行检查,这就否定了该模型的益处。

最终网络架构

作者照片。

模型编译超参数

我使用二进制交叉熵作为损失函数,因为这是一个二进制分类问题,RMSprop 和 Adam 用于优化。学习率设置为 0.001,衰减为 0.0001。

模型部署

使用 AWS 端点部署了性能最佳的模型,以便从测试集中加载尚未看到的图像,从而生成预测。部署位于我的 GitHub 中模型训练下的 003_Modeling_AWS 笔记本中。

错误分类的图像

在这里,我们看到一个模型误归类为正常的图像,而它实际上是所有。该模型显然是对缺乏内部空泡和分裂以及致密染色质作出反应,以归类为正常。不规则的形状应该表明这是所有。

作者照片。

在这里,我们看到一个图像,该模型误归类为所有,而它实际上是正常的。该模型可能会对不规则的细胞轮廓以及内部较亮的不均一区域做出反应,这些区域表明存在空泡或未包装的染色质,从而将其归类为 ALL。这绝对是一个具有挑战性的细胞正确排序。

作者照片。

见解和建议

该模型达到了 84%的准确率,使其成为在新病例中识别 ALL 的有用工具。由于血液样本显微镜检查已经是所有人的默认诊断测试,该模型可以很容易地用于验证人类医生或标记该模型没有信心进行进一步审查的病例。即使对人类来说,诊断 ALL 也是困难的,因此拥有一个健壮、准确的验证模型可以提高诊断的速度和准确性。由于 ALL 是一种急性白血病,因此早期确诊尤为重要,如果不治疗,它可能在几周或几个月内死亡。

后续步骤

模型改进

这种模式有几个潜在的改进途径。我尝试使用 Adam optimizer,它为 RMSprop 计算的梯度增加了动量和偏差校正的感觉,并使用批量标准化来提高模型性能,尽管它迄今为止确实有助于建模。我还可以实现早期停止和模型检查点,通过允许模型在达到过度拟合阈值时停止训练来对抗过度拟合。我尝试了几个层次的辍学,定在 25%,但进一步的调查可能会产生更好的结果。

产品改进

模型的可解释性通常与模型的准确性同等重要,甚至更重要,尤其是对于医学诊断需求而言。在现实世界的应用中,医生能够看到为什么模型已经达到某个决定是非常重要的。为此,建立一个图像分割模型来识别和标记重要的特征,如图像中空洞、非球形细胞或切割边缘的存在和数量,可以大大提高模型的可用性。此外,部署模型并允许新图像的实时集成将使模型保持最新。

连接

这是这个项目的 GitHub repo。你可以在 LinkedInTwitter 上与我联系,或者访问我的网站获取更多文章。

来源

[1] S.P. Hunger 和 C.G. Mullighan,儿童急性淋巴细胞白血病。2015.新英格兰医学杂志 373(16):1541–1552。

2 C.H. Pui,J.J. Yang,S.P. Hunger 等,儿童急性淋巴细胞白血病:通过合作取得进展。2015.临床肿瘤学 33(27):2938–2948。

[3] T. Terwilliger 和 M. Abdul-Hay,急性淋巴细胞白血病:综合综述和 2017 年更新。2017.血癌杂志 7:1–12。

[4] M.M. Amin,S. Kermani,a .塔莱比和 M.G. Oghli,使用 K-Means 聚类和支持向量机分类器识别显微图像中的急性淋巴细胞白血病细胞。2015.医学信号与传感器杂志 5(1):49–58。

[5] F. Scotti,外周血显微镜图像中急性白血病识别的自动形态学分析。2005.测量系统计算智能会议。

使用计算机视觉检测车牌

原文:https://towardsdatascience.com/detecting-license-plates-using-computer-vision-87b2f6d3e56e?source=collection_archive---------37-----------------------

给定汽车的图像和视频,计算机视觉将被用来找出车牌的样子以及如何检测车牌。

来自 Unsplash 的 Damir Kopezhanov 的 Phtot

计算机视觉是一个不同于任何其他领域的数据科学领域。他们不是处理数据集,而是处理图像。与神经网络试图像人脑一样处理数据一样,计算机视觉试图以人类视觉的方式来查看、识别和处理图像。

在本文中,我们将检测计算机视觉最常用的案例之一,检测车牌。它们很明显,很容易辨认,这使得它们很容易被计算机拾取和识别。但是首先我们要让电脑知道是什么让车牌成为车牌。

级联分类

我们告诉电脑车牌是什么样子的方法是,我们给它几百个车牌样本,以及不是车牌图像的样本。然后在这些例子上训练一个分类器,如果输入图像包含牌照,它将输出 1,否则输出 0。

级联分类的不同分类器

级联分类被用作分类器,因为它由几个更简单的分类器(阶段)组成,这些分类器随后被应用于感兴趣的区域,直到在某个阶段候选被拒绝或者所有阶段都通过。这些简单的分类器检测车牌的边缘、车牌中的线条和周围的特征。如果在输入图像中不能检测到这些分类器中的一个或多个,它将拒绝该图像并声明没有牌照。但是如果可以找到所有这些特征,它会将图像分类为其中有牌照。

特征匹配

为了让您了解级联分类的作用,我将向您展示一个特征匹配的示例。特征匹配从两幅图像中找到相应的特征。

下面是一张汽车牌照和车尾的照片。特征匹配要做的是找到与汽车后部图像中的特征相对应的车牌特征。

特征匹配的输出

上面的图像是匹配两幅图像的特征的输出。这些线条显示了两幅图像中的共同特征。正如我们所见,几乎所有的线路都连接到汽车后面的牌照上。这基本上就是级联分类器的工作方式,以及它如何检测图像中的车牌。

结果呢

在我们对图像应用级联分类之后,如果检测到牌照,它将返回在图像中发现它的位置的 x,y 位置以及牌照的宽度和高度。现在我们已经有了图像中显示车牌位置的点,我们可以在图像上绘制一个围绕它的矩形。使用 OpenCV(一个计算机视觉库),它有一个功能,我们可以在给定的图像上绘制矩形,它所需要的只是应该绘制的点。

因此,从级联分类器输出的 x,y,宽度和高度,我们可以改变这个图像…

原象

o…

检测到牌照,现在它周围有一个红色框

但是有了这些点,我们可以做更多的应用。我们能做的实际上是模糊车牌。这在现实世界中经常使用,因为显示汽车的电视网络在没有他们的批准下不能合法地显示某人的车牌。所以他们模糊了车牌,这样就没人能看到了。类似于绘制矩形,OpenCv 有一个函数,给定一组点,它将在该位置模糊图像。

所以我们的原始图像变得模糊,现在看起来像这样…

牌照模糊后,就再也看不清楚了

检测视频中的车牌

为了理解我们如何做到这一点,我们必须了解什么真正构成了一个视频。视频本质上只是连续放置的帧,以感知某物在移动。你可以把它想象成一本动画书,当书被翻动时,图画看起来会移动,即使只是图像一次改变一点点。构成视频的这些帧只是被轻微改变的图像。因此,就像我们对上面的图像所做的那样,我们要做的就是对给定视频中的每一帧应用相同的分类器。如果该框架有一个牌照,一个红色的矩形将被放置在它的周围。

将要使用的视频是在高速公路上行驶的汽车。为了展示计算机视觉的更多应用,我们不仅要检测下面视频中的汽车牌照,还要放大牌照并显示在每个牌照被检测到的地方。

注意:不要指望分类器会提取视频中的每一个车牌。你会发现,当一辆车离得太远时,它就不会认出那个车牌,因为车牌的特征开始变得不太清楚,无法通过分类器。

视频中的计算机视觉

结论

计算机视觉不同于其他任何视觉。这是一个不断发展的领域,数据科学家和工程师正在寻找新的方法来创建有影响力的可视化。上面的例子是为了给那些不知道什么是计算机视觉的人一个介绍,并让他们了解计算机视觉的发展方向。希望这能激励你更多地了解这个迷人的领域,就像它激励我做这个项目一样。

如果你感兴趣,这个项目的代码可以在我的 GitHub 上找到:https://GitHub . com/zita 9999/License-Plates-and-Computer-Vision/tree/master

参考

[1] K .穆拉塔列夫,白色轿车,【https://unsplash.com/photos/3Gg-98LaCxE

2 G .比亚尔基,黑色奔驰,【https://unsplash.com/s/photos/pennsilvania-licenseplates

[3]4k 都市生活,https://beautifulwashington.com/汽车驾驶放松视频,

[4] OpenCV,级联分类,https://docs . OpenCV . org/2.4/modules/obj detect/doc/Cascade _ class ification . html

利用迁移学习检测疟疾

原文:https://towardsdatascience.com/detecting-malaria-using-transfer-learning-fab5e1810a88?source=collection_archive---------42-----------------------

使用机器学习和显微血液图像来检测疟疾

描述如何开发诊断疟疾的 ML 程序的视频。

弗朗切斯科·帕尔马和艾萨克·罗萨写的

在本文中,我们将首先描述疟疾是如何工作的,如何诊断这种疾病,以及它固有的问题。然后我们将讨论用于借助血液样本检测疟疾的 ML 模型及其性能结果。

疟疾是人类已知的最致命的寄生虫相关疾病之一。自从人类出现在地球上,它就一直存在,而且肯定会长期存在。

2018 年,有 2.28 亿人感染,405,000 人死亡,这是一个重大的健康问题。

非洲是所有疟疾病例的 94%(2018),但它也在中国南方流行,几乎存在于所有大陆。由于疟疾主要袭击非洲国家,遏制和有效抗击这种寄生虫变得更加困难。事实上,疟疾肆虐的发展中国家并不总是拥有适当的资源来降低其对疟疾的脆弱性。

据估计,受疟疾影响的国家每年损失 120 亿美元,这是由于许多公民在疟疾大爆发期间无法工作、高昂的医疗费用以及对旅游业的不利影响。加上大约 27 亿美元的人道主义援助,毫无疑问,疟疾对受影响国家的经济产生了巨大的负面影响。

疟疾,是什么?

疟疾实际上只是这种疾病的名称。它是由一种单细胞原生动物寄生虫引起的,这种寄生虫的属名是疟原虫。

疟原虫包括各种各样的寄生虫,大约有 200 种,但只有少数几种能污染人类。因为它们是寄生虫,所以它们利用几种宿主来进食和繁殖。

5 种疟原虫寄生虫能成功寄生人类并对人类有害,迟缓疟原虫、间日疟原虫、卵形疟原虫、三日疟原虫、诺氏疟原虫 (P 代表疟原虫)。虽然引用的所有 5 个物种都可能导致疟疾,但通常致命并导致严重疟疾的是弱毒疟原虫

引起疟原虫的两种不同类型的疟疾,来源:https://microbenotes . com/differences-between-plasmodium-vivax-and-plasmodium-falciparum/

与其他类型的寄生虫相比,这些寄生虫的生命周期相当简单,因为它们只有两个宿主,即蚊子和人类。

这种寄生虫的生命始于蚊子的肠道,经过一个繁殖阶段后,它们转移到昆虫的唾液腺。当蚊子以人类为食吸血时,疟原虫进入了人类的血流中。感染后,它们首先进入肝脏并经历增殖期。一旦成熟并达到更高的数量,它们就会离开肝脏,进入红细胞。

此时,寄生虫将不断繁殖,直到身体能够有效地对抗感染。一些疟原虫将分化成有性卵样细胞,并在人类血液中自由流动,直到蚊子再次进食并吃掉它们。一旦再次进入蚊子的内脏,雄性卵样细胞将使雌性受精,循环可以再次开始。

疟原虫的生命周期,来源:https://sk.pinterest.com/pin/706220785288117948/

疟疾发烧通常发生在疟原虫大量冲出红细胞时,并引发免疫反应,如高烧、呕吐、恶心和头痛。由于许多红细胞被溶解,在某些情况下还会导致贫血,这种贫血会导致多种器官衰竭和代谢性酸中毒。

有效对抗寄生虫的最好方法在于预防胜于一切。这包括晚上睡觉时使用驱蚊剂和驱虫蚊帐。一些高风险地区也用杀虫剂熏制,以避免有太多的蚊子。

一旦感染,有几种药物存在,但这种药物必须非常迅速地给药,以避免对个体的严重伤害甚至死亡。

这种寄生虫的一个大问题,也可能是它仍然存在的主要原因之一,是它能够迅速进化并对它遇到的药物产生耐药性。随着蚊子对杀虫剂产生抗药性,抗击疟疾变得更加困难。此外,发展中国家的不卫生条件,尤其是撒哈拉以南非洲,是理想的蚊子滋生地,尤其是在雨季,昆虫有许多水坑产卵。

避免疟疾严重并发症的最有效方法是快速诊断。这样既能避免死亡,又能遏制寄生虫,以免感染更多人。

检测疟疾感染最常见的方法是进行显微镜血液分析。这不需要一套复杂的技能,但是,基本的医学知识是必不可少的。问题是,在发展中国家,适当的医疗材料和人员并不总是容易获得,使得这种诊断慢于预期,如果不是不存在的话。

另一个主要问题是,当资源可用时,有高估感染人数的趋势。许多研究表明,存在严重的过度诊断问题(某些农村卫生中心高达 98%的错误诊断(安哥拉,2012)。这导致疟疾治疗被大量滥用,因此可能导致疟疾药物短缺。此外,这种药物滥用降低了患者在真正生病时对药物的反应,并增强了疟原虫的抵抗力。最后,这加剧了进行血液微观分析所需的适当知识的缺乏。

尽管为抗击疟疾做出了许多努力,但资源的滥用仍然是一个主要问题

A .我如何帮助治疗疟疾?

我们已经看到,滥用资源是一个主要问题,但如何更好地投资以帮助防治疟疾?

A.我可能是答案,而且在很多方面。首先,使用人工智能和人工授精程序快速检测这种疾病可以通过快速诊断挽救无数生命。鉴于之前看到的数据,它不仅比人快,而且可能更准确。这种准确性将导致更好的药物管理,从而节省大量资金。这些节省下来的钱可以重新注入,更好地利用。

给红细胞拍照非常容易,只需要一台显微镜和一个适配环就可以给红细胞拍照。一旦拍摄了照片,就有可能简单地通过一个 ML 程序来运行它,这个程序被训练来识别被感染的细胞。

鉴于检测感染的方法相当简单,我们认为可以尝试使用 Giotto 开发一个疟疾检测程序,不涉及任何代码。重点是输入未分类的红细胞图像,让程序以令人满意的准确度进行分类。

Giotto 是一个机器学习*台,可以开发图像分类的 ML 程序,而不必编码。要更详细、一步一步地描述乔托,你可以阅读我们以前的博客文章

无代码*台使用起来很简单,这可能会真正使人工智能民主化。不仅任何人都可以使用它,而且部署 docker 的可能性意味着只有一台计算机,没有 wifi,你可以用最简单的方式使用人工智能。这是一个关键点,因为许多高风险疟疾区非常偏远,因此没有像样的互联网连接。如果这行得通,农村社区就不必去最*的医疗中心了(记住,有时这很远)。重点不是取代人类的专业知识,但当没有其他选择时,这可能是一个答案。

正确训练程序的关键是拥有适当的数据。这意味着你需要有充分标记的每类文件夹来分析,以及每个文件夹中更多或更少的相同数量的图像(当然,当谈到图像分类时)。我们使用了由 27'558 幅红细胞图像组成的数据集,其中一半是寄生的,一半是正常的。

拥有正确标记的图像是首要的

为了处理这个数据集,我们首先必须把它上传到乔托。然后,我们必须选择适用于我们图像的数据增强技术。在这种情况下,应用了所有的方法,因为它们都不会改变图像的完整性。通过进行这种增强过程,我们通过向模型提供比初始集更多的数据来提高模型的性能。

所有的数据扩充过程都应用于我们的数据。

一旦完成,我们必须选择模型的所有特性,比如 resNet 数和历元数。我们的模型在 resNet 34 和 30 个历元的情况下表现最佳。

这个项目的训练时间相当长,因为数据集非常庞大;完成培训大约需要 3 个小时。

通过 20%的验证分割,我们的模型实现了 97.88%的准确率,没有一行代码。

这个精度是令人满意的,因为为程序选择的设置不是太高(resNet 34 和 30 历元)。已经用 10 个时期获得了非常相似的结果(约 96%)。

结论

尽管医学取得了令人印象深刻的创新,但这种寄生虫仍然在世界许多地方蓬勃发展,每年夺走数十万人的生命。找到对抗疟疾的新方法至关重要。这可以帮助数百万人,也可以促进高风险地区的经济发展。

97.88%的准确率是令人满意的,尤其是这是在仅仅训练了 3 个小时,完全没有使用代码的情况下实现的。在资源匮乏的地方,这比那些很少或根本没有受过适当分析培训的人更容易获得更好的结果。这样一个简单的应用程序可以直接部署在农村地区,允许人们在没有其他选择的情况下进行自我治疗。

我们模型的总结。

你可以自己试试这个程序:https://cloud.giotto.ai/ic/malaria密码:malaria123

来源和链接

[## 疟疾细胞图像数据集

用于检测疟疾的细胞图像

www.kaggle.com](https://www.kaggle.com/iarunava/cell-images-for-detecting-malaria) [## 乔托

停止编码。启动人工智能

www.giotto.ai](https://www.giotto.ai/) [## 安哥拉的疟疾过度诊断和抗疟药的过度消费:后果…

疟疾病例的过度诊断高达 85%。大量滥用抗疟药物。缺乏数据可靠性…

www.sciencedirect.com](https://www.sciencedirect.com/science/article/abs/pii/S0001706X16311251?via%3Dihub) [## 疟疾|语义学者

德国联邦各部的工人们强烈要求国家赔偿…

www.semanticscholar.org](https://www.semanticscholar.org/paper/Malaria-Greenwood-Bojang/2245f5204a16f1e4765ed239b54432c9c4a96764) [## 一个二级医疗保健中心对儿童疟疾的过度诊断和过度治疗…

疟疾的过度诊断和过度治疗是疟疾流行国家儿童的一个主要问题。这个…

journals.sagepub.com](https://journals.sagepub.com/doi/10.1177/0049475515622861) [## 瓦基索临床诊断的成年女性中实验室确诊的疟疾发病率低

谢尔盖·叶戈罗夫,1 罗纳德·m·加利旺戈,1 阿洛伊修斯·塞马甘达,2,3 摩西·穆万加,4 艾琳·韦松加,4 乔治·米罗,5…

www.ncbi.nlm.nih.gov](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5109652/) [## 疟疾概况介绍

疟疾是由疟原虫寄生虫引起的。寄生虫通过被感染女性的叮咬传播给人类…

www.who.int](https://www.who.int/news-room/fact-sheets/detail/malaria) [## 疟疾

恶性疟原虫][诺氏疟原虫][三日疟原虫][卵形疟原虫][间日疟原虫]血液…

www.cdc.gov](https://www.cdc.gov/dpdx/malaria/index.html)

利用人工智能和计算机视觉实时检测密集人群中的面具

原文:https://towardsdatascience.com/detecting-masks-in-dense-crowds-in-real-time-with-ai-and-computer-vision-9e819eb9047e?source=collection_archive---------49-----------------------

迈向美好未来的一小步

这是从半夜醒来开始的,在极度困难的过程中,由于新冠肺炎·疫情病毒,封锁期很长。

一个周六的早上 5 点,我起床去买东西,看到一群人在附*的办公区踢足球。然后我想,为什么我们不能从远处发现谁在不戴面具的情况下走来走去。

然后我突然想到,等等……你可以!我可以试试。(有时候你忘了,你自己拥有什么技能。我们大多数人都会这样!😂)我带着兴奋的心情回家,设置好自己的深度学习环境。

我使用我的版本 DarkNet 运行 YOLOv3 模型进行场景检测,并快速旋转标准场景检测模型。然后,我开始从不同的公共数据集和存储库中,管理一个由屏蔽和未屏蔽图像组成的数据集。

DarkNet 的美妙之处在于,一旦你构建了它所有的 C 二进制文件和绑定,重新训练它最外层的迁移学习就相当容易了。因此,我得到了模型的权重,然后我必须对数据集进行注释,并开始在我的 GTX 1060 上用 CUDA 进行大约 10 个小时的训练。

我达到一个点,直到损失为 0.02,然后导出生成的权重。

对我的网络摄像头拍摄的照片进行第一次测试

这是第一个结果。

我在几种光照条件下运行它,看到结果在低光照环境下波动,所以我添加了一些直方图均衡技术。

直方图均衡化为现有图像增加并*衡了一定程度的对比度。结果相当好。

下一步是通过视频来运行它。现在,在当前的封锁情况下,我无法使用 IP 摄像头,所以我让我的室友指向并拍摄我(原谅我的短裤😅,这里太热了!)从窗口到街上。

第二个测试来自我手机拍摄的视频

一旦精度适合我,我意识到我需要更多的性能提升。所以我尝试了不同的方法。我需要优化分配给运行该作业的线程的内存量,以及每个节拍处理的帧的缓存。

因此,我没有使用 Python 脚本来运行这项工作,而是必须整体构建 DarkNet 的其他模块,并使用 CMake 来构建我的操作系统的 C 绑定,并将 DarkNet 添加到我的系统路径变量中。现在,我可以只使用 CLI 运行推理了😉

然后我开始在密集人群的视频上进行测试

使用该模型在视频上运行推理

在印度的人群中取得了惊人的效果

这是 YouTube 上运行项目演示的最终视频。

我达到了大约 40FPS,这对于视频处理来说足够好了。我真的很想运行网络摄像头,但遗憾的是,被隔离并没有给我在我的公寓里太多的空间来大规模测试一些东西。

这意味着我们现在可以在 IP 摄像机、无人机、公共场所的闭路电视和系统网络摄像头上运行这一功能。

理想的情况是将它部署在数据中心 GPU 上,如 Nvidia 2020 主题演讲中宣布的新 Nvidia V100 ,以获得惊人的性能和大规模的结果。

如果我们只是发现问题,我们可以建立很多东西,我觉得大多数问题只是每天出现。我们只需要在这方面有所创新。

住宿之家#住宿安全

用一对一检测黑色素瘤

原文:https://towardsdatascience.com/detecting-melanoma-with-one-vs-all-f84bc6dd0479?source=collection_archive---------46-----------------------

生物医学数据的机器学习

使用皮肤镜图像创建自动检测黑色素瘤的应用程序

L 在需要对离散值输出进行分类和预测的应用中,多重分类的逻辑回归是一种很有前途的方法。在之前题为“癌症中恶性肿瘤预测的逻辑回归”的文章中,我介绍了这个惊人的监督学习模型背后的一些基本概念,暗示了它在预测乳腺癌恶性肿瘤结果中的可能用途。

在这篇文章中,我希望展示一对一算法,它代表了逻辑回归的一个特殊实现,扩展到多个结果。我们将看到如何在 Python 3.7 中创建一个基于该算法的病理学信息学应用程序,以自动使用皮肤镜图像来检测黑色素瘤。不幸的是,由于数据集的限制,这种方法对于实例和特征之间的比例不均衡的任务来说并不是最佳的。重要的是:本练习的唯一目的是揭示将机器学习应用于皮肤病变图像的基本概念,并且仅用于实验目的,而非临床使用。

那么,为什么要使用一对一算法对皮肤癌图像进行分类呢?

这是我个人的观点,利用生物医学数据,尝试用最直接的方法来解决一个复杂的问题。如果这种方法导致“过于简单”,找到它的限制可以让我们在扩展它时有更多的控制。同时,一个简单的程序可以让我们发现它在现实中是多么强大。然后,永远不要低估逻辑回归:它可能会让你吃惊!

我第一次看到一对一应用是在 Coursera 的机器学习课程上,由 Andrew NG 教授2。课程的第三周“主要”是对 MNIST 数据集进行分类的练习,该数据集由 5000 张手写数字图像组成。Andrew NG 的课程基于 Octave/Matlab 代码,因此当我决定用 Python 实现我的逻辑回归函数时,我将它应用于 MNIST 数据集进行测试。测试的准确率为 89.5%,matthews 相关系数为 0.88(将训练集拆分为 4167 个图像,将测试集拆分为 833 个图像)。MNIST 图像具有 20X20 像素的分辨率,这意味着输入 400 个特征。手写数字是灰度的,每个数字位于单色背景的中心。MNIST 数据集的性质使逻辑回归方法更加简单,并解释了它在正确分类数字方面的成功。

所以我想,如果我把我的一对一代码应用到一个由更复杂的灰度图像组成的数据集,去掉所有多余的特征并保留每幅图像的最小特征集,会发生什么。在这个实验中,我使用了 PH2 ,这是一个 8 位 RGB 彩色皮肤镜图片的数据集,是在佩德罗·西斯潘诺医院(葡萄牙马托西尼奥斯)的皮肤科获得的。我得到的结果是惊人的,尽管考虑到它的性能有点令人失望,这就是我将在这篇文章中向你展示的,以及 ML 理论的一些基础知识(最低限度)。

1.Pedro Hispano 医院)数据集

黑色素瘤(皮肤癌)是世界上最致命的癌症之一。美国癌症协会将其列为 2019 年美国 7000 多人死亡的原因。它来自黑素细胞,黑素细胞是含有色素的皮肤细胞。紫外线照射被普遍认为是最重要的致病因素。通过皮肤镜分析区分黑素瘤病变和良性皮肤癌是一项基本任务。然而,这种分类问题在医学上的复杂性至今仍是争论的焦点。

2019 年,来自南非德班夸祖鲁-纳塔尔大学数学、统计和计算机科学学院的 Adekanmi A. Adeguin 和 Serestina Viriri 利用 2017 年国际生物医学成像研讨会(ISBI)和 PH2 的数据集,开发了一种基于深度学习的黑色素瘤检测系统[3]。所有 PH2 图像的原始分辨率大约为 768x560 像素。200 个图像数据集包括三种黑色素细胞病变:80 个普通痣(结果 0)、80 个非典型痣(结果 1)和 40 个黑色素瘤(结果 2)。

2.上传和显示数据集

我已经将 PH2 图像转换为 128X128 像素的分辨率。您可以下载这个数据集作为压缩的存档文件“ PH2_128X128.pickle.zip ”。此外,我还制作了同一个数据集的另一个版本,通过双变量分析过滤掉所有冗余的特征,(见第 4 段),你可以在这里找到: PH2_128X128_BIVA.pickle

在进行本文提出的实验之前,请按照超链接下载这两个文件。然后打开你的 Jupyter 笔记本,输入代码 1 ,导入所有必要的 Python 库:

代码 1:导入库。

代码 2 将实现 UploadDataset 函数来上传 PH2 档案。

代码 2:上传一个 PH2 数据集

使用 UploadDataset 指定您从此链接下载的档案文件名:

df, X, y = UploadDataset('PH2_128X128.pickle')

该函数将返回一个 Pandas Dataframe, Xy 向量,并将产生以下输出:

Dataset uploaded.
archive: PH2_128X128.pickle
num of examples: 200
num of features (X): 16384
y is the output vector
num of classes: 3

在上传数据集的过程中, UploadDataset 提供了一些关于存档结构的有用信息,如数据集中示例的数量(200)、X 中特征的数量、以及类/标签的数量(在本例中为 3)。浏览表 1 中总结的数据帧,了解其结构:

表 PH2 数据框架

dataframe 表示 PH2 数据集的基本组成部分(此处未提供关于图像的具体信息,例如组织学)。关于完整数据库的详细描述,请点击 PH2 网站的链接。它由 ID 列、要素列和输出列组成。feature 列包含 16384 个特征的 numpy 数组,对应于 128X128 像素的乘积。

如果我们想要可视化存储在档案中的 200 幅图像中的一幅,则代码 3显示功能代表一种可能的解决方案:

代码 3:显示 PH2 图像

我们所要做的就是以这种方式调用显示函数:

Display(df, 1)

其中 df 是上传的数据帧,第二个参数,在这种情况下,1 是图像的编号。显示器的输出如图 1 所示:

图 1:来自 PH2 数据集的图片之一。(图片来自https://www.fc.up.pt/addi/ph2%20database.html)

该函数显示图像及其相关结果,在本例中为 0(80 种常见痣中的一种)。与原始图像相比,该图像的分辨率大大降低。我尝试了几种分辨率(256X256,512X512,以及更低的像 20X20,我的结论是 128X128 是一个很好的折中。显示功能在 128X128 像素灰度图像中重塑 16384 个特征的 numpy 阵列。无论如何,相对于样本数量,该数据集的特征数量仍然太高,这将导致稀疏性问题。正如我们将在接下来的段落中看到的,我将展示如何解决这个问题。

3.正则化 Logistic 回归及其对决策边界的影响

我们已经展示了 PH2 数据集,并描述了访问其图像的代码;现在,我们需要引入一些关于逻辑回归正则化的新概念,我们将在这种情况下使用。显然,处理正则化的论点听起来可能跑题了,因为 PH2 数据集受“太多特征”的影响,而不是“很少特征”的问题,这是正则化的典型情况。然而,我认为对于逻辑回归极限的详尽解释,一个完整的关于这个主题的讨论是值得考虑的。

为什么要正则化逻辑回归?

在机器学习中,我们将数据分为训练集和测试集。训练集用于调整代表我们模型的假设 h 的参数;测试集用于评估我们的模型在未知的新例子上的表现,概括新数据。术语“一般化”指的是我们的假设适用于新出现的病例的程度。如果我们要创建一个可以对三种皮肤癌进行分类并预测新的癌症样本的应用程序,这就是我们想要的。当您准备数据集时,首先要做的是浏览一下关于要素的观测值数量,避免欠拟合/过拟合问题。

例如,一个典型的欠拟合问题是当您的假设 h 与数据趋势的映射很差时(可能是由于缺少特征)。您可以添加额外的特性( x1 和 x2 )来添加额外的高阶多项式项。图 2 解释了这一概念,以应用于两类皮肤癌的逻辑回归的可能实现为例。图 2A 示意了装配不足的问题:

图 2:欠拟合和过拟合问题。青色圆盘代表普通痣;紫色星星对应黑色素瘤。

增加额外的特征会导致更好的假设,如图 2B 所示。但是当添加了这些额外特性之后,我们不得不面对相反的问题时,问题就出现了:过度拟合。文献中描述的解决欠拟合问题的方法之一是正则化成本函数的所有θ。

等式 1:逻辑回归成本函数。

逻辑回归的成本函数(如等式 1 中所述)的特征在于假设 h 具有 sigmoid 函数,用于非凸性(如本文所述)。

正则化工作的机制包括惩罚我们必须添加到成本函数中的所有 θ ,以向特征添加额外的高阶多项式项,使它们变小。首先,我们希望消除膨胀成本函数的最后多项式项的影响,将它们减少到零。

等式 2:正则化的逻辑回归成本函数。

一种合适的方法是修改成本函数以收缩所有θ参数,因为我们不知道收缩哪个参数是必要的。在末尾添加一项(等式 2 中以黄色突出显示的新正则项)将具有收缩所有θ的效果。重要的是:不要惩罚θ0。 lambda 的作用是收缩θ,所以如果 lambda 极大,假设 h 就会欠拟合。

为了阐明整个正则化过程,让我们报告一个小测试。想象一下,从黑素瘤数据集的一系列图像中仅绘制两个特征(x1 和 x2)。这两个特征聚集在蓝色和橙色的两个同心环中。每个环代表属于普通痣(蓝色类= 0)的一组值,而橙色类= 1 的值对应于黑色素瘤。我们希望应用逻辑回归来预测新值将落在何处(例如,新的未知值将落在蓝色点组中还是橙色点组中)。此外,我们希望计算一个决策边界,将蓝色组与橙色组分开。(您可以通过此链接下载测试输入文件)。

图 3:测试。

看一下图 3:很明显,用一条直线将两类点分开是不可能的:这是一个典型的欠拟合问题(图 2A)。我们需要添加额外的特征来为我们的假设添加额外的高阶多项式项。这里提出的代码示例将通过一个 mapFeature 函数处理添加额外特征的测试,将两个特征向量(x1 和 x2)转换为一个 28 维的二次特征向量,比如 x1 + x2 + x1 + x2 + x1x2 + x1x2 …等等,其中输入 x1 和 x2 必须是相同的大小。那么,假设就会有这个形状:hθ(x)= g(θ0+θ1x1+θ2x 2+θ3x 1+θ4x 2+θ5x1x 2…)。训练新特征的多维向量将导致逻辑回归形成更复杂的决策边界(图 4)。

这个测试的 Python 代码被分成三个部分(代码 4代码 5代码 6 )。下载完测试数据后,按顺序复制并粘贴代码块。代码 4 包装了三个基本函数: Sigmoid 函数、 Cost 函数和 Gradient 。关于这三个功能的详细描述,我推荐读者阅读我的一篇文章,这篇文章致力于使用逻辑回归预测乳腺癌的恶性程度。

代码 4:正则化的逻辑回归函数

代码 5 绘制决策边界图的特征。该代码改编自由 Srikar 在其帖子中提出的 Python 源代码:

代码 5:映射特征

最后,代码 6 执行正则化测试并绘制决策边界(由 Srikar 重新调整):

代码 6:测试正则化和决策边界。

代码 456 合并到同一个 Jupyter 笔记本中,运行整个练习:结果输出如下所示:

Running Regularized Logistic Regression...

Optimization terminated successfully.
         Current function value: 0.394594
         Iterations: 35
         Function evaluations: 118
         Gradient evaluations: 118

Accuracy %: 84.0
matthews_corrcoef: 0.6807791256663034

图 4:决策边界

准确率为 84%,马修斯相关系数为 0.68。这些结果随着不同的λ值而显著变化。

对于λ= 0.1,代码 6 还会生成一个数据集图,其中一条线代表决策边界

这里,我使用了 fmin_cg scipy 优化函数,它实现了用于线性方程组数值解的共轭梯度算法。共轭梯度法是作为迭代算法实现的。在这种情况下,使用优化算法来解决太大而不能由直接实现处理的稀疏系统是必要的。

4.维数灾难和双变量分析。

所提出形式的 PH2 数据集由 200 个观察值和 16384 个灰度像素特征组成。这个数字高得令人难以置信,因为它代表了一幅图像的总像素数。试图使用一系列图像的“所有像素”来训练逻辑回归是适得其反的。此外,特征的数量远远高于观测值,我们可能会遇到一个被称为“维数灾难”的问题。尽管如此,对于一个预测模型来说,200 次观察是非常少的。

“维数灾难”是理查德·e·贝尔曼(Richard E. Bellman)创造的一个表达式(也称为“p>>n 问题”,其中 p 代表预测值, n 代表观察值)。这个问题出现在分析高维空间中的数据时,空间的体积增长如此之快,以至于可用的数据变得稀疏。这种“稀疏”的后果之一是过拟合问题(图 2C)。当我们有太多的特征时,它就会发生。已学习的假设 h 可能很好地符合训练集,但是不能概括新的例子(例如,新的黑色素瘤或普通痣的分类)。

在因维数灾难而过度拟合的情况下,正则化没有帮助。相反,将数据减少到几个一致的特征可以解决问题。为此,我在这里使用了我上一篇文章中的双变量分析,来过滤掉多余的特征。

双变量分析是一种基于相关性的方法,它分析成对特征之间的关系。一般的假设是,高度相关的特征提供了我们想要消除的冗余信息,以避免预测偏差。以下代码改编自 AN6U5 ,用于相关矩阵的显示部分。上传 PH2 数据集后,从Chris Albon【4】重新改编的一段代码删除了所有相关性高于 0.9 的特征,保留了那些具有较低均值的特征。然后程序调用feature _ correlation _ matrix函数对矩阵进行可视化。该过程可以删除 16354 个冗余特征,仅保留 30 个。

代码 7:双变量分析。

图 5:删除冗余特征后的特征相关矩阵。

去除冗余特征后得到的相关矩阵如图 5 所示。该矩阵显示了 30 个相关性小于 0.9 的特征。每个要素都标有一个数字,该数字对应于原始 16384 要素数据集的索引。

5.一对多的实施

在关于癌症恶性预测的逻辑回归的文章中,我使用逻辑回归作为二元分类器,它能够将阳性类别与阴性类别(良性与恶性)分开。这里,我们需要扩展逻辑回归来解决多重分类问题。

PH2 数据集有三个结果:普通痣(结果 0)、非典型痣(结果 1)和黑色素瘤(结果 2)。一对一算法是逻辑回归的一种特殊实现,由三个不同的二元分类器组成。例如,如果我们从具有三个标签 0、1 和 2 的两个特征 x1x2 收集值,在第一步中,算法将三个标签中的两个分配给负类,也就是说,标签 0 和 1 被分配给负类,而剩余的标签 2 被分配给正类。该算法前进到第二步,将负类分配给另一对标签(0 和 2),将正类分配给标签 1;在第三步,我们将把标签 1 和 2 标记为负,把标签 0 标记为正。所以我们有三个分类器,每个都被训练来识别三个标签中的一个。对于每个标签 i,**一对一训练逻辑回归分类器 hθ(x),以预测 y=1 的概率。每次计算对应于一系列θ值,这些值必须乘以向量x。最后,对于每个标签 i,该算法将挑选将 hθ(x) 最大化的唯一标签 i

图 6 将解释一对多过程:

图 6。OneVsAll 算法。图 6B :青色圆盘代表普通痣(结果 0),红色圆盘代表非典型痣(结果 1),紫色星星对应黑色素瘤(结果 2)。考虑来自两个特征 x1 和 x2 的值:该算法包括在三个步骤中实现的三个不同的二元分类器。第一步将标签 0 和 1 的值分配给负类,将标签 2 的值分配给正类。第二步将负类分配给另一对标签(0 和 2),将正类分配给标签 1。在第三步中,我们将把标签 1 和 2 标记为负,把标签 0 标记为正(图 6A6C )。最后,对于每个标签 i ,该算法将挑选将 hθ(x) 最大化的唯一标签 i 。

黑色素瘤检测的完整一对一算法包含在代码 8 中。在 Jupyter 笔记本单元格中复制、粘贴并运行代码。“main”部分表示代码的驱动部分,它由正则化逻辑回归成本函数和梯度函数组成。此外,代码还提供了两个功能,一对多的实现和测试结果的预测。

'''
MAIN
'''# Upload the dataset
df, X, y = UploadDataset('PH2_128X128_BIVA.pickle')# Split the dataset
X_train, y_train, X_test, y_test, indices, num_test = splitDataset(X, y)# Run oneVsAll
lmbda = np.float64(1e-4)
all_thetas = oneVsAll(X_train, y_train, lmbda)# Calc Accuracy
df_test_bench, pred_train, pred_test = CalcAccuracy(all_thetas, X_train, y_train, X_test, y_test, num_test)# Print the test results
df_test_bench

上传 PH2 数据集(双变量 30 特征版本)后, splitDataset() 函数将随机生成训练和测试数据集。然后 oneVsAll() 函数将在训练集上运行逻辑回归,但这里的一个关键函数是 CalcAccuracy()。该函数将计算训练和测试集的准确性。它将调用另一个名为 predictOneVsAll() 的函数,该函数将选取将 hθ(x)最大化的唯一标签 i ,使用以下 numpy 操作:

预测= np.argmax(sigmoid( np.dot(X,all_thetas。t)),axis=1)

最后, CalcAccuracy() ,将产生一个包含测试结果的 pandas dataframe,以及准确性和 matthews 相关分数。

代码 8:一对一对所有人

代码 8 产生的输出如下:

'''
-UPLOADING DATASET-
archive: PH2_128X128_BIVA.pickle
num of examples: 200
num of features (X): 30
y is the output vector
num of classes: 3

-SPLITTING DATASET-
random seed: 22549
# Training set:  160
# Test set:  40

-ONE VS ALL-
Optimization terminated successfully.
         Current function value: 0.495204
         Iterations: 67
         Function evaluations: 251
         Gradient evaluations: 251
Optimization terminated successfully.
         Current function value: 0.526326
         Iterations: 62
         Function evaluations: 241
         Gradient evaluations: 241
Optimization terminated successfully.
         Current function value: 0.184121
         Iterations: 215
         Function evaluations: 884
         Gradient evaluations: 884

-TRAINING ACCURACY-
Accuracy: 74.375000
matthews_corrcoef: 0.5928012927684577

-TEST ACCURACY-
Accuracy: 60.000000
matthews_corrcoef: 0.396701196586351

训练集由 160 幅图像组成,而测试集包含 40 幅图像。每次运行代码时,两个数据集的分割都是随机执行的。在这种情况下,训练准确率为 74%,matthews 相关分数为 0.59。对于测试的准确性,我们得到了 60 %, Matthews 相关分数为 0.40。也可以通过 df_test bench dataframe 获取测试结果:

包含测试结果的数据帧

代码 8 还包含一个名为showthematheta(),的有用函数,它使用数据集的矢量 Xy ,所有标签的找到的θ矢量和在训练/测试期间计算的预测矢量,产生应用于特定图像的所有最大θ的输出。例如,键入:

showTheMaxTheta(X, y, all_thetas , 145, pred_train)

该函数将显示图像 145 的最大θ值:

Real outcome: 1
Max Theta: 0.9213422724776613
Predicted category: 1

          0
0  0.232627
1  0.921342
2  0.000085

这个图像的真实结果是 1,一个非典型痣,预测值是 1。这是因为标签 1 的最大θget 为 0.92,而标签 0 和标签 2 的最大θget 分别为 0.23 和 0.000085。

6.结论

一对一算法并不代表解决医学图像分类问题的最佳解决方案。这是一种基于多结果逻辑回归的算法,由于它被认为是一种广义线性模型,因此有许多限制。这意味着它的结果总是取决于输入和参数【4】的总和,而不是乘积/商。为 PH2 数据集计算的性能显示了低准确度和低的 matthews 相关分数(使用 matthews_corrcoef: 0.59 的训练准确度:74.4,使用 matthews_corrcoef: 0.40 的测试准确度:60.0)。这是一个典型的欠拟合问题,可能是由于数据集中缺少信息。尽管如此,该算法能够捕捉普通痣和恶性病变之间的差异,这是一个很好的观点,因为这意味着数据集下面有一种信息,一对一可以检索。我个人认为这个算法的性能可以通过增加图片的数量来提高。毫无疑问,200 次观察对于任何一种预测模型来说都是非常少的。特征的数量远远高于观测值,这导致了一个被称为“T2 维度诅咒”的问题。最小化特征是有用的,尤其是当我们处理图像的时候。双变量分析将 16384 个特征减少到 30 个。这可能意味着表征整个数据集的特征比我们想象的要少。“一对所有”限制的进化结果是神经网络的应用,它可以克服逻辑回归带来的许多问题,这将是我下一篇文章的论点。

参考资料:

  1. Andrew NG,机器学习| Coursera
  2. A.A. Adegun 和 S. Viriri,“基于深度学习的自动黑色素瘤检测系统”,载于 IEEE Access,第 8 卷,第 7160-7172 页,2020 年,doi:10.1109/Access。20207.686386866106
  3. 克里斯·阿尔邦(Chris Albon),用 Python 编写的机器学习食谱,O'Really,ISBN-13:978–1491989388。
  4. 机器学习常见问题解答:为什么逻辑回归被认为是线性模型?作者塞巴斯蒂安·拉什卡。

用 CNN 检测微控制器

原文:https://towardsdatascience.com/detecting-microcontrollers-with-cnn-ced688a8a144?source=collection_archive---------51-----------------------

点击时的对象检测

根据 Kaggle 竞赛数据检测微控制器的简单教程

照片由来自佩克斯乔纳斯·斯维德拉斯拍摄

像 TensorFlow 或 PyTorch 这样的 tandart 库没有提供任何简单的方法来训练你的自定义对象检测模型。很多时候你需要安装一个大的库作为 Detectron 2 或者 Tensorflow 物体检测 API。不要误解我的意思,这些库功能强大,但通常需要大量的检查、调优和处理数据。这就是为什么我想向您展示一种更简单有效的方法,通过调用 Rest API 和一点点击来训练您的检测器。

这种方法有一些优势:你不需要成为机器学习专家,你的数据都在一个地方。

资料组

对于本教程,我从 Kaggle 选择一个小数据集来检测由Gilbert Tanner[@ Medium]开发的微控制器。它包含大约 250 幅图像,包含四种类型的对象:

  • Arduino Nano
  • Heltec ESP32 Lora
  • ESP8266
  • 树莓 Pi 3

我们将通过 API 上传 Ximilar *台上的数据(带边框的图片)。边界框包含 4 个坐标,并定义微控制器的确切位置(矩形)。我们也可以通过 app.ximilar.com 拖放图像,并通过绘制手动创建边界框。

创建任务和标签

在我们上传数据之前,我们需要通过应用程序定义我们的神经网络模型。我们将创建任务和 4 个与该任务相关联的标签。

创建带有一些标签的新任务。作者图片

选项 A:通过脚本上传数据

如果您不想手动创建所有的边界框,您可以通过运行以下脚本来上传它们。只需更改标签 id 并从下载的数据集文件夹中运行该脚本。

选项 B:用绘图框拖动&放置

用前端绘制边界框。作者图片

火车

上传所有数据后,我们进入微控制器任务页面,点击 训练 按钮。培训可能需要 30 分钟到几个小时。想出去走走也可以注销应用:)。这真的需要一些时间,因为用于对象检测的神经网络是在我们的服务器上自动训练的。

如果你想了解所有这些背后的神经网络架构,你可以查看 Libor 的帖子。

检查结果

训练已经完成,现在我们可以在一些图像上测试它。同样,我们有两个使用 API 或 app 来获取结果的选项。

检查训练好的模型。作者图片

在我们的任务定义中,我们可以看到我们的模型用 IoU 0.75 实现了 mAP 0.85。这是一个不坏的结果!什么是地图度量?解释在另一篇文章中,所以你可以在这里阅读更多。简单地说,数字越高,结果越好。如果我们转到训练模型的细节,我们可以查看每个标签的地图。我们可以看到数据集很*衡(每个标签有图像,每个标签有对象)。

您可以使用 Python SDK 客户端(这是一个 REST/JSON 包装器库)连接到 API,并获得经过训练的检测模型的结果:

训练模型的技巧

这只是我们的第一个训练模型,所以结果不是最好的。我们可以通过上传更多的图片和重新训练模型来改善它。如果是这样,应用程序将训练一个新模型,而不删除旧模型。如果你想对你的型号进行比较或 A/B 测试,这是很好的选择。

你可以玩其他的选择。您可以编辑高级选项来控制图像分辨率和图像增强技术。图像增强是一种改变(稍微或更积极地)输入图像以创建更大数据集的技术,因此您的模型将在更多图像上更好地泛化。

您还可以上传图像并将它们标记为测试,这样您的模型将始终在这些标记的图像上评估结果。这些图像在训练过程中是看不到的,因此您的测试数据集独立于您的训练数据集,并且该数据集的地图编号更加可靠。

最后的话

目标检测或目标识别只是机器视觉领域中许多常见问题之一。它可以用于电子商务中检测时尚服装,用于医疗保健中检测肿瘤组织,用于汽车油漆划痕的保险检测,用于检测免费停车位,等等。

使用数据科学检测含糊说唱

原文:https://towardsdatascience.com/detecting-mumble-rap-using-data-science-fd630c6f64a9?source=collection_archive---------17-----------------------

实践教程

使用数据科学建立一个模型,客观地将说唱歌手归类为咕哝者。

资料来源:pexels.com

警告:本文引用的说唱歌词可能包含露骨的语言。

介绍

了解我的人都知道,我花了很多时间处理数据和听说唱音乐。自从在小学收到我的第一张 cd“大威利风格”的威尔·史密斯,我几乎每天都要听说唱几个小时。从小学到现在,我获得了包括数据和统计在内的许多领域的知识和经验,当然说唱的世界也在不断发展。在嘻哈音乐的*期历史中,出现了一个被称为“咕哝说唱”的新流派。

城市词典将咕哝说唱定义为“一种听起来像中风患者试图发表演讲的音乐形式;往往无法理解,不合逻辑。”。在我看来,mumble rap 的一个很好的例子是 Playboi Carti 的@ MEH ,其中 YouTube 的顶部评论是“听起来不错,等不及英文版了。”。然而,并不是每个例子都如此清晰,一些说唱歌手根本不想与“咕哝”这个词联系在一起。那么,谁来决定哪些说唱歌手符合成为咕哝说唱歌手的标准呢?因为甚至维基百科条目也将其描述为“定义宽松”,所以我决定打开我的数据工具箱来获得一个更客观的指标,看看你最喜欢的说唱歌手喃喃自语了多少。

如何测试曼波

我测试曼波的想法很简单:

  • 选一首歌
  • 把它输入语音到文本的转换器
  • 将生成的文本与实际歌词进行比较

当然,和任何软件项目一样,事情并不像计划的那样顺利。我大约一年前开始从事这个项目,但在进行了一些初步测试后,语音到文本转换器(Google API)似乎真的很难适应背景中的节拍、乐器和其他声音。糟糕的结果和一大堆其他项目的想法结合在一起,让我决定放弃这个项目。

快进到 2020 年初,我在 Reddit 上看到一个帖子,有人创建了一个在线工具来从歌曲中提取人声。由于这是丢失的关键,我再次对完成这个项目抱有希望。确定咕哝量的基本概念保持不变:

项目设置

除了这次我会先用工具提取人声。

现在让我们更详细地了解一下我是如何获得数据并进行分析的。

获取数据

我在收集数据时遇到了各种各样的障碍。最初的想法很简单:下载歌曲,去掉人声,然后输入 API。然而,我很快发现,尤其是在说唱音乐的情况下,一整首歌往往是录音艺术家发音的糟糕表现。这主要是因为:

  • 合唱或挂钩占据了歌曲的大部分,不应该算作说唱
  • 大多数说唱歌曲都有其他艺术家的诗句

这意味着样本应该限于诗句。对于每首曲目,将使用一段歌词。因此,我不得不修剪所有的歌曲,并选择相应的歌词部分。总而言之,这个过程是这样的:

为了获得音轨,我写了一个简单的机器人,但是选择正确的诗句和复制粘贴相应的歌词是一项繁琐的手工工作。由于手动部分花费了大量的时间,我不得不限制我的样本。我采用了以下方法:

  • 在网上搜索“咕哝说唱歌手
  • 选择前 15 名(受欢迎程度,而非质量指标)
  • 在 Spotify 上搜索艺术家时,选择前 5 首歌曲结果
  • (经典说唱重复)

这导致了 150 个轨道(15×5×2)。

当然,更多的说唱歌手和每位歌手的歌曲会产生更好的结果,但正如之前所说,数据收集是一项非常劳动密集型的任务,幸运的是,结果将显示大多数说唱歌手在不同的歌曲中相当一致。

一路走来,我意识到随着时间的推移,说唱音乐可能也变得越来越难以理解,因为俚语越来越多(例如“让我兴奋不已”)。所以我又添加了 30 首来自 Complex 的“自 1979 年以来每年最好的说唱歌曲”。此列表包含 30 多首曲目,但由于其中一些曲目与样本中已有的曲目重叠,因此只产生了 30 首新曲目,总共有 180 首曲目。我在 Kaggle 上分享了完整的表格。

在这里,您可以找到数据集中所有艺术家的概述和一些关键数字。

敲门者

按类别/类型选择所有艺术家。

轨道长度

按年份

准备数据

预处理

在开始预处理之前,我添加了一个额外的——虚构的——说唱歌手,我命名为“Lil Controlla”。“Lil Controlla”将作为一个控制组,到目前为止只发布了两首歌曲:

  • OneHunnid (API 生成的歌词与实际歌词相同)
  • 不匹配(API 生成的歌词与实际歌词完全不匹配)

“Lil Controlla”将帮助我仔细检查模型的各种参数。

人工智能生成了虚构说唱歌手 Lil Controlla 的图片。(来源:https://thispersondoesnotexist.com/)

对于预处理,对原始和 API 生成的歌词都应用了以下步骤:

  • 删除所有标点符号
  • 全部小写
  • 删除 Genius.com 不需要的添加,如“[第 1 节]”
  • 将俚语转换成英语(lil -> little,em -> them,…)
  • 将数字转换成单词(21 个野人-> 21 个野人)

堵塞物

词干化是自然语言处理中的一种常用方法,用于将单词简化为词干,即词根形式的基础。例如,单词“ball”、“balling”、“baller”、“ballers”都将被简化为单词“ball”。对于这种分析,原始的 API 生成的歌词都被词干化。这是为了给语音到文本 API 更多的宽容。如果原来的歌词是“ballers”,但 API 捕捉到了“ballers”,人们可能会认为它不应该因此受到惩罚,因为你很容易就能从听音乐中分辨出来。通常,单词将被词干化为英语词典中没有的新单词,但这应该不是问题,因为 API 和原始变体都将被词干化为相同的基础。

在这里你可以找到预处理和词干化前后的一段诗的例子。这是来自 Genius.com 的版本。

预处理前&炮泥:富小子—塞走

你联系不到我(什么?)太空跑车像 E.T. (E.T .)它是插头 tryna 打电话给我(skrrt,skrrt)我在清晨捕捉(插头)哦,在波浪上像一个 durag (durag) Pussy nigga 呼叫他的 boo back (pussy)插头走,古驰在我的鞋架上(古驰)在房子里走,炉子在哪里?直到我跑进塞子(直到我跑进)直到我跑进烂泥(到烂泥)我跑进了一些架子,我跑进了你的女孩(对你的女孩)为什么塞子向我示爱?(向我展示我的爱)我从一个配音演员(嗯?)

预处理后的&炮泥:富小子—塞走

你够不到我什么样的空间妙招像 et et it' the plug tryna 叫我 skrrt skrrt 我在清晨醒来像 durag durag pussi nigga 叫你嗨 boo back pussi plug 走 gucci 在我的鞋架上 gucci 走在房子里炉子在那里打着转直到我碰到塞子直到我碰到直到我碰到泥巴 我做的泥跑进一些机架我做的跑进你的女孩'到你的女孩,而插头显示我的爱显示我的爱我做了从一个配音嗯

模糊分析

现在数据已经准备好了,是时候进行实际分析了。对技术方面不感兴趣的可以跳过这部分,直接看结果。

从这一部分开始,我与我的朋友 Frederik Caenepeel 博士一起工作,他是一位数学家,对编码、数据和 hip hop 有着共同的兴趣。在一次我们用披萨、嘻哈和啤酒进行编码的会议上,我告诉了他这个想法,经过头脑风暴,我们决定一起解决这个问题。弗雷德里克也应该为上述单调乏味的工作得到赞扬。

为了确定原始歌词和语音到文本版本之间的相似性,我们使用了不同度量和影响这些度量的因素的组合。

达默劳-莱文斯坦距离

第一个,也是最明显的,我们用来比较原始歌词和计算机生成歌词的算法是 Damerau-Levenshtein 距离。该算法的原理非常简单,因为它归结为计算使字符串 A 与字符串 b 相同所需的操作次数。该算法的出发点是有三种可能的方法来操作文本:

  • 插入
  • 删除
  • 代替

Cardi B 的《我喜欢》以“现在我喜欢美元,我喜欢钻石”开头。然而转录"美元"作为达拉斯。使用 Damerau-Levenshtein,我们计算两种操纵:

第一步:替换(O → A)

第二步:删除

使用这种算法为每个诗句生成一个分数,分配相似性的定量描述。在应用这个算法之前,我们使用 Python 的 NLTK 删除了停用词。你可以在这里找到更多关于这个算法的信息。

探测法

虽然 Damerau-Levenshtein 对于许多 NLP 项目来说已经足够了,但是这个特殊的案例也可以使用不同的方法。NLP 项目主要关注拼写或意义,而在这种情况下,更多的是语音理解。目的是听你是否能听懂说唱歌手的话,而不一定是你抓住了这个词的确切意思或拼写。让我用一个例子来说明这一点:如果一个说唱歌手说单词“nice ”,而 API 将其捕获为“guys ”,则没有一个字母重叠。然而,从语音的角度来看,这两个词非常相似。出于这个原因,我们决定增加一层分析,通过声音来比较单词。

SoundEx 是一种常用的语音算法,通过声音来索引单词。维基百科将该算法描述为:

  1. 保留名字的第一个字母,去掉所有其他出现的 a,e,I,o,u,y,h,w。
  2. 用数字代替辅音如下(首字母后):
    b,f,p,v → 1 / c,g,j,k,q,s,x,z → 2 / d,t → 3/ l → 4 / m,n → 5 / r → 6
  3. 如果原姓名中有两个或两个以上同号字母相邻(步骤 1 之前),只保留首字母;同样,由“h”或“w”分隔的具有相同数字的两个字母被编码为单个数字,而由元音分隔的这种字母被编码两次。这条规则也适用于第一个字母。
  4. 如果单词中的字母太少,无法分配三个数字,则添加零,直到有三个数字。如果你有四个或更多的数字,只保留前三个。

这个项目的问题是,API 不一定会抓取每个单词,这意味着 API 生成的文本几乎总是比原始歌词短。因此,不能简单地使用 SoundEx 进行一对一的单词分析。为了克服这个问题,我生成了两个 SoundEx 列表:一个用于 API 文本,一个用于原始歌词。从后者中减去前者,剩下的元素就是那些没有被捕获的元素。尽管这种方法并不完美(考虑到不同地方相似的发音单词可能会导致冲突),但它确实很好地表明了使用语音作为度量标准的计算机生成的歌词的性能。

振幅

我们使用的第三个也是最后一个参数意外出现。正如数据收集中所描述的,这些歌曲是从 YouTube 上下载的,然后用在线工具进行了修整。该工具以波形音频格式(或简单地。wav)。事实证明,不同歌曲的质量有相当大的差异。虽然大多数曲目都是高质量的,但一些离群值的音频质量确实很差。将这些负面的异常值输入 API 会导致歌词的转录性能非常差。

对于人耳来说,并不总是容易听到差异,但通过可视化振幅,它变得非常清楚。基本思想是,较高的振幅导致较高的“音量”或响度。

这里你可以看到两个振幅变化很大的音轨的例子。

这种振幅差异的原因实际上很容易解释。记住,所有的歌曲都是从 YouTube 上下载的,音频质量是由上传者设定的。由于 YouTube 是一个相对现代的现象,本样本中的许多曲目来自 YouTube 出现之前的时代。与拥有唱片公司的现代艺术家上传尽可能高质量的歌曲不同,前几代人没有任何 YouTube 频道。他们的歌曲经常出现在 YouTube 上的唯一方式是由一些粉丝自己上传,通常是从 CD 上撕下来的。结果,轨道越老,质量越差的可能性越高,这表现在低振幅中。

为了用个位数表示质量,我用了功率,也就是每秒的能量。绘制每个时间段的*均功率时,您可以清楚地看到一段时间内的趋势。

不考虑 1975 年至 1980 年,其中只包含一个轨道,你可以看到质量大大提高,从 1995 年以后。尽管我们花费了大量的时间和精力来准备所有的曲目,但我们决定根据特定的标准放弃所有的曲目,因为糟糕的质量对转录性能的影响太大了。

我们提出的标准是:

  • 仅 2000 年以后发行的曲目(与振幅密切相关)
  • 追踪能量(振幅)至少为 50(去除异常值)
  • 没有复杂的年度跟踪(随着时间的推移,我们决定放弃 2000 年的阈值)
  • 仅剩余 3 首或更多曲目的艺术家

经过这一截,新的艺术家选择现在看起来像这样:

艺术家的最终选择。

组合参数

为了组合参数,我们考虑了许多不同的选项,包括更多的参数,如同一说唱歌手的方差、音轨长度、每秒字数、词汇丰富度等等。然而,考虑到这个(个人)项目的规模,不想过度设计,以及两个参数的满意结果,我们决定将其简化为一个非常简单的公式。

Mumble 得分= (DamLev 距离+ Soundex 得分)/ 2 *

*使用振幅作为先验标准。

使用这个公式,我们获得了每个音轨的“模糊分数”,范围从 0 到 1,解释如下:

0:非常差的分数,曲目除了喃喃自语什么都没有。

1:满分,歌词都是完全可以理解的。

结果

现在方法已经过去了,让我们来看看结果吧!

在这个柱状图中,我们可以看到所有说唱歌手的概况和他们的*均分数(分数越高,意味着咕哝越少)。颜色编码用于识别维基百科(见简介)中提到的咕哝说唱歌手。这张图表证实了这一假设,并清楚地表明所谓的咕哝说唱歌手的歌词*均来说更难用语音到文本分析来转录。但是让我们更深入地了解一些细节。

说唱歌手的结果

在光谱的低端,我们可以找到喃喃自语。那些是得分最低的艺术家。同样,低分数意味着语音到文本算法很难将他们所说/敲击的单词与实际歌词匹配。Young Thug,Gunna 和 Playboi Carti 在底部,这符合预期,因为他们有时被认为是 mumble rap 的“海报男孩”。我个人也不觉得奇怪。如果你自己听了他们的一些曲目,试着自己转录一下,你就会明白低分从何而来。

当我们看到最高分时,这些名字也并不令人惊讶。德瑞医生、J·科尔斯、纳斯和德雷克都表达得很好,很容易理解。看到 J .科尔在顶端是特别有趣的,因为他是一个众所周知的含糊说唱评论家。

在中间,我们可以找到一些说唱歌手,他们被“误标”为含糊不清的说唱歌手或非含糊不清的说唱歌手。基本上,他们是媒体给他们贴上的标签与数据不完全相符的艺术家。例如,21 岁的萨维奇经常被归类为含糊不清的说唱歌手,但这个实验表明,他实际上表达得相当好。另一方面,像李尔·韦恩这样的人似乎表现不如预期。然而,0.5 分左右的分数应该被轻松地解释为样本仍然很小,并且还有许多其他变量在起作用。对结果的主要关注点应该放在极端情况上:最含糊的和最清晰的。

说唱歌手的可变性

鉴于每位艺术家的样本很少,研究他们得分的可变性就显得尤为重要。每个说唱歌手的标准差(更容易解释)是这样的。

简单来说,你可以说标准差越低,mumble 得分越适合作为说唱技巧的代表。

按类型分类的结果

在这个项目的开始,我使用维基百科作为一个来源来寻找哪些说唱歌手被贴上了含糊不清的说唱歌手的标签。使用这种分类,我们可以比较咕哝组和非咕哝组的*均分数:

这种差异是显而易见的,因为不咕哝或“经典”说唱歌手的*均表现明显高于咕哝者,证实了这一假设。

跟踪结果

最后,我们可以看看“微观层面”,实际上看到模型在最佳和最差赛道上的表现。先说其中一首最好的(也是个人最喜欢的)J·科尔的《无角色 Modelz》(评分 0.86)。

j·科尔——没有榜样

作为一个低评分曲目的例子,我选择了 Playboi Carti 的“@ MEH”和臭名昭著的 YouTube 评论“听起来不错,等不及英文版了。”(得分 0.09)。

Playboi Carti — @MEH

最后,我想展示一个“标签错误”的例子。换句话说,一首歌获得的分数远低于/高于你听自己演唱时的预期。这是 DMX 的经典之作《X Gon' Give It To Ya》。

DMX——X 会给你的

当听我们刮来的版本和从中移除乐器的版本时,我能够找到 API 性能差的原因之一;所有露骨的词都被审查了,这在音频中创造了大量的词间隙。看起来 API 在努力解决这个问题。此外,轨道的振幅也很低,这导致了较差的分数。

结论

当查看艺术家的结果时,我们可以将含糊或不含糊的标签归因于一些具有一定程度的信心的说唱歌手。例如,J·科尔显然处于正确的位置,与咕哝说唱保持距离,因为他的分数不仅很高,而且表现出一致性。其他作词人如纳斯、肯德里克·拉马尔和阿姆也不负盛名。在“口齿伶俐”的说唱歌手中,我们也可以看到像德瑞医生、Jay-Z、坎耶·韦斯特和德雷克这样的大牌。

另一方面,预期的咕哝者名不虚传,如 Playboi Carti,Gunna,Young Thug 和 Lil Pump。所以从现在开始,如果你听他们的音乐,却听不懂他们在说什么,要知道你并不孤单。从这一点上说,不仅仅是你,一个为理解人类声音而构建的计算机算法也和你一样在挣扎。

从整体上评价这个模型,我很高兴地说它表现得相当好。这些结果都符合你的预期,或者当你评价自己是一个“含糊不清”的人时,你会看到什么。我也对谷歌 API 的质量感到惊讶,即使它设法抓取了许多含糊不清的音轨,并正确转录了相当大的一部分。我们可以得出结论,该模型能够在含糊说唱和正常或“经典”说唱之间做出明智的区分。我甚至自信地说,60%的时候,它都有效…每次都有效!

最后,尽管整体表现良好,但仍有很大的改进空间。例如,像 DMX 和李尔·韦恩这样的说唱歌手得分远低于人们的预期。当考虑更多因素时(如露骨的语言或俚语),分数可能会更准确。API 似乎也在速度上挣扎,这在阿姆的《哥斯拉》中表现得较低。这给我们带来了一些可以在“进一步研究”下进行改进的列表。

进一步研究

尽管我和我的朋友在这个项目上花了大量的时间,但仍然有巨大的改进空间。在这里,我列出了一些可以改进或可以进一步探索的东西。

更多数据

这可能是最重要的一条。在目前的项目中,我们每个艺术家只有大约 5 到 8 首歌曲,这是非常低的。由于提取、整理、转换和转录音频的任务非常耗时,我们受到资源的限制,无法进行更深入的研究。将每个艺术家的曲目数量增加到至少 20 首应该会给出更可靠的结果。其次,总体上包括更多的艺术家也是不错的。我们试图尽可能客观地选择“经典”说唱歌手(基于谷歌搜索结果),但我们知道很多读者会不同意,因为他们最喜欢的说唱歌手不在名单中,而他们不喜欢的艺术家在名单中。总之,艺术家人均时间和艺术家总数都应该增加。

更高的数据质量

除了数据量,质量也可以提高。不幸的是,由于振幅太低,我们不得不移除许多音轨。YouTube 上的音频质量差别很大。理想情况下,应该从更好的来源抓取音轨,以保证所有音轨的高质量和同等质量。

重新思考公式

用于计算 mumble 分数的公式目前非常简单。我们认为可以通过增加一些参数来改善。比如,露骨的语言起了作用。有些曲目中的脏话被删掉了。因此,虽然这些词被写在原始歌词中,但它们永远不会被 API 拾取。另一个因素可能是每秒钟词汇和字数的丰富程度。想象一下,我们用了 Lil Pump 著名的“古驰帮”,与其他曲目相比,这是不公*的。如果 API 能够正确地选择它,那么对于相同的文本/单词,他的分数将会提高数倍。相反,如果 API 会错过它,他将被惩罚多次。应该考虑到词汇量的更大/更小的变化和每秒更高/更低的单词速率。

创建 Kaggle 笔记本

在写这篇文章的时候,我很快意识到这可能会变成一篇很长的阅读。正如你在我的其他帖子中看到的,我通常倾向于解释我的分析中的每一步,使读者能够完全复制这个过程。为了不使它太长,我没有详细介绍每一个步骤。因为我的代码中有 API 证书,所以我也没有使用公共笔记本(例如使用 Kaggle)。这样做将使其他人更容易在项目上合作,用更多的数据扩展它或改进分析。如前所述,我上传了数据,你可以在这里找到。

其他改进

如果你能想到其他的改进或改编,请随意在下面的评论中提出,这可能会引发讨论或激发我的后续项目。

技术堆栈

Ffmpeg、Acapella extractor、Mp3cut.net、Python (Matplotlib、Seaborn、nltk、SoundEx、SciPy、PyDub、NumPy、Pandas)和 Power BI。

关于我:我叫布鲁诺,是欧盟委员会的数据科学顾问。你可以通过我的网址与我联系:https://www . zhongtron . me

我的朋友 Frederik Caenepeel 博士为这个项目做出了贡献,也可以在LinkedIn上找到。

使用深度学习检测 CERN CMS 实验中的μ子动量

原文:https://towardsdatascience.com/detecting-muon-momentum-in-the-cms-experiment-at-cern-using-deep-learning-934b0ef24586?source=collection_archive---------42-----------------------

理解大数据

图 CMS 束管的移除(图片由 Maximilien Brice/Julien Ordan/CERN 提供——来源: CERN

在欧洲核子研究中心 CMS 实验探测μ介子是一项重要的任务。欧洲核子研究中心的 CMS 物理项目深入研究了许多物理实验,通常预期会产生μ子。例如,研究著名的希格斯玻色子粒子的一种方法是通过一个衰变通道,在那里希格斯玻色子衰变为四个μ子。

由于μ子可以穿透几米厚的铁而没有明显的能量损失,它们很难被 CMS 系统的任何一层阻止。因此,μ子探测器是最外面的,远离相互作用点。当前μ子横向动量探测器桶μ子轨迹探测器使用查找表来估计μ子的横向动量。后者是使用伪快度η测量的,伪快度η是与带电粒子从这些碰撞中出现的角度相关的空间量,方位角φ是碰撞路径与 z 轴形成的角度。(来源: CMS 一级触发带有机器学习的μ子动量分配 —托马索·迪奥塔列维)

图 2:采用的坐标系

在这个水*上的μ介子的任何检测被称为触发

问题描述

需要更加复杂的技术来提高动量检测的精度以降低触发率。由于瞬发μ子光谱遵循指数分布,精度上的任何微小改进都可以显著减少触发的数量,特别是通过减少被误归类为高动量μ子的低动量μ子的数量。

这就是机器学习发挥作用的地方。通过应用更智能的算法,如神经网络、,我们可以提高触发系统的精度,以准确检测μ子及其相应的横向动量。(来源: CMS 一级触发带有机器学习的μ子动量分配——托马索·迪奥塔列维)

在下面的文章中,我们将应用几种深度学习方法来准确预测μ介子动量。我们将在 CMS 实验中使用来自阴极条室(CSC)的蒙特卡罗模拟数据。该数据集包含超过 300 万个利用皮媞亚产生的μ子事件。

探索数据集

我们检索的数据组织如下:

  • 87 个特征 : 84 个与探测器相关;3 个作为路径变量
  • CSC 内部有 12 个探测器面,每个探测器面有 7 个特征 (12*7=84)

这些功能组织如下:

  • 0–11:φ坐标
  • 12–23:角坐标
  • 24–35:弯曲角度
  • 36–47:时间信息
  • 48–59:环号
  • 60–71:前/后击
  • 72–83:面罩
  • 84–86:X _ road
  • 87:φ角度
  • 88 : Eta 角度
  • 89 : q/pt(横向μ子动量)——目标标签

在μ介子室内,有多个探测器站,如下图所示。这些探测器*面被组织在特定的室中。

图 3:CMS 象限的示意图(来源: CERN 文件服务器)

然而,我们只关心 CSC 室中的μ介子击中,因此只与 CSC 室相关的特征。

让我们首先删除那些不需要的特性:

现在我们已经删除了这些要素,接下来我们可以将所有要素放入一个紧凑的 Pandas 数据框中,以便于以后进行数据分析。

探索性数据分析

让我们用熊猫的描述方法来看一下数据统计:

表 1:具有缺失值的要素的统计数据

快速查看会发现一些特征,如φangle 1Theta angle1Bend angle1 有一些缺失值。让我们找出每个要素的空值的确切百分比:

图 4:缺失值分布

我们注意到前/后 1φ角度 1θ角度 1弯曲角度 1时间 1环 1 特征有超过 70%的缺失值!我们需要稍后删除这些特性,对于缺失值少于 25%的其他特性,我们将用每列的*均值填充缺失值。

接下来,我们将可视化所有特征的数据分布。

图 5:选定的特性直方图

我们注意到如上图所示,如果我们想要提高模型的学习速度,一些特征如 Theta angle1Theta angle2Theta angle3X Road1 需要转换成正态分布(使用标准化)。

预处理用于训练的数据

将问题框定为分类任务

不要试图应用回归来预测μ子动量值( q/pt ),让我们首先尝试将动量分成 4 类:0–10 GeV、10–30 GeV、30–100 GeV 和> 100 GeV ,并因此将问题构建为分类任务。

为了对动量进行分组,我们将使用目标特征的倒数的绝对值(pt/q) 。让我们来看看这个新生成的要素的数据分布

图 6:pt/q 的数据分布

如图所示,很明显存在不同大小的不同组。让我们使用 Pandas 的 cut 方法对数据进行聚类,并检查新生成的组分布。

图 7:目标类的数据分布

现在我们已经成功地将标签分组,我们可以观察到类不*衡,因此每当我们开始训练我们的神经网络以避免任何偏差时,我们都需要*衡它们。

将数据集分为训练集和测试集

接下来,让我们将数据分为训练和测试数据,我们将使用 90%-10%的分割。重要的是使测试集代表原始数据集中的目标类分布。因此,我们将使用 Scikit-Learn 中的 StratifiedShuffleSplit 方法来使训练数据和测试数据都代表类的原始分布,而不是随机分割我们的原始数据集。

让我们检查新生成的集合中的类分布:

表 2:比较原始、训练和测试集之间的类分布

如上表所示,训练集和测试集都代表原始数据集。我们现在可以安全地进入预处理的最后一步:准备管道

准备预处理管道

该管道将执行以下任务:

  1. 删除缺失值超过 70%的列
  2. 使用 Scikit-Learn 简单估算器用相应的方法估算缺失值的其他列
  3. 用 Scikit-Learn 标准定标器将数据标准化
  4. 将目标特征编码成四个一个热编码特征

以下是管道完整代码:

构建神经网络

我们将使用 Tensorflow 的 Keras 库来构建我们的神经网络。神经网络将有 5 个隐藏层,每层的神经元数量为 512、256、128、64 和 32 。我们还在网络中添加了脱落层以减少过度拟合。输出层将有 4 个神经元(与类的数量相同),我们将对每个输出神经元应用 softmax 激活函数,以获得每个类的概率

由于这是一个分类任务,我们选择的损失函数分类交叉熵,Adam 将被用作优化器:

让我们为模型设置一些回调,包括一个检查点回调提前停止回调,它们都将监控模型的验证准确性。我们将使用 25%的验证分割500的批量,并将训练 200 个周期。现在我们终于可以开始训练了!

现在我们已经完成了模型的训练,让我们来看看它在训练时期的性能演变。

图 8:分类器度量在训练时期的演变

看起来我们在验证集上达到了 84%的准确率。令人印象深刻!但如果说我从机器学习中学到了什么的话,那就是从来不依靠准确性,只依靠来判断模型性能。我们需要更深入地了解这个案例。

测试模型

让我们使用 Scikit-Learn 的分类报告来检查模型在训练集和测试集上的性能。它包括一系列重要的分类指标,包括精确度、召回率和 f1 分数:

表 3:列车数据评估报告

表 4:测试数据评估报告

令人印象深刻!似乎增加类别权重肯定会减少偏差,我们在测试数据上达到了 0.85 的加权 f1 分数!

回归实验

让我们尝试直接预测每个μ子动量的 q/pT 值,而不是将目标标签分成四组,因此将问题框架化为回归任务。我们只改变了模型的最后一层,用一个线性激活函数的输出神经元代替了 softmax 的 4 个神经元。

由于这是一个回归任务,我们将选择均方误差作为我们的损失函数,类似于分类任务,我们将使用 Adam 作为优化器。

让我们来看看回归模型在训练时期的性能演变:

图 8:模型训练的演变和训练时期的验证损失

让我们在训练集和测试集上检查模型的性能。我们将找到均方根误差,以便更好地了解这些值:

训练数据的均方根误差为 0.046,测试数据的均方根误差为 0.047 。一点都不差!与目标值相比,这些值似乎是相对可接受的,但肯定还有改进的空间。

未来方向

  1. 我们发现分类器模型在检测少数类方面不太好。因此,我们需要寻找更多的技术来使模型更少偏差(例如上采样少数类下采样多数类)。
  2. 我们可以通过网格搜索调整超参数来进一步提高我们的回归模型的性能。

最后的想法

在这个项目中,我们尝试了几种深度学习方法来准确预测μ介子动量。首先,在预处理用于训练的数据之前,我们研究了数据属性。然后,我们训练一个分类器来预测μ子动量类别,并使用多重分类度量来评估分类器对新数据的性能。接下来,我们训练了一个回归模型预测μ子动量值而不是它们的类别。这两种方法都相当成功,我们计划采用更先进的技术来减少模型偏差并提高性能。

原载于 2020 年 11 月 14 日【https://anisdismail.com】

探测颤动中的物体

原文:https://towardsdatascience.com/detecting-objects-in-flutter-4fe8cfccef14?source=collection_archive---------7-----------------------

实践教程,全面的指南

使用 tflite 和 SSD-MobileNet

照片由韦斯顿·麦金农Unsplash 上拍摄|只是一些:D 的物品

介绍

在本指南中,我们将使用 tflite 包和预训练的 SSD-MobileNet 模型在 Flutter 中开发一个应用程序,能够检测图像和实时摄像机流中的对象。这个应用程序能够离线检测对象。我们还将能够从应用程序中拍照,并将其输入到模型中进行检测。

[## rupakkarki 27/对象检测

使用 Flutter 和 TensorFlow Lite 的对象检测应用程序。GitHub 是超过 5000 万开发者共同工作的家园…

github.com](https://github.com/rupakkarki27/object_detection)

请注意,由于我繁忙的日程安排,我不再维护这个项目。最*版本的 Flutter 和 dependencies 中引入的突破性变化可能会破坏应用程序。但你可以自由选择回购,按照自己的方式改变事情。谢谢!

设置项目

如果您还没有安装,安装程序会在您机器上跳动。Flutter 网站上的这个指南是一个很好的起点。设置 Flutter 后,在终端中输入以下命令创建一个新项目。

$ flutter create object_detection
$ cd object_detection

现在,您可以在您喜欢的编辑器中打开您的项目。

安装软件包

在您的 pubspec.yaml 文件中,在 dependencies 部分下添加以下内容以安装所需的包。

image_picker: ^0.6.7
tflite: ^1.1.1
camera: ^0.5.8+7

我们使用 image_picker 从图库中选取图像,使用 tflite 运行我们的模型,使用 camera 包控制相机。你可以在 pub.dev 上读到更多关于他们的信息。

在您的应用程序级别 build.gradl e 文件(/android/app)中,在 android 块下添加以下行,以确保 Flutter 不会压缩您的模型或 tflite 包。

aaptOptions {
  noCompress 'tflite'
  noCompress 'lite'
}

模型

您可以从上面提到的 GitHub repo 或任何地方下载 SSD-MobileNet 模型及其标签,并将它们放在您的项目中。然后,在您的 pubspec.yaml 文件中添加您的资产。

assets:
  - assets/models/ssd_mobilenet.tflite
  - assets/models/labels.txt

初始化摄像机

该应用程序的主要功能是以这样一种方式创建的,即所有的摄像机在应用程序启动后立即初始化。然后,摄像机描述被传递给所有需要它的类。

初始化摄像机的主要功能

图像中的目标检测

为了检测图像中的对象,我们首先需要使用 tflite 包中的 Tflite.loadModel 方法加载模型。然后,我们需要从我们的图库中获取图像,或者通过启动相机从应用程序中拍摄一张图像。相机包提供了获取图像的方法,这两种方法都可以使用。

加载图像后,我们使用TF lite . detectobjectonimage方法将它输入到我们的模型中。该方法返回检测到的类别、置信度和兴趣点,这将帮助我们在对象周围绘制边界框。

各种操作的功能

绘制边界框

围绕检测到的对象绘制边界框的基本思想是使用来自模型的兴趣点和图像尺寸。

使用堆栈小部件,我们可以将边界框放在图像的顶部。在定位的小部件中,我们放置一个四周有边框的容器。我们还可以通过简单地添加一个文本小部件并将置信度转换为百分比,以百分比的形式显示检测到的类及其准确性。

边界框的代码

静态图像检测页面有两个浮动操作按钮。使用其中一个,我们可以直接从图库中挑选图像,并在上面运行我们的模型。使用另一个,一个相机被打开,我们可以拍照,并把它提供给我们的模型。

模型检测图像中的对象(图片由作者提供)

实时目标检测

实时检测对象有点类似于检测图像中的对象。视频流中的每一帧都被视为一幅图像,模型在其上运行。该模型每帧输出结果,边界框在图像流上被一遍又一遍地重画。

相机插件中的相机控制器对象有一个名为 startImageStream 的方法,可用于向我们的模型提供帧。在这个方法中,我们可以调用TF lite . detectobjectonframe方法,该方法获取相机流并在我们的模型中运行它。该方法的其余部分是相同的,即模型返回 detectedClass、confidence 和 poi,我们使用它们在相机流的顶部绘制边界框。

实时检测

实时检测(GIF 由作者提供)

结论

我们开发了一个能够使用 Flutter、 tflite 包和一个预训练模型来检测对象的应用程序。该应用程序并不完美,可能无法在所有图像上工作。我们可以通过训练我们自己的模型来改善这一点,该模型可以以更高的准确性检测更多的类,或者使用其他一些强大的模型。

尽管有这个障碍,该应用程序在图像和视频光照良好的情况下表现非常好。对于那些希望将机器学习和 Flutter 知识结合起来的人来说,这是一个非常好的项目。我们还可以使用谷歌的可教机器来训练模型对特定类型的图像进行分类或检测。

tflite 插件目前只支持 SSD-MobileNet 和 YOLO 进行物体检测。

你可以在这里 查看项目回购 。如果有任何问题,请随时打开问题或创建一个公关。欢迎并鼓励任何反馈或建议。

你也可以在这里 看看我的作品集

在 Java 中从胸部 x 射线图像中检测肺炎

原文:https://towardsdatascience.com/detecting-pneumonia-from-chest-x-ray-images-e02bcf705dd6?source=collection_archive---------52-----------------------

基于 Keras 和 Deep Java 库的图像分类

照片来自 Unsplash 上的国家癌症研究所

免责声明:这篇博文仅用于教育目的。该应用程序是使用实验代码开发的。该结果不应用于肺炎的任何医学诊断。此内容尚未经过任何科学家或医学专业人士的审核或批准。

介绍

在这篇博客文章中,我们展示了深度学习(DL)如何用于从胸部 x 光图像中检测肺炎。这项工作的灵感来自 Kaggle 上的胸部 x 光图像挑战一篇相关论文。在这篇文章中,我们通过关注企业部署来说明人工智能如何帮助临床决策。这项工作利用了使用 Keras 和 TensorFlow 与 Kaggle 内核训练的模型。在这篇博文中,我们将重点关注使用 Deep Java Library (DJL),一个用 Java 构建和部署 DL 的开源库,用这个模型生成预测。

软件设置

我们选择了 Keras 和 DJL ,两个用户友好的 DL 工具来实现我们的图像分类器。Keras 是一个易于使用的高级深度学习 API,支持快速原型制作。与此同时,DJL 为 Keras 用户提供了简单的 API 来在 Java 中部署 DL 模型。现在,让我们深入教程。

使用 Keras 训练并保存您的模型

第一步是训练图像分类模型。你可以按照这个内核中引用的指令来获得一步一步的指导。该模型试图通过目视检查胸部 x 光图像中的特征来识别肺炎。作为一个参考点,下面的图像比较了三个具有正常肺(左)、细菌性肺炎(中)和病毒性肺炎(右)的候选人之间的差异。[1]

图 1 据 论文图 S6,正常胸片(左)示双肺清晰,细菌性肺炎(中)示局灶性肺叶实变,病毒性肺炎(右)示双肺更弥漫性“间质”样改变。

训练过程包括 3 个步骤:准备数据、构建模型和训练模型。您可以使用此链接下载用于训练该模型的数据集。该模型由深度方向可分离的卷积层组成,具有 ImageNet 上的部分预训练权重。深度方向可分离的卷积层具有更少的参数,并且比可比较的 DL 模型更有效。我们还使用了迁移学习,这是一种流行的 DL 技术,它将针对一个问题训练的模型应用于另一个相关的问题。迁移学习利用在类似问题上已经学到的特征,而不是从零开始开发模型,并且快速产生更健壮的模型。对于我们模型中的前 2 层,我们使用了一个 VGG 网络的权重,该网络是在 ImageNet 上预先训练的,这是一个大得多的数据集。

你可以直接下载内核笔记本,在本地运行来生成模型。注意,我们需要将模型保存为 TensorFlow 保存的模型格式。你可以在笔记本的最后加上下面一行。有关在 DJL 使用 Keras 模型的更多信息,请参见如何在 DJL 导入 Keras 模型

model.save("best_model")

如果你想用预先训练好的模型直接运行预测,从下载这个模型开始。

使用深度 Java 库加载和运行预测

一旦有了训练好的模型,就可以使用 DJL 生成预测。完整代码见肺炎检测。您可以使用以下命令从命令行运行预测。使用-Dai.djl.repository.zoo.location指定模型的位置。

以下是输出示例:

下面几节将带您详细了解代码。

导入 DJL 库和 TensorFlow 引擎

要在 Keras 模型上运行预测,您需要 DJL 高级 API 库和底层 TensorFlow 引擎。它们可以使用 Gradle 或 Maven 导入。更多详情,请参见肺炎检测自述文件。以下示例使用 Gradle 来设置依赖关系:

负荷模型和运行预测

接下来,我们需要加载我们训练好的模型。DJL 提供了简单易用的 API 来加载模型。你可以使用我们的模型动物园来加载模型,或者从你的本地驱动器使用你自己的模型。以下示例使用本地模型动物园来加载模型并运行预测。这只用几行代码就可以完成。

在这段代码中,我们首先使用一个 Criteria builder 来告诉 model zoo 我们想要加载什么样的模型。我们在这里指定希望加载一个模型,将一个[BufferedImage](https://javadoc.io/doc/ai.djl/api/latest/ai/djl/modality/cv/util/BufferedImageUtils.html)作为输入,并预测一个[Classifications](https://javadoc.io/doc/ai.djl/api/latest/ai/djl/modality/Classifications.html)作为结果。然后我们可以使用ModelZoo.loadModel在模型库中找到匹配的模型。默认情况下,DJL 将在我们的内置库中寻找模型。我们需要告诉 DJL 查看一个自定义路径,该路径包含我们在培训部分获得的 TensorFlow SavedModel 格式。我们可以通过指定`【T3]来做到这一点。之后,我们创建一个新的预测器来运行预测并打印出分类结果。这非常简单明了。

定义你的翻译

当我们加载模型时,我们还想定义如何预处理模型的输入数据和后处理模型的输出数据。DJL 为这个函数使用了[Translator](https://javadoc.io/doc/ai.djl/api/latest/ai/djl/modality/cv/translator/package-summary.html)类。下面是实现过程:

转换器将输入数据格式从[BufferedImage](https://javadoc.io/doc/ai.djl/api/latest/ai/djl/modality/cv/util/BufferedImageUtils.html)转换为[NDArray](https://javadoc.io/doc/ai.djl/api/latest/ai/djl/ndarray/NDArray.html),以符合模型的要求。它还将图像的大小调整为 224x224,并在将图像输入模型之前,通过除以 255 使图像正常化。运行推理时,您需要遵循在训练期间使用的相同预处理过程。在这种情况下,我们需要匹配 Keras 训练代码。运行预测后,模型将每个类别的概率输出为一个数组。然后,我们将这些预测转换回我们想要的类别,即“肺炎”或“正常”。

下一步是什么?

就是这样!我们已经完成了对 x 光图像的预测。现在,您可以尝试构建更复杂的模型,并尝试使用更大的数据集进行学习。关注我们的 GitHub演示库twitter 获取更多关于 DJL 的文档和示例!

关于 DJL

DJL 是一个用 Java 编写的深度学习框架,支持训练和推理。用户可以轻松地使用 DJL 部署他们喜欢的模型,而无需为各种引擎进行额外的转换。它包含 ModelZoo 概念,允许用户在 1 行中加载深度学习模型。DJL 模型动物园现在支持 70 多个预先训练好的模型,如 GluonCV、HuggingFace、TorchHub 和 Keras。

NDArray 的加入使其成为 Java 中运行深度学习应用的最佳工具包。它可以自动识别您运行的*台,并判断是否利用 GPU 来运行您的应用程序。

从最新发布的版本来看,DJL 0.5.0 正式支持 MXNet 1.7.0、PyTorch 1.5.0、TensorFlow 2.1.0。它还有一个 PyTorch Android 的实验引擎。

参考资料:

[1] 通过基于图像的深度学习识别医疗诊断和可治疗疾病
【2】企业最常用的 10 种编程语言:2019 版
【3】胸部 x 光图像(肺炎)
【4】胸部 x 光图像的内核

利用深度学习从胸片中检测肺炎

原文:https://towardsdatascience.com/detecting-pneumonia-from-chest-x-rays-with-deep-learning-6b83b4a77ee8?source=collection_archive---------38-----------------------

建立各种模型,并使用预先训练的模型从胸部 x 光诊断肺炎

疾控中心在 Unsplash 拍摄的照片

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

2017 年有 256 万人死于肺炎。这些人中大约三分之一是不到 5 岁的儿童。世卫组织估计,这些过早死亡中有 45,000 例是由于家庭空气污染。随着诊断效率的提高,许多死亡可以减少。
这个项目的目标是创建各种机器学习和深度学习模型,以便在优化后,可以帮助放射科医生从胸部 x 光片中检测肺炎。

环境和工具

在整个项目中,我们将使用 python,因此建议您使用一些编辑器,如 Google Colaboratory,这些编辑器与 python 兼容,但也允许使用某些 python 包。

我们将使用 python 包:

  • Numpy
  • 熊猫
  • Tensorflow(版本 1.x)
  • Sci-Kit Learn 和 Keras
  • Seaborn 和 Matplotlib

我们将使用其他包来下载与构建模型无关的文件和辅助函数。要获得完整的列表,请查看下面附加的代码。

项目和代码

既然我们已经有了所有的介绍,让我们开始吧。

我们将从导入一些关键包开始,我们将在整个项目中使用这些包。我们还将为项目下载数据(在这种情况下,胸部 x 光图像)。

你可以在 Github 上找到完整的代码。

在开始构建各种模型之前,我们必须分析并熟悉我们的数据。让我们下载一个名为“元数据”的文件,它为我们提供了关于数据的关键信息。之后,我们将使用 pandas 库创建一个数据框(本质上是一个表),它将提供关于我们数据集中前五幅图像的信息。

作者图片

表格中的每一行代表一幅胸部 x 光图像。您可以看到三列:类别、拆分和索引。级别为 0 或 1,0 表示肺部健康,1 表示肺部有肺炎。索引是图像的标签,它告诉我们正在查看数据集中的哪个图像。

关于分裂,当我们教计算机如何做某事(在这种情况下诊断肺炎)时,我们必须通过给图像加标签来训练它。但是,我们也要通过给计算机不同的以前没见过的图像来测试计算机,让计算机来决定肺部有没有肺炎。因此,拆分列描述了图像是用于训练计算机还是测试计算机。下面是我做的一个图表,用来帮助区分这两者。

作者图片

现在,制作所给信息的图表,进一步分类每个类别中有多少张图片,并进行分割。我们将使用 pandas 方法“count”来显示该表,并且我们将使用 seaborn“count plot”来显示一个对数据进行分类的图表。

作者图片

作者图片

如图表所示,1200 个肺是健康的,1200 个肺有肺炎。在这 1200 个中,一千个将用于训练模型,另一千个将用于测试模型。

现在我们已经完全了解了我们的数据属于哪一类,我们可以继续绘制一些图像,以查看胸部 x 射线将会是什么样子。

运行此功能,允许您绘制图像:

在这里,您可以通过运行下面的代码来调用该函数。它下载训练和测试数据(从我们之前定义的函数中),并根据索引(与图像相关的数字)绘制图像。注意第 4 行的 1)。“数据”是图像,而“标签”部分是数字 0 或 1,表示患者是否患有肺炎。

我特别选择了一张健康的照片,和一张肺部有肺炎的照片。您可以随意使用索引来查看其他图像。

左图是健康的肺,右图是肺炎。作者提供的图片

简单的机器学习模型

现在,我们已经完成了对数据的检查和分析,我们可以继续构建一些机器学习模型。我们将从简单的开始,使用 K-最*邻和逻辑回归分类器。

k-最*邻

K-最*邻的关键概念是,当我们看到一个未知的例子时,我们也会看到这个未知的最接*的例子,并预测它是同一个例子。

作者图片

上图显示了 K-最*邻分类器。例如,如果 k=1,与所讨论的形状最接*的(单个)形状是圆形。因此,如果 k=1,形状是圆形。然而,如果 k=3,与所讨论的形状最接*的 3 个形状是 2 个矩形和 1 个圆形。所以,如果 k=3,形状是长方形。

逻辑回归

逻辑回归用于预测概率,这些概率随后会变成一个类别(0–1)。在线性回归中,预测的 y 值可能会超过 0–1 范围(使用连续直线)。但是,在逻辑回归中,预测的 y 值不能超过 0–1 的范围,因为它呈“s”形。举例来说,请看下图。

图片由 Michaelg2015 在公共领域发布

x 轴显示学生学习的小时数,y 轴显示他们是否通过了考试(0 或 1)。然而,逻辑曲线的 y 轴显示了他们是否通过考试的概率。如你所见,曲线预测学习少的人会不及格,而不是及格,反之亦然。

构建机器学习模型

我们将使用 sci-kit learn 库来构建这些模型,特别是 KNeighborsClassifier 和 LogisticRegression 方法。

建立机器学习模型的步骤是加载模型,拟合(或训练)模型,用模型预测病人是否患有肺炎,最后对模型进行评估。

正如您所看到的,在第 6 行和第 7 行,我们加载或初始化了模型。然后,在第 10 行和第 11 行,我们使用训练数据训练模型。对于预测,模型根据 test_data 预测 test _ labels 是什么。这就是为什么,为了检查准确性分数,我们基于 test_data 检查我们的预测如何。

现在,我们可以运行模型并检查准确性分数。请注意,您可以通过更改邻居的数量来提高 KNN 分类器的性能。

准确度分数

很明显,这些模型的准确度分数很低。因此,这些不是解决这个问题的最佳模型。所以,我们必须采取不同的方法。

卷积神经网络

卷积神经网络是一种特定类型的神经网络,用于查找图像之间的模式。我将简要描述 3 个关键部分:

  1. 盘旋
  2. 联营
  3. 完全连接的层

盘旋

卷积核是一个权重矩阵,类似于全连接层的权重矩阵。通过将权重与图像输入中的相应像素值逐元素相乘,将卷积核应用于输入。这将有助于锐化图像。

迈克尔·普罗特克在公共领域发布的图片

联营

卷积层输出仍然太大,神经网络无法做出任何预测。我们可以通过汇集来减少它的规模。它将卷积层中的某些像素组合起来,并将其合并成一个像素。最大池化是最常见的池化示例之一,它将输出分成多个分块,并取每个分块的最大值。

图片由 Aphex34 在公共领域发布

完全连接的层

完全连接层将单个神经元中的每个神经元连接到下一层中的所有其他神经元。最后一层使用输出概率的激活函数,如 softmax 或 sigmoid,计算机将使用这些函数对图像进行分类。

图片由 Kjell Magne Fauske 在公共领域发布

构建我们的卷积神经网络

我们将使用 Keras 库来构建我们的模型。在你建立你的模型之前,运行这两个函数,这将允许你绘制精确度和损失。

现在,我们已经运行了这些函数,让我们来构建模型。您必须了解一些关键组件,它们是:

  • add(Conv2D()) :执行卷积的层。它需要三个参数。第一个是它执行卷积的次数,第二个是卷积的维数,第三个是激活函数。对于第一层,请确保也指定了输入形状。
  • 添加(MaxPooling2D()): 执行最大池的层。它接受 1 个参数,即组合像素的尺寸。
  • add(Flatten()): 将图像展*成一维数组。
  • add(Dense()): 添加一个全连接层。它接受两个参数,该层中神经元的数量,以及该层的激活函数。
  • add(Dropout(): 关闭一定数量的神经元,以减少过度拟合。接受一个参数,通常是一个介于 0 和 1 之间的数字,当转换成百分比时,就是前几层中被切断的神经元的百分比。
  • 我们对每一层(除了输出层)的激活函数将是 ReLU 。对于我们的输出层,激活函数将是 sigmoid ,它输出我们的患者是否患有肺炎的概率。
  • 我们的损失将是 binary_crossentropy ,我们将使用优化器 RMSprop ,定制为 1e-4 的学习速率和 1e-6 的衰减。

太好了!现在我们已经构建了模型,让我们运行它,看看它做得有多好。

作者提供的图片

从上面的图中可以看出,我们的模型做得相当好。然而,它的表现还不够好,不能用于临床。您可以从这里继续修补模型,以提高准确性和减少损失。但是,确保避免过拟合(当计算机记忆训练数据时,因此它在测试数据上表现很差。

如何阅读图表

x 轴显示了历元的数量。只要 x 轴上有小数,就可以忽略它,因为只允许完整的历元(整数)。在 y 轴上,您有您正在测量的值。可能是损耗,精度等。黄线表示训练数据,而蓝线表示验证数据。绿线代表该指标的最佳时期。

迁移学习

对于我们的迁移学习,我们将使用 VGG16。VGG16 是在“ImageNet”分类问题中使用的“专家”模型。在 ImageNet 中,参赛者被要求建立能够区分 1400 万个图像类别的模型,其中有超过 20,000 个类别可用。

VGG16 被允许研究这 1400 万张图像 74 次。然后,它能够比人类更好地猜测图像的真实标签。

我们将带着 VGG16,让它在我们的 x 射线上训练。希望他们在 ImageNet 问题上的经验将有助于区分肺炎和我们的 x 光片。

第一行将下载 VGG16 的卷积算法。然后我们将不得不声明它是可训练的,通过使用一个“for”循环,确保我们可以训练每一层。之后,我们必须添加和自定义完全连接的层,因为 VGG16 包含固定的卷积层。

现在,运行它,让我们看看它的表现如何!

如您所见,我们的模型的性能随着 VGG16 的使用而显著提高。您还可以看到,模型在 1-2 个时期后开始过度拟合。这是因为 VGG16 是预先训练好的,这使得它更有效和准确,但同时,它也更容易过度拟合。

结论

我们开始这个项目是通过分析我们学到的数据,并了解有多少图像患有肺炎或健康。我们还将数据集分为训练数据和测试数据。之后,我们构建了简单的机器学习模型,这些模型能够根据我们对其进行的训练做出明智的决策。最后,我们构建了卷积神经网络来提高模型的精度和效率。之后,我们使用一个预先训练好的模型作为我们的迁移学习来进一步优化我们的模型。现在,我把它留给你。你如何继续改进这个模型,使它能够用于医疗实践?也许你甚至可以在一些现场数据上运行它,并应用数据扩充。

参考文献

[1]匿名,分类(未标明),可教授

2无名氏,肺炎 (2019),世界卫生组织

2 B. Dadonaite 和 M. Roser,肺炎 (2019),数据中的我们的世界

[3] C .阿奇,利用卷积神经网络进行胸部 X 线肺炎检测 (2020),Medium.com

[4] R. Prabhu,对卷积神经网络(CNN)的理解—深度学习 (2018),Medium.com

感谢 Inspirit AI 教会了我所有的技术细节并提供了数据集。

用 CNN 建立图像分类模型

原文:https://towardsdatascience.com/detecting-pneumonia-using-convolutional-neural-network-599aea2d3fc9?source=collection_archive---------40-----------------------

用卷积神经网络检测肺炎

正常和肺炎 X 射线的特征图像

在这篇博客中,我将概述如何使用卷积神经网络建立一个简单的图像分类模型,以从胸部 X 射线图像中检测肺炎的存在。

肺炎是一种常见的感染,它使肺部的气囊发炎,导致呼吸困难和发烧等症状。尽管肺炎不难治疗,但及时诊断至关重要。如果没有适当的治疗,肺炎可能会致命,特别是在儿童和老年人中。胸部 x 光检查是诊断肺炎的一种负担得起的方法。开发一种能够从 X 射线图像中可靠地对肺炎进行分类的模型,可以减轻需求高的地区的医生的负担。

数据

Kermany 和他在 UCSD 的同事们利用深度学习,基于胸部 X 射线和光学相干断层扫描,主动识别疾病。我们使用他们研究中提供的胸部 x 光图像作为我们的数据集。

[## 标记的光学相干断层扫描(OCT)和胸部 X 射线图像的大型数据集

确保下载该数据集的最新版本,以保持准确性。该数据集包含数千个…

data.mendeley.com](https://data.mendeley.com/datasets/rscbjbr9sj/3)

数据结构

数据文件夹的结构如下。

DATA
│ 
├── train
│    ├── NORMAL
│    └── PNEUMONIA
│
├── test
│    ├── NORMAL
│    └── PNEUMONIA
│
└── validation
     ├── NORMAL
     └── PNEUMONIA

在删除没有适当编码的图像文件后,我们的数据集中有 5,639 个文件,我们将这些图像中的 15%用作验证集,另外 15%用作测试集。我们的最终训练集包括 1,076 个正常病例和 2,873 个肺炎病例。

数据探索

如果您对在图像数据上运行探索性数据分析的步骤感兴趣,请参见我以前的帖子。

[## 图像分类的探索性数据分析思路

图像数据的可视化模式

towardsdatascience.com](/exploratory-data-analysis-ideas-for-image-classification-d3fc6bbfb2d2)

我们的探索性数据可视化显示,肺部炎症通常会阻碍心脏和胸腔的可见性,从而在肺部区域周围产生较大的可变性。

第一个模型

作为我们的基线模型,我们将构建一个简单的卷积神经网络,它在将图像调整为正方形矩阵并将所有像素值归一化为 0 到 1 的范围后接收图像。完整的步骤如下所示。

现在我将详细解释每个步骤。

1.缩放数据

keras.image.ImageDataGenerator()拍摄图像并根据参数创建增强数据。在这里,我们只是要求它将所有像素值重新调整为 0 到 1,而不指定任何其他增强参数。与flow_from_directory结合,生成器以指定的格式从目录中调用图像,然后创建重新缩放的数据。

2.构建模型架构

keras.models.Sequential()启动顺序模式。该模型将顺序处理添加的层。

Conv2D层是卷积层,它接收输入并通过指定数量的滤波器。内核大小指的是过滤器的尺寸。因此,在本例中,我们的 2562561 图像(1 表示通道数,RGB 图像有 3 个通道,而灰度图像有 1 个通道)中的每个连续 33 像素组将通过 32 个过滤器,生成 32 个大小为 256256*1 的特征图。

因为 256 不能被 3 整除,所以padding = ‘same'用于在窗口周围添加相等的填充。

activation = 'relu'意味着我们将调整后的线性单位指定为激活函数。简单来说,我们是在告诉层把我们所有的负值都转换成 0。

然后,我们将卷积层的这些输出馈入池层。MaxPooling2D层通过仅保留卷积输出的每个 22 矩阵的最大值来提取卷积输出。现在,我们将有 32 个大小为 128128*1 的特征地图。

现在,我们需要将这些四维输出缩小到一个数字,它可以告诉我们是将图像分类为肺炎还是正常。我们首先将层展*成一维,然后让它们通过越来越小的致密层。sigmoid 函数作为激活函数应用于最后一层,因为我们现在希望模型输出一个输出是否为肺炎的概率。

3.配置

我们已经定义了模型的架构。下一步是决定这个模型的目标,以及我们希望它如何实现。使用model.compile,我们告诉模型使用梯度下降来最小化二元交叉熵损失(对数损失,想想逻辑回归)。这里,我们使用 RMSprop 算法通过自适应降低学习速率来优化这个过程。在后来的模型中,我使用了 AMSGrad 算法,它对我们的问题表现得更好。

4.拟合数据

最后,我们完成了模型的构建。是时候拟合我们的训练数据了!默认情况下,每个时期将运行 32 个批次。我们设置EarlyStopping是为了防止过度拟合。如果我们的验证损失连续 5 个时期没有减少,该模型将停止运行。我将restore_best_weights设置为真,这样在这 5 个时期之后,它将恢复到最高的性能权重。它在我们之前创建的验证生成器上测试其性能。

5.估价

我们的第一个模型显示了 94%的准确性,预测了验证数据的类别,对数损失为 0.11。根据下图,我们可以看到培训损失有改进的空间,因此我们可以增加模型的复杂性。此外,验证损失似乎徘徊在 0.1 左右。我们可以尝试通过使用数据扩充来模仿添加更多数据,从而提高可推广性。

这里有一个完整的代码来绘制拟合模型的损失图和精度图。

模型 2

现在,我们将尝试实现数据扩充,并为我们的模型增加更多的复杂性。

数据扩充

这一次,我们向列车图像数据生成器添加了一些参数。因此,现在我们的生成器将通过对原始图像集应用指定范围内的不同旋转、亮度、剪切和缩放来为每批图像创建新图像。

模型复杂性

我们还通过增加三组卷积层和池层来增加模型的复杂性。建议随着图层的进展增加卷积过滤器的数量。这是因为当我们在这些层中移动时,我们试图提取更多的信息,因此需要更大的过滤器集。这个类比类似于我们的大脑处理视觉信息的方式。随着信号从我们的视网膜移动到视交叉,到丘脑,到初级视觉皮层,然后通过下颞叶皮层,神经元的感受野在每一步都变得更大,对复杂信息越来越敏感。

估价

我们的第二个模型显示了 97.3%的准确性,在验证集上的对数损失为 0.075。看来我们的调整确实改进了我们的模型!让我们在我们的测试集上测试它,以确保它们能很好地推广到看不见的数据。

最终性能

我们的模型以 97.8%的准确度预测了测试集中的 X 射线图像的类别。它成功地识别了 97.9%的肺炎病例。

结论

我们的模型表明,在给定数据集的情况下,使用卷积神经网络,它能够正确检测出接* 98%的肺炎病例。但尤其是对于生命受到威胁的医疗问题,即使只有 2%的漏诊病例也不应该简单地不予考虑。为了理解我们的模型的局限性,下一步重要的工作是对模型失败的地方进行详细的调查。

使用自然语言处理检测来自美国参议员的带有政治偏见的短语(教程)

原文:https://towardsdatascience.com/detecting-politically-biased-phrases-from-u-s-senators-with-natural-language-processing-tutorial-d6273211d331?source=collection_archive---------70-----------------------

气候危机、劳动人民和负担得起的健康?还是共产主义者,自由主义者,堕胎?

早在 3 月份,我观察了 2020 年疫情选举前的投票模式,并将其与相对两党对医改法案的投票进行了比较。现在,新冠肺炎疫情已经开展了几个月,其他事件正在成为焦点——即反对警察暴行和种族不公正的示威游行。此外,我们离共和党和民主党全国代表大会只有几个月的时间,选举随后就要到来。那么,政治家们在谈论什么呢?

为了掌握这一点,我决定用 VoteSmart.org 的(我从 T4 的一篇研究论文中得到这个想法)来看看政治演讲,并看看党派短语。帖子将按如下方式进行:

  1. 集合语料库
  2. 提取常用短语
  3. 衡量政治两极化短语

步骤 1:集合语料库

我从一个维护良好的数据集开始,这个数据集包含国会中的每个人,其中包含一个链接到他们的投票智能页面的 ID。为了便于阅读,我的目标是为每位立法者制作一个文件夹,其中包含他们所有发言的文本文件。我提到的研究论文使用了几种类型的演讲,但我包括了从 2020 年 1 月开始的所有类型的公开声明。

本教程将侧重于文本分析,但你可以在这里找到抓取语料库的代码。我用它从 VoteSmart 收集了超过 10,000 条独特的声明和演讲(我删除了推文和重复的声明),不过如果你对它进行微调,并不仅仅包括参议员,你还可以收集更多。以下是伯尼·桑德斯三月份接受 CNN 采访时的一段文字样本:

COOPER: Now to our interview with Senator Bernie Sanders. He is campaigning in the Super Tuesday state of Minnesota.Senator Sanders, thanks for being with us. You just heard Mayor Buttigieg endorsing Vice President Biden. Klobuchar is expected to do the same tonight, as is Beto O'Rourke. How does the consolidation of the moderate vote affect your plans moving forward, especially since Senator Warren shows no signs of getting out?SEN. BERNIE SANDERS (D-VT), PRESIDENTIAL CANDIDATE: Well, Anderson, I think, as you know, from day one we have been taking on the establishment, whether it is the corporate establishment, you know, Wall Street, the drug companies, the insurance companies, the fossil fuel industry, or the political establishment.And let me be very clear, it is no surprise they do not want me to become president because our administration will transform this country to create an economy and a government that works for all of the people, not just the 1 percent. It will not be the same old same old....

这是有组织的语料库的样子:

步骤 2:提取常用短语

下一步是通过将文本分割成标记来提取短语。我使用了 scikit-learn 的令牌矢量器,因为它有一些很棒的内置特性。下面是设置一切看起来有多简单:

from sklearn.feature_extraction.text import CountVectorizer
from nltk.corpus import stopwordsnltk_stop_words = stopwords.words('english')tf_vectorizer = CountVectorizer(max_df=0.8, min_df=50,
    ngram_range = (1,2),
    binary=True,
    stop_words=nltk_stop_words)

停用词(即nltk_stop_words)有助于去除无信息的单词,常见的例子有“of”、“to”和“and”我使用 NLTK 的列表是因为 scikit 的内置列表有一些已知的问题。然后,tf_vectorizer (tf 代表“术语频率”)通过一些设置进行初始化:

  • max_df=0.8意味着排除出现在 80%或更多文档中的短语(类似于停用词,它们不太可能提供信息,因为它们太常见了)
  • min_df=50意味着该词必须在语料库中出现至少 50 次才能被纳入分析(我使用 50 次,因为我提到的研究论文也是如此,尽管您可以尝试不同的临界值)
  • ngram_range=(1,2)意味着包括一个单词和两个单词的短语(你可以很容易地将它设置为(1,3)来包括三元组/三个单词的短语
  • binary=True表示只计算一个单词在给定文档中出现的次数(即 0 或 1),而不是精确计算它出现的次数(即 0 或 1 或 2 或 3 或…)
  • stop_words=nltk_stop_words插入前一行中设置的 NLTK 停用词表,这样就不包括“of”和“to”这样的词

使用文件 I/O 将文本放入列表后,tf_vectorizer可以将文本转换成只有一行的短语矩阵:

term_frequencies = tf_vectorizer.fit_transform(texts_list)

现在,term_frequences是一个矩阵,包含来自矢量器的每一项的计数。我们可以把它变成一个数据框架,让事情更直观,看到最常见的短语:

phrases_df = pd.DataFrame(data=tf_vectorizer.get_feature_names(),columns=['phrase'])phrases_df['total_occurrences']=term_frequencies.sum(axis=0).Tphrases_df.sort_values(by='total_occurrences',ascending=False).head(20).to_csv('top_20_overall.csv',index=False)

生成的 csv 文件如下所示:

步骤 3:衡量政治两极化短语

首先,我们需要将民主党和共和党撰写的文章分开,然后得到它们的词频矩阵。熊猫数据框架让这变得相当容易:

dem_tfs = tf_vectorizer.transform(texts_df[texts_df.party=='Democrat'].text.tolist())rep_tfs = tf_vectorizer.transform(texts_df[texts_df.party=='Republican'].text.tolist())

现在到了有趣的部分:找出哪些短语带有政治色彩。以下是解释这种方法的文章部分(关键公式突出显示):

你可能会注意到公式中只有两个变量:民主党人撰写的文本的短语概率和共和党人撰写的文本的短语概率。因此,为了计算党派偏见分数,我们只需要计算这两个概率,我将其简称为p_demp_rep。一旦我们有了这些,每个短语的偏差分数就是:

bias = (p_rep - p_dem) / (p_rep + p_dem)

我使用了一个基本的概率度量:包含一个短语的文档数除以文档总数。有一些更复杂的方法来衡量概率,但根据我对论文的阅读,这可能是作者所做的。

快到了!现在,我们只需要将偏见分数放入之前的phrases_df数据框架中,然后我们就可以轻松地查看一些常见的党派短语。当我第一次运行这个时,一些名字短语,如“参议员哈里斯”和“参议员帕蒂”是最具党派性的——一个抄本的人工制品。为了解决这个问题,我做了一个过滤器,以确保至少有三名参议员使用党派短语:

top_rep = phrases_df.sort_values(by='bias_score',ascending=False).head(100)top_rep['n_senators'] = top_rep.apply(lambda x: len(texts_df[texts_df.text.str.contains(x.phrase)].person.unique()),axis=1)top_rep = top_rep[top_rep.n_senators > 2]

现在,我们终于可以看到党派短语了!你会注意到他们与党派议程保持一致,例如,民主党人谈论气候危机和医疗保健,而共和党人谈论堕胎。

这里是最倾向于民主党的短语,以及我们计算的分数和概率。

和最倾向共和党的短语:

有了这些短语和它们的偏见分数,你可以衡量推特、演讲、文章等的政治偏见。通过计算党派短语的频率:如果一篇文章大量谈论未出生者、自由主义者和共产主义者,它可能倾向于共和党,而如果一篇文章谈论气候危机、劳动人民和可负担的健康,它可能倾向于民主党。

感谢阅读!所有代码都是可用的,语料库也将很快可用,在这个资源库:

[## 流氓/党派用语

分析美国参议员的党派短语。有助于 jackbandy/党派短语的发展,创造一个…

github.com](https://github.com/jackbandy/partisan-phrases)

检测流数据中的实时和无监督异常:一个起点

原文:https://towardsdatascience.com/detecting-real-time-and-unsupervised-anomalies-in-streaming-data-a-starting-point-760a4bacbdf8?source=collection_archive---------12-----------------------

图 1:智能设备生成实时数据,这些数据可能会出现异常,如果我们不检测并正确管理它们,就会导致我们做出错误的数据驱动型决策。图片来自 pixabay.com。

传感器通过收集各种系统中的数据来实现物联网( 物联网 )。数据通常以实时方式产生,然后我们可能会发现自己被迫进行实时处理(流数据挖掘 [1】)。系统的行为并不总是恒定不变的,而是可能表现出一种不寻常的、明显不同于先前正常行为的行为( 异常【2】)。异常检测是有价值的,但在实践中,它可能会变成一项难以可靠执行的任务。

本文并不声称是方法和解决方案的详尽列表,但是对于那些第一次处理这个问题并且需要简单、可理解和可伸缩的解决方案的从业者来说,它确实是一个简单的切入点。异常可能存在于真实世界的应用中,例如欺诈预防、金融、能源需求或消耗、电子商务、网络安全、医疗诊断、社交媒体、预测性维护或故障检测等。本文分析了一些处理异常的算法。它们是 Welford 的算法,基于四分位数的解决方案,基于 z-score 度量的解决方案,以及基于机器学习的解决方案,称为半空间树(HST)。前 3 个解决方案基于统计指标/度量,而最后一个来自机器学习领域。

流媒体:游戏规则

批处理学习相反,批处理学习【】中假设数据是静止的(历史数据是可用的),并且模型不连续地将新信息集成到已经构建的模型中, 流学习 对实时处理施加约束:

  • 流中的实例(数据)在线到达(通常一次一个实例),并且最多可以被读取一次,这构成了处理数据流的最强约束,并且系统必须决定当前实例是应该被丢弃还是存档。
  • 只有选定的过去实例可以通过将它们存储在内存中来访问,相对于数据流的大小,内存通常较小。当设计流学习算法时,我们必须考虑几个算法和统计因素。例如,我们必须面对这样一个事实,即由于我们不能存储所有的输入,我们不能撤销根据过去的数据做出的决策。
  • 每个实例的处理时间必须小且恒定。
  • 处理算法必须产生一个模型,该模型等同于由批次处理算法产生的模型。

这组约束是大多数现有的用于 bacth 处理的异常检测算法不适用于应用的原因。

在大多数实际情况下,数据由一个连续的单变量数据集组成,其中关于异常的监督信息(有多少,在哪里)是不可用的。

威尔福德算法

Welford 的方法是一种可用的单程方法,用于计算运行方差或运行标准差。它可以通过查看 N 个和 N-1 个实例的*方差之和的差来导出。不需要为第二次传递存储数据[3]。为了将 Welford 的方法用于异常检测问题,我建议加入以下简单的修改。

我们创建一个上限(UL)和一个下限(LL)。当在线*均消耗(橙色实线) 克服这些限制中的任何一个(或 X 乘以在线标准偏差,那么我们将该读数(实例)归类为异常。限值(黑色虚线)可计算如下:

UP =在线*均消费+X *在线标准差

LL =在线*均消耗量-X *在线标准偏差

X 越高,我们假设的假阴性(FNs)就越多,而 X 越低,我们获得的假阳性(FPs)就越多。因此, X 的选择不是微不足道的,并且在该参数 X 与 FPs 和 FNs 之间存在权衡。然后,你需要定义 X=1,2,3,4,… 等等。取决于这个决定。如您所见,每次新实例到达时,在线*均消耗和限制都会在线更新。

代码:原方法的简单实现可以在这里找到。

注释:读数=0 应视为异常与否。您还注意到,根据读数和 X. 的不同,LL 可能低于 0,如果这对于您的图表是个问题,可以很容易地调整这一事实。请注意,如果您获得许多连续的异常,您可能需要将它们视为唯一的异常,或者甚至视为“异常”周期。最后,我想提一下使用大小为 w、的滑动窗口的可能性,并计算它上面的所有指标。

基于四分位数的解决方案

箱线图是一种基于一组数字汇总来表示数据集分布的流行方法:最小值、第一个四分位数(Q1 / 第 25 个百分位数)、中值、第三个四分位数(Q3/75 个百分位数)和最大值。这种表示可以告诉您异常值及其值。

图 5:箱线图的元素。图片修改自维基共享

四分位距(IQR) 从 Q1 到 Q3,我们可以计算最大值和最小值如下:

最大值=Q3+1.5*IQR

最小值=Q3-1.5*IQR

(关于 boxplots 和 quartiles 的更多详细信息,我建议您查看以下文章:https://towardsdatascience . com/understanding-box plots-5e 2 df 7 bcbd 51)

然后,我们可以将所有高于最大值或低于最小值的点视为异常值。我们可以在线计算这些数字汇总。

代码:如你所见,这个解决方案很容易实现。对于懒惰的人来说,在已知的存储库或其他网站上有许多这种方法的可用实现。

注意:这里我们也可以使用前面提到的滑动窗口。

基于 z 分数度量的解决方案

标准分数或 z 分数( z )给出了一个数据实例离均值有多远的概念,即原始分数高于或低于总体均值多少个标准差。

实例 x 的 z 值可以计算为:z =(x-μ)/σ

标准分数也可以通过在线方式计算。但这一次,我们使用了滑动窗口,然后被称为运行或移动 z 分数。给定此窗口大小 w ,移动 z 值将是每个实例偏离*均值的标准偏差数,其中*均值和标准偏差仅在之前的 w 实例中计算。

代码:如你所见,这个解决方案很容易实现。对于懒人来说,这个方法在众所周知的源代码库中有很多可用的实现。

半空间树

半空间树(HST) [4]是一个快速的单类异常检测器,用于进化数据流。它只需要正常的数据进行训练,并且在异常情况及时扩散时工作良好。如果在时间窗口内将异常打包在一起,效果并不好。这种技术是随机 HST 的集合,其中每个树结构都是在没有任何数据的情况下构建的,这使得该技术非常高效,因为它在适应进化的数据流时不需要模型重构。

这种技术是增量训练的,并且使用滑动窗口 w. 其他相关参数是集合中的树的数量( nt ),以及用于声明异常的阈值( th )。任何高于此阈值的实例预测概率都将被声明为异常:分数越低,当前实例越有可能是异常的。要了解更多关于所有参数的信息,请查看下面的代码部分,或这篇论文

代码:这个解决方案可以在 Creme 或者 scikit-multiflow 中找到,这两个框架都是用 Python 实现的。

其他方法

它也值得特别注意一些其他已知的方法,其中包括:

  • 局部异常因素(LOF,见此处更多细节),
  • 单变量参数方法,如 Grubb 检验(*均值可能是离群值的 mak)或 Tietjen y Moore 检验(可能会遭受淹没),
  • 不要忘记检查[5],在那里已经进行了许多检测器之间的广泛比较。

结论

  • 正如您已经意识到的,所有这些技术都需要调整一个或多个参数,这些参数会影响它们在 FPs 和 FNs 方面的性能(参见 F1-score 性能指标)。
  • 由于这是一个无人监管的场景,因此为了评估该技术的性能,以及正确地找到 FPs 和 FNs 之间的*衡,具有该领域的广泛知识是非常重要的。在任何情况下,他们的评价都是主观的,这就是领域知识至关重要的原因。
  • 每种技术根据不同的标准发现异常,因此它们不一定与其分类相匹配(异常是/否)。但是我们可以找到相似之处,例如在基于度量的解决方案和 T2 的解决方案之间。
  • 最后,您应该考虑将这些技术组合在一起的可能性,因为它们可以互补并检测不同类型的异常。

参考

[1] 比费特,a .,霍尔姆斯,g .,柯克比,r .,&普法林格,B. (2010)。Moa:海量在线分析。机器学习研究杂志,11(5 月),1601–1604。

2钱德拉,v .,米塔尔,v .,T15 库马尔,V. (2008 年 12 月)。序列数据异常检测技术的比较评估。2008 年第八届 IEEE 数据挖掘国际会议(第 743-748 页)。IEEE。

[3] Knuth,D. E. (2014)。计算机编程艺术,第 2 卷:半数值算法。艾迪森-韦斯利专业版。

[4] S.C.Tan,K.M.Ting,和 T.F.Liu,“流数据的快速异常检测”,载于《国际人工智能联合会议论文集》, 2011 年,第 22 卷,第 1 期,第 1511-1516 页。

[5] 艾哈迈德,s .,拉文,a .,波弟,&阿迦,Z. (2017)。流数据的无监督实时异常检测。神经计算,262,134–147。

用变形金刚探测国家支持的推特巨魔

原文:https://towardsdatascience.com/detecting-state-backed-twitter-trolls-with-transformers-5d7825945938?source=collection_archive---------63-----------------------

一个在定制数据集上微调 Distilbert 模型的实际用例,并针对更常用的模型(如逻辑回归和 XGBoost)测试其性能

web 应用程序插图作者:蔡金汉

随着 2020 年美国大选的临*,对国家行为者通过社交媒体和其他在线手段干预选举的担忧再次成为人们关注的焦点。

Twitter 是俄罗斯用来干涉 2016 年美国大选的一个主要*台,很少有人怀疑俄罗斯、中国和其他国家会再次转向这个*台,发起新的造谣运动。

这篇文章将概述如何通过使用自定义数据集微调 transformer 模型( Distilbert )来构建 state troll tweets 检测器。这建立在我的早期项目的基础上,使用“经典”的机器学习模型和简单的单词袋方法来检测 state troll 推文。

我还将比较微调后的 Distilbert 模型与逻辑回归和 XGBoost 模型的结果,看看 transformer 模型在实际用例中是否真的表现得更好。

剧透提示:微调后的 transformer 模型的表现明显好于 Log-Reg 和 XGBoost 模型(当然,它们也不是没精打采的),并且在面对来自第三国的 state troll 推文时表现得更好。请跳到第 4 部分查看结果。

1.基础事实、数据来源、模型和回购

首先:我如何确定谁的推文被认为是国家影响力运动的作品?在这种情况下,地面真相是由 Twitter 的选举诚信团队建立的。

该项目中使用的 state troll 推文是那些已经由 Twitter识别并自 2018 年以来逐步向公众发布的推文。我从 Twitter 上选择了六组 state troll 推文——中国和俄罗斯各三条——我对它们进行了清理、合并,并缩减到 5 万行

我通过使用 Tweepy 收集 175 个账户,创建了一组等价的 5 万行真实推文,这些账户由经过验证的用户和我亲自检查真实性的用户组成。由此产生的 100,000 行 state troll-plus-real tweets 的组合数据集被进一步分成通常的训练测试验证集,分别为 70:20:10 的标准比例。

完整的细节在我的笔记本里,为了简洁起见,我就不在这里重复了。此处提供完整回购。微调是在一个 Colab Pro 账户上完成的,花了大约五个半小时。

微调过的 Distilbert 模型对于 Github 来说太大了,但是我已经上传了一个副本到 Dropbox 上,供那些只想尝试这个模型的人使用。如果您希望创建一个更大的训练集,那么必须从 Twitter 下载包含 state troll tweets 的六个原始 CSV 文件。

2.数据准备

应该指出的是,数据清理和准备过程中的关键假设会影响结果。这些假设对于保持项目范围的实用性是必要的,但是如果您不同意这些假设,请同意根据您自己的首选清理规则对不同版本的数据进行切片。

我对这个项目的主要数据清理规则:

  • 排除非英语推文,因为工作假设是目标受众是讲英语的。我还想防止模型根据语言做出预测。
  • 排除转发。
  • 排除文本清理后少于三个单词的推文。

出于实际原因,我还将最终的组合数据集保持在 100,000 行。我最初尝试用 600,000 行数据集对 Distilbert 进行微调,结果导致 Colab 笔记本反复崩溃和/或显示非常长且不切实际的运行时间。如果不能获得更多的计算/硬件,这个项目更雄心勃勃的版本是不切实际的。

3.使用自定义数据集微调 DISTILBERT 模型

对于这个项目,我选择了无壳蒸馏模型(更小,更容易管理),并使用拥抱脸的教练来完成任务。在运行了太长时间的几次尝试后,我放弃了尝试进行超参数搜索,并希望在未来的某一天回到这个主题(查看这里的讨论)。

所涉及的步骤相当简单,如我的回购的笔记本 2.0 中所述。代码大部分基于拥抱脸这里这里的优秀例子和文档。

微调的直接结果当然令人印象深刻:

'eval_accuracy': 0.9158421345191773,
 'eval_f1': 0.9163813100629625,
 'eval_precision': 0.9098486510199605,
 'eval_recall': 0.9230084557187361

我对验证集运行了一个快速测试——保留了 10,000 行,而模型根本没有看到——优秀的分类指标几乎没有变化:

'eval_accuracy': 0.9179, 
'eval_f1': 0.9189935865811544, 
'eval_precision': 0.9178163184864012, 
'eval_recall': 0.9201738786801027

为了进行更彻底的比较和分析,我使用用于微调 Distilbert 模型的相同数据集训练了两个独立的逻辑回归和 XGB 分类器模型。让我们看看他们在同样的测试中表现如何。

4.微调 DISTILBERT 与 LOG-REG 和 XGB

腌制的 Log-Reg 和 XGB 模型可以在我的 repo 的“pkl”文件夹中找到。我的笔记本详细记录了他们的优化过程,这里是,这里是。这里就不赘述了,只强调两个模型在训练和网格搜索中的得分都在 0.8 以上。虽然明显低于微调 Distilbert 模型的分数,但我认为这两个模型做得足够好,可以提供足够的比较。

下面的图表通过混淆矩阵显示了所有三个模型在验证集(10,000 行,包括 5,061 条 state troll 推文和 4,939 条真实推文)上的表现。

图片作者:蔡展汉

一眼看去,很明显,微调过的 Distilbert 模型(最左边)是表现最强的,比 Log-Reg 或 XGB 模型准确地挑选出了更多的状态 troll 和真实 tweets。更重要的是,Distilbert 模型的假阳性和假阴性数量大约是 log-reg 和 XGB 模型的一半。

因此,尽管这三个模型的性能指标似乎很接*,但通过混淆矩阵来看,它们的分类能力差距变得非常明显,这让我们更好地了解它们在分类成千上万条推文中的表现。

4.1 3 种型号的附加测试

所有三个模型都接受了来自中国和俄罗斯的真实推文和国家巨魔推文对半分的训练。事实上,我们并不知道 Twitter 上真人和巨魔的实际比例。更重要的是,state troll 推文可能来自任何国家,语气、语言和主题的变化可能会显著影响分类器将真实推文与来自国家支持的竞选活动的推文区分开来的能力。

如果暴露在来自第三国的国家巨魔推文中,这三个模型中的哪一个会保持得更好?为了找到答案,我通过三个模型运行了一个新的数据集——包括来自伊朗的 1000 条 troll 推文和来自美国用户的 993 条真实推文。这个新的数据集是从我在同一主题上做的早期项目中创建的。

图片作者:蔡展汉

正如所料,所有三个分类器在暴露于他们以前没有见过的伊朗国家巨魔推文时,他们的性能显著下降。

但在我看来,微调后的 Distilbert 模型仍然相当不错。与 Log-Reg 或 XGB 模型相比,它不仅正确地挑选出了更多的 troll 和真实推文,而且假阴性(模型认为是真实推文的 troll 推文)的数量也不是非常多。

这在 Log-Reg 模型中尤其成问题,该模型将一半(1000 条中的 501 条)的 troll 推文归类为真实推文,而实际上它们是由国家支持的运营商所为。XGB 模型在这方面稍好一些,但不是很好,假阴性的数量(468)明显高于假阳性的数量。

对于我在早期项目中训练的模型来说,这是一个特别明显的问题,这意味着在一个特定的州演员的 troll 推文中训练的分类器非常善于发现来自所述州演员的新的、看不见的推文。但是,一旦来自另一个国家运营商的 troll tweets 被注入混合,分类器的性能就会显著下降。

微调后的 Distilbert 模型并没有完全克服这个问题,但它足够好地支持了一个可以更好地“概括”的模型的希望。如果你有足够的计算资源在一个更大的数据集上训练一个 transformer 模型,这个数据集包括迄今为止 Twitter 识别的所有国家的 state troll tweets,那么有理由认为,上述模型可能在我们在这篇文章中尝试的测试中做得更好。

不幸的是,这是一个假设,我将不得不在另一个时间进行测试。

5.结论

当然,对 Twitter 上国家影响力活动的检测不仅仅包括对推文的审查。国家巨魔通常会留下更大的泄露秘密的迹象,比如账户创建的(协调)日期,或者他们发推的时间。照片和迷因的使用越来越多,也使得检测过程变得更加棘手。

但是在他们的推文中发现趋势和隐藏的结构将继续是一个主要的关注领域。与更流行的或传统的分类器相比,微调的 transformer 模型在这项任务中表现得更好。

当然,在资源和时间方面有所取舍。对大多数用户来说,在一百万行 tweets 上微调 transformer 模型所需的硬件并不容易获得,更不用说这是否是处理这项任务的最有效方式了。

6.奖励部分:网络应用

我尝试将微调后的 Distilbert 模型作为一个简单的 web 应用程序的一部分进行部署,但很快发现免费托管帐户没有足够的磁盘空间来在托管模型的基础上安装 pytorch。

但是我已经将必要的文件上传到 repo,以便任何想在本地机器上尝试的人使用。只要确保从 Dropbox 下载微调后的模型,并将其移动到“app”文件夹。

Gif 作者:蔡钦汉

和往常一样,如果你在这篇文章或我之前的文章中发现了错误,请联系我:

  • 推特:蔡振鸿
  • 领英:【www.linkedin.com/in/chuachinhon

检测在线社交网络中的可疑账户

原文:https://towardsdatascience.com/detecting-suspicious-accounts-in-online-social-networks-48eabf4c75b6?source=collection_archive---------38-----------------------

基于特征的分类方法

图片来源:www.bluecoat.com/

*年来,社交媒体的覆盖范围和受欢迎程度大幅上升。许多社交媒体*台拥有数百万用户。就像他们说的,好的会带来坏的。除了吸引真正的订户,在线社交网络也吸引了不良行为者的注意。僵尸程序和恶意账户占据了用户群的很大一部分。幸运的是,就像真实用户一样,虚假用户也会在数据中留下痕迹,从而能够检测到这些不需要的和潜在危险的帐户。

在这篇文章中,我描述了不同的虚假用户场景,以及如何使用基于特征的分类技术来检测这些用户,正如研究论文中所解释的那样。

检测个人虚假账户

一般来说,人类的行为与假账户或机器人账户不同。如果这种行为差异可以在数字或分类属性中捕捉到,那么机器学习技术就可以应用于检测真假。这是检测恶意账户的基于特征的分类方法的本质。

在账户层面检测真实或虚假状态的洗钱过程有 3 个组成部分。

  1. 功能设计

网络中的单个用户和用户组可以用两类特征来描述:

  • 注册时或注册前后出现的属性-个人资料特征
  • 随着时间发展的属性——与网络中其他用户的联系、活动或行为模式

根据检测假冒用户的时间敏感性,设计的功能可能来自上述一个或两个类别。如果限制虚假用户与真实用户的交互是至关重要的,那么仅使用简档特征的方法是有用的。

研究和调查有助于通过增加用户了解来更好地进行功能设计。

2.功能选择

在 OSN(在线社交网络)中,可能有大量属性与一个账户相关联——使用所有这些特征可能会变得计算量很大。在一些特征中可能存在冗余,或者一些特征可能不是用户状态的良好预测器。

特性选择解决了其中的一些问题。包装器和过滤器方法通常用于包括最佳预测器。为每个属性分配一个权重,所选择的属性是那些权重高于某个阈值的属性。

3.模型训练和评估

在分类任务中表现良好的一些算法——随机森林、决策树、支持向量机、朴素贝叶斯和神经网络。从特征选择步骤确定的加权属性可以应用于这些算法。常用的指标有精度、召回率和 F 值。

表演

对于所使用的数据集,考虑到 F-score 和精度,随机森林算法表现良好。随着权重的增加,其他算法也开始表现得更好。当使用权重高于 50%的特征时,考虑到精度,SVM 给出了最好的预测,而朴素贝叶斯在 F 分数度量中表现最好。

检测由同一代理创建的虚假账户群

在大规模的 OSN 中,一个坏演员可以创建几十到几千个恶意账户。像大多数虚假用户检测技术一样,对每个账户进行预测,可能不具有可扩展性或效率。在这种情况下,集群级检测是合乎需要的。

合法用户群显示出档案模式的多样性,而由单个参与者创建的虚假账户群显示出相似的属性分布和频率。因此,描述整个聚类的工程特征允许检测虚假账户的聚类。

预测每个用户的状态和一个组的状态的方法之间的主要区别是特征的级别——个体或集群。

接下来描述在集群上操作的基于分类的机器学习流水线。有 3 个主要组件。

群集检测 ML 管道

  1. 聚类生成器

该组件获取帐户的原始列表,并构建帐户聚类及其原始特征。该模块有 3 个用户指定的参数 a)最小和最大集群大小 b)注册账户的时间跨度(例如,过去 24 小时),以及 c)集群标准(例如,注册 IP 地址)。

该组件的输出是一个帐户表,其中每一行代表一个帐户,并包含用户名、组织、教育和帐户集群特有的集群标识符等特性。

集群生成器还使用个人帐户的假或真状态来将集群标记为假或真。阈值“x”决定分类标签—分类中的虚假帐户少于 x %,则它是真正的分类。

2.个人资料特征化

该模块将每个聚类的原始数据转换成代表该聚类的单个数字向量。它被实现为一组从原始特征中提取信息的函数。这些特征可以是

a)基本分布特征——每列的统计测量。数值特征的*均值或四分位数,类别特征的唯一值的数量

b)模式特征—将用户生成的文本映射到分类空间(例如电子邮件地址中的模式)

c)频率特征——每个特征值在所有单个账户中的频率,以及它们在这些频率上的分布。合法帐户的群集有一些高频率和一些低频率的数据,然而,恶意帐户的群集在它们的数据频率上显示较少的变化。

3.账户计分器

第三个组成部分是训练模型,并根据以前未见过的数据评估它们的性能。该模块可以在训练模式评估模式下运行。输出为模型描述和评估指标(训练模式)或聚类得分(评估模式),即由虚假账户组成的聚类的可能性。

绩效和评估指标

考虑的回归方法 1)具有 L1 正则化的逻辑回归 2)具有径向基函数核的支持向量机 3)随机森林

当考虑由 AUC 和 95%精度的召回测量的预测性能时,随机森林表现最佳。采用 RBF 核的 SVM 在 AUC 值方面也有不错的表现,但是它的召回@p95 不如 random forest。逻辑回归的性能最差,因为它是线性分类器,不能很好地模拟模式中的非线性。

基于特征的分类方法的考虑

用户行为模式很少是固定不变的,它们会随着时间的推移而发生变化,通常是对应用程序内外因素的反应。攻击者也一样!他们修改自己的内容和活动模式,以逃避检测。基于特征的技术易受此影响,必须定期进行多样化以跟上变化的模式。

使用分类器时,高维(非常大量的特征)数据可能导致计算成本增加。这可以通过使用降维或特征子集选择等特征降维技术来缓解。

结论

基于特征的分类方法是检测机器人和其他恶意用户的常用方法。它可以很好地扩展到大型 osn,并提供良好的性能。基于图形的技术也常用于检测虚假用户,但是基于特征的方法和简档属性允许早期检测。有许多分类算法可以迭代和调整性能。像 SVM 神经网络这样的组合可以进一步改善预测。总的来说,基于特征的分类提供了一个多样化的工具箱,可以调整并应用于多种情况。

[1]:埃拉扎布,艾哈迈德&马哈茂德,马哈茂德&赫夫尼,希沙姆。(2016).基于最小加权特征集的 Twitter 虚假账户检测。《国际计算机、电气、自动化、控制与信息工程杂志》2016 年第 10 卷第 1 期。

[3]:哈立德、萨拉&埃尔-塔齐、尼亚马特&莫赫塔尔、霍达。(2018).检测社交媒体上的虚假账号。3672–3681.10.1109/bigdata . 18666 . 186686866616

检测异常数据:共形异常检测

原文:https://towardsdatascience.com/detecting-weird-data-conformal-anomaly-detection-20afb36c7bcd?source=collection_archive---------31-----------------------

共形预测和共形异常检测框架介绍(附代码)

怪异的数据很重要。通常在数据科学中,目标是发现数据的趋势。然而,考虑医生查看肿瘤图像、银行监控信用卡活动或使用摄像头反馈的无人驾驶汽车,在这些情况下,知道数据是否怪异或异常可能更重要。怪异数据更正式地称为异常,并且在数学上可以被认为是从用于生成训练数据的分布的尾端生成的数据。通俗地说,我们的模型没有准备好处理这些奇怪的数据,因为它从未被训练过这样做,导致模型错误地对待这些数据。最终结果是——医生可能看不到恶性肿瘤,欺诈性的信用卡活动可能不会被发现,无人驾驶汽车可能会做出错误的决定。接下来的挑战是检测和消除这些异常。

为了举例说明这一点,让我们考虑图 2中显示的简单二维数据。其中每个圆圈代表训练数据,并根据 10 个可能的类别进行着色。黑色十字是在 2D *面上均匀随机生成的测试数据,其标签目前未知。一个模型如何知道哪些测试数据点应该被标记为异常并被丢弃,以及哪些可以被准确地分类?一种方法是使用聚类算法,并忽略距离每个聚类质心超过预定义异常阈值的新数据;然而,设置这些阈值需要微调,并经常导致许多假阳性异常检测[1]。相反,我们更喜欢一种超参数少且易于解释的方法,这种方法独立于数据集和手头的任务。

图一。上面的数据是随机构建的,用来说明训练数据(标记=圆圈)和测试数据(标记=十字)。在这个场景中,异常检测器的目标是将每个测试数据点分类为异常或不异常。

本文将描述一种相对新的、有效的、可扩展的方法,通过称为共形异常检测(CAD) 的过程来检测异常数据,该过程构建在共形预测(CP) 框架上。CP 适用于任何监督任务,其中每个数据由一个输入-输出对表示;然而,我们不需要测试输入的标签来确定它是否异常。此外,CP 和 CAD 具有与几乎任何算法家族(神经网络、SVM、决策树等)一起工作的优势。)和任何类型的任务(回归或分类)。CP 框架也有很好的统计解释,并且只有一个超参数,这使得它可以扩展到各种情况。除了介绍基本理论之外,本文还提供了执行 CAD 的代码。链接可以在下面的【资源】 中找到。对于 CP/CAD 的正式数学定义,我推荐查阅[1]。

这篇文章涵盖了什么

  1. 共形预测(CP)框架
  2. 共形异常检测(CAD)
  3. 从这里去哪里

资源

  1. Google Colab 笔记本: 一个简单的 CAD 实现

第一节。保形预测

通常,回归或分类模型在给定输入的情况下预测单个输出,回归模型返回连续输出,而分类模型返回离散输出。乍一看,这似乎很奇怪,但是 CP 框架返回的不是单个值,而是一组看似合理的输出。例如,对于回归,输出是潜在值的范围,而对于分类,输出是所有可能标签的子集。您可能想知道这有什么用——我们不是对输出更不确定了吗?实际上,通过一些基本的假设,我们可以验证我们的测试输入的真实输出将落在预测的一组可信输出中,并具有预期的置信度。使用这个 CP 框架作为异常检测机制的基础,我们可以确定地确信是否将新的测试输入标记为异常。

那么做一个 CP 框架需要什么呢?该框架只需要三个特定的要素:一个训练数据集、一个显著性水*(ϵ)和一个为我们的每个输入产生不一致分数的不一致度量。我们将在简单分类示例的上下文中逐一查看这些组件。

成分 1:训练数据集

在监督任务中,训练数据只是输入-输出对,其中输入通常表示为具有 m 样本和 n 自变量或特征的 m x n 矩阵,输出通常表示为具有 m 样本和 d 因变量的 m x d 矩阵。我们的训练数据集由 250 个输入-输出对组成,每个输入有 2 个特征,每个标签都是集合{0,…,9}的成员。训练数据*均分布在 10 个类中,每个类有 25 个数据点。很简单。

成分 2:显著水*ϵ

显著性水*与统计显著性有直接的相似性,统计显著性通常被用作实验中确定是否拒绝零假设的阈值。为了理解 CP 框架上下文中的显著性水*,让我们首先考虑它是如何使用的。记住,CP 框架计算一组潜在的标签,而不是为一个新的测试输入产生一个单一的输出预测。假设训练数据和测试数据是独立且同分布 (I.I.D .),错误概率或我们测试数据的真实标签不在那组潜在标签中的概率等于显著性水*。因此,显著性水*允许我们将预测集解释为置信区间。这就是我们(1-ϵ)%确信,给定我们的独立同分位数的假设,真正的标签在我们预测的集合中)

如果你仔细观察,你可能会注意到在图 1 中。违反了测试数据和训练数据之间的 I.I.D 假设。然而,这个例子是用来说明不管这个假设如何,CP 仍然可以用来检测异常(尽管统计保证消失)。在现实生活中,假设测试数据和训练数据之间的 I.I.D .很少是准确的;然而,这种假设也很少被违反。提到 I.I.D .假设的要点是,它允许对我们的预测集进行统计保证。实际上,使用可交换性鞅[5]在线测试 I.I.D 假设是可能的,可交换性鞅[5]接受一系列 p 值而不是单个 p 值,并且仅由于一系列小 p 值而增长,这意味着大量奇怪的输入同时进入。如果测试分布与训练分布相同,这显然是不常见的。鞅可用于拒绝可交换性假设(也是 I.I.D .假设),并检测出大于某个阈值的异常[4]。

成分 3:不合格度量(NCM)和不合格分数(α)

不一致测量(NCM)是我们测量陌生感的方式。理论上,NCM 可以是给每个输入分配不符合分数 α 的任何实值函数。这甚至可以是一个简单地返回随机不符合分数的函数;然而,我们倾向于根据其效率来评估 NCM,即其返回小的、有区别的预测集的能力。当给定新的输入时,随机 NCM 可能会返回无信息的预测集。相反,我们更希望 NCM 能够有意义地测量物体之间的相似性和不相似性。

NCM 通过计算一个值来计算不合规分数,该值考虑了相对于其他输入子集的特定输入。该子集可以包括其余的训练数据和测试输入(即,除了所考虑的输入之外的一切)。我们将较大的不合规分数解释为更奇怪,即更有可能是异常。

可能的 NCM 的一个例子是 k-最*邻函数,它计算输入的 k-最*邻的*均距离(例如欧几里德距离)。例如,如果输入 1 到类 0 的 5 个最*邻的*均距离是 25,而输入 2 到类 0 的 5 个最*邻的*均距离是 100,我们会认为输入 2 比输入 1 对类 0 更陌生。通常,流行的 NCM 是到同一类中的 k 个最*邻居的*均距离与到不同类中的 k 个最*邻居的*均距离的比率,从而捕获类内和类间的相似性和不相似性。

计算 P 值

一旦选择了合适的 NCM,CP 框架就可以用于预测新测试输入的一组潜在标签。为此,CP 框架为每个可能的标签计算 p 值。p 值是具有至少与测试输入一样大的不符合性度量的训练输入的归一化比例。情商。1 显示了如何计算单个 p 值。

方程式 1 。对于每个可能的标签(k=10),计算所有可能输入(n=250)和测试输入的不合格分数,并使用这些分数计算 p 值。在这个例子中,我们将得到 10 个 p 值。

最后,如果对应于每个 p 值的标签的 p 值大于或等于指定的显著性水*,则该标签被包括在预测集中。换句话说 根据我们的共形分数【1】,如果我们的训练集的重要部分比我们的测试输入更陌生,则标签被添加到我们的预测集。

共形预测的一些有用和无用的性质

已经提到的有用的性质是 CP 产生一个我们所处的置信区间(1-ϵ)%确信真正的标签存在于我们预测的集合中。另一个有用的属性是 CP 框架在 I.I.D 假设下校准良好,这意味着即使训练集用测试输入更新(即测试输入的真实标签被确定)并且收集了新的测试输入,这两个预测集的误差也将是独立的。因此,给定足够的测试输入,我们的错误率将接*ϵ.如果我们的训练数据足够大,并且 I.I.D .是真实的,大数定律告诉我们,真实的错误率可能已经被ϵ.精确地估计出来了

CP 框架的一个明显的缺点是,它必须为每个新的测试输入重新计算保形分数,这可能是耗时的,尤其是如果我们的不符合性度量是复杂的。一种解决方法是使用归纳保形预测(ICP)框架,该框架使用单独的训练集(称为校准数据集),不需要对每个新输入进行重新计算,对于大型数据集更实用。

第二节。共形异常检测(CAD)

共形异常检测(CAD)建立在 CP 框架上,可用于执行异常检测。如果您遵循了上一节的内容,CAD 应该很容易理解。我们来看算法。

共形异常检测(CAD)算法

输入/输出:CAD 算法的输入是显著性水*ϵ和一组输入,包括训练集和新的测试输入。输出是一个布尔变量,指示测试输入是否异常。

  1. NCM 为每个输入分配一个非一致性分数,该非一致性分数是该输入与其余输入之间相似性的度量。
  2. CAD 为我们的测试输入计算一个 p 值,它是大于或等于我们的测试输入( Eq)的不合格分数的数量的标准化比例。2 )。
  3. 如果计算的 p 值小于我们的显著性水*ϵ.,则测试输入被标记为异常换句话说,如果一个输入比我们训练集的一个重要部分更奇怪,那么它就被标记为异常。

****方程式 2。计算 CAD 的 p 值。

情商。2Eq 来说应该很熟悉。1 用于计算 CP 框架的 p 值。CP 中的 p 值和 CAD 中的 p 值之间的主要区别在于,CP 生成一组 p 值,每个 p 值对应一个可能的标签,而 CAD 只为每个测试输入提供一个 p 值。

回到例子

让我们回顾一下之前的分类示例。让我们假设ϵ为 0.025,并考虑我们的训练数据集有 250 个输入输出对。让我们选择其中一个黑叉作为新的测试输入。我们可以使用 10 个最*的邻居为 251 个输入中的每一个分配一个不符合分数。为此,我们可以计算一个 251 x 251 距离矩阵,并对行进行排序,使得最*的距离在第一列(该距离矩阵的第一列被忽略,因为它将始终为 0,因为欧几里德度量总是产生非负值,并且当两个输入相同时为 0)。然后,我们通过计算距离矩阵每一行中接下来的 10 个元素的*均值,来计算一个大小为 251 x 1 的不合格分数数组。然后,我们对这个*均 k-最*邻数组中的元素大于我们的测试输入的不一致性分数的次数进行求和。接下来,通过将总和除以 251 来计算我们的归一化 p 值。最后,如果 p 值小于 0.025,则测试输入被视为异常。

****图二。显示了使用具有该特定参数化的 CAD 来确定我们的假测试数据是否异常的结果。根据 CAD,红叉被视为异常,蓝叉被视为有效输入。

****图二。CAD 算法发现 21/25 的假输入被认为是异常——那些被标记为符合(非异常)的输入是直观的。

幸运的是,我们可以看到图 2** 中的结果。有道理。CAD 倾向于将所有远离类簇的测试输入标记为异常,而将所有位于类簇中的测试输入标记为有效测试数据。对于更高维的数据,尽管我们不能在不执行降维的情况下可视化结果,但是同样的原理也适用。**

CAD 的有用属性

CAD 优于典型异常检测技术的原因有很多。与许多异常检测技术不同,CAD 只有一个阈值超参数ϵ,它代表统计显著性水*,而不是异常阈值。在实践中,指定置信度阈值而不是异常阈值减少了执行异常检测所需的假阳性和微调的数量。其次,CAD 可以被解释为一个零假设测试,其中ϵ控制异常检测器的灵敏度。也就是说,如果我们可以合理地假设训练输入和测试输入是同分布的,那么ϵ就是应该拒绝零假设的比率,即期望 CAD 将随机生成的测试输入标记为异常的比率。这在实践中很有用,因为对于安全相关的任务,如信用卡欺诈检测或自动驾驶应用,我们可以增加ϵ以提高 CAD 的灵敏度。因为它是建立在 CP 框架上的,所以当不能假定 I.I.D .时,同样的限制也适用。在这种情况下,鞅可以用来测试独立同分布,并从 p 值序列中确定异常[5]。

第三节。从这里去哪里

希望您发现这次讨论内容丰富且有趣。如果您想了解更多,有几篇研究论文继续研究异常检测中使用的 CP 框架。已经提到的是比 CP 框架更有效的非正式共形预测(ICP)框架。但是,ICP 的一个缺点是,它可能无法生成与 CP 一样准确的预测集,并且它需要将训练数据分成校准和训练数据集,如果数据有限,这可能会很困难。一篇解释使用 CP 和 ICP 框架进行异常检测的论文可以在这里 [1]找到。此外,虽然我没有真正深入研究,但对于高维数据,通常使用一个模型来产生共形分数,如这篇使用神经网络产生共形分数的[论文](http://Papadopoulos, Harris, Volodya Vovk, and Alex Gammermam. "Conformal prediction with neural networks." 19th IEEE International Conference on Tools with Artificial Intelligence (ICTAI 2007). Vol. 2. IEEE, 2007.)或这篇在医疗诊断背景下使用随机森林的论文【3】。这就是为什么保形预测如此有用的一个原因——只要你能提取有意义的不合规分数,它就可以与任何类型的模型一起使用。

我的母校范德比尔特大学写的另一篇伟大的论文对变分自动编码器(VAE)的潜在空间进行了采样,不仅为给定的测试输入提供了一个 p 值,还提供了几个用于鞅测试的 p 值[4]。我强烈建议你去看看那本书,因为它也对 CP/ICP 做了很好的、简洁的解释。

感谢您的阅读!像往常一样,对于任何问题或顾虑,请随时在下面留下评论。我所有文章的目标都是帮助人们理解和使用这项技术,所以我很乐意帮忙。干杯!

引文

[1]拉克萨马尔、里卡德和约兰·福尔克曼。"感应共形异常探测用于异常子轨迹的连续探测."数学与人工智能年鉴74.1–2(2015):67–94。

2帕帕多普洛斯、哈里斯、沃洛佳·沃夫克和亚历克斯·甘默尔曼。"用神经网络进行保形预测."第 19 届 IEEE 人工智能工具国际会议(ICTAI 2007 年)。第二卷。IEEE,2007 年。

[3] Devetyarov 和 I. Nouretdinov。"基于医学诊断的随机森林分类器学习的可靠预测."第六届 IFIP 工作组会议记录。第 12 卷。

[4]蔡、和谢诺丰·库特苏科斯。"学习型信息物理系统中的实时非分布检测."arXiv 预印本 arXiv:2001.10494 (2020)。

[5] Fedorova,Valentina 等,“在线测试可交换性的插件鞅” arXiv 预印本 arXiv:1204.3251 (2012)。

利用多普勒雷达径向速度探测风切变

原文:https://towardsdatascience.com/detecting-wind-shear-using-radial-velocity-of-doppler-radar-e10e4ae440?source=collection_archive---------45-----------------------

推导公式,选择最佳有限差分和源代码

照片由 Kelvin YanUnsplash 上拍摄

风切变是速度和/或方向突然改变的风。我在之前的 帖子 中已经讨论了很多关于风切变的内容。能够探测风切变的众多工具之一是多普勒雷达。多普勒雷达利用多普勒效应来计算周围的风。但是我们将得到的只是一个径向速度(标量,远离将导致< 0 值,而另一方面对于靠*的风将具有> 0 速度),而不是作为笛卡尔矢量的风(南北、东西和上下分量)。通常的风切变公式是矢量运算。那么我们如何使用雷达来探测或计算风切变呢?我们将在这里讨论它。我们将使用众多风切变雷达产品之一,HSHEAR

**HSHEAR** 产品

遗憾的是我们无法获得实际的风矢量,但我们仍然可以通过径向速度监测风的变化来检测风切变。风切变的本质是变化,记住。当我们说“风的变化”时,我们指的是空间的变化。

在数学中,如何表达空间的变化?它是

或者“状态”的梯度(在每一维度)。我们所说的水*剪切(HSHEAR)乘积的量纲当然是水*量纲(南北和东西),而“状态”是径向速度(Vr),所以方程变成

现在我们得到了每个维度的变化。我们想知道的是变化的幅度或者说风的变化有多大。很简单,就是向量的长度。

单位向量可以被抵消,因为我们*方了它。所以更简单的形式是

由此我们得到了许多风切变雷达产品的公式HSHEAR,1。

数值解

基本上,我们都知道,计算机甚至不能解决最基本的微分方程。所以我们必须把我们的HSHEAR公式转换成数字形式。最简单的方法是使用有限差分。有 3 种有限差分:

前进差

向后差异

中枢差异

其中i是维度中f(状态)的指标数据,h是维度的分辨率。想象我们有网格形式的f

我们会选择什么?当然是误差最小的公式。而且是中央差!为什么?所以基本上,你可以从泰勒级数得到所有的有限差分,截断误差最小的是中心差分。证明?就当练习自己试试吧。我不会在这里详细说明,因为会有相当多的方程弹出。

让我们用中心差分代替之前HSHEAR公式中的所有微分方程。

这里ij分别是 x 和 y 维度上的索引。hxhyx(东西)和y(南北)维度的分辨率。

源代码

事实上,如果你不在乎这是如何运作的,你可以跳过所有的解释,只看这一部分。是的,最重要的部分,给我看看代码!基于我们的数值解,这里是代码

关于示例数据,您可以在这里下载

上面这个脚本的结果会是这样的。

在上面的图中,通常没有风切变发生。你可以看到这个情节从无到有,逐渐变成一个点,然后看起来像一个甜甜圈。这是雷达扫描方案的效果。这就是我们在雷达数据中所说的“沉默锥”。我想(如果我有心情的话)我们会讨论天气雷达是如何工作的。就目前而言,这就足够了。

所有关于雷达的代码和资料,包括我们以前的代码和数据,都可以在我的 GitHub 知识库这里访问。再见!

使用 CNN 和类激活图从胸部 X 射线扫描检测新冠肺炎存在的尝试

原文:https://towardsdatascience.com/detection-of-covid-19-presence-from-chest-x-ray-scans-using-cnn-class-activation-maps-c1ab0d7c294b?source=collection_archive---------12-----------------------

作者:Souradip Chakraborty

图 1:冠状病毒病 2019, 来源

冠状病毒病 2019 ( 新冠肺炎)是由严重急性呼吸综合征冠状病毒 2 引起的高度传染性疾病。这种疾病于 2019 年 12 月首次起源于中国武汉,自那以来,它已经在全球范围内传播,影响了超过 200 个国家。影响如此之大,以至于 T21 世界卫生组织(世卫组织)宣布正在进行的新冠肺炎疫情为国际关注的突发公共卫生事件

截至 2020 年 4 月 1 日的日,全球超过 200 个国家共有 873,767 例确诊病例,其中 645,708 例活跃病例, 43,288 例死亡病例(来源: 维基百科 )。

图 2:冠状病毒(新冠肺炎)地图。 来源

各国政府正在努力关闭边境,实施接触者追踪,识别和接纳受影响者,隔离可能的病例,但在大多数国家,受病毒影响的人数呈指数增长,不幸的是,预计在大量临床试验后开发和应用药物/疫苗之前,这一数字还会增加。

图 3a:冠状病毒在几个国家的传播速度。 来源

虽然研究表明,社会距离可以显著减少传播和*坦的曲线,如图 3a 所示,但这是可持续的吗?好吧,我把答案留给你们大家。

图 3b:社会距离对冠状病毒传播的影响。 来源

因此,在这种特殊的情况下,需要做的一件主要事情是多重测试,并且大多数国家已经开始这样做,这样才能了解真实情况并做出适当的决定。

但我们可以理解,这些测试非常关键,应该绝对精确地进行,这肯定需要时间。这可能非常危险,因为如果被感染的人没有及时被隔离,他们会感染其他人,这可能导致指数增长,如图 3b 。特别是在像印度这样人口密度极高的国家,这可能是造成灾难的原因。

标准的新冠肺炎测试被称为 PCR(聚合酶链式反应) 测试,用于寻找特定感染的抗体的存在。但是这个测试有一些问题。 病原实验室检测 是诊断的金标准,但费时且假阴性结果显著,如本文 论文 所述。

此外,*的 大规模实施 新冠肺炎测试对于许多发展中的&不发达国家来说是负担不起的,因此,如果我们能够使用 人工智能&机器学习 *并利用历史数据来进行一些并行的诊断/测试程序,将会非常有帮助。这也有助于在过程中选择主要测试的项目。

迫切需要快速准确的诊断方法来对抗这种疾病。在最*由王帅等人发表的论文“ 中,一种深度学习算法使用 CT 图像来筛选冠状病毒疾病(新冠肺炎) ”。al 他们已经使用深度学习计算机断层扫描(图像)中提取新冠肺炎的图形特征,以便在病原测试之前提供临床诊断,从而为疾病控制节省关键时间。

这项研究利用初始卷积神经网络(CNN)对1119 次 CT 扫描进行迁移学习。模型的内部和外部验证精度分别记录在 89.5%79.3%

在我的实验中,我进行了类似的分析,但是是在胸部 X 射线图像上,主要原因是对人们来说,获得 CXRs(T21)比获得 CT 扫描更容易,特别是在农村和偏远地区。还会有更多的潜在数据可用。

现在来看看我用过的数据集。于是,约瑟夫·保罗·寇恩 ( 蒙特娄大学博士后 ),最*开源了一个数据库,里面有患有 【新冠肺炎】 疾病患者的胸部 x 光照片。所使用的数据集是一个开源数据集,包括来自公开研究的 新冠肺炎 图像,以及不同肺炎致病疾病(如 SARS、链球菌和肺囊虫)的肺部图像。****

因此,数据集由 新冠肺炎 X 射线 扫描图像以及进行扫描时的角度组成。原来最常用的视图是 后前视图 并且我考虑了新冠肺炎 PA 视图 X 射线 扫描用于我的分析。****

现在,我还使用了 Kaggle 的胸部 x 光 竞赛数据集来提取健康患者和肺炎患者的 x 光,并对每个类别的 100 张图像进行了采样,以与新冠肺炎的可用图像进行*衡。(不过我会在这部分下功夫,改进方法)。****

从 X 射线中检测新冠肺炎存在的卷积神经网络方法:

让我们看一下数据集的类级分布。

图 4:数据集的分类分布

所以,在我的方法中,我在三个分类问题上运行了卷积神经网络

  1. 对正常与新冠肺炎病例进行分类。【2 类问题】
  2. 肺炎 vs 新冠肺炎病例分类。【2 类问题】
  3. 分类正常 vs 新冠肺炎 vs 肺炎病例。【3 类问题】

我在一些分析中看到,人们将正常和肺炎病例结合在一起,我认为这不合适,因为模型将试图忽略这两个类别之间的组间差异,因此获得的准确性将不是真正的衡量标准。

图 5:将两个不同的类别合并为一个类别可能会产生误导。 来源

所以,这是我上述假设的一个简单说明(只是为了解释)。假设“特征 1”和“特征 2”代表潜在空间,在潜在空间中,CNN 将图像投射到潜在空间中,并且属于三个类别中的每一个的图像已经在图像中被标记。

可以看出,它们目前是线性可分的,但如果我们将“正常”和“肺炎”这两个类别合并为一个类别,则可分性消失,结果可能会产生误导。因此,如果我们要合并类,就需要进行某些验证。

虽然有人可能会说投影会解决这个问题,但这并不成立,因为我们使用的是迁移学习。

反正在我的分析中,重点是既要减少的假阳性。让我们来分析一下。我已经使用转移学习与 VGG-16 模型和微调最后几层。****

*******vgg_pretrained_model = VGG16(weights="imagenet", 
                             include_top= False,
                             input_tensor=Input(shape=(224, 224,3)))new_model = vgg_pretrained_model.output
new_model = AveragePooling2D(pool_size=(4, 4))(new_model)
new_model = Flatten(name="flatten")(new_model)
new_model = Dense(64, activation="relu")(new_model)
new_model = Dropout(0.4)(new_model)
new_model = Dense(2, activation="softmax")(new_model)
model = Model(inputs=vgg_pretrained_model.input, outputs=new_model)*******

我们模型的最终参数如下所示。该模型已经使用 Kaggle GPU 进行了训练。

******Total params: 14,747,650
Trainable params: 2,392,770
Non-trainable params: 12,354,880******

案例 1:正常 vs 新冠肺炎分类结果

图 6:新冠肺炎与正常模型的分类报告

可以清楚地看到,该模型几乎可以以 100%的准确率和召回率区分这两种情况。现在,为了有更多的理解,我使用了基于梯度的类激活图的概念,以便找到图像中最重要的部分,这有助于模型进行如此精确的分类。

现在要了解更多关于【GRAD-CAM】如何工作,请参考 论文 。我可能会在我未来的博客中详细介绍它们。******

图 7:基于梯度的类激活图

绘制 Grad-CAM 热图的代码如下所示。为了看得更清楚,我做了一些修改。

****def get_class_activation_map(ind,path,files) :

    img_path =  path + files[ind]
    img = cv2.imread(img_path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img = cv2.resize(img, (224, 224))
    img = np.expand_dims(img,axis=0)

    predict = model.predict(img)
    target_class = np.argmax(predict[0])
    last_conv = model.get_layer('block5_conv3')
    grads =K.gradients(model.output[:,target_class],last_conv.output)[0]
    pooled_grads = K.mean(grads,axis=(0,1,2))
    iterate = K.function([model.input],[pooled_grads,last_conv.output[0]])
    pooled_grads_value,conv_layer_output = iterate([img])

    for i in range(512):
        conv_layer_output[:,:,i] *= pooled_grads_value[i]

    heatmap = np.mean(conv_layer_output,axis=-1)

    for x in range(heatmap.shape[0]):
        for y in range(heatmap.shape[1]):
            heatmap[x,y] = np.max(heatmap[x,y],0)
    heatmap = np.maximum(heatmap,0)
    heatmap /= np.max(heatmap)
    plt.imshow(heatmap)img_gray = cv2.cvtColor(img[0], cv2.COLOR_BGR2GRAY)
    upsample = cv2.resize(heatmap, (224,224))

    output_path_gradcam = '/kaggle/working/' + files[ind] + 'gradcam.jpeg'
    plt.imsave(output_path_gradcam,upsample * img_gray)****

正常患者的分类激活图输出:

******

图 8:正常患者的 Grad-CAM 热图******

因此,我们可以看到,该模型更侧重于突出显示的部分,以识别和分类他们为正常/健康的患者。

新冠肺炎患者的分类激活图输出:

******

图 9:新冠肺炎患者的 Grad-CAM 热图******

同样,突出显示的部分朝向图像的右端部分,这表明该部分可能是确定患者是否患有新冠肺炎的重要特征,或者可能是 新冠肺炎已经影响了 部分中的患者。这可以通过临床记录进行验证。**

病例 2:肺炎 vs 新冠肺炎分类结果

图 10:新冠肺炎 vs 肺炎模型分类报告

肺炎患者的分类激活图输出:

******

图 11:肺炎患者 Grad-CAM 热图******

病例 3:肺炎 vs 新冠肺炎 vs 正常分类结果

图 12:新冠肺炎 vs 肺炎 vs 正常模型的分类报告

在这三种情况下,即使数据集很小,模型的表现也非常好。此外,建立三个不同模型的目的也是为了检查模型与 【新冠肺炎】 病例检测的一致性。在这三种情况下,测试数据中的案例的准确率和召回率都明显较高。******

*******话虽如此,但这仅仅是对一些图像进行的实验,并未经过外部卫生组织或医生的验证/检查。还没有基于这种方法的临床研究来验证它。该模型已被用作概念验证,不能从该结果中得出任何结论/推断。 *******

但是,这种方法有巨大的潜力,可以成为一种优秀的方法来拥有高效、快速的 诊断系统 ,这正是当前所需要的。以下列出了主要优势:

优点:

优点已经从这个 来源 中提到了。

  1. 运送测试或样本是 PCR 测试的缺点之一,而 x 光机可以解决这个问题。
  2. 如果放射科医生&医生受到影响,AI 可以生成初步诊断,以了解患者是否受到影响。

结论:

因此,作为总结,我想重申一下我自己,分析是在有限的数据集上进行的,结果是初步的,不能从中推断出任何结论。该方法尚未进行临床试验/医学验证。

我计划用更多的 X 射线扫描来增加我的模型的稳健性,这样模型就可以推广了。此外,与健康人群的数量相比,COVID 病例的数量将会更少(尽管是指数增长),因此将会出现阶层失衡。我想改进我的采样技术,建立一个可以处理类别不*衡的模型,为此我需要更多的数据。

此外,当前的方法是基于微调 I mageNet 权重 ,但是如果我们能够专门为此目的建立一个模型,结果将更加可信和可推广。

因此,如果您有库可接受的新冠肺炎患者的 X 射线扫描图像, 请将 贡献给 ,因为它将在这些关键时刻有所帮助。

一个好消息是麻省理工已经发布了一个 数据库 包含了 新冠肺炎 受影响患者的 x 光照片。因此,作为下一步,我将尝试将这些数据整合到我的建模方法中,并检查结果。

此外,我将根据梯度值对 类激活图输出 进行处理,并使用临床记录对其进行验证。

注意——我不是来自医学领域/生物学背景,所做的实验是为了证明概念。

编者注: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

保持安全和快乐阅读:)

**** [## Souradip Chakraborty -数据科学家-沃尔玛印度实验室| LinkedIn

我是一名有抱负的统计学家和机器学习科学家。我探索机器学习、深度学习和…

www.linkedin.com](https://www.linkedin.com/in/souradip-chakraborty/) [## 专家|谷歌开发者

机器学习我是 Souradip Chakraborty,目前在沃尔玛实验室担任统计分析师(研究)

developers.google.com](https://developers.google.com/community/experts/directory/profile/profile-souradip_chakraborty)

参考资料:

  1. https://github.com/ieee8023/covid-chestxray-dataset
  2. 艾尔顿·圣华金撰写的类似的精彩博客:https://towardsdatascience . com/using-deep-learning-to-detect-ncov-19-from-x-ray-images-1a 89701 D1 ACD
  3. https://github . com/harsh Casper/Brihaspati/blob/master/新冠肺炎/COVID19-XRay.ipynb
  4. 论文“Grad-CAM:通过基于梯度的定位从深度网络进行视觉解释”。
  5. https://www . ka ggle . com/paultimothymooney/胸部 x 光-肺炎
  6. https://www.kaggle.com/michtyson/covid-19-xray-dl#1. -数据准备****

Python 中价格支持和阻力位的检测

原文:https://towardsdatascience.com/detection-of-price-support-and-resistance-levels-in-python-baedc44c34c9?source=collection_archive---------0-----------------------

Python 中寻找价格支撑位和阻力位的算法

算法交易是交易和统计的一个迷人领域,量化交易者经常希望自动化的最有用的交易技术之一是价格行为,这是在不使用衍生指标如振荡器或移动*均线的情况下对价格运动的分析。

在这篇文章中,我将介绍一种自动检测价格行为的两个重要工具的算法,这两个工具是支撑和阻力。

什么是支撑和阻力?

支撑和阻力通常被称为“关键水*”。它们是股价反转的价格水*。如果价格上涨,然后反转其向下移动的趋势,它所达到的最高点被称为阻力。如果价格已经下降,然后开始上升,最低价格值被称为支持

这些价格水*确定了供给和需求区域,交易者在这些区域增加了交易量,并表现出一定的兴趣。这就是为什么,一旦价格接*关键水*,交易者必须睁大眼睛,看看会发生什么。

支撑和阻力示例

关键能级非常重要,因为在这些反转能级附*可能会发生许多有趣的事件。例如,市场可以再次反弹,让均值回归策略获胜,或者它可以突破关键水*,这对突破交易者来说更好。

有一个经验法则是,一个关键水*被测试的次数越多(即市场在它附*反弹了很多次),这个水*的重要性就越高。

另一个经验法则是,一旦阻力位被突破,它会自动成为支撑位。反之亦然,一个被打破的支撑位变成了阻力位。

反抗变成了支持

级别或区域?

在这篇文章中,我将关键水*称为价格水*,但有一些交易者说关键水*是区域,而不是水*。发生这种情况是因为波动性让一切都变得更嘈杂,所以供需区从来没有那么清晰。这就是为什么,在现实生活的交易中,你应该总是考虑围绕关键水*的某种包络线,大致与波动性一样宽(例如,*均真实范围,标准差)。为了简单起见,在本文中,我将把关键价格水*视为固定价格水*,而不是更广泛的区域。

如何识别关键级别

关键水*是拒绝点,所以我们必须检查市场是否达到了一定的水*,然后拒绝向相反的方向移动。

一个好主意是使用蜡烛图,检查每根蜡烛的高低价格。如果一根蜡烛线的低点比前一根低,下一根蜡烛线的低点,这是一个支撑。这种特殊的价格行为模式被称为摆动。不幸的是,由于市场波动和噪音,这种模式经常显示出一些缺陷,这就是为什么我们可以使用一种更好的模式,称为分形

分形

分形是由 5 根蜡烛组成的烛台图案。第三根蜡烛的价格最低,前面的蜡烛价格越来越低,后面的蜡烛价格越来越低。根据这种模式,第三根蜡烛线的低点是支撑位。同样的概念也适用于阻力位,第三根蜡烛线是五根蜡烛线中最高的。

使用分形的支持识别

分形非常有用,因为它们消除了一些由摆动显示的噪声,并以更高的精度识别关键水*。这就是为什么我要在我的算法中使用它们。

Python 中的自动检测

让我们看一个使用标准普尔 500 数据的 Python 示例。我的笔记本可以在 GitHub 上找到这里:https://GitHub . com/gianlucamalato/machine learning/blob/master/Support _ and _ resistance . ipynb

对于所有的烛台图表代码,我使用了一些在这里找到的代码:https://saralgyaan . com/posts/python-烛台图表-matplotlib-tutorial-chapter-11/

我们先安装 yfinancempl_finance 库。

!pip install yfinance
!pip install mpl_finance

让我们导入一些有用的库并初始化绘图环境。

import pandas as pd
import numpy as np
import yfinance
from mpl_finance import candlestick_ohlc
import matplotlib.dates as mpl_dates
import matplotlib.pyplot as pltplt.rcParams['figure.figsize'] = [12, 7]
plt.rc('font', size=14)

现在我们可以下载标准普尔 500 日报的数据。

name = 'SPY'
ticker = yfinance.Ticker(name)
df = ticker.history(interval="1d",start="2020-03-15", end="2020-07-15")df['Date'] = pd.to_datetime(df.index)
df['Date'] = df['Date'].apply(mpl_dates.date2num)
df = df.loc[:,['Date', 'Open', 'High', 'Low', 'Close']]

让我们不要创建两个识别 4 蜡烛分形的函数。

def isSupport(df,i):
  support = df['Low'][i] < df['Low'][i-1]  and df['Low'][i] < df['Low'][i+1] and df['Low'][i+1] < df['Low'][i+2] and df['Low'][i-1] < df['Low'][i-2] return supportdef isResistance(df,i):
  resistance = df['High'][i] > df['High'][i-1]  and df['High'][i] > df['High'][i+1] and df['High'][i+1] > df['High'][i+2] and df['High'][i-1] > df['High'][i-2] return resistance

最后,让我们创建一个包含我们找到的级别的列表。每个级别都是一个元组,其第一个元素是信号蜡烛线的指数,第二个元素是价格值。

levels = []
for i in range(2,df.shape[0]-2):
  if isSupport(df,i):
    levels.append((i,df['Low'][i]))
  elif isResistance(df,i):
    levels.append((i,df['High'][i]))

我们现在可以定义一个将价格和关键水*绘制在一起的函数。

def plot_all():
  fig, ax = plt.subplots() candlestick_ohlc(ax,df.values,width=0.6, \
                   colorup='green', colordown='red', alpha=0.8) date_format = mpl_dates.DateFormatter('%d %b %Y')
  ax.xaxis.set_major_formatter(date_format)
  fig.autofmt_xdate() fig.tight_layout() for level in levels:
    plt.hlines(level[1],xmin=df['Date'][level[0]],\
               xmax=max(df['Date']),colors='blue')
  fig.show()

最后,我们可以绘制结果。

如您所见,我们已经能够检测出主要的剔除水*,但仍有一些噪声。有些级别高于其他级别,但本质上是同一级别。

我们可以通过修改检测关键电*的函数来清除这种噪声。如果一个级别接*另一个级别,它将被丢弃。那么,我们必须决定“*”是什么意思。如果一个级别与另一个级别之间的距离小于图表中的*均蜡烛线大小(即蜡烛线中最高价和最低价之间的*均差值),我们可以说这个级别接*另一个级别。这将给我们一个波动性的粗略估计。

s =  np.mean(df['High'] - df['Low'])

让我们定义一个函数,给定一个价格值,如果它接*某个先前发现的关键级别,则返回 False。

def isFarFromLevel(l):
   return np.sum([abs(l-x) < s  for x in levels]) == 0

现在我们可以使用这个函数作为过滤器来扫描价格历史,寻找关键水*。

levels = []
for i in range(2,df.shape[0]-2):
  if isSupport(df,i):
    l = df['Low'][i] if isFarFromLevel(l):
      levels.append((i,l)) elif isResistance(df,i):
    l = df['High'][i] if isFarFromLevel(l):
      levels.append((i,l))

最后,我们可以再次策划一切。

现在级别更清楚了,它们彼此不重叠,我们可以很容易地看到,有时价格在每个级别上不止一次地跳跃。

结论

自动化价格水*对定量交易者非常有用,可以消除一些市场噪音,使图表更加清晰。关键水*可用于均值回归策略(即当价格从支撑位反弹时买入)或突破策略(即当价格突破阻力位时买入)。

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

Detectron2 和 Python Wheels 缓存

原文:https://towardsdatascience.com/detectron2-python-wheels-cache-bfb94a0267ef?source=collection_archive---------29-----------------------

在 Windows 上构建一个 Detectron2 wheel 包并缓存它

巴尼·莫斯Flickr 上的原始照片

检测器 2

我最*在做一些定制的探测器 2 模型的工作。我一直在云中的 Linux VM 上训练我的模型,但是我想在 Windows 环境中使用这个训练过的模型。脸书研究公司关于 Detectron2 的官方说法是它在 Windows 上不受支持。但我不会让这阻止我去尝试!好消息是我能够做到,这篇文章描述了我使用的过程。

初始设置

在解释我是如何做到这一点的过程中,我将假设您熟悉/熟悉以下内容:

  • Python 虚拟环境
  • GIT 命令行

首先要创建一个虚拟环境,然后激活它:

virtualenv detectron2
detectron2\Scripts\activate

从您的虚拟环境安装 PyTorch 和 torchvision(仅限 CPU 版本):

pip install torch==1.5.1+cpu torchvision==0.6.1+cpu -f https://download.pytorch.org/whl/torch_stable.html

或许还值得安装 fvcore 和 windows 版本的 pycocotools,即 pycocotools-windows :

pip install fvcore
pip install pycocotools-windows

下载并安装检测器 2

为了下载 Detectron2 源代码,我们将使用 GIT 命令行克隆一个特定的标记版本(这里的标记是“v0.1”)。

git clone --depth 1 --branch v0.1 https://github.com/facebookresearch/detectron2.git

将发布变更克隆到刚刚在虚拟环境(不是 GIT 命令行)中用这个克隆创建的 detectron2 文件夹之后。例如,如果您将 GIT 克隆到文件夹D:\ Source \ Python \ detectron 2中,则切换到该目录并发出以下命令:

pip install -U .

不要忘记结尾的句号,这真的很重要!

这应该会构建 detectron2 包,如果一切顺利,您应该会在最后看到如下内容:

构建检测器 2 包

因为我们克隆了 v0.1 标签,所以您会看到它是由 detectron 2–0.1 构建的

缓存车轮

你会注意到,当你安装一个 python 包时,它会检查它的本地轮缓存,看看它过去是否下载过这个包,如果下载过,它就使用缓存的版本。要创建您自己的车轮缓存,您需要首先安装车轮包:

pip install wheel

完成后,我们要列出当前为我们的虚拟环境安装的包,并将它们放入一个文件中(这里称为 requirements.txt):

pip freeze > requirements.txt

要为当前安装的包复制/创建所有的轮子,并把它们放在一个缓存文件夹中(这里我使用的是 D:\wheels_cache ),请执行以下操作:

pip wheel --wheel-dir=D:\wheels_cache -r requirements.txt

车轮缓存的优势

使用 wheels 缓存的好处之一是,将来您可以使用缓存的 wheels 直接安装,而不必再次构建一个包。如果你想在一台不同的电脑上做这件事,这是很有用的,因为你可能没有所有的依赖项。你可以这样做:

pip install D:\wheels_cache\detectron2-0.1-cp38-cp38-win_amd64.whl

这种方法需要注意的一点是轮子依赖于目标*台和 Python 版本。这个是针对 Windows 64 位和 Python 3.8 的。

你甚至可以安装来自 requirements.txt 文件的所有东西,告诉它在你的缓存文件夹中寻找轮子:

pip install --no-index --find-links=D:\wheels_cache -r requirements.txt

有一次,我必须在客户处安装一台电脑,而这台电脑是隔离的,即不允许连接到互联网或本地网络。我必须能够在这台机器上安装 Python 和所有需要的包,以运行我实现的机器学习软件。我采用的方法是为机器构建一个包含所有需要的包的 wheels 缓存。这样,安装可以从缓存中进行。

参考

探测器 2:最基本的端到端教程

原文:https://towardsdatascience.com/detectron2-the-basic-end-to-end-tutorial-5ac90e2f90e3?source=collection_archive---------5-----------------------

https://commons . wikimedia . org/wiki/File:simmon _ Telescope _ at _ Eiffel _ Tower _ In _ Paris . jpg

历史第一

2018 年,脸书 AI 开发了一个名为 Detectron 的物体检测库。这是一个了不起的图书馆,但有点难以使用。我的早期版本写了一篇关于如何安装 Detectron 和运行示例演示的博文,仅此而已。Detectron 的安装和使用有点困难,它是由 Caffe2 供电的。自 2018 年以来,有许多代码更改将 Caffe2 & PyTorch 纳入了一个单一的存储库,这增加了使用 Detectron 的难度。

看起来社区里有一些建设性的反馈,脸书推出了 v2。

根据 Detectron2 的 GitHub 页面:

Detectron2 是脸书人工智能研究所的下一代软件系统,实现了最先进的物体检测算法。

Detectron2 是使用 PyTorch 构建的,py torch 现在拥有更活跃的社区,可以与 TensorFlow 本身竞争。此外,设置指令更容易,加上一个非常容易使用的 API 来提取评分结果。像 YOLO 这样的其他框架有非常模糊的评分结果格式,以普通多维数组的形式提供。任何与 YOLO 一起工作的人都可以想象首先解析评分结果并将其正确无误需要付出的努力。

历史已经足够了,在这篇文章中,我将带你做一个端到端的练习,学习如何准备一个 Detectron2 docker 映像来托管一个用于对象检测的 web API,并在一个充当服务消费者的小型 web 应用程序中使用它。

1.装置

我将首先从安装开始。不幸的是,Windows 不被支持,但是我将使用容器绕过它。快速地说,我们不介意安装一个 CPU 版本,因为 GPU 需要(猜猜是什么)一个 GPU,CUDA 和所有来自 NVIDIA 的可爱的东西。

因此,使用您喜欢的文本编辑器,用这个内容创建一个 docker 文件。

首先,根据 Detectron2 设置指令的要求,选择 Python 版本≥ 3.6 的基础映像。接下来安装一些先决条件,然后在 Detectron2 安装页面上安装相同的安装说明。安装的版本是一个 CPU 版本,它不会超级快,但足够好的教程。最后,Flask 包含在内,因为这个 docker 映像将托管一个 web API 网站,以接受客户的评分请求。

让我们先建立形象。

docker build --rm . -t ylashin/detectron2:latest

您可以使用任何您想要的名称/标签,并为接下来的步骤做相应的调整。接下来,让我们试一试。

docker run -it ylashin/detectron2:latest bin/bash

希望上面所有的工作都很好,现在我们已经有了一个安装了 Detectron2 的容器。因此,我们需要验证没有任何东西损坏,我们有独角兽和彩虹。

必须使用 docker CLI 或使用安装在容器上的 nano 将以下test.py脚本复制到容器中。

涉及的主要任务有:

  1. 印刷检测器 2 版本。
  2. 莱昂内尔·梅西和一个足球下载图片。
  3. 使用预先训练的架构之一创建预测器实例。
  4. 使用预测器实例对下载的图像进行评分。

接下来,我们将运行测试脚本,如下一个屏幕截图所示。

在撰写本文时,Detectron2 的版本似乎是 0.1.1。此外,评分是正确的,结果不是一个简单的张量像 YOLO。它是一个类型化的类,具有易于使用的成员,如边界框和预测类。稍后我们将讨论将类代码映射到人类可读的名称。我们在这里有一对夫妇的边界框和一对夫妇的高分加上预测类 0(人)和 32(运动球)。

附注:根据你正在解决的问题,你需要选择正确的架构,看看它是否针对类似的数据集进行了训练,否则你可能需要进行定制训练。

2.发布 API

下一步是让这个评分功能可以从容器外部访问。Flask web API 需要驻留在该容器中,以接受图像并返回评分结果。为了简单起见,API 将接受一个图像 URL 并自己下载。它不接受二进制有效负载,这是很自然的事情,但它只是很容易使用相同的测试脚本稍加修改。

此外,响应将是一个序列化为 JSON 对象的字典,其中包含调用者所需的足够信息,无需任何复杂的解析。

现在,因为容器将托管 Flask web 服务器,所以必须通过发布 web API 端口来启动它。因此,退出当前容器,并使用端口发布再次启动它。

docker run -p 8181:5000 -it ylashin/detectron2:latest bin/bash

烧瓶端口 5000 映射到主机端口 8181。

现在,在名为web_api.py的容器中创建一个文件,并将下面的 GitHub 要点粘贴到其中。

这与之前使用的测试脚本几乎相同,但有以下区别:

  • 进行了一些重构,以便为每个请求准备好一个全局预测器实例。
  • 映射到 web API 端点的函数用于接收带有 JSON 对象的 HTTP 请求,该对象具有要评分的图像 URL。
  • 该函数进行评分和一些后处理,以准备最终的响应对象。

要启动 web 服务器,请运行:

python web_api.py

显示的 URL 有一个 5000 端口,但那是因为它只是在容器内部。任何像 Postman、curl 或 PowerShell 这样的工具都可以用来测试 API 是否按预期工作。对于您使用的任何工具,请记住包含带有键content-type和值application/json的请求头。

如果我们在 Postman 中向下滚动响应,我们将找到预期的得分字段,如边界框、得分和类别预测。

现在 web API 服务器似乎工作得很好,最好将其作为 Dockerfile 定义的一部分。这将允许我们将构建好的映像推送到 docker hub 或任何其他注册表,并与其他人共享或使用它,而不必担心每次都要构建它。

更新的 Docker 文件可以在链接到这篇文章的报告中找到,但是为了简洁起见,添加到 Docker 文件的增量是:

WORKDIR /appCOPY web_api.py web_api.pyENTRYPOINT ["python", "/app/web_api.py"]

一旦构建了修改后的 docker 映像,我们可以再次启动容器,但这一次我们不需要复制 web API 文件,也不需要自己启动它。实际上,我们可以将容器作为守护进程启动。

docker run -p 8181:5000 -d ylashin/detectron2:latest

可以使用 Postman 再次测试 web API 以进行验证,但我们需要给容器几秒钟时间来下载预测器准备的权重文件部分。

一旦我们对运行的容器满意了,我们就可以关闭它并发布图像。

docker push ylashin/detectron2:latest

我将该图像发布到我自己的 Docker Hub 帐户,以便我稍后可以向您展示如何将它用于 Azure 容器实例。我将用来消费评分服务的 web 应用程序将在本地托管,因此它可以轻松地访问本地运行容器。但是我更喜欢进入下一个层次,将容器托管在云中的某个地方,以模拟更真实的实现。

客户端应用程序

唷,快到了。最后一个阶段是从任何 RESTful 客户端使用 web API。但首先,我将使用 Azure CLI 和 Azure container instances 服务启动 Azure 中的容器。如果你想继续在本地使用容器,你可以跳过这个 Azure 位,但在稍后到来的 web 应用中调整 web API URL。

az group create --name detectron2 --location eastusaz container create --resource-group detectron2 --name predictor --image ylashin/detectron2:latest --cpu 2 --memory 4  --dns-name-label detectron2api --ports 5000az container show --resource-group detectron2 --name predictor --query "{FQDN:ipAddress.fqdn,ProvisioningState:provisioningState}" --out table

上面的最后一个命令将显示容器的 FQDN,我们可以用它来测试使用 Postman 的云托管 API。请注意,这里使用的端口是普通烧瓶端口,没有映射到其他端口。

我们有一个在云中运行的 web API 端点,可以从任何地方的任何 REST 客户端使用。我已经建立了一个小的 JavaScript 应用程序。这款应用非常简单:

  • 它有一个文本框和一个按钮。
  • 在文本框中输入一个公共图像 URL,然后单击按钮。
  • 该应用程序将调用我们的 API,呈现请求的图像并绘制边界框。

要试用该应用程序,请先克隆它并安装所需的 npm 软件包:

git clone [https://github.com/ylashin/detectron2-tutorial](https://github.com/ylashin/detectron2-tutorial)
cd '.\3\. client\'
npm install
npm install -g browserify
npm install -g watchify
watchify index.js -o bundle.js

在文本编辑器中打开index.html文件,并更新函数scoreImage中 API 的 URL,以匹配本地或云托管 API 的 URL。然后双击index.html文件,这将在您的默认浏览器中打开应用程序。使用不同的图片网址,但是请注意一些图片网站有一点严格的 CORS 政策,所以不是所有的图片都能正常工作。这与我们的 web 应用程序或 API 无关,而是更多地与 web 的工作方式有关。

本帖安装部分使用的图片是上面试用过的。我们可以看到梅西和球上的边框、分数和标签。开发人员控制台窗格也显示了 API 的 JSON 响应。

在这个 web 应用程序中要考虑的主要部分是解析和使用 API 响应,这非常简单明了。

所有剩下的代码都是通过 npm 包进行管道和 HTML 画布渲染。

包裹

我们仅仅触及了 Detectron2 的表面,它还有许多令人惊奇的特性有待探索。此外,为了使帖子尽可能简洁,我们还设置了许多快捷方式。总之,Detectron2 是任何开发人员工具箱的一个非常受欢迎的补充,因为它的特性,但更重要的是易于使用。

如果你碰巧在 Azure 中创建了容器,请记住一旦完成实验就删除资源组或停止容器,否则它将继续消耗你的信用。

资源

[## ylashin/检测器 2-教程

使用 Detectron2 进行物体探测的端到端教程-ylashin/detectron 2-教程

github.com](https://github.com/ylashin/detectron2-tutorial) [## Detectron2:一个基于 PyTorch 的模块化对象检测库

自 2018 年发布以来,Detectron 对象检测*台已成为脸书人工智能研究(FAIR)最…

ai.facebook.com](https://ai.facebook.com/blog/-detectron2-a-pytorch-based-modular-object-detection-library-/) [## Facebook 研究/检测器 2

Detectron2 是脸书人工智能研究所的下一代软件系统,实现了最先进的物体检测…

github.com](https://github.com/facebookresearch/detectron2) [## 准备 Detectron 沙盒的快速简单指南

medium.com](https://medium.com/@ylashin/quick-and-easy-guide-to-prepare-a-detectron-sandbox-940ccad8ffe2)

使用 Python 为您的投资组合确定安全的提款率

原文:https://towardsdatascience.com/determine-a-safe-withdrawal-rate-for-your-investment-portfolio-with-python-cf2df9185f73?source=collection_archive---------54-----------------------

在钱不用完的情况下能取多少?

蒂埃拉·马洛卡在 Unsplash 上拍摄的照片

1999 年,一项研究发表,详细说明了一系列名义和通胀调整提款率对投资组合的影响,最长支付期为 30 年。在金融、投资咨询和退休规划领域,这项研究被非正式地称为三位一体研究

该研究表明,至少 75%股票的投资组合提供了 4%至 5%的通胀调整后提款。换句话说,如果你有一个 100 万美元的投资组合,你可以每年提取 40,000 至 50,000 美元(经通胀调整),至少在未来 30 年内没有资金耗尽的风险。

在阅读了这项研究后,我受到启发,扩展了本文的工作。因此,我编写了一个 python 脚本,遵循本研究中描述的方法来确定任何投资组合的可持续提款率(假设有足够的历史数据)。

这篇文章由以下部分组成,首先,我将解释数据和方法。其次,我将详细阐述 Python 实现并解释如何使用它。最后,给出了一个关于确定安全撤出率的结论。

数据和方法

为了确定一个可持续的退出率,该研究使用了一个比率,称为投资组合成功率。该比率用于比较具有不同提款率和支付期的所有投资组合。投资组合成功率被定义为投资组合成功的次数除以模拟的次数。如果投资组合在支付期结束时的期末值大于或等于零,则该投资组合被视为成功。

研究中使用的数据是标准普尔 500 指数的总月回报率和所罗门兄弟长期高等级公司债券指数。总月回报是给定期间投资的实际回报,包括利息、资本收益、股息和分配。

使用这些历史月总回报,通过使用不同支付期的重叠年方法来进行模拟。下图详细说明了这种方法:

此图中的三个点( )指的是两年和/或模拟之间的年份和/或模拟。

为了确定投资组合的成功率,需要计算月末投资组合的价值。该研究区分了具有名义提款率的投资组合和经通胀调整后提款的投资组合。这些月末投资组合价值确定如下:

通货膨胀调整是根据消费者价格指数(CPI)确定的。

在继续 python 实现之前,我还想进一步阐述两个项目。这些是投资组合回报( Rₜ )和每月提取金额( Wₜ )的确定。请参考下图:

投资组合回报的计算隐含地假设每月对投资组合进行再*衡以达到期望的投资组合权重。请注意,研究或实施中未考虑交易佣金和费用。

不幸的是,由于数据限制,python 实现的范围仅限于确定名义提款率。此外,我只能找到历史月回报,而不是总月回报。因此,不考虑股息或其他分配,这可能会影响投资组合的实际成功率。不过,我相信这个影响不会很大。

Python 实现

首先,我用于这个实现的库是 yfinanceplotly 。要使用这个 python 实现,您需要安装这些库。您可以使用pip来安装这些库。

pip install yfinance --upgrade --no-cache-dir
pip install plotly

在安装了必要的库之后,我们可以将注意力转向 python 实现。考虑到不同的投资组合构成、支付周期和提款率的数量,我发现创建一个名为sustainable_withdrawal_rate的 python 类是合适的。

在加载这个类之前,如果你在 Yahoo Finance 上查找你选择的符号会有所帮助,因为你将需要它作为 python 类的输入。例如,我想确定包含英国、德国和法国指数的投资组合的(名义)可持续提款率。雅虎财经上这些指数的符号是:

  • 英国富时指数:^FTSE
  • 德国 DAX 指数:^GDAXI
  • 法国 CAC 40 指数:^FCHI

加载 python 类后,需要实例化它。对于实例化,需要符号作为输入。以下是使用上述符号的示例:

symbols = "^FTSE ^GDAXI ^FCHI"
port = sustainable_withdrawal_rate(symbols)

观察到以下输出:

输出表明所有三个指数的历史(月度)数据范围从 1991 年到 2020 年,这是可用于分析的 30 年历史数据。这是有用的,因为它表明,对于这种投资组合,没有足够的历史数据来确定 30 年支付期的可持续提款率。

基于该投资组合的历史数据量(30 年),我们可以使用 10 年的支付期。如果您想要确定给定投资组合组合和 10 年支付期的成功率,您可以使用以下代码:

portfolio_composition = {"^FTSE":0.4, "^GDAXI":0.4, "^FCHI":0.3}
payout_period = 10
port.portfolio_success_rate(payout_period, portfolio_composition)

代码显示,该投资组合的权重包括 40%的富时指数、40%的 DAX 指数和 30%的 CAC 40 指数。运行此代码会产生以下输出:

输出是一个表格,其中包含不同的年度提款率及其相应的成功率。换句话说,由 40%的富时、40%的 DAX 和 30%的 CAC 40 组成的投资组合可以在 10 年的支付期内维持高达 7%的年提款率而不会被耗尽。

如果你想调整投资组合的组成和/或支付期,看看这些变化如何影响成功率。通过调整portfolio_composition和/或payout_period,并运行代码port.portfolio_success_rate(payout_period, portfolio_composition),你可以很容易地做到这一点。

最后,您还可以绘制特定年提款率的投资组合模拟图。让我们根据上面描述的投资组合构成和支付期,模拟 8%的年提款率。您可以使用以下代码来绘制模拟:

annual_withdrawal = 0.08
port.plotsimulations(annual_withdrawal)

运行此代码应该会在您的 webbrowser 中产生以下图形:

该研究和实施的基本假设是,本金在支付期间也被消耗。因此,提款率越低,在支付期后剩余大量资金的可能性就越大。

该图显示了年提款率为 8%,支付期为 10 年(120 个月)的不同投资组合模拟。投资组合模拟是根据方法一节中讨论的重叠年方法确定的。此外,该图显示了初始投资组合价值 1,以及对于不同的模拟,月末投资组合价值如何在整个月份中变化。

图中的绿线是被认为是成功的投资组合模拟,因为期末值大于零。相反,图中的红线是失败的投资组合模拟,因为它们的期末价值是负的。

如果您想绘制不同年提款率的投资组合模拟图,只需调整annual_withdrawal并运行代码port.plotsimulations(annual_withdrawal)

python 类sustainable_withdrawal_rate的完整代码如下所示:

三位一体研究的 Python 实现

结论

在本文中,我扩展了三一研究的工作,假设有足够的数据,任何投资组合的(名义)可持续提款率都可以确定。

通过使用 python 类sustainable_withdrawal_rate,您可以为您的投资组合确定一个可持续的提款率。选择一个可持续的退出率是主观的,不存在全局最优的退出率。

可持续的提款率取决于许多个人偏好,如当前消费、可变金融需求以及个人是否希望将初始退休投资组合的大部分留给其继承人。因此,这一分析的结果应被视为一种输入,以确定您的可持续戒断率。

这项研究中没有考虑的一个重要因素是个体的预期寿命。对于那些感兴趣的人,我写了一篇文章详细说明了预期寿命对提前退休人数的影响,这里是链接

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

参考

[1] Phillip L. Cooley、Carl M. Hubbard 和 Daniel T. Walz,《投资组合的可持续提款率》( 1999 年),《财务咨询和规划》第 10 卷第 1 期。

本文表达的金融观点来自作者的个人研究和经验。本文仅供参考。不应将其视为财务或法律建议。

确定您的数据是否可以建模

原文:https://towardsdatascience.com/determine-if-your-data-can-be-modeled-e619d65c13c5?source=collection_archive---------48-----------------------

你收集到正确的数据了吗??

一些数据集并不意味着具有可以聚类的地理空间表示。你的特征有很大的变化,理论上也有很大的特征。但是,这并不意味着统计上是可分的。

那么,我什么时候停止?

  1. 始终根据您试图预测的类别标签来可视化您的数据
columns_pairplot = x_train.select_dtypes(include=['int', 'float']).join(y_train)
sns.pairplot(columns_pairplot, hue = 'readmitted')
plt.show()

作者图片:不可分割的类

不同阶层的分布几乎是精确的。当然,这是一个不*衡的数据集。但是,请注意这些类的分布是如何重叠的?

2.应用 t-SNE 可视化

t-SNE 是“t-分布随机邻居嵌入”。它将高维数据映射到二维空间。这个 大致保持了样本的接*度。

您可能需要应用不同的学习率来找到最适合您数据集的学习率。通常,尝试 50 到 200 之间的值。

超参数,困惑度*衡了 t-SNE 赋予数据的局部和全局可变性的重要性。这是对每个点的*邻数量的猜测。使用 5-50 之间的值。更高,如果有更多的数据点。困惑值不应超过数据点的数量。

注意:轴到 t-SNE 图是不可解释的。每次应用 t-SNE 时,它们都会有所不同

作者图片:T-SNE 可视化

嗯,让我们再看多一点——调整一些超参数。

# reduce dimensionality with t-sne
tsne = TSNE(n_components=2, verbose=1, perplexity=50, n_iter=1000, learning_rate=50)
tsne_results = tsne.fit_transform(x_train)

图片作者:重叠数据-无法分类!

你看到集群是怎么分不开的吗!我应该停在这里的!但是,我不能让自己走出这个疯狂的洞。[是的,我们有时都会这样]。

3.多类分类

从上面我们已经知道,决策边界是非线性的。因此,我们可以使用一个 SVC (具有 RBF 核的支持向量分类器)

from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCVsvc_model = SVC() ## default kernel - RBF
parameters = {'C':[0.1, 1, 10], 'gamma':[0.00001, 0.0001, 0.001, 0.01, 0.1]}
searcher = GridSearchCV(svc_model, param_grid = parameters, n_jobs= 4, verbose = 2, return_train_score= True)
searcher.fit(x_train, y_train)
# Report the best parameters and the corresponding score

训练分数:0.59
测试分数:0.53
F1 分数:0.23
精度分数:0.24

所以,我应该早点停止…在你试图过度调整和复杂化模型以期望更好的结果之前,理解你的数据总是好的。祝你好运!

使用 Scikit-Learn 确定报价来源

原文:https://towardsdatascience.com/determining-a-quotes-source-using-scikit-learn-9d3e2af894f4?source=collection_archive---------58-----------------------

使用逻辑回归和朴素贝叶斯进行整体*均,以确定一条消息更有可能是伯尼·桑德斯或唐纳德·川普发的。

用于文本分类的机器学习管道。图片作者。

人们可以利用视觉和听觉等感官来学习。机器学习遵循类似的概念,但有一个关键的区别。电脑不能像我们一样看或听。它只懂一件事——数字。因此,在机器能够学习之前,它首先需要将人类能够感知的信息转换为数字。数字图像以像素的形式存储数字信息就是一个例子。

在本文中,我们将开发一个机器学习模型,它可以接收打字信息,并确定伯尼·桑德斯或唐纳德·川普更有可能发微博。在我的 GitHub 上可以找到包含数据集、Python 代码和将要讨论的 Jupyter 笔记本的存储库。现在让我们开始吧!

最小化数据集偏差

为了最大限度地减少偏见,我们需要根据我们两位政治家在类似情况下使用的文本来训练我们的模型。例如,如果我们只从一个政治家对国家悲剧的回应中提取文本,从另一个政治家对积极事件的回应中提取文本,那么我们的模型将学习区分积极和消极的文本,而不一定是他们的写作风格。因此,我们将在自 2015 年(即,他们为 2016 年美国总统大选发起竞选活动)以来的两位政治家的推特上训练模型。我们将不包括转发,因为尽管它们可能反映了政治家的社会经济观点,但它们不一定反映他们的语言模式。

特征抽出

清理推文

推文可以包含指向其他网站、图像或视频的链接,这些链接将带有自己的 URL,包括诸如(https://…)之类的术语。标签(#)和提及(@)也包含一些符号,这些符号不一定是这些政客文章的一部分,但却是使用某些 twitter 功能的必需品。因此,我们将删除这些项目和任何其他非字母数字字符,并将剩下的内容转换为小写。本质上,我们将只剩下包含小写字母、数字和空格的文本。例如:

  • 她打算买电视机。它以 500 美元出售。

会变成:

  • 她打算买这台减价 500 英镑的电视机

该消息在阅读时仍然有意义,并且现在将更容易在我们的模型中实现。

词袋模型

让我们考虑以下三个 文件 :

  • 我们正在学习机器学习。
  • 具体来说,我们正在学习文本分类。
  • 你考虑过学习 Python 吗?

清理这些文件给了我们:

  • 我们正在学习机器学习
  • 具体来说,我们正在学习文本分类
  • 你考虑过学习 python 吗

接下来,我们将把每个文档标记成 个术语 :

  • 我们|正在|学习|关于|机器|学习
  • 具体来说,我们正在|学习|关于|文本|分类
  • 你考虑过学习 python 吗

注意“|”符号在我们的模型中实际上并不存在,它只是在这里用来帮助可视化标记。每个文档现在可以被认为是一个包含每个单词的术语的袋子。因此得名。让我们看看标记化对文档的影响:

  • 我们是→我们|是
  • 我们→曾经是
  • 曾经→曾经

前两个术语(“我们是”和“我们是”)具有相同的含义,但将被注册为不同的术语。而且“我们”和“是”这两个词已经分离开了。这可能看起来不可取,但是请记住某人是否使用缩写是他们如何书写的一个显著特征。相反,“we 're”和“was”有不同的意思,但现在已经合并为同一个术语。

n-gram 模型

在前面的例子中,我们将文档标记为一个单词术语,称为 unigrams ( ,即,1-grams)。为了改进我们的模型,我们还可以提取由包含两个单词的术语组成的二元模型(,2-grams):

  • 我们正在学习→我们|正在|学习|我们正在|正在学习
  • 我们在学习→我们在学习
  • 你是吗?你是吗

使用二元模型,我们现在可以包括新的术语,如“我们是”。我们也有更多的信息来区分“我们是”和“曾经是”,因为“曾经是你”可能比“我们是你”更常见。我们还可以提取像“机器学习”这样的新术语,以前只能作为“机器”和“学习”使用。

将二元模型添加到我们的模型中会增加每个文档中的术语数量,使我们的模型更加复杂,但是我们必须小心不要忘乎所以。**包括比必要特征更多的特征(,例如,3-grams,4-grams,5-grams,等。* ) 来描述我们的模型会使它容易过拟合,以及增加它的规模和计算时间。**虽然在本文中我们不会对过度拟合进行详细的讨论,但总的想法是,我们希望尽可能用最少的必要特征制作最精确的模型。*

计数矢量化

考虑下面的 文集 ( ,文献集):

  • 这是语料库中的第一个例子。
  • 这是第二个。
  • 每一个例子都在增加。

首先,我们的模型不知道任何术语。因此,我们需要创建一个字典,包含我们希望模型知道的所有术语。这些术语组成了模型的 词汇 ,并且可以使用 Python 中的 scikit-learn 的[CountVectorizer](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html)从语料库中提取:

*from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd

corpus = ['This is the first example in the corpus.',
          'This is the second.',
          'The corpus is growing with each example.']

count = CountVectorizer(ngram_range=(1, 2))
count.fit(corpus)
df = pd.DataFrame.from_dict(count.vocabulary_,
                            orient='index', columns=['INDEX'])
df.sort_values(by=['INDEX'], inplace=True)

X_count = count.transform(corpus)
df['doc1_tf'] = X_count.toarray().T[df['INDEX'], 0]
df['doc2_tf'] = X_count.toarray().T[df['INDEX'], 1]
df['doc3_tf'] = X_count.toarray().T[df['INDEX'], 2]
print(df)*

输出是我们的词汇表,其中包含我们的语料库中所有唯一的术语(,单词和双词)和 术语频率 ( tf ) ( ,每个术语在文档中出现的次数)表。

 *INDEX  doc1_tf  doc2_tf  doc3_tf
corpus             0        1        0        1
corpus is          1        0        0        1
each               2        0        0        1
each example       3        0        0        1
example            4        1        0        1
example in         5        1        0        0
first              6        1        0        0
first example      7        1        0        0
growing            8        0        0        1
growing with       9        0        0        1
in                10        1        0        0
in the            11        1        0        0
is                12        1        1        1
is growing        13        0        0        1
is the            14        1        1        0
second            15        0        1        0
the               16        2        1        1
the corpus        17        1        0        1
the first         18        1        0        0
the second        19        0        1        0
this              20        1        1        0
this is           21        1        1        0
with              22        0        0        1
with each         23        0        0        1*

术语频率-逆文档频率(tf-idf)

有很多大家都用的常用词,在某人的写作中不会成为显著特征。例如,“is”和“the”都有一个 文档频率 ( df )等于 3 ( ,它们出现在我们语料库的所有三个文档中),因此,它们不会像具有 df = 1 ( ,它只出现在一个文档中)的术语“growing”那样给我们提供那么多有区别的信息。我们希望对文档出现频率低的术语赋予更高的权重。注意,在计算 df 时,一个术语在文档中出现多少次并不重要,只要它至少出现一次。例如,术语“the”仍然有 df = 3,尽管在语料库中总共出现了 4 次。我们可以通过将术语频率乘以 逆文档频率 ( idf )来应用这个权重。这给了我们 术语频率—逆文档频率 (tf-idf 或 tfidf ):

其中 n 是语料库中的文档总数(在我们最后的例子中, n =3)。请注意,等式中“+ 1”的用法因实施方式而异。它们的目的是避免产生零,尤其是在分母中。这里显示的等式是我们即将使用的[TfidfTransformer](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfTransformer.html)的默认 scikit-learn 实现。

最后,我们希望确保文档的长度不会影响我们的模型。例如,如果一个政客通常比另一个政客写得更短,我们不希望用户能够通过简单地写较长的消息来欺骗我们的模型。因此,我们将标准化每个文档向量,使其*方和等于 1。换句话说,在计算了 tfidf 值之后,我们将把每个文档缩放到一个单位向量

*from sklearn.feature_extraction.text import TfidfTransformer

tfidf = TfidfTransformer()
X_tfidf = tfidf.fit_transform(X_count)
df['doc1_tfidf'] = X_tfidf.toarray().T[df['INDEX'], 0]
df['doc2_tfidf'] = X_tfidf.toarray().T[df['INDEX'], 1]
df['doc3_tfidf'] = X_tfidf.toarray().T[df['INDEX'], 2]
print(df[['INDEX', 'doc1_tfidf', 'doc2_tfidf', 'doc3_tfidf']])*

这为我们提供了下面的 tfidf 表:

 *INDEX  doc1_tfidf  doc2_tfidf  doc3_tfidf
corpus             0    0.227103    0.000000    0.235457
corpus is          1    0.000000    0.000000    0.309598
each               2    0.000000    0.000000    0.309598
each example       3    0.000000    0.000000    0.309598
example            4    0.227103    0.000000    0.235457
example in         5    0.298613    0.000000    0.000000
first              6    0.298613    0.000000    0.000000
first example      7    0.298613    0.000000    0.000000
growing            8    0.000000    0.000000    0.309598
growing with       9    0.000000    0.000000    0.309598
in                10    0.298613    0.000000    0.000000
in the            11    0.298613    0.000000    0.000000
is                12    0.176366    0.280520    0.182854
is growing        13    0.000000    0.000000    0.309598
is the            14    0.227103    0.361220    0.000000
second            15    0.000000    0.474961    0.000000
the               16    0.352732    0.280520    0.182854
the corpus        17    0.227103    0.000000    0.235457
the first         18    0.298613    0.000000    0.000000
the second        19    0.000000    0.474961    0.000000
this              20    0.227103    0.361220    0.000000
this is           21    0.227103    0.361220    0.000000
with              22    0.000000    0.000000    0.309598
with each         23    0.000000    0.000000    0.309598*

注意,即使一些术语在不同的文档中有相同的 tf ,它们也可以有不同的 tfidf

既然我们知道了如何从语料库中提取特征并转换成模型可以理解的格式,我们就可以继续前进,开始训练实际的模型。

训练模型

在前面的例子中,我们查看了一个包含 3 个文档和 24 个词汇的小型语料库。在实践中,如果我们想要开发一个模型来确定一个引用是属于伯尼·桑德斯还是唐纳德·川普,我们将需要更多的文档和更大的词汇表。如前所述,我们将使用他们自 2015 年以来的所有推文。

使用新的 Jupyter 笔记本,让我们从使用 Python 标准库中的[re](https://docs.python.org/3.7/library/re.html)清理推文开始:

*import os
import re
import pandas as pd

def clean_text(text):
    text = re.sub(r"'", '', text)
    text = re.sub(r'http\S+', '', text)
    text = re.sub(r'pic.twitter\S+', '', text)
    text = re.sub(r'\W+', ' ', text.lower())

    return text

df = pd.read_csv(os.path.join('tweets', 'tweets.csv'),
                 low_memory=False)
df.drop_duplicates(inplace=True)
df['tweet-clean'] = df['tweet'].apply(clean_text)
drop_index = []

for i in range(len(df)):
    if df['tweet-clean'].iloc[i] in ('', ' '):
        drop_index.append(i)

df.drop(drop_index, inplace=True)*

我们定义了clean_text,它获取一个字符串,并根据我们之前讨论的需求对其进行清理。然后,我们将数据集加载到一个[pandas.DataFrame](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html)中,并将clean_text应用到每条推文中。最后,在我们的清理过程之后,我们会删除任何现在是空白的推文。在我们训练模型之前,让我们定义两个常数:

*random_state = 0
n_jobs = -1*

注意,通过设置random_state = 0,我们实际上并没有初始化我们的随机种子,而是将一个整数传递给我们的各种 scikit-learn 实现,这将允许我们在每次运行代码时保持相同的随机状态。在调整超参数时,我们希望确保每次测试我们的模型时都生成相同的随机序列,这样我们就可以确定我们看到的任何性能改进都是由于我们所做的更改,而不是由于随机数生成器产生的随机性。

Scikit-learn 支持多线程。今天大多数电脑都使用多核 CPU。我们可以设置[n_jobs](https://scikit-learn.org/stable/glossary.html#term-n-jobs) = -1使用一个 CPU 上的所有线程来加快模型训练。

现在我们将计算推文的矢量化。使用[TfidifVectorizer](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html)可以将语料库直接转换为 scikit-learn 中的 tfidf 向量,这实际上是一个CountVectorizer后跟TfidfTransformer的管道,两者我们之前都使用过。

*from sklearn.feature_extraction.text import TfidfVectorizer

tfidf = TfidfVectorizer(ngram_range=(1, 2), min_df=2)
X = tfidf.fit_transform(df['tweet-clean'])

print(f'Number of documents: {X.shape[0]}')
print(f'Size of vocabulary:  {X.shape[1]}')*

它为我们的数据集输出一些统计数据:

*Number of documents: 34648
Size of vocabulary:  86092*

为了在整篇文章中保持一致,我们将它们指定为:

  • 文档数量: n = 34 648 条推文
  • 词汇量: v = 86 092 个词汇

我们设置了ngram_range=(1, 2)min_df=2,这表明我们的词汇表将由单词和双词组成,文档频率至少为 2。通过消除文档频率仅为 1 的术语,我们可以减少模型中的特征数量,并减少过度拟合。注意,这种方法在这里工作得很好,因为我们的语料库包含成千上万的文档。这可能不适合较小的语料库,这些参数需要针对每个项目进行专门调整。

就像我们的模型需要以数字的形式接收 tweets 一样,它也需要以数字的形式接收政客的名字。这可以使用 scikit-learn 的[LabelEncoder](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html)来完成:

*from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
y = le.fit_transform(df['name'])

for i in range(len(le.classes_)):
    print(f'{le.classes_[i]:<15} = {i}')*

它分配以下标签:

*Bernie Sanders  = 0
Donald J. Trump = 1*

在训练我们的模型之前,将我们的数据集分成训练和测试集是极其重要的。训练集将用于训练我们的模型,但重要的是要有一个单独的测试数据集,以真正衡量我们的模型在以前从未见过的数据上有多准确。使用 scikit-learn 的[train_test_split](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html)功能:

*from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y,
                                    test_size=0.5,
                                    random_state=random_state,
                                    stratify=y)*

在这里,我们用test_size=0.5指定我们将保留 50%的数据集作为我们的测试集。我们还设置了[stratify](https://en.wikipedia.org/wiki/Stratified_sampling)=y,以确保我们的测试和训练数据集具有相同的伯尼·桑德斯和唐纳德·川普推文比率。

现在我们已经建立了数据,让我们看看我们的第一个算法。

逻辑回归

逻辑回归是最著名的机器学习模型之一,通常是大多数人在开始机器学习时首先学习的算法之一。标准逻辑函数如下所示:

**

标准逻辑函数。图片作者。

标准逻辑函数接收值 z 并输出 0 和 1 之间的值。我们正在处理一个二元分类问题,这意味着结果必须是伯尼·桑德斯或唐纳德·特朗普,没有其他选择。这就是为什么我们之前给每个政治家分配 0 或 1 的值。

现在让我们看看如何将一条 tweet 转换成一个值:

从这个等式中,我们看到 z 等于我们的 tfidf 向量( x )与添加了偏置项( b_0 )的权重向量( w )的点积。注意,虽然 Python 列表从 0 开始索引,但更常见的是在描述数学模型时从 1 开始索引,并为我们的偏差项保留索引 0(有时也会出现为 w_0 )。对于每条推文,我们可以计算一个值 z ,通过逻辑函数传递它,并四舍五入到最接*的整数,得到 0 =伯尼·桑德斯或 1 =川普。为了做到这一点,我们的机器学习算法需要计算出权重向量( w )的哪些值将导致最高比例的推文被归因于正确的政治家。

我们不会探究解决 w 的各种方法,因为这本身就是一篇完整的文章。Scikit-learn 实现了各种求解器来训练一个[LogisticRegression](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html)分类器。在这个应用中,我们将solver='[saga](https://arxiv.org/abs/1407.0202)'设置为我们的优化方法,将C=20设置为我们的逆正则项,以减少过度拟合,并使我们的模型更容易训练:

*from sklearn.linear_model import LogisticRegression

clf_log = LogisticRegression(C=20, solver='saga',
                             random_state=random_state,
                             n_jobs=n_jobs)

clf_log.fit(X_train, y_train)
log_score = clf_log.score(X_test, y_test)
print(f'Logistic Regression accuracy: {log_score:.1%}')*

这返回了我们在测试数据集上的准确性:

*Logistic Regression accuracy: 95.8%*

伯努利朴素贝叶斯

朴素贝叶斯分类器在文本分类任务中相对流行。我们将实现一个称为伯努利朴素贝叶斯的特定事件模型。每个政治家写的特定推文的可能性可以计算如下:

其中 p_ki ,是政客 C_k 在推文中使用术语 i 的概率。让我们使用 scikit-learn 的[BernoulliNB](https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.BernoulliNB.html)分类器来训练我们的模型,然后看看这些参数代表了什么:

*from sklearn.naive_bayes import BernoulliNB

clf_bnb = BernoulliNB(alpha=0.01, binarize=0.09)
clf_bnb.fit(X_train, y_train)*

现在让我们来看看下面伯尼·桑德斯的名言:

“全民医疗保险” -伯尼·桑德斯

此报价将包含术语“medicare for”。让我们看看这如何转化为上述等式中的参数:

*import numpy as np

C_k = 'Bernie Sanders'
k = le.transform([C_k])[0]
i = tfidf.vocabulary_['medicare for']
p_ki = np.exp(clf_bnb.feature_log_prob_[k, i])
print(f'k = {k}')  # class label
print(f'i = {i}')  # index for term 'medicare for'
print(f'C_k = {C_k}')
print(f'p_ki = {p_ki:.3}')*

它返回:

*k = 0  
i = 44798  
C_k = Bernie Sanders
p_ki = 0.0289*

这里, p_ki = 0.0289 可以解释为在我们的训练集中,来自伯尼·桑德斯的推文有 2.89%包含术语“医疗保险”。关于伯努利朴素贝叶斯有趣的是可以直接求解 p_ki。它简单地等于政治家 C_k 语料库中术语 i 的文档频率除以政治家 C_k 语料库中的文档总数:

*df_ki = clf_bnb.feature_count_[k, i]
n_k = clf_bnb.class_count_[k]
p_ki_manual = df_ki / n_k
print(f'{p_ki:.5}')
print(f'{p_ki_manual:.5}')*

这两者都为我们提供了相同的值,p_ki 有 4 个有效数字:

*0.028924
0.028922*

在逻辑回归中, x 包含 tfidf 值。在伯努利朴素贝叶斯中, x_i 必须等于 0 或 1。最简单的形式是,如果术语 i 出现在 tweet 中, x_i 等于 1,如果没有出现,则等于 0。然而,我们可以通过在我们的 tfidf 值上设置一个阈值来提取更多的信息。最佳阈值通常通过试错法或穷举搜索法找到,例如 scikit-learn 中的[GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html)。对于这个应用程序,一个最佳的阈值是binarize=0.09。因此,高于 0.09 的任何 tfidf 值被设置为 1,低于 0 的任何值被设置为 0。我们还设置了alpha=0.01,这是一个*滑参数。

回到我们的等式,我们可以看到,如果我们从用户那里接收到一个文档,其中 x_i = 1,那么我们正在乘以术语 i 出现在政治家 C_k 的推文中的概率( p_ki )。相反,如果 x_i = 0,那么我们就在成倍增加这个词 i 不会出现在政客 C_k 的推特上的概率。对词汇表中的每个术语和每个政治家都进行这种乘法运算。然后输出具有最高联合对数似然的政治家作为结果。记住当逻辑函数输出概率时,伯努利朴素贝叶斯输出可能性。这两个术语是相关的,但并不意味着同一件事。这里将不讨论将可能性转换成概率的方法,但是下面的维基百科条目包含了对该主题及其与逻辑回归的关系的简明讨论。此外,BernoulliNB可以使用它的[predict_proba](https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.BernoulliNB.html#sklearn.naive_bayes.BernoulliNB.predict_proba)方法将可能性转换成概率。现在让我们计算一下测试数据集的准确度:**

*bnb_score = clf_bnb.score(X_test, y_test)
print(f'Bernoulli Naive Bayes accuracy: {bnb_score:.1%}')*

它返回:

*Bernoulli Naive Bayes accuracy: 96.2%*

整体*均

我们训练了两个模型,逻辑回归和伯努利朴素贝叶斯,这两个模型在测试数据集上都具有相对较高的准确性。使用 scikit-learn 的[VotingClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.VotingClassifier.html),我们可以通过使用estimators=[('log', clf_log), ('bnb', clf_bnb)]选择我们的分类器并设置voting='soft'来获得一个更准确的结果,从而获得它们各自计算的概率的加权*均值。通过设置weights=(0.6, 0.4)将 60%的逻辑回归概率与 40%的伯努利朴素贝叶斯概率相加具有最高的准确性。一个有趣的结果,考虑到我们的伯努利朴素贝叶斯有更高的准确性,但我们赋予它更小的权重。这可能是因为来自我们的伯努利朴素贝叶斯分类器的潜在概率估计不一定像来自我们的逻辑回归分类器的概率计算那样可靠。现在让我们训练我们的集合模型:

*from sklearn.ensemble import VotingClassifier

clf_vot = VotingClassifier(
    estimators=[('log', clf_log), ('bnb', clf_bnb)],
    voting='soft', weights=(0.6, 0.4), n_jobs=n_jobs)

clf_vot.fit(X_train, y_train)
vot_score = clf_vot.score(X_test, y_test)
print(f'Ensemble Averaging accuracy: {vot_score:.1%}')*

这返回了我们在测试数据集上的准确性:

*Ensemble Averaging accuracy: 96.4%*

虽然这只是准确性的微小提高,但我们应该记住人们可能会输入不一定是任何一个候选人可能会说的信息。在这些情况下,整体*均可能是有益的,因为这相当于在决定哪位政治家更有可能在推特上发布用户所写的内容之前获得第二种意见。

最终培训

一旦我们确定不再改变任何超参数(,例如,朴素贝叶斯的阈值,投票的加权*均值,等)。)然后,我们可以在整个数据集上重新训练我们的模型,以获得两倍的训练样本。

*clf_vot.fit(X, y)*

使用应用程序

我希望你现在对 scikit-learn 如何应用于文本分类有了更好的理解,如果你是机器学习的新手,你现在有兴趣学习更多关于它的知识。

现在您可以亲自试用应用来看看我们实际操作过的模型!

*[## 谁说的?

写一条信息,看看伯尼·桑德斯和唐纳德·川普谁更有可能说出来。

www.shawnchahal.com](https://www.shawnchahal.com/who-said-it)*

确定兼容性

原文:https://towardsdatascience.com/determining-compatibility-b952d941c22a?source=collection_archive---------40-----------------------

配置管理示例

在各种行业和商业模式中,公司寻求评估兼容性;例如,关于工业配置管理、合同条款、供应链点、买方和供应商等等。

无论这一过程是与装配、生产还是数据分析相关,都需要检查数百万个组合,以评估组件是否匹配以及是否满足特定要求。大量的数据、复杂的流程和可扩展性问题意味着传统方法效率低下。

本文将展示如何使用 RDFox 使兼容性解决方案正确,迭代次数几乎不明显,并且比其他 RDF 存储快 50-100 倍。它将使用一个工业配置管理解决方案的例子。

例如,参见 Festo 案例研究。或者点击此处跟随配置解决方案网络研讨会

传统解决方案

传统上,SQL 数据库可用于确定兼容性。但是,这个过程很长,需要为每个组件创建表,连接表以形成更大的表,等等。然后使用完整的系统来评估兼容性。

确定与 SQL 数据库的兼容性

由于可能有数以千计的组件具有许多不同的特征,并且没有通用的模式,因此这个过程极其复杂并且令人厌倦,可扩展性有限。对于包含数万个组件的数据库,这个过程可能需要几个小时。

对于有时间压力和限制的企业来说,这带来了挑战,并可能限制竞争活力。每次添加或删除组件时,整个系统都需要更新,导致开发或修改过程中的长时间迭代。

为什么是 RDFox?

RDFox 是一个高性能的知识图和语义推理引擎。知识图由存储数据的图形数据库和解释并操作数据的推理层组成。关系数据库(如上面的 SQL 示例)以严格的表格结构存储数据,而图形数据库以节点(数据点,即主体或客体)和边(数据点之间的关系)的形式存储信息。这些结构差异为需要计算兼容性的用例提供了显著的优势,因为知识图克服了关系数据库的灵活性限制,允许将数据点编码为丰富连接的实体。

RDFox 是一个内存解决方案,这使得它非常快。强大的推理引擎在效率和推理能力方面无与伦比,通过使用规则,它可以提供灵活、增量的数据添加和撤销,以及新事实的快速并行具体化。

但是在配置解决方案的上下文中,推理意味着什么呢?

在这种情况下,推理就是理解和应用组件如何装配以满足客户需求的逻辑。

配置挑战

“给我造一个能以每分钟 2000 转的速度旋转并提供 800 克/厘米扭矩的装置”

一个基于 RDFox 的配置管理界面的例子。

对于这个例子,我们已经创建了一个简单的配置管理 web 应用程序,它允许我们查询数据库以获得提供特定需求的配置解决方案。结果是实时更新的,可以在右边看到。

对于一个包含数万个组件的数据库,包括电机、齿轮、开关、电源和控制器,我们需要检查数百万个潜在的组合来确定兼容性。这是通过计算组件是否匹配以及它们是否满足彼此的要求来完成的。每个组件都有一定的要求,并负责一定的规定;例如,如果电池电源和电机需要兼容的电压量。

为了开始这个过程,我们将每个组件的属性映射到知识图中。在这个例子中,我们有 500 个组件。

每个组件都会添加到图表中。此图提供了一个特定的 DC 发动机及其规定和要求的示例。

此外,我们可以向图中添加组件的本体。这将捕获组件层次结构并编码到系统中,提供子类和关系。在为特定配置解决方案查询数据集的过程中,以及在编写规则时,使用本体是有帮助的。

一旦所有组件的数据都存储在知识图中,我们就可以使用推理能力来建立组件的兼容性。使用 datalog 中表达的规则,我们可以轻松、正确地将组件兼容性的逻辑写入系统。

规则允许将组件的约束与组件属性进行比较,从而确定兼容性并为兼容性解决方案提供选项。然后,兼容的配置解决方案可以作为节点(数据点,在这种情况下是组件)之间的新边(关系)存储在知识图中。

这是 datalog 中兼容性规则的一个示例,可能会导致以下结果:

在检查这个特定的规则时,很明显规则是逻辑的表达式,datalog 提供了一种清晰的语言来编码规则。规则读作“如果…那么”语句。例如:左边的公式:- operator 是规则头(**then '部分 ) ,右边的公式是规则体(**' if '部分)。

直觉上,这个规则说,如果电源提供 DC 电压、特定量的电压和特定量的电流,而电机需要 DC 电压、相同量的电压和相同量的电流,那么这两者是兼容的。该示例显示了这两个组件基于组件的要求和规定是相互兼容的。

此示例仅代表一个配置序列。然而,该数据库包含 500 个组件和许多兼容性链。如果所有配置解决方案都经过计算并具体化到数据库中,那么配置解决方案将有多种途径,例如:

可以构建 Web 应用程序并将其附加到 RDFox 控制台,允许用户与知识图进行交互,而不必编写 SPARQL 查询。这对于要求整个公司的每个人都能够正确、快速地访问信息的企业来说有着重大的好处。通过在左侧的“搜索参数”框中键入搜索约束,将触发一个 SPARQL 查询,从知识图中请求信息。

配置管理应用程序

或者,不使用 web 应用程序,您可以使用 RDFox 的控制台直接与知识图交互。RDFox 使用 RDF 标准查询语言 SPARQL,它向知识图发送信息请求。

带有兼容性查询的 RDFox 控制台

上面的控制台包含使用示例数据库的配置解决方案的查询。查询表明选择了特定的扭矩和速度要求。该查询获取了 47 个答案,并在 0.702 秒内执行—眨眼之间,它就出现了!

通过使用规则,RDFox 可以在查询时间之前计算配置解决方案的所有兼容性。这种高级功能意味着查询比其他知识图解决方案更快,从而提高了企业的效率,因为解决方案提供得更快。这对用户体验和客户满意度产生了间接影响。不使用规则的系统将不得不在查询过程中确定兼容性,导致结果明显变慢。

添加或删除新项目时会发生什么?

在现实世界的应用程序中,组件将被添加到数据库中或从数据库中删除。这对使用长迭代周期数据库的公司来说是一个很大的限制。

新的组件数据可以在任何时候导入到 RDFox 中,同时还有它的兼容性规则。由于 RDFox 以增量方式处理更新,因此可以在不需要整个系统更新的情况下添加。

类似地,要删除一个组件,需要告诉 RDFox 删除它。一旦从数据中删除了组件,从该组件到其他组件(节点)的所有关系(边)也将被逐渐删除。

如果约束条件改变了呢?

与添加组件数据的过程类似,可以更新规则。这对于必须满足不断变化的约束(如预算、环境、需求等)的公司和客户来说非常重要。

这个增量特性是 RDFox 所独有的,并且提供了巨大的好处,因为它允许从应用程序中实时添加或删除规则和数据;例如,当组件不再生产、进货或缺货,或者产品被召回时。与其他兼容性解决方案相比,RDFox 在不影响性能的情况下提供灵活性的能力非常重要。

整体情况:

1.数据和规则进去了

2.RDFox 评估规则

3.使用 RDFox 控制台或基于该控制台构建的 web 应用程序,通过 SPARQL 查询来访问轮换解决方案。

知识图为数据建模提供了绝对的灵活性,因为规则可以对领域专业知识进行编码,并且可以定制以适应每个公司的需求。有关这一特定使用案例的更多信息,请观看网络研讨会。

要了解更多关于 RDFox 的信息,请访问我们的网站媒体出版物。要申请评估许可,请点击此处

团队和资源

牛津语义技术背后的团队于 2011 年在牛津大学计算机科学系开始研究 RDFox,他们坚信灵活和高性能的推理是数据密集型应用的一种可能性,而不会危及结果的正确性。RDFox 是第一个面向市场的知识图,它是从底层开始设计的,并考虑到了推理。牛津语义技术公司是牛津大学的一个分支,由主要投资者支持,包括三星风险投资公司(SVIC)、牛津科学创新公司(OSI)和牛津大学的投资部门(OUI)。笔者很自豪能成为这个团队的一员。

封面照片由作者在征得其子女同意后使用的主题。

利用加权 K-均值确定最优配送中心位置

原文:https://towardsdatascience.com/determining-optimal-distribution-centers-locations-using-weighted-k-means-1dd099726307?source=collection_archive---------20-----------------------

寻找在美国分发新冠肺炎疫苗所需的 DC 的位置和最佳数量

Unsplash 上的 CHUTTERSNAP 拍摄

背景

在座的各位一定听说过亚马逊及其*年来的增长。亚马逊成功的主要原因之一是其供应链管理。所有至少从亚马逊订购过一次的人都应该熟悉他们广受欢迎的 1 日送达服务。有没有想过像亚马逊这样的公司如何能如此迅速地将产品送到美国的任何地方?

考虑到美国广袤的土地和他们每天从全国各地收到的订单数量,这不是一个简单的任务。事实证明,你订购的大多数产品都是直接从你所在的州发货,而不是从其他地方。所有像沃尔玛、亚马逊这样的公司都会根据客户需求预测,在配送中心储存客户不急需的剩余产品。

所有的服务,如产品混合、订单履行、跨站台、包装都在配送中心完成。这些 DC 的位置便于在最短的时间内将货物运送到最大的区域。任何公司要想取得成功,有效的供应链战略是必不可少的,而 DC 在供应链战略中扮演着至关重要的角色。

问题

9 月 24 日,美国的 COVID 19 例病例总数已突破 700 万大关。另一方面,许多国家,如英国,声称他们的新冠肺炎疫苗开发已进入最后阶段,将于 2020 年底发布。我认为了解疫苗何时最终发布并在所有医院分发会很有趣,包括美国治疗新冠肺炎患者的临床中心。如果美国政府计划利用配送中心向所有治疗新冠肺炎患者的医院提供疫苗接种,DC 的配送中心应该设在哪里?需要多少个 DC?

首先,我从维基百科的一些网络垃圾开始,得到美国所有医院的地址和郡名。并将医院区域的县名与该区域中活跃的新冠肺炎病例进行匹配。为了使绘图和查找距离更容易,我使用地理编码找到了所有地址的纬度和经度,对此我在之前的博客中清楚地解释了步骤。

[## 使用 Python 进行地理编码和反向地理编码

当地址已知时查找纬度和经度,或者如果纬度和经度是…

towardsdatascience.com](/geocoding-and-reverse-geocoding-using-python-36a6ad275535)

找到所有医院的经纬度后对数据集的一瞥

图一。美国医院位置数据

既然我们有了纬度和经度,就很容易把它们标绘出来。下图显示了美国所有使用 python 中的 follow 地图生成的活跃新冠肺炎病例的医院。

图二。美国有活跃新冠肺炎病例数的医院位置(图片由作者提供)

这里,圆圈较大的点代表新冠肺炎活跃病例较多的区域。可以清楚地看到,加利福尼亚州的一些地区的活跃病例数最高。回到我们的问题,我们正试图找到配送中心向所有医院供应疫苗的最佳位置。这里,为特定医院确定 DC 的位置类似于将所有医院分成不同的集群,并为每个医院集群定位一个质心点。这种情况与 K-Means 聚类算法非常相似。因此,可以应用 K-均值聚类。

(标准)K 均值聚类是如何工作的?

K 均值聚类是一种流行的无监督 ML 算法,用于将数据划分为 K 个聚类。该算法反复工作,将每个数据点分配给 K 个组中的一个。数据被随机分成 K 组,每组分配一个*均质心点,算法迭代以找到:

  1. 所有数据点到质心点之间的距离,并通过将数据点重新分配到其最*的质心来形成新的聚类。
  2. 再次通过取距离的*均值找到新的质心点。

重复这个过程,直到距离*方和最小,或者达到预定的极限。

在开始 k-means 之前要执行的一个重要步骤是决定聚类的数量。K 的数量是一个预定义的超参数,应该对其进行调整以获得最佳结果。这可以使用肘方法来完成,本文稍后将对此进行简要说明。

这是一个通用的算法,可用于任何分组。用例的一些例子是基于需求的库存分组或基于购买的客户细分。

解题:

我们在这里的唯一问题是,应该更多地优先考虑新冠肺炎病例更活跃的地点。这就是加权 K 均值聚类发挥作用的地方。

标准的 K-means 方法不会起作用,因为它没有考虑到这样一个事实,即医院所在的一些地区有更多活跃的新冠肺炎病例,这意味着对要供应的疫苗有更高的需求量。

加权 K 均值与标准 K 均值有何不同?

加权 K-均值与标准 K-均值聚类的工作原理相同。唯一的区别是,不是仅仅根据距离的*均值来计算质心点。应该使用加权*均值。因此,数据点的权重越大,质心将被拉得越*。下图显示了标准 K 均值和加权 K 均值的对比。这里,在右图中,W2 和 W3 的数据点权重较高。所以,质心被拉着它们而不是位于中心。

图三。不带权重的左侧图像与带权重的右侧图像(作者提供的图像)

权重可以赋予我们想要从数据集中得到的任何变量,如城市或城市的总人口。在我们的例子中,权重将给予每个县的总活跃新冠肺炎病例。所以应该给他们更多的优先权。

另一个问题是,我们不能使用传统的欧几里德距离作为距离度量来寻找质心点,因为我们有代表地球球面维度的纬度和经度,而不是欧几里德距离中的 2D (x,y)坐标。许多选项可用于计算两个球形点之间的距离,如哈弗线距离或大圆距离。我们将使用哈弗线距离。

哈弗森距离

哈弗线距离 d 可以用下面的公式求出,其中φ代表纬度,λ代表经度。

A = sin((φB—φA)/2)+cosφA * cosφB * sin((λB—λA)/2)

c = 2 * atan2( √a,√( 1a))

d = R ⋅ c (R =地球半径,即 6371 公里)

幸运的是,我们不需要使用所有这些公式来计算哈弗辛距离,因为在 python 中,有一个名为哈弗辛的库,它用一行代码直接计算位置坐标之间的距离

from haversine import haversine
haversine((31.215827,-85.363433),(28.703230,-81.815668))

使用具有哈弗线距离的加权 K-Means 作为距离度量,创建了一个改进的加权 K-Means 算法,可以在我的 Github 库中找到。

最后,我们需要确定配送中心的最佳数量,以更好地满足需求并最小化配送费用。即 k 的最佳数量。这可以使用肘方法来确定。

肘法

在聚类分析中,肘方法是一种启发式方法,用于确定数据集中聚类的最佳数量。计算' k' 的不同值的组内误差*方和(SSE)。对于而言,无论哪个‘k’值 WSS 首先开始变小,都选择那个特定的‘k’。通常,形成弯头形状的 K 值被认为是最佳值。SSE 只不过是所有聚类中每个数据点到各自质心的距离的*方和。下图显示了 SSE 与我们数据的聚类数的关系。因为在 4 个聚类之后 SSE 值的降低不再显著。K=4 可以被认为是我们的最佳 K 值。

图 4。确定最佳聚类(K=4)的肘方法(图片由作者提供)

最后,我们发现 4 是所需配送中心的最佳数量。在用 4 个集群实现了我们的算法之后,DC 发现的位置如下所示:

图五。美国最佳配送中心位置(图片由作者提供)

实施该算法后发现的推荐 DC 位置为:

  1. 加州河滨
  2. 德克萨斯州达拉斯
  3. 伊利诺伊州厄巴纳
  4. 弗吉尼亚州彼得斯堡。

结论

在本文中,应用加权 K-均值聚类算法来确定最佳分布位置进行了演示。综上所述,在这种改进的 K-Means 聚类中,通过考虑加权*均值而不是*均值来计算质心,并且使用哈弗斯距离而不是欧几里德距离。

希望那有用!如果你有任何问题,请随时在 LinkedIn 上给我发信息。并且代码可以在我的 Github 库中找到。

德国联邦议院:谁是我们的代表?

原文:https://towardsdatascience.com/deutscher-bundestag-who-are-our-representatives-85a0e0c9669a?source=collection_archive---------46-----------------------

联邦议院:德国政治体系的议会和中央机构

利用主题建模和无监督学习分析第 19 届德国联邦议会

政治过程和政治机构的透明度是民主制度的关键要素。德国政治的核心机构是联邦议院,有来自六个不同政党的 700 多名议员。联邦议院通过法律,监督联邦预算,选举联邦总理。此外,全体会议是德国政治体系中交流政治立场和意见的核心小组。

但是组成议会并代表德国人民的 700 多人是谁呢?虽然联邦部长和一些选定的政治家经常出现在媒体和报刊上,但议会的大多数成员对普通公民来说实际上仍然是匿名的。

如果仔细观察德国的选举制度,这一观察结果会更加引人注目。对于德国议会的选举,每个选民投两票。在第一次投票中,地方代表被直接选举并送往议会,而第二次投票则是为政党名单投票。

为了确保透明度,议会讨论在电视上播出,每次辩论后都公布书面记录。然而,只有少数选民有时间和资源密切关注议会辩论,并在很大程度上依赖媒体报道。因此,几乎没有选民知道他们的地方代表在做什么,更不知道他或她在说什么,而这些地方代表实际上是被派到议会来代表他们的。

这个数据科学项目旨在通过应用机器学习和自然语言处理(NLP)的技术,进一步提高德国议会及其成员的透明度。项目的最终结果被可视化为 Tableau Public 上的一个交互式仪表盘:

桌面上的仪表盘公共(英文)(针对桌面优化&链接仅在桌面浏览器中有效)

【Dashboard on Tableau Public(德语)(针对桌面优化&链接仅在桌面浏览器中有效)

交互式 Tableau 仪表盘可视化结果摘录

该控制面板公开提供,并提供以下使用案例:

  • 了解每位议员的政治专业领域
  • 探索政党/政治家讨论的主题以及它们如何随着时间的推移而演变
  • 确定涉及类似主题的跨党派议员
  • 通读个别议员的全会发言

项目方法

在这个项目中,用 Python 分析了联邦议院的全体辩论,以得出关于个别议员的结论。为此,使用一种称为主题建模的 NLP 技术来检查全体会议演讲,以识别演讲中的潜在主题。使用主题洞察,然后通过应用无监督聚类将政治家分组到政治领域中。最后,开发了一种启发式方法来识别具有相似主题简介的对等组。

数据汇总

该项目的数据来源是第 19 届联邦议院从 2017 年 10 月 24 日首次会议到 2019 年 7 月 24 日夏季休会前最后一次会议的 109 份全体会议讨论记录。

德国议会已经在其网站上发布了自 1949 年德意志联邦共和国成立以来所有全会讨论的文字记录。然而,只有第 19 届联邦议院的 XML 文本包含了详细的标记,可以清楚地区分演讲和各自的演讲者。

使用 Python 库 Selenium 和 Beautiful Soup 对抄本进行抓取和解析,以提取日期、发言者姓名、政党和各自的发言等信息。然后,这些数据经过清理,并增加了额外的信息,最终得到一个由 717 位政治家的逾 1 万篇演讲(约 650 万字)组成的数据集。

请注意,第 19 届联邦议院正式成员为 709 人。这种差异可以通过以下偏差来解释:

1.当前内阁中在议会中没有正式席位的联邦部长也包括在数据集中。

2.根据某些议员的退出日期,数据中可能只反映前任、继任者或两者。

3.对于一些议员来说,在相关时间段内没有确定的发言。

主题建模概念

非负矩阵分解(NMF)是线性代数中的一种算法,应用于自然语言处理中,从一组文档中提取潜在的主题。

来自 NMF 的主题模型的基线构建了文档-术语矩阵 A。A中的每行描述了术语在文档中的出现频率,即每行代表一个文档,每列代表一个术语(文档 x 术语)。在 NLP 中,文档是文本的术语,术语是单词的术语。

NMF 算法将文档项矩阵 A 分解成仅具有非负值的两个矩阵,两个矩阵的乘积以最低误差再现原始矩阵。两个结果矩阵是文档-主题矩阵 H(文档 x 主题)和主题-术语矩阵 W ( 主题 x 术语)。

A(文档 x 期限)≈ H(文档 x 题目)x W(题目 x 期限)

直观地说,文档-主题矩阵 H 描述了文档中的主题是什么,而主题-术语矩阵 W 描述了特定主题中哪些词被频繁使用。

文本预处理

要使用 NMF 主题建模生成有意义的结果,需要几个预处理步骤,这些步骤按如下方式实现:

  • 通过删除标点符号、将所有单词转换为小写字母并排除所有数字来清理演讲
  • 通过应用 Python 的 NLTK 库中的德语停用词表,停用词(最常见的词)被移除。此外,用经常出现的上下文含义较低的单词手动扩展列表
  • 词干分析(将单词缩减为单词库)是通过应用 NLTK 雪球斯特梅尔公司的德语模块来完成的

然后,通过应用 sklearn 的 TF-IDF 矢量器,将议会演讲转换成文档术语矩阵。与简单的单词包方法(只统计单词在文档中的出现次数)相比,TF-IDF(术语频率-逆文档频率)减少了在所有文档中频繁出现的单词的影响。结果,具有高信息增益的单词在文档中也具有相对较高的权重。

话题识别

事实上,NMF 主题建模是一种矩阵分解技术,并不提供关于底层文本中存在多少主题或者主题的上下文含义是什么的指导。因此,这些步骤需要手动实现。

为了确定全体会议发言中的主题,将 sklearn 的 NMF 模块应用于先前创建的文件术语矩阵。这产生了各自的文档-主题和主题-术语矩阵。然后,对于主题-术语矩阵中的每个主题,手动检查具有最高权重的单词,即对于该主题最重要的单词。基于这种分析,每个主题被识别和命名。

例如,权重最高的词是“银行”、“贷款”、“存款保险”、“银行联盟”、“欧洲央行”、“纳税人”、“风险”、“金融危机”、等。(德语中这些都是单字)定义为“金融体系”。

9 个主题及其前 20 个单词的摘录(德语)

由于主题模型中的主题数量需要手动设置作为算法的输入,所以对不同数量的主题重复该过程,以识别在主题内的上下文一致性方面产生最有意义的结果的数量。对于联邦议院的演讲,选择了一个包含 35 个不同主题的模型。

在识别和命名每个主题后,文档-主题矩阵指示每个演讲涉及的主题。每个演讲都是所有 35 个主题的组合,其中一些主题的权重高于其他主题。

语音聚合

为了不仅对演讲,而且对议员个人产生洞察力,对每个政治家的主题信息(演讲中每个主题的权重)进行总结。议员的发言通过将发言中的主题权重之和缩放至 100%并取所有发言中主题的*均值来汇总。

聚类分析

这种汇总显示了每个议员在 35 个确定的主题中所占的份额。虽然这些信息本身就已经很有见地,但仍然相对难以解读,因为 35 个不同的主题很难同时掌握。此外,只有将几个话题结合起来,才能对政治家关注的政治领域得出有意义的结论。

因此,每位议员都根据其演讲的主题被分配到一个特定的政治领域。为此,使用 sklearn 的 KMeans 模块应用 k-means 聚类(无监督学习)。

直观上,k-means 分割一个数据集,将具有相似特征的数据点分配到一个组(聚类)中。基于距离度量(在这种情况下是欧几里德距离)来评估特征的相似性。该算法以这样的方式定义聚类,使得数据点到相应聚类质心的距离(一个聚类中所有数据点的特征的*均值)最小化。

通过将每个议员的话题权重作为特征,每个代表被反映为 35 维空间中的一个数据点。这些特征随后被用于对政客进行聚类。最后,手动检查每个聚类质心的主题份额,以分配政治领域。

例如,在“f 金融系统(11%)、“联邦预算(10%)、“经济(10%)中具有最高份额的集群被定义为“经济/金融政策”。

4 个集群的摘录和各自的前 8 个主题(按权重)

与主题模型类似,k-means 中的聚类数需要手动选择,并且通过手动检查不同数量的聚类的结果来选择。这导致 15 个不同的政治领域集群。

为了可视化聚类分析的结果,在最后一步中,通过使用来自 sklearn 的 TSNE 模块应用 t-SNE 维数缩减,将 35 维空间缩减为二维空间。

同等群体分析

同行群体分析的示例性结果(针对联邦总理安格拉·默克尔)

仪表板的一个用例是显示具有相似主题简介的不同政党的议会成员,即涵盖相似主题范围的政治家。为此,为每个政治家构建一个对等组,该对等组由来自每个政党的三名议会成员组成,基于 35 维主题向量具有最*的欧几里德距离。

可视化&验证

最后,分析的结果被可视化在一个 Tableau 仪表板中,可以交互地用于更好地理解联邦议院及其政治家。

联邦部长和国务秘书的集群分配

同时,仪表板提供了验证分析结果的机会:

  • 按党派划分份额最高的主题似乎是合理的,例如环境/能源对于邦迪尼斯 90/迪格鲁 NEN劳工对于迪克林以及数字化对于 FDP
  • 联邦部长和国务秘书的集群分配基本上与各自的度假胜地一致
  • 同辈群体似乎是合理的,例如,对于联邦总理安格拉·默克尔来说,同辈群体包括海科·马斯安东·霍夫赖特克里斯蒂安·林德纳莎拉·瓦根克内希特亚历山大·高兰

最终,我们希望该项目能够为提高德国政治环境的透明度做出自己的贡献,使选民能够做出更明智的决定,并增强对民主制度的信任。

一个 GitHub 项目的资源库可以在 这里找到

免责声明:本文仅代表作者个人观点,不代表作者雇主的工作或观点。

开发一个图像到图像的转换模型,以捕捉机械网络(GAN)中的局部相互作用

原文:https://towardsdatascience.com/develop-a-image-to-image-translation-model-to-capture-local-interactions-in-mechanical-networks-9c2f45230849?source=collection_archive---------45-----------------------

入门

生成式对抗网络,用于在各种机械网络的图像上自动绘制链接。

概观

超材料是一种机械性能依赖于其结构的材料,这种结构赋予了它们传统系统中没有的变形模式。超材料的一个流行模型由通过机械链接相互连接的构建模块组成,这定义了材料的结构。这些被称为机械网络。两个机械网络的不同之处在于:

  • 积木是如何连接的。这将定义我们处理的系统类别(例如 Kagome 系统、正方形、三角形等..).
  • 区块在空间中的分布情况,即区块之间的距离。

换句话说,为了对系统进行分类并掌握其机械特性,了解块体的位置和连接性是至关重要的。通常情况下,机械网络可以用一个晶格表示 : (也称为位置)来直观地描述,代表建筑块,并通过(也称为边)连接。在研究界经常被考虑的一个典型的机械网络是 Kagome 系统,如下图所示。

Kagome 点阵:点(黑点)由边(直线)连接。图片作者。

问题陈述和方法

在某些情况下,特别是在处理微观超材料时,用户/研究人员将只处理构件(点)的图像,连接键太小而无法检测,但仍然存在并对系统的机械性能有贡献。该项目旨在使用深度学习和神经网络在仅包含点的图像上自动绘制出键连接。

用户仅提供块的图像;模型绘制连接键。图片作者。

为此,我们将使用 Jason Brownless 博士的文章介绍如何开发一个生成式对抗网络(GAN) 作为图像到图像算法。该模型仅通过对三种不同机械网络(Kagome、三角形和正方形网格)的 90 张图像进行训练,就成功地在看不见的系统图像上绘制了连接键。虽然结果相当惊人,但了解该模型的架构也同样令人着迷。

用于训练/测试/验证模型的数据包括由 Mathematica 生成的图像,Mathematica 是一个经常用于研究和学术社区的程序。提供的每个图像实际上由一对图像组成,分别是具有和不具有结合的相同系统(即,点在空间上相同分布)。然后,我们选择 30 个随机生成的 Kagome 点阵,以及另外 30 个正方形点阵和 30 个三角形点阵:

无键和有键的变形正方晶格。图片作者。

变形的三角形晶格,有键和无键。图片作者。

这里使用的代码显然是由 Python 编写的,并且主要依赖于包 Keras (以及常见的嫌疑人 numpymatplotlib )来构建和训练多个神经网络。笔记本(可以在这里找到)是通过 Google Colab 编写的,它允许我们利用 Google 的 GPU 服务。

生成对抗网络

GAN 的架构由两个以对抗方式训练在一起的主要模型组成——鉴别器和生成器——以及将它们绑定和训练在一起的其他功能

鉴别器

鉴别器是一个深度卷积神经网络(CNN) ,它获取图像形状并执行条件图像分类。总之,它获取源图像(无焊接)和目标图像(有焊接),并分类目标是否是源的真实转换。在被传送到网络之前,这两幅图像被连接成一幅图像。

鉴别器模型。图片作者。

深度 CNN 由 6 层组成,每一层都缩小前一层的输出图像,以输出一个分数,该分数用作分类度量

发电机

生成器遵循 U-net 架构,由三部分组成:编码器(收缩)、瓶颈和解码器(扩展)。

发电机型号。Jason Brownless 关于机器学习掌握的图片。

  1. 编码器部分由多个对输入图像进行下采样的模块组成。每个块都是一个卷积层,具有数量不断增加的过滤器。
  2. 相反,解码器由几个扩展模块组成,滤波器数量不断减少。重要的是,每个扩展层的输入既有前一个扩展块的输出,也有相应收缩块的输出。这确保了在编码阶段学习的特征被重新用于在解码阶段重建图像。
  3. 瓶颈部分连接编码和解码部分。

复合模型和训练模型

生成对抗网络是一个同时包含鉴别器和生成器的复合模型。当生成器通过鉴别器更新其权重时,鉴别器不被训练并“自己”更新其权重。关键特征是,与生成器相比,鉴别器的权重更新需要较慢,因此生成器可以快速学习绘制焊接。

每个训练步骤包括使用复合模型以及来自训练数据的“真实”图像和来自生成器的“虚假”生成图像。这个想法是,真实目标和假生成图像的组合,分别被分类为 1 和 0,将帮助生成器建立一个模型,更快地收敛到一个解决方案。

GAN 的整体架构及其训练方式。图片作者。

这个模型中有许多可调参数和复杂的设计。为了保持这篇文章的简单和可读性,我故意忽略了代码的复杂性,但是请读者查看我的 Github 库以获得更多细节。

结果

我们在 90 幅图像上训练该模型,分成 3 批,这意味着在每个时期的每批中随机抽取 30 幅图像。我们选择在 500 个历元上训练模型,这意味着总共有 500 x 30 = 15,000 个迭代步骤。虽然在本地机器上训练模型可能需要长达一天的时间,但谷歌 GPU 将这一过程加快到不到 2 小时!通过迭代过程,我们显示了从训练数据集中随机抽取的样本的生成图像:

通过模型训练生成的图像(随机选择)的演变。图片作者。

对照模型自己的训练集测试模型不是检查其性能的好选择,但它让我们了解生成功能执行得有多好。因此,我们还需要展示模型如何处理看不见的数据:

验证集:戈薇,正方形和三角形格子。图片作者。

最初,我的目标是只针对 Kagome 类构建模型。然后,我决定扩大模型的应用范围,将正方形和三角形格子包括在内:

  • 顶行:第一个模型仅在 Kagome 系统的图像上进行训练,显然在绘制正方形和三角形的连接方面存在困难
  • 底部一行:第二个模型包含了所有三个格子,产生了更好更重要的结果

非常重要的是,除了绘制键之外,第二个模型还保持所生成图形上的点的位置,这是一个必须保持不变的关键属性,因为这些点的位置决定了系统的机械属性(如上所述)。

结论和进一步改进

通过只对 90 对图像进行训练,该模型可以获取部分完整的机械网络的看不见的图像,并绘制正确的键连接,这是理解系统力学的关键特征。这样做,模型不会改变材料的基本属性(点/块的位置),并为研究者提供额外的信息。令人兴奋的是,该模型能够在不止一个,而是三个机械系统上区分和执行其图像到图像的翻译功能:Kagome,正方形和三角形晶格。

虽然这是一个令人满意的结果,但是可以做许多事情来提高模型的性能。特别是,我们可以:

  • 在更大的一组图像上训练模型并持续更长的时间(更多的时期)
  • 扩大训练批次,以包括额外的超材料类别,特别是更复杂的结构,如每个站点的*均连接数比我们迄今为止看到的更多

参考文献和致谢

同样,代码、幻灯片和报告可以在这里找到。所有图片(除非另有说明)均由作者制作。我要特别感谢我在 Springboard 的导师卢卡斯·艾伦(Lucas Allen),感谢他在这个项目中的指导。我还要感谢 Brownlee 博士在帮助开发人员构建机器学习模型方面的多个在线教程。

[1] J. Brownlee,如何开发一个 Pix2Pix GAN 用于图像到图像的翻译 (2020),机器学习之谜

开发基于 CNN 的交互式绘图识别应用程序——使用 Flask 部署

原文:https://towardsdatascience.com/develop-an-interactive-drawing-recognition-app-based-on-cnn-deploy-it-with-flask-95a805de10c0?source=collection_archive---------20-----------------------

数据科学项目

关于数据科学项目的基本技术的快速简单的教程。

照片由 Dries AugustynsUnsplash 拍摄

建立机器学习模型是一项常见的任务,你可能会觉得很舒服。然而,一旦你离线训练和测试的模型让你满意了,你该怎么做呢?你会如何向你的非技术型老板或客户展示它?你将如何在线部署它,以便其他人可以使用它?

在本文中,我将尝试解决那些在学校里通常不会详细讨论的问题,尽管这些问题是数据科学项目中非常重要的一部分。

为此,我决定以一个绘图应用程序为例,它使用一个卷积神经网络模型对用户绘制的绘图进行分类。

工作流程如下:

我将首先介绍模型,然后描述应用程序的开发。通读之后,我希望本文对您未来的数据科学项目部署有所帮助!

以下所有代码都可以在我的 github 上找到。

CNN 模型

这个项目的第一部分是准备数据和建立我们的模型!

我已经决定使用来自的数据,‘快,画!’游戏中用户需要尽可能快地绘制任意对象。数据集在这里可用。

我将我的用例集中在 6 动物上:猫、长颈鹿、羊、蝙蝠、章鱼和骆驼,使任务成为多类分类。下面是一个数据示例:

预处理

幸运的是,来自这个数据集的图像已经被预处理成统一的 2828* 像素图像大小。以下是接下来的步骤:

  • 我们需要结合我们的数据,以便我们可以使用它进行培训和测试。我只为这个模型使用了 10 000 个样本。
  • 然后,我们可以分割要素和标注(X 和 y)。
  • 最后,我们按照通常的(80–20)比率在训练和测试之间分割数据。当灰度图像的像素位于 0 和 255 之间时,我们还归一化了 01 (X/255)之间的值。

预处理. py

架构

一旦一切准备就绪,让我们使用 Keras 建立我们的模型!该模型将具有以下结构:

  • 卷积层 : 30 个滤波器,(3 * 3)内核大小
  • 最大池层数 : (2 * 2)池大小
  • 卷积层 : 15 个滤波器,(3 * 3)内核大小
  • 最大池层 : (2 * 2)池大小
  • 脱落层:脱落 20%的神经元。
  • 展*图层
  • 密集/全连接层 : 128 个神经元,Relu 激活功能
  • 密集/全连接层 : 50 个神经元,Softmax 激活功能

下面是相应的代码:

Cnn 模型

现在我们的模型已经准备好了,我们只需要训练它并评估它的性能。

经过 15 个时期后,我们的分类器达到了 92.7% 的准确率,这对于我们的识别 app 来说已经足够了!让我们检查一下混淆矩阵。

正如我们所看到的,大部分的画都被很好的分类了。然而,有些类别似乎比其他类别更难区分:例如,猫与蝙蝠或骆驼与羊。这可以用它们形状的相似性来解释!

这是一些被我们的模型错误分类的图片。这些图像中的大部分很容易被误认为是错误的,甚至是被人眼误认为是错误的!别忘了我们的数据集收集了玩‘快,画吧!’的手工人类图画游戏。因此,许多图像可能与一个类无关。

保存模型

现在我们的模型已经准备好了,我们想把它嵌入到一个Flask Web App中。为此,使用 pickle 保存(序列化)我们的模型会更方便。

注意:你可以直接将你的模型训练到 flask 中,但是这将会非常耗时,而且对用户不友好。

**import** **pickle**
**with** open('model_cnn.pkl', 'wb') **as** file:
      pickle.dump(model_cnn, file)

用 Flask 开发我们的绘图应用程序

烧瓶

Flask 是一个用 Python 编写的 web 微框架。它允许你设计一个可靠和专业的 web 应用程序。

它是如何工作的?

虽然它不需要特定体系结构,但是有一些好的实践可以遵循:

  • app.py :是运行 Flask 应用程序的主要代码。它将包含我们的应用程序的不同路由,响应 HTTP 请求并决定在模板中显示什么。在我们的例子中,它还会调用我们的 CNN 分类器对我们的输入数据进行预处理步骤,并进行预测
  • 模板文件夹:模板是一个 HTML 文件,可以接收 Python 对象,链接到 Flask 应用。因此,我们的 html 页面将存储在这个文件夹中。
  • 静态文件夹:样式表、脚本、图片等永远不会动态生成的元素必须存放在这个文件夹中。我们将把 Javascript 和 CSS 文件放在里面。

该项目将需要:

  • 两个静态文件: draw.jsstyles_draw.css
  • 两个模板文件:draw.htmlresults.html
  • 我们的主文件: app.py
  • 我们的 model_cnn.plk 早存了。

现在,让我们来构建我们的应用程序吧!

获取用户输入

这个项目的第二部分是获得用户输入:一个将被我们训练好的模型分类的绘图。为此,我们将首先使用 javascriptHTML5 设计绘图区域。我不会在本文中介绍 styles_draw.css 但是你可以在我的 github 上找到它。

draw.html

draw.html

  • 我们使用{{url_for('static',filename='styles_draws.css’)}}{{url_for('static',filename='draw.js’)}}导入位于静态文件夹中的 css 和 js 文件。这是 Jinja 导入文件的语法。
  • 我们用<canvas>标签设置我们的绘图区域。
  • 我们调用 draw.js 中包含的 drawCanvas() javascript 函数。
  • 我们初始化表单,这样就可以使用POST方法将数据发送到 flask 实例/ app.py
  • action = “{{url_for('predict')}”又是金贾句法。它指定了提交表单时将在 app.py 中使用的路径。
  • 我们在表单中添加了一个额外的隐藏字段,用于传输图像。<input type = “hidden“ id =’url' name = ‘url' value = “”>
  • 仅此而已!简单对吗?

我们现在必须使用 javascript 来使它更加动态!否则,你的画布什么也做不了…

draw.js

draw.js

这段 Javascript 代码允许我们设计绘图区域并与之交互。

  • drawCanvas() 旨在初始化画布的主要功能(mouseUp、mouseDown、…),这些功能将允许与用户的鼠标进行交互。
  • addClick() 保存用户点击画布时光标的位置。
  • redraw() 每次调用该函数时,清除画布并重新绘制所有内容。

在我画完之后,画布看起来是这样的(顺便说一下,这是一只长颈鹿) :

Draw.html

现在我们的画布已经准备好获取用户的绘图,我们需要确保图像能够到达我们在 app.py 中的应用程序。

通常我们可以直接使用POST函数,通过一个表单提交数据。然而,目前不能用这种方法提交原始图像。此外,我不希望用户保存然后上传他的画,因为这会影响他的体验的流畅性。

我用来克服这个问题的一个小技巧是,在通过表单发送之前,使用之前在results.html中设置的隐藏输入字段,在 base64 中对图像进行编码。该编码过程将在 app.py. 中反向进行

  • 当用户点击‘预测’按钮时,调用 save() 。它将通过表单发送 base64 编码的图像。

做预测

既然我们能够获得用户输入,那么是时候使用它来进行预测了!为此,我们只需要一个文件:

app.py

如前所述, app.py 是我们项目的主文件,Flask 应用程序在其中被实例化。

app.py

本规范的要点:

1) 初始化 app,指定模板文件夹。我们可以使用这行代码来实现:

app = flask.Flask(__name__, template_folder =’templates’)

2) 定义路线(我们的应用程序只有两条) :

  • @app.route('/') :是我们默认的路径——它会返回默认的draw.html模板。**
  • @app.route('/predict') :点击‘预测’按钮时调用。处理用户输入后返回results.html模板。**

3)预测功能将由表单中的POST动作触发(还记得我们在result.html中设置此路径时感谢 Jinja 语法!).然后,它将按如下方式进行:**

  • request.form['url']访问 base64 编码图形输入,其中“url”是包含编码图像的表单中隐藏输入字段的名称
  • 解码图像并将其设置为一个数组。
  • 调整图像的大小和形状,为我们的模型获得一个 28 * 28 的输入。我们关心的是保持它的比例。
  • 使用我们的 CNN 分类器进行预测。
  • 由于model.predict()返回单个数组中每个类的概率,我们必须找到数组的最高概率,并使用预定义的字典获得相应的类。
  • 最后返回results.html模板,并将之前做的预测作为参数传递:

return render_template('results.html', prediction= final_pred)

:

—我们的 base64 编码图像看起来会像这样:data:image/png;base64,iVBOR…。因此,我们只需要删除第一个 21 字符就可以得到干净的 url。为此,我们使用了draw[init_base64:]行代码。—

显示结果

仅此而已!几乎一切都搞定了。下一步是展示我们的结果。

results.html

最后,我们使用results.html来显示在 app.py 中计算的预测。我们将再次需要使用 Jinja 语法来显示预测

results.html

下面是我们预测是“长颈鹿”时的渲染图:

显示结果

运行应用程序

最后一步是启动我们的应用程序!你可以进入你的绘图应用文件夹(你可以在根目录下找到 app.py 并使用flask run.

烧瓶运行

您的应用将在本地服务器上运行。默认为 127.0.0.1:5000

绘图应用程序

结论

就是这样!在本文中,我们看到了如何开发一个烧瓶绘图应用程序,它使用以前构建的 CNN 模型对用户绘制的绘图进行分类。

这是 Flask 部署机器学习模型的众多可能用途之一。事实上,可以找到无限的用例,我希望这个具体的项目将帮助您构建其他 ML web 应用程序,使您的代码更容易被他人访问!

所有代码在我的github上都有!

祝您愉快!

参考

当然,这不是我一个人做的。我在这里找到了一些灵感:

** [## “快,画!”-使用 Python 对图形进行分类

图像识别一直是机器学习中的一个主要挑战,与大规模标记数据集一起工作来训练…

www.datacareer.de](https://www.datacareer.de/blog/quick-draw-classifying-drawings-with-python/) [## 欢迎使用 Flask - Flask 文档(1.1.x)

欢迎阅读 Flask 的文档。开始安装,然后了解快速入门概述。有…

flask.palletsprojects.com](https://flask.palletsprojects.com/en/1.1.x/) [## 使用 HTML5 Canvas 和 JavaScript 创建一个绘图应用程序

威廉·马隆:本教程将带你一步一步地开发一个简单的网络绘图应用程序…

www.williammalone.com](http://www.williammalone.com/articles/create-html5-canvas-javascript-drawing-app/) [## 用 Python 中的卷积神经网络进行手写数字识别

深度学习技术能力的最新流行演示是图像中的对象识别…

machinelearningmastery.com](https://machinelearningmastery.com/handwritten-digit-recognition-using-convolutional-neural-networks-python-keras/)**

开发和销售机器学习应用程序—从头到尾教程

原文:https://towardsdatascience.com/develop-and-sell-a-machine-learning-app-from-start-to-end-tutorial-ed5b5a2b6b2b?source=collection_archive---------2-----------------------

入门

摄影丹尼尔·科尔派https://unsplash.com/photos/HyTwtsk8XqA

新冠肺炎预测端到端 app

在开发和销售 Python API 之后,我现在想用机器学习解决方案来扩展这个想法。所以我决定快速编写一个新冠肺炎预测算法,部署它,并使它可以销售。如果你想知道我是如何做到的,可以查看帖子里的一步一步的教程。

目录

关于这篇文章

在本文中,我从我的上一篇文章“如何从头到尾销售一个 Python API”中汲取了一些思想,并构建了一个机器学习应用程序。如果这里描述的步骤太粗糙,可以考虑先看看我以前的文章。

本项目涉及许多新的、更复杂的问题:

  1. 机器学习内容。该应用程序采取构建机器学习模型的基本步骤。这包括准备,也包括预测。
  2. 在预测的时间评估(不是时间训练)中。这意味着数据集是新获取的,并且对最新数据执行预测。
  3. 部署。部署机器学习应用程序面临各种挑战。在本文中,我们遇到并解决了在 AWS 上外包训练模型的问题。
  4. 它不仅是一个 API,而且还有一个小前端。

它从头到尾描绘了一幅开发 Python API 的图画,并在更困难的领域提供了帮助,比如 AWS Lambda 的设置。

有各种各样的困难,这让我对部署和构建过程有了更多的了解。这也是一个很好的方式来建立副业项目,甚至可能赚一些钱。

如目录所示,它由 4 个主要部分组成,即:

  1. 设置环境
  2. 使用 Python 创建问题解决方案
  3. 设置 AWS
  4. 设置 Rapidapi

你会发现我所有的代码都在 Github 上打开:

您将在 Rapidapi 上找到最终结果:

放弃

我与本文中使用的任何服务都没有关联。

我不认为自己是专家。如果你觉得我错过了重要的步骤或者忽略了什么,可以考虑在评论区指出来或者联系我。此外,始终确保监控您的 AWS 成本,不要为您不知道的事情付费。

我总是乐于听取建设性的意见以及如何改进。

有许多事情需要改进和发展。比如机器学习部分,付出的努力非常低。准备工作非常粗糙,缺少许多步骤。从我的专业工作来看,我知道这个事实。然而,我无法在一篇文章中涵盖所有细节。尽管如此,我还是很想在评论中听到你们的改进建议。😃

如果你需要更多关于某些部分的信息,请在评论中指出来。

关于术语“教程”

我认为这是一个循序渐进的教程。然而,由于我作为一名开发人员已经工作了很长时间,我假设对某些工具有所了解。这使得教程很可能是一个中级/高级应用程序。

我假定了解:

  • 计算机编程语言
  • 饭桶
  • Jupyter 笔记本
  • 终端/Shell/Unix 命令

使用的堆栈

我们将使用

  • Github(代码托管),
  • 依赖和环境管理,
  • Docker(可能在微服务中进一步使用)
  • Jupyter 笔记本(代码开发和文档),
  • Python(编程语言),
  • AWS,尤其是 AWS Lambda 和 S3(用于部署)、
  • Rapidapi(销售市场)

1.创建项目手续

它总是一样的,但却是必要的。我按照以下步骤来做:

  1. 创建本地文件夹mkdir NAME
  2. NAME在 Github 上创建一个新的存储库
  3. 创造康达环境conda create --name NAME python=3.7
  4. 激活康达环境conda activate PATH_TO_ENVIRONMENT
  5. 创建 git 回购git init
  6. 连接到 Github repo。添加自述文件,提交并
git remote add origin URL_TO_GIT_REPO
git push -u origin master

2.开发解决问题的方法

由于我们将开发一个机器学习解决方案,Jupyter 笔记本将非常有用。

正确安装软件包和跟踪 Jupyter 文件

安装 jupyter 笔记本和 jupytext:

pip install notebook jupytext

在 jupyter 中注册新环境ipython kernel install --name NAME--user

.git/hooks/pre-commit中设置一个钩子,用于正确跟踪 git 中的笔记本变化:

touch .git/hooks/pre-commit
code  .git/hooks/pre-commit

把这个复制到文件里

#!/bin/sh
# For every ipynb file in the git index, add a Python representation
jupytext --from ipynb --to py:light --pre-commit

之后让钩子可执行(在 mac 上)

chmod +x .git/hooks/pre-commit

找到解决问题的方法

目标

目前,世界处于疫情,我想我使用了新冠肺炎案例的多个数据集之一。鉴于数据集的结构,我们希望预测一个国家每天的新增感染病例。

pip install -r requirements.txt

这将安装我们需要的所有软件包。看看/development/predict_covid.ipynb笔记本,看看都用什么库。

最重要的是图书馆

  • 熊猫用于转换数据集和
  • 用于机器学习的 sklearn

对于以下小标题,请查看 Jupyter 笔记本了解更多详情:

https://github . com/Createdd/ml _ API _ covid/blob/master/development/predict _ covid . ipynb

下载数据

我们将使用来自https://ourworldindata.org/coronavirus-source-data的 csv 格式的数据集。

准备

简而言之,我做到了:

  1. 检查丢失的数据
  2. 删除丢失数据超过 50%的列
  3. 删除剩余缺失内容的行,如洲或等编码。(对需要国家/地区的应用程序解决方案没有帮助)
  4. 用标签对分类数据进行编码
  5. 用该列的*均值填写剩余的数字缺失数据
  6. 分为训练集和测试集

创建分类器并预测

  1. 创建随机森林回归变量
  2. 用数据训练它并评估
  3. 使用 RandomizedSearchCV 执行超参数调整
  4. 保存训练好的模型
  5. 通过提供国家名称来预测新病例

构建一个服务器来执行 REST 的功能

对于 API 功能,我们将使用 Flask 服务器(在app.py中)

服务基本前端

@app.route('/')
def home():
    return render_template("home.html")

它提供一个基本的 HTML 和 CSS 文件。

应用程序前端

负荷预测

这个有点复杂。

关键路线是这样的:

但是在我们返回预测结果之前,我们需要获得最新的数据并再次对其进行预处理。这已经结束了

为了机器学习的目的,Pre-process再次转换下载的数据集,而get_prediction_params获取输入值(要预测的国家)和最新数据集的 URL。

这些过程使最新数据的预测成为现实,但也减慢了应用程序的速度。

你可能想知道我们为什么做rf = load_model(BUCKET_NAME, MODEL_FILE_NAME, MODEL_LOCAL_PATH)。这样做的原因是,当使用 AWS Lambda 执行所有操作时,我们需要从 AWS S3 存储桶中加载预训练模型以节省内存。向下滚动查看更多详细信息。

但是如果我们不想把它部署在云中,我们可以简单地做一些类似于joblib.load(PATH_TO_YOUR_EXPORTED_MODEL)的事情。在笔记本中,我们用joblib.dump导出模型。 sklearn 文档中关于模型导出的更多信息

但这仅仅是高射炮服务器的功能。提供用于服务 HTML 模板的路径和用于预测的路径。相当简单!

正在运行

env FLASK_APP=app.py FLASK_ENV=development flask run

将启动服务器。

工作应用

好处:使 Docker 可复制

也许你想扩展应用程序,或者让其他人更容易地测试它。为此,我们可以创建一个 Docker 容器。我不会详细解释它是如何工作的,但如果你感兴趣,可以查看我的“灵感”部分的一个链接。

构建一个 Docker 容器并不是让这个应用程序工作的必要条件!

创建 Dockerfile 文件

FROM python:3.7ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1ENV FLASK_APP=app.py
ENV FLASK_ENV=development# install system dependencies
RUN apt-get update \
    && apt-get -y install gcc make \
    && rm -rf /var/lib/apt/lists/*sRUN python3 --version
RUN pip3 --versionRUN pip install --no-cache-dir --upgrade pipWORKDIR /appCOPY ./requirements.txt /app/requirements.txtRUN pip3 install --no-cache-dir -r requirements.txtCOPY . .EXPOSE 8080CMD ["gunicorn", "--bind", "0.0.0.0:8080", "app:app"]

注意:最后一行用于启动 Flask 服务器

创建Dockerfile运行后

docker build -t YOUR_APP_NAME .

然后呢

docker run -d -p 80:8080 YOUR_APP_NAME

之后,你会看到你的应用在[http://localhost/](http://localhost/)上运行

3.部署到 AWS

到目前为止,这是一条相当容易的道路。不要太复杂,也不要太花哨。现在我们开始部署,它变得有趣和具有挑战性。

同样,如果您对 Zappa 和 AWS 有任何问题,我强烈建议您查看我以前的文章https://towardsdatascience . com/develop-and-sell-a-python-API-from-start-to-end-tutorial-9a 038 e 433966

这里我不再赘述,而是指出痛点。

设置 zappa

在我们本地创建应用程序后,我们需要开始在一个真实的服务器上设置主机。我们将使用 zappa

Zappa 使得在 AWS Lambda + API Gateway 上构建和部署无服务器、事件驱动的 Python 应用程序(包括但不限于 WSGI web apps)变得超级简单。可以把它想象成 Python 应用程序的“无服务器”网络托管。这意味着无限扩展、零停机、零维护,而成本只是您当前部署的一小部分!

pip install zappa

由于我们使用的是 conda 环境,我们需要指定它:

which python

会给你/Users/XXX/opt/anaconda3/envs/XXXX/bin/python(针对 Mac)

移除bin/python/并导出

export VIRTUAL_ENV=/Users/XXXX/opt/anaconda3/envs/XXXXX/

现在我们能做的

zappa init

来设置配置。

只要点击浏览所有内容,你就会有一个zappa_settings.json的样子

{
    "dev": {
        "app_function": "app.app",
        "aws_region": "eu-central-1",
        "profile_name": "default",
        "project_name": "ml-api-covid",
        "runtime": "python3.7",
        "s3_bucket": "zappa-eyy4wkd2l",
        "slim_handler": true,
        "exclude": [
            "*.joblib", "development", "models"
        ]
    }
}

没错。不要为 s3 存储桶输入名称,因为找不到它。我真的不知道给你的 s3 桶命名有什么问题,但是从来没成功过。有多个错误语句,我无法解决这个问题。只要留下建议的那个,一切都很好。;)

请注意,我们还没有准备好部署。首先,我们需要获得一些 AWS 凭证。

设置 AWS

注意:这需要相当大的努力。不要因为 AWS 及其策略管理的复杂性而气馁。

AWS 凭据

首先,你需要得到一个 AWS access key idaccess key

使用 IAM 中的用户和角色设置凭据

我尽可能简单地分解它:

  1. 在 AWS 控制台中,在搜索框中键入 IAM。IAM 是 AWS 用户和权限仪表板。
  2. 创建一个组
  3. 为您的群组命名(例如 zappa_group)
  4. 为您的小组创建我们自己的特定内联策略
  5. 在“权限”选项卡的“内联策略”部分下,选择链接以创建新的内联策略
  6. 在设置权限屏幕中,单击自定义策略单选按钮,然后单击右侧的“选择”按钮。
  7. 创建一个用 json 格式编写的定制策略
  8. 通读并复制此处讨论的一项政策:https://github.com/Miserlou/Zappa/issues/244
  9. 向下滚动到“我的自定义策略”查看我的策略的片段。
  10. 使用您的 AWS 帐号粘贴和修改 json 后,单击“验证策略”按钮以确保您复制了有效的 json。然后单击“应用策略”按钮,将内联策略附加到该组。
  11. 创建一个用户并将该用户添加到组中
  12. 回到 IAM 控制面板,使用“用户”左侧菜单选项和“添加用户”按钮创建一个新用户。
  13. 在“添加用户”屏幕中,为新用户命名,并选择编程访问的访问类型。然后点击“下一步:权限”按钮。
  14. 在“设置权限”屏幕中,选择您之前在“将用户添加到组”部分创建的组,然后单击“下一步:标记”。
  15. 标签是可选的。如果需要,添加标签,然后单击“下一步:查看”。
  16. 查看用户详细信息,然后单击“创建用户”
  17. 复制用户的密钥
  18. 先不要关闭 AWS IAM 窗口。在下一步中,您将把这些密钥复制并粘贴到一个文件中。此时,将这些密钥复制并保存到一个安全位置的文本文件中不失为一个好主意。确保不要在版本控制下保存密钥。

我的自定义策略:

正如你在政策中看到的,我添加了 S3 的相关政策。这是因为我们想从 S3 下载我们的预训练模型。稍后会有更多信息。

在项目中添加凭据

在你的根目录下创建一个.aws/credentials文件夹

mkdir ~/.aws
code ~/.aws/credentials

并从 AWS 粘贴您的凭据

[dev]
aws_access_key_id = YOUR_KEY
aws_secret_access_key = YOUR_KEY

config相同

code ~/.aws/config# and add:[default]
region = YOUR_REGION (eg. eu-central-1)

注意,code是用我选择的编辑器 vscode 打开一个文件夹。

将分配给用户的 AWS 访问密钥 id 和秘密访问密钥保存在文件~/中。AWS/凭据。请注意。aws/ directory 需要在您的主目录中,并且凭据文件没有文件扩展名。

部署

现在,您可以使用

zappa deploy dev

但是,有一些事情需要考虑:

  1. Zappa 将打包您的整个环境和整个根内容。这个会很大。
  2. AWSλ有一个上传限制

减小上传大小

有几个关于如何用 zappa 减少上传大小的讨论。查看灵感部分的链接。

首先,我们需要为上传减少包的大小。

我们将把所有探索性的内容放入一个自己的文件夹中。我把它命名为“发展”。之后,您可以使用 exclude 在 zappa_settings.json 中指定排除的文件和文件夹:

{
    "dev": {
        ...
        "slim_handler": true,
        "exclude": [
            "*.ipynb", "*.joblib", "jupytext_conversion/", ".ipynb_checkpoints/",
            "predict_covid.ipynb", "development", "models"
        ]
    }
}

您可以添加部署时不需要打包的任何东西。

另一个问题是环境依赖性。在我们的例子中,我们有多个依赖项,这是部署所不需要的。为了解决这个问题,我创建了一个新的“requirements_prod.txt”文件。这应该只有 AWS 上需要的依赖项。

请确保使用导出您当前的包

pip freeze > requirements.txt

之后,卸载所有软件包

pip uninstall -r requirements.txt -y

安装用于部署的新包,并将它们保存在文件中

pip install Flask pandas boto3 sklearn zappapip freeze > requirements_prod.txt

当你点击zappa deploy dev时,需要打包的尺寸应该会小很多。

你会注意到我还设置了slim_handler=true。这允许我们上传超过 50MB。在幕后,zappa 已经将内容放入自己的 S3 桶中。阅读 zappa 文档了解更多信息。

将模型装入 S3 存储桶

因为我们从 AWS Lambda 上传中排除了我们的模型,所以我们需要从其他地方获取模型。我们将使用 AWS S3 铲斗。

在开发过程中,我试图上传程序,但我只是手动上传,因为它现在更快了。(但您仍然可以尝试上传它——我在回购中仍有一个注释文件)

https://console.aws.amazon.com/s3/

  1. "创建存储桶"
  2. 给定一个名称,将 rest 作为缺省值。检查是否有足够的权限。
  3. "创建存储桶"

检查您是否有足够的策略来与 bucket 和 boto3 交互。您应该有类似于

{
      "Effect": "Allow",
      "Action": [
        "s3:CreateBucket",
        "s3:ListBucket",
        "s3:ListBucketMultipartUploads",
        "s3:ListAllMyBuckets",
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::zappa-*",
        "arn:aws:s3:::*"
      ]
    }

调试和更新

最后,不应该再有任何错误了。但是,如果还有一些,您可以使用以下命令进行调试:

zappa status# andzappa tail

最常见的错误是与权限相关的(然后检查您的权限策略)或关于不兼容的 python 库。无论哪种方式,zappa 都会为调试提供足够好的错误消息。根据我的经验,最常见的错误是:

  1. IAM 用户的政策问题
  2. Zappa 和大小问题
  3. Boto3 和文件的权限/位置问题

如果您更新您的代码,不要忘记使用

zappa update dev

AWS API 网关—限制访问

要在市场上设置 API,我们需要首先用 API-key 限制它的使用,然后在市场*台上设置它。

分解一下:

  1. 转到 AWS 控制台并转到 API 网关
  2. 点击你的 API
  3. 我们希望创建一个 x-api-key 来限制对 api 的不希望的访问,并且也有一个计量使用
  4. 为 API 创建一个使用计划,包括所需的限制和配额限制
  5. 创建关联的 API 阶段
  6. 添加 API 密钥
  7. 在 API 键概述部分,单击 API 键处的“显示”并复制它
  8. 然后将 API 与键相关联,并丢弃所有没有键的请求
  9. 回到 API 概述。在“资源”下,单击“/任意”转到“方法请求”。然后在“设置”中,将“需要 API 密钥”设置为真
  10. 对“/{proxy+}方法执行相同的操作

现在,您已经限制了对 API 的访问。

4.设置 Rapidapi

  • 添加新 API
  • 使用 rapidapi 测试端点
  • 创建使用 API 的代码

在这篇文章中我不再赘述。再次查看我之前的https://towardsdatascience . com/develop-and-sell-a-python-API-from-start-to-end-tutorial-9a 038 e 433966设置好一切。我的新机器学习模型没有大的区别。

最终结果

上的 API 接口 https://rapidapi . com/Createdd/API/covid _ new _ cases _ prediction

https://rapidapi . com/Createdd/API/covid _ new _ cases _ prediction

灵感

这次我的主要动机来自于 Moez Ali,他提供了很多关于部署机器学习系统的文章。我也喜欢在社交媒体上关注他。我可以推荐他的文章:

还有弗朗索瓦·马索

常见问题

附加阅读

最终链接

开放源代码:

在 Rapidapi 上:

关于

丹尼尔是一名企业家、软件开发人员和商业法毕业生。他曾在各种 IT 公司、税务咨询、管理咨询和奥地利法院工作。

他的知识和兴趣目前围绕着编程机器学习应用程序及其所有相关方面。从本质上说,他认为自己是复杂环境的问题解决者,这在他的各种项目中都有所体现。

如果您有想法、项目或问题,请不要犹豫与我们联系。

你可以在 https://www.buymeacoffee.com/createdd 或者 https://etherdonation.com/d?支持我 to = 0xc 36 b 01231 a8f 857 b 8751431 c 8011 b 09130 ef 92 EC

连接到:

艺术相关:

开发和销售 Python API —从头到尾教程

原文:https://towardsdatascience.com/develop-and-sell-a-python-api-from-start-to-end-tutorial-9a038e433966?source=collection_archive---------0-----------------------

本文从头到尾描述了开发 Python API 的过程,并在更困难的领域提供了帮助。

图片:

最*看了一篇博文,是关于建立自己的 API 并出售的。

我很受启发,想测试一下是否有效。仅用了 5 天时间,我就能够从头到尾创建一个 API。所以我想我会分享我遇到的问题,详细阐述文章介绍的概念,并提供一个快速的清单来自己构建一些东西。所有这些都是通过开发另一个 API 实现的。

目录

关于这篇文章

这篇文章可以被认为是其他文章的教程和理解(列在我的“灵感”部分)。

它从头到尾描绘了一幅开发 Python API 的图画,并在更困难的领域提供了帮助,比如 AWS 和 Rapidapi 的设置。

我想这对其他想做同样事情的人会有帮助。我在路上遇到了一些问题,所以我想分享一下我的方法。这也是一个很好的方式来建立副业项目,甚至可能赚一些钱。

如目录所示,它由 4 个主要部分组成,即:

  1. 设置环境
  2. 使用 Python 创建问题解决方案
  3. 设置 AWS
  4. 设置 Rapidapi

你会在 Github 上找到我所有的开源代码:

您将在 Rapidapi 上找到最终结果:

如果你觉得这篇文章有帮助,请告诉我和/或购买 Rapidapi 上的功能以示支持。

放弃

我与本文中使用的任何服务都没有关联。

我不认为自己是专家。如果你觉得我错过了重要的步骤或者忽略了什么,可以考虑在评论区指出来或者联系我。此外,始终确保监控您的 AWS 成本,不要为您不知道的事情付费。

我总是乐于听取建设性的意见以及如何改进。

使用的堆栈

我们将使用

  • Github(代码托管),
  • 依赖和环境管理,
  • Jupyter 笔记本(代码开发和文档),
  • Python(编程语言),
  • AWS(部署),
  • Rapidapi(销售市场)

1.创建项目手续

它总是一样的,但却是必要的。我按照以下步骤来做:

  1. 创建本地文件夹mkdir NAME
  2. NAME在 Github 上创建一个新的存储库
  3. 创造康达环境conda create --name NAME python=3.7
  4. 激活康达环境conda activate PATH_TO_ENVIRONMENT
  5. 创建 git 回购git init
  6. 连接到 Github repo。添加自述文件,提交并
*git remote add origin URL_TO_GIT_REPO
git push -u origin master*

现在我们有:

  • 本地文件夹
  • github 知识库
  • anaconda 虚拟环境
  • git 版本控制

2.创建问题的解决方案

然后我们需要创造一个解决问题的方法。为了便于演示,我将展示如何将 excel csv 文件转换成其他格式。基本功能将首先在 Jupyter 笔记本上进行编码和测试。

安装软件包

安装 jupyter 笔记本和 jupytext:

*pip install notebook jupytext*

.git/hooks/pre-commit中设置一个钩子,用于正确跟踪 git 中的笔记本变化:

*touch .git/hooks/pre-commit
code  .git/hooks/pre-commit*

把这个复制到文件里

*#!/bin/sh
# For every ipynb file in the git index, add a Python representation
jupytext --from ipynb --to py:light --pre-commit*

之后让钩子可执行(在 mac 上)

*chmod +x .git/hooks/pre-commit*

找到解决问题的方法

*pip install pandas requests*

添加一个.gitignore文件并添加数据文件夹(data/)以不将数据上传到主机。

下载数据

下载一个示例数据集 (titanic dataset) 并保存到一个数据文件夹中:

*def download(url: str, dest_folder: str):
    if not os.path.exists(dest_folder):
        os.makedirs(dest_folder) filename = url.split('/')[-1].replace(" ", "_")
    file_path = os.path.join(dest_folder, filename) r = requests.get(url, stream=True)
    if r.ok:
        print("saving to", os.path.abspath(file_path))
        with open(file_path, 'wb') as f:
            for chunk in r.iter_content(chunk_size=1024 * 8):
                if chunk:
                    f.write(chunk)
                    f.flush()
                    os.fsync(f.fileno())
    else:
        print("Download failed: status code {}\n{}".format(r.status_code, r.text)) url_to_titanic_data = 'https://web.stanford.edu/class/archive/cs/cs109/cs109.1166/stuff/titanic.csv'download(url_to_titanic_data,'./data')*

创建功能

转换格式

*df = pd.read_csv('./data/titanic.csv')
df.to_json(r'./data/titanic.json')*

Jupyter 笔记本中的转换示例

用 REST 构建服务器来执行功能

在 jupyter notebook 中开发了功能后,我们希望在 python 应用程序中实际提供该功能。

有很多方法可以使用 jupyter 笔记本的某些部分,但是为了简单起见,我们现在重新创建它。

添加一个app.py文件。

例如,我们希望用户上传一个 excel 文件并返回转换成 JSON 的文件。

浏览互联网,我们可以看到已经有软件包可以处理 flask 和 excel 格式。所以让我们利用它们。

*pip install Flask*

启动 Flask 服务器时使用

*env FLASK_APP=app.py FLASK_ENV=development flask run*

Tipp:用 Postman 测试你的后端功能。它很容易设置,并允许我们快速测试后端功能。在“表单-数据”选项卡中上传 excel:

用邮递员测试后端

在这里您可以看到上传的 titanic csv 文件和数据集返回的列名。

现在我们只需编写将 excel 转换成 json 的函数,如下所示:

*import json
import pandas as pd
from flask import Flask, requestapp = Flask(__name__)@app.route('/get_json', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        provided_data = request.files.get('file')
        if provided_data is None:
            return 'Please enter valid excel format ', 400 data = provided_data
        df = pd.read_csv(data)
        transformed = df.to_json() result = {
            'result': transformed,
        } json.dumps(result) return result if __name__ == '__main__':
    app.run()*

(查看我的中的完整代码。)

例如,现在我们有了将 csv 文件转换成 json 的功能。

3.部署到 AWS

在本地开发之后,我们想把它放到云中。

设置 zappa

在我们本地创建应用程序后,我们需要开始在一个真实的服务器上设置主机。我们将使用 zappa

Zappa 使得在 AWS Lambda + API Gateway 上构建和部署无服务器、事件驱动的 Python 应用程序(包括但不限于 WSGI web apps)变得超级简单。可以把它想象成 Python 应用程序的“无服务器”网络托管。这意味着无限扩展、零停机、零维护,而成本只是您当前部署的一小部分!

*pip install zappa*

由于我们使用的是 conda 环境,我们需要指定它:

*which python*

会给你/Users/XXX/opt/anaconda3/envs/XXXX/bin/python(针对 Mac)

移除bin/python/并导出

*export VIRTUAL_ENV=/Users/XXXX/opt/anaconda3/envs/XXXXX/*

现在我们能做的

*zappa init*

来设置配置。

只要点击浏览所有内容,你就会有一个zappa_settings.json的样子

*{
    "dev": {
        "app_function": "app.app",
        "aws_region": "eu-central-1",
        "profile_name": "default",
        "project_name": "pandas-transform-format",
        "runtime": "python3.7",
        "s3_bucket": "zappa-pandas-transform-format"
    }
}*

请注意,我们还没有准备好部署。首先,我们需要获得一些 AWS 凭证。

设置 AWS

AWS 凭据

首先,你需要得到一个 AWS access key idaccess key

你可能认为这很简单:

要获得凭据,您需要

  • 转到:http://aws.amazon.com/
  • 注册并创建一个新账户(他们会给你一年试用期或类似的选择)
  • 转到您的 AWS 帐户概述
  • 账户菜单;子菜单:安全凭证

但是不,AWS 中的权限更多!

使用 IAM 中的用户和角色设置凭据

我发现 Peter Kazarinoff 的这篇文章非常有帮助。他非常详细地解释了下一部分。我下面的要点方法是一个快速总结,我经常引用他的步骤。如果你被困在某个地方,请查看他的文章了解更多细节。

我尽可能简单地分解它:

  1. 在 AWS 控制台中,在搜索框中键入 IAM。IAM 是 AWS 用户和权限仪表板。
  2. 创建一个组
  3. 为您的群组命名(例如 zappa_group)
  4. 为您的小组创建我们自己的特定内联策略
  5. 在“权限”选项卡的“内联策略”部分下,选择链接以创建新的内联策略
  6. 在设置权限屏幕中,单击自定义策略单选按钮,然后单击右侧的“选择”按钮。
  7. 创建一个用 json 格式编写的定制策略
  8. 通读并复制此处讨论的一项政策:【https://github.com/Miserlou/Zappa/issues/244
  9. 向下滚动到“我的自定义策略”查看我的策略的片段。
  10. 使用您的 AWS 帐号粘贴和修改 json 后,单击“验证策略”按钮以确保您复制了有效的 json。然后单击“应用策略”按钮,将内联策略附加到该组。
  11. 创建一个用户并将该用户添加到组中
  12. 回到 IAM 控制面板,使用“用户”左侧菜单选项和“添加用户”按钮创建一个新用户。
  13. 在“添加用户”屏幕中,为新用户命名,并选择编程访问的访问类型。然后点击“下一步:权限”按钮。
  14. 在“设置权限”屏幕中,选择您之前在“将用户添加到组”部分创建的组,然后单击“下一步:标记”。
  15. 标签是可选的。如果需要,添加标签,然后单击“下一步:查看”。
  16. 查看用户详细信息,然后单击“创建用户”
  17. 复制用户的密钥
  18. 先不要关闭 AWS IAM 窗口。在下一步中,您将把这些密钥复制并粘贴到一个文件中。此时,将这些密钥复制并保存到一个安全位置的文本文件中不失为一个好主意。确保不要在版本控制下保存密钥。

我的自定义策略:

*{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:AttachRolePolicy",
        "iam:GetRole",
        "iam:CreateRole",
        "iam:PassRole",
        "iam:PutRolePolicy"
      ],
      "Resource": [
        "arn:aws:iam::XXXXXXXXXXXXXXXX:role/*-ZappaLambdaExecutionRole"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "lambda:CreateFunction",
        "lambda:ListVersionsByFunction",
        "logs:DescribeLogStreams",
        "events:PutRule",
        "lambda:GetFunctionConfiguration",
        "cloudformation:DescribeStackResource",
        "apigateway:DELETE",
        "apigateway:UpdateRestApiPolicy",
        "events:ListRuleNamesByTarget",
        "apigateway:PATCH",
        "events:ListRules",
        "cloudformation:UpdateStack",
        "lambda:DeleteFunction",
        "events:RemoveTargets",
        "logs:FilterLogEvents",
        "apigateway:GET",
        "lambda:GetAlias",
        "events:ListTargetsByRule",
        "cloudformation:ListStackResources",
        "events:DescribeRule",
        "logs:DeleteLogGroup",
        "apigateway:PUT",
        "lambda:InvokeFunction",
        "lambda:GetFunction",
        "lambda:UpdateFunctionConfiguration",
        "cloudformation:DescribeStacks",
        "lambda:UpdateFunctionCode",
        "lambda:DeleteFunctionConcurrency",
        "events:DeleteRule",
        "events:PutTargets",
        "lambda:AddPermission",
        "cloudformation:CreateStack",
        "cloudformation:DeleteStack",
        "apigateway:POST",
        "lambda:RemovePermission",
        "lambda:GetPolicy"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucketMultipartUploads",
        "s3:CreateBucket",
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::zappa-*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:AbortMultipartUpload",
        "s3:DeleteObject",
        "s3:ListMultipartUploadParts"
      ],
      "Resource": "arn:aws:s3:::zappa-*/*"
    }
  ]
}*

注意:用您的 AWS 帐号替换内嵌政策中的 XXXXXXXXXXX。

您的 AWS 帐号可以通过点击“支持→”支持中心找到。您的帐号列在左上角的支持中心。上面的 json 是对我有用的。但是,我估计这组安全权限可能太开放了。为了增加安全性,你可以慢慢削减权限,看看 Zappa 是否还在部署。上面的设置是最后对我起作用的。如果你想了解更多关于运行 Zappa 所需的特定 AWS 权限,你可以在 GitHub 上深入讨论:https://github.com/Miserlou/Zappa/issues/244

在项目中添加凭据

使用以下命令在根目录下创建一个.aws/credentials文件夹

*mkdir ~/.aws
code ~/.aws/credentials*

并从 AWS 粘贴您的凭据

*[dev]
aws_access_key_id = YOUR_KEY
aws_secret_access_key = YOUR_KEY*

config相同

*code ~/.aws/config[default]
region = YOUR_REGION (eg. eu-central-1)*

注意,code是用我选择的编辑器 vscode 打开一个文件夹。

将分配给用户的 AWS 访问密钥 id 和秘密访问密钥保存在文件~/中。AWS/凭据。请注意。aws/ directory 需要在您的主目录中,并且凭据文件没有文件扩展名。

现在,您可以使用

*zappa deploy dev*

使用 zappa 部署应用程序

不应该再有任何错误了。但是,如果还有一些,您可以使用以下命令进行调试:

*zappa status
zappa tail*

最常见的错误是与权限相关的(然后检查您的权限策略)或关于不兼容的 python 库。无论哪种方式,zappa 都会为调试提供足够好的错误消息。

如果您更新您的代码,不要忘记使用

*zappa update dev*

AWS API 网关

要在市场上设置 API,我们需要首先用 API-key 限制它的使用,然后在市场*台上设置它。

我发现 Nagesh Bansal 的这篇文章很有帮助。他非常详细地解释了下一部分。我下面的要点方法是一个快速总结,我经常引用他的步骤。如果你被困在某个地方,请查看他的文章了解更多细节。

我再一次把它分解:

  1. 转到 AWS 控制台并转到 API 网关
  2. 点击你的 API
  3. 我们希望创建一个 x-api-key 来限制对 api 的不希望的访问,并且也有一个计量使用
  4. 为 API 创建一个使用计划,包括所需的限制和配额限制
  5. 创建关联的 API 阶段
  6. 添加 API 密钥
  7. 在 API 键概述部分,单击 API 键处的“显示”并复制它
  8. 然后将 API 与键相关联,并丢弃所有没有键的请求
  9. 回到 API 概述。在“资源”下,单击“/任意”转到“方法请求”。然后在“设置”中,将“需要 API 密钥”设置为真
  10. 对“/{proxy+}方法执行相同的操作

它看起来像这样

在 AWS API 网关中设置限制

现在,您已经限制了对 API 的访问。

4.设置 Rapidapi

在 Rapidapi 上创建 API

  1. 转到“我的 API”和“添加新 API”
  2. 添加名称、描述和类别。请注意,以后不能再更改 API 名称
  3. 在 settings 中,添加您的 AWS API 的 URL(它在您使用 zappa 部署时显示)
  4. 在“转换”下的“访问控制”部分,添加您在 AWS 中添加的 API 键

Rapidapi 中的访问控制

5.在安全选项卡中,您可以检查一切

6.然后转到“端点”,通过单击“创建 REST 端点”从 Python 应用程序添加路径

添加 REST 端点

7.为您的 API 添加图像

8.制定定价计划。Rapidapi 发表了一篇自己的关于定价选择和策略的文章。正如他们总结的那样,如何定价取决于你的偏好和产品。

9.我创建了一个免费增值定价计划。这样做的原因是,我想给免费测试它的机会,但增加了定期使用它的价格。此外,我想创建一个计划来支持我的工作。例如:

制定价格计划

10.创建一些文档和教程。这很容易解释。我们鼓励这样做,因为如果你的 API 被恰当地记录下来,人们会更容易使用它。

11.最后一步是公开您的 API。但在此之前,亲自测试一下是很有用的。

测试您自己的 API

创建私人测试计划

设置好一切之后,您当然应该使用提供的代码片段进行测试。这一步并不简单,我必须联系支持人员来理解它。现在我在这里简化一下。

为自己制定一个私人计划,不要设定任何限制。

转到 API 的“用户”部分,然后转到“免费计划用户”,选择您自己并“邀请”您加入私人计划。

将您自己加入您的私人计划

现在,您已经订阅了自己的私人计划,可以使用提供的代码片段测试功能。

使用 Rapidapi 测试端点

上传一个示例 excel 文件,然后单击“测试端点”。然后你会得到一个 200 ok 的回复。

在 Rapidapi 中测试端点

创建使用 API 的代码

现在要使用 API,您可以简单地复制 Rapidapi 提供的代码片段。例如 Python 和请求库:

*import requestsurl = "https://excel-to-other-formats.p.rapidapi.com/upload"payload = ""
headers = {
    'x-rapidapi-host': "excel-to-other-formats.p.rapidapi.com",
    'x-rapidapi-key': "YOUR_KEY",
    'content-type': "multipart/form-data"
    }response = requests.request("POST", url, data=payload, headers=headers)print(response.text)*

最终结果

https://rapidapi.com/Createdd/api/excel-to-other-formats

灵感

文章“作为产品的原料药。如何在你只知道一个后端的情况下销售你的作品?

制作一个解决问题的 API

使用无服务器架构进行部署

通过 API 市场分发

对于设置一切,我发现 Nagesh Bansal 的文章非常有帮助:

彼得·卡扎林诺夫的这篇文章:https://python forundergradengineers . com/deploy-server less-we B- app-AWS-lambda-zappa . html

我鼓励你也看看那些文章。

你也可以直接在 Github 上阅读我的文章(为了更好的代码格式)

关于

丹尼尔是一名企业家、软件开发人员和律师。他曾在各种 IT 公司、税务咨询、管理咨询和奥地利法院工作。

他的知识和兴趣目前围绕着编程机器学习应用程序及其所有相关方面。从本质上说,他认为自己是复杂环境的问题解决者,这在他的各种项目中都有所体现。

如果您有想法、项目或问题,请不要犹豫与我们联系。

*

你可以在 https://www.buymeacoffee.com/createdd 支持我* * [## 主页

关于我丹尼尔是一名企业家,软件开发人员和律师。他曾在各种 IT 公司,税务咨询…

www.createdd.com](https://www.createdd.com/)

连接到:

用 Python 在 10 分钟内开发数据库驱动的 REST API

原文:https://towardsdatascience.com/develop-database-driven-rest-api-with-python-in-10-minutes-9b8cbb7ce5b2?source=collection_archive---------5-----------------------

用 Python 做一个完整的 CRUD REST API。我提到过它是数据库驱动的吗?

REST APIs 在我们身边无处不在,被用来构建高质量的软件。在数据科学中,它们用于将机器学习模型部署到生产中,所以不,从长远来看,你无法避免它们。今天我们将使用 Python 和Flask-RESTful创建一个简单但功能齐全的数据库驱动 API。

照片由 Cookie 在 Unsplash 上的 Pom 拍摄

以下是所用技术的简要概述:

  • Python 是一种神奇的编程语言,广泛用于各种类型的任务
  • Flask-RESTfulFlask库的扩展。使我们能够快速开发 API
  • SQLAlchemy —一种 ORM(对象关系映射器)。帮助我们在不编写 SQL 的情况下与数据库通信

差不多就是这样。这篇文章应该很容易理解,完成它不应该花费你超过 10-15 分钟的时间(如果按照代码进行的话)。

这篇文章的结构如下:

你可以在这里下载源代码。让我们开始吧。

问题描述

我们想创建一个存储用户数据的数据库(想想网站上的注册表单)。我们可以访问用户名、密码、真实姓名和年龄等信息。

接下来,我们想开发一个 REST API 来简化数据库处理。此外,API 使我们的逻辑可用于任何编程语言、终端和工具,如。

我们希望以尽可能简单的方式从数据库中读取、插入、更新和删除记录。让我们就这样做吧,从下一节开始。

设置和模型声明

首先,在某个地方创建一个新目录,并在其中创建一个 Python 文件。我把我的命名为app.py,因为这是一个惯例,但这不是一个要求——所以你可以随意命名你的。

让我们继续进口,好吗?我们需要几个库:FlaskFlask-RESTfulFlask-SQLAlchemyFlask-Marshmallow。以下是进口货:

from flask import Flask, request, jsonify 
from flask_sqlalchemy import SQLAlchemy 
from flask_marshmallow import Marshmallow 
from flask_restful import Resource, Api

当这个问题解决后,我们可以继续初始化。我们必须创建一个Flask应用程序和 API 的实例,并指定数据库的位置。我们正在使用,因此请确保您首先熟悉它:

[## Python 有一个内置的数据库——下面是如何使用它

如何利用内置数据库进行数据存储和操作

towardsdatascience.com](/python-has-a-built-in-database-heres-how-to-use-it-47826c10648a)

我们还必须制作一个SQLAlchemyMarshmallow的实例。后者用于使处理 JSON 响应变得轻而易举。代码如下:

app = Flask(__name__) 
api = Api(app) 
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db' 
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 
db = SQLAlchemy(app) 
ma = Marshmallow(app)

厉害!现在让我们进入正题,为我们的用户声明一个模型。SQLAlchemy需要它来动态构建和执行 SQL,所以我们不必担心这个问题。如简介部分所述,我们将处理姓名、年龄、用户名和密码等数据。

我们需要指定数据类型和它们的大小,所以SQLAlchemy可以创建表。这一切都发生在继承自SQLAlchemy.Modelclass内。最后,我们将把参数传递给类的构造函数。代码如下:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(32), unique=True)
    password = db.Column(db.String(32))
    first_name = db.Column(db.String(32))
    last_name = db.Column(db.String(32))
    age = db.Column(db.Integer)

    def __init__(self, username, password, first_name, last_name, age):
        self.username = username
        self.password = password
        self.first_name = first_name
        self.last_name = last_name
        self.age = age

上面的代码片段应该易于阅读和理解,因为没有什么复杂的东西。现在我们可以为我们的用户声明一个模式。这只是继承自Marshmallow.Schema的另一个类,用于避免令人头疼的 JSON 解析。代码如下:

class UserSchema(ma.Schema):
    class Meta:
        fields = ('id', 'username', 'password', 'first_name', 'last_name', 'age')

此时,我们已经准备好初始化数据库并创建users表。为此,在根文件夹中打开一个新窗口,执行如下所示的所有操作:

厉害!我们需要做的最后一件事是使用声明的UserSchema。我们将声明两个变量——一个用于获取单个用户,另一个用于获取多个用户:

user_schema = UserSchema() 
users_schema = UserSchema(many=True)

我们现在可以继续实际的 API 开发了。

API 开发

现在,我们将处理五件不同的事情:

所有这些逻辑都写在一个名为UserManager的类中。你可以随意命名你的名字,但这个似乎更合适。在谈到我们需要编写的样板代码的数量时,Flask-RESTful非常友好。它是最小的。首先,我们需要声明一个继承自Flask-RESTful.Resource的类。这是一个起始代码:

class UserManager(Resource): 
    pass

我们将从实现获取一个/所有用户的逻辑开始。后面的每个代码块都在UserManager类中。

获取用户

UserManager类中,我们将声明一个名为get的静态方法。这一次命名非常重要,因为方法的名称代表了我们打算发出的 HTTP 请求的类型。请求是获取数据最合适的方式,所以我们将使用它。

逻辑是这样的:

  • 检查用户是否在 URL 后面附加了ID参数——如果是,我们需要单个用户的数据。如果没有,我们需要所有用户的数据
  • 通过SQLAlchemy进行相应的查询
  • 使用flask.jsonify函数返回 JSON 格式的数据

这是代码:

@staticmethod
def get():
    try: id = request.args['id']
    except Exception as _: id = None

    if not id:
        users = User.query.all()
        return jsonify(users_schema.dump(users))
    user = User.query.get(id)
    return jsonify(user_schema.dump(user))

让我们继续插入新用户。

插入用户

这次我们将使用 HTTP 请求。这意味着用户应该以 JSON 格式为新用户传递数据——在测试部分会有更多的介绍。此外,我们的新静态方法必须命名为post

这是我们必须实现的逻辑:

  • 获取提供的用户名、密码、名字、姓氏和年龄的 JSON 数据
  • 用提供的数据创建一个User类的实例
  • 将该用户添加到数据库中,并提交事务
  • 返回一条消息,表明用户已被插入

这是一个相对简单的函数。代码如下:

@staticmethod
def post():
    username = request.json['username']
    password = request.json['password']
    first_name = request.json['first_name']
    last_name = request.json['last_name']
    age = request.json['age']

    user = User(username, password, first_name, last_name, age)
    db.session.add(user)
    db.session.commit()

    return jsonify({
        'Message': f'User {first_name} {last_name} inserted.'
    })

让我们继续更新现有用户。

更新用户

要更新现有用户,我们将使用 HTTP 请求。然后,静态方法被命名为put,您已经猜到了。这是逻辑的概述:

  • 检查呼叫中是否传递了用户ID。否则,将返回一条错误消息。这是因为我们一次只更新一个用户
  • 获取提供的用户名、密码、名字、姓氏和年龄的 JSON 数据
  • 根据提供的数据为数据库用户设置值,并提交事务
  • 返回一条消息,表明用户已被更新

这种方法比前一种稍微复杂一点,但是仍然相当容易实现:

@staticmethod
def put():
    try: id = request.args['id']
    except Exception as _: id = None

    if not id:
        return jsonify({ 'Message': 'Must provide the user ID' })

    user = User.query.get(id)
    username = request.json['username']
    password = request.json['password']
    first_name = request.json['first_name']
    last_name = request.json['last_name']
    age = request.json['age']

    user.username = username
    user.password = password
    user.first_name = first_name
    user.last_name = last_name
    user.age = age

    db.session.commit()
    return jsonify({
        'Message': f'User {first_name} {last_name} altered.'
    })

删除用户

这是我们要实现的最终方法。它的任务是从数据库中删除单个用户。我相信您现在已经猜到我们将发出什么类型的 HTTP 请求,以及必须如何调用该方法。逻辑是这样的:

  • 检查呼叫中是否传递了用户ID。否则,将返回一条错误消息。这是因为我们一次只删除一个用户
  • 从数据库中删除用户并提交事务
  • 返回一条消息,表明用户已被更新

代码如下:

@staticmethod
def delete():
    try: id = request.args['id']
    except Exception as _: id = None

    if not id:
        returnjsonify({ 'Message': 'Must provide the user ID' })

    user = User.query.get(id)
    db.session.delete(user)
    db.session.commit()

    return jsonify({
        'Message': f'User {str(id)} deleted.'
    })

整个UserManager班就这样。接下来让我们完成文件,开始测试。

收尾

为了完成app.py文件,我们需要将UserManager类附加到某个实际的端点上。我已经决定把我的名字命名为/api/users,但是命名的决定取决于你。

此外,从终端执行文件后,我们需要运行Flask应用程序。以下是两者的代码:

api.add_resource(UserManager, '/api/users')

if __name__ == '__main__':
    app.run(debug=True)

就这样——我们可以开始测试了。

测试

要启动我们的应用程序,请在根文件夹中打开一个新的终端窗口,并运行以下命令:

厉害!API 现在在http://127.0.0.1:5000/api/users运行,我们可以开始测试了。为了使这个过程简单明了,我决定使用这个应用程序。您不必这样做,因为您可以直接从 Python 甚至从终端做任何事情。我们将从插入开始,因为这对空数据库最有意义。

如果您正在跟随,请打开 Postman 并按照下面的说明进行操作。

创建新用户

获取所有用户

获取单个用户

更新用户

删除用户

差不多就是这样了!一切都像宣传的那样工作,所以让我们在下一部分总结一下。

结论

这是一篇很长的文章,值得一读——我承认这一点。不过,我希望你已经设法跟上了,如果没有,请参考源代码

了解如何使用 API 以及如何设计它们是任何数据科学家的基本技能,Python 提供了一种令人惊讶的简单入门方式。现在由你来决定向你认为合适的方向发展。请在下面的评论区留下你的想法。

感谢阅读。

加入我的私人邮件列表,获取更多有用的见解。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

[## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)

原载于 2020 年 10 月 6 日 https://betterdatascience.com**

使用 Docker 容器在本地开发胶水工作

原文:https://towardsdatascience.com/develop-glue-jobs-locally-using-docker-containers-bffc9d95bd1?source=collection_archive---------16-----------------------

Docker 容器在本地测试 glue spark ETL 脚本,而不会产生任何额外的成本,也不会使用开发端点

图片由 Free 提供-照片来自 Pixabay

随着当前世界数据量的不断增加,对处理大数据的服务的需求非常高。当我们考虑大数据时,大多数数据工程师使用的框架非常少。阿帕奇 Spark 就是其中之一。

Apache Spark 是一个分布式处理引擎,它需要一个大型集群来执行任何类型的分析或简单地对数据集执行 ETL。要使用 Apache Spark,我们需要建立自己的大型集群,这非常昂贵,或者我们可以在云上利用它们。在这里,我们将讨论 AWS 提供的服务。因此,为了处理大型数据集并使用 spark 对其进行分析,AWS 提供了两个主要服务

  1. AWS EMR(弹性地图缩减)
  2. AWS 胶水

AWS EMR 为我们提供集群来执行我们的处理,并且非常昂贵,因此我们需要仔细确定我们需要集群多长时间,以及如何适当地优化我们的作业。我们不会在这篇文章中讨论 EMR,因为它本身就是一个非常大的讨论话题。

AWS Glue 是一个完全托管的 ETL 服务,由 amazon web services 提供,用于处理大量数据。AWS Glue 最好的部分是它在 AWS 无服务器保护伞下,我们不需要担心管理所有这些集群和与之相关的成本。在无服务器模式中,我们为我们使用的东西付费,因此,如果我们的工作只使用 25 个 DPU 来处理我们的数据,并且运行 20 分钟,那么我们最终只需支付利用 25 个 DPU 20 分钟的成本,而不会多花一分钱。

如今,AWS Glue 是创建基于 python 或 scala 的 spark 处理作业的最大需求。要在 AWS glue 上开发 jobs,我们有三个选项。让我们逐一讨论。

  1. 直接在 glue 编辑器中创建作业并运行作业:

如果您是 spark 开发人员,并且不太熟悉 glue libraries 及其图生成,那么无论如何都要避免使用这个编辑器。这是写给那些非常确定他们正在写什么,并且从心里知道他们的工作将在第一轮中运行的人。这是完全不推荐的,只有当我们需要对现有的工作做一些改变时才可以考虑。当您在代码中使用胶水库时,直接使用作业编辑器是很好的,因为它会在您编写代码时生成谱系图。在选择这个选项之前,我建议浏览一下胶水库这里

2。创建一个胶开发端点:

您可以设置一个 glue dev 端点,并将其链接到 zeppelin 笔记本或您的 pycharm IDE,或者您甚至可以连接本地 jupyter 笔记本。如果您想在开发工作时测试它们,这是一个更好的选择。要设置 Glue Dev 端点,您可以遵循官方 AWS 文档这里。这个 glue dev 端点的唯一问题是它的成本。您将为它运行的时间付费,所以它基本上是用您想要的容量和安装在集群上的胶水库来启动 EMR 集群。如果开发成本不是问题,并且可以考虑的话,这是最好的选择之一。

3。使用 AWS 胶水库并在本地 Docker 容器上运行它们

考虑到作业的开发和在相对较小的数据集上测试作业,并且一旦作业准备好使用 glue job console 本身运行它们,这是迄今为止最好的选择。通过这个选项,您可以在您的机器上灵活地使用 glue libraries,或者您可以根据您的数据集大小启动 EC2 实例,并在这些 EC2 上启动 docker 容器,因为这将是一个相对便宜的选项,也是最适合运行您的作业的选项。

要在本地设置 AWS glue,你可以点击这里查看 AWS 文档。但这似乎并不奏效,我们将详细讨论它。因此,我创建了一个 Docker 图像,并将解释我们正在做什么。

DockerFile 文件

我将 centos 作为基础映像,然后设置这些 env 变量,稍后我们将需要它来下载库

ENV MAVEN=https://aws-glue-etl-artifacts.s3.amazonaws.com/glue-common/apache-maven-3.6.0-bin.tar.gz
ENV SPARK=https://aws-glue-etl-artifacts.s3.amazonaws.com/glue-1.0/spark-2.4.3-bin-hadoop2.8.tgz
ENV GLUE=https://github.com/awslabs/aws-glue-libs.git

然后,我们将创建一个目录 glue 并安装所需的库,如 Java、python、wget、tar 和 Python 包,并将我们的工作目录设置为 glue

RUN mkdir glue
RUN yum install -y python3 java-1.8.0-openjdk java-1.8.0-openjdk-devel tar git wget zip
RUN ln -s /usr/bin/python3 /usr/bin/python
RUN ln -s /usr/bin/pip3 /usr/bin/pip
RUN pip install pandas
RUN pip install boto3
RUN pip install pynt
WORKDIR ./glue

现在在这个目录下会下载 maven,spark 和 glue libs 并解压。然后我们将更新 path 变量,并向它添加 SPARK_HOME、JAVA_HOME、MAVEN_HOME 和 GLUE_HOME 变量。

#To get the latest aws libraries
RUN git clone -b glue-1.0 $GLUE#To get latest spark version
RUN wget $SPARK#To install Maven for dependencies
RUN wget $MAVENRUN tar zxfv apache-maven-3.6.0-bin.tar.gz
RUN tar zxfv spark-2.4.3-bin-hadoop2.8.tgz#Removing zip files inorder to reduce the final docker image size
RUN rm spark-2.4.3-bin-hadoop2.8.tgz
RUN rm apache-maven-3.6.0-bin.tar.gz#Setting up env variables
RUN mv $(rpm -q -l java-1.8.0-openjdk-devel | grep "/bin$" | rev | cut -d"/" -f2- |rev) /usr/lib/jvm/jdk
ENV SPARK_HOME /glue/spark-2.4.3-bin-spark-2.4.3-bin-hadoop2.8
ENV MAVEN_HOME /glue/apache-maven-3.6.0
ENV JAVA_HOME /usr/lib/jvm/jdk
ENV GLUE_HOME /glue/aws-glue-libs
ENV PATH $PATH:$MAVEN_HOME/bin:$SPARK_HOME/bin:$JAVA_HOME/bin:$GLUE_HOME/bin

这里有一个重要的已知问题,将删除一些库

RUN sed -i '/mvn -f/a rm /glue/aws-glue-libs/jarsv1/netty-*' /glue/aws-glue-libs/bin/glue-setup.shRUN sed -i '/mvn -f/a rm /glue/aws-glue-libs/jarsv1/javax.servlet-3.*' /glue/aws-glue-libs/bin/glue-setup.sh

现在我们将使用 maven 编译所有的依赖项。这个 shell 脚本运行 maven build 命令并获得所有需要的依赖项。

我们只运行一次,这样我们的 docker 映像就可以预先包含这些库,从而节省以后运行 spark 作业的时间。

RUN sh /glue/aws-glue-libs/bin/glue-setup.sh

最后,我们将清理所有的 tmp 目录,并使用 bash 作为容器的入口点。

RUN yum clean all
RUN rm -rf /var/cache/yum
CMD ["bash"]

现在使用 docker 文件并创建您的容器,以便开始开发 glue spark 作业。

从 Dockerfile 构建 docker 映像

要从该 Dockerfile 文件构建映像,请运行以下命令:

docker build -t jnshubham/glue_etl_local .

从 DockerHub 中提取现有图像

要使用现有的映像来启动您的容器,只需从 docker hub 中提取映像,并运行所提供的命令来提交作业

要提取图像,请运行以下命令:

docker pull jnshubham/glue_etl_local:latest

通过运行以下命令检查下载的图像

docker images

运行 Docker 容器

要运行容器并进入 repl shell:

docker run jnshubham/glue_etl_local "gluepyspark"

进入终端并提交 spark 作业运行

docker run -it jnshubham/glue_etl_localgluesparksubmit script.py --JOB_NAME script

这样,您将能够在本地机器上测试您的作业,或者您也可以根据您的数据大小在任何 EC2 实例上使用它。

更多信息,请访问我的 GitHubdockerhub

使用谷歌云人工智能*台开发、训练和部署 TensorFlow 模型

原文:https://towardsdatascience.com/develop-train-and-deploy-tensorflow-models-using-google-cloud-ai-platform-32b47095878b?source=collection_archive---------23-----------------------

实用指南

张量流模型训练和部署的实用流程

TensorFlow 生态系统在开发涉及深度学习的应用程序方面已经变得非常受欢迎。原因之一是它有一个强大的社区,围绕核心库开发了许多工具来支持开发人员。在本教程中,我将指导您如何在 google colab 中制作模型原型,在 Google Cloud AI *台上对其进行训练,并将最终完成的模型部署在 Google Cloud AI *台上进行生产。我将包括工作的谷歌 colab 笔记本电脑,以重建工作。

Google colab 是 TensorFlow 中用于模型原型制作的免费资源,并附带各种运行时。准备一台带有 GPU 或 TPU 的机器一开始可能会很昂贵,但是用户可以从带有 google colab 的免费 GPU 开始。请记住,colab 资源有限,可能不适合正确训练需要大量计算资源的模型。尽管如此,colab 是构建模型原型和进行一些初步实验的完美工具。

可视化工作流程的框图

谷歌云*台上的培训模型

一旦您对模型管道感到满意,就该用适当数量的历元和完整数据集来训练模型了。正如你可能知道的那样,训练深度学习模型需要很长时间和一大群 CPU 的 GPU 或 TPU。一种选择是用户建立他们自己的计算集群,这在大多数情况下既昂贵又耗时。另一种选择是使用云计算来训练模型,然后按需付费。TensorFlow 团队发布了一个名为 Tensorflow Cloud 的包,让用户在谷歌云*台上训练模型,没有任何麻烦。我遵循了的步骤,使用 TensorFlow Cloud 博客在 Google Cloud 上训练你的 TensorFlow 模型,并将分享我为使它工作所面临的一些问题。向 GCP *台提交培训工作的项目指南中定义了一些先决条件。

创建 GCP 项目后,按照下面的步骤为环境配置 Google cloud 身份验证。

# Authenticate 
from google.colab import auth
auth.authenticate_user()

在环境中设置PROJECT_ID

os.environ['PROJECT_ID']='gcpessentials-rz'!gcloud config set project $PROJECT_ID

创建服务帐户并设置tensorflow-cloud包所需的一些权限。下载服务帐户密钥并作为环境变量添加为GOOGLE _ APPLICATION _ CREDENTIALS。向谷歌云*台提交工作需要这些凭证。

os.environ['PROJECT_ID']='gcpessentials-rz'!gcloud config set project $PROJECT_IDos.environ['SA_NAME']='gcpessentials-rz'!gcloud iam service-accounts create $SA_NAME!gcloud projects add-iam-policy-binding $PROJECT_ID \--member serviceAccount:$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com \--role 'roles/editor'!gcloud iam service-accounts keys create key.json --iam-account $SA_NAME@$PROJECT_ID.iam.gserviceaccount.comos.environ['GOOGLE_APPLICATION_CREDENTIALS']='key.json'

即使完成了上述步骤,我还必须在云构建设置下启用service Accountscloud_build状态。下面是我的项目设置的快照。

下一步是创建 GCP_BUCKET 来存储向 Google Cloud 提交作业所需的数据。

BUCKET = 'tf2-model-training'
!gsutil mb gs://$BUCKET

一旦我们在 google colab 中建立了环境并创建了 GCP_BUCKET,我们就必须准备笔记本来训练模型。以下是准备笔记本时需要考虑的一些要点。

  1. 使用 google colab 在笔记本上测试少量的纪元代码
  2. 确保笔记本中没有错误,并删除任何不必要的代码
  3. 准备requirements.txt并上传到 google colab 环境。
  4. 将训练好的模型保存在 GCP_BUCKET 中(将用于部署)

一旦我们准备好笔记本,我们就使用tensorflow-cloud包在谷歌云*台上提交培训。

import tensorflow_cloud as tfcBUCKET = 'tf2-model-training'labels= {'phase': 'test','owner': 'raza',}tfc.run(requirements_txt="requirements.txt",distribution_strategy="auto",chief_config='auto',docker_image_bucket_name=BUCKET,job_labels=labels,)

上面的代码会把笔记本转换成identifier-Fg45-a.py,以 docker 的形式提交 Google 云*台上的训练。提交作业后,您可以看到如下图所示的消息。

向 GCP 提交培训工作的状态

等待几分钟后,工作开始实际培训

通过点击提供的链接,您将看到如下图所示的页面

使用人工智能*台查看训练进度的链接

您可以点击view logs查看日志,如下图所示。日志有助于了解代码中发生了何种异常。

培训日志

在提交庞大的作业之前,测试几个时期的管道提交脚本,然后提交完整的作业

如果一切顺利,你的模型将使用谷歌人工智能*台进行训练,并与其他资源一起保存在 GCP _ 水桶中。

用于培训的 Google Colab 笔记本

下面是使用 TensorFlow-Cloud 包在 Google AI *台上运行培训的工作笔记本。

在谷歌云*台上部署训练好的模型

一旦模型被训练和最终确定,用户希望在可扩展的基础设施上部署该模型。Google Cloud 还提供了必要的基础设施,无需大量修改就可以在其*台上部署 TensorFlow 模型。我将向您展示如何在 google 云*台上部署该模型。在培训结束时,我们将最终确定的模型保存在 Google Cloud Bucket 中。下面是部署模型的步骤。

  • 使用人工智能*台配置模型服务
  • 对部署的模型执行预测

使用下面的命令集来配置模型,以便在 Google colab 中进行部署。我已经在模型中用 TensorFlow 详细解释了如何在 Google Cloud 上部署模型,并在 Google Cloud *台上服务。

按照上面教程中的相同步骤,我已经将模型配置为v2

获取已部署模型的预测

一旦部署了模型,并且您可以看到绿色的勾号,就该测试模型的预测了。一些需要考虑的要点。

  • 使用测试&测试型号预测使用您的版本或型号选项卡下的选项卡。
  • 输入 JSON 数据取决于您如何定义您的模型
# [Reference](https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/ml_engine/online_prediction/predict.py)

import googleapiclient.discovery

def predict_json(project, model, instances, version=None):

    service = googleapiclient.discovery.build('ml', 'v1')
    name = 'projects/{}/models/{}'.format(project, model)

    if version is not None:
        name += '/versions/{}'.format(version)

    response = service.projects().predict(
        name=name,
        body={'instances': instances}
    ).execute()

    if 'error' in response:
        raise RuntimeError(response['error'])

    return response['predictions']

为预测加载看不见的数据

df_new_products = pd.read_csv(data_path + 'proposed_new_product.csv')
tdata_instances = {'dense_input':df_new_products.values[0].tolist()}
predictions_gcloud = predict_json(CLOUD_PROJECT, 'earnings_prediction', tdata_instances, version='v2')
predictions_gcloud = predictions_gcloud[0]['dense_3'][0] + 0.1159
predictions_gcloud = predictions_gcloud/0.0000036968

print('Earnings predictions for Proposed product - ${}'.format(predictions_gcloud))Earnings predictions for Proposed product - $259671.15201209177

用于预测的 Google Colab 笔记本

下面是对部署的模型执行预测的工作笔记本

结论

在本指南中,我们已经了解了在tensorflow-cloud包的帮助下,使用 Google Cloud AI *台使用 TensorFlow 2.3.0 训练深度学习模型,并将训练好的模型部署在 Google Cloud AI *台上。以下是一些重要的经验教训

  • 使用 Google Colab 构建张量流模型
  • 使用 TensorFlow-Cloud 在 Google Cloud AI *台上训练模型
  • 训练后将训练好的模型保存在 GCP 桶中
  • 在 GCP 建立服务模型
  • 使用云中部署的模型进行预测

参考资料/阅读/链接

  1. https://blog . tensor flow . org/2020/04/how-to-deploy-tensor flow-2-models-on-cloud-ai-platform . html
  2. https://blog . tensor flow . org/2020/08/train-your-tensor flow-model-on-Google . html
  3. https://scikit-learn.org/stable/modules/preprocessing.html

将您的数据作为产品开发

原文:https://towardsdatascience.com/develop-your-data-as-a-product-f9ba268c4e20?source=collection_archive---------8-----------------------

理解大数据

起草数据工程实务

TL:吻博士💕DevOps!

图片来自 slon.pics

在一次工作讨论的启发下,我试图写下我个人对数据工程最佳实践的看法。要做到这一点,我认为最好先通过回答以下问题来定义数据工程的目标:

我们这些数据工程师试图推动的成果 是什么?

然后,在我们清楚结果之后,让我们详细说明哪些原则和实践可以帮助我们实现这一点。

免责声明:我有在我称之为大企业的工作经验(> 50,000 名员工),与科学家密切合作或直接在产品/分析团队工作。如果你在一个小公司工作,像一个人的军队,或者在一个新成立的公司,有些事情可能是不相关的——尽管我认为前提和原则仍然适用。

前提:数据是一种产品

闲置和休眠的数据本身是没有价值的,正是这些数据产生的结果为你(和公司)创造了价值。这意味着数据是一种产品。没有真正使用/购买它的客户,它就不会产生任何东西。
如果我们遵循这个简单的前提,我们可以很快得出一些简单的指标,告诉我们我们的数据产品有多成功:

  • 产生价值的产品的使用
  • 上市速度和变化速度
  • 质量和可靠性
  • 可用性和互操作性

打造好的产品=保持简单

以我的经验来看,产品思维真的有助于我的工作更有影响力。每次我们开发某样东西时,解决方案的价值、可行性、合意性和可行性的产品维度应该是我们所考虑的。

大部分时间我们将花在如何构建和操作解决方案上,这将决定它们的可行性。因此,了解业务问题,然后设计可持续的解决方案至关重要。在这里,我看到了产品思维模式和 KISS 之间的紧密联系(简单点,笨蛋)。后者是构建可持续(长期可行的)产品的关键。

一个(过于)简单的例子:假设我们是星巴克,每天都需要决定我们要向每一家店发送多少纸杯。现在,如果有一个实时纸杯数据流来监控库存并对变化做出反应,岂不是很酷?—绝对不是。如果我们只需要每天做一次决定,我们可以通过每天运行的简单 cronjob 来完成。

保持简单只做您的解决方案需要的事情;仅仅因为我们可以做一些更奇特的事情并不意味着我们应该这样做。

开发产品的实践

剧透:数据工程师和软件工程师的最佳实践实际上是一样的。特别是 DevOps 实践改进了我们的构建方式,虽然也有数据操作,但后者只是一个将 DevOps 原则与数据领域联系起来的术语。

这并不意味着数据工程和软件工程是一样的,但事实是软件工程师在快速构建产生价值的数字产品方面已经领先,我们应该从中学习。

让我们更详细地分析一下,并将其与上面的指标联系起来。

用法和产生的价值。这才是最重要的,我们希望推出有影响力的产品。我们从软件开发中知道,这可以通过了解我们的消费者并与他们密切合作来有效地完成,最好是在同一个团队中。了解需求,理解痛点,并迭代地解决它们。实际上,这意味着我们必须试验和改进我们的产品。从技术上来说,这意味着我们需要能够跟踪这一点,并不断能够开发新的功能(或回滚更改)。

上市速度。自动化流程和工具,我们需要能够在生产级别快速交付和开发数据产品。有效地做到这一点的唯一方法,尤其是在分析环境中,是拥有解耦的数据资产。如果每次我们必须首先更新大量的管道,以向我们可信赖的星型模式添加新的维度(从而打破一些未记录的下游依赖),我们就没有机会获得任何可持续的速度。

质量和可靠性。在开发和运营方面,我们首先需要的是健康的持续改进心态。我们永远不会从一开始就制造出完美的产品。从技术上讲,这意味着我们应该始终有一个良好的 CI/CD 设置(DevOps)。从精神上来说,这意味着我们必须接受一种死后文化。换句话说,我们尽最大努力利用自动测试/自修复 pods 数据质量检查来发现问题。当事情不可避免地出错时,我们确保从中吸取教训并改进产品!

可用性和互操作性。可用性不仅仅是数据产品的存在,而是其消费的难易程度。不是为我们,而是为我们的消费者。我们的产品必须被用来最大限度地创造价值,所以我们需要让它容易获得。我们需要使用标准界面来促进不同团队使用我们的产品,也就是说,我们不会为我们的消费者做出技术选择,也不会让他们跳过技术关卡。为了保持敏捷和快速,我们需要将我们内部开发的关注点从我们与消费者共享的界面中分离出来。

以上几点都是从软件工程师在构建数字产品时学到的经验教训中得来的。在我看来,它们都同样适用于数据工程——尽管它们的实现可能在技术上有所不同。

还有一点:永恒性。这在软件工程最佳实践中可能不那么重要/普遍,更多来自函数式编程人员,但它对数据工程非常有影响。尤其是在分析领域。尝试实践功能数据工程,这意味着:我们不改变历史,相反,我们快照所有的数据。不这样做是一条通往疯狂的道路——这是一件值得写一整篇文章的事情。现在,我将留给你们一个指针,指向 Maxime Beauchemin 的一些工作,他有一些关于❤️.功能数据工程的很棒的材料

数据工程实践

如果你做到了,那太好了!让我们试着将事情进一步归结为一些我们作为数据工程师可以在日常生活中应用的简单而切实的实践。

版本控制— 我们所有的工作都需要进行版本控制,包括我们的代码、数据和数据文档。进化,实验,必要时回滚!

自动化测试和部署 —自动化测试提供高质量和可持续的质量。自动化部署提高了我们的效率,减少了错误。我们需要这个(查看 Python for DevOps 开始)!

使数据可用并保持可用 —尽可能以最简单的方式使您的数据可用。并确保它保持可用—使用监控和警报来主动修复问题。

测试并交流数据质量 —持续评估您产品的数据质量并进行交流,最好是通过自动化数据文档。使用监控和警报来主动解决问题。

分离关注点— 确保你没有将事情紧密地耦合在一起。不要马上把所有东西都放在一个星型架构中,尽可能保持数据产品的分离。

与同事分享最佳实践— 与我们的数据工程同事交流,了解最佳实施方案,并分享它们。最终我们把最好的想法放到一个框架里,抽象出实现细节——>利润!

构建不可变的数据集— 数据是历史,历史是不可变的。更新观察值(行)会导致分析数据历史时出现问题。这对于调试和机器学习用例有着巨大的影响。我们努力使它变得简单,并通过保存历史来支持我们数据产品的下游使用- >数据是不可变的。

这些是我的最佳实践,这些实践(依我拙见)给我们带来了最大的经济效益,并且与前面描述的指标密切相关。这并不意味着没有更多东西可以学习!

关于在大公司中定位的说明

如果我们遵循数据作为产品的前提,我们必须密切了解我们的消费者,我们必须与他们进行实验,以获得最佳结果。我们必须共同创造价值,并不断改变以找出可行的方法,我们必须不断关注我们的产品,以进一步改进它。

本质上,这意味着在一个产品团队中工作,而不是在一个集中的数据团队中工作(从我的经验来看,这太棒了😉).当然,分散数据工程师的概念并不新鲜,你甚至可以说这只是认真对待跨职能团队——我同意这一点。其中一个将此整合并推广的人是 Zhamak Dehghani,她写了一篇很棒的文章,从鸟瞰的角度描述了这种方法如何大规模应用(她在 Youtube 上也很有说服力)👍).我相信我在这篇文章中描述的是一个数据工程师的观点和动机,因此我完全同意她的观点。

结论

我用这篇文章来理清自己的思路,理清自己的一些想法。

通过这样做,我希望我能够给一些人一些东西来思考。也许是一些关于如何改进他们的日常数据工程工作或如何变得更有生产力的灵感。如果你不同意我的观点,我也很乐意听取你的意见并向你学习。

我相信我们可以通过数据产品推动的结果是有影响力的,我们必须让他们成为一等公民。我们拥有实现这一目标的所有工具和技术,让我们开始行动吧!💪

开发数据科学模型预测假新闻

原文:https://towardsdatascience.com/developing-a-data-science-model-to-predict-fake-news-184c25a13cb8?source=collection_archive---------30-----------------------

使用随机森林、GridSearchCV、Python 和 NLP 进行假新闻检测

freestocksUnsplash【1】上拍摄的照片。

目录

  1. 介绍
  2. 探索性数据分析
  3. 特征工程
  4. 模型
  5. 准确(性)
  6. 特征重要性
  7. 摘要
  8. 参考

介绍

解读一篇新闻文章是否有效可能很困难。作为一名研究数据科学、分析 Vidhya 和数据系列的新作者,我获得了一些直觉,可以发展出一双辨别真假的眼睛。我想用数据科学和机器学习来测试我的理论,而不是纯粹依靠直觉。我编译了 Python 代码,构建了一个随机森林模型来预测一篇文章是否是假的。作为一名数据科学家,我一直对创造力和自动化很好奇——我相信我的文章和关于这个模型的工作结合了科学和艺术的两个方面来预测新闻的有效性。下面,我概述了我为这个模型使用的代码,以及对进一步工作的评论,以及对真正的文章的特征感兴趣的非技术用户的总结。

马库斯·温克勒Unsplash【2】上拍摄。

探索性数据分析

这个模型中使用的数据集是从我的虚拟数据中创建的。我正在使用一些常见文章的特征或特性,并试图预测它们是否是假的。在我的情况下,false 是由预先确定的标签决定的,true 也是如此。出于本教程的考虑,这些数据是从我自己的文本中随机生成的。这种数据和模型的伟大之处在于,它可以被缩放和重新定义,比如你从更多的来源收集了几篇文章,你的标签可以是来自脸书、推特甚至纽约时报的真实世界的文章。现在我们知道了我的目标变量 fake(或 true ),让我们看看我用来构建模型的特性:

  • 标题——文章标题中使用的文字/单词(主要的 20 个理由等等)。)
  • 副标题——文章副标题中使用的文本/词语(施工区等)。)
  • title_characters —(":","-",分割文字的特殊字符)
  • 图像计数—使用的图像数量

下面是数据帧的前五行:

返回数据的前几行。作者截图[3]。

特征工程

由于该模型中同时使用了文本和数字特征,自然语言处理(NLP)有利于预测。我使用了常见的术语频率逆文档频率矢量器,将文本计数转换为术语重要性的加权矩阵。然后,我为文本特征如标题副标题编译了 TextTransformertfidf 矢量器。接下来,我使用 NumberTransformerr 类执行了一个类似的方法,但是针对的是数字特性。最后,我将所有的特征,文本和数字结合在一起。下面使用的代码 [3]用于特征工程,NLP,并最终准备/预处理数据,使其能够正确输入到模型中。

# use the term-frequency inverse document frequency vectorizer to transform count of text
# into a weighed matrix of term importance
vec_tdidf = TfidfVectorizer(ngram_range=(1,2), analyzer='word', norm='l2')# compile both the TextTransformer and TfidfVectorizer 
# to the text features
title = Pipeline([
                ('transformer', TextTransformer(key='title')),
                ('vectorizer', vec_tdidf)
                ])
subtitle = Pipeline([
                ('transformer', TextTransformer(key='subtitle')),
                ('vectorizer', vec_tdidf)
                ])# compile the NumberTransformer
# to the numeric features
title_character = Pipeline([
                ('transformer', NumberTransformer(key='title_character')),
                ])
image_count = Pipeline([
                ('transformer', NumberTransformer(key='image_count')),
                ])# combine all of the features, text and numeric together
features = FeatureUnion([('title', title),
                      ('subtitle', subtitle),
                      ('title_character', title_character),
                      ('image_count', image_count)
                      ])

模型

数据科学过程的下一部分,也许是最有趣的部分,是创建一个预测目标变量的模型。在这种情况下,模型是一个随机森林分类器。我创建了一个通用的分类器,然后将所有的特征和分类器统一在一个管道中。我从变量 y 中分离出这些特性,并相应地存储起来以备后用。下一步是对数据进行训练-测试分割,同时建立 70:30 的训练和测试规模,然后为再现性引入随机状态。为了了解模型在新数据上的表现,开发这种分割,并最终在完全不可见的数据上进行测试(这将是模型的真实应用)。

下一步是为 GridSearchCV 创建一个参数网格进行搜索。该网格用于测试几个列出的参数,并查看哪一个是最好的。对于我的模型,我查看了n _ estimates。我创建了一个对象来存储评估器,这是已经创建的管道,其中 param_grid ,2 的 cv (交叉验证),1 的 n_jobs (为了更快的计算),1 的 verbose (为了查看文本输出),以及用于模型诊断的 return_train_score 。我不仅查看了 mean_train_score ,还想看看这个模型在查看带有 mean_test_score 的新数据时有多有用。我用grid _ search . best _ params找出了哪些参数是最好的,这有助于区分 30 个估计量是最好的。

以下是用于此流程建模部分的代码:

# create the classfier from RF
clf = RandomForestClassifier()# unite the features and classfier together
pipe = Pipeline([('features', features),
                 ('clf', clf)
                 ])# split the data into train and test
# isolate the features from the target field
text_numeric_features = ['title', 'subtitle', 
'title_character', 'image_count']y = 'fake_true'X_train, X_test, y_train, y_test = train_test_split(df[text_numeric_features], df[y], 
                                                    test_size=0.30,
                                                    random_state=42
                                                   )# parameter grid to scan through
param_grid = {
     'clf__n_estimators': [10, 20, 30, 40, 50, 100]}grid_search = GridSearchCV(estimator = pipe, param_grid = param_grid, 
                          cv = 2, n_jobs = 1, verbose = 1, return_train_score=True)grid_search.fit(X_train, y_train)grid_search.cv_results_['mean_train_score']grid_search.cv_results_['mean_test_score']grid_search.best_params_clf_test = grid_search.best_estimator_

准确(性)

也许数据科学建模过程中最令人满意的部分是看到您的结果。我在我的 X_test 上预测并将其分配给 preds。我使用 metrics.accuracy_score 来确定我的准确性。

我的模型准确率是 91%

看看这个模型的准确性。作者截图[3]。

要使用引用的代码,请参见以下内容:

# test stats
preds = clf_test.predict(X_test)# print out accuracy
print("Accuracy:", metrics.accuracy_score(y_test, preds))

特征重要性

最重要的功能(字数/计数栏数)。作者截图[3]。

在非数据科学词汇中,特征重要性是指数据集的哪些部分对于预测响应变量非常重要,或者在这种情况下,一篇文章的特征是重要的,以及它们有多重要。因为这个模型是新的,而且数据很少,我看了看绘制最高的特征(大部分是文本),因为使用的特征都很重要。

我调用了grid _ search . best _ estimator _来返回一篇虚假文章的特征重要性。在数据框架中,有几个词不会导致一篇假文章。然而,有很多有助于确定一篇假货。重要词汇包括:

  • 文章正文— 1000,000(格式错误的数字)
  • 图像计数—一篇文章 20 张图像(过高)

以下代码用于特征重要性分析:

pd.DataFrame(grid_search.best_estimator_.named_steps["clf"].feature_importances_)importances = list(zip(grid_search.best_estimator_.named_steps["clf"].feature_importances_, df.columns))
importances.sort(reverse=True)print(grid_search.best_params_)
print(grid_search.best_score_)feature_importances = grid_search.best_estimator_.named_steps["clf"].feature_importances_feat_importances = pd.Series(grid_search.best_estimator_.named_steps["clf"].feature_importances_, 
                             #index=df.columns
                            )
feat_importances.nlargest(10).plot(kind='barh')
plt.title("Top 10 Important Features")
plt.show()

摘要

对于任何数据科学模型和数据集,重要的是要注意,没有一个特征是预测的主要原因,或者在这种情况下,如果一篇文章是假的。正是它们的结合创造了一篇或真或假的文章。虽然我的分析和模型很擅长预测,但最擅长的是根据我自己的数据进行分类。要改变这种模式,除了收集各种真假文章进行训练之外,不需要做太多的工作。一篇文章的关键属性是:

  • 文章标题、文章副标题、文章特殊字符和图片数量

将来要测试的其他字符包括:

  • 正文、画质、图像分类(照片是什么?)、读者数量、星期几、一天中的时间、照片或代码的位置、字母的大小写以及其他一些信息

我希望这篇文章既有趣又有用,并为您提供了一些关于如何对假新闻进行分类的想法,以及构建您自己的数据科学模型的想法和代码。

对于我的模型中使用的所有代码,请参见下面的要点【4】:

GitHub 要点作者使用的代码【4】。

参考

[1], Unsplash ,(2016)

2 马库斯·温克勒Unsplash(2020)

[3] M.Przybyla,截图(2020 年)

[4] M.Przybyla,要点 (2020)

sklearn, sklearn (2020)

熊猫,熊猫 (2020)

培养数据科学家的思维模式

原文:https://towardsdatascience.com/developing-a-data-scientists-mindset-b44cb2476b22?source=collection_archive---------45-----------------------

当数据科学家意识到他们部门或公司内的某个事件时,他们有责任确保该事件产生的任何数据都得到考虑,并得到充分利用

照片致谢

我看过很多关于如何从零开始,将自己转变成一名可雇佣的数据科学家的精彩资源。这些资源建议学习 Python 或 R,掌握数据管理和清理,理解有效和有意的数据可视化,或者甚至学习机器学习。

所有这些技能都是无价的,要成为一名行业数据科学家,通常需要这些技能的不同组合。然而,掌握这些技能并不意味着战斗结束。数据科学家除了具备上面列出的一些技术技能外,还应该从团队中其他人独有的角度来分析公司的日常活动。当数据科学家意识到一个事件(需要一个新的 KPI、即将发布到生产中的功能、最*客户流失的增加、新的营销活动等)时。),他们有责任确保该事件产生的任何数据都得到考虑,并充分发挥其潜力。

例如,我们能想出一些有创意的、特定领域的方法来衡量新特性发布的成功吗?我们能分析数据并分离出客户离开网站之前的一个源事件或一系列行为吗?我们能合理地证明营销策略 A 优于策略 B 吗?

保持数据科学家的心态至关重要。捕捉这种思维模式本质的一个很好的方法是,将数据科学家的复杂职责和思维过程并列在一起。

坚定,但适应性强

“决心驱使数据科学家从数据中获取尽可能多的价值,适应性让数据科学家保持诚实。”

我不断提醒自己,“如果你不相信自己,谁会相信你呢?”没有人比你更了解你的工作。没有人像你一样相信你的工作。没有人会真正知道你的发现什么时候可以像你一样被展示。没有人会像您一样知道您的模型何时可以部署到生产中。你被聘用是因为你的特殊技能为公司带来了独特的价值。你有责任确保你所做的所有工作都是诚实和正直的。当你需要下定决心并倡导你的工作时,你必须这样做。您可以通过多种方式做到这一点,但这里有几个例子:

  • 争取宝贵的时间与高级工程师、业务伙伴或经理会面,以获得阻碍你完成分析的问题的答案
  • 向您的同事解释您的项目想法如何以及为什么会产生对 X、Y 和 Z 部门有益的见解
  • 提醒你自己和你的上司,准确、有价值的洞察力来自时间、诚信和对细节的关注..不是仓促的分析和拼凑的预测模型

另一方面,数据科学家必须愿意在时机成熟时为团队做出贡献。如果公司的工作重心发生了转移,他们应该能够迅速转变,将注意力转移到手头的任何重要任务上。数据科学家应该总是愿意学习新东西,无论是新领域(如消费金融、出站电子邮件营销、公民技术)还是新的商业智能软件。数据科学家应该有决心,但永远不应该让对研究的追求阻止他们看到何时该转移重点。有时,如果业务方面决定有更重要的优先事项,或者当前项目被认为是一个死胡同,甚至可能是时候完全放弃一个项目了。数据科学家应始终尽最大努力在以下方面保持适应性:

  • 尝试新的软件包、算法、软件等。这是同事们建议的,即使你从第一天起就忠于“不成功便成仁”的技术
  • 最大限度地减少负面评论当你的经理要求你放弃一个你非常兴奋的项目,专注于一个需要立即关注的“热点项目”时
  • 不断地从不同的角度处理问题,并试着站在公司不同角色的角度考虑问题
  • 接受不正确的假设,用它们来进一步推动你的研究,不要让它们阻碍、阻止或分散你的注意力

我知道决心和适应能力并不一定是完全相反的。但是,这两种特质的本质确实在某种程度上实现了*衡,从而使数据科学家变得更加全面。这种决心促使数据科学家尽可能地从他们所掌握的数据中获取所有价值,并让他们有信心相信这些发现是准确的、有价值的、值得一听的。适应性让数据科学家保持诚实,防止他们在教育和技能发展方面停滞不前,并且(在我看来)让他们总体上更容易共事。

口齿伶俐,但好奇

所有的技术人员在这个行业都很快认识到,交流你的想法、关注点和关于项目的新想法是非常困难的……尤其是当你试图和一个和你不在同一个领域的人交谈时。然而,数据科学中最需要的“软技能”之一是有效的沟通,因为数据科学家是故事讲述者。当决定下一季度专注于公司的哪个部门时,数据科学家需要提出一个叙述来证明哪个重点会给公司带来最大的利益。当数据科学家开发一个模型来帮助预测消费者行为时,他/她必须向利益相关者传达为什么该模型会对收入产生积极影响。数据科学家必须能够发现最复杂和最深刻的见解,但这不是他们任务的终点。一个伟大的发现只能让你到此为止!他们必须将这些见解转化为成熟的故事和可操作的项目,吸引业务对手,并让他们相信这些见解的实际价值。成为口齿伶俐的可能是一个很难掌握的任务,但是这里有一些方法可以练习:

  • 更多地关注构建数据库表、代码库或过程的文档的机会,这将使公司的其他员工受益
  • 在与业务伙伴讨论时,花时间解释为什么某些东西会起作用或者数据来自哪里(注意:这是互利的!他们学习,你练习你的沟通!)
  • 练习将复杂的数据科学概念传达给身边不在该领域的人(家人、朋友、重要的其他人等)的能力。)

能够解释你的发现显然是数据科学家工作流程中非常重要的一部分,但比说话更重要的是提问和倾听的能力。数据科学家应该总是向他们的业务伙伴提问。虽然他们不是编写代码的人,但是业务伙伴(产品所有者、主管、执行官等。)是那些拥有有价值的、基本的特定领域知识的人,这些知识将帮助代码获得价值。商业对手不是分析数据的人。但是,他们是生成数据的人,或者至少参与了数据的生成,他们拥有不可或缺的行业知识,这些知识将极大地帮助你的分析。同样,数据科学家应该总是询问有关他/她自己工作的问题。如果那里有一个 0 或者 NULL 会发生什么?我丢失数据了吗?这些数字有意义吗?数字胜于雄辩,所以听着!这里有几个在工作中变得更加好奇的好机会:

  • 在任何 sprint 计划或项目会议之前,为你的同事准备一份问题清单,这样在你着手一项任务之前,你可以获得尽可能多的信息
  • 确保在接受数据源为事实、将一段代码投入生产或向高管层提交发现之前,完成尽职调查测试

与前面提到的特征相似,善于表达和好奇并不相互排斥。但是,这两种特质确实在某种程度上相互补充,将数据科学家变成了一股不可忽视的力量。这种表达使数据科学家能够与来自各种背景的同事和客户联系;它还允许他们提供更有力、更相关的解释和演示。不断的调查推动数据科学家不断保持他们工作的质量,并不断追求卓越。

数据科学的领域如此广阔。每天都有新的语言、包、软件和算法发布,而且没有减缓的迹象。随着所有这些新工具的不断涌现,保持你的技能达到标准的压力总是存在的。不管你把时间集中在哪些工具上,如果你不断检查你的心态,你将会成为更好的数据科学家。坚定,但适应性强。表达清晰,但好奇。

原载于 2020 年 4 月 24 日https://data dreamer . io

使用 Plotly Dash & TigerGraph 开发新冠肺炎文章的动态作者搜索(第 4 部分)

原文:https://towardsdatascience.com/developing-a-dynamic-author-search-of-covid-19-articles-using-plotly-dash-tigergraph-part-4-34e240882a06?source=collection_archive---------51-----------------------

船员Unsplash 上拍照

议程

  1. 背景
  2. 安装和导入软件包
  3. 建立与 TigerGraph 的连接
  4. 排序数据
  5. 创建应用程序
  6. 创建 Plotly 图像
  7. 建立布局和元素
  8. 配置用户输入
  9. 运行应用程序
  10. 后续步骤

1.背景

CORD-19 是一个巨大的开源新冠肺炎文章数据库。该数据集最初是作为数据分析师收集有意义的信息的挑战而创建的,这些信息可以回答关于该病毒的一些未解决的问题。虽然我没有参加那个挑战,但我发现数据库是一个有趣的工作工具,于是我开始研究和实践计算机科学中的新课题,并将它们应用于这些数据。

这是一个系列的第 4 部分,详细介绍了我为创建一个完整的端到端应用程序而采取的所有步骤,该应用程序分析 CORD-19 数据集的元数据。在第 1 部分的中,我们看了如何使用 scispaCy,一个为医学数据设计的 NLP 工具,从研究论文的摘要中提取关键词。在第 2 部分中,我们看到了如何使用 TigerGraph Cloud 在图形中建模我们的数据及其相互联系。在第 3 部分的中,我们介绍了如何编写查询来有效地搜索和提取图表中的数据。在本系列的最后一部分,我们将探索使用我们的图形查询来提取数据,并使用 Python 库 Plotly 和 Dash 可视化地表示这些数据。

这个项目的完整代码可以在我的 GitHub 页面上找到。

2.安装和导入我们的包

我们有相当多的软件包需要安装和导入。要安装软件包,请从终端执行 pip 安装。

pip install package_name

然后,无论您在哪里编写代码(我使用了 Atom ,导入以下包。

在 Google Colab 这样的在线*台上运行 Dash 相当困难,所以我建议把所有东西都写在本地。

3.连接到 TigerGraph 云

我们使用 pyTigerGraph 连接到 TigerGraph 云,pyTigerGraph 是由 Parker Erickson 制作的 python 包。他在 Medium 上写了一些令人惊叹的文章,你可以在这里查看。要连接到 Cloud,我们需要输入域名、图名和一个 API 令牌(为了保护我自己的图的隐私,我没有包括它)。

要获得自己图形的令牌,请进入 TigerGraph Cloud 上的管理门户,然后选择创建秘密

tigergraph 管理页面

一旦创建了您的秘密,您就可以使用以下代码获得您的令牌:

一旦您的连接建立,我们可以运行我们的查询。

为了运行我们的查询,我们输入查询名称、参数、超时时间和大小限制。你可以在 pyTigerGraph 这里看到这个函数和所有其他函数的完整文档。

我们正在运行两个查询。第一个获取数据库中所有作者的列表。查询代码如下所示:

CREATE QUERY AuthorSearchDash() FOR GRAPH MyGraph {   
/* This querry grabs all authors in our database */ SumAccum<INT> @pubNum; ListAccum<VERTEX> @pubList; Seed={AUTHOR.*}; Author = SELECT a                         FROM Seed:a-()-:t                                      ACCUM a.@pubNum +=1, a.@pubList +=t              ORDER BY a.@pubNum DESC; PRINT Author;
}

第二个查询获取我们所有的出版物。该代码如下所示:

CREATE QUERY GrabPubs() FOR GRAPH MyGraph {   
/* Grab all publications with their relevant information */ Seed = {PUBLICATION.*}; Pubs = SELECT s                        FROM Seed:s -() - :t; PRINT Pubs[Pubs.id, Pubs.pub_title, Pubs.pub_url];
}

要进一步了解在 TigerGraph Cloud 中编写 GSQL 查询,请参考本系列的第 3 部分。

4.整理我们的数据

导入数据后,我们现在需要对其进行排序,使其更易于管理。我们使用 pandas 将数据存储为数据帧。然后,我们使用 flat-Table 来标准化我们的数据。最后,我们将数据分类到列表和字典中,以提供更快的查找。

由于我们的应用程序是动态的,它需要连续查找数据。如果数据存储在列表或字典中,这比存储在数据帧中要快得多。

5.创建我们应用程序的实例

我们使用之前导入的 Dash 包实例化我们的应用程序。我们还指定了要使用的样式表。顾名思义,样式表是应用于仪表板的样式和布局的集合。我们使用 Bootstrap 框架,因为它允许我们方便地配置我们的应用程序布局。

我们还在这里创建了两个字典。这些将在稍后用于创建我们的条形图的颜色。

6.创建一个空的 Plotly 条形图

接下来,让我们创建图表。我们现在只是创建一个空白图表,因为当用户与仪表板交互时,图表会更新。我们使用 Plotly Express 制作条形图。图表中的 x 轴代表作者的姓名,而 y 轴代表每位作者的出版物数量。

7.建立我们的布局和元素

这是我们代码的核心所在。Dash 的工作原理是模仿你的网站的 HTML 结构。如果你没有 HTML 的经验,不要惊慌。我之前没有任何经验,仅仅通过查看 Dash 文档就能学到很多东西。而且,如果你以前有过 HTML 的经验,这应该看起来很熟悉。

让我们浏览一下这个仪表板的结构。我们从包含仪表板中所有内容的父 Div 开始。然后,我们为标题和副标题添加两个组件。然后,我们使用 Dash Bootstrap(还记得我们之前导入的样式表)创建一个包含两个等宽列的行。在左栏中,我们有一个包含作者列表的下拉列表,一个显示出版物数量的 div,一个显示出版物列表的 div。在右栏,我们有我们的图表。

8.用用户输入更新我们的用户界面

现在,我们已经完成了仪表板布局。但是,为了使它动态,我们需要添加回调。回调允许我们从特定的容器(比如下拉菜单)获取输入,执行一些操作或更新,并将结果输出到其他容器。我们使用了三个回调函数,每个回调函数对应一个我们输出数据的容器。

更新我们的表格

这个回调从 dropdown 容器中获取输入(因此输入是作者的名字),并打印出与该作者对应的文章表。这些出版物以及它们的细节都来自我们之前制作的字典。

更新我们的数字字段

这是最简单的回调。我们只需从下拉列表中取一个作者的名字,并打印相应数量的出版物。由于我们在开始时创建了字典,这变得特别容易。

更新我们的图表

我们的第三次回调用我们刚刚选择的作者的新条形图更新了条形图。我们在 Plotly 中用 add_trace 函数添加了这个条。每当向图形中添加跟踪时,该跟踪都会收到自己的图例图标。为了防止这种情况,我们创建了 legendgroups ,并使用一些操作来只显示还没有显示的组。

9.运行我们的仪表板

我们通过在本地服务器上运行应用程序来结束我们的代码

有了这两行代码,我们的程序就完成了。要运行代码,打开终端,切换到代码所在的目录,然后运行 python 脚本。运行前,确保您的图形解决方案已启动。

cd location/where/code/is/located
python app_name.py

调用脚本后,需要一段时间来加载。最终加载后,您应该会看到如下所示的内容:

终端输出

打开 URL,您应该会看到这个屏幕。

仪表板图像

就这样,你可以看到你辛辛苦苦建立的仪表板!但是,现在不要停止。试一试,看看我们已经实现的所有功能。

仪表板使用示例

10.后续步骤

这是我第一次处理 Plotly 和 Dash。我知道代码有很大的优化和定制空间,这个我就留给你了。但是,在微调运行时和使仪表板在视觉上更有吸引力(我认为美学显然不是我的强项)的过程中,您还可以添加更多的交互式模块。最好的部分是我们已经写好了查询。如果您参考本系列的第 3 部分,我们编写了这里没有实现的多个查询。特别是,在这个仪表板中实现查询查找相似的出版物和查询查找引用给定关键字的顶级出版物是非常有趣的。我希望有一天能自己解决这些问题,但我也希望你们也能这样做。或者,进一步编写一些新的查询,提取其他有用的数据进行显示。

结论

到此,这个简短的系列就结束了。这是一段不*凡的旅程。我们首先使用 NLP 从我们收集的新冠肺炎文章中提取数据。然后,我们将数据映射到一个图表中,并学习如何编写查询来搜索数据。最后,我们学习了如何在后端实现查询来创建可视化用户界面。感谢您和我一起探索数据科学中一些非常酷的话题。我希望你已经学到了一两件可以应用到你正在做的任何事情上的东西,无论是一个有趣的小项目还是一个全面的应用程序。感谢阅读,敬请关注未来更多文章!

资源

  1. https://www . ka ggle . com/Allen-institute-for-ai/CORD-19-research-challenge
  2. https://towards data science . com/using-scispacy-for-named-entity-recognition-785389 e 7918d
  3. https://towards data science . com/linking-documents-in-a-semantic-graph-732 ab 511 a01e
  4. https://towards data science . com/graph-query-searches-part-3-A8 BFF 845 C3 f1
  5. https://github . com/akash-Kaul/Dash-Publication-visualizer . git
  6. https://atom.io/
  7. https://medium.com/@parker.erickson
  8. https://Parker Erickson . github . io/pyTigerGraph/query functions/
  9. https://dash.plotly.com/

[## akash-Kaul/Dash-出版物-可视化工具

使用 Plotly 和 Dash-akash-Kaul/Dash-Publication-Visualizer 对新冠肺炎文章进行动态作者搜索

github.com](https://github.com/akash-kaul/Dash-Publication-Visualizer) [## 阿卡什·考尔-数据科学实习生-未来学家学院| LinkedIn

查看阿卡什·考尔在全球最大的职业社区 LinkedIn 上的个人资料。阿卡什有 5 个工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/akash-kaul-6a8063194/)

培养对数据科学的良好态度

原文:https://towardsdatascience.com/developing-a-good-attitude-towards-data-science-be4b7d0e1e49?source=collection_archive---------48-----------------------

作为一名专业或有抱负的数据科学家、机器学习或人工智能工程师,你需要养成良好的工作态度。

Arif Riyanto 在 Unsplash 上拍摄的照片

目前在数据科学领域的任何人,AI/ML 都可以说这是一个非常广泛和动态的领域,因此,为了实现你的目标或学习许多新东西,你也必须非常灵活。在这个故事中,我将分享一些我认为已经在这个领域或寻求进入这个领域的每个人都应该采用的东西。

要有创意

作为数据人员,我们必须知道并接受这样一个事实,即做事没有唯一的方式。我们必须避免拘泥于一种特定的做事方法,而是探索我们可以用于特定用例的许多工具、框架、库和包。不要执着于一件事,用那些让你的工作更容易、更快的事情。如果目前没有什么适合你的,那就创造一些东西,联系你社区里志同道合的人,一起创造一些东西。可能对以后几百人甚至几千人都有帮助。不要害怕开始,需要时寻求帮助,测试你的创造力。

好奇

学习是一个永无止境的过程,因此,你永远不会知道太多。好奇心是每个数据科学家、人工智能或人工智能工程师都需要培养的基本态度。不知道某事并不可耻,知识只有在寻求时才能找到。每当需要的时候,养成提问或寻求清晰的习惯。这表明你对这个话题非常感兴趣,并证明你愿意学习更多的知识来获得更多的知识。作为通过从数据中进行推断来工作的人,我们必须确保我们知道如何完成工作,我们需要做什么来完成工作,以及我们为什么要做某些事情来完成工作。向你的同事或主管询问关于你的工作或项目的技术问题,将有助于你理解你正在做的工作的核心概念,并指导你完成工作。

保持一致

对于有抱负的数据科学家、AI 或 ML 工程师来说,最重要的事情之一是一致性。很难在一个学习轨道上坚持这么长时间,尤其是当事情似乎停滞不前的时候。要知道每个人都有突破的时候,就像每朵花都有绽放的时候一样。坚持学习,坚持一个学习计划,不要不惜一切代价去违背。你的突破会到来,但是当它到来的时候一定要做好准备。作为初学者,你所学的一切都是你在行业中会用到最多的东西,所以不要跳过最初的步骤。如果你坚持不懈地学习,你会比你预期的更快地为行业做好准备。

编写干净且可重用的代码

这个领域的大多数人每天都在编写代码。这个领域可能有一些人的具体工作任务不包括编写代码,但对于我们大多数每天花很多时间编写代码的人来说,我们需要接受一组道德规范,使我们成为优秀的优秀程序员。代码伦理基本上是一种公认的编写代码的方式,它使我们的工作看起来整洁有序。遵守代码道德有许多好处,最常见的是,它给你一种职业程序员的感觉,并证明你是一个有条理的人。有许多代码道德规范,但我认为每个程序员都需要知道的基本规范是:

  • 给变量命名:不要把任何变量命名为任何字母表或字母之类的东西。你的变量名应该告诉任何看代码的人这个变量代表什么。它可以是一个单词或两个或更多单词的简短形式。您可以使用下划线来分隔缩短的单词,或者使用一种称为驼峰式大小写的样式。在这里,您连接两个单词,第一个单词以小写开始,任何新单词以大写开始。例如 MyVar1 或 firstVariableName。
  • 缩进:缩进是编码中必须遵循的原则,因为它以一种更具可读性和组织性的方式构建代码。
    属于一个块的任何代码,如函数、子程序、循环和 if 语句必须缩进以显示其在程序中的作用域。
  • 注释:注释是不影响代码结果的任何文本,它只是让某人知道你在程序中做了什么或者在代码块中正在做什么的一段文本。注释不应该美化代码。它们将作为指导方针。所以坚持简单的评论。不要做
!!#<<!--comment--!>>

简单的评论就可以了,比如:

# This is a comment

广泛阅读

作为一名数据科学家,人工智能或 ML 工程师,你只有学得好才算好。阅读你在你的领域感兴趣的主题的博客帖子、文章或论文,会对你拓宽知识面和学习新事物有很大帮助。经常阅读,让自己了解优秀作家的文章。

自我测试

落地数据科学,AI/ML 工作最常涉及的是参加编码测试的过程。这可能是非常压倒性和困难的,尤其是如果你没有准备好。让自己为编码测试做好准备的最好方法是每天测试自己。这不仅能帮助你提高技能,还能让你变得更快更有时间意识。互联网上有许多*台,你可以在那里进行编码测试,但我最熟悉的一个是 HackerRank 。坚持每天至少进行一次测试,随着时间的推移,你会非常擅长编码测试。此外,你可以留意模拟面试,或者让朋友或同事偶尔面试你一次。这有助于你在真正的面试中建立自信,并为你在实际面试中可能被问到的一些问题做好准备。

建立稳固的投资组合

作为一名数据科学家、人工智能或 ML 工程师,一份好的投资组合应该包括你已经完成的个人或专业项目、你的成就、专业目标和目的、技能、兴趣和教育背景。一份可靠的投资组合会让你脱颖而出,很容易让你受到招聘人员和雇主的青睐。

建立一个良好的网络

与和你兴趣相投的人交往,经常保持联系。向这些人寻求帮助或分享想法。与一些你尊敬的人互动,向他们寻求技巧和其他问题,这些可以帮助你成为数据科学家、人工智能或人工智能工程师。

准备团队工作

在大多数公司,数据科学家、数据工程师、人工智能和人工智能工程师作为一个团队一起工作,因此,任何渴望进入这个行业的人都需要让自己具备一些团队工作技能,以帮助团队取得进步。团队工作技能可以是软技能和技术技能。软技能主要指与团队中其他人的沟通和关系,无论是同事还是主管。技术技能是应用于工作的核心技能,可以带来最大的进步。学习如何使用分布式版本控制工具,如 Git 和 Github,对于团队工作来说是非常重要的,因为它让团队中的每个人都可以自由地作为一个团队一起工作,而彼此却不在一起。你可以从的这篇文章中学习如何使用分布式版本控制系统,比如 Git 和 Github。

利用你的领域知识成为你的优势

作为一名数据科学家,你的领域知识就是你的超能力。— 德里克·德贝杜伊

如果数据科学家在专业领域工作,他们会工作得最好。一名研究银行和金融的数据科学家将在金融公司工作得最好,而一名接受过生物科学培训的数据科学家同样会在生物行业的公司工作得最好。数据科学是当今发展最快和最多样化的领域,你不需要拥有计算机科学的理学学士或理学硕士学位就能从事数据科学职业。无论你在哪个领域找到自己,只要你真的想,你都可以成为一名数据科学家。展开你的翅膀,作为数据科学家在你的领域里伸出援手。将领域转换到你知之甚少的领域会大大降低你作为该领域数据科学家的价值。在一家需要数据科学家来处理气候或地理空间数据的公司中,受过金融数据处理培训的数据科学家几乎毫无用处。人们可能会说“每个数据都是数据”,但作为一名数据科学家,你必须知道理解你的数据是利用数据取得任何工作进展的关键。

感谢您花时间阅读这篇文章。欢迎你在回复区分享你的想法和观点,你可以直接在推特LinkedIn 上联系我。祝你有美好的一天。

非常感谢 Benacq 校对并纠正了我写这篇文章时犯的许多错误。

使用 PyCaret 开发心脏病预测模型

原文:https://towardsdatascience.com/developing-a-model-for-heart-disease-prediction-using-pycaret-9cdf03a66f42?source=collection_archive---------46-----------------------

来源:Adobe Stock(许可证编号 262173764)

背景

在一个发达的专业数据科学环境中,你可能可以访问 AWS、GCP、Azure 或其他*台或软件,并使用工具来进行实验设置、跟踪和记录。但是,如果你只是想让一个试点项目启动并快速运行,或者你正在做一个研究项目呢?这就是 py caret(https://pycaret.org/)快速系统地做实验的能力可能派上用场的地方!

PyCaret 是什么?它的创建者将其描述为“…开源的、低代码的Python 机器学习库,允许你在几秒钟内从准备数据到在你选择的笔记本环境中部署你的模型。”任何能让你在内容上花更多时间并最大化影响的东西都是好的,对吗?

在下面的例子中,我们将开发、评估和检验一个使用 PyCaret 预测心脏病的模型。因为这是我第一次使用 PyCaret,所以我也将在最后提供一些想法和第一印象。一如往常,在任何涉及健康的示例应用中,关联、推论和评论绝不构成医疗建议或专业知识。用于支持本文的笔记本和其他材料可以在我的 Github 上获得(https://Github . com/Jason-Bentley/medium _ articles/tree/master/heart _ disease _ py caret)。

数据

克利夫兰诊所处理过的心脏病数据集(https://archive.ics.uci.edu/ml/datasets/heart+Disease)包含 13 个特征和 303 名患者的结果。当分为两类时,结果表明患者是否患有心脏病,并且是感兴趣的目标。总体而言,队列中 45%的患者患有某种程度的心脏病,因此我们的目标是*衡的。

对于我们的简略探索性数据分析(EDA),我们将比较有心脏病和无心脏病患者的特征,并使用图(图 1 和图 2)更详细地查看连续特征。

图一。队列表

图二。连续特征的绘图

来自 EDA 的指示是我们可能期望的。患有心脏病的患者更可能是老年人、男性、无症状胸痛、较高的血清胆固醇、较低的最大心率、运动诱发的心绞痛、运动期间与休息时相比较高的 st 段压低、*坦或向下倾斜的运动 ST 段峰值斜率、受影响的主要血管以及通过铊负荷试验识别的血流缺陷(固定或可逆)。

我们在预处理时需要考虑 EDA 的一些观察结果:

  1. 连续(通过荧光镜检查确定的血管计数)和分类特征(铊负荷试验心脏血流)的一些缺失值。
  2. ST-T 异常的静息心电图结果在整个队列中只有 4 例——这是一个罕见的水*,我们可以将其与另一个水*相结合,或者您可以将其视为一个低方差的特征。我们可能还想结合其他功能的水*。
  3. 一些潜在的异常值,一个没有心脏病的患者的血清胆固醇水*高于 500,心脏病组中的两个患者的 ST 段压低值> 5。

实验装置

我结合了一些类别(胸痛的典型和非典型心绞痛;静息心电图 ST-T 异常与左心室肥厚:峰值运动 ST 段斜率*缓或下降;血流铊负荷试验中的固定缺陷和可逆缺陷)并将运动期间的血清胆固醇和 st 下降调整至 99.5 百分位,以解决上述第 2 点和第 3 点。

修改后的数据通过 setup() 功能成为实验的基础。该功能有大量输入,因为它创建了一个数据处理管道,涵盖许多常见任务,如转换、归一化、插补等。完整的列表可以在这里找到(【https://pycaret.org/preprocessing/】T2)。

在实验设置中,我们将使用 65%的数据进行训练。为了解决缺失值,我们将数值和分类特征的插补方法分别设置为中位数和众数。运行时,我们首先确认分类变量和数字变量的名称。然后创建管道的其余部分,实验设置完成,生成一个漂亮的汇总表,突出显示管道的各个方面(图 3)。

图 3。实验设置包括确认特征类型,然后生成管道汇总表(截断)。

我们可以看到,我们保留了原始数据中的所有观察值(如果我们选择使用 PyCaret 来过滤离群值,那么与原始数据相比,采样数据中的观察值数量会更少)。使用我们的 65%训练 35%测试分割,我们分别有 196 和 107 个观察值。总共有 15 个特征(5 个数字特征和 10 个分类特征)。第 4 行中突出显示的部分表示检测到缺失数据,第 13 行和第 14 行表示我们对这些数据进行估算的选择。

重要的是,这个设置对象构成了所有后续工作的基础。模型开发的许多后续函数调用会将结果保存为实验对象的一部分,以便可以随时访问它们,而且还可以保存整个过程。例如,实验对象包含用于采样、训练和测试特征矩阵以及目标向量的单独项目。

模型开发

设置完成后,为了快速识别一组好的候选模型,我们使用 compare_models() 。这使用默认超参数来评估不同的分类模型,并使用 10 重交叉验证来评估训练数据中的性能。有 18 种可能的分类器可用,但为了好玩,让我们将自己限制在一些增强方法(梯度,极端和轻),两种风格的 SVM(线性,径向基)和随机森林。 compare_models() 的输出很好地总结了被评估者的六个常用分类器指标(图 4)。

图 4。compare_models()的输出

理想情况下,我们会选择最佳候选模型,并在调整后选择最终选项。然而,为了简单起见,鉴于我们的极端梯度推进模型是一个很好的准确性候选,让我们继续这样做。如果我们想查看上表中所选分类器的 CV 结果,我们可以使用 create_model() 函数为一个特定的模型创建一个对象。

超参数调优是使用 tune_model() 函数完成的,这稍微提高了性能(图 5)。例如,精确度从 0.82 提高到 0.85。请注意,如果你看引擎盖下,随机网格搜索与 10 次迭代正在使用。当然,可以使用更多的迭代,甚至是不同的方法,例如 hyperopt,但是为了本文的目的,我们将继续查看模型。

图 5。调整后候选模型的性能

evaluate_model() 函数提供了一个交互式单元格输出,其中包含许多常用的有用图表和摘要。可用性可能取决于您正在评估的模型,但是大多数对于所有模型都是通用的,并且代表了我们在评估模型时想要的一组良好的标准输出。交互式单元格如下所示,其中灰色框中的每个选项都可以在笔记本中点击。查看我们的混淆矩阵作为示例输出(图 6),我们可以看到在测试集中我们有 45 个真阴性,36 个真阳性,以及 13 个假阳性和假阴性的实例,这给了我们 76%的准确率。

图 6。evaluate_model()中调优模型的混淆矩阵

为了理解是什么特征驱动了模型的心脏病预测,通常使用 SHAP 值(https://shap.readthedocs.io/en/latest/)。PyCaret 允许我们使用函数 interpret_model() 创建选定的基于 SHAP 的输出,以便更好地理解我们的模型。

图 7。SHAP 值汇总图

对于我们的模型,三个主要因素(图 7)是受影响的主要血管的数量,其中最低值(0)降低了预测风险,无症状胸痛(如果存在)增加了预测风险,铊负荷试验表明正常血流(高值)降低了预测风险。我们还可以看到一些似乎对预测风险没有影响的因素:空腹血糖高、胸痛(心绞痛或非心绞痛)和性别。

为了更深入一点,我们可以看看在我们的测试集中,特征对患者的预测风险评分的贡献(图 8)。

图 8。对高风险患者的预测贡献

与基础风险评分(*均模型输出= -0.21,概率= 0.45)相比,该患者的高度 ST-T 抑制、最大心率、铊负荷试验的血流缺陷、无症状胸痛和 2 条受影响的主要血管均导致心脏病的高预测风险评分(4.97,概率= 0.99)。

使用 predict_model() 函数,我们可以使用拒绝集来检查性能。性能比训练 CV 差一点,所以我们可能有点过度拟合,但也可能更差(图 9)。另外,通过适当的超参数调整,我们也可以克服这个问题。

图 9。我们所选模型的保留集性能与训练数据中的默认和调整模型性能的比较

最后,为了在实践中使用这个模型,我们可能还希望将预测的心脏病可能性分组,以便我们可以定义要采取的一系列行动。一种方法是根据预测的风险十分位数,在测试组中绘制心脏病发病率图。我们设定阈值的位置取决于具体情况,需要具备专业的临床知识并了解收益与成本。由于这是一个例子,我掩饰这一点。目测之后,我们假设有三个不同的风险组(低、中、高),每个风险组都有不同的跟进措施。

图 10。根据预测的风险十分位数,测试组的心脏病发病率。虚线是队列中的总体风险(0.45)

读者可能已经注意到上面的输出缺少 Python 代码。那么,在我自己准备数据并生成上面的一些自定义数字之后,设置数据管道、使用 CV 识别候选模型并对其进行调优、评估和解释,以及最终评估保留测试集的性能,到底需要多少 PyCaret 代码呢?这就是,7 个功能,最少的输入!

# experiment set-up
exp1 = setup(hd_df,
             train_size=0.65,
             target='target',
             session_id=101,
             ignore_features=['num', 'target_c'],
             numeric_imputation = 'median',
             categorical_imputation = 'mode')# find a good candidate model
compare_models(blacklist=['lr', 'lda', 'qda', 'et', 'catboost', 'ada', 'ridge', 'dt', 'nb', 'gpc', 'knn', 'mlp'],
               fold=10,
               turbo=False)# tune the candidate model - you can skip create_model as this is called as part of tune_model anyway
tuned_model = tune_model('xgboost')# evaluate
evaluate_model(tuned_model)# SHAP-based feature importance and understanding of prediction
interpret_model(tuned_model)
interpret_model(tuned_model, "reason", observation=94)# performance in hold-out test set
predict_model(tuned_model)

摘要

这是我第一次尝试使用 PyCaret,虽然仍然有大量的文档需要完成,但我的第一印象是它太棒了!它真的让我可以很快地了解我想了解的细节,文档和可用的教程都很有帮助。

正如我们看到的实验设置,找到一个模型,调整,评估和检查当然是低代码。低代码当然并不意味着在数据理解、数据清理和功能工程方面跳过尽职调查,但是 PyCaret 方法意味着你可以在这些事情上花更多的时间。

当然,任何低代码解决方案都需要权衡灵活性。以下是我的一些观察:

  1. 在实验设置中,您不能选择仅应用于选定特征的预处理选项,并且并非所有可能性都可用。例如,不能对单个要素应用法线变换,也不能设置阈值来修剪要素以减少异常值。
  2. 您需要检查构造的管道对象,以了解预处理步骤的执行顺序。生成管道流程图表示的功能可能是一个奇妙的未来附加功能。
  3. 允许超参数调整的不同方法的灵活性将是很大的,例如访问 hyperopt 的简单方法。我确实自己尝试了一些实验,在实验对象之外使用 hyperopt,然后将这些参数传回到模型摘要中是可能的(但是很笨拙)。
  4. 包含 SHAP 值的函数是很棒的,但是这种功能没有扩展到通过标准 SHAP 库提供的全套可视化。例如,通过 link='logit '参数传递单个力图的多患者力图,或者选择用于相关性图中交互项的变量,都不能通过 interpret_model() 获得。然而,您可以从实验对象中获取模型对象和测试数据,并自己进行 SHAP。
  5. 您可以通过实验对象访问的内容有些随意,您可能需要稍微搜索一下您想要的内容,或者您可能需要检查实际的函数(即,您选择的估计器的调整模型中使用的参数网格)。然而,这些可以被访问,因此可以创建模型开发的定制摘要/可视化,并且希望在未来的更新中,从引擎盖下获得您需要的东西可能会更加用户友好。
  6. 该结构引导用户遵循适当的标准化工作流程来开发预测模型。
  7. 将最终模型和整个实验作为单独的对象保存的能力对于部署和可再现性来说是非常重要的。
  8. 虽然我能够提取信息并创建自己的总结,例如初始训练、调整和保持之间的性能指标,但从实验对象创建这种性质的总结报告的功能将是非常棒的。

在未来,我希望更多地利用 PyCaret 来处理更大的数据集,其中高基数特性的内置处理会非常有用。一如既往,欢迎评论、想法、反馈和讨论。

开发机器学习管道

原文:https://towardsdatascience.com/developing-machine-learning-pipelines-2881e50fc5e4?source=collection_archive---------11-----------------------

在数据科学领域,你的表现取决于你构建工作的方式

E 即使最有经验的数据科学家也不总是熟悉开发机器学习管道的最佳实践。对于应该包括哪些步骤,它们的顺序应该是什么,以及总的来说,如何确保您创建的见解是准确和有价值的,存在很多困惑。描述实用和正确方法的好资源也非常有限。

然而,在许多数据科学项目之后,你开始意识到构建管道的方法总是相同的。

机器学习管道是模块化的,根据情况,可以添加或跳过一些步骤。你有分类变量吗?添加代码对它们进行一次性编码。你有丢失的数据吗?引入一些代码来估算它们。

为了给出更实用的方法,您可以在我的 Github 上找到一个示例管道。这个例子旨在开发一个预测模型,用于估计驾驶员发生严重事故的风险。

1.商业问题

任何机器学习管道都是从最重要的一步开始的,这根本不是机器学习,而是商业问题。在对我们要实现的目标进行彻底讨论之前,机器学习不应该发挥作用。

所有利益相关者都应该参与到这样的对话中,尤其是业务团队和最终用户。应该仔细倾听他们的目标,在整个项目过程中,应该始终牢记他们的需求和目标。因为,说到底,做机器学习是没有意义的,不管它有多性感,除非它能解决利益相关者的问题。你应该问你的利益相关者:这个项目的动机是什么?有哪些痛点?结果将如何被使用?

即使在这些问题得到回答之后,立即开始编写机器学习模型也是错误的。有没有更容易、更务实、更有效的解决方案来实现你的利益相关者的目标?我们能否使用描述性统计或更容易使用的工具,如 Excel?当且仅当答案是否定的,我们才能继续下一步。

2.翻译需求

一旦同意 ML 是正确的方法,下一步就是将目标、难点和限制转化为技术需求。换句话说,您需要将业务需求转化为易于应用于标准建模技术的东西。如果你的利益相关者寻求一个实数的预测,那么使用回归模型;如果您必须预测有限的一组值,分类模型是最合适的解决方案。

3.数据收集

没有数据,任何机器学习项目都不可能成功。要保证项目的成功,需要获得足够多的高质量样品。更具体地说,像线性回归或逻辑回归这样的算法即使只有几百个观察值也能很好地工作,而更复杂的算法,从 CART 到神经网络,至少需要几千个。

就质量而言,来自自动化、不灵活系统的数据,在没有人为干预的情况下,将更适合机器学习应用。例如,应该避免自由文本字段。如果数据收集设置是数据科学家创建的 Google 表单,下拉列表比自由文本框更受欢迎。

然而,总的来说,每个数据科学家都应该接受这样的事实:数据将会是杂乱的,手工输入的,充满了缺失的数据。这只是工作的一部分。

4.数据加载

数据集最常见的格式通常是 CSV 和 Excel 文件。要加载数据,您可以使用:

vehicles = pd.read_csv(‘Data/Vehicles.csv’, low_memory=False)
casualties = pd.read_csv(‘Data/Casualties.csv’, low_memory=False)
accidents = pd.read_csv(‘Data/Accidents.csv’, low_memory=False)

也就是说,如果您可以从数据库中获取数据,这将是首选。数据库被配置为保持完整性,这意味着只允许通过完整性检查的数据。此外,数据库维护跨表的关系,同时易于更新。这样做,脚本可以通过编程从相同的源中提取数据,这保证了数据的一致性。为此,请使用适合各种 SQL 的 Python 库。例如,要连接到 PostgreSQL 数据库,您可以使用 psycopg2 库。要建立连接:

con = psy.connect(host=<Database Address>,
                  user=<Username>,
                  password=<Password>,
                  dbname=<Database Name>)

一旦建立了连接,就可以使用熊猫:轻松获取数据

pd.read_sql('select * from tbl_vehicles', con)

5.探索性分析

一旦数据加载到内存中,熟悉它们是关键。应进行初步探索性分析,以了解数据集的粒度、可用的信息类型和目标变量。

通常要计算的统计数据是每个特征的*均值和标准差,以及突出显示特征分布的直方图。值的范围也是注意异常值的关键。获得最有用的统计数据的一个简单方法是使用:

vehicles.head()
vehicles.describe()

其中第一行给出了前 k 行,而第二行显示了数据的基本统计。

要显示感兴趣特征的分布,您可以使用熊猫。hist()函数:

casualties.Casualty_Severity.hist()

6.数据聚合

数据通常不是正确的格式。它可以是不适合任务的粒度,例如在“伤亡级别”而不是“车辆级别”,其中每一行对应一个伤亡。此外,它可以跨多个文件拆分,需要将多个数据集聚合在一起。

为了克服这些限制,我们可以,例如,简单地使用熊猫的 groupby 函数。在本例中,我们做到了:

casualties.groupby(['Accident_Index', 'Vehicle_Reference'])['Casualty_Severity'].min().reset_index()

这使得我们可以为每辆车只选择最严重的伤亡事故(得分最低),在“车辆级别”汇总这些信息。

7.数据清理

在我们熟悉数据集之后,我们可以开始构建生产管道本身。第一步是处理数据,清除错误和不一致。例如,日期应该在合理的范围内(例如,过去事件的日期不应该在未来),并且在日期功能中采用一致的格式(例如,我们不应该有一个“mm/dd/yyyy”格式的列和另一个“dd/mm/yyyy”格式的列)。

如果模型在预测一个未来的结果,比如下个月发生车祸的可能性,我们只能考虑所谓的“事前”信息。这些特征是目前已知的,即驾驶员的年龄、通常驾驶的汽车的发动机类型等。同时必须删除所有“事后”信息。这些包括诸如事故地点、天气状况等特征。直到要预测的事件发生后才知道。否则会让我们的模型“窥视未来”,使其无法预测结果。

8.特征工程

另一个关键步骤是特征工程。这一步包括从结构化格式的数据中提取信息。例如,我们可以通过从收集驾驶员数据的日期中减去出生日期来得出驾驶员的年龄。这一步可以帮助机器学习算法更好地识别数据中的信号。

8.1 处理分类特征

通常教授许多不同的技术来处理分类特征。此类特征的问题在于它们不是数字,因此无法计算量化指标,如数字和类别之间的距离。

对类别进行编码的一种常见方式是将它们映射到数字,只需将相同的数字分配给相同的类别。然而,这种方法是极其有害的,因为它创造了现实中并不存在的关系。例如,如果我们将['汽车','摩托车','自行车']编码成[1,2,3],我们基本上是在声明'自行车'是'汽车'的三倍,不管那是什么意思,或者两次'汽车'等于'摩托车'。

更好的方法是一键编码和目标编码。一键编码包括创建额外的二进制特征,每个类别的值一个,如果样本具有这样的值,则假设为 1,否则为 0。这可以通过以下方式实现:

pd.get_dummies(data[c])

相反,目标编码是用目标变量的*均值替换分类值的过程。这样做,我们基本上可以根据分类变量对目标变量的影响对它们进行排序。

9.分割培训、验证和测试

一旦我们有了一个包含相关特征的数据集,我们就可以把它分成训练集、验证集和测试集。通常情况下,训练和验证占 70%的数据,而测试是剩下的 30%。如果有足够的数据,测试集可以减少到 20%,因为样本的数量无论如何都足够多。这种分割通常是随机进行;然而,这个一般规则有几个例外。

第一,在分类问题中,我们经常使用分层抽样。如果少数类的频率明显低于其他类,这一点尤为重要。在这种情况下,如果我们随机选择一个拆分,我们可能会很不幸地没有选择训练集中少数类的任何样本,而是选择测试集中的所有样本,从而大大降低性能。

相反,当使用时态数据时,分割应该按顺序进行。特别地,训练数据应该是时间上排序的数据的最初 70%,而测试集应该是最*的部分。这阻止了模型“展望未来”。

10.归罪

只有分割数据集后,我们才能处理丢失的值。如果我们用所有的数据集来估算数据,从技术上来说,我们就是在作弊。我们将用来自测试集的信息填充训练集。正确的方法是仅用训练集拟合插补学习者,然后转换训练集和测试集。

有许多方法可以用来估算缺失数据。最著名的包括计算*均值、中间值或其他常量指标。然而,这些方法通常是要避免的。主要原因是它们完全改变了特征的分布,减少了方差,因为我们增加了多次常数项。此外,他们没有考虑功能之间的关系,一次只关注一个功能。

两个更好的解决方案是 MICE 和 KNN,前者适合一个分布,后者考虑用最接*的邻居来估算数据。为了选择 K 的参数,可以使用验证,使用肘方法,增加 K 的数量,直到验证集上的性能仅略微增加。

lnr = si.KNNImputer()lnr.fit(train_X)train_X = lnr.transform(train_X)
test_X = lnr.transform(test_X)

11.系统模型化

现在,你可以训练你的模型,但是..你应该选择哪一个?

这在很大程度上取决于我们要完成的任务、样本数量以及我们想要的互操作性水*。在医疗保健和金融等风险较高的领域,了解一个模型为什么会做出预测至关重要。如果模型没有如此强烈的含义,我们可以使用更复杂的黑盒算法,如神经网络。

一般来说,测试的模型应该在可解释性和性能方面有所不同。如果一个更简单的模型达到的性能几乎接*更复杂的模型,同时更容易理解,那么这个模型应该是首选的。

我通常使用的模型有:

  • 逻辑回归(或用于回归任务的线性回归)
  • 随机森林
  • XGBoost

为了调整此类模型的参数,我们通常执行网格搜索,测试所有参数组合以找到最佳组合。

12.性能赋值

为了评估模型的性能,我们可以使用各种度量标准,但是分类和回归任务有两个不同的集合:

对于回归,使用均方误差(MSE)、均方根误差(RMSE)和 R。其中,RMSE 和 R 通常是首选,因为 RMSE 的原始任务单位相同,而 MSE 的单位是*方。如果我们想预测投掷物体的距离,RMSE 会用米(或英里)来计算误差,而 MSE 会用*方米(或*方英里)来计算,这就失去了很多直觉。

对于分类,通常可以计算的指标是准确性、敏感性(或真阳性率)和特异性(或真阴性率)。另一个有用的度量是通过绘制不同阈值下的灵敏度和特异性,获得更全面的图,ROC 曲线(接收器操作特征曲线)。在这些度量中,准确性通常是最常用的度量之一,然而,当类严重不*衡时,它就变成了一个无意义的度量。为了解决这个问题,AUC,即 ROC 曲线下的面积,是通常首选的指标,因为它更可靠。AUC 从 0.5(随机选择)到 1(完全分类)。

13.部署

最后,一旦我们对模型的性能感到满意,并且无法实现进一步的改进,我们就可以继续进行最后的步骤。这些包括向利益相关者展示结果,强调性能、特性重要性等。以及在生产中部署模型。要做到这一点,我们可以利用 Amazon Web Services 或 Azure 等*台来托管该模型,并通过前端让最终用户可以使用该模型进行交互。

摘要

开发机器学习管道的过程涉及相同的一组步骤:

  1. 商业问题
  2. 翻译需求
  3. 数据收集
  4. 数据加载
  5. 探索性分析
  6. 数据聚合
  7. 数据清理
  8. 特征工程
  9. 分割培训、验证和测试
  10. 归罪
  11. 系统模型化
  12. 性能赋值
  13. 部署

要阅读更多类似的文章,请关注我的 Twitter LinkedIn或我的 网站

为数据科学家开发 Python 库

原文:https://towardsdatascience.com/developing-python-libraries-for-data-scientists-17dc28872f07?source=collection_archive---------52-----------------------

来源: Pexels (CC0)的 luis gomes

很大一部分数据科学家每天都使用 Jupyter 笔记本。如果你不熟悉 Jupyter 笔记本,你可能会问,为什么它们这么受数据科学家的欢迎?我对这个问题的回答是因为他们太棒了!Jupyter 笔记本允许交互式编程。有了这些笔记本,除了许多其他功能,您可以轻松地用 markdown 记录您的代码,轻松地查看单元格的输出,以及创建和查看数字。如果你以前从未使用过 Jupyter 笔记本,我强烈建议你尝试一下(这里是一篇很好的博客文章,讲述了 Jupyter 笔记本的一些其他酷功能)。这些笔记本是数据科学家和所有科学家的完美之选。它们允许我们轻松地试验创建新的模型,记录我们的试验,并轻松地调试代码。

尽管 Jupyter 笔记本是数据科学家通常用于实验和创建模型的工具,但实现数据科学项目的实际生产代码很少写在笔记本上。通常它们是用 Python 文件编写的(即。py 文件),当在生产环境中工作时,这是一个合理的选择。例如,历史上,Jupyter 笔记本存在一些版本控制问题。这很大程度上与渲染问题有关。一台计算机呈现 Jupyter 笔记本的方式在另一台计算机上可能不同,因此如果两个不同的开发人员在一台笔记本上工作,这可能会出现一些问题。此外,许多软件工程师不熟悉 Jupyter 笔记本电脑,因此在数据科学家和软件工程师的团队中,软件工程师不太可能想要参与和维护写在笔记本电脑中的生产代码(不是说没有例外!).但这真的很丢人!Jupyter 笔记本非常适合记录和讲述一个图书馆是如何发展的故事。我还发现在 Juptyer 笔记本上编码时,调试代码更容易,最重要的是实验!

不要害怕!随着 fast.ai 团队开发的名为 nbdev 的惊人 Python 库的发布,许多这些问题都得到了解决。最终,nbdev 的目标是允许在 Jupyter 笔记本中创建 Python 库。其工作方式是,在 Jupyter Notebook 中编写您希望包含在库中的代码,并在您希望包含在生产代码中的单元格中,在单元格顶部包含#export标记(如下图所示)。当您准备好导出库时,您只需在命令行中键入nbdev_build_lib,您的代码将被导出到 Python 文件中。很简单!

来自 nbdev 网站

再说一次,Jupyter 笔记本电脑的真正强大之处在于增强的文档功能。nbdev 不仅可以轻松地在笔记本上开发生产代码,还可以集成文档。Jupyter 笔记本允许使用 markdown,这使得讲述/记录代码甚至演示代码的特性变得很容易。例如,在上图中,有描述combined_cos函数的文档,甚至还有下面的示例值图。该代码不会被导出到生产代码中,而是保存在 Jupyter 笔记本中以供记录。这可以允许用户容易地理解功能。还有,文档可以转换成可以托管在 GitHub 页面上的网页,非常有用(如下图所示)!直接从源代码中提取代码文档的想法非常强大,我发现这是一个非常有用的特性。你再也不用担心库的文档是与源代码同步的,因为有了 nbdev,文档是直接从源代码中提取的。

来自 nbdev 网站

结论

如果你是数据科学家/软件工程师,给 nbdev 一个机会吧!fast.ai 团队有很棒的教程如果你想入门的话。我使用 nbdev 创建了一个异常检测库,这是一次很棒的体验——我也发现维护这个库很容易。nbdev 还有很多我没有在这里描述的其他特性(例如,导出到 pip,解决合并冲突),这些特性可以在教程和 nbdev 的文档中找到。祝您编码愉快,如果您在开发数据科学库方面需要帮助,请访问我的网站获取我的联系信息!

数据科学、迪士尼和 Tindering

原文:https://towardsdatascience.com/developing-successful-data-science-career-30b20a8892f6?source=collection_archive---------24-----------------------

与数据科学长期关系的 5 个事实

图片由俏皮话

TL;DL —谈恋爱很容易。持久的爱很难。在第一次约会并与数据科学建立长期关系之前,你应该知道以下 5 个事实。最后,您可以通过现场调查了解社区对数据科学的承诺程度。

免责声明 :所有观点均为本人观点。我交替使用“数据科学”、“机器学习”和“分析”。

喜欢读什么? 跟我上 LinkedIn,或者Twitter

外星人、火绒和爱情

我最*看到了俏皮话的一个娱乐性和挑衅性的视频。它探索了什么是真爱,以及现代夫妻之间的互动。这让我想起了我们与“数据科学”(或任何职业)的关系。

YouTube:里克和莫蒂谈爱情

如果你很忙,以下是要点:

  • 一个外星人做了一个类似 Tinder 的 app 这个应用程序让“爱”变得丰富。
  • 这太棒了。人们可以很容易地逃离糟糕的情况。
  • 但是,恶性循环从未打破。我们相爱,争吵,逃避,重复。
  • 在某一点上,每个人都累了,并问:我们为什么要这样做?什么是真正的爱情?我们如何维持良好的关系?

坠入爱河又失恋的故事

让我们将它与数据科学领域的职业生涯进行对比。

你对数据科学一见钟情是因为它太性感了——嗯,它是 21 世纪最性感的工作。谁不会得意忘形?所以,向右滑动。

吉菲

然后,你带着最好的西装、妆容或任何你想做的事情去约会。数据科学展示了所有奇妙的可能性和新奇的小玩意。事实上,数据科学非常喜欢你,并决定给你一个机会进一步探索事情。

接下来,你最终通过签署要约结婚(哎呀)。在迪斯尼电影中,这是灰姑娘和白马王子幸福生活的时刻。电影结束;幕布落下;人群欢呼鼓掌。

但是在现实中,白马王子变懒了(可能还变胖了)。灰姑娘变得脾气暴躁(并且可能满脸皱纹)。灰姑娘宝宝一直在哭。迷人国王生病了。魅力大叔引发内战。最后,王子像懦夫一样逃跑了。

吉菲

现在,你开始质疑数据科学是否适合你,并开始寻找新的工作。恶性循环开始。你爱上别的,受挫,寻找出路,重复。进入数据科学就像使用 Tinder 寻找关系一样。

那么,我们为什么不专注于寻找合适的人(例如数据科学职业)并维持良好的关系呢?

事实核查

我相信每个人都想要幸福、满足和健康的关系,无论是个人还是事业。建立这种关系的关键是理解并诚实面对现实。

这里有 5 个重要的(伪)事实可以帮助你做到这一点:

事实 1:数据科学使用最好的自拍滤镜。雇主希望尽可能好地描述数据科学角色。这可以理解。所以,问问他们每天都做些什么。不要被个人资料图片骗了。

事实 2:家务永远不会结束。“天下没有免费的午餐。”凡事都有代价。恋爱,关系好也不例外。注意那些为了享受数据科学的乐趣而不得不做的无聊事情

事实 3:家庭动态可能很复杂。许多数据科学团队试图向业务、工程和产品同行证明价值。这会导致紧张、困惑和沮丧。

事实四:狗狗很可爱;孩子可能很烦人。制作原型就像养狗一样。它需要更少的工作和温暖的心。相比之下,将 ML 部署到生产中就像有了孩子一样。这需要做更多的工作,而且当东西坏了的时候很烦人,尤其是在半夜。

事实 5:变化是唯一不变的。就像我们一样,数据科学也随着时间而变化。我们不知道未来 5 年、10 年它会变成什么样。接受和适应变化在一段关系中至关重要。保持学习和好奇心,否则就会落后。

认识、理解和接受这些事实是走向健康和可持续关系的重要一步。

斗牛中的最后一剑

那么,什么是真正的爱情呢?

“爱是最持久的建筑。真正的爱情是持久的,有时是痛苦的,战胜时间、空间和世界设置的障碍。”

法国哲学家阿兰·巴迪乌

那么,你对数据科学的热爱是真的吗?

喜欢读什么? 跟我上 LinkedIn,或者Twitter。你想学习如何沟通,成为一名有影响力的数据科学家吗?查看我的《* 用机器学习影响 》指南。*

这里有几篇你可能会喜欢的文章:

* [## 最有用的 ML 工具 2020

每个懒惰的全栈数据科学家都应该使用的 5 套工具

towardsdatascience.com](/the-most-useful-ml-tools-2020-e41b54061c58) [## 被遗忘的算法

用 Streamlit 探索蒙特卡罗模拟

towardsdatascience.com](/how-to-design-monte-carlo-simulation-138e9214910a) [## 数据科学很无聊

我如何应对部署机器学习的无聊日子

towardsdatascience.com](/data-science-is-boring-1d43473e353e) [## ML 和敏捷注定的联姻

如何不对 ML 项目应用敏捷

towardsdatascience.com](/a-doomed-marriage-of-ml-and-agile-b91b95b37e35) [## 人工智能的最后一英里问题

如何培养人类和人工智能之间的信任

towardsdatascience.com](/fixing-the-last-mile-problems-of-deploying-ai-systems-in-the-real-world-4f1aab0ea10) [## 又一个 AI 冬天?

如何部署更多的 ML 解决方案——五种策略

towardsdatascience.com](/the-last-defense-against-another-ai-winter-c589b48c561)*

发展对机器学习模型预测的信任

原文:https://towardsdatascience.com/developing-trust-in-machine-learning-models-predictions-e49b0064abab?source=collection_archive---------38-----------------------

使用 LIME 解释和说明机器学习模型做出的预测

肖恩·梅因斯在 Unsplash 上拍摄的照片

如果我告诉你今天投资 10 万美元在一只特定的股票上,因为我的机器学习模型预测会有高回报。你会问我的问题将是解释我的预测的基础,因为这对你来说是一个重大的决定。你不想赌博,但想根据数据做出明智的决策。

为了信任机器学习模型的预测,你会问以下问题。

  • 模型是如何做出预测的?
  • 为什么模型会对特定的实例做出特定的预测?
  • 哪些特征对预测的影响最大,哪些影响最小,并给出一个易于理解的解释。
  • 模型的解释应该呈现特征和模型预测之间的文本或视觉定性关系。

在这篇文章中,你将学习使用 LIME 来解释机器学习模型的预测,并解释对做出预测贡献最大的特征。

有几种解释机器学习模型的技术,但这里我们将讨论 LIME(局部可解释模型-不可知论者解释)。

什么是石灰?

LIME 是机器学习模型的局部可解释模型不可知解释,它让你理解个体预测,

  • LIME 可以解释机器学习模型的单个预测,而不是解释整个数据集。
  • 它是局部忠实的,并且具有局部保真性,这意味着全球基本特征在局部环境中可能不那么重要,反之亦然。它通过用一个可解释的模型对其进行局部*似来做到这一点。
  • 它是模型不可知的,可以应用于分类器以及基于回归的机器学习算法。

石灰是怎么起作用的?

LIME 扰动输入数据集以查看预测中的变化。这些扰动是基于数据的方差。

  • 创建一个可解释的表示,该表示根据输入数据的小扰动进行训练,这提供了一个用于解释个体预测的良好的局部*似。
  • 它在可解释表示数据 和原始数据之间创建相似性分数,以了解它们有多相似
  • 使用可解释制图表达数据集上的模型进行预测。
  • 在可解释的表示数据集上尝试不同的组合,以找到最大可能匹配模型在原始数据集上所做预测的最小要素集
  • 确定的最小特征集给出了原始数据的大部分信息以及相似性得分,用于解释个体预测。

有哪些不同的机器学习模型可以用到 LIME?

LIME 与模型无关,可以用于

  • 分类以及回归问题。
  • 它可以使用 NLP 在文本数据上使用。
  • 可应用于图像数据
  • LIME 也可以应用于表格数据,其中列代表特征,行是单独的实例。

如何将 LIME 应用于基于分类的机器学习模型?

石灰在使用表格数据的分类模型中的应用

使用的数据集是默认信用卡客户数据集

对于分类问题,值 1 意味着客户将拖欠付款,值 0 表示客户不会拖欠信用卡付款。

加载数据并显示列名

**import pandas as pd
import numpy as np
np.random.seed(0)
df = pd.read_csv(r'c:\data\default of credit card clients.csv')
df.columns**

创建特征和目标变量

**Y = df[['default payment next month']]**
**X =  df[['LIMIT_BAL', 'SEX', 'EDUCATION', 'MARRIAGE', 'AGE', 'PAY_0', 'PAY_2', 'PAY_3', 'PAY_4', 'PAY_5', 'PAY_6', 'BILL_AMT1', 'BILL_AMT2','BILL_AMT3', 'BILL_AMT4', 'BILL_AMT5', 'BILL_AMT6', 'PAY_AMT1', 'PAY_AMT2', 'PAY_AMT3', 'PAY_AMT4', 'PAY_AMT5', 'PAY_AMT6']]**

将数据集分成训练和测试

**from sklearn.model_selection import train_test_split
from sklearn import preprocessing****X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.4)**

创建随机森林分类器并拟合训练数据

**from sklearn.ensemble import RandomForestClassifier**
**model = RandomForestClassifier(max_depth=6, random_state=0, n_estimators=10)
model.fit(X_train, Y_train)**

显示特征重要性

**importances = model.feature_importances_
indices = np.argsort(importances)****features = X_train.columns
plt.title('Feature Importances')
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Importance')
plt.show()**

创建石灰表格实例

因为我们的数据集是表格形式的,所以我们创建了 LimeTabularExplainer()的一个实例。 training_data :通过训练数据集,

模式:可以是回归分类。我们正在处理一个分类问题,所以我们将模式参数设置为“分类”

feature_names :数据集中的所有输入特征,用于计算每个特征的统计数据。*均值,计算数值特征的标准偏差,而分类特征被离散化为四分位数。

训练 _ 标签:传递训练目标变量

**import lime
from lime.lime_tabular import LimeTabularExplainer****explainer= LimeTabularExplainer(*training_data*=np.array(X_train),
                                *mode*='classification', 
                                *feature_names*=list(X_train.columns),
                                *training_labels*=np.array(Y_train),
                                *random_state*=12**

使用从训练数据生成的计算统计

  1. 创建扰动的样本实例,这是一个可解释的表示数据集。
  2. 当属性不在同一标度上时,缩放数据以计算相似性得分的距离

为预测生成解释

现在,您可以通过将观察结果传递给 explain_instance() 来为特定的观察结果生成解释

data_row: 指定需要解释的观察结果

classifier_fn: 需要为分类模型指定模型预测概率,采用 numpy 数组,输出预测概率。对于回归模型,我们可以指定模型预测。

num_features :我们需要解释的最大特征数

**exp = explainer.explain_instance(X_test.iloc[0], model.predict_proba, num_features=8)****exp.as_pyplot_figure()
from matplotlib import pyplot as plt
plt.tight_layout()**

在 python 笔记本中显示 HTML 解释

**exp.show_in_notebook(show_table=True, show_all=True)**

如何解读结果?

对于观察,概率预测是 87%,即客户不会拖欠信用卡付款。

客户未拖欠信用卡付款的原因

客户没有拖欠本月、2 月、3 月、4 月、5 月和 6 月的任何付款(PAY_0、PAY_2、PAY_3、PAY_4、PAY_5 和 PAY_6 为 0)。最*三个月的付款少于 1800 美元

让我们来看另一个观察的解释。

**exp = explainer.explain_instance(X_test.iloc[731], model.predict_proba)
exp.show_in_notebook(show_table=True, show_all=False)**

对于观察,概率预测是 75%,客户将拖欠信用卡付款。

客户拖欠信用卡付款的原因

客户将本月、2 月、3 月、4 月、5 月和 6 月的付款延迟了两个月(PAY_0、PAY_2、PAY_3、PAY_4、PAY_5 和 PAY_6 为 2)。消费信贷少于或等于 500 美元。

基于回归的机器学习模型如何应用 LIME?

LIME 在使用表格数据的回归模型中的应用

使用的数据集是房地产价格预测 n。

这里我们将使用 RandomForestRegressor

#Importing required libraries
**import pandas as pd
import numpy as np
import plotly
np.random.seed(0)
import matplotlib.pyplot as plt
import lime
from lime.lime_tabular import LimeTabularExplainer
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.ensemble import RandomForestRegressor**#Reading the data file
**df = pd.read_csv(r'c:\data\Real estate.csv')**# Creating the input features and target variable
**Y = df[['Y house price of unit area']]
X =  df[[ 'X2 house age',
       'X3 distance to the nearest MRT station',
       'X4 number of convenience stores', 'X5 latitude', 'X6 longitude']]**# check for missing data
**X.isnull().sum()**#Creating train and test data
**X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.2)**#Random Forest Regressor
**model = RandomForestRegressor(max_depth=50, random_state=0, n_estimators=1000, bootstrap=True)
model.fit(X_train, Y_train)**#printing feature importances
**importances = model.feature_importances_
indices = np.argsort(importances)
features = X_train.columns**
**plt.title('Feature Importances')
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Importance')
plt.show()**

创建一个石灰表格实例

将模式指定为回归

**explainer= LimeTabularExplainer(training_data=np.array(X_train),
                                mode='regression', 
                                feature_names=list(X_train.columns),
                                class_names=['Y house price of unit area'],
                                random_state=12
                                         )**

为预测生成解释

**exp = explainer.explain_instance(X_test.iloc[0], model.predict, num_features=4)****exp.as_pyplot_figure()
from matplotlib import pyplot as plt
plt.tight_layout()**

**exp.show_in_notebook(show_table=True, show_all=False)**

结论

LIME 是一种模型不可知的机器学习技术,用于以人类可理解的格式解释基于分类或回归的模型的预测。LIME 为一次观察提供当地的解释。它最适用于表格数据、图像和文本。

参考资料:

我为什么要相信你?解释任何分类器的预测

https://github.com/marcotcr/lime

直观地学习数据结构

原文:https://towardsdatascience.com/developing-visual-intuition-in-computer-science-7efb62f81c49?source=collection_archive---------35-----------------------

发展视觉直觉以理解复杂数据结构的艺术。

天一马Unsplash 上拍照

作为一名经历了大学经历考验和磨难的计算机科学本科生,我遇到过的最被滥用的术语之一是直觉。从第一次打开终端,我的教授向我保证,有一种内在的理解会冲刷我。这种直觉是慢慢产生的,但通常不是来自讲课或残酷的考试。它来自于缓慢地完成家庭作业和项目,试图理解我面前的这个金属大块头是如何解释我在键盘上疯狂键入的希腊语的。然而,随着我成为一名程序员,我开始看到现实世界中与数字世界直接相关的模式和寓言,这极大地帮助了我的理解。

本质上,计算机科学只不过是试图让一块石头以你的方式思考,让一个无生命的物体以与程序员看待世界的方式相似的方式感知世界。因此,在一种悖论中,计算机让用户重新分析他们自己看待世界的方式,将他们的感觉分解为处理器可以理解的基本构件。所以,我的教授们所说的这种直觉不是一种编程:学习计算机如何思考,而是理解程序员如何思考,将复杂的感知分解成计算机可以概念化的比特大小的积木。我清楚地记得,当我意识到这一点的时候——我正在学习一种叫做链表的数据结构。

我能找到的最简洁的链表定义是:

“链表是一种线性数据结构,其中的元素不是存储在连续的内存位置上”(GeeksforGeeks.com:链表数据结构)

这个定义虽然在技术意义上是描述性的,但它很少告诉我们这个结构的物理表示,所以当我们继续阅读时,我们看到了一幅图:

链表图片||来源:https://www.geeksforgeeks.org/data-structures/linked-list/

现在,有了这张图片,我们对这个数据结构有了更多的了解。似乎有一个开始()和一个结束(),中间有一些节点。存储数据的节点都指向另一个节点,它们之间存在单向关系,每个节点都知道哪个节点跟在后面。现在,根据现代学术界的观点,我们应该准备好实现和使用这种数据结构来达到我们想要的任何目的,对吗?嗯,它比这个稍微复杂一点,在我们进入这个数据结构的内部之前,有一个直觉需要开发。我们如何从这个结构中获取一条信息?我们怎么把一个放进去?回顾一下之前的观点,我们不应该考虑计算机如何完成这项任务,而应该考虑在人类世界中我们会如何看待这一点。因此,为了开发这个模型,我们现在将开始一段小学时期最美好的回忆之旅。

当我还是个孩子的时候,这个简单的玩具到处都是,这可能是为什么很多年后我重温它来帮助我理解复杂的数据结构。

童年回忆||作者图片

现在,想象一下,我们让一个孩子从堆栈中取出深蓝色的戒指。只有一种方法可以做到这一点,所以我们观察孩子首先从顶部拿起紫色的环,然后是每个连续的环,直到最后深蓝色的环被抽出。太好了!!!这和计算机科学又有什么关系呢?好吧,我们可以把这个游戏重新设计成一个链表的实现,我们会看到这两者是怎么一回事。

问题的重铸版||作者图片

正如我们所看到的,这是以新的视角展示的上图,顶部的紫色环作为头部,每个连续的环作为一个节点,而结构的蓝绿色底部作为空。这个模型保持了链表的单向性吗?除非孩子在其中一个环上咬出一个洞,那么是的。结构有头有尾吗?没错。有什么环看起来是重叠的吗?不,满足连续内存位。因此,有了这个模型,我们可以很容易地看到如何从系统中可视化地提取数据。假设我们想要在红色环中存储一条信息。首先,我们将取下紫色的顶部()并继续下去,直到堆栈的顶部是红色的环。当我们把它拿掉,我们现在有了我们正在寻找的数据。

去掉头像后||作者图片

为了用伪代码实现这个动作序列,我们需要假设孩子一次至少可以看两个环。他们可以查看他们当前持有的戒指,即,以及堆叠中的下一枚戒指,即。因此,当孩子将拉出堆栈时,当前的现在位于新的顶部,因此它成为,它下面的环成为新的。因此,要在代码中实现这一点,我们可以说:

直到深蓝色的环是头部,继续移除环:因此将顶部的环重新分配给头部。

在伪代码中:

*while head != dark blue:           
    head = tail
return head*

正如我们所看到的,我们已经开发了一个现实世界的寓言来描述这个抽象的概念,一个视觉直觉来描述可以应用于计算机科学中许多概念的系统。

为 Hadoop 访问控制设计一个联合代理

原文:https://towardsdatascience.com/devising-a-federation-broker-for-hadoop-access-control-f9e24ab7648a?source=collection_archive---------61-----------------------

理解联邦方法中的数据授权以获得更好的安全性。

作者图片

你是数码守望者的粉丝吗?想想一个人工智能系统,可以处理海量数据,阻止城市犯罪?是的,你猜对了, POI相关人员是一个强有力的例子,说明数据可能比诺克斯堡的所有黄金都值钱(如果真的有黄金存在,而美国政府一直否认这一点)!

Hadoop 是最强大的数据处理开源框架之一。但是,它存在安全问题,我们将通过联合访问代理来减少这一问题。在我们开始探索 Hadoop 访问控制的新框架之前,让我们先了解一下 Hadoop 框架。

Hadoop 是什么?

Hadoop 是由 Apache 开发的开源框架。它基于数据聚类和并行处理。不可否认的事实是,一个大型开源社区一直在支持 Hadoop 在大数据应用程序中的存在。他们为创建更强大的企业级数据应用程序堆栈做出了贡献。

存储和处理大量数据的能力对于更大规模地接受 Hadoop 至关重要。Hadoop 擅长结构化和非结构化数据的计算资源管理。但是,这种现代数据架构存在一些挑战,尤其是在数据安全性方面。

为了了解安全挑战,让我们来了解一下 Hadoop 在 BigData 中的应用。

Hadoop 是如何运作的?

我们知道 Hadoop 是基于并行处理和分布式计算机制而设计的。该*台提供了 Hadoop 分布式文件系统或 HDFS。HDFS 支持硬件商品和不同处理框架的容纳。

IAM 或 HDFS 身份认证管理系统用于定义一组协议,帮助最终用户通过应用程序访问数据。这些协议集被称为 API 或应用程序编程接口,这些接口可以由企业开发用于数据访问。

Hadoop 联盟

随着数据集群的增加,Hadoop 框架面临着很大的压力。为了解决这个问题,它引入了两个联盟

  • HDFS 联邦
  • 纱线联盟

HDFS 联盟使用多个命名节点。这些 NameNodes 是独立的,管理整个名称空间的子集。这里,NameNodes 维护名为名称空间的文件系统。他们通过名称分组来维护文件的层次结构。树状文件结构在一个名为名称空间的容器中进行管理。

任何 HDFS 系统都由两层组成。

图片: HDFS 联邦系统(下一代大数据联邦访问控制:参考模型

第 1 层:NameNodes 中的名称空间控制着与目录、文件和块相关的数据的存储。

第 2 层:它是支持低级操作的块存储,有两个部分——数据的块管理和物理存储。

通过添加水* DataNodes,可以轻松扩展物理存储,这与 NameNodes 不同。扩展 NameNodes 有一个限制,因为它只能垂直进行,由于单节点架构,这很难做到。但是,有了 HDFS 联邦,NameNodes 的名称空间层可以水*扩展。

HDFS 建筑

图片: HDFS 架构(下一代大数据联邦访问控制:参考模型)

它有一个架构来提高大数据存储和访问管理的效率。HDFS 结构有两个主要组成部分。

  • 将单个节点 NameNode 作为主节点
  • 在集群从属服务器上运行的几个 DataNodes。

命名节点运行命名空间层来管理与文件系统相关的数据。它管理对文件的访问,并使用分级系统。它还跟踪块的位置,并维护日志文件,以便在必要时进行审计。这些文件在内部被分成多个块。块被放置在存储在本地存储磁盘中的数据节点中。

HDFS 的出入控制

如果一个客户想要访问存储在 HDFS 系统中的任何数据,就会发出一个调用。在收到调用后,HDFS 使用 NameNodes 来提供对存储在本地磁盘的 DataNodes 中的数据的访问。

数据一旦写入,没有高级 IAM 协议就无法编辑。没有适当的协议,HDFS 不允许对客户端的任何其他访问。因此,所提供的访问是一次写入多次读取。

在这里,HDFS 建筑提出了几个挑战。

  • 客户端需要获得多级权限才能访问数据。
  • 重新认证任务需要取消原始会话,从而造成更多的时间浪费。
  • 由于成千上万的节点到节点的交互,通信的复杂性增加了。
  • 节点之间缺乏端到端的数据加密可能会威胁到数据安全。
  • 为了有效管理,节点编排必须在令牌时间内完成。
  • 安全审计需要广泛且难以执行。
  • 由于几个 NNs 集群,日志信息审计变得很困难。

HDFS 联邦接入代理

联合经纪人并不新鲜。许多企业使用这种解决方案进行数据访问控制。这种体系结构引入了一个中间层,它将客户端的流量重定向到代理服务器或网关进行身份验证。访问代理是基于云的系统或内部数据中心的授权执行点。

图片:HDFS 联邦代理系统(下一代大数据联邦访问控制:参考模型

这里,我们发现了一个联邦访问代理,它可以抽象远程访问调用的管理。这些调用通常是客户端为了数据访问而对 Hadoop 联合服务进行的。

该架构执行两个基本功能。

  1. Apache Knox 网关用于客户端识别和集群访问控制。
  2. 执行管理员授权分配。

在这里,客户端需要在 Knox 网关得到认证。接下来,这个用于身份验证的 ClientID 被传递给 Ranger,以验证对 NNs 的访问。验证客户端调用后,将建立一个安全会话。

如果 Ranger 授权成功,它将提供访问 NNs 的证书。它将为客户端分配与每个 NameNode 交互的权限。NN 将通过分配给特定 NameNode 的 DataNodes 执行数据访问。

每次尝试访问 DataNodes 进行数据访问时,都会创建审计日志。这些日志存储在一个集中的 HDFS 存储中,以降低跨集群分布审计日志的复杂性。

结论:

我们发现使用联合代理可以降低 Hadoop 框架中安全性和客户端认证的复杂性。由于世界各地的企业都在大力投资数据聚合和存储,因此需要像 Hadoop 这样高效的框架。但是,由于它使用数据集群和并行处理,人们已经感受到了联合的需要。

开源框架已经见证了联邦框架的兴起,但是还有一些问题需要解决。联合代理增加了额外的身份验证层,创建了更加严格的数据安全性。它还简化了对数据的访问,而不需要太多的验证时间。因为抽象层有两个不同的授权和验证网关来快速推进流程。

这种数据访问是通过协议实现的。企业可以使用应用程序编程接口在联邦层之前创建数据访问协议。那么,你愿意冒数据被盗的风险吗?或者创建安全的数据访问、验证和存储协议。

联系我们 立即获取 API 开发解决方案并创建安全协议!

面向数据科学的开发运维:让您的 Python 项目具有可重复性

原文:https://towardsdatascience.com/devops-for-data-science-making-your-python-project-reproducible-f55646e110fa?source=collection_archive---------16-----------------------

从依赖地狱中拯救你的朋友

在亚马逊担任软件工程师的第一年年末,我的经理给我上了宝贵的一课。提高团队的效率和我个人的贡献一样重要。

我把这一课带到了位于impossible的建模团队,在那里,当我们处理大规模模拟项目时,我专注于最大化科学家的生产力。这些经历现在让我倡导我们一起努力解决一个我经历了*十年的问题。

问题是

现在是 2013 年,我是 Python 开发的新手,正在玩一些自然语言处理代码。根据电子邮件的内容推断人们的态度(感谢安然)。当时对我来说这就像科幻小说。

不幸的是,这在一段时间内仍然是科幻的,因为我花了 4 天时间让作者的代码运行起来。缺少系统库,相互冲突的依赖关系,未知的 Python 版本。在接下来的 7 年里,软件工程取得了很大的进步,但是这个问题仍然存在。为什么运行对方的代码这么难?

一些历史背景

Python 包管理有着悠久而丰富多彩的历史,这是我从未想过会写的一句话。 开源应用的架构 描述了社区从一个打包系统到下一个打包系统的几次迁移。经过多年的迭代,我们已经有了几种安装 Python 代码的主流方式和两种不同的主要包索引。每个 Python 开发人员都需要投入一些时间来学习它们,以确保他们的工作可供他人使用。

强制 XKCD(https://xkcd.com/1987/)

本指南

实现一般意义上的可再现性真的很难——数据版本控制、确定性保证等等。本指南只解决依赖管理问题。每个 Python 开发人员都有可能确保他们的代码可以安装在他们同事的机器上。我的目标是帮助传授必要的“devops”知识,这样你就可以改变你的工作的成熟度。

默认情况下,您的项目代码与安装在您笔记本电脑上的所有东西交织在一起。尽管在依赖配置方面做了一些努力,但它是一个自包含的产品,将在开源生态系统中蓬勃发展。

在项目的早期进行组织是关键。它留给您维护您的环境的更简单的任务,以便您的工作是一种乐趣,构建,部署和发布!

可复制的项目对合作者更有吸引力,迭代更快,并且可移植。这对于自动化测试、分析和在像活页夹这样的服务上分享你的工作是非常棒的。

关于 Devops 的一个注记

本指南不是关于编写代码的,而是关于一旦编写好代码,有效地使用它所必需的活动。在传统的软件开发中,“操作”不是开发者关心的问题。然而,在过去的 15 年中,角色已经合并(因此是开发人员操作),因为改进的工具允许个人编写和运行他们的代码。学习操作技能让你产生影响!

库与应用

把你的作品交到人们手中是不同的,这取决于你是在制作一个库还是应用程序。如果您正在构建库,那么您可能已经了解了许多依赖项管理的机制,以及如何通过 Pypi 或 conda 通道使您的工作可用。

另一方面,可能在 Jupyter 笔记本中分析数据、创建 CLI 工具或构建仪表板的应用程序构建者是从重新思考依赖性管理中获益最多的人。

你的代码只是冰山一角

我想挑战简单地分享你的代码就意味着你的分析是可重复的这一观点。您的代码实际上是冰山的一角,为了让它在新的环境中运行,需要一系列工具来重建冰山。

你的项目不仅仅是你的代码。它几乎肯定需要外部包,其中一些可能具有特定的本机依赖性(专门为某个操作系统构建的二进制文件),并且可能需要特殊的硬件。目标是以编程方式尽可能多地指定这些内容。(图片由作者提供)

假设您已经将您的 repo 上传到 GitHub,我们如何确保其他人可以复制您的项目环境的下一个级别 Python 包?这就需要选择一个包管理器并创建一个依赖文件。

软件包管理架构入门

你无疑对包管理器客户端比较熟悉:pip installconda activate等。但这只是这个系统的一部分。

包管理器从存放数百万不同社区提交的项目的存储库中定位并获取必要的依赖项。(图片由作者提供)

每个包管理器客户端在您的本地设备上都有配置,告诉它当前项目需要什么(例如 matplotlib v3.2.1,python 3.8+),应该检查哪些包索引,等等。

使用配置,客户端调用一个或多个包索引来解析哪些文件需要下载到您的系统上,然后从可能不同的包存储中下载这些文件。

现在我们已经描述了用于重现项目依赖关系的不同组件,我们可以评估主要的包管理器客户端选项。

选择您的软件包管理器

我将只讨论 pip、pipenv 和 conda,因为它们将涵盖您的几乎所有用例。我发现自己出于不同的原因经常使用这三种方法,如果你喜欢冒险,还有更多的方法。

1.Pip (+ Virtualenv)

✅ 安装速度快
✅简单配置文件
❌不锁定可传递依赖关系
❌ 必须组合两个独立的 CLI 工具
❌不能锁定 Python 版本
ℹ️使用纯文本配置requirements.txt

Pip 是默认的 Python 包管理客户端,它是随 Python 自动安装的。Virtualenv 允许您用自己的 Python 二进制文件和依赖项为项目创建一个独立的目录。

➜ which python
/usr/local/anaconda3/bin/python # my system python~/Desktop/cfg
➜ virtualenv venv # create the virtualenv
...
~/Desktop/cfg
➜ . venv/bin/activate # activate it.➜ which python # $PATH has changed!
/Users/alexremedios/Desktop/cfg/venv/bin/python~/Desktop/cfg
➜ ls -la venv # take a look inside
total 8
drwxr-xr-x  21 alexremedios  staff   672B 26 May 12:01 bin
drwxr-xr-x   3 alexremedios  staff    96B 26 May 12:01 lib
-rw-r--r--   1 alexremedios  staff   265B 26 May 12:01 pyvenv.cfg

venv/bin包含您的 Python 解释器副本和用于激活虚拟环境的脚本。venv/lib包含site-packages,在那里pip install放置您的 Python 依赖项。

Pip + Virtualenv 让您可以使用不同的 Python 版本和依赖项在一台机器上运行多个 repos。

⚠️没有 virtualenv,Pip 写入您的全局站点包目录,这可能会导致混乱和冲突。
ℹ️您可以使用which找到当前 python 环境的站点包目录

~/Desktop/cfg
➜ which python
/usr/local/anaconda3/bin/python~/Desktop/cfg
➜ ls -la /usr/local/anaconda3/lib/python3.7/site-packages

现在 Pip + Virtualenv 感觉有点低级,但是对于在你的笔记本电脑上有多个项目污染你的全球包环境的问题,这是最简单的可能的解决方案。

如何导出 pip 环境…正确的方法

我推荐手动编写你的 requirements.txt,你大概没有超过 10 个直接需求,文件格式超级简单。手动编写文件还会鼓励您留意项目所依赖的内容。

# requirements.txt, doesn't have to be complex
matplotlib>=3.2
numpy
pandas

创建 requirements.txt 的另一种方法是冻结您当前的环境:pip freeze > requirements.txt但是您应该在创建文件之后减少以下缺点。

⚠️ ❄️ 1.传递依赖将变成直接依赖

您可能想知道为什么您只安装了两个包,而现在您的 requirements.txt 中有 50 个包,这是因为 pip freeze 不知道您直接需要的包和子依赖包之间的区别。

# pip freeze > requirements.txt results in the whole transitive closure being treated as direct dependencies
…
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.4
spinners==0.0.23
SQLAlchemy==1.3.15
streamlit==0.56.0
tenacity==6.0.0
termcolor==1.1.0
terminado==0.8.3
testpath==0.4.4
textwrap3==0.9.2
timeago==1.0.13
toml==0.10.0
toolz==0.10.0
toposort==1.5
tornado==6.0.3
tqdm==4.42.1
traitlets==4.3.3
…

这是不好的,因为当你想删除一个依赖项时,你必须手动识别并删除所有的子依赖项。或者,你的 Python 环境将会有很多不需要的依赖,这会导致依赖地狱

⚠️ ❄️ 2.版本将被过度固定

版本锁定是指您确切地指定您的项目应该使用哪个版本的依赖项,如上所示(例如tornado==6.0.3)。虽然能够保证其他人将与您的项目安装相同的包版本是有用的,但是将每个依赖项都固定在 requirements.txt 中并不是最好的解决方案,原因有三。

第一个原因是您必须通过更改固定版本来手动更新每个包。您的依赖项的次要版本更新包含错误修复和其他改进。定期更新依赖关系对于防止代码腐烂很有用。

第二个原因是,当你添加一个新的需求时,它更有可能导致冲突。例如,当您只需要jupyter-client==6.*时依赖jupyter-client==6.0.0会导致不必要的冲突,如果您随后安装依赖jupyter-client>=6.1.0nbconvert

ERROR: nbclient 0.3.1 has requirement jupyter-client>=6.1.0, but you'll have jupyter-client 6.0.0 which is incompatible.

不固定所有需求的最后一个原因是,如果其他人遇到上述问题,他们会对使用您的代码感到困惑。他们如何知道您的代码是否真的需要需求的特定版本?

也就是说,您应该只在必要的时候将版本固定在特定的依赖项上。在这种情况下,最好留下评论。

如果您想获得锁定所有依赖项版本的好处而没有这些问题,那么 Pipenv 是您的最佳选择。

2)管道

👍推荐,除非你需要大量的科学库
✅锁定传递依赖
✅锁定 Python 版本
✅ CLI 工具自动创建依赖配置
❌锁定传递依赖可能很慢
ℹ️使用 TOML 格式的Pipfile和 JSON 格式的Pipfile.lock进行配置

Pipenv 就像包装在命令行工具中的 pip + virtualenv,它也锁定了可传递的依赖关系。

什么是锁定?

锁定将您的一般需求锁定在整个传递闭包的精确版本上。例如,如果你说你需要matplotlib==3.2,那么加锁会让你说你最后一次运行代码使用了matplotlib==3.2.1 +所使用的子依赖的确切版本

前面我说过版本锁定是不好的,但是 pipenv 的锁定足够智能,可以给你版本锁定的好处,而没有脆弱性。

Pipfile 和 Pipfile.lock

Pipfile 类似于 requirements.txt,它是人类可读的,并且指定了您的直接 Python 包依赖项+您的 Python 版本(不同于 requirements.txt)。

您通常不需要直接编辑它们,因为 pipenv CLI 工具会在您pipenv install something时为您管理它们。

# Pipfile is a TOML formatted description of your project runtime and direct dependencies.[[source]]
name = "pypi"
url = "[https://pypi.org/simple](https://pypi.org/simple)"
verify_ssl = true

[dev-packages]
pylint = "*"
autopep8 = "*"
pipenv = "*"
pytest = "*"
python-magic = "*"

[packages]
treebeard = {editable = true,path = "."}

[requires]
python_version = "3.7"

[pipenv]
allow_prereleases = true

每次 Pipfile 发生变化时,都会重新生成锁定文件。它描述了你的项目的传递闭包,即当前安装的所有依赖项(不仅仅是直接依赖项)。Pipfile.lock 非常适合部署您的工作:它准确地描述了要安装哪些包,考虑到有些包只在特定的操作系统上需要。

// Pipfile.lock is a JSON formatted description of your project's transitive closure, programmatically derived from your Pipfile
...
"appnope": {
   "hashes": [
       "sha256:5b26757dc6f79...",
       "sha256:8b995ffe925347a2138d7..."
   ],
   "markers": "platform_system == 'Darwin'",
   "version": "==0.1.0"
},
...

注意:Pipenv 的一个快速发展的替代品是诗歌

3)康达

👍推荐用于大型数据科学或机器学习项目
✅更好地支持原生依赖关系
✅锁定 Python 版本
✅默认安装包含有用的数据科学包
❌由于solving environment
❌不锁定可传递依赖关系
ℹ️使用 YAML 格式配置environment.yml

Conda 是三个包管理器中最强大的,因为它支持用任何语言编写的包,但是比 pip + virtualenv 慢一个数量级。

处理本机依赖关系

Conda 被设计成在比 pip 更低的层次上工作——使用二进制文件而不是 Python 包。这有几个很好的特性:

首先,这意味着 Python 和 Pip 只是 conda 包。您可以将它们安装在 conda 环境中,并像使用 Pip + virtualenv 一样使用 Pip + conda。也就是说,如果您已经处于 conda 环境中,则不需要 virtualenv。

第二,conda 的通用性意味着依赖于非 Python 包的 Python 包往往会工作得更好。

例子:安装 cartopy(一个通用的映射库) Cartopy 可能很难运行。它是一个 Python 库,可以通过 Pypi 安装,但是 Pypi 包通常不包含它们运行所需的所有本机依赖项。

因此,您可能需要安装带有 pip 的 Python 代码

➜ pip install cartopy

然后用您*台特定的包管理器来填充缺失的库,例如brewyumapt-get

brew install proj

Conda 不在乎 cartopy 是用 python 写的,但 proj 是用 C++写的,它照样安装它们。

会照顾好一切。

conda 的这个特性对于经常依赖于这些原生依赖项的科学用例来说非常有用。

康达频道和康达锻造

因为 conda 能够管理本机依赖项,所以它有一个不同于 Pypi 的包结构。因此,您可以从 conda 通道安装 conda 软件包。

包的默认来源渠道是https://anaconda.org/anaconda,类似于https://pypi.org/是 pip 的默认渠道。

然而,与 pip 不同的是,有一些非默认的频道包含许多您需要的软件包,例如康达锻造频道(https://anaconda.org/conda-forge)。

Conda 包名称

Pypi、anaconda、conda forge 和其他通道都有自己的名称空间。这意味着这是可能的,但是不能保证一个公共包在每个源中都有相同的名字。

⚠️🐍不要假设 requirements.txt 可以粘贴到 environment.yml 而不改变一些包名(除非您将它们粘贴到pip:部分)。

为您的 conda 环境创建 environment.yml

与 pip 类似,我建议手动维护您的环境。yml,但是如果事情已经远离您:

➜ **conda env export --from-history --no-builds** # ✅ good
name: base
channels:
  - conda-forge
  - defaults
dependencies:
  - conda
  - python
  - conda-env
# Note! Conda does not know about anything you have pip installed, you will have to manually add them:
  - pip:
    - tensorflow

**—-no-builds**标志防止包含特定于*台的构建 id。如果没有这个标志,你将会遇到像ResolvePackageNotFound这样的问题,即使是存在于每个*台上的依赖关系。

举例:OpenSSL openssl=1.1.1d存在于每个*台,openssl=1.1.1d=h0b31af3_0只存在于 OS X 上自己看

**--from-history**是在 Conda 4.7.12 中引入的,因此您可能需要更新 Conda。如果你花了一段时间让某个东西工作起来,却忘记记下你安装了什么,那么这个标志非常有用。Conda 将只导出您使用conda install明确安装的包和版本。

⚠️ ❄️如果你不使用这些标志,你会遇到与pip freeze相同的问题

➜ **conda env export** # ❌ bad, has transitive dependencies with pinned versionsname: blah
channels:
  - conda-forge
  - defaults
dependencies:
  - ca-certificates=2019.11.28=hecc5488_0
  - certifi=2019.11.28=py37_0
  - libcxx=9.0.1=1
  - libffi=3.2.1=h6de7cb9_1006
  - ncurses=6.1=h0a44026_1002
  - openssl=1.1.1d=h0b31af3_0

看这里的官方指南。

验证项目再现性

唷,这可能是你主动学习配置 conda 环境之类的最长时间了。

现在,我们已经选择了一个包管理器,并对它进行了配置,以成功安装我们的依赖项。这是一个巨大的进步,让合作者可以快速开始,但是我们如何确保随着项目的增长,可再现性不会随着时间的推移而被侵蚀呢?

手动方式是定期在一台新机器上安装你的项目,只是为了检查它是否还在运行。这听起来效率很低,所以在结束之前,我打算先研究一下自动方式。

监控你工作的整体质量的过程被称为持续集成(CI) ,它围绕着将自动化服务连接到你的源代码库。持续集成超出了本文档的范围,但我将向您介绍两个产品: Github Actions ,它默认集成到 Github 中,以及 Treebeard (完全公开:我正在开发),它也可以安装在 Github repos 上以跟踪可再现性。

一旦你经历了使你的项目可复制的麻烦,不附加 CI 服务将是一种浪费。这就像写了一篇博客文章却没有进行拼写检查一样。说到这里,我们结束吧。

外卖食品

  1. 在您的项目中包含一个维护良好的依赖文件,可以让您通过避免依赖地狱,以更快的速度进行协作和交付
  2. 如果您需要pip freezeconda export您的环境,记得删除可传递的依赖项和不必要的固定版本
  3. 持续集成让您可以自动检查依赖性

进一步阅读

这篇文章讨论了一些 devops 实践,它们帮助你在团队中更有效地工作,并让你的代码在外面的世界中运行。有关相关实践,请阅读:

posted @ 2024-10-15 13:47  绝不原创的飞龙  阅读(213)  评论(0)    收藏  举报