TowardsDataScience 博客中文翻译 2021(三百九十七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

如何使用 AWS Amplify 部署 React 应用程序

原文:https://towardsdatascience.com/how-to-use-aws-amplify-to-deploy-a-react-application-ae93cd6e4525?source=collection_archive---------9-----------------------

使用 AWS Amplify 部署 React 应用程序的指南

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我的作品集网站

自从我作为一名软件工程师开始从事咨询工作以来,我就想建立一个作品集网站,展示我参与的个人项目和专业项目。今年寒假,我花时间设计、开发和部署了我的 portfolio 站点,在本文中,我将向您介绍我是如何使用 AWS Amplify 部署它的。你可以在dan-murphy.com查看网站,在 GitHub 查看代码。

简要背景

我的大部分专业工作需要构建数据驱动的应用程序和简化数据管道。为了完成这些任务,我经常使用 Python 和 Ruby,并在任何前端工作中加入 JavaScript。为了更好地使用 React,我决定使用这个框架来构建我的作品集网站。

设置应用程序

我采取的第一步是决定如何构建应用程序。我利用create-react-app作为我的目录的基本模板,然后用一些额外的文件夹重新构建了应用程序。最终的设置如下所示:

src
├── components
│   ├── archives
│   └── extras
│       ├── data
│       └── imgs
├── pages
│   ├── contents
│   └── data
├── styles
└── tests
    └── fixtures

一些显著的变化是**components****pages****styles**目录。

  • **components**:这是我存储应用程序所有组件的地方。通过将组件存储在一个集中的文件夹中,可以更容易地重用和重构我的代码,并且让其他人更直观地理解。组成我的作品集网站的一些组件是[Header](https://github.com/danmurphy1217/website/blob/main/src/components/Header.js)[Footer](https://github.com/danmurphy1217/website/blob/main/src/components/Footer.js)[ProjectSidebar](https://github.com/danmurphy1217/website/blob/main/src/components/ProjectSidebar.js)
  • 这是我为应用程序构建不同页面的地方。我从**components**文件夹中导入所需的组件,然后将它们集合起来设计页面。下面是我如何为主页这样做的一个例子:

Home.js

  • **styles**:这是我为应用程序定义全局 CSS 样式的地方。我喜欢将styled-components用于单个组件,但我也发现它有助于构建适用于每个页面的全局样式。

最后,为了将请求映射到正确的页面,我们使用了react-router-dom。路径在App.js文件中定义,如下所示:

App.js

这将把/请求映射到HomePage,把/projects请求映射到ProjectsPage,把/about请求映射到AboutPage,把/bookshelf请求映射到BookPage。既然应用程序的开发已经完成,我们需要部署它以便其他人可以使用它!

使用 AWS Amplify 部署

概观

部署 React 网站有几种方法,但我发现最简单的方法之一是使用 AWS Amplify 。Amplify 被描述为“构建可扩展的移动和网络应用的最快和最简单的方式。”为了实现这一点,AWS 推断出设置服务器、安装依赖项和创建网站生产版本的所有复杂性,允许您专注于构建直观的 UX。要了解更多关于 AWS Amplify 为数据驱动的应用提供了什么(具体来说,有前端后端的网站),请查看他们的文档

连接存储库

要在 AWS Amplify 上托管您的 web 应用程序,您首先需要连接包含您的源代码的存储库。为此,您可以导航至 AWS Amplify 入门 页面,滚动至托管我的 Web App ,点击连接 App 回购

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AWS Amplify 入门页面

然后,您将被重定向到一个单独的页面,在那里您可以连接包含您的源代码的存储库。对于这个例子,我将选择 GitHub,但 AWS Amplify 也支持 BitBucket、GitLab、AWS CodeCommit,甚至在没有 Git 提供者的情况下进行部署。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将存储库连接到 AWS Amplify

成功授权后,您可以选择想要部署的存储库,并选择 AWS Amplify 应该用于生产构建的分支。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

选择存储库和分支

之后,点击下一步,AWS 将要求您配置您的构建测试设置。AWS 提供的基本模板如下所示。

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm install build:
      commands:
        - npm run build
  artifacts:
    baseDirectory: build
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*

此外,在高级设置开关下,您可以设置环境变量和自定义构建容器。

最后,在检查完应用程序的设置后,单击 Save and Deploy 和AWS 将开始配置和部署应用程序。当 AWS 完成部署后,您可以导航到 Amplify 主页并查看您新部署的应用程序。

现在,让我们使用 AWS Amplify 域管理定制 URL。

添加自定义域

要开始添加自定义域,导航到左侧边栏并选择域管理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AWS Amplify 主页,在域管理设置周围有一个红框。

然后,选择添加域名输入您的域名(如下图所示),点击配置域名**。**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

配置您的自定义域

之后,您可以设置您的域所需的任何重定向。例如,在下面的例子中,我创建了一个从https://dan-murphy.comhttps://www.dan-murphy.com的重定向。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AWS 放大器域管理设置页面

最后,在您的自定义域被正确配置后,AWS 将为您提供一个验证证书。您也可以在 AWS 证书管理器控制台中查看该证书。

添加 CNAME 记录

配置自定义域的最后一步是添加 CNAME 记录。在下面的例子中,我使用了 Google Domains ,但是不同的域名注册商的基本概念是一样的。

首先,向下滚动到谷歌域名中的自定义资源记录。创建一个 CNAME 记录,将所有子域指向 AWS 放大器域:

  1. 名称:输入子域名称。如果子域为www.domain.com输入 www 。如果是**app.domain.com,**进入 app
  2. 数据:在域管理页面,点击动作,然后选择查看 DNS 记录。然后,在配置 DNS 提供商下输入可用的 AWS Amplify 域。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

域管理页面中,选择操作查看 DNS 记录

总之,自定义资源记录将如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Google 域中创建自定义资源记录。第一个 CNAME 记录突出显示在一个红框中。

接下来,再添加一个指向 AWS 证书管理器验证服务器的 CNAME 记录。经验证的 AWS 证书管理器为您的应用程序处理 TLS:

  1. 名称:输入验证服务器的子域。如果验证您的域名所有权的 DNS 记录是 _1234.example.com ,只需输入 _1234
  2. 数据:输入 ACM 验证证书。如果验证服务器是**_ 1234 . abcdefg . ACM-validations . AWS .,输入_ 1234 . abcdefg . ACM-validations . AWS .**

您的验证证书的所有信息可在 AWS 证书管理器控制台中找到。添加第二个 CNAME 后,您的自定义记录应该如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Google 域中创建自定义资源记录。第二个 CNAME 记录在一个红框中突出显示。

最后,让我们添加一个合成记录来建立一个子域 forward:

  1. 子域:输入 @
  2. 域名网址 : 输入你要转发到的子域。在这个例子中,子域是 www

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在谷歌域名创建一个子域转发。

包扎

总之,在本文中,我们学习了如何构建 React 应用程序并使用 AWS Amplify 部署它们。首先,我们讨论了如何将 react 应用程序模块化到组件页面文件夹中。然后,我们了解了 AWS Amplify 以及如何使用它部署静态和数据驱动的应用程序。最后,我们学习了如何使用 AWS Amplify 域管理Google 域来定制我们应用程序的域。

如果你对这篇文章或我的作品集网站有任何问题、顾虑或反馈,请随时评论或发邮件给我,地址是danielmurph8@gmail.com。感谢阅读!

如何使用 AWS Secrets Manager 管理凭据

原文:https://towardsdatascience.com/how-to-use-aws-secrets-manager-for-managing-credentials-abf57ab7344c?source=collection_archive---------11-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

在很多情况下,您需要使用凭证、令牌、API 密钥等。访问某些服务。例如,您需要使用 SQL server 凭据来访问应用程序的特定数据库。但是,将它们以纯文本文件的形式存储在代码库中并不是最好的主意。这是一个安全漏洞。任何有权访问您的代码库的人都可以读取这些机密,未经授权访问您的服务并执行恶意操作。您可以对秘密进行加密,并将密钥作为配置文件在应用程序外部共享,以允许解密。但是管理这样的秘密会变得很复杂。AWS 有一个秘密管理器,顾名思义,它是一个允许你管理秘密的服务。在本文中,我将讨论如何以编程方式存储和检索秘密。

AWS 机密管理器[1]

此服务允许您保护访问您的应用程序、服务和 IT 资源所需的机密。人们可以在数据库凭证、API 密钥和其他秘密的整个生命周期中轻松地轮换、管理和检索它们。用户和应用程序通过调用 Secrets Manager APIs 来检索机密,无需以纯文本方式硬编码敏感信息。该服务可扩展到其他类型的秘密,包括 API 密钥和 OAuth 令牌。此外,您可以使用细粒度的权限控制对机密的访问,并对 AWS 云中的资源、第三方服务和内部资源集中审计机密轮换。这些秘密可以很容易地复制到其他区域,以支持多区域应用。现在我们将看看创建一个秘密并以编程方式检索它所需的步骤。

步骤 1:创建和存储秘密

您可以使用 AWS Secrets manager 控制台或 AWS CLI 来创建机密。

机密管理器控制台

  1. 登录控制台:【https://console.aws.amazon.com/secretsmanager/

2.在“机密列表”页面上,单击“存储新机密”。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:作者

3.在“存储新密码”页面上,选择“其他密码类型”。(这种类型允许您存储键值对或纯文本。)然后,您可以在这个页面上将机密指定为键值对。例如,您的密钥可以是“用户名”和值“secrets@aws.com”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:作者

4.对于选择加密密钥,请选择 DefaultEncryptionKey。当您选择此选项时,Secrets Manager 将始终加密机密,无需额外费用。

5.选择下一步

6.在“机密名称”下,键入机密的名称。它只能是字母数字和/_+=。@-.可以用的例子:tutorial/firstkey。等级制度允许你将你的秘密分组并更好地维护它们。如果你愿意,你可以在这里添加描述和标签。

7.按下一步。

8.查看最终细节。此外,该页面还为您提供了不同语言的非常好的示例代码,您可以在您的应用程序中直接使用它们。你可以得到 Python,Java,JavaV2,JavaScript,C#,Ruby 和 Go 语言片段。相当整洁!出版社商店。这将创建一个名为 tutorial/firstkey 的秘密,其中包含 testkey:testvalue 对作为秘密。

机密管理器 CLI

  1. 打开命令提示符运行 AWS CLI。(安装 AWS 命令行界面
  2. 要创建密码,请运行以下命令:$ aws secretsmanager create-secret --name tutorial/firstkey *2* --description "Basic Create Secret" --secret-string '{"testkey":"testvalue"}'

步骤 2:从机密管理器中检索机密

在 AWS 机密管理器控制台中检索您的机密

  1. 登录秘密管理员控制台:https://console.aws.amazon.com/secretsmanager/
  2. 在“机密列表”页面上,选择您创建的机密。
  3. 在“机密值”部分,选择“检索机密值”
  4. 您可以将这个秘密视为键值对,或者 JSON 文本结构。

使用 AWS Secrets Manager CLI 检索

  1. 打开命令提示符。
  2. 输入以下命令:

使用 boto3 Python 代码检索

您也可以使用 boto3 库检索秘密。需要配置您的 AWS CLI。

该函数将给出以下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:作者

结论

最后,我们将 AWS Secrets Manager 视为存储数据库凭证、API 密钥等的一种方式。我们看到了如何使用控制台和 AWS CLI 创建密码。最后,我们看了如何使用控制台、AWS CLI 和 boto3 Python 库获得密钥。我希望你喜欢这篇文章,并学到一些有用的东西。感谢您的阅读。关注我更多有趣的文章。

参考

[1]https://aws.amazon.com/secrets-manager/

[2] 快速入门— Boto3 文档 1.17.96 文档

[3]AWS Secrets Manager—boto 3 Docs 1 . 17 . 97 文档

[4] 教程:创建和检索秘密— AWS 秘密管理器

如何使用 Bash 来自动化数据科学的枯燥工作

原文:https://towardsdatascience.com/how-to-use-bash-to-automate-the-boring-stuff-for-data-science-d447cd23fffe?source=collection_archive---------7-----------------------

使用命令行为您的数据科学项目编写一些可重用代码的指南

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

伊莲娜·科伊切娃在 Unsplash 上的照片

作为一名数据科学家,您倾向于通过终端反复使用一些命令。这些可能是命令为一个项目创建一个新目录启动一个新的虚拟环境激活它,安装一些标准库等等。

当你开始一个项目的工作时,你自己的标准工作流程可能每次都不一样。

**例如,**我总是为一个新项目创建一个新文件夹,并通过以下方式将其移入:

mkdir newproject
cd newproject

然后我通过以下方式创建了一个新的虚拟环境:

pipenv shell # orpython -m venv newenv

最后,我还做了 numpypandas 作为项目的样板安装。为了形象化的目的,我也经常使用 matplotlibplotly

事实上,我也喜欢为我的机器学习应用程序快速开发 web 应用程序,所以我也倾向于安装 streamlit,因为它是最好的库。如果你不太了解它,这里有一个我写的快速介绍,让你开始使用它。

因此,到目前为止我们需要执行的命令是:

pip install numpy pandas matplotlib plotly streamlit

如果您忘记添加库,您必须返回并通过终端重新安装它们。现在来看,通过一个命令来自动完成这一切不是一个好主意吗?

你可以使用一个脚本,每次执行时自动执行一些重复的命令,这样可以提前一点,节省一些宝贵的时间。

在本文中,我将演示一个简单的命令行过程,您可以很容易地习惯于有效地自动化枯燥的东西,这是我经常使用的一种方法。

我们开始吧!👇

检查系统上的 bash

了解 bash 在系统中的位置的一个简单方法是使用:

$ which bash

输出将类似于:

**/bin/bash**

检查 bash 版本:

bash --version

输出应该如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例如,Mac 上的 bash 版本

太好了,现在我们有了一点信息,让我们看看我们可以用它来构建什么。

制作新的 bash 脚本

我们将创建一个包含所有要执行的样板命令的文件。这将被称为我们的 bash 脚本,它将具有的扩展。sh 就一般惯例而言。

首先,创建一个新文件。

touch createmlapp.sh

接下来,让我们在文件的顶部添加一行代码,以确保系统知道使用默认的 bash shell 来运行我们的脚本。

#!/bin/bash

现在,让我们明白我们在这里想要做什么。我们的流程如下:

  1. 为我们的项目创建一个新目录
  2. 创建和激活虚拟环境
  3. 安装我们需要的任何软件包
  4. 打开项目目录中的 VSCode。

让我们现在过一遍。

写我们的剧本

我们所有的命令都将类似于我们在终端中正常运行的命令。

只有一个区别——为了使我们的项目成功,我们需要一个名字,我们将通过一个参数传递这个名字。

APP_NAME="$1"

执行脚本时输入的第一个参数将是我们的 $1

现在,剩下的代码将是熟悉的:

cd
cd Desktop/ # use whatever directory you wish here 
mkdir $APP_NAME
cd $APP_NAME

现在进入虚拟环境:

python -m venv newenv
source newenv/bin/activate

最后,我们安装我们需要的任何软件包:

pip install --upgrade pip
pip install numpy pandas matplotlib streamlit

最后,作为奖励,让我们打开我们最喜欢的代码编辑器 VSCode 开始我们的项目。

code .

我们完事了。😄。您的脚本现在应该是这样的:

#!/bin/bashAPP_NAME="$1"
cd
cd Desktop/
mkdir $APP_NAME
cd $APP_NAME
python -m venv newenv
source newenv/bin/activate
pip install --upgrade pip
pip install numpy pandas matplotlib streamlit
code .

运行我们的脚本

首先,我们做chmod +x(在我们的脚本上)使它可执行。

chmod +x createmlapp.sh

厉害!这太棒了。剩下的唯一一件事就是将这个脚本移动到我们的主目录中,这样我们就可以运行它,而不用每次都将 cd — ing 放入任何其他文件夹中。

首先,找出您的主目录——在终端中键入 cd 。无论您要去哪里,您都需要将脚本移动到那里,以便使它可以从那里执行。

现在,只需输入:

./createmlapp.sh yourmlappname

来看看实际的脚本!

结束…

恭喜你。在这个小指南之后,你现在应该能够自动化类似的工作流程,以便在开始一个新项目时节省一些时间!

我现在能给你的建议就是探索更多,尝试创建更多的脚本,也可能执行更复杂的任务,比如运行新的应用自动、T21【将代码推送到 GitHub 等等。

你可以在这里找到代码库

如果您喜欢这篇文章,我每周都会在这里分享一些来自数据科学世界的有用工具和技术。跟随我永远不会错过他们!

最后,这里有几篇我的类似文章,你可能也会觉得有用:

</26-datasets-for-your-data-science-projects-658601590a4c>

如何使用来自拥抱脸变压器库的伯特

原文:https://towardsdatascience.com/how-to-use-bert-from-the-hugging-face-transformer-library-d373a22b0209?source=collection_archive---------2-----------------------

如何使用来自拥抱脸变形库的 BERT 完成四项重要任务

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

eberhard grossgasteiger 在 Unsplash 上的照片

在这篇文章中,我将演示如何使用 BERT 的拥抱面部变形库来完成四个重要的任务。我还将向您展示如何配置 BERT 来执行您可能希望使用它的任何任务,除了它旨在解决的标准任务之外。

请注意,本文写于 2021 年 1 月,因此拥抱脸库的早期/未来版本可能会略有不同,本文中的代码可能不一定有效。

伯特建筑的快速回顾

BERT 是一个双向转换器,使用屏蔽语言建模和下一句预测的组合进行预训练。BERT 的核心部分是来自 transformer 模型的堆叠双向编码器,但在预训练期间,在 BERT 上添加了屏蔽语言建模和下一句预测头。当我说“头”时,我的意思是在 BERT 上添加几个额外的层,可以用来生成特定的输出。BERT 的原始输出是来自堆叠双向编码器的输出。这个事实特别重要,因为它允许您使用 BERT 做任何事情,您将在本文后面看到这样的例子。

BERT 可以解决拥抱脸提供的许多任务,但我将在本文中讨论的是掩蔽语言建模、下一句预测、语言建模和问题回答。我还将演示如何配置 BERT 来完成除上述任务和拥抱脸提供的任务之外的任何任务。

在讨论这些任务之前,我将描述如何使用 BERT 记号赋予器。

伯特记号赋予器

BERT 记号赋予器是一个与 BERT 一起工作的记号赋予器。对于任何类型的令牌化任务,它都有许多功能。您可以使用这行代码下载令牌化器:

from transformers import BertTokenizertokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

与 BERT 模型不同,您不必为每个不同类型的模型下载不同的标记器。您可以对 hugging face 提供的各种 BERT 模型使用相同的标记器。

给定一个文本输入,下面是我在项目中通常如何标记它:

encoding = tokenizer.encode_plus(text, add_special_tokens = True,    truncation = True, padding = "max_length", return_attention_mask = True, return_tensors = "pt")

由于 BERT 一次只能接受 512 个令牌作为输入,因此我们必须将截断参数指定为 True。add special tokens 参数只是让 BERT 添加标记,如开始、结束、[SEP]和[CLS]标记。Return_tensors = "pt "只是让 tokenizer 返回 PyTorch 张量。如果您不希望这种情况发生(也许您希望它返回一个列表),那么您可以移除该参数,它将返回列表。

在下面的代码中,你会看到我没有添加上面列出的所有参数,这主要是因为这是不必要的,因为我没有对真实项目的文本进行标记。在一个真实的机器学习/NLP 项目中,您会想要添加这些参数,尤其是截断和填充,因为我们必须在一个真实的项目中对数据集中的每个批次进行此操作。

tokenizer.encode_plus()专门返回值的字典,而不仅仅是值的列表。因为 tokenizer.encode_plus()可以返回许多不同类型的信息,如 attention_masks 和令牌类型 id,所以所有内容都以字典格式返回,如果您想检索编码的特定部分,可以这样做:

input = encoding["input_ids"][0]
attention_mask = encoding["attention_mask"][0]

此外,因为记号赋予器返回一个不同值的字典,而不是像上面显示的那样找到这些值,并分别将它们传递到模型中,我们可以像这样传递整个编码

output = model(**encoding) 

关于记号赋予器,需要知道的另一件非常重要的事情是,如果需要,您可以指定检索特定的记号。例如,如果您正在进行掩码语言建模,并且您想要在模型解码的位置插入一个掩码,那么您可以像这样简单地检索掩码标记

mask_token = tokenizer.mask_token

您可以通过将它与您的输入文本连接起来,简单地将其插入到您的输入中。

您还可以用同样的方式检索许多其他标记,比如[SEP]标记。

我通常使用 tokenizer.encode_plus()函数来标记我的输入,但是还有另一个函数可以用来标记输入,这个函数就是 tokenizer.encode()。这是一个例子:

encoding = tokenizer.encode(text, return_tensors = "pt")

tokenizer.encode_plus()和 tokenizer.encode()的主要区别在于 tokenizer.encode_plus()返回更多信息。具体来说,它返回实际的输入 id、注意掩码和令牌类型 id,并在一个字典中返回所有这些内容。tokenizer.encode()只返回输入 id,并根据参数 return_tensors = "pt "以列表或张量的形式返回。

掩蔽语言建模

屏蔽语言建模是对句子中的屏蔽标记进行解码的任务。简单来说就是填空的任务。

我将演示如何获取掩码标记的前 10 个替换单词,而不是仅获取最佳候选单词来替换掩码标记,下面是您可以如何做:

from transformers import BertTokenizer, BertForMaskedLM
from torch.nn import functional as F
import torchtokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForMaskedLM.from_pretrained('bert-base-uncased',    return_dict = True)text = "The capital of France, " + tokenizer.mask_token + ", contains the Eiffel Tower."input = tokenizer.encode_plus(text, return_tensors = "pt")
mask_index = torch.where(input["input_ids"][0] == tokenizer.mask_token_id)
output = model(**input)
logits = output.logits
softmax = F.softmax(logits, dim = -1)
mask_word = softmax[0, mask_index, :]
top_10 = torch.topk(mask_word, 10, dim = 1)[1][0]
for token in top_10:
   word = tokenizer.decode([token])
   new_sentence = text.replace(tokenizer.mask_token, word)
   print(new_sentence)

拥抱脸是这样设置的,对于它有预训练模型的任务,你必须下载/导入那个特定的模型。在这种情况下,我们必须下载用于屏蔽语言建模模型的 Bert,而正如我在上一节中所说的,标记器对于所有不同的模型都是相同的。

屏蔽语言建模的工作方式是,在您希望预测最佳候选单词的位置插入一个屏蔽标记。您可以简单地插入掩码标记,就像我上面所做的那样,将它连接到输入中所需的位置。用于屏蔽语言建模的 Bert 模型预测其词汇表中替换该单词的最佳单词/记号。在 softmax 激活函数应用于 BERT 的输出之前,logits 是 BERT 模型的输出。为了获得 logits,我们必须在初始化模型时在参数中指定 return_dict = True,否则,上面的代码将导致编译错误。在我们将输入编码传递到 BERT 模型中之后,我们可以通过指定 output.logits 来获得 logit,这将返回一个张量,然后我们可以最终将 softmax 激活函数应用到 logit。通过对 BERT 的输出应用 softmax,我们得到了 BERT 词汇表中每个单词的概率分布。具有较高概率值的单词将是掩码标记的更好的候选替换单词。为了获得 BERT 词汇表中所有单词的 softmax 值的张量以替换屏蔽令牌,我们可以指定屏蔽令牌索引,这是使用 torch.where()获得的。因为在这个特定的例子中,我正在检索掩码标记的前 10 个候选替换单词(通过相应地调整参数,可以得到 10 个以上),所以我使用了 torch.topk()函数,它允许您检索给定张量中的前 k 个值,并且它返回包含这些前 k 个值的张量。在此之后,过程变得相对简单,因为我们所要做的就是迭代张量,并用候选标记替换句子中的掩码标记。下面是上面代码编译的输出:

The capital of France, paris, contains the Eiffel Tower. 
The capital of France, lyon, contains the Eiffel Tower. 
The capital of France, lille, contains the Eiffel Tower. 
The capital of France, toulouse, contains the Eiffel Tower. 
The capital of France, marseille, contains the Eiffel Tower. 
The capital of France, orleans, contains the Eiffel Tower. 
The capital of France, strasbourg, contains the Eiffel Tower. 
The capital of France, nice, contains the Eiffel Tower. 
The capital of France, cannes, contains the Eiffel Tower. 
The capital of France, versailles, contains the Eiffel Tower.

您可以看到 Paris 确实是 mask token 的首选替换单词。

如果您只想获得第一个候选单词,可以这样做:

from transformers import BertTokenizer, BertForMaskedLM
from torch.nn import functional as F
import torch
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForMaskedLM.from_pretrained('bert-base-uncased',    return_dict = True)
text = "The capital of France, " + tokenizer.mask_token + ",
contains the Eiffel Tower."
input = tokenizer.encode_plus(text, return_tensors = "pt")
mask_index = torch.where(input["input_ids"][0] == tokenizer.mask_token_id)
logits = model(**input)
logits = logits.logits
softmax = F.softmax(logits, dim = -1)
mask_word = softmax[0, mask_index, :]
top_word = torch.argmax(mask_word, dim=1)
print(tokenizer.decode(top_word))

我们不使用 torch.topk()来检索前 10 个值,而是使用 torch.argmax(),它返回张量中最大值的索引。代码的其余部分与原始代码基本相同。

语言建模

语言建模的任务是在给定句子中所有单词的情况下,预测跟随或继续句子的最佳单词。

import transformersfrom transformers import BertTokenizer, BertLMHeadModel
import torch
from torch.nn import functional as F
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertLMHeadModel.from_pretrained('bert-base-uncased',
return_dict=True, is_decoder = True)
text = "A knife is very "
input = tokenizer.encode_plus(text, return_tensors = "pt")
output = model(**input).logits[:, -1, :]
softmax = F.softmax(output, -1)
index = torch.argmax(softmax, dim = -1)
x = tokenizer.decode(index)
print(x)

语言建模的工作方式与屏蔽语言建模非常相似。首先,我们必须下载特定的 BERT 语言模型 Head Model,它本质上是一个 Bert 模型,上面有一个语言建模 Head。在实例化该模型时,我们必须指定的一个额外参数是 is_decoder = True 参数。如果我们想要使用这个模型作为预测序列中下一个最佳单词的独立模型,我们必须指定这个参数。代码的其余部分与屏蔽语言建模中的代码相对相同:我们必须检索模型的逻辑,但我们不必指定屏蔽标记的索引,我们只需获取模型最后一个隐藏状态的逻辑(使用-1 索引),计算这些逻辑的 softmax,找到词汇表中的最大概率值,解码并打印这个标记。

下一句预测

下一句预测是预测一个句子是否跟随另一个句子的任务。这是我的代码:

from transformers import BertTokenizer, BertForNextSentencePrediction
import torch
from torch.nn import functional as Ftokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForNextSentencePrediction.from_pretrained('bert-base-uncased')prompt = "The child came home from school."next_sentence = "He played soccer after school."encoding = tokenizer.encode_plus(prompt, next_sentence, return_tensors='pt')
outputs = model(**encoding)[0]
softmax = F.softmax(outputs, dim = 1)
print(softmax)

下一句预测是预测一个句子对给定句子的下一句有多好的任务。在这种情况下,“孩子放学回家。”是给定的句子,我们试图预测“他放学后是否踢足球。”就是下一句。为此,BERT tokenizer 自动在句子之间插入一个[SEP]标记,表示两个句子之间的分隔,特定的 BERT For Next sense 预测模型预测该句子是否为下一句的两个值。Bert 在一个张量中返回两个值:第一个值表示第二个句子是否是第一个句子的延续,第二个值表示第二个句子是否是随机序列或者不是第一个句子的良好延续。与语言建模不同,我们不检索任何逻辑,因为我们不试图在 BERT 的词汇表上计算 softmax 我们只是试图计算下一句预测的 BERT 返回的两个值的 softmax,这样我们就可以看到哪个值具有最高的概率值,这将代表第二句话是否是第一句话的下一句话。一旦我们得到了 softmax 值,我们就可以简单地通过打印出来来查看张量。以下是我得到的值:

tensor([[0.9953, 0.0047]])

因为第一个值大大高于第二个指数,所以 BERT 认为第二句话跟在第一句话后面,这就是正确答案。

抽取式问题回答

抽取式问题回答是在给定一些上下文文本的情况下,通过输出答案在上下文中所处位置的开始和结束索引来回答问题的任务。以下是我回答问题的代码:

from transformers import BertTokenizer, BertForQuestionAnswering
import torch
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForQuestionAnswering.from_pretrained('bert-base-
uncased')
question = "What is the capital of France?"
text = "The capital of France is Paris."
inputs = tokenizer.encode_plus(question, text, return_tensors='pt')
start, end = model(**inputs)
start_max = torch.argmax(F.softmax(start, dim = -1))
end_max = torch.argmax(F.softmax(end, dim = -1)) + 1 ## add one ##because of python list indexing
answer = tokenizer.decode(inputs["input_ids"][0][start_max : end_max])
print(answer)

与其他三个任务类似,我们从下载特定的用于问题回答的 BERT 模型开始,我们将两个输入标记化:问题和上下文。与其他模型不同,该模型的过程相对简单,因为它输出标记化输入中每个单词的值。正如我之前提到的,抽取式问题回答的工作方式是通过计算答案在上下文中所处位置的最佳开始和结束索引。该模型返回上下文/输入中所有单词的值,这些值对应于它们对于给定问题的起始值和结束值有多好;换句话说,输入中的每个单词接收表示它们是答案的好的开始单词还是答案的好的结束单词的开始和结束索引分数/值。这个过程的其余部分与我们在其他三个程序中所做的非常相似;我们计算这些分数的 softmax 以找到值的概率分布,使用 torch.argmax()检索开始和结束张量的最高值,并在输入中找到对应于这个 start : end 范围的实际记号,解码它们并打印出来。

使用 BERT 完成您想要的任何任务

尽管文本摘要、问题回答和基本语言模型特别重要,但人们通常希望使用 BERT 来完成其他不确定的任务,尤其是在研究中。他们的方法是获取 BERT 堆叠编码器的原始输出,并附加自己的特定模型,通常是一个线性层,然后在特定数据集上微调该模型。当在 Pytorch 中使用 Hugging Face transformer 库执行此操作时,最好将其设置为 Pytorch 深度学习模型,如下所示:

from transformers import BertModel
class Bert_Model(nn.Module):
   def __init__(self, class):
       super(Bert_Model, self).__init__()
       self.bert = BertModel.from_pretrained('bert-base-uncased')
       self.out = nn.Linear(self.bert.config.hidden_size, classes)
   def forward(self, input):
       _, output = self.bert(**input)
       out = self.out(output)
       return out

如您所见,我没有下载已经为特定任务(如问答)设计的特定 BERT 模型,而是下载了原始的预训练 BERT Model,它没有附带任何头部。

要获得原始 BERT 输出的大小,只需使用 self.bert.config.hidden_size,并将它附加到您希望线性图层输出的类的数量。

要使用上面的代码进行情感分析,这是一个令人惊讶的任务,没有下载/已经在拥抱脸变压器库中完成,您可以简单地在线性层的末尾添加一个 sigmoid 激活函数,并将类指定为等于 1。

from transformers import BertModel
class Bert_Model(nn.Module):
   def __init__(self, class):
       super(Bert_Model, self).__init__()
       self.bert = BertModel.from_pretrained('bert-base-uncased')
       self.out = nn.Linear(self.bert.config.hidden_size, classes)
       self.sigmoid = nn.Sigmoid() def forward(self, input, attention_mask):
       _, output = self.bert(input, attention_mask = attention_mask)
       out = self.sigmoid(self.out(output))
       return out

我希望您觉得这些内容很容易理解。如果你认为我需要进一步阐述或澄清什么,请在下面留言。

参考

拥抱变脸库

如何在 Python 中有效地使用注释

原文:https://towardsdatascience.com/how-to-use-comments-effectively-in-python-2a793014307f?source=collection_archive---------18-----------------------

如果使用得当,注释是一个很有价值的工具——这就是你应该如何最有效地使用它们。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(src =https://unsplash.com/photos/5KKglNl852A

介绍

软件工程师或数据科学家可能会使用许多工具来为他们的代码提供更多的表达。有很多原因可以让你这么做。例如,在需要教授的循序渐进的过程中,注释可能是宝贵的资产。注释还可以提供有价值的信息,这些信息对于处理某些代码是必不可少的。

我回想起一个例子,我不得不挖掘一些 Julia 代码,因为没有它的文档。我不知道某个东西的输入应该是如何构造的,但是我发现一些奇怪的注释存储在一边,解释了我需要的数据结构是如何呈现的,然后我的代码开始了比赛。虽然这绝对不是注释的最佳应用,但它确实坚定地证明了注释对于阐明某些观点是多么重要。我们不能指望文档包含开发人员可能想从最初的程序员那里了解的所有内部信息,这正是注释派上用场的地方。

然而,我想谈一点关于使用注释的原因是,虽然它们很简单,但实际上使用它们是一门艺术。也就是说,我发现在较新的程序员代码中发现一些相当可怕的注释是很常见的。很多时候,有些评论要么是矛盾的,要么是直接解释的…例如,我不需要一个评论告诉我你在做这个算术:

# divide x by 5
new = x / 5

如果对此有任何评论,它应该高于所有的算术,而仅仅是一个公式,例如:

# z = 3 * 2 + x / 5

然而,在这种特殊情况下,这仍然没有太大意义——因为这个表达式中只有一个独立变量。有那么多正确的地方可以评论,但结果也有那么多错误的地方和事情可以评论。所以事不宜迟,我想提供一些有效注释代码的个人技巧,以及 Python 编程语言的 PEP8 代码注释惯例。

PEP8 要说的话

首先,PEP8 指出代码需要与软件保持同步。随着给定注释集周围的代码发生变化,这些注释也应该重写。不适用于给定代码的注释比没有注释更糟糕。PEP8 还指出,注释应该用完整的句子。这当然是有适当的语法和标点的,比如一个句子以大写开头,以句号结尾。

# This would be a proper comment.
#this one isn't

当然,这有一个例外,如果我们有一个已存在的别名,我们应该在代码中遵守那个别名的大小写,比如这个例子:

# g is Jimmy's height
g = jimmys_height

# G is Jimmy's height
g = jimmys_height

在多句注释中,除了在最后一句之后,你应该在句末句号之后使用两个空格。当然,这些评论也应该具有可读性,并且易于理解。PEP8 的另一个奇怪的惯例是注释应该是英文的……“除非你 120%确定只有说你的语言的人会查看代码……”(直接引用)。)我发现这很有趣,因为我在一些非常流行的 Python 软件中看到过许多西班牙语或其他语言的评论。

还有一点,PEP8 说行内注释应该很少使用。明确地说,行内注释就是代码后面的注释。

我要说的是

首先,我想说的是,如果有一种负面的注释类型,我宁愿看到空白,那就是

多余的评论。

评论可以被过度使用,这绝对不是你想做的事情。因为你在解释你正在做的每件事而重复你的代码行不是一个好的编码实践。不要做这样的工程师:

# Multiply z and x to get b.
b = z * x
# Add five to b
b += 5
# Multiply slope by x and add b:
y = m * x + b

我们可以看到你在做什么!这不需要注释,只要看一下这个例子,您就能看出注释使代码更难阅读——而不是更容易?这一部分的一个更好的例子是用这个算法实际做了什么来标记它下面的整个代码,而不是用它所需要的操作来标记。

# Calculate the line.
b = z * x
b += 5
y = m * x + b

另外,在你的磅后面加一个空格也是程序员之间的约定。这绝对是一个可以遵循的好规则:

# Comment this.
#Not this.

我认为这类似于将操作符挤在数据旁边,这只是让东西难以阅读。另一件事是当描述一个短语时,要理解评论实际上属于哪里。想想之前的台词。我们不希望在任何地方添加内嵌评论,尤其是在这之后!

# This is correct.
b = z * x
b += 5    # This is not correct.
y = m * x + b
# Please do not do this.

您可以非常有效地使用注释来描述功能区域的目标,而不是描述单独的行。虽然有时这些确实是一个好主意,但请考虑我的 OddFrames.jl 包中的以下代码:

function OddFrame(file_path::String)# Create labels/columns from file.extensions = Dict("csv" => read_csv)extension = split(file_path, '.')[2]labels, columns = extensions[extension](file_path)length_check(columns)name_check(labels)types, columns = read_types(columns)# Get our coldata.coldata = generate_coldata(columns, types)# dead function."""dox"""head(x::Int64) = _head(labels, columns, coldata, x)head() = _head(labels, columns, coldata, 5)# drop function.drop(x) = _drop(x, columns)drop(x::Symbol) = _drop(x, labels, columns, coldata)drop(x::String) = _drop(Symbol(x), labels, columns, coldata)
# dropna function.dropna() = _dropna(columns)dtype(x::Symbol) = typeof(coldata[findall(x->x == x,labels)[1]][1])
# dtype function.dtype(x::Symbol, y::Type) = _dtype(columns[findall(x->x == x,labels)[1]], y)# Create the type.self = new(labels, columns, coldata, head, drop, dropna, dtype);select!(self)return(self);end

这些评论是针对 Julia 包的,但实际上这两个包在评论时应该没有太大区别。在这个例子中,我使用注释来解释我正在创建的数据——这些数据都包含在我们的类型中。我正在描述我想要的输出,您可以让代码解释我是如何到达那里的。我认为这是使用注释的一个很好的方式,因为它使得找出函数的特定区域变得不那么困难。

结论

老实说,评论是一个完整的主题,我认为从教育的角度来看,应该更加关注它。这是因为它们非常强大,但只有在正确使用的情况下。当然,这在很大程度上取决于程序员个人认为需要评论什么,这是非常主观的。关于什么该评论,什么不该评论,确实没有指南。

然而,使用这些建议来避免重复,从一个更广泛的角度来看问题,肯定会使你的评论比过去更有价值。我认为我们都可以不断改进这一点,我知道我肯定不会总是写评论,当我写评论时,它们可能非常模糊,也不是非常全面。在很多方面,我觉得好的代码不应该需要注释。如果你的代码很棒,那么它应该像读英语或其他什么一样可读。然而,话虽如此,我仍然发现如果使用得当,注释会有很大的好处,而且我肯定能看到它们在某些方面是如何有效的。我希望这个关于我们都可能犯过无数次的错误的小概述,特别是当涉及到 PEP8 方面的事情时,有助于使我们未来的代码看起来更好,并且通过准确、无冗余的注释更容易理解。感谢您阅读我的文章。

如何在机器学习模型中使用置信度得分

原文:https://towardsdatascience.com/how-to-use-confidence-scores-in-machine-learning-models-abe9773306fa?source=collection_archive---------0-----------------------

入门

从二进制分类教科书案例到现实世界的 OCR 应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与人类一样,机器学习模型有时会在根据输入数据点预测值时出错。但是也像人类一样,大多数模型能够提供关于这些预测可靠性的信息。当你说“我确信……”或“也许是……”时,你实际上是在给你对自己所说的话的自信程度赋予一个相对的资格。在数学中,该信息可以被建模为例如百分比,即 0 和 1 之间的数字,并且大多数 ML 技术提供这种类型的信息。

该置信水平的人机等价可以是:

“我确信……”<=>100%

“我认为是……”<=>70%

“我不知道,但我会说……”<=><50%

The main issue with this confidence level is that you sometimes say “I’m sure” even though you’re effectively wrong, or “I have no clue but I’d say…” even if you happen to be right. Obviously in a human conversation you can ask more questions and try to get a more precise qualification of the reliability of the confidence level expressed by the person in front of you. But when you’re using a machine learning model and you only get a number between 0 and 1, how should you deal with it?

Most common ML confidence scores

There is no standard definition of the term “confidence score” and you can find many different flavors of it depending on the technology you’re using. But in general, it’s an ordered set of values that you can easily compare to one another.

The three main confidence score types you are likely to encounter are:

一个介于 0 和 1 之间的十进制数字,可以解释为信心的百分比。

  • 优点:人类容易理解
  • 缺点:分数“1”或“100%”令人困惑。这很矛盾,但 100%并不意味着预测是正确的。

0 与+,或-与+

  • 优势:你几乎总是可以比较两个置信度得分
  • 弱点:对一个人来说没什么意义

一组表达式,如{ “低”、“中”、“高” }

  • 优点:非常容易操作和理解
  • 缺点:缺乏粒度,无法在数学函数中使用

重要技术说明:你可以使用任何双射函数转换[0,+[0,1 中的点],例如使用 sigmoid 函数,轻松地从选项#1 跳到选项#2,或者从选项#2 跳到选项#1(广泛使用的技术)。请记住,由于浮点精度的原因,从 2 切换到 1 或从 1 切换到 2 可能会丢失两个值之间的顺序。试着计算一下 sigmoid(10000)和 sigmoid(100000),都可以给你 1。

理解问题的一些指标

大多数情况下,决策是基于输入做出的。例如,如果你正在开车,收到“红灯”数据点,你(希望)会停下来。

当您使用 ML 模型做出导致决策的预测时,您必须让算法做出反应,如果它是错误的,将导致不太危险的决策,因为根据定义,预测永远不会 100%正确。

为了更好地理解这一点,让我们深入研究用于分类问题的三个主要指标:准确度、召回率和精确度。我们可以将这些度量扩展到分类以外的其他问题。

真阳性、真阴性、假阳性和假阴性

这些定义对计算指标非常有帮助。一般来说,它们指的是一个二元分类问题,在这个问题中,对一个拥有真值“是”或“否”的数据进行预测(要么是“是”,要么是“否”)。

  • 真阳性:预测“是”且正确
  • 真正的否定:预测“不”和正确
  • 误报:预测“是”和错误(正确答案实际上是“否”)
  • 假阴性:预测“否”和错误(正确答案实际上是“是”)

在接下来的部分中,我们将使用缩写 tp、tn、fp 和 fn。

准确(性)

准确性是最容易理解的指标。它只是数据集上正确预测的数量。例如,给定一个包含 1,000 幅图像的测试数据集,为了计算准确性,您只需对每幅图像进行预测,然后计算整个数据集中正确答案的比例。

假设你从这 1000 个例子中做出了 970 个好的预测:这意味着你的算法准确率是 97%。

当在假阳性和假阴性预测之间没有令人感兴趣的折衷时,使用该度量。

但是有时候,根据你的目标和你的决策的重要性,你可能想用其他的指标来平衡你的算法的工作方式,比如召回率和精确度。

精度公式:(tp + tn ) / ( tp + tn + fp + fn)

回忆(也称为敏感性)

为了计算算法的召回率,你只需要考虑测试数据集中真正“真实”的标签数据,然后计算正确预测的百分比。这是一个有助于回答以下问题的指标:“在所有真正的正值中,我的算法实际预测为真的百分比是多少?”

如果一个 ML 模型必须预测一个交通信号灯是否是红色的,以便你知道你是否必须开车,你更喜欢一个错误的预测:

  1. 虽然不是红色,但上面写着“红色”
  2. 虽然它是红色的,但上面写着“不是红色的”

让我们来看看在这两种情况下会发生什么:

  1. 你的车停下来了,尽管它不应该停下来。这只是轻微的危险,因为后面的其他司机可能会感到惊讶,这可能会导致一场小型车祸。
  2. 你的车不会在红灯时停下来。这是非常危险的,因为过马路的司机可能看不到你,造成全速撞车,造成严重的损害或伤害…

每个人都会同意情况(b)比情况(a)糟糕得多。在这种情况下,我们因此希望我们的算法永远不要说灯不是红色的:我们需要一个最大的回忆值,只有当灯是红色时算法总是预测“红色”,即使这是以灯实际上是绿色时预测“红色”为代价的,才能实现。

可以通过在测试数据集上测试该算法来测量召回率。它是一个百分比,除以算法预测为“是”的数据点数,再除以实际上为“是”值的数据点数。

例如,假设我们有 1000 幅图像,其中 650 幅是红灯,350 幅是绿灯。为了计算我们算法的召回率,我们将对我们的 650 个红灯图像进行预测。如果算法对这 650 张图片中的 602 张说“红色”,召回率将是 602 / 650 = 92.6%。这还不够!7%的情况下,存在全速车祸的风险。我们将在后面看到如何使用我们算法的置信度来防止这种情况,而不改变模型中的任何东西。

召回公式:tp / ( tp + fn)

精确度(也称为“阳性预测值”)

你的算法的精度让你知道当你的算法预测“正确”时,你可以信任它多少。它是正确猜测为“真实”的预测与所有猜测为“真实”的预测(其中一些实际上是“错误的”)的比例。

让我们现在想象一下,有另一个算法正在查看一条两车道的道路,并回答以下问题:“我可以超过我前面的车吗?”

再一次,让我们弄清楚一个错误的预测会导致什么。错误的预测意味着算法说:

  1. “你能超过那辆车”尽管你不能
  2. “不,你不能超过那辆车”尽管你可以

让我们看看在这两种情况下会发生什么:

  1. 你提高车速以超越你前面的车,然后你移动到你左边的车道(向相反的方向行驶)。然而,可能会有另一辆车在相反的方向全速驶来,导致全速撞车。结果:你们都受了重伤。
  2. 你可以超越你前面的车,但你会轻轻地跟在慢的司机后面。结果:什么也没发生,你只是损失了几分钟。

同样,每个人都会同意(b)比(a)更好。我们希望我们的算法只在“你可以超车”是真的时候才预测它:我们需要一个最大的精度,当它实际上是“不”的时候,永远不要说“是”。

为了测量测试集上的算法精度,我们计算所有“是”预测中真正“是”的百分比。

为此,假设我们有 1000 张超车情况的图像,其中 400 张代表安全超车情况,600 张代表不安全超车情况。我们想知道在我们的算法做出的所有“安全”预测中,真正“安全”的百分比是多少。

假设在我们的“安全”预测图像中:

  • 其中 382 个是安全超车情况:真=是
  • 其中 44 个是不安全超车情况:真相=否

计算精度的公式为:382/(382+44) = 89.7%。

意思是:89.7%的时候,当你的算法说你可以超车的时候,你实际上是可以的。但这也意味着 10.3%的时候,你的算法说你可以超越这辆车,尽管它不安全。精确度不够好,我们将看到如何通过置信度得分来提高精确度。

精度公式:tp / ( tp + fp)

度量摘要

您可以使用测试数据集(越大越好)估计以下三个指标,并计算:

  • 准确率:正确预测的比例— ( tp + tn ) / ( tp + tn + fp + fn)
  • 回忆:所有真实“是”数据中“是”预测的比例— tp / ( tp + fn)
  • Precision:所有“是”预测中真实“是”数据的比例— tp / ( tp + fp)

置信度阈值

在所有之前的例子中,我们认为我们的算法只能预测“是”或“否”。但是这些预测从来不会被输出为“是”或“否”,它总是一个数字分数的解释。实际上,机器总是以 0 到 1 之间的概率预测“是”:这是我们的置信度得分。

作为一个人,在给定 0 到 1 之间的置信分数的情况下,将预测解释为“是”的最自然的方式是检查该值是否高于 0.5。这个 0.5 是我们的阈值,换句话说,它是最小的置信度,超过这个值我们就认为预测是“是”。如果低于,我们认为预测为“否”。

然而,正如我们在前面的例子中看到的,犯错误的代价根据我们的用例而不同。

幸运的是,我们可以改变这个阈值,使算法更好地符合我们的要求。例如,让我们想象一下,我们正在使用一个返回 0 到 1 之间的置信度得分的算法。将阈值设置为 0.7 意味着您将拒绝(即在我们的示例中将预测视为“否”)所有置信度低于 0.7 的预测(包括在内)。这样做,我们可以微调不同的指标。

总的来说:

  • 提高阈值会降低召回率,提高准确率
  • 降低阈值会产生相反的效果

现在需要指出的重要一点是,上面的三个指标都是相关的。一个简单的例子是:

  • threshold = 0 意味着您的算法总是说“是”,因为所有的置信度得分都在 0 以上。你得到最小的精确度(你在每一个真正的“否”数据上都是错的)和最大的回忆(当它是一个真正的“是”时,你总是预测“是”)
  • threshold = 1 意味着您拒绝所有预测,因为所有置信度得分都低于 1(包括 1)。你有 100%的准确性(你说“是”永远不会错,因为你从来不会说“是”…),0%回忆(……因为你从来不说“是”)

试图设置最佳分数阈值无非是在精确度和召回率之间进行权衡。

精确召回曲线(PR 曲线)

要选择应用程序中要设置的最佳阈值,最常用的方法是绘制精确召回曲线(PR 曲线)。

为此,您将在一个测试数据集上,针对许多不同的阈值,计算算法的精度和召回率。一旦你有了所有的情侣(pr,re),你就可以把它们画在一张图上,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PR 曲线总是以一个点开始(r = 0;p=1)按照惯例。

一旦你有了这条曲线,你可以很容易地看到蓝色曲线上的哪一点最适合你的用例。然后,您可以找出这个点的阈值,并在您的应用程序中设置它。

如何绘制你的 PR 曲线?

所有之前的例子都是二元分类问题,我们的算法只能预测“真”或“假”。在现实世界中,用例稍微复杂一点,但是所有之前的度量都可以通用化。

让我们举一个新的例子:我们有一个基于 ML 的 OCR,它对发票执行数据提取。这个 OCR 提取一堆不同的数据(总金额、发票号、发票日期……)以及这些预测的可信度分数。

我们应该为发票日期预测设置哪个阈值?

这个问题不是二元分类问题,要回答这个问题,绘制我们的 PR 曲线,需要定义什么是真预测值,什么是假预测值。

这里所有的复杂性是做出正确的假设,这将允许我们符合我们的二元分类度量:fp,tp,fn,tp

以下是我们的假设:

  1. 我们数据集中的每张发票都包含一个发票日期
  2. 我们的 OCR 可以返回一个日期,或者一个空的预测

如果与#1 不同,您的测试数据集包含没有任何发票日期的发票,我强烈建议您将它们从数据集中删除,并在增加更多复杂性之前完成第一个指南。这个假设在现实世界中显然不成立,但是如果没有这个假设,下面的框架描述和理解起来会复杂得多。

现在,让我们定义我们的指标:

  • true positive:OCR 正确提取了发票日期
  • 误报:OCR 提取了错误的日期
  • 正误:这种情况是不可能的,因为我们的发票上总是有日期
  • 假阴性:OCR 没有提取发票日期(即空预测)

在开始绘制我们的 PR 曲线之前,让我们考虑一下我们的模型和二元分类问题之间的区别。

在我们的 OCR 用例中,将阈值设置为 0 意味着什么?这意味着我们不会拒绝任何预测,但与二元分类问题不同,这并不意味着我们会正确预测所有的正值。事实上,我们的 OCR 可以预测错误的日期。

这意味着我们可能永远不会到达回忆为 1 的曲线点。将阈值设置为 0 时,通常会达到这一点。在我们的例子中,这个阈值将给出我们整个数据集中正确预测的比例(记住没有发票日期就没有发票)。

我们预计最终会有这样的曲线:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们现在准备绘制我们的公关曲线。

步骤 1:对测试数据集的每张发票运行 OCR,并为每张发票存储以下三个数据点:

  • 这个预测正确吗?
  • 预测的置信度是多少?
  • 预测是否填充了日期(与“空”相对)?

第一步的输出可以是一个简单的 csv 文件,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 2:计算阈值= 0 的召回率和精确度

我们现在需要计算 threshold = 0 的精度和召回率。

这是最简单的部分。我们只需要将我们的每个预测限定为 fp、tp 或 fn,因为根据我们的模型化,不可能有任何真正的否定。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们算一下。在上面的例子中,我们有:

  • 8 个真阳性
  • 5 次误报
  • 3 个假阴性

在阈值为 0 的第一个例子中。,我们就有了:

  • 精度= 8 / (8+5) = 61%
  • 召回率= 8 / (8+3) = 72%

我们有了 PR 曲线的第一个点:(r=0.72,p=0.61)

步骤 3:对不同的阈值重复此步骤

我们刚刚计算了第一个点,现在让我们对不同的阈值进行计算。我们以阈值= 0.9 为例。

正如我们上面提到的,设置 0.9 的阈值意味着我们认为任何低于 0.9 的预测都是空的。换句话说,我们需要把它们都限定为假负值(记住,不可能有任何真负值)。

为此,您可以在我们的 csv 文件中添加一列:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在上面的 csv 文件中:

  • 灰线对应于低于我们阈值的预测
  • 蓝色单元格对应于我们必须将资格从 FP 或 TP 更改为 FN 的预测

让我们再算一次。

我们有:

  • 6 个真阳性
  • 3 次误报
  • 7 个假阴性

在阈值为 0 的第一个例子中。,我们就有了:

  • 精度= 6/ (6+3) = 66%
  • 召回率= 6 / (6+7) = 46%

这导致了我们的 PR 曲线的一个新点:(r=0.46,p=0.67)

对一组不同的阈值重复这一步,存储每个数据点,就大功告成了!

解读你的公关曲线

在理想情况下,您的测试集中有大量数据,并且您使用的 ML 模型非常适合数据分布。在这种情况下,随着回忆的增加,你会得到一条向下的公关曲线。

但是你可能没有很多数据,或者你可能没有使用正确的算法。在这种情况下,你得到的 PR 曲线可能是不成形的,是可利用的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是我们在 Mindee 绘制的真实世界 PR 曲线的一个例子,它与我们在日期字段上的收据 OCR 非常相似。

我们的测试集中有来自大约 20 个国家的 10k 个带注释的数据。日期字段的 PR 曲线如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

任务完成了。现在,您可以选择曲线上对您的用例最感兴趣的点,并在您的应用程序中设置相应的阈值。

无论您的用例是什么,您几乎总能找到一个代理来定义适合二元分类问题的度量。这样,即使你不是数据科学专家,你也可以谈论你的模型的精度召回:两个清晰而有用的指标来衡量算法有多适合你的业务需求。

如何在 Matplotlib 中使用自定义字体——在 5 分钟或更短时间内

原文:https://towardsdatascience.com/how-to-use-custom-fonts-with-matplotlib-in-5-minutes-or-less-57c63ece2a11?source=collection_archive---------12-----------------------

使用自定义字体(包括 TTF)使您的可视化效果更加引人注目

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

默认情况下,Matplotlib 可视化效果会很难看。对你来说,幸运的是,几行代码就可以做很多调整。今天,我们将看看改变字体,并解释为什么它通常是一个好主意。

这篇文章的结构如下:

  • 自定义字体—为什么?
  • 使用内置字体
  • 使用 TTF 文件中的自定义字体
  • 结论

自定义字体—为什么?

为什么不呢?默认的不会让你走远。如果你的公司有一个独特的品牌,为什么不尽可能使用它呢?

让我们来看看默认样式是什么样子的。没有数据就没有数据可视化,所以让我们先声明一个简单的数据集。它包含一家虚构公司的虚拟季度销售额:

以下是数据集的外观:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-虚拟可视化数据集(作者提供的图片)

让我们用折线图和散点图来展示这些数据。我们将保留大多数默认样式,只移除顶部和右侧的脊线:

这是视觉效果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2 —使用默认字体的可视化效果(作者提供的图片)

正如你所看到的,字体看起来不错,但我不知道有哪个品牌使用 DejaVu Sans 作为他们的首选字体。接下来看看怎么改。

使用内置字体

Matplotlib 使得使用安装在机器上的字体变得容易。您可以使用以下代码片段列出前十种可用字体:

结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-预装字体(作者图片)

如果您想要整个列表,请移除[:10]。您可以指定参数font的值,以便在标题或轴标签中使用感兴趣的字体。

以下代码片段向您展示了如何在标题中使用 Courier 新字体:

这是可视化效果的样子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4 —预装系统字体的可视化效果(图片由作者提供)

但是你知道在使用之前不需要安装字体吗?你所需要的只是一个 TTF 文件。接下来让我们探索一下它是如何工作的。

使用 TTF 文件中的自定义字体

要跟进,请从这里(或任何其他地方)下载梅里韦瑟字体。解压缩文件,并将路径复制到文件夹。

从这里,我们可以使用 Matplotlib 中的font_manager从文件中添加字体。你需要在循环中一个接一个地添加字体。

添加后,我们将把整个 Matplotlib 字体系列设置为 Merriweather,这样我们就不必到处手动指定字体。

完成后,您可以像往常一样进行可视化:

结果如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5 —使用自定义 TTF 字体的可视化效果(图片由作者提供)

这就是在 Matplotlib 中添加自定义字体有多简单!接下来让我们总结一下。

结论

今天的文章很短,但很中肯。你已经学会了如何将你的品牌融入到数据可视化中,如果你想在所有媒体上传递一致的信息,这是一项基本技能。

如果你喜欢这篇文章,请继续关注博客——更多类似的文章即将发表。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

原载于 2021 年 4 月 1 日 https://betterdatascience.com**

如何利用数据(和心理学)获得更多数据

原文:https://towardsdatascience.com/how-to-use-data-and-psychology-to-get-more-data-1749996ea704?source=collection_archive---------37-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

约书亚·索蒂诺在 Unsplash 上拍摄的照片

在进行研究调查时,使用这些技巧平均能让我多得到 70%的回答

不幸的是,让人们填写调查问卷是一件复杂的事情。没有什么灵丹妙药能让每个人都一直填写。然而,我已经将一些技术组合在一起,当它们相互结合使用时,会有很大的帮助。

众所周知,好的数据和大量的数据对于构建任何工作模型都是必不可少的。因此,当你试图从公众那里收集数据时,这篇文章将帮助你增加你收集的数据量。

  • 首先,我将讨论杠杆突出理论及其对让个人填写调查的影响。
  • 其次,我将讨论使用机器学习(K-means)将个人分组到同类偏好的组中来对个人进行聚类。
  • 最后,我将讨论行为经济学和心理学揭示的人类内部的系统性非理性,以及如何将它们纳入您的调查邀请以提高接受度。

一份好的调查邀请函要阐明个人认为有吸引力的调查属性。

调查参与最突出的理论之一是杠杆突出理论。这个理论是由密歇根大学的格罗夫斯、辛格和康宁在 2000 年创立的。顾名思义,该理论利用调查特征的显著性来影响个人参加调查的概率。

下图将有助于解释这一点。一开始可能会让人觉得有点困惑和费解,但我会尽力解释。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://www.jstor.org/stable/3078721?seq=1

该图显示了两个人面对两个独立的调查—一个在左边,一个在右边。成功概率(进行调查)是调查属性的系数加权和。

图表上圆圈的大小代表了勘测设计者对勘测各个方面的重视程度。例如,左侧调查中的“5 美元现金奖励”圆圈较大,因此在本次调查的调查介绍中更为突出。这可能是在标题中而不是副标题中提到的。支点(铅笔尖)代表个体的一个无关紧要的点,与支点的距离代表个体对属性的重视程度。球挂得越靠右,个人对这个属性的评价就越积极。以同样的现金激励为例,右边的人比左边的人更看重现金。这意味着现金激励比左边的人更有可能说服他填写调查。

因此,可以看出,面对两个独立调查的两个人之间的主要区别是一个向左倾斜,一个向右倾斜。图表越向右倾斜,个人回答调查的可能性就越大。

简而言之,人们重视不同的东西,我们需要设计调查邀请来说明这一点——突出好的,隐藏坏的。

不同的人对不同的东西有不同的价值——所以让我们把他们分成具有相同偏好的群体。

我相信你能发现,这其中的主要问题是人们对不同事物的重视程度不同。那么,我们如何着手设计一份调查邀请函来说明这一点呢?我们没有——我们设计了一些不同的。我们将个人聚集到具有相似偏好的群体中,然后针对这些群体定制邀请。还有一些所有人都重视的属性,这些属性几乎总是会产生积极的影响,但我将在下一节谈到这一点。

因此,你可能明白我的意思了。我们可以使用机器学习算法将个人分成我们认为具有相似偏好的群体。我们可以使用许多算法,但最常用的技术是 K-means 。K-means(经常与它的监督学习堂兄 KNN 混淆)使用最近的均值将数据划分到聚类中。我不会在这里深入 K-means 的细节,因为这不是这篇文章的内容。维基百科页面在这里是,Scikit-learn 文档在这里是我假设从现在开始,大多数人都知道 K-means 是如何工作的,如果你不知道,那么你真正需要知道的是,该算法根据个人的特征将他们分组。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

K 表示行动中的(维基百科)

如果你想进一步了解如何用 K-means 对你的客户/参与者进行细分,请阅读这篇伟大的文章。我还必须指出,你最终选择的集群越多,你需要写的邀请函就越多,所以我从来不倾向于超过 k = 5。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

标准 K 均值算法演示(维基百科)

好了,现在我们把所有的潜在参与者分组。然后,我们可以分析这些群体,并尝试辨别这些群体中的个人可能重视什么。这完全取决于你有什么数据。例如,如果您发现一个群体的平均年龄为 20 岁,平均收入为 10,000 英镑,而另一个群体的平均年龄为 50 岁,平均收入为 50,000 英镑,那么假设前一个群体可能更看重金钱并不是一个大胆的假设。在 Python/Pandas 中使用描述性统计的完整指南可以在这里找到。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们星团平均年龄的一个例子。

然后,利用你愿意提供的任何金融服务来完成你的调查可能是明智的。在您的调查中直接提供资金并不总是一个好主意,因为这有各种各样的问题,我稍后会谈到。不过,为调查未来产品提供较大折扣将是一个好主意。

个人也看重同样的东西——来自行为经济学和心理学的见解

奇怪的是,尽管人们的偏好范围很广,但他们也倾向于同一方向。

个体就是我们行为经济学家所说的“系统性非理性”。因此,除了个体对激励的反应千差万别之外,某些事物也会吸引所有的个体。我们可以整合并利用这些有利于我们的偏见来增加调查的参与度,而不管我们是否已经聚集了个人。

下面我将重点介绍一些最常见的偏见,这些偏见被用来鼓励个人采取某些行动,以及如何在您的调查邀请中使用这些偏见。

互惠

1974 年,杨百翰大学的社会学家菲利普·昆兹向 600 名陌生人发出了手写的圣诞卡。他在验证一个理论,即如果你为某人做了好事,他们会回报你。他是对的。尽管没有一个人见过他,他还是收到了数百个回复。有些信长达 3 页,人们经常把家庭照片发给陌生人。在行为经济学中,我们称之为互惠准则——如果别人为我们做了积极的事情,我们会因为没有回报而感到非常不舒服。

因此,要求某人为你做某事的最佳时机是在你已经为他们做了某事之后。然而,这并不是双向的。只有在你已经为个人做了一些事情的情况下,这种方法似乎才有效。承诺以后做事就是不切实际。

因此,如果你刚刚提供了一些令人难以置信的客户服务,为什么不在你发送最后一封电子邮件时,请个人在调查中给你一些反馈。在这一点上,个人会比其他任何人更有责任感。这在业内开始变得相当普遍,如果你以前没有注意到这一点,我会感到惊讶。另一个常见的方法是预先给某人一些东西(比如他们下一个订单的 20%),然后立即让他们填写一份关于“他们如何能进一步帮助你”的调查。

让它社交

个人喜欢从众,他们喜欢做别人做的事。通常情况下,做决定是复杂且耗费精力的,因此个人只能求助于默认选项——其他人都在做的事情。因此,我们可以反过来使用这些知识。告诉人们‘嘿,其他人都在这么做,你也应该这么做’效果非常好。

英国政府正是通过这样做收回了数百万未缴税款一句话可以拯救百万。

因此,如果很多人在做你想让他们做的事情,那么告诉其他人,这部分人很可能会越来越多。

告诉你的客户 80%的人会留下一些反馈,这可能会鼓励其他人也这样做。这也带来了越来越多的回报——随着越来越多的人留下反馈,百分比会变得更高,球会继续滚动。

使之容易

这是最基本的常识,但是经常被忽视。人类很懒,我们不想使用不必要的努力——尤其是脑力。因此,请使调查(和介绍)简短,易于理解,并尽可能简单易用。大多数时候,在调查时,你想要的是个人首先想到的。让他们尽可能容易地提供它。不要让调查变得复杂,因为信息太多。

在信息可能有用的前提下抛出问题不是一个好策略。你应该事先有一个清晰简明的计划,知道你需要什么信息。这将有助于消除多余的问题,并消除参与者在完成一页而进度条几乎没有移动时的恐惧。

你为什么不直接付钱给他们?

在经济学中,我们有一个术语叫做挤出。该理论认为,在一个经济体中,公共部门的过度支出会压低或消除(挤出)私人部门的支出。奇怪的是,也有证据表明排挤与个人的道德意图有关。例如,Richard Titmuss 的一项著名实验表明,当个人有偿献血时,最终献血的人会减少。

因此,支付激励挤出了良好的意图(或自我感觉良好的激励)。就 LS 模型而言,这意味着调查的某些属性不兼容。正如这个例子所示,当个人收到现金激励时,他们就失去了向慈善事业捐款的激励。人们努力让自己感觉良好,做一些道德的事情,同时还能获得报酬。

当然,如果你付给某人 1000 英镑来完成一个 5 分钟的调查,你将很难在这个国家找到一个不这样做的人。但是,如果您可以选择为个人 1 提供一份 20 分钟的调查(例如癌症研究),那么向个人付费可能不是一个好主意。由于个人的良好天性,你可能会得到同样多的回应,如果不是更多的话。

结论:

因此,总结一下,下面是我在调查个人时的过程总结。

  • 个体差异很大,所以使用 K-means 等算法根据他们的偏好对他们进行聚类。使用描述性统计从这些群体中进行推断,并为他们定制调查邀请。
  • 在某些领域,个人会受到系统性的影响——诸如互惠、社会规范和从众倾向等偏见会显著提高回应的可能性。
  • 结合使用上述两种技巧,设计出量身定制且具有心理吸引力的调查邀请函。

我在针对标准调查邀请的 A/B 测试中多次测试了这种方法,正如所述,平均回报是回复率增加了 70%。

我希望这能有所帮助,如果你喜欢阅读,请不要犹豫跟随。以下是我的一些类似的文章。

干杯,

詹姆斯

如何在工业生产环境中使用数据科学

原文:https://towardsdatascience.com/how-to-use-data-science-in-industrial-production-environments-6accf24afeb2?source=collection_archive---------21-----------------------

关于如何在工业生产环境中使用数据科学的方法源于我的学士论文

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Unsplash 上拍摄的 ThisisEngineering RAEng

这篇文章来源于我的工业工程学士论文“用数据科学技术进行生产数据分析”。我的论文来自真实的工业世界,所以我可以使用真实的工业数据,创建一个对我的论文有用的案例研究。

介绍

我研究了一个分三个阶段制造的特定对象:两个组装阶段和一个系统运行测试阶段。该系统已经批量生产了三年,因此操作员对他们的工作非常有信心。我的分析集中在装配线的流程交付时间(*)和两个装配阶段的周期时间(**)。在我的分析中,我还没有考虑操作测试周期时间,因为在过去的几个月中发生了一些变化,数据仍然有点脏。

这项研究的统计基础

在这个案例研究中,我使用回归模型来研究数据集;特别是:线性回归、多项式回归和样条回归。这个想法是细分每个操作员在两个装配阶段的周期时间;这样回归方法可以帮助我找到:

  • 每个装配阶段最快的操作员
  • 每个装配阶段的常量运算符

如何理解一个操作者在工作中是否恒常?从数学上讲,当一个变量在图表中是一条垂直线或水平线时,我们可以说它是常数;这就是回归,尤其是线性回归,帮助我的地方。

数据分析

现在来说说数据,看看数据分析是怎么做出来的。但是在继续之前,我必须说整个数据分析都是用 r。

流程提前期分析

首先,我研究了装配线流程提前期。我已经使用 r 中的“read excel”库导入了数据。绘制了一个散点图,其中“观察值”在“x”轴上,“流程交付时间”在“y”轴上,结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

流程提前期分析。图片由作者提供。

正如我们所看到的,有很大的数据分散;事实上,我不得不使用双对数标度,以便图表可以在特定的维度上绘制。所以,我在这项研究中首先要面对的是数据清洗。我问自己:流程提前期的哪些值太小了?哪些数值过高?我可以用什么标准来排除过高和过低的值?

我决定使用高斯正态函数对数据集进行归一化,结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过标准化数据绘制的图。图片由作者提供。

我们可以看到,这是一条右偏的高斯曲线;此时,我已经计算了平均值(m)和标准偏差(s ),并清理了(m-s;m+s)范围。数据清理后,我用线性回归线绘制了流程交付时间的散点图,结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

清理流程交付周期数据:线性回归散点图。图片由作者提供。

我发现了一条负斜率线;这是什么意思?这意味着随着观察的增加,过程交付时间减少;但是为什么会这样呢?有两个答案:

  • 操作员已经在该系统上工作过多次,他们获得了专业知识
  • 外部修改已经使流程交付周期缩短

由于该系统已经制造了三年,正如我在本文开始时所说,流程交付周期缩短的正确答案是第二个。

正如我之前所说的,在过去的几个月中,一些变化使我避免研究功能测试周期时间;这些变化也会影响流程交付时间,从而缩短交付时间。

这是第一个结果:使用线性回归方法,流程交付时间随着负斜率线的减少而减少。

第一个装配阶段:周期时间分析

首先,我得说这个组装阶段是一个“标准阶段”。我所说的标准装配阶段是什么意思?我的意思是,所涉及的操作是典型的工业装配线;例如,在一个标准的,我们可以找到像螺丝,机械和物理装配等操作。为了更好地理解它,请考虑这样一个事实,即周期时间取决于操作员对该阶段的信心(他们做了数百次),而不是他们的手工技能。在第二个组装阶段,我们将了解什么是非标准的组装阶段,这样在本文的后面会更加清楚。

我已经确定了至少贡献了 400 次观察的操作员;操作符有四个:操作符 A、D、N、o。然后,我已经使用我们在流程交付周期分析中看到的相同方法清理了数据,所以我不再重复了。那么,让我们来看看第一个装配阶段的数据分析。

线性回归模型

我做的第一件事是对四个运算符进行线性回归,结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

周期时间:四个操作员的线性回归散点图。图片由作者提供。

从图中我们可以看出,除了运算符 A,线性回归看起来是水平线;对于这个算符,直线有一点正斜率。当然,这种分析不足以得出任何结论。事实上——这也是这项研究的重点——统计学中的水平回归线有明确的含义:两个变量之间没有回归;换句话说,观察值和周期时间之间没有联系。

从数学上来说,我们可以在这里停下来说:“没有回归”,也许会中断研究。但是我们在一个工程领域,所以我问自己:“如果观察值和周期时间之间没有联系,这意味着什么?”。答案非常简单:对于任何观察,平均周期时间都是相同的;换句话说,操作者的周期时间是一致的;这是一个伟大的成果!

无论如何,这项研究还没有完成。我想深入回归方法,以表明那些水平线是真正水平的。怎么做呢?首先我做了一个残差分析。从残差分析来看,“多重 R 平方”值都接近于零。这发生在两种情况下:

1)线性回归模型不是描述数据的最佳方法

2)回归线真的是水平的

此外,通过残差分析,我可以找到每个操作员的周期时间;事实上,R 给了我们截距的值,由于这条线是水平的,这个值就是实际的周期时间。因此,在这一点上,我决定更深入地尝试用多项式回归模型来分析数据。

多项式回归模型

我问自己的第一个问题是:完美拟合数据的最佳多项式次数是多少?我怎么找到它?

回答这些问题有不同的方法:

  • 随着多项式次数的增加进行残差分析迭代
  • 随着多项式次数的增加进行图形迭代

选择这种方式或那种方式没有对错:无论如何,这是一个迭代的问题,决定何时停止迭代;但是我们什么时候停止?

对于残差分析,我们可以参考“调整后的 R 平方”值;一个好的方法是研究每次迭代的值;我们应该看到它在每次迭代中增加,在某一点上它应该减少;当它下降时,尤其是接近零时,这是一个好迹象,表明这与最符合数据的多项式次数有关。

相反,对于图形迭代,我们只是实现一个多项式回归,每次迭代的次数增加,我们可以用图形方式看到哪条曲线最符合数据;在一定程度上,这些曲线应该看起来都是相同的:我们只选择与“所有相似曲线”相关的最小程度。

在这个案例研究中,我使用了这两种方法,只是为了进行一些实践。

在下图中,我们可以看到四个运算符的迭代结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

周期时间:四个操作员的多项式回归散点图。图片由作者提供。

通过分析图形,我可以说,对于算子 N 和 O,曲线实际上是一条线,呈现非常小的波动,但这些波动在域的边界上。与算子 D 相关的曲线似乎是可疑的,但在这种情况下,波动也在域的边界。相反,对于 operator A 曲线,毫无疑问:数据的最佳近似值是一条曲线(7 次曲线)。

总结:拟合操作员 A 数据的最佳曲线似乎是 7 次多项式。拟合运算符 N 和 O 数据的最佳曲线似乎是一条水平线。对于算子 D,曲线有些疑问:它甚至可能是一条水平线。为了更加确定这些结果,我使用了样条回归方法。

样条回归模型

为了简单起见,我使用了一个三次样条来研究数据。我已经决定沿着 x 轴在每个域的 25%、50%和 75%的位置上施加样条线结,这是一个相当标准的选择。

这是运算符 A 样条:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

周期时间:操作员 A 样条散点图

相反,对于其他三个运算符,当尝试进行样条回归时,R 给了我一个错误,这是一个好结果;事实上,这意味着没有样条可以插值数据。因此,最符合数据的曲线实际上是一条(水平)线。

这一结论是对这一装配阶段研究的自然完成,因为对于这三个操作符,多项式回归方法对最符合数据的曲线留下了一些疑问。相反,样条消除了任何疑虑:因为没有样条,所以曲线实际上是每个操作符的一条线。

第二装配阶段:周期时间分析

应用于第二组装阶段的研究的方法论与之前相同,所以我只是直奔结果;但在此之前,有几件事要说。

这个装配阶段是非标准的。事实上,在这一阶段,操作者手动将垫圈施加到产品的整个外表面上。可以理解这一阶段与操作员的手工技能的关系。

因此,记住第一阶段的研究,这里的期望是发现大多数运营商显示周期时间振荡。

这意味着,对它们中的大多数来说,描述数据的最佳模型是样条模型。

因此,我发现四个操作者中有两个在周期时间中出现振荡,这些是他们的样条:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

周期时间:操作员 A 样条散点图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

周期时间:带操作员 D 样条的散点图

对于另外两个操作者,最好地描述数据的方法当然是一条水平线,这意味着它们在其周期时间内保持不变。

结论

最后,我想强调本研究中使用的方法的重要性,并谈谈本研究的一些可能的应用。

方法:对流程进行异常检测

这个案例研究的重要性依赖于方法,它是对流程的异常检测。事实上,对于每个操作者,我都进行了线性回归研究——首先找到了周期时间;然后,我通过多项式回归和样条回归来验证插值曲线是直线还是 n 次曲线。如果曲线是一条水平线,我们可以接受——就像我们在工程领域中一样——残差分析结果接近 0,这意味着该线在一定范围内是水平的(可能有一个小的正斜率或负斜率)。

因此,这种方法使我能够找到速度最快的操作员和/或在工作中最稳定的操作员,也就是那些在周期时间内呈现水平线的操作员。

这项研究的可能应用

该方法与操作员技能矩阵相结合,可用于:

1)根据数据,为每种产品找到最快和最稳定的运算符

2)拥有基于数据的替身操作员

3)在不参与生产环境的情况下研究生产时间,有几个好处:

3a)访问全部可用的历史数据,而不是对一小部分数据(在实际参与生产环境时注册的数据)做出假设。

3b)在生产环境中参与时,注册的数据不可能 100%干净。我的意思是,操作人员可能会有某种情绪上的参与,在他们的工作中感觉有点“被监督”。

因此,生产环境中唯一可用的注册数据只能为我们提供真实情况的一部分,此外,由于脏数据,这甚至可能是错误的。

— — — -

我想公开感谢卡洛·德拉戈教授对这项研究的指导

— — — -

(*)对于流程交付周期,我指的是完全制造某种产品所需的总时间。它从产品“进入”装配线开始计算,直到产品“离开”装配线

(**)周期时间是指完全完成一个制造阶段所需的时间。

我们一起连线吧!

中型

LINKEDIN (向我发送连接请求)

如果你愿意,你可以 订阅我的邮件列表 这样你就可以一直保持更新了!

考虑成为会员:你可以免费支持我和其他像我一样的作家。点击 这里 成为会员。

如何在 PyTorch 中为自定义文本数据使用数据集和数据加载器

原文:https://towardsdatascience.com/how-to-use-datasets-and-dataloader-in-pytorch-for-custom-text-data-270eed7f7c00?source=collection_archive---------2-----------------------

在本教程中,您将学习如何使用 PyTorch 中的 DataLoader 创建自定义数据集并管理它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:https://thenounproject . com/term/natural-language-processing/2985136/

创建 PyTorch 数据集并使用 Dataloader 管理它可以保持数据的可管理性,并有助于简化您的机器学习管道。数据集存储所有数据,Dataloader 可用于迭代数据、管理批处理、转换数据等等。

导入库

import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader

熊猫对于创建数据集对象来说并不重要。然而,它是管理数据的强大工具,所以我打算使用它。

torch.utils.data 导入创建和使用数据集和数据加载器所需的函数。

创建自定义数据集类

class CustomTextDataset(Dataset):
    def __init__(self, txt, labels):
        self.labels = labels
        self.text = textdef __len__(self):
        return len(self.labels)def __getitem__(self, idx):
        label = self.labels[idx]
        text = self.text[idx]
        sample = {"Text": text, "Class": label}
        return sample

***类 custom text Dataset(Dataset)😗**创建一个名为‘custom text Dataset’的类,你可以随意调用这个类。传递给该类的是我们之前导入的数据集模块。

def init(self,text,labels): 初始化类时需要导入两个变量。在这种情况下,变量被称为“文本”和“标签”,以匹配将要添加的数据。

***self.labels = labels&self.text = text:***导入的变量现在可以通过 self . text 或 self . labels 在类内的函数中使用

***def _ _ len _ _(self)😗**这个函数被调用时只返回标签的长度。例如,如果数据集有 5 个标签,那么将返回整数 5。

def getitem(self,idx): 这个函数被 Pytorch 的 Dataset 模块用来获取一个样本,构造数据集。初始化时,它将循环通过这个函数,从数据集中的每个实例创建一个样本。

  • ***【idx】***传递给函数的是一个数字,这个数字就是数据集将要循环的数据实例。我们使用前面提到的 self.labelsself.text 变量与传入的’ idx '变量来获取当前实例的数据。然后,这些当前实例被保存在名为“标签”和“数据”的变量中。
  • 接下来,声明一个名为’ sample '的变量,它包含一个存储数据的字典。这存储在由数据集中所有数据组成的另一个字典中。在用数据初始化这个类之后,它将包含许多标记为“文本”和“类”的数据实例。你可以把“文本”和“类”命名为任何东西。

初始化 CustomTextDataset 类

# define data and class labels
text = ['Happy', 'Amazing', 'Sad', 'Unhapy', 'Glum']
labels = ['Positive', 'Positive', 'Negative', 'Negative', 'Negative']# create Pandas DataFrame
text_labels_df = pd.DataFrame({'Text': text, 'Labels': labels})# define data set object
TD = CustomTextDataset(text_labels_df['Text'],                               text_labels_df['Labels'])

首先,我们创建两个名为 【文本】和【标签】 的列表作为例子。

text_labels_df = pd。DataFrame({‘Text’: text,’ Labels’: labels}): 这不是必需的,但是 Pandas 是一个用于数据管理和预处理的有用工具,可能会在 PyTorch 管道中使用。在本节中,包含数据的列表“文本”和“标签”保存在 Pandas 数据帧中。

***TD = custom text dataset(Text _ labels _ df[’ Text ‘],Text _ Labels _ df[’ Labels ‘])😗**这将使用传入的’ Text ‘和’ Labels '数据初始化我们之前创建的类。这些数据将成为该类中的“self.text”和“self.labels”。数据集保存在名为 TD 的变量下。

数据集现已初始化,可以使用了!

一些代码向你展示数据集内部发生了什么

这将向您展示数据是如何存储在数据集中的。

# Display text and label.
print('\nFirst iteration of data set: ', next(iter(TD)), '\n')# Print how many items are in the data set
print('Length of data set: ', len(TD), '\n')# Print entire data set
print('Entire data set: ', list(DataLoader(TD)), '\n')

输出:

数据集的第一次迭代:{‘Text’: ‘Happy ‘,’ Class’: ‘Positive’}

数据集长度:5

整个数据集:[{‘Text’: [‘Happy’],’ Class’: [‘Positive’]},{‘Text’: [‘Amazing’],’ Class’: [‘Positive’],{‘Text’: [‘Sad’],’ Class’: [‘Negative’]},{ ’ Text ‘:[’ unhappy ‘],’ Class’: [‘Negative’]},{‘Text’: [‘Glum’],’ Class ‘:[’ Negative ']]}]]]]]

如何使用’ collate_fn’ 对数据进行预处理

在机器学习或深度学习中,需要在训练之前清理文本并将其转化为向量。DataLoader 有一个方便的参数叫做 collate_fn。 该参数允许您创建单独的数据处理函数,并在数据输出前将该函数内的处理应用于数据。

def collate_batch(batch): word_tensor = torch.tensor([[1.], [0.], [45.]])
    label_tensor = torch.tensor([[1.]])

    text_list, classes = [], [] for (_text, _class) in batch:
        text_list.append(word_tensor)
        classes.append(label_tensor) text = torch.cat(text_list)
     classes = torch.tensor(classes) return text, classesDL_DS = DataLoader(TD, batch_size=2, collate_fn=collate_batch)

例如,创建两个张量来表示单词和类。实际上,这些可能是通过另一个函数传入的单词向量。然后这个批处理被解包,然后我们将单词和标签 tensors 添加到列表中。

然后,单词张量被连接起来,类别张量的列表,在本例中为 1,被组合成单个张量。该函数现在将返回已处理的文本数据,准备用于训练。

要激活此功能,只需在初始化 DataLoader 对象时添加参数collate _ fn = Your _ Function _ name

训练模型时如何循环访问数据集

我们将在不使用 collate_fn 的情况下遍历数据集,因为这样更容易看到 DataLoader 是如何输出单词和类的。如果上述函数与 collate_fn 一起使用,那么输出将是张量。

DL_DS = DataLoader(TD, batch_size=2, shuffle=True)for (idx, batch) in enumerate(DL_DS): # Print the 'text' data of the batch
    print(idx, 'Text data: ', batch['Text']) # Print the 'class' data of batch
    print(idx, 'Class data: ', batch['Class'], '\n')

DL_DS = DataLoader(TD,batch_size=2,shuffle=True) : 这用我们刚刚创建的 Dataset 对象“TD”初始化 DataLoader。在本例中,批量大小设置为 2。这意味着当您遍历数据集时,DataLoader 将输出 2 个数据实例,而不是一个。有关批次的更多信息,请参见本文。Shuffle 将在每个时期重新排列数据,这将阻止模型学习训练数据的顺序。

***for (idx,batch)in enumerate(DL _ DS):遍历我们刚刚创建的 DataLoader 对象中的数据。【DL _ DS】***返回批次的索引号以及由两个数据实例组成的批次。

输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如您所见,我们创建的 5 个数据实例以 2 个为一批输出。因为我们有奇数个训练样本,所以最后一个样本在自己的批次中输出。每个数字— 0、1 或 2 代表一个批次。

完整代码

如何对时间序列数据使用深度学习

原文:https://towardsdatascience.com/how-to-use-deep-learning-for-time-series-data-f641b1b41a96?source=collection_archive---------3-----------------------

实践教程

了解时间序列深度学习的可用选项

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

埃里克·维特索Unsplash 上拍摄的照片

关于机器学习和数据科学,ime 系列数据通常被单独归为一类。然而,由于分布随着时间和顺序测试而变化,数据科学的这一领域可能很难管理。

本文将介绍三种不同的深度学习模型,用于基于时序数据创建预测模型。第一个将是 LSTM,随后是两个具有一维卷积和二维卷积的 CNN。

我包含了代码块,这样您可以通过简单地更新正在使用的数据和调整参数来复制和重用这些代码。

请随意将本页加入书签,以供将来参考。

请注意,这些模型可能比时间序列预测所需的要多得多。然而,从简单的模型和 2D 表格数据开始,您可以对您可能期望的性能进行基准测试。

要将时间序列数据转换为 2D 数据,请在整个可用时间段或时间段的子集内进行聚合。这里不讨论其他选择,其中最常见的是自回归(AR)模型。

数据,数据,数据

任何精通数据的科学家都知道,数据争论、操作和全面的数据工程是数据科学家最耗时的任务。特别是有了机器学习和深度学习,这个任务就更复杂了。例如,与使用表格数据(基本熊猫数据框架或 2D 数字阵列中的数据)的模型相比,时间序列数据需要额外的维度才能使模型正常运行。

将数据处理成三维或四维的直接方法是一次考虑一个实例。这样,您可以一次查看一个实例的数据,以在进一步转换之前确认正确的信息(如标准时间间隔)。

X = []for i in instances:
    # ‘df’ is a 2D pandas dataframe or numpy array
    df = generate_instance(i) # Produce a single instance here
    X.append(df)X_3D = np.array(X)
X_4D = X_3D.reshape((X_3D.shape[0], X_3D.shape[1], X_3D.shape[2], 1))

对于每个实例,创建一个 2D 数据帧或 numpy 数组。该数据帧的列将包含特征,行代表单个实例的不同时间步长。

一次创建一个实例,并将它们添加到列表中。一旦每个数据帧都在一个列表中,就转换成一个 numpy 数组,然后轻松地将信息输入到下面的模型中。

请注意,每个实例必须具有相同的尺寸。如果它们不同,你会得到一些令人兴奋的错误。

对于二维卷积,数据必须有一个额外的维度。对于多元时间序列数据,这意味着使用 reshape 函数添加另一个维度。

模型的结构

这些模型使用“relu”或 sigmoid 激活函数以及最终输出的 sigmoid 激活。

对于这些模型,您可以调整卷积层数、内核大小、过滤器数量、学习速率、密集层中的节点数量、LSTM 单元数量、批量大小和池大小。

这里的模型被建立来处理使用多元时间序列数据的分类问题,并使用二元交叉熵作为它们的损失函数。此外,这些模型包括根据其发生率的比例类加权。最后用 Adam 优化对整个网络进行优化。

T-CNN 模型:

两个 CNN 模型的结构遵循相似的格式:

  1. 数据经过一系列一维或二维的卷积层。
  2. 汇集层。合并后,输出被展平并连接到完全连接的图层。
  3. 在完全连接的层之后,产生预测的概率。

LSTM 模式:

  1. 数据通过具有可变数量单元的 LSTM 单元。
  2. 输出被展平并连接到完全连接的图层。
  3. 在完全连接的层之后,产生预测的概率。

结构故意保持相似。因此,很容易只交换 CNN 和 LSTM 模型之间不同的第一层。

超参数和导入

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Flatten, Conv1D, Conv2D, MaxPooling1D, MaxPooling2D
from tensorflow.keras.optimizers import Adam, schedules, SGDKERNEL_SIZE = 2
POOL_SIZE = 2
N_FILTERS = 24
BATCH_SIZE = 128
LEARNING_RATE = 0.00001
DENSE_UNITS = 50
LSTM_UNITS = 50
EPOCHS = 100N_STEPS = X.shape[1]
N_FEATURES = X.shape[2]
class_weight = {0: 1., 1: 1/np.mean(y_train)}ACTIVATION_FUNC = ‘relu’
FINAL_ACTIVATION = ‘sigmoid’LOSS_FUNC = ‘binary_crossentropy’
METRIC = ‘accuracy’
OPTIMIZER = Adam(learning_rate=LEARNING_RATE)# Split you own data from X_3D or X_4D, and a target
X_train, y_train, X_val, y_val = None
X_test, y_test = None

这里有几件事需要注意。我认为数据的第一个维度是实例的数量,第二个维度是时间步长的数量,第三个维度是特征的数量。对于 2D 卷积模型的四维数据,第四维是“虚拟”维度,以便进行适当的处理。然而,其余的维度保持相同的解释。

根据您为这些 Keras 型号使用的后端,了解订购很重要。不幸的是,约定并不一致,这可能是您错误的来源。如果是这种情况,请考虑调整数据的形状,以更改维度的顺序。

我还特意将训练、校准和测试数据设置为“无”,以便您可以根据自己的喜好调整数据分割。在拟合期间,校准集用于评估模型。

关于如何为不同类型的问题和训练模型分离数据的更多细节,你可以阅读这篇文章:

长短期记忆模型

长短期记忆模型(LSTM)是递归神经网络(RNN)的一种变体。这些模型由多个通道组成,数据可以通过这些通道来维护以前步骤中的信息,以便在将来的步骤中使用。

此处显示的预测模型中使用的 LSTM 单元遵循相同的结构。乍一看,它们看起来很复杂,但通过一些观察可以直观地解释。

穿过 LSTM 单元有两条主要路径;这些大致可以解释为短时记忆和长时记忆。短期是通过单元的底部路径,长期是通过单元的顶部路径。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

LSTM 细胞(作者照片)

对于短期记忆,注意输入是如何被引导到这条路径的。正如人们对短期记忆的预期,模型与新数据 Xt 和上一步的输出相互作用。然后,该数据在单元中有几个可能的路径。

长期记忆是沿着细胞顶部的路径。这条路径有来自先前长期记忆输出的输入。然后通过细胞,基于来自几个不同通道的更新来更新长期记忆。

从短期到长期,LSTM 细胞的不同路径通过所使用的激活函数和中间输出的组合来最清楚地区分。

请务必注意,sigmoid 函数用于某些路径,双曲正切函数用于其他路径。这个选择是有意义的。这里的重要观察结果是,sigmoid 函数的输出为 0 到 1。相比之下,双曲正切函数的输出是-1 比 1。

现在,为什么会有区别呢?

在短期和长期记忆路径之间的第一个通道中,激活是 sigmoid 函数,这意味着输出在 0 和 1 之间。因此,这条路径决定了当前步骤的输入是否对长期记忆更重要。如果这个输出是零,那么这个输出和前一个长期记忆输出之间的最终乘积为 0。另一方面,如果这个输出更接近于 1,那么先前的长期记忆会持续。

第二和第三通道分别使用 sigmoid 和双曲线正切激活。这种组合作为一个两步过程,根据双曲正切函数的-1 到 1 输出来确定当前信息是否相关,以及它的贡献是正还是负。细胞的这一部分基本上回答了这两个问题。然后将当前时间步长对长期记忆的贡献添加到长期记忆中。

最终路径结合了当前时间步长和包含在长期记忆路径中的当前理解。这条通路的输出成为下一个 LSTM 细胞的输出。

LSTM 模型的设置

model = Sequential()model.add(
    LSTM(LSTM_UNITS, activation=ACTIVATION_FUNC, 
         input_shape=(N_STEPS, N_FEATURES) 
))
model.add(Flatten())
model.add(Dense(DENSE_UNITS, activation=ACTIVATION_FUNC))
model.add(Dense(1, activation=FINAL_ACTIVATION))model.compile(
    optimizer=OPTIMIZER,
    loss=LOSS_FUNC,
    metrics=[tf.keras.metrics.AUC(), METRIC]
)

卷积神经网络

卷积网络是深度学习中最复杂的模型之一;它们通常由许多不同的层组成,并且这些层可以有不同的行为。

与具有全连接层的标准神经网络相比,卷积神经网络使用卷积层、汇集层和全连接层。一些先进的模型甚至使用了这些层越来越复杂的变化。

卷积神经网络 CNN 通常与图像和视频机器学习应用相关联,因为它们能够有效地捕捉像素之间的关系,并建立开放的这些关系以模拟日益复杂的结构。

在其核心,这些网络依靠其卷积层来有效地捕捉邻近像素之间的关系。然而,这种架构不限于多维图像。例如,很容易将时间序列数据转换成与 CNN 一致的格式。

您还可以使用卷积来模拟时间序列中不同步骤之间的交互。与图像相反,一维卷积可以模拟先前和未来时间步骤的行为,以从系列中捕捉复杂的关系。

一些一维卷积非常常见,你可能在不知道的情况下使用过它们。例如,移动平均是一种卷积类型,其中每一步的权重相等。所以,粗略地说,你可以把一维卷积看作不同长度的移动平均。周期中的每个时间步长的权重不同。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

卷积比较(作者供图)

1D 卷积—时间序列 CNN

model = Sequential()
# Add one or more convolutional layers
model.add(Conv1D(filters=N_FILTERS, kernel_size=10, activation=ACTIVATION_FUNC))model.add(MaxPooling1D(pool_size=2))
model.add(Flatten())
model.add(Dense(DENSE_UNITS, activation=ACTIVATION_FUNC))
model.add(Dense(1, activation=FINAL_ACTIVATION))
model.compile(
    optimizer=OPTIMIZER, 
    loss=LOSS_FUNC,
    metrics=[tf.keras.metrics.AUC(), METRIC]
)

当你有多个时间序列时,一维卷积仍然是可能的;但是,使用二维卷积组合不同的序列可以捕获更复杂的关系。

这些高维卷积捕捉不同时间序列之间的关系。

2D 卷积——时间序列 CNN

model = Sequential()
# Add one or more convolutional layers
model.add(Conv2D(
    filters=N_FILTERS,
    padding=”same”,
    kernel_size=(2,2),
    activation=ACTIVATION_FUNC,
    input_shape=(N_STEPS, N_FEATURES, 1)),
)model.add(MaxPooling2D(pool_size=2))
model.add(Flatten())
model.add(Dense(DENSE_UNITS, activation=ACTIVATION_FUNC))
model.add(Dense(1, activation=FINAL_ACTIVATION))model.compile(
    optimizer=OPTIMIZER,
    loss=LOSS_FUNC,
    metrics=[tf.keras.metrics.AUC(), METRIC]
)

拟合模型

为了训练每个模型,您可以使用以下相同的代码块。因为模型被假定为分类器,所以拟合包括类别权重。在大多数情况下,职业并不是完全平衡的,所以这个增加考虑到了这一点。

model.fit(
    X_train, y_train, epochs=EPOCHS,
    verbose=1, class_weight=class_weight,
    batch_size=BATCH_SIZE,
    validation_data=(X_val, y_val),
)

结论

时间序列问题有许多活动部分。然而,许多其他简单得多的模型也可以用于合理程度的性能。

当从多变量时间序列数据中创建分类器(或回归器)时,我还忽略了一些更多涉及时间的部分。两个最重要的是:

  • 当时间步长不一致时会发生什么,以及如何标准化数据和处理差距。
  • 深度学习模型架构如何优化,不是所有的模型都是生而平等的。虽然您可能不需要 100 层的网络,但您仍然可以从一些调整中受益。

然而,使用多元时间序列数据构建模型可能是一项令人愉快的任务。它迫使您不要将所有数据都视为可用于 scikit-learn 模型的表格数据。这些模型非常灵活,可以捕捉复杂的时间相关关系。你应该将它们添加到你现有的车型库中。

如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。

如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。

https://zjwarnes.medium.com/membership

如何对任意 GLM 使用弹性网正则化

原文:https://towardsdatascience.com/how-to-use-elastic-net-regularization-with-any-glm-6eab524bbcc6?source=collection_archive---------11-----------------------

思想和理论

斯坦福研究人员开发的新算法及其在 r。

广义线性模型(GLMs)是使用最广泛的推理建模技术之一。它们的简单性使它们易于解释,因此当向利益相关者传达因果推理时,它们是非常有效的工具。

弹性网正则化是一种广泛使用的正则化方法,是与 GLMs 的逻辑配对-它删除了不重要和高度相关的特征,这些特征会损害准确性和推断性。这两种方法是任何数据科学工具包的有用部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

JESHOOTS.COMUnsplash 上拍照

在 2021 年 3 月之前,GLMs 和弹性网正则化的组合相当复杂。然而,斯坦福大学的研究人员发表了一篇论文,利用循环坐标下降允许有效计算任何链接函数的模型系数,而不仅仅是简单的链接函数。他们还在著名的 R 包 glmnet 中实现了这个模型。

在这篇文章中,我们将讨论 GLMs 的基本原理,弹性网络正则化,并了解这两者如何协同工作。让我们开始吧…

技术 TLDR

在 R 中, glmnet 包现在支持所有的链接函数族。如果您的链接是规范的,将一个字符串传递给family参数。如果没有,则传递一个家族函数。请注意,您可以查看文档以获得受支持的规范函数的列表。

在后端,这个包有两个主要的变化…

  1. **用 OLS 求解器替代最大似然法。**注意,这仅适用于非规范链接函数——规范链接仍使用 OLS 求解。
  2. 用迭代加权最小二乘法(IRLS)求解。需要 IRLS(也称为费希尔评分),因为不保证最大似然是凹的。

好的,我想我明白了。但是这种新方法实际上是如何工作的呢?

让我们慢一点,从 GLM 实际工作方式开始。

什么是广义线性模型(GLM)?

GLM 是一个相当简单的概念,从 20 世纪 70 年代就有了。随着大数据的兴起,它们已经成为开发推理模型的宝贵工具,即,为我们的数据提供统计有效结论的模型。

为什么你会问?

嗯,GLM 的只是带有额外技巧的线性回归:链接函数。链接函数的目的是转换我们的因变量,以便线性模型能够更好地拟合。

让我们看一个简单的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:使用日志链接功能的 OLS 对 GLM。图片作者。

在图 1 的顶部,我们有一条由 GLM 拟合的指数曲线,没有连接函数。是的,这只是简单的线性回归。不是很合适,对吧?

因为我们知道数据大致遵循指数分布,所以我们使用带有对数链接函数的 GLM,并观察到更好的拟合(下图)。

从推理的角度来看,使用 GLM 拟合数据的主要好处是我们可以像线性回归一样解释系数。因此,在我们的例子中,X 的一个单位的变化导致 y自然对数的 1.007 的变化。如果您想更进一步,查看给定的 xy 的原始单位,我们可以取对数的倒数 exp(1.007 * x) ,以获得 x 的任意值的拟合 y

很有用吧?

现在,GLM 链接函数的选择取决于因变量的结构。在上面的例子中,我们的数据是连续的,看起来是指数型的,所以我们使用了对数分布。如果是整数数据,我们会使用泊松分布。如果它是连续的并且大致呈正态分布,我们将使用高斯(又名正态)分布。个人最喜欢的是 Tweedie 分布,它本质上是一种泊松分布,允许许多 0 值。

什么是弹性网正规化?

现在我们已经了解了 GLM 的,让我们看看这篇文章的主人公,弹性网正规化。

任何类型的正则化的目的是去除无用预测值的影响。此外,弹性网络正则化也不例外— 它移除了高度相关且不会提高我们模型准确性的预测因子。

因此,让我们假设我们正在寻找一个 GLM 来模拟股票价格(顺便说一下,这可能不是一个好主意)。我们的因变量是能源行业 ETFXLE的价格。我们的独立预测变量是:

  • 星期几
  • 前一天 XLE 的价格
  • 前两天 XLE 的价格
  • 前两天你衬衫的颜色

如果你用这些预测值来拟合价格,我们会认为一周中的天,昨天的 XLE 价格,两天前的 XLE 价格会高度预测今天的价格。遗憾的是,你的衬衫颜色对价格没有影响,因此弹性网会将我们的系数缩小到 0。

但是,我们有一个问题。如果我们观察昨天和两天前的价格之间的相关性,我们会注意到高共线性。共线性会阻止模型收敛并降低我们系数的可解释性,因此 elasitc net 发现了这一点,并降低了两天前的价格的系数。

第一种方法是通过将系数缩小到零来去除不重要的系数,这种方法称为拉索(或 L1)正则化。第二种方法是减少与其他预测因子相关的预测因子的系数大小,称为岭回归(或 L2 正则化)。

这两个组件协同工作被称为弹性净回归。

弹性网正则化的数学

随着一些直觉的发展,让我们看看 OLS 线性回归的弹性网的数学定义。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2:弹性网正则化公式。图片作者。

在图 2 中,我们可以看到,我们正在寻找能够最大限度降低方括号中值的模型系数。左边是 OLS 项,它计算误差平方和。在右边,我们有我们的弹性网正则化项。让我们快速定义一下这些变量…

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

稍微研究一下这个方程后,我们会注意到α是一个非常重要的参数。实际上,我们只允许 alpha 取 0 到 1 之间的值。因此,如果α= 0,L1 项抵消,我们最终得到岭回归。相反,如果α= 1,L2 项抵消,我们得到套索。

通常,我们希望获得岭和套索的好处,因此α-大约 0.5 既可以将系数缩小到零,又可以利用岭回归的系数缩减能力。

很酷,对吧?

最后一点:lambda 不是用户指定的参数。相反,用户指定一个 lambdas 范围,而弹性网试图确定最佳的一个。这里,lambda 完全控制偏差-方差权衡。如果 lambda 很大,我们会进行更多的正则化,从而创建一个低偏差/高方差模型。如果 lambda 为 0,我们将减少正则化并专注于准确性,从而创建高偏差/低方差模型。

这就是你要的——简而言之,弹性网络正则化。

为什么弹性网对所有的链接功能都不起作用?

正如您可能想象的那样,能够将弹性网络正则化应用于许多不同类型的链接函数是非常有用的。然而,直到最近,还有一些复杂的解决方法来让弹性网络与某些链接功能一起工作。但是斯坦福大学的研究人员取得了突破,他们一直在 R(编程语言)中率先使用 GLMs,他们开发了一种新方法,允许弹性网络为所有链接函数工作。

简而言之,OLS 最小化适用于规范的链接函数。在这种情况下,锥形意味着链接函数具有某些保证其形状为凹形的性质(想想抛物线,如 x )。其他更复杂的链接函数不一定有常数二阶导数,因此它们的形状可能会不规则,这使得找到全局最小值更加困难。

解决方案

新方法巧妙地避开了 OLS,而是利用了最大似然估计(MLE),这是另一种流行的拟合标准。最大似然法的缺点是它需要一个分步求解器——我们必须迭代地测试值,直到我们达到一个足够最优的解。最重要的是,MLE 并不总是保证全局最小值,所以从技术上讲,我们可能会错过一组更好的系数。

但是,在实践中,MLE 产生了稳健的结果。

R 中的解

如前所述,研究人员致力于提高 R 处理所有类型链接函数的能力。著名的 glmnet 包已经更新,支持规范和非规范链接函数。

但是,你怎么知道你的链接函数是否规范呢?

好吧,如果你的链接函数是*高斯,二项式,泊松,多项式,考克斯,或者高斯,*它是正则的。现在这不是一个完整的列表,但是这些是目前由 glmnet 支持的规范链接。

**在编码方面,如果你的函数在那个列表中,你可以把链接函数族作为一个字符串传递。如果不是,你需要传递一个家族函数。**参见下面的例子:

library(glmnet)# canonical exmaple - pass gaussian string
fit <- glm(y ~ x, family = **"gaussian"**)# non-canonical exmaple - pass quasi-poisson function
fit <- glm(y ~ x, family = **quasipoisson()**)

有了这次更新,我们现在可以选择任何最能代表我们数据的分布,不管它有多复杂。如果我们觉得有创意,我们甚至可以创造一些新的链接功能。

但是这个解决方案实际上是如何工作的呢?

新的优化算法使用了一种叫做循环坐标下降的方法。与基于梯度的优化不同,基于梯度的优化通过模型的导数(如随机梯度下降)来计算“山”,坐标下降使用原始数据。从那里,它沿着这些坐标移动,寻找全局最小值。

概念化这两者之间的区别的一个方法是通过思考旧金山这个城市。它有许多山丘,代表我们的特征空间。山的高度是我们的模型拟合的估计值,纬度和经度是正在优化的两个特征。

循环坐标下降使用旧金山的道路来寻找最低点,其中每条道路代表我们变量的不同组合。另一方面,梯度下降完全忽略了道路,只是以最陡的坡度下山。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:循环坐标下降与随机梯度下降。图片作者。

循环坐标下降的好处是你不需要根据模型的导数计算一个完整的梯度,这对于某些链接函数是不可能的。

为了完整起见,我们将在这里讨论优化算法。这将是技术性的,所以请随意跳到实现说明和注释。

本文中标记为算法 1 的主要算法如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里面有很多,但是让我们快速总结一下。在初始化了一组可能的λ值后,我们遍历每个值,并尝试最小化该值的损失,搜索最佳的λ值。然而,因为我们使用最大似然法而不是 OLS,我们需要使用循环坐标下降法。然后,我们希望在最后一步中最小化加权最小二乘(WLS)表达式,这涉及到另一个类似的算法。

我发现只盯着算法是有帮助的,但是如果你对细节感兴趣,可以看看论文的第 2.3 节。

实施说明

  • 当运行弹性网正则化时,通常我们要同时使用套索和脊。所以,最好尝试不同的α值,看看保留了哪些变量。如果你想要优化,使用交叉验证来找到 alpha 的最佳值是一个好主意。
  • 选择一个好的连接函数对于模型的准确性和稳定性至关重要。
  • 选择更“高级”的链接功能可以节省时间。一个例子是使用特威迪分布而不是零膨胀泊松分布——如果我知道特威迪分布,我可以在论文上节省很多时间。
  • 通常最好将预测值标准化,这样它们的范围就不会影响您的变量选择。z 分数也非常容易解释,如果需要,可以转换回原始单位。
  • R 中的 glmnet 包为 GLMs 的易用性铺平了道路。大多数其他语言落后于这个包几个发布版本,但是希望很快会有一个支持所有链接功能的 python 库。

感谢阅读!我将再写 44 篇文章,将“学术”研究引入 DS 行业。查看我关于使用 GLMs 进行推理建模的链接/想法的评论。

如何使用 fastai 评估 DICOM 医学文件

原文:https://towardsdatascience.com/how-to-use-fastai-to-evaluate-dicom-medical-files-738d7f7bc14d?source=collection_archive---------25-----------------------

开始 Kaggle 医学竞赛

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

机器学习意味着你可以像放射科医生一样*看东西——*📸疾控

Kaggle 竞赛可能会非常激烈,仅仅获得领域知识就需要做大量的前期工作。

我有相当多使用 fastai 的经验,现在,这并不意味着我总是在最后的比赛中使用它,但它是一个快速原型化和学习数据集的伟大工具。

本文将向您展示一些有用的技巧,帮助您快速了解 DICOM 医学文件及其相关数据。这篇文章不会包含所有的代码,这些代码在 Kaggle 上与大家分享。所以我会在这里添加一些片段,但会把你指向 Kaggle 上的完整笔记本。还用了惊艳 fastai 医学影像教程学习

你可能会问自己的第一个问题(或者如果你在谷歌搜索“fastai dicom 文件”就不会问):什么是 dicom 文件?

什么是 DICOMs?

DICOM 代表(DIImaging 和COcommunications inMedicine)并且是事实上的标准,其建立了允许医学图像(X 射线、MRI、CT)和相关信息在来自不同供应商、计算机和医院的成像设备之间交换的规则。DICOM 格式提供了一种合适的方法,该方法符合医疗信息交换(HIE)标准和 HL7 标准,HIE 标准用于在医疗机构之间传输与健康相关的数据,HL7 标准是使临床应用能够交换数据的消息标准

DICOM 通常与一个.dcm扩展名相关联。DICOM 文件真正令人惊奇的地方在于,它们提供了一种以单独的“标签”存储数据的方式,例如患者信息以及图像/像素数据。DICOM 文件由打包成一个文件的标题和图像数据集组成。

这是我们了解 fastai 如何让您快速查看存储在.dcm文件中的信息的好机会。如果你习惯使用 fastai,你会熟悉一些导入,但是要注意医疗导入。这对处理 DICOM 文件很重要。

from fastai.basics import *****
from fastai.callback.all import *****
from fastai.vision.all import *****
from fastai.medical.imaging import *****

import pydicom

import pandas **as** pd

我使用的数据集在 Kaggle 上: VinBigData 胸部 x 光异常检测。这是一场有趣的比赛;你可以阅读 Kaggle 上的信息了解更多。作为一个简单的教程,您将在下面看到我访问该文件的代码。该结构非常简单,有一个父文件夹“vinbigdata-胸部-x 射线-异常-检测”,以及包含 DICOM 图像的训练路径:

path = Path('../input/vinbigdata-chest-xray-abnormalities-detection')
train_imgs = path/'train'

接下来,您可以设置您的图像,以便可以阅读。

items = get_dicom_files(train_imgs)

Pydicom 是一个 python 包,用于解析 dicom 文件,使访问 DICOM 文件头以及将原始 pixel_data 转换为 python 结构变得更加容易。fastai.medical.imaging 使用 pydicom.dcmread 加载 dicom 文件。

要绘制 X 射线,我们可以在项目列表中选择一个条目,并用 dcmread 加载 DICOM 文件。在这里,我们可以编写一行简单的代码来查看与 dcm 文件相关的有趣的、有潜在价值的数据。

#add any number here to pick one single patient 
patient = 3xray_sample = items[patient].dcmread()

现在我们可以在 dicom 文件中查看标题元数据。

xray_sampleOutput:Dataset.file_meta -------------------------------
(0002, 0000) File Meta Information Group Length  UL: 160
(0002, 0001) File Meta Information Version       OB: b'\x00\x01'
(0002, 0002) Media Storage SOP Class UID         UI: Digital X-Ray Image Storage - For Presentation
(0002, 0003) Media Storage SOP Instance UID      UI: 7ecd6f67f649f26c05805c8359f9e528
(0002, 0010) Transfer Syntax UID                 UI: JPEG 2000 Image Compression (Lossless Only)
(0002, 0012) Implementation Class UID            UI: 1.2.3.4
(0002, 0013) Implementation Version Name         SH: 'OFFIS_DCMTK_360'
-------------------------------------------------
(0010, 0040) Patient's Sex                       CS: 'M'
(0010, 1010) Patient's Age                       AS: '061Y'
(0028, 0002) Samples per Pixel                   US: 1
(0028, 0004) Photometric Interpretation          CS: 'MONOCHROME2'
(0028, 0010) Rows                                US: 2952
(0028, 0011) Columns                             US: 2744
(0028, 0030) Pixel Spacing                       DS: [0.127, 0.127]
(0028, 0100) Bits Allocated                      US: 16
(0028, 0101) Bits Stored                         US: 14
(0028, 0102) High Bit                            US: 13
(0028, 0103) Pixel Representation                US: 0
(0028, 1050) Window Center                       DS: "8190.0"
(0028, 1051) Window Width                        DS: "7259.0"
(0028, 1052) Rescale Intercept                   DS: "0.0"
(0028, 1053) Rescale Slope                       DS: "1.0"
(0028, 2110) Lossy Image Compression             CS: '00'
(0028, 2112) Lossy Image Compression Ratio       DS: "2.0"
(7fe0, 0010) Pixel Data                          OB: Array of 5827210 elements

这里有很多信息,好消息是有一个很好的资源可以了解更多信息:

http://DICOM . NEMA . org/medical/DICOM/current/output/chtml/part 03/Sect _ c . 7 . 6 . 3 . html # Sect _ c . 7 . 6 . 3 . 1 . 4

最后,你可以看到一张真正的 x 光片。

xray_sample.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

还记得上面那些看起来很有趣的元数据吗?你可能想知道如何让它变得有用?好消息是,你可以把这些数据放到一个数据框架中。

作为一个小提示。我将在下面添加两个版本的代码。一个用于 Google Colab 和点击链接查看更复杂的 Kaggle 版本。任何使用过 Kaggle 的人都知道,有时候你必须做一些改变才能让事情正常进行。

以下是将元数据放入数据帧的简单方法:

dicom_dataframe = pd.DataFrame.from_dicoms(items)dicom_dataframe[:5]

我将在下面添加一个截图,因为数据是 29 列,将离开页面。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

希望这能对你们中的一些人有所帮助。接下来,我将设置边界框来检测 x 射线中的各种疾病。

如果有人在 fastai 和/或医学数据方面做了什么了不起的事情,我想听听!请在下面的回复中让每个人都知道你创造了什么,或者随时在 LinkedIn 上联系。

如何用第一性原理思维解决数据科学问题?

原文:https://towardsdatascience.com/how-to-use-first-principle-thinking-to-solve-data-science-problems-db94bc5af21?source=collection_archive---------11-----------------------

埃隆·马斯克解决问题的方式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

莫尔·蒂亚姆在 Unsplash 上的照片

大约 2000 年前,亚里斯多德将*【第一原理】定义为【认识事物的第一基础】*。这个概念仍然非常相关,可以帮助您为复杂的数据科学问题提出创新的解决方案。第一原理思维背后的思想是将一个复杂的问题分解成它的基本部分,然后使用自下而上的方法来构建一个以前没有概念化的独特解决方案。

在本文中,我将向您解释如何应用第一原理思维来解决数据科学问题。为了简单明了,让我们考虑一下*“客户流失问题”*。为了帮助你理解第一原理思维的好处,我将首先展示如何使用传统方法解决这个问题,然后使用第一原理思维方法。

问题陈述:零售能源领域的客户流失

让我们假设“XYZ”是一家试图解决客户流失问题的零售能源公司。每年大约有 10%的客户流失,“XYZ”公司正在寻找减少客户流失的方法。

传统方法

解决问题的传统方法或最常用的方法是主观思维。也就是说,我们大多受已有假设或观点的影响。这种方法涉及的一般步骤是,

  1. 从现有的假设开始
  2. 根据假设确定需要逐步改进的领域
  3. 探索选项并选择最佳解决方案

现在,让我们考虑一下能源零售行业的客户流失情况,看看如何使用传统方法解决这个问题。如前所述,传统方法的第一步是从假设开始,

假设:

  • 与客户代理的糟糕经历会导致客户流失
  • 可以通过折扣/优惠来防止流失

基于上述假设,我们现在提出了可以帮助我们解决问题的解决方案。

  • 向不满意的客户提供折扣—我们可以通过检查投诉登记簿来识别不满意的客户
  • 专注于获得更多客户
  • 确定导致最多投诉的投诉类别,并使用表现最佳的代理来处理这些问题——这有助于避免给客户带来不好的体验
  • 确定高能耗消费者,并主动向他们提供折扣

以上是一些基于假设的解决方案。这里的优点是,

  • 这里确定的解决方案易于实现,不需要太多的努力。
  • 增量改进可以很快实现

但另一方面,缺点是,

  • 客户流失的主要原因没有得到解决
  • 无法作为长期战略持续下去

第一原理思维方法

现在,我将向您展示如何通过使用第一原理方法来解决客户流失问题。这种方法背后的主要思想是花尽可能多的时间去理解问题,然后试图解决它。就像爱因斯坦说的,

“如果我有一个小时来解决一个问题,我会花 55 分钟思考问题,花 5 分钟思考解决方案。”——阿尔伯特·爱因斯坦

理解问题

更好地理解问题的一个最好方法是尽可能多地提问。不要认为任何假设都是理所当然的。一直问问题,直到没有进一步的问题!

有助于更好地理解问题的一些问题是,

  • 每月有多少客户流失?
  • 客户流失的行业平均水平是多少?
  • 你的客户是什么样的?
  • 搅动的客户是什么样的?
  • 不同配置文件给客户带来的收入/利润是多少?
  • 客户流失的原因都是什么?
  • 客户什么时候会流失?有什么趋势吗?

所有这些问题有助于更好地理解问题,量化问题,也有助于确定当前的重点领域。如果你试图解决一个不同的问题,试着用下面的问题来理解它,

  • 有什么问题?
  • 问题有多大?(可以用美元或受影响的客户来量化)
  • 为什么会发生?
  • 谁面临这个问题?
  • 它什么时候发生?

将它分解

一旦对问题有了很好的理解,下一步就是开始分解问题。对于客户流失这个问题,我们先根据客户流失的原因来分解一下。这有助于区分可解段和不可解段。假设客户流失可以分为以下几类:

  1. 客户离开了我们不提供能源零售商服务的国家/州?
  2. 因业务关闭而流失
  3. 前 3 个月内的流失
  4. 成为常客超过 3 个月,然后流失的客户

以上原因,很少是可解的,其他都是不可解的。第 1 类和第 2 类是无法解决的,因为在第一类中,客户正在转移到能源零售商不提供服务的地方,而在第二类中,客户由于他们的业务关闭而搅动,从能源零售商的角度来看,没有什么可以做的。

第三类是客户在 3 个月内流失,这是一个问题,但这应被视为入职问题,而不是流失问题。由于这些客户没有花足够的时间来正式成为客户,他们几乎没有花任何时间。

所以,现在我们只剩下第四类了。这一类别的客户可以进一步划分成组,

  • 根据客户的终身价值、在平台上的年龄等将客户进一步细分。

这种细分实际上有助于识别需要立即关注的细分市场和可以忽略的细分市场。继续细分类别,直到单个组/类别变得更小

数据怎么说?

根据上述细分,确定需要立即关注的细分市场/类别。对于所有这些客户,探索他们跨不同业务部门的数据。就像在我们的客户流失问题中,需要做的分析是,

  • 客户的能源使用模式是怎样的?
  • 这些顾客抱怨过吗?解决这些投诉需要多长时间?谁处理这些投诉?
  • 最近 2 个月内是否与客户有过互动?
  • 是否有客户的能源账单出现峰值?
  • 这些客户中有谁收到过营销信息吗?

使用自下而上的方法求解

根据上述数据分析,找出导致客户流失的前 10-15 个场景。深入研究这些已确定的场景,假设我们有这样一个场景,客户就账单问题联系支持中心时,大多数情况下都是不了了之。我们需要确切了解导致这些客户流失的原因。原因可能是,

  • 这些类别的合规性需要更长的时间来解决?为什么它们需要更长的时间来解决?
  • 修改账单所需的时间要长得多。为什么他们需要更多的时间?

像上面一样,问尽可能多的问题,直到没有进一步的问题。这样,问题就一清二楚了,因此可以主动解决。

是什么阻止了许多数据科学家使用第一原理思维?

而我们可以清楚地看到,第一原理思维才是解决问题的方法。但是为什么数据科学家不在他们解决的所有用例中使用它们呢?

原因是时间。是的,“时间”是一项非常重要的资源,数据科学团队通常会处理具有不同重要程度的多项任务,因此可能会有一些问题不值得使用绝对没问题的第一原理思维方法来解决。

但是,当有一个对业务有更大影响的业务问题时,最好使用第一原则思维方法来解决,而不是采用增量增强。

结束语

有许多数据科学项目时不时会失败。虽然技术挑战仍然是许多失败的关键因素,但也有失败是由于缺乏对业务问题的理解。没有很好地理解问题的首要原因是因为组织试图关注太多的问题,并且经常面临过快交付结果的压力。在这个视频中,我分享了一些使用第一原理思维解决数据科学问题的技巧

保持联系

如何在报告中使用 GETDATE()

原文:https://towardsdatascience.com/how-to-use-getdate-for-reports-d8cdc504a261?source=collection_archive---------33-----------------------

不再需要手动调节!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Manavita S via Unsplash 拍摄

只需复制并粘贴这个查询,转到 WHERE 子句,将其更改为上周,然后运行它。这很简单!”—一些你可能认识的人

每天/每周/每月手动更改查询中的值可能会非常痛苦。这也为人为错误打开了大门。我们将回顾 SQL 的 GETDATE()函数的强大功能,如何将它包含在查询中(例如,也许您有一个总是上周数据的报告),以及非常重要的是,如何避免日期/周范围的一些问题。

这东西到底有什么用?

和所有工具一样,理解一个函数的作用是非常有帮助的。今天的日期是 2021 年 8 月 27 日。让我们看看运行一个 GETDATE 会给我们带来什么(格式为’ yyyy-MM-dd '):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者照片

它会得到执行的日期。当你在《第六感》中发现布鲁斯·威利斯一直都死了的时候,你可能不会有那种惊天动地的震惊……但也很接近了。

自动化上周的报告

因此,假设您每周一都有需要提取的数据。该报告只包括前一周的数据。不包括上周或部分当前周之前的周。

为此,你需要一些日历表。在其中,理想情况下,您将拥有一个一年一周的组合列。请在年和周之间包含某种分隔符。如果你的公司还没有这个,我假设你正在你自己的电脑/手机上阅读这篇文章,因为你的公司可能还没有电脑。

现在,很明显,查看今天的日期不会给出我们所说的上周的信息。让我们来看一个表格,其中包含本周和上周的“日历日期”和“年份周”列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者照片

GETDATE() — 7?

您可能习惯于使用 DATEADD 函数,其中一个参数是数字,另一个参数是间隔类型(年、日等)。).当使用 GETDATE 时,你可以简单地说“-7”来获得一周前的日期。现在让我们看看当我们从“calendar_table”中选择 GETDATE()和 GETDATE( ) — 7 时会得到什么。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者照片

假设我们在星期一运行它。在本例中,我们可以选择 2021–08–16 作为上周的星期一,并提取“year_week”等于“calendar_table”中的值的所有数据,在本例中也是“2021–33”。如果我们在周日运行,上周周日的“year_week”将是我们要使用的变量,仍然是“2021–33”。周六也可以。你明白了。事情正在好转。

我们在赚钱,恰恰,恰,恰。我们在赚钱,恰恰,恰,恰。我们在赚钱,恰恰,恰,恰。恰恰,恰,恰,恰,恰,恰,恰,正!—帕梅拉·普金

齐心协力

有多种方法可以做到这一点。我们可以使用子查询来选择“year_week ”,并将该子查询放在 WHERE 子句中。我们可以将需要的日期内联。我们甚至可以创建一个变量来存放这个值。

对于这个例子,我推荐使用变量 route,因为当您开始进入更多的临时表、CTE 或子查询以引入多个表时,命名一个变量并将其包含在每个表的 WHERE 子句中可以节省时间。从长远来看,它还减少了代码行数。

现在我们有了“daily_sales”表,我们只想提取上周的行。下面是结果,后面是代码,最后是使用“year_flag”列的有用信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者照片

注意,例如,如果我们想要包含一个滚动的 6 周期间,我们可以创建两个变量。另一个变量可以设置为 GETDATE 之前的不同天数。然后,我们可以在两个“year_week”值之间提取行。

为什么前导零很重要?

当创建这个“year_week”列时,非常需要使用一个前导 0 来表示一位数的周。本质上,这些值将像字母一样被读取,0 =A,1 = B,等等。按字母顺序思考这个问题,我们可以看到如果没有前导 0,拉取和排序结果会是什么样子。在本例中,我们提取了“2021–1”和“2021–3”之间的值。

请注意,第 10 周、第 105 周(只是为了展示)、第 11 周和第 12 周都包括在内。在我们的“日历表”中,我们只有第 1–12 周(加上 105 周)。不包括 13 周以上。如果是这样的话,10 到 29 之间的所有星期都会出现。第 30 周不会出现,因为那是 D 后面的 DA。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者照片

在本例中,我们可以看到,如果我们按“year_week”或“year_week_alpha”排序,我们会得到相同的结果。

天空是无限的!

我们不仅限于按天或按周划分范围。我们可以发挥创意,使用季度或年度。我们可以设置像年初至今这样的事情。

我们甚至可以使用一些规则,比如“总是在输出中包括至少 10 周(如果需要的话,返回到上一年),但是在新的一年的第 10 周之后,然后包括本年度的所有周并删除去年的周”。当新的一年开始,人们不希望在 Power BI 报告中看到可视化的一周的数据时,类似这样的东西会很有帮助。

关于连接和联合的更多信息,请查看这篇更详细的文章。一如既往,有趣的可视化和超级爸爸笑话包括在内。

最后的想法

SQL 是一个强大的工具,它让生活变得更加简单。如果使用得当,它可以节省大量时间。当使用常规查询时,GETDATE()函数是一个包裹在温暖的小狗模糊闪光云中的祝福。

这是我们今天的课。一如既往,继续学习!

如何在 SQL 中使用 Group By 和 Partition By

原文:https://towardsdatascience.com/how-to-use-group-by-and-partition-by-in-sql-f3d241846e3e?source=collection_archive---------3-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

简介

当我第一次学习 SQL 时,我有一个问题,就是如何区分通过划分的和通过分组的**,因为它们都有一个用于分组的函数。相信很多开始接触 SQL 的人可能都会遇到同样的问题。因此,在这篇文章中我想和你分享一些使用 PARTITION BY 的例子,以及它和 GROUP BY 在 select 语句中的区别。**

探测

抽样资料

首先,我创建了一个包含 4 列的简单数据集。下面的 df 表格描述了不同职能部门的每位员工在公司旅行中会携带的金额和水果种类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1: 测向表

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2:测向信息

分区由 vs 组由

下面是 Partition By: 的语法

SELECT expression 1, expression 2, ...
aggregate function () 
OVER (PARTITION BY expression 1 order_clause frame_clause)
FROM table

当我们想要在特定的列上进行聚合时,我们可以应用带有 OVER 子句的 PARTITION BY 子句。让我们看看下面的例子,看看数据集是如何转换的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 Partition By 子句的输出

在示例中,我想计算每个函数为旅行带来的总收入和平均收入。截图中可以看到的是我通过查询分区的结果。

现在,如果我在上面的例子中使用 GROUP BY 而不是 PARTITION BY ,结果会是什么样子?

首先, GROUP BY 的语法可以写成:

SELECT expression 1, expression 2
aggregate function ()
FROM tables
WHERE conditions
GROUP BY expression 1, expression 2

当我将它应用到查询中以查找每个函数中的总金额和平均金额时,聚合输出类似于由子句划分的分区。然而,正如您所注意到的,图 3 的和图 4 的结果有所不同。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 Group By 子句的输出

  • GROUP BY 给出公司中每个职能的结果*(图 4)。同时,由于我们在 df 表中有 7 条记录,PARTITION BY 检索所有 7 行,每行有 total_amount 和 average _ amount(图 3)。*因此,总之, PARTITION BY 检索表中的所有记录,而 GROUP BY 只返回有限的数量。
  • 还有一点就是 GROUP BY 不允许在 select 语句中添加不属于 GROUP BY 子句的列。但是,使用分区 BY 子句,我们可以添加所需的列。

按行号进行分区

我们可以通过和行号组合分区,使行号按特定值排序。例如,如果我想看看每个函数中的哪个人带来的钱最多,我可以很容易地通过将 ROW_NUMBER 函数应用于每个团队,并获得每个人的钱数(按降序排列)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5:行号函数示例

用累积值进行分区

分区由+行无界前置

为了更容易想象,我将从一个例子开始解释这一部分的思想。

我创建了一个新表*,命名为* df8

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6:新数据帧(df8)

通过应用 ROW_NUMBER ,我得到了按每个函数中每个雇员的金额排序的行号值。基本上直到这一步,在图 7 中可以看到,一切都和上面的例子差不多。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 7:输出

但是,由于我想再计算一列,这是当前行的平均金额和分区中当前行之前的较高值金额。例如在图 8 中,我们可以看到:

  • 在技术团队中,仅萨姆一人就有平均 40 万的累积金额。
  • 但是,在技术小组的第 2 行,平均累计金额是 340050,等于(Hoang 的金额+ Sam 的金额)的平均值。
  • 在第 3 行中,Dung 的钱数低于 Hoang 和 Sam,所以他的平均累计金额是(Hoang、Sam 和 Dung 的金额)的平均值

= >这是关于 ROWS UNBOUNDED PRECEDING 和 PARTITION BY 子句如何一起使用的一般概念。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 8:使用前面无界的行的累积平均量

当前行和 1 之间按+行划分

这种组合的用途是计算分区中当前行和下一行的聚合值(平均值、总和等)。让我们继续使用***【df9】***数据来看看这是如何实现的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9:当前行和 1 个 之间使用 行的累计平均金额

图 9 中,我们可以得出:

  • 在技术功能第 1 行中,Sam 的平均累计金额为 340050,等于她和她在第 2 行中的跟随者(Hoang)的平均金额。
  • 然后,Hoang 的平均累积量是第 3 行中 Hoang 的量和 Dung 的量的平均值。

结论

在本文中,我提供了我对由划分分区和由划分组的理解,以及使用分区的一些不同情况。希望以上信息对你有所帮助。****

参考

https://www.sqlshack.com/sql-partition-by-clause-overview/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值