TowardsDataScience-博客中文翻译-2020-九-

TowardsDataScience 博客中文翻译 2020(九)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

“地球上最难的数据科学锦标赛”的简单指南

原文:https://towardsdatascience.com/a-guide-to-the-hardest-data-science-tournament-on-the-planet-748f46e83690?source=collection_archive---------21-----------------------

好玩的数据科学?为了加密?为什么不两者都要?😀

来源:数字博客

更新—2020 年 12 月 01 日:笔记本已根据新目标“Nomi”更新。目标名称现在是“目标”,而不是“目标一杉”

更新—2021 年 9 月:本笔记本使用的数据集现为旧版。一个新的超级海量数据集现已上线。只要稍加修改,代码仍然可以使用。

告诉我密码:

确保你已经在number . ai注册了,因为你需要设置你的 API 密匙来直接从 colab 提交。

[## 谷歌联合实验室

第一次数字投稿指南

colab.research.google.com](https://colab.research.google.com/drive/1un9sQF5063VQ1UH13elYM269ZeYxHKFw?usp=sharing)

💡数字锦标赛问题

数字数据科学问题就像一个典型的监督机器学习问题,其中数据有几个输入特征和相应的标签(或目标)。我们的目标是使用各种技术学习从输入到目标的映射。我们通常将数据分成训练验证两部分。而且大部分时间都花在清理数据上。

左图:训练数据样本。右图:样本提交

然而,数字数据是不同的。这是一个预测股票市场的问题,但它的独特之处在于数据被混淆并且已经被清洗!我们不知道哪一行对应哪一只股票。此外,每一行都被分成代表不同时间点的时代,但是只要它有结构,我们当然可以尝试从中学习和绘制模式。

Numerai 将这些经过清理的数据交给数据科学家,并要求他们为这些数据提供更好的估计。这些众包预测被用来建立一个元模型,并投资于世界各地的真实股票市场。奖励是基于你预测的质量和你的核磁共振赌注的数量。如果你的预测有助于获利,你就可以获得一定比例的股份,否则,你的股份就会被烧掉。这个赚/烧系统不断激励更好和独特的预测。因此,预测越准确和/或独特,回报越高。这就是它有趣和复杂的地方(最难的数据科学问题)。

让我们在 Google Colab 上解决这个问题。使用简单但非常好的技术— CatBoost 的端到端走查。我将在这里解释 colab 片段。如果您在与此平行的新标签中打开笔记本链接,将会非常有帮助。

管道➿

  1. 加载数据集(以及您将需要的一些操作)
  2. 定义模型
  3. 训练模特
  4. 验证
    4.1 调整一些东西(回到步骤 1)
  5. 预测并提交
    5.1 观察 4 周以上的表现

设置 Colab

我们需要切换运行时来使用 GPU,方法是转到

Runtime -> Change runtime type -> GPU -> Save

Colab 预装了如此多的数据科学库。我们需要安装CatBoostnumerapi

我们将在 colab 中设置您的管道,并使其足够灵活,以便在那里执行实验并使用 API 键提交预测。因此,一旦设置好按键并完成模型,您只需按下 colab 上的Run all即可。

同样,确保你已经打开了这篇文章旁边的笔记本。

加载数据📊

使用 numerapi 下载数据并加载到内存中

锦标赛数据已经包含验证集(val1 和 val2 )。我们通常评估我们的模型对这个子集的预测,目标是在看不见的数据上表现良好。

定义和训练模型🤖⚙️

定义和训练模型

这可能是您进行大部分观察和调优的地方。您应该尝试其他类型的建模算法。

做出和评估预测📐

不要被这里这么多的代码弄得不知所措。这主要是帮助评估预测的样板代码。你可能不需要改变太多。然而,一旦你对锦标赛感到满意,你可能会想要添加更多的指标以获得更好的评估。

预测和验证

训练和验证集的评估结果

一旦你认为你的预测满足了你的目标,你可以使用你的秘钥在numerapi的帮助下保存并上传它们。

提交预测📤

右上角的设置菜单

虽然您可以手动上传predictions.csv ,但我们将使用 API 来轻松提交。Numerai 允许你为不同的目的创建密钥,但是我们只为上传预测创建密钥。

用于创建密钥的自动化选项

不同用途的关键选项

要创建新的密钥,请转到

Settings -> Create API key -> select "Upload Predictions" -> Save

系统会提示您将密钥保存到安全的地方。

以下是提交预测的示例关键字。

提交预测的示例关键字

一个账号可以有 10 个型号。所以,在保持你的表现良好的模型不变的情况下,请随意试验新的技术。您可以使用numerapi提交不同模型的预测。您可以在“设置”上方的“选项”中看到您的型号列表。你只需要复制model_id并粘贴在这里。

获取模型密钥

提交预测

我的一个模型的统计,不是这个。

上传预测后,您将看到一些关于您提交的指标和信息。

从我的经验来看,在锦标赛中启动和运行需要几个提交。一旦你建立了你的工作流程,你需要做的就是在 Google colab 中按下Run all

Your predictions will be tested on live data and given scores,[CORR](https://docs.numer.ai/tournament/learn#scoring): Correlation between your predictions and live data
[Meta Model Contribution(MMC)](https://docs.numer.ai/tournament/metamodel-contribution): *An advanced staking option which incentivizes models that are unique in addition to high performing*You can [stake](https://docs.numer.ai/tournament/staking-and-payouts) your NMR on either CORR or CORR+MMC.

下一步是什么?💭

你可以做几件事来提高你的表现。你也会因为你预测的独特性而得到报酬。

  1. 玩弄数据
  2. 调整模型参数
  3. 变更模型架构
  4. RocketChat论坛上提问
  5. 加入每周办公时间——详情请访问 RocketChat

从软件开发人员/工程师过渡到机器学习工程师的指南

原文:https://towardsdatascience.com/a-guide-to-transitioning-from-software-developer-engineer-to-machine-learning-engineer-49c8395dd63a?source=collection_archive---------3-----------------------

如何从软件开发人员过渡到机器学习工程师的指南

图片由皮克斯拜的 Gerd Altmann 提供

他的博客面向任何对机器学习感兴趣的初学者或专业程序员/或学者。踏入机器学习工程领域,不需要依靠数据科学的工作经验。这个博客是为任何打算自学机器学习的人准备的。

我来告诉你我是如何开始成为一名机器学习工程师的旅程的。我有多年的 C++开发经验,对图像处理感兴趣。最近,机器学习已经被应用到许多现实世界的应用中。我很快就迷上了这种新的范式。从两年前开始,我一直在积极寻求更多的信息和知识,包括自学和做许多自己的项目。

作为一个热爱图像处理各方面的人,我从两年前开始决定探索深度学习。现在,我想发布这个资源来帮助其他人,那些像我一样对人工智能着迷的人,以及那些希望做同样事情的人。我希望这个博客能让他们更容易尝试我的方法。

目录

  1. 数据科学 vs 机器学习工程
  2. 机器学习技能
  3. 机器学习编程技能
  4. 其他活动
  5. 结论
  6. 资源

1。数据科学 vs 机器学习工程

理解数据科学家和机器学习工程师之间的差异至关重要。机器学习工程师角色专门针对机器学习,在工作描述中也可能被称为“软件工程师、机器学习”或“数据工程师”。

关于数据科学家和机器学习工程师之间的区别,有大量的在线资源,请务必查看:

作为机器学习工作流程的一部分,数据科学家利用统计分析来确定使用哪种机器学习方法。只有到那时,他们才开始原型制作和构建这些模型。

机器学习工程师通常会在建模过程之前和之后与数据科学家合作;构建数据管道,将数据输入模型。最后,设计一个服务于这些模型的工程系统,以确保模型的持续健康。

下图将解释机器学习项目中不同角色的交互:

机器学习项目中的不同角色

2.机器学习技能

2.1.机器学习理论

有很多资源可以学习机器学习理论。就我个人而言,我喜欢 T2 和吴恩达的课程。以下是我发现对理解机器学习有用的一些课程:

斯坦福 CS229 by 吴恩达:机器学习

本课程提供了机器学习和统计模式识别的广泛介绍。这门课更深入算法的数学推导。

吴恩达斯坦福 CS229A:应用机器学习

这是一门令人惊叹的课程,提供了机器学习的完整概述。作为一门应用机器学习课程,与 CS229 相比,它的数学性要低得多,在实践方面花费的时间更多。

吴恩达斯坦福 CS230:深度学习

在这门课程中,你将学习深度学习的基础,了解如何构建神经网络,并学习如何领导成功的机器学习项目。本课程不太关注数学,而是花更多时间教授应用机器学习算法的实用方法。这是这个列表中最实用的。

斯坦福 CS231 作者费-李非:卷积神经网络

本课程详细介绍了深度学习架构的细节,重点是学习端到端模型,尤其是图像分类。它比 CS230 更深入地关注深度学习。

UC Berkeley stat-157 作者 Alex Smola:深度学习

这个课程是一个关于深度学习的很棒的课程,对最新的深度学习架构进行了解释。您将学习如何详细实现每个模型。你可以完全访问 GitHub 中的所有代码。

这些课程都很有用,你将从探索所有这些课程中受益。在每门课程中,你会学到不同的东西。这些课程为该领域提供了良好的基础。如果你想学习深度学习,你将需要学习机器学习和深度学习的基础。在你深入研究计算机视觉、自然语言处理、机器人技术或深度强化学习之前,你将需要这个基础。你还会从计算机视觉,自然语言处理,语音识别,甚至自动驾驶汽车上看到一点点每个专业化。这将帮助你决定你对这个领域的哪个领域最感兴趣。

2.2.深度学习框架

存在许多用于构建深度学习应用的库。最常见的有 TensorFlow,Keras,PyTorch。这三个库都是开源的。有许多资源可以用来了解关于这些框架的更多信息。我做了一个比较,你可以在我的 Github 中找到。

2.3.机器学习工作流程

机器学习工作流是从零开始构建机器学习项目所需的过程。这个过程可能因项目而异。然而,机器学习项目的核心通用步骤如下:

机器学习工作流程

3.机器学习编程技能

3.1.计算机编程语言

Python 是机器学习中最常用的语言。Python 的调试非常具有挑战性,因为它是基于动态数据类型的。对于那些来自强结构化语言(如 C++)的人来说,适应动态类型和脚本可能是一个挑战。

脚本语言旨在快速学习和编写,因为一般来说,它们要求简短的源代码。然而,随着应用程序的增长,您可能会面临一些困难。首先,你没有像 C++这样的编译器来捕捉你的错误。此外,所有的类型都是动态的,所以当你的程序变大时,你可能很难跟踪并找出变量的类型。这可能会使你的代码变得容易出错,尤其是如果它设计得不好的话。

使用 python 包管理器是一个很好的实践。全局安装的问题是,对于给定的 Python 解释器,一次只能安装一个版本的包。当您的应用程序需要同一库的不同版本时,这可能是一个问题。此外,升级库可能会破坏应用程序

有许多 python 包管理器,但是在数据科学工作中最常用的是 Anaconda。Anaconda 简化了包的管理和部署。它只需一次安装就可以带来许多数据科学和机器学习中使用的工具,因此它非常适合进行简短的设置。

Anaconda 的另一个重要特性是 conda,它是 Anaconda 包管理器。您可以使用 conda 安装许多库。此外,在 Anaconda 中,我们可以创建一个虚拟环境,这有助于隔离不同的库和版本。如果他们使用不同的 Python 库,那么为每个项目创建一个虚拟环境是一个好主意。

3.2。Python 库

Python 的标准库非常大,您的项目可能需要很多。这些库包含了很多用 c 编写的模块,最常见的你应该知道的有 panda、numpy、matplotlib、opencv-python、scipy、scikit-learn、tensorboard。

如果您想了解更多,我会在参考资料部分留下有用的链接供您访问。

3.3。Python 集成开发环境

有许多集成开发环境(ide)可供您选择来开发您的软件。用于机器学习的常见 ide 有 Jupyter NotebookPyCharm 。这些 ide 使得机器学习的编程更加容易。

如果你正在构思一个想法或制作一个简单的功能,Juyter 笔记本是很容易的。我发现在 Jupyter Notebook 中格式化我的代码或调试我的代码并不容易。

PyCharm 是 JetBrains 公司开发的一款开源软件,JetBrains 公司以其名为 IntelliJ IDEA 的 Java IDE 而闻名。PyCharm IDE 的一些有趣特性包括一个代码编辑器,一个非常强大的带有图形界面和错误高亮的调试器。它内置了对 Git、SVN 和 Mercurial 的支持。

4。其他活动

4.1。免费提供的博客

有许多博客提供关于人工智能和机器学习的信息。其中一些博客属于谷歌或 Bair Blog 等知名公司。但是如果你正在寻找简单的例子和指南,你可以参考以下三个博客;走向数据科学中等机器学习精通

4.2。播客

播客是获取新技术和市场方向信息的绝佳资源。下面是我最喜欢的两个播客:实用 AI今日 AI

4.3。练习机器学习

send ex Youtube频道包含了很多机器学习和深度学习的实际应用。他专注于机器学习和深度学习的实现,因此他不会深入每个算法背后的理论。他用每个人都能听懂的非常简单的语言一步一步地解释一切。你可以从他的博客中获得所有的代码。

我使用 Keras 和 TensorFlow 做了一个简单的狗和猫的分类项目,可以帮助你开始建立深度学习项目。您还将熟悉使用 TensorFlow 数据集构建数据管道来对猫和狗的图像进行分类。你可以访问我的 GitHub 中的代码。

我做了一个小的回归项目,演示了如何建立一个简单的线性回归。这段代码也可以从我的 GitHub 中获得。

4.4。参加比赛

另一个学习新技术和建立人际网络的好地方是 meetup。参加聚会会非常有用。黑客马拉松是练习和提高你的 python 和深度学习技能的另一个好方法。黑客马拉松通常是为期一天的比赛,在比赛中你会收到真实的数据和挑战,你需要在一天结束前解决这些问题。

现在,我们知道如果我们需要建立一个深度学习项目,我们需要数据。要开始一个深度学习项目,你首先需要有一个图像数据集。构建数据集可能非常具有挑战性,甚至是不可能的。幸运的是 Kaggle 为我们提供了许多免费的数据集用于此目的。

如果你达到了需要更大挑战的地步,你可以参加 AI 比赛。每年,许多公司,如人工智能实验室、微软、Kaggle 和其他公司都会举办你可能会参加的竞赛。

5.结论

希望这篇文章对那些想知道如何成为一名机器学习工程师的人有所帮助。

以下是一些你可以自己研究的想法:

  • 测试机器学习系统
  • 尝试了解机器学习部署
  • 尝试了解 Docker

6.资源

l \从科里斯查费 youtube 频道和send exYouTube 频道学习 python:这些频道是学习 Python、机器学习、深度学习和自然语言处理的丰富资源

Conda 备忘单:该备忘单总结了 Conda 命令行指令的常用方法,以供快速参考

PyCharm 插件库:插件非常有用,可以帮助你轻松扩展 PyCharm 的功能

Kotlin 数据类的 Spring Boot 配置属性指南

原文:https://towardsdatascience.com/a-guide-to-use-spring-boots-configurationproperties-annotation-in-kotlin-s-dataclass-1341c63110f4?source=collection_archive---------0-----------------------

照片由孙渔·金Unsplash 上拍摄

我将 Spring Boot 描述为软件工程框架的苹果等价物。🍎原因是它设计得很好,允许你写更少更干净的代码。我是说,它很优雅,就像苹果一样。(由于我是苹果团队,所以我在这里可能有点偏见)。

Spring Boot 附带了很多注释,使得我们程序员的生活变得更加容易。🙂其中一个我经常使用的是@ConfigurationProperties。我发现它非常有用,因此,我想向您展示如何在您的应用程序中使用它。

更具体地说,您将学习如何将您的应用程序配置定义为一个由 Spring 管理的dataclass。我们将使用@ConfigurationProperties注释和application.yml文件的组合来创建配置dataclass

定义一个配置类是很方便的。我们只需要定义它一次,之后,我们可以在需要它的不同类中多次使用它。

为了遵循这个指南,您可以克隆这个 Github repo 。请注意,本教程是从这个提交开始的,所以如果您想在本教程中自己构建代码,请检查这个提交。如果没有,你可以直接复制回购协议,跟着读。🙂

回购中包含的应用程序是一个 Kotlin 应用程序,使用 Spring Boot 和 Spring Webflux 构建,并与 DynamoDB 相结合。如果您感兴趣,您可以查看这篇文章来了解应用程序最初是如何构建的。

正在创建 DynamoConfigProperties 数据类

来看看我们现在的DynamoClientProperties班。您可以看到,它将regionendpoint作为其类构造函数的 2 个参数。这两个值都将由 Spring 通过@Value注释注入,该注释通过传递给参数的路径查看位于src/main/kotlin/resources目录中的application.yml文件。

DynamoClientProperties.kt

另一方面,让我们检查一下我们的application.yml文件的内容。非常简单直接。它只是定义了与 DynamoDB 相关的类的配置。

应用程序. yml

现在,如果我们让应用程序保持原样,一切都很好。真的没必要改变什么。但是,想象一下,如果我们的配置由几个值组成,而不仅仅是 2 个值(在我们的例子中,只有regionendpoint),并且相同的配置用于多个类,而不仅仅是 1 个类(例如在DynamoClientProperties.kt)。

在这种情况下,这意味着我们需要在不同的地方编写相同的@Values语句。这就是为什么我们要改用@ConfigurationProperties的原因。它使我们能够在一个地方定义一个包含所有用于特定目的的配置值的dataclass(例如,与 DynamoDB 相关的配置),只需一次,并且我们可以根据需要在许多其他地方/类中使用它。

继续创建一个新的 Kotlin 文件并将其命名为DynamoConfigProperties.kt。文件的内容会是这样的。

DynamoConfigProperties.kt

很快您就可以看到,您编写了更少的代码来获得您需要的值。然后你可以去DynamoClientProperties班,注射DynamoConfigProperties而不是regionendpoint。就会变成这样。

使用 DynamoConfigProperties 的 DynamoClientProperties.kt

简单干净多了吧?另一个好处是,如果你需要任何值customerTableNameregionendpoint,你可以简单地传递DynamoConfigProperties,顺便说一下,它是一个 Spring bean,所以它只在 Spring Boot 应用程序启动时初始化一次。

运行应用程序

现在,如果您从 IntelliJ 运行应用程序的DynamodemoApplication.kt中的main函数,一切都将像更改前一样运行。一切都好,伙计们。😃

DynamodemoApplication.kt

您可以继续按照这个教程来测试与 DynamoDB 的交互是否仍然如预期的那样工作(这是教程的最后一部分,抱歉,Medium 还不支持锚链接😜).

关于编写 DynamoConfigProperties 数据类的附加说明

当你看到DynamoConfigProperties是如何编写的,你可能会有点犹豫,或者认为它有点混乱(或者难看),因为我们将字段声明为var而不是val,尽管事实上这些值永远不会改变(或者应该说不应该改变)。

此外,我们需要提供一个空字符串""(或者任何一个String),或者null(为此,需要将DynamoConfigProperties中的字段类型改为String?)。

如果您将它们声明为val或者不提供默认值并运行应用程序,您将看到以下错误。

2020-01-16 07:21:57.883  WARN 97395 --- [           main] onfigReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerHandler' defined in file [/Users/billyde/demo/dynamodemo/out/production/classes/io/codebrews/dynamodemo/CustomerHandler.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerRepo' defined in file [/Users/billyde/demo/dynamodemo/out/production/classes/io/codebrews/dynamodemo/CustomerRepo.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dynamoClientProperties' defined in file [/Users/billyde/demo/dynamodemo/out/production/classes/io/codebrews/dynamodemo/DynamoClientProperties.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dynamoConfigProperties' defined in file [/Users/billyde/demo/dynamodemo/out/production/classes/io/codebrews/dynamodemo/DynamoConfigProperties.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
2020-01-16 07:21:57.960  INFO 97395 --- [           main] ConditionEvaluationReportLoggingListener :Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-01-16 07:21:58.085 ERROR 97395 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   :***************************
APPLICATION FAILED TO START
***************************Description:Parameter 0 of constructor in io.codebrews.dynamodemo.DynamoConfigProperties required a bean of type 'java.lang.String' that could not be found.Action:Consider defining a bean of type 'java.lang.String' in your configuration.Process finished with exit code 1

你可以看到 Spring 抱怨我们的DynamoConfigProperties的构造函数。😫

我想我们只需要处理我们的配置dataclass写得有多“丑”就行了,不是吗?🤷‍♂

不,我们没有。Spring Boot 来救援了。😊

为配置数据类使用 ConstructorBinding 批注

如果你的项目使用 Spring Boot 框架版本2.2.0.RELEASE或者更高版本,你可以改变你写DynamoConfigProperties的方式如下。

带有 ConstructorBinding 的 DynamoConfigProperties.kt

现在,继续运行应用程序的main功能。你应该看到下面的异常被抛出。😦

2020-01-16 13:29:03.367  WARN 87367 --- [           main] onfigReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerHandler' defined in file [/Users/billyde/demo/dynamodemo/out/production/classes/io/codebrews/dynamodemo/CustomerHandler.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerRepo' defined in file [/Users/billyde/demo/dynamodemo/out/production/classes/io/codebrews/dynamodemo/CustomerRepo.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dynamoClientProperties' defined in file [/Users/billyde/demo/dynamodemo/out/production/classes/io/codebrews/dynamodemo/DynamoClientProperties.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'io.codebrews.dynamodemo.DynamoConfigProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
2020-01-16 13:29:03.422  INFO 87367 --- [           main] ConditionEvaluationReportLoggingListener :Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-01-16 13:29:03.498 ERROR 87367 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   :***************************
APPLICATION FAILED TO START
***************************Description:Parameter 0 of constructor in io.codebrews.dynamodemo.DynamoClientProperties required a bean of type 'io.codebrews.dynamodemo.DynamoConfigProperties' that could not be found.Action:Consider defining a bean of type 'io.codebrews.dynamodemo.DynamoConfigProperties' in your configuration.Process finished with exit code 1

不幸的是,Spring 会向您抱怨它找不到我们的应用程序运行所需的DynamoConfigProperties bean。这是因为 Spring 不会扫描由@ConfigurationProperties注释的类。

我们最初的DynamoConfigProperties工作得很好,因为我们用@Component对它进行了注释,Spring 在构建应用程序上下文时会扫描它。

我知道你在想什么…你会给更新的DynamoConfigProperties添加@Component注释,是吗?但不幸的是,这也不行,当你启动应用程序时,它会抛出这个错误。

2020-01-16 13:45:06.021  WARN 92292 --- [           main] onfigReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dynamoConfigProperties': [@EnableConfigurationP](http://twitter.com/EnableConfigurationP)roperties or [@ConfigurationPropert](http://twitter.com/ConfigurationPropert)iesScan must be used to add [@ConstructorBinding](http://twitter.com/ConstructorBinding) type io.codebrews.dynamodemo.DynamoConfigProperties
2020-01-16 13:45:06.031  INFO 92292 --- [           main] ConditionEvaluationReportLoggingListener :Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-01-16 13:45:06.039 ERROR 92292 --- [           main] o.s.boot.SpringApplication               : Application run failedorg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dynamoConfigProperties': [@EnableConfigurationP](http://twitter.com/EnableConfigurationP)roperties or [@ConfigurationPropert](http://twitter.com/ConfigurationPropert)iesScan must be used to add [@ConstructorBinding](http://twitter.com/ConstructorBinding) type io.codebrews.dynamodemo.DynamoConfigProperties
 at org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator.validate(ConfigurationPropertiesBeanDefinitionValidator.java:66) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
 at org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator.postProcessBeanFactory(ConfigurationPropertiesBeanDefinitionValidator.java:45) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
 at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:286) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
 at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:174) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
 at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
 at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
 at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
 at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
 at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
 at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
 at io.codebrews.dynamodemo.DynamodemoApplicationKt.main(DynamodemoApplication.kt:15) [classes/:na]Process finished with exit code 1

那么,我们现在做什么?我们改进了代码的编写方式,但是我们的应用程序崩溃了!我们应该回到过去的方式吗?

绝对不行!🙅‍♂

以下是修复方法。(其实很简单)。

将配置属性扫描或启用配置属性应用到我们的主应用程序类

凭借另一个 Spring Boot 的注解——@ConfigurationPropertiesScan。我们试图用@Component注释更新的DynamoConfigProperties时,错误消息实际上告诉我们使用@ConfigurationPropertiesScan@EnableConfigurationProperties

在本教程中,我们将继续进行@ConfigurationPropertiesScan。因此,让我们像这样将注释添加到我们的DynamodemoApplication类中。

带有配置属性扫描的 DynamodemoApplication.kt

或者,如果你想用@EnableConfigurationProperties代替,这是你如何做。这需要一点额外的步骤来实现,也就是说,您需要明确地指定您想要启用哪个配置类。在我们这里是DynamoConfigProperties

带有 EnableConfigurationProperties 的 DynamodemoApplication.kt

如果您想要启用其他配置类,您需要指定所有配置类,用逗号分隔,例如@EnableConfigurationProperties(DynamoConfigProperties::class, KafkaConfigProperties::class)

应用上述任一项后,继续运行main功能。这次我不会再耍花招了。😜

DynamodemoApplication.kt 运行成功

瞧啊。现在一切正常。

干得好,伙计们!👍 👍

托里·莫里森在 Unsplash 拍摄的照片

参考

这里的应用程序 Github—

关于应用程序最初是如何构建的教程— 此处

关于@ConfigurationProperties——的 Spring Boot 官方文件在这里

单词嵌入指南

原文:https://towardsdatascience.com/a-guide-to-word-embeddings-8a23817ab60f?source=collection_archive---------20-----------------------

这是什么?它怎么会比单词袋模型更有用呢?

阅读、理解、交流并最终产生新内容是我们所有人都会做的事情,不管我们在职业生活中是谁。

当要从给定的文本体中提取有用的特征时,所涉及的过程与连续整数向量相比有着根本的不同。这是因为一个句子或一段文本中的信息是以结构化序列编码的,单词的语义位置传达了文本的意思。

因此,对数据的适当表示以及保留文本的上下文含义的双重要求使我了解并实现了两种不同的 NLP 模型来完成文本分类的任务。

单词嵌入是文本中单个单词的密集表示,考虑了上下文和该单个单词出现的其他周围单词。

可以选择这个实值向量的维数,并且比简单的单词袋模型更有效地捕捉单词之间的语义关系。

单词之间的线性关系。图片来自 developers.google.com

简而言之,拥有相似含义或经常在相似上下文中一起出现的单词将具有相似的向量表示,这取决于这些单词在含义上的“接近”或“远离”。

在这篇文章中,我将探索两个单词嵌入——

1。训练我们自己嵌入

2。预先训练好的手套字嵌入

数据集—

对于本案例研究,我们将使用 Kaggle 中的 堆栈溢出数据集 。该数据集包含用户在网站上提出的 60,000 个问题,主要任务是将所提问题的质量分为 3 类。

现在让我们看看这个多类 NLP 项目的实际模型本身。

但是,在开始之前,请确保您已经安装了这些包/库。

pip install gensim            # For NLP preprocessing taskspip install keras             # For the Embedding layer

1.训练单词嵌入—

如果您想跳过解释,请在此 访问第一个型号的完整代码

1)数据预处理—

在第一个模型中,我们将训练一个神经网络从我们的文本语料库中学习嵌入。具体来说,我们将使用 Keras 库向神经网络中的嵌入层提供单词标记及其索引。

在训练我们的网络之前,必须确定一些关键参数。这些因素包括词汇表的大小或语料库中独特单词的数量以及嵌入向量的大小。

下载 zip 中提供了 2 个 数据集 用于训练和测试。我们现在将导入它们,只保留问题和质量列进行分析。

我还更改了列名并定义了一个函数 text_clean 来清理问题。

如果您查看原始数据集,您会发现 HTML 标签中包含的问题如下所示,

…..问题 < /p >。而且还有 href,https 等词。,遍布整个文本,所以我要确保从文本中删除这两组不需要的字符。

Gensim 的simple _ preprocess方法返回一个去掉了重音符号的小写记号列表。

在这里使用 apply 方法将通过预处理函数迭代运行每个观察/行,并在移动到下一行之前返回输出。继续将文本预处理功能应用于训练和测试数据集。

由于因变量向量中有 3 个类别,我们将应用一键编码并初始化一些参数以备后用。

2)标记化—

接下来,我们将使用 Keras Tokenizer 类将仍然由单词组成的问题转换为一个数组,该数组表示单词及其索引。

因此,我们首先必须使用 fit_on_texts 方法,从数据集中出现的单词中构建一个索引词汇表。

在构建了词汇表之后,我们使用 text_to_sequences 方法将句子转换成代表单词的数字列表。

pad_sequences 函数确保所有观察值长度相同,设置为任意数字或数据集中最长问题的长度。

我们之前初始化的 vocab_size 参数仅仅是我们的独特单词词汇表的大小(用于学习和索引)。

3)训练嵌入层—

最后,在这一部分中,我们将构建和训练我们的模型,该模型由两个主要层组成,一个嵌入层将从上面准备的训练文档中学习,另一个密集输出层用于实现分类任务。

嵌入层将在训练时学习单词表示和神经网络,并需要大量的文本数据来提供准确的预测。在我们的例子中,45,000 次训练观察足以有效地学习语料库并对所提问题的质量进行分类。正如我们将从指标中看到的。

4)评估和度量图—

剩下的就是评估我们的模型的性能,并绘制图表来查看模型的准确性和损失度量如何随时代而变化。

我们模型的性能指标显示在下面的屏幕截图中。

绩效指标。

其代码如下所示。

以下是准确度在训练中如何提高的…

超过 20 个训练时期的准确度

…损失在 20 个时期内下降。

超过 20 个训练时期的损失。

2.预先训练的手套单词嵌入——

完整代码 这里 ,如果你只是想运行模型。

代替训练你自己的嵌入,另一个选择是使用预先训练的单词嵌入,像 GloVe 或 Word2Vec。在这一部分,我们将使用在 Wikipedia + Gigaword 5 上训练的手套单词嵌入;从 这里 下载。

I)选择预训练的单词嵌入,如果—

你的数据集是由更“通用”的语言组成的,而且你一开始就没有那么大的数据集。

由于这些嵌入已经在来自不同来源的大量单词上进行了训练,如果你的数据也被一般化,预训练模型可能会做得很好。

此外,通过预先训练的嵌入,您将节省时间和计算资源。

ii)选择训练自己的嵌入,如果—

你的数据(和项目)是基于一个利基行业,如医药、金融或任何其他非通用和高度特定的领域。

在这种情况下,一般的单词嵌入表示可能不适合您,并且一些单词可能从预先训练的嵌入中完全丢失。

另一方面,需要大量的数据来确保正在学习的单词嵌入能够恰当地表示不同的单词以及它们之间的语义关系,这是您的领域所特有的。

此外,遍历您的语料库并构建单词嵌入需要大量的计算资源。

最终,选择从您已获得的数据中训练您自己的嵌入还是使用预训练的嵌入将归结为您独特的项目环境。

显然,您仍然可以试验这两种模型,并选择一个提供更好的准确性,但上面的指南是一个简化的指南,以帮助您做出决定。

这个过程—

所需的大部分步骤已经在前面的部分中完成,只需要做一些调整。

我们只需要建立一个单词和它们的向量的嵌入矩阵,然后用它来设置嵌入层的权重。

所以,如果你正在跟随这个教程(你是吗?),保持预处理、标记化和填充步骤不变。

一旦我们导入了原始数据集并运行了前面的文本清理步骤,我们将运行下面的代码来构建嵌入矩阵。

决定嵌入的维数(50,100,200 ),并将其名称包含在下面的 path 变量中。

应该稍微修改构建和训练嵌入层和神经网络的代码,以允许嵌入矩阵用作嵌入层中的权重。

这是我们预训练模型的测试集的性能指标。

预训练手套模型的准确性和损失度量。

结论:

从两个模型的性能指标来看,训练嵌入层似乎更适合此数据集。

一些原因可能是—

1)大多数关于栈溢出的问题都与 IT 和编程有关,也就是说,一个从定制嵌入中获益更多的利基领域。

2)45,000 个样本的大型训练数据集为我们的嵌入层提供了良好的学习场景。

希望你觉得这个教程很有帮助,并且能够理解训练你自己的单词嵌入背后的概念。

一如既往,任何改进建议都是有益的,也是受欢迎的。

我将在下面留下一些链接供进一步阅读,因为这绝对是一个高级的主题,你应该进一步练习才能很好地理解。

感谢您的阅读,我们将在下一篇文章中再见。

更多资源:

[## 数学之光 ML:理解手套嵌入的直观指南

理解 GloVe 和 Keras 实现背后的理论!

towardsdatascience.com](/light-on-math-ml-intuitive-guide-to-understanding-glove-embeddings-b13b4f19c010) [## 词嵌入及其与分布式语义模型的联系综述

近年来,无监督的学习单词嵌入在许多 NLP 任务中取得了巨大的成功。以至于…

aylien.com](https://aylien.com/blog/overview-word-embeddings-history-word2vec-cbow-glove) [## 理解神经单词嵌入——纯人工智能

微软研究院的数据科学家解释了单词嵌入是如何在自然语言处理中使用的——这是一个…

pureai.com](https://pureai.com/articles/2020/01/06/neural-word-embeddings.aspx)

指南:将 OpenStreetMap 位置数据转化为 ML 要素

原文:https://towardsdatascience.com/a-guide-turning-openstreetmap-location-data-into-ml-features-e687b66db210?source=collection_archive---------25-----------------------

如何将商店、餐馆、公共交通方式和其他当地设施融入您的 ML 模型。

伦敦一系列便利设施的热图。由作者用 Python 制作。

就拿下面这个问题来说。你的任务是预测一个新的 Airbnb 主机可能会在伦敦收取多少费用(推而广之,客人可能会支付多少)。要回答这个问题,你需要收集可能影响该市 Airbnb 房产夜间价格的因素的数据。

你收集的数据越多,你的 ML 模型就越能接近接近完美预测的最佳点。

作者制作

你已经有了关于伦敦 80,000 处 Airbnb 房产和它们的主人的信息。然而,你错过的是关于竞争的关键信息——酒店在哪里,附近有多少商店、酒吧、餐馆、旅游目的地等。毕竟,谁去伦敦旅游是为了呆在一个安静的街区,没有任何活动呢?这就是 OpenStreetMap 可以提供帮助的地方。

在我们继续之前,如果你更愿意以 Jupyter 笔记本的形式遵循这个指南,在文章的最后提供了一个链接。

什么是 OpenStreetMap?

OpenStreetMap (OSM)将自己描述为“一个创建免费可编辑世界地图的合作项目”。它们是地图的维基百科。它的 500 万贡献者可以做任何事情,从增加新的道路或移除已经关闭的商店。

可靠,准确,免费!

如果有人能改变它,它甚至是可靠的吗?是啊!除非你是谷歌的铁杆用户,否则你可能每天都在使用 OSM。苹果、微软、脸书、Mapbox 和 FourSquare 都使用 OSM 作为他们地图工作的基础。亚马逊将其用于他们的物流链。特斯拉在他们的自动驾驶汽车上使用。优步在他们的内部寻路平台上使用它。OSM 可能是现存最久经考验的地图平台。

你也可以从这些企业技术贡献者正在大规模增加平台的事实中得到一些安慰。微软将计算机视觉和卫星图像结合起来,在美国增加了 1 . 24 亿个建筑足迹。

随着时间的推移,企业对 OpenStreetMap 的贡献。来自 SOTM2020 的截屏(在 07:45)。

OSM 最大的优势是绝对免费,可以无限制使用。你可以获得大量关于当地的信息——从当地的便利设施到公交车站、自行车道甚至饮水机。点击这里查看 OSM 特色的完整列表。

访问 OpenStreetMap 数据

安装和基本查询

我们通过 OSMnx 访问 OSM 数据——这是一个 python 模块,最初由 Geoff Boeing 编写,以支持他的博士论文。

pip install osmnx

假设我们想找到伦敦所有的餐馆:

Geopandas 是伦敦 OSMnx 搜索的数据框架。图片作者。

你可以循环这个过程,还可以提取酒吧、餐馆、夜总会和所有其他可能影响房东对 Airbnb 收费的便利设施的所有数据。

绘图和可视化

让我们快速检查一下我们得到的数据。我们将使用 OSMnx 绘制伦敦边界的几何图形,并使用 matplotlib 绘制两者。

伦敦机场地图。由作者使用上述代码制作。

将数据转化为要素

我们目前拥有的是伦敦所有餐馆的数据框架。对于机器学习模型,我们需要的是 Airbnb 每家酒店 10 分钟步行范围内的餐厅数量。要做到这一点需要相当多的操作。

步骤 1:将多边形转换为点

OSMnx 以单点(经度/纬度)坐标的形式返回大多数属性。但是,有一些会以多边形(一种形状)的形式返回。当属性很大时,通常会发生这种情况。处理多边形比处理点更复杂,所以我们将通过计算它们的中心点把它们都转换成点。我们用 shapely 来做这个。

步骤 2:将点坐标转换为局部投影

在我们进行任何计算之前,我们需要将我们的点坐标转换成局部投影。正如你所知道的,地球是一个球体。投影是一种展平地球表面的方法,因此我们可以在地图上显示它。然而,问题是,没有办法使球体表面变平,使得所有部分的大小成比例地相等。

以下面的例子为例。在左边,我们有墨卡托投影——一种流行的地图投影,最初是为了帮助 16 世纪的水手环游世界而设计的。注意,离赤道越远,陆地越大。在右边,我们有一个等矩形投影,它纠正了其中的一些问题。注意两张地图上非洲和格陵兰岛的大小差异。

左:墨卡托投影。右图:等角矩形投影。两张图片都来自维基百科。

一些等地球投影确实存在,但它们作为视觉工具毫无用处。取这两个方位等距投影。你应该能认出右边的那个是联合国的标志。

左图:方位角等距投影照片。右联合国标志。均来自维基百科

解决这个问题的唯一方法是找到一个投影,使你感兴趣的世界的特定部分大小相等。这些被称为本地 UTM 坐标参考系统。幸运的是,OSMnx 内置了一个方法,可以帮助我们快速找到正确的本地 UTM。

现在我们有了本地 UTM,我们导入 Airbnb 数据并将其转换为本地投影。我们对从 OSMnx 获取的原始餐馆数据进行同样的处理。

步骤 3:创建一个 K-D 树来计算距离

最后,我们需要遍历每个 AirBnb 酒店,并计算出在 10 分钟步行距离内(大约 1 公里)有多少家餐馆。

我用 K-D 树来做这个。解释 K-D 树是如何工作的超出了本文的范围,但简而言之,它们是搜索我们的 80,000 个 AirBnb 房间和 6,000 家餐厅并找出哪些房间靠近哪些餐厅的超级有效的方法。首先,我们建立所有餐馆点的树:

然后,我们创建一个函数,将在我们的每个 Airbnb 资产上执行该函数。该函数将查询该树,找到最近的 500 家餐馆,并计算它们离 Airbnb 酒店的距离。我们使用 500 这个数字,希望附近没有超过 500 家餐馆。

最后,我们设置了一个计时器,并将该函数应用于 Airbnb 的每一行:

该功能在 80,000 个属性上需要大约 90 秒。让我们来看看结果:air_gdf[[‘id’,’restaurants’]].head(5)

结果呢

所以你有它。现在你知道有多少家餐馆在每个 AirBnb 房产 10 分钟的步行范围内,有 80,000 个 Airbnb 房产。你可以对酒吧、商店、地铁站、旅游热点、公园以及任何你认为可能影响 Airbnb 房产价格的地方重复这个过程——就像我一样。

在我的最终 XGBoost 模型中,正如你在下面看到的,这些 OSM 的特征(用红色突出显示)最终成为伦敦价格的一些最重要的驱动因素。

功能重要性。由作者用 Python 制作。

完整的 Jupyter 笔记本请看这里

喜欢这篇文章吗?在 Instagram 上查看我的数据可视化页面:HouseOfData

文本预处理手册

原文:https://towardsdatascience.com/a-handbook-to-text-preprocessing-890f73fd28f8?source=collection_archive---------37-----------------------

帕特里克·托马索在 Unsplash 上的照片

自然语言处理的第一步

自然语言处理(NLP)是人工智能中最复杂的领域之一。这背后的原因是文本数据是上下文相关的,需要修改以使其能够被机器理解。它需要经历多个预处理阶段。

在这篇博客中,我们将了解文本预处理是什么,为什么,如何用最简单的代码来尝试。

文本预处理

文本数据很容易被人类理解。但是阅读和分析海量数据是一项复杂的任务。

为了完成这项任务,我们需要将这些文本转换为机器可理解的数据,即,将单词转换为与机器学习算法一起工作的数字特征。

但是,这种转换并不简单,因为文本数据包含冗余和重复的单词。因此,在将文本数据转换成数字特征之前,我们需要对文本数据进行预处理。

文本预处理的基本步骤包括:

  1. 清理原始数据
  2. 符号化
  3. 规范化令牌

让我们用一段代码来看看每一步。

如何实现文本预处理?

在本文中,我们将在 Kaggle 的 Twitter 数据集上使用客户支持。

[## Twitter 上的客户支持

Twitter 上最大品牌的 300 多万条推文和回复

www.kaggle.com](https://www.kaggle.com/thoughtvector/customer-support-on-twitter)

关于数据集:

Twitter 上的客户支持数据集是一个大型的现代推文和回复语料库,用于帮助自然语言理解和会话模型的创新,以及研究现代客户支持实践和影响。该数据集提供了 Twitter 上消费者和客户支持代理之间的大量现代英语对话。

导入数据:

import pandas as pd
data = pd.read_csv("customer-support-on-twitter.csv")

使用 pandas 库将数据从 CSV(逗号分隔值)加载到数据框中。

data.columns

数据列的输出

让我们只考虑用于预处理的‘文本’列。

1.清理原始数据

这个阶段包括删除对文本意义没有任何价值的单词或字符。一些常见的清洁步骤是,

  • 下降箱
  • 特殊字符的删除
  • 停用词的删除
  • 移除 URL
  • 移除 HTML 标签
  • 移除多余的空格

下降箱:

出于以下原因,降低文本的大小写非常重要:

  • 单词“文本”、“文本”、“文本”给句子添加了相同的值
  • 对于文本矢量化,使用像 TF-IDF 这样的技术计算单词的频率,而不考虑大小写
  • 降低所有单词的大小写也非常有助于通过减少词汇量来降低维度。
data["text_lower"] = data["text"].str.lower()

降低外壳前后列'文本'

观察: 所有单词都转换成小写

删除特殊字符:

这是另一种文本预处理技术,有助于处理“万岁”和“万岁!”同理。

import re
no_special_char=[]
for sentence in data.text_lower:
    no_special_char.append(re.sub('[^A-Za-z0-9]+', ' ', sentence))
data["no_special_char"]=no_special_char

正则表达式库提供了一个函数:
sub( actual_pattern,replacing_pattern,data )
帮助我们用数据中的第二个参数替换它的第一个参数

删除特殊字符前后的“文本”列

观察:删除“@”、“`”等特殊字符。

停用词的删除:

停用词是语言中常见的词,如“the”、“a”等。大多数时候,它们可以从文本中删除,因为它们没有提供有价值的信息。

from nltk.corpus import stopwords
stopwords = set(", ".join(stopwords.words('english')))

nltk.corpus 包含一个巨大的常用停用词库。

no_stopwords=[]
for sentence in data["no_special_char"]:
    no_stopwords.append(' '.join(e.lower() for e in sentence.split() if e.lower() not in stopwords))
data["no_stopwords"]=no_stopwords

删除停用词前后的“文本”列

观察: 删除“the”、“to”、“at”等词语

删除任何 URL

下一个预处理步骤是删除数据中存在的任何 URL。这条推文很有可能会包含一些 URL。为了进一步分析,我们可能需要移除它们。消除 URL 的简单代码如下:

no_url=[]
for sentence in data["no_stopwords"]:
    no_url.append(re.sub(r"http\S+", "", sentence))
data["no_url"]=no_url

这里,re()用空字符串替换任何以“http”开头的单词。

移除 HTML 标签

另一种常见的预处理技术是去除 HTML 标签,这种技术在很多地方都会派上用场。如果我们从不同的网站上删除数据,这是非常有用的。我们最终可能会将 HTML 字符串作为文本的一部分。

no_html_tags=[]
for sentence in data["no_url"]:
    no_html_tags.append(re.sub(r"'<.*?>'", "", sentence))

在这里,使用re(),我们用一个空字符串替换包含在< >中的任何模式。

2.标记化

标记化是将文本分割成更小的块的过程,称为标记 每个令牌都是作为特征的机器学习算法的输入。

for sentence in data["no_url"]:
    sentence.split()

Split( ) 将句子转换成单词

3.规范化令牌

规范化是基于单词语义的清洗。规范化令牌可确保进一步预处理或分析的数据的一致性。有两种规范化令牌的技术:

  • 堵塞物
  • 词汇化

词干:

这是从单词中移除和替换后缀以获得单词的词根或基本形式的过程,称为词干。波特词干分析器是一种广泛使用的词干分析技术。

from nltk.stem.porter import PorterStemmer

nltk.stem 提供端口定时器

def stem_words(text):
    return " ".join([stemmer.stem(word) for word in text.split()])
data["text_stemmed"] = data["no_url"].apply(lambda text: stem_words(text))

执行词干分析前后的列文本

观察:所有单词都被转换为其基本形式,就像“消息”被转换为“消息”

词汇化:

目标与词干化是一样的,但是词干化有时会失去单词的实际意义。

词汇化是指正确地使用词汇和词的形态分析来做事情。

它返回单词的基本形式或字典形式,也称为词条

from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()

nltk.stem 提供了 WordNetLemmatizer ,它被广泛用于执行词汇化

def lemmatize_words(text):
    return " ".join([lemmatizer.lemmatize(word) for word in text.split()])data["text_lemmatized"] =data["text_stemmed"].apply(lambda text: lemmatize_words(text))
data["text_lemmatized"]

未规范化的列文本、带词干的文本、带词条的文本

观察:词干提取通过移除后缀将单词转换为基本形式。这可能会导致更多的混乱。词汇化将单词转换成语义基础,从而使其可解释。

这些是在文本数据上广泛执行的不同类型的文本预处理步骤。然而,我们不需要一直执行所有这些。我们需要根据我们的用例仔细选择预处理步骤,因为这也起着重要的作用。

我将继续这篇文章,将这些规范化的标记处理成向量,作为机器学习模型的输入。

谢谢你的阅读。以后我会写更多初学者友好的帖子。请在媒体上关注我,以便了解他们。我欢迎反馈,可以通过 Twitter ramya_vidiyala 和 LinkedIn RamyaVidiyala 联系我。快乐学习!

使用 Python 实践端到端数据科学项目

原文:https://towardsdatascience.com/a-hands-on-an-end-to-end-data-science-project-using-python-4ed97842e27f?source=collection_archive---------32-----------------------

来源:未知,来自

使用 Python 运行数据科学项目的 6 步指南

机器学习、数据科学、预测,这些词你可能听过很多,但它们到底是什么?在什么情况下有用?
机器学习诞生于 20 世纪 60 年代,是人工智能的一个分支,它为系统提供了学习模型和进行预测的能力,例如根据房子的特征(位置、面积、房间数量……)预测房子的价格,或者预测肿瘤是否是良性的。在房子问题中,我们希望预测一个连续值,这类问题属于我们所说的回归问题。在肿瘤的情况下,结果是二进制值或更一般的离散值,这种类型的问题称为分类问题。在处理数据科学问题时,了解您正在寻找的结果的类型以了解您正在处理的是回归还是分类问题是极其重要的。

在这篇文章中,我写了一个进行端到端机器学习项目的指南。如下图所示,图中显示了数据科学项目问题的不同步骤,共有 6 个步骤。我们将在整篇文章中深入研究它们。

为了说明数据科学项目的不同步骤,我将使用一个数据集来描述在高时间分辨率宇宙巡天期间收集的脉冲星候选样本。脉冲星是一种罕见的中子星,它产生的无线电辐射在地球上可以探测到。作为时空、星际介质和物质状态的探测器,它们具有相当大的科学价值。随着脉冲星的旋转,它们的发射光束扫过天空,当光束穿过我们的视线时,会产生一种可检测的宽带无线电发射模式。随着脉冲星快速旋转,这种模式周期性重复。因此,脉冲星涉及到用大型射电望远镜寻找周期性的无线电信号。每颗脉冲星产生的发射模式略有不同,每次旋转都会略有不同。因此,被称为“候选者”的潜在信号探测在脉冲星的多次旋转中被平均化,这由观测的长度决定。在缺乏额外信息的情况下,每个候选者都有可能描述一颗真正的脉冲星。然而在实践中,几乎所有的检测都是由射频干扰(RFI)和噪声引起的,使得合法信号很难被发现。

在这里,使用机器学习模型来预测一颗恒星是否是脉冲星是完全合法的,因为纯物理模型有很多障碍要克服。通过使用机器学习模型,我们可以获得准确的结果,从而降低问题的复杂性。让我们看看我们能做什么!
你可以在这里找到数据集

1.问题的定义

在这个项目中,想法是预测一颗恒星是否是脉冲星。我们可以清楚地看到,我们的模型的结果将是二元的:如果恒星是脉冲星,则为 1,否则为 0。因此,我们将实现分类模型来回答这个问题。

2.提取数据并将其可视化

当我们使用 Python 时,我们将使用 Pandas 库从 csv 文件中提取数据。对于数据可视化,库 seaborn 是一个非常好的库,因为很多数据科学工具已经实现。 matplotlib.pylab 库对于绘制图形也很有用。

**import** **numpy** **as** **np** 
**import** **pandas** **as** **pd** 

*# for data visualization*
**import** **seaborn** **as** **sns** 
**import** **matplotlib.pylab** **as** **plt**

然后,我们可以从 csv 文件中提取数据,并查看不同的特征。您应该经常做的一件事是检查每个特性中的元素数量。如果某些特征的元素数量不同,您必须应用某些操作来填补空白,或者如果缺少太多的值,您必须放弃该特征。

pulsar_stars = pd.read_csv("pulsar_stars.csv") # read the data*# to check if we have to clean the data* 
print(pulsar_stars.apply(pd.Series.count))

我们可以看到,它们是定义恒星的 8 个特征,而目标类是一个二进制值(如果候选恒星是脉冲星,则为 1,否则为 0)。所有不同的特征具有相同数量的元素,因此没有必要进行填充间隙的操作。

下一步是将数据分割成我们将用来训练机器学习算法的数据和我们将用来测试它们各自性能的数据。

*# we set the seed for the random cursor* 
random.seed(10) *# we split the data* 
X = pulsar_stars.drop(['target_class'], axis = 1) 
y = pulsar_stars['target_class'] 
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size = 0.8, random_state = 10) X_columns = X_train.columns

接下来,我们可以查看不同特性之间的相关性以及一个特性和目标类之间的链接,以便了解对结果的影响。

*#correlation plot*
corr = pulsar_stars.corr()
sns.heatmap(corr)

我们注意到,综合轮廓的过度峰度是与目标类更相关的特征。现在,我们将研究每个变量的分布,看看我们是否必须应用一个变换来使它更有价值。

*#create numeric plots*
num = [f **for** f **in** X_train.columns **if** X_train.dtypes[f] != 'object']
nd = pd.melt(X_train, value_vars = num)
n1 = sns.FacetGrid (nd, col='variable', col_wrap=3, height = 5.5, sharex=**False**, sharey = **False**)
n1 = n1.map(sns.distplot, 'value')

大多数变量具有高斯分布(对于大多数特征,您可能认为数据遵循右偏分布,但这只是因为数据的数量不够大)。

现在我们对数据有了更好的理解,我们可以对其进行预处理,以便为我们的机器学习算法提供信息。

3.数据的预处理

由于不同的特征有完全不同的尺度,我们需要将我们的数据标准化。当特征具有相同的尺度时,这个步骤是不必要的,除了诸如 PCA 的一些算法。

它们是规范化数据的不同方法:

scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

4.机器学习模型的选择及其评估指标

在这一部分中,我们实现了不同的机器学习模型来处理分类问题,并定义了评估其性能的措施。对于机器学习模型,我将使用决策树算法、逻辑回归算法、随机森林算法和 K-最近邻算法。我将使用时间、精确度、回忆、加权 f1 分数和 AUC 分数来评估模型。我将更详细地解释我的选择和每个措施的意义。

5.训练机器学习模型并评估它们

这些模型中的一些具有超参数,即其值在学习过程开始之前设定的参数。一种方法是建立超参数可以采用的值列表,并根据尽可能精确的度量通过网格进行搜索,以便找到最佳模型。另一种方法是使用贝叶斯优化(一种更有效的方法)。

*# we start by DecisionTreeClassifier*

dc = DecisionTreeClassifier(max_depth = 4)
dc.fit(X_train, y_train)

params = {'max_depth' : [2,4,8]}
dcgrid = GridSearchCV(estimator = dc, param_grid = params, cv = KFold(5, random_state = 10) , scoring = 'accuracy')
dcgrid.fit(X_train, y_train)

*# Then by LogisticRegression*

lg = LogisticRegression(C=0.001, solver='liblinear')
lg.fit(X_train, y_train)

params = {'C':[0.01,0.1,1,10]}
lggrid = GridSearchCV(estimator = lg, param_grid = params, cv = KFold(5, random_state = 10), scoring = 'accuracy')
lggrid.fit(X_train, y_train)

*# then by RandomForestClassifier*

rf = RandomForestClassifier(n_estimators = 10, max_depth = 10)
rf.fit(X_train, y_train)

params = {'n_estimators' : [10, 20, 50, 100], 'max_depth' : [10, 50]}
rfgrid = GridSearchCV(estimator = rf, param_grid = params, cv = KFold(5, random_state = 10), scoring = 'accuracy')
rfgrid.fit(X_train, y_train)

*# then KNeighborsClassifier*

kn = KNeighborsClassifier(n_neighbors = 10, p = 2)
kn.fit(X_train, y_train)

params = {'n_neighbors' : [2, 5, 10, 50], 'weights' : ['uniform', 'distance'], 'p' :[1,2]}
kngrid = GridSearchCV(estimator = kn, param_grid = params, cv = KFold(5, random_state = 10), scoring = 'accuracy')
kngrid.fit(X_train, y_train)

然后我们找到最佳模型,我们还可以看到训练这些模型所需的时间,这可以作为选择最终模型的一个指标。

*# we define the best models* 
dc_best = dcgrid.best_estimator_
lg_best = lggrid.best_estimator_
rf_best = rfgrid.best_estimator_
kn_best = kngrid.best_estimator_

*# now we will launch each model and see the time and the performance of each* 
start = time.time()

dc = dc_best
dc_best.fit(X_train, y_train)

end = time.time()
print('time for Decision Tree Classifier = ', end - start, 's')
performance_df['Decision_tree']['time(s)'] = end - start

*# Then by LogisticRegression*
start = time.time()

lg = lg_best
lg_best.fit(X_train, y_train)

end = time.time()
print('time for Logisitic Regression= ', end - start, 's')
performance_df['Logistic_regression']['time(s)'] = end - start *# then by RandomForestClassifier*
start = time.time()

rf = rf_best
rf_best.fit(X_train, y_train)

end = time.time()
print('time for Random Forst Classifier = ', end - start, 's')
performance_df['Random_forest']['time(s)'] = end - start

*# then KNeighborsClassifier*
start = time.time()

kn = kn_best
kn_best.fit(X_train, y_train)

end = time.time()
print('time for K_Neighbors Classifier = ', end - start,'s')
performance_df['K-NNeighbors']['time(s)'] = end - start

现在,我们还可以根据另一个指标来评估模型,这个指标就是召回。回忆,也称为敏感度,衡量模型预测积极结果的强度,即 1 正确识别的比例。

*# we will calculate the scores of each model* 
y_predict_dc = dc_best.predict(X_test)
accuracy = accuracy_score(y_test, y_predict_dc)
recall = recall_score(y_test, y_predict_dc)
performance_df['Decision_tree']['accuracy'] = accuracy
performance_df['Decision_tree']['recall'] = recall

y_predict_lg = lg_best.predict(X_test)
accuracy = accuracy_score(y_test, y_predict_lg)
recall = recall_score(y_test, y_predict_lg)
performance_df['Logistic_regression']['accuracy'] = accuracy
performance_df['Logistic_regression']['recall'] = recall

y_predict_rf = dc_best.predict(X_test)
accuracy = accuracy_score(y_test, y_predict_rf)
recall = recall_score(y_test, y_predict_rf)
performance_df['Random_forest']['accuracy'] = accuracy
performance_df['Random_forest']['recall'] = recall

y_predict_kn = dc_best.predict(X_test)
accuracy = accuracy_score(y_test, y_predict_kn)
recall = recall_score(y_test, y_predict_kn)
performance_df['K-NNeighbors']['accuracy'] = accuracy
performance_df['K-NNeighbors']['recall'] = recall

然后,我们可以计算作为误差矩阵的混淆矩阵:

*# generate confusion matrix for Decision Tree classifier* 
conf_mat_dc = confusion_matrix(y_test, y_predict_dc) *# put it into a dataframe for seaborn plot function* conf_math_dc_df = pd.DataFrame(conf_mat_dc)  *# Use a seaborn heatmap to plot confusion matrices* *# The dataframe is transposed to make Actual values on x-axis and predicted on y-axis* 
*# annot = True includes the numbers in each box* 
*# vmin and vmax just adjusts the color value* 
fig, ax = plt.subplots(figsize = (7,7)) sns.heatmap(conf_math_dc_df.T, annot=**True**, annot_kws={"size": 15}, cmap="Oranges", vmin=0, vmax=800, fmt='.0f',              linewidths=1, linecolor="white", cbar=**False**, xticklabels=["no pulsar star","pulsar star"],              yticklabels=["no pulsar star","pulsar star"]) plt.ylabel("Predicted", fontsize=15) 
plt.xlabel("Actual", fontsize=15) 
ax.set_xticklabels(["no pulsar star","pulsar star"], fontsize=13) ax.set_yticklabels(["no pulsar star","pulsar star"], fontsize=13) plt.title("Confusion Matrix for 'Decision Tree' Classifier", fontsize=15) plt.show()
print("")
print(classification_report(y_test, y_predict_dc))

在对其他模型做了这些之后,我们计算最后的测量,即 AUC 曲线。AUC-ROC 曲线是在不同阈值下对分类问题的性能测量。ROC 是概率曲线,AUC 是可分性的程度或度量。它表明模型区分不同类别的能力。AUC 越高,模型就越能预测 0 是 0,1 是 1。

*#Plotting the ROC curve*

*#Generating points to plot on ROC curve (logistic model)*
dc_best_prob = dc_best.predict_proba(X_test)
fpr_logis, tpr_logis, thresholds_logis = roc_curve(y_test, dc_best_prob[:, 1])

fig, ax = plt.subplots(figsize = (10,7))*#plotting the "guessing" model* plt.plot([0, 1], [0, 1], 'k--')*#plotting the logistic model*
plt.plot(fpr_logis, tpr_logis)
plt.fill_between(fpr_logis, tpr_logis, alpha=0.2, color='b')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
AUC = roc_auc_score(y_test, dc_best_prob[:, 1])
plt.title('Decision Tree Classifier ROC curve: AUC=**{0:0.3f}**'.format(AUC))
plt.show()

performance_df['Decision_tree']['AUC'] = AUC

6.关于是否达到初始目标的结论,以及实现这些目标的最佳模式的选择

最后我们得到了下表:

根据我们的问题,这些指标对我们的结果没有同等的权重。AUC 分数是我们模型中最重要的指标,因为预测一颗恒星为非超级恒星,而犯错是我们想要避免的。因此,逻辑回归似乎是最有效的模型。

基于我们选择的模型,我们可以检查不同特征对结果的重要性。

*# thus the logistic regression is the best model : we will keep it* 
*# Now we want to see the importance of each feature on the result* 
dataframe_importance = pd.DataFrame()
columns = X_train.columns
importances = np.abs(lg_best.coef_[0])

**for** i **in** range(len(columns)):
    dataframe_importance[columns[i]] = [importances[i]]

dataframe_importance.insert(0, '', 'Importance features')
dataframe_importance.head(10)

如果模型不够有效

有时我们可能有时间限制或计算能力限制,我们需要使模型更简单。一种方法是进行特征选择。我们可以通过使用统计方法,如卡方检验,或使用维度缩减算法,如 PCA 。然后,我们重新评估模型,我们可以得出结论,是否考虑了我们在时间和精度方面的约束。

为您介绍数据科学世界提供一些评论和提示

不要犹豫花很多时间来定义问题。一旦你习惯了数据科学项目的实现技术,你就会意识到这是你的项目中最容易的部分。另一个相当棘手的部分是数据提取和数据清理。在我在本文中向您展示的项目中,数据非常干净,但是情况几乎从来不是这样。最后,我希望你喜欢这篇文章,并且这是一门实用的科学,熟悉它的最好方法是实践它。选择一个你感兴趣的话题,把你学到的东西付诸实践!

你可以在我的 github 上找到作为神经网络的其他实现的整个项目。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名灵媒成员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你注册使用我的链接,我会赚一小笔佣金,你仍然要支付 5 美元。谢谢大家!!

[## 通过我的推荐链接加入媒体-乔纳森·莱班

阅读乔纳森·莱班的每一个故事(以及媒体上成千上万的其他作家)。您的会员费直接支持…

medium.com](https://medium.com/@jonathan_leban/membership)

PS:我目前是伯克利的工程硕士,如果你想讨论这个话题,请随时联系我。*这里的 是我的邮箱。*

单应性的实际应用:IPM

原文:https://towardsdatascience.com/a-hands-on-application-of-homography-ipm-18d9e47c152f?source=collection_archive---------7-----------------------

校正透视

图一。左:正面视图 RGB。右图:来自 IPM 的 BEV

基于单应性的 IPM

在计算机视觉中,单应矩阵是一个变换矩阵 H 当应用于一个投影平面时将它映射到另一个平面(或图像)。在反向透视映射( IPM )的情况下,我们想要从正面图像平面产生场景的鸟瞰图像。

在自动驾驶领域,IPM 有助于一些下游任务,如车道标志检测、路径规划和路口预测,仅通过使用单目摄像机,因为这种正交视图是比例不变的。强调这项技术的重要性。

IPM 是如何工作的?

IPM 首先假设世界是平面的。然后,它通过单应投影将来自给定视点的所有像素映射到这个平面上。

IPM 什么时候起作用?

实际上,IPM 在摄像机附近工作良好。对于场景中的远处特征,在透视投影过程中,场景的模糊和拉伸变得更加突出,因为表现了较少数量的像素,这限制了 IPM 的应用。这可以在图 1 中观察到,在更远处产生严重的不良失真。准确地说,图中的前瞻距离约为 50 米。

此外,必须满足以下约束条件:

  1. 相机处于固定位置:由于道路的位置对相机敏感,位置或方向的轻微扰动将改变 3D 场景投影到图像平面上的方式。
  2. 表面是平面的:任何具有高度或高程的对象都将违反此条件。非平面表面将在 BEV 图像中产生伪影/失真。
  3. 没有带高度的物体。由于在 3D 场景中任意放置的两个平面之间的透视投影,地面上的所有点都将引起假象。

在本文中,我将尝试解释 IPM 的思想。更重要的是,这篇文章致力于我们如何仅使用 Python 和 Numpy 来计算和应用单应性。

接下来,我将展示使用 OpenCV 可以获得多少有些相似的结果。我们将使用城市景观数据集中相对常见的道路场景作为示例。如有任何问题/疑问,甚至是你可能发现的错误,请随时给我发信息。

这篇文章的代码可以在这里找到。并且所有的inline文本都是指代码中的某个变量或函数。

设置问题

我们试图解决的问题是将正面视图图像转换成鸟瞰视图图像。IPM 通过消除前置摄像头的透视效果并将其图像重新映射到俯视 2D 域来实现这一点。BEV 中的图像试图保持距离和平行线,纠正透视效果。

以下要点总结了基于单应性的 IPM 程序:

  • 将道路(X,Y,Z=0)建模为平坦的 2D 平面。当道路被离散到 BEV 图像上时,必须对分辨率进行一些近似。
  • 根据已知的外部和内部参数确定并构建投影矩阵 P 。通常,这是通过校准获得的。
  • 通过应用 P 来变换和扭曲道路。也称为透视投影。
  • 将正面像素重新映射到新的图像平面。

我将在接下来的章节中详细介绍。

图二。信号源

在我们开始之前,知道相机相对于道路的位置是很重要的。对于 Cityscape 中的道路场景,摄像机安装在稍微向下倾斜的车辆顶部。确切的位置和方向写在文件camera.json中。注意,这些值是相对于自我载体而言的。

概念

要理解 IPM,需要一些透视投影和相机射影几何的背景知识。在本节中,我将简要描述您需要了解的关于这些主题的内容。

1。透视投影

透视投影精确地描述了我们周围的世界是如何被映射到 2D 平面上的。在这个映射过程中,世界(欧几里得空间)中的两条平行线被转换成新平面中的一对线,这对线收敛于无穷远点。参考图 3,放置在世界中的两个立方体的平行属性在我们现在观察的地方没有被保留。这方面的一个例子就是车道线。

图 3

在图 4 所示的例子中,当从不同的视角观察道路时,注意到相同的区域看起来不同。平行谎言不再保留在射影变换中。

图 4。左图:通过车辆顶部的摄像头观察。右图:场景的俯视图。

2。相机射影几何

图 5。针丨孔丨照相机模型

摄像机模型描述了从 3D 场景到 2D 图像的透视投影。形成的图像取决于内在和外在属性。

外部【R | t】描述了世界相对于相机的相对位置和方向。它将世界坐标中的场景引入相机坐标系统。

固有,K 定义 3D 场景将如何根据焦距和相机中心的变化扭曲到图像上。注:这是一个简单的针丨孔丨摄像头模型。其他因素,如像素倾斜和镜头失真,并没有反映在方程中。

我们的问题。原点设置为图像平面 2 的左上角。想法是将位于图像平面 2 上的整个场景(X,Y,Z)投影到摄像机图像平面 1 上。

图 6。场景的 3D 视图。只有道路被建模

3.将这种正向投影视为单应

如前所述,我们假设道路是平坦的。因此,Z = 0对于每一个躺在路上的分。这有效地将问题转化为平面单应。这是一种可以在 OpenCV 中执行图像变形的方法。

实施细节

ipm_from_parameters

我处理这个问题的方法如下:

  1. 在 BEV plane中截取我们希望看到的道路区域。对于该区域,定义像素分辨率、每个像素的绝对距离(比例)和姿势(位置和方向)。
  2. 使用相机投影模型将透视投影perspective应用于像素坐标区域中的所有 3D 点(X,Y,Z=0)。
  3. 从前视图图像重新采样相应的像素,并将其映射回图像平面 2。需要某种形式的插值来防止空洞和混叠效应。我使用双线性插值bilinear_sampler

现在让我们讨论一下上面提到每一点。

1.定义地面上的平面

当车辆移动时,我们希望观察区域相对于它保持一致。因此,该平面是相对于车辆定义的。

平面的原点位于左上角。可视区域被照亮,并取决于摄像机的视野。这就是 IPM 后图像上出现不可见像素(黑色)的原因。我定义了具有以下属性的平面(图 7)

  • 以像素为单位的区域大小:500 X 500
  • 分辨率:每像素 0.1m。
  • 相机被定位并与平面 y 轴的中点对齐。

图 7。该平面由灰色区域定义。可见区域被照亮,表示摄像机的视野

2.导出和应用透视投影

摄像机参数在camera.json中给出,并针对本车给出。由于投影模型要求我们相对于摄像机定义场景,因此需要一些操作来反转变换。

# Notably
np.linag.inv(T) = - T
np.linag.inv(R) = np.transpose(R) # property of orthogonal matrix

外部和内部参数在此函数load_camera_params中构建。

然后,在将点变换成同质表示之后,应用投影变换。像素被比例归一化。即有效焦距= 1。这是在perspective中完成的。

3.重新采样像素

随着我们离相机越远,稀疏度就越容易被观察到。因此,我使用双线性插值作为近似。

图 8。双线性插值

这是通过取 4 个角的加权(按距离)和来完成的

(px, py) = w0 * im0 + w1 * im1 + w2 * im2 + w3 * im3

使用 OpenCV 的单应性

ipm_from_opencv

既然我们已经了解了如何进行透视变形。让我们看看如何在 OpenCV 中轻松执行上述所有步骤。这是通过将问题公式化为平面到平面的变换来实现的。

OpenCV 通过使用点对应在内部求解单应矩阵 H 来实现这一点。现在相当于我上面讨论过的相机矩阵。通过最小二乘法估计 H 至少需要 4 个点。

只有 2 个步骤来执行转换

  • 在图像中选取至少 4 个显著特征,并定义其在目标图像中的新位置。将这些对应关系传入cv2.getPerspectiveTransform以获得投影矩阵。
  • 使用cv2.warpPerspective将投影矩阵应用于图像。这将扭曲到一个鸟瞰图,同时,应用你选择的插值方法。

可供选择的最方便的特征是车道线。因为我们确实知道它们在目标图像(BEV)中将是平行的。

为了说明它产生的结果与前面讨论的派生方法大致相同,我挑选了表示绿色多边形顶点的点,如图 4 所示。

结束

现在我们有了。如果你正在研究计算机视觉,我希望你会发现这篇文章很有用。

[## darylclimb/cvml_project

使用计算机视觉和机器学习的项目和应用

github.com](https://github.com/darylclimb/cvml_project/tree/master/projections/ipm)

爱因斯坦引力方程的启发式推导

原文:https://towardsdatascience.com/a-heuristic-derivation-of-einsteins-gravity-equations-8d3659c8a46c?source=collection_archive---------0-----------------------

从简单论证中获得爱因斯坦方程

图 byElena 11/shutterstock . com

广义相对论对所有认真研究过它的人都有独特的美学吸引力。英国理论物理学家保罗·狄拉克,20 世纪最有影响力的物理学家之一曾经说过:

“牛顿引力理论及其力的瞬时传播很难符合狭义相对论的要求;爱因斯坦在这个难题上的努力导致了他的相对论的推广——这可能是有史以来最伟大的科学发现。”

—保罗·狄拉克

伟大的苏联物理学家列夫·兰道叶夫根尼·利夫希兹在他们的著作《经典场论》中写道:

“建立在相对论基础上的引力场理论,叫做广义相对论。它是由爱因斯坦建立的,代表了可能是所有现存物理理论中最美好的一种。”

在这篇文章中,我将密切关注钱德拉塞卡 T10 的这篇出色的文章(任何省略或不清楚的细节都可以在其中找到),并试图澄清导致这些伟大科学家做出如此强烈声明的一些原因。

对等原则

在牛顿力学中,质量有两个概念,分别是惯性质量和引力质量。前者是对施加的外力的抵抗力的量度(根据牛顿第二定律)。后者是引力场的来源,也是对另一个大质量物体产生的场的反应。

图 1:根据牛顿万有引力定律,两个质量相互吸引的示意图(来源)。

相距 R 的两个质量 mM 相互吸引的大小

根据牛顿第二定律, m (或等价地 M )所经历的加速度为:

等式 1:惯性质量和重力质量之间的等效性是加速度不依赖于被研究物体的事实的结果。由于加速度不变,质量比必然是常数。更明显选择是常数为 1。

a 不依赖于 m 的事实意味着上述质量比是一个普适常数。由此可以推断惯性质量和引力质量大小相等。

时钟滴答之间的关系

请考虑下图:

图 2:根据等效原理,时钟 AB 会根据时钟 C ( )保持相同的相对时间。

随着时钟向上移动,根据狭义相对论,由 AB 测量的间隔与在自由空间中的时钟 C 中的相应间隔具有以下关系:

结合这两个表达式,我们得到:

我们使用了托里切利方程和引力势的定义:

现在,如果我们把时钟 B 带到一个没有引力场的位置 x ,上面的表达式变成:

等式 2:两个事件之间的时间间隔如何随引力势 U(x)变化。

广义相对论中的时空

在狭义相对论中,我们知道闵可夫斯基区间具有以下形式:

等式 3:狭义相对论的闵可夫斯基区间。

其中 是所谓的适当时间的度量。沿着世界线(物体在时空中的轨迹)的正确时间是沿着这条线的时钟所测量的时间。

图 3:对于一个给定的事件,图中显示了闵可夫斯基时空(源)的四个不相交的细分。

如图 3 所示,时空中的世界线可以有三种(详见此链接):

  • 类似光的曲线,在每一点都有光速。这样的世界线在时空中形成一个光锥
  • 时间曲线。这些速度小于光速的曲线落在光锥内(注意大质量粒子的世界线总是类时的)
  • 类似空间的曲线。例如,这些曲线代表一个物体的长度。

图 4:多种类型的世界线,每一种对应一个符号 dτ。

合适的时间间隔 取决于时空的性质。在一个时空区域里。2 是有效的,我们可以在等式中代入。3 获取:

等式 4:由恒定引力场的存在引起的闵可夫斯基时空间隔的变化。

现在考虑一个到匀加速坐标系的坐标变换。新的 xt 成为

等式 5:到匀加速坐标系的坐标变换。

yz 保持不变。**闵可夫斯基区间方程。3 在这个坐标中表示为:

等式 6:匀加速框架的闵可夫斯基区间。

现在,选择时间乘以小于或等于变换方程 Eq.5 中的 c / g ,并执行简单的扩展,新的时空间隔 Eq。3 变成了:

等式 7:用非惯性坐标表示的平坦闵可夫斯基时空中的时空间隔。

请注意,这与等式的形式相同。4.因此,我们看到转换到一个加速框架相当于引入一个引力场,这证实了等效原理。

到目前为止,我们只考虑了平坦闵可夫斯基度规的小偏差。按照爱因斯坦的说法,我们假设一般情况下(不仅仅是小偏差),引力场的存在会扭曲时空的几何形状。更准确地说,爱因斯坦的引力理论假设在存在引力场的情况下,时空变成光滑的伪黎曼流形,其时空间隔的形式为:

等式 8:拟黎曼流形上的时空区间。

在闵可夫斯基时空中,粒子以匀速直线运动:

方程式 10:在闵可夫斯基时空中,粒子以匀速直线运动。

还是在没有重力的情况下,让我们把下面的变换转换成曲线坐标系:

方程式 11:在没有重力的情况下,转换成曲线坐标。

时空间隔变成:

情商。12:变换等式后的时空间隔。11.

其中:

情商。13:变换 Eq 后的度量张量。11.

图 5:在惯性参考系中(上图),黑球做直线运动。然而,站在旋转参照系(底部)中的观察者(红点)看到,由于该参照系中存在的科里奥利力和离心力,它沿着一条弯曲的路径运动()。

运动方程。10 成为无处不在的测地线方程:

情商。14:运动方程 Eq。10 坐标变换后的等式。11、仍处于无重力状态。

那里的物品

情商。15:出现在测地线方程中的克里斯托夫符号。

被称为克里斯托夫符号

Christoffel 符号生成(在等式中。14)一个“表观”加速度,它仅仅是使用曲线坐标来描述笛卡尔坐标中的线性运动的结果。但它们实际上是惯性加速度(例如科里奥利加速度)。但是根据等效原理,所有的加速度,无论是来自惯性力还是来自重力的加速度,在起源上都是度规的:重力扭曲了时空几何(这是一个具有关联度规的准黎曼流形),粒子在时空上以方程式(1)给出的测地线运动。16.

情商。16:粒子在时空中运动的测地线运动方程。

图 6:在 2D 表面移动的插图。如果昆虫继续往前走,它会描绘出一条测地线。

推导爱因斯坦引力定律

在牛顿物理学中,描述引力场的方程是以引力势 U. 来表述的,当没有引力时,人们只需U= 0;当有一个大质量物体,但受其场作用的测试粒子在物体外时,∇u*= 0;在有物质的区域,方程变成∇ U =4 π Gρ。*

让我们看看如何将这三个方程推广到广义相对论的背景下。首先,考虑一个粒子按照运动方程运动。16.如果 Eq。16 可以转化为 Eq。10 坐标的某些变化,意味着粒子不在引力场中。同样,对于现在的重力来说,克里斯托夫符号不会在任何坐标变换后消失。利用克里斯托夫符号的变换定律,很容易证明一般的坐标变换

情商。17:应用于 Christoffel 符号的变换。

将使所有的克里斯托夫符号消失,只有当方程

情商。18:γs 消失的条件

对等式中的四个变换 f s 有一个(非平凡的)解。17.如果所谓的黎曼-克里斯托费尔张量消失,这就会发生。后者由下式给出:

情商。19:黎曼曲率张量或黎曼-克里斯托费尔张量。

我们得出结论,引力场不存在的条件是:

情商。20:无重力的条件。这个方程是 U=0 牛顿方程的相对论对应物。

这个方程是牛顿方程 U =0 的广义相对论版本。可以证明,∇ U=0 的最简单的推广是等式的收缩。20,即:

情商。21:瑞奇标量的消失是∇ U =0 牛顿方程的相对论对应。

这个消失的物体被称为瑞西张量。最后一步是确定∇右侧的一般化 U =4 π Gρ。想到的第一个对象是能量动量张量。从狭义相对论中我们知道,它的导数消失了。但是广义相对论是一个协变理论,所以标准导数的消失是不够的:我们需要协变导数的消失**

这在所有坐标系中都是成立的。但是 Ricci 张量的协变导数不为零。这是通过引入一个相关的张量来解决的,即所谓的爱因斯坦张量,其协变导数为零。

图 7:在广义相对论中,质量之间的引力效应是时空扭曲的结果。

因此,爱因斯坦引力定律变成:

常数 k 可以通过在极限 c → ∞中求得到,牛顿方程被恢复(详见钱德拉塞卡)。

我的 Github 和个人网站 www.marcotavora.me 有一些其他有趣的材料,既有关于物理的,也有关于数学、数据科学和金融等其他主题的。看看他们!

你可能不知道的 Python 正则表达式的一个隐藏特性

原文:https://towardsdatascience.com/a-hidden-feature-of-python-regex-you-may-not-know-f00c286f4847?source=collection_archive---------22-----------------------

蓝皮鹦鹉Pixabay 上拍摄的照片

Python 编程技巧

re.sub()函数的高级用法

众所周知,Python 为正则表达式(regex)提供了许多方便的内置函数,使得字符串操作变得极其简单和方便。

在本文中,我将介绍 Python 中内置于re库中的一个非常棒的特性,用于使用 regex 替换字符串组件。

让我们看看下面的例子。

问题定义

papazachariasaPixabay 上拍摄的照片

在一些面向客户的软件/web 开发中,当我们在 UI 中显示一些敏感信息时,我们可能需要隐藏这些信息。例如,我们有这样一个包含用户手机号码的字符串:

s = "User's mobile number is 1234567890"

如果我们想用星号隐藏手机号码,这并不太难。

import res_hide = re.sub('\d', '*', s)
print(s_hide)

re是 Python 中的内置库,所以我们可以简单地导入并使用它。这里我们使用re.sub()函数,它有 3 个参数:

  1. 正则表达式模式将用于匹配字符串中的模式
  2. 我们要用来替换字符串中每个模式的字符串
  3. 原始字符串

但是,大多数情况下我们可能并不想隐藏一切。例如,我们可能希望只显示最后 3 个数字,这样用户就可以得到我们在这里提到的手机号码的提示。这是一个非常常见的密码重置用例。我们不想显示手机号码的所有数字,因为我们不想向任何未经授权的人透露该号码,但同时,我们希望提供几个数字作为用户经过身份验证的提示。

这意味着我们所期望的如下:

User's mobile number is *******890

让我们把它变得更复杂。如果一个字符串中有多个数字,我们想隐藏其中的一部分,该怎么办?

s = "UserID: 12345, Mobile Number: 1234567890"

假设我们有一个用户 ID 和手机号码,我们想只显示用户 ID 的后 2 位和手机号码的后 3 位,这是如何实现的?使用re.compile()re.search()还是其他功能?

我确信有很多解决方案,但我认为使用re.sub()是最直观的,也是可读性最好的。让我们看看如何实现这一点。

将功能传递到re.sub()

照片由 MarandaPPixabay 上拍摄

在关于re.sub()的 Python 官方文档(见参考文献部分)中,我们可以发现该函数的签名如下:

re.**sub**(*pattern*, *repl*, *string*, *count=0*, *flags=0*)

让我们注意第二个参数,我们已经介绍了这个参数,它将用于替换在字符串中找到的模式。然而,文档说它也可以是一个函数。

返回用替换 repl 替换字符串模式最左边不重叠出现的字符串。如果没有找到模式,字符串不变地返回。 repl 可以是字符串也可以是函数

让我们看看如果我们传递一个函数作为第二个参数会发生什么。

def replace(term):
    print('Matched term: ', term)
    return '*'s = "UserID: 12345, Mobile Number: 1234567890"
s_hide = re.sub('\d+', replace, s)

太酷了!我们定义了一个名为replace()的函数,并将其作为第二个参数传递。然后,在我们的replace()函数中,我们可以有与模式匹配的term

看起来我们可以用这个term做很多事情。在 Python 文档的同一个页面上,我们可以看到有一个例子告诉我们使用.group(0)来获取匹配的字符串,返回的字符串将用来替换这个匹配的词条。

让我们做一个测试。

def replace(term):
    print('Matched term: ', term.group(0))
    return term.group(0)s = "UserID: 12345, Mobile Number: 1234567890"
s_hide = re.sub('\d+', replace, s)
print('String should not change: ', s_hide)

有用!我们找到了两个匹配的术语。同样,因为我们将term.group(0)返回,所以字符串没有改变。

好的。现在,很明显,我们可以转换函数中的项,然后将它传递回来。那么,我们应该这样做。

def replace(term):
    if len(term.group(0)) == 5:  # UserID
        return '***' + term.group(0)[-2:]
    elif len(term.group(0)) == 10:  # Mobile
        return '*******' + term.group(0)[-3:]
    else:
        return term.group(0)s = "UserID: 12345, Mobile Number: 1234567890, Age: 32"
s_hide = re.sub('\d+', replace, s)
print(s_hide)

这正是我们想要的!在这个例子中,我还添加了一个年龄,它也是数字,但假设我们不想隐藏它。这个功能运行得很好。

其他提示

照片由pix abay上的自由照片拍摄

如果您已经阅读了参考资料中附带的文档页面,您可能会注意到还有一个名为subn()的函数。老实说,在我重新检查文档之前,我从来不知道这个功能,但我相信它在某些情况下非常有帮助。

函数subn()的作用与sub()相同。唯一的区别是,它还会返回匹配了多少个terms(不一定被替换,因为它是我们定义的函数来决定如何替换)。

出于测试目的,让我们重复这个字符串 10 次。

s = "UserID: 12345, Mobile Number: 1234567890, Age: 32.\n" * 10
print(s)

然后,让我们将re.subn()与我们之前定义的replace()函数一起使用。这里我们需要将结果解包到两个变量中,因为它将返回一个元组。

s_hide, num_matched = re.subn('\d+', replace, s)print('String with hidden ID and Mobile:\n', s_hide)
print('Total number of users: ', int(num_matched/3))

因此,如果你想做下面的两件事,你现在可以在单个函数中实现它们!

  • 统计字符串中模式的出现次数
  • 替换字符串中出现的所有模式

感谢 Eric PASCUAL 在我的代码和解释中发现了一个错误。重要的是澄清re.subn()方法将返回匹配而不是替换的术语数量,因为如何替换术语是在我们的定制函数中定义的,而不一定被re.subn()函数检测到。

摘要

照片由 Engin_AkyurtPixabay 上拍摄

在本文中,我介绍了如何以更高级的方式使用函数re.sub()。它不仅可以帮助我们替换字符串中某个正则表达式模式的所有出现,还支持深度定制的替换模式,因为它可以在一个单独的函数中完成。

本文中的所有代码都可以在这个 Colab 笔记本中找到:

[## Regex sub()示例

Python re.sub()和 re.subn()函数示例

colab.research.google.com](https://colab.research.google.com/drive/1eZ5QWo17fGIorISEYeFDe0WZdWpE2o-e?usp=sharing) [## 通过我的推荐链接加入 Medium 克里斯托弗·陶

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@qiuyujx/membership)

如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)

参考

Python 文档:re . sub()
https://docs.python.org/3/library/re.html#re.sub

一个数据科学计划,以提高你的 ML 问题解决技能的酒吧

原文:https://towardsdatascience.com/a-highly-recommended-data-science-program-de46eae796ea?source=collection_archive---------39-----------------------

一位在线微大师将为你的数据科学职业生涯提供助力

蒂姆·莫斯霍尔德Unsplash 上拍摄的照片

“教育没有止境。不是说你读了一本书,考了一个,学历就完了。整个人生,从你出生的那一刻到你死去的那一刻,都是一个学习的过程。”—吉杜·克里希那穆提

引用的相关性增加了多倍的 ML 从业者。随着海量数据的激增,市场越来越需要能够通过挖掘海量数据来解释和提供决策解决方案的候选人。

这种动态的需求要求不断提高自己在数据科学(DS)领域的技能。虽然对一些人来说这是一项沉闷的任务,但对另一些人来说却是一种纯粹的快乐。

如果你属于后一类,并且总是在寻找一个新的概念或者重温这些概念,仅仅是为了更新和验证你当前的理解,那么这篇文章就是为你准备的。

随着教育民主化的到来,学习从未如此简单。随着整个教育系统在疫情经历范式转变,在线学习成为新的规范。

谢天谢地(或者不是😊),有一大群数据科学 MooCs 帮助参与者准备进入 DS 职业生涯或晋升。

我最近完成了麻省理工学院统计学和数据科学的 Micromasters 项目的 3 门课程,我想分享一下这是多么丰富的经历。一般来说,当我们考虑选择特定课程的标准时,我们会检查课程主题的广度和深度,时间和金钱投资的回报是什么,在建立直觉方面的回报是多少。该计划在更大程度上符合所有这些要求。

麻省理工学院的 Micromasters 课程经过精心策划,为数据科学、机器学习和统计学奠定了坚实的基础。

Micromasters 计划是一系列课程,旨在提供与特定职业领域相关的更深层次的概念性理解。参与者在完成 Micromasters 后,可以申请该大学更快、更便宜的硕士学位。

麻省理工学院微硕士课程的完成也使一个人有资格成为麻省理工学院校友会的会员,该校友会有各种好处,例如:

  • 访问 Micromasters 证书持有人和图书馆期刊的在线目录
  • 一些麻省理工学院校友会活动的邀请,有资格在所有麻省理工学院的新闻出版物和在 edx 主办的麻省理工学院课程上获得折扣

该计划期望大学水平的微积分和数学推理和 Python 编程的舒适。

项目涵盖的课程:

它由 4 门强化在线课程(和一门顶点课程)组成,每门课程预计每周 12-14 小时,持续 13-16 周。

  • 概率:麻省理工学院教授了几年的经典概率课程,内容包括离散或连续随机变量、贝叶斯推理方法、随机过程(泊松过程和马尔可夫链)
  • 社会科学中的数据分析:因果关系,分析随机实验,&非参数回归
  • 统计学基础:参数估计、假设检验、使用拟合优度的模型选择
  • 使用 Python 的机器学习:线性和非线性分类器、神经网络、无监督学习、强化学习、SGD、推荐器问题、协同过滤、生成模型、混合、EM 算法
  • 顶点考试:虚拟监考考试,以获得微观硕士证书

结束语:

这是我经历过的最累人的数据科学项目之一,但在概念的内化方面回报同样巨大。包括概率和统计等课程使其成为一个非常全面的数据科学项目。

你将开始编写各种 ML 模型的实现,从线性模型到深度学习和强化学习。

即使到目前为止你已经在你的数据科学旅程中学习了机器学习的基础——统计学和概率,我仍然建议你报名参加这个项目。你将有新的东西要学——建立 ML 算法背后的直觉或作为 ML 基础的复习。

我希望这篇文章能给你足够的动力去检查项目课程,并融入学习的世界!!!

声明:这不是为了做节目的营销。写这篇文章的唯一原因是分享它如何有效地巩固了我职业生涯中 ML 的基础。我希望在整个 ML/DS 社区分享这些知识。

人工智能的历史——从头开始

原文:https://towardsdatascience.com/a-history-of-artificial-intelligence-from-the-beginning-10be5b99c5f4?source=collection_archive---------46-----------------------

人工智能的历史远早于图灵,甚至早于计算机。

从简单机器到民主 AI 的时间线(非线性时间轴)。由作者在 Apteo 创作。

在关于人工智能的开创性论文中,题为 计算机械和智能 ,艾伦·图灵提出了一个著名的问题:“机器能思考吗?”—或者,更准确地说,机器能成功模仿思维吗?

70 年后,答案仍然是“不”,因为一台机器还没有通过图灵测试。

图灵澄清说,他对“旨在执行任何可以由人类计算机完成的操作”的机器感兴趣。换句话说,他对复杂的数字机器感兴趣。

既然具有思维能力的数字机器的实现事关机器的进化,那就从机器历史的开端说起吧。

机器的历史

机器是一种做功的装置。在工程术语中,的意思是将能量从一个物体转移到另一个物体。机器使我们能够施加更大的力,或者更有效地工作,从而完成更多的工作。

波士顿动力公司的机器人从 2009 年到 2019 年的演变。

现代机器——就像上面的波士顿动力机器人一样,Atlas——使用数百个零件,包括液压接头、活塞、齿轮、阀门等等,来完成复杂的任务,比如自校正稳定,甚至后空翻。

简单的机器

然而,“简单的机器”也符合我们早先的定义,包括轮子、杠杆、滑轮、斜面、楔子和螺丝钉。事实上,所有的机械都是由这六种简单的机器组合而成的。

图册不仅仅是机械机器,还是数字机器。

简单的机械机器已经有几百万年的历史了。例如,“石头切割工具[一种楔子]和人类社会一样古老,”考古学家发现了“150 万到 200 万年前”的石头工具

复杂的机器

简单机器的组合可以用来制造任何东西,从手推车到自行车到机械机器人。

事实上,机械机器人的记录可以追溯到 3000 多年前。

写于公元前 5 世纪的道教文献 【列子】记载了周穆王(公元前 1023 年至公元前 957 年)和一位名叫颜石的工程师的一次更早的会面。颜石向国王赠送了一个真人大小的人形机械机器人:

”国王惊讶地盯着那个身影。它迈着大步,上下移动着它的头,这样任何人都会把它当成一个活生生的人。工匠摸了摸它的下巴,它开始唱歌,完全合拍。他摸了摸它的手,它开始摆姿势,保持着完美的时间……当表演接近尾声时,机器人眨了眨眼睛,并向在场的女士们示好,于是国王变得愤怒,如果不是后者在致命的恐惧中,立即把机器人撕成碎片,让他看看它到底是什么,他会当场处决颜氏。事实上,它只是一个由皮革、木材、胶水和油漆构成的建筑……”

机械心脏图。日期未知。

国王问道:“人类(创造机器)的技能能与伟大的自然(上帝)作者的技能相提并论吗?”

换句话说,图灵关于机器能否模仿人类的问题其实已经有几千年的历史了。

与此同时,希腊科学家正在创造各种各样的自动机。阿尔库塔斯(约公元前 428-347 年)创造了一种能飞约 200 米的机械鸟,被描述为一种鸟形的人工蒸汽推进飞行装置。

"阿尔库塔斯用如此精巧的机械和艺术制作了一只鸽子的木制模型,以至于它能飞起来。"

一些现代历史学家认为,这可能得益于电线的悬挂,但无论如何,这显然是为了创造一台机器。

另一位希腊科学家代达罗斯创造了会移动的雕像:

"据说代达罗斯创造了栩栩如生的雕像,它们可以自己移动。"

“第一座布谷鸟钟”在《亚历山大的兴衰:现代世界的发源地》一书中有所描述(第 132 页);

很快,克特西比乌斯的钟就被塞住了,它们控制着一系列装置,从铃铛到木偶,再到唱歌来标志每个小时过去的机械鸽子——这就是第一个布谷鸟钟

几个世纪以来,越来越多复杂的装置被用来创造自动机,如风力驱动的移动机器。

可编程复杂机械设备

直到公元九世纪CE才出现了第一台有记载的可编程的复杂机械机器:

已知最早的可编程机器设计是 9 世纪巴格达的穆萨兄弟描述的自动长笛演奏器

这也被描述为“自我演奏的乐器”一本关于这些设备的书保存在梵蒂冈图书馆。

**创意成果中的秘密之书ZKM·卡尔斯鲁厄,摄影:哈拉尔德·沃尔克尔。由 ZKM·卡尔斯鲁厄和梵蒂冈图书馆提供。

机械计算机器

通往现代人工智能的漫长道路上的另一步是机械计算器的发明。

第一台机械计算器是由威廉·席卡在 17 世纪上半叶制造的,允许加法和乘法。

Schickard 的计算器。图宾根大学提供。

下一台由布莱士·帕斯卡制造的机械计算器也可以进行减法运算。

这些机器启发了像戈特弗里德·威廉·莱布尼茨这样的思想家去思考下面的想法:

如果人类经验的每一个领域都可以通过数学思维来理解,如果思维是一种计算形式,并且计算可以机械化,那么原则上所有关于现实的问题都可以通过机器执行的计算来回答

在很多方面,这类似于我们今天的人工通用智能概念。

莱布尼茨的想法是,一个特性一个普遍性,或一个普遍的逻辑程序,可以回答所有关于现实的问题。

可编程计算机器

1833 年,查尔斯·巴贝奇将 9 世纪可编程机器的创新和 17 世纪计算机器的创新结合起来,构想出了一种分析引擎:可编程计算机器。

查尔斯·巴贝奇分析引擎的一部分(完成于 1910 年)。在巴贝奇于 1871 年去世时,这部分建筑只完成了一部分,它包括“磨坊”(功能上类似于现代计算机的中央处理器)和一个印刷机构。伦敦科学博物馆。

巴贝奇从未制造出一台完整的机器,但他的“穿孔卡片技术”后来被用于第一批数字机器。

数字机器(计算机)

从机械计算机到数字计算机的转变是我们今天的巨大飞跃。

在 20 世纪 30 年代末到 40 年代,出现了几台数字计算机,竞争“第一台数字计算机”的位置

ENIAC 被广泛认为是第一台数字计算机,于 1946 年完成建造,因为它是第一台具有完整功能的计算机。

鸣谢:计算机历史博物馆

其他的数字计算机包括 1943 年的巨像,它帮助英国密码破译者阅读加密的德国信息,以及 1942 年的 ABC 计算机。

从这里开始,进步迅速加快,在内存中存储程序、RAM、实时图形和晶体管等进步相对较快地相继推出。

机器学习

最后,随着复杂的数字机器的出现,我们可以讨论机器学习的主题。

正如一开始所探讨的,机器的兴起促使艾伦·图灵在 1950 年提出了一个问题:“机器能思考吗?”五年后,达特茅斯大学发表了一篇关于人工智能的开创性论文,自那以后,该领域的基本原则一直保持相似。

1955 年,M.L .明斯基写道:

一个“机器可以通过“试错”过程被“训练”以获得一系列输入输出功能中的一个。这样一台机器,当它被放在一个合适的环境中,并给出一个“成功”或“失败”的标准时,它可以被训练成表现出“寻找目标”的行为。”

换句话说,机器学习算法在“训练数据”上建立数学模型来做出决定,而不是通过显式编程来做出这些决定。

这是计算器和机器学习(或人工智能)之间的关键区别:计算器或任何形式的自动机都有预先确定的输出。人工智能即时做出概率决策。

机械机器也有更严格的物理限制,在一个装置中可以安装多少机器组件(如滑轮、杠杆、齿轮)方面,而现代数字机器的 CPU 可以安装数十亿个晶体管。

“机器学习”这个词是阿瑟·塞缪尔在 1952 年发明的,当时他开发了一个用死记硬背的方法玩跳棋的计算机程序。

在 IBM 701 上玩亚瑟·塞缪尔的跳棋。信用: IBM

1957 年,Frank Rosenblatt 创造了 Mark I 感知器——一种二进制分类器的监督学习算法——用于图像识别。

在 1958 年向美国海军展示了他的工作后,《纽约时报》报道了:

感知机是“电子计算机的胚胎,海军期望它能够行走、说话、看、写、自我复制并意识到自己的存在。”

甚至在 1958 年,研究人员就预见了人工智能有感知能力的一天。

后来的成就包括前馈神经网络(像一个感知器,但有多层),67 年的最近邻算法,70 年代计算机上的反向传播(现在用于训练深度神经网络),90 年代初的助推算法,97 年的 LSTMs

数据和计算能力带来的改进

在首席人工智能研究员吴恩达最近的人工智能课程中,他指出,在人工通用智能方面“几乎没有进展”,但在“狭义智能”方面取得了令人难以置信的进展——输入输出功能“做一件事,比如智能扬声器或无人驾驶汽车。”

在高层次上,人工智能仍然是关于“学习一个从 x 映射到 y 的函数。”

我们最近看到的令人难以置信的进步主要是由于数据和计算能力的爆炸,以及更好的(更高质量的)数据和更多的人工智能工程师。

更多的数据和计算能力自然会提高大多数人工智能模型的准确性,尤其是在深度学习方面。

鸣谢:吴恩达《机器学习的向往》。**

AI 的民主化

随着人工智能架构、计算能力和数据的发展,人工智能最近在行业中占据了一席之地,这要归功于更容易获得的人工智能工具的激增。

让技术变得更容易使用的工具的出现有很长的历史。例如,古腾堡的印刷机在 15 世纪使知识民主化。

约翰内斯·古腾堡,1904 年重建。

在互联网时代,像 Wordpress 和 Wix 这样的“无代码”工具使网站建设民主化。

同样,在 50 年代人工智能提出后的几十年里,人工智能在很大程度上仅限于学术界,没有看到多少实际用途。

TensorFlowKeras 这样的工具使更多的企业实现人工智能变得可行,尽管它们仍然是技术复杂的工具,需要使用高薪的机器学习工程师。

加剧这一复杂性的是,数据科学专业人员的短缺导致那些可以创建人工智能系统的人获得天价薪酬。结果,像 FAANGs 这样的大公司控制了 AI 的大部分。

Apteo 这样的无代码人工智能工具的出现降低了前期成本,同时消除了对技术专业知识的需求,实现了真正民主化的人工智能。

没有代码 AI

无代码人工智能工具是民主化人工智能道路上合乎逻辑的下一步。

200 万年前,早期人类制造了石头切割工具,能够比用手做更多的工作。

今天,AI 使我们更加高效,可以为我们做工作,而无代码 AI 则为每个人带来这些好处。

随着无代码人工智能工具的兴起,我们正在走向一个无障碍人工智能的时代。

人工智能将标志着政治史上的一个转折点

原文:https://towardsdatascience.com/a-i-will-mark-a-turning-point-in-the-history-of-politics-e78e4a961e69?source=collection_archive---------17-----------------------

马库斯·斯皮斯克在 Unsplash 上的照片

科技如何让世界变得更加民主

科技对政治影响的证据无处不在。在大多数情况下,它被视为对民主体制基础的明确而紧迫的威胁。从对选举黑客和数据监控的担忧,到脸书广告和谷歌搜索结果中加权算法的影响,无论你走到哪里,新兴数据技术似乎都被认为是文明衰落的原因。

人工智能在政治上承诺通过加强政府官员和人民之间的联系,在事实上恢复更直接和更具代表性的民主。

尤其令人担忧的是人工智能,它正以惊人的速度扩大我们收集和解释数据的能力。对新科学的危言耸听的反应由来已久。我们的世界必须努力应对人工智能和机器学习带来的合法挑战和困境,但我们也应该追求这些新能力的好处。虽然技术进步对政治的渗透是不可否认的,但人们往往没有认识到这些应用在加强我们的民主价值观和政府运作方面的巨大潜力。

人工智能正在以惊人的方式改变世界,并将带来更大的变革,影响人类努力的所有领域——从社会互动和医疗保健到国际关系和军事行动。政治也不例外;人工智能的出现标志着人类最古老领域之一的一个全新时代的开始,除了明显的负面影响外,它还将产生巨大的积极用途。

直面民主

几千年来,自由民主的批评者认为,自由民主并不代表真正的“民主”,即公民做出政治和经济决策。事实上,当我们说国家是“民主的”时,我们指的是它们是“代议制共和国”,因为民主的原始含义(人民的直接统治)只在古代雅典实行。

越来越多的政治家使用人工智能数据分析研究人们的观点,然后将他们的观点与公民的观点相适应,以获得更多的支持者。

代议制共和国中出现的主要问题是,代表们经常违背自己的承诺,无法促进其选民的利益——甚至选择成为特殊利益集团的说客。因此,反对当今社会制度的人认为,政府官员和公民之间固有的差距意味着代议制共和国不会促进民主多数的利益。

然而,人工智能在政治中的应用有望通过加强政府官员和人民之间的联系,在事实上恢复更直接和更具代表性的民主。越来越多的政治家使用人工智能数据分析研究人们的观点,然后将他们的观点与公民的观点相适应,以获得更多的支持者。巴拉克·奥巴马 2012 年的总统竞选、2016 年的唐纳德·川普以及 2014 年的印度选举中的纳伦德拉·莫迪都是成功运用这一策略的政治家的典范。

一个政治家所拥有的最伟大的才能之一是通过展示他或她对选民的兴趣并真诚地试图理解他们的世界观来吸引选民的能力。这样的政治家很少见;然而,随着机器学习在选举中的使用,每个人的意见都将受到关注,人工智能算法将选民和政治家直接联系起来。人工智能将弥合代表和公民之间的差距,人们的意见将得到考虑,从而促进民主进程。

用著名人工智能专家佩德罗·多明戈斯的话来说,多亏了人工智能,“民主运作得更好,因为选民和政治家之间的沟通带宽大大增加了。”

Adolfo Félix 在 Unsplash 上拍摄的照片

数据驱动的政策制定

人工智能将帮助我们在政治和经济上做出更好的决定。机器学习、数据科学和预测分析在治理中的使用可以让决策者追求循证政策,人工智能可以提供一个国家需要什么以及如何解决问题的精确图像。例如,通过利用预测分析,人工智能专家可以识别经济中可能引发衰退的潜在漏洞,并就如何应对这些漏洞提出建议。事实上,在人工智能驱动的经济中,准确地预测和最小化商业周期的负面影响是可能的。

人工智能可以减少政治决策过程的“政治性”和党派性,更多地以证据为基础——通过在只需要更彻底调查以达成妥协的问题上达成共识,可能会减少两极分化。

数据驱动的决策将使民主制度更好地运作,使政府能够更好地回应公民的需求,并以最有效的方式提供公共服务。决策者可以依赖数据和人工智能算法,而不是依赖个人经验、非理性本能、被误导的教条或有害的偏见和成见。

正如丹尼尔·埃斯蒂(Daniel Esty)和里斯·拉什(Reece Rushing)所写的那样,“新的信息技术使得一系列的监控机会、数据交换、分析调查、政策评估和绩效比较成为可能,而这在几年前还是不可能的……就目前的情况来看,制定政策就像在午夜穿越浓雾一样。巨大的数据差距使得我们很难清楚地看到问题,并制定出前进的路线。”通过利用人工智能技术,我们可以弥合阻碍有效数据驱动决策的数据差距。

人工智能可以减少政治决策过程的“政治性”和党派性,更多地以证据为基础——通过在只需要更彻底调查以达成妥协的问题上达成共识,可能会减少两极分化。

每一个自由民主的内在特征是从错误中学习和适应变化的条件的能力。在这方面,开放社会的功能类似于机器学习的“强化学习”范式,其中软件不断从其环境中学习,以不断改进自己。将先进的强化学习算法应用于政治将大大提高政府的效率。毕竟,数据越多,现有算法的功能就越好,让数据驱动的决策者能够追求更有效的治理。

历史上,开放社会比封闭社会更成功,因为前者在信息处理方面的内在效率。中央集权的国家使用集中的数据处理,而开放的社会则分散在多个数据处理单元中。分布式处理已被证明是一种更有效的模式——如果多个处理器(政府、非政府组织、企业、民间社会)中的一个出现故障,其他处理器会很快发现并纠正错误。在独裁政权中,只有一个决策者。如果这个决策者是一个有才华、聪明的领导人(比如后教员时代的中国),这个国家可能会取得一些成功,但即使是一个小小的错误也可能带来灾难性的后果,因为没有人来纠正它。

然而,很快,有利的天平可能集中式系统倾斜——毕竟,算法在处理更多数据时工作得更好,在集中式系统中,所有数据都集中在一个处理器中。

随之而来的是,由于将面临来自威权国家的竞争,开放社会将更加集中决策以提高效率——或者至少所有数据将由政府收集,然后政府将与私人公司和公民协商以做出更好的选择。

从社会研究到社会科学

也许人工智能最大的承诺是它有可能使社会“科学”成为真正的科学。社会科学(如政治和经济)的主要问题是,由于实际事态和人们对世界的解释之间的差异,很难做出可靠的预测。

如果摩根大通宣布,它创造了一种可以以 98%的准确率预测股市行为的人工智能算法,然后定期在推特上发布预测,股市本身的行为就会发生变化。相反,牛顿定律或爱因斯坦相对论的发现根本不会影响宇宙定律。

例如,在天文学中,如果我们观察恒星的行为,我们只是观察者,因此我们获得的知识不会影响事件的进程;星星不会因为我们看着它们而移动。然而,如果世界银行修改其经济增长预测,那么现实本身将随着市场参与者改变其行为而改变,预测可能变得不准确。

另一个例子:如果摩根大通宣布,它创造了一种可以以 98%的准确率预测股市行为的人工智能算法,然后定期发布预测,股市本身的行为就会发生变化。相反,牛顿定律或爱因斯坦相对论的发现根本不会影响宇宙定律。

社会科学无法解决这一根本缺陷:无法将人们的偏见、成见和误解导致的不确定性因素考虑在内。然而,人工智能的出现可以让社会科学家更好地解释人类行为。毕竟,大型金融机构已经在使用算法来预测股市走势和资产价格。考虑到人工智能技术进步的惊人速度,我相信人工智能将使我们能够把社会学科变成真正的“科学”。在过去,由于社会科学固有的不确定性,很难对现有挑战提出明确而准确的解决方案(例如,在对抗衰退时在多大程度上使用货币和财政政策,或者当政治对手做出意外举动时选择哪种方案)。

完成这一壮举将标志着社会科学史上最重要的里程碑。通过消除不确定性,我们将能够最终就复杂的政治问题和经济问题达成共识,促进社会凝聚力和稳定,并帮助我们更接近实现人类对世界的最终理想——因为解决全球问题的最大障碍是无法促进共同的态度和找到精确的解决方案。

然而,人工智能将改变游戏规则——而且这一次,是以积极的方式。

原载于 人类事件

从仪表板到数据驱动型组织的旅程。

原文:https://towardsdatascience.com/a-journey-from-dashboards-to-a-data-driven-organization-b6f8dcdbc32e?source=collection_archive---------47-----------------------

跟随我的旅程

被遗忘的一步:实施、跟踪和跟进。

大卫·蒙涅Unsplash 上拍摄的照片

在上一集中,我介绍了一个以用户为中心的构建仪表板的过程。现在它已经准备好了,您最常观察到的是:

  • 向所有用户发送一封电子邮件,宣布该仪表板的可用性
  • 就是这样。

这是一个非常大的问题。如果你还记得,我们说过关键是要记住,仪表板是用来帮助人们做决定的。因此,我们实际上需要授权他们这样做。

实施阶段

实现仪表板需要将仪表板实际呈现给最终用户。要做好这一点,需要涵盖 3 个方面:

  • 为什么会有这个仪表板
  • 仪表板中有什么
  • 如何使用仪表板做出决策

这个简单的框架来自于我在医疗器械行业教育领域十年的经验。大多数时候,教育仅限于展示产品的特性。问题是,如果人们不明白为什么他们甚至应该知道这些功能,他们不会听。

为什么

确立“为什么”是让你的听众倾听的关键。它需要你知道你的观众面临的问题是什么。

如果你读过上一集,你会记得我坚持认为你需要对最终用户和他们的需求保持好奇?好吧,这又是非常有用的。如果没有,你就不会和他们联系,他们就不会听你的,你就达不到你的目标。

以我的经验来看,最好的表达方式是讲故事。越有趣越好。这将起到打破僵局的作用,让人们真正倾听你在说什么。

当您在为最终用户构建工具时与他们进行讨论时,找到这样的例子应该是您要考虑的事情之一。事实上,在这些讨论中,你应该听到很多。所以,如果你没有想到,你可能没有和你的最终用户进行足够的交流!不是你做的,而是你听得不够好。

解释为什么不应该花超过几分钟的时间——这为接下来的演示做好了准备。

什么

一旦你知道了为什么,你就可以继续做什么了。您的仪表板显示什么数据点?

这是一个举办数据素养课程的绝佳机会,但它并不被称为数据素养课程!再次强调,了解您的受众是关键,因为您需要根据群体的数据素养水平定制内容。

在我职业生涯的早期阶段,我得到了三条非常有用的建议,它们是

  1. 总是从高层次到详细层次解释,而不是相反。因此,例如,在你向人们解释你正在寻找的比率之前,确保他们理解你正在使用的术语(每个组织都有自己对“销售”、“客户”、“活跃客户”等等的定义)
  2. 翻译。对于每个数据点,举一个例子,说“所以在这里,用文字来说,它的意思是…”
  3. 永远不要假设人们明白了,总是问是否每个人都明白了。在一个理想的世界里,你会让一些人拿起一个例子并翻译它。

怎么

最后,您准备好将所有东西放在一起,并向他们展示如何实际使用该工具来做出决策。

在这里,它意味着你已经与一个关键的利益相关者(理想的是你正在演示的团队的团队领导)一起工作,确定最终用户需要采取的决策的几个例子,并指导他们通过这个过程。如果团队领导想亲自动手就更好了。

如果可能的话,让几个参与者根据你和团队领导制定的场景进行角色扮演。那么你真的确定他们真的可以使用仪表板来实现它的目的。

跟踪和跟进

定量和定性跟踪是基础。

数量的

借助大多数可用的 BI 工具,您将能够获取利用率数据,并了解谁在连接、连接频率和连接时间。这有助于跟踪工具的采用,并且很好地代表了团队的信念,即这将有助于他们实现目标。

但这并不能真正告诉你这是否有助于他们做决定。真正有趣的是跟踪利用率预期结果。例如,对于一个销售团队,使用频率和产生的收入之间有关联吗(当然,假设主要目标是产生收入)?或者使用频率和目标实现之间的关系?如果你从事数据工作,你就会明白我的意思了!

这些数据应传达给最终用户的管理人员,并提供给他们使用。同样,这旨在帮助他们做出更好的决策。例如,增加对特定销售代表的指导,或确保最佳销售代表与其他人分享他/她的最佳实践。

定性的

除了定量跟踪之外,跟踪定性方面也很重要,并在此过程中获得反馈以改进仪表板。

是否有人们从未使用过的数据点?压制他们。

是否缺少数据点?添加它们。

对于一个特定的图表,你是否总是得到同样的问题?改变它。

这可以通过小组汇报(在线或离线)、问卷调查或一对一讨论来完成。最后一个选项是我最喜欢的。走出办公室,去观察人们实际上是如何在现场使用该工具的,建立联系并进行适当的对话。好奇。

后续行动

除了基于上述跟踪所做的改进,不要忘记我们是在一个快节奏的环境中离开的。今天相关的事情明天可能就不相关了。产品变了,商业优惠变了,团队变了,策略变了。跟上业务中发生的事情,确保你的工作保持相关性。

正如我在上一集所说,这不是一个线性过程,而是一个循环过程。

柴坦尼亚电视台在 Unsplash 拍摄的照片

你也可以在我的 medium 系列上跟随我的旅程。

[## 从仪表板到数据驱动型组织的旅程。

现在有人说仪表板是过时的工具。

medium.com](https://medium.com/series/a-journey-from-dashboards-to-a-data-driven-organization-84bdcbdc3014)

从仪表板到数据驱动型组织的旅程。

原文:https://towardsdatascience.com/a-journey-from-dashboards-to-a-data-driven-organization-what-goes-wrong-with-dashboarding-9815619bb71a?source=collection_archive---------52-----------------------

跟随我的旅程

仪表板出了什么问题?

照片由 chuttersnapUnsplash 上拍摄

现在有人说仪表板是过时的工具。

我认为它仍然是构建数据驱动型组织的垫脚石。

原因如下:

  • 它让我们让人们习惯于看到数据。
  • 它允许您确定知识差距并建立相关的数据素养计划。
  • 它允许您开始展示数据对业务的影响。

因此,让你的仪表板正确是关键。

为此,我将分享我使用的框架。

大多数 BI 团队遵循 3 个步骤来构建仪表板:

  1. 定义
  2. 样机研究
  3. 构建和部署

定义是我们试图理解需求,从而明确需要什么数据点的阶段。

原型是我们迭代检查我们是否满足用户需求的时候。

最后一旦完成,我们就开始构建(在我们的最终工具中,通常原型是在 excel 或 google sheet 中完成的),然后部署。

我相信这个过程经常失败,有三个主要原因。

  1. 定义阶段缺乏适当的流程,而且通常没有合适的人参与。 这个阶段的讨论通常是非结构化的,这会导致我们错过更大的图景,从而错过我们的目标。它们很少涉及最终用户,这是我的经验中最大的错误之一;好消息是它很容易修复!
  2. 这个过程的最后还缺少一个关键步骤:实施跟踪跟进。说起来有点可笑,为其他部门建立跟踪他们活动的能力的团队经常无法跟踪自己的活动。
  3. 有一种普遍的误解,认为构建仪表板是一个线性过程(定义、原型、构建、部署——下一步),而实际上是一个循环过程。

是的,我的书写非常糟糕。

后果是相当巨大的。终端用户不使用该工具,我们无法展示数据对业务的影响,因此我们无法向数据驱动型组织迈出进一步的步伐。

以我的经验来看,我们可以避免这些陷阱,首先要明白仪表板是让用户做决定的。在整个流程中保持这种心态将有助于确保您提出正确的问题,让正确的人参与进来,并跟踪正确的 KPI。

让我们深入了解定义阶段的

我们将涵盖需要涉及的流程、人员和工具工具请注意,该框架是通用的,需要适应您的环境(初创企业与大公司,数据环境与非数据环境……)。

在谈论数据之前

该过程

在我们谈论数据之前,我们需要了解很多东西。还记得我们说过的我们需要牢记在心吗?仪表板是让人们做决定的。所以…让我们从了解开始

  • 仪表板是给谁的?
  • 那些人需要做什么决定?
  • 为了做出这些决定,他们需要什么信息?

然后,只有我们研究我们需要拉什么数据。这似乎是显而易见的,但这往往被忽视,或者做得太快,或者假设这些问题有许多答案。

让我举一个例子来说明为什么这是关键的一步。假设我们想要构建一个销售仪表板。是面向全球管理人员、区域销售管理人员还是面向现场人员?这些人可能都在同一个部门工作,但是他们需要做出非常不同的决定,因此需要不同的信息。有时可能是相同的数据,但聚合方式不同。这造成了巨大的差异。

  • 全球管理层可能需要决定世界上哪个地区比其他地区需要更多的投资。
  • 区域销售管理人员可能需要知道他们的销售团队中是否有可以利用的最佳实践,或者他们的指导是否带来了更好的结果。
  • 销售代表可能需要知道应该关注哪个客户。

这些都是需要做出的非常不同的决定。因此需要显示非常不同的信息。

这项工作需要对业务有很好的理解,最重要的是要有很强的好奇心和情商。

一些组织将促进这一部分,因为他们将是非常结构化的,团队将有非常好定义的 KPI——很容易。有些组织不会,这就是乐趣所在!

最近有很多关于分析翻译概念的讨论,分析翻译是企业业务和数据之间的桥梁。这就是它们非常强大的地方。它不一定是一个角色,取决于组织的规模。也可以是数据端情商强的人,或者是业务端有数据知识的人。

人民

在此阶段,让合适的人参与进来非常重要:

  • 利益相关者和/或高管(都在较大的组织中)
  • 最终用户(总是!理想情况下至少有 2-3 个)
  • 双性恋的
  • 最终,根据组织的规模

一旦您定义了您的小组,那么只有您可以开始回答我们上面列出的问题。我建议先进行一对一的讨论,然后召集所有人进行协调。

在一对一的讨论中,你应该进行真正的讨论,而不是浏览问题列表(也就是说,你不能通过在线问卷来完成!).关键是要了解人们在哪里,他们是否愿意看到仪表板,他们目前在看什么…等等。这将使你能够更多地了解你的受众(他们对数据的了解程度如何,他们有多渴望看到新的东西,他们是否已经有了他们认为足够的东西……?),从而制定相关的利益相关者管理策略。

总而言之,你正在开发一个产品——一个数据产品。在产品管理中应用的所有项目管理和利益相关者管理策略在这里也应该适用。

工具

在这个阶段,我喜欢开发一个简单的框架,即一个表(我知道,花式,花式!).看起来像这样的东西:

漂亮的桌子。

现在来说数据!

好,这就是我们开始谈论数据的时候。

既然我们知道每个人都需要哪些信息,我们就可以定义需要提取哪些数据,以及如何为每个目标群体聚集这些数据。

我不会讨论这一步——我们运行 SQL 请求,检查我们的数据等等。你知道该怎么做。

重要的是记住我们的仪表板是用来帮助人们做决定的!那么,我们如何确保这一点呢?

该过程

这里真正关键的是用户反馈。我喜欢做的是构建一个原型(在工具部分会有更多的介绍),然后做一些用户测试。当您定义了需要采取的决策后,您可以直接进入评估阶段,向一些最终用户(单独)提供您的原型,并要求他们采取一些列出的决策。

  • 不起作用?回去工作。
  • 它可以工作,但是很复杂?回去工作?
  • 工作容易吗?太好了!

通常需要几次迭代,直到你 100%正确。没关系。

人民

这里,好奇心和情商是关键。

除了评估最终用户是否能够根据原型做出决定,评估他们在现实生活中是否能够做到这一点也很关键。

是的,你知道,在它们通常的栖息地。他们的办公室,他们的车…任何他们需要的地方。

工具

我们可以在这里就什么是原型的正确工具进行长时间的讨论。

我个人喜欢在 excel 或 google sheet 中完成它们——只是因为它设定了预期,它是一个原型,人们不太倾向于提供关于布局、颜色等的详细反馈。在这个阶段,这真的不是重点。这个以后再说。

一旦原型稳定下来,我就开始使用 Bi 工具(Tableau、Power Bi、quick sight……无论你用什么),然后我们进行第二轮用户反馈,重点是布局细节。

然后——我们完成了!

丹尼尔·麦金尼斯在 Unsplash 上的照片

嗯……不尽然。这实际上只是一个开始。现在我们需要实施、跟踪和跟进。下集见讨论那个阶段!

你也可以在我的 medium 系列上跟随我的旅程。

[## 从仪表板到数据驱动型组织的旅程。

现在有人说仪表板是过时的工具。

medium.com](https://medium.com/series/a-journey-from-dashboards-to-a-data-driven-organization-84bdcbdc3014)

库伯内特斯的气流之旅

原文:https://towardsdatascience.com/a-journey-to-airflow-on-kubernetes-472df467f556?source=collection_archive---------4-----------------------

…或者我是如何让它一点一点地、合乎逻辑地运转起来的

当阿帕奇气流任务着陆图看起来更像波洛克的画(来源:作者)

简介

我对 Apache Airflow 的拙见:基本上,如果您有多个自动化任务要调度,并且您正在摆弄 cron 任务,即使它们的一些依赖项失败了,您也应该尝试一下。但是如果你不愿意接受我的话,请随意查看这些帖子。 深入研究气流概念及其工作原理超出了本文的范围。就此而言,请检查这些其他职位。t11】⁵

长话短说,它的任务定义是基于代码的,这意味着它们可以如你所愿的那样动态。您可以创建任务,并根据变量或条件定义任务相关性。它有大量的本地操作符(任务类型的定义) 将您的工作流与许多其他工具集成在一起,并允许您使用 Apache Spark 运行从最基本的 shell 脚本到并行数据处理,以及大量其他选项。贡献者操作员⁷也可以用于大量的商业工具,而且这个列表每天都在增长。这些操作符是 python 类,因此它们是可扩展的,并且可以根据您的需要进行修改。您甚至可以从零开始创建自己的操作符,从BaseOperator类继承。此外,使用它的分布式执行器(如 Celery 或 Kubernetes ),它使您的工作流可以轻松扩展到数百甚至数千个任务。

我们从 2018 年开始在 iFood 使用气流。我们的第一个实现非常好,基于 docker 容器在一个隔离的环境中运行每个任务。从那时起,它经历了很多变化,从一个服务于我们团队工作负载的简单工具到一个服务于 200 多人的任务调度平台,上面有很多抽象。最后,不管您是有多年经验的软件工程师还是 SQL 知识很少的业务分析师,您都可以使用我们的平台编写一个 yaml 文件来调度您的任务,该文件包含三个简单的字段:您的任务的 ID、包含您的查询的文件的路径及其表依赖项的名称(即,要运行我的任务,我依赖于表ordersusers),瞧,您已经将您的任务调度为每天运行。但不幸的是,这是未来文章的主题

拥有超过 1000 个任务的巨型 DAG 的一部分。其中大部分是由业务分析师或数据分析师安排的 Apache Spark / Hive 作业(来源:作者)

为什么是 Kubernetes?

很明显,我们需要将我们的应用程序从 AWS t2.medium EC2 实例扩展到更强大的东西。我们最初的方法是垂直扩展到一个r4.large实例,然后扩展到一个r4.xlarge,但是内存使用量一直在增加。

我们公司发展很快。每天都有几十个任务被创建,突然间我们将运行在一个r4.16xlarge实例上。我们需要一种方法来横向扩展应用程序,更重要的是,考虑到高峰时间来扩展应用程序,并在黎明时缩减应用程序,以最大限度地减少不必要的成本。当时,我们正在将所有平台迁移到 Kubernetes 集群上运行,那么为什么不迁移 Airflow 呢?

我在互联网上搜索,从官方的 Apache Airflow 文档到 Medium 文章,寻找如何在 Kubernetes 上使用KubernetesExecutor运行 Airflow 的简单实现的信息(我知道CeleryExecutor的存在,但它不符合我们的需求,考虑到您需要预先安排您的工作人员,没有本机自动伸缩)。我发现很多人都在谈论在 Kubernetes 上运行 Airflow 的好处,它背后的架构和一堆掌舵图,但很少有信息告诉我如何以一种符合逻辑的方式一点一点地为 Kubernetes 初学者部署它。这是本文的主要观点。假设您知道 Apache Airflow,以及它的组件如何协同工作,这个想法是向您展示如何利用KubernetesExecutor的优势部署它在 Kubernetes 上运行,并提供一些有关 Kubernetes 资源的额外信息( yaml 文件)。这些例子将是基于 AWS 的,但我确信,只需很少的研究,您就可以将信息移植到任何您想要的云服务,甚至可以在本地运行代码。

考虑

为了完全理解下面的部分并让事情运转起来,我假设您已经:

  1. 一个可用的 AWS EKS 集群,或另一种类型的 Kubernetes 集群,在本地或在云环境中。
  2. Kubernetes 和kubectl工具的基本“实践”知识。至少在如何部署资源以及检查它们的描述和日志方面。
  3. 关于 Apache Airflow 及其单元(配置、调度程序、web 服务器、数据库、Dag 和任务)的扎实知识

如果你没有,我建议你在当地玩一会儿 Kubernetes 和 Airflow。你可以在网上找到很棒的教程,甚至在官方网站上。对于 Kubernetes,您可以从 Katacoda 教程开始。关于阿帕奇气流,这是我尝试的第一个教程。

起点

首先,我找到了一种方法,可以从 Airflow git 存储库中的官方舵图中获取 Kubernetes 资源 yaml 文件。 给我带来了很多资源,其中一些是空的(可能是因为我使用了 base values.yaml来填充 Helm 使用的模板),还有一些对于KubernetesExecutor方法是无用的(也就是说,我不需要 Redis 集群,或者 Flower 资源,或者结果后端,因为这些是芹菜特有的)。除去那些无用的资源,我最终得到了大约 15 个资源文件,其中一些我当时甚至都不知道。有点势不可挡!我还删除了与 PostgreSQL 实例相关的所有资源(即 pgbouncer),因为我知道我将使用一个在 Kubernetes 集群外部的 AWS RDS 实例。

如何从 Apache Airflow 舵图导出 Kubernetes 资源 yaml 文件

Obs:我在本地有这些图表,所以当我执行helm template命令时,helm抱怨找不到 PostgreSQL 图表(如果您使用 Helm 存储库,这不会发生)。如果是这种情况,只需在包含你的舵轮图的文件夹中创建路径charts/,并将postgresql/舵轮图文件夹放入其中(可从官方舵轮图 github 库获得)。同样重要的是要注意,与我使用的图表相比,在 https://github.com/helm/charts提供的阿帕奇气流舵图表将带给你一组不同的资源。

经过所有的清理,我得到了这 12 种资源:

resources
├── configmap.yaml
├── dags-persistent-volume-claim.yaml
├── rbac
│   ├── pod-launcher-rolebinding.yaml
│   └── pod-launcher-role.yaml
├── scheduler
│   ├── scheduler-deployment.yaml
│   └── scheduler-serviceaccount.yaml
├── secrets
│   └── metadata-connection-secret.yaml
├── statsd
│   ├── statsd-deployment.yaml
│   └── statsd-service.yaml
├── webserver
│   ├── webserver-deployment.yaml
│   └── webserver-service.yaml
└── workers
    └── worker-serviceaccount.yaml

思考体积

我找到的大多数文章都描述了两种存储 DAG 信息的方法:将 DAG 存储在可从多个 AWS 可用性区域访问的持久卷上,例如 AWS 弹性文件系统(EFS ),或者将它们从 git 存储库同步到集群中挂载的临时卷。如果该 pod 终止,当创建另一个 pod 时,它将再次与存储库同步以获得最后的修改。

由于我们目前的工作流,我们需要从许多写在 yaml 文件中的任务动态构建我们的 Dag,这意味着当文件在 git 存储库上被版本化时,我们的 Dag 还没有准备好。一个简单的 git-sync 带来的信息对我们来说是不可行的,但它可能是一个起点。考虑到我们还需要日志的某种持久性,我们决定也采用 EFS 方法,使用我们在网上找到的某种混合方法:将我们的 yaml 文件 git-sync 到安装在 EFS 顶部的PersistentVolume中,并让另一个 pod 处理它,并将新构建的 Dag 扔进调度程序和 web 服务器不断查看以填充DagBag的文件夹中。

用于存储 Apache Airflow DAG 文件的持久卷配置

用于存储 Apache Airflow DAG 文件的 PersistentVolumeClaim 配置

基于 AWS EFS 的存储的存储类配置

如上所示,为了在 EKS 集群中挂载 EFS,我使用了官方的 AWS CSI 驱动程序, ,它必须安装在集群中。除了驱动因素之外,这种方法还占用了五种 Kubernetes 资源:

  • 2 个持久卷:Dag、日志
  • 2 个 PersistentVolumeClaim:Dag、日志(类似于前面的那些)
  • 1 节储物课

这些资源不在初始列表中,因为最初的部署使用了emptyDir卷。

我应该在哪里存储我的 airflow.cfg 文件?

任何使用过 Apache Airflow 一段时间的人都知道airflow.cfg文件(也许还有webserver_config.py文件)对于设置这些东西非常重要。但是将它放入 EFS 卷似乎并不明智,因为它包含敏感信息(数据库密码、fernet 密钥)。然后,我发现 Kubernetes 存储配置文件的方式是使用ConfigMap,这是一种“卷”,您可以将其安装在 pod 中,以便为它们公开配置文件。还有 Kubernetes Secret来存储敏感数据。它们一起工作,所以我可以在一个ConfigMap中引用一个Secret,或者甚至将一个Secret传递给一个环境变量。任务完成!

随着您对 Kubernetes 了解得越来越多,您会注意到在存储库中发布“普通”秘密有些不安全。它们包含 base64 字符串,可以在您的终端中使用base64 -d命令轻松“解密”。看看这个 ExternalSecrets API, 将您的秘密存储在 AWS 参数存储中,并从那里检索它们。

如果您检查上面的文件列表,您会注意到ConfigMap已经存在,您只需定制它。

好的,但是部署呢?

我在 Kubernetes 上的一点点经验足以让我认为我至少需要两个部署:一个用于调度器,一个用于web 服务器。它们就在那里,躺在舵轮图爆炸产生的schedulerwebserver文件夹里。还有第三个部署,是一个statsd应用程序,我后来发现它与应用程序内部的指标收集有关。酷,少了一件事要担心!普罗米修斯会乐意刮的。

我打开文件,注意到它们有一些熟悉的环境变量,与 fernet 键和数据库连接字符串相关。我用库本内特公司的秘密获取的数据填充了它们。我需要稍微调整一下音量部分,以匹配我的 EFS PersistentVolumePersistentVolumeClaim

气流调度程序的部署配置

很容易注意到这些 shell 脚本是作为 init 容器执行的。它们与气流开始时发生的数据库迁移相关。scheduler 窗格一启动就运行迁移,webserver 窗格在启动 webserver 容器之前一直等待迁移完成。webserver 部署具有非常相似的结构,所以我冒昧地省略了它。

Webserver 是一个…服务器!应该有与之相关的服务!

有过。公开容器端口 8080 的 Kubernetes 服务资源。后来我加入了一个Ingress资源,给它一个 AWS Route53 友好的 DNS。

Airflow 服务器的服务配置

statsd应用程序也在一个端点监听,并有一个与之相关联的服务。这两个服务都包含在由helm template命令导出的文件中。

嗯,应该可以的,对吧?

我尝试将这些配置应用到集群中。Scheduler 和 webserver 都启动了,它们都连接到我的外部 RDS PostgreSQL 数据库。我想:“如果我把一些 DAGs 扔进dags文件夹,那么它应该可以工作,对吗?”的确如此。我创建了一个简单的 DAG,其中有一个基于KubernetesPodOperator的任务,使用了存储在 AWS 弹性容器注册表中的容器映像。我仔细检查了我的 pod 是否被允许访问 ECR 存储库。

然后,我触发了 DAG,但是失败了(你真的没想到会那么容易吧?).检查日志时,我注意到它是由于某种权限问题而发生的。我的调度程序没有权限生成新的 pod。然后我明白了分散在文件夹中的ServiceAccount资源以及ClusterRoleClusterRoleBinding的需求。这些人允许你的资源产生新的资源。完成所有配置后,我可以让我的任务成功运行。KubernetesPodOperator也有service_account_name参数,应该用能够生成 pod 的ServiceAccount资源名来填充,因为这就是它要做的:用您作为参数传递给image参数的图像生成另一个 pod。那个舱将负责运行你的任务。

气流调度程序的 ServiceAccount 配置

如果你想直接从你的网络服务器上运行任务,点击任务菜单中的“运行”按钮,你必须给你的网络服务器ServiceAccount权限来观察和产生 pod。如果您忘记了这一点,您的任务将被触发,但它们永远不会运行。

作为可信实体的服务帐户

如果你在 AWS 上运行你的东西,你需要确保你的 pods 能够访问所有的 AWS 资源,比如 S3、DynamoDB 表、EMR 等等。为此,您需要将您的ServiceAccount资源绑定到一个附加了 IAM 策略的 AWS IAM 角色,以授予您所需的所有访问权限。只需为您的 IAM 角色提供一个假定角色策略:

允许 Kubernetes ServiceAccounts 承担具有所需权限的 IAM 角色的策略

您的员工和任务的ServiceAccount应与上述政策所附的 IAM 角色相关联。您可以使用注释来完成:

注释 AWS IAM 角色的 ServiceAccount 资源示例

现在,让那里有光!

如果您是作为一个教程来跟随这个旅程的,那么在所有的调整之后,您可以在您的集群中创建所有上述资源:

kubectl apply -f resources/ --recursive

但是,等等!暂时不要应用它们!如果你是一个细心的读者,你会注意到上面的大多数资源都引用了airflow-on-k8s名称空间。Namespace是一种告诉 Kubernetes 同一个名称空间中的所有资源多少有些关联(即它们是同一个项目的一部分)的方式,也是一种在集群内部组织事物的好方法。您应该在resources/文件夹中声明您的Namespace资源,并在应用其他所有资源之前应用它,否则您将得到一个错误。

声明 airflow-on-k8s 命名空间。小菜一碟,不是吗?

仅供参考,并不是 Kubernetes 上的每个资源都有名称空间(即PersistentVolumeStorageClass和其他低级资源),这就是为什么其中一些资源没有对名称空间的任何引用。

体系结构

这种方法如何工作的一个极简主义的表现(来源:作者)

收场白

这是我在 Kubernetes 上展开气流之旅的一个快进。我试图涵盖舵图导出生成的各种资源,但如果您认为我遗漏了什么,请在评论部分随意提问。

上面这些 yaml 资源来自我做的一个功能部署。其中一些是我从头开始构建的,另一些是我从导出的版本中改编的。我建议你花时间去理解它们,并为更好的组织和表现做出改变。

要充分利用这种实现,您还可以做更多的事情。您可以为部署中的容器设置limitsrequests字段,以确保它们拥有正常工作所需的资源。进一步了解 Kubernetes 的优势,您将会看到KubernetesPodOperator允许您标记您的 pod 并向其传递许多 Kubernetes 配置,例如亲和力耐受性和一堆其他东西。如果你有被感染的节点,你可以保证只有一些特定的 pods 会在上面运行,把最强大的节点留给最关键的任务。

如果你尝试过这个设置,并且有什么要补充的,有什么有用的或者是一个糟糕的选择,请在评论中告诉我们。

Kubernetes 上的气流(来源:基于官方徽标的作者组合)

[1]: 使用气流的十大好处:https://medium . com/analytics-and-data/10-Benefits-to-use-air flow-33d 312537 BAE

[2]: 我们为什么改用阿帕奇气流:https://www . solita . fi/en/blogs/Why-we-switched-to-Apache-air flow/

[3]: 罗宾汉为什么使用气流:https://robin hood . engineering/Why-robin hood-uses-air flow-aed 13 a9 a90 c 8

【4】:气流:如何及何时使用:https://towardsdatascience . com/air flow-How-and-when-to-use-it-2e 07108 ac9f 5

[5]:Apache air flow 入门:https://towards data science . com/Getting-started-with-Apache-air flow-df 1a 77d 7 B1 b

[6]: Airflow 原生操作符:https://air flow . Apache . org/docs/stable/_ API/air flow/operators/index . html

[7]:air flow contrib operators:https://air flow . Apache . org/docs/stable/_ API/air flow/contrib/operators/index . html

[9]: hgrif 气流教程:https://github.com/hgrif/airflow-tutorial

[11]: 亚马逊 EFS CSI 司机:https://github.com/kubernetes-sigs/aws-efs-csi-driver

【12】:【https://github.com/godaddy/kubernetes-external-secrets】Go-daddy Kubernetes:外部秘密

Apache Airflow 徽标是 Apache 软件基金会在美国和/或其他国家的注册商标或商标。使用这些标志并不意味着 Apache 软件基金会的认可。 Kubernetes logo 文件在 Apache-2.0 或 CC-BY-4.0(知识共享署名 4.0 国际版)的选择下获得许可。

用于图形出版物图形布局的 juypter 笔记本扩展

原文:https://towardsdatascience.com/a-juypter-notebook-extension-for-graphical-publication-figure-layout-d2f207d7e63f?source=collection_archive---------49-----------------------

沟通是科学的关键,在许多领域,沟通意味着以可视格式呈现数据。在一些领域,比如神经科学,花上编辑数字以发表论文并不罕见。这一方面是由于数据的复杂性,另一方面是由于使用 matplotlib 等工具很难快速绘制出符合该领域出版标准的图。不同大小的支线剧情、错综复杂的插图和复杂的配色方案常常驱使科学家使用基于图形的工具,如 photoshop 或 inkscape。

这篇文章描述了一对工具的开发,它们可以扩展使用 python 和 matplotlib 很容易实现的图形复杂性。主要的想法是在图形中定义支线剧情。这是利用 jupyter 笔记本在浏览器中运行的事实完成的,对笔记本的扩展可以将 HTML/javascript 绘图小部件注入到笔记本中。这使得用户可以使用鼠标来定义子图布局,而不是使用更麻烦的 matplotlib 数字方式来定义轴。然后,一旦粗略的绘图完成,各种组件可以通过算法调整大小,以适应分配的画布空间。

第 1 部分:绘图小部件

设置扩展框架

如前所述,小部件构建在jupyter-contrib-nbextensions包之上,它为创建可独立启用/禁用的分区扩展提供了良好的基础设施。创建自己的扩展需要将现有扩展的功能拼凑起来。这个环节是一个很好的起点。

nbextensions包将每个扩展保存在一个已知目录下自己的文件夹中。一旦你安装了nbextensions包,这个代码片段将帮助你找到目录

from jupyter_core.paths import jupyter_data_dir
import os
nbext_path = os.path.join(jupyter_data_dir(), 'nbextensions')

nbext_path是您的扩展代码最终应该结束的地方。然而,这个位置并不是开发代码最方便的位置,更重要的是,如果我们想将我们的扩展分发给其他人不需要将它包含在主nbextensions库中,我们将需要某种方式在这里自动“安装”代码。(这样做有各种各样的原因,包括“beta 测试”新的扩展,并且在撰写本文时,对nbextensions库的“master”分支的最后一次提交是在将近 1 年前)。

比直接在nbext_path中开发更好的方法是创建一个更容易访问的编码位置的符号链接。在你的代码目录中包含这个 python 脚本将作为一个安装脚本。执行python install.py将创建一个从当前目录到nbext_path的适当命名的符号链接。

现在分发你的扩展!

创建扩展

用户流
在开始实现之前,让我们简单讨论一下扩展的用户流

从一个空的笔记本单元格开始,按下最右边的图标,它看起来像两个桌面窗口。

你可以用鼠标创建一个初始支线剧情:

当你对你的布局感到满意时,点击“生成 python 单元”按钮,用等效的 python/matplotlib 代码创建一个单元。

主要的挑战是在按下工具栏按钮时注入 HTML 画布,然后在布局就绪时自动创建 python 单元。一旦完成了这些,剩下的实现就和其他 javascript 项目一样了。

实现
main.js文件是大部分编码发生的地方。下面是空扩展的轮廓

define([
  'base/js/namespace',
  'base/js/events'
], function(Jupyter, events) {// add a button to the main toolbar
  var addButton = function() {
    Jupyter.toolbar.add_buttons_group([
      Jupyter.keyboard_manager.actions.register({
        'help': 'Add figure layout generator',
        'icon': 'fa-window-restore',
        'handler': inject_figure_widget
      }, 'add-default-cell', 'Default cell')
    ])
  } // This function is run when the notebook is first loaded
  function load_ipython_extension() {
    addButton();
  }
  return {
    load_ipython_extension: load_ipython_extension
  };
});

这个框架代码在笔记本加载时运行一个“启动”功能。这个“启动”函数创建了工具栏按钮,并注册了一个对工具栏按钮的回调。这个回调函数inject_figure_widget是扩展的“主”函数,它将把 HTML 画布注入到笔记本中。为了使main.js独立,您可以在主function(Jupter, events)中定义助手函数。

使用控制台和元素检查器,找出 JS/HTML 来将画布插入输出字段是一个反复试验的过程。大致的轮廓是:

// execute the current cell to generate the output field; otherwise it won't be created
Jupyter.notebook.select();
Jupyter.notebook.execute_cell();// get reference to the output area of the cell
var output_subarea = $("#notebook-container")
  .children('.selected')
  .children('.output_wrapper')
  .children('.output');// add to DOM
let div = document.createElement("div");
output_subarea[0].appendChild(div);

现在,小部件的 HTML 元素可以添加到div中,就像在任何 javascript 支持的网页中一样。然而,键盘输入元素需要一些特殊的处理。您会发现,如果您尝试在输入字段中键入数字,它会将您的单元格转换为 markdown 并消除输出字段。这是因为 Jupyter 笔记本的默认按键。修复方法是当您的一个文本字段成为焦点时禁用 Jupyter 的键盘管理器,当它退出焦点时重新启用:

function input_field_focus() {
 Jupyter.keyboard_manager.disable();
}function input_field_blur() {
 Jupyter.keyboard_manager.enable();
}
$("#subplot_letter_input").focus(input_field_focus).blur(input_field_blur);

其他功能
实现的小部件有许多其他功能,我不会描述它们的实现,因为它们都是相当标准的 javascript:

  • 将情节分割成网格状支线情节
  • 用鼠标调整支线剧情的大小
  • 将所选地块的水平/垂直边缘与其他地块对齐
  • 用鼠标移动支线剧情
  • 通过键盘箭头移动支线剧情
  • 复制/粘贴、撤消、删除
  • 创建标签
  • 代码生成
  • 从笔记本中保存和重新加载

参见小工具的自述文件了解功能说明。

第 2 部分:编程调整大小

基于鼠标的布局工具(希望)是定义复杂支线剧情布局的更简单的方法。在 matplotlib 中布局具有多个子情节的图形的一个困难是,有时文本会在子情节之间重叠。Matplotlib 开始用紧凑布局特性来处理这个问题,但是这个特性似乎与这里使用的定义子情节位置的一般方式不兼容;它旨在与基于网格的子图布局定义一起使用。

作为用户,我们希望

  1. 以图形方式创建粗略的布局
  2. 填写所有数据和标签
  3. 调用一个例程来自动使所有东西“适合”可用空间。

第二步必须发生在一切都可以“适应”之前。这是因为很难事先考虑基于文本的元素的大小。您可以添加或省略文本标签,这会占用或释放空间。根据您的数据范围,刻度标签可能包含不同数量的字符,占据不同数量的画布区域。

使所有情节元素适合画布的一个非常简单的算法是

  1. 计算所有子情节元素周围的边界框。
  2. 对于每对图,根据边界框确定图是否重叠。
  3. 如果有重叠,计算一个比例因子来减少最左边/最上面的图的宽度和高度。假设每个支线剧情的左上角都是锚定的。当应用该比例因子时,这对图应该没有重叠。(旁注:如果两个图重叠,假设为文本分配的区域为零,则不会调整它们的大小;假设重叠是有意的,例如对于插图)。
  4. 全局应用最小的成对比例因子。

这绝不是最好的数据可视化算法,但它应该总是产生一个无重叠的图。这个算法在这个简单的 python 模块中实现

轴边界框

maplotlib中寻找各种元素的边界框需要一些反复试验。表示绘图元素的数据结构非常灵活,如果您不熟悉 API(我坚定地站在“不熟悉”的阵营),这可能会使您很难弄清楚如何在画布上获得元素的大小。下面是一个简单的搜索,它遍历一个轴的所有子元素,并试图获得不同的识别元素的大小。我想不出比下面这个更统一的方法了。

def get_axis_bounds(fig, ax, scaled=False):
    children = ax.get_children()# initial est based on ax itself
    p0, p1 = ax.bbox.get_points()
    xmax, ymax = p1
    xmin, ymin = p0for child in children:
        if isinstance(child, matplotlib.axis.XAxis):
            text_obj = filter(lambda x: isinstance(x, matplotlib.text.Text), child.get_children())
            text_obj_y = [x.get_window_extent(renderer=fig.canvas.renderer).p0[1] for x in text_obj]
            ymin_label = np.min(text_obj_y)
            if ymin_label < ymin:
                ymin = ymin_label
        elif isinstance(child, matplotlib.axis.YAxis):
            text_obj = filter(lambda x: isinstance(x, matplotlib.text.Text), child.get_children())
            text_obj_x = [x.get_window_extent(renderer=fig.canvas.renderer).p0[0] for x in text_obj]
            xmin_label = np.min(text_obj_x)
            if xmin_label < xmin:
                xmin = xmin_label
        elif hasattr(child, 'get_window_extent'):
            bb = child.get_window_extent(renderer=fig.canvas.renderer)
            if xmax < bb.p1[0]:
                xmax = bb.p1[0]
            if xmin > bb.p0[0]:
                xmin = bb.p0[0]
            if ymin > bb.p0[1]:
                ymin = bb.p0[1]
            if ymax < bb.p1[1]:
                ymax = bb.p1[1]if scaled:
        rect_bounds = np.array([xmin, ymin, xmax, ymax])
        fig_size_x, fig_size_y = fig.get_size_inches() * fig.dpi
        rect_bounds /= np.array([fig_size_x, fig_size_y, fig_size_x, fig_size_y])
        return rect_bounds
    else:
        return np.array([xmin, ymin, xmax, ymax])

有一个小问题:这个方法要求matplotlib首先呈现人物画布。在这个渲染之前,matplotlib可能不会正确的通知你一个元素会占用多少空间。所以你必须在交互模式下使用matplotlib。如果您使用的是第 1 部分中的小部件,想必您已经处于 jupyter 环境中。如果你使用交互式的%matplotlib notebook风格的图形生成,这个问题应该不成问题。

获取绘图区域的边界要简单得多,因为这是指定在哪里绘制轴的方法。信息存储在轴的bbox属性中。

fig_size_x, fig_size_y = fig.get_size_inches() * fig.dpi
plot_bounds = ax.bbox.get_points() / np.array([fig_size_x, fig_size_y])

一旦知道了轴边界和绘图边界,就可以计算每一边包含文本元素的边界的大小。边框的大小是固定的(除非文本发生变化),因此计算绘图上的重定比例因子的算法是简单地按边框文本所占的分数将其缩小

调整大小示例

下面是几个自动缩放图的例子,以适应文本占用的错误空间。

轴水平延伸过远
前:

之后:

轴垂直延伸过远
:

之后:

轴水平重叠
:

之后:

轴垂直重叠
:

之后:

结论

总的来说,这种方法可能会使研究人员在发布时可能面临的一些更繁琐的数据可视化任务自动化。从算法上处理布局问题可能有助于开发更复杂的算法,使图形的布局更加自然可读。

基于 Keras 的序列异常检测自动编码器

原文:https://towardsdatascience.com/a-keras-based-autoencoder-for-anomaly-detection-in-sequences-75337eaed0e5?source=collection_archive---------4-----------------------

使用 Keras 开发一个健壮的神经网络结构,可以用来有效地识别序列中的异常

马库斯·斯皮斯克在 Unsplash 上的照片

假设您有一个很长的字符串序列列表,例如氨基酸结构列表(' PHE-SER-CYS ',' GLN-ARG-SER ',…),产品序列号列表(' AB121E ',' AB323 ',' DN176'…),或者用户 uid,您需要创建某种验证过程来检测这个序列中的异常。异常可能是一个与其他字符串格式稍有不同或不寻常的字符串(无论是错误创建的还是故意创建的),或者只是一个极其罕见的字符串。更有趣的是,假设您不知道序列应该遵循的正确格式或结构是什么。

这是一个相对常见的问题(尽管不常见),许多数据科学家通常使用流行的无监督 ML 算法来解决,如 DBScan、Isolation Forest 等。这些算法中的许多通常通过挑选出相对远离其他数据点或大多数数据点所在区域的数据点,在发现异常或异常值方面做得很好。虽然自动编码器也因其异常检测能力而闻名,但它们的工作方式非常不同,在遇到这类问题时不太常见。

照片由米卡·鲍梅斯特Unsplash 上拍摄

我将把什么是自动编码器的解释留给许多有见地的、写得很好的帖子和在线免费提供的文章。非常简单地说(如果这对你没有意义,请继续读下去),就像其他类型的 ML 算法一样,自动编码器通过创建不同的数据表示并通过测量这些表示在生成预期结果方面的表现来学习;就像其他类型的神经网络一样,自动编码器通过创建这种表示的不同来学习,这使它们能够学习更复杂和复杂的数据表示(在我看来,这正是它们在像我们这样的任务中更胜一筹的原因)。然而,自动编码器是一种特殊形式的神经网络,因为它们试图生成的输出是它们接收到的输入的的重构。自动编码器从输入数据(即一组数字)开始,然后使用一组数学运算以不同的方式对其进行转换,直到它学习到应该使用的参数,以便重建相同的数据(或非常接近该数据)。在这个学习过程中,自动编码器本质上学习输入数据的格式规则。这正是它在我们这样的环境中作为异常检测机制表现出色的原因。

使用自动编码器检测异常通常包括两个主要步骤:

首先,我们将数据输入自动编码器,并对其进行调整,直到它经过良好的训练,能够以最小的误差重建预期的输出。例如,如果我们认为重建的输出足够接近输入,并且如果自动编码器能够以这种方式成功地重建大部分数据,那么接收类似 10,5,100 的输入并返回 11,5,99 的自动编码器就是训练有素的。

第二,我们再次将所有数据馈送给我们训练过的自动编码器,并测量每个重构数据点的误差项。换句话说,我们测量重建的数据点离实际的数据点有多远。一个训练有素的自动编码器本质上学习如何重构遵循特定格式的输入,因此,如果我们给一个训练有素的自动编码器一个糟糕的数据点,那么我们很可能会得到与我们的输入完全不同的东西,以及一个大的误差项。

是时候写点代码了

让我们进入细节。不过,我应该强调,这只是使用自动编码器完成这项任务的一种方式。还有其他方法和技术来构建自动编码器,您应该进行试验,直到找到适合您项目的架构。

这些是我将要遵循的步骤:

  1. 生成一组遵循指定格式的随机字符串序列,并添加一些异常。
  2. 将这些序列编码成数字并进行缩放。
  3. 设计、安装和调整自动编码器。
  4. 将序列输入到经过训练的自动编码器,并计算每个数据点的误差项。
  5. 通过找到具有最高误差项的数据点来找到异常。
  6. 生成一长串字符串。

首先,我们将编写一个函数来创建以下格式的字符串:CEBF0ZPQ ([4 个字母 A-F][1 个数字 0–2][3 个字母 QWOPZXML]),并生成这种格式的 25K 个序列。

字符串生成

2.将字符串序列编码成数字并缩放

现在我们有一个如下形状的数组,因为每个字符串序列有 8 个字符,每个字符编码为一个数字,我们将把它作为一个列。

encoded_seqs.shape
#(25005,8)

最后,在将数据输入 autoencoder 之前,我将使用 MinMaxScaler 对数据进行缩放,并将其分成训练集和测试集。适当的缩放通常可以显著提高神经网络的性能,因此尝试多种方法非常重要。

3。设计、安装和调整自动编码器。

如前所述,设计自动编码器的方法不止一种。它通常基于用较大的层包裹的小的隐藏层(这就是产生编码-解码效果的原因)。我进行了几次调优,以确定这里使用的最佳参数,因为不同种类的数据通常会产生非常不同的最佳性能参数。

事实上,我们的自动编码器似乎表现得非常好,因为它能够最大限度地减少误差项(或损失函数),令人印象深刻。

4。计算误差,找出异常!

现在,我们再次将数据作为一个整体馈送给自动编码器,并检查每个样本的误差项。回想一下 seqs_ds 是一个 pandas 数据帧,它保存实际的字符串序列。第 2 行对每个字符串进行编码,第 4 行对其进行缩放。然后,我使用 predict()方法获得存储在 seqs_ds 中的字符串的重构输入。最后,通过计算输入数据点(或实际数据点)与自动编码器重建的输出之间的“距离”,我得到了每个数据点的误差项:

mse = np.mean(np.power(actual_data - reconstructed_data, 2), axis=1)

在我们将误差项存储在数据帧中之后,我们可以看到每个输入数据由我们的自动编码器构造得有多好。

我们如何发现异常?

嗯,我们需要做的第一件事是决定什么是我们的阈值,这通常取决于我们的数据和领域知识。例如,有些人会说异常是一个数据点,它的误差项高于我们数据的 95%。如果我们预计有 5%的数据是异常的,这将是一个合适的阈值。但是,回想一下,我们向 25,000 个完全格式化的序列列表中注入了 5 个异常,这意味着只有 0.02%的数据是异常的,因此我们希望将阈值设置为高于 99.98%的数据(或 0.9998 百分点)。首先让我们找到这个门槛:

接下来,我将向数据集添加一个 MSE_Outlier 列,并在误差项超过这个阈值时将其设置为 1。

现在我们要做的就是检查我们有多少异常值,以及这些异常值是否是我们在数据中注入和混合的

['XYDC2DCA', 'TXSX1ABC','RNIU4XRE','AABDXUEI','SDRAC5RF']

所以让我们看看我们有多少异常值,它们是否是我们注入的异常值。

还有…瞧啊。我们发现了 6 个异常值,其中 5 个是“真正的”异常值。

看起来像魔术哈?

git 上的源代码可用

数据科学家在几分钟内创建 API 的外行指南

原文:https://towardsdatascience.com/a-layman-guide-for-data-scientists-to-create-apis-in-minutes-31e6f451cd2f?source=collection_archive---------9-----------------------

图片由转化为图形来自 Pixabay

API 创建变得简单了

您是否曾经遇到过这样的情况:您希望将您的模型预测提供给前端开发人员,而他们却无法访问与模型相关的代码?或者有没有开发人员要求您创建一个他们可以使用的 API?我已经面对过很多次了。

随着数据科学和 Web 开发人员试图合作,API 成为使代码和技能更加模块化的难题的重要部分。事实上,同样地,不能指望数据科学家对 Javascript 或 nodeJS 了解很多,前端开发人员应该能够在不了解任何数据科学语言的情况下应付过去。API 在这个抽象中扮演了相当重要的角色。

但是,API 令人困惑。我自己在创建它们并与我的开发团队分享它们时也感到很困惑,我的开发团队使用他们的 API 术语,如 GET request、PUT request、endpoint、Payloads 等。

这篇文章将会简化和理解 API 是如何工作的,解释上面的一些术语,并使用优秀的 API 构建框架 FastAPI 创建一个 API,这使得创建 API 变得轻而易举。

什么是 API?

在我们继续深入之前,我们需要理解什么是 API。根据维基百科:

一个应用编程接口 ( API )是一个计算接口,它定义了多个软件中介之间的交互。它定义了可以进行的调用或请求的种类、如何进行、应该使用的数据格式、应该遵循的约定等等。

我喜欢理解 API 的方式是它是一个“在线函数”,一个我可以在线调用的函数。

例如:

我可以有一个电影 API,当我将“动画”类型作为输入时,它会返回戏剧电影的名称。

使用这种机制的好处是,API 用户不必访问整个数据集或源代码,但他们可以获得他们需要的所有信息。 这是互联网上有多少服务像 亚马逊 Rekognition ,是一个图像和视频 API,或者 谷歌自然语言 API ,是一个 NLP API 作品。它们让我们可以使用一些很棒的功能,却不让我们拥有源代码,而源代码通常是很有价值的,而且是隐藏的。例如,我可以将一张图像发送到亚马逊 Rekognition API,它可以为我提供人脸检测和分析。

来源

例如,这里有一个由 Open Movie DB 提供的免费 API,它允许我们使用参数搜索电影:

[http://www.omdbapi.com/?i=tt3896198&apikey=9ea43e94](http://www.omdbapi.com/?i=tt3896198&apikey=9ea43e94)

这里我为电影《银河护卫队 2》提供了 IMDB id,使用了 API 的参数i。如果您在浏览器中打开此链接,您将看到电影的所有信息,如打开的电影数据库所示

来自 OMDB 的输出

但在我们继续之前,让我们先了解一些术语:

  • 端点:以上 API 调用中,端点为:http://www.omdbapi.com/。简单地说,这就是函数代码运行的位置。
  • API 访问键:大多数公共 API 都会有一些访问键,你可以请求。对于 OMDB API,我必须注册并获得 API 密钥[9ea43e94](http://www.omdbapi.com/?i=tt3896198&apikey=9ea43e94)
  • **?** 操作符:该操作符用于指定我们想要发送给 API 或我们的“在线函数”的参数这里我们给 API 两个参数,即 IMDB 电影 ID 和使用?操作符的 API 访问密钥。由于有多个输入,我们也使用&操作符。

为什么选择 FastAPI?

“如果你想学习一个构建 REST APIs 的现代框架,那么试试 FastAPI 吧……它快速、易用、易学……”—空间创造者

虽然 Python 有许多构建 API 的框架,最常见的是 Flask 和 Tornado,但 FastAPI 在易用性方面比可用的替代方案好得多,因为与 Flask 相比,它似乎更 Python 化。

还有,FastAPI 很快。正如 Github 文档所说, “非常高的性能,与 NodeJS 和 Go 不相上下。” 我们也可以为自己检查延迟 基准

来源

与 Flask 相比,速度提高了大约 2 倍,而且没有太多代码更改。当构建一个可以服务数百万客户的 API 时,这意味着一笔巨大的交易,因为它可以减少生产工作,还可以使用更便宜的硬件来服务。

比较和讨论到此为止,让我们尝试使用 FastAPI 来创建我们的 API。

如何用 FastAPI 写一个 API?

数据科学最常见的用例之一是如何创建一个 API 来获得模型的预测?让我们假设我们有一个巨大的生存模型来预测一个人是否能生存。并且,它需要一个人的agesex作为输入参数来预测。我们将使用 FastAPI 以两种方式创建这个 API:GET 和 PUT。不用担心;我会边走边解释。

什么是 GET?— 在 GET 请求中,我们通常尝试使用嵌入查询字符串本身的查询参数来检索数据。例如,在 OMDB API 中,我们使用 GET 请求来指定电影 id 和访问键,作为查询本身的一部分。

放的是什么?—GET 请求的另一种选择是 PUT 请求,我们使用有效载荷发送参数,正如我们将在第二个方法中看到的。有效负载不是查询字符串的一部分,因此 PUT 更安全。看到第二部就更清楚了。

但是在我们继续之前,我们需要安装 FastAPI 和uvicorn ASGI 服务器:

pip install fastapi
pip install uvicorn

1.那位挨道:

为我们的 titanic 模型用例编写 GET API 的一个简单的 FastAPI 方法如下:

from fastapi import FastAPIapp = FastAPI()@app.get("/predict")
def predict_complex_model(age: int,sex:str):
    # Assume a big and complex model here. For this test I am using a simple rule based model
    if age<10 or sex=='F':
        return {'survived':1}
    else:
        return {'survived':0}

将上面的代码保存在一个名为fastapiapp.py的文件中,然后您可以在终端上使用下面的命令运行它。

$ uvicorn fastapiapp:app --reload

以上意味着您的 API 现在正在您的服务器上运行,--reload标志表示当您更改fastapiapp.py文件时,API 会自动更新。这在开发和测试时非常有帮助,但是在将 API 投入生产时,您应该移除这个--reload标志。现在,您可以在浏览器中访问以下路径,您将获得预测结果:

[http://127.0.0.1:8000/predict?age=10&sex=M](http://127.0.0.1:8000/predict?age=10&sex=M)

当您在浏览器中点击该命令时,它调用[http://127.0.0.1:8000/](http://127.0.0.1:8000/predict?age=10&sex=M)predict端点,而端点又调用带有参数age=10 and sex='M'的关联方法predict_complex_model

因此,它允许我们从浏览器使用我们的功能,但这仍然不是很有帮助。你的开发者朋友需要使用你的 predict 函数在前端网站上显示输出。你如何让他使用这个功能?

这很简单。例如,如果你的开发者朋友也使用 Python,他可以像下面这样使用requests模块:

import requestsage = 15
sex = "F"response = requests.get(f"[http://127.0.0.1:8000/predict?age={age}&sex={](http://127.0.0.1:8000/predict?age=10&sex=M)sex}")
output = response.json()

因此,我们可以将正在运行的 API(在服务器上)的输出放到我们的 Python 程序中。Javascript 用户将使用 Javascript 请求库,nodeJS 开发人员将在 nodeJS 中使用类似的东西来做这件事。我们只需要向他们提供所需的端点和参数。

要测试您的 API,您也可以访问:

[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)

在这里您可以找到一种测试 API 的 GUI 方式。

但是正如我们前面所说的,这是不安全的,因为 GET 参数是通过 URL 传递的。这意味着参数存储在服务器日志和浏览器历史中。这不是有意的。此外,这个玩具示例只有两个输入参数,所以我们可以这样做,考虑一下我们需要为预测函数提供许多参数的情况。

在这种情况下或者我敢说在大多数情况下,我们使用 PUT API。

2.推杆方式

使用 PUT API,我们可以通过向函数提供有效负载来调用任何函数。有效负载不过是一个输入参数的 JSON 字典,不会附加到查询字符串中,因此比 get 安全得多。

这是一个最小的例子,我们用 PUT 做同样的事情。我们只是将fastapiapp.py的内容改为:

from fastapi import FastAPI
from pydantic import BaseModelclass Input(BaseModel):
    age : int
    sex : strapp = FastAPI()[@app](http://twitter.com/app).put("/predict")
def predict_complex_model(d:Input):
    if d.age<10 or d.sex=='F':
        return {'survived':1}
    else:
        return {'survived':0}

注意,我们在这里用app.put代替前面的app.get。我们还需要提供一个新的类Input,它使用一个名为pydantic的库来验证我们将从 API 最终用户那里获得的输入数据类型,而之前在 get 中,我们使用函数参数列表来验证输入。此外,这一次您将无法使用网络上的 URL 查看您的内容。例如,使用浏览器指向端点位置给出:

因此,我们可以再次使用 Python 中使用请求的编程方式进行检查:

import requests,json
payload = json.dumps({
  "age": 10,
  "sex": "F"
})
response = requests.put("[http://127.0.0.1:8000/predict](http://127.0.0.1:8000/predict)",data = payload)
response.json()

注意,我们在这里使用了requests.put,我们使用requests.put函数中的数据参数提供了有效载荷,我们还使用了json库将有效载荷从 dict 对象转换为 JSON。

我们也可以像以前一样使用 GUI 方式:

[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)

我们已经完成了 API 的创建。换换口味很简单。

FastAPI 使得 API 创建变得更加直观、简单和快速,而 API 创建曾经是数据科学过程中令人恐惧的部分之一。

你可以在我的 GitHub 库找到这篇文章的代码以及我所有的文章。

还有很多人在评论“ 中问我,如何在 ec2 上部署 FastAPI API,如何使用图像数据而不是简单的字符串、整数和浮点数作为 API 的输入?”, 我写了这个帖子的继任者。如果你觉得有趣的话,一定要看一看,

[## 部署可能很容易—数据科学家指南使用…部署图像检测 FastAPI API

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

towardsdatascience.com](/deployment-could-be-easy-a-data-scientists-guide-to-deploy-an-image-detection-fastapi-api-using-329cdd80400)

继续学习

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

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

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

深度 Q 学习的门外汉衍生|强化学习

原文:https://towardsdatascience.com/a-laymans-derivative-on-deep-q-learning-reinforcement-learning-5e79506a7020?source=collection_archive---------63-----------------------

照片由晨酿Unsplash 拍摄

本文试图建立深 Q 网络背后的直觉。在我们开始之前,让我们花一些时间来理解什么是 Q 学习。太长了,一定要读!

简单来说, Q 学习是一种无模型强化学习方法,使智能体能够在环境中采取行动或导航,并达到其目标。无模型并不意味着没有任何网络来训练代理(像在 Deep Q 网络中使用的那样),而是没有能够理解环境并预测下一个状态或回报的模型。在像这样的无模型学习中,代理主要依赖于过去对变迁的记忆(在状态 s 给出一些奖励 r 时采取的动作 a 来训练网络。这组转换也被称为动作重放重放缓冲器

给定一个状态,奖励或惩罚由环境在每一步安排。当然,达到目标会得到更高的回报。

当谈到现实生活中的用例时,环境会变得复杂,有多个动作空间。我们将在这里使用一个简单的基于网格的例子,只有 4 个动作:左,上,右,下

基于网格的环境示例(图片由作者提供)

突出显示的框是代理的目的地。在给定的情况下,没有奖励或惩罚,代理很容易到达目的地。一个喜欢解谜的孩子可能会这样画:

多重解决方案(图片由作者提供)

计划

现在让我们制作一个更有趣的网格。代理商达到目标后将获得 1 的奖励,但每走一步将被罚款 -0.5 (活罚)。聪明的孩子选择了最小的路。他的回答大概是这样的:

(图片由作者提供)

虽然孩子很容易找到最佳路径,但这里的代理必须从目标开始追踪路径。以蓝色突出显示的路径是给定状态(起始位置)的最佳路径。对于每个状态,一个由最优路径(如路径 2)组成的行动计划可以通过奖惩系统来确定。

路径 1 的开销= 4 * -0.5 + 1 = -1
路径 2 的开销= 2* -0.5 + 1 = 0
路径 3 的开销= 4 * -0.5 + 1 = -1

在这种情况下,代理的行为是确定的。当一个代理人决定向右走,代理人就迈出正确的一步。现在你会想,当代理已经决定向右时,它怎么会向下呢?想象一个机器人在沙地上行驶。当它决定右转 20 度时,它无法克服沙子的阻力,一直往前走。还有其他环境条件会影响行动。这就是行动变得不确定 的地方。让我们坚持这个想法,稍后我们将回到这个话题。

贝尔曼方程

这与我们的谜题略有不同,但我们最终会将它连接回来,这一部分将帮助我们理解为什么这个等式很重要,并且是许多强化学习方法的基础。

还记得我们讨论过的重放缓冲器吗?它存储所有状态转换和代理采取的动作。让我们找出代理成功到达目标的路径,路径 3 。现在,我们开始追溯它的路径,并确保我们在返回起点的路上留下了面包屑。代理知道当它从倒数第二个州拿了权时,它得到了奖励 1。

回来的路上的面包屑(作者图片)

同样地,追根溯源。

这是代理看到的内容(图片由作者提供)

现在,我们清楚地知道从这个特定的起点该走哪条路。跟着面包屑走就行了。这个聪明的孩子给我画了另一个谜题:这个怎么样?

聪明的孩子:1,特工:0(图片由作者提供)

现在,我们必须确保面包屑以这样一种方式放置,即面包屑有梯度,代理可以跟随它们。这就是贝尔曼方程的由来。

贝尔曼方程

γ:贴现因子
R:每采取一步的奖励
s:状态
V:状态的值
Y:γ或贴现因子,< 1

将该方程扩展到下面的状态 S0

州(图片由作者提供)

S0 的最大值

马尔可夫决策过程

虽然这是在确定性空间中发生的事情,但在非确定性的情况下,每个动作都有可能导致期望的状态。贝尔曼方程现在

P(s,a,s’)基本上是从状态 s 完成预定动作 a 并到达新状态 s 的概率。假设当代理人试图上升时,上升的概率是 0.5,下降的概率是 0.2,向右上升的概率是 0.2,向左上升的概率是 0.1。这个等式基于马尔可夫性质,即当前状态足以让代理决定未来的行动。
1)到目前为止,不依赖于历史动作/状态。
2)通过执行一个动作从一个状态到另一个状态的转换可能并不总是具有相同的结果。因此,对于每个(s,a)或状态-动作转换,都有一个与之相关的概率。

所以 action = top 的第二项看起来会是:
*Gamma *(0.5 * V(s _ up)+0.2 * V(s _ down)+0.2 *(s _ right)+0.1 (s _ left))

现在让我们来计算面包屑的外观。为了简单起见,让我们假设目标的奖励= 1。活罚= 0。

对于倒数第二个状态,
终态值:V(s _ pre _ final)= R+Y * V(s _ final)
V(s _ pre _ final)= 1,我们这里有一个大面包屑
V(s _ left _ pre _ final)= R+Y * V(s _ pre _ final)= 0+Y = Y,面包屑减少到 1 的 Y%
V(s _ left _ pre _ final)= R+Y * V(s _ left _ pre _ pre

假设 Y = 0.7,那么面包屑将是 0.49,0.7,1

应用贝尔曼方程后的路径(图片由作者提供)

现在,代理更容易按顺序跟踪更大的面包屑。

q 学习:

状态的 V(s)或值基本上表示一个状态有多好。为了解决这个难题,Q 函数很有帮助。这基本上意味着给定一个状态,这个动作有多好。q 可以被认为是一个动作的质量。

由于状态的值将依赖于给出最大值的动作,所以状态 s’的值函数:

价值-质量关系

只有 Qs 形式的 q 学习方程

使用这些等式,可以创建一个 Q 表来确定实现目标的最佳路径或行动顺序。

深度 Q 学习:

与 Q 学习相反,我们不使用表格,而是依靠深度学习网络。这个网络或深度 Q 网络将帮助代理在给定状态下决定最佳行动。

带有密集图层的 DQN 样本(图片由作者提供)

这里,我们将状态值传递给网络,让它决定动作空间中每个动作的值。这种网络的工作方式与任何深度神经网络非常相似——最小化损失并更新权重,直到它们达到最优。现在你可能想知道我们从哪里获得这个网络的数据——这就是重放缓冲器开始工作的地方。

好像理论很多啊!如果你有兴趣 使用深度 Q 网络 培训你自己的代理。

本文试图在贝尔曼方程和 Q 学习背后建立一种直觉。我们将在下一篇文章中尝试揭示 Q 学习、时间差异、计划与政策的细节。

参考文献
贝尔曼方程解释

使用 Keras 在 R 中构建第一个图像分类模型的外行指南

原文:https://towardsdatascience.com/a-laymans-guide-to-building-your-first-image-classification-model-in-r-using-keras-b285deac6572?source=collection_archive---------21-----------------------

动手香草建模第一部分

作者图片

机器学习的应用现在几乎是我们日常生活中不可或缺的一部分。从智能手机中基于语音识别的虚拟助理到超级智能的自动化无人机,人工智能和人工智能(AI)正在彻底改变人机交互的动态。人工智能算法,特别是卷积神经网络(CNN)使得计算机视觉比以往任何时候都更加强大。虽然它的应用程序令人惊叹,但构建自己的 CNN 模型可能会非常令人生畏,特别是对于非程序员或数据科学初学者来说。作为一个 R 爱好者,我不难断言,对于一个 R 程序员新手来说,它变得更加神秘。这种不平衡的合理原因可能是,标准神经网络和 ML 库(如 Keras 和 Tensorflow)主要与 Python 兼容,并自然地吸引大众使用 Python 本身,导致严重缺乏新手指南和文档来帮助在 r 中实现这些复杂的框架。在本文中,我们将使用 Keras 和 Tensorflow 框架在 R 中制作一个基于 CNN 的普通图像分类模型。通过这篇文章,我的目标是使您能够使用 Keras 在 R 中概念化和构建自己的 CNN 模型,并通过亲自动手编码来帮助增强您的信心,以便在将来使用这个深奥的 API 构建更复杂的模型。除了模型的脚本之外,我还将尽量简明地阐述必要的组件,同时深入核心的底层数学。现在我们开始吧。

卷积神经网络(CNN)快速介绍。

图一。卷积神经网络架构(图片作者

作为 CNN 脚本的前奏,让我们简单了解一下它的形式主义。就像人眼只在有限的接收框架中记录信息,并学习特定的模式和空间特征,随后触发特定的神经反应一样,CNN 模型也以相同的方式运行。我们将尝试探索 CNN 架构并理解其关键组件(图 1)。

图二。可视化卷积(作者的图像)

不是一次合并整个图像像素,而是将一个像素子集卷积成一个数据图 2 。卷积是通过在整个图像上滑动一个较小尺寸的帧来实现的,该帧充当考虑了时间-空间特征的感受域。这个帧被称为内核/过滤器。想象一下用手电筒扫描一面建筑墙,过滤器以同样的方式工作。现在,如果您有多种过滤器,您可能会提取或观察到更具鉴别性的空间要素和经常重复出现的相邻值。该方案通过不仅以最少的信息损失保持空间特征,而且显著地减少所需的权重数量来增强学习,使得图像分类实际上可行并且可扩展。例如,考虑一幅 2D 黑白(b & w)图像作为 CNN 的输入。该模型通过使用滤波器开始卷积图像,然后以给定的步长滑过图像,也称为步长。滤波器值类似于神经网络中的权重。在一个实例中,这些滤波器值和图像的前景像素值的线性组合生成单个特征输出。生成的一组这些值产生一个新层,称为特征图。直观地说,特征图是输入图像的浓缩形式,它将所有主要特征和模式保留在较小的维度中,以便有效学习。

图 3。卷积方案(图片作者

为了说明这一点,在图 3 中,在尺寸为 10X10 的黑白图像上使用了尺寸为 4x4 的滤波器。滤镜以 1 个单位的步幅在图像上滑动,从而生成一个维度为(10–4+1)X(10–4+1)的回旋层,即 7X7。注意,本例中的偏差/截距假定为 0。类似地, n 个滤波器将生成 n 个特征图。

图 3。彩色图像的卷积(作者的图像)

对于黑白图像,深度为 1,因此滤镜的深度为 1。然而,彩色图像是红色、蓝色和绿色(RBG)通道的集合。确切地说,是三个 2D 层的堆叠,其中每一层代表特定颜色通道的强度。所以对于深度为 3 的彩色图像,你需要一个尺寸为(4X4)X 3 的滤镜(图 4)。

一旦生成了特征图,就对它们中的每一个应用一个激活函数。为此,整流线性单元(ReLU) 激活功能就派上了用场。如果 ReLU 的输入是一个负值,它就简单地将它转换为零,否则它将输出完全相同的输入值(图 4)。数学上, f(x)= max(0,x)。

图 5。ReLU 和 Max Pooling ( 图片作者)

在激活层之后,另一种方案被用来在不丢失重要信息的情况下灵活地降低特征图的维数。这种技术被称为最大池。与卷积方案非常相似,这里只选取最大池窗口中的最高值。该窗口以与过滤器相同的方式滑动,但是步长等于池窗口的尺寸(图 5)。最大池显著降低了特征图的维度,同时还保留了重要的/主要的特征。最终的最大池层然后被挤压和展平成神经元层,该神经元层连接到完全连接的神经网络以执行分类任务。

请注意,CNN 并不局限于单个卷积或一组上述方案。有足够数量的过滤器支持,你的网络越深入,它将实现更高的性能。直观地说,初始卷积将捕获低级的循环特征,例如边缘和颜色。随后,深层往往会捕捉高级特征,如重复出现的像素簇,如肖像中的眼睛或鼻子。所以,总之,基于你的图像复杂性和计算能力,你应该选择足够的有效数量的层和过滤器。

现在让我们开始制作我们的玩具模型🤓!!

数据集

我相信,要理解任何统计概念,没有什么比一副扑克牌更容易的了。在这里,我将利用一副扑克牌,但在一个稍微非正统的形式。是的,你猜对了!!我将制作一个预测模型,它应该能够准确地分类和预测任何任意非正面扑克牌的给定图像的花色。

该数据集包含每种花色的一组 43 张纸牌图像,即梅花♣、红心♥️、方块♦️和黑桃♠️。请注意,每种花色的符号都遵循标准的形状,但是这些符号的设计和排列因卡而异。我们将结合这个数据集来训练和测试我们的模型。(为了方便地遵循脚本,我建议您下载图像,并将所有文件保存在一个父文件中,就像它们出现在 Github 存储库中一样)

需要软件包和安装

对于这个任务,你需要 Keras 和 EBImage 。前者可从 cran 知识库中获得。后者用于有效处理图像,可以从一个名为 Bioconductor 的开源软件中调用。这些可以安装在 Windows 操作系统上,如下所示:

install.packages(“keras”) # Install the package from CRAN
library(keras)
install_keras() #to setup the Keras library and TensorFlow backendif (!requireNamespace(“BiocManager”, quietly = TRUE))
install.packages(“BiocManager”)
BiocManager::install(“EBImage”)
library(EBImage)

这将安装 Keras API 的 CPU 版本,目前推荐新手使用。

注意:Keras API 将需要 Python 支持和 R tools 插件。因此,请确保在您的机器上安装了 anaconda 和 R 工具,并将其正确添加到您的系统路径中。

探索数据集

接下来,我们将把每套衣服的图像转换成一个张量(编号矩阵)。EBImage 库中的 readImage() 函数可以很好地做到这一点。让我们试着从数据集中读取一幅图像。

setwd(“C:/parent/spade”) # To access the images of Spades suit.
                         # The path should be modified as per your 
                         # machinecard<-readImage(“ace_of_spades (2).png”) # Reading an imgae from the
                                         # dataset
print(card) # Print the details of image

这给出了如下输出:

Image 
colorMode : Color 
storage.mode : double 
dim : 500 726 4 
frames.total : 4 
frames.render: 1imageData(object)[1:5,1:6,1]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 1
[2,] 1 1 1 1 1 1
[3,] 1 1 1 1 1 1
[4,] 1 1 1 1 1 1
[5,] 1 1 1 1 1 1

这表示图像的颜色尺寸为 500 X 726 X 4。注意,正如我们之前讨论的,这里图像深度是 4,所以我们需要深度为 4 的过滤器。为了揭示这四个矩阵,我们使用:

getFrames(card, type=”total”)

这将分别给出四个通道的详细信息。

[[1]]
Image 
colorMode : Grayscale 
storage.mode : double 
dim : 500 726 
frames.total : 1 
frames.render: 1imageData(object)[1:5,1:6]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 1
[2,] 1 1 1 1 1 1
[3,] 1 1 1 1 1 1
[4,] 1 1 1 1 1 1
[5,] 1 1 1 1 1 1[[2]]
Image 
colorMode : Grayscale 
storage.mode : double 
dim : 500 726 
frames.total : 1 
frames.render: 1imageData(object)[1:5,1:6]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 1
[2,] 1 1 1 1 1 1
[3,] 1 1 1 1 1 1
[4,] 1 1 1 1 1 1
[5,] 1 1 1 1 1 1[[3]]
Image 
colorMode : Grayscale 
storage.mode : double 
dim : 500 726 
frames.total : 1 
frames.render: 1imageData(object)[1:5,1:6]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 1
[2,] 1 1 1 1 1 1
[3,] 1 1 1 1 1 1
[4,] 1 1 1 1 1 1
[5,] 1 1 1 1 1 1[[4]]
Image 
colorMode : Grayscale 
storage.mode : double 
dim : 500 726 
frames.total : 1 
frames.render: 1imageData(object)[1:5,1:6]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 0 0 0 0 0
[2,] 0 0 0 0 0 0
[3,] 0 0 0 0 0 0
[4,] 0 0 0 0 0 0
[5,] 0 0 0 0 0 0

哦耶!为了阐明我们选择的卡,我们:

图 6。显示在 R 查看器中的所选卡片(作者图片)

display(card)

尽管数据集中每张卡片的深度都相同,但像素尺寸却各不相同,因此我们必须将每张卡片的尺寸调整为 100x100x4,并将它们组合在一个与 Keras 兼容的堆栈中。这个堆栈然后直接进入架构作为输入。

setwd(“C:/parent/club”) # To access the images of Clubs suit.
                        # The path should be modified as per your 
                        # machineimg.card<- sample(dir()); #-------shuffle the order
cards<-list(NULL);        
for(i in 1:length(img.card))
{ cards[[i]]<- readImage(img.card[i])
 cards[[i]]<- resize(cards[[i]], 100, 100)} #resizing to 100x100club<- cards              # Storing stack of the Clubs cards in
                          # matrix form in a list
#-----------------------------------------------------------setwd(“C:/parent/heart”)# To access the images of Hearts suit.
                        # The path should be modified as per your 
                        # machineimg.card<- sample(dir());
cards<-list(NULL);
for(i in 1:length(img.card))
 { cards[[i]]<- readImage(img.card[i])
cards[[i]]<- resize(cards[[i]], 100, 100)} #resizing to 100x100heart<- cards             # Storing stack of the Hearts cards in
                          # matrix form in a list
#------------------------------------------------------------setwd(“C:/parent/spade”)# To access the images of Spades suit.
                        # The path should be modified as per your 
                        # machineimg.card<- sample(dir());
cards<-list(NULL);
for(i in 1:length(img.card))
{ cards[[i]]<- readImage(img.card[i])
cards[[i]]<- resize(cards[[i]], 100, 100)} #resizing to 100x100spade<- cards             # Storing stack of the Spades cards in
                          # matrix form in a list
#------------------------------------------------------------setwd(“C:/parent/diamond”) # To access the images of Diamonds suit.
                           #The path should be modified as per your 
                           # machine
img.card<- sample(dir());
cards<-list(NULL);
for(i in 1:length(img.card))
{ cards[[i]]<- readImage(img.card[i])
cards[[i]]<- resize(cards[[i]], 100, 100)} #resizing to 100x100
diamond<- cards           # Storing stack of the Diamonds cards in
                          # matrix form in a list
#-------------------------------------------------------------train_pool<-c(club[1:40], 
              heart[1:40], 
              spade[1:40], 
              diamond[1:40]) # Vector of all the training images. 
                             # The first 40 images from each suit 
                             # are included in the train settrain<-aperm(combine(train_pool), c(4,1,2,3)) # Combine and stackedtest_pool<-c(club[41:43], 
             heart[41:43], 
             spade[41:43], 
             diamond[41:43]) # Vector of all test images. The last
                             # 3 images from each suit is included
                             # in test settest<-aperm(combine(test_pool), c(4,1,2,3)) # Combined and stacked

为了查看测试集中包含了哪些图像,我们这样做:

par(mfrow=c(3,4)) # To contain all images in single frame
for(i in 1:12){
  plot(test_pool[[i]])
  }
par(mfrow=c(1,1)) # Reset the default

图 8。测试集(作者图片)

我得到了如图 8 所示的卡片。对你来说可能是一套不同的卡片。

需要一个热编码来创建对应于输入数据的分类向量。

#one hot encoding
train_y<-c(rep(0,40),rep(1,40),rep(2,40),rep(3,40))
test_y<-c(rep(0,3),rep(1,3),rep(2,3),rep(3,3))train_lab<-to_categorical(train_y) #Catagorical vector for training 
                                   #classes
test_lab<-to_categorical(test_y)#Catagorical vector for test classes

让我们来构建架构

下面是构建 CNN 模型的 R 脚本。我还提供了一个全面的动画,演示了脚本运行的过程(图 9)。

# Model Buildingmodel.card<- keras_model_sequential() #-Keras Model composed of a 
                                      #-----linear stack of layersmodel.card %>%                   #---------Initiate and connect to #----------------------------(A)-----------------------------------#layer_conv_2d(filters = 40,       #----------First convoluted layer
 kernel_size = c(4,4),             #---40 Filters with dimension 4x4
 activation = ‘relu’,              #-with a ReLu activation function
 input_shape = c(100,100,4)) %>%   
#----------------------------(B)-----------------------------------#layer_conv_2d(filters = 40,       #---------Second convoluted layer
 kernel_size = c(4,4),             #---40 Filters with dimension 4x4
 activation = ‘relu’) %>%          #-with a ReLu activation function
#---------------------------(C)-----------------------------------#layer_max_pooling_2d(pool_size = c(4,4) )%>%   #--------Max Pooling
#-----------------------------------------------------------------#layer_dropout(rate = 0.25) %>%   #-------------------Drop out layer
#----------------------------(D)-----------------------------------#layer_conv_2d(filters = 80,      #-----------Third convoluted layer
 kernel_size = c(4,4),            #----80 Filters with dimension 4x4
 activation = ‘relu’) %>%         #--with a ReLu activation function
#-----------------------------(E)----------------------------------#layer_conv_2d(filters = 80,      #----------Fourth convoluted layer
 kernel_size = c(4,4),            #----80 Filters with dimension 4x4
 activation = ‘relu’) %>%         #--with a ReLu activation function
#-----------------------------(F)----------------------------------#layer_max_pooling_2d(pool_size = c(4,4)) %>%  #---------Max Pooling
#-----------------------------------------------------------------#layer_dropout(rate = 0.35) %>%   #-------------------Drop out layer
#------------------------------(G)---------------------------------#layer_flatten()%>%   #---Flattening the final stack of feature maps
#------------------------------(H)---------------------------------#layer_dense(units = 256, activation = ‘relu’)%>% #-----Hidden layer
#---------------------------(I)-----------------------------------#layer_dropout(rate= 0.25)%>%     #-------------------Drop-out layer
#-----------------------------------------------------------------#layer_dense(units = 4, activation = “softmax”)%>% #-----Final Layer
#----------------------------(J)-----------------------------------#compile(loss = 'categorical_crossentropy',
          optimizer = optimizer_adam(),
          metrics = c("accuracy"))   # Compiling the architecture

图 8。说明模型创建 ( 作者图片 )

我们可以使用summary(model . card)得到这个模型的概要。这样的输出将是一个简洁明了的模型总结。

Model: “sequential”
____________________________________________________________________
Layer (type) Output Shape Param # 
====================================================================
conv2d (Conv2D) (None, 97, 97, 40) 2600 
____________________________________________________________________
conv2d_1 (Conv2D) (None, 94, 94, 40) 25640 
____________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 23, 23, 40) 0 
____________________________________________________________________
dropout (Dropout) (None, 23, 23, 40) 0 
____________________________________________________________________
conv2d_2 (Conv2D) (None, 20, 20, 80) 51280 
____________________________________________________________________
conv2d_3 (Conv2D) (None, 17, 17, 80) 102480 
____________________________________________________________________
max_pooling2d_1 (MaxPooling2D) (None, 4, 4, 80) 0 
____________________________________________________________________
dropout_1 (Dropout) (None, 4, 4, 80) 0
____________________________________________________________________
flatten (Flatten) (None, 1280) 0 
____________________________________________________________________
dense (Dense) (None, 256) 327936 
____________________________________________________________________
dropout_2 (Dropout) (None, 256) 0 
____________________________________________________________________
dense_1 (Dense) (None, 4) 1028 
====================================================================
Total params: 510,964
Trainable params: 510,964
Non-trainable params: 0
____________________________________________________________________

模型拟合

一旦构建了架构,就该让数据集适合模型的训练了。拟合过程如下:

#fit model
history<- model.card %>%
 fit(train, 
 train_lab, 
 epochs = 100,
 batch_size = 40,
 validation_split = 0.2
 )

图 9 ( 作者图片)

装配时,每个时期(前馈-反馈)将出现在控制台区域。处理时间可能因机器而异。当 epochs 运行时,您应该会在 Rstudio 查看器中看到一个图形(图 9)。这些是训练集和验证集的损失和准确性的并列曲线。

控制台中出现的运行时期如下所示:

Train on 128 samples, validate on 32 samples
Epoch 1/100
128/128 [==============================] — 10s 78ms/sample — loss: 1.3648 — accuracy: 0.3281 — val_loss: 2.0009 — val_accuracy: 0.0000e+00
Epoch 2/100
128/128 [==============================] — 8s 59ms/sample — loss: 1.3098 — accuracy: 0.3359 — val_loss: 1.9864 — val_accuracy: 0.0000e+00
Epoch 3/100
128/128 [==============================] — 8s 61ms/sample — loss: 1.2686 — accuracy: 0.3516 — val_loss: 2.5289 — val_accuracy: 0.0000e+00

整个训练过程的总结可以用 【剧情(历史) 来绘制。

模型评估

一旦训练结束。是时候评估我们新训练的模型了。首先,我们将查看 moel 在训练数据集上的性能,然后我们将最终在我们的测试集上测试和评估我们的训练模型。

#Model Evaluationmodel.card %>% evaluate(train,train_lab) #Evaluation of training set pred<- model.card %>% predict_classes(train) #-----Classification
Train_Result<-table(Predicted = pred, Actual = train_y) #----Resultsmodel.card %>% evaluate(test, test_lab) #-----Evaluation of test set
pred1<- model.card  %>% predict_classes(test)   #-----Classification
Test_Result<-table(Predicted = pred1, Actual = test_y) #-----Resultsrownames(Train_Result)<-rownames(Test_Result)<-colnames(Train_Result)<-colnames(Test_Result)<-c("Clubs", "Hearts", "Spades", "Diamonds")print(Train_Result)
print(Test_Result)

这个会吐槽:

(图片作者)

在训练集上 100%的准确率可能是过度拟合的迹象,但是请注意,我们的模型在测试集上也达到了 100%的准确率。这意味着我们已经成功地制作了一个卷积神经网络模型,将一个给定的纸牌图像正确地分类到它真正的花色中。

如果你在这里,那么恭喜你!!你已经成功地制作了你的卷积神经网络模型。希望你旅途愉快。如果你发现任何错误或不正确的地方,请随时联系我。我也欢迎所有可以提高本文件质量的建议。

谢谢你的阅读和快乐的 R-ing😀

其他著名读物

人工智能用在哪里:可以用 AI 的领域

图解:10 个 CNN 架构

深入了解卷积神经网络背后的数学知识

卷积神经网络综合指南 ELI5 方式

Keras 代表 R

电子图像简介

深度卷积神经网络的外行指南

原文:https://towardsdatascience.com/a-laymans-guide-to-deep-convolutional-neural-networks-7e937628605f?source=collection_archive---------17-----------------------

图片鸣谢—@ frankin Japan[Unsplash]

深度学习基础

用 PyTorch 对卷积神经网络进行快速、非数学和实用的介绍

这篇文章是我计划以增量方式发布的基于中级的' 深度学习外行指南 '系列的一部分。目标受众是具备基本编程技能的初学者;最好是 Python。

先决条件

这篇文章假设你对深度神经网络有一个基本的了解。关于这一点的详细帖子已经在之前的帖子中发表了— 深度神经网络的外行指南。强烈建议阅读之前的帖子,以便更好地理解这篇帖子。

序幕

随着深度学习的出现,计算机视觉作为一个领域已经发展到了新的高度。与孤立的像素值或少量手工制作的特征相比,帮助机器以更直观的方式理解图像细节的能力已经在该领域带来了范式转变。如今,我们的日常生活、商业以及企业和工业技术产品中使用了大量尖端的计算机视觉应用。我们在日常生活中从计算机视觉深度学习的最新进展中受益匪浅;你可能没有意识到该领域在某些产品中的应用细节。几个值得注意的例子是,特斯拉的自动驾驶模式,iPhones 的 face-id 解锁,Animoji 和高级相机功能,智能手机相机的散景效果(人像模式),Snapchat 和脸书信使的滤镜等。

计算机视觉领域的基本思想始于一个非常简单的问题,即识别图像中存在的内容。事实证明,这个问题是一个非常难解决的任务,尽管我们人类觉得它非常容易。

图像以其数字形式使用具有像素值的三维矩阵来表示,即长度 x 宽度和#通道(RGB)。从这个三维矩阵中提取信息并不简单。

让我们从一些历史开始

传统计算机视觉解决方案

在早期,当机器学习被接受时,计算机视觉问题取得了相当大的成功。这些问题主要是通过使用手工制作的特征和传统的机器学习算法如 SVM(支持向量机)来解决的。手工制作的特征是使用各种其他算法得到的图像的属性。这种特征的一个常见例子是边缘和拐角的存在。一个基本的边缘检测算法的工作原理是找到图像强度突然变化的区域,即附近像素值的巨大差异。几个这样的基本属性和几个更复杂的特征使用算法的组合来导出,然后结果被馈送到监督的 ML 算法。

这种方法可行,但结果并不令人鼓舞。手工制作功能所需的工作量首先是巨大的;此外,它需要相当数量的领域知识,并且非常特定于用例。比方说,为检测 X 射线图像中的骨折而创建的手工制作的特征对于识别写在递送包裹上的名字可能没有用。

图 1-插图-使用机器学习的传统计算机视觉解决方案

为了减少手工制作特征的工作量,如果我们考虑以表格形式表示图像,即每个像素值都转换为一个特征,结果会非常令人失望。网络/ML 算法捕获的图像几乎没有任何信息,因此性能很差。

图 2 —插图—将图像展平为 ML 解决方案的表格数据

从上面的问题空间,我们可以推断出一个重要的细节——图像的特征提取是不可避免的,但很难解决

这里有几个例子可以帮助你理解基于计算机视觉的任务难以解决的原因。为了简单起见,让我们假设我们正试图从图像中预测一只猫,作为一个二元问题。

参考下面演示的两幅图像;基于像素值,这两个图像在数字格式中将具有完全不同的表示。由于像素值仅表示每个像素应该输出的颜色,因此底层表示的语义没有任何直观意义。

图片来源——亚历山大伦敦https://unsplash.com/photos/mJaD10XeD7w

类似地,一只猫经常被表现为背景分离不良。看看下面的图片;传统的功能大多会产生徒劳的结果。因此,手工制作的功能在这里将不会那么有效。

图片鸣谢——米哈伊尔·瓦西里耶夫、赵凯文、汉娜剧团@ Unsplash.com

此外,给猫拍照的方式多种多样,这使得拍摄过程变得更加困难。这些与猫不同的姿势只是其中的几个。

图片来源:马尔科·布拉泽维奇、蒂莫·沃尔茨、威利安·贾斯登·德·瓦斯康塞洛斯@ Unsplash.com

这些问题,当外推到一个更一般的用例时,比如说在一幅图像中检测多个对象,会成倍地增加复杂性。

显然,像素的表格表示或开发检测特定特征的手工特征或将两者结合起来并不是解决计算机视觉问题的最佳手段。

那么,解决计算机视觉问题的更好方法是什么呢?

从历史上看,我们已经看到手工制作的功能,虽然需要大量的努力,但是在一定程度上解决了问题。但是这个过程非常昂贵,并且需要大量的领域知识来解决特定的问题。

如果我们能自动提取特征会怎么样?

幸运的是,这是可能的,它最终将我们的讨论主题'卷积神经网络'带到了最前沿。CNN 提供了一种优越的方法来解决计算机视觉问题,它使用一种通用的、可扩展的但可持续的方法,这种方法可以跨领域应用,而无需预先了解该领域。不再需要创建手工制作的特征,因为给定足够的训练和数据,网络可以自我学习提取强大的特征。

深度卷积神经网络的想法最初由 Hinton,Krizevsky,Sutskever 发表,并在当时的 ImageNet 分类挑战中用于实现最先进的性能。这项研究彻底改变了计算机视觉领域。你可以在这里阅读更多原文。

深入了解深度卷积神经网络

CNN 的通用架构如下所示。目前细节可能有点抽象,但只要再坚持一会儿,很快就会了解每个组件的细节。该架构中的特征提取组件将是“卷积+汇集”的组合。您可能已经注意到这个组件是重复的,在大多数现代架构中,您会看到这个组件在一个层次结构中重复多次。这些特征提取器首先提取低级特征(比如边缘、线),然后从若干低级特征中提取作为形状或组合的中级特征,最后提取高级特征,比如在猫检测示例的情况下的耳朵/鼻子/眼睛。最后,这些层被展平,并使用激活连接到输出层(类似于前馈神经网络)。

图 3—卷积神经网络示意图

但是首先,让我们从基础开始

让我们花一点时间来了解人类大脑通常是如何通过视觉识别物体的。简而言之,我们的大脑从视网膜接收关于它从外部世界感知的视觉信号。首先,检测边缘,然后这些边缘有助于检测曲线,然后是更复杂的图案,如形状等。从小边缘到线条、曲线、复杂形状甚至更复杂的形状,神经活动的层次编排最终有助于识别特定的对象。当然,这是一个高度简化的过程,人类大脑同时处理更复杂的操作。

类似地,在卷积神经网络中,我们在学习非常基本的特征的早期层中进行特征学习。“深度 CNN”中的“深度”是指网络的层数。在常规 CNN 中,通常有 5-10 个甚至更多的特征学习层。尖端应用中使用的现代架构的网络深度超过 50-100 层。CNN 的工作非常类似于人脑通过视觉皮层识别视觉成分的过于简化的工作。

让我们进入 CNN 构建模块的细节

我们将首先从理解什么是卷积开始。

“卷积”是从信号处理领域借用的运算;在深度学习领域,它基本上是通过滑动图像的长度和宽度来执行图像(矩阵)与核或过滤器(另一个更小的矩阵)之间的矩阵乘法。下面的动画演示了在[5x5]图像上卷积[3x3]滤镜/内核。卷积运算的结果是一个尺寸为[3x3]的较小图像。

来源—https://giphy.com/gifs/blog-daniel-keypoints-i4NjAwytgIRDW

这种矩阵乘法本质上是特征提取的基础。使用正确的内核值,我们可以从图像中提取显著的特征。下面演示了在真实图像上进行这种操作的一个示例。我们可以看到,在使用核作为单位矩阵时,原始图像保持不变。然而,当我们使用不同的内核时,可以看到类似于使用其他边缘检测器/平滑/锐化等的结果。图像处理技术。

来源——维基百科

这就完成了故事的一部分,同一组件的下一部分是池。一个层有助于减少图像表示的空间大小,以减少网络中的参数和计算的数量。这个操作简单地通过使用定义的内核大小的最大值来进行。下图是一个简单的池操作示例。对来自大小为[20×20]的卷积(另一个矩阵)的输出执行使用大小为[10×10]的核的池操作。最终结果是一个[2 x 2]矩阵。

来源—http://deep learning . Stanford . edu/tutorial/supervised/Pooling/

使用卷积层和池层(通常是最大池)的组合,我们创建了 CNN 的基本构建块。根据内核和池的大小,执行卷积+池操作可以减小原始输入的大小。使用 1 核,当我们对输入图像执行卷积时,我们得到一个特征图。在 CNN 中,通常在单个卷积单元中使用几个核。下图突出显示了卷积过程中从 n 内核中提取的特征图。

图 4——CNN 架构示意图

多次重复这个过程会产生更深的卷积神经网络。每个图层都有助于从前一个图层中提取要素。这些层的分级组织有助于增量学习特征,从小边到从较低级别特征创建的更复杂的特征,再到捕获足够信息的高级特征,以便网络可以准确预测。

最后一个卷积层连接到一个全连接层,该全连接层用于应用相关的激活来预测结果;对于二元结果,我们对非二元结果使用 sigmoid 和或 softmax 激活。

所讨论的整个架构可以简化如下——

图 5——简化 CNN 架构示意图

到目前为止,我们已经忽略了复杂的 CNN 架构中的几个重要方面。但这是有意让事情变得简单,并帮助您了解 CNN 的基本概念。

其他几个重要的关键概念是-

  • 步距 —简单来说,步距可以定义为过滤器移动的量。当我们讨论滤波器在输入图像上的滑动时,我们假设该移动只是在预定方向上的 1 个单位。然而,我们可以用我们选择的数来控制滑动(尽管通常使用 1)。基于用例的需要,我们可以选择一个更合适的。更大的步幅通常有助于减少计算、概括特征学习等。
  • 填充— 我们还看到,与输入图像的大小相比,应用卷积会减小特征图的大小。在应用大于 1x1 的过滤器并避免边界处的信息丢失之后,零填充是控制维度收缩的通用方法。

为了说明填充和步幅的概念,下面的图片会非常方便

  1. 无步长填充(蓝色为输入,绿色为输出)

来源和学分-【https://github.com/vdumoulin/conv_arithmetic

2.无步长填充(蓝色为输入,绿色为输出)

来源和信用—https://github.com/vdumoulin/conv_arithmetic

我们直到现在才接触到的其他几个重要方面是批量规范化层漏失层。这两者都是 CNN 关注的重要话题。今天,我们通常将卷积单元定义为(卷积+最大池化+批处理规范化)的组合,而不仅仅是前两者。批量标准化是一种技术,通过对每个小批量的层的输入进行标准化,有助于轻松训练非常深的神经网络。标准化输入有助于稳定学习过程,从而大大减少训练深度网络所需的训练次数。

另一方面,是一种最有助于减少过度拟合和泛化的正则化技术。

将这些点连接起来

现在我们已经对卷积神经网络的基本构建模块有了一个相当好的理解,我相信你会有几个问题困扰着更好的细节。你可能会想到的最重要的问题是‘我们如何决定使用什么过滤器’,‘有多少过滤器?’等。

让我们逐一解决这些问题

我们如何决定使用什么样的过滤器?

这个问题的答案很简单。我们用从正态或其他分布中采样的随机值来设置过滤器。这个想法可能有点令人困惑,难以推理,但它工作得很好。在训练网络的过程中,它逐步学习最佳过滤器,这些过滤器将有助于提取准确预测标签所需的最多信息。这就是神奇的地方,我们从技术上消除了手工制作特征的过程。给定足够的训练和数据,网络负责制作适当的过滤器来提取最佳特征。

在每个卷积单元中,我们使用多少个滤波器?

没有标准的数字。过滤器的尺寸和数量是可以调节的超参数。一般的经验法则是使用奇数尺寸的过滤器,比如 3x3、5x5 或 7x7。此外,较小的过滤器通常比较大的过滤器更受欢迎,但这也带来了一种折衷,可以通过经验验证来解决。

网络如何学习?

这类似于我们在之前的博客中研究的前馈神经网络。我们使用网络的反向传播技术来更新滤波器中的权重,从而学习图像中的地面特征。学习过程有助于网络发现能够从输入图像中提取最多信息的最佳过滤器。

上面的图像是一个简单的 2D,大多数图像是三维的;3D 图像的网络是如何工作的?

为了简单起见,插图使用了 2D 图像。我们使用的大多数图像都是带有(RGB)颜色通道的三维图像。在这种情况下,除了内核的维度之外,一切都保持不变。核现在将是 3 维核,其中第 3 维将等于通道的数量。比方说,输入图像中的 3 个颜色通道(R、G 和 B)的 5x5x 3

卷积神经网络和深度卷积神经网络有什么区别?

他们两个是一样的;这里的深是指架构中的层数。大多数现代 CNN 架构有 30-100 层深。

训练一个 CNN 需要 GPU 吗?

不是强制性的,而是建议性的。利用 GPU 几乎可以将训练神经网络的处理速度提高 50 倍。此外,Kaggle 和 Google Colab 平台免费提供基于 GPU 的环境(每周使用上限。

好了,基础完成了;给我一个切实的例子

让我们用一个实际的例子来演示如何使用 PyTorch 构建一个 ConvNet。

我们将回忆在上述内容中涉及的所有主题。

首先,让我们导入所有必需的包。我们将从 Scikit-learn 导入所需的实用工具、神经网络核心模块和少量外部模块,以评估网络性能。

接下来,让我们将数据集加载到内存中。对于这个例子,我使用的是 Kaggle 上的 MNIST csv 数据集。你可以在 Kaggle 上找到完整的数据集

图 6—上述代码片段的输出

现在,我们已经加载了数据集,让我们将它转换成 PyTorch 友好的抽象。

图 7—上述代码片段的输出

我们现在将定义 CNN 架构,还将定义有助于我们评估和生成预测的其他功能。

图 8—上述代码片段的输出

最后,让我们来训练我们的模型。

图 9—上述代码片段的输出

我们现在有一个经过 5 个时期训练的简单模型。对于大多数用例,您需要 30 个以上的历元才能获得出色的性能。现在,让我们计算验证数据集的准确度,并绘制混淆矩阵。

图 10—上述代码片段的输出

这就完成了对这个沉重话题的简单介绍。希望你喜欢。此外,我建议玩这个神奇的工具,以了解每个图层如何为不同的输入图像生成过滤器和特征地图。

工具——可视化 CNN 在行动

您可以从我的 git 资源库—pytorchesamples访问并下载整个笔记本

总结想法

这篇文章的目的是用一种非常简单的语言给初学者一个简单的入门。保持数学的抽象性,将注意力从纯粹的功能性方法转移到利用现代企业项目的深度卷积神经网络。

在下一篇文章中,我将介绍“递归神经网络的外行指南”,这些例子将再次出现在 PyTorch 中。

模糊文档重复数据删除的外行指南

原文:https://towardsdatascience.com/a-laymans-guide-to-fuzzy-document-deduplication-a3b3cf9a05a7?source=collection_archive---------6-----------------------

检测近似重复文档的实用概念,后面是一个 Python 代码示例。

来源:aitoff via Pixabay

在我们这个数据呈指数级增长、项目复杂、团队庞大、渴望进入下一个截止日期的时代,小事情经常被忽略。

我们的数据分析师团队在一家大型律师事务所看到了这种情况,在那里,重要的文档经常被共享、编辑、再次共享,并存储在专用的文档服务器上。二十年和一百万份文档之后,服务器变成了一个由嵌套文件夹、难以理解的文件名和损坏的文件组成的迷宫。

我们的目标是在海量存储中筛选重要文件,但我们首先要解决一个问题。

我们为非常重要的文件建议了一个新的干净的地方。然而,这需要文档是可搜索的,相关的,特别是独特的。快速浏览一下文件,我们可以发现数据中有许多重复的地方。

我们不能依赖文件名、日期或任何其他唯一的标识符。我们所拥有的只是文本文档本身的内容。

为什么这个问题比编写一个简单的“完全相等”的脚本来查找文本完全相同的文档更复杂呢?问题在于,在实践中,搜索 100% 相似度会漏掉许多重复的文档。原因多种多样,但包括:

  • OCR(光学字符识别—将 PDFs 图像转换为文本时使用)期间的差异
  • 小的修改、草稿
  • 用于保存或加载文档的软件版本/方法的可变性

通过允许“模糊”的重复数据删除,其中脚本识别出大部分相似的文档,我们可以避开任何可能导致两个重复文档彼此不一致的问题,例如标点符号、大写字母、空格等。如您所见,我们将有一个杠杆来调整如何将相似的文档归类为副本。

虽然此使用情形非常具体,但在许多情况下可能需要大规模重复数据消除,包括:

  • 节省存储空间
  • 检查抄袭/版权
  • 确保问答网站上只有新问题
  • 检查数据库中的新条目以确保唯一性
  • 消除膨胀数据集中的噪音

首先,让我们从理论的角度来看解决方案。之后,我们可以向那些对理论背后的代码感兴趣的人展示一个简短的 Python 实现。

为了便于说明,我们将考虑一个现实生活中的用例。我们将使用来自 Kaggle 竞赛的数据集,其目标是检测在线市场中的重复广告。在本指南中,我们将重点关注广告文本。

提交广告的人通常会对他们现有的广告进行调整,然后重新提交,以提高人们找到他们产品的几率。

在 Craigslist 上的一次快速旅行马上向我们展示了这样一个例子:

Craigslist 上发布的多余广告

看到其中一些措辞略有不同了吗?精确匹配系统永远不会发现这些。

我们希望通过标记和删除重复广告(即使它们不是逐字相同的)来减少用户的混乱。

关于数据集的一些基本信息:

  • 我们使用了 100,000 个广告样本。这个解决方案可以扩展到数百万个文档,这取决于您有多少时间和计算能力/内存可用。
  • 执行一个简单的“完全相同”的脚本,就像我们上面描述的那样,我们看到大约 96,000 个广告是原创的(或者至少,不是任何其他广告的精确复制)。
  • 大约有 1000 个广告是完全相同的。有些是复制了几十次的,有些只是一次。
  • 虽然重复的广告应该只占数据集的 1%,但大量的副本使它们膨胀到数据的 3.7%。
  • 文本本身是俄语的——幸运的是这并不重要,因为解决方案对语言来说是矛盾的。必要的地方我会用谷歌翻译。

让我们使用“完全相等”脚本来看看数据集中重复次数最多的广告:

网上销售跨越语言障碍!

我们可以马上看到严格重复检测的一些缺点。请注意“状况良好”是如何因为大写或标点符号而被分成三个独立的类别的。我们简单的脚本错误地将这些归类为完全独立的原始文本。

数据中的另一个常见模式更加可疑——更长、措辞略有不同的特定广告:

太巧了!

下面我们将开发一个更复杂的解决方案来检测附近的副本以及精确副本。

在我们深入研究这个案例之前,让我们先来谈谈支持我们努力的概念。

字符串相似度与余弦距离

为了以一种“模糊”的方式删除这些冗余广告,我们需要找到一种方法,将文本转化为数字,以定量分析相似性。

有几种不同的方法,但最流行和有效的测量“字符串相似性”或文本相同性的方法之一被称为余弦相似性

背后的逻辑非常简单。如果我们可以将文本转换成一个向量(图上的一条线),我们就可以在数字上将其与其他向量(同一张图上更多的线)进行比较。线条的位置取决于文档的内容。

例如,考虑以下三个短语:

"黄油爆米花"

“咸爆米花”

"黄油羊角面包"

直观上,我们可以看到这些短语或文档之间的一些相似之处。其中两个是黄油,两个是爆米花。然而,为了扩展到比较数百万个文档,我们需要使问题能够被机器理解。

让我们简单统计一下一个单词在每个短语中出现的时间。结果将如下所示:

将文档转换成文档向量

每一行都是我们称之为的文档向量,定量地表示每个文档。

我们在这里只包括了两个特性(列),尽管您可以拥有与您的语料库(整个文档集合)中的独特单词一样多的特性。例如,我们可以为羊角面包添加第三维度。

因为我们只有 butterypopcorn ,我们可以在 2D 绘制这个数据集来说明余弦相似性是如何工作的:

y 轴测量我们看到“黄油”的频率,而 x 轴测量我们看到“爆米花”的频率。我们可以看到我们的三个文档标有蓝点。

  • 黄油羊角面包富含黄油
  • 咸爆米花在爆米花维度上很高
  • 黄油爆米花两样都有

绿色文本表示我们的余弦相似度计算。我们可以看到黄油羊角面包咸爆米花之间有一个非常大的 90 度角。黄油爆米花咸爆米花的角度更小,只有 45 度。

我们可以停在这里,但是取这些角度的余弦值将会使它们归一化,分别为 0.0 和 0.7。很方便,余弦计算的最小值总是-1(180 度),最大值总是 1(0 度)。

我们已经成功地用两个特征量化了这些文本的不同之处。考虑到我们的文档包含成百上千个独特的单词,我们将拥有同样多的特性。不可能在上面这样的图上可视化这么多的文档向量,但是请放心,逻辑在数千个维度上是完全相同的。电脑会帮我们处理的。

然而,还有一个问题。如果我们只是计算文档中的字数,我们的方法不会考虑词序。例如,我们上面的余弦相似性方法如何解释以下两者之间的差异:

  • “条件好,没得商量”
  • “条件不好,可以商量”

不是很清楚,因为它们包含完全相同的单词,只是顺序不同。我们可以看到这些短语具有非常不同的含义,但是我们的余弦相似性将简单地看到它们包含所有相同的单词,对于 100%相似的分数!

N-Grams 保持词序

一个 n-gram 简单地描述了来自给定样本的一系列 n 项。在文本中,这可能是给定句子中的一系列单词。因此,假设您想要文档“条件良好,不可转让”中的所有 2 个字母(或字母组合),以下是您将收到的三个字母组合:

“状态良好”

"条件 _ 非"

“不可协商”

类似地,如果您想要 3-grams(或三元组,您将收到:

“良好 _ 条件 _ 不”

“条件不可协商”

你能明白为什么拥有这些额外的特性会有用吗?

我们不仅在单个单词上创建文档向量,还在所有二元模型和三元模型上创建它!现在“条件好,不可协商”和“条件不好,可协商”将理所当然地获得较低的相似性分数,因为它们的二元模型和三元模型不一致。

为什么不是欧几里德距离?

你可能会问的一个问题是——为什么要费力测量文档向量之间的角度?从上面的图表中我们可以看到,您可以为每个文档绘制一个点—为什么不只是查看点之间的距离(欧几里德距离)?

这是一个很好的问题。要回答这个问题,让我们看看下图:

现在,我们已经为文档增加了数量,其中一些单词出现了多次。我们有一个非常黄油的文档(x4),一个是黄油加爆米花的文档(x2,x1),一个只是爆米花的文档(x1)。

虽然直觉告诉我们第二个文档更接近第一个文档,因为它们都在黄油上超载,但是欧几里得距离 A (2.2)实际上大于欧几里得距离 B (2.0)。使用这些距离,我们可以说共享一个“爆米花”术语的文档比共享两个“黄油”术语的文档更相似!

然而,角度 A 和 B(用余弦相似性度量)支持我们的直觉,即 buttery 文档比 popcorn 文档更相似。

事实上,当量值被归一化时(所有的点从图形的原点开始都是等长的),欧几里德距离和余弦相似度将返回相同的结果。

余弦相似性的另一个好处是计算机计算起来更便宜,当我们谈论数百万或数十亿次比较时,这可以节省大量时间。

其他标准化

自然语言处理领域既深且广,根据您的用例,还有许多其他方法可以通过预处理来提高数据质量。

比如,词干化会将所有单词规格化为它们最基本的形式(运行变成运行交付变成交付)。

另一个转换采用我们创建的文档向量,称为单词袋向量(因为我们只是简单地计算每个文档中有多少单词),并将其转换为术语频率—逆文档频率向量( TF-IDF) 。这是一个非常强大的转换,可以帮助您完成像文档分类这样的任务。你忽略了在你的整个语料库中频繁出现的单词( the,he,her,it,等)。 )关注在特定文档中出现的较罕见的单词,但而不是在整个语料库中出现,因为后面这些单词更有可能是有意义的。

这些转换值得了解,但我们不会在这里使用它们,因为副本通常会使用相同的单词形式(不需要词干)和术语频率(不需要特别加权不同的术语/文档)。

最后,如果你处于这个领域的前沿,你会考虑使用文档嵌入,这是将文本意义映射到数字向量的另一种方法。这超出了本文的范围(对于我们的重复数据删除应用程序来说可能有些过头了)。

用余弦相似度去重广告

做得好!您现在已经掌握了一个非常有用的工具。让我们看看如何将它应用到前面的重复广告检测示例中。

第一步是创建一个文档术语矩阵。您已经在前面的 popcorn 示例中看到了其中的一个——它只是一个在行上跟踪文档的结构,在列上跟踪特定的术语(注意:不再是“单词”,因为我们也可以放入 n-grams)。文档中每出现一个术语,矩阵中相应的单元格就加 1。

让我们看看数据中的几个例子的矩阵是什么样的。为了更好的说明,我把俄语的例子翻译成了英语,尽管这种方法适用于任何语言。

橙色单元格代表我们的文档和术语之间的交叉点。我们可以看到多个文档包含相同的术语——就像条件属于四个文档。这将有助于提高这些文档之间的余弦相似性得分。

既然我们已经将文本数据转换为文档向量,我们可以应用成对余弦计算来评估所有文档之间的相似性。成对只是意味着我们将从数据集中的每两个例子中得到一个数字——每个文档都需要与其他每个文档进行比较,以查看是否有任何相似之处。

请注意,这可能会变得计算量很大——在技术部分,我们将讨论一个在执行该计算时可以节省资源的伟大包。

让我们看看上面例子的余弦相似性计算为我们提供了什么:

每个文档沿着行和列放置,成对余弦相似性填充在单元格中。

正如我们所料,我们在对角线上看到了 100%的相似性——所有文档都是完全相同的。例如,“状态极佳的 14.5cm”在第一行第一列,导致第一个单元格为橙色 100%。当然,当我们进行分析时,我们不会将这些自相似的细胞算作数据集中的“重复细胞”。

马上,我们看到一些有趣的结果:

  • “14.5 厘米处于极好状态”和“处于极好状态”共享足够多的术语,以至于它们具有 71%的余弦相似性。
  • “状态良好的衬衫”和“状态良好的衬衫”获得 100%的相似性,因为我们的过程不区分大小写。

我们可能会认为第一场比赛是而不是重复,而第二场重复。我们可以开始看到在 71%和 100%之间形成复制截止的直觉,但更多的是在以后选择这个阈值。

请注意,我还在图形中包含了原始的俄语文本。这有助于解释为什么“ 14.5 厘米状况极佳”“状况良好”没有收到任何相似性。在俄语中,两个 ccondition术语的拼写略有不同(一个表示“条件”,另一个在技术上表示“状态”),导致该术语背后的含义完全不同/独立。

这些结果来自 6 个文档的小样本,为我们提供一些直觉。让我们看看在 100,000 个文档的数据集上的结果是什么样的。

为了进行比较,让我们将调查结果与本文前面采用精确/严格的重复数据消除标准得出的结果进行对比:

我们的模糊重复数据删除发现了 2,244 个重复文档,约占总数据集的 2%。当考虑到这些重复广告的多个副本的膨胀效应时,这些重复广告占我们数据的 7.5%!

通过允许模糊重复数据删除,我们发现的重复文档是以前的两倍。

我们将看看三个例子,这些模糊的发现是我们现在发现的。

在第一个例子中,我们选取了“良好状态”的变体。虽然很有趣,但这并不是欺骗性广告的例子——这只是销售商品的人们的常用语!

第二个例子代表了在整个数据集中看到的许多广告的模式。虽然语序不同,但内容是一样的!我们可以确信这是一个销售同一双运动鞋的欺骗性广告。

作为我们的最后一个例子,我们看到几十个蹦床广告,其中唯一的变化是蹦床本身的尺寸。一个对蹦床不感兴趣的本网站用户当然不需要看到这样的品种。作为网站所有者,你可以选择对这种冗余采取行动。

其他适合这种模式的例子是重复广告,唯一的区别是地址、电话号码或产品颜色。

现在,我们已经完全开发了余弦相似性重复数据删除方法,并看到了一些结果,我们几乎完成了本文的理论部分。有一个非常重要的悬而未决的问题需要讨论。

设置带有精度/召回的截止值

需要考虑的一个重要方面是我们选择的余弦相似性阈值。记住,当我们比较两个文档向量时,我们会得到一个介于 0%和 100%之间的余弦相似度。由我们来决定结果是通过还是未通过预定义的设定点。

0%的余弦相似性截止值会将所有内容标记为与其他内容重复,而 100%的截止值需要完全重复(非模糊)才能抛出重复标记。

没有普遍“正确”的答案,因为我们设置的截止值将取决于我们特定的用例。

一种极端的情况是,假设您正在删除稀有且非常有价值的旧手稿的重复数据。你会因为删除哪怕一份原稿而陷入麻烦,因为你认为这是一份非常相似但不同的原稿的副本。如果一些重复的数据没有出现在数据集中,也没什么大不了的。在这种情况下,您可能会错误地选择一个更高的重复数据删除截止值,该值对重复数据的检测更加严格。

在另一个极端,您正在删除数百万条推文的重复数据,作为大型项目的预处理步骤。每条推文本身没多大关系,你的主要目标是缩小数据。例如,你想通过垃圾邮件删除大量冗余的推文。如果你不小心删除了原创推文,那也没什么——你只是想通过删除唾手可得的果实来缩小你的语料库。

这就是精度召回的概念变得有用的地方——这些相反的力量将帮助您设置一个良好的重复数据删除截止值。

Precision 询问—在我们标记的“肯定”文档中(在我们的例子中,肯定与重复同义),有多少是真正的肯定/重复文档?

请记住,如果我们将文档标记为“正”/副本,但它不是真正的“正”/副本,我们只是错误地将原始文档标记为副本!根据我们的用例,这可能意味着我们已经提示删除一个原始文档。

来源:维基百科

在前一个罕见的手稿例子中,我们优化了精确度我们希望确保我们标记为重复的所有文档都是真正的重复文档。没有人会责怪我们为了安全而设置 99%的重复数据消除截止值。

另一方面,回忆询问——在所有真实的肯定/重复文档中,我们正确识别出多少是重复的?

这和精确有什么不同?在精度方面,我们关心的是我们得到了多少真阳性与假阳性。在回忆中,我们关心的是我们得到了多少真阳性与假阴性

在推文重复数据删除的例子中,我们更关心整个推文的重复数据删除,而不是确保我们标记的每条推文都是重复的。我们愿意为了召回而牺牲精确性。由于这种权衡,我们可以接受较低的余弦相似性截止值,比如说 70%。

假设我们有一个包含 100 个文档的数据集。我们已经手动查看了数据,并且知道有 20 个重复的文档应该被删除。

在余弦相似性截止值为 99%时,我们删除了 15 个重复的文档。然而,我们 100%确定我们删除的 15 个都是真正的重复。我们非常精确(15/15–100%),但是召回率很低(15/20–75%)。

在余弦相似性截止值为 70%时,我们删除了 30 个文档。我们当然删除了 20 个真正的重复项,以获得非常好的回忆分数(20/20–100%)。然而,我们也删除了 10 份并非真正重复的文件。这导致精确度分数很低(20/30–66%)。

看到精度和召回是怎么对立的了吧?在实践中,有必要提取数据集的样本,标注原件和副本,并尝试针对您的具体情况优化截止阈值。

此外,余弦相似性可能只是更大的统计模型的一个特征。在广告重复数据删除示例中,包含关于产品图像、用户名、发布时间戳等信息可能是有意义的,最终将这些信息输入到二进制分类模型中以标记重复广告。

为了便于说明,我们使用了 95%的相似性截止值。相对严格,但正如我们在上面看到的,我们仍然在模糊重复数据删除方面获得了显著的性能。

理论到此为止!如果您已经坚持了这么长时间,谢谢您——您现在已经实际熟悉了一种有价值的方法来帮助您驯服重复数据。

如果您有技术爱好,并且想知道如何编写类似上述示例的代码,我们将继续提供一些 Python 代码片段,它们可以执行我们刚刚讨论的方法。

使用 Gensim 在 Python 中实现

为什么是 Gensim?

Gensim 是一个 Python 库,广泛用于主题建模。但是,它对于重复数据消除也有非常有价值的实用程序。

虽然在 Python 中有几种有效的方法来计算余弦相似性,包括使用流行的 SKLearn 库,但当数据集变得非常大时,Gensim 的主要优势就来了。

当你的语料库增长超过你的计算机在内存中存储数据的能力时,Gensim 会自动将你的语料库分割成计算机可读的数据块,然后将其保存到磁盘。通过将数据放在磁盘上,您可以在遇到内存问题之前处理更大的数据集。您还可以加载并重用存储在磁盘上的碎片。

与此相关的是,一旦你生成了一个相似性索引(我们将在下面看到),你可以把它保存到磁盘上,并逐步增加更多的文档,而不是从头开始重新计算。这允许一次性的时间密集型提升来加载您现有的语料库,每当您向您的语料库添加新数据并想要重新计算相似性时,更新都非常快。

导入包

首先,我们从 Gensim 导入我们需要的模块。注意,要自己运行代码,您需要下载带有 pipconda 的 Gensim。

#Import necessary gensim packagesfrom gensim.utils import simple_preprocess
from gensim.models.phrases import Phrases, Phraser
from gensim import corpora
from gensim.similarities import Similarity

让我们定义一些测试数据。

#Test datasetdocuments = [
    “Used SpaceX rocket as-is, buyer must transport.”,
    “Used SpaceX rocket as-is, buyer must transport.”, “For sale: bulk 100lbs pack of spaghetti noodles”,
    “Spaghetti noodles for sale — 100lbs bulk pack”, “Pale blue tuxedo, used, good condition. Call 555–555–5555”,
    “Brand new yellow tuxedo in great condition!”
]

数据预处理

一般来说,我们在单词级别处理文档。这里有一个简单的方法将文档分解成正确的格式:

*#Convert documents to collection of words**texts = [[text for text in simple_preprocess(doc, deacc=True)] for doc in documents]*

simple_preprocess 是一个有用的 Gensim 函数,用于将文档解析成单个单词。您可以根据需要向它传递额外的参数。在这里,我们通过“deacc=True”来去除标点符号、重音符号和数字。

这里是“二手 SpaceX 火箭原样,买家必须运输。”简单预处理后:

[‘used’, ‘spacex’, ‘rocket’, ‘as’, ‘is’, ‘buyer’, ‘must’, ‘transport’]

构建 N-Grams

我们将使用单词级结构来训练一个 Gensim n-gram 短语器。

普通的二元模型生成器会为每个词对(used_spacex,spacex_rocket,rocket_as)生成一个二元模型,而 Gensim 短语生成器经过预处理,可以选择搭配,或者通常会在一起出现的词。例如,只有 spacex_rocket 将被保留,因为短语者认为它是单词的可能搭配。

这种选择性是节省程序运行时间的一个很好的方法,因为它不需要为每个可能的单词排列存储一个特征。

#Build a bigram model to capture every pair of words in the textsbigram = Phrases(texts, min_count=1)
bigram_phraser = Phraser(bigram)

min_count 参数指定短语必须在语料库中找到多少次才能被保留。因为我们的数据集很小,所以我们把它保持在 1。

现在我们有了一个训练有素的 Gensim Phraser,我们将在句子转换成术语的过程中使用它。这看起来和以前一样,除了我们包含了 bigram_phraser 变量。

#Reconvert documents to collection of words/bigramstexts_bigrams = [[text for text in bigram_phraser[ simple_preprocess(doc, deacc=True)]] for doc in documents]

例如,“出售意大利面条——100 磅散装”现在变成了:

['spaghetti_noodles', 'for_sale', 'lbs', 'bulk', 'pack']

创建 Gensim 词典和语料库

Gensim 使用特定于包的结构来提高运行效率。具体来说,我们需要创建一个 Gensim 字典和 Gensim 语料库。

#Create dictionarydictionary = corpora.Dictionary(texts_bigrams)

Gensim 字典简单地将每个特定的术语(键)映射到一个唯一的 ID(值)。一个普通的 Python 字典表示如下:

In: {k: v for k, v in dictionary.items()}Out: 
    {0: 'as_is',
    1: 'buyer_must',
    2: 'spacex_rocket',
    3: 'transport',
    4: 'used',
    ...
    18: 'great',
    19: 'in',
    20: 'new',
    21: 'yellow'}

接下来是语料库:

#Create corpuscorpus = [dictionary.doc2bow(docString) for docString in texts_bigrams]

Gensim 语料库使用我们刚刚创建的字典将我们的原始文本文档转换成数字表示。通过用数字代替文本,计算变得更快。

例如,我们数据中的第一个文档——“二手 SpaceX 火箭,买方必须运输。”—现在看起来像:

[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)]

每组括号(元组)代表一个单词。第一个数字是单词在字典中的位置,第二个数字是它在文档中出现的次数。

对于(0,1),0 表示我们的二元模型“as_is”,它在文档中出现一次。

这些数字实际上只是代表一个单词包——我们之前使用的术语,意思是从文档中解构出来的、独立的术语集合。

这些元组中的每一个都代表我们的文档术语向量中的一个维度。

创建相似性指数

我们已经准备好为我们的文档术语向量集合计算余弦相似度了!

Gensim 为我们做了所有繁重的工作,我们只需使用正确的语法:

#Build similarity index
index = Similarity(corpus=corpus,
                   num_features=len(dictionary),
                   output_prefix='on_disk_output')

这实例化了相似性索引,它计算并跟踪每个文档相对于所有其他文档的余弦相似性——成对计算。Gensim 经过优化,可以相对快速地执行这一计算。 output_prefix 参数就是将要保存到硬盘上的文件的名称——如果需要的话,可以在以后重新加载。

让我们打开索引,看看里面有什么:

#Parse similarities from indexdoc_id = 0
similar_docs = {}
for similarities in index:
    similar_docs[doc_id] = list(enumerate(similarities))
    doc_id += 1

similar_docs 现在是一个 Python 字典,它跟踪每个文档,以及它和语料库中所有其他文档之间的相似性得分。

例如,第一个条目看起来像:

{0: [(0, 0.9999), #“Used SpaceX rocket as-is, buyer must transport.”
    (1, 0.9999),  #“Used SpaceX rocket as-is, buyer must transport.”
    (2, 0.0),
    (3, 0.0),
    (4, 0.1690), #“Pale blue tuxedo, used, good condition...
    (5, 0.0)],
 ...
}

因此,我们集合中的第一个文档(“0”——Python 是零索引的)(“二手 SpaceX 火箭,买家必须运输。”)和自己一模一样,和第二个文档一模一样。

它与第五份文件有 17%的相似性(“淡蓝色燕尾服,用过,状况良好。致电 555–555–5555”)。我们可以看到“used”是一个共享令牌。

设置截止阈值

我们将使用 90%相似的阈值。根据用例,我们可以将它上移或下移,如上所述。

sim_threshold = 0.9

查找相似文档

下面的帮助器代码将向我们返回超出阈值的文档对:

for doc_id, sim_doc_tuples in similar_docs.items():
    for sim_doc_tuple in sim_doc_tuples:
        sim_doc_id = sim_doc_tuple[0]
        sim_score = sim_doc_tuple[1]if sim_score >= sim_threshold and doc_id != sim_doc_id:
            print(f"Found similar documents, score of {sim_score:.2f}:")
            print('\t', documents[doc_id])
            print('\t', documents[sim_doc_id], '\n')

打印的结果包括:

我们找到了。我们能够验证第一对文档是精确的副本,第二对是模糊的副本。请随意使用这个测试代码来处理您自己的一些数据。

本指南到此为止!现在,您已经熟悉了有价值的文本分析技术,并准备在您的下一个项目中实施一种复杂的模糊重复数据删除方法。

感谢阅读!

python 和 matplotlib 绘图入门指南

原文:https://towardsdatascience.com/a-laymans-guide-to-plot-with-python-and-matplotlib-8462054f2059?source=collection_archive---------29-----------------------

卢克·切瑟在 Unsplash上的照片

在 10 分钟的咖啡休息时间用 matplotlib 打破僵局!

无论数据是多小或多大,数据可视化在任何领域都是一项必不可少的例行任务,无论是绘制简单的正弦曲线,还是为利益相关者创建复杂的交互式仪表盘。 Python 是当今最受欢迎的编程语言之一(在堆栈溢出的活跃前 3 名中),提供了数据可视化的巨大可能性。

Matplotlib 是一个如此强大的 python 绘图库,它提供了各种各样的 1D、2D 和 3D 可视化。作为 Stack Overflow 上 matplotlib 的金牌持有者,我想到创建一系列教程,旨在教授使用python&matplotlib绘制引人注目的图形的基本知识,提供即用型 Jupyter 笔记本

我的这第一篇帖子将教你 matplotlib 的,以一维图、连同基本饼图 图表为例。整个笔记本可以从我的 GitHub 下载/分叉。使用以下系统设置:Python 版本:3.7.7,Matplotlib 版本:3.1.3。本教程预计也适用于旧版本。

1) 让我们从 1D 的剧情开始

要在 Jupyter 笔记本中启用内嵌绘图,您需要在笔记本的开头使用以下内容

*%matplotlib inline*

如果您的屏幕支持 retina 显示屏,您可以使用以下方法提高图形的分辨率

*%config InlineBackend.figure_format = ‘retina’*

Matplotlib 提供了几个很酷的样式表来增强人物美感。我会用'fivethirtyeight'

*plt.style.use('fivethirtyeight')*

1.1)最简单的情节

最简单的示例是绘制一个值列表。让我们创建一个增量值列表并绘制它。**

*values = [5, 6, 7, 8, 9]
plt.plot(values)*

简单的线条图

你可以看到values被绘制在 y 轴上。为了在 x-y 空间上绘图,通常需要两个列表:一个用于 x值,另一个用于 y* 值。请注意,默认情况下,实线用于绘图。*

现在你可能想知道这个数字是如何在没有传递 x 值的情况下创建的。

默认情况下,当我们将单个列表传递给plt.plot()时,x-轴假定从零开始的整数值,直到比 y 值的长度小 1。在上图中,values有五行。所以x-值变成了 0,1,2,3,4(因为在 python 中索引是从 0 开始的)。换句话说,x-值为range(len(values)),其中len(values)返回列表的长度,即 5。因此,下面的线也将绘制相同的图形:

*plt.plot(range(len(values)), values)*

注意:如果您使用其他 python IDE,例如 spyder,您需要在plt.plot()命令后使用plt.show()来显示图形窗口。虽然你不需要在 Jupyter 笔记本上。

1.2)让我们绘制一些函数, 𝑦 =𝑓(𝑥)

我们将为𝑥∈(0,3𝜋):绘制以下两个函数

  • y = sin( x )
  • y = cos( x

NumPy 包在执行向量化操作时非常方便:

*import numpy as np*

接下来,我们将定义𝑥-values 并计算相应的 y- 值:

*x = np.linspace(0., 3*np.pi, 100) # 0 to 3*Pi in 100 stepsy_1 = np.sin(x) 
y_2 = np.cos(x)*

现在让我们绘制中的两个功能相同的图。在 1D 图中,两个关键元素是线标记(符号)。它们的属性都可以在打印时自定义。在下面的代码片段中,我将使用一些必须已知的必要属性(带有选择的选项)。传递给plt.plot()命令的参数将在本文稍后解释。

用下面的正弦和余弦曲线生成图形的代码片段。

同一图形中的正弦和余弦曲线。

1.3)面向对象的绘图方法

现在,让我们使用面向对象的方法来操作图形的属性。其中,有以下两种可能性:

方法一

*fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111)*

方法二

*fig, ax = plt.subplots(figsize=(8,6))*

下面我来演示一下方法 2 (我的最爱)的使用方法:

代码片段生成如下图。

使用上述面向对象方法的正弦和余弦曲线。

2)定制情节

2.1 选择线条样式和标记

在上述两种方法中,我使用了实线和圆形标记。下一节将教你如何选择不同的线条样式和标记。

1。线条样式:你可以明确地使用关键字linestyle='-'或者缩写ls='-'。以下是几种可用的线条样式:

  • '-':实线
  • '--':虚线
  • '-.':点划线
  • '.':虚线

2。标记:可以用关键字marker='o'。以下是几个可用的标记:

  • 'o':圆形
  • 's':方形
  • 'p':五边形
  • 'h':六边形
  • '^':上三角
  • 'v':下三角形
  • 'x':十字

2.2 选择颜色

1。颜色:你可以明确地使用关键字color='g'或者缩写c='g'

  • 标准颜色可以用单个字母:'r''g''b''k''o'表示红、绿、蓝、黑、橙
  • 对于标准色以及其他非标准色如'navy''darkorange''indigo'也可以指定全称为'red''green''orange'
  • 允许颜色的完整列表可以在这里找到。

妙招:使用'-r''--g'-.k等简写符号,既可以组合线型,也可以组合色彩。然而,您不能使用类似linestyle='-.r'ls='-k'的东西,因为现在您正在指定线条样式的属性,但是同时指定了线条样式和颜色。

加成:组合线条和标记 如果你想同时使用线条和标记,有两种可能。假设您想要一条带有方形标记的红色点划线。您可以使用以下两个选项之一:

  • '-.rs'
  • '-.r', marker='s'

2.3 控制线条和标记的属性

从上一节中,您现在知道了可以使用哪些线条样式和标记。下面将教你如何定制它们的属性。

1。台词:

  • lw代表线宽,例如:lw=2。也可以用关键字linewidth=2
  • alpha控制透明度(0 表示完全透明,1 表示不透明)。您可以选择 0 到 1 之间的任何浮点值。

2。标记:

  • ms代表标记尺寸,例如:ms=10。也可以使用关键字markersize=10
  • mfc代表标记面颜色,例如:mfc='green'。也可以使用关键字markerfacecolor='green'
  • mec代表标记边缘颜色,例如:mec='red'。也可以使用关键字markeredgecolor='red'
  • mew代表标记边缘宽度,例如:mew=5。也可以用关键字markeredgewidth=5
  • alpha控制透明度(0 表示完全透明,1 表示不透明)。您可以选择 0 到 1 之间的任何浮点值。

3)散点图

到目前为止,我们使用了plot模块,其中两条不同的曲线分别用直线和标记绘制。有时候,你会想要一个散点图。这可以通过间接实现,就像你在上面看到的余弦曲线那样,也可以通过scatter图直接实现。**

plt.plot()中,您只能传递 y 值,而 x 值会自动生成。然而,在散点图中,**你需要同时传递 xy-值**。

以下是散点图的一些基本特征参数:

  • marker:选择散点样式。在这种情况下,你不能使用缩写m
  • s:定义标记尺寸。
  • c:定义散射颜色。也可以用关键字color
  • edgecolor:定义标记的边缘颜色。也可以用关键字ec
  • facecolor:定义标记的颜色。也可以用关键字fc。它做的事情和c一样。但是,如果首先指定c='red',然后再指定facecolor='blue',最初设置的红色标记将被蓝色取代。

plt.plot()类似,对于标准颜色,您可以使用它们的全名(redbluegreen等)。)或者只是他们的第一个字母'r''g''b'等等。

您可以试验一下ax.legend()中的TrueFalse值,看看它是如何影响图例框的。

您可以阅读散点图的官方文档了解更多详情。

*fig, ax = plt.subplots(figsize=(8,6))ax.scatter(x_1, y_1, color='red', marker='s', edgecolor='black', s=50, label='$f(x)$=sin($x$)')# 'fancybox=False' produces a legend box with sharp edges.
ax.legend(loc='best', frameon=True, fancybox=False)
ax.set_title('A simple scatter plot');*

显示正弦曲线的散点图。

4)条形图

4.1)垂直条形图(又名柱形图)

我将使用面向对象的方法。也可以用plt.bar()。以下是传递给条形图的一些基本参数:

  • width:棒材的宽度。
  • edgecolor:定义条形的边缘颜色。也可以用ec
  • linewidth:定义棒材边缘的宽度。也可以用lw
  • linestyle:定义边缘的样式。也可以用lw。可以使用与前面为线图指定的样式相同的样式。
  • color:定义条的颜色。在这种情况下,你不能使用缩写c
  • hatch:定义条形的阴影/填充样式。可以用o*///\\-+|这样的风格。影线也将具有与边缘相同的颜色。

您可以阅读条形图的官方文档了解更多详情。

让我们定义一些样本数据,例如一个班中 5 个学生的成绩,并绘制一个垂直条形图。

*names = ['Tom', 'Mark', 'Sam', 'Jim', 'Henry']
grades = [79, 85, 49, 98, 65]fig, ax = plt.subplots(figsize=(8,5))ax.bar(names, grades, width=0.5, hatch='/', edgecolor='black', ls='--', linewidth=3, color='orange')
ax.set_ylabel('Grades')
ax.set_title('A basic bar chart');*

显示一个班中五个学生成绩的垂直条形图。

如果您希望每个条形都具有特定的颜色,可以传递所需颜色的列表。如果传递的颜色列表中的元素数小于条形数,颜色循环将会重复。

例如,如下图所示,如果您有五个条,但您选择了color=['r', 'b', 'g'],前三个条将分别为红色、蓝色、绿色,其余两个条将分别为红色和蓝色。

*fig, ax = plt.subplots(figsize=(8,5))ax.bar(names, grades, width=0.5, hatch=’/’, edgecolor=’black’, linewidth=3, color=[‘r’, ‘b’, ‘g’])
ax.set_ylabel('Grades');*

带有自定义颜色的垂直条形图。

4.2 水平条形图

绘制水平条形图时,只需用barh代替bar

最重要的是,你要用关键字height代替条块的width

*fig, ax = plt.subplots(figsize=(8,5))ax.barh(names, grades, height=0.5, hatch=’/’, edgecolor=’black’, linewidth=3, color=[‘r’, ‘b’, ‘g’])
ax.set_xlabel('Grades');*

显示一个班中五个学生成绩的水平条形图。

5)饼图

我将使用面向对象的方法。也可以使用plt.pie()

以下是饼图的一些基本特征参数:

  • labels:饼图每个扇区的名称标签。
  • shadow:开启阴影效果。可以是True也可以是False
  • labeldistance:控制labels径向远离/靠近饼图的距离。
  • autopct:自动计算百分比分布,并以定义的格式给每个楔形标注相应的值。例如,'%.0f%%'将百分比显示为整数值,'%.2f%%'将显示最多两位小数的百分比。

更多详情可以阅读饼状图的官方文档

*names = ['Tom', 'Mark', 'Sam', 'Jim', 'Henry']
shares = [15, 13, 46, 22, 30]fig, ax = plt.subplots(figsize=(8,8))ax.pie(shares, labels=names, autopct=’%.2f%%’, shadow=True, labeldistance=1.1)
ax.set_title(‘Distribution of shares’, fontsize=18, y=0.95);*

份额持有人分布饼状图。

5.1)设计饼图的样式

如果您希望突出贡献最大的人,您可以使用选项explode从饼图中分割出最大的楔形。

您需要指定explode的值,它决定了分割的楔形从饼图中心的距离。由于我们有五个人,我们需要指定一个包含五个分解值的列表,例如explode = [0, 0, 0.15, 0, 0]。您还可以为所有元素指定有限值,例如explode = [0.1, 0.2, 0.3, 0.4, 0.5]。下面的例子说明了这一点。

这里,我手动将值 0.15 指定为explode列表的第三个元素,因为百分比最高的是names列表的第三个元素“Sam”。

*fig, ax = plt.subplots(figsize=(8,8))explode = [0, 0, 0.15, 0, 0]ax.pie(shares, labels=names, explode=explode, autopct='%.2f%%', shadow=True, labeldistance=1.1)
ax.set_title('Distribution of shares', fontsize=18, y=0.95);*

份额持有人分布饼图,突出显示最高分布。

给那些想成为数据科学家的人的一封信

原文:https://towardsdatascience.com/a-letter-to-those-seeking-to-become-a-data-scientist-f217253cd2dd?source=collection_archive---------11-----------------------

地面零点

我试图通过自己的故事来阐明这个行业。

王思然·哈德森Unsplash 上拍摄的照片

我写这封信是为了尽可能地揭示数据科学行业。这可能会帮助你们中的一些人找到一些问题的答案,比如“如果我没有数学背景,我可以转行到这个行业吗?”,“我需要创新来解决一个行业问题吗?”,或者“我当前的技能组合能为数据科学项目增加价值吗?”。我分享我的故事是为了让你知道我来自哪里以及这个行业的现状,以了解你应该如何决定。请注意,我试图对现状保持中立。

[## 人工智能:非正统的教训:如何获得洞察力和建立创新的解决方案…

人工智能:非正统的教训:如何获得洞察力和建立创新的解决方案(创业书…

www .亚马逊. ca](https://www.amazon.ca/gp/product/B08D2M2KV1/)

—远离数学中不必要的细节。

我的数据科学之旅始于 2005 年,当时我熟悉了一个名为流形学习的美丽概念。我热爱数学,所以我爱上了多元学习。你必须擅长线性代数、解析几何和概率论,才能理解和运用多种学习技巧。我使用这些技术开发了一个面部识别引擎,至少在学生项目中是有效的。使用多种学习技术,我能够解释很难分析的高维数据。这给了我力量。

今天,这个行业不要求你知道算法背后的数学。为什么?因为大多数解决方案都是通过以数据为中心,而不是以模型为中心的方法构建的。所以,如果你对数学没有深入的了解也没关系。你只需要学会如何使用库。

—在这个行业,你不需要创新。

2013 年,我开始用一个名为 NLTK 的强大库学习自然语言处理或 NLP。那一年,我有机会成为一家创新公司的一员,致力于开发手势控制臂章。该公司旨在制造一种可以戴在前臂上的臂带,并根据前臂水平记录的肌肉信号识别你的手势。我负责开发一个识别引擎,可以在 ARM 微控制器上运行,可以处理大量用户。我发明了我们所说的肌肉语言,并使用 NLP 技术设计了一个手势识别引擎。该算法必须在低计算能力的处理器上运行,并且对于我们的用户来说仍然工作良好。这是一个非常成功的项目。

你不再需要创新。创新发生在大公司的研究实验室,或者很少的创业公司。它们引入了强大的库,您只需要学习如何使用和调优这些库。所以,你不需要成为一个创新的问题解决者。尤其是当您对计算能力或数据存储没有任何限制时。

—利用您的领域知识。

2015 年,我和我的朋友参加了一个项目,建立一个用于汽车行业的计算机视觉或 CV 解决方案。我的朋友是一名机械工程师,而我显然是一名机器学习工程师。我们被要求开发一种粒子检测解决方案。我们必须设计和建立我们的数据收集设置,这需要其他知识,如流体动力学。我们发现,如果我们不关心细节,由于流体动力学定律,粒子很容易被捕获在成像室中。以前,我知道数据质量对于任何数据科学项目的重要性。但是,在这个项目中我从心底里注意到了。

例如,如果你是一名化学工程师或环境工程师,并希望成为一名数据科学家,你肯定可以从你的工具集为数据科学项目带来很多价值。例如,如果你处理 LinkedIn 个人资料数据,你的背景并没有太大的区别。但是,另外,你的领域知识很重要。

—了解最常用的工具。

2018 年,我加入了一家旨在构建基于 NLP 的解决方案来理解和解释监管文件的公司。我们开发了可以读取文档和结构化数据的解析引擎,以及解释数据的 NLP 模型。这次我用了 spaCy。NLTK 库输给了 spaCy,尤其是行业解决方案。spaCy 库是由小型创业公司开发的为数不多的广泛使用的库之一。

你必须学习当前广泛使用的工具。您应该选择一组工具,如 spaCy、scikit-learn 和 TensorFlow。然后,忘记其他工具,甚至那些以前广泛使用的工具。所以,如果你是这个领域的新手,你不知道 NLTK 是完全可以的,但是你应该学习 spaCy,而且你应该学得很快!

—坚定地选择您在数据科学领域的关注点。

在过去的几年里,我为时间序列、图像和文本数据设计了机器学习模型。然而,我并不认为自己是计算机视觉专家。我有更多处理文本和时间序列数据的经验。技术进步很快,你不可能成为所有这些领域的专家。它们都是人工智能或人工智能的一部分,但使用不同的工具和方法,需要花很多时间来学习。

如果你有兴趣在计算机视觉和自然语言处理方面做不同的令人兴奋的项目,这是可以的。然而,你应该尽早选择你关注的领域。这是你成为这个领域主人的唯一途径。最终,生活是一场精力和时间有限的游戏。

临终遗言

年复一年,与顶级的广泛使用的库和工具相比,数据科学家的重要性越来越小。不过这不一定是坏事。这意味着你可能不需要多年使用不同库和框架的经验。你只需要学习那些最近引进的。

数据科学家的角色在很多情况下可以外包,尤其是在后新冠肺炎时代。这在处理非机密数据的公司中更容易发生。如果你生活在北美,这可能会在某种程度上打击你。

如果你想在公司里提高自己的技能,或者想自己创业,强烈建议你学习数据科学。然而,我不能建议你辞掉工作去成为一名数据科学的摇滚明星。现在已经不是做那件事的时候了。

感谢阅读!

如果你喜欢这个帖子,想支持我…

[## 通过我的推荐链接加入 Medium—Pedram Ataee 博士

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

pedram-ataee.medium.com](https://pedram-ataee.medium.com/membership)

用于照明的光通道

原文:https://towardsdatascience.com/a-light-passage-for-lightgbm-76543bb09a07?source=collection_archive---------38-----------------------

作为一个决定将数据科学作为职业的非 IT 背景的人,我意识到有太多的知识需要扩展和技能需要利用,包括写作技能——以简单易懂的方式解释概念,而不管受众背景如何。因此,我决定开始在媒介上写作。

首先,本文将解释 LightGBM。LightGBM 代表光梯度提升机,我们试着用 5W+1H 来分解概念。

什么是光梯度助推机?

LightGBM 是一个梯度推进框架,使用基于树的学习算法。在我看来,基于树的算法是最直观的算法,因为它模仿人类如何做决定。

现在是上午 11 点,你不知道是现在吃还是等会儿吃,所以你做了一个决策树。一个决策树由作为根本原因的根节点、作为判定节点的分支节点和作为判定结果的叶节点组成。图片由作者提供。

在回答问题之前,首先我们需要知道什么是 boosting,以及梯度 boosting 框架。

Boosting 是一种用于创建预测器集合的集成技术,或者是将弱学习器组合成强学习器以预测输出的方法。这里的弱学习者是决策树的每一个。它之所以弱,是因为它在预测或分类方面表现不佳。为了获得更好的预测,我们组合弱学习者,其中每个学习者将产生一个假设,并将它组合在一起将在预测输出时创建一个最终假设。Boosting 的工作方式是让树按顺序生长:每棵树都是使用以前生长的树的信息生长的。

既然我们想在我们的模型中添加许多弱学习者,我们可能会问,我们如何知道我们的模型是否被优化了?这里,我们使用梯度推进,我们应用梯度下降程序来寻找损失函数最小化的最佳模型。

这意味着要理解梯度推进,我们必须理解梯度下降,损失函数和优化函数。

一个简单的 gif 来说明梯度下降,其中我们想找到一个损失函数为 RMSE 的线性回归的概念。绿线下降的梯度,直到找到梯度接近 0 的最小 RMSE 量。gif 是作者做的。

优化函数是我们应用来达到我们想要的目标的函数,在这种情况下是最小化损失函数。损失函数将测量模型与实际数据的差距。如果模型或预测的结果相差甚远,损失函数将产生一个很大的数字。优化函数将逐渐减小损失函数/误差,直到它收敛到最小值。我们经常遇到的损失函数有回归问题的均方根误差(RMSE)和平均绝对误差(MAE ),分类问题的二元损失函数和交叉熵损失。梯度下降意味着梯度将随着损失函数变得最小而逐渐下降,直到梯度达到极限值 0。

回到 LightGBM,使用基于树的学习算法,弱学习器将依次增长,这意味着我们构建的第一个树将学习如何适应目标变量,然后第二个树将从第一个树学习并学习如何适应残差,下一个树将学习减少残差并适应来自前一个树的残差,这将继续,直到残差不变。误差的梯度在整个系统中传播,这被称为逐级树生长。

摘自 LightGBM 文档,描述了逐叶生长的树。

LightGBM 与另一种梯度提升算法的不同之处在于,在 XGBoost 中,树的增长是逐级的,而 CatBoost 更适合分类变量。

谁构建了 LightGBM?

2017 年,微软将 LightGBM 作为 XGBoost 的替代产品。lightGBM 可以在 Python、R 和 C++中使用。

为什么我们需要使用 LightGBM?

正如文档中所述,LightGBM 是梯度推进算法在效率、速度以及支持分布式并行处理和 GPU 方面的改进。

如果你想建立一个有大量数据的模型,LightGBM 是适合使用的。如果你只有 100 个数据,最好使用其他机器学习算法,因为你的模型可能会导致过度拟合。

如何使用 LightGBM?

简而言之,我在使用 lightGBM 时采用了三个步骤:

  1. 准备训练和测试数据(数据预处理、探索性数据分析和分类变量的数据编码)
  2. 选择优化函数以获得调谐参数。你可以选择网格搜索、随机搜索、贝叶斯优化等等。几个重要的调整参数是:
  • learning_rate:在梯度下降中向损失函数的最小值移动时,每次迭代的步长
  • max_depth:树的最大深度,通过降低树的深度来处理过度拟合
  • min_data_in_lead:一个叶子可以拥有的最小记录数
  • feature_fraction:在构建树的每次迭代中随机选择的特征/参数的分数
  • bagging_fraction:指定在创建新数据集的每次迭代中使用的数据的分数
  • λ:用于调节以解决过度拟合和特征选择的参数,l1 范数用于套索回归,l2 范数用于岭回归
  • min_split_gain:在树中进行拆分的最小增益

3.训练模型、拟合模型和评估模型

如果您有兴趣了解变量和目标变量之间的关系,您可以使用 feature_importance。特征重要性将显示哪些变量在预测/分类中起主要作用。

LightGBM 是一种流行的 boosting 算法,广泛用于数据科学。它可以处理分类数据,速度快,并按叶子顺序增长树。

为了关闭这个,

在哪里可以找到完整的文档、学习地点和项目示例?

完整文档: LightGBM

我遇到的很棒的教程和读物:

统计学习入门一本学习的好书,而且是免费的!

一本解释 XGBoost、LightGBM 和 CatBoost 性能的好书

kaggle 中应用 LightGBM 的例子

更多关于梯度增强算法

对于视听学习者来说,这是一个伟大的 youtube 频道,作者是 Alexander Ihler 教授

和 LightGBM 一样,我的写作是按顺序增长的。

如果你发现这篇文章有什么可以改进的地方,请随时给我留言。干杯!

一点点工作可以帮助向非信徒推销数据科学项目

原文:https://towardsdatascience.com/a-little-pre-work-can-help-sell-data-science-projects-1cd32c94fe19?source=collection_archive---------48-----------------------

如果你的公司不相信数据科学的好处,那么一点点准备工作可以极大地增加你让他们抓住第一次机会的机会。

你是否曾试图说服你的老板或同事,某个数据科学项目会给公司或企业带来好处,但却遭到拒绝或打折扣,尽管你可以看到这样做非常好?

你经常会被拒绝,最常见的原因有:

  • 看不到好处
  • 目前的方式更好,我们为什么要冒险改变呢?
  • 被认为过于昂贵或复杂,不值得冒险

这个清单还可以继续下去,但最根本的结果是关键利益相关者没有参与进来,你永远得不到他们的认可。

卡蜜拉·金特罗·佛朗哥在 Unsplash 上拍摄的照片

那么,你能做什么?

类似于我之前写的一篇文章,通过只关注将推动项目的核心技术来启动你的项目(而不是一个完成的项目需要的所有花里胡哨的东西),你可以通过保持简单的提问来增加你的机会。如果你向从未见过精心规划、执行和设计的数据科学项目所能带来的好处的人要求大量资源或大量资金,他们永远不会同意。

这里的关键是坚持:

保持简单

一个很好的方法是,不要坚持使用概念验证 (POC)策略来交付完整的产品。在这里,您尝试交付足以证明整个项目是否可行的内容。

它还有一个很大的好处,就是让您对整个项目有一个更好的想法:

  • 需要什么技能
  • 需要付出的全部努力
  • 可能的好处(即,与现有解决方案相比,解决方案的准确性和能力)
  • 觉得这会让人们丢掉工作(甚至是自己的工作)

为了有所帮助,我将给出一个我们可以浏览的基本示例。

追踪那些坑洞

坑坑洼洼的道路示例(来源: Kaggle

你在一家为地方当局管理道路的公司工作。作为公司的新员工,你注意到他们在老化道路维护方面的主要问题之一是处理每年需要修复的坑洞数量。

坑洞需要水的进入和交通才能形成。发生的情况是,水进入顶部表面的裂缝,它冻结并膨胀,推动路面上升,增加裂缝。当它融化和收缩时,地表下留下一个洞,交通的重量将这个洞打破。这些物质随后会流失,随着时间的推移,洞会变大。

这个过程的一个很好的图解如下所示:

坑洞形成机制的例子(来源:维基百科

因此,随着道路老化和裂缝开始形成,坑洞会随着时间的推移而增加。如果任其发展(某些区域大约 40 毫米深被认为需要紧急维修),它可能会变得足够大,可能会损坏车辆,并可以向议会提出索赔(他们向公司索赔)。

该公司试图修复路面坑洼,计划维修比紧急维修便宜 17%。他们的问题是跟踪路面坑洼和监控道路状况。

目前,该公司有团队在它管理的道路网络周围行驶,检查并标记需要维护的道路区域。然而,他们往往在高交通量道路上花费大量时间,而公司只有几个训练有素的人员团队可以做到这一点。

这意味着许多支路没有得到积极的监控,而是依靠公众的报告来引起注意,而这通常是在它们已经非常大并且需要立即修复的时候。

数据科学在哪里?

作为公司的数据科学家,我们认识到机会是存在的。如果我们可以获得道路网络的镜头,我们可以应用基于视觉的机器学习解决方案来识别漏洞。如果我们把它和一个全球定位系统结合起来,我们就可以制作一张地图,标出他们的位置。

想想吧!我们可以让某人一周或一个月驾驶一次,带着安装在仪表板上的摄像机和一些电子设备,我们可以生成道路质量的动态图像。我们甚至可以添加一些其他问题(如道路上的异物或损坏的井盖)。想想这将如何彻底改变商业运作方式!我们将从高度被动转向积极主动。

不幸的是,没有人买账

照片由蒂姆·莫斯霍尔德Unsplash 上拍摄

这通常是当你发现这些项目没有进展的时候。虽然你的老板或直线经理可能认为这不是一个坏主意(否则他们当然不会雇用你),但他们可能没有预算或不同意你的要求,也没有能力让不同的利益相关者参与进来,因为这是跨部门的。

这些是你需要说服的人,他们并不热心。这可能是因为他们从未见过一个成功的数据科学项目能做些什么,但如果你想一想你要求的是什么:

  • 获得自己工作所需的公路车辆(可能需要一段时间来获得足够的示例镜头进行培训)
  • 允许添加电子设备和设备
  • 让人们(做他们主要工作的人)运行和使用设备
  • 获得他们可以使用的定制电子设备和套件(GPS 和视频记录)
  • 用于映射和处理功能的计算资源和软件设计,以生成结果仪表板(因此 IT 可能对此也不满意)
  • 不仅仅是你的时间,还有其他人的足够长的时间来完成这项工作。如果你仔细想想,这可能需要几个月的时间

将所有这些加在一起,您可以看到这不是一个小的资源请求,如果它不成功,可能会损失很多,他们必须对此负责。

我们能做什么?

这就是概念验证思想的来源。我们只需要证明关键的可交付成果是可能的。

这是一个需要考虑的关键问题,因为如果这是他们的第一个数据科学项目,并且出现严重问题,他们可能永远不会再购买另一个项目。进行低风险的 POC 可能会让您确保不会丧失再次尝试的能力。

关键交付成果是什么?

基拉·奥德·海德在 Unsplash 拍摄的照片

我们能否检测到足够可靠的路面坑洼,从而值得开发成一项业务能力?

我们也想把它变薄,所以我们需要足够的资源来做这件事。如果我们考虑需要展示什么样的关键交付成果,我们需要的是:

  • 我们可以使用的数据
  • 适合使用的模型
  • 运行和准备数据的计算资源和时间

这就是足智多谋的用处所在。你经常会发现有不同开源数据集的大型存储库,虽然可能不完美,但可以满足需求,经过一番搜寻后, Kaggle 上确实有一个坑坑洼洼的数据集。

在模型方面,这是成为数据科学家的一部分,我可能会考虑使用现有的图像识别模型并转移学习,这样我们就不需要大量的新图像来重新训练它,而且我们应该比我们从开始训练时获得更好的性能。

作为一名数据科学家,这一切都应该可以在您拥有的计算资源上实现(例如,一台强大的笔记本电脑或访问公司服务器上的计算资源)。

注意:如果你没有任何计算资源,现在是告诉你的工作人员你需要它来完成工作的好时机。

建立模型

我使用 TensorFlow 作为我选择的 ML 工具,使用 LabelImg 给原始图像加上坑洞标签。

我做了大约 150 张图片,然后分成 100 张用于训练,50 张用于测试。这个较小的精选集很有用,因为我可以选择看起来与我对 dash 相机拍摄的图像的预期相似的图像(即,他们像汽车行驶一样看着道路)。

在我们的数据集中标注坑洞

然后,我设置我的模型训练,并查看输出。我在下面举了一个例子,但是结果相当不错。我给自己设定的最后期限只有一天,所以我不得不提前停止模型训练,但看起来它达到了大约 70%的准确率,这对一个草稿模型来说已经很不错了!

初始概念验证模型识别从未见过的图像中的坑洞

结果呢

那么,我们该怎么办?我们所做的是获取一些非常粗略的数据,进行一些粗略的清理和快速训练,并取得了非常好的结果。我们知道,随着更多的数据符合我们的预期(许多图像并不完全符合 dash cam 镜头),我们只在一个小数据集上非常快速地训练了一个模式,获得了良好的结果。

我们可以自信地说,我们期望性能达到或超过这一水平,我们有图像和结果,我们可以编译到一个定义的路径中,并使用真实的图像来显示整个系统可能工作的可比结果。例如,我们现在可以向他们展示这样的设计:

虽然看起来不重要。能够展示实际结果并更好地处理事情会有所帮助,有了一些数字,我们就可以开始做一个商业案例。

在我们的例子中,我们发现:

  • 他们往往会忽略较小道路上的坑洼,因为优先考虑的是交通量较大的道路
  • 我们希望仅仅通过 dash 相机拍摄路面,就能识别出至少 70%的坑洞
  • 任何驾驶这条路线的人都可以拍摄这个镜头,并且不依赖于有限的经过坑洞训练的成员
  • 主动维修比被动维修便宜 17%

将这些结合在一起,我们可以说,我们预计可以节省 70%的坑洞中的 17%。

现在怎么办?以实数为基础

照片由费边布兰克Unsplash 上拍摄

从这里开始,我会鼓励获取一些公司数据,以便利益相关者可以看到潜力,并了解运行完整项目的成本是否值得。

例如,如果我们发现:

  • 49 美元来主动修复每个坑洞
  • 60 美元被动修复坑洞
  • 很少被调查的道路倾向于每月进行 100 次左右的坑洞修补
  • 每个月 5 个危险的大坑洞,并且每个危险的坑洞产生 300 美元的车辆索赔修理费用(与坑洞修理费用分开)
  • 我们假设所有这些坑洼都是在接到公众报告后进行的被动维修

我们现在可以说,目前的成本是:

  • 系统目前每年花费 72,000 英镑来修复 1200 个坑洞
  • 60 个危险的坑洞每年可索赔的修理费为 18,000 英镑

有了这个新系统,我们可以说我们至少希望:

  • 41,160 次(840 次主动维修)和 21,600 次
  • 5,400 英镑的可索赔修理费

每年的费用从 90,000 英镑降到 68,160 英镑。每年为公司节省 21,840 英镑。

然后,风险承担者可以评估这个估计的最小节省,以更好地平衡风险/回报,以及项目成本。你也可以通过说明它如何影响更广泛的网络来扩大节省。所有这些都是一天工作的结果!

有了这种概念验证,你可以从一个模糊的主张到一个更坚定的立场,并开始一项业务成本,以获得人们的支持。

摘要

照片由丹尼尔·库切列夫Unsplash 拍摄

我们从只有主观节约和成本的宏大项目愿景,到有 POC 的小资源成本(您的经理可能会给你), POC 的结果可以开始给出资源和节约的想法。在此基础上,您可以构建一个案例,增加您销售数据科学项目的机会。

这是我在工作中经常使用的策略。不要试图销售和启动大型项目,围绕关键交付成果的小范围项目通常可以降低风险,增加成功的机会。这也意味着你会做很多不同的事情,如果你喜欢多样性,这是件好事。

注意 : 在可能的情况下,我尽可能使用现实的数字。然而,在某些情况下,我使用了看起来合理的数字。这些当然只是为了说明的目的。

从零开始的逻辑回归

原文:https://towardsdatascience.com/a-logistic-regression-from-scratch-3824468b1f88?source=collection_archive---------18-----------------------

将张量流转换为普通数字

在我之前的博文中,我们研究了人工神经网络,开发了一个类来构建任意层数和神经元数的网络。虽然博客引用了前面的笔记本来解释先决条件,但是还没有附带的文章,也就是这篇博客文章。

这篇文章也可以在我的 Github 上作为 Jupyter 笔记本获得,所以你可以边阅读边编码。

如果你是 Python 和 Jupyter 的新手,这里有一个关于我如何管理我的 Python 环境和包的简短解释

我们将讨论的主题的简短概述:

  1. 神经网络和逻辑回归之间的联系
  2. 退一步:线性回归
  3. 从线性回归到(二元)逻辑回归
  4. 围捕

神经网络与逻辑回归之间的联系

当我们听到或读到深度学习时,我们通常指的是使用人工神经网络 (ANN)的机器学习子领域。这些计算系统在解决各种领域的复杂问题方面相当成功,例如图像识别、语言建模和语音识别。虽然 ANN 这个名字意味着它们与我们大脑的内部工作有关,但事实是它们主要共享一些术语。人工神经网络通常由多个相互连接的层组成,这些层本身是使用神经元(也称为节点)构建的。图 1 显示了一个例子。

图 1:一个典型的神经网络的例子,借用于我关于神经网络的后续文章。

在这个例子中,我们有一个输入层,由四个独立的输入节点组成。该输入层“完全连接”到第一个隐藏层,即完全连接意味着每个输入连接到每个节点。第一个隐藏层再次完全连接到另一个“隐藏”层。术语“隐藏”表示我们没有直接与这些层交互,这些层对用户来说有点模糊。第二个隐藏层依次完全连接两个最终输出层,它由两个节点组成。因此,在本例中,我们向模型提供四个输入,我们将接收两个输出。

现在让我们把注意力集中在前面例子中的单个神经元上。这个神经元仍然连接到所有的输入,也称为特征。使用这些特征,神经元计算单个响应(或输出)。这种系统的示意图如图 2 所示。

图 2:具有四个输入特征的单个神经元。神经元有两个操作:线性部分和激活函数。

输入特征被命名为 𝑓𝑓𝑓𝑓⁴ ,并且都连接到单个神经元。这个神经元执行两个操作。第一个操作是将特征与权重向量𝑊 相乘,并添加偏置项 𝑏 。第二个操作是所谓的激活功能,这里由 𝜎 表示。神经元的输出是介于零和一之间的概率。单个神经元的行为就像一个小的逻辑回归模型,因此,人工神经网络可以被视为一堆相互连接的逻辑回归模型堆叠在一起。虽然这个想法很简洁,但潜在的事实却有点微妙。人工神经网络有许多不同的体系结构,它们可以使用各种不同的构建模块,其行为与本例中的完全不同。

我们单个神经元中的线性运算只不过是线性回归。因此,要理解逻辑回归,第一步是了解线性回归是如何工作的。下一节将展示一个逐步的例子作为回顾。

退一步:线性回归

什么是线性回归来着?

最简单形式的线性回归(也称为简单线性回归),使用单个自变量 𝑥 对单个因变量 𝑦 建模。这听起来可能令人望而生畏,但这意味着我们要解下面的方程:

*𝑦* = *a𝑥* + *𝑏*

机器学习的背景下, 𝑥 代表我们的输入数据, 𝑦 代表我们的输出数据,通过求解我们的意思是找到最佳权重(或参数),在线性回归方程中用 𝑤𝑏 来表示。计算机可以帮助我们找到𝑤和𝑏的最佳值,使用输入变量 𝑥 得到𝑦 的最接近匹配

对于接下来的例子,让我们为 xy 定义以下值:

*𝑥* = [−2,−1,0,1,2,3,4,5]
*𝑦* = [−3,−1,1,3,5,7,9,11]

𝑥𝑦 的值具有线性关系,因此我们可以使用线性回归找到(或拟合)最佳权重并解决问题。也许,通过长时间盯着这些值,我们可以发现它们之间的关系,然而,使用计算机来找到答案要容易得多。

如果你已经盯得够久了,或者只是想知道答案,那么 𝑥𝑦 的关系如下:

*𝑦* = 2*𝑥* + 1

在下一节中,我们将使用 Tensorflow 来创建我们的单神经元模型,并尝试“求解”该方程。

Tensorflow 中的实现

在我们开始使用 Tensorflow 之前,我们应该首先组织我们的输入数据( 𝑥 )和输出数据( 𝑦 )。为此,我们将使用 Numpy:

下一步,我们将导入 Tensorflow。检查我们正在使用的版本始终是一个好的做法:

现在我们可以使用 Keras 创建一个模型,它现在是 Tensorflow 的一部分。为了做到这一点,我们将使用 Sequential 类,它可以将不同的层一个接一个地“顺序”堆叠起来。我们使用 Keras 中的密集类来创建一个“完全连接”层,它由单个神经元(单元)组成。

Dense 函数用于创建许多完全连接的神经元(逻辑单元)的层。参数 units 用于设置神经元的数量。我们只使用一个单位,因此,我们将它设置为 1。由于这是我们的模型的第一个“层”,我们需要告诉 Tensorflow 它可以预期什么形状作为输入。这只对第一层是必要的。

既然我们已经定义了模型,我们需要使用 Compile()方法来配置模型以进行训练。该方法需要至少两个参数,损失函数和优化器。损失函数是模型预测实际值的程度的度量。对于这个例子,我们将使用均方误差(𝑦 的预测值和实际值之间的平方差的平均值)。“学习算法将通过调整(优化)每一步的参数(权重和偏差)来尽量减少损失。优化器定义了一个方法来执行这个优化步骤,一个常用的方法是梯度下降,或者在我们的例子中是随机梯度下降(SGD)。在下一节中,我们将用简单的 Numpy 实现这个方法,这个方法将变得更加清晰。

接下来,我们使用 Fit()方法让算法学习最佳参数。虽然 Tensorflow 有许多聪明的方法来解决这个问题,但秘诀或多或少是这样的:

  1. 使用当前参数( 𝑊𝑏 )计算预测 ŷ
  2. 计算当前值的损失
  3. 计算损失函数相对于参数的梯度
  4. 使用渐变调整权重(优化)。
  5. 重复上述操作,以确定出现的次数,即浏览所提供的示例(数据集)的次数。

如果这不是完全清楚的,不要太担心。我们将用简单的 Numpy 编码每一步,并对下一节中使用的所有数学进行彻底的推导。

我们已经使用我们的训练数据在 Tensorflow 中训练了该模型,并且我们准备尝试一下。现在,我们可以使用我们的模型来“预测”它从未见过的值。这有时也被称为推理。我们来试试 12 的值。我们知道应该是 25。

为什么值不正好是 25?

该模型计算实际值和预测值之间的差异,并慢慢向实际值靠拢。长时间运行 fit 方法会让你更接近 25。

这并不难,但可能感觉像某种黑暗绝地的力量。因此,在下一节中,我们将用普通 Python 实现这个算法(借助 Numpy)。

“引擎盖下”到底发生了什么

在上一节中,我们大致介绍了 Tensorflow 正在做的事情:

  1. 使用当前参数( 𝑊𝑏 )计算预测 ŷ
  2. 计算当前值的损失
  3. 计算损失函数相对于参数的梯度
  4. 使用渐变调整权重(优化)。
  5. 重复上述操作,以确定出现的次数,即浏览所提供的示例(数据集)的次数。

我们现在将在普通 Python 中实现这一点,并希望得到与 Tensorflow 类似的结果。

首先,我们定义模型参数。这些是权重 𝑊 ,这只是一个单一的值,因为我们只有一个单一的输入。我们还需要定义偏差项 𝑏

这是我们模型中所有可训练的参数,单个标量用于权重,单个标量用于偏差。

接下来,我们将定义一个使用当前模型参数进行预测的函数。在深度学习术语中,这被称为向前传递。预测值的变量一般命名为 ŷ (或者 A 但你可以在我的下一篇文章中了解到这一点)。

该函数名为 forward,使用输入向量 𝑋 并将其与权重参数 𝑊 相乘,并添加偏差项 𝑏 。正如我们在前面提到的等式中描述的那样。

我们现在可以用当前参数测试函数。同样,我们将输入一个值 12.0,但是当然,它将返回乱码,因为权重是随机初始化的。

-0.2122614846691141

事实上,-0.212261…并不是我们真正想要的,但我们仍然需要训练我们的模型,然后它才能做出正确的预测。在此之前,我们需要计算当前的损失。作为损失,我们使用预测值 ŷ 和实际值 𝑦 的均方误差。

希望数学不会吓到你,但是如果你花时间,它并不难。变量 𝑚 这里是例子的数量(数据集中的点)。我们的 𝑋 有八个值,因此, 𝑚 =8。当我们有一个 1/ 𝑚 后跟 as sum(≘)超过所有 𝑚 值时,它无非是这些值的平均值,即 𝑖𝑛𝑠𝑖𝑑𝑒 的总和。这里,我们取所有(𝑦ŷ)的平均值,这是真实值 𝑦 和预测值 ŷ 的平方之差。平方很重要,因为如果我们不把差平方,负差和正差就会互相抵消。既然我们完全理解了均方误差,我们可以用代码实现它:

要查看我们之前计算的值之间的损失,我们可以这样做:

*149.13933056993267*

正如我们所看到的,损失相当大,我们的重量相当大。因此,我们需要更新我们的可训练参数,以做出更好的预测。为此,我们需要首先计算梯度 𝛿 损失/ 𝛿𝑊𝛿 损失/ 𝛿𝑏 。也许你的鉴别能力有点生疏了。诀窍是应用链式法则。另一个好处是平均算子(和)是线性的,因此,我们可以在微分中忽略它,以后再放回去。

为了计算 𝛿 损失/ 𝛿𝑏 我们只需要重复最后一步,关于 𝑏 :

我们将在“反向传递”函数中实现这一点。由于变量名变得有点长,我们也有点懒,我们就称它们为 𝑑𝑊𝑑𝑏

现在,我们可以得到之前测试示例的梯度:

*(-605.0942756320587, -50.42452296933823)*

在构建训练循环之前,我们需要的最后一个函数是更新函数。该功能将一步“优化”我们的权重。这是实际的梯度下降,其中我们从当前权重中减去(下降)梯度。梯度下降定义如下:

这里我们有一个新的参数 𝛼 ,它被称为学习率。这个值将设置我们试图收敛到最小损失的速度。对于这个例子,我们将它设置为 0.01。学习率没有黄金值,这个值需要针对每个问题进行微调。我们的更新函数代码如下:

要更新我们当前的模型参数,我们只需:

*(array([6.0332543]), 0.5042452296933823)*

好的,我们第一次更新了我们的权重。为了提高重量,我们必须重复这个过程很多次。为此,我们将编写一个循环:

*129.7037237445872
0.06819476739792682
0.00458155318441586
0.0003078050915820409
2.067944441333496e-05*

我们很幸运,损失,即我们的模型预测和实际值之间的差异,正在减少。当我们输入值 12.0 时,我们现在如何预测?

*array([25.00101652])*

我希望 Tensorflow 中的这种黑魔法现在更加清晰了。在下一节中,我们将使用我们新学到的知识来解决一个二元逻辑回归问题。

从线性回归到(二元)逻辑回归

到底有什么区别?

线性回归和逻辑回归之间的差别不是很大。与我们之前创建的代码有两个不同之处。首先,我们的线性回归模型只有一个单一的特征,我们用 𝑥 输入,这意味着我们只有一个单一的权重。在逻辑回归中,通常输入多个特征,每个特征都有自己的权重。从技术上讲,你可以有一个单一的特性,但是它只不过是一个 if 语句(想想看)。增加功能的数量会将之前的简单乘法变为矩阵乘法(点积)。其次,我们将添加一个所谓的激活函数来映射 0 或 1 之间的值。让我们再次提醒自己我们的简单模型:

按照 Tensorflow 中的惯例(根据我的理解),输入向量有用于特征的列和用于示例的行。如果我们有 2 个数据点,输入矩阵将如下所示:

上标表示特征号,下标表示例子。

这些输入中的每一个都与它们自己的权重相关联。节点本身有两个不同的操作。第一个是权重向量和输入向量之间的点积。第二个是 Sigmoid 函数。这个例子中的权重向量 𝑊 具有四个权重:

在节点中,我们首先计算线性部分:

在我们的例子中,它看起来像这样:

请注意,每个示例的结果都只有一个值。

对于 𝑥 的所有值,可以从∞到+∞(全部为实数),Sigmoid 函数将 𝑥 映射到 0 和 1 之间。接近零的 𝑥 的值具有最大的影响,因为它们处于“线性状态”。非常大或非常小仅分别被限制为 1 和 0。Sigmoid 函数的数学定义是:

这就是后勤单位的全部情况。Sigmoid 函数赋予节点非线性特征。许多这样的单位一起可以做几乎神奇的事情。在下一节中,我们将首先在 Tensorflow 中制作一个逻辑回归模型。

Tensorflow 中的实现

在我们开始之前,我们首先需要一些数据来做逻辑回归。我从 Kaggle 的 Azeem Bootwala 下载了 titantic 数据集,以演示这个例子。可以从这里下载:
https://www.kaggle.com/azeembootwala/titanic

*(792, 17)*

首先,始终检查列和数据类型:

*<class 'pandas.core.frame.DataFrame'>
RangeIndex: 792 entries, 0 to 791
Data columns (total 17 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   Unnamed: 0   792 non-null    int64  
 1   PassengerId  792 non-null    int64  
 2   Survived     792 non-null    int64  
 3   Sex          792 non-null    int64  
 4   Age          792 non-null    float64
 5   Fare         792 non-null    float64
 6   Pclass_1     792 non-null    int64  
 7   Pclass_2     792 non-null    int64  
 8   Pclass_3     792 non-null    int64  
 9   Family_size  792 non-null    float64
 10  Title_1      792 non-null    int64  
 11  Title_2      792 non-null    int64  
 12  Title_3      792 non-null    int64  
 13  Title_4      792 non-null    int64  
 14  Emb_1        792 non-null    int64  
 15  Emb_2        792 non-null    int64  
 16  Emb_3        792 non-null    int64  
dtypes: float64(3), int64(14)
memory usage: 105.3 KB*

我认为 Azeem 没有使用 index=False 选项保存集合,因此我们有一个“未命名:0”列。这个对于我们当前的索引来说是多余的,所以我们可以删除它。此外,PassengerId 对于我们的模型来说不是很有用,让我们也删除该列。之后,让我们对数据集进行采样,以获得一个概念:

*Azeem 已经做了一些预处理。目标变量 𝑌 是‘幸存’,所有其他列都是特征。功能简介: - 性别:0 或 1 - >男或女
-年龄:值在 0 和 1 之间重新调整
-票价:票价在 0 和 1 之间重新调整

  • Pclass_1..Pclass_3:一键编码乘客类别
    -家庭规模:家庭规模的 0 到 1 之间的重新调整值。
    -标题 _1..title_4:先生、夫人、主人、小姐 one-hot encoded
  • emb_1..emb_3:登船位置一-热编码。*

总共我们将有 14 个功能。

对于这个例子来说,数据就足够了,我不会详细讨论这些数据是如何变成现在这个样子的。老实说,我不知道我自己,刚刚从 Kaggle 下载;-).

让我们把这些变量放入我们之前定义的格式中( 𝑋𝑌 )。这里 𝑌 对应一个人是否幸存的标签。我们总共有 792 个例子。因此, 𝑌 的形状为( 𝑚 ,1)其中 𝑚 = 792。对于 𝑋 我们期望( 𝑚,14 ),其中列是特性。

*((792, 14), (792,))*

现在我们已经准备好了数据,我们可以在 Tensorflow 中创建一个模型:

Tensorflow 中的模型与我们的线性回归模型非常相似。输入从 1 个特征变为 14 个特征,并且我们增加了 Sigmoid 激活功能。接下来,我们必须再次编译我们的模型:

在这个例子中,我将损失改为“二元交叉熵”。这是另一个对二元逻辑回归问题更有效的损失函数。如果你对内部工作感兴趣,我推荐维基百科。
我们增加了一个额外的指标,叫做“准确度”,现在是为每个历元计算的。现在我们准备训练我们的模型:

这些都是在 Tensorflow 中训练二元逻辑分类器所需的步骤。我们达到了大约 80%的准确率,对于我们付出的努力来说,这已经算不错了。

我们可以从我们的模型中提取权重 𝑊 和偏差 𝑏 。我们稍后可以将这些值与我们自己的逻辑回归实现进行比较:

策划损失也很容易:

不介意好看的 XKCD 抖动:-)。令人印象深刻的是,只需几个步骤就能达到这样的结果。在最后一部分,我们将揭开由 Tensorflow 表演的黑暗绝地艺术。

实际发生了什么?

嗯,总的配方没有变:

  1. 前进传球
  2. 计算损失
  3. 偶数道次
  4. 更新权重
  5. 重复

这些步骤本身需要稍加修改。正向传递将是更一般的点积,我们需要添加激活函数。损失函数是二元交叉熵,当然和均方差不同。反向传递将计算新损失函数相对于 𝑊𝑏 的梯度。由于我们现在也有一个激活功能,我们将有一个额外的步骤。update-weights 函数不变,最终的循环也非常相似。

据我所知,在 Numpy 和一般数学中,点积需要向量(和矩阵)的形状兼容:

这意味着 𝑋 的列数必须等于 𝑌 的行数。为了让我们自己简单一点,我们将转置我们的输入向量 𝑋 并翻转向量。这将导致行成为特征,列成为示例。

*(14, 792)*

为了便于测试,我们只选择两个例子,让它更具可读性:

*(14, 2)*

让我们定义我们的重量。因为我们有 14 个特征,我们的向量 𝑊 将有 14 个值。偏差对于整个节点是常数,并且只有一个值。

*(14, 1)*

接下来,我们需要定义 Sigmoid 函数:

*array([3.72007598e-44, 5.00000000e-01, 5.24979187e-01, 1.00000000e+00])*

现在让我们重新定义我们的转发函数,让它使用点积和激活函数。我们可以把这些分成两步:
𝑍=
𝑊𝑋+𝑏
a =𝜎(𝑍)

注意 𝑊𝑋 是一个点积。

*array([[0.48951622, 0.50149394]])*

现在我们有了实际的预测,我们可以写出损失函数来衡量我们的预测有多好。这是通过二元交叉熵完成的,对此我将简单地给出等式:

可能会发生这样的情况,我们试图计算一个 log(0 ),当然这是没有定义的。为了避免警告,我们将在损失中增加一个微小的值。由于它非常小,差异并不明显,但确实有助于抑制警告。一天少一个警告,保持…

*1.3625601508159457*

接下来是向后传球。为此,我们需要用 𝑊𝑏 区分损失函数。为了不让你们觉得无聊,我已经提供了这些函数,但是我不会阻止你们自己计算微分:

在 Python 中,这看起来像这样:

*(array([[ 0.06118953],
        [-0.01277168],
        [-0.0078041 ],
        [-0.06231326],
        [ 0\.        ],
        [ 0.06118953],
        [-0.00011237],
        [-0.00112373],
        [ 0\.        ],
        [ 0\.        ],
        [ 0\.        ],
        [-0.06231326],
        [ 0\.        ],
        [ 0.06118953]]),
 -0.0011237299781017493)*

差不多了,接下来我们需要更新权重。该函数与我们之前的示例没有变化:

*(array([[-0.01830035],
        [ 0.00088324],
        [-0.01122826],
        [-0.00589117],
        [-0.00893116],
        [-0.01335291],
        [-0.00061042],
        [ 0.00065638],
        [ 0.00410113],
        [-0.00572882],
        [-0.00801334],
        [ 0.01374348],
        [ 0.01274699],
        [-0.01275547]]),
 1.1237299781017494e-05)*

为了比较结果,我们可以计算准确度。然而,我们的激活函数返回一个介于 0 和 1 之间的概率。根据定义,值<= 0.5 are rounded to 0 and values > 0.5 被四舍五入为 1。这与常规的 round 函数略有不同,因此我们将为此创建自己的函数:

*array([[0, 1]], dtype=uint8)*

现在我们有了创建训练循环的一切。我们将存储一些指标,以便以后绘制:

*loss: 17.16646271874957 	accuracy: 64.4%
loss: 12.757526841623513 	accuracy: 75.9%
loss: 11.688361064742441 	accuracy: 79.5%
loss: 11.150776615503466 	accuracy: 79.5%
loss: 10.83231532525657 	accuracy: 79.8%
loss: 10.622380143288218 	accuracy: 79.8%
loss: 10.473049466548982 	accuracy: 79.8%
loss: 10.36043263717339 	accuracy: 80.8%*

我们对网络进行了训练,得到了略高于 80%的最终准确率,与使用 Tensorflow 时的结果非常相似。当然,多一点努力,也多一点乐趣。让我们绘制我们的指标:

当然,我们已经计算了训练数据的指标。为了对模型有一个正确的认识,这应该使用测试数据来完成。这一点,我留给读者;-).

围捕

好了,这就是关于逻辑回归的教程。希望你对逻辑回归工作原理有所了解,张量流不仅仅是魔法。我发现从头开始写这些是一个很好的练习,正如你所看到的,也不是很难。

如果您有任何意见或建议,请告诉我。

《与命运的幽会》的情感分析

原文:https://towardsdatascience.com/a-long-tryst-with-destiny-a35424f44841?source=collection_archive---------21-----------------------

用 NLTK 对贾瓦哈拉尔·尼赫鲁著名演讲的情感分析

潘迪特·尼赫鲁在蒙巴顿勋爵的主持下宣誓就任印度独立后的第一任总理(个人电脑:photodivision.gov.in/公共领域)

1947 年 8 月 14 日印度独立前夕,印度首任总理潘迪特·贾瓦哈拉尔·尼赫鲁发表了一篇现在被认为是 20 世纪所有政治家中最优秀的演讲之一。

1947 年 8 月 14 日,接近午夜,潘迪特·尼赫鲁站在自由独立的印度制宪会议前,说了这些鼓舞人心的话-

“很久以前,我们与命运订了一个幽会;现在是我们兑现承诺的时候了,不是全部或全部,而是相当大的一部分。当午夜钟声敲响的时候,当世界沉睡的时候,印度将会为生命和自由而觉醒……

这篇演讲证明了一个时代,公开演说是许多政治家和自由战士致命优雅地挥舞的武器。不仅是潘迪特·尼赫鲁的演讲技巧让这篇演讲与众不同,还有他在没有诉诸沙文主义的情况下,向印度民众传达爱国热情和激情斗争的细致入微和雄辩。一个长期受压迫的民族的希望和愿望通过坚定的乐观主义和谨慎的实用主义表达出来。

在这篇文章中,我试图从分析的角度来看他的演讲。由于他的演讲鼓舞人心,我想知道情绪分析是否会揭示同样的情绪。

前言

简单地说,情绪分析是一种知道一个观点或陈述是积极的还是消极的能力。比如说—

句子 1——“我不太喜欢那种柠檬姜冰茶”

句子 2——“我喜欢柠檬姜冰茶”

句子 3——“让我想想,我是不是想要一杯柠檬姜汁冰茶”

第一句表达的是消极的感觉,而第二句表达的是积极的感觉,第三句是中性的。我们的大脑天生就有能力辨别积极的陈述和消极的陈述,而我们甚至不知道这是什么时候发生的。

现在想象一个计算机算法有能力做到这一点。想象一下,如果它有能力理解隐藏在句子中的情绪,并正确地说出它是什么——“积极”、“消极”或“中性”。这种情感识别和分类就是情感分析的全部内容。

它是自然语言处理(NLP)中的一套工具和方法,帮助我们筛选大量的客户反馈数据、产品评论数据、twitter feed 等。,并正确识别积极情绪和消极情绪。

虽然情感分析在客户反馈/评论和 twitter 分析中得到广泛使用和优化,但我想在潘迪特·尼赫鲁的演讲中尝试一下。我在这个项目中使用了流行的自然语言处理库 NLTK ,你可以在我的 github 页面上找到完整的代码来玩。该代码非常简单明了,我将在本文中只分享一些有趣的结果。演讲全文可以免费获取这里,这里这里,这里这里

一.探索性数据分析

潘迪特·尼赫鲁的演讲持续了近 8 分钟,以他那个时代的演讲风格发表。他的演讲是英文的,总共有 1099 个单词。

潘迪特·尼赫鲁演讲的文字云(来源:我的朱庇特笔记本

考虑到演讲的时间和背景,人们很自然地会经常提到“印度”、“自由”和“人民”等词。事实上,在他演讲中出现的前 20 个词中,印度美国自由被提到了超过 10 次。我们必须记住,潘迪特·尼赫鲁的演讲不仅仅是为了他的同胞,更是为了向世界其他国家发表声明。历经千辛万苦获得独立后,他现在的任务是领导一个脆弱的国家进入下一个十年。他经常使用“我们”和“人民”这样的词,这是他想向因第二次世界大战而分裂的国际社会展示的民族团结和统一的表现。

尼赫鲁演讲中最常用的 20 个词。

一篇演讲之所以伟大,是因为它的内容和讲述内容的方式。我早些时候说过,尼赫鲁的雄辩是他的品质之一,这也是他的演讲获得尊崇地位的部分原因。另一部分是书面内容。快速浏览一下他演讲中的词汇类别可以发现,最常被提及的词汇类别及其对应的热门词汇是-

  1. 名词:'印度'——既然演讲是关于印度的自由;
  2. 形容词:''和' ' —在争取独立的斗争和困难的背景下;
  3. 副词:' never ' —在英国殖民地对其占领者的顽强态度和历史性胜利的背景下;
  4. 动词:'来了'
  5. 人称代词:' us ' —突出人民的团结统一;
  6. 情态动词:' may '和'shall'——象征谨慎的希望。

潘迪特·尼赫鲁演讲中出现的每个词汇类别的前 5 个单词

二。情感分析

探索性数据分析产生了一些有趣的结果,并给出了从情感分析中期望得到什么的想法。

在这里,我使用了 NLTK 包中的 VADER 模型(情感推理的效价感知字典)来测量“极性得分”方面的情感。这是代表特定文本的情感的指数或分数。文本可以有一个中性 分数或所有三个分数的归一化分数,称为复合分数。

我使用 NLTK 库的 sent_tokenize 函数将整篇演讲分成多个句子,并使用 VADER 的SentimentIntensityAnalyzer测量每个句子的极性得分。

这样做的原因是这样的,

当你听一个演讲者时,你会在他或她的演讲中感受到不同的情绪,特别是如果是由像潘迪特·尼赫鲁这样的人在那个特定的历史时期发表的演讲。这些情绪和感悟可以量化吗?

因此,作为量化这些情绪的基本练习,我绘制了整个演讲的极性得分(请记住,这些是单个句子的极性得分)。

个人情感分数确实给出了某个句子是否引发了特定情感的想法。这里的情绪代表了整个句子。你可以立即看到,在整个演讲过程中,情绪并不是一致积极的。相反,它接近于中性和负面情绪的爆发。看一看复合分数,它是单个分数的集合,会给出更好的见解。

从复合得分图中,你可以感觉到潘迪特·尼赫鲁演讲的很大一部分是积极的(52%),中度消极的(28%)和中性的(20%)。

这正是我所期待的!

我不希望在独立前夕发表的演讲过于积极,这个演讲是通过多年的斗争获得的,由一位优雅的政治家发表,而不是尖酸刻薄或狂热的沙文主义。负面情绪的暗示可以被认为是代表了讲话中提到为获得独立所面临的斗争以及未来的斗争的部分。中性情绪可能代表他演讲中的实用或非感性部分。

对潘迪特·尼赫鲁演讲的总体评价是积极的(标准化综合得分为 0.21)。

结束语

通过这个小练习,我能够证实一个广为流传的观点,即潘迪特·尼赫鲁的演讲确实鼓舞人心,并向整个国家传达了积极的情感。

一些需要记住的事情—

1.我想向读者指出,情感分析,尤其是 VADER 在 NLTK 中进行的情感分析,是为分析社交媒体上的用户情感而优化的,社交媒体通常包括许多最高级,表情符号和标点符号。尽管如此,我还是想尝试一种不同的文本结构。

2.VADER 模型基本上是一种基于词汇和规则的情感分析方法。因此,无论这种情绪被识别出来,并不完全意味着机器智能。要做到这一点,应该有一个机器学习和预测/分类的元素。那是我想要尝试的事情。

3.最重要的一点——这个项目的目的是用 NLTK 学习情感分析,我期待着建议、评论和批评。

目前就这样。当我游向更深处时,我会发表更多我对情绪分析的理解!
Ciao!

费城一瞥

原文:https://towardsdatascience.com/a-look-a-philadelphia-e710eff69a3f?source=collection_archive---------37-----------------------

贫困、教育和劳动力如何帮助理解一个大城市的健康。

费城是一个多元化的城市,拥有 159 万居民,占地 142.7 平方英里。在这 159 万居民中,约有 50 万人生活贫困。今天,我们将利用 R 和地图来研究费城的贫困动态。根据 2010 年人口普查,贫困将在邮政编码层面进行调查。在这里,几个问题将被调查,包括整个费城的贫困、教育和劳动力,以获得城市健康的快照。总之,调查将利用以邮政编码为中心的彩色编码地图。

在这里,贫困的原始统计,人均贫困统计,贫困的差异统计,以及黑人和西班牙裔社区之间的差异比较都被关注。

贫困的基本统计

快速浏览一下贫困人口的总数,我们就会发现:

图 1:每个邮政编码的原始贫困人口数。注:Zips 19113 和 19112 是工业区,不包含任何居民区,因此不包括在分析中。

很明显,最大的贫困人口集中在“北费城”(邮编:19140、19133、19134、19120、19111、19149、19124)和“西南部”(邮编:19139、19143、19131)。其他地区属于中等贫困水平,靠近“中心城市”的贫困人口较少(zips: 19102、19103、19109、19107、19123、19130)。

尽管统计数据很有帮助,但如果没有人口统计或每个邮政编码内的总人口的背景数据,这些数据就不太具有洞察力。首先,将绘制人口层面的贫困数据,以探索任何人口层面的贫困模式。

白人的贫困

以下是白人每个邮政编码的原始贫困人口统计图:

图 2:费城每个邮政编码的贫困白人的原始数量。注意:邮政编码 19113 和 19112 的数据点太少,无法进行有意义的解释。

显而易见,随着人们在费城向东北方向迁移,白人的原始贫困率会增加。同样,在“南费城”,一个传统的意大利遗产区(zips: 19148,19147,19145),白人贫困人数也有所增加。除 19128 年外,西部、西南部和西北部的贫困水平较低。

黑人的贫困

以下是黑人每个邮政编码的原始贫困人口统计图:

图 3:整个费城根据 Zp 编码的贫困黑人原始人数。注意:邮政编码 19113 和 19112 的数据点太少,无法进行有意义的解释。

与白人相比,这里有一个几乎相反的趋势。对于贫困的黑人来说,统计集中在“西费城”地区(邮编:19143、19139、19131),以及极北地区(邮编:1938、19144、19141、19120、19140)。在费城南部、老城区或东北部,很少有黑人处于贫困之中。

西班牙人的贫困

以下是西班牙裔人每个邮政编码的原始贫困人口数地图:

图 4:费城拉美裔贫困人口的原始统计。注意:邮政编码 19113 和 19112 的数据点太少,无法进行有意义的解释

拉美裔贫困人口的原始数据表明,贫困人口集中在北费城地区,这是该市传统的拉美裔聚居区。在整个费城,除了这个地区以外,很少有拉美裔人处于贫困之中。

结论

人口的原始计数是有趣的,因为人们可以看到聚类。然而,如果不控制人口数量或代表性,它们就没有那么有意义。下文考虑了这些因素。

按邮政编码统计的人均贫困人口

更直观地观察整个城市的贫困状况,可以看到每个邮政编码与所有其他邮政编码相比的人均贫困率。下图显示了贫困水平。

图 5:每个邮政编码的相对原始贫困数与整个费城的原始贫困数的对比。注:邮政编码 19113、19112 没有足够的数据用于分析。

在这里,可以看出一个普遍的主题是存在的。在费城市中心,贫困水平相对较低,随着人们离开中心而增加。查看原始数据,我们看到在邮政编码 19107(老城区)的范围是 0.8%,在邮政编码 19133(北费城)的范围是 2.8%。另一个低于平均水平的贫困水平是邮政编码为 19134(浅蓝色),被称为大学城,那里有德雷克塞尔大学、宾夕法尼亚大学和科学大学。费城另一所著名的大学,天普大学,排名 19122,贫困率约为 1.7%。

按人口统计的人均贫困人口

现在,我们的注意力转向了人口统计中的人均贫困率。为了更好地理解人均贫困率,让我们先来看看每个 zip,看看哪个人口统计组最有代表性。

图 6:查看每个邮政编码代表的人口统计组。注:邮政编码 19112、19113 没有足够的数据用于分析。

上图中,我们看不到西班牙裔社区最多的邮政编码。此外,南费城、中心城、旧城(19107、19106)、菲什敦(19123、19122、19125、19133)、东北和西北的社区由白人社区主导。相比之下,费城西南部、西部和北部则由黑人社区主导。

白色贫困

下图向我们展示了每个邮政编码区的白人贫困率与该邮政编码区总人口数的对比。

图 7:与费城其他地区相比,按邮编划分的白人人均贫困率(每万人)。注:19113 和 19112 不包含用于分析的足够数据。

上面的地图显示了与整个城市的人均贫困总量相比,每个种族的贫困总量。上图显示,与其他人均贫困地区相比,白人贫困程度最高的地区也是白人数量最多的地区,因此这种分布并不令人惊讶。然而,在白人群体中,相对人均贫困率最高的邮政编码是 19154 年的远东北部。

黑色贫困

看看黑人社区与白人社区有着相似的分布模式。它遵循多数人占主导地位的邮政编码。如下图所示:

图 8:黑人群体的人均贫困率(每 10,000 人)与整个城市的人均贫困率的关系。注:邮政编码 19113、19112 没有足够的数据用于分析。

上图中,我们看到了与白人群体相似的主题。黑人群体的最高相对贫困率在邮政编码区内遵循相同的模式,其主要人口群体是黑人。北费城是整个城市中黑人相对人均贫困率最高的地方。

拉美裔贫困

虽然没有西班牙裔社区占主导地位的邮政编码。因此,当数据标准化时,可能很难辨别任何模式,并且与整个城市的总人均贫困数相比,查看西班牙裔社区的人均贫困数可能仍然是有见地的。如下图所示。

图 9:西班牙裔人均贫困数(每万人)与全市人均贫困数的对比

这里的趋势类似于原始贫困统计,因为西班牙裔社区集中在北费城地区。邮政编码 19122 显示了西班牙裔社区最高的人均贫困水平。

结论

在这里,通过以邮政编码为中心的地图来查看每个人口统计群体的人均贫困人数。与其他邮政编码相比,这些邮政编码是根据其人均贫困人数进行排名的。总的来说,人们注意到,人均贫困模式遵循一般趋势,正如在每个邮政编码中哪个社区群体最占主导地位所示。然而,与贫困的原始统计数字相比,调查人均统计数字时存在微妙的差异。

虽然在调查社会或人口因素时,人均比率显示了典型的标准化值,但人均比率并没有捕捉到任何可能存在的公平差异。因此,在下一节中,将调查根据特定邮政编码内的特定人口统计数据进行标准化的人均贫困率。

贫困分布的种族差异模型

贫困分布的种族差异模型背后的基本原理如下:假设一个村庄有两组人,A 组和 B 组。该村庄的总人数为 100 人,A 组有 80 人,B 组有 20 人。A 组有 20 人贫困,B 组都有 15 人贫困。在人均值上,A 组(每 100 个村庄中有 20 个贫困人口)高于 B 组(每 100 个村庄中有 15 个贫困人口)。然而,与每个群体的人数相比,B 群体的贫困人口似乎过多。例如:A 组每 80 人中有 20 人贫困(20%),B 组每 20 人中有 15 人贫困(75%)。

据说,第一个指标(每一群体中的贫困人数与总人数之比)是贫困的平等模型。相比之下,后一种衡量标准(每一群体的贫困人数与该群体的人数之比)被认为是贫困分布的种族差异模型。

因此,下图显示了与整个城市的相同指标相比,某个邮政编码内每个人口统计的贫困人口数量(由该邮政编码内该人口统计的人口数量控制)。

白人悬殊

下面是费城的白色差异度量。

图 10:整个费城白人群体贫困分布的差异模型,与整个费城相比,每个邮编每 10,000 名白人中有 1 名白人贫困。注:由于数据不足,19112 和 19113 未纳入分析。

在这里,我们看到差异模型计数给出了整个城市贫困行为的清晰视图。无论是从数量上还是从人均价值上看,白人贫困人口都不多的邮政编码现在都有了重要的价值。随着高贫困值的出现,新的邮政编码出现了西北部的邮政编码 19118、19119、19150、19138 与城市的其他地区相比,白人群体的人均贫困值相对较高。

黑色贫富差距模型

图 11:与整个费城相比,每个邮政编码的黑人社区人均贫困差异模型(每 10,000 名黑人中有 1 名黑人贫困)。注:19112 和 19113 包含的数据不足以进行分析。

值得注意的是,从不平等的角度来看,黑人社区的贫困模式显示了广泛的贫困,从平等的角度来看,这种贫困大大超出了贫困的范围。股票衍生人均价值相对较低的唯一邮政编码是在中心城市(19103,19102)和老城区(19107)。在这些邮政编码之外,贫困的公平模型捕捉到了一个更全面的视角。整个城市的黑人社区都很贫困。

拉美裔差异贫困模型

西班牙裔社区的差异模型如下所示。

图 12:与整个费城相比,西班牙裔社区人均贫困差异模型(每 10,000 名西班牙裔人中有 1 名西班牙裔贫困人口)。注:19112 和 19113 包含的数据不足以进行分析。

西班牙裔社区的公平地图显示了以费城北部和东北部地区为中心的广泛贫困。最初未被平等模型涵盖的地区包括南费城(19145,19148)和西费城(19139)。然而,与平等模型相比,差异模型显示了西班牙裔社区更广泛的贫困。然而,北费城地区西班牙裔社区的人均贫困水平仍然很高。

结论

公平模型是一种简单而强大的工具,用于查看邮政编码范围内特定人口的贫困水平,地图有助于查看整个费城这些贫困水平的相对丰富程度。

值得注意的是,公平模型强调了所有三个群体更广泛的贫困,但特别是黑人社区,其在公平模型中的贫困水平强调了系统性贫困水平。公平模型的一个结果是,人们可以在一个更合适的水平上比较不同的人口统计。尽管等式模型考虑了每个邮政编码的人口统计,但它并不提供表示各个邮政编码的人口统计信息。

因此,好处是公平的邮政编码比较可以帮助确定哪个邮政编码,一个人口统计或其他,可能超过或低于一些贫困的基准水平。这将在接下来探讨。

邮政编码差异比较

在按人口公平比较邮政编码时,人们必须选择基准水平的贫困进行比较。也就是说,如果在一个村庄里,我们调查占主导地位的 A 组的人均差距贫困水平,就会发现 80 个成员中有 20 个处于贫困状态。因此,如果 A 组代表村内的主导群体,通过将其他群体对资源的可获得性或可获得性与主导群体进行比较,可以直接衡量差距的程度。

A 组的差距模型贫困水平为每 10,000 人 2,500 人。B 组的差距模型贫困水平为每 10,000 人 7,500 人。因此,比较两者,我们看到 B 组的差距水平为 3.0 (7,500 / 2,500)。也就是说,与占主导地位的群体相比,B 群体的贫困率高出 3 倍。

差距水平是一个事实上的公平数字。这个数字代表了一个群体的贫困程度。将此量化为公平数字的推理思路是,假设资源的可获得性与一个社区将经历的贫困程度成反比。因此,可以在种族层面上比较两个群体,尤其是一个少数群体与一个多数群体在整个城市的贫困和资源分配方面的情况。

值得注意的是,另一种方法是根据美国的平均贫富差距水平来衡量贫富差距水平。尽管在确定资源或生活质量的偏差水平(通过贫困水平衡量)方面很有用,但这一指标将提供对费城邮政编码位置的深入了解;如果试图考察费城内部的相对差异,那将不会有什么好处。因此,必须在费城建立一个基地组织。尽管费城的一些邮政编码区的主要人口是黑人,但将该邮政编码区内的黑人社区视为资源主导群体似乎是不合理的,因为与白人社区在全国范围内的影响力相比,一个邮政编码区社区的影响力是最小的。

此外,通过公平模型比较邮政编码有助于在复杂或过度饱和的系统中确定每个人口统计群体贫困增加的地区,如费城。通过根据已知或基数(在这种情况下,是全国主导的人口群组)对人口统计数据进行标准化,可以将大范围的贫困转化为模式。

总之,可以看出,差异模型可用于比较整个费城地区的邮政编码,以深入了解不同邮政编码之间的不同资源分配水平(通过贫困衡量)。

黑人群体与白人群体在贫困差异模型方面的比较

在这里,我们看到了黑人社区贫困的公平性与白人社区贫困的公平性之间的差异。有过度的代表性,特别是在西费城邮政编码 19130(最暗的红色)。然而,从总体上看,很难看出代表性是过多还是不足。因此,下图有助于回答这个问题:“在哪个邮政编码区,贫困的黑人社区比例过高?”。

图 13:全市人口人均贫困水平的比较。该值越高,与白人社区的差异-贫困模型相比,黑人社区的贫困程度越高。注:由于数据不足,19113 和 19112 未包括在内。

这些图表极具洞察力。他们证明,与人口的原始计数相比,黑人社区在更大数量的邮政编码中的贫困比例过高,这一点可能无法通过查看平等图甚至原始计数图来说明。因为即使在费城西部和北部以黑人为主的社区,当控制人均贫困率和相对人口数量时,与白人群体相比,这些人口统计数据中的贫困比例仍然过高。

图 14:看看哪些邮政编码代表了过多或过少的贫困黑人社区。注:由于数据不足,19113 和 19112 未包括在内。

有趣的是,与白人的平等贫困水平相比,黑人社区人均贫困值最高的地区的过度贫困水平有所下降。这表明,在一些邮政编码区,白人和黑人的贫困水平都不正常,而且相对较高。

在贫困差异模型方面,西班牙裔群体与白人群体的比较

使用同样的方法,我们可以看看西班牙裔群体的贫困水平。下面是两张图表,第一张展示了在同一邮政编码内,西班牙裔社区与白人群体的公平贫困计数相比的相对公平贫困水平。第二项调查显示了西班牙裔社区在贫困人群中的代表性是过高还是过低。

图 15:西班牙裔社区的公平贫困指标与白人社区的公平贫困指标的对比。注:由于数据不足,19113 和 19112 未包括在内。

同样,与黑人社区一样,与白人社区的贫困水平相比,西班牙裔社区似乎在整个费城的贫困群体中占了很大比例,其贫困程度超过了使用简单的平等甚至公平模型所观察到的水平。在这里,拉美裔社区的贫困人口比例远远超过了之前提到的孤立的北费城地区。现在,可以看出西费城和北费城地区的贫困程度更不平衡。

图 16:西班牙裔社区的公平贫困指标与白人社区的公平贫困指标的对比,白人社区的每个邮政编码被分类为西班牙裔社区代表过多或代表不足。注:由于数据不足,19113 和 19112 未包括在内。

结论

该理论认为,在研究贫困时,人们可以深入了解整个城市的资源分配水平。这是基于这样一种假设,即一个人拥有的资源越多,贫困的可能性就越小,或者说就越不突出。然而,要想了解由差距导致的贫困水平的相对数量,就必须有可以与之进行比较的东西。在这项调查中,选择了历史上和国家资源占主导地位的群体,即白人群体,作为所有其他人口统计数据进行比较的基准。

由此产生的贫困差异比较模型为了解整个城市的相对贫困程度提供了有用的信息。尽管原始计数、人均计数甚至差异模型计数都很有用,但差异模型的真正好处是比较不同邮政编码的人口统计数据。差异模型比较可以让我们看到,少数民族人口和主要人口之间的贫困水平可以讲述一个更完整的故事。

研究表明,与白人群体相比,所有人口统计数据的贫困水平都比没有对比的简单计数更为显著。特别是,在使用差异比较模型时,黑人社区似乎在贫困群体中占了很大比例。虽然这是在简单的视差模型中提出的,但是当使用视差比较模型时,真正的意义才被抓住。

通过差异模型,尤其是差异比较模型,对西班牙社区贫困水平的看法发生了巨大变化。从原始数据甚至人均数据来看,拉美裔社区的贫困水平似乎集中在北费城地区。然而,当使用差异模型时,人们注意到西班牙裔社区的贫困水平远远超出了北费城地区。差异比较模型更加精确地反映了这一点,该模型显示,在整个费城,西班牙裔社区的过度代表性是系统性的。

当需要使用基于公平的决策系统来努力增加特定人群的资源可用性时,这些模型是有用的。因此,这些可能对希望利用更全面的方法来分配他们的注意力和资源的社会工作者或社会机构特别有用。

接下来的步骤

接下来,将进行更深入的调查。下一篇文章将允许我们回答诸如“有没有办法将贫困水平纳入这些模型中?这将如何改变费城人对贫困的看法”。

对于那些对这些模型背后的数学和所使用的代码感兴趣的人,请留意我关于这些主题的文章!

费城一瞥:第二部分

原文:https://towardsdatascience.com/a-look-at-philadelphia-part-two-63f165792850?source=collection_archive---------51-----------------------

在之前的系列中,费城是从贫困的角度来看的,强调了人口统计和贫困之间的关系。现在,让我们来看看贫困水平是如何描述费城的贫困的。此外,一旦确定了贫困的程度,将会尝试在特定的邮政编码范围内平衡贫困人口的数量和贫困的严重程度。希望建立一个模型,能够捕捉到城市中可能需要额外资源和援助的区域。

贫困水平是以低于联邦贫困线的百分比为基础的,目前的贫困线为 12,760 美元。贫困百分比代表贫困线以上的金额,50%约为每年 6000 美元,500%约为每年 64000 美元。

下面是费城的地图,展示了在一个给定的邮政编码中,哪一个贫困等级是最普遍的。

图 1:根据每个邮政编码的原始计数来看,哪种贫困程度最具代表性。注:19112、19113 因数据不足未包括在内。

图中的亮点(紫色)出现在费城的老城区和中心城区,代表该市最富裕的部分。

没有大多数人口生活在贫困线或贫困线以下(100%或 50%)的邮政编码。

另一种观点是研究居住在贫困线以下至少 50%的邮政编码区的人口比例。下图显示了整个城市中生活在贫困线以下至少 50%的人的贫困分布情况。

图 2:看看全市人均邮政编码低于贫困线 50%的人的生活水平。

看起来,贫困率最高的地区的邮政编码至少比联邦贫困线低 50%,延伸到北部和西部的中心城市。随着人们从东西两个方向向北方各县移动,贫困程度会逐渐降低。

有趣的是,当将其与原始贫困计数图进行比较时,两张图有很大不同:在第一部分图 5 中,贫困人口的原始计数显示了更广泛的人均贫困水平。当使用 50%的贫困截止点时,贫困水平聚集得更紧密。这表明,图 5 第一部分的贫困水平可能比贫困线以下 50%的人更加贫困。

此外,我们可以在全市范围内相互比较邮政编码。下图展示了贫困线以下 50%人口与整个城市的其他邮政编码之间的关系。

图 3:费城人均城市范围内生活在贫困线以下的人口比例高达 50%。

在比较整个城市的邮政编码时,出现了一个相似的趋势:北费城地区最为贫困。19140 年,19133 年,19134 年在北费城,以及该市的肯辛顿地区,人均贫困率几乎高出一个数量级,高达贫困线以下 50%。

贫困指标

对社会研究人员来说,将贫困严重程度的数量与特定地理区域内的贫困严重程度相协调可能是有用的。在本节中,将介绍一个量化人口数量和贫困水平之间的平衡的模型。

虽然这里没有提供证据,但是使用了两个度量标准。在记录贫困人口数量和贫困水平方面发挥更大作用的指标。这两个指标都考虑到了,但是一个更适合另一个,这取决于它的优先级。

等式 1:贫困指标,每个贫困水平的每个邮政编码的人口数量的权重增加。

更重要的捕捉人口数量的度量是 Eq。1.其中 Np 是人数,p 是贫困水平。

相反,为了最大限度地减少人口的影响,采用了人口计数的对数,这可以提高对生活贫困者的敏感性,如下所列。

等式 2:贫困指标,每个贫困水平的每个邮政编码的人口数量权重递减。

因此,如果需要决定向何处投资资源,该指标提供了平衡两种对立考虑的基本方法。一个人是否将资源投资于贫困数量最多或距离贫困线最远的地方。

下图图 4 显示了对贫困人口数量更敏感的第一个指标(使用等式 1)。

图 4:费城每个邮政编码的贫困指标。

有趣的是,随着人口比重的增加,西费城和南费城的贫困水平相比之下有所下降。因此,如果一个人关注于以人口统计为中心的模型,同时仍然希望识别贫困增加的地区,那么北费城地区将是目标。

如果将人口数量的影响最小化,并考虑到贫困水平的更大影响,我们会看到下面的地图:

图 5:以贫困水平为中心的贫困度量计算。

当最小化人口的影响时,在图 5 中可以看到整个城市的贫困状况。北费城是该市最贫困的地区,这一持续趋势在人口统计模型和贫困水平模型中都存在。然而,如果不强调人口数量,西费城和南费城的贫困状况就会变得更加明显。

另一个持续的趋势是大学城(19103),中心城市和老城区的贫困水平最低。

结论

在这一篇,也是最后一篇文章中,我们观察了整个费城的贫困状况,其中运用了几种观点。首先,在图 1 中查看了每个邮政编码最普遍的贫困水平。据发现,费城的大部分居住在大约 125%的贫困线以上,除了中心城市和老城区,随着向周围县的延伸,与贫困线的距离也增加了。

为了观察那些生活在贫困线或贫困线以下的人,多达 50%的人生活在贫困线以下,图 2 观察了每个邮政编码区的人均患病率。然后,为了比较整个城市的邮政编码,图 3 向我们展示了生活在贫困线以下 50%的人的邮政编码是如何比较的。在这两个例子中,北费城被强调为贫困加剧的地区。

最后,为了捕捉社会工作的竞争性意识形态:功利主义与基于差异的救济,设计了一个贫困衡量标准,以结合贫困人数的影响或可能存在的贫困水平。虽然在贫困指标中考虑到了这两种观点,但人们可以通过选择指标中贫困人口原始数量的影响来突出或专门关注其中的一个。在图 4 中,人数的影响被最大化,费城与贫困相关的传统区域相对于费城北部的普遍贫困状况有所减少。如图 5 中的图所示,当该指标与贫困人口数量对比时,北费城贫困人口数量的影响进一步凸显。在这里,相对于目前的贫困水平,人口数量被最小化。在这里,尽管费城北部再次被强调,但费城其他贫困地区也同样被展示出来。

在对费城的分析中,始终有几个趋势显示出来。首先,北费城有严重的贫困问题。贫困表现在原始统计、人均统计、人口控制统计、贫困水平统计和贫困度量统计中。

其次,紧随北费城之后的是西费城。尽管西费城的原始统计数据较低,但人口统计和计量得出的贫困水平却很明显。

第三,南费城是一个混合体;当考虑到人口统计时,对一些人来说,南费城是一个突出的贫困地区。但是当控制人均数量和贫困水平数量时,南费城在整个费城的贫困人口中处于中游。

最后,中心城市、老城区、偶尔还有大学城(取决于视角)的贫困率一直很低。无论从哪一方面来看,老城区都没有明显贫困。

总之,我希望提供一些费城的贫困状况。作者希望通过强调人们看待贫困的各种方式,突出对围绕社会工作的困难和挑战的理解。此外,尽管不是重点,作者希望贫困度量至少提供一种基本的方式,试图调和确定最需要的领域的至少两个方面。

精确度、召回率和 F1 分数

原文:https://towardsdatascience.com/a-look-at-precision-recall-and-f1-score-36b5fd0dd3ec?source=collection_archive---------1-----------------------

入门

探索机器学习度量之间的关系

特定领域的术语通常很难开始。有了软件工程背景,机器学习有许多这样的术语,我发现我需要记住使用工具和阅读文章。

一些基本术语是精确度、召回率和 F1 值。这些涉及到获得一个分类器做得有多好的更细粒度的想法,而不是只看整体准确性。写解释迫使我思考,帮助我自己记住题目。这就是我喜欢写这些文章的原因。

我在这篇文章中看到了一个二元分类器。同样的概念确实适用于更广泛的领域,只是需要对多类问题进行更多的考虑。但这是另一个时间要考虑的事情。

在进入细节之前,一个概览图总是不错的:

从原始测量值/标记数据到 F1 分数的指标层级。图片作者。

乍一看,这是一个有点混乱的网络。现在不需要担心细节,但是我们可以在下面的部分中自下而上地解释细节时回头看看。这些指标形成了一个层次结构,从真/假阴性/阳性(在底部),一直到F1-分数将它们绑定在一起。让我们从那里开始。

真/假阳性和阴性

二元分类器可以被视为将实例分类为负:

  • 肯定的:实例被分类为分类器试图识别的类的成员。例如,寻找猫照片的分类器会将有猫的照片分类为正面的(当正确时)。
  • 否定的:实例被归类为不是我们试图识别的类的成员。例如,寻找猫照片的分类器应该将有狗(没有猫)的照片分类为负面的。

精确度、召回率和 F1 分数的基础来自于真阳性真阴性假阳性假阴性的概念。下表说明了这些情况(将值 1 视为正面预测):

真/假阳性和阴性的例子

真阳性(TP)

下表显示了真阳性(TP)的 3 个示例。第一行是一个通用示例,其中 1 表示正面预测。下面两行是带有标签的示例。在内部,算法将使用 1/0 表示,但是为了更直观的理解,我在这里使用了标签。

真正正(TP)关系的例子。

假阳性

这些假阳性(FP)的例子说明了做出错误的预测,用实际的阴性样本预测阳性样本。这种失败的预测被称为假阳性。

真阴性(TN)

对于真阴性(TN)示例,猫分类器正确地将照片识别为其中没有猫,并且将医学图像识别为没有癌症的患者。所以预测是否定的,正确的(真)。

假阴性(FN)

在假阴性(FN)的情况下,分类器预测了阴性结果,而实际结果是阳性的。有猫的时候就像没有猫一样。所以预测是否定的,错误的(错误的)。因此,这是一个假阴性。

混淆矩阵

混淆矩阵有时用于说明基于上述四个值(TP、FP、TN、FN)的分类器性能。这些图表相互对照,显示出一个混淆矩阵:

混乱矩阵。图片作者。

以癌症预测为例,100 名患者的混淆矩阵可能如下所示:

癌症例子的混淆矩阵。图片作者。

这个例子有:

  • TP:正确预测了 45 个阳性病例
  • TN: 25 个阴性病例被正确预测
  • FP: 18 个阴性病例被错误分类(错误的阳性预测)
  • FN: 12 个阳性病例被错误分类(错误的阴性预测)

想一想,这里不同的错误有不同的严重性。将患有癌症的人归类为没有癌症(假阴性,拒绝治疗),可能比将没有癌症的人归类为患有癌症(假阳性,考虑治疗,做进一步测试)更严重。

由于不同种类的错误的严重性在不同的用例中有所不同,因此可以使用诸如准确度精度召回F1-分数之类的度量来平衡分类器的估计值。

准确(性)

用于模型评估的基本指标通常是准确度,描述所有预测中正确预测的数量:

精确度公式。图片作者。

这三个公式显示了相同的计算精度,但在不同的措辞。从更形式化到更直观(我的看法)。在上面的癌症例子中,精确度是:

  • (TP+TN)/DatasetSize =(45+25)/100 = 0.7 = 70%。

这可能是模型评估度量中最直观的,因此也是最常用的。但是更深入一点通常也是有用的。

精确

精度是对有多少正面预测是正确的(真阳性)的度量。它的公式是:

精确公式。图片作者。

以上三个都是相同的不同表达方式,最后一个用癌症作为具体的例子。在这个癌症示例中,使用来自上述示例混淆矩阵的值,精度将是:

  • 45/(45+18)=45/63=0.714=71.4%.

回忆/敏感度

Recall 是对数据中所有阳性案例中分类器正确预测的阳性案例数量的度量。它有时也被称为**。它的公式是:

回忆公式。图片作者。

同样,这只是用三种不同方式表达的同一个公式。对于癌症的例子,使用混淆矩阵数据,回忆将是:

  • 45/(45+12)=45/57=0.789=78.9%.

特征

特异性是对做出的否定预测有多少是正确的(真否定)的度量。它的公式是:

特异性公式。图片作者。

在上面的医学例子中,特异性是:

  • 25/(25+18)=0.581=58,1%.

f1-分数

F1 分数是一个结合了精确度和召回率的指标。一般描述为两者的调和平均值。调和平均值只是计算值的“平均值”的另一种方法,通常被描述为比传统的算术平均值更适合比率(如精确度和召回率)。在这种情况下,F1 分数使用的公式为:

f1-得分公式。图片作者。

这个想法是提供一个单一的衡量标准,以平衡的方式衡量两个比率(精确度和召回率),要求两者都有一个更高的值,以提高 F1 值。例如,精度为 0.01,召回率为 1.0,则得出:

  • (0.01+1.0)/2 的算术平均值=0.505,
  • f1-得分分数(上式)为 2(0.011.0)/(0.01+1.0)=~0.02。

这是因为 F1 分数对两个输入中的一个具有低值(此处为 0.01)更加敏感。如果你想平衡这两者,这很好。

F1 分数的一些优势:

  • 非常小的精确度或召回率将导致较低的总得分。因此,它有助于平衡这两个指标。
  • 如果您选择阳性类别作为样本较少的类别,F1-score 可以帮助平衡阳性/阴性样本之间的指标。
  • 正如本文中的第一个图所示,它将许多其他指标组合成一个单一的指标,一次捕获许多方面。

在上面的癌症例子中,F1 值为

  • 2 * (0.7140.789)/(0.714+0.789)=0.75 = 75%*

探索 F1 分数

我发现通过看一些例子最容易理解概念。首先是 Python 中计算 F1 分数的函数:

F1 分数公式的 Python 实现。图片作者。

为了比较精度和召回率的不同组合,我生成了精度和召回率的示例值,范围为 0 到 1,步长为 0.01(0.01、0.02、0.03、…、1.0 的 100 个值):

生成精度和召回率的示例值。图片作者。

这将产生一个包括精确度和召回率的列表来进行实验:

生成的精度和召回值。图片作者。

f1-精确度=回忆时的分数

如果精度等于召回率,要查看 F1 分数是多少,我们可以计算每一点的 F1 分数 0.01 到 1.0,精度=每一点的召回率:

计算示例值的 F1 分数,其中精度=每 100 分的召回率。图片作者。

f1-当精确度=回忆时得分。当 p=r 时,f1-分数等于每个点的精确度和召回率。

f1-如果两个输入指标(P&R)相等,得分等于精确度和召回率。表格中的差异栏显示了较小值(精确度/召回率)与 F1 分数之间的差异。这里它们是相等的,所以没有区别,在下面的例子中它们开始变化。

f1-召回率= 1.0,精确度= 0.01 至 1.0 时的得分

因此,F1 值应该能够很好地处理其中一个输入(P/R)较低的情况,即使另一个输入非常高。

让我们尝试将 Recall 设置为最大值 1.0,并将精度从 0.01 变到 1.0:

当召回率始终为 1.0 且精确度在 0.01 到 1.0 之间变化时,计算 F1 分数。图片作者。

f1-当回忆= 1.0 且精确度从 0.1 到 1.0 变化时的分数。图片作者。

正如预期的那样,当两个输入( Precision / R ecall)中的一个为低时,F1 值保持低。差异列显示了在这种情况下 F1 分数如何比较小的输入值(此处为精度)上升得更快,在图表的中间增加更多,由较大的值(此处为回忆一下)加权一点。然而,它永远不会远离较小的输入,平衡基于两个输入的总得分。这些差异也可以在图上看到(差异在垂直红线处最大):

f1-精度得分= 1.0,回忆得分= 0–1.0,突出显示文章。图片作者。

f1-精确度= 1.0,回忆= 0.01 到 1.0 时的得分

如果我们交换上述示例中精度召回的角色,我们会得到相同的结果(由于F1-分数公式):

当精度始终为 1.0,召回率在 0.0 到 1.0 之间变化时,计算 F1 分数。图片作者。

f1-精确度= 1.0 且回忆从 0.01 到 1.0 变化时的分数。图片作者。

也就是说,无论哪一个更高或更低,总的F1-分数都受到完全相同的影响(这在公式中似乎相当明显,但容易忘记)。

f1-精确度=0.8,回忆= 0.01 到 1.0 时的得分

除了将一个输入固定在最大值之外,让我们试着降低一点。这里精度固定为 0.8,而召回率和以前一样在 0.01 到 1.0 之间变化:

当精度始终为 0.8,召回率在 0.0 到 1.0 之间变化时,计算 F1 分数。图片作者。

f1-当精确度= 0.8 且回忆从 0.01 到 1.0 变化时的分数。图片作者。

输入(0.8,1.0)的最高分是 0.89。上升曲线形状类似于回忆值上升。在最大精度* = 1.0 时,它获得的值比较小的值(0.89 比 0.8)高大约 0.1(或 0.09)。*

f1-精确度=0.1,回忆=0.01 到 1.0 时的得分

如果我们把一个值固定在最小值 0.1 附近呢?

当精度始终为 0.1,召回率在 0.0 到 1.0 之间变化时,计算 F1 分数。图片作者。

f1-当精确度= 0.1 且回忆从 0.01 到 1.0 变化时的分数。图片作者。

因为两个输入中的一个总是低电平(0.1),所以F1-分数不会升得很高。然而,有趣的是,它再次上升到最大值,大约比较小的输入值大 0.08(精度* = 0.1,F1-分数 =0.18)。这非常类似于上面的固定值精度 = 0.8,其中达到的最大值比较小的输入高 0.09。*

关注 F1 分数的准确性或回忆性

除了普通的 F1-score 之外,还有一个更通用的版本,叫做 Fbeta-scoreF1-scoreFbeta-score 的特例,其中 beta =1。它允许人们通过增加一个加权因子来衡量精确度或回忆更多。在这篇文章中,我不会深入探讨这个问题,但是,这是需要记住的。

f1-分数与准确性

准确性通常被描述为一个更直观的指标,使用 F1-score 可以更好地处理更不平衡的数据集。那么,F1-score(F1)vsAccuracy(ACC)如何在不同类型的数据分布(正/负比率)之间进行比较呢?

不平衡:阳性病例很少

在此示例中,存在 10 个阳性病例和 90 个阴性病例的不平衡,对于分类器来说,具有不同的 TN、TP、FN 和 FP 值来计算 f 1 和 ACC:

不同预测率和不平衡数据下的 F1 分数与准确性。图片作者。

等级不平衡的最大精度是 TN=90 和 TP=10 的结果,如第 2 行所示。

在 TP =0 的每种情况下,精度召回都变成 0,并且F1-分数不能计算(除以 0)。这种情况可以被评分为 F1-score = 0,或者通常将分类器标记为无用。因为分类器不能预测任何正确的肯定结果。这是上表中的第 0、4 和 8 行。这些还示出了对于损坏的分类器的高准确度的一些情况(例如,具有 90% 准确度的第 0 行,同时总是仅预测负面)。

剩余的行说明了 F1 分数如何对分类器做出更平衡的预测做出更好的反应。比如第 5 行的F1-得分* =0.18 vs 准确度 = 0.91,到第 7 行的F1-得分 =0.46 vs 准确度 = 0.93。这只是 2 个正面预测的变化,但由于这是 10 个可能中的一个,变化实际上相当大,并且 F1 分数强调了这一点(并且准确度看不到任何其他值的差异)。*

平衡 50/50 阳性和阴性病例:

当数据集更加平衡时会怎样?以下是具有 50 个负项目和 50 个正项目的平衡数据集的类似值:

f1-分数与不同预测率和平衡数据的准确性。图片作者。

F1-score 在这里仍然是一个稍微好一点的指标,当只有很少(或没有)的正面预测时。但是这种差异并不像不平衡的班级那么大。一般来说,更深入地研究结果总是有用的,尽管在平衡的数据集中,高精度通常是分类器性能良好的良好指标。

不平衡:很少有负面案例

最后,如果少数阶级被认为是消极的而不是积极的,会发生什么? F1-score 不再平衡而是相反。下面是一个有 10 个阴性病例和 90 个阳性病例的例子:

f1-当正类为多数类时,得分与准确度。图片作者。

例如,第 5 行在 10 个否定情况中只有 1 个正确预测。但是 F1 得分仍然在 95%左右,所以非常好,甚至高于准确度。在同样的比例适用于少数阳性病例的情况下,该病例的 F1 得分为 0.18,而现在为 0.95。这是一个更好的质量指标。

少数阴性病例的这一结果是因为计算 F1 分数的公式是如何定义超过精度召回(强调阳性病例)的。如果你回头看看本文开头的图表,你会看到真阳性是如何进入精度召回,并从那里进入F1-分数。该图还显示了真阴性F1 分数没有任何影响。如果你颠倒比例,并且有更少的真阴性,这似乎是不可思议的。

因此,像往常一样,我认为牢记如何表示您的数据是有好处的,并做您自己的数据探索,不要盲目相信任何单一的指标。

结论

那么这些指标有什么用呢?

如果您有非常平衡的数据集,并且对所有类型的输出都同样感兴趣,那么传统的精度是一个很好的衡量标准。在任何情况下,我都喜欢从它开始,因为它是直观的,并根据需要从那里深入挖掘。

如果你想尽量减少误报,精确度是非常重要的。例如,您构建了一个垃圾邮件分类器。您希望看到尽可能少的垃圾邮件。但是你不想错过任何重要的,非垃圾邮件。在这种情况下,您可能希望以最大化精度为目标。

回忆在医疗(如识别癌症)等领域非常重要,在这些领域中,您确实希望将遗漏阳性病例的几率降至最低(预测假阴性)。在这些典型的案例中,错过一个积极的案例比错误地将某件事归类为积极的要付出更大的代价。

无论是精度还是召回都不一定单独有用,因为我们通常对整体感兴趣。精度作为一个选项总是很好检查的。F1-得分又是一个。

F1-score 结合了精确度和召回率,也适用于数据集不平衡的情况,因为它要求精确度和召回率都有一个合理的值,正如我在本文中展示的实验所证明的那样。即使有少量正例与负例,如果正类的精度或召回率较低,公式也会降低指标值的权重。

除此之外,还有各种其他指标和方法来探索您的结果。一种流行且非常有用的方法也是使用 ROC-和 precision-recall 曲线 。这允许根据我们想要最小化的误差类型来微调评估阈值。但这是另一个需要探讨的话题。

今天到此为止..😃

信用风险评估的机器学习方法

原文:https://towardsdatascience.com/a-machine-learning-approach-to-credit-risk-assessment-ba8eda1cd11f?source=collection_archive---------5-----------------------

分类任务

预测贷款违约及其概率

来源:unDraw.co

1.介绍

信用违约风险被简单地称为由于借款人未能偿还贷款而给贷款人造成损失的可能性。信用分析师通常负责通过彻底分析借款人偿还贷款的能力来评估这种风险——但信用分析师的时代已经一去不复返了,现在是机器学习时代!由于其无与伦比的预测能力和速度,机器学习算法可以为信用风险评估领域提供很多东西。在这篇文章中,我们将利用机器学习的力量来预测借款人是否会拖欠贷款,并预测他们的违约概率。让我们开始吧。

2.资料组

我们正在使用的数据集可以在 Kaggle 上找到,它包含 32,581 名借款人的数据和与每个借款人相关的 11 个变量。让我们看看这些变量是什么:

  • 年龄——数字变量;年龄(年)
  • 收入——数字变量;美元年收入
  • 家庭状况——分类变量;“租金”、“抵押贷款”或“自有”
  • 就业时间——数值变量;就业年限(年)
  • 贷款意向——分类变量;“教育”、“医疗”、“风险”、“家居装修”、“个人”或“债务合并”
  • 贷款金额——数字变量;贷款金额(美元)
  • 贷款等级——分类变量;“A”、“B”、“C”、“D”、“E”、“F”或“G”
  • 利率——数字变量;百分比利率
  • 贷款收入比——数字变量;介于 0 和 1 之间
  • 历史默认值—二元、分类变量;“Y”或“N”
  • 贷款状态—二进制数字变量;0(无默认值)或 1(默认值)→这将是我们的目标变量

现在我们知道了我们在这里处理的是什么样的变量,让我们来看看事情的本质。

3.数据探索和预处理

首先,让我们继续检查数据集中缺失的值。

#Checking for missing values
data.isnull().sum()Age                       0 
Income                    0 
Home_Status               0 
Employment_Length       895 
Loan_Intent               0 
loan_Grade                0 
Loan_Amount               0 
Interest_Rate          3116 
Loan_Status               0 
loan_percent_income       0 
Historical_Default        0 
dtype: int64

我们可以看到就业时间和利率都有缺失值。鉴于缺失值只占数据集的一小部分,我们将删除包含缺失值的行。

#Dropping missing values
data = data.dropna(axis=0)

接下来,我们将寻找数据集中的异常值,以便进行相应的补救。我们将使用 describe()方法来完成这项工作,该方法用于计算描述性统计数据。它不仅有助于识别异常值,还能让我们更好地理解数据是如何分布的。我们还将使用散点图矩阵,这是一个散点图网格,用于可视化变量组合之间的二元关系,以直观地检测异常值。

data.describe()

作者图片

我不知道你的情况,但我没遇到过那么多活到 144 岁或工作了 123 年的人。除此之外,来自变量年龄就业时间的异常值可能会对的模型产生负面影响,因此应该被移除。在此之前,我们将使用散点图矩阵寻找更多的异常值。

#Scatterplot matrix
fig = px.scatter_matrix(data, dimensions=
["Age","Income","Employment_Length","Loan_Amount","Interest_Rate"],
labels={col:col.replace('_', ' ') for col in data.columns},           height=900, color="Loan_Status", color_continuous_scale=px.colors.diverging.Tealrose)
fig.show()

作者图片

现在很清楚的是收入也有一个需要剔除的异常值。我们现在将使用下面几行代码删除所有异常值。

#Removing outliers
data = data[data["Age"]<=100]
data = data[data["Employment_Length"]<=100]
data = data[data["Income"]<= 4000000]

鉴于我们数据集的性质,我们预计我们正在处理一个不平衡的分类问题,这意味着我们的非违约案例比违约案例多得多。使用下面的代码,我们确认 78.4%的数据集包含非默认案例的情况确实如此。

#Percentage of non-default cases
data_0 = data[data.Loan_Status == 0].Loan_Status.count() / data.Loan_Status.count()
data_0

考虑到这一点,我们现在将进一步探索贷款状态如何与数据集中的其他变量相关联。

#Box plot
fig = px.box(data, x="loan_Grade", y="loan_percent_income", color="Loan_Status",
color_discrete_sequence=px.colors.qualitative.Dark24,
labels={col:col.replace('_', ' ') for col in data.columns},
category_orders={"loan_Grade":["A","B","C","D","E","F","G"]})
fig.update_layout(legend=dict(orientation="h", yanchor="bottom",
y=1.02, xanchor="right", x=1))
fig.show()

作者图片

当我们看这个方框图时,两件事很快就凸显出来了。我们可以清楚地看到,那些没有违约的人在所有贷款等级中都有较低的贷款收入比均值;这并不奇怪。我们还可以看到,没有贷款等级为 G 的借款人能够偿还他们的贷款!

使用平行类别图,我们可以了解数据集中不同类别变量之间的相互关系,并且我们可以根据贷款状态绘制出这些关系。

#Parallel category diagram
fig = px.parallel_categories(data, color_continuous_scale=px.colors.sequential.RdBu, color="Loan_Status",
dimensions=['Home_Status', 'Loan_Intent', "loan_Grade", 'Historical_Default'], labels={col:col.replace('_', ' ') for col in data.columns})
fig.show()

作者图片

上图的主要要点:

  • 我们的数据集主要由以前从未拖欠过贷款的借款人组成;
  • 贷款等级“A”和“B”是最常见的等级,而“F”和“G”是最不常见的等级;
  • 房屋租赁者比有抵押贷款的人更经常拖欠贷款,而房主拖欠的最少;
  • 借款人用于房屋装修的贷款最少,用于教育的贷款最多。此外,用于支付医疗费用和债务整合的贷款违约更为常见。

在我们开始模型训练之前,我们需要确保我们所有的变量都是数值型的,因为我们将要使用的一些模型不能对标签数据进行操作。我们可以简单地使用一键编码方法来做到这一点。

#One hot encoding of categorical variables
df = pd.get_dummies(data=data,columns=['Home_Status','Loan_Intent','loan_Grade','Historical_Default'])

现在是时候将我们的数据集分割成一列并测试分割,我们将准备好开始构建一些模型。

#Train and test split
Y = df['Loan_Status']
X = df.drop('Loan_Status',axis=1)
x_train, x_test, y_train, y_test = model_selection.train_test_split(X, Y, random_state=0, test_size=.20)

Giphy

4.模型训练和评估

在本节中,我们将训练和测试 3 个模型,即 KNN、逻辑回归和 XGBoost。我们还将评估他们在预测贷款违约及其概率方面的表现。

首先,我们将构建模型并查看一些评估指标,以评估模型预测类别标签的能力,即默认或无默认。

def model_assess(model, name='Default'):
model.fit(x_train, y_train)
preds = model.predict(x_test)
preds_proba = model.predict_proba(x_test)
print('                   ', name, '\n',
classification_report(y_test, model.predict(x_test)))#KNN
knn = KNeighborsClassifier(n_neighbors=151)
model_assess(knn, name='KNN')#Logistic Regression
lg = LogisticRegression(random_state=0)
model_assess(lg, 'Logistic Regression')#XGB
xgb = XGBClassifier(n_estimators=1000, learning_rate=0.05)model_assess(xgb, 'XGBoost')

作者图片

我们之前已经认识到,我们正在处理一个不平衡的数据集,因此我们需要确保我们在我们的案例中使用了适当的评估指标。出于这个原因,我们将对常见的准确性指标持保留态度。为了说明为什么会出现这种情况,accuracy 计算了真实预测值与输入样本总数的比率,这意味着我们的模型通过预测多数类可以获得相当高的准确性,但无法捕获少数类 default,这可不是什么好事。这就是为什么我们将重点评估模型分类性能的评估指标是精度召回F1 得分

首先, Precision 给出了分类器预测的真阳性与总阳性的比率,其中阳性表示我们上下文中的默认情况。考虑到它们是我们数据集中的少数类,我们可以看到我们的模型在正确预测这些次要实例方面做得很好。此外,回忆,也称为真阳性率,给出了真阳性的数量除以实际上属于阳性类的元素总数。在我们的例子中,回忆是一个比精确度更重要的指标,因为我们更关心假阴性(我们的模型预测某人不会违约,但他们会违约)而不是假阳性(我们的模型预测某人会违约,但他们不会)。最后, F1 分数提供了一个衡量精确度和召回率的单一分数。现在我们知道了要寻找什么,我们可以清楚地看到 XGboost 在所有 3 个指标中表现最好。尽管它在精确度上比在召回上得分更高,但它仍然有 0.81 的不错的 F1 分数。

我们现在来看看 ROC 其中是一条概率曲线,x 轴是假阳性率(FPR),y 轴是真阳性率(TPR,召回)。最佳模型应该最大化 TPR 为 1,最小化 FPR 为 0。也就是说,我们可以使用 ROC 曲线曲线下的面积 AUC 来比较分类器,其中其值越高,该模型在预测 0 为 0 和 1 为 1 时就越好。

#ROC AUC
fig = plt.figure(figsize=(14,10))
plt.plot([0, 1], [0, 1],'r--')#KNN
preds_proba_knn = knn.predict_proba(x_test)
probsknn = preds_proba_knn[:, 1]
fpr, tpr, thresh = metrics.roc_curve(y_test, probsknn)
aucknn = roc_auc_score(y_test, probsknn)
plt.plot(fpr, tpr, label=f'KNN, AUC = {str(round(aucknn,3))}')#Logistic Regression
preds_proba_lg = lg.predict_proba(x_test)
probslg = preds_proba_lg[:, 1]
fpr, tpr, thresh = metrics.roc_curve(y_test, probslg)
auclg = roc_auc_score(y_test, probslg)
plt.plot(fpr, tpr, label=f'Logistic Regression, AUC = {str(round(auclg,3))}')#XGBoost
preds_proba_xgb = xgb.predict_proba(x_test)
probsxgb = preds_proba_xgb[:, 1]
fpr, tpr, thresh = metrics.roc_curve(y_test, probsxgb)
aucxgb = roc_auc_score(y_test, probsxgb)
plt.plot(fpr, tpr, label=f'XGBoost, AUC = {str(round(aucxgb,3))}')plt.ylabel("True Positive Rate")
plt.xlabel("False Positive Rate")
plt.title("ROC curve")
plt.rcParams['axes.titlesize'] = 18
plt.legend()
plt.show()

作者图片

我们可以再次看到,XGBoost 性能最好,因为它具有最高的 AUC,因此是区分默认和非默认类的最佳分类器。

到目前为止,我们已经研究了每个模型预测类别标签的能力,现在我们将评估它们在预测样本属于正类别的概率(即违约概率)方面的性能。对于这项任务,我们将使用可靠性图Brier 评分,其中前者创建实际概率与测试集预测概率的图表,后者计算预测概率与其各自正类值之间的均方误差。考虑到 Brier 得分是一个成本函数,Brier 得分越低表示预测越准确。

#Reliability plot and Brier Score
fig = plt.figure(figsize=(14,10))
plt.plot([0, 1], [0, 1], color="black")#KNN
knn_y, knn_x = calibration_curve(y_test, preds_proba_knn[:,1], n_bins=10, normalize=True)
loss_knn = brier_score_loss(y_test, preds_proba_knn[:,1])
plt.plot(knn_x, knn_y, marker='o', label=f'KNN, Brier score = {str(round(loss_knn,3))}')#Logistic Regression
lg_y, lg_x = calibration_curve(y_test, preds_proba_lg[:,1], n_bins=10, normalize=True)
loss_lg = brier_score_loss(y_test, preds_proba_lg[:,1])
plt.plot(lg_x, lg_y, marker='o',label=f'Logistic Regression, Brier score = {str(round(loss_lg,3))}')#XGBoost
preds_proba_xgb = xgb.predict_proba(x_test)
xgb_y, xgb_x = calibration_curve(y_test, preds_proba_xgb[:,1], n_bins=10, normalize=True)
loss_xgb = brier_score_loss(y_test, preds_proba_xgb[:,1])
plt.plot(xgb_x, xgb_y, marker='o', label=f'XGBoost, Brier score = {str(round(loss_xgb,3))}')plt.ylabel("Actual probabilty")
plt.xlabel("Predicted probability")
plt.title("Reliability plot")
plt.rcParams['axes.titlesize'] = 18
plt.legend()
plt.show()

作者图片

我们可以从上面的 Brier 评分中看到,与其他型号相比,XGBoost 再次表现最佳,这并不令人惊讶。从这个分数和图中,我们得出结论,我们的模型对于概率预测来说是校准良好的,这意味着预测的概率与每个类别的预期概率分布非常匹配,因此不需要进一步校准。

不用说,哪个模型被选为我们在预测类别标签和违约概率方面表现最好的模型。如果你不知何故跳过了前面所有的步骤,发现自己在这里,你应该回去读一下,顺便说一下,这是 XGBoost。

吉菲

5.特征重要性

最后但并非最不重要的一点,是时候确定哪些特征对预测我们的目标变量最有影响了。对于这个任务,我们将通过信息增益使用特性重要性,它测量每个特性对 XGBoost 中每棵树的贡献。

#Feature importance plot
fig, (ax1, ax2) = plt.subplots(figsize = (15, 17), ncols=1, nrows=2)
plt.subplots_adjust(left=0.125, right=0.9, bottom=0.1, top = 0.9, wspace=0, hspace = 0.5)plot_importance(xgb, importance_type='gain', ax = ax1)
ax1.set_title('Feature Importance by Information Gain', fontsize = 18)
ax1.set_xlabel('Gain')

作者图片

从上图中我们可以看出,作为住房状况的租金、贷款收入比和贷款等级 C 是预测贷款违约及其概率的三个最重要的特征。

就这样。

6.结论

总之,我们分析和预处理了我们的数据,训练和评估了 3 个模型,纳姆利 KNN,逻辑回归和 XGBoost,以了解它们预测贷款违约的能力和概率。我们使用 Precision、Recall、F1 和 ROCAUC 来评估模型在预测类别标签方面的性能。我们特别使用了这些指标,并放弃了准确性,因为我们正在处理一个不平衡的数据集。我们还使用可靠性图和 Brier 评分来评估我们的模型的校准。在确定 XGBoost 在所有指标上表现最佳之后,我们使用信息增益的特性重要性研究了哪些特性对我们的预测最重要。说完这些,我们就可以总结我们的演示了,机器学习是如何应用于信用风险评估领域的。

希望你觉得这篇文章很有见地!

机器学习项目——预测二手车价格

原文:https://towardsdatascience.com/a-machine-learning-project-predicting-used-car-prices-efbc4d2a4998?source=collection_archive---------6-----------------------

你的第一个机器学习项目的逐步指南!

这是给那些想进入数据科学的人,他们有一点点知识,但很难想出你的第一个数据科学项目。这就是为什么我创建了一个逐步指南来完成您的第一个端到端机器学习模型!跟着做,你会学到很多新技能。

我使用了 Kaggle 的二手车数据集,因为它有各种分类和数字数据,并允许您探索处理缺失数据的不同方式。我把我的项目分成三部分:

  1. 探索性数据分析
  2. 数据建模
  3. 特征重要性

1.探索性数据分析

了解我的数据

*# Importing Libraries and Data*
import numpy as np
import pandas as pd *# data processing, CSV file I/O (e.g. pd.read_csv)*
import os
for dirname, _, filenames **in** os.walk('/kaggle/input'):
    for filename **in** filenames:
        print(os.path.join(dirname, filename))df = pd.read_csv("../input/craigslist-carstrucks-data/vehicles.csv")*# Get a quick glimpse of what I'm working with*
print(df.shape)
print(df.columns)
df.head()

在处理数据科学问题时,我总是做的第一件事是了解我正在处理的数据集。使用 df.shapedf.columnsdf.head() ,我能够看到我正在处理的特性以及每个特性需要什么。

探索分类数据

df.nunique(axis=0)

我喜欢使用 df.nunique(axis=0) ,来查看每个变量有多少个唯一值。利用这个,我可以看到是否有什么不寻常的事情,并找出任何潜在的问题。例如,如果它显示有 60 个州,这将引发一个红旗,因为只有 50 个州。

探索数字数据

df.describe().apply(lambda s: s.apply(lambda x: format(x, 'f')))

对于数字数据,我使用 df.describe() 来快速浏览我的数据。例如,我可以立即看到价格、的问题,因为最低价格是 0 美元,最高价格是 3,600,028,900 美元。

稍后,您将看到我是如何处理这些不切实际的异常值的。

包含太多空值的列

NA_val = df.isna().sum()def na_filter(na, threshold = .4): *#only select variables that passees the threshold*
    col_pass = []
    for i **in** na.keys():
        if na[i]/df.shape[0]<threshold:
            col_pass.append(i)
    return col_passdf_cleaned = df[na_filter(NA_val)]
df_cleaned.columns

在继续我的 EDA 的其余部分之前,我使用上面的代码删除了超过 40%的值为 null 的所有列。这使我剩下下面的专栏。

移除异常值

df_cleaned = df_cleaned[df_cleaned['price'].between(999.99, 250000)] *# Computing IQR*
Q1 = df_cleaned['price'].quantile(0.25)
Q3 = df_cleaned['price'].quantile(0.75)
IQR = Q3 - Q1*# Filtering Values between Q1-1.5IQR and Q3+1.5IQR*
df_filtered = df_cleaned.query('(@Q1 - 1.5 * @IQR) <= price <= (@Q3 + 1.5 * @IQR)')
df_filtered.boxplot('price')

在使用四分位(IQR)方法移除价格的异常值之前,我决定将价格的范围设置为更现实的数字,这样标准差将被计算为比 9,575,025 更现实的数字。

IQR 也称为中间值,是一种统计离差的度量,可用于识别和移除异常值。IQR 范围规则的理论如下:

  1. 计算 IQR (=第三个四分位数-第一个四分位数)
  2. 找出范围的最小值(=第一个四分位数— 1.5 * IQR)
  3. 找出范围的最大值(=第三个四分位数+ 1.5 * IQR)
  4. 删除任何超出此范围的值。

你可以在上面的方框图中看到,我使用这种方法显著缩小了价格的范围。

df_filtered.describe().apply(lambda s: s.apply(lambda x: format(x, 'f')))

使用。describe() 同样,我们可以看到价格范围似乎比最初更现实,但年份和里程表似乎有点偏离(例如,2021 年的最大值)。

我使用下面的代码将年份范围设置为 1900–2020,将里程表设置为 0–271,341.5。

*# cant be newer than 2020*
df_filtered = df_filtered[df_filtered['year'].between(1900, 2020)]*# = 140000 + 1.5 * (140000-52379)*
df_filtered = df_filtered[df_filtered['odometer'].between(0, 271431.5)]

删除剩余的列

df_final = df_filtered.copy().drop(['id','url','region_url','image_url','region','description','model','state','paint_color'], axis=1
df_final.shape

通过部分使用我的直觉,部分猜测和检查,我删除了以下几列:

  • urlidregion_urlimage_url: 它们与正在进行的分析完全无关
  • 描述:描述可能可以使用自然语言处理,但是超出了本项目的范围,因此不予考虑
  • 地区,州:我去掉了这些,因为它们本质上传达的信息和经度和纬度是一样的。
  • model :我去掉了这个,因为有太多不同的值,无法将其转换为虚拟变量。此外,我不能使用标签编码,因为值是无序的。
  • paint_color :最后我在进行了特征重要性(稍后你会看到)后去掉了这个。由于特征重要性表明 paint_color 在确定价格中的重要性很小,所以我将其移除,模型的准确性提高了。

可视化变量和关系

import matplotlib.pylab as plt
import seaborn as sns*# calculate correlation matrix*
corr = df_final.corr()*# plot the heatmap*
sns.heatmap(corr, xticklabels=corr.columns, yticklabels=corr.columns, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True))

清理完数据后,我想可视化我的数据,并更好地理解不同变量之间的关系。利用 sns.heatmap() 我们可以看到年份价格正相关里程表价格负相关——这个有道理!看来我们走对了路。

df_final['manufacturer'].value_counts().plot(kind='bar')df_cleaned['type'].value_counts().plot(kind='bar')

出于我自己的兴趣,我使用条形图绘制了一些分类属性(见下文)。为了更好地了解数据集,您还可以做更多的可视化工作,如散点图和箱线图,但我们将进入下一部分,数据建模!

数据建模

虚拟变量

df_final = pd.get_dummies(df_final, drop_first=True)
print(df_final.columns)

为了能够在我的随机森林模型中使用分类数据,我使用了 pd.get_dummies()。这实质上是将变量的每个唯一值变成它自己的二进制变量。例如,如果制造商之一是本田,那么将创建一个名为“manufacturer_honda”的新虚拟变量,如果是本田,它将等于 1,否则等于 0。

缩放数据

from sklearn.preprocessing import StandardScaler
X_head = df_final.iloc[:, df_final.columns != 'price']X = df_final.loc[:, df_final.columns != 'price']
y = df_final['price']
X = StandardScaler().fit_transform(X)

接下来,我使用标准缩放器缩放数据。Prasoon 提供了一个很好的答案这里为什么我们要缩放(或标准化)我们的数据,但本质上,这样做是为了我们的自变量的缩放不会影响我们模型的组成。例如,的最大数字是 2020,里程表的最大数字超过 20 万。如果我们不对数据进行缩放,里程表的一个小变化会比的同样变化产生更大的影响。

创建模型

from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error as maeX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.25, random_state=0)
model = RandomForestRegressor(random_state=1)
model.fit(X_train, y_train)
pred = model.predict(X_test)

我决定使用随机森林算法有几个原因:

  1. 很好地处理了高维度,因为它采用了数据子集。
  2. 它非常通用,并且只需要很少的预处理
  3. 这在避免过度拟合方面很棒,因为每个决策树都具有低偏差
  4. 它允许您检查特性重要性,您将在下一节看到!

检查模型的准确性

print(mae(y_test, pred))
print(df_final['price'].mean())model.score(X_test,y_test)

总的来说,我的模型在平均价格为 12600 美元左右的情况下实现了 1590 美元的 MAE,准确率为 90.5%!

MAE 和平均价格

模型的准确性

特征重要性

feat_importances = pd.Series(model.feature_importances_, index=X_head.columns)
feat_importances.nlargest(25).plot(kind='barh',figsize=(10,10))

我花了很多时间寻找特性重要性的最佳定义,Christoph Molnar 提供了最佳定义(见这里)。他说:

我们通过计算置换特征后模型预测误差的增加来衡量特征的重要性。如果打乱某个特征的值会增加模型误差,则该特征是“重要的”,因为在这种情况下,模型依赖于该特征进行预测。“如果改变某个特征的值而不改变模型误差,则该特征是“不重要的”,因为在这种情况下,模型在预测中忽略了该特征。”

鉴于此,我们可以看到决定价格的三个最重要的特征是年份、驱动(如果是前轮驱动的话)里程表。特性重要性是向非技术人员合理化和解释您的模型的好方法。如果您需要降低维度,它对于特征选择也非常有用。

我的项目到此为止!我希望这能激励那些想进入数据科学的人真正开始。请在评论中让我知道你将来还想看到哪些有趣的项目:)

更多类似的文章,请查看 https://blog.datatron.com/的

感谢阅读!

如果你喜欢我的工作,想支持我…

  1. 支持我的最好方式就是在媒体T2 上关注我。
  2. 推特 这里成为第一批关注我的人之一。我会在这里发布很多更新和有趣的东西!
  3. 此外,成为第一批订阅我的新 YouTube 频道 这里
  4. LinkedIn 这里关注我。
  5. 在我的邮箱列表 这里报名。
  6. 查看我的网站,terenceshin.com

iPad Pro 的机器学习工作流程

原文:https://towardsdatascience.com/a-machine-learning-workflow-for-the-ipad-pro-bc640eead25a?source=collection_archive---------11-----------------------

iPad 是一个革命性的设备。我带着它记下所有的笔记,阅读注释论文,并在上面进行大部分的概念头脑风暴。但是机器学习应用怎么样?在今天的帖子中,我们将回顾一组有用的工具&探索 iPad Pro 的爱情故事&新的 Raspberry Pi (RPi)。之后,您将能够建立自己的“迷你”ML 工作流程,了解 ML 定制的应用环境&开始将 RPi 设置为 iPad 驱动的 USB-C 设备。更具体地说,我们将讨论我如何在日常研究中集成一组有用的应用程序,我如何开始使用 iPad & RPi,以及如何使用 iPad 在远程服务器上运行更大的计算任务。所以让我们开始吧!

iPad Pro 是我最好的金融投资之一。它主要是为需要直观高效工作流程的多媒体创意人员设计的。这包括艺术家、创作者和媒体编辑。不一定是喜欢编程的人。就在最近,苹果一直在推动 iPad Pro 成为独立的电脑替代品。最大的进步是 USB-C 端口,它允许同时充电和数据交换。结合新的 iPadOS 我们可以开始梦想&实验。此外,最近应用程序的更新和新的推出为代码 savy peepz 带来了过多的可能性。以下是我最喜欢的一些:

笔记&论文注释与显著性&生成✏️

诉讼中的知名度

我用大部分“iPad 时间”阅读论文,在会谈或项目头脑风暴会议上做笔记。有许多选项允许你这样做。我个人真的很喜欢 T2 的知名度。这是非常灵活的,同时在它的设计最小化。我非常欣赏的一个功能是裁剪文本片段的简易性 &你可以流畅地包含来自演示文稿/白板/在线搜索的图片。完成写作后,或者如果你想分享你的笔记,你可以将它们导出到任何云存储中,或者通过隔空投送/电子邮件来分享。这使得协作变得超级容易!我还为所有的可视 ml 注释使用了 Notability(查看)。最后,一个我没有充分使用(但应该使用)的功能是录音&回放笔记。知名度允许你在写作的时候记录。之后,您只需按下 play,就可以在再次收听音频的同时获得笔记创建过程的视频形式。您可以“轻敲”笔记,音频时间线将自动跳转到写作时正在录制的音频。很漂亮,对吧?

让我们用生育创造一些艺术

如果我想更艺术一点,我喜欢选择生育。有时候,让自己沉浸在绘画的一些细节中真的很放松(有时候我在想,星期天是不是为“人类创造的极致”)而生的)。我最近的博客缩略图在《生育》中有插图。对于艺术家(和艺术爱好者)来说,生殖是一个“严肃”的应用🤗)并有大量的功能来调整颜色,绘画风格,画布&等等。我不得不承认——最初选择的数量有点多。这就是万维网拯救我的地方。YouTube 上有很多很棒的教程。即使你不是最擅长绘画的人(我肯定不是), Procreate 也有一套工具来支持你(线捕捉,不同的图层,等等)。).我真正喜欢的是镜像选项,它让每一个小涂鸦看起来都像一个书法大师的作品(也许我在这里有点夸张)。

使用 blink.sh ️连接到远程机器👀

很多时候,当我参加会议时,我不想带着笔记本电脑,因为我知道我不会有太多的时间专注于项目。但是我仍然可能运行一些任务或者测试一些超参数直觉。在这种情况下,我只需要某种方式进入我的远程机器,这样我就可以监视正在发生的事情,并根据需要启动新的作业。这就是 blink.sh 的用武之地。

在 blink.sh 中添加远程主机

Blink 是一个 Mosh(移动外壳)应用程序,可以让你顺利地进入你选择的任何远程机器。Blink 允许您为您的ssh服务器设置多个主机&快捷方式。我已经为一个小型 AWS EC2 实例、我的实验室集群和我的 Raspberry Pi 设置了几个组件(稍后会详细介绍)。给我一个 LTE 连接,我可以从任何地方登录到主机,而无需设置热点。一旦你登录了(并且掌握了一个终端模拟器,比如[tmux](https://gist.github.com/andreyvit/2921703) / [screen](https://gist.github.com/jctosta/af918e1618682638aa82))你就已经把普通 Linux 操作系统的所有远程功能移植到 iPad 上了!

我用 blink.sh 设置的例子

我需要告诉你 Blink 还有一个很棒的特性:使用外部显示器和多个 Blink 窗口。你所要做的就是通过 USB-C 将你的 iPad 连接到一个外部显示器上。虽然通常外部显示器会与你的 iPad 同步,但 Blink Shell 会自动在外部显示器上投影第二个窗口,这样你就可以充分利用你的设置。然后,您可以使用cmd + o在闪烁窗口之间轻松切换,并使用远程tmux会话& ctrl + b + arrows在闪烁窗口内切换。对我来说,这个功能非常重要,它让我觉得我可以在列车上完成较小类型的任务之间无缝切换,在办公室类型的环境中切换到更严肃的工作。

Blink 的设计是最小化的,它专注于 mosh/ssh 服务。下面是一些我期待被整合(或者可能还没有发现)的东西:

  • 分割闪烁窗格:有时你想同时登录两台独立的机器。眨眼没问题。但是你必须创造一个新的眨眼“窗口”&在它们之间移动。相反,我想把当前窗口分成多个窗格。
  • 一种直接在 iPad 上编辑文件的方法&与 iPadOS 文件系统集成。
  • 一些简单的方法可以将 iPad 上的文件同步到远程机器上&反之亦然。

使用 Kodex & WorkingCopy 进行编辑和版本控制💾

如果我想在 iPad 上本地编码,这通常包括 4 个主要步骤:

使用工作副本进行版本控制

  1. 使用版本控制应用 WorkingCopy 从我的 GitHub 本地克隆一个库。
  2. 使用免费的& awesome Kodex 编辑器在本地编辑必要的文件。
  3. 使用本地 IDE(例如 Pythonista3Juno for Jupyter——见下文)测试代码,或者在使用scp复制文件后远程测试代码。
  4. commitpush使用 WorkingCopy 将编辑内容再次返回到您想要的存储库分支。

WorkingCopy 允许您将 iPad 与 GitHub 帐户连接起来,并提供所有可能需要的版本控制功能。另一方面,Kodex 是 iPad 的文本编辑器,它支持几乎所有编程语言的 linter 工具。你可以直接从你的云存储(Dropbox 等)中编辑文件。)或 iPad 本地。Kodex 和 WorkingCopy 都是免费的!

使用 Juno Connect 连接到 Jupyter 服务器📶

所以让我们回顾一下到目前为止我们已经涉及的内容:文书工作和艺术类的东西,连接到远程机器&编辑/管理基于代码的项目。我们遗漏了什么?没错,每个数据科学家最喜欢的应用程序——Jupyter 笔记本——下面是如何在 iPad 上使用 Jupyter:Juno 应用程序集合为我们提供了两个选项来设置/连接 Jupyter 服务器&在 iPad 上本地或远程使用笔记本:

  1. Juno for Jupyter :本地版可以让你直接在 iPad 上运行笔记本。您可以通过标准的 PyPi 存储库安装软件包。从那以后,你可以自由地制作原型。注意:在你的 iPad 上拥有一个完整的“迷你”环境可能会有所帮助,但我个人更喜欢在没有任何互联网连接的情况下通过 Raspberry Pi 运行东西(见下文)。
  2. Juno Connect for Jupyter :我真正的全明星是 Juno Connect。connect-version 使得通过隧道连接到任何转发远程 jupyter 服务器的端口变得非常简单。这是通过在您的远程机器上使用jupyter notebook --ip 0.0.0.0 --port 8899 --no-browser启动和暴露 jupyter 端口来完成的。

用户界面和笔记本呈现如下所示:

通过 Juno 轻松实现远程服务器连接

我在 Juno 中缺少的并且希望在未来看到的是 Jupyter Lab 的功能,它包括对系统外壳的支持以及其他 T2 的优秀扩展。Jupyter Lab(与普通的 Jupyter 笔记本相比)我最喜欢的功能之一是内置的终端多路复用器,它允许你在命令行和笔记本编辑之间轻松切换。

iPad Pro +树莓 Pi 型号 4B = ️🧡

iPad Pro 本身没有完整的操作系统,也不应该被认为是一台计算机🤖。

尽管苹果声称 64 位 A12X/A12Z 仿生芯片比许多 Windows 电脑都快,但它们的性能是针对渲染/4K 编辑/游戏等图形操作进行优化的,而不是针对运行 Python 代码。这就是树莓派的用武之地。新的四核 RPi 型号 4 有几个不同的版本(1/2/4 GB) RAM,最重要的是有一个 USB-C 连接,可以同时供电和交换数据。它不比一包香烟大🚬&可以轻松连接到 iPad Pro。那么这种设置的主要好处是什么呢?

  1. 您可以随时随地构建小型应用程序的原型。
  2. 你有一个扩展(和美化)的加密狗。RPi 有一组 USB 2.0 和 3.0 端口以及一个音频插孔。
  3. 通过 Raspbian Buster/Linux 环境,您可以获得更流畅的 git/版本控制支持。
  4. 您不再依赖稳定的互联网连接来登录远程服务器。
  5. 您可以安装外部固态硬盘/存储器,以便与 iPad 交换更大的文件,并随时进行备份。

那么,我们如何让这个工作?

设备,设备⚒️ -我们需要什么?!

那么,我目前使用的配料是什么呢?下面是一个简短的列表:

工具,工具,工具

  1. 带有 USB-C 的 iPad Pro 第 3 代(或更高版本)
  2. RaspberryPi Model 4 又带 USB-C。有许多入门包以合理的价格为您提供入门所需的一切。
  3. 一套基本的 RPi 基础,包括一个微型 SD 卡,一些散热器和一种保持 Pi 冷却的方法(用于 CPU 的迷你超频)。
  4. 一根 USB-C 转 USB-C 线,可以给 RPi 充电,我们将用它来连接 iPad 和 RPi。请注意,RPi 并不支持所有 USB-C 电缆。我用的是 Anker 的电缆。
  5. 初次启动时将 RPi 连接到屏幕的方法(例如微型 HDMI 电缆)。
  6. 快速外置固态硬盘,可交换文件和数据。(我用的是 500 的三星 T5
  7. 蓝牙兼容鼠标。(我用的是罗技 MX Master 2 。)
  8. 额外的 RPi 小工具和扩展,如传感器和摄像头。

最后三个都是可有可无的可以平滑掉的体验。

设置树莓 Pi 的步骤🍓

  1. 下载一个刷新操作系统镜像的工具(例如 Etcher )。
  2. 下载一个 Raspbian Buster 图像并将其刷新到 Pi 的微型 SD 上。然后,插入 Pi 的 Micro-SD 插槽(在板的背面)。
  3. 将 Raspberry Pi 放入机箱中,连接散热器和风扇(使用引脚 4 和 6)。
  4. 启动 Pi 并设置新密码。之后,您可以将您的 RPi 连接到互联网
  5. 设置 Miniconda 3(例如使用这些指令)。
  6. 按照这些说明将 Pi 设置为 USB-C 设备。

注意正确的最终指令应该加上sh /root/usb.sh to /etc/rc.local

如果您可以使用外部显示器来检查一切是否都如您所愿,那么第一步就容易多了。

设置 iPad Pro 的步骤📱

此时,您已经准备好在 iPad 上运行所有内容:

  1. 下载一个 shell 客户端。比如我最喜欢的 Blink shell。
  2. 通过 USB-C 将 Raspberry Pi 连接到 iPad。此时,Pi shoot 检测到电源并开始启动。这可能需要 30 秒。
  3. 转到设置,检查是否有一个新的“以太网”标志,并确保检测到 Pi。如果没有,请确保将 RPi 设置为 USB-C 设备的第 6 步成功完成!
  4. 转到您的 iPad shell,通过ssh pi@10.55.0.1SSH 到 Pi,这是我们之前设置的静态 IP。然后,您应该能够使用您的 RPi 用户名和密码登录。

您应该第一次登录 RPi,现在我们可以更深入地了解了。完整的 RPi-iPad 设置如下所示:

⎘接下来要做的事情

您已经完成了&现在可以开始根据您的需求定制所有功能了!我最初的一些步骤包括:

  • 通过创建 iPad 热点并自动将 RPi 连接到您的 WiFi 来设置 LTE 使用。为此,我使用了一个捷径(见最后一节的交易技巧)。
  • 安装 Jupyter 并使用 Juno 软件包创建工作环境。
  • 在 Blink shell 中设置主机,并开始在其他远程机器上工作。
  • 熟悉使用tmuxscreen操作多个终端面板。
  • 熟练使用基于命令行的编辑器,如vimnano进行编辑。

根据我的经验,RPi 不会从 iPad 吸取太多能量。在没有任何电源的情况下,iPad 充满电可以让我使用大约 5 个多小时的 RPi(在中等计算和主动风扇的情况下)。这通常对我来说已经足够了。有两个 USB-C 端口的 USB-C 适配器可能会派上用场。这样你就可以给 iPad 充电,同时给 RPi 供电。

计算,计算,计算📈

至此,我们已经讨论了使用 iPad 进行科学计算的两种主要方式:

  1. 使用一个远程服务器,并使用 Blink.sh 将ssh加入其中。
  2. 使用 Juno Connect 作为移植 Jupyter 服务器的便捷方式。

现在我们有了更多的选择:

如前所述,Juno 还允许您连接到运行在 RPi 上的笔记本电脑。为此,您只需在 RPi 上设置 Miniconda(Python > = 3.6),然后再次运行带有端口转发的无浏览器笔记本进程。而且你甚至不需要任何网络连接!

使用外部固态硬盘管理文件,scp & Netatalk

RPi 的优势之一是随身携带一个增压适配器加密狗🤓这让你可以更好地利用 iPad 的单个 USB-C 端口,并开辟了在 RPi 和 iPad 之间交换文件的可能性。我做的第一件事就是在 RPi 上安装一个固态硬盘,并在启动时自动完成这个过程。这允许您在 RPi &上探索更大的数据集,以便随时随身携带我的主笔记本电脑的备份。此外,iPad 的文件系统允许我们轻松地将 RPi 中的文件下载到 iPad 或任何电脑上

使用新的 iPadOS 快捷方式应用程序来顺利整合事情。

在启动和设置 RPi 时,以及更一般的日常活动中,快捷方式非常方便。以下是我最喜欢的几个:

  1. 通过 TechCraft 的快捷方式关闭 RPi
  2. 通过 TechCraft 的快捷方式连接 RPi 和 WiFi
  3. Jason Snell分享文件尺寸缩小的图像

使用 ngrok 监控远程 Tensorboard 环回地址

使用 ngrok 查看张量板

另一个很酷的通用工具是 ngrok 。ngrok 允许您从公共 URL 访问本地服务器。正如 public 这个词可能已经说明的那样,安全性不一定得到保证,可能需要您做出一些额外的努力。我主要使用 ngrok 来隐式转发一个端口,我用它来简单地监视 tensorboards。原因是我还没有找到一种方法可以单独在 blink shell 中实现这一点。注册&安装 ngrok 后,您必须在您的 ngrok 配置中添加一个认证 id,然后 tensorboard 端口转发就像下面这样简单:

  • 在远程机器的端口上启动 tensor board:tensorboard --logdir experiments/tboards/ --port 6006
  • 将端口暴露给公共 URL(也来自远程机器):./ngrok http 6006

ngrok 会将您的本地主机实例转发到一个扩展名为.ngrok.io的 web URL。无论你在哪里,你都可以渴望学习曲线。

哇,这是相当多的文本和图像。但是仍然有太多的东西需要讨论(例如,Bear 的 markdown 编辑)。将来,我期待在一组 rpi 上建立一个小型 Kubernetes 集群。目前我对它没有任何用处,但这将是一次很好的(也不太昂贵的)学习经历——因为我对分布式计算知之甚少。此外,我很想让 JAX 参加 RPi。截至目前,有一个未解决的问题来创建类似于如何将 TensorFlow 安装在 RPi 上的臂轮。CPU 的加速真的可以促进我的一些移动深度学习项目。

一些最后的公共服务公告:

👉鼓舞人心的道具去了 Rob 的(不是另一个)YouTube 频道 TechCraft 。他有一个很棒的视频是关于用 iPad Pro 驱动一个普通的 RPi 设置。看看吧!

👉大多数应用程序和设置都是要花钱的。我一直相信投资教育和工具能让我最有效率。但是你可能会有不同的想法或者处于不同的位置。这没关系。对于我在这篇博客中提到的大多数事情,都有免费的替代方案&你不需要苹果平板电脑来创建类似的工作流程。

👉我没有因为写这篇博客而从应用公司、苹果或任何人那里得到任何报酬/收益(从来没想过我会写这篇文章)。我只是喜欢分享我喜欢的东西,让我的生活更轻松。

对你的新设置满意的工具,

抢劫

附:让我( @RobertTLange )知道我是否错过了你最喜欢的工具!

原载于 2020 年 5 月 23 日https://roberttlange . github . io

一台机器预测了我的下一句话

原文:https://towardsdatascience.com/a-machine-predicts-my-next-sentence-d5a0767b6233?source=collection_archive---------61-----------------------

使用 Docker 和 TensorFlow 通过 RNN 生成文本

亚历山大·奈特Unsplash 上的照片【1】

目录

  1. 文本生成
  2. 码头工人
  3. 张量流
  4. 资料组
  5. 密码
  6. 摘要
  7. 参考

文本生成

文本生成属于数据科学的一个分支,即自然语言生成或通常称为 NLG。自然语言处理(NLP)使用库来清理、转换、变换并最终操纵文本,而 NLG 则努力从过去的数据中创造新的文本。

其中一个突出的例子是聊天机器人。它使用各种不同类型的算法来模仿以前的文本,以产生一个用户认为(在某种程度上)他们正在与人而不是机器交谈的响应。这一代文本不仅很棒,而且也很有用,因为它可以自动完成手工操作。

码头工人

Docker【2】利用虚拟化,利用容器来开发和传播软件。容器包含那些已配置的文件和库。在这个例子中,docker 文件中使用的信息有几个主要方面:中的公开工作目录复制入口点。运行完所有必要的建模代码后,tensor flow列出了 3 个步骤来运行您的第一个生产文本生成器,如下所示:

  • 建设

docker build -t tf-text-generator .

  • 奔跑

docker run --rm -p 8080:8888 tf-text-generator

  • 试验

curl -d '{"text" : "ROMEO:"}' -H "Content-Type: application/json" -X POST [http://127.0.0.1:8080](http://127.0.0.1:8080)

张量流

TensorFlow 是一个免费、易用的软件库,有助于建立机器学习模型(包括数据科学和深度学习模型)。它的主要应用之一是神经网络。在tensor flow【3】提供的例子中,许多聪明的、富有灵感的作者合作开发了一个文本生成器,它可以被克隆并在你的本地桌面上执行。

资料组

使用的数据集是莎士比亚作品片段的汇编。对于自己的版本,可以使用任意。txt文件,只要您在模型类中定义了变量 pathname,如下所示[3]:

text = open(your_text_path, ‘rb’).read().decode(encoding=’utf-8')

密码

例子的代码可以在 TensorFlow 的网站上找到。这个函数只是整个管道的一部分,但它是文本生成最突出的地方[3]:

def generate_text(model, start_string):
  # Evaluation step (generating text using the learned model)

  # Number of characters to generate
  num_generate = 1000

  # Converting our start string to numbers (vectorizing)
  input_eval = [char2idx[s] for s in start_string]
  input_eval = tf.expand_dims(input_eval, 0)

  # Empty string to store our results
  text_generated = []

  # Low temperatures results in more predictable text.
  # Higher temperatures results in more surprising text.
  # Experiment to find the best setting.
  temperature = 1.0

  # Here batch size == 1
  model.reset_states()
  for i in range(num_generate):
      predictions = model(input_eval)
      # remove the batch dimension
      predictions = tf.squeeze(predictions, 0)

      # using a categorical distribution to predict the character returned by the model
      predictions = predictions / temperature
      predicted_id = tf.random.categorical(predictions, num_samples=1)[-1,0].numpy()

      # We pass the predicted character as the next input to the model
      # along with the previous hidden state
      input_eval = tf.expand_dims([predicted_id], 0)

      text_generated.append(idx2char[predicted_id])

  return (start_string + ''.join(text_generated))

两个参数是模型start_string ,一旦 docker 映像被构建、运行和测试,就可以在您的终端中执行,它将返回您生成的文本。在这段莎士比亚对话中,马歇斯生成的文本或句子的输出是[3]:

MARCIUS:
How do thou wast forced;
The endempily east enought than whence, or, bear
headed me aple, to-morrow why I rue,
My own brothers on't, but stins abbooon of
so sours; or ghinf purnicy in base as as
Two kings at my heart?

摘要

提供的代码是实现 TensorFlow 众多令人印象深刻的功能的好方法。它被存储和开发以容易地产生简单和强大的模型。为了使这个过程更加个性化,修改文本文件当然会得到不同的生成文本,但是模型中的参数也可以通过反复试验来调整,这样您就可以制作自己的生成文本的机器。

参考

[1] A .奈特, Unsplash ,(2020)

[2] Docker, Docker (2020)

[3]张量流,张量流,(2015)

  • 致谢:
Martín Abadi, Ashish Agarwal, Paul Barham, Eugene Brevdo,
Zhifeng Chen, Craig Citro, Greg S. Corrado, Andy Davis,
Jeffrey Dean, Matthieu Devin, Sanjay Ghemawat, Ian Goodfellow,
Andrew Harp, Geoffrey Irving, Michael Isard, Rafal Jozefowicz, Yangqing Jia,
Lukasz Kaiser, Manjunath Kudlur, Josh Levenberg, Dan Mané, Mike Schuster,
Rajat Monga, Sherry Moore, Derek Murray, Chris Olah, Jonathon Shlens,
Benoit Steiner, Ilya Sutskever, Kunal Talwar, Paul Tucker,
Vincent Vanhoucke, Vijay Vasudevan, Fernanda Viégas,
Oriol Vinyals, Pete Warden, Martin Wattenberg, Martin Wicke,
Yuan Yu, and Xiaoqiang Zheng.
TensorFlow: Large-scale machine learning on heterogeneous systems,
2015\. Software available from tensorflow.org.

基于 TF-IDF 和 k-NN 的大麻推荐系统

原文:https://towardsdatascience.com/a-marijuana-recommendation-system-using-tf-idf-and-k-nn-bd472242cb3f?source=collection_archive---------26-----------------------

使用 NLP、TF-IDF、k-NN、Pickling 和 Dash 的内容推荐系统

基于内容的推荐系统利用用户提供的数据为用户生成推荐。推荐系统可以用于为用户个性化信息,并且通常用于推荐电影、书籍、餐馆以及其他产品和服务。

使用下面的大麻推荐系统或此处的链接,我们将使用用户选择的效果和口味从 2300 多种大麻品种中推荐五种大麻品种。在我们的例子中,产品是大麻,特征是效果和味道的列表。

点击此处查看大麻推荐系统网页 App

该项目的所有代码、数据和相关文件都可以在 my GitHub 访问。自述文件提供了 repo 目录和文件的详细信息。

采用 k-NN 的 TF-IDF 模型

TF-IDF 指术语频率-逆文档频率。TF 就是一个单词在文档中出现的频率。IDF 是整个文档语料库中的文档频率的倒数。TF-IDF 背后的思想是在确定一个项目(文档)的重要性时抑制高频词的影响。

k-NN 指的是 K 最近邻,是一种简单的算法,在我们的例子中,它基于相似性度量对数据进行分类。换句话说,它为我们的用户输入选择“最接近”的匹配。

让我们使用 tf_knn.ipynb 笔记本浏览一个示例。基本步骤是:

  1. 加载、清理和争论数据
  2. 对要素进行符号化和矢量化
  3. 创建文档术语矩阵(DTM)
  4. 将最近邻模型拟合到 DTM
  5. 从模型中获取建议
  6. 泡菜 DTM 和矢量器

加载、清理和整理数据

大麻品种数据来自 Kaggle 的 LiamLarsen 的大麻品种数据库。数据被加载到数据帧中,带有 nans 的菌株被删除(少量< 70),效果和风味特征被合并到一个标准特征中。

df = pd.read_csv(“[https://raw.githubusercontent.com/JimKing100/strains-live/master/data/cannabis.csv](https://raw.githubusercontent.com/JimKing100/strains-live/master/data/cannabis.csv)")
df = df.dropna()
df = df.reset_index(drop=True)
df[‘Criteria’] = df[‘Effects’] + ‘,’ + df[‘Flavor’]

原始数据

对特征进行符号化和矢量化

效果和风味特征非常清晰,由 16 种独特的效果和 50 种独特的风味组成。我们在 TfidVectorizer 中使用了默认的标记器来标记特征,但是如果我们想从大量的文本描述中提取特征,我们可能会使用自定义的标记器。然后我们实例化矢量器。

tf = TfidfVectorizer(stop_words=’english’)

创建文档术语矩阵

特征(标准)然后被矢量化(拟合/转换)成文档术语矩阵(dtm)。dtm 是一个矩阵,每个要素在一列中,每个“计数”在每一行中。该计数是 tf-idf 值。下图显示了矢量化矩阵。

dtm = tf.fit_transform(df[‘Criteria’].values.astype(‘U’))
dtm = pd.DataFrame(dtm.todense(), columns=tf.get_feature_names())

文档术语矩阵(dtm)

拟合最近邻模型

然后实例化最近邻模型,并且 dtm 适合该模型。这是我们用来选择前五名推荐的推荐模型。

nn = NearestNeighbors(n_neighbors=5, algorithm=’ball_tree’)
nn.fit(dtm)

获得推荐

理想应变测试数据变量代表用户期望的 8 个特征。前五个特征是效果,后三个特征是味道。然后将变量矢量化,并在模型中运行。结果以数组元组的形式返回。为了获得这些值,首先访问第 2 个元组,然后访问第 1 个数组,最后访问第 1 个值— results[1][0][0]。在这种情况下,它返回索引 0。“应变”的值为“100-Og ”,并且“标准”与用户特征完全匹配。第二个示例是 index 1972,它的应变值为“日晒伤”,匹配 8 个特征中的 6 个。这些推荐非常符合用户的特点!

ideal_strain = [‘Creative,Energetic,Tingly,Euphoric,Relaxed,Earthy,Sweet,Citrus’]
new = tf.transform(ideal_strain)
results = nn.kneighbors(new.todense())df[‘Strain’][results[1][0][0]]
#’100-Og’
df[‘Criteria’][results[1][0][0]]
#’Creative,Energetic,Tingly,Euphoric,Relaxed,Earthy,Sweet,Citrus’df[‘Strain’][results[1][0][1]]
#’Sunburn’
df[‘Criteria’][results[1][0][1]]
#’Creative,Euphoric,Uplifted,Happy,Energetic,Citrus,Earthy,Sweet’

腌制

最后,dtm 和矢量器将在 Dash 应用程序中使用。

pickle.dump(dtm, open(‘/content/dtm.pkl’, ‘wb’))
pickle.dump(tf, open(‘/content/tf.pkl’, ‘wb’))

Dash 应用

由于本文的重点是创建一个基于内容的推荐系统,Dash 应用程序的细节将不在本文讨论之列。有关创建 Dash 应用程序的详细信息,请参阅我的文章 如何创建交互式 Dash Web 应用程序

我欢迎建设性的批评和反馈,请随时给我发私信。

在推特上关注我

这篇文章最初出现在我的网站上

大麻数据来源: 大麻品种大麻数据集来自卡格尔 的利亚姆拉森

图片来源:“free images . com/Gerhard Taatgen Jr .”

卷积神经网络:它与其他网络有何不同?

原文:https://towardsdatascience.com/a-math-free-introduction-to-convolutional-neural-network-ff38fbc4fc76?source=collection_archive---------23-----------------------

内艾

CNN 有什么独特之处,卷积到底是做什么的?这是对 CNN 奇迹的无数学介绍。

我不是深度学习研究人员,但我通过各种接触了解了一些关于神经网络的事情。我一直听说 CNN 是一种神经网络,特别擅长与图像相关的问题。但是,这到底意味着什么呢?卷积这个词是怎么回事?一个与图像相关的问题需要不同的网络,这有什么不寻常的?

最近,我有机会研究新冠肺炎图像分类问题,并使用tensorflow.keras 构建了一个基于 CNN 的分类器,达到了 85%的准确率。最后,我想我已经找到了这些问题的答案。让我用一种没有数学的方式和你分享那些答案。如果你已经熟悉 CNN,这篇文章应该是一个很好的复习。如果没有,看一看,你可以对 CNN 背后的动机和定义 CNN 的独特功能有一个直观的了解。

深度神经网络

在深入研究神经网络之前,我们先来看看机器学习的全貌:

机器学习 (ML)是通过经验自动改进的计算机算法的研究。—维基百科

看看 ML 试图解决的问题,ML 经常被切成

  • 监督学习:预测标签,例如分类或连续变量;
  • 无监督学习:未标记数据的模式识别,例如聚类;
  • 强化学习:算法学习“行为”的最佳方式,例如 AlphaGo、自动驾驶汽车。

其中,深度学习是一种强大的机器学习形式,因其在计算机视觉(例如,图像识别)、自然语言处理等领域的成功而备受关注。神经网络的灵感来自生物系统中的信息处理和通信节点。按照设计,输入数据通过网络的各个层传递,这些层包含几个节点,类似于“神经元”。然后,系统输出信息的特定表示。DNN 可能是最知名的深度学习网络,它可以通过训练很好地学习数据的特征。

粗略来说,组成一个神经网络有两个重要的操作:
1。正向传播
2。反向传播

正向传播

这是预测步骤。网络读取输入数据,通过网络计算其值,并给出最终输出值。

但是网络如何计算输出值呢?让我们看看当单层网络进行一次预测时会发生什么。它将输入作为一个数字向量。层中的每个节点都有其权重。当输入值通过图层时,网络会计算其加权和。这之后通常是(典型的非线性)激活函数,例如阶跃函数,其中加权和被“激活”。

单层感知。来源:感知器。米切尔,机器学习,p87。/ CC BY-SA

如果您对代数有所了解,那么操作是这样进行的:

y = f(**w** • **x**+ **b**)

其中w****x+b为加权和,f 为激活函数,y 为输出。现在,在更深层次的神经网络中,程序本质上是相同的,即输入- >加权求和- >激活过程对许多层重复。

反向传播

这是训练步骤。通过比较网络的预测/输出和实际值,即计算损耗,网络调整其参数以提高性能。

网络如何通过训练调整参数(权重和偏差)?这是通过称为反向传播或反向传播的操作完成的。网络获取损失,并递归计算损失函数相对于每个参数的斜率。计算这些斜率需要使用微积分中的链式法则;你可以在这里了解更多信息

然后使用优化算法利用梯度信息更新网络参数,直到性能不能再提高为止。一种常用的优化器是随机梯度下降。

经常用来解释基于梯度的优化的一个类比是徒步旅行。训练网络使损失最小化就像从山上下到地面的最低点。反向投影运算寻找损失函数梯度就像寻找向下的路径。优化算法是你实际走的路,最终到达最低点的那一步。

来源:雅格布·贝尔托洛蒂/ CC0

我掩盖了许多细节,但我希望你现在知道 DNN

  • 是一种强大的机器学习技术;
  • 可用于解决有监督无监督、强化学习问题;
  • 包括正向传播(输入到输出)和反向传播(误差到参数更新)。

我们准备好谈论 CNN 了!

卷积神经网络

我们上面讨论过的普通神经网络期望输入数据是数字的向量,即x=【x1,x2,x3,…】。如果我们想训练一个图像分类器,即使用一幅图像作为输入,该怎么办?先说一些数字图像基础知识。

  • 一幅图像是像素的集合。例如,32 乘 32 的图像有 32*32 = 1024 个像素。
  • 每个像素是由范围[0,255]中的数字表示的强度,其中 0 是黑色,255 是白色。
  • 彩色图像有三个维度:【宽度、高度、深度】其中深度通常为 3。
  • 为什么深度是 3?那是因为它编码了[ R ed, G reen, B lue]的强度,即 RGB 值。

所以,这张黑白林肯像只是一个整数矩阵。

作者:戈兰·莱文图像处理与计算机视觉

由于数字图像可以表示为像素值的 2D 网格,我们可以拉伸/展平网格,将其转换为数字向量,并将其输入神经网络。那解决了问题…对吗?

然而,这种方法有两个主要限制。

  1. 它不能很好地缩放到更大的图像。
  • 虽然对于 32*32 = 1024 维的输入来说它仍然是可管理的,但是大多数现实生活中的图像都比这大。
  • 例如,大小为 320x320x3 的彩色图像将转换为尺寸为 307200 的输入!

2。它不考虑图像的属性。

  • 位置:附近的像素通常是强相关的(如看到林肯脸部的轮廓)。拉长它会打破这种模式。
  • 平移不变性:有意义的特征可以出现在图像的任何地方,例如,看到飞鸟。

图片信用

卷积的力量

另一方面,CNN 被设计成很好地缩放图像,并利用这些独特的属性。它有两个独特的功能:

  1. 权重共享:图像的所有局部部分都用相同的权重处理,这样可以在许多位置检测到相同的模式,例如水平边缘、曲线等。
  2. 特征层次:将开始时学习的较低层次的模式进行组合,形成跨层的较高层次的模式,例如从边缘到轮廓到面部轮廓。

这是通过卷积的操作完成的:

  1. 定义滤波器:特定大小的 2D 加权矩阵,例如 3 乘 3 滤波器。
  2. 用滤波器对整个图像进行卷积:将滤波器下的每个像素乘以权重。
  3. 卷积输出形成新的图像:特征图。
  4. 使用多个过滤器(每个具有不同的权重矩阵),可以捕获不同的特征。

卷积示例:均值滤波器

其实还是用数字和图像来看操作吧。会更容易理解到底发生了什么。这里我们用 0 和 1 创建了一个明亮的正方形。matplotlib将[0,1]中的值解释为与[0,255]中的值相同。

Original image pixel values: 
 [[0\. 0\. 0\. 0\. 0\. 0\. 0.]
 [0\. 0\. 0\. 0\. 0\. 0\. 0.]
 [0\. 0\. 1\. 1\. 1\. 0\. 0.]
 [0\. 0\. 1\. 1\. 1\. 0\. 0.]
 [0\. 0\. 1\. 1\. 1\. 0\. 0.]
 [0\. 0\. 0\. 0\. 0\. 0\. 0.]
 [0\. 0\. 0\. 0\. 0\. 0\. 0.]]

这是图像的样子:

回想一下,滤波器是一个 2D 加权矩阵。让我们创建一个示例过滤器,并将其命名为“均值过滤器”:

[[0.11 0.11 0.11]
 [0.11 0.11 0.11]
 [0.11 0.11 0.11]]

在卷积中,这种“均值滤波器”实际上会滑过图像,取 9 个相连像素的值,将每个值乘以权重(0.11),然后返回总和,即原始 9 个值的加权平均值,因此称为“均值滤波器”:

您可以从过滤后的图像像素值中看到平均效果。它会模糊图像中的任何边缘。

Filtered image pixel values: 
 [[0.11 0.22 0.33 0.22 0.11]
 [0.22 0.44 0.67 0.44 0.22]
 [0.33 0.67 1\.   0.67 0.33]
 [0.22 0.44 0.67 0.44 0.22]
 [0.11 0.22 0.33 0.22 0.11]]

这和卷积神经网络有什么关系?

CNN 本质上应用了相同的卷积程序,但关键的区别在于通过反向传播(训练)来学习滤波器权重

此外,通常每个图层都有许多滤镜,每个滤镜都有不同的权重矩阵,应用于同一个图像。每个过滤器将捕捉同一图像的不同模式。CNN 也可以有多层卷积。网络的复杂性允许捕捉不同尺度的特征。例如,这是过滤器从网络的早期到后期学习的特征的图示。

  • 早期的滤镜捕捉边缘和纹理。(通用)
  • 后面的过滤器形成部件和对象。(具体)

图片信用

CNN 的主要特点

虽然 DNN 使用许多全连接层,但 CNN 主要包含卷积层。最简单的形式,CNN 是一个由一组层组成的网络,这些层将图像转换成一组类别概率。一些最受欢迎的图层类型有:

  • 卷积层 (CONV):图像经过滤波器的卷积。
  • RELU 层 (RELU):单元式非线性激活函数(与 DNN 之前的相同)。
  • 池层(池):图像经过均值(或最大值)滤波器的卷积,因此它被向下采样。
  • 全连通层 (FC):通常作为最后一层输出一个类概率预测。

现在,如果你是设计自己的 CNN ,有很多元素可以玩。它们通常分为两类:

  1. 卷积层的类型
  • 深度:每层使用的滤镜数量。
  • 步幅:在图像上滑动滤镜时的步幅,通常是 1(见上面的卷积 GIF)或 2。
  • 大小:每个卷积滤波器的大小,例如均值滤波器为 3 乘 3。
  • 填充:卷积时是否在图像周围使用填充。这决定了输出图像的大小。
  • 和其他人。

2.各层如何连接?

除了层的类型,你需要为你的 CNN 设计一个架构。这是一个活跃的研究领域,例如,什么是更好的架构?还是可以自动搜索更好的架构?如果你有兴趣,可以去“神经结构搜索”看看。一个常用的架构是这样的:

**INPUT --> [ [CONV --> RELU]^N --> POOL]^M --> [FC --> RELU]^K --> FC**

幂(N,M,K)意味着操作重复这些次数。

下一步是什么?

谢谢你一直读到最后!我希望到现在为止,你可以看到 CNN 和普通 DNN 的区别,并且对卷积运算有一个直观的理解。请在评论区告诉我你的想法或任何反馈。

在下一篇文章中,我们将探讨如何使用 CNN 来构建一个新冠肺炎 CT 扫描图像分类器。不出所料,一个预先训练好的 CNN 可以达到很强的基线表现(85%的准确率)。然而,要产生可靠和令人信服的结果,需要的不仅仅是一个神经网络。下面是这篇文章:

[## 深度学习需要什么来更好地检测新冠肺炎

这个世界可能不需要另一个神经网络,但它需要与那些在第一线的人进行咖啡聊天。

towardsdatascience.com](/domain-expertise-what-deep-learning-needs-for-better-covid-19-detection-56cdeefde564)

更多资源

如果你有兴趣了解更多关于 CNN 的信息,请查阅👉:

以及如何实现它们👉:

尽情享受吧!👏👏👏

原载于https://yang xiaozhou . github . io

5 分钟 AdaBoost 的数学解释

原文:https://towardsdatascience.com/a-mathematical-explanation-of-adaboost-4b0c20ce4382?source=collection_archive---------9-----------------------

用一个例子彻底解释 AdaBoost

作者创建的图像

目录

  1. 介绍
  2. AdaBoost 有何不同
  3. AdaBoost 工作原理的示例
  4. 如何评估一个新的点

介绍

AdaBoost,或称自适应 Boost,是一种相对较新的机器学习分类算法。这是一个集成算法,它将许多弱学习器(决策树)组合在一起,并将其转化为一个强学习器。因此,其算法利用装袋助推方法来开发增强的预测器。

如果这些词让你感到困惑,不要担心。在本文中,我们将通过一个简单的例子来展示 AdaBoost 的工作原理及其背后的数学原理。

AdaBoost 有何不同

AdaBoost 类似于随机森林,因为预测来自许多决策树。然而,AdaBoost 的独特之处主要有三点:

  1. 首先,AdaBoost 创造了一个树桩森林,而不是树木。树桩是只由一个节点和两片叶子组成的树(如上图)。
  2. 第二,生成的树桩在最终决策(最终预测)中的权重不同。造成更多错误的树桩在最终决策中的发言权会更小。
  3. 最后,生成树桩的顺序很重要,因为每个树桩都旨在减少前一个树桩所犯的错误。

AdaBoost 工作原理的示例

现在我们来看一个例子。假设我们有下面的样本数据,有三个特征(x1,x2,x3)和一个输出(Y)。注意 T =真,F =假。

步骤 1:为每个样品分配样品重量

使用上面的等式,计算每个样品的样品重量。第一轮,样品重量相等。在本例中,每个样品的样品重量将等于 1/6。

第二步:计算每个变量的基尼系数

下一步是计算每个变量的基尼系数。这样做是为了确定使用哪个变量来创建第一个树桩。计算每个节点的基尼系数的公式如下:

一旦你计算出每个节点的基尼系数,每个变量的基尼系数就是每个节点的加权平均值。

举个例子,我们来计算 x2 的基尼杂质。

上面是样本的合并表,显示了适合每个类别的样本数(无论 x2 和 Y 是 T 还是 F)。

接下来,我们可以为 x2 计算每个叶节点的 Gini 杂质。

一旦计算出每个叶节点的基尼系数,就可以通过对两个单独的系数进行加权平均来计算出总的基尼系数。

因此,x2 的基尼系数= 0.25。

如果你对每个变量都这样做,你会得到 x2 具有最低的基尼系数,所以 x2 将被用来创建第一个树桩。

第三步:计算已创建的树桩的发言权

接下来,我们将使用总误差来计算这个树桩获得的“发言权”。

总误差 等于错误分类样本的权重之和。由于其中一个样本被错误地分类为 x2,总误差等于 1/6。

一旦你知道了总误差,你就可以计算出量,比如:

因此对于这个树桩…

步骤 4:计算下一个树桩的新样本权重

接下来,我们将使用以下等式增加错误分类样本的样本权重,并减少正确分类样本的样本权重:

因此,利用上面的等式,我们能够计算新的样本权重。由于样本权重的总和等于 0.84,我们通过将每个权重除以 0.84 来标准化样本权重,使得新样本权重的总和等于 1。

步骤 5:创建一个引导数据集,根据新的样本权重选择每个样本的概率。

在这一步中,我们将从数据集中随机选择 6 个带有替换物的样本,选择每个样本的几率基于它们新的样本重量。

请注意,被错误分类的那一个的权重是其他的两倍多。这意味着它更有可能被选择多次,因此,下一个 stump 将更多地关注正确分类错误的样本。这就是 AdaBoost 的力量!

一旦创建了新的引导数据集,样本将再次被赋予相等的权重,并重复该过程。

步骤 6:重复这个过程 n 次

最后,重复这个过程,直到产生 n 个树桩,每个树桩都有自己的发言权。一旦完成,模型就完成了,可以对新点进行分类。

通过在所有树桩中运行新点并查看它们是如何分类的,可以对新点进行分类。然后,对每一个类的 say 量进行求和,say 量较高的类就是新点的分类。

感谢阅读!

学完本课程后,您应该理解 AdaBoost 模型是如何创建的,并且应该知道它背后的数学原理。

特伦斯·申

创始人ShinTwin|我们连线上LinkedIn|项目组合是 这里

5 分钟内对朴素贝叶斯的数学解释

原文:https://towardsdatascience.com/a-mathematical-explanation-of-naive-bayes-in-5-minutes-44adebcdb5f8?source=collection_archive---------2-----------------------

用一个例子彻底解释朴素贝叶斯

考特尼·库克在 Unsplash 上的照片

朴素贝叶斯。看起来非常令人困惑的算法实际上是曾经被理解的最简单的算法之一。理解和实现它如此简单的部分原因是因为它固有的假设。然而,这并不是说它是一个糟糕的算法,尽管它拥有强大的假设-事实上,朴素贝叶斯在数据科学领域中被广泛使用,并有很多现实生活中的应用。

在本文中,我们将了解什么是朴素贝叶斯,它如何通过一个例子来使其易于理解,朴素贝叶斯的不同类型,优点和缺点,以及它的一些实际应用。

初步知识

为了理解朴素贝叶斯并从本文中获得尽可能多的价值,您应该对以下概念有一个基本的了解:

  • 条件概率:一个事件 A 发生的概率的量度,假设另一个事件已经发生。例如,“假设天气多云,下雨的概率有多大?”是条件概率的一个例子。
  • 联合概率:计算两个或更多事件同时发生的可能性的度量。
  • 比例:指的是与一个常数相乘的两个量之间的关系,或者更简单的说,它们的比值是否产生一个常数。
  • 贝叶斯定理:根据维基百科,贝叶斯定理描述了一个事件发生的概率(后验),是基于可能与该事件相关的条件的先验知识。

什么是朴素贝叶斯?

朴素贝叶斯是一种机器学习算法,但更具体地说,它是一种分类技术。这意味着当输出变量是离散的时,使用朴素贝叶斯。该算法的底层机制是由贝叶斯定理驱动的,您将在下一节看到这一点。

朴素贝叶斯是如何工作的

首先,我将介绍朴素贝叶斯背后的理论,然后用一个例子来巩固这些概念,使其更容易理解。

朴素贝叶斯分类器受贝叶斯定理的启发,贝叶斯定理陈述了以下等式:

这个等式可以用 X(输入变量)和 y(输出变量)改写,使其更容易理解。用简单的英语来说,这个方程就是在给定输入特征 x 的情况下求解 y 的概率。

因为假设变量是独立的,我们可以将 P(X|y)改写如下:

此外,由于我们求解 y,P(X)是一个常数,这意味着我们可以将其从等式中删除,并引入一个比例。这使我们得出以下等式:

现在我们已经得到了这个等式,朴素贝叶斯的目标是选择具有最大概率的类 y。Argmax 是一个简单的操作,它从目标函数中找到给出最大值的参数。在这种情况下,我们希望找到最大的 y 值。

现在让我们来看一个例子,这样你可以从这个算法中得到更多的意义。

朴素贝叶斯的例子

假设你跟踪了 14 天的天气状况,根据天气状况,你决定是否打高尔夫球。

首先,我们需要把这个转换成频率表,这样我们就可以得到 P(X|y)和 P(X)的值。回想一下,我们正在求解 P(y|X) :

其次,我们希望将频率转换成比率或条件概率:

最后,给定 x,我们可以使用比例方程来预测 y。

想象一下,X = {展望:晴天,温度:温和,湿度:正常,有风:假}。

首先,我们将计算给定 X,P(是|X)你将打高尔夫球的概率,然后是给定 X,P(否|X)你将不打高尔夫球的概率。

使用上面的图表,我们可以获得以下信息:

谢谢各位的评论。上面我已经做了修正。

现在我们可以简单地将这些信息输入到下面的公式中:

类似地,您将为 P(no|X)完成相同的步骤序列。

既然 P(yes|X) > P(no|X),那么你可以预测这个人会打高尔夫球,因为天气晴朗,温度适中,湿度正常,没有风。

TLDR

综合我们刚刚做的…

  1. 首先,我们创建了一个频率表,然后创建了一个比率表,这样我们就可以得到 P(X)和 P(y|X)的值
  2. 然后,对于给定的一组输入要素 X,我们计算每个类 y 的比例 P(y|X)。在我们的示例中,我们有两个类,是和否。
  3. 最后,我们取所有类中 P(y|X)的最高值来预测最有可能的结果。

朴素贝叶斯的类型

实践中使用的朴素贝叶斯主要有三种类型:

多项式

多项式朴素贝叶斯假设每个 P(xn|y)遵循多项式分布。它主要用于文档分类问题,查看单词的频率,类似于上面的示例。

伯努利

伯努利朴素贝叶斯类似于多项式朴素贝叶斯,只是预测值是布尔型的(真/假),就像上面示例中的“Windy”变量一样。

高斯的

高斯朴素贝叶斯假设连续值是从高斯分布中采样的,并假设如下:

朴素贝叶斯的利与弊

赞成的意见

  • 如上所示,一旦你理解了这个概念,它就相当直观了
  • 它易于实现,在多类预测中表现良好
  • 它适用于分类输入变量

骗局

  • 当测试集中有一个类别不在训练集中时,您可能会遇到零频率问题
  • 从这个算法来看,概率估计不是最值得信赖的
  • 如上所述,朴素贝叶斯有很强的假设。

朴素贝叶斯应用

下面是朴素贝叶斯的一些流行应用:

  • 实时预测:因为朴素贝叶斯速度快,而且基于贝叶斯统计,所以它在实时预测方面做得很好。事实上,很多流行的实时模型或在线模型都是基于贝叶斯统计。
  • 多类预测:如前所述,当输出变量有两个以上的类时,朴素贝叶斯工作得很好。
  • 文本分类:文本分类还包括垃圾邮件过滤和情感分析等子应用。由于朴素贝叶斯最适合处理离散变量,因此它在这些应用程序中也能很好地工作。
  • 推荐系统:朴素贝叶斯通常与其他算法一起使用,如协同过滤,以建立推荐系统,如网飞的“为你推荐”部分,或亚马逊的推荐产品,或 Spotify 的推荐歌曲。

感谢阅读!

特伦斯·申

创始人ShinTwin|我们连线一下LinkedIn|项目组合这里是

压缩的数学入门

原文:https://towardsdatascience.com/a-mathematical-primer-of-compression-5ea1ca53fc45?source=collection_archive---------29-----------------------

如何在不丢失信息的情况下减少存储空间?

阿列克谢·鲁班在 Unsplash 上的照片

由于我对音乐感兴趣,它经常出现在一个日益增长的趋势中:音乐以数字和黑胶的形式出售。有时我会听到人们错误地称黑胶潮流为“复古”、“新潮”、“时髦”或其他什么。但是如果你真的问别人为什么他们更喜欢唱片,他们可能会告诉你音质更好。

这将是一篇关于无损压缩的文章,我会尽量保持一般概念或例子。

先说术语。首先,媒体文件可能很大。在我年轻的时候,计算机基本上没有无限的空间,所以压缩是减小媒体文件大小的一个重要工具。就在那时,我迷上了这个话题。

压缩 基本上是一种获取文件大小并使其变小的算法。最明显的方法是 有损压缩 。这只是意味着你丢失了信息。这种算法的目标是只丢失“不重要”和“不会被注意到”的信息。

一种更令人惊讶的压缩方法叫做 无损 。起初,这似乎是矛盾的。如何使文件变小,但不丢失任何信息?文件大小基本上不就是信息吗?

我们稍后会回答这些问题。

有损压缩

先说大家为什么不喜欢有损压缩音频文件。有一个快速和肮脏的事情,你可以做立即失去信息,并减少音频文件的大小。

这是 动态范围 (DR)压缩。

想象一种声波。振幅基本决定了声音有多大。你可以在不改变任何其他音乐品质的情况下,将声波压缩到更小的振幅。

但这太可怕了!

音乐中最重要的部分之一是高潮部分,如果整个高潮部分的响度相同,那么动人的高潮部分就不会有同样的效果。

这是一种极具争议的压缩技术,以至于许多人纯粹出于灾难恢复的原因转而使用乙烯树脂。有一个完整的、可搜索的在线专辑数据库,可以找到唱片目录,以及它是好的、可接受的还是坏的。

去搜索你最喜欢的专辑。这是一种有趣的发现有多少已经被压扁了,即使在无损光盘格式与乙烯基!(例如,一个唐氏系统的毒性在黑胶上是 DR 11【可接受】,在 CD 上是 DR 6【非常糟糕】)。

另一种最常见的音频有损压缩技术有点复杂,但它实际上改变了音乐,因此值得考虑。让我们实际上做一个粗略的算法来做这件事(目前有更好的和更微妙的形式如下,但它相当于同一件事)。

这是一个有点傻的例子,但是我去了 www.wavsource.com 的得到了一个原始的 wav 文件。我抓住了第一批中的一个,来自电影 2001:太空漫游的音频样本。这是声波的数据可视化:

我们可以做的一件事是快速傅立叶变换。这会把这些声波去掉,去掉时间成分。通常你会想做一个“移动窗口”,这样你就可以记录一些时间。

例如,我们可以看到从 0.5 秒到 1.5 秒是一个“数据包”我们可能应该首先转换它,然后再进行下一步。

FFT 留给我们的只是出现的频率以及它们有多大。我用 python 的 scypy.fftpack 做到了这一点:

import matplotlib.pyplot as plt
import scipy.fftpack as sfft
import numpy as np
from scipy.io import wavfilefs, data = wavfile.read('daisy.wav')
b=[(ele/2**8.)*2-1 for ele in data]
c = sfft.fft(b)
d = len(c)/2
plt.plot(abs(c[:(d-1)]),'r')
plt.show()compressed = []
for ele in c:
	if abs(ele) &gt; 50:
		compressed.append(ele)
	else:
		compressed.append(0)compressed = np.asarray(compressed)
plt.plot(abs(compressed[:(d-1)]),'r')
plt.show()e = sfft.ifft(compressed)

忽略那些只是为了让所有东西都更明显而没有标准化的比例。我们能做的最简单的事情就是设置一个截止频率,去掉所有我们认为听不到的频率:

如果我们做得太多,我们会破坏声音的自然性。所有自然产生的声音都有大量微妙的弦外之音。您通常无法明确听到这些,因此它们会在截止阈值以下出现。

这将把我们带向一个“纯净”的音调,听起来更像是合成的或计算机生成的。这可能就是为什么没有人真正这样压缩的原因。这个例子只是给出了一种方法的概念(要完成它,你现在只需逆 FFT 并写入 wav)。

稍微好一点的压缩技术是采用短时间间隔,并用一个凸起函数乘以峰值频率。这将缩小所有无关的频率,而不会完全消除声音的强度。

这就是一些有损压缩实际上是如何完成的。小波还有其他更有趣的东西,需要几篇文章来描述,但这里的目标是实现无损压缩。

我希望这有助于了解什么是有损压缩,如果不小心的话,它会造成一些严重的伤害。小心的话,你仍然会失去足够的音质,以至于许多音乐爱好者完全避免 mp3 和数字下载,而选择黑胶唱片。

现在让我们来解决无损压缩这个看似矛盾的概念。

无损压缩

我首先要指出的是,即使这个看起来像是一个矛盾的概念,每个人都已经相信这是可以做到的。当我们通过压缩电脑上的文件时,我们一直在使用它。

当然,这会导致文件变小,但是没有人会认为当他们解压缩时会丢失信息。这意味着必须存在无损压缩的方法。

今天的例子是一个非常简单和聪明的方法。它暂时与音乐无关,但不要认为这仅仅是一个玩具例子。 霍夫曼编码 实际上是作为 mp3 编码中的一个步骤使用的,所以和我们一直在讨论的内容有关。

大致思路是这样的。假设你想用最简单的方法将文本编码成二进制。你把 A 分配给 0,B 分配给 1,C 分配给 10,D 分配给 11,等等。当你到 Z 的时候,你会得到 11001。这意味着你必须为每个字母使用 5 位。

“猫”应该是 00010 00000 10011。

为了给“猫”编码,我们做了些蠢事。我们只需要 3 个字母,所以如果我们提前选择了一个更好的编码方法,比如 C = 00,A = 01,T = 10,那么我们可以将文本编码为 00 01 10。

换句话说,我们通过巧妙选择编码 00010 00000 10011 -> 000110 来压缩数据,而不会丢失任何信息。

我已经知道你的抱怨了。任何足够长的文本都将包含每个字母,因此没有比最初的简单方法更好的方法了。嗯,你只是不够聪明!

有些字母会比其他字母出现得更频繁。例如,如果字母“s”出现的频率是 100,而下一个出现频率最高的字母出现了 25 次,那么您应该选择类似“01”这样的字母来代表“s”。这样,最少数量的位被用于最频繁的字母。

啊,但是精明的读者又抱怨了。我们以前不能这样做的原因是,我们无法在一个长字符串中区分两个频繁的字母:10 01 和一个不太频繁的字母:1001。这就是为什么当我们使用整个字母表时,我们需要全部 5 位。

这是一个唯一性问题。我们要解决的是,一旦我们给字符串赋值,就不允许“01”成为它的前缀。这样,当我们遇到 01 时,我们就停下来。我们知道那是字母“s ”,因为没有其他字母以“01”开头。

当然,最终发生的情况是,对于某些字母,我们必须使用比 5 位多得多的位,但我们的想法是,它们的使用频率如此之低,而 2 位和 3 位字母的使用频率如此之高,最终会比我们坚持使用 5 位节省更多的空间。

现在你应该问两个问题:

  1. 可以证明它更小吗?
  2. 有没有什么简单的算法可以计算出如何将一个字母分配给一个比特序列,从而产生唯一性和微小性?

答案:两个都是!

我们不会谈论证据,因为这是一篇“通过例子”的文章,让你感受一下人们在压缩中做的事情的类型。但是我认为生成要编码的符号串的算法非常简洁。

让我们为“Titter Twitter Top”生成 哈夫曼树 (只是为了得到一个高频和几个“重复”频率的东西)。

首先,把字母和它们出现的频率按顺序列出来:(T:7),(I:2),(E:2),(R:2),(W:1),(O:1),(P:1)。

现在我们将构建一个以这些为叶子的二叉树。从底部的 2 个叶开始,用占位符(*)和频率的总和将它们连接到父节点。然后将这个新的占位符插入列表中的正确位置,并删除您使用的两个占位符:

现在对列表底部的两个节点重复这个过程(如果一个节点已经在列表中,在树中使用它):

不断重复这个过程,直到你用尽了列表,你将得到完整的二叉树,我们将使用:

现在,为了找出如何对每个字母进行编码,在每个左边缘写一个 0,在每个右边缘写一个 1。从顶部往下到你想要的字母,按顺序写下数字。这是编码。

所以 T = 1,I = 000,R = 010,E = 011,W = 0011,O = 00101,P = 00100。

自己测试一下吧。你会发现没有歧义,因为用于一个字母的每个数字串从不作为另一个字母的前缀出现。

此外,请注意,出现频率最高的字母是一位,只有当频率变低时,位才会变长。使用霍夫曼码的 Twitter Top 的编码是 39 位,而简单编码是 80 位。

这将压缩到所需空间的一半,并且不会丢失任何信息!

我们不会进入计算机实际上如何存储信息的繁琐细节,以了解我们在实践中忽略了许多微妙之处(加上我们必须将转换表作为数据的一部分存储),但至少我们在理论上看到了无损压缩的例子。

此外,这里的字母也没什么特别的。我们可以用基本上任何信息来做这件事(例如声音文件中的频率或图像中的像素颜色)。

灰度问题:理解 Dicom 窗口

原文:https://towardsdatascience.com/a-matter-of-grayscale-understanding-dicom-windows-1b44344d92bd?source=collection_archive---------17-----------------------

DICOM 图像可以包含大量的体素值,可以将开窗视为操纵这些值的一种手段,以改变图像的外观,从而突出显示特定的结构

作者图片

DICOM 图像通常包含 12–16 位/像素,相当于大约 4,096 到 65,536 种灰度。大多数医学显示器和常规计算机屏幕通常限于 8 位或 256 种灰度。高端医疗显示器可以显示 1024 种灰度(如针对乳房 x 线摄影优化的显示器)。

然而,即使电脑屏幕可以显示 256 种灰度,我们的眼睛通常也只能察觉到灰度的 6% 变化

这意味着我们通常只能探测到大约 100/6 = 17 种灰度。

Hounsfield 单位 ( HU )标度是用于描述放射性密度的定量标度。它采用线性变换,其中标准压力和温度(STP)下蒸馏水的放射性密度定义为 0 HU ,而标准压力和温度下空气的放射性密度定义为 -1000 HU

CT 数的 Hounsfield 标度【图像来源】

大多数图像需要在 -1000 HU (空气的参考值)和 +1000 HU (通常参考硬骨)之间查看。

因此,DICOM 图像的范围大约为 2000 HU (从-1000 HU 到+1000 HU),如果我们想在只能显示 256 种灰度的计算机屏幕上显示这个范围:

2000/256 = 8

那么每个灰色阴影将具有 8 HU 的差异。

人眼只能检测到 6%的灰度变化,因此为了让人类检测到密度的差异(在 2000 HU 的图像范围内),每个变化必须变化:256/17∫8 = 120 HU。正常组织和病变组织之间的差异通常远小于 120 HU,这就是应用windows的重要性。

为了解释windowing如何工作,我们使用这个数据集,导入 fastai 库并加载一个测试映像。

关于如何使用 fastai 的医学成像模块的更多信息,请访问我的[github](https://github.com/asvcode/MedicalImaging) 页面或我的关于医学成像的教程博客(哪个更适合查看笔记本教程:)

查看pixel_array

show_image(patient6.pixel_array, cmap=plt.cm.bone);

作者图片

使用fastai时的区别在于,默认情况下,当使用show功能时,它将显示归一化图像。

patient6.show();

作者图片

很明显,图像中显示了更多的深度。然而,当试图定位那些由于某种情况而发生病理改变的正常区域时,这可能是一个问题。在大多数情况下,正常组织和病理改变组织之间的 Hounsfield 单位的差异可能非常小。

作者图片

归一化图像显示了大范围的组织密度(从-1000HU(空气)到大约+1000HU(骨骼))。如上所述,普通的电脑屏幕只能显示 256 种灰度,我们的眼睛只能推断出 6%的灰度变化

应用windows的基础是将 256 种灰度聚焦到一个包含我们可能感兴趣的相关组织密度的狭窄区域。

Fastai 的内置窗户

fastai 医学影像库方便地提供了多个窗口范围,可通过其windowed功能使用。可以使用dicom_windows调用这些窗口

Fastai 医学影像【信用】

窗口是如何工作的?

一个窗口有两个值:

  • window levelcenter,又称亮度,l
  • window widthrange,又称对比、w

使用以下公式计算窗口像素值:

  • lowest_visible_value =窗位-窗宽/ 2
  • highest_visible_value =窗位+窗宽/ 2

以脑窗为例:它的window width为 80,window level为 40。

  • lowest _ visible _ value =40—(80/2)= 0
  • 最高 _ 可见 _ 值= 40 + (80/2) = 80

在这种情况下,lowest_visible_value将是 0 并且 80highest_visible_value。这意味着每个大于 80 的像素值将显示为白色,任何小于 0 的像素值将显示为黑色

为了看看这在像素级别是什么样子,我们可以缩小到图像的一小部分,看看windowing有什么效果。

作者图片

进一步缩小(上图是为了说明我们正在看的图像区域)

按比例缩小以显示我们将在像素级别看到的图像部分[图片作者]

我们现在可以绘制每个像素值

作者图片

使用肺窗,其window width为 1500,window level为-600。

  • lowest _ visible _ value =-600—(1500/2)=-1350
  • 最高可见值= -600 + (1500/2) = +150

在这种情况下,最低可见值将为-1350,最高可见值为+150。这意味着大于+150的每个像素值将显示为白色,小于-1350的任何值将显示为黑色。

作者图片

作者图片

像素强度已被缩放到窗口范围内的值。为了检查窗口范围是否按计划工作,我们可以比较原始图像和窗口图像的像素值。任何高于+150的像素值将显示为白色,任何低于-1350的像素值将显示为黑色,在这些值之间有各种阴影。

从左边的第一个像素开始,234的像素值高于+150的 highest_visible_value,因此该像素将在窗口图像上显示为白色(由1.0表示)。第 21 列的像素值为-731,其不低于-1350的最低可见值,因此不会显示为黑色,而是由值为0.4的阴影颜色(取决于 cmap 设置)表示。

更改窗口设置的意义

窗口宽度

  • 增加窗口宽度将decrease图像的对比度
  • 减小窗口宽度将increase图像的对比度

作者图片

窗位

  • 增加窗位将decrease图像的亮度
  • 降低窗位将increase图像的亮度

作者图片

各种窗肺范围

dicom_windows中有许多指定的窗口范围,或者您可以通过指定window widthwindow center创建自己的窗口范围。这些是特别查看肺部图像时最常用的窗口范围。

肺窗

  • 窗口设置:(宽:1600,长:-600)
  • 通常与宽窗口一起使用,以提供良好的分辨率并显示各种密度。

作者图片

纵隔窗

  • 窗口设置:(宽:500,长:50)
  • 纵隔是分隔肺部的区域。它被前面的胸骨和后面的脊柱包围,肺在两侧。它包括心脏、主动脉、食道、胸腺(颈部后面的一个腺体)和气管(气管)。

作者图片

PE 窗口

  • 窗口设置:(宽:700,长:100) —这不是dicom_windows的一部分,但您可以通过指定window levelwindow width轻松使用自定义窗口范围
  • 专门用于观察肺栓塞的窗口范围

作者图片

每个窗口突出显示特定的范围,使放射科医师更容易看到正常组织和病理改变组织之间是否有任何变化。如果我们将上面的三幅图像与一幅没有开窗的图像进行比较,我们可以清楚地看到为什么开窗很重要。

作者图片

如果你有兴趣了解更多关于 DICOM 的知识,你可以阅读我的文章 了解 DICOM,这篇文章也发表在《走向数据科学》上。

参考

( 1)增加医疗显示系统中的灰度数量——多少才够?

( 2)了解 CT 窗口、级别和密度

( 3)豪恩菲尔德量表

给大学生的信息

原文:https://towardsdatascience.com/a-message-for-undergraduates-6fd16caa1da1?source=collection_archive---------38-----------------------

更客观地看待自己,看着肩上的重量消散。

Joshua Hoehne 在 Unsplash 上拍摄的照片

你是大学生。要么你即将毕业(像我一样),要么你正在获得你的第一个大学学位。这个过程并不容易,我只能想象硕士和博士生的压力有多大。但是,我对此毫无头绪,所以这不会是我关注的话题。你可以很容易地认为我是为自己写这篇文章——这部分是对的。不管怎样,我还是想把这条消息发出去。申请机器学习领域的工作并不容易。任何人告诉你的都没有你现在工作的一半努力。

保持客观:

获得数学、统计学、计算机科学或任何与数据科学和机器学习相关的技术领域的本科学位是迈出这一步的绝佳途径。一般来说,在大学四年里,你应该有某种形式的实习或研究经历。事后获得经验同样很棒。但我说的客观对待自己,不一定是指你的经历。

我是我大学的一名高三学生。这意味着我还有不到一年的时间来获得统计学学士学位。我不断回想自己大二时上的第一堂高年级统计学课——方差分析。当我的教授在讨论如何找到总体样本均值时,我有生以来第一次看到了双重求和。我差点惊恐发作。这是一个等式:

作者图片

现在,你可能会认为这个方程非常直观。真的是。但是,我永远不会动摇我第看到这个等式时的那种感觉。这是一种数学知识不足以理解二重求和的感觉。这是一种落后于班级的感觉,尽管在看到方程之前不到两周就开始了。那是一种失败的感觉。对这样一个方程来说,那不是太多感情了吗?真的是。

我第一次看到二重求和的时候是 19 岁,不到两年后的今天,我 21 岁,正在撰写一篇论文,要求我了解两个我没有接受过正规教育的领域。在不到两年的时间里,我从害怕方程变成了对方程看不够。现在回头看自己上这门课,也能客观理解自己的感受。作为一名新生,我第一次看到许多概念,所以我被这样的公式吓倒是有道理的。作为一名大学生,你可能会看到许多(我指的是许多 ) 你一生中从未见过或想过的新概念。这些概念中的许多会让你着迷不已,并与你对世界的解读完美契合。更多的这些概念会打破你的思维方式,让你困惑几天、几周,有时甚至几个学期才能理解它们(旁注:如果你对一个概念如此困惑,可以和你的教授和助教谈谈。如果这仍然没有帮助,YouTube 一直支持我。)

如果你不能认识到你在过去几年中取得的进步,你就不能认识到你在未来必将取得的进步。你的目标是什么?你打算如何实现你的目标?客观地审视自己会提醒你,不要期望你一开始就知道所有的事情。成为一名本科生意味着一件非常重要的事情:你是这个领域的新手。这绝不是一件坏事。事实上,只有你认为它是坏事,它才是坏事。开始认识到,你正沿着自己选择的道路开始你的旅程。开始认识到你现在不知道的并不代表你将来的知识和潜力。开始认识到你知识的延展性可以让你成为超级巨星——你只需要自己去看。

深层图像修复的里程碑——综述:全局和局部一致的图像修复

原文:https://towardsdatascience.com/a-milestone-in-deep-image-inpainting-review-globally-and-locally-consistent-image-completion-505413c300df?source=collection_archive---------15-----------------------

欢迎回来,伙计们,我希望之前的帖子激起了你们对图像修复的深度生成模型的好奇心。如果你是新朋友,我强烈建议你浏览一下之前的帖子这里这里。根据前一篇文章中的声明,我们今天将进入深层图像修复的另一个里程碑!你准备好了吗?开始吧:)

*图像修复图像完成 代表相同的任务

回忆

这里只是简单回顾一下我们以前学过的内容。

  • 对于图像修复,填充像素的纹理细节非常重要。有效像素和填充像素应该一致,填充的图像应该看起来逼真。
  • 粗略地说,研究人员采用像素级重建损失(即 L2 损失)来确保我们可以用“正确”的结构填充缺失的部分。另一方面,应当使用 GAN 损失(即对抗性损失)和/或纹理损失来获得具有所生成像素的更清晰纹理细节的填充图像。

动机

图一。一个例子显示了为图像修补任务生成新片段的需要。摘自并修改自[1]

  • 对于基于补片的方法,一个重要的假设是,我们相信我们可以在缺失区域之外找到相似的补片,并且这些相似的补片对于填充缺失区域是有用的。这种假设对于自然场景可能是正确的,因为天空和草坪在一幅图像中可能有许多相似的斑块。如果丢失区域之外没有任何相似的补片,就像图 1 所示的人脸图像修复的情况一样,该怎么办?对于这种情况,我们无法找到任何眼罩来填补相应的缺失部分。因此,鲁棒的修复算法应该 能够生成新颖的片段
  • 现有的基于 GAN 的修补方法利用鉴别器(对抗损失)通过将填充区域馈送给鉴别器(即欺骗鉴别器)来增强填充区域的锐度。一些人可以在预训练的网络中比较丢失区域内部和外部的局部神经响应,以确保丢失区域内部和外部的局部补片的相似纹理细节。如果我们同时考虑图像的局部和全局信息来加强局部和全局一致性,会怎么样?我们会获得更好的完整图像吗? 让我们看看。

图二。上下文编码器的网络体系结构。摘自[2]

介绍

  • 现有的大多数方法都假设可以找到相似的图像块来填充同一幅图像中缺失的部分。图像修复并不总是如此,请参见图 1。更准确地说,我们应该看整个图像来理解它的上下文,然后根据它的上下文来填充缺失的部分。
  • 如果采用全连接层,则输入图像大小必须是固定的。因此,网络不能仅通过一次向前传递来处理不同分辨率的测试图像。回想一下,全连接层完全连接两层之间的所有神经元,因此它对先前层的输出大小的变化很敏感,并且测试图像大小必须是固定的。另一方面,对于卷积层,神经元之间没有完全连接。较小的输入要素地图会导致较小的输出要素地图。因此,如果网络仅由卷积层组成,它可以处理各种大小的输入图像。我们称这类网络为全卷积网络

解决方案(简而言之)

  • 使用扩展卷积而不是全连接层,这样我们仍然可以理解图像的上下文,并构建一个全卷积网络(FCN)来处理不同大小的图像。
  • 使用两个鉴别器来确保完成的(填充的)图像的局部和全局一致性。一个鉴别器在全局意义上查看整个图像,而一个鉴别器在局部意义上查看填充区域周围的子图像。
  • 采用简单的后处理。有时很容易发现生成像素和有效像素之间的差异。为了进一步提高视觉质量,作者采用了两种常规技术,即快速行进法泊松图像融合。这两种技术超出了本文的范围,感兴趣的读者可以点击超链接了解更多。后来,在某种程度上,后处理步骤已经以细化网络的形式嵌入到网络中。我们将在以后的文章中讨论它。

贡献

  • 提出一种全卷积网络,采用扩展卷积进行图像修复。它允许我们在不使用完全连接的层的情况下理解图像的上下文,因此训练的网络可以用于不同大小的图像。这种架构实际上形成了后来基于深度学习的图像修复方法的基础。这就是为什么我认为这篇论文是修复的里程碑。
  • 建议使用两个鉴别器(一个局部和一个全局)。多尺度鉴别器似乎可以在各种尺度下提供完整图像的更好的纹理细节。
  • 强调在图像修复任务中生成新颖片段的重要性。实际上,训练数据极其重要。简单来说,你不能生成你以前没见过的东西!

方法

图 3。提议的体系结构概述。摘自[1]

  • 图 3 显示了建议的整体网络架构。它由三个网络组成,即完备网络(即生成器,在训练和测试中都使用)、局部鉴别器和全局鉴别器(在刚训练时用作学习的辅助网络)。快速回忆一下这个 GAN 框架。生成器负责完成图像以欺骗鉴别器,而鉴别器负责区分完成图像和真实图像。

细胞神经网络中的扩张卷积

扩张卷积的概念对于读者理解本文的网络设计是重要的。所以,我想尽力为不熟悉扩张卷积的读者解释一下。对于非常了解它的读者,也请快速回顾一下。

图 4。标准卷积和扩展卷积的图示

  • 在论文中,作者用了半页的篇幅来描述 CNN、标准卷积和扩张卷积。他们还提供了卷积方程供参考。有一点我必须澄清,扩张卷积不是作者在本文中提出的,他们用它来进行图像修复。
  • 在这里,我只想用一个简单的图来说明标准卷积和扩张卷积的区别。
  • 图 4(a)是一个标准卷积层,具有 3×3 内核,步幅=1,填充=1,膨胀率=1。在 case 设置中,8×8 输入产生 8×8 输出,每 9 个相邻位置构成输出端的一个元素。
  • 图 4(b)也是标准卷积层。这次我们使用一个 5×5 的内核,步幅=1,填充=2(用于保持相同的输入和输出大小),膨胀率=1。在这种情况下,每 25 个相邻位置对输出端的每个元素都有贡献。这意味着对于输出端的每个值,我们必须更多地考虑(关注)输入端。我们通常称之为更大的感受野。对于一个大的感受野,来自远处空间位置的更多特征将被考虑以给出输出的每个值。
  • 然而,对于图 4(b)中的情况,我们使用更大的核(5×5)来获得更大的感受野。这意味着需要学习更多的参数(与 5×5=25 相比,3×3=9)。有什么方法可以在没有更多参数的情况下增加感受野?答案是扩张卷积。
  • 图 4(c)是一个具有 3×3 内核、步幅=1、填充=2 和膨胀率=2 的膨胀卷积层。当比较图 4(b)和图 4(c)中的核的覆盖范围时,我们可以看到它们都覆盖了输入端的一个 5×5 的局部空间区域。通过跳过连续的空间位置,3×3 核可以获得与 5×5 核一样的感受野。跳跃的步骤由膨胀率决定。举例来说,一个 3×3 的核,其扩张率=2 给出一个 5×5 的感受野;具有扩张率=3 的 3×3 核给出 7×7 感受野,依此类推。显然,通过跳过连续的空间位置,扩展卷积增加了感受野,而没有增加额外的参数。优点是我们有更大的感受野和相同数量的参数。缺点是我们跳过了一些位置(我们可能会因此丢失一些信息)。

为什么要扩张卷积?

在回顾了膨胀卷积的概念后,我现在要谈谈作者在他们的模型中使用膨胀卷积的原因。你们中的一些人可能已经猜到了原因。让我们检查一下!

  • 如前所述,理解整个图像的上下文对于图像修复任务是很重要的。以前的方法采用全连接层作为中间层,以便理解上下文。请记住,标准卷积层在局部区域执行卷积,而全连接层完全连接所有神经元(即每个输出值取决于所有输入值)。然而,全连接层对输入图像大小施加了限制,并引入了更多可学习的参数。
  • 为了解决这些限制,使用扩张卷积来构建允许各种大小输入的全卷积网络。另一方面,通过调整标准核的膨胀率(通常为 3×3),我们可以在不同的层上有更大的感受野,以帮助理解整个图像的上下文。

图 5。感受野大小的影响。摘自并修改自[1]

  • 图 5 是一个示例,显示了扩张卷积的有效性。你可能认为(a)是具有 3×3 核(较小感受野)的标准卷积,而(b)是具有 3×3 核且扩张率≥2(较大感受野)的扩张卷积。位置 p1 和 p2 位于孔区域内,其中 p1 靠近边界,p2 大致位于中心点。对于(a),可以看到位置 p1 的感受野(影响区域)可以覆盖有效区域。这意味着有效像素可以用来帮助填充位置 p1 处的像素。另一方面,位置 p2 的感受野不能覆盖有效区域,因此没有来自有效区域的信息可用于生成。
  • 对于(b),我们使用扩张卷积来增加感受野。这一次,两个位置的感受野可以覆盖有效区域。读者现在可以认识到扩张卷积的有效性。

完井网络

让我们回到图 3 所示的完井网络的结构。

表 1。完井网络的结构。每个卷积层后面都跟有 ReLU,除了最后一个卷积层后面跟有 Sigmoid [1]

  • 完成网络是一个完全卷积网络,它接受不同大小的输入图像。
  • 该网络对输入进行 2 倍的下采样。这意味着,如果输入为 256×256,则中间层的输入大小为 64×64。
  • 为了充分利用有效像素并保证逐像素精度,作者用有效像素代替空洞区域以外的像素。

上下文鉴别器

让我们来谈谈本地和全球歧视者。没有什么特别的,和单一鉴别器的情况一样。唯一不同的是我们这次有两个。

表二。局部和全局鉴别器的结构。FC 代表全连接层。级联层(c)的最后一个 FC 后面是一个 Sigmoid [1]

  • 局部和全局鉴别器共享几乎相同的架构。全局鉴别器以 256×256 的大小(整个图像,为了全局一致性)获取输入图像,而局部鉴别器以 128×128 的大小围绕缺失区域的中心获取输入,为了局部一致性。
  • 需要注意的一点是,在训练过程中,总有一个单一的缺失区域。在测试过程中,图像中可能会有多个缺失区域。此外,对于局部鉴别器,由于实际图像没有填充区域,因此对实际图像采用随机选择 128×128 的块。

训练策略和损失函数

  • 和以前一样,使用两个损失函数来训练网络,即 L2 损失和对抗损失(GAN 损失)。

  • C ( xM_c )表示作为函数的完井网络。 x 是输入图像,并且 M_c 是指示缺失区域的二进制掩码。1 表示孔区域,0 表示外部区域。你可以看到 L2 损耗是在空穴区域内计算的。注意,完整图像的外部区域的像素直接被有效像素替换。

  • D ( xM_d )表示作为函数的两个鉴别器。 M_d 是一个随机掩码,用于为局部鉴别器随机选择一个图像块。这是标准的 GAN 损耗。我们希望鉴别器不能区分完整的图像和真实的图像,因此我们可以得到具有真实纹理细节的完整图像。

  • 这是训练网络的联合损失函数。α是一个加权超参数,用于平衡 L2 损耗和 GAN 损耗。

算法 1。提议的培训程序[1]

  • 作者将他们的训练分为三个阶段。对于 T_C 次迭代,训练仅具有 L2 损耗的完成网络。 ii) 固定完成网络,使用 GAN 损耗训练鉴别器进行 T_D 次迭代。 iii) 交替训练完成网络和鉴别器,直到训练结束。
  • 为了稳定的训练,在除了完成网络的最后一层和鉴别器之外的所有卷积层之后使用批量标准化(BN)。
  • 为了生成训练数据,他们随机将图像的最小边缘调整到[256,384]像素范围。然后,他们随机裁剪一个 256×256 的图像块作为输入图像。对于掩模图像,他们随机生成一个洞,每个边的范围从[96,128]。
  • 简单的后处理:如前所述,作者还采用传统的快速行进方法,然后进行泊松图像混合,以进一步提高完成图像的视觉质量。

实验

  • 作者使用来自 Places2 数据集[3]的 8,097,967 幅训练图像来训练他们的网络。联合损失函数中的 alpha 加权超参数设置为 0.0004,批量大小为 96。
  • 从论文来看,完井网络训练为T _ C= 90000 次迭代;鉴别器被训练 T_D = 10,000 次迭代,最后所有网络被联合训练 400,000 次迭代。他们声称,整个训练过程在一台配有 4k 80 GPU 的计算机上需要大约 2 个月的时间。

表 3。提议方法的时机[1]

  • 他们使用 8 核英特尔酷睿 i7–5960 X CPU @ 3.00 GHz 和 NVIDIA GeForce TITAN X GPU 在 CPU 和 GPU 上进行评估。其实速度挺快的,半秒多一点完成一张 1024×1024 的图像。

图 6。与现有修复方法的比较[1]

  • 图 6 显示了与一些现有方法的比较。总的来说,基于补片的方法能够完成局部一致的图像补片,但是它们可能不与整个场景全局一致。最近基于 GAN 的方法,上下文编码器(第五行),往往会给出模糊的完整图像。所提出的方法提供了局部和全局一致的完整图像。

图 7。与上下文编码器(CE)对中心缺失孔的比较。CE 和我们的(CM)都使用来自 ImageNet 的相同 100k 训练图像子集进行训练,用于中心孔洞填充【1】

  • 为了与最新的基于 GAN 的修复方法进行比较,作者执行了中心区域填充,结果如图 7 所示。可以看出,对于中心区域完成,CE 比任意区域完成执行得更好(图 6)。在我看来,CE 和所提出的方法在图 7 中具有相似的性能。读者可以放大来看不同之处。

图 8。不同鉴别器设置的影响[1]

  • 作者对这两种鉴别器进行了消融研究。从图 8(b)和(c)可以看出,当不使用局部鉴别器时,完成的区域看起来更加模糊。另一方面,对于(d ),如果仅使用局部鉴别器,我们可以获得良好的局部一致性纹理细节,但不能保证全局一致性。对于(e)中的完整方法,我们实现了具有局部和全局一致性的结果。

图 9。简单后处理的效果[1]

  • 图 9 显示了简单后处理的效果。对于图 9(b ),我们可以很容易地观察到边界。

图 10。修复不同数据集的训练结果[1]

  • 图 10 显示了在不同数据集上训练的模型的修复结果。请注意,Places2 包含大约 800 万张不同场景的训练图像,而 ImageNet 包含 100 万张用于对象分类的训练图像。我们可以看到,在 Places2 上训练的模型的结果比在 ImageNet 上训练的结果要好一些。

图 11。提出的方法去除物体的例子[1]

  • 图像修补的一个潜在应用是对象移除。图 11 示出了通过使用所提出的方法来移除对象的一些例子。

图 12。更具体数据集的结果,即面部和立面[1]

  • 本文作者还考虑了特定领域的图像修复。他们在 CelebA 数据集4和 CMP Facade 数据集5上微调了他们的预训练模型,这两个数据集分别由 202,599 和 606 幅图像组成。他们使用在 Places2 数据集上训练的预训练模型。对于新的数据集,他们从头开始训练鉴别器,然后完成网络和鉴别器一起交替训练。
  • 图 12 示出了由所提出的用于域特定图像修补的方法给出的一些修补结果。对于人脸修复,提出的方法能够生成新颖的片段,如眼睛和嘴巴。对于立面修复,所提出的方法还能够生成像窗口一样的片段,这些片段在局部和全局上与整个图像一致。
  • 作者还对完整的人脸图像进行了用户研究。结果表明,77.0%的人脸被 10 个用户认为是真实人脸。另一方面,96.5%的真实人脸可以被 10 个用户正确识别。

局限性和讨论

以下是作者列出的关于局限性和未来方向的一些观点。

图 13。失败情况 I)掩模在图像的边界 ii)场景复杂。摘自[1]

  • 对于图 13 左侧的情况,我们可以看到缺失的部分在上部图像的边界处。作者声称在这种情况下,可以从邻近位置借用的信息更少,因此基于 GAN 的方法(第 3 行和第 4 行)比传统的基于补丁的方法(第 2 行)表现更差。另一个原因是,这个例子是自然场景,所以基于补丁的方法可以很好地工作。
  • 对于图 13 右边的例子,场景要复杂得多。根据遮罩,我们想要移除一个人,我们必须填充一些建筑物的细节来完成这个复杂的场景。在这种情况下,所有的方法都不能正常工作。所以在复杂场景中填充缺失的部分还是很有挑战性的。

图 14。举例说明生成新片段的重要性,我们只能生成我们以前在训练中见过的内容。摘自[1]

  • 作者提供了额外的例子来强调另外两点。 i) 生成眼睛、鼻子、嘴巴等新奇片段的重要性。 ii) 训练数据集的重要性。
  • 对于我们无法找到相似图像补片来填充缺失部分的情况,基于补片的方法(第 2 行和第 3 行)无法正常工作,如图 14 所示。因此,鲁棒的修复算法必须能够生成新颖的片段
  • 为了进一步表明选择训练数据集的重要性,作者比较了在 Places2(通用数据集,(d))和 CelebA(人脸数据集,(e))上训练的两个模型。显然,( d)不能用合理的面部细节来填充缺失的部分,因为它是在不包含任何对齐的面部图像的地点 2 上训练的。另一方面,(e)工作得很好,因为它是在 CelebA 上训练的,CelebA 是一个具有许多对齐的人脸图像的数据集。因此,我们只能生成我们在训练时看到的内容。鲁棒的通用修复还有很长的路要走。

结论

  • 所提出的体系结构是大多数后期修复论文的基础。具有扩展卷积的全卷积网络允许我们在不使用全连接层的情况下理解图像的上下文,因此网络可以采用各种大小的输入图像。
  • 多尺度鉴别器(这里我们有两个鉴别器,实际上有些可能有三个!)对于增强不同比例的完整图像的纹理细节是有用的。
  • 在场景复杂的情况下,填补缺失的部分仍然具有挑战性。另一方面,自然场景相对容易完成。

外卖食品

在这里,我想列出一些对以后的帖子有用的点。

  • 记住,具有扩展卷积的全卷积网络是用于图像修复的典型网络结构。它允许不同大小的输入,并为完全连接的层提供类似的功能(即帮助理解图像的上下文)。如果你愿意,你可以跳转到[ 这里 ]查看最近的修复论文,看看这种典型结构的变化。
  • 实际上,人脸图像修复比一般图像修复相对简单。这是因为我们总是在人脸数据集上训练模型来进行人脸图像修复,而数据集由许多对齐的人脸图像组成。对于一般的图像修复,我们可以在更加多样化的数据集上进行训练,如 Places2,它包含来自各种类别的数百万张图像,如城市、建筑物和许多其他图像。对于一个模型来说,学习生成具有良好视觉质量的所有东西要困难得多。不管怎么说,路还很长。

下一步是什么?

  • 到目前为止,我们已经深入研究了三篇非常好的早期修复论文。下次,我想复习一下。我将讨论另一篇论文,它采用了这种具有扩展卷积的全卷积网络。希望你能看到基于深度学习的图像修复的发展。尽情享受吧!😃

参考

  1. 饭冢聪,埃德加·西莫-塞拉,石川宽,“全球和局部一致的图像完成ACM Trans。《论图形》,第 36 卷第 4 期第 107 条,出版日期:2017 年 7 月。
  2. Deepak Pathak,Philipp krhenbüHL,Jeff Donahue,Trevor Darrell 和 Alexei A. Efros,"上下文编码器:通过修补进行特征学习," Proc .计算机视觉与模式识别 ( CVPR ),2016 年 6 月 27-30 日。
  3. 地点 2 数据集,http://places2.csail.mit.edu/download.html
  4. 、罗平、王晓刚和唐晓鸥,“在野外深度学习人脸属性”, Proc。计算机视觉与模式识别 ( CVPR ),2015。
  5. Radim Tyleč ek 和 Radimára,“用于识别具有规则结构的对象的空间模式模板”, Proc。2013 年德国模式识别会议

感谢你花时间写这篇文章。如果您有任何问题,请随时询问或在此留下评论。下次见!😃

R 中结合 H2O 自动分解和沙普利分解的一个极小例子

原文:https://towardsdatascience.com/a-minimal-example-combining-h2os-automl-and-shapley-s-decomposition-in-r-ba4481282c3c?source=collection_archive---------44-----------------------

Borna Bevanda 在 Unsplash 上的照片

作为巴西一家大型金融机构的数据科学家,每天都要为业务的许多不同方面构建预测模型,这是很常见的。这取决于问题规模、数据类型、时间可用性等。,我的方法可以从开发快速和肮脏的模型(例如,基线逻辑回归)到更复杂(也许更精确)的模型。这两种方法都很有价值,在权衡每个问题的成本效益及其潜力时,都应该加以考虑。

作为一名经常使用 R 的用户,我最喜欢的机器学习方法之一是将 AutoML 的 H2O 框架的预测建模能力与 Shapley 值的可解释性结合起来。虽然有很多关于这两种技术的在线教程/解释(对于 H2O,我推荐艾琳·莱德尔的视频,比如这个:【https://www.youtube.com/watch?v=DjzKTeIIxOY】,对于沙普利的价值观,斯科特·伦德伯格的视频,比如这个https://www.youtube.com/watch?v=ngOBhhINWb8),博客帖子,笔记本等等。,我从来没有找到一种材料能以简洁的方式将它们结合在一起。

这篇博客文章是我构建的一个方便的脚本中的一个演练,我偶尔会为机器学习任务重新访问这个脚本(该脚本可在https://github . com/renanxcortes/SHAP _ with _ H2O _ AutoML/blob/master/SHAP _ with _ H2O _ AutoML 获得。R )。其思想是在拟合后,使用 AutoML 和 Shapley 的可解释性值逐步解释模型估计的整个过程。

你准备好了吗?所以,让我们开始吧!

我们首先加载所需的库:

library(h2o)
library(tidyverse)
library(ggbeeswarm)

因为我想尽可能保持简单,所以让我们为具有五个协变量的二元分类问题构建一个数据框架:

df <- tibble(y = rep(c(0,1), c(1000,1000)),
x1 = rnorm(2000),
x2 = rf(2000, df1 = 5, df2 = 2),
x3 = runif(2000),
x4 = c(sample(rep(c('A', 'B', 'C'), c(300, 300, 400))),                     sample(c('A', 'B', 'C'), 1000, prob = c(0.25, 0.25, 0.5), replace = T)),
x5 = c(rnorm(1000), rnorm(1000, 0.25)))

现在,作为中间步骤,H2O 的框架需要处理因子而不是字符。因此,让我们改变一些变量的类:

df <- df %>%   
mutate(y = as.factor(y)) %>%   
mutate_if(is.character, factor)

接下来的三个步骤分别是:在 R 会话中启动 H2O 实例,将数据框转换为 H2O 数据框,以及将数据拆分为定型集和维持集。

h2o.init() 
df_frame <- as.h2o(df) 
df_frame_split <- h2o.splitFrame(df_frame, ratios = 0.8)

值得注意的是,在分割画面时,H2O 并没有给出精确的分割。它旨在使用概率分割方法而不是精确分割来高效处理大数据。

现在,时候到了!鉴于我们之前运行的步骤,是时候拟合机器学习模型了。下面的代码完成了这个任务:

# Metric for binary classification (deviance is the default). Check documentation here [http://docs.h2o.ai/h2o/latest-stable/h2o-docs/automl.html](http://docs.h2o.ai/h2o/latest-stable/h2o-docs/automl.html)
automl_model <- h2o.automl(y = 'y',
balance_classes = TRUE,
training_frame = df_frame_split[[1]],
nfolds = 4,
leaderboard_frame = df_frame_split[[2]],
max_runtime_secs = 60 * 2,
include_algos = c('DRF', 'GBM', 'XGBoost'),
sort_metric = "AUC")

好吧…深呼吸,因为这里发生了很多事情。我强烈建议您看一下官方文档,键入help(h2o.automl)可以更好地了解每个参数设置。我想强调其中一些我认为至关重要的因素:

  • include_algos :首先也是更重要的,由于 Shapley 的值分解是为基于树的模型开发的,这篇博文的王牌就是通过设置include_algos = c('DRF', 'GBM', 'XGBoost')来限制算法。这样,AutoML 将保证生成的最佳模型对于第二阶段的 Shapley 值生成是可行的;
  • max_runtime_secs :其次,一个很重要的论点是max_runtime_secs。这是功能运行的最长时间,以秒为单位。如果您有复杂和/或大型数据集,并且有时间等待更准确的模型,则可以将设置为更大的值;
  • sort_metric :最后,我想强调一下sort_metric参数,可以根据您的喜好或机器学习问题对其他度量进行调整(例如,对于回归模型,您可以设置sort_metric = "RMSE")。

关于h2o.automl最酷的事情之一是它生成了一个排行榜,非常类似于 Kaggle 的排行榜对模特进行排名:

lb <- as.data.frame(automl_model@leaderboard)

排行榜的第一行是在这个简单的例子中产生的

我们可以提取领导者模型:

aml_leader <- automl_model@leader

现在,我们计算并绘制 Shapley 值,以获得每个特征如何影响 leader 模型中因变量的总体概述,代码片段如下:

# SHAP values: http://docs.h2o.ai/h2o/latest-stable/h2o-r/docs/reference/predict_contributions.H2OModel.html 
SHAP_values <- predict_contributions.H2OModel(aml_leader, df_frame_split[[2]]) # Wrangling inspired here: https://bradleyboehmke.github.io/HOML/iml.html shap_df <- SHAP_values %>%  
as.data.frame() %>%  
select(-BiasTerm) %>%  
gather(feature, shap_value) %>%  
group_by(feature) %>%  
mutate(shap_importance = mean(abs(shap_value)),         
shap_force = mean(shap_value)) %>%   
ungroup() # SHAP contribution plotp1 <- ggplot(shap_df, aes(x = shap_value, y = reorder(feature, shap_importance))) +  
ggbeeswarm::geom_quasirandom(groupOnX = FALSE, varwidth = TRUE, size = 0.9, alpha = 0.5, width = 0.15) +  
xlab("SHAP value") +  
ylab(NULL) +  
theme_minimal(base_size = 15) # SHAP importance plotp2 <- shap_df %>%   
select(feature, shap_importance) %>%  
distinct() %>%   
ggplot(aes(x = reorder(feature, shap_importance),              
y = shap_importance)) +  
geom_col(fill = 'black') +  
coord_flip() +  
xlab(NULL) +  
ylab("mean(|SHAP value|)") +  
theme_minimal(base_size = 15) # Combine plotsgridExtra::grid.arrange(p1, p2, nrow = 1)

全球重要性的两个主要图

虽然 Shapley 的值在分析局部观测值时更直观,但检查这些全局属性也是有意义的。左侧的图表描述了维持集中每个功能的所有 Shapley 值的分布。可以看出, x5 具有大多数 Shapley 值负值,并且具有更宽的分布,表明其在预测能力或模型中的重要性,而 x2 是“不太重要的”。右侧的重要性图中的图表也加强了这一点,该图由分解的所有绝对值的平均值给出。

此外,还可以为每个特性的值构建部分相关图。让我们来看看最重要的特征是如何与因变量相关的:

# Shapley-based dependence plots for a numerical feature
SHAP_values %>%
  as.data.frame() %>%
  select(-BiasTerm) %>% 
  mutate(x5_feature_values = as.vector(df_frame_split[[2]]$x5)) %>% 
  ggplot(aes(x = x5_feature_values, y = x5)) +
  geom_point(aes(color = x5), width = 0.1) +
  scale_colour_gradient(low = "red", high = "blue", name = 'SHAP values') +
  ylab('Shapley\'s values for x5 feature') +
  xlab('x5 values') +
  theme_minimal(base_size = 15) +
  geom_smooth()

x5 特征的部分相关图:非线性关系

上图描绘了特征 x5 和其 Shapley 值之间明显的非线性关系。

此外,对于范畴特征,这种情节也是令人感兴趣的:

# Shapley-based dependence plots for a categorical feature
SHAP_values %>%
  as.data.frame() %>%
  select(-BiasTerm) %>% 
  mutate(x4_feature_values = as.vector(df_frame_split[[2]]$x4)) %>% 
  ggplot(aes(x = x4_feature_values, y = x4)) +
  geom_jitter(aes(color = x4), width = 0.1) +
  scale_colour_gradient(low = "red", high = "blue", name = 'SHAP values') +
  ylab('Shapley\'s values for x4 feature') +
  xlab('x4 feature classes') +
  theme_minimal(base_size = 15)

x4 特征的部分相关图:C 类高于其他类

您可以看到,类别 C 与因变量的较高值相关联,在本例中,因变量是“成功”的较高概率(y = 1)。

收尾

这篇文章描述了一个使用 R-数据科学中最常用的语言之一-的最小示例,用于使用 H2O 的 AutoML 和沙普利的值拟合机器学习模型。由于 H2O 的 AutoML 工具具有广泛的预测模型,这种方法的关键点是通过设置include_algos = c('DRF', 'GBM', 'XGBoost')将模型搜索限制为仅基于树。此外,为了说明这种方法的可解释性,使用了 Shapley 值、全局重要性图和部分相关性图。

你喜欢你读到的东西吗?推荐/分享这篇文章,让别人也能看到!还有 , 有什么意见或建议,不要犹豫和我联系!随时欢迎反馈!

通过LinkedinTwitterGithub。另外,你可以看看我的 网站

由于 H2O 在幕后依赖于 Java,为了让它正常工作,您可能需要它。更多信息请访问https://docs . H2O . ai/H2O/latest-stable/H2O-docs/downloading . html

很容易在不考虑绝对值的情况下检查这些方法,试图检查每个特征的“总体方向”。但是,应考虑绝对值,而不是原始的正值和负值,因为正如 Scott Lundberg 所解释的那样,“正值和负值都很重要,但是如果在测量全局特征重要性时允许它们相互抵消,那么您将不会测量特征对于模型的重要性,而是测量每个特征在您解释的样本和您的背景样本集之间的影响有多大不同。”中提到的https://github . com/slund Berg/shap/issues/696 # issue comment-581993726。

理解和创建 Python 虚拟环境的简明指南

原文:https://towardsdatascience.com/a-minimal-guide-to-understanding-and-creating-python-virtual-environments-38ba3eac1bc7?source=collection_archive---------24-----------------------

以及依赖性管理的重要性

大多数严肃的数据科学项目应该在 Docker 容器或虚拟环境中进行。无论是对于测试还是依赖管理,这都是很好的实践,容器化为您调试和理解事物如何在统一的范围内协同工作提供了更大的能力。这篇文章是关于在 Python 3 中创建一个虚拟环境的,虽然文档看起来很简单,但我想指出几个重要的清晰点,尤其是在使用 Jupyter 笔记本和管理内核和依赖项时。

乔治·霍丹的照片,公共领域

venv 是什么?

Python 3 模块“venv”是 Python 3 的标准库。这意味着它是在你下载 Python 3 时内置的,所以你不必担心安装它。创建一个真实的虚拟环境非常简单:

python3 -m venv choose_your_venv_name

第一个命令是‘python 3’。这指示命令行运行 Python 3 脚本。后跟'-m ',该选项进一步指示 Python3 查找模块名,在本例中为' venv '。最后一个参数是您的虚拟环境的名称,它应该与您的预期项目的上下文相关(例如,基于统计的虚拟环境的“statsbox”)。

运行这个命令将会在你当前所在的目录中用你选择的名字创建一个目录,所以在运行它之前要小心地cd找到你想要的目录。几秒钟后,您的虚拟环境就应该创建好了。例如,我在主目录中运行了以下命令:

python3 -m venv tutorial_box

几秒钟后,我运行ls查看我的 home 目录,唉,‘tutorial _ box’就在那里。如果我们cd进入任何一个虚拟环境的目录,我们会发现它不是空的!

bin    include    lib    pyvenv.cfg

太好了。这些实际上是基本的“白板”文件,是启动和运行虚拟环境所必需的。仅仅因为你创造了一个虚拟环境,并不意味着你已经真正置身其中(激活)。这是一个重要的概念区别,我发现它会让入门学习者感到困惑。即使你cd进入虚拟环境目录(如上),你的命令行命令,你的 Jupyter 笔记本,你的包仍然由你的全局环境的 PATH 变量决定。这意味着你打开的任何 Jupyter 笔记本仍然可以访问你在全球环境中安装的任何包或模块,如果你无意中制作了一个 genius 机器学习模型,而该模型依赖于一个无法在不同环境中编译的包版本,那么你的代码将在该环境中中断。例如,当试图用 Heroku、Streamlit、Flask、Dash 等部署数据科学应用程序时,这种情况很常见。

将虚拟环境(或 Docker 容器)想象成一台字面上的计算机是一个很好的比喻,它是您计算机内部的一台迷你计算机。换句话说,仅仅因为你的电脑里有新的迷你电脑,并不意味着你还没有打开它

为此,在命令行中激活您的虚拟环境:

source bin/activate

就是这样!为了知道它在工作,您应该在左下方看到您的虚拟环境的名称,带有括号,在您通常的计算机的当前目录路径之前。在这种情况下,它是(tutorial_box)

最后,我们创建并激活了我们的虚拟环境。如果您在终端中手动运行 Python 3,您将在一个全新的环境中操作,并且您必须从头开始安装新项目所需的任何模块和包。但是记住,这是好事!它会把你从依赖地狱中拯救出来。

…但为什么我的 Jupyter 笔记本仍在使用我的全球套餐?

这是我想在本教程中阐明的基本观点。

所以,我们已经激活了我们的虚拟环境。我们运行的任何 Python 3 命令都将被限制在我们新的虚拟环境的范围内。那么当我们打开一个新的 Jupyter 笔记本时会发生什么呢?

jupyter notebook

Jupyter 应该仍然可以在浏览器中打开,但是如果我们尝试创建一个新的笔记本,我们应该会看到下面的内核选项:

在右下角,我们只有一个选择

在“新”笔记本选项卡下,我们看到了“Python 3”。这很令人困惑:我们可以选择创建一个新的 Jupyter 笔记本,但是我们有一个潜在的内核列表可供选择。在某种程度上(与虚拟环境有些不同),这些内核本身就是虚拟 Python 环境,它将独立于您的虚拟环境运行,即使它被激活了!

出现的默认 Python 3 内核实际上将再次成为您的全局 Python 3 环境,这完全挫败了使用虚拟环境的意义,因为我们希望从空白状态中精确地控制我们正在使用的包和模块。

为了向您的 Jupyter 环境添加一个新的内核,它与您刚刚用 venv 创建的虚拟环境相匹配,您需要在一个已经激活的虚拟环境中运行下面的命令【T9:

pip install --user ipykernel

这将在您的虚拟环境中安装 kernel-creator,并且您将总是需要在一个新创建的虚拟环境中运行它,因为它是一张白纸,不会安装ipykernel。然后,为了最终将内核添加到 Jupyter 笔记本的内核选项列表中,运行以下命令:

python -m ipykernel install --user --name=whatever_you_want 

这里有几点很重要。首先,whatever_you_want名称可以是您想要的任何名称,并且不必与您的虚拟环境名称相匹配。重要的是,用这个命令创建的内核将包含当前激活的虚拟环境中的所有包和模块。因此,给它起一个与你的虚拟环境相关的名字是有意义的,但是明智的做法是附上一个版本号。随着时间的推移,你可能会添加更多的包到你的虚拟环境中,然后你会添加那个虚拟环境 state 作为一个新的修改过的带有ipykernel的内核。最终,某些东西会坏掉,或者一些安装或更新的包会给你一个稍微不同的机器学习模型,你会想要恢复到以前的 Jupyter 内核。给这些内核添加您自己的版本号解决了这个问题,并且是虚拟环境的一种本地化版本控制。

或者,您也可以使用以下命令创建一个requirements.txt文件:

pip freeze > requirements.txt

那个。txt 文件可以安装在其他地方(更确切地说,是它里面的所有东西),比如不同的虚拟环境或 Docker 容器。

或者,我会推荐使用 pip-compile,这是一个pip-tools包。这对于从手动输入的requirements.in文件自动生成requirements.txt文件非常有帮助。这非常有用,因为pip-compile会自动检测requirements.in文件中列出的包的所有必需依赖项。

这就足够了。使用venvipykernelpip-compile是创建全新虚拟环境所需要的,希望这篇文章已经阐明了它们是如何与 Jupyter 笔记本、内核和依赖管理联系在一起的。

感谢阅读!

TensorFlow 2.0 中连续策略梯度的最小工作示例

原文:https://towardsdatascience.com/a-minimal-working-example-for-continuous-policy-gradients-in-tensorflow-2-0-d3413ec38c6b?source=collection_archive---------24-----------------------

一个简单的训练高斯演员网络的例子。定义自定义损失函数并应用 GradientTape 功能,只需几行代码就可以训练演员网络。

列宁·艾斯特拉达在 Unsplash 上的照片

目前设计和应用的所有复杂的行动者-批评家算法的基础是普通策略梯度算法,它本质上是一个只针对行动者的算法。现在,学习决策政策的参与者通常由神经网络来表示。在连续控制问题中,该网络输出相关的分布参数以采样适当的动作。

有这么多深度强化学习算法在流通,你可能会认为很容易找到大量即插即用的 TensorFlow 实现,用于连续控制的基本参与者网络,但事实并非如此。这可能有各种原因。首先,TensorFlow 2.0 于 2019 年 9 月才发布,与其前身有很大不同。第二,大多数实现关注离散的动作空间,而不是连续的动作空间。第三,流通中有许多不同的实现,但有些是定制的,因此它们只在特定的问题环境中工作。仔细阅读数百行充满占位符和类成员的代码,却发现这种方法根本不适合您的问题,这可能有点令人沮丧。本文基于我们的 ResearchGate 笔记[1],提供了一个在 TensorFlow 2.0 中运行的最小工作示例。我们将向您展示真正的神奇只发生在三行代码中!

一些数学背景

在这篇文章中,我们提出了一个简单和通用的执行机构网络的背景下的香草政策梯度算法加强[2]。在连续变量中,我们通常从高斯分布中提取动作;目标是学习适当的均值 μ 和标准差 σ 。演员网络学习并输出这些参数。

让我们更正式地描述一下这个演员网络。这里,输入是状态 s 或特征数组 ϕ(s) ,后面是一个或多个变换输入的隐藏层,输出是 μσ 。一旦获得该输出,从相应的高斯分布中随机抽取动作 a 。由此,我们得到 a=μ(s)+σ(s)ξ,其中ξ∾𝒩(0,1)。

在采取行动 a 后,我们观察到相应的奖励信号 v 。与一些学习率α一起,我们可以将权重更新为提高我们策略的预期回报的方向。基于梯度上升的相应更新规则[2]由下式给出:

如果我们使用线性近似方案μ_θ(s)=θ^⊤ϕ(s】,我们可以直接对每个特征权重应用这些更新规则。对于神经网络来说,我们应该如何执行这种更新可能不那么简单。

通过最小化损失函数来训练神经网络。我们通常通过计算均方误差(预测值和观测值之差的平方)来计算损失。例如,在一个批评网络中,损失可以定义为(r+qₜ₊₁-q),其中 Q ₜ是预测值,而 r+ Q ₜ₊₁是观测值。计算损失后,我们通过网络反向传播它,计算更新网络权重所需的部分损失和梯度。

乍一看,更新方程与这种损失函数几乎没有共同之处。我们只是试图通过向某个方向前进来改进我们的政策,但头脑中没有明确的“目标”或“真正的价值”。事实上,我们需要定义一个“伪损失函数”来帮助我们更新网络[3]。当将更新规则表达成其通用形式时,传统更新规则和该损失函数之间的联系变得更加清楚:

转换成损失函数相当简单。由于损失仅为反向传播过程的输入,我们首先丢弃学习速率 α 和梯度 ∇_θ 。此外,使用梯度下降而不是梯度上升来更新神经网络,因此我们必须添加减号。这些步骤产生以下损失函数:

跟更新规则挺像的吧?提供一些直觉:提醒对数转换对所有小于 1 的值产生一个负数。如果我们有一个低概率和高回报的行动,我们会希望观察到一个大的损失,即一个强烈的信号,将我们的政策更新到高回报的方向。损失函数正是这样做的。

为了应用高斯策略的更新,我们可以简单地用高斯概率密度函数(pdf)代替π_θ——注意,在连续域中,我们使用 pdf 值而不是实际概率——以获得所谓的加权高斯对数似然损失函数:

TensorFlow 2.0 实施

现在数学已经讲得够多了,是实现的时候了。

我们刚刚定义了损失函数,可惜在 Tensorflow 2.0 中不能直接应用。在训练一个神经网络的时候,你可能习惯了类似于model.compile(loss='mse',optimizer=opt),其次是model.fit或者model.train_on_batch的东西,但是这个不行。首先,高斯对数似然损失函数不是 TensorFlow 2.0 中的默认函数,它在 Theano 库中,例如[4],这意味着我们必须创建一个自定义的损失函数。但是更具限制性:TensorFlow 2.0 要求损失函数正好有两个参数,y_truey_predicted。正如我们刚刚看到的,我们有三个论点,因为与奖励相乘。让我们稍后再考虑这个问题,首先介绍我们的定制高斯损失函数:

所以我们现在有正确的损失函数,但是我们不能应用它!?我们当然可以——否则所有这些都是毫无意义的——只是与你可能习惯的略有不同。

这就是GradientTape功能的用武之地,它是 TensorFlow 2.0 [5]的新增功能。它本质上是在一个'磁带'上记录你前进的步伐,这样它就可以应用自动微分。更新方法包括三个步骤[6]。首先,在我们的自定义损失函数中,我们向前传递参与者网络(已记忆)并计算损失。第二,通过函数.trainable_variables,我们回忆在我们向前传递时发现的重量。随后,tape.gradient通过简单地插入损失值和可训练变量,为您计算所有梯度。第三,使用optimizer.apply_gradients我们更新网络权重,其中优化器是您选择的一个(例如,SGD、Adam、RMSprop)。在 Python 中,更新步骤如下所示:

所以最后,我们只需要几行代码来执行更新!

数例

我们给出了一个连续控制问题的最小工作示例,完整代码可以在我的 GitHub 上找到。我们考虑一个极其简单的问题,即只有一个状态和一个微不足道的最优策略的一次性博弈。我们越接近(固定但未知的)目标,我们的奖励就越高。奖励函数形式上表示为 R =ζ β / max (ζ,|τ - a|) ,其中 β 为最大奖励, τ 为目标, ζ 为目标范围。

为了表示演员,我们定义了一个密集的神经网络(使用 Keras ),该网络将固定状态(值为 1 的张量)作为输入,使用 ReLUs 作为激活函数(每层五个)在两个隐藏层中执行变换,并返回 μσ 作为输出。我们初始化偏置权重,使得我们从 μ =0 和 σ =1 开始。对于我们的优化器,我们使用 Adam,其默认学习率为 0.001。

下图显示了一些运行示例。请注意,收敛模式符合我们的预期。起初,损失相对较高,导致 μ 向更高回报的方向移动,σ增加,允许更多的探索。一旦达到目标,观察到的损失减少,导致 μ 稳定, σ 下降到接近 0。

收敛到目标 μ (作者自己的工作[1])

要点

  • 政策梯度法不适用于传统的损失函数;我们必须定义一个伪损失来更新行动者网络。对于连续控制,伪损失函数只是 pdf 值乘以回报信号的负对数。
  • 几个 TensorFlow 2.0 更新函数只接受正好有两个参数的自定义损失函数。GradientTape功能没有这种限制。
  • 使用三个步骤来更新演员网络:(I)定义定制损失函数,(ii)计算可训练变量的梯度,以及(iii)应用梯度来更新演员网络的权重。

本文部分基于我在 ResearchGate 上发表的论文: 在 TensorFlow 2.0 中实现用于连续控制的高斯行动者网络。

GitHub 代码(使用 Python 3.8 和 TensorFlow 2.3 实现)可以在我的 GitHub 资源库 找到。

希望实施离散变量或深度 Q 学习?退房:

[## TensorFlow 2.0 中离散策略梯度的最小工作示例

一个训练离散演员网络的多兵种土匪例子。在梯度胶带功能的帮助下…

towardsdatascience.com](/a-minimal-working-example-for-discrete-policy-gradients-in-tensorflow-2-0-d6a0d6b1a6d7) [## TensorFlow 2.0 中深度 Q 学习的最小工作示例

一个多臂土匪的例子来训练一个 Q 网络。使用 TensorFlow,更新过程只需要几行代码

towardsdatascience.com](/a-minimal-working-example-for-deep-q-learning-in-tensorflow-2-0-e0ca8a944d5e)

参考文献

[1] Van Heeswijk,W.J.A. (2020)在 TensorFlow 2.0 中实现连续控制的高斯行动者网络。https://www . research gate . net/publication/343714359 _ Implementing _ Gaussian _ Actor _ Networks _ for _ Continuous _ Control _ in _ tensor flow _ 20

[2] Williams,R. J. (1992)连接主义强化学习的简单统计梯度跟踪算法。机器学习,8(3–4):229-256。

[3] Levine,S. (2019)加州大学伯克利分校 CS 285 深度强化学习:政策梯度。http://rail . eecs . Berkeley . edu/deeprlcourse/static/slides/LEC-5 . pdf

[4]the nets 0 . 7 . 3 文档。高斯对数似然函数。https://the nets . readthe docs . io/en/stable/API/generated/the nets . losses . Gaussian loglikelihood . html # the nets . losses . Gaussian loglikelihood

[5] Rosebrock,A. (2020)使用 TensorFlow 和 GradientTape 来训练 Keras 模型。https://www.tensorflow.org/api_docs/python/tf/GradientTape

[6]南丹,A. (2020)演员评论家法。https://keras.io/examples/rl/actor_critic_cartpole/

TensorFlow 2.0 中离散策略梯度的最小工作示例

原文:https://towardsdatascience.com/a-minimal-working-example-for-discrete-policy-gradients-in-tensorflow-2-0-d6a0d6b1a6d7?source=collection_archive---------38-----------------------

一个训练离散演员网络的多兵种土匪例子。在 GradientTape 功能的帮助下,只需几行代码就可以训练演员网络。

照片由你好我是 Nik via Unsplash

一旦你知道如何做,用 TensorFlow 2.0 训练离散演员网络是很容易的,但与 TensorFlow 1.0 中的实现有很大不同。由于 2.0 版本是 2019 年 9 月才发布的,所以网上流传的大部分例子还是为 TensorFlow 1.0 设计的。在与相关的一篇文章中,我们也更详细地讨论了数学——我们已经处理了连续的情况。在这里,我们使用一个简单的多臂土匪问题,以显示我们如何可以实现和更新一个演员网络的离散设置[1]。

一点数学知识

我们使用经典的策略梯度算法加强,其中参与者由称为参与者网络的神经网络表示。在离散情况下,网络输出仅仅是选择每个动作的概率。因此,如果动作集合由 A 定义,动作由 a ∈ A 定义,那么网络输出是概率 p(a)∀a ∈ A 。输入层包含状态 s 或特征数组 ϕ(s) ,后面是一个或多个转换输入的隐藏层,输出是每个可能被选择的动作的概率。

策略π由 θ、参数化,在深度强化学习中表示神经网络权重。在我们采取的每一个行动之后,我们都会观察到一个奖励 v 。计算 θ 的梯度并使用学习率 α ,教科书中常见的更新规则如下所示[2,3]:

当对神经网络应用反向传播更新时,我们必须稍微修改这个更新规则,但是程序遵循相同的路线。虽然我们可能手动更新网络权重,但我们通常更喜欢让 TensorFlow(或您使用的任何库)来处理更新。我们只需要提供一个损失函数;计算机处理梯度的计算和其他花哨的技巧,如定制的学习率。事实上,我们唯一要做的就是加上一个负号,因为我们执行的是坡度下降而不是上升。因此,损失函数——被称为对数损失函数交叉熵损失函数【4】——看起来像这样:

TensorFlow 2.0 实施

现在让我们转到实际的实现。如果你有一些 TensorFlow 的经验,你可能首先用model.compile编译你的网络,然后执行model.fitmodel.train_on_batch来使网络适合你的数据。由于 TensorFlow 2.0 要求损失函数正好有两个参数,(y_truey_predicted),我们不能使用这些方法,因为我们需要动作、状态和奖励作为输入参数。TensorFlow 1.0 [5]中没有的GradientTape功能方便地解决了这个问题。在“磁带上存储一个通过演员网络的前向通道后,它能够在稍后的后向通道中执行自动微分。

我们首先定义交叉熵损失函数:

在下一步中,我们使用函数.trainable_variables来检索网络权重。随后,tape.gradient通过简单地插入损失值和可训练变量,为您计算所有梯度。通过optimizer.apply_gradients,我们使用选定的优化器更新网络权重。如前所述,在 GradientTape 中包含正向传递(在此过程中,我们从网络中获取动作概率)是至关重要的。更新权重的代码如下:

多臂土匪

在多臂土匪问题中,我们能够玩几个具有独特支付属性的老丨虎丨机[6]。每台机器 i 都有一个平均收益 μ_i 和一个标准差 σ_i ,这些都是玩家不知道的。在每一个决策时刻,你玩一个机器,观察回报。经过充分的迭代和探索,你应该能够相当准确地估计每台机器的平均回报。自然,最佳策略是总是玩预期收益最高的老丨虎丨机。

使用 Keras,我们定义了一个密集的演员网络。它以一个固定的状态(一个值为 1 的张量)作为输入。我们有两个隐藏层,每层使用五个 ReLUs 作为激活函数。网络输出玩每个老丨虎丨机的概率。以这样的方式初始化偏置权重,使得每个机器在开始时具有相等的概率。最后,选择的优化器是 Adam,其默认学习率为 0.001。

我们测试了四种不同平均收益的设置。为了简单起见,我们把所有的标准差都设为相等。下图显示了每台老丨虎丨机的学习概率,使用四台机器进行测试。正如预期的那样,该策略学习玩预期收益最高的机器。一些探索自然会持续下去,尤其是当收益非常接近的时候。稍加调整,你肯定会在下一次拉斯维加斯之旅中做得更好。

要点

  • 我们定义了一个伪损失来更新行动者网络。对于离散控制,伪损失函数只是负对数概率乘以回报信号,也称为对数损失或交叉熵损失函数。
  • 常见的 TensorFlow 2.0 函数只接受恰好有两个参数的损失函数。而GradientTape则没有这个限制。
  • 使用三个步骤来更新演员网络:(I)定义定制损失函数,(ii)计算可训练变量的梯度,以及(iii)应用梯度来更新演员网络的权重。

本文部分基于我的方法论文:【tensor flow 2.0 中离散控制的 Actor 网络实现【1】

GitHub 代码(使用 Python 3.8 和 TensorFlow 2.3 实现)可以在我的 GitHub 资源库 找到。

希望实施连续变量或深度 Q 学习?结账:

[## TensorFlow 2.0 中连续策略梯度的最小工作示例

一个简单的训练高斯演员网络的例子。定义自定义损失函数并应用梯度胶带…

towardsdatascience.com](/a-minimal-working-example-for-continuous-policy-gradients-in-tensorflow-2-0-d3413ec38c6b) [## TensorFlow 2.0 中深度 Q 学习的最小工作示例

一个多臂土匪的例子来训练一个 Q 网络。使用 TensorFlow,更新过程只需要几行代码

towardsdatascience.com](/a-minimal-working-example-for-deep-q-learning-in-tensorflow-2-0-e0ca8a944d5e)

参考

[1] Van Heeswijk,W.J.A. (2020)在 TensorFlow 2.0 中实现离散控制的参与者网络。https://www . researchgate . net/publication/344102641 _ Implementing _ Actor _ Networks _ for _ Discrete _ Control _ in _ tensor flow _ 20

[2]威廉斯,R. J. (1992 年)。联结主义强化学习的简单统计梯度跟踪算法。机器学习,8(3–4):229–256。

[3] Levine,S. (2019)加州大学伯克利分校 CS 285 深度强化学习:政策梯度。http://rail . eecs . Berkeley . edu/deeprlcourse/static/slides/LEC-5 . pdf

[4] McCaffrey,J.D. (2016)对数损失和交叉熵几乎相同。https://jamesmccaffrey . WordPress . com/2016/09/25/log-loss-and-cross-entropy-are-almost-same/

[5] Rosebrock,A. (2020)使用 TensorFlow 和 GradientTape 来训练 Keras 模型。https://www.tensorflow.org/api_docs/python/tf/GradientTape

[6] Ryzhov,I. O .,Frazier,P. I .和 Powell,W. B. (2010 年)。多臂土匪问题中一期前瞻策略的鲁棒性。Procedia 计算机科学,1(1):1635{1644。

Python 虚拟环境的极简方法

原文:https://towardsdatascience.com/a-minimalist-approach-to-python-virtual-environments-f5dacf76bfad?source=collection_archive---------13-----------------------

Python 虚拟环境对于数据科学家来说是一个非常有用的工具,但是有时候使用和管理它们会很痛苦。
当然,现在已经有很多管理虚拟环境的解决方案,为什么还要创建一个新的呢?
因为我是一个简单的人,喜欢简单的东西——不需要太多思考并且容易使用的东西,这样我就可以把注意力集中在更复杂的问题上。我发现大多数成熟的工具都是多余的,我需要一些我可以随意使用的东西。

虚拟环境快速介绍

虚拟环境有时会被误解,并且缺乏你为什么想要使用它们的背景。为了清楚起见,这里有一个超级简单的(虚构的)场景来说明为什么您需要使用虚拟环境。

一个虚构的例子
假设您正在本地机器上使用 awesome _ python _ package 版构建一个模型(免责声明:不是一个真正的包),并且您有以下代码行:

y = “one” + “two”
print(y)

显然, awesome_python_package 的开发者在版本 2.0 中做了一个更新,将数字串读取为数字。

现在想象一下,您已经完成了您的模型,并且需要将它部署到生产环境中,以便您的模型可以在现实世界中生活和玩耍。
但问题是这个生产环境没有使用awesome _ python _ package 2.0 版。它使用的是1.0 版,不幸的是1.0 版不具备将数字串读取为数字的能力。那么会发生什么呢?当您的代码试图在生产环境中运行时,它将返回一个错误,世界将真正结束。

这就是虚拟环境的用武之地。他们允许你在隔离的容器里工作

“电脑,这个项目请用 awesome _ python _ package 版”
-virtualenv

这样,当您在这个特定的项目上工作时(在虚拟环境中),您将使用正确的包版本。

总而言之,虚拟环境是一个干净、隔离的石板,你可以在这里安装项目所需的软件包和版本,而不会破坏世界。

我们得到了“为什么”,但是“如何”呢?

现在,我们已经了解了为什么要使用虚拟环境,让我们来讨论如何管理它们。
我们要用一个极简的命令行工具,叫做 venvtool。

设置

  1. 首先,如果你还没有 virtualenv,那么你需要安装它。
pip install virtualenv

你可以单独使用 virtualenv 工具,实现你所有最疯狂的虚拟环境梦想,但管理它们将取决于你自己。

所以下一步就是“极简主义”的部分了。

2.使用 venvtool 来帮助你管理你的虚拟环境
你可以在这里 下载 并按照说明进行设置。

使用 venvtool

一旦您运行 venvtool 的设置脚本,它将在您的主路径中创建一个目录,所有未来的虚拟环境都将存储在该目录中。现在你已经准备好创建你的第一个虚拟环境了。

vnv -c my_virtual_environment

现在您已经创建了您的虚拟环境,您可能会想要使用它。您需要使用以下命令来激活它:

vnv -a my_virtual_environment

您现在正在虚拟环境中工作。这是您可以开始使用 pip 安装所需软件包的地方。

当您完成了所有令人惊叹的建模并需要继续生活时,您可以使用以下方式停用当前的虚拟环境:

vnv -d

大功告成!
突然间,使用虚拟环境变得超级简单。它们都在一个地方,你只需几个命令就能与它们互动。
创建、激活和取消激活只是使用 venvtool 可以执行的几个命令。你也可以列出,复制和删除。

感谢您的阅读,并祝您在未来管理虚拟环境的努力中好运!

这里是 venvtool 的链接

对相关性的误解

原文:https://towardsdatascience.com/a-misinterpretation-of-correlations-147bd1164887?source=collection_archive---------55-----------------------

给定两个随机变量与第三个随机变量的相关性,我们知道它们的相关性是什么?

“x₂X₃ 都在 X₁ 增加时增加”;如果这些变量之间存在确定性关系,那么这样的陈述在逻辑上意味着当 X₃ 增加时, X₂ 也增加。然而,一旦我们转向概率设置,并在第一个陈述中添加副词“平均”,其含义就不再正确了!

三种情况

在概率设置中,s 是随机变量,“平均增加”相当于正相关。考虑一个简单的样本设置,并假设 X₁X₂ 之间的相关性和 X₁X₃ 之间的相关性相同并等于 0.5。要有一个直觉,两个相关性几乎等于 0.5 的随机变量的一个著名例子是一个父亲的身高和他儿子的身高。

对于我们的简单样本设置,有三种可能的场景:

  • 情景 1: 与我们的直觉一致, X₃增加x₂.增加

****图一。第一个场景。显示了 X₁ 、X₂和 X₃.的 1000 个样品每个图显示了一对随机变量之间的关系。

  • 场景二: X₂X₃ 不相关!

****图二。第二种情况— 1000 个样本。

  • ****场景三:出人意料的是, X₂X₃ 负相关!

****图 3。第三种情况— 1000 个样本。

基本结论:概率设置违背我们的直觉!但是,现在我们应该问一下,关于x₁X₂X₁X₃ 之间存在正相关关系的说法,是否有任何信息

有什么信息吗?

为了找到额外的信息,我们必须做一些更正式的分析。为此,让我们考虑相关矩阵

那么,我们问题的正式陈述是:给定σ₁₂和σ₁₃的值,我们能找到σ₂₃值的界限吗?答案是肯定的!

作为相关矩阵,σ需要正半定。利用这个条件,人们可以找到σ₂₃:值的以下(相对较弱的)界限

  • 每当σ₁₂和σ₁₃有相同的星座(即σ₁₂×σ₁₃>0):

  • 每当σ₁₂和σ₁₃有相反的符号(即σ₁₂×σ₁₃ <0):

The simple but interesting conclusion is that as long as we have (|σ₁₂|+|σ₁₃|)²> 2,我们至少可以肯定σ₂₃的符号;显然,对于我们的范例设置来说,情况并非如此。

数解

我们可以进一步找到,对于每一对σ₁₂和σ₁₃,σ保持正半定的σ₂₃的最小值和最大值。这些值在图 4 中显示为热图。右图显示了σ₁₃固定且等于 0.5 的情况下的界限,对应于热图上的虚线。第一部分中的三个不同场景由位于上限和下限之间的三个圆圈表示。

****图 4。左边和中间图:每对σ₁₂和σ₁₃.的σ₂₃的下限和上限虚线对应于σ₁₃=0.5.的情况右图:与热图上的虚线相对应的切片的 1D 图。第一部分中的三个不同场景由位于上限和下限之间的三个圆圈表示。

结论

一个快速而简单的结论是:除了极端情况(热图中靠近角落的情况),鉴于σ₁₂和σ₁₃.,我们不能说太多关于σ₂₃的情况

代码:

分析的代码(用 Julia 语言)可以在这里找到

脚注:

此处供参考。

对于感兴趣的读者来说,边界的推导仍然是一个练习。

高级管理人员的模型

原文:https://towardsdatascience.com/a-model-for-the-c-suite-2031a0cecc6d?source=collection_archive---------47-----------------------

量化 R&D 和营销支出的财务影响的贝叶斯网络

我们都见过一张抓住利益相关者观众的好照片。

让我们都注意到,前排右侧的女士并没有被黑板上的图像所吸引(照片由克里斯蒂娜@ wocintechchat.comUnsplash 上拍摄)

这种效果如此强烈,以至于爱德华·塔夫特以解构它为生。当一个伟大的视觉形象被用在演讲中时,它对整个团队有一种磁性的吸引力;它会引发讨论和深入研究(我认为在一次典型的会议中,对一张持续超过 30 秒左右的图片的关注就相当于深入研究)。在正确的上下文中,一些图表可以作为完整、独立的执行摘要。

网络模型提供了这种清晰和引人注目的可视化,使它们非常适合管理人员。但是这些模型不仅仅是一幅美丽的图画。它们是生成模型,允许使用高效的自动模型发现方法进行模拟和推理。在普遍接受的因果框架下,网络模型估计因果效应。这些属性中的任何一个都是值得使用的分析工具,但是在一个方法中拥有所有这三个属性是非常特别的

为了展示网络模型的威力,本文将通过一个简单的英特尔财务网络模型进行演示。我们主要关注净收入与研发和广告费用之间的联系。

下面就从简单的网络开始吧。

一个图形模型

在没有任何指导的情况下,我敢打赌你马上就能理解左边图片的关键点:每个命名的点(“节点”)是一个量,箭头(“边”)表示这些量之间的关系,你可能会猜到箭头是从原因指向结果的。

这些节点是英特尔财务报告以及公司关键市场之一的全球零售销售(单位)的最小框架。大多数标签是不言自明的,但 g&A 可能不是。它是从报告的广告、一般和管理费用行项目中计算出来的,减去广告支出以使广告支出与其他两项分开。这里的英特尔数据来源于在SEC.gov上发现的 28 份年度 10-K 申报文件,涵盖 1992 年至 2019 年。同年的全球个人电脑销量可以在维基百科ars technica 上找到。所有数值均以百万计,美元数值已根据通货膨胀调整为 2000 年的美元值。

在网络中,变量被标记为 _0,以表示所有这些都代表相同的时间步长;即该网络表示同一年中的值之间的关系。

使用 AIC 作为优化度量,通过带有重新启动和一些修整的简单爬山算法从数据中学习网络结构。我已经使用 R 的 bnlearn 包的 tabu()函数做到了这一点。这种方法速度很快(适用于大型网络),但不能保证找到真正的全局最优解。但这可以对我们有利,让我们有空间应用业务知识,并仍然获得一个不比“最优”模型差的模型。

网络模型的核心是显示变量之间的关系,甚至是非常复杂的关系。如果一个变量是一个可控制的数量(如广告支出),那么网络会显示哪些数量会因改变可控制的数量而受到影响。如果网络中的两个节点之间不存在路径(我们网络中的任何节点对都不是这种情况),那么这两个量在实际上(即我们不能改变一个来影响另一个)和概率上(即一个以另一个为条件的分布与第一个量的分布相同)都是相互独立的。如果两个节点之间确实有路径,则有证据表明关于一个节点的信息对另一个节点有影响。

在我们的示例网络中,我们可以看到 R&D 费用驱动除广告以外的所有其他价值,并且广告驱动净收入和总 PC 销售。虽然这本身很有趣,但我想我们都同意这是意料之中的。也许一个更难的问题是,广告和研究费用有持久(即多年)的影响吗?

这个模型很容易扩展来解决这个问题;我们简单地添加节点来覆盖前几年的值。我再给我们的模型加两年,看看会有什么结果。在下面的可视化中,后缀“_ 1”意味着在“_0”值之前 1 年的变量值。

多年网络:AIC = -3589

当你探索多年的关系时(标题中的链接将带你到一个互动图,可能有助于使关系更加可视化),你会看到去年的 R&D 和两年前的间接 R&D(通过前几年的净收入)的持续影响。

我们还发现,一年之内,每一层的关系都不一样——这让人觉得有问题。例如,如果年份是 2018 年,当前的广告支出会影响净收入。但一旦当前年份是 2019 年,2018 年的支出就不再影响 2018 年的净收入了?

坦白地说,这没有什么意义。因为我承诺了一个立即有意义的模型,我们需要用一些专家的建议来帮助结构学习算法。我建议保持所有年份中的年内关系与初始模型相同,并让年间关系通过算法来识别。这很容易做到,只需将一年网络的边缘作为白名单数据帧传递给 bnlearn 的结构查找函数。

单年关系守恒:AIC = -3584

现在我们看到原来的关系是守恒的。我们也看到更多年份之间的联系(这里每一层是一年)。更多的箭头意味着更多的参数,因此需要注意的是,这个修改模型的 AIC 非常接近自动学习模型的 AIC。

因此,这“证明”R&D 和广告支出具有持久的商业影响。这些职能部门的高管认为,今年削减预算会让业务在未来几年受到阻碍。

想必,任何想出名的高管团队都会立即跟进:“如果我们裁员,业务会受到多大影响?“幸运的是,我们的网络模型允许通过简单地设置这些决策节点的值、our(广告和 R&D 预算)以及对利益结果(比如净收入)的最终分布进行采样来进行推断和模拟。

如果模型中考虑了所有相关变量,那么随着决策节点值的变化,结果期望值的差异就是改变决策的因果影响。通过将 2019 年净收入的预期值与过去 3 年的实际支出水平进行比较,我们可以很容易地找到 R&D 和广告支出的历史因果影响。

嗯...是时候解雇市场部了?

嗯,这当然是一个意想不到的结果!一项快速调查显示,年内广告系数为正(如预期),但年间广告系数总是为负。我想我们可以这样合理化,即推动今年销售的广告正在窃取下一年的销售。。。但我们也可以注意到,第 0 年的广告支出与第 1 年和第 2 年的支出高度相关。这表明对给定净收入节点的当前和过去广告支出的估计受到共线性的不利影响。

有时,您可以使用高度相关的特征进行建模。有时候不行。

鉴于高相关性和不合理的估计,我们可以简单地禁止前几年的广告对当前净收入产生直接影响。这仍然为通过例如前几年的净收入进行间接影响留有余地。最终网络如下图所示。

去除年度间广告支出的弧线:AIC = -3607

AIC 低于我们的最后一个模型,所以我们没有破坏我们的模型删除违规的边缘!

现在,我们可以像以前一样应用同样的“关掉它”方法来获得 R&D 和广告效应对净收入的因果影响。这一模式显示出积极的影响,符合常识,并给 CMO 带来一些缓解。有趣的是,R&D 现在对收入的正面影响比以前大得多。所以大家都打算更喜欢这种模式!

每个人都保住了工作!

总结一下,让我们注意这里给出的模型是有意简单的,并且在某种程度上受到示例中使用的公开可用数据的限制。

为了方便起见,我们使用了 bnlearn 内置的拟合函数,该函数将连续变量限制为高斯分布。这不是网络模型的必要假设。更复杂的网络可能具有不同的节点分布(bnlearn 可以通过离散化连续变量来处理这个问题,其他软件可以直接模拟不同的分布)。此外(但不是附加的),节点之间的关系可以是非线性的,而在这些例子中,每个节点平均值是其父节点平均值的线性组合。

从分析角度来看,寻找 R&D 总支出的全球影响很难(也许资本支出和工作支出应该分开?也许大的计划应该用不同的持续时间分别建模?)或广告支出(随着时间的推移,B2B 和直接面向消费者的活动肯定会产生不同的效果吧?).也许我们需要更多的网络时间来解释长期的影响?几乎可以肯定的是,我们应该加入更多的外部因素(竞争对手的广告支出?服务器销售?计算机制造商的合并和收购活动?)添加到模型中,然后声称我们已经包含了影响净收入的所有相关变量。

但是我们的简化示例用来展示图模型的灵活性和实用性。在此过程中,它强调了像共线性这样的基本数据问题是多么重要,因为无论构建什么模型,它们都很重要。

我希望我已经使你相信了网络图本身的价值。对于获得观众对模特的认同来说,怎么强调都不为过。因为观众真的能看到模型,他们几乎立刻就能对它的推理感到舒服。

想象一下,在最后一次演示中,大部分对话都是关于你的建议,而不是你的模型是什么——这难道不是一个很好的转变吗?

这只狗展示了你和你的网络模型在一起会有多开心!(由德莱尼·道森Unsplash 上拍摄)

我将为此撰写一篇如何编写代码的配套文章,并在以后撰写关于其他方法的文章;请在媒体上关注我的最新消息。

Spark RDDs 的现代指南

原文:https://towardsdatascience.com/a-modern-guide-to-spark-rdds-725cd7c14059?source=collection_archive---------36-----------------------

作者照片。2011 年春天,西班牙阿尔特亚。

每天都有机会发挥 PySpark 的全部潜力

网络上充满了 Apache Spark 教程、备忘单、技巧和诀窍。最近,他们中的大多数人都在关注 Spark SQL 和 Dataframes ,因为它们提供了一个温和的学习曲线,具有熟悉的 SQL 语法,而不是旧的 RDD API 所需的陡峭曲线。然而,正是 rdd 的多功能性和稳定性点燃了 2015 年 Spark 的采用,并使其成为分布式数据处理的主导框架。

随着您成为 Spark 的正式用户,主要有三种情况会让您考虑 RDD API:

  • 访问原始非结构化数据源
  • 执行比 SQL 更适合通用编程语言的数据操作。避免 UDF
  • 并行执行第三方库

这份固执己见的材料涵盖了这种情况以及由此经常产生的问题,因此您可以充分享受 PySpark 的潜力。

目录

关于样式
垂直扩展您的函数式 python
将 Spark 类型附加到变量名

将数据帧转换成 rdd&反之亦然
数据帧到 RDD
RDD 到数据帧

富于表现力的 Python 字典
单行字典转换
Python 集合&字典不可修改

缓存&广播
缓存 RDDs
不持久化 RDDs
清理整个 RDD 缓存

Python 库的分布式执行
Numpy —一种通用方法
NLTK —分区设置

关于风格的一点注记

当函数式编程遇到大数据时,代码可读性尤其重要,一方面是因为传统的 IDE 调试工具是围绕命令式编程设计的,另一方面是因为为了调试目的而运行多个代码既昂贵又耗时。

垂直发展您的功能 Python

火花逻辑被定义为Dag。通过在每个转换动作之后用反斜杠“\”换行,保持代码的简洁以提高可读性。

将火花类型附加到变量名

分布式数据主要属于以下三种类型之一:

将数据帧转换成 rdd,反之亦然

数据帧的主干是一个 RDD[ ],一个 Spark 类型,其行为非常类似于 Python 字典。正如您在下面看到的,这个类型充当了两个 API 之间的桥梁。

RDD 的数据帧

  • 方法: Dataframe - > RDD【排】- > RDD【排】

RDD 到数据帧

  • 方法一:【字典】- > RDD【排】- > Dataframe

  • 方法 B: RDD【元组】- >数据框架

富有表现力的 Python 词典

随着 RDD 上的操作链越来越长,保持代码的可读性和逻辑的可理解性变得越来越困难。Python 字典在这方面起着关键作用。与 Scala 元组相反,它们允许通过名称而不是位置来访问字段,与 Scala Case 类相反,它们可以在没有外部定义的情况下内联创建。

单行字典转换

Lambda 函数在语法上被限制为单个表达式。在需要 RDD[dict]转换的常见场景中,考虑这些单行 lambdas。注意, **old_dict 导致了浅层复制,但是在 RDD 操作中不需要深层复制操作,因为 PySpark 保证了新字典是完全独立的,即rdd 是不可变的

Python 集合和字典是不可混淆的类型

诸如 groupByKeyreduceByKey 之类的 RDD 聚合要求密钥为可散列类型,以便进行混洗。因此,避免使用 Python 字典和集合作为混排键。如果必须的话,考虑使用 frozensets。

缓存和广播

学习如何定制 Spark 的分布式内存处理,可以为 ETL 和 ML 培训作业带来最佳的资源使用。此外,对于 JupyterZeppelin 笔记本来说,这也是快速流畅的 REPL 体验的关键要素。

缓存 rdd

持久化到内存的常见用例见 RDD.cache ,其他存储级别见 RDD.persist 。请注意,下面的行 4 设置了缓存指令,但只有像行 6 这样的动作才会触发 DAG 执行和随后的内存存储。

不持久 rdd

调用 RDD.unpersist 并从内存和磁盘中移除其所有块主要有两个原因:

  1. 你已经用完了 RDD。依赖于 RDD 的所有操作都已经执行,您想要释放存储空间,以用于管道或 ETL 作业中的后续步骤。
  2. 你想修改持久化的 RDD,这是在 Jupyter/Zeppelin 笔记本上工作时的一个常见用例。鉴于 RDD 是不可变的,您可以做的是重用 RDD 名称来指向新的 RDD。因此,如果上面的代码运行两次,您将在同一个 cached_rdd 的内存中得到两次分配。第一次运行后, cached_rdd 将指向下面的第一个分配,然后指向第二个分配,使第一个分配成为孤儿。

为了避免重复的内存分配,在初始化 RDD 的 Jupyter 段落前添加一个 try-unpersist (下面的第 1–4 行):

清理 RDD 缓存

取消所有 rdd 的持久性可以通过以下方式实现:

Python 库的分布式执行

RDDs 的灵活性允许在运行几乎任何 Python 代码时分发有效负载。对于计算成本较低的任务,如 O(n) 及以下任务,需要真正的大数据才能让并行化的优势显而易见。然而,对于线性以上的复杂性,并行化可以轻松地将中型数据作业的几小时变成几分钟,或者将小型数据作业的几分钟变成几秒钟。

Numpy —一种通用方法

为了并行执行库,如 statsmodelsscikit-learnnumpy ,只需从一个映射平面映射过滤器或任何其他转换内部调用它们。在下面的例子中, np.median 调用在 RDD 映射中,因此,它将在每个 Spark 执行器中本地运行:

NLTK —分区设置

除了导入之外,自然语言工具包( NLTK )库还需要进一步设置。下面例子中的 nltk.download 调用必须在的每个执行器中运行,以保证本地 nltk 数据的可用性。在这种情况下,考虑使用 RDD.mapPartitions 来避免在同一个执行器中对 nltk.download 的多余调用。RDD 映射分区调用允许对每个分区的 RDD 条目的整个列表进行操作,而 RDD 映射/平面映射/过滤器对每个 RDD 条目进行操作,并且不提供该条目属于哪个分区的可见性:

…更多章节即将推出。

生物多样性和恢复的多边人工智能策略

原文:https://towardsdatascience.com/a-multilateral-ai-strategy-for-biodiversity-and-restoration-422ca8f70515?source=collection_archive---------26-----------------------

南非图乌斯河阿奎拉野生动物园私人禁猎区图片来自— @bellaskova

我们必须质疑现有的国际战略,并在人工智能领域达成新的共识

摘要

我们星球上的动植物物种正在迅速消亡。我们在与人工智能相关的战略中没有更多地关注这一点,这似乎很奇怪,但考虑到对少数拥有专业知识的开发人员进行人工智能开发和运营的财务吸引力,这也就不足为奇了。我们可以用人工智能来分析生物量;减轻线性基础设施的影响;以及通过监测进行海洋保护。我们必须问自己这样一个问题:我们是否在以正确的优先级使用人工智能。葡萄牙的国家人工智能战略是为数不多的谈到“人工智能促进生物多样性,从森林和绿色经济到海洋物种和蓝色经济”的国家战略之一。他们将此作为第三个优先考虑的方面,但我们必须考虑是否应该在我们的全球议程上进一步推进这一点。恢复我们的环境需要在技术行业和其他部门进行同样的多边合作,作为解决日益增多的问题的综合方法的一部分。

人工智能最明显的用途似乎是用于进一步的提取、消费和生产。然而,在气候危机中,随着生态系统的恶化,物种正在死亡。我绝对没有提出人工智能可以成为帮助我们恢复地球的神奇银弹(远非如此),然而当所有这些策略被制定时,我发现很少有人提到使用人工智能来恢复环境是很奇怪的。

大多数珊瑚礁正在死亡:

[## 所有的珊瑚礁都可能在 80 年内死亡

一项新的模拟显示,到 2100 年,可生存的珊瑚地点将几乎全部消失。科学家们正竞相保存…

www.popularmechanics.com](https://www.popularmechanics.com/science/a31024955/coral-reef-restoration-sites-climate-change/)

造成损失的原因是多方面的。

[## 物种灭绝的驱动因素本质上是多方面的

联合国环境规划署执行主任英格·安德森在第 18 届……

www.unenvironment.org](https://www.unenvironment.org/news-and-stories/speech/drivers-species-loss-are-multilateral-nature)

物种数量急剧减少:

IUCN(2012)记录的已灭绝或已灭绝的野生脊椎动物累计物种,摘自 科学进展 的研究文章。

有计划正在进行,试图减少物种的损失。

我以前曾思考过,如何从启发性的角度考虑人工智能,从超越人类的更广阔的角度来看,人工智能更负责任:

[## 以地球为中心的人工智能方法

让人工智能为我们的共享生态服务

medium.com](https://medium.com/@alexmoltzau/a-planet-centered-approach-to-artificial-intelligence-a33de6bc7d44)

其他时候我问人工智能的和平战略在哪里:

[## AI 和平战略在哪里?

对国家人工智能战略症结的简短思考

towardsdatascience.com](/where-is-the-ai-strategy-for-peace-a89c1c681fe9)

这些问题似乎没有得到应有的重视。

那么为什么这不是重点呢?

我们投资保持健康,投资能源。

人工智能人才也被吸引到各种其他领域。

也就是说,在许多其他行业,你会发现更多的资金,如开采。

我最近问一位人工智能高管,为什么我们不更多地关注这个领域。

简单的回答是:“这个领域几乎没有钱。”

生物信息学领域最聪明的人可能会去制药行业。

地球观测或石油工业地质学方面的最佳人选。

如果你擅长自动化和机器人技术——采矿就有机会。

如此等等,我可以继续下去。

当然,也有人选择超越这些界限,选择一个潜在的低工资级别来解决与自然相关的问题,以保持生物多样性。我并不是说能效不重要,而是说编程领域的不同人才可能会在薪酬最高的行业中选择有趣的问题。

这没有什么新奇的。在阳光下没有什么是新的,因为在实现我们社会中提出的规范方面,人才可能会走有利于他们的更高程度的道路。

另一方面,我确实希望我们能够在自动化恢复工作方面投入更多的精力。

尽管我们必须确保这需要技术行业全心全意地努力,以确保更好地利用基础设施,并让技术用户意识到大量数据与物理产品相关的足迹。

[## 气候危机&为什么数据不能成为新的石油

人工智能和数据存储的足迹

towardsdatascience.com](/the-climate-crisis-why-data-must-not-become-the-new-oil-32d2429b8657)

生物量分析

认为我们可以用 BIODISCOVER 机器自动给昆虫分类是有希望的。来自 Tempere 大学、芬兰 Jyvaskyla 大学、丹麦奥尔胡斯大学和芬兰环境研究所的科学家团队设计了一种可以自动拍摄和分析昆虫的机器人。我在杰克·克拉克的人工智能时事通讯中读到了这些消息:

他们写道:“我们提议用一种基于图像的自动技术来取代人类专家分类和识别的标准手动方法”。“可靠的物种鉴定至关重要,但由于其固有的缓慢性和高成本,传统的手动鉴定在生物评估过程中造成了瓶颈”

[## 基于图像的无脊椎动物自动识别和生物量估计

了解生物群落如何响应环境变化是生态学和生态系统的一个关键挑战…

arxiv.org](https://arxiv.org/abs/2002.03807)

其他领域也取得了进展。然而,我们知道我们对这个星球上的其他物种做的事情并不幸运。

减轻线性基础设施的影响

人们可以想象在一个给定的区域追踪野生动物的可能性,以确定实施一个项目是否可行,这已经在做了。缓解物种沿

联合国在《需求》中提到了减轻公路和铁路等线性基础设施对移栖物种影响的工具的指导和实施。

[## 联合国关于野生动物的重要会议旨在解决对迁徙物种的严重威胁

2020 年 2 月 17 日,甘地讷格尔----联合国防治荒漠化公约缔约方大会第十三次会议

www.unenvironment.org](https://www.unenvironment.org/news-and-stories/press-release/major-un-meeting-wildlife-address-critical-threats-migratory-species)

通过监测保护海洋

在国家捕鱼作业中进一步实施减少海洋哺乳动物副渔获物的措施。机器学习在这个领域的应用。有一些利用人工智能来保护濒危物种的项目。

[## NOAA 将使用微软人工智能推进濒危物种保护

国家海洋和大气管理局的研究科学家正在开发人工智能…

www.nextgov.com](https://www.nextgov.com/emerging-tech/2020/02/noaa-use-microsoft-ai-advance-protection-endangered-species/163208/)

倾听虎鲸的声音:

[## 谷歌的新人工智能模型“倾听”虎鲸的声音,以帮助保护该物种

谷歌的人工智能团队开发了一种新的模式来保护濒危物种虎鲸,在世界上被称为虎鲸。

thenextweb.com](https://thenextweb.com/artificial-intelligence/2020/01/29/googles-new-ai-model-listens-to-killer-whales-to-help-protect-the-species/)

识别非法拖网渔船:

[## 从太空捕捉工业捕鱼侵入非洲近海水域

小规模渔业为沿海社区提供了生计和…

onlinelibrary.wiley.com](https://onlinelibrary.wiley.com/doi/abs/10.1111/faf.12436)

AI 有哪些重要的应用?

我们必须批判性地问自己,我们如何才能让人工智能以更深刻的方式发挥作用,而不是在错误的方向上跑得更快。我确实认为,如果我们选择将这些想法付诸行动,我们就能有所作为。然而,与这些方面有关的问题不仅仅是地方性的,而是国际性的,需要多边合作。

考虑到葡萄牙的战略已经将重点放在了生物多样性上,葡萄牙可以在这方面起带头作用:

[## 葡萄牙的国家人工智能战略

环境和生物多样性的人工智能:从森林和绿色经济到海洋物种和蓝色…

medium.com](https://medium.com/dataseries/portugals-national-ai-strategy-747b39671f2c)

战略中概述的生活实验室七个方面中的第三个方面:

㈢人工智能促进生物多样性,从森林和绿色经济到海洋物种和蓝色经济;

我认为这应该是当务之急,因为如果我们要恢复和考虑更广泛的经济影响以及更大的长期生态责任,这必须被推到议程的更高位置。

这是#500daysofAI,您正在阅读第 261 条。500 天来,我每天都在写一篇关于或与人工智能相关的新文章。我目前 100 天 200-300 的重点是人工智能的国家和国际战略。

一堂音乐课来理解数据科学到底是怎么一回事

原文:https://towardsdatascience.com/a-music-lesson-to-understand-what-data-science-is-really-all-about-c34496c8cb26?source=collection_archive---------57-----------------------

弹吉他如何教会我最重要的原则

达米尔·科佩扎诺夫在 Unsplash 上拍摄的照片

有时候现实只会给你一记耳光。当这种情况发生时,你不能回击,因为(a)你太害怕/惊讶/没有准备,(b)现实没有一张你可以回击的脸…所以你基本上完蛋了。除非你意识到事实上有一课要学。

我作为一名音乐家开始了我的职业生涯,如果世界上有任何一群人有故事要讲...嗯,是音乐家。所以看看这个:

一个太过年轻的我正站在舞台中央,身边有三名经验丰富的爵士乐手(鼓、贝斯、钢琴)随行,等着我开始表演,这样我就可以展示我的才华了。手心冒汗,脖子上挂着电吉他,想做点脑瑜伽让思绪平静下来。这是我的机会(事实上这是我唯一的机会)来证明我足够优秀,可以获得一所著名的爵士学校的奖学金,我知道我必须展示自己。

我也做好了准备。至少我是这么认为的。我在商店买了挂在墙上的别致吉他,漂亮的皮带,很酷的电缆(带静音按钮等等),甚至还有一个大功率的功放。我也记住了所有的音阶,“正确的”音符(不管那是什么意思)和和弦。我的意思是,会出什么问题呢?事实证明,一切都是。

伯爵来了,那些该死的爵士乐手跑得比牙买加短跑运动员还快:踩镲好像要从架子鼓里飞出去了,行走的低音好像在跑,钢琴看起来好像要掉几个键了。我呢?我困惑地盯着看了一会儿,无法开始弹奏,直到事情变得有点尴尬,钢琴师问“兄弟,你要弹吗?”

所以我做了正常人在经历大脑完全冻结时会做的事情:我让自己出丑了。到处都是笨拙的音阶(那不起作用),然后是一些和弦(那实际上使它变得更糟),最后我干脆完全停止了演奏。最后,伴奏的音乐家也停下来了,我被迫走了一生中最长的一段路,从舞台走到门口。但是现实还没有结束。

走出门,看见一个音乐学院的同学,坐在走廊上,打着冷颤,抽着烟。他问礼堂里发生了什么,我告诉了他试镜的情况,他回答说:“嘿,也许我可以试一试。我可以用你的吉他吗?”仍然羞愧震惊,不知道还能做什么,我把吉他递给他,他走了进来。

陪同的演奏者数到四,我简直不敢相信自己的耳朵:这个穿着糟糕、气味难闻、在走廊里抽烟的家伙听到了这首歌的前两个和弦,并且知道该怎么做。他接着演奏了我在现场听过的最好的爵士乐独奏曲之一。说真的。他用我的吉他做的!!你在开玩笑吗?这个家伙甚至不知道有试镜,显然没有准备,他仍然设法无耻地踢我的屁股,同时微笑着,看起来很享受。

不用说,我从来没有成为一个专业的爵士乐吉他手。

那么,这和数据科学有什么关系呢?

佩德罗·拉斯特拉Unsplash 上的照片

一晃 12 年过去了,我戴着口罩走在巴黎的街道上,听着“走向数据科学”播客。我已经从(不太耀眼的)爵士乐时代转行到大众媒体消费数据分析师的工作。在那一集里,Jeremie 向他的客人 Goku Mohandas 询问了他从一个非计算机类领域到数据科学的转变,以及他是否建议人们从一开始就专注于计算机科学。虽然莫汉达斯证实了对纯计算机专业人员的需求,但他关于从另一个领域过渡到数据领域的人的实际推理让我突然停下了脚步:

“我强烈建议你要么选择计算机科学之外的其他小众专业,要么根本不要选择计算机科学作为专业,因为你可以在业余时间学习它……所以也许你可以专注于你希望产生影响的行业,然后将数据科学作为一种工具,而不是作为一个行业本身”。

等等。什么?他建议我们不要学习计算机科学?在过去十年的大部分时间里,我都希望自己“更有效地利用了时间”,学习计算机,而不是……不管我在那些年里做了什么。我想“如果我早几年学会编程,或者学习计算机科学或应用数学,我在数据方面的职业生涯会发展得更快更轻松”。然而,这位嘉宾在我最喜欢的播客中说这正是你不应该做的?我不明白。

然后,我明白了

回到我的爵士乐大师朋友那里,我意识到我和他之间有一个根本的不同。那个家伙明白爵士乐是怎么一回事。站在舞台上,他停顿了几秒钟,听了听其他音乐家在演奏什么,并准确地知道一场伟大的演出需要什么。不需要任何花哨的玩具,只需要对爵士音乐领域的纯粹理解。

我吗?嗯,我有所有很酷的东西:漂亮的吉他,功放,皮带…我几乎是一个移动的音乐商店。但是我一点也不知道要演奏好一首爵士乐独奏需要做些什么。我也想听听其他人在演奏什么,但就是无法理解或诊断这种情况。底线是,我有好玩具,但另一个家伙有诀窍。在专业圈子里有一个名称:它叫做领域知识,这正是悟空莫汉达斯所说的。你知道为什么这很重要吗?因为它为你提供了最重要的技能:问正确问题的能力

数据科学到底是什么

照片由路易斯·汉瑟@shotsoflouisUnsplash 拍摄

如果你问了错误的问题,你就会得到错误的答案。问题是,要问正确的问题,你需要知道你到底在说什么。否则,你只是一个在舞台中央拿着吉他的白痴,希望你能穿上哈利波特的隐身衣(或者不管它叫什么。我没有哈利波特领域的知识…)

数据科学不是闪亮的玩具。这与工具无关,就像音乐与吉他、扩音器或皮带无关一样。当你学习编码,或解偏导数,或训练一个卷积神经网络时,你不会成为一名数据专家。别误会,那些东西都是必须的,但不会让你变成真正的数据问题解决者。

有趣的问题只有当你问一些与你是专家的特定领域相关的聪明的问题时才会浮出水面。基本上,就像我的吉他手朋友一样,只有当你能“听到歌曲的前两个和弦,并确切知道该做什么”时,你才成为真正的解决数据问题的英雄。

从本质上来说,数据科学是数百年研究工艺的现代版本。每一个好的研究是如何开始的?带着一个好问题!

从第一个试图找出如何不被猛犸象吃掉的人开始,到计算机视觉的发展以及其间的一切,研究一直围绕着 4 件事:

(1)提出与你在现实生活中看到的问题相关的好问题(学术界称之为“现象”)

(2)找出是否有人已经回答了这些问题(学术界称之为“文献综述”)

(3)如果没有人回答这些问题,开发一个逻辑过程来自己寻找答案(学术界称之为“方法论”和“经验证据”)

(4)与他人分享那些答案(这是研究期刊最初存在的原因)。

就是这样!

这不也是我们数据极客一直在努力做的事情吗???去看看你在大学读过的那本书上的“数据挖掘过程”的图片(他们都有类似的东西)。难道真的不能归结为这个吗?当艾萨克·牛顿看到苹果从树上掉下来的时候,他不就是这样做的吗?唯一不同的是,他是用铅笔和纸做的,而我们每天都像疯子一样敲着电脑键盘。不相信我?做以下事情:在网上查看任何学术期刊,阅读其中一篇文章,问问自己结构是否符合我刚才提到的内容。我给你省点时间:的确如此。

现在,注意研究过程是如何开始的:问题。问题是,只有当你了解这个领域时,你才能提出好的问题,这就是领域知识如此重要的原因。

让我给你举个例子:大约一年前,我带我的女朋友去看了她的第一场足球比赛。这位女士对足球一无所知,她惊讶于周围的每个人都注意到了她没有注意到的事情。到了一个队进了一个球,3 万人起立庆祝,她都不知道怎么回事。我不得不说“嗯,这是你站起来像个疯子一样尖叫的部分”。所以她就这样做了。这不是她的错,她只是零领域知识(另一方面,每当我们有一个关于法律和人权的讨论,她摧毁我。只是她的领域)。

我想强调的一点是:数据科学是为了找到有趣问题的答案而进行研究的艺术和工艺。但是开始这个过程的要素是“问正确的问题”部分。为此,您需要领域专业知识。这就是为什么你应该将数据科学视为一种工具,让你能够解决你所关心的特定领域的问题。

世界的主要需求不是知道如何编码或做复杂数学的人(已经有太多这样的人了)。它迫切需要的是对自己的领域充满热情的人,他们知道自己在说什么,并利用数据科学来解决该领域的问题(如果你也是代码和数学天才,那就更好了)。

所以,如果你学过生物学、建筑学或任何其他很酷的学科,那就好好利用吧!当然,你仍然需要学习数据科学和计算机的技术方面,但是你比那些对这些东西一无所知的人(比如我)有巨大的优势。

回到一切开始的地方

听了那期播客集,我改变了对自己过去音乐生涯的看法。正如我大学时的一位教授曾经告诉我的那样:“如果你为你热爱的事情奉献了这么多年,那么你就有天赋。不要放弃。用吧”。

我的思绪不断回到我的童年,那时我开始热爱音乐,我在房子里跑来跑去,玩玩具吉他。它让我想起了我喜欢的事情,以及在某种程度上,它们如何赋予我作为数据专业人员的日常工作以意义。

我希望你也能抓住你内心深处的东西,利用数据科学在这些领域取得重要进展。如果你曾经怀疑过,请记住至少你从来没有像个白痴一样站在舞台上。

机器学习工具箱的必备算法:XGBoost

原文:https://towardsdatascience.com/a-must-have-algorithm-for-your-machine-learning-toolbox-xgboost-3e295cf8d69b?source=collection_archive---------39-----------------------

图片来自 Pixabay维基图片

最高效的机器学习算法之一

XGBoost 是一种监督学习算法,可用于回归和分类。像所有的算法一样,它有它的优点和吸引人之处,我们将会详细介绍。

在这篇文章中,我们将从分类问题的上下文中学习 XGBoost。对于回归部分,请务必关注我在 datasciencelessons.com 的博客。

监督学习赶上来

我不会在这里深入探讨,但是对于那些需要快速复习监督学习的人来说;监督学习是指当你头脑中有一个你想要预测的特定事物时。例如,你想预测未来的房价;所以你有了你想要预测的东西,下一步就是标记历史数据作为预测未来的手段。为了更深入地研究这个例子;比方说,你想卖掉你的房子,但想知道你应该付多少钱,你可以潜在地积累关于房子的数据点,以及在同一时期它们的销售价格。从这一点出发,您将训练一个模型,您将把关于您自己住宅的数据点传递给该模型,以生成关于您住宅价值的预测。对于分类的例子,你的预测类;比方说你的 Gmail 和想要预测垃圾邮件…这需要一个模型来训练许多被“标记”为垃圾邮件的电子邮件以及相应数量的未被“标记”为垃圾邮件的电子邮件。

到底是什么?

XGBoost 使用的是所谓的系综方法。在不深入研究集成方法的情况下,XGBoost 的独特之处在于它如何利用许多模型的输出来生成预测!XGBoost 利用所谓的“弱学习者”来培养“强学习者”。

XGBoost 过程看起来像这样:

  • 它迭代地训练许多弱模型
  • 根据性能对每个预测进行加权
  • 结合许多加权预测,得出最终输出。

是什么让 XGBoost 如此受欢迎?

  • 准确(性)
  • 速度
  • 该算法很好地利用了现代计算,允许其并行化
  • 持续优于其他算法

您的第一个 XGBoost 模型

我们来分解步骤吧!

  • 您将从用 python 导入 XGBoost 包开始
  • 分别用 y 和 X 分解你的因变量和自变量
  • 分解列车测试分裂
  • 实例化您的分类器
  • 训练你的分类器
  • 预测测试集的 y
  • 评估准确性!

在这个例子中,我们将对泰坦尼克号上的幸存者进行分类。

import xgboost as xgb from sklearn.model_selection 
import train_test_splitX, y = titanic.iloc[:,:-1], titanic.iloc[:,-1]X_train, X_test, y_train, y_test= train_test_split(X, y, test_size=.2, random_state=44)xgb_model = xgb.XGBClassifier(objective='binary:logistic', n_estimators= 7, seed=44)xgb_model.fit(X_train, y_train) pred = xgb_model.predict(X_test)accuracy = float(np.sum(pred == y_test)) / y_test.shape[0]

干得好!这是一个伟大的第一次传球!让我们学习更多关于如何评估模型质量的知识。

评估绩效

我们已经在上面的代码片段中看到了准确性,但是还有混淆矩阵的其他方面,精度和召回。我不会在这里谈论这两个,但如果你想了解更多信息,请跳转到关于随机森林算法的这篇文章:https://datasciencelessons . com/2019/08/13/random-forest-for-class ification-in-r/

除了这些,我想说一下 AUC。

简单来说;如果您选择一个正数据点和一个负数据点,AUC 是正数据点比负数据点排名更高的概率。

XGBoost 允许您运行交叉验证测试&在核心算法调用本身中指定您关心的指标。这部分是通过创建一个叫做 dmatrix 的数据结构来完成的,这个数据结构由 X & y 值组成。

这次的核心区别是,我们将创建一个 dmatrix,指定模型的参数,然后生成一个输出,其中我们将指标指定为 AUC。

titanic_dm = xgb.DMatrix(data=X, label=y)params = {"objective":"reg:logistic", "max_depth":3}output = xgb.cv(dtrain=titanic_dm, params=params, nfold=3, num_boost_round=5, metrics="auc", as_pandas=True, seed=123)print((output["test-auc-mean"]).iloc[-1])

你应该多久使用一次?

XGBoost 并不是每次你需要预测什么的时候都要用。但是,在适当的情况下,它会非常有用:

  • 你有很多训练数据
  • 你不仅有分类数据,还有数值和分类变量的混合,或者只有数值变量。

你肯定希望 XGBoost 远离计算机视觉和 nlp 相关的任务…或者如果你有一些非常有限的数据。

一如既往,我希望这证明对您的数据科学工作有用!一定要看看我在 datasciencelessons.com 的其他帖子!

祝数据科学快乐!

每个数据科学家的必备工具

原文:https://towardsdatascience.com/a-must-have-tool-for-every-data-scientist-5e7c76f1916f?source=collection_archive---------10-----------------------

TensorDash——一款远程监控机器学习模型的应用

卢克·切瑟在 Unsplash上的照片

让我们面对它;训练一个机器学习模型是非常耗时的。即使在过去几年中计算能力有所提高,训练机器学习模型也需要很多时间。即使是最普通的模型也有超过一百万个参数。在更大的范围内,这些模型有超过 10 亿个参数(GPT-3 有超过 1750 亿个参数!),训练这些模型需要几天,如果不是几周的话。作为一名数据科学家,我们希望关注模型的指标,以了解模型是否按照预期执行。但是坐在你的电脑旁边,几个小时监控这些指标是没有意义的。如果我们能在你的手机上得到所有这些数据,那不是很好吗?

你最后一次让你的模型训练几个小时然后离开那个地方,但是当你回来的时候你的模型已经中途坠毁了是什么时候?这令人沮丧,完全是浪费时间。由于大多数人没有能力在本地训练机器学习模型,所以像 GCP、谷歌实验室、AWS 和 Azure 这样的云服务是用户按使用付费的首选。在这种情况下,如果模型在训练过程中崩溃了,你就要为没有使用的服务付费。如果你被告知你的模特身份,这将有助于你避免 FOMO。

TensorDash

TensorDash 是一款免费使用的开源应用程序,可以让你通过所有指标的详细图表来远程监控你的机器学习模型。它还会在训练完成或模型崩溃时通知您。它支持所有主要的机器学习框架,如 TensorFlow、Pytorch、Keras 和 Fastai。

现在你不必紧张地坐在电脑前,祈祷精确度提高。你可以在家里舒舒服服地做这件事。

TensorDash 示例(图片由作者提供)

使用 TensorDash

  1. 从 play store 安装 TensorDash 应用程序。对 iOS 设备的支持即将推出。
  2. 创建一个帐户。
  3. 使用命令pip install tensor-dash安装 TensorDash python 包。
  4. 按照下面的说明将 TensorDash 用于您各自的框架。

Keras/tf.keras 支持

Keras 和 tf.keras 的远程监控使用回调函数。进口 Tensordash。使用模型名称、您的帐户电子邮件 ID 和密码作为参数来定义 TensorDash 对象。通过 fit()函数中的回调来传递 TensorDash 对象。要在模型崩溃时得到通知,请在异常处理下添加 fit()函数,并在 except 中调用 sendCrash()方法。

下面是在 Keras/tf.keras 上使用 TensorDash 的示例代码

示例 Keras/tf.keras 代码

PyTorch 支持

从 Tensordash 包中导入 Torchdash。创建一个 Torchdash 对象,将模型名称、电子邮件 ID 和密码作为参数。使用训练循环中对象的 sendLoss()方法将模型指标发送到您的帐户。将损失、准确性、验证损失和验证准确性度量作为参数传递(请注意,您必须至少添加一个度量)。要在模型崩溃时得到通知,请在异常处理下添加训练循环,并在 except 中调用 sendCrash()方法。

下面是在 PyTorch 上使用 TensorDash 的示例代码

PyTorch 代码示例

Fast.ai 支持

fast.ai 的远程监控通过回调来实现。进口 Fastdash。使用模型名称、您的帐户电子邮件 ID 和密码作为参数来定义 Fastdash 对象。通过 fit()函数中的回调传递 Fastdash 对象。要在模型崩溃时得到通知,请在异常处理下添加 fit()函数,并在 except 中调用 sendCrash()方法。

下面是使用 Fast.ai 的样例代码

fast.ai 代码示例

张量流支持

从 Tensordash 包导入 Customdash。创建一个 Customdash 对象,将模型名称、电子邮件 ID 和密码作为参数。使用训练循环中对象的 sendLoss()方法将模型指标发送到您的帐户。将损失、准确性、验证损失和验证准确性度量作为参数传递(请注意,您必须至少添加一个度量)。要在模型崩溃时得到通知,请在异常处理下添加训练循环,并在 except 中调用 sendCrash()方法。

请注意,Customdash 可以与任何指定自定义训练循环的框架一起使用。

下面是在 TensorFlow 自定义循环上使用 TensorDash 的示例代码

样本张量流代码

结论

TensorDash 是完全免费和开源的。欢迎发布和投稿。点击这里查看存储库,点击这里查看详细文档

我和 Harshit Maheshwari 建立了这个工具来解决我们在人工智能研究期间的监控问题。我希望这能像帮助我们一样帮助你。

关于我

我喜欢写一些在人工智能中很少被谈论的话题。关注我,了解最新动态。

你可以在 TwitterLinkedInGithub 上找到我。

创建封闭域聊天机器人的朴素贝叶斯方法!

原文:https://towardsdatascience.com/a-naive-bayes-approach-towards-creating-closed-domain-chatbots-f93e7ac33358?source=collection_archive---------19-----------------------

机器学习|自然语言处理

顾名思义,聊天机器人是一种设计用来进行对话或讨论的软件。它们被广泛应用于各种行业,以实现各种功能,从提供客户服务到协助治疗,再到仅仅是一种乐趣。

亚历山大·奈特Unsplash 上拍照

你有没有在网上订餐时寻求客户支持帮助的经历?你的第一次互动很有可能是和聊天机器人。许多公司使用基于规则或基于检索的聊天机器人,这些机器人是为特定主题训练的,这些被称为封闭域聊天机器人。例如,如果您想查看您的航班状态,您可以像这样聊天:

在上面的对话中,chatbot 给出了一个对它来说最有意义或与所提问题非常相似的回答。这个聊天机器人是专门为处理客户报告或航班查询而训练的。

当基于检索的聊天机器人使用意图分类、实体识别和响应选择来进行真实对话时,基于规则的聊天机器人使用 RE(正则表达式)模式来匹配输入用户响应和它被训练用来与人进行对话的响应。

朴素贝叶斯方法介绍!

有一种简单有效的方法来创建使用朴素贝叶斯分类器的封闭域聊天机器人。在该方法中,形成包含问题/用户响应和相应答案的封闭域数据集,其中每个问题/用户响应被给予一个标签,该标签将问题与其答案相关联。因为多个问题可能有相同的回答,所以可能有多个问题有相同的答案。为了拨开云雾,让我们看看这个例子。

hi there 1
hello how are you 1
what is your name 2
who are you 2
you are who 2
my name is 2
how old are you 3
what is your age 3
are you getting older 3
what about your age 3

末尾的标签/数字只是答案数据集中答案的索引。

Hi there, how are you !?
My name is etcetera, but you can call me etc.
I'm 22 years old

前两个问题包含标签“1 ”,因此它们指的是回答“嗨,你好吗!?'。同样,后四个问题指的是‘我 22 岁’。

这里的概念是朴素贝叶斯分类器将根据我们给它的输入来预测标签。因此,当你说“嗨”时,我们的分类器将预测标签“1”,反过来我们可以用它来找到一个合适的答案。当输入是“你的年龄是多少?”分类器会预测标签‘3’,这是答案‘我 22 岁’的一个索引。

下图将消除你对这个概念的任何疑虑。

解释系统流程的图

现在让我们进入编码部分!

准备培训数据

如果我们在一个名为“que.txt”的文件中设置了如上格式的问题,在一个名为“ans.txt”的文件中设置了答案,我们可以借助以下代码准备包含问题、标签和答案的单独列表:

labels = []
questions = []
for line in open('que.txt', encoding="utf8"):
    labels.append(line.strip().split(" ")[-1])
    que.append(" ".join(line.strip().split(" ")[:-1]))
answers = []
for line in open('ans.txt', encoding="utf8"):
    ans.append(line.strip())

每个标签都在问题的最后,我们可以如上图获取。在此之后,我们将在一个名为“问题”的列表中包含所有用于训练的问题,并在一个名为“标签”的列表中包含这些问题的标签。记住,问题的标签把它们和它们的答案联系起来。“答案”列表中会存储所有可能的答案。

注意:在这里,问题末尾的标号从 1 开始,但是为了将它们映射到‘答案’列表中的答案,我们必须从标号中减去 1,因为 python 列表索引从 0 开始。

现在,我们需要将我们的训练问题转换成向量,以便将它们提供给我们的分类器。为此,我们将使用来自机器学习库 sci-kit learn计数矢量器。下面是执行此操作的代码片段:

from sklearn.feature_extraction.text import CountVectorizer
bow_vectorizer = CountVectorizer()
training_vectors = bow_vectorizer.fit_transform(questions)

bow_vectorizer 中的‘bow’代表单词包。CountVectorizer() 的 fit_transform() 方法做两件事:1 .2)训练特征字典—训练语料库中所有唯一单词的字典。)将每个问题转换成特征字典大小的向量,该向量在除了问题中使用的单词之外的所有地方都包含零

如果你没有理解上面的解释,让我们举个例子。

#our sentence
sentence = “Help my fly fish fly away”#example features dictionary based on the training corpus
features_dictionary = {'all':0,'my':1, 'fish':2, 'fly':3, 'away':4, 'help':5, 'me':6, 'open':7}#Our vector for the sentence above will be
vector = [0, 1, 1, 2, 1, 1, 0, 0] 
#size of vector = size of features dictionary

特征字典包含来自训练语料库的所有唯一单词作为关键字,以及它们的索引作为值。“fly”这个词在我们的句子中出现了两次。如果我们查看“fly”的特征字典,我们发现它的索引是 3。所以,当我们看向量时,我们希望索引 3 处的数字是 2。如上所示, CountVectorizer() 为我们的问题提供了向量。

注意:这里,我们在一个包含 10 个答案和 37 个问题的非常小的数据集上训练我们的分类器,只是为了保持简单。尺寸可以根据不同的应用而不同。

进入培训部分

现在我们有了训练向量,是时候创建我们的朴素贝叶斯分类器了。为此,我们将使用 sci-kit learn 的 MultinomialNB()

from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(training_vectors, labels)

我们使用训练我们的分类器。fit() 方法,传入训练向量和相应的标签。

现在,我们的分类器可以进行预测了。我们可以从用户那里获取输入,在我们之前创建的矢量器的帮助下将其转换为矢量,并从我们的分类器中获得标签的预测。

创建聊天机器人类

是时候创建一个聊天机器人类了,它包含了进行对话的所有方法。 start_chat() 方法是开始谈话。 chat() 方法检查退出命令,如“退出”或“再见”,如果在用户的响应中发现任何这些词,就停止对话。

class ChatBot:
  exit_commands = ("quit", "pause", "exit", "goodbye", "bye", "later", "stop")
  def start_chat(self):
    user_response = input("Hi, I'm a chatbot trained on random dialogs!!\n")
    self.chat(user_response)

  def chat(self, reply):
    while not self.make_exit(reply):
      reply = input(self.generate_response(reply)+"\n")
    return

  def generate_response(self, sentence):
    input_vector = bow_vectorizer.transform([sentence])
    predict = classifier.predict(input_vector)
    index = int(predict[0])
    print("Accurate:",str(classifier.predict_proba(input_vector)[0][index-1] * 100)[:5] + "%")
    return answers[index-1]

  def make_exit(self, reply):
    for exit_command in self.exit_commands:
      if exit_command in reply:
        print("Ok, have a great day!")
        return True
    return False

让我们创建一个聊天机器人类的实例,并测试我们的工作。

etcetera = ChatBot()
etcetera.start_chat()

当我们调用时。start_chat() 最终通话转到。chat() 用于检查退出单词,然后到。生成 _ 响应()。。generate_response() 方法将用户响应作为输入,将其转换为基于训练语料库的向量,并将其提供给我们的分类器,以获得标签的预测,这反过来将为我们提供给用户的答案的索引。记住,这里我们要通过索引减去一个来访问答案列表。

与聊天机器人的对话

上面的 GIF 显示了 chatbot 如何响应天气查询。在训练数据中,有一个用户响应/问题——“告诉我今天的天气报告 8”,其中包含标签“8”。在答案数据集中,第 8 行是回答——“今天的温度将是 37 摄氏度,全天都是晴朗的”。很明显,这里的响应是硬编码的,可以有一些函数来完成从用户响应(“天气”)中识别实体的工作,并使用可用的 API 从 web 中获取实时数据。

我们的聊天机器人准备好了。上面的输出还显示了预测的准确性,但是对于本项目,由于使用了最小数据集,准确性相对较低。尽管如此,它工作得还不错。公司可以通过替换他们更大的封闭领域数据集来简单地采用这个系统。

GitHub 这个项目的链接是 this 。你可以从那里得到上面所有的代码,你可以在 LinkedIn 上找到我这里

未来范围

意图分类实体识别可以集成到该方法中,以服务于诸如支付账单或基于不同流派建议歌曲或提供用户指定的航班状态的应用。词性标注可以用于此。

限制

这种方法不能应用于开放域应用程序,在开放域应用程序中,用户响应可能因各种应用程序而异。这种方法严格地适用于封闭领域的应用程序,在这些应用程序中,可以预先确定响应,并且我们可以将问题映射到它们。

结论

总之,聊天机器人可以使用朴素贝叶斯方法来构建,在这种方法中,我们只需给每个训练问题一个相应的答案标签号,我们的分类器将预测用户输入的标签。这个标签号是我们的答案数据集中相应回答的索引。这样,我们不需要像基于规则的聊天机器人那样担心正则表达式模式匹配。上面构建的聊天机器人是在一个非常小的数据集上训练的,因为这应该是对新方法的简单解释。这些公司可以根据特定的应用来创建他们的数据集。

对于一个生产系统,您会想要考虑一个现有的 bot 框架,并将这种方法集成到其中;这样,你不必从头开始。互联网上有很多资源,读完这篇文章后,你可能想创建一个自己的聊天机器人。

跨越时间和数字的名字

原文:https://towardsdatascience.com/a-name-across-time-and-numbers-a9f432c3981b?source=collection_archive---------40-----------------------

这篇文章是对我女儿充满爱意的致敬,在这些黑暗和不安的夜晚,她的眼睛是闪亮的星星。

名字不断演变。父母会从流行文化、历史、体育、时事或神圣的经文中取一个名字,并加入他们自己的想法。起名的行为既唤起了原来名字的含义,也给新生儿留下了空白页来写。

以卡珊德拉为例。还有更短的变种如 Cass。一些辅音可能会被替换。在某些国家,可以用 k 代替 c,比如 Kassandra。有趣的是,在菲律宾,例如,在拼写(Cassandhra)中添加一个“h”是很常见的。这是一个随时间变化的图表。

请继续阅读,看看我是如何做到的!这是卡格尔笔记本,如果有人感兴趣的话。

识别变体

有了数据,我们可以看到姓名及其变体如何随着时间的推移而流行。我使用了从美国社会保障数据中收集的美国婴儿名字数据集。然后,我使用双变音算法将单词按照它们的英语发音组合在一起。劳伦斯·菲利普斯在 1990 年设计的原始变音算法通过元音和辅音发音变化的复杂规则进行语音匹配。从那以后,该算法有过两次更新。对我们来说幸运的是,有一个来自 C/C++代码的 Python 端口,即模糊库。结果是一组单词,如:

Mark -> MRK 
Marc -> MRK 
Marck -> MRK 
Marco -> MRK

在下面的代码中,我们首先获取数据中所有姓名的指纹(也称为哈希代码):

names = df["Name"].unique()
fingerprint_algo = fuzzy.DMetaphone()

list_fingerprint = []
for n **in** names:
    list_fingerprint.append(fingerprint_algo(n)[0])

结果是每个名字都有一个索引。然后通过简单的过滤,我们可以提取 Cassandra 和 Cass 的变体。

def get_subset(df, df_fp, names):
    fingerprint_candidates = []
    for name in names:
        matches = df_fp[df_fp["name"] == name]["fingerprint"]
        fingerprint_candidates.extend(matches.values.tolist())

    name_candidates = df_fp.loc[df_fp["fingerprint"].isin(
fingerprint_candidates), "name"]

    df_subset = df[(df["Name"].isin(name_candidates)) & (df["Gender"] == "F")]
    return df_subset

# using my function
df_fp_names = pd.DataFrame([list_fingerprint, names]).T df_fp_names.columns=["fingerprint", "name"] df_subset = get_subset(df, df_fp_names, ["Cass", "Cassandra"])

卡珊德拉的变体

然后我们可以画出整个 20 世纪最流行的卡珊德拉变体。我还绘制了一个对数比例版本,这样我们可以更好地看到那些在包中间的。我正在使用 plotnine 库,所以我可以做 ggplot 风格的代码。

ggplot(df_top_n_global, 
aes(x = "Year", y = "Count", colour = "Name")) + \
    geom_text(aes(label = "Name"), show_legend = False) +\
    geom_line() +\
    labs(y = 'Number of babies', title = 'Cass: 1900\'s and beyond') +\
    scale_y_continuous(trans='log10') +\
    theme(panel_grid_minor_y=element_blank(),
           panel_grid_major_y=element_blank())

看起来卡桑德拉这个名字和几乎所有它最流行的变体在 90 年代达到了顶峰,但从那以后急剧下降。我曾经读到过,在 90 年代,这个名字甚至进入了美国前 70 名。其他受欢迎的变体包括凯西、凯西和卡桑德拉,这些变体的受欢迎程度都在下降。

佐伊最受欢迎的变体

佐伊的情况有所不同,我们发现她在 2000 年代的受欢迎程度大幅上升。也许佐伊 101 和这个节目有关?还有那部经典的 rom-com,2009 年夏天 500 天…

然而,自 20 世纪 50 年代以来,一种被确认的变体 Sue 的受欢迎程度急剧下降。我很确定他们有不同的发音。双重变音错误地将它们索引在一起。

研究名字如何随着时间的推移而演变、变得更流行、变得更稀少,这是非常有趣的。著名的人和事件总是与它有关,因此名字成为时代的反映。我记得有一种趋势,父母给他们的孩子取名 Danaerys,或者在名字的某个地方加一个 Jon。我猜测,截至这篇文章的写作时间,可能有很多安东尼的出生。甚至 X A-12都是时代的标志。

因为我只使用美国的数据,所以看到每个国家的趋势和变化会更有意思。每个国家的命名风格是什么?命名风格的异花授粉是什么样子的?中性名字越来越受欢迎了吗?这些都是值得探索的迷人问题!

原载于 2020 年 9 月 19 日【http://itstherealdyl.com】

从零开始的神经网络

原文:https://towardsdatascience.com/a-neural-network-from-scratch-c09fd2dea45d?source=collection_archive---------31-----------------------

用神经元、Python 和 Numpy 预测达斯·维德

在这篇文章中,我将向你展示如何用 Python 从头开始创建一个神经网络。我们将使用的唯一外部库是 Numpy,用于一些线性代数。因为今天是 5 月 4 日作为奖励,我们将使用这个新创建的神经网络来拟合一条复杂的消息,这条消息是从穆斯塔法截取的。一步一步地编写神经网络代码将有助于您理解内部工作方式,这与 Torch 和 Tensorflow 等流行框架非常相似。就我个人而言,我认为从零开始构建东西是掌握一个主题的最好方法,当然也很有趣!

“就是这条路”——丁·贾林

这篇文章在我的 Github 上也可以作为的 Jupyter 笔记本获得,所以你可以边阅读边编码。

如果你是 Python 和 Jupyter 的新手,这里有一个关于我如何管理我的 Python 环境和包的简短说明

👉Pip,conda,aaah 是我每天 10 分钟 Python 课程的一部分!

我们将讨论的主题的简短概述:

  1. 神经网络和逻辑回归
  2. 多层网络的一般化
  3. 逐步实施
  4. 它做了它应该做的事情吗?
  5. 符合从穆斯塔法截获的信息

1.神经网络和逻辑回归

当我们随机问一个人关于机器学习的问题时,很有可能会提到神经网络。这些术语不仅发挥了我们的想象力,而且这些数学结构也证明了它们能够解决复杂的任务。这种任务的例子是对象检测、音频转录和文本翻译。神经网络可以相对较小,如图 1 所示,但仍然很强大,可以预测复杂的系统。

图 1:一个典型的神经网络,由一个输入层、两个隐藏层和一个输出层组成。

在图中,我们展示了一个人工神经网络(ANN),或简称为神经网络(NN),它有三层。按照惯例,我们不计算输入层,稍后我们会看到,图中的这一层表示您输入到神经网络的输入数据。这个特殊的神经网络有两个隐藏层。虽然我不确定为什么它被称为隐藏层,但我可以想象一个原因是这些层对用户是“隐藏”的。用户通过输入层输入数据,并从输出层获得结果,因此不会与隐藏层进行交互。对于用户来说,一个系统有一个或二十个隐藏层是没有区别的。与输入层相反,输出是一个实际的层,在我们的例子中是一个单个神经元,它“收集”来自前一个隐藏层的结果。

在我之前的教程中,我试图解释逻辑回归(和一点线性回归)是如何工作的。逻辑回归可以被看作是最小的神经网络,只有一层,由一个神经元组成。可能最好首先简要回顾一下图 2 所示的逻辑模型。

图 2:一个逻辑回归模型的例子。这个例子有三个输入特征供给单个神经元。神经元本身分为两个操作,线性部分和非线性激活函数。请注意,线性方程中使用的权重是输出图层的一部分。

对于这个例子,第一步是对输入数据进行按摩,使个体特征 ( 𝑥 1、 𝑥 2、 𝑥 3)在我们输入向量 𝑋 的行中,列是实例(训练样本)。这个输入向量 𝑋 用于我们单个神经元的前向传递。这个神经元分为两个操作。先是一个线性运算(线性回归),z=𝑋𝑊+𝑏,接着是一个激活函数𝐴=𝑔(𝑧)。在逻辑回归教程中,我们执行了二元逻辑回归。这具体使用了 Sigmoid 激活函数𝜎(𝑧)= 1/(1+exp(𝑧)),因此我们在这里将其表示为 𝜎 ( 𝑧 )。在这里,我们通过使用 𝑔 ( 𝑧 )来表示激活函数来概括这一点。我们必须定义我们将使用哪个激活函数。正如我们今天将要学习的,有许多激活功能可供选择。

激活函数使用来自神经元线性部分的结果作为输入。这是权重向量 𝑊 和输入向量 𝑋 的内积(也叫点积),加上了偏置项 𝑏 。偏差项 𝑏 和权向量 𝑊 (由 𝑤 1、 𝑤 2、 𝑤 3 组成)是该系统的可训练参数。每个可训练权重( 𝑤 1、 𝑤 2、 𝑤 3)对应于一个输入特征( 𝑥 1、 𝑥 2、 𝑥 3),并表示该特征添加到问题中的“权重”。在图表中,这些权重显示在输出图层的虚线框内,这意味着这些权重与该图层相关联。

我希望这个简短的回顾是清楚的,否则,我可以推荐我以前的 Jupyter 笔记本来获得更全面的解释和 Numpy 中的一步一步的例子。

虽然逻辑回归是一个很好的工具,但它只能将参数空间分成一条线,至少在我们这里给出的形式中是这样。例如,如果你有两个特征 𝑥 1 和 𝑥 2,它们将用于预测 𝑦 ,逻辑分类器只能在两个参数之间有一个线性边界。如果这没有意义,也不要担心,因为我们将通过一个例子来说明这个问题。

图 3:一个神经网络可以被看作是一堆逻辑回归单元的组合。

为了让系统预测更复杂的关系,我们可以向一层添加更多的神经元,或者向我们的网络添加更多的层。每个神经元都是某种逻辑回归单元,其中许多结合起来可以预测高度非线性的关系(见图 3)。我说类似于,因为在常规逻辑回归中,我们通常使用 Sigmoid 激活函数,而在神经网络中,许多其他激活函数的性能要好得多。

在我们开始概括一个神经网络和所用的层之前,请观察图 3 中不同的神经元是如何连接的。您会注意到每个节点都连接到下一层的所有节点。这被称为密集连接(有时是完全连接),这样的层通常被称为“密集层”。在下一节中,我们将尝试概括网络并确定所需的结构。

2.多层网络的一般化

在我们开始编码我们的系统之前,让我们首先尝试概括所需的步骤。本教程的目标是创建一个通用的神经网络类,我们可以在其中添加任意数量的层,包含任意数量的神经元。稍后,我们将在具有不同复杂性的各种问题上测试这种结构。

当我们想到输入层时,我们已经发现它不是神经网络的实际层,而是以正确形式重新整形的输入数据。因此,输入“层”不是我们架构的一部分。当然,输入数据具有许多特征,因此定义了我们的第一层的至少一个维度。

神经网络将由任意数量的层组成。这些结构的行为方式相似,并且是相互连续的。这意味着我们将有一个层结构,以及某种父结构来保存所有的层。当进行正向传递时,我们将遍历所有层,并将前一层的输出用作下一层的输入。最终层的输出,也称为最终激活 𝐴 是神经网络的输出。这意味着,如果神经网络用于预测二进制值,则输出必须转换(或舍入)为实际预测值。

为了测试我们的预测,我们需要定义一个成本函数。成本函数是对模型预测效果的衡量,因此需要预测值和真实值。在最正式的意义上,我们需要定义一个损失函数,该函数计算单个示例的预测误差,并将所有这些损失合并到一个成本函数中,以获得我们输入到模型中的整个批次的一个度量。损失和成本函数只需要一次,而不是在每一层中,因此,它应该在父结构中实现。

为了优化权重并有希望改进模型,我们需要使用向后传递来计算梯度。首先我们需要计算父类中损失函数的梯度。这将是最后一层的输入,从这一点,我们向后循环计算梯度 𝑑𝑊𝑑𝑏 ,随着每次迭代,前一层的输入将是下一层的输入。为了计算梯度,我们需要来自向前传递的输入,为此我们可以做一个聪明的技巧,在向前传递期间缓存 𝑧𝐴 的值。这看起来有点吓人,但这些步骤主要是记账。所有这些步骤都可以在图 4 中看到。

图 4:我们的神经网络结构的概述。完整的结构,包括输出层 𝐿𝑜 在我们的神经网络框架内。正向传递循环通过每一层,并输出最终激活的结果。进行反向传递时,首先计算成本函数的梯度,然后我们通过所有层反向迭代,计算梯度。

在我们计算了每一层的梯度后,我们可以做一个更新步骤,并执行梯度下降步骤。这一步实际上与我们在逻辑回归教程中讨论的一步相同,在逻辑回归教程中,我们使用学习率将权重向真实结果“移动”一步。然而,这一次,我们必须对神经网络中的每一层都这样做。

我们现在应该认识到,网络中的所有层在根本上是相同的。它们可以在节点数量或激活功能上有所不同,但第一层 𝐿 1 和输出层 𝐿𝑜 之间没有结构上的区别。这意味着我们可以创建一个层结构作为神经网络的一个构建模块。

我们的神经网络将只由密集层组成,即所有神经元都完全连接到下一层神经元的层,因此我们将只制作单层结构。在这个结构中,我们必须计算向前传递、向后传递和更新步骤。每一层的输入都是前一层的输出。显然,对于第一层,这是输入向量。对于反向传递,我们按相反方向依次通过网络。然而,这里我们需要做一个额外的步骤,因为我们需要计算关于定义的损失函数的梯度。为此,我们需要在反向传递期间输入真实标签 𝑌 和预测输出 𝐴 。在这之后,我们有一个层期望的值,我们称之为 𝑑𝐴 。每一层都以完全相同的方式处理向后传递。

图 5:显示单层向前和向后传递的图表。在向前传递过程中,我们缓存 A 和 z 的值,以便在向后传递过程中使用。

每一层的向前和向后传递如图 5 所示。让我们一步一步地走过每一关。在前向传递中,它期望前一层的输出 𝐴𝑝 (或输入向量 𝑋 )作为输入。在线性方程之前,输入 𝐴𝑝 被缓存用于向后传递。接下来,我们计算单个矢量化内积中的线性部分。这是对该层中的所有神经元以单一步骤完成的。在内积之后,加上偏置项。接下来,我们还缓存了向后传递的 𝑧𝑝 的值。最后,我们将计算激活函数,并将结果传递给下一层(或者如果这是最后一层,这就是输出)。

向后传递只是反向的向前传递,但是期望前一个渐变作为输入。首先我们需要计算激活函数的微分。这些都比较容易计算(或者在网上找)。我们使用缓存的𝐴𝑝的值和𝑧𝑝的值来计算梯度。作为最后一步,我们计算 𝑑𝐴𝑝 ,这将是下一层的输入。虽然数学与之前的教程相似,但现在更加简化了。我不想过多地关注实际的差异,但会在代码中多解释一些。如果你真的想知道这些微分是怎么算出来的,我会建议你拿纸笔试着算一下。他们并不难,Wolfram Alpha 可以帮助你:-)。

最后一点,你应该意识到,在向后传球中,我们正在做所有链式规则之母。为了计算第一层的梯度,我们必须将所有其他的微分链接在一起。如果不完全清楚每个步骤在做什么,不要太担心。我会试着解释编码过程中的每一步。经验和理解来自实验。

“我已经说过了”——库伊尔

逐步实施

在我们开始编码之前,让我们先对我们计划做的事情做一个简短的总结。这个想法是创建两个结构,在这个例子中是类。一个类定义层,而另一个类充当父类并保存完整神经网络的所有层。

密集层类

  • 结构来保存任意数量的节点
  • 将具有各种激活功能
  • 将通过单层执行正向传递
  • 反向传递的缓存值
  • 将对该层执行向后传递
  • 将对图层执行更新步骤

神经网络类

  • 结构来保存任意数量的层
  • 将在所有层中顺序执行向前传递
  • 将计算各种损失函数的成本
  • 将执行反向传递并计算所有梯度
  • 将对所有图层进行更新(梯度下降步骤)

让我们开始吧!

我们将使用 Numpy 的线性代数例程,因此需要导入它。此外,定义有意义的错误是一种好的做法,因此我们将定义几个异常。另一种方法是使用 Python 的日志模块,这是另一个很好的工具。

致密层:

接下来,让我们创建名为 DenseLayer 的新类。该类采用一个带有两个必需参数和两个可选参数的构造函数:

  • inputDimension,即输入向量的特征数,或前一层的单元数。
  • 单位,即该层神经元的数量。
  • 激活:在这里你可以指出层应该使用什么激活。定义了“sigmoid”、“relu”、“tanh”和“”。空字符串表示没有激活,意味着我们只有一个回归。
  • randomMultiplier 是随机权重相乘的值。通常,0.01 就可以了,但有时调整这个数字会有所帮助。

由于可能有不同的激活函数,并且我们不想检查我们使用了 if 语句的哪个激活,我们在 init 语句中引用所使用的激活函数。

在 initialize 方法中,权重被初始化。注意,神经元的数量 nh (单位)在行中,输入特征的数量 nx 是列。这是使我们的点积稍后工作所必需的。

最近学到的另一件事是 Python 中‘self’的用法。虽然我认为我理解这个概念,但我并不完全理解其后果。类的定义与每个实例的值是分开的。这些值存储在自身对象中,即实例本身的对象中。在其他编程语言中,通常在类本身中定义类型。然而,在 Python 中,您必须在 init-method 中定义它们。如果不这样做,该变量将在所有实例中共享,您可能会得到奇怪的结果。我刚刚发现这篇博文,其中唐·克罗斯有一个非常清晰的解释。有兴趣推荐阅读!

接下来,我们定义所有使用的激活函数。我们在前面的教程中已经知道了 Sigmoid,但是,我们还包括 Tanh 和 Relu,它们也是非常常用的激活函数。

双曲正切函数是一个类似于 Sigmoid 的函数,但是它将所有实数值映射到-1 和+1 之间的值。在 Relu 函数登上舞台之前,它已经非常流行了。

Relu,代表整流线性单位,可能是目前最流行的激活函数。它的计算速度很快,而且通常比双曲正切函数的结果更好。因此,如果你不确定,Relu 函数是一个很好的开始。Relu 函数将所有小于 0 的值映射为零,并将所有大于 0 的值映射为值本身。

我们将介绍的最后一个激活函数称为线性函数。这和没有激活功能是一样的,只是一个占位符。什么进来,什么出来,我们用它来测试我们之前的线性回归练习。

向后传递需要所有这些函数的微分,这些微分带有 Grad 后缀。请随意检查这些差速器是否正确。请注意,每个函数都有一个额外的步骤,它不是函数微分本身的一部分,但需要应用链规则。我们将输入的差分乘以计算出的差分。这个步骤在整个反向传播中连续运行。

接下来,我们定义正向传播步骤,这对于逻辑回归版本来说应该非常熟悉:

我们首先计算线性部分。存储 Z 和 A 的值,供以后在反向传播中使用,然后应用激活函数。

反向传播应该看起来也很熟悉,但是,我们已经将激活函数的微分部分拆分为函数本身。此外,该函数期望 dA 作为输入,这是多层的更一般化的形式。在我们之前的单层示例中,我们在这一步中合并了损失函数的微分。这一步现在包含在我们的父类中,而不是每个层中,因为它只在最后一层之前需要。

梯度存储在每个图层中,以后可由执行梯度下降步骤的更新函数使用。反向传递将每一层链接在一起,我们将在后面处理父类时看到。剩下唯一需要的函数是 update 函数,它执行梯度下降步骤。没什么了不起的,但它期望一个学习率。

虽然不是必需的,但这些 next 函数有助于打印模型并返回输出节点的数量,这些节点用作下一层的输入维度。

神经网络类:

好吧,搞定一个,还有一个。接下来,我们将创建一个类来合并这些层。它还将保存损失函数,并且必须计算损失的梯度。为了方便起见,我们还将添加一个包装器来添加层,并添加一种方法来漂亮地打印我们的模型。

首先,我们再次从构造函数开始,它有两个选项,要使用的损失函数和用于新层的 randomMultiplier。损失函数再次在函数引用中创建,并使用包装函数调用。模型初始化时没有层(空)。

下一个方法是一个帮助器函数,用于向模型添加层。您需要给出输入维度,即第一层的输入要素的数量。对于第二层和更深的层,它将查找前一层并将其用作输入维度。

你必须指定层(单元)中神经元的数量以及使用哪个激活函数。如果你不指定激活函数,它将不会使用激活函数,你将得到一个线性系统。

接下来,我们定义损失函数及其微分。请随意检查差速器是否正确。成本方法是一个包装器,用于在训练循环中调用适当的成本函数,我们将在后面定义。

前进、后退和更新方法非常相似,因为它们在所有层上循环。只有后向通道必须首先计算损失函数的梯度,然后将其用作第一层(从右侧开始)的输入。

后两种方法非常简单,用于漂亮的打印,一种用于打印可训练参数。没什么特别的。

好了,课程结束了。现在我们需要对这些类进行测试。虽然它看起来非常有序,但其中一个差速器的小错误会使我们的整个系统变得毫无用处。因此,我们将在下一节中分步进行测试。期待旋转!

如果想一次复制所有的类,可以从 my Github 下载。

4.它做了它应该做的事情吗?

没有什么比空等更烦人的了。因此,重要的是首先测试容易的东西,而不是花几个小时训练,看看你在损失函数中犯了一个错误。让我们重复上次实验中做过的实验。

线性回归:25 再来一遍

我们用几个输入值 𝑋 创建了一个数组。接下来我们用超级复杂的公式 𝑦 =2 𝑥 +1 提供 𝑌 。在 Numpy 中是这样的:

现在,我们将构建我们的模型,该模型将尝试找到我们的困难公式并匹配 25 的真实值。为此,我们将启动我们的新类,并将损失设置为均方误差。接下来,我们将添加一个单层,只有一个神经元,没有激活功能。让我们也试试我们漂亮的印刷:-)

现在我们将再次需要我们的训练循环。上次的逻辑回归模型看起来很熟悉:

成本如预期的那样下降,并且由于长时间的训练,该值接近机器精度。当我们在 forward 方法中输入 12 时,我们会再次找到 25 吗?

array([[25.00000019]])

当然,我们有!

逻辑回归:泰坦尼克号数据集的又一次尝试

坏消息,泰坦尼克号又沉了,我们需要一个二元逻辑分类器。没有过多评论,我们导入数据(来源: Kaggle 泰坦尼克号比赛/由 Azeem Bootwala 预处理):

我们需要创建一个有 14 个输入特征的模型,当然还有 sigmoid 激活函数。损失函数将是交叉熵,这是默认的,所以我们不需要指定它。

在创建训练循环之前,我们像上次一样定义一个精度函数来快速计算精度。上次我们有大约 80%的准确率。

现在,让我们运行训练循环,看看我们是否能匹配前面的结果。

cost: 0.6912384614194468 	accuracy: 58.7%
cost: 0.5140056920509907 	accuracy: 75.9%
cost: 0.4824062497934128 	accuracy: 79.5%
cost: 0.4697113881273363 	accuracy: 79.5%
cost: 0.46275860969195476 	accuracy: 79.8%
cost: 0.45807429458700816 	accuracy: 79.8%
cost: 0.4544915367177524 	accuracy: 79.8%
cost: 0.4515471545581365 	accuracy: 80.8%

如你所见,一点也不差。

更多的神经元和层:复杂的花朵

酷的东西从更复杂的功能开始。来自吴恩达的深度学习课程展示了一种使用多节点模型预测玫瑰函数的方法。让我们也试试吧!

首先,我们需要导入数据。生成数据的代码在 Github 上的 Jupyter 笔记本里。

图 7:输入数据的可视化。

数学方程式创造了美丽的花状结构,如图 7 所示。我们已经将 7 个花瓣中的 3 个着色为不同的值,现在将使用我们的神经网络来预测 x,y 坐标上的值应该是 0 还是 1(颜色)。

但在此之前,让我们先展示一下,当我们试图用一个过于简单的模型来预测时会发生什么,比如逻辑回归,它只能有一个线性边界。在下一个代码片段中,我包含了模型创建、训练循环和可视化结果的帮助函数。

结果显示在图 8 的左侧。肯定不是很合适,而且明显是一条线。现在让我们添加另一个有四个单元的层到模型中,最后一层是相同的 Sigmoid 层。我们保留的这个模型的激活函数与 Andrew 的相似,它有一个 Tanh 激活函数。

图 8:同一花形函数的两种拟合。在图 8a 中,逻辑回归模型只能拟合一条线,而图 8b 中的两层模型可以拟合花的复杂形状。

这真的让我很惊讶。再多一层,我们就有能力学习这个更复杂的功能。非常棒的东西!

5.符合从穆斯塔法截获的信息

因为今天是 5 月 4 日(与你同在),我们截获了一份来自穆斯塔法的秘密电报,这不可能是巧合。最重要的是,我们用这些数据训练我们的模型,这样我们的 ai (read: model)就可以完全理解这种传输的本质。

第一步是导入数据,即 2d 传输数据。我还创建了一些辅助函数来创建模型,一个训练循环,以及一个可视化和分析传输的函数。

当你创建更大的模型,尤其是更复杂的模型时,你会发现超参数的数量会大大增加。有关于如何选择它们的指导方针,但没有金科玉律,因此,你经常要尝试很多。

我做了一个参数扫描,其中我自动搜索以找到最佳的层数、单元数和迭代数。我做得很粗糙,花了 15 个小时运行了近 100 个模型。参数搜索包含在 Jupyter 笔记本的附录部分。以下参数给出了很好的结果,损耗低于 0.09。损失值本身没有意义,它只是预测值与真实值匹配程度的度量,应该最小化。你可以自己尝试这些设置。如果发现更好的参数,请分享给我:-)。

[
  1 -> Dense layer (nx=2, nh=27, activation=relu)
  2 -> Dense layer (nx=27, nh=31, activation=relu)
  3 -> Dense layer (nx=31, nh=31, activation=relu)
  4 -> Dense layer (nx=31, nh=1, activation=sigmoid)
]
There are 1973 trainable parameters in the model.

我们的模型有四个连续的层。前三个有许多单元和 Relu 激活功能。最后一层是简单的逻辑层。我们的实现没有 pyTorch 或 Tensorflow 中提供的所有功能(可以随意添加)。一件很棒的事情是在训练时调整学习速度。首先以较大的学习速率开始,当你接近收敛点时降低学习速率。下面的方法就是模拟这一点。

1000 -> cost: 0.42574001278351997
2000 -> cost: 0.310616390460577
2000 -> cost: 0.21932529403735668
2000 -> cost: 0.15604826952436227
4000 -> cost: 0.11089920071653515
5000 -> cost: 0.09616265347246447
8000 -> cost: 0.09046567290400138
4000 -> cost: 0.08879263912657591

经过 28000 次迭代后,我们达到了一个足以分析数据的收敛状态。为此,我们将使用 testModel 函数。使用 h 参数,我们可以增强我们消息的分辨率。各种“增强”的结果如图 9 所示。

图 9:现在我们发现了一个可怕的事实:这条信息是关于西斯尊主本人的!

哦,天哪,是黑魔王本人!啊啊!当然,没有提高分辨率这样的事情,我们只是用更大的网格来填充神经网络。结果还是蛮牛逼的,我必须说我自己:-)。

下一个很酷的尝试是使用 RGB 图像作为输入。为此,您需要调整输入图像的形状,使 RGB 通道垂直堆叠。对于我们当前的输入图像,这意味着三倍长的输入向量(三个通道)。创建和操作输入数据的程序可在 Jupyter 笔记本中找到。输入图像的剪贴画源是从niceclipart.com下载的。

围捕

我希望你们玩得开心,写自己的神经网络。在我看来,从头开始写这些东西是了解它实际上是如何工作的最好方法。我希望你能看到这些系统并不神奇,只是简单的矩阵乘法,不幸的是它们非常多。最困难的部分当然是反向传播,我们需要计算梯度。我们简单的神经网络是相当可行的,但增加更多的层和不同类型的层,会使它变得有点麻烦。尽管如此,本质还是和我们今天所做的非常相似。

我的建议是尝试一下这些结构,重写它们的一部分,或者更好,从头开始写你自己的!

这是一条路

如果您有任何意见,请告诉我!在 LinkedIn 上随意联系。

如何用 Numpy 从零开始构建神经网络!(第一部分)

原文:https://towardsdatascience.com/a-neural-network-implementation-part-i-eb31f4ea470?source=collection_archive---------43-----------------------

图一。我关于反向传播的笔记。我拍的照片。

仅使用 Numpy 的前馈实现!

神经网络是深度学习的核心。它们为伯特或 GPT-3 等卓越模型奠定了基础。为了对变形金刚的功能有一个非常肤浅的了解,我认为有必要学习如何从零开始建立一个神经网络,使用现有的最基本的数学工具。

基于此,我决定投资一些时间和代码我自己的神经网络实现。你可以在我的 Github 页面( neuralnet )看看完整的项目。是的…我知道,这不是一个非常原始的名字👻!

我将在几篇不同的博文中讨论这个话题。

理论第一

我想做的第一件事,是向前和向后传播背后的精确的数学运算。我不想看也不想复制其他帖子的实现,所以我选择了桑德罗·斯坎西 (来自斯普林格出版社)的《深度学习入门》,这本书似乎正适合这个任务。

图二。桑德罗·斯坎西的《深度学习导论》封面。图片来自 亚马逊

在第四章有一个关于浅层前馈神经网络的精彩解释。我研究了一下,先用手开发了方程,这样开发的时候就不用挤破头了。(事实上,帖子顶部的图片是我的真实笔记,我花了一个下午的时间把整个算法做对了)。当你对自己想要创造的东西有了一个明确的想法时,最好开始编码。此外,当你进行科学编程时。

您会注意到,我的项目明显带有“Keras API-based”偏见。我从它那里借用了一些概念来封装元素,比如抽象。最后,是最合理的方式来揭露神经网络的建设。

基本概念

现在,我将总结实现网络的这一系列文章中将要涉及的主题。将有数学表达式和相关代码的解释。

这一部分将涉及的主题有:

前馈传播

  • 层权重
  • 激活功能
  • 向量化偏置吸收
  • 全正向传播

以下几点将在即将到来的第二部分中解释!😄

  • 优化:梯度下降
  • 损失函数
  • 反向传播和链式法则
  • 权重初始化

正向传播

从这一步开始,我们将关注一个二进制分类问题,使用一个基本的前馈架构作为构建代码的基础。我们会使用这个设置,因为这是机器学习中最常见的问题之一,也是最容易解释这个概念的。

正如下面图 3 的描述,我们的网络在输入层由 2 个神经元组成,这意味着网络将接受 2 个分量的向量,然后是隐藏层的 3 个和输出层的 1 个。我们将在后面看到,通过使用激活函数,输出神经元将返回输入观察值属于这一类或那一类的概率。

图 3。浅层前馈神经网络

层权重

每条线和每个箭头表示权重矩阵,该权重矩阵关于每一层将神经元相互关联。这些权重将考虑前一个输入或层输出的“多少”将被转移到下一个。我们可以用数学方法写出这些矩阵,如下所示。

表示输入层和隐藏层之间的权重关系的矩阵将被表示为θIH,隐藏层和输出层之间的权重被表示为θHO。

图 4。每层的权重矩阵。

然后,为了明确定义从每一层到下一层的转换,我们需要定义什么是激活函数。

激活功能

基于生物启发模型来阅读激活函数的定义是很常见的。但是让我们忽略一部分,因为我认为这有点令人困惑。

关于生物学和哲学基础的一些注释可以在论文 “关于深度学习的起源 ”中阅读,该论文用非常精辟和系统的方法解释了这些初级概念化。

我更喜欢将激活函数视为非线性的(实际上,除了在感知器上,总是非线性的)转换,这种转换将它们的输出压缩到某个范围内(近似概率分布),并最终允许神经网络证明它们是通用函数近似器** 这个理论解释了为什么神经网络表现出如此高的表示能力。**

关于普适近似理论的一个很酷的解释可以在这里读到

在我的实现中,我选择了 sigmoid 激活函数,它很长时间以来一直是标准的激活函数(尽管最近它已经被 ReLu 及其所有派生函数所取代)。

图 5。乙状结肠激活功能。

代码实现如下所示。

偏置吸收

现在,我们有了几乎所有的工具来了解如何计算前向传播。让我们先看看表达式在 2 层前馈架构上是什么样子的:

图 6。浅层网络上的前向传播。

可以清楚地看到,正向传播的形式似乎很简单。这只是一种类型的功能组合

*在这篇文章中,我们继承了用神经元和它们的联系来展示什么是神经网络的传统,但最终如果你看一下上面的表达式,就很容易理解网络的基础是什么。如果应用于输入 X,表达式的输出将是该输入属于第一类的概率。

为什么θIH 和θHO 有 b 下标?→因为我们正在利用偏置吸收实现正向和反向传播。这不是一个非常流行的概念,但我认为它在计算方面更有效,因为它允许完全矢量化的实现。

偏置吸收基本上是将偏置项视为各层的另一个输入,并迫使它们为 1。然后,权重将被叠加到图层权重中,以便对其进行估计以符合数据。

*我们之所以需要使用偏差项,是因为它提高了模型适应不同数据点的灵活性。

让我们用一个简单的例子来解释这个:****

图 7。单层感知器

想象具有上面在图 7 中定义的架构:

如果我们对输入向量和权重应用偏置吸收,

然后,把这个想法带到我们最初的问题和网络架构中,

注意,我们已经在两个矩阵中添加了一个新行来处理点积,我们将在下一步解释。****

正向传播的定义

现在,我们有了一切来显示如何计算前向传播。让我们看一下代码。

函数 add_bias 基本上是将一列 1 叠加到给定的向量上,以允许层内的偏置吸收。然后在 FullyConnectedLayer 类中,我们有激活,它是之前定义的 sigmoid 函数的封装,还有权重属性,它应该由一个更高级别的类 NeuralNet (将在后面介绍)通过使用方法 initialize_weights 来初始化。在这一点上,只要认为权重是从正态分布中随机初始化的。

虽然我在上面的要点中删除了一些样板代码,你会注意到有一些痕迹。这是因为它应该处理不同的初始化技术或激活功能,但对所有这些功能保持相同的接口。走 这里 为完整代码。

然后,我们有了 前进 的方法。该方法应该在承载它的层上执行传播。将这一行代码转换成数学表达式将会产生类似于:

yFCL 表示的最后一个表达式,它只是 FullyConnectedLayer 的首字母缩略词,它所做的正是 forward 方法所显示的。它应用输入 x 和权重矩阵θIHb 的点积。

***** 您可能已经注意到,在权重和输入顺序方面,该表达式与图 6 中的表达式并不完全相同。只要你的向量和矩阵适当地适应矩阵乘积,这是完全有效的。**

****注意形状对于正确实施来说,这是非常重要的一点。您应该知道输入所需的形状,以及它们将如何在网络的各层之间相乘和转换。

这只是对单层转发的解释,但是,如何处理输入信号端到端的传播,直到网络的末端?如果我们回想起展示 2 层网络上完全正向传播的数学表达式的图:

图 6。浅层网络上的前向传播。

这是一个简单的编码操作,可以毫不费力地推广到 N 层。这是它在 Python 中的样子。

简单总结一下我们在这里做的事情, _build_layers 方法负责设置在实例化类 NeuralNet 时定义的层。您应该做类似于以下的事情:

**nn = NeuralNet(
    layer_shapes=(
        (2, 3),
        (3, 1)
    )
)**

通过这样做,你只是在每层之间定义权重的初始形状。然后,在 init 中,那些形状被转换成吸收的 bias 版本,也就是在初始形状上增加一个新行(就像我们之前解释过的一样!).

**def set_bias_as_weight(shape):
    return shape[0] + 1, shape[1]**

在有了合适的权重形状后,通过使用一种叫做 和普通 初始化的技术,它们被初始化。每一层都集成在我称之为层链中(类似于 Keras 提供的顺序类)。它基本上是一个增强的列表对象,具有一些功能来简化整个层的操作。

你可以在 NeuralNet 类中看到我们如何使用这个类来遍历所有层以执行完整的传播。另外,澄清一下,这个实现是完全矢量化的。这样做的根本原因是训练基于神经网络的模型是通过*梯度下降以分批迭代的方式完成的。这给了我们利用并行处理和矩阵运算来优化代码效率空间。因此,尽管我们在整篇文章中一直在使用单个观察示例,但是如果不是一个观察,而是将 N 个观察堆叠到同一个向量 x 中,所有的计算也将有效地工作。*

正向*方法的输出将用于反向传播,以计算我们相对于目标产生的误差,并且一旦我们训练了我们的神经网络,也用于进行推断。***

这就是第一部分的全部内容!希望你喜欢它,一切都很清楚!第二部分见。

新文化时代

原文:https://towardsdatascience.com/a-new-culture-time-f555fcd351aa?source=collection_archive---------78-----------------------

如何在疫情之后继续在线运营

乔纳斯·史密斯在 Unsplash 上拍摄的照片

一个新的文化时间音频版本

人们对文化活动有了一种新的时间观念,这种观念矛盾地源于新冠肺炎疫情带来的限制。这种对时间的新理解的关键是数字内容。随着限制慢慢但小心翼翼地放松,一种新的规范开始形成尽管是短期的,我们非常清楚新冠肺炎对集体思维的影响就在那里。同样基于新兴趋势的最新迹象表明,封闭和受限的空间可能是最后一个吸引观众的空间,因为公园和开放空间与我们在过去几周和几个月养成的健康意识更加同步。在这种情况下,数字和社会媒体已经成为一个重要的工具…几乎一夜之间!

继续前进类似于声明演出必须继续。当我们寻求与我们的新常态接触时,这些是帮助你调整风帆的一些想法和主意。在这篇文章中,我们重点关注可以用来缓解我们目前面临的一些挑战的数字工具。

1。我们谁也没想到会这样!

在过去的几十年里,媒体让我们接触到了全球性的灾难,但大多数灾难都发生在电视屏幕的另一端。现在的疫情不同了。它像晴天霹雳一样击中了我们,而且就发生在我们的后院。没有任何文化机构或创意对此有所准备——你不是唯一一个在这个时候感到失落的人。保持相关性并利用可用的渠道做到这一点至关重要。

盘点手头的数字和非数字内容非常重要。你感觉到的反映了你的工作,你是谁,你作为一个组织或创意者在做什么。社交媒体可能会成为你新的最好的朋友,因为它是最有效的分销渠道之一。但不管你选择哪种渠道,最重要的是做你自己。

其中一个受到高度赞扬的在线营销和推广活动来自一个小博物馆——美国奥克兰的国家牛仔和西部遗产博物馆。博物馆要求其安全负责人(对社交媒体知之甚少)交流和分享经验。他不断请求他的听众帮助他,并参与听众感兴趣的谈话和演讲。所以不要害怕寻求帮助。联系你的支持者,让他们关注你的内容。

普拉桑娜·库马尔Unsplash 上拍摄的照片

2。通过社交媒体参与和交流

这就是创造力发挥作用的地方。创造力是没有限制和界限的,尽管很大程度上取决于受众和媒介。作为开始,考虑你的专长和知识作为出发点。有些知识只有你自己掌握,可以让你的内容脱颖而出——你独特的卖点。

先说现代手机。这使得用户可以拍摄比平时更宽的全景照片。实际上,你可以在一张图片中填满整个房间的四面墙。这些照片可以展示分散在房间各处的许多细节,非常适合展示周围环境,并邀请人们寻找类似于“发现隐藏物品”游戏的细节。视频也可以在网上分享,其影响范围比照片要广得多。为您的数字内容选择合适的平台需要一些思考,这在很大程度上取决于您所追求的受众。

社交平台迎合不同的受众。这些受众有他们自己的期望,这反过来会影响你的活动的成功(或失败)。因此,让我们引导您了解不同的平台,从您可能最熟悉的平台开始。

脸书 是全球最大的社交媒体平台,拥有超过 10 亿用户账户。它允许你创建你自己的网页,在那里你可以推广你的产品。最成功的帖子似乎是视频和现场表演,其中包括操作指南、总结和演讲。第二个最成功的是策划职位。这可能包括您创建的内容或您从其他网站上重新分享的内容,这些网站的观众有着相似的品味。一份成功的《脸书邮报》必须用简单明了的文字在视觉上引人注目。它还必须包括一个行动号召,比如要求人们点击一个链接(也许是访问你的网站)或者订阅一个邮件列表。最后,人们喜欢免费赠品,所以考虑给他们一些回报。它可能是一个免费文档的下载链接,可能是购买你的产品的折扣,或者只是你下一个大项目的预告片。文章应该少于 160 个字符,还将包括一些标签。标签只是一个以#开头的单词,这样更容易在网上找到文章。如果有疑问,像 best-hashtags.com这样的网站会帮你找出你的帖子最受欢迎的标签。

我们选择的脸书最佳实践— 梵高博物馆

Youtube 是互联网上最大的视频库,也是第二大搜索引擎。这意味着当人们需要寻找某样东西时,他们倾向于参考 YouTube。除了存储视频,像 YouTube 这样的平台还允许一些令人兴奋的变化。一个视频还可以链接到其他视频,因此在一个位置的漫游可能会让您选择进入不同的房间。互动视频可以充当跨越不同地点的“寻宝游戏”。对于更喜欢冒险的人来说,视频可以作为一个你自己选择的冒险故事,演员表演一个场景,最后,用户必须做出决定。事实上,进入门槛很低,因为你只需要一部手机,其中许多手机可以拍摄非常高分辨率的视频。

我们选择的 Youtube 最佳实践— 洛杉矶国家艺术博物馆

Instagram 是另一个非常注重审美的流行社交网络。这是一个理想的平台,你可以在这里发布你的作品或产品的高分辨率图像、幕后信息以及用户生成的内容(需要得到相关所有者的许可)。Instagram 上的热门内容包括励志名言。理想情况下,寻找支持你使命的最佳引语,并使用合适的图片来突出你的文章。在 UnsplashPexelsPixabay 等平台上都有质量好的图片,其中很多都是免费使用的。像 Canva 这样的在线应用也可以让你免费进行专业编辑。Instagram 中另一个有趣的功能是故事。这些帖子的生命周期为 24 小时。它们可以有效地用于讲故事,推广博客文章,宣布限时优惠,提供赠品,分享数据,发送更新…实际上可能性的列表是无穷无尽的!

我们选择的 Instagram 最佳实践— 大都会艺术博物馆

Twitter 帖子也值得关注,尽管这更小众。然而,这是一个很好的工具,从哪里可以获得你的最新消息。事实上,几乎 80%的 Twitter 用户声称他们的最新更新是从该平台获得的。与脸书非常相似,Twitter 允许用户分享他们的帖子,但每条帖子有 280 个字符的严格限制。正因为如此,它比其他任何平台都更适合每天分享零碎的博客文章。它还支持链接到其他网站和媒体,包括图像,照片,视频或 gif。视频也有 140 秒的限制。顺便提一下,gif 代表图形交换格式,但它们只是可以使用程序制作动画的图像,例如 CanvaEzgifGiphy 等等。

我们选择的 Twitter 最佳实践— 大英博物馆

LinkedIn 更像是一个专业的网络平台,更适合展示组织文化、经验和成就。带有图片的帖子通常比文本帖子的参与度高 98%。LinkedIn 的用户似乎也喜欢网络研讨会、咨询文件和研究。

我们选择的 LinkedIn 最佳实践— 应用艺术与科学博物馆

Pinterest 是另一个与 Instagram 非常相似的可视化社交平台。它非常适合垂直图像和信息图(快速清晰地呈现信息的可视化表示)。它们可以很容易地用免费程序创建,如 Picktochart 或 Venngage。Pinterest 也更适合那些自己动手的帖子、食物和设计。

我们选择的 Pinterest 最佳实践— 现代艺术博物馆

抖音相对来说是一个新人,但却是一个非常受欢迎的社交网络(比 Instagram 更大),更重要的是拥有年轻得多的受众。事实上,超过 40%的用户年龄小于 25 岁。这是一个短循环视频(15 到 60 秒之间)的平台,允许用户编辑视频,添加音乐,插入滤镜和各种视觉内容。帖子有一种典型的轻松感,这使它成为诙谐笑话、有趣事实和其他轻松对话的理想选择。抖音也非常适合通过竞赛让年轻人参与进来,让他们创造有趣的内容。

我们选择的抖音最佳实践— 自然历史博物馆

缩放 Skype Messenger 微软团队 都不是社交网络平台。这些主要用作视频会议平台,是专家会谈或讨论的理想选择,因此,理论上,它们仍然是可以考虑的工具。其中大多数几乎自动保存活动视频,用户可以反复播放。这些系统也是参与者较少的更亲密环境的理想选择,因此可以与主扬声器进行更好的互动。然而,他们也可以扩大规模,其中一些计划提供最多 100 人参加的免费视频会议。

正如一个人所能收集到的,机会就在那里。可供选择的平台不止一个。对于你的需求和目的,有些可能比其他的更好。其他人更少,尽管这很大程度上取决于你的信息和环境。不用说,你试验得越多,你就越能更好地理解什么对你最有效。

照片由威廉·艾文Unsplash 上拍摄

3。利用数字优先方法

数字优先是一种传播理论,它认为出版商应该首先将内容发布到新的媒体渠道,而不是直接印刷。鉴于我们已经变得更加习惯于通过手机、平板电脑和其他小工具获取信息,这种看法源于连通性的增加。因此,在线内容消费有所增加。正因为如此,博物馆或文化体验的第一步最有可能,而且在未来肯定会更是如此,数字优先。第一个接触点,与体验的第一个联系,应该越来越在线。除了传统的营销要求和实体展览或文化表演的界面,这也意味着许多额外的东西。也有好的例子可以效仿。博物馆和剧院也经常探索以学习体验为特色的合作创意项目。

数字优先的方法可以帮助你保持相关性,但它也可以帮助你在事情回归新常态时提前宣传你的工作。事实上,这可能是在网上推广你的作品或预测你在不久的将来可能提供的产品或服务的好时机。不要因为目前的情况看不到明确的结果而感到沮丧。

克里斯蒂安·威迪格在 Unsplash 上拍摄的照片

4。体验赚钱

这可能是迄今为止最大的挑战,尤其是考虑到网上有太多的内容,可能太多了。有各种方法可以做到这一点。首先,一些在线活动可以是基于捐赠的,人们可以免费参加,但被礼貌地要求捐赠,即使这只是他们选择的象征性捐赠。如果你设法为你的工作或服务协商一笔费用,那么你可以很容易地与网上资金转移设施合作,作为回报,你可以将链接发送到活动。像 Paypal 或 Revolut 这样的应用程序使得在线汇款和收款变得非常容易。你也可以通过分发内容(比如 YouTube 上的视频)来赚钱,但要想成功,你的受欢迎程度需要相对较高。

一些平台通过换位思考来解决服务付费问题。有些人要求捐赠,同时也让用户根据其当前的财务状况来支付。同理心是处理这种情况的最佳工具,这是与你未来的公众和观众建立信任的黄金机会。

耶稣·基特克Unsplash 上拍摄的照片

5。现在是时候了!

社交媒体的快速发展已经伴随我们多年了,它对我们的生活产生了决定性的影响。我们可能很少注意到这一点,也许是因为我们更多地被日常琐事所占据,这让我们无法在这个未知的领域进行更多的冒险。但现在是时候了!这并不像你第一印象中想象的那么复杂。所讨论的平台相对容易使用,正如俗话所说,熟能生巧!当我们走出困境时,这个疫情将有希望成为过去,你会给你的文化活动一个新的生命。

文章由 阿列克谢丁力 桑德罗德邦 撰写。它最初发表在 https://www.businesstoday.com.mt

* [## 重塑办公室之外的工作场所

如何在家中舒适地高效工作

towardsdatascience.com](/reinventing-the-workplace-beyond-the-office-3a41c42b426c) [## 空荡荡的博物馆

以及大流行后的博物馆景观

medium.com](https://medium.com/the-neo-humanist-museum/the-empty-museum-8ed23c1431d1)

阿列克谢·丁力教授 是马耳他大学的 AI 教授。二十多年来,他一直在人工智能领域进行研究和工作,协助不同的公司实施人工智能解决方案。他的工作被国际专家评为世界级,并赢得了几个当地和国际奖项(如欧洲航天局、世界知识产权组织和联合国等)。他出版了几本同行评审的出版物,并且是马耳他的一部分。由马耳他政府成立的人工智能工作组,旨在使马耳他成为世界上人工智能水平最高的国家之一。

桑德罗·德博诺 (生于 1970 年)是一位博物馆思想家和文化战略家。他是 muża——马尔他国家社区艺术博物馆——的幕后策划者,他是该博物馆的先锋,并为其开发了最初的指导性愿景。他是马耳他共和国总统的文化顾问,欧洲博物馆学会的国家代表,也是博物馆创新者和变革者国际平台 We Are Museums 的顾问委员会成员。他还是马耳他大学艺术、开放社区和成人教育系以及其他系的客座讲师。他经常受邀在欧洲各大学和博物馆、国际会议和活动中演讲。*

学术项目中数据科学的新定义

原文:https://towardsdatascience.com/a-new-definition-of-data-science-in-academic-programs-2d48ad6db8b7?source=collection_archive---------9-----------------------

是时候更具体地了解数据科学需要什么了。

D 过去几年的 ata science 已经被用来指代几乎所有与数据相关的事物(数据分析、数据挖掘、机器学习等。).越来越多的人寻求数据科学教育,越来越多的大学和在线平台争相开发这样的课程。然而,数据科学和数据科学家的定义缺乏清晰度显然伤害了每个人,无论他们听起来多么时髦。每个人都把自己想要的投射到角色上:

申请人:“我对在海量数据集上进行机器学习感兴趣。所以我在申请一份数据科学家的工作!”

业务:“我需要一个能从这些 Excel 工作簿中构建一个不错的管理仪表板的人,所以我会雇佣一名数据科学家!”

因此,申请数据科学家工作的人不高兴,因为他们最终做的是数据提取和仪表板,而不是任何机器学习。与此同时,企业意识到,除了拥有一些优秀的数据分析师,他们并没有获得更多的价值。我个人非常不愿意称自己为数据科学家,尽管我用数据做了很多“事情”。

数据科学家是做什么的?来源

那么应该如何定义数据科学呢?

几周前发表的一篇麻省理工学院的文章提出了数据科学的新定义和数据科学项目的设计。他们认为数据科学不是一个单一的学科。更确切地说,这是一个总括 ( 通用)术语 ,描述了一个拥有非重叠技能的数据科学家团队中的复杂流程。考虑到当今从数据中提取价值所涉及的广泛活动和多个步骤,假设一个数据科学家拥有所有必要的专业知识是不合理的。

更清晰地了解数据科学需要什么不仅有助于学术项目更好地设计课程,也有助于学习者和企业更好地理解这些项目到底需要什么和期望什么。

后端和前端数据科学

这篇文章认为,后端和前端数据科学之间需要明确的区别。我把他们的想法总结如下:

后端和前端数据科学(作者基于麻省理工学院文章举例说明)。

数据科学管道中涉及的主要角色有:

  • 数据工程师负责处理硬件、高效计算和数据存储基础设施。
  • 数据分析师,他们争论、探索、质量评估、使模型符合数据、执行统计推断以及开发原型。
  • 机器学习工程师,他们构建和评估预测算法,并为许多用户提供可扩展和健壮的解决方案。
  • 数据科学软件开发人员他们不直接参与数据科学管道的生产,而是开发促进数据科学的软件工具。例如 Hadoop、R、RStudio、IPython 笔记本、TensorFlow、D3、pandas 和 tidyverse 等的开发者。

这些角色中的每一个都需要非常不同的专业知识,在数据科学学术项目中应该有完全不同的方向。

我还认为,在现实中,有更多可能的数据科学角色。比如一个数据科学翻译员/通信员(?)谁拥有沟通管理团队和数据科学团队的技能。他/她可以通过可视化或演示,熟练地向外行人解释复杂的数据科学概念。许多数据科学项目被推迟或得不到资助,因为管理层没有完全理解背后的想法。另一个角色可能是某人(数据科学业务开发人员?)拥有丰富的领域专业知识,同时对数据科学概念有很深的了解。他善于将点点滴滴联系起来,发现可能给企业带来好处的有价值的数据科学机会。

数据科学教育需要什么

通过上面的概述,您可以看到数据科学实际上非常广泛,而机器学习和建模只是拼图中相当小的一部分。这意味着学术界需要更好地定义他们的课程提供什么,学习者需要更好地定义他们的目标,企业需要更好地了解他们在寻找什么。

文章建议学术界通过以下方式为学习者提供更好的准备:

  • 三个不同的方向:提供对应于数据科学不同方面的具体方向:数据工程师、数据分析师、机器学习工程师、数据科学软件开发人员等。
  • 突出应用:强调现实世界应用的必要性和问题的主题。课程需要联系实际实施。
  • 实际经验:对于那些有兴趣成为数据科学软件开发人员的人来说,开发软件包的顶点项目课程是他们在项目中寻找的。此外,学习者能够生成可靠且可重复的代码也非常重要,因为数据科学管道或应用程序需要为许多用户工作。这是一个经常被学术界忽视的培训方面。
  • 实用编程技能:针对特定角色和任务的适当语言的强大编程培训:

作者基于麻省理工学院文章的插图。

  • 关注研究生水平的项目:数据科学学位建议针对硕士或博士水平,而不是本科水平。

如果你是一名正在寻找数据科学教育的学习者,问自己以下问题非常重要:

  • 你希望自己扮演什么样的角色?
  • 你需要获得哪些相关技能?
  • 一旦你有了这些问题的答案,看看课程,看看它是否符合你的需求和期望。

如果你正在为一家企业招聘员工,务必小心使用数据科学家术语,并在工作描述中尽可能具体。从长远来看,每个人都能从中受益。

感谢您的阅读。享受学习!

量化医疗保健中机器学习公平性的新指标——closed loop . ai

原文:https://towardsdatascience.com/a-new-metric-for-quantifying-machine-learning-fairness-in-healthcare-closedloop-ai-fc07b9c83487?source=collection_archive---------51-----------------------

最近几起备受瞩目的不公平人工智能算法案件凸显了在任何人工智能系统开发的早期解决偏见的重要性。在大多数情况下,算法中不会出现偏见,这是因为创建算法的个人怀有恶意。偏见来自于在确保人工智能系统对每个人都公平方面缺乏勤奋。为了消除偏见,必须以与问题背景相关的方式来衡量。在医疗保健行业,偏差检测的“黄金标准”并不合适。正因为如此,ClosedLoop 开发了一种新的衡量医疗保健偏差的指标。

最近,有大量的努力来衡量和打击算法偏差。在他们 2018 年的论文[1]中,维尔马和鲁宾提出了一系列丰富的公平指标,并定义了所有公平指标使用的基本统计指标。这些指标各有优缺点,部署算法的环境决定了哪些指标是合适的。通常,实现公平的方法是基于不同影响【2】【3】的法律标准。当对不同群体的预测结果不同时,就会产生不同的影响。使用这一指标的例子有累犯[4]、雇佣[5][6]和贷款申请[2]。这个标准指标只考虑了一个因素:算法预测一个人应该从特定分类中受益的比率。

在医疗保健的背景下,不同影响的标准是完全不合适的。上述例子有一个共同的特点;该算法所适用的每一个人都将从正面标签中受益。如果人们不在乎结果,他们不会申请假释、工作或贷款。在医疗保健领域,尤其是人口健康领域,预测被用来分配资源,但是不同的群体受益不同。只有那些将遭受特定结果的个体从模型的干预中受益。在大多数情况下,特定结果的发生率在性别、种族和社会经济分组之间有显著差异。明显的例子是乳腺癌,不到 1%的病例发生在男性[7],或镰状细胞病不成比例地影响美国黑人8。不太明显的情况是跌倒伤害,女性发病率较高[9],或自杀率,性别和种族差异较大10。对于许多其他疾病,会出现更细微的差异,但差异仍然具有统计学意义。公平的常识概念当然不会期望偶数的男性和女性被确定为具有乳腺癌高风险,但这正是基于不同 影响的指标所优化的。因此,ClosedLoop 开发了一种专门适用于医疗保健的新的公平量化指标。

群体利益平等

我们提出了一种新的衡量公平的方法,称为“群体利益平等”。群体利益平等旨在衡量特定事件在子群体中的预测发生率与其实际发生率的比较。假设有一个带有预测标签y’和真实结果 y 的预测器。一个群体受益于该算法,因为在他们有一个肯定的预测(y’= 1)的情况下,提供者给予这些个体关注。在以下情况下,预测者被认为具有完美的群体利益均等性:

P(y '= 1 | C =C)= P(y= 1 | C =C)对于 C 中的所有 c

这里, c 是分区变量 C 的一个子组,C 可以是应该被检查保护的任何分区,包括种族、性别、年龄、医疗补助状态(收入的一个代理)和残疾状态。群体利益平等可以转化为比率 P(y '= 1 | C =C)/P(y= 1 | C =C)。在标准的准确性测量方面,组利益均等是(tp + fp)/(tp+fn),其中 tp 是真阳性的数量,fp 是假阳性的数量,fn 是假阴性的数量。如果该比率波动较低,这意味着该亚组被标记为以低于该亚组内事件发生率的速率进行干预。如果这个数字足够低于 1.0,这意味着该模型有可能通过拒绝向他们提供资源来损害这些子群体。因此,应该采取措施减少这种偏向,或者在分配资源时考虑到这种偏向。如果该比率波动较大,这意味着资源以高于该组需求的速度分配给该组。只要不引起另一组的第一种波动,这种波动是可以接受的。使用 0.8 的阈值将一个群体标记为潜在偏见,这来自不同影响的法律标准。

图 1——预测医疗保险受益人严重跌倒相关伤害的模型的群体利益平等,按性别划分。

为了了解如何使用这一指标,我们评估了其在一个模型中的应用,该模型用于预测未来 30 天内医疗保险患者的严重跌倒相关损伤。图 1 描述了一个预测严重跌倒相关伤害的模型的群体受益均等性。据观察,2010 年医疗保险记录样本的患病率为整个样本的 0.843%。如果我们按性别划分,我们观察到女性为. 975%,男性为. 686%。出于一致性的目的,选择一个阈值,使得整个样本的群体利益均等非常接近 1.0(在这种情况下,p>=.071 的决策阈值导致群体利益均等为 1.005)。该阈值意味着该模型将标记与观察到的伤害发生大致相同数量的处于危险中的个体。表 1 总结了这个阈值的性能和公平性。请注意,女性亚人群的患病率约为男性的 1.5 倍。可以看出,模型预测反映了这种不平等。不同影响的值是 0.569,远低于 0.8 的标准阈值;这意味着按照这个标准,这个模型对男性有偏见。相反,如果计算团体福利平等,则观察到 0.875 的分数。虽然在为这部分人口提供服务方面还有改进的空间,但人们不会认为这种模式对男性有偏见。

与现有指标的比较

群体利益平等类似于现有的“机会平等”措施。当两组的敏感度相同时(tp/(tp+fn)),机会均等。我们的度量在数学上的不同之处在于分子中存在假阳性项。如果存在这样一个相似的术语,为什么人们会选择使用不同的度量来报告公平性呢?群体利益平等的优势在于其透明度和易于解释。群体利益平等的一个巨大优势是有一个调整决策阈值的默认目标。即使大多数提供者选择在略高于事件流行率的报警率下运行,我们设定的阈值使人群的受益均等为 1.0。对于平等机会,没有规定这样的准则。没有机会均等的默认水平为实践者提供了改变他们的决策阈值的机会,以使他们的模型公平看起来更好。

群体利益平等也得益于对公平更直观的解释。此度量直接衡量针对某个组发出的警报及其发生率。虽然人们可以看到所有子群体的平等机会,但对于什么构成不可接受的偏见,并没有明确的界限。这类似于皮尔逊相关或回归中误差平方和的差值。虽然两者都量化了模型的性能,但前者更容易理解和解释;不出所料,这是大多数人用来描述回归模型的指标。为了实现这种效果,许多公平性度量被表示为受保护子组与基本子组的商[2]。由于医疗保健的目标是向那些需要干预的个人提供干预,选择参考亚组意味着模型将使公平性评估对基础类别的警报率过低的情况视而不见。在大多数情况下,男性是性别的基本类别,因此使用这种方法,公平性评估将完全无视该亚群体的潜在缺点。

图 2——根据年龄划分,预测医疗保险接受者严重跌倒相关伤害的模型的群体受益均等性。

这个模型的最后一个优点是警报的内在经济观点。图 1 描述了数据集中几个年龄组的群体福利平等。查看该图,可以发现 65-74 岁人群的得分很低。该模型建立在医疗保险账单数据的基础上,因此该群组实际上代表了数据中最大的群体。从分布来看,这个亚组中较低的预测率是由 18-64 岁和 85-100 岁组中较高的预测率直接造成的。由于这一模型来自医疗保险数据,18-64 岁范围内的个体通常因严重的医疗并发症而残疾。另一组,85-100 岁,是最老的,也是最容易受到这类伤害的人群。通过这种方式,对预测高风险人群有偏见的解释使得在我们大部分人口中较低的预测更容易理解。

个案研究

为了抗击新冠肺炎,ClosedLoop 建立了一个开源工具,用于量化由于新冠肺炎感染导致的严重并发症的脆弱性,称为 CV19 指数。众所周知,新冠肺炎老年人的死亡率很高。ClosedLoop 构建了 CV19 索引的多个实例。一个模型针对医疗保险人群,一个针对医疗补助人群。这两个群体有非常不同的动态,因此跨年龄线看公平是这一措施的自然分解。该模型的第一个实例是在医疗保险人口的 5%样本上训练的。图 3 显示了该人群的群体利益平等。有趣的是,在混合人群中 3%的警戒率下,这个模型低估了年轻人群。要理解这一点,重要的是要记住医疗保险主要是 65 岁以上的个人。医疗保险确实允许这个年龄以下的人被纳入,但是这些人有严重的健康状况。结果是,当这个模型应用于一般人群时,它高估了年轻人的健康脆弱性。

图 3——基于医疗保险数据的新冠肺炎模型的群体福利平等。

类似地,我们可以检验根据一般人群的医疗补助数据训练的模型的性能,如图 4 所示。有趣的是,完全相反的组在较低水平被触发。恰恰相反的动态在起作用。65 岁以上的人通常享受医疗保险,而不是医疗补助。然而,一些有严重医疗需求的个人有双重资格。结果很明显,这是为什么将模型应用于相同人群非常重要的例证。

图 4——根据医疗补助数据训练的模型在一般人群中测量的新冠肺炎模型的群体利益平等。

为了有一个在一般人群中执行的模型,我们创建了一个混合模型,如图 5 所示。一旦一个人年满 65 岁,就从医疗补助模式转换到医疗保险模式,并按比例调整医疗补助预测,从而混合了这些模式。在这里,我们观察到大多数年龄组的总体良好表现。对于最年轻的人群来说,这是相当直观的。大多数年轻人不会有严重的新冠肺炎并发症,即使有,数据也支持这种不可预测的观点。随着更多关于经历这种并发症的年轻个体的信息出现,将这些信息纳入这些模型是高度优先的。

图 5——根据来自医疗保险和医疗补助数据的整体模型,在普通人群中测量的群体福利平等。

结论

没有一个单一的指标是对抗算法偏差的灵丹妙药。从业者应该计算几个偏差指标,如群体利益平等和机会平等,并批判性地思考可能观察到的任何差异的影响。也就是说,拥有一个易于解释的单一指标是有帮助的,它受益于一个透明的过程,并且当一个模型存在潜在偏差时,它具有定义良好的目标值和阈值。群体利益平等唯一满足所有这些要求,是医疗保健中量化算法公平性的最佳指标。

参考

[1]维尔马,萨赫勒和朱莉娅鲁宾。"解释了公平的定义。" 2018 IEEE/ACM 软件公平性国际研讨会(FairWare) 。IEEE,2018。

[2] IBM 云。“公平指标概述”。【https://cloud.ibm.com/docs/ai-openscale? topic = ai-open scale-anlz _ metrics _ fairness

[3]费尔德曼,迈克尔等人,“证明和消除完全不同的影响。”第 21 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集。2015.

[4]亚历山德拉·乔尔德乔娃。"具有不同影响的公平预测:对累犯预测工具偏差的研究."大数据5.2(2017):153–163。

[5]杰弗瑞·达斯廷。“亚马逊废弃了对女性有偏见的秘密人工智能招聘工具”。https://www . Reuters . com/article/us-Amazon-com-jobs-automation-insight/Amazon-scraps-secret-ai-recruiting-tool-that-show-bias-against-women-iduskcn 1 MK 08g

[6] Ajunwa,Ifeoma 等人,“通过算法招聘:预测和防止完全不同的影响”在 SSRN (2016)上市。

[7] Anderson,William F .等人,“男性乳腺癌:与女性乳腺癌的基于人群的比较。”临床肿瘤学杂志 28.2 (2010): 232。

8疾病控制和预防中心。“镰状细胞病的数据和统计”。【https://www.cdc.gov/ncbddd/sicklecell/data.html

[9]史蒂文斯、朱迪·a 和埃伦·d·索戈洛。“老年人非致命意外跌落相关伤害的性别差异。”伤害预防11.2(2005):115–119。

10莎莉·柯廷和玛格丽特·华纳。"按种族和族裔分列的女性和男性自杀率:美国,1999 年和 2014 年"。国家健康统计中心。https://www . CDC . gov/nchs/data/hestat/suitary/rates _ 1999 _ 2014 . htm

原载于 2020 年 3 月 2 日https://closed loop . ai

一个新的 Python 包:如何检测异常?

原文:https://towardsdatascience.com/a-new-python-package-how-to-detect-an-anomaly-fcff730778a3?source=collection_archive---------18-----------------------

来源

背景

每次我从新设备或新位置登录 Gmail 收件箱时,它都会发出一个标记,警告我可能存在未经授权的访问。每当我收到这样的通知,我就会想,为什么每次我去一个新的地方,谷歌都要发送这样的通知。想象一下,如果我的工作需要我经常出差到一个新的地方,我的收件箱就会充满这些安全警报——用数据科学的说法就是误报。

假阳性的问题

这些误报是所有数据科学项目中的常见问题,是一种潜在风险,尤其是对于异常检测用例。在这种情况下,大量的误报会导致解决方案不可用。问题变得更加复杂,因为一般来说,这些数据集没有大量的真阳性可以用来训练机器。

一个很好的例子是银行欺诈检测系统,在大多数情况下,在数百万次批准的交易中,实际欺诈交易不到 1%。此外,如果您遇到这些交易的特征,大多数都是分类特征,唯一真正的数字特征是付款或交易金额。

基于规则的欺诈检测系统主要依靠“交易金额”功能来检测异常交易。这就是为什么你每次高价购买时都会接到银行的电话。然而,这些高价值的购买在所有小额购买中并不常见,因为平均来说,人们每 2 到 3 年才会买一次 iPhone。

因此,仅仅根据交易金额来标记交易必然会导致大量的误报。实际上,这个基于规则的系统并没有试图标记真正的异常,而只是试图保护银行免受巨大的美元损失。

相反,数据中的分类特征具有有限数量的可能值,例如,您将向一组国家/地区付款,而一个新的国家/地区可能是异常的。同样,这可能是高假阳性的来源。就像我们之前的 Gmail 功能一样。

因此,需要一种基于客户行为的动态性而不是纯粹基于新值进行标记的算法来克服高阳性的问题。一个新的 Python 库就是解决方案: CategoricalOutlier

这里是 Github 的代码链接。

简介

该软件包的目标是纯粹基于分类特征对异常值进行评分。该算法的训练要求您提供数据中所有分类特征的列表以及 0 到 100 之间的阈值。阈值非常重要,因为它决定了你愿意承担的风险。价值越高,风险越小。对于每个新的观察,预测是 0 到 1 之间的异常分数。

对二维模型的阈值意义的直观解释。对于 50 的阈值,最内圈之外的任何东西都将是异常的。对于 99 的阈值,最外圈之外的任何东西都将是异常的——图片由作者提供

理论讲得够多了,让我们来谈实质的东西吧。

出于演示目的,我将使用从这里的获得的信用卡交易数据。我将提供数据集的概述,之后我们将在数据上训练我们的算法,并对测试支付进行预测。

数据

该数据是德国信用卡交易数据,具有以下特征及其相应的类型

数据集中的要素-按作者分类的影像

如您所见,20 个特征中有 15 个是绝对的,可以提供关于潜在欺诈付款的重要信息。

这个博客和软件包的范围仅限于预测异常的分类特征,因此,我将忽略数字特征。此外,目前大多数其他异常检测方法都集中在数字特征上。这是一种根据分类特征对观察结果进行评分的算法。

从数据集中,我接受了付款,这些付款被批准为真实的,由数据中的最后一列确定。这些付款将用于建立付款档案,新交易将根据该档案进行评分。该算法的一个主要优点是,它只需要批准的交易,而不依赖于历史欺诈交易来获得新的支付。它会自动消除冷启动问题。

形象化

在构建模型之前,让我们对分类特征进行一些可视化处理,并查看分布情况,以了解更多关于支付性质的信息。以下是一些重要的特征-

分类特征的分布—按作者分类的图像

一些观察-

信用记录——很少有付款的信用记录是“全部付清”

目的——支付目的通常是家用物品,如电视

就业——失业人数不多

担保人——有担保人是很少见的

训练模特

下一步是对所有批准的交易训练一个模型。我选择的阈值是 95。使用从类别输出者库中导入的 TrainOutlier 类来执行训练。cat_cols 是数据帧中所有分类变量的列表。

cat_cols = [‘CheckAccStatus’, ‘CreditHistory’, ‘Purpose’, ‘Savings’, ‘Employment’, ‘PersonalStatus’, ‘Guarantors’, ‘Property’, Installment’, ‘HousingType’, ‘Job’, ‘Telephone’, ‘Foreign’]**from categoricaloutlier import TrainOutlier, PredictOutlier**trainedprofile = TrainOutlier(95,cat_cols)
trainedprofile.train(df_train)

为了简单起见,训练是在具有大约 700 个观察值的相对较小的数据集上进行的。对于用于训练的数据观察的最小数量没有限制,但是,观察越多,从观察构建轮廓就越好。

trainedprofile 对象是对所有已批准的付款进行训练的模型,该模型将用于对新付款进行评分。

对欺诈交易评分

现在我们已经有了训练好的模型,让我们使用这个模型对一个新的交易进行评分,看看它的表现如何。我从同一数据集中选择了 3 笔被归类为欺诈的付款,以检查模型预测的内容。这些支付不是训练数据集的一部分。

对实际欺诈付款的评分-按作者排序的图片

交易 1 —由具有良好信用记录并有担保人的人支付,这在训练数据中相当少见。因此,使用基于规则的系统很难将此标记为欺诈交易。然而,该模型很好地将其归类为风险交易,得分为 75 分。

交易 2 —该支付发起人在就业、技能、财产所有权方面有着良好的历史。但是,这个人没有存款,这对于一个信用记录很好的人来说是很少见的。这解释了该模型不仅仅基于一个特征进行预测,而是结合多个特征来得出风险分数。支付得到 63 分,这是潜在的欺诈。

交易 3 —另一笔付款,与第一笔类似,但是,个人有更好的技能和就业历史。然而,他住在免费的住处。该模型生成的分数为 55,接近阈值,表明该特征并不罕见。

这 3 个事务给出了模型性能的一个合理的概念。这里值得注意的一点是,该模型能够完全基于分类特征来标记交易。结合数值特征的集合技术肯定会进一步提高解决方案的性能。

得分误报

我想测试的一件事是检查模型对最初被归类为误报的付款的性能。也就是说,被标记为潜在欺诈的交易结果却是真实的交易。不幸的是,数据集没有明确提供任何例子。

为了测试误报的性能,我挑选了几笔交易,由于它们的历史,这些交易会被标记为潜在的欺诈。我将在这里讨论两个这样的交易以及该模型生成的相应分数

误报评分-按作者排序的图片

交易 1 —付款由没有支票账户的个人进行,代表延迟偿还其先前的信用,并且没有技能。更有可能是潜在的欺诈交易;然而,该模型给它的评分很低,为 12。它提供了一个避免虚惊一场的好例子。

交易 2 —基于规则的引擎会标记此人执行的大多数交易,因为他的信用记录不佳。然而,该模型给出了一个 2 分的低分数,引用了他在住房、储蓄和就业方面的有力凭证。

结论

到目前为止,该模型给了我合理的结果,并对每笔交易进行了内在的解释。我想让你试试这个算法,告诉我这种方法是否有缺点。我很想纠正它。您可以直接从 PyPi 资源库下载,或者在 GitHub 中派生代码。

为您的下一个机器学习数据可视化项目提供新的技术堆栈

原文:https://towardsdatascience.com/a-new-tech-stack-for-your-next-machine-learning-data-visualization-project-ea64e3de3241?source=collection_archive---------19-----------------------

作者 Gif

Observable/D3.js 和 Google Colab/Python 技术栈— 设计交互式、可配置、动态数据可视化的案例

数据可视化是交流结果和制定决策的最重要工具之一。没有它们,我们只能看原始数据,这显然不好玩。设计动态和交互式数据可视化的最有效和最流行的工具之一是 D3 JavaScript 库。虽然众所周知程序员在学习和使用 D3 的低级 API 方面有很多问题,但熟悉其复杂性的人会知道,它仍然是设计交互式和动态可视化最有效的工具。尽管如此,如果你曾经遇到过你的研究顾问或经理批评可视化的一个小方面,如颜色或缺少图例,你知道可视化,即使是由 Excel 这样的高级应用程序创建的,更新起来也是一件令人沮丧的事情。此外,当人们想到数据科学编程语言时,大多数人会想到使用 R 或 Python,很少有人会想到 JavaScript。因此,与 D3.js 的情况一样,可视化与可能有问题的机器学习算法是分开的。如果我们把它翻过来,只剩下 Python,我们通常会局限于在 Matplotlib 中设计静态可视化,这可能是笨重的、静态的、难以调整的。

很明显,需要灵活的数据可视化;然而,这种对灵活性的需求不仅仅是外观和编程语言。我们还需要知道与数据可视化相关的权衡。例如,如果我们使用一个回归任务的线图,我们应该显示误差线吗?我们的直方图中的数据是否应该归一化,这个决定的确切后果是什么?数据可视化本身应该能够回答这些问题,并为其推理提供正当理由。最后,我们的可视化需要是动态的!Excel 很棒,但是我们经常从其他来源导入或复制粘贴数据。如果这个来源改变了,我们的可视化将保持不变,如果我们使用这个可视化积极地做决策,这可能是一个问题。

很明显,我们需要一个有效的技术堆栈来考虑所有这些问题。以此为动机,我将描述我最喜欢的机器学习数据可视化技术栈,最终结果看起来相当不错

…看看这里!

这篇文章涵盖了什么

  1. Observable/D3.js,Google Colab/Python 技术栈
  2. 案例:混淆矩阵
  3. 将 Observable 连接到 Google Colab 笔记本

资源

  1. 可观察笔记本 : D3 数据可视化的一个混乱矩阵

第一节。一个有效的可视化技术栈

机器学习数据可视化技术栈

数据可视化环境: Observable 是一个在 JavaScript 笔记本环境下设计数据可视化的网站。笔记本中的每个单元都由代码块组成,这些代码块可用于功能(如操作数据、导入包等)或操作 DOM(如通过 HTML 或 SVG 创建可视化)。可观察的快速介绍可以在这里找到。Observable 的主要优势是它的易用性、可读性和社区支持。

JavaScript 仍然是设计数据可视化最流行的语言。这个技术栈将使用 D3.js,这是一个流行的 JavaScript 库,用于创建交互式和动态可视化以及编辑 Observable 中的 DOM。D3 的优势在于它是开源的、轻量级的,并且提供了一个低级的 API(虽然也有更高级的 API,比如 D3FC ),随着数据可视化变得更加复杂,这个 API 变得越来越重要。

机器学习/数据生成环境:数据分析通常需要一台比大多数个人程序员所能获得的更强大的计算机。幸运的是, Google Colab 提供了一个免费的、GPU 支持的笔记本运行时环境,可以在 Google 的云上执行 Python 代码。除了强大的 GPU 后端之外,Google Colab 的优势还在于可以将 Google Drive 安装为存储设备来保存结果,使协作和共享变得容易,并且因为它运行在云上,所以您不需要担心在自己的机器上安装庞大的 Python 包,如 Tensorflow、Keras 或 PyTorch!Python 的主要优势是其庞大的数据科学社区支持、各种高级包、可读性和易开发性。

机器学习数据可视化设计目标

一般来说,在设计数据可视化时,无论使用何种技术,都应该考虑一些经验法则:

  1. 虽然简单往往更好,但交互式可视化可能更有效。
  2. 只有数据生成源尽可能靠近数据可视化,才能实现实时、动态的可视化。
  3. 可视化,就像算法一样,伴随着权衡,这应该由可视化本身来清楚地解释。
  4. 改变可视化的风格(字体大小,颜色等)应该很容易,而不是一个时间水槽。大部分时间和决策应该是在可视化的信息方面。

考虑到这些目标,让我们看看如何使用 Observable/D3.js 和 Google Colab/Python 环境来创建有效的机器学习数据可视化。

第二节。案例:混淆矩阵

这种技术堆栈的有效性将通过设计可视化来分析监督任务中分类模型的性能来显示(即,我们在带标签的数据集上训练模型来分类未知实例)。用于分析分类模型的性能的最流行的数据可视化之一是混淆矩阵,对于具有 k 个可能类别的监督任务,它由一个 k x k 矩阵组成,该矩阵被设计成矩阵的列代表基本事实,行代表模型的预测。例如,第I列和第j行中的单元格描述了模型预测类 i 实例的相对次数,如标签 j 所示。矩阵的对角线(即 j=i) 显示了每类的真实阳性率。图 1 显示了混淆矩阵的一个例子。

图一。D3 . js 可视化在 Observable 中的最终结果。(来源:作者)

为了加速开发,首先设计数据可视化的概要通常是有用的。混淆矩阵可视化的主要部分可以在下面的图 2 中找到。虽然我不会深入研究用于设计如图 2所示的数据可视化的 JavaScript 代码。(可以在可观察笔记本中找到),我将描述这个技术堆栈如何让我增强可视化的灵活性、交互性和可解释性。

图一。混淆矩阵可视化主要组件的基本布局。(来源:作者)

灵活性和交互性

D3.js 用于实现灵活性和交互性。首先,数据可视化的标签(包括标题和轴标签)是使用 JavaScript 抽象的,以允许用户交互。例如,用户可以使用滚轮(即双指滚动)来增大/减小字体大小,或者通过拖动动作来平移标签。我还在 Observable 中创建了单独的单元格,允许用户在必要时更改这些标签的文本。此外,轴刻度字体大小也可以使用滚轮增大/减小,图例也可以通过拖动进行转换。Observable notebook 中的输入单元格还允许您调整图形的颜色(目前支持蓝色、绿色、橙色和红色)。

除了微小的外观修改之外,其他输入单元格对图表的功能性影响更大。例如,一个单元格提供切换输入来确定文本是否应该出现在单元格中以显示单元格的值。如果有很多类,这个文本会造成混乱,因此需要禁用;然而,在很少出现类的情况下,该文本提供了可能对数据科学家有用的附加信息。在另一个输入单元格中,您可以选择如何(如果有的话)规范化填充混淆矩阵中单元格的数据。这个决定的后果在可观察笔记中有解释。

可解释性

可解释性不仅仅意味着提供有用的数据可视化——它意味着理解可视化背后的权衡,提供可以回答不同问题的替代方案,然后解释这个问题到底是什么。这就是 Observable 的降价/latex 支持派上用场的地方。

图三。如果你刚刚看到这些各种各样的统计数据,你会知道它们意味着什么吗?我也没有。(来源:作者)

例如,通常在数据科学中,单变量(单个变量)统计是首选的,如均值或标准差,因为它们简单且易于比较。虽然混淆矩阵提供了模型性能的整体视图,但是仅使用它们的混淆矩阵来比较各种分类器可能是困难的。因此,数据科学家经常将混淆矩阵与精确度、召回率和 F1 分数等统计指标结合起来(在可观察笔记中有解释)。将这些统计数据简化为单变量指标;然而,我们必须对每类度量的 k 取平均值,当然,平均技术会产生提供不同信息的不同统计数据。唷!

幸运的是,在 Observable 中,我们能够用 Markdown 来注释可视化,以解释决策,并使用 Latex 来简洁地描述底层数学。因此,我们可以充分解释设计决策,例如使用加权平均值与微平均值(提示加权平均值通常是首选),或者跨列而不是行进行标准化。我知道我一直在说它,但如果你还没有检查过可观察的笔记本,我强烈推荐它来看看我的意思!Observable 通过为开发人员提供解释工具,在使事情变得更容易理解方面做了大量工作。虽然可能需要更多的时间来开发,但是提供各种度量标准的简短解释将有助于为将来使用可视化的任何人节省大量时间。

分享你的想象!

Observable 的一个主要优点是可视化很容易发布和共享。例如,如果您需要与同事分享您的可视化效果,该怎么办?一种方法是通过点击可视化旁边的省略号将可视化导出为静态实体,然后将可视化下载为 SVG 或 PNG。然而,如果您需要可视化来保持动态呢?这里你有几个选择。首先,您可以发布可视化,在这种情况下,可视化现在是公开的(像我一样),或者您可以简单地将链接复制并粘贴到同事,在这种情况下,可视化对拥有链接的人保持私有。在开发人员方面,Observable 允许用户派生项目进行自己的编辑。Observable 甚至支持自己的版本控制类型,尽管我承认无法合并令人沮丧。尽管有这个缺点,一旦你在 Observable 中制作了一个可视化的东西,分享、编辑和发布就很容易了!

第三节。将 Observable 连接到 Google Colab 笔记本

如果你碰巧在早些时候检查了可观察的笔记本,你可能会看到它被虚假的数据填充;但是,上传自己的静态数据或者将笔记本连接到动态数据是很容易的!这就是 Google Colab 和 Python 发挥作用的地方,允许您将可视化直接与机器学习算法和数据源进行通信。

另外,上传静态数据就像上传一个 JSON 文件到 Observable notebook 并使用这个简单的一行程序data = (await FileAttachment('YOURFILENAME.json').json()).data在单元格中正确引用它一样简单。

然而,更有趣(也更有用)的场景是将数据可视化直接连接到数据生成源。为了实现这一点,我们使用 HTTP 请求。下面的代码片段创建了一个 JavaScript 块,可以添加到 Observable 中,每 6000 秒从某个端点获取动态数据。

代码片段 1。每 6000 秒在/data 获取内容,动态更新响应变量单元。

现在,剩下的就是创建一个 Python 服务器,在 Google Colab 运行时的后台运行。为了实现这一点,我使用了 FlaskNgrok ,前者是一个简单的 web 框架,为处理 HTTP 请求提供后端支持,后者为能够绕过 NAT/防火墙的本地主机提供安全隧道。为什么这是必要的?为了让 Observable 到达一个端点,它必须是公开的和安全的(例如 HTTPS)。Ngrok 提供了一个安全的、公共的、基于云的端点,Observable 可以访问并使用该端点隧道连接到本地 Flask 主机,在这个场景中,本地 Flask 主机位于 Google 的云环境中。这看起来很多,但是当使用 flask-ngrok 时,这实际上是一行程序。以下代码片段可用于在 Google Colab 笔记本的后台运行服务器,该服务器在公共 URL 上提供数据。注意:服务器是在一个线程中执行的,因此 Colab 环境中的其他单元可以并发执行。

来自 2020–07–11 16–46–04代码片段 2 的截图。在 Google Colab 环境中的公共托管 ngrok 服务器上运行 flask 服务器。

一旦成功执行,代码片段 2。会在 Google Colab 环境的输出中打印出类似下面的东西。

图 4。这意味着你的服务器已经启动并运行在 Google Colab 上。

就是这样!您的服务器现在可以在打印的公共 URL 的data路径上提供数据了。你所要做的就是更新 Observable notebook,创建一个指向公共地址的server_url单元格(上例中的https://B2B 83913 d2c 4 . ngrok . io)。在 Google Colab 环境中更新YOURDATA变量取决于您,这个变量实际上存储了您想要发送给 Observable 的数据。在代码片段 2 中。,我将数据变量指定为全局,以便其他单元格可以操纵它;然而,对于更安全或更复杂的应用程序,您可能需要将数据隐藏在以数据库为目标的单独查询之后。最后,当您使用完服务器或需要重启它时,在 Google Colab 的另一个单元格中运行kill_server()

我应该注意到,虽然我使用了 GET 请求,但是可以向 Colab 环境发送命令,从而改变 Python 代码的行为。这在我们的可视化实际上用于支持学习算法的训练而不是简单地分析其性能的场景中是有用的。POST 请求可以用于实际修改模型的学习方式,并支持人工监督的学习!

第三节。结论

数据可视化是交流复杂信息的重要方式,但是它们很难有效地设计。因此,利用现有最佳工具的优势非常重要。在这篇文章中,我描述了一种新的技术栈来完成各种机器学习数据可视化任务。该堆栈使用 Google Colab/Python 来执行机器学习/数据生成任务,这可能包括监控机器学习算法、评估已训练模型的性能或执行数据探索,如降维或聚类。然后,通过将数据源直接链接到 Observable/D3 数据可视化环境,可以实现灵活、交互式和动态的数据可视化,这可以用于共享、发布或进一步的协作。

希望你能找到这些技术的一些用途——感谢阅读!

一种新的机器学习建模可视化方法

原文:https://towardsdatascience.com/a-new-visual-approach-to-machine-learning-modeling-87d620b56cae?source=collection_archive---------54-----------------------

机器学习(ML)工具正在爆炸和专门化,为用户提供了以不同方式构建和管理 ML 模型的选择,从编写代码、依赖框架到使用自动化解决方案,每种方式都有其优缺点。好消息是,PerceptiLabs 通过我们的可视化建模器开发了下一代 ML 工具,使模型构建更容易、更快,并且更广泛的用户都可以使用,无论您是专家还是初学者。

为了理解这个工具的重要性,让我们后退一步,回顾一下 ML 是如何发展的。

一开始,人工智能(AI)是为那些只用纯代码开发算法的博士们保留的。他们必须运用想象力在头脑中想象他们的模型。随着人工智能和人工智能的发展,人工智能从业者的经验水平多样化,将人工智能民主化的努力变成了一套丰富的开源框架和数据集。

这些产品中的许多都需要高级知识,并且仍然依赖专家来编写端到端的 ML 解决方案。在构建定制解决方案时,这可能有一些优势,但可能需要在资源、基础设施和维护方面进行大量投资。

最近推出了各种 AutoML 工具,这些工具承诺端到端的能力,其中输入数据,调整参数,并生成经过充分训练的可部署 ML 模型。这听起来很简单——实际上在某些场景中是合适的——但是,通过 AutoML 创建的 ML 模型通常缺乏对其性能和可解释性的透明性(例如,它们为什么产生某些结果)。同样,AutoML 解决方案经常限制用户只能使用几种 ML 技术。

下一代 ML 建模

我们已经看到 TensorFlow 成长为最流行的 ML 框架。我们也明白,并不是每个 ML 领域的人都在模型构建方面有丰富的经验。因此,我们开始创造一种更好的方式来授权给更大范围的用户,从专家到初学者。

我们将我们的工具设计成基于 TensorFlow 之上的可视化 API。这为开发人员提供了对低级 TensorFlow API 的完全访问,以及引入其他 Python 模块的自由,同时为初学者提供了一个具有 AutoML 的一些简单性的易于使用的 GUI。

让用户完全透明地了解他们的模型是如何构建的,以及他们的模型是如何执行的,这一点非常重要。结果是一种新的可视化方法,它提供了纯代码的灵活性、拖放 UI 的简易性,以及连接组件、生成模型架构以及调整设置和超参数的一些自动化。

图 PerceptiLabs 截图。左上:用于设计模型的建模工具;左下角:用于管理模型的模型中心屏幕;右上:培训期间显示的统计视图;右下:代码编辑器和调试窗口。图像由感知。

ML 建模方法一览

纯代码与 AutoML 以及感知器实验室的适用范围。图像由感知实验室提供。

在构建机器学习模型时,你有很多选择,每种方法都需要根据你可用的资源进行仔细评估。

这就是为什么在 PerceptiLabs,我们认为我们建立机器学习模型的新的视觉方法,在广泛的 ML 用户中取得了恰到好处的平衡,同时提供了更好的可解释性,复杂性和可用性。这是一种灵活而全面的方法,让您根据自己的经验和项目需求选择想要的工作方式。

如果这听起来很吸引人,你可以从我们免费的、功能齐全的个人版 PerceptiLabs 开始。查看我们的快速入门指南了解更多信息。

一种新的 BOW 分析方法&特征工程(一)

原文:https://towardsdatascience.com/a-new-way-to-bow-analysis-feature-engineering-part1-e012eba90ef?source=collection_archive---------63-----------------------

在不建立 ML 模型的情况下,比较跨标签的频率分布。

卢克·切瑟在 Unsplash 上的照片

我的一个朋友问了我一个问题——“我们如何在不同的类别或标签之间比较蝴蝶结?其中类别或标签可以是情绪或状态或某个客户群。

我的直觉反应是——为每个类别创建一个词频条形图。这确实是一个易于实现的解决方案,但是有各种缺点,其中一些是:

  • 从事这项工作的数据科学家/分析师需要比较所有类别中的单词及其频率,在某些情况下,如国家或地区,可能会轻松超过 100 个
  • 比较频率可能不会给出任何见解。例如,我们有一个词——“数据”,它在标签 1 和标签 2 上的出现频率分别是 150 和 100。是的,的确有 50 英镑的差别,但这种差别有意义吗?
  • 如果——我想知道在没有建立模型/分类器的情况下,区分这些类别的最热门的词是什么,有没有一种方法可以分辨出来?

然后下一个想法是创建一个单词云,但即使它也没有解决上述问题。

经过一段时间的思考,我知道解决方案在于比较不同类别的频率,但在一键编码或计数矢量化或 TF-IDF 中找不到答案,因为在使用这些方法时存在一个常见问题。

问题是这些为每个文档创建特性和它们的值,然后我们如何在标签/类别级别上进行汇总?甚至让我们以计数矢量器为例——我们将获得每个文档中出现的单词的频率——但是要在标签/类别级别进行任何分析,我们将需要合计计数并汇总到类别级别。一旦我们积累起来,我们肯定可以使不同标签上的词的频率有所不同,但同样——这不能解决上面提到的第三个问题。也就是说,如果单词“数据”的频率差是 50,它告诉我们什么?这有意义吗?

现在,你可以猜测我们正在走向哪里——我们在频率上有差异,我们想知道这些差异是否显著。随之而来的是帮助我们的统计数据

我假设你知道各种测试,如 z-测试,t-测试,方差分析等。我们使用这些测试来比较多个平均值或分布,这与我们在这里试图解决的问题是一致的。

下表包含一个词在标签上的出现频率—目标 0 和目标 1。,也就是分布图。我们可以很容易地使用像 z-检验,t-检验等测试。并且比较这些分布,并且如果差异被证明是显著的(给定显著性水平),我们可以说这样的词在标签上具有不同的分布,并且因此可以是模型中的区分因素。

标签中单词的出现频率—目标 0 和目标 1

因此,这样我们甚至可以将这种技术用于特征工程,并减少模型中的特征数量。

简单对吗?是的,确实只有在我们处理完最后一点之后。

z 检验t 检验、ANCOVA参数检验,这意味着它们对数据做出假设,其中一个主要假设是数据呈正态分布。

但是,这种假设可能对数据集中的所有特征/单词都成立,也可能不成立。因此,我们将不得不依靠一些非参数测试,这些测试不做任何这样的假设。

我们很少有这样的测试,我们将使用的唯一测试是曼惠特尼 U 测试。该测试一次比较两个分布,非常适合我们使用二项式标签的情况,以及使用多项式的情况,我们可以使用克鲁斯卡尔-沃利斯测试

Kruskal-Wallis 检验类似于 ANOVA,它告诉我们标签之间的分布是否相同,但它不告诉哪些标签的分布不同,为了得到相同的结果,我们可以应用成对的 Mann Whitney U 检验。

让我们应用所有的学习,同样的,来自 Kaggle 的灾难推文分类数据集也被使用。

读取数据集。

train_df = pd.read_csv("/kaggle/input/nlp-getting-started/train.csv")[['target', 'text']]print("Size of the data: ", train_df.shape[0])
train_df.head(2)

一些样本记录

现在,我们将使用 CrazyTokenizer 将数据集中的句子转换为单词包。此外,一些额外的清理是在下面的预处理函数中完成的。

该函数将被传递给 CountVectorizer,它将给出输入数据集中每条记录的单词频率。

ctokenizer = CrazyTokenizer(lowercase=True, normalize=1, remove_punct=True, ignore_stopwords=True, stem='lemm', 
                            remove_breaks=True, hashtags=' ', twitter_handles=' ', urls=' ')ctokenizer.tokenize("There's an emergency evacuation happening now in the building across the street")

句子的结尾

# the preprocessor function for CountVectorizer
def preprocessor(text):# split the sentence into tokens
    tokens = ctokenizer.tokenize(text)# remove any numeric character
    tokens = [re.sub(r'[0-9-]+', '', token) for token in tokens]# remove stop words or any token having size <3
    tokens = [token for token in tokens if len(token) >= 3]

    return " ".join(tokens)# create the CountVectorizer object
cvectorizer = CountVectorizer(preprocessor=preprocessor, min_df=20)# to get the features
features = cvectorizer.fit_transform(train_df['text'])# create a dataframe of features
features = pd.DataFrame(features.toarray(), columns=cvectorizer.get_feature_names())
features.head(5)

使用计数矢量器创建的要素

现在让我们把目标变量和特性一起带来。

# merge features with the reviews_data to get labels
train_df_w_ft = pd.concat([train_df[['target']], features], axis=1)
train_df_w_ft.head(5)

具有目标变量的特征数据

现在,我们将绘制一个条形图,显示属于每个目标值的前 30 个单词。

def plot_bar_graph(xs, ys, names, xlabel, ylabel, title):# create figure object
    fig = go.Figure()# create bar chart for each of the series provided 
    for (x, y), name in zip(zip(xs, ys), names):fig.add_trace(go.Bar(x=x, y=y, name=name, orientation='v'))# Here we modify the tickangle of the xaxis, resulting in rotated labels.
    fig.update_layout(
        barmode='group',
        autosize=False,
        width=1300,
        height=500,
        margin=dict(l=5, r=5, b=5, t=50, pad=5),
        xaxis={'type': 'category', 'title': xlabel},
        yaxis_title=ylabel,
        title=title
    )
    fig.show()top_x = 30words_lists = []
frequencies = []
targets = []for target in train_df_w_ft['target'].unique():# add label name
    targets.append("Target-{}".format(target))# get the top words
    word_freq = train_df_w_ft[train_df_w_ft['target'] == target].iloc[:, 1:].sum(axis=0)
    word_freq = sorted(word_freq.to_dict().items(), key=lambda x: x[1], reverse=True)[: top_x]# append the words
    words_lists.append([x[0] for x in word_freq])# append the frequencies
    frequencies.append([x[1] for x in word_freq])plot_bar_graph(words_lists, frequencies, targets, "Words", "Frequency", "Frequency of Words across Targets")

目标值中前 30 个词的出现频率。

在上图中,我突出了两个词——“火灾”和“紧急情况”。对于单词“fire ”,目标之间的频率差异很大(~ 180 °),而对于单词“emergency ”,差异非常非常小。

正如我们上面讨论的,我们的目的是确定这些差异是否显著,这很重要,因为两个单词都出现在两个目标值的句子中。我们想知道它是否使这些特征变得无关紧要,即它们在决定一个句子是属于目标 0 还是目标 1 时是否有发言权。

下面是单词“fire”的曼-惠特尼 U 检验结果。

fire_data0 = train_df_w_ft[train_df_w_ft['target'] == 0]['fire']
fire_data1 = train_df_w_ft[train_df_w_ft['target'] == 1]['fire']mannwhitneyu(fire_data0, fire_data1)

从测试中,我们得到了小于 0.05(我们的显著性水平)的~0 的 p 值,因此,我们可以得出结论,“火灾”的频率分布在目标值之间有显著差异(置信度为 95%)。

让我们来看看同样的“紧急情况”。

emergency_data0 = train_df_w_ft[train_df_w_ft['target'] == 0]['emergency']
emergency_data1 = train_df_w_ft[train_df_w_ft['target'] == 1]['emergency']mannwhitneyu(emergency_data0, emergency_data1)

此处,p 值为 0.07,大于 0.05 的显著性水平,因此我们可以得出结论,“紧急事件”的频率分布相似,置信度为 95%。

现在,该是沙漠的时候了——也就是说,让我们来看看那些在目标上有显著不同分布的单词,这是我们想要解决的问题。

下面的代码将对数据集中的所有单词应用 Mann Whitney U 检验,并将记录那些具有不同分布的单词。同样,将策划这样的 50 个字。

words_significance = []for word in cvectorizer.get_feature_names():# get the pvalue
    _, pval = mannwhitneyu(
        train_df_w_ft[train_df_w_ft['target'] == 0][word],
        train_df_w_ft[train_df_w_ft['target'] == 1][word]
    )# check for significance
    if pval < 0.05:
        words_significance.append((word, pval))print("Total Number of words: ", len(cvectorizer.get_feature_names()))
print("Number of words having different distributions with confidence of 95%: ", len(words_significance))# plot the top words by pvalue
top_x = 50# seperate the word and pvalues
words_list = [x[0] for x in words_significance][: top_x]
significance = [0.05 - x[1] for x in words_significance][: top_x]# get the total frequencies of significantly different words across labels
freq_label0 = [train_df_w_ft[train_df_w_ft['target'] == 0][x[0]].sum() for x in words_significance]
freq_label1 = [train_df_w_ft[train_df_w_ft['target'] == 1][x[0]].sum() for x in words_significance]# plot the bar graph
plot_bar_graph([words_list, words_list], [freq_label0, freq_label1], ['target0_freq', 'target1_freq'], "Words", "Frequency", "Frequency of Words across Targets")

从上面的图表中我们可以看到,有些词同时出现在两个目标值中,但是频率的差异是显著的。

我们也只剩下 633 个单词中的 451 个,这是原始特征的 71%,因此这可以用作特征选择的技术之一。

我还绘制了 0.05 的差值和上述单词的 p 值。因此,具有更接近 0 的 y 轴值的单词将指示它们的 p 值更接近显著性水平,因此相对来说不如 y 轴值更接近 0.05 的单词重要,因为这指示它们的 p 值接近 0。

像“ago”、“big”、“blue”这样的词与其他词相比意义较低。

这些都是为了现在的分析。我将很快写另一篇文章,在这篇文章中,我将建立两个模型,一个具有所有的特征,另一个仅具有重要的单词,并将比较这两个模型的准确性。

更新:请点击分析第二部分的链接。

上述分析的代码可在 Kaggle 上找到,并可通过https://www . ka ggle . com/pikkupr/a-new-way-to-bow-analysis-and-feature-engg访问

希望你觉得我的上述工作有价值,请分享你对这种方法的看法,如果有任何改进的建议,请提出意见,我很想听听你的想法:)

一种新的 BOW 分析方法&特征工程(二)

原文:https://towardsdatascience.com/a-new-way-to-bow-analysis-feature-engineering-part2-451d586566c6?source=collection_archive---------50-----------------------

使用统计技术为您的模型选择正确的特征。

Unsplash 上的 Katarzyna Pe 拍摄

这是由两部分组成的系列文章的第二部分。你应该先读完 第一部分

我们正在讨论一种方法,在不建立机器学习模型的情况下,跨类别比较单词包,并进行特征工程。

到目前为止,我们已经了解了:

  1. 将跨类别的词频视为单独的分布
  2. 应用 Mann-Whitney U 检验——对每个词的分布进行非参数检验,以检验它们的显著性
  3. 分析结果,即比较重要单词的频率和 p 值

看了结果之后,我们确实对这种方法有了一些信心,但是它还不完整。我的意思是使用这种技术来减少我们必须衡量模型性能影响的特征,无论它们是否是训练数据集的一部分。这是我们在这一部分将要研究的内容。

测试 1-用所有特征训练模型

  • 首先,我将使用从 CountVectorizer 获得的所有特征建立一个模型,并检查单词的系数,这些系数在它们的频率分布中没有显著差异。
  • 这样做的目的是检查我们是否得到非常低的系数值(接近 0 ),并且这将证明我们的假设,即这些特征/单词是否确实可以从模型中排除。
  • 此外,我将使用套索,因为它给不重要的功能 0 权重
# split the data into test and trainX = train_df_w_ft.iloc[:, 1:]
Y = train_df_w_ft.iloc[:, 0]

print("Shape of X: ", X.shape)
print("Shape of Y: ", Y.shape)

X_train, X_test, Y_train, Y_test = train_test_split(X, Y, stratify=Y, test_size=0.3, random_state=42)

print("Size of X_train - **{}** and Y_train - **{}**".format(X_train.shape[0], Y_train.shape[0]))
print("Size of X_test - **{}** and Y_test - **{}**".format(X_test.shape[0], Y_test.shape[0]))

# training a Logistic Regression model with L1-penalty (Lasso)log_reg1 = LogisticRegression(penalty='l1', random_state=42)\
            .fit(X_train, Y_train)

print("Accuracy on Train dataset: ", accuracy_score(Y_train, log_reg1.predict(X_train)))
print("Accuracy on Test dataset: ", accuracy_score(Y_test, log_reg1.predict(X_test)))

训练和测试数据集的准确性

print("Test Data Classification Report:**\n\n**", classification_report(Y_test, log_reg1.predict(X_test)))

跨目标的精确度、召回率和 F1 分数

现在,我们将比较重要和不重要单词的系数。

LR 的系数在范围(-INF,+INF)内,其中-INF 系数表示这种特征与目标/因变量成反比关系。远离 0 的系数表示特征越重要,0 表示根本不重要。因此,我们将取系数的绝对值,然后将它们归一化,使它们具有可比性。

def normalize_coefs(coefs):
    *# normalizing the coefficients*

    abs_coef = [abs(x) for x **in** coefs]

    _max = max(abs_coef)
    _min = min(abs_coef)

    return [(x - _min)/(_max - _min) for x **in** abs_coef]

feature_coef = dict([(ft, coef) for ft, coef **in** zip(X_train.columns, normalize_coefs(log_reg1.coef_[0]))]) *## get the list of words which were not significant and their coefficients from the mode*

top_x = 50

*# get the list of significant words*
sig_words= [x[0] for x **in** words_significance]
sig_words_coef = [feature_coef[ft] for ft **in** X_train.columns if ft **in** sig_words]

*# get the list of insignificant words and their coefficients*
insig_words = [ft for ft **in** X_train.columns if ft **not** **in** sig_words]
insig_words_coef = [feature_coef[ft] for ft **in** X_train.columns if ft **not** **in** sig_words]

*# plot the words and their coefficients*
plot_bar_graph([sig_words[: top_x], insig_words[: top_x]], [sig_words_coef[: top_x], insig_words_coef[: top_x]], 
               ['Significant', 'Insignificant'], "Insignificant Words", "Model Coefficients", "")

输入要素的系数图

上面是一些重要和不重要特征的图,可以观察到,与不重要的特征相比,更重要的特征(蓝色)的值更接近 1。同样,这些只是一些特征,可能有点偏差,因此,下面是重要和不重要特征的系数直方图,以获得更多的清晰度。

# to plot the histograms
def plot_histograms(xs, names, xlabel, ylabel, title, _min=0.0, _max=1.0, step=0.05):# create figure object
    fig = go.Figure()# create bar chart for each of the series provided 
    for x, name in zip(xs, names):fig.add_trace(go.Histogram(
            x=x, 
            histnorm='percent', 
            name=name, 
            xbins=dict(start=_min, end=_max, size=step), 
            opacity=0.75)
        )# Here we modify the tickangle of the xaxis, resulting in rotated labels.
    fig.update_layout(
        barmode='group',
        autosize=False,
        width=1300,
        height=500,
        margin=dict(l=5, r=5, b=5, t=50, pad=5),
        yaxis_title=ylabel,
        xaxis_title=xlabel,
        title=title,
        bargap=0.2,
        bargroupgap=0.1
    )
    fig.show()plot_histograms([sig_words_coef, insig_words_coef], ['Significant', 'Insignificant'], "Coefficients", "Percentage of occurances", "")

重要和不重要特征的系数直方图

在上图中,左侧不重要特征的密度较高,表示不重要集合中有更多系数非常低的特征,其中低系数值表示预测/分类目标值的重要性较低。

因此,这表明,从模型本身来看,这些特征的系数确实很低。现在,剩下的就是检查对模型性能的影响,我们将在下面看到。

测试 2-仅使用重要特征训练模型,并比较精确度

# split the data into train and testX = train_df_w_ft.loc[:, sig_words]
Y = train_df_w_ft.iloc[:, 0]

print("Shape of X: ", X.shape)
print("Shape of Y: ", Y.shape)

X_train, X_test, Y_train, Y_test = train_test_split(X, Y, stratify=Y, test_size=0.3, random_state=42)print("Size of X_train - {} and Y_train - {}".format(X_train.shape, Y_train.shape[0]))print("Size of X_test - {} and Y_test - {}".format(X_test.shape, Y_test.shape[0]))

# train the Logistic Regression only on the Significant featureslog_reg_sig = LogisticRegression(penalty='l1', random_state=42)\
            .fit(X_train, Y_train)print("Accuracy on Train dataset: ", accuracy_score(Y_train, log_reg_sig.predict(X_train)))print("Accuracy on Test dataset: ", accuracy_score(Y_test, log_reg_sig.predict(X_test)))

之前我们的训练精度是 0.824,测试精度是 0.778。因此,训练数据集的准确性降低了大约 1%。但是,在测试数据的准确性方面有大约 1%的改进。还有,我们来看看分类报告。

print("Test Data Classification Report:\n\n", classification_report(Y_test, log_reg_sig.predict(X_test)))

之前,我们对目标 0 的 f1 评分为 0.81,对目标 1 的 f1 评分为 0.73。在这里,我们可以清楚地看到两个目标班级的 f1 分数都提高了 0.01。

因此,我们对这种方法的最终结论是:

  1. 我们观察到精确度有微小的提高和下降,但是,当我们比较两个目标的 f1 分数(“0”和“1”)时,它们有 0.01 的微小提高。
  2. 我们可以得出结论,在使用问题中的技术移除特征之后,对模型的性能没有显著影响,因此,它可以用作特征选择的技术之一。在我们有成千上万个特性的情况下,它肯定可以减少训练时间,而不会对性能产生太大影响。
  3. 我相信这也适用于连续变量,我一定会在这样的数据上进行测试,并与大家分享结果。

分析的工作代码保存在 Kaggle 上,可以使用链接https://www . ka ggle . com/pikk UPR/a-new-way-to-bow-analysis-and-feature-engg进行参考

希望你发现这个分析是有帮助的,如果你最终在你的分析中实现了这个,请分享你的故事。

我很想听听你的想法和建议,所以,请留下你的评论。

共享电子表格数据的新方法

原文:https://towardsdatascience.com/a-new-way-to-share-spreadsheet-data-eab276c24310?source=collection_archive---------47-----------------------

来回发送电子表格已经成为过去

声明:这涉及到我做的一个工具, API 电子表格 。有人告诉我,这是一种在团队中共享电子表格数据的简单明了的方法:)

您目前如何与其他数据人员共享您的电子表格数据?让我猜猜,你下载了你的 Google Sheet 或者 Dropbox 文件。或者等一下,你邮件里的文件是 3 天前发的吗?糟糕,是在你的工作电脑上,不是吗?好吧,你找到文件了。

现在你发邮件给约翰,让他做些分析。他运行他的分析。他会把它寄回给你。你重新运行你的旧模型…..又是什么鬼?!这些数字不再有意义,哦,我的上帝,你的老板会生气的,你花了这么多时间做这个。啊啊啊。

照片由安德鲁·尼尔Unsplash 上拍摄

好吧,结果是约翰添加了一些新数据,打乱了你的计算。一旦你考虑到这一点,一切都会好的。唷。危机解除。

但是危机本来就不应该发生

输入 API 电子表格

如果您可以对电子表格数据使用相同的真实来源会怎么样?即使数据改变了,你的代码也不会改变。你还可以阅读最新的电子表格数据。

即使电子表格在 Dropbox、Google Sheet 或你的本地电脑上。

我的工具, API 电子表格,让你做到这一点。

怎么会?

它利用 API 的力量创建一个指向你的电子表格数据的 URL,无论是在 Google Sheets、Dropbox 还是本地。那么无论发生什么,该 URL 都保持最新。

所以你、John 和 Koya 都可以在你的 Python 代码中拥有相同的 URL。当数据发生变化时,您什么都不用做:)

如果你不知道什么是 API,可以随意查看我公司描述API的文章。

好吧,听起来很有趣。但是它实际上是如何工作的呢?

让我们来看一个场景。

你是数据分析团队的团队领导。John 和 Koya 是你们的直接下属,你们三个用 Python 做实验性建模,找出顾客可能离开的原因。

您的销售团队每周都会向您发送一份 Customers.xlsx 文件。你的团队在 Google Sheets 上维护一个地区文件。这两者对你的建模都是必不可少的。

因此,你可以使用 API 电子表格为你的每个文件获取一个 URL,而不是每次数据改变时都重新下载并通过电子邮件发送给每个人。

你挑选一个人负责创建网址。只有一个负责数据治理的领导者非常重要。

这个人在 API 电子表格上创建一个帐户,然后上传 Customers.xlsx 文件,并连接到 Google Sheets 上的 Regions 文件。

你点击谷歌表单,上传或删除文件,连接到你的两个文件

文件上传并连接后,您将获得一个 API URL。以及如何读取数据的 Python 代码片段。

您可以尝试数据格式,看看您希望如何读取数据。您可以在示例响应中看到每种数据格式的外观。

现在,你们三个都可以使用相同的 Python 代码来读取数据了!

等等,那么数据将如何自动更新呢?

对于 Google Sheets,当你添加、删除或更新任何行时,数据总是会自动更新。

对于 Excel 文件,在这种情况下, Customers.xlsx,数据管理员需要在 API 电子表格的仪表板中用新版本替换当前版本。

这非常简单,它维护您的 API URL。这意味着你的 Python 代码不需要修改。

  1. 转到文件选项卡

2.转到您的 Customers.xlsx 文件,点击更多选项,点击替换文件并替换为您当前的版本

这将保留 URL,但用新文件更新数据!

就是这样!现在您的 Customers.xlsx 文件是最新的,您的 URL 将为您提供最新的数据。

就是这样!

我希望这对你的帮助和对其他用户的帮助一样多。如果你有任何问题,请随时发邮件到 info@apispreadsheets.com 给我们!

《纽约客》Airbnb 定价指南

原文:https://towardsdatascience.com/a-new-yorkers-guide-to-airbnb-pricing-59ef9b097478?source=collection_archive---------40-----------------------

机器学习流水线的迭代方法

照片由 @mikenusbaum

你想尝一口大苹果吗?你想在一个不睡觉的城市醒来吗?你不在乎是在唐人街还是在河边。你不是第一个。这座城市每年有 1000 万居民和 6000 万游客,相当一部分人穿过了 JFK 或 LGA 的大门。

对于这 6000 万的年度访客来说,许多人可能会住在 Airbnb 的 50k 租房中。这提出了一个有趣的问题,即使用纽约可用的数据集来准确地为 Airbnb 全年的租金定价。我们将用迭代的方法来解决这个问题,我们首先建立一个模型,然后逐步改进它。

最终的结果是一个实时定价租金的 web 应用程序: Pad Pricer

第一步:搜集 Airbnb 的月度房源

正如你可能已经猜到的,Airbnb 租赁定价的第一步是从 Airbnb 获得租赁清单。幸运的是,Airbnb 非常乐意提供这些数据(每月一次)。然而,为了达到我们能够预测租赁价格的程度,我们需要采取三步走的方法:

  1. 获取所有纽约市租赁的链接(过去 50 个月)
  2. 将 50 个链接下载到 50 个熊猫数据框中
  3. 将 50 个数据帧编译成一个单独的清洁过的数据帧

第 1.1 步:获取 Airbnb 纽约租房链接

为了从 Airbnb 的数据存储中获得所有纽约的月租金,我们将使用BeautifulSoup从网站的索引页面中抓取链接,然后将 URL 以及月份和年份存储在pandas数据框架中。对于这个过程,月和年是基于与每个 url 相关联的日期时间字符串来计算的。get_airbnb_links代码可以在 github 上找到,结果如下:

Airbnb 链接数据框的前几行

步骤 1.2:并行下载月租链接

下一步是使用 panda 的read_csv函数将上述列表中的所有url读入它们自己的数据帧。预计到下一步,我们将删除许多不需要的,因为它们只是占用空间。因为下载csv文件的过程相对较慢,我们可以使用下面的代码片段异步运行它们:

from concurrent.futures import ThreadPoolExecutor
from tqdm.auto import tqdmdef async_run(f, my_iter):
    with ThreadPoolExecutor(max_workers=6) as executor:
      results = list(tqdm(
          executor.map(f, my_iter), total=len(my_iter)
      )) return results

此步骤的代码可从以下位置获得:

[## load_airbnb_links.py

Airbnb 月租相关的 URL 下载表(并行)

github.com](https://github.com/djsegal/metis/blob/master/X_airbnb_revisited/airbnb_pricer/airbnb/load_airbnb_links.py)

步骤 1.3:编译干净的定价数据集

纽约和布鲁克林的 Airbnbs 价格地图,用橙色显示火车线路。请注意剧院区、村庄和威廉斯堡周围的群集。

构建初始 Airbnb 定价数据集的最后一步是汇编最后一步中生成的 48 个数据框架。通过这些数据帧的简单连接,我们还必须清理结果表。这包括两个方面:将许多列更新为它们最近的值(例如对于bedrating)以及对数据集进行一些过滤。

为了清楚起见,我们的数据集最初包含 200 万个唯一条目(成对的:idmonthyear)。根据以下标准进行过滤后,我们只剩下 30 万英镑,降幅为 85%。

租赁选择标准

  • 房产类型:公寓
  • 房间类型:整个单元
  • 价格:每晚 25 美元到 1250 美元之间
  • 月:至少上市三个月
  • 评级:超过 60%来自评论
  • 审查频率:至少每 8 个月一次
  • 自治市:曼哈顿还是布鲁克林
  • 容纳:1 至 8 人
  • 亚达亚达

虽然这些限制可能看起来很严格,但这样做是为了只关注该领域的做市商,淘汰一些更业余的主持人。实际代码可以在 github 上查看。

第二步:回归定价 Airbnb 租金

我们有了数据,现在让我们建立一个模型。我们的目标是首先创建最简单的原子模型。然后增加它的复杂性,直到我们有一个集成回归拟合,其中包含来自 Airbnb(租赁)、纽约市卫生局(食品)、Yelp(咖啡馆/酒吧)和 MTA(火车)的数据。但首先,让我们从头开始…

步骤 2.1:构建原子数据集

奥卡姆剃刀说“最简单的解决方案几乎总是最好的。”尽管在这里不会出现这种情况,但这通常是最好的起点。从上一步开始,我们在 Airbnb 纽约价格数据集中有大约 30 万个条目(涵盖过去 4 年)。

我们纽约 Airbnb 租赁数据集的前 7 个条目

从这个表中可以看出,id与多行相关联。除了pricemonthyear,其他栏目都包含大量冗余信息。因此,我们将把这个数据集一分为三,每个数据集都有一个id列(用于连接)以及以下各列:

  1. 价格数据集(pricemonthyear)
  2. 租赁数据集(accommodatesbathroomsbedroomsbeds)
  3. 位置数据集(geometryzipcodeis_brooklyndensity)

从最接近原始表的表开始,Price数据集就是第一步中删除了所有常量字段的表(即现在只有价格、月份和年份)。然后Rental数据就是假定的与每个纽约公寓相关的常量字段:住宿、浴室、卧室和床。为了清楚起见,Rental数据的长度比Price数据的长度小 20x

Location数据集需要更多的解释。首先,zipcode实际上是在初始数据集中给出的。is_brooklyn旗指的是我们如何关注曼哈顿和布鲁克林。接下来,geometry是存储租赁的纬度和经度的字段;这实际上意味着我们将使用一个 GeoPandas 数据框架来执行 GIS 探索。最后,density是我们从 ZipAtlas [ 12 ]的表上连接得到的字段。

尽管我们在这里似乎变得更复杂了,但这是为了构建最简单的模型做准备:一个基于Price数据集的模型。

步骤 2.2:训练最简单的模型

我们的目标是得到一个基于月份和年份来预测租金的模型。正如您可能已经猜到的那样,这将表现得非常糟糕。然而,它将提供一个引导点来开始(过度)复杂化我们的模型。

from sklearn.linear_model import LinearRegressioncur_target = "price"cur_X = price_data.drop(columns=["id", cur_target])
cur_y = price_data[cur_target]cur_model = LinearRegression()
cur_model.fit(cur_X, cur_y)R_2 = cur_model.score(cur_X, cur_y)

你由此得到的R^2就是 0.14% !这是一个真正可怕的模型。它只能解释不到 0 . 25%的租赁夜价格差异。这是有道理的,因为它基本上是说价格必须只与两者线性相关:月和年——这是完全不正确的。

更好的——尽管仍然很糟糕——模式是为每个月和每年添加一面旗帜。这反过来解开了月和年之间的耦合。更简单地说,不是一个可以是 1 到 12 之间任何数字的month变量,而是有 12 个变量是TrueFalse(例如is_janis_feb等)。).实际上,我们从一个有两个特性monthyear的表发展到 16 个布尔表。这 16 个月来自我们的数据集涵盖的 12 个月和 4 年。

通过代码,我们使用 Scikit-learn 的OneHotEncoder完成了从 2 个变量到 16 个变量的扩展。为了形式化我们的构建过程,我们将使用一个Pipeline将这个编码器与之前的LinearRegression模型结合起来。虽然只是将R^2提高到 0.15%,但我们现在已经真正开始取得一些进展了。

from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import Pipelinecur_one_hot = OneHotEncoder(categories="auto")cur_pipeline = Pipeline([
    ("one_hot", cur_one_hot),
    ("lin_reg", LinearRegression())
])cur_pipeline.fit(cur_X, cur_y)
R_2 = cur_pipeline.score(cur_X, cur_y)

编辑:除了昙花一现的几个月之外,另一种方法是将month视为一种周期性特征——正如这篇博文所展示的那样。

步骤 2.3:加入租赁数据

既然我们已经将数据集原子化并构建了一个简单的模型,那么是时候开始重新添加来自RentalLocation数据集的数据以及其他基于地理的指标了。特别是对于这一步(和子步骤),我们将只添加租赁数据,即住宿、卧室、浴室和床。这将需要对管道进行一些调整,但最终我们会有一个真正开始竞争的模型。

在看下面这个庞然大物之前,清楚地说明我们现在在做什么是很重要的。我们首先将我们的Price数据集与Rental数据集合并。接下来,我们一次加热monthyear,同时保持其他功能完全相同(参见:remainder="passthrough")。然后,只需对管道做一点小小的更改,我们就可以恢复运行了!

from sklearn.compose import ColumnTransformercur_X = price_data.merge(rental_data, on="id")
cur_X.drop(columns=["id", cur_target], inplace=True)cur_transformer = ColumnTransformer([
    ("one_hot", cur_one_hot, ["month", "year"])
], remainder="passthrough")cur_pipeline = Pipeline([
    ("transformer", cur_transformer),
    ("lin_reg", LinearRegression())
])cur_pipeline.fit(cur_X, cur_y)
R_2 = cur_pipeline.score(cur_X, cur_y)

如果你看一下R^2值,我们现在是 25%!这比我们最初的模型提高了两个数量级以上。然而,在我们从这场胜利中获得太多安慰之前,我们必须更加认真地对待数据科学。

我们的模型在纽约 Airbnb 数据集上表现如何的地图。请注意,蓝绿色圆圈代表 125 个最佳预测租金,而红色圆圈代表 125 个最差租金。很明显,在这里,红色标记大量聚集在曼哈顿下城!因此,一些地理数据可能会改进模型(敬请关注……)

步骤 3:认真对待数据科学

虽然我们可能会对一个获得 25%的R^2的模型感到自豪,但它很难说明它在野外的表现有多好。事实上,我们可以通过简单地记忆数据(可能使用决策树)来拟合一个 90%以上的模型。然而,在新数据上,它会做得非常糟糕。因此,我们现在将进一步完善我们的渠道,更加认真地对待数据科学。

步骤 3.1:创建测试集

学会信任我们的新模型的第一步是将数据分成两组:traintest。这允许我们使用一组在上训练模型,然后使用另一组进行测试。对于像我们这样的中型数据集,训练和测试之间的 80/20 分割通常是惯例。(一些阵营甚至会与一个名为validation的新组织争夺 60/20/20 的分成,这使得test数据只能在最后用作部署的保障。)

从初始数据集创建训练和测试数据集的最简单方法是使用 Scikit-learn 的train_test_split函数和test_size = 0.2。然而,这将导致两个问题:

  1. 每个长期租赁都很有可能在两个数据集中有一个月的记录(这是一种数据泄漏的形式)
  2. 目标价值(即每晚的租金价格)可能会偶然出现偏差

为了解决第一个问题,我们在id计数上使用了宁滨,并选择了 10%的唯一id(基于它们的 bin 计数)。接下来,为了获得测试集的另外 10%,我们实际上使用了来自 Scikit-learn 的train_test_split——我们只是输入了stratify参数,以允许我们绑定price!

基于 id 和价格的定制培训/测试分割

使用上面和下面的代码,我们现在看到模型仍然徘徊在 25%的R^2附近。实际上,R^2并没有改变!这实际上意味着我们可能低估了模型。如果误差与上一步相比确实发生了巨大变化——即如果test分数明显比train分数差——我们将处于过度拟合模型的情况。

X_train, X_test, y_train, y_test = custom_train_test_split(
    price_data.merge(rental_data, on="id")
)...cur_pipeline.fit(X_train, y_train)
R_2 = cur_pipeline.score(X_test, y_test)# R_2 still around 25% !

//这只能说明我们还有改进的空间

步骤 3.2:缩放各种功能

现在,我们有了一个经过认证的欠适应模型,它既有训练数据集,也有测试数据集。为了提高拟合度,我们将从缩放各种特征开始。从目标开始,我们将做一个简单的日志转换。这是因为租赁价格根据对数正态分布而变化,这意味着衡量误差的更好方法是相对大小。这可以使用以下更新来添加:

import numpy as npfrom sklearn.compose import TransformedTargetRegressorcur_regressor = TransformedTargetRegressor(
    regressor=LinearRegression(),
    func=np.log, inverse_func=np.exp
)cur_pipeline = Pipeline([
    ("transformer", cur_transformer),
    ("regressor", cur_regressor)
])

执行这个操作——并将y改为引用它——实际上将R^2从 25%减少到 22%。这就是强调R^2对于建模者来说是一个有用的度量标准的重要之处,但是对于行业来说真正有价值的度量标准可能是非常不同的(例如MAERMSE)。为方便起见,在拟合价格时,我们将关注模型的平均绝对误差(MAE)。该值以美元为单位,显示每个预测的平均值。(注意,即使对于 log MAE 的情况,我们也不会使用 log-dollars。)

def mae(vec_1, vec_2):
    assert len(vec_1) == len(vec_2)
    vec_3 = np.abs( vec_1 - vec_2 )

    return np.sum(vec_3) / len(vec_3)

lin_predict = lin_pipeline.predict(X_test)
log_predict = log_pipeline.predict(X_test)

# mae(y_test, lin_predict) ~ $62
# mae(y_test, log_predict) ~ $60

因此,即使目标上的R_2从对数转换中下降,它的MAE也一样。这是一个度量权衡很重要的例子!接下来,我们将使用 Box-Cox 幂变换来变换这些特征。这样做的目的是将要素修改为更正态分布(线性回归的核心假设之一)。不过,俗话说:天下没有免费的午餐。在这种情况下,你为改进的模型所付出的代价通常是可解释性的降低。

在我们刚才在目标上添加 log 转换之前,我们的模型实际上非常简单。它对其 20 个特征变量(和偏差补偿)具有线性关系。这实际上意味着每个变量都与一个简单的per_unit值相关联——这里用美元来衡量。例如,一套公寓每多容纳一个人,每晚租金就会增加 10 美元。

一旦我们转移到对数转换,这些效果就从线性$/unit值转换成标量,从而扩大或缩小目标(想想从总和到乘积)。当我们对变量进行幂变换时,解释会变得更加困难。最后,当我们添加模型集合时,解释将变得更加困难。关键是在每一步都要问一问这种交换是否值得。

与这种可解释性的想法相联系的是变量实际上意味着什么你真正能控制它们的是什么。例如,月和年是由您在托管时设置的变量。然而,一年一热的特点使你无法预测未来的年份(而month则不能)。因此,去掉year功能,但保留month功能可能是有意义的

同样,如何将信息传递给最终用户也是一个问题。在上表中:每间浴室的租金增加了 110 美元/晚,而每间卧室只给你 30 美元。这并不意味着你应该把卧室变成浴室。可能发生的是bathrooms正在成为平方英尺的代表。而bedrooms可能正纠结于住宿和床位的数量。

在进入下一步之前,必须展示 Scikit-learn 的电源变压器(例如 Box-Cox 变压器)如何适应管道:

from sklearn.preprocessing import PowerTransformercur_pipeline = Pipeline([
    ("transformer", cur_transformer),
    ("normalizer", PowerTransformer()),
    ("regressor", cur_regressor)
])

一旦你做了这个修改,R^2实际上会下降一点!因此,如果它继续降低性能,在某个时候移除它可能是有意义的(例如,它是GridSearchCV的潜在超参数)。

步骤 3.3:添加特征工程

在这一点上,我们有一个好的模型,它有一些功能缩放。我们现在将通过改变为多项式回归(相对于简单的线性回归)来推进特征工程过程。这实际上意味着,我们现在将拥有像accommodates_per_bathrooms这样的术语,或许能够捕捉到更微妙的细微差别。为了防止参数爆炸的问题——即维数灾难——我们需要引入正则化。

到目前为止,我们有一个相对简单的管道(考虑到所有的事情)。几个月来一直有一些一次性的事情发生。然后做一些幂变换,使特征更高斯。然后我们用一个线性回归来总结它——用对数标度的目标来完成。

现在我们要让它稍微复杂一点…

为了让每个人都在同一个页面上,此时我们有一个数据框架,其中每一行都是一个租赁列表(给定月份),具有以下特征:

  1. 身份证明
  2. 价格
  3. 容纳
  4. 浴室
  5. 卧室

month特征被选择用一个热向量来处理(例如is_janis_feb、…、is_dec)。price是目标,用一个日志转换来处理。现在我们要对最后四个特性做一些事情:accommodatesbathroomsbedroomsbeds

这四个变量将为我们设计子管道提供一个出口。我的意思是,我们将利用ColumnTransformer为这四列(例如,住宿和床位)传输某些命令。如下所示:

from sklearn.preprocessing import PolynomialFeatures
from sklearn.feature_selection import VarianceThresholdcur_poly_feats = PolynomialFeatures(
    degree=2, include_bias=False, interaction_only=True
)cur_sub_pipeline = Pipeline([
    ("reciprocal", ReciprocalFeatures()),
    ("polynomial", cur_poly_feats),
    ("cancel", VarianceThreshold()),
    ("clean", CleanFeatures()),
    ("box_cox", PowerTransformer(method="box-cox"))
])

那么这个(子)管道是做什么的呢?第一部分是为四个值,即per_accommodatesper_bathrooms设置互逆特征的步骤。这个自定义代码可以在: github 上获得。接下来,我们用最少的新特性做一个简单的 2 次多项式展开。此外,在我们对数据进行 Box-Cox 幂变换之前,我们移除:

  • 无信息特征:cur_data["bed _per_bed"] ~ 1.0
  • 互逆特征:beds_per_accommodates & accommodates_per_beds

为了将这个新的 sub_pipeline 与现有的 sub _ pipeline 连接起来,我们现在需要修改主管道中使用的ColumnTransformer:

one_hot_cols = ["month"]
poly_cols = rental_data.columns.drop("id").tolist()cur_one_hot = OneHotEncoder(categories="auto")cur_col_transformers = [
    ("one_hot", cur_one_hot, one_hot_cols),
    ("poly_feats", cur_sub_pipeline, poly_cols)
]cur_transformer = ColumnTransformer(cur_col_transformers)

好吧,那么现在我们肯定有太多的特性让LinearRegression不合适了。维数灾难表明,我们现在可能正面临严重的过度拟合情况。即使情况并非如此,也就是说,我们可能仍然有一个糟糕的模型,每个训练批次的系数可能变化如此之大,以至于数据集合之间几乎没有一致性。这是坏事!

因此,我们将在模型中添加特征选择,以降低特征创建的影响。实际上,这意味着将线性回归替换为两步过程:

  1. 特征选择
  2. 正则回归

该功能选择将通过包裹在 Scikit-learn 的SelectFromModel中的LassoCV来完成。在这里,Lasso(参见: L1 范数)是一种正则化的回归技术,它剔除了不会改进模型的特征(CV 代表交叉验证)。另一方面,SelectFromModel 是一个运行LassoCV的函数,目标是挤出不重要的特性。在实践中,这可以移除超过 60%的特征(从 100 多个初始特征的列表中)。

下一步是使用ElasticNetCV而不是LassoCV的实际求解器。这样做是因为它添加了岭回归(L2 范数)的一些元素,这在经验上提高了R^2值。在继续之前,有必要指出另外两个问题。首先,我们现在使用一个定制的LogTransformedTargetRegressor来处理 SelectFromModel。

其次,这些正则化回归技术(即套索、山脊和弹性网)要求对要素进行缩放。例如,如果不按比例缩放,我们的模型将尝试比计量的模型更严格地缩放公里量 1000 倍(如果我们添加了地理特征)。因此,我们添加了一个StandardScalar,它将所有特征转换为平均值为 0,标准偏差为 1。这条新管道如下:

from sklearn.linear_model import LassoCV, ElasticNetCV
from sklearn.feature_selection import SelectFromModel
from sklearn.preprocessing import StandardScalercur_selector = SelectFromModel(
    LogTransformedTargetRegressor(
        LassoCV(cv=4, n_jobs=-1, max_iter=5e4)
    ), threshold=1e-6
)cur_regressor = LogTransformedTargetRegressor(
    ElasticNetCV(cv=4, n_jobs=-1, max_iter=5e4)
)cur_pipeline = Pipeline([
    ("transformer", cur_transformer),
    ("scalar", StandardScaler()),
    ("selector", cur_selector),
    ("regressor", cur_regressor)
])cur_pipeline.fit(X_train, y_train)

现在,如果我们检查traintest组的R_2,两者都在 23%左右。我们实际上稍微改进了模型,使两个分数更加接近。后者证明我们现在有一个相对通用的模型(与过度拟合模型相反)。现在是时候将R_2提高不止一个百分点了!

步骤 4:使用纽约市地理信息

我们对 Airbnb 租赁进行高精度定价的下一步是添加一些与纽约及其运作方式相关的 GIS(地理信息系统)数据。这可以包括更明显的细节,如:人口密度和租赁是否在布鲁克林。但也可以涉及更多内容,例如查找从租赁点到最近地铁站的距离或附近有多少寿司店。

步骤 4.1:将位置数据带回到图片中

在步骤 2.1 中,我们将location特征提取到它们自己的数据集中。其中包括:geometryzipcodeis_brooklyndensity。现在,我们将关注以下参数:人口密度和检查是否在布鲁克林租房。这意味着我们目前将忽略几何图形和邮政编码。

忽略邮政编码的原因是因为邮政编码可能需要一次性处理,而且邮政编码太多了,所以不相关。然而,它们被用来获得density值。另一方面,geometry字段在这个阶段没有用,因为线性拟合纬度和经度通常不是一个好主意。但是,我们稍后将使用它来检查到各个位置的距离,例如公园、地铁入口和餐馆。

而且就像 那个 ,我们把我们的R^2增加到了 35% !这还不算太糟:10%的绝对增长和 40%的相对增长。查看我们当前的参数重要性,可以为我们的模型提供一些线索:

那么这告诉我们什么呢?airbnb 租金价格的第一指标是它能容纳多少人,以及他们之间有多少浴室(和卧室)。Is-Brooklyn 接着补充了一个明显的效果,即曼哈顿是最昂贵的行政区,而density与我们想象的方向相反。我的意思是,我们最初期望密度跟踪人们想去的热门地区。

density与我们希望的方向相反,这表明我们的模型仍有改进的空间。我们现在将添加地铁和餐馆地理数据,以更好地了解不同租赁提供了多少娱乐。

最后要指出的一点是,我们的初始参数(每月一次)现在在列表的底部。它们基本上意味着寒冷的月份稍微便宜一些,而夏天的月份稍微贵一些。这可能支持使用季节性的一个热点媒介,而不是 12 个月一个。

步骤 4.2:寻找最昂贵的热点

在引入新的数据源之前,我认为我们可以从位置数据库中获得更多的信息。使用平均每晚房价,我相信我们可以找到与每晚住宿最高的景点相关的聚类。这类似于卡尔·安德森在重新划分美国大陆时面临的问题。

//完成类比:夜间价格现在是人口的替代品

纽约市地图,以彩色显示 Airbnb 每夜平均租金。在这里,红色和橙色标记突出了城市中最昂贵的景点。

好的,那么产生热点的方法——显示为橙色和红色——是使用 KMeans 聚类进行无监督学习。虽然这可能值得在管道中,我们说它从一开始就添加了字段(甚至在test_train_split之前)。

因此,该图的聚类是实际选择的聚类!这 10 颗红钻是这两个区的最高价格集中度。而橙色的星星是整个数据集的质量中心:城市中(平均值)最昂贵的地方。

布鲁克林和纽约聚类标记(is_bkn =是布鲁克林)。此外,还有一个面向两个区的质心(is_com)点。这些是我们的模型中使用的点。

将这些无监督聚类节点合并到模型中的方法是找到每个租赁点和红色标记之间的最小距离(以及每个租赁点到橙色中心星形标记的距离)。这将给我们带来两个新特性:dist_to_centerdist_to_hub。两者都需要被转换成更高斯的。虽然一个简单的log可能适用于 center,但我们将再次使用 Box-Cox,并考虑重新缩放(因为我们添加了更多的dist功能)。

好的,我们需要计算租赁列表和聚类列表之间的距离。这里,距离将是欧几里德距离,其中latitudelongitude用来自堆栈溢出的简单关系进行缩放:

ave_nyc_latitude = 40.731 * (2*pi/360)
meter_per_degree__longitude = cos(ave_nyc_latitude) * (40075/360) kmmeter_per_degree__latitude ≈ 70 miles
meter_per_degree__longitude ≈ 50 miles

在“获取到聚类的距离”函数中使用这些知识后,等待一分钟的运行时间,我们得到了与上面聚类图中橙色和红色标记相关的距离列表!获得新的R^2值之前的最后一步是将特征添加到主DataFrame中,并更新用于适应它的Pipeline:

cur_data = price_data.copy()
cur_data = cur_data.merge(geo_data, on="id")...geo_cols = ["hub_dist", "center_dist"]mentioned_cols = [ 
    "id", "price", *pass_cols, 
    *one_hot_cols, *drop_cols, 
    *poly_cols, *geo_cols
]...cur_col_transformers = [
    ("one_hot", cur_one_hot, one_hot_cols),
    ("poly_feats", cur_sub_pipeline, poly_cols),
    ("geo_feats", PowerTransformer(method="box-cox"), geo_cols),
    ("passthrough", [PassThroughTransformer](https://gist.github.com/djsegal/237d96c0eef26002c4aaf6c6ef957374)(), pass_cols)
]...R_2 ≈ 45%

就这样,我们接近了 50% R_2点!使用聚类信息将这一准确性指标从 35%提高到了 45%,而我们才刚刚开始。然而,在下一步添加地铁和餐馆信息之前,通过查看测试数据,指出我们的无监督聚类确实作弊是有用的。对于生产,可能会建议将此引入到管道中(以及添加 Queens 以增加租赁主体的大小)。

编辑:我们可以使用贝叶斯高斯混合,而不是使用 KMeans 对热点进行聚类。这将允许星系团呈长方形并以任意角度定向,而不是圆形且大小大致相等。

步骤 4.3:集成纽约开放数据源

我们现在正处于添加更多数据的最后阶段。我们的最后一个子步骤是通过收集一些纽约市公开的数据集来扩充 GIS 数据库。这些包括:MTA 所有地铁站的清单,以及曼哈顿和布鲁克林所有符合卫生部要求的 餐厅 的集合。这让我们在理解 Airbnb 每夜租金价格时,又多了两个考虑的尺度。

为了清楚起见,在前面的子集中,我们基本上循环了 15k(唯一的)租赁列表,以找到它们与 10 个菱形集群中心以及橙色星星(表示高成本中心)的距离。这在计算上意味着我们一次遍历两个列表:租金和聚类中心。在 Big-O 符号中,我们对最小距离的搜索花费了 O(N M)左右,其中 N 是租赁的数量,M 是另一个地理位置列表的大小

到目前为止,对于橙色和红色,M 分别为 1 和 10。对于火车和餐馆,这些将是 O(100)和 O(10k),所以在规模建立一个解决这个问题的框架是有意义的。这是因为简单的情况,如 M ≤ 10,仍然需要一分钟来运行。在讨论如何构建解决此问题所需的可扩展 k-d 树之前,再次强调 N 和 M 的以下数量级是有用的:

如图所示,我们有一组数据(M ),其数量级在 1 到 N(即 15k)之间

这其中的一个主要含义是:距离(1D)和面密度(2D)之间的重要性权衡。对于之前的两个集群示例,即 M=1 和 M=10,只有距离是真正相关的。当你越靠近餐厅的一端,O(N)~O(M),密度就变得越重要:半英里半径内有多少家餐厅?然后,这个半英里半径成为一个超级参数,**r_bubble**,它可以被调整以获得一个城市如何重视距离的更好的视角。

要做的另一个评论是,像地铁站一样,我们没有使用餐馆数据集中的所有信息。例如,我们可以使用地铁站的线路信息(即 L 列车、A/C/E 列车等。)以及烹饪类型(例如,河粉、咖啡和墨西哥玉米卷),以将其他尺度和文化数据引入混合。现在,让我们只对火车和餐馆进行简单的距离和计数…

正如人们可能会怀疑的那样,聚类步骤中 10 个最昂贵的 Airbnb 区域与重要的地铁站交叉口相吻合。整洁!

在不把这份文件弄得太乱的情况下,我们基本上是在搜集纽约市的公开数据,然后在我们认为合适的地方进行清理。这可能是为了:糟糕的卫生等级餐馆或只是为了删除与地铁站相关的不必要的列。

这两个刮刀的代码可以在 Github 上找到:一个用于餐馆,另一个用于地铁站。我们现在的目标是围绕地理空间数据集建立 k-d 树,最终加快我们的距离和计数测量。

简而言之,k-d 树是一种可以快速进行空间搜索的数据结构。为了简化这些树的制作,我们将使用下面的辅助函数:

from pysal.lib.cg import KDTree, RADIUS_EARTH_MILESdef custom_KDTree(cur_data):
    cur_geom = cur_data.geometry.map(
        lambda tmp_geom: (tmp_geom.x, tmp_geom.y)
    ) cur_tree = KDTree(
        cur_geom, distance_metric="Arc", 
        radius=RADIUS_EARTH_MILES
    ) return cur_tree

请注意,我们使用 PySAL 的 KDTrees 实现来方便地将我们的纬度/经度度量转换为英制英里。

我们表现如何?请击鼓… 48%。在做了一堆繁重的工作后,我们得到了几个微不足道的百分点——这可能是噪音造成的。为什么会这样?很可能是因为这个线性模型在系统中看到了太多的共线性。因此,它最重视两个极端:

  • 食物密度
  • 离市中心的距离(米~1)

然后,它强调了我们从 35%和 25% R^2模型中学到的事实。从前者中,我们了解到租金价格随着人口密度而下降,如果你在曼哈顿以外(即在布鲁克林)。后者强调了容纳功能的重要性:

  1. 容纳
  2. 住宿/浴室
  3. 住宿/卧室

步骤 5:最终确定模型管道

到目前为止,这是一次有趣的旅行。我们从一个糟糕到连 1%的 T1 都得不到的模型开始。然后我们转到了 25%的人口密度和 35%的人口密度,以及对行政区的检查。为了达到 50%,我们添加了一系列与租赁的纬度/经度相关的功能,但此后似乎没有任何进展。

现在我们将尝试另外三个选项:

  • 基于行政区分割数据
  • 尝试其他回归模型
  • 构建集成方法

一旦我们尝试了一切,我们将后退一步,简化模型,提取我们实际学到的东西。

步骤 5.1:根据行政区分割数据

在尝试一堆新模型并对它们进行集成之前,有趣的是看看我们数据集中唯一的真实布尔变量:is_brooklyn。该功能非常巧妙地将数据集一分为二,并且——如步骤 4.3 末尾的表格所示——极大地影响了 Airbnb 公寓的每夜租金。我们将尝试解决这个问题的两种方法是:

  1. 在我们的距离和密度上添加一个is_brooklyn筛子
  2. 将我们的回归变量一分为二:一个用于布鲁克林,一个用于曼哈顿

第一个例子是由一个定制的 BooleanProduct 处理的。这允许变量有一点额外的伸缩(就像如果food_density对布鲁克林人来说更重要)。在实践中,这意味着您最终会得到类似于:"food_density _is_brooklyn"的特性。第二种方法需要另一个定制的 BooleanForkRegressor,寻找最接近相等的数据划分布尔变量;这里是is_brooklyn字段。

请击鼓,基本上还是 50%。看起来,如果不找到一个新的数据源,我们就无法提升到下一个 10%的水平。幸运的是,我们还没有尝试 Scikit-learn 提供的大量其他回归模型。

步骤 5.2:尝试其他回归模型

我们收集了所有的数据,做了功能工程,但似乎无法超过 50% R^2的阈值。不要害怕!Scikit-learn 提供了一长串回归算法,当ElasticNetCV(我们一直在使用的那个)停止切割芥末时。我们要关注的是:随机森林和增强方法。例如,这不包括 SVM 和神经网络回归方案,因为前者对于拟合来说太慢,而后者需要太多的调整(为了本教程)。

在将这些回归量添加到管道之前,查看它们的形式评估指标是有用的。这些可以在下面的代码和表格中看到:

regressor_list = [
    ElasticNetCV(cv=4, n_jobs=-1, max_iter=5e4, n_alphas=256),
    BooleanForkRegressor(HuberRegressor(max_iter=250, tol=1e-4)),
    RandomForestRegressor(n_estimators=48, n_jobs=-1, max_depth=20),
    ExtraTreesRegressor(n_estimators=64, n_jobs=-1, max_depth=24),
    AdaBoostRegressor(n_estimators=128, learning_rate=0.6),
    XGBRegressor(n_estimators=256, n_jobs=-1)
]

我们 7 个回归模型的评估指标。除了 R2——我们可以解释的模型中方差的百分比——还有另外两个指标:MAE 和 LMAE。MAE 是衡量平均绝对误差的行业标准(单位:美元)。LMAE 是日志空间(目标上)中的 MAE,因此是一个百分比。

从这里你可以看到,到目前为止我们一直在研究的两个模型实际上是性能较差的。随机森林和它们更多的同类表现最好——到目前为止。然后在默认参数下,XGBoost似乎比我们的模型表现更好,而AdaBoost表现稍差。这现在需要一个集合方法的解释,它似乎表现得和最好的模型一样好。

为了清楚起见,集成方法是利用几个不同的模型并将它们的答案缝合在一起的方法。这些科学怪人将他们的结果组合在一起的方式决定了他们的多样性:简单的平均用于打包回归变量,一个元回归变量用于堆叠回归变量。在这种情况下,元回归元是根据其他回归元的结果而不是根据特征训练的另一个回归元!为了清楚起见,我们的系综方法——在上表中——是一个带有RidgeCV元回归变量的叠加回归变量。

退一步说,现在一个明显的问题可能是:为什么?为什么模型这么复杂?我们需要做所有这些步骤吗?我们实际学到了什么?作为一个怀疑论者,我认为这些都是好问题。这个模型可能被过度设计了。除了以美元为单位的误差测量,我们在可用性方面还有很多不足之处。在这一过程中,我们只有一两个真知灼见,比基于原始特征(如住宿和位置)的简单随机森林得出了更好的答案。

下一个子步骤将尝试做一些路线修正,简化我们的模型,并提供一些最终用户的可解释性。在此之前,强调我们所有工作中的一件好事似乎是有价值的。如下所示,我们现在有了每个使用的模型的特征重要性的集合!我们之前说的重要变量,主要还是相关的。然而,似乎一个新的特性变得对树方法很重要,即accommodates*bedrooms。这个特性可能是一个衡量标准:越大越好/越贵。

我们的 6 个(+1)模型的 12 个最强预测变量。请注意,在取绝对值后,每列总和为 100%。当方法使用系数(即线性回归)时,会出现负值。曼哈顿和布鲁克林的空行是因为它们是整个纽约市的准分裂版本。

步骤 5.3:处理经度和纬度

价格预测难题的最后一块是正确处理纬度和经度。到目前为止,它一直被视为一个隐式变量,一种测量到各种位置(如火车、餐馆和热点)的距离的方法。现在我们将解释为什么这样做,然后把添加它的练习留给读者。

我们最初从回归模型中剔除经度和纬度的原因是因为它们最初都是线性的。除非价格随着向北的距离严格增加,否则将这种行为描述为线性是没有意义的。实际上,这意味着纬度可能会改善像纽约这样的城市的预测——它是建立在美国网格系统上的。但可能无法捕捉到欧洲城市的任何细微差别,欧洲城市通常有一个辐射/极地系统,价格从市中心下降。

另一方面,树模型,如随机森林和 XGBoost,是非线性模型。他们可以毫不费力地消除金融城昂贵的泡沫。通常有 16 层(2⁴)的深度,一棵树可以识别像村庄、剧院区和威廉斯堡这样的地方。因此,我们可以简单地将纬度和经度添加到每个森林(即非线性)回归模型中。

然而,这对于线性模型来说似乎有点不公平,所以我们可以给它们每一个来自弱学习者的结果,该弱学习者只给出基于纬度和经度的价格预测。这些调整就是我的 4 城市价格预测工具所使用的:Pad Pricer它涵盖了纽约、旧金山、柏林和巴黎。********

结论

倒带时间。记录刮痕你可能想知道我们是怎么来的。是的,那是我们的模型。想想第一步有多简单,有点疯狂。时间/脚步去了哪里。我们现在在第 5.3 步。对于我们的工作,我们有一些东西要展示(例如,一个可以预测平均每晚租金在 30 美元以内的模型),但它很复杂,似乎表现得和一个非常简单的随机森林一样好。然而,我们不会为此而自责,而是会从我们所做的事情中吸取教训,简单,简单。**

极简主义是好的机器学习模型的标志。就像欠装配/过装配一样,您需要足够的基础设施来完成 90%的工作,但不足以让读者感到厌烦。现在有必要列出我们的模型的哪些方面带来了快乐/价值:

  • 容纳
  • 住宿/浴室
  • 容纳间卧室*
  • 食物密度
  • 距离价格吸引点(例如华盛顿广场、剧院区)

这意味着我们可以丢弃:所有地铁数据、季节数据和其他表现不佳的特性。此外,我们现在将只使用随机森林,而不是我们以前使用的所有森林(即我们最初的 ElasticNet 森林)。

最终产品是一个非常简单的模型,可以用 javascript 而不是 python 来编写!这就是 Pad Pricer 如何实时更新费率。

大多数自然语言处理模型的简明指南——前 LSTM 冰河时期——(R)NNLM,GloVe,Word2Vec & fastText

原文:https://towardsdatascience.com/a-no-frills-guide-to-most-natural-language-processing-models-part-1-the-pre-lstm-ice-age-86055dd5d67c?source=collection_archive---------23-----------------------

对前 LSTM 语言模型的起源、用例以及优缺点的总结:(R)NNLM、GloVe、Word2Vec & fastText。

随着我对自然语言处理(NLP)的了解越来越多,我意识到关于最近模型的信息特别分散,很难获得。我希望集中概括每个不同的主要模型的起源、用例以及优缺点。在这篇文章中,我总结了四个主要的模型。

虽然这可能仍然包含一些无法解释的术语,但是通过其他帖子可以很容易地获得关于各种概念的信息。

强调“LSTM 时代”之前四种主要模式的时间表

(R)NNLM —(递归)神经网络语言模型(有时也称为本吉奥神经语言模型)

这是一个非常早期的想法,也是最早的嵌入模型之一。该模型同时学习每个单词的表示和相邻单词序列的概率函数。它能够“理解”句子的语义。这项训练是以连续不断的单词袋为基础的。

假设模型输入一个句子,输出一个嵌入,它可能会考虑上下文。然而,架构仍然很简单。

最初的版本不是基于递归神经网络(RNN),而是后来开发了一种依赖于后者的替代方案(既不是基于门控递归单元(GRUs),也不是基于长短期记忆(LSTM),而是真正基于“香草”RNN)。虽然 rnn 速度较慢,并且在保存长期依赖关系的信息方面经常有问题,但它允许 NNLM 模型克服其一些限制,例如需要指定其输入的长度,或者尽管输入较长,但仍能保持模型的大小不变。

谷歌已经开源了一个针对大多数语言的预训练嵌入模型(英文版在这里是)。该模型使用三个隐藏层的前馈神经网络,并在英文 Google News 200B 语料库上训练,输出 128 维嵌入。

优点: -简单性:训练和生成嵌入很快(对于大多数简单的应用来说可能就足够了)
-预训练的版本可以在多种语言中使用

缺点:

Yoshua Bengio,Réjean Ducharme,Pascal Vincent,Christian Jauvin, 一个神经概率语言模型 (2003),《机器学习研究杂志》

Word2Vec

它起源于 Google,通常被视为 NLP 语言模型的转折点。

为了训练模型,广泛采用的 Word2Vec 版本摆脱了 NNLM 的连续单词袋,采用了跳格和负采样。本质上,模型不是试图预测下一个单词,而是试图预测周围的单词。为了使训练变得复杂,给出了许多否定的例子(通常是 4:1 ),并且该模型解决了一个简单的分类任务(两个单词在相同的上下文中吗?)使用只有一个隐藏层的神经网络。

Word2Vec 的“可解释性”让每个人都感到惊讶(例如:女人和男人经常被一个向量分开,这个向量非常类似于区分国王和王后的向量,因此可以被解释为“性别”向量)。

虽然很有影响力,但是 Word2Vec 嵌入本身并没有真正被使用,因为它们已经被后继者所取代。

预先训练好的模型可以在线获得,并且可以使用 gensim python 库导入。

优点:
-非常简单的架构:前馈,1 个输入,1 个隐藏层,1 个输出
-简单性:训练和生成嵌入很快(甚至是你自己的!)这对于简单的应用来说可能就足够了
-嵌入“有意义”:它可以允许破译偏差
-该方法可以扩展到许多其他领域/问题(即 lda2vec)

缺点:
-
在单词级训练:没有关于句子或单词使用的上下文的信息
-共现被忽略,意味着该模型在技术上忽略了单词根据其使用的上下文可能具有非常不同的含义(主要原因 GloVe 通常比 Word2Vec 更受欢迎)
-不能很好地处理未知和罕见的单词

托马斯·米科洛夫、程凯、格雷戈·科拉多、杰弗里·迪恩, 向量空间中词表征的高效估计 (2013),学习表征国际会议

手套

GloVe 通常与 Word2Vec 联系非常紧密,因为它们几乎同时出现,并且依赖于一些相同的关键概念(即嵌入向量的可解释性)。然而,它们有一些重要的区别。

在 Word2Vec 中,单词的共现频率并不十分重要,它只是帮助生成额外的训练样本。然而,对于 GloVe 来说,它是指导学习的一条中心信息。

手套未使用神经网络/跳格图/等进行训练。相反,该模型使用随机梯度下降来最小化单词嵌入的乘积和同现概率的对数之间的差异。

在斯坦福大学网站的专门页面上可以很容易地找到手套嵌入物

优点:
-非常简单的架构:没有神经网络
-简单:它很快(多个预先训练的嵌入),这对于简单的应用来说可能足够了

  • GloVe 通过增加单词的共现频率来改进 Word2Vec,并且在大多数基准测试中的表现优于 word 2 vec
    -嵌入“有意义”:它可以允许破译偏差

缺点:
-
虽然共现矩阵提供了全局信息,但 GloVe 仍然在单词级别上接受训练,并且在使用单词的句子或上下文中具有相对较少的信息(特别是与我们将在未来帖子中看到的一些模型相比)
-不能很好地处理未知和罕见的单词

Jeffrey Pennington、Richard Socher 和 Christopher D. Manning, GloVe:单词表示的全局向量 (2014),自然语言处理中的经验方法

快速文本

fastText 最初创建于脸书,通过将每个单词视为由“字符 n 元语法”组成的来扩展 Word2Vec。本质上,单词向量是其所有 n 元语法的总和(例如:“他们”可能有“th”、“he”、“ey”、“the”、“hey”,这取决于超参数)。

因此,对于不太频繁的单词,单词嵌入往往更好(假设它们共享一些 n 元语法)。因此,该模型还能够为未知单词生成嵌入(与 Word2Vec 和 GloVe 相反),假设它通过它们的 n 元语法来分解它们。

在多个不同的基准测试中,fastText 的性能都优于 Word2Vec 和 GloVe。

157 种不同语言的预训练模型在这里可用

优点:
-相对简单的架构:前馈、1 个输入、1 个隐藏层、1 个输出(尽管 n 元语法增加了生成嵌入的复杂性)
-嵌入“有意义”:它可以允许破译偏差
-由于其 n 元语法方法,嵌入在罕见和不在词汇表中的单词上的表现比 GloVe 和 Word2Vec 好得多

缺点:
-
在单词级训练:没有关于该单词使用的句子或上下文的信息
-共现被忽略,这意味着该模型在技术上忽略了一个单词根据其使用的上下文可能具有非常不同的含义(手套可能是首选的主要原因)

Armand Joulin,Edouard Grave,Piotr Bojanowski and Tomas Mikolov, 高效文本分类的锦囊妙计 (2016),计算语言学协会欧洲分会

正如您所看到的,所有四个模型都有很多相似之处,但是它们中的每一个都应该在不同的环境中使用。不幸的是,这一点经常被忽视。我希望这个指南将使你的模型决策更加明智,并引导你获得更好的结果。

PS:我现在是伯克利的工程硕士,我还在学习这方面的知识。如果有什么需要改正或不清楚的地方,请告诉我。也可以邮件我 这里

大多数自然语言处理模型的简明指南——LSTM 时代——seq 2 seq、InferSent、Skip-Thought、Quick-Thought、ELMo、Flair 和 ULMFiT

原文:https://towardsdatascience.com/a-no-frills-guide-to-most-natural-language-processing-models-the-lstm-age-seq2seq-infersent-3af80e77687?source=collection_archive---------21-----------------------

总结了 LSTM 语言模型的起源、使用案例和优缺点:Seq2Seq、Skip-think、Quick think、InferSent、ELMo、Flair 和 ULMFiT

随着 LSTMs 越来越流行,NLP 社区通过从仅部分考虑单词上下文的浅层静态嵌入转移到利用周围上下文创建更深层表示的更上下文化/动态的单词表示,改进了语言模型。

虽然这可能仍然包含一些无法解释的术语,但是通过其他帖子可以很容易地获得关于各种概念的信息。

突显“LSTM 时代”七种主要模式的时间线

Seq2seq

没有嵌入

Seq2seq 在这个列表中很突出,因为它本身不生成嵌入。然而,它可以成为一个人的 NLP 工具包中的一个有价值的武器,因为它可以很容易地适应特定的用例。

Google 在机器翻译的背景下引入了 Seq2seq。这是第一个使用注意力的模型(被最近的 transformer 架构广泛利用)。该结构在编码器/解码器之间划分,并且它们中的两个使用波束搜索与注意力层相关(参见下图或吴恩达的自由序列模型课程以获得关于注意力机制的更多细节)。

图片来自谷歌的 seq2seq GitHub

Seq2seq 因彻底改变了机器翻译而闻名(在谷歌翻译上几个月内超过了统计学家多年的工作)。它也可以很容易地调整为其他任务,其中输出是一个序列(即会话或总结)。

优点:
-生成序列的卓越性能(它奠定了 transformer 模型的基础)
-与“传统”LSTM 模型相比,注意力层允许更好地处理长期依赖性

缺点:

Ilya Sutskever,Oriol Vinyals,Quoc V. Le,用神经网络进行序列对序列学习(2014),NIPS

跳过思维向量(奖励:思维敏捷)

句子级嵌入

Skip-Thought Vectors 基于静态单词嵌入中使用的 skip-gram 训练方法,并将其扩展到句子。Skip-Thought 不是使用一个单词并试图预测上下文,而是使用一个句子并试图预测周围的句子。

该模型使用递归神经网络(通常是 GRU 或 LSTM)对句子中的单词进行编码。然后,它使用以编码器的输出为条件的解码器(也称为它使用与编码器相同的嵌入层)来生成最佳可能的目标输出(下一个和上一个句子)。使用实际编码的句子和预测的嵌入之间的差异,训练该模型以尽可能准确地预测其周围的句子。

Quick Thoughts 是后来开发的另一个模型,它使用类似的编码器/解码器策略。不同的是,它是在一个更经典的分类任务上训练的,更接近于 skip-gram 和负采样。对于每个句子,另一个目标句子被提供给解码器(与编码器的权重相同),然后编码的原始句子和“解码的”句子被提供给分类器进行“比较”(即原始句子是否与目标句子相邻)。

考虑到训练中的差异,快速思维通常被认为更适合区分性任务,而跳过思维更适合生成性任务。

优点: -句子级嵌入对某些任务有用
-通用和健壮的句子嵌入:在许多下游任务(语义相似性、分类等)上相当准确。)

缺点: -LSTM 结构和嵌入在句子级别的事实使其训练缓慢,使用大量内存,并且难以训练长句
-它是第一个句子嵌入之一,因此不再被认为是最先进的(SOTA)
-它被训练的任务,即预测相邻的句子, 很难(即使对人来说也是如此),所以通常不是最好的嵌入方式(尽管快速思考会使问题简化一点)
-使用 Skip 思想,一个句子被嵌入到一个 2400 维的向量中,比大多数其他类型的嵌入方式都要多得多
-与长期的上下文依赖作斗争(与基于 transformer 的长句模型相比)

Jamie Ryan Kiros,Yukun Zhu,Ruslan Salakhutdinov,Richard S. Zemel,Antonio Torralba,Raquel Urtasun,Sanja Fidler,Skip-think Vectors(2015),NIPS

Lajanugen Logeswaran,Honglak Lee,学习句子表征的有效框架 (2018),ICLR

InferSent

句子级嵌入

使用 Stanford 自然语言推理(SNLI)语料库,通过使用双 LSTM 层(具有最大池)来编码句子对(两个句子使用相同的编码器)来构建推理。添加几个密集层,并训练模型来预测这两个句子是体现“中性”、“矛盾”还是“蕴涵”。在向量被馈送到双 LSTM 层之前,单词通常首先被转换成静态单词嵌入(在原始情况下是手套嵌入)。结果,隐含嵌入提供了句子的深层语义表示。

由脸书创建的 InferSent 也可以很好地推广到其他任务,并且预先训练的版本很容易在脸书研究公司的 GitHub 上获得。

优点: -句子级嵌入可能对某些任务有帮助
-该模型在复述检测和蕴涵任务上表现特别好

缺点: -复杂的双 LSTM 结构使其训练和生成嵌入变得缓慢
-输出是 4096 维的嵌入,这显著多于几乎所有其他语言模型
-在情感分析、语义关联、标题检索等许多任务上的表现不如 ELMo 或 Flair。
-监督训练使得很难在定制数据集/更具体的上下文中重现
-与长期上下文依赖作斗争(相对于基于转换器的长句模型)

Conneau,Alexis 等人,从自然语言推理数据 (2017),计算语言学协会

ELMo(语言模型嵌入)

单词级嵌入

ELMo 使用深度双 LSTM 架构来创建情境化嵌入。
AllenNLP 所述,ELMo 表示为:“上下文”(取决于使用单词的上下文)、“深度”(通过深度神经网络训练)和“基于字符”(参见 fastText 嵌入,以便更好地处理不在词汇表中的单词)。

为了训练模型,ELMo 使用正向和反向语言建模(LSTM 的一个方向预测第一个单词,另一个方向预测最后一个单词)。

该模型包含许多层,这些层之间存在残余连接。有趣的是,每一层最终都会学习句子的不同特征,比如前几层的词性标注和后几层的词义消歧。

通过 Tensorflow Hub ,可以轻松使用在 10 亿字基准上预先训练的 ELMo 嵌入。

优势: ——深度的基于上下文和字符级的单词表示,适用于更复杂的任务
——在许多任务上表现得比简单的嵌入好得多
——易于使用的预训练版本

缺点: -复杂的双 LSTM 结构使其训练和生成嵌入非常缓慢
-类似的模型如 Flair(见下文)通常表现更好
-与长期上下文依赖作斗争(相对于长句的基于 transformer 的模型)

马修·e·彼得斯、马克·诺依曼、莫希特·伊耶、马特·加德纳、
克里斯托弗·克拉克、肯顿·李、卢克·塞特勒莫耶、 深度语境化的词语表征 (2018)、NAACL

天资

单词级嵌入

随着 ELMo 的流行,Flair 由 Zalando Research 开发,并在 ELMo 的基础上通过更多地依赖角色级别进行了改进。

与 ELMo 类似,Flair 学习基于字符的双 LSTM(也使用向前和向后语言建模)。然而,此外,单词嵌入是通过将单词一个字符一个字符地给定到两个 LSTMs 中并仅保持/连接每个单词的最后状态(即,第一个和最后一个字符)来表示单词嵌入而计算的。

Flair 单词嵌入有多种语言版本,使用 Flair python 库(构建于 PyTorch 之上)可以非常容易地生成。

优势: -适用于更复杂任务的深度基于上下文和字符级别的单词表示
-考虑到嵌入的特殊性,仅保留第一个和最后一个状态,嵌入尤其能很好地处理词汇外的标记,并能处理小得多的字典
-表现优于静态嵌入,通常在许多任务上 ELMo
-易于访问预训练版本

缺点: -复杂的双 LSTM 结构使得训练和生成嵌入非常缓慢
-与长期上下文依赖作斗争(与基于转换器的长句模型相比)

Akbik 等人,用于序列标记的上下文字符串嵌入 (2018),计算语言协会 Seq2Seq

乌尔菲特

单词级嵌入

ULMFiT 源于 Fast.ai,通常被认为是第一个真正有效地将迁移学习推广到任何任务的模型。

ULMFiT 依赖于双向 LSTM 架构(向前和向后语言建模)。ULMFiT 在三个连续的任务上进行训练:在维基百科数据集上进行通用领域语言模型预训练,在 IMDb 数据集上进行特定任务语言模型微调,最后在 IMDb 数据集上进行特定任务分类器微调。

两项发展使 ULMFiT 具有出色的性能:
-随着训练的进行,ULMFiT 在微调过程中通过逐渐解冻其不同层来进行微调,以及
-它使用“倾斜三角形学习率(STLR)”,这意味着学习率开始增加,随后随着训练的进行以线性方式衰减。

ULMFiT 的主要优势在于它能够轻松适应各种任务。对迁移学习的特别关注使 ULMFiT 成为许多任务/适应的非常好的竞争者。

使用 Fast.ai Python 库和他们的教程,可以很容易地下载和微调一个预先训练好的模型。

优点: -通用:一个预先训练好的模型,非常容易适应任何任务
-LSTM 模型的出色性能
-需要比其他模型少得多的数据来针对特定领域/任务进行微调
-由于 Fast.ai 的精彩教程,易于访问和使用

缺点: -复杂的双 LSTM 结构使得训练和生成嵌入非常缓慢
-与长期上下文依赖作斗争(与基于转换器的长句模型相比)

杰瑞米·霍华德,塞巴斯蒂安·鲁德,文本分类通用语言模型微调 (2018),计算语言学协会

与静态嵌入相比,上下文化的表示对于更复杂的任务来说要强大得多,并且知道选择哪种模型会对模型的性能产生重大影响。像往常一样,努力记住每个模型是如何被训练的,并努力找到其主要任务与应用程序的目的最相似的模型。希望这篇文章能帮助你更好地理解众多 LSTM 时代模型的优缺点和用例。

虽然基于 transformer 的模型提供了更复杂的表示,可以考虑长期的依赖性,但是 LSTM 模型在 transformer 模型的复杂性和有时过于简单的静态嵌入之间提供了一个非常相关的替代方案。

PS:我现在是伯克利的工程硕士,我还在学习这方面的知识。如果有什么需要改正或不清楚的地方,请告诉我。你也可以发邮件给我 这里

大多数自然语言处理模型的简明指南——Transformer(XL)时代

原文:https://towardsdatascience.com/a-no-frills-guide-to-most-natural-language-processing-models-the-transformer-xl-era-ff5035f04e0f?source=collection_archive---------28-----------------------

从通用语句编码器到 Open-GPT2、(AL)BERT、XLNET 和图灵-NLG

LSTMs 非常受欢迎,但是它们也有很多限制。它们计算量很大,并且很难维持长期的依赖关系(尽管它们的名字如此)。2018 年,谷歌发表了一篇论文“注意力是你所需要的一切”介绍了变形金刚,表明我们可以克服递归神经网络的很多缺陷,并彻底改变语言模型领域。

虽然这可能仍然包含一些无法解释的行话,但通过其他帖子应该很容易获得关于各种概念的信息。

展示变形金刚时代主要型号的时间表

通用句子编码器

谷歌发布了通用句子编码器,旨在提供一种句子嵌入,这种句子嵌入特别适合迁移学习,可以用于各种各样的任务(因此是“通用的”)。

通用句子编码器最初发布了两个版本:一个利用深度平均网络(DANs),另一个使用变压器。自最初实现以来,谷歌已经发布了许多基于 DANsTransformers 的版本,并使它们在他们的 Tensorflow Hub 平台上非常容易访问。所有模型都采用单词、句子或句子组,并输出 512 维的向量。

为了训练这个模型,谷歌使用了各种各样的数据源和任务,但主要的是围绕着在斯坦福自然语言推理语料库上识别相似的句子(所谓的“语义文本相似性”)。这种语言模型在这个任务上表现得特别好。

优点:
-该模型在句子相似度方面表现特别好
-在各种各样的“开箱即用”任务方面表现相对较好
-将您的输入转换为嵌入非常快(比大多数 LSTM 模型快得多)

缺点: -模型可以嵌入单词或句子。但是,它是针对句子进行训练的,因此当输入不是正确的“句子”时应该更加小心使用
-其特殊的训练(主要集中在句子相似性上)使其具有独特的地位,但也使其在各种任务(如文本生成)中的表现不如其他模型

Cer 等人通用语句编码器 (2018),ACL

Open-GPT2

最初,OpenAI 在开发 Open-GPT2 时拒绝发布他们的模型,因为他们认为它太危险,并担心人们可能会恶意使用它。

该模型有大约 15 亿个参数,并在 OpenAI 的 WebText 数据集上进行训练,该数据集包含超过 800 万个文档和大约 40 GB 的文本数据(一些人试图复制和开源他们的版本)。

Open-GPT2 由具有多头注意力的变压器解码器块组成,并接受语言建模训练,一次预测一个下一个令牌。由于这种训练,它特别适合文本生成。

来自 http://jalammar.github.io/illustrated-gpt2/的图表说明了 Open-GPT2 解码器的不同层次

OpenAI 最终向公众发布了这个模型,现在已经可以轻易获得了。

该模型需要大量的磁盘空间、计算和内存资源。

优点: -由于数据集和从左到右的语言建模训练方法,在文本生成方面表现出色(明显优于 BERT 和其他从掩蔽语言模型学习的类似模型)

缺点: -仅用于文本生成:该非营利组织看到了该模型在语法辅助、自动完成、创造性写作和游戏/聊天机器人创建方面的潜在用例,但这仍然有限

  • GPT-2 占用超过 5Gb,需要非常高的计算和内存要求(提取的模型有所帮助,但仍在进行中)

拉德福德等人语言模型是无监督的多任务学习者 (2019)

伯特

谷歌在 2018 年底发布了 BERT,吸引了大量关注。该模型利用多层双向变压器架构(即带有一个编码器和一个解码器),在广泛的任务中创下了新的记录。

BERT 主要在两个任务上接受训练:
-掩蔽语言模型:该模型试图预测随机掩蔽的句子的大约 15%的单词
-识别下一个句子

BERT 占用大量内存,速度相对较慢。基础版和大版分别有 1000 万和 3.4 亿个参数。

2019 年,另一个研究团队发布了 ALBERT,引入了参数缩减技术,允许降低内存要求和提高训练速度,同时取得了明显优于 BERT 的结果,在一些主要基准上达到了最先进的水平(SOTA)。ALBERT 的参数比 BERT-large 少 18 倍,训练速度快 1.7 倍。

伯特和 T2【艾伯特都很容易访问,你可以通过 Tensorflow Hub 轻松创建你的嵌入。

优势: -在多种任务(分类、句子相似度、名称实体识别、问题回答)上表现出色
-在 Tensorflow Hub 上有超过 100 种不同语言的模型

缺点:

Devlin 等人 BERT:用于语言理解的深度双向转换器的预训练 (2018),ACL

兰等阿尔伯特:一个用于语言表征自我监督学习的 Lite BERT(2019)

XLNet

来自谷歌大脑和卡耐基梅隆大学的一组研究人员研究了 BERT 的主要缺陷,并利用新的 Transformer-XL 架构发布了 XLNet,在 18 个 NLP 任务上实现了 SOTA。

XLNet 基于 Transformer-XL 。后者对 Transformer 架构进行了改进,速度快了很多(根据 Google 的说法是 1800+),并且增加了段级递归以及相对位置编码。与标准的 transformer 架构相比,它能够处理更大的句子,并保留更长时间的依赖性。Transformer-XL 学习依赖关系的时间分别比 RNNs 和标准 Transformer 长约 80%和约 450%。

来自https://ai . Google blog . com/2019/01/Transformer-XL-unleashing-potential-of . html解释 Transformer-XL 的段级递归机制的图形

伯特展示了两个大问题。屏蔽的令牌出现在训练中,但不出现在微调中,导致训练测试偏斜
2。被屏蔽的令牌是并行预测的,因此它们之间的依赖关系通常不能被正确处理。

通过使用“置换语言建模”,XLNet 能够克服这一点。XLNet 不是预测下一个令牌或前一个令牌,而是以随机顺序预测令牌。假设 Transformer-XL 允许它保持位置嵌入的一致性,并且该模型将定位与嵌入的剩余部分分开,并且在尝试预测屏蔽的记号时保持其可用,则该模型仍然能够以所需的顺序处理记号。

由于 Transformer-XL 架构,以前的段被缓存和冻结,使得置换语言建模成为可能,而无需知道以前的置换顺序。

通过所有的改进,XLNet 有效地取代了(AL)BERT,成为语言模型中的新参考。该模型可以很容易地在 Tensorflow 2.0 和 PyTorch 上使用拥抱脸的变形金刚库进行使用和调整。

优势: -在几乎所有任务上比(AL)BERT 表现更好
-比(AL)BERT
训练和使用速度快得多-由于其“置换语言建模”和自回归方法,在文本生成方面相当不错

缺点:

杨等 XLNet:面向语言理解的广义自回归预训练 (2019)

图灵-NLG

2020 年 2 月,微软提出了一个有 170 亿个参数的生成语言模型。该模型有 78 个变形层和 28 个注意力头。

该模型的许多成就源于微软实现的并行化,以跨 GPU 训练图灵-NLG。作者充分利用了 PyTorch 和最近的微软库/出版物,如 DeepSpeedZeRO ,这些库/出版物显著改善了具有超过 10 亿个参数的深度学习模型的并行训练。

目前,作者对模型的许多细节保持沉默,提到了不同的层类型,以及它是以多任务的方式训练的。尽管如此,这种规模的模型标志着大规模深度学习语言模型的重大突破,可能是未来趋势的一个标志。

图表突出显示了来自微软研究院博客的最新模型及其参数数量(https://www . Microsoft . com/en-us/Research/Blog/turing-NLG-a-170 亿-parameter-language-model-by-Microsoft/)

这个模型最近才发布,但是使用微软的 API 来生成这个模型的嵌入是可能的。

优点: -在众多任务中实现 SOTA,在文本生成方面非常高效

缺点: ——相对难以接近,不可能训练出自己的模型
——目前还没有透露太多细节

罗赛特,科比。图灵-NLG:微软的 170 亿参数语言模型 (2020)

在过去的两年里,变形金刚彻底改变了 NLP 的世界。这个领域已经从静态嵌入(我在这里写了那些的概述)和第一个上下文化的表示(我在这里写了那些的(其他)概述)走了很长的路。Transformer、Transformer-XL 和分布式计算的进步允许开发具有更多参数的模型,这些模型能够保留越来越多的长期依赖关系。一些最新的模型已经能够在许多 NLP 任务中击败人类,并且它们能够生成的文本越来越难与人类书写的文本区分开来。成为基准的新模型似乎每 6 个月就出现一次,在 NLP 中从未像现在这样令人兴奋。

如果你想从生成建模中获得乐趣并创建酷文本,我强烈推荐抱抱脸的“用变形金刚写”

PS:我现在是伯克利的工程硕士,我还在学习这方面的知识。如果有什么需要改正或不清楚的地方,请告诉我。你也可以发邮件给我 这里

一个关于希格斯玻色子如何赋予粒子质量的合理解释

原文:https://towardsdatascience.com/a-no-nonsense-explanation-of-how-the-higgs-gives-particles-their-masses-639a0aba6d54?source=collection_archive---------8-----------------------

希格斯机制的简化解释

图片来自皮克斯巴伊加里克·巴尔塞吉安

粒子物理学家主要在 20 世纪下半叶发展了一个优雅的理论模型,构成了我们理解宇宙中基本粒子和力的框架。这个强大的框架就是所谓的标准模型,它的主要成分之一是希格斯场,这是一个无处不在的量子场,负责给粒子赋予质量。由于量子力学中的波粒二象性,希格斯场有一个与之相关的基本粒子,即所谓的希格斯玻色子。
这篇文章的目标是为希格斯玻色子及其特性提供一个更加数学化的解释。

图 1: 这张图片显示了希格斯玻色子衰变为两个光子的事件,其中绿线是它们的能量沉积。这个实验让科学家缩小了希格斯粒子的质量( 来源 )。

自发对称性破坏

正如 Zee 所观察到的,尽管自然的基本法则有几种对称,但我们所经历的世界远非对称。用物理学术语来说,我们的拉格朗日量是对称的,但他们描述的世界却不是。事实上,研究这种对称性如何被打破是物理学的一个中心话题。

首先,让我们考虑一个对称性破缺的例子,其中系统由相互作用的 N 分量标量场组成。

标量字段

考虑一个具有分量的 N 维标量场的拉格朗日量:

情商。1:N-维标量场。

拉格朗日密度T3 给出:

情商。2:旋转对称的拉格朗日密度(在 N 维中)。

注意质量项的符号是负的(故意的)。拉格朗日是:

情商。3:拉格朗日密度 Eq 对应的拉格朗日。2.

情况 N =1 如果 N =1,则拉格朗日函数有极值

情商。4:拉格朗日 l 的极值这里,第一个 ϕ 是局部最大值

其中 ϕ =0 是最大值。其他两个 ϕ 中的任何一个,即 v 或- v ,都是等价的基态,我们可以选择其中一个作为我们的基态。基态被称为 VEV(真空期望值)。

注意,两个极值之间的隧道势垒是无穷大:

情商。5:QFT 拉格朗日 L 的极值之间的势垒是∞。

这是因为方程中的时空积分。5 是无限的。由于势垒是无限的,基态波函数不能在极值之间隧穿。它必须保持在由等式的正版本确定的值 v 。4.于是,普通量子力学中存在的反射对称性 ϕ → - ϕ 被打破。但是,正如 Zee 指出的,对称破缺是而不是L 中(人为)引入新术语造成的。ϕϕ对称性被“自己”打破。

案例 N =2 势,在这个案例中,就是著名的墨西哥帽势。我们现在有无限多的物理等价极小值(或真空)。所有这些真空具有相同的(平方)值,即:

情商。6:N = 2 时所有最小值的平方值。

现在请注意,每个最小值指向不同的方向。但是结果不能取决于的选择——所以我会跟着 Zee 的方向而选择:

  • ϕ 要在单向(这样 ϕ ₂=0).
  • 等式给出的 ϕ ₁=+ v 的值。6(正号)。

图 2:v(ϕ的“墨西哥帽”势函数及其无穷小值。

我们现在研究ϕ₁和ϕ₂的波动,把最小值写成:

情商。7:最小值附近的波动。在该电势的最小值处,1 分量在径向上波动,2 分量在圆周上波动。

1-分量在径向上波动,2-分量在电势的最小值处围绕圆周波动(因此,其绝对值不变)。

代入等式。7 在拉格朗日中我们得到:

情商。8:ϕ的第二个部件是无质量的!

这个等式告诉我们, ϕ 的二维分量是无质量的。

希格斯机制

我们现在将在我们的拉格朗日量中包括一个规范场 一个 。根据定义,规范理论是一种场论,它的拉格朗日量在某些类型的群的变换下是不变的。根据规范原理,它是宇宙中三个基本相互作用的基础,如果我们改变描述它的方式,物理学不应该改变。规范理论有两种类型:阿贝尔和非阿贝尔。阿贝尔规范理论的一个例子是我们熟悉的电磁理论。

电磁场

让我们从电场和磁场的麦克斯韦方程开始, EB :

情商。9:电场和磁场的麦克斯韦方程组, EB.

图 3:描绘了一场地磁暴,带电粒子通量的激增改变了地球的磁场,在大气中感应出电场。这种现象导致电网中的电涌(来源)。

电场和磁场可以用电势 V 和**AA表示如下:**

情商。10:用电势 Va .写出的电场和磁场

我们可以将 VA组合成矢势:

情商。11:四矢量(或双矢量)电位。

与电磁场有关的拉格朗日量,它的方程在矢势的规范变换下是不变的

情商。12:规范变换,其中χ是标量函数

由下式给出:

情商。13:电磁场的拉格朗日量。矢量 j 是以电荷和电流密度为分量的 4-电流。

而张量 F 是:

情商。14:电磁场张量。

注意 F 在规范变换 Eq 下不变。12(按建筑)。阿贝尔规范理论在 U(1)群下是全局不变的。次数为 n 的酉群 U( n )由 n × n 酉矩阵组成,具有矩阵乘法的群运算。群 U(1)也称为圈群,是所有模数为1 的复数的乘法群。

图 4:圆组 U(1)的图解(来源)。

狄拉克场 狄拉克场 ψ费米子场的一个例子,这是一个量子场,它的量子是费米子(它们服从费米-狄拉克统计)。这种场服从正则反对易关系,与玻色子场相反,玻色子场服从正则对易关系。

电荷为 e、质量为 m、T42 的狄拉克场有如下的自由拉格朗日量

情商。15:自由的狄拉克拉格朗日。

其中:

情商。16:狄拉克伴随。

是狄拉克伴随场,并且:

情商。17:伽玛矩阵的标准表示。

伽马矩阵的标准表示。狄拉克拉格朗日量在全局规范变换下是不变的:

情商。18:全球规范转换。

在局部规范变换中, α 变成函数 α ( x )并且新的拉格朗日不变量在

情商。19:局部规范变换。

变成了:

情商。20:局域规范变换下的自由狄拉克拉格朗日不变量。

其中:

情商。21:协变导数。

包括电磁场和狄拉克场的量子电动力学(或 QED)拉格朗日量为:

情商。22:量子电动力学(或 QED)拉格朗日量。

图 5:首次发表的费曼图,它出现在理查德·费曼的物理评论论文“量子电动力学的时空方法”(来源)。

希格斯场和希格斯玻色子

如前所述,我们的世界不是规范对称的。然而,一个理论有可能具有某种对称性,即使我们对那个物理理论的经验没有反映出相应的对称性。没有大量无质量的向量场(例如电磁场)意味着规范对称性被破坏。

*现在让我们考虑一个在规范理论中自发对称性破缺是如何发生的例子。为简单起见,我将考虑最简单的规范理论,即电磁学,它是一个 U(1)规范场,耦合到一个复杂的标量场 *ϕ.拉格朗日量,在 Eq 下不变。18 是:

情商。22:耦合到复标量场的 U(1)规范场的拉格朗日量。

这里的组件 ϕ ₁和 ϕ ₂是ϕ.的实部和虚部****

现在我们将标量场写成如下形式:

情商。23:用极坐标表示的标量场。

进行转变

我们生成一个规范不变的组合:

情商。24:规范不变组合。

正如我们之前所做的,我们选择

情商。25:标量电位最小的点。

电位最小的值。

如前所述添加波动项

情商。26:为说明自发对称性破缺而增加的波动项。

我们得到下面的拉格朗日量:

情商。27:拉格朗日方程。22 增加一个波动项来解释自发的对称性破缺。

这个拉格朗日描述了一个质量为 M = ev 的向量场 B ,它与质量为 has 的标量场χ相互作用

情商。28:标量场的质量χ。

注意,玻色子 θ 在拉格朗日中是不存在的。一说 θ 被规范场T5 AT7“吃掉”变成了BT11,现在是大质量。先前的无质量场 A 具有两个自由度,或者等效地,两个偏振方向(两个自旋方向)。大质量规范场获得多一个(纵向)自由度(或多一个可能的自旋状态)。这种从无质量到有质量的转变被称为希格斯机制,ϕ被称为希格斯场。而正如简介中所解释的,由于量子力学中的波粒二象性, ϕ 有一个与之相关的基本粒子,即所谓的希格斯玻色子****

图 6:希格斯势。选择底部的任何一个点都会自发破坏旋转 U(1)对称性(来源)。

电弱理论和大质量矢量玻色子

电弱理论描述了电磁力和弱核力。

图 7:一个中子通过一个中间重 W 玻色子()β-衰变为质子、电子和电子反中微子。

这些力量看起来非常不同:

  • 弱核力只在很小的距离内起作用(小于原子核)
  • 电磁力作用于巨大的距离,并随着距离的平方而减小。
  • 质子之间的电磁力比弱核力强 10⁶倍。

然而,物理学家谢尔登·格拉肖阿卜杜勒·萨拉姆史蒂芬·温伯格表明,在所谓的统一能量 (~246 GeV )之上,这些力会合并成一个力。

图 8:诺贝尔奖获得者谢尔登·格拉肖史蒂芬·温伯格阿卜杜勒·萨拉姆表明,在统一能量以上,电磁力和弱核力合二为一。

换句话说,在这个极限阈值之上,这两种力是更基本的电弱力的不同方面。无质量规范场 A 的自发对称性破缺,如上所述gIves起源于三个大质量矢量玻色子,即:**

情商。29:无质量规范场的自发对称性破缺 A 给出了三个大质量玻色子的起源,即。

换句话说,希格斯机制解释了方程中弱相互作用规范玻色子的质量。29.

图 9:标准模型中的希格斯玻色子(来源)。

感谢您的阅读,再见!一如既往,我们随时欢迎建设性的批评和反馈!

我的 Linkedin 、个人网站 www.marcotavora.me 、以及 Github 都有一些其他关于物理以及数学、机器学习、深度学习、金融等等其他话题的有趣内容!看看他们!

Excel 中使用发布/订阅模式的非易失性间接替代方案

原文:https://towardsdatascience.com/a-non-volatile-indirect-alternative-in-excel-using-the-pub-sub-pattern-15cea21272a3?source=collection_archive---------12-----------------------

显著提高电子表格的性能,并分离您的工作簿。

图像来源

Excel 中的间接函数是一个棘手的问题。一方面,它非常有用,但另一方面,它也影响了许多电子表格的性能。

在本文中,我们将了解什么是间接函数,为什么它对性能如此不利,以及一个有趣的替代方法,它几乎在所有方面都是优越的。

间接功能的简要说明

使用 INDIRECT 从另一个工作簿获取值

INDIRECT 函数获取单元格地址并返回单元格中包含的值。

当设计一个电子表格或一组电子表格时,提前计划并保持它们井井有条是值得的。从概念上讲,结合使用间接和命名范围似乎是一种很好的方式。您可以在一个工作簿中保留一个功能区域,并通过使用间接查询与其他相关工作簿共享关键结果。

使用命名范围避免了硬编码显式地址引用,并允许我们以后重构或重新构造被引用的工作簿。

为什么使用间接对性能很糟糕

间接函数是一个可变函数。这意味着,每当工作簿中的任何内容发生更改,或者每当您按 F9 进行计算时,都会调用间接函数。就其本身而言,这可能没什么大不了的,但是因为间接函数被重复调用,并且将该函数的结果作为输入的计算也将被重复调用。

如果间接调用的结果是某个复杂计算或缓慢函数的输入,那么您的电子表格将会爬行。每次您更改任何内容时,整个计算都将重新进行,即使您所做的更改与电子表格的该部分无关。

Excel 维护一个依赖关系图,使其能够知道在进行任何更改后哪些单元格需要重新计算。这允许它在更改后重新计算工作表时进行最少的计算。这是一种非常有效的方法,可以最大限度地减少需要完成的工作,以便电子表格可以快速更新。使用间接会破坏这一点,因为每次 Excel 重新计算时,任何相关(直接或间接)都将被重新计算

Excel 的开发人员这样做并非偶然。INDIRECT 函数检索指定地址的值,但它不依赖于该地址指向的单元格。如果在 Excel 的公式选项卡中使用追踪引用单元格,就可以看到这一点。这意味着它对参考单元格的变化不敏感。它不知道引用的单元格是否改变了,所以每次都要重新计算,这就是为什么它是一个易变函数。

引入间接的替代方案

如上所述使用 INDIRECT 是从一个电子表格中引用另一个电子表格中的值的常见解决方案。它将两个电子表格解耦,以便其中一个(我们称之为生产者)的计算可以被另一个(消费者)使用。不一定只有一个消费者,一个生产者可以有多个消费者。

需要将生产者消费者分离的问题并不是电子表格独有的。事实上,在软件工程中,这是众所周知的,并且有一些模式可以做到这一点。

发布/订阅发布者/订阅者模式就是这样一种模式,通常用于分离生产者和消费者。在这种模式中,消息被发布并且订户被通知这些消息。发布者和订阅者之间的消息传递由消息代理处理。

为了使单个消息代理可以用于不同类型的消息,通常将消息分成不同的主题。主题只是发布者和订阅者都知道的字符串。消息发布在特定的主题上,订阅者订阅一个主题。订阅者将只接收发布到他们订阅的主题的消息。

使用消息代理发布和订阅消息

在我们的电子表格中,我们可以使用这种发布/订阅模式,而不是使用间接方式从另一个工作簿中获取值。每当发生更改时,生产者工作簿将向消息代理发布值,而消费者工作簿将订阅这些消息,并仅在收到消息时进行更新。

我们将在下一节中实现这一点。

在 Python 中实现发布/订阅模式

我们将使用 Python 来实现发布/订阅模式。稍后我们将使用 Python Excel 插件 PyXLL 从 Excel 调用 use this。PyXLL 是一个商业产品,它使我们能够在 Excel 中使用 Python 代码,而不是 VBA。对本文至关重要的是,它还可以用来编写 RTD 或实时数据函数。我们将在消费者工作簿中使用一个 RTD 函数,以便每当从生产者工作簿中发布消息时更新该值。

PyXLL 可以从 https://www.pyxll.com 下载,并且有 30 天的免费试用。这里介绍的相同技术也可以用另一种语言实现,只要可以用那种语言编写 Excel 工作表函数和 RTD 函数(例如,使用 Excel-DNA 和 C#或 Jinx 和 Java、Scala、Kotlin 或 Clojure)。

通常在使用发布/订阅模式时,会使用一些消息中间件,如 Kafka、 RabbitMQApacheMQ 。这在我们在应用程序之间甚至服务器之间传递消息的情况下非常有用。在我们的例子中,所有的东西都将在一个应用程序中的 Excel 中运行,所以使用这样的消息服务是多余的。我们所需要的是一种将消息从生产者传递到消费者的方法,这些过程都是相同的。

我们将从一个具有三种方法的 MessageBroker 类开始:发布、订阅和取消订阅。我们的生产者将使用发布方法发布消息,我们的消费者将使用订阅方法订阅消息。当他们不再感兴趣时,他们可以使用取消订阅方法。消息本身将只是 Python 对象,而消费者将是接受这些 Python 对象消息作为单个参数的 Python 函数。我们的 MessageBroker 将为订阅者维护一个主题字典。

我们做到了!使用它,我们可以订阅一个主题,并在消息发布到该主题时接收回调。希望这表明发布/订阅模式不需要复杂就能有用:)

我们还可以做一些事情来改善这一点。在我们在 Excel 表之间传递值的例子中,如果在订阅时我们得到了最后发布的值,这将是有用的。这样,如果消费者在生产者已经发布了一些东西之后订阅,它将获得最新的值,而不必等到下一个。此外,Excel 函数可以(可选地)从多个线程调用,因此如果这是我们想要做的事情,那么我们需要小心多个线程同时访问 MessageBroker。

带有这些额外改进的完整代码可以在 github 上的 PyXLL 示例报告的“pubsub”文件夹中找到。

在 Excel 中汇总所有信息

提醒一下,我们走这条 pub/sub 道路的原因是为了在 Excel 中找到间接的替代方法,现在我们将回到这一点!

我们需要两个新的 Excel 函数,“发布”和“订阅”。publish 函数将从我们的 producer 工作簿中调用,带有一个主题名和我们想要发布的值。subscribe 函数将从我们希望接收值的消费者工作簿中调用。订阅方法将是 RTD 或实时数据函数。这是一种特殊类型的函数,即使在被调用后也能更新它的值。

如果您还没有下载 PyXLL,那么您现在需要下载,因为我们将使用它从 Excel 中调用上一节中的 MessageBroker 类。你可以从 https://www.pyxll.com 下载 30 天的 PyXLL 试用版。

我们将使用上面的 MessageBroker 类,并创建它的一个全局实例。我们还将添加一些方便的函数,以便可以在我们的全局 MessageBroker 实例上调用发布、订阅和取消订阅。

接下来,使用 PyXLL 我们可以编写“发布”Excel 函数,这样就可以从 Excel 工作簿中调用它。

如果您以前没有使用过 PyXLL,您可能会惊讶于这是多么容易!我们编写一个普通的 Python 函数,并简单地向它添加@xl_func 装饰器。这就是告诉 PyXLL 将我们的 Python 函数公开为 Excel 函数的原因。

为了保持简洁,我将 MessageBroker 类以及发布、订阅和取消订阅函数放在了一个模块 pubsub.py 中。你可以在 github 的 PyXLL 示例报告的“pubsub”文件夹中找到完整的代码。

要从 Excel 调用这个函数,您需要安装 PyXLL 插件(如果您还没有这样做的话),并将您的新 pubsub_example.py 模块添加到 PyXLL 配置文件 pyxll.cfg 中

从 Excel 函数发布值

现在我们准备添加“订阅”功能。为了使用 PyXLL 编写 RTD 函数,我们创建了一个从 PyXLL 的 RTD 类派生的类。你可以在用户指南中了解更多信息。

RTD 类有两个方法,连接和断开。当 Excel 准备好开始接收更新和不再需要更新时,分别调用这些函数。我们将在我们的类中覆盖这些来订阅和取消订阅消息代理。当收到新消息时,我们在 RTD 对象上设置“值”属性,该属性更新 Excel 中的值。

为了在 Excel 中创建“subscribe”函数,我们像以前一样使用@xl_func 装饰器,只是这次我们返回一个 SubscriberRTD 对象。当调用@xl_func decorator 时,我们还需要向 PyXLL 提供更多的信息,以便它知道将返回值视为 RTD 对象。

这就是用 PyXLL 在 Python 中编写 RTD 函数的全部内容!我们现在可以从另一个具有相同主题的工作簿中调用这个新的 subscribe 函数,每次生产者表发布一个值时,它都会在消费者表中更新。

我们可以让多个消费者订阅同一个主题,也可以让多个生产者发布不同的主题。每当发布的值更新时,将使用主题和新值调用“发布”Excel 函数。这将导致订阅同一主题的“订阅”功能的所有结果自动更新。

由于 RTD“订阅”函数是非易失性的,因此只有当值实际改变时,才会计算任何依赖性。

使用 PyXLL,我们不仅仅局限于在工作表之间传递数字或字符串。我们可以从 Excel 函数中返回完整的 Python 对象,并以完全相同的方式发布它们。

重述;我们做了什么?

我们开始寻找 Excel 间接函数的替代方法,避免使用可变函数带来的性能影响。

使用 INDIRECT 函数的原因是为了将一个电子表格中产生的结果与另一个电子表格中用作输入的结果分离开来。命名范围被认为是避免对特定单元格引用进行硬编码的一种方式。

使用发布/订阅模式,我们现在可以从任何工作簿发布结果,并在另一个工作簿中订阅这些结果。使用主题字符串,我们可以同时发布和订阅多个命名值。

使用 RTD 函数来订阅主题允许我们在发布新值时更新 Excel 中的值,而不必让函数变得不稳定。

我们已经实现了解耦多个电子表格的目标,通过使用命名主题,我们避免了直接引用另一个工作簿中的单元格。通过不使用可变函数,我们确保了我们的工作簿只需要在值改变时计算所需的最小值。

参考

数据科学和机器学习管理人员注意事项

原文:https://towardsdatascience.com/a-note-to-data-science-and-machine-learning-managers-bbeb820a606a?source=collection_archive---------58-----------------------

使用启发法,特别是那些指导你不要做什么的方法

丹尼尔·延森Unsplash 上拍照

我不是一个喜欢提建议的人。人们很快就放弃了这种通常毫无价值的商品,事实上这是一个相当大的产业。书架上到处都是如何自助的七个步骤。那就蛇油吧!在资金管理的世界里,我发现摆脱混乱的方法是不要问我在投资方面应该做什么,这几乎总能得到一些规范性的建议,而是问你在做什么——让我看看你的钱在哪里。有趣且不令人惊讶的是,建议看起来与给出建议的人实际做的事情大相径庭。他们所做的告诉了我所有我需要知道的。这些建议往往毫无价值。

因此,在这篇笔记中,我将不再提建议,而是把重点放在我发现在复杂环境中非常有用的启发式方法上,尤其是那些指导你不要做什么的方法。以国际象棋为例,大师专注于避免失误,新手则试图获胜。正如(Taleb,Goldstein,Spitznagel,2009)所指出的,“不要做”的建议通常比“要做”的建议更有效。

因此,下面是我应用的“不要”类的经验法则的小集合:

不找员工,青睐创业人士

你怎么可能清楚地区分一个企业家和一个雇员呢?我发现这相当容易。创业的人,在看了事情不成功的所有原因后,会考虑如何让它成功,然后去做。另一方面,员工会寻找一些事情不工作的所有原因,并以此作为不去做的理由。它们很容易被发现。像这样的陈述;“我和我的配偶都有很高的薪水,很难放弃。”是一个明确的信号,表明你正在和一个员工打交道。如果你的组织旨在产生影响,企业家是最适合这样做的人。

不控制,激发

你要造船,不要鼓民采木,分工合作,发号施令。而是教他们向往浩瀚无边的大海。(德圣埃克苏佩里,2003 年)

试着找出如何通过设置适当的环境,而不是试图控制人们来获得好的结果。企业家在自由中茁壮成长,他们需要资源来取得成功,而组织的重点需要放在赋予这些人权力上。这与倾向于消耗资源、需要管理的员工形成对比。随着组织的成长,挑战也随之而来,流程被用来应对规模扩大带来的复杂性。这有削弱创新和驱逐企业家的趋势。为了应对这一点,关键是不要忽视雇佣合适的人,避免增加流程和新规则。以网飞休假政策为例;“没有政策或跟踪。网飞也没有着装规定,但没有人裸体上班。教训:你不需要事事都有政策。”(网飞,2009 年)

不要假装你知道未来

商业计划是江湖骗子的天意。正如约吉·贝拉曾经说过的:"很难做出预测,尤其是对未来的预测。"商业计划、商业案例之类的东西属于粪堆。现实世界太动态了,无论你认为它有多灵活,它都不符合你的普鲁克斯床。你的组织的成功将更多地依赖于它里面的人,而不是你那光鲜亮丽的文档。

不要上当规划谬误

在《思考的快慢》一书中,丹尼尔·卡内曼提供了一些有趣的例子来支持他所谓的“规划谬误”:

  • 1997 年拟建新苏格兰议会大厦 4000 万英镑。在 2004 年完成大约 4 . 31 亿英镑
  • 2005 年对 1969 年至 1998 年间全球铁路项目的研究:90%的情况下,预计使用该系统的乘客人数被高估。平均而言,规划者高估了 106%的人会使用新铁路项目。平均成本超支为 45%
  • 2002 年美国房主调查发现,改造厨房的成本:平均预期:18 658 美元,平均实现:38 769 美元

(卡尼曼,2013 年)

这个故事的寓意是对预计的时间框架、预算等持怀疑态度。为事情不按计划进行做好准备。

不要让生存取决于一个单一的结果,让选择成为你的朋友

我将在这里讲述泰勒斯和橄榄压榨机的故事。泰勒斯是一位哲学家,是讲希腊语的爱奥尼亚人,腓尼基血统,来自小亚细亚沿海城镇米利都。我们知道泰勒斯,部分是因为亚里士多德的著作。

用亚里士多德的话来说,这个故事如下:

“当他们责备他[泰勒斯]因为他的贫穷,好像哲学是没有用的,据说,通过他的研究观察到天体会有一个大的橄榄作物,他筹集了一点资本,而它仍然是冬天,支付存款在米利都和希俄斯所有的橄榄印刷机,便宜地雇用他们,因为没有人对他出价。当适当的时候来了,有一个突然要求印刷的热潮;然后,他以自己的条件把他们雇用出去,因此赚了一大笔钱,从而证明,如果哲学家愿意,他们很容易变得富有,但他们感兴趣的不是这个。”(莫里斯·恩格尔佩辛,2015 年)

亚里士多德对泰勒斯成功的推理是在泰勒斯卓越的知识中“…通过他对天体的研究观察到将会有一个巨大的橄榄收成,…

事实是,泰勒斯进入了有记录以来的第一个选项。你看,泰勒斯有权利,但没有义务,使用橄榄压榨机,以防需求激增。橄榄压榨商有义务,而不是权利。泰雷兹为这种特权付出了很小的代价,损失有限,可能的结果很大。(Taleb,2014 年)

不依赖直觉

这里我喜欢用蒙蒂霍尔问题作为例子。

让我们假装我们在一个游戏节目上。有三扇门,其中一扇门后是奖品,在这种情况下是一辆新车。其他每扇门后都有一只山羊。游戏节目主持人知道每扇门后是什么。游戏节目主持人让你选一扇门,你选了 2 号门。你选择后面有车的门的概率是 1/3。

在向你展示 2 号门后面是什么之前,游戏节目主持人打开了一扇你没有选择的门,3 号门,来展示一只山羊。

有两扇门尚未揭晓,一号门和你选择的二号门。现在知道了你所知道的,要不要换个选择?有关系吗?转换你的选择会提高你的胜算吗?看起来你赢的几率是 50% —两扇门选择其中之一。但是你错了。此时将您的选择切换到 1 号门将使您赢得汽车的机会加倍。

这是怎么回事?因为我们一开始有两只山羊,所以你的第一个选择,2 号门后面的更有可能是一只山羊——一开始选择一只山羊的概率是 2/3。通过在你没有选择的一扇门后展示一只山羊,如果你改变选择,游戏节目主持人会加倍你的获胜机会。

不要高估自己的衡量能力【1】

不是所有能算的都算,也不是所有能算的都算。(奥图尔,2010 年)

不允许决策者在没有切身利益的情况下做出决策

在信息不透明的情况下,为了对抗道德风险,应该使用博弈中的皮肤启发式。简而言之,任何参与可能对他人造成伤害的行为的人,即使是概率上的,都应该被要求暴露在某种伤害之下,而不考虑背景。(塔勒布、桑迪斯,2013 年)

不要在技术和商业之间选择,你需要两者

在《分析型领导者的秘密》一书中,韦恩·埃克森谈到了他所谓的紫色人。埃克森将它们描述为:

"…..生活在不同方法和观点交汇处的人拥有更广阔的视角。他们看到了别人忽略的联系和可能性。他们说多种语言,在不同的群体和规范之间优雅地移动。他们不断地翻译、综合和统一。因此,他们想象新的方法来解决老问题,他们重新发明旧的方法来应对新的挑战。他们是强大的变革推动者和价值创造者。

在分析的世界里,我把这些男人和女人称为“紫色的人”。它们在业务上不是“蓝色”的,在技术上也不是“红色”的,而是两者的混合,因此是紫色的。”(埃克尔森,2012 年)

纯技术人员并不完全了解要解决的业务问题,纯业务人员也不具备得出问题解决方案的技术专长。正是这些紫色的人给组织带来了最大的价值。

不要为了自己的创作而变得多情

大多数人使用统计数据的方式就像一个醉汉使用灯柱一样,更多的是为了支持而不是启发。(奥图尔,2014 年)

虽然主要是针对那些在量化金融社区,金融建模者的宣言可以扩展到一般建模领域以外,并与之相关:

建模者的希波克拉底誓言(德曼,威尔莫特,2009)

  • 我会记得世界不是我创造的,它不满足我的方程。
  • 虽然我会大胆地使用模型来评估价值,但我不会对数学印象太深。
  • 我永远不会为了优雅而牺牲现实,而不解释我这样做的原因。
  • 我也不会让使用我的模型的人对它的准确性感到虚假的安慰。相反,我将明确它的假设和疏漏。
  • 我明白我的工作可能会对社会和经济产生巨大影响,其中许多影响超出了我的理解。

附录:

[1]

弗兰克·奈特可能也在考虑之列:

经常从开尔文勋爵(Lord Kelvin)那里引用的一句话(尽管我认为这句话的实质要古老得多)“如果你不能衡量你的知识,那它就是贫乏和不令人满意的,”这句话应用在精神和社会科学中,是误导和有害的。这是另一种说法,即这些科学不是物理科学意义上的科学,也不能试图成为物理科学,否则就会丧失其应有的性质和功能。坚持具体的数量经济学意味着使用物理量的统计,其经济意义和重要性是不确定和可疑的。(即使是“小麦”也只有在经济条件下才是近似同质的。)类似的说法甚至更适用于其他社会科学。在这个领域,开尔文格言在实践中很大程度上意味着,“如果你不能度量,无论如何都要度量!”也就是说,一个人要么执行一些其他操作并将其称为测量,要么测量其他东西,而不是表面上正在讨论的东西,通常不是一种社会现象。称之为平均估计或猜测,测量似乎只是盗用了一个词的声望值。也可以指出,在人类利益和关系的领域里,我们许多最重要的知识本质上是非量化的,不可能不被破坏就以量化的形式存在。也许我们不“知道”我们的朋友真的是我们的朋友;在任何情况下,试图衡量他们的友谊几乎不会使知识更确定或更“令人满意”!

参考:

德圣埃克苏佩里(2003 年)。金沙的智慧。【书】。阿梅里奥有限公司[ISBN-13:978–0848825959]

德曼,e .威尔莫特,P. (2009 年)。金融建模者的宣言。[pdf]。检索自http://www . uio . no/studier/em ner/SV/oekonomi/econ 4135/h09/undervisningsmateriale/financialmodelersmastario . pdf

埃克尔森,W. (2012 年)。分析型领导者的秘密:来自信息业内人士的见解(第 1 版。).工艺出版有限责任公司。[国际标准书号 10: 1935504347]

卡尼曼博士(2013 年)。思维忽快忽慢。【书】。法勒,斯特劳斯和吉鲁。[ISBN-13:978–0374533557]

奈特,F. (1940)。经济学中的“真理是什么”?。[pdf]。芝加哥大学出版社。从 http://www.jstor.org/stable/1825908取回

网飞。(2009).自由和责任。[pdf]。从 http://www.slideshare.net/reed2001/culture-1798664取回

奥图尔(2010 年)。不是所有有价值的东西都可以被计算。【网站】。检索自http://quote investigator . com/2010/05/26/everything-counts-Einstein/

奥图尔(2014 年)。大多数人使用统计数据的方式就像一个醉汉使用灯柱一样,更多的是为了支持而不是启发。【网站】。从 http://quoteinvestigator.com/2014/01/15/stats-drunk/取回

南莫里斯·恩格尔佩辛(2015 年)。哲学研究:带阅读材料的文本。【书】。利特尔菲尔德出版社。[ISBN-13:978–1442242821]

北卡罗来纳州塔勒布(2014 年)。抗脆弱:从混乱中获得的东西。【书】。兰登书屋。[ISBN-13:978–0812979688]

北卡罗来纳州塔勒布,加利福尼亚州桑迪斯(2013 年)。游戏中的皮肤启发防止尾部事件。[pdf]]。从 http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2298292取回

塔勒布,n,戈尔茨坦。斯皮茨纳戈尔医学博士(2009 年)。管理者在风险管理中犯的六个错误。[pdf]。检索自https://HBR . org/2009/10/the-six-mistakes-executives-make-in-risk-management

特征重要性的一种新方法——Shapley 附加解释

原文:https://towardsdatascience.com/a-novel-approach-to-feature-importance-shapley-additive-explanations-d18af30fc21b?source=collection_archive---------2-----------------------

韦斯利·廷吉在 Unsplash 上拍摄的照片

最先进的功能重要性

如果你被困在付费墙后面,点击这里获取我的朋友链接并查看这篇文章。

机器学习的可解释性在这个领域是一个越来越重要的话题。解释的意思是用可理解的术语解释或陈述。在人工智能系统的背景下,可解释性是用可理解的术语解释或呈现给人类的能力。当投资面临风险时,机构更喜欢可以解释的模型,而不是可能给出相对更好准确性的模型。事实上,更好的说法是,当你处理现实世界的问题时,机器学习的可解释性成为衡量一个好模型的一部分。

不要做那种把机器学习和深度学习当成黑箱,认为叠加几层就会增加准确率的人。

在商业案例应用中,出于可解释性的考虑,公司通常会选择使用简单的线性模型,而不是复杂的非线性模型。当你建立一个模型时,你需要能够理解它是如何做出预测的。这有助于您确定模型何时会运行良好,何时不会运行良好(这就是它需要人工干预的地方)。通常,你可能需要向你的客户和投资者解释你的模型,尤其是当你用这个模型管理他们的资金的时候。它不仅止于管理投资,还远远不止于此——当你在医疗保健、安全、教育等领域使用人工智能时。基本上在 jupyter 笔记本之外的任何地方,模型的可解释性都成为一个重要的因素。在本文中,我将讨论机器学习可解释性的一个方面— 特征重要性。然而,在此期间,我将讨论一种更新颖的方法,称为 Shapley Additives 。我已经给出了相同的理论、数学和代码解释。

下面是这篇文章的不同部分。请随意跳到您需要访问的部分。

  1. 背景
  2. 理论解释
  3. 数学表达式
  4. 代码实现
  5. 可视化

背景

有许多不同的方法可以增加你对模型的理解,特性重要性是其中之一。要素重要性可帮助您估计数据的每个要素对模型预测的贡献程度。执行要素重要性测试后,您可以找出哪些要素对模型决策的影响最大。您可以通过移除对模型预测影响较小的功能,并专注于对更重要的功能进行改进来实现这一点。这可以显著提高模型性能。

有许多方法可以计算特征的重要性。使用statmodelsscikit-learn的一些基本方法已经在文章这里中讨论过。然而,很多人已经写了关于传统方法的文章,因此,我想讨论一种新的方法,叫做形状附加解释(ShAP)。这种方法被认为比传统的 sckit-learn 方法稍好,因为这些方法中的许多方法可能不一致,这意味着最重要的特征可能不总是被给予最高的特征重要性分数。一个例子是,在基于树的模型中,基于使用特征完成的分裂的级别,可能给两个同等重要的特征不同的分数。首先分割模型的特征可能被给予更高的重要性。这就是使用最新的特征归因方法 Shapley 附加解释的动机。

介绍

图片来自 Pixabay汉斯汉斯

让我们从一个例子开始,来获得这个方法背后的一些直觉。假设你是马克·库班,你拥有一支篮球队,比如达拉斯小牛队,你有三名球员——德克·诺维茨基(A),迈克尔·芬利(B),贾森·基德(C)。你想确定每个球员对球队最终得分的贡献,显然这并不意味着我们只是计算他们每个人得分的篮筐数,因为这在这里可能行得通,但从机器学习的角度来看却行不通。我们希望能够量化他们的存在对球队表现的影响,而不仅仅是计算每个球员可能得分的次数。第二个原因是,并不是所有人都打同一个位置。其中一名球员可能踢进攻位置,而另一名可能踢防守位置,我们也希望能够考虑到这一点。

一种方法是,你计算有和没有玩家 A 的团队绩效。玩家 A 的影响可以是有和没有玩家 A 的团队绩效之间的差异。

Impact of A = Team Performance with A - Team performance without A

这可以扩展到每个球员,我们可以单独计算他们的重要性。这是匀称的附加解释背后的主要直觉。对于每种功能组合,我们通过查看模型在有和没有该功能时的表现来评估模型的重要性。值得注意的是,Shapley Additive Explanations 为每个观察值计算局部特征重要性,这与 scikit-learn 中使用的计算全局特征重要性的方法不同。您可以理解某个特性的重要性在所有数据点上可能并不一致。因此,局部要素重要性计算每个数据点的每个要素的重要性。全局测量是指模型的所有特征的单一等级。在某些情况下,局部特征的重要性也变得相关,例如贷款申请,其中每个数据点都是一个人,以确保公平和公正。我还可以想到一个混合的例子,比如信用卡欺诈检测,每个人都有多次交易。虽然每个人都有不同的特征重要性等级,但是需要对所有事务进行全局测量,以检测事务中的异常值。我是从财务角度写这篇文章的,因为全球特性的重要性更相关。您可以通过聚合每个数据点的局部要素重要性来获得全局测量值。

注意:-这只是一个例子,比较玩家统计可能不是所有者的工作,但我喜欢鲨鱼池上的马克·库班,因此,这个例子。

这种方法根据联盟博弈理论计算出一种叫做 Shapley 值的东西。它是由 Lundberg,Scott M .和 Su-In Lee 在 2017 年首次提出的[1]。数据实例的特征值充当联盟中的参与者。Shapley 值告诉我们如何在特性之间公平地分配“支出”(=预测)。“玩家”可以是单个特征或一组特征。

如何计算一个特征的 Shapley 值?

该值是一个特性值在所有可能的特性组合中的平均边际贡献。让我们扩展前面的例子,看看球队在一个赛季的每场比赛中的得分。我们想知道球员 A 在一场比赛中对球队得分的贡献有多大。因此,当特征玩家 A 被添加到玩家 B 和玩家 c 的联盟时,我们将计算它的贡献。

注意:- 在这个实验中,我们需要在有和没有每个玩家的情况下完成所有的试验。我假设在一个赛季中会有一些比赛我们可以得到相关的数据,因为至少会有一场比赛每个球员都没有被选中,而其他两个球员却被选中了。其次,这只是一个例子,衡量标准可以是从积分差异到锦标赛排名的任何东西。为了便于解释,我只取了总分。

步骤 1: 没有玩家 A 的玩家 B 和玩家 C 的组合

在这种情况下,我们可以取玩家 B 和 C 比赛而玩家 A 没有比赛的所有比赛的平均分数。我们也可以随机抽取一个样本,但我认为平均值/中值是更好的衡量标准。假设平均分等于 65 分。

第二步:玩家 B、玩家 A 和玩家 C 的组合

在这一步中,我们将对球员 A、B 和 C 参加的所有比赛取平均值,假设该值等于 85 分。

因此,A 的贡献是 85–65 = 20 点。够直观了吧?如果你随机抽取了一个样本,那么你应该多次进行这个实验,并计算其平均值。

Shapley 值是所有可能联盟的所有边际贡献的平均值。计算时间随着特征的数量呈指数增长。保持计算时间可管理的一个解决方案是仅计算可能联盟的几个样本的贡献。[2]

Shapley 值的数学解释[3]

你可以看看这个笔记本更详细的解释。理论够了!让我们用一些代码来弄脏我们的手。

代码实现

首先导入必要的库。

import pandas as pd
import numpy as np
import shap
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from xgboost.sklearn import XGBRegressor
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
from sklearn import tree

import matplotlib.pyplot as plt
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')

读取数据并进行预处理。

我正在处理房价数据集,但是你可以对任何数据集使用这种方法。我不会在预处理和插补上花太多时间,但是强烈建议你这么做。

# Read the data 
data = pd.read_csv(‘data.csv’)# Remove features with high null values 
data.drop([‘PoolQC’, ‘MiscFeature’, ‘Fence’, ‘FireplaceQu’, 
‘LotFrontage’], inplace=True, axis=1)# Drop null values 
data.dropna(inplace=True)# Prepare X and Y 
X = pd.get_dummies(data)
X.drop([‘SalePrice’], inplace=True, axis=1)
y = data[‘SalePrice’]

拟合模型

下一步是在数据集上拟合模型。

model = XGBRegressor(n_estimators=1000, max_depth=10, learning_rate=0.001)# Fit the Model
model.fit(X, y)

Shapley 值特征重要性

对于这一节,我将使用shap库。这是一个非常强大的库,你应该看看他们不同的情节。首先将 JS 可视化代码加载到库中。

# load JS visualization code to notebook
shap.initjs()

使用 shap 解释模型的预测。收集讲解者和shap_values

explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X)

绘制我们的结果

力图

i = 4
shap.force_plot(explainer.expected_value, shap_values[i], features=X.iloc[i], feature_names=X.columns)

交互力图

上面的解释显示了将模型输出从基础值(我们传递的训练数据集的平均模型输出)推送到模型输出的每个功能。将预测值推高的要素显示为红色,将预测值推低的要素显示为蓝色。请注意,该图只能用于一次观察。对于这个例子,我采取了第四个观察。

概要图

为了了解哪些特征对模型最重要,我们可以绘制每个样本的每个特征的 SHAP 值。下图按所有样本的 SHAP 量值总和对要素进行排序,并使用 SHAP 值显示每个要素对模型输出的影响分布。颜色代表特征值(红色高,蓝色低)。

shap.summary_plot(shap_values, features=X, feature_names=X.columns)

每个特征的摘要图

汇总柱状图

我们也可以只取每个要素的 SHAP 值的平均绝对值来得到一个标准条形图(为多类输出生成堆积条形图):

shap.summary_plot(shap_values, features=X, feature_names=X.columns, plot_type=’bar’)

特征重要性条形图

结论

这些图告诉我们哪些特征对于模型来说是最重要的,因此,我们可以使我们的机器学习模型更具解释性和说明性。这是您数据科学之旅中非常重要的一步。

我希望你能从这篇文章中学到一些东西。期待听到你的评论。

参考

  1. 斯科特·m·伦德伯格和李秀英。"解释模型预测的统一方法."神经信息处理系统进展。2017.
  2. 克里斯托弗·莫尔纳尔。“可解释的机器学习。让黑盒模型变得可解释的指南”,2019。https://christophm.github.io/interpretable-ml-book/
  3. 《n 人游戏的价值》对博弈论的贡献 2.28(1953):307–317。

一种新颖的清理极脏非结构化文本的方法

原文:https://towardsdatascience.com/a-novel-solution-to-cleaning-extremely-dirty-unstructured-text-490d4ba934de?source=collection_archive---------50-----------------------

你好,我是尼克🎞 on Unsplash

经过整整两周的反复试验,几乎认为这是不可能的…

我做到了。

我设法把这个:

"这是一个很难解决的问题. "

变成这样:

“这是一个很难解决的问题”

我以为在和类似新加坡式英语甚至推特的人合作后,我已经见识了这一切。

但我从未想过我会遇到如此肮脏的非结构化文本数据。

我显然夸大了上面的例子,但问题归结为以下两点:

  • 拼写错误的检测和解决
  • 处理单词之间的随机空格

作为人类,我们可以很容易地将上面的陈述解读为:

“这是一个很难解决的问题”

然而,提出一种方法来解决这样一个数据问题被证明比预期更具挑战性。

在这篇文章中,我将介绍一个新颖的解决方案,它是我用来清理一个非常脏的非结构化文本数据集的。

以下是这些数据的大概情况:

肮脏的非结构化文本的例子

注意:这只是脏数据的一个例子,而不是实际的数据。

今天不会有太多的代码片段,但在这篇文章结束时,如果你曾经遇到过这种数据问题,你会对解决这种问题的方法有所了解。

数据质量问题 1:拼写错误的检测和解决

在我以前的一篇关于处理拼写错误的帖子中,我使用了单词向量,并进行了大量的翻译,以形成一个通用的翻译向量来处理拼写错误。

[## 使用广义翻译向量来处理拼写错误和不在词汇表中(OOV)的单词…

我的实验和结果是用一种新颖的方法来处理拼写错误和 OOV 单词。希望你能找到他们…

towardsdatascience.com](/using-a-generalised-translation-vector-for-handling-misspellings-and-out-of-vocabulary-oov-words-494cd142cd31)

在这篇文章中,我将依靠算法来处理拼写错误。

这一部分包括两个部分:

  1. 检测拼写错误的单词
  2. 解决拼写错误的单词

我使用了 SAS Viya 的开箱即用的拼写错误动作 tpSpell 来做这件事。

注意:SAS 与称为动作集的东西一起工作,动作集是 Python 包的同义词。在每个动作集中,有许多可以执行的动作

第 1 部分:检测拼写错误的单词

在这一步中,tpSpell 动作执行所谓的候选提取。

候选提取将单词分为两类:

  • 拼写正确的候选单词
  • 拼写错误的候选单词

在运行该过程之前,由预定的参数(“最小亲本”)来确定拼写正确的候选单词。

此参数指定一个术语要被视为拼写正确的候选单词,必须出现在多少个文档中。

所有拼写正确的候选单词都采用<term>-<role>-<parent>的形式。

例如,参考下面的图 1:

图 1 —拼写正确的候选示例(来源)

请注意,潜在的候选名称是如何将“Term”、“Role”和“Parent”列连接起来形成“algorithms-N-algorithm”的。

这是逻辑的分解。

  1. 如果潜在候选名称“algorithms-N-algorithm”在 4 个文档中出现 5 次,那么它出现的文档的数量等于 4。
  2. 如果称为“最小双亲”的预定参数被设置为 3,因为 4 比 3 大,所以单词“algorithms-N-algorithms”被添加到拼写正确的候选列表中。

那么,拼写错误的候选单词列表呢?那么我们如何创建这个表呢?

就像拼写正确的单词候选列表一样,还有另一个预先确定的参数要设置。

这次叫“最大子女”。

例如,请看下面的图 2:

图 2 —拼写错误的候选示例(来源

逻辑很简单。

如果“maximum children”参数设置为 3 并且出现类似“algoxxxthzs-N-algoxxxthzs”的潜在候选名称的文档数量小于 3,则“algoxxxthzs-N-algoxxxthzs”被添加到拼写错误的单词候选列表中。

对图 2 中指定的整个表重复这个逻辑。

现在我们已经得到了一个拼写正确的候选列表和一个拼写错误的单词候选列表,接下来是将拼写正确的单词分配给其各自的错误拼写的逻辑。

第 2 部分:拼写错误的解决方案

在该步骤中,执行候选比较以解决拼写错误。

该算法现在将对照拼写正确的列表中的所有单词来检查拼写错误的列表中的所有单词。

它将拼写错误的候选单词与每个拼写正确的候选单词进行比较,并计算它们之间的距离。

另一个被称为“最大拼写距离”的预定参数确定拼写错误的单词是否具有正确的拼写。

例如,如果单词“algoxxxthzs”是给定的拼写错误的单词并且单词“算法”是正确拼写的候选,那么计算出的“algoxxxthzs”和“算法”之间的距离将是 50。

如果“最大法术距离”设置为 20。由于 50 大于 20,正确拼写的候选“算法”现在被认为是单词“algoxxxthzs”的正确拼写。

您还可以在这里设置其他高级参数,以考虑多个术语,如“消防车”、“继续”或“加入”等。你可以在这里阅读文档。

虽然我在上面说得听起来很复杂…

不是。

下面是如何运行以上所有操作的方法。

proc cas;
 textParse.tpSpell /
  table={name="pos", caslib="public"}
  minParents=3
  maxChildren=6
  maxSpellDist=15
  casOut={name="tpSpell_Out", replace=true};
   run;
quit;

结果将是这样的:

图 3 —拼写错误的解析结果

我喜欢 SAS 编程的一点是,只用几行代码就能轻松利用复杂的算法。

是的,Python 包做同样的事情,但是有时,这些包没有 SAS 高级。

一个很好的例子是 SAS 如何优化深度学习超参数和层内参数。有趣的是,在 SAS 中进行超参数调优真的很容易。

SAS 将拉丁超立方体与用超带方法优化的遗传算法相结合,以说明资源利用率。此外,一切都是自动多线程的。

用 Python 编写 SAS 的现成代码肯定会花费更多的时间和精力,更不用说如何用 Python 分配处理、计算资源分配和利用所需的知识了——我认为大多数人对此并不熟悉。

数据质量问题 2:处理随机空白

这个问题确实让我测试了多种方法。所有这些都表现不好,除了我现在要讲的方法。

为了恢复你的记忆,你的问题就像这样

上面有几个值得指出的数据质量问题:

  1. 单词之间的空格,如“probl em”
  2. 缺少字符,即“锁定”
  3. 交换字符,即“thsi”
  4. 双重字符,即“你”
  5. 问题的组合,即“m emry”——1 和 2 的组合。

我必须找到一种方法来解决单词之间的空格,同时解决拼写错误(数字 2、3 和 4)。

幸运的是,处理拼写错误相对容易,正如我在上面用 tpSpell 展示的那样。

但是问题的组合带来了复杂性(第五点)。

对于像这样的组合问题,我首先需要在应用拼写错误解决方案之前解决空白。

在思考这项工作的最佳解决方案时,我从编码器-解码器网络的工作方式中获得了灵感。

我能以某种方式“编码”句子,然后“解码”它们吗?

显然我在这里用词不当。我说的“编码”实际上是指删除单词间的所有空白。像这样:

torefreshyyourmerytheekedlikethsi

通过“解码”,我的意思是在解决拼写错误后,将单词重新分解成它们各自的单词:

提醒你一下,问题是这样的

“解码”的问题第 1 部分

我必须解决的最大问题之一是,一旦字符串被“编码”,何时插入空格。

就拿“ torefresh 这个词来说吧。

如何知道在“和“刷新”之间插入一个空格?为什么不是“”、“ re ”和“ fresh ”?

下面是我是如何做到的,以及我的 SAS 脚本的逻辑。

解码的单词基于单词的最长匹配

例如,如果我看到单词“ helloworld ”,我将首先在预定义的潜在候选列表中查找单词“ hell ”。即字典表

直到下一个角色“ o 出现,既然“hell+o”=“hello”,“ hello ”就成了比较好的潜在候选人。

我放弃单词“ hell ”作为主要候选,保留单词“ hello ”作为新的主要候选。

随着下一个字符被读入,"hello+w" = "hellow",由于" hellow "在潜在候选列表中不是一个合适的单词,所以最好的候选是" hello "。

一旦这些检查完成,我就在" hello "后面添加一个空格,并继续上面的逻辑,用于" w "、" o "、" r "、" l "和" d "直到我得到" hello world "

那么这个潜在候选列表是什么,我是怎么得到这本字典的?

这是我根据前面的 tpSpell 操作生成的拼写正确的单词列表创建的字典。

也就是说,所有拼写正确的单词都放在这个字典表中,以便我在“解码”每个字符串时查找。

“解码”的问题第 2 部分

要让“解码器”工作,还有其他问题需要解决。

也就是说,我必须删除停用词,所有形式的标点符号,小写所有单词,只保留父术语。

为什么?

因为如果我不这么做,就会有很多问题浮出水面。

以这句话为例:

《丛书》

在“编码”之后,它将是:

《系列丛书》

回想一下,我创建的算法在“解码”过程中采用了字典中的最长匹配

如果我保留所有停止字,“解码器”会将第一个字解析为“这些”,而不是“这些”。

正因为如此,单词"series中的下一个字符" ries "将不再是我的字典中的一个单词,并将被丢弃。

这意味着“解码的”字符串将会以“这些书”结束,这显然是不正确的。

影响“解码器”的另一个复杂因素如下所示:

“自行车运动”→“自行车竞技”→“自行车港口”(错误)

为了解决这个问题,我只在字典表中保留了父术语

例子 1:自行车 s →自行车

示例 2:运动 s →运动

通过只查看父术语,我的输出如下所示:

“自行车运动”→“自行车运动”→“自行车运动”(正确)

因为“自行车 s ”已经不在我的字典里而“自行车在,解码器解析正确,没有输出“自行车端口”。

所以你有它!

我自己的“编码器-解码器”方法来清理非常肮脏的非结构化文本!😉

这不是一个完美的解决方案,但它确实足够让我开始我的下游 NLP 任务。

亲眼目睹这一切!

为了向您展示运行代码后的样子,我对一个存在模拟数据质量问题的图书评论语料库运行了代码。

下面是示例和流程的样子:

图 4 —数据清理过程正在进行

结尾注释

嗯,那就这样吧!

我希望你觉得这篇文章很有见地!😃

尽管花了将近 2 周的时间尝试了许多方法,但我从中获得了巨大的乐趣!

下次见,再见!

领英简介:蒂莫西·谭

大规模超参数优化新手指南

原文:https://towardsdatascience.com/a-novices-guide-to-hyperparameter-optimization-at-scale-bfb4e5047150?source=collection_archive---------56-----------------------

可扩展 HPO 策略综述与研究

作者图片

尽管机器学习(ML)取得了巨大的成功,但现代算法仍然依赖于各种免费的不可训练的超参数。最终,我们选择质量超参数的能力决定了给定模型的性能。在过去,甚至现在,超参数都是通过反复试验手动选择的。整个领域都致力于改进这一选择过程;这被称为超参数优化(HPO)。本质上,HPO 需要测试许多不同的超参数配置,因此可以从大规模并行资源中受益匪浅,如我们正在国家能源研究科学计算中心( NERSC )建造的佩尔穆特系统。当我们为 Perlmutter 做准备时,我们希望探索存在于感兴趣的模型上的众多 HPO 框架和策略。本文就是这种探索的产物,旨在根据我最近的经验和结果,介绍 HPO 的方法,并提供大规模运行 HPO 的指导。

免责声明;这篇文章包含了大量关于 HPO 的一般非软件特定信息,但是对适用于我们在 NERSC 的系统的自由开源软件有偏见。

在本文中,我们将涵盖…

带光线调节的可伸缩 HPO

能够利用现代计算资源的能力来大规模运行 HPO 对于高效搜索超参数空间非常重要,尤其是在深度学习(DL)时代,神经网络的规模不断增加。对我们所有人来说幸运的是, Ray Tune 的人让可扩展 HPO 变得简单了。下图是在 NERSC 上运行光线调节的一般程序。 Ray Tune 是基于 Ray 构建的分布式 HPO 的开源 python 库。Ray Tune 的一些亮点:

  • 支持任何 ML 框架
  • 根据可用资源在内部处理作业调度
  • 集成外部优化包(如 Ax、蜻蜓、HyperOpt、SigOpt)
  • 实施最先进的调度程序(例如 ASHA、AHB、PBT)

我很喜欢使用 Ray Tune ,但是如果你选择不同的 HPO 框架,不用担心,本文中仍然有大量的通用信息。

作者图片

调度程序与搜索算法

关于 HPO 策略,我想指出的第一个区别是调度程序和搜索算法之间的区别。搜索算法控制超参数空间的采样和优化方式(如随机搜索)。从实践的角度来看,搜索算法提供了一种选择超参数配置(即试验)进行测试的机制。HPO 总是需要一个搜索算法。或者,调度程序通过提前终止没有希望的尝试来提高 HPO 的整体效率。例如,如果我使用随机搜索,一些试验预计会表现不佳,因此能够提前终止这些试验就好了,这样可以节省宝贵的计算资源。这就是调度程序的工作。对于 HPO 来说,调度程序并不是必需的,但是它们可以极大地提高性能。

下面是我在本文中研究的调度程序和搜索算法的简要描述和参考。

异步连续减半算法(ASHA —调度程序)

首先,我想定义连续减半算法(SHA),而不是我自己做,我真的很喜欢这篇论文中给出的定义——如果你感兴趣,他们也有 SHA 和 ASHA 的伪代码。

SHA 背后的思想很简单:为每个配置分配一个小的预算,评估所有配置并保留前 1/η,将每个配置的预算增加η倍,并重复直到达到每个配置的最大预算 R。

作者图片— 改编自汽车帖子

SHA 不能很好地并行化,因为在选择前 1/η之前,需要对所有配置进行短时间评估。这在每个梯级处产生了瓶颈(每个连续的减半被称为一个梯级)。ASHA 将试验推进和梯级完成分离,这样试验可以在任何给定时间推进到下一个梯级。如果一个试用无法升级,可以将其他试用添加到基本等级,这样就可以进行更多的升级。

SHA 和 ASHA 的一个主要假设是,如果一项试验在最初的短时间间隔内表现良好,它将在更长的时间间隔内表现良好。这种假设可以打破的一个经典例子是调整学习率。较大的学习速率可能在短时间内胜过较小的学习速率,导致较小的学习速率试验被错误地终止。实际上,我真的不确定这有多重要。

异步超高频带(AHB —调度程序)

Hyperband (HB)是一个调度器,旨在减轻 SHA 对初始性能的偏见。HB 本质上以各种减半率在 SHA 上循环,试图平衡提前终止与每次试验提供更多资源,而不管初始性能如何。SHA 的每个循环都被视为一个支架,它可以有多个梯级。见下图。除了在 ASHA 上空盘旋之外,AHB 与 HB 完全相同。射线调谐中使用的 AHB 和 ASHA 实现在本论文中描述。

作者图片

基于人群的培训(PBT —混合)

我称 PBT 为混合型,因为它同时具有调度器和搜索算法的特点。它也可以作为 HPO 战略和教练的功能。更多的是,不是所有的超参数都在同一个部分。在高层次上,PBT 类似于遗传算法。存在工人群体,其中每个工人被分配超参数的随机配置(试验),并且在设定的间隔超参数配置被群体中表现更好的工人替换(开发)和随机扰动(探索)。用户可以设置开发和探索之间的平衡。这里有一些资源可以让你了解更多,博客论文

作者图片

随机搜索(RS-搜索算法)

当感兴趣的超参数空间相当大,对于网格搜索来说太大时,默认算法是随机搜索。听起来确实如此,超参数配置或试验是从搜索空间中随机选择的。如果有足够计算时间,RS 工作得相当好。

贝叶斯优化(BO-搜索算法)

BO 提供了一种算法方法来确定最佳超参数,而不是随机搜索。因为目标函数在 HPO 是未知的,所以像 BO 这样的黑盒优化器是必要的。在阿伯替代模型中,在这种情况下,目标函数和采集函数用于采样新点或新的超参数配置。高斯过程通常用作 HPO 业务对象的替代模型。理想情况下,BO 可以比随机搜索更有效地收敛到最优超参数。

并非所有的超参数都可以被同等对待

在 ML 中有两种主要类型的超参数,它们决定了什么样的 HPO 策略是可能的。

模型超参数:建立模型架构

  • 卷积层数
  • 完全连接的层数
  • 等等。

算法超参数:参与学习过程

  • 学习率
  • 批量
  • 动力
  • 等等。

重要的一点是,并非所有的 HPO 策略都能处理模型和算法超参数。PBT 就是一个很好的例子。PBT 被设计成从群体中的其他高绩效工人进化和继承超参数;然而,如果员工有不同的网络架构,我不清楚这到底是如何工作的。使用 PBT 可能有一种方法可以做到这一点,但它不是标准的,并且不能与 Ray Tune 一起开箱即用。

求解时间研究

为了比较不同的 HPO 策略,我决定保持简单,专注于平均解决时间,这是一个相对简单易懂的指标。对于我的结果,有几点需要注意的地方:

  1. 我是带着一个特定的模型和问题做这项工作的(下面会有更多),所以我不期望这些结果是完全通用的。
  2. 在各种 HPO 策略中,有许多任意的选择可能会改变结果。

调查 HPO 战略

  • 随机搜索(RS) —无调度程序的搜索算法
  • 异步连续减半算法/随机搜索(ASHA/RS)—调度器和搜索算法
  • 异步超波段/随机搜索(AHB/遥感)—调度程序和搜索算法
  • 异步连续减半算法/贝叶斯优化(ASHA/BO)—调度器和搜索算法

模型细节

我感兴趣的优化超参数的模型是在催化领域中用于预测吸附能的图形神经网络。具体细节可以在这里找到

超参数优化

我检查了六个超参数,如下所示:

  • 学习率
  • 批量
  • 原子嵌入尺寸
  • 图形卷积层数
  • 完全连接的特征尺寸
  • 完全连接的层数

专业提示:在决定要搜索的超参数空间的大小时,要考虑内存使用情况。在调整网络架构和批量大小时,我在 NERSC 的 16GB GPUs 上遇到了内存问题。

探索的问题

  1. 调度程序的影响是什么?
  2. 一个复杂的搜索算法能在多大程度上改善 HPO?

我想研究的第一个问题是使用调度程序的影响。为了解决这个问题,我比较了 ASHA/遥感、AHB/遥感和遥感使用相同计算资源的求解时间(4 个柯里 GPU 节点 8 小时)。除了 ASHA 和 AHB 调度程序之外,所有三种策略都使用相同的搜索算法。我使用的符号是调度/搜索算法。

除了调度程序,我很好奇一个“更智能”的搜索算法,比如 BO,能在多大程度上提高 HPO 的性能。为了探索这个问题,我比较了 ASHA/遥感和 ASHA/BO 使用相同计算资源的求解时间(4 小时 4 个柯里 GPU 节点)。

结果和讨论

给定相同计算资源的情况下,比较 ASHA/遥感、AHB/遥感和遥感的平均求解时间图

ASHA/遥感明显优于 AHB/遥感和遥感,在较短的时间内达到较低的平均测试 MAE。与 RS 相比,ASHA/RS 将解决问题的时间缩短了至少 5 倍。我说至少 5 倍,因为 RS 没有在 8 小时的限制内收敛到测试 MAE 的下限。此外,更多的 ASHA/遥感试验接近平均值,导致较小的标准偏差。在所有情况下,前 6 个试验是时间平均值。我怀疑 ASHA/斯普斯卡共和国的表现主要是因为完成的审判数量。ASHA RS 完成了 AHB RS 将近 2 倍的试验,超过 RS 的 8 倍。完成的试验数量可以在右上角看到。我还应该提到,由于我所做的检查点的数量,that 斯普斯卡共和国和 AHB/斯普斯卡共和国的审判数量没有达到上限。最小检查点对于基于 SHA 的 HPO 策略的性能至关重要。下面的 that 遥感实验中使用较少检查点完成的试验数量说明了这一点——在一半的时间内完成相同数量的试验。与 RS 相比,减少的检查点将 ASHA/RS 的求解时间提高了大约 10 倍!

给出相同计算资源的情况下,比较 ASHA/RS 和 ASHA/BO 的平均求解时间图

从上图可以看出,对于我的特定型号,添加业务对象平均没有任何好处。我的假设是,我试图优化的超参数曲面有一堆局部最小值(想想鸡蛋纸盒),没有明显的全局最小值,这会降低 BO 的好处。我可以看到 BO 工作良好的情况是具有更好定义的全局最小值的大型超参数搜索空间——不是说你可以先验地知道这个。总的来说,我认为 HPO 的一个好方法是按需构建复杂性。关于 BO 的最后一个注意事项,虽然使用 BO 并没有得到平均的改善,但我发现的最佳试验是使用 ASHA/BO。因此,如果我必须选择一种超参数配置,我会选择这种配置。

ASHA/RS 和 ASHA/BO 曲线之间的时间延迟是可能的,因为在对新的超参数配置进行采样之前,BO 中使用的采集函数需要以一定量的数据为条件。

基于 PBT 的最优调度

PBT 的一个很好的特性是能够开发一个理想的调度程序。例如,我可以在整个训练过程中确定理想的学习速度,这通常非常重要。在我的例子中,我想要一个超参数配置和一个学习率调度器,我可以用它来反复训练我的模型。大多数 ML 框架包括学习速率调度器(例如,多步、平台上减少、指数衰减等。)随着训练的进行降低学习率。因此,可以使用 PBT 开发定制的学习速率调度器,并将其合并到给定的 ML 框架中用于后续训练。

或者,如果您的应用不需要重复训练,PBT 可以直接用作训练程序,并且可以同时为所有算法超参数开发理想的时间表。

就实际时间而言,使用 PBT 进行培训非常有效,事实上,它使用的时间与您的正常培训程序大致相同,但总计算时间增加了,因为需要多个工作人员,可能需要 16-32 个 GPU。在 Ray Tune 中,如果工作线程的数量超过资源大小,也可以对工作线程进行时间复用。

最佳学习率——结果和讨论

我想用 PBT 进行实验,并为我的模型找到一个学习率时间表(如上所述)。这是结果。

上面的图显示了群体中最佳试验的试验 MAE。在试验 MAE 中有一些跳跃,可能是尝试了随机扰动,由于没有改进,扰动最终被逆转。下方的图显示了作为训练迭代函数的学习率。看起来我的理想学习速度可以合理地用多步计划程序来模拟。

选择 HPO 策略的备忘单

选择 HPO 策略实际上取决于您的特定应用。对于我感兴趣的许多化学和材料科学应用,达到 85%的合理的超参数就足够了。或者,你们中的一些人可能对给定模型的最后一点性能感兴趣。没有一个放之四海而皆准的解决方案,但是我已经整理了一个小备忘单来帮助想法流动。

作者图片

技术提示

射线调谐

Ray Tune 非常用户友好,当设置它来运行您的模型时,您只需要考虑一些事情(我在这里不打算深入讨论,因为 Ray Tune 的文档示例非常棒):1 .定义一个可训练的 API,基于函数或类——我推荐类选项,因为它允许你做更多的事情。通过tune.run()编写运行 Tune 的脚本

一般提示

  • 检查以确保你的模型被放在正确的设备上,这听起来很傻,但很值得。如果您使用的是类 API,那么在您的_setup函数中放一个 print 语句来进行双重检查
  • 射线调有一堆方便的函数(例如tune.uniform)来生成随机分布

**Tune.run()** 性能标志

  • checkpoint_at_end=False默认值为 False,不管其他检查点设置如何,我都会让它保持原样。真,不应该与基于 SHA 的策略一起使用
  • 这可以提高性能,但可能作用有限——这取决于检查点的频率
  • 我喜欢这个标志,因为它会在试验失败后立即终止试验,否则试验会经历所有的训练迭代,每次迭代都会失败
  • reuse_actors=True这个标志可以提高 ASHA 和 PBT 的性能,但是它要求你在你的可训练类中增加一个reset_config功能。在某种程度上,此标志可以节省资源,因为它不会在每次旧的试验终止和新的试验开始时重新加载数据集。

蜻蜓—博

我喜欢贝叶斯优化的蜻蜓,因为它能够处理离散和连续变量。许多业务对象包只能处理连续变量,你必须想办法解决这个问题。然而,我确实发现实际定义超参数空间有点棘手。下面是我用来设置蜻蜓波使用射线调的代码片段。

Slurm —工作管理

对于那些使用 Slurm 的人来说,就像我们在 NERSC 所做的一样,这里的是支持使用 Ray Tune 的脚本。可以直接复制start-head.shstart-worker.sh文件;只有提交脚本需要少量的修改,以便在资源和选择的环境中执行您的代码。如果你遇到工作节点不能启动的问题,并且你看到这样的错误ValueError: The argument None must be a bytes object在启动这个线上的头节点后延长睡眠时间。这不是一个 bug——head 节点需要设置一个变量,有时需要一段时间。

TensorBoard —测井/可视化

默认情况下,光线调整日志使用 TensorBoard (TB)。关于 HPO 肺结核和雷的一些想法:

  • TB 允许您轻松过滤您的结果,这在您使用 ASHA 运行 1000 次试验时非常重要
  • 使用 HParams 仪表盘实现良好的可视化
  • TB 在 Ray Tune 中与基于 SHA 的策略配合得很好,我唯一的抱怨是与 PBT 的集成不太好

对于 NERSC 用户来说,这里的是我通常运行 TB 的方式。一个缺点是一次只能打开一个 TB 客户端。

权重和偏差—记录/可视化

W&B 有一个与 Ray Tune 集成的记录器,我在测试的模型中使用了它。显然存在很大的潜力,总的来说我喜欢 W & B 平台,但当时(2020 年 3 月/4 月)我很难用 W & B 记录大规模的 HPO 活动。我相信一些更新/升级正在进行中。

关键要点

调查的结果

  1. 与单独的随机搜索相比,ASHA 调度程序将我的模型的求解时间提高了至少 10 倍
  2. BO 可能不总是能提高平均 HPO 性能,但是我能够用 ASHA/BO 找到我的最佳超参数配置
  3. 使用 PBT,我找到了我的最佳学习速率,它可以用多步调度器合理地建模

结论

  1. 光线调节是一个简单和可伸缩的 HPO 框架
  2. 使用调度程序来提高 HPO 效率至关重要
  3. BO 等更复杂的搜索算法可能会带来一些好处,但并不总是值得投资
  4. 如果模型不需要经常保留,PBT 对于开发理想的调度器和训练非常有用
  5. 对于 HPO,没有放之四海而皆准的解决办法。简单起步,按需构建复杂性—ASHA/遥感是一种合理的默认战略

感谢:我要感谢扎卡里·乌里西(CMU)穆斯塔法·穆斯塔法 (NERSC)和理查德·廖(雷·调)让这部作品成为可能。

原载于 2020 年 8 月 31 日https://wood-b . github . io

计算机视觉一站式指南—第 1 部分

原文:https://towardsdatascience.com/a-one-stop-guide-to-computer-vision-96f72025f82d?source=collection_archive---------50-----------------------

计算机视觉与 GluonCV 模型动物园

弗拉德·希利塔努在 Unsplash 上拍摄的照片

第二部分:设计你自己的神经网络

介绍

对于我们人类来说,图像很容易理解。我们能够识别一幅图像是一只狗还是一只猫,一幅图像是否有一个红球,或者计算一幅图像中的人数。这些任务对计算机来说并不容易。

什么是计算机视觉?

计算机视觉允许你的计算机理解图像。但是怎么做呢?

简单来说:

  1. 你所有的图像都是由像素组成的。每个像素都有一个 RGB 值,分别代表红、蓝、绿。这三种颜色的组合可以创造出任何想象得到的颜色。
  2. 您的计算机将这些像素“视为”数字。数字对计算机来说更容易理解。
  3. 这些数字的组合形成了您的图像,因此,您的计算机现在能够“看到”您的图像。
  4. 一个图像带有一个标签,以表明这个图像是什么(狗,猫,球,树,船等)。).
  5. 类似于你教婴儿/狗的方法,你给电脑看一个图像,告诉他这是一只狗。你给电脑看另一张图片,告诉他这是一只猫。
  6. 步骤 5 被重复数百万/数十亿次。
  7. 下次当你问计算机什么是图像时,它会很有把握地给你一个答案(比如 80%是船,10%是人,10%是鸟)。

控制台上的 deadbuiltin 拍摄的照片-漫画

计算机视觉有 4 个主要任务:

  1. 图像分类-图像分类允许您对图像进行分类,是狗、猫、梨还是苹果。
  2. 对象检测—对象检测允许您在图像中检测一个以上的对象。将绘制一个边界框来封装检测到的对象。
  3. 语义分割——语义分割允许您将图像中的对象分为不同的类别,如动物、环境、食物。
  4. 实例分割-实例分割是语义分割的一个更复杂的版本,在每个类别中,实例分割允许您区分同一类别下的不同对象(例如,动物-蛇、兔子、狗)。

截图来自 GluonCV

为什么我们不对每个任务都使用实例分段呢?

每个模型都有自己的权衡。越复杂,越慢,越贵。越简单越快越便宜。如果您只是希望程序检测图像中是否有球,那么使用最昂贵的实例分割是没有意义的。

简介:GluonCV

为了实用从零开始开发自己的计算机视觉模型是疯狂的。当您可以使用研究人员预先训练的模型获得更好的结果时,为什么要花费大量的时间和金钱来构建您自己的模型呢?

通过卡通库存迈克·鲍德温致谢

MXNet 是一个开源的深度学习框架。MXNet 提供了一个名为 Gluon 的高级 API。Gluon 为几个任务提供了几个工具包:

  1. Glu oncv——计算机视觉
  2. gluonlp—用于自然语言处理
  3. GluonTS —用于时间序列处理

根据 GluonCV 的说法:

G luonCV 提供计算机视觉领域最先进(SOTA)深度学习算法的实现。它旨在帮助工程师、研究人员和学生快速制作产品原型、验证新想法和学习计算机视觉。

GluonCV 拥有大量模型,这些模型已经由知名机构和研究人员进行了微调,这些机构和研究人员使用难以想象的计算能力和时间在数年内收集了大量数据。所有预先训练好的模型都被安置在模型动物园的 GluonCV 里。

在这篇文章之后,你应该能够用gluo cv 和 MXNet 完成所有 4 个计算机视觉任务。

设置 MXNet 和 GluonCV

整篇文章只需要你下载 2 个包——MXNet 和 GluonCV。您可以使用以下命令来完成此操作:

pip install mxnet
pip install gluoncv

如果您想利用您的 CPU/GPU 或 TPU 进行处理,您只需更改安装命令:

截图来自 MXNet

在我们开始之前,记得导入已安装的包(如果您还没有这样做,请下载 numpy 和 matplotlib):

import mxnet as mx
import gluoncv as gcv
import numpy as np
import matplotlib.pyplot as plt

图像分类

点击这里查看文档。有许多模型可用于每个 CV 任务。这些模型中的每一个都用不同数量的图像和标签来训练,因此将具有不同的超参数集。例如,ImageNet22k 在超过 1400 万张图像上进行训练,可以预测超过 22,000 个类别。下图显示了每个型号的精度和速度之间的权衡。自然,精度越高,速度就会越低。

截图来自 GluonCV

对图像进行分类只需 4 个步骤:

1.下载图像

image_url = "[https://raw.githubusercontent.com/dmlc/web-data/master/gluoncv/classification/mt_baker.jpg](https://raw.githubusercontent.com/dmlc/web-data/master/gluoncv/classification/mt_baker.jpg)"image_filepath = 'mt_baker.jpg'
gcv.utils.download(url=image_url,path = image_filepath)

你可以使用任何你想要的图片,只需简单地编辑链接。我们将使用贝克山的图像。接下来,我们将可视化图像并探索图像:

image = mx.image.imread('mt_baker.jpg')print("shape:",image.shape)
print("data type:",image.dtype)
print("min value:",image.min().asscalar())
print("max value:",image.max().asscalar())

第一行将我们的图像设置为一个变量。接下来的 4 行打印出图像的细节,结果如下:

形状是三维的(HCW ),因为它由高度、宽度和通道组成。高度和宽度表示图像的垂直和水平长度,通道表示图像的深度。由于图像由 RGB 颜色组成,因此深度仅为 3:

来源: packtpub

数据类型是用整数填充的 numpy 数组,最小值为 0,最大值为 255 。最后,让我们想象一下这幅图像:

plt.imshow(image.asnumpy())

2.转换数据

GluonCV 要求您的图像符合以下标准:

  1. 数据的形式必须是“批次数量、通道、高度、宽度(NCHW)”而不是“HWC”。通常,我们不仅仅用一幅图像来训练我们模型,我们用成千上万幅图像来训练它们。我们也不会一张一张地传入图像。我们一批一批地传入图像然后在 NCHW 的 N 部分显示每批图像的数量。
  2. 数据类型必须是 float 的 numpy 数组,而不是整数。
  3. 图像值必须归一化,以 0 为中心,标准偏差为 1。

不用担心,所有这些步骤都可以通过一个命令完成:

image = gcv.data.transforms.presets.imagenet.transform_eval(image)print("shape:",image.shape)
print("data type:",image.dtype)
print("min value:",image.min().asscalar())
print("max value:",image.max().asscalar())

3.准备模型

我们将使用 ResNet 50 型号。我们将使用模型的预训练版本。

network = gcv.model_zoo.get_model("resnet50_v1d", pretrained=True)

要查找您可以使用的所有型号的列表,只需键入:

gcv.model_zoo.get_model_list()

所有模型都将下载到您的本地 mxnet 缓存中。您可以在此查看尺寸:

!ls -sh C:/Users/<your username>/.mxnet/models

4.给我们的形象分类

预测只需一行代码即可完成:

prediction = network(image)

由于我们只输入了 1 幅图像,我们将检索结果的第一个索引:

prediction = prediction[0]

预测存储该图像所属的每个类别的原始概率。由于 ResNet 50 能够预测 1000 个类,因此预测的长度将是 1000。

您可以检索 ResNet 50 模型能够预测的所有类的列表,应该有 1000 个:

预测存储模型输出的原始概率。解释它们是没有意义的,因为有些概率是负的。因此,我们将使用一个 softmax 函数来转换所有的概率,使其介于 0 和 1 之间:

probability = mx.nd.softmax(prediction)

现在,让我们检索前 5 个预测类:

k = 5
topk_indices = mx.nd.topk(probability, k=5)for i in range(k):
    class_index = topk_indices[i].astype('int').asscalar()
    class_label = network.classes[class_index]
    class_probability = probability[class_index]
    print("#{} {} ({:0.3}%)".format(i+1,class_label,class_probability.asscalar()*100))

结果是这样的:

GluonCV 有 84.1%的把握预测这是一张火山的图像。因为 ResNet 50 没有专门针对贝克山的类,所以火山是我们能得到的最接近的了。

目标检测

点击这里查看文档。你会发现这部分和图像分类很像。然而,不使用 ResNet 50,我们将使用 YOLO V3 ,这是一个非常快速的对象检测模型。

1.下载图像

让我们使用另一个包含几个对象的图像:

image_url = "[https://raw.githubusercontent.com/zhreshold/mxnet-ssd/master/data/demo/dog.jpg](https://raw.githubusercontent.com/zhreshold/mxnet-ssd/master/data/demo/dog.jpg)"image_filepath = 'dog.jpg'
gcv.utils.download(url=image_url,path = image_filepath)

我们来探究一下数据。这一部分与您之前所做的非常相似。

image = mx.image.imread(image_filepath)print("shape:",image.shape)
print("data type:",image.dtype)
print("min value:",image.min().asscalar())
print("max value:",image.max().asscalar())plt.imshow(image.asnumpy())

2.转换数据

由于我们使用的是另一种模型,我们必须将数据转换成另一种适合 YOLO V3 的格式。不用担心,这也可以用一行代码完成:

image, chw_image = gcv.data.transforms.presets.yolo.transform_test(image, short=512)

我们现在有两个图像,而不是一个变换后的图像,即图像chw_image。图像由您的原始图像组成,而 chw_image c 由您的转换图像组成。变量 short=512 用于指示图像的宽度,同时仍然保持纵横比。

print("shape:",image.shape)
print("data type:",image.dtype)
print("min value:",image.min().asscalar())
print("max value:",image.max().asscalar())

3.准备模型

这是我们将使用的模型:

network = gcv.model_zoo.get_model('yolo3_darknet53_coco',pretrained=True)

4.打开结果

然而,这一次,我们的预测返回给我们 3 个项目:

prediction = network(image)
for index,array in enumerate(prediction):
    print('#{} shape: {}'.format(index+1,array.shape))

  • 第一项是类别标签。它告诉我们检测到的类的索引。请记住,您可以使用 network.classes 获得类名。
  • 第二项是预测概率。
  • 第三个项目是一个边界框数组。因为你需要 4 个角来组成一个盒子,所以会有一个 4 坐标的列表。

此外,还有一些细微的区别:

  1. 您不必对概率应用 softmax 函数。
  2. 类别和概率已经为您按降序排序。

让我们看一些例子:

prediction = [array[0] for array in prediction] #since we only input 1 image
class_indices, probabilities, bounding_boxes = prediction #unpacking#Let's  list the top 10 items
k = 10
print(class_indices[:k])
print(probabilities[:k])
print(bounding_boxes[:k])

十大类指数

十大可能性

边界框的坐标

注意“-1”是一个特殊的类,这意味着没有检测到任何对象。

5.在对象周围绘制方框

现在我们有了坐标,让我们给我们的图像加标签吧!

gcv.utils.viz.plot_bbox(chw_image,
                       bounding_boxes,
                       probabilities,
                       class_indices,
                       class_names=network.classes)

图象分割法

点击这里查看文档。

语义分割

语义分割旨在对图像中的每个像素进行分类。它将在进行分段级预测之前查看图像的完整上下文。之后,该模型将使用不同的颜色来覆盖图像的所有像素,以将它们分类。在本节中,背景类被标记为-1。

本节将使用 FCN ResNet ADE,这是一个具有 ResNet 架构的全连接神经网络,在 ADE20K 数据集上进行训练。

1.下载图像

该部分与物体检测完全相同。如果你愿意,可以跳过这一步

image_url = "[https://raw.githubusercontent.com/zhreshold/mxnet-ssd/master/data/demo/dog.jpg](https://raw.githubusercontent.com/zhreshold/mxnet-ssd/master/data/demo/dog.jpg)"image_filepath = 'dog.jpg'
gcv.utils.download(url=image_url,path = image_filepath)

2.转换数据

这一部分没有一行代码。您必须定义自己的函数来转换数据:

from mxnet.gluon.data.vision import transformstransform_fn = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize([.485, .456, .406], [.229, .224, .225])
])image = transform_fn(image)
print("shape:",image.shape)
print("data type:",image.dtype)
print("min value:",image.min().asscalar())
print("max value:",image.max().asscalar())

ToTensor()将图像从 HWC 格式转换为 CHW 格式,并将数据类型从 8 位整数转换为 32 位浮点数。然后根据 ImageNet one case 统计对图像进行归一化。

如前所述,我们通常逐批预测图像。尽管我们只预测了一个图像,我们仍然需要指定批量大小:

image = image.expand_dims(0)

3.准备模型:

network = gcv.model_zoo.get_model('fcn_resnet50_ade',pretrained=True)

4.打开结果

为了加快速度,我们将申请。向我们的网络演示。更长的版本可以在实例分段下找到。

output = network.demo(image)
print(output.shape)

只有 1 个图像,150 个预测类,图像的宽度为 576,高度为 768。

output = output[0] # since there is only 1 image in this batch
prediction = mx.nd.argmax(output,0).asnumpy() # to get index of largest probability

5.给我们的形象上色

现在,让我们给我们的图像着色来分割它们:

from gluoncv.utils.viz import get_color_palleteprediction_image = get_color_pallete(prediction, 'ade20k')
prediction_image

实例分割

实例分割能够识别一个人不同于另一个人。我们可以预测这些像素的确切边界和颜色,而不是边界框。

这要归功于 gluonvc 的原始文档:https://gluon-cv . mxnet . io/build/examples _ instance/demo _ mask _ rcnn . html # sphx-glr-build-examples-instance-demo-mask-rcnn-py

1.下载图像

image = gcv.utils.download('[https://github.com/dmlc/web-data/blob/master/'](https://github.com/dmlc/web-data/blob/master/') +
                          'gluoncv/detection/biking.jpg?raw=true',
                          path='biking.jpg')

2.转换数据

x, orig_img = gcv.data.transforms.presets.rcnn.load_test(image)

3.准备模型

network = gcv.model_zoo.get_model('mask_rcnn_resnet50_v1b_coco', pretrained=True)

4.打开结果

ids, scores, bboxes, masks = [xx[0].asnumpy() for xx in network(x)]

5.在图像上绘画

# paint segmentation mask on images directly
width, height = orig_img.shape[1], orig_img.shape[0]
masks, _ = gcv.utils.viz.expand_mask(masks, bboxes, (width, height), scores)
orig_img = gcv.utils.viz.plot_mask(orig_img, masks)
plt.imshow(orig_img)

让我们添加一些框:

# identical to Faster RCNN object detection
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(1, 1, 1)
ax = gcv.utils.viz.plot_bbox(orig_img, bboxes, scores, ids,
                         class_names=network.classes, ax=ax)
plt.show()

结论

恭喜你!你只用一个框架就完成了 4 个主要的计算机视觉任务!

一定要尝试不同的型号,确定哪种最适合你。记住:更复杂的模型不一定是最好的模型。

理解业务需求非常重要。选择最符合您目的的型号。凡事总有取舍。花一些时间浏览文档,以确定哪个模型架构和哪个类标签最适合您的需要。

来源: kxcd

参考

  1. https://medium.com/r/? URL = https % 3A % 2F % 2f gluon-cv . mxnet . io % 2f contents . html
  2. https://www.coursera.org/learn/aws-computer-vision-gluoncv/
  3. https://gluon-cv . mxnet . io/build/examples _ instance/demo _ mask _ rcnn . html # sphx-glr-build-examples-instance-demo-mask-rcnn-py

计算机视觉一站式指南—第二部分

原文:https://towardsdatascience.com/a-one-stop-guide-to-computer-vision-part-2-f5db1b025588?source=collection_archive---------65-----------------------

带有 MXNet 和胶子的计算机视觉(逐行解释)

弗拉德·希利塔努在 Unsplash 上拍摄的照片

第 1 部分:使用高级 API 创建神经网络。

介绍

在上一篇文章中,我们学习了如何使用 GluonCV 模型动物园中预先训练好的模型来执行 4 种不同的计算机视觉任务。在本文中,我们将从头开始构建自己的模型。

这篇文章的目的是让你了解计算机视觉模型内部通常会发生什么。我们将创建一个卷积神经网络(CNN)来识别服装。是的,你没听错,我们不再识别手写数字(MNIST)或探测狗了。我们现在识别服装。

但是为什么呢?

根据扎兰多:

事实上,MNIST 经常是研究人员尝试的第一个数据集。他们说,“如果在 MNIST 行不通,那就根本行不通”。“嗯,如果它对 MNIST 有效,对其他人也可能无效。”

再按 Zalando :

MNIST 太容易了。卷积网在 MNIST 上可以达到 99.7%。经典的机器学习算法也能轻松做到 97%。

本文假设您对机器学习和神经网络有某种形式的基础知识,如训练测试数据、优化器、损失函数、度量、前向传播、后向传播等。如果没有,不要担心。这些概念非常基本,很多信息都可以在网上找到。我将尽力解释构建 CNN 所需的每一行代码。

导入库

必须导入以下库来构建我们的模型。如果您遵循了本文的第 1 部分,您将不需要安装任何额外的包。否则,一定要看看这篇文章,看看你应该下载哪两个包!(是的,你所需要的是 2 个软件包来创建你自己的神经网络)

from mxnet import nd,autograd,gluon,init,metricfrom mxnet.gluon import nn
from mxnet.gluon.data.vision import datasets, transformsimport matplotlib.pyplot as plt
from time import time

下载数据

胶子自带数据库。你可以用一行代码下载时尚 MNIST

因为我们稍后将评估我们的模型,所以我们也将通过将参数train设置为False来下载验证数据集。

train_data = datasets.FashionMNIST(train=True)
valid_data = datasets.FashionMNIST(train=False)X_train,y_train = train_data[0]print(X_train.shape, y_train.dtype)
print(len(train_data))

然后,我们可以打印出第一幅图像的形状和数据类型:

  • 形状:(28,28,1)。图像的高度和宽度是 28,并且它是黑白图像,因为深度只有 1。
  • dtype: int32。图像由 32 位整数表示。

最后,我们观察到我们的训练数据中有 60,000 张图像。

转换数据

数据必须被转换成胶子神经网络能够消化的格式。幸运的是,胶子也为我们提供了轻松实现这一点的功能:

  • transforms.Compose 允许我们将几个转换函数拼接成一个函数。请注意转换的顺序很重要。
  • transforms.ToTensor()将您的图像从 HWC 格式更改为 CHW 格式,并将数据类型从 32 位整数更改为 32 位浮点。
  • transforns.Normalize()根据提供的两个参数——平均值、标准差,对图像进行归一化处理。
transformer = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(0.13,0.31)
])train_data = train_data.transform_first(transformer)

将数据加载到批中

把你的图像一张一张地发送到你的神经网络中是个坏主意。这将花费大量的时间来为你的网络提供信息。因此,我们创建一个数据加载器,将数据加载到 256 个批次中(您可以试验并更改这个批次号)。

创建数据加载器需要 4 个参数:

  • train_data:您的训练数据(长度 60000)
  • 每一波都会有 256 张图片输入你的神经网络
  • 随机打乱你的数据以减少数据间的虚假关联
  • num_workers:用于训练的核心数。您可以检查可用内核的数量。不同的计算机会返回不同的结果。在我的例子中,我将其设置为 4。
# check number of CPUs avaiable
from multiprocessing import cpu_count
print(cpu_count())batch_size = 256
train_data_batch = gluon.data.DataLoader(train_data,
                                         batch_size = batch_size,
                                         shuffle=True,
                                         num_workers=4)valid_data = gluon.data.DataLoader(valid_data.transform_first(transformer),
                                   batch_size=batch_size)

定义您的模型

我们将复制一个 LeNet-5 模型。

原始图片发表于[ LeCun 等人,1998]

我们首先从空白画布开始:nn.Sequential()

接下来,我们根据 LeNet-5 架构在我们的模型中添加一层又一层的隐藏层。

  • nn.Conv2D:从图像中提取特征的卷积层。
  • nn.MaxPool2D:减少待训练参数数量的池层。
  • nn.Flatten:将我们的数据展平到一维,为完全连接的层做准备
  • nn.Dense:全连接层
  • network.initialize(init=init.Xavier()):执行“ Xavier ”权重初始化。Xavier 初始化器有助于保持所有层的梯度比例大致相同
network = nn.Sequential()
with network.name_scope():
    network.add(
        nn.Conv2D(channels=6, kernel_size=5, activation='relu'),
        nn.MaxPool2D(pool_size=2, strides=2),
        nn.Conv2D(channels=16, kernel_size=3, activation='relu'),
        nn.MaxPool2D(pool_size=2, strides=2),
        nn.Flatten(),
        nn.Dense(120, activation='relu'),
        nn.Dense(84, activation='relu'),
        nn.Dense(10)
        )network.initialize(init=init.Xavier())

损失函数

为了让我们的模型确定它是否表现良好,我们需要一个损失函数。你可以认为损失函数是错误,关于我们离正确的标签/基本事实有多远。

在多项式分类问题中,我们通常会使用交叉熵损失函数。交叉熵损失函数通常与 softmax 成对使用,以挤压(0,1)之间的值。

softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()

评估指标

有了损失函数,我们需要一种方法来确定我们的模型有多好。我们通过使用指标来确定这一点。有几个指标,如 F1,召回,精度,准确性等。最常用的衡量标准是准确性。

train_acc允许我们创建一个对象,并不断向它反馈预测结果和实际结果。它会自动重新计算精度,直到您调用精度。这将在本文的后面部分演示。

train_acc = metric.Accuracy()

【计算机】优化程序

我们需要定义我们的优化器。如果我们不采取任何措施来改进我们的模型,那么了解它的表现是好是坏是没有意义的。因此,我们利用随机梯度下降来告诉我们的模型在给定当前误差/精度的情况下下一步做什么。

  • network.collect_params() :我们能够检索我们模型的当前权重。我们的教练需要当前的体重,以便更新。
  • 'sgd':我们选择随机梯度下降优化器。访问原始文档了解可用的优化器类型。
  • learning_rate:学习率越低,我们就越能达到最小/最大值。然而,这也导致了更长的模型训练时间。
trainer = gluon.Trainer(network.collect_params(),
                       'sgd', {'learning_rate':0.1})

训练循环

这一部分将我们到目前为止为训练模型所做的一切放在一起。我将逐步解释下面的代码:

  1. for epoch in range(10): 我们将对我们的模型进行总共 10 个纪元/时间的训练。
  2. 对于每次迭代,我们将损失实例化为 0。
  3. tic = time()我们记录当前时间,这样我们就可以跟踪我们的模型训练需要多长时间。
  4. 我们现在循环处理批量数据
  5. with autogra.record():我们记录模型中发生的事情
  6. output=network(data)通过将data传递给我们的network,也就是我们的模型,我们得到了一个预测output
  7. loss=softmax_cross_entropy(output,label)利用之前定义的损失函数,我们可以通过传入预测输出和实际输出来计算我们的损失
  8. 损失通过 CNN 反向传播
  9. trainer.step(batch_siz)在反向传播损失后,我们向前迈出一步来更新我们的权重
  10. train_loss += loss.mean().asscalar()用该批数据发生的损失更新培训损失
  11. train_acc.update(label,output)训练精度随着这批数据的损失而更新
  12. 打印报表打印每个时期的损耗、精度和性能。我们通常会将它打印出来,这样我们就可以观察并确保模型正在进展。
  13. network.save_parameters("trained_net.params")这一步是可选的。将模型训练成文件后,它会保存更新的权重。砝码可以随时加载到另一个环境中。
for epoch in range(10):
    train_loss = 0
    tic = time()
    for data, label in train_data_batch:
        with autograd.record():
            output=network(data)
            loss=softmax_cross_entropy(output,label)
        loss.backward()

        trainer.step(batch_size)

        train_loss += loss.mean().asscalar()
        train_acc.update(label,output)

    print("Epoch[%d] Loss: %.3f Acc: .%3f Perf: %.1f img/sec"%(
        epoch,train_loss/len(train_data_batch),
        train_acc.get()[1],
        len(train_data)/(time()-tic)
    ))
network.save_parameters("trained_net.params")

上面的代码需要相当长的时间来运行,这取决于你的计算机的能力。你可以观察到随着迭代次数的增加,损耗如何减少,精度如何增加。这说明我们的模型学习的很好。

模型评估

最后,我们对我们的模型进行最终评估,以了解它在看不见的数据上的表现。切记创建新的精度指标,不要重复使用train_acc以防止信息泄露。

解释:

  1. network.load_parameters("trained_net.params")加载我们之前训练的模型权重。
  2. 就像我们如何传递一批批训练数据来训练我们的模型一样,我们现在传递一批批验证数据来评估我们的模型,同时更新valid_acc
  3. 为了获得最终精度,使用valid_acc.get()[1]将其打印出来。我设法获得了 0.9025 的验证精度。你应该得到一个不同的号码。这意味着我们的模型在 90%的时间里预测正确的输出!
network.load_parameters("trained_net.params")valid_acc = metric.Accuracy()for data,label in valid_data:
    output = network(data)
    valid_acc.update(label,output)print(valid_acc.get()[1])

结论

祝贺你完成这篇文章!现在,您应该能够从头开始创建和设计自己的神经网络。还有许多其他深度学习库,如 TensorflowKerasPytorchScikit-learn 也可以实现相同的结果。去做你熟悉的事情。不同的包应该仍然为您提供相似的结果。

我鼓励你去看看现有的不同模型和架构,用你能在网上找到的不同数据进行实验。

新冠肺炎隔离期间免费下载施普林格书籍的软件包

原文:https://towardsdatascience.com/a-package-to-download-free-springer-books-during-covid-19-quarantine-6faaa83af13f?source=collection_archive---------35-----------------------

查看如何下载在新冠肺炎隔离期间免费提供的所有(或部分)Springer 书籍

斯坦尼斯拉夫·康德拉蒂耶夫拍摄的照片

更新:促销活动已经结束,因此无法通过 r 下载图书。如果您没有及时下载图书,您仍然可以通过此 链接 获得图书。

介绍

你可能已经看到斯普林格继新冠肺炎·疫情之后免费发行了大约 500 本书。据斯普林格称,这些教科书将至少免费提供到 7 月底。

在这个声明之后,我已经从他们的网站上下载了几本统计学和 R 编程的教科书,我可能会在接下来的几周内再下载一些。

在这篇文章中,我展示了一个为我节省了大量时间的包,它可能会引起我们很多人的兴趣:由雷南·泽维尔·科尔特斯开发的[{springerQuarantineBooksR}](https://github.com/renanxcortes/springerQuarantineBooksR) 1

这个软件包可以让你轻松下载新冠肺炎隔离期间免费提供的所有(或部分)Springer 书籍。

有了这么多高质量的资源和我收集的关于冠状病毒的顶级 R 资源,我们没有任何借口在隔离期间不阅读和学习。

在这篇文章中,我展示了:

  • 如何一次性下载所有可用的教科书
  • 给定特定的标题、作者或主题,如何下载书籍的子集

事不宜迟,下面是这个包在实践中的工作方式。

装置

安装完{devtools}包后,您可以从 GitHub 安装{springerQuarantineBooksR}包并加载:

# install.packages("devtools")
devtools::install_github("renanxcortes/springerQuarantineBooksR")
library(springerQuarantineBooksR)

一次下载所有书籍

首先,用setwd()功能设置保存所有书籍的路径,然后用download_springer_book_files()功能一次性下载所有书籍。请注意,这需要几分钟时间(取决于您的互联网连接速度),因为所有书籍加起来差不多有 8GB。

setwd("path_of_your_choice") # where you want to save the books
download_springer_book_files() # download all of them at once

你会在一个名为“springer_quarantine_books”的文件夹里找到所有下载的书籍(PDF 格式),按类别整理。 2

如果您想下载 EPUB 版本(或 PDF 和 EPUB 版本),请在函数中添加filetype参数:

# for EPUB version:
download_springer_book_files(filetype = "epub")# for both PDF and EPUB versions:
download_springer_book_files(filetype = "both")

默认情况下,它只下载英文书籍。但是,也可以通过添加参数lan = 'ger'来下载所有德语书籍:

download_springer_book_files(lan = 'ger')

请注意,总共有 407 个独特的英语标题和 52 个德语标题。

创建一个斯普林格图书表

像我一样,如果你不知道 Springer 提供了哪些书,也不想下载所有的书,你可能想在下载任何书之前有一个已发行书籍的概述或列表。为此,您可以使用download_springer_table()函数将包含 Springer 提供的所有图书的表格加载到 R 会话中:

springer_table <- download_springer_table()

然后可以用{DT}包改进该表,以:

  • 只保留最少的信息,
  • 允许按书名、作者、分类或年份搜索书籍,
  • 允许下载可用书籍列表,以及
  • 例如,使 Springer 链接可点击
# install.packages("DT")
library(DT)springer_table$open_url <- paste0(
  '<a target="_blank" href="', # opening HTML tag
  springer_table$open_url, # href link
  '">SpringerLink</a>' # closing HTML tag
)springer_table <- springer_table[, c(1:3, 19, 20)] # keep only relevant informationdatatable(springer_table,
  rownames = FALSE, # remove row numbers
  filter = "top", # add filter on top of columns
  extensions = "Buttons", # add download buttons
  options = list(
    autoWidth = TRUE,
    dom = "Blfrtip", # location of the download buttons
    buttons = c("copy", "csv", "excel", "pdf", "print"), # download buttons
    pageLength = 5, # show first 5 entries, default is 10
    order = list(0, "asc") # order the title column by ascending order
  ),
  escape = FALSE # make URLs clickable
)

该表不能在介质上导入,所以参见原始帖子中的表。供您参考,该表允许您查看 Springer 提供的教科书(以及一些信息),并允许您找到您最有可能感兴趣的教科书。

请注意,您可以使用download_springer_table(lan = "ger")函数为德语书籍创建一个类似的表。

仅下载特定的书籍

现在你对你感兴趣的书有了更好的了解,你可以按书名、作者或主题下载它们。

按标题

假设您只对下载一本特定的书感兴趣,并且您知道它的书名。例如,假设您想下载名为《所有统计学》的书:

download_springer_book_files(springer_books_titles = "All of Statistics")

如果您有兴趣下载多本书,请运行以下命令:

download_springer_book_files(
  springer_books_titles = c(
    "All of Statistics",
    "A Modern Introduction to Probability and Statistics"
  )
)

或者,如果您没有特定的书名,但是您有兴趣下载书名中带有“统计学”一词的所有书籍,您可以运行:

springer_table <- download_springer_table()library(dplyr)
specific_titles_list <- springer_table %>%
  filter(str_detect(
    book_title, # look for a pattern in the book_title column
    "Statistics" # specify the word
  )) %>%
  pull(book_title)download_springer_book_files(springer_books_titles = specific_titles_list)

提示:如果您想下载标题中带有“统计学”或“数据科学”字样的所有书籍,请将上述代码中的"Statistics"替换为"Statistics|Data Science"

按作者

如果您想要下载特定作者的所有书籍,您可以运行:

springer_table <- download_springer_table()# library(dplyr)
specific_titles_list <- springer_table %>%
  filter(str_detect(
    author, # look for a pattern in the author column
    "John Hunt" # specify the author
  )) %>%
  pull(book_title)download_springer_book_files(springer_books_titles = specific_titles_list)

按主题

您还可以下载涵盖某一特定科目的所有教材(参见汇总表中subject_classification栏中的所有科目)。例如,以下是如何下载“统计学”主题的所有书籍:

springer_table <- download_springer_table()# library(dplyr)
specific_titles_list <- springer_table %>%
  filter(str_detect(
    subject_classification, # look for a pattern in the subject_classification column
    "Statistics" # specify the subject
  )) %>%
  pull(book_title)download_springer_book_files(springer_books_titles = specific_titles_list)

丰富

下面列出了为改进套件而可能实施的功能:

  • 增加了下载一本书所有版本的可能性。目前,只能下载最新版本。
  • 增加了下载停止后继续下载的可能性。目前,如果再次执行代码,下载将从头开始。
  • 增加了按题目下载书籍的可能性。目前只能通过标题作者主题来实现。

如果您有其他改进的想法,请随时在 GitHub 上打开一个 pull 请求。

感谢

我要感谢:

  • 雷南泽维尔科尔特斯(和所有贡献者)提供了这个包
  • 被用作{springerQuarantineBooksR}包灵感的[springer_free_books](https://github.com/alexgand/springer_free_books) Python 项目
  • 最后但同样重要的是,斯普林格免费提供他们的许多优秀书籍!

感谢阅读。我希望这篇文章能帮助你下载和阅读更多新冠肺炎检疫期间斯普林格提供的高质量材料。

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

  1. 我感谢作者允许我在博客中展示他的包。
  2. 请注意,您可以通过指定参数destination_folder = "name_of_your_choice"来更改文件夹名称。

相关文章

原载于 2020 年 4 月 26 日https://statsandr.com

深度 Q 网络中的一对相关神经网络

原文:https://towardsdatascience.com/a-pair-of-interrelated-neural-networks-in-dqn-f0f58e09b3c4?source=collection_archive---------30-----------------------

在 DQN 和双 DQN 模型中,比较两个相互关联的神经网络是至关重要的。

资料来源:123rf.com

我们将遵循在开发 DQN DQN 算法中为对抗相关性和高估而采取的一些步骤。作为 DQN双 DQN 应用的例子,我们展示了 CartPole-v0CartPole-v1 环境的训练结果。最后一节包含一些关于 PyTorch 张量的提示。

从查找表到神经网络

直到 2013 年左右,深度 Q-Learning 还是一种强化学习( RL )方法,只对查找表有效。神经网络在计算机视觉中的成功激起了人们在《T21》RL 中尝试它们的兴趣。论文“ 用深度 RL 玩雅达利”(V.Mnih 等人,2013,DeepMind)提出了第一个使用神经网络函数逼近的成功的深度学习模型。在 2015 年, DeepMind 展示了Deep Q-network 代理,仅接收行像素数据和游戏分数作为输入,就能够超过之前所有算法的性能。

在这两个 DeepMind 工作之后,查找表被神经网络取代,一个Q-学习变成了一个深度 Q-学习、或者等价地,深度 Q-网络(DQN)。其实是 RL 特工训练的一个突破。

DQN 是将 Q 学习与神经网络相结合的算法。

DQN组件

  1. 一对Q-网络(本地和目标)。
  2. 体验回放—一种生物启发机制。
  3. ε-贪婪机制。
  4. Q-学习,即将最大值用于所有可能的动作。
  5. 利用梯度下降机制最小化损失函数。

相关性有害

当神经网络被用作函数逼近时,强化学习被认为是不稳定的。这种不稳定性的原因如下:

  • 观察序列中的相关性,
  • Q 值的微小更新可能会显著改变策略,
  • Q-值***Q(s_t, a_t)***TD-目标值之间的相关性

TD-目标

用于 DQN 的关键方程,eq。(2).

DQN 关键方程

Q-网络:本地和目标

DQN 算法在对抗相关性中的一个重要组成部分就是使用目标网络 ( ***q_target*** ) 。目标网络(具有参数***θ****)与本地网络相同,除了它的参数从本地网络(***q_local***)的每个***τ***步骤被复制,以便然后***θ**_*t* = *θ*_*t***,并在所有其他步骤保持固定。在看起来如下:

横翻 中设置 τ = TARGET_UPDATE = 10。

损失函数为 DQN 代理

比较代表相同 Q-表的两个神经网络并找到这些网络非常接近的点是 DQN 算法的基本部分。

由网络 q_localq_target 张量当前估计 ***Q*(s_*t, a_t*)**备选估计 ***G_t*** 参见(1),进行计算。此外,在**class Agent**的功能***learn()***

表 1。 三张量(PyTorch 中),DQN

  • **Q_targets****Q_expected** 之间的距离由***MSELoss*** 函数计算***loss***值通过梯度下降机制最小化;
  • 执行***loss***张量的***backpropagation*** 机制;
  • 梯度下降算法由优化器执行,例如***torch.optim.Adam*, *torch.optim.RMSprop***或任何其他。

DQN 的学习功能

体验回放——一种受生物启发的机制

DQN 用来减少相关性的另一个东西是体验回放机制,它将数据放入特定的内存存储中,并从内存存储中随机接收数据。

ε-贪婪机制

DQN**ε**-贪婪机制促进了勘探开采之间的合理比例。该机构提供参数**ε**,其中**0 < ε < 1**,允许控制该比例。对于任何**ε**,以概率**1-ε**,选择剥削。利用意味着代理通过在给定状态的所有可能动作中最大化Q-值找到以下动作,参见函数***get_action()***中的相关行:**

退火ε-贪婪机制

但是如何选择 epsilon 呢?一个流行的选择是退火**ε**——贪婪算法。对于任何一集***i***,动作都是贪婪概率**1-ε**

在 eq 中。(3)**ε_m**是中**ε**的最小值,在**Mε** 中必须达到。由(3)如果***i* = 0** 我们有**ε = 1**;如果***i =* 1** 那么**ε** 接近**1** 为例,对于**Mε = 50****ε_m =0.01**我们有**ε = 0.98** 然后以概率**0.02**选择开采,以概率**0.98** 选择,动作号的一个相当随机的值。因此,对于第一集来说,动作会被随机选择,这就是探索。********

如果***i =* Mε** 我们得到**ε = ε_m** **ε = 0.01**为例,然后以概率**0.99**选择利用,仅在 1%的情况下获得行动数的随机值。对于从**0****Mε**的剧集,**ε** 的值从**1****ε_m**递减,之后固定在**ε_m**

双 DQN 对 DQN

高估DQN**

众所周知, DQN 算法高估了动作值。 Thrun 和 Schwartz (1993) 首次调查了 DQN高估。他们给出了一个例子,其中这些高估渐进地导致次优政策。假设,对于某个状态***s***’,所有动作***a***的真值为***Q(s’, a) = 0***,而 Q 的估计值分布在零上下。那么这些估计值的最大值就是对真实值的高估。2015 年,( Hasselt et。艾尔。, DeepMind)表明,估计误差会使估计值上升并远离真正的最优值。他们假设减少高估的解决方案:双 DQN。****

高估的原因是什么?问题出在 eqs 中的**max**运算符。(1)和(2)。假设***Q(S_t, a)*** 的评估值已经被高估。然后在方程中得到的动作值。(1)或(2)变得更加高估。等式中的TD-目标***G_t***。(1)可以重写为TD-目标***G^Q_t***如下:****

这里,***θ*_*t***是网络的权值集合***q_target***见上表 1。**

解耦动作和评估

双 DQN 的解决方案是在解耦中选择动作 ***argmax_a***求值 ***Q*(*S_{t+1}, argmax_a*)**,参见(4)。这是使用另一个具有权重集***θ’*_*t*** : 的网络来完成的

通过(5)贪婪策略(argmax)由神经网络*q_local* ***(***权重***θ*_*t).*** 估计,网络 q_target (权重***θ'*_*t)*** 用于公平地评估该策略。这个方案是双 DQN 的主要思想。**

损失函数为 DQN 代理**

对于 DQN 代理的情况,张量***Q*(s_*t, a_t*)*****G_t*** 的计算同 DQN、见表 1 和表 2。**

表二。四张量(PyTorch 中),双 DQN

表 1 和表 2 的主要区别在于张量***Q_target_next*** 的计算(评估 Q 值):

  • 在表 1 中,***Q_target_next***仅由一个网络计算***q_target,*** 见(4)。
  • 在表 2 中,***Q_target_next*** 使用两个网络计算:***q_target******q_local***(见(5)和***Q_max_action***)。

双 DQN 的学习功能

杠-v0 和杠-v1 训练

一根杆子通过一个接头连接到一辆沿轨道移动的车上。通过对推车施加+1 或-1 的力来控制该系统。

是一个二元分类问题**

**小车观察空间的维数为 4,因为有 4 个特征构成输入:小车坐标速度立柱与垂线的角度及其导数(立柱“下落”速度)。横竿是一个二元分类问题,因为在每个时间步,代理人在移动***left******right***之间进行选择。钟摆开始直立,目标是防止它翻倒。柱子保持直立的每个时间步长提供+1 的奖励。当柱子偏离垂直方向超过 15 度,或者手推车偏离中心超过 2.4 个单位时,该集结束。

如果连续 100 次试验获得平均奖励>195,则认为环境问题解决;横竿-v1 如果连续 100 次试验得到平均奖励>475**就认为解决了。

小车-v0小车-v1的训练实验****

下面是我用 DQN双 DQN 进行实验的结果,是在训练 CartPole-v0CartPole-v1 时获得的。对于所有情况,LEARNING_RATE = 0.001。贪婪参数**ε****1**变为**ε_m = 0.01****

与 DQN 一起翻筋斗

对于 CartPole-v0CartPole-v1、我们把**Mε= 50.**

  1. **DQN,钢管舞-v0,奖励 195 在第 962 集达成。
  2. **DQN,扁担-v1,奖励 475 在第 1345 集达成。

翻筋斗带双 DQN

对于 CartPole-v0 我们把**Mε= 200;**对于 CartPole-v1,我们把**Mε= 150.**回忆一下**Mε****ε** 达到最小值**ε_m.**的那一集的数量

3.双 DQN,弹弓-v0,奖励 195 在第 612 集达成。**

4.双 DQN,横竿-v1,奖励 475 在第 1030 集达成。**

超参数的选择

如果**Mε**设置得太大,那么**ε**的选择将在探索的高概率(**> ε_m**)条件下进行很长时间。换句话说,很长一段时间**ε**将在神经网络中没有信息积累的情况下进行。这意味着在移动***left******right***之间做出选择,我们可能会在很长一段时间内有一半的情况是错误的。**

如果**Mε**设置过小,那么**ε**的选择将会在利用的高概率(**= ε_m**)的情况下进行很长时间。这在神经网络训练的早期阶段可能非常糟糕,因为使用***argmax***动作的选择将从神经网络中做出,这仍然非常粗糙。那么在很多情况下,选择的动作就会被弄错。****

结论

在开发 DQN双 DQN 算法时,采取了三个步骤来对抗相关性和高估:(1)目标和局部网络,(2)经验重放机制,(3)将选择与评估分离。这些机制是通过大量使用两个相关的神经网络开发出来的。**

附录。关于 PyTorch 张量

用 torch.no_grad()

PyTorch 函数***no_grad()*** 从渐变计算中排除一些元素。当确信没有执行反向传播过程时使用。该功能减少了内存消耗,参见***get_action().*** 使用***detach()*** 功能时也会出现类似的效果。***with***声明阐明了对应于***try...finally*** 块的代码。

optim.zero_grad()

清除上一步的旧梯度(否则梯度将从所有***loss.backward()***调用中累加)

视图(1,1)

该函数返回一个新的张量,与原始张量相同,但形状不同。试图去除***view(1,1)*** 中的***get_action()***我们得到了中不同形状的动作张量的两个分支***get_action().***然后在***learn()***中我们得到了由各种形状的张量组成的***batch.action*** 。这是失败。函数***view(1,1)*** 将形状从***tensor([a])*** 改变为***tensor([[a]]).*** 参数***1,1***表示每个维度的元素个数。例如,view(1,1,1,1,1)表示
***tensor([[[[[a]]]]]).***
****

torch.cat

将给定的张量元组连接成单个张量。例如在***learn()***函数中,***batch.state*** 是形状[1,4]的 64 个张量的元组。函数***torch.cat***将该元组转换为形状【64,4】的单个张量***states***,如下所示:

States = torch . cat(batch . state)

整形(-1)

为什么我们要用***reshape(-1)***来求***Q_targets_next***张量,见表 2?在***learn()***函数中我们比较两个张量:***Q_targets.unsqueeze(1)******Q_expected.***如果我们不使用***reshape***函数,那么由表 3 可知这些张量具有不同的形状,那么比较就是失败的。

表 3 learn()函数中比较的张量形状

其他深度强化学习项目,见我的 github 目录。关于贝尔曼方程和神经网络之间的相互关系,见我之前的论文。同一篇文章提供了关于 PyTorch 的更多提示。

参考

[1] V.Minh 等人艾尔。,用深度强化学习玩雅达利(2013),arXiv:1312.5602

[2] H .范·哈塞尔特等人。艾尔。,采用双 Q 学习的深度强化学习(2015),arXiv:1509.06461

[3] A.Karpathy,深度强化学习:Pong from Pixels (2016),karpathy.github.io

[4]魔方密码,双 Q 学习导论,(2020),rubikscode.net

[5] S.Karagiannakos,将深度 Q 网络推进一步,(2018),TheAISummer

[6] V.Minh 等人艾尔。,通过深度强化学习的人类级控制,(2015),《自然》

[7] R.Stekolshchik,贝尔曼方程在 Deep RL 中是如何工作的?,(2020),走向数据科学

8 C.Yoon,双深度 Q-Networks 2019,走向数据科学

*****[9] S.Thrun 和 A.Schwartz,使用函数逼近进行强化学习的问题,(1993 年),
卡内基梅隆大学机器人研究所

【10】F . Mutsch,cart pole with Q-Learning——open ai Gym 的首次体验(2017 年),muetsch.io*****

[11] T.Seno,欢迎来到深度强化学习第一部分:DQN,(2017),走向数据科学

[12]https://towards data science . com/dqn-part-1-vanilla-deep-q-networks-6 EB 4a 00 feb FB

贝叶斯优化的并行实现

原文:https://towardsdatascience.com/a-parallel-implementation-of-bayesian-optimization-2ffcdb2733a2?source=collection_archive---------20-----------------------

介绍一种适用于昂贵、不连续或不确定函数的并行优化方法。

作者上传的图片

“优化”的概念是数据科学的核心。我们通过优化神经网络中的权重来最小化损失。我们优化梯度增强树中的超参数,以找到最佳偏差-方差权衡。我们使用 A-B 测试来优化我们网站上的行为。无论我们的功能是神经网络、消费者行为,还是更险恶的东西,我们都有想要优化的东西。

有时,我们试图优化的功能是昂贵的,我们希望以尽可能少的步骤到达我们的目的地。有时我们希望确信我们找到了可能的最佳解决方案,有时我们的函数没有易处理的梯度,所以没有好的箭头来给我们指出正确的方向。通常,我们的函数有随机元素,所以我们真的试图优化 f(x) = y + e,其中 e 是一些随机误差元素。贝叶斯优化是一种函数优化器(maximizer),在这些条件下蓬勃发展。

目录

  1. 什么是贝叶斯优化
  2. 从头开始实施
  3. 并行实施
  4. 最后的话

什么是贝叶斯优化

假设我们有一个函数 f,,我们想找到最大化(或最小化) f(x)x 。我们有很多很多选择。然而,如果我们的函数符合目录上面的描述,我们肯定会考虑贝叶斯优化。

有几种不同的方法来执行贝叶斯优化。所有这些都涉及到创建一个关于某些事物如何分布的假设,基于这个假设做出一个决定,然后更新这个假设。

本文中的方法使用高斯过程来创建关于 f(x) 如何分布的假设。这些过程可以被认为是函数的分布——从高斯分布中抽取随机样本会产生一个数字,从高斯过程中抽取随机样本会产生一个函数。如果你不熟悉高斯过程,这有点难以想象。我推荐这个视频,是它让我对这个概念产生了兴趣。

算法本身可以总结如下:

作者上传的图片

从头开始实施

在这里,我们不使用软件包,只进行一次贝叶斯优化迭代。这个过程非常简单。首先,我们定义一个玩具函数 func 我们想要最大化,然后我们采样它 4 次:

# Function to optimize
func <- function(input) {
  dnorm(input,15,5) + dnorm(input,30,4) + dnorm(input,40,5)
}# Sample the function 4 times
func_results <- data.frame(input = c(5,18,25,44))
func_results$output <- func(func_results$input)# Plot
library(ggplot2)
p <- ggplot(data = data.frame(input=c(0,50)),aes(input)) +
  stat_function(fun=func,size=1,alpha=0.25) +
  geom_point(data=func_results,aes(x=input,y=output),size=2) +
  ylab("output") +
  ylim(c(-0.05,0.2))
p + ggtitle("Our Function and Attempts")

作者上传的图片

我们假装不知道真正的函数,所以实际上我们看到的只是我们采样的 4 个点。为了保持这个演练的趣味性,我们在选择初始点时做了一件很糟糕的工作。让我们用高斯过程来拟合这 4 个点,以定义我们对每个输入的输出分布的假设。

library(DiceKriging)
set.seed(1991)
gp <- km(
    design = data.frame(input=func_results$input)
  , response = func_results$output
  , scaling = TRUE
)

让我们看看采样点旁边的高斯过程和真实函数值:

predGP <- function(x,grab) {
  predict(gp,data.frame(input=x),type = "UK")[[grab]]
}a=1
cl = "purple"
plotGP <- function(grab,cl,a) {
  stat_function(
    fun=predGP,args=list(grab=grab),color=cl,alpha=a,n=1000
  )
}
p + ggtitle("Gaussian Process Results") +
  plotGP("mean",cl,a) +
  plotGP("lower95",cl,a) +
  plotGP("upper95",cl,a)

作者上传的图片

高斯过程允许我们为每个输入定义输出的正态分布。在上图中,紫色线条显示的是高斯过程。中间的线是平均值,上面/下面的线是该输入的正态分布的第 95 个百分位数。因此,举例来说,如果我们想知道如何假设输出在输入= 30 时分布,我们可以这样做:

predict(gp,data.frame(input=30),type="UK")[c("mean","sd")]$mean
[1] 0.05580301

$sd
[1] 0.007755026

这说明我们假设,在输入= 30 时,我们的输出服从正态分布,均值= 0.0558,标准差= 0.0078。

既然我们已经定义了关于输出分布的假设,我们需要确定下一步在哪里对函数进行采样。要做到这一点,我们需要定义一个输入的“承诺”程度。我们通过定义一个获取函数来做到这一点。有几种可供选择:

作者上传的图片

其中,置信上限是最容易实现的,因此让我们定义该函数并将其绘制在图表上:

ucb <- function(x,kappa=3) {
  gpMean <- predGP(x,grab="mean")
  gpSD <- predGP(x,grab="sd")
  return(gpMean + kappa * gpSD)
}a=0.25
p + ggtitle("Upper Confidence Bound") +
  plotGP("mean",cl,a) +
  plotGP("lower95",cl,a) +
  plotGP("upper95",cl,a) +
  stat_function(fun=ucb,color="blue")

作者上传的图片

我们可以看到,我们的置信上限在 10 到 15 之间的某处达到最大值(绿色菱形),所以让我们找到具体的点,对其进行采样,并更新我们的 GP:

# Find exact input that maximizes ucb
acqMax <- optim(
    par = 12
  , fn = ucb
  , method = “L-BFGS-B”
  , control = list(fnscale = -1)
  , lower = 10
  , upper = 20
)$par# Run our function as this spot
func_results <- rbind(
    func_results
  , data.frame(input = acqMax,output = func(acqMax))
)

我们刚刚完成了贝叶斯优化的一次迭代!如果我们继续运行更多,我们会看到我们的图表演变:

作者上传的图片

并行实施

我们不会从零开始实现这一部分。相反,我们将使用 ParBayesianOptimization R 包来完成繁重的工作。这个软件包允许我们一次对多个有希望的点进行采样。如果只有 1 个有希望的点,它会对周围区域进行多次采样。因此,在我们的第一个例子中,我们将对采集函数的所有 5 个局部最大值进行采样:

作者上传的图片

让我们让它运行起来,看看会有什么结果。我们用上述 4 个相同的点初始化流程,然后用 5 个点运行 1 个优化步骤:

library(ParBayesianOptimization)
library(doParallel)# Setup parallel cluster
cl <- makeCluster(5)
registerDoParallel(cl)
clusterExport(cl,c('func'))# bayesOpt requires the function to return a list with Score
# as the metric to maximize. You can return other fields, too.
scoringFunc <- function(input) return(list(Score = func(input)))# Initialize and run 1 optimization step at 5 points
optObj <- bayesOpt(
  FUN = scoringFunc
  , bounds = list(input=c(0,50))
  , initGrid = list(input=c(5,18,25,44))
  , iters.n = 5
  , iters.k = 5
  , acqThresh = 0
  , parallel = TRUE
)
stopCluster(cl)
registerDoSEQ()# Print the input and score of the first Epoch
optObj$scoreSummary[,c("Epoch","input","Score","gpUtility")] Epoch    input        Score gpUtility
     0  5.00000 0.0107981936        NA
     0 18.00000 0.0677578712        NA
     0 25.00000 0.0573468343        NA
     0 44.00000 0.0581564852        NA
     1 35.59468 0.0916401614 0.6558418
     1 50.00000 0.0107985650 0.6326077
     1 13.74720 0.0773487879 0.5417429
     1 21.13259 0.0462167925 0.4734561
     1  0.00000 0.0008863697 0.1961284

我们的分数摘要显示,bayesOpt 运行了我们的 4 个初始点(Epoch = 0),然后运行了 1 个优化步骤(Epoch = 1),其中它对采集函数的所有 5 个局部最优值进行了采样。如果我们运行更多的迭代,我们将继续一次采样 5 个点。如果我们的函数最大化实际上是昂贵的,这将允许我们更快地找到全局最优。

bayesOpt 中的 acqThresh 参数对于采样过程至关重要。该参数代表采集函数全局最优值的最小百分比,局部最优值必须达到该百分比才能进行采样。例如,如果 acqThresh=0.5,那么每个局部最优值(在我们的例子中是置信上限)必须至少是全局最优值的 50%,否则将被忽略。我们设置 acqThresh=0,这样所有的局部优化都会被采样。

请注意上面的 gpUtility 字段。这是采集函数在每个采样点的缩放值(在我们的例子中是置信上限)。如果您注意到这个值在多个时期内收敛到 0,那么高斯过程的观点是没有多少有希望的点留下来探索。一个更彻底的,包具体的解释可以找到这里

最后的话

贝叶斯优化是一个令人惊讶的利基场景工具。在现代数据科学中,它通常用于优化黑盒模型的超参数。然而,作为一个通用的函数优化器,它已经在许多不同的地方找到了用途。我个人倾向于用这种方法来调优我在 R 和 Python 中的超参数。

一瞥缺失的熊猫数据

原文:https://towardsdatascience.com/a-peek-into-missing-data-with-pandas-2fb9e5df8bd0?source=collection_archive---------42-----------------------

PyTrix 系列

PyTrix #6:检测缺失数据

凯莉·西克玛在 Unsplash 上的照片

当我们观察到数据中缺少值时,这是因为没有数据值存储在观察的特定变量中。缺失数据在实践中极为常见,并且会对从数据中得出的结论产生很大影响,因此数据科学家的大部分时间都花在了数据清理上。

我们可能会有缺失数据的各种原因,例如,可能有未被调查者,可能只有在已经收集了一定数量的观察值后才开始收集特定特征,数据输入中出现错误,或者在某些情况下,参与者可能会随着时间的推移而退出-一般来说,可能有各种原因。

无论如何,给定一些先决条件(即,我们有一个想要解决的已定义的问题),我们想要从我们处理的数据中提取有意义的见解,这将意味着在我们开始处理数据集之前要面对缺失数据的问题。这样我们就避免了对一个仅由 45%的观察值代表的变量做出任何具体的结论。此外,在训练我们的机器学习算法时,缺失值可能会被我们的模型视为 0 或无穷大,这可能会对我们的训练结果产生一些严重的影响。

熊猫的例子

注意:对于此任务,我们将使用来自 Kaggle 的数据集,具体来说就是 分类特征编码挑战 代码可在下面的链接中找到。

[## kurtispykes/演示

github.com](https://github.com/kurtispykes/demo/blob/master/pytrix/pytrix_missing_data.ipynb)

我们将从使用pd.read_csv文档读入数据开始。

import pandas as pd *# load and peek at data*
df = pd.read_csv("../data/categorical_feature_engineering_raw/train.csv")
df.head()

图 1:df . head();该表太大,无法放入图像中(并且太大,无法显示列,因此出现省略号)。

在用于数据操作的 Python 框架 Pandas 中,缺失值被表示为NanNone,并且有多种方法来检查我们的数据中是否存在缺失值:

  • pd.isnull()
  • pd.notnull()
  • pd.isna()
  • pd.notna()
  • df.isna()
  • df.notna()
  • df.isnull()
  • df.notnull()

是的,我知道你在想什么,我应该用哪一个?嗯,你会发现它们之间最大的不同是,4 个是顶级函数,另外 4 个是 pandas dataframe 类(pd.DataFrame.isna())的方法。本质上,在数据帧级别上df.isna()df.isnull()是相同的,同样df.notna()df.notnull()也是相同的(它们实际上有相同的文档)——这种现象也适用于顶级函数。

为什么名称不同的多个方法做同样的事情?Pandas 建立在 NumPy 之上,NumPy 使用np.isnan()来检测丢失的值,因此它既没有**Na**也没有**Null**值。然而,Pandas 使用基于 R 数据帧的数据帧,并且 R 中的**Na****Null**是不同的东西——在这里阅读更多关于 R **Na****Null**T35 的信息,在这里查看我的答案来源

所以我想在这个意义上,我们可以选择让熊猫成为我们自己的,这是熊猫框架中的一个共同主题。

我通常使用df.isna()和相反的df.notna(),主要是因为它比df.isnull()df.notnull()需要输入的字符少。此外,我更喜欢用点符号直接访问数据帧,这排除了顶级函数(它们要求您将数据帧或系列对象作为参数传递)。

*# see what .isna() returns*
df.isna()

图 2: df.isna()为 DataFrame 中的每个元素返回一个 bool 值的掩码,指示一个元素是否不是安娜值。

作为理智检查,我将对pd.isna()做同样的事情…

pd.isna(df)

图 3: pd.isna(df)返回一个布尔值,表明是否缺少每个相应的元素。

好吧,这是一样的(你注意到你必须为顶层函数路径键入几个额外的字母吗——是的,我很懒)。现在我们可以检查df.notna()是否真的是df.isna()的倒数…

*# see what .notna() returns* df.notna()

图 4: df.notna()

尽管df.notna()的文档说明这个方法返回的东西和df.isna()完全一样(我个人觉得很困惑),df.notna()确实是相反的。

除此之外,让我们进一步挖掘我们的数据,以检查丢失的值。

df.isna().sum()>>>> 
id        0
bin_0     0
bin_1     0
bin_2     0
bin_3     0
bin_4     0
nom_0     0
nom_1     0
nom_2     0
nom_3     0
nom_4     0
nom_5     0
nom_6     0
nom_7     0
nom_8     0
nom_9     0
ord_0     0
ord_1     0
ord_2     0
ord_3     0
ord_4     0
ord_5     0
day       0
month     0
target    0
dtype: int64

Oooops,看起来我们有一个没有缺失值的数据集——这在现实世界中不太可能发生,所以我们将利用我们在 PyTrix 系列第 4 集中学到的一些技能来添加一些缺失值——链接如下。

[## 用熊猫切片和索引

PyTrix #4:用熊猫访问数据

towardsdatascience.com](/slicing-and-indexing-with-pandas-2bff05ec361e)

*# inputting NaN's randomly into data*
df.loc[2:1000:100, ["bin_0"]] = **None**
df.loc[:300:20, ["ord_4", "ord_5"]] = **None** 
df.loc[500::50, ["nom_4", "bin_4"]] = **None**df.isna().sum()>>>> 
id           0
bin_0       10
bin_1        0
bin_2        0
bin_3        0
bin_4     5990
nom_0        0
nom_1        0
nom_2        0
nom_3        0
nom_4     5990
nom_5        0
nom_6        0
nom_7        0
nom_8        0
nom_9        0
ord_0        0
ord_1        0
ord_2        0
ord_3        0
ord_4       16
ord_5       16
day          0
month        0
target       0
dtype: int64

太棒了。这意味着当我们使用逆方法时,df.notna()应该发生的是,缺失值的数量应该从特定列的行数中扣除,对吗?

*# how man non-null values?* 
df.notna().sum()>>>>
id        300000
bin_0     299990
bin_1     300000
bin_2     300000
bin_3     300000
bin_4     294010
nom_0     300000
nom_1     300000
nom_2     300000
nom_3     300000
nom_4     294010
nom_5     300000
nom_6     300000
nom_7     300000
nom_8     300000
nom_9     300000
ord_0     300000
ord_1     300000
ord_2     300000
ord_3     300000
ord_4     299984
ord_5     299984
day       300000
month     300000
target    300000
dtype: int64

没错。

为了只查看有特定缺失观察值的行,我们可以在调用 dataframe 后将一个条件语句传递到括号([])中,如下所示…

*# viewing only the rows where bin_4 = NaN* 
df[df["bin_4"].isna()]

图 bin _ 4 是缺失值的行

在不深入研究我们如何处理缺失值的情况下——这可能会在另一篇文章中讨论——接下来的几行代码将展示处理缺失值的最简单的方法(尽管不总是最好的方法)…删除它们!

*# priginal df shape*
df.shape
>>>> (300000, 25)*# df shape after dropping rows with any missing values* 
df.dropna(how="any").shape
>>>> (293984, 25)*# df shape  after dropping rows with all missing values*
df.dropna(how="all").shape
>>>> (300000, 25)*# dropping any row if it has NaN in ord_4 or ord_5*
df.dropna(subset=["ord_4", "ord_5"], how="any").shape
>>>> (299984, 25)

你们中的一些人可能已经注意到,当我在图 5 的中返回 bin_4 缺少值的行时,bin _ 4 列返回了一个None值,而不是NaN,如果您这样做了,请不要担心!这是另一个例子…

df[df["ord_4"].isna()]["ord_4"]>>>>
0      None
20     None
40     None
60     None
80     None
100    None
120    None
140    None
160    None
180    None
200    None
220    None
240    None
260    None
280    None
300    None
Name: ord_4, dtype: objectdf[df["bin_0"].isna()]["bin_0"]>>>>
2     NaN
102   NaN
202   NaN
302   NaN
402   NaN
502   NaN
602   NaN
702   NaN
802   NaN
902   NaN
Name: bin_0, dtype: float64

还记得我之前说的np.nan吗?很好。原来NaN是数据类型 float,因此当它在 object 数据类型列中使用时,它将其转换为None,当它在 int 上使用时,它将其转换为 dtype,如上面的示例代码所示。

包裹

Pandas 使检测数据帧中的缺失值变得非常容易,这在任何数据科学/机器学习工作流中都很重要。虽然我们没有通过 PyTrix 来处理丢失的值,因为这将是下周的主题,但是您现在知道如何在数据帧中发现丢失的值。

非常感谢你读到这个故事的结尾。如果您认为我遗漏了什么,或者您想向我指出什么,或者如果您仍然不确定什么,您的反馈是有价值的。发个回应!然而,如果你想和我联系,我在 LinkedIn 上是最活跃的,我也很乐意和你联系。

[## Kurtis Pykes -人工智能作家-走向数据科学| LinkedIn

在世界上最大的职业社区 LinkedIn 上查看 Kurtis Pykes 的个人资料。Kurtis 有一个工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/kurtispykes/)

与水力压裂有关的镭污染源的一瞥

原文:https://towardsdatascience.com/a-peek-into-sources-of-radium-contamination-related-to-fracking-d2d9749d9f44?source=collection_archive---------84-----------------------

介绍

随着非常规油气勘探的发展,一种称为水力压裂的新技术被广泛用于辅助油气生产。水力压裂的使用产生了大量的废水,其中含有高浓度的潜在污染物。

根据其不同的用途,废水有不同的术语,可分为钻井液(用于钻透泥浆和岩石)、注入液(注入以导致源岩破裂)、原始盐水(源岩中预先存在的盐水)和返回液(包括后期压裂液、回流水和采出水——后者的名称通常指流体返回地面的后期阶段)。

这些废水通常含盐量很高,含有大量天然放射性物质和重金属(见图 1)。例子包括钠(Na)、镁(Mg)、氯化物(Cl)、溴化物(Br)、镭(Ra)和钡(Ba)。这些化学物质在很多方面都有问题。例如,一旦与富含硫酸盐地表水混合,高浓度的钡将沉淀并在管道内形成水垢,从而阻碍生产效率。

图 1 显示不同废水类型的主要化学物种的盒须图。Brn、Drl、Flb、Frcl、Frce 和 Pw 是指盐水、钻井液、返排液、后期压裂液、早期压裂液和采出水。

值得注意的一点是:虽然从绝对值来看,Ra 浓度并不高,因此被认为是废水中的微量化学物质,但废水中 Ra 的含量已经比美国环境保护局建议的安全天然水中允许的含量高出 10,000 倍。因此,相对高水平的 Ra 成为严重的环境威胁,本工作旨在调查 Ra226 和 Ra228(废水中发现的最丰富的 Ra 形式)的潜在来源。

在这里,我查阅了从多个来源收集的化学报告数据(环境保护部、美国地质调查局和夸西等)。)并简要介绍了压裂过程中导致 Ra 污染的来源和过程。该化学报告数据总结了超过 100,000 条特征记录。本次调查包括 100 多种记录,例如:

  • 位置:县,纬度,经度
  • 时间:采集开钻年月日
  • 化学品:硫酸盐浓度(mg/L),Ra226 浓度(pCi/L)

镭污染有四个来源:钻井液、注入液、原始盐水和岩石。下面,我展示了我对如何划分 Ra 污染源的理解,然后比较了用于将 Ra 污染源与其他特征相关联的两种机器学习方法。

第一部分:镭污染源的划分

对于一种废水,为了划分化学物质的四个来源(三种流体和一种岩石),我们需要求解四个方程。但是因为我们已经知道岩石只提供有限数量的化学物质,而许多主要的化学物质只来自三种流体,所以我们可以先用三种流体求解三个方程:

  • A1 *流体 1 + A2 *流体 2 + A3 *流体 3 = A_target
  • B1 *流体 1 + B2 *流体 2 + B3 *流体 3 = B_target
  • 流体 1 +流体 2 +流体 3 = 1

其中,fluid1、fluid2 和 fluid3 是待求解的三种流体源的比例;a 和 B 是两种化学物质的测量浓度,这两种化学物质通常存在于流体中,但不来自岩石。研究表明溴和氯可以作为两种常见的化学物质。对于目标废水中的其他化学物质,剩余的未解释部分将由 rock source 提供。以 Ra 为例:% Ra _ from _ rock = 1-% Ra _ from _ all _ fluids。

图 2 来源于盐水、岩石、钻井液和注入液的 Ra226 比例分布图

上图显示了来自不同来源的含 Ra226(压裂废水中发现的最丰富的镭之一)的废水样本数量(图 2)。超过 250 个废水样本的 Ra226 完全由 rock 提供。除了这些样品,其他样品形成了一个偏态分布,平均大于 50%的 Ra226 来自原始盐水,小于 50%的 Ra226 来自岩石。由于钻井液和注入液由作业者直接提供,自然不含大量污染物,因此近 0%的 Ra226 来自这些流体。下面的 Ra228 来源图显示了与 Ra226 相似的分布,在数量上略有不同(图 3)。

图 3 来源于盐水、岩石、钻井液和注入液的 Ra228 比例分布图

现在我们知道 Ra 被认为是废水中的痕量化学物质,与废水中的主要化学物质(如镁)相比,它的来源分布有何不同?如图 4 所示,除了岩石溶解对废水中的 Mg 浓度有贡献的样品之外,大多数其他样品实际上都经历了 Mg 沉淀,这通过源自岩石的 Mg 的负百分比(例如-50%)来证明。

图 4 来源于盐水、岩石、钻井液和注入液的镁比例分布图

很明显,Ra 污染物的表现不同于压裂废水中发现的其他主要化学物质。与其他化学物质(如镁)相比,Ra 的来源更可能来自与岩石的相互作用。

下一个问题是,导致这种 Ra 源的因素是什么?具体来说,我们能否选择被测废水的重要特征,并用它们来预测来自盐水的 Ra 的百分比?什么特征对于确定来源于岩石的镭是重要的?我们尝试用回归模型预测实际值,也尝试用分类模型预测来源是否增加 Ra 浓度。

第二部分:使用线性回归模型来预测来源的比例

预测比例的线性回归模型按以下四个步骤开发:

  1. 基于我们想要预测的目标值(例如来自盐水的%Ra226 ),生成初始特征和结果(ML 模型中的 X 和 y)数据集;
  2. 通过移除原始线性回归模型中的异常值来清理数据;
  3. 使用套索法选择最重要的特征和最佳参数用于预测模型;
  4. 使用最终模型进行预测,并将预测结果与测量结果进行比较。

结果,上述四个步骤帮助选择了对来自盐水的%Ra226 的线性回归起重要作用的 18 个特征,并且为训练集和测试集分别生成了 0.775 和 0.686 的分数。预测结果与测量结果的 R 平方值为 0.68(图 5 左图)。对于来源于盐水的%Ra228,建模步骤在线性回归模型中选择 22 个重要特征,以 0.671 和 0.576 作为训练和测试分数。R 平方值为 0.475(图 5 右图)。

图 5 来源于盐水的预测与测量的%Ra226(左)和%Ra228(右)散点图

显然,线性回归模型在预测源划分结果方面表现不佳。精心选择的模型表现不佳,表明污染物 Ra226 和 Ra228 的来源百分比不一定与其他化学品的浓度相关。预测不佳也可能有各种原因,包括:样本量仍然太小,由于采样条件的可变性而导致的异常值太多,不一致的测量技术等。

现在,预测百分比似乎不够可靠,让我们试试运气,看看问题“Ra 是否来自盐水或岩石”是否可以用分类方法预测。

第三部分:使用分类模型预测污染源是否会造成污染

与构建线性回归模型类似,我们再次遵循四个步骤来预测我们的“是否”问题:

  1. 基于我们想要预测的目标值(例如来自岩石的%Ra226)生成初始特征和结果(ML 模型中的 X 和 y)数据集;
  2. 使用 feature_importances_ 为预测模型选择重要特征;
  3. 调整并选择决策树分类器中使用的最佳参数;
  4. 使用调整后的模型执行预测,并检查结果。

图 6 显示了用于确定 Ra226 和 Ra228 是否部分来源于岩石的所选特征和相应的重要性。它们自身的浓度、废水中 Cl 的浓度和取样位置在分类中起着最重要的作用。放射性核素和 Cl 的浓度越高,废水中 Ra226 和 Ra228 来自岩石的机会就越大。预测 Ra226 和 Ra228 是否来自岩石的训练和测试准确率分别为 100%和 83%,以及 93%和 86%。

图 6 确定%Ra226(左)和%Ra228(右)是否部分来源于岩石的重要特征柱状图。特征标签有:0-As(毫克/升)、1-B(毫克/升)、2-Ba(毫克/升)、3-Ca(毫克/升)、4-Cu(毫克/升)、5-Fe(毫克/升)、6-Li(毫克/升)、7-Mg(毫克/升)、8-Mn(毫克/升)、9-Na(毫克/升)、10-Se(毫克/升)、11-Sr(毫克/升)、12-Zn(毫克/升)、13-硬度(毫克/升)、14-碱度(毫克

具有岩石源的 Ra226 和 Ra228 的决策树模型的可视化表明,模型以低杂质或不确定性合理地构建,导致在每个节点处更好的分类或分裂。

图 7 有岩石源的%Ra226(左)和%Ra228(右)的决策树模型的部分图。

决策树模型在预测源分类方面似乎比回归模型在预测源分区值方面表现得更好。预测结果表明,污染物 Ra226 和 Ra228 的源分类与某些离子浓度相关,并且具有高度的位置特异性。

结论

本文探讨了水力压裂中 Ra 的来源以及在确定这些来源时可能起重要作用的特征。数据处理和机器学习的发展为 Ra 污染源提供了三种见解:

  1. Ra 污染主要来源于盐水和岩石;与其他化学品相比,它的岩石来源有助于提高废水中总浓度的百分比。
  2. 由于各种原因,线性回归模型不是预测源划分结果的好方法。较差的性能还表明,污染物 Ra226 和 Ra228 的来源百分比不一定与化学物质的浓度相关,而是更多地取决于它们在相应来源中的浓度。
  3. 决策树模型在预测源分类方面表现良好(或优于线性回归模型)。结果表明,某些化学物质的浓度和废水取样的位置是决定 Ra 是否部分来源于岩石的重要因素。

上述分析仅仅是观察和主观的,人们可能有许多方法来确定和解释压裂废水中的污染物。不同的数据处理方法可能导致不同的源成分和解释。此外,这种分析没有达到很高的准确性,主要是因为缺乏一致的采样和标记,以及样本量小,这为研究人员留下了更多的空间来重新访问和处理数据。要查看有关该分析的更多细节,请点击这里的链接查看我的 Github。

归纳机器学习的哲学困境

原文:https://towardsdatascience.com/a-philosophical-quandary-for-inductive-learning-a4ffbd63c3d2?source=collection_archive---------33-----------------------

我们有什么理由认为未来会与过去相似?

照片由德鲁·比默Unsplash 上拍摄

机器学习是基于归纳推理的。不像演绎推理,前提的真实性保证结论的真实性,通过归纳得出的结论不能保证是真实的。因此归纳推理本质上是概率性的。

在分类的上下文中,我们使用过去收集的训练数据,并根据我们发现的模式推断未来。例如,如果 90%的 X 档案的人在培训期间拖欠贷款,我们假设将来大约 90%的人会拖欠贷款。我们可以使用一个独立的测试集来检查这个推断的有效性,并验证我们的推断跳转的准确性。这种推论相当简单。奥卡姆会为这把剃刀感到骄傲。

但是,什么能证明这种逻辑上的跳跃呢?

从过去观察到的事件到未来未观察到的事件的这种跳跃,我们可以基于什么理由或原则?逻辑表明,支撑这种跳跃的一个自然原则是相信未来将与过去相似。大卫·休谟称这个重要的假设为“自然一致性原则”早在 18 世纪 40 年代,休谟就是第一个努力解决所谓的归纳问题的哲学家。然而,自那以后没有太大的变化。今天的哲学家仍然在努力为归纳推理提供逻辑证明。

无圆感应?

所以归纳推理的力量来自于自然的一致性。但是为什么要假设自然的一致性呢?我们如何为这个假设打基础?

因为在过去,过去与未来相似。但是等等,这个论证用归纳推理来证明归纳推理本身的有效性! 我们用归纳法 进行归纳推理的做法。这明显是循环的。休谟得出了一个著名的结论,即我们没有好的方法来证明这种推理性的飞跃。没有充分的理由相信从真实(或概率)结论得出的归纳结论。你也可能猜到休谟对诸如原因结果这样的“形而上学”概念持怀疑态度,但那是另一篇博文

自休谟以来,我们还没有走太远

科学哲学家韦斯利·萨蒙(Wesley Salmon)在 1953 年关于归纳问题的文章中总结道,“承认不合理和不合理的假设来处理[归纳]问题,就等于使科学方法成为一个信仰问题。”如果归纳的问题是基于一个信念的问题,那么这对机器学习,一套自动化归纳推理实践的巧妙方法意味着什么?机器学习的逻辑和科学基础也是基于信仰吗?或者可能有更深层次的逻辑原理来支撑我们对归纳推理的依赖?

纳尔逊·古德曼对归纳法的挑战:格鲁的例子

纳尔逊·古德曼在 20 世纪 50 年代写了一本简短但有影响力的书,名为事实小说,并预测。在书中,他给出了几个“谜语”,旨在突出归纳推理及其科学应用的一些逻辑问题。

古德曼想象存在一个被称为“grue”的谓词(我们可以归因于一个对象的属性)一个物体是灰色的,以防它在时间 t 之前是绿色的,之后是蓝色的。假设我们观察到,在过去,直到时间 t,1000 颗绿宝石是绿色的。然后,我们陈述,基于这一观察证据,一个假设,如“在未来所有的祖母绿将是绿色的。”

尼尔森指出的有趣的事情是,我们的证据可以支持两个同样有效但相互矛盾的假设:未来所有的绿宝石都将是绿色的,未来所有的绿宝石都将是灰色的。哪个是正确的?从表面上看,纳尔逊之谜表明,我们可以想象任意数量的关于物体的归纳合理的假设,并且每一个都和其他假设一样有效。正如这个谜语巧妙地说明的那样,将科学知识建立在归纳推理的基础上可能终究不是一个明智的选择。

古德曼对自己的谜题的解决方案是,建议我们更谨慎地对待我们赋予物体的谓词。他说,把谓语分成两类可能更有用:可投射的不可投射的。对于描述对象,像 green 这样的谓词比像 grue 这样的谓词更“根深蒂固”,因此我们可以将 grue 视为不可投射谓词的一个例子。

这对机器学习意味着什么?

假设当我们谈论原子粒子、分子或像岩石和树木这样的可感知物体时,自然的均匀性似乎没有太大问题。鉴于我们过去对它们的经验,我们相当确定地把各种属性和特性投射到未来。 但是这个原理在应用到人 身上时似乎明显被误导了。这很重要,因为记录的人的行为是机器学习的生命线,也称为行为大数据 (BBD)。如果没有 BBD,我们在日常生活中经常收到的自动推荐将不再起作用。

我在另一篇名为将人放回机器学习的文章中写过一些围绕机器学习个性化的概念问题。基本上,我的观点是,如果我们真的希望推断一个人的偏好、需求、欲望和兴趣,我们需要考虑他们的社会和道德身份、自我叙述以及他们丰富的内心生活的其他方面。目前,曼梯·里没有办法做到这一点,哲学家们认为这无论如何都是不可能的,因为主观经验(我对疼痛的感觉)和客观物理事实(C 纤维放电)之间存在的解释差距。

为什么归纳对机器学习个性化有问题(MLP)

人们在道德上和社会上以非传递性、非线性的方式改变和成长。归纳推理不能很好地解释我们道德身份的这种突然的结构变化。当我们意识到对人的描述既有内在的(主观的)也有外在的(客观的)时,MLP 遇到了进一步的问题。我在 A、B、C 阶段看到的自己可能是不同的。然而,从一个局外人的角度来看,如果 A=B and B=C,那么通过传递性,我们可以假设 A=C。但这在道德进步和发展的情况下不起作用。这尤其成问题,因为 MLP 表面上是通过利用我们观察到的行为来推断我们的兴趣、偏好和欲望。但是我们的兴趣、偏好和欲望只是我们共有的一系列道德价值观中的一小部分。当我们的道德价值观进化时,我们的兴趣、偏好和欲望也会进化。

不幸的是,对 MLP 来说,我们的价值观往往会以突然的、不可预测的方式改变,就像我们生活中发生重大事件或悲剧时一样。对预测科学来说,更困难的是道德进步似乎天生不可预测。回顾过去,道德进步——比如废除人类奴隶制——似乎是不可避免的。但是从过去的观点来看,道德实践似乎反映了基本的“自然法则”

从这里去哪里?

致力于推荐系统的研究人员已经开始理解归纳问题和自然一致性背后的假设。推荐系统现在经常在他们的预测中引入serendipity——本质上是在预测中加入一种随机性元素,以避免相同内容或用户账户的推荐的陈旧循环。例如, Instagram 的 Explore 就是这么做的。机缘巧合是反映个人道德成长的非线性和非传递性过程的第一小步。

我也希望看到更多的社会科学家参与数据科学,特别是他们可能会利用他们的定性数据收集知识,为个性化预测和建议提供新的输入。在机器能够学会区分事件的客观记录和个人叙述之间的区别之前,真正的个性化将是一个白日梦。

理解随机森林算法的图示指南

原文:https://towardsdatascience.com/a-pictorial-guide-to-understanding-random-forest-algorithm-fbf570a0ae0d?source=collection_archive---------47-----------------------

了解随机森林算法的内部工作原理

RandomForestClassifier 算法中发生了什么(图片由 pxhere.com 提供)

这篇文章是关于什么的

在本文中,我们将了解随机森林算法的内部工作原理。要真正理解它,了解一点决策树分类器可能会有所帮助。但是这并不是完全必需的。

👉 注意 :我们并不涵盖建模中涉及的预处理或特征创建步骤——而只是看看当我们为 sklearn 的RandomForestClassifier 包调用.fit().transform()方法时,算法 中的 会发生什么。

一段中的随机森林

随机森林(RF)是一种基于树的算法。它是不同种类的多个随机树的集合。模型的最终值是由每棵树创建的所有预测/估计的平均值。

包裹

我们的文章将基于 sklearn 的 RandomForestClassifier 模块

sklearn.ensemble.RandomForestClassifier

数据

为了便于说明,我们将使用类似于下面的训练数据。

训练数据快照(图片作者)

👉 : age ,glucose_level, weight, gender, smoking .. … f98, f99均为自变量或特征量。

Diabetic 是我们要预测的 y 变量/因变量。

问题是

预测可能患糖尿病的患者。

内部真正发生了什么

有了这些基本信息,让我们开始并理解当我们将这个训练集传递给算法时会发生什么…

步骤 1 —引导

随机选择记录或自举(图片作者)

一旦我们向RandomForestClassifier 模型提供了训练数据,它(算法)就会随机选择一组行。这个过程称为引导(随机替换)。对于我们的例子,假设它选择了 m 个记录。

👉注 1 : 要选择的行数可以通过使用超参数- (max_samples)中的 r 来提供,就像代码中这样

import sklearn.ensemble.RandomForestClassifiermy_rf = RandomForestClassifier(max_samples***=****100)*

👉注 2 : 这仅适用于在超参数(bootstrap = True)中打开自举的情况。bootstrap 默认为真。

👉注 3: 一行可能会被选择多次

步骤 2 —为子树选择特征

选择小型决策树的功能

现在,RF 随机选择特征/列的子集。这里为了简单起见,我们选择了 3 个随机特征。

👉您可以在超级参数— max_features 中控制这个数字,类似于下面的代码

import sklearn.ensemble.RandomForestClassifiermy_rf = RandomForestClassifier(***max_features=****3)*

步骤 3 —选择根节点

一旦选择了 3 个随机特征(在我们的示例中),该算法将对 m 记录(来自步骤 1)进行拆分,并对指标的值之前和之后的进行快速计算。

这个指标可以是基尼系数或者是熵。它基于您在超参数中提供的标准— ginientropy

import sklearn.ensemble.RandomForestClassifiermy_rf = RandomForestClassifier(max_features=8 , **criteria = 'gini'**)

criterion = 'gini' (或“entropy”)

默认设置为criteria = 'gini’

哪个随机特征分裂给出最小的组合基尼不纯度/熵值,该特征被选为根节点。

根据最佳分割点,在此节点分割记录。

步骤 4 —选择子节点

随机选择特征

该算法执行与步骤 2 和步骤 4 相同的过程,并选择另一组 3 个随机特征。(3 是我们指定的数字—您可以选择您喜欢的数字—或者让算法选择最佳数字)

根据标准(gini / entropy ),它选择哪个特性将进入下一个节点/子节点,并且在这里进一步分割记录。

步骤 5—进一步拆分和创建子节点

继续选择特征(列)以选择更多的子节点

现在我们有了第一级子节点

该过程继续(步骤 2、4)选择随机特征,并且发生节点的分裂,直到以下任一条件发生

  • a)您已经用完了要拆分的行数,或者已经达到了阈值(每个子节点中存在的最小行数),您可以在 hyper 参数中指定这一点— min_samples_leaf
  • b)分割后的基尼系数/熵值不会降低到超过规定的最低限度
  • c)您已达到您指定的分割数(max_depth)

你现在有了你的第一个“迷你决策树”。

使用随机选择的行(记录)和列(特征)创建的第一个小型决策树(作者图片)

步骤 6 — 创建更多小型决策树

算法返回到您的数据并执行步骤 1-5,以创建第二棵“迷你树”

这是我们使用另一组随机选择的行&列创建的第二个迷你树。注意:如果您仔细选择了超参数,这个迷你树的结构将与第一个不同。

第七步。建造树木的森林

一旦达到 100 棵树的默认值(您现在有 100 棵迷你决策树),就可以说模型已经完成了它的fit()过程。

100 棵树中的 2 棵树

👉注意:你可以在你的超级参数( n_estimators)中指定你想要生成的树的数量

import sklearn.ensemble.RandomForestClassifiermy_rf = RandomForestClassifier(***n_estimators=300****)*

我们继续构建迷你树,直到我们有 n 棵树(n 是由 n_estimators 超参数指定的数字,如果我们没有指定任何东西,它的默认值是 100)。这里,蓝框代表结束节点。(图片作者)

现在你有了一个随机创建的迷你树森林(因此得名随机森林)

第七步。推理

现在让我们预测一个看不见的数据集(测试数据集)中的值

为了推断(通常被称为预测/评分)测试数据,算法通过每个迷你树传递记录。

从测试数据集预测第一行(作者图片)

记录中的值根据每个节点代表的变量遍历迷你树,最终到达一个叶节点。基于该记录结束的叶节点(在训练期间)的预定值,该迷你树被分配一个预测输出。

以同样的方式,相同的记录通过所有 100 个小型决策树,并且 100 个树中的每一个都有该记录的预测输出。

所有的迷你树为那个记录做一个预测。(图片作者)

这个记录的最终预测值是通过对这 100 棵小树进行简单的投票计算出来的。

现在我们有了对单个记录的预测。

该算法按照相同的过程遍历测试集的所有记录,并计算出总体准确度

重复获取测试集每一行的预测的过程,以达到最终的准确性。

参考

[1] sklearn 的 RandomForestClassifier 文档(版本:3.2.4.3.1)

https://sci kit-learn . org/stable/modules/generated/sk learn . ensemble . randomforestclassifier . html

没有真实数据的学习姿态估计的流水线

原文:https://towardsdatascience.com/a-pipeline-for-learned-pose-estimation-with-no-real-data-3df0599fd90e?source=collection_archive---------26-----------------------

实践教程

使用领域随机化和深度学习来估计 3D 模型的姿态

姿态估计是计算机视觉领域的一个新兴趋势,使研究人员能够利用图像中的深度信息——这是 AR 和其他空间相关应用的必要条件。从传统的计算机视觉开始,现代研究使用深度神经网络直接预测 6D 姿势(即旋转和平移),例如通过最小化来自已知扰动的误差,或者直接将 3D 模型拟合到输入图像。

在这篇文章中,我将展示一个完整的基于神经网络的姿态估计管道,使用随机生成的低保真度渲染数据。具体来说,我们将探索仅使用 3D 模型生成图像和地面真实数据,以及为姿势估计估计关键点(以及如何做)。

在我的上一篇帖子中,在这里找到了,我们探索了仅使用简单的 Unity3D 引擎生成的合成数据来训练对象检测器的方法。对象检测器通常不需要使用合成数据,因为有各种各样的注释工具可用,相反,它大大简化了过程并降低了输入成本。然而,姿态估计更难以手动注释,尤其是如果你不想估计包含在 LineMOD 或类似数据集中的对象的姿态。

领域随机化(DR)是为这样的项目生成数据的完美方法。简而言之,DR 旨在扩大生成数据的方差,以便生成的样本包含现实生活中的数据分布。这篇帖子很好地描述了这个概念。这是我们将用于为此项目生成数据的方法;仅使用 3D 模型的任意对象的 6D 姿态估计的端到端解决方案。

数据生成

对象检测帖子中,我展示了我们的 Unity3D 数据生成器,一个简单的低保真度图像和边界框生成器。对于这个项目,我们感兴趣的不仅仅是边界框——事实上,我们需要一个完整的相应的对象的 3D 表示。我将遮罩着色器从生成器更改为一个归一化对象坐标空间(NOCS) 着色器,它将对象的局部 XYZ 空间渲染为 RGB,并用 Alpha 指示对象是否存在于像素中。下面可以看到一个例子:

渲染和裁剪的图像(左)及其相应的 NOC 表示(右)。作者图片

生成 NOC 图像时,禁用任何类型的抗锯齿都很重要。插值会洗掉数据,我们的最终产品会不太精确。根据图像的大小和限制的严格程度,我们可以在一台像样的笔记本电脑上每秒生成数千到数十万张这样的图像。与注释真实图像相比,这可以给我们带来显著的优势。

关键点和注释

我们决定利用传统、成熟的计算机视觉技术来估计物体的姿态,即解决物体的 2D 到 3D 投影,也称为透视 n 点问题。这也为项目提供了额外的健壮性,因为关键点表示比试图直接适合图像要抽象得多。这是我们的优势,因为我们的对象从一个图像到另一个图像改变外观,以提高最终产品的通用性。为了做到这一点,我们需要在整个项目中建立一组基线关键点。

跟踪的关键点在许多渲染的顶部可视化。作者图片

好的、可追踪的关键点很难获得。幸运的是,我们有几乎无限数量的感兴趣的对象(在这种情况下,博世钻)的渲染图像及其各自的 3D 表示和遮罩。我们可以将所有超大像素归零,并使用 OpenCV 的“goodFeaturesToTrack”方法来找到钻头的可跟踪角落。该方法为我们提供了以质量水平 q 和最小像素距离 d 为阈值的 N 个可跟踪特征的像素位置。我们可以使用相应的 NOCS 图像将输出特征位置转换到对象的局部空间。我们决定 N=32,q=0.2,d=√(min(image_width,image_height))。

然而,最终这只会返回数千个不连贯的 3D 位置。为了实际确定哪些是最好的,我们使用 K-Means 来寻找这些可跟踪位置的大簇的质心。我们再次决定寻找 32 个关键点。使用这个简单的方法有一些缺点;首先,关键点可能永远不会准确地出现在模型上,而是稍微在模型内部,这取决于群集的大小和位置。其次,该对象是随机生成的,并且是对称的,这意味着平均而言,在一侧找到的关键点看起来与它们(潜在的)镜像伙伴一模一样。

基于关键点与 NOCS 图像中最接近的表示的距离来排除关键点的不同阈值。作者图片

在分析了成千上万的图像并使用上述方法建立了基线关键点之后,我们可以针对每个图像-NOC 对,计算最准确地表示每个关键点的像素。这必然会有一些误差,所以我们对其进行阈值处理,以排除不在图像中特定距离内的关键点。当然,这个边距应该根据对象的大小来设置。上图显示的阈值范围从 1 厘米到 0.1 厘米,假设钻头大约 22.3 厘米高。

在合成数据上训练关键点检测器

既然我们有 32 个基线关键点,并且可以估计它们在训练数据中的位置,我们需要能够在图像中准确地检测它们。我们希望利用卷积神经网络(CNN)提供的强大的视觉抽象,所以这就是我们将开始的地方。

很简单,人们可能会认为这是一个回归问题,因为我们只想为每个关键点估计两个数字(一个 X 坐标和一个 Y 坐标)。然而,问题并非如此简单。空间感知是关键,如果不在网络中特别考虑这一点,这些信息将在完全卷积层和池中丢失。为了避免这个问题,我们采用了一个具有 32 个输出层的 U-Net 风格的 CNN,每个输出层对应一个关键点。该模型创建于 PyTorchfast.ai 。具体来说,我们的网络包括:

  • ResNet34 的前 7 个(下采样)模块,预训练并锁定开始
  • 2 个上采样模块,利用跳过连接和 ICNR 像素溢出进行升级
  • 生成输出热图的最终 1 宽 Conv 图层

我们的目标目前只是一系列数字(32 个关键点,它们在帧中的位置,以及从它们的质心到该位置的真实距离)。我们需要我们的网络可以比较和学习的目标。为了实现这一点,我们将关键点栅格化为 2D 高斯曲线,而不是简单的 1 像素步骤。这极大地改进了训练,因为网络不会因为接近但不完全的预测和非常差的预测而受到同等的惩罚。

所有 32 个光栅化关键点覆盖在示例渲染的顶部。作者图片

现在,并不是所有的 32 个关键点都与每张图片相关。有些超过了我们设定的距离阈值,因此必须以某种方式丢弃。我们发现,简单地忽略它(在计算损失时屏蔽掉热图)并让网络决定是否画出它比试图抑制它或强迫它更有效。

损失和培训计划

现在我们有了一个数据点(一个钻孔的渲染图像)和一个目标(32 个热图),我们只需要一个损失函数。我们可以看到,简单地将目标热图与输出热图进行匹配(忽略不可见点)应该可以提供一个不错的起点——均方误差。这在一定程度上是好的,在这种情况下,网络通过减弱或多次猜测学会作弊。我们也可以通过引入回归损失来补偿这一点。2D SoftArgMax 函数允许我们将网络估计的热图减少到亚像素精度的猜测,非常适合我们的项目,该项目输出的热图比输入图像的比例小。

现在我们已经创建了两个损失,我们需要确定它们之间的权重。现在,像素损失(MSE)可以显著地帮助网络学习初始表示,但这最终不是我们感兴趣的。最后,我们需要图像中关键点的位置。我发现从 100%的像素损失开始,并稳步走向回归损失效果很好。

在整个训练中,我建议在每个时期后稳步减少损失。我们不希望网络过度适应合成数据的特征,但是我们也不希望永远等待,所以我们从相当高的值开始(使用 Adam 优化器,在 0.01 的范围内)。几个时期之后,当我们相信网络已经开始学习适当的表示时,我们解锁初始 ResNet 层,允许下采样层也学习。

我测试了批量大小为 32 的 1000 次迭代的 20 个时期的训练方案。在每个时期结束时,我们更新组合损失和学习率的权重。它们由总共 200000 幅渲染图像中的 32000 幅图像组成,这意味着各个时期会有一些重叠。随着以后时代学习率的严重下降,这一点就不那么重要了。最后,我们的损失曲线看起来有点像这样:

损失(像素级 MSE 和回归损失的组合,由以下公式给出:ploss *0.5^ᵉᵖᵒᶜʰ+r loss *(1–0.5^ᵉᵖᵒᶜʰ).作者图片

有两件事需要注意:训练损失在某些地方偏离很大,即下采样层(时期 5)的初始释放以及回归损失的每次增加和像素损失的随后减少。另一个值得注意的观察是验证损失,它相对于没有明显过度拟合迹象的训练损失如何稳定。这可以部分地归因于学习率的稳定下降以及与变化的组合损失权重相结合的分裂训练集。

实际上,避免过度适应 Unity 渲染器的数据分布几乎是不可能的。这可能会在现实生活的实验中引入伪像,例如由对象和 3D 模型不匹配引起的伪像。克服这一障碍的一种方法是注释由现实世界中的图像组成的附加训练集,在现实生活的图像上微调关键点检测器以解决 sim2real transfer 问题。

结果

现在网络已经训练了一段时间,让我们看看它是否能检测到一些关键点。

左:实际栅格化热图和确定的可见关键点叠加在图像上。中间:输入图像。右图:由神经网络估计的热图和关键点覆盖在图像上,丢弃的关键点映射到左上角。作者图片

这看起来相当准确,但是当然不能保证关键点是正确的。我们可以这样想象它们目标旁边的热图:

热图。左:图像。中间:目标热图。右图:估计的热图。作者图片

那看起来也很不错。这应该意味着,知道了 3D 模型的物理尺寸,以及随后其中的关键点位置,以及相机参数,我们可以将点投影到对象空间中。

首先,我们估计摄像机的固有参数。其次,我们需要通过阈值化来确定要屏蔽哪些关键点。我们之前决定在 NOCS 图像中使用距离,但是这对于验证图像是不可行的,因为理论上我们没有目标数据。相反,我们决定一个阈值,并包括满足条件 max(heat map)≥threshold * max(all _ heat map)的任何关键点。最后,我们可以利用 OpenCV 的 SolvePnP 和迭代求解器来估计相机的旋转和平移——速度较慢,但结果更稳定。

投影到物体空间的盒子。左:基线,使用阈值化的已知关键点。右图:使用我们模型中的热图进行估算。作者图片

现在,最后一个障碍是:用合成数据训练的模型在现实世界中的表现如何?我使用 Unity 和 ARFoundation 制作了一个快速请求/响应服务器和移动应用程序来测试预测的准确性。在我们上一个项目中,我们取得了一些非常好的成果。让我们看看能否复制它们:

我们管道的真实结果。Unity 应用程序向服务器发送图像和相机内部图像,服务器计算并返回钻头的预测边界框。作者图片

这些结果看起来很不错。有几个明显的错误,但钻头的大致方向及其在相机空间内的大小是清楚的。同样,神经网络从未见过真正的演习,也没有见过图像捕捉和压缩的人工制品,因此它在如此短的时间内就能猜出这口井是一个巨大的成功。

你有它!从 3D 模型到结果的姿态估计的完整管道。我们探索了在 Unity 中使用域随机化的数据生成、关键点估计和训练神经网络来预测它们的位置,以及将它们投影到 3D。结果显示了很大的希望,相当稳健地转换到现实世界的图像数据。这只是表明,合成数据可以成为进入深度学习和计算机视觉世界的巨大敲门砖,几乎没有成本。

我在 Alexandra Institute 工作,这是一家丹麦非营利公司,专门研究最先进的 it 解决方案。在视觉计算实验室,我们专注于利用最新的计算机视觉和计算机图形研究。我们目前正在探索数据收集和注释的选项,以允许较小的公司和个人开始深度学习。我们永远欢迎合作!

数学背景的潜在数据科学基础

原文:https://towardsdatascience.com/a-potential-data-science-foundation-for-math-backgrounds-188b03b9f1ff?source=collection_archive---------33-----------------------

帮助您开始学习数据科学的课程指南

米尔科·布利克在 Unsplash 上拍摄的照片

你决定投身数据科学领域!恭喜你。但是也许你还不确定你想在这个领域做什么,但是你昨天就想进去了。许多人主张你应该投入到自己的项目中去,了解你需要什么。虽然这是一个很好的方法,你会从中学到很多东西,但你可能会因为缺乏编码背景而不适应这种方法。你可能更喜欢先学习几门课程,为解决项目打下基础。

没关系。所以让我来帮你。

照片由埃里克·麦克莱恩Unsplash 上拍摄

作为一个有数学背景的人(纯数学硕士),这是我的问题。我想进入这个领域,但除了多年前参加的一个随机 JavaScript 课程之外,我没有足够的编码技能。我也不知道我喜欢数据科学的哪一个方面,因为这个领域还没有为每个子领域做出区分的标题。

在这里,我会告诉你我对你可以选择哪些基础课程的看法,以及为什么。这一选择是基于我尝试进入该领域的经验以及我现在作为数据科学家的经验。如果您仍然不确定想要深入数据科学领域的哪个部分,这可能是一个有用的选择。在解释的最后,我还会按照这种格式提供我上过的具体课程。如果你只是想看一个没有解释的快速列表,只需看下面:

  1. 一门 Python 或者 R 编程课程。
  2. 一门 SQL 课程。
  3. 数据操作/可视化课程。
  4. 一门机器学习课程。
  5. 深度学习课程。

现在解释一下!

Python 或 R 编程课程

克里斯里德 T21 在 Unsplash 上的照片

Python 或 R 的目的是为您提供一种方法,来执行您在数据科学中需要的所有酷技术。它们是达到目的的手段。您将使用的数据是您无法用笔和纸操作的数据。

你可以两种都尝试,但是不管你选择哪种语言,你都需要掌握一种主要的编程语言技能。原因是您从一种语言中学到的概念(如循环、内置函数和其他编程概念)可以带到其他语言中。如果你擅长一门编程语言,你也可以更轻松地取得成就。

在我的例子中,我选择了 Python 。这种语言被认为是一种伟大的通用编程语言,这意味着它可以处理一切,包括数据操作、可视化、机器学习和 web 开发。如果你仍然对选择一种编程语言犹豫不决,我觉得学习 Python 是一项安全的投资。你也可以下载 Anaconda 进行快速设置。

SQL 课程

照片由卡斯帕·卡米尔·鲁宾Unsplash 上拍摄

学习数据科学时,您可能不需要 SQL,因为您可能处理的许多数据不会占用太多内存。但是套用一位来自采访的谷歌数据科学家的话:

“如果数据适合你机器的内存,你可以使用任何东西。否则使用 SQL "

我在目前的职位上发现了这一点。通常情况下,至少有一百万或更多行的数据集。为了在 Python 中使用它进行进一步的分析,或者为机器学习模型做准备,SQL 已经变得必不可少。SQL 允许你过滤数据以适应内存,并通过 Python 或 r 在你的机器上平稳运行。无论你选择哪种语言,都要把 SQL 作为你的第二语言。

数据操作/可视化课程

照片由 Deb KennedyUnsplash 上拍摄

处理数据是任何数据科学任务的关键。它将允许你以一种揭示不为人知的故事的方式来观察数据。它将允许您格式化您的数据,以使您的机器学习模型产生最佳结果。据说该领域 80%的工作是数据清理和操作。你会很快发现,当你经历特定的课程或你自己的项目时。

在数据操作之后是可视化数据的需要。你需要理解你的数据在说什么。同样,数据背后的故事是什么?要为机器学习模型正确准备数据,您需要了解数据的原始形式。探索性数据分析(又名可视化)是上述所有工作的关键。

机器学习课程

安迪·凯利Unsplash 上拍摄

机器学习是解决与执行动作相关的问题,这些动作由于不明确的变量(以及大量变量)而无法直接编程。这就是以下技术的来源:

  1. 预测房价
  2. 对植物是否为毒藤进行分类
  3. 确定患者是否患有癌症
  4. Youtube 根据您的观看历史向您推荐视频

如果你对解决这类问题感兴趣,那么你绝对应该学习机器学习。如果你有兴趣学习如何构建自动化任务的软件,学习机器学习将帮助你处理这些自动化任务。另一个原因是一些基本的分类回归技术属于你将在统计学中学习的相同技术,例如线性回归。

深度学习课程

罗西·克尔在 Unsplash 上拍摄的照片

深度学习是机器学习的一个子领域,其中使用所谓的神经网络来建立模型。这些神经网络允许重型计算产生比你在你选择的机器学习课程中学习的模型更好的结果。

如果你对任何与图像数据文本数据相关的东西感兴趣,我会推荐你深入深度学习(双关语)。当前与图像和文本数据相关的进步要归功于深度学习及其神经网络结构。

我遵循这个指南选择的路线

Lili PopperUnsplash 上拍摄的照片

下面是我按照这个指南的链接所选的课程列表(按顺序排列)。

注意:这些不是附属链接,我也不是这些平台的赞助商。把这个放在这里以防有人担心。

  1. Python 课程——solo learn Python。我选了这门 Python 课程,因为它是免费的,课程很快,而且它很好地概述了这门语言。也可以在你的手机上用他们的应用程序完成,并允许实验。
  2. SQL 和可视化课程数据科学 A-Z:包含真实数据科学练习。这是我上的一门 Udemy 课程,它让我对数据科学有了一个很好的了解。这就是我通过 Tableau 学习可视化,通过微软 SQL 学习 SQL 的地方。
  3. 数据操作课程——Python A-Z:数据科学用 Python,带实操。这是我学习数据操作和更多 Python 特有的可视化工具的课程。看完本课程后,您现在可能会认为第一个课程是多余的。第一门课没有提到的是课程的概念,如果你决定走一条机器学习工程师的路线,这是必须的。
  4. 机器学习课程——机器学习 A-Z:数据科学中的动手 Python&R。这是我学习机器学习的课程。最近更新的。本课程是对机器学习技术的一个很好的概述。它还包括一些关于深度学习的部分,以便对它有一些初步的了解。除了深度学习部分,这门课的大部分内容都是 Python 和 R 代码。
  5. 深度学习课程——深度学习 A-Z:动手人工神经网络。这是我为了对深度学习有个总体了解而选的课程。如果你学习上面的机器学习课程,你可以跳过前两个部分,因为它们完全相同。也给你机会分类图像。

现在,您可能已经注意到,这些课程中的大多数是:

a)来自 Udemy

b)有一个相似的标题,因为…

c)他们都来自同一个导师。

这都是真的。我发现,在这两位先生的前两门课之后,我从他们的教学风格中获益匪浅。所以我坚持和他们在一起,我很高兴我这样做了。我同意支付课程费用,因为当时课程费用大约是 10-11 美元。Udemy 总是随机销售,所以你可以等到那时。现在我看到的最低价格接近 12 美元。其他原因是,Udemy 可以让你永远保留课程,并可以在手机上观看视频。

轮到你了

维多利亚诺·伊斯基耶多Unsplash 上拍摄的照片

有很多课程涵盖了与上述课程相同的内容,只是有些不同。重要的是选择一门对你最有益的课程。我建议,如果你能尝试和坚持一个平台,使课程管理更容易。但是如果你可以在不同的平台间跳跃,那也没关系。如果你想听听关于这个问题的第二种意见,看看这个由 Kenjee 制作的视频,它讨论了你可以开始学习的免费课程。

最后的想法

感谢阅读这篇文章!如果你觉得这篇文章很有帮助,并想为你的数据科学之旅获得更多提示,请查看下面的文章。

[## 我的数据科学之旅给你的 11 个建议。

帮助您更成功地进入数据科学的提示。

towardsdatascience.com](/11-tips-for-you-from-my-data-science-journey-df884faa9f3) [## 为什么专注对您的数据科学之旅至关重要

以及它将如何节省您进入该领域的时间

towardsdatascience.com](/why-focus-is-key-for-your-data-science-journey-b62715b2a1c)

再说一遍,这个指南是基于我的经验,因为我已经有了很好的数学背景。不管你做什么,确保你尽快花时间在你自己的项目中练习你所学的东西。不要陷在教程炼狱里!

如果你有你尝试过的并且对你有帮助的课程,请留下评论给其他人看。你可以通过这个简单的行为在未来帮助别人。

你可以在 LinkedinTwitter 上关注或联系我。对 Twitter 上的 DM 开放。

直到下一次,

约翰·德杰苏斯

监督学习的实用方法

原文:https://towardsdatascience.com/a-practical-approach-to-supervised-learning-63a9e9075b17?source=collection_archive---------26-----------------------

弗兰·基·查马基在 Unsplash 上的照片

机器学习是教会机器从数据中做出决策的艺术。有多种算法可以帮助计算机分析数据并获得有价值的见解,从而帮助它对以前从未见过的新数据集做出决策。这些算法大多属于以下三类之一:

  1. 监督学习:从标记数据中学习的算法,并对从未见过的数据进行预测。
  2. 无监督学习:试图在未标记数据中找到模式和相似性的算法,以便可以相应地对其进行聚类。
  3. 强化学习:允许与环境进行交互的算法,它们的性能通过奖惩系统进行优化。

在本文中,我们将重点关注监督学习(SL) 方法。如前所述,SL 使用有标记的数据,并根据无标记的数据给出其预测。被标记的数据是已经被分类到一个或多个类别中或者已经被赋予特定值的数据。例如,存在参加校际比赛的不同学校的所有学生的数据,那么,在这种情况下,学校名称可以用作对学生进行分类的标签。在另一种情况下,如果有多栋面积不同的房子,它们的成本取决于它们的面积,那么在这种情况下,成本可以用作标签。尽管在这两个实例中,数据都被标记,但它们的标记类型却大不相同。在第一个例子中,标签的数量是离散的,而在第二个例子中,标签是一些十进制值,因此本质上是连续的。SL 在此基础上进一步分类:

  1. 分类:要预测的值是分类的和离散的。
  2. 回归:待预测值本质上是连续的。

分类

在许多情况下,您会使用分类方法对分类数据进行预测。各种示例包括将电子邮件分类为垃圾邮件或非垃圾邮件、癌症是恶性还是良性、将植物或动物划分为一个王国和物种等。分类问题中使用了许多不同的算法。其中一些是:

  1. 逻辑回归
  2. 支持向量机(SVM)
  3. k-最近邻
  4. 决策图表

在这里,我只会展示 k-NN,但会在即将到来的博客中写其他人。此外,我将使用 scikit-learn Iris 数据集(Fisher,UC Irvine ),它包含三个类,每个类有五十个实例。

k 近邻分类器

这是一个最简单和超级容易学习的分类算法。k-NN 算法背后的主要思想是,彼此接近的元素将属于同一类别。对于所有的数据点,这可能是真的,也可能不是真的。它通过查看“k”个最接近的标记数据点来预测数据点的标记。未标记的数据点将被分类到在“k”个最接近的数据点中占多数的类别中:

k = 3 和 k = 5 的 k-NN 分类

在上图中,您可以看到 k-NN 分类器对两个不同的“k”值所做的预测。在这两种情况下,分类器做出了不同的预测。这可能会引起你对 k 值的思考,但是不要担心,我稍后会谈到它。既然你对这个算法有了清晰的直觉,让我们在 Iris 数据集上实现它,看看它是如何工作的。

首先,让我给你一些虹膜数据集的见解。这是一个包含花卉数据的非常简单的数据集。它包含四个特征,即花瓣长度花瓣宽度萼片长度萼片宽度。它还包含目标变量,即花卉种类,即杂色海滨锦葵Setosa 。这三个标签各有五十个实例。

首先,导入您以后可能需要的所有库是一个好习惯。

from sklearn import datasets     #importing datasets from sklearn
import pandas as pd              #importing pandas with an alias pd
import numpy as np               #importing numpy with an alias np 
import matplotlib                #impoting matplotlib
import matplotlib.pyplot as plt  #importing pyplot with an alias plt

注意,我从sklearn导入了datasets模块。这将有助于加载虹膜数据集。现在,对给定数据进行探索性数据分析是一个好主意。为了做到这一点,你必须首先加载虹膜数据集,并将其分配给某个变量,在本例中为iris:

iris = datasets.load_iris()

这个数据是以Bunch的形式出现的,您可以使用type(iris)来检查它。Bunch类似于字典,因为它也包含键值对。让我们检查这个数据集的键,可以使用print(iris.keys())来完成,它输出dict_keys([‘data’, ‘target’, ‘target_names’, ‘DESCR’, ‘feature_names’, ‘filename’])data包含所有特征的数据,即花瓣长度、花瓣宽度、萼片长度和萼片宽度,target包含数字形式的目标值(即,0 代表 Setosa,1 代表 Versicolor,2 代表 Virginica),target_names包含目标变量的名称(即,Setosa,Versicolor,Virginica),DESCR包含关于其贡献者的数据集描述、统计数据和更多内容,feature_names包含特征的名称(即,萼片长度(cm),萼片 花瓣长度(cm),花瓣宽度(cm)),最后,filename包含文件的加载位置。

让我们从 iris 中提取出datatarget,将它们分别赋给某个变量XY

X = iris['data']
Y = iris['target']

要对数据执行进一步的操作,您应该将数据转换成 pandas 数据帧,并将其分配给某个变量,比如使用:

df = pd.DataFrame(X, columns = iris.feature_names)

使用pd.plotting.scatter_matrix(df, c = Y, figsize = [15, 10],s=150)对 Iris 数据集进行可视化探索性数据分析,将得到一个输出:

如您所见,对角线由对应于行和列的特征直方图组成,非对角线图是列特征和行特征的散点图,由它们的目标变量着色。很明显可以看到特性值和目标变量之间的相关性。让我们分别绘制花瓣长度和花瓣宽度的散点图,并清楚地看到这种相关性。它可以用以下公式绘制

plt.scatter(df[‘petal length (cm)’], df[‘petal width (cm)’], c = Y):

在这里,相关性变得更加明显。紫色图对应于 Setosa,蓝色图对应于 Versicolor,黄色图对应于 Virginica。

在我们的数据集上训练模型之前,将它分成训练集、验证集和测试集是非常重要的。这里,我将把我的数据分为训练集(70%的数据)和测试集(30%的数据)。Scikit-learn 使用其train_test_split模块帮助我们非常容易地做到这一点。为此,您必须首先使用from sklean.model_selection import train_test_splitsklearn.model_selection导入它。它返回四个数组:定型数据、测试数据、定型标签和测试标签。我们将这些分解为四个变量,本例中为 X_train、X_test、y_train、y_test:

from sklean.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, 
                    test_size = 0.3, random_state = 21,stratify = Y)

test_size参数决定分配给测试集的数据百分比,random_state为在训练和测试中分割数据的随机数生成器设置种子(每次设置相同的种子将产生相同的分割),startify被设置为包含标签的数组,以便标签像在原始数据集中一样分布在训练和测试集中。

最后,是时候实现分类器了,但是首先,我们需要使用from sklearn.neighbors import KNeighborsClassifier导入它,然后通过使用knn = kNeighborsClassifier(n_neighbors = 6)设置邻居的数量来实例化分类器。这里,我从邻居数等于 6 开始,并将其赋给一个变量knn。为了训练模型,scikit-learn 提供了fit()方法,因为我们试图将数据拟合到我们的分类器,然后对新的未标记数据进行预测,它提供了predict()方法。我们在使用train_test_split生成的训练集上训练模型,稍后将在测试集上进行预测。

from sklearn.neighbors import KNeighborsClassifier
knn = kNeighborsClassifier(n_neighbors = 6)
knn.fit(X_train, Y_train)   #training on the X_train, Y_train
knn.predict(X_test)         #testing on the X_test

这将输出测试集的预测标签数组:

array([2, 1, 2, 2, 1, 0, 1, 0, 0, 1, 0, 2, 0, 2, 2, 0, 0, 0, 1, 0, 2, 2,2, 0, 1, 1, 1, 0, 0, 1, 2, 2, 0, 0, 1, 2, 2, 1, 1, 2, 1, 1, 0, 2,1])

为了检查我们的模型的准确性,我们对我们的测试数据和标签使用 k-NN 的score()方法,knn.score(X_test, Y_test)给出0.955555555556。对于这样一个简单的模型来说,这是一个不错的结果。

“k”的值在这个分类器中很重要。较小的“k”值意味着模型非常复杂,可能导致过度拟合(模型试图拟合正确类别中的所有点),而较大的“k”值意味着模型不太复杂,决策边界更平滑,这可能导致拟合不足(模型不拟合大多数明显的点)。有一个更好的“k”值,它既不太大也不太小,不会导致过拟合或欠拟合。

回归

当目标变量是连续值时,使用回归。连续值可以是整数、浮点等。回归问题有很多例子,包括预测房价、预测股票价值等。由于该值在回归问题中是连续的,因此无法评估其准确性。因此,通过成本函数的值对其进行评估,该成本函数可以是均方根误差(RMSE)或交叉熵函数或任何其他函数。

为了演示回归,我将对 Kaggle 的波士顿住房数据集进行分析,该数据集可从这里下载。Scikit-learn 也提供这个数据集,并且可以以与我们使用 Iris 数据集相似的方式使用。我会通过从 Kaggle 下载来使用它。如果您想使用内置的 scikit-learn 数据集查看它是如何加载的,您可以在这里完成。

现在,下载完数据集后,需要在 jupyter 文件中导入 Pandas 和 Numpy。要加载数据,您可以使用pd.read_csv()并将文件(以字符串的形式)作为参数传入:

import pandas as pd              #importing pandas with an alias pd
import numpy as np               #importing numpy with an alias npdf = pd.read_csv('Boston.csv') 

您可以使用head()方法进一步检查数据。默认情况下,它会显示前五行,但是您可以将行数作为参数传入,并且可以查看尽可能多的记录。它有 15 列,其中第一列用于索引,接下来的 13 列是数据集的特征,最后一列(即 medv )是目标变量,它是房主自住房屋的中值,以千美元计。如果你想知道我是怎么知道的,我只是简单地检查了数据集的文档,你也可以这样做。正如您所看到的,使用 pandas 加载的数据是特性和目标变量的组合,但是 scikit-learn 需要它们在单独的数组中。我们可以通过删除 medv 列并将其用作目标来拆分数据集:

X = df.drop('medv', axis = 1).values       #dropping the medv column
Y = df['medv'].values                      #using medv as target

我们使用了values属性,因为它返回 NumPy 数组供我们使用。

线性回归

现在是时候选择我们的回归模型来帮助预测未标记数据的值了。我会选择一个非常简单的模型,叫做线性回归(LR)。LR 定义了一条适合所有给定数据的最佳线,并且它假设它以后要考虑的所有数据也将遵循相同的模式。在一个维度中(即只有一个特征的数据集),它是一条简单的线,带有参数 ab :

y = ax + b

这里, y 是目标变量,x 是数据集的特征, a,b 是要学习的参数。学习 a、b 的最佳方式是定义一个损失函数,然后将其最小化,以获得参数的最佳值。那么,如何在这里建立一个损失函数呢?如您所知,线性回归试图将数据拟合在一条线上,但在实际情况下,所有数据可能都不适合这条线。最好的办法是尽量减小直线和数据点之间的垂直距离。答对了。这是我们成本函数的公式。不要被术语“成本”混淆,因为损失函数也被称为成本函数或误差函数。现在,这个垂直距离也被称为“剩余”。我们可以尝试最小化残差的总和,但这可能会导致许多正残差与负残差相抵消,如下所示:

为了避免这种情况,我们最小化残差的平方和。这将是一个完美的损失函数,它通常被称为普通最小二乘法(OLS)。Scikit-learn 在我们应用其线性回归模型并尝试将我们的数据拟合到该模型时执行该操作。

当我们的数据只有一个特征,即一维数据时,就是这种情况。对于具有更高维度的数据,scikit-learn 尝试将数据拟合到这个线性方程中:

线性回归必须了解 n+1 个参数。

现在您已经知道了 LR 模型背后的逻辑,让我们尝试在波士顿数据集上实现它。首先,我们将使用 Scikit-learn 的train_test_split模块将数据分成训练集和测试集,就像我们在前面的分类示例中所做的那样:

from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, 
                                 test_size = 0.3, random_state = 21)

然后,我们需要使用from sklearn.linear_model import LinearRegression从 Scikit-learn 导入线性回归模型,然后实例化它。现在,您可以对训练集应用fit()方法,并使用predict()方法对测试集进行预测:

from sklearn.linear_model import LinearRegression
reg = LinearRegression()
reg.fit(X_train, Y_train)
pred = reg.predict(X_test)

与分类不同,我们不能用精确度来评估回归模型。在线性回归模型的情况下,使用 R 来评估性能,R 是根据特征变量预测的目标变量的方差的评估。为了计算 R,我们应用 score 方法并传递参数 X_test 和 Y_test,reg.score(X_test, Y_test)

到目前为止,我一直在拆分训练集和测试集中的数据。但是,为了让模型对新数据集进行增强评估,我们可以使用称为交叉验证(CV)的技术。假设我们想做 n 重交叉验证,我们会把数据分成 n 等份。然后,我们将举行第一次折叠,在剩余的 n-1 上拟合我们的模型,在测试集上预测并计算感兴趣的度量。接下来,我们保留第二个集合,拟合剩余的数据,并计算感兴趣的度量。我们对所有的 n 倍继续这样做。

来源:交叉验证维基

我们得到了我们感兴趣的度量的 n 个值(在我们的例子中是 R)。我们可以取所有数据的平均值,也可以计算其他统计数据,如平均值、中间值等。然而,需要注意的一点是,折叠的次数越多,我们的模型的计算开销就越大,因为我们要训练和测试那么多次。要使用 CV 实现 LR:

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression
reg = LinearRegression()
cv = cross_val_score(reg, X, Y, cv = 5)  #5-fold cross validation
print(cv)

它将以数组的形式输出为所有五次折叠计算的 R 值:

[ 0.57280576  0.72459569  0.59122862  0.08126754 -0.20963498]

请注意,我使用这个线性回归只是为了演示的目的,它从来没有这样使用。我们通常使用的是正则化的线性回归模型。

你可以在这里查看分类模型的代码,在这里查看回归模型的代码。

希望这篇教程能帮助你入门机器学习。你应该对分类和回归监督学习方法有更好的了解。我将继续这个系列,并在我即将到来的博客中写下关于无监督学习的内容。

数据科学项目管理的一个实例

原文:https://towardsdatascience.com/a-practical-example-of-project-management-for-data-science-bae9dbd924a?source=collection_archive---------18-----------------------

“数据科学中的项目管理”理论的实践指南

我写了一篇关于如何对你的数据科学项目进行项目管理的文章——无论是一个人的项目组合构建练习还是整个公司的计划——你可以在这里阅读。它回顾了项目管理工具,我个人认为这些工具对我以前的工作很有帮助。如果你从未使用过,这些描述和工具可能非常抽象。所以为了让它更容易理解,我写了这篇文章来展示如何将这个项目管理过程应用到你的数据科学问题中。

拿出你的笔记本电脑。这是一本实用指南。由马文·迈耶Unsplash 上拍摄的照片

接收业务问题

在我早期的项目中,我决定根据计算的财务比率对上市公司进行分类。虽然我没有遇到这个业务问题,但基于我在金融领域的专业知识,我认为这个问题应该是这样的:

我们的股票分析师分析公司财务数据,以确定这些公司的价值。这是通过提取公共记录来完成的,如报告的财务状况—资产负债表、损益表、现金流量表等。—计算描述公司运营状况的财务比率。财务比率比纯粹的财务比率更有帮助,因为它让我们可以跨公司标准化,不管公司有多大。然而,在确定一家公司的价值时,我们经常比较行业内的财务状况,而不是跨行业的。这是因为一家公司的运营方式存在根本性的差异,会影响他们的财务状况。例如,银行和其他金融行业参与者的市净率(P/B)接近 1,而其他行业的市净率可能更高,在 3 到 5 倍之间。你会问,这是为什么?因为银行从事再融资业务,所以它们的资产负债表(它们“账面”的大小)与收入产生(以及最终人们愿意支付的“价格”)直接相关。例如,非必需消费品等其他行业有望用更少的资产创造更多的价值或收益。到目前为止,我们一直在使用一家公司报告的行业,将其财务比率与类似公司进行比较,并确定该公司是否被低估或高估。然而,最近许多公司都加入了科技潮流,并将自己描述为科技公司,而他们的财务状况可能会描绘出一个不同的故事。我们希望能够根据财务比率“看到”哪些公司是相似的,而不是根据自我报告或预先确定的行业类型对公司进行分组。我们希望使用机器学习来确定公司的相似性,并验证它是否符合我们按行业进行比较的过程——甚至可能尝试根据公司所处的群体或集群来识别被低估或被高估的公司。

将业务问题转化为数据科学问题

只见树木不见森林?总是从业务问题开始。埃文·丹尼斯在 Unsplash 上的照片

那么,我是如何解决这个业务问题的呢?正如你在商业问题陈述的结尾所看到的,我决定把它带向无人监管的机器学习方向。虽然企业想看看他们的假设是否正确,但我们不一定有“标记”的数据——使用行业对公司进行分组不一定是“正确”的答案,所以我没有数据的目标值。此外,我认为使用聚类算法将是我的最佳选择,因为我们正试图根据财务比率特征找到类似的公司。在我们对公司进行聚类之后,我们可以根据它们的行业对公司进行着色,以帮助我们的股票分析师发现哪些公司在他们的行业之外进行了聚类。

开始我们的 RAID 日志

正如我在之前的博客文章中提到的,RAID 代表 R isks、 A 假设、Issuses 和 D 依赖。一旦我们认为我们理解了业务问题,并从数据科学的角度概述了我们希望如何处理它,我们最好以假设、依赖和风险的形式记录我们所知道的。通过这种方式,我们可以将 RAID 日志交给股票分析师,确保不仅我们对业务问题的理解是正确的,而且我们的利益相关者也同意我们的方法和对数据的理解。

rAid 日志—假设

基于我们的问题,让我们列出一些我们可能做出的假设。请注意,列出我们的假设的过程给了我们指导我们项目的启示:

  1. 假设#1: 只有上市公司才会被纳入我们的聚类。推理:我们需要获得公司的财务数据来计算我们想要的财务配额,而我们没有获得私人公司的财务数据。言外之意:我们无法对尚未上市的公司做出判断。此外,如果股票研究人员还没有内部数据源,这将告知我们将从哪里获取数据——在我的案例中,是从 SEC 获取的 10-Q 表格。
  2. 假设#2: 财务比率将根据提交给 SEC 的 10-Q 财务数据计算得出。推理:基于我们之前的假设,这个公共信息来源似乎是我们获得数据一致性和易用性的最佳选择。含义:我们的财务比率计算只能在与 10-Q 中提交的财务数据的粒度级别相匹配的级别上进行。
  3. 假设# 3:10-Q 财务项目在各公司之间是一致的。推理:由于向美国证券交易委员会(SEC)提交文件是一项监管要求,因此格式应该是一致的。含义:这将使计算我们的比率变得简单,因为我们可以使用相同的行项目以相同的方式计算财务比率。

请注意,当我们继续写出我们的假设时,我们是如何自然地从业务部门告诉我们的关于业务问题的内容过渡到可用的数据(上市公司),我们将从哪里获取数据(10-Q 文件),以及我们期望这些数据看起来如何(在所有公司中保持一致)。如果我们带着这些假设回到业务中,我们可能会被告知存在一个我们不知道的内部数据源。也许它已经计算好了所有的比率来节省我们的时间。虽然这一节省时间的事实可能会在我们的第一次会议中出现,但如果业务部门认为我们知道这个内部数据仓库(但是,作为一名新的数据科学家,我们并不知道),并且我们认为业务部门会告诉我们数据源是否已经存在(他们可能不会告诉我们),那么许多工作可能会重复。最佳实践是与利益相关者一起审查和确认所有假设。

为了这个思想实验的目的,让我们继续让我们的假设成立。

raiD 日志—依赖关系

这些东西是如何组合在一起的?思考依赖关系是理解整个项目的可靠方法。Gabriel Crismariu 在 Unsplash 上拍摄的照片

在依赖开始对我们的项目过程产生负面影响之前,我们往往不会考虑依赖。在这一点上,我们的利益相关者或高级管理层已经受够了我们,因为这是应该早点发现和补救的事情。这就是为什么在整个项目中,当我们识别依赖项时,列出依赖项对于识别延误的开始并在它影响到项目期限之前补救它们是至关重要的。

对于我们的例子,让我们假设我们在项目开始时确定的依赖关系如下:

  1. 依赖关系#1: 与股权研究部门就用于进行聚类的财务比率以及如何计算这些财务比率以实现特征工程的目的达成一致。缓解措施:使用股票研究小组内部使用的现有财务比率文件。(注:假设这是项目范围内要设计的合理数量的功能。如果特性的数量变得太多,您可以在每个比率类别中添加选择第一个(可能是最重要的财务比率)的警告。
  2. 依赖#2: 数据工程团队创建了一个 API,数据科学团队可以通过它获取 10-Q 数据。缓解措施:使用 EDGAR 提供的最新财务数据(电子数据收集、分析和检索)
  3. 依赖#3 :股权研究小组提供的各公司行业分类。缓解措施:对来自 EDGAR 的数据使用 SIC(标准产业分类法),并使用高级行业进行总结。

我们通常包括依赖项的交付日期,并与交付团队就日期达成一致,因此每个人都知道他们的工作如何影响项目进度。请注意我们如何在依赖性实际成为问题之前确定缓解措施(RAID 中的 I )。这样做可以让我们清晰地思考,并在恐慌模式关闭我们思考创造性解决方案的能力之前安排好资源。这也迫使我们进行尽职调查,例如确定我们可以从哪里获得行业分类,或者 10-Q 数据的各种来源。

这些依赖关系是在假设这个项目需要几个团队的协助才能完成的情况下编写的。事实上,大多数项目都需要交叉协作,即使它们主要是数据科学项目。对于单独项目,这些依赖关系可以更简单,并且可以包括不同项目阶段之间的依赖关系(例如,在继续到特征工程阶段之前,必须获取数据并起草财务比率计算)。

Raid 日志—风险

风险有时会与依赖关系(不满足依赖关系的风险)或假设(不满足假设的风险)混淆。虽然对假设或依赖关系的识别可以阐明我们之前没有注意到的潜在风险,但它们是不同的。请注意一些风险是如何被假设#3 告知的,但却被充实为风险:

  1. 风险#1: 各公司报告的财务数据的粒度级别是相同的。暗示或缓解措施:工程特性将默认为可用的最低粒度级别。最终模型中不会包含某些公司无法提供的需要粒度级别的特性。
  2. 风险#2: 每家公司将报告所有行项目。任何不适用的行项目(如长期债务)对于没有该行项目的公司将为零(而不是为空)。影响或缓解措施:数据科学团队将与股权研究部就缺失行项目的额外必要假设进行协商。还需要 1-2 周的时间来进一步清理数据。
  3. 风险#3: 使用肘方法或轮廓评分确定的理想聚类数太少(1-2)或太多(20+)而无法得出任何结论。暗示或缓解措施:选择接近行业数量(7)的最佳集群数量。

列出风险可能很难。尤其是如果你没有很多经验,在项目开始时很难发现风险——你没有经验知道哪里可能出错。有两种方法可以帮助你识别风险。第一,询问不同的团队(股票研究员、数据工程团队、数据科学团队)他们害怕什么。第二,如果你的公司有记录他们的数据科学项目的好习惯,看看旧的 RAID 日志甚至事后文档,看看哪里可能存在陷阱。

此外,随着项目的继续,当您报告进展并向不同的团队提问时,风险自然会被识别出来。在整个过程中继续更新 RAID 日志。事实上,定期更新 RAID 日志的好习惯会让您时刻警惕潜在的风险。

创建工作分解结构(WBS)

WBS 是关于任务管理和计划的。照片由柯蒂斯·麦克牛顿Unsplash 上拍摄

WBS 将您的项目分成工作流,并进一步分成更小的类别,直到我们完成最小的工作,通常是单个任务。这些任务是互斥的,并且完全穷尽了完成项目所需的所有工作。虽然通常建议完成 WBS 以确定依赖关系,但我更愿意认为这两者是一前一后创建的——当您确定依赖关系时,您会被告知项目如何自然地划分为工作流(或功能区域),并且确定任务可以澄清哪些任务需要优先,以及存在哪些依赖关系。

数据科学过程框架是创建 WBS 的良好开端。虽然有很多这样的框架,包括 CRISP-DM、KDD 和 OSEMN,但是不要因为担心“选择正确的框架”而不使用任何一个框架作为良好的起点。我将使用 OSEMN 作为一个例子:

  1. 获取数据——数据仓库和/或 ETL 团队
  2. S crub Data —数据工程团队
  3. E xplore Data —数据分析师团队
  4. M 模型数据—机器学习团队
  5. i N 企业数据—机器学习团队&股票研究团队
  6. 部署模型(CRISP-DM 的一部分,而不是 OSEMN,但是我想出于说明的目的将它包括在内)——软件工程师

正如您所看到的,如果您在一个大型组织中工作,OSEMN 框架中的每一个步骤都可以有一个不同的团队负责(如所标记的)。这显示了过程中的每个阶段是如何自然地与其他阶段分开的。虽然这些阶段可以以迭代的方式同时发生,尤其是在创建模型和解释结果之间,但是负责每个阶段的团队或小组是不同的。这使得将我们的工作分解成上述 6 个工作流变得自然而容易。让我们关注# 4 建模并创建一个更详细的 WBS:

(题外话:请注意,一些数据科学过程框架将业务理解或数据理解作为过程的一部分。我们没有该阶段的工作流,因为项目的启动发生在我们进行所有的分析并确定我们是否要继续我们的项目之后。因此,这不包括在我们的 WBS 中)

**4\. Modeling****4.1\. Run K-Means Clustering****4.1.1 Determine ideal number of clusters k**4.1.1.1 Calculate silhouette score for clusters from k=2 to 204.1.1.2 Calculate sum of squared distances (SSE) for clusters from k=2 to 204.1.1.3 Plot silhouette score and elbow graph4.1.1.4 Identify ideal number of clusters using both silhouette score and elbow method**4.1.2 Review assumptions**4.1.2.1 Plot clusters in 2D space, including centroid4.1.2.2 Identify if any clusters are not spherical in shape4.1.2.3 Identify if clusters are not evenly sized**4.1.3 Run model for different hyperparamters and document silhouette score, SSE, and 2D plot**4.1.3.1\. k = result from 4.1.1, n_init = 10, max_iter = 3004.1.3.2 k = result from 4.1.1, n_init = 20, max_iter = 3004.1.3.3 k = result from 4.1.1, n_init = 10, max_iter = 6004.1.3.4 . k = result from 4.1.1, n_init = 20, max_iter = 600**4.2 Run Agglomerative or Single-Linkage Hierarchical Clustering****4.3 Run Mean-Shifting Clustering****4.4 Run DBSCAN (Density-Based Spatial Clustering of Applications with Noise)****4.5 Run Expectation-Maximization (EM) Clustering using Gaussian Mixture Models (GMM)**

注意我是如何充实 K-means 聚类模型的一些任务的。这是一种很好的方式,可以在使用模型之前考虑需要确定什么(例如,聚类的数量),我们应该检查违反什么模型假设(例如,聚类形状和聚类大小),以及我们想要运行的一些超参数(例如,4.1.3.1 步骤 4.1.3.4)。这告诉我们事情需要多长时间——如果我们知道在不同的超参数上运行一个模型需要 2-3 个小时,列出我们打算运行的所有模型可以帮助我们计算项目合理预计需要多长时间。这对于主张更多的时间或者立即减少超参数搜索都有很大的帮助。

在 WBS 中记录任务也迫使我们系统地审查诸如模型假设之类的东西,使我们的科学过程更加稳健,并记录所采取的必要步骤。你可能也注意到了 WBS 的部分可能会在不同的项目中重复使用——如果我们的下一个项目也需要集群,我们已经有一个成熟的格式可以遵循。

最后,我们可以识别任务之间的依赖关系,并能够将任务分配给团队成员。如果我们有一个以上的 ML 研究人员被分配到这个项目,我们可能会分配一个运行 K-means 聚类,而另一个研究人员并行地拟合和运行层次聚类模型。或者,如果我们只有一名研究人员,当与高级管理层讨论项目时,这再次给了我们一个很好的立足点来争取更多的时间或更多的 ML 研究人员。

监控项目

项目管理工具不仅仅是被创造出来并被搁置的。随着项目的继续,应该不断地更新和检查它们。蒂埃拉·马洛卡在 Unsplash 上拍摄的照片

正如我简单提到的,随着项目的进行,这些项目管理工具应该不断地被重新评估和更新。例如,当我在做我的傻瓜财务项目时——博客就是基于这个项目——我意识到我对公司间数据一致性的假设是不正确的。它从一个“风险”变成了一个完全意识到的“问题”由于我没有额外的时间来完成我的项目,这意味着我需要采取缓解措施,例如减少计算财务比率的数量,并削减几个机器学习聚类模型。

让利益相关者了解情况

虽然我没有任何利益相关者可以随时了解情况,但这种将未实现的风险升级到实际问题的方式是避免指责并将对话集中在实际问题补救上的一个好方法。这是因为风险在项目之前就被识别出来了,并且被风险承担者和管理层认为是可以接受的。更好的是,养成在 RAID 日志中记录企业风险接受程度的习惯!

范围、成本和时间的三重优势

一般来说,项目是一个三角形,边是成本、范围和时间。也就是说,如果范围等边的长度增加,我们必须调整项目的大小或成本,否则。这个项目不可行。如果出现问题,时间无法改变,这意味着需要在成本(投入更多的计算能力或人员来解决问题)或范围(取消你计划要做的任务)上做出让步。以下是您在自己的数据科学项目中解决问题的一些方法:

问题解决—要求更多时间

对于可能出现的任何问题,这是最简单的解决方案,但是如果时间不是问题(或者,不像购买一个草率完成的模型那样是一个问题),这只是一个选项。诚实,甚至夸大估计解决问题需要多长时间。解决问题的时间可能比你想象的要长 1.5 倍。

问题解决—转移或增加资源

创建 WBS 并将任务分配给人们的好处在于,你能够识别谁是自由的。也许是一个可以协助运行机器学习模型的数据分析师。或者他们可以帮助清理数据。这让不同的团队有机会在相邻的领域使用他们的技能,特别是如果他们可能在以前的工作中使用过技能,但不需要在当前的角色中使用。请注意,这只有在当前项目优先于其他职责,或者高级管理层重新安排优先级以允许他们专注于当前项目时才有效。否则,雇用一名兼职或短期的额外数据工程师会有所帮助。

问题解决方案—削减其他任务

我们一开始雄心勃勃,但事情往往不按计划进行。你也可以使用 WBS 来删除那些更“值得拥有”的任务例如,您可能只需要运行 2-3 种聚类模型,而不是 WBS 上列出的 5 种。根据您对数据的理解,在数据清理和探索性数据分析(EDA)完成后,继续进行所有 5 个步骤可能没有意义。这样,随着项目的进行,您可以继续调整分配给每项任务的时间,同时保持自己的进度。

问题解决—依赖关系的迭代方法

你能采取迭代的方法,而不是等待任务完美完成吗?蒂姆·约翰逊Unsplash 上拍照

这是最常用的问题解决策略之一,因为它可以让你鱼与熊掌兼得。这是怎么回事?

项目被延迟是因为任务被延迟。这听起来很明显。但是,当您考虑任务延迟的影响时,这意味着另一个团队必须完成任务的时间会由于相关任务的延迟或必要数据的未交付而减少。当在专业经验中发生这种情况时,我们会采取迭代的交付方法。整个模型文档还没有准备好交付评审?然后只发前几章。或者更好的是,发送草稿并尽早获得反馈。

然而,这种策略可能是一把双刃剑。而迭代可以节省时间,例如,如果下一个团队发现方法有问题,被延迟的团队可以中途改变他们的方法。问题是,对于在数据准备好之前进行审查或使用数据的团队来说,这可能是浪费时间。我的建议是总是要求更多的时间或资源,而不是希望迭代方法将节省时间。可能会,但也会增加工作量。

最后,对于一个单独的项目,这种方法可能很难实现。一种想法是构建您的项目,使您能够在运行模型或特别耗时的流程时继续进行数据清理或特征工程。

我的项目是如何出错的

正如我提到的,当我在做我的假人财务项目时,我假设所有公司的财务报表看起来都一样。事实并非如此。由于我一个人在一周的紧张期限内工作,我唯一的选择就是缩小范围。

通过规划我的项目,我能够在早期发现我落后了。我受到激励,向我的教练寻求帮助,尽快处理长格式数据。

虽然我无法创造出我想要的那么多或那么多不同的特征——财务比率——但我能够认识到什么时候我需要“区分优先次序”(根据容易计算的比率)并继续前进。

关闭项目

照片由 Can AhtamUnsplash 上拍摄

当项目接近尾声时,RAID 日志和 WBS 最终成为所有风险、问题、假设(被证实为真或被证明为假)、依赖关系和任务的优秀文档。它还变成了一个极好的资源,用于事后分析您的数据科学项目为什么出错,以及如何防止它在未来出错。而且,随着您越来越多地使用这些工具,它们会成为可重复使用的模板,可以为您节省宝贵的时间和精力来思考所有需要完成的微小任务。

我承认,当我刚开始做项目经理时,很难识别风险和依赖性。我无法缩小来看到完整的画面以及事物是如何结合在一起的。然而,这是项目经理最重要的技能,最好的项目经理能够在风险成为真正的问题之前重新安排和重新确定优先级。但是随着我继续遵循结构化的方法,并强迫自己从风险、依赖性、假设、问题和任务的角度来考虑项目,我能够更好地处理项目中的任何问题。

因此,我鼓励你尝试这些工具,看看它如何为你工作。如果您有管理数据科学项目实际经验,请告诉我一些陷阱、困难和巧妙的解决方案。

[1]:“当每个人都是科技公司时,没有人是”,https://www . Washington post . com/technology/2019/09/27/When-every one-is-tech-company-no-one-is/(最后一次访问时间:2020 年 1 月 27 日)。

熊猫数据分析实用指南

原文:https://towardsdatascience.com/a-practical-guide-for-data-analysis-with-pandas-e24e467195a9?source=collection_archive---------9-----------------------

加快您的数据分析过程

数据科学项目中最耗时的部分是数据清理和准备。然而,有许多强有力的工具可以加速这个过程。其中之一是 Pandas,它是一个广泛使用的 Python 数据分析库。

图像来源

在这篇文章中,我将介绍一个典型的熊猫数据清理过程。我将举一个例子,因为一如既往,熟能生巧。

主要议题是:

  • 创建数据框架
  • 数据概述
  • 缺少值
  • 选择数据

我们总是从导入所需的库开始:

import pandas as pd
import numpy as np

创建数据帧

在现实生活中,我们通常从文件中读取数据,而不是创建数据帧。Pandas 提供了函数,通过从各种文件类型中读取数据来创建数据帧。在这篇文章中,我将使用字典来创建一个示例数据帧。

df = pd.DataFrame({'a':np.random.rand(10),
                 'b':np.random.randint(10, size=10),
                 'c':[True,True,True,False,False,np.nan,np.nan,
                      False,True,True],
                 'b':['London','Paris','New York','Istanbul',
                      'Liverpool','Berlin',np.nan,'Madrid',
                      'Rome',np.nan],
                 'd':[3,4,5,1,5,2,2,np.nan,np.nan,0],
                 'e':[1,4,5,3,3,3,3,8,8,4]})
df

数据概述

Pandas describe 函数为数值(int 或 float)列提供汇总统计信息。它计算值的数量,并显示平均值、标准差、最小值和最大值以及 25%、50%和 75%的分位数。

df.describe()

虽然所有的列都有相同的行数,但是 d 列的计数不同,因为 describe 函数不计算 NaN(缺失)值。

value_counts() 以出现次数显示列中的值:

df.c.value_counts()
True     5
False    3
Name: c, dtype: int64

value_counts()不计算 NaN(缺失)值。

我们还应该检查数据类型,并在我们的分析中考虑它们。有些功能只能在某些数据类型上执行。我们可以使用 dtypes 轻松检查数据类型:

df.dtypes
a    float64
b     object
c     object
d    float64
e      int64
dtype: object

“d”和“e”列都有整数,但“d”列的数据类型是 float。原因是列 d 中的 NaN 值。NaN 值被认为是浮点型的,因此该列中的整数值被向上转换为浮点数据类型。

Pandas 1.0.1 允许使用 NaN 作为整数数据类型。我们只需要显式地将 dtype 表示为 pd。Int64Dtype():

pd.Series([1, 2, 3, np.nan], dtype=pd.Int64Dtype())
0      1
1      2
2      3
3    NaN
dtype: Int64

如果 pd。不使用 Int64Dtype(),整数值被强制转换为浮点数:

pd.Series([1, 2, 3, np.nan])
0    1.0
1    2.0
2    3.0
3    NaN
dtype: float64

缺失值

处理缺失值是数据清理和准备过程的重要部分,因为现实生活中几乎所有的数据都有一些缺失值。

在处理缺失值之前,我们需要检查数据帧中缺失值的数量。这一步很重要,因为行或列中缺失值的比率在如何处理它们方面起着关键作用。 isna() 检查条目是否为 NaN(缺失)。当与 sum 方法结合使用时,它会给出每列中缺失值的总数:

df.isna().sum()
a    0
b    2
c    2
d    2
e    0
dtype: int64

当与 any()结合使用时,它返回一个布尔值,指示该列中是否有任何缺少的值:

df.isna().any()
a    False
b     True
c     True
d     True
e    False
dtype: bool

有许多方法可以处理丢失的值,没有一个“最佳”的选择可以用于每项任务。它高度依赖于数据的任务和特征。我将在这里列出几种处理缺失值的不同方法。

我们可以用一列中的最大值替换该列中缺少的值:

df.d.fillna(df.d.max(), inplace=True)

原位参数设置为真很重要。否则不会保存更改。

根据具体情况,如果缺少的值太多,我们可能会决定删除一行或一列。在没有先验知识的情况下填充许多缺失值可能会对我们的分析产生负面影响。我们的数据框架中有 5 列,我只想保留至少有 4 个值的样本(行)。换句话说,至少有两个缺失值的行将被删除。我们可以使用带有 thresh 参数的 dropna 函数。轴参数用于指示行(0)或列(1)。

df.dropna(thresh=4, axis=0, inplace=True)

thresh 参数的变元是一行或一列需要不被删除的非缺失值的数量。

我们也可以用它之前或之后的值来填充丢失的值。这种方法多用于时间序列数据。方法参数与' ffill '(向前传播)或' bfill '(向后传播)参数一起使用:

df.b.fillna(method='ffill', inplace=True)

我们还可以用该列中最常见的值来填充缺失值。Value_counts()根据值在列中出现的次数对它们进行排序。所以我们可以使用 value_counts()的索引来获取最常见的值:

df.c.fillna(df.c.value_counts().index[0], inplace=True)

选择数据

ilocloc 允许选择数据帧的一部分。

  • iloc:按职位选择
  • 位置:按标签选择

让我们来看一些例子,因为一如既往,熟能生巧。

国际劳工组织理事会

选择第二行:

df.iloc[1] 
a    0.835929
b       Paris
c        True
d           4
e           4
Name: 1, dtype: object

选择第一行,第二列(即第一行中的第二个值):

df.iloc[0,1] 
'London'

所有行,第三列(与选择第二列相同,但我只想展示':'的用法):

df.iloc[:,2]
0     True
1     True
2     True
3    False
4    False
5     True
7    False
8     True
9     True
Name: c, dtype: bool

前两行,第二列:

df.iloc[:2,1]
0    London
1     Paris
Name: b, dtype: object

loc

最多 2 行,列“b”:

df.loc[:2,'b']
0      London
1       Paris
2    New York
Name: b, dtype: object

最多 2 行和最多“b”列:

df.loc[:2, :'b']

第“2”行和第“b”列:

df.loc[2, :'b']
a     0.16649
b    New York
Name: 2, dtype: object

您可能想知道为什么我们在 loc 和 iloc 中对行使用相同的值。原因是数字指数。Loc 按位置选择,但行的位置与索引相同。

让我们创建一个带有非数字索引的新数据帧,这样我们就可以看到不同之处:

index = ['aa','bb','cc','dd','ee']
df2 = pd.DataFrame({'a':np.random.rand(5),
                 'b':np.random.randint(10, size=5)},
                   index = index)
df2

df2.loc['bb','b']
1df2.loc[:'cc','a']
aa    0.892290
bb    0.174937
cc    0.600939
Name: a, dtype: float64

完成数据清理或预处理后,最好将其保存到文件中,这样下次处理项目时就不必再经历相同的步骤。Pandas 提供了许多 IO 工具来读写不同的文件格式。最常见的是 to_csv :

df.to_csv("df_cleaned.csv")

结论

我在这里介绍的只是熊猫在数据分析过程中的一小部分能力,但肯定会在你的项目中有用。试图一下子全部学会是不合理的。相反,学习小块和通过实践吸收信息将帮助你建立全面的数据分析技能。

我关于数据操作和分析的其他帖子

数据清理实用指南:肥胖率数据集

原文:https://towardsdatascience.com/a-practical-guide-for-data-cleaning-obesity-rate-dataset-aff9d12390c8?source=collection_archive---------44-----------------------

如何清理和重新格式化原始数据集。

艾玛·弗朗西斯·洛根在 Unsplash 上的照片

每一个机器学习或深度学习模型的燃料都是数据。没有数据,模型是没有用的。在建立模型和训练模型之前,我们应该尝试探索和理解手头的数据。我所说的理解是指数据中的相关性、结构、分布、特征和趋势。对数据的全面理解将非常有助于构建一个稳健且设计良好的模型。我们可以通过研究数据得出有价值的结论。在我们开始研究数据之前,我们需要清理和重新格式化数据集,以便可以轻松地对其进行分析。

在本帖中,我们将介绍 Kaggle 上提供的“成人肥胖国家数据集”的数据清理过程。我将在另一篇文章中讨论探索性数据分析部分。如果我们把它们放在一篇文章里,读者会觉得篇幅太长,难以集中注意力。

该数据集包含 1975 年至 2016 年间 195 个国家的成人肥胖率。让我们从将数据集读入熊猫数据帧开始,并查看它:

import numpy as np
import pandas as pddf = pd.read_csv("obesity_data.csv")df.shape
(198, 127)df.head()

肯定不是什么好看的格式。前三行似乎在重复同样的信息。我们可以确认在行上使用 nunique 函数:

print(df.iloc[0, :].unique())
[nan, 'Prevalence of obesity among adults, BMI &GreaterEqual; 30 (age-standardized estimate) (%)']

前两行在除第一列之外的所有列中包含相同的值,该值为 NaN。第三列表示性别,但是我们可以从列名中得到相同的信息。2016.1 是男性,2016.2 是女性,2016 是平均值,这适用于所有年份。前三行是多余的,所以我们删除它们。

df.drop([0,1,2], axis=0, inplace=True)
df.reset_index(drop=True, inplace=True)

现在数据帧看起来像这样:

平年(如 2016 年)的数值是同一年其他两列的平均值(如 2016.1 和 2016.2)。保留一个通过简单的数学运算就能实现的列是没有意义的。所以我们放弃了平淡的岁月。

列名中有一种模式。从第二列开始,每隔三列就是一个平年。我们可以使用这个模式来过滤列名,并将其传递给 drop 函数:

df.drop(df.columns[1::3], axis=1, inplace=True)
df.head()

年份列包含一个值和一个范围。该值是范围上限和下限的平均值。因此,我们只能将该值视为平均肥胖率。我们可以通过拆分值和范围来实现这一点,然后在拆分后获取第一个元素。

for i in range(1,85):
    df.iloc[:,i] = df.iloc[:,i].str.split(expand=True)[0]df.head()

这种格式对于分析来说不是很理想。如果我们有以下几列就更好了:

  • 国家、年份、性别、肥胖率

所以我们需要将宽数据帧转换成窄数据帧。熊猫的转置功能可以用于这个任务,但是有一个更好的选择,那就是熊猫的融化功能。我认为融化功能是“智能转置”。

df2 = df.melt(id_vars=['Unnamed: 0'], value_name='obesity_rate')
df2.head()

我们越来越接近理想的形式。附在年份上的数字表示性别。1 代表男性,2 代表女性。我们可以将可变列拆分为“年份”和“性别”列:

df2[['year','gender']] = df2.iloc[:,1].str.split('.', expand=True)
df2.head()

我们需要做一些调整:

  • 删除“变量”列,因为它由“年份”和“性别”列表示。
  • 更改“性别”列中的值,使 1 为男性,2 为女性。
  • 将第一列的名称更改为“country”
df2.drop('variable', axis=1, inplace=True)gender = {'1':'male', '2':'female'}
df2.gender.replace(gender, inplace=True)df2.rename(columns={'Unnamed: 0':'country'}, inplace=True)df2.head()

现在我们有了一个漂亮干净的数据框架。最后,让我们检查新数据帧的形状和数据类型,并寻找丢失的值。

df2.shape
(16380, 4)df2.isna().sum()
country         0
obesity_rate    0
year            0
gender          0
dtype: int64df2.dtypes
country         object
obesity_rate    object
year            object
gender          object
dtype: object

我们需要将“obesity_rate”列的数据类型改为浮点型。当我试图转换这些值时,我发现在 obesity_rate 列中有“No”值,这些值不能转换为数值。在检查了“否”值后,我看到只有少数国家在肥胖率列中包含“否”值:

df2[df2.obesity_rate == 'No']['country'].unique()array(['Monaco', 'San Marino', 'South Sudan', 'Sudan'], dtype=object)

实际上,这些国家的所有价值观都是“不”:

omit = df2[df2.obesity_rate == 'No']['country'].unique()df2[df2.country.isin(omit)]['obesity_rate'].unique()df2 = df2[~df2.country.isin(omit)]

所以我们放弃他们:

df2 = df2[~df2.country.isin(omit)]

波浪号(~)操作符表示不是,所以我们采用国家不在省略列表中的行。我们现在可以将数据类型更改为数值:

df2 = df2.astype({'obesity_rate': 'float32'})
df2.dtypes

我们现在有了一个适合探索性数据分析(EDA)的清晰的数据框架。我将在下一篇文章中详细介绍 EDA 过程,并提供丰富的可视化信息。

感谢您的阅读。如果您有任何反馈,请告诉我。

数据可视化实用指南

原文:https://towardsdatascience.com/a-practical-guide-for-data-visualization-9f1a87c0a4c2?source=collection_archive---------26-----------------------

Matplotlib 和 Seaborn 的关系图、分类图和分布图。

JOSHUA COLEMAN 在 Unsplash 上拍摄的照片

探索性数据分析(EDA)是数据科学或机器学习管道的重要组成部分。为了使用数据创建健壮且有价值的产品,您需要探索数据,理解变量之间的关系以及数据的底层结构。EDA 中最有效的工具之一是数据可视化。

数据可视化告诉我们的远不止简单的数字。它们也更容易粘在你的头上。在本帖中,我们将尝试利用可视化的力量探索一个客户流失数据集

我们将创建许多不同的可视化,并在每一个上尝试引入 Matplotlib 或 Seaborn 库的特性。

我们从导入相关的库和将数据集读入 pandas 数据框架开始。

import pandas as pd
import numpy as npimport matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='darkgrid')
%matplotlib inlinedf = pd.read_csv("/content/Churn_Modelling.csv")df.head()

数据集包含 10000 个客户(即行)和关于银行客户及其产品的 14 个特征。这里的目标是预测客户是否会使用提供的功能流失(即退出= 1)。

让我们从一个 catplot 开始,它是 Seaborn 库的分类图。

sns.catplot(x='Gender', y='Age', data=df, hue='Exited', height=8, aspect=1.2)

发现:45 岁到 60 岁的人比其他年龄段的人更容易流失(即离开公司)。就搅拌而言,女性和男性之间没有太大的差异。

色调参数用于根据分类变量区分数据点。

下一个可视化是散点图,它显示了两个数值变量之间的关系。我们来看看一个客户的预估工资和余额是否有关联。

plt.figure(figsize=(12,8))plt.title("Estimated Salary vs Balance", fontsize=16)sns.scatterplot(x='Balance', y='EstimatedSalary', data=df)

我们首先使用 matplotlib.pyplot 接口创建一个 Figure 对象并设置标题。然后,我们用 Seaborn 在这个图形对象上绘制了实际的绘图。

发现:预计工资和余额之间没有有意义的关系或关联。余额似乎呈正态分布(不包括余额为零的客户)。

下一个可视化是箱线图,它显示了变量在中位数和四分位数方面的分布。

plt.figure(figsize=(12,8))ax = sns.boxplot(x='Geography', y='Age', data=df)ax.set_xlabel("Country", fontsize=16)
ax.set_ylabel("Age", fontsize=16)

我们还使用 set_xlabelset_ylabel 调整了 x 和 y 轴的字体大小。

箱线图的结构如下:

箱线图的结构(图像源)

Median 是对所有点进行排序时位于中间的点。Q1(第一个或下四分位数)是数据集下半部分的中位数。Q3(第三或上四分位数)是数据集上半部分的中位数。

因此,箱线图给我们一个关于分布和异常值的概念。在我们创建的箱线图中,顶部有许多异常值(用点表示)。

发现:年龄变量的分布是右偏的。由于上侧的异常值,平均值大于中值。国与国之间没有太大的差别。

在变量的单变量分布中也可以观察到右偏。让我们创建一个 distplot 来观察分布。

plt.figure(figsize=(12,8))plt.title("Distribution of Age", fontsize=16)sns.distplot(df['Age'], hist=False)

右边的尾巴比左边的重。原因是异常值,正如我们在箱线图上观察到的那样。

默认情况下,distplot 也提供直方图,但我们使用 hist 参数对其进行了更改。

Seaborn library 还提供了不同类型的配对图,概述了变量之间的配对关系。让我们首先从我们的数据集中随机抽取一个样本,使这些图更有吸引力。原始数据集有 10000 个观测值,我们将选取一个有 100 个观测值和 4 个特征的样本。

subset=df[['CreditScore','Age','Balance','EstimatedSalary']].sample(n=100)g = sns.pairplot(subset, height=2.5)

在对角线上,我们可以看到变量的直方图。网格的另一部分代表成对的关系。

观察两两关系的另一个工具是热图,它采用矩阵并生成彩色编码图。热图主要用于检查特征和目标变量之间的相关性。

让我们首先使用 pandas 的 corr 函数创建一些特征的关联矩阵。

corr_matrix = df[['CreditScore','Age','Tenure','Balance',
'EstimatedSalary','Exited']].corr()

我们现在可以画出这个矩阵。

plt.figure(figsize=(12,8))sns.heatmap(corr_matrix, cmap='Blues_r', annot=True)

发现:“年龄”和“余额”栏与客户流失(“退出”)正相关。

随着数据量的增加,分析和探索数据变得更加困难。当有效和恰当地使用时,可视化是探索性数据分析的伟大工具。可视化也有助于向你的观众传递信息,或者告诉他们你的发现。

没有一种通用的可视化方法,因此某些任务需要不同类型的可视化。根据任务的不同,不同的选项可能更合适。所有可视化的共同点是,它们都是探索性数据分析和数据科学讲述部分的伟大工具。

感谢您的阅读。如果您有任何反馈,请告诉我。

探索性数据分析实用指南

原文:https://towardsdatascience.com/a-practical-guide-for-exploratory-data-analysis-5ab14d9a5f24?source=collection_archive---------38-----------------------

听数据,好奇又认真!

艾玛·弗朗西斯·洛根在 Unsplash 上的照片

每一个机器学习或深度学习模型的燃料都是数据。没有数据,模型是没有用的。在建立模型和训练模型之前,我们应该尝试探索和理解手头的数据。我所说的理解是指数据中的相关性、结构、分布、特征和趋势。对数据的全面理解将非常有助于构建一个稳健且设计良好的模型。我们可以通过研究数据得出有价值的结论。

在这篇文章中,我将对 Kaggle 上的电信客户流失数据集进行探索性的数据分析。

让我们从将数据读入熊猫数据帧开始:

import numpy as np
import pandas as pddf = pd.read_csv("Telco-Customer-Churn.csv")

首先要做的是检查我们有什么。

df.shape
(7043, 21)df.columns
Index(['customerID', 'gender', 'SeniorCitizen', 'Partner', 'Dependents','tenure', 'PhoneService', 'MultipleLines', 'InternetService','OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport','StreamingTV', 'StreamingMovies', 'Contract', 'PaperlessBilling',
'PaymentMethod', 'MonthlyCharges', 'TotalCharges', 'Churn'],
dtype='object')

数据集包括 7043 个观测值(行)和每个观测值的 21 个特征(列)。一个特征“客户流失”是目标变量,这是我们使用其他 20 个特征预测的目标变量。目标变量是因变量,其他 20 个特征是自变量。

让我们用方法来看看数据帧的前 5 行:

虽然 dataframe 有 21 列,但只有 10 列适合屏幕显示。使用以下代码可以很容易地更改该选项:

pd.set_option("display.max_columns", 21)

该数据集经过预先清理,因此没有任何缺失值,但检查和处理缺失值是一个良好的做法:

df.isna().sum().sum()
0

我们没有像预期的那样丢失任何值。df.isna()。sum()返回每列中缺失值的数量。通过再加一个总和,我们可以看到整个数据帧中缺失值的总数。以下是关于如何查找和处理缺失值的详细帖子:

[## 用熊猫处理缺失值

关于如何检测和处理缺失值的完整教程

towardsdatascience.com](/handling-missing-values-with-pandas-b876bf6f008f)

我认为最好开始探索目标变量,因为最终,我们将建立一个模型来预测目标变量。我们可以使用 value_counts() 来检查目标变量的分布,或者将其可视化:

df.Churn.value_counts()
No     5174
Yes    1869
Name: Churn, dtype: int64plt.figure(figsize=(10,6))
sns.countplot('Churn', data=df).set_title('Distribution of Target Variable')

目标变量具有不平衡的类分布。正类(流失=是)远小于正类(流失=否)。不平衡的类别分布会对机器学习模型的性能产生负面影响。上采样或下采样可以用来克服这个问题。向上采样是通过随机选择样本中的行来增加样本较少的类的样本数。下采样是应用于主导类以减少观察数量的类似过程。

我们也来看看自变量的分布。我们可以从二元分类特征开始:

fig, axes = plt.subplots(2, 3, figsize=(12, 7), sharey=True)sns.countplot("gender", data=df, ax=axes[0,0])
sns.countplot("SeniorCitizen", data=df, ax=axes[0,1])
sns.countplot("Partner", data=df, ax=axes[0,2])
sns.countplot("Dependents", data=df, ax=axes[1,0])
sns.countplot("PhoneService", data=df, ax=axes[1,1])
sns.countplot("PaperlessBilling", data=df, ax=axes[1,2])

老年人和电话服务变量之间存在严重的不平衡。大多数顾客都不是老年人,而且大多数顾客都有电话服务。

我们还应该检查其他分类变量的分布。

sns.countplot("InternetService", data=df)

光纤比 DSL 更常用,也有没有互联网服务的客户。

fig, axes = plt.subplots(2, 3, figsize=(12, 7), sharey=True)sns.countplot("StreamingTV", data=df, ax=axes[0,0])
sns.countplot("StreamingMovies", data=df, ax=axes[0,1])
sns.countplot("OnlineSecurity", data=df, ax=axes[0,2])
sns.countplot("OnlineBackup", data=df, ax=axes[1,0])
sns.countplot("DeviceProtection", data=df, ax=axes[1,1])
sns.countplot("TechSupport", data=df, ax=axes[1,2])

这些变量的共同点是“无互联网服务”类别,因此只有当客户有互联网服务时,这些变量才会发挥作用。在选择特征和构建模型时,我们应该记住这一点。

“合同”和“支付方法”也是分类变量,因此我们可以类似地检查它们。

让我们看看连续变量的分布。

fig, axes = plt.subplots(1,2, figsize=(12, 7))sns.distplot(df["tenure"], ax=axes[0])
sns.distplot(df["MonthlyCharges"], ax=axes[1])

保有权变量显示客户已经成为客户多少个月了。大多数顾客都是新会员或老会员。从月费分布一栏可以看出,大多数客户支付的是最低月费。情况可能是,该公司为新员工提供了相当不错的待遇。

自变量与目标(因变量)的关系也很重要。我们需要揭示相关性,看看每个特征如何影响目标变量。

我们可以使用相关矩阵来表示连续变量,或者使用 groupby 函数来探索分类变量。在开始这一步之前,我们需要在目标变量中做一个小的操作。“流失”列中的类别表示为“是”和“否”。对于数值分析,我们需要将“是”改为 1,将“否”改为 0:

new = {'Yes':1, 'No':0}
df.Churn = df.Churn.replace(new)

我们从“老年人”和“伴侣”特征开始。只要您详细研究每个变量,顺序并不重要:

这些数字告诉我们什么?我们根据每个类别对客户进行分组,并计算平均流失率。记住 1 表示客户流失,因此平均值越高,该群体流失的可能性越大。看来老年人比非老年人更容易流失。有一个合作伙伴可以降低流失率。

让我们再检查几个:

正如“家属”一栏所暗示的,单身人士更有可能变动,这是有道理的,因为当我们安定下来后,一般来说,我们不容易改变。拥有电话服务对客户流失率的影响很小。

我真的很想知道性别对流失率有没有影响。让我们检查一下:

男性和女性的流失率几乎相同。

我怀疑任期和合同变量高度相关,因为如果客户有长期合同,他们会呆得更久。让我们检查一下:

结果证实了我的怀疑。在这种情况下,没有必要在预测模型中使用这两个变量。包括其中之一就足够了。

我们可以进一步分析并研究一些组合特征。例如,对于有受抚养人的人,流失率如何根据互联网服务类型而不同?我们可以简单地用 pivot_table 函数来回答这个问题:

我们可以使用相关矩阵来寻找连续特征之间的相关性。 corr() 方法可应用于数据帧,结果也可使用热图可视化:

plt.figure(figsize=(10,6))sns.heatmap(corr, square=True, center=0.5, yticklabels=False).set_title('Correlation Matrix')

y 轴上的变量顺序与 x 轴上的顺序相同(从上到下:流失、任期、月度费用)。任期和流失率之间存在负相关关系。客户在公司呆的时间越长,他/她流失的可能性就越小。

以这种方式探索变量有助于我们更好地理解数据。我们将大致了解在实现模型时有用的变量。我们可以根据探索过程的结果决定消除或修改某些变量。如果结果相同,最好使用更简单的模型。

我们也可以不经过任何计算就做出推论。例如,我们的数据集包括“任期”、“每月费用”和“总费用”列。总费用的价值与任期乘以每月费用成正比。因此,没有必要在模型中包含“TotalCharges”列。

结论

探索性数据分析过程中使用的技术取决于任务和数据集的特征。但是,目标是一样的。我们试图探索和理解这些数据。在没有全面了解手头数据的情况下,永远不要急于构建模型。数据能告诉我们很多东西,所以我们应该仔细而好奇地倾听。

感谢您的阅读。如果您有任何反馈,请告诉我。

探索性数据分析实用指南——流失数据集

原文:https://towardsdatascience.com/a-practical-guide-for-exploratory-data-analysis-churn-dataset-508b6da2d594?source=collection_archive---------13-----------------------

使用熊猫、Matplotlib 和 Seaborn。

尼尔斯·内德尔在 Unsplash 上的照片

探索性数据分析(EDA)是数据科学或机器学习管道的重要组成部分。为了使用数据创建健壮且有价值的产品,您需要探索数据,理解变量之间的关系以及数据的底层结构。

在本帖中,我们将使用 Pandas、Matplotlib 和 Seaborn 库探索客户流失数据集。数据集可在 Kaggle 上的这里获得。

第一步是将数据集读入熊猫数据帧。

import pandas as pd
import numpy as npdf = pd.read_csv("/content/Churn_Modelling.csv")df.shape
(10000, 14)df.head()

数据集包含 10000 个客户(即行)和关于银行客户及其产品的 14 个特征。这里的目标是预测客户是否会使用提供的功能流失(即退出= 1)。因此,在机器学习方面,我们的目标是建立一个监督学习算法来执行分类任务。

我们永远不应该只是将原始数据转储到机器学习模型中。垃圾进,垃圾出!这就是为什么彻底的 EDA 过程非常重要的原因。

清理数据

让我们首先检查是否有任何丢失的值。

df.isna().sum()

该数据集没有任何缺少的值,这在现实生活的数据集中是不常见的。处理缺失值是 EDA 过程的重要组成部分。如果与数据集的大小相比,缺少的值非常少,我们可以选择删除缺少值的行。否则,最好用合适的值替换它们。Pandas fillna 函数可以用来处理这个任务。

重要说明:如果您选择基于列中的非缺失值估算缺失值(例如,用列的平均值填充缺失值),您应该在将数据集拆分为训练和测试子集后执行此操作。否则,您会将测试集中的数据泄露给机器学习模型,这些数据应该是新的、以前未见过的数据。

像客户流失预测和垃圾邮件检测这样的任务很可能具有不平衡的类别分布。流失(即离开)的客户数量通常比没有流失的客户数量少得多。我们可以用 value_counts 函数检查值的分布。

df.Exited.value_counts()
0    7963 
1    2037 
Name: Exited, dtype: int64

目标变量不平衡(“已退出”)。重要的是消除不平衡。否则,机器学习模型很可能会偏向于占优势的阶层。有不同的技术来处理类不平衡,如欠采样和过采样。

我们还应该确保数据以适当的数据类型存储。例如,数值不应该存储为“对象”。 Dtypes 函数返回每一列的数据类型。

df.dtypes

数据类型是适当的。下一步是去掉多余的特性。“RowNumber”列只是一个索引。“客户 Id”和“姓氏”列对于机器学习模型来说显然是无用的。因此,我们应该放弃它们。

df.drop(['RowNumber','CustomerId','Surname'], axis=1, inplace=True)

我们只是传递要删除的标签列表。参数告诉 drop 函数我们是删除行(0)还是列(1)。将原位参数设置为真以保存更改。

更精彩的部分!

现在是时候深入研究数据集了。

让我们看看“性别”和“地理位置”与客户流失有什么关系。一种方法是使用熊猫的 groupby 功能。

df[['Geography','Gender','Exited']].groupby(['Geography','Gender']).agg(['mean','count'])

发现:一般来说,女性比男性更容易“退出”。德国的离职率高于法国和西班牙。

EDA 过程中的另一个常见做法是检查变量的分布。分布图、直方图和箱线图让我们了解变量(即特征)的分布。

fig , axs = plt.subplots(ncols=2, figsize=(12,6))fig.suptitle("Distribution of Balance and Estimated Salary", fontsize=15)sns.distplot(df.Balance, hist=False, ax=axs[0])sns.distplot(df.EstimatedSalary, hist=False, ax=axs[1])

大多数客户的余额为零。对于剩余的客户,“余额”具有正态分布。“估计销售额”似乎是均匀分布的。

由于有许多客户的余额为零,我们可以创建一个新的二元特征来指示客户的余额是否为零。熊猫的功能将在哪里完成这项工作。

df['Balance_binary'] = df['Balance'].where(df['Balance'] == 0, 1)df['Balance_binary'].value_counts()
1.0    6383 
0.0    3617 
Name: Balance_binary, dtype: int64

大约三分之一的客户余额为零。让我们看看零平衡对搅动的影响。

df[['Balance_binary','Exited']].groupby('Balance_binary').mean()

发现:余额为零的客户不太可能流失。

另一个需要检查的重要统计数据是变量之间的相关性。

相关性是每个变量的标准差对协方差的归一化。协方差是一个定量的度量,表示两个变量的变化彼此匹配的程度。更具体地说,协方差比较两个变量与它们的均值(或期望值)的偏差。

通过检查相关性,我们试图找出两个随机变量如何相似地偏离它们的均值。

pandas 的 corr 函数返回一个相关矩阵,表示数值变量之间的相关性。然后我们可以将这个矩阵绘制成热图。

如果我们将“性别”栏中的值转换成数字就更好了,这可以通过熊猫的替换功能来实现。

df['Gender'].replace({'Male':0, 'Female':1}, inplace=True)corr = df.corr()plt.figure(figsize=(12,8))sns.heatmap(corr, cmap='Blues_r', annot=True)

相关矩阵

发现:“年龄”、“余额”和“性别”栏与客户流失(“退出”)正相关。成为活跃会员(“IsActiveMember”)与客户流失之间存在负相关关系。

如果你比较“Balance”和“Balance_binary”,你会注意到一个非常强的正相关性,因为我们是基于另一个创建的。

因为“年龄”被证明具有最高的相关值,所以让我们更深入地研究一下。

df[['Exited','Age']].groupby('Exited').mean()

顾客的平均年龄更高。我们还应该检查“年龄”一栏的分布情况。

plt.figure(figsize=(6,6))plt.title("Boxplot of the Age Column", fontsize=15)sns.boxplot(y=df['Age'])

上线以上的点表示异常值。因此,在上端有许多异常值。另一种检查异常值的方法是比较平均值和中值。

print(df['Age'].mean())
38.9218print(df['Age'].median())
37.0

平均值高于符合箱线图的中值。有许多不同的方法来处理异常值。它可以是一整篇文章的主题。

这里做一个简单的。我们将删除前 5%的数据点。

Q1 = np.quantile(df['Age'],0.95)df = df[df['Age'] < Q1]df.shape
(9474, 14)

第一行查找区分前 5%的值。在第二行中,我们使用这个值来过滤数据帧。原始数据帧有 10000 行,因此我们删除了 526 行。

请注意,这在许多情况下是不可接受的。我们不能仅仅摆脱行,因为数据是一种有价值的资产,我们拥有的数据越多,我们就能建立更好的模型。我们只是想看看异常值是否对年龄和客户流失之间的相关性有影响。

让我们比较一下新的平均值和中值。

print(df['Age'].mean())
37.383681655055945print(df['Age'].median())
37.0

他们很亲密。是时候检查一下流失客户和未流失客户的平均年龄差异了。

df[['Exited','Age']].groupby('Exited').mean()

我们的发现仍然适用。顾客的平均年龄更高。

探索性数据分析没有限制。根据我们的任务或目标,我们可以从不同的角度处理数据,并深入挖掘。然而,过程中使用的工具通常是相似的。为了在这个过程中做好,大量练习是非常重要的。

感谢您的阅读。如果您有任何反馈,请告诉我。

探索性数据分析实用指南:英格兰超级联赛

原文:https://towardsdatascience.com/a-practical-guide-for-exploratory-data-analysis-english-premier-league-cac1e2695d30?source=collection_archive---------51-----------------------

探索英超 2019-2020 赛季

Unsplash 上由 Tevarak Phanduang 拍摄的照片

每一个机器学习或深度学习模型的燃料都是数据。没有数据,模型是没有用的。在建立模型和训练模型之前,我们应该尝试探索和理解手头的数据。我所说的理解是指数据中的相关性、结构、分布、特征和趋势。对数据的全面理解将非常有助于构建一个稳健且设计良好的模型。我们可以通过研究数据得出有价值的结论。

在本帖中,我将对 Kaggle 上的英超联赛 2019-2020 赛季数据集进行探索性的数据分析。

让我们从将数据读入熊猫数据帧开始:

import numpy as np
import pandas as pddf_epl = pd.read_csv("../input/epl-stats-20192020/epl2020.csv")print(df_epl.shape)
(576, 45)

数据集有 576 行和 45 列。为了能够显示所有的列,我们需要调整 display.max_columns 设置。

pd.set_option("display.max_columns",45)df_epl.head()

它不适合屏幕,但我们可以通过滑动滚动条看到所有的列。该数据集包括 288 场比赛的统计数据。有 576 行,因为每场比赛用两行表示,一行来自主队,一行来自客队。例如,前两行代表“利物浦-诺维奇”比赛。

第一列(“未命名:0”)是多余的,所以我们可以删除它:

df_epl.drop(['Unnamed: 0'], axis=1, inplace=True)
df_epl = df_epl.reset_index(drop=True)

该数据集包括许多关于游戏的不同统计数据。

  • xG、xGA:团队和对手的预期目标
  • 进球,失球:进球和失球
  • xpts,pts:预期和收到的点数
  • 赢、平、输:显示游戏结果的二元变量
  • tot_goal,tot_con:从赛季开始的总进球数和失球数

还有一些基本的统计数据,比如射门,命中目标,角球,黄牌,红牌。我们也有关于比赛日期和时间的信息。

先说天:

df_epl.matchDay.value_counts()

大多数比赛都在周六进行。

我们可以根据到目前为止获得的总分数快速建立排名。tot_points 列中的最大值显示了最新的点:

df_epl[['teamId','tot_points']].groupby('teamId').max().sort_values(by='tot_points', ascending=False)[:10]

我只展示了前 10 支队伍。如果你是一个足球迷,你可能听说过本赛季利物浦成功称霸英超联赛。利物浦领先 25 分。

技术和数据科学的进步带来了新的足球统计数据。一种相对较新的统计是“预期”统计,如预期目标和预期积分。让我们检查一下期望值和实际值有多接近。有不同的方法来做比较。一种方法是检查差异的分布:

#Data visualization libraries
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='darkgrid')
%matplotlib inlineplt.figure(figsize=(10,6))
plt.title("Expected vs Actual Goals - Distribution of Difference", fontsize=18)diff_goal = df_epl.xG - df_epl.scoredsns.distplot(diff_goal, hist=False, color='blue')

这很像均值接近于零的正态分布。因此,一般来说,期望值非常接近实际值,当然也有一些例外。这些例外正是足球令人兴奋的地方。

我们得到一个类似的期望点和实际点的分布:

预期点数和实际点数之间的差异可能在-3 和+3 之间。分布曲线的尾部再往前一点,就完成了分布曲线。

我不知道预期的进球统计是如何计算的,但它应该多少与射门和射门准确度有关。我们可以使用 pandas 的 corr 函数来检查预期目标(xG)和其他一些统计数据之间的相关性。

df_epl[df_epl.h_a == 'h'][['xG','HS.x','HST.x','HtrgPerc','tot_goal']].corr()

射门和命中目标绝对与预期目标相关。预期进球和球队本赛季迄今为止的进球数之间也存在微弱的正相关关系。

我们也可以通过预期进球和实际进球来了解守门员的表现。如果一支球队的失球比对方球队的预期目标少,这表明守门员表现良好。另一方面,如果一支球队的失球比预期的多,那么守门员的表现就不太好。

df_epl['keep_performance'] = df_epl['missed'] / df_epl['xGA']df_epl[['teamId','keep_performance']].groupby('teamId').mean().sort_values(by='keep_performance', ascending=False)[:5]

曼城的失球是预期的 2.22 倍,这表明门将表现不佳。这不仅仅是守门员的责任。防守球员在这种情况下也有责任。

另一方面,纽卡斯尔联队和莱斯特队的门将表现出色。

我们还可以检查“比赛日”对球队表现是否有影响。利物浦本赛季只丢了 5 分,所以让我们看看第二支球队曼城。

df_epl[df_epl.teamId == 'Man City'][['pts','matchDay']].groupby('matchDay').agg(['mean','count'])

看起来曼城不喜欢星期天。周五他们的平均分数是 0 分,但是只有一场比赛,所以我们实际上不能做出真正的判断。

我们来看看平均每场比赛进了多少球。一种方法是将进球和失球相加,然后取平均值:

df_epl['goals']= df_epl['scored'] + df_epl['missed']
df_epl['goals'].mean()
2.7222222222222223

场均进球数为 2.72。主场球队通常比客场球队得分更多,因此由于体育场内球迷的支持而获得更多积分。

df_epl[['h_a','scored','pts']].groupby('h_a').mean()

总的来说,主队主宰了比赛。我们也可以从每场比赛的投篮次数上看出这一点。我们来对比一下主队和客场队的射门情况:

print("Home team stats \n {} \n".format(df_epl[df_epl.h_a == 'h'][['HS.x','HST.x','HtrgPerc']].mean()))print("Away team stats \n {} \n".format(df_epl[df_epl.h_a == 'a'][['AS.x','AST.x','AtrgPerc']].mean()))

主队在投篮次数和投篮命中率上超过了客场队。不过,对于客场球队来说,准确率略好于主场球队。

衡量一个团队表现的一个方法是他们相对于预期的分数获得了多少分。当然,在某些情况下有“运气”的因素,但这是一个有趣的统计。所以,我们来检查一下。我们可以检查实际点数和预期点数之间的差值的平均值。这将显示每个团队在满足期望方面有多成功。

df_epl['performance'] = df_epl['pts'] - df_epl['xpts']df_epl[['teamId','performance']].groupby('teamId').mean().sort_values(by='performance', ascending=False)

出乎意料

低于预期

利物浦远远超过其他球队,这是有道理的,因为在 29 场比赛中,他们在可能的 87 分中只丢了 5 分。曼城、曼联和切尔西得到一些令人惊讶的结果,因为他们的平均表现低于预期。

一些裁判倾向于比其他人更容易使用黄牌和红牌。我认为球员们会记住这一点。让我们看看每场比赛每位裁判平均有多少张牌:

df_epl['cards'] = df_epl['HY.x'] + df_epl['HR.x'] + df_epl['AY.x'] + df_epl['AR.x']df_epl[['Referee.x','cards']].groupby('Referee.x').mean().sort_values(by='cards', ascending=False)[:10]

当裁判是米迪恩的时候,球员应该更加小心。

关于球队、球员和裁判的表现,我们可以想出更多的表现指标。我已经试着涵盖了足球中一些有趣的标准。Pandas 为探索性数据分析提供了许多有用且易于使用的功能和方法。可视化也是探索数据的好工具。它们也比数字更有信息量,更容易记忆。

关于探索性数据分析的更多信息

感谢您的阅读。如果您有任何反馈,请告诉我。

探索性数据分析的实用指南:航班延误

原文:https://towardsdatascience.com/a-practical-guide-for-exploratory-data-analysis-flight-delays-f8a713ef7121?source=collection_archive---------25-----------------------

对航班延误的详细分析。

尼尔斯·内德尔在 Unsplash 上的照片

我们生活在大数据时代。我们收集了大量数据,这些数据可以推断出有意义的结果,并做出明智的商业决策。然而,原始数据并不能提供太多信息,除非对其进行处理和探索。为了充分利用原始数据,我们需要一个彻底的探索性数据分析过程。即使我们建立了复杂的、结构良好的机器学习模型,我们也不能只是将原始数据转储给它们。模型和我们提供给它们的数据一样好。随着数据量的增加,分析和探索数据变得更加困难。这里有数据分析和可视化工具的力量。

我们将探索一个关于航班延误的数据集,这个数据集可以在 Kaggle 上这里找到。有两个数据集,一个包括 2019 年 1 月的航班细节,另一个包括 2020 年 1 月的航班细节。在本帖中,我们将使用 2019 年 1 月的那个。我们从将数据集导入熊猫数据框架开始。

import numpy as np
import pandas as pddf = pd.read_csv("/content/Jan_2019_ontime.csv")print(df.shape)df.columns

该数据集包含超过 50 万个航班(行)的信息和每个航班的 22 个特征(列)。有些列似乎是多余的或者是重复出现的,所以我们将在分析中包括一些列。

df = df[['DAY_OF_MONTH', 'DAY_OF_WEEK', 'OP_CARRIER_AIRLINE_ID', 'ORIGIN', 'DEST','DEP_TIME', 'DEP_DEL15', 'ARR_TIME', 'ARR_DEL15', 'CANCELLED', 'DIVERTED', 'DISTANCE']]df.head()

对于每个航班,以下功能可用:

  • 一月中的某一天
  • 星期几
  • 承运航空公司(
  • 出发城市和出发时间(出发地,DEP 时间)
  • 抵达城市和抵达时间(DEST,ARR_TIME)
  • 出发和到达时延迟(DEP_DEL15,ARR_DEL15)
  • 取消,转移
  • 距离

缺失值

我们首先处理缺失值。首先,让我们检查每一列中缺失值的数量。

df.isna().sum()

我们在 4 列中缺少值。缺失值的数量接近,因此它们可能在同一行中。为了确认,我们可以使用 missingno 模块可视化缺失值。

%matplotlib inlineimport missingno as msno
msno.matrix(df)

白线表示缺少值。这 4 列中的大多数缺失值都在同一行中。缺少值的行可能属于取消或改道的航班。在处理缺失值之前,让我们检查一下“取消”和“转移”列。

取消航班的数量与航班信息列中缺失值的数量大致相同。

改道的航班也会导致价值缺失。缺失的值是由于航班取消或改道造成的。因此,我们可以放弃它们。

df.dropna(axis=0, how='any', inplace=True)
df.isna().sum().sum()
0

取消和转移列现在充满了零,所以我们也可以删除它们。

df.drop(['CANCELLED','DIVERTED'], axis=1, inplace=True)

延期概述

表示延迟的列是二进制的,因此航班要么延迟(1),要么不延迟(0)。

df['ARR_DEL15'].value_counts()

抵达时的延误不仅仅是离开时的延误,这是有道理的,因为离开时的延误很可能导致抵达时的延误。我们可以使用 pandas 的分组功能来比较出发和到达的延误。

df[['ARR_DEL15','DEP_DEL15','DEST']].groupby(['DEP_DEL15',
'ARR_DEL15']).count()

不出所料,如果出发时间延迟,到达时间更有可能延迟。请注意,我们可以使用任何列作为上述语句中的第三列(我选择了“DEST”)。该列的目的只是为了查看计数。

出发地和目的地

始发地列包含出发地点,DEST 列包含目的地地点。让我们看看数据集中有多少个起点和终点。

print("There are {} unique origin city".format(df['ORIGIN'].nunique()))print("There are {} unique destination city".format(df['DEST'].nunique()))

我们可以根据延误率对始发地和目的地进行分类。

df[['ORIGIN','DEP_DEL15']].groupby('ORIGIN').agg(['mean','count']).sort_values(by=('DEP_DEL15','mean'), ascending=False)[:10]

df[['DEST','ARR_DEL15']].groupby('DEST').agg(['mean','count']).sort_values(by=('ARR_DEL15','mean'), ascending=False)[:10]

我们根据出发延误率对出发地进行了分类,根据到达延误率对目的地进行了分类。延误率高的地点航班很少。

每个地点的平均航班数为 1635 次。那些少于 100 次飞行的可能是异常值,不能给我们一个准确的估计。让我们对超过 500 个航班的始发地进行排序。

origin_delays = df[['ORIGIN','DEP_DEL15']].groupby('ORIGIN').agg(['mean','count'])origin_delays[origin_delays[('DEP_DEL15','count')] > 500].sort_values(by=('DEP_DEL15','mean'), ascending=False)[:10]

除了迄今为止延迟率最高的“ASE”之外,整个列表都发生了变化。请注意,当我们使用多级索引过滤数据帧时,我们需要使用所有级别。例如,为了根据“计数”过滤上述数据帧,我们使用origin_delays[(‘DEP_DEL15’,’count’)], 而不是origin_delays[‘count’]

星期几和月份

该数据集涵盖 2019 年 1 月。我们可以根据一周中的某一天和一月中的某一天来检查延迟率。因为我们不是基于位置检查延误,所以我们可以通过合计出发和到达时的延误来创建一个新列。

df['DEL15'] = df['ARR_DEL15'] + df['DEP_DEL15']

如果出发和到达都有延误,“DEL15”列的值为 2。

让我们从平均延迟的角度来比较一下一周中的每一天。

df[['DAY_OF_WEEK','DEL15']].groupby('DAY_OF_WEEK').agg(['mean','count'])

大多数航班在周三和周四,这两天的平均延误率也比其他几天略高。这表明,随着航班频率的增加,延误也会增加。

让我们也检查基于一个月中的某一天列的平均延迟。这次我们将使用 plotly 库的 plotly express API 创建一个信息可视化,但是我们首先需要计算每天的平均延迟。

day_of_month = df[['DAY_OF_MONTH','DEL15']].groupby('DAY_OF_MONTH').agg(['mean','count'])day_of_month.columns = ['mean','count']

我们现在可以绘制它。

import plotly.express as pxfig = px.bar(day_of_month, x=day_of_month.index, y='mean',   color='count', height=400, title="Delays in Jan 2019")fig.show()

条形的颜色根据右侧的计数刻度指示每天的航班数量。条形的高度显示了延迟比。就天数而言,没有很强的模式,但航班较多的日子往往有较高的延误率。

承运航空公司

航空公司的运营问题也可能导致航班延误。

数据集中有 17 种不同的载体。我们首先根据平均延迟对载波进行排序。

carrier = df[['OP_CARRIER_AIRLINE_ID','DEL15']].groupby('OP_CARRIER_AIRLINE_ID').agg(['mean','count']).sort_values(by=('DEL15','mean'), ascending=False).reset_index()carrier.columns = ['carrier_ID','mean','count']carrier['carrier_ID'] = carrier['carrier_ID'].astype('object')carrier.head()

让我们创建一个类似于我们几天前创建的柱状图。

fig = px.bar(carrier, x=carrier.index, y='mean', color='count', height=500, title="Delays of Different Airlines")fig.show()

颜色越浅表示航班越多。我们看不到更多航班导致更多延误的趋势。例如,用第二、第三和第四条表示的航空公司在航班数量方面处于最低区域。然而,它们比大多数其他载波具有更高的延迟比。因此,就像航班数量一样,承运人也是延误的决定因素。

我们分析了基于位置、日期和承运人的航班延误。我们的发现是:

  • 随着航班频率的增加,我们更有可能看到更多的延误。
  • 一些航空公司有更高的延误率,尽管没有比其他航空公司更多的航班。
  • 虽然不是非常确定,但是位置也可能对延迟有影响。

该数据集还包括航班的时间和距离信息,这也可能对延误产生影响。可以用类似的方法分析这些柱。探索性数据分析没有限制。根据我们的任务或目标,我们可以从不同的角度处理数据,并深入挖掘。然而,过程中使用的工具通常是相似的。为了更好地掌握这个过程,大量练习是非常重要的。

感谢您的阅读。如果您有任何反馈,请告诉我。

探索性数据分析实用指南:流媒体平台上的电影

原文:https://towardsdatascience.com/a-practical-guide-for-exploratory-data-analysis-movies-on-streaming-platforms-5ea494fee9d2?source=collection_archive---------26-----------------------

探索网飞、Hulu、Prime Video 和 Disney+上的电影。

Unsplash 上由 Thibault Penin 拍摄的照片

我们生活在大数据时代。我们可以收集大量数据,从而推断出有意义的结果,做出明智的商业决策。为了充分利用数据,需要一个强大而全面的数据分析流程。在本帖中,我们将尝试探索一个关于流媒体平台上电影的数据集。数据可从 Kaggle 上的这里获得。

我们可以直接将 Kaggle 数据集下载到 Google Colab 环境中。以下是如何操作的分步说明:

[## 如何在 Google Colab 中使用 Kaggle 数据集

使用 kaggle API 将数据集直接下载到 colab。

towardsdatascience.com](/how-to-use-kaggle-datasets-in-google-colab-bca5e452a676)

让我们从下载数据集开始,并将其读入熊猫数据帧。

import pandas as pd
import numpy as np!kaggle datasets download -d ruchi798/movies-on-netflix-prime-video-hulu-and-disneydf = pd.read_csv("/content/movies-on-netflix-prime-video-hulu-and-disney.zip")df.drop(["Unnamed: 0", "ID", "Type"], axis=1, inplace=True)df.head()

“未命名:0”和“ID”列是多余的,因为它们不提供关于电影的任何信息,所以我们删除它们。“类型”栏指示标题是电影还是电视节目。我们删除它们是因为所有的行都包含电影数据。

我们有关于电影的数据和关于它们在流媒体平台上的可用性的信息。还提供了 IMDb 和烂番茄的电影评级。

缺失值

首先处理缺失值是一个好的做法。

df.shape
(16744, 14)

数据集包括超过 16k 行和 14 列。让我们看看每一列包含多少个缺失值。

df.isna().sum()

“年龄”和“烂番茄”列中的大部分值丢失。其他一些列也有缺失值。有一个很棒的 python 库来探索数据集中缺少的值,即没有缺少的值。我们可以通过绘制缺失值矩阵来了解缺失值在数据集中的分布情况。

import missingno as msno%matplotlib inlinemsno.matrix(df)

白线表示缺少值。不出所料,“年龄”和“烂番茄”列中缺少值。有趣的模式是,其他列中缺少的值大多是匹配的。行或者没有缺失值,或者在多列中有缺失值。此外,有缺失值的行数比没有缺失值的行数少得多。因此,我们可以删除包含任何缺失值的行。请注意,我们不能总是删除丢失的值。在某些情况下,我们不能放弃它们。相反,我们需要找到一种方法来填充缺失的值。这在很大程度上取决于我们正在进行的任务。

df.drop(['Age', 'Rotten Tomatoes'], axis=1, inplace=True)df.dropna(axis=0, how='any', inplace=True)df.isna().sum().sum()
0df.shape
(15233, 12)

我们已经丢失了大约 9%的行。数据集现在没有任何缺失值。

概述

我们先来看电影内部的语言分布。我们将使用最近发布的名为 sidetable 的 pandas 实用程序库。Sidetable 基于选定的列创建频率表。这是一种改进版本的值计数功能。如果你想了解更多关于 sidetable 的信息,你可以访问下面的帖子:

[## 熊猫侧桌刚刚宣布

对数据框架的信息丰富、见解深刻的概述。

towardsdatascience.com](/pandas-sidetable-just-announced-708e5f65938f)

!pip install sidetable
import sidetabledf.stb.freq(['Language'], thresh=.8)

英语电影遥遥领先。有 10300 部英语电影,占整个数据集的 67%。9 种语言主导了几乎 80%的电影。

IMDb 评级是一部电影非常重要的标准,因为许多人根据 IMDb 评级来选择电影观看。让我们看看 IMDb 收视率的分布。

df['IMDb'].describe()

另一种方法是绘制分布图。

plt.figure(figsize=(10,6))
plt.title("Distribution of IMDb Ratings", fontsize=15)
sns.distplot(df['IMDb'])

大多数电影的平均评分在 5.89 左右,在 5 到 8 之间。我们还在高值和低值上都看到了较少数量的极值。

如果你喜欢看电影,你可能有一个最喜欢的导演。我们可以查看董事的平均 IMDb 评级。

df[['IMDb','Directors']].groupby('Directors').agg(['mean','count']).sort_values(by=('IMDb','mean'), ascending=False)[:10]

这是 IMDb 收视率最高的 10 位导演。然而,他们都只有一部电影,我认为这不足以做出真实的评价。我们改成对至少有 5 部电影的导演进行排名吧。

directors = df[['IMDb','Directors']].groupby('Directors').agg(['mean','count'])directors[directors[('IMDb', 'count')] > 5].sort_values(by=('IMDb','mean'), ascending=False)[:10]

流媒体平台

数据集中包含的平台有网飞、Hulu、Prime Video 和 Disney+。有些电影只能在其中一个平台上观看,而有些电影可以在多个平台上观看。让我们看看每个平台有多少部电影,以及平台的平均 IMDb 评分。

df[['IMDb','Netflix']].groupby(['Netflix']).agg(['mean','count'])

网飞有 3152 部电影,平均 IMDb 评分为 5.8 分。我们可以创建一个 for 循环并将结果保存到一个字典中,然后从该字典创建一个 dataframe,而不是逐个检查。

streams = ['Netflix', 'Hulu', 'Prime Video', 'Disney+']
dict_a = {}for stream in streams:
    a = df[['IMDb', stream]].groupby([stream]).agg(['mean',
        'count']).iloc[1,:].values dict_a[stream] = a df_stream = pd.DataFrame(dict_a, 
                index=['Avg_IMDb','Number of Moviews'])df_stream

我们取 groupby 函数返回的第二行,因为第二行包含该平台上可用电影的数据(1)。然后,该行被保存在一个字典中,其中有一个键是平台的名称。字典完成后,它被转换成数据帧。

Prime Video 拥有迄今为止最多的电影和最低的平均 IMDb 评分。我认为这表明 Prime Video 对内容不是很挑剔。迪士尼+在 IMDb 的平均评分最高,紧随其后的是网飞。

国家

技术和流媒体平台的进步使我们有可能观看来自世界各地的电影。由于不同国家的口味和偏好不同,流媒体平台通常会根据国家的不同而改变其内容。看看哪些国家的内容最丰富。

df.stb.freq(['Country'], thresh=.75)

美国遥遥领先,超过 50%。

运行时

虽然有一些例外,但电影的长度通常在 1.5 到 2 小时之间。我们来看看运行时的分布。

plt.figure(figsize=(10,6))
plt.title("Movie Length Distribution", fontsize=15)
sns.distplot(df.Runtime)

我们看到一个平均值约为 90 分钟的正态分布。

df.Runtime.describe()

平均是 94 分钟。我们还看了一部 1 分钟长的电影,这一定是个错误。让我们看看这些电影是什么。

df.query('Runtime > 300 or Runtime < 2')

卡斯特的最后一站实际上是 328 分钟长,但另一个当然不是 1 分钟。

我想知道这部电影的长度和 IMDb 的收视率之间是否有关联。我们可以用熊猫的corr功能来查。

df[['IMDb','Runtime']].corr()

IMDb 等级和运行时间之间没有显著的相关性。

我们已经尝试从几个不同的角度处理数据集,但是探索性数据分析过程没有限制。根据我们的需要,我们可以从特定的角度来处理数据框架。然而,技术和操作通常是相同的。因此,最好使用不同种类的数据集进行练习。

感谢您的阅读。如果您有任何反馈,请告诉我。

带有 Keras 的卷积神经网络实用指南

原文:https://towardsdatascience.com/a-practical-guide-on-convolutional-neural-networks-cnns-with-keras-21421172005e?source=collection_archive---------47-----------------------

理论解释和实际例子

马库斯·斯皮斯克在 Unsplash 上的照片

卷积神经网络通常用于数据科学领域,尤其是计算机视觉和图像分类任务。考虑一个图像分类任务。图像由用数字表示的像素组成。在 CNN 的卷积层中,滤波器(或特征检测器)被应用于图像,以通过保持像素之间的空间关系来提取图像的独特特征。

卷积运算如下进行:

我们有一个 10x10 的图像和一个 3x3 的过滤器。过滤器从黄色标记的位置开始,扫描图像并创建特征图。在每一步,计算图像像素和滤波器的点积,并将结果标量放入特征图的相应位置。

步幅参数控制滤镜的移动。当跨距为 1 时,过滤器每次移动 1 个像素。

过滤器的目标是保持像素的空间关系,因此它需要看到左侧、右侧、上方和底部的像素。因此,对于 3×3 滤波器,我们从第二行第二列的像素开始。第一行和最后一行上的像素以及第一列和最后一列上的像素不能是特征地图的一部分,因为它们没有上下左右相邻像素。

这就是生成的特征图是 8×8 的原因。如果我们应用一个 5x5 的过滤器,特征图就变成了 6x6。

如果我们想保留边界上的像素,我们可以使用填充并在图像周围添加零。

用零填充的 10x10 图像。生成的图像为 12x12。

在卷积层中,不仅仅使用一个过滤器。许多不同的过滤器被应用于图像。每个过滤器旨在捕捉不同的特征,如边缘、水平线等。

图像是高度非线性的,所以我们需要增加卷积层的非线性。在卷积层中,应用整流器函数来增加图像中的非线性。整流器功能充当额外的滤波器来分解线性。

卷积层

然后,我们有层,它减少了特征地图的大小,同时保持图像的保留特征。

2x2 盒子的最大池

在池层中,捕获一个具有指定大小的框,并获取该框中的最大值。这是最大池。我们也可以取盒子里数值的和或平均值。该框扫描整个特征地图。上图显示的是带有 2x2 方框的 max pooling 图层,因此要素地图的大小缩小为 4x4。

联营的优势:

  • 在保留特征的同时减小尺寸
  • 删除不重要的部分
  • 引入空间方差
  • 减少特征的数量,从而降低过度拟合的风险

在卷积神经网络中,根据任务的复杂程度,有多个卷积层和池层。

现在,我们需要展平合并的要素地图,以便将其提供给完全连接的图层。在展平步骤之后,卷积神经网络的剩余部分的结构就像前馈神经网络一样。展平步骤非常简单。

展平后得到的阵列被用作一个密集层的输入。汇集的要素地图被展平,并通过密集图层传送。卷积神经网络的典型结构是:

图来源

请注意,子采样用于池化。这个卷积神经网络有两个卷积层和两个池层。

我们来看一个真实的例子。

建立 CNN 对图像进行分类

我们将使用来自 Caltech101 数据集的摩托车和飞机图像。这是训练和测试 CNN 的一个很好的数据集。非常感谢社区准备并让我们使用这个数据集。

我们将使用 Keras,这是一个基于 TensorFlow 构建的高级深度学习库。让我们从基本的导入开始:

import numpy as np
import tensorflow as tftf.__version__
'2.2.0-rc3'

我们将使用谷歌 colab 环境来完成这项任务。我把照片保存到了我的谷歌硬盘里。为了从 colab 直接访问驱动器中的文件,我们只需要导入驱动器:

from google.colab import drive
drive.mount('/content/gdrive')

这将提示我们通过复制粘贴链接来批准。然后我们就可以轻松访问 google drive 里的文件了。

让我们使用 matplotlib 检查几张图像:

import matplotlib.pyplot as plt
import matplotlib.image as mpimg%matplotlib inline

图像只是 2D(黑白)和 3D(彩色)中的数字阵列。除了看图像的样子,我们还应该检查图像的结构。

img = mpimg.imread('/content/gdrive/My Drive/airplane_motorbike/train/airplanes/image_0001.jpg')type(img)
numpy.ndarrayimg.shape
(164, 398, 3)

前两个维度显示像素网格的大小,第三个维度指示它是彩色的还是灰度的。所以这个图像是一个 164x398 像素的彩色图像。如果最后一个维度为 1,则图像为灰度。让我们看看它是什么样子的:

imgplot = plt.imshow(img)

让我们再来看一张摩托车的图片:

img2 = mpimg.imread('/content/gdrive/My Drive/airplane_motorbike/train/motorbikes/image_0001.jpg')print(img2.shape)
(161, 262, 3)imgplot = plt.imshow(img2)

你可能已经注意到像素的数量是不同的。摩托车图像的形状是(161,262,3),而飞机图像的形状是(164,398,3)。这些图像必须与 CNN 中使用的形状相同。我们可以手动调整尺寸,但这是一项繁琐的任务。

我们可以使用 Keras 的图像预处理类 ImageDataGenerator 。我们只需要在一个文件夹结构中组织图像,ImageDataGenerator 将处理其余的工作:

文件夹结构

ImageDataGenerator 通过实时数据扩充生成批量张量图像数据。ImageDataGenerator 通过成批应用随机选择和变换(如旋转和移动)来创建许多批图像。所以它增加了数据集的多样性。数据扩充增加了数据的多样性,这是非常有用的,尤其是当图像的数量有限时。增加数据集的多样性有助于获得更准确的结果,还可以防止模型过度拟合。

图像在“飞机”和“摩托车”文件夹中。我把每个类别的 640 张图片放在 train 文件夹中,160 张图片放在 validation 文件夹中。让我们为训练和验证实现 ImageDataGenerator 对象:

from tensorflow.keras.preprocessing.image import ImageDataGeneratorimport os

我们首先为训练集和验证集创建 ImageDataGenerator 对象:

我们传入 rescale 参数来归一化[0,1]范围内的像素值。数据规范化是神经网络中的一项基本实践。

然后,我们指出包含图像的文件的路径:

然后,我们创建训练和验证生成器:

我们使用了 flow_from_directory 方法。另一种选择是使用流量方法。在 keras 文档中详细解释了每种方法的细节。

让我们检查一下参数。第一个是我们在上一步中已经创建的文件路径。目标尺寸表示结果图像的尺寸。训练和验证生成器会将所有图像的大小调整为 150x150 像素。 Batch_size 是一批图像的数量。 class_mode 是二进制的,因为我们有两个类。正如我们在输出中看到的,train 文件夹中有 1280 个图像,validation 文件夹中有 320 个图像,属于两个类。

是时候建立我们的模型了:

我们有 3 个卷积层和一个池层紧接着每个卷积层。在第一个卷积层,我们定义了过滤器的数量和过滤器的大小。我选择使用 16 个大小为 3x3 的滤镜。然后我们定义激活函数为 relu。对于第一个卷积层,我们还需要定义输入形状,因为模型不知道我们图像的大小。对于池层,我们只需要指定用于池的盒子的大小。

对于其他卷积层,我们遵循相同的过程。唯一的区别是,我们不必指定输入形状,因为模型将从上一层的输出中知道输入。

仅第一个卷积图层需要 Input_shape。

然后我们有展平层来展平合并的特征地图。展平的特征地图被输入到一个密集层。然后我们有一个输出层。

重要的是要注意,没有严格的规则来确定滤波器的数量、滤波器的大小、层中神经元的数量等等。这些参数的值根据经验或反复试验来调整。您可以调整并尝试不同的值。

我们刚刚建立了一个 CNN 模型。使用总结方法查看模型概述:

model.summary()

输入图像的尺寸为 150x150。我们使用 3×3 的过滤器,所以特征图的大小是 148×148。在第一个池层中,大小减少了一半。在每个卷积池图层对中,尺寸会减小,但图像中的特征会保留。在这个模型中,我们有超过 200 万个参数要训练,这是一个很大的数目。这是一个简单的图像分类任务。想象一下在非常复杂的任务中训练模型所使用的参数的数量。

现在是编译模型的时候了:

我们需要指定损失函数优化器度量来评估性能。对于损失函数,可以使用二元交叉熵,因为这是二元分类任务。Keras 中有很多优化器,常用的有RMSprop亚当优化器。我们使用的衡量标准是准确性。

我们完成了图像的预处理,模型的建立和编译。现在,我们可以将数据拟合到模型中并对其进行训练:

我们使用之前创建的 ImageDataGenerator 对象作为训练集和验证集。 Steps_per_epoch 参数是图像数量除以批量大小。 Validation_steps 使用验证集中的图像数量和批量大小进行类似计算。当模型通过整个训练集时,一个时期完成。我使用 5 个历元,但是你可以改变它,看看它如何影响精度。让我们看看结果:

该模型在训练集上有 99.69%的准确率,在测试集上有 99.37%的准确率,这是一个很好的结果。请记住,这是一个简单的图像分类任务。我们将处理更复杂的任务。但是,后面构建网络和逻辑的方式是一样的。因此,如果我们很好地学习基础知识,我们可以很容易地适应更复杂的任务。

感谢您的阅读。如果您有任何反馈,请告诉我。

参考文献

  • By Aphex34 —自己的作品,CC BY-SA 4.0,https://commons.wikimedia.org/w/index.php?curid=45679374
  • 长度飞飞、r .弗格斯和 p .佩罗娜。从少量训练示例中学习生成视觉模型
    :在
    101 个对象类别
    上测试的增量贝叶斯方法。IEEE。CVPR 2004,基于视觉的生成模型研讨会。2004

数据可视化实用指南

原文:https://towardsdatascience.com/a-practical-guide-on-data-visualization-5c31a0e0fcd5?source=collection_archive---------46-----------------------

一张图胜过千言万语

我们生活在大数据时代。我们可以收集大量数据,从而推断出有意义的结果,做出明智的商业决策。然而,随着数据量的增加,分析和探索数据变得更加困难。当有效和恰当地使用时,可视化是探索性数据分析的伟大工具。可视化也有助于向你的观众传递信息,或者告诉他们你的发现。没有一种通用的可视化方法,因此某些任务需要不同类型的可视化。在本帖中,我们将介绍如何创建基本情节并有效地使用它们。

我们需要一个样本数据框架来工作。在本帖中,我们将使用两个不同的数据集,它们都可以在 Kaggle 上找到。第一个是电信客户流失数据集,另一个是美国汽车数据集。

import pandas as pd
import numpy as npdf = pd.read_csv("Projects/churn_prediction/Telco-Customer-Churn.csv")df.shape
(7043, 21)

数据集包括 21 列。“流失”列指示客户是否流失(即离开公司),其余列包括关于客户或客户拥有的产品的信息。

注意:有很多工具和软件包可以创建很棒的可视化效果。在这篇文章中,我将使用两个最常见的 matplotlib 和 seaborn。只要你得到你想要的,随便使用任何包装。

import matplotlib.pyplot as plt
import seaborn as snssns.set(style="darkgrid")%matplotlib inline

%matplotlib inline 命令允许渲染笔记本中的图形,以便我们可以立即看到它们。

在开始创建可视化之前,我想强调一点。可视化数据的主要目标是探索和分析数据或解释结果和发现。当然,我们需要注意人物看起来如何,并努力创造有吸引力的人物。然而,没有任何信息力量的非常漂亮的可视化在数据分析中是无用的。让我们从记住这一点开始。

这个数据集的主要对象是客户流失。因此,最好检查一下这个变量的样子:

plt.figure(figsize=(8,5))sns.countplot('Churn', data=df)

我们用 matplotlib 后端创建了一个指定大小的图形对象。然后,使用 seaborn 添加了一个 countplot。这个数字显然告诉我们,该公司善于留住客户,因为流失率实际上很低。

这个数字简单明了。让我们给它增加一些信息的力量。我们可以根据“老年人”和“性别”栏看到客户流失的变化:

sns.catplot('Churn', hue='SeniorCitizen', 
            col='gender', kind='count', 
            height=4, aspect=1, data=df)

性别似乎没有改变流失率,但老年人和非老年人之间存在差异。老年人更有可能流失。我们可以通过以这种方式尝试其他列来扩展我们的分析。

另一种探索数据的方法是检查变量的分布,这给我们一个关于分布和密度的概念。让我们检查一下“任期”和“每月收费”功能。

fig, axs = plt.subplots(ncols=2, figsize=(10,6))sns.distplot(df.tenure, ax=axs[0]).set_title("Distribution of Tenure")sns.distplot(df.MonthlyCharges, ax=axs[1]).set_title("Distribution of MonthlyCharges")

我们用两个支线剧情创建了人物对象。然后,使用 seaborn 创建分布图。我们还使用 set_title 添加了标题:

任期变量表示客户成为客户的时间(以月为单位)。大多数顾客都是新顾客,或者是老顾客了。月度电荷变量呈现出奇怪的分布,但在最低量上可以看到高密度。

另一种了解数据分散性的方法是箱线图

plt.figure(figsize=(10,6))sns.boxplot(x="Contract", y="MonthlyCharges", data=df)

方框中的线代表中间值。方框的下边缘和上边缘分别显示第一和第三分位数。所以,高的方框表示数值更加分散。从这个情节中我们可以理解:

  • 短期合同的价格范围较小
  • 随着合同期的延长,月费趋于减少

第二数据集相对于目标变量是不同的。流失是一个分类变量,它使任务成为一个分类,而价格是连续的,我们需要解决一个回归问题来预测价格。

删除冗余列后,cars 数据集如下所示:

让我们看看里程和价格是如何关联的:

sns.relplot(x="price", y="mileage", hue="brand", data=df,
           height=6, aspect=1.2)

不出所料,价格和里程是负相关的。另一个值得注意的是“尼桑”汽车。与其他品牌相比,它们位于低价位——低里程区域。

让我们来看看价格的分布:

plt.figure(figsize=(10,6))sns.distplot(df['price']).set_title('Distribution of Car Prices')

价格变量不是正态分布的。它是右偏的,意味着分布的尾部右侧比左侧长。另一种证明偏度的方法是比较平均值和中位数。如果平均值高于中值,则分布是右偏的。Mean 是平均值,median 是中间的值。因此,如果平均值高于中位数,我们有更多的样本在中位数的上边。

如预期的那样,平均值高于中值。所以,昂贵的汽车比便宜的汽车多。

现在我想展示两种相关的可视化类型:散点图和点状图。散点图通过分散数据点显示两组数据之间的关系。点阵图显示点估计值和置信区间。所以,这是一种基于散点图的估计。如 seaborn 文档中所述,“点阵图通过散点图点的位置来表示对数值变量的集中趋势的估计,并使用误差线来提供该估计周围的不确定性的一些指示”。让我们来看一个例子,让这个概念更清楚:

#Scatter plot
plt.figure(figsize=(12,8))
sns.scatterplot(x="age", y="mileage", data=df).set_title("Scatter plot")#Point plot
plt.figure(figsize=(12,8))
sns.pointplot(x="age", y="mileage", data=df).set_title("Point plot")

点图上条形的长度与不确定性成正比。如果我们比较两个图,我们会发现散点图点密集的区域中的条形较短。

还有许多不同的可视化类型。根据任务的不同,不同的选项可能更合适。还有动态图,通常是时间序列分析的更好选择。所有可视化的共同点是,它们都是探索性数据分析和数据科学讲述部分的伟大工具。

关于探索性数据分析的更多信息

感谢您的阅读。如果你有任何问题,请让我知道。

探索性数据分析实用指南:城市的历史温度

原文:https://towardsdatascience.com/a-practical-guide-on-exploratory-data-analysis-historical-temperatures-of-cities-e4cb0ca03e07?source=collection_archive---------54-----------------------

全球变暖是真的吗?

玛格达莱娜·库拉·曼切在 Unsplash 上的照片

我最近在 Kaggle 上发现了一个有趣的数据集,它包含了 321 个城市从 1995 年到 2020 年的历史气温。我认为在关于全球变暖的讨论中探索这个数据集将是一个很好的实践。你可以在 Kaggle 上的这里访问数据集

我将使用 python 数据分析库 pandas 和基于 plotly javascript (plotly.js)构建的开源绘图库plotly python(plotly . py)。

让我们从导入库和将数据集读入 pandas 数据帧开始。当我阅读数据集的描述时,我发现值“-99”被用作温度的缺失值标记。我们可以使用 read_csv 函数的 na_values 参数将“-99”替换为熊猫的标准缺失值表示,即 NaN。我们也可以在创建数据帧后进行替换,但我认为在读取数据时更容易处理。

#Data analysis
import numpy as np
import pandas as pd#Data visualization
import plotly.express as pxdf = pd.read_csv("/content/city_temperature.csv", na_values=[-99])
print(df.shape)
(2906327, 8)df.head()

年份范围应该是 1995-2020 年。我们可以使用 value_counts 来确认。

我们对“201 年”和“200 年”有些误解。我认为这些只是错别字,代表了很小一部分数据。

这些年的总行数是 440,与 2906327 行相比是非常小的。再者,我们无法知道这些年的真实值是多少。因此,我们可以删除年份为 201 或 200 的行。

df = df[df.Year > 1900]

让我们也寻找丢失的值。

df.isna().sum()

“州”列中有许多缺失值是正常的,因为大多数国家没有州的概念。因此,我们将忽略缺失状态。另一个缺少值的列是“AvgTemperature”。数据集的结构是连续的行每天都在变化,因此缺失的温度值可以向前填充。对于缺失的温度,我们将假设日平均温度与前一天相同。如果城市的第一条记录丢失,这种方法的一个缺点就会出现。我们将使用 fillna 并将“ffill”传递给方法参数。

df['AvgTemperature'].fillna(method='ffill', inplace=True)

数据集包含“华氏”温度,但我更熟悉“摄氏”值。让我们通过将华氏温度转换为摄氏温度来增加一列。

df['celcius'] = (df['AvgTemperature'] - 32) * 5/9
df.head()

我们知道,非洲国家总体上气温最高。但是,世界上不同地区之间有很大的差异吗?我们可以使用 groupby 函数来查看 1995 年到 2020 年间各地区的平均温度。

df[['Region','celcius']].groupby('Region').mean().sort_values(by='celcius', ascending=False)

非洲的平均温度大约是欧洲平均温度的两倍。平均值与我们的地理知识相符。随着我们远离赤道,温度会降低。

年度价值如何?全球变暖是真的吗?让我们先看一下各地区的年平均值。

df_region = df[['Region','Year','celcius']].groupby(['Region','Year']).mean().reset_index()df_region.head()

我们现在可以用线图来显示趋势。

fig = px.line(
df_region, x="Year", y="celcius", color='Region',
title='Avg Temperature in Regions from 1995 to 2020')fig.show()

所有地区都略有增加。我们忽略 2020 年,因为它还没有完成。看来全球变暖是真的。我们还可以对比 1995 年和 2019 年的平均值。

df[df.Year.isin([1995,2019])][['Region','Year','celcius']].groupby(['Region','Year']).mean().reset_index()

所有地区的平均气温都上升了。看来全球变暖是真的。

地球形状和运动的一个好处是,不同半球的国家在同一时间有不同的季节。虽然欧洲是冬天,澳大利亚却享受夏天。让我们看看我们是否能在月平均气温中看到这种趋势。

df_region2 = df[['Region','Month','celcius']].groupby(['Region','Month']).mean().reset_index()df_region2.head()

我们现在有各地区的月平均气温。让我们画出它们。

fig = px.line(
df_region2, x="Month", y="celcius", color='Region',
title='Avg Monthly Temperatures in Regions',
width=900, height=400)fig.show()

我们确实观察到南北半球不同季节的影响。在一些地区,不同季节的气温变化很大,而非洲和南/中美洲的气温波动不大。这与这些地区的地理位置和面积有关。

一件有趣的事情是检查世界上最热和最冷的城市。以下是最热门的 10:

df[['City','celcius','Country']].groupby(['City','Country']).mean().sort_values(by='celcius',ascending=False).reset_index()[:10]

你可能会惊讶,最热城市的温度竟然是 30 摄氏度。我们可以通过使用[-10:]选择最后 10 行来查看最冷的 10 行。

大多数最冷的城市在加拿大或美国。

在过去的 25 年里,全世界的平均气温都在上升。全球变暖是科学家一再强调的一个严重问题。正如我们所看到的,真实的测量结果与科学家和研究人员所关心的一致。我们需要认真对待这件事。

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫缺失价值观实用指南

原文:https://towardsdatascience.com/a-practical-guide-on-missing-values-with-pandas-8fb3e0b46c24?source=collection_archive---------32-----------------------

处理缺失值的综合指南。

照片由 Zach Lucero 在 Unsplash 上拍摄

缺失值表示我们没有关于特定观察(行)的特征(列)的信息。为什么不直接从数据集中删除那个观察值,然后继续呢?我们可以,但不应该。原因是:

  • 我们通常有许多观察特征,所以我们不想仅仅因为一个缺失的特征而失去观察。数据是有价值的。
  • 我们通常会有多个观测值缺失。在某些情况下,我们不能从数据集中删除许多观察值。还是那句话,数据是有价值的。

在本帖中,我们将介绍如何检测和处理丢失的值,以及一些需要记住的要点。

帖子的概要:

  • 缺少值标记
  • 检测缺失值
  • 缺少值的计算
  • 处理缺失值

一如既往,我们从进口熊猫开始。

import numpy as np
import pandas as pd

缺少值标记

Pandas 中默认的缺失值表示是 NaN ,但是 Python 的 None 也被检测为缺失值。

s = pd.Series([1, 3, 4, np.nan, None, 8])
s

虽然我们用整数创建了一个序列,但是值被向上转换为 float,因为 np.nan 是 float。熊猫 1.0 引入了缺失值的新表示法,即 < NA > 。它可以与整数一起使用,而不会导致向上转换。我们需要显式地请求 dtype 为 pd。Int64Dtype()。

s = pd.Series([1, 3, 4, np.nan, None, 8], dtype=pd.Int64Dtype())
s

整数值不会被强制转换为浮点型。

另一个缺失的值表示是用于表示 datetime64[ns]数据类型的 NaT

:名词性的不相等,而没有一个是相等的。

注意:并非所有丢失的值都是简洁明了的 np.nan 或 None 格式。例如,我们处理的数据集可能包含“?”和“- -”值。当将数据集读入熊猫数据帧时,我们可以将它们转换成 np.nan 表示。我们只需要将这些值传递给na_values参数。

检测缺失值

让我们首先创建一个示例数据框架,并向其中添加一些缺失的值。

df = pd.DataFrame({
'col_a':np.random.randint(10, size=8),
'col_b':np.random.random(8),
'col_c':[True, False, True, False, False, True, True, False],
'col_d':pd.date_range('2020-01-01', periods=8),
'col_e':['A','A','A','B','B','B','C','C']
})df.iloc[2:4, 1:2] = np.nan
df.iloc[3:5, 3] = np.nan
df.iloc[[1,4,6], 0] = np.nan
df

正如我们前面提到的,NaT 用于表示 datetime 缺失值。

isna()返回用布尔值表示缺失值的数据帧。

isna().sum()返回每列中缺失值的数量。

notnaisna 相反,因此notna().sum()返回非缺失值的个数。

isna().any()返回每列的布尔值。如果该列中至少有一个值缺失,则结果为真。

有缺失值的计算

np.nan 和数字之间的算术运算返回 np.nan。

df['sum_a_b'] = df['col_a'] + df['col_b']
df

cumsumcumprod 这样的累积方法默认情况下会忽略缺失值,但是它们会保留缺失值的位置。

df[['col_a','col_b']].cumsum()

我们可以通过设置skipna 参数为假来改变这种行为。

df[['col_a','col_b']].cumsum(skipna=False)

缺失值现在包括在求和中。因此,第一个 nan 之后的所有值也是 nan。

Groupby 函数默认排除缺失值。

df[['col_e','col_a']].groupby('col_e').sum()

处理缺失值

主要有两种方法来处理缺失值。我们可以丢弃丢失的值,或者用合适的值替换它们。更好的选择是替换丢失的值,但是在某些情况下,我们可能需要删除它们。

删除缺失值

我们可以使用dropna()函数删除缺少值的行或列。how 参数用于设置下降条件。

  • how='any ':如果有任何缺少的值,则删除
  • how='all ':如果所有值都丢失,则删除

让我们首先稍微修改一下我们的数据框架:

df.iloc[7,:] = np.nan
df

how=’any’将删除除第一行和第六行之外的所有行:

how=’all’只会删除最后一行:

注意:为了将这些更改保存在原始数据帧中,我们需要将inplace 参数设置为真。

使用thresh 参数,我们可以设置缺失值的阈值,以便删除某行/列。如果axis 参数设置为 1,Dropna 也进行列操作。

替换缺失值

fillna()熊猫功能方便处理缺失值。使用fillna(),缺失值可由特殊值或聚合值替代,如平均值、中值。此外,缺失的值可以用它之前或之后的值替换,这对时间序列数据集非常有用。

我们可以选择一个值来替换数据帧中所有缺失的值,但这没有任何意义。相反,我们可以创建一个字典,指示在不同的列中使用不同的值。

replacements = {'col_a':0, 'col_b':0.5, 'col_e':'Other'}
df.fillna(replacements)

我们可以使用聚合函数作为值来替换缺失的值:

df['col_b'].fillna(df['col_b'].mean())

我们也可以使用method 参数用它们之前或之后的值来填充缺失的值。 ffill 代表“向前填充”,用前一行的值替换缺失的值。顾名思义, bfill (反向填充)做的正好相反。如果一列或一行中有许多连续的缺失值,我们可以使用 limit 参数来限制向前或向后填充的缺失值的数量。

所有缺少的值都用前一个单元格中的值填充。让我们将需要填充的缺失值的数量限制为 1:

让我们尝试使用 bfill 方法来填充缺失的值:

末尾的值仍然是缺失的,因为它们后面没有值。

加成:插值

interpolate 通过插值填充缺失值,这对于序列或时间序列数据特别有用。默认方法是线性的,但可以使用方法参数进行更改。一些可用的选项是多项式,二次,三次。我们来做一个线性插值的例子。

s = pd.Series(np.random.random(50))
s[4, 5, 9, 11, 18, 19, 33, 34, 46, 47, 48] = np.nan
s.plot()

ts.interpolate().plot()

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫侧桌实用指南

原文:https://towardsdatascience.com/a-practical-guide-on-pandas-sidetable-581dda0864ec?source=collection_archive---------53-----------------------

如何有效利用侧桌?

马库斯·斯皮斯克在 Unsplash 上拍摄的照片

Pandas 是一个非常强大和通用的 Python 数据分析库,它加速了数据科学项目的预处理步骤。它提供了许多在数据分析中非常有用的函数和方法。

虽然熊猫的内置功能能够执行有效的数据分析,但定制的功能或库为熊猫增加了价值。在本帖中,我们将探索这些附加组件中的一个,它是 侧表

Chris Moffitt 创建的 Sidetable 提供了一个基于所选列的频率表。这也可以使用 pandas 的**value_counts**功能来实现,但是 sidetable 更加灵活和全面,正如我们将在示例中看到的。

如果你使用 jupyter 笔记本,我们首先需要用pip!pip安装它:

!pip install sidetable

我们现在可以和熊猫一起进口 sidetable。

import pandas as pd
import sidetable

我将使用一个视频游戏数据集,它可以在 kaggle 上这里获得。让我们将 csv 文件读入 pandas 数据帧,并开始处理示例。

df = pd.read_csv("/content/vgsales.csv")df.shape
(16598, 11)df.head()

该数据集包含 16598 个视频游戏,销售额(以百万计)和一些特征,如流派、出版商和年份。让我们看看数据集中有多少不同的流派。

df.Genre.nunique()
12

我们可以使用value_counts查看每个流派有多少游戏。

df.Genre.value_counts()

动作和体育类游戏最多。我们可能希望看到每种类型的比例,而不是数量。归一化value_counts参数可以如下使用。

df.Genre.value_counts(normalize=True)

几乎 20%的游戏属于动作类。我认为同时看到计数和百分比要好得多。Sidetable 提供了这种便利以及一些其他信息统计。

Sidetable 用作带有 stb 关键字的数据帧上的访问器。

df.stb.freq(['Genre'])

如您所见,显示了计数和百分比值。除此之外,还提供了累积值。例如,前 4 个流派构成了整个数据集的 53%。

在某些情况下,可能有许多不同的类别,这使得很难看到所有的类别。sidetable 的 Thresh 参数允许根据累计百分比的阈值限制显示值。例如,我们可以显示包含 70%视频游戏的平台。

df.stb.freq(['Platform'], thresh=70)

视频游戏数量最多的前 8 个平台占整个数据集的 69.96%。其余的合并在“其他”标签下。侧表允许使用其他标签参数更改该标签。

df.stb.freq(['Platform'], thresh=70, other_label="Other Platforms")

到目前为止,我们已经根据一列中的类别研究了数据的分布。Sidetable 允许组合多个列,并检查更具体的类别。例如,最常见的平台类型组合可以用 sidetable 来检查。

df.stb.freq(['Platform', 'Genre'], thresh=15)

最常见的平台类型类别是 PS2 体育,占整个数据集的 2.4%。前 8 个平台类型对构成了数据集中所有视频游戏的近 15%。

默认情况下,如“计数”列所示,sidetable 返回每个类别的观察次数。考虑上面的例子。数据集中有 400 个视频游戏属于 PS2-体育类别(即平台是 PS2,类型是体育)。然而,我们可能对其他一些措施感兴趣。例如,在我们的例子中,我们可能需要根据全球销售额对平台进行排序。使用参数可轻松实现侧钻。我们只需要将列名传递给值参数。

df.stb.freq(['Platform'], value='Global_Sales', thresh=50)

PS2 游戏的全球销售额约为 12.6 亿美元。有趣的是,平台“DS”在全球销售额方面并不在前 4 名,尽管它在数据集中拥有最高数量的游戏。

全球销售额和数量方面的平台比较

虽然 DS 平台在游戏数量上排名第一,但它并没有产生最高的销售额。可能的原因:

  • DS 游戏不是很受欢迎,所以不如其他平台的游戏卖得多
  • DS 游戏比其他流行平台的游戏便宜

与 DS 相反,X360 平台的游戏数量少于 DS、PS3 和 Wii,但销售额却更高。同样可能的原因适用,但以相反的方式。X360 游戏可能比其他平台更便宜或销量更高。

Sidetable 还可用于生成缺失值的概览。

它返回每列中缺失值的数量以及缺失值的比率。

sidetable 的另一个非常有用的函数是subtotal ,它可以应用于groupby 函数来轻松计算分类汇总。用例子会更清楚。我们先来看看北美、欧洲、日本各流派的总销量。

df[['NA_Sales','EU_Sales','JP_Sales', 'Genre']].groupby('Genre').sum()

它返回每个流派在指定地区的总销售额,但不计算小计。我们只需要添加 stb.subtotal()来计算小计。

df[['NA_Sales','EU_Sales','JP_Sales', 'Genre']].groupby('Genre').**sum().stb.subtotal()**

还有其他方法来计算小计,但 stb.subtotal 使它更简单。当有嵌套的类别时,您可以更多地感受到方便。

我认为熊猫的成功和流行来自于其多功能、强大且易于使用的操作和分析数据的功能。和熊猫一起完成一项任务几乎总是有多种方式。熊猫上添加的定制实用程序库优化了某些操作,并为熊猫带来了更多价值。再次感谢克里斯·莫菲特提供了这个宝贵的工具。

感谢您的阅读。如果您有任何反馈,请告诉我。

R 中的 Bootstrap 实用指南

原文:https://towardsdatascience.com/a-practical-guide-to-bootstrap-with-r-examples-bd975ec6dcea?source=collection_archive---------0-----------------------

统计数字

什么,为什么,什么时候,怎么做

梅格·坎南在 Unsplash 上的照片

2020 年 8 月 11 日更新

TL;速度三角形定位法(dead reckoning)

  • Bootstrap 是一种带替换的重采样方法。
  • 它允许我们估计人口的分布,甚至从一个单一的样本。
  • 在机器学习中,bootstrap 在应用于未观察到的数据时估计预测性能。
  • 数据集和 R 代码请查看我的 Github ( 链接)。

什么是自举?

Bootstrap 是一种重采样方法,从单个原始样本中重复抽取相同大小的大量样本 并替换

这是英文翻译。通常,不可能从一个或有限数量的样本中推断出总体参数。总体的不确定性来源于抽样的可变性:一个样本有一个值,而如果我们收集另一个样本,就会得到另一个值。

下一个问题是:

如何消除变异性,尽可能逼近总体参数?

通过重复替换采样,bootstrap 创建了高斯分布的结果样本分布,这使得统计推断(例如,构建置信区间)成为可能。

引导分为以下步骤:

  1. 决定执行多少引导样本
  2. 样本量是多少?
  3. 对于每个引导样本:
  • 用所选尺寸的替换物绘制样品
  • 计算该样本的兴趣统计量

4。计算样本统计的平均值

这些过程可能看起来有点令人生畏,但幸运的是,我们不必手动运行计算。现代编程语言(如 R 或 Python)为我们处理了这些脏活。

照片由米切尔罗Unsplash 上拍摄

为什么自举?

在回答为什么之前,让我们看看作为数据科学家我们面临的一些常见的推理挑战。

在 A/B 测试之后,我们能在多大程度上相信一个小样本量(比如 100)能代表真实的总体?

如果重复取样,对利息的估计会有变化吗?如果它们确实不同,分布是什么样的?

当人口的分布太复杂或未知时,有可能作出有效的推论吗?

做出有效的统计推断是数据科学家日常工作的主要部分。然而,有效的推断有严格的假设和前提,这些假设和前提可能不成立或仍然未知。

理想情况下,我们希望收集整个人口的数据,这样可以省去一些统计推断的麻烦。显然,考虑到时间和金钱上的花费,这是一种昂贵的并且不推荐的方法。

例如,调查所有美国人的政治观点是不可行的,但是调查一小部分美国人,比如 1 万名美国人,并询问他们的政治偏好是可行的。

这种方法的挑战在于,每次收集样本时,我们得到的结果可能会略有不同。从理论上讲,对于来自总体的重复抽样,点估计的标准差可能相当大,这可能会使估计有偏差。

妙语如下:

作为一种非参数估计方法,bootstrap 派上了用场,它量化了估计值与标准差之间的不确定性。

维多利亚摄她Unsplash

什么时候?

对于以下情况,引导是一种理想的方法:

  1. 当统计数据的分布未知或复杂时。
  • 原因 : bootstrap 是非参数方法,不要求特定的分布)。

2.当样本量太小而无法得出有效的推论时。

  • 原因 : bootstrap 是一种带有替换的重采样方法,如果需要,可以重新创建任意数量的重采样。

3.你需要一个试点研究,在把你所有的资源倒向错误的方向之前,先感受一下水的味道。

  • 原因:与#2 点相关,bootstrap 可以创建总体的分布,我们可以检查方差)。

r 代码

既然 Sport 回来了, DraftKings 也是最近的趋势,我就用凯尔特人和热火的 NBA 季后赛第六场( Github )。

mydata <- read.csv("Celtics_Heat_Game_6_Actual.csv")
mydata

我们感兴趣的是两个变量之间的相关性:球员被选中的百分比( X .被选中)和梦幻得分( FPTS )。

计算一个游戏的相关性很简单,但实用价值不大。我们有一个普遍的印象,顶级球员(如杰森·塔图姆、吉米·巴特勒)会成为选秀最多的球员,也会在一场比赛中获得最多的分数。

可能有助于挑选下一场比赛的球员的是:

如果我们抽取重复的样本 10,000 次,这两个变量之间的相关范围是多少?

在 R 中,自举有两个步骤。

如果你还没有安装软件包启动。

第 0 步:包装准备

install.packages('boot',dep=TRUE)library(boot)

步骤 1:定义一个计算感兴趣的指标的函数

function_1 <- function(data, i){
 d2 <- data[i,] 
 return(cor(d2$X.Drafted, d2$FPTS))
}

上面的函数有两个参数:数据i 。第一个参数 data 是要使用的数据集,而 i 是将从数据集中选取哪些行来创建引导样本的向量索引。

第二步:应用 boot() 功能

set.seed(1)
bootstrap_correlation <- boot(mydata,function_1,R=10000)

记住设置种子以获得可重复的结果。boot()函数有三个参数:数据集、哪个函数和引导样本的数量。

bootstrap_correlation

两个变量之间的原始相关性为 0.892,标准误差为 0.043。

summary(bootstrap_correlation)

返回值是一个名为“boot”的类的对象,它包含以下部分:

t0:原始数据集中我们的统计值

t:有 sum(R)行的矩阵,每一行都是调用统计结果的 bootstrap 副本

(更多信息请参考R 文档 )。)

class(bootstrap_correlation)
[1] "boot"range(bootstrap_correlation$t)
[1] 0.6839681 0.9929641mean(bootstrap_correlation$t)
[1] 0.8955649sd(bootstrap_correlation$t)
[1] 0.04318599

bootstrap 样本的一些其他常见统计数据:范围、平均值和标准差,如上所示。

boot.ci(boot.out=bootstrap_correlation,type=c(‘norm’,’basic’,’perc’,’bca’))

这就是我们如何计算自举样本的 4 种置信区间。

照片由埃琳娜·科劳彭伯格Unsplash 上拍摄

结论

在上面的例子中,我们感兴趣的是两个变量之间的相关性: X.DraftedFPTS 。然而,这只是一个样本,有限的样本量使得很难在群体水平上概括这一发现。换句话说,我们能把发现从一个样本扩展到所有其他情况吗?

在第六场比赛中,被选中的球员百分比和在 DraftKings 获得的幻想分数之间的相关系数为 0.89。我们将样本引导 10000 次,得到以下样本分布:

  1. 相关系数的范围:[0.6839681,0.9929641]。
  2. 平均值:0.8955649
  3. 标准偏差:0.04318599
  4. 95%置信区间:[0.8041,0.9734]

我们可以看到,系数的范围相当宽,从 0.68 到 0.99,95% CI 从 0.8 到 0.97。下次我们可能会得到 0.8 的相关系数。

两个统计数据都表明,这两个变量从中度到强相关,我们可能会在这两个参与者之间得到一个不太强相关的关系(例如,因为对顶级参与者均值的回归)。实际上,我们在挑选表现最好的球员时应该特别小心。

Medium 最近进化出了自己的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。

[## 阅读叶雷华博士研究员(以及其他成千上万的媒体作家)的每一个故事

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

leihua-ye.medium.com](https://leihua-ye.medium.com/membership)

关于数据集和 R 代码,请查看我的 Github ( 链接 )。

[## 使用 5 种机器学习算法对罕见事件进行分类

哪一种最适合不平衡数据?有什么权衡吗?

towardsdatascience.com](/classifying-rare-events-using-five-machine-learning-techniques-fab464573233)

喜欢读这本书吗?

请在 LinkedIn和 Youtube 上找到我。

还有,看看我其他关于人工智能和机器学习的帖子。

DBSCAN 方法实用指南

原文:https://towardsdatascience.com/a-practical-guide-to-dbscan-method-d4ec5ab2bc99?source=collection_archive---------11-----------------------

流行的聚类方法 DBSCAN 的综合指南

检索 2020 年 4 月 19 日,来自【gloria.com】

当我在处理我的第一个数据科学任务时,我想使用 DBSCAN(带噪声的基于密度的应用程序空间聚类)进行聚类,我多次搜索以下问题的答案:

  • 如何选择 DBSCAN 参数?
  • DBSCAN 如何工作?
  • DBSCAN 如何选择哪个点将属于哪个集群?
  • 为什么用 DBSCAN 而不用 K-means?

当然,要找到所有这些问题以及更多问题的答案并不困难。然而,可能很难找到一篇总结所有这些和许多其他基本问题的文章。此外,你可能会感到惊讶,但一些重要的问题没有这样容易得到的答案。

我的目标是编写一个指南,总结 DBSCAN 方法,回答所有这些问题以及更多问题。我发现 DBSCAN 算法不如 K-means 和层次聚类等其他流行的聚类方法直观,所以我将使用许多示例,并且我保证在本文结束时,您会理解这种方法。

基于密度的聚类的动机

两种流行的聚类方法是:分区和层次方法。

划分方法将数据集划分为 k(方法的主输入)个组(簇)。分区迭代过程将数据集中的每个点或对象(从现在起我将把它称为点)分配给它所属的组。将点分配到组中后,通过取组中所有点的平均值来计算组的平均值(质心)。最广为人知的划分方法是 K-means 。分区方法有一些明显的缺点:您应该预先知道要将数据库分成多少个组(K 值)。另一个重要的缺点是 K-means 在发现非凸/非球形的簇时表现不佳(图 1)。此外,K-means 对噪声数据很敏感。

图 1-K-means 不能识别的聚类形状。检索自数据挖掘简介(谭,Steinbach,Kumar,2004)

分层方法使用特殊的树(树状图)为数据创建一个分层的可视化表示。凝聚层次聚类法始于其聚类中的每个点,在每一步中,它将相似或接近的聚类合并为一个聚类。在最后一步中,所有点都在同一个簇中。与 K-means 相反,您不需要决定应该有多少个聚类,但它也有一些严重的缺点:它不适合大数据集,计算复杂性高,您需要选择影响聚类结果的合并聚类的度量(链接)。此外,每个度量都有其缺点:对噪声敏感,难以处理簇密度的严重差异,以及对簇的形状和大小敏感。

正如我们所看到的,划分和分级方法的主要缺点是:处理噪声,并且在寻找非球形的簇时得到不好的结果。

DBSCAN 聚类方法能够表示任意形状的聚类并处理噪声。

图 2-任意形状的簇,例如“S”形和椭圆形簇。检索自数据挖掘:概念与技术 s(韩,Peri,Kamner,2011)。

DBSCAN 直觉

让我们想象一个有很多居民和游客的大城市。想象一下,在不远的地方有一个小村庄。如果我们带一个外星人去两个地方,尽管它们离得很近,他也能很容易地分辨出它们是完全不同的地方。是的,景色、面积、建筑和其他许多方面都完全不同。但是有一个方面与我们的案例相关——地方的密度。城市很拥挤,有很多当地人和游客,而村庄很小,人少得多。

根据密度来区分点组是 DBSCAN 的主要思想。

DBSCAN 概念

DBSCAN 将具有密集邻域的点组合成簇。

如果一个点附近有许多其他相邻点,则该点将被认为是拥挤的。DBSCAN 找到这些拥挤的点,并将它们和它们的邻居放在一个簇中。

DBSCAN 有两个主要参数-

  • ε (或 eps 或 epsilon)——定义每个邻域的大小和边界。ε(必须大于 0)是半径。点 x 的邻域称为 x 的ε-邻域,是围绕点 x 的半径为ε的圆/球。

一些书籍和文章将 x 的ε-邻域描述为:

数据挖掘和分析中检索的公式。基本概念和算法(扎基,梅拉,梅拉,2014 年

在图 3 中,我们可以看到不同大小的ε如何定义 x 的ε-邻域。

图 3 —我们可以看到ε大小如何影响 x 的ε邻域的大小。

现在,您可能会问自己,为什么它是基于密度的集群?一个非常密集的邻域和一个稀疏的邻域会被认为是两个不同的邻域(图 4),然后被分成两个不同的簇吗?

图 4 —密集邻域和稀疏邻域。

点 x 和它的邻居会在一个邻域内,而 y 和它的几个邻居会在另一个邻域内。然而,最终,点 x 和它的邻居可能会在一个聚类中,而点 y 和它的邻居会被认为是异常值或噪声。这是因为 y 的ε-邻域不够稠密。邻域包含的点越多,密度就越大。

如何定义一个邻域是否足够密集?为此,DBSCAN 使用 MinPts 参数。

MinPts — 密度阈值。如果一个邻域至少包含 MinPts 个点,它将被视为一个密集区域。或者,如果一个点的ε-邻域中至少有 MinPts 个点的值,则该点将被认为是稠密的。这些密集的点被称为核心点*。*

让我们再次检查图 4,如果 MinPts 参数是 3,点 x 将是核心点,因为它的ε-邻域的大小是 9,并且它大于 3。点 y 不会是核心点,因为它的ε-邻域包含两个点。

** 点 x 的ε-邻域内的点数包含 x 本身。*

一个边界点有包含少于 MinPts 个点的ε-邻域(所以它不是一个核心点),但它属于另一个核心点的ε-邻域。

如果一个点不是核心点,也不是边界点,那么它就是一个噪声点或者一个离群点。

在图 5 中我们可以看到点x 是一个核心点,因为在其ε-邻域中它有超过 11 个点。点 y 不是核心点,因为它的ε-邻域中的点少于 11 个,但是因为它属于点 x 的ε-邻域,并且点 x 是核心点,点 y 是边界点。我们很容易看出 z 点不是核心点。它属于 y 点的ε-邻域,而 y 点不是核心点,因此 z 点是一个噪声点。

图 5-在这个图中我们可以看到三种类型的点:x 是核心点,y 是边界点,z 是噪声点。

既然我们看到核心点和边界点将在一个集群中,那么 DBSCAN 如何知道哪个点去哪个集群呢?为了回答这个问题,我们需要定义一些定义:

直接 密度可达— 点 y 是从点 x 直接密度可达的,如果:

  • 点 y 属于点 x 的ε-邻域
  • 点 x 是一个核心点。

在图 5 中,点 y 是从点 x 可直接密度到达的点。注意,点 x 不是从点 y 可直接密度到达的点,因为点 y 不是核心点。

密度可达— 点 y 是从点 x 可达的密度,如果在点 x 和点 y 之间有一条点的路径,其中路径中的每一个点都可以从前一个点直接到达。这意味着路径上的所有点都是核心点,除了 y 点。我们可以在图 6 中看到一个例子。

维基百科:

如果有一条路径 P₁ P₂ …, Pₙ P₁ = p, Pₙ = q,则从核心点 p 到点 q 是可达的,这条路径上的所有点都是核心点,除了点 q 可能例外

图 6-点 y 是从点 x 可达到的密度。点 y 是边界点,点:x、z 和 p 是核心点。

密度连通- 一个点 x 与一个点 y 是密度连通的,如果有一个点 o 使得 x 和 y 都是密度可达的。通过这种方式,DBSCAN 在密集区域中连接核心对象和它们的邻居。我们可以在图 7 中看到一个例子。

图 7-点 x 和点 y 是从点 o 密度可达的。因此,点 x 是密度连接到点 y 的。图从数据库中的知识发现(Seidl,2016) 检索并由我编辑。

基于密度的聚类:聚类 C 是一个非空的点组,给定:

  • 点 x 在 C 中,y 是从 x 密度可达的,在这种情况下,y 将在 C 中
  • C 中的所有点都是密度相关的

在图 6 中,点 x、y、z、p 和 y 将在同一个群中。

DBSCAN 算法

输入:

  • D —具有 n 个点的数据集
  • **min pts——邻域密度阈值
  • ε-邻域半径

方法:

1)我们将数据中的所有点标记为未访问。

2)我们随机选择一个未访问的点进行访问,并将其标记为已访问。姑且称之为‘p’吧。

3)我们检查 p 的ε-邻域是否至少有 MinPts 个点。

如果‘p’在其ε-邻域中没有足够的点(图 8),我们将其标记为噪声,并继续执行步骤 4。

*注意,在稍后的迭代中,在步骤 3.d 中,该点可能被包括在一个聚类中。

图 8-点“p”将被视为噪声,因为其ε-邻域包含的点少于 MinPts 点。

如果点‘p’在其ε-邻域内有足够多的点(图 9 ),我们继续步骤 3.a

图 9—‘p’在它的ε-邻域中有超过个 MinPts

3.a)我们将创建一个新的集群 C,并将“p”添加到该集群中。

3.b)我们将给 p 的ε-邻域取一个新名字——N(图 10)。n 将包括这些点:{a,b,c,d,e,f,g,h,i}

图 10-我们将赋予 p 的ε-邻域一个新的名字-N. 图 8-10 检索于 2020 年 4 月 19 日,来自 爱尔兰时报 由我编辑

3.c)我们将对 n 中的每个点执行以下步骤。第一个点是“a”。如果“a”未被访问,我们将执行步骤 3.c.1 和 3.c.2。否则,我们将继续执行步骤 3.d。

3.c.1)我们将点‘a’标记为已访问。****

3.c.2)我们将检查点‘a’在其ε-邻域中是否至少有 MinPts。如果是这样,我们将把这些点加到 N 上。例如,如果‘a’的ε-邻域包括点{j,k,l}并且 MinPts 是 3,则新的 N 将包括点:{a,b,c,d,e,f,g,h,I,j,k,l }。但是,如果‘a’的ε-邻域仅包括点{j},N 将保持不变。

3.d)如果点‘a’不属于任何聚类,我们将把它添加到聚类 C,现在聚类 C 将包括点‘a’和‘p’。

3.e)我们将移动到 N 中的下一个点(点‘b’)并返回到步骤 3.c。在检查了 N 中的所有点之后,我们将完成重复步骤 3.c-3.e。记住,N 可能随时更新(步骤 3.c.2)

4.我们已经完成了 p。我们将返回到步骤 2,访问下一个未访问的点,并重复这些步骤。当访问完数据集中的所有点时,我们就结束了。

算法的一个例子-

图 11。检索于 2020 年 4 月 19 日,来自走向数据科学(Seif,2018)

我推荐查一下 这个 DBSCAN 玩具例子(舒伯特,2018)

MinPts 和ε怎么选?

这是一个价值百万的问题。首先,我将定义一些术语:

函数 k-distance(p) :点 p 到其 K 最近邻的距离(用户选择 K 值)。例如,如果用户选择 k 值为 4(图 12),那么从点 p 到 4 最近邻的距离就是从 p 到它的 4 最近邻的距离。

图 12- k 距离。检索自数据库中的知识发现(Seidl,2016)

****K 距离图:所有物体的 K 距离,按降序排列。也称为排序 k 线图。

参数估计

如果ε值很小,许多点可能会被视为异常值,因为它们不是核心点或边界点(ε邻域将非常小)。较大的ε值可能会导致大量的点位于同一个聚类中。

如前所述,DBSCAN 的主要优势之一是它可以检测噪声。根据舒伯特、桑德等人在 2017 年进行的一项研究,理想的噪音量通常在 1%到 30%之间。该研究的另一个启示是,如果一个聚类包含数据集的许多(20%-50%)点,则表明您应该为ε选择一个较小的值,或者尝试另一种聚类方法。

一般情况下,ε应选择尽可能小的。

根据 DBSCAN 算法的发起人(Ester,Kriegel,Sander 和 Xu,1996),我们可以使用这种启发式算法来找到ε和 MinPts:

对于给定的 k,我们建立排序的 k-dist 图。阈值点是排序的 k-dist 图的第一个“谷”中的第一个点。阈值的 k-dist 值将是ε值。研究表明,对于 k > 4 的 k-dist 图与 4-dist 图没有显著不同,并且它们需要相当多的计算。因此,对于所有数据库(对于二维数据),他们通过将参数 MinPts 设置为 4 来消除该参数。阈值点的 4-dist 值用作 DBSCAN 的ε值。

图 13 — K 分布图(对于 k=4) ( Ester,Kriegel,Sander 和 Xu,1996)

如果不希望 MinPts 值为 4,可以决定 MinPts = k+1。选择 k 的一个启发式方法是将 k 设为 2∫维数-1 (Sander,Ester 等人,1998)。

另一种选择 MinPts 值的启发式方法是

其中,Pᵢ是点 I 的ε-邻域中的点数,n 是数据集中的点数。对于ε的每个不同值,我们将得到相应的 MinPts 值(萨万特,2014)

在下一个例子中(图 15 ),我们:

  1. 选择 K =3。
  2. 计算每个点的第三近邻距离。例如,对于点 n,这个距离稍大于 5。
  3. 对距离进行排序(图 15 中的柱状图是在我们对所有的点距离进行排序之后)。
  4. 选择ε为第一个膝盖的值,所以ε ≈ 2.5。

图 14-使用 k 线图选择参数。检索自埃里希·舒伯特 2018 年出版的数据库中的知识发现。由我编辑

计算的复杂性

如前所述,DBSCAN 检查数据中每个点的ε-邻域。检查它需要 O(n)。

因此,在最坏的情况下,DBSCAN 的总复杂度是 O(n)。

在某些情况下,复杂度可以降低到 O(nlogn)。

DBSCAN PROS

  • 识别随机形状的簇
  • 不需要事先知道数据中的聚类数(与 K-means 相反)
  • 处理噪音

DBSCAN

  • 具有不同密度的数据集是有问题的
  • 输入参数(ε和 MinPts)可能难以确定
  • 计算复杂度——当维数很高时,计算复杂度为 O(n)

摘要

DBSCAN 是一种基于密度的聚类方法,可以发现非球形的聚类。

它的主要参数是ε和 Minpts。ε是邻域(一组相互靠近的点)的半径。如果邻域将至少包括 MinPts,则它将被视为密集区域,并将成为聚类的一部分。

有许多选择参数的方法。一种流行的启发式方法是选择一个 k 值并构建一个排序的 k-dist 图。阈值点是排序的 k-dist 图的第一个“谷”中的第一个点。阈值的 k-dist 值将是ε值min pts 值将是 k+1 的值。您可以选择 4 作为 K 和 MinPts 值的默认值。****

DBSCAN 的主要优点是不需要预先知道簇的数量,它可以识别随机形状的簇。主要缺点是计算复杂度高,需要为ε和 MinPts 选择好的值,以及处理不同密度的数据集。

参考

  1. 艾斯特,m .,克里格尔,H. P .,桑德,j .,&徐,X. (1996 年 8 月)。一种基于密度的发现带噪声的大型空间数据库中聚类的算法。在 Kdd (第 96 卷,№34,第 226–231 页)。
  2. 韩,j .,Kamber,m .,T13 裴,J. (2011)。数据挖掘概念和技术第三版。摩根·考夫曼。
  3. DBSCAN。(2020).于 2020 年 4 月 8 日从 https://en.wikipedia.org/wiki/DBSCAN 检索
  4. 普拉多,K. (2017)。DBSCAN 如何工作,为什么要使用它?。检索于 2020 年 3 月 11 日,来自 https://towards data science . com/how-DBS can-works-and-why-should-I-use-it-443 B4 a191c 80
  5. 萨万特,K. (2014 年)。确定 DBSCAN 参数的自适应方法。国际创新科学杂志,工程&技术1 (4),329–334 页。
  6. 桑德,j .,埃斯特,m .,克里格尔,H. P .,T23 徐,X. (1998)。空间数据库中基于密度的聚类:gdbscan 算法及其应用。数据挖掘与知识发现2 (2),169–194。
  7. 塞德尔,T. (2016)。数据库中的知识发现——第 4 章:聚类。介绍,路德维希-马克西米利安-慕尼黑大学。
  8. 舒伯特,e,桑德,j,埃斯特,m,克里格尔,h . p .&徐,X. (2017)。DBSCAN 重温,重温:为什么和如何你应该(仍然)使用 DBSCAN。美国计算机学会数据库系统汇刊(TODS)42 (3),1–21。
  9. 拉夫桑贾尼、扎拉·阿斯加里·瓦尔扎内·纳西贝·埃马米·楚坎托。层次聚类算法综述。数学和计算机科学杂志,229–240 页。
  10. m . j .扎基,&w .梅拉(2014)。数据挖掘和分析:基本概念和算法。剑桥大学出版社。

探索性数据分析实用指南:Spotify 数据集

原文:https://towardsdatascience.com/a-practical-guide-to-exploratory-data-analysis-spotify-dataset-d8f703da663e?source=collection_archive---------20-----------------------

一张图胜过千言万语

普瑞亚·贝伦吉在 Unsplash 上的照片

我们生活在大数据时代。我们可以收集大量数据,从而推断出有意义的结果,做出明智的商业决策。然而,随着数据量的增加,分析和探索数据变得更加困难。当有效和恰当地使用时,可视化是探索性数据分析的伟大工具。可视化也有助于向你的观众传递信息,或者告诉他们你的发现。没有一种通用的可视化方法,因此某些任务需要不同类型的可视化。在本帖中,我们将尝试探索 Kaggle 上这里提供的 Spotify 数据集。

Kaggle 是数据科学领域非常受欢迎的平台。它的名气来自比赛,但也有许多数据集,我们可以在实践中工作。Kaggle 很酷的一点是,你可以创建笔记本,直接在 Kaggle 上导入数据集,并在网站上分享你的工作,而不必下载任何东西。

只需点击“新笔记本”并选择您喜欢的语言。笔记本启动后,点击“添加数据”并选择您想要处理的数据集。

添加数据集后,我们可以从将数据集读入 pandas 数据帧开始。

import pandas as pd
import numpy as npdf = pd.read_csv("../input/spotify-dataset-19212020-160k-tracks/data.csv")print(df.shape)
df.columns

数据集包含从 Spotify Web API 收集的超过 160,000 首歌曲。这些特征包括歌曲、艺术家、发行日期以及歌曲的一些特征,如声音、舞蹈性、响度、速度等等。日期范围从 1921 年到 2020 年。

让我们首先检查是否有任何丢失的值:

df.isna().sum().sum()
0

没有缺失值。 df.isna()。sum() 返回每列中缺失值的数量。通过添加另一个 sum() ,我们得到数据集中缺失值的总数。

我不会在我的分析中使用一些特性,所以我会放弃它们。

df.drop([
'Unnamed: 0', 'id','explicit','key','release_date','mode'], axis=1, inplace=True
)df.head()

宋动向

该数据集包括对歌曲的许多不同的度量。一些名称给出了他们的意思,如速度,响度,能量。如果你对音乐不是很感兴趣的话,还有一些非常具体的措施很难理解。例如,声音、活力和语言是我们不常听到的专业术语。

这些措施中的一些可能是相关的。乍一看,可跳性和效价似乎是相关的。我们可以使用熊猫的 corr 方法来计算相关性,并使用热图来可视化它们。

corr = df[['acousticness','danceability','energy',
'instrumentalness','liveness','tempo','valence']].corr()import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='darkgrid')%matplotlib inlineplt.figure(figsize=(12,8))
sns.heatmap(corr, annot=True)

正如我们所猜测的,配价和可舞性之间存在正相关。能量和声音之间似乎有很强的负相关性。

让我们也根据每首歌的平均能量来检查前 10 名艺术家,并将结果与他们的平均声音值进行比较。

df[['artists','energy','acousticness']].groupby('artists').mean().sort_values(by='energy', ascending=False)[:10]

除了少数例外,演唱高能歌曲的艺术家声音很低。整个数据集中的平均声音度是 0.50。

df.acousticness.mean()
0.5013601471548411

数据集包含了早在 1921 年的歌曲。我们可以大致了解宋的特征在百年间是如何变化的。

year_avg = df[['danceability','energy','liveness','acousticness', 'valence','year']].groupby('year').mean().sort_values(by='year').reset_index()year_avg.head()

对于五种不同的测量方法,我们得到了年平均值。各种不同的软件包和有用的功能,在数据科学领域,几乎总是有多种方法来完成一项任务。我将向您展示两种不同的方法来创建一个线形图,显示这些变量随时间变化的趋势。

第一个是创建一个图形,并为每个趋势添加一条线。

plt.figure(figsize=(14,8))
plt.title("Song Trends Over Time", fontsize=15)lines = ['danceability','energy','liveness','acousticness','valence']for line in lines:
    ax = sns.lineplot(x='year', y=line, data=year_avg)plt.legend(lines)

另一种方法是使用熊猫融化函数将 year_avg 数据帧转换为 long 数据帧。

melted = year_avg.melt(id_vars='year')
melted.head()

不同的测量值组合在一个名为“变量”的列下。5 个要素合并为一个要素,因此融合数据帧的长度必须是 year_avg 数据帧长度的 5 倍:

我们确认了形状。现在让我们看看如何使用熔化的数据帧创建相同的绘图。

plt.figure(figsize=(14,6))
plt.title("Song Trends Over Time", fontsize=15)
sns.lineplot(x='year', y='value', hue='variable', data=melted)

我们没有添加多个轴,而是使用了色调参数,这使得语法更加简单。这两种方式都产生了这个情节:

歌曲最多的艺人

我想知道数据集中有多少独特的艺术家。

df.artists.nunique()
33268

整个数据集中有 33268 位艺术家。他们中的一些人创作了很多歌曲,而有些艺术家却很少创作歌曲。让我们看看数据集中歌曲最多的前 7 位艺术家。

df.artists.value_counts()[:7]

弗朗西斯科·卡纳罗有 956 首歌,亚军伊格纳西奥·科西尼有 635 首歌。我们可以创建一个新的数据框架,显示这 7 位艺术家每年的歌曲产量。

我们首先使用由 value_counts 函数返回的索引创建一个列表:

artist_list = df.artists.value_counts().index[:7]

然后使用此列表过滤数据框,并按年份分组:

df_artists = df[df.artists.isin(artist_list)][['artists','year',
                                                        'energy']].groupby(['artists','year']).count().reset_index()df_artists.rename(columns={'energy':'song_count'}, inplace=True)df_artists.head()

该数据帧包含艺术家姓名、年份以及艺术家当年创作的歌曲数量。

plt.figure(figsize=(16,8))sns.lineplot(x='year', y='song_count', hue='artists', data=df_artists)

我们无法真正区分界限。因为这是一个很长的时期(100 年),艺术家只出现在整个时间线的一部分。例如,“弗朗西斯科·卡纳罗”似乎主宰了 20 世纪 30 年代。

我现在将尝试一种不同的方式来看看哪些艺术家主宰了哪个时代。首先,我将创建一个包含整个时间线(1921-2020)和前 7 名艺术家姓名的空数据框。

df1 = pd.DataFrame(np.zeros((100,7)), columns=artist_list)
df1['year'] = np.arange(1921,2021)
print(df1.shape)
df1.head()

数据帧包括 100 年的 100 行和 8 列(7 位艺术家和一年列)。然后我会用 melt 函数把它转换成一个长数据帧。

df1 = df1.melt(id_vars='year',var_name='artists', value_name='song_count')
print(df1.shape)
df1.head()

历年歌曲计数为零。我将使用熊猫合并功能合并 df_artists 数据帧中的歌曲数。

df_merge = pd.merge(df1, df_artists, on=['year','artists'], how='outer').sort_values(by='year').reset_index(drop=True)df_merge.head()

如果某个艺术家在某一年没有任何歌曲,则该值用 NaN 填充。请注意,重要的是将合并功能的 how 参数设置为“外部”。否则,合并的数据帧只包括年份-艺术家组合,其中至少有一首该艺术家的歌曲。

我将用 0 替换 NaN 值,并删除 song_count_x 列。

df_merge.fillna(0, inplace=True)
df_merge.drop('song_count_x', axis=1, inplace=True)
df_merge.rename(columns={'song_count_y':'song_count'}, inplace=True)df_merge.head()

我还想添加一个列,显示每个艺术家多年来创作的歌曲的累积总和。一种方法是使用 groupbycumsum 函数。

df_merge['cumsum'] = df_merge[['song_count','artists']].groupby('artists').cumsum()df_merge.head(10)

如果我们只对艺术家使用累计和而不使用 groupby,则累计和列只包括基于年份的累计和。它不考虑艺术家列。

我已经成功地重新格式化了数据帧,以适应我想要绘制的内容。我将创建一个跨越整个时间线的动画条形图。每位艺术家都有一个酒吧。随着艺术家歌曲累积数量的增加,条形将会上升。我们将能够看到每个艺术家如何在不同的年代占据主导地位。

我将使用 plotly python (plotly.py ),这是一个很棒的库来创建交互式可视化。Plotly express 是 Plotly 的高级 API,它也使得语法非常简单和易于理解。

import plotly.express as pxfig = px.bar(df_merge,
             x='artists', y='cumsum',
             color='artists',
             animation_frame='year', animation_group='year',
             range_y=[0,1000],
             title='Artists with Most Number of Songs')
fig.show()

我在 1986 年暂停录音,并在结尾重新开始。动态图根据传递给 animation_frame 和 animation_group 参数的内容而变化。定义一个范围以防止数据点从图中掉出是很重要的。

我们已经介绍了一些操作或改变数据帧格式的技术。我们也创造了一些基本的情节以及一个动画情节。我们可以在这个数据集上做更多的事情。例如,我们可以分析歌曲或艺术家的受欢迎程度。也可以研究流行度如何基于音乐风格随时间变化。因此,探索性数据分析过程没有限制。根据我们的需要,我们可以从特定的角度来处理数据框架。然而,技术和操作通常是相同的。因此,最好使用不同种类的数据集进行练习。

感谢您的阅读。如果您有任何反馈,请告诉我。

PostgreSQL 入门实用指南🐘

原文:https://towardsdatascience.com/a-practical-guide-to-getting-set-up-with-postgresql-a1bf37a0cfd7?source=collection_archive---------27-----------------------

Python 的 PostgreSQL、pgAdmin 和 SQLAlchemy 入门。将 SQL 融入 Python 项目的核心。

南安Unsplash 上的照片

作为当前的或者有抱负的数据专业人士,我们经常被提醒具有扎实的 SQL 基础的重要性(如果你不相信,可以看看这个这个这个)。

来源:“想要一份数据方面的工作?学习 SQL”,DataQuest 博客

虽然,也许没有 Python 或机器学习那么吸引人,但你很难找到一个不引用 SQL 的数据科学招聘广告(见上图)。也就是说,有多种语言可供选择,有许多不同的工具可以用来与数据库进行交互,学习 SQL 时很难知道从哪里开始。

虽然尝试通过嵌入式 ide(如 DataCampDataQuest )的在线课程来学习 SQL 可能很诱人,但真正的学习过程是在我们能够玩和试验自己的个人项目时。要做到这一点,我们必须能够:建立我们自己的数据库,加载相关的数据集,并查询我们的数据。这篇文章的目的是展示我们如何在几分钟内设置好所有这些事情。

安装 PostgreSQL 和 pgAdmin

PostgreSQL 官方 logo,来源:https://wiki . PostgreSQL . org/wiki/File:PostgreSQL _ logo . 3 colors . SVG

有一系列数据库管理系统(DBMS)可供选择,特别是:PostgreSQL、MySQL、Oracle、SQL Server、SQLite。这里我们将使用 PostgreSQL :一个流行的开源解决方案(PostgreSQL 优于其他开源 SQL 数据库 )。

我们可以在这里 安装 PostgreSQL

在安装过程中,确保勾选 pgAdmin 4 框;这将是我们机构的一个重要补充。如果您需要单独安装 pgAdmin,您可以在此处安装

pgAdmin 入门

pgAdmin 是 Postgres 的管理工具;它本质上位于我们的 PostgreSQL 安装之上,为我们提供了一个优雅的 GUI 来可视化数据库对象并与之交互。一旦我们安装了 Postgres 和 pgAdmin(如上所述),我们就可以打开 pgAdmin 4 自己看了。如果这是我们第一次使用它,它应该会在浏览器窗口中弹出,并提示我们设置主密码。

探索 pgAdmin

正如我们所看到的,有一个服务器可供我们连接,对应于我们的本地 PostgreSQL 12 安装。在这里,我们可以看到默认的“postgres”数据库和一个包含数据库对象的嵌套列表。对于我们的设置,我们不需要太担心所有这些对象是什么,但是这篇文章很好地解释了基本概念,并且 pgAdmin 文档更详细。

现在让我们创建一个新的数据库,并尝试导入一些数据,这样我们就可以开始查询它了。我们假设没有 SQL 命令的先验知识,所以现在我们将使用 pgAdmin 的用户界面与 PostgreSQL 进行交互。为了保持话题性,我们将使用由欧洲疾病预防和控制中心提供的新冠肺炎地理病例分布数据集,可以在这里找到该数据集作为 CSV。

创建数据库非常简单,只需右键单击'数据库对象,选择'创建,然后选择'数据库,并选择一个合适的名称。同样,我们可以通过右键单击' Tables '对象来创建一个表。现在唯一的区别是我们需要指定表中每一列的名称和数据类型。将我们的列的顺序与我们想要导入的数据集中的顺序相匹配是很重要的,尽管名称不一定必须相同。

在 pgAdmin 中创建新的数据库和表

现在我们已经创建了数据库和一个表来存放 CSV 数据集,我们可以继续导入它了。右键单击我们刚刚创建的表对象,我们可以选择“导入/导出”对话框,指定我们要导入数据,选择我们选择的文件,并让 pgAdmin 知道数据有一个标题,我们希望在导入时跳过它。

使用 pgAdmin 导入 CSV 数据集

现在,我们已经具备了开始查询项目数据所需的一切。导航到窗口的最顶端,我们可以选择'工具'菜单,然后是'查询工具'选项。这将在我们的窗口中打开一个新的选项卡,我们可以在其中编写并执行 SQL 代码,以便查看数据输出。我们甚至可以选择将输出下载为 CSV 文件。

在 pgAdmin 中查询数据

现在我们有了一个基本的设置,允许我们使用 pgAdmin GUI 与 PostgreSQL 数据库进行交互,让我们看看如何进一步扩展它。在下一节中,我们将看到如何以编程方式与 PostgreSQL 数据库进行交互:一种将 Postgres 嵌入项目核心的更实用的方法。

SQLAlchemy 和 pandas——PostgreSQL 的 Pythonic 接口

Artem Maltsev 在 Unsplash 上拍摄的照片

SQLAlchemy 是一个整洁的 Python 库:自称为“Python 的数据库工具包”,它使我们能够以干净、Python 化的方式访问数据库的功能。我们可以用 SQLAlchemy 做的事情超出了这个设置的范围,但是如果你有兴趣进一步探索的话,官方的文档本教程应该是足够的。在这里,我们将了解如何使用 SQLAlchemy 在 Python 脚本中向我们的数据库运行原始 SQL 命令,以及从 pandas Dataframe 加载数据。

创建表格

让我们从尝试复制上面创建一个表并加载到 CSV 数据集中的过程开始。创建表的 SQL 命令很简单;我们只需要提供一个表名和一个我们希望包含在表中的所有列的列表,以及它们对应的数据类型:

添加DROP TABLE IF EXISTS意味着如果我们的 worldwide_cases 表已经存在,那么我们将在运行CREATE TABLE命令之前删除它。

要从 Python 脚本中运行这些 SQL 命令,我们首先需要安装 SQLAlchemy,这可以通过带有pip install SQLAlchemy的 pip 简单地完成。关于替代安装方法,请查阅官方安装指南

我们现在可以使用 SQLAlchemy 的create_engine函数连接到 Postgres 数据库:

*# Connecting to Postgres*from sqlalchemy import create_engineconnection_uri = 'postgres://username:password@host:port/database'
engine = create_engine(connection_uri)

我们传递给create_engineconnection_uri字符串让 SQLAlchemy 知道在哪里可以找到我们的数据库,它是使用上面给出的一般结构组成的。首先,我们让 SQLAlchemy 知道我们正在使用' postgres' ,而不是 SQL 的其他风格。然后,我们传递我们的'用户名'和'密码'(除非您专门创建了一个新用户,否则您可以使用默认用户名' postgres '和您最初设置的密码)。“主机和“端口”的值决定了数据库运行的服务器;鉴于我们已经在本地安装了 Postgres,这很可能是localhost:5432的默认设置。最后,我们指定我们试图连接的数据库的名称。关于构建 URI 的更多信息,你可以在这里找到文档。

一旦我们为数据库创建了一个引擎实例,我们就可以简单地使用以下命令来执行 SQL 命令:

# Executing SQL command
with engine.connect() as con:
    con.execute(sql)

将所有这些放在一起,我们可以编写一个create_table.py脚本,它将连接到我们的数据库,并从我们的create_table.sql文件中执行所需的 SQL 命令:

我们现在应该在我们的covid-19数据库中有一个名为worldwide_cases的空白表(如果您按照上一节中的步骤操作,它将会覆盖我们之前创建的表)。您可以在 pgAdmin 中通过右键单击数据库并选择“Refresh”来验证这一点,这将使我们能够看到嵌套在“Schemas/public/Tables”下的表。或者,打开查询工具并运行命令SELECT * FROM worldwide_cases

现在让我们将一些数据加载到我们的表中!

将数据加载到表中

将 SQLAlchemy 与熟悉的 pandas 库结合使用,加载数据再简单不过了。我们可以使用 pandas DataFrame 类的df.to_sql()方法将数据直接加载到指定的表中:

*# Load DataFrame into database*df.to_sql(
    name='table_name',
    con=engine,
    if_exists='append',
    index=False)

我们指定希望填充的表的名称,以及将我们连接到数据库的 SQLAlchemy 引擎。我们还可以用if_exists参数来规定表已经存在的情况下的行为。在我们的例子中,由于我们的表已经建立,我们将''追加 T10'我们的数据帧到表中。然而,我们也可以将该值设置为' fail ',如果该表已经存在,这将在我们的代码中引发一个异常,或者设置为' replace ',在这种情况下,该表将被删除并从数据中重新创建。

事实上,在前面的部分中,我们不需要麻烦地预先创建一个表。这是一个很有价值的演示,展示了我们如何使用 SQLAlchemy 运行原始 SQL 命令;然而,我们可以简单地运行我们的df.to_sql()命令,这个表就会神奇地为我们创建。我们可以使用dtype参数指定表中列的数据类型,该参数采用列名和 SQL 数据类型的字典,类似于我们在CREATE TABLE命令中指定它们的方式。如果我们不指定这一点,pandas 将从我们的数据帧中的数据推断出数据类型。

将数据集加载到worldwide_cases表中的完整脚本如下所示:

这里唯一增加的是几行代码,用于根据我们在表中选择的列标题重命名 CSV 数据集的列。我使用了一些 SQLAlchemy 技巧,很好地演示了如何用它以 Pythonic 方式访问数据库对象。导入元数据和表类,我们可以实例化一个表对象,反映我们的worldwide_cases表;由此,我们可以访问它的columns属性。这只是保存再次写出所有列名列表的快捷方式,但是我们也可以等效地通过df.columns = list_of_column_names,所以如果您愿意的话,可以随意这么做。

查询数据库

最后,我们可以重新创建我们在 pgAdmin 中演示的过程的最后一部分:查询我们的数据集。

假设我们有兴趣了解哪些国家目前的病例总数最高,我们可能会生成类似于下面的查询。

我们在上面看到,我们可以通过 SQLAlchemy 运行原始 SQL 命令来创建一个表。让我们用我们的SELECT查询尝试一下,看看会发生什么:

运行上面的脚本来执行我们的 SQL 查询并存储结果(可以使用fetchall()方法以列表的形式访问结果),返回以下输出:

('United_States_of_America', 1920061, 109802)
('Brazil', 645771, 35026)
('Russia', 458689, 5725)
('United_Kingdom', 284868, 40465)
('India', 246628, 6929)
         ...
('Papua_New_Guinea', 8, 0)
('British_Virgin_Islands', 8, 1)
('Bonaire, Saint Eustatius and Saba', 7, 0)
('Lesotho', 4, 0)
('Anguilla', 3, 0)

现在,我们的数据集中的每一行都有一个类似元组的对象,我们可以用任何我们喜欢的方式来解析和操作它,以便将这些数据合并到我们的 Python 脚本中。这太好了;正是我们需要的。尽管如此,如果我们能把数据直接放入熊猫的数据框架,而不需要任何事先的处理,那不是很好吗?我们很幸运。与 pandas 提供的将数据加载到数据库的df.to_sql()方法相同,我们也可以使用它的pd.read_sql()通过我们的数据库连接执行查询。

pd.read_sql()方法实际上是两个独立方法的组合:pd.read_sql_table()pd.read_sql_query()。前者将第一个参数作为我们希望读取的表的名称,后者是一个 SQL 查询。因此,使用pd.read_sql(),我们可以提供两者之一,这取决于我们是想读取单个表还是执行查询。现在,让我们开始实践,执行上面的query.sql查询:

现在,我们的查询结果有了一个简洁的 DataFrame 对象,使我们可以立即访问 pandas 提供的用于操作数据的资源套件:

 countries_and_territories   cases  deaths
0  United_States_of_America  1920061  109802
1                    Brazil   645771   35026
2                    Russia   458689    5725
3            United_Kingdom   284868   40465
4                     India   246628    6929

包扎

Wolfgang Hasselmann 在 Unsplash 上拍摄的照片

这篇文章的目的是演示一个简单的设置,使我们能够开始学习 SQL,并给我们在自己的项目和数据探索中使用它的自由。我们现在已经在系统上安装了 PostgreSQL、pgAdmin,以便通过 GUI 与它进行交互,我们已经看到可以使用 SQLAlchemy 从 Python 脚本中加载和查询数据。

现在轮到您了:去学习更多关于 SQL 的知识和它的能力,询问您选择的数据集以找到见解,并将 PostgreSQL 融入您的 Python 项目的核心!

感谢阅读!

这个博客的所有源代码都可以在这里找到:

[## Emile gill 743/postgres-设置

Python 的 PostgreSQL、pgAdmin 和 SQLAlchemy 入门。-Emile gill 743/postgres-设置

github.com](https://github.com/emilegill743/postgres-setup)

如果你喜欢这篇文章,可以看看我的其他文章:

[## 聪明的方法是找到一个杂货递送点

使用 Python、Heroku 和 Twilio 从一个杂货网站的 API 中抓取数据,并在出现插槽时获得文本通知…

towardsdatascience.com](/finding-a-grocery-delivery-slot-the-smart-way-f4f0800c4afe)

喀拉斯 RNN 和 LSTM 实用指南

原文:https://towardsdatascience.com/a-practical-guide-to-rnn-and-lstm-in-keras-980f176271bc?source=collection_archive---------2-----------------------

照片由丹尼尔·利维斯·佩鲁西Unsplash 上拍摄

介绍

在阅读了大量关于循环层的理论文章后,我只想建立我的第一个 LSTM 模型,并在一些文本上对其进行训练!但是对于我来说,图层暴露参数的庞大列表和图层结构的精致对我来说太复杂了。这意味着我不得不花费大量的时间来研究 StackOverflow 和 API 定义,以获得更清晰的图像。这篇文章试图巩固所有的笔记,它可以加速从理论到实践的转变过程。本指南的目标是培养对使用 RNN 和 LSTM 等重现图层的实际理解,而不是提供理论理解。为了更深入的理解,我建议这个这个,我建议在阅读本文之前先过一遍。如果你准备好了,让我们开始吧!

递归神经网络

完整的 RNN 图层在 Keras 中显示为SimpleRNN类。与许多文章中建议的体系结构相反,Keras 实现非常不同,但是很简单。每个 RNN 单元接受一个数据输入和一个隐藏状态,从一个时间步骤传递到下一个步骤。RNN 细胞看起来像这样,

Keras 中 RNN 单元实现内部的数据流和隐藏状态。图片作者。

RNN 单元的完整公式是,

这里,h{t}和 h{t-1}是从时间 t 和 t-1 开始的隐藏状态。x{t}是 t 时刻的输入,y{t}是 t 时刻的输出,需要注意的是,有两个权重矩阵 W{hh}和 W{hx}以及一个偏置项 b{h}。这些矩阵中的每一个都可以被认为是一个内部 1 层神经网络,其输出大小在参数units中定义,偏差也具有相同的大小。y{t}是原始的 h{t},我们不像许多文章建议的那样在这里应用另一个权重矩阵。这表示 RNN 的一个单个像元,像元的顺序组合(计数等于数据中的时间步长)创建了完整的 RNN 层。请记住,RNN 单元共享相同的权重矩阵和偏差。最后,我们可以如下计算训练 RNN 层所需的参数数量,

请注意,输入在格式上是一个元组(时间步长、要素),参数仅取决于要素,因为我们在每个时间步长上共享相同的权重。这可以通过在 Keras 中显示 RNN 的样本模型的概要来检查。

检查 simple_rnn_2 中的参数,它等于我们上面计算的。使总参数计数达到 17921 的额外的 129 是由于在 RNN 之后添加的密集层。

我们还可以获取精确的矩阵并打印出它的名称和形状,

要点注意,Keras 调用输入权重为内核,隐藏矩阵为递归 _ 内核,偏差为偏差。现在我们来过一遍 Keras 曝光的参数。虽然完整的清单是由提供的,但我们将简要地看一些相关的清单。

  • 第一个也是最重要的是units,它等于内核recurrent_kernel 的输出大小。也就是偏向项的大小项和隐藏项的大小。
  • 接下来,我们有activation在我们的公式中定义了 g()函数。默认为“tanh”。
  • 然后我们为内核、递归 _ 内核和偏差分别设置了{*}_initializer{*}_regularizer{*}_constraint参数。如果您不确定,可以忽略这些,因为默认值已经足够好了。
  • use_bias是打开或关闭偏置项的布尔参数。
  • dropoutrecurrent_dropout分别用于将丢弃概率应用于内核递归 _ 内核
  • return_sequence是一个布尔参数。当其为“真”时,RNN 图层的输出形状为(时间戳,要素),当其为“假”时,输出仅为(要素)。这意味着,如果它打开,在输出中我们返回所有时间步的 y{t},如果它关闭,我们只返回 1 y{t}(这里是从最后一个时间步)。一个额外的警告,不要忘记在添加Dense层之前,在打开return_sequence的 RNN 之后添加一个TimeDistributed层或Flatten层。
  • go_backwards为布尔类型,当其为“真”时,RNN 以相反的顺序处理数据。默认值为“假”
  • return_state为布尔型,当“真”时,除输出外,还返回最后一个状态。默认值为“False”。
  • stateful是一个重要的参数。当设置为“真”时,Keras 对相同的样本索引使用相同的批次隐藏状态。这样理解,我们为多个时期训练我们的模型,这就像对完整数据的迭代。1 个历元是完整数据的 1 次传递。现在,每个时期包含多个批次,这些批次又包含多个样本,即单独的数据。通常,在批量运行每个样品后,RNN 池的状态会被重置。但是,如果我们以这样的格式准备数据,使得在多个批次中,特定索引处的样本只是同一个句子的扩展,那么我们可以将 stateful 转换为“True ”,这相当于一次训练所有句子(作为一个样本)。由于内存限制,如果我们不能一次加载完整数据,我们可能会这样做。默认值为“False”。

在对 RNN 有了基本了解之后,让我们来看看 RNN 经常创作的一个建筑。

深垂直 RNNs

已经有人建议将多个循环层堆叠在彼此之上,以便更好地为多个应用工作。这导致了网状结构,其中水平深度(想象展开的 RNN)是由于时间步长,而垂直副本(堆叠)是由于新的 RNNs 层。这被称为 Seq2Seq 建模,主要用于语言翻译、实体标记、语音识别等需要输入和输出序列的应用。也就是说,我们也可以在最终应用完全连接的密集层之前堆叠多个 rnn,这是输入序列但输出变平的一个示例。一个示例代码是,

这非常简单,因为我们刚刚在前面的代码中添加了两个新的 RNN 层。但是请注意,如果我们想在 RNN 图层上叠加另一个 RNN,我们会将return_sequence设为“真”。这是因为下一个 RNN 期望时间分布的输入,并且前一个 RNN 的每个时间步长的输出成为相同时间步长的上 RNN 的输入。这里,虽然第一 RNN 的可训练参数保持与之前建议的相同,但是第二和第三 RNN 具有不同的参数,因为这些 RNN 的输入大小是 128。这使得接下来的两个 RNN 中的每一个的训练参数等于,

LSTM

继续看 LSTMs,上面有一堆非常好的文章,比如这个这个。我建议在继续前进之前先看一看它们。与 RNN 的问题类似,LSTM 的实现与大多数文章中提出的没有什么不同。主要的区别在于,不是连接输入和先前的隐藏状态,而是在将它们传递到 LSTM 单元中的 4 个内部神经网络之前,我们具有应用于两者的不同权重矩阵。这意味着我们将所需的矩阵数量增加了一倍(实际上,它将维度增加了一倍,但稍后会有更多的介绍)。与输入相乘的 4 个矩阵称为,与前一隐藏状态相乘的 4 个称为递归 _ 核。为了更好地理解这一点,让我们看看公式,

在这里,如果您观察,我们总共有 8 个权重矩阵,假设每个矩阵的大小相同,我们可以说,在某种程度上,我们正在进行与 RNN 相同的操作,但现在增加了 4 倍。因此,可训练参数的数量现在可以通过下式计算,

而从 RNN 切换到 LSTM 就像替换各自的函数调用一样简单,这可以从下面的代码中看出,

将 lstm_1 中提到的参数与我们计算的参数进行匹配。

我们可以再次从模型中提取所有的权重,

这里注意,所有 4 个内核矩阵和 4 个递归 _ 内核矩阵都存储在 1 个单块矩阵中(串联在列轴上),因此维数为 128*4=512。偏差项也是如此。此外,几乎所有在 RNN 使用的参数在这里都适用。一个附加参数警告recurrent_activation,其默认值为“sigmoid ”,应用于输入、遗忘和输出门,如公式中所示。这留下了实际的activation,它应用于单元格状态和隐藏状态(默认值为“tanh”),如上面公式中所建议的。

结论

在 Keras 中,我们试图涵盖一些将理论和实践联系起来所需的基本主题。作为一个包含所有内在细节的完整指南,对于一篇文章来说太多了,我认为有很多资料可以很好地解释这个主题。我真正错过的是一些注释,这些注释将我在文章中看到的公式与 Keras 中真正实现的内容联系起来,并提供了一些额外的实用细节。希望这有所帮助!

干杯。

文章中的所有代码已经被 上传到这里。

更多类似的文章请访问我的 网站 并联系我@LinkedIn

使用 Scikit-Learn 进行堆叠的实用指南

原文:https://towardsdatascience.com/a-practical-guide-to-stacking-using-scikit-learn-91e8d021863d?source=collection_archive---------10-----------------------

如何使用堆叠构建更健壮的模型?

格雷格·罗森克在 Unsplash 上的照片

介绍

在过去的 20 年中,集成方法,如随机森林和梯度推进,这些使用投票或加权平均结合相同类型模型的几个实例来产生强模型,已经变得非常流行。然而,还有另一种方法可以让我们通过使用更高层次的模型将它们各自的预测结合起来,从而获得不同模型的好处。

堆叠概括,也称为堆叠,是一种训练元模型以智能地组合不同基础模型的预测的方法。

本文的目标不仅是解释这种赢得竞争的技术是如何工作的,而且还展示了如何用 Scikit-learn 中的几行代码来实现它。

堆叠的工作原理

由于模型背后的假设所产生的偏见,每个机器学习模型都有优点和缺点。这是我在上一篇关于有监督机器学习的“没有免费的午餐”定理的帖子中提到的一个概念。

[## “没有免费的午餐”在机器学习中真正意味着什么

揭开这个经常被误解的定理。

towardsdatascience.com](/what-no-free-lunch-really-means-in-machine-learning-85493215625d)

不同的机器学习算法可能擅长以不同的方式解决问题。如果我们有多个算法一起工作来解决一个问题,一个算法的优点可能会掩盖另一个算法的缺点,反之亦然。这就是堆叠背后的想法。

堆叠包括训练多个基础模型来预测机器学习问题中的目标变量,同时元模型学习来使用每个基础模型的预测来预测目标变量的值。下图展示了这一想法。

堆叠模型的蓝图。图片由作者提供。

正确训练堆叠模型的算法遵循以下步骤:

  1. 将数据拆分成k-折叠就像在k-折叠 交叉验证
  2. 选择一个折叠进行验证,剩余的 k-1 折叠进行训练。
  3. 在训练集上训练基础模型,在验证集上生成预测。
  4. 对剩余的 k-1 褶皱重复步骤 2-3,并创建一个扩充数据集,将每个基础模型的预测作为附加特征包括在内。
  5. 在扩充数据集上训练最终元模型。

请注意,模型的每个部分都是单独训练的,元模型学习使用基础模型的预测和原始数据来预测最终输出。

对于那些不熟悉 k 折叠交叉验证的人来说,这是一种将机器学习问题的数据分成 k 折叠或不同子集,并在所有 k 折叠中迭代评估模型的技术。在每一次迭代中,一个折叠用于评估,剩余的 k-1 折叠用于训练模型。

使用一个 k 倍交叉验证分割确保了基础模型在看不见的数据上生成预测,因为基础模型将在每次迭代中在不同的训练集上被重新训练。

堆叠的力量在于最后一步,在这一步中元模型实际上可以学习每个基础模型的优缺点,并智能地组合它们的预测,以产生最终的输出

使用 Scikit-Learn 的实际示例

Scikit-learn 0.22 中引入了 StackingClassifierStackingRegressor 模块。因此,请务必升级到 Scikit 的最新版本——学习使用下面的 pip 命令来完成这个示例:

pip install --upgrade scikit-learn

导入基本库

我在下面导入的大多数基本库都是数据科学项目中常用的,应该不会感到意外。然而,我也使用了 Scikit-learn 中的 make_classification 函数来生成一些合成数据,并且我还使用了 Plotly 来构建交互图。为了嵌入互动的情节,我还使用了数据面板

import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import make_classification
import plotly.graph_objects as go
import datapane as dp
%matplotlib inline

生成数据集

Scikit-learn 的 make_classification 函数对于生成可用于测试不同算法的合成数据集非常有用。我在此场景中生成的数据集旨在基于以下参数,以实际难度表示二元分类问题:

  • n_features — 数据集中的要素数量,我将其设置为 20。
  • n _ 信息和 n _ 冗余— 数据集中信息和冗余要素的数量。我加入了五个多余的特性来增加问题的难度。
  • n_clusters_per_class —每个类中包含的聚类数。较高的值会使问题更加困难,所以我将这个值设置为五个集群。
  • class_sep —控制簇/类之间的分离。较大的值使任务更容易,所以我选择了一个低于默认值 1.0 的值 0.7。
  • flip_y —指定将被随机分配的分类标签的百分比。我将该值设置为 0.03,以便向数据集添加一些噪声。
X, y = make_classification(n_samples=50000, 
                           n_features=20, 
                           n_informative=15, 
                           n_redundant=5,
                           n_clusters_per_class=5,
                           class_sep=0.7,
                           flip_y=0.03,
                           n_classes=2)

培训和评估单个模型

为了获得与堆叠模型进行比较的基准性能水平,我对以下基本模型进行了培训和评估:

  • 有 50 棵决策树的随机森林
  • 支持向量机(SVM)
  • K-最近邻(KNN)分类器

为了代码的可重用性,模型都存储在一个字典中。

from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifierfrom sklearn.model_selection import cross_val_score, RepeatedStratifiedKFold
from collections import defaultdictmodels_dict = {'random_forest':     RandomForestClassifier(n_estimators=50),
               'svm': SVC(),
               'knn': KNeighborsClassifier(n_neighbors=11)}

每个模型都使用重复的五重交叉验证策略进行验证,其中每个折叠都使用不同的随机样本集进行重复。在每一次折叠中,每个模型用 80%的数据进行训练,用剩下的 20%进行验证。

该方法为每个模型产生 10 个不同的准确度分数,这些分数存储在字典中,如下所示。

def evaluate_model(model, X, y):
    cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=2, random_state=1)
    scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, verbose=1, n_jobs=3, error_score='raise')
    return scoresmodel_scores = defaultdict()for name, model in models_dict.items():
    print('Evaluating {}'.format(name))
    scores = evaluate_model(model, X, y)
    model_scores[name] = scores

可视化单个模型的结果

下面定义的函数获取所有评估模型的交叉验证分数字典,并使用 Plotly 创建一个交互式箱线图,以比较每个模型的性能。正如我在本文中所做的,这个函数还创建了一个数据面板报告来嵌入这些图。

def plot_results(model_scores, name):

    model_names = list(model_scores.keys())
    results = [model_scores[model] for model in model_names]
    fig = go.Figure()
    for model, result in zip(model_names, results):
        fig.add_trace(go.Box(
            y=result,
            name=model,
            boxpoints='all',
            jitter=0.5,
            whiskerwidth=0.2,
            marker_size=2,
            line_width=1)
        )

    fig.update_layout(
    title='Performance of Different Models Using 5-Fold Cross-Validation',
    paper_bgcolor='rgb(243, 243, 243)',
    plot_bgcolor='rgb(243, 243, 243)',
    xaxis_title='Model',
    yaxis_title='Accuracy',
    showlegend=False)
    fig.show()

    report = dp.Report(dp.Plot(fig) ) #Create a report
    report.publish(name=name, open=True, visibility='PUBLIC') plot_results(model_scores, name='base_models_cv')

三种基本型号的性能比较。

根据上面的箱线图,我们可以看到所有基本模型的平均准确率都超过了 87%,但支持向量机的平均表现最好。令人惊讶的是,一个简单的 KNN 分类器,通常被描述为“懒惰学习算法”,因为它只记住训练数据,明显优于有 50 个决策树的随机森林。

定义堆叠模型

现在让我们看看如果我们训练一个堆叠模型会发生什么。Scikit-learn 的 StackingClassifier 有一个构造函数,它需要一个基本模型列表,以及产生最终输出的最终元模型。请注意,在下面的代码中,这个基本模型的列表被格式化为带有模型名称和模型实例的元组列表。

堆叠模型使用随机森林、SVM 和 KNN 分类器作为基础模型,使用逻辑回归模型作为元模型,使用基础模型的数据和预测来预测输出。下面的代码演示了如何用 Scikit-learn 创建这个模型。

from sklearn.ensemble import StackingClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.linear_model import LogisticRegressionCVbase_models = [('random_forest', RandomForestClassifier(n_estimators=50)),
               ('svm', SVC()),
               ('knn', KNeighborsClassifier(n_neighbors=11))]
meta_model = LogisticRegressionCV()
stacking_model = StackingClassifier(estimators=base_models, 
                                    final_estimator=meta_model, 
                                    passthrough=True, 
                                    cv=5,
                                    verbose=2)

评估堆叠模型

在下面的代码中,我简单地重用了我之前定义的函数来获取模型的交叉验证分数,并使用它来评估堆叠模型。

stacking_scores = evaluate_model(stacking_model, X, y)
model_scores['stacking'] = stacking_scores

可视化和比较结果

我重用了前面定义的绘图函数,使用并排箱线图来比较基本模型和堆叠模型的性能。

plot_results(model_scores, name='stacking_model_cv')

根据上面的图,我们可以清楚地看到堆叠带来了性能的提高,其中堆叠模型优于所有基本模型,并且实现了接近 91%的中值精度。使用 Scikit-learn 的 StackingRegressor 模块,可以对回归问题重复同样的过程,其行为方式类似。

堆叠的优点和缺点

像机器学习中的所有其他方法一样,堆叠有优点也有缺点。以下是堆叠的一些优势:

  • 叠加可以提高模型的性能。
  • 叠加通过组合多个模型的预测来减少方差并创建更稳健的模型。

请记住,堆叠也有以下缺点:

  • 与简单模型相比,堆叠模型的训练时间要长得多,并且需要更多内存。
  • 使用堆叠模型生成预测通常会更慢,计算成本也更高。如果您计划将堆叠模型部署到产品中,那么考虑这个缺点是很重要的。

摘要

叠加是一种很好的方式,通过结合不同模型的预测来利用它们的优势。这种方法已经被用来赢得机器学习比赛,由于 Scikit-learn,它非常容易实现。然而,堆栈带来的性能提高是以更长的训练和推理时间为代价的。

您可以在 GitHub 上找到用于实际示例的完整代码。如果你喜欢这篇文章,请随意看看我最近写的一些关于机器学习的文章。

[## “没有免费的午餐”在机器学习中真正意味着什么

揭开这个经常被误解的定理。

towardsdatascience.com](/what-no-free-lunch-really-means-in-machine-learning-85493215625d) [## 为什么 XGBoost 不能解决你所有的问题。

XGBoost 和其他基于树的算法的一个关键限制。

towardsdatascience.com](/why-xgboost-cant-solve-all-your-problems-b5003a62d12a) [## 基于递归卷积神经网络的假新闻分类

介绍

towardsdatascience.com](/fake-news-classification-with-recurrent-convolutional-neural-networks-4a081ff69f1a)

来源

  1. D.H. Wolpert,,(1992),神经网络
  2. F.佩德雷戈萨等,sci kit-learn:Python 中的机器学习,(2011),机器学习研究杂志。

使用以人为中心的设计交付高级分析项目的实用指南

原文:https://towardsdatascience.com/a-practical-guide-to-using-human-centered-design-to-deliver-advanced-analytics-projects-3c7795cf8cfc?source=collection_archive---------20-----------------------

使用以人为中心的设计可以降低高级分析项目的失败风险,并有助于推动员工和客户的创新

图片来自 Sharon McCutcheon 通过 Pexel

未来 3 年,企业面临在失败的分析和数据科学项目上浪费数十亿美元的风险:

在过去的十年中,分析项目,尤其是高级分析项目的失败率非常低。数据和分析的业务采用仍然是一个问题,公司严重低估了这些项目的失败率

绝大多数(77%)企业报告称,采用大数据和人工智能计划是一项挑战【1】通常是因为它们是在孤岛中设计的,处理的是错误的用例,而且企业领导人不认为它们会带来价值

不出所料, 85%的数据项目以失败告终【2】并且没有通过初步阶段,更不用说转变业务流程、功能或最终体验了

尽管失败率很高,但企业正在寻求增加对数据和分析的投资,92%的企业表示他们将在未来一年增加支出

如果这些举措的支出水平很低且增长迅速,那么加速的速度可能并不惊人。然而,2019 年,企业在人工智能系统上花费了近 375 亿美元。IDC 预计,到 2023 年,这一数字将超过 979 亿美元。如果这些项目的成功率没有提高,那么可能会有多达 900 亿美元花费在失败的计划上。

以人为中心的设计可以帮助我们更好地设计项目,克服这些障碍:

三年前,我们推动我们的分析和数据科学团队使用设计思维来处理他们的所有项目,并将以人为中心的设计作为我们处理所有项目的基石——端到端。这使得通过 POC 阶段的项目有 90%的成功率,并且将这些项目整合到我们的日常业务中。

我们将所有项目分为三个阶段:

第一阶段-灵感和共鸣:

在我们开始任何重要的分析或接触任何一个数据之前,我们会先进行用户/利益相关者研究和背景研究。我们的目标是真正了解我们所关注领域的需求和痛点。

如果我们为我们的财务团队处理预测,我们的目标是了解要建模的 KPI,并了解团队目前如何完成该流程,什么是容易的,什么是困难的,以及他们将来可能如何使用我们的解决方案。这完全是为了理解今天的流程,并思考我们如何设计解决方案来改善未来客户和员工的体验

我们不仅想了解使用什么模型,还想了解解决方案本身是什么样子的。团队是否需要进行模拟建模或假设分析,他们将如何使用模型中的解释,以及我们如何展示模型结果,从而为我们的员工或客户带来最积极的体验?

第二阶段——构思和探索:

这个阶段从基于第一阶段所做工作的假设开始。然后,我们继续进行探索性数据分析,以帮助回答一些最初的假设,帮助我们更好地理解领域,并指导我们对特征工程的最初思考。

然后,我们集体讨论解决方案看起来像什么,关键要求是什么,以及如何将它融入我们员工的工作流程或我们客户的旅程,既作为原型/MVP,也作为我们解决方案的未来愿景。

根据这些会议的反馈创建原型,并将这些原型交到利益相关者、业务领域的主题专家以及最终用户/客户手中,这一点非常重要。在构建推荐引擎时,我们从高保真线框和体验模型开始,对于预测模型,它通常是仪表板以及我们应该包括的任何假设分析的参数,对于营销组合模型,我们的原型显示了模型如何支持所有渠道的投资决策。

这些是如何建立的各不相同。通常,我们从白板草图开始,转向 Figma 或 Sketch 等工具,然后使用 python libraries/ R shiny 或 in React 构建更高逼真度的版本。这些不需要完善到可以产业化。重点应该是可以快速构建的东西,以显示解决方案将如何工作,然后获得与我们的模型集成和与我们的业务部门试点所需的最低版本。

最后,还有我们模型本身的发展。我们从广泛的模型和特性选择开始,目标是向下选择 2-5 个模型进行广泛的调整和特性工程。我们的目标是平衡更透明和可解释的模型与整体模型性能(准确性、实现成本等)..).根据我们模型之间的性能差异,我们可能无法利用透明模型。这就导致我们花时间解释我们的模型,使用诸如 LIME 或 Shapley 值等技术来解释我们的最佳表现模型。

没有放之四海而皆准的方法,但是通常我们会发现,与实际开发和选择模型相比,我们会花费更多的时间来确保我们的模型和特性是可解释的。

第三阶段—实施和实验:

通常是我们最长的阶段。这一阶段的目标是与我们的业务和利益相关者合作,将我们的原型引入现实世界并进行评估。这需要与业务合作来开发我们的实验设计的参数,了解有限的发布会是什么样子(在哪里,在哪些组中),然后评估原型解决方案与现有的基准或控制组。

根据结果,我们为我们的解决方案构建或改进我们的业务案例,而不是工业化和扩展解决方案所需的路线图和工作。然后,我们要么经历第 1 阶段和第 2 阶段的加速版本以进行更广泛的发布,要么在构建下一版本的解决方案时扩展 MVP 以进行进一步的评估。

这个阶段也几乎总是需要重新思考业务流程和激励机制。适当设计的评估还将提供反馈,说明我们可能需要如何改变团队需要如何工作,或者他们当前的激励框架如何与我们希望我们的解决方案如何工作不一致。

这实际上是什么样子:

上面的过程描述了我们一个大型高级分析 MVP 的实际项目计划(考虑构建一个推荐系统)。这个过程看起来非常像一个“敏捷”的方法,但是应该适合任何解决方案开发过程。我们的主要目标是确保:

我们每两周交付某种形式的可交付见解,或反馈原型

没有一个项目在进入第三阶段之前超过 16 周,理想的目标是在 8-12 周内进入第三阶段,如果不是更早的话

我们至少要与“指导委员会”联系两次,以获得反馈和任何需要做出的关键决策的帮助

这确保了我们不会在没有得到关于我们的解决方案的更广泛反馈的情况下花费太多时间,并让我们诚实地了解我们如何确定范围和开发我们的解决方案。我们的目标是在一个季度内与我们的业务合作伙伴一起推出足够好的产品。

虽然没有完美的流程,但我们发现上述方法在引导我们的高级分析解决方案被我们的业务合作伙伴采用并实际推动变革方面取得了巨大成功。我们希望更多的组织能够成功地使用设计主导的方法来开发分析项目,因为持续的高失败率对所有分析专业人员都是一种伤害。

[1]2019 年新华帝合作伙伴、大数据和人工智能高管调查

【2】https://www . techrepublic . com/article/85-of-big-data-projects-fail-but-your-developers-can-help-yours-success/

【3】https://new vantage . com/WP-content/uploads/2018/12/Big-Data-Executive-Survey-2019-findings . pdf

【4】https://www.idc.com/getdoc.jsp?containerId=prUS45481219

实践中的早期停止:以 Keras 和 TensorFlow 2.0 为例

原文:https://towardsdatascience.com/a-practical-introduction-to-early-stopping-in-machine-learning-550ac88bc8fd?source=collection_archive---------3-----------------------

添加和自定义提前停止的分步教程

塞缪尔·伯克在 Unsplash 上的照片

在本文中,我们将重点关注在我们的机器学习模型中添加和定制早期停止,并查看我们如何在 Keras 和 TensorFlow 2.0 的实践中做到这一点的示例。

提前停止简介

在机器学习中,早期停止是最广泛使用的正则化技术之一,用于对抗 过拟合 问题。

早期停止在训练期间监视保持的验证集上每个时期的模型性能,并根据验证性能终止训练。

来自动手 ML [1]

早期停止是一种非常不同的正则化机器学习模型的方法。其方法是,一旦验证误差达到最小值,就停止训练。下图显示了一个正在训练的模型。

随着时代的推移,算法倾斜,它在训练集上的误差自然下降,在验证集上的误差也下降。然而,过了一段时间后,验证误差停止下降,实际上开始回升。这表明模型已经开始过度拟合训练数据。通过提前停止,只要验证误差达到最小值,您就可以停止训练。

这是一种简单而有效的规则化技术,杰弗里·辛顿称之为“美丽的免费午餐”[1].

随机和小批量梯度下降

随着随机和小批量梯度下降,曲线不是那么平滑,可能很难知道你是否达到了最小值。一种解决方案是,仅在验证误差超过最小值一段时间后停止(当您确信模型不会做得更好时),然后将模型参数回滚到验证误差最小的点。

在下面的文章中,我们将在我们的机器学习模型中添加和定制早期停止。

环境设置和数据集准备

我们将使用我们在模型正则化批量归一化中使用的相同数据集。如果你已经熟悉这一章,你可以跳过它。

为了运行本教程,您需要安装

TensorFlow 2,numpy,pandas,sklean,matplotlib

它们都可以直接安装在 vis PyPI 上,我强烈建议创建一个新的虚拟环境。关于创建 Python 虚拟环境的教程

源代码

这是一个循序渐进的教程,所有的说明都在这篇文章中。源代码请查看我的 Github 机器学习报告

数据集准备

本教程使用安德森鸢尾花(iris) 数据集进行演示。数据集包含五个属性下的一组 150 条记录:萼片长度萼片宽度花瓣长度花瓣宽度、(从 sklearn 数据集称为目标)。

首先,让我们导入库并从 scikit-learn 库中获取虹膜数据集。你也可以从 UCI 虹膜数据集下载。

import tensorflow as tf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split**iris = load_iris()**

为了研究数据,让我们将数据加载到一个数据帧中

# Load data into a DataFrame
**df = pd.DataFrame(iris.data, columns=iris.feature_names)** # Convert datatype to float
**df = df.astype(float)** # append "target" and name it "label"
**df['label'] = iris.target** # Use string label instead
**df['label'] = df.label.replace(dict(enumerate(iris.target_names)))**

并且df应该如下所示:

我们注意到 标签 列是一个分类特征,需要将其转换为一键编码。否则,我们的机器学习算法将无法直接将其作为输入。

# label -> one-hot encoding
**label = pd.get_dummies(df['label'], prefix='label')**
**df = pd.concat([df, label], axis=1)**
# drop old label
df.drop(['label'], axis=1, inplace=True)

现在,df应该是这样的:

接下来,让我们创建Xy。Keras 和 TensorFlow 2.0 只接受 Numpy 数组作为输入,所以我们必须将 DataFrame 转换回 Numpy 数组。

# Creating X and y**X = df[['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']]**
# Convert DataFrame into np array
**X = np.asarray(X)y = df[['label_setosa', 'label_versicolor', 'label_virginica']]** # Convert DataFrame into np array
**y = np.asarray(y)**

最后,让我们使用来自 sklearn 库中的**train_test_split()** 将数据集拆分成训练集(80%)和测试集(20%)。

X_train, X_test, y_train, y_test = **train_test_split**(
  **X,
  y,
  test_size=0.20**
)

太好了!我们的数据已经准备好建立一个机器学习模型。

建立一个神经网络

用 Keras 和 TensorFlow 2.0 创建机器学习模型有 3 种方法。由于我们正在构建一个简单的全连接神经网络,为了简单起见,让我们使用最简单的方法:带有Sequential()的顺序模型。

让我们继续创建一个名为create_model()的函数来返回一个序列模型。

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Densedef **create_model()**: 
    model = Sequential([
        Dense(64, activation='relu', **input_shape=(4,)**),
        Dense(128, activation='relu'),
        Dense(128, activation='relu'),
        Dense(128, activation='relu'),
        Dense(64, activation='relu'),
        Dense(64, activation='relu'),
        Dense(64, activation='relu'),
        **Dense(3, activation='softmax')**
    ])
    return model

我们的型号有以下规格:

  • 第一层(也称为输入层)有input_shape来设置输入大小(4,)
  • 输入层有 64 个单元,接着是 3 个密集层,每个层有 128 个单元。然后还有 3 个密集层,每个层有 64 个单元。所有这些层都使用 ReLU 激活功能。
  • 输出密集层有 3 个单元和 softmax 激活功能。

编译和训练模型

为了训练一个模型,我们首先必须使用compile()配置我们的模型,并传递以下参数:

  • 使用 Adam ( adam)优化算法作为优化器
  • 对于我们的 多类分类 问题,使用分类交叉熵损失函数(categorical_crossentropy
  • 为简单起见,使用accuracy作为我们在训练和测试期间评估模型的评估指标。
model.compile(
    **optimizer='adam', 
    loss='categorical_crossentropy', 
    metrics=['accuracy']**
)

之后,我们可以调用model.fit()来使我们的模型适合训练数据。

history = model.fit(
    X_train, 
    y_train, 
    **epochs=200, 
    validation_split=0.25, 
    batch_size=40,** 
    verbose=2
)

如果一切顺利,我们应该得到如下输出

Train on 84 samples, validate on 28 samples
Epoch 1/200
84/84 - 1s - loss: 1.0901 - accuracy: 0.3214 - val_loss: 1.0210 - val_accuracy: 0.7143
Epoch 2/200
84/84 - 0s - loss: 1.0163 - accuracy: 0.6905 - val_loss: 0.9427 - val_accuracy: 0.7143
......
Epoch 200/200
84/84 - 0s - loss: 0.5269 - accuracy: 0.8690 - val_loss: 0.4781 - val_accuracy: 0.8929

绘制学习曲线

最后,让我们在训练集和验证集上绘制损失对时期图。

最好创建一个小函数来绘制指标。我们继续创建一个函数plot_metric()

%matplotlib inline
%config InlineBackend.figure_format = 'svg'def **plot_metric(history, metric)**:
    train_metrics = history.history[metric]
    val_metrics = history.history['val_'+metric]
    epochs = range(1, len(train_metrics) + 1)
    plt.plot(epochs, train_metrics)
    plt.plot(epochs, val_metrics)
    plt.title('Training and validation '+ metric)
    plt.xlabel("Epochs")
    plt.ylabel(metric)
    plt.legend(["train_"+metric, 'val_'+metric])
    plt.show()

通过运行plot_metric(history, 'loss')获得损失进度图。

从上面的图表中,我们可以看到,该模型对训练数据进行了过度拟合,因此其性能优于验证集

添加提前停止

Keras 模块包含一个内置的回调函数,用于提前停止[2]。

首先,让我们导入EarlyStopping回调并创建一个提前停止对象early_stopping

from tensorflow.keras.callbacks import **EarlyStopping****early_stopping = EarlyStopping()**

EarlyStopping()有几个选项和默认:

  • monitor='val_loss':使用验证损失作为绩效衡量标准,终止培训。
  • patience=0:没有改善的时代数。值0意味着一旦性能测量从一个时期到下一个时期变得更差,就终止训练。

接下来,我们只需要将回调对象传递给model.fit()方法。

history = model.fit(
    X_train, 
    y_train, 
    epochs=200, 
    validation_split=0.25, 
    batch_size=40, 
    verbose=2,
    **callbacks=[early_stopping]**
)

您可以看到early_stopping在一个列表中被传递给了callbacks参数。这是一个列表,因为在实践中,我们可能会为执行不同的任务传递许多回调,例如调试和学习率调度。

通过执行该语句,您应该得到如下所示的输出:

注意:由于权重初始化不同,您的输出可能会有所不同。

由于val_loss值的增加,训练在时期 6 终止,这正是条件monitor='val_loss'patience=0

看一个剧情往往更方便,我们来运行plot_metric(history, 'loss')来一个清晰的画面。在下图中,验证损失显示为橙色,很明显,验证误差在第 6 时段增加。

定制提前停止

除了我们之前提到的选项monitorpatience之外,另外两个选项min_deltamode可能会经常使用。

  • monitor='val_loss':使用验证损失作为绩效衡量标准,终止培训。
  • patience=0:无改善的时期数。值0意味着一旦性能测量从一个时期到下一个时期变得更差,就终止训练。
  • **min_delta**:符合改善条件的监测量的最小变化,即小于min_delta的绝对变化,将被视为无改善。
  • **mode='auto'**:应为autominmax中的一种。在'min'模式下,当监控的数量停止减少时,训练将停止;在'max'模式下,当监控的数量停止增加时,它将停止;在'auto'模式下,方向由监控量的名称自动推断。

这是一个定制的提前停止的例子:

custom_early_stopping = EarlyStopping(
    **monitor='val_accuracy',** 
    **patience=8,** 
    **min_delta=0.001,** 
    **mode='max'**
)

monitor='val_accuracy'使用验证准确度作为绩效衡量标准来终止培训。patience=8表示训练在 8 个周期后终止,没有改善。min_delta=0.001表示验证准确度必须至少提高 0.001 才能算作改进。mode='max'表示当监控的数量停止增加时,它将停止。

让我们继续用定制的提前停止来运行它。

history = model.fit(
    X_train, 
    y_train, 
    epochs=200, 
    validation_split=0.25, 
    batch_size=40, 
    verbose=2,
    **callbacks=[custom_early_stopping]**
)

这一次,训练在时期 9 终止,因为有 8 个时期在验证准确性上没有改进(它必须≥ 0.001 才能算作改进)。为了清晰起见,让我们通过运行plot_metric(history, 'accuracy')来看看精确度的图形表示。在下图中,验证准确性显示为橙色,很明显验证准确性没有任何提高。

好了

感谢阅读。

请在我的 Github 笔记本上查看源代码。

如果你对机器学习的实用方面感兴趣,请继续关注。

参考

posted @ 2024-10-14 11:51  绝不原创的飞龙  阅读(335)  评论(0)    收藏  举报