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

龙哥盟 / 2024-10-22 / 原文

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

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

将 Dockerized Python 应用部署到 Azure 的简单指南

原文:https://towardsdatascience.com/a-simple-guide-to-deploying-a-dockerized-python-app-to-azure-29753ee507eb?source=collection_archive---------10-----------------------

以下是如何使用 Docker、Azure 容器注册中心和 Azure 容器实例在 Azure 上部署令人惊叹的应用程序

詹姆斯·哈里逊在 Unsplash 上拍摄的照片

你是说你已经开发了一个应用程序,现在你想把它发布给所有人看?不要再看了。下面是如何使用 Docker、Azure 容器注册中心和 Azure 容器实例在 Azure 上部署它。

本指南使用 FastAPI 应用程序作为示例应用程序,并假设您熟悉使用终端、构建 Python 应用程序和基本 Docker 命令的基础知识。如果你有一个你自己的应用程序,你想把它部署到 Azure 上,你唯一需要做的就是使用一个合适的 Dockerize 文件来 Dockerize 化这个应用程序。

读完这本指南后,你会有什么收获?那么,你将在 Azure 上拥有你的应用的部署版本。很好,对吧?

1.设置你的应用

首先,让我们设置一个可以部署到 Azure 的 FastAPI 应用程序。我将使用一个简单的 Hello World 示例,您可以在这里找到:【https://github.com/bmaelum/fastapi-hello-world

该应用程序在/app 文件夹中包含一个主文件,这是 FastAPI 代码所在的位置。

from fastapi import FastAPI app = FastAPI(
    title="FastAPI - Hello World",    
    description="This is the Hello World of FastAPI.",
    version="1.0.0",) @app.get("/")
def hello_world():    
    return {"Hello": "World"}

要使用 app,首先在你自己的 Github 帐户中创建一个副本。这是使用 Github 动作完成这些步骤所必需的。如果您想使用本指南的示例代码,请转到这个 URL:https://github.com/bmaelum/fastapi-hello-world并单击“fork”按钮。

为了能够测试代码,将 repo 克隆到您的机器上:

git clone [git@github.com](mailto:git@github.com):<your-username>/fastapi-hello-world.git

然后将 requirements.txt 文件中的需求安装到您的环境中:

pip install -r requirements.txt

要运行该应用程序,只需输入:

uvicorn app.main:app

您应该在终端中看到类似这样的内容:

INFO:     Uvicorn running on [http://127.0.0.1:8000](http://127.0.0.1:8000) (Press CTRL+C to quit)

测试应用程序可以在浏览器中完成,也可以使用类似 Postman 的工具。要在您的浏览器中查看应用程序,只需转到终端中打印的 URL,在本例中为: http://127.0.0.1:8000 。

2.是时候归档了

现在,让我们将应用程序归档。

照片由伊恩·泰勒在 Unsplash 上拍摄

使用 Docker 来部署你的应用程序是很棒的,原因有很多,其中之一是它可以帮助你确保你的本地开发和 Azure 上的部署有相同的环境。

确保你有一个合适的 docker 文件。在示例文件中,docker 文件如下所示:

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

2.1 建立码头工人形象

要构建 Docker 映像,只需运行:

docker build -t fastapi-image .

2.2 运行并测试 Docker 映像

要在容器中运行映像,只需运行:

docker run -p 80:80 -it fastapi-image

要测试 app 你可以用和以前一样的地址,只需要把端口改成 80 就可以了,像这样: http://127.0.0.1:80 。

你的应用在本地工作,太好了!现在是时候把它部署到 Azure 了!

3.让我们将应用程序部署到 Azure

准备部署到 Azure 了吗?激动人心!

将应用部署到 Azure 需要我们在 Azure 门户中做一些动作,以及使用 Github 动作。

本指南将遵循微软的官方文档,网址为:https://docs . Microsoft . com/en-us/azure/container-instances/container-instances-github-action

3.1 资源组和服务主体

首先,我们需要在所需的资源组中创建一个服务主体,一个角色。如果您还没有资源组,只需在 Azure 门户的资源组中创建一个即可。

为了创建服务主体,我们在 Azure Cloud Shell 中使用 Bash。通过点击页面顶部的云壳图标打开它:

天蓝色云壳图标

确保它设置为在云壳的左上方猛击:

在 Azure 门户中使用云外壳时的 Bash

然后,通过使用以下命令在 Azure 中为资源组创建一个服务主体,并给角色一个名称,范围是您的资源组的资源 ID。

获取资源组 ID:

groupId=$(az group show \
  --name <resource-group-name> \
  --query id --output tsv)

创建角色:

az ad sp create-for-rbac \
  --name githubactions \
  --scope $groupId \
  --role Contributor \
  --sdk-auth

这将为您提供以下格式的 JSON:

{
  "clientId": "",
  "clientSecret": "",
  "subscriptionId": "",
  "tenantId": "",
  "activeDirectoryEndpointUrl": "[https://login.microsoftonline.com](https://login.microsoftonline.com)",
  "resourceManagerEndpointUrl": "[https://management.azure.com/](https://management.azure.com/)",
  "activeDirectoryGraphResourceId": "[https://graph.windows.net/](https://graph.windows.net/)",
  "sqlManagementEndpointUrl": "[https://management.core.windows.net:8443/](https://management.core.windows.net:8443/)",
  "galleryEndpointUrl": "[https://gallery.azure.com/](https://gallery.azure.com/)",
  "managementEndpointUrl": "[https://management.core.windows.net/](https://management.core.windows.net/)"
}

请务必保存此信息,因为在使用 Github 操作时将使用它进行身份验证。

4.创建容器注册表

要管理 Docker 容器和图像,您需要在 Azure 中创建一个容器注册表。

搜索“容器注册表”,然后选择“创建”。选择您的资源组、实例名称和位置。对于 SKU,您可以选择基本选项。

5.准备好 Github 动作和 Azure 容器实例了吗?

很好,让我们开始设置 Github 操作。

还记得上一步收集的 JSON 吗?现在是时候使用它了。

转到 Github 和包含您的应用程序的存储库。然后进入设置->密码,添加以下凭证(官方文件):

AZURE_CREDENTIALS服务主体创建步骤的整个 JSON 输出

REGISTRY_LOGIN_SERVER您的注册表的登录服务器名称(全部小写)。示例: myregistry.azurecr.io

服务主体创建的 JSON 输出中的REGISTRY_USERNAMEclientId

REGISTRY_PASSWORD来自服务主体创建的 JSON 输出的clientSecret

RESOURCE_GROUP用于确定服务主体范围的资源组的名称

6.在 Github 操作中设置工作流程

现在,让我们使用 Github 操作来设置工作流。首先,在 Github 上打开你的回购,点击“操作”按钮。在那里,选择“跳过这一步,自己设置工作流程”。

Github 操作入门

用以下代码替换 main.yml 文件中的现有代码:

on: [push]
name: PythonAppAzureDeployment
jobs:
    build-and-deploy:
        runs-on: ubuntu-latest
        steps:
        # checkout the repo
        - name: 'Checkout GitHub Action'
          uses: actions/checkout@main

        - name: 'Login via Azure CLI'
          uses: azure/login@v1
          with:
            creds: ${{ secrets.AZURE_CREDENTIALS }}

        - name: 'Build and push image'
          uses: azure/docker-login@v1
          with:
            login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
            username: ${{ secrets.REGISTRY_USERNAME }}
            password: ${{ secrets.REGISTRY_PASSWORD }}
        - run: |
            docker build . -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/sampleapp:${{ github.sha }}
            docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/sampleapp:${{ github.sha }}

        - name: 'Deploy to Azure Container Instances'
          uses: 'azure/aci-deploy@v1'
          with:
            resource-group: ${{ secrets.RESOURCE_GROUP }}
            dns-name-label: ${{ secrets.RESOURCE_GROUP }}${{ github.run_number }}
            image: ${{ secrets.REGISTRY_LOGIN_SERVER }}/sampleapp:${{ github.sha }}
            registry-login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
            registry-username: ${{ secrets.REGISTRY_USERNAME }}
            registry-password: ${{ secrets.REGISTRY_PASSWORD }}
            name: fastapi-sampleapp
            location: 'west europe'

然后,提交文件,因为我们已经指定了“on: push ”,它将立即运行。如果它不能确保代码已被提交并推送到回购。

现在,等待构建和部署代码。您可以通过单击“Actions”并选择正在运行的管道来跟踪进度。

如果出现错误:

Error: The subscription is not registered to use namespace ‘Microsoft.ContainerInstance’.

只需在 PowerShell 中执行以下操作:

Register-AzResourceProvider -ProviderNamespace Microsoft.ContainerInstance

或者,在 Azure 中,您可以转到“订阅”,选择您的订阅,转到资源提供商,搜索“ContainerInstance”,单击所需的结果,然后单击“注册”。

7.Azure 容器实例

当你进入 Azure 门户中的容器实例时,你的 Dockerized 应用现在应该是可见的。

Azure 容器实例

测试应用程序

要测试应用程序,请单击新部署的容器实例,然后转到 Properties。在 FQDN 下面有一个网址。将 URL 粘贴到您的浏览器中,您应该会看到类似这样的内容:

在浏览器中测试部署的应用程序

恭喜你,你现在已经在 Azure 上部署了一个 Dockerized app!

布鲁斯·马尔斯在 Unsplash 上的照片

提高查询调度技能的简单指南

原文:https://towardsdatascience.com/a-simple-guide-to-improve-your-skills-in-scheduling-queries-40df2aea1f24?source=collection_archive---------25-----------------------

创建计划查询时可以遵循的一些基本原则和策略。

由 Djim Loic 在 Unsplash 上拍摄的照片

在我作为数据专家的日常工作中,查询是您将面临的最常见的任务之一。当您重复使用这些查询来生成报告、仪表板甚至培训数据时,我们将需要高效地调度和管理它们。

我想分享一些原则和策略,您可以使用这些原则和策略根据您的具体情况创建一个计划查询。如果您是数据分析师或数据科学家的新手,我希望这些知识会派上用场。

要遵循的一些原则

在我的日常活动中,我发现这些原则在执行和管理我的预定查询时帮助很大。它不会在一夜之间到来,你必须一点一点地开始做,并让自己适应它。

声明你的变量/参数

它可以是开始和结束日期或时间戳、过滤器中使用的特定变量等。这是一个很好的实践,因为您可以根据自己的需要快速更改它。

此外,当您从多个表中进行查询时,日期筛选器可能会在多个子查询中使用,这种方法使您只需更改参数,而不必更改子查询的 ALL 中的 WHERE 子句

要在查询中使用的开始和结束日期变量/参数声明

首先处理数据的小子集

首先使用一小部分数据组成查询(如果可能的话)。您可以首先使用过去 1 天或过去 7 天的数据,然后基于这些数据创建一个完全运行的计划查询(根据第一条原则,您可能只需更改参数😃).

使用分区!

最常见的是按日期分区。此外,我发现使用 date local 作为您的分区(在您的调度查询中)非常有帮助。因为您的报告经常需要您根据当地时间中的某个时间段进行过滤,这可以节省您运行查询的时间和成本。

要了解表中分区的更多信息,您可以访问此链接:https://www . SQL shack . com/database-table-partitioning-SQL-server/

避免使用从另一个预定查询创建的表

如果可能的话,总是使用主表作为 SQL 查询的源。它可以是直接从事务数据库、数据仓库、数据集市提取的表,或者是您和其他人都认为这些表是您所需数据的主要来源的任何类型的表。

如果您使用另一个计划查询中的表并一直这样做,您可能会失去对更改和执行时间的跟踪,如果一些计划失败并导致您的仪表板停止工作,情况可能会很混乱。

要清楚,要干净

像在编程语言实践中一样,编写清晰的 SQL 查询,必要时添加注释,尽可能使用清晰的变量或别名。这将有助于您和您的团队理解查询中正在发生的事情,并使您在将来需要重新访问它进行更新时变得更加容易。

不太清楚和非常清楚的 SQL 查询示例

一些你可以使用的策略

创建查询后,就该安排它了。如果你的查询不需要产生任何表,那么 你可以忽略这些策略 。但是,通常您需要将结果存储在一个表中,以便在报告工具、仪表板甚至基本的机器学习管道中使用。

替换所有策略

这是最简单的策略,只需运行您的查询,然后将其存储在一个表中。它可以是每日生成的销售线索/销售列表、上个月的流失客户列表等。

我不认为我需要解释更多关于这个策略,它已经很明显了。

简单追加策略

当您需要不断地向表中添加新数据时,可以使用这种策略,比如监控仪表板。

首先,您需要创建您的初始表作为您的基表,然后您可以根据您的需要,每天、每周、每月使用您的预定查询追加更多的数据。

简单附加策略(图片由作者提供)

如果需要,不要忘记设置分区👍

窗口追加策略

有时,您会处理不断更新的数据,这些数据可能来自事件跟踪器或其他一些系统,我们预计从这些数据源提取数据会有延迟,例如 firebase 事件数据。

假设您已经使用计划查询制作了昨天数据的快照,并将其存储在您的表中,但是在您运行计划查询之后,您的主数据源中的数据会有一些更新,此外,您不知道确切的数据更新/插入时间。这会使您的表中的数据无效或不完整,因此您的报告中产生的信息也无效。

在这种情况下,最好以窗口方式运行追加策略。因为在每次运行中,我们都用新的数据替换数据,所以我们可以减少无效或不完整数据的可能性。您可以根据在您的数据环境中最有意义的方式来设置窗口时段。对于每日计划查询,我通常将窗口设置为 3 到 7 天。

窗口附加策略(作者图片)

计算然后替换策略

在某些用例中,您需要根据以前的数字计算一些数字,就像运行计算一样。

例如,我们希望有一个不断更新的特定用户的每周总支出,根据这个支出金额,我们希望给我们的客户特殊待遇。

这种问题实际上可以通过简单地根据我们的每日/每周附加表(来自前面的策略)合计用户的所有支出来解决。当数据变得太大时,将来可能会出现不好的情况,运行这种聚合查询的成本会很高。

因此,您可以简单地一次性捕获每个用户的最新周总支出作为基表,然后通过简单地添加previous _ total _ spending+current _ week _ total _ spending来逐步更新该值。

计算然后替换策略(图片由作者提供)

结束语

处理查询确实是数据专业人员最常执行的任务之一。随着时间的推移,我们必须提高工作效率,以便更快地交付成果和见解。到一天结束时,我们可以开始花更多的时间来解决越来越多的业务问题。

上面的一些策略是基于我的经验,可能会有更多的策略来探索其他用例。我很开放,如果你有反馈或想补充一些我在这里错过的其他策略,将不胜感激!

最后,快乐学习!!!🚀

使用 Python 进行线性回归的简单指南

原文:https://towardsdatascience.com/a-simple-guide-to-linear-regression-using-python-7050e8c751c1?source=collection_archive---------3-----------------------

学习机器学习的核心概念,同时在 Python 中构建线性回归模型

作者图片

每个数据科学家应该学习的第一个机器学习算法之一是线性回归。这个简单的模型帮助我们掌握机器学习的核心概念,例如识别因变量和自变量,建立模型,以及理解模型背后的数学和统计学。

在 Python 中有两种进行线性回归的常用方法——使用 statsmodel 和 sklearn 库。两者都是很好的选择,各有利弊。

在本指南中,我将向您展示如何使用这两者进行线性回归,并且我们还将学习线性回归模型背后的所有核心概念。

**Table of Contents** 1\. [What is Linear Regression?](#8e94)
2\. [Linear Regression in Python](#65ed)
 - [The Data](#cbcb)
3\. [Linear Regression with Statsmodels](#0e95)
 - [Simple Linear Regression](#b74c)
 - [Multiple Linear Regression](#0fa8)
4\. [Linear Regression with sklearn](#894e)
5\. [Python for Data Science Cheat Sheet (Free PDF)](#ee7e)

什么是线性回归?

线性回归是一种建模两个(简单线性回归)或多个变量(多元线性回归)之间关系的方法。在简单线性回归中,一个变量被视为预测变量或自变量,而另一个变量被视为结果变量或因变量。

这是线性回归方程:

其中,y为因变量(目标值),x1, x2, … xn为自变量(预测值),b0为截距,b1, b2, ... bn为系数,n为观察值。

如果等式不清楚,下面的图片可能会有所帮助。

信用: Quora

在图中,你可以看到一个线性关系。也就是说,如果一个自变量增加或减少,因变量也会增加或减少。

线性回归可用于进行简单的预测,例如根据学习的小时数预测考试分数,根据工作经验预测员工的工资等等。

理论够了!我们来学习一下如何用 Python 做一个线性回归。

Python 中的线性回归

在 Python 中有不同的方法进行线性回归。最受欢迎的两个选项是使用 statsmodels 和 scikit-learn 库。

首先,让我们看看我们将用来创建线性模型的数据。

数据

为了在 Python 中进行线性回归,我们将使用包含波士顿房价的数据集。原始数据集来自 sklearn 库,但我对其进行了简化,因此我们可以专注于构建我们的第一个线性回归。

你可以在我的 Github 或者 T2 的 Google Drive 上下载这个数据集。确保将这个 CSV 文件放在 Python 脚本所在的目录中。

让我们来看看这个数据集。为此,导入 pandas 并运行下面的代码。

**import pandas as pd**
df_boston = pd.read_csv('Boston House Prices.csv')
df_boston

作者图片

有 3 列。“价值”列包含以 1000 美元为单位的自住房屋的中值(这是我们想要预测的,也就是我们的目标值)。“房间”和“距离”列包含每个住所的*均房间数和到五个波士顿就业中心的加权距离(两者都是预测值)

综上所述,我们希望根据房屋的房间数量及其到就业中心的距离来预测房屋价值。

带统计模型的线性回归

Statsmodels 是一个帮助我们进行统计测试和估计模型的模块。它为每个估计量提供了一个广泛的结果列表。

如果您已经通过 Anaconda 安装了 Python,那么您已经安装了 statsmodels。如果没有,你可以用 conda 或者 pip 安装。

# pip
pip install statsmodels# conda
conda install -c conda-forge statsmodels

一旦安装了 statsmodel,就用下面的代码行导入它。

**import statsmodels.api as sm**

创建线性回归之前要做的第一件事是定义因变量和自变量。我们已经在前一节讨论过了。因变量是我们想要预测的值,也称为目标值。另一方面,自变量是预测因子。

在我们的数据集中,我们有 2 个预测,所以我们可以使用其中任何一个或两个。

让我们从简单的线性回归开始。简单的线性回归估计一个自变量和一个因变量之间的关系。

简单线性回归

对于这个例子,我将选择“房间”作为我们的预测/独立变量。

  • 因变量:“值”
  • 自变量:“房间”

让我们也在代码中定义因变量和自变量。

y = df_boston['Value'] # dependent variable
x = df_boston['Rooms'] # independent variable

在本指南中,我将使用线性代数符号——小写字母用于向量,大写字母用于矩阵。

拟合模型 现在该拟合模型了。为了向您解释拟合模型的含义,请考虑以下用于简单线性回归的通用方程。

𝑦 = 𝑎𝑥 + 𝑏

信用: Quora

拟合模型意味着找到ab的最优值,因此我们获得一条最适合数据点的线。拟合良好的模型会产生更准确的结果,因此只有在拟合模型之后,我们才能使用预测值来预测目标值。

现在让我们使用 statsmodels 拟合一个模型。首先,我们在拟合模型之前添加一个常数(sklearn 默认添加它),然后我们使用。fit()方法。

x = sm.add_constant(x1) # adding a constant
lm = sm.OLS(y,x).fit() # fitting the model

“lm”代表线性模型,代表我们的拟合模型。这个变量将帮助我们预测我们的目标值。

>>> lm.predict(x)0      25.232623
1      24.305975
2      31.030253
3      29.919727
4      31.231138
         ...    
501    24.603318
502    20.346831
503    27.822178
504    26.328552
505    19.661029

上面的代码根据“房间”列中的数据预测房屋价值(打印输出)。

回归表

虽然我们可以预测目标值,但是分析还没有完成。我们需要知道这个线性模型的表现。回归表可以帮助我们解决这个问题。该表提供了一个结果的详细列表,揭示了我们的模型有多好/多差。

要获得回归表,请运行以下代码:

lm.summary()

您将获得此表:

作者图片

这个表格的标题是“OLS 回归结果”OLS 代表普通最小二乘法,这是估计线性回归最常用的方法。

让我们看看第一和第二个表中的一些重要结果。

  • 离开变量:这是因变量(在我们的例子中,“值”是我们的目标值)
  • r *方:取 0 到 1 之间的值。接* 0 的 r *方值对应于解释不了任何数据可变性的回归,而接* 1 的值对应于解释数据全部可变性的回归。获得的 r *方告诉我们,房间数量解释了房屋价值变化的 48.4%。
  • Coef:这些是我们之前在模型方程中看到的系数(a,b)。
  • 标准误差:表示预测的准确性。标准误差越低,预测越好。
  • t,P>t (p 值):t 分数和 P 值用于假设检验。“房间”变量具有统计学显著性 p 值。此外,我们可以在 95%的置信度下说“房间”的值在 8.279 到 9.925 之间。

线性回归方程 根据上表,让我们使用系数(coef)创建线性方程,然后用数据点绘制回归线。

# Rooms coef: 9.1021
# Constant coef: - 34.6706# Linear equation: 𝑦 = 𝑎𝑥 + 𝑏
y_pred = 9.1021 * x['Rooms'] - 34.6706

其中 y_pred(也称为 yhat)是回归方程中 y(因变量)的预测值。

线性回归图 为了绘制方程,我们使用 seaborn。

**import seaborn as sns
import matplotlib.pyplot as plt**# plotting the data points
sns.scatterplot(x=x['Rooms'], y=y)#plotting the line
sns.lineplot(x=x['Rooms'],y=y_pred, color='red')#axes
plt.xlim(0)
plt.ylim(0)
plt.show()

上面的代码产生了下面的图。

作者图片

红色的图是我们用 Python 构建的线性回归。我们可以说这是最符合蓝色数据点的线。

恭喜你!您刚刚在 Python 中构建了第一个简单的线性回归。如果你准备迎接挑战,看看如何进行多元线性回归。

多元线性回归

现在你已经知道了线性回归的核心概念,我们可以很容易地创建一个多元线性回归。

让我们从设置因变量和自变量开始。在这种情况下,我们将使用 2 个独立变量。

  • 因变量:“值”
  • 自变量:“房间”和“距离”

让我们也在代码中定义因变量和自变量。

y = df_boston['Value'] # dependent variable
X = df_boston[['Rooms', 'Distance']] # independent variable

现在让我们添加一个常数并拟合模型。

X = sm.add_constant(X) # adding a constant
lm = sm.OLS(y, X).fit() # fitting the model

让我们看看结果。

lm.summary()

作者图片

r *方增加了一点。此外,在第二个表中有一个新行代表“距离”变量的参数。该表的分析类似于简单的线性回归,但如果您有任何问题,请随时在评论部分告诉我。

使用 sklearn 进行线性回归

Scikit-learn 是 Python 中的标准机器学习库,它还可以帮助我们进行简单的线性回归或多元线性回归。

由于之前我们已经用 statsmodels 深入分析了简单线性回归,现在我们用 sklearn 做一个多元线性回归。

首先,我们来安装 sklearn。如果您已经通过 Anaconda 安装了 Python,那么您已经安装了 sklearn。如果没有,你可以用 conda 或者 pip 安装。

# pip
pip install scikit-learn# conda
conda install -c conda-forge scikit-learn

现在让我们从 sklearn 库中导入 linear_model。

**from sklearn import linear_model**

因变量和自变量如下。

y = df_boston['Value'] # dependent variable
X = df_boston[['Rooms', 'Distance']] # independent variable

现在我们必须拟合模型(注意,使用 sklearn 的 fit 方法中的参数顺序与 statsmodels 不同)

lm = linear_model.LinearRegression()
lm.fit(X, y) # fitting the model

与 statsmodels 类似,我们使用 predict 方法来预测 sklearn 中的目标值。

lm.predict(X)

然而,与 statsmodels 不同,我们不会使用.summary()得到一个汇总表。相反,我们必须逐个调用每个元素。

>>> lm.score(X, y)
0.495>>> lm.coef_
array([8.80141183, 0.48884854])>>> lm.intercept_
-34.636050175473315

结果与我们使用 statsmodels 获得的表格相同。

注意,为了简单起见,我们没有将数据分为训练和测试。在构建模型之前拆分数据是一种避免过度拟合的流行方法。这将是未来文章的主题,请继续关注!

就是这样!您刚刚学习了如何在 Python 中进行简单的多元线性回归。你可以在我的 Github 上找到本指南中写的所有代码。

与 3k 以上的人一起加入我的电子邮件列表,获取我在所有教程中使用的 Python for Data Science 备忘单(免费 PDF)

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让您可以无限制地访问数以千计的 Python 指南和数据科学文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。

https://frank-andrade.medium.com/membership

熊猫数据框简单指南

原文:https://towardsdatascience.com/a-simple-guide-to-pandas-dataframes-b125f64e1453?source=collection_archive---------9-----------------------

如何使用 Python 的 Pandas 库创建、存储和操作数据

埃米尔·佩龙在 Unsplash 上的照片

标准 Python 库pandas是用于数据分析和操作的最流行的库之一。pandas用于将数据转换为称为 DataFrame 的结构化格式,可用于各种操作和分析。数据帧有助于将数据格式化为清晰的表格,便于阅读和操作。

装置

pandas是标准的 Python 库之一,应该已经安装了,但是如果没有,可以用下面的命令安装:

pip install pandas

入门指南

pandas库通常与 Python 的numpy库一起使用,因此为了本教程,我将导入并使用这两个库。(将来会写一个如何使用numpy库的指南!)下面是一个从numpy系列创建pandas数据帧的简单例子:

import pandas as pd
import numpy as npvalues = np.random.randn(3, 2)
print(values)
print(type(values))df = pd.DataFrame(values)
print(type(df))
print(df)

下面是两个打印语句的输出:

<class 'numpy.ndarray'>
[[-1.01774631  1.0842383 ]
 [-0.04752437 -0.19560713]
 [-0.3643328   0.34562402]]<class 'pandas.core.frame.DataFrame'>
          0         1
0 -1.017746  1.084238
1 -0.047524 -0.195607
2 -0.364333  0.345624

如您所见,第一个输出是一个 3 行 2 列的多维numpy数组。np.random.randn就是简单地在指定的输出形状中生成随机数。通过使用numpy数组作为参数调用pd.DataFrame(),可以将数组转换为pandas数据帧。第二组打印语句显示了 DataFrame,它包含与numpy数组相同的值,以及 3 行 2 列的相同形状。默认情况下,列和行的索引从 0 开始,但这些可以手动更改,也可以在创建数据帧时通过初始化来更改。

更新表格

更改列/行索引

如前所述,默认情况下,列和索引从 0 开始。但是,使用简单的整数作为索引并不总是有用的,因此建议根据您正在处理的数据将行和列更改为更合适的标签。您可以在初始化数据帧时或之后更改它们。假设您有想要用来标记列和行的字段名称。以下代码显示了如何使用名称初始化 DataFrame:

import pandas as pd
import numpy as npvalues = np.random.randn(3, 2)rows = ["A", "B", "C"]
features = ["foo", "bar"]df = pd.DataFrame(values, index=rows, columns=features)
print(df)

输出:

 foo       bar
A -2.702060  0.791385
B  1.696073 -0.971109
C -1.430298 -2.549262

如您所见,indexcolumns参数允许您在创建 DataFrame 时指定索引和列名。您也可以使用以下内容手动更改它们(建议使用关键字重命名,而不是位置):

df.rename(columns={"bar": "baz"}, inplace=True) foo       baz
A  0.010732  0.420194
B -1.718910 -1.810119
C  0.409996  0.694083

在这里您可以看到,通过调用rename()函数,列bar被更改为baz。注意inplace=True被添加到参数的末尾。如果要提交对数据帧的更改,这是必要的。或者,由于 DataFrame 上的函数返回 DataFrame 对象,您可以执行以下操作,其效果与添加inplace=True相同:

df = df.rename(columns={"bar": "baz"})

在这里打印df会得到与上面相同的结果,只是列被重命名了。

此外,通过使用set_index()函数,您可以选择其中一列作为索引,如下所示,使用 3x4 矩阵:

import pandas as pdvalues = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
rows = ["A", "B", "C"]
features = ["foo", "bar", "baz", "qux"]df = pd.DataFrame(values, index=rows, columns=features)df.set_index("foo", inplace=True)print(df)

输出:

 bar  baz  qux
foo
1      2    3    4
5      6    7    8
9     10   11   12

这将获取foo列并用这些值替换当前索引。当有一列用于dateid并且您想要将索引设置为这些唯一值时,这通常会很方便。

添加新列/行

如果您想在数据帧的底部追加一个新行,您必须确保它与现有数据帧的形状相同。例如,如果您有与上面相同的 4 列数据帧,则正在添加的新行也应该有相同的 4 列。下面是新的数据框架,由 3 行 4 列组成:

import pandas as pdvalues = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
rows = ["A", "B", "C"]
features = ["foo", "bar", "baz", "qux"]df = pd.DataFrame(values, index=rows, columns=features)
prrint(df)

输出:

 foo  bar  baz  qux
A    1    2    3    4
B    5    6    7    8
C    9   10   11   12

现在,如果您想添加一个新行,这 4 列必须对齐。至于索引,您可以指定它或者让pandas自动生成一个新的(默认为下一个可用的整数):

new_data = [[13, 14, 15, 16]]
new_df = pd.DataFrame(new_data, index=["D"], columns=features)df = df.append(new_df)
print(df)

输出:

 foo  bar  baz  qux
A    1    2    3    4
B    5    6    7    8
C    9   10   11   12
D   13   14   15   16

注意new_data不仅仅是一个列表,而是一个 1 行 4 列的矩阵。这是因为它必须遵循与附加它的初始数据帧相同的结构。然后,您可以将这个 1x4 转换为第二个 DataFrame,它具有指定的索引和相同的列。功能df.append()允许您将这个由单行组成的新数据帧添加到原始数据帧中。

要向数据帧添加新列,只需用新列名和新数据引用数据帧。使用与上面相同的数据帧,它看起来像这样:

import pandas as pdvalues = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
rows = ["A", "B", "C"]
features = ["foo", "bar", "baz", "qux"]df = pd.DataFrame(values, index=rows, columns=features)
df["quux"] = [55, 56, 57]print(df)

输出:

 foo  bar  baz  qux  quux
A    1    2    3    4    55
B    5    6    7    8    56
C    9   10   11   12    57

只要新列表与初始数据帧具有相同的行,就可以很容易地追加新列。

还有一个更巧妙的技巧——如果您想选择所有的列名,您可以调用df.columns来返回['foo', 'bar', 'baz', 'qux', 'quux']

选择数据

有时,您可能需要访问特定的行或列,甚至是特定的数据单元格。与我们之前添加列的方式类似,您可以用同样的方式访问一个或多个列:

import pandas as pdvalues = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
rows = ["A", "B", "C"]
features = ["foo", "bar", "baz", "qux"]df = pd.DataFrame(values, index=rows, columns=features)
print(df[["foo", "baz"]])

输出:

 foo  baz
A    1    3
B    5    7
C    9   11

通过调用由列名列表索引的df,您可以创建一个只包含指定列的新对象。现在,如果您只想访问某些行,您可以使用.loc.iloc。这两者的区别只是通过名称或索引位置来访问行。以下示例显示了两种方法以及它们如何返回同一行:

import pandas as pdvalues = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
rows = ["A", "B", "C"]
features = ["foo", "bar", "baz", "qux"]df = pd.DataFrame(values, index=rows, columns=features)row_loc = df.loc["B"]
print(row_loc)row_iloc = df.iloc[1]
print(row_iloc)

输出:

foo    5
bar    6
baz    7
qux    8
Name: B, dtype: int64foo    5
bar    6
baz    7
qux    8
Name: B, dtype: int64

索引 1 处的行(第二行,因为我们从 0 开始计数!)和索引为B的行是同一行,可以用任何一种方法访问。

如果您想访问单个单元格,您也可以使用.iloc,如下图所示:

import pandas as pdvalues = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
rows = ["A", "B", "C"]
features = ["foo", "bar", "baz", "qux"]df = pd.DataFrame(values, index=rows, columns=features)
print(df)cell = df.iloc[1, 2]
print("cell: ", cell)

输出:

 foo  bar  baz  qux
A    1    2    3    4
B    5    6    7    8
C    9   10   11   12cell:  7

使用.iloc,第一个值是行,第二个值是列——因此.iloc[1, 2]访问第 2 行第 3 列的单元格。

操作

数学运算也可应用于pandas数据帧中的数据。简单地说,可以将标量应用于数据帧的一列,如下所示:

import pandas as pdvalues = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
rows = ["A", "B", "C"]
features = ["foo", "bar", "baz", "qux"]df = pd.DataFrame(values, index=rows, columns=features)df["qux"] = df["qux"] * 10print(df)

输出:

 foo  bar  baz  qux
A    1    2    3   40
B    5    6    7   80
C    9   10   11  120

这里,我们将qux列乘以标量 10,并用新的值替换该列中的值。您还可以在多列之间执行操作,例如将列相加或相乘。在下面的示例中,我们将两列相乘,并将它们存储到一个新列中:

import pandas as pdvalues = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
rows = ["A", "B", "C"]
features = ["foo", "bar", "baz", "qux"]df = pd.DataFrame(values, index=rows, columns=features)df["quux"] = df["bar"] * df["baz"]print(df)

输出:

 foo  bar  baz  qux  quux
A    1    2    3    4     6
B    5    6    7    8    42
C    9   10   11   12   110

这里,新的quux列的每一行都是bar列和baz列的每一行的乘积。

您可以在数据帧上执行的另一个重要操作是apply()功能。这允许您对数据帧中的数据应用整个函数。以下是使用apply()函数对数据应用独立函数的简单示例:

import pandas as pddef sum_function(row):
    return row["foo"] + row["bar"] + row["baz"] + row["qux"]values = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
rows = ["A", "B", "C"]
features = ["foo", "bar", "baz", "qux"]df = pd.DataFrame(values, index=rows, columns=features)df["quux"] = df.apply(sum_function, axis=1)print(df)

输出:

 foo  bar  baz  qux  quux
A    1    2    3    4    10
B    5    6    7    8    26
C    9   10   11   12    42

这里,我们有一个名为sum_function()的函数,它简单地将一行中的 4 个元素相加。使用相同的 DataFrame,我们可以用这个函数作为参数调用df.apply()。第二个参数axis=1是必需的,因为默认情况下轴被设置为 0,而apply()将作用于行而不是列。使用这个apply()函数,我们可以看到quux列包含所有先前字段的总和,这是由指定的函数应用的。

读取/写入数据

pandas的另一个简洁的特性是你可以读写数据帧中的文件。例如,您可以读入 CSV 或 JSON 文件,处理数据,然后将其写回新文件。假设您在与 Python 脚本相同的目录中有一个名为data.csv的文件,其中包含我们一直在处理的相同数据。您可以使用以下代码将它读入数据帧:

import pandas as pddf = pd.read_csv("data.csv")print(df)

其输出将与我们一直在处理的数据相同:

 foo  bar  baz  qux
A    1    2    3    4
B    5    6    7    8
C    9   10   11   12

然后,如果您想将数据写回一个新的 CSV,您可以使用以下命令将它写到您的工作目录:

output.csv:

,foo,bar,baz,qux
A,1,2,3,4
B,5,6,7,8
C,9,10,11,12

这个output.csv正是我们最初用read_csv()函数读入数据帧的data.csv所包含的内容!

外卖食品

pandas库非常灵活,对于处理数据集和数据分析非常有用。使用pandas对数据进行存储、操作和执行操作非常简单。此外,许多机器学习模型可以使用pandas数据帧作为它们的输入。本指南的目标是提供该库的简单概述,并提供一些基本示例来帮助您更好地理解pandas的一些关键特性。

感谢您的阅读,我希望您已经对pandas有了足够的了解,可以开始在您的下一个 Python 项目中实现它了!

一个简单的黑客来提高任何全局优化算法

原文:https://towardsdatascience.com/a-simple-hack-to-boost-any-global-optimization-algorithm-bdea461b87?source=collection_archive---------21-----------------------

用准随机数生成器给你的优化器加点盐和胡椒

比尔·杰伦在 Unsplash 上的照片

许多计算机程序依靠随机数工作。

这就是全局优化算法的情况,其中属于应用数学和数值分析的一个分支,研究如何在给定的优化超空间上有效地找到函数 f(x) 的全局最小值/最大值。

在每个全局优化算法中,优化过程从生成维度为 DN 个个体的随机抽样群体开始。

这些个体中的每一个都代表了要解决的优化问题的候选解决方案。

许多研究表明,第一代候选解的空间分布对优化算法的性能有重要影响。

安迪·马克里在 Unsplash 拍摄的照片

像混沌理论的蝴蝶效应一样,随机过程优化算法初始化中的小偏差会导致非常不同的结果。

在本文中,你会发现有一种特殊的“随机”数字发生器可以提高优化算法向全局最优的收敛速度。

当我第一次开始从事进化算法的开发工作并遇到这个相对简单的黑客时,我怀疑它是否会对性能产生任何明显的影响,但没过多久我就发现混沌理论著名的蝴蝶效应也适用于全局优化问题。

欢迎来到疯狂而美丽的随机世界。

克瑞丝·布朗从澳洲墨尔本拍摄的照片。维基共享。

电脑不玩骰子

我们生活在一个混沌的世界里,随机性时刻存在于我们的生活中。然而,在我们在计算机上运行的程序中准确模拟这种随机性并不容易。

一台普通的计算机,就像一台机器,在设计上是确定的,这意味着相同的输入总是产生相同的输出。

随机值通常用于统计分析、艺术,或者只是当我们不得不随机选择一些东西时,例如在抽奖中。

然而,当涉及到用标准计算机产生随机性时,我们归因于硬币或骰子等物理对象的完美随机性有点难以实现。

计算机试图以纯数学的方式生成随机数,这是一个问题,而不是一个优势——过了一段时间,看似随机的东西最终不再那么随机了。

虽然随机物理过程的组合可以用来生成纯随机数(从桌上的鼠标移动到放射性),但如果我们像计算机一样依赖纯数学,我们能得到的最好结果是伪随机数。

标准计算机中纯粹的随机性只是一个错误的幻觉,我们所能得到的最好的结果是“几乎随机”的不可预测性

由马克斯·费尔纳在 Unsplash 上拍摄的照片

伪随机数非常接*纯粹的概率,但在随机性方面也有一些限制。这就是前缀“伪“的原因。

无论如何,在计算机中生成一个好的伪随机数序列也不容易。

这个游戏的名字是寻找一个函数,它的结果在每次使用时都不同,尽管我们知道它的输出会在某个时间重复,因为从技术上讲,只能使用有限数量的数字(例如,手表表面的数字或存储在变量中的 264 位数字)。

为什么伪随机数可能不足以进行全局优化?

在任何基于群体的全局优化算法中,如 PSO 、 CMA-ES 、 GA 或 DE 等等,当我们使用伪随机数发生器从均匀概率分布 U(0,1) 中对初始代的前 N 个个体进行采样时,我们得到如下结果:

在 Matlab 中使用伪随机数发生器分配 1000 个样本。图片由作者提供。

你不认为 2D 空间中的个体分布在某些区域过于稀疏吗?

这是伪随机数的问题,它们不会以均匀的方式有效地填充空间。

用伪随机数发生器创建的样本并不是沿着采样超空间的每个维度完美地均匀分布的。正如您稍后将看到的,这可能会对优化性能产生很大的影响。

但是不要担心,这个问题有一个非常简单的方法,叫做准随机数。处理伪随机数缺乏同质性的一个非常好的替代方案。

准随机数与伪随机数有许多相似之处,但它们是基于低差异序列确定性选择的。

低差异序列?

好吧,我知道你现在可能想知道,什么是低差异序列?

在数学中,差异( DN) 为一个样本序列( s₁,...)关于区间[a,b]被定义为

根据这个定义,当 N (序列中元素的数量)趋于无穷大时,一个均匀分布序列具有趋于零的差异。

低差异序列的一个优点是它们以均匀分布的方式更加均匀地填充 N 维超空间,因此,使用这种类型的序列创建的初始群体将提供对优化超空间的更加有效的探索。

低差异序列也被称为准随机序列。

对于我们的情况,真正重要的是要注意,准随机数的低差异属性对于全局优化方法至关重要。

但是,最重要的低差异序列类型是什么?

哈尔顿序列和哈默斯利集

哈尔顿序列和哈默斯利集合定义了对 D 维空间采样的两种确定性的https://en.m.wikipedia.org/wiki/Deterministic_system方式,使得连续的点彼此尽可能远离。

本质上,Halton 序列和 Hammersley 集合都是针对多维情况的 Van der Corput 序列的推广。

Van der Corput 序列最初被提出来对一维区间[0,1]进行采样,使得序列的一个点和下一个点尽可能远。

假设我们想要生成基数为 b 的范德科尔特序列的 N 个样本(其中 b 是一个质数),那么第 n 个元素可以通过两个简单的步骤获得:

  1. 获取系数 ai 表示基数 b: 中整数 n 的二进制表达式

****

2.然后,利用 aᵢ 系数,我们可以最终计算出序列的第 n 个元素ϕ(n】如下:

例如,数字 n = 5 可以用基数 b = 2 表示,其中 a₀ = 1, a₁ = 0, a₂ = 1,因此范德科尔普特序列的第 5 个元素将等于 1/2 + 1/8 = 5/8。

下图将帮助您以升序(红点)显示基数为 b = 2 的范德科尔特序列的前十二个样本。

资料来源:从范德科尔普特到拟蒙特卡罗规则序列的现代构造。论文

我知道这里涉及的数学可能不简单。老实说,我一直很难想象数字在不同于 b = 10 的基数下的表示。

然而,您会惊讶地发现,在通用库 b. 中编写范德科尔特序列是多么简单

看看这段 C 代码片段。

是不是简单得令人难以置信?确实是!

到目前为止,我们已经看到了如何生成一个一维序列,所以下一步是将这些序列扩展到更高维度。

这就是哈尔顿的贡献发挥作用的时候了。

为了将范德科尔普序列推广到一个 D- 维超 - 空间,哈尔顿使用了一个非常简单的策略,即使用一个范德科尔普序列,每个轴具有不同的素数基。

这是,对于 D- 维的情况,哈尔顿序列的第一维是基数为 b = 2 的范德科尔普序列,第二维是基数为 b = 3 的范德科尔普序列,第 D-th 维是基数与第 D-th 素数一致的范德科尔普序列。

这是 1000 个哈尔顿序列样本的样子。

此图像显示了来自伪随机数发生器(顶部)的 1000 个点,与 Halton 低差异序列(底部)进行了比较。图片由作者提供。

哈默斯利使用了这个策略的一个小变体来产生另一个准随机序列,即哈默斯利集合。

在哈默斯利集合中,第一维的第 n 个样本不是基数为 2 的范德科尔普序列,而是简单的 n / N

此图像显示了伪随机数发生器(顶部)的 1000 个点,与 Hammersley 集(底部)进行了比较。随着样本以递增的顺序呈现,观察 Hammersley 集合的第一维如何是 n / N。

Halton 序列和 Hammersley 集都是多维中最基本的低差异序列生成器,它们可以被认为是其他低差异序列的构造块。

2.Sobol 序列

Sobol 序列是另一种广泛使用的准随机数生成器,它是由 Ilya M. Sobol 早在 1967 年发明的。

这个准随机数生成器使用基数 2 来生成区间[0,1]的均匀分区,然后对采样超空间的每个维度执行主序列的特殊重新排序。

Sobol 序列的数学实现稍微繁琐一些,所以我们将直接使用它获得结果,并将它们与使用伪随机数生成器获得的结果进行比较。

如果你想了解更多 Sobol 序列背后的理论,可以参考这个来源。

该图显示了 Sobol 序列中的 1000 个点(底部)与伪随机样本(顶部)的比较。Sobol 序列更均匀地覆盖空间。图片由作者提供。

对于 Python 、 Matlab 、 Julia 、 Fortran 和 C++ 编程语言来说,Sobol 序列有太多的实现。

🟣应用实例——助推粒子群优化算法

这里,我们将评估随机初始化对最简单但有效的优化算法之一粒子群优化(PSO)的优化性能的影响。

基于粒子群优化算法的种群进化动画。来源:维基共享。

为该比较分析选择的函数 f(x) 将是一组三个多维函数,它们通常用于全局优化算法的基准测试。

  • f₁ :球体功能

  • f₂ :超椭球函数

  • f₃ :阿克利函数

我们将只考虑自变量 x 的值的上下限约束,而不考虑非线性约束。

将比较三种不同的粒子群优化算法的种群初始化方法:

  • U-PSO :使用伪随机数发生器(rand()函数)的统一初始化。
  • H-PSO :使用随机 Halton 序列初始化。
  • S-PSO :使用随机化的 Sobol 序列进行初始化。

选择用来测量优化性能的品质因数将是找到基准函数的全局最小值(在这种情况下是已知的)所需的函数求值的*均数。越低越好。

为了分析维度诅咒的影响,我们还将考虑三种不同的情况,维度 D = 10, D = 20, D = 30。

你渴望看到优化基准测试的结果吗?

这是我在笔记本电脑上运行了几次优化后得到的结果。

D = 10 的优化基准测试结果,显示了寻找最优解的函数评估的*均值。图片由作者提供。

D = 20 的优化基准结果,显示了寻找最优解的函数评估的*均值。图片由作者提供。

D = 30 的优化基准测试结果,显示寻找最优的函数评估的*均值。图片由作者提供。

如结果所示,S-PSO 算法(用随机化的 Sobol 序列初始化的 PSO)优于其他两种算法(U-PSO 和 H-PSO),而不考虑成本函数和优化空间维度 D.

从这些结果得出的另一个结论是,尽管用随机化 Halton 序列初始化的 PSO 算法并不比使用 Sobol 序列的算法好,但它与使用标准伪随机数发生器的算法一样好(在某些情况下稍好)。

最后的想法

正如您所看到的,从伪随机初始化策略切换到准随机初始化策略可以提高优化算法的性能。

这个技巧非常简单,可以应用于任何全局优化器,您只需修改那些使用rand()函数的代码行,作为您自己的低差异序列生成器。

但一如既往,有一个免责声明:

“低差异序列破解不是魔术”

有时,根据您正在使用的成本函数,您看不到任何改进,但是无论如何,这都不会损害优化器的性能。所以值得一试!****

参考文献

[1]马阿拉宁,h .,米耶蒂宁,k .和马克勒,M. M. 2004 年。遗传算法的准随机初始种群。计算机与数学应用,第 47 卷:1885-1895。

[2] 莫罗科夫,W. J .和卡弗利什,R. E. 1994。准随机序列及其差异。暹罗 J. Sci。计算机。, 15(6):12511279

[3]马斯卡尼,m .和迟,H. 2004 年。在加扰的 Halton 序列上。蒙特卡洛方法应用,10(3):435–442

【范·德·科尔普特,J.G. 1935。Verteilungsfunktionen。一.米特。继续。阿卡德。潮湿。阿姆斯特丹。38: 813–821

[5] Pausinger,f .和 A. Topuzoglu,Van der Corput 序列和置换多项式,预印本。

OpenCV Python 上一个简单的 HDR 实现

原文:https://towardsdatascience.com/a-simple-hdr-implementation-on-opencv-python-2325dbd9c650?source=collection_archive---------12-----------------------

了解如何使用 Python 和 OpenCV 创建高动态范围(HDR)图像

在 Unsplash 上由 Lerone Pieters 拍摄

HDR 图像包含了不同曝光的多幅图像的信息。在光源不均匀的场景中,单次拍摄可能会使图像的某些区域过度曝光,并且由于亮度增加,细节会丢失。相反,这张照片也可能出现曝光不足的区域,这也将导致信息丢失。

要创建 HDR 图像,您需要:

  1. 用不同的曝光量拍照。最少 2 个,通常 3 个,你可以使用 3 个以上的图像,但这将占用大量的 CPU 资源。
  2. 对齐图像。即使你使用三脚架,你也需要执行这一步(我们说的是像素级对齐)。没有正确对齐您的图像将导致您的 HDR 图像中的伪像和“幽灵”。
  3. 将对齐的图像合并为一个。
  4. 对合并的图像执行色调映射。在自然界中,最小的可能亮度是零,但最大值不限于 255,事实上没有限制,它可以是无穷大。为此,我们需要将第三步中获得的图像映射到(0,255)范围。这可以通过色调映射来实现。

例子

import cv2 as cvimport numpy as np# Loading exposure images into a listimg_fn = [r"C:\Users\felipe.cunha\Documents\venv\HDRTest\100.jpg", r"C:\Users\felipe.cunha\Documents\venv\HDRTest\250.jpg", r"C:\Users\felipe.cunha\Documents\venv\HDRTest\500.jpg"]img_list = [cv.imread(fn) for fn in img_fn]exposure_times = np.array([100, 250, 500], dtype=np.float32)# Merge exposures to HDR imagemerge_debevec = cv.createMergeDebevec()hdr_debevec = merge_debevec.process(img_list, times=exposure_times.copy())merge_robertson = cv.createMergeRobertson()hdr_robertson = merge_robertson.process(img_list, times=exposure_times.copy())# Tonemap HDR imagetonemap1 = cv.createTonemap(gamma=2.2)res_debevec = tonemap1.process(hdr_debevec.copy())# Exposure fusion using Mertensmerge_mertens = cv.createMergeMertens()res_mertens = merge_mertens.process(img_list)# Convert datatype to 8-bit and saveres_debevec_8bit = np.clip(res_debevec*255, 0, 255).astype('uint8')res_mertens_8bit = np.clip(res_mertens*255, 0, 255).astype('uint8')cv.imwrite(r"C:\Users\felipe.cunha\Documents\venv\HDRTest\ldr_debevec.jpg", res_debevec_8bit)cv.imwrite(r"C:\Users\felipe.cunha\Documents\venv\HDRTest\fusion_mertens.jpg", res_mertens_8bit)

德贝韦克方法。看看这些细节!

默滕斯方法。

结论

我们已经介绍了 HDR 的基本情况。当您需要在曝光不足和曝光过度的大视场中定位特征时,此技术特别有用。

希望这能对你的计算机视觉项目有所帮助。

如果你想要一篇关于这个话题的更深入的文章,请在评论中告诉我。

谢谢!

逻辑回归系数的简单解释

原文:https://towardsdatascience.com/a-simple-interpretation-of-logistic-regression-coefficients-e3a40a62e8cf?source=collection_archive---------0-----------------------

入门

赔率简单解释了一下。

图片由伊恩·杜利(来源:Unsplash)——感谢伊恩!

我一直对逻辑回归很着迷。这是一个相当简单但功能强大的机器学习模型,可以应用于各种用例。它已经被广泛地解释和应用,然而,我还没有看到许多对模型本身的正确和简单的解释。让我们现在破解它。

我不会深入研究什么是逻辑回归,它可以应用在哪里,如何测量模型误差等细节。已经有很多关于它的好文章了。这篇文章将以一种简单、直观的方式专门处理的系数的解释,而不引入不必要的术语。

步骤零:解释线性回归系数

让我们首先从一个线性回归模型开始,以确保我们完全理解它的系数。这将是稍后解释逻辑回归的基础。

这是一个线性回归模型,有两个预测变量和结果 Y :

Y = a+ bX₁ + cX₂ ( 等式 ** )*

我们来选一个随机系数,比如说, b 。让我们假设 b > 0 。解释 b 很简单:x₁增加 1 个单位将导致 Y 增加 b 个单位,如果所有其他变量保持不变(了解这一条件很重要)。注意,如果 b < 0 ,那么 X₁ 增加 1 个单位将使 Y 减少 b 个单位。

作为一个例子,让我们考虑以下基于 2 个输入变量预测房价的模型:*方英尺年龄。请注意,该模型是“假的”,即我编造的数字只是为了说明这个例子。

房价= a + 50,000*方英尺-20,000年龄

如果我们增加 1 *方英尺的面积,房价将增加 50,000 美元。如果我们将房龄增加 1 年,房价将减少 2 万美元。年龄每增加 1 岁,房价将继续下降 20,000 美元。

好吧,这很简单。现在让我们继续进行逻辑回归

接下来:解释逻辑回归系数

逻辑回归模型是这样的:

logit(p) = a+ bX₁ + cX₂(方程式**)

你会注意到它与线性模型略有不同。让我们澄清它的每一点。 logit(p) 只是 log(p/1-p) 的一个快捷方式,其中 p = P{Y = 1} ,即“成功”的概率,或者说一个结果的存在。X₁和 X₂是预测变量, bc 是它们对应的系数,每个系数决定了 X₁和 X₂对最终结果 Y (或 p )的侧重。最后, a 就是简单的截距。

我们仍然可以使用旧的逻辑,比如说, X₁ 增加 1 个单位将导致blogit(p)增加。我在这里只是一个模仿者,应用线性模型解释。为什么不呢?方程和**其实形状一样!*

但是现在我们不得不更深入地研究“X₁每增加 1 个单位将导致 logit(p)增加 b”这一说法。第一部分很清楚,但是我们真的感觉不到 logit(p)b 的增加。这到底意味着什么?

要理解这一点,我们先解开 logit(p) 。前面说过, logit(p) = log(p/1-p) ,其中 pY = 1 的概率。 Y 可以取两个值,0 或 1。P{Y=1}称为成功的概率。因此logit(P)= log(P { Y = 1 }/P { Y = 0 })。这被称为对数优势

揭开对数概率的神秘面纱

我们得出了这个有趣的术语 log(P{Y=1}/P{Y=0}) 又名log-odds。现在回到系数解释:X₁每增加 1 个单位将导致成功几率的对数增加:失败。

好吧,这样更有道理。但是让我们充分阐明这个新术语。先从赔率说起,再扩展到对数赔率

你可能以前听说过赔率,例如赢得赌场游戏的赔率。人们经常错误地认为几率和概率是一回事。他们不是。这里有一个例子:

掷出公*的 6 面骰子得到 4 的概率为 1/6 或~16.7%。另一方面,得到 4 的几率是 1:5,或者 20%。这等于 p/(1-p) = (1/6)/(5/6) = 20%。所以,几率代表了成功概率和失败概率的比率。从赔率到概率的转换相当简单,反之亦然。

现在,对数几率就是几率的对数。引入对数的原因很简单,因为对数函数将产生一个可爱的正态分布,同时缩小 P{Y=1}/P{Y=0} 的极大值。还有,对数函数是单调递增的,所以不会破坏原来数列的顺序。

也就是说, X₁ 的增加将导致 log-oddslog(p { y = 1 }/p { y = 0 })增加数量 b > 0 ,这将增加赔率本身(因为 log 是单调递增的函数),这意味着 P{Y=1} 获得 100%概率馅饼的更大比例。换句话说,如果我们增加 X₁ ,那么 Y=1Y=0 的几率会增加,导致 Y=1 比增加前更有可能。

当 b < 0. I’ll leave it up to you to interpret this, to make sure you fully understand this game of numbers.

Phew, that was a lot!

But bear with me — let’s look at another “fake” example to ensure you grasped these concepts.

logit(p) = 0.5 + 0.13 * study_hours + 0.97 * female

In the model above, b = 0.13,c = 0.97,p = P{Y=1} 是通过一次数学考试的概率时,解释是类似的。让我们挑选出学习时间,看看它如何影响通过考试的机会。学习时间增加 1 个单位(1 小时)将导致 logit(p)log(p/1-p) 增加 0.13。现在,如果log(p/1–p)增加 0.13,那就意味着 p/(1 — p) 会增加 exp(0.13) = 1.14 。这意味着通过考试的几率增加了 14%(假设变量女性保持不变)。

我们也来解读一下身为女性对通过考试的影响。我们知道 exp(0.97) = 2.64 。也就是说,女性通过考试的几率要高出 164%。

模型解释日益成为机器学习&数据科学的一个重要方面。理解模型做什么以及它如何做出预测在模型构建&评估过程中至关重要。现在您对逻辑回归的工作原理有了更好的理解,您将能够更好地理解您构建的模型!

如果您喜欢这篇文章,请关注我,以便在新内容发布时收到通知!❤你可能也会喜欢下面的内容,在这里我用简单的方式解释统计概念:

  1. p 值的简单解释
  2. 大数定律的关系&中心极限定理
  3. 5 个激动人心的概率问题(有清晰的解答)

p 值的简单解释

原文:https://towardsdatascience.com/a-simple-interpretation-of-p-values-34db3777d907?source=collection_archive---------11-----------------------

简单解释了 p 值和冰淇淋消耗量。

Katie Smetherman 的照片(来源:Unsplash——感谢 Katie!❤)

p 值很有意思。它们非常有用,但又耐人寻味,神秘莫测,难以理解。这篇文章将试图在不使用太多技术术语的情况下解释它们。

让我们简单地从一个关于冰淇淋消费的有趣故事开始,用通俗易懂的方式来说明 p 值

冰淇淋店问题🍦

为了便于说明,我将讲述一个虚构的冰淇淋店,我经常在那里停下来买我最喜欢的冰淇淋口味。这家店位于多伦多一条繁忙的街道上,每天都有数百人驻足品尝美味。

在一个阳光明媚的星期天,我路过这个地方,点了我最喜欢的草莓🍓冰淇淋。出于好奇,我问店主,她认为普通顾客一周会买多少冰淇淋。她摇摇头说:

“嗯,我想说,*均来说,一个顾客一周会买 3 个冰淇淋,可能多一个或少一个。”

我谢过她,走到附*的长椅上享用我的甜点。

当我坐在附*的长椅上时,我仔细观察了所有进出的人,注意到有些人甚至一天来多次。我想——嗯,他们可能会在本周再次回来。所以我开始怀疑——她告诉我真相了吗?我开始怀疑现实可能是*均每个顾客一周消费超过 3 个冰淇淋。考虑到冰淇淋的美味,这并不奇怪。

我非常注重数据,喜欢根据数据点做出结论,所以我决定做一个彻底的统计分析来验证我的怀疑。我决定进行假设检验(即 A/B 检验),并收集我做决定所需的数据。

首先,我使用所有者与我分享的数据点绘制了一个分布图:

我假设我的数据*似正态分布,均值= 3,标准差= 1。请记住,并不是所有的真实生活数据都是正态分布的![图片是我自己的]

太好了——现在我们对底层数据有了一个大致的概念。让我们继续并建立一个 A/B 测试。

设置 A/B 测试

在 A/B 测试中,你可能已经知道,你有一个控制组 A (也称为现状)与一个处理组 B竞争。在这种情况下,让我们这样设置它们:

答:*均每位顾客每周在观察到的冰淇淋店购买 3 份冰淇淋

和...相对

B:*均每位顾客每周在观察到的冰淇淋店购买3 个以上的冰淇淋**

如果我能找到足够的证据来否定 A 而支持 B,那就太好了,这也证实了我的怀疑。

那么,我如何收集足够的证据呢?我需要数据(耶!).我要做的是,我将收集关于 n = 50 顾客的数据点,观察他们的习惯,并获得他们在给定的一周内冰淇淋的*均数量。

好吧,假设我收集了这些数据,并观察到X̅ = 4,也就是说,我观察到*均来说,一位顾客每周从这家虚拟的冰淇淋店订购 4 份冰淇淋。下一步是使用一个测试统计,它将帮助我得出一个结论,即我怀疑店主对我撒谎是否正确。因为我们在这里测试样本均值,所以我将使用以下常用的测试统计:

Z = (X̅— μ)/ (σ / sqrt(n))

****边注:根据 A/B 测试的设置,有大量可用的测试统计数据。例如,如果您测试的是一个比例而不是一个*均值,或者您测试的是多个治疗组,那么测试统计看起来会有所不同。你可以点击了解更多信息。

注意上面的 Z 测试统计的公式。我们基本上期望从样本均值中减去假设(理论)均值 μ ,然后通过样本大小和理论标准偏差 σ 将这一差异归一化。这将有助于我们确定我们选择的样本*均值与理论*均值相差多少。另外,根据店主告诉我们的,注意 μ = 3,σ = 1 。X̅是 4,而 n = 50:

z =(4–3)/(1/sqrt(50))= 7.07。

好了,我们得到了这个所谓的 z 值 7.07,现在,我们该怎么做呢?我们将在图表上绘制这个数字,旁边是假设的差值 0(即,如果语句 A 是正确的,那么 Z = 0 )。

[图片是我自己的]

因此,您看到的是,A 与 B 的对比——我们看到现状为 0,即没有差异,这意味着所有者是正确的,B 意味着归一化差异为 7.07,即根据我的观察,我与现状相差 7.07 个单位(或者,如果我们将 z 分数非归一化并查看原始原始值,则相差 1 个冰淇淋)。

现在的问题是,这种差别太大了吗?这个观察到的差异足够大(显著)让我说“好吧,我有足够的证据拒绝 A,接受 B”

融合 p 值以进行数据驱动的决策

看上面的图表,我们到达了需要做出决定的点,但是我们不知道如何做。救市是为了找到一个有助于我们做出最终决定的 p 值。什么是 p 值?

假设零假设(A)是正确的,p 值是获得至少与已经观察到的结果一样极端的结果的概率。

好吧,这是一个非常类似维基百科的定义,让很多人感到困惑(当我第一次了解 p 值时,我也感到困惑😌).通俗地说,p 值是下图中绿色的区域,所以本质上它是得到比我们观察到的更极端结果的概率(在我们的场景中 X̅ = 4)。****

p 值是曲线下的绿色区域。在我们的例子中,我们很快就会看到这个面积几乎为 0。显然,上图中的面积远不为零,我们想从概念上强调 p 值,所以不要让这个问题困扰你!😃【图片是我自己的】

这意味着,我们离*均值越远,这个区域(即 p 值)就越小,因此我们就越不可能观察到比我们已经看到的更极端的情况。这个区域越小,我们反对现状的证据就越多(假设 A)。这个区域越小,我们已经观察到的(X̅ = 4)就越有可能已经非常极端,并且如此极端,以至于观察到更极端的东西是如此不可能。所以,我们有很多反对现状的证据。计算 p 值意味着计算钟形曲线下的面积,以查看这些极端事件发生的可能性有多大。

让我们也正式计算我们的 p 值:

p = P{Z ≥ z} = P{Z≥ 7.07} ≈ 0。

****边注:我用这个 Z 分表得出 P{Z≥ 7.07} ≈ 0。这些表在推断统计中非常常用,所以请继续将链接加入书签以备将来使用!

现在你可能想知道——多小的 p 值才算足够小?多大的差异才算足够大?为此,我们需要一个预先确定的门槛。请注意,这些阈值是在实验之前确定的,以避免 p-hacking 提前调整阈值以获得所需的最终结果。

这个阈值在统计学上正式称为显著性水*,或 alpha,通常为 5%或 0.05。在不同的情况下,你会看到不同的阈值,例如在医学等更敏感的领域,阈值可能会更低。

拒绝规则是,如果 p 值小于α,我们拒绝 A 而支持 B** 。在我们的例子中,这是真的,所以我们可以继续拒绝 A,并得出结论,我们有足够的证据来支持我们的假设 b。😃**

End Note 1: 在设置 A/B 检验时考虑其他因素的细节我没有赘述,比如选择最佳样本量、检验的功效、效应大小等。这篇文章的目的是专注于解释 p 值,而不是转移到其他话题。

结尾注释 2: 作为一项作业,我会让你观察如果我们观察到 X̅ = 3.2 而不是 X̅ = 4 会发生什么。继续计算这种情况下的 p 值,您也可以绘制图表,给你一个更好的直觉。**你还有足够的证据来否定你的零假设 A 吗?X̅ = 3.2 而不是 X̅ = 4 这一事实如何改变了你的直觉?请在评论中告诉我!👇**

谢谢你陪我走完这段旅程!我希望你喜欢学习 p 值。请随意查看我在中以简单、务实的方式解释统计概念的几篇文章:

  1. 逻辑回归系数的简单解释
  2. 大数定律的关系&中心极限定理
  3. 比较 ML 模型:统计意义与实际意义

另外,请关注我的博客更新。干杯!❤

一个简单的数学自由 PyTorch 模型框架

原文:https://towardsdatascience.com/a-simple-maths-free-pytorch-model-framework-3eedfd738bd4?source=collection_archive---------18-----------------------

喜欢数据科学和深度学习,但被所有的数学和公式搞糊涂了,只想要一个简单的解释和一组例子?我也是。所以现在我们来纠正一下,好吗?

本文的目标是尝试并制作一个简单的可解释的构建 PyTorch 深度学习模型的示例,以给出回归、分类(二元和多类)和多标签分类的示例。

我发现每一种都有几十个甚至几百个例子,但没有一个以相似的方式给出了每一种的例子,并且经常归结为大型的数学公式,所以我在不同的风格和方法之间来回转换,因此我一次又一次地困惑自己,所以我想要一些简单的东西可以重复使用。我还想尽可能简单地完成它们,使用可爱的、随处可得的库和模块,尽可能少地定制“我的解释”。

因此,我不想陷入 EDA、特征工程和所有那些非常重要的东西(我会说比模型更重要),并希望尽可能保持简单和“只是模型的框架”。
考虑到这一点,我们将使用来自 sklearn.datasets 的精彩的 make_regressionmake_classification、make _ multi Label _ classification,从而模拟一旦您为第一个基线模型做好所有 EDA 和功能工程准备,您的数据将处于的状态,这意味着我们将不会进行任何标签编码、解决不*衡等。

我也想完全远离数学。我会解释为什么我们在没有符号、公式和算法的情况下做我们正在做的事情。
这不仅仅是给你一些代码来剪切/粘贴,而是向你展示我在这个过程中遇到的一些错误,从而产生(我希望)一组有用的函数和信息。

我写这篇文章是为了帮助我拥有一个入门笔记本,我可以用它来做各种各样的事情,我希望这样做能帮助到其他人,所以我们开始吧。

准备笔记本

首先,加载相关模块。基本上就torchNumPymatplotlib

from sklearn import metricsfrom sklearn.model_selection import train_test_split
from sklearn.datasets import make_regression, make_classification, make_multilabel_classification
from sklearn.preprocessing import LabelEncoder, StandardScaler, MinMaxScalerimport torch
from torch.utils.data import Dataset, DataLoader
import torch.optim as torch_optim
import torch.nn as nn
import torch.nn.functional as Fimport numpy as np
import matplotlib.pyplot as plt

创建可重复使用的 PyTorch 组件

好了,下一节是我们将在整篇文章中反复使用的函数。我将概述他们做什么,但是损失函数和精度函数的任何细节将随着我们的进展详细解释。

使用 PyTorch 数据集

作为其中的一部分,我们将熟悉并使用 PyTorch 数据集。为什么?嗯,它们提供了一个很好的方法来在我们的数据周围放置一个迭代器,并允许所有的好处,比如干净地批处理数据等等,所以为什么不使用它们呢。

这是建立一个数据库的最低要求,而且都是不言自明的。

我相信你知道,深度学习模型喜欢数字,所以当你准备好数据时,所有的分类特征都已经被编码了。如果它是一个整数,即所有特性的 np.float32 和目标的 np.int64,否则它也是 np.float32。

在这个过程中,它还把我们可爱的 numpy 数组变成了时髦的 PyTorch 张量。

class MyCustomDataset(Dataset):
    def __init__(self, X, Y, scale=False):
        self.X = torch.from_numpy(X.astype(np.float32))
        y_dtype = np.int64 if Y.dtype == np.int64 else np.float32
        if scale: self.y = torch.from_numpy(MinMaxScaler().fit_transform(Y.reshape(-1,1)).astype(y_dtype))
        else:     self.y = torch.from_numpy(Y.astype(y_dtype))

    def __len__(self):
        return len(self.y)

    def __getitem__(self, idx):
        return self.X[idx], self.y[idx]

创建一个简单的 PyTorch 模型

这里我们将创建一个相当简单的模型,因为这不是一篇关于特定问题类型的最佳模型类型的文章。这给你的是构建 PyTorch 模型的类的结构,你可以用你认为合适的任何东西改变/扩展/替换这些模型。

它以输入 X 形状 10(这将是我们在这些例子中使用的数据的大小)开始,并且可以有一个参数传递给它以形成最终的层(y 形状),默认为 1。

class BetterTabularModule(nn.Module):
    def __init__(self, out_features=1):
        super().__init__()
        self.lin1 = nn.Linear(10, 200)
        self.lin2 = nn.Linear(200, 70)
        self.lin3 = nn.Linear(70, out_features)
        self.bn1 = nn.BatchNorm1d(10)
        self.bn2 = nn.BatchNorm1d(200)
        self.bn3 = nn.BatchNorm1d(70)
        self.drops = nn.Dropout(0.3)
    def forward(self, x):
        x = self.bn1(x)
        x = F.relu(self.lin1(x))
        x = self.drops(x)
        x = self.bn2(x)
        x = F.relu(self.lin2(x))
        x = self.drops(x)
        x = self.bn3(x)
        x = self.lin3(x)
        return x

设置一个简单的优化器

对于所有这些问题,我们将坚持使用 Adam 优化器。看起来很合适。

def get_optimizer(model, lr=0.001, wd=0.0):
    parameters = filter(lambda p: p.requires_grad, model.parameters())
    optim = torch_optim.Adam(parameters, lr=lr, weight_decay=wd)
    return optim

现在一个简单的训练功能,训练循环和评估功能

这些是使用 PyTorch 的标准方法,所以让我们将它们放在函数中,并在整个过程中使用它们。唯一需要改变的是,是的,你已经猜到了,损失函数,它将作为一个参数传入,还有精度函数。

def train_model(model, optim, train_dl, loss_func):
    # Ensure the model is in Training mode
    model.train()
    total = 0
    sum_loss = 0 for x, y in train_dl:
        batch = y.shape[0]
        # Train the model for this batch worth of data
        logits = model(x)
        # Run the loss function. We will decide what this will be when we call our Training Loop
        loss = loss_func(logits, y)
        # The next 3 lines do all the PyTorch back propagation goodness
        optim.zero_grad()
        loss.backward()
        optim.step()
        # Keep a running check of our total number of samples in this epoch
        total += batch
        # And keep a running total of our loss
        sum_loss += batch*(loss.item())
    return sum_loss/totaldef train_loop(model, epochs, loss_func, lr=0.1, wd=0.001):
    optim = get_optimizer(model, lr=lr, wd=wd) train_loss_list = []
    val_loss_list = []
    acc_list = [] for i in range(epochs): 
        loss = train_model(model, optim, train_dl, loss_func)
        # After training this epoch, keep a list of progress of the loss of each epoch 
        train_loss_list.append(loss)
        val, acc = val_loss(model, valid_dl, loss_func)
        # Likewise for the validation loss and accuracy (if applicable)
        val_loss_list.append(val)
        acc_list.append(acc)
        if acc > 0: print("training loss: %.5f     valid loss: %.5f     accuracy: %.5f" % (loss, val, acc))
        else:       print("training loss: %.5f     valid loss: %.5f" % (loss, val))

    return train_loss_list, val_loss_list, acc_listdef val_loss(model, valid_dl, loss_func):
    # Put the model into evaluation mode, not training mode
    model.eval()
    total = 0
    sum_loss = 0
    correct = 0 for x, y in valid_dl:
        current_batch_size = y.shape[0]
        logits = model(x)
        loss = loss_func(logits, y)
        sum_loss += current_batch_size*(loss.item())
        total += current_batch_size # All of the code above is the same, in essence, to Training, so see the comments there # However the functions to assess Accuracy change based on the type of problem we are doing.
        # Therefore the following lines will make more sense as we progress through the article. # Accuracy for Binary and Multi-Class Classification
        if loss_func == F.cross_entropy:
          # Find out which of the returned predictions is the loudest of them all, and that's our prediction(s)
          preds = logits.sigmoid().argmax(1)
          # See if our predictions are right
          correct += (preds == y).float().mean().item() # Accuracy for Multi-Label Classification
        if loss_func == F.binary_cross_entropy_with_logits:
          # Find out, of ALL the returned predictions, which ones are higher than our test threshold (50%), and they are our predictions
          preds = logits
          correct += ((preds>0.5) == y.bool()).float().mean().item() return sum_loss/total, correct/total

现在一个小函数来查看结果。

def view_results(train_loss_list, val_loss_list, acc_list):
  plt.figure()
  epochs = np.arange(0, len(train_loss_list))
  plt.plot(epochs-0.5, train_loss_list) # offset by half an epoch as Training calculated mid epoch but val calculated at end of epoch
  plt.plot(epochs, val_loss_list)
  plt.title('model loss')
  plt.ylabel('loss')
  plt.xlabel('epoch')
  plt.legend(['train', 'val', 'acc'], loc = 'upper left')
  plt.show()

  if acc_list[0]:
    plt.figure()
    plt.plot(acc_list)
    plt.title('accuracy')
    plt.ylabel('accuracy')
    plt.xlabel('epoch')
    plt.legend(['train','val', 'acc'], loc = 'upper left')
    plt.show()

回归

好的,让我们从回归模型开始。具有 10 个特征的 1000 个样本,其中 8 个是信息性的(即,在模型/预测中实际有用的数量),让我们进行 80/20 训练测试分割。

X, y = make_regression(n_samples=1000, n_features=10, n_informative=8, random_state=1972)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=1972

现在将它们加载到我们的 PyTorch 数据集,并在 PyTorch 数据加载器中将它们分成 256 个大小的批次。

train_ds = MyCustomDataset(X_train, y_train, scale=True)
valid_ds = MyCustomDataset(X_val, y_val, scale=True)batch_size = 256
train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True)
valid_dl = DataLoader(valid_ds, batch_size=batch_size, shuffle=True)

如果我们愿意的话,我们可以看看这些,看看他们玩得好不好。

train_features, train_labels = next(iter(train_dl))
train_features.shape, train_labels.shape
(torch.Size([256, 10]), torch.Size([256, 1]))train_features[0], train_labels[0]
(tensor([ 0.8939, -1.0572, -2.1115,  0.9993, -0.4022, -0.7168, -0.1831,  0.3448, -0.6449, -0.4287]), tensor([0.5383]))

现在开始训练

回归是我们这里最简单的问题类型。

让我们建立我们的模型。对于输出目标的数量,我们可以坚持默认值 1。

我们这里的损失函数是 MSE 损失。(MSE 代表均方误差,基本上就是我们的预测与 y 目标相比有多“错误”)。这是回归问题的一个很好的起点,所以让我们用它来训练。

我们无法计算回归模型的准确性,因为回归模型的性能必须报告为回归预测中的错误。

model = BetterTabularModule()
train_loss_list, val_loss_list, acc_list = train_loop(model, epochs=10, loss_func=F.mse_loss)
view_results(train_loss_list, val_loss_list, acc_list)

很好,是吧?

分类—单一类别

好了,现在让我们来看一个分类模型。具有 10 个特征的 1000 个样本,其中 8 个是信息性的(也就是说,在模型/预测中实际有用的数量),让我们再次进行 80/20 训练测试分割。

X, y = make_classification(n_samples=1000, n_classes=2, n_features=10, n_informative=8, n_redundant=0, random_state=1972)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=1972

现在将它们加载到我们的 PyTorch 数据集,并在 PyTorch 数据加载器中将它们分成 256 个大小的批次。

train_ds = MyCustomDataset(X_train, y_train)
valid_ds = MyCustomDataset(X_val, y_val)batch_size = 256
train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True)
valid_dl = DataLoader(valid_ds, batch_size=batch_size, shuffle=True)

现在训练

二元分类(例如,是/否)比回归稍微复杂一点,但不会太复杂。

让我们建立我们的模型。我们需要为输出目标的数量传入 2。首先是答案是第一个选项的概率。第二个是它是第二个选项的概率。

我知道你在想什么。为什么不只有一个输出,并根据它接* 0 或 1 的程度给出我们的答案呢?是的,我们可以这样做,但我认为这种方式更好,原因将变得清楚。

我们这里的损失函数是交叉熵损失(F.cross_entropy ),它的基本功能是返回每个答案的概率。它通过在内部将 log_softmax(一条漂亮的 sigmoid 曲线中的所有值和整行值的总和为 1)和 nll_loss(根据适当的目标标签选择适当的损失)组合成一个函数来实现这一点。

对于分类,我们只关心哪个返回的预测是最响亮的,这就是我们的预测。我们可以使用 logits.argmax(1)来基本上说明 F.cross_entropy 的预测行中的哪一项是最大值。

然后,为了查看我们的预测是否正确,我们将所有预测与实际目标(y)进行比较,并返回正确的数字:(preds == y)。浮动()。*均值()。项目()。这是分类问题的一个很好的起点,所以让我们用损失函数进行训练,用准确度函数进行验证。

model = BetterTabularModule(2)train_loss_list, val_loss_list, acc_list = train_loop(model, epochs=100, loss_func=F.cross_entropy, lr=0.001, wd=0.001)view_results(train_loss_list, val_loss_list, acc_list)

一点都不差!!

分类—多类

好了,现在让我们来看一个多类分类模型。具有 10 个特征的 1000 个样本,其中 8 个是信息性的(即,在模型/预测中实际有用的数量),同样具有 80/20 训练测试分割。

X, y = make_classification(n_samples=1000, n_classes=3, n_features=10, n_informative=8, n_redundant=0, random_state=1972)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=1972)

现在将它们加载到我们的 PyTorch 数据集,并在 PyTorch 数据加载器中将它们分成 256 个大小的批次。

train_ds = MyCustomDataset(X_train, y_train)
valid_ds = MyCustomDataset(X_val, y_val)batch_size = 256
train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True)
valid_dl = DataLoader(valid_ds, batch_size=batch_size, shuffle=True)

现在列车

多类分类(比如狗/猫/马)比二元分类难多了。

笑话!!!一点也不,因为我们用二元分类法做的。想想看,我们建立的模型有两个输出目标。第一个是答案是第一个选项的概率。第二个是它是第二个选项的概率。

那么,我们真的需要现在就用更多的输出目标来构建模型,并让我们的损失函数和准确度与我们使用二元分类时完全相同吗?

没错。!

告诉过你这很容易。

model = BetterTabularModule(3) # Now we want 3 outputs
train_loss_list, val_loss_list, acc_list = train_loop(model, epochs=100, loss_func=F.cross_entropy, lr=0.001, wd=0.001)
view_results(train_loss_list, val_loss_list, acc_list)

分类—多标签

X, y = make_multilabel_classification(n_samples=1000, n_features=10, n_classes=3, n_labels=1, allow_unlabeled=False, random_state=1972)
# This returned mimicked one hot encoded data, but we need those as Floats, not Integers for our Accuracy Function
y = y.astype(np.float32)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=1972)

现在将它们加载到我们的 PyTorch 数据集,并在 PyTorch 数据加载器中将它们分成 256 个大小的批次。

train_ds = MyCustomDataset(X_train, y_train)
valid_ds = MyCustomDataset(X_val, y_val)batch_size = 256
train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True)
valid_dl = DataLoader(valid_ds, batch_size=batch_size, shuffle=True)

现在列车

我们这里的损失函数是 f . binary _ cross _ entropy _ with _ logits loss,它只是在 BCE 损失之前做一个 sigmoid,因此最终因为我们可以有一个以上最响亮的激活(因为它可以是多标签),所以我们希望让它们通过 sigmoid,并基于阈值来识别它们是否正确。即:正确+= ((preds>0.5) == y.bool())。浮动()。*均值()。项目()

model = BetterTabularModule(3)
train_loss_list, val_loss_list, acc_list = train_loop(model, epochs=50, loss_func=F.binary_cross_entropy_with_logits, lr=0.001, wd=0.001)
view_results(train_loss_list, val_loss_list, acc_list)

同样,我认为这在样本数据上训练和验证得非常好。

一路上的教训

在把这些放在一起的过程中,我遇到了各种各样的错误和问题,下面我整理了一些。其原因是,当你(希望)利用这一点创建自己的模型,改变损失函数或精度函数,甚至当然只是使用自己的数据时,你可能会遇到相同或类似的问题。

目标 2 出界。

  • 这是因为当我创建我的模型时,我没有改变一个输出目标的默认值。所以一旦 a 尝试了一个分类模型,我就得到错误
    通过将 2 传递给函数来建立我的模型,我正在纠正我的错误,并确保我的模型有两个可能的结果目标

我的训练看起来很*静,没有什么事情发生

  • 我错误地没有重置我的模型,所以这个训练是在我已经做过的训练之上的,所以看起来根本没有什么不同

RuntimeError:张量 a (256)的大小必须与非单一维度 1 的张量 b (3)的大小相匹配

  • 在多标签分类中,我使用 argmaxing 而不是 sigmoid,因此,对于所有目标,我没有获得介于 0 和 1 之间的良好概率,而是像我对标准分类所做的那样,再次选择最响亮的目标

结论

现在你知道了。一个简单的 PyTorch 用例的不同问题类型及其方法的例子,您可以根据您的问题需求对其进行扩展。

我希望这有所帮助。

Python 中数值积分的一种简单方法

原文:https://towardsdatascience.com/a-simple-method-for-numerical-integration-in-python-7906c1703af8?source=collection_archive---------1-----------------------

在本文中,我们将介绍一种用 python 计算积分的简单方法。我们将首先导出积分公式,然后在 python 中的几个函数上实现它。这篇文章假设你对概率和积分有基本的了解,但是如果你没有,你可以直接跳到例子。尽情享受吧!

衍生物

我们必须首先说明连续随机变量的期望值的定义。

假设 X 是一个概率密度函数为 f(x)的随机变量。X 的期望值定义如下:

X 的期望值

接下来,我们使用期望公式来推导一个计算积分的简单方程。我们想估计以下积分:

函数 g(x)从 a 到 b 的积分

我们首先将积分改写如下:

然后,我们可以将函数 h(x)定义为:

这允许我们以熟悉的形式重写积分:

积分中的所有计算都被简化为一个期望值,我们知道如何找到一组数据的期望值。最终*似值变为:

Python 示例 1:积分初等函数

我们从简单的从 0 到 1 积分二次函数 f(x) = x 开始。

# Dependencies
import numpy as np
import scipy.integrate as integrate
import matplotlib.pyplot as plt# Our integral approximation function
def integral_approximation(f, a, b):
    return (b-a)*np.mean(f)# Integrate f(x) = x^2
def f1(x):
    return x**2# Define bounds of integral
a = 0
b = 1# Generate function values
x_range = np.arange(a,b+0.0001,.0001)
fx = f1(x_range)# Approximate integral
approx = integral_approximation(fx,a,b)
approx

我们的积分*似值为:

这是我们所期望的,因为积分的真实值是 1/3。然而,我们也可以将我们的结果与 Scipy 的“quad”函数进行比较。

# Scipy approximation
integrate.quad(f1,a,b)

结果值:

我确信这个例子让你坐立不安,但是让我们看看我们是否能集成一个更复杂的函数。

Python 示例 2:整合高斯函数

高斯函数因极难积分而臭名昭著。在这个例子中,我们将通过整合标准正态分布来测试我们的方法。

# Integrating a random function
np.random.seed(42)def gaussian(x, mu, sigma):
    return np.exp((-1*(x - mu)**2) / (2 * sigma**2))# Define mu and sigma
mu = 0
sigma = 1# Define bounds of integral
a = -3
b = 3# Generate function values
x_range = np.linspace(-3,3,200)
fx = gaussian(x_range, mu, sigma)

结果函数如下所示:

我们的积分*似法的好处是,函数的复杂性确实会影响计算的难度。在任何情况下,我们需要的只是积分的边界和函数值。

# Our approximation
approx = integral_approximation(fx,a,b)
approx

与 Scipy 解决方案相比:

# Scipy approximation
integrate.quad(lambda x: np.exp((-1*(x - mu)**2) / (2 * sigma**2)),a,b)

我希望你觉得这篇文章简单易懂而且有趣!

谢谢大家!

喜欢我的文章吗?请我喝杯咖啡:https://www.buymeacoffee.com/HarrisonfhU

独立于模型的分数解释

原文:https://towardsdatascience.com/a-simple-model-independent-score-explanation-method-c17002d66da7?source=collection_archive---------27-----------------------

如何为任何模型分数生成的案例级解释

T 机器学习(ML)应用的指数级增长以及模型在许多生产应用中的嵌入推动了对解释这些模型的可解释性和透明性的需求。在这篇文章中,我提出了一种简单的方法来提供对模型分数的案例级解释——即:哪些输入特征导致了特定案例的预测分数或记录的增加或减少?

照片由 Siora 摄影在 Unsplash 上拍摄

介绍

在数据科学中,我们处理统计和机器学习模型的广泛工具箱,从最简单的回归到最复杂的深度学习神经网络架构。此外,在当今数据丰富的世界中,具有数百个输入特征的模型并不罕见,这增加了通常产生单一输出信号的机器的整体复杂性,即指示某事是真还是假,或者预测连续测量。

在许多情况下,最终预测可以推动关键行动,或者为人类决策提供信息。例如,我在税务合规领域的 ML 应用领域进行了大量工作,使用模型自动对数百万份个人纳税申报单进行评分,以识别可疑的申报单,供进一步检查。在这种情况下,仅仅有一个模型级的特性重要性的解释是不够的(在许多开源包中都有);相反,我们需要一些案例层次的解释来解释模型预测。具体来说,如果给定输出类的概率很高(或很低),我们需要提供一个我们认为导致模型做出特定决定的要素列表。这可以帮助用户获得对预测的信心,并帮助推动进一步的决策。

ML 模型被使用的地方越多,对可解释性的需求就越大。例如,在大多数欺诈检测应用中,能够支持拒绝单个交易的决策是非常重要的。显然,这同样适用于大多数类型的信用评分,在这种情况下,重要的贷款决策是在整体模型评分的基础上做出的。通常,分数解释对于最终用户获得对模型的信心并推动采用是至关重要的。当 ML 模型被引入到历史上依赖于专家知识和直觉的现有过程中时,这是特别真实的。

不是每个 ML 模型都需要可解释性。当模型驱动高度自动化的决策时,如流程控制、直接营销、内容推荐等。在应用程序的调优和调试过程中,模型输出的案例级解释可能更有用,但对操作来说用处不大。

一般来说,当分数影响到个别案例时,解释是有用的。当模型分数只影响一个大规模的过程时,单独的解释只适用于在过程中具有启发性或历史性专业知识的人。

这些仅仅是多希-维勒兹和金在这篇论文中陈述的 ML 模型的可解释性的一般问题的几个例子,该论文提供了该问题的一般框架和定义。

可解释的模型?

在数据科学中可用的各种模型类型中,有些被认为比其他模型更适合“解释”——但是我们真的能这样说吗?比如分类,我能想到的最基本的框架大概就是 Logistic 回归模型。这里,除了最后的非线性单调变换,预测基本上是根据输入的线性函数计算的。

因此,可以用每个特征的系数乘以特征本身的值的乘积来量化每个特征对最终得分的贡献。够简单吗?事实上,在大多数情况下,这将是可行的,尤其是在某些假设为真的情况下,即特征是独立的(无共线性)和标准化的,因为偏差项可能会使模型的解释变得复杂。当一个模型有许多特征时,完全没有共线性是不可能的,因此,即使是最简单的可用模型的可解释性也成问题。

决策树,至少在其最简单的形式中,也被认为是“可解释的”,因为它们可以从数据中推断出定义良好的决策规则。同样,这在理论上是正确的,特别是如果我们控制树的深度,从而限制每个规则中的前提条件的数量。但是在实践中,为了使模型达到合理的准确性,决策树通常会产生大量的“深层”规则。除此之外,规则是人类可读形式的事实并不总是意味着这些规则也是可解释的

虽然一般来说,更简单类型的模型和具有更少变量的模型可能更容易解释,但这种准确性/可解释性权衡在给定的应用程序中可能不容易协商,或者至少不需要一些努力。例如,我经常发现自己不得不“简化”复杂的模型,纯粹是为了可解释性。虽然执行模型缩减对于获得泛化和限制过度拟合很重要,但是缩减模型以使其更易解释并不总是容易的,或者是可能的。即使驯服一个“简单”的逻辑模型来减少变量,降低共线性,并使系数更容易解释,同时保持其准确性,也是一项艰巨的工作。

案例级模型解释技术

在我提出这个高度简化的方法来提供模型输出的案例级解释之前,让我们回顾一下文献中已经提出的一些更复杂的技术。

作为一般背景,我强烈推荐谷歌关于人工智能可解释性的白皮书,它很好地概述了这个主题,并讨论了在谷歌云中实现的解决方案(充分披露:我在谷歌工作,但这不是为了宣传我们的服务,我只是认为这是一篇很好的文章)。具体来说,本白皮书中用于描述在实例级别“解释”ML 模型分数的能力的术语是特征属性 (FA)。FA 是一个有符号的连续值,表示在分数的特定实例中,任何单个输入要素对模型输出的贡献程度。

谷歌用于 FA 的技术是基于由劳埃德·沙普利首先引入的博弈论概念,被称为沙普利值(SV)。由 Christopher Molna r 撰写的关于可解释机器学习的优秀在线书籍中有一节专门介绍了 Shapley Values ,该书对这种方法进行了出色的概述。SV 方法有几个优点:

  • 它是独立于模型的:它可以应用于任何“黑盒”模型,因为它只需要对从数据集中抽取的例子进行评分的能力。
  • 有一个清晰的解释:对于一个给定的实例,每个输入特征的 SV 表示实例得分与总体*均得分之间的差异部分,这可以通过该特征假设其特定值来解释。
  • 完整性:保证所有特征的所有 SV 之和与分数的边际差与其基线相匹配。

这种方法的缺点是计算 Shapley 值所涉及的计算复杂性随着特征的数量呈指数增长,使得它不可能以其原始形式应用于现实世界的问题。然而,一些方法可以通过采样来*似计算 SV。

另一种流行的模型解释方法是 LIME ,最早出现在 2016 年。在高层次上,LIME 通过用可解释的模型(例如,回归)局部*似任何黑盒模型来工作。这是通过用从黑盒模型生成的数据训练*似模型来完成的,通过从被解释的实例的值扰动其输入来实现。LIME 也是一种独立于模型的方法,但是它对问题采取了与 SV 方法完全不同的态度。石灰和 SHAP (一种基于沙普利原理的方法)的比较见本帖。

请注意,上面提到的方法比这篇文章中提到的方法要复杂得多,理论上也更加合理。然而,我们的方法很容易实现,并且在实践中运行良好。对于负责根据分数采取行动的人来说,这也可能更容易理解。也就是说,我会确保强调那些可能不太好的情况。

一种简单的独立于模型的方法

给定一个模型 M ,让我们假设我们可以对数据集 X 进行评分,该数据集包含一个记录样本,该样本包含 M 所需的所有输入特征。该数据集可以是训练数据本身,模型 M 基于该数据集进行估计,或者是保留集,或者是完全不同的样本。唯一的要求是 X 提供一个合理的输入空间表示,在这个空间内 M 将在生产中运行。

接下来,我们将 M 应用于数据集 X ,产生分数 Y 的向量。注意,我们不需要目标的实际真值,也不需要知道关于 M 的任何细节——我们需要给定输入数据集 XM 产生的分数。

对于每个输入特征 J ,我们做如下操作:

  • 对于分类特征:计算 J 的每个不同值的 Y 的*均值。我们还可以计算标准偏差,因为它提供了额外的有用信息。
  • 对于连续/数值特征:应用任何合理的宁滨方法(如等频宁滨)首先离散变量 J 。然后,计算与分类变量相同的分数统计。

然后我们计算一个比率, Zj ,即 Y 的*均值与JY的总体*均值之间的比率。该比率表示当输入 J 采用特定值 Ji 时,整个数据集中得分的*均变化。我们还可以计算出 J = Ji 时得分的标准差与 Y 跨总体的标准差之比。姑且称这个值为 Vj

上述过程的输出可以看作是一个简单的查找表。作为一个例子,这里我们将一个简单的逻辑回归模型(我们可以使用任何其他类型的模型)拟合到众所周知的 UCI 人口普查收入数据集。然后,我们为模型的每个输入计算了 ZjVj 值。结果示例如下所示,由于篇幅限制,我只显示了 11 个模型输入中 4 个的计算值。请注意,对于连续输入,如年龄教育编号,添加离散化仅用于此评估方法——这些输入不是为了创建模型而离散化的。事实上,这种方法完全独立于输入是如何在模型“内部”具体转换的,因为它只取决于模型在给定输入向量的情况下生成的分数。颜色编码有助于识别那些对增加(绿色)或减少(红色)模型分数贡献最大的输入/值组合。

UCI 人口普查收入数据集模型的模型说明表示例(图片由作者制作)

给定一个实例 I ,我们可以根据每个输入 J 的对应值 检索一组对应的 ZjVj 值。第一组数字, Zj,代表输入 J 假设值 Ji 对分数的*均影响;高于 1.0 的值表示 J = Ji 增加分数(正贡献),低于 1.0 的值表示反而有助于降低分数(负贡献)。【Zj】值的相对比例为我们提供了对【J】输入的贡献差异的指示,例如 I

因此,给定一个实例 I ,我们可以检索 Zj 分数,并使用它们根据它们的值对输入特征进行排序。同样,大于 1.0 的因子代表正贡献,而小于 1.0 的因子代表负贡献。接* 1.0 的 Zj 值表示中性贡献。下面的示例显示了所选数据集的特定记录的模型输入的分级效果,该模型为此产生了很高的分数。

示例 1:高分案例(作者制作的图片)

在第一个示例中,输入的关系排名最高,因为它对获得高于*均水*的分数贡献最大,职业和婚姻状况紧随其后。虽然输入 fnlwgt本国在列表的底部,但是请注意 Zj 分数接* 1.0,这意味着这些输入对该记录分数起着中性作用,而不是负的作用。**

下一个例子是模型产生相对较低的概率分数 0.18 的情况。请注意,在这种情况下,输入的排序完全改变了。相对于这个例子,贡献最大的特性是教育数量每周小时数;然而,在这种情况下,最高的贡献因子仅略高于 1.0,因此接*于“中性”贡献。另一方面,该图解释了低得分的主要驱动因素,在这种情况下,是职业工作类,它们的 Zj 得分在 0.6 左右,推低了整体模型得分。

示例 2:低分案例(作者制作的图片)

Vj 值为实例 I 提供了关于每个输入效果的附加信息。具体来说,它通知我们关于对分数的贡献的可变性,以及因此由 Zj 表示的信息的可靠性。 这也解决了这种方法的主要弱点和局限性——让我们假设,事实上,当 J = Ji 时,分数的分布 Y 实际上是双峰的。

双峰分布的一个例子(来源:Statology.org)

在这种情况下,得分【Y】的*均值将不能恰当地捕捉特征 J 假设值 Ji 对模型输出的典型影响。实际上,类似于这里描述的情况将意味着模型实际上正在捕捉输入特征 J 和一个或多个其他输入特征之间的一些高度非线性的关系。这肯定是可能的,尽管并不常见。所提出的方法将完全不能代表输入特征贡献是强负还是强正的事实,这取决于其他输入特征的值。相反,这是像 SV 或 LIME 中实现的局部估计这样的计算强度大得多的方法可以明确解决的问题。

然而,通过测量当 J 取值时得分 Y 的可变性,并将其与得分的总体可变性进行比较,我们至少可以意识到这样的情况。如果得分可变性相对较高,如在双峰分布的示例中, Vj 值将增加,这表明与具有可比较的 Zj 值但具有较低的 Vj 值的特征相比,效果的差异较大。因此,例如,我们可以使用【Vj】值基于 Zj 值对条形图进行颜色编码,以捕捉特征属性的方向、强度和一致性。

下图提供了模型输入对分数、一致性、可变性或贡献方向的影响的可视化表示示例。

颜色编码的影响图:条形的长度表示对更高分数的贡献强度,而相邻单元格的颜色表示这种贡献的可靠性或一致性(图片由作者制作)

结论

在数据科学中,我们学会处理的许多权衡之一是准确性与复杂性。正如在特征归属的已建立方法的简要概述中所讨论的,存在复杂的方法,其可以在个体实例水*上提供模型分数的更准确的“解释”,包括 Shapley 值和 LIME。虽然这些方法肯定会为更复杂和非线性的模型提供更精确的结果,但这里建议的独立于模型的方法实施起来非常简单,并且可以提供一种快速的解决方案,将“解释因素”添加到模型得分报告中。

我要感谢 Paul McQuesten 在这篇文章的准备过程中对我的支持,特别是在制作这些例子时的帮助。

一个简单的用于歧义消解的 NLP 应用

原文:https://towardsdatascience.com/a-simple-nlp-application-for-ambiguity-resolution-bb698d19aff7?source=collection_archive---------10-----------------------

如何利用 expert.ai 自然语言处理技术解决同形词和多义词的歧义问题

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

歧义是自然语言处理中最大的挑战之一。当我们试图理解一个词的意思时,我们会考虑几个不同的方面,例如使用它的上下文,我们自己对世界的了解,以及一个给定的词在社会中通常是如何使用的。词汇会随着时间的推移而改变意思,在某个领域可能是一个意思,在另一个领域可能是另一个意思。这种现象可以在同形词和多义词中观察到,同形词是指两个单词恰好以相同的方式书写,通常来自不同的词源,而多义词是指一个单词有不同的意思。
在本教程中,我们将看到如何使用 expert.ai 技术解决词性标注和语义标注中的歧义。

开始之前

请查看如何安装 expert.ai NL API python SDK,要么在这篇关于数据科学的文章上,要么在官方文档上,这里。

词性标注

语言是模糊的:不仅一个句子可以用不同的方式来表达相同的意思,就连词条——一个被认为不那么模糊的概念——也可以表达不同的意思。

例如,单词 play 可以指几种不同的事物。让我们来看看下面的例子:
我真的很喜欢这部戏。我在一个乐队里,我弹吉他。

不仅同一个词可以有不同的意思,而且它可以用在不同的角色中:在第一句中, play 是名词,而在第二句中它是动词。给每个单词分配正确的语法标签被称为词性标注,这并不容易。

让我们看看如何用 expert.ai 解决 PoS 歧义性—首先,让我们导入库并创建客户端:

我们将看到两个句子的词性标注——注意,在两个句子中,词条是相同的,但其词性发生了变化:

为了分析每个句子,我们需要创建一个对 NL API 的请求:最重要的参数——也显示在下面的代码中——是要分析的文本、语言和我们请求的分析,由资源参数表示。
请注意,expert.ai NL API 目前支持五种语言(en、it、es、fr、de)。我们使用的资源是消歧,它作为 expert.ai NLP 管道的产品,执行多级标注。
事不宜迟,让我们创建第一个请求:

现在我们需要迭代文本的位置,并检查哪个被分配给了词条:

Part of speech for "The key broke in the lock."

The            	POS: DET
key            	POS: NOUN
broke in       	POS: VERB
the            	POS: DET
lock           	POS: NOUN
.              	POS: PUNCT

上面打印的是跟随 UD 标签的 PoS 列表,其中名词表示词条关键字在这里用作名词。我们在第二个句子中看到的同形异义词不应该是这种情况,其中用作形容词:

Part of speech for "The key problem was not one of quality but of quantity."

The            	POS: DET
key            	POS: ADJ
problem        	POS: NOUN
was            	POS: AUX
not            	POS: PART
one            	POS: NUM
of             	POS: ADP
quality        	POS: NOUN
but            	POS: CCONJ
of             	POS: ADP
quantity       	POS: NOUN
.              	POS: PUNCT

正如您在上面看到的,在这个句子中,词条被正确地识别为一个形容词。

语义标注

一个单词也可以有相同的语法标签,也可以有不同的意思。这种现象被称为一词多义。能够推断每个单词的正确含义就是执行语义标记。

更常见的单词往往有更多的及时添加的含义。比如,引理纸可以有多种含义,这里看到:
我喜欢在纸上做笔记。每天早上,我丈夫都会阅读当地报纸上的新闻。

指出每个词条的正确含义是一项重要的任务,因为一个文档可能会基于此改变含义或焦点。要做到这一点,我们必须依靠发达和强大的技术,因为语义标记严重依赖于来自文本的许多信息。

对于语义标记,通常使用 ID:这些 ID 是概念的标识符,每个概念都有自己的 ID。对于同一个引理,比如论文,我们会用某个 id x 表示其作为材料的意义,用另一个 y 表示其作为报纸的意义。
这些 id 通常存储在知识图中,在知识图中,每个节点是一个概念,而拱形是遵循特定逻辑的概念之间的连接(例如,如果一个概念是另一个的下位词,则拱形可以链接两个概念)。现在让我们看看 expert.ai 是如何执行语义标记的。我们首先选择句子来比较两个引理:

现在是对第一句话的请求—使用与上一个示例相同的参数:

语义信息可以在每个令牌的 syncon 属性中找到:syncon 是一个概念,存储在 expert.ai 的知识图中;每个概念由一个或多个引理构成,这些引理是同义词。
让我们看看信息是如何在文档对象中呈现的:

Semantic tagging for "Work out the solution in your head."

Work out       	CONCEPT_ID: 63784
the            	CONCEPT_ID: -1
solution       	CONCEPT_ID: 25789
in             	CONCEPT_ID: -1
your           	CONCEPT_ID: -1
head           	CONCEPT_ID: 104906
.              	CONCEPT_ID: -1

每个令牌都有自己的 syncon,而其中一些表示为-1 作为概念 id:这是分配给没有任何概念的令牌的默认 ID,比如标点符号或文章。
因此,如果对于前一个句子,我们获得了引理的概念 id 25789,那么对于第二个句子,我们应该获得另一个概念 id,因为这两个引理在两个句子中具有不同的含义:

Semantic tagging for "Heat the chlorine solution to 75° Celsius."

Heat           	CONCEPT_ID: 64278
the            	CONCEPT_ID: -1
chlorine       	CONCEPT_ID: 59954
solution       	CONCEPT_ID: 59795
to             	CONCEPT_ID: -1
75             	CONCEPT_ID: -1
° Celsius      	CONCEPT_ID: 56389
.              	CONCEPT_ID: -1

不出所料,引理对应的是不同的概念 id,说明使用的引理与上一句的意思不同。

请在 GitHub 上找到这篇文章作为笔记本。

结论

NLP 很难,因为语言是模糊的:一个单词、一个短语或一个句子根据上下文可能有不同的意思。利用 expert.ai 等技术,我们可以解决歧义,并在处理词义时建立更准确的解决方案。

强化学习的简单概述

原文:https://towardsdatascience.com/a-simple-outline-of-reinforcement-learning-4c20ddc497c9?source=collection_archive---------33-----------------------

让我们来一次人工智能和控制相遇的旅行

“我们想要的是一台能够从经验中学习的机器。”艾伦·图灵,1947 年

你知道机器(或计算机)是如何在像国际象棋和围棋(DeepMind 的 AlphaGo、AlphaZero 和 MuZero)这样的复杂游戏中超越人类的表现,或者在没有人类干预的情况下驾驶汽车的吗?答案隐藏在它们的编程方式中。这种机器被编程为最大化某些目标,这些目标是由人类明确定义的。这种方法被称为强化学习,完全模仿人类和动物在世界中学习行为。

在这篇文章中,我的目的是解释什么是强化学习和基础知识,而不是太多的细节。

梁杰森在 Unsplash 上的照片

是什么让强化学习如此特别?

今天,机器学习由 3 个主要范例概括。除了有监督学习(SL)和无监督学习(UL),强化学习(RL)形成了第三种也是最后一种。虽然它是机器学习的一个子领域,但它有控制理论和博弈论的缺点。

我们可以把智能代理想象成一种功能,当输入(或观察)时,期望它给出有用的输出(或动作)。学习只是越来越接*给出一个正确的(或有用的)输出。

在二语习得中,智能体被输入和相应的正确输出所反馈,以使它学会给看不见的输入合理的输出。

UL 只给智能体输入信息,并让智能体学会给出一些输出信息,从而优化一个预定义的目标,如紧密度或熵之类的度量。

当代理需要通过在动态环境中反复试验来学习行为时,RL 的问题就出现了。这就是人类和动物如何学习他们的行为,如说话和运动。

学习类型的图解,照片由 IBM 拍摄

不像上面所说的,学习方法不需要严格区分。如果从更大的角度来看,它们都是基于某些目标的优化。*年来,许多成功的人工智能应用是这三种范式的混合,如自监督学习、逆强化学习等。最*在 ML 上的成功隐藏在定义适当的目标,而不是选择 3 种学习类型中的一种。

但是,RL 仍然是唯一的,因为它处理的是动态环境,数据不是事先给定的。因此,与 SL 和 UL 不同,RL 代理应该:

  • 收集数据本身,
  • 探索环境(学习如何收集有用的数据),
  • 利用其知识(学习如何考虑未来状态,学习最佳策略),
  • 辨别后果的原因(过去的哪些行为导致了当前的情况),
  • 在探索过程中保持自身安全(对于机械应用)。

勘探开发困境

如上所述,代理应该利用它的知识来获得最优策略。然而,如果没有足够的环境知识,agent 可能会陷入局部最优解。因此,特工应该同时探索环境。这就出现了勘探-开发的困境,这是 RL 的重要组成部分。许多算法有各种技术来*衡它们。

代理人应该在哪里吃饭?,照片由加州大学伯克利分校 CS188 AI 课程

现在,让我们进入技术细节。

顺序决策

顺序决策或离散控制过程是在离散时间的每个时间步做出决策,考虑环境的动态性。

在时间 t,我们代理人在 sₜ,受到 rₜ奖励,得到 oₜ观察,并根据其政策 π 采取行动 aₜ。作为行动的结果,sₜ₊₁发生状态转变,新观察 oₜ₊₁以回报 rₜ₊₁.

期望观察值代表代理的状态。如果状态可以使用即时观察形成,观察直接用作状态(sₜ=oₜ),这被称为马尔可夫决策过程。如果不能,则称之为部分可观测马尔可夫决策过程,因为即时观测不能完全告知主体状态。然而,我们现在专注于 MDP。

马尔可夫决策过程(MDP)

MDP 由以下部分组成:

  • 状态空间 S,作为所有可能状态的集合。
  • 动作空间 A,作为所有可能动作的集合。
  • 模型函数 T(s'|s,a),作为状态转移概率。
  • 奖励函数 R(s),作为从状态、动作、下一个状态元组到奖励的奖励映射。
  • 贴现因子γ ∈ [0,1],一个实数,决定未来奖励对控制目标的重要性。

马尔可夫决策过程,作者图片

RL 的建筑单元

  • 策略函数π(a|s):取决于状态的行动的概率函数,指示在特定情况下如何行动。
  • 回报 G:未来奖励在时间上的累积总和,按折现因子γ缩放。它被定义为:

返回值

  • 价值函数 V(s|π):状态 s 下遵循策略π时的期望收益,定义为;

价值函数

  • 动作值函数 Q(s,a|π):遵循策略π时的期望收益,除了状态 s 第一步的动作 a,定义为;

动作值函数,又名 Q 函数

贝尔曼方程

RL 的整体目标是最大化价值函数 V,以获得最优策略π*。为此,价值函数必须满足以下贝尔曼方程。贝尔曼方程告诉我们,最优策略必须以隐含的方式使所有可能状态的*均价值函数(未来的累积报酬)最大化。

贝尔曼方程

你可能想知道为什么我们需要 Q 函数。它与政策有着直接的关系。

Q 函数的策略推导

注意,两者都是相互依赖的。那么,为什么我们需要另一个定义呢?通过观察环境和行为的结果,代理可以学习当前策略的 Q 函数。然后,代理可以使用这个等式来改进它的策略。它允许代理在学习 Q 函数的同时,通过学习来改进策略。

无模型强化学习

无模型 RL 纯粹基于经验,没有模型和奖励函数。

照片由 UC Berkeley CS188 AI 课程

蒙特卡罗方法

蒙特卡罗方法使用统计抽样来逼* Q 函数。为了使用这种方法,必须等到模拟结束,因为每个状态都使用将来的累积奖励总和。

一旦 sₜ被访问,并采取行动 aₜ,回报 Gₜ是计算从其定义使用即时和未来奖励等待结束的一集。蒙特卡罗方法旨在最小化所有可能样本的 Q(sₜ,aₜ和目标值 Gₜ之间的差距。

利用预定的学习速率α,Q 函数被更新为:

蒙特卡洛 Q 更新

时间差分法

目标返回的时间差分(TD)方法 bootstrap Q 函数估计。这允许代理从每个奖励更新 Q 函数。

主要的 TD 方法是 SARSA 和 Q 学习。

  • SARSA 最小化 Q(sₜ,aₜ和目标值 rₜ₊₁+γ Q(sₜ₊₁,aₜ₊₁之间的差距,目标值是收益的自举估计。因为还需要下一个动作,所以它被命名为 SARSA,表示状态、动作、奖励、状态、动作序列。学习率为α时,Q 更新为:

SARSA Q 更新

  • q 学习最小化差距 Q(sₜ,aₜ)和目标值 rₜ₊₁+γ最大 Q(sₜ₊₁),这也是一个收益的自举估计。与 SARSA 不同,它不需要下一个动作,并假设在下一个状态采取最佳动作。学习率为α时,Q 更新为:

Q 学习 Q 更新

基于模型的强化学习

在基于模型的强化学习中,模型和奖励函数要么预先给定,要么通过 SL 方法学习。

基于模型的 RL 依赖于学习模型的质量。

照片由 UC Berkeley CS188 AI 课程

动态规划

动态编程不需要采样。它是在给定模型和报酬函数的情况下解析求解最优策略。

动态编程 Q 更新

基于模拟的搜索

有时,状态和动作空间太大。这使得动态编程不适用。在这种情况下,会生成随机模拟路径。其余的是通常的无模型 RL,可以使用蒙特卡罗或时间差分方法。这种方法唯一优点是代理从它想要的任何状态开始模拟。

蒙特卡洛法、时间差分法和动态规划法之间的比较如下所示。

三种主要方法的备份图,照片由大卫·西尔弗的 RL 课程,第 4 讲拍摄

结论

在大多数应用中,RL 是通过称为深度强化学习的深度学习来结合的。最* RL 的成功与神经网络有关。然而,由于样本学习效率低和安全限制,RL 难以适应真实世界的场景。RL 的未来取决于我们对人类学习方式的掌握。

总的来说,RL 不过是在动态环境中学习。有许多 RL 算法和方法,但我试图给出核心定义和算法,让初学者有一个关于它的想法,保持定义尽可能简单。我希望你喜欢!

作为临时演员,我把 OpenAI 的捉迷藏模拟留给 RL。

寻找商品碳强度的简单 Python 指南

原文:https://towardsdatascience.com/a-simple-python-guide-to-find-carbon-intensity-of-commodities-6f973170f64e?source=collection_archive---------16-----------------------

使用 ResourceTradeEarth 和 ClimateTrace 数据计算碳强度

来自 Pexels 的汤姆·菲斯克的照片

文件和数据

ClimateTrace

  1. 数据

资源贸易地球:

  1. 数据
  2. 文档

此会话中使用的 GitHub 数据集

  1. 数据

外卖食品

建立一个排放估算模型是非常具有挑战性的,即使应用于高质量的数据集,由于必须做出大量的假设。由于缺乏准确性、清晰度和对数据的理解,这种分析很难用于决策目的。

目前的方法是从交易的重量/价值,而不是生产/消费,得出碳强度。因此,这将导致对碳强度的更高估计。

它将主要作为将来如何使用 Python 对类似数据集进行分析的指南。

介绍

排放数据一直很难估计。迄今为止,大多数排放清单都是基于自我报告的。报告的排放数据往往有很大的时滞,估算的方法也往往相互不一致。Climate TRACE 的任务是使用人工智能(AI)和机器学习(ML)技术为卫星/传感器数据提供每个部门的最新排放数据。

据推测,碳排放可以通过关于每种商品的生产水*和每个不同国家在生产商品时的局部碳强度的足够信息来准确确定。然而,这两种数据都很难获得。

我的方法是,通过将发现的排放量与交易的商品进行对比,找到与商品相关的*均碳强度,从而逆向计算方程式。

数据分析

助手函数和库

import warnings
import numpy as np 
import pandas as pd
import plotly as py
import seaborn as sns
import statistics as stat
from datetime import dateimport plotly.express as px
import plotly.graph_objs as go
warnings.filterwarnings("ignore")
pd.set_option('display.max_columns', None)import plotly.offline as pyo
pyo.init_notebook_mode()import matplotlib.lines as lines
import matplotlib.pyplot as plt%matplotlib inline

显示/隐藏按钮

import random
from IPython.display import HTMLdef hide_toggle(for_next=False):
    this_cell = """$('div.cell.code_cell.rendered.selected')""" ; next_cell = this_cell + '.next()';
    toggle_text = 'Code show/hide'  # text shown on toggle link
    target_cell = this_cell ;  js_hide_current = ''if for_next:
        target_cell = next_cell; toggle_text += ' next cell';
        js_hide_current = this_cell + '.find("div.input").hide();'
    js_f_name = 'code_toggle_{}'.format(str(random.randint(1,2**64)))html = """<script>
            function {f_name}() {{{cell_selector}.find('div.input').toggle(); }}
            {js_hide_current}
        </script>
        <a href="javascript:{f_name}()">{toggle_text}</a>
    """.format(f_name=js_f_name,cell_selector=target_cell,js_hide_current=js_hide_current, toggle_text=toggle_text )
    return HTML(html)hide_toggle()

ClimateTrace 的排放数据

file = 'climatetrace_emissions_by_subsector_timeseries_interval_year_since_2015_to_2020.csv'df = pd.read_csv(PATH + file)df[‘year’] = pd.DatetimeIndex(df[‘start’]).year
df[‘month’] = pd.DatetimeIndex(df[‘start’]).monthco2 = pd.DataFrame( df.groupby(['sector', 'subsector', 'year'])['Tonnes Co2e'].sum() ) \
.reset_index() 
    # wow magic linepd.set_option('display.max_rows', 250)
co2

作者图片

def make_bar_plot(data, xdata, ydata, cdata, title, legend=True, width=900, height=600):
    import plotly.express as pxfig = px.bar(data, 
                 x= xdata, 
                 y= ydata, 
                 color= cdata, 
                 )fig.update_layout(
        title= title,
        xaxis_tickfont_size=14,
        yaxis=dict(
            title='',
            titlefont_size=16,
            tickfont_size=14,
        ),
        legend=dict(
            x=0.995,
            y=0.98,
            bgcolor='rgba(255, 255, 255, 0)',
            bordercolor='rgba(255, 255, 255, 0)',
        ),
        showlegend= legend,
        height= height,
        width= width,
        barmode='group', #'stack',
        bargap=0.25, 
        bargroupgap=0.1 
    )fig.show()

hide_toggle()

按国家

make_bar_plot(df[ df['country'].isin(['USA']) &  df['year'].isin([2015, 2016, 2017, 2018, 2019]) ], 
              xdata='year', 
              ydata='Tonnes Co2e', 
              cdata='sector', 
              title='Co2 Emissions by USA')

作者图片

图表中的数字应该与 Climate TRACE live 网站上的数字完全一样。我们可以尝试更进一步,深入到每个部门和子部门。

按部门和分部门

make_bar_plot(co2[ co2['year'].isin([2015, 2016, 2017, 2018, 2019]) ], 
              xdata='year', 
              ydata='Tonnes Co2e', 
              cdata='sector', 
              title='Co2 Emissions by Sector')

作者图片

make_bar_plot(co2[ co2['sector'].isin(['agriculture']) &  co2['year'].isin([2015, 2016, 2017, 2018, 2019]) ], 
              xdata='year', 
              ydata='Tonnes Co2e', 
              cdata='subsector', 
              title='Co2 Emissions by Subsector (Agriculture)')

作者图片

资源贸易地球的商品贸易数据

ResourceTradeEarth 按年份提供商品交易价值和重量的数据。该网站是由查塔姆研究所开发的,他们的数据是从国际商品贸易统计(IMTS)中获得的精确版本。

随后,IMTS 数据由国家海关当局收集,并由联合国统计司编入联合国商品贸易统计数据库。

现在我们已经有了来自 Climate TRACE 的排放数据,我们的目标是通过将商品部门从 Climate race 结果产生的排放量除以从 ResourceTradeEarth 获得的交易价值/重量结果来估计每种商品的排放强度。

export = pd.read_csv(PATH + SUBPATH + 'rte-exporters-2019.csv', 
                     encoding= 'ISO 8859-1')
importe= pd.read_csv(PATH + SUBPATH + 'rte-importers-2019.csv', 
                     encoding= 'ISO 8859-1')commodities = pd.read_csv(PATH + SUBPATH + 'rte-commodities-2019.csv', 
                          encoding= 'ISO 8859-1')commodities.drop(['Exporter M.49', 'Exporter ISO3', 'Exporter region', 
                  'Importer M.49', 'Importer ISO3', 'Importer region'], axis=1, inplace=True)trend = commodities.sort_values(by=['Resource', 'Year'], ascending=True)# Create differenced column
trend['dvalue_share'] = trend.groupby('Resource')['value share'].diff()
trend['dweight_share'] = trend.groupby('Resource')['weight share'].diff()

按重量绘图

make_bar_plot(commodities, 'Year', 'Weight (1000kg)', 'Resource', 'Weight (1000kg) Traded by Commodities')

作者图片

按价值/重量份额绘图

使用以下等式估算以下变量:

价值份额 _2015 =资源价值 _2015 /价值总和 _2015

权重份额 _2015 =资源权重 _2015 /权重总和 _2015

这个想法是不同的商品在生产和交易过程中有不同的碳强度。我们想知道我们的商品贸易中有多大比例是高碳密度的。

make_bar_plot(commodities, 'Year', 'value share', 'Resource', 'Value Share By Traded Commodities')

作者图片

make_bar_plot(commodities, 'Year', 'weight share', 'Resource', 'Weight Share By Traded Commodities')

作者图片

按商品和年份分列的价值/重量份额的变化

如果企业的目标是利润最大化,同时排放最少,一些人可能会对按交易价值计算的碳强度感兴趣。然而,这很容易被大宗商品价格扭曲。

如果一种商品的交易价值份额下降,而交易重量份额保持不变或上升,这意味着价格对该商品越来越不利。

trend

作者图片

def make_line_plot(data, xdata, ydata, cdata, title, legend=True, width=900, height=600):
    import plotly.express as pxfig = px.line(data, 
                  x= xdata,
                  y= ydata, 
                  color= cdata, 
                  symbol= cdata,
                 )fig.update_layout(
        title= title,
        xaxis_tickfont_size=14,
        yaxis=dict(
            title='',
            titlefont_size=16,
            tickfont_size=14,
        ),
        legend=dict(
            x=1.02,
            y=0.98,
            bgcolor='rgba(255, 255, 255, 0)',
            bordercolor='rgba(255, 255, 255, 0)',
        ),
        showlegend= legend,
        height= height,
        width= width,
    )fig.show()hide_toggle()

价值份额变化

make_line_plot(trend, 
               'Year', 
               'dvalue_share', 
               'Resource', 
               'Value Share Change By Traded Commodities')

作者图片

make_line_plot(trend[ ~trend['Resource'].isin(['Pearls and gemstones']) ], 
              'Year', 
              'dweight_share', 
              'Resource', 
              'Weight Share Change By Traded Commodities')

作者图片

估算商品的碳强度

co2 = pd.DataFrame( df.groupby(['sector', 'year'])['Tonnes Co2e'].sum() ) \
.reset_index() # wow magic line# Agriculture
agri = trend[ trend['Resource'].isin(['Agricultural products']) ]
agri2 = co2[ co2['sector'].isin(['agriculture']) & ~co2['year'].isin([2020]) ]

有了排放和交易数据的信息,我们可以将它们结合到一个数据框架中。这里,我们假设:

  1. Agricultural productsRTE 的商品与agriculture部门的气候微量排放相关。
  2. Fossil fuels商品与oil and gas排放有关。
  3. Metals and minerals商品与extraction排放有关。
agriculture = pd.concat([agri.reset_index(drop=True), 
                         agri2['Tonnes Co2e'].reset_index(drop=True)],
                        axis= 1) 
agriculture['co2 vintensity'] = agriculture['Tonnes Co2e'] / agriculture['Value (1000USD)']
agriculture['co2 wintensity'] = agriculture['Tonnes Co2e'] / agriculture['Weight (1000kg)']# Oil and gas
oil = trend[ trend['Resource'].isin(['Fossil fuels']) ]
oil2 = co2[ co2['sector'].isin(['oil and gas']) & ~co2['year'].isin([2020]) ]fossilfuel = pd.concat([oil.reset_index(drop=True), 
                         oil2['Tonnes Co2e'].reset_index(drop=True)],
                        axis= 1)

fossilfuel['co2 vintensity'] = fossilfuel['Tonnes Co2e'] / fossilfuel['Value (1000USD)']
fossilfuel['co2 wintensity'] = fossilfuel['Tonnes Co2e'] / fossilfuel['Weight (1000kg)']# Metals and Minerals
metal = trend[ trend['Resource'].isin(['Metals and minerals']) ]
metal2 = co2[ co2['sector'].isin(['extraction']) & ~co2['year'].isin([2020]) ]extraction = pd.concat([metal.reset_index(drop=True), 
                        metal2['Tonnes Co2e'].reset_index(drop=True)],
                        axis= 1)extraction['co2 vintensity'] = extraction['Tonnes Co2e'] / extraction['Value (1000USD)']
extraction['co2 wintensity'] = extraction['Tonnes Co2e'] / extraction['Weight (1000kg)']# All commodities
allcomm = pd.concat([agriculture, fossilfuel, extraction], axis=0)
allcomm

作者图片

make_line_plot(allcomm,
              'Year', 
              'co2 wintensity', 
              'Resource', 
              'Carbon Intensity by Weight, by Commodities')

作者图片

make_line_plot(allcomm,
              'Year', 
              'co2 vintensity', 
              'Resource', 
              'Carbon Intensity by Value, by Commodities')

作者图片

结果不令人满意。以下是一些问题:

  1. 金属和矿物的碳强度数据非常低,你实际上从图表中看不出来。原因是来自气候跟踪的开采部门的 CO2 排放数据没有更新,特别是来自煤炭开采部门的数据。
  2. 化石燃料和金属的碳密度数据非常低。尚不清楚我们是否还应包括同样受到这些商品影响的其他部门的排放量。(例如:化石燃料的电力和运输,金属的制造)。
  3. 由于碳强度来源于交易的重量/价值,因此没有考虑国内消费的商品,导致对碳强度的估计要高得多。在我们的图表中,农产品碳强度的上升趋势可能意味着国内对农产品的消费将会增加。
  4. 同一种商品的碳强度在很大程度上取决于生产地。由于垂直农业技术,与欧洲生产的农产品相比,非洲农业单位产量的碳密度可能更高。

虽然我们最终没有做出任何有意义的结论,但我希望这能激励其他人采取更好的方法来处理这个问题。

如果您有任何错误或建议希望引起我的注意,请随时留下任何评论。

参考:

[1]查塔姆研究所(2021),' resourcetrade.earth ',https://resourcetrade.earth/

[2]气候追踪(2021 年),https://www.climatetrace.org/

带有 AWS Lambda + Surprise 的简单无服务器协作过滤器

原文:https://towardsdatascience.com/a-simple-serverless-collaborative-filter-with-aws-lambda-surprise-309413fdf410?source=collection_archive---------20-----------------------

我们将回顾一个使用 Python 的 Surprise 库的内容推荐协作过滤器的简单部署。

图片由朱莉安娜·贝尔纳尔提供

介绍

在电子商务、社交媒体和其他应用中,需要将全部内容的子集与特定用户匹配,以最大化转化率、应用内时间或其他所需指标,这是一个常见要求。

确定向给定用户推荐什么内容的一种可能的方法是推荐被表现出类似内容评级倾向的对等体良好评级的项目。这种方法被称为协同过滤。有几种不同的方法来计算不同项目(视频、产品或其他要推荐的内容)的用户评级之间的相似性。然而,对于这个部署,我们将使用 Python 的 SciKit Surprise ,它带有内置算法。

协同过滤通常分 3 步进行:

  1. 数据的收集和预处理。
  2. 模型的训练。
  3. 生成预测。

在接下来的部分中,我们将讨论如何实现这些步骤。

架构和设置

现有的应用程序堆栈,增加了用于存储结果的 Lambda 和 S3。

先决条件

在我们深入 Lambda 的代码之前,我们需要设置 Lambda 的运行环境。关于要添加推荐算法的应用程序的设置的一些假设:

  1. 该应用程序运行在一个虚拟专用集群(VPC) 中。
  2. 训练模型所需的数据存储在可从 VPC 内部访问的 SQL 数据库中。
  3. 应用服务器可以访问(或者可以被允许访问)S3。

鉴于上述假设,我们可以设置我们的 Lambda,以便它从 SQL 数据库中读取数据,并将结果输出到 S3。这确保它从应用服务器异步运行,如果训练和预测是缓慢的过程,这可能是所期望的。

λ配置

我们将使用 SAM 来部署 Lambda 及其依赖资源。关于山姆的更深入的介绍,请看下面的文章。

https://medium.com/better-programming/private-serverless-rest-api-with-lambda-using-sam-2eb31864b243

先说文件夹结构。我们将有一个应用程序源文件目录,一个用于部署应用程序的脚本目录,以及 SAM 使用的顶层文件,如template.yaml

my-collaborative-filter/
├── cmd/
│   └── deploy.sh
├── src/
│   └── app.py
├── .gitignore 
├── test-event.json
└── template.yaml

template.yaml将如下图所示。

它定义了 3 种资源:

  1. RecommendationFunction是将执行协同过滤的实际 Lambda。
  2. 如果您的数据库限制访问,可能需要一个RecommendationFunctionSecurityGroup。可以将数据库安全组配置为允许来自该特定安全组的访问。
  3. OutputBucket将是我们输出结果的 S3 桶。

注意RecommendationFunction中的Layers规格。由于 Surprise 和psycopg 2(PostgreSQL adapter)不是 Lambda 操作系统包含的 Python 库之一,我们需要在能够将其导入 Lambda 之前添加它。

在下面的文章中,我们将讨论创建这样一个层的可能过程。

https://medium.com/better-programming/creating-a-python-opencv-layer-for-aws-lambda-f2d5266d3e5d

如果您更喜欢在不使用 Docker 的情况下构建该层,您可以使用 EC2 实例在 Python 虚拟环境中安装 Suprise,并将文件复制到该层。在 EC2 实例上安装库的命令如下所示:

python3 -m venv lambda_layer_packages
source lambda_layer_packages/bin/activate
pip install psycopg2 numpy scikit-surprise

λ代码

将放入app.py文件中的完整 Lambda 代码如下所示,带有内嵌注释。

部署

要部署 Lambda,只需运行下面的部署脚本:

sam deploy \
  --template-file template.yaml \
  --stack-name recommender-stack \
  --parameter-overrides RdsPassword=YOUR_PASSWORD \
  --guided

限制

由于该实现被设计为简单的,所以讨论它的一些限制以及如何改进它是很重要的:

最大λ时间限制

截至撰写本文时,Lambda 的最大执行时间为 15 分钟。在包含 5000 个项目和 5000 个用户的数据集上运行接*超时限制。

大部分时间花在预测步骤,因为代码需要为每个用户执行。一旦到达的用户数量足够大,使得 Lambda 超时,我们可以让上面描述的主 Lambda 只执行步骤 1 和 2,并将输出模型(通过pickle)保存到 S3 桶中。然后它会为每个用户排队(使用 SQS )一个作业,这样另一个 Lambdas 系列可以运行并做出预测。

最大磁盘空间

Lambda 被限制在 512MB 的/tmp目录上的最大临时磁盘空间。如果作为 CSV 的数据集超过(或接*)这个数量,您可能需要为 Lambda 附加一个额外的卷,或者更改代码,以便数据集完全存储在内存中。

新用户预测

上述设置只会对至少有 1 个评分的用户进行预测。根据您的设置,有些用户可能没有评级。

如果需要为这些用户推荐,可以推荐全球最好的商品。这可以完全作为一个单独的服务来完成,或者(取决于为协作过滤选择的算法)您可以对不存在的user_id进行预测(例如用户 0 ),并且每当没有对您当前正在寻找的用户的预测时,默认使用该服务。

下面的代码将这个功能添加到现有的 Lambda 中。

非实时

这种方法以一个固定的速率重新训练模型,这个速率至多需要 Lambda 运行的频率。因此,它不适用于必须能够向用户提供自适应推荐的系统。

结论

我们已经回顾了在 AWS 的 Lambda 上使用 Python 的 Suprise 库部署一个简单的推荐算法。该方法可用于测试算法的性能,而无需投入资源来实现全面的解决方案。

如果你有任何问题或只是想聊聊创业、创业、承包或工程,请给我发电子邮件:Paulo @https://avantsoft.com.br/

避免内存不足的简单技巧

原文:https://towardsdatascience.com/a-simple-trick-to-avoid-running-out-of-memory-d45b0a014ceb?source=collection_archive---------28-----------------------

在不丢失数据的情况下减少熊猫内存使用的艺术

当您处理大型数据集时,会面临内存不足的风险。

内存不足的错误尤其令人沮丧,因为在你耐心地等待程序加载完你所有的数据后,你的程序突然崩溃了。

内存不足错误可能需要等待很长时间,然后才发现你的程序已经崩溃了。西格蒙德在 Unsplash 上拍照。

幸运的是,在使用 Python 和 Pandas 时,有大量的最佳实践来克服这个障碍,尤其是在 Itamar Turner-Trauring 的这篇优秀的参考文献中。

本文重点介绍一种简单而有效的技术,即改变 pandas 数据帧的数据类型,使其更有效地存储。

去哪里找

我们将很快讨论如何在 Python 中实现这一点,但是首先,让我们考虑一下幕后发生了什么。

最常见的情况是,三种主要的数据类型可以更有效地表示,因为 Pandas 过于谨慎,分配的内存类型常常容纳比实际需要更多的数据。

漂浮物

您的计算机可以表示特定精度级别的浮点数,这可能远远超出您的需要。如果内存是一个问题,问问你自己你的算法是否需要看到 52 位小数的数字。

NumPy 有各种各样的浮点数据类型,您可以在数据帧中指定自己喜欢的精度级别。

你要求的最低精确度是多少?照片由沃尔坎·奥尔梅斯在 Unsplash 上拍摄。

整数

假设你有人们鞋码的数据。在英国,它们通常介于 2 和 15 之间,所以即使考虑到偶尔的篮球运动员,拥有一个可以存储高达 9223372036854775807 的值的 NumPy 数据类型也是浪费内存。

如果您正在测量鞋号,您真的需要一个可以达到 9223372036854775807 的数据类型吗?Julian Hochgesang 在 Unsplash 上拍摄的照片。

如果您对数据所属的典型范围有很好的感觉,那么您可以选择一种只适应它需要的数据类型。另外,如果你不确定这些数字的范围,你可以使用有用的功能 iinfo 。

用线串

有时你有字符串(或熊猫称之为对象),它们只来自一个独特的可能的值集合。例如,您的数据可能会根据一个固定的列表['蓝色','棕色','绿色','其他']记录一个人的眼睛颜色。事实上,眼睛的颜色可能更微妙,但让我们用这个例子来说明。

将这些表示为字符串是很好的,但是当它们只能是四个值中的一个时,它需要占用内存来一次又一次地存储所有的字符。

简单来说,一个人眼睛的颜色大多属于一个固定的可能颜色列表。Alex Iby 在 Unsplash 上拍摄的照片。

幸运的是,Pandas 有一个分类数据类型,它将每个可能的值映射到一个整数,这样它就不需要每次存储字符串本身来浪费内存,例如{'blue': 0,' brown': 1,' green': 2,' other': 3}。

付诸实践

为了执行这些检查,我编写了一个名为pandas _ dtype _ efficiency的库,可以通过 pip 安装:

pip install pandas_dtype_efficiency

功能很简单:

  1. 取一个现有的数据帧
  2. 检查潜在的内存改进
  3. 将改进应用于现有的数据帧,或者将建议的数据类型存储为字典,以便在加载数据帧时使用。

这里是它的一个短暂停留之旅,但是你可以随意查看这个例子的更多细节这里。

熊猫 _ dtype _ 效率在行动。作者 GIF。

下次您处理一些大数据时,试试这个库;根据您的数据帧,它可以将它们减少到原始内存使用量的 10%左右。

当你在这里的时候

请随意查看我的其他文章:

  • 如何管理初级数据科学家
  • 如何找到正确的集群数量
  • 计算损失函数
  • 排列测试的威力

获取股票基本面数据的简单方法

原文:https://towardsdatascience.com/a-simple-way-to-get-a-stocks-fundamental-data-26506adf1214?source=collection_archive---------5-----------------------

我如何使用 Python 和 API 调用来检索公司的财务报表和收益报告

照片由西格蒙德在 Unsplash 上拍摄

获取或搜集股票数据有时说起来容易做起来难。找到包含适当的相关数据的正确资源或网站可能相当困难。在我的数据科学项目中,在过去几年中,我需要使用许多不同的数据集,其中相当一部分涉及股票数据和分析。

根据我的经验,股票的价格历史是最容易找到和检索的数据之一。通常,我会使用 Yahoo Finance 和附带的 Python 库来访问这些历史价格数据。然而,我发现对于一只股票的基本面数据来说,情况并非如此。

为了找到基本数据,比如财务报表和收益报告,你可能需要进行大量的谷歌搜索和烦人的网络搜索。在我之前的一个项目中,我幸运地发现了一个现已关闭的网站,名为 stockpup.com。这个网站包含了数千种股票的数千行基本面数据。它们都被整齐地组织成一个简单的 CSV 文件,供我下载并用于我的机器学习项目。

由于那个网站不再可用,我不得不在其他地方寻找数据…

在这里注册一个中级会员,可以无限制地访问和支持像我这样的内容!在你的支持下,我赚了一小部分会费。谢谢!

财务数据 API

有许多金融数据 API 可以让你访问股票的基本数据。就我个人而言,我发现并使用了一个网站,它不仅能够提供基本数据,而且可以免费注册,这个网站叫做——【eodhistoricaldata.com】,也被称为 EOD 高清。披露:我从通过上面的链接购买的任何商品中赚取一小笔佣金。

使用这个财务数据 API,我能够从数千家公司检索基本数据。数据已经准备好并可用,但现在我需要将它组织并格式化成我能够使用的熊猫数据框架。为此,我利用 Python 做好了一切准备:

# Libraries
import pandas as pd
from eod import EodHistoricalData
from functools import reduce
from datetime import datetime, timedelta# Importing and assigning the api key
with open("../eodHistoricalData-API.txt", "r") as f:
    api_key = f.read()

# EOD Historical Data client
client = EodHistoricalData(api_key)

有了我提供的 API 键和上面的代码,我就可以开始检索和格式化基础数据了。

获取基础数据

我使用的 API 能够为我提供季度基础数据,如资产负债表、损益表、现金流和收益报告,但它们都整齐地存储在 API 的 return 对象中各自的部分。我需要创建能够访问的功能,然后将所有这些数据整合到一个大的数据框架中。

所以我创建了一个函数,它能够将这些独立的数据转换成它们自己的数据帧,然后将它们合并成一个大的 DF:

在这个函数中,我能够从给定的股票报价机中检索基本数据。如您所见,每个财务报表都存储在我需要访问的特定属性中。一旦我将它们存储到各自的数据框架中,我就可以通过将它们合并在一起来整合它们。我还删除了任何多余的列,比如在我删除它们之前一直重复的“ Date 列,以及任何重复的列。

获取历史价格数据

我发现返回的基本面数据中缺少的一点是当时的股价。我认为这是一条重要的信息。API 也能够很容易地检索历史价格,所以这不成问题,但是我需要将这些价格与我上面创建的数据框架结合起来。

我创建了一个能够检索每日历史价格的函数,并将它们添加到更大的数据框架中:

当我最初将价格添加到数据框架中时,我发现了一个问题,即在较大的 DF 中,某些日期的一些价格数据丢失了。我假设这些日期有时是假日、周末或类似的日子。不管怎样,我只是想知道在财务报表报告日期前后的股票价格。它不需要很精确,事实上,它可能就在报告日期的前一天或后两天。

正如你在上面的函数中看到的,我可以填写周末、假期等。以之前的股价。之后,我将它们添加到最终返回的更大的数据帧中。

获取基本面和价格数据

因为我能够创建两个函数来检索基本面和价格数据,所以我决定将它们压缩成一个函数:

在这个函数中,我合并了前两个函数。我还添加了额外的数据清理选项,提供了在更大的 DF 中删除空值的选择。如果您需要在此数据上训练机器学习模型,并且无法使用数据集中的 n a 值,则此选项可能会很有用。

从多只股票中获取数据

前面的函数在从一个给定的股票行情自动收录器中检索基本数据时都很有用,但是如果我想从不止一只股票中检索数据呢?为此,我创建了以下函数,它允许从多只股票中检索基本面数据:

这是一个相对简单的函数,利用了上面的函数。我需要做的第一件事是交叉引用 API 中可用的代码。这样做是为了防止给定的 ticker 不存在或给得不正确。然后,如果给定的报价器是有效的,那么它将从所有给定的股票中检索基本面数据,并将它们组合成一个更大的 DF,其中包含多个股票的基本面数据。

结束语

通过使用 Python 和这个金融数据 API,我能够轻松地检索几乎任何股票的基本数据。除了对格式化过程进行编码,整个任务相当简单。

随着多只股票的基本面数据准备就绪,我现在可以将这个数据集应用于任何未来的数据科学项目。可以对该数据集使用分类或回归 ML 模型。或者使用 Python 的众多可视化库进行简单的分析。有各种各样的项目可以使用这样的数据集。

另外在 eodhistoricaldata.com 出版

开源代码库

**https://github.com/marcosan93/Medium-Misc-Tutorials/blob/main/Stock-Market-Tutorials/Analyze-Fundamental-Data.ipynb **

一种在 Google BigQuery 中查询表元数据的简单方法

原文:https://towardsdatascience.com/a-simple-way-to-query-table-metadata-in-google-bigquery-92dc7f1edec1?source=collection_archive---------5-----------------------

轻松确定 BigQuery 数据集中的内容,以及哪些表对使用 INFORMATION_SCHEMA 和表进行分析有用

作者照片(使用 Canva.com 创建)

元数据!我打赌你以前可能听说过这个术语,并且可能问过自己它是什么,为什么它很重要。让我们用 Google BigQuery 探索一下这个概念。

在这篇文章中,你会发现:

  • 什么是元数据?
  • 为什么要在 Google BigQuery 中查询表元数据?
  • 如何用 INFORMATION_SCHEMA 和表查询表元数据?

什么是元数据?

许多来源将元数据定义为“关于数据的数据”。但我个人觉得太模糊,难以理解。所以我尝试用通俗的语言来定义元数据。

作者照片(使用 Canva.com 创建)

为什么要在 Google BigQuery 中查询表元数据?

想象一下在 BigQuery 中给我们一个包含很多表的庞大数据集,我们应该查询哪个?我们如何识别哪些表是最新的?每个表是什么时候创建的?每个表中有哪些列?信不信由你,所有这些问题都可以用元数据来回答。

当涉及到查询表元数据时,有许多潜在的解决方案,从 Google Cloud Console 中的简单视图到更复杂的客户端库。但是这里有 3 个最简单和最不需要技术的解决方案。

第一个解决方案是查看数据目录,这是一个元数据集合,旨在帮助我们搜索所有可用的表,评估它们的质量和有用性,然后访问我们认为适合我们分析的任何表。这可能是确定我们应该查询哪些特定表的最简单的方法。但是,如果我们手边没有现成的数据目录,那该怎么办呢?怎么样,棕色的母牛?

作者照片

如上所示,第二个选项在 Google Cloud Console 中很容易找到。是的,我说的是与 BigQuery 下每个表相关的“细节”和“模式”选项卡。然而,如果我们必须一个接一个地点击几十个(甚至几百个)表,这种解决方案将会引发严重的问题。一定有更好的方法,对吗?

第三个解决方案是在这里扭转乾坤。你猜怎么着?我们可以使用 INFORMATION_SCHEMA 或 TABLES 元表轻松获得跨多个数据集的所有表元数据,所有这些都可以通过熟悉的 BigQuery 接口进行简单的 SQL 查询。这就是我们将在下一节讨论的内容。大伙儿,击鼓吧!让我们开始吧。

如何查询表元数据

关于所有表的概述

有两个选项可以获得数据集中所有表的概览。下面列出了这两个选项。

选项 1。信息 _ 模式视图

INFORMATION_SCHEMA 是一系列视图,提供对有关数据集、例程、表、视图、作业、预订和流数据的元数据的访问。

——来自谷歌云

在编写第一个查询之前,记住以下两点是至关重要的。

  1. 针对 INFORMATION_SCHEMA 视图的查询不会被缓存,而会产生数据处理费用(10MB)或消耗 BigQuery 槽 ,这取决于与您的项目相关的定价。
  2. INFORMATIONS_SCHEMA 查询必须用标准 SQL 语法编写。

列出所有表格

让我们开始探索 BigQuery 公共数据中的以太坊区块链数据集。我们将从 2 个简单的问题开始: 数据集中有多少个表?那些桌子是什么?

我们可以通过运行一个简单的查询来轻松获得答案。

# List all tables and their creation time from a single dataset#standardSQL 
SELECT * 
FROM `bigquery-public-data.ethereum_blockchain`.INFORMATION_SCHEMA.TABLES;

作者照片

查看查询结果,首先,这个数据集下有 14 个表。每个表格对应一行,以及以下各列。根据 GCP 文档,下面是每个列的含义的快速概述。

  1. 包含数据集的项目的项目 ID
  2. 包含表和/或视图的数据集的名称
  3. 属于指定数据集的所有表的名称
  4. 指示表是普通的 BigQuery 表(也称为基表)、视图、实体化视图还是引用外部数据源。
  5. 指示表是否支持 SQL INSERT 语句
  6. 该值始终为否
  7. 创建表的日期时间

使用 WHERE 子句列出数据集中选定的表

这次我们只对 获取包含令牌信息 的以太坊区块链数据集中 BigQuery 表的表名和创建时间感兴趣。好吧,让我们添加一个相关的 WHERE 子句来过滤我们想要的结果。Tada!下面是查询和结果。

# List metadata from selected tables with WHERE clause 
#standardSQL 
SELECT table_name, creation_time 
FROM `bigquery-public-data.ethereum_blockchain`.INFORMATION_SCHEMA.TABLES 
WHERE table_type = "BASE TABLE" 
AND table_name LIKE "%token%";

作者照片

选项二。表元表

到目前为止还不错,但是很明显,仅仅 INFORMATION_SCHEMA 视图不足以帮助我们 根据大小识别最大的表或者根据“最后修改时间” 识别最新的表。别急,伙计们!因为在每个数据集中,都有一个隐藏的表,其中包含关于每个表的更多元数据。幸运的是,可以在<project name . dataset . name>访问这个隐藏的表。__ 表格 _ _

重要提示:您需要在“表格”的每一侧键入 2 条下划线。

让我向您介绍一个非常有用的查询,它利用这个表元表来获取我们数据集中所有表的大小、行数和上次修改时间。对我来说,从谷歌云培训的 Coursera 课程中学习这个查询绝对是一种福气。我们走吧,各位!

#standardSQL 
SELECT dataset_id, table_id, # Convert size in bytes to GB 
ROUND(size_bytes/POW(10,9),2) AS size_gb, # Convert creation_time and last_modified_time from UNIX EPOCH format to a timestamp 
TIMESTAMP_MILLIS(creation_time) AS creation_time, TIMESTAMP_MILLIS(last_modified_time) AS last_modified_time,
row_count, # Convert table type from numerical value to description 
CASE 
WHEN type = 1 THEN 'table' 
WHEN type = 2 THEN 'view' 
ELSE NULL 
END AS type 
FROM `bigquery-public-data.ethereum_blockchain`.__TABLES__ 
ORDER BY size_gb DESC;

作者照片

但是,如果您想列出多个数据集中的所有表及其详细信息,该怎么办呢?您可以使用 UNION ALL 遍历每个数据集,类似于这个 GCP GitHub 中列出的查询。

放大列

让我们仔细看看以太坊区块链数据集中的所有数据列。我们将发现 每个表中有多少列,并识别分区列或聚集列

列出所有列

这个查询再简单不过了。

# List all columns related to all tables within a dataset 
SELECT table_name, column_name, is_nullable, data_type, is_partitioning_column 
FROM `bigquery-public-data.ethereum_blockchain`.INFORMATION_SCHEMA.COLUMNS;

作者照片

这里,我在 SELECT 子句中指定了 5 个属性,因为我只对获得列名、数据类型、为空性以及该列是否用于分区感兴趣。请随意让 SELECT *尝试查看包含数据列元数据的所有其他属性。

仅过滤用于分区的时间戳列

如果我们需要识别当前用于分区的所有时间戳列,该怎么办?让我们扭曲上面的查询来得到我们想要的。

#standardSQL 
SELECT table_name, column_name, is_nullable, data_type, is_partitioning_column 
FROM `bigquery-public-data.ethereum_blockchain`.INFORMATION_SCHEMA.COLUMNS 
WHERE data_type = "TIMESTAMP" 
AND is_partitioning_column = "YES";

作者照片

离别的思绪

我们处理大数据越多,我们决定哪些表值得我们研究,哪些表可以忽略的时间就越短。虽然本文仅仅触及了在探索 BigQuery 数据集的元数据时可以用表、元表和 INFORMATION_SCHEMA 视图做些什么的皮毛,但我希望它可以作为一个良好的起点。如果您热衷于使用 INFORMATION_SCHEMA 视图探索关于数据集、流、作业等的元数据,请不要忘记查看 GCP 文档。

感谢您的阅读。对我如何能做得更好有反馈,或者只是想聊天?请在评论中告诉我,或者在 LinkedIn 上找到我。祝大家这周过得愉快!

原载于 2021 年 2 月 1 日【http://thedigitalskye.com】

Python 中计时代码的一种简单方法

原文:https://towardsdatascience.com/a-simple-way-to-time-code-in-python-a9a175eb0172?source=collection_archive---------16-----------------------

使用装饰器来计时你的函数

作者:爱德华克鲁格和道格拉斯富兰克林。

布拉德·尼瑟里在 Unsplash 上拍摄的照片

介绍

我们的目标是在 Python 中创建一种简单的函数计时方法。我们通过用 Python 的库functoolstime编写装饰器来实现这一点。然后,这个装饰器将被应用到我们感兴趣的运行时的函数中。

计时装饰:@timefunc

下面的代码代表了一个通用的装饰模式,它具有可重用和灵活的结构。注意functool.wraps的位置。这是我们关闭的装饰。这个装饰器保存了传递给闭包的func的元数据。

timer.py

Functools 在第 16 行变得很重要,我们在打印语句中访问了func.__name__。如果我们不使用functools.wraps来修饰我们的闭包,将会返回错误的名称。

这个装饰器返回传递给timefunc()的函数的运行时。在第 13 行,start 开始计时。然后,第 14 行的result 存储func(*args, **kwargs).的值,之后计算time_elapsed。打印语句报告func的名称和执行时间。

使用@符号应用 timefunc

在 Python 中,decorators 可以很容易地用@符号来应用。并非所有装饰者的应用都使用这种语法,但是所有的@符号都是装饰者的应用。

我们用符号@timefunc 来修饰single_thread

用@timefunc 装饰函数

现在single_thread被修饰了,当它在第 13 行被调用时,我们将看到它的func.__name__和运行时。

timefunc 修饰的 single_thread 的输出

如果你想知道这是如何工作的,下面我们将更深入地讨论为什么以及如何为时间函数编写装饰器。

为什么一个人可以计时一个函数

原因相对简单。更快的功能是更好的功能。

时间就是金钱,朋友。—加斯洛维

时序装饰器向我们展示了一个函数的运行时。我们可以将装饰器应用于一个函数的几个版本,对它们进行基准测试,并选择最快的一个。此外,在测试代码时,知道执行需要多长时间也很有用。提前五分钟运行?这是一个很好的起床、活动双腿和倒满咖啡的窗口!

为了用 Python 编写装饰函数,我们依赖于functools 和对作用域的认识。我们来回顾一下范围和装饰。

装饰、关闭和范围

修饰是 Python 中的一种设计模式,允许您修改函数的行为。装饰器是一个函数,它接受一个函数并返回一个修改过的函数。

当编写闭包和装饰器时,必须记住每个函数的作用域。在 Python 中,函数定义范围。闭包可以访问返回它们的函数的范围;装饰者的范围。

在将修饰函数传递给闭包时,保留它的元数据是很重要的。了解我们的作用域让我们可以用functools.wraps恰当地修饰我们的闭包。

要了解这些概念的更多信息,请阅读这篇三分钟的文章。

这个装饰器的可重用性

注意func 被当作第 7 行的一个参数。然后在第 11 行,我们传递*args, **kwargs,进入我们的闭包。这些*args, **kwargs用于计算第 10 行func(*args, **kwargs)result

timer.py

*args**kwargs的灵活性使得timefunc可以处理几乎任何功能。我们闭包的 print 语句被设计用来访问函数__name__argskwargsresult,为func创建一个有用的定时输出。

结论

装饰是增强功能行为的有力工具。通过编写一个装饰器来为函数计时,您可以获得一个优雅的、可重用的模式来跟踪函数的运行时。

请随意将timefunc复制到您的代码库中,或者您可以尝试编写自己的时序装饰器!

用 Python 追踪代码的简单方法

原文:https://towardsdatascience.com/a-simple-way-to-trace-code-in-python-a15a25cbbf51?source=collection_archive---------24-----------------------

使用装饰器来跟踪你的函数

作者:爱德华·克鲁格和道格拉斯·富兰克林

Maksym Kaharlytskyi 在 Unsplash 上拍摄的照片

介绍

我们的目标是创建一种可重用的方法来跟踪 Python 中的函数。我们通过用 Python 的functools库编写装饰器来实现这一点。然后,这个装饰器将被应用到我们感兴趣的运行时的函数中。

跟踪装饰者:@tracefunc

下面的代码代表了一个通用的装饰模式,它具有可重用和灵活的结构。注意functool.wraps的位置。这是我们关闭的装饰。这个装饰器保存了传递给闭包的func的元数据。

tracer.py

如果我们没有在第 7 行使用functools.wraps来修饰我们的闭包,那么在第 11 行打印func.__name__时将会返回错误的名字。

这个装饰器打印出传递给tracefunc()的函数的轨迹。在第 10 行,result ,存储func(*args, **kwargs).的值,之后生成一个打印语句。该语句报告了func.__name__、args、kwargs 和result

因此,我们用tracefunc修饰的函数将生成关于它们执行的附加信息。

使用@符号应用 tracefunc

在 Python 中,decorators 可以很容易地用@符号来应用。并非所有装饰者的应用都使用这种语法,但是所有的@符号都是装饰者的应用。

我们用符号@tracefunc 来修饰show_args_and_kwargs

@tracefunc 的应用

现在show_args_and_kwargs被修饰了,当它在第 8–10 行被调用时,我们将看到它的func.__name__、args、kwargs 和 result。

跟踪输出

下面我们将更深入地探讨为什么以及如何编写一个装饰器来跟踪函数。

为什么人们会追踪一个函数

跟踪是模拟程序的执行,一行一行地遍历程序,显示变量是如何变化的。有经验的程序员使用跟踪来调试程序,通常作为调试器的替代品。描摹对于正在学习语言的初学者来说也是非常有用的。

“干杯,爱!骑兵来了!”—示踪剂

为了用 Python 编写装饰函数,我们依赖于functools 和对作用域的认识。我们来回顾一下范围和装饰。

装饰、关闭和范围

修饰是 Python 中的一种设计模式,允许您修改函数的行为。装饰器是一个函数,它接受一个函数并返回一个修改过的函数。

当编写闭包和装饰器时,必须记住每个函数的作用域。在 Python 中,函数定义范围。闭包可以访问返回它们的函数的范围;装饰者的范围。

在将修饰函数传递给闭包时,保留它的元数据是很重要的。了解我们的作用域让我们可以用functools.wraps恰当地修饰我们的闭包。

要了解这些概念的更多信息,请阅读这篇三分钟的文章。

这个装饰器的可重用性

注意func 被当作第 4 行的一个参数。然后在第 8 行,我们通过*args, **kwargs,进入我们的闭包。这些*args, **kwargs用于计算第 10 行func(*args, **kwargs)result

tracer.py

*args**kwargs的灵活性允许tracefunc处理几乎任何函数,不管它是使用 args、kwargs,还是两者都不使用。我们的闭包的 print 语句被设计用来访问函数__name__argskwargsresult,从而为func创建一个有用的跟踪输出。

结论

装饰是增强功能行为的有力工具。通过编写一个装饰器来跟踪您的函数,您获得了一个优雅的、可重用的模式来跟踪函数的行为。

请随意将tracefunc复制到您的代码库中,或者您可以尝试编写自己的跟踪装饰器!

从客户购物篮分析用例理解关联规则的简单方法

原文:https://towardsdatascience.com/a-simple-way-to-understand-association-rule-from-the-customer-basket-analysis-use-case-c7bcd75bdec1?source=collection_archive---------34-----------------------

本文是对 的全面概述 的关联规则和不同的度量标准

来自 Pixabay 的图片由史蒂夫·比辛内拍摄

a)导言

本文的目标是解释应用于客户购物篮分析用例的关联规则。我们将经历定义什么是关联规则的步骤,识别测量它的主要方法,并且也提及它的优点和缺点。

b)关联规则的定义

关联规则是一种基于 规则的机器学习方法 ,用于部署模式识别,以识别不同但相关的项目之间的关系。自 20 世纪 90 年代以来,它一直用于零售业,以帮助分析客户同时购买的产品。这可以帮助商店经理找到更好的产品布局、产品折扣、库存管理等策略。当然,其他行业也可以从这项技术中受益。

c)展示我们的使用案例

比方说,咖啡和糖经常一起购买。有了这些信息,您可以通过以下方式增加销售额:

  • 将咖啡和糖放在一起,这样购买一种产品的顾客就不会步行去买另一种产品。
  • 向购买咖啡或牛奶的人做广告,以增加此人购买配对的其他产品的倾向。
  • 如果顾客一次购买牛奶和咖啡,则提供折扣。

d)将关联规则应用于我们的用例

首先,需要注意的是,一个关联规则有两部分: 一个前因(if)一个后果(then) 。前提是在数据中找到的项目。结果项是与先行项结合在一起的项。

通过将关联规则应用到我们之前的用例中,我们可以用咖啡和牛奶的例子得到下面的表达式。

  • " 如果购买了 项咖啡, 项购买糖的可能性是 __"
    可以表示为:
  • {咖啡}→

e)测量关联规则的三种主要方法

测量联想的三种主要方式是: 支持度、信心度、升力度。

让我们用咖啡和糖的类比来突出这些概念。想象以下场景,其中:

  • 店内总交易笔数3000
  • 咖啡(C)的购买数量是 800 次交易
  • 糖的购买数量为 500 笔交易
  • 一起购买的咖啡和糖(C → S)的数量是 400 个交易

1)支持

这是给定数据集中某项的相对频率(所有事务)。它代表了商品的受欢迎程度,也是由它在总销售额中所占的比例来定义的。

c 是的先行词。s 是的后件

基于我们的案例,我们可以将咖啡的支持计算为:

2)信心

这对应于在数据中看到结果项的概率,假设数据也包含先行项。换句话说,它告诉 在购买了一件商品的情况下,购买另一件商品的可能性有多大。

c 是的先行词。s 是的结果

咖啡是 T21 的前身。糖是的后件

这个分数意味着,如果购买咖啡,有 50%的几率会购买糖。

3)电梯

这衡量了前因和后果一起发生的频率比它们独立发生的频率高多少。

c 是先行词。s 是的结果

  • 如果 Lift 得分< 1,则表示如果购买 C 不太可能购买 S
  • 如果 Lift 得分> 1,说明 CS 关联度高。换句话说,如果购买了 C ,很可能会购买 S
  • 如果 Lift score = 1,则表示 CS. 之间没有关联

咖啡是先行词。糖是的后件

  • 从结果中,我们可以看到 lift 得分> 1,这意味着如果购买了咖啡,很可能也会购买糖。

f)关联规则的优点和缺点

1)优势

  1. 这个技术是最具描述性的,一旦我们修正了 结果,它就可以成为预测。
  2. 它是有效的,对所分析的离散数据的性质没有任何理论限制。
  3. 它提供了广泛的可能性;例如,我们可以添加时态、个人数据等。
  4. 由此产生的规则非常容易理解。

F.2)缺点

  1. 处理大量数据(大量交易或/和项目)非常耗时。
  2. 它不适合处理连续变量。
  3. 这种技术仅提供局部规则,而不是给出现象的全局视野,强调主要因素和因素之间的相互作用。

g)文章结尾

我希望您喜欢这篇文章。如果您有任何问题或意见,我将很高兴欢迎进一步讨论。

如需进一步阅读,请随时查阅以下链接:

https://searchbusinessanalytics . techtarget . com/definition/association-rules-in-data-mining

https://searchbusinessanalytics . techtarget . com/definition/association-rules-in-data-mining

【https://en.wikipedia.org/wiki/Rule-based_machine_learning

再见🏃🏾

一个简单而有效的掌握数据可视化的 5 步框架

原文:https://towardsdatascience.com/a-simple-yet-effective-5-step-framework-to-master-data-visualization-a1825e050c7c?source=collection_archive---------7-----------------------

让我们用一个例子来慢慢分解框架,并创建可视化效果。包括截图。

图片由 Freepik 上的 Freepik 提供

将数据可视化一直令我着迷。用视觉图像呈现我的想法和发现,并讲述一个故事一直是我的强项。

我们都知道数据可视化在大数据时代的重要性。

你的教授喜欢精心设计的课堂演示。你的老板喜欢你通过可视化揭示模式、趋势和商业洞察力。你已经在新的 iPhone 发布会上看到了这些可视化的画面,是吗?

当人们通过可视化的方式讲述一个引人入胜的故事时,你可能会感到敬畏,但请相信我;这不是火箭科学。我可以坚持这样做,因为随着时间的推移,我已经开发了自己的 5 步框架,并且每次都依靠这个过程来做好。

关键是要反复进行框架实践,直到你自然而然地创造出“魔法”

我不会把它放在那里,而是用一个例子带你浏览这个框架。

我挑选的是美国超市数据集,它由一个电子商务*台从 2014 年到 2018 年的交易列表组成,可在 Kaggle 上获得。去吧,下载数据(你需要的只是一个免费的 Kaggle 账户)然后照着例子做。

1.明确目的

这是很多人一开始就忽略的,包括我。甚至在弄清楚你要想象什么之前,你就开始浏览数据。你花了几个小时去理解数据,后来才意识到;这种努力没有什么价值。

作为第一步,让我们明确目的。

  • 你想回答什么问题?
  • 你想通过想象传达什么?
  • 你的视觉化将如何帮助观众?
  • 你试图用视觉化来完成什么?

这些简单的问题将有助于你在接下来的阶段提高工作效率。

将此应用于示例:

在我们的例子中,美国超市数据集,一些你可能想要解决的问题。

  1. 各州之间的销售额有何不同?
  2. 每个产品的利润是多少?
  3. 哪个产品类别产生高利润?
  4. 每种产品对利润贡献的百分比?

这些只是问题的几个例子,还可以有更多。接下来,我们将使用第一个问题,即各州之间的销售额如何变化,作为示例。

2.了解您的数据

现在你清楚了你要回答的目的或问题,你应该理解呈现给你的数据。

你需要非常了解数据集。数据集可能有数百列,一眼看去可能会让人不知所措。但是要花时间让自己熟悉变量,每个变量代表什么,以及变量在数据集中的意义。

现在你已经有了一个清晰的目标(来自第一步的),并且已经理解了每个变量所代表的含义,你将能够过滤出你可视化所需要的列。

了解数据集还将澄清您是否可以按原样使用数据,或者是否应该执行任何修改。

将此应用于示例:

在检查数据时,为了更好地理解,您可能会问这些问题。

  1. 数据集中的每个变量代表什么?
  2. 回答问题需要哪些变量?
  3. 解决问题需要哪些修改?
  4. 你需要绘制哪些变量?

现在你已经有了明确的目的和对数据的理解,让我们进入下一步。我们走吧。

3.定义你的受众

理解你的观众是至关重要的,因为它给你的视觉化的想法,你应该拿出来。

例如,如果你的读者是数据科学家,你可以使用 matplotlib 作为你的可视化工具。但是让我们假设你被要求把它展示给一个业务分析师或销售人员;用 matplotlib 创建可视化将是一个错误。你可以使用 MS Excel 或者一些高级工具,比如 Tableau 和 PowerBI。

如果您向客户推销您的数据,您可能希望它尽可能有吸引力。在这种情况下,您可能不想使用 MS Excel,而是选择使用 Tableau 或 PowerBI。

了解你的受众不仅仅是选择你使用的工具,还包括你使用的标题和说明。

将此应用于示例:

为了更好地了解你的听众,你可以问自己几个问题

  1. 你的目标受众是谁?(或者你在为谁创造可视化?)
  2. 你的目标受众是技术人员吗?
  3. 他们在解释数据方面有什么能力?
  4. 他们希望可视化是什么形式?(例如,在线仪表板、MS Excel 表格、演示文稿)

在我们的例子中,让我们假设销售人员是我们的目标受众。我们可以选择创建 Tableau 仪表板来显示美国不同州之间的销售差异。

4.发展你的想象力

前三个步骤会给你一个清晰的你将要创建的可视化的图像。现在是时候动手开发可视化了。

可视化类型

选择正确的可视化类型至关重要。如果你在视觉化的类型上没有做出正确的选择,你到目前为止所付出的所有努力都会以失败告终。

我大概可以写一整篇文章来讨论如何在不同的可视化类型之间进行选择,但是在这篇文章中我将保持简单。

  1. 条形图:当您想要对数据进行比较时,可以使用条形图。
  2. 折线图:这些图表可以用来可视化数据随时间变化的趋势。例如,一种产品在一年中的价格,一年中每天产生的利润。
  3. 饼状图:这些是用来展示构图的。来解释整体的百分比。比如每个产品贡献利润的百分比。
  4. 地图:你可以选择使用地图来可视化基于地理位置的数据。这将使最终用户更好地了解位置。
  5. 甘特图:这是一种广泛使用的图表类型,用于可视化一段时间内的项目进度或活动。

可视化的类型不限于以上五种。为了简单起见,我只提到了上面五个。一旦你选择了正确的图表类型,注意颜色和比例的选择。

将此应用于示例:

在我们看到的例子中,我们可以创建一个类似下图的条形图。

作者创造的形象

5.测试和改进

在这个阶段,您测试您的实现以进行改进。人类在开发时做出假设是很常见的。为了减少这种偏见,你应该总是期待同事的反馈。

将此应用于示例:

在我们的示例中,我们可以将上一步中创建的条形图改进为地图。(我在上一个步骤中特意创建了条形图,以显示反馈可能带来的改进)。

作者创造的形象

让我们重温一下,永远记住它

简单的五步指南可以节省你创建可视化的时间。

  1. 明确目的:把自己要解决的问题说清楚。
  2. 理解你的数据:检查数据,清楚每个变量代表什么。根据问题过滤掉变量。
  3. 定义你的受众:了解你的受众将有助于你决定在开发阶段使用的工具和短语。
  4. 发展你的视觉化:现在,你确切地知道要创造什么。为数据集选择正确的可视化类型,并开始创建。
  5. 测试和改进:获得对开发的可视化的反馈,并对其进行改进。最后,与利益相关者分享。

好了,你知道了。这不是魔法。很简单。当你把它付诸实践时,你就会知道它有多有效。万事如意!

非常感谢你读到这里。我希望你喜欢阅读,这篇文章给你增加了一些价值。我希望听到您对我如何改进的反馈。期待看到你的恒星可视化!

为您的数据科学项目创建 CLI 的简化指南

原文:https://towardsdatascience.com/a-simplified-guide-to-create-clis-for-your-data-science-project-bf9bcaa26e1?source=collection_archive---------39-----------------------

CLI 是一种与机器学习模型交互的强大而直接的方式

迈克尔·泽兹奇在 Unsplash 上的照片

这是一个可怕的假设。我以为一旦部署,就结束了。但是,部署只是大多数数据科学项目的开始。

我们经常需要重新训练和更新模型。通常使用新数据,有时使用不同的配置,偶尔使用完全独特的体系结构。

更糟糕的是,有时,你把它交给另一个团队或没有技术能力的客户去做。如果不是,无论是谁在做这些维护工作,都可能对架构有不同的理解。

在这种情况下,我们建立一个门户网站来支持善后处理。我们将应用程序链接到数据存储库,让用户通过 web 表单进行配置,并运行算法。

构建一个 web 应用程序来与您的机器学习模型进行交互是一个不错的主意。特别是,Streamlit 等工具允许数据科学家创建 web 应用程序,而无需任何 HTML、CSS 或 JavaScript 代码。

然而,网络应用并不适合一些人。假设你对托管 web 应用程序有所顾虑。不用担心;不是死路一条。我们有一个后备方案,这确实是一个解决问题的可靠方案。

您可以创建命令行界面(CLI)来产品化和交付您的机器学习项目。

你能用 CLI 为你的机器学习模型做什么?

CLI 允许您在命令提示符下运行编程指令,而无需与代码库交互。CLI 可以有许多命令,每个命令都有不同的参数。例如,下面启动一个 web 服务器,您可以选择使用哪个端口。

python -m "http.server" 8080

您也可以创建像这样有用的 CLI 来与您的 ML 模型交互。如果您的客户想要用不同的数据重新训练模型,他们可以用一个像下面这样的命令来完成。

manage retrain /<path>/new_data.csv

您还可以为您的 CLI 创建帮助页面,在训练(或任何其他任务)时显示进度,并在终端窗口中有意义地设计日志和错误。

创建您的第一个 CLI。

我们将使用一个名为 Typer 的 python 库来创建 CLI。Typer 是创建 CLI 命令、打印时尚输出和显示进度的最小框架。

您仍然可以使用 Typer 为您的非 Python 程序创建 CLI。您必须使用 Python 子流程,或者通过 HTTP 或消息代理与非 Python 代码通信。这里就不讨论了。但是,这可能是未来文章的主题。

安装 Typer 很简单。您可以使用 PyPI:

pip install typer

安装完成后,您可以尝试这个 Hello World 应用程序,了解一下 Typer 是如何工作的。

在您的项目目录中创建一个名为 app.js 的文件(您可以选择不同的名称)和以下内容。

作者的代码片段。

运行上面的命令将在终端上打印一条彩色的 Hello World 消息。

作者截图。

当然,上面的练习不仅仅是简单的 Hello World。您可以更改文本颜色和字体颜色。如果您使用的是带有 IntelliSense 的编辑器,如 VSCode,找到它们就很容易了。如果没有,你可以在 Typer 的文档上找到它们,无论如何都值得一查。

作者截图。

在继续之前,让我们看看如何向您的 CLI 添加多个命令。它需要对代码库稍加修改。

我们创建一个类型的实例,并在“main”方法中调用它。它需要对代码库稍加修改。我们可以在函数上使用“command”修饰符,将每个函数转换成一个 CLI 命令。

代码片段由作者提供。

通过这种新的安排,您可以在同一个 CLI 下使用多个命令。您可以在文件名后面加上函数,告诉 CLI 要执行哪个函数。

作者截图。

这不是已经很棒了吗?现在我们已经安装并测试了 Typer,让我们继续集成一个 ML 算法。

为 K-Means 算法创建 CLI。

我将使用 K-Means 算法,我在以前的帖子中讨论过。K-Means 是一种简单而强大的数据点聚类技术。

这是我们的应用程序的修改版本。我们创建了两个命令:一个用于训练和保存 K 均值模型,另一个用于加载和在预测中使用。注意,train 函数定义有一个参数 file_path。Typer 会将其转换为命令行参数。

代码片段由作者提供。

使用文件路径运行我们的应用程序 CLI 的“train”命令就可以做到这一点。您可以通过实现 predict 命令来练习一下。

作者截图。

显示进度条

对于消耗任务,你必须显示一个进度条,这样用户就不用拔头发了。Typer API 可以帮助你创建进度条,而不用拖动你的进度条。

让我们使用另一个命令,使用 elbow 方法找出集群的最佳数量。该方法将对不同数量的组运行 K-Means 多次。理想的数字应该是具有低惯性的数字。在大型应用程序中,这可能是一个运行几个小时的任务。

下面是完成这项工作的代码片段。注意,这一次,我们添加了两个参数,其中一个有默认值。Typer 会把它当做一个选项,而不是一个论点。您可以选择留空。

代码片段由作者提供。

现在尝试运行python app.py elbow voters_demo_sample.csv

作者截图。

这段代码目前没有进度条。运行这个命令将使终端在几秒钟内没有任何输出,并立即打印出来。

让我们放一个进度条来帮助我们的用户。这是更新后的脚本。请注意 for 循环中的细微变化。

代码片段由作者提供。

下面是现在运行它的样子:

作者截图。

为 CLI 创建手册页。

手册页是帮助用户的文档。Typer 很聪明地将您的函数及其输入转换成详细的手册页。它将列出所有可用的命令、参数和选项。

您可以使用后缀- -help 来访问 Typer 生成的手册页。

python app.py --help

作者截图。

您也可以访问特定命令的手册页:

python app.py elbow --help

作者截图。

如果你需要给用户更多的信息,你可以在函数的开头使用多行注释。Typer 将在帮助页面上显示它们。

代码片段由作者提供。

作者截图。

结论

在本文中,我们创建了一个 CLI 来帮助与机器学习模型进行交互。您可以将这些技术扩展到数据科学项目之外。CLI 可以处理任何用户交互。

虽然我们使用 Python 来生成 CLI,但是您也可以使用它来运行其他程序。在这种情况下,您可能必须使用子流程、HTTP 或消息代理。

CLI 是解决关键问题的快速方法。如果不适合开发门户网站或其他解决方案,您可以构建一个。此外,您不必担心服务器停机等不可预见的事件。这使得 CLIs 成为值得考虑的可靠替代方案。

通过 Typer,一个极简的 Python 库,我们创建了

  • 与 K-Means 算法交互的 CLI 命令;
  • 终端窗口上的彩色消息;
  • 一个进度条,让用户随时了解情况;
  • 指导用户的命令行文档。

感谢阅读,朋友!看来你和我有许多共同的兴趣。我很乐意通过 LinkedIn、T2、Twitter 和 Medium 与你联系

还不是中等会员?请使用此链接 成为 会员。你可以享受成千上万的有见地的文章,并支持我,因为我赚了一点佣金介绍你。

用于评估对象检测模型的单个数字度量

原文:https://towardsdatascience.com/a-single-number-metric-for-evaluating-object-detection-models-c97f4a98616d?source=collection_archive---------15-----------------------

F1 分数以及它们如何帮助评估模特的表现

尼古拉斯·卡佩罗在 Unsplash 上拍摄的照片

介绍

使用精度和召回率来评估对象检测模型可以提供对模型在各种置信度值下如何执行的有价值的洞察。类似地,F1 分数尤其有助于确定*衡给定模型的精度和召回值的最佳置信度;然而,该值跨越了从 0 到 1 的置信值的范围。单值评估度量可以从给定模型的 F1 分数集合中导出,其可以是整体模型性能的良好指标。

背景

F1 分数、精确度和召回率可使用以下等式进行评估:

F1 分数、精确度和回忆方程式,作者图片

当在各种置信值下评估模型时,这些指标可以很好地协同工作,从而根据设计规范提供关于模型如何执行以及哪些值可以优化模型性能的有价值的见解。通常,随着置信度阈值的增加,精确度会上升,召回率会下降,如下面显示的自定义 yolo v5 模型的结果所示:

自定义 yolo v5 对象检测模型的单一类别精度分数,图片由作者提供

自定义 yolo v5 对象检测模型的单一类别召回分数,图片由作者提供

使用 F1 得分曲线,可以看到精确度和召回率之间的*衡,并且可以使用下面的图表确定设计点:

自定义 yolo v5 对象检测模型的 F1 得分曲线,图片由作者提供

从 F1 曲线来看,优化精度和召回率的置信度值是 0.352。在许多情况下,更高的置信度值是可取的。在该模型的情况下,选择置信度 0.6 可能是最佳的,因为 F1 值看起来大约为 0.75,这与最大值 0.81 相差不远。观察置信度为 0.6 的精度和召回值也证实了这可能是一个合适的设计点。从 0.6 左右开始,召回值开始吃亏,精度值还是大致在最大值。

理论

现在,通过提供具有相应置信度的最大值,可以用 F1 分数中的单个数字来评估模型;然而,这可能不能准确地代表模型的整体。从 F1 得分中得出的一个建议的单个数字指标如下所示:

建议度量的基本积分形式,作者提供的图像

该值通过对 F1 得分曲线进行积分来确定,积分的指数因子称为 gamma。如果 F1 曲线的方程是已知的,可以使用这种形式。在大多数情况下,F1 得分曲线由使用评估或测试数据集评估的值生成。在这种情况下,可以使用更一般形式的方程:

建议指标的求和符号,作者提供的图像

当应用矩形积分时,可以使用具有中点规则的公式的详细形式:

中点规则应用于矩形块,按作者排序的图像

p 是给定索引处的精度值,R 是给定索引处的召回值。指数γ1/c 已被给定指数的*均置信度值所取代。

在这个新的符号中,将计算每个数据点的 F1 得分曲线下的面积,并将其添加到累计总数中。指数因子 gamma 可用于惩罚和奖励 F1 曲线的各个区域。例如,对于 gamma 的标准值,置信值较低的 1/c: F1 分数由于被驱动到 0 而受到严重惩罚,并且对整体度量几乎没有贡献。类似地,对于高置信度值的 F1 分数,指数因子最低限度地惩罚总分数。此指标可获得的最大值为 1,最小值为 0。yolo v5 模型 F1 得分曲线各点的建议指标值如下所示:

衍生 F1 评分曲线与处罚,图片由作者

蓝线表示等式 7 在每个数据点的计算值。请注意,随着数据点数量的增加,该值会越来越小。浅橙色条代表所有计算的单个数据点得分的累计总数。

由于伽马因子,在置信度为 0.1 或更低时评估的大多数 F1 分数点被驱为零,并且 F1 分数贡献被抑制直到置信度为 0.4。F1 分数值的惩罚程度可以使用 gamma 因子来控制。例如,如果需要更高的惩罚,将伽马因子中的分子从 1/c 增加到 10/c。这将使置信度为 0.4 之前的所有值比以前受到更严重的惩罚,但不会改变惩罚开始改变的置信度值。

类似地,如果想要更少的惩罚,减少分子或者甚至移除伽马指数将会有所帮助。用于评估度量标准的一种形式的方程,该度量标准考虑了控制惩罚程度和惩罚点的变量,可描述为:

带有惩罚因子的度量评估,由作者提供的图像

其中 f 用于控制上面讨论的惩罚量(默认值 1)。请注意,将 f 增加到大于 1 的值将显著影响分数。

比较

我们来比较三个模型:前面提到的基础模型,一个比基础模型差的模型,一个比基础模型好的模型。这些模型被指定为优于或劣于基本模型的方式可以总结为:

  • F1 曲线、积分面积、罚积分面积
  • 推理结果的人工评估
  • 通过较少的训练数据、不同的配置参数以及时期和批次变化,专门训练得更好或更差

各种模型的 F1 曲线、非惩罚积分值和惩罚积分值曲线如下所示:

各种度量得分曲线,图片由作者提供

非惩罚曲线将遵循 F1 曲线的相同轮廓,因为它们是线性相关的。请注意,F1 曲线和非惩罚积分曲线之间的幅度是不同的。这是由于等式 9 中的δ置信项。任何积分分数的最大可能值是用于积分 F1 曲线的增量。在这种情况下,使用 0.05 的增量,因此非惩罚和惩罚积分的最大值是 0.05。当置信度接*约 0.4 时,惩罚曲线的低置信度部分随着衰落严重程度而明显降低。所有被罚曲线都是在 f 值为 1 的情况下计算的。

上述曲线的最终得分总结如下:

分数摘要,按作者分类的图像

最后一行是处罚分数与非处罚分数的比率。它代表综合 F1 分数中位于较高置信区域的部分。如果期望更高的置信度,当确定多少非惩罚分数实际上是相关的时,这可能是一个很好的指标。

一个 GitHub 知识库已经公开,可以很容易地计算出被罚和未被罚的综合分数。可以在以下位置找到它:

https://github.com/plebbyd/integrated-F1

此外,对于任何给定的置信度和 F1 分数值的输入,该存储库中的函数返回惩罚与非惩罚的比率。

结论

惩罚的和非惩罚的综合 F1 分数可以是用于评估对象检测模型的良好的单个数字度量。如果在多个模型的研究或训练过程中无法对 F1 曲线进行手动检查,那么评估这些新指标可能会有所帮助。

参考

[1]戴维·m·w·鲍尔斯(2011 年)。“评价:从精度、召回率、F-Measure 到 ROC、信息量、标记性&相关性”。机器学习技术杂志2(1):37–63。

[2] Yolo v5 (2021)。In: GitHub。https://github.com/ultralytics/yolov5。访问时间是 2021 年 5 月 31 日。

模拟森林火灾、流行病和经济的单一技术

原文:https://towardsdatascience.com/a-single-technique-to-model-forest-fires-pandemics-and-economies-3d68d7c1a865?source=collection_archive---------64-----------------------

探索 Python 中的交互代理建模

流行病,森林大火和经济危机。不仅是去年的菜单,还有一小部分现象可以在基于主体的建模(ABM)框架下进行建模。

图片来自 Unsplash

ABM 非常适合于理解复杂行为是如何在基于系统个体参与者之间简单交互的系统中出现的。abm 在解释一般观察结果方面表现出特别的优势,这些观察结果被称为“程式化事实”,例如观察到的中子散射模式或资产回报的分布。这些代理可以是任何东西,从人或公司到生态系统中的动物或气体中的原子。这种建模方法是自下而上的方法,其中系统的行为完全由对参与者个体行为的假设驱动,而不是自上而下的方法,该方法假设参与者将如何一起行为。

一个简单的例子是野火建模,每个代理代表一小片土地。每块土地的规则可能非常简单:如果土地着火,将顺风的相邻土地点燃,直到该土地上的所有燃料都烧完。尽管有这些简单的规则,wildfire 系统的整体行为表现出复杂的行为。此外,探索改变假设的影响,如使火灾蔓延概率化或引入燃料再生,只需要改变地块之间相互作用的规则,而不改变模型框架。这有助于快速实验和假设测试。

有两个点火点的野火反弹道导弹。原始图形

快速实验并不是 ABM 优于自顶向下方法的唯一优势。考虑被建模的个体中的变化会在自上而下的模型中引入显著的复杂性,而在基于代理的方法中是微小的变化,因为这种异质性可以被变化的个体代理捕获。这可用于捕捉差异,如野火模拟中不同的燃料水*,或创建模仿流行病模型的人口普查数据的代理群体。

ABMs 不局限于在模拟物理空间中交互的代理,模型框架扩展到代理交互的非物理限制,例如限制代理只与他们“知道”的其他代理交互。这允许引入社会异质性,许多代理人属于封闭的社会圈子,而较少的高度社会化的代理人连接这些圈子。

这是在下面的简单流行病模型中通过将代理的社会联系表示为具有小世界属性的网络来实现的。

具有小世界相互作用的简单 ABM 流行病模型。原始图形

这也让我们能够探索限制社会交往如何影响流行病的持续时间和强度的程式化事实。在该模型中,这是通过减少网络中的*均连接来实现的,这类似于个人减少与他们最亲密的朋友和家人的物理接触。

与上面相同的流行病模型,但是社会联系减少了 40%。原始图形

ABM 的另一个关键优势是潜在假设的可解释性,这可以为结果提供信心,并使发现更容易沟通。例如,对收入不*等和税收影响的自上而下的分析通常是高度数学化的,并且对个人非常抽象,这使得政策决策的沟通成为一个持续的挑战。

各种税收制度下的收入*等——基尼系数越高,不*等程度越高。原始图形

另一方面,自下而上的 ABM 方法允许模型减少到只有三个步骤,每个周期由代理重复:1)与他们有社会联系的代理随机交易,如在流行病模型中;2)缴纳交易所得税,如果财富低于最低水*,则领取福利金;3)产生固定的生活费用,并获得储蓄利息。注意到这些假设没有提到每个代理人的工作道德或生产力,模型的程式化事实仍然模仿自上而下模型中发现的事实,特别是统一税导致比累进税更高的财富不*等(以基尼系数衡量),以及需要福利支付以防止固定生活成本使大部分代理人破产。

不幸的是,通常缺乏关于这些基本假设和输入的知识,因为有关系统的相关数据通常是在总体水*上而不是在单个水*上获取的。此外,模型输出通常对所使用的输入敏感,这可能极大地限制预测中的使用并削弱信心。

一种解决方案是将假设捕捉为一组参数,然后优化参数以拟合历史数据,针对各种参数组合运行模型,直到模型输出与观察到的数据相匹配。然后,来自该调整模型的参数被用于正在进行的预测或建模练习。这种实践增加了对所产生的洞察力的信心,并在模拟世界和现实世界之间提供了更强的联系。

虽然 ABM 技术并没有取代传统的自上而下的方法,但它们确实提供了一种替代的视角,并且在某些情况下提供了一种方法来处理那些太复杂而无法以自上而下的方式定义的问题,或者代理表现出大量异质性的问题。虽然编写和测试 abm 需要一定水*的技术技能,但由于模型框架的可重用性和开源库(如 Mesa for Python)的存在,这种学习曲线变*了,Mesa for Python 为代理、代理交互和数据捕获提供了通用框架。最后,通过易于沟通的假设和方法,增加了对模型结果的信心。通过将模型输入建立在已知真实世界数据的基础上并优化参数以适应历史观察,这将得到进一步的测试和改进。

这个故事是基于代理的建模系列的第一篇,是基于我自己对构建 abm 的研究和实验。如果你想跟进,请考虑关注我的个人资料或这份出版物。

一些来源如下:

https://www . science direct . com/science/article/pii/s 1755436517300221

https://www . bankofengland . co . uk/-/media/BOE/files/quarterly-bulletin/2016/agent-based-models-understanding-the-economy-from-the-bottom-up . pdf

关于如何维护人工智能/人工智能模型的六点框架

原文:https://towardsdatascience.com/a-six-point-framework-on-how-to-maintain-your-ai-ml-models-b466e926005c?source=collection_archive---------27-----------------------

行业笔记

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

随着疫情在我们的世界上发生了巨大的变化,我们不能总是依赖我们用来训练和构建我们的第一个模型版本的历史数据。我们都知道——或者我们现在应该意识到——这些最初的版本会以某种方式崩溃。这只是时间问题。在我们去年 12 月的第一篇文章中,我们讨论了为什么你需要在你的 AI/ML 模型上进行模型监控。让我们通过考虑一个整体框架来维护我们的模型,来拓宽我们的讨论和视野。这一点至关重要,因为模型是活生生的功能性工具,支持我们的业务决策、推动收入、降低成本,并代表着公司的重大投资。简单地监控模型是一个好的开始,但是还不够,特别是当您想要扩展到生产中的少数模型之外的时候。

一个整体的框架应该确保你的模型没有偏见(我们都记得亚马逊的招聘模型,它只使用大部分男性进行培训)。它应该包含可解释性。它应该涵盖我们在重新培训时完全再现性所需的所有内容。我们将其分为以下六个要点。

1.一个有据可查的目的是第一步。我们的模型应该与我们的商业目标和目的一致,否则它们会变得陈旧和失去效力。这似乎是显而易见的,但经常被忽视,因为有时建模者为了他们的研究或满足他们的求知欲而更多地参与构建它们。正如我的同事大卫·布洛赫在他的博客中所说,“挑战的一部分是评估一个好决策的价值的困难。”有时,可以使用模型来阐明这些决策,并更紧密地映射和量化它们对业务的价值。有了这个目的,并了解实际的业务目标,就可以将模型从数据科学项目中转移出来,并使其成为业务的一个合法部分。有目的的方法的一部分是考虑您的目标、KPI 和其他指标,以评估 ROI 并填写有关目标最终用户和交付机制的详细信息。另一部分是理解一个模型在满足特定业务标准之前和之后将如何被使用。

2.数据血统详情。每个模型都有一些内置的底层数据。诀窍是捕捉这些细节,以及如何准备足够详细的数据,以确保模型可以重现和可信。这在审计时也很有用,所以我们不必试图追踪模型的数据来源,也不必从头开始。

正如我在之前的文章中提到的,即使是最好的模型也会进化,因为底层数据和关系会随着时间而变化。拥有这种数据谱系是跟踪并有望防止概念漂移的关键,概念漂移是指世界在变化,但模型没有反映这些变化。这种偏差可能是由数据分布、测量值或潜在用户群的变化引起的,而这些变化可能会被您的模型忽略。如何记录这些变化至关重要。

3.全生命周期跟踪系统。与软件开发生命周期一样,这是一个将模型运行与特定数据版本联系起来的过程,也是记录对模型元素所做的各种更改的另一种方式,这些更改是实验性构建过程的一部分。想想 GitHub 在跟踪程序代码版本方面做了什么,Docker 在跟踪系统定义和组件方面做了什么,Kubernetes 在跟踪和编排计算版本方面做了什么。当我们完成各种模型运行时,我们需要记录这些元素,这样我们可以注释我们的进展,并显示我们如何修复模型的各种问题。我们的模型的演变几乎比实际模型本身更重要,因为我们可以更好地理解我们正在建模什么,以及为什么我们不仅选择首先构建它们,而且还要调整它们的数据输入和假设。

4.一个模型注册中心,链接到上面提到的生命周期跟踪系统。注册表还可用于跟踪模型版本历史,其中每个版本都可以完全重现,其元素与我们在更改数据、代码、软件和硬件*台方面的实验相同。理想的情况是拥有一个带有汇总仪表板的中央注册表,您可以在其中浏览模型版本并深入了解每个版本的历史。

5.验证例程记录代码审查,报告关于道德和偏见检查的各种解释,并获得用户的批准。这也是报告其服务水*协议和我们所做的其他功能测试以及评论其总体生产准备情况的好地方。我见过很多建模者跳过这一步。验证是确保模型确实如您所愿的关键。这也是在模型的使用寿命即将结束,需要淘汰或重建时做出决策的关键。

6.最后一点是有一个开放式模型监控系统。这就是我在 12 月的帖子中讨论的内容,应该用于捕获数据漂移、单一接地真相、测量精度等项目,并提供深入分析信号故障的功能。监控系统还应该能够检测异常情况,并在超过特定阈值时自动向利益相关者发出警报。

随着您扩大在数据科学和建模方面的投资,您将需要管理和维护您的业务日常所依赖的不断增加的模型集合。这里有两种方法可以开始。首先,根据这里提到的六个目标中的每一个目标,检查您当前的模型维护计划。第二,为这项工作建立一个特别工作组,或者考虑寻求外部帮助。这将需要时间和资源的前期投资,但您最终会得到更好的模型,它们寿命更长、更安全,并在指导您的业务决策方面发挥更大的作用。在未来几年中,在模型护理方面领先的企业将在竞争优势方面处于有利地位。把这种资源看作是一种为你的企业设想和指导一个坚实的未来的方式。

如何在 Python 中分割序列

原文:https://towardsdatascience.com/a-skill-to-master-in-python-d6054394e073?source=collection_archive---------17-----------------------

了解如何在 Python 中分割列表和字符串

格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片

能够有效地分割 Python 中的序列(比如列表、字符串和元组)是编程时最重要的技能之一。幸运的是,python 提供了索引语法,极大地方便了切片过程,并使其更加直观。

在本教程中,我们将首先回顾如何索引一个序列,然后继续切片序列,特别是列表和字符串。此外,我们将涵盖切片列表和切片字符串之间的一些重要差异。然后,我们将查看列表中的片分配。最后,我们将看看在 Python 中使用索引语法时到底发生了什么。

索引序列

在我们开始切片之前,让我们简单回顾一下如何在一个序列(特别是一个列表)中索引元素。

请记住,我们可以通过使用方括号中的索引来访问列表中的单个元素。让我们看看下面的数字列表:

num_list = [0,5,10,15,20,25,30,35,40]
            0,1, 2, 3, 4, 5, 6, 7, 8
           -9,-8,-7,-6,-5,-4,-3,-2,-1

序列中元素的索引是它在序列中的位置。在上面的例子中,我们有一个数字列表, num_list ,列表下面的数字代表相应元素的索引。我们可能还记得,我们可以从开始处(从左侧开始)对序列进行索引,从索引 0 开始进行正索引,或者从序列的结尾处(从右侧开始)进行负索引,从索引-1 开始。

换句话说,如果我们想从 num_list 中检索数字 10(或第三个元素),我们可以使用它的正索引 2,也可以使用负索引-7:

num_list[2] 
#10or num_list[-7]
#10

如果我们想获得列表中的最后一个数字 40,我们可以使用索引 8 或-1:

num_list[8]
#40ornum_list[-1]
#40

或者我们可以使用 len()函数,如下所示:

num_list[len(num_list)-1]
#40

如果我们使用一个不在列表中或超出范围的索引值,我们将收到一个 IndexError:

num_list[12]
#IndexError: list index out of rangenum_list[-12]
#IndexError: list index out of range

既然我们已经回顾了如何使用正索引和负索引来索引一个序列,让我们来看看切片。

分割序列

我们刚刚看到了如何使用索引从列表中检索单个元素。另一方面,切片允许我们从序列中获取一部分,比如一个列表或字符串。

有时,为了理解切片,想象索引指向元素之间,而不是指向元素本身是很有用的。尽管这仅在步长值为正值时有用,也就是说当我们从左向右切片时。稍后将详细介绍步长值。

num_list = [0,5,10,15,20,25,30,35,40] +---+---+----+----+----+----+----+----+----+
 | 0 | 5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 |
 +---+---+----+----+----+----+----+----+----+
 0   1   2    3    4    5    6    7    8    9
-9  -8  -7   -6   -5   -4   -3   -2   -1

对序列进行切片的语法如下:

变量[开始:停止:步进]

为了分割一个序列,我们需要在方括号中使用冒号。换句话说,下标符号[方括号]中的冒号(:)构成切片符号。尽管我们可以在括号中提供三个可能的值(开始值、停止值和步/步幅值),但我们实际上不必提供所有三个值,除非我们需要,正如我们将在下面看到的。

让我们看一些例子。

指定开始和停止值

我们分割一个序列(比如一个列表)的一种方法是指定起始值和终止值。换句话说,如果我们想要列表中两个特定点之间的所有元素,我们可以使用以下格式:

变量[开始:停止]

variable[start:stop]返回以位置 start 开始的变量部分,直到但不包括位置 stop。

例如,如果我们想获得从索引 2 到索引 6 的所有元素,我们可以这样做:

num_list = [0,5,10,15,20,25,30,35,40]num_list[2:7]
#[10,15,20,25,30]

注意开始值是如何包含的,但是停止值是如何排除的。因此,我们从索引 2(即数字 10)开始,一直到但不包括索引 7(即索引 6 处的数字 30)。如果我们将索引想象为元素之间的索引(如上所示),那么将进一步说明这一点,因为索引 7 在数字 35 之前。由于我们没有提供步长值,的默认步长值是 1 。因此,我们从索引 2 开始,然后向索引 3 前进 1 步,再向索引 4 前进 1 步,依此类推。换句话说,因为步长值是正的,所以在对列表进行切片时,我们将索引增加 1(向右移动)。

仅指定起始值

如果我们想从一个特定的数字开始并遍历整个列表,那么我们只需要提供起始值。

变量[开始:]

variable[start:]返回从位置 start 开始到序列结尾的变量部分。

例如,如果我们想从整个列表的第二个索引中检索所有元素,我们可以使用下面的代码:

num_list = [0,5,10,15,20,25,30,35,40]num_list[2:]
#[10,15,20,25,30,35,40]

正如我们所看到的,如果我们只在冒号前提供一个索引,那么这将是我们的开始索引,我们将获得列表中的其余元素(因为步长值仍然是 1)。

仅指定停止值

如果我们想从列表的开头开始,一直到一个特定的索引,那么我们只需要提供停止值。

变量[:停止]

variable[:stop]返回从序列开始处开始的变量部分,直到但不包括位置 stop。

例如,如果我们想要检索从列表开始到索引 7(包括索引 7)的所有元素,我们可以这样做:

num_list = [0,5,10,15,20,25,30,35,40]num_list[:8]ornum_list[:-1]#[0,5,10,15,20,25,30,35]

因此,如果没有为起始值提供数字,那么它假设我们希望从索引 0 开始。由于我们想要检索索引 7 之前的所有元素,我们将使用停止值 8,因为它是排他的。我们也可以使用-1 作为停止值。

使用正指数和负指数

我们也可以混合搭配正负指数。例如,如果我们想要检索索引 2 到索引 7 之间的所有元素,我们可以这样做:

num_list = [0,5,10,15,20,25,30,35,40]num_list[2:8]or num_list[2:-1]ornum_list[-7:-1]ornum_list[-7:8]#[10,15,20,25,30,35]

注意,在所有情况下,停止值都在起始值的右边,因为我们使用的是正的步长值。换句话说,相对于起始值,停止值必须在步长值的方向上。如果步长值为正,则停止值必须在起始值的右侧。如果步长值为负,则停止值必须位于起始值的左侧。稍后会详细介绍。

检索整个列表

我们还可以通过使用不带开始或结束值的冒号来检索整个列表。

变量[:]

变量[:]返回整个序列。

num_list = [0,5,10,15,20,25,30,35,40]num_list[:]or num_list[::]#[0,5,10,15,20,25,30,35,40]

步幅值

到目前为止,我们只指定了开始和/或停止值,我们从开始值开始,在停止值之前结束(因为它是唯一的)。但是如果我们不想要这两点之间的所有元素呢?如果我们想要所有其他元素呢?这就是步长值的来源。

假设我们需要列表中的所有其他值,从索引 0 开始。或者我们只需要偶数索引的元素。我们可以使用步长值来实现:

变量[::步长]

num_list = [0,5,10,15,20,25,30,35,40]num_list[::2]#[0,10,20,30,40]

因为我们没有指定开始或停止值,所以它假设我们想要从序列的开始处开始并遍历整个列表。所以它从索引 0 开始,然后到索引 2(因为步长是 2),然后到索引 4,依此类推。

之前我们提到过,相对于起始值,停止值必须与步长值方向相同。换句话说,如果步长值为正,这意味着我们向右移动,停止值必须在起始值的右边。如果步长值为负,则停止值必须位于起始值的左侧。否则,将返回一个空列表:

num_list = [0,5,10,15,20,25,30,35,40]num_list[8:5]
#[]num_list[8:5:-1]
#[40,35,30]

正如我们所看到的,在两个例子中,开始值是 8,停止值是 5,所以停止值在开始值的左边。在第一个示例中,步长值为+1。因为停止值在开始值的左边,而我们的步长值是正的,所以返回一个空列表,因为我们不能向停止值的方向移动。然而,在第二个示例中,我们将步长值更改为-1。因此,我们从索引 8(40)开始,向负方向或左方向移动 1 个索引到索引 7(35),然后到索引 6(30)。我们不去索引 5,因为停止值是唯一的。

颠倒顺序

也许步长值最重要的实际应用是反转一个序列。例如,如果我们想以相反的顺序检索整个列表,我们可以使用-1 作为步长值:

num_list[::-1]#[40,35,30,25,20,15,10,5,0]

因为我们没有指定开始或停止值,所以将检索整个序列。但是,因为我们的步长值是-1,所以它以相反的顺序获取元素。

如果我们的止损值大于序列中可用的最高指数,该怎么办?或者我们的开始和/或停止值是否超出范围?换句话说,如果我们要求的东西比现有的多,会发生什么?

例如,如果我们尝试以下方法:

num_list = [0,5,10,15,20,25,30,35,40]num_list[2:12]
#[10,15,20,25,30,35,40]

正如我们所看到的,即使我们请求的条目比序列中的多,它也只是返回所有存在的元素,而不会给我们一个错误。相比之下,如果我们试图索引一个超出范围的元素(而不是切片),那么我们会得到一个 IndexError,就像我们前面看到的那样。

num_list[12]
#IndexError

分割字符串

索引和切片对于字符串也是同样的工作方式。同样,如果我们使用如下的正步长值,我们可以想象字符之间的索引:

 word = 'Python' +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

因此,为了通过切片获得子串“yt ”,我们可以这样做:

word[1:3]#'yt' 

要反转一个字符串,我们可以使用步长值-1:

word[::-1]#'nohtyP'

回文示例

让我们用我们所学的知识来解决一个非常常见的 python 编码问题。我们想写一个函数,接受一个字符串,并返回这个字符串是否是一个回文。如果一个字符串的倒数与原字符串相同,则该字符串为回文。例如,“civic”是回文,但“radio”不是,因为“radio”的反义词是“oidar”,而“civic”的反义词是“civic”。

我们刚刚学习了如何通过使用步长值-1 来反转序列。因此,我们可以很容易地编写一个函数来实现这一点,如下所示:

isPalindrome(word):
    return word == word[::-1]

就是这样!表达式 word == word[::-1] 的计算结果为真或假。如果我们传入的字符串等于它的倒数,那么表达式的计算结果为 True,返回 True。如果我们传入的字符串不等于它的倒数,那么表达式的计算结果为 False,并且返回 False。

isPalindrome('civic')
# TrueisPalindrome('radio')
# False

切片分配

如果我们记得,列表是 python 中的可变对象。换句话说,它们能够变异或改变。因此,我们可以使用片分配操作来适当地改变或编辑列表。

代替

num_list = [0,5,10,15,20,25,30,35,40]num_list[2:5] = [1,2,3]num_list
#[0,5,1,2,3,25,30,35,40]num_list[2:5] = [1,2,3,4,5,6]num_list
#[0,5,1,2,3,4,5,6,25,30,35,40]

注意我们如何用更多或更少的元素替换列表的一部分。

删除

我们还可以使用 del 关键字删除列表的一部分或片段:

num_list = [0,5,10,15,20,25,30,35,40]del num_list[2:5]num_list
#[0,5,25,30,35,40]

注意:字符串和元组是不可变的。因此我们不能像对列表那样编辑或改变它们。

分割字符串与列表

分割列表将返回该列表的副本,而不是对原始列表的引用。

我们可以在这里看到这一点:如果我们将我们的列表片分配给另一个列表,因为列表片返回一个副本,而不是对原始列表的引用,我们可以修改新列表(因为列表是可变的)而不影响原始列表:

num_list = [0,5,10,15,20,25,30,35,40]# assign a slice of num_list to new_list
new_list = num_list[2:5]new_list
#[10,15,20]# replace the third element of new_list with 3
new_list[2] = 3# new_list changes
new_list
#[10,15,3]# num_list remains the same
num_list
#[0,5,10,15,20,25,30,35,40]

相比之下,当我们分割一个字符串时,返回的是对原始字符串对象的引用,而不是副本。记住,字符串在 Python 中是不可变的。

我们可以使用 Python 的标识操作符(is)和等式操作符(==)来确认对列表进行切片会返回一个副本或不同于原始列表的对象,但是对字符串进行切片会返回对原始字符串对象的引用:

**Lists:**num_list = [0,5,10,15,20,25,30,35,40]num_list == num_list[:]
#Truenum_list is num_list[:]
#False**Strings:**word = 'Python'word == word[:]
#Trueword is word[:]
#True

相等运算符(==)检查值是否相等。identity 运算符(is)检查这两个变量是否指向内存中的同一个对象。

https://levelup.gitconnected.com/the-ultimate-guide-to-sorting-in-python-d07349fb96d5

切片函数

当我们在 python 中使用索引语法时,包括在方括号中使用冒号,内置的 slice 函数实际上被用来创建一个 slice 对象。

切片(停止)

切片(开始,停止[,步进])

slice 函数可以以两种不同的方式创建 slice 对象(类似于创建 range 对象的 range 函数)。如果我们给 slice 函数传递一个参数,那么这就是停止值。如果我们向 slice 函数传递三个参数,那么它们将具有开始、停止和步进值。换句话说,起始和步长参数将默认为无。

以下是一些示例,显示了使用索引语法对列表进行切片时使用的切片对象:

num_list[:8] is equivalent to num_list[slice(8)]num_list[2:8] is equivalent to num_list[slice(2,8,None)]num_list[2:] is equivalent to num_list[slice(2,None,None)]

如果我们想要保存一个特定的 slice 对象并多次使用它,使用 slice 函数创建一个 slice 对象会很有用。我们可以这样做,首先实例化一个 slice 对象并将其赋给一个变量,然后在方括号中使用该变量。

evens = slice(None,None,2)num_list[evens]
#[0,10,20,30,40]odds = slice(1,None,2)num_list[odds]
#[5,15,25,35]

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

https://lmatalka90.medium.com/membership

结论

在本教程中,我们首先回顾了索引序列意味着通过使用方括号中的正或负索引来提取单个元素。然后,我们比较了索引序列和切片序列,后者可以检索序列的一部分。我们学习了如何用方括号和冒号分割序列,包括指定我们想要检索的部分的不同方法。由于 Python 中的列表是可变的,我们看到了如何使用片赋值来改变列表的一部分。然后我们看到了分割一个列表和分割一个字符串之间的区别,因为分割一个列表会返回该列表的一个副本,但是分割一个字符串会返回一个对原始字符串对象的引用。最后,我们看到了在 Python 中使用切片符号时切片对象是如何被实际使用的。

一篇关于居住和沉思的演讲

原文:https://towardsdatascience.com/a-speech-for-dwelling-and-contemplation-machine-learning-the-inaugural-address-67818295585?source=collection_archive---------51-----------------------

机器学习和就职演说

1 月 20 日,按照宪法治理的正常流程,拜登总统宣誓就职。总统用演讲来纪念这一时刻——通常具有特别的说服力。在他们关于就职演说的经典方法中,Karlyn Kohrs Campbell 和 Kathleen Hall Jamison 认为就职演说通常是由他们的条件所决定的,这些演说重新组成了“人”,论证了总统职位的可能性和局限性,并且在邀请沉思中是永恒的。最好的就职演说会提出一些深刻的论点,它们不像威尔逊式的国情咨文,读起来像是一系列政策建议。里根的第一次就职颁布了跨领域的统一复兴幻想。奥巴马的第一次就职解散二进制,建立新的国家统一。坎贝尔和贾米森总结了就职演说的作用:

就职典礼必须复述过去的公共价值观,阐明指导新政府的政治原则,并证明总统能够恰当地扮演总统角色。

这是有道理的,在大多数情况下,这些地址会有非常相似的签名,因为它们可能会说许多相同的事情。在这篇文章中,我不是在阅读演讲的语义内容。我以前用情绪分析做过这个,在这一点上,这位即将离任的高管的风格是众所周知的——高度多变、情绪化、粗暴和好斗。

就职的签名

情感分析是一个有用的工具,但是经常被过度使用。在我们今天看到的背景下,知道使用普通词汇是有用的。拜登今天的情绪比他的前任更消极,但变化较小。这对于具有简单连接的词汇的情感分析来说是一个问题:高价值单词的混乱可以产生非常正常的和或*均情感得分,这只能通过偏差来揭示。深刻负面的文本很容易得到正面的分数。

我没有为了感悟而阅读,而是把拜登的就职演说加入了一个更大的可以追溯到 JFK 的就职文集。使用 Mallet for LDA,一种机器学习方法,我们可以使用停用词的一般选择来读取三十个主题的语料库。

我们三十个话题的标签

主题之间的关系如下:

请注意,话题 11 和 24 是在底部结合在一起的——这些话题在很大程度上与总统之间的共同价值观有关。12 和 23 这一组讲述了关于阿灵顿国家公墓的讨论和不断变化的对话。而在第 19 题的第一个休息处,我们可以找到每一位总统列举的人物的开头段落,比如众议院议长。在我做过的 LDA 驱动的项目中,这是在主题层面上最连贯的。机器学习的远距离阅读过程增强了*距离阅读的修辞阅读维度,作为一名研究总统沟通的研究人员,我可以以我坐在几十页纸上永远无法做到的方式快速查看和判断案件。

重要的是就职演说有多少,它们是如何进行的,以及总统们是如何选择一些话题的。每位总统都会留下一个特别的签名。

为了这个图形的目的,只有超过 0 . 4 的值被包括在内,毕竟每个段落都有 30 分,我们不需要图形的底部完全拥挤。你可以在第二届就职典礼上看到紧缩,因为与上届政府没有什么不同。为了量化这种转变,我们需要查看*均赋值值、赋值总数和每个单词的赋值。

主题 11 是最常见的作业。这里的特殊异常值包括尼克松关于越南战争结束的言论被框定为和*(29),除了特朗普咄咄逼人的一段。话题 30 是对美国的祝福和忠诚,这是拜登的一个中心主题,一个典型的总统可能会说一两个。

第二次就职典礼往往有更高的*均分配值和更高的最大值(奥巴马是一个例外),这将再次表明第二次演讲更集中。从这个意义上来说,拜登读起来更像是第二次就职演说,尽管他的最高分出现在主题 11、16 和 30,其中拜登的标志性主题“献身美国”非常明显。JFK 使用话题 11,然后是话题 26,这是一个被许多人使用的外交政策话题,但在乔治·w·布什的作品中只出现过一次。这是有道理的,因为他的第一次演讲是在 9/11 之前,但他关于外交政策的最有力的陈述是在主题 8 中——因为它们是用莱茵霍尔德·尼布尔的语言表达的,古典现实主义——它们是灵魂的问题。这也证实了另一件事:除了议题 26 中的合作语言,没有外交政策驱动的就职演说,外交政策问题隐藏在美国公民宗教中。

我们可以用这种方法确认,奥巴马的第一个是关于主题 11,然后是主题 21——一个关于克服二进制的旅程的主题。60%的 topic 21 位置来自奥巴马的第一个,Nixon1 使用了两次,Reagan2 和克林顿 1 使用了单个段落。里根的用法特别有趣,因为这是一个关于历史终结的混合隐喻:“这首歌永远回荡在未知的空气中。”

最后,考虑主题被检测到的速率是很重要的。

拜登的演讲相当长,话题比*均水*多,话题发现率接**均水*。除了奥巴马,每第二次演讲都比前一次详细。当然,有一个引人注目的异常值,我们已经确定它与其他异常值在性质上是不同的。

结论

拜登总统就职演说的修辞信号在主题选择和变化上都符合预期。主题建模过程进一步表明,除了被检测为主题 11 的标准框架(国家的未来承诺),拜登的演讲通过对美国和民主的主题关注为语料库贡献了独特的签名。虽然读数完全有可能会发生变化,但在这种最初的机器学习驱动的方法和对这些结果的修辞性阅读的背景下,很明显,拜登总统发表了一个非常符合就职典礼形式的演讲,并且非常适合这个时刻。最后,我们可以清楚地看到支持就职演说研究的悠久历史的证据。

影响公民幸福感的社会因素的统计分析

原文:https://towardsdatascience.com/a-statistical-analysis-of-social-urban-and-national-factors-that-affect-citizen-happiness-c24ed0e87dcf?source=collection_archive---------15-----------------------

使用线性回归对不同因素进行深入的统计分析

图片由 Ricardo Moura 在 Unsplash 上拍摄

摘要

本文旨在探索可能影响全球公民幸福的各种社会、城市和国家因素。报告的布局包括对用于分析数据的方法的描述,包括数据集选择、数据清理和预处理、探索性数据分析和数据建模(使用多元线性回归),然后是对每个阶段的调查结果的详细分析。该分析集中于确定对幸福分数的预测和我们的拟合模型的质量有贡献的各种因素的重要性。在我们进行的过程中,每个阶段都会回答多个子问题。然而,最重要和最有趣的分析结果在最后进行了总结,并提出了可行的建议。

介绍

随着 COVID 的出现,一种绝望和不确定感笼罩了整个世界。全世界人民的福祉和精神健康受到严重影响。这暗示了这样一个想法:随着世界一天天进步,我们的注意力更多地转向永无止境的进步,而不是真正重要的事情。我们忽略的一件事就是幸福。了解幸福的决定因素以及它们如何影响个人的福祉非常重要,这样我们作为一个社会可以共同努力改善它们,以形成一个更幸福的环境。因此,在本报告中,我们开始着眼于更大的图景,并确定以下研究问题的答案:

“公民的幸福如何取决于各种社会、城市和国家因素?”

数据集

《世界幸福报告》是一项具有里程碑意义的全球幸福状况调查。这项调查是 2012 年发起的同类调查之一,自那以来每年在 155 个国家进行。它衡量了几个社会、城市、国家和个人因素,这些因素可能会以这样或那样的方式影响幸福。幸福指数较高的国家被认为更幸福,更有利于公民的福祉,而幸福指数较低的国家则被鼓励实施以公民为中心的政策。总的来说,该报告因其完整性和在跨学科研究中的实用性而获得了巨大的全球认可。

我们将使用的数据集是 2015 年至 2019 年的世界幸福报告。它基于五个 CSV 文件,即每年一个文件,这些文件合并在一起形成一个整合的数据集。我们打算确定这些年来国内生产总值、家庭、健康和预期寿命、自由、无腐败和慷慨对公民福祉的贡献程度【1】。关于本次调查数据收集过程的背景研究显示,受访者被要求参加盖洛普世界民意测验。他们必须对上述每个因素对他们生活的影响进行评分,满分为 10 分,最低分为 0 分(即该因素不会带来幸福),最高分为 10 分(即该因素对他们的幸福贡献很大)。

方法

为了系统地找到我们的研究问题的答案,我们将我们的方法分为三个阶段,即数据清理(和预处理)、探索性数据分析(EDA)和最后的回归分析。

数据清理

在开始分析之前,理解和预处理数据是很重要的。我们首先导入我们需要用于分析的相关库。接下来,我们读取数据集并检查它们的维度,以了解我们正在处理的行数和列数。

图 1:数据集维度的 R-输出

正如我们所见,每个数据集中的列(要素)数量各不相同。我们选择了所有数据中共同的数据,以形成一个更大的数据集,并去掉不同的数据。然后,我们分别清理每个数据集。他们每个人都遵循相似的模式。我们首先检查每个数据帧中的空值,并相应地处理它们。幸运的是,我们在数据帧中几乎没有发现空值。如果我们有,我们适当地估算他们。然后,我们对列进行了标准化,即为了便于访问而对它们进行了重命名,将名称转换为小写,并检查了适当的数据类型。为了确认数据清理是否成功,我们从每个数据集中抽取了 10 行样本,并检查我们所做的更改是否成功应用。

在分别清理数据帧后,我们将它们合并成一个名为 df 的数据帧。它由 782 行和 10 列组成,如下面的 R 输出所示:

R-组合数据集的维度和列的输出

然后我们检查数据集是否有空值,我们在 corruption 列中发现了一个空值。我们有两个选择,要么删除行,要么填充空值。我们决定采用后者,并用腐败列的*均值来估算缺失值。

R-清洗前后的空值输出

上面 R 输出中的 False 表示现在数据集中没有空值或缺失值。

最后,我们检查每一列的数据类型是否合适,或者我们是否需要改变什么。让我们来看看:

R-列数据类型的输出

除了 country 之外的所有列都具有数值或整数数据类型。事实上,这些就是我们分析中将要用到的列(或前面提到的起作用的因素)。因此,列的当前数据类型对于我们的后续分析来说是很好的,因此不需要标记或编码。这使我们进入方法的第二阶段,即探索性数据分析(EDA)。

探索性数据分析

对于一个 782 行 10 列的数据集,重要的是从分析数据在正式建模、回归分析和其他测试之外能够揭示什么开始。因此,我们进行了探索性数据分析,以可视化数据并总结其特征。我们还想看看是否有任何明显的趋势,以便我们可以相应地构建我们的研究问题。

分析的特征

现在,我们知道我们有 10 个特征。其中之一是幸福得分,这是因变量。我们使用的数据源和其他网站的背景研究使我们能够找出自变量的确切含义和目的。其中每一项的详细情况如下:

数据集中特征(列)的描述

相互关系

既然我们知道了每个特性代表什么,我们想看看这些特性是如何相互关联的。我们以相关矩阵的形式计算不同特征之间的皮尔逊相关(r)。我们检查了每一个变量,看它们是正线性相关,负线性相关还是没有。

皮尔森特征间的相关性

为了便于解释,我们随后在彩色编码的热图中绘制了相关性,并附有一个参考尺度来理解它。产生的图如下:

关联热图(r)

从右边的刻度可以明显看出,特征之间较暗的图表示强线性相关性(r 更接*+1)。蓝色代表正线性相关(r > 0),而红色代表负线性相关(r < 0)。显然,特征与其自身的相关性是 1,即完全相关。令人惊讶的是,没有一个特征与另一个负相关。这暗示了一个事实,因为所有的预测变量都以一种形式衡量幸福,增加其中一个并不会导致另一个因素的减少。分数,我们的反应变量,与其余特征有最强的正相关。GDP、家庭和健康与其余变量也有中等程度的相关性,但慷慨度与其他变量的相关性最弱甚至没有相关性。

由于我们的主要目标是预测幸福分数和影响幸福分数的因素,我们决定更深入地研究每个可能的因素与幸福分数(因变量)的相关性,以了解哪些因素更有可能强烈影响幸福分数。这一次,我们打算查看皮尔逊相关的确切值,以做出尽可能准确的判断:

特征与分数的皮尔逊相关性

幸福得分与所有考虑的因素呈线性正相关。它与 GDP 的相关性最强,其次是健康和家庭。它与自由有适度的相关性,与腐败和慷慨有微弱的正相关性。

幸福分数

在探索性数据分析的前两个步骤中,我们非常重视我们的响应变量——得分。让我们更深入地了解它,以了解它在数据集中的分布。这将使我们对回归建模结果的解释更加容易。如前所述,幸福指数是人们在调查时对自己幸福程度的评价。可能的最高分是 10 分(这意味着回答者是他/她所能得到的最快乐的人),最低分是 0 分(这意味着回答者一点也不快乐)。

幸福指数的五位数汇总显示,幸福指数在 2.693 到 7.769 之间。*均幸福指数为 5.379,*均幸福指数为 5.322。最低和最高分数足够合理,即它们既不太低也不太高。由于没有异常值(如下面的方框图所示),很明显没有需要考虑的幸福指数特别高或特别低的国家。

同样,下面的幸福得分分布也表明,甚至没有一个国家的幸福得分是完美的。事实上,所有国家的幸福指数都低于 8。大多数国家的幸福指数在 5 到 6 之间(包括*均值和中间值)。所以总体来说,幸福得分的分布是对称的。

乡村幸福指数

虽然对幸福分数的国别分析超出了我们研究问题的范围,但注意到不同国家幸福分数的差异还是很有趣的。因此,我们决定鸟瞰各国的幸福指数。

下面的世界地图(以 R 绘制)显示了我们数据集中 156 个国家的彩色幸福指数。光谱左侧的颜色(即蓝色阴影)不太快乐,而光谱右侧的颜色(即红色和黄色阴影)更快乐。看看这张地图,像巴西、俄罗斯、美国和加拿大这样的发达国家显然比不发达国家更幸福。

世界范围内相关量表的幸福得分

为了有一个更具体的图片,前 20 个最幸福的国家和他们的分数被绘制如下:

回归分析

在使用预测变量和反应变量的可视化和总结彻底理解数据后,我们继续通过一个模型来理解所选预测变量对幸福得分的影响。

我们使用对幸福得分起作用的因素的多元线性回归,假设我们的预测变量与响应变量有线性关系(根据之前计算的皮尔逊相关值推断)。

该模型的基本思想是找到 GDP、家庭、健康、自由、腐败和慷慨程度的线性组合,这种组合最能预测幸福得分。我们确定了显著变量(用回归模型汇总表的 p 值< 0.05) in the prediction of score. Important diagnostics for the model included determining coefficient of determination (R-squared and Adjusted R-squared) and making and analyzing ANOVA table. We also visualized our model and the residuals using Residual Plots and Q-Q plots the interpretations of which are discussed in the latter part of the report. Lastly, to make sure our model was not faulty (i.e., it neither underfitted nor overfitted), we also employed several measures — tested multicollinearity, data distribution and then drew final conclusions from the results.

Analysis

Multiple Linear Regression

As mentioned earlier, we employed Multiple Linear Regression to model the dependence of response variable (happiness score) on a set of predictor variables (GDP, family, health, freedom, corruption, and generosity). The relevant R code for this is shown in the excerpt below alongside the summary table of the regression model as the output.

R 输出

回归方程式

根据上面的 R 输出,我们构建了以下回归方程来预测幸福得分:

得分= βo + gdpβ1 +家庭β2 +健康β3 +自由β4 +腐败β5 +慷慨β6

**得分= 2.17749+1.14675 * GDP+0.64109 *家庭+1.00394 *健康+1.47913 *自由+0.85366 腐败+0.59359 慷慨

上述方程的这些系数被解释为当一个变量改变 1 个单位而所有其他变量保持不变时幸福得分的边际增加。

βo :在所有其他预测因素都不在模型中的情况下,幸福得分将为 2.17749

gdp :如果所有其他特征保持不变,那么 gdp 每增加一个单位,幸福指数就会增加 1.14675 个单位。

家庭:如果其他所有特征保持不变,那么家庭(社会支持)水*每增加一个单位,幸福得分就会增加 0.64109 个单位。

健康:如果所有其他特征保持不变,那么健康(预期寿命)每增加一个单位,幸福指数就会增加 1.00394 个单位。

自由度:如果其他所有特征保持不变,那么自由度每增加一个单位,幸福得分就会增加 1.47913 个单位。

腐败:如果所有其他特征保持不变,那么腐败(在我们的上下文中,是对政府的信任)增加一个单位将导致幸福指数增加 0.85366 个单位。

慷慨度:如果所有其他特征保持不变,那么慷慨度增加一个单位将导致幸福得分增加 0.59359 个单位。

特征显著性(p 值)

通过分析回归模型汇总表中 Pr(>|t|)列中给出的 p 值,我们可以衡量每个预测变量在解释响应变量时的重要性。p 值是对观察到的差异可能只是随机发生的概率的度量,也可以称为对零假设的证据强度的度量。对于我们的模型,零假设(Ho)表明幸福得分和相应的预测变量之间没有关系。如果预测变量的 p 值小于 0.05(标准阈值),我们将认为它在估计响应变量中具有重要意义。

从汇总表中可以看出,Pr(>|t|)列中的所有值都小于 0.05。这表明了这样一个事实,即 Bo、gdp、家庭、健康、自由、腐败和慷慨中的所有特征在估计幸福分数时都起着重要作用。我们的回归模型的总体 p 值也小于 0.05,因此,它具有统计学意义,可以用于从给定的预测变量预测幸福得分。

下表总结了每个预测变量的 p 值及其显著性:

由各自的 p 值指示的特征(列)的重要性

决定系数

r *方是一种统计度量,表示回归模型中自变量解释的因变量方差的比例。在这种情况下,多个 R *方值代表了幸福分数的可变性,这可以用 6 个特征来解释。然而,在多变量回归设置中,多重 R *方不是一个可靠的度量,因为随着我们向模型添加更多的特征,它会不断增加,即使这些特征中的一个或多个变量可能不重要(这会导致模型过度拟合)。这可能导致对我们模型预测能力的不准确估计。

因此,在这种回归模型中,采用调整的 R *方,并确保在向模型中添加非显著变量时其值降低。在这种情况下,调整后的 R *方的值为 0.7622 或 76.22%,这表明模型使用 gdp、家庭、健康、自由、腐败和慷慨度等特征估计了大约 76% 的幸福得分可变性。

诊断学

回归模型基于一组假设,在得出关于响应变量与预测变量之间关系的结论之前,必须检查这些假设。一是初步模型拟合;为此可以采用不同的技术。

残差与回归模型拟合图

上图显示了 y 轴上的残差值(未知误差的预测值)和 x 轴上的拟合值。理想情况下,该图应该看起来像一个随机散点图,线残差= 0,方差恒定,因为残差的总和为 0。从上面的散点图中可以看出,这些点是随机分布的,没有明显的模式会违反回归模型的一个或多个假设。在该图中,编号为 457、616 和 774 的点被表示为异常值,因为它们远离残差= 0 线,但与我们拥有的数据量相比,该数字并不显著。

回归模型的分位数图

上图显示了标准化残差和理论分位数之间的正态分位数-分位数图。它用于评估残差呈正态分布的回归假设。如果数据来自正态分布,则这些点位于图上的一条直对角线上。因此,为了使正态假设成立,这些点应该位于 y = x 线上或靠* y = x 线。该曲线尾部的曲率表明数据中存在异常值。例如,编号为 457、616 和 774 的点在该图中被表示为异常值(就像残差图一样),因为它们远离 y = x 线。尽管与 y = x 线有一些偏差,但绝大多数数据点位于 y = x 线上,因此,保持正态假设有效。

回归模型残差直方图

为了重申残差正态分布的概念,我们还绘制了它们的直方图,以展示正态假设事实上是有效的。上面的图还描绘了*均值以 0 为中心,这是正态分布数据的情况。

我们还测试了模型的偏斜度,如上面的代码片段所示,模型只是稍微向左偏斜了–0.286,这并不多,可以忽略不计。因此,我们得出结论,我们的模型包含了需要在回归中考虑的一组假设。

方差分析

接下来,我们继续进行回归的一个组成部分,即 ANOVA 分析。以下是我们构建的方差分析表的 R 输出:

ANOVA(方差分析)测试允许同时对两个以上的组进行比较,以确定它们之间是否有任何关系。我们将逐一查看输出的主要结果:

我们的数据的自由度被计算为 N-(P+1)= 782-(6+1)= 775。这些是数据集中可以自由变化的数据值的数量。自由度将多次用于计算统计测量值,如 F 值,如下所示。

方差分析公式的结果 F 统计量(也称为方差分析系数)可以计算为

F =回归均方/残差均方

F 统计允许对多组数据进行分析,以分析和确定样本间和样本内的变异性。如果两组之间不存在真正的差异,即两组之间没有明显的差异,则 F 统计量接* 1。然而,在我们的模型中,高 F 值表明每个预测变量在预测幸福得分中起着重要作用。p 值的计算也表明了这一点,但是 F 值证实了我们先前的主张。因此,如上面的 ANOVA 表所示,*均值之间的所有差异都具有统计学意义,这使我们得出结论,我们拟合的回归模型作为预测变量的集合,具有高度显著性。

预测变量分析

在本节中,我们将逐一分析每个预测变量,以便更好地理解模型的结果。它包括它的分布、相关性和对幸福分数的影响,以及合理的原因。

国内生产总值

最低人均国内生产总值为 0.000,最高人均国内生产总值为 2.096,差距为 2.096。人均国内生产总值的四分位数间距为 0.6297。

如相关图所示,人均 GDP 与幸福指数有很强的正相关关系。

正如我们的回归模型所确定的,人均国内生产总值的单位增长也会导致幸福指数单位的最高增长。

直觉上,经济状况较好的国家通货膨胀率较低,国民生活更轻松。这里的一个例子是任何发达国家和发展中国家之间的比较。经济较好的国家有较高的生活水*,这可能会导致公民的幸福。

家庭的

个人以家庭、朋友和亲戚形式获得的最低社会支助水*为 0.000,最高为 1.6440,范围为 1.6440。家庭/社会支持的四分位数范围是 0.4579。

如相关图所示,个人获得的社会支持水*与幸福指数有很强的正相关关系。

正如我们的回归模型所确定的,家庭(社会支持)单位的增加也会导致幸福指数单位的增加。

从逻辑上讲,人们需要从亲戚朋友那里获得一定程度的社会支持才能快乐,这是有道理的,这两者之间的关系根植于社会环境中。很多人依靠他们的支持系统来获得幸福。因此,家庭(社会支持)是预测幸福的一个似是而非的衡量标准。

健康

健康预期寿命的最低水*是 0.000,最高水*是 1.1410,范围是 1.1410。健康预期寿命的四分位距是 0.3678。

如相关图所示,健康预期寿命与幸福指数有很强的正相关关系。

正如我们的回归模型所确定的,健康预期寿命增加一个单位也会导致幸福指数增加一个单位。

直觉上,反过来也是有道理的,因为更快乐会提高生活质量,从而带来更健康的预期寿命。在这个前所未有的疫情时代,健康生活、高免疫力和更长的预期寿命的需求凸显出来,我们的幸福建立在我们的健康和我们周围人的健康之上。

自由

做出生活选择的最低自由度为 0.000,最高自由度为 0.7240,范围为 0.7240。自由度的四分位数范围是 0.2212。

如相关图所示,做出生活选择的自由与幸福指数呈正相关。

正如我们的回归模型所确定的,自由增加一个单位也会导致幸福分数增加一个单位。

这又一次有了直觉,因为对许多人来说,以自我为中心的自主和选择是影响幸福的重要因素。

腐败

腐败认知的最低水*为 0.000,最高水*为 0.55191,范围为 0.55191。对腐败的看法的四分位数范围是 0.10161。

如相关图所示,特定国家的低腐败水*和对政府的信任度的增加与幸福指数之间的正相关性相当弱。

正如我们的回归模型所确定的那样,腐败感(在我们的案例中是对政府的信任感)每增加一个单位,幸福指数就会增加一个单位,但这种增加不如人均*均绩点或健康预期寿命等预测变量的影响深远。

如柱状图所示,对腐败的看法是正确的,这意味着这些国家对腐败的看法很高,也就是说,有腐败问题的国家越多。

慷慨

最低慷慨度为 0.000,最高慷慨度为 0.8381,范围为 0.55191。慷慨的四分位数范围是 0.1488。

正如相关图所示,慷慨与幸福指数也有微弱的正相关。

正如我们的回归模型所确定的,慷慨度单位的增加会导致幸福指数单位的增加,但这种增加不如人均*均绩点或健康预期寿命等预测变量的影响深远。

多重共线性分析

多重共线性是多元回归模型中两个或多个独立变量之间存在高度相关性的一种现象,它会导致扭曲和误导的结果,并使回归模型估计值不可靠和不稳定。虽然我们在开始分析之前检查了变量之间的相关性,但我们再次进行了交叉检查,以便(这次从多重共线性的角度)检查模型中使用的变量是否很少或没有多重共线性。

多重共线性的可视化(如果有)

上图展示了每个独立变量和其他预测值的散点图,以直观地寻找多重共线性。对角线代表 gdp、家庭、健康、自由、腐败和慷慨的密度图。从图中可以看出,只有健康和国内生产总值高度相关,而家庭-国内生产总值和健康-家庭中度相关。总的来说,可以得出结论,在自变量的总体集合中存在非常轻微的多重共线性,这不会影响我们的统计推断的可靠性。

我们通过使用下面的方差膨胀因子(VIF)模型进一步证实了这一观点。

预测变量的 VIF 分数

此处使用的测量方法 VIF 量化了多元回归设置(即我们使用的回归技术)中一组独立变量内的多重共线性的数量。从数值上来说,它是整个模型的方差和各个独立变量的方差的比例。因此,较大的 VIF 值表明一个独立变量与其他多元回归变量高度共线性,应进行调整。

在我们的回归模型中,没有一个独立变量的 VIF 值超过 3(即 VIF <= 3),如上面的水*条形图所示。一般来说,高于 10 的 VIF 表示高相关性。因为我们的预测变量的值小于阈值,所以几乎没有可能使模型不可靠的多重共线性。总体而言,无需对多重共线性进行进一步调整。

结果和结论

除了在分析的每个阶段回答的多个子问题之外,以下是可以从上述统计数字的广泛分析、可视化和阐述中得出的关键结果:

GDP、家庭、健康、自由、腐败和慷慨等因素在决定幸福得分方面发挥着重要作用。增加这些特征中的任何一个,保持其他特征不变,都会导致幸福感的增加(正如回归方程及其解释所解释的那样)。在所有因素中,自由对幸福得分的影响最大,其次是人均 GDP 和公民的健康(预期寿命)。

所有起作用的因素的 p 值< 0.05(即,我们拒绝零假设的阈值)。因此,它们对预测幸福得分都有统计学意义。然而,p 值本身不足以证实我们的发现。因此,方差分析表和 F-统计量的计算使我们得出结论,我们拟合的回归模型作为预测变量的集合,确实非常显著。

在探索性数据分析中,我们发现很少或没有异常值,并且整个数据中的偏斜度非常小,这使得数据建模和解释相关统计数据更加容易。多元线性回归足以有效地模拟和描述我们的数据。

总的来说,数据选择、数据整合、数据清理、特征选择、探索性数据分析、回归建模和后续分析使我们能够找到一开始提出的研究问题的答案,即各种社会、城市和国家因素确实有助于决定公民的幸福。

前进的道路

从我们的分析中得出了如此有趣的结果和结论,我们希望随后的幸福报告和幸福测量可以有效地用于评估国家的进步和幸福。我们的分析涵盖了 2015 年至 2019 年的幸福报告。然而,在新冠肺炎之后,幸福报告的重点需要从典型的预测稍微转移到理解疫情对主观幸福感的影响,反之亦然。

全世界已有 200 多万人死亡,变异的威胁和关于如何应对的不均衡政策决定给未来带来了不确定性。尽管如此,当务之急是通过理解个人的福祉并采取必要的措施,让彼此的事情变得更容易。这就是幸福报告及其分析发挥作用的地方。即使未来几年的报告中的影响因素保持不变,重要的是要评估在疫情的背景下,哪些因素对个人和国家的幸福影响更大。这不仅使政府能够更好地制定以公民为中心的政策,而且也使我们作为个人能够为彼此创造一个更幸福的环境。

参考

[1]网络,可持续发展解决方案。《世界幸福报告》卡格尔,2019 年 11 月 27 日,【www.kaggle.com/unsdsn/world-happiness】T2。(数据集)

[2]《世界幸福报告》。首页,可持续发展解决方案网,worldhappiness.report

[3]“起重机和生物导体上的 R 封装。”文档,数据营,www.rdocumentation.org

查看完整 R 码 此处

超级碗 LV 的统计分析

原文:https://towardsdatascience.com/a-statistical-analysis-of-super-bowl-lv-76138e70b727?source=collection_archive---------56-----------------------

酋长海盗队比赛的讨论要点

罗伯特·埃尔南德斯·维拉塔摄于佩克斯

22 周后,NFL 赛季终于结束了,我们可以坐下来回顾一下我们刚刚目睹的一切。作为联盟的惯例,汤姆·布拉迪赢得了他的第 7 枚戒指,这次是在海盗队。这是双方真正的统治性表现,海盗队自始至终赢得了这场比赛。这篇文章将呈现一个游戏的统计摘要,回顾谈话要点并呈现支持它的分析。

关键术语

  • YAC——接球后码数
  • xYAC —接球后的预期码数
  • EPA —每场比赛的预期加分
  • WPA —每次游戏增加的获胜百分比
  • EP —预期点数(可作为 EPA 的总和计算)
  • 移动——获得第一次击倒的动作

如果最后的分数没有告诉你足够的信息,这些数字可以证明这是一场多么没有争议的比赛。

作者图片

31-9 的最终比分很好地向我们展示了这场比赛是如何进行的。酋长队在前三节每节都得了 3 分,第四节一分未得,而海盗队继续疯狂得分,上半场得了 21 分,下半场得了 10 分。当我们查看 Bucs 的胜率时,在上图中用四分之一进行了颜色编码,这一事实得到了进一步强调,因为 Bucs 在上半场结束前就超过了 90%的水*。很明显,海盗队在第二节给这场比赛打上了印记。在前 15 分钟,他们设法将胜率提高了大约 5%,但在第二季度,这一数字从 60%上升到 90%。自 2014 年海鹰队和野马队之间的总决赛以来,我们还没有见过这种统治地位。在那场比赛中,海鹰队也有类似的统计表现,在第二节达到了 90%的分数,尽管西雅图队在上半场的时间超过了 3 分钟,而上周末的比赛只有 30 秒。

酋长的防守使他们输掉了比赛

作者图片

图表显示了排名前 20 的 WPA 比赛。WPA 是赢球百分比的总和,它本质上代表了一场比赛对一支球队赢得比赛的贡献。这是使用每场比赛的一系列情况输入来计算的,例如获得的码数、剩余时间、第一次进攻所需的码数、新的场地位置等。WPA 的计算方式是这样设计的,即在游戏快结束时,重要的玩法比游戏开始时的相同玩法对 WPA 的影响更大。在对方半场跑 20 码也会比在自己半场跑 20 码得到更高的 WPA。WPA 被设计来调整所有这些情境因素,因此在分析剧本时是一个相当可靠的方法。

在上图中,海盗队在 WPA 排名前 20 的比赛中占据了 14 席。橙色突出显示的是比赛中涉及点球的那些,正如我们所看到的,所有这四个点球都是针对酋长队的。合计 18.82%的罚款成本非常高,尤其是考虑到它们发生的关键时刻。4 个点球中的 3 个发生在触地得分,第一个在第 4 和第 5 次投篮尝试中,给了海盗队第一次得分,最终导致 7 分而不是 3 分。从本质上来说,在 WPA 中奖励一支球队 18%的得分和 2 次触地得分在这里是不能低估的,因为我们可以清楚地看到这对决定比赛的胜负有多大的贡献。

首席执行官们没有给帕特里克·马霍斯提供任何东西

作者图片

当看简单的盒子分数时,泰瑞克希尔和特拉维斯凯尔斯有合理的外出。酋长队的两个主力队员的码数比整个 Bucs 接收队加起来还多,但这并不能说明他们的情况表现。整个游戏过程中,酋长们都在丢弃捕获量,EPA 的统计数据让我们更好地了解了这种影响。希尔在比赛中有 73 码,但他不完整的传球和多次移动球棍的失败导致了环保局更具破坏性的表现,而不是积极的表现。例如,凯尔斯的统计数据和伦纳德·福内特的统计数据之间的比较,突出了简单统计数据中没有显示的推论。Fournette 有 1/3 的 Kelce 的接收码,也有 0 次触地得分,但总 EPA 略好。这背后的很大一部分原因可能是因为凯尔斯的不完整传球有多么重要。第三次下降时的多次下降或失误将导致环保局受到更大的处罚,因为局长们将被迫放弃。

作者图片

xYAC EPA 表示进位后从预期码增加的预期点数。持球后的预期码是另一个情境统计,根据球员接球时的位置、接球时的速度和最*的防守队员的距离计算得出。这个统计数据也是为不完整传球计算的,它代表了接球者在接球后的预期跑动距离。酋长的总 xYAC EPA 为 29.98。这告诉我们一些事情。直接的翻译是,马霍斯把他的接球手放在一个很好的位置,因为他们有持续的机会在接球后把球带到更远的地方。这也是对海盗队后场或任何在覆盖范围内打球的人的轻微指控,因为他们确实在太空中留下了接球手。这不一定是一件坏事,托德·鲍尔斯的防守一直优先向 QBs 施压,他的防守计划在周日完美地发挥了作用,但它确实给了我们一些关于海盗如何防守传球的洞察力。

完成的 YAC EPA 是 xYAC EPA 的一半,告诉我们接收器在周日完全丢失。我们不得不称赞海盗队的防守,因为他们预测传球和追截接球手的速度非常快,但这是一种无能为力的真实反映。对酋长队来说,在空中和空中得到 60 分,但实际上只得到 9 分是另一个重大的失败。

优化生活的统计法则:呼唤效应

原文:https://towardsdatascience.com/a-statistical-rule-to-optimize-your-life-the-lindys-effect-96d2c75b080d?source=collection_archive---------11-----------------------

在一个信息太多的世界里,你如何从噪音中分辨出信号?

照片由思想目录在 Unsplash 上拍摄

有时候,我一觉醒来,会着急打开手机。浏览所有的社交媒体新闻,浏览《纽约时报》的应用程序,希望在 Youtube 上看到一些新的上传,这需要 很多时间

每天淹没我的信息洪流产生的痛苦大于收获。每一点信息都被优化得“看起来紧急/重要”,以至于我们不得不不断地选择要处理什么,而我们知道其中很少(如果没有的话)会在接下来的 24 小时内保持相关?

如果存在一种规则来识别哪种类型的新闻或信息在未来很长一段时间内仍然相关,那会怎样?

如果有一个指南,你可以用来从其他的噪音中过滤出值得知道的知识,那会怎么样?

有——这叫做林迪效应

呼唤效应——或作为质量评判标准的时间价值

呼唤效应是这样一个观察结果:

一件藏物存在的时间越长,它可能存在的时间就越长。

纳西姆·尼古拉斯·塔勒布在他的书https://www.amazon.com/dp/B0083DJWGO/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1中,把这个概念解释得相当干净:“如果一本书已经印了四十年,我可以预计它还会印四十年。但是,[……],如果它能再生存十年,那么它就有望再出 50 年。”

这个想法是,像一本书/技术/智力产品等一些不易腐烂的东西的未来预期寿命与它们当前的年龄成正比;每多存活一段时间意味着更长的预期寿命。

数学动机:

呼唤效应始于一个想法,即一些智力人工制品的寿命遵循帕累托分布:一个带有沉重的、“缓慢衰减”尾部的偏斜分布(即大部分数据在尾部)。

帕累托图的一个例子。左边是占主导地位的少数,右边是包含大量数据的长尾。图片来自维基百科——公共领域。

你可能听说过帕累托分布,即著名的 80/20 法则:有几个项目非常普遍,对分布的“头部”贡献很大,例如,20%的高收入者占全国财富的 80%;顶级足球队在英国联赛中只占一小部分,但他们却占据了电视版税的大头。

通过帕累托分布对工件的生命周期建模意味着大多数项目将只持续很短的一段时间,但是有一个长尾巴的项目可以持续更长的时间。大量的经济研究已经证实了智能人工制品的这一特性。

我们可以将这种工件的寿命概率分布函数——PDF(t)写成帕累托形式:

其中 t_m (比例参数)是 t 的最小可能值, α 是形状参数,也称为尾部指数。注意 t_m 必然是正数,即工件的寿命必须为> 0。

现在,我们要找到预期寿命 E(t) ,条件是它已经持续了一段时间 t_0 。换句话说,我们要找到 E(t|t > t_0)。

因此,在 t_0E(t-t _ 0 | t>t _ 0)之后的预期额外寿命为:

虽然数学看起来令人生畏,但结果却出人意料地清晰。有条件的预期额外寿命简单地是已经过去的时间()乘以比例常数【α-1】

  • α 越接* 1,比例常数越大,我们对工件的预期额外寿命就越大。如果 α = 2,则比例常数为 1。即 预期额外寿命等于目前所见寿命。
  • 例如,当 α = 2 时,一旦到达 t_0,我们期望的未来寿命也是 t _ 0;如果达到该点使得总寿命到目前为止为 2t_0,则新的预期未来寿命是 2t _ 0;诸如此类。

模拟

我知道不是每个人都喜欢数学证明,所以我会试着用一个小模拟来说服你。

让我们假设 2021 年是你最喜欢的书的 20 周年纪念,你想知道这本书在完全被遗忘之前还有多少年。

我们要做的是从 P(t-t_0|t > 20,α)α, 的不同值,模拟生命周期的许多许多场景,并观察分布如何表现

现在,实际执行这种模拟需要一种称为逆随机采样的技术。它的细节超出了本帖的范围,但是如果你感兴趣,我写了 一个小说明 解释技巧。

条件抽样和绘图的样本代码

您可以看到,随着 α 值的增加,头部周围的条件分布变得“更重”,从而导致剩余年数的条件预期更小。一本已经印了 20 年的书,如果 α=1.5 ,20 如果如果 α=2 ,10 如果 α=3 ,预计还能再印 40 年。

一个有趣的结果是比较了剩余寿命的条件预期在呼唤人和人之间的差异。

通过一些快速的研究,我发现美国男性的寿命分布遵循*均寿命为 70 岁的威布尔分布。有了这些信息,我们就可以做一些模拟,看看一个人庆祝完 20 岁生日后剩余寿命的条件概率是多少:

左图:前 20 年过去后呼唤氏好(Pareto withα= 2)和人类(Weibull with mean = 70)的条件概率分布函数——虚线代表各自分布的均值。右图:作为已过去年数的函数的预期剩余年数。****

我们了解到技术和人类有不同的生存模式。

  • 考虑到最初的 20 年,呼唤的预期剩余寿命是 20 年,而我们预计美国男性的*均寿命是 50 年(加起来是 70 岁)。
  • 然而,一个人越老,他剩下的预期年数就越少。这是因为人类的寿命遵循细尾分布——比帕累托分布的尾部细得多。帕累托分布的重尾是为什么一项技术存活的时间越长,我们就能期待它存活的时间越长。用塔勒布的话来说,技术 “反过来老化。”

运用呼唤效应优化你的生活:

本质上,呼唤效应教给我们一个简单的原则:如果你无法决定,那么就让时间成为内容的自然过滤器:

  • 我已经卸载了手机上所有的新闻应用,同时订阅了每周新闻简报。如果一个事件是重要的和有新闻价值的,那么它应该在最初的 24 小时之外保持如此。
  • 书籍:不知道在比尔·盖茨的读书笔记和 NPR 的书《礼宾》中选择哪本书?读经典。《圣经》、马基雅维利的《君主论》、马可·奥勒留的《沉思录》,这些书的真知灼见经受住了时间的考验,它们很可能比今年 NYT 的大多数畅销书都要长寿。
  • ML 算法:根据 2016 年 Kdnuggets 的一项调查,高斯在 19 世纪发明的通过最小*方估计的线性回归仍然是迄今为止数据科学家中最受欢迎的机器学习技术。如果我必须在最小*方线性回归和深度神经网络之间打赌,并选择哪种算法在 2200 年仍将被使用,我的赌注肯定是前者。

一些警告:

正如我们已经看到的,呼唤效应是非常整齐的概率陈述。但它们确实是概率陈述,你不应该把它看得太重:

  • 我们并不确定哪一项展现了呼唤效应。申请的条件相当严格。并非一切都遵循帕累托分布:人类的寿命当然不会,原子衰变也不会。最重要的是,即使一个工件的寿命以帕累托方式分布,我们已经看到,如果我们只是稍微移动一下形状参数,额外的寿命预期会有很大的不同。
  • 注意,我计算的是E(t | t>t _ 0),也就是说,它只以知道 t > t_0 为条件。如果你有额外的信息,比如有证据表明某项技术正在衰落,那么你就需要以这些信息为条件。

因此,林迪效应是一种微不足道的启发法,随着你获得更多的相关信息,它的有用性会降低。

但是你知道,要过滤阅读的书籍和新闻,也许琐碎的试探法就足够了。

如果你喜欢这篇文章,你可能也会喜欢我的另一篇关于有趣的统计事实和经验法则的文章

  • 迪士尼电影是对的——我们都是特殊的,从统计数据来看也是如此
  • 规则三:计算尚未发生事件的概率

对于其他深潜分析:

  • 贝叶斯统计如何说服我去健身房?
  • 利用数据驱动的体育博彩策略赚大钱
  • 寻找上帝的贝叶斯探索

这个项目的完整代码可以在我的 Github 中找到。

图像聚类的分步指南

原文:https://towardsdatascience.com/a-step-by-step-guide-for-clustering-images-4b45f9906128?source=collection_archive---------0-----------------------

用于图像簇的检测和探索。了解如何仔细预处理图像,利用众所周知的特征提取方法,并评估聚类的良好性。理论背景,然后是实践教程。

万用眼在 Unsplash 上拍照

许多计算机视觉任务依赖于(深度)神经网络,旨在预测“图像上有什么”。然而,并不是所有的任务都需要监督方法或神经网络。通过无监督的方法,我们可以确定图像的自然组或簇,而不局限于固定数量的(学习的)类别。在这篇博客中,我将总结无监督聚类的概念,然后是一个关于如何预处理图像、提取特征(PCA、HOG)以及考虑到聚类的良好性对具有高相似性的图像进行分组的实践教程。我将演示对【MNIST】数据集* 、 101 对象数据集花数据集 的聚类,最后使用【Olivetti】数据集面孔 的聚类。所有结果都是使用 Python 库clustimage导出的。***

如果你觉得这篇文章很有帮助,可以使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 关注我的最新内容!

重要的事情先来。

图像识别是一项计算机视觉任务,其识别部分可以分为有监督的和无监督的方法。在监督任务的情况下,目标可以是对图像或图像上的对象进行分类。现在有各种各样的预学习模型用于分类任务。共同的主题是,所有监督模型都需要一个学习步骤,其中使用基础事实标签来学习模型的对象。一些模型可以容易地识别数百个对象,并且这个数字在稳步增加,但是大多数特定领域的对象在预先学习的模型中可能仍然是未知的。在这种情况下,向无监督聚类方法的过渡似乎是不可避免的。构建高质量的标注数据集是一项艰巨的任务,因此倾向于使用聚类方法。

**一般来说,无监督机器学习的任务是从“未标记”的数据中推断出一个描述隐藏结构的函数

非监督任务不仅仅是聚类,还可以用于各种其他任务,如数据探索、离群点检测和特征提取。在这篇博客中,我将关注 无监督聚类方法及其在图像识别中的应用 。然而,图像的聚类需要多个步骤,每个步骤都会影响最终的聚类结果。让我们从一个示意图开始,然后进入兔子洞。

图像聚类的示意图。

图像的聚类是一个多步骤的过程,其步骤是 预处理图像提取特征根据相似性对图像 进行聚类, 使用优度来评估聚类的最佳数目 。另请参见图 1 中的示意图。所有这些步骤都很容易在 python 包clustimage中实现,该包只需要 路径位置原始像素值 作为输入。

图一。图像无监督聚类的 clustimage 中所采取步骤的示意图。图片来自作者。

我将在接下来的章节中描述这些步骤,但是让我们先简单介绍一下无监督聚类的背景和一些术语。

无监督聚类。

对于无监督聚类,我们的目标是在不使用关于标签或类别的先验知识的情况下,确定数据中的“自然的或“数据驱动的”组。使用不同的无监督聚类方法的挑战在于,它将导致样本的不同划分,从而导致不同的分组,因为每种方法都隐含地对数据施加了结构。因此问题出现了;什么是“好的”集群?图 2A 描绘了二维空间中的一串样本。直观上,我们可以将它描述为一组杂乱的样本(也称为图像)。我会声明有两个不使用任何标签信息的聚类。为什么?因为点与点之间的距离,以及杂乱样本之间相对较大的“间隙”。

图二。聚类示例。图片来自作者。

考虑到这一点,我们可以将我们对“”的直觉转换成一个数学陈述,例如;所谓的类内样本的方差应该较小( 内方差【σW】,红蓝* ),同时类间方差应该较大( 间方差,【σB】),如图 2B 所示。样本之间的距离(或内在关系)可以用 一个距离度量 (例如欧几里德距离)来测量,并存储在所谓的相异度矩阵中。然后可以使用 链接类型 计算样本组之间的距离(用于层次聚类)。*

距离度量

最广为人知的距离度量是欧几里德距离。尽管在许多方法中它被设置为默认度量,但它并不总是最佳选择。

理解指标的数学属性,使其符合数据的统计属性,并与研究问题保持一致。

各种距离度量的示意图如图 3 所示[1]。在图像相似的情况下,当使用主成分分析(PCA)【2】或梯度方向直方图(HOG)* 提取特征时,推荐使用欧几里德距离。*

图 3:最流行的距离度量的示意图。图片作者:马腾·格鲁特·奥斯特[1]。由作者编辑。

链接类型

**分级聚类的过程包括将样本分组到更大的聚类中的方法。在此过程中,需要计算两个子集群之间的距离,不同类型的链接描述了集群之间的连接方式(图 4)。

图 4:链接类型。图片由作者提供。

简单来说,两个聚类之间的 单连锁 就是它们最接*的两个样本之间的接*程度。它产生一个长链,因此非常适合聚类球形数据,也适合异常值检测。 完全连锁 两个星团之间的距离就是它们两个最远样本之间的接*度。直观上,两个相距最远的样本不可能比其他完全不同的样本对更不相似。它迫使星系团呈球形,其边界通常具有“紧凑的”轮廓,但内部不一定是紧凑的。 两个集群之间的*均链接 是一侧的一个对象与另一侧的另一个对象之间的所有邻*度的算术*均值。 形心连锁是簇的几何形心之间的接*度。谨慎选择度量链接类型,因为它直接影响最终的聚类结果。考虑到这一点,我们可以开始预处理图像。

图像预处理。

在我们从图像中提取特征之前,我们需要执行一些预处理步骤,以确保图像在图像大小 中与 相当。预处理步骤利用了open-cv和流水线中的clustimage。******

  1. 色阶: 将图像转换成例如灰度(二维)或彩色(三维)。
  2. scale: 归一化最小和最大范围[0,255]之间的所有像素值。
  3. dim: 调整每个图像的大小,确保特征的数量相同。
**pip install clustimage**

图像预处理示例,包括颜色缩放、数值缩放、大小调整和矢量化。

图像特征提取。

在对图像进行预处理之后,我们可以开始使用像素值信息从图像中提取特征。有许多方法来提取特征,但我将集中于 PCA 和 HOG 特征,因为这些是公认的技术,可以很好地概括不同类型的对象。我将简要回顾 PCA 和 HOG,但更多细节我建议阅读其他文章和博客。

主成分分析

使用主成分分析,我们可以降低维数,并提取主要成分(PC ),其中大部分方差可见。非常重要的是,所有图像必须具有相同的宽度和高度,并且进行类似的预处理,因为像素值将形成特征空间。假设我们有 100 张 128×128 像素的灰度 2D 图像。每个图像将被展*并形成大小为 16384 的向量。现在可以将向量堆叠起来,形成一个新的 NxM 阵列,其中 N 是 100 个样本,M 是 16384 个特征。特征提取将在 NxM 阵列上进行。在在后一种情况下,将自动确定电脑的数量。

方向梯度直方图(HOG)

HOG 是一个特征描述符,用于从图像数据中提取与边缘的方向和方位相关的特征。一般来说,它是图像的简化表示,仅包含最重要的信息,例如图像的局部部分中梯度方向的出现次数。总结如下:

  1. HOG 描述符侧重于对象的结构或形状。HOG 特征包含边缘和方向信息。
  2. 完整的图像被分解成更小的区域(局部部分),并且对于每个区域,计算梯度方向。
  3. 最后,HOG 会为这些区域分别生成一个直方图。直方图是使用像素值的梯度方向创建的,因此称为梯度方向直方图。

使用 HOG 功能时,并非所有应用程序都有用,因为它“仅”提供图像的轮廓。例如,如果用例是对不同的通用对象进行分组,HOG 特征可以做得很好,但是对象内更深层次的相似性可能很困难,因为细节可能会丢失。然而,如果需要增加 HOG 特征,可以减少每个像元的像素(例如 4,4)。

从花中提取 HOG 特征的例子。

图 5。HOG 特征描述符。左:输入图像。右图:猪的特征。图片由作者提供。

集群评价。

在这一点上,我们预处理图像,提取特征,并且在我们心中有了目标,我们选择链接类型并且能够开始聚类图像以基于距离度量找到相似的组。然而,聚类方法不 而不 提供关于聚类的可分性、良好性或最佳数量的信息。为了评估聚类,有各种方法,其中最著名的方法是Silhouette scoreDavies–Bouldin(DB)。每种都有其属性,其摘要如下:

  • 戴维斯–波尔丁指数(dbindex) :直观上可以描述为簇内距离和簇间距离的度量。分数有界在[0,1]之间, 越低越好 。请注意,由于它测量聚类质心之间的距离,因此仅限于使用欧几里德距离。
  • 剪影得分 :剪影值是一个样本与其聚类(内聚)相比与其他聚类(分离)相似程度的度量。分数限制在[-1,1]之间,其中高值指示对象与其聚类匹配良好,而与相邻聚类匹配较差。因而 分数越高越好 。与 DBindex 相反,剪影得分是一种样本方式的测量,即测量一个聚类内的样本的*均相似性以及它们与其他聚类中的其他对象的距离。轮廓分数可以与任何距离度量结合使用。

对于聚类的评价,clusteval库在clustimage中使用,包含三种评价方法: 剪影DBindex ,以及 衍生 方法。评估方法应与聚类方法结合使用,如agglomerate、k-means 或 dbscan ,这些方法也包含在 clustimage 中。同样,理解这些方法的数学属性很重要,这样它才能与(预期的)聚类的统计属性相匹配。例如, DBscan 结合剪影评估可以检测具有不同密度和形状的聚类,而 k-means 假设聚类是凸形的。**

请注意,聚类评估方法很容易被欺骗,因为分数会随着聚类数量的增加而逐渐提高。

明智的做法是设置聚类数量的搜索范围,以找到局部最小值/最大值。

MNIST 数据集。

MNIST 是一个著名的手写数字数据集,它非常适合于检查和展示方法的性能。让我们加载数据集并运行clustimage来检测集群。在这种情况下,我将使用 PCA 提取特征,并将所有其他参数保留为默认值。默认设置如下:对于 预处理 ,将灰度设置为(将其设置为真不会改变结果,因为图像很容易被灰度化),如果需要,图像尺寸减少到 128,128 。PCA 用于 特征提取 ,其中选择覆盖 95%方差的主成分数。使用具有欧几里德距离度量和沃德链接的凝聚方法来检测聚类。使用剪影得分评估聚类和最佳聚类数。聚类数的搜索范围在[3,25]之间。为了可视化的目的,执行 tSNE 以减少高维空间并分散相对于彼此的样本。

正如您可能注意到的,在clustimage中,有许多参数的所有功能都很容易流水线化,以对图像进行聚类并确定最佳聚类数。输出存储在 结果 和对象本身中。让我们看看结果。维数减少到 29 个特征(图 6)并存储在 feat 键中。可用cl.pca.plot()绘制解释的差异。嵌入的坐标存储在 xycoord、 中,聚类标签可以在 标签 中找到。为了更直观地了解性能,我们可以绘制各种图表,例如聚类的良好程度、每个聚类中相似检测样本的一致性,以及散点图。

图 6。解释差异。图片作者。

集群评价。

我们使用检测到 10 个最佳聚类的轮廓分数(图 7A 中的最高相对分数)来评估分级聚类。数据集也包含 10 个数字[0 到 9],但我们需要检查聚类是否也表示这些数字。在图 7B 中,我们可以看到每个样本的系数值。许多样本具有较高的值,这意味着聚类配置是适当的。如果有许多点具有低值或负值,则聚类配置可能具有太多或太少的聚类。因此,总的来说,两个图都表明样本的良好聚类。

cl.clusteval.plot() cl.clusteval.scatter()

图 7。基于轮廓得分的聚类评价结果。a .聚类数与轮廓分数的关系。b .每个样本的轮廓系数值。图片由作者提供。

为了研究样本在聚类中的分布,我们可以用cl.plot_dendrogram()绘制树状图。树状图提供了样本在 10 个聚类中的分布情况,聚类之间的距离似乎或多或少是均匀分布的,没有强烈的异常值或其他可能干扰聚类结果的影响。

使用功能cl.plot_unique(),我们可以绘制每个聚类的质心图像。此外,还可以通过设置以下参数对每个聚类的所有图像进行*均:cl.plot_unique(img_mean=True)。后一个选项有助于更直观地了解每个聚类的图像是否相似。例如,如果我们看图 9 中的聚类 7,聚类的质心似乎是数字 3,而*均图像似乎更像 9?这表明群集可能看到不完全相同的图像。

图 9。绘制每个集群的独特图像。a .每个聚类的最质心图像。b .每个聚类的*均图像。图片由作者提供。

基于 t 分布随机邻居嵌入的散点图

使用散点图功能cl.scatter(zoom=5),我们可以将样本分散在嵌入的 2D tSNE 空间中,并直观了解样本相对于彼此的分布情况。注意,样本(数字图像)在高维空间中确定的聚类标签上是有颜色的。在这种情况下,2D tSNE 嵌入仅用于可视化目的。对于每个聚类,在 2D 空间中确定质心,并绘制最接*质心的图像。总的来说,我们看到一些数字可能需要进一步检查的聚类的清晰分离,例如聚类 4 和 5。为了查看集群标签,我们可以将zoom参数设置为 None,cl.scatter(zoom=None)

图 10。tSNE 嵌入的散点图。图片作者。

为了更深入地检查集群中的图像,我们可以使用绘图功能cl.plot(cmap=’binary’, labels=[4,5])。这里我们只画出感兴趣的聚类,比如聚类 4 和 5。簇 4 似乎包含数字 1 和 9,簇 5 包含数字 1、4 和 9。

图 11。为指定的集群绘制图像。a .群组 4 中的图像。b .第 5 组中的图像。图片作者。

猪的特征。

使用clustimage,也可以通过将方法设置为 hog,使用方向梯度直方图提取特征。** 因为 MNIST 的图像尺寸很小,所以也需要减少每个像元的像素数来计算 hog 特征。让我们再次聚类 MNIST 数据集,但现在使用 HOG 特征。**

使用pixels_per_cell:(2,2)可以获得以下结果。

图 12。使用 HOG 特征检测聚类。a .聚类数与轮廓分数的关系。使用 HOG 特征的 tSNE 嵌入的散点图。图片作者。

基于最大剪影 分数检测十四个聚类。注意,第二个局部最优值是 10 个集群。当我们将聚类结果(图 12B)与使用 PCA 的聚类结果(图 10)进行比较时,基于视觉检查,使用 HOG 特征的聚类显得不太明显。当使用最接*质心的图像和每个聚类的*均图像绘制每个聚类的独特图像时,我们可以更深入地检查聚类。尽管如此,结果似乎是合理的。

图 13。绘制每个集群的独特图像。a .每个聚类的最质心图像。b .每个聚类的*均图像。图片由作者提供。

聚类 101 对象和花数据集的示例。

对 MNIST 数据集进行聚类很有趣,但现在我们将对两个真实世界的数据集进行聚类。第一个数据集包含大量不同的对象,第二个数据集相对较小,但包含不同的花的子类型。

加州理工 101 对象数据集。

包含 101 个对象的大型数据集是 Caltech101 数据集。该数据集包含属于 101 个类别的 9144 幅真实世界图像。大约 40 至 800 每类图像。每张图片的大小大约为 300 x 200 像素,可以在加州理工学院的网站上下载。作为对clustimage的输入,我们可以简单地提供存储所有图像的路径位置。子目录中的所有图像将被递归收集。

检测到最佳的 63 个聚类(图 14A ),其中聚类的质心图像在图 14C 中示出,这少于 101 个已知输入对象。尽管如此,一些聚类还是很好地从整体中分离出来(图 14B),并且包含具有高相似性的图像(图 14D)。由于 tSNE 算法的性质,在 2-D 空间中更居中的聚类可能不像图 14D 所示的那样纯。总的来说,一些对象倾向于很好地聚类,而其他对象可能需要进一步微调模型参数,或者甚至可能需要不同的特征提取方法。

图 14。Caltech101 数据集。a .轮廓分数在 63 个聚类处检测到最佳值。b .使用检测到的聚类标签对样本进行着色的 tSNE 嵌入。c .每个聚类的质心图像。d .在群集 13 中检测到的图像。图片由作者提供。

花卉数据集

花卉数据集包含 210 幅图像,并使用 HOG 方法进行聚类。在花数据集的情况下,与使用基于视觉检查的 PCA 特征相比,HOG 特征似乎产生更好的结果(结果未示出),即使颜色在特征提取方法期间丢失。如果图像数量变大,也可以将方法设置为pca-hog,对 HOG 特征执行 PCA,从而显著减少特征数量,节省内存并保留结果。

检测到最佳的 6 个聚类(图 15A ),这些聚类的质心图像在图 15B 和 c 中示出。质心图像的 HOG 特征在图 15D 中示出。

图 15。花卉数据集。a .轮廓分数在 6 个集群处检测到最佳值。b .使用检测到的聚类标签对样本进行着色的 tSNE 嵌入。c .每个聚类的质心图像。提取的猪特征。图片由作者提供。

图。检测到的聚类 1 和聚类 4 中的样本。图片由作者提供。

聚类人脸。

使用 clustimage 库也可以进行人脸聚类。然而,这可能需要额外的步骤,即从图像中提取脸部的。可以使用 cl.extract_faces()功能从图像中提取人脸,该功能反过来使用 openCV 的 haar 级联,更具体地说,是 Haar cascade _ frontal face _ default . XML。在本例中,我们将加载具有 400 张人脸图像的著名的 Olivetti faces 数据集。对于这个数据集,不需要提取人脸,因为人脸很容易被裁剪。

当我们运行 clustimage 时,检测到 18 个簇的最优值(图 16A),嵌入了簇标签的 tSNE 如图 16B 所示。我们确实看到了一些集群的分离,现在可以使用cl.plot()功能检查每个集群。

图 16。人脸数据集。a .轮廓分数在 18 个聚类处检测到最佳值。b .使用检测到的聚类标签对样本进行着色的 tSNE 嵌入。c .每个聚类的质心图像。d .聚类 15 中的图像示例。图片由作者提供。

找到相似的图像。

除了聚类功能外,clustimage**库也包含了搜索图片的功能。使用find功能,可以提供输入图像,并将返回类似的图像。实现了两种方法:

  • 基于 k *邻。
  • 基于概率密度拟合后的显著性。

对于这两种方法,使用指定的距离度量(默认欧几里德)跨所有图像计算邻接矩阵。在 k-最*邻方法的情况下,选择 k-最*邻,并且逻辑上它将总是导致命中。在密度拟合的情况下,邻接矩阵用于估计测试分布 ['norm ',' expon ',' uniform ',' gamma ',' t'] 中 loc/scale/arg 参数的最佳拟合。拟合的分布形成样本的相似性分布。对于每个新的看不见的输入图像,跨所有图像计算相似性的概率,并且返回在分布的下限中为P<α的图像。这种方法只会返回重要的命中结果。在指定了 kα两个参数的情况下,取检测样本的并集。让我们使用 flower-dataset,使用来自路径位置的输入图像来查找相似的图像。**

在上面的例子中,我们的目标是检测两幅输入图像的相似图像。出于演示目的,这些图像也在 fit_transform 功能本身中。或者换句话说,我们至少应该能够检测到相同的图像。图 17 展示了相似性显著且 P < 0.05 的图像。请注意,由于拟合分布中的随机成分,结果可能会略有变化。

图 17。输入图像用红色矩形表示。a .检测到一幅输入图像。b .检测到 34 个相似性显著的图像。图片由作者提供。

最后的话。

我提到了无监督聚类的概念,以及如何从原始输入图像到高度相似图像的聚类。图像的聚类需要多个步骤和各种方法。采取不同的步骤和/或方法将产生不同的分组,因为它隐含地对数据施加了结构,从而对样本进行了划分。 clustimage 包可以帮助使用众所周知的特征提取、评估和聚类方法。通过各种绘图功能可以很容易地研究结果。此外,它还可以用于检测新的看不见的图像的非常相似的图像。如果你的目标是找到(几乎)相同的图像(照片),我推荐阅读这个博客,它是关于使用 可撤销库 使用图像哈希函数检测重复图像的这已经成为一篇冗长的文章,但是底线是总是确保方法的数学属性与数据的统计属性相匹配。

注意安全。保持冷静。

干杯 E.

如果你觉得这篇文章很有帮助,可以使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 保持我的最新内容!

软件

  • clustimage Colab 笔记本
  • clustimage Github/文档
  • clusteval Github/文档
  • 无疑问 Github/文档

我们连线吧!

  • 我们在 LinkedIn 上连线
  • 在 Github 上关注我
  • 在媒体上跟随我

参考

  1. Maarten Grootendorst 、、数据科学中的 9 个距离测度走向数据科学,2021 年 2 月
  2. *Kimberly L. Elmore 等人*、、欧氏距离作为主成分分析的相似性度量、、 AMS,2001 年 3 月 1 日
  3. Sergei Evgenievich Ivanov 基于修正距离度量的物体识别与分类Procedia Computer Science 136(2018)**

使用贝叶斯定理设计知识驱动模型的分步指南。

原文:https://towardsdatascience.com/a-step-by-step-guide-in-designing-knowledge-driven-models-using-bayesian-theorem-7433f6fd64be?source=collection_archive---------7-----------------------

实践教程

万一你没有数据但是有专家知识。将知识转化为计算机辅助模型的入门指南。

照片由: 基兰木 ,Unsplash

数据是模型的燃料,但是您可能已经目睹了没有数据,只有一个领域专家可以很好地描述甚至预测给定环境下的情况的情况。我将从 贝叶斯概率 的角度总结 知识驱动 模型的概念,接下来是一个动手教程,演示将专家的知识转化为贝叶斯模型的步骤,目标是做出推论。我将使用 S prinkler 系统从概念上解释从知识到模型的过程中的步骤。最后,我将讨论复杂知识驱动模型的挑战,以及由于提问和提取知识而可能出现的系统性错误。所有的例子都是使用 python 库 bnlearn 创建的。

如果你觉得这篇文章很有帮助,可以使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 关注我的最新内容!

我们能把专家的知识融入模型吗?

当我们谈论知识时,它不仅仅是描述性的知识,如事实。知识也是对某人或某事的熟悉、觉察或了解,程序性知识(技能),或熟人知识[ 1 ]。

无论你有什么知识,或者想使用什么知识,如果你想建立一个计算机辅助知识模型,它都需要以计算机可解释的方式呈现。

这意味着你需要设计一个建立在一系列流程阶段上的系统。或者换句话说,一个序列从一个过程的输出进入下一个过程的输入。多个简单的序列可以组合成一个复杂的系统。我们可以把这样一个系统表示成一个有节点和边的图。每个节点对应一个变量,每条边代表变量对之间的条件依赖关系。通过这种方式,我们可以根据专家的知识定义一个模型,最好的方法是使用贝叶斯模型。要回答这个问题,我们能把专家的知识转化为模型吗? ' 嗯,这要看你把知识用图形表示出来有多准确,用概率定理又叫贝叶斯图形模型把它粘在一起有多精确。尽管如此,还是有一些限制。

贝叶斯图形模型是创建知识驱动模型的理想选择。

机器学习技术的使用已经成为在许多领域获得有用见解和做出预测的标准工具包。然而,许多模型是数据驱动的,这意味着需要数据来学习模型。将专家的知识整合到数据驱动的模型中是不可能的,也不容易做到。然而,机器学习的一个分支是 贝叶斯图形模型 (又名贝叶斯网络、贝叶斯信念网络、贝叶斯网、因果概率网络和影响图),可以用来将专家知识纳入模型并进行推理。下面是一些贝叶斯图形模型的优点,我将在本文中强调。

  • 将领域/专家知识纳入图表的可能性。
  • 它有模块化的概念。
  • 复杂的系统是由简单的部分组合而成的。
  • 图论直观地提供了高度交互的变量集。
  • 概率论提供了结合各部分的粘合剂。

要制作贝叶斯图形模型,您需要两个要素:1 .有向无环图和 2。条件概率表。只有一起才能形成专家知识的表示。

第 1 部分:贝叶斯图是有向无环图(DAG)

至此,你知道知识可以表示为一个系统化的过程,可以看做一个图形。在贝叶斯模型的情况下,一个图需要被表示为一个 DAG但达格到底是什么? 首先,它代表 D 有向 A 循环 G 图,是一个具有有向的节点(变量)和边的网络(或)。图 1 描绘了三个独特的 图案,可以用三个变量(X,Y,Z)来制作。节点对应于变量 X、Y、Z,有向边(箭头)表示依赖关系或条件分布。网络是无环的 T21,这意味着不允许有反馈回路。

使用 DAG,可以通过组合(较简单的)部分来创建复杂的系统。

图 1:三节点 DAG 的三种独特模式(图片由作者提供)。

所有 Dag(大型或小型)都是根据以下 3 条规则构建的:

  1. 边是条件依赖。
  2. 边缘是有方向的。
  3. 不允许反馈循环。

这些规则很重要,因为如果您删除方向性(或箭头),三个 Dag 将变得相同。或者换句话说,有了方向性,我们可以使 DAG 可识别[2]。有许多博客、文章和维基百科页面描述了 Dag 背后的统计数据和因果关系。您需要理解的是,每个贝叶斯网络都可以通过这三种独特的模式来设计,并且应该代表您想要建模的过程。设计 DAG 是创建知识驱动模型的第一部分。 第二部分是定义条件概率表 ,用(条件)概率描述每个节点的关系强度。

第 2 部分:定义条件概率表来描述节点关系的强度。

概率论(又名贝叶斯定理或贝叶斯规则)构成了贝叶斯网络的基础。查看这篇关于 贝叶斯结构学习3的中型文章,阅读更多关于贝叶斯定理的具体部分。虽然这个定理在这里也适用,但还是有一些不同。首先,在知识驱动的模型中,CPT 不是从数据中学习的(因为没有数据)。相反,概率需要通过提问从专家那里获得,并随后存储在所谓的条件概率表(CPT)(也称为条件概率分布,CPD)中。在本文中,我将交替使用 CPT 和 CPD。**

CPTs 用条件概率或先验来描述每个节点的关系强度。

然后,CPT 与 Bayes 规则一起使用,以更新允许做出推断的模型信息。在下一节中,我将通过洒水车用例来演示如何用专业知识准确地填写 CPT。但是首先,将专家的知识转化为概率存在挑战。

将专家知识转化为概率

当我们想要建立一个知识驱动的模型时,从专家那里提取正确的信息是至关重要的。领域专家将告知成功流程的可能性和副作用的风险。将信息理解为旨在最大限度地降低沟通失误的风险,这一点非常重要。当与专家交谈时,许多估计的概率是口头传达的,用诸如“很可能之类的术语,而不是确切的百分比。**

确保发送方和接收方的口头概率短语在概率或百分比方面是相同的。

在某些领域中,有一些指导原则将诸如' common '这样的术语描述在一定的范围内,比如说 1-10%。但是如果没有该领域的背景知识,单词' common '很容易被解释为不同的数字[ 4 ]。此外,概率短语的解释会受到其上下文[ 4 ]的影响。例如,比较您在下面两个语句中的数字解释:

  • 明年六月,曼彻斯特(英格兰)可能会下雨。**
  • 明年六月的 巴塞罗纳 (西班牙)可能会下雨。

很可能,你对第一句话中的“可能”的数值解释高于第二句话。小心上下文曲解,因为它也可能导致系统性错误,从而导致不正确的模型。概率短语的概观图如图 2 所示。

“不可能”似乎并不总是不可能的!

图 2:概率短语的解释。资料来源:Sanne Willems 等人,JCOM [ 4 ]

bnlearn 图书馆。

关于用于本文所有分析的 bnlearn 库的一些话。bnlearn 库旨在应对一些挑战,例如:

  • 结构学习 :给定数据:估计一个捕捉变量间依赖关系的 DAG。
  • 参数学习 :给定数据和 DAG:估计个体变量的(条件)概率分布。
  • 推理 :给定学习过的模型:为你的查询确定准确的概率值。

bnlearn相比其他贝叶斯分析实现有什么好处?**

  • 在 pgmpy 库的基础上构建
  • 包含最想要的贝叶斯管道
  • 简单直观
  • 开源
  • 文档页面

建立一个基于专家知识的喷水灭火系统。

让我们从一个简单直观的例子开始,展示如何基于专家的知识构建真实世界的模型。在这个用例中,我将扮演自动喷水灭火系统领域专家的角色。

假设我的后院有一个自动喷水灭火系统,在过去的 1000 天里,我亲眼目睹了它是如何以及何时工作的。我没有收集任何数据,但我创造了一种关于工作的直觉。姑且称之为专家观点领域知识。注意,洒水系统是贝叶斯网络中一个众所周知的例子。**

从我的专家的角度来看,我知道一些关于这个系统的事实;它有时开有时关(是不是很棒)。我经常看到--如果自动喷水系统在上,那么可能会---湿。然而,我也知道下雨--几乎肯定 -也会导致湿草,并且喷水系统在大多数时间 - 关闭。我知道在开始下雨之前经常出现。最后,我注意到在洒水器多云之间有一个微弱的互动,但我不完全确定。**

从这一点开始,你需要将专家的知识转化为模型。这可以通过首先创建 然后定义连接图中节点的CPT来系统地完成。

喷水灭火系统由四个节点组成,每个节点有两种状态。

在喷水灭火系统中有四个节点,您可以从专家的视图中提取。每个节点有两种工作状态:下雨:是或否,多云:是或否,喷水系统:开或关,湿草:真或假。

定义简单的一对一关系。

复杂的系统是由简单的部分组合而成的。这意味着你 不需要 立刻创建或设计整个系统,而是首先定义较简单的部分。更简单的部分是一对一的关系。在这一步,我们将把专家的观点转换成关系。我们从专家那里得知:取决于多云状态,湿草取决于状态,但是湿草也取决于 s prinkler 状态。最后我们知道洒水多云。我们可以建立以下四种有向的一对一关系。

  • 多云下雨
  • 湿草
  • 洒水器湿草
  • 多云洒水器

重要的是要认识到,一对一部分之间的关系强度存在差异,需要使用 CPT 来定义。但是在进入 CPTs 之前,让我们先使用 bnlearn 制作 DAG。

DAG 基于一对一的关系。

这四个有向关系现在可以用来构建带有节点和边的图。每个节点对应一个变量,每个边代表变量对之间的条件依赖关系。在 bnlearn 中,我们可以赋值并图形化表示变量之间的关系。

pip install bnlearn

根据一对一的关系设计喷水灭火系统的 DAG。

在图 3 中是生成的 DAG。我们称之为因果 DAG* ,因为我们已经假设我们编码的边代表我们对喷水系统的因果假设。*

图 3:喷水灭火系统的 DAG。它编码了以下逻辑:湿草依赖于洒水器和雨水。洒水车依多云,雨依多云(图片作者)。

此时,DAG 拥有 没有 关于底层依赖关系的知识。我们可以用bn.print(DAG) 检查 CPT,这将导致消息“没有 CPD 可以打印”。我们需要用所谓的条件概率表和向 DAG 添加知识,我们将依靠专家的知识来填充条件概率表。**

可以用条件概率表(CPT)将知识添加到 DAG 中。

建立条件概率表。

洒水系统是一个简单的贝叶斯网络,其中湿草(子节点)受到两个父节点(洒水器)的影响(见图 1)。节点洒水下雨受单个节点影响;多云多云节点不受任何其他节点的影响。

我们需要将每个节点与一个概率函数相关联,该函数将该节点的父变量的一组特定值作为输入,并给出(作为输出)该节点所表示的变量的概率。让我们为四个节点做这件事。

CPT:多云

多云节点有两种状态(是或否)并且没有依赖关系。当处理单个随机变量时,计算概率相对简单。从我专家的角度来看,在过去的 1000 天里,我有 70%的时间亲眼目睹了多云的天气(不过我没有抱怨,只是失望)。由于概率加起来应该是 1, 不是 多云的时间应该是 30%。CPT 看起来如下:

定义节点的 CPT:多云。

CPT:下雨

节点有两种状态,受多云制约,多云也有两种状态。总的来说,我们需要指定 4 个条件概率,即在给定一个事件发生的情况下,另一个事件发生的概率。在我们的情况下;假定多云,事件下雨发生的概率。 证据 因此多云变量。从我的专家的角度来看,我可以告诉你,当下雨的时候,80%的时间都是多云。我也确实看到下雨 20%的时间看不到 ( 真的吗?是的。真实故事)。**

定义节点的 CPT:Rain。

CPT:洒水喷头

洒水器节点有两种状态,并受多云两种状态的制约。总的来说,我们需要指定 4 个条件概率。这里我们需要定义喷头出现多云的概率。 证据 因此多云变量。我可以说当洒水器关闭时,90%的时间都是多云。因此,对于洒水器为真和多云为真的对应情况是 10%。其他的概率我不太清楚,所以我会设置为 50%的几率。**

定义节点的 CPT:喷水装置。

CPT:湿草

湿草节点有两种状态,受两个双亲节点制约;下雨洒水。这里我们需要定义湿草的概率,给定洒水车的发生。总之,我们必须指定 8 个条件概率(2 个状态^ 3 个节点)。**

  • 作为一个专家,我可以肯定,比如说 99%,在下雨或者洒水器开了之后看到湿草😛(湿草=1 |雨=1,洒水器=1) = 0.99。因此对应的是 P(湿草=0|雨=1,洒水器= 1)= 1–0.99 = 0.01
  • 作为一个专家,我完全确定当不下雨或者洒水器没有打开的时候,没有湿草😛(湿草=0 |雨=0,洒水器=0) = 1。相应的是:P(湿草=1 |雨=0,洒水器= 0)= 1–1 = 0
  • 作为专家,我知道湿草几乎都发生在下雨洒水器关闭的时候(90%)。p(湿草=1 |雨=1,洒水车=0) = 0.9。对应的就是:P(湿草=0 |雨=1,洒水车= 0)= 1–0.9 = 0.1。
  • 作为专家,我知道湿草几乎总是发生在不下雨并且洒水器开着(90%)的时候。p(湿草=1 |雨=0,洒水车=1) = 0.9。对应的就是:P(湿草=0 |雨=0,洒水车= 1)= 1–0.9 = 0.1。

定义节点的 CPT:湿草地

就是这个!此时,我们定义了 DAG 与 CPT 之间的关系强度。现在我们需要连接 DAG 和 CPT。

使用 CPT 更新 DAG:

所有 CPT 都已创建,现在我们可以将它们与 DAG 连接起来。作为健全性检查,可以使用 print_DAG 功能检查 CPT。

用 CPT 更新喷水灭火系统的 DAG。

带有 CPT 的 DAG 现在将如图 4 所示。

图 4:喷水灭火系统的因果 DAG 与连接的 CPT(图片由作者提供)。

对因果模型进行推论。

干得好!至此,您已经创建了一个描述数据结构的模型,以及定量描述每个节点及其父节点之间的统计关系的 CPT。让我们对我们的模型提几个问题,举一反三!

****How probable is having wet grass given the sprinkler is off?*** *P(Wet_grass=1 | Sprinkler=0) = 0.6162****How probable is a rainy day given sprinkler is off and it is cloudy?***
*P(Rain=1 | Sprinkler=0, Cloudy=1) = 0.8**

对因果喷水灭火系统做出推论。

讨论

贝叶斯网络的一个优点是,对于人类来说,直观上更容易理解直接相关性和局部分布,而不是完全的联合分布。要制作知识驱动的模型,我们需要两种成分;DAG 和条件概率表(CPT)。两者都来源于专家的提问。DAG 描述数据的结构,需要 CPT 来定量描述每个节点与其父节点之间的统计关系。虽然这种方法似乎是合理的,但是您应该意识到通过向专家提问可能会出现系统错误,以及在构建复杂模型时的局限性。

我如何知道我的因果模型是正确的?

在喷头的例子中,我们通过个人经验提取领域专家的知识。虽然我们创建了因果图,但是很难完全验证因果图的有效性和完整性。例如,你可能对概率和图表有不同的观点,你也可能是对的。作为一个例子,我描述道:“我也确实在 20%的时间里没有看到云的情况下看到了雨”。对这样的说法进行争论可能是有道理的。相反,也可能在同时存在多个真知识模型。在这种情况下,你可能需要综合各种可能性,或者决定谁是对的。

所使用的知识和专家的经验一样丰富,和专家的偏见一样丰富多彩。

或者换句话说,我们通过向专家提问提取的概率是 主观概率【5】。在洒水喷头的例子中,接受这个概率的概念是个人的就足够了,它反映了特定的人在特定的时间特定的地点的信仰程度。这样质疑自己;如果专家生活在英国相比于西班牙,喷头型号会有变化吗?**

如果你想使用这样的程序来设计一个知识驱动的模型,理解人们(专家)如何得出概率估计是很重要的。在文献中描述了当对不确定事件进行推理时,人们很少遵循概率原则,而是用有限数量的试探法[ 6 ,7]代替概率法则,例如代表性可用性来自锚的调整。请注意,这可能会导致系统误差和不正确的模型。此外,确保发送方和接收方的口头概率短语在确切的概率或百分比方面是相同的。

复杂性是一个主要的限制。

所提出的喷水灭火系统只有几个节点,但是贝叶斯网络可以包含更多具有多级父子依赖关系的节点。在贝叶斯网络中填充条件概率表(CPT)所需的概率分布的数量随着与该表相关联的父节点的数量呈指数增长。如果要通过从领域专家那里获得的知识来填充表格,那么任务的巨大规模会形成相当大的认知障碍[ 8 ]。

过多的父子依赖会对领域专家形成相当大的认知障碍。

例如,如果 m 父节点表示布尔变量,那么概率函数由一个具有条目的表来表示,每个条目对应一个可能的父组合。不要创建大图(超过 10-15 个节点),因为父子依赖的数量会对领域专家形成相当大的认知障碍。如果您有想要建模的系统的数据,也可以使用结构学习[3] 来学习结构(DAG)和/或其参数(CPTs) 。**

我们能把专家的知识变成模型吗?

我再重复一遍我之前的说法:“嗯,这取决于你用图形表示知识的准确度,以及你用概率定理把它粘在一起的准确度。”

最后的话

这就是了。创建一个知识驱动的模型并不容易。这不仅是关于数据建模,也是关于人类心理。确保你为专家面试做好准备。多次短面试比一次长面试好。系统地问你的问题。首先设计有节点和边的图,然后进入 CPTs。讨论概率时要谨慎。理解专家如何得出他的概率,并在需要时进行标准化。检查时间和地点是否会影响结果。建立模型后进行健全性检查。偶尔微笑。

注意安全。保持冷静。

欢呼,E.

如果你觉得这篇文章很有帮助,可以使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 保持我的最新内容!

软件

  • bnlearn github/documentation

我们连线吧!

  • 让我们在 LinkedIn 上联系
  • 在 Github 上关注我
  • 在 Medium 上跟随我

参考

  1. 维基百科,知识

2.朱迪亚·珀尔(2000 年)。因果关系:模型、推理和推论。剑桥大学出版社。ISBN 978–0–521–77362–1。OCLC 42291253。

3.E.Taskesen,使用 Python 中的贝叶斯结构学习检测因果关系的逐步指南,Medium,2021

4.Sanne Willems 等人,荷兰新闻文章中概率短语解释的可变性——误传的风险,JCOM,2020 年 3 月 24 日

5.R. Jeffrey,主观概率:真实的事物,剑桥大学出版社,剑桥,英国,2004 年。

6.A. Tversky 和 D. Kahneman,不确定性下的判断:启发和偏见,《科学》,1974 年

7.特沃斯基和 d .卡内曼,“不确定性下的判断:试探法和偏见”,载于《不确定性下的判断:试探法和偏见》,d .卡内曼、p .斯洛维奇和 a .特沃斯基编辑。,剑桥大学出版社,剑桥,1982 年,第 3-2 页

8.Balaram Das,生成贝叶斯网络的条件概率:缓解知识获取问题。Arxiv

使用 Python 中的贝叶斯结构学习检测因果关系的分步指南

原文:https://towardsdatascience.com/a-step-by-step-guide-in-detecting-causal-relationships-using-bayesian-structure-learning-in-python-c20c6b31cee5?source=collection_archive---------0-----------------------

实践教程

有效确定变量间因果关系的入门指南。

照片由GR 股票

确定变量之间的因果关系可能是一个具有挑战性的步骤,但它对于战略行动非常重要。我将从 贝叶斯概率 方面总结 因果模型 的概念,后面是一个动手教程,利用贝叶斯结构学习检测因果关系。我将使用喷洒器数据集从概念上解释如何使用 Python 库 bnlearn 学习结构。

如果你觉得这篇文章很有帮助,可以使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 关注我的最新内容!

背景

在疾病预测、推荐系统、自然语言处理等许多领域,机器学习技术的使用已经成为获得有用见解和进行预测的标准工具包。虽然可以实现良好的性能,但提取与目标变量的因果关系并不简单。换句话说:哪些变量对目标变量有直接的因果作用?这些洞察对于确定得出结论的驱动因素非常重要,因此可以采取战略行动。机器学习的一个分支是贝叶斯概率图形模型,也称为贝叶斯网络(BN),可用于确定这些因果因素。

在我们进入因果模型的技术细节之前,让我们重温一些术语。术语“相关性”和“关联性”经常互换使用。但我们都知道,相关或关联并不是因果关系。或者换句话说,观察到的两个变量之间的关系并不一定意味着一个导致另一个。从技术上讲,相关性指的是两个变量之间的线性关系,而关联性指的是两个(或更多)变量之间的任何关系。另一方面,因果关系意味着一个变量(通常称为预测变量或自变量)引起另一个变量(通常称为结果变量或因变量)[1]。在接下来的两节中,我将通过示例简要描述关联关联

相互关系

皮尔逊相关是最常用的相关系数。这是如此普遍,它经常被用作相关的同义词。强度由 r 表示,并在从-1 到 1 的标准化范围内测量样本中线性关系的强度。使用关联时有三种可能的结果:

  • 正相关:两个变量之间的关系,其中两个变量的运动方向相同
  • 负相关:两个变量之间的关系,其中一个变量的增加与另一个变量的减少相关
  • 无相关性:两个变量之间没有关系。

图 1 展示了一个正相关的例子,在图 1中,我们看到了巧克力消费量与每个国家诺贝尔奖获得者人数之间的关系【2】。

图 1:巧克力消费与诺贝尔奖得主之间的相关性

该图显示,巧克力消费可能意味着诺贝尔奖获得者的增加。或者反过来说,诺贝尔奖获得者的增加同样可能导致巧克力消费量的增加。尽管相关性很强,但更有可能的是,社会经济地位或教育系统质量等未被观察到的变量可能会导致巧克力消费量和诺贝尔奖获得者人数的增加。或者换句话说,这种关系是否是因果关系还是个未知数[2]。这并不意味着相关性本身是无用的,它只是有一个不同的目的[3]。相关性本身并不意味着因果关系,因为统计关系并不唯一地约束因果关系。

联想。

当我们谈到关联时,我们的意思是一个变量的某些值往往与另一个变量的某些值同时出现。从统计学的角度来看,有许多关联的测量方法(如卡方检验、Fisher 精确检验、超几何检验等),通常用于一个或两个变量为序数或名义变量的情况。应该注意的是,相关性是一个技术术语,而术语关联不是,因此,在统计学上并不总是有一致的含义。这意味着陈述你正在使用的术语的含义总是一个好习惯。关于关联的更多信息可以在这个博客[4]中找到,并且阅读这个关于如何通过一个重要关联的网络 [5】探索和理解你的数据的博客。

为了举例,我将使用超几何测试来演示两个变量是否与使用 Titanic 数据集的相关联。泰坦尼克号数据集在许多机器学习例子中使用,众所周知,性别状态(女性)是存活率的良好预测器。我来演示一下如何计算幸存女性之间的关联

首先安装bnlearn库,只加载泰坦尼克数据集。

*pip install bnlearn*

问:雌性存活的概率有多大?

存活与雌性之间的超几何检验

无效假设:存活者与女性没有关系。

超几何检验使用超几何分布来衡量离散概率分布的统计显著性。在本例中, N 是总体大小(891), K 是总体中成功状态的数量(342), n 是样本大小/抽签数(314), x 是成功的数量

等式 1:使用超几何检验来检验存活者和雌性之间的关联。

我们可以在α= 0.05 的情况下拒绝零假设,因此,我们可以谈论幸存者和女性之间的统计显著关联。* 重要的是,联想本身并不意味着因果关系。 我们需要区分 边际 关联和 条件 关联。后者是因果推理的关键组成部分。*

因果关系。

因果关系是指一个(独立)变量引起另一个(因变量),由赖兴巴赫(1956)* 表述如下:*

如果两个随机变量 x 和 y 在统计上是相关的(X/Y),那么要么(a) X 导致 y,(b) Y 导致 x,要么(c)存在第三个变量 z 导致 x 和 y。此外,给定 z,即 X⊥Y∣Z.,x 和 y 变得独立

这个定义包含在贝叶斯图形模型中(又称贝叶斯网络、贝叶斯信念网络、贝叶斯网、因果概率网络和影响图)。同一个技术有很多名字。为了确定因果关系,我们可以使用贝叶斯网络(BN)。让我们从图表开始,可视化由赖兴巴赫* (X,Y,Z)描述的三个变量之间的统计相关性(见图 2)。节点对应于变量(X,Y,Z ),有向边(箭头)表示依赖关系或条件分布。*

图 2:Dag 编码条件独立性。(a,b,c)是等价类。(a,b) 级联,(c)、【d】是具有 V 型结构的特殊类。**

可以创建四个图形;*【a,b】Cascade、【c】Common parent 和(d)V-结构、这些图构成了贝叶斯网络的基础。***

但是我们怎么能知道什么导致什么呢?

确定因果关系的方向,从而确定哪个节点影响哪个节点的概念思想是通过保持一个节点不变,然后观察效果。举个例子,让我们看一下图 2 中的 DAG (a ),它描述了 Z 是由 X 引起的,Y 是由 Z 引起的,如果我们现在保持 Z 不变,如果这个模型是真的,Y 应该不会有变化。每一个贝叶斯网络都可以用这四个图来描述,用(见下一节)我们可以把各个部分粘在一起。**

贝叶斯网络是概率论和图论的完美结合。

应该注意,贝叶斯网络是一个有向无环图 (DAG),DAG 是因果的。这意味着中的边是指向的,并且没有(反馈)循环(非循环)。**

概率论

概率论,或更具体的贝叶斯定理或贝叶斯规则,形成了贝叶斯网络的基础。贝叶斯规则用于更新模型信息,在数学上表述为以下等式:**

等式 2:贝叶斯法则。

该方程由四部分组成; 后验概率 是给定 x 时 Z 发生的概率 条件概率 或可能性是假设为真时证据出现的概率。这可以从数据中推导出来。我们的 先验 信念是在观察证据之前假设的概率。这也可以从数据或领域知识中获得。最后, 边际 概率描述了新证据在所有可能假设下需要计算的概率。如果你想阅读更多关于(因式分解)概率分布或贝叶斯网络联合分布的细节,试试这个博客[6]。

贝叶斯结构学习估计 DAG。

通过结构学习,我们希望确定能够最好地捕捉数据集中变量之间的因果依赖关系的图的结构。换句话说:

最符合数据的 DAG 是什么?

寻找最佳 DAG 的一种简单的方法是创建图的所有可能的组合,即,通过制作几十个、几百个、甚至几千个不同的 DAG,直到所有的组合都用尽。然后,可以根据数据的拟合度对每个 DAG 进行评分。最后,返回得分最高的 DAG。在变量 X,Y,Z 的情况下,我们可以做出如图 2 所示的图形以及更多的图形,因为它不仅是 X>Z>Y(图 2a),还可以是 Z>X>Y,等等。变量 X,Y,Z 可以是布尔值(真或假),但也可以有多种状态。Dag 的搜索空间在使分数最大化的变量数量上变成所谓的超指数。这意味着对于大量节点,穷举搜索实际上是不可行的,因此,已经提出了各种贪婪策略来浏览 DAG 空间。使用基于优化的搜索方法,可以浏览更大的 DAG 空间。这种方法需要一个核函数和一个搜索策略。一个常见的评分函数是给定训练数据的结构的后验概率,如 BIC 或 BDeu。**

大型 Dag 的结构学习需要评分函数和搜索策略。

在我们进入示例之前,理解何时使用哪种技术总是好的。有两种广泛的方法来搜索整个 DAG 空间并找到数据的最佳拟合图。

  • 基于分数的结构学习
  • 基于约束的结构学习

注意,局部搜索策略进行了旨在提高结构得分的增量改变。像马尔可夫链蒙特卡罗这样的全局搜索算法可以避免陷入局部极小值,但我不会在这里讨论。

基于分数的结构学习

基于分数的方法有两个主要组成部分:

  1. 在所有可能 Dag 的搜索空间中进行优化的搜索算法;如穷举搜索HillclimbsearchChow-Liu**
  2. 评分函数表示贝叶斯网络与数据的吻合程度。常用的评分函数有贝叶斯狄利克雷得分BDeuK2贝叶斯信息准则* ( BIC ,也叫 MDL)。***

下面描述了四种常见的基于评分的方法,但是关于贝叶斯评分方法的更多细节可以在这里找到[9]。

  • 穷举搜索 顾名思义,对每个可能的 DAG 进行评分,并返回得分最高的 DAG。这种搜索方法只对非常小的网络有吸引力,并且阻止有效的局部优化算法总是找到最佳结构。因此,确定理想的结构通常是不容易的。然而,如果只涉及几个节点(例如:少于 5 个左右),启发式搜索策略通常会产生好的结果。
  • Hillclimbsearch是一种启发式搜索方法,如果使用更多的节点,可以使用这种方法。 HillClimbSearch 执行贪婪的局部搜索,从 DAG“start”(默认:断开的 DAG)开始,通过迭代执行单边操作来最大限度地增加分数。一旦找到局部最大值,搜索就终止。
  • Chow-Liu 算法是一种特定类型的基于树的方法。Chow-Liu 算法找到最大似然树结构,其中每个节点最多有一个父节点。可以通过限制树形结构来限制复杂度。
  • 树增强朴素贝叶斯(TAN) 算法也是一种基于树的方法,可用于对在其各种相互依赖的特征集之间涉及大量不确定性的巨大数据集进行建模[6]。

基于约束的结构学习

  • 卡方检验。 一种不同但相当直接的方法,通过使用假设检验(如 chi2 检验统计量)识别数据集中的独立性来构建 DAG。这种方法依赖于统计测试和条件假设来学习模型中变量之间的独立性。chi2 检验的 P 值是观察到计算出的 chi2 统计值的概率,给定零假设,即 X 和 Y 是独立的,给定 z。这可用于在给定的显著性水*上做出独立的判断。基于约束的方法的一个例子是 PC 算法,该算法从一个完整的全连通图开始,并且如果节点是独立的,则基于测试结果移除边,直到达到停止标准。

bnlearn 图书馆

关于本文中用于所有分析的 bnlearn 库,说几句话。 bnlearn 库旨在应对一些挑战,例如:

  • 结构学习 :给定数据:估计一个捕捉变量间依赖关系的 DAG。
  • 参数学习 :给定数据和 DAG:估计个体变量的(条件)概率分布。
  • 推论 :给定学习过的模型:为你的查询确定准确的概率值。

bnlearn相比其他贝叶斯分析实现有什么好处?**

  • 在 pgmpy 库的基础上构建
  • 包含最想要的贝叶斯管道
  • 简单直观
  • 开源
  • 文档页面

喷头数据集中的结构学习。

让我们用一个简单直观的例子来演示结构学习的工作原理。假设你的后院有一个喷水系统,在过去的 1000 天里,你测量了四个变量,每个变量有两种状态:(是或否)多云(是或否)喷水系统(开或关),以及湿草(对或错)。基于这四个变量和你对现实世界的概念,你可能会有一个图形应该是什么样子的直觉。对吗?对吗?如果没有,你最好读一下这篇文章,因为通过结构学习你会发现!**

bn learn只用几行代码就很容易确定因果关系。**

在下面的例子中,我们将导入 bnlearn 库,加载洒水喷头数据集,并确定哪个 DAG 最适合该数据。请注意,洒水喷头数据集很容易清理,不会丢失值,并且所有值都具有状态 1 或 0。

图 3:喷水灭火系统的最佳 DAG 示例。它编码了以下逻辑:草地潮湿的概率取决于洒水器和雨水。洒水喷头开启的概率取决于多云天气。下雨的可能性取决于多云天气。

就是这样!我们已经学习了如图 3 所示的结构。检测到的 DAG 由通过边连接的四个节点组成,每个边指示一个因果关系。湿草的状态取决于两个节点,下雨洒水下雨的状态受多云的制约,另外洒水器的状态也受多云的制约。这个 DAG 表示(分解的)概率分布,其中 S 是洒水喷头的随机变量, R 表示下雨, G 表示湿草地, C 表示多云。****

通过检查图表,您很快就会看到模型中唯一的独立变量是 C 。其他变量取决于多云、下雨和/或洒水的概率。通常,贝叶斯网络的联合分布是给定其父节点的每个节点的条件概率的乘积:

bnlearn 中对于结构学习的默认设置是 hillclimbsearch 方法和 BIC 评分。值得注意的是,可以指定不同的方法和评分类型。请参见指定搜索和评分类型的示例:

bnlearn 中各种结构学习方法和评分类型的示例。

尽管检测到的洒水喷头数据集的 DAG 很有见地,并显示了数据集中变量的因果相关性,但它不允许您询问所有类型的问题,例如:

  • 洒水装置关闭时,草地潮湿的可能性有多大?
  • **在洒水装置关闭且多云的情况下,下雨的可能性有多大

在洒水喷头数据集中,根据您对世界的了解和逻辑思维,结果可能很明显。但是一旦你有了更大、更复杂的图表,它可能就不再那么明显了。有了所谓的 推论, 我们就可以回答“假设我们做了什么”类型的问题,这些问题通常需要受控实验和明确的干预来回答。**

如何进行推论?

为了做出推论,我们需要两个因素: DAG条件概率表(CPTs) 。此时,我们将数据存储在数据帧( df )中,并且我们很容易计算出描述数据结构的 DAG 。需要 CPT 来定量描述每个节点与其父节点之间的统计关系。CPT 可以使用 参数学习 来计算,所以让我们先跳到参数学习,然后我们再回到做出推论。

参数学习

参数学习的任务是估计条件概率表的值。 bnlearn 库支持离散节点的参数学习:**

  • 最大似然估计 是利用变量状态发生的相对频率进行的自然估计。当估计贝叶斯网络的参数时,缺少数据是一个常见的问题,并且 ML 估计器具有过拟合数据的问题。换句话说,如果观察到的数据对于基础分布不具有代表性(或者太小),那么最大似然估计可能会非常遥远。例如,如果一个变量有 3 个父变量,每个父变量有 10 个状态,那么对于 10 = 1000 个父变量的配置,将分别进行状态计数。这可能使 MLE 对于学习贝叶斯网络参数非常脆弱。减轻 MLE 过拟合的一种方法是贝叶斯参数估计。
  • 贝叶斯估计 从容易存在的先验 CPT 开始,这些 CPT 表达了我们在数据被观察到之前对变量的信念。然后使用来自观测数据的状态计数来更新那些“先验”。人们可以认为先验存在于伪状态计数中,其在归一化之前被添加到实际计数中。一个非常简单的先验是所谓的 K2 先验,它简单地将“1”加到每个单个状态的计数上。更明智的先验选择是 BDeu (贝叶斯狄利克雷等价均匀先验)。****

喷头数据集上的参数学习。

我将继续使用洒水喷头数据集来学习其参数,从而检测到条件概率表(CPT)。为了学习参数,我们需要一个有向无环图(DAG)* 和一个具有完全相同变量的数据集。想法是将数据集与 DAG 连接起来。在前面的例子中,我们很容易计算 DAG(图 3)。您可以在这个示例中使用它,或者,您可以基于您对世界的了解创建自己的 DAG!在示例中,我将演示如何创建您自己的 DAG,它可以基于专家/领域知识。***

使用喷头数据集进行参数学习的示例。

如果您达到了这一点,那么您已经使用最大似然估计(MLE) 基于 DAG 和输入数据集 df 计算出了 CPTs (图 4)。注意,为了清楚起见,图 4 中包括了 CPT。**

图 4:CPT 是使用最大似然估计通过参数学习得出的。**

使用 MLE 计算 CPT 很简单,让我通过手动计算节点多云下雨的 CPT 来举例说明。**

为多云和下雨的节点手动计算最大似然的例子。

请注意,条件依赖可以基于有限的数据点。作为一个例子, P(Rain=1|Cloudy=0) 是基于 91 个观测值。如果 Rain 有两个以上的状态和/或更多的依赖项,这个数字会更低。 是更多数据的解决方案? 也许吧。也许不是。请记住,即使总样本量非常大,每个父配置的状态计数都是有条件的,这一事实也会导致碎片。查看 CPT 与 MLE 方法的区别。

关于洒水喷头数据集的推论。

为了进行推理,它要求贝叶斯网络有两个主要组件:描述数据结构的有向无环图(DAG) 和描述每个节点及其父节点之间的统计关系的条件概率表(CPT)* 。此时,您有了数据集,使用结构学习计算了 DAG,使用参数学习估计了 CPT。你现在可以做推论了!***

通过推理,我们在一个叫做变量消除的过程中边缘化变量。变量消去法是一种精确的推理算法。它还可以用于计算出网络的状态,通过简单地交换最大函数的和,具有最大概率。它的缺点是,对于大型 bn,它可能在计算上很难处理。在这些情况下,可以使用*似推理算法,如吉布斯采样或拒绝采样。

bnlearn 我们可以做出如下推论:

现在我们有了问题的答案:

******How probable is it to have wet grass given the sprinkler is off?*** *P(Wet_grass=1 | Sprinkler=0) = 0.51* ***How probable is it have a rainy day given sprinkler is off and it is cloudy?*** *P(Rain=1 | Sprinkler=0, Cloudy=1) = 0.663****

我如何知道我的因果模型是正确的?

如果你仅仅使用数据来计算因果图,很难完全验证你的因果图的有效性和完整性。然而,一些解决方案有助于在因果图中获得更多信任。例如,有可能根据经验测试变量集之间的某些条件独立性或依赖性关系。如果它们不在数据中,则表明因果模型的正确性[8]。或者,可以添加先前的专家知识,例如 DAG 或 CPTs,以在进行推断时获得对模型的更多信任。

讨论

在本文中,我谈到了一些概念,关于为什么相关性或关联性不是因果关系,以及如何使用结构学习从数据走向因果模型。贝叶斯技术的优势总结如下:

  1. 后验概率分布的结果或图形允许用户对模型预测做出判断,而不是将单个值作为结果。
  2. 在 DAG 中整合领域/专家知识的可能性,以及不完整信息和缺失数据的推理。这是可能的,因为贝叶斯定理是建立在用证据更新先验项的基础上的。
  3. 它有模块化的概念。
  4. 复杂的系统是由简单的部分组合而成的。
  5. 图论直观地提供了高度交互的变量集。
  6. 概率论提供了结合各部分的粘合剂。

贝叶斯网络的另一方面的弱点是寻找最优 DAG 在计算上是昂贵的,因为必须对所有可能的结构进行穷举搜索。穷举搜索的节点限制可能已经是大约 15 个节点,但是也取决于状态的数量。如果您有更多的节点,则需要具有评分功能和搜索算法的替代方法。然而,为了处理具有数百甚至数千个变量的问题,有必要采用不同的方法,例如基于树或基于约束的方法,并使用变量的黑名单/白名单。这种方法首先确定顺序,然后找到该顺序的最佳 BN 结构。这意味着在可能排序的搜索空间上工作,这是方便的,因为它小于网络结构的空间。

确定因果关系可能是一项具有挑战性的任务,但 bnlearn 库旨在应对一些挑战,如 结构学习、参数学习、推理 。但是它也可以导出(整个)图的拓扑排序,或者比较两个图。文档可在此处找到,其中还包含了报警、安第斯、亚洲、探路者、萨克斯车型的示例。****

注意安全。保持冷静。

欢呼,E.

如果您觉得这篇文章很有帮助,请使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 关注我的最新内容!

软件

  • bnlearn 文档
  • Colab 笔记本示例

我们连线吧!

  • 让我们在 LinkedIn 上联系
  • 在 Github 上关注我
  • 在媒体上跟我来

参考

  1. 麦克劳德,S. A,相关定义,例题&释义 。单纯心理学 2018 年 1 月 14 日
  2. F.达布兰德,因果推理导论,心理学方法系,阿姆斯特丹大学,https://psyarxiv.com/b3fkw
  3. 布列塔尼·戴维斯,当相关性优于因果关系,中等,2021
  4. 保罗·金里奇措施协会。第 766–795 页
  5. Taskesen,E,通过一个重要关联网络探索和理解您的数据。2021 年 8 月,中等
  6. 布拉尼斯拉夫·霍兰德,概率图形模型介绍,中型,2020 年
  7. Harini Padmanaban,朴素贝叶斯和 Tes 的朴素分析与树增强朴素增强朴素贝叶斯模型的比较分析,圣何塞州立大学,2014 年
  8. 胡萨尔。曲线拟合之外的 ML:因果推理和微积分简介
  9. E.巴黎水等人,给定超结构寻找最优贝叶斯网络,《机器学习研究杂志》9(2008)2251–2286。

处理复杂研究项目的循序渐进指南

原文:https://towardsdatascience.com/a-step-by-step-guide-to-approach-complex-research-projects-2a819cd30d3?source=collection_archive---------18-----------------------

思想和理论

如何推动数据科学的重点研究

当你看一支冠军运动队时,很容易把球队的成功归功于明星球员。而且,虽然大部分功劳确实属于团队,但有一个关键人物在带领他们前进——教练。尽管教练一分也拿不到,但他必须管理球队并制定策略。本质上,教练创造了获胜的蓝图。

与教练类似,管理研究项目需要一个团队领导,他要对团队成员负责,要有足够的计划,并培养一种适应性思维来执行工作(这种思维经常会改变)。就像教练设计获胜路线图一样,拥有一份如何进行研究的指南可以完全重塑你如何接*你的项目,并最大化你获得成功结果的机会。

为了更好地理解我的意思,让我们从我担任团队领导的几个赛季中撕下一页。

2016 年,我在 OrCam 的 R&D 团队从零开始开发自动语音识别(ASR)引擎。从那时起,我们一直在进行一个(相对)漫长的迭代过程,收集见解并相应地完善我们的研究。

根据我们从自己的错误中吸取的经验,我们开发了一种如何进行研究的方法:

  1. 鼓励我们花时间思考,然后决定什么是最佳解决方案,而不是执行我们脑海中的第一个想法(在大多数情况下,这不是理想的解决方案)。
  2. 促进重点研究。
  3. 最大限度地减少(并实现)高度复杂的研究项目的交付时间。

我们经常被问到:这种方法是否减缓了项目的启动,并导致工作的耗尽和延迟?

这个问题的答案很简单:我们的目标是尽快完成项目,而不是尽快开始执行。通过坚持下面概述的方法,启动项目不会比预期花费更长的时间,如果确实如此,你可以放心,这是有充分理由的。

无限可能的世界

照片由 Sneha Chekuri 在 Unsplash 上拍摄

有时候,开始一个研究项目感觉就像是一个在糖果店的孩子。

有这么多选择摆在你面前,很难选择如何进行。此外,随着您深入项目,每个选项听起来都比上一个更吸引人,选项的数量似乎呈指数增长。但是,在一天结束时,你需要保持专注,交付任何要求你做的事情(例如,一个产品的功能或一篇研究论文)。

整体情况

粗略地说,一个研究项目应该包括四(4)个连续的阶段:

  • 第 0 步:动机 —理解为什么我们要做这个项目
  • 第一步:目标——定义我们想要达到的
  • 第二步:计划 —定义我们将如何实现目标
  • 第三步:执行执行选定的计划

如果我们不承认这些步骤在理论上是正确的,那就是我们的失职。在实践中,我们知道复杂的研究项目往往是周期性的。这意味着在执行过程中,我们可能需要重新审视目标,重新思考我们的计划,并改变我们的执行方式。为了简单地解释这个方法,让我们假设这些步骤按照这个定义的顺序形成。但是,请记住,在实践中,这些步骤可能是迭代的。

这里有一个方法论的介绍,以及一些带有实践例子的理论见解。

第 0 步:动机

你生命中最重要的两天是你出生的那天和你找到原因的那天【马克·吐温】

照片由艾米丽·莫特在 Unsplash 上拍摄

许多人更想知道他们为什么要从事一个项目。通过回答这个问题,我们将不得不理解项目背后的动机,这将我们引向它的背景。

这一步被标记为零(0 ),因为虽然它不是完全必要的,但它是一个额外的好处。理解项目背后的动机可以积极地影响研究和开发的执行方式。

研究是一个动态的领域,事物可能会迅速变化;当事情没有按预期进行时,理解动机会让我们保持专注,并使我们朝着解决问题的方案收敛,而不是分裂。

此外,当其他部门的人要求某个功能或一些帮助时,他们可能没有意识到其中的动态。通过理解他们请求背后的原因,我们可以同意或者建议一个更容易实现的替代解决方案。

第一步:目标

“如果你不知道你要去哪里,每条路都将使你一事无成”【亨利·a·基辛格】

由马库斯·温克勒在 Unsplash 上拍摄

我们希望知道,当我们交付某个东西时,我们解决的是最初提出的问题,而不是另一个问题(或者更糟——根本没有问题)。所以动机说清楚之后,就该非常明确的回答:项目的目标是什么

在这里,定义成功的衡量标准至关重要(即选择基准和评估指标,并将其设计为前进过程中的良好进展指标[ Ruder,2021 ])。)

以下是我们发现在构建基准和选择评估指标时有用的(部分)高级技巧列表:

有效性:基准应该反映你的最终目标。

我们定义了我们的基准,这样当我们达到期望的关键绩效指标(KPI)时,我们就实现了我们的目标。换句话说,达到你的基准意味着你已经成功地完成了你设定的目标。【鲍曼,2021 】。

例如,在自动语音识别(ASR)中,研究人员经常使用 LibriSpeech [ Panayotov,2015 ]作为基准。LibriSeech 来源于有声读物,由音频片段及其相应的抄本组成。如果有人想开发一个用于会议转录的 ASR 引擎,他们应该选择一个不同的基准,因为 LibriSpeech 不能反映他们的最终目标,因为自发的语音与有声读物的结构化阅读相比具有不同的特征。这个例子展示了选择与您的目标一致且相关的基准是多么重要。

可靠性:标签必须正确一致鲍曼,2021 】。

为了信任基准测试结果,标签必须正确。情况可能是,您在内部开发您的基准,甚至将这一阶段外包出去。由于指令可能会以不同的方式进行解释,因此在与他人分享您的想法时,简明准确至关重要。在开始工作之前,请务必检查随机抽样的数据和标签。

当考虑评估指标时,客观性比主观性更受青睐,因为它减少了偏差并支持可重复的评估。

我们更喜欢与人类感知高度相关的指标。虽然这听起来很简单,但在许多领域中,寻找这些指标有时是具有挑战性的,因为很难模仿人类的感知。

此外,考虑是否所有的错误都应该在你的统计数据中具有相同的权重。例如,在评估与语言相关的任务时,记住真正重要的单词很少。填充词最终可能会使您的统计数据产生偏差,因此通过创建特定的基准来解决这些问题是非常重要的。

如果需要进行人工评估,尽最大努力减少偏见。这样做的一个常见解决方案是使用众包,但应该非常注意细节,因为即使是指南本身也可能固有偏见[ Hansen,2021 ]。因此,众包应该从不同的人群中收集,人数应该适当确定。

定义成功:关于基本事实的表现不是衡量成功的唯一标准,基准应该反映这一点[ Aksenova,2021 ]。

达到 100%的准确率并不总是比 95%更好。让我们举一个例子,在 iPhone 上发现像“嘿 Siri”这样的永远在线的关键词。与其让你的 iPhone 总是延迟 30 秒才醒来,不如选择一个准确度较低的短响应时间。

基准应该接*现实,并随着项目的进展而发展

基准应该足够大并具有代表性,以便接*现实[ Kiela,2021 ]。

此外,基准应该随着项目的进展而发展。

我们的工作方式是在项目开始时,根据我们在特定时间点对问题的理解,定义一个基准。当我们工作时,新的挑战出现了。为了确保我们能够解决这些挑战,我们制定了新的具体基准。

第二步:计划

“不做准备,就是在为失败做准备。”【本杰明·富兰克林】

照片由万花筒在 Unsplash 上拍摄

规划答案:我们将如何实现我们的目标?或者解决挑战最好的方法是什么?

这个过程可以抽象地看作是一个广度优先搜索算法,这意味着在每个决策点,我们在继续下一个决策之前检查所有可能的行动。递归地这样做(当然,在时间上有限制)可以清楚地看到项目要遵循的所有可能的路径。

然后,我们可以选择给定约束条件(可能包括产品、发布日期、技术堆栈等)的预期最佳解决方案。).规划阶段是至关重要的,应该在我们放松和思想开放的情况下进行,因为在这里做出的每个错误决定都有可能花费大量的时间和金钱。

规划有两个主要目标,即:

减少不确定性

通过提供不同的解决方案、听取相关团队(如产品和基础设施团队)的建议等,尽可能消除未知因素。

你经常会遇到这样的情况,两个选项看起来都很有希望,但很难在它们之间做出选择。为了消除未知,现有的工具(如开源软件)可以帮助开发一个快速的概念证明,即使它不能解决你的确切问题。例如,如果一个人想要自动检测图像中的狮子,他们找到一个现有的工具来检测狗、马、羊、牛、大象等。除了可用的训练数据之外,他们可以安全地假设可以检测到狮子,因为各组之间不应该有差异。此外,在计划时,记住你的武器库中已有的工具集。在许多情况下,修改现有工具比从头开始开发新工具更快。

为项目设定路线图

列出并详述实现项目目标必须完成的技术步骤,包括时间表。它有助于将复杂的研究项目分解成小步骤。虽然每一步本身不会带领我们到达最终目标,但它使我们能够沿着正确的方向前进,而不是在最后,这往往更具挑战性和耗时。此外,它使得查找和修复 bug 的过程更加简单。

我们将通过比较承包商建造房屋的过程来展示复杂的项目是如何分解成小步骤的。房子,或者说最终目标,是在所有的建筑阶段从地基和框架,基础设施(管道,电力等)都完成后准备好的。),到内饰,不一而足。施工阶段作为小任务;虽然每个阶段本身不会创造一个房子,但每个完成步骤的组合会。此外,如果在执行的某个特定阶段出现问题,可以很容易地找到问题并指派必要的专业人员来解决。当你把一个复杂的研究项目分解成几个部分时,情况也是如此。

包括一个坚实的基线也很重要。我们可以在另一篇文章中讨论基线的重要性以及如何构建基线,但简单总结一下:

  1. 基线通过将结果与先前的工作/幼稚的方法进行比较来评估方法的质量。你认为一个高度复杂的模型达到 95%的准确率的性能是好的吗?如果原始基线达到 97%,答案是否定的。基线有时是给定的,比如一个想要改进的现有组件。但是这里的主要要点是,即使基线不存在,也要努力创建一个,即使它很幼稚,不会成为最终的解决方案。文本摘要的简单基线的例子可以在[ Ferriera,2013 ]中找到。

为了使计划尽可能有效,我们通常会集思广益。我们收集并简要回顾动机和项目目标。然后,我们要求每位参与者独立思考他们喜欢的解决方案。

自然,有些人倾向于进行文献综述,而有些人喜欢独立思考。我们鼓励这种多样性,因为它有助于保持我们中的一些人更加开放,更少偏向于基于我们各自的学科和专业知识的某种解决方案。

在每个人都完成他们的“家庭作业”后,我们再次见面,每个参与者都提出他们的观点,而其他人只是听着。这样,像“谁是房间里最有主见的人?”或者“我的想法听起来很傻,我就不提了”都被最小化[ Kahneman,2011 ]。

在每个人都分享了他们的解决方案后,技术讨论就开始了。批评是受欢迎的,但它应该是具体的和解释清楚的。由于复杂的研究问题往往需要进一步思考,因此可能需要不止一次会议来达成最佳解决方案。

当计划阶段结束时,我们知道(在某种程度上)实现目标需要执行的步骤,以及估计的时间表。

第三步:执行

“做正确的事比把事情做对更重要。”【彼得·德鲁克】

Todd Quackenbush 在 Unsplash 上拍照

首先,让某样东西工作,然后让它更好地工作。

我们更喜欢通过增加难度来解决问题,首先在没有约束的情况下解决挑战,然后才添加约束和执行优化。例如,假设我们想为移动设备开发一个低延迟的应用程序。在这种情况下,我们将从开发一个运行在无限计算能力(服务器)上的离线(非流式)版本开始。当这个问题解决后,我们将添加流媒体和移动设备的限制。

为了能够相信你的结果,你必须尽量减少你的实验方法中的缺陷。Musgrave [ Musgrave,2020 ]表明,在修复了诸如缺乏超参数调整的验证集(导致使用测试集反馈进行训练)等缺陷后,2016 年至 2020 年间的度量学习论文充其量只有边际改善,尽管它们声称在准确性方面有了很大进步。

一旦你已经最小化了缺陷,并且可以相信你的模块是高性能和准确的,那么最好执行一个消融研究来理解为什么会这样。消融可以用来获得对未来项目的直觉,指出应该在哪里应用模块的优化,并确保独立的效果不会合并。

关于消融研究必要性的一个很好的例子,可参见 Tay 等人的文章[ Tay,2021 ]。他们的论文声称,将自然语言处理(NLP)任务中的预训练和架构进步(即变形金刚)联系起来是错误的,这两种进步应该独立考虑。因此,当一个人应用预训练-微调范式并希望提高模型的性能和内存消耗时,他们可以优化对新的架构变化的搜索,这些变化之前由于这种牢不可破的联系而没有测试过。

请记住,事物存在于上下文中,这意味着您将需要在更大的系统中部署您的项目。为了防止尴尬的结果,你应该包括一个【故障安全】机制。

请记住:虽然我们希望最初的计划成功,但最终用户并不关心您如何找到解决方案;他们只关心产品或服务是否如承诺的那样有效。所以,如果你看到一种新的方法/技术胜过你努力工作和不眠之夜的解决方案,不要犹豫,接受它。同样,试着理解为什么事情可能会出错或改变,这样你就可以防止重复同样的错误两次。

如果你决定偏离最初的计划,确保你这样做的决定是数据驱动的。正如吉姆·巴克斯代尔(Jim Barksdale)所说,“如果我们有数据,就让我们看看数据。如果我们只有意见,那就用我的吧。”

最后,使用一个可靠的基础设施来构建一切,这个基础设施可以很容易地修改,并且可以服务于多种用途。在尽可能快地跑和做出能持续很长时间的东西之间有一种持续的紧张关系。

我们试图遵循以下经验法则:我们 70–80%的代码是以这样一种方式编写的,即使项目被丢弃,我们也可以在未来的项目中使用它。这有两个好处:未来项目的执行时间缩短了(因为我们已经准备好了部分构建模块),并且它使我们能够专注于特定于任务的核心问题。

我们以乐高为例。模型共享大部分相同的构建模块,只有大小、颜色和数量不同。拥有一个统一的块集可以通过削减制造成本和其他费用来为公司节省资金。

从 R&D 的角度来看,它大大减少了执行所需的工作量和注意力(因为只需要一小部分特定模型的构建块),这最终减少了新模型的交付时间,并允许创建更多的模型,包括复杂的乐高积木。

结束语

这篇文章旨在介绍一种有助于保持研究重点的循序渐进的方法。该方法论可以回答三个主要问题:为什么什么,以及如何,所有这些都指导的实施。

回想起来,拥有这样一份管理研究指南本可以帮助我和我的团队避免多年来过多的错误(尽管事实上我一直有很好的执行监督和监管)。

在我的职业生涯中,我喜欢重温同事和高管给我的反馈。一个突出的评论是,一旦有事情要做,我就“跑得太快”,没有花足够的时间去计划。这条评论一直伴随着我,并成为我创作和分享这份研究指南的巨大动力。

实际上,一旦我和我的团队开始坚持这种方法,我们已经见证了在我们的研究和项目中,与我们过去进入角色时相比,效率更高,错误更少。

希望本文概述的方法能像教练对待团队一样让你受益——帮助你选择正确的前进道路,指引你踏上研究之旅。如果你对这个循序渐进的研究指南有任何建议或想法,我热烈欢迎你在评论中提出来。

通过做项目完全学习数据科学的分步指南

原文:https://towardsdatascience.com/a-step-by-step-guide-to-completely-learn-data-science-by-doing-projects-d7b6a99381ef?source=collection_archive---------4-----------------------

建立一个文件夹,在学习的过程中做好工作准备

照片由 Unsplash 上的 Prateek Katyal 拍摄

Kaggle 上有超过 500 万注册用户。超过 500 万人注册了至少一门吴恩达的机器学习课程。数据科学就业市场竞争激烈。不管你是通过硕士课程还是自学来学习数据科学。要想脱颖而出,动手能力强、有实际曝光度是绝对必要的。它会给你从真实工作经历中获得的一样多的自信。

如果我告诉,你可以在学习的同时获得真正的数据科学经验呢?是的,掌握数据科学最有效的方法是通过做项目来学习。这给数据科学家的日常工作带来了一些现实挑战。您将最终学习概念、它们的实现以及问题的解决。最重要的是,它有助于在学习数据科学的同时建立一个令人惊叹的投资组合。

为了做好工作准备,一个人需要在下面得到更好实践机会,

  1. 数据收集和清理
  2. 提取洞察力
  3. 机器学习算法
  4. 提高沟通技巧和炫耀

许多人面临的问题是确定有助于学习数据科学的项目。在本文中,我将展示一些有趣的数据集和项目,帮助您了解数据科学的重要方面。这里唯一的先决条件是拥有数据科学编程语言的基础知识。如果你想获得一些编程方面的知识,可以点击查看文章中的“使用 Python/R 学习编码”一节。

1.数据收集和清理

按照课程学习数据科学的一个关键问题是,它不会让你接触到现实世界的问题。在大多数学习环境中,所提供的数据足够干净,可以直接使用。Kaggle 数据集大部分也是干净的,或者至少可以直接使用。实际上,数据科学家会花几天时间从不同来源收集数据。然后将它们组合起来创建一个主数据集。这样的数据在质量和一致性方面会有问题。

因此,为了在数据收集和数据清理中获得更好的实际曝光率。最好的前进方式是收集你自己的数据集。到处都是数据,你只需要找到一个有趣的问题。让我通过分享一些示例项目想法来简化它。此外,参考学习和实施网络抓取。

项目 1 —天气和疫苗接种率对每日新冠肺炎病例的影响

分析所需数据:

  • 天气数据——温度、降雨量、湿度等。
  • 每日疫苗接种率
  • 感染总人数
  • 每日 covid 病例数

键学习:

  • 收集数据的网络搜集
  • 合并收集的不同数据集
  • 清理和格式化数据

项目 2——在 IMDB 上分析电影

这个项目的棘手之处在于,它需要从许多页面中提取数据。要了解如何从 IMDB 中提取所有需要的数据,请查看下面的这篇文章。这个概念可以应用于废弃来自任何公共来源的数据。

https://betterprogramming.pub/how-to-scrape-multiple-pages-of-a-website-using-a-python-web-scraper-4e2c641cff8

将这个数据集与来自社交媒体的数据结合起来,将会产生一些很酷的见解。社交媒体数据可以包括主要人物的追随者和社会影响力。这将有助于使你的工作独特而有趣。在下一节中,我们将看到更多关于从数据中提取洞察力的内容。

重点学习:

  • 处理丢失的数据
  • 数据转换,使它们一致
  • 合并从不同来源收集的数据

2.提取洞察力

上一步中收集的数据可用于进一步深入分析。开始的步骤是首先提出一系列问题或假设。然后在数据中寻找见解,并检查属性之间的关系。在第一个项目中,目标是了解天气和疫苗接种率对每日 covid 病例的影响。第二个项目没有预先定义的方法,它只是取决于从事它的个人的创造力。第二个数据集的重点可能是理解成功/不成功电影的模式、电影中有受欢迎的男演员/女演员的影响、受欢迎的类型、理想的电影长度等。

要了解更多关于提取洞察力的信息,请查看下面的笔记本。它有助于理解探索性数据分析中的常用技术和方法。

https://www.kaggle.com/pmarcelino/comprehensive-data-exploration-with-python https://www.kaggle.com/kashnitsky/topic-1-exploratory-data-analysis-with-pandas

要进行全面的数据分析,需要遵循以下要求:

  • 第一步——制定问题
  • 第二步——寻找模式
  • 第三步——建立叙述

下面让我们来详细了解一下。

提出问题

总是从询问更多关于数据集的问题开始。这里的关键是对问题有最好的理解。许多数据科学项目由于缺乏对实际根本原因的关注而失败。下面的文章讨论了如何使用心智模型来更好地理解问题并取得成功。

</5-mental-models-to-help-boost-your-data-science-career-2a40fd9b7d8f>

寻找模式

使用不同的分析和可视化技术从数据集中提取模式。制定的问题以及来自其他来源的输入应该首先推动分析。然而,保持开放的心态将有助于发现有趣的见解。总是有可能找到与我们期望相反的模式。

注意属性之间的关系以及一个属性如何影响另一个属性。它有助于筛选机器学习模型的属性。此外,重点处理包含大量噪声(包括缺失值)的属性。

构建一个故事

现在是时候挑选有趣的发现,并想出一个故事。叙述更像是一个链接因素,有助于以观众最容易理解的顺序讲述调查结果。许多重要的见解和发现如果没有被包装成一个好的叙述,就会被浪费掉。例如,如果您正在处理一个客户流失问题,那么叙述可以组织如下:

  • 一个月有多少客户流失?
  • 整个行业的流失率如何?
  • 顾客的一般情况是怎样的?
  • 是谁在搅动?根据他们的个人资料类型进行分组?
  • 不同配置文件类型的收入损失是多少?
  • 确定最重要的部分
  • 消除那些因为无法停止的真正原因而被搅动的
  • 其他人流失的 10 大原因
  • 如何解决这个问题?推荐?

当你想出一个好的叙述,它有助于清晰地传达分析。数据科学项目的成功在于它为业务提供的价值。如果业务团队看不到任何可行的见解,那么就被认为是失败的。因此,想出一个好的叙述和进行彻底的分析一样重要。

3.机器学习算法

现在让我们通过使用它们来学习不同的机器学习算法。我已经包含了不同类别的机器学习问题的数据集和样本学习脚本。这些将足以学习最常用算法的一切。这里涉及的不同问题是,

  • 监督学习
  • 无监督学习
  • 自然语言处理
  • 计算机视觉问题
  • 推荐系统

监督学习

当我们有一个带标签的数据集时,我们使用监督学习来解决它们。监督学习的关键类别是回归和分类。我已经为他们每个人提供了两个数据集。

首先,参考下面的 kaggle 笔记本来更好地理解监督学习算法。这些记录良好的脚本将帮助您正确理解解决监督学习问题的步骤和标准。第一个是关于回归问题,第二个是关于分类。

https://www.kaggle.com/faressayah/linear-regression-house-price-prediction https://www.kaggle.com/alexisbcook/titanic-tutorial

边做边学的目标是获得尽可能多的实践机会来提高理解能力。使用上述脚本作为参考,并求解以下数据集。为了做得更好,确保你花足够的时间阅读 kaggle 论坛。论坛是信息的金矿。他们有许多有趣的技术和技巧来更好地解决问题。

为了增加你的学习和最大化你找到工作的机会,请遵循下面的方法,

  • 从分析数据集开始
  • 识别有趣的模式和见解
  • 理解自变量和目标之间的关系
  • 探索特征工程
  • 尝试不同的预测模型
  • 测量准确度
  • 通过尝试不同的功能、算法和参数设置进行优化
  • 将代码上传到您的 Git 存储库
  • 写一篇博客和/或在 Kaggle 上上传你的详细笔记本

回归问题: 这个问题所附带的数据集是房价。它将帮助你了解回归问题和用来解决它们的算法。这个特定的数据集有超过 75 个描述属性的属性。这将帮助您在解决回归问题时掌握特性选择和其他典型问题。

https://www.kaggle.com/c/house-prices-advanced-regression-techniques/data

分类问题: 分类问题就是我们把数据分类成类的问题。下面的例子是一个二元分类问题。这里有一个健康保险公司想预测他们的客户对汽车保险的兴趣。像回归问题一样,总是从分析数据集开始。对数据理解得越好,预测结果就越好。

https://www.kaggle.com/anmolkumar/health-insurance-cross-sell-prediction?select=train.csv

在解决这些问题时,重点是

  • 学习不同的技术来分析数据
  • 了解特征工程技术
  • 试着理解什么样的算法适合什么样的数据
  • 清晰地记录脚本,并在您的 Git 存储库中提供它们
  • 写一篇关于你的学习的博文——相信我,这很有帮助

无监督学习

无监督学习用于处理未标记的数据集。例如,当我们希望使用客户的个人资料信息将他们分成不同的类别时。解决无监督学习问题的方法应该类似于监督学习。总是从数据分析开始。

首先,让我们了解一下使用商场客户细分问题的聚类算法。它是根据提供的信息创建不同的客户群。一旦确定了集群,我们就不会停止。我们可以进一步分析,以了解一个集群内的相似性和集群之间的不同之处。下面是一个示例脚本,清晰地记录了如何处理集群问题。

https://www.kaggle.com/roshansharma/mall-customers-clustering-analysis

现在让我们放大并求解传感器数据。这将有助于了解如何使用物联网设备产生的数据。同时更容易处理和理解人类可读的数据,如客户简档数据。传感器数据通常很棘手,因为它们需要更多的分析来提取洞察力。直接查看数据集时,洞察通常是不可见的。

https://www.kaggle.com/uciml/electric-power-consumption-data-set

这个例子将帮助您更好地理解集群问题。学习时应重点关注以下方面:

  • 理解不同的算法
  • 哪种算法对什么数据效果更好?
  • 数据转换以适应算法的要求
  • 帮助比较聚类的可视化效果

自然语言处理

下一个重点领域是自然语言处理。社交媒体和其他在线*台产生了越来越多的数据。许多公司开始关注这个数据集,因为他们有许多重要的信息。

下面的 tweets 数据集将有助于熟悉文本数据。文本数据的问题与结构化数据的问题非常不同。它需要不同的技术和方法来解决这些问题。在处理以下数据集时,重点关注

  • 数据清理的技术和方法
  • 消除无用的词和其他无用的词
  • 处理数据集中的噪声
  • 用于提取情感的库

如果你是自然语言处理的新手,那么首先参考这里的介绍性脚本。它有助于理解处理和解决 NLP 问题。然后利用所学知识处理下面的数据集。

https://www.kaggle.com/datatattle/covid-19-nlp-text-classification

计算机视觉问题

最*在处理能力方面的进步使得执行图像识别成为可能。计算机视觉应用越来越多地用于,

  • 医疗保健
  • 安全和监控
  • 检查和预测性维护
  • 自动驾驶

要了解卷积神经网络以及它们如何应用于计算机视觉问题,请阅读下面的介绍性脚本。现在,看看下面来自 kaggle 的图像数据集,这对学习计算机视觉应用有帮助。在处理计算机视觉应用程序时,请关注以下内容:

  • 优化图像尺寸而不丢失信息的技术
  • 有助于计算机视觉的工具和框架
  • 图像数据不足时的增强技术
  • 预训练模型可用于更好的预测

以下两个数据集略有不同。第一个是关于识别狗的品种,这是一个典型的图像识别问题。解决这个问题将使您获得关于图像识别问题所涉及的步骤的第一手经验。

https://www.kaggle.com/c/dog-breed-identification/data

下面的数据集是关于对象检测的,这里的目标是正确识别图像中的对象。下面的数据集是一组船只的卫星图像,这里的问题是识别每张图片中出现的所有船只。这需要大量的训练,因为在某些情况下,船只会非常小,或者与背景融为一体。

https://www.kaggle.com/andrewmvd/ship-detection

推荐系统

推荐系统是一种非常有趣的技术,在商业中很流行。这项技术已经帮助许多组织改善了销售和客户体验。根据这份麦肯锡的行业报告,亚马逊大约 35%的销售额来自其推荐系统。此外,75%的人会在网飞上观看推荐给他们的内容。

https://grouplens.org/datasets/movielens/

如果你想了解一个推荐系统的实现,请点击下面的链接。它会让你对推荐系统的工作有一个很好的认识。

https://www.kaggle.com/rounakbanik/movie-recommender-systems

4.提高沟通技巧和炫耀

写一个博客,拥有一个 git 存储库

确保你的学习长期伴随你的一个好方法是写下来。这也有助于为你自己建立信誉。数据科学领域的竞争越来越激烈,因此拥有博客有助于脱颖而出。确保至少有一些你想在简历中展示的项目可以在你的 git 库中找到。

创建一个作品集网站

拥有一个作品集网站可以传达一个关于你技能的强烈信息。作品集网站就像是在线版的简历。包括你所有的工作和成就。如果你有兴趣学习如何使用 GitHub 页面免费创建一个作品集网站,

制作一份真正好的简历

最后一步是创建一份令人印象深刻的简历。如果没有一份好的简历,你到目前为止所获得的知识量没有多大意义。有一些工具和技巧可以写出一份有影响力的简历。这里有一篇文章可以帮助你为自己准备一个。

结束语

这些项目将足以完全学习数据科学家所需的关键技能。本文中作为参考提供的笔记本应该用于更好地理解这些概念。这是非常重要的,你要自己解决这些问题,才能学到最多的东西。你获得的实践经验将有助于增强你的自信,在面试中表现得更好。与通过阅读或观看教程学习相比,通过实践获得的知识将是多倍的。它还会在内存中停留很长时间。

保持联系

  • 如果你喜欢这篇文章,并对类似的文章感兴趣,在 Medium 上关注我。订阅 Medium 获取数千篇类似文章
  • 我在我的 YouTube 频道上教授和谈论各种数据科学主题。在这里订阅我的频道。
  • 在这里注册我的电子邮件列表获取更多数据科学技巧,并与我的工作保持联系

如果你觉得这很有趣,你可能也会喜欢,

Python 中语音识别和音频信号处理的分步指南

原文:https://towardsdatascience.com/a-step-by-step-guide-to-speech-recognition-and-audio-signal-processing-in-python-136e37236c24?source=collection_archive---------1-----------------------

向机器教授人类词汇的科学

凯利·西克玛在 Unsplash 上的照片

言语是人类交流的主要形式,也是理解行为和认知的重要组成部分。人工智能中的语音识别是一种部署在计算机程序上的技术,使它们能够理解所说的话。

声音和图像、视频一样,也是人类通过感觉器官感知的模拟信号。

对于机器来说,要消耗这些信息,需要将其存储为数字信号,并通过软件进行分析。从模拟到数字的转换包括以下两个过程:

  1. 采样:是用来将时变(随时间变化)信号 s(t)转换为实数 x(n)的离散级数的过程。采样周期(Ts)是一个术语,定义两个连续离散样本之间的间隔。采样频率(fs = 1/Ts)是采样周期的倒数。常见的采样频率为 8 kHz、16 kHz 和 44.1 kHz。1 Hz 的采样速率意味着每秒一个样本,因此高采样速率意味着更好的信号质量。
  2. 量化:这是将采样产生的每一个实数用一个*似值代替以获得有限精度(定义在一个比特范围内)的过程。在大多数情况下,每个样本 16 比特用于表示单个量化样本。因此,原始音频样本通常具有-215 到 215 的信号范围,尽管在分析期间,为了更简单的验证和模型训练,这些值被标准化到范围(-1,1)。样本分辨率总是以每个样本的位数来衡量。

通用语音识别系统旨在执行下述任务,并可轻松与标准数据分析架构相关联:

  1. 捕获人类给出的语音(单词、句子、短语)。你可以将此视为任何通用机器学习工作流程的数据采集部分。
  2. 转换音频,使其机器就绪。这个过程是数据预处理部分,在这里我们清除数据的特征,以便机器对其进行处理。
  3. 对获取的数据应用自然语言处理(NLP)来理解语音内容。
  4. 合成已识别的单词,以帮助机器说出类似的方言。

语音(音频)信号的处理|作者提供的图像

让我们用相应的伪代码逐一详细地介绍所有这些步骤和过程。此外,在我们开始之前,下面是一个完整代码库的链接,可以方便地与本教程一起阅读。

https://github.com/rjrahul24/ai-with-python-series/tree/main/10. AI in Speech Recognition

步骤 1:读取音频信号文件

Python 中的文件 I/O(SciPy . io):SciPy 有很多在 Python 中执行文件操作的方法。包含方法 read(文件名[,mmap])write(文件名,速率,数据)的 I/O 模块用于读取. wav 文件并以. wav 文件的形式写入 NumPy 数组。我们将使用这些方法读取和写入声音(音频)文件格式。

启动语音识别算法的第一步是创建一个可以读取包含音频文件的系统。wav、. mp3 等。)并理解这些文件中的信息。Python 有一些库,我们可以用它们来读取这些文件,并对它们进行分析。该步骤的目的是将音频信号可视化为结构化的数据点。

  • 记录:记录是我们给算法作为输入的文件。然后,该算法对该输入进行处理,以分析其内容并建立语音识别模型。这可能是一个保存的文件或一个现场录音,Python 允许两者。
  • 采样:记录的所有信号都以数字化方式存储。这些数字签名对软件来说很难处理,因为机器只能理解数字输入。 采样 是用于将这些数字信号转换成离散数字形式的技术。采样以一定的频率进行,并产生数字信号。频率水*的选择取决于人类对声音的感知。例如,选择高频率意味着人类对该音频信号的感知是连续的。
# Using IO module to read Audio Files
from scipy.io import wavfile
freq_sample, sig_audio = wavfile.read("/content/Welcome.wav")# Output the parameters: Signal Data Type, Sampling Frequency and Duration
print('\nShape of Signal:', sig_audio.shape)
print('Signal Datatype:', sig_audio.dtype)
print('Signal duration:', round(sig_audio.shape[0] / float(freq_sample), 2), 'seconds')
***>>> Shape of Signal: (645632,) 
>>> Signal Datatype: int16 
>>> Signal duration: 40.35 seconds***# Normalize the Signal Value and Plot it on a graph
pow_audio_signal = sig_audio / np.power(2, 15)
pow_audio_signal = pow_audio_signal [:100]
time_axis = 1000 * np.arange(0, len(pow_audio_signal), 1) / float(freq_sample)plt.plot(time_axis, pow_audio_signal, color='blue')

作者图片

这是输入文件的声音振幅相对于播放持续时间的表示。我们已经成功地从音频中提取了数字数据。wav)文件。

步骤 2:转换音频

我们在第一部分中所做的音频信号表示代表一个时域音频信号。显示声波相对于时间的强度(响度或振幅)。振幅= 0 的部分表示静音。

就声音工程学而言,振幅= 0 是指当环境中没有其他声音时,静止或运动的空气粒子发出的声音。

频域表示:为了更好的理解一个音频信号,有必要通过频域来看。音频信号的这种表示将为我们提供信号中不同频率存在的细节。傅立叶变换是一种数学概念,可用于将连续信号从其原始时域状态转换到频域状态。我们将使用 Python 中的傅立叶变换(FT)将音频信号转换为以频率为中心的表示。

Python 中的傅立叶变换:傅立叶变换是一个数学概念,可以分解这个信号,带出各个频率。这对于理解所有组合在一起形成我们听到的声音的频率是至关重要的。傅立叶变换(FT)给出了信号中存在的所有频率,还显示了每个频率的幅度。

所有音频信号都是由许多单频声波的集合组成,这些声波一起传播,并在运动介质(例如房间)中产生干扰。捕捉声音本质上是捕捉这些波在空间中产生的振幅。

NumPy (np.fft.fft): 这个 NumPy 函数允许我们计算一维离散傅立叶变换。该函数使用快速傅立叶变换(FFT)算法将给定序列转换为离散傅立叶变换(DFT)。在我们正在处理的文件中,我们有一个从音频文件中提取的幅度序列,它最初是从连续信号中采样的。我们将使用该函数将该时域信号转换为离散的频域信号。

音频信号从时域到频域的转换|图片由作者提供

现在让我们浏览一些代码来实现对音频信号的傅立叶变换,目的是用声音的强度(分贝(dB))来表示声音

# Working on the same input file
# Extracting the length and the half-length of the signal to input to the foruier transform
sig_length = len(sig_audio)
half_length = np.ceil((sig_length + 1) / 2.0).astype(np.int)# We will now be using the Fourier Transform to form the frequency domain of the signal
signal_freq = np.fft.fft(sig_audio)# Normalize the frequency domain and square it
signal_freq = abs(signal_freq[0:half_length]) / sig_length
signal_freq **= 2
transform_len = len(signal_freq)# The Fourier transformed signal now needs to be adjusted for both even and odd cases
if sig_length % 2:
  signal_freq[1:transform_len] *= 2
else:
  signal_freq[1:transform_len-1] *= 2# Extract the signal's strength in decibels (dB)
exp_signal = 10 * np.log10(signal_freq)
x_axis = np.arange(0, half_length, 1) * (freq_sample / sig_length) / 1000.0plt.plot(x_axis, exp_signal, color='green', linewidth=1)

作者图片

这样,我们就能够对音频输入文件进行傅立叶变换,并随后看到音频的频域(频率对信号强度)表示。

步骤 3:从语音中提取特征

一旦语音从时域信号转换为频域信号,下一步就是将频域数据转换为可用的特征向量。在开始之前,我们必须了解一个叫做 MFCC 的新概念。

梅尔频率倒谱系数

MFCC 是一种旨在从音频信号中提取特征的技术。它使用 MEL 标度来划分音频信号的频带,然后从每个单独的频带中提取系数,从而在频率之间创建分离。MFCC 使用离散余弦变换(DCT)来执行这个操作。MEL 标度建立在人类对声音的感知上,即人脑如何处理音频信号并区分不同的频率。下面让我们来看看梅尔标度的形成。

  • 人声声音感知:成年人的基本听力范围为 85 Hz 至 255 Hz,并且这可以进一步区分性别(男性为 85Hz 至 180 Hz,女性为 165 Hz 至 255 Hz)。在这些基频之上,还有人耳处理的谐波。谐波是基频的倍数。这些是简单的乘法器,例如,100 Hz 频率的二次谐波将是 200 Hz,三次谐波将是 300 Hz,等等。

人类的粗略听觉范围是 20Hz 到 20KHz,这种声音感知也是非线性的。与高频声音相比,我们可以更好地分辨低频声音。例如,我们可以清楚地说出 100 赫兹和 200 赫兹信号之间的区别,但不能区分 15000 赫兹和 15100 赫兹。为了产生不同频率的音调,我们可以使用上面的程序或者使用这个工具。

  • 梅尔标度: Stevens、Volkmann 和 Newmann 在 1937 年提出了一种向世界介绍梅尔标度的方法。它是一种音高音阶(具有不同音高水*的音频信号的音阶),由人类根据它们的距离相等来判断。它基本上是一个源自人类感知的尺度。例如,如果你接触到两个相距很远的声源,大脑会感知到这两个声源之间的距离,而不会实际看到它们。这个标度是基于我们人类如何用听觉测量音频信号距离。因为我们的感知是非线性的,这个尺度上的距离随着频率而增加。
  • 梅尔间隔滤波器组:为了计算每个频带的功率(强度),第一步是区分可用的不同特征频带(由 MFCC 完成)。一旦进行了这些分离,我们就使用滤波器组在频率中创建分区并将它们分开。可以使用分区的任何指定频率来创建滤波器组。随着频率的增加,滤波器组中滤波器之间的间距呈指数增长。在代码部分,我们将了解如何分离频带。

MFCC 和滤波器组的数学

MFCC 和滤波器组的创建都是由音频信号的性质所激发,并受到人类感知声音的方式的影响。但是这种处理也需要大量的数学计算,这些计算在其实现过程中是幕后进行的。Python 直接为我们提供了构建滤波器和对声音执行 MFCC 功能的方法,但让我们看一下这些函数背后的数学原理。

进入该处理的三个离散数学模型是离散余弦变换(DCT) ,用于滤波器组系数的去相关,也称为声音白化,以及高斯混合模型——隐马尔可夫模型(GMMs-HMMs) ,它是自动语音识别(ASR)算法的标准

虽然,在今天,当计算成本下降时(由于云计算),深度学习语音系统对噪声不太敏感,被用于这些技术之上。

DCT 是一种线性变换算法,因此它会排除许多有用的信号,因为声音是高度非线性的。

# Installing and importing necessary libraries
pip install python_speech_features
from python_speech_features import mfcc, logfbank
sampling_freq, sig_audio = wavfile.read("Welcome.wav")*# We will now be taking the first 15000 samples from the signal for analysis* sig_audio = sig_audio[:15000]*# Using MFCC to extract features from the signal* mfcc_feat = mfcc(sig_audio, sampling_freq)
print('\nMFCC Parameters\nWindow Count =', mfcc_feat.shape[0])
print('Individual Feature Length =', mfcc_feat.shape[1])
***>>> MFCC Parameters Window Count = 93 
>>> Individual Feature Length = 13***mfcc_feat = mfcc_feat.T
plt.matshow(mfcc_feat)

每段下面的第一条水*黄线是基频,处于最强状态。黄线上方是谐波,它们之间的频率距离相同。|作者图片

*# Generating filter bank features* fb_feat = logfbank(sig_audio, sampling_freq)
print('\nFilter bank\nWindow Count =', fb_feat.shape[0])
print('Individual Feature Length =', fb_feat.shape[1])
***>>> Filter bank Window Count = 93
>>> Individual Feature Length = 26***fb_feat = fb_feat.T
plt.matshow(fb_feat)

作者图片

如果我们看到这两个分布,很明显,低频和高频声音分布在第二个图像中是分开的。

MFCC 连同滤波器组的应用是分离高频和低频信号的好算法。这加快了分析过程,因为我们可以将声音信号分成两个或多个独立的片段,并根据它们的频率单独进行分析。

第四步:识别口语单词

语音识别是理解人类声音并在机器中将其转录为文本的过程。有几个库可用于处理语音到文本,即 Bing 语音、Google 语音、Houndify、IBM 语音到文本等。我们将使用谷歌语音库将语音转换成文本。

谷歌语音 API

关于谷歌语音 API 的更多信息可以从谷歌云页面和语音识别 PyPi 页面中阅读。Google Speech API 能够实现的几个关键特性是语音的自适应。这意味着 API 理解语音的领域。例如,货币、地址、年份都被规定到语音到文本的转换中。在算法中定义了特定于域的类别,这些类别识别输入语音中的这些出现。在当前的工作环境中,API 既可以处理现场预录制的文件,也可以处理麦克风上的现场录音。在下一节中,我们将通过麦克风输入来分析现场语音。

Google Speech API 的架构流程|作者图片

  1. 使用麦克风:py audio 开源包允许我们通过连接的麦克风直接录制音频,并使用 Python 进行实时分析。PyAudio 的安装会因操作系统而异(安装说明在下面的代码部分提到)。
  2. 麦克风类:的实例。microphone()类可以与语音识别器一起使用,直接在工作目录中记录音频。要检查麦克风在系统中是否可用,请使用 list_microphone_names 静态方法。要使用任何列出的可用麦克风,请使用 device_index 方法(实现如下面的代码所示)
  3. 捕获麦克风输入:listen()函数用于捕获麦克风的输入。所选麦克风接收的所有声音信号都存储在调用 listen()函数的变量中。这种方法持续记录,直到检测到无声(0 振幅)信号。
  4. 降低环境噪音:任何功能环境都容易产生环境噪音,从而妨碍录音。因此,Recognizer 类中的 adjust_for_ambient_noise()方法有助于自动消除录音中的环境噪音。
  5. 声音识别:下面的语音识别工作流程解释了信号处理后的部分,其中 API 执行诸如语义和语法纠正的任务,理解声音域、口语,并最终通过将语音转换为文本来创建输出。下面我们还将看到使用 Microphone 类实现 Google 的语音识别 API。
# Install the SpeechRecognition and pipwin classes to work with the Recognizer() class
pip install SpeechRecognition
pip install pipwin# Below are a few links that can give details about the PyAudio class we will be using to read direct microphone input into the Jupyter Notebook
# [https://anaconda.org/anaconda/pyaudio](https://anaconda.org/anaconda/pyaudio)
# [https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio](https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio)
# To install PyAudio, Run in the Anaconda Terminal CMD: conda install -c anaconda pyaudio
# Pre-requisite for running PyAudio installation - Microsoft Visual C++ 14.0 or greater will be required. Get it with "Microsoft C++ Build Tools" : [https://visualstudio.microsoft.com/visual-cpp-build-tools/](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
# To run PyAudio on Colab, please install PyAudio.whl in your local system and give that path to colab for installationpip install pyaudio
import speech_recognition as speech_recog# Creating a recording object to store input
rec = speech_recog.Recognizer()# Importing the microphone class to check availabiity of microphones
mic_test = speech_recog.Microphone()# List the available microphones
speech_recog.Microphone.list_microphone_names()# We will now directly use the microphone module to capture voice input. Specifying the second microphone to be used for a duration of 3 seconds. The algorithm will also adjust given input and clear it of any ambient noisewith speech_recog.Microphone(device_index=1) as source: 
    rec.adjust_for_ambient_noise(source, duration=3)
    print("Reach the Microphone and say something!")
    audio = rec.listen(source)***>>> Reach the Microphone and say something!***# Use the recognize function to transcribe spoken words to text
try:
    print("I think you said: \n" + rec.recognize_google(audio))
except Exception as e:
    print(e)
***>>> I think you said: 
>>> hi hello hello hello***

我们的语音识别和声音分析文章到此结束。我仍然建议您浏览参考资料部分提到的链接和故事顶部链接的代码库,以便能够在每一步都遵循它。

这是一个总结!

结论

语音识别是一个人工智能概念,允许机器听人的声音,并从中转录文本。尽管本质上很复杂,但围绕语音识别的用例是很多的。从帮助不同能力的用户访问计算到自动应答机器,自动语音识别(ASR)算法目前正在被许多行业使用。本章简要介绍了声音分析工程,并展示了一些处理音频的基本技巧。虽然不详细,但它将有助于创建一个语音分析在人工智能世界中如何工作的整体画面。

수안 최 在 Unsplash 上拍照

关于我

我是 Rahul,目前在研究人工智能,在 Xbox 游戏上实现大数据分析。我在微软工作。除了专业工作之外,我还试图制定一个程序,来理解如何通过使用人工智能来改善世界上发展中国家的经济状况。

我现在在纽约的哥伦比亚大学,你可以通过 LinkedIn 和 Twitter 与我联系。

[参考文献]

  1. https://www.ibm.com/cloud/learn/speech-recognition
  2. https://www . science direct . com/topics/engineering/speech-recognition
  3. https://signalprocessingsociety . org/publications-resources/blog/what-are-benefits-speech-recognition-technology
  4. https://www . analyticsvidhya . com/blog/2021/01/自动语音识别和自然语言处理简介/
  5. https://cloud.google.com/speech-to-text
  6. https://www . analyticsvidhya . com/blog/2021/06/MFCC-technique-for-speech-recognition/
  7. 【https://www.google.com/intl/en/chrome/demos/speech.html
  8. https://OCW . MIT . edu/courses/electrical-engineering-and-computer-science/6-345-automatic-speech-recognition-spring-2003/lecture-notes/lecture 5 . pdf
  9. https://towards data science . com/understanding-audio-data-Fourier-transform-FFT-spectrogram-and-speech-recognition-a 4072d 228520
  10. https://haythamfayek . com/2016/04/21/speech-processing-for-machine-learning . html

主成分分析的逐步实现

原文:https://towardsdatascience.com/a-step-by-step-implementation-of-principal-component-analysis-5520cc6cd598?source=collection_archive---------2-----------------------

一个分步教程,解释 PCA 的工作原理,并从头开始用 python 实现它

作者图片

介绍

主成分分析(PCA)是一种常用的降维方法。它的工作原理是计算主成分并执行基变换。它保留最大方差方向的数据。减少的特征彼此不相关。这些特征可用于无监督聚类和分类。为了降低维数,自动编码器是另一种常用的方法。但是,自动编码器的潜在空间不一定是不相关的。而 PCA 保证所有特征彼此不相关。

首先,PCA 计算协方差矩阵。然后我们找到协方差矩阵的特征向量和特征值。之后,我们沿着特征向量投影数据。如果原始数据的维数为 n ,我们可以将维数减少到 k,使得 k≤ n.

在本教程中,我们将从头开始实现 PCA,并理解每一步的意义。

履行

首先,导入库。

步骤 1:创建随机数据

通过从多元正态分布中随机抽取样本来创建数据。我们将从二维数据开始。

意思是,mu 是:[10,13]。

协方差矩阵,sigma 为:[[3.5 -1.8],[-1.8,3.5]]。

这是数据的散点图:

原始数据散点图

步骤 2:均值居中/归一化数据

在 PCA 之前,我们将数据标准化/规范化。

通常,进行归一化是为了使所有要素的比例相同。例如,对于房价预测数据集,我们有不同的功能。价格以美元为单位,而面积以*方为单位。制成现在,该算法将认为数值越高越重要。因此,我们需要在同一范围内对所有特征进行归一化。

进行均值居中以确保第一主分量在最大方差的方向上。

我们将通过从所有特征或通道中减去*均值来进行均值居中。

原始数据(左)和*均值居中数据(右)的散点图

步骤 3:计算协方差矩阵

现在,我们计算所有特征维度的协方差。每个协方差矩阵都是对称的和半正定的。它有正交的特征向量。

协方差矩阵的大小将是(2×2)。

步骤 4:计算协方差矩阵的特征向量

现在,我们执行协方差矩阵的特征分解,我们将得到特征向量和特征值。(特征值/向量的数量将与特征/通道的数量相同。)

每个特征向量代表一个方差方向。对应于最大特征值的特征向量将给出最大方差的方向。这是第一个主成分。然后,对应于第二大特征值的特征向量将给出第二大方差的方向。这是第二个主成分。诸如此类。

因此,我们需要根据特征值的降序对特征向量进行排序。记住,所有的特征向量都是相互正交的。

步骤 5:计算解释的方差并选择 N 个分量

我们可以基于我们想要的压缩程度来选择顶部的 k 特征向量。

选择组件数量的最佳方法是计算每个特征的解释方差。我们通过将特征值除以所有特征值的总和来计算解释方差。然后,我们取所有特征值的累积和。

这里的特征值是:[5.50,1.72]。

特征值之和为:7.22

解释方差为:[0.76,0.23]

累计解释方差为:[0.76,0.99]

因此,当我们有更高维度的数据时,我们通常以这样一种方式获取 k 分量,从而得到 0.95 或更大的解释方差。

在本文中,我们将选择这两个组件来解释 PCA 的工作原理。

步骤 6:使用特征向量转换数据

现在,我们将我们的数据与特征向量进行点积,以获得我们的数据在这些特征向量方向上的投影。

这是转换数据的散点图:

原始数据的散点图(左),*均中心数据(中),PCA 后的转换数据(右)

在散点图中,我们可以看到 PCA 后,y 轴是方差最大的方向。例如,如果我们将 10 维数据简化为 2 维数据,我们将得到沿两个垂直方向的具有最大方差的投影。

步骤 7:反转 PCA 并重建原始数据

我们还可以通过取特征向量的转置与变换数据的点积来重构原始数据。请记住,我们在开始时从数据中减去*均值,以使数据居中。所以,现在我们需要加上*均值。

所有的特征向量都是相互正交的。所以,当我们取特征向量的点积时,我们得到一个单位矩阵。

X = X —*均值

pca_X = X * V

recon _ X =(PCA _ X * V ')+mean =((X * V)* V ')+mean =(X *(V * V ')+mean =(X * I)+mean = X+mean

PCA _ X:PCA 后的变换数据

recon_X:重建数据

V:特征向量矩阵

*均值:每个维度/通道的*均值

所以,我们可以从 k 个分量重建 X。

如果原始数据的形状为:num_samp x N.

那么,协方差矩阵的形状将是:N×N。特征向量的形状也将是 N×N。

如果我们选择顶部 d 个特征向量,我们得到形状的特征向量:N×k。

现在,我们将原始数据与前 d 个特征向量进行点积。因此,在使用 PCA 转换数据后,我们将得到如下形状:num_samp x k.

当我们将重构数据时,我们用顶部 d 个特征向量的转置来取 pca 数据的点积。因此,我们将有形状:

(num _ samp x k)(N x k)' =(num _ samp x N)。*

这是重建数据的散点图:

原始数据的散点图(左),*均中心数据(中),反转 PCA 后的重建数据(右)

您还可以计算重建损失:

在这种情况下,重建损失为:2.6426840324903897e-32。

它非常低,因为我们使用了所有组件来重建数据。

完整的代码库可从以下网址获得:

https://github.com/AdityaDutt/PCATutorial/blob/main/PCA_tutorial.ipynb

在本教程中,我们没有降低维度。但是我们可以取前 N 个特征向量并计算其与原始数据的点积来获得 PCA 特征。其他都一样。

您可以签出这个库中的代码来减少特性。

外卖食品

  1. PCA 是一种正交线性变换。
  2. PCA 给出不相关的特征。(自动编码器将给出相关的特征,它们也可以模拟非线性数据)
  3. 协方差矩阵是对称且半正定的。
  4. 协方差矩阵的特征向量彼此正交。
  5. PCA 可以被反转以重建数据。
  6. 我们还可以使用 PCA 来检测异常值。当我们将使用 k 个分量重建数据时,k≤n,其中 n 是原始维度,异常值将给出更高的重建损失。我们可以计算离群值和非离群值的重建损失直方图。然后选择一个阈值来丢弃异常值。
  7. PCA 特征也可以用于聚类和分类。我们可以将这些简化的特征输入神经网络。

我希望这篇文章对你有用。

如果您有关于 PCA 和使用 PCA 进行异常值检测的其他问题,并且需要帮助,请告诉我。我将在以后的文章中尝试介绍它们。

非常感谢您的阅读!🙂

在创建基于人工智能的手语翻译系统方面又进了一步

原文:https://towardsdatascience.com/a-step-further-in-the-creation-of-a-sign-language-translation-system-based-on-artificial-9805c2ae0562?source=collection_archive---------31-----------------------

大规模实现可访问性的策略

乔·希尔顿在 Unsplash 拍摄的照片

通信是我们社会的基础,人们每天用它来表达自己,并获得最基本的服务,如公共交通、学校和医疗保健。所有国家的重度听力损失者都使用手语,全世界有数百万人患有这种疾病。问题是,大多数听力正常的人不知道如何通过手势说话,这就造成了一种障碍,使聋人很难进行社会互动。

为了转移这个障碍,我们可以使用人工智能技术,如卷积神经网络,来创建一个符号翻译系统,并为执行的符号生成图例。

另一个有趣的点是,虽然每个国家都有自己的手语,但深度学习架构可以很好地概括相同领域的问题,只需一些训练和超参数优化。

然而,对于世界上所有的手语来说,这个过程中有一个部分是昂贵、耗时和重复的:数据集创建

想象一下,有人用美国手语(ASL)创建了一个最先进的架构来识别标志并以非常高的准确度生成传说。为了在实践中实现这种解决方案,并使其在现实世界中具有可访问性,每个不使用美国手语的国家的科学家都需要创建一个巨大的数据集(例如,使用日常使用的最常用的单词)来重新训练网络。因此,很明显,主要瓶颈之一是数据集创建!

在此基础上,我将探索如何更有效地为手语创建数据集以训练高精度模型的一些发现,作为未来工作的指南。

本文基于我的一篇名为: 基于深度学习和图像处理的高效手语识别系统和数据集创建方法 的论文。

实验数据集

这项工作的主要想法是基于廉价数据集创建一个手语识别系统,帮助未来需要这样做的工作。

但是什么是廉价数据集呢?

在我看来,这是一个数据集,它使用一个简单的传感器,如 RGB 相机,几个解释器,以及记录中相同的背景。

这就是为什么我们创建了一个数据集,记录来自两个不同智能手机的视频,在相同的标准背景下,有两个解释器,配置一个简单而容易的设置。

另一个疑问是捕捉记录或二次采样图像的每秒帧数(FPS ),一旦它可以在最终性能中产生不同的结果,因此我们使用相同的程序创建了两个数据集,其中第一个以 60 FPS 记录,第二个以 30 FPS 记录。

此外,我们还对第一个数据集进行了 30 和 20 FPS 的二次采样,对第二个数据集进行了 20 FPS 的二次采样,以测试我们是否可以在记录完成后减少图像数量,而不会影响结果。

最后,我们记录了聋人每天使用的 14 个手势,每个手势重复三次,每次重复之间有一些变化。数据集可以在 Kaggle 上找到。

我们数据集中考虑的单词列表。

为了证明模型的效率,我们创建了一个最终的验证数据集,考虑了相同的 14 个标志,但在不同的背景和光照条件下进行记录,试图再现真实世界的场景。

使用相同的背景和光照条件训练和测试图像。(图片由作者提供)

验证设置,使用不同的背景和光线条件。(图片由作者提供)。

假设和实验

这些是这项工作的主要假设,基于研究过程中出现的问题以及我们为回答这些问题所做的实验。

一旦减少运动模糊,60 FPS 可能比 30 FPS 更好。

必须有运动才能产生标志,而运动会在视频记录中产生模糊。在这种情况下,使用更大的 FPS 应该减少模糊,并且这可以提高模型精度。

实验:我们将比较以 30 和 60 FPS 记录的数据集的准确性

人工背景创建可以提高模型的泛化能力

在同一个静态背景下记录所有标志这比通过编程改变场景、移动设备和人员要容易得多。但我们认为,这可能会导致偏差,从而影响验证数据集上的模型准确性。

实验:我们将使用语义分割来创建新的数据集背景,并用清晰的场景来训练模型。

对于数据扩充,几何变换比强度变换更好

如果我们分析人类如何理解一个标志,很容易注意到几何特征(如手的位置和形状)是识别的基础。另一方面,背景、肤色、衣服、头发和其他配饰与我们无关。这就是为什么我们认为几何变换(旋转、缩放、剪切)将优于强度变换(亮度、通道反转)。

我们的转换用于增加数据和应用范围。(图片由作者提供)

实验:我们将分别测试不同的数据增强技术。

模型创建

CNN 模型是基于 EfficientNet-B0 的,因为它减少了参数数量并具有良好的准确性。在特征提取器之后,我们创建了一个神经网络来预测符号。每个测试在相同的设置中重复 3 次,获取*均结果并使用方差分析(ANOVA)或 T-student 测试进行统计比较。数据被随机分成 80%的样本用于训练,20%的样本用于测试。你可以在 Google Colab 中查看细节和实现。

结果

数据扩充

下表显示了单独测试的每种数据扩充技术的*均精度。

考虑到 20 FPS 数据集,三次执行的*均准确度。(图片由作者提供)

由于数据扩充的主要目标是提高模型不变性,我们将注意力集中在验证集的结果上,很明显,几何变换在提高符号识别方面表现得相当好。

除此之外,我们注意到数据扩充成功地减少了过度拟合,如下图所示。

20 FPS 中数据增强前后的精度,显示它如何减轻训练(橙色)和测试(蓝色)差异。(图片由作者提供)

由于引入了图像不变性,一般准确性随着数据增加而降低,但结果在验证集中显著提高。此外,我们的几何变换假设得到了证实,如下表所示,达到了比强度变换更高的精度。

人工背景创建

下图显示了基于 DeepLabV3 的语义分割结果,以改变背景。由于计算成本的原因,最终分辨率为 331x331 像素。

用新的人工背景签名执行。(图片由作者提供)

我们用 5 个不同的场景来代替每个标志的背景。下表显示了 de 结果。

比较使用人工背景替换(“背景后缀”)和不使用人工背景替换的*均模型精度。(图片由作者提供)

为了更多地了解这些结果,我们使用了一个名为 LIME 的工具来解释模型预测,突出显示了图像中对推断贡献更大的部分,如下图所示。

使用 LIME 来解释验证集中的模型预测。(图片由作者提供)

解释表明,考虑到解释者的手的位置来推断信号,该模型正专注于图像的正确部分。这表明背景没有偏向结果,这就是为什么替换没有聚集相关特征,就像颜色变换一样

每秒帧数比较

首先,我们研究了将视频二次采样为图像的最合适的 FPS,以便通过以 60 FPS 记录来训练模型。表 5 给出了结果。

图像子样本之间的比较。(图片由作者提供)

值得注意的是,60 FPS 并不能补偿所需的计算资源,因为它在验证集中获得了大约 10%的低准确度。这可能是因为该帧速率的图像几乎是 30 和 20 FPS 的 2 到 3 倍,如图 2 所示,这可能会导致过度拟合,从而导致验证集中的差异更大。除此之外,视频的连续图像彼此相似,产生低的信息增益。

T-student 测试显示,30 帧/秒和 20 帧/秒在测试集中存在显著差异,因此得出结论,这是这种情况下的最佳选择,但这应根据数据集大小而有所不同,一旦 30 帧/秒的训练时间变长,时空特征的探索会影响需要从视频中提取的信息量。

最后一个涉及帧速率的测试是比较以 30 FPS 捕捉的数据集和以 60 FPS 捕捉的数据集之间的性能,如表 6 所示。

以 60 FPS 和 30 FPS 捕获的数据集之间的比较。(图片由作者提供)

在测试集中,结果有利于以 60 FPS 捕获的数据集,因为更多数量的图像有助于模型在训练期间更好地拟合(如表 5 所示)。另一方面,在验证集中,以 60 或 30 FPS 捕获的数据集之间没有显著差异(p 值为 0.58)。另一个相关的事实是,以 30 FPS 捕获的数据集比以 60 FPS 捕获并二次采样到 30 FPS 的数据集具有更少的图像,这是因为符号的执行更快,这是取决于解释者和情况的正常变化。因此,指示口译员缓慢执行手势应该有助于进一步缓解这些捕捉率的准确性差异,主要是在光线充足的场景中,的运动模糊不太明显

因此,在不受控制的情况下,在不同的照明条件和口译员执行的手势速度下,以 60 FPS 捕捉视频并将其重新采样为 30 FPS 应该是最佳选择,在获得大量图像的同时避免运动模糊,缺点是需要更好的传感器和更多的存储空间。尽管如此,在控制良好的情况下,以 30 FPS 的速度捕捉会产生令人满意的结果。

利用多流 CNN 提高验证准确性

作为最后的测试,我们创建了一个多流 CNN 来捕捉图像中的本地和全局信息,如下图所示。

符号识别的多 CNN 架构。(图片由作者提供)

为了分割手,我们使用 EfficientDet 作为对象检测器,将各个图像传递到特征提取器,然后传递到神经网络。我们的最终结果显示,在测试集上的准确率为 96%,在验证集上的准确率为 81%,这表明即使使用简单的数据集进行训练,也有可能获得良好的结果并推广到更复杂的情况。

结论和最后想法

由于新算法和技术的出现,在一些年内,手语识别对于机器学习来说将变得相当容易,但我希望它已经明确了对创建数据集的效率进行进一步研究的需要,因为每个新的翻译系统都需要大量的数据。

我们看到,只需要很少的翻译、简单的记录设置、相同的背景,以及正确的数据扩充选择,就有可能推广到现实世界的场景。在未来的工作中,可以进行更深入的分析,用更多的人和标志来测试这里观察到的相同模式是否会重复。

如需进一步阅读和概念,请参考原文。感谢阅读!

机器学习项目中经常错过的一步——问正确的问题

原文:https://towardsdatascience.com/a-step-often-missed-out-in-machine-learning-project-asking-the-right-questions-c0600401e2a5?source=collection_archive---------28-----------------------

一个经常被忽视的步骤,并立即投入到建筑模型中

照片由艾米丽·莫特拍摄自 Unsplash

介绍

作为一名数据科学家,您可能渴望并兴奋地开始处理数据并运行模型。但是作为一个优秀的数据科学家,我知道这不是最好的方法,因为你可能会在项目进行到一半的时候意识到自己走错了路。

机器学习项目的第一步是对数据和问题陈述有很好的理解。如果没有对数据和数据中的模式有很好的理解,你将无法构建好的模型。在这一步,你进行批判性思考,列出一系列问题、假设,并找到它们的答案。

下面是几个要问的关键问题:

(1)这个机器学习项目的主要目标是什么?

  • 重要的是与公司/客户保持一致的业务,以了解项目的方向和最终目标是什么,退出标准是什么。
  • 了解项目的目的,以及可以为组织提供哪些价值。

(2)收集的数据是否足以回答您的问题并达到项目的目标?

  • 拥有正确的数据集对于帮助实现最终目标非常重要。如果您没有合适的数据集来回答您的问题,那么拥有最佳解决方案和最佳方法就毫无意义。确定收集的数据集是否与用例相关。此外,确定收集的数据是否足够,是否有足够的历史数据/训练数据用于模型训练。
  • 例如,目标是预测某个特定州的房价,但是前几年的数据存在巨大的差距/缺失值。这将影响模型预测的结果,除非采取措施获得正确的数据或预处理缺失的差距以反映正确的趋势。

(3)你的分析的受众是谁?

  • 重要的是要知道谁将是阅读报告的接收端的受众,以及报告中的信息如何对他们有用。他们是技术组的吗?董事会成员?营销团队?销售团队?数据分析师?等等。这些人对技术和统计有不同的理解,所以最好定制你的报告以适合你的听众,以确保你的发现能够被准确地传达。
  • 例如,我的项目的大部分受众是具有很少或零技术知识的业务用户,他们只对预测的最终价值感兴趣。因此,在一个用户友好的交互式仪表盘中显示结果对他们来说非常有用,因为他们可以进行交互并选择特定一周的预测,然后立即查看结果。

(4)何时需要交付预测/报告?

  • 了解何时需要准备好预测或报告是很重要的,这有助于计划安排流程运行,也有助于确定适合使用的数据范围。
  • 例如,如果您正在处理时序数据以预测每周销售需求,并且需要在每周二进行预测。然后,您需要调查最*一周的数据集是否在星期二之前生成并预处理,以便模型进行预测,或者需要进行哪些调整。

(5)你是否具备与本项目相关的领域知识?

  • 是的,你可能是一名拥有技术技能的数据科学家,但有时拥有领域知识有助于数据分析过程,例如更好地理解数据并能够提出正确的问题。拥有与项目相关的特定行业的领域知识,可以让您了解业务流程,并构建可以提高模型性能的特定功能工程。因此,执行额外的研究来更好地理解您正在工作的用例行业肯定是有益的。
  • 拥有领域知识有助于为模型确定正确的特性集,因为您将知道是什么驱动了性能。例如,股票市场价格会受到许多因素的影响,如利率、GDP、债券价格等。在开发预测未来股票价格的模型时,拥有经济学背景可能是一个优势。

(6)你了解数据集中的变量吗

  • 这又回到了上面的问题,即拥有领域知识有助于了解数据集中属性的含义,以及变量是否可以成为预测目标值的强特征。如果在理解变量方面存在障碍,最好做一些研究,并确定谁是你可以联系的合适的人,以帮助填补你在数据集中理解的空白。
  • 例如,帮助金融行业的客户建立机器学习模型,但对金融数据集中使用的术语/词汇没有任何线索或理解,这可能会给你带来困难。因此,在这种情况下,最好花点时间了解一下金融行业,常用术语是什么,您应该了解哪些关键概念。这几个额外的步骤将有助于整个机器学习过程。

(7)如果项目失败,对组织有什么风险/影响

  • 数据科学项目并不总是成功的,也有可能失败,比如数据不足。确定这给组织带来了什么影响,并确定是否有另一个用例,该项目可以基于已构建的现有知识进行转换并仍然能够利用。

结论:

数据科学不仅仅是构建模型、调整模型参数,而是拥有正确的领域知识、理解数据、与项目目标保持一致,并能够将您的发现传达给最终用户。一旦您对数据有了正确的理解,那么您将能够进入下一步,即执行更深入的数据探索,查看数据集的总体统计数据,并了解应该如何预处理数据,需要哪些功能工程步骤。

本文中指定的问题列表是一些关键问题,还可以有更多。如果你对其他问题有好的建议,请在下面的评论中列出来。

最后,感谢您阅读这篇文章!😃

参考和链接:

[1]https://towards data science . com/domain-expertise-why-it-important-for-data-scientists-2d 6a 406d 544d

Python 中的一个故事帮助你理解 Itertools

原文:https://towardsdatascience.com/a-story-in-python-helps-you-understand-itertools-c8a45ed3d80b?source=collection_archive---------28-----------------------

图片由 Boke9a 从 Pixabay 拍摄

不要总是从枯燥的理论开始学习

很多 Python 开发者喜欢用 Itertools 模块,这个模块确实非常强大。排列和组合是这个模块中最受欢迎的功能。

当人们学习这两个术语时,几乎总是从理论开始。这是数学领域之一——组合学。然后,有很多原理和公式要理解甚至记忆。

维基百科页面截图— 排列

嗯,理论是重要的,但有时它可能不是将知识应用于实践的最快方法,特别是当我们想用编程来解决现实生活中的一些问题时。

例如,无论有没有替换,我们都不太可能在袋子里捡起红色和蓝色的球。然而,我们更有可能使用编程来生成一个花名册,以计划谁负责某事:)

在本文中,我将使用一个实际的例子来介绍 Python 中 Itertools 模块的 4 个重要函数(product()permutations()combinations()combinations_with_replacement())。

0.问题定义和准备

图片由 Gerd Altmann 来自 Pixabay

现在,我们直接进入问题。假设我们是一个三人团队:

  • 爱丽丝
  • 上下移动
  • 克莉丝

我们需要有人在这个周末待命,因为促销活动应该会给我们的网站带来非凡的流量。所以,有两天时间,我们需要名字。

假设我们需要使用 Python 来生成花名册的所有可能性。因为我们需要使用 Itertools 模块,所以为了方便起见,让我们在本文中导入所有的函数。

from itertools import *

1.这两天有人吗

在第一种情况下,两个人的顺序确实很重要。这是可能的,因为周六和周日对某些人来说可能有不同的意义。

还有,假设这些人不介意这两天都值班,只是假设:)

在这种情况下,我们可以使用product()函数,它是一个笛卡尔乘积。基本上所有的可能性都会列出来,穷尽。

for i in product(['Alice', 'Bob', 'Chris'], repeat=2):
    print(list(i))

在上面的代码中,product()函数有两个参数。第一个是所有名字的列表,第二个告诉它我们需要名字填充多少个“空格”。

2.两天里两个不同的人

我能听到团队在抱怨,因为他们肯定不想两天都随叫随到。所以,花名册上的两个名字应该不会重复。除此之外,顺序仍然很重要

在这种情况下,我们可以使用permutations(),因为它严格地选取两个而不重复。

for i in permutations(['Alice', 'Bob', 'Chris'], 2):
    print(list(i))

由于这个函数,签名已经改变,所以我们不应该使用参数名repeat。这两个参数不需要改变,仍然是名称列表和空格数。

3.任何人在这两天没有秩序

在这种情况下,假设团队成员有自己的灵活性,如果他们在名册上,他们可以随时待命。这意味着顺序不再重要了,因为被接走的人可以互相交流,决定哪一天走。

为了满足这个需求,我们需要使用combinations_with_replacement()函数。

for i in combinations_with_replacement(['Alice', 'Bob', 'Chris'], 2):
    print(list(i))

4.两个不同的人在没有订单的两天里

在前一次运行之后,团队再次抱怨,因为我们忘记了使人不可重复。因此,在这种情况下,名称不应重复,顺序也很重要。

在这个场景中,我们需要如下使用combinations()函数。

for i in combinations(['Alice', 'Bob', 'Chris'], 2):
    print(list(i))

摘要

图片来自 Pixabay 的 Joshua Woroniecki

你有没有注意到我们实际上在玩两个条件?

  • 秩序是否重要
  • 人员是否可重复

对于上述两个条件,我们有完全不同的可能性。我们实际上可以使用product()功能来帮助穷尽所有的可能性,因为“是或否”是可以重复的,而且顺序确实很重要。

for i in product(['Yes', 'No'], repeat=2):
    print(i)

到目前为止,我希望您已经理解了在某些情况下何时使用 Itertools 模块中的这 4 个函数。我也将它们组织在下图中。希望能说的更清楚一点!

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

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

一个频繁统计推断的故事

原文:https://towardsdatascience.com/a-story-of-frequentist-statistical-inference-12d38a7bcd77?source=collection_archive---------22-----------------------

为假人解释统计推断、假设检验、显著性水*和 p 值的概念。

照片由 Siora 摄影在 Unsplash 上拍摄

学习统计学应该是有趣且直观的,至少我是这么认为的。然而,当我们试图在研究生院或网上学习统计学时,所有与统计学相关的技术术语突然向我们扑来。

看看下面维基百科对统计假设的定义:

统计假设是一种基于观察数据可检验的假设,观察数据建模为随机变量集合的实际值。—维基百科

什么?

对于刚开始学习统计学的初学者来说,上面的统计假设定义几乎没什么帮助。所以在这篇文章中,我们将会以一种有趣的方式讲述频率主义统计推断的基本原理。希望这篇文章能帮助你建立对推断统计学的直觉。

事不宜迟,让我给你介绍一个低于*均水*的学生吉米和他的教授之间的故事。

统计推断的故事

一个夏天的下午,就在假期开始前,吉米接到一个不同寻常的电话,电话是他的教授打来的,请他去他的办公室。

他的教授对他说:“我想和你讨论一些事情,请现在到我办公室来一趟。”。

在他教授的办公室里,吉米只是坐在桌子后面,想知道他的教授在想什么样的讨论。

作者图片

基本上双方都是因为不同的原因而震惊。教授震惊地发现,低于*均水*的学生吉米在期末考试中得了最高分。另一方面,吉米感到震惊,因为他的教授明确指控他作弊,尽管他为期末考试努力学习。

上面吉米和他的教授之间的场景是你需要知道的关于统计推断的好和坏的一面。

统计推断总是伴随着不确定性。然而,它是理解一切的有力工具。它告诉我们什么是可能的,什么是不可能的。

有了统计推断,你就有能力观察一些模式,然后用概率来确定这些模式最可能的解释。

如果吉米是个 A+的学生,他的教授不会对他在考试中获得最高分感到惊讶。然而,由于吉米是一个中等偏下的学生,他在这学期的考试中获得最高分的事实完全出乎意料。

教授的作弊指控是可以理解的,尽管他不能真正证明吉米作弊。从教授的角度来看,吉米有可能因为学习得当而获得最高分,但这种可能性极小。这是一种反常现象。

那么,教授怎么知道什么是可能的,什么是不可能的呢?从历史资料来看。吉米过去几个学期不太好的考试成绩记录。

统计推断在很大程度上依赖于数据来解释一切。

这就是统计推断的美妙之处。它结合了数据和概率,使我们能够对一个现象得出有意义的见解。

假设检验

假设检验只是一个书呆子术语,用来描述上面吉米和他的教授之间的场景。你可以把假设想成一种假设或者一种信念。所以当你试图用样本数据来解释你的假设或信念时,你基本上是在做假设检验。

假设检验是试图通过查看样本数据来理解假设的方法。

在假设检验的世界里,有两件事你应该知道:零假设替代假设

无效假设假设一切正常,没有异常情况发生,吉米是无辜的。与此同时,另一种假设认为有可疑或异常的事情正在发生。吉米成绩很好,因为他作弊了。

基于上面的故事,教授可以把他的无效假设和替代假设框定为这样:

  • 零假设:吉米得到他的分数完全是因为一个随机的机会。任何低于*均水*的学生都可能偶尔在班上取得好成绩,对吗?
  • 另一种假设:吉米因为作弊而得到分数。

作者图片

接下来,我们的主要工作是拒绝这两个相互冲突的假设中的一个。如果我们拒绝零假设,这意味着我们接受另一个假设,反之亦然。但是,我们如何接受一个而拒绝另一个呢?

再一次,通过观察我们的数据。记住,统计推断是数据和概率的结合。

假设教授有过去几个学期 1000 名学生各科考试成绩的历史数据。在每一个科目中,吉米的考试成绩总是在倒数 3 名。然而,在这学期的考试中,吉米在那 1000 名学生中得了最高分。

教授接着想:'根据我在数据中看到的证据,吉米在 1000 名学生中随机获得最高分,这听起来有多荒谬?不,这太荒谬了。这不可能是偶然的。一些可疑的事情正在发生。

因此,他决定拒绝零假设,支持替代假设。吉米一定是作弊了!

显著性水*

教授拒绝零假设的决定是可以理解的,即吉米得到最高分是由于一个随机的机会。为什么一个在 1000 名学生中考试成绩一直排在最后 3 名的学生突然得到了最高分?有可能,但是极不可能

然而,现在我们需要通过解决一个基本问题来扩展这个概念:零假设有多荒谬或不可能让我们拒绝它而支持替代假设?

答案是:这取决于你和你的具体研究领域。每个人都有自己的主观判断来判断零假设是否足够荒谬。

然而,根据经验,人们有一个共同的阈值来拒绝零假设:5%或十进制形式的 0.05。这个 0.05 是显著性水*,表示假设我们的零假设为真,在我们的数据中观察到结果的可能性的上限。

显著性水*表示在我们决定拒绝零假设之前,我们对结果的容忍水*。

假设教授有吉米过去几个学期考试成绩的大量历史数据。根据数据,Jimmy 的考试成绩可以表示为如下分布。

从曲线中,我们可以看到,总体而言,吉米的*均成绩为 40,标准差为 10。然后教授能够形成他的零假设,就像:

“吉米只是一个中等偏下的学生。我是说,看看他的成绩。他的*均成绩是 40 分!如果在这学期的考试中,他的*均分在 40 分左右,我不会感到惊讶。

这学期,教授想进行 10 次考试。基于上面的分布和他想要进行 10 次考试的事实,教授能够对吉米这学期的*均考试分数做出假设。

首先,他将计算标准误差,即标准偏差(10)除以样本数量的*方根(他这学期将进行 10 次考试)。

基于 3.16 的标准误差,教授可以构建如下分布曲线:

基于如上所述的分布,教授能够基于所谓的经验法则形成假设:

“如果我要进行几个实验,每个实验包括 10 次考试,我希望…

  • 在 68%的情况下,吉米的*均考试成绩会在*均值的一个标准误差范围内,*均值大约在 36.84 到 43.16 之间。
  • 在 95%的情况下,吉米的*均考试成绩都在*均值的两个标准误差范围内,*均值大约在 33.81 到 46.19 之间。
  • 在 99%的情况下,吉米的*均考试成绩都在*均值的 2.5 倍标准误差范围内,*均值大约在 31.88 到 48.12 之间。

对于显著性水*,假设教授遵循经验法则,这意味着在他说服自己拒绝他的零假设之前,他有 5%的显著性水*。

这意味着,如果他进行几个实验,每个实验包括 10 次考试,他预计在 95%的实验中,吉米的*均考试分数将大致位于*均值的两个标准误差内,或大约 33.81 至 46.19。相反,只有在 5%的实验中,吉米的*均考试分数会低于 33.81 或高于 46.19。

作者图片

如果教授有 1%或 0.01 的显著性水*,这意味着什么?这意味着,如果他进行几个实验,每个实验包括 10 次考试,他预计在 99%的实验中,吉米的*均考试分数将位于*均值的大约 2.5 个标准误差内,或大约 31.88 到 48.12。相反,只有 1%的实验中,吉米的*均考试分数会低于 31.88 或高于 48.12。

显著性水*越低,你就越谨慎地宣布发生了异常情况。这意味着在你决定拒绝零假设之前,你需要非常有力的证据或异常。

现在让我们回到吉米的教授和他的 5%显著性水*。

在批改完所有的试卷后,教授发现吉米这学期的 10 次考试*均得分为 50 分。基于他的显著性水*,教授有权拒绝零假设,即吉米由于随机机会得到 50 分的事实,因为:

  • 吉米这学期的*均考试分数远高于他之前的预期范围,在 33.81 到 46.19 之间。如果教授具有 5%的显著性水*,他将期望吉米在仅 5%的时间内,或者在 100 次实验中的 5 次,或者在 1000 次实验中的 50 次实验中获得超出该范围的*均考试分数。
  • *均来说,教授 100 次中有 95 次会正确地拒绝零假设,即有可疑的事情发生。吉米一定是作弊了。
  • 相反,100 次教授中只有 5 次是错的,这意味着他错误地指责吉米作弊,而实际上他没有。

p 值

当教授发现吉米在考试中得了好成绩时,他有多惊讶,这可以用一个单一的标量值来量化。这个值叫做 p 值。

p 值的作用是,它为你提供了一个总结,告诉你,假设我们的零假设为真,你刚才看到的结果有多不可能。

p 值越低,假设我们的零假设为真,我们刚刚看到的证据就越令人惊讶。

在统计学中,p 值代表概率值,您可以通过样本数据的分布来计算该值。将 p 值与您的显著性水*进行比较,将使您能够评估是否应该拒绝您的零假设。

如果吉米这学期的*均考试成绩是 60 分,那么在他的教授看来,p 值是如此之小(可能在 0.00001 左右),以至于他不得不指责吉米作弊,也就是说,他拒绝零假设,而支持替代假设。

同时,如果吉米的*均得分是 50,而不是 60,p 值仍然很小,但不会像以前那么小。然而,p 值足够小,以至于它仍然低于教授的显著性水*(0.05),这意味着教授很可能仍然拒绝零假设。

现在,如果吉米的*均分是 42,在*均值的两个标准误差范围内,那么在他的教授看来,p 值很大(高于 0.05)。这意味着没有发生任何令人惊讶的事情,一切都很正常。吉米就是吉米,一个一贯低于*均水*的学生。由于一个随机的机会,他得了 42 分。

第一类错误和第二类错误

当你有了一个 p 值,然后将它与你的显著性水*进行比较,你就有权力决定是否拒绝零假设。

然而,你需要记住我们在第一节讨论的内容:统计推断总是伴随着不确定性。它不是一个神奇的工具。即使是世界上最好的数学家也不会让你在做统计推断时没有机会犯错。

统计推断的要点是在数据和概率的帮助下理解你的问题。基于我们从数据中看到的证据,通过查看 p 值和显著性水*,我们有两个选择:

  • 拒绝替代假设,支持无效假设,或
  • 拒绝零假设,支持替代假设。

问题是,拒绝或接受零假设的决定完全是主观的。如前所述,每个人都可以微调自己的重要性级别。这意味着我们容易犯错误。

在统计学中,误差分为两种:第一类误差第二类误差

第一类错误是错误地拒绝零假设。

第二类错误是未能拒绝零假设。

第一类错误意味着你错误地拒绝了零假设。你是说发生了一些特殊的事情,而实际上,什么都没发生,一切都只是一堆灰尘(想象一下马修·麦康纳在《华尔街之狼》中的场景)。

现在让我们回到吉米和他的教授身上。

假设吉米在这学期的考试中*均得了 47 分,因为他学习非常努力。比以前更努力。吉米光明正大地得到了分数。然而,他的教授并不相信,因为他预计 95%的情况下吉米的*均考试分数会在 33.81 到 46.19 之间。因为他 5%的显著性水*,p 值在他眼里已经足够小了。因此,教授指责吉米作弊,而实际上他并没有作弊。

他的教授犯了一个 I 型错误。他错误地指控一名无辜的学生。

作者图片

同时,第二类错误意味着你不能拒绝零假设。这意味着你说什么都没发生,而事实上,一些特殊的事情发生了。

和以前一样,假设吉米在这学期的考试中*均得了 47 分。剧透:他整个考试都在作弊,所以他的*均成绩是 47 分。但是,这次他的教授显著性水*非常低(0.01)。这意味着只有吉米的*均考试成绩大致在 48 分以上,教授才有信心指控吉米作弊。

当教授发现 Jimmy 的*均分为 47 时,他的显著性水*小于 p 值,因此他无法拒绝零假设。他断定吉米是无辜的,吉米得了 47 分是因为他努力学习,而实际上他并没有。

他的教授犯了一个第二类错误。他错误地释放了一名有罪的学生而没有受到惩罚。

作者图片

现在你知道有两种类型的错误。但是哪个更差呢?

同样,答案取决于你从事的研究领域。

如果你是一名经常试图诊断病人是否患有癌症的医生,你可能想要提高你的显著性水*,以抑制你犯第二类错误的机会。你不想告诉一个病人他们很好,很健康,但事实上,他们得了结肠癌。

另一方面,如果您正在构建一个垃圾邮件分类器,您可能希望构建一个具有较低显著性级别的算法,以抑制分类器犯 I 类错误的可能性。您不希望一封重要的非垃圾邮件被您的分类器归类为垃圾邮件。如果发生这种情况,你会收到同事和客户的投诉。

这就是用频率主义者的观点介绍统计推断的全部内容。希望这篇文章能帮助你学习统计学。

Python 中 A/B 测试的简明指南

原文:https://towardsdatascience.com/a-straightforward-guide-to-a-b-testing-in-python-4432d40f997c?source=collection_archive---------19-----------------------

通过几个简单的步骤,让您的实验更加严谨

杰森·登特在 Unsplash 上拍摄的照片

A/B 测试在实验过程中非常有用。在比较一个选项和另一个选项时,增加统计的严谨性。这是有助于防止做出错误结论的一个步骤。

本文将演示 A/B 测试中的关键步骤:

  1. 确定最小可检测效应
  2. 计算样本量
  3. 分析结果的统计显著性

场景概述

为了演示公司可能采用 A/B 测试的情况,我将创建一个虚拟的视频游戏数据集。

在这种情况下,一家视频游戏开发公司意识到许多用户在一个特定的级别后会退出游戏。产品团队提出的一个假设是,关卡太难了,让它变得更容易会减少用户的挫折感,最终会有更多的玩家继续玩这个游戏。

样本量计算

期望的业务效果

我们的视频游戏公司对关卡做了一些调整以使其更容易,有效地将难度从改为。在盲目地向所有用户推出更新之前,产品团队希望在一个小样本上测试这些变化,看看它们是否会产生积极的影响。

理想的衡量标准是达到我们的等级后继续玩游戏的玩家的百分比。目前,70%的用户在剩下的 30%停止游戏的地方继续玩。产品团队已经决定将这一比例提高到 75%,这将保证对游戏进行部署和更新。

最小可检测效应

这条信息(70%到 75%)帮助我们计算最小可检测效应——计算样本量的输入之一。我们的问题是测试两个比例,所以我们将使用 statsmodels 中的proportion _ effectsize函数将这种变化转换成我们可以处理的东西。

Output: For a change from 0.70 to 0.75 - the effect size is -0.11.

样本量

现在我们有了最小可检测效应,我们可以计算样本大小。为了解决比例问题,使用了ZT ind solve power(也来自 statsmodels 库)。

我们设置 nobs1 (样本 1 的观察值)参数,表示这就是我们要解决的问题。

0.05 的显著性水*和 0.8幂是通常选择的默认值,但是这些可以基于场景和期望的假阳性与假阴性灵敏度进行调整。

Output: 1250 sample size required given power analysis and input parameters.

实验数据概述

在与产品团队沟通所需的样本量后,进行了一项实验,随机抽取 1250 名玩家玩新的较容易的级别,另外 1250 名玩家玩较难的级别。

收集数据后,我们了解到 980 名用户(1250 名)在达到中等难度后继续玩游戏,而 881 名用户(1250 名)在达到高难度后继续玩游戏。这看起来相当不错,超过了我们至少 5%改进的希望,我们应该做出改变吗?

在决定之前,测试统计显著性是很重要的,以防止这种差异可能只是随机发生的(考虑到我们的显著性和功效)。

作者提供的实验数据、图像和数据

分析结果

计算输入

我们将使用的统计测试是比例 _ztest 。我们需要首先计算一些输入——成功和观察的数量。数据存储在 pandas 数据帧中,其中有中、硬列,0 代表停止游戏的用户,1 代表继续游戏的用户。

Output: Medium: 980 successes of 1250 trials. Hard: 881 successes of 1250 trials.

执行 Z 测试

执行 z 测试很简单,只需输入:

Output: z stat of 4.539 and p value of 0.0000. 

低于 0.05 的 p 值符合我们的标准 。把关卡难度降低到中等才是正道!

摘要

虽然这是一个虚构的简单示例,但是在现实世界中使用类似的方法可以为您的实验增加一些严谨性。当您有两个样本,并希望根据您想要的度量来判断某个实验是否导致了显著的变化时,可以考虑使用 A/B 测试。

Github上可以找到所有的例子和文件。

原载于https://data stud . dev

用 Python 清理和准备数据的简单指南

原文:https://towardsdatascience.com/a-straightforward-guide-to-cleaning-and-preparing-data-in-python-8c82f209ae33?source=collection_archive---------2-----------------------

如何识别和处理脏数据?

杰西·奥里科在 Unsplash 上的照片

真实世界的数据是肮脏的。事实上,数据科学家大约 80%的时间都花在收集、清理和准备数据上。这些繁琐(但必要)的步骤使得数据适合我们想要建立的任何模型,并确保数据的高质量。

数据的清理和准备有时可能很棘手,因此在本文中,我想通过展示一些用于清理和准备数据的技术、方法和函数来简化这些过程。为此,我们将使用一个在 Kaggle 上可用的网飞数据集,它包含了关于网飞所有图书的信息。我使用电影数据集是因为它们经常在许多数据科学项目的教程中使用,例如情感分析和构建推荐系统。您还可以遵循本指南,使用来自 IMDb、MovieLens 的电影数据集或任何需要清理的数据集。

虽然 Kaggle 数据集可能看起来组织良好,但它还没有准备好被使用,所以我们将识别丢失的数据、离群值、不一致的数据并进行文本规范化。下表详细显示了这一点。

**Table of Contents** 1\. [Quick Dataset Overview](#4e47)
2\. [Identify Missing Data](#8508)
 - [Create a percentage list with .isnull()](#3b34)
3\. [Dealing with Missing Data](#e729)
 -[Remove a column or row with .drop, .dropna or .isnull](#0a8b)
 - [Replace it by the mean, median or mode](#263c)
 - [Replace it by an arbitrary number with .fillna()](#06bb)
4\. [Identifying Outliers](#3eef)
 - [Using histograms to identify outliers within numeric data](#691c)
 - [Using boxplots to identify outliers within numeric data](#89e4)
 - [Using bars to identify outliers within categorical data](#199b)
5\. [Dealing with Outliers](#63cd)
 - [Using operators & | to filter out outliers](#3399)
6\. [Dealing with Inconsistent Data Before Merging 2 Dataframes](#49f0)
 - [Dealing with inconsistent column names](#5803)
 - [Dealing with inconsistent data type](#2f54)
 - [Dealing with inconsistent names e.g. "New York" vs "NY"](#d8d7)
7\. [Text Normalization](#1e4f)
 - [Dealing with inconsistent capitalization](#b2c9)
 - [Remove blank spaces with .strip()](#ff95)
 - [Remove or replace strings with .replace() or .sub()](#0b36)
8\. [Merging Datasets](#2e19)
 - [Remove duplicates with .drop_duplicates()](#3019)

1.快速数据集概述

下载数据集后要做的第一件事是检查每列的数据类型(列的值可能包含数字,但可能不是日期时间或整数类型)

读取 CSV 文件后,键入.dtypes 找到每一列的数据类型。

df_netflix_2019 = pd.read_csv('netflix_titles.csv')
df_netflix_2019.dtypes

一旦运行该代码,您将获得以下输出。

show_id          int64
type            object
title           object
director        object
cast            object
country         object
date_added      object
release_year     int64
rating          object
duration        object
listed_in       object
description     object
dtype: object

这将帮助您识别列是数值变量还是分类变量,在清理数据之前知道这一点很重要。

现在要找到数据集包含的行数和列数,使用.shape 方法。

In [1]: df_netflix_2019.shape
Out[1]: (6234, 12) #This dataset contains 6234 rows and 12 columns.

2.识别缺失数据

当数据收集不当、数据输入错误或数据值未存储时,有时会发生数据丢失。这种情况经常发生,我们应该知道如何识别。

创建一个百分比列表。isnull()

识别缺失数据的一个简单方法是使用.isnull().sum() 方法

df_netflix_2019.isnull().sum()

这向我们显示了每一列中的一些“NaN”值。如果数据包含许多列,您可以使用.sort_values(ascending=False) 将缺失值最多的列放在最上面。

show_id            0
type               0
title              0
director        1969
cast             570
country          476
date_added        11
release_year       0
rating            10
duration           0
listed_in          0
description        0
dtype: int64

也就是说,我通常用百分比来表示缺失值,因此我对缺失数据有一个更清晰的了解。以下代码显示了%中的上述输出

现在更明显的是,数据集中省略了许多控制器。

show_id: 0.0%
type: 0.0%
title: 0.0%
director: 31.58%
cast: 9.14%
country: 7.64%
date_added: 0.18%
release_year: 0.0%
rating: 0.16%
duration: 0.0%
listed_in: 0.0%
description: 0.0%

既然我们发现了丢失的数据,我们就必须管理它。

3.处理缺失数据

处理缺失数据有不同的方法。处理缺失数据的正确方法将在很大程度上受到数据和项目目标的影响。

也就是说,下面介绍了处理缺失数据的 3 种简单方法。

用移除列或行。下降,。dropna 或者。isnull

如果您认为有必要删除一个列,因为它有太多的空行,那么您可以使用.drop()并添加axis=1 作为参数来表示您想要删除的是一个列。

但是,大部分时间只够删除包含那些空值的行。这样做有不同的方法。

第一个解决方案使用.dropaxis=0 来删除一行。第二个解决方案标识空值,并通过使用求反运算符~ 获取非空值,而第三个解决方案使用.dropna删除列中的空行。

如果您想在丢弃后保存输出,使用inplace=True 作为参数。在这个简单的例子中,我们不会删除任何列或行。

用*均值、中间值或众数代替它

另一种常见的方法是使用*均值、中间值或众数来替换空值。*均值和中值用于替换数值数据,而众数用于替换分类数据。

正如我们之前看到的,rating 列包含 0.16%的缺失数据。由于rating是一个分类值,我们可以很容易地用模式完成这一小部分数据。

首先我们计算了模式(TV-MA),然后我们用.fillna填充了所有的空值。

用任意数字替换它。菲尔娜

如果数据是数字,我们还可以设置一个任意的数字来防止删除任何行,而不会影响模型的结果。

如果duration 列是一个数值(目前的格式是 string,例如90 minutes,我们可以用下面的代码将空值替换为 0。

df_netflix_2019['duration'].fillna(0, inplace=True)

此外,您可以使用ffillbfill分别向前和向后传播最后一次有效观察。这对于某些数据集非常有用,但在df_netflix_2019数据集中却没有用。

4.识别异常值

异常值是指与其他观察值显著不同的数据。数据集可能包含真正的异常值或在数据收集不良后获得的异常值或由数据输入错误导致的异常值。

使用直方图识别数值数据中的异常值

我们将使用持续时间作为参考,这将有助于我们识别网飞星表中的异常值。在我们的数据集中,duration列不被视为数值(例如 90),因为它与字符串混合在一起(例如 90 min)。此外,电视节目的持续时间是按季节划分的(例如,两季),因此我们需要将其过滤掉。

使用下面的代码,我们将只从数据集中提取电影,然后从duration列中提取数值。

现在,数据可以显示在柱状图中了。你可以用 Python 中的 matplotlib,seaborn 或者 pandas 制作剧情。在这种情况下,我将使用 matplotlib。

import matplotlib.pyplot as pltfig, ax = plt.subplots(nrows=1, ncols=1)
plt.hist(df_movie['minute'])
fig.tight_layout()

下面的情节揭示了电影的时长是如何分布的。通过观察剧情,我们可以说第一个条(3 '–34 ')和最后一个可见条(> 189 ')的电影很可能是离群值。它们可能是短片或长纪录片,不太适合我们的电影类别(同样,这仍然取决于你的项目目标)

作者图片

使用箱线图识别数值数据中的异常值

另一种识别异常值的方法是箱线图。我更喜欢使用箱线图,因为它将离群值排除在了盒子的触须之外。因此,在不考虑异常值的情况下,更容易确定最小值和最大值。

我们可以用下面的代码很容易地做出箱线图。

import seaborn as snsfig, ax = plt.subplots(nrows=1, ncols=1)
ax = sns.boxplot(x=df_movie['minute'])
fig.tight_layout()

箱线图显示,低于 43 '和高于 158 '的值可能是异常值。

作者图片

同样,我们可以用.describe() 方法识别箱线图的一些元素,如下四分位数(Q1)和上四分位数(Q3)。

In  [1]: df_movie['minute'].describe()
Out [1]: count    4265.000000
         mean       99.100821
         std        28.074857
         min         3.000000
         25%        86.000000
         50%        98.000000
         75%       115.000000
         max       312.000000

除此之外,您可以轻松地显示 boxplot 的所有元素,甚至使其与 Plotly 交互。

import plotly.graph_objects as go
from plotly.offline import iplot, init_notebook_modefig = go.Figure()
fig.add_box(x=df_movie['minute'], text=df_movie['minute'])
iplot(fig)

使用条形识别分类数据中的异常值

如果数据是分类的,您可以通过绘制条形图来识别具有少量观察值的类别。

在这种情况下,我们将使用内置的熊猫可视化来制作条形图。

fig=df_netflix_2019['rating'].value_counts().plot.bar().get_figure()
fig.tight_layout()

作者图片

在上面的图中,我们可以看到模式(列中最常出现的值)是“TV-MA ”,而“NC-17”和“UR”并不常见。

5.处理异常值

一旦我们确定了离群值,我们就可以使用 Python 的操作符轻松地过滤掉它们。

使用运算符& |过滤掉异常值

Python 运算符很容易记忆。&相当于and,而|相当于or

在这种情况下,我们将根据箱线图显示的值过滤掉异常值。

#outliers
df_movie[(df_movie['minute']<43) | (df_movie['minute']>158)]
#filtering outliers out
df_movie = df_movie[(df_movie['minute']>43) & (df_movie['minute']<158)]

现在创建的df_movie 只包含持续时间在 43 '到 158 '之间的电影。

6.在合并两个数据帧之前处理不一致的数据

我们经常遇到的一个常见任务是合并数据帧以增加观察的信息。不幸的是,大多数时候,数据集有许多不一致的地方,因为它们来自不同的来源。

从现在开始,我们将使用第二个数据集 **df_netflix_originals** ,它只包含网飞原件(。csv 在 myGithub上可用),我们将它与原始数据集 **df_netflix_2019** 合并,以确定原创和非原创内容。

处理不一致的列名

我们必须处理的一个常见问题是表之间不同的列名。使用.rename 方法可以很容易地更改列名。

处理不一致的数据类型

如果您试图基于具有不同数据类型的列合并两个数据集,Python 将会抛出一个错误。这就是为什么你必须确保类型是相同的。如果同一个列有不同的类型,你可以使用.astype方法来规范化它。

处理不一致的名称,例如“纽约”与“纽约”

通常,列和数据类型规范化足以合并到数据集;但是,有时,由于数据输入错误(打字错误)或单词书写方式不一致,导致同一列中的数据不一致。

电影片名一般不会有这些问题。他们可能在标点符号上有分歧(我们稍后会处理这个问题),但是电影通常有一个标准的名称,所以为了解释如何处理这个问题,我将创建一个数据集和一个包含以不同方式编写的状态的列表。

有很多库可以帮助我们解决这个问题。在这种情况下,我将使用fuzzywuzzy 库。这将根据两根弦之间的距离给出一个分数。您可以选择更适合您的数据的计分器。在这个例子中,我将设置scorer=fuzz.token_sort_ratio

正如我们在输出中看到的,scorer 在匹配字符串方面做得很好。

states         match       score
CA             California  33       
Hawai          Hawaii      91       
NY             New York    40       
Washington DC  Washington  87 

但是,请记住,它仍然可以匹配错误的名称。

7.文本规范化

文本规范化是自然语言处理的必要条件。这涉及到以下使文本一致的技术。

  • 删除空格、标点符号和非字母数字字符
  • 标记化、词干化、词汇化、删除停用词

为了简单起见,本文将只涉及第一点。然而,在下面的文章中,我将解释如何在 Python 中标记文本。

</5-simple-ways-to-tokenize-text-in-python-92c6804edfc4>

处理不一致的大写

在合并 2 帧之前,我们必须确保大多数行匹配,规范大写有助于此。

有许多方法可以降低框架中的小写文本。下面你可以看到两个选项(.apply.str.lower)

用删除空格。条状()

有时数据有前导或尾随空格。我们可以用.strip方法摆脱它们

用移除或替换字符串。替换()或。sub()

两个数据集之间的文本常常在标点符号上有分歧。您可以使用.apply and .sub.replace将其移除

把它们中的任何一个和正则表达式一起使用都很好。例如,正则表达式[^\w\s] 将帮助您删除单词(a-z,A-Z,0–9,_)或空格以外的字符。

正则表达式(regex)可能看起来令人生畏,但它们比您想象的要简单,并且在从文本数据中提取信息时至关重要。在下面的链接中,你会发现我为轻松学习正则表达式而制作的简单指南。

8.合并数据集

最后,我们可以合并数据集df_netflix_originalsdf_netflix_2019。有了这个,我们可以识别哪些电影是网飞原创,哪些只属于目录。在这种情况下,我们执行一个外部连接,将“Catalog”值赋予“Original" 列中所有值为空的行。

用删除重复项。drop_duplicates()

具有两个键列的外部连接的一个缺陷是,如果我们只考虑一个列,我们将获得重复的行。在这种情况下,我们基于titlerelease_year列进行合并,因此很可能存在具有不同release_year的重复titles

您可以使用.drop_duplicates方法删除一列中的重复项

按类型和来源分组的数据分布如下。

In[1]: df_netflix[['original', 'type']].value_counts()Out[1]:
original  type   
Catalog   Movie      3763
          TV Show    1466
Netflix   TV Show    1009
          Movie       504

就是这样!现在数据是干净的,准备好进行处理了!此分析背后的代码可在我的 Github 上找到

如果你想学习西班牙语 Python,可以订阅我的 YouTube 频道。每周我都会发布类似下面这样的视频。

你仍然可以清理更多(如果必要的话)或者在你的数据科学项目中使用这些数据,就像我找到最好的网飞和迪斯尼电影来学习外语一样(NLP 项目)

下面是一些我争论真实世界数据的项目:

https://medium.datadriveninvestor.com/i-used-to-pay-180-yr-for-a-profitable-betting-tool-this-year-i-built-one-in-python-dda1a9b9581f https://medium.datadriveninvestor.com/make-money-with-python-the-sports-arbitrage-project-3b09d81a0098

用人工智能发现构思人工智能用例的结构化方法

原文:https://towardsdatascience.com/a-structured-approach-for-ideating-ai-use-cases-with-ai-discovery-85d00db078b5?source=collection_archive---------27-----------------------

行业笔记

改编的设计 Sprint 可以帮助团队构思相关且有影响力的人工智能用例

图片来源:AI 新加坡

本月早些时候,我有机会在一个关于人工智能诊所和人工智能发现的网络研讨会上分享,这是人工智能新加坡(AISG)综合项目的一部分,旨在帮助组织加快人工智能的采用。在这篇文章中,我将详细阐述在人工智能发现研讨会上发生的事情,在那里人工智能用例被构思和优先化。

AI 原型不同于软件原型,需要准备数据和实验算法来确定用例的可行性。既费时又费钱。组织必须想出正确的用例来减少浪费的努力,并增加采用人工智能的可能性。

作为 AI 新加坡的助理主管,我目睹了商业领袖在确定 AI 用例时犯的常见错误。这些错误导致了不可行或不完美的人工智能用例的开发,这些用例继续困扰着组织,并削弱了未来对人工智能的兴趣。这些本可以最小化。

构思人工智能用例的常见错误

1。没有最小化群体思维

商业领袖通常会召集不同部门的代表,就潜在的人工智能用例进行头脑风暴。头脑风暴会议通常以商业领袖分享他们的想法、员工展示他们的想法或者非正式的圆桌讨论开始。

“首席执行官建议的第一个项目并不适合投资。”—亚马逊 re:MARS 2019 期间的吴恩达

所有这些方法都有严重的缺陷:群体思维通常发生在高级管理层分享他们的想法之后;好的想法可能在提交给管理层之前就已经被筛选掉了;外向的人将主导讨论。所有这一切将导致一系列低风险和“常识性”的想法,无法利用人工智能的全部潜力。

2.没有对齐团队

部署人工智能解决方案不仅仅是安装新软件。鉴于人工智能的能力,它通常会要求组织调整业务流程,要求员工调整工作流程,以充分利用信息技术的潜力。换句话说,成功的人工智能模型部署需要一致的团队。

然而,商业领袖在构思过程中经常忽略团队的一致性。这导致缺乏对 AI 模型的支持和采用,因为具有不同优先级的团队不会投入时间和精力来调整他们现有的过程。人工智能解决方案将自然消亡。

3.没有聘请具有人工智能专业知识的主持人

我见过一些公司在内部“人工智能构思会议”后选择与人工智能无关的用例。根本原因?会议中没有人有人工智能方面的专业知识。他们无法破译选择的用例是否可能用于人工智能开发。这是徒劳的,因为参与者必须重新进行构思练习,以确定更好的和相关的人工智能用例。

例如,我工作过的一家公司选择了“使用人工智能来确保客户在现场收取快递”。这个用例与其说是 AI 用例,不如说是业务流程问题。它可以在构思研讨会期间更早存档,以将每个人的注意力集中在人工智能相关的用例上。

什么是 Design Sprint,它如何提供帮助?

Google Ventures 开发了 Design Sprint 来构思和测试结构化方法中的用例。它是专门为解决头脑风暴中提到的常见错误而设计的。然而,最初的过程并不是为构思人工智能用例而优化的。

基于我与各种公司合作的经验,我通过做一个主要修改,将它用于构思人工智能用例:当参与者投票决定要关注的挑战时,主持人将过滤掉非人工智能用例。此外,研讨会的第一部分将以'寻找灵感结束,而不是最初设计冲刺中描述的'目标映射

个案研究

理解改进的构思过程如何工作的最好方法是通过案例研究。下面的案例研究来自我主持的一次实际会议;出于保密目的,公司名称和敏感信息已被掩盖。

客户背景

更好的大脑是一所高等学府。他们的首席执行官对在他们的组织中使用人工智能感兴趣。然而,首席执行官不确定从哪里开始。他决定让 AISG 为他的团队主持一个构思研讨会。

步骤 0:准备工作

主持人将与项目发起人或参加研讨会的最高级别人员讨论,以确定研讨会的合适主题。这为探索设置了一个软边界,将讨论保持在一个限定的空间内。

主持人还将建议谁应该参加研讨会。最好是来自与研讨会主题相关的不同部门/职能的 4-7 名参与者。

BETTER BRAIN 的首席执行官决定召集营销、IT 和项目部门的员工参加研讨会。他还决定了主题:改善学习者的体验和成果。

第一步:参与者分享挑战,并将挑战转化为“我们可以怎样做”(HMW)

每个参与者轮流分享他们的业务挑战。包括主持人在内的其余参与者将把共同面临的挑战转化为机会领域。这些问题将以“我们如何……”(HMW)的格式编写。

目的是产生潜在的想法来解决共同的业务挑战。由于每个参与者都有不同的视角,因此对于相同的业务挑战,会产生不同的想法。参与者之间没有讨论,以尽量减少集体思维,防止外向者主导讨论。

“我们使用‘我们会怎样’的格式,因为它暗示一个解决方案是可能的,并且因为它们给你提供了以各种方式回答它们的机会。一个恰当的框架“我们如何可能”并不建议一个特定的解决方案,而是给你一个创新思维的完美框架。”—视频

在下面的例子中,在 BETTER BRAIN 的项目经理分享了她的商业挑战后,其余的人将其转换为 HMW 格式的问题:

参与者将共享的业务挑战转换为 HMW 格式。图片作者。

第二步:对挑战进行分类和投票

辅导员和参与者将确定整个 HMW 的共同主题,并相应地对其进行分类。然后,每位参与者都有两次投票来决定哪些挑战值得挑战。参与者之间没有讨论。

对质疑进行分类是为了便于投票;挑战投票旨在确定团队想要应对的重要且相关的挑战。

下图显示了为“更聪明的大脑”投票的结果:

HMW 根据相似性进行分类,并投票决定相关的 AI 用例。图片作者。

步骤 3:过滤挑战

少于两票的挑战被移除。主持人还将消除与人工智能无关的挑战,并向参与者解释为什么它们与人工智能无关;这是对原工艺的修改之一。

在这一步之后,所有剩下的用例都是人工智能解决方案开发的潜在候选对象。

少于两票的 HMW 和与 AI 无关的 HMW 被删除。图片作者。

第四步:定义目标

每位参与者用“两年后,我们将… ”的格式写下一个目标。然后参与者投票决定哪个是值得追求的目标;每个人都有一票。

本练习的目的是让参与者从他们的角度设想,如果所有确定的挑战都得到解决,公司或业务部门将会是什么样子。

对于更好的大脑,参与者已经确定他们在两年内的主要目标是利用数据来指导学生选择合适的课程。

参与者确定潜在的两年目标,并投票决定相关目标。图片作者。

第五步:识别阻挡者

每个参与者将列出 2-3 个可能阻止他们实现最高投票目标的潜在障碍。应该以“我们能不能… ”的格式来编写阻止程序。然后,每位参与者有 3 次投票来选择与确定的目标最相关的阻碍因素。

目的是强调潜在的陷阱,这些陷阱可能会破坏人工智能项目或阻止团队实现他们的目标。这允许管理层先发制人地解决它们,以增加人工智能项目成功的可能性。

为了更好的大脑,参与者已经确定了可能阻止他们实现目标的三大障碍:

已识别和投票的阻止者列表。参与者列出潜在的屏蔽程序,并投票决定相关的屏蔽程序。图片作者。

第六步:寻找灵感

参与者有 15 分钟时间寻找 1-2 个灵感来解决类似的挑战,并记下每个灵感的关键想法。这些灵感不一定来自同一个行业。

当参与者到达这一部分时,他们会对潜在的解决方案有初步的想法。分享想法的挑战在于它们可能很难解释,人们对相同的抽象解释有不同的解释。

因此,本部分的目的是让参与者以具体的形式展示他们的想法,并分享他们想法的关键应用。

参与者共享的解决投票问题的潜在应用程序。图片作者。

总体结果

在规划过程结束时,参与者将获得以下信息:

  • 已确定的机会领域和潜在解决方案列表。
  • 参与者设想的人工智能用例将有助于实现的目标,以及可能破坏人工智能项目的潜在障碍。
  • 通过一系列投票环节,参与者就需要解决的关键问题达成一致。

管理层在决定他们应该开发哪些人工智能用例时,可以考虑这些输入。

工作坊结束时制作的艺术品。图片作者。

结论

确定可行且有影响力的人工智能用例具有挑战性。组织用来确定人工智能用例的常用方法不适合人工智能的模糊性和数据依赖性。AISG 将设计 Sprint 改编成一种结构化的、经过验证的方法,用于构思人工智能用例。

如果您希望了解更多信息,您可以致电 ai-advisory@aisingapore.orgT3 联系我们。

本文首发于 AI 新加坡 makers space。

一个 50 毫秒以下的神经搜索

原文:https://towardsdatascience.com/a-sub-50ms-neural-search-with-distilbert-and-weaviate-4857ae390154?source=collection_archive---------16-----------------------

如何使用 Transformers、DistilBERT 和 vector search engine Weaviate 构建一个快速且可投入生产的神经搜索

当利用现代 NLP 模型(如 BERT)的功能时,获得准确的结果通常不是最大的问题。以 UX 为中心的库已经出现,这使得使用 NLP 模型变得更加容易。最值得注意的是拥抱脸变形金刚使伯特和类似模型的实验和调整变得相当容易。

然而,将 Jupyter 笔记本的实验投入生产则是另一回事。主要的挑战是如此沉重的神经模型的速度以及在生产中操作它们,被称为 MLOps 。

在本教程中,我们将利用 vector search engine Weaviate 的能力来运行生产中的任何模型。Weaviate 还带有各种各样的内置模型,可以通过 Weaviate 的模块功能进行配置。这也包括对基于变压器的模型的支持。然而,对于本教程,我们决定在 Weaviate 之外进行所有的矢量化,以演示 Weaviate 如何用于任何模型。

高速和低延迟将是我们在本教程中将要构建的神经搜索的关键特征。由马修·施瓦茨在 Unsplash 上拍摄的照片

我们如何为这个实验选择技术

主要的技术选择包括:

  • 拥抱脸变形金刚
    变形金刚已经迅速成为与基于神经网络的 NLP 模型(如 BERT)一起工作的事实标准。PyTorch 和 Tensorflow 的深度集成提供了最大的灵活性和易用性。
  • DistilBERT
    本文的一个关键方面是在生产中实现高速度和极低的延迟。DistilBERT 的精度是普通 BERT 的 97%,同时重量更轻,速度快了大约 60%。这使得它成为一个伟大的选择。如果你想用不同的型号,你可以很容易地换成其他型号。
  • Weaviate 矢量搜索引擎 Weaviate 是一个实时矢量搜索引擎,它不仅在查询时非常快,而且适合生产使用。它内置于 Go 中,具有云原生思维。这使得它既可靠又容易在 Kubernetes 和类似的容器编排器上运行。还有一个 python 客户端可用,它将使我们的变形金刚代码和 Weaviate 之间的连接变得容易。在引擎盖下,Weaviate 使用了一个 HNSW index 的变体,该变体被定制为提供您期望从适当的数据库中获得的所有特性。

我应该用 CPU 还是 GPU 来运行这个?

基于神经网络的模型在 GPU 上往往比在 CPU 上快得多,然而,当需要 GPU 时,进入的障碍更高。幸运的是,下面的所有代码在没有 GPU 的情况下也能工作。我们将强调在 CPU 和 GPU 上运行时需要做最小改动的地方。Weaviate 本身不需要任何 GPU,因为它在 CPU 上运行得相当快。使用 CUDA 支持的 CPU 可以极大地提高 BERT 和 BERT 衍生转换器的性能,这也是我们在本例中选择使用 GPU 的原因。

我从哪里得到一个 GPU?

如果你想在 GPU 支持下运行,至少有两个方便的选择:

  1. 您可能已经在使用配有 CUDA 兼容 GPU 的计算机。
  2. 你可以在云中旋转一个。对于这个例子,我们使用的是 Google Cloud 上可用的最小也是最便宜的 GPU 一辆英伟达特斯拉 T4。在我写这篇文章的时候每月花费大约 180 美元。我们甚至不需要超过一个小时,使成本可以忽略不计。

我们的路线图:我们将建设什么?

在本教程中,我们将介绍以下步骤:

  1. 首先,我们将使用 docker-compose 在本地启动 Weaviate Vector 搜索引擎
  2. 我们将下载并预处理一个免费的基于文本的数据集。如果您愿意,也可以用自己的数据替换数据集中的数据。
  3. 然后我们将使用转换器和 DistilBERT 将我们的文本编码成矢量。您可以轻松地切换到您选择的另一个基于 transformer 的模型。
  4. 我们现在可以将文本对象和它们的向量导入到 Weaviate 中。Weaviate 将自动建立一个矢量索引和一个倒排索引,使各种搜索查询成为可能。
  5. 最后,我们将再次使用 DistilBERT 模型对搜索查询进行矢量化,然后使用这个执行矢量搜索。

先决条件

对于本教程,您需要:

  • bash 兼容的 shell
  • python >= 3.8 & pip 已安装
  • Docker 和 Docker Compose 已安装

可选择的

  • 与 CUDA 兼容的 GPU,为您的操作系统安装了相应的驱动程序

步骤 1-旋转 Weaviate

在本地运行 Weaviate 最简单的方法是下载一个 docker-compose 示例文件。如果您愿意,您可以调整配置,但是对于本教程,我们将保留所有默认设置:

要下载 docker-compose 文件,请运行:

然后,您可以使用以下命令在后台启动它:

$ docker-compose up -d

Weaviate 现在应该正在运行,并在您的主机端口8080上公开。您可以使用docker ps进行验证,或者简单地向 Weaviate 发送一个测试查询,它应该会返回如下内容:

$ curl localhost:8080/v1/schema
# {"classes":[]}

它显示了一个空的模式,因为我们还没有导入任何东西。

您还可以查看文档,了解运行 Weaviate 的其他方式,如 Kubernetes、Google Cloud Marketplace 或 Weaviate cloud service。

步骤 2-下载示例数据集

对于本教程,我们选择使用 20 个新闻组数据集,这是一个通常用于 NLP 相关任务的数据集。

我们将创建一个名为data的文件夹,在其中下载并提取数据集:

请注意,我们将不得不做一些预处理,例如删除每个文件的标题,这样我们只剩下帖子本身。我们将在接下来编写的 python 脚本中实现这一点。

步骤 3-安装 python 依赖项

我们将需要torchtransformers用于 BERT 模型,需要nltk用于标记化,需要weaviate-client将所有东西导入 Weaviate。

$ pip3 install torch transformers nltk weaviate-client

步骤 4 —开始构建我们的 python 脚本

我们现在将构建我们的 python 脚本,它将加载和预处理我们的数据,将我们的数据编码为向量,将它们导入到 Weaviate 中,最后用 Weaviate 运行向量搜索。

下面的代码片段被分成了更小的块,以便于阅读和解释,你也可以在这里下载完整的 python 脚本。

初始化一切

首先,让我们初始化我们将要使用的所有库。请注意,如果您没有运行 GPU 支持,您必须删除行model.to('cuda')

加载和预处理数据集

接下来,我们将构建两个助手函数来从磁盘读取数据集。第一个函数将得到一个随机选择的文件名。第二个函数读取这些文件名并做一些简单的预处理。我们将通过识别两个换行符的第一次出现来从 newgroup 帖子中去除标题。此外,我们将用常规空格替换所有换行符和制表符。然后,我们跳过每个少于 10 个单词的帖子,以删除非常嘈杂的帖子。最后,我们将截断所有帖子,最多不超过 1000 个字符。您可以随意调整这些参数。

使用蒸馏模型进行矢量化

接下来,我们构建另外两个助手函数,它们用于对我们之前从数据集中读取的帖子进行矢量化。注意,我们将text2vec流程提取到一个单独的函数中。这意味着我们可以在查询时重用它。

注意,如果你运行时没有 GPU 支持,你必须删除线tokens_pt.to('cuda')

初始化弱模式

Weaviate 有一个非常简单的模式模型。对于您创建的每个类,Weaviate 将在内部创建一个向量索引。类可以有属性。对于我们的Post类,类型为text的单个属性content就足够了。注意,我们还明确地告诉 Weaviate 使用none矢量器,这意味着 Weaviate 本身不会对任何东西进行矢量化——我们提供了用上面的 DistilBERT 创建的矢量。

将我们的数据导入 Weaviate

我们现在可以将所有数据导入到 Weviate 中。注意,对于每篇 20 条新闻的文章,我们将导入文本和向量。这将使我们的结果非常容易阅读,甚至允许混合基于文本和基于矢量的搜索。

我们可以使用 Weaviate 的批量导入特性,该特性将利用内部并行化来加速导入过程。根据您的资源选择批量大小,我们的测试 VM 应该能够轻松地一次处理 256 个对象。

用 DistilBERT 对搜索词进行矢量化,用 Weaviate 进行矢量搜索

我们现在可以重用上面定义的text2vec函数来矢量化我们的搜索查询。一旦我们从 DistilBERT 获得了向量,我们就可以使用客户端的with_near_vector方法将它传递给 Weaviate 的nearVector API。

让我们也测量一下需要多长时间,因为速度是这篇文章的主要动机之一。

全部运行

终于到了运行我们所有方法的时候了。让我们首先初始化模式,读取并矢量化一些帖子,然后将它们导入 Weaviate。如果你在没有 GPU 支持的情况下运行,减少帖子的数量可能是有意义的。

您应该会看到如下内容:

So far 100 objects vectorized in 2.073981523513794s
So far 200 objects vectorized in 4.021450519561768s
So far 300 objects vectorized in 6.142252206802368s
...
So far 3800 objects vectorized in 79.79721140861511s
So far 3900 objects vectorized in 81.93943810462952s
Vectorized 3969 items in 83.24402093887329s

现在让我们执行一些搜索:

它应该打印类似于以下内容的内容:

Query "the best camera lens" with 1 results took 0.018s (0.008s to vectorize and 0.010s to search)
0.8837:    Nikon L35 Af camera. 35/2.8 lens and camera case. Package $50  Send e-mail
---Query "which software do i need to view jpeg files" with 1 results took 0.022s (0.007s to vectorize and 0.015s to search)
0.9486:   How do I view .eps files on X? I have an image in color encapsulated postscript, and need to view it on my screen.  Are there any utilities that will let me convert between encapsulated postscript and plain postscript?  Joseph Sirosh
---Query "windows vs mac" with 1 results took 0.019s (0.007s to vectorize and 0.011s to search)
0.8491:   Appsoft Image is available for NeXTStep. It is a image processing program similar to Adobe Photoshop. It is reviewed in the April '93 issue of Publish! Magazine.   Richardt

请注意,这三个响应时间都低于 25 毫秒,我们成功实现了 50%的延迟目标!

请随意尝试不同的查询和限制。如果有些帖子的内容看起来有点过时,不要感到惊讶,20 个新闻组数据集确实很老了。当时肯定没有 iPhone,但有大量的麦金塔内容。

有更简单的方法吗?

上面练习的一个要点是表明 Weaviate 与任何 ML 模型都是兼容的,只要它能产生向量。结果,我们不得不自己采取一些措施。幸运的是,Weaviate 带有可选模块,可以帮助您对数据进行矢量化。例如,[text2vec-contextionary](https://www.semi.technology/developers/weaviate/current/modules/text2vec-contextionary.html)模块可以在导入时使用基于 fasttext 的算法对所有数据进行矢量化。如果你想使用伯特和朋友,看看即将发布的text2vec-transformers模块。

一个回顾和从这里去哪里。

我们已经证明,我们可以将 Weaviate、Hugging Face Transformers 和(提取)BERT 结合起来,产生一种生产质量的神经搜索,它能够在大约 25 毫秒内搜索数千个对象。对于这个演示来说,这是一个很好的例子,但是在实际应用中,您的数据集可能要大得多。幸运的是,Weaviate 的扩展性非常好,甚至可以在 50 毫秒内搜索数百万甚至数十亿个对象。要了解 Weaviate 如何处理大规模矢量搜索,请阅读Weaviate内部如何利用 HNSW。

一套用于电子商务推荐、个性化和产品分类的基本数据产品

原文:https://towardsdatascience.com/a-suite-of-essential-data-products-for-e-commerce-recommendations-personalisation-and-product-316b9d75f99e?source=collection_archive---------21-----------------------

弗兰基·查马基在 Unsplash 上拍摄的照片

理解大数据

内容列表

介绍

Word2Vec 到 Product2Vec —产品嵌入生成器

产品一:相似商品推荐

产品 II:产品分类扩展器

产品三:基于内容的高级相似项目推荐器

产品四:个性化商品推荐

产品 V:列表类别修正器

产品六:用户兴趣分类器

结论—总体情况

介绍

这是一个关于我们如何为电子商务*台开发包含 6 种不同解决方案的数据科学产品捆绑包的故事。(在我们的例子中是一个市场)这个故事的本质是,捆绑包中的所有这些产品都来自一个单一来源,这是一个产品数字代表列表,或者更通俗地称为“产品嵌入”。这些产品被开发成一个链条,从一个产品结果到另一个产品结果。最终产品套件可以被视为一个与推荐、个性化和产品分类相关的电子商务综合解决方案。

就个人而言,我最喜欢这个项目的是,一旦你有了代表性的产品数值向量,你就可以为你的业务提供所有 6 种不同的数据产品。因此,这里最重要的事情是提出一种健壮的方法来生成位于所有产品核心的高质量产品嵌入。因此,本文将首先描述我们创建嵌入的方式。

在深入这个多层项目的细节之前,让我提醒您注意一个简单而微妙的事实:数据科学家对业务/产品透彻理解的重要性。正如您将在本文的其余部分看到的,我们在整个项目中开发的每个产品都从不同的方面解决了我们的业务问题。因此,将特定的业务问题与适当的数据解决方案相匹配必须是数据科学家的关键素质之一,这需要良好的产品知识水*。

从技术角度来看,数据科学家还必须能够转换现有的机器学习算法,以适应自己的业务问题。在下一节中,我们将给出一个例子,并讨论我们如何将最著名的 NLP(自然语言处理)算法之一-“word 2 vec”-转换为一个“产品嵌入生成器”

重要提示:在整篇文章中,“产品”、“项目”和“列表”这些词将交替使用。

WORD2VEC 到 PRODUCT2VEC —产品嵌入生成器

Word2Vec 是一种众所周知的利用单层神经网络的 NLP 方法。它使用隐藏层的激活作为结果,而不是使用最终输出层的预测。这种方法背后的主要逻辑是在隐藏层上创建一个瓶颈,并将稀疏的 one-hot-encoded 输入单词向量转换为密集的低维数值向量。

为这种神经网络生成训练数据的方法是使用上下文窗口,在一组文档中的所有句子上滑动。上下文窗口是句子中连续单词的固定大小的分组。使用上下文窗口中的单词对组合,我们生成(x =输入单词,y =输出单词)标记的训练数据,然后将其馈送给网络。最终,共享相同上下文的单词会以相似的嵌入结束。例如,人们总是交替使用“荷兰”和“荷兰”这两个词。(有趣的事实:该国的官方名称是“荷兰”,代表所有 12 个省,“荷兰”是一个中部地区的名称,仅包含 2 个省,包括阿姆斯特丹市。)由于这两个词在许多文档中用相似的词包装或共享相似的上下文,所以它们也将从算法中获得相似的嵌入。深入讨论 Word2Vec 超出了本文的范围,但是有很多博客文章可以让您了解更多。

现在,让我们考虑一个电子商务*台来回答这个问题:电子商务业务中的基本单元是什么?首先,主要资产是我们的产品、用户以及这两者之间的互动。每个用户很可能在某个时间段在*台上有几个会话。这些会话由同一用户的大量连续产品视图组成。现在,退一步,尝试在 Word2Vec 和电子商务*台中的基本单元之间进行类比。

word 2 vec 和 Product2Vec 的类比(图片由作者提供)

如图,一个词和一个单一的产品观有一个类比。此外,由用户查看的产品序列组成的单个会话可以被解释为一个句子。包含所有会话的用户的整个旅程可以被视为一个文档。

借助这个类比,我们可以使用 Word2Vec 算法来生成我们的产品嵌入,就像它对 Word 的工作方式一样。我们将拥有产品的数字代表,而不是以单词嵌入结束。这就是为什么,为了命名惯例,将我们的产品嵌入生成器命名为‘product 2 vec’是有意义的。

现在,让我们花一点时间来思考产品嵌入维度中的这些价值代表了什么。Product2Vec 仅基于用户点击/查看数据,它隐式地对产品属性进行编码。换句话说,在创建嵌入时,我们不使用任何明确的产品质量、属性或特征。因此,我们无法将每个维度与特定的产品属性相匹配,但您可以将每个维度视为随机属性,如颜色、尺寸、位置或卖家信任分数等。

我们不得不使用这种方法来生成代表性特征向量的原因是,我们*台上的列表没有很多明确的产品属性或标签。我相信这是绝大多数电子商务*台的共同问题,但特别是市场*台遭受产品信息不足的问题,因为它们的内容完全依赖于用户。然而,如果你的*台上的每一件商品都有许多清晰的描述性产品标签,我强烈建议你使用这些明确的产品标签来生成产品嵌入。

在结束这一部分之前,我想提一下我们在嵌入过程中采取的两个技术决策。第一个决定是关于创建我们的训练数据的不同方法。请记住,我们将每个用户会话视为一个句子,并相应地生成(输入单词-输出单词)对。(注意:会话是一系列产品视图,任何后续视图之间的间隔不超过 30 分钟。)我们还尝试通过滑动用户的整个旅程——所有会话的组合,来创建训练数据对。事实证明,在我们的案例中,后者给了我们更高质量的产品嵌入。这是一个依赖于问题的设计决策,需要由项目开发人员进行调整。

我们做的第二个决定是关于嵌入的最佳尺寸。正如您将在以下部分看到的,不同的产品需要不同的嵌入大小。对于推荐者,我们使用 64 维产品嵌入,对于聚类分析涉及的其他产品,我们使用 16 维嵌入,以避免遭受维数灾难。因此,值得注意的是,您还需要根据您的问题来调整嵌入大小。

本文的主要目的是向您介绍 6 种不同产品的开发过程,并向您展示产品嵌入是如何为这些产品铺*道路的。我不会在这里深入讨论 Product2Vec 的更多技术细节,但是如果你感兴趣,你可以阅读我之前的关于它的博客文章。在本文的其余部分,产品将按照我们想出它们各自想法的完全相同的顺序呈现给你。通过这种方式,我们旨在传达整个项目中所有产品的实时开发链。

产品一:相似商品推荐

相似商品推荐器是最受欢迎的推荐器类型之一,被许多电子商务*台广泛使用。它对 CTR(点击率)和 CR(转化率)的强大影响使其成为所有产品中最具吸引力的数据科学产品。常见的用例是通过给产品页面命名为“推荐的相似产品”或“相似”,在推荐转盘中向用户展示相似的产品。

现在,让我们快速浏览一下下面的“流程—构建模块”图表。您将看到所有后续产品的类似图表,因此现在有必要花点时间来定义这些单独的模块。最上面一行表示带有一些构建模块和中间数据集的高级产品流。构建模块将显示为黑色椭圆形,我们将在相应产品部分下的单独小节中简要讨论每个构建模块的详细信息。这些构建模块可以是现有的算法,也可以是我们为特定任务创建的函数。

在流程中,这些灰色矩形代表输入或中间数据集。我们放大的最后一个彩色块显示了每个产品的最终结果。正如你在图表中看到的,为了便于理解,我们用一组小的彩色编码方块来表示嵌入。在本例中,直观地看,奥迪汽车列表具有相似的颜色嵌入,而福特汽车的嵌入与奥迪不同,但彼此相似。

产品一—流程图(图片由作者提供)

构建模块:HNSW

一旦我们有了代表产品内在质量和属性的嵌入,为了提出对特定产品的类似商品推荐,您应该做的就是使用距离度量在嵌入空间中找到最*的产品。如果您的问题中没有很多产品,那么使用强力 k-最*邻算法来寻找最*的嵌入是最好的办法。然而,由于我们讨论的是数以百万计的产品,强力算法——将单个商品与所有其他商品进行比较——对我们来说不是一个合适和及时的选择。相反,我们使用了一种“*似最*邻”算法:HNSW。如果你只有 10 秒钟,你需要知道这些算法是如何工作的,就是在空间中画一组线(这些线的数量是你可以设置的参数),然后通过比较空间中两个点在每条线的同一侧停留的时间来决定它们有多*。换句话说,它假设如果空间中的点或向量彼此靠*,它们将倾向于停留在与所画的线相对的同一侧。这种方法使这个过程比它的暴力版本快得多,因为不是将一个点与其余的点进行比较,而是只与行数进行比较。你可以在下面看到*似最*邻的简化解释。

简化的*似最*邻(图片由作者提供)

对于每个产品,只需使用 HNSW 找到前 N 个最接*的嵌入,并将它们作为推荐产品保存在一个表中。正如上面的产品 I 流程图中所总结的,您现在有了类似的商品推荐器。最终结果就像一个只有两列的表格一样简单,其中一列是我们正在生成推荐的产品 id,第二列是相似产品 id 的列表。

在开始展示之前,我想提一下我们在项目的这个阶段做出的一个技术决定。由于 HNSW 只是返回输入产品嵌入的类似项目,我们有机会看到由 Product2Vec 生成的那些产品嵌入的质量。在这个过程中,我们意识到,被用户浏览几次的产品不会获得高质量的嵌入,因此,HNSW 会返回相关的类似商品推荐。换句话说,这些产品之前不会被点击很多次,因为可能有各种原因,例如它们可能是新发布的新鲜列表或只是*台上不受欢迎的列表。那些以非代表性嵌入结束的原因是 Word2Vec 算法在设计上对罕见单词的较差性能。

在算法中有一个名为“最小词频”的特定参数,以防止为那些罕见的词生成嵌入。您可以将该参数设置为某个值,算法将忽略那些在整个语料库中出现次数少于您设置的值的单词(或我们示例中的产品)。在我们的例子中,我们将这个参数设置为 10,基本上是告诉算法不要去理会以前浏览次数少于这个数字的产品。当然,这也是一个应该由开发人员调整的特定问题参数。正如你现在所看到的,这个产品只为以前浏览过至少 10 次的“热门”列表生成推荐。其余的呢?继续阅读这篇文章,你会在产品 III 部分看到一个专门为新鲜、新的或不受欢迎的产品开发的解决方案。

展示区

在评估产品的性能和推荐的质量时,我们首先随机选择一个产品 id 作为种子项目,然后为它获取类似的产品。我们将种子的产品页面和推荐项目放在一张图片中,以帮助我们直观地评估它。如下图所示,您将在左上角看到种子产品,在右手边看到其前 4 名推荐的类似产品。

产品一——展柜(来源:【www.marktplaats.com】T4)

种子广告是一个居住在哈勒姆的用户发布的吸尘器,其价格为 100 欧元。从广告的标题,我们确实看到它的品牌是戴森。现在,让我们检查一下那些被推荐的项目。正如你所看到的,所有的推荐都是 Dyson 真空吸尘器,贴在哈勒姆附*的各个地方,价格在 75 到 150 欧元之间。值得称赞的是,这种方法很好地捕捉了产品的不同品质,如位置、价格或品牌,尽管根本没有使用任何一个明确的产品属性。同样,这一切都是基于用户点击行为数据。

产品 II:产品分类扩展器

在产品 I 之后,我们再次将焦点转移回产品嵌入。我们开始思考如何以其他不同的方式利用它们。这是因为我们相信在这些嵌入中隐藏着许多潜力。这种想法让我们想到了我们的第二个产品,即产品分类扩展器。

由于市场*台的内容完全依赖于用户,产品分类可能会变得具有挑战性,很容易脱离我们的控制,因为我们的库存是如此动态,并由我们的用户管理。实际上,这是市场和纯电子商务*台的主要区别。在电子商务*台上,所有产品都由单独的库存或分类团队列出,他们相对容易控制这些产品类别的名称。然而,如果你正在经营一家市场企业,你很可能在某个时候需要自动化产品分类。我们的业务需要这样一个自动化系统的原因是为了动态地发现*台上存在的更具体的产品类型,以便组织所有可用的列表,使客户能够以最少的点击次数找到他们想要的东西。

在这个产品中,流程从嵌入开始,然后是两个不同的构建块:K-Means 和定义集群。让我们在接下来的两节中更深入地研究它们。

产品二——流程图(图片由作者提供)

构建模块 I: K-Means

在第一步中,我们在嵌入的基础上使用 k-means 聚类算法将相似的产品聚集到同一个产品组中。我们已经在市场上列出了一些现有类别,如洗碗机或冰箱,但数量不多,也不够详细。因此,一旦我们将聚类数参数(K)设置为某个任意数,最好大于当前类别的总数,这将使我们能够在我们的*台上结束更具体且更详细的产品类型组,如台面洗碗机或葡萄酒冰箱。

为了便于理解,让我们继续使用前面提到的产品 II 流程图中的汽车示例。由于这种聚类,奥迪汽车将被收集到同一个聚类中,而菲亚特汽车将聚集在另一个单独的聚类中。当然,这些集群不会只由奥迪或菲亚特汽车组成。你可能会看到来自同一细分市场的其他品牌。例如,奥迪集群中可能有一些宝马汽车,而菲亚特集群中可能有一些福特或大众汽车。这是完全正常的,对我们的解决方案来说没有问题,只要我们的聚类算法像预期的那样将相似的产品分组在一起。这只是一个假设的例子,以便向您阐明我们的观点,但实际上,您可能希望将分类数设置得更高,这样,即使不同类型的特定汽车品牌也将归入单独的分类,如菲亚特 500 Lounge Manual 或黑色菲亚特 500 Sport。根据集群的数量(参数 K),我们有机会调整这些产品集群的细化程度,并相应地选择最佳参数值。

在我们的例子中,我们如何找到最佳 K 值?首先,我们在一个主要类别——白色家电和设备——上测试了这款产品,该类别包括大约 40 个不同的子类别,如洗衣机或炉灶。因此,我们希望将 K 设置为大于 40,因为我们的主要目标是扩展当前类别并发现更详细的类别。在寻找最佳 k 值时,你可以将现有类别的数量作为你的下限,那么上限呢?在这里,集群的大小开始发挥作用。我们可以将这个数字 K 增加到某一点,这样那些产品簇仍然足够大,可以被称为类别。我们从 40 开始逐渐增加 K 的值,并找到 100 左右的最佳值,最终得到最有意义的产品组。底线是这个数字 K 需要根据问题和*台进行特别的调整。

构建模块 II:定义集群

将我们的产品分成几个子类别后,下一步是找出这些新产品类别的良好描述,以便给它们命名。这个构建块可以做到这一点,逻辑很简单:对于每个集群,我们取所有集群成员产品的标题,然后计算词频分布,并列出最常用的词及其各自的百分比。由于在市场中,商品的标题对于吸引更多的买家非常重要,因此大多数商品的标题都已经被卖家写得非常清楚和详细,例如“移动冷藏箱——服务柜——带轮子的冰箱。因此,这有助于我们在分析列表标题时,为每一个产品群找到好的描述性词语。

如产品 II-流程图所示,该构建模块的输出也是产品的最终结果,该产品是一个具有两列的表格:产品聚类数和热门词分布。关于该表的一个重要注意事项是,尽管它如此简单易用,但我们仍然需要对结果进行人工解释,以便对新发现的产品类别进行花哨和高质量的命名。这也是同样的程序,它是如何做的网飞 Tagger 团队想出电影类型,如黑暗斯堪的纳维亚电影。

展柜

在下面的图片中,您将看到来自总共 100 多个产品集群中的 2 个不同集群的一些示例。在第一行中,所有这些产品都来自一个名为“闹钟”(荷兰语为“wekkers”)的类别,正如您从顶部的面包屑中看到的那样。然而,在这些产品中有一些独特和共同的东西。这些不仅仅是闹钟,还是一盏唤醒灯,所有人的品牌都是飞利浦。这一产品群的前四个词是“飞利浦唤醒灯”,这对于这一特定产品群来说已经是不言自明的了。在第二行中,所有这些产品都属于相同的现有类别“个人护理设备”,但看起来它们实际上是一种特定类型的产品,即“足浴”(荷兰语为 Voetenbad)。不出所料,“Voetenbad”一词的使用率比该产品群中的任何其他词都要高。

产品二——展示区(来源:【www.marktplaats.com】T2)

该产品在我们的市场上主要有两个明确的使用案例。在第一种情况下,我们可以将这些产品组作为新的二级类别,列在一级 主类别页面 上。(注意,在第二个用例中,1 级类别是白色家电和设备)在结果的帮助下,我们可以通过添加更多的产品类型过滤器来改进我们的 优化搜索结果 组件。你可以在我们的市场*台上看到下面的页面,在那里我们可以使用该产品的最终结果

产品二—使用案例(来源:www.marktplaats.com)

产品三:基于内容的高级相似项目推荐器

请记住,在产品 I 中,我们跳过了为用户仅浏览几次的广告生成推荐。这些产品中的绝大多数都是新发布在*台上的新鲜商品。在推荐空间,我们对这种情况有一个专门的称呼:冷启动问题。在这里,我们有机会处理这个问题,并且能够为这些列表生成推荐。

在这个产品中,我们利用了前一个产品的结果,即带有描述性顶词的产品簇。如上面的流程图所示,我们只是在这个结果和新发布的列表标题的数据集合之间添加了一个新的构建块——加权 Jaccard 距离。

产品三——流程图(图片由作者提供)

构建块:加权 Jaccard 距离

该函数将每个新发布的列表的标题与每个产品分类的描述性单词列表进行比较。为了决定哪个产品群最适合某个新发布的列表,我们使用 Jaccard 距离(相似性)和一点权重技巧。Jaccard 距离是两个句子之间的常用词数量与总联合集中的词数量的比率。

雅克卡距离/相似度(来源:维基百科)

我们在计算分子时使用了一点权重技巧,分子是一个列表的标题和一个产品群的描述性词语的交集。如果与描述性单词列表顶部的单词匹配,它会给出更多的权重。您可以看到,这是一个直观的、更强有力的指示,表明了列表和产品集群之间的相似性,如下面的简单示例所示。

重量戏法(图片由作者提供)

一旦一个列表以我们上面描述的方式与每个产品群进行了比较,这个构建块就将每个列表分配给一个特定的最适合的产品群。之后,它通过从指定的产品群中随机挑选一些商品,为每个列表生成相似的商品推荐。

该构建模块的输出也是该产品的最终结果,其格式与我们为产品 I 中的“热门”列表创建的最终表格完全相同。换句话说,通过产品 I 和该产品的组合,我们现在可以为我们*台上的所有库存提供类似的商品建议。

还有一件事我故意跳过了,但在这里值得一提。在我们的案例中,总共有大约 100 个产品集群。当通过计算加权 jaccard 距离将新列表与那些聚类进行比较时,它可能与几个不同的聚类具有一些*局分数。为了打破这些束缚,最终只分配一个产品群,我们还将地区和列表价格与这些产品群的地区分布和中间价格进行比较。您可以将此视为推动集群分配过程的最后一小步。

这种方法相对于冷启动问题的其他解决方案的最大优势是基于用户行为数据,而不仅仅是一对一的属性比较。我们将每个列表与一组产品进行比较,这些产品实际上是用户点击行为分析的结果。与仅基于属性比较的一对一方法相比,这可以被视为更健壮的一对多方法。

展柜

该展示与我们在产品 I 中看到的非常相似。我们用一个新发布的列表作为种子输入,并获得前 4 名推荐的类似商品作为回报。正如你从上面的图片中看到的,我们正在寻找类似项目的种子列表是一个机器人吸尘器。在右侧,您会看到这一特定产品类型的相关建议。其中三个是不同的机器人真空吸尘器列表,其中一个是机器人真空吸尘器的特殊过滤器。实际上,最后一个过滤器建议总结了我们的方法及其相对于其他方法的优势。

产品三——展示区(来源:【www.marktplaats.com】T2)

由于这些建议来自指定的特定产品群,因此可以看到不同的产品类型,但在某种程度上都是相关的。这使我们能够为某个列表增加相似项目推荐的多样性。除此之外,让我们快速看一下上图中右上方的清单。在那个和种子列表之间没有共同的单词或属性共享。如果使用了一对一的属性比较方法,那么就没有办法得出这样的建议。总的来说,我们可以说这个新发布的列表的推荐器可以正确地捕获产品类型,然后相应地生成相关的推荐。

产品四:个性化商品推荐

在项目的这个阶段,我们开始考虑如何为用户提供个性化的产品推荐。该产品的主要目标是根据用户最*在*台上的浏览行为,向用户展示最相关的产品推荐。

请记住,在产品 I 作为热门广告推荐器和产品 III 作为新发布的新鲜广告推荐器的帮助下,现在我们能够为我们*台上的所有商品提供类似的商品推荐。因此,我们所要做的就是在用户查看的最后列表和产品 I 和产品 III 的结果组合之间放置一个新的构建块——“加权随机选择”。你可以在下面的流程图中清楚地看到这些联系。

产品四——流程图(图片由作者提供)

构建模块:加权随机选择

该函数将用户查看的最后 10 个列表作为输入,并且对于该输入中的每个列表,从先前开发的推荐器中检索前 5 个相似的项目推荐。正如你所想象的,最终会有一个由 50 个列表组成的推荐池。这最后 10 个列表和前 5 个推荐数字是任意的,但是决定了最终推荐候选人池的大小。换句话说,你应该根据你想给用户的最终推荐增加多少种类来设置这些数字。

该构件的下一步是根据它们各自的种子广告的新*性和它们在推荐的相似项目列表中的顺序,给池中的所有列表赋予不同的权重。它以这样的方式分配权重,即用户观看的最后一个列表的顶部推荐项目将具有最高的权重,并且类似地,用户观看的最后 10 个列表的第 5 个推荐项目将具有最低的权重。下图描述了这一过程。

对推荐池中的候选人进行加权(图片由作者提供)

在加权步骤之后,最后要做的是根据给定的权重从推荐池中随机选择。那些选中的列表将作为个性化推荐提供给我们的用户。从上面的产品 IV 流程图中可以看出,最终的结果是一个只有两列的表:用户 Id 和推荐的产品 Id。

在展示步骤之前,我想强调一下为什么我们想采用像加权随机选择这样的方法。主要原因是,就个性化产品推荐而言,提供各种不同的推荐产品非常重要。你应该给不同的产品一个被挑选出来推荐的机会,而不是坚持只推荐一种产品或者一遍又一遍地推荐同样的产品。通过这种方式,你也可以在许多不同的产品中公*地分配用户流量。

展柜

在下图的上方,你会看到一个用户最*的观看序列。我们列出了用户查看的最后 10 个项目,从最早的到最*的。正如你所看到的,这些列表中的大多数都是机器人吸尘器,尤其是包括最*访问过的那些。还有一些不同产品类型的列表,如移动空调(1、3 和 7)和分体空调(5)。

产品四——展示区(来源:www.marktplaats.com)

现在,看一下最下面一行,其中显示了为该特定用户生成的前四个推荐。正如所料,推荐的清单中有两个是机器人吸尘器。这是因为用户查看的大多数和最*的最后列表是真空吸尘器。因此,首先显示更多来自该产品类型的推荐相似项目是有意义的。在第二个和第四个推荐中,你会看到一些来自不同产品类型的列表,就像你之前在用户最*查看的项目序列中看到的一样。这是用户推荐中良好多样性的重要标志。

产品 V:列表类别修正器

在市场*台中,由于内容完全依赖于用户,*台上可能有许多错误分类的列表。这里值得一提的原因是为了深入理解业务问题。首先,用户总是有可能无意中从类别列表中为他们的项目选择了错误的类别。另一个原因可能是没有找到他们正在寻找的特定类别,不得不将他们的项目放在他们找到的下一个最佳类别下。这只是问题的一个方面,这些实际上是我们*台上大多数错误分类的主要原因。

然而,这个问题还有另一个更有害的方面,它与用户的免费增值使用剥削和欺诈行为有关。例如,如果你有 2 台冰箱要在我们的*台上出售,你有权在冰箱类别下免费发布其中一台,但你必须支付发布费才能将第二台冰箱列在同一类别下。因此,一些用户故意喜欢将这些列表放在一些其他不相关的类别下,如洗碗机,以避免支付任何费用。

这种情况对我们的*台有两个有害的影响。首先,它导致企业亏损,更糟糕的是,它将市场*台变成了一个产品大杂烩,用户很难找到他们想要的东西。

对于这个问题的解决方案,我们将回到我们之前生成的产品集群。一些产品集群可能由不同的产品类型组成,但大多数集群倾向于更加同质。在这些同类群中,大多数列表属于同一产品类别。其中只有少数产品发布在其他类别下,但与其他产品归为同一类,因为我们的模型认为这些产品也是相似的。在这种情况下,我们将这一小群产品命名为通常的嫌疑产品。下一节,我们来详细说说这个积木。

产品 V —流程图(图片由作者提供)

构建模块:常见的嫌疑人

这个构建块首先在这些集群的列表中找到最常见的产品类别。现在,让我们称之为主导集群类别。然后,将每个集群成员列表的实际类别与同一集群的主导类别进行比较。如果两者之间存在不匹配,我们将该集群成员标记为通常的可疑成员。我们的模型认为,那些通常的嫌疑人可能被错误地分类,因此他们落入主导产品类别不同于他们自己的产品类别的集群中。很可能他们的正确类别应该是集群的主导类别。因此,模型为这些列名提议的新类别是其各自集群的主导类别。

让我们看看上面产品 V 流程图中的汽车示例。顶部的产品集群主要由奥迪汽车组成,底部的另一个集群以菲亚特品牌为主导产品类别。从图中可以看出,奥迪集群中有一个宝马,菲亚特集群中有一个福特和大众。这些列表有点像其他集群成员中的离群值。因此,我们的模型怀疑宝马上市可能是一辆奥迪汽车事实上。同样,我们的模型也怀疑这些福特和大众上市可能是菲亚特汽车。

最终的结果集就像一个总共只有三列的表一样简单:Listing Id—Current Category—Proposed Category。这是一个动态表,定期更新,并及时捕捉越来越多的错误分类列表。然而,仍然需要人力来验证最终的结果集。这是因为在那些通常的嫌疑人中可能有一些假阳性。换句话说,我们的模型仍然有可能怀疑一个列表,即使它发布在正确的类别下。这种情况有一个直观简单的解释。

记住,聚类算法将相似的列表分组到同一个聚类中,并且有可能那些通常的嫌疑可能是来自其他不同类别的相似列表,并且不一定被错误地分类。事实证明,如果一个聚类的纯度很高(占主导地位的类别的比率),那么那些通常的嫌疑人就更有可能在现实中被错误地分类。因此,您可以通过调整主要产品类别比率的阈值来更改最终结果集的准确性,同时选择我们将在其中寻找常见可疑点的分类。如果你提高这个阈值,你可能会得到更少的普通嫌疑人,但有更高的真实阳性率。下图描述了通常嫌疑人分析的阈值选择过程。

选择产品集群进行常规嫌疑人分析(图片由作者提供)

展柜

下图中。在许多被发现的错误分类的列表中,你只会看到 3 个例子。我们在发布的列表的实际类别上画了一个矩形。在底部,您会看到每个列表的推荐或提议的正确类别。由于这些截图来自我们的荷兰*台,所有标题和类别都是荷兰语。让我来帮你把这些翻译成英语。如你所见,在最左边,是一个迷你冰箱列表,但贴在“风扇和空调”类别下。我们的模型建议将冰箱作为正确的类别。在中间,这是一个雀巢 Dolce Gusto 咖啡机,列在 Taps 类别下,但我们的模型建议将其类别更改为正确的类别:咖啡机和浓缩咖啡机。在最右边的图片中,它是一个台钟,由卖家发布在其他白色家电类别下。事实上,我们有一个单独的类别,那就是闹钟。请注意,我们尝试了单一主要类别(L1 级别)的所有产品:白色家电和设备。因此,它在底部显示了推荐的 L2 类别,因为我们的目标是检测我们*台上 L2 级别的错误类别。

产品 V——展示区(来源:【www.marktplaats.com】T2)

产品六:用户兴趣分类器

在使用产品嵌入创建这些产品集群之后,我们认为也可以对我们的用户应用类似的集群。通过这种方式,我们将有机会根据用户最*在我们*台上的浏览历史,将相似的用户分组到相同的兴趣群中。该产品的主要目标是,如果我们有显示相似特征的用户群,那么我们将能够以更个性化的方式瞄准不同的用户群,从而进行更有效的营销。

使用本产品的结果,我们希望通过回答以下 3 个问题及时发现用户不断变化的兴趣:

  • Q1:用户目前对哪种具体的产品类型感兴趣?
  • Q2:这些用户更喜欢昂贵的物品还是更便宜的搜索者?
  • Q3:对于这些用户来说,列表位置是一个决定性因素吗?

首先要做的是找到一种生成用户嵌入的方法,这样我们才能进行下一步。构建模块——加权*均值——就是为此目的而添加到流程中的。现在,让我们看看下面的方法的细节。

产品六——流程图(图片由作者提供)

构建模块 I:加权*均值

在生成用户嵌入时,我们希望在第一个产品中利用以前创建的产品嵌入。我们在流程中放置一个构建块,只是为了将这些产品嵌入转换成新的用户嵌入。我们的方法非常简单明了,甚至连构造块的名字都透露了这一点。基本上,我们检索用户查看的最后 10 个列表,并以这样的方式对列表嵌入进行加权*均,即用户查看的列表越*,其嵌入在计算中得到的权重就越大。

在上面的产品 VI 流程图中,如果我们再次查看我们的汽车示例,由于用户往往对某些品牌或汽车类型更感兴趣,我们最终将获得展示用户在*台上的最新产品品味的用户嵌入。因此,如果两个用户最*访问了相似的项目,那么在这个过程结束时,他们将具有相似的嵌入。现在,是时候在用户嵌入的基础上应用聚类算法了。

构建模块二:K-Means

这个构建模块的工作方式与产品 II 中的 K-Means 完全相同。这次我们对用户嵌入应用了聚类。这基本上是这两个构建模块的唯一区别。因此,我不会在这里再深究细节。这个构建块的结果是一组用户群,它们作为输入被传递给下一个构建块。

构建模块三:定义集群

该构造块的工作方式与产品 II 中的定义集群构造块类似。请记住,我们在描述产品集群时只使用了热门词汇。这里,在生成用户群的描述性质量时,我们还考虑了地区和价格范围。

最后一个构建块的结果也是该产品返回的最终结果集。它是一个总共有 4 列的表:聚类 Id —热门词分布—地区分布—中间价格。

集群 Id: 代表用户集群的编号

热门词汇分布:这是特定集群的用户在最*查看的列表的标题中频繁使用的词汇的列表

地区分布:发布感兴趣物品的邮政编码列表

中间价格:集群用户所有感兴趣的列表的中间价格

展柜

在下面的图片中,您将看到 4 个不同用户群的例子。当我们成对比较时,这 4 个聚类总结了该产品的所有品质。让我们从比较用户群 1 和 2 开始。先看这两个集群的词分布。圆圈的大小表示该词在感兴趣的列表标题中出现的频率。

产品六——展示区(来源:【www.marktplaats.com】T2)

很明显,集群 1 中的用户正在寻找咖啡机,但是他们在品牌上没有任何明确的偏好。他们检查了不同品牌的咖啡机,如汝拉、西门子和飞利浦。集群 2 中的用户也在寻找咖啡机,但是他们对单一的特定品牌 Jura 感兴趣。可以说,与用户群 1 相比,群 2 中的用户是品牌特定的。

现在,让我们比较用户群 3 和前两个群的区域分布。如您所见,第 3 类用户的绝大多数感兴趣的列表发布在区域 1、2 和 3 中。实际上,这是荷兰一个特别著名的阿姆斯特丹地区,而你看不到前两个集群的任何区域模式。这里我们可以得出一个结论,物品的位置是集群 3 的用户的事情。

最后,让我们比较用户群 3 和用户群 4 的地区分布和中值价格。与聚类 3 的情况一样,我们也可以看到聚类 4 的区域模式。这些用户喜欢从荷兰北部(格罗宁根地区)发布的房源。更有趣的是,尽管这两个用户群都喜欢同一种特定的产品类型,即飞利浦 Senseo 咖啡机,但中间价格却有所不同。如您所见,与另一个集群相比,第四个集群中的用户对更昂贵的列表表现出兴趣。我们相信,在最终的结果集中,有一个隐藏的潜力,让营销人员从中提取一些有用的关于用户的信息。

结论—总体情况

如果你设法看到了这篇文章,可能你已经意识到所有的产品都以某种方式相互联系着。正如你从下面的大图中看到的,这个项目最令人惊讶的方面是,所有的产品都来自同一个来源: 广告嵌入 。除此之外,一个产品 的 输出作为另一个产品输入。因此,它可以被视为多个数据产品的开发链。

大图!(图片作者提供)

为了对您的业务有一个如此全面的了解和这 6 种不同的数据产品,您需要的只是用户产品视图和这些产品标题的基本点击流数据。仅此而已!将这一大图景整合到您的业务中就这么简单。请记住,所有产品的性能都强烈依赖于初始产品嵌入的质量。因此,如果您可以通过使用另一种方法或者在我们的方法之上添加一些额外的逻辑层来改进您的产品嵌入,那么您的所有产品将会逐渐给出更好的结果。

干得好!你坚持到了最后。这成了我写过最长的一篇文章。希望你喜欢读它,尽管它很长。我们欢迎您对文章和项目的反馈或评论。此外,如果你觉得这项工作很有趣,并想让其他人知道它,请随时在你的个人资料中分享它。

作者签名

主动学习框架综述

原文:https://towardsdatascience.com/a-summary-of-active-learning-frameworks-3165159baae9?source=collection_archive---------20-----------------------

比较不同的主动学习工具实现框架,选择最适合自己需求的框架

萨彦纳特在 Unsplash 上的照片

TL;速度三角形定位法(dead reckoning)

如果您正在处理分类任务,我推荐 modAL。至于序列标记任务,羊驼是你唯一的选择。

AL freamworks 对比(图片由作者提供)

主动学习工具

主动学习可以减少标签数量,节省标注预算。为了找到一个适合序列标记任务的主动学习工具,我对 OSS 主动学习工具做了一些调查。我想在这里分享我的结果。

模态

它建立在 scikit-learn 之上,允许您以*乎完全的自由度快速创建主动学习工作流

modAL 的 API 设计的很好,很好用。下面是朱庇特笔记本中 MNIST 的一个互动例子。左上角显示图像,底部要求人类输入该图像的标签。输入标签后,右上角会重新训练模型,并立即显示精度。

Jupyter 交互界面(图片作者)

我真的很喜欢莫代尔。它有很多好的特性,格式良好的文档,简单友好的 API 接口。它还支持定制模型。但遗憾的是,它只支持分类任务,不支持序列标签任务。

ALiPy

ALiPy 提供了一个基于模块的主动学习框架,允许用户方便地评估、比较和分析主动学习方法的性能

ALiPy 拥有简单的使用界面,支持比其他工具更多的主动学习算法。我在运行下面的例子时遇到了一个错误。原因是 Python 3.8 中删除了 time.clock()。我们在使用 ALiPy 时不得不注意 python 版本。

from sklearn.datasets import load_iris
from alipy.experiment.al_experiment import AlExperiment

X, y = load_iris(return_X_y=True)
al = AlExperiment(X, y, stopping_criteria='num_of_queries', stopping_value=50,)
al.split_AL()
al.set_query_strategy(strategy="QueryInstanceUncertainty", measure='least_confident')
al.set_performance_metric('accuracy_score')
al.start_query(multi_thread=True)
al.plot_learning_curve()----
AttributeError: module 'time' has no attribute 'clock'

一些例子和格式不良的文档提高了尝试这个工具的水*。我希望开发者能对文档做一些改进。

libact

一个 Python 包,旨在使现实世界的用户更容易进行主动学习。

libact 类似于 modAL。它们都基于 scikit-learn 并具有相似的界面。

# interface of libactqs = UncertaintySampling(trn_ds, method='lc') # query strategy instance
ask_id = qs.make_query() # let the specified query strategy suggest a data to query
X, y = zip(*trn_ds.data)
lb = lbr.label(X[ask_id]) # query the label of unlabeled data from labeler instance
trn_ds.update(ask_id, lb) # update the dataset with newly queried data

该文档格式良好,并提供了一些示例供您尝试。但是由于依赖错误,我不能安装 libact,即使我创建了 Python 3.6 环境。

ERROR: Could not find a version that satisfies the requirement libact ERROR: No matching distribution found for libact

羊驼

用于序列标记的基于主动学习的群体注释框架,例如命名实体识别(NER)。

AlpacaTag 是我发现的唯一支持序列标记任务的工具。通过使用 doccano 具有友好的交互界面。设置有点复杂。

下面是我在本地的实现。但是与预期的实现不同,本地版本不能激活在线学习功能。这可能是我的错误,但是其他的在文件上没有解释。

本地实现(作者图片)

预期实现(图片来自羊驼)

其他主动学习工具

  • 主动学习操场:这是一个 python 模块,用于实验不同的主动学习算法。
  • 深度主动学习:以下主动学习算法的 Python 实现
  • PyTorch 主动学习:常用主动学习方法库
  • 主动学习工作坊 :KDD 2018 动手教程:用 R 和 Python 大规模主动学习和迁移学习。 PDF

GitHub: 荆棘徐 LinkedIn:徐亮 博客: 荆棘徐

基本机器学习模型综述

原文:https://towardsdatascience.com/a-summary-of-the-basic-machine-learning-models-e0a65627ecbe?source=collection_archive---------16-----------------------

从线性回归到支持向量机

图片来自 Unsplash 。

亲爱的读者你好!这篇文章的目标是概述最基本的,有时也被称为【传统】机器学习模型,简要描述它们每一个,并引导你到无数的资源,在那里你可以深入了解它们。

我们将从最简单的模型到最复杂的模型,概述每个模型的优势,它们可以在哪里使用以及应该在哪里使用,并查看一些示例。当你争论使用哪种 ML 模型时,你可以使用这篇文章作为你的指南。

太棒了,现在我已经让你着迷了,让我们开始吧,从最开始开始:线性回归。

线性回归

图片来自 Flaticon.com

线性回归倾向于所有老师先讲解,大多数书先开始,大多数人最后学习以此开始职业生涯的机器学习算法。

这是一个非常简单的算法,它将一个特征向量(我们数据的变量或特征)作为输入,然后给出一个数字的连续输出。正如它的名字和前面的解释大纲,它是一个 回归算法,也是广义线性模型 ( GLMs )来源的线性算法家族的主要成员和始祖。

它可以使用封闭形式的解决方案进行训练,或者,正如机器学习领域通常所做的那样,使用迭代优化算法,如 梯度下降

线性回归是一种 参数化 机器学习模型(具有固定数量的参数,这些参数取决于我们数据的 n 个特征,并且训练速度非常快),对于与我们的目标变量(我们希望稍后预测的连续数字特征)线性相关的数据非常有效,学习起来非常直观,并且易于解释。这就是我们所说的一个' 可解释的人工智能模型 ',因为它做出的预测在知道模型权重的情况下非常容易解释。

线性回归模型的一个例子是预测房价的模型,该模型考虑了每个家庭的特征,如表面积、位置、房间数量或是否有电梯。

下图显示了线性回归如何仅使用一个特征来预测特定房屋的价格:房屋的表面积(*方米)。在我们的模型中包含更多变量的情况下,X 轴将反映这些特征的加权线性组合。

用于预测的线性回归示例。图片作者。

上图中的直线将在使用优化算法(如梯度下降)的训练过程中拟合,该算法迭代地改变直线的斜率,直到获得我们任务的最佳可能直线。

要了解更多信息,请查看以下资源:

  • StatQuest 的 Youtube 视频:'[线性回归【T1]'](https://www.youtube.com/watch?v=nk2CQITm_eo)
  • 走向数据科学文章:'线性回归解释【T3 ' '
  • 机器学习掌握:'机器学习的线性回归【T5 ' '
  • 统计学习介绍:在第三章 R 中的应用。

现在我们知道什么是线性回归,让我们学习它的离散兄弟:逻辑回归!

逻辑回归

图片作者。

逻辑回归是线性回归的兄弟,用于 分类 而不是回归问题。作为线性回归,它接受一个输入特征向量,但这次它给出的是一个类标签,而不是一个连续的数值。

逻辑回归的一个例子可以是一种算法,该算法根据某个病人的医疗记录来预测他是否患有疾病。

它使用一个 sigmoid 函数来实现这一点,因此它不仅能够给我们分类标签(生病与否),还能给我们这个事件发生的概率;即患有某种疾病的概率,或者我们店的某个顾客会购买某种产品的概率。

这真的很有用,因为我们可以根据从模型中获得的输出概率选择执行不同的操作,而不仅仅是二元预测。

作为线性回归,它是一种非常直观和可解释的算法,因为仅通过分析模型参数或权重,我们就可以看到我们的数据的哪些特征是最重要的,并且还可以看到为什么模型会预测它所预测的内容。

这使得它成为一个非常强大的分类模型,这通常是在面临分类问题时尝试的第一种方法,并希望快速获得结果以建立基线。

下图显示了一个逻辑回归模型的示例,该模型仅使用一个特征(患者体重)来计算该患者肥胖的概率:

逻辑回归示例。图片作者。

在上图中,我们可以看到具有特定形状的 sigmoid 曲线,用于预测 60Kg 患者肥胖的概率,我们可以看到该概率约为 10%(纵轴为 0.1),120Kg 患者肥胖的概率约为 93%(纵轴为 0.93)。

如果有不止 1 个特征,在水*轴上我们将看到这些特征的线性加权组合,在 Y 轴上我们将再次看到概率。

有关逻辑回归的更多信息,请查看以下资源:

  • StatQuest 的 Youtube 视频:'逻辑回归'
  • 走向数据科学文章:“逻辑回归解释”
  • KD 金块:'线性和逻辑回归黄金贴子'(令人惊叹的图解资源)
  • 安德烈·布尔科夫对《百页机器学习书》第 3 章的精彩简明解释。

Oki Doki!让我们继续另一个非常简单和直观的模型:决策树!

决策树

图片来自 Flaticon 。

决策树是非常通用的机器学习模型,可以用于回归和分类。

它们由两种元素构成:节点和分支。在每个节点上,我们会评估数据的一个特征,以便在训练过程中拆分观察值,或者在进行预测时使特定的数据点遵循特定的路径。

简而言之,决策树就是:评估不同变量的路径,这些路径通向一个离开节点,在这里相似的观察结果被分组。

在训练过程中,通过分析可能的特征及其值来构建树,并决定哪些特征最好地分割我们的数据,以便不同的数据点位于分割的一侧,同时最小化某种错误。

在下图中,你可以直观地看到什么是决策树。

使用 Iris 数据集构建决策树。图片作者。

正如你所看到的,它们是非常简单的模型,这通常意味着它们不会像例如神经网络那样产生如此强大的结果,并且它们也倾向于过度拟合(非常好地学习训练集,并且很难归纳到新的数据点),这限制了它们在行业中的使用。

然而,尽管有这些缺点,它们可能是最直观和最容易理解的机器学习模型,通过检查我们的数据点遵循的路径,我们可以很容易地知道为什么一棵树做出了某种预测。

对于分类问题,进行预测时所选择的类是新观察值沿着其路径穿过树后落入的离开节点的训练数据点的最频繁的类。对于回归,它是这些点的目标值的*均值。

  • StatQuest 视频:“决策树解释”
  • 迈向数据科学文章:'决策树解释
  • Towardsai post: ' 决策树用实例说明
  • 塞巴斯蒂安·拉斯卡在他的书' Python 机器学习'第 3 章中解释道。

酷!让我们看看如何堆叠大量的决策树来创建一个随机森林!

随机森林

图片来自Flaticon.com

随机森林模型是一种 参数化模型,可用于回归和分类。它们是最流行的集成方法之一,属于 Bagging 方法的特定类别。

en 集合方法包括使用多个学习者来单独提高其中任何一个人的表现。这些方法可以被描述为使用一组弱学习者 ( 那些*均成绩仅比随机模型稍好的人)在一起的技术,以便创建一个更强的、聚合的

在我们的例子中,随机森林是许多个体决策树的集合,这是我们之前看到的机器学习模型家族。

随机森林将随机性和数字引入方程,修复了单个决策树的许多问题,如过度拟合和预测能力差。

在随机森林中,每棵树都是使用训练数据的子集构建的,并且通常只使用可能特征的子集。随着越来越多的树被建立,我们的数据被更广泛地使用,更多的功能开始发挥作用,从而形成非常强大的聚合模型。

单独的树是独立构建的,使用与普通决策树相同的过程,但是仅使用数据的随机部分,并且仅考虑每个节点的特征的随机子集。除此之外,训练过程与单个决策树完全相同,重复 N 次。

要使用随机森林进行预测,需要从每棵树中获得一个单独的预测。然后,如果是分类问题,我们将最频繁的预测作为结果,如果是回归问题,我们将所有单棵树的*均预测作为输出值。下图说明了这是如何实现的:

使用随机森林模型的预测。图片作者。

有关随机森林的更多信息,请查看:

  • StatQuest 在随机森林上的视频。
  • 走向数据科学岗:随机森林讲解。
  • 内置:随机森林完整指南。

随机森林和 Boosting 方法可能是工业中最常用的传统机器学习模型,因为它们易于使用、强大且灵活。

让我们看看这些【助推法】是什么!

升压方式

图片来自 Flaticon 。

助推方法类似于我们刚刚看到的' Bagging' 随机森林,但有一个关键区别:在随机森林中,所有的树都可以并行建造,它们非常独立。在 boosting 方法中,每个树都是按顺序构建的,从前面的树中获取信息:树 4 依赖于树 3,树 3 依赖于树 2,依此类推。

Boosting 最初被命名为 假设 Boosting ,其思想是对用于训练我们的弱学习者团队的数据进行过滤或加权,以便每个新学习者给予更多的权重,或者只使用先前学习者分类不佳的观察值进行训练。

通过这样做,我们的模型团队学会了对各种数据做出准确的预测,而不仅仅是对最常见或最简单的观察。此外,如果其中一个单独的模型非常不擅长根据某种观察结果做出预测,这也没关系,因为其他 N-1 个模型很可能会弥补这一点。

Boosting 方法非常强大,当面对机器学习/数据科学行业中的普通表格数据时,LightGBM、AdaBoost 或 XGBoost 等模型以及之前讨论的随机森林可能是最常用的方法。

有关增强的更多信息,请查看以下资源:

  • 什么是机器学习中的 Boosting?@走向数据科学
  • 由我们可爱的乌达城助推。
  • 在 QuantDare 博客上解释了。

让我们以最后一个令人敬畏的模型结束:支持向量机!

支持向量机

图片来自 Flaticon 。

支持向量机或 SVMs 是一个广泛使用的机器学习模型家族,可以解决许多 ML 问题,如线性或非线性分类、回归,甚至异常值检测。

话虽如此,的最佳应用是在将应用于小型或中型复杂数据集的分类时。

对于分类,支持向量机通过在我们的数据之间创建一个决策边界来工作,该边界试图尽可能地将数据分开,如下图所示:

线性 SVC 的判决边界。作者图。

有时,使用线性决策边界来完全分离我们的数据是不可能的,有时也是不可能的,所以支持向量机使用一种称为 内核技巧 的聪明技巧来尝试分离我们的数据,尽管它们有时必须让错误类的一些点位于决策边界的一侧,而它们不应该在那里。

通过调整多少点,以及我们使用哪种内核,支持向量机可以非常强大,特别是当我们的数据有很多特征时。然而,它们需要相当长的时间来训练,所以它们应该只用于小型或中型数据集。

想了解更多关于 SVMS 的信息,请访问:

  • 支持向量机讲解走向数据科学。
  • 我们的朋友 Josh Starmer 的 SVMs 视频。
  • MonkeyLearn 上的支持向量机简介。

结束语和其他资源。

就是这样!一如既往,我希望你喜欢这篇文章,我设法帮助你了解了一些基本的机器学习模型,并给你提供了深入研究它们的资源。

我们排除了人工神经网络,并包括了助推模型(有些人排除在这个列表之外)。概率方法也没有包括在内,但是你可以在我的其他关于数据科学的文章中学到很多。最后,无监督的模型没有包括在内。

为了使本文更加完整,我将在下面的列表中为您提供资源,以帮助您决定在每种情况下使用哪种机器学习算法:

  • sci kit-Learn 的机器学习模型备忘单。
  • 机器学习算法是你的朋友。
  • SaS 机器学习算法小抄。

此外,你可以查看 这个资源库 获取更多关于机器学习和人工智能的资源!

  • 封面图片来自Unsplash
  • 来自 Flaticon.com 的图标
  • 所有其他图像都是自己制作的。

计算机视觉在美术分类中的应用综述

原文:https://towardsdatascience.com/a-survey-of-computer-vision-in-fine-art-classification-9c7e60ad3fc2?source=collection_archive---------22-----------------------

图片来自 Cetinic 等人(2018)

概观

随着在线画廊和在线美术市场的出现,数字化美术绘画收藏变得越来越有需求。Google Arts & Culture 是一个教育和娱乐在线*台的优秀例子,它让人们更容易接触到在线艺术——让人们甚至可以通过其 VR 技术沉浸在虚拟艺术画廊中。另一个例子是 Artsy,这是一家在线艺术品经纪公司。它利用一个搜索系统来链接基于彼此关系的艺术作品。此外,许多其他应用需要美术分类技术。因此,提高数字化艺术的搜索算法的能力以及记录和管理这种文化遗产的过程仍然是必要和有意义的。然而,要解决这个问题,至少还有一些挑战需要解决。

问题

一个重大的挑战是缺乏大数据集的标记数字化艺术品。如果没有大量的数据,即使公认的分类模型也不会产生好的分类结果。分类模型的设计和模型训练的实现也同样重要。因此,在以下几节中,我将首先回顾一种数据增强方法,该方法试图克服 Smirnov & Eguizabal (2018)提出的标记精细艺术数据的缺乏。以及他们在一些著名的 CNN(卷积神经网络)上改进迁移学习的方法。接下来,将讨论 Rodriguez 等人(2018)提出的一种使用图像补丁和迁移学习对美术图像进行分类的新方法。最后,我将前述作品与 Cetinic 等人(2018)提出的设计进行比较。他们发现,场景识别和情感预测可以为这项工作产生更好的结果,而不是专注于分类任务的对象检测。

资料组

上述三篇论文中使用的数据集是:

  • 帕斯卡 VOC
  • 绘画数据集
  • TICC 版画数据集
  • 网络美术馆(WGA)
  • 维基亚特

PASCAL VOC 包括 20 类由摄像机拍摄的带注释的图像,无需进一步的风格转换即可用于对象识别和分割任务。绘画数据集包含 10 类美术绘画,标签来自 PASCAL VOCTICC 版画数据集是一个在纸质版画上复制数字化摄影作品的数据集。WGA 包括从 3 世纪早期到 19 世纪的美术绘画。除了 WGA, WikiArt 是最大的在线数字化绘画收藏之一,包括 19 至 20 世纪 3000 名艺术家的超过 25 万件艺术品。

算法和方法

数据扩充

与一些最知名的数据集相比,如 ImageNet (14 M+图像,20000 个类别)和腾讯 ML 图像(约 18M 图像,11166 个类别),美术绘画的数据要少得多。幸运的是,一组研究人员已经找到了解决这个问题的方法。

Smirnov & Eguizabal (2018)提出对从 PASCAL VOC 获得的真实世界图像应用风格转移。这个概念结合了(或者用一个更专业的术语来说,多重)PASCAL VOC 的自然图像和特定艺术风格的图像,比如印象主义或现实主义。因此,它允许生成具有相同内容(对象)但具有不同艺术风格或纹理的各种新图像。下图显示了该流程的一个示例。

图一。风格转移过程的一个例子。图像(e)、(f)和(g)分别应用了样式(b)、(c)和(d)。所有结果图像呈现图像(a)的相同内容,但是具有独特的艺术风格。图片来自 斯米尔诺夫&equizabal(2018)

卷积神经网络的迁移学习

为了从一些预先训练的细胞神经网络中获得有价值的特征并节省计算成本,这三篇论文都在不同的细胞神经网络模型上采用了迁移学习方法来对美术绘画进行分类。

1.卡芬内及其变体

Cetinic 等人(2018)使用了 CaffeNet 的基础架构,这是对 AlexNet 的轻微修改。它是一个只有八层的浅网络。五个三卷积层,后面是三个全连接层。此外,在第一、第二和第五卷积层之后还有三个最大池层。他们选择 ReLU 作为所有层的激活函数,输出层连接到 softmax 层。下图描绘了卡芬内的建筑。

图二。卡芬内的建筑。图片来自https://medium . com/coin monks/paper-review-of-Alex net-caffenet-winner-in-ils vrc-2012-image-class ification-b 93598314160

由于迁移学习的目的是利用预训练的权重,作者保留了前七层的权重,但保留了预训练的 CaffeNet 的最后一层。相反,他们用与数据集中目标类数量相对应的特定数量的神经元替换了最后一个完全连接的层。他们还试图测试冻结层的不同组合(意味着设置和权重保持与预训练模型相同),以评估它们是否会影响分类任务的最终性能。他们认为,最初的几层 CNN 是为了发现像明显的斑点或边缘这样的一般特征。相比之下,其余的层将深入到每个图像,提取更多的细节特征。有趣的是,根据下表,他们发现最佳性能是通过仅冻结第一个或前两个卷积层的权重并重新训练所有其他层来实现的。

图三。不同微调场景下的测试精度比较。图来自 Cetinic 等人(2018)

除了专注于对象识别,该研究还发现,使用预训练的 CNN 的场景和对象识别的组合产生了比仅仅对象识别更好的结果。此外,数据集混合了地点和 ImageNet 图像。该实验可以表明美术分类任务可能需要场景特征来帮助提高分类准确度。

2.图像补丁或分割

Rodriguez 等人(2018 年)建议,数据集中的每张图像都应被等分成五份,作为 CNN 模型的输入。然后,结合来自前一步骤的加权分类结果,可以预期比未分割图像的分类结果更高的分类精度。

三个主要步骤如下:首先,将来自训练集的每个图像的大小调整为当前大小的两倍。然后,每个图像被分割成大小相等的五块,其中四块是与原始图像具有相同高度和宽度的角块,第五块是中心块,正好占每个角块的 25%。

图 4。将原始图像分割成五个大小相等的片段的示例。图片来自 Rodriguez 等人(2018)

第二,新的图像集(补丁图像)然后被馈送到一些预先训练的 CNN 模型,以对每个图像分割的风格进行分类。本实验中使用的预训练 CNN 模型有 AlexNet、VGG-16、VGG-19、GoogLeNet、ResNet-50 和 InceptionV3。值得注意的是,它们只替换了这些神经网络的最后三层,以适应类别的目标数量。这里,重点不是每个 CNN 的性能,而是观察是否有任何趋势或指示加权图像补片可以带来更高的分类精度。

最后,对每个原始图像执行优化过程,以根据前一步骤的分类结果发现每个分割图像的类别概率的最优权重。由于每个图像碎片被独立分类,这意味着来自同一原始图像的所有图像碎片不会影响分类过程,因此来自同一原始图像的不同图像碎片被分类到不同的目标类别(艺术风格)是可能的。因此,他们应用了一个优化过程,即遗传算法,来迭代地搜索最优组合加权结果,以最终决定每个原始图像的决策类。算法及其过程如下图所示。

图五。每个图像块的权重优化过程。图片来自 罗德里格斯等人(2018)

这里,Cn,k 是来自 CNN 的每个图像块的结果,wn 表示 Cn,k 的相应权重,CTk 是第 k 个原始图像的总结果向量。现在,找到了每个图像块结果的最佳权重,最后一步是通过最佳权重和每个图像块的概率向量的点积运算来找到最大总概率向量 CTk。此外,每个图像补片权重被设置为小于或等于 1 (100%)有一个约束,以保证没有单独的图像补片权重比其他图像补片权重超过 100%。最终结果如下图所示。

图六。不同模型和场景组合的风格分类结果。图片来自 罗德里格斯等人(2018)

从条形图中,我们可以观察到,与仅使用原始图像作为输入数据相比,使用加权图像块在风格分类任务中产生更高的准确度。当图像被分割时,它似乎无助于解决这个问题。然而,考虑那些具有最佳权重的单个片段显示了图像补片如何通过贡献更高的分辨率来提高分类准确度。因此,该研究得出结论,分辨率较高的图像可以为美术风格分类任务添加有价值的信息,如艺术风格。

3.CNN 与 SVM 的融合

美术分类任务的一个常见问题是缺乏数据。没有足够的数据,任何分类或目标检测任务都将是困难的。为了解决这个问题,Smirnov & Eguizabal (2018)提出了上面提到的数据增强方法和他们的训练方法——两个 CNN 和一个 SVM。概念是首先训练两个 CNN,然后连接来自 CNN 的结果向量,并将它们馈送到 SVM,用于最终的对象检测。下图说明了流程图。这里,一个 CNN 用于物体检测,另一个用于风格分类。PASCAL VOC 数据集被训练用于对象检测任务,而 WikiArt 图像数据集被训练用于风格分类。他们用 VGG-19 作为两个 CNN 的模型。两个 CNN 的权重保持与原始预训练的 VGG-19 相同,除了最后一个完全连接的层,为来自两个 CNN 的输出特征向量的后续连接而定制。测试结果表明,它比传统的目标检测和分类方法提高了 5%。这项研究证明了通过将艺术风格应用于日常图像来增加艺术图像数据集的功效,以及用 SVM 融合两个训练不同主题(对象和风格)的 CNN 的可行性。

图 7。SVM 的两个 CNN 的流程图。图片来自 斯米尔诺夫&埃奎扎巴尔(2018)

未来研究趋势

有几种方法可以改进目前对美术图像进行分类或检测的方法。在 Cetinic 等人(2018 年)的研究中,他们建议,除了从事美术图像分类任务,研究人员还可以发现数字化艺术品之间图像特征的内在联系。在未来的研究中,也可以考虑摄影和图像中的情感、质量和美学等目标。此外,研究人员与美术历史学家和相关领域的专家合作,以更好地了解美术领域,这总是一个好主意。

其他研究建议调查其他神经网络或 CNN,以评估它们的计算成本和分类性能,并找到这项任务的最佳*衡。例如,尽管 InceptionV3 模型在分类图像方面具有更高的准确性,但与 AlexNet 和其他简单的 CNN 相比,它需要更长的时间来训练相同的数据集。因此,这是一个值得研究的优化课题。

创造力

在美术分类中发现的一个普遍问题是印象主义和表现主义艺术品之间的高错误分类率。是因为后者是由前者进化而来的。然而,我想出了一个主意——两阶段分类法,来解决这个问题。最初,对数据集中的所有图像进行粗略分类。然后,执行专门为区分印象主义和表现主义数字化图像而设计的更精细的分类。在建立第二个分类器之前,我们需要知道这两种艺术风格的一些共同特征。印象主义侧重于光线的变化,表现主义主要关注人脸上的表情。有了这些先验信息,我们可以构建一个提取图像和面部表情像素值的分类器。如果输入图像显示强烈的面部表情,我们可以假设它属于表现主义艺术作品。另一方面,如果一幅图像被检测到有大量的像素值偏移而没有人脸特征,我们可以说它是一件印象派作品。

结论

美术分类中的计算机视觉是一个有趣的话题,可以给现实世界带来巨大的价值。随着*年来数字化艺术品越来越流行,以及在线艺术品拍卖市场的蓬勃发展,艺术品分类开始在这些趋势中发挥至关重要的作用。有了这项技术,各方将更容易识别从古代历史到现代世界的不同艺术品。节省了对每件艺术品进行确认、分类甚至鉴定的人力成本。然而,需要进一步的研究来利用计算机视觉的力量,让人类从这项技术中受益。

参考

塞蒂尼奇公司、立皮奇公司和格吉奇公司(2018 年)。用于美术分类的微调卷积神经网络。专家系统与应用114 ,107–118。

罗德里格斯,C. S .,莱赫,m .,&皮罗戈瓦,E. (2018,12 月)。使用迁移学习和加权图像补片对美术绘画风格进行分类。在 2018 第十二届信号处理与通信系统国际会议(ICSPCS) (第 1–7 页)。IEEE。

Smirnov,s .,& Eguizabal,A. (2018 年 10 月)。美术绘画中物体检测的深度学习。在 2018 考古与文化遗产计量学(MetroArchaeo) (第 45–49 页)。IEEE。

用 Python 快速介绍概率论

原文:https://towardsdatascience.com/a-swift-introduction-to-probability-theory-with-python-afb24e1bd7bd?source=collection_archive---------17-----------------------

Python 中概率论背后的编程基础微积分和统计学概述。

(src =https://pixabay.com/images/id-5363809/

介绍

P 概率理论是数学的一个分支,专注于解释某些结果的可能性。数学分支使用公理来正式度量概率空间中的概率。可能空间是用于确定可能性的样本空间的名称。有了这个定义,就很容易理解为什么概率论在实验和预测这些实验的结果中占有重要地位。利用数据和可能的空间,我们可以利用基于先前结果的数据做出明智的决策。同样,我们可以确定分析相关性,从而为我们生活的世界提供有价值的信息。

不用说,这使得这个数学分支相当强大。我们不仅可以使用这些数学来对我们周围的世界以及如何改善它做出明智的决定,而且我们还可以用它来预测这些决定的影响。这反过来让我们更加了解这些分析所做出的决策的潜在结果。现在我们已经了解了概率论的力量,让我们深入到概率空间、分布以及如何在 Python 编程语言中使用它们。

分布和空间

概率分布是一个函数,它给出了实验中不同可能结果的可能性。概率论中使用了许多不同的统计分布,但最流行的两种可能是 t 分布和 Z 分布,也称为正态分布。有两种不同类型的分布用于预测两种不同类型的特征。

要考虑的第一类特征是离散特征。这些特征代表某种非数字的类别或可能性。例如,我们掷骰子,我们有可能将掷骰子分为一、二、三、四、五或六。另一种类型的分布是连续概率分布。这些用于测量连续值的样本空间。连续值只是在数字空间中具有表示形式的特征,例如,被观察人群中不同体重的测量值。关于分布值得一提的另一件事是,它们有两个用于创建统计推断的函数,累积分布函数(CDF)和概率密度函数(pdf)。)虽然我没有一篇深入讨论 CDF 的文章,但是我有一篇关于 pdf 的文章,稍微涉及了一下什么是 CDF。因此,我在这里只简要回顾一下这些信息,如果您想进一步了解这两项功能,可以点击:

[## 什么是概率密度函数?

towardsdatascience.com](/what-is-a-probability-density-function-d9b4b8bea121)

Python 中的不同发行版

概率论中所有连续样本空间的基础是正态分布。正态分布有一个简单的 PDF,它利用了连续特征中的三个重要值:

  • μ——样本均值。
  • σ —样本标准偏差。
  • n —样本中观察值的数量。

使用特征的这些简单属性,该 PDF 将显示给定值偏离*均值的标准偏差数。该公式可以用 Python 编写如下:

x = [5, 10, 15]
N = len(x)               
σ = std(x)
μ = mean(x)
normally_distributed = [i = (i-μ) / σ for i in x]

但是,您也可以使用 NumPy 或 SciPy 实现:

import numpy as np
import scipy.stats as scs
normal = np.normal(x)
normal = scs.norm.pdf(x)

正态分布完全能够用于测试,然而大多数科学家选择使用另一种概率分布。这是为什么呢?走向统计显著性的分布的最重要部分是分布的尾部。分布的尾部通常用 alpha 值的长度来表示,表示样本空间中很少的样本。alpha 值是一个百分比值,它是通过将我们在测试中需要的置信度减去 1 而得到的。用来证明假设的最流行的阿尔法值是 0.05,这意味着通常科学是在 95%的置信度下完成的。就我个人而言,我更喜欢争取 97%的信心水*,以便在接受假设之前真正巩固其有效性。现在我们了解了尾部,我们可以考虑为什么正态分布不经常用于测试。

正态分布的尾部很小,有一个陡峭的截止点,在尾部内部留给样本实际下落的空间很小。换句话说,正态分布的数据不太可能落入我们的阿尔法区域,因为尾部更小。这是因为正态分布是一个规则的概率分布,而 t 分布是一个等价的概率分布。让我们从 SciPy.stats 看一下 T 分布的 PDF 函数。为了使用 T 分布,我们首先需要获得我们的自由度。这通常用 v 表示,可以通过将样本长度减去 1 来计算。

v = len(x) - 1
t_data = scs.t.pdf(x, v)

结论

概率论已经成为应用科学中最重要的数学分支之一。这是因为使用这种数学方法,我们既可以分析从实验中返回的数据,也可以用收集到的数据实际执行实验,以获得洞察力。作为拥有大量技术的人类,很容易认为我们已经发现了所有需要知道的东西。然而,事实并非如此,使用统计测试方法,你可以用数学自信来证明你的想法!这就是这些技能如此强大的原因!非常感谢你阅读我的文章,我很感激。

VegaLite.jl 快速介绍 Julia 的统计图表

原文:https://towardsdatascience.com/a-swift-introduction-to-vegalite-jl-statplots-for-julia-640c02263fd6?source=collection_archive---------26-----------------------

VegaLite.jl 使用基础的快速概述;Julia 最受欢迎的统计绘图库之一

数据可视化是一项极其重要的技术,数据科学家或分析师可以通过这项技术了解更多关于数据的信息。可视化您的数据可以使相关性更容易发现,并且可以很好地了解数据的其他方面,如变化和样本数。不用说,对于科学计算来说,可视化数据非常重要。如果有一种编程语言想要将一个生态系统投射到可能想要使用该语言的数据科学家身上,那么这个生态系统很可能需要包含一些可视化库。针对这个领域的最年轻的语言之一是 Julia。

Julia 是一种很棒的编程语言,尤其是对科学而言。它有多重调度,速度快,层次很高。然而,与类似的选择相比,Julia 确实有一些不足之处,那就是它的生态系统。实际上,我在另一篇文章中多次谈到这一点,在那篇文章中,我讨论了 Julia 语言及其各自的生态系统所面临的问题。如果你对这样的阅读感兴趣,你可以在这里找到那篇文章:

鉴于 Julia 确实有一个相当不成熟的生态系统,这是否意味着在 Julia 中数据可视化的选择相当有限?这个问题的第一个答案是否定的,但第二个答案是,即使受到限制——Julia 是 LLVM 编译器库和 C 编程语言的好朋友,这意味着在 Julian 包不适合应用程序的任何情况下,它通常都可以调用外部库。

虽然 Julia 相对不成熟,而且使用不同的语言可能会得到更好的可视化和更健壮的 API,但仍然有一些强大的选项是完全用 Julia 编写的。这种库的一个例子是 Vega lite . JL。Vega lite . JL 是一个针对 Julia 的调制可视化库,我认为它很可能与 Plot.ly 最相似……这真的不是一件坏事——

我爱 Plot.ly!

另一个值得一提的是,Julia 现在也有了一个 Plot.ly 端口,所以你也可以一直使用 Plot.ly。此外,他们甚至对朱丽亚有所图谋。如果您想了解更多关于 Julia 语言的非 Plot.ly 或 Vegalite.jl 库的信息,那么我强烈推荐这篇文章,在这篇文章中,我讨论了 Plots.jl 包以及我个人最喜欢的 Julia 库,牛虻. jl:

在我们深入研究这个包之前,最后一件事是,那些可能想跟随或查看源代码的人可以查看这个笔记本的内部:

https://github.com/emmettgb/Emmetts-DS-NoteBooks

更多关于 VegaLite.jl

关于 Vegalite,我想讨论的第一件事是这个图书馆实际上有多包容。只要看一下文档的主页,我们很快就会看到 Vegalite.jl 包中包含了多少内容。这个包可以做很多事情,而且不仅仅局限于绘图。

Vegalite 最大的优势在于数据。Vegalite 处理绘图和几何数据的方式是一种更现代的软件工程方法,它使用 JSON 数据作为参数,以便使绘图更加基于数据,而不是基于会话。这种说法的问题当然是这是否会给一揽子计划带来任何好处。

关于这个方法应该说的第一件事是,它很可能比它最终可能与之竞争的大多数其他包表现得更好。这种 JSON 的做事方式至少在 CPU 处理方面非常有效,但是如果我在工作中经常使用这个包,我可能会担心我的内存。我想补充的另一点是,预编译真的很快。我讨厌很多 Julia 模块的一点是,预编译会花费令人不安的时间,Plots.jl 就是一个很好的例子。也就是说,这是一个非常酷的方法,但是这种方法也有一些奇怪的地方。

在数据可视化的世界中,对这类场景使用特定的方法是一种惯例。例如,大多数语言的代码都类似于这样:

plt = plot(feature, other_feature, arguments)

然而,在 Vegalite,事情变得有点古怪。宏@vlplot 几乎可以用于任何事情。这个宏返回一个类型,当我们开始绘图时,我们将会看到这个类型,并且这个类型也被分派来处理一些非常酷的事情。这个包的强大之处在于该类型的内部构造函数。

基本绘图

现在我们已经了解了 Vegalite,让我们深入了解一下,并在其中完成一些绘图!

import VegaLite: @vlplot

如前所述,这个包中确实没有太多我们需要导入的内容。考虑到这一点,我将通过直接导入宏来保持环境整洁。现在让我们看一个基本的散点图示例。我们需要为此提供的数据将是数组类型。我们为关键字参数提供了各自的数组。Vegalite 也有一组数据集,可以用来下载一些数据,所以我会这样做,然后将数据分配给一个新的数组,然后准备好放入我们的宏调用中。

using VegaDatasetsdata = dataset("cars")

然后,我们可以使用右边的按位运算符将这些数据“注入”到宏中,并创建一个新的绘图:

data |> @vlplot(:point)

作者图片

恭喜你,你刚刚完成了你的第一个素食主义者计划!我不确定我们是否应该称之为阴谋,它更像是一个要点。VegaLite 实际上正在绘制我们提供给宏的所有数据,唯一的问题是它没有最大值或最小值。允许详细说明,每当图形数学完成时,我们需要在屏幕上找到一个完美的像素来放置给定的形状。问题是分辨率和屏幕尺寸总是不一样。也就是说,如果我在 1080p 的屏幕上放一张 30px 高的自己的照片,或者放在那个尺寸的图片中,如果我们换成 240p,它就不会在同一个地方了。

为了减轻这种情况,通过将该值除以分辨率来计算分数,以获得像素占整体的百分比。之后,从图像尺寸中减去该百分比与分辨率或图像尺寸的乘积,这就是像素的最终位置。我怎么知道这么多?我实际上做了我自己的奇怪的小图形库,不久前在 Medium 上写了关于它的文章,你可以查看我在软件包上发布的最后更新,我可能很快会继续工作!

为了让我们的 VegaLite 图实际工作,我们需要在宏调用中添加两个新的关键字参数。这些只是我们的 x 和 y 值。

data |> [@vlplot](http://twitter.com/vlplot)(:point, x=:Miles_per_Gallon, y=:Horsepower)

作者图片

调整我们的情节

在这个神奇的 VegaLite.jl 包的快速介绍中,我想做的最后一件事就是回顾一下人们可以对其情节进行的一些基本更改。我不想太详细地介绍 Vegalite 中的所有内容,因为内容实在太多了,至少对于一篇文章来说是这样的,也许我会在以后继续讨论这个包。

首先,散点图是一个很好的东西,也是一个很棒的工具,但是它们并不是在每种情况下都有用,所以让我们改变我们正在使用的图的类型。第一个参数,也是唯一的位置参数,符号点是我们想要替换的。例如,酒吧:

data |> [@vlplot](http://twitter.com/vlplot)(:bar, x=:Miles_per_Gallon, y=:Horsepower)

我们可以在这里提供各种关键字,但仅举几个例子:

  • 因素
  • 宽度
  • 不透明
  • 改变

他们有很多,所以我们将只关注基本的,有一点闪光。现在让我们制作一些新的数据:

arm_motion_data = [(; ϕ1 = cos(t), ϕ2 = sin(t), t) for t in 0:0.01:2pi]

现在让我们创建一些参数。现在让我们创建一个基本的情节,我将使用表情来创建形状,这对于动画之类的东西来说是理想的,但这里我将出于方便使用它。

arm_motion_data |>
VegaLite.[@vlplot](http://twitter.com/vlplot)(
    width = 500,
    height = 500,
    transform = [
        {calculate = "cos(datum.ϕ1)", as = "px1"},
        {calculate = "sin(datum.ϕ1)", as = "py1"},
        {calculate = "datum.px1 + cos(datum.ϕ2)", as = "px2"},
        {calculate = "datum.py1 + sin(datum.ϕ2)", as = "py2"},
    ],
)

最后,我将使用加法运算符+来添加一些新标记:

+
VegaLite.[@vlplot](http://twitter.com/vlplot)(
    mark = :rule,
    x = {datum = 0, scale = {domain = [0, 2.8]}},
    y = {datum = 0, scale = {domain = [-1.4, 1.4]}},
    x2 = "px1:q",
    y2 = "py1:q"
) +
VegaLite.[@vlplot](http://twitter.com/vlplot)(mark = :point, x = "px1:q", y = "py1:q") +
VegaLite.[@vlplot](http://twitter.com/vlplot)(mark = :rule, x = "px1:q", y = "py1:q", x2 = "px2:q", y2 = "py2:q") +
VegaLite.[@vlplot](http://twitter.com/vlplot)(mark = :point, x = "px2:q", y = "py2:q")

整个结果看起来像这样:

arm_motion_data = [(; ϕ1 = cos(t), ϕ2 = sin(t), t) for t in 0:0.01:2pi]arm_motion_data |>
VegaLite.[@vlplot](http://twitter.com/vlplot)(
    width = 500,
    height = 500,
    transform = [
        {calculate = "cos(datum.ϕ1)", as = "px1"},
        {calculate = "sin(datum.ϕ1)", as = "py1"},
        {calculate = "datum.px1 + cos(datum.ϕ2)", as = "px2"},
        {calculate = "datum.py1 + sin(datum.ϕ2)", as = "py2"},
    ],
) +
VegaLite.[@vlplot](http://twitter.com/vlplot)(
    mark = :rule,
    x = {datum = 0, scale = {domain = [0, 2.8]}},
    y = {datum = 0, scale = {domain = [-1.4, 1.4]}},
    x2 = "px1:q",
    y2 = "py1:q"
) +
VegaLite.[@vlplot](http://twitter.com/vlplot)(mark = :point, x = "px1:q", y = "py1:q") +
VegaLite.[@vlplot](http://twitter.com/vlplot)(mark = :rule, x = "px1:q", y = "py1:q", x2 = "px2:q", y2 = "py2:q") +
VegaLite.[@vlplot](http://twitter.com/vlplot)(mark = :point, x = "px2:q", y = "py2:q")

作者图片

结论

如果您使用 Julia 编程语言,或者即使您碰巧对它感兴趣,我也强烈推荐您查看 Vegalite 包。这个包有各种各样令人敬畏的特性,和一个我以前从未见过的非常酷和有趣的方法。非常感谢您的阅读,我希望这个整洁的小软件包和文章能够激发您对在 Julia 中可视化数据的兴趣!

处理不良数据的系统方法

原文:https://towardsdatascience.com/a-systematic-approach-to-bad-data-6c7e2f86e5ef?source=collection_archive---------20-----------------------

行业笔记

因为有时候仅仅打扫是不够的

由萨姆·穆卡达姆在 Unsplash 上拍摄的照片

任何与数据打交道的人都知道最初的预处理步骤是多么耗时(而且会让人白发苍苍)。我们都已经咬了分析位,急切地盯着项目路径到我们遥远的建模目的地。那么如果数据不完美呢?几个可疑的值或变量真的会对研究结果产生多大影响?

抵制掩盖原始数据的冲动。

相信我。你的雇主、股东和未来的自己都会感谢你。为什么?

简单地说,没有首先验证所提供数据的质量就一头扎进探索性分析或运行模型是一个重大疏忽。据 IBM 估计,人为错误和随之而来的低质量每年给美国造成了超过 3 万亿美元的损失。是的,你没看错。脏数据不是小事。

幸运的是,数据清理通常是数据科学和分析相关课程的早期主要内容。面对当今“大数据”时代常见的膨胀、复杂的数据集,新手可以在掌握经典数据清理技术中找到解脱。清洗无疑是确保高质量数据的重要步骤。如果您不确定这些技术需要什么,或者需要复习最佳实践,请查看我以前的文章,详细介绍一个基本的数据清理框架这里。

但是,数据新手要当心… 有时候清理并不能解决问题。

米歇尔·特雷瑟默在 Unsplash 上拍摄的照片

我知道。不是你想听到的。但是,严峻的事实是,有些数据无法清理到足够的程度。

数据不仅可能是“脏的”,还可能在体系结构上不合理。

好吧,但是“建筑不合理”是什么意思?

数据架构是一个相当宽泛的概念。它描述了构建什么系统来将数据连接到总体业务战略,从收集什么数据到如何存储、管理、转换和最终使用数据。

不幸的是,任何给定的数据管道都有出错的空间。这些错误可能以各种方式出现,包括数据集工程中的失误和数据流错误。

因此,体系结构不健全的数据将具有诸如缺失数据的整行或整列、不正确的强制选择答案响应、在错误的时间范围内或用错误的样本收集的数据,或者(恐怖的恐怖😱)不符合原始业务或项目目标的数据。

好吧,但是我该怎么做呢?

你可以清理掉长时间的工作,但是,如果在你争吵的过程中出现这样的错误,你可能会想把事情暂时搁置。无论您捕捉了多少个“NA”或重新标记了多少个变量名,都无法弥补完全缺失或无效的数据

没有人希望收集来之不易的数据却发现这些数据是不可用的。但是你如何判断数据是否真的不可用呢?您是否必须立即丢弃每个不可靠数据的实例并重新运行收集?

简单的回答是不!

照片由布鲁斯·马尔斯在 Unsplash 拍摄

有了清晰的四步系统,您可以减少架构错误,挽救可用数据,潜在地为您的公司节省重新运行数据收集措施的财务负担,并确保最高质量的数据。咻。

该系统的首要目标是在管道源头识别并纠正错误。要做到这一点,只需按顺序一个接一个地遵循提出的问题,直到找到最适合您的特定体系结构问题的解决方案。

下面我们来概述一下流程图:

专业提示: 在一头扎进上面的流程图之前,检查一下你的原始数据集。寻找指示错误数据的模式。是否有大量数据神秘失踪?测量值能否回答您的项目问题?您信赖的清洁包(如 R's tidyverse)是否存在无法轻易解决的重大错误?不到万不得已,不要收集更多的数据。

一个简单的合成例子

在教程领域,实例胜于雄辩。

假设你在一家整体精神健康初创公司工作,该公司希望在他们的应用程序上试行一项新的调查。这项调查旨在通过进一步了解以前的应用体验如何影响客户当前的应用活动来促进客户与应用的互动,并最终让产品团队更好地锁定互动时间较短的客户。在一些团队会议之后,在应用范围内启动之前,设计了一个调查,并提供给 50 个客户的小组。

作为该项目的分析团队的一员,您被要求查看最终的调查数据。你很快意识到有些事情不对劲。请注意,本例中使用的数据集是人工生成的,不一定代表真实的数据趋势。

这里有几个问题。

第一个,app 追踪的四个客户端行为(冥想习惯(冥想 _ 特征)、饮食习惯(饮食 _ 特征)、运动习惯(运动 _ 特征)、睡眠习惯(睡眠 _ 特征))中,冥想值全部缺失。

第二个,what _ app _ type变量的每个值都是“教育性”的,虽然这是可能的,但在统计上是不可能的。

第三个,每个功能都是通过它被访问的次数来跟踪的,而不是花在该功能上的总时间。尽管有用,但是这些数据并没有像最初希望的那样捕捉到项目目标。

现在让我们看一下处理坏数据的流程图!

第 1 步:您能清理或请求新数据吗?

:正如之前的专业建议,除非万不得已,否则不要请求新数据。数据错误是常见的,许多是可以修复的。再次,查看我的帖子这里关于数据清理,更多关于识别和纠正可修复类型错误的见解。

如果错误确实是可以清除的,那么在分析之前就清除。

不幸的是,当前数据集的误差太大,不能简单地清除掉。在众多的探索工具中,我们可以运行 R "plyr "包的 count()函数来确定数据集(df)的频率分布:

正如我们在上面看到的,完整的冥想 _ 特征数据丢失(“NA”),并且什么 _ 应用 _ 类型数据可疑地同质。是的,插补在许多情况下是一种可行的清理技术,但预测整列数据是一种加剧有效性问题的明确方法。

空的沉思 _ 特征栏也表明数据流故障可能是错误的根本原因,因为已建立的应用程序特征的所有数据不太可能丢失。同质的 what_app_type 列也暗示了一个架构错误,因为同样不可能所有 50 个客户端之前只与“教育”应用交互过。

:如果问题的根源是架构本身,简单地请求新数据并不能修复错误。而且,由于错误的程度,清理也是不可能的,我们被迫进入步骤 2。

第二步:你有足够的有效数据来排除错误吗?

:在得出这个结论之前,要确保你的样本量足够大,能够在剔除有误差的观测值后可靠地运行你的后续模型。如果你不确定,这里有一个关于如何做的外部概述。

此外,确保删除无效数据不会导致系统错误。如果你不确定这需要什么,这里有一个关于这个主题的维基百科概述。

如果您的数据集足够大,可以忽略架构错误而不会产生显著的统计成本,请在数据集被适当地划分后执行您的分析。

:在我们的示例中,数据集的所有列都会受到影响。因此,去除每个有误差的观察结果是不合理的,因为我们将没有任何数据。

此外,请记住,与大型数据集相比,移除观测值对小型数据集的准确性影响更大。让我们再次检查数据集的大小:

我们的特定示例数据集相对较小,只有 50 个观察值,不幸的是,这远远不在“大数据”的范围内。

记住这些警告,我们没有足够的有效数据来排除错误。我们将进入第 3 步。

步骤 3:是否有可用的代理数据?

:代理数据可能与项目目标不直接相关,但仍可用于未测量变量的代理的数据。同样,为了更仔细地了解代理数据的定义,请查看这个维基百科页面。

照片由斯科特·格雷厄姆在 Unsplash 上拍摄

在我们这里的例子中,代理数据可以以历史数据的形式出现(即,由创业公司在较早的时间点收集的具有最接*的相关变量的数据)。历史代理数据也可以以公开可用的数据集或其他公司自愿共享的数据集的形式出现。

更具体地说,我们的虚拟初创公司可能有来自以前项目的数据,这些数据也测量每个功能在较早时间戳被访问的次数。

:为了举例,我们假设“冥想”功能最*才推出,还没有足够的客户端功能交互数据来预测当前项目的准确使用趋势。

因为我们没有冥想特征数据的替代品,所以我们将转到步骤 4。

第四步。可以执行另一次数据收集吗?

是的:这似乎是一个很简单的问题,但在评估答案时,往往会有几个因素在起作用。

其中一个因素是重新运行数据收集的成本。无论是时间费用、重新安排公司优先事项,还是支付参与者、相关技术服务和/或员工本人的实际资金投入,数据收集都会造成预算损失。在前进之前,一定要和你的团队成员商量。

另一个起作用的因素是数据管道本身。如果这些错误实际上是架构性的,那么简单地重新运行集合将会返回最初导致这一步的不一致。为了避免这一点,再次咨询您的团队成员,以确定根管道故障。调查误差前端设计有错误吗?有没有不同的流媒体服务可以更好地与您选择的应用*台集成?在合并多个数据集时,数据是否会丢失?只有当这些问题得到回答,小故障得到适当修正后,数据收集才能再次开始。

一旦解决并批准了架构错误和运行额外收集方法的负担,您就可以在新数据集可用时继续进行分析。

:同样,为了举例,让我们假设你的创业公司是新成立的,资金最少,期限严格。在与您的团队成员交谈后,他们认为及时提供可用数据比拥有最初的完美数据更重要。

这将我们引向流程图中的最终解决方案:修改您的项目目标。因为我们的可用数据无法在团队最初希望的微观层面上衡量之前的应用程序交互是否对客户与当前应用程序功能的交互产生积极影响(即行为是否受到应用程序类型、全部功能的评估以及花在功能上的总时间而非总访问次数的影响),所以必须改变项目目标,以突出宏观评估。

考虑到这一点,您可以模拟一个条形图,将这些新的宏观分析可视化,放入您的演示文稿中。

不像希望的那样进行细致的分析,但总体趋势仍然存在。然而,你确实注意到,与自然假设相反,有应用经验的客户不太可能打开给定的功能。因此,在您的演示中,您肯定会强调,为了更好地分析趋势,可能需要更多关于在每个功能上花费的总时间的数据。您还包括了完全解决潜在架构错误的建议,以便不会加剧未来的数据有效性问题。

最后

记住对数据质量要诚实和现实。无论我们希望以多快的速度完成数据检查和清理,如果没有适当的审查,坏数据将仍然是坏数据。

尽管包含的示例是一个简单的综合示例,但是无论手头的项目有多复杂,流程图步骤都是一样的。将这种简单的方法结合到日常数据预处理中,可以很容易地将不安、浪费的时间和金钱以及使用劣质数据转化为信心、财务效率和高质量的分析✨

参考

我的数据清理框架

Coursera 的“处理数据从脏到干净”课程来自谷歌数据分析证书

确定样本量

观察错误 维基

代理统计 Wiki

两个模特的故事

原文:https://towardsdatascience.com/a-tale-of-two-models-6c0c7a14d1c9?source=collection_archive---------44-----------------------

语言课程:我们如何构建决定通话目的的人工智能模型

由拨号盘提供。

Dialpad 的 ASR 和 NLP 团队在不断创新。事实上,我们最*推出了一项新功能,利用人工智能的力量来检测呼叫的目的,以便客户可以更好地了解常见的交互模式,并从这些模式中提取可操作的见解。

然而,正如我们所发现的,打电话并不像看起来那么简单。查看我们关于为什么我们建造这个和的其他文章,我们查看了的数据以获得额外的背景。在这篇文章中,我们将深入研究我们为这一特定功能开发的两个人工智能模型,包括我们看到的成功和我们克服的挑战。

更简单的基于规则的模型

首先,根据我们对数据的洞察(参见上面提到的博客,我们构建了一个简单的基于规则或启发式的模型,仅用了几周时间就投入生产。由于 Dialpad 为许多行业的许多企业提供服务,我们不能依赖基于呼叫主题的模型,这种模型经过培训可以识别吸尘器维修的所有方面,对于安排采访或收集教育产品的反馈几乎没有用处。

我们必须找到更通用的东西。

我们训练模型要看的一些东西:

  • 特定词汇模式的存在或缺失,这些模式通常出现在呼叫语句的目的中,例如“呼叫是因为”或“呼叫的原因”
  • 围绕文本上下文——看看之前说了什么,问了什么问题
  • 时间线索—多注意通话的某些部分,如通话的开始或客户帐户验证后的通话部分。
  • 扬声器类别—确定扬声器是发出呼叫的人还是正在接收呼叫的人

在处理模糊会话数据时,该模型必须考虑词汇和结构的可变性,容忍语音识别错误,并处理口语的特性,如不完整的句子和填充词的大量使用。

我们决定首先建立一个简单的模型,原因有两个——在投入更多时间之前衡量客户对该功能的兴趣,以及为有监督的机器学习模型廉价地收集训练数据集。

正如每一位经验丰富的机器学习科学家可以证明的那样,建立一个好的人工智能模型的关键是好的数据。但是组装高质量数据集的成本和劳动可能令人望而生畏。对于这种模式,它将涉及到检查整个通话记录,其中许多很长,有些包含转录错误,并确定通话目的的陈述点。

这需要几个月的时间,而且收集起来相当繁琐。

但是我们的顾客很感兴趣!他们希望这种能力能够检测通话的目的。

因此,我们开始构建一个更强大的模型(功能开发的下一阶段)。

由拨号盘提供。

深度学习模型

启发式模型精确度高,但召回率低,这意味着它没有像我们希望的那样频繁启动——但当它启动时,它非常准确。这实际上是启发式模型的一个常见问题,因为规则是相当生硬、不灵活的工具,不可能解释进行预测时令人眼花缭乱的变量数量。

例如,一个只关注于呼叫开始时检测呼叫目的的规则将错过在呼叫的很晚时候才陈述呼叫目的的时间,而一个关注于匹配陈述的规则将错过呼叫目的作为问题出现的情况。

启发式模型也很难维护,因为组成模型的规则需要定期更新,例如当模型使用的数据在内容或结构上发生变化时。但是由于其有限的范围,基于规则的模型对于最明显的情况来说是相当准确的,并且运行起来很便宜。

这种设置实际上证明了它非常能够生成标记为通话目的陈述的通话记录部分的丰富训练数据集,并由一个人在循环中验证数据子集以确保质量。

然后,用基于规则的模型所遗漏的语言模式来扩充数据集。现在,我们可以用它来训练一个深度学习模型,该模型根据话语表达呼叫目的的可能性来评分。

以前的模型是做出一个二元决策,即命中或未命中,而这一新的概率评分模型能够找到最具信息性的通话目的陈述,一旦更好地代表对话的话语进入系统,该陈述就会实时更新。

因此,在对话开始时出现的以下话语是有效的呼叫目的:

你好。是的,我想和经理谈谈最*的交货问题。

但是,新模型能够捕捉到随后出现的更具信息性的通话目的:

我会解释我打电话的原因。上周,我接到通知,我订购的自行车 X-5 型号将于周二交付,我不得不呆在家里接受交付。我不得不请了一天假,等了一整天,但是没有发生。这辆自行车本周四才到,包装破损,到处都是划痕。我想在这个问题上得到帮助。

以前的模型面临的另一个挑战是检测隐式声明的调用目的。例如,您能猜出“似乎无法登录”是客户打电话的原因还是解决另一个更大问题的步骤吗?

确定这一点的规则将过于复杂和不灵活,但深度学习模型能够从数据中学习这些细微差别,并相应地对话语进行评分。

然而,这种设置有其自身的弱点:深度学习模型非常消耗资源,运行起来非常耗时。为了减少负载,我们开发了简单的规则来过滤提供给深度学习模型的数据,这样它就不必在对话的每个部分都运行。这种过滤机制使得模型快速有效。

这种混合模型目前正在生产中,具有高精度和高召回率,能够捕获更广泛的呼叫目的陈述,更少地依赖于抄本的质量,并且比基于规则的模型更容易维护,因为它无缝地适应变化的数据。

由拨号盘提供。

简洁明了

通话目的陈述,尤其是在通话的早期说出,也可能有其他目的:问候、建立联系、寒暄、确保技术正常工作(你能听到我吗?!),使通话目的难以识别。因此,我们精心设计了一些规则来剔除这些陈述中的错误。曾经是这样的陈述:

很好,谢谢。下午好。我是带拨号盘的本杰明。是的,我能听见你。我正在联系我们的新产品报价。现在打电话合适吗?

现在就像一样简单:“我正在联系我们的新产品报价。”

特别感谢我的同事 Elena Khasanova。

用于分类评估的 F 值的有形变量

原文:https://towardsdatascience.com/a-tangible-variant-of-the-f-value-for-classification-evaluation-8a82092e66e4?source=collection_archive---------41-----------------------

全面证明您的型号选择

作者图片

一旦您开始执行分类任务并尝试不同的分类算法、超参数调整或特征选择,您将需要选择您最喜欢的设置。这绝不是一项微不足道的任务,需要仔细检查您的数据结构以及您想要实现的目标。如果您有不*衡的类,基于准确性选择分类器可能完全不合适 Matthews 系数可能是更好的选择。

有时,您并不关心非类(“0”)的预测,在这种情况下,您可能会根据算法的敏感度来决定算法,即算法检测阳性(“1”)类的能力。然而,一个超级敏感的预测器可能只是一个总是预测“1”的预测器(如图 A 所示),你可以通过其蹩脚的精度立即认出它。

因此,在导致图 A 或图 B 中给出的分类的设置之间进行选择,您应该选择哪个?答案可能取决于您的任务,但*衡您的灵敏度和精确度的一个常用方法是 F1 测量。

F1 测度是 F 测度的特例,F 测度是两个值之间的调和*均值。一般来说,F 值定义为:

在 n=1 的情况下,这变成了众所周知的公式(其中 TP =真阳性,FP=假阳性,f n=假阴性,TN =真阴性):

这是灵敏度和精度之间的合理折衷,有助于您选择在生产中不会出错的算法。然而,一旦你试图理解 F1 值的含义,你就会意识到翻译成人类语言有多么困难。毕竟,什么是谐波呢?虽然您可以将精确度表示为真阳性与预测阳性病例的比例,但是 F 值并不容易解释。

当我和戴维·汉德以及他在澳大利亚国立大学的合作者争论基于 F 值的算法时,这困扰了我。他们提议将 F 值稍微转换成他们所谓的“F*”:

因此,F可被解释为所有样品的真阳性与真阳性、阴性、但预测阳性以及遗漏阳性的比率。或者,作为除了正确的阴性预测之外的所有样品的真阳性的比率。或者,真阳性与所有误分类或正确阳性预测样本的比率。作者还表明,F 和 F密切相关,不太可能基于 F 做出决定,而基于 F*做出的决定会有所不同。

对于从业者来说,这意味着 F 值可以安全地用 F*代替,从而获得可解释性,并为客户报告提供更具体的内容。

[1] Hand,D.J .,Christen,p .和 Kirielle,n . F:F-测度的可解释转换。马赫学 (2021)。https://doi.org/10.1007/s10994-021-05964-1

线性回归的技术探讨

原文:https://towardsdatascience.com/a-technical-dive-into-linear-regression-7636077f42aa?source=collection_archive---------37-----------------------

了解在尝试解释线性模型结果之前应考虑哪些因素

Teo Duldulao 在 Unsplash 上的照片

众所周知的线性回归模型可能是数据科学家口袋里的第一批工具之一。虽然被视为“简单”,但它的潜力不应该被低估,尤其是如果你有兴趣做预测,同时也了解它们背后的原因。事实上,许多研究人员继续使用这一伟大的工具,通过各种商业和科学领域的数据进行推理。然而,在一些情况下,在花了一些时间试图解决“现实世界的问题”之后,数据科学家倾向于将线性回归模型降级,并将他们的注意力转向具有更强预测能力的算法。当然,所选择的方法应该始终取决于手头的问题和目标,即您只是想回答“什么”还是也需要理解“如何”?。

无论如何,使用线性回归不一定是一项简单的任务,因为它需要时间、统计知识和非线性过程(矛盾的是)来处理数据。这不仅仅是运行一个脚本和验证某些超参数,你需要更深入地挖掘。

在这篇短文中,我们打算总结一下实现线性回归模型时要考虑的主要方面和考虑事项。请注意,这不是处方,而是在试图解释结果之前,了解要考虑什么和注意哪里的指南。

应用程序

正如我们提到的,我们可能有兴趣回答的问题之一是“如何”。例如,了解学习时间与考试成绩、教育水*和工资之间的关系;或者也许你拥有一个企业,并有兴趣了解边际增长的销售每一美元花在一个特定的营销活动。无论哪种方式,您都会注意到每个例子中的关键是“理解”这个词,它可以被解释为理解变量之间的相关性。在这种情况下,线性回归非常有助于捕捉一些可解释的模式,并“给出”一些关于数据背后发生的事情的想法。

作为复习,当应用线性回归时,我们假设数据存在某种“函数或自然分布”,这种分布不能直接看到,但可以使用来自人群样本的一组特征进行部分估计。特别是,这一假设涉及许多考虑因素,我们应该对其进行测试和验证,以便能够就结果的“准确性”进行辩论。

示例:R 中的线性回归模型分析

话虽如此,让我们从一个用 R 实现的实际例子开始,但首先是一个简短的上下文介绍。

假设你计划下周末和几个朋友去钓鱼,你想让他们大吃一惊,告诉他们你只用卷尺就可以非常精确地估计鱼的重量。但这还不是全部!你也可以告诉他们鱼的重量可能会有多大的变化,如果任何特定的尺寸测量(垂直长度,高度等。)变化。所以在这一点上,你可能不是你朋友中最受欢迎的,但是你可以赢得一些赌注。

这只是使用我们的线性回归模型和钻研高级技术的一个有趣的背景。在这个例子中,我们将使用鱼市场中常见鱼类的数据库,您可以从 Kaggle 的 Aung Pyae 处获得。这个数据集包含几列,描述了不同的大小和物种的措施,并有 158 个观察。对于这个分析,我们将从使用 3 个简单的尺寸测量变量开始:垂直长度、高度和对角线重量(所有变量都以厘米为单位)。这些变量是我们模型的预测器。对于响应变量,我们有鱼的克重。所以现在,我们去钓鱼吧!

导入包

library(MASS)
library(Kendall)
library(car)
library(corrplot)
library(RColorBrewer)

创建绘制残差的函数

首先,我们将创建一个函数,允许我们绘制回归模型产生的残差。在这种情况下,我们采用学生化残差,因为它们在执行后续异方差分析时比原始残差表现得更好。这是因为理论线性模型中的方差被定义为“已知的”,而在应用中,样本方差是估计的,因此原始残差可能在误差中显示异方差,即使残差是同方差的。在这里你可以找到关于这个效果的简要解释。

plot_residuals = function(linear_model){
    res_stud=rstudent(linear_model)
    k=1
    for(i in res_stud){
      if(is.na(i)){res_stud[k]=0}
      else{res_stud[k]=i}
      k=k+1}
par(mfrow=c(1,2))
plot(linear_model$fitted.values,res_stud); abline(0,0); abline(-3,0,col="red"); abline(3,0,col="red")
qqnorm(res_stud); qqline(res_stud, col = 2)
}

导入和浏览数据集

我们最初将使用变量鱼的垂直长度、高度和宽度作为预测值,变量“重量”作为响应变量。

df_fish = read.csv('Fish.csv',header=TRUE)
selected_cols = c('Weight','Length1', 'Height','Width')
df_fish = df_fish[,selected_cols]
attach(df_fish)summary(df_fish)

删除有错误的行

在对数据进行简要回顾后,我们发现一个“权重”等于 0 的观察值,因此我们将其删除以避免将来出现问题。此外,应该注意的是,用于随后转换响应变量和预测值的技术要求变量总是取正值。

df_fish = df_fish[Weight!=0,]
rownames(df_fish)=1:nrow(df_fish)

探索数据

我们通过绘制变量散点图和相关矩阵来继续研究数据。我们的目的首先是发现回归变量和响应变量之间的相关性,其次是在预期可能的多重共线性问题中看到预测变量之间的相关性。

# Scatter plot
par(mfrow=c(1,3)) 
pairs(df_fish)# Correlation matrix
M = cor(df_fish)
corrplot(M, type="lower",col=brewer.pal(n=8, name="RdYlBu"))

正如我们从图表中看到的,不仅预测变量和响应变量之间,而且预测变量本身之间似乎也有很高的相关性。这意味着我们将不得不面对多重共线性的问题。

此外,还可以观察到预测值和响应变量之间存在非线性关系,这意味着如果我们要实现一个没有任何变量变换的线性模型,我们将面临残差中的结构问题。

在这方面,我们将继续使用测试和转换技术来评估这些推论,这将允许我们实现模型的更精确的修正。

训练测试分割样本

我们分别使用 80%和 20%的观察值来执行训练和测试分割。

n_sample = floor(0.8*nrow(df_fish))
set.seed(7)
train = sample(seq_len(nrow(df_fish)),size = n_sample)
train_sample = df_fish[train,]
row.names(train_sample) = NULL
test_sample = df_fish[-train,]
row.names(test_sample) = NULL

模型 1

原始线性模型

我们使用 3 个原始预测值和响应变量来拟合第一个模型。然后我们打印回归的结果。

lm_original = lm(Weight~., data=train_sample)
summary(lm_original)

正如我们所料,回归结果显示了回归器的良好性能。事实上,该模型作为一个整体优于其预测由预测响应变量的*均值组成的模型(这种差异在传统的置信水*值上具有统计学意义)。我们可以在 p 值接* 0 的 Fisher 统计量和调整后的 R *方中观察到这一点,其值表明该模型解释了响应变量在其均值附*的 88%的可变性。

此外,当分析模型内每个变量的统计显著性时,我们可以看到鱼的截距、垂直长度(长度 1)和高度在 1%具有统计显著性,而鱼的宽度变量仅在 10%具有显著性。

此外,值得注意的是,根据我们在初始图中看到的,我们可以预期鱼的“重量”和“宽度”之间有更高的相关性或显著性水*。我们所期望的和我们所发现的之间的差异是由于所谓的多重共线性。

这怎么解释呢?我们在开始时看到的效果并不符合变量“宽度”和变量“重量”之间的关系,而是符合这个变量与变量“垂直长度”和“高度”密切相关的事实。当孤立地看待因变量时,它使用其他变量所反映的信息来显示其部分相关性。然而,一旦我们添加了直接影响响应变量的变量,所有这些信息就不再被“宽度”所捕获,从而降低了它的解释力。

检查多重共线性

这种现象的主要问题是什么?在预测因子之间存在很高相关性的情况下,变量的解释效果很难分离,并且在许多情况下会扭曲相关系数的值及其统计意义。您必须记住,在大多数情况下,我们可以发现我们的解释变量是相互关联的,但是当这种相关性很高时,问题就出现了。如果您试图做出推论并需要解释变量,这一点很重要,而在纯预测模型的情况下,这并不相关。

让我们看看在这种情况下多重共线性会发生什么。为此,我们将使用方差通货膨胀因子(VIF),因为它使我们能够理解每个预测因子相对于其他预测因子的相关性(更详细的信息(此处为)并帮助我们定义变量是否可能成为我们模型的风险。

没有确定多重共线性高或低的 VIF 值,但是,在实践中,认为该指数接* 10(或更高)的值可以表示多重共线性,而接* 1 的值表示多重共线性非常低。

vif(lm_original)

观察结果,我们先验地注意到,存在与变量“宽度”相关的更高 VIF。因此,我们将通过消除多重共线性最高的变量来减少模型,并使用剩余模型重新计算 VIF。

型号 2

简化线性模型

现在,我们只使用变量“垂直长度”和“高度”再次拟合我们的模型。

lm_reduced = lm(Weight~Length1+Height, data=train_sample)
summary(lm_reduced)

具有新变量子集的模型结果实际上保持不变。我们实际上可以观察到的是,调整后的 R *方值小幅下降,均方误差小幅上升,变量“高度”的统计显著性水*小幅改善。

检查多重共线性

让我们看看每个预测器的 VIF 发生了什么。

vif(lm_reduced)

正如我们所看到的,对于剩余的两个解释变量,VIF 显著下降。这告诉我们,删除变量“宽度”似乎是一个好决定(越简单越好)。

绘制残差

现在我们已经定义了变量,我们继续对回归结果进行彻底的分析。

在这个过程中,残差分析是充分利用回归模型的基本要素。首先,当使用这种类型的模型时,我们从误差分布的正态性假设出发,不是任何类型的正态分布,而是均值为 0 的正态分布。这让我们能够利用这个模型在推理方面给我们带来的所有好处。

然后,我们使用该函数对残差进行分析,以绘制上述学生化残差。

plot_residuals(lm_reduced)

正如我们在图中看到的,残差和一些异常值中似乎有一种二次结构。这表明使用预测器仍然可以提取一些额外的信息,但是我们必须对变量执行某些转换来提取这些信息。

关于数据的正态性(正态 Q-Q 图),与正态分布的理论分位数相比,我们可以观察到残差分布的一些偏斜和重尾,因此很可能误差的分布不具有正态分布。为了验证这种直觉,我们将使用 Kolmogorov-Smirnov 检验,该检验允许我们比较两个分布是否相等,以及在这种特殊情况下,残差的分布是否类似于均值为 0 且方差等于样本方差的理论正态分布。

检验残差的正态性

lm_reduced_residuals=rstudent(lm_reduced)
ks.test(lm_reduced_residuals,"pnorm",mean(lm_reduced_residuals),sd(lm_reduced_residuals))

Kolmogorov-Smirnov 检验的零假设是两个分布不相等,而另一个假设是两个分布相等。然后,我们将演示在运行测试后,零假设被拒绝(我们需要一个高 p 值)。然而,在这种情况下,我们观察到 p 值小于一些传统的置信水*,因此我们可以说(在 1%的水*上)我们不拒绝零假设,因此我们没有足够的证据表明两个分布是相等的。

异方差:检验残差和拟合值之间的相关性

接下来,我们对检验残差的同方差感兴趣。我们所说的同方差是指误差不会随着模型预测值的增加或减少而增加或减少。这是模型构建中的一个期望属性,因为测试残差中的结构缺失将表明不再有可能对当前使用的变量进行转换,从而允许我们改进模型的性能。

在这种情况下,我们需要证明残差中存在某种一致性,并且它们是尺度不变的。否则,我们将面临最小二乘估计的效率损失,以及在计算估计的方差和协方差矩阵时产生的问题。

这是我们在之前的剧情中已经可以观察到的。然而,我们的目标是能够进行假设检验,使我们能够验证相关性的缺失。

summary(Kendall(abs(lm_reduced$residuals),lm_reduced$fitted.values))

应用检验(肯德尔检验)是一种类似斯皮尔曼检验的相关检验,在计算相关系数(肯德尔检验中的 Tau,斯皮尔曼检验中的 Rho)时有一定优势。更多详情请访问以下链接。

肯德尔检验表明,残差和拟合值之间的相关系数(tau)为正(0.16),在 1%时具有统计显著性。这表明没有足够的证据来支持缺乏相关性的假设,这意味着我们处于异方差残差的情景中。

模型 3

转换响应变量

那么,当残差中有结构时,我们该怎么做呢?我们有两个选项可以帮助我们扭转这个问题:a)转换响应变量,b)转换预测变量。开始执行转换没有正确的方法,但在实践中,通常的做法是从转换响应变量开始,并在提出新的转换之前重新评估结果。

然后,我们将从使用 Box-Cox 最大似然技术转换变量“权重”开始,因为它允许我们估计一个λ值,变量可以转换为 x 次λ(希望这将减少残差中的结构)。更多详情请访问以下链接。

y_transformed=boxcox(lm_reduced)
y_transformed$x[which.max(y_transformed$y)]

结果表明,对变量“权重”的一种可能的变换是应用λ幂= 0.38。请注意,这种量级的转换会使模型最终结果的解释变得复杂。为了解决这个问题,一般来说,最好是应用一个接*建议值的变换,这仍然允许我们容易地解释系数。为此,我们选择对数变换。

运行响应变量转换后的线性模型

lm_transform_y = lm(log(Weight) ~ Length1 + Height, data=train_sample)
summary(lm_transform_y)

在应用这个转换之后,我们注意到模型的性能有了一个微小但重要的改进。我们可以观察到调整后的 R *方增加了 1%以上,同时保持了模型本身和预测因子的统计显著性水*。关于误差,重要的是要强调,现在它与以前的情况不可比,因为响应变量在另一个尺度上。

绘制残差

plot_residuals(lm_transform_y)

那么,我们解决问题了吗?当评估误差的结构时,第一次变换不仅没有逆转异方差问题,而且似乎“恶化”了残差的分布,这远远不是正态分布。

让我们看看测试会发生什么。

检验残差的正态性

lm_transform_y_residuals=rstudent(lm_transform_y)
ks.test(lm_transform_y_residuals,"pnorm",mean(lm_transform_y_residuals),sd(lm_transform_y_residuals))

残差的分布越来越远离正态分布,正如我们在新的 p 值(当前为 0.01,之前为 0.04)中看到的那样。因此,我们继续拒绝误差分布的正态性。

异方差:检验残差和拟合值之间的相关性

summary(Kendall(abs(lm_transform_y$residuals),lm_transform_y$fitted.values))

关于异方差,它似乎也“恶化”了,虽然只是轻微的,所以我们仍然不能扭转这个问题。

模型 4

转换预测值

然后我们继续讨论预测因子的转换。为此,我们将使用 Box-Tidwell 最大似然变换技术,像 Box-Cox 变换一样,该技术将允许我们理解从解释变量中提取更多信息的建议λ功效是什么。

boxTidwell(log(Weight) ~ Length1 + Height ,data=train_sample)

获得的结果建议对可变长度 1 应用λ= 0.007 的变换,对可变高度应用λ=-0.38 的变换。在这两种情况下,建议的转换在 1%的水*上具有统计学意义,如两个变量的 p 值所示。因此,我们又一次处于这样一个场景中,相对于建议的值进行过于精确的转换可能会使结果的后续解释变得非常复杂。因此,我们再次选择对两个变量进行对数变换。

使用转换后的响应变量和预测值运行线性模型

有了这些新的转换,我们继续再次调整我们的线性回归模型。

lm_transform_y_X = lm(log(Weight) ~ log(Length1) + log(Height), data=train_sample)
summary(lm_transform_y_X)

可以看出,作为一个整体进行的转换对模型的性能产生了实质性的改善,其中调整后的 R *方显示了约 9%的增加,同时保持了模型和预测值的统计显著性水*。

绘制残差

plot_residuals(lm_transform_y_X)

当分析残差图时,我们还可以观察到残差结构的简化和接*正态分布方面的显著改进。

检验残差的正态性

lm_transform_y_X_residuals=rstudent(lm_transform_y_X)
ks.test(lm_transform_y_X_residuals,"pnorm",mean(lm_transform_y_X_residuals),sd(lm_transform_y_X_residuals))

最后,我们已经能够拒绝零假设(p 值= 0.5!)因此,对于当前模型,没有足够的信息来证明残差的分布是不正常的。实际上,这个绕口令可以归结为这样一个事实:残差可以被认为是正常的。

异方差:检验残差和拟合值之间的相关性

summary(Kendall(abs(lm_transform_y_X$residuals),lm_transform_y_X$fitted.values))

最后但并非最不重要的是,我们还发现残差和拟合值(0.01)之间的相关性显著降低,p 值较高(0.84),这表明没有足够的证据甚至可以说存在的少量相关性具有统计显著性。所以我们颠倒了异方差的问题。

结果

事不宜迟,这里是我们的最终模型及其结果。

正如我们已经提到的,该模型的性能似乎非常好,决定系数(调整后的 R *方)接* 99%,因此仅用变量“垂直长度”和“高度”我们就可以解释变量“体重”的几乎所有变化。换句话说,我们的朋友没有机会在赌注上击败我们。

此外,正如我们强调的,我们很好地说明了这种类型的模型还允许我们推断预测因素对响应变量的部分影响(在这种情况下,我们不讨论因果关系),由于应用的变换是对数函数,我们可以将系数解释为解释变量的百分比变化。换句话说,当转换建立了一个对数-对数模型(对数中的响应变量-对数中的预测变量)时,我们就有可能用百分比变化率来解释偏相关。

这样,伴随转换后的变量 log (Length1)的系数接*于 2,这告诉我们,如果我们没有捕获我们刚刚捕获的鱼,而是捕获了一条长 10%的鱼,那么这些鱼的估计重量将比我们现在所拥有的大约重 20%。类似地,伴随转换后的变量 log(高度)的系数接* 1,这告诉我们,如果我们没有捕获我们刚刚捕获的鱼,而是捕获了一条高度高 10%的鱼,这种类型的鱼的估计重量也将比我们现在拥有的重 10%左右。

这太棒了!我们已经将系数转换成因变量和每个预测值之间的弹性度量。没错,我们连规模都不在乎!

有了这个我的朋友,放心你会成为书呆子钓鱼之王的。

结论

总之,这个简单的实际例子让我们能够处理大量的概念并深入研究线性回归模型。有趣的是,就像这个玩具例子一样,许多次线性模型,无论它们看起来多么简单,都可以有非常好的表现,同时让我们有可能从结果中获得非常有价值的见解。记住,问题的最佳答案并不总是最复杂的。

定制和分布式培训的模板

原文:https://towardsdatascience.com/a-template-for-custom-and-distributed-training-c24e17bd5d8d?source=collection_archive---------32-----------------------

使用此模板快速编写自定义张量流算法

定制训练循环提供了极大的灵活性。您可以快速添加新功能,并深入了解算法的工作原理。然而,一遍又一遍地设置自定义算法是乏味的。总体布局通常是相同的;只有很小的部分会改变。

这就是跟随模板的发挥作用的地方:它概述了一个定制的分布式训练循环。所有需要修改以适应任务的地方都用待办事项突出显示。

照片由克里斯里德在 Unsplash 上拍摄

自定义分布式循环的一般布局

定制训练循环——与调用 model.fit()相反——是一种迭代数据集、更新模型权重和计算任何指标的机制。

在迭代任何数据集之前,无论是训练、验证还是测试分割,数据集都必须准备好分发。这是借助 TensorFlow 的分发策略对象完成的。

我们首先创建策略对象,它负责所有的分布式计算。通过选择不同的分发策略,我们可以在各种计算环境中使用我们的算法。这一事实使得定制循环高度灵活。

在第 2 行,在创建了我们的策略之后,我们准备好了我们的数据集分布;TensorFlow 处理所有内部细节。

对于我们的分布式数据集,我们可以使用“ for i in x ”方法对其进行迭代:

该循环对于所有子集(训练、验证、测试)都是相同的。主要区别是被调用的步骤。上面,我示例性地调用了 distributed_train_step ,它处理我们的数据到所有加速器的分发。但是不要担心,TensorFlow 处理大部分内部设备到设备的通信。我们只有它知道我们想做什么。方法已经为我们做好了。

作为培训、测试或验证步骤的一部分,我们还会更新我们希望在培训期间跟踪的任何指标。我们必须手动执行此操作,如下所示:

在这里,我编写了一个训练步骤,该步骤采用单个数据批次,将其解包为要素和标注,计算梯度,更新模型,并计算任何训练度量。这种方法类似于验证和测试步骤;我们只跳过模型更新。

概括总体布局:

  • 准备好分发所需的对象(模型、数据集、优化器、指标)
  • 迭代数据集
  • 调用分布式训练/测试/验证步骤来更新模型并计算指标

总体布局到此为止。在接下来的内容中,我们将检查模板,看看您需要为手头的任务修改什么。

分布式定制培训模板

我们从必要的导入和一些全局定义开始:

对于这个模板,我决定将训练、测试和验证步骤中使用的所有对象和变量设为全局。这样,我们就不必一直传递它们,这使得代码更干净。然而,这只是一种方法,我相信还有更好的方法。

所有模型及其优化器都是全局可用的,任何度量和损失也是如此。我没有在模板中包括测试和验证损失,但是我强烈建议您这样做。除此之外,我们还全局注册全局批量大小和分配策略(如前所述)。

我们的训练脚本是用几个示例命令调用的,所以我们还导入了 argparse 库。完整脚本的代码是

并引出了主要的方法:

主要方法

main 方法从使用我们之前介绍过的大部分全局对象开始。到目前为止,它们只是占位符,这就是我们现在实例化它们的原因。我们从分布策略(第 13 行)开始,然后是损失(第 16 行)、指标(第 19 行)和模型(第 22 行)。我们将很快详细介绍所有被调用的方法。

在这个模板中,我跳过了数据集创建部分。有太多的方法可以做到这一点,你知道什么最适合你的问题。从第 26 行开始,我只使用了 None 作为初始值;将这一部分替换为创建和分发数据集(使用前面代码片段中显示的策略)

从第 31 行开始,我们首先使用分布式训练和验证数据集训练模型,然后在保留测试数据集上评估它。

损耗

第一种方法 create_loss_objects ,负责创建我们使用的任何损失。如下所示:

在分配策略的范围内,我们创造任何我们需要的损失。在示例代码中,这只是一个虚拟损失——修改它以满足您的需要。无论选择哪个损耗,不要忘记设置如图所示的减少参数:我们在后面的方法中手动减少损耗。无论您使用单个损失还是多个损失,都在这里创建并返回对象。您应该全局注册所有返回的亏损对象。我已经对样本 train_loss_object1 执行了此操作。对所有损失重复此步骤。

韵律学

创建用于跟踪模型进展的指标的代码遵循相同的方案:

在分布策略的范围下,我们实例化所有的度量。在模板中,这只是训练精度。缺少的是任何验证(在培训期间)和测试(在培训之后)的度量。我建议在打印时使用有意义的名称来标识指标。像以前一样,全局注册所有返回的指标。在方法中,我已经用第 9 行中的 train_metric1 实现了这一点。

在实例化指标之后,我们现在关注模型和优化器。这种模板方法遵循前两种方法:

和以前一样,我们在选择的策略范围内创建任何东西。这一步是强制性的,以使模型的内部变量和优化器分布准备就绪。在示例代码中,我没有选择任何特定的模型或优化器;修改第 8 行中的任何内容以适合您的任务。此外,不要忘记全局注册返回的对象,正如我在 main 函数的第 9 行中对模型优化器所做的那样。

数据集

在所有必需的对象都被实例化并准备好发布后,就该创建数据集了。我有意将此留作空白,因为创建数据集有多种方法:从 tf.data.Dataset 对象到定制生成器或混合方法。你可以在这里找到概述,但是因为这个模板是面向更有经验的程序员的,我怀疑它对你是否有必要。无论如何,在创建数据集之后,您必须使用

一旦数据集准备好,我们就可以继续训练循环(主中的第 31 行)。对于我们使用的模板,我们需要训练和验证数据集,但是您可以随意放弃后者。

训练和验证循环

训练循环是我们分布式算法的核心:

在第 12 行,我们开始在数据集上迭代个时期次。然后,从第 15 行到第 20 行,我们对训练数据进行循环,并将每一批数据提供给 distributed_train_step 方法。在我们完成一次迭代之后,我们计算训练损失,并对验证数据重复这个过程。

完成之后,我们查询所有(全局)度量和丢失对象的当前值,我们打印并为下一个时期重置这些值(第 34 到 39 行)。正如评论所指出的,修改这段代码以考虑任何度量或损失对象。此外,如果您不在每个时期后重置度量(第 37 行),它们将跟踪所有时期的进度,导致错误的每个时期值。

分布式训练步骤

训练循环(从第 17 行开始)在内部调用分布式训练步骤。这个的代码是

我们在这里没有太多事情要做:我们得到一个数据批次( dataset_inputs ),告诉策略运行一个单独的训练步骤,并减少返回的损失。现在,我们为什么不直接调用 train_step ?因为我们处理分布式数据。第 5 行中的 strategy.run 调用说明了这一点;为每个计算设备调用它。例如,如果我们连接了 5 个 GPU,TensorFlow 将自动调用 train 步骤五次。

然后,我们必须合计(考虑“合并”或“合并”)从每个副本到当前设备(我们运行脚本的地方)的火车损失,并减少它以考虑加速器的数量。查看文档了解更多信息。

训练步骤

如果我们没有分配我们的工作负载,我们可以直接调用实际的 train 步骤。然而,由于我们使用的是分布式设置,我们必须让 TensorFlow 知道。我们使用前面的方法做到了这一点,该方法使用 strategy.run 来处理分发。在这个调用中,我们说实际的训练方法是 train_step 方法,如下所示:

由于 TensorFlow 负责拆分批处理,因此我们接收的是单个批处理。在第 9 行,我们将它分解成特性和标签——这只是一个例子,根据您的需要修改代码。接下来的几行遵循一个标准的定制循环:我们计算损失(第 15 行),计算并应用梯度(第 18 行和第 19 行),并更新任何训练指标(第 22 行)。正如我在 TODO 注释中所做的标记,您必须对此进行调整,以考虑您所使用的所有模型、损失和指标。

计算(培训)损失

为了计算培训损失,我们使用以下简短模板:

我们在第 10 行查询我们的 loss 对象,它给出了每个副本的损失。让我解释一下:我们的定制算法运行在多个计算设备或副本上。在每个设备上,独立调用训练步骤,导致总共 n 个损失。每个损失现在用于计算梯度,通过求和在复制品之间同步。如果我们不衡量损失,结果会被夸大。

还不服气?在单台机器上,损耗除以小批量样品的数量。在多 GPU 设置中,我们不必将损失除以本地批量大小,而是除以全局批量大小。例如,本地批处理大小可能是 8,而全局批处理大小可能是 32 (=4*8 代表 4 个 GPU)。如果除以 8,我们会假设我们在正向传递中看到的样本总数是 8,这是不正确的。因此,在第 14 行中,我们对损失进行*均,以考虑全局批量大小。

那是为了训练程序。总结一下:我们首先调用 distributed_train_step ,它负责将计算分发给每个工人。然后,在每个工人身上,调用 train_step ,它接受一个批处理并更新模型的权重。

验证步骤

验证程序与培训程序非常相似:

只有微小的区别:我们不更新模型的权重(第 11 行),我们更新我们的验证指标(第 13 行)。修改这些部分以适应你的需要。distributed _ validation _ step遵循与 distributed_train_step 相同的布局:获取按比例缩放的每个副本的损失并将其合计(第 25 至 28 行)。

测试回路

测试循环与前两个相似:

我们迭代分布式测试数据集(第 11 行),对损失求和(第 12 行),并对其求*均值(第 14 行)。之后,我们收集所有指标的结果。我没有包括任何单独的测试指标;根据您的需要修改这一部分(第 16 行和第 17 行)。

一旦我们查看了 distributed_test_step (第 12 行),我们会注意到它再次高度相似:

在第 32 行中,我们收集了缩放后的损失,并在第 36 行中对其进行*均。实际的 test_step (第 2 行)取一个批次,打开它(第 9 行),并计算损耗(第 16 行)和任何测试指标(第 18 行)。在这个片段中,我没有包括任何单独的测试指标。你必须调整它以适应你的问题。通常,您可以在 create_metrics 方法中创建所有指标。记住要全局注册它们,以便能够轻松访问它们。

摘要

我们已经讨论了定制和分布式算法的基本部分。通过选择适当的分布策略,我们可以将它用于各种计算环境,也可以用于单 GPU 设置。一般来说,所有需要修改的地方都标有 TODO 注释。虽然模板应该涵盖大多数用例,但它只是作为一个起点。像你我这样的从业者应该调整关键部分以满足他们的需求。完整的代码可以在 GitHub 获得。

编写快速机器学习应用程序的模板

原文:https://towardsdatascience.com/a-template-for-writing-quick-machine-learning-apps-7c7b8bdfeb91?source=collection_archive---------38-----------------------

在 Unsplash 上由Cookie Pom拍摄的照片

使用 PyTorch 和 Streamlit 加速您的机器学习原型

ML 应用原型

开发一个机器学习模型的过程可以是很多事情:从一个有益的学习体验,到一个可怕和令人沮丧的低准确性和调试噩梦的过程。机器学习工作流程的一个方面曾经很棘手,那就是原型阶段,在这个阶段,我们希望有一个简单的界面来展示我们模型的功能。

编写数据应用程序的框架 Streamlit 填补了这一空白,它让人们能够尽快赋予他们的人工智能模型生命,而无需编写成熟的 GUI。

在这篇文章中,我将向你展示一个用 Streamlit 和 Pytorch 编写简单 ML 应用程序的模板。

从模型到原型

在这个例子中,我们将编写一个简单的图像分类应用程序。编写人工智能应用程序的步骤如下:

  1. 导入依赖关系

2.写一个标题,顶部有一个漂亮的标志图像

输出:

图片由作者提供。来自 Unsplash 的 Jason Leung 的标识

3。设置文件上传程序以加载图像

输出:

图片由作者提供。来自 Unsplash 的 Jason Leung 的标识

4.编写一个脚本,加载一个预先训练好的模型来运行推理

在这里,我们可以将训练模型的权重放在一个文件夹中,或者从标准库中加载一个预训练模型。在这个例子中,我们将使用 PyTorch 库加载 Resnet 模型。

在此之前,我们需要下载 imagenet 类:

# source: [https://pytorch.org/hub/pytorch_vision_resnet/](https://pytorch.org/hub/pytorch_vision_resnet/)
!wget https://raw.githubusercontent.com/pytorch/hub/master/imagenet_classes.txt

现在,我们可以编写加载模型和运行推理的脚本了:

在这里,我们在图像上做一些基本的转换,比如调整大小,裁剪,然后把它输入到我们的模型中。我们在这里创建的函数predict()将从我们的主应用程序中调用,如下所示:

5.加载测试图像

为了加载样本图像进行测试,我们将使用与本 Pytorch 教程中相同的示例,

最终的应用程序如下所示:

图片由作者提供。来自 Unsplash 的 Jason Leung 的 Logo

我们可以看到底部的分类是萨摩耶,这是我们讨论的狗的品种。

关于人工智能应用的最后一点说明

在本教程中,希望你学会了如何编写一个简单的人工智能应用程序来使用 Streamlit 和 Pytorch 对图像进行分类,你可以在这里找到完整的源代码。

在本文中,您了解了:

  • 如何用 Streamlit 写一个简单的图像分类 app
  • 如何设置一个脚本,用 Pytorch 加载一个预先训练好的模型进行推理

如果你喜欢这篇文章,请在 Twitter 、 LinkedIn 、 Instagram 上联系我,并在 Medium 上关注我。谢谢,下次再见!😃

参考

  • Pytorch Vision ResNet
  • 流线
  • Pytorch

时间序列分析彻底指南

原文:https://towardsdatascience.com/a-thorough-guide-to-time-series-analysis-5439c63bc9c5?source=collection_archive---------12-----------------------

理解时间序列数据的组成部分。将机器学习和统计模型应用于现实生活中的数据。

来自 Unsplash 的

本文将指导您完成以下部分:

  1. 什么是时序数据?
  2. 时间序列数据的组成部分。
  3. 时间序列分析有什么用?
  4. 最常用的时间序列预测方法(统计和机器学习)。
  5. 使用机器学习模型预测气候数据的端到端示例。

事不宜迟,我们开始吧!

1.什么是时间序列数据?

一个 时间序列 是一系列 数据点 按时间顺序索引(或列出或绘制)。最常见的是,时间序列是在连续的等间隔时间点拍摄的 序列 简单来说,时间序列数据是一个数据集,它随着时间的推移跟踪一个样本,并定期收集。例如,商品价格、股票价格、房价、天气记录、公司销售数据以及心电图等患者健康指标。时间序列数据广泛存在于我们的生活中。因此,作为一名数据科学家,分析数据的能力至关重要。玩起来也很有意思。

患者的心电图数据(来自 MIMIC-III 波形数据库的图像)

2.时序数据的组成部分

大多数时间序列数据可以分解为三个部分:趋势、季节性和噪声。

趋势 — 数据有一个系列的长期运动,不管是向上还是向下。它可能是由人口增长、通货膨胀、环境变化或技术的采用引起的。例子可以是过去十年美国股票市场的长期增长,以及过去一年世界大部分地区房地产市场的增长,以及人们寿命的延长。

过去五年美国鳄梨价格的趋势(图片由作者根据 Prophet 模型生成)

季节性 —数据与日历相关的影响相关联,无论是每周、每月还是季节性的,并且是特定于域的。例如,对于大多数电子商务*台来说,他们在 12 月份左右的销售额因为圣诞节而上升。相比之下,对于房地产来说,加拿大夏季的房屋销售量会高于冬季,因为人们不愿意在冬季四处迁移。

季节性很强的德里气温数据(图片由作者提供)

噪音 —噪音也被称为残留物或不规则物。这是除去趋势和季节性之后剩下的东西。这是不可预测的短期波动。有时,与趋势和季节性相比,噪声可能占主导地位,使这种时间序列数据更难预测。股票价格就是一个明显的例子。

白噪声是没有趋势和季节性的噪声的极端情况。因此几乎不可能预测,这是一种*稳的时间序列数据。

白噪声(图片来自维基媒体共享)

3.时间序列分析有什么用?

时间序列分析在多个行业有不同的用例。根据一般经验,它可用于以下情况:

  • 基于历史数据预测未来价值,如预测房价、售价和股价。
  • 识别经济、业务或健康指标中的异常值或波动,也称为异常检测。例如,当经济受到地缘政治事件或患者生命体征不规则性的影响时,可以确定转折点。
  • 模式识别、信号处理、天气预报、地震预测等。

4.最常用的时间序列预测方法

文献中有一些时间序列预测模型。我将在本文中介绍使用最广泛的:脸书先知,一个叫做 LSTM 的深度神经网络模型,以及 ARIMA。

脸书先知

正如在文档中所述, Prophet 是一种基于加法模型预测时间序列数据的程序,其中非线性趋势符合每年、每周和每天的季节性,加上假日影响。 它最适用于有强烈季节效应的时间序列和几个季节的历史数据。Prophet 对缺失数据和趋势变化非常稳健,通常能够很好地处理异常值。 这意味着 Prophet 已经考虑到了上面提到的所有组成部分:趋势、季节性和噪音,加上假日效应,并将其与一个加法模型相结合。

Prophet 有一个 Python API 和 R API。这很容易实现和预测。

在下一节中,我们将应用这个模型来预测印度的气温。

LSTM(长短期记忆)

LSTM 是一种递归神经网络(RNN ),擅长处理序列数据。它广泛应用于机器翻译和语音识别。如果你已经熟悉 RNN 的结构,LSTM 在每个细胞中添加了三个特殊的门,以记住长期和短期记忆,而香草 RNN 模型不擅长记住长期序列。

LSTM 各牢房的结构(来源)

前一幅图像中的符号(来源)

你也可以参考这篇博客来更好地了解 LSTM 和这篇博客来亲自动手用 Python 中的 LSTM 预测一个时间序列数据对一条国际航线的乘客量进行预测的问题。

ARIMA

ARIMA 是自回归综合移动*均的统计方法的简称。自回归意味着模型使用一个观察值和一些滞后观察值之间的依赖关系。综合是指对原始观测值进行差分(例如,从上一时间步的观测值中减去一个观测值)以使时间序列*稳。移动*均是指模型使用观测值和应用于滞后观测值的移动*均模型的残差之间的相关性。听起来有点混乱;然而,我们不会在文章中深入探讨这种方法,但您可以转到这篇博客来更好地了解。它将向您全面介绍 ARIMA 以及如何使用 Python 在洗发水销售数据集上实现 ARIMA。

5。利用脸书预言家预测印度日*均气温

太好了!现在,您更好地了解了什么是时间序列数据,它是用什么构造的,它的用途是什么,以及最常用的预测模型。现在是时候摆弄一些现实生活中的数据并开始预测了!你可以通过这个 git 回购拿到笔记本。

我们正在使用的数据集提供了 2013 年 1 月 1 日至 2017 年 4 月 24 日印度德里的训练和测试气候数据,具有四个特征:*均温度湿度、 风速、*均气压。它是从 Weather Underground API 收集的,并发布在 Kaggle 上。

我们将使用 Google Colab 作为我们的 python 笔记本,让我们首先安装所需的包。

pip install pystan==2.19.1.1 prophet

我们正在安装一个不熟悉的名为 pystan 的包。在引擎盖下,Prophet 正在使用 stan 进行优化(如果用户需要,还可以进行采样),Stan 是一个用于统计建模和高性能统计计算的*台,而 pystan 是 Stan 的 python 接口。

导入必要的库:

import pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom prophet import Prophetfrom datetime import datetimefrom prophet.plot import plot_plotly, plot_components_plotly

然后让我们从 Kaggle API 下载数据。可以参考我另一篇关于如何从 Kaggle 下载数据到 Google Colab 的帖子。我把代码贴在这里供参考:

! pip install kaggle
from google.colab import drive
drive.mount('/content/gdrive')import os
os.environ['KAGGLE_CONFIG_DIR'] = "/content/gdrive/My Drive/TimeSeries"  #The folder TimeSeries is where you kaggle.json file is.!kaggle datasets download -d sumanthvrao/daily-climate-time-series-data!unzip \*.zip && rm *.zip

压缩数据集 zip 文件夹后,我们可以找到一个训练数据集和一个测试数据集。我们将使用训练数据集来训练我们的 Prophet 模型,并使用测试数据集来测试模型的准确性。

df = pd.read_csv('/content/DailyDelhiClimateTrain.csv')
df_test = pd.read_csv('/content/DailyDelhiClimateTest.csv')

训练和测试数据集都有五列,我们可以使用其中任何一个功能作为预测的标签。作为一个例子,我们将在教程中使用 meantemp 。Prophet 只需要两个有特定名称的列:“ds”和“y”。所以下一步是过滤掉列并重命名它们。小心两个数据集中的重复:日期 2017–01–01 存在于两个数据集中。您可以在任一数据集中删除它。在我的例子中,我在训练集中删除了它,并将其作为一个预测日。

df=df[['date','meantemp']]df=df.rename(columns={'date':'ds','meantemp':'y'})pd.to_datetime(df.ds)# Delete the last row (2017-01-01)
df = df[:-1]df.head()

这是数据现在的样子,准备输入到 Prophet 模型中。

先知训练数据的前五行(图片由作者提供)

让我们初始化模型和预测!我们将预测未来 114 天,因为测试数据具有确切日期的真实值。

# Initialize model
m = Prophet(interval_width=0.95, yearly_seasonality=True, weekly_seasonality=True,daily_seasonality=True)# Add monthly seasonality to the model
m.add_seasonality(name='monthly', period=30.5, fourier_order=5, prior_scale=0.02)# Fit the model with training data and make prediction
m.fit(df)
future = m.make_future_dataframe(periods=114)
forecast = m.predict(future)
fig = m.plot_components(forecast)

温度时间序列数据的组成部分(图片由作者提供)

figure = m.plot(forecast)

预言家预测图(图片由作者提供)

让我解释一下上面的图表。黑点是我们从 Kaggle API 中获得的历史数据。深蓝色线是预测数据。浅蓝色的上限和下限也是基于 80%的置信区间预测的。你可以看到蓝色的数据在黑点之后,这些是 114 天的预测。

您还可以使用 Plotly 生成一个交互式图表,以便更好地理解数据点。

plot_plotly(m, forecast)

Plotly 生成的交互图(图片由作者提供)

一切就绪!让我们看看先知有多准!

我们将使用度量标准的 R *方来检查准确性。幸运的是 Python 在 sklearn 库中有一个内置函数。还是直接用吧!

from sklearn.metrics import r2_scorey_true = df_test.meantempy_pred = forecast.yhat.tail(114)r2_score(y_true, y_pred)

预测值和真实值之间的 R_squared(图片由作者提供)

准确度还不错!通过配置 Prophet 模型的参数,应该可以达到更好的效果。例如,添加变点和假日;改变季节性参数。

接下来,我们可以构建一个 web 应用程序,并将模型部署到云中。但是我们今天已经讲了很多了,关于如何部署模型的话题我就不细说了,但是如果你有兴趣,请在下面留下评论。我将撰写另一篇关于使用 Django+JQuery+Heroku+VSCode 堆栈将机器学习模型部署到动态 web 应用程序的帖子。

感谢阅读。如果你有任何想法或建议,请告诉我,我很乐意在 Linkedin 上帮你联系。

波士顿大学应用数据分析硕士课程的全面回顾

原文:https://towardsdatascience.com/a-thorough-review-of-boston-universitys-ms-in-applied-data-analytics-program-f3599be9aade?source=collection_archive---------19-----------------------

alevision.co在 Unsplash 上拍照

试着不要有偏见

在我开始这个硕士项目之前,我正在寻找不同硕士项目的课程,并试图找到其他人的评论,以了解哪个项目适合我。现在,由于我的硕士课程即将完成,我想我应该写一篇评论来帮助其他正在寻找数据科学或分析硕士课程的学习者。

在我进入 MS 程序之前,这里是我的背景。我有土木工程学士学位和环境工程硕士学位。所以,我不是计算机专业出身。我参加了为期六个月的编程训练营,并在 Coursera 上学习了很多关于 Python、应用数据科学、机器学习和统计学的在线课程。所以,我有一个很好的基础,即使我没有计算机科学的背景。

我会试着详细解释如果你不带偏见或评判地选择这样做,你会得到什么

微软程序

这是一个完整的基于课程的硕士项目。但是在整个项目中会有很多项目。总共有八道菜。六门必修课和两门选修课。六要素是算法分析,用 R 打好分析基础,用 R 打好数据分析和可视化,用 Python 打好 Web 分析和挖掘、数据挖掘、数据科学。选修课有多种选择,如机器学习、大数据分析、高级数据库管理、设计和实现数据仓库、数理统计。

我肯定选择了所有的要点,并选择了机器学习和大数据分析作为选修课。我就从这六个要领开始一个一个来说。

算法分析

这是一门强化课程。研究了算法的时间和空间复杂度,以及常用的算法,如搜索排序算法、图论算法、动态规划、记忆算法等。要在这七周内真正掌握所有这些是不可能的,但它提供了一个很好的基础。有时候,所有的材料对于一个没有计算机科学背景的学生来说可能是压倒性的,但它是可以管理的。特别是,我们每周都有很棒的辅导员会议来帮助完成作业。

R 分析的基础

本课程从一开始就教授 R 编程的基础知识。如果你没有任何 R 编程知识,没问题。从头说起。但是它移动得非常快。因为我已经非常了解 Python,所以我学得相当快。所以,如果你知道另一种编程语言,你是好的。本课程讲授使用 base R 进行数据分析和数据可视化的不同库。在本课程的稍后部分,将转向概率分布和抽样方法等统计主题。本课程还涉及正则表达式和文本挖掘。

数据分析和可视化与 R

这是前一门课的续篇。它从上一门课程结束的地方开始,继续学习更高级的统计学主题。本课程教授一些更高级的库,用于数据分析、假设检验和数据建模。学完这两门关于 R 的课程后,任何人都应该对使用 R 进行数据分析和建模感到舒服了。

网络分析和挖掘

本课程涵盖文本挖掘、web 数据挖掘、文本数据建模、从社交媒体中提取数据以及使用文本数据生成仪表板。你可以看到,在文本数据上做了很多工作。这大部分时间使用 R 编程语言。仅在前两周允许使用 Python。

数据挖掘

坦白说,我在这门课中第一次知道机器学习模型属于数据挖掘,这感觉很奇怪。这个课程几乎没有编码。它涵盖了机器学习的一些基本构建模块,我们必须手动完成所有计算。我认为这很有帮助,因为它很好地教会了我很多概念。甚至一些流行的机器学习模型也是用简单的案例手工完成的。手动处理复杂的数据集几乎是不可能的。在学习了简单的数据集之后,我们使用 Weka 和 JMP Pro 来处理更大更复杂的数据集。在使用 Python 和它的库之前,我几乎完成了我在这个类中所做的所有事情,而不知道幕后发生了什么。这次我学到了幕后部分。

使用 Python 的数据科学

学习这门课程需要了解 Python。因为它不教 python。它教授 Python 的数据科学库,如 Numpy、Pandas、Matplotlib、Seaborn 和 scikit-Learn。这意味着使用 Python 中不同的库进行数据分析、可视化和机器学习。这是一门强化课程,因为要在 6 周内涵盖很多内容。这对我来说并不难,因为我以前从网上课程中学到了大部分材料。但是如果对一个学生来说是新的,那就要花很多时间去掌握每周的材料。

机器学习

正如你从前面的描述中看到的,一些课程已经关注机器学习和数据建模。所以,期望你在来上这门课之前,已经了解了机器学习。虽然课程的名称是“机器学习”,但它实际上专注于神经网络和深度学习。从从头开始开发基本的神经网络开始,然后使用 Tensorflow 执行更高级的主题。本课程重点学习 TensorFlow 和 Keras 功能背后的概念,并使用 TensorFlow 和 Keras 构建深度学习模型。

这些是我能谈论的所有课程。我还没上过大数据分析。那是我唯一剩下的课程。所以,我不能谈论这个。

结论

我不是在这里谈论利弊。我只想详细分享你在课程中学到的东西。因为在课程网站上看课程表可能没那么清楚。我试着在这里多解释一些。如果你注意到,六门基础课程中的四门涵盖了一些或大量的预测建模。所以,如果这就是你想要的,这太好了!

最后,我应该提到每门课程都需要很多时间。每周都有作业,有些课程每周都有作业和测验。大多数课程每周都有很多内容。我目前没有工作,但在学期快结束的时候,感觉还是很忙碌。不过,我对此很认真。因为我想改变我的职业道路。根据你的水*,可能需要每周至少 20 小时或更多的学习时间。

我只能分享这么多了!

请随时在 Twitter 上关注我。

更多阅读

一千个大脑理论综述

原文:https://towardsdatascience.com/a-thousand-brains-theory-a-review-3ea6bbeeced0?source=collection_archive---------6-----------------------

未点燃: 淡淡的

关于智力和大脑皮层如何工作的新理论。

介绍

很长一段时间以来,我一直在关注神经科学家的初创公司 Numenta ,该公司的目标是了解新皮层,以再现学习算法中的机制。

创始人杰夫·霍金斯写了《一千个大脑:智力新理论》一书。对于热爱神经科学和人工智能的我来说,这个标题很有吸引力。在他的书中,作者讲述了大脑和智力理论的历史。他用轶事和经历解释他是如何得出他的理论的。

他的假设很有趣,改变了我们计算所有实际机器学习算法的方式:

我在本章探讨的假设是,大脑使用参照系储存所有知识,思维是一种运动形式。当我们在参照系中激活连续的位置时,思考就发生了。第 71 页

在这篇博客文章中,我将只谈论这本书的前两部分 1) 对大脑的新认识和 2) 机器智能。第三部分是关于人类智力但是,我不打算解释它。我认为读者应该对这一部分有自己的看法,而不是我提供给他们的偏见。

我们走吧。

对大脑的新认识

作者在 Mountcastle (1978)[1]的基础上建立了他的理论。在这篇论文中,他解释说,新大脑皮层是一种皮层算法。Mountcastle 将其描述为一种通用算法,而没有关于算法的细节。

新大脑皮层可以被视为一个张量,其相同的计算单位被克隆了十万次。事实上,新大脑皮层包含 150,000 个皮质柱(将其视为包含固定数量神经元的神经层)。每个皮质柱由 100 个迷你柱组成。形象化这种架构的最佳方式是想象一盒意大利面条。盒子是皮质柱,意大利面是迷你柱。

好了,这里你已经掌握了什么是皮层柱。现在,想象这个皮层柱是一个乐高积木,为了构建新皮层,你将许多皮层柱相互靠着放置,并将它们连接起来,以创建一个 3D 网络。这就是美所在。除了一些细节,无论你从哪里看,每一列几乎都是一样的。每一列可以计算任何刺激或感觉(听觉、嗅觉、触觉、味觉和视觉)。

现在,考虑一个单独的列。它可以分析和处理输入信号,不管信号的类型。所以,每一列也可以预测一个输出。这意味着每一瞬间有 150,000 个预测。新大脑皮层以连续的时间步长预测成千上万的现实。这是预判,意识看不到它,除非它犯了错误。你通过分析错误来学习。

但是,大脑学习什么呢?如果所有的信号都被相似地感知。如果大脑区域不容易区分。大脑是如何学习的?

所有信号都在同一位置进行处理和计算。大脑如何确定距离?确定声音来自特定的一侧。它是如何知道到达特定空间抓住一个物体需要给初级大脑哪个信号的?大脑从对现实的感知中学到了什么?

我们学习一个的世界模型

大脑,皮质柱,预测未来,对片刻的逐渐适应学习出现在它所犯的错误中,并为它的世界模型提供更新。

此外,大脑必须对它感知到的东西做出假设。周围没有环境标签。它必须首先假设,以一种无人监管的方式,并发出个假设,然后用标签验证它们。

新大脑皮层会学习物体的形状或总体特征。这将允许识别它们,而不管特征的添加或修改。因此,它学习规则。

它还必须学习检索信息的机制。它学习的信息不可能永久可用。信息流刚刚击落了它。因此它必须通过关联来学习。气味会唤起记忆。纹理带回图像等。

因此,新大脑皮层将充当知识图表。特定的输入将允许访问与类似事件相关联的存储器。我把它想象成一个理解的数据库。

与当前通用的机器学习方法不同,大脑必须在双动态空间中持续学习。世界在运动,大脑也在运动。我们可以将其视为持续强化学习持续探索

动力将允许大脑皮层在事件和感觉之间建立联系。此外,它将能够学习它产生的动作的效果。就是感觉运动学习

大脑需要预测事件的持续时间,以便能够在环境中运动和行动。但是,它需要做两种类型的预测。一个关于环境的。第二,他在环境中的表现。

因此,大脑学习并创建具有位置参考帧。参考系就像是环境和物体的网格。大脑不会保存每个事物的图像,而是保存兴趣点的表示。这就像你脑子里有一个多重网格的世界。每个皮层列可以学习上百个的对象。

世界,对于大脑来说,是一个记忆序列(动力学)。需要位置来关联位置记忆,因为它允许你找到路并移动。

人工智能领域目前的对等物是 RNN 家族和注意力机制。新大脑皮层创建的世界模型是感官输入、参考框架和位置组合。新大脑皮层并不负责运动和地图的创建。这需要老脑来做。主要是海马内嗅皮层

每个神经元会在数百个之间搜索对应的映射。它在树突的帮助下作为联想记忆工作。在引言中提供的引文中。作者假设知识被编码在参考框架中,位置,或者连接这些点的能力创造了思维。思维是选择相应的皮质柱。这是可能的,因为参照系学习的是世界的表象,而不仅仅是物体。该位置允许皮层列选择相应的地图。

理论的名称从何而来?如前所述,新大脑皮层是以基于迷你柱的皮质柱为基础的。这种方法是一种千脑万脑理论

在这个理论中,大脑皮层柱相对相似,但只能保留固定大小的知识。所以知识是传播在十五万栏里面但是与重叠。如果一个零件受伤,信息不会丢失。

但是,这里有一个问题。如果数百列保留相同的信息或信息的一个版本,大脑如何只感知一件事?叫做绑定问题

皮质柱如何解决束缚问题?笔者简单的回答是:通过投票。对我来说,每一列都会以的概率预测一条信息。如果信息达到多数,则选择参考帧。

神奇的是,在皮层列中,提供投票的神经元总是同一个。每次需要投票的时候,相同的神经元就会通过皮质柱被激活。

如果不幸的是,两张地图出现的概率相同,神经元就会达成共识。这就是为什么注意力是强制性的

机器智能

很棒的标题。但是,人工智能中没有智能。在目前 AI 使用的方法中,只有一个 a。

人工智能的未来将基于模仿大脑的原理。第 117 页

为什么?

作为人类,我们不断地学习。我们的大脑每秒更新一次它的世界模型。实际的神经网络需要完全训练一次,并且在重新训练时难以学习更多的东西而不丢失太多的信息(称为灾难性遗忘【2】)。一个名为持续终身学习【3】【4】的新领域使用连续的数据流来训练神经网络,而不会丢失信息。

但是为什么不是 I 呢?这是因为今天的系统专门做一件事,而人类可以做多件事。人工智能不灵活。

目前,人工智能研究人员无法编写一个接*五岁儿童智力的系统。他们还没有找到创造日常知识的方法。这个问题叫做知识表示,被认为是唯一的问题

大脑学习一种知识模型,而不是文字或图像。就像我们在第一部分看到的,大脑学习类似地图的参考框架

那么如何认为一个系统是智能的呢?标准是什么?

作者提供了四个标准来构成机器智能的基础

  1. 机器需要不断学习(持续终身学习)。机器需要从错误中学习来更新它的世界模型。机器需要创建新的连接来获取新的知识,而不需要替换或删除旧的连接。
  2. 机器将需要通过移动(称为具体化)来学习。运动导致定位。如果回避,世界表象就会有偏差。
  3. 机器需要创建许多模型。新大脑皮层的每个皮层列学习一个上千个对象的模型,解决绑定问题(一个独特的感知)的过程是通过投票进行的。一台机器需要获得同样的流程。
  4. 机器需要使用参考系来存储知识。思考是一种运动。它是通过连接参考帧中的点而出现的。如果机器不能运动,它就不能思考。
    皮质柱使用类似网格细胞和位置细胞的细胞。

当机器有意识时

意识依赖于不断形成我们最*的想法和经历的记忆,以及回放它们的能力。

觉知似乎与意识错综复杂。记忆和注意力是意识的基础。如果我记得我昨天在做什么,并取代每一个时刻。我知道他们,我有意识。

机器智能需要目标和动机。但是,它们按照不同的程序出现,在机器中编码(我们的 DNA 为我们的身体编制了吃饭、呼吸等程序。).或者他们是有学问的。他们还需要安全措施。对我们来说,一个安全措施就是屏住呼吸不死。对于一台机器来说,艾萨克·阿西莫夫的机器人三定律可能是一个好的开始。
目标和动机不是智力的结果,不会自己出现。

结论

新大脑皮层的缺点:每个神经元都是有线的,所以如果一个区域在开始时(年轻时)不活跃,它就永远不会活跃。这就是为什么小时候听过多种语言的孩子长大后有更多机会流利地使用多种语言。目标是在机器中避免这种机制。

作者没有谈论大脑中存在的量子过程或量子现象(化学过程或信息的传送)。

越来越强大的量子计算机的出现,很可能会改变我们对大脑的看法。

最后一句话,这是一本很棒的书,我推荐给大家。它为新皮层和我们如何学习提供了一个新的视角。作者的方法非常有趣,并一直引发想法和问题。

我更欣赏的是作者提出了他的观点,他的理论而没有批评那些已经存在的人。即使当他讨论智能机器时,他也只是指出已经建立的限制。

参考

  • [1]芒特卡斯尔,弗农,1978 年。大脑功能的组织原则单元模型和分布式系统。正念的大脑,7-50。麻省剑桥—麻省理工学院出版社。http://ni corg . Pb works . com/w/file/fetch/49365852/mount castle % 20 organizing % 20 principle . pdf
  • [2]迈克尔·麦克洛斯基,尼尔·j·科恩,1989 年。连接主义网络中的灾难性干扰:顺序学习问题。学习与动机心理学,学术出版社,第 24 卷,第 109–165 页。https://doi . org/10.1016/s 0079-7421(08)60536-8
  • [3]詹姆斯·柯克帕特里克和阿尔, 2016.克服神经网络中的灾难性遗忘。ArXiv。http://arxiv.org/abs/1612.00796
  • [4]德国帕里西等人著,2019 年。利用神经网络的持续终身学习:综述。神经网络,第 113 卷,第 54–71 页。https://doi.org/10.1016/j.neunet.2019.01.012
  • https://en.wikipedia.org/wiki/Three_Laws_of_Robotics

10 个有用的 Github 特性之旅

原文:https://towardsdatascience.com/a-tour-of-10-useful-github-features-d92dde0bf412?source=collection_archive---------27-----------------------

充分利用 Github 体验的一些提示和技巧

由罗曼·辛克维奇在 Unsplash 上拍摄的照片

本文汇集了我在使用 Github 的过程中发现的一些有用的技巧和窍门。这些是随着时间的推移从各种来源收集的。我已经把那些太熟悉的过滤掉了,以免重复。我相信你会发现这个列表很有用,你可能会在日常工作中用到它们。

作者图片

有时候,我们希望直接通过 Github 库编辑代码,而不是先将其克隆到我们的本地环境中。有两种方法可以做到。

Github 的网络编辑器

基于 web 的编辑器[是一个免费的轻量级编辑器环境,可以直接从您的存储库中创建和提交代码更改。您可以通过以下方式在基于 web 的编辑器中打开任何 GitHub 存储库:](http://Github's Web-based editor)

  • 按下圆点(。)键浏览 GitHub 上的任何存储库。

Github 的网络编辑器|作者图片

  • 将网址从github.com改为github.dev

访问 Github 的网络编辑器|作者图片

直接在 Colab 中打开 GitHub Jupyter 笔记本

也可以直接在 Colab 中打开 Github 笔记本。将 URL 中的github替换为githubtocolab,其他内容保持不变。这会在 Colab 中打开同一个笔记本。

在 Colab 中打开 GitHub Jupyter 笔记本|作者图片

作者图片

README 是 Github 存储库中的一个降价文件,让其他人知道项目的范围和其他细节。自述文件中包括的内容有:投稿指南、行为准则、项目运作等。

自动生成自述文件。

有一个方便的工具叫做 readme.so 可以帮助你轻松创建和定制你的 readme。它是一个简单的编辑器,你只需要点击一个部分来编辑内容,这个部分就会被添加到你的自述文件中。

使用 readme.so |图像按作者生成自动阅读材料

创建配置文件级自述文件

您还可以自定义您的 GitHub 个人资料页面,以包含您想要展示的信息。Github 个人资料自述文件是一个公共存储库,包含一个 README.md 文件,显示在您的个人资料页面的顶部。你想在 Github 页面上展示的所有内容都应该包含在这个 README.md 文件中。但是,有几点需要记住:

  • 存储库的名称应该与您的 GitHub 用户名相匹配。例如,如果您的用户名是octo,那么存储库名称必须是octo
  • 存储库应该是公共的。
  • 在存储库的根目录下应该有一个 README.md 文件,并且应该填充一些内容。

按作者创建配置文件级别的自述文件|图像

查看matiassingers/awesome-readme获取一些很酷的读物的灵感。

作者图片

现在让我们看看对 Github 有用的浏览器扩展和应用程序。

八叉树

Octotree 是一个浏览器扩展,增强了 GitHub 代码审查和探索。它可以帮助你浏览目录和打开一个熟悉的树状结构的文件。

八叉树浏览器扩展|作者图片

透视眼

Octoclairvoyant是一个工具,可以在一个视图中过滤和比较多个版本的 GitHub 变更日志。很容易发现哪个版本引入了特定的变化,以及一系列其他的优点。

八眼透视工具|作者图片

Github URL 缩写

Github 有自己的 URL 缩短器,名为 Git.io ,可以缩短任何 Github 库的 URL。

Github 网址缩写|作者图片

作者图片

本节包括一些有助于创建 wikis 和文档的格式化技巧。

<kbd>标签使文本看起来像按钮

您可以通过包含<kbd>标签将文本转换成类似按钮的格式。这在编写文档时很方便。

Pressing the <kbd> .</kbd> key while browsing any repository on GitHub.

神奇的减价表

Table-magic 是一个开源工具,允许您轻松快速地在几种表格格式之间转换,包括 CSV、TSV、Markdown、SQL 和 HTML。

魔力减价表|作者图片

作者图片

最后,文章结尾,有一个 Github 的优秀可视化项目。

Github Octo

Github Octo 项目是一种自动生成代码库鸟瞰图并理解我们的代码是如何构造的方式。下图是来自 H2O.ai 的 H2O-3 库的可视化图,你可以点击亲自尝试一下!

作者使用 Github Octo | Image 对 H2O-3 储存库进行可视化

结论

这些是我发现有帮助的一些 Github 黑客。我相信你还会遇到其他人,如果你能把他们列在评论里,那就太好了,这样我就可以把他们添加到这篇文章里。有时候,了解工具的一些鲜为人知的事实是有好处的。如果您觉得这篇文章有帮助,我已经写了一篇关于使用 Colab 的类似文章。别忘了去看看。

** [## 通过这些技巧更有效地使用 Colab

towardsdatascience.com](/use-colab-more-efficiently-with-these-hacks-fc89ef1162d8)**

非数学家的内核指南

原文:https://towardsdatascience.com/a-tourist-guide-to-kernels-for-non-mathematicians-639c9d7ab03a?source=collection_archive---------9-----------------------

思想和理论

在不走出房间的情况下,进行一次到无限的往返旅行

布鲁斯唐在 Unsplash 上的照片

我经常从数学中获得关于现实和我们人类如何适应的灵感(尽管并不完美)。我明白内核实际上为我做了什么的那一天仍然是那些令人难忘的敬畏时刻之一。

数据科学家和机器教师肯定熟悉内核技巧的概念。他们研究它,经常理解它,哪怕只是一秒钟,然后迅速把它束之高阁。有数十篇关于内核及其对数据科学家的意义的技术论文和帖子。但是它们的美丽、优雅,以及它的使用可以给非数学家带来的关于符号思维能力的直觉,使我确信值得花时间为非数学家写一本内核的旅游指南。

尽管我会以不严谨为代价,尽可能减少数学术语(请原谅),但这一旅程需要一些耐心。相信我,会有回报的。

如果你认为你不能线性分离一组物体,你只是没有从正确的角度看待它

由大卫·拉古萨在 Unsplash 上拍摄的照片

想象一下,你在一个亭子前排队领取你的(疫情之前的)音乐会门票,队伍由你、你前后的几个朋友以及一群你不认识的人组成。

现在,从你的角度来看,没有办法把你的朋友和其他人区分开来。假设你们都整齐有序地排队,除了谁在后面,谁在前面,你看不到什么。但是如果你在一栋建筑的二楼,俯瞰同一条线,这个练习反而会非常容易;从顶部你可以清楚地看到你的朋友在哪里停下来,其他人在哪里开始排队。

换句话说,对你来说,在二维停车场上和其他东西放在一起,看起来像前面的一个点和后面的一个点,对住在三维建筑中的你上面的观察者来说,看起来像一楼有序的线。对于这个人来说,很容易画出另一条假想的线来区分朋友和陌生人。这种维度转换就是数学家所说的添加一个额外的特征来使数据集线性可分。

这个戏法从二维到三维,从三维到四维,从四百万到五百万都有效。无需发明任何东西,只需转换你所拥有的关于一组物体的信息,为这些物体增加新的维度或坐标,你就可以几乎线性地分离任何一组。

我再举两个例子。

图片来自悉达多·夏尔马,SVM 的内核把戏

在左边的图表中,你可以看到一个二维空间中的点云,这些点永远无法线性分离(在那个空间中)。换句话说,一条线必然会穿过一些红色或绿色的点,却无法将红色和绿色区分开来。但是看看右手边发生了什么:通过某种特征转换,将这些数据从二维空间转移到三维空间,可以画一条线(或者更好,现在是一个*面)来完美地区分两组。回到我们最初的二维空间,同一个*面看起来就像一条圈出红点并将它们从绿色中分离出来的圆形线。这又是一个视角问题。

特征转换是什么意思?数学家们之所以谈论特征变换,是因为在从二维空间到三维空间的变换中,没有添加任何东西,而只是增加了一些内部特征。在数学中,这种转换可以描述如下。二维空间中的每一个点都可以用坐标向量x= x₂}.{x₁来表示特征变换函数ϕ( x )将这两个坐标组合起来,并吐出三个坐标:ϕ( x ) = {x ₁,√2x₁x₂,x ₂}.由于ϕ( x ,右手边的图形将所有点 x 绘制到新的空间中。

图片来自 Sourodip Kundu,在 SVM 发现非线性决策边界

第二个也是最后一个例子不太直观,但让我们了解了离散特征到(更)高维空间的转换是多么强大。在这种情况下,ϕ将二维空间的特征扩展到一个更高维的空间(不要被立方体所迷惑,我们根本无法在一张照片中表现出许多维度)。在这个更高维度的假设空间的某个地方,数据仍然可以被一个更高维度的超*面线性分离——你需要相信我。在纸张的二维*面上,这个超*面看起来像一条围绕红点弯曲的线。

当你认为一种现象太模糊而不能被清楚地理解和分类时,这可能仅仅是因为你不能从一个足够复杂的角度来看待所有的信息,从而对它有所了解。

没关系,但是内核是什么?

再忍耐我一会儿。事实证明,在这个更高维度的空间中进行计算会使事情变得非常复杂。你通常想要处理(和分离)的信息比具有两个坐标的点复杂得多,这意味着它已经存在于高维空间中。例如,一幅图片有数千或数百万个像素,每个像素代表一个坐标。将这些高维对象投影到一个甚至更多维的宇宙中,会使这些对象之间的每一次操作都变得极其昂贵,当你知道机器学习需要大量计算,涉及数百万条数据,这些数据已经具有令人难以置信的数量的独特特征时,你不会感到惊讶。

在机器学习中(或者更具体地说,在线性 SVM 分类中),我们需要执行的最典型的操作之一称为点(或内)积,涉及将一个对象的每个坐标乘以另一个对象的相同坐标,然后将所有这些乘积的结果求和。回到我们的第一个例子,x= x₂}{x₁和y= y₂}{y₁的点积将是(x₁y₁ + x₂y₂).)这个点积包括 3 次运算、2 次乘法和一次求和,从而得到结果。相反,将相同对象的点积转换到它们新的三维空间ϕ( x )={x ₁,√2x₁x₂,x ₂}和ϕ( y ) = {y ₁,√2y₁y₂,y ₂}会更昂贵,(x \y +2x y \y \y +x \y \y \y \u)涉及变换、乘法和求和之间的若干运算。

在更高维度的空间中,也就是机器通常运行的空间中,这种复杂性的差异是巨大的,使得这些转换在我们的有生之年往往是不可行的。正是在这里,所谓的内核技巧(终于)来帮助我们了。内核实际上是一个能够仅基于原始向量 xy 来计算ϕ( x 和ϕ( y 之间的点积的函数,因此不必计算(甚至不必知道)变换ϕ.可以证明(默瑟定理),在很少的数学条件下,这样的函数 K( xy )总是存在的。

在我们的具体例子中,函数 K( xy ) = ( xᵗ ∙ y ),即原向量 xy 的点积的*方(在 x 上面的上标 t 代表转置,这只是由于矩阵代数和你的复杂性然而,不同之处在于,为了计算 K( xy ),我们需要 4 次运算(2 次乘法和一次点积求和,加上数字的*方),仅此而已。

所发生的事情乍看起来可能是无辜的,但实际上却是强大的。通过在概念上想象一个在我们的原始空间中运行的功能,我们可以获得在更高维度空间中运行的全部好处,而不必去访问这样的空间,或者为与之相关的复杂性而烦恼。

但是让我进一步扩展一下,以防你仍然需要一些说服力。

就拿下面的核函数来说,所谓的高斯核。

K( xy)= exp(-γ∨x-y∨)

可以证明,处理函数 K( xy ,即在 xy 所在的原始离散维空间中进行简单的数学运算,等于将 xy 投影到一个无限维空间中,并计算这些变换的点积。如果你对前面的例子没有什么印象,现在试着比较一下我们求解这个核函数所需的运算次数,包括计算无限次的变换、无限次的乘法和无限次的求和。

我们从概念上思考的能力,不受时间和空间的限制,使我们有可能在办公桌上或通过屏幕享受无限的未知之旅的所有实际好处。

使用 PyTorch 和 Fastai 创建对象检测数据管道的教程

原文:https://towardsdatascience.com/a-tutorial-on-creating-data-pipeline-for-object-detection-using-pytorch-and-fastai-eae20a4e8472?source=collection_archive---------7-----------------------

PyTorch 中的数据管道

一种构建数据管道的通用方法

作者图片

大多数时候,你开始使用预处理数据集(如 Sklearn 的数据集)进行机器学习,以实现机器学习算法,但随着你转向更新颖的机器学习项目,数据集通常是原始格式,可能具有非常松散的结构。

我在这里分享一个我开发的通用方法,从这些原始数据集开始,在 PyTorch 中构建一个数据集管道。

我们要使用的数据集是象棋数据集,这是一个对象检测数据集,您可以使用链接https://public.roboflow.com/object-detection/chess-full/23下载数据集,在本教程中,我们将使用 Yolo v5 PyTorch 版本的数据集。

使用https://github . com/varun 9213/Blog _ machine _ learing/blob/main/Dataset _ pipeline _ Blog _ 1 . ipynb下载教程的笔记本

作者图片

您可以直接从笔记本上下载带有网站生成的链接的数据集。本文的其余部分将由小节组成,这些小节将构建一个创建 PyTorch 数据集管道的逐步方法。

数据集中的一般结构和文件扩展名

原始数据集通常看起来像复杂的谜题。第一次打开一个非常原始的数据集时,我也不知所措,但后来我仔细查看了一段时间,然后将问题分解成更小的部分,它开始变得有意义了。将拼图分成小块总是一个好主意。

一般来说,你会遇到两种形式的结构化方案。

更常见的结构是根据标签将图像划分到单独的文件夹中。父文件夹的名称是这些图像所属的标签。另一种常见的结构是将所有图像放在一个文件夹和一个单独的文件中。csv,。txt,。json 等。)保存标签,其索引或文件名是图像和相应标签的名称。

作者图片

Chess 数据集包含三个文件夹 train、valid 和 test,每个文件夹都有一个 images 文件夹和 labels 文件夹。有两个自述文件和一个名为 data.yaml 的 YAML 文件。我们的数据集属于第二种类型,其中类和边界框位于单独的。txt 文件,这是您通常会在对象检测数据集中找到的结构。

现在,我们已经研究了结构并查看了我们正在处理的文件的扩展名,让我们打开这些文件,以便更好地理解我们接下来需要采取的步骤。

打开并浏览数据集中的文件

开始时,你会经常遇到你从未处理过的文件类型,这似乎是一件复杂的事情,但是,大多数情况下,这只是一个五分钟的谷歌搜索,并不像一开始看起来那么复杂。

该数据集有 3 种类型的文件。jpg,。大多数读者可能熟悉前两种文件类型,虽然 yaml 对一些读者来说可能是新的,但 YAML 只是一种类似于 JSON 的序列化标准,主要用于存储配置。在大多数情况下,您不需要了解文件类型遵循的协议,您只需要知道如何在 python 中打开这些文件并从中提取数据。

我们将从研究 YAML 档案开始。你可以点击链接https://stack abuse . com/read-and-write-YAML-to-a-file-in-python/了解如何处理 YAML 文件。它几乎涵盖了在 python 中处理 YAML 文件所需的所有工具。

让我们从安装和导入本教程所需的所有库开始。

!pip install fastai --upgrade
!pip install pyyamlfrom fastai import *
from fastai.vision.all import *
from fastai.imports import *
import yaml, cv2, os
from torchvision import transforms as Troot = Path("/content/data")

路径是 fastai 中的一个对象,它让你的生活变得更加容易,你可以在 fastai 网站【https://course19.fast.ai/part2】的 docs.fast.ai 上阅读 fastai library 提供的路径和其他非常方便的工具,我也强烈推荐 Jeremy 在 fastai 网站上的免费 fastai 深度学习课程。

现在让我们看一下 data.yaml 文件。

with open(root/"data.yaml") as file:
data = yaml.load(file)
data

作者图片

这是一个字典,包含标签名称、类别数量以及训练和验证文件夹的路径。为了构建管道,我们可以忽略这个文件。

接下来,让我们看看图片

path_train = Path("/content/data/train")
path_val = Path("/content/data/valid")
path_test = Path("/content/data/test")train_images = get_image_files(path_train/"images")img = cv2.imread(str(train_images[-1]), cv2.IMREAD_UNCHANGED)
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
plt.imshow(img)

作者图片

get_image_files()是另一个非常方便的 fastai 方法,可以获取所有常见格式的图像,如 jpg、png 等。从所有子目录中。返回的列表不包含图像本身,而是包含所有图像的路径。

注意注意图像的分辨率是 1371 x 2048,这是相当高的,大多数对象检测算法,如 yolo,允许矩形图像,但是当使用高分辨率图像时,训练自然会慢一些。因此,我们可能希望将这些图像调整到较低的分辨率。然而,与分类任务相反,在对象检测中,目标对于分辨率不是不变的,因为如果图像被调整大小,边界框也必须被调整大小。

让我们最后打开相应的标签。

f = train_images[-1].name[:-4] + ".txt"
with open(root/"train"/"labels"/f, 'r') as file:
  targets = file.read()
targets = targets.split("\n")
targets

作者图片

样本的第一个条目显然是类,接下来的 4 个条目定义了边界框。边界框的格式对于不同的算法是不同的,Yolo 的边界框格式是[ center_x,center_y,width,height]https://towards data sciences . com/image-data-label-and-annotation-you-the-knowledge-86 ed 6 c 684 b 1如果你想更深入地探讨这个主题,这是一个很好的资源。

准备数据帧以有效访问图像标签

这个步骤非常主观,每个人都有自己的偏好,我喜欢在创建 PyTorch 数据集对象之前,将数据编译到一个数据框中。

此步骤无必要且可跳过。然而,在我看来,只需少量的工作和几行代码,就可以大大简化数据集构建步骤。话虽如此,任何方法中最重要的是来自实践的熟悉,所以我强烈建议您找出一个您熟悉的通用方法,并尽可能多地坚持下去。

让我们从选择一个样本开始,并为这个样本制作一个数据框。数据框将具有图像的名称、类和边界框坐标。

col = ["name", "class", "center_x", "center_y", "width", "height"]
train_df = pd.DataFrame(columns= col)
train_dfrow = {}
row[col[0]] = f[:-4]
for i,t in enumerate(targets[0].split(" ")):
  row[col[i+1]] = float(t)
rowtrain_df.append(row, ignore_index=True)

作者形象

注意通常最好从整个数据集中抽取一个样本,并使用该样本。这有两个优点,一是速度快得多,尤其是在数据集非常大的情况下,二是处理单个样本比处理整个数据集容易得多。这种做法极大地提高了我高效准备数据集管道的能力。

最后,我们将把这些单独的命令转换成函数,将整个数据集转换成一个数据框架

def get_targets(image_path):
  f = image_path.name[:-4] + ".txt"
  with open((image_path.parent).parent/"labels"/f, 'r') as file:
    targets = file.read()
  return targets.split("\n")def get_row(image_path, target, col): 
  row = {}
  row[col[0]] = image_path.name[:-4]
  for i,t in enumerate(target.split(" ")):
    try:
      row[col[i+1]] = float(t)
    except:
      print("Could not convert {} to float".format(t))
  return rowdef add_targets_to_df(df, image_path):
  targets = get_targets(image_path)
  df_new = df
  for target in targets:
    row = get_row(image_path, target, df.columns)
    df_new = df_new.append(row, ignore_index = True)
  return df_newdef create_df(cols, images_paths):
  df = pd.DataFrame(columns=cols)
  for path in images_paths:
    df = add_targets_to_df(df, path)
  return df

将复杂的任务分解成更小的部分并将每个部分包装成一个函数总是一个好的做法,它简化了问题并产生了更可读的代码,这使得故障诊断比将所有事情都塞进一个函数中更容易。

作者形象

final_df = create_df(col, train_images)
final_df.head()

作者形象

现在,最后一步是创建 PyTorch 数据集对象,这将是最后一部分。

创建 Pytorch 数据集

Pytorch 和 Tensorflow 是最受欢迎的深度学习图书馆,PyTorch 因其提供的灵活性最*在研究人员中变得更受欢迎。

让我们从为象棋数据集构建数据集管道开始。

def get_target_ds(name, df): rows = df[df["name"] == name[:-4]]
  return rows["class"].values, rows[bboxes_cols].valuesclass ChessDataset(torch.utils.data.Dataset):

  def __init__(self, images_path, df):
    super(ChessDataset, self).__init__()
    self.images_path = images_path
    self.df = df def __len__(self):
    return len(self.images_path) def __getitem__(self,idx):
    img_path = self.images_path[idx]
    img = cv2.imread(str(img_path), cv2.IMREAD_UNCHANGED)
    target = {}
    labels, boxes = get_target_ds(img_path.name, self.df)
    areas = boxes[:,2] * boxes[:,3]
    iscrowd = torch.zeros((boxes.shape[0],))
    image_id = torch.tensor([idx])
    labels = torch.as_tensor(labels, dtype=torch.float32)
    boxes = torch.as_tensor(boxes, dtype=torch.float32)
    areas = torch.as_tensor(areas, dtype=torch.float32)
    target["boxes"] = boxes
    target["labels"] = labels
    target["areas"] = areas
    target["iscrowd"] = iscrowd
    target["image_id"] = image_id img = F.to_tensor(img) return img, target

ChessDataset 类从 PyTorch 继承 torch.utils.data.Dataset 类,我们需要为其定义 init()、len()和 getitem()函数,以更深入地了解如何创建 PyTorch 自定义数据集。

最后,让我们通过创建一个实例来测试我们的类,并通过调用 getitem()来获得一个样本,以查看它是否正常工作。

dataset = ChessDataset(train_images, final_df)img , target = dataset.__getitem__(1)
size = img.shape
print(img.shape, target["boxes"], target["labels"])plt.imshow(img.permute(1,2,0))

作者图片

您的数据集可以与 PyTorch 的数据加载器一起使用了!!

结论

这里的想法是有一系列的步骤,对大多数数据集来说足够宽泛。为训练准备数据集也是一项技能,正如任何技能练习都是胜任的关键一样,我强烈建议你继续 Kaggle,用看起来复杂的数据集打开封闭的比赛,并尝试为这些比赛建立一个数据集管道,然后使用人们为这些比赛发布的内核来排除故障,数据集越让你不舒服,你就越能从练习中学到更多。

最后,我希望这篇文章为所有读者提供一些见解,我计划继续发表这篇文章,讨论相同的数据集,包括各种绘图函数和策略,在 PyTorch 中挑选和训练预训练的模型,以及其他任何可能与主题相关的内容,敬请关注,谢谢。

公司目前需要收集的一种数据

原文:https://towardsdatascience.com/a-type-of-data-that-companies-need-to-collect-today-624056a18831?source=collection_archive---------62-----------------------

商业智能

为什么在企业内部收集决策数据是必要的

Elia Pellegrini 在 Unsplash 上拍摄的照片

在数字化转型的时代,公司正在收集几乎所有类型的数据。传感器、财务和物流数据只是几个例子。然而,至少有一种重要的数据类型是大多数企业忽略的,那就是内部“决策数据”

决策数据

“决策数据”可能是每个组织内部产生但很少收集的最重要、最昂贵和最复杂的数据。为了理解这种类型的数据,让我们从一个简单的例子开始。你们很多人都玩过象棋。你们中的一些人熟悉 PGN 或者便携式游戏符号。PGN 用计算机可处理的格式记录国际象棋比赛。PGN 用一系列符号记录棋手在游戏中的动作。它不明显,但实际上,它记录了一个有价值的“决策数据”有了这种数据,计算机就可以向人类学习如何下棋。

下棋和 PGN 是开始理解决策数据概念的一个很好的例子。在这个例子中,由于有限的移动次数、不变的游戏规则、做出错误决定的低风险以及试错的可能性,计算机可以在没有 PGN 或任何专家帮助的情况下学习游戏。

在现实世界的任务中,与象棋不同,环境是不断变化的。此外,即使不是所有的任务,也是大多数任务比下棋风险更大,试错(即探索)不是一个选项。自动驾驶汽车领域就是其中之一。我们不能让一个开着车的人工智能司机在街上行驶并自己学习。人工智能驱动程序需要访问一些决策数据,并从这些数据中学习。决策数据只是专家(在这种情况下,是人类驾驶员)的一系列有目的的行动以及环境数据(在这种情况下,是来自汽车传感器、摄像头和气象站的数据)。这些数据对于像特斯拉这样的公司的价值就像其所有有形资产加在一起一样有价值。

石油和天然气行业的一个例子

用下棋或驾驶特斯拉汽车这样的例子来谈论决策数据既简单又直接。但是,它在一个行业或企业中是什么样子的呢?让我举一个石油和天然气行业的例子来说明。

要回答这个问题,我们需要把决策数据分为两个层次: 低层决策数据(姑且称之为 LLDD)和高层决策数据(姑且称之为 HLDD) 。有趣的是,石油和天然气行业传统上非常擅长收集 LLDD。当地质学家解释一系列地图、测井记录和岩心时,他/她就产生了 LLDD(有时称为软数据)。我希望它能帮助你找出你的行业或企业正在收集的其他种类的 LLCD。我们将这种类型的数据称为“低级”决策数据,因为像象棋游戏一样,围绕这些任务的规则不会改变太多。实际上,你是在一个有限的动态系统中做决定。大多数公司已经在以结构化或非结构化数据的形式记录低级决策数据(例如,技术报告)。

大多数时候,当我们谈论决策数据时,我们谈论的是高级决策数据(HLDD)。假设一个工程师和经理团队正在进行一个即将到来的油气田开发项目。在成千上万种不同的可能性中,他们会想出一个最佳方案。与低级决策不同,在这里,我们需要整合太多的数据、不确定性和考虑因素来做出一个决策。换句话说,这个系统是高度动态的,这也是我们称之为高层决策的原因。

现在,我们对这个漫长的思考和决策过程了解多少呢?如果一个领域的发展规划像一盘棋,如何从这一盘棋中收集数据?有什么方法可以记录我们公司或业务中好的和坏的决策数据?

人工智能和决策数据

由于数字化转型、新兴机器学习技术和大数据,企业和公司在过去几年中在预测分析方面取得了重大进展。但是,当涉及到规定性分析(例如,找到最佳商业解决方案)和认知分析(例如,做出最终商业决策和行动)时,人工智能就失去了可信度。原因之一是缺乏高水*的决策数据来训练人工智能系统实现这些目的。如果我们需要一个面向未来的人工智能辅助决策支持系统,我们需要收集今天的内部决策数据。

关注我在媒体和推特上的最新报道。

图形神经网络的统一视图

原文:https://towardsdatascience.com/a-unified-view-of-graph-neural-networks-12b40e8fdac5?source=collection_archive---------14-----------------------

实践教程

图形注意、图形卷积、网络传播都是图形神经网络中消息传递的特例。

三种不同 gnn 的插图。图片来自[1]。

消息传递网络(MPN)、图形注意力网络(GAT)、图形卷积网络(GCN),甚至网络传播(NP)都是属于图形神经网络(GNN)范畴的密切相关的方法。这篇文章将提供这些方法的统一观点,主要来自于[1]中的第 5.3 章。

TL;速度三角形定位法(dead reckoning)

  • NP 是 GCN 的特例,没有隐藏特征变换和非线性。
  • GCN 是 GAT 的一个特例,其“注意力”完全由图结构单独决定,没有节点特征。
  • GAT 是 MPN 的一个特例,具有作为“消息传递”规则的隐藏特征聚合。
  • 这些 gnn 之间的关系可以通过包含关系总结如下。

图形卷积-隐藏特征的局部聚合

图形卷积[2]遵循层传播规则:

就每一个节点而言,传播可以看作是邻居节点的变换( psi )隐藏特征 h )的局部聚集 ( 圈加),之后是某种变换(φ)具体来说,在 GCN [1]中, phi 是仿射变换( W )后跟非线性( sigma )。

聚集量( c_{ij} )完全由图结构决定,比如谱归一化邻接矩阵。

注意:聚合( circle-plus )可以是任何排列不变函数,如求和、元素乘积等。

有趣的是,网络传播可以被视为没有任何特征转换的图形卷积的特例,正如我在上一篇帖子中更详细讨论的那样。简而言之,按照这里相同的符号,网络传播将遵守如下传播规则

图形注意-重新学习边权重

类似于 GCN,GAT [3]执行隐藏特征的局部*均。但是,它不是只使用图结构来指导传播,而是通过一个可学习的函数 alpha ,根据隐藏的特征来学习重新加权传播权重 ( c_{ij} )。

在[3]中,这个“自我注意机制” alpha 被计算为可学习向量 a 和两个节点的仿射变换隐藏特征的串联之间的 softmax 归一化内积。

消息传递—更一般的聚合

消息传递网络[4]通过用两个节点的隐藏特征的某个任意函数代替隐藏特征聚集,进一步概括了对聚集的信息量进行控制的思想。

将所有不同的 GNN 方法放在一起,我们可以看到它们都遵循相同的局部聚集,或者通过局部*均(NP)或者置换不变函数(圆加)。

最后,现在更清楚不同的 gnn 是如何相关的。

  • GCN 是通过将注意力函数α设置为谱归一化邻接矩阵来实现 GAT 的。
  • GAT 是 MPN 的一种实现,通过以自我关注为消息传递规则的隐藏特征聚合。

参考

[1] M. M .布朗斯坦,j .布鲁纳,t .科恩,p .维利科维奇,几何深度学习:网格、组、图、测地线和量规 (2021)

[2] T. N. Kipf,M. Welling,利用图卷积网络的半监督分类 (2016)

[3] P .韦利奇科维奇,g .库库尔,a .卡萨诺瓦,a .罗梅罗,p .莉雅,y .本吉奥,图形注意网络 (2018)

[4] J. Gilmer,S. S. Schoenholz,P. F. Filey,O. Vinayls,G. E. Dahl,量子化学的神经信息传递 (2017)

[5] 网络学习——从网络传播到图形卷积

学习 SQL 的有益心态

原文:https://towardsdatascience.com/a-useful-mindset-for-learning-sql-b0c98764e17?source=collection_archive---------11-----------------------

分享这种思维加速了我的 SQL 学习过程

卡斯帕·卡米尔·鲁宾在 Unsplash 上的照片

对于好奇的工作者来说,尤其是那些在科技行业工作的人,探索数据库可以把你带到天堂。这就是我在挖掘大量数据集,为我的项目寻找有见地的信息时的感受。使用结构化查询语言(SQL ),我可以轻松地组合和聚合来自各种来源的数据来回答我的问题。这真的消除了下载各种 excel 文件,然后编写和复制所有 VLOOKUP 和 IF 函数的痛苦。通过我的定制 SQL 脚本,我可以使用 Tableau 或 PowerBI 创建数据可视化,与业务利益相关者分享见解。关键工具确实是 SQL,我现在认为它是新的 Excel。

说实话,我一开始很害怕学 SQL。它看起来像一种复杂的编码语言,只有计算机科学家才能理解。然而,事情通常没有看起来那么复杂。有一次跟同事学了之后实际尝试了一下,真的掌握了窍门。我开始探索用例并生成以前没有使用过的模型。最重要的是,这项新技能带来的灵活性和速度让工作变得更加愉快。

在这篇文章中,我想分享我的 SQL 故事:帮助我快速获得这项技能的心态。

这都是简单的数学

照片由安托万·道特里在 Unsplash 上拍摄

高中时,基础数学是我最喜欢的科目。我喜欢解二次方程和三角学问题。这就像解决一个难题或谜团,比如谁是 x,或者当我们知道 o 的正弦值时,a 点到 b 点的距离是多少?这种心态带来的兴奋会建立你的逻辑思维。

数学和 SQL 都是关于逻辑的,你只需要理解逻辑就能得到预期的结果。体现数学思维真的有助于加速我的 SQL 学习过程。这种思维模式还帮助我学习了会计学(我的本科专业)、经济学和 Microsoft Excel 中的数据建模。后者实际上是最重要的,我将在下一节讨论。

和 Excel 没那么大区别

在从事技术工作之前,我几乎所有的工作都使用 Microsoft Excel。我被要求使用 VLOOKUP、IF 和 Pivot tables 等函数为价格计算和市场份额分析等案例创建模型。多亏有一个像老鹰一样盯着我的老板,还有时间来完善我的技能,我可以学习 Excel 的逻辑并创建更有效的模型。掌握这些知识对我学习 SQL 至关重要。我发现编写一个查询与构建一个 Excel 模型没有什么不同。数据仓库就像一个包含 Excel 文件的大型共享文件夹,我的查询就是填充这个空白表格。下面是我为这篇文章做的一个简单的例子。

假设有一家健身公司,姑且称之为好地方,它为公共和私营部门的组织提供企业会员。每个俱乐部都有这些活动/设施:健身班、健身房、篮球场、游泳池、水疗中心和小吃店。有几组数据:(1)从客户组织的注册表单中提取的成员列表,以及(2)每次成员使用他们的卡登记/离开时收集的活动日志。Good Place 希望进一步分析每个客户组织的活动。

第一个数据集包含成员的唯一 ID、全名、公司/机构和性别,如下所示。

作者使用 DBeaver 制作的图像

而第二个数据集包含日期 id、成员 ID、活动和花费的分钟数,如下所示。

作者使用 DBeaver 制作的图像

如您所见,两个数据集之间唯一的共享列是 MemberID。与此同时,The Good Place 的首席执行官 Eleanor Shellstrop 希望了解每个客户组织花费的*均时间,并按运动(健身班、篮球、游泳、健身房)和非运动(小吃店和 spa)对活动进行分类。Excel 和 SQL 都可以做到这一点,我们来看看它们是如何比较的。

擅长

由于有两个独立的数据集,最好从将成员列表中的列添加到活动日志开始,因为后者被视为事实表(存储度量和指标)。prior 是一个维度表,因为它提供了成员 ID 列的详细信息/属性。

为了创建链接,我们将在“Minutes_Spent”之后的列中使用 VLOOKUP 函数,即:VLOOKUP(MemberID,' Sheet1_Member_List!一个:D,列号,0)。一个更方便但未被充分利用的函数是 INDEX + MATCH,它将是:INDEX(MemberList Array,MATCH(MemberID,' Sheet1_Member_List!A:A,0),MATCH(列名,' Sheet1_Member_List!A1:D1!, 0).这消除了为 VLOOKUP 函数填充列号的需要。

要添加自定义列,我们可以使用流行的 IF 函数结合 OR,那将是 IF(OR(Activity = "Snack Bar ",Activity="Spa ")," Non-Sport "," Sport ")。

下一步是汇总数据以生成所需的见解。有两种方法可以做到这一点:创建一个数据透视表或者使用 SUMIFS 和 COUNTIFS 这样的聚合函数。前一个要简单得多,你所需要做的就是阻塞数据区域并插入一个数据透视表。但是,它的可持续性较差,因为(1)它为 Excel 文件增加了更多的内存,使其操作更加繁重,( 2)如果有额外的行,每次更新数据和更改范围时,您都需要刷新它。

如果文件将被长期重用,那么聚合函数更为有利。为了满足 Eleanor 的请求,我们可以复制类别和客户组织,然后删除重复项。然后,我们使用 SUMIFS 计算总分钟数,使用 COUNTIFS 计算总会话数,因为它不是数字。该功能将是:

总分钟数:=SUMIFS('Combined Dataset.csv '!\(D:\)D,'组合数据集. csv '!\(E:\)E,A5,'组合数据集. csv '!\(F:\)F,B5)

会话总数:=COUNTIFS('Combined Dataset.csv ')!\(E:\)E,A5,'组合数据集. csv '!\(F:\)F,B5)

有了这两个汇总,我们可以用总分钟数除以总会话数,得到总分钟数/会话数。最终输出如下所示:

作者使用 Microsoft Excel 制作的图像

对于 excel 用户来说,这似乎很简单。但是想象一下,如果有更多的客户组织和活动日志,再加上 Eleanor 每天都在请求这些信息,那该有多好?此外,如果埃莉诺要求更多的报告呢?制作模型、下载各种文件和复制数据将花费大量时间,这也容易出现人为错误。现在让我们看看 SQL 方法。

结构化查询语言

我们不必打开所有这些文件,只需编写一个简单的查询,如下所示:

作者使用 DBeaver 制作的图像

这将生成 Excel 格式的精确输出:

作者使用 DBeaver 制作的图像

用 Excel 的术语来解释,SELECT 就像使用等号在 FROM 中声明的主数据集中召唤所需的列,在本例中是活动日志。不使用 VLOOKUP,我们可以输入 LEFT JOIN,然后输入我们想要链接的数据集(就像 Excel 公式中的列选择),然后设置链接列(查找单元格)。CASE WHEN 类似于 IF 函数,只是格式不同。对于聚合,您只需要使用 SUM 和 COUNT,然后在最后使用 GROUP BY 来表示所使用的列。这与 SUMIFS 和 COUNTIFS 函数的后半部分相同,在后半部分,我们选择列和单元格作为聚合的基础。使用 SQL 可以消除上一节中提到的所有 Excel 工作。

为了让 Eleanor 了解情况,可以用 Tableau 编写这个查询,并创建一个可访问的仪表板。然后,她的分析师可以处理其他项目,而不必进行任何手动操作,也不必为这个特定主题发送电子邮件。

不断探索和挑战自己

通过不断练习和访问新的数据集,我对 SQL 的理解变得更加流利。有更多的机会刺激好奇的头脑进一步探索。当学习数据集时,我总是很兴奋,因为这可以加强我的分析。这将带来被忽视的新见解,并对问题陈述有更深的理解。

由于技术增加了工作动力,我总是认为有必要挑战自己。主要目标是如何更有效地工作,以产生及时和准确的见解。我花时间回顾我以前的问题,并思考如何缩短它,首先想到的是“总有改进的空间”。有许多可能的功能尚未使用。像 Presto 这样的 SQL 引擎在网站上有完整的列表供进一步学习。另一个简单的学习方法是不断搜索,搜索的信息就会出现。不断完善你的技能总是很重要的,或者用斯蒂芬·柯维的话说,磨利锯子。

结束语

我强烈建议任何从事分析工作的人都应该学习 SQL,尤其是从事技术工作的人。它不仅会加快你的交付速度,还会给你探索新见解的空间和灵活性。此外,精通 SQL 将使你更容易进入下一个层次:Python。从我的个人经验来看,我可以用类似的思维方式快速学习 Python Pandas:这都是简单的数学,与 SQL 没有太大的不同,并且不断练习。最重要的是,我们必须承认当前的技术发展需要新的技能。因此,我们必须不断学习,成为我们组织的宝贵财富。

基于变分信息瓶颈(VIB)的人体动作识别序列网络压缩方法

原文:https://towardsdatascience.com/a-variational-information-bottleneck-vib-based-method-to-compress-sequential-networks-for-human-b559d3a50e30?source=collection_archive---------35-----------------------

压缩 LSTMs 并推断边上的模型

本文是关于我们 最*在 WACV 2021 上发表的关于神经网络压缩的论文。

需要压缩网络以执行具有序列数据的任务,例如用于动作识别的视频:

递归神经网络(RNNs)及其高级变体长短期(LSTM)等网络专门用于处理文本、口语和视频等序列数据。但是这些网络具有大量的参数,并且导致大量的推理时间。这些网络中隐藏状态的数量是一个超参数,通常选择的数量(256 或 512 或 1028)通常比精确预测所需的数量大得多,并导致过度参数化。在视频动作识别任务中,输入视频帧通常由 RGB 叠加彩色帧组成,形成高维输入。因此,对于 RNNs,输入的维数变高,使得输入-隐藏矩阵非常大。例如,来自 UCF11 数据集的视频具有尺寸为 160x120 像素的 RGB 帧。因此,总输入大小必须为 160x120x3= 57,000。即使相对较小的隐藏状态大小为 256,单层 LSTM 模型中所需的总参数为5890 万。天真的过参数化一层端到端 LSTM 模型在 UCF11 数据集上以 67.7%的精度过度拟合[4]。

具有可变信息瓶颈的“相关性”思想:

几种张量分解方法[3,4,5]已应用于 RNNs,以低秩结构取代标准的输入-隐藏矩阵。这些方法修改输入并对输入-隐藏矩阵建模,以保留较低秩的密集权重矩阵。然而,大多数压缩 RNNs 的方法并不压缩隐藏到隐藏矩阵的大小。作为一个简单的动作识别数据集,UCF11 比其他大型数据集(如 UCF101)具有更少的类,数据集中的变化很小。这提示只需要几个与正确预测动作相关的隐藏状态来对数据表示进行建模。Tishby 等人[1]提出的变分信息瓶颈(VIB) 理论引入了在神经网络中仅保留相关中间数据表示同时保持预测准确性的思想。

图 1: Tishby 等人。文献[1]提出了基于信息论测度的变分信息瓶颈原理,以获得最简洁而又可预测的相关表示。

我们将这一想法应用于 RNNs 的复杂变体,LSTM 网络移除冗余输入特征和隐藏状态,从而减少模型参数的总数。

如何用 VIB 保留相关的隐藏状态和输入特征到 LSTMs?

受 VIB 去除冗余神经元思想的启发,我们在压缩时序网络方面做出了以下贡献:

(a)我们提出了如图 2(a)所示的新型 VIB-LSTM 结构,用于训练高精度稀疏 LSTM 模型。

(b)我们开发了一个顺序网络压缩流水线,该流水线稀疏化 RNNs/lstm/gru 的预训练模型矩阵。

(c)对于结合 CNN 和 LSTM 的架构,我们的 VIB 框架仅保留预测相关特征,这些特征可以作为 VIB-LSTM 结构的输入。

(d)我们在流行的动作识别数据集 UCF11、UCF101 和 HMDB51 上评估我们的方法,以产生具有可与最先进模型相比的验证准确度的紧凑模型。

图 2: (a)单个 VIB-LSTM 电池。它在每个门输出后有一个 VIB 层 z (显示为绿色),作为一个可训练的面具。每个 z 遵循具有可训练参数的多元高斯分布。(b)VIB-LSTM 结构的方程表明只需要对原始方程稍加修改。

我们的目标是学习一个压缩表示门表示 it、ft、o^t 和 g^t ,同时保留 v^t 中预测所需的相关空间和时间信息。在变分信息瓶颈(VIB)框架[1]中,这是一个优化问题,目标是学习 k\tilda^T ,使其具有最少的关于 LSTM 输入 v^t 的信息,同时保留学习目标 Y 所需的所有相关信息。注意,压缩 k\tilda^T 等同于压缩 h^T、,因为它们之间存在确定性映射。从数学上讲,它相当于优化以下目标函数:

其中 I()表示两个随机变量之间的互信息, θ 是将 v^t 转换为 k\tilda^T 的压缩神经网络的参数集,β 是控制压缩和预测精度之间的折衷量的超参数。由于模型的复杂性和互信息项的不可行性,上述方程通常是难以处理的,因此调用了变分上限[2]。我们将 VIB 理论作为一个层应用于 LSTM 门输出,这产生了图 2(b)中的方程。这仅保留了相关的隐藏状态,从而降低了 LSTM 的隐藏到隐藏矩阵的隐藏状态维数。类似地,对于端到端和 CNN-LSTM 架构,我们在 LSTM 的输入上引入 VIB 层,以仅保留预测相关的特征向量,从而降低 LSTM 的输入到隐藏矩阵的输入维度。这种基于 VIB 的模型压缩方法稀疏化了所有的 LSTM 矩阵,不像以前的动作识别张量分解方法[3,4,5]。

对树莓 Pi 的推断:

为了测试使用我们的方法获得的压缩 CNN-VIB-LSTM 模型相对于相同任务的天真的 CNN-LSTM 模型的推理速度,我们在 Raspberry Pi 模型 3 上部署了这两个模型。我们从 UCF11 数据集中提取了一个人从跳板上跳水的视频,标记为“跳水”,并分别使用未压缩和压缩模型来推断动作。如图 3 所示,压缩模型的执行速度比未压缩版本快 100 倍。

图 3:来自 UCF11 数据集的视频的动作识别,标记为在 Raspberry Pi 模型 3 上潜水运行。左图:使用经过训练的未压缩 CNN-LSTM 模型,在 1.26 秒内使用 33.57 米的 LSTM 参数推断动作。右图:使用经过训练和压缩的 CNN-VIB-LSTM 模型在 0.013 秒内使用 2052 个 LSTM 参数进行动作推断。

结论和进一步工作:

我们提出了一种基于 VIB 理论的通用 RNN 压缩技术。具体来说,我们提出了一种从输入特征中提取预测相关信息的压缩方案。为此,我们制定了一个损失函数,旨在利用端到端的 LSTM 压缩和 CNN-LSTM 架构进行人体动作识别。我们最小化公式化的损失函数,以表明我们的方法显著压缩了基线的过参数化 LSTM 结构矩阵,从而减少了它们中的过拟合问题。因此,我们的方法可以产生适合部署在边缘设备上的模型,我们通过在 Raspberry Pi 上部署我们的 CNN- VIB-LSTM 训练模型并对其进行推理来展示这一点。此外,我们表明,我们的方法可以有效地与其他压缩方法一起使用,以获得更显著的压缩,而精度略有下降。进一步的研究可以尝试将张量分解和基于 VIB 的压缩相结合,用于 RNNs 的所有变体。

更多细节可以在论文和下面的 Youtube 视频中找到。

参考文献

[1] Tishby,Naftali 和 Noga Zaslavsky。"深度学习和信息瓶颈原理." 2015 年 IEEE 信息论研讨会(ITW) 。IEEE,2015。

[2]Alemi,Alexander A .等,“深度变分信息瓶颈” arXiv 预印本 arXiv:1612.00410 (2016)。

[3]杨、尹冲、丹尼斯·克龙帕斯和福尔克·特雷普。"用于视频分类的张量训练递归神经网络."机器学习国际会议。PMLR,2017。

[4]潘,于,等.“用张量环压缩递归神经网络进行动作识别.”AAAI 人工智能会议记录。第 33 卷。№01.2019.

[5]叶,金冕,等.“用块项张量分解学习紧致递归神经网络”IEEE 计算机视觉和模式识别会议论文集。2018.

决策树和其他机器学习算法的非常贝叶斯的解释

原文:https://towardsdatascience.com/a-very-bayesian-interpretation-of-decision-trees-and-other-machine-learning-algorithms-b9d7280a9790?source=collection_archive---------29-----------------------

介绍

我记得我注册了一门课,在这门课中,我的教授花了两堂课仔细研究数学萌芽决策树,然后否认说,“同学们,决策树算法不使用这些。”。请注意,这些课程与基尼指数或熵增无关。他在几分钟内避开了他们。两节课是 180 分钟的贝叶斯定理和贝塔分布的对抗。那么,为什么我们被鼓励去痛饮那些数学?嗯,生长决策树的通常方法是贝叶斯模型的一种*似。但不是这样。这个模型也包含了集合方法的思想。就此,让我们投入到一些数学中,揭示贝叶斯定理的优越性。(注意:我假设你知道概率概念,如随机变量、贝叶斯定理和条件概率)

弗拉季斯拉夫·巴比延科在 Unsplash 上的照片

构建挑战

我想你熟悉决策树,以及它们如何使用基尼系数或熵损失来工作。所以,我们会忽略它,而使用贝叶斯定理。考虑一个布尔分类问题,你需要使用决策树来解决。因为我是一个好人,所以我代表你做苦工,用训练数据建立一个所有可能的决策树的花园。为什么都是?嗯,你的挑战是通过在决策过程中包含所有的树来分类一个新的数据实例 x。你将如何进行?

如前所述,你必须用贝叶斯心理来处理这个问题,它涵盖了 x 属于特定类别 Y (y1 或 y2)的概率。利用这个概率,你可以决定合适的类。注意,从现在开始,我们将把 X 和 Y 视为随机变量(RV)。但是它们是你唯一需要的房车吗?不,估计值 P(Y|X=x)取决于另外两个因素。

让我们思考一下包含所有可能的决策树的难题。并非所有的树都足够绿来解决这个问题。为什么这样对于任何问题,人们通常使用基尼指数或熵增益来挖掘最佳分离训练数据的树。这表明任何特定的数据集 d 都有唯一的匹配树。因此,如果您将树和数据集视为 RVs,那么对于特定的树 T=t 和训练数据集 D=d,您可以找到 T 对 D 的作用效果的概率估计 P(T=t|D=d)。理想的树将具有 P 的最大值(T=t|D=d)。此外,每个树还会对数据实例进行不同的分类。本质上,一个新数据实例属于任何类 P(Y|X=x,T=t,D=d)的概率在不同的树上是不同的。现在,你是否认识到,为了*息我的奇怪挑战,你需要两个讨论过的每棵树的概率?观察下面的等式。你对它有什么看法?

L.H.S 是属于 y1 的 x 的最终概率估计。这取决于训练数据集,因为对于不同的数据集,树将会修改。R.H.S .提出,要在决策过程中包括所有的树,我们应该对一棵树 t 取 x 属于 y1 的概率,用它乘以该树是理想候选树的概率,并对所有乘积求和。换句话说,您做出的最终决定应该是所有树的分类概率的加权和。因此,如果一棵树很好地分离了训练数据,P(T=t|D=d)很高,它在最终决策中就有更多的发言权。

等式的可能扩展

高级集成方法是最可靠的预测模型之一,也根据上述方程起作用。他们使用来自众多小树的预测的加权和来对数据实例进行分类。请注意,与我的挑战不同,集合方法并不衡量所有可能的树的预测。那会浪费计算能力。通过基尼指数或熵增等方法,他们隐式地逼* P(T|D ),并忽略劣质树。因此,基尼系数和熵仅仅是计算上有效的方法,而不是贝叶斯解。

但是我们不一定要把这个方程局限在树上。您可以使用不同的分类或回归模型(ML 算法)并计算其概率预测的加权*均值来做出最终决策,而不是使用几棵树。在这里,你只需要用另一个随机变量 M 代替随机变量 T,这个随机变量 M 包含了一系列不同的模型(算法)。

总结

这篇文章非常简要地概述了贝叶斯定理是如何构成集合方法的核心的。目的是从贝叶斯的角度理解决策树,并强调贝叶斯统计如何总是在任何 ML 算法的背景下悄悄地忙碌。我故意没有讨论所讨论的方程中的每一项是如何计算的。这将运行很长时间,还涉及一些其他的数学概念,如贝塔分布。然而,由衷地欣赏决策树是很重要的。我希望以后能报道它。

一个非常好的方法来建立一个“Ok Google”语音应用程序…没有谷歌

原文:https://towardsdatascience.com/a-very-nice-way-to-build-an-ok-google-vocal-application-without-google-6c29681616d1?source=collection_archive---------33-----------------------

杰森·罗斯韦尔在 Unsplash 上的照片

我们都知道,由于更好的 NLP 模型和像 Alexa 或 home 这样的消费者家庭硬件,语音驱动的应用程序在数量和效率上都在增加。

根据谷歌的数据,27%的全球在线人口正在使用手机语音搜索,这一趋势正在上升,而且一旦你开始使用它,它就会变得非常快速和自然。

因此,对于我正在开发的一个个人项目(未来几周会有更多相关内容),我决定构建一个语音界面来执行一些操作,我的需求是:

  • 能够有一个唤醒词,就像“嘿谷歌”,开始语音输入阶段
  • 拥有一些结构化的数据模型,比如链接到命令执行的“意图”,而不是仅仅通过文本库的语音来捕捉单词,并编写大量的“如果 word== 'this' do that”。换句话说,拥有像 DialogFlow 或 Lex 这样的聊天机器人方法。
  • 出于隐私考虑而离线,但没有在本地构建和部署 TensorFlow 或 Pytorch 解决方案,这肯定不是一项简单的任务

因此,当我不得不放弃隐私和控制来换取易用性时——毕竟还是老一套——我发现了 Picovoice!

输入微微语音

引用他们的网站,的话来说,Picovoice 是一个端到端的*台,可以根据你的需求构建语音产品。

最相关的功能是它可以部署在特定的设备上并在本地运行,因此该解决方案不需要互联网连接就可以工作。

这是因为可以使用特定的 web 应用程序(Picovoice 控制台)在线训练特定的模型,然后只需下载并由应用程序使用,无需进一步连接。

但是让我们更详细地看看它是如何工作的

首先,它有四个不同的引擎:

  • 豪猪尾流发动机
  • 犀牛语音意图引擎
  • Cheetah 和 Leopard 语音转文本引擎

顾名思义,第一个用于处理唤醒词,在检测到时触发操作,第二个用于理解意图,基于特定的词检测,另外两个用于一般的语音到文本。

我只使用前两个,但我可能会检查其他的一个,因为有一个完整的和工作良好的离线语音到文本的解决方案会很棒

我们来深究一下吧!

豪猪

控制台非常简单。你输入一个唤醒词,选择一种语言,训练模型。

Picovoice 控制台截图

一旦准备好了,你可以立即在控制台上测试它(或者测试一些已经存在的默认设置,比如“嘿谷歌”、“Alexa”、“Jarvis”等等)

Picovoice 控制台截图

我们马上会看到如何在应用程序中使用它。

控制台也非常直观,但这里的事情有点复杂,因为我们需要声明意图,最终在其中包含变量。

让我们看一个例子,假装建立一个家庭解决方案来控制灯光。

Picovoice 控制台截图

在这个例子中,有三个意图,但让我们关注第一个:它与不同的短语相关联以触发它,每个短语都由替换词、可选词和可能的参数组成,称为槽。

因此,要触发第一个触发器,我可以说“把灯变成绿色”或“把灯变成绿色”或“把所有的灯都变成绿色”等等。

由于模型被预先训练以供本地使用,因此也必须预先决定时隙。当然,如果事情发生变化,这可能是一个缺点,因为新的模型需要用新元素进行训练(在这个例子中,如果新的颜色变得可用)。

Picovoice 控制台截图

在这种情况下,语音到文本的解决方案可以更好地工作,因为不需要再培训。

一旦一切就绪,几乎可以立即测试模型。只需点击麦克风并讲话!

Picovoice 控制台截图

最后,可以在目标设备上本地下载和使用它

Picovoice 控制台截图

请注意,它可以用于个人用途,但有一些限制,但也有企业许可证。

但是,然后呢?如何使用这些模型?只需构建一个应用程序并使用 Picovoice API 和 SDK

有详尽的文档和几个可用选项,所以开始使用它们应该很快。

从文档网站截取的屏幕截图

结论

好的,但是我应该使用它吗?是的,肯定的

首先,也是最重要的,在谷歌和 AWS 服务层面上,它在单词检测方面做得非常好,甚至可能更好。

然后,在本地运行它不仅在隐私方面而且在性能方面都有优势,因为没有网络延迟。

但是,能够在网上试用这个模型,而不需要在本地下载和测试,真的可以节省时间。

最后,它可以部署在几个不同的*台上(Linux,Windows,macOS,Android,iOS,Raspberry Pi 和更开放的其他*台),非常灵活。

因此,如果你需要建立一个基于语音的应用程序,或者只是给你的应用程序添加一些声音,Picovoice 是一个很好的选择:也许比使用托管服务稍微复杂一点,但性能和隐私值得额外的努力。

一个非常简单的健康数据科学家知识图表指南

原文:https://towardsdatascience.com/a-very-simple-guide-of-knowledge-graph-for-health-data-scientists-bb8cefc1db31?source=collection_archive---------12-----------------------

本文旨在为那些对知识图在健康数据科学中的应用感兴趣的人提供一个非常快速的知识图介绍。

凯莉·西克玛在 Unsplash 上的照片

什么是知识图?

好吧,什么是知识图?事实上,我们很多人几乎每天都在使用它。例如,当你在谷歌中搜索单词UCL(点击这里查看它的运行情况),你会在搜索结果页面的右侧看到一个名为 Infobox 的小框。它给你一个伦敦大学学院的快速总结,包括标志,谷歌地图链接,以及关键属性,包括其地址,电话号码和与 UCL 有关的人。所有这些数据实际上都是谷歌从其知识图谱中提取出来的。假设部分或全部这样的信息可以作为你搜索背后的假设问题的直接答案。而且,就像我们所有人都经历过的那样,在许多情况下,这个假设成立。

(谷歌搜索结果的截图)谷歌关于肺炎的信息框,由它的知识图提供支持

同样,如果你搜索一种疾病,比如Pneumonia,谷歌会向你展示一个更加结构化的信息框,让你了解这种疾病的概况、症状以及治疗方法。(点击此处查看)

同样,毫不奇怪,如果你搜索Google Knowledge Graph,谷歌会显示它的信息框。当然,Google Knowledge Graph的信息来自Google Knowledge Graph

知识图谱从何而来?

好吧,那么,Knowledge Graph这个概念是何时何地产生的呢?万维网之父蒂姆·伯纳斯·李爵士提出了所谓的the Web of Linked Data的概念,意思是网络不应该仅仅是相互链接的文档,还应该是相互链接的数据。它还有一个名字叫Semantic Web。其背后改变游戏规则的主要思想是,相互关联的数据可以被计算机直接理解和使用。通过这种方式,计算机可以通过直接与不同的 web 服务对话来自动完成任务。“数据网络”的理念是knowledge graph的根源。对于那些想知道更多的人来说,你可以在下一个网站上查看 Tim 先生 2009 年的 TED 演讲。

知识表示是知识图的核心

(图片作者) 三联 —知识图的原子

“数据网”和“知识图”共享同一个技术栈,叫做knowledge representation。本质上,它由两个主要组件组成:

  • 第一个叫做本体:它是一个特定领域的工件,描述了特定领域中的概念及其关系。例如(上图),二型糖尿病是一种人类疾病,二甲双胍是一种用于治疗二型糖尿病的药物。
  • 第二个组成部分是计算,这就是计算机如何在本体术语上进行类似人类的推理。这叫做推理。大致来说,有两种类型的推理:一种是基于集合论的,另一种是基于规则的。

从技术上讲,有一套实现数据网络的技术(见这里)。万维网联盟 W3C 规定了所有这些技术的技术细节。正如我所承诺的,我不会讨论这些技术细节。

临床知识图表的玩具示例

(作者图片)我们知识图谱的第一个三元组

让我们看一个知识图的例子。假设我们都同意heart attackheart disease的一种类型,并把它作为一条知识放在我们的知识图中(如上)。

(图片由作者提供)包含关于汤姆·史密斯的知识

现在,我们有一个叫Tom Smith的家伙。我们知道他的基本信息,包括姓名和出生日期。不幸的是,汤姆心脏病发作了。我们将所有关于 Tom 的信息添加到我们的图表中(如上所述更新)。

我们现在进一步扩展我们对Heart Diseases的知识。假设所有的Heart Diseases都是一种Diseases。并且,我们定义了上面使用的关系*suffersFrom*,指定它将Patient关联到Diseases

(作者图片)更多关于概念及其关系的定义

有了这样的知识,计算机现在可以从我们的知识图谱中推断出一些新的知识。比如,它会说——好吧,你说所有的Heart Attacks都是Heart Diseases。所以,任何患Heart Attacks的人,也患Heart Diseases。因此,计算机将绘制一个标记为suffersFrom的虚线箭头,如下所示。

(图片由作者提供)电脑可以推断汤姆·史密斯也患有心脏病

现在,计算机查看suffersFrom关系的定义,它将Patient关联到Diseases。现在因为Tom Smith有两个suffersFrom的关系,那么这个人一定是一个patient。因此,它绘制了另一个虚线箭头(见下文)。

(图片由作者提供)*电脑可以推断汤姆·史密斯是患者***

这两种推断的关系对人类来说似乎微不足道。但是,这是一个相当大的进步,因为计算机现在可以像人类一样进行推理,尽管只是一小步。完整的知识图现在看起来如下,包括两个推断的关联。

**(图片由作者提供)两次推理计算后的全知识图

在知识图中,我们通常把事物分成两组:T-boxA-box(见上面用绿色虚线隔开的两个区域)。任何关于概念及其关系的东西都是 T-box 的一部分,T-box 代表术语盒。任何描述实际实体的东西,比如特定的病人,都是 A-box 的一部分,A-box 代表断言框。显然,T-box 是领域特定知识,类似于关系数据库的模式,而 A-box 是实际数据,类似于数据表中的数据行。

T-box 和 A-box 的在线资源

语义 web 社区在创建和共享许多领域的 T-box 和 A-box 方面做了大量工作,生命科学是最受欢迎的领域之一。对于开放领域的 T-box,有一个很棒的网站叫做链接开放词汇。截至 2021 年 9 月,LOV 现在包含大约 760 个词汇(本体)。

对于生物医学领域的 T-box,有一个名为生物门户的网站,由美国国家生物医学本体论中心维护,由斯坦福大学领导。是做生物医学信息学的人必备的工具。它有 922 个本体(截至 2021 年 9 月),包括许多广泛使用的本体,涵盖疾病、药物、遗传学和临床程序。像 SNOMED-CT 、 UMLS 、 ICD 和基因本体这样的东西应用广泛。

对于可公开访问的 A-box, DBpedia 是一个广泛使用的知识库,本质上是维基百科的结构化版本。可以理解,它包含了广泛的开放领域和常识知识。这是一个由德国研究人员领导的项目。维基数据是一个协作编辑的知识图表。它由> 22k 用户维护,目前包含>9500 万个实体的数据,大约是 DBpedia 的 20 倍。在开放和互联的 also 方面也有机构群体的努力。它被称为链接开放数据云,有跨越 10 个不同领域的> 1200 个数据集。

摘要

我们已经学习了关于知识图的四件事。

  • 什么是知识图?
  • 它从哪里来的?
  • 临床领域的一个玩具例子
  • 使用知识图表的在线资源

一种(非常)简化的 ML 模型定价方法

原文:https://towardsdatascience.com/a-very-simplified-approach-to-ml-models-pricing-4af251226779?source=collection_archive---------34-----------------------

如何评估实现模型的预期收益

通常,在数据组织中,利益相关者必须做出关于 ML 策略的决策。诸如是否追求新模型的开发、决定实现一个新模型(希望花费很少的部署成本)或者从数据提供者那里购买信息的选择通常仅仅基于直觉。

在这篇文章中,基于对情景、公司经营的经济模式和 ROC 曲线形状的一般假设,我试图阐明这个话题。目标是有一个函数来计算将基于具有给定 AUC 的模型的策略替换为具有不同 AUC 的模型的边际预期利润增益。

经济模式

在该研究的第一次迭代中,我们将商业模型*似为一个游戏,当客户不违约时,公司赚取费用,否则将失去一个单位价格。

公司可以选择是否向任何顾客出售产品。让我们将条件正定义为客户违约的事件,将预测正定义为公司拒绝运营的事件。

预期利润是:

预期利润=概率真阴性×费用-概率假阴性-概率假阳性×费用

一个假阳性的成本费用作为机会成本,一个假阴性的成本 1,因为价格是单一的。

从 AUC 到 ROC 曲线

目的是在给定 AUC 的情况下构建 ROC 曲线。我们假设所有 ROC 曲线是参数 a 设置为 1 的正则化β函数,并且参数 b 使得曲线的面积等于 AUC 这意味着 b = AUC/(1-AUC)。

下面我们展示了这些曲线的一些例子:

具有不同 AUC 的 ROC 曲线—作者图片

从运营角度到利润

在具有恒定总体不良率的场景中,可以基于一个操作点——(假阳性率,真阳性率)ROC 空间中的一个点——获得经济模型计算代理期望利润所需的所有概率:

Probability true negative = False Positive Rate × bad rate Probability false negative = (1 - True Positive Rate) ×bad rate Probability false positive = False Positive Rate ×(1 - bad rate)

如果公司有一个给定 AUC 的模型,它可以选择最优操作点作为最大化期望利润的点。

预期利润增长

至此,我们可以建立一个从 AUC 到预期利润的函数。

一个公司,在一个给定的场景-不良利率和费用-面临的问题是,是否改变其基于模型的战略,一个新的算法,承诺更好的 AUC,可以使用这个函数作为决策的输入。基于当前模型的 AUC 的该函数的输出减去基于新模型 AUC 的输出是预期利润增加。

让我们通过调查一些示例场景来研究不同的因素如何促成预期利润的增加。

作为第一个例子,让我们看看在费用为 0.2 和不同坏账率的情况下,不使用模型(AUC=0.5)的相对利润增加。

预期利润增加示例-作者图片

可以做一些评论:

  • 对于任何 AUC 收益,利润的显著增加并不是在每种情况下都发生。
  • 在不良率较低的情况下,AUC 收益应该非常显著,以证明模型变化的合理性。

更具体地说:在费用为 0.2 且不良率为 10%的情况下,当新模型的 AUC 至少为 0.79 时,从不使用模型且不过滤掉任何操作的策略进行切换是有利的。

在这种情况下,对提供 AUC 0.85 模型的服务进行查询的最高价格是产品价格的 0.009 倍。

接下来,我们绘制了针对不同场景改变模型时的预期利润增长:

不同情景下的相对利润增长—图片由作者提供

一些进一步的结论:

  • 只有当达到某个临界性能时,切换模型才是有利的。
  • 在分析空间中,结果似乎对 fee 比对基础 AUC 更敏感。

关键 AUC

在示例中,我们看到只有达到某个 AUC 阈值,转换模型才是明智的决策。让我们称之为临界 AUC:给定场景中的最小值,如果被模型超越,则可以看到利润增加。

下面我们可以看到在基本 AUC=0.5 的情况下,不同费用的关键 AUC 在不同坏账率之间的变化。

关键 AUC 示例—按作者分类的图像

对这一结果的观察:

  • 对于一个固定的费用,只有在一个特定的坏率的情况下,任何模型性能增益增加利润。在这种情况下,公司会收支*衡。
  • 对于低不良率,新模型的性能应该非常高,以证明改变简单地不过滤任何操作的天真策略是正确的。
  • 费用越少,就越容易获得关键 AUC。
  • 对于接* 1 的不良率,该模型也应该非常好,以取代拒绝任何操作的天真策略。

警告

  • 本研究中考虑的 AUC 是从整个人群中计算的。实际上,这是很难做到的:我们只能观察实际服用该产品的人的事件结果。这就是为什么没有考虑新人是否有资格进行手术。
  • 我们还认为,改变策略时,费用将保持不变。因此,减少费用以增加产量的可能性就被忽略了。
  • 所考虑的 ROC 曲线族很小。虽然我相信曲线的形状不会对整体结果产生重大影响,但这还有待于进一步的分析来证实。
  • 我们认为模型是完全连续的。专注于某些预测在模型开发中很常见,可能会改变结果。

结束注释

这项研究并不自称已经完成。如果您看到一些可以更好地解决的问题或任何荒谬的假设,请通过任何方式 ping,或者更好的是,使用我在本次研究中使用的回购并进行调整。

如果您想自己探索结果,在回购中实现了计算从具有基本 AUC 的模型切换到不同模型的预期利润的功能。

对 IBM 数据科学专业证书的非常主观的评论

原文:https://towardsdatascience.com/a-very-subjective-review-of-ibms-data-science-professional-certificate-b3294fe92482?source=collection_archive---------0-----------------------

软件开发人员对 PHP 代码的照片由莎拉普卢格。

在您决定选择哪门数据科学课程时,需要考虑一些事情

2020 年 10 月的某个时候,我决定是时候开始我的数据科学生涯了。我有经济学背景,在硕士论文期间自学了编程,所以我完全不知道如何进入这个领域。在阅读了一堆关于其他人认为一个人应该如何开始他的数据科学职业生涯的媒体文章和其他博客帖子后,我最终报名参加了 IBM 的数据科学专业证书。经过一年的学习、咆哮、欢乐,我结束了与课程一年的爱恨情仇,拿到了证书。这是我对本课程非常主观的评价,也是我为什么要从头再来一遍的原因——希望它能帮助你做出更明智的决定!

我为什么选择这门课程?

好问题!还有很多其他的课程,比如哈佛的数据科学课程或者约翰·霍普斯金项目。只需浏览“数据科学课程”的媒体,您将获得数千篇关于哪个课程最适合什么的文章。最后,他们都告诉你同样的事情:你必须从某个地方开始,这不会是你学的最后一门课程。我决定学习 IBM 课程有两个原因:

  • 我想要这个品牌。在撰写本文时,IBM 在财富 500 强公司中排名第 42 位。地球上大部分人都听说过他们,对他们在做的事情有个大概的了解。拥有 IBM 的证书会让向人力资源部门解释变得更容易。
  • 我读了杰夫·黑尔的这篇文章,文章分析了 2019 年就业市场上数据科学家最需要的技能。它指出,Python 和相关库以及 SQL 越来越受欢迎,而像 R 这样的编程语言需求却很少。由于 IBM certificate 主要基于 Python 和 SQL,所以它非常适合我。

课程是如何组织的?

当我开始学习这门课程时,它由 9 个不同的模块组成。大约两个月后,出现了一个弹出窗口,询问我是否愿意升级到包含以下 10 个模块的课程更新版本:

模块 1:什么是数据科学?

我能说什么呢?这是一门标准的入门课程,它完美地完成了自己的工作:它让你对主题有一个宽泛的概述,并有助于消除一些最初的问号。我的主要收获是对数据科学家的杰出定义。它还向我介绍了这本关于数据科学的书,我强烈推荐阅读。

模块 2:数据科学工具

对于像我一样对这个领域完全陌生的人来说,这将会让你大吃一惊。该模块为您提供了大量工具,您可以使用这些工具来处理您在数据科学职业生涯中可能遇到的各种不同的用例。你没有必要把它们都背下来,但是如果你面临新的挑战,这是一个很好的地方。

模块 3:数据科学方法

你将学会如何组织你的工作。听起来很无聊,因为你终于想编码了?是的…听起来很熟悉,但是相信我——你不会想错过的。当你分析和编码更大的项目时,你会很容易迷失。了解一些要坚持的框架是实现你的目标的关键。

模块 4:用于数据科学、人工智能和开发的 Python

标题比实际材料更有前途。您将学习 Python 基础知识以及如何处理标准数据类型。就是这样,没有花哨的 AI,没有开发经验,只是多了一些理论和简单的编码。

模块 5: Python 数据科学项目

终于有事可做了!在这个项目中,你将把学到的基础知识应用到现实生活中。我想说这对于每个人都是可行的,并且给你对新技能的信心——很棒的模块,做起来很有趣!

模块 6:使用 Python 进行数据科学的数据库和 SQL

你没用过 SQL?那么这个课程非常适合你。它为理论提供了一个很好的介绍,并会让你接触很多编码。

模块 7:使用 Python 进行数据分析

这个模块会让你感觉从 0 到 100。它教你数据争论、数据分析和模型创建。如果你以前从未这样做过,你可能会感到不知所措,因为模块 5 和模块 6 没有为你做好准备。慢慢来,一行一行的理解,一个视觉一个视觉的消化。你以后会需要它的。

模块 8:使用 Python 实现数据可视化

没有什么比可视化数据更好的了。这有助于你理解它,本单元将教你如何去做。我不想撒谎——我讨厌用 Python 进行数据可视化。这需要很长时间,但你获得的洞察力是无价的,所以最好仔细听。

模块 9:使用 Python 进行机器学习

另一个听起来更有前途的花哨头衔。本模块将向您介绍使用 Python 可以完成的最常见和最基本的机器学习方法。别指望这会让你掉进兔子洞。然而,我认为这是一个很好的介绍,如果你以前没有经验的话。

模块 10:应用数据科学顶点

这是目前为止我最喜欢的模块。你可以在一个大项目中运用你学到的所有技能。首先,他们告诉你如何做,然后你必须复制它。你给自己制造多大的困难,是你自己的决定。你可以简单地复制和粘贴模块的代码,并以稍微不同的方式应用它,或者你可以想出一些独特的东西。这两种方式都能让你得到你想要的:最终证书。如果你对我是如何做到的感兴趣,请随意阅读我的关于我的顶点项目的文章。

我花了多少时间?

我在一家投资公司做全职工作,我尽可能把空闲时间花在我的未婚夫和我们的两只狗身上。这种惯例不允许花太多时间看几个小时的学习材料,阅读文档,以及花几个小时开发我的代码。所以我最终更有效地安排了我的一天。因此,我每天都会抽出一两个小时来上这门课。我通过每天早上早起来做到这一点。有时我的工作受到干扰,我不得不打破我的时间表,但最终我设法在 11 个月内完成了所有模块。

你要花这么多钱吗?那得看情况。这取决于你已经知道了多少,你有多少承诺,以及你的顶点计划有多困难。我大概花了三个月时间。从我看过的其他顶点项目来看,大多数人在他们的项目上花了两到三周的时间。此外,很多选修这门课程的人都是学生,比工作的人有更多的空闲时间。因此,如果你有一些 Python 的经验,有很多空闲时间,并且倾向于用简单的方法解决问题,你可能不需要超过 3 个月来完成整个证书。

花了多少钱?

订阅这门课程每月花费我 39 美元。你越快,就越便宜。然而,我发现与其他课程或大学学位相比,它非常便宜。另外,在德国,你可以从税收中扣除课程费用。所以最终成本更低。

我的最终意见是什么?

上面我写了一段爱恨交加的关系。我讨厌这门课,因为我早上必须早起。我不喜欢你在最终到达编码部分之前必须观看/通读这么多理论。我讨厌你的作业被其他人评分,他们显然没有花时间阅读你的文档,结果给你的分数更低。

我喜欢这门课程,因为我必须制定一套能让我更有效率的程序。我后来意识到,我不得不看几个小时的理论,因为它不止一次地拯救了我。我发现在给别人打分的时候阅读他们的作品非常有趣。

每个奖牌都有两面。这门课程会让你成为数据科学家吗?不,不会的。但它会让你对主题有一个坚实的理解,并启动你的职业生涯。完成本课程后,您就可以深入更复杂的主题并获得更多技能。

我会再做一次吗?

当然可以。事实上,我刚刚开始了另一门数据工程的 IBM 课程。我开始喜欢我清晨的例行工作,并发现自己缺少一些关于如何从头构建 ETL 管道的知识。我的目标是在 12 个月内完成这个证书,并获得技能,为自己打造一些有用的工具。所以…接受挑战!;-)

低资源 NLP 的可视化指南

原文:https://towardsdatascience.com/a-visual-guide-to-low-resource-nlp-d7b4c7b1a4bc?source=collection_archive---------20-----------------------

思想和理论

如果您只有有限数量的标记数据,最*的方法可以帮助您训练 NLP 模型。

由保罗·基亚布兰多在 Unsplash 上拍摄的照片

深度神经网络在自然语言应用(NLP)中变得无处不在。然而,它们需要大量的带标签的训练数据,而这些数据通常只适用于英语。对于标记数据有限的许多语言和领域来说,这是一个巨大的挑战。

*年来,已经提出了多种方法来处理这种情况。本文给出了这些方法的概述,帮助您在资源贫乏的场景中训练 NLP 模型。这既包括增加标记数据量的想法,也包括遵循流行的预训练和微调范式的方法。我们希望提供指导,帮助您决定哪些方法适用于您的低资源场景。

这篇文章的基础是我们最*关于低资源 NLP 的调查,在那里你可以找到更多的细节和对公开问题的进一步讨论(但是更多的文字和更少的彩色图像😉).

资源可用性的维度

当讨论低资源场景时,通常焦点在于缺少标记数据。然而,存在不同类型的数据,并且许多低资源方法对特定数据的可用性有某些假设。理解一个人的低资源环境和特定方法强加的假设对于选择最佳方法是至关重要的。我们区分资源可用性的三个维度:

  • 特定任务标注数据:最突出的维度。需要领域专家手动注释实例,这通常既费时又费钱。
  • 未标记的特定于语言或领域的文本:通常更容易获得,但对于某些资源匮乏的场景来说可能很少。对于大多数基于某种形式的预训练嵌入的现代 NLP 方法来说,它已经成为需要考虑的重要资源。
  • 辅助数据:虽然在“正常”NLP 中不太占优势,但大多数低资源方法都需要某种形式的辅助数据。这可以是例如不同语言的标记数据、知识库或机器翻译工具。必须考虑到这一点,因为如果一种方法对辅助数据的假设被打破,那么来自一个低资源情景的见解可能无法转移到另一个情景。

我们现在将给出针对低资源场景的当前方法的概述。

数据扩充

在数据扩充中,我们需要少量的标记数据。然后,我们通过获取现有实例并更改其特征而不更改标签来创建更多数据。这是计算机视觉中的一种流行技术,例如,旋转猫的图像不会改变猫的标签。

在下面的例子中,我们有一个情感任务。我们可以扩充句子“电影很棒”,例如,用“电影”或“棒极了”这样的同义词替换一些单词这就保持了情绪标签不变。新句子仍然有积极的情绪。

作者图片

Amit Chaudhary 给出了一个很好的,可视化的调查关于不同的技术来增加 NLP 数据集(他的文章是这篇文章的灵感来源)。

监管不力

弱监督通过一个(半)自动化的过程获取未标记的数据并标注标签。关于如何获得这种自动注释,存在不同的方法。有些是针对某项任务的,有些则可以更普遍地应用。

a)远程监督

对于命名实体识别或关系提取等任务,远程监督是一种流行的方法(Mintz et al .,2009)。需要一个外部知识库作为辅助数据。这可能只是一个名单,但也可能是一个更复杂的知识库,如维基数据。

未标记文本中的标记被自动映射到知识库。在下面的例子中,我们想要自动标注位置。获得城市名称的列表(例如,从维基百科)。如果令牌序列匹配列表中的条目,则为其分配相应的标签;在这里是位置。

b)标签规则

领域专家的许多见解可以用简单的规则来表达。专家可以写下一小组规则,然后使用这些规则自动注释未标记的数据。与必须手动标记大量实例相比,这可以更有效(和有趣)地利用专家的时间。

在下面的例子中,我们编写了一个在文本中查找日期术语的规则。由两个点分隔的一系列 8 位数字通常匹配日期,如 14.03.1879。类似的日期规则已被用于(Strö tgen & Gerz,2013 年)各种语言的时间标记,或(Hedderich 等人,2020 年)检测豪萨语和约鲁巴语的日期。这种标记规则、标记函数或试探法的不同应用可以在例如 such 中找到(Ratner 等人,2020)。

c)跨语言投影

如果一项任务在一种语言中得到很好的支持,而在另一种语言中得不到支持,那么可以使用跨语言预测(Yarowsky 等人,2001)。在下面的例子中,我们假设西班牙语是一种低资源语言,我们只有一个用于英语的命名实体识别工具。我们把这个句子从西班牙语翻译成英语。在英语中,我们的工具识别墨西哥城是一个位置。通过翻译我们知道,英语中的墨西哥城在西班牙语中是 Ciudad de México(所谓对齐)。因此,我们也可以给出墨西哥城的标签位置。

为了从两种语言获得文本,可以使用句子已经对齐的*行语料库,例如 OPUS 或 JW300 。或者,如果存在对这两种语言的支持,也可以使用机器翻译。

d)噪声处理

虽然弱监督允许快速和自动地获得标记的数据,但是与完全手动注释的数据相比,标记的质量通常较低。为了消除不正确标签的负面影响,已经提出了各种标签噪声处理方法。可以训练另外的模型,例如,检测和过滤不正确的标签或者给予它们较低的权重。或者,可以对噪声本身进行建模以清除标签,或者可以使用噪声鲁棒性类型的模型。

预先训练的语言表达

远程监督和数据扩充产生并扩展特定任务的训练数据,

NLP 中最*工作的一个重点在于使用在未标记数据上训练的预训练语言表示。这些方法通过转移学习的表示和模型来减少对标记的目标数据的需要。

a)预培训变压器

变换模型,如 BERT (Devlin 等人,2019)或 RoBERTa(刘等人,2019),在大规模文本语料库上进行训练,其语言建模目标是通过预测下一个单词或句子来创建上下文感知的单词表示。这些模型对于低资源语言特别有帮助,对于这些语言,大量的未标记数据是可用的,但特定任务的标记数据是稀缺的(Cruz 和 Cheng,2019)。

Jay Alammar 在他的博客文章中提供了对 BERT 和相关语言模型的详细描述和可视化效果:图文并茂的 BERT、ELMo 和 How NLP 如何破解迁移学习)。

b)特定领域的预培训

专业文本领域的语言可能与标准语言有很大不同。因此,许多文本域也经常资源不足。然而,最*的大多数语言模型都是在通用领域数据上预先训练的,例如来自新闻或网络领域的文本,当应用于不同领域时,这可能导致所谓的“领域差距”。

克服这一差距的一个解决方案是通过微调语言模型或从头开始训练新的特定于领域的语言模型来适应目标领域。常见的公开可用的领域适应模型包括 BioBERT (Lee 等人,2020 年)、ClinicalBERT (Alsentzer 等人,2019 年)和 SciBERT (Beltagy 等人,2019 年)。

c)多语言语言模式

在跨语言设置中,在低资源目标语言中没有可用的特定于任务的标记数据。相反,来自高资源语言的标记数据被利用。多语言模型可以在高资源语言的目标任务上进行训练,然后应用于看不见的目标语言。

这通常需要通过为多种语言训练单个模型来训练多语言语言表示,例如多语言 BERT (Devlin 等人,2019 年)或 XLM-罗伯塔(Conneau 等人,2020 年)。这些模型使用来自不同语言的未标记的单语语料库进行训练,并且由于在预训练期间看到了许多语言,因此可以在跨语言和多语言环境中使用。

结论

除了上面提到的方法,还有其他令人兴奋的方法来处理低资源 NLP,未来还会有更多的方法出现。关于当前方法和参考文献的更详细概述,以及关于开放问题的讨论,我们想参考我们的 NAACL 论文关于低资源场景中自然语言处理的最*方法的调查。基于这些见解,我们对未来的发展以及低资源 NLP 的其他方面感到兴奋。

作者:迈克尔·海德里希和卢卡斯·兰格。

引文

如果您发现这项工作有用,并希望在学术背景下引用它,请引用 NAACL 的论文:

@ inproceedings { Hedderich-et al-2021-Survey,
title = "低资源场景下自然语言处理*期方法综述",
作者= {Hedderich,Michael A. and Lange,Lukas and Adel,Heike and Str{"o}tgen,Jannik and Klakow,Dietrich},
booktitle = "计算语言学协会北美分会 2021 年会议论文集:人类语言技术",
year = "年

参考文献

  • Alsentzer 等人,“公开可用的临床 BERT 嵌入”(2019),ClinicalNLP@NAACL
  • Beltagy 等人,“ SciBERT:科学文本的预训练语言模型”(2019),EMNLP
  • 曹等.语境词表征的多语种对齐(2020),
  • Conneau 等人,“大规模无监督跨语言表征学习”(2020),ACL
  • Cruz 和 Cheng,“评估低资源语言的语言模型微调技术”(2019),arXiv
  • Devlin 等人,“ BERT:用于语言理解的深度双向转换器的预训练”(2019),NAACL
  • Hedderich,Lange 等人,“低资源场景下自然语言处理的*期方法综述”(2021),NAACL
  • Hedderich 等人,“多语言变压器模型的迁移学习和远程监督:非洲语言研究”(2020),EMNLP
  • 艾尔的李。、“ BioBERT:一种用于生物医学文本挖掘的预训练生物医学语言表示模型”(2020),生物信息学
  • 刘等,“ Roberta:一种稳健优化的 bert 预训练方法”(2019),arXiv
  • Mintz 等人,“无标记数据关系提取的远程监督”(2009),ACL
  • Ratner 等人,“潜航器:在弱监督下快速创建训练数据”(2020 年),《VLDB 日报》
  • Schuster 等人,“上下文单词嵌入的跨语言对齐,应用于零触发依存解析”(2019),NAACL
  • strtgen 和 Gerz,“多语言和跨域时间标记”(2013 年),《LRE 日报》
  • Yarowsky 等人,“通过跨对齐语料库的鲁棒投影归纳多语言文本分析工具”(2001),HLT

多维数组聚合的可视化指南

原文:https://towardsdatascience.com/a-visual-guide-to-multidimensional-numpy-array-aggregation-97a8960b3c59?source=collection_archive---------18-----------------------

思考轴编号的直观方式

如果您刚刚学习使用 NumPy 中的聚合函数,如 sum、mean 或 median,理解轴参数的作用可能会很困难。在接下来的文章中,我提供了一个直观的轴编号指南,这样你就可以确保你的代码按照预期工作。

聚集一维数组很简单,因为只需要考虑一个轴。然而,对于 2 维或更多维,我们必须考虑我们希望聚合数组的方向。在本指南中,我们将使用 numpy.sum()函数讨论一维、二维和三维问题。(注意:其他聚合函数如 mean、median、amin、amax 使用相同的逻辑。)

维度缩减和轴编号

我们可以将沿单个轴的聚合视为将数组的维度减少一个。如果我们聚集一个一维数组,我们得到一个单点。如果我们聚集一个二维数组,我们得到一个一维数组,以此类推。如果我们有多个维度,我们必须决定要消除哪个维度(或轴)。在 NumPy 中,这可以通过在函数调用中指定 axis 参数来实现。

让我强调一下:当您设置参数时,您选择了您想要消除的维度。

关于轴编号,我们必须知道的是索引总是从最高尺寸开始。每增加一个维度,新维度的索引为 0,其他所有索引都增加 1。我们将在下面的示例中详细了解这一点。NumPy 中 axis 参数的默认值是 None,在这种情况下,数组被展*,然后被聚合。

提示:如果你不确定你有多少个维度,但你想选择最低的,你可以使用负索引。例如,axis=-1 将消除最低的维度。

聚集一维数组

>>> a = numpy.array([1,2])

>>> numpy.sum(a, axis=0)
3

在这个简单的例子中,只有一个维度可以用来聚集数组。这个维度是第 0 个维度,即第 0 个轴。(不需要指定轴参数,因为展*的二维数组本身就是。)

聚集二维数组

>>> b = numpy.array([[1,2],[3,4]])

在本例中,我们在前面的数组中添加了第二个一维数组,创建了一个二维数组。请注意,添加的维度是最高的,因此将具有索引 0,而先前的将具有索引 1。

在这里,我们可以选择是消除第 0 维并沿其垂直轴折叠数组,还是消除第一维并沿其水*轴折叠数组。让我们两个都看:

>>> numpy.sum(b, axis=0)
array([4,6])

轴=0 时,我们希望消除第 0 维。我们通过沿其纵轴折叠阵列来实现这一点。

>>> numpy.sum(b, axis=1)
array([3,7])

按照同样的逻辑,这里我们消除了第一维,并沿其水*轴折叠数组。

聚集三维数组

c = numpy.array([[[1,2],[3,4]],[[5,6],[7,8]]])

在这个三维示例中,我们只需将一个二维数组添加到前面的数组中,创建一个 shape(2,2,2)的三维数组。这个添加的维度将是最高的,因此它的索引为 0,而所有其他的索引都增加 1。因为我们有三个维度,所以聚合数组时有三个选项需要考虑。

>>> numpy.sum(c, axis=0)
array([[6,8],[10,12]])

使用轴=0 ,我们指定希望删除最高维度(我们刚刚添加的维度)。我们可以通过折叠三维阵列的两个“层”来实现这一点。

>>> numpy.sum(c, axis=1)
array([[4,6],[12,14]])

随着轴=1 我们希望消除第一维。我们通过沿垂直轴折叠两个二维数组(层)来实现这一点。

这样,我们将形状(2,2,2)的数组简化为形状(2,1,2)的数组。请注意,NumPy 将完全消除大小为 1 的维度,并输出一个较低维度的 shape(2,2)数组,如我的图表的第三阶段所示,除非您设置 keepdims=True。

>>> numpy.sum(c, axis=2)
array([[3,7],[11,15]])

由于轴=2 ,我们希望消除第二维。我们通过沿水*轴折叠两个二维数组(层)来实现这一点。

与前面的例子类似,我们得到了 shape(2,2,1)的数组,但是 NumPy 默认会输出 shape(2,2)的低维数组。

需要记住的要点

  1. 您可以将聚合视为降低数组的维度
  2. 当您选择一个轴时,您实际上设置了您希望消除的尺寸
  3. 索引总是从最高的维度开始

参考

SciPy 社区, NumPy v1.20 手册

(所有图片均由作者创作并拥有。)

想象北极海冰面积的减少

原文:https://towardsdatascience.com/a-visualization-of-decrease-in-arctic-sea-ice-extent-over-past-40-years-fb377bdf94a1?source=collection_archive---------27-----------------------

过去 40 年的动画数据故事

Eva Blue 在 Unsplash 上的照片

嗨!

这篇文章主要是为了展示我的 Udacity 可视化纳米级顶点项目。在这篇文章中,我将向你展示如何制作一个动态雷达图与蓬勃发展和创建演示幻灯片与音频&自动播放功能!

背景照片来源

数据集和清理

根据 Udacity 计划的要求,我只能从 改头换面星期一网站 中选择一个数据集。经过仔细搜索,我决定从事 北极海冰范围数据集 的工作,因为我一直对这个美丽的冰的世界感兴趣。我很想知道在过去的几十年里,冰层减少的速度有多快。

数据来源于 国家雪&冰数据中心 。并且在改头换面星期一网站上与大家分享。

数据集非常简单,有 12,751 行和 2 列。一列是 yyyy-mm-dd 格式的日期,另一列是以百万*方公里为单位的冰范围的数值。

与网站上的原始可视化相比,我想改进它,使其对读者更具吸引力,并确保人们能够感受到几十年来的变化。

为了使数据集更容易可视化,我编写了一些 python 代码来将数据集处理成以下格式:

已清理的数据集(作者提供的图像)

本质上,清理代码如下所示:

import pandas as pd
import calendar #convert month number to month namedf = pd.read_csv('data.csv') #replace with your dataset namedf.Date = pd.to_datetime(df.Date) #Date column to datetime data typedf['month'] = df.Date.dt.month #create new column of month number
df['year'] = df.Date.dt.year #create new column of year df = df.drop('Date',1) #convert month number to month name
df['month'] = df['month'].apply(lambda x: calendar.month_name[x])#group by year and month to calculate monthly average for each year
df = df.groupby(['year','month']).mean().reset_index()#pivot the dataframe to make each month as a new column and year as index
df = df.pivot('year', columns='month')
df.head()

完成以上步骤后,您可能会发现数据集列有点乱。我手动删除多余的列和行,只保留年份和月份名称的列。

蓬勃发展的数据可视化

在 fluorescent 上进行数据可视化的真正好处是,您可以将可视化制作成动画,并上传一个音频文件,该文件将随演示文稿一起自动播放。

riche 提供了如此多的可视化格式和示例,对于这个项目,我选择了带过滤器的雷达。

选择可视化类型(按作者排序的图像)

一旦你点击进去,你会在顶部看到一个按钮,允许你在预览数据之间切换。要上传我们刚刚清理的数据集,需要先点击数据选项。然后,您可能需要根据数据集列更改名称过滤器的值。

最终,数据页面对我来说看起来如下:

资料页(图片由作者提供)

现在,如果我们点击返回预览,您可能会看到每年的雷达图。在右边,有许多选项供我们添加背景图像,调整颜色,字体等。

预览页面(图片由作者提供)

为了查看每年的雷达图变化,而不是在一个页面上查看所有变化,您可以将右侧栏上的控件下的过滤器控件更改为滑块类型。

过滤器控件(图片由作者提供)

默认情况下,可视化可能从“全部”开始,一旦您将滑块滑动到右侧,它应该会开始每年查看一次,雷达图也会相应地改变。

背景照片来源

蓬勃发展的数据故事

最后,我们可以将您之前的可视化变成数据故事!

您可以通过点击新故事在主页上创建一个新故事:

繁荣主页(图片由作者提供)

实际上,一旦进入故事页面,您可以从现有的可视化效果中添加一个新的幻灯片,或者选择一个基本的静态幻灯片。对于基本幻灯片,您可以通过替换图像 URL 链接来上传自己的背景图像。

最后,如果您感兴趣,您可以将 mp3 格式的音频记录上传到数据故事。您可能需要练习几次,以确保您的音频演示完全符合幻灯片自动播放的速度。

点击启用音频上传(图片由作者提供)

局限性和偏见

关于这个项目中现有的限制和偏见,我想指出以下几点:

  • 数据收集偏差:一个月中只有某些天被记录在数据集中,所以每个月的*均值可能不够准确。
  • 数据处理偏差:虽然在我选择的年份中没有缺失值,但如果没有适当的处理,仍然可能存在一些异常值。
  • 数据洞察偏差:目前我们定性地看待变化,并了解过去 40 年的下降,但理想情况下,我们应该给出定量计算,并公布更准确的估计结果。

结论

总之,我对北极海冰面积减少的速度感到惊讶。我只在纪录片中看到过北冰洋是什么样子,但看到这个可视化后,我觉得历史就在眼前。据我所知,许多冰山已经在地球上存在了数千年。然而,有人提出,在本世纪中叶之前,我们可能会在夏天看到一个几乎没有冰的北极。

最后,这里是 链接 到我的顶点演示与蓬勃发展。

非常感谢你的阅读!

数据引用

按年份组织的海冰范围和面积 美国科罗拉多大学博尔德分校国家冰雪数据中心提供

费特尔、f . k .诺尔斯、W. N .迈耶、m .萨瓦和 A. K .温德纳格尔。2017,每日更新。海冰指数,第三版。按年份组织的海冰范围和面积。美国科罗拉多州博尔德。NSIDC:国家冰雪数据中心。土井:https://doi.org/10.7265/N5K072F8

马尔可夫转换动态回归模型的蠕虫视角

原文:https://towardsdatascience.com/a-worms-eye-view-of-the-markov-switching-dynamic-regression-model-2fb706ba69f3?source=collection_archive---------10-----------------------

个人消费支出高波动区域(数据来源美国弗雷德在公共领域许可下)(图片由作者提供)

详细解释了 MSDR 模型,并提供了 Python 教程来帮助您使用真实世界的数据集在 MSDR 上运行

马尔可夫切换动态回归模型是一种隐马尔可夫模型,可以用来表示这样的现象,其中一部分现象是直接观察到的,而其余部分是“隐藏的”。使用马尔可夫模型对隐藏部分建模,而使用合适的时间序列回归模型对可见部分建模,使得时间序列回归模型的均值和方差根据隐藏马尔可夫模型所处的状态而变化。

本文的前半部分详细解释了 MSDR 模型是如何工作的,后半部分是一个快速教程,讲述如何在真实世界数据集上使用 Pythonstatsmodels 和构建和训练 MSDR 模型。****

如果您不熟悉马尔可夫过程,请阅读以下文章:

关于隐马尔可夫模型的详细处理,包括 MSDR 模型,请查看以下内容:

MSDR 模型的一般说明

我们将查看 MSDR 模型的一般说明,该模型由时间索引因变量 y 、回归变量矩阵 X 、拟合系数向量*β_ cap和残差 ε 组成。*

粗体变量表示向量或矩阵。带有“上限”的变量是指该变量的拟合值,即在数据集上训练模型得到的值。

因变量 y

y 为“ n ”时间索引观测值的【n×1】向量 y_t:

因变量 y (图片作者提供)

回归变量矩阵 X

X 为回归变量的【n X(m+1)】矩阵。第一列是截距。x_ t就是这个矩阵的一行。

回归变量矩阵 X (图片来自作者)

拟合回归系数 β_cap

β_cap 为回归系数的 [(m+1) X 1] 向量。**β上的“cap”表示它是模型训练产生的系数的拟合值。

拟合回归系数β_cap 的向量(图片由作者提供)

我们现在考虑包含附加误差分量的时间序列模型的以下一般规范:

y_t 表示为*均值和误差项之和(图片由作者提供)

在上面的模型中,观测值 y_t 是预测值 μ_cap_t 和残差 ε_t 之和。我们进一步假设 ε_t 是一个同态分布和 N(0,σ ) 分布随机变量。

μ_cap_t 是某个回归函数 η(。)这样说:

μ_ cap _ t =η(x_ t,β_ cap)

  • η(。)=0 得出 白噪声模型:y _ t =ε_ t .
  • η(。)=y_bar=(y_1+y2+…+y_n)/n 得出均值模型:y _ t = y _ bar。**
  • η(。)=x_ tβ_ cap产量 线性模型:y _ t =x_ tβ_ cap+ε_ t
  • η(。)= exp(x_ tβ_ cap***)产生了泊松模型或 非线性 泊松模型。***

诸如此类。

马尔可夫模型中的混合

让我们介绍一下 k 状态马尔可夫过程对上述指定回归模型的影响,如下:

用预测均值 μ_cap_t_j 和残差 ε_t 之和表示的观测值 y_t(图片由作者提供)

其中,如前所述,预测*均值是x***_ tβ_cap 的函数:***

μ_ cap _ t _ j =η(x_ t,β_ cap_ j)****

但是这一次,注意回归系数向量被称为β_ cap*_ j对应于第 j 个马尔可夫状态。***

一般来说,如果马尔可夫模型在' k' 状态【1,2,…,j,…,k】上运算,回归系数是大小为 [(m+1) X k] 的矩阵,如下所示:

大小为[k x (m+1)]的系数矩阵(图片由作者提供)

这里的直觉是,取决于[1,2,…,k 中的哪个马尔可夫状态或“状态” j *当前有效,回归模型系数将切换到适当的状态特定的向量β_ cap_ jβ_cap_s 因此得名‘马尔可夫切换动态回归模型’。*****

k-状态马尔可夫过程本身由以下状态转移矩阵 P 支配:

马尔可夫过程的状态转移矩阵 P (图片由作者提供)

并且在时间步 t 具有以下状态概率分布 π_ t :

k 状态马尔可夫过程的状态概率分布向量(图片由作者提供)

并且已知/假设在 t=0π_0 的某个值,我们计算π_***t如下:***

给定 t=0 时的概率分布和转移矩阵 P (图片由作者提供),马尔可夫过程在 t 时的状态概率分布公式

具有线性连接函数的 MSDR 模型

现在假设我们为预测*均值假设一个线性链接函数:****

η(。)=x_ tβ_ cap _ s从而产生 线性模型 为可见过程:****

y _ t =x_ tβ_ cap _ s+ε_ t****

回想一下X*_ t是一个大小为【1x(m+1)】的矩阵,而 β_cap_s 是一个大小为 [(m+1) X k],的矩阵,因此, x***

(图片由作者提供)

因此,对于每个时间步,上述计算返回*均值的 k 个可能预测,对应于基础马尔可夫过程的 k 个状态。我们需要一种方法将它们整合成一个单一的预测。我们通过计算 μ_cap_t_j 的期望值来实现:

预测*均值的期望值(图片由作者提供)

马尔可夫模型在时间 t 处于状态 j 的概率由马尔可夫变量 s_t 的状态概率分布的第 j 个元素给出。我们之前看到,它是以下向量:**

k 状态马尔可夫过程的状态概率分布向量(图片由作者提供)

训练和评估

MSDR 模型的训练包括估计系数矩阵【β_ cap _ s】、转移矩阵 P 和因变量【y】的方差 σ ,估计过程通常是最大似然估计(MLE)或期望最大化。******

我们将说明 MLE,它找到了将使观察整个训练数据集y 的联合概率密度最大化的P**β_ cap _ s和σ的值。换句话说,我们希望最大化以下产品:********

观察数据集的可能性(图片由作者提供)

在上面的乘积中,概率密度f(y= y _ t)的形式取决于我们对【y假设了什么样的模型。****

如果我们假设一个像前面看到的线性模型,概率密度f(y= y _ t)由下面的等式给出:****

k 状态隐马尔可夫模型影响下的正态分布 y (图片由作者提供)

其中, μ_cap_t 是使用等式(1)计算的所有可能状态的预测*均值的期望值。在给定回归变量值x_ t和状态特定系数矩阵 β_cap_s. 的情况下,L.H.S .上的概率被读取为在时间 t 观察 y_t 的条件概率密度******

还有一种计算概率密度的方法。让我们将 f( ) 的公式改写如下:

y 的概率密度取决于 X 以及在时间 t 处于状态 j 的隐马尔可夫过程(图片由作者提供)

其中,μ_ cap _ TJ =x_ tβ_ cap_ j .即回归变量的线性组合和与状态 j:****

正态分布 y_t 的条件均值,表示为回归变量 x t、y_t 的滞后版本和马尔可夫状态相关拟合系数 β_cap * j 的线性组合(图片由作者提供)*

对于一个 k- 状态马尔可夫过程,我们将得到 k 这样的概率密度值,对于每个时间步 t ,对于【1,2,3,…,k】中的每个状态 j 都有一个。**

和以前一样,对于每个时间步,我们希望将这些 k 概率密度合并成一个密度。这一次,我们求助于 全概率定律 ,该定律指出,如果事件 A 可以与事件 A1,或事件 A2,或事件 A3 等等共同发生,那么 A 的无条件概率可以表示如下:

全概率定律(图片由作者提供)

利用这个定律,我们得到在时间 t 观察到 y_t 的概率密度如下:

k 状态马尔可夫模型影响下的 y 的概率密度(图片由作者提供)

注意,在 k 项的每一项中,我们都使用相应的条件均值 μ_cap_tj。而且我们知道 P(s_t=1),P(s_t=2),…等等。是马尔可夫过程在时间 t. 的状态概率

现在我们已经有了 f(y= y _ t)的公式,让我们回到似然方程:******

观察数据集的可能性(图片由作者提供)

最大化这个乘积的自然对数通常是迅速的,因为它的好处是将乘积转换成在微积分中更容易处理的求和(我们很快就会知道为什么)。因此,我们最大化下面的 日志-可能性:****

观察数据集的对数似然性(图片由作者提供)

对数似然的最大化通过使用以下程序来完成:

  1. 取对数似然 w . r . t .中的每个转移概率 p_ij 和系数矩阵 中的每个状态特定系数β_ cap _ q _ jβ_ cap _ s其中 q in [0,1,…,m] 和马尔可夫状态****
  2. 将每个偏导数设为零,
  3. 使用诸如牛顿-拉夫森、内尔德-米德或鲍威尔的中的(k+(m+1)* k系数以及方差σ的某种优化算法来求解与 k 马尔可夫转移概率、 (m+1)k 相对应的 (k +(m+1)k +1)* 方程(实际上比那个数少得多)*

使用 Python 和 Statsmodels 构建 MSDR 模型的教程

在本教程中,我们将使用 MSDR 模型来调查美国个人消费支出和密歇根大学发布的消费者情绪指数之间的可能联系。正如我们将很快看到的,MSDR 模型的隐马尔可夫部分将帮助我们解释个人消费支出数据中的一些可变性,否则用消费者情绪数据进行直接回归可能无法完成。

让我们从检查两个数据集开始:个人消费支出和消费者情绪指数。两个数据集都可以从这里下载。使用 Pandas ,我们将两个数据集加载到一个数据帧中:

***import** pandas **as** pd
**import** numpy **as** np
**from** matplotlib **import** pyplot **as** plt
**import** statsmodels.api **as** sm ***#Load the PCE and UMCSENT datasets*** df = pd.**read_csv**(**filepath_or_buffer**=**'**UMCSENT_PCE.csv**'**, **header**=0, **index_col**=0, **infer_datetime_format**=True, **parse_dates**=[**'**DATE**'**])***#Set the index frequency to 'Month-Start'*** df = df.**asfreq**(**'**MS**'**)*

让我们绘制两个时间序列:

*fig = plt.**figure**()
fig.**suptitle**('% Chg in Personal Consumption Expenditure')
df['PCE_CHG'].**plot**()
plt.**show**()fig = plt.**figure**()
fig.**suptitle**('% Chg in U. Michigan Consumer Sentiment Index')
df['UMCSENT_CHG'].**plot**()
plt.**show**()*

我们得到下面的图:

个人消费支出的百分比变化(数据来源美国弗雷德在公共领域许可下)(图片由作者提供)

消费者情绪指数的百分比变化(数据来源:密歇根大学在公共领域许可下)(图片由作者提供)

回归目标和回归策略

我们的回归目标是使用美国密歇根消费者情绪指数的方差来解释个人消费支出的方差。

因此,我们的回归模型的变量如下:

因变量y= PCE _ CHG(个人消费支出的 M-o-M %变化)

回归变量X= UMCSENT _ CHG(消费者情绪指数的 M-o-M %变化),加上回归的截距。

下面是我们的 yX 矩阵:

yX 矩阵(图片由作者提供)

回归的截距由 statsmodels 添加。

在这两个图表中,我们都可以看到高波动性区域(即方差),如 PCE 图表下方的红圈所示:

个人消费支出高波动区域(图片由作者提供)

我们将使用一个 2 态马尔可夫转换动态回归模型来尝试对高低方差区域之间的这些方差“转换”进行建模:

在高低方差状态之间切换的双态 MSDR 模型(图片由作者提供)

注意,这次我们对马尔可夫状态使用基于 0 的索引,因为这是 statsmodels 使用的。

状态转移矩阵是:

状态转移矩阵(图片由作者提供)

我们的 MSDR 模型的等式如下:

具有状态依赖均值和方差的 2 状态 MSDR 模型的方程(图片由作者提供)

请注意,我们还引入了一个特定于州的方差。我们说,模型的残差正态分布在一个零均值和一个方差周围,该方差根据基础马尔可夫过程所处的状态在两个值之间切换。**

statsmodels 支持方差切换 MSDR 模型。

让我们构建并训练两状态 MSDR 模型:

*msdr_model = sm.**tsa**.**MarkovRegression**(**endog**=df[**'**PCE_CHG**'**], **k_regimes**=2, **trend**=**'**c**'**, **exog**=df[**'**UMCSENT_CHG**'**], **switching_variance**=True)msdr_model_results = msdr_model.**fit**(**iter**=1000)*

trend='c' 告诉 statsmodels 给 X 矩阵添加一个截距。

让我们打印模型培训总结:

***print**(msdr_model_results.**summary**())*

我们得到以下输出:

MSDR 模特培训总结(图片由作者提供)

上述结果中的变量名可以解释为:
β_ 0 = const
β_ 1 = x1
σ= sigma 2
p[0->0]= p _ 00,因此,p _ 01 = 1—p _ 00
p[1->0]= p _ 10,因此,p _ 11–1-p _ 10

通过查看结果中的拟合系数值,我们可以写出特定于制度的模型方程如下:

对于体制=0(低方差体制): PCE _ CHG = 0.0048+0.0026 * UMC sent+ε_ t,
其中ε_t ~ N(0,1.701e-05)

对于政权=1(高方差政权): PCE _ CHG = 0.0041+0.1203 * UMCSENT+ε_ t,
其中ε_t ~ N(0,0.0012)

马尔可夫状态转移图和矩阵 P 如下:

拟合 2 态马尔可夫模型的状态转移图和转移矩阵 P(图片由作者提供)

我们看到,当个人消费支出处于低方差状态时,不到 2%的时间倾向于切换到高方差状态,而如果消费支出处于高方差状态,则倾向于以大约 20%的概率切换回低方差状态。

训练结果中暴露出的一个有些令人不安的事实是,在状态 0 中,UMCSENT ( β_10) 的系数在 95% 置信水* (p 值=0.513 > 0.05) 下不具有统计显著性,在状态 1 中, β_01β_11 在 95%置信水*下不具有统计显著性

让我们画出每个时间步t的马尔可夫状态概率π_t在我们的例子中,时间步是一个月。除了图表π_*t之外,我们还将绘制 PCE %变化图,我们还将绘制根据基于 GDP 的衰退指标数据集(来源于美国 FRED 在公共领域许可下)推断的美国衰退日期。***

*df_r = pd.read_csv(**'JHDUSRGDPBR.csv'**, header=0, index_col=0, infer_datetime_format=**True**, parse_dates=[**'DATE'**])

figure, axes = plt.**subplots**(3)
ax = axes[0]
ax.**plot**(df.**index**, df[**'**PCE_CHG**'**])
ax.**set**(**title**='% Chg in Personal Consumption Expenditure')

ax = axes[1]
ax.**plot**(df.**index**, msdr_model_results.**smoothed_marginal_probabilities**[0])
ax.**set**(**title**=**'**Smoothed probability of regime 0')

ax = axes[2]
ax.**plot**(df.**index**, msdr_model_results.**smoothed_marginal_probabilities**[1])
ax.**plot**(df_r.**index**, df_r[**'**JHDUSRGDPBR**'**])
ax.**set**(**title**='Smoothed probability of regime 1 super-imposed on GDP based recession indicator (Orange)')

plt.**show**()*

我们得到如下的情节:

马尔可夫状态概率叠加了基于 GDP 的衰退指标(图片由作者提供)

我们看到往往当马尔可夫状态模型处于高方差状态时,美国经济处于衰退状态。

下面是完整的源代码:

参考文献和版权

数据集

美国经济分析局,个人消费支出[PCE],从圣路易斯美联储银行检索;https://fred.stlouisfed.org/series/PCE,2021 年 11 月 11 日。在公共许可证下可用。

密歇根大学,调查研究中心,消费者调查。消费者情绪指数。在公共许可下可用。

Hamilton,James,根据基于 GDP 的衰退指标[JHDUSRGDPBR]推断的美国衰退日期,从圣路易斯美联储银行的 FRED 处检索;https://fred.stlouisfed.org/series/JHDUSRGDPBR,2021 年 11 月 12 日。

詹姆斯·d·汉密尔顿, 时间序列分析 ,普林斯顿大学出版社,2020 年。ISBN: 0691218633

形象

所有图片的版权 Sachin Date 归 CC-BY-NC-SA 所有,除非图片下面提到了不同的来源和版权。

相关阅读

***

感谢阅读!如果您喜欢这篇文章,请 关注我 获取关于回归和时间序列分析的提示、操作方法和编程建议。***

贝叶斯统计的零数学介绍

原文:https://towardsdatascience.com/a-zero-maths-introduction-to-bayesian-statistics-4ad3aa1f09df?source=collection_archive---------21-----------------------

解码统计世界的十字军东征——贝叶斯与频率主义

这个不需要多介绍了。数以千计的文章,论文已经写了,一些战争已经打了贝叶斯与频率主义。根据我的经验,大多数人从通常的线性回归开始,并逐步建立更复杂的模型,只有少数人能够涉足贝叶斯的神圣池,这种机会的缺乏以及主题的简洁在理解上造成了漏洞,至少对我来说是这样的。

我不想被太多的数学方程所困扰,我想对贝叶斯统计的内容、原因和位置有一个直观的理解。这是我的一点小小的尝试。

粘土银行在 Unsplash 拍摄的照片

为贝叶斯过程建立直觉

让我们为贝叶斯分析建立一个直觉。我相信你可能曾经被卷入频繁主义和贝叶斯主义的争论中。有很多文献可以解释这两种统计推断方法之间的区别。

简而言之, 频数主义 是从数据中学习的常用方法,用 p 值来衡量变量的显著性。频率主义方法是关于点估计的。如果我的线性方程是:

y 是响应变量,x₁、x₂是因变量。β₁和β₂是需要估计的系数。β₀是截距项;如果 x₁改变 1 个单位,那么 y 将受到β₁单位的影响,例如,如果 x₁是 1,β₁是 2,那么 y 将受到 2 个单位的影响。常见的线性材料。这里需要注意的是,回归方程基于最小化误差*方和(最佳拟合线)来估计各种β的值,这最好地解释了手头的数据,并且估计值是奇点,即β₀、β₁和β₂各有一个值,依此类推。β的估计值被称为β的最大似然估计值,因为它是给定输入 x 和输出 y 时最有可能的值。

贝叶斯 与频率主义方法的不同之处在于,除了数据之外,它还考虑了数据的先验知识。这就是这两个群体之间的分歧所在。频繁主义者将数据视为福音,而贝叶斯主义者则认为总有一些我们知道的关于系统的东西,为什么不用它来估计参数。

数据和先验知识一起被用来估计所谓的后验概率,它不是一个单一的值,而是一个分布。贝叶斯方法估计模型参数的后验分布,而不是像 frequentist 方法那样的单一最佳值。

我们为模型参数选择的先验不是单一值,而是分布,它们可以是正态分布、柯西分布、二项式分布、贝塔分布或根据我们的猜测认为合适的任何其他分布。

我希望你知道贝叶斯定理的术语和脚本

(如果你已经理解了贝叶斯定理,请随意跳过这一节)

虽然这是不言自明的,但让我用一个非常基本的例子来解释一下。

P(A|B)是指给定 B 已经发生的概率。例如,从一副 52 张牌中随机抽出一张牌,假设我们抽出一张红心牌,它是国王的概率是多少?

A =卡为王,B =卡来自红心组曲。

P(A=国王|B =红心)

P(A) = P(King) = 4/52 = 1/13

P(B) = P(红心)= 13/52 = 1/4

P(B|A) = P(红心|国王)=得到红心牌的概率,假设它是国王= 1/4(一组 52 张国王中有 4 张国王,您只能从这 4 张国王中选择一张红心国王)

综合起来,P(A|B) = (1/4)。(1/13) / (1/4) = 1/13 ,所以如果是红心,有 13 分之一的机会拿到国王。

我选择这个简单的例子是因为它并不真的需要贝叶斯法则来解决,所以即使是初学者也可以直观地思考它;如果是红心牌,拿到国王的概率是 13 分之一。

贝叶斯方法如何包含先验信息?

P(A)是我们的*似值或我们拥有的数据。在上面的例子中,P(A)是不考虑套房的情况下获得国王的概率。我们知道得到一个国王的概率是 1/4,所以我们没有从头开始,而是给系统提供一个 0.25 的值。

顺便说一句,托马斯·贝叶斯没有提出上面的方程式,是拉普拉斯提出的。贝氏写了一篇关于他的思想实验的论文“ 一篇关于解决机会主义中一个问题的论文 ”。贝氏去世后,他的朋友理查德·普莱斯发现了这份报纸,在他编辑了几版后,这份报纸在伦敦皇家学会被阅读。

对于贝叶斯推断:

P(β|y,X)称为模型参数β的后验分布,给定数据 X 和 y,其中 X 为输入,y 为输出。

P(y|β,X)是数据的似然性,乘以参数 P(β|X)的先验概率,再除以 P(y | X ), P(y | X)被称为归一化常数。需要此归一化参数来使 P(β|y,X)中的值之和等于 1。

简而言之,我们使用关于模型参数和数据的先验信息来估计后验。

如果你已经走了这么远,给自己一点鼓励吧!😃

资料来源:Giphy.com

许多贝叶斯学派的思想家将谜底归功于艾伦·图灵。是的,他的确建立了概率模型,但是波兰数学家帮助了他。早在战争之前,波兰数学家已经用数学方法解决了这个谜,而英国人还在试图用语言来解决它。万岁https://en.wikipedia.org/wiki/Marian_Rejewski

通过一个例子说明关键时刻

让我们用一些简单的例子来建立我们的直觉,看看我们是否能理解我们在上面学到的东西。

让我们掷硬币 20 次,1 是正面,0 是反面。以下是掷硬币的结果:

这个数据*均值是 0.75;换句话说,有 75%的机会是正面即 1,而不是反面即 0

顺便说一下,任何正常情况下只有两个结果 0 或 1 的过程被称为伯努利过程

采用频率主义者的方法,看起来硬币是有偏差的,即如果我们再扔一次,那么根据频率主义者的估计,硬币更有可能(75%的情况下)正面朝上,即 1。

尽管如此,大多数硬币是没有偏向的,得到 1 或 0 的概率应该是 50%。根据中心极限定理,如果我们投掷硬币无限次,那么正面和反面的概率都是 0.5。现实生活与定理大相径庭,没有人会把一枚硬币扔无限次;我们必须根据现有的数据做出决定。

这就是贝叶斯方法有用的地方。这给了我们包含先验(我们最初的信念)的自由,这就是我们将对抛硬币数据所做的。如果我们没有关于先验的任何信息,那么我们可以使用完全无信息的均匀分布——在实践中,均匀分布的结果将与频率主义方法相同,因为我们告诉我们的模型每种可能性都是同等可能的。**

非贝叶斯(频率主义者)=具有统一先验的贝叶斯

不提供信息的先验给出了与频繁主义者方法相同的结果(图片由作者提供)

在上图中,后验结果和频率主义结果一致,峰值在 0.75 左右(就像频率主义方法一样)。先验是一条直线,因为我们假设是均匀分布。在这种情况下,绿色分布实际上是一种可能性。

我相信我们可以做得更好。让我们改变我们的先验知识,也许是一个 beta 分布,然后观察结果。

之前改为测试版,我们看到它比 frequentist 做得更好

这似乎更好。我们的先验已经改变,因此后验概率向左移动,它不在 0.5 附*,但它至少与频率主义者的 0.75 不一致。

我们可以通过调整先前发行版的几个参数来进一步改进它,使它变得更加自以为是。

与 frequentist 相比,固执己见的先验使贝叶斯方法的结果模拟了真实世界(图片由作者提供)

这看起来好多了,后验概率已经改变了,因为我们已经改变了先验概率,这也更加符合这样一个事实:一个无偏的硬币有 50%的时间是正面,其余时间是反面。

我们现有的关于硬币的知识对结果产生了重大影响,这是有道理的。这与频率主义者的方法截然相反,在频率主义者的方法中,我们假设我们对硬币一无所知,这 20 个观察结果就是福音。

结论

所以你可以看到,通过贝叶斯,尽管数据匮乏,当我们在模型中包含我们最初的信念时,我们还是能够得出大致正确的结论。贝叶斯规则是贝叶斯统计的直觉(这是一个显而易见的说法)的背后,它为频率主义提供了一个替代方案。

  1. 贝叶斯方法结合了先验信息,当我们的数据有限时,这是一个可靠的工具。

2.这种方法似乎很直观——估计您的解决方案是什么,并在收集更多数据时改进这种估计。

请理解,这并不意味着贝叶斯是解决所有数据科学问题的最佳方法;这只是其中的一种方法,学习贝叶斯和频率主义的方法比在这些思想流派之间进行战斗更有成效。

权力越大,责任越大。对一切都要半信半疑。虽然贝叶斯方法有明显的优势,但它更容易产生高度偏倚的结果。人们可以选择一个先验来改变整个结果。例如,在制药业,选择“正确的”药物比投资数百万美元研发更安全有效的药物要容易和便宜得多。当数十亿美元岌岌可危时,在掠夺性期刊上发表*庸的研究并把它们作为你的先验更容易。

延伸阅读:

约翰逊(2002 年)。涌现:蚂蚁、大脑、城市和软件的互联生活。西蒙和舒斯特。

快乐阅读&保持好奇!

资料来源:Giphy

对贝叶斯优化的零数学理解

原文:https://towardsdatascience.com/a-zero-maths-understanding-of-bayesian-optimization-e064a957a124?source=collection_archive---------14-----------------------

为机器学习的贝叶斯优化建立简单的直觉

我送给你一台复杂的假想咖啡机,让你通过调节机器上的数千个转盘来为自己调制最好的咖啡。你是一个聪明的家伙,很快意识到这是一个优化问题。你有两个选择:

  1. 无数次地改变转盘的设置,冲泡不同类型的咖啡,品尝所有的咖啡,找到你最好的咖啡,然后死于过量摄入咖啡因。
  2. 尝试通过量化所涉及的各种因素来找到函数brew-quality = f(brew-styles),并通过计算函数的导数,使用梯度下降法来找到全局最大值。

资料来源:联合国人类住区规划署

这里有两点需要注意:

  1. 我们真的不知道这个函数是什么,它是一个黑盒。我们通过调节转盘来煮咖啡,我们得到咖啡作为输出,机器内部发生了什么,我们真的不知道。我们仅有的信息是在机器的特定设置下咖啡的味道如何。
  2. 即使我们知道的酿造质量功能是什么,评估它也是昂贵的,因为考虑到胃容量和健康危害,我们不能有几千杯咖啡。

那么,我们该怎么办?

有一个框架可以解决这个问题,那就是贝叶斯优化。

当函数是一个黑盒,因此梯度下降不是一个选项和/或函数是昂贵的评估时,它是适用的。这两个标准在这里都得到满足。

贝叶斯优化

让我们假设酿造质量的黑盒函数是:

原始功能,对用户隐藏。这是一个黑盒函数(图片由作者提供)

该函数是一个黑盒,我们只能对不同的输入(brew 风格)进行评估。

假设我们想在只对 15 杯咖啡 进行采样后找到最佳的冲泡方式,我们要做的是冲泡几杯咖啡< 15,在这种情况下,我们冲泡了 6)并有一个如下红色所示的估算函数。

第一次迭代中的估计函数(图片由作者提供)

现在,我们将使用这个估计函数来确定下一步在哪里求值。

这个由估计函数对原函数的估计是一个高斯过程(暂时不需要了解)。另一方面,估计函数被称为替代函数(只是命名)

第二次迭代中的估计函数(图片由作者提供)

借助新生成的数据创建新的估计函数。

从新估计的函数中估计新的评估点(第三次迭代)。继续重复这个过程,直到你完成了所有的评估(在我们的例子中是 15 次)。并希望在 15 次迭代结束时,估计的函数是原函数的良好逼*。

如果估计的函数足够好,那么这种方法将会有效并节省你很多时间。

这种方法比评估每一杯咖啡的冲泡质量更直观,更能模拟现实生活。它本质上是贝叶斯理论(下面讨论)。比方说,对于一杯 100 毫升的特定风格的饮料,你可以以 1 毫升的增量将牛奶量从 15 毫升调节到 50 毫升。如果你已经知道加了 20 毫升牛奶的咖啡太淡了,不适合你的口味,那么你为什么还要评价一杯加了 20 到 50 毫升牛奶的咖啡呢?

另一方面,随机搜索可能会评估许多从 20 到 50 毫升牛奶含量的杯子,从而浪费评估。

请注意,我们的目标不是确定 orange 函数,而是确定采集函数的值,这将有助于以最少的计算次数来确定代理。

写报告的零数学部分到此结束。我将继续讲述更多的细节,并尽可能远离复杂的方程。

关于高斯过程的一个注记

如上所述,从替代物对原始函数的估计是一种高斯过程。让我们试着理解它的意思。

我们使用估计函数(蓝线)来确定评估点(接下来要品尝什么类型的咖啡),从而改进估计函数(尽可能接*橙色虚线函数)。

现在,基于蓝线,我们如何推断出更多关于橙线的信息?

我们想要两样东西:

  1. 我们希望在产量高的点进行评估(记住,我们是在最大限度地提高酿造质量,因此高价值是受欢迎的)。这是 剥削
  2. 我们应该探索我们了解较少的曲线区域,例如,我们不太了解 2 和 3 之间或 5 和 10 之间的情况,因此新的评估点应该来自那里。这是 探索

这种新点的估计是通过称为采集功能的功能完成的。该功能负责*衡勘探和开发之间的权衡,并让我们知道我们在实现这种*衡方面做得如何。

(以下等式在 Quora 的一篇文章中讨论过)

常见的获取函数包括期望改善和最大改善概率

这个获取函数并不大,评估它要便宜得多,因此优化它比做其他事情要容易得多。

让我们定义两个值,

μ(x) =任意输入 x 的函数估计值(蓝线)

∑(x)=不同 x 值的标准偏差(标准偏差 w.r.t 蓝线)

让我们定义一个函数,ζ(x)

在这个ζ函数的基础上,我们可以定义一个(x)获取函数。

a(x)内部发生的事情超出了这篇简单文章的范围,但 a(x)本质上所做的是试图在低μ(x)和高σ(x)之间取得*衡。μ(x)表示开采,σ(x)表示勘探。

这个 pyData 演讲对于理解高斯过程非常有用。

这篇关于 TDS 的文章也讨论了这个问题。

贝叶斯优化的贝叶斯是什么?

(以下部分摘自我在贝叶斯统计上的旧帖子)

贝叶斯 方法考虑系统的先验知识。贝叶斯主义者认为,我们对这个系统总是有所了解,所以,为什么不用它来对这个系统做出更好的猜测呢。

数据(在这种情况下是函数评估)与先验知识一起被用来估计所谓的后验,它不是一个单一的值,而是一个分布。

贝叶斯定理的通俗说法是:

P(β|y,X)称为需要评估的值的后验分布,β,给定数据 X 和 y,其中 X 为输入,y 为输出。

P(y|β,X)是数据的似然性,它乘以参数 P(β|X)的先验概率,再除以 P(y | X ), P(y | X)被称为归一化常数。需要此归一化参数来使 P(β|y,X)中的值之和等于 1。

简而言之,我们正在使用我们关于替代函数的先验信息来估计后验概率。

在贝叶斯优化的情况下:

  1. 我们在代理函数上放置一个先验(由试图捕捉我们对函数行为的信念的高斯过程定义)。
  2. 函数评估被视为数据并用于更新先验以获得目标函数的后验分布。

结论

BO 是直观的,因为它模拟了现实生活,我们有我们的先验信念,我们用它们来估计输出,估计成为新的先验,我们得到更新的后验。当我们处理昂贵的计算和问题空间太大的时候,使用 BO 比梯度下降和它的变种要好得多。

在机器学习中,BO 用于超参数优化,例如,可以在 BO 的帮助下调整随机森林中的树木数量、深度、树叶等。有许多语言的许多库可用于进一步探索概念,如 hyperopt、botorch、bayes-optim 等,并且可以亲眼目睹强大的功能。

我们试图借助一个更接*日常生活的场景来介绍一个困难而简洁的数学过程。

好吧,不完全是!这种假设的咖啡机并不存在,但尽管如此,你有工具在数学方法的帮助下找到最好的咖啡。

来源:

https://static . SigOpt . com/773979031 a2 d 61595 B9 BDA 23 bb 81 a 192341 F11 a 4/pdf/SigOpt _ Bayesian _ Optimization _ primer . pdf

创建图表的 github:【https://github.com/Prashantmdgl9/Bayesian_Optimization

Aarogya-Bot:人工智能驱动的聊天机器人,回答你的医疗问题

原文:https://towardsdatascience.com/aarogya-bot-the-ai-driven-chatbot-to-answer-your-medical-queries-4a76daf80fc4?source=collection_archive---------19-----------------------

Aarogya-Bot 徽标

Aarogya-Bot 是我们在 HackOff-3.0 中打造的聊天机器人,在 2020 年 12 月的“西门子健康人挑战赛”赛道中获得第一名。我们在这次黑客马拉松中谈论我们远程工作的经历,以及我们如何努力适应新的“临时”常态。由于西门子协议对源代码可用性的限制,我们不能开放源代码。

什么是 Aarogya-Bot?

Aarogya Bot 是一个 NLP 驱动的聊天机器人,它将帮助你回答你的基本医疗问题,在新冠肺炎疫情,外出咨询医生不再是一种奢侈。聊天机器人只能根据它的知识图谱库来回答你的医疗问题,所以请记住这一点,并经常与医疗专业人员交叉检查 Aarogya 机器人的回答!我们的 Aarogya 机器人建立在以下技术基础之上:

  1. Python3
  2. 克拉斯
  3. sklearn
  4. Neo4j
  5. vue . j

正如你所看到的,各种各样的技术被用于构建这个普通版本的聊天机器人。截至目前,我们的聊天机器人运行在本地主机上。

Aarogya-Bot 解决什么问题?

今天,当世界面临新冠肺炎疫情时,世界进入了封锁模式,部分封锁因人口而异。人们对很多事情感到困惑,希望咨询医学专业人士的意见。然而,封锁限制了这种奢侈,因此拥有一个可以回答基本医疗问题的聊天机器人变得非常方便。

尽管出现了不同的解决方案,如在线医生咨询、与医生的实时聊天等。,他们还是需要医生坐在屏幕前的时间投入,然后远程诊断一个病人。因此,需要利用 NLP 的能力来帮助回答常见的医疗问题,因为它们构成了患者问题的大部分。这也将有助于节省医生的时间,并允许他们以更好的护理诊断严重的病人。

因此,我们试图建造一个 Aarogya-Bot。到目前为止,它可以尝试回答你关于有限的一组疾病的问题。它可以告诉你它的症状,预防措施和对疾病的描述。如果它不能回答你的问题,或者你对它的回答不满意,强烈建议你去咨询医学专家。由于这是我们聊天机器人的一个普通实现,我们强烈建议不要盲目相信回复。

打个招呼。敬阿洛吉亚机器人

Aarogya-Bot 是如何工作的?

这是我们第一次以团队形式构建聊天机器人。我个人曾开发过集成了 Messenger 和 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 的简单聊天机器人,但它们大多是基于实用程序的,缺少“人工智能”组件。在这里,我们想完全从零开始构建一些东西,从整个后端模型到聊天机器人的前端。因此,眼前的问题相当棘手。因此,我们遵循一个系统的方法,这就是 Aarogya-Bot 的工作方式:

  • 我们建立了一个知识图表数据库,包括选定的疾病、症状、注意事项和描述。这些关系然后被存储在 Neo4j 数据库中,从那里可以获取结果。
  • 为了理解用户的查询,我们使用 Aho-Corasick 算法来识别问题类型的模式并获取合适的结果。
  • 当我们的算法理解用户问题的类别时,查询我们的 Neo4j 数据库,并将适当的结果返回给用户。
  • 如果在我们的知识图中没有找到问题,我们利用从https://questiondoctors.com得到的问答对,并使用问题相似度来获得最可能匹配用户查询的问题,并返回对应于该问题的答案。
  • 对于问题相似性,我们最初训练了一个双向 LSTM +注意力模型,但我们在试图将其用作预测函数时遇到了问题。因此,我们继续使用暹罗 LSTM 来预测最有可能的问题。使用的数据集是 Quora-Question-Similarity,托管在 Kaggle 上。
  • 通过问题相似性方法获取的结果并不总是最合适的,因为一个完全不相关的问题仍然可能与我们数据集中的一些查询相匹配,基于相似性得分。

建造 Aarogya-Bot 时面临的挑战

由于疫情仍然没有消失,封锁仍然存在,这是我们团队必须远程处理的另一个黑客马拉松。因此,我们的第一个挑战是记下聊天机器人的重要组件,确定构建这些组件的技术,然后最终给每个成员分配职责。

我们遇到的第一个障碍是找到一个知识数据库,可以作为我们聊天机器人开始学习的基础。获得精致的知识库是非常困难的,但是由于一些开源创作者的贡献,我们获得了一些知识库。我们建立在他们的想法上,并搜集了一些网站来获得问答配对和疾病信息、预防措施、症状等。一旦这些都准备好了,所有需要做的就是为我们的聊天机器人在 neo4j 数据库中存储关系。

通过知识库图回答问题

下一个障碍是使用双向 LSTM +注意力模式。在训练了整个模型之后,我们努力将其与基于终端的预测器集成,并意识到在将聊天机器人的端点暴露给该模型时存在多个问题,因为数据在馈送到模型之前需要进行大量处理。因此,在网上做了一些调查后,我们又去了 T2 的暹罗 LSTM。

阿罗吉亚机器人利用暹罗 LSTM

这一次,我们能够非常容易地实现我们的预测器功能,这对我们来说是一个很大的解脱,因为这个组件使我们能够回答知识图中不存在的问题,而是从我们收集的问答对中访问类似的问题。

暹罗 LSTM 建筑。来源: MDPI

最后一个障碍,你们可能都很熟悉,就是后端和前端的集成。哦,天哪,这难道不是每个软件工程师的噩梦吗?我们使用 Vue.js 作为前端,使用 Flask 托管聊天机器人来管理我们模型的 REST APIs。我们需要它动态地工作,并相应地设计聊天机器人的用户界面,以便它保持用户参与。“打字…”表情符号的使用确实给我们的聊天机器人增加了“人性化”的感觉。一旦完成,我们的聊天机器人就可以投入测试和使用了。

最终产品(或者是?)

我们的最终产品在黑客马拉松的时间框架内勉强完成。我仍然记得我的智能手表的心率超过 120 次,因为我和我的团队一直在等待我们的一名成员发送我们必须提交的演示视频链接,以验证我们的提交。我记得在截止日期前 30 秒提交了链接。“您的回复已提交”消息帮助我将心跳速率降至正常。感谢 HackOff 3.0 的极其友好和善解人意的组织者,感谢他们在整个黑客马拉松中的持续支持。该项目的演示如下:

虽然我们赢得了这个赛道的黑客马拉松,但我们仍然相信我们的聊天机器人还有很多工作要做,以提高其性能。我们为项目确定的一些潜在未来范围是:

  • 改进我们的暹罗 LSTM 模型,以表现更好。
  • 尝试其他算法,如 XGBoost 等。在 Kaggle 上的 Quora 挑战赛中表现不错。
  • 到目前为止,我们还没有关于问题相似性的好的医学数据集。因此,我们期待在这一领域做出贡献,改进我们的模型。
  • 以更好的方式处理非医疗查询或垃圾邮件查询,即提供更好的意图识别和处理。
  • 与 RASA 集成以获得更好的 NLU,并取代当前使用的 Aho-Corasick 算法。
  • 我们的聊天机器人的在线部署,具有实时响应和低响应时间,因为当前的暹罗 LSTM 在相对较小的问答对语料库上运行相当慢。

关于开发商

我们是队随机。我们忙着做决定。随着每个时代的到来,我们做出下一个决定。毕竟这个世界上的任何事情都是随机的!您可以通过我们会员的个人资料联系他们:

  1. Arghyadeep Das: GitHub , LinkedIn
  2. Nachiket Bhuta: GitHub , LinkedIn
  3. 尼兰什·马图尔: GitHub , LinkedIn
  4. 杰耶什·尼夫: GitHub , LinkedIn

编码快乐!😄

AB 测试:当外部效度扰乱了你的结果

原文:https://towardsdatascience.com/ab-testing-when-external-validity-messes-with-your-results-888197b6bc7b?source=collection_archive---------15-----------------------

适当的统计设置只是成功的一半

(图片来自pixabay.com)

在进行 AB 测试时,etflix 必须考虑周一和周五用户的不同偏好。谷歌,在线实验的最大倡导者之一,检查观察到的结果是否只是一个短期现象。AirBnb 非常清楚 AB 测试的结果可能会随着假期的变化而变化。

这些公司控制的偏见的关键词是外部有效性。AB 测试可以有一个完美的统计设计,如果结果不是外部有效的,仍然会导致错误的结论。让我们更仔细地看看这个在线实验的巨大且经常被遗忘的误差源。

当测试结果和现实有偏差时

终于!你的一项 AB 测试显示了非常积极的,有意义的结果。整个团队都很兴奋,迫不及待地想看到生产中新的设计变化。但是几个星期后,总体指标还是一样的,变化似乎没有任何影响。怎么会这样呢?

有了像 Optimizely 和 Co .这样的现代 AB 测试工具,在进行 AB 测试时有一个适当的统计设计是很简单的。此外,有无数的文章和书籍向分析师、数据科学家和任何对该主题感兴趣的人介绍在线实验背后的机制。

如果 B 测试结果不能代表对你网站未来访问者的真实影响,那么它们就是无用的。

从业者学会思考问题,比如设置适当的重要性水*,决定是进行单边还是双边测试,或者只是如何使用 Optimizely 这样的工具来自动完成所有这些工作。不幸的是,如果结果不是外在有效的,所有这些都是徒劳的。这是一个非常相关的话题,我自己在进行 AB 测试时几乎没有遇到过。

外部有效性的无数面孔

当进行一项实验(或一般的定量研究)时,我们通常从样本中检查数据,以了解我们的测试人群。关于测试人群的学习然后被概括,这意味着我们为整个人群得出结论。

归纳推理的过程(图片由作者提供,基于 Spiegelhalter)

外部效度处理的是由于实验中的人群和从测试中学到的知识所应用的人群之间的差异而产生的偏差。或者用更简单的话来说:实验中的用户可能不能代表你的整个用户群,所以一个特定的变化可能会对这部分人产生积极的影响,但不会对其余的人产生积极的影响。

因此,当考虑外部有效性时,人们不得不问的问题是:实验中观察到的结果可以推广到整个用户群吗?

(图片来自 pixabay.com 的

让我们仔细看看一些可能对在线实验结果的普遍性产生负面影响的因素,以及如何处理它们。

新奇和学习因素

网站的重大改变会让用户(尤其是回头客)感到困惑,并影响关键绩效指标,这被称为新奇效应。例如,如果引入了一个新按钮,用户可能倾向于点击它来看看会发生什么。另一方面,第一次访问网站的新用户可能不太感兴趣,因为他们从未见过没有这个按钮的网站。随着时间的推移,所有用户都会习惯新的组件,相关的指标会在较低的点上趋于*稳。这种效应的影响可以通过在实验中只包括新用户来减轻。

在谷歌 2015 年的一项研究中,用户学习是另一个非常有趣的因素。在实验中,该团队增加了显示给用户的广告数量,以增加每个用户的收入。在实验进行的过程中,谷歌的工程师们观察到,鉴于用户更有可能点击其中一个广告,关键指标有了显著提高。但是在这种实验的通常持续时间之后很久,该团队可以观察到这些收入增加只是短期效应,随后是收入的实际减少。原因是用户习惯于忽略广告,导致广告盲的增加。

时间相关因素

结果可能会有所不同,取决于一周中的某一天、当月或其他季节性影响如假期。一些行业比其他行业更容易受到这些影响。例如,航空业可能会发现,在假期开始前,试图在网站上预订机票的私人客户比例高于商业客户。

在建立 AB 测试时考虑这些影响通常意味着延长测试的持续时间,以获取更广泛的用户群。从事电子商务的一个很好的经验法则是至少运行一整周的 AB 测试,以说明一周中不同天之间的差异。对于航空公司或旅行社等更容易受到季节性影响的企业来说,重新考虑 AB 测试的时间也是一个不错的选择。

另一个非常有趣的时间相关效应是行动时间。一些用户可能会立即使用新的功能或设计,而另一些用户则有点犹豫。结果是,我们首先看到对更冲动的用户的影响。当一个实验只运行一小段时间时,我们可能只根据对这个特殊群体的观察来做决定。更长的运行时间也有助于减轻这种影响。

(图片来自 pixabay.com 的

用户相关因素

在一个实验中,用户的类型可能会大大偏离你的正常用户群,这取决于除季节性以外的外部影响。想象一下,你的营销团队开展了一场新的活动,为你的网站吸引了大量新用户。或者一个竞争对手也这样做,导致你的网站这个时间的新用户比例发生了显著的变化。你的实验运行的时间越长,就越有可能干扰这样的事件,导致潜在的有偏见的结果。

un 竞争对手的营销活动等可预测的事件会使你的实验结果无效。

严重的用户偏见是一种在游戏或社交网络*台上特别容易观察到的现象。它描述了这样一个事实:在一个特定的实验中,频繁使用的用户比不频繁使用的用户更容易被淘汰。这种不*衡会使整体治疗效果偏向那些重度使用者的偏好。根据您对这个特定测试的目标,这可能会产生深远的影响。

我不想遗漏的另一个与人口相关的影响在于实验(*台)设置本身。用户可能会同时接触到多个实验,这些实验可能会相互影响。假设一个用户在您的测试 A 和另一个测试 B 中被分类。测试 A 显示正面结果,而与测试 B 相关的指标没有变化,因此只实施了测试 A。在这一点上,可能发生的情况是,从实验 A 引入的改变不再交付测量的效果,因为它只在与 b 结合时起作用。

在实践中处理外部有效性

进行 AB 测试时,有一个统计上完美的设置是必要的。但是正如你所看到的,如果这些测试的结果来自一个不具代表性的样本,那么它们是没有用的,因为它们是不可概括的。

可能威胁 AB 测试可推广性的因素很多,而且到目前为止还不完整。那么在进行 AB 测试结果时,我们该如何处理外部效度呢?

广泛的共识是,更长的测试持续时间将减轻几乎所有这些威胁的影响。当然,测试时间的延长会带来新的挑战。长时间运行测试会增加机会成本,并且像 cookie 搅动这样的事情可能会成为一个问题。进一步的措施是在一段时间后重新运行测试,并确保在您的实验中包括不同的流量来源。

在我看来,风险必须逐案评估。总的来说,我强烈主张不要进行少于 7 天的 AB 测试。但是有时候,这样做可能是好的。在其他情况下,季节性效应导致的错误决策的风险可能太高,因此需要更长的时间窗口。最终,人们必须权衡一个错误决策的影响(例如,关于一个新特性的发布)和在测试进行时对结果的可推广性的威胁。

参考

对本文有帮助并提供更详细概述的论文和文章:

  • 统计的艺术:如何从数据中学习
  • 着眼长远:对用户和业务都有好处 霍恩霍尔德等人。
  • 值得信赖的在线对照实验:Kohavi 等人解释的五种令人困惑的结果
  • 在线 A/B 考试的可信度分析:陷阱、挑战与解决方案Alex Deng 等人。
  • 格奥尔吉·格奥尔杰夫在线 AB 测试 中的统计方法
  • 论 A/B 测试中的大用户偏差 王等。
  • 网飞和 AirBnb 的例子

关于后决策状态

原文:https://towardsdatascience.com/about-post-decision-states-again-5725e5c15d90?source=collection_archive---------34-----------------------

思想和理论

论强化学习中状态-动作对和决策后状态的(不那么)细微差别。

照片由雷·轩尼诗在 Unsplash 上拍摄

我之前关于后决策状态的文章没有得到太多关注,所以我决定再写一篇(我猜是关于狐狸和陷阱的)。

在上一篇文章中,我为强化学习中状态-动作对和决策后状态之间的相似性做了一个案例。简而言之,决策后状态是状态和行动的结合(例如,在添加标记后的,但是在之前的),这是世界再次开始运动之前的一种中间状态。

然而,在关注相似之处的同时,我也掩盖了这两个概念之间的一些重要差异。留下他们未提及的感觉未完成。这篇文章着重于区分后决策状态和状态-行为对,给出了一个更完整的观点。

什么是决策后状态?

当然,我不能从我离开的地方跳回去,所以让我们总结一下后决策状态的概念(详细描述见 Powell [1])。正如介绍中所说,这是采取行动后的问题状态,但在新的随机信息到来之前(这将引导我们进入下一个预决策状态)。通常,根据当前状态和可行的行动,您可能会达到决策后状态S'⊆S 的子集。通过分解从一个状态到另一个状态的转换函数,可以更好地理解这个概念。

通常,我们有一个转移函数f,它将当前状态s_t、选择的动作a_t和外部信息ω_t引导到下一个状态s_t+1:

从一种状态到另一种状态的转换

这个转移函数包含一个确定性成分和一个随机成分,我们可以明确区分。首先,我们可以确定性地从预决策状态s_t前进到后决策状态s_t^a:

从状态-动作对到决策后状态的确定性转换

第二,我们可以从随机过程中采样ω_t,并从决策后状态移动到下一个决策前状态s_t+1:

从决策后状态到下一个决策前状态的随机转换

除了计算 Q 值Q(s_t,a_t),我们还可以计算决策后状态的 Q 值Q(s_t^a),提供一个更清晰的视角。此外,我们通常基于决策后的状态来设计功能:再订购后的库存水*、移动后的网格位置等。简单地说:决策后状态包含了我们拥有的最新信息。

井字游戏

在井字游戏中——上一篇文章中使用的例子——状态-动作对和决策后状态实际上是相同的。只有最新的主板配置才是最重要的,而不是为了达到这个目标而采取的措施。决策后状态实际上是状态-动作对的串联:

查看给定井字游戏状态下的可用操作。绿色玩家可以采取三个动作或者(等价地)达到三个决策后状态。[图片由作者提供]

实际上,状态-动作对和决策后状态在这里是等价的。你最后采取的行动并不重要,重要的是棋盘的当前状态。在当前状态下,您要么采取 3 个允许动作中的 1 个(即,3 个状态-动作对),要么评估可能达到的 3 个决策后状态。

接下来的两个例子说明了概念并不总是如此相似。

悬崖漫步

为了显示状态-动作对不同的情况,考虑悬崖行走问题。在 SARSA 或 Q-learning 中,你可以用Q(s,a)值填充一个查找表,用s表示网格上的位置,用a表示可行的移动(左、右、下、上)。相比之下,决策后状态将只是网格位置。

状态-动作对和决策后状态的 Q 值之间的比较。对于每四个状态-动作对,我们只需要存储一个决策后状态的值。[图片由作者提供]

请注意,在处理状态-动作对时,我们有 48*4=192 个 Q 值,但只有 48 个决策后值。到底有什么区别?

让我们仔细看看突出显示的单幅图块。它可以从四个相邻的图块到达,每个图块都有自己的状态-动作对。然而,对于剩余的轨迹,你如何在给定的瓷砖上着陆实际上并不重要——重要的是到达目标的剩余步骤数。

决策后状态巧妙地抓住了这一现象。不考虑前面的图块,我们只需要一个单个后决策值来预测剩余的步数。让四个不同的Q(s,a)值指向单个图块实际上是一个非常低效的解决方案。观察到——为了达到相同的精度——我们需要比决策后实现多四倍的观察值。

只有四个动作,我们或许可以承受打击,但如果我们有 1000 个动作呢?对于大多数 RL 问题来说,将计算工作量减少 1000 倍将是非常有益的。决策后状态是这里首选的建模选择。

多臂土匪

在 RL 教科书的例子中,多臂匪徒有点古怪,因为它本质上是一个无状态问题。我们有 n 台老丨虎丨机,拉一下杠杆,我们又回到了同一套老丨虎丨机。如果没有问题状态,我们如何计算决策后状态?

由卡尔·劳在 Unsplash 上拍摄的照片

实际上,我现在不想讨论这个哲学问题。更有趣的是,没有直接奖励。只有在拉动杠杆后我们才能观察到随机回报,这意味着它被嵌入到外生变量ω中。我们如何将它纳入决策后状态?

恐怕严格来说我们不能。如果后决策状态必须在状态空间的子集中S'⊆S并且S不存在——或者,充其量,它保持一个单一的、不变的状态——我们不能导出任何(有意义的)后决策状态。相比之下,国家-行动对出现在(s,a) ∈ S × A中,这是我们可以处理的事情。

在这种情况下,状态-动作对优于决策后状态。即使我们有实际的状态要处理,我们也必须记住区分奖励所采取的行动;我们不能简单地把所有的观察堆到一个单一的决策后状态。

正如您所看到的,选择最佳的建模方法并不总是微不足道的!

外卖食品

  • 在许多情况下,决策后状态和状态-动作对可以很容易地互换,但建模的含义可能是实质性的。
  • 如果如何达到给定状态并不重要,那么使用决策后状态。
  • 如果奖励是随机的,并且在选择行动时是未知的,那么使用状态-行动对。

对更多背景感兴趣?查看我之前关于后决策状态的文章:

[## 什么是后决策状态?他们想从我们这里得到什么?

towardsdatascience.com](/what-are-post-decision-states-and-what-do-they-want-from-us-9e02105b7f40)

参考

[1]鲍威尔,W. B. (2007)。*似动态规划:解决维数灾难。约翰·威利&的儿子们。

关于 Spark 3.x 中的排序

原文:https://towardsdatascience.com/about-sort-in-spark-3-x-f3699cc31008?source=collection_archive---------11-----------------------

深入探究 Spark SQL 中的数据排序。

由iorni.com在 Unsplash 上拍摄的照片

排序数据是许多应用程序、ETL 过程或各种数据分析中需要的非常重要的转换。Spark 提供了几个函数来根据用户的特定用例对数据进行排序。在本文中,我们将描述这些函数,并进一步了解 sort 是如何工作的,以及它的结果是什么。我们还将运行一个简单的实验,看看排序对文件系统中已创建文件大小的影响。

对整个数据帧进行排序

对于整个数据帧的排序,有两个等价的函数 orderBy()sort() 。它们之间真的没有什么区别,所以你会用哪一个真的是你个人喜好的问题。关于这些函数,需要了解的重要一点是,它们会导致混乱,因为数据需要在集群上重新组织才能达到所需的顺序。

此外,这些排序函数是转换,所以它们是懒惰的,不直接触发作业。然而,当您运行一个作业时——通过调用诸如 write 之类的动作——您会注意到 Spark 运行了由排序引起的另一个作业。

从 3.0 版本开始,发现它变得更加困难,因为启用了自适应查询执行(AQE)功能,并且它为每个阶段运行不同的作业,因此现在一个操作触发更多作业是很常见的事情。但是无论 AQE 是否启用,排序都将触发一个额外的作业,因为 Spark 需要估计排序列中数据的分布,以确定如何在分区之间创建边界。让我们看一个特殊的例子:

(
    df.orderBy('creation_date')
    .write
    .mode('overwrite')
    .format('noop')
    .save()
)

运行上述查询后,如果我们检查 Spark UI,我们将看到为该查询生成了两个作业。第一个作业(id 为 2)负责估计 creation_date 列中的分布,并试图将其分成 200 个区间。这个数字 200 是由内部配置设置spark . SQL . shuffle . partitions给出的,可以更改为不同的数字。这也是下一个作业(id 为 3)有 208 个任务的原因,因为它分两个阶段运行,其中第一个阶段有 8 个任务,第二个阶段在重新分区后有 200 个任务:

作者图片

关于数据排序的信息也可以从查询计划中推断出来。它由排序操作符表示,如果您在 Spark UI 的 SQL 选项卡中查看图形表示,您将会看到以下操作符:

作者图片

将鼠标悬停在它上面时,您还会看到一个较小的黑色矩形,其中包含一些附加信息,告诉您哪些列用于排序。布尔信息 true/false 表示这种排序是全局的还是局部的。在这里,因为我们正在对整个数据帧进行排序,所以它说 true 表示全局排序。

如上所述,全局排序需要对数据进行重新分区,因此整个数据集将被打乱,这由位于排序之前的交换操作符表示:

作者图片

关于分区的信息在黑色矩形中,它表示range partitioning(creation _ date,200)。**range partitioning是一种不同于 hashpartitioning 的分区类型,当您想要实现 hashpartitioning 时,也可以通过调用 repartitionByRange() 来实现这种分配,repartitionByRange() 是 repartition(col) 的对应物。

这两种排序函数都可以与下列列转换结合使用:

  • asc_nulls_first(列名)
  • ASC _ nulls _ last(col _ name)
  • desc(列名)
  • desc_nulls_first(列名)
  • desc _ 空值 _ 姓氏(列名)

这些函数只是用来定义空值应该放在哪里,以及应该使用升序还是降序。然后,我们可以将它称为排序函数的参数,如下所示:

df.orderBy(desc('creation_date'))

分类分区

如果您不关心所有数据的全局排序,而是只需要对 Spark 集群上的每个分区进行排序,那么您可以使用sortwithinspartitions(),这也是一个数据帧转换,但与 orderBy() 不同,它不会导致洗牌。该函数不会对数据进行重新分区,它将保持当前的分区,并且只会对这些分区进行排序:

# each partition will be sorted by creation_date column
df.sortWithinPartitions('creation_date')

分类桶

创建分桶表时,有一个函数 bucketBy 可以用来对桶进行排序:

(
  df
  .write
  .bucketBy(n, field1, field2, ...)
  .**sortBy**(field1, field2, ...)
  .option('path', output_path)
  .saveAsTable(table_name)
)

关于分桶和这个特定函数的更多细节,请查看我最*的文章Spark SQL中的分桶最佳实践。

对每个数据帧行上的数组进行排序

另一个排序用例是 Spark 复杂数据类型的数组。数组包含有顺序的元素,Spark 提供了改变顺序的函数:

  • 数组 _ 排序
  • sort_array

这两个函数都按升序对数组进行排序,它们在处理空值的方式上有所不同。另外, sort_array 可以接受另一个参数 asc=False ,通过这个参数可以对数组进行降序排序。对数组进行排序的一种更灵活的方式是 SQL 函数 array_sort ,它可以将一个比较器作为附加参数。更多细节,请见我的另一篇文章,在那里我也描述了它并提供了一个特殊的例子。

与排序相关的 Spark 优化

排序是一个非常昂贵的操作,因此一个好的优化是避免它,如果它不是必要的。Spark optimizer 有一个规则消除排序,它就是这样做的。想象一个如下的例子:

(
  df
  .orderBy('created_date')
  .select('id', 'message', 'interaction_count')
  .filter(col('interaction_count') > 100)
  .orderBy('interaction_count')
)

在这里,我们可以看到,第一次按 created_date 排序对最终输出没有影响,并且是多余的,因此规则 EliminateSorts 将删除它。只要 select 或 filter 中的表达式是确定性的,就可以这样做。在消除排序规则中,不确定性表达式被跳过。例如,如果在 select 函数中使用 rand() ,两个排序都将保留在查询计划中并被执行。

排序对数据压缩的影响

将数据保存到外部存储系统时,对数据进行排序也会产生影响。根据选择的文件格式,它将影响保存数据的最终压缩。让我们来看一个简单的基准测试,其中这一点非常明显。我们将获取一个数据集并多次保存,每次都使用不同的排序技术,最后检查所创建文件的大小。我们将使用的数据集表示社交网络上一年内发布的消息,它具有以下列和结构:

  • profile_id —社交网络上的个人资料/页面的标识符
  • created_time —一个在个人资料上发布消息的时间戳
  • 创建 _ 月份 —从创建 _ 时间时间戳导出的月份
  • 许多其他具有复杂层次结构的字段对分析并不重要

数据集有 301 204 753 条记录,并且在 profile_id 列中包含许多重复项,因为每个配置文件可以发布许多消息。数据集中配置文件的不同计数是 410 836。在下面的 7 个查询中,我们将测试所有三个排序函数并检查最终大小。对于所有查询,我们将 shuffle 分区设置为 2000,考虑到数据集的容量,这似乎是合理的。在前六种情况下,我们将以 parquet 文件格式保存数据,在最后一种情况下,我们将使用 orc 来查看它与最后一种情况下的 parquet 相比如何。

  1. 作为参考,我们将首先应用无排序,然后随机分配数据:
(
  df.repartition(n)
  .write
  .format('parquet')
  .mode('overwrite')
  .option('path', output_path_1)
  .save()
)

2.接下来,我们将对 created_time 列应用全局排序,因此所有发布的消息将根据它们发布的时间进行排序:

(
  df.orderBy('created_time')
  .write
  .format('parquet')
  .mode('overwrite')
  .option('path', output_path_2)
  .save()
)

3.现在,我们将尝试首先按 profile_id 列排序,然后按 created_time 排序:

(
  df.orderBy('profile_id', 'created_time')
  .write
  .format('parquet')
  .mode('overwrite')
  .option('path', output_path_3)
  .save()
)

4.在下一个测试中,我们还将应用按月分区,因为数据非常大,并且在实践中,您可能希望在文件系统中对其进行分区,以便可以使用分区过滤器更快地检索数据。请注意,我们将按两列进行重新分区: created_time ,然后是给定时间间隔内的一个随机值,通过这个值我们可以控制创建文件的数量。然后,每个创建的 Spark 分区按照创建月概要 id、创建时间进行排序:

(
  df.repartition('created_month', (rand() * 200).cast('int'))
  .sortWithinPartitions(
      'created_month', 'profile_id', 'created_time'
  )
  .write
  .partitionBy('created_month')
  .format('parquet')
  .mode('overwrite')
  .option('path', output_path_4)
  .save()
)

5.作为先前技术的替代方法,我们现在将按范围重新分区,这样我们可以避免分布的随机性:

(
  df.repartitionByRange('created_time')
  .sortWithinPartitions(
       'created_month', 'profile_id', 'created_time'
   )
  .write
  .partitionBy('created_month')
  .format('parquet')
  .mode('overwrite')
  .option('path', output_path_5)
  .save()
)

6.接下来,我们还将测试存储桶,并根据 profile_id 列将数据集分成 200 个存储桶。实际上,如果您想要将 profile_id 列上的表与其他一些表(例如,包含每个概要文件的一些附加信息)连接起来,这可能会很有用。

使用 sortBy 函数,每个存储桶将按照 profile_id 进行排序。我们还希望保留按月进行的分区,并且在每个文件系统分区中,我们希望每个存储桶创建一个文件,以达到合理的文件数量。为此,我们通过列 created_month 以及由 bucketing 函数生成的表达式对数据进行重新分区,您可以在下面看到该函数的定义。这个 bucketing 函数模仿了 Spark 的内部行为,关于它的更多细节请参见我最*的关于 bucketing 的文章。

(
  df.repartition('created_month', bucketing('profile_id', 200))
  .write
  .partitionBy('created_month')
  .bucketBy(200, 'profile_id')
  .sortBy('profile_id', 'created_time')
  .format('parquet')
  .mode('overwrite')
  .option('path', output_path_6)
  .saveAsTable('test_table')
)from pyspark.sql.functions import hash, whendef bucketing(col, buckets):
  _mod = hash(col) % buckets
  return when(_mod < 0, (_mod + buckets) % buckets).otherwise(_mod)

7.最后,我们将测试最后一个查询的 orc 文件格式。所以这里我们运行相同的查询,但是使用。格式(' orc')

对于所有的查询,我们使用 Spark 3.0.1 和 Databricks runtime 7.3。现在,让我们在下图中查看每个已创建数据集的最终大小:

分类文件的其他好处

除了更好的压缩之外,以 parquet 等文件格式排序的数据对于在排序列上使用过滤器的查询也是有益的,因为 Spark 将能够应用数据跳过技术。关于 parquet 中数据跳过的更多细节,请参见我的另一篇文章。

结论

在本文中,我们讨论了 Spark SQL 中可用的不同排序技术。我们已经看到了局部排序和全局排序的区别。我们还提到,全局排序通常是一种开销很大的操作,因为它需要对数据进行重新分区,导致数据混乱,还需要一项额外的工作来估计数据的分布。

我们还检查了排序对文件系统中创建的文件大小的影响。大小的差异可能非常大,在我们的示例中,从没有排序的 346 GB 到对两个特定列进行全局排序的 214 GB 不等。这里,字段的不同组合可能会导致更好的压缩。在实践中,全局排序可能不是最有用的设置,因为通常希望对大型表进行分区,甚至可能为了高效的连接而分桶。在这里,我们可以看到,与仅使用分区相比,分区和分桶一起使用导致了更小的大小。这很可能是因为在 profile_id 列上的分桶将具有相同配置文件的记录放在一起,从而提高了压缩。在上一个示例中,我们还看到,orc 数据集的大小略大于相应的拼花数据源的大小,但差异很小,两个数据集在大小上是相当的。

使用气流 DAG 工厂提取数据加载

原文:https://towardsdatascience.com/abstracting-data-loading-with-airflow-dag-factories-12b6689f0aaa?source=collection_archive---------9-----------------------

创建一个抽象层,提高用 Airflow 加载 Google Sheets 数据的可伸缩性和可用性

这个话题并不新鲜。我看过不少关于为气流 Dag 生成不同层次抽象的文章。例如,这篇文章解释了如何以编程方式生成 Dag,这个库允许您使用 YAML 生成 Dag。然而,这两种抽象仍然需要数据从业者来处理。我在寻找一种抽象,它将消除创建气流 Dag 的复杂性和技术性,并允许作者专注于数据源特定的配置。要做到这一点,DAG 工厂需要做很多假设,并且非常固执己见,所以我正是这么做的。

这篇文章将向你展示我如何生成气流工厂来处理不同的数据源,允许我使用显式 YAML 文件创建 Dag。我的目标是创建一个抽象,使涉众能够生成气流 Dag 来提取他们的数据并将其加载到我们的数据仓库中。

我们来谈谈 Google Sheets

我将向您展示的概念适用于任何数据源,如果您实现了它,无论数据源是什么,您都将获得好处。然而,这方面的一个小例子是 Google Sheets。不管你喜不喜欢,大多数业务要么在 Excel 上运行,要么在 Google Sheets 上运行(或者两者都运行!)不久之后,您将会遇到利益相关者,他们会请求将数据从 Google Sheets 文件加载到您的数据仓库中。现在,这不是一篇关于数据哲学的博文,我也无意讨论 Excels 和 Google Sheets 这个(非常敏感的)话题。但是,我要说的是,如果您选择允许您的利益相关者将 Google Sheets 加载到您的数据仓库,您很快就会看到许多请求:更改列名、列类型、添加列、删除列、更改表名等等。想象一个理想的世界,在这个世界中,你的利益相关者拥有自己创建管道的权力。在这个世界中,作为数据从业者,您将从所有这些请求中解脱出来,不再成为利益相关者的瓶颈。与此同时,权力越大,责任越大,当你的利益相关者获得管理他们自己的 Google Sheets 管道的权力时,他们就成为了这些数据的所有者。如果改变一个列破坏了摄取,你不再对此负责(某种程度上),这是他们的责任,他们有能力修复它。我知道你在想什么,是的,这实际上是一把双刃剑。创建自己的 Google Sheets 管道的能力可能意味着您的数据仓库变成了一个黑洞,充满了结构、含义和/或命名约定都很差的无尽 Google Sheets 数据。再说一遍,我不是在这里争论赞成或反对。如果你实现了这一点,我相信你会对推向生产的东西保持高度的治理。你的批判性思维最终会让你自由。

你不同意让股东加载他们的 Google Sheets 文件吗?好吧。从具体的用例中抽象一点,把 DAG 工厂看作是帮助你的团队更有效率、更干爽和避免错误的一种方式。所以不管它是从事务 API 加载 Google Sheets 还是其他一些数据都没关系;你的团队可能会受益于使用气流 DAG 工厂。

说完这些,我们可以探索如何使用 Airflow DAG 工厂加载 Google Sheets 数据。还有一点很重要,那就是这绝对不是从 Google Sheets 文件加载数据的唯一方式。例如,Gitlab 实现了他们自己的工具,他们称之为 SheetLoad (说真的,很棒的名字),还有类似 Fivetran 和 Stitch 的工具。然而,如果你的团队已经在使用气流或者你想要额外的定制,这篇文章将会很有帮助。

我跑题了。关于这一点的真正要点是,它不是关于谷歌表;是关于易用性。这很重要,即使只有你的团队在使用这个工具。例如,我宁愿为从 Salesforce 加载数据编写 YAML 文件,也不愿为每个对象编写 Python 脚本。本质上我只是在倡导好用和干爽(不要重复自己)。

DAG 工厂到底是什么?

所以在这一点上,你可能会想,DAG 工厂到底是什么?更一般地说,DAG 工厂是以编程方式生成气流 DAG 的脚本。但是,在这种情况下,我再加一个条件。工厂从 YAML 配置文件以编程方式生成 Dag。

作者图片

更具体地说,在我们的/dags目录中,我希望有一个/dags/gsheets目录来保存所有的 YAML 文件。所以我们会有类似/dags/gsheets/invoices.yaml/dags/gsheets/products.yaml的东西,目标是让 Airflow 为那些配置文件创建相应的 Dag。使用这种结构,YAML 配置文件和气流 Dag 之间应该有 1:1 的关系。但是,没有什么可以阻止您拥有一个生成许多 Dag 的 YAML 配置文件。

配置文件看起来像什么?

考虑到易用性是我们的主要目标之一,这是一个关键问题。配置文件最终成为分析师和其他利益相关者交互的界面。在这种情况下,配置文件相当于 web 应用程序中的前端。所以我们需要确保它有一个好的“UX”。从这个意义上来说,简单是至关重要的,任何你可以隐藏的复杂都是非常受欢迎的。

下面是一个配置文件的样子:

这是我们能得到的最简单的配置文件吗?肯定不是!如果我们做一些假设,我们可以简化得更多。例如,这些配置文件的创建者是否需要决定数据将存储在数据仓库中的什么位置,比如模式名、表和数据库?当然,这完全取决于您的用例。

然而,让我们开门见山,解决这个问题。那本地图词典是什么?

这是我们处理列的重命名和类型转换的一种方法。当我们查看 DAG 工厂时,这一点会变得更加明显,但是它的本质是我们可以从 Google Sheets 中显式地定义我们想要加载的列,并将它们重命名为 SQL 兼容的(例如,将它们重命名为 snake_case)。例如,如果在我们的 Google Sheet 文件中有一个名为Product Name的列,那么在我们的数据仓库中有一个同名的列会很烦人,这可能会导致各种各样的问题。我们希望将该列的名称改为类似于product_name的名称。使用这个映射器,我们可以这样做:

让我们建一座工厂

所以这一切都从一个古老的时尚/dags/gsheets_factory.py剧本开始。该文件将从/dags/gsheets导入所有配置文件,为每个文件创建一个气流 DAG。

我们就是这样开始的。我们从拿到所有 YAML 的文件开始:

现在我们可以迭代它们并使用它们来创建 Dag:

我们在这里所做的就是迭代这些文件并用 PyYAML 打开它们,这将返回我们之前讨论过的 YAML 文件的字典版本。我们将配置字典存储在config中。最后,我们将配置字典传递给一个名为create_gsheets_dag的函数,并将该函数返回的 DAG 添加到气流全局范围。

正如我说过的,create_ghseets_dag返回一个气流 DAG,所以这实际上是魔术发生的地方。让我们来看看吧。

下面是整个函数:

但是让我们分解一下,了解一下每个部分在做什么。

第一部分简单地定义 DAG 的属性,例如 ID、计划间隔等。注意,所有这些都来自于config,它是我们之前讨论过的 YAML 配置文件的字典表示。

对于这个任务,我们将使用 Airflow 的 PythonOperator 。这个操作符将一个 Python 函数作为参数(python_callable)并执行它。所以我们首先需要定义这个函数。在我们的例子中,我们称之为_sync_data

这个函数做的第一件事是从 Google Sheets 获取数据

下一步是清理我们得到的数据:

我们正在调用一个我们写的clean_data的助手函数,但是这个函数的细节不是超级相关或者令人兴奋的;它只是获取映射器字典并重命名列。

之后,我们准备将数据插入到我们的数据仓库中。在我们的例子中,我们使用雪花,我们已经有了一个函数load_df,它获取一个熊猫数据帧并将其写入雪花。这是基于具有类似功能的雪花 Python 库。但是,这一部分可以适用于您正在处理的任何目的地:

如前所述,我们使用 PythonOperator 向 DAG 添加一个任务,它将执行我们刚刚定义的函数(_sync_data)。

结论

希望我成功地展示了我们如何通过引入抽象层次来极大地改进我们创建气流 Dag 的方式。不管你是从 Google Sheets、Hubspot 还是 Salesforce 加载数据;这些概念仍然适用。

使用 Pytorch 的抽象摘要

原文:https://towardsdatascience.com/abstractive-summarization-using-pytorch-f5063e67510?source=collection_archive---------5-----------------------

总结任何文本使用变压器在几个简单的步骤!

照片由 Aaron Burden 在 Unsplash

介绍

抽象摘要自然语言处理(NLP) 中的任务,目的是生成源文本的简明摘要。与抽象概括不同,抽象概括不只是简单地从源文本中复制重要的短语,还可能提出相关的新短语,这可以被视为释义。抽象概括在不同的领域产生了大量的应用,从书籍和文献,到科学和研发,到金融研究和法律文件分析。

迄今为止,最新最有效的抽象摘要方法是使用 转换器 模型,这些模型是在摘要数据集上专门调整的。在本文中,我们演示了如何通过几个简单的步骤,使用强大的模型轻松地总结文本。我们将要使用的模型已经过预训练,因此不需要额外的训练:)

所以事不宜迟,我们开始吧!

步骤 1:安装变压器库

我们将要使用的库是 Huggingface 的 Transformers。如果你不熟悉变形金刚,你可以继续阅读我以前的文章,看看它能做什么:

要安装变压器,您只需运行:

pip install transformers

注意:变压器要求事先安装 Pytorch。如果您还没有安装 Pytorch,请前往 Pytorch 官网 并按照其说明进行安装。

步骤 2:导入库

成功安装 transformers 后,现在可以开始将其导入到 Python 脚本中。我们还可以导入os来设置环境变量,供 GPU 在下一步中使用。请注意,这完全是可选的,但如果您有多个 GPU(如果您使用的是 Jupyter 笔记本),这是一个防止溢出到其他 GPU 的好做法。

from transformers import pipeline
import os

步骤 3:设置要使用的 GPU 和模型

如果您决定设置 GPU(例如 0),那么您可以如下所示进行设置:

os.environ["CUDA_VISIBLE_DEVICES"] = "0"

现在,我们可以选择要使用的总结模型了。Huggingface 提供了两个强大的总结模型可以使用: BART (bart-large-cnn)和 t5 (t5-small,t5-base,t5-large,t5–3b,t5–11b)。你可以在他们的官方论文里读到更多关于他们的内容(巴特论文、 t5 论文)。

要使用在 CNN/Daily Mail 新闻数据集上训练的 BART 模型,您可以通过 Huggingface 的内置管道模块直接使用默认参数:

summarizer = pipeline("summarization")

如果您想使用 t5 模型(例如 t5-base),它是在 c4 通用抓取网页语料库上训练的,那么您可以这样做:

summarizer = pipeline("summarization", model="t5-base", tokenizer="t5-base", framework="tf")

你可以参考 Huggingface 文档了解更多信息。

步骤 4:输入要总结的文本

现在,在我们准备好模型之后,我们可以开始输入我们想要总结的文本。想象一下,我们想总结以下关于新冠肺炎疫苗的文字,摘自medicine net的一篇文章:

一个月前,美国开始了全国 COVID 疫苗接种运动,这已经成为一个麻烦,这项努力终于获得了真正的动力。

美国疾病控制和预防中心(u . s . Centers for Disease Control and Prevention)周三报告称,在过去 24 小时内,* 100 万剂——更准确地说,超过 95.1 万剂——流入了美国人的手中。据哥伦比亚广播公司新闻报道,这是自推出以来一天内注射数量最多的一次,也是前一天的一大飞跃,前一天注射了不到 34 万剂。

在联邦政府周二批准各州为 65 岁以上的人接种疫苗,并表示将发放所有可用的疫苗剂量后,这一数字可能会迅速上升。与此同时, CBS 新闻报道,许多州已经开放了大规模疫苗接种点,以努力让更多的人接种疫苗。

我们定义我们的变量:

text = """One month after the United States began what has become a troubled rollout of a national COVID vaccination campaign, the effort is finally gathering real steam.
Close to a million doses -- over 951,000, to be more exact -- made their way into the arms of Americans in the past 24 hours, the U.S. Centers for Disease Control and Prevention reported Wednesday. That's the largest number of shots given in one day since the rollout began and a big jump from the previous day, when just under 340,000 doses were given, CBS News reported.
That number is likely to jump quickly after the federal government on Tuesday gave states the OK to vaccinate anyone over 65 and said it would release all the doses of vaccine it has available for distribution. Meanwhile, a number of states have now opened mass vaccination sites in an effort to get larger numbers of people inoculated, CBS News reported."""

第五步:总结

最后,我们可以开始总结输入的文本。这里,我们声明了我们希望摘要输出的 min_length 和 max_length,并关闭了采样以生成固定的摘要。我们可以通过运行以下命令来做到这一点:

summary_text = summarizer(text, max_length=100, min_length=5, do_sample=False)[0]['summary_text']
print(summary_text)

瞧啊。我们得到我们的摘要文本:

疾病预防控制中心称,在过去的 24 小时内,一天内注射了超过 951,000 剂疫苗。这是自推出以来一个月内拍摄数量最多的一次。周二,联邦政府批准各州为 65 岁以上的人接种疫苗。哥伦比亚广播公司新闻报道,许多州现在已经开放了大规模疫苗接种点,以努力让更多的人接种疫苗。

如摘要文本所示,我们可以看到模型知道 24 小时相当于一天,并且足够聪明地将美国疾病控制和预防中心缩写为 CDC。此外,该模型成功地链接了第一段和第二段的信息,表明这是自上个月开始展示以来给出的最大数量的镜头。我们可以看到,这个总结模型的性能相当不错。

结论

恭喜你,你现在知道如何对任何文本进行抽象概括了!将所有这些放在一起,下面是 Jupyter 笔记本形式的完整代码:

仅此而已!希望你喜欢这篇文章。如果你喜欢我的作品,请随意看看我的其他文章,敬请期待更多内容:)

参考

[1] 抽象的文本摘要,带代码的论文

[2] 自动摘要在企业中的 20 个应用,Fraise

【3】变形金刚 Github ,拥抱脸

[4] 变形金刚文档,拥抱脸

[5] Pytorch 官网,脸书艾研究

[6] Lewis,Mike,et al .“Bart:用于自然语言生成、翻译和理解的去噪序列间预训练” arXiv 预印本 arXiv:1910.13461 (2019)。

[7] Raffel,Colin,et al. “用统一的文本到文本转换器探索迁移学习的极限” arXiv 预印本 arXiv:1910.10683 (2019)。

[8] Tensorflow 数据集,谷歌

[9] 美国 COVID 疫苗首次推出日均接* 100 万支,MedicineNet

使用 scikit-optimize 加速超参数优化

原文:https://towardsdatascience.com/accelerate-your-hyperparameter-optimization-with-scikit-optimize-e72426e60bf1?source=collection_archive---------14-----------------------

训练另一个模型,为您的模型找到最佳超参数,避免繁琐的网格搜索

作者照片

尽管是创建模型的最后阶段之一,超参数优化(“HPO”)可以使好的模型(概括得很好)或难看的过度拟合(在训练数据中表现很好,但在验证集上表现差得多)之间产生很大差异。

对于流行的基于树的模型,如 Random Forest、XGBoost 或 CatBoost,尤其如此。通常,基本模型会严重过度拟合您的数据。另一方面,试图通过在 RandomForest 中设置一些超参数(如“max_depth”或“max_features ”)来手动增加偏差通常会导致严重的欠拟合。可能的超参数的搜索空间有如此多的维度和值,以至于您需要一种方便的方法来找到最佳点。

1.介绍

最简单的方法是网格搜索——基本上是一种强力方法,使用一组定义的参数和范围的所有可能组合来重新训练模型。这种方法的巨大缺点是,您将花费大部分时间探索效果不佳的参数组合,只有一小部分接*最佳点。

如果我们可以有另一个模型,它评估超参数的每次迭代的结果,并试图将它们向一个方向移动,从而提高基本模型的性能,会怎么样?幸运的是,scikit-optimize (SKOPT)正是这样做的。

在本文中,我将演示如何使用 scikit 启动 HPO,使用 RandomForest 和 XGBoost 优化,并使用 25 万德国租金的样本数据来预测租金价格。数据是 Kaggle 数据集的转换版本,它和用于文章的代码可以在 GitHub 上找到。

2.SKOPT 入门

SKOPT 通过创建另一个模型,使您的超参数优化变得更加容易,该模型试图通过改变其超参数来最小化您的初始模型损失。我们将首先为一个简单的 RandomForestRegressor 模型设置 HPO。

首先,你需要准备三样东西:

  • 搜索空间
search_space = [
         skopt.space.Integer(4, 12, name='max_depth'),
         skopt.space.Integer(50, 200, name='n_estimators'),
         skopt.space.Integer(5, 20, name='max_features'),
         skopt.space.Real(0.0, 1.0, name='min_impurity_decrease'),
         skopt.space.Categorical(categories = [True, False],name="bootstrap")
         ]

搜索空间定义了您想要在搜索中探索的超参数以及探索边界。大多数参数要么是整型,要么是实型(浮点型),要么是分类型。您可以使用 skopt.space 类为每个参数定义搜索空间。

  • 超参数优化参数
HPO_params = {
              'n_calls':100,
              'n_random_starts':20,
              'base_estimator':'ET',
              'acq_func':'EI',
             }

我知道这有点令人困惑——为什么我们需要另一组参数来寻找最佳超参数?HPO 参数定义了我们将用来寻找最佳参数的过程的一些基本属性。

  • n_calls 定义您想要进行多少次参数迭代
  • n_random_starts 定义在开始寻找最佳点之前,模型将进行随机迭代的次数,以获得搜索空间的更广泛探索。在这种情况下,我们让我们的模型在开始寻找最佳区域之前,随机搜索搜索空间 20 次迭代
  • base_estimator 选择用于优化初始模型超参数的模型,“ET”代表额外应力回归量
  • acq_func 定义了最小化的函数,“EI”意味着我们期望损失度量的减少作为改进
  • 设定我们的模型试图最小化的目标
[@skopt](http://twitter.com/skopt).utils.use_named_args(search_space)
def objective(**params):
    return (evaluator.evaluate_params(model, params))

我们的 HPO 模型使用目标函数来衡量每次迭代在提高基础模型性能方面的有效性。它将每次迭代中选择的超参数组合作为其输入,并输出我们的基本模型性能(隐藏在 evaluator 类中)。

我们使用@skopt.utils.used_named_args 包装器来转换我们的目标函数,以便它接受列表参数(默认由优化器传递),同时保留特性名称。

3.设置评估员类别

需要解释的最后一部分是 evaluator 类的 evaluate_params 函数。为了更好的可读性,我创建了一个类来将所有与模型训练和评估相关的代码从 HPO 中分离出来

evaluator = Params_Evaluate(X_train, X_val, y_train, y_val)
evaluator.select_model(model = RandomForestRegressor(n_jobs=4))

我们从训练和验证数据开始,选择我们想要评估的模型,然后我们搜索最佳参数集,以最小化我们的验证集上的 RMSE。我还在每次迭代后添加了一个 print 语句,这使得跟踪进度更加容易。

4。执行超参数优化

现在,我们已经做好了一切准备,可以用最后一行代码开始搜索最佳超参数了:

results = skopt.forest_minimize(objective,search_space,**HPO_params)

为了得到结果,我们使用 skopt.forest_minimize 函数,它使用了我们已经准备好的 3 个参数——目标、搜索空间和 HPO 参数。

对于在 HPO 参数中定义的迭代次数,搜索空间中选择一组参数,将它们提供给目标函数,该函数使用我们的 evaluator.evaluate_params 函数来检查这些参数在我们的模型中的表现。由于我在 evaluate_params 函数中添加了 print 语句,我们可以跟踪每次迭代之间的进度。

5.评估结果

得到结果可能需要一段时间,因为我们正在训练我们的模型 100 次,但一旦他们准备好了,就开始有趣了。我们可以使用 SKOPT 来可视化我们的超参数搜索。

我们可以从评估收敛结果开始,看看我们的模型在每次迭代中的最佳性能是如何提高的

skopt.plots.plot_convergence(results)

我们还可以看到我们的搜索空间的哪些区域被更精确地评估了——这意味着它们给出了更好的结果,并且可能接*最优

skopt.plots.plot_evaluations(results)

每个特征的搜索区域和频率

查看图表,我们可以看到搜索主要集中在 max_depth 和 max_features 最大值附*,这表明我们可以扩大搜索范围以获得更好的结果。

Plot_objective 函数允许我们评估与我们的目标相关的超参数之间的相关性

skopt.plots.plot_objective(results)

搜索区域和最佳结果

该图证实了对 max_depth 和 max_features 参数的高度依赖性,因为所有最佳结果(浅绿色)都集中在它们的顶部边界周围。

基于对上述结果的评估,我们可能应该修改我们的 search_space 以获得更好的结果,但是为了这个练习,我对当前的结果很满意。

我们可以通过调用 results.x 来获得最佳参数——不幸的是,它们是作为一个没有 param_name 的列表给出的,我创建了一个 helper 函数来将其转换成一个更易于阅读的字典。

best_params = to_named_params(results, search_space)
best_params{'max_depth': 12,
 'n_estimators': 137,
 'max_features': 20,
 'min_impurity_decrease': 0.03287287860139721,
 'bootstrap': False}

将具有最佳参数的模型与初始模型(具有 n_estimators=100,max_depth=5,max_features=20 的 RandomForestRegressor)进行比较,我们可以看到 R2 得分显著增加:

  • 基本型号为 0.80
  • 0.87,适用于带有调谐超参数的模型

6.为 XGBoost 重组工具

为新型号重新装备需要 3 个简单的步骤:

  • 在评估器类中选择新模型
evaluator.select_model(model =  XGBRegressor())
  • 重新定义搜索空间
search_space_xgb= [
         skopt.space.Integer(4, 5, name='max_depth'),
         skopt.space.Real(0.0, 1.0, name='eta'),
         skopt.space.Real(0.0, 1.0, name='subsample'),
         skopt.space.Categorical(categories = ["gbtree", "dart"],name="booster")
         ]
  • 重组目标函数,使包装器使用更新的 search_space 名称
[@skopt](http://twitter.com/skopt).utils.use_named_args(search_space_xgb)
def objective(**params):
    return  evaluator.evaluate_params(params)

现在,我们准备在同一个数据集上对 XGBoost 模型进行超参数优化

 results=skopt.forest_minimize(objective, search_space_xgb,**HPO_params)

7.摘要

SKOPT 是我最喜欢的超参数优化工具,它结合了易用性和可视化来分析结果。

该库也是非常通用的,因为我们可以自由地设置我们的目标函数,我们可以使用它来评估任何模型和任何超参数集。

我希望我的技巧可以帮助你尝试 SKOPT,这样你就不需要在这些乏味的网格搜索上浪费时间,而是利用另一个模型来找到适合你的超参数最佳点。

基于多目标回归神经网络和 Shapley 值的加速材料设计

原文:https://towardsdatascience.com/accelerated-materials-design-using-multi-target-regression-neural-network-and-shapley-values-e3172027bf57?source=collection_archive---------30-----------------------

多目标回归分析在材料发现中的意义

照片由 Robert Bye 在 Unsplash 上拍摄

简介

本文是我上一篇文章 Shapley 值辅助材料设计配方 的延伸,这篇文章解释了 Shapley 值在提取特征重要性方面的用法,以及它们对单个目标变量的影响,从而为材料设计绘制蓝图。然而,为了创新和制造新材料,我们需要考虑决定性能的几种性质的协同效应。

丹尼尔·罗梅罗在 Unsplash 上的照片

例如,用于智能手机和*板电脑的康宁大猩猩玻璃,拥有硬度、亮度和耐刮擦性等属性的适当*衡。有无数这样的例子表明材料具有特定应用领域的综合性能。因此,有必要建立具有多个紧密结合的目标的预测模型。

案例研究

让我用一个人工神经网络(ANN)来说明上述观点,该网络被建模来预测两个相互依赖的目标的重要性程度。在这里,我将使用前两篇文章中使用的相同数据集,包括 204 种热电材料、它们的元素组成以及它们的两个重要属性——热导率(kappa)和与电导率相关的功率因数(PF)。kappa 和 PF 的正确组合决定了性能。这些材料导热性差,但同时又是良好的电导体,根据物理定律,这非常具有挑战性。它们可用于发电和制冷。这些热电材料的一个值得注意的应用是它用作火星漫游车的电源,、【好奇号】、【毅力号】

问题是我们如何找到具有最佳属性集的最佳产品。答案在于建立一个稳健的回归模型,该模型可以连接所有必要的参数,并确定最重要的特征组合。这里我们讨论建立这样一个模型的过程。

建立双输出的人工神经网络回归模型

使用 Matminer 和 Pymatgen 等 python 库对材料数据进行预处理后,在我的帖子“使用 Matminer 和 Pymatgen 发掘材料数据的潜力”中有所描述,细化后的数据集如下所示:

为深度学习清理数据集

这个干净的数据集包含 49 个预测值或 X 和 2 个目标值或 y。预测值都是材料成分的单个元素。而‘kappa’和‘PF’是两个目标(y)。

识别 X 和 y

X = ds_RT.iloc[:, 1: 50]
y = ds_RT.iloc[:,50:]

现在让我们将数据分成训练集和测试集。

拆分数据

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

缩放数据

一般来说,描述符或预测符(X)因其值的范围较宽而被缩放。然而,在这种情况下,所有的预测因子都是元素周期表的元素,它们的数据代表从 0 到 1 的元素分数。

相反,由于这些目标变量的范围分布很广,因此需要应用 Sklearn 的 MinMaxScaler 函数对 y 进行缩放。

from sklearn.preprocessing import MinMaxScaler
sc = MinMaxScaler()
y_train = sc.fit_transform(y_train)
y_test = sc.transform(y_test)

是时候构建 ANN 层了。

序贯层和优化安模型

我安排了三个密集或完全连接的层,第一层具有 49 的输入维度,表示预测器的数量,最后一层具有用于 2 个目标的 2 个输出神经元。下面的代码片段显示了图层及其属性。

from keras.models import Sequential
from keras.layers import Dense
model = Sequential()model.add(Dense(25, input_dim=49, kernel_initializer='he_uniform', activation='relu'))model.add(Dense(25, kernel_initializer='he_uniform', activation='relu'))model.add(Dense(2))

基于随机梯度下降的自适应矩估计算法 ADAM 用于模型优化,损失函数用*均绝对误差估计。在编译模型之后,拟合训练数据集,并相应地计算损失函数。

model.compile(loss ='mae', optimizer = 'adam')
model.summary()
history = model.fit(X_train, y_train, verbose = 'auto',epochs = 400)from sklearn.metrics import mean_absolute_error
mae = mean_absolute_error
mae(y_test, y_pred)

分析预测因素对目标变量的影响程度

让我们借助 Shapley 值深入研究预测因素对这些目标变量的影响。这种影响分析对于每个数据集理解和解释任何机器学习模型都是至关重要的,否则这些模型是无法理解的。

随着几个 XAI ( E 可解释的 A 人工 I 智能)算法的出现,我们可以更精确地测量超参数的调整,从而产生更有意义的预测。

现在让我们看看 Shapley 值在这个热电数据集示例中的作用。让这些数据接受深度学习算法并计算预测器对目标的贡献(以 Shapley 值的形式)的整体思想是提取它们之间的有用相关性。当参数之间的相互关系变得越来越复杂时,这些相关性非常重要。

在安装了 SHAP(【SHapley Additive exPlanations】)包之后,KernelExplainer 函数在这种情况下用于计算特征/预测因子的贡献。我正在分享同样的代码片段。

pip install shap
import shapexplainer = shap.KernelExplainer(model = model, data = X_train,link = 'identity' )
shap_values = explainer.shap_values(X_train)

根据训练数据 绘制并解释 Shap 值

class_names = y.columns
shap.summary_plot(shap_values, feature_names = X_train.columns)

kappa 和 PF 这两个目标变量分别用红色和蓝色进行颜色编码。形状图在 X 轴上具有特征,在 Y 轴上具有绝对形状值或贡献。从这个柱状图中,我们可以立即了解每个特征对单个目标变量的贡献程度。

显示两个目标贡献的条形图

让我通过考虑一些元素/特征来解释,例如 Zn(锌)和 Sb(锑),以及它们对 kappa 和 PF 的贡献。我们可以很快估算出,对于 Zn 来说,kappa(红色条)的贡献要比 PF(蓝色条)大得多。另一方面,Sb 对 kappa 和 PF 的影响几乎相等。现在,由于该汇总图仅显示绝对 Shap 值,它并未捕捉目标上特征的影响方向(正相关或负相关)。

解释特征与特定目标之间的相关性

为了理清 kappa 和 PF 与特征之间的关系,我绘制了汇总图,每次选取一个目标。

Shapley 汇总图显示了元素对 kappa 和 PF 的影响

这些图揭示了相关性的符号:正、负或零红色表示高影响,而“蓝色”表示低影响。以锌和锑为例,可推断出以下内容:

  • 锌与 kappa 的正相关大于与 PF 的正相关。

  • Sb 与 PF 呈高度正相关,与 kappa 呈高度负相关。

在本研究中,材料的类别要求特征分别与 PF 和 kappa 的正相关和负相关共存。例如,Sb 就展示了这样一个理想的组合。预先知道特征对目标的影响方向,确实有助于为所需应用的任何类型的材料提出设计想法。

你可以在这里 得到整码

参考数据可用性:https://www.nature.com/articles/s41524-021-00564-y.

关键要点

-建立能够同时处理多个目标的机器学习和深度学习模型,是释放有价值的信息以实现创新和发展的一步。它们有助于理解目标和预测者之间的相互依赖关系。

-一起考虑所有目标变量的好处是节省时间与一次拟合一个目标相比,计算成本更低

-使用 XAIs 的多目标拟合和分析为调整影响目标变量的预测因子的超参数提供了更好的清晰度。

  • 拟合多个响应回归和分类算法中都是可能的。当回答是数字时,进行多目标回归,而在分类目标变量的情况下,进行多标签或多类分类。

最后,应该鼓励训练机器为特定目的回收和重用具有多个目标的数据,因为它揭示了最终输出之间相互关系的本质。这增强了任何机器学习模型的预测和可靠性,从而在现实世界的应用中实现更富有成效的部署。

快乐阅读!

针对通用和科学计算开销大的任务的加速 Python

原文:https://towardsdatascience.com/accelerated-python-for-general-purpose-and-scientific-computationally-expensive-tasks-55ac46f7f52b?source=collection_archive---------19-----------------------

理解大数据

借助强大的 Numba CPU/CUDA 目标编译,快速学习如何以最小的努力提高代码的性能。

由 NASA 在 Unsplash 上拍摄的照片

大家都喜欢 Python 。Python 是一种解释型高级通用编程语言。它是动态类型的,并提供垃圾收集。Python 支持多种范式,包括过程化、面向对象和函数式编程。

此外, Guido Van Rossum 创造的语言带有简单易学的语法,并通过设计鼓励代码可读性,从而允许程序员编写干净的代码,即使对于大型生产级项目也是如此。

所有这些漂亮的特性,一方面使 Python 如此吸引人,另一方面,不可避免地增加了执行速度的负担,这并不是它的强项。在本文中,我们将讨论如何使用 Numba 和 CUDA,不费吹灰之力或以最小的努力提高代码的性能。****

为此,我们准备了两种算法,我们将比较和测试使用和不使用 Numba 的不同实现。

我们不是故意考虑Cython的:虽然它提供了——至少在理论上——与静态编译语言相当的性能,但 cy thon 实际上是 Python 的扩展,对它的翻译需要相当大的努力来重写代码,遵循类似于 c 的静态类型语法

注意:下面显示的所有代码在这里都有:https://github . com/Andrea-ci/misc-stuff/tree/master/numba-test。

列表操作

我们要测试的第一个算法在列表上工作,列表是 Python 最常见的内置对象之一。一个函数接收一个字符列表,这些字符是从前五个字符(即 A、B、C、D 和 E)中随机选择的,并为每个元素分配一个与字符在字母表中的位置相对应的整数。新的整数列表是函数的输出。

def translate_list_01(char_list):
    """Working on a list.
    Pure Python implementation.""" num_list = []
    for word in char_list: if word == 'A':
            num = 1
        elif word == 'B':
            num = 2
        elif word == 'C':
            num = 3
        elif word == 'D':
            num = 4
        else:
            num = 5 num_list.append(num) return num_list

让我们看看这个简单函数对于不同大小的列表的执行时间,用 2 的幂来表示。

简单实现的执行时间

输入数字

Numba 标志

我们现在引入 Numba,这是一个在 Python 代码上实现实时编译的库。来自 Numba 的官方主页:

Numba 是一个针对 Python 的实时编译器,最适合使用 NumPy 数组和函数以及循环的代码。使用 Numba 最常见的方式是通过它的 decoratorss 集合,这些 decorator 可以应用到您的函数中来指示 Numba 编译它们。当一个 Numba 修饰的函数被调用时,它被编译成“实时”执行的机器代码,你的全部或部分代码随后可以以本机代码的速度运行!

Numba 的目标是针对 CPU 或 CUDA 内核进行编译,以实现大规模并行化(稍后将详细介绍)。

因此,第二个实现在我们的函数上添加了 JIT 编译。

[@jit](http://twitter.com/jit)(nopython=True)
def translate_list_02(char_list):
    """Working on a list.
    CPU-acceleration with Numba.""" num_list = []
    for word in char_list: if word == 'A':
            num = 1
        elif word == 'B':
            num = 2
        elif word == 'C':
            num = 3
        elif word == 'D':
            num = 4
        else:
            num = 5 num_list.append(num) return num_list

实际上,为了从 JIT 编译中获益,我们需要的唯一改变是添加 Numba jit装饰器。nopython=True选项确保修饰函数将完全在没有 Python 解释器参与的情况下运行。这是从 Numba 获得最佳性能的推荐方法。

无需任何重新编码,编译后的代码会立即快 4 到 5 倍。

执行时间的比较

Numba 并不支持所有的 Python 构造,所以在某些情况下,可能需要重新组织代码和/或在object mode中编译,这是当nopython=True未设置时jit装饰器的一种备用模式。使用这种模式,Numba 将识别它可以编译的部分,并在解释器模式下运行其余的代码,这对性能没有好处。

你可以在这里找到 Numba 编译器支持的 python 特性。

科学计算

Python 还被广泛用于科学和数字任务,这要归功于一个强大的社区积极开发和支持的大量库。毕竟 Python 是机器学习的语言,仅举一例。

毫无疑问,Python 科学生态系统的基础是 Numpy 。

Numpy 标志

Numpy 附带了一个丰富的工具集,其中的函数是为高效的矢量化而编译的,以便为需要在数组和矩阵上快速迭代的代码提供优化。其他高级语言也采用相同的方法,一个著名的例子是 Matlab。

Numba 方面,声称是 Numpy-friend :

Numba 的一个目标是与 NumPy 无缝集成。

然而,使用 Numba,我们在已经编译好的工具上增加了一个编译层。乍一看,这似乎有点令人困惑

为了更好地关注这个方面,我们要测试的第二个算法是在 Numpy 2D 数组上进行的一系列元素操作:加法、减法、对数、指数、最小值、最大值、乘法和除法。

该算法的第一个实现仅使用 Numpy。

def computing_01(A, B, a, b):
    """Numpy operations with no acceleration.""" # Scalar multiplication and addition of matrices.
    Y = a * A + b * B
    # Scalar multiplication and subtraction of matrices.
    Y -= a * A - b * B
    # Element-wise logarithm.
    Y += np.log(A) + np.log(B)
    # Element-wise exponential.
    Y -= np.exp(A) - np.exp(B)
    # Element-wise minimum and maximum.
    Y += (np.maximum(A, B) - np.minimum(A, B)) / 2
    # Element-wise multiplication and division.
    Y -= np.multiply(A, B) - np.divide(A, B) return Y

第二个实现在上面添加了 Numba 编译。

[@jit](http://twitter.com/jit)(nopython=True)
def computing_02(A, B, a, b):
    """Numpy operations with Numba acceleration.""" # Scalar multiplication and addition of matrices.
    Y = a * A + b * B
    # Scalar multiplication and subtraction of matrices.
    Y -= a * A - b * B
    # Element-wise logarithm.
    Y += np.log(A) + np.log(B)
    # Element-wise exponential.
    Y -= np.exp(A) - np.exp(B)
    # Element-wise minimum and maximum.
    Y += (np.maximum(A, B) - np.minimum(A, B)) / 2
    # Element-wise multiplication and division.
    Y -= np.multiply(A, B) - np.divide(A, B) return Y

最后,第三实现避免了 Numpy 函数的任何使用,并且矩阵上的迭代是显式的。换句话说,我们完全依赖 Numba** 来消耗循环的**

[@jit](http://twitter.com/jit)(nopython=True)
def computing_03(A, B, a, b):
    """Numba acceleration, without Numpy.""" # Matrix size.
    N = A.shape[0] # Init temporary matrices.
    Y = np.empty((N,N)) for ii in range(N):
        for jj in range(N): # Scalar multiplication and addition of matrices.
            Y[ii, jj] = a * A[ii, jj] + b * B[ii, jj]
            # Scalar multiplication and subtraction of matrices.
            Y[ii, jj] -= a * A[ii, jj] - b * B[ii, jj]
            # Element-wise logarithm.
            Y[ii, jj] += math.log(A[ii, jj]) + math.log(B[ii, jj])
            # Element-wise exponential.
            Y[ii, jj] += math.exp(A[ii, jj]) - math.exp(B[ii, jj])
            # Element-wise minimum and maximum.
            Y[ii, jj] += (max(A[ii, jj], B[ii, jj]) - min(A[ii, jj], B[ii, jj])) / 2
            # Element-wise multiplication and division.
            Y[ii, jj] -= A[ii, jj] * B[ii, jj] - A[ii, jj] / B[ii, jj] return Y

我们最终可以针对不同的 N 值测量这些实现的性能。 NA、BY 方阵的顺序。

执行时间的比较

我们在这里注意到两件主要的事情。第一个是用 Numba 编译,我们得到了额外的优化,只针对 Numpy。所以尽管引入了开销,Numba 编译仍然是有益的

第二,令人惊讶的是,或者也许不那么令人惊讶的是,当我们让 Numba 做所有的迭代工作时,它的表现比 Numpy 好得多。

在这种情况下,Numba 的编译似乎比 Numpy 的矢量化更有效。

输入 CUDA

哈梅内伊索尔蒂斯,CC BY-SA 4.0,通过维基共享

最后我们打出最后一张牌: CUDA 。CUDA(计算统一设备架构)是由 Nvidia 创建的并行计算*台。它提供了一个应用程序编程接口,允许软件使用图形处理单元(GPU)进行通用处理。

Numba 也支持 CUDA 编程。来自 Numba 文档:

Numba 通过按照 CUDA 执行模型将 Python 代码的有限子集编译成 CUDA 内核和设备功能来支持 CUDA 编程。用 Numba 编写的内核似乎可以直接访问 NumPy 数组。NumPy 数组在 CPU 和 GPU 之间自动传输。

由于 Numba-CUDA 支持的指令集进一步受到限制,所以在这里翻译代码需要稍微多做一些工作。

为了生成多维数组,CUDA 的一般方法是让每个 GPU 线程处理数组的单个元素,从而实现真正的并行计算。Numba 前端管理主机(CPU)和设备(GPU)之间的同步

这是我们算法的 CUDA 实现。我们可以注意到在这个例子中使用了不同的装饰器。此外,为 CUDA 编译的函数不返回任何对象,因此处理结果作为输入参数包含在内。最后,在这个实现中没有使用 Numpy 方法。

[@cuda](http://twitter.com/cuda).jit
def computing_04(Y, A, B, a, b, N, size):
    """Operations accelerated with Cuda.""" # Thread id in a 1D block
    tx = cuda.threadIdx.x
    # Block id in a 1D grid
    ty = cuda.blockIdx.x
    # Block width, i.e. number of threads per block
    bw = cuda.blockDim.x
    # Compute flattened index inside the array
    pos = tx + ty * bw if pos < size: ii = int(math.floor( pos / N ))
        jj = int(math.floor( (pos - ii * N) / N )) # Scalar multiplication and addition of matrices.
        Y[ii, jj] = a * A[ii, jj] + b * B[ii, jj]
        # Scalar multiplication and subtraction of matrices.
        Y[ii, jj] -= a * A[ii, jj] - b * B[ii, jj]
        # Element-wise logarithm.
        Y[ii, jj] += math.log(A[ii, jj]) + math.log(B[ii, jj])
        # Element-wise exponential.
        Y[ii, jj] += math.exp(A[ii, jj]) - math.exp(B[ii, jj])
        # Element-wise minimum and maximum.
        Y[ii, jj] += (max(A[ii, jj], B[ii, jj]) - min(A[ii, jj], B[ii, jj])) / 2
        # Element-wise multiplication and division.
        Y[ii, jj] -= A[ii, jj] * B[ii, jj] - A[ii, jj] / B[ii, jj]

CPU 和 CUDA 实现之间的区别是不言自明的!

CUDA 增加了执行时间的比较

结论

Numba 是一个很棒的工具,它可以显著提升 Python 代码的性能,只需很少或者不需要重新编码。

在矢量化数值运算的情况下,我们也可以从 CUDA 并行化中受益。在这种情况下,重新编码的成本肯定会更高,但是的性能提升是显著的

用于测试代码的机器是一台 Windows 机器,配备了 Intel i7–10700k CPU、32 GB RAM 和 Nvidia GeForce 3060Ti。

GPU 支持加速信号处理

原文:https://towardsdatascience.com/accelerated-signal-processing-with-gpu-support-767b79af7f41?source=collection_archive---------17-----------------------

借助 GPU 支持的生态系统,加速您的信号处理任务。

在 Unsplash 上由娜娜杜瓦拍摄的照片

简介

信号处理是应用于各种领域的一系列重要技术的一部分,无论是科学研究还是商业应用,从大型天体物理现象的分析到语音识别应用的开发。它涉及不同的任务,例如滤波或把原始数据变换到频域。

目前有各种各样的代码框架可用于通用编程语言,它们可用于实现这些任务,但仍然很难将像 C++ 这样的编程语言的代码执行速度与像 Python 这样的高级语言的开发难度结合起来。对于科学计算,后者被大量使用,拥有完整的 API 源代码和库,如 NumpySciPy 。尽管比其他低级解决方案慢,特别是在密集数据计算的情况下,这些环境正由 GPU 等加速硬件支持。更具体地说,通过来自 CUDA 函数的后端支持,从而优化科学任务的时间消耗。

在本文中,我们将介绍一些 GPU 支持的框架的功能,这些框架可用于两种特定的信号处理技术(短时傅立叶变换和功率谱密度),并与基于 CPU 推理的库进行比较。

五金器具

  • CPU: AMD 锐龙 7 2700X
  • GPU:英伟达 GTX 1060 6GB。

短时傅立叶变换算法

短时傅立叶变换( STFT )是一种高度用于分析非*稳信号(时变频率)的数学技术。其功能的基础是在某个信号内等长的不同段中计算连续的傅立叶变换( FFT )。时频 STFTX【f,n】,可以用等式 1 来简要描述。

等式 1 — STFT。

其中 w[m] 为窗函数, v 为频率指数, n 为时间段, H 为不同窗中心之间的距离(跳长 ), x[m+nH] 表示带有 nH 段重叠数据的输入信号, N 为每段的长度。关于如何在计算上应用 STFT 的更详细描述可以在本文中看到。

为这项工作选择的窗口函数是余弦窗口的一个特例,定义在等式。2,were α 是一个非负有理数。

等式 2 —广义余弦窗函数。

对于 α = 25/46(或大约 0.54),我们有已知的汉明窗口函数,定义在等式中。3.

等式 3——汉明窗函数。

图 1 示出了所描述的过程的一般图示,其中连续的 FFT 在具有特定窗函数 w[m]的原始信号 x[m] 中被计算。

图 1—STFT 插图(“作者图片”)。

有了这个关于 STFT、的数学背景的简短修正,我们现在可以前进到性能分析。

scipy vs tensor flow vs RAPIDS Cu signal

为了计算 STFT ,我们可以使用两个有 GPU 支持的API(tensor flowRAPIDS Cu signal)内置函数,并比较它们与 SciPy 实现的性能。

用于此项工作的库

出于这种比较的目的,我们将使用来自一个 wav 文件的一个片段,采样率为 48 kHz ,这是一个个人尝试,涵盖了 Heitor Villa-洛沃斯古典吉他作品“前奏№1 ”。你可以通过这个链接来听一听。

导入 wavfile

图 2 —信号数据。

选择的 STFT 段长度为 8192,窗口半重叠。为了测量每个内置方法的执行时间,使用了 timeit 模块。也可以使用其他运行时方法,如 时间cProfile

计算 STFT 运行时间

利用获得的每个 API 的运行时值,我们现在可以绘制一个柱状图来评估结果。

绘制 STFT 运行时

图 3 — STFT 运行时结果。

利用张量流cuSignal ,SciPy 实现可以分别被加速几乎 10 倍和 75 倍。 cuSignal 的最佳性能可以部分解释为对 CUDA 阵列计算加速库的额外后端支持。

为了表示的目的,我们也可以用时间对频率表示法来表示 STFT 计算的结果,或者换句话说,用频谱图来表示(图 4)。

图 4 —信号频谱图(“作者提供的图像”)。

为了提高时间分辨率δt,可以减小 FFT 的窗口大小,但是要记住这样做会有降低频率分辨率δf的缺点,如下面的不确定关系所述。

时间与频率的不确定关系。

图 5 —具有更高δt 的信号频谱图(“图片由作者提供”)。

现在让我们转到本研究中涉及的第二种信号处理技术。

使用韦尔奇方法的功率谱密度

功率谱密度( PSD )将功率分布描述为特定信号的不同频率分量的函数,考虑傅立叶变换的实部。估计功率谱有许多选择。具体来说,这项工作将集中在 韦尔奇的方法 上,它可以分为以下几个步骤:

  • 将信号分成 K 段;
  • 对于每个片段 K 计算离散傅立叶变换(DFT);
  • 使用计算出的 DFT 获得周期图值,定义见等式。4,其中 M 为每段长度k

等式 4——周期图。

  • *均 K 段的所有周期图值,给出所需的 PSD(等式。5).

等式 5 —韦尔奇方法功率谱密度。

Scipy vs RAPIDS cuSignal

在这种情况下, PSD 的计算仅考虑到 SciPycuSignal API ,使用先前定义的相同 FFT 参数。

用韦尔奇方法计算功率谱密度

同样,我们使用柱状图分析两种方法的性能。

绘制 PSD 运行时

图 7 — PSD 运行时结果。

结果再次表明 cuSignal 具有优化处理任务的潜力。使用 cuSignalPSD 的运行时计算可以增加 50 倍。所得到的光谱可以在图 8 中看到。

图 8 — PSD 图(“作者提供的图像”)。

总结与未来工作

正如预期的那样,结果证明了这些具有 GPU 支持的API在信号处理方面的潜力,无论是采集后分析还是实时应用,尽管对于高采集速率信号,后者仍然优先采用低级代码处理。根据每个用户拥有的硬件和软件,显示的结果可能略有不同,但这足以提供一个大致的视角。

作为未来的工作,将这些高级实现与 CC++ 函数进行比较会很有趣,以便提取关于所呈现的API的容量的所有信息。此外,作为对读者的一个建议,可以用更高的采样频率信号(> 100 MHz )和不同的 FFT 参数替换所使用的 wav 文件,执行新的基准测试。

关于这项工作,请随时提出建议。

参考文献

【1】Hohyub Jeon,Yongchul Jung,Seongjoo Lee 和郑允浩,“ 面积有效的短时傅里叶变换处理器,用于非*稳信号的时频分析 ”,应用科学,2020;

【2】m . Solomon, 采用韦尔奇方法的 PSD 计算 美国能源部,1991。

英特尔 Mac GPUs 上的加速张量流模型训练

原文:https://towardsdatascience.com/accelerated-tensorflow-model-training-on-intel-mac-gpus-aa6ee691f894?source=collection_archive---------4-----------------------

如何通过 TensorFlow PluggableDevice 在 MacBook Pro dGPU 上训练 TensorFlow 模型的迷你指南

照片由尼古拉·塔拉先科在 Unsplash 拍摄

TensorFlow 在 2021 年年中推出了 PluggableDevice ,这使得硬件制造商能够将其加速器(例如 GPU、TPU、npu)无缝集成到 TensorFlow 生态系统中。这使得用户可以在非 CUDA 设备上享受加速培训,只需对代码进行最少的修改。更重要的是,硬件制造商不再需要派生和实现自己版本的 TensorFlow(例如 AMD ROCm port ),可以纯粹专注于 TensorFlow 和设备级操作之间的通信层。随着最* macOS Monterey 的公开发布,苹果为 PluggableDevice 架构添加了金属支持,因此,现在可以在 MacBook Pros 和 iMacs 上轻松地使用专用 GPU (dGPU)训练 TensorFlow 模型。

在本迷你指南中,我将介绍如何安装tensorflow-metal以在英特尔 MacBook Pro 和 iMac 上启用 dGPU 培训。此外,我在配备 AMD 镭龙 Pro 560X 的 MacBook Pro 上训练了一个简单的 CNN 图像分类器,以展示加速后的性能。

创建开发环境

我个人更喜欢 miniconda ,但是其他环境管理器比如 anaconda 和 virtualenv 也应该以类似的方式工作。

我们首先用 Python 3.8 创建一个名为tf-metal的新conda环境

conda create -n tf-metal python=3.8

然后我们激活环境

conda activate tf-metal

安装金属启动张量流

我们必须安装以下 pip 包:[tensorflow-macos](https://pypi.org/project/tensorflow-macos/)[tensorflow-metal](https://pypi.org/project/tensorflow-metal)。通常,你可以简单地做pip install tensorflow-macos tensorflow-metal,然后就万事大吉了。但是,您可能会收到以下错误,因为这两个包都是针对 macOS 11 SDK 之后的版本构建的:

ERROR: Could not find a version that satisfies the requirement tensorflow-macos (from versions: none)
ERROR: No matching distribution found for tensorflow-macos

为了绕过版本兼容性问题,我们需要使用下面的标志SYSTEM_VERSION_COMPAT=0pip install:

SYSTEM_VERSION_COMPAT=0 pip install tensorflow-macos tensorflow-metal

现在应该已经安装了这两个软件包:

(tf-metal) ➜  ~ pip list
Package                 Version
----------------------- ---------
absl-py                 0.15.0
astunparse              1.6.3
cachetools              4.2.4
certifi                 2021.10.8
charset-normalizer      2.0.7
clang                   5.0
flatbuffers             1.12
gast                    0.4.0
google-auth             2.3.1
google-auth-oauthlib    0.4.6
google-pasta            0.2.0
grpcio                  1.41.1
h5py                    3.1.0
idna                    3.3
keras                   2.6.0
Keras-Preprocessing     1.1.2
Markdown                3.3.4
numpy                   1.19.5
oauthlib                3.1.1
opt-einsum              3.3.0
pip                     21.2.4
protobuf                3.19.0
pyasn1                  0.4.8
pyasn1-modules          0.2.8
requests                2.26.0
requests-oauthlib       1.3.0
rsa                     4.7.2
setuptools              58.0.4
six                     1.15.0
tensorboard             2.7.0
tensorboard-data-server 0.6.1
tensorboard-plugin-wit  1.8.0
tensorflow-estimator    2.6.0
tensorflow-macos        2.6.0
tensorflow-metal        0.2.0
termcolor               1.1.0
typing-extensions       3.7.4.3
urllib3                 1.26.7
Werkzeug                2.0.2
wheel                   0.37.0
wrapt                   1.12.1

在 TensorFlow 中检查物理设备

我们可以使用tf.config.list_physical_devices()来检查所有可用的物理设备:

>>> import tensorflow as tf
>>>
>>> tf.config.list_physical_devices()
[PhysicalDevice(name='/physical_device:CPU:0', device_type='CPU'), PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]

我们可以看到,在我配备 AMD 镭龙 Pro 560X dGPU 的 2018 MacBook Pro 的情况下,有两个物理设备:一个CPU和一个GPU

类似于在 TensorFlow 中使用本地设备或 CUDA 设备,我们可以使用with tf.device()语法声明一个变量或定义在特定设备上运行的操作:

>>> with tf.device('/GPU'):
...     a = tf.random.normal(shape=(2,), dtype=tf.float32)
...     b = tf.nn.relu(a)
...
2021-10-26 12:51:24.844280: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  SSE4.2 AVX AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
Metal device set to: AMD Radeon Pro 560XsystemMemory: 16.00 GB
maxCacheSize: 2.00 GB2021-10-26 12:51:24.845013: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:305] Could not identify NUMA node of platform GPU ID 0, defaulting to 0\. Your kernel may not have been built with NUMA support.
2021-10-26 12:51:24.845519: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:271] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 0 MB memory) -> physical PluggableDevice (device: 0, name: METAL, pci bus id: <undefined>)
>>>
>>> a
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([-1.6457689, -0.2130392], dtype=float32)>
>>> b
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([0., 0.], dtype=float32)>

您可以在初始化期间看到金属装置AMD Radeon Pro 560X被设置的打印输出。

训练 CNN 分类器

为了演示使用tensorflow-metal对普通tensorflow(即在CPU上)的训练性能,我编写了一个脚本,使用RMSPropMNIST上训练一个简单的 CNN 模型 50 个时期。请注意,我使用 TensorFlow 数据集来下载MNIST,所以如果您想运行完全相同的代码,请使用pip install tensorflow_datasets

以下是用tensorflow (CPU)和tensorflow-metal (GPU)训练的 CNN 模型的训练结果和活动监视器截图。

活动监视器截图和 CNN 在 CPU 上的训练表现[图片由作者提供]

活动监视器截图和 CNN 在 GPU 上的训练表现[图片由作者提供]

我们可以看到在tensorflowtensorflow-metal上的训练达到了相似的训练和验证精度。此外,CNN 模型在 CPU 上*均耗时 40 毫秒/步,而在 GPU 上*均耗时 19 毫秒/步,加速约 52%。从活动监视器截图中,我们也可以看到 AMD 镭龙 Pro 560X dGPU 确实正在被 python3.8 使用,GPU 使用率约为 56%。

由于 TensorFlow PluggableDevice 架构,硬件开发人员现在可以支持非 CUDA 加速器与 TensorFlow 一起工作,而无需分叉或移植现有的 TensorFlow 代码库。根据我们有限的实验,tensorflow-metal似乎在采用 dGPU 的英特尔 MAC 电脑上运行得相对良好且无缝。尽管如此,Metal 插件仍处于早期开发阶段,还有一些已知的错误(如 Adam optimizer 目前不工作)阻止 ML 开发者切换到tensorflow-metal工作流。希望随着越来越多的硬件制造商开始将他们的产品与 PluggableDevice API 集成,我们将在 AI 硬件加速器中看到更好的支持和更多的选择。

关于 TensorFlow 可插拔设备和 Apple Metal 的其他参考资料

  • tensor flow-pluggable Device:tensor flow 的设备插件
  • TensorFlow - GPU 设备插件
  • 苹果- Tensorflow 插件- Metal -苹果开发者

加速计算机视觉:我们如何将 EfficientNet 扩展到 IPU-波德超级计算系统

原文:https://towardsdatascience.com/accelerating-computer-vision-how-we-scaled-efficientnet-to-ipu-pod-supercomputing-systems-e4e6b506b671?source=collection_archive---------27-----------------------

更快的大规模图像处理

图片作者。

Graphcore 研究展示了我们如何在 Graphcore 最新的超大规模 IPU-POD128 和 IPU-POD256 系统上加速训练创新的计算机视觉模型 EfficientNet-B4,在不到两个小时内达到收敛。

为什么选择 EfficientNet?

EfficientNet 系列模型 [1]展示了计算机视觉的最新发展水*,以相对较少的参数和失败实现了高任务性能。然而,它在实践中的采用受到以下事实的限制:传统的处理器架构不能利用使 EfficientNet 如此高效的许多属性。

例如,与标准卷积运算相比,EfficientNets 中的深度方向或组卷积具有很高的表达能力和计算效率,但算术强度较低(计算与数据移动的比率)。由于内存和处理器内核之间的大量数据传输,这些类型的操作在 GPU 上的性能很差。由于 IPU 以内存为中心的架构,整个模型及其激活都可以保留在芯片上,从而缓解了这种昂贵的数据移动。

此外,IPU 的 MIMD(多指令、多数据)范式支持模型和训练过程的多维度上的细粒度并行性。这有助于实现高吞吐量,同时使用小卷积并并行处理非常少的数据样本。相比之下,具有 SIMD(单指令,多数据)架构的 GPU 在利用并行性的方式上受到限制,迫使用户在他们的机器学习算法的设计和硬件上该算法可达到的吞吐量之间进行权衡。

IPU 硬件上的这种加速为更多的创新者和人工智能从业者带来了机会,他们可以从 EfficientNet models 的高效率中受益。

Graphcore 在 GitHub 上的例子提供了广泛的流行模型,任何人都可以在 IPU 上直接使用,包括 EfficientNet 模型家族。在这个练习中,我们考虑 EfficientNet-B4,它通常用于人工智能领域来测试 EfficientNet 性能。

优化吞吐量

分发模型

有许多方法可以在一组 IPU 上分发模型,包括数据并行复制和管道模型并行。给定 EfficientNet-B4 的大小和 IPU-pod 的规模,数据和模型并行性的某种组合可以获得最佳结果。Poplar 软件堆栈使得在框架级别尝试不同的分布式设置变得容易,加快了我们对配置各种类型并行性的最佳方式的搜索。

GitHub 示例中 EfficientNet-B4 的默认配置通过四个 IPU 来传输模型。拥有多级管道意味着需要花费更多时间来填充和排空管道,从而降低了 IPU 的整体利用率。这也意味着需要更加注意*衡 IPU 之间的工作量。如果我们能够将流水线阶段的数量减少到两个,这些挑战是可以解决的。这也使我们能够将副本数量增加一倍。

为了使 EfficientNet-B4 仅适用于两个 IPU,我们采用了三种技术:

  • 使用 16 位浮点运算和主权重
  • 减少本地批量大小
  • 使用 Graphcore Research 的“让 EfficientNet 更高效”博客和论文【2】中探索的 G16 版本的 EfficientNet

IPU 本身支持 16 位和 32 位浮点数表示,允许用户灵活调整应用中各种张量的表示。在某些情况下,可能有必要存储 FP32 主重量,其中在整个训练过程中以完全精确的方式存储模型参数的副本。我们发现,对于 EfficientNet,当使用 FP16 主权重并在权重更新中采用随机舍入时,性能仍然可以保持不变。

由于存储激活所需的内存随批量大小而增加,因此考虑如何在不影响培训的情况下减少激活开销非常重要。激活重新计算是一种我们可以在需要的时候重新计算激活的方法。这提供了计算和内存之间的简单权衡。这种方法在 Poplar 中可用,并且可以通过管道 API 在框架级别轻松访问。使用 EfficientNet-B4,我们可以使用激活重新计算来适应本地批处理大小 3。与四级管道设置相比,这种配置允许并行处理更多的样本,因为我们有两倍多的副本来分发小批量。对于这项工作,我们使用组规范,一个批次独立的标准化方法。由于该模型没有任何批间依赖性,因此我们可以拥有任何适合内存的本地批大小,并简单地累积梯度以实现我们想要的任何全局批大小,从而允许我们在不影响模型的训练动态的情况下在内存中调整我们的激活。

通过将卷积组的大小从 1 增加到 16(并随后降低扩展比以补偿触发器和参数的增加),我们降低了 EfficientNet 中 MBConv 模块的内存开销。这在 Graphcore Research 的“让 EfficientNet 更高效”论文中有更详细的探讨,并在我们的博客中有总结。除了节省内存之外,该模型的这种变体还有增加 ImageNet 验证准确性的额外好处。

这三种技术允许我们仅在两个 IPU 上拟合模型,而不必将任何优化器状态卸载到流存储器,从而允许以高吞吐量进行训练。

数据输入输出

当在像 IPU-POD 这样强大的人工智能加速器系统上训练机器学习模型时,一个常见的瓶颈是从主机向模型提供足够的数据来处理。PopRun 是一个命令行实用程序,它通过在多个程序实例上以分布式方式启动应用程序来帮助缓解这一瓶颈。每个实例的 I/O 由其对应的主机服务器管理,这允许我们将模型扩展到各种 IPU-POD 系统,而不受我们向模型提供数据的速度的限制。

虽然 ImageNet 数据集最初以 INT-8 表示,但作为预处理的一部分,它通常在主机上被转换为更高精度的浮点数据类型。一旦数据位于 IPU 上,通过应用这种转换,通信开销就会降低,因为输入数据可以以较低的精度流式传输到 IPU。这有助于提高向模型提供数据的速率,从而进一步提高吞吐量。

IPU 内部和之间的数据移动是在批量同步并行 (BSP)执行方案下实现的。有了 BSP,瓦片 (IPU 处理器内核)在本地计算和与其他瓦片的数据交换之间交替,中间有一个同步步骤。

批量同步并行(BSP)执行方案。图片作者。

这种执行方案使 Poplar 能够高效地并行处理数十万个图块。对于 I/O 受限的应用,跨越所有瓦片的天真 BSP 范例会抑制性能。Poplar 通过允许一部分瓦片以异步方式专用于流数据,而剩余的计算瓦片在 BSP 范式下执行来解决这一问题。重叠 I/O 缓解了性能瓶颈,同时仍然允许高度可伸缩的执行方案。我们发现,将每个 IPU 1472 个切片中的 32 个分配给 I/O 重叠,并预取多达三批数据,结合上述方法,可以在所有系统规模下实现令人印象深刻的吞吐量。

调整批量大小

要跨大型系统(如 IPU-波德 128 和 IPU-波德 256)进行训练,使用大的全局批量是有益的。这使我们能够并行处理多个副本上的数据样本,同时确保每个副本都有足够的工作来保持效率。此外,为了分摊减少副本之间的梯度的成本,我们在副本之间通信和更新权重之前,在多个前向和后向通道上本地累积梯度,这被称为梯度累积(GA)。因此,全局批量大小是本地批量大小、副本数量和梯度累积计数的乘积。

我们的基线来自“让 EfficientNet 更高效”,使用的全球批量为 768。给定我们的本地批次大小为 3,这将在 IPU-POD256 上每次训练迭代仅产生两个本地批次,未充分利用流水线设置,并且必须应对频繁的高成本重量更新。然而,简单地增加全局批量大小会导致泛化性能下降。这种现象在许多机器学习应用中很常见,特别是在计算机视觉中 [3]。因此,我们寻求一个足够大的全球批量,以维持所有 IPU-POD 系统的高通量,但又足够小,以获得良好的统计效率。

众所周知,优化器对大批量训练的鲁棒性有很大影响 [4]。最初的 EfficientNet 论文使用了 RMSProp 优化器,在我们的研究中,当增加批量时,它很难保持统计效率。王帕尼奇等人。[5]进行了类似的观察,并建议使用分层自适应速率缩放 (LARS) [6],这是一种已知的优化器,可以很好地训练大批量的视觉模型。LARS 在逐层的基础上缩放学习率,以确保权重和权重更新之间的相似幅度。除了 LARS,我们还采用了多项式衰减学习率计划,通常与优化器结合使用。

通过对批量大小、学习速率、预热时期的数量、动量系数和重量衰减进行超参数扫描,我们发现,与我们最初的 EfficientNet-B4 实施相比,我们可以实现 6144 的全局批量大小,而不会有任何性能损失。在此批量下,所有考虑的 IPU 容器都可以保持高梯度累积计数。

图片作者。

绩效结果

借助灵活的超参数配置,我们现在能够在一系列 IPU-POD 系统上以高吞吐量训练 EfficientNet-B4。根据最初的效率网论文,我们训练了 350 个纪元。虽然“让 EfficientNet 更高效”展示了 EfficientNet 系列模型在以其原始分辨率进行微调之前,可以在较低的图像分辨率下进行预调整,但我们保持了原始分辨率,以便与其他实施保持一致。

图片作者。

图片作者。

所有的实验都使用相同的基本机器学习超参数配置,通过根据 IPU 荚的大小缩放复制品的数量和梯度累积计数。结果都收敛了,验证准确率为 82.54±0.13%。

上述结果显示了 EfficientNet 在基于 IPU 的系统上的训练速度,并与领先的 GPU 硬件上的结果进行了对比。能够快速训练模型对于创新者快速迭代和测试新想法至关重要——我们可以在不到两个小时的时间内训练 EfficientNet-B4,将创新速度从几天加快到几小时。

这种加速表明,当不受传统处理器架构的限制时,许多计算机视觉应用可以更快地进行大规模训练。像 EfficientNet 这样的下一代计算机视觉模型,当与 Graphcore 的 IPU-POD 系统等新型硬件一起使用时,可以帮助加速大量与视觉相关的用例,从 CT 扫描分析和视频升级到故障诊断和保险索赔验证。

这些配置现在可以在 Graphcore 的 GitHub 示例上试用。

谢谢你

感谢 Dominic Masters 和 Carlo Luschi,他们也为这项研究做出了贡献,感谢我们在 Graphcore 的其他同事的支持和见解。

参考

[1] M. Tan,Q. V. Le, EfficientNet:重新思考卷积神经网络的模型缩放,arXiv 2019

[2] D. Masters,A. Labatie,Z. Eaton-Rosen,C. Luschi,使效率网更有效率:探索独立于批处理的标准化、组卷积和降低分辨率训练,arXiv 2021

[3] D. Masters,C. Luschi,重温深度神经网络的小批量训练,arXiv 2018

[4] C. J. Shallue,J. Lee,J. Antognini,J. Sohl-Dickstein,R. Frostig,G. E. Dahl,测量数据并行性对神经网络训练的影响,arXiv 2018

[5] A. Wongpanich,H. Pham,J. Demmel,M. Tan,Q. Le,Y. You,S. Kumar,超级计算机规模的训练效率网络:一小时内 83%的 ImageNet Top-1 准确性,arXiv 2020

[6] Y. You,I. Gitman,B. Ginsburg,卷积网络的大批量训练,arXiv 2017

加速数据探索

原文:https://towardsdatascience.com/accelerating-data-exploration-e0047fbd08b6?source=collection_archive---------17-----------------------

使用数据描述进行探索性数据分析

数据描述(来源:作者)

探索性数据分析是更好地理解数据集和基础数据的重要初始步骤之一。它帮助我们理解数据是什么,数据集的不同特征是什么,理解不同数据点之间的关联,等等。

事先对数据的探索让我们在创建机器学习或深度学习模型时拥有优势。它不仅有助于理解数据相关性,还有助于分析数据集中的统计属性和任何隐藏模式。

EDA 通常会耗费大量的时间和精力,因为我们需要创建不同的条形图和图表来可视化和分析数据。如果我告诉你,你可以用少得多的时间和精力完成 EDA,那会怎么样?是的,这是可能的,我们可以用单行代码创建不同的图。

Data Describe 是一个开源的 python 库,可用于通过创建不同的可视化来轻松理解和分析数据集。

在本文中,我们将使用数据描述来轻松地执行 EDA。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装数据描述开始。下面给出的命令可以做到这一点。

!pip install data_describe

导入所需的库

在这一步中,我们将导入所需的库和函数来创建机器学习模型和仪表板。我们将在本文中使用 IRIS 数据集,因此我们将从 sklearn 导入它。数据集的链接如下所示:

https://scikit-learn.org/stable/datasets/toy_dataset.html#iris-plants-dataset

import pandas as pd
from sklearn.datasets import load_iris
dat = load_iris()
df = pd.DataFrame(dat['data'], columns=dat['feature_names'])
df['outcome'] = dat['target']
df.head()

数据集(来源:作者)

探索性数据分析

现在,我们将从数据探索开始。我们将从分析统计摘要开始,然后创建不同的图形和图表。

a .统计汇总

dd.data_summary(df)

统计摘要(来源:作者)

在这里,我们可以分析显示数据集的中位数、众数、四分位数等的统计摘要。

b .热图

dd.data_heatmap(df)

c.相关矩阵

dd.correlation_matrix(df)

相关性(来源:作者)

相关矩阵有助于理解数据点之间的相关性。

d.分布图

分布图显示了数据集的分布,这可以帮助我们理解数据集的偏斜度。我们将使用 ipywidget python 库来绘制所有数据点的分布图。

from IPython.display import displayfor col in df.columns:
     display(dd.distribution(df,        
                         plot_all=True).plot_distribution(col))

分布图(来源:作者)

e.散点图

dd.scatter_plots(df, plot_mode='matrix')

散点图(来源:作者)

f.聚类图

聚类图有助于可视化目标变量的聚类。

dd.cluster(df)

集群(来源:作者)

g.特征重要性

这是最重要的图之一,有助于我们识别数据集中最重要的要素。我们将使用特征重要性的 RanbdomForest 分类器。

特征重要性(来源:作者)

这些是我们可以使用数据描述创建的一些绘图和图表,用于分析和可视化数据集。继续尝试不同的数据集,轻松创建不同的图。如果您发现任何困难,请在回复部分告诉我。

本文是与 Piyush Ingale 合作完成的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时联系我在 hmix13@gmail.com 或我的 LinkedIn 简介 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

使用 WBGAPI 探索数据世界

原文:https://towardsdatascience.com/access-a-world-of-data-with-wbgapi-61849354f769?source=collection_archive---------16-----------------------

世界银行有大量的数据。下面介绍如何用 Python 获取。

华盛顿的世界银行——闪亮事物的影像(CC BY 2.0)

世界银行收集了大量关于我们生活的世界和国家的信息。这些数据可以从 API 免费访问,或者从 WBGAPI Python 库访问可能更容易一些。

浏览信息是很有可能的,但是信息太多了,所以在你开始编程之前对你要找的东西有一个合理的概念可能是个好主意。

我们将快速浏览一下有哪些信息可用,我们如何访问这些信息,以及我们可以通过 WBGAPI 图书馆获取并分析这些信息。但是首先我们需要安装 WBGAPI。

pip install wbgapi

虽然如果你是康达人…你知道该怎么做。

然后在我们开始编程之前,我们需要导入我们将使用的库: wbgapi ,当然,我们还需要 pandasmatplotlib 用于后面的内容。

import pandas as pd
import matplotlib.pyplot as plt
import wbgapi as wb

使用 Python 的帮助工具是一个很好的起点。您可以从 Python 命令行或 Jupyter 笔记本中完成这项工作。

help(wb)

*help(wb)*的结果——作者的形象

来自 help 的完整输出要比这个长得多,但这向我们展示了一些我们可以访问的信息。我们将使用其中的一些,从开始。

来源

世界银行保存着数以万计的关于世界经济不同方面的指标,它们存储在许多数据库中。通过运行以下命令,我们可以看到可以访问的源代码:

wb.source.info()

正如我们将看到的,WBGAPI 库的许多内容都有一个info()方法。下图只是最初几个可用的数据库。

世界银行数据来源——作者图片

经济

一个经济体是世界银行存储数据的国家或地区。我们再次使用info()方法得到一个列表。

wb.economy.info()

这就是结果:

前几个经济体—作者图片

这是最初的几个经济体,正如你所看到的,它们中的大部分都是独立的国家。第一列是地区的国家代码,然后是名称,接下来是地区代码,上表的最后一列将经济分类为:

  • LIC——低收入国家
  • HIC —高收入国家
  • LMC——中低收入国家
  • HMC——中高收入国家

地区

区域代码可以这样找到:

wb.region.info()

区域—按作者分类的图像

你可以看到代码和他们的名字一起出现在经济表中。

系列

现在我们来看实际数据。系列包含各种主题的数据,从人口,经济因素,如各经济体的年龄范围和性别的就业,健康数据等等。下面是列表中的前几个。

wb.series.info()

前几个系列—作者图片

有如此多的数据可供访问,以至于浏览上面生成的列表会非常乏味。为了使事情变得简单一点,我们可以通过设置一个查询来过滤我们得到的信息。下面的代码将返回包含字符串“population”的所有序列。

wb.series.info(q='population')

他们来了。

人口指标-按作者分类的图像

如果我们有兴趣了解一个国家或地区的 GDP:

wb.series.info(q='gdp')

GDP 指标-作者图片

有不少 GDP 相关的项目。

获取数据

这很好,但我们实际上还没有得到任何真实的数据。让我们开始吧。

我们需要使用库的数据组件来获取我们的数据,当然,我们需要指定我们想要的数据。

在下面的代码中,我们以熊猫数据帧的形式获取数据。第一个参数是一个字符串,它是我们在上面看到的序列之一(您在图像中看不到它,因为它在列表的后面)— NY。GDP.PCAP.CD 是一个国家的人均 GDP。第二个参数是国家列表。这可能是单个国家的实际 Python 列表(我们将在后面看到),或者在本例中是由wb.region.members()函数生成的列表。这将一个地区作为参数,并返回该地区的国家列表。EMU 是欧洲的欧元区。

gdppercap=wb.data.DataFrame('NY.GDP.PCAP.CD',
                               wb.region.members('EMU'))

欧洲货币联盟的人均 GDP 作者图片

当然,上图只是数据框的一部分。

在下面的代码中,我使用了数据框架来描绘从 1960 年到 2020 年,欧洲货币联盟成员国的人均 GDP 是如何增长的。为了便于阅读,我突出显示了排名前五的国家,其余的用灰色标出。

卢森堡似乎做得特别好,在遭受 2008 年金融危机重创后,爱尔兰似乎也恢复得不错。

g5=gdppercap.sort_values(by=['YR2020'],ascending=False)[:5]
ax=gdppercap.T.plot(color='lightgray', legend=False)
g5.T.plot(ax=ax, figsize=(15,5))

人均国内生产总值的增长—作者图片

因此,您可以看到,一旦我们确定了想要访问的数据,获取和使用它就非常简单了。

这是另一个例子。

可再生能源

我们都应该关注气候状况和化石燃料的使用,因为它们增加了温室气体的排放。因此,让我们看看不同国家采用替代能源发电的速度有多快。

首先,我们寻找合适的指标。

wb.series.info(q='renewable electricity output')

可再生电力指示器—图片由作者提供

因此,我们感兴趣的指标是 EG.ELC.RNEW.ZS。我们将使用它以及一些我们将放入 Python 列表的国家。['DEU','FRA','ESP','GBR','USA']代表德国、法国、西班牙、英国和美国。而这次我们增加了一个额外的参数time

我们使用 Python 的 range 函数来指定时间,该函数将返回一个整数列表(在本例中为年),从第一个参数开始,在第二个参数之前结束一个参数,使用第三个参数作为一个步长。

ren=wb.data.DataFrame('EG.ELC.RNEW.ZS',
                      ['DEU','FRA','ESP','GBR','USA'],
                      time=range(2000,2016,5))

可再生电力的使用——作者图片

从这个数据图表中我们可以看到我们选择的国家做得有多好。

ren.plot.bar()

可再生电力的使用——作者图片

好消息是我们所有的国家都在进步。英国起步较低,但已有显著改善,德国也是如此,尽管西班牙领先。但是法国和美国呢?你们动作快点!

一个线形图也显示了每个国家的相对进展(我把数据框调换了,所以时间在 X 轴上)。

wb.data.DataFrame('EG.ELC.RNEW.ZS',
       ['DEU','FRA','ESP','GBR','USA'],
       time=range(2000,2016,5)).T.plot()

但是还有更多

总是有更多,不是吗?

你可以探索世界银行在他们的开放数据网站上保存的数据,要了解更多关于 WBGAPI 库的信息,你可以在 Pypi 上查找,或者在这里查看最新版本的博客公告。

我希望这个小小的品尝者已经吊起了你的胃口,你会探索更多。一如既往,感谢您的阅读,如果您想不断更新新文章,请考虑注册 Medium alerts(下面应该有链接)或订阅我偶尔的免费简讯这里。

如果你对用熊猫制作图形和图表感兴趣(就像上面的那些),下载我的书《用熊猫绘图》怎么样。

使用运行 R 内核的 Google Colab 访问 Google Drive

原文:https://towardsdatascience.com/access-google-drive-using-google-colab-running-an-r-kernel-3736db7835?source=collection_archive---------15-----------------------

实践教程,云计算

从 Google Drive 文件或直接从 web URLs 导入数据

本文描述了将 Google 协同实验室与 R 内核结合使用的一步一步的方法。

作为一名工程师和生物统计学家,我主要用 python 和 r 编写代码。在过去的六个月里,我决定,对于小型项目,通过 Google Drive 和 Google Colaboratory 与他人共享代码是最快的。对于小型的非正式项目来说,访问共享云存储的便利性是无与伦比的。避免共享服务器访问、工作目录更新和 Git 混乱等问题可以节省时间,特别是当合作者对数据科学和编程语言的熟悉程度/流畅性不同时。

这种方法建立在之前的一篇媒体文章的基础上,在这里附上。它作为一个灵感和最初的指南;然而,对我来说,它抛出了错误,这似乎是 Colab 版本控制工件。在解决了一些小问题后,我能够通过 R 内核从 Google 协作笔记本文件成功访问我的 Google Drive 文件存储。完整的源代码被上传到 Github 。

请记住,可以使用 rmagic 函数在单个单元中运行 R。因此,R 内核并不是在 Colab 中使用 R 的唯一方式。但是,如果您希望笔记本适合以后的本地使用,或者确保其他人可以复制您的 R 代码,您可能希望将整个内核更改为 R,但仍然使用基于浏览器的云实例。

为什么要在 Colab 中使用 R:

  1. 许多专门的统计包都是用 R 而不是 python 构建的。
  2. r 有简单的语法来获得漂亮的视觉效果。
  3. 对于许多数据科学角色,你需要既懂 R 又懂 python。

在 Colab 中运行 R 时会出现什么问题:

  1. 挂载你的驱动器只能在 python 运行时下工作。
  2. 安装驱动器是使用 Google Colab 的关键驱动因素之一。
  3. 安装的驱动器提供了无尽的功能,试图弄清楚这一点让我发疯。

使用默认设置和默认 python 内核,在 Colab 中挂载 Google Drive 没有问题。很简单。点击阅读几种方法。或者单程这里。或者只需点击我在下面截图中显示的按钮。

Google Colab 中最棒的功能。图片作者。

但是,在您更改内核后,该功能将停止工作。因此,你可能会发现自己需要遵循我提出的三步计划来维护对你的 Google Drive 文件的访问。请注意,这需要一些欺骗和几分钟的运行时间。运行安装程序块会稍微慢一些,但是值得等待。幸运的是,他们只有三个人。

步骤 0。

打开浏览器,进入https://colab.to/r。你会看到通过运行时>改变运行时类型,R 内核已经被选中。

如何检查你的运行时设置?图片作者。

步骤一.初始化

安装 Httpuv 库。它允许 R 代码与 HTTP 和 WebSocket 客户端交互,以服务来自 R 进程的 web 流量。

install.packages(“googledrive”) *#only need to install occasionally* install.packages(“httpuv”) 
library(“googledrive”) 
library(“httpuv”)

另外,更改本地路径。这在偶尔更新时会改变,所以这一行可能会过时。

**if** (file.exists("/usr/local/lib/python3.7/dist-packages/google/colab/_ipython.py")) { *#may update python version  
                                       #occasionally*
  install.packages("R.utils")
  library("R.utils")
  library("httr")
  my_check <- function() {**return**(TRUE)}
  reassignInPackage("is_interactive", pkgName = "httr", my_check) 
  options(rlang_interactive=TRUE)
}

单独运行这个程序块。不要与前面的块合并,因为,虽然看起来没问题,但是合并两个块会抛出你不相信的错误。

drive_auth(use_oob = TRUE, cache = FALSE)

现在,您已经初始化了 Google Drive 和 Google Colab 会话之间的连接。现在你有两个选择。

如果您想从一个 web URL 直接下载一个文件到本地 Google Colab 会话,那么请转到第二步。

如果您想从您的 Google Drive 文件夹下载一个文件到本地 Colab 会话,请转到步骤 III。

第二步。从 Web 直接下载到 Colab 会话的方法

首先检查本地会话的工作目录。

getwd()
>>>'/content'

工作目录是内容文件夹。

接下来,下载文件,并解压缩文件。这个特殊的例子是美国疾病预防控制中心关于健康相关行为的公共数据集,这些行为是导致美国青年和成年人死亡和残疾的主要原因。解压缩会产生一个警告消息,但是如果您检查文件目录列表,您下载的解压缩文件将会出现。

download.file('https://data.cdc.gov/api/views/vba9-s8jp/rows.csv?
           accessType=DOWNLOAD','/content/dnld_direct_from_web.csv')unzip(zipfile="/content/downloaded.zip", exdir=".")
>>>Warning message in unzip(zipfile = "/content/downloaded.zip", >>>exdir = "."):
>>>“error 1 in extracting from zip file”

既然它是本地的,您可以使用典型的 R import 函数读入 csv 或其他文件类型。

library(readr) 
a <- read.csv(‘/content/dnld_direct_from_web.csv’) 
head(a)

产生 R 数据帧。图片作者。

第三步。方法从您的 Google Drive 下载到 Colab 会话

这使用了 googledrive 包。您可以使用 drive_get 函数获取该文件。接下来,您必须使用 drive_download 函数显式下载该文件。

x <- drive_get("~/Folder1/Folder2/Nutrition__Physical_Activity__
              and_Obesity_-_Youth_Risk_Behavior_
              Surveillance_System.csv")
drive_download(x)
z <- read.csv("/content/Nutrition__Physical_Activity__and_Obesity_-
              _Youth_Risk_Behavior_Surveillance_System.csv")
head(z)

类似地,这个文件现在已经到达您的文件目录。既然它是本地的,您可以使用典型的 R import 函数读入 csv 或其他文件类型。

再次得到 R 数据帧!图片作者。

哒哒!我希望这篇教程能让你免去我所招致的头痛。请让我知道你是否找到了这个功能的更好的实现!源代码上传到 Github 。

通过 SSH 使用 JupyterLab 轻松访问远程代码

原文:https://towardsdatascience.com/access-remote-code-in-a-breeze-with-jupyterlab-via-ssh-8c6a9ffaaa8c?source=collection_archive---------10-----------------------

使用 SSH 在本地系统中运行远程 Jupyter Lab

作者照片

在我们的日常开发工作中,我们需要访问远程系统来

  • 在共享的工作场所与同事共同发展
  • 在强大的机器上训练深度学习模型
  • 在生产中部署一些脚本

远程服务器可能指的是公共云、组织的私有数据中心、个人工作站或其他。

作者照片

这些远程服务器有一个共同的属性—它位于一个固定的位置,通常具有顶级的安全性和良好的冷却系统。基本上,由于服务器位于远程,用户需要通过 SSH 或其他基于 UI 的远程桌面应用程序来访问服务器。

基于 UI 的远程桌面应用程序,如 Anydesk、Teamviewer,可能不是首选,原因如下

  • 长期使用这些应用程序可能不是免费的
  • 需要让应用程序始终在后台运行
  • 远程服务器是无头的
  • 图形界面的引入增加了网络延迟

因此,大多数人选择 SSH 作为访问远程系统的安全方法。SSH 只在终端上工作,有时很难只用 vim/vi 编辑配置或代码。

作者照片。

这就是将基于 web 的 IDE — JupyterLab 转发到本地系统的便利之处。

内容:

  • 工作流程演练
  • 在后台运行 JupyterLab
  • 以 root 用户身份运行 JupyterLab
  • 但是我用的是 Jupyter 笔记本

工作流程演练

作者照片

要允许 JupyterLab 与远程系统同步运行,有两个主要步骤

  1. 无界面启动 JupyterLab 运行。
  2. 将远程端口转发到本地端口

步骤 1:在没有界面的情况下启动 JupyterLab 的运行

作者照片

Ssh 以

ssh <remote-user>@<remote-host>

安装 JupyterLab 后,运行以下命令

jupyter lab --no-browser --port <port-number>

作者照片

步骤 2:将远程端口转发到本地端口

作者照片

要转发端口,请打开另一个终端并运行以下命令

ssh -N -L localhost:<local-port>:localhost:<remote-port> <remote-user>@<remote-host>
  • -N: 用于端口转发。这抑制了远程命令的执行。
  • -L: 将远程端口绑定到本地端口。

作者照片

继续在浏览器中打开http://localhost:/

作者照片

从步骤 1 的终端窗口复制,输入令牌密钥。

作者照片

有三个要点需要记笔记:

  • 在当前的设置中,远程系统中运行 JupyterLab 的终端必须保持打开。或者,检查在后台运行 JupyterLab,允许终端在不终止进程的情况下关闭。
  • 同样,转发端口的终端必须在整个操作过程中保持打开。
  • 端口转发终端不会生成任何输出消息来提示操作成功(由于使用了标志-N)。

在后台运行 JupyterLab

有一个在后台运行 JupyterLab 的选项,允许终端在不终止 JupyterLab 进程的情况下关闭。

只需在命令末尾添加一个&符号。

jupyter lab --no-browser --port <port-number> &

作者照片

要终止该进程,请使用以下命令来标识该进程

ps -ef | grep python | sort

作者照片

用…扼杀进程

kill -9 <process-id>

以 root 用户身份运行 JupyterLab

不建议以 root 用户身份运行 JupyterLab。

作者照片

但是,解决方法是添加一个标志,明确允许在 root 用户模式下运行。

jupyter lab --no-browser --port <port-number> --allow-root

作者照片

但是我用的是 Jupyter 笔记本

仍然有大量的社区选择 Jupyter Notebook 作为他们的首选 IDE。不要害怕。本文中介绍的所有命令也与 Jupyter Notebook 兼容。

只需将 JupyterLab 的命令交换到 Jupyter Notebook 中。

示例:

jupyter notebook --no-browser --port <port-number>

JupyterLab 包的安装也允许运行 Jupyter 笔记本!

作者照片

下次见!

从 Garmin 可穿戴设备访问和清理数据以进行分析

原文:https://towardsdatascience.com/accessing-and-cleaning-data-from-garmin-wearables-for-analysis-56c22b83d932?source=collection_archive---------9-----------------------

一个友好的如何为匆忙的人们提取 Garmin 菲尼克斯数据的指南

当我开始做一个项目来分析我的 Garmin 菲尼克斯数据时,不清楚如何访问这个惊人的数据集,需要一些技术知识。

Garmin 的文档也很难理解和过时,导致我不得不通过代码回购和旧的互联网论坛挖掘…

这是我开始这个项目时希望存在的 Garmin 数据指南🚀

希望这篇文章能把我花了不少时间的东西变成简单易懂的东西。

文中所有图片,除非特别注明,均为作者所有

步骤 0:有哪些数据可用?

照片由 Zan 在 Unsplash

虽然有很多因素影响可用的数据,从您使用的 Garmin 型号到您是否一直佩戴胸部心率监测器,但以下是我能够从没有胸带的 Garmin 菲尼克斯中提取的特征:

一般健身数据:

  • 醒来时间
  • 步伐
  • 周期
  • 上升/下降
  • 心率
  • 活动类型和时间(中度和剧烈)
  • 总移动时间
  • 行走步长,*均速度
  • 燃烧的卡路里,燃烧的总脂肪卡路里
  • 训练压力分数
  • 最高和*均温度
  • 应力水*
  • 速度和强度
  • 静息代谢率,静息心率
  • 游泳:泳池长度、泳姿长度和距离、游泳节奏、首圈指数
  • 跑步:最大跑步步频、最大一般步频、总步数

特定运动事件数据:

  • 时间
  • 旅行距离
  • 位置(经度/纬度)
  • 海拔和温度
  • 心率
  • 节奏(和分数节奏)
  • 速度和功率
  • 左右*衡

步骤 1:获取数据转储

虽然您也可以通过 Garmin 的名为“ Garmin Connect IQ 的 SDK 来访问这些数据,但我将通过手动方式来访问这些数据。它实际上容易得多,尤其是对于个人使用,但是 Garmin 有过时的文档,所以它看起来很复杂…

首先,进入你的 Garmin 账户数据管理(https://www.garmin.com/en-US/account/datamanagement/)并登录:

来自网站的截图

然后转到“导出您的数据”并点击Request Data Export

然后,您将收到一条消息,说明:

Your request has successfully submitted.You can request a copy of all personal data, including your profile, order history, information from Garmin Connect and other applications, subscriptions, registered devices and more.We will send a link to download your export file to [yourAccountEmail@email.com]Files typically take about 48 hours to prepare but, depending on the number of requests being processed and the amount of data associated with your profile, could take up to 30 days.

恭喜你。你很快就会得到你的数据。虽然信息说最多 30 天,但我在 30 分钟内就收到了。(为什么他们需要 30 天来处理一个数据请求?我是从我的账户里申请的,所以不存在任何许可/安全问题…他们有人手动给我发送数据吗…?)

最终你会收到一个. zip 文件。打开它以显示文件夹结构:

对我来说,这些文件夹大部分是空的,因为我没有使用它们。在那些不为空的数据库中,几乎所有的数据库都包含一个包含客户数据或聚合练习数据的 JSON 文件。

我们唯一关心的是 DI _ CONNECT > DI-CONNECT-Fitness-Uploaded-Files:

点击。zip 文件放在这个嵌套的文件夹中,你将创建一个充满。适合文件类型

步骤 2:转换成可用的文件类型

这是最棘手的部分,因为我们需要将这些从.fit转换成。CSV 使用命令行。.fit是 Garmin 使用的一种特殊文件类型,您的任何数据分析工具(Excel、Atom、Jupyter)都无法使用。

我们将依赖 Garmin 的 FIT SDK 的 FIT CSV 工具(https://developer.garmin.com/fit/fitcsvtool/)。这是免费的,但需要设置。

首先,打开命令行终端。如果您不熟悉 CLI,它应该是这样的:

接下来我们需要检查我们是否安装了 JAVA。检查的一个简单方法是在我们的终端中键入java -version。如果我们得到一个号码返回,它被安装。如果我们收到错误信息,我们需要安装它

安装 JAVA 时的成功消息

未安装 JAVA 时的错误消息响应

安装 Java: 根据你运行的是 MacOS/Windows/Linux,你需要下载不同的文件。正如终端消息所说,前往https://www.java.com/en/download/下载 java 包。这将提示一个安装程序窗口,您可以沿着这里的进行操作。下载成功后,关闭并重新打开你的终端,并通过同样的java -version测试验证 java 是否已安装。

一旦我们知道已经下载了 Java,继续下载 FIT SDK(https://developer.garmin.com/fit/download/)并解压。活力

这将为您提供一个包含以下内容的文件夹:

现在,我们可以将我们的.fit文件转换成。战斗支援车🚀完成这项工作的 jar 文件位于一个名为FitCSVTool.jar的 java 文件夹中

在命令行中键入以下内容,将<file>替换为.fit文件的文件路径:

java -jar FitCSVTool.jar <file>

如果你得到像Unable to access jarfile FitCSVTool(No such file or directory)这样的错误,你需要找出正确的文件路径。在 Mac 上,直接将文件拖放到终端就像一样简单。在 windows 中,您需要从文件属性中复制/粘贴文件路径。

如果成功,将在与原始.fit文件相同的目录下创建一个. csv 文件。

这可能是转换过程的结束,但是为每个文件输入上面的命令是一件痛苦的事情。我有超过 8000 个.fit文件,你可能有更多。幸运的是,我们可以自动化这一点。

对于这一步,Windows 和 Mac 指南将会有所不同。如文件中所述:

FIT SDK 包括多个 Windows 批处理文件,为 FitCSVTool 提供拖放界面。这些批处理文件与 OSX 不兼容;但是,使用 Automator 应用程序也可以实现相同的功能。

对于苹果电脑,我们可以创建一个如上述文件概述的自动机;打开 Automator 并…

  • 从窗口中选择“应用程序”,然后点按“选取”
  • 给它一个名字
  • 在“资源库”文件夹中找到“过滤器 Finder 项目”,并将其拖到右侧屏幕。输入"。适合“包含”字段
  • 在 Library 文件夹中找到“Run Shell Script”并拖动到右侧屏幕。用下面的代码片段填充,用上面使用的工具的路径替换path/to/fit/sdk/java/FitCSVTool.jar(记住你可以拖放!):
FitCSVToolJar=path/to/fit/sdk/java/FitCSVTool.jar
while read inputfile
do
outputfile=${inputfile/.fit/}
java -jar $FitCSVToolJar -b "$inputfile" "$outputfile"_raw
java -jar $FitCSVToolJar -b "$inputfile" "$outputfile"_definitions --data none
java -jar $FitCSVToolJar -b "$inputfile" "$outputfile"_records --defn none --data record
done

完成所有这些后,您的 Automator 应用程序应该如下所示:

  • 将此保存到桌面

  • 高亮显示并拖动所有的 *.fit* 文件到应用程序桌面图标上,如图所示

这将开始自动转换您拥有的所有成千上万的文档。对我来说,这让我的 MacBook 风扇非常吵,花了大约半个小时。

虽然我没有 Windows 机器来测试这一点,但我相信 Windows 会通过将所有的.fit 文件拖到 FitSDK 文件夹中的一个.bat文件上来实现类似的拖放系统:

全部 5 个。FitSDK 文件夹中的 bat 文件。只需拖拽!

如 Windows 文档中所述:

An easier way to use FitCSVTool is to use one of the five batch files included in the SDK. These files are located in the same folder as FitCSVTool.jar. Drag-n-drop a FIT file onto any of the batch files and the output .csv files will be created in the same folder as the source FIT file.

由于之前从.fit转换到.csv的步骤,我们现在每个.fit文件有几个.csv文件:

  • 概述数据中存在哪些字段的文件
  • 一个_records_data文件,包含锻炼程序的距离、速度的汇总数据
  • 一个_records文件,包含每时每刻锻炼程序的位置、速度和距离
  • 一个包含所有内容的_raw 文件,包括压力水*、心率和其他指标。(正如下一节所见,这些极其混乱)

🎉恭喜你,你有 CSV 格式的数据了!🎉

为你骄傲!扎克·杜兰特在 Unsplash 上的照片

第三步:清洁

这一步及以后的一切都是我推荐的数据清理,但是可选的。你也可能有和我不一样的数据,所以这些清理过程可能不适合你。

也就是说,我很有信心下面的步骤将帮助任何人分析他们的 Garmin 数据。

删除定义表

定义文件的屏幕截图

查看定义文件,它们似乎不包含任何有用的内容。从抽查来看,所有的值列似乎都是 1。我假设这对.fit文件很重要,但对我们的目的来说并不重要。

要移除定义文件,请通过运行以下命令在终端中导航到 csv 文件的位置:

cd path/to/csv/files

然后运行:

rm *definitions*

这也可以很容易地通过从我们的 automator 中删除 java -jar $FitCSVToolJar -b "$inputfile" "$outputfile".definitions --data none 来实现,但是要确保任何想要该文件的人都可以使用它

创建一个大型 CSV

我们仍然有一个问题,需要解析成千上万个 CSV 来查看我们的数据。您可以将所有 CSV 与以下内容结合使用:

cat *.csv >garmin_combined.csv

或者如果您计划生成与我下面的数据模式相同的数据模式:

cat *_records.csv >combined_records_full.csv
cat *_raw.csv >combined_raw_full.csv

这创建了两个不同的组合 CSV 供我们使用。

创建可用的列

来自记录文件的屏幕截图

😃好消息:从我们的.fit转换生成的_records文件看起来不错。

🙁坏消息:_raw数据文件如此凌乱不堪。空字段、特殊字符、表示不同意思的列值…天啊。

从一个原始数据文件截图…这将需要一些工作

我强烈建议按时间戳进行旋转,这样列才有意义。通过这种方式,您可以在记录时快速轻松地检查任何感兴趣的指标,这可能是该数据最常见的用途。

通过时间戳聚合,我们还可以在不丢失任何数据的情况下极大地减小文件大小。双赢!

我用 Python 编写了一个更简洁的函数来创建这些列。我已经把它上传到一个 Github Repo 文件clean_garmin.py中,或者把下面的内容复制粘贴到你自己的clean_garmin.py文件中:

安装 Python: 你需要在电脑上安装 Python 来运行上述功能。去https://www.python.org/downloads/安装 Python。然后进入终端,用python --version确认下载成功。

一旦保存了上面的代码块,就可以在终端中运行了:

python clean_garmin.py -i combined_records_full.csv -o combined_records_clean.csvpython clean_garmin.py -i combined_raw_full.csv -o combined_raw_clean.csv

注意:这需要很长时间,尤其是原始文件。我的电脑花了 10 分钟录制,花了大约 2.5 小时录制 raw。其原因是,有时数据条目上的时间戳是本地的而不是全局的,这意味着它引用最*的全局时间戳。因此,每次我们进行这种转换时,代码都需要找到最*的全局时间戳,并将本地时间戳转换为全局时间戳…但这需要 O(n)时间💀

…我们的数据看起来好多了🙌

转换的记录文件。尼斯(法国城市名)

如果我的清理功能对您的数据失败,或者如果您有更好的数据清理实现,请留下评论,以便我们可以合作!

清理回购

我们的文件夹里还有成千上万的文件,这让我很紧张。继续删除所有未聚合的 CSV,包括:

rm *_raw.csv*
rm *_records.csv*
rm *_records_data.csv*

第四步:掉进兔子洞

现在我们已经有了一个干净的、可用的 Garmin 数据 CSV,我们可以开始分析这个漂亮的数据集并从中获得见解。

这是数据科学/分析的有趣部分,希望我们所经历的一切都是值得的!

由于这篇文章已经相当长了,我将写一篇后续文章,介绍一些分析 Garmin 数据的方法,以得出关于我们运动和健身习惯的有趣见解。

如果以上任何步骤对你不起作用,请留下评论,这样我可以试着帮助调试并把解决方案添加到文章中。我的希望是,没有人必须再次通过论坛寻找答案,在这里得到所有的答案。

希望您喜欢,并祝您在分析之旅中好运!

在熊猫的多索引数据框架中访问数据

原文:https://towardsdatascience.com/accessing-data-in-a-multiindex-dataframe-in-pandas-569e8767201d?source=collection_archive---------0-----------------------

熊猫帮助你开始数据分析的提示和技巧

安娜斯塔西娅·切*斯卡在 Unsplash 上拍摄的照片

一个 MultiIndex (也称为层次索引)数据帧允许您将多个列作为一个行标识符,将多个行作为一个标题标识符。使用 MultiIndex ,您可以进行一些复杂的数据分析,尤其是处理更高维度的数据。访问数据是处理多索引数据框架的第一步。

在本文中,您将了解如何访问多索引数据框架中的数据。这篇文章的结构如下:

  1. 通过一级索引选择数据
  2. 通过多级索引选择数据
  3. 使用切片选择数据区域
  4. 使用slice(None)选择所有内容
  5. 使用横截面xs()
  6. 使用IndexSlice

为了进行演示,我们创建了一个虚拟数据集,并将使用前 2 列作为行标识符前 2 行作为标题标识符来加载它。

df = pd.read_csv('dataset.csv',
    **index_col=[0,1],**
    **header=[0,1]**
).sort_index()

昼夜天气数据(作者制作)

请查看笔记本获取源代码。

1.通过一级索引选择数据

当选择数据帧上的数据时,Pandas loc是最受欢迎的数据之一。在上一篇文章中,我们已经介绍了[loc](/how-to-use-loc-and-iloc-for-selecting-data-in-pandas-bd09cb4c3d79)[iloc](/how-to-use-loc-and-iloc-for-selecting-data-in-pandas-bd09cb4c3d79) 用于在通用(单索引)数据框架中选择数据。访问多索引数据帧中的数据的方式与访问单索引数据帧的方式相似。

我们可以将第一级标签传递给loc来选择数据

# Retrieve London's Day weather
df.loc['London', 'Day']

作者图片

我们也可以使用:返回所有数据。

# To get all rows - all Day weather
df.loc[:, 'Day']

作者图片

并获取所有列

# To get all columns
df.loc['London' , :]

作者图片

以上工作如我们所料。然而,你可能会惊讶地发现df.loc['London', '2019-07-02']也很管用

# This also works
>>> **df.loc['London' , '2019-07-02']**Day    Weather                Shower
       Wind                SW 16 mph
       Max Temperature            29
Night  Weather            Heavy rain
       Wind                SW 16 mph
       Max Temperature            17
Name: (London, 2019-07-02), dtype: object

这个结果通常会导致歧义。事实上,上述所有语句都是从多索引数据帧中检索数据的简写符号。对于多索引数据帧,建议使用元组来避免歧义。

以下是使用元组的等效语句

# Equivalent to **df.loc['London', 'Day']**
df.loc[**('London', )** , **('Day', )**]# Equivalent to **df.loc[:, 'Day']**
df.loc[:, **('Day',)**]# Equivalent to **df.loc['London' , :]**
df.loc[('London', ) , :]# Equivalent to **df.loc['London' , '2019-07-02']**
df.loc[**('London' , '2019-07-02')**]

2.通过多级索引选择数据

如果你想阅读 2019-07-01 的伦敦天气,你可以简单地做:

>>> df.**loc['London', 'Day']**.**loc['2019-07-01']**Weather               Shower
Wind               SW 16 mph
Max Temperature           28
Name: 2019-07-01, dtype: object

注意,loc['London', 'Day']返回一个数据帧,并调用loc['2019-07-01']再次提取数据。这当然有效,但是有一种更有效的方法使用元组。

>>> df.loc[**('London', '2019-07-01')**, '**Day**']Weather               Shower
Wind               SW 16 mph
Max Temperature           28
Name: (London, 2019-07-01), dtype: object

多索引键采用元组的形式。在这种情况下,('London', '2019-07-01')选择行标签,'Day'选择列。

我们还可以传递标签列表来选择多行或多列:

# Select multiple rows
df.loc[ 
    ('London' , **['2019-07-01','2019-07-02']** ) ,
    'Day'
]# Select multiple columns
df.loc[ 
    'London' ,
    ('Day', **['Weather', 'Wind']**)
]

作者图片

3.通过切片选择数据范围

Slice(写为start:stop:step)是一种强大的技术,允许选择一定范围的数据。当我们想要选择两个项目之间的所有内容时,这非常有用。

对多索引数据帧中的一级索引进行切片与对单索引数据帧进行切片的方式相似。举个例子,

df.loc[
    **'Cambridge':'Oxford'**,
    'Day'
]

然而,当分割多层索引时,我们将会得到一个语法错误,如下所示:

# We are getting a SyntaxError
df.loc[
    ('London', **'2019-07-01': '2019-07-03'**),
    'Day'
]

对多级索引进行切片的正确方法是使用元组:

df.loc[
    **('London','2019-07-01'):('London','2019-07-03')**,
    'Day'
]

作者图片

较低级别的索引不必相同。例如,我们可以选择从('Cambridge', '2019-07-01')('London', '2019-07-02')的数据范围

df.loc[
    **('Cambridge', '2019-07-01'):('London','2019-07-02')**,
    'Day'
]

作者图片

4.使用slice(None)选择所有内容

当通过一级索引检索数据时,我们可以使用:来选择所有内容。然而,当使用多级索引时,我们会遇到语法错误。

# Getting **SyntaxError**
df.loc[ 
    **('London', :)**,
    'Day'
]# Getting **SyntaxError**
df.loc[ 
    **(: , '2019-07-04')**,
    'Day'
]

选择特定索引级别上所有内容的正确方法是使用slice(None)

df.loc[ 
    ('London', **slice(None)**),
    'Day'
]df.loc[
    (**slice(None)** , '2019-07-04'), 
    'Day'
]

作者图片

5.使用横截面xs()

DataFrame 的xs()方法可以接受一个level参数,使得在多索引的特定级别选择数据更加容易。

df.xs('2019-07-04', **level='Date'**)

df.xs 的结果(' 2019–07–04 ',level='Date ')(图片由作者提供)

xs()也允许使用多个键进行选择

df.xs(('London', '2019-07-04'), **level=['City','Date']**)

df.xs 的结果(('伦敦',' 2019–07–04 '),level=['城市','日期'])(图片由作者提供)

您还可以通过提供axis参数来选择带有xs()的列。

df.xs('Wind', level=1, **axis=1**)

df.xs 的结果('风',级别=1,轴=1 )

请注意,所选的列标签'Wind'不包括在结果中。为了保持被选中的级别,我们可以通过drop_level=False

df.xs('Wind', level=1, axis=1, **drop_level=False**)

df.xs 的结果(' Wind ',level=1,axis=1, drop_level=False )

6.使用IndexSlice

您可以使用 Pandas IndexSlice来简化更自然的语法。

例如,用:代替slice(None)

from pandas **import IndexSlice as idx**df.loc[ 
    **idx[: , '2019-07-04'],** 
    'Day'
]# Instead of **slice(None)**
# df.loc[ 
#    **(slice(None) , '2019-07-04')**, 
#    'Day'
# ]

对行和列都使用IndexSlice

rows = idx[: , '2019-07-01']
cols = idx['Day' , ['Max Temperature','Weather']]df.loc[rows, cols]

使用xs()IndexSlice选择数据范围

rows= (
    **idx['2019-07-02':'2019-07-04']**, 
    'London'
)df.xs(
    rows , 
    level = ['Date','City']
)

结论

使用 MultiIndex ,您可以进行一些复杂的数据分析,尤其是处理更高维度的数据。使用多索引数据框架时,访问数据是第一步。我希望这篇教程对你访问多索引数据框架有用。我建议你查看一下文档来了解你可以做的其他事情。

感谢阅读。请查看笔记本获取源代码,如果您对机器学习的实用方面感兴趣,请继续关注。

你可能会对我的其他一些熊猫文章感兴趣:

  • Pandas cut()函数,用于将数值数据转换为分类数据
  • 使用熊猫方法链接提高代码可读性
  • 如何对熊猫数据帧进行自定义排序
  • 为了数据分析你应该知道的所有熊猫移位()
  • 何时使用 Pandas transform()函数
  • 你应该知道的熊猫串联()招数
  • 熊猫的应用()和变换()的区别
  • 所有的熊猫合并()你应该知道
  • 在 Pandas 数据框架中处理日期时间
  • 熊猫阅读 _csv()你应该知道的招数
  • 用 Pandas read_csv()解析日期列应该知道的 4 个技巧

更多教程可以在我的 Github 上找到

为 Instagram Business 访问脸书 API

原文:https://towardsdatascience.com/accessing-facebook-api-for-instagram-business-568cfe3efb77?source=collection_archive---------19-----------------------

供个人使用的社交媒体分析技巧

为企业可靠提取 Instagram 数据的经验

来源( unsplash )

我的追随者增长一直停滞不前。为什么?

我该怎么做才能吸引我的追随者?

节选自我之前的帖子( “建立你的 Instagram 业务的最快分析” )

问题陈述

假设你是一个开了一家花店的企业主。为了宣传您的新企业,您激动地注册了 Instagram 企业帐户。

仅仅一个月,你的追随者就增加到了 200 人。你确信你的帖子非常吸引人。所以你推动自己创造更多的内容,期待类似的增长。

但到了下一季度,你并没有获得你预期的高增长。看起来你不再推送吸引人的内容了。

那么问题是什么呢?你会怎么解决?你将如何有效地与你的追随者互动?

进入 Instagram Analytics

Instagram 抓取的限制

上周,我重点介绍了一个方法,使用一个简单的 REST 调用快速抓取 Instagram 数据。除了会遇到一些限制之外,这种方法工作得很好:

  1. 无法从与趋势相关的帖子或故事中获取数据。
  2. 缺少其他关键指标数据,如展示次数和覆盖范围。

如果你想对 Instagram 数据进行更彻底的分析,我建议你使用 Instagram Graph API 访问 Instagram 数据并利用你的商业账户。

Instagram Graph API 允许 Instagram 专业人士——企业和创作者——使用你的应用管理他们在 Instagram 上的存在。该 API 可用于获取和发布他们的媒体,管理和回复他们媒体上的评论,识别他们被其他 Instagram 用户@提及的媒体,查找带标签的媒体,以及获取关于其他 Instagram 企业和创作者的基本元数据和指标。— 脸书文件

这些数据将用于创建 Instagram 仪表盘;更多背景信息(来源作者。)

什么是 Instagram 商业账户?

Instagram 商业帐户将您的 Instagram 帐户转变为品牌帐户,以了解故事、帖子和关注者。— 商务 Instagram

转换成企业账户有几个好处:

  1. 实时访问您帖子的绩效指标
  2. 包括描述性配置文件字段,如位置和移动电话。
  3. 【品牌】 下从 Instagram 推荐中获取促销。

注册过程很简单。In 插入您的业务详情并在获得批准后登录。

使用脸书 API 访问您的 Instagram 数据

创建您的开发者帐户

在指定数据之前,您需要在脸书开发者 API 中注册并创建一个开发者账户。

这允许 Instagram 验证您的应用程序并建立连接以使用他们的数据服务。请遵循脸书指南中关于如何注册开发者账户的说明。

查找您的业务 ID 和令牌

你可以在脸书图形 API 浏览器中找到你所有的 API 访问控制。

在浏览器中,点击 “生成访问令牌” 并运行以下查询以获取您的脸书业务 ID。

me?fields=instagram_business_accounts

接收 Instagram 商业帐户 ID

注意:此令牌是短期的,将在一天内到期。您需要按照下面的说明来生成长期访问令牌。

获取长期访问令牌

运行以下代码以访问长期访问令牌

https://graph.facebook.com/v9.0/oauth/access_token?grant_type=fb_exchange_token&client_id=<**client_id**>&client_secret=<**client_secret**>&fb_exchange_token=<**Short_lived_token**>Sample LONG lived token generated(modified for privacy): EAAPLSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM

这里注意,你需要包括 3 个参数:

  • client_id :你的应用标识符。你可以很容易地在你的 FB 开发者应用设置的基本设置中找到它
  • client_secret :你的应用认证的秘密令牌。你可以很容易地在你的 FB 开发者应用设置的基本设置中找到它
  • 短命令牌:您在上一步中使用脸书图形 API 浏览器生成的令牌

在那里你可以找到你的客户 ID 和客户秘密(来源于作者)

请求脸书图表数据

一旦我们有了所有这些信息,我们就可以运行基本的 POST/GET 请求,正如在 Instagram Graph API 中提到的

最好开始的服务是insta gram Graph business discovery API。请随意复制这个 Google 电子表格并检查 Google Appscript 代码。

用户趋势数据:

[https://graph.facebook.com/{business_id}?fields=business_discovery.username(instagram_id){username,website,followers_count,media_count}&access_token=](https://graph.facebook.com/17841444468251721?fields=business_discovery.username(yayasanmerajuthati){username,website,followers_count,media_count}&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[{](https://graph.facebook.com/v9.0/18151326238114763/insights?metric=engagement,impressions,reach,saved,video_views&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)access_token}**Parameters:
business_id**: the business ID from Instagram Explorer
**instagram_id**: the instagram account (check the instagram account URL or your business profile)
**access_token**: short lived or long lived token which you generate

一旦您替换了参数并运行它,您将收到 JSON 字符串,您可以进一步解析和分解它的路径组件:

访问 Instagram 业务发现 API

我应该知道的其他请求是什么?

发布趋势数据:

目的:提取所有帖子趋势,包括喜欢和评论

[https://graph.facebook.com/](https://graph.facebook.com/17841444468251721?fields=business_discovery.username(yayasanmerajuthati){media.limit(100000){caption,timestamp,permalink,comments_count,like_count}}&period=lifetime&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[{business_id}](https://graph.facebook.com/17841444468251721?fields=business_discovery.username(yayasanmerajuthati){username,website,followers_count,media_count}&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[?fields=business_discovery.username(](https://graph.facebook.com/17841444468251721?fields=business_discovery.username(yayasanmerajuthati){media.limit(100000){caption,timestamp,permalink,comments_count,like_count}}&period=lifetime&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[instagram_id](https://graph.facebook.com/17841444468251721?fields=business_discovery.username(yayasanmerajuthati){username,website,followers_count,media_count}&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[){media.limit(100000){caption,timestamp,permalink,comments_count,like_count}}&period=lifetime&access_token=](https://graph.facebook.com/17841444468251721?fields=business_discovery.username(yayasanmerajuthati){media.limit(100000){caption,timestamp,permalink,comments_count,like_count}}&period=lifetime&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[{](https://graph.facebook.com/v9.0/18151326238114763/insights?metric=engagement,impressions,reach,saved,video_views&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)access_token}**Note:** You need to add media.limit(10000) to override the default limits and ensure that Facebook does not limit the number of the latest posts

每日趋势命令:

目的:提取每日个人资料趋势(印象数、到达数、个人资料浏览量)

[https://graph.facebook.com/v9.0/](https://graph.facebook.com/v9.0/17841444468251721/insights?metric=impressions,follower_count,profile_views,reach,email_contacts,text_message_clicks,website_clicks&period=day&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[{business_id}](https://graph.facebook.com/17841444468251721?fields=business_discovery.username(yayasanmerajuthati){username,website,followers_count,media_count}&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[/insights?metric=impressions,follower_count,profile_views,reach,email_contacts,text_message_clicks,website_clicks&period=day&access_token=](https://graph.facebook.com/v9.0/17841444468251721/insights?metric=impressions,follower_count,profile_views,reach,email_contacts,text_message_clicks,website_clicks&period=day&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[{](https://graph.facebook.com/v9.0/18151326238114763/insights?metric=engagement,impressions,reach,saved,video_views&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)access_token}

寿命趋势命令:

目的:提取关注者的人口统计信息(年龄/城市/等)

[https://graph.facebook.com/v9.0/](https://graph.facebook.com/v9.0/17841444468251721/insights?metric=audience_country,audience_city,audience_gender_age&period=lifetime&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[{business_id}](https://graph.facebook.com/17841444468251721?fields=business_discovery.username(yayasanmerajuthati){username,website,followers_count,media_count}&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[/insights?metric=audience_country,audience_city,audience_gender_age&period=lifetime&access_token=](https://graph.facebook.com/v9.0/17841444468251721/insights?metric=audience_country,audience_city,audience_gender_age&period=lifetime&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[{](https://graph.facebook.com/v9.0/18151326238114763/insights?metric=engagement,impressions,reach,saved,video_views&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)access_token}

帖子具体趋势

目的:提取帖子信息(每个帖子的浏览量、影响范围和参与度)

[https://graph.facebook.com/v9.0/](https://graph.facebook.com/v9.0/18151326238114763/insights?metric=engagement,impressions,reach,saved,video_views&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[{media_id}](https://graph.facebook.com/17841444468251721?fields=business_discovery.username(yayasanmerajuthati){username,website,followers_count,media_count}&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)[/insights?metric=engagement,impressions,reach,saved,video_views&access_token={](https://graph.facebook.com/v9.0/18151326238114763/insights?metric=engagement,impressions,reach,saved,video_views&access_token=EAAPLSLMjcEoBAJbrqs9m3nPhwUaLMwiHmQ4zYKU7jsiB325KNS0H3KE8VK9fq1CHpgLDZCLDbeaXRGRcBpBQBvVmVf725TxZAFrkU4l1abDNCsZAJIhzobkXHH1mxwCSpZAAoE9uyfTFvIKu6vpRkxDwZBzXtZBd5XXNxDZCoaZCd2W34tHr7RvM)access_token}**Parameter**:
*** media_id**: from the post trends call. For me, I would iterate through all medias that I have and generate the following JSON strings to store.

结论

在 Instagram 中提取数据是一种以可靠的方式获取数据的有益方式。通过以下方式每天刷新统计数据,可以节省您查看趋势的时间:

  1. 与脸书图形 API 建立连接。
  2. 运行简单脚本挖掘 Instagram。

正确完成后,您将能够建立数据分析管道并按如下方式自动运行您的触发器。

自动化 Instagram 拉脚本(来源于作者)

然后,您可以自由地将 pulls 与任何仪表板工具(如 Google Data Studio)连接起来

恭喜你。您已成功免费获取您的 Instagram 数据。

更多信息请参考我之前的帖子。

来自作者的更多提示:

  • 建立 Instagram 业务的最快分析方法
  • 如何构建您的终极数据科学投资组合
  • 如何在 10 分钟内搭建一个惊艳的互动仪表盘
  • 谷歌数据工作室的基础
  • 写作分析的隐藏宝石

关于作者

我用 ML @ Google 对抗网络钓鱼。

我热爱我的工作是因为我使用先进的 ML 算法和 MLOps 来保护 Chrome、Gmail 和 Android 用户免受网络钓鱼攻击,这些攻击每周都可能窃取弱势群体的生活积蓄。

我也是一名面向数据科学媒体的作家,为全球 50 多万观众的有志 ML 和数据从业者提供指导。

最后,请通过 LinkedIn 、 Medium 或 Youtube 频道联系我

索利·德奥·格洛丽亚

准确性和损失:关于前 1 名和前 5 名准确性需要知道的事情

原文:https://towardsdatascience.com/accuracy-and-loss-things-to-know-about-the-top-1-and-top-5-accuracy-1d6beb8f6df3?source=collection_archive---------2-----------------------

数据科学

衡量我们模型的性能

作者图片

假设我们正在使用深度学习解决一个简单的分类问题。我们将图片(蓝莓)作为模型的输入,得到我们的预测结果(有概率)如下。

  • 樱桃:0.35
  • 覆盆子:0.25
  • 蓝莓:0.2
  • 草莓:0.1
  • 苹果:0.06
  • 橙色:0.04

你将如何评价你的模型?你知道前 1 名和前 5 名准确性之间的区别吗?

  • 使用 top-1 精度,您将该输出计为true,因为它预测了一个樱桃。
  • 使用前 5 名准确度,您将该输出计为false,因为蓝莓是前 5 名猜测之一。

我们在 5 幅图像上测试了该模型,得到了以下结果。

作者图片

给定这个例子,我们的模型正确地预测了 2 个图像,并且真实标签在前 5 个预测标签中出现了 3 次。

准确(性)

什么是准确性?

它是描述算法在分类任务上的准确性的度量之一。准确度是配对样本数除以样本数。

准确度=正确预测数/正确预测总数

例如:如果准确率达到 91%,这意味着 100 个例子中有 91 个是正确的。

最高精度

最高精度是常规精度,模型预测(概率最高的一个)必须完全是预期的答案。

它测量预测标签与单个目标标签匹配的示例的比例。

在我们的例子中,最高精度= 2/5 = 0.4。

前 5 名准确度

前 5 名准确性意味着我们模型的前 5 名最高概率答案中的任何一个与预期答案相匹配。

如果五个预测中的任何一个与目标标签匹配,它就认为分类是正确的。

在我们的例子中,前 5 名的准确度= 3/5 = 0.6。

今天,我们已经看到了前 1 名准确性和前 5 名准确性之间的差异。请记住:with N >= K then Top-N Accuracy >= Top-K Accuracy。换句话说,随着精度的提高,前 N 名的精度可以提高或保持不变。

很简单,对吧?

理解准确性和可解释性的权衡

原文:https://towardsdatascience.com/accuracy-interpretability-trade-off-8d055ed2e445?source=collection_archive---------16-----------------------

讨论机器学习中模型准确性和可解释性之间的权衡

Abel Y Costa 在 Unsplash 上拍摄的照片

介绍

在我之前的一个角色中,我讨论了机器学习环境中参数化和非参数化方法之间的差异。

参数方法对数据和要估计的函数之间的关系做出假设,因此它们通常是不灵活的。例如,我们可以假设函数 f 是线性的,并使用简单的线性回归,这在只能估计 f 的线性形状的意义上可以认为是不灵活的。

另一方面,非参数方法更加灵活,因为它们能够“考虑”函数 f 更多可能的形状。

模型可解释性

当我们估计一个未知函数 f 时,我们最感兴趣的是执行推理或预测(有时两者都有)。

当在推理设置中工作时,我们通常将模型视为白盒,因为我们试图理解输入 X 和输出变量 y 之间的关系。不太灵活的方法往往更容易解释,因此更适合进行推理

另一方面,更灵活的方法(如支持向量机或 Boosting)能够为未知函数 f 估计更复杂的形状,但更难解释。这意味着这种方法可能不太适合推理设置。函数的形状越复杂,就越难理解预测变量(X)和目标变量 y 之间的关系

模型精度

现在,如果我们对执行预测感兴趣,我们需要训练一个能够尽可能准确地预测目标变量的模型。在预测设置中,我们可以将模型视为黑盒,在某种意义上,我们并不真正关心估计的 f 的形状,只要它能够导致准确的预测。

在预测设置中,我们并不真正关心模型的可解释性,我们最感兴趣的是模型的性能。因此,更灵活(但更难解释)的方法是通常是(这是这里的关键词——在下一节中会有更多的介绍!)更适合这类用例。

过度拟合

同样需要强调的是更灵活的模型并不能保证比相对不复杂的模型更好的结果。在某些情况下,与更灵活的模型相比,不太灵活的模型可能会产生模型性能。

这是因为更灵活的模型容易出现一种叫做过度拟合的现象。当模型过于紧密地跟随训练数据的噪声和误差时,它是过度拟合的,因此它不能很好地推广到新的、看不见的数据点。

最后的想法

在今天的文章中,我们讨论了机器学习环境中模型准确性和模型可解释性之间的权衡。

不太灵活的模型更容易解释,因此更适合我们最感兴趣的理解输入和输出之间关系的推理环境。另一方面,更灵活的模型更难解释,但结果可能更准确。

根据我们正在处理的问题,我们可能必须选择最适合我们用例的模型。然而,我们应该记住,在大多数情况下,我们必须在模型准确性和模型可解释性之间找到最佳*衡点。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。

你可能也会喜欢

Ace 系统面试—设计一个聊天应用程序

原文:https://towardsdatascience.com/ace-the-system-interview-design-a-chat-application-3f34fd5b85d0?source=collection_archive---------0-----------------------

1.介绍

设计像 Slack 或 Messenger 这样的聊天应用程序一直是系统设计面试官最常问的问题之一。就我个人而言,到目前为止,我已经遇到过几次这样的问题。作为新毕业生 SDEa 的初级成员,我们擅长实现,但是设计整个系统本身就是一个挑战。在这篇文章中,我想与你分享我对 Slack 的设计,这是基于我收到的真实采访反馈以及与高级工程师的讨论。

1.1.要求

首先,我们必须弄清楚目标系统的确切需求。对于 Slack(或您使用的其他应用程序),可以预期以下功能:

  • 直接消息传递:两个用户可以互相聊天
  • 群聊:用户可以参与群聊
  • 加入/离开群组,(添加/删除对 Slack 不重要的朋友)
  • 输入指示器:当输入时,接收者得到通知
  • 用户状态:您是在线还是离线
  • 当用户离线时,如果有新消息到达,尝试向用户的移动设备发送通知。

除了上述特性之外,该系统显然应该具有可伸缩性和高可用性。

1.2.交通量估计

我采访过的一些面试官不喜欢预先的粗略估计,因为统计数据是随意挑选的,准确的数字没有多大意义。在某种程度上,他们是对的。然而,我们确实需要一些粗略的数字来帮助我们做出关键的决定:

  • 我们期待来自世界各地的数百万日活跃用户(DAU)。
  • *均来说,每条消息大约有几百个字符。每个人每天发送几百条信息。
  • 有些团体只有几个人,有些团体有数百名成员

根据以上数字,我们可以得出以下结论:

  • 可以肯定地说,我们需要一个全球分布的系统(为不同地区的用户服务)。用户将连接到不同的服务器。
  • 后端数据库应该是可水*扩展的,因为每天都会保存大量的邮件(大约 100 GB)。
  • 该系统的写入量很大,因为消息被写入数据库,但很少被读取(大多数消息是通过通知服务传递的,并保存在客户端的本地。我们将在后面看到原因)

2.高层设计

2.1.数据库设计

说到数据库设计,考虑应用程序的访问模式总是一个好主意。

读取操作

  • 给定用户 A 和用户 B,检索特定时间戳之后的消息
  • 给定组 G,检索某个时间戳之后的所有消息
  • 给定组 G,查找所有成员 ID
  • 给定用户 A,查找他/她加入的所有组

写操作

  • 保存用户 A 和用户 B 之间的消息
  • 保存 G 组中用户 A 的新消息
  • 在组 G 中添加/删除用户 A

在我们的例子中,很明显,数据库主要用作键值存储。不需要复杂的关系操作,如 join。除了访问模式之外,请记住,数据库必须是水*可伸缩的,并且针对写入进行了调整。

在我们的例子中,我们可以使用 Cassandra 这样的 NoSQL 数据库或者 Postgres 这样的分片 SQL(如果您不关心关系或外键约束,SQL 也是非常可伸缩的)。在实践中,许多公司(如 Discord)使用 Cassandra,因为它容易扩展,更适合写繁重的工作(Cassandra 使用 LSTM,而不是 SQL 使用的 B+树)。关于更详细的讨论,我建议你参考这篇很棒的帖子。

模式

在 Cassandra 中,记录由分区键分割。在每个节点上,具有相同分区键的记录按排序键排序。聊天表的设计最适合我们的访问模式。

图一。私人聊天表,按作者分类

图二。群聊表,按作者分类

这里的一个关键观察是消息 ID 用于确定排序。消息 Id 是而不是全局唯一的,因为它的范围是由分区键决定的。系统永远不会只通过邮件 ID 来检索邮件。

然而,分布式数据库不太支持自动增量密钥生成。我们可以使用专门的密钥生成服务,例如 Twitter 的雪花 ID ,或者简单地使用一个精确的时间戳作为消息 ID(是的,时钟偏差可能会发生,但是一个组中/两个用户之间的消息量可能很小,通过仔细的时间同步可以忽略这一点)

图 3。成员表,按作者分列

我们需要两个表来捕捉用户和组之间的关系。组成员表用于消息广播——我们需要确定谁收到了消息。用户成员表用于列出用户加入的所有组。我们可以使用带有二级索引的单个表,但是组 ID/用户 ID 的基数对于二级索引来说太大了。两个表的方法也不是没有问题——如果我们改变一个,另一个应该被修改以保持一致性,这需要分布式事务。

图 4。用户概况表,按作者分列

最后,用户配置文件表。它跟踪用户特定的数据,如个人资料图片位置和其他东西。

2.2.API 设计

在系统设计面试中,预先制定系统的 API 总是一个好主意。它有助于您将实现的功能形式化,并展示您的严谨思维。

我们系统的需求可以分解为以下 RPC 调用:

send_message(user_id, receiver_id, channel_type, message)
get_messages(user_id, user_id2, channel_type, earliest_message_id)
join_group(user_id, group_id)
leave_group(user_id, group_id)
get_all_group(user_id)
// ignore RPC for login/logout, ignore authentication token 
  • channel_type 字段用于区分私聊和群聊。
  • receiver_id /user_id2 可以是用户 id 或群组 id。
  • earliest_message_id 是客户端本地可用的最新消息。它被用作范围查询聊天表的排序关键字。

2.3.体系结构

最后,是时候进行建筑设计了!到目前为止,我们已经为应用程序打下了坚实的基础——数据库模式、RPC 调用。记住所有这些,我们可以继续写下系统中的组件列表。

  • 聊天服务:每个在线用户在聊天服务中维护一个与 WebSocket 服务器的 WebSocket 连接。传出和传入的聊天消息在这里交换。
  • Web 服务:它处理除了 send_message()之外的所有 RPC 调用。用户使用该服务进行身份验证、加入/离开群组等。这里不需要 WebSocket,因为所有的调用都是客户端发起的,都是基于 HTTP 的。
  • 通知服务:当用户离线时,消息被推送到外部手机厂商的通知服务器(例如苹果的)
  • 在线状态服务:当用户输入或改变状态时,在线状态服务负责确定谁获得推送更新。
  • 用户地图服务:我们的聊天服务是全球性的。我们需要跟踪用户会话主机的服务器 ID。

图 5。高层建筑,作者图

注意,图 5 中省略了 ID 生成服务。

2.4 数据流

正常消息传递

当用户发出一条消息时,它被传递到同一地区的 WebSocket 服务器。WebSocket 服务器会将消息写入数据库并确认客户端。如果接收者是另一个用户,她的 WebSocket 服务 ID 是通过调用用户映射服务获得的。一旦消息被转发到适当的服务器,接收者将通过 WebSocket 获得推送消息。

图 6。正常消息传递,按作者分类

消息传递失败

如果由于某种原因 WebSocket 被切断,用户无法联系到,所有消息将被重定向到通知服务,以便尽最大努力传递(不能保证传递,因为用户可能没有互联网连接)。

图 7。失败的消息传递,按作者统计

历史赶超

即使使用 duo 消息传递系统,客户端也可能永远收不到消息。因此,所有客户端在重新连接时/以固定的时间间隔请求网关服务以获得权威聊天历史记录是至关重要的。

图 8。历史追赶,按作者分类

群聊

当用户参加群聊时,他的消息被广播给所有的群成员。给定一个组 ID,WebSocket 服务器查询数据库,将消息转发给其他服务器。

图 9。群聊,作者图

存在检测

当用户在应用程序中活跃时,Slack 等应用程序会通知其他用户你的状态。我们可以把这个信号作为一种特殊形式的群聊来处理。WebSocket 服务器不是查询数据库,而是联系呈现服务,呈现服务返回用于广播的联系人列表。因为通知曾经与用户聊天的每个人的成本非常高,所以存在服务运行某种算法(可能基于聊天频率、最*的交流等)来保持列表简短和精确。

图 10。存在检测,按作者分类

对于不太频繁的联系,可以通过轮询存在服务而不是等待推送消息来获得用户的状态。

打字指示

逻辑上,打字指示信息和普通信息没有区别。我们可以以与私人聊天消息相同的方式传播打字指示消息(图 6)。

3.细节

到目前为止,我们已经建立了一个清晰的架构和具体的数据流,涵盖了所有的功能需求。然而,面试官会问你很多问题。在这一部分,我想谈谈面试官可能会问你的一些有趣的权衡。

3.1.Web 套接字服务器之间的通信

第一个问题是 web socket 服务器如何相互通信(图 6 中的步骤 5)。最简单的方法是对每条消息使用单独的同步 HTTP 调用。然而,出现了两个问题:

  1. 没有消息排序:如果两个消息按顺序发送,那么第一个消息到达的时间可能会非常晚。在用户看来,在你刚刚阅读的最新消息上方会弹出一条未读消息,这是非常令人困惑的。
  2. 每秒大量的请求:如果每条消息都通过单独的 HTTP 调用发送,那么入口流量可能会淹没 web socket 服务器。

一个可能的解决方案是使用队列作为中间件。每个服务器都有一个专用的传入队列,作为缓冲区并对消息进行排序。

图 11。作为中间件的队列。按作者分列的数字

虽然看起来队列是一个更好的解决方案,但我认为它本身就是一个魔鬼:

  • 对于 Slack 这样的大型应用,web socket 服务器有上万台。维护和扩展中间件是昂贵的,而且本身就是一个挑战。
  • 如果消费者(web socket 服务器)关闭,我们不希望消息在队列中堆积,因为用户将重新连接到不同的服务器并启动历史记录。服务器总是来来去去,用它们创建/清除队列是很费力的。
  • 如果消费者重新加入,我们应该如何处理队列中的陈旧消息?哪些消息要丢弃,哪些要处理?

在这里,我提出了第三种基于同步 HTTP 调用的方法:

为了解决排序问题,我们可以用一个 prevMsgID 字段来注释每条消息。接收者检查他的本地日志,并在发现不一致时启动历史记录。

图 12。无序检测,按作者分类

为了减少服务器之间交换的消息数量,我们可以在 WebSocket 服务器上实现一些缓冲算法——发送累积的消息,比如说,大约 50 毫秒的随机偏移(防止每个人同时发送消息)。

3.2.处理群聊

目前的设计是广播所有的群组信息,而不管群组大小。如果组非常大,这种方法就不太适用。理论上,有两种处理群聊的方法——推和拉:

  • 推送:消息被广播到其他 web 套接字服务器,然后这些服务器将消息推送到客户端
  • 拉取:客户端向 HTTP 服务器发送请求,获取最新的消息。

推送的问题在于,它将一个外部请求(一条消息)转换成许多内部消息。这叫做写放大。如果群组很大并且很活跃,推送群组消息将占用大量带宽。

拉取的问题是一条消息被不同的客户端反复读取(读取放大)。采用这种方法肯定会使数据库不堪重负。

图 13。混合群聊处理,作者图

我的想法是,我们可以用上面的逻辑建立一个混合系统。对于较小的组或非活动组,可以进行推送,因为写入放大不会给服务器带来压力。对于非常活跃的大型组,客户端必须定期向 HTTP 服务器查询消息。

3.3.Web Socket 服务器和数据库

当 web socket 服务器收到消息时,它会被持久化到数据库中。最简单的方法是直接调用数据库。通过这种实现,数据库受到大约 100K RPS 流量的冲击,这需要大量的基础设施。

另一种方法是使用队列进行批量插入。当队列服务收到一个写请求时,web socket 服务器会依次确认客户端。在队列的另一端,一个专门的批处理编写器可以将数百条消息组合成一个请求,从而大大减少了 RPS。

图 14。中间件的问题,按作者分类

但是,使用 Kafka 之类的队列确实会在服务器 ACK 和实际写入之间引入延迟。如果客户端在收到来自 web socket 服务器的 ACK 后立即查询 HTTP 服务器,则可能消息尚未写入。使用中间件,很难提供写后读的一致性,而这对于某些应用程序可能是重要的。

4.摘要

在本文中,我们提出了 Slack 的高级架构,定义了系统 API 和数据库模式。此外,当更仔细地检查系统时,我们探索了许多重要的权衡。在系统设计面试中,没有完美的答案。所有的解决方案都有缺陷,我们的工作是评估每一个方案,并选择最简单的一个满足所有要求。

使用 Python 中的这个简单技巧赢得下一次面试

原文:https://towardsdatascience.com/ace-your-next-interview-using-this-simple-trick-in-python-6994b2198c9f?source=collection_archive---------32-----------------------

借助几行代码,减少焦虑,自信地参加任何面试。

来自 Unsplash 的照片由粘土银行

焦虑,不安,紧张,恶心。这些都是我在进入房间进行一次改变人生的面试之前感觉到的…我确信我不是唯一一个。

我相信每个人都讨厌面试,原因是你不知道面试会是什么样,你会被问到什么问题,而且这往往是你第一次看到招聘人员的脸。

不确定的事情太多了,这种不确定性会让你焦虑、不安、紧张,甚至反胃。

不要像这里的 BMO 一样焦虑

我是一个经常焦虑的人,因为我讨厌不确定性,我觉得我必须控制一切,因此我讨厌面试。

但实际上,我已经找到了一种方法,可以在面试中使用 python 中的几行代码收回一些控制权。

玻璃门

Glassdoor 是一个网站,现任和前任员工可以匿名评论公司。更进一步,这些员工可以讨论面试过程和他们被问到的问题。

看看这个帖子,它是由面试脸书数据科学家职位的人提交的。

你可以看到他们在 2020 年 11 月参加了面试,他们讨论了面试过程中的各种利弊以及我们感兴趣的问题,他们被问到的问题

这只是脸书大学数百个数据科学家职位中的一个。Glassdoor 的伟大之处在于,你可以搜索任何公司的任何职位的确切职位。

通过分析特定公司的数百份特定职位的职位,我们可以找出面试中被问得最多的问题,从而消除一些不确定性。

显然,手动浏览数百个帖子是毫无意义的,所以为什么不让速度成倍增长的计算机来做呢?

让电脑来做脏活

这就是编码和 python 的威力所在,但实际上它是通过利用两个概念来工作的。

1.网页抓取

你知道吗,每当你在网上阅读时,你的阅读数据?对你来说,这可能只是几个词,但在后台,你在网上读到的一切都可以被拿走,被拆开,被操纵。

这就是网络抓取,通过编写一些代码,我们可以获取 Glassdoor 上与帖子相关的数据,并将它们放入 python。

网络抓取的好处是只需要几秒钟就可以收集到数百条数据。

2.自然语言处理

现在我已经用 python 写好了所有的帖子,我使用了一点(NLP)或自然语言处理。

这听起来很复杂,但我向你保证我所做的事情并不复杂,我会尽量解释清楚

简单来说,我所做的就是创建一个单词字典。

我写了一段代码,逐字逐句地检查我们从网上搜集的每个帖子的面试问题。然后,这些单词将被添加到字典中,并计算该特定单词出现的次数。

例如,在下面的段落中,单词 confirmation 出现了两次,所以计数为 2。

(这是脸书问的一个实际面试问题)

给定两个表,一个包含脸书发送确认消息的电话号码,另一个包含确认验证的电话号码,编写一个 SQL 查询来计算确认百分比。

通过创建单词词典,我们可以找出哪些单词和短语最常出现,从而确定哪些问题最有可能被问到。

让我给你看一个例子,这样你会有更好的想法。

脸书大学的数据科学家

假设我有一个脸书数据科学家的面试。我会去 Glassdoor 搜索职位和公司。

当我搜索它的时候,我可以看到有 289 个帖子是关于那些在脸书做了这个采访并且在 Glassdoor 上讨论了这个采访的人的。

我接下来要做的是运行我的 web 抓取代码,将这些帖子的面试问题导入 python。

一旦我收集了所有的问题,我会在我的字典里搜索所有的单词和短语。

最后,我列出了所有这些面试中最常用的词,我对最有可能被问到的问题有了一个很好的想法。

让我们来看看在脸书大学的数据科学家面试中最常用的 3 个单词和短语,这样你就可以知道这对你的面试有什么帮助了。

1.结构化查询语言

在我搜集的所有采访中,SQL 是出现频率最高的词。这可能意味着脸书非常重视他们的数据科学家职位对 SQL 的了解。

更进一步,当我查看包含 SQL 的具体问题时,大多数都是基于真实的脸书案例,就好像他们在告诉你这正是你在工作中要做的工作。

让我们看看在这些访谈中被问到的一些真实的 SQL 问题:

  • 提供一个包含 user_id 和他们访问*台的日期的表,编写一个 SQL 查询,查找截至昨天连续访问*台时间最长的前 100 名用户。
  • 给定两个表,一个包含脸书发送确认消息的电话号码,另一个包含确认验证的电话号码,编写一个 SQL 查询来计算确认百分比
  • 给定一个包含不同类型的详细客户投诉单的表,使用 SQL 计算每种类型中已处理单的份额。

2.可能性

在所有的采访中,第二个最常出现的词是概率。这再次潜在地意味着脸书强调他们的数据科学家要知道概率。因此,回去读一些大学/学院的概率课本可能是个好主意。

这些访谈中提出的概率问题示例如下:

  • 脸书雇佣了评级机构来给广告评级。80%是仔细评级,将 60%的广告评级为好,40%为坏,20%是懒惰评级,将 100%的广告评级为好。广告被评为好广告的概率有多大
  • 三只蚂蚁坐在等边三角形的三个角上。每只蚂蚁随机选择一个方向,开始沿着三角形的边移动。没有蚂蚁相撞的概率是多少?
  • 从一副洗好的 52 张牌中抽出一张不同颜色或形状的牌的概率是多少?

3.你如何决定一个产品的成功

这个短语是迄今为止被问到的最具体的重复出现的问题。SQL 和 Probability 出现得最多,但它们只是在不同问题中出现的单个单词。

“你如何决定一个产品的成功”这句话反复出现。

因此,如果你有机会面试脸书大学的数据科学家职位,得到这个问题的答案将对你最有利,因为你现在知道这个问题以前已经被别人问过多次了。

这会帮助你在面试中胜出吗…

老实说,运行我的代码并找出最常出现的问题并不能保证你得到一份工作,但这真的不是我写这段代码的原因。

正如我在介绍中所说的,我在面试时会非常焦虑,我相信你也一样。这种焦虑会一直存在,但是有办法减少它。

我发现通过了解和研究以前问的问题确实有助于减少我的焦虑,这就是我编写这个代码的原因。

所以如果我留给你什么的话,那就是面试对每个人来说都是可怕的,但是在这里或那里的小技巧的帮助下,我们可以鼓起勇气自信地去参加任何面试。

访问我在本文中使用的代码

如果你想获得我在这篇文章中描述的代码的完全清理和评论版本,你可以加入我的群 "Clean Code Z" ,通过加入你将获得我在所有文章和视频中使用的代码的清理版本。

感受感受加入这里: 洁码 Z

利用强化学习和模仿学习实现 QWOP 中的超人性能

原文:https://towardsdatascience.com/achieving-human-level-performance-in-qwop-using-reinforcement-learning-and-imitation-learning-81b0a9bbac96?source=collection_archive---------13-----------------------

思想和理论

这个游戏难度惊人,显示了人类运动的复杂性。

特工苦练!来自 QWOP 的游戏。(图片由作者提供)

介绍

QWOP 是一款简单的跑步游戏,玩家用 4 个按钮控制布娃娃的下半身关节。这个游戏难度惊人,显示了人类运动的复杂性。使用机器学习技术,我能够训练一个人工智能机器人像人一样跑,并达到 47 秒的完成时间,这是一项新的世界纪录。本文介绍了一般的方法以及培训过程。非常感谢 Kurodo ( @cld_el ),世界顶级速度赛跑运动员之一,捐赠编码的比赛录音来帮助训练代理人。

环境

第一步是将 QWOP 连接到 AI 代理,以便它可以与游戏交互。为了检索游戏状态,我编写了一个 Javascript 适配器,从游戏引擎中提取关键变量,并使它们可以从外部访问。然后使用 Selenium 读取 Python 中的游戏变量,并将按键发送到浏览器。

环境设置。游戏截图来自 QWOP 。(图片由作者提供)

接下来,游戏被包装在 OpenAI gym 风格的环境中,该环境定义了状态空间、动作空间和奖励函数。该状态包括每个身体部分和关节的位置、速度和角度。动作空间由 11 个可能的动作组成:4 个 QWOP 按钮中的每一个,6 个双按钮组合,以及没有按键。

方法

第一个代理的学习算法是带有经验回放的演员评论家(ACER)。这种强化学习算法结合了 A2C(Advantage Actor-critical)和重放缓冲器,用于策略上和策略外学习。这意味着代理不仅从最*的经验中学习,还从存储在内存中的旧经验中学习。这使得宏碁比其仅在保单上的同行更具样本效率(即学习速度更快)。

为了解决偏离策略估计器的不稳定性,它使用回描值估计、重要性权重截断和有效的信赖域策略优化。更多细节参考原论文。

宏学习离散动作的步伪码。摘自 宏基论文

与大多数 RL 算法相比,ACER 相当复杂,所以我使用稳定基线实现,而不是自己编码。稳定的基线还提供了定制环境集成和预培训功能,这在后来被证明是非常有价值的。

底层神经网络由 256 个和 128 个节点的两个隐藏层组成,全部与 ReLU 激活完全连接。下图说明了网络如何吸收游戏状态并产生候选动作。

说明:强化学习代理神经网络架构。动作在训练期间被采样,但是在测试期间可以被确定。(图片由作者提供)

整个架构稍微复杂一点,包含更多网络输出,包括一个 Q 值估计器。

在代理的第二次迭代中,优先化的 DDQN⁷用于完善运行技术和优化速度。该算法将 DQN 与许多特征相结合,以稳定和加速偏离策略的学习。该代理使用与 ACER one 相同的网络结构和激活功能。

优先级 DDQN 伪代码。摘自 每文

培养

初步试验

我第一次尝试完全通过自我表演来训练代理人。我希望这个代理可以学习表演人类运动,就像 DeepMind 在穆乔科·environments⁴.中所做的那样然而,经过多次尝试后,我注意到它学会跑完 100 米的唯一方法是“擦膝盖”这与之前用机器学习解决 QWOP 的许多尝试是一致的。

AI 通过膝盖刮擦学习完成。从 QWOP 重新编码。

代理根本没有发现步幅机制,而是学习最安全和最慢的方法到达终点线。

学习大步走

然后,我试着亲自向代理教授大步的概念。这类似于 DeepMind 在最初的 AlphaGo⁴中使用的方法,在自我游戏之前,代理首先被训练模仿顶级玩家。然而,当时我不认识任何顶级玩家,所以我试图自己学习这个游戏。不幸的是,我在这项运动中相当糟糕,经过一天的练习,我只能跑大约 28 米。

虽然我弹得很差,但我仍然像人类一样使用腿。我想也许代理人可以从那个机械师那里得到一些信号。所以我录了 50 集我*庸的戏,编码了,喂给经纪人。不出所料,结果相当糟糕——代理理解 stride 的想法,但不知道如何应用它。

艾试图模仿我的跨步动作。改编自 QWOP 。

然后,我让代理自己训练,看看它是否能利用新技术。令我惊讶的是,它竟然学会了像人类一样大步行走和奔跑!经过 90 个小时的自我训练,它能够以不错的速度跑完比赛,并以 1 分 25 秒的成绩完成比赛,这是前 15 名的速度跑,但离冠军还差得很远。

AI 终于学会大步走了。改编自 QWOP 。

这位经纪人并没有发现所有速度最快的跑步者都使用的一种特殊技术:向上和向前摆动双腿以创造额外的动力。我想向人工智能展示这一技术,但我自己肯定不够熟练来演示,所以我寻求帮助。

学习高级技术

Kurodo ( @cld_el )是世界上最顶尖的 QWOP 速度赛跑运动员之一,他非常慷慨地录制并编码了 50 集他的比赛,供我的经纪人学习。我第一次尝试像以前一样进行有监督的预训练,但结果并不理想。代理不能立即利用数据,然后很快忘记/覆盖训练前的体验。

然后,我尝试将这种体验直接注入宏碁重放缓冲区,进行非政策学习。代理人的一半记忆是他玩过的游戏,另一半是 Kurodo 的经历。这种方法有点类似于从演示中进行深度 q 学习(DQfD)⁶,除了我们没有在开始时添加所有的演示,我们以与真实体验相同的速度添加演示。行为政策 ( |s) 也必须包含在每次注射中。虽然这个方案没有什么理论基础,但效果却出奇的好。

艾学习高级摆腿技术。从 QWOP 重新编码。

但是,代理的策略(操作)过一段时间后会变得不稳定,因为它无法使外部数据与其自己的策略完全一致。此时,我从它的内存中删除了专家数据,让它自己继续训练。最终的代理有如下的训练时间表:预训练,25 个小时自己,15 个小时用 Kurodo 的数据,另外 25 个小时自己。这个代理的最好记录是 1 米 8 秒,这是前 10 名的速度跑。

优化速度

现在代理掌握了正确的技术,我创建了一个新的代理,只是为了提高速度。我记录了宏碁代理的运行,并将其提供给一个新的优先 DDQN⁷代理。选择这种 DQN 变体是因为它的样本效率更高,因此可以快速优化宏碁已经学会的技术。

奖励函数也被修改了。以前它有一些惩罚措施,包括对躯干高度低、躯干垂直运动和膝盖过度弯曲的惩罚。当代理刚刚学习大步,这些有助于稳定其运行技术。但现在它知道如何大步前进,我把训练轮拿掉,让它纯粹为了前进速度而优化。

训练和测试的有效帧速率分别从之前的 9 提高到 18 和 25,这样代理可以做出更精确的动作。新代理首先接受宏碁 runs 的预培训,然后通过自学进行改进。它没有像宏碁那样用 Kurodo 的数据进行混合记忆训练。它总共接受了 40 个小时的训练,除了几分钟的预训练外,所有的训练都是自学。

结果

最终代理的最佳记录是 47.34 秒(见下图),比人类的最佳记录( 48.34 秒)还要快。随着这一点,QWOP 被添加到 AI 已经超越人类的游戏列表中。

47.34 秒的世界纪录。

链接

  • 第一代理视频摘要:【https://youtu.be/-0WQnwNFqJM
  • 第二代理视频摘要:【https://youtu.be/82sTpO_EpEc
  • Github 库:https://github.com/Wesleyliao/QWOP-RL

文章于 3/6/21 更新,介绍新的 DQN 车型和世界纪录。

参考

  1. QWOP (Foddy,2008)
    http://www.foddy.net/Athletics.html

  2. 样本高效影评人带经验回放(王等,2017)

  3. 稳定基线(希尔等人,2018)
    https://github.com/hill-a/stable-baselines

  4. 丰富环境中运动行为的出现(Heess 等人,2017)
    https://arxiv.org/pdf/1707.02286.pdf

  5. 用深度神经网络和树搜索掌握围棋游戏(Silver et al .,2016)
    https://doi.org/10.1038/nature16961

  6. 深度 Q-从示范中学习(Hester 等人,2017)【https://arxiv.org/pdf/1704.03732.pdf

  7. 优先体验回放
    https://arxiv.org/pdf/1511.05952.pdf

用神经网络实现真实感

原文:https://towardsdatascience.com/achieving-photorealism-with-neural-networks-f80ded1b4cdb?source=collection_archive---------42-----------------------

使用来自 GTA V 的合成数据

在研究领域,特别是在处理图像时,人们对使用流行的游戏环境越来越感兴趣,例如用于实验的侠盗猎车手(GTA)、。有了今天的高质量图形,这些环境产生了与现实生活相似的合成图像,使研究人员能够测试他们解决复杂问题的方法,如[这个](http://Domain Adaptation for Traffic Density Estimation),其数据集仍处于萌芽状态。

照片由 Josue Michel 在 Unsplash 上拍摄

为了进一步弥合这一差距,Vladlen Koltun 和他的团队在城里推出了一项新的工作,让合成图像更加逼真,他们称之为增强真实感增强。我们看到 GTA V cityscape 的使用证明了该方法如何神奇地将游戏中的视频片段转换为看起来像是用 dash 相机拍摄的翻译。

让我们来看看增强剂的结果。下图是由游戏生成的原始合成图像。它确实有那种游戏合成的感觉。这是在没有任何增强器的情况下,从游戏引擎获得的渲染。虽然这仍然可以用作实验的测试场,但它不能保证在真实环境中重现结果。

来自 GTA V [1]的原始图像

现在让我们看看由增强剂流产生的一个。人们很容易把这个和真的混淆。它看起来确实比上一部有点沉闷,但却更加真实。

增强图像的真实感[1]

起初,这可能看起来像一个简单的策略,但它有很多内容,使这项工作非常新颖。

幕后

从广义上讲,这种增强器是一种卷积神经网络(CNN ),它以所需的间隔生成增强帧。然后,它试图将原始帧转换成 Cityscapes 数据集的样式,该数据集拥有 dash 相机记录的大量德国城市。

有趣的一点是,网络不只是使用完全渲染的图像(由游戏引擎)作为输入。游戏引擎产生了 G 缓冲区,这是一种中间缓冲区,提供场景的详细信息,如几何,材质和照明。如下图所示,除了渲染图像之外,增强网络还以多种比例使用这些辅助输入。

增强流程[1]

在将 G-buffer 信息传递到增强网络之前,有一个额外的编码器网络来完成编码。使用 LPIPS loss,训练这两个网络,其保留了渲染图像的结构和感知辨别,以最大化增强图像的真实性。

基于输入的图像,该网络可以给汽车增加光泽,铺*道路,并做出其他类似的改变。这种方法获得的稳定性几乎没有任何伪影,这使得这种新方法成为所有现有方法中最好的,下面的视频中可以看到两者的比较。

增强真实感增强

前方是什么

机器视觉研究的一个痛点是拥有一个为问题陈述量身定制的数据集。由于缺乏高质量的数据集,作者求助于标准数据集,这可能经常低估或少报工作的潜力。如上所述的策略可以引发一个新的维度,其中可以使用模拟环境(如游戏)基于需求生成模拟数据集。在赛场上运行任何新的基于视觉的自动驾驶算法之前,它可以在增强型 GTA V 等模拟上快速运行,以找到缺陷并报告结果。因此,人们可以加快测试速度并创建您需要的数据集,这非常棒。在不久的将来,为许多这样的作品做好准备吧!

我希望你喜欢阅读斯蒂芬·里希特、哈桑·阿布·阿尔海贾和弗拉德伦·科尔顿的这篇文章。如果你对这个新策略的细节感兴趣,别忘了查看全文。要查看这项工作的更多对比结果,请点击此链接。

[1] Richter,Stephan R .,Hassan Abu AlHaija 和 Vladlen Koltun。“增强照片真实感增强。”arXiv 预印本 arXiv:2105.04619 (2021)

用 D-Wave 实现超级数独的量子优势

原文:https://towardsdatascience.com/achieving-quantum-advantage-at-solving-super-sudokus-with-d-wave-a7d2ae97d534?source=collection_archive---------25-----------------------

数独,人类,经典和量子计算机

图 1:D 波退火量子计算机的中心部分,在这张图片中没有冷却到 15 mK。由 D-Wave 提供的媒体。

数独,人类,经典和量子计算机

数独是谜题有些人喜欢手动解决。这是一个 9x9(或(33)(3*3))的难题,在每个方块中,你应该填写从 1 到 9 的数字。每行和每列以及每个标记的 3×3 子方块只能包含 1 到 9 中的每个数字一次。

最训练有素的人通过反复试验,或者用计算机科学术语来说,通过回溯算法,在几分钟内解决 9x9 版本。

有些人更喜欢让计算机解决数独。然而,计算机发现传统的(33)(33)数独简单得可笑。使用传统的混合整数规划方法,这些问题通常在大约 15 毫秒内解决。为了增加挑战,我们考虑了更大的(n * n)(n * n)n > = 4、“超级”或“元”数独。当 n 变大时,(nn)(n*n)以快得多的速度变大。所以在 n 点,大约 6,7,8 台经典计算机开始挣扎,这意味着它们需要几个小时或几天来解决这样一个数独。

图二。一个 99 (=(33) * (33))的数独游戏是为人类设计的,让他们可以玩几分钟。在 15 毫秒的典型求解时间内,它对经典计算机来说没有挑战,所以我们大幅增加它们的规模,就像这个(77) * (7*7)超级数独,然后让经典和量子计算机工作来解决它们。

这是量子计算机可能表现更好的地方。

研究这个问题是本文的主题。

什么是量子计算?

多亏了量子现象(1) 叠加 (不像经典比特在任何时候要么是 1 要么是 0,一个量子比特或者量子比特可以同时有两种状态(对,就是很奇怪!))和(2) 纠缠 (远距离的多个量子比特可以同时保证相同或相反的状态(‘幽灵般的远距离作用’爱因斯坦说,是的,又怪异了!)),量子计算机可以一次尝试多个潜在的解决方案,因此可以比经典计算机更快,因为经典计算机必须依次尝试每个解决方案。

量子计算理论到此为止。但是它已经在实践中得到证明了吗?你可以在这里阅读和这里关于“量子优势”这个问题的答案更谦虚地称为“量子优势”仍然存在争议。

为什么是数独?

为了让经典计算机和量子计算机在一个具体的问题上进行比较,我们采用了数独难题,因为(1)它是最广为人知的优化问题,( 2)它很容易放大到任意大的和任意难的版本,因此无论是经典系统还是量子系统,如果存在优势,都可以放大到任意大的比例。

以自动化甚至最快的方式解决数独游戏,对于整个世界来说,尽管有很多严重的问题,看起来可能是徒劳的。然而,数独只是被称为“优化问题”(更具体地说,混合整数规划或 MIP 问题)的一大类问题中的一个例子。在那个类中,存在更多实际相关的问题,像供应链优化问题、列车时刻表优化问题、护士调度问题、自动化能源市场交易问题等等。今天,在经典计算机上解决这些问题可能需要几个小时或几天的时间,因此妨碍了它们的实时应用,并且消耗大量的电力。一些人认为,很快,或者今天已经,量子计算机可以在解决这些问题时节省时间和精力。

现在让我们开始我们的挑战。

1.我们在经典电脑上解决了超级数独

如前所述,对于经典的 MIP 方法,随着 n 变大,求解时间迅速增加。使用的模型和我们获得的计算时间,在 2020 年 3 月的这篇文章中报告,对于[1,..7].我们重新做了实验,现在对[1,..8],MIP 解算器 Gurobi 的更新版本为 v9.1.0。新体验的解算器时间如下表 1 所示。

表 1:我们在经典计算机上从 Gurobi MIP 模型实现中得到的每个数独案例的计算时间。1e99 代表还没有结果。模型构建时间很短。模型求解时间占优势。阶段时间是两者的总和,所以总持续时间。上半部分显示没有任何预填充方块的案例,而下半部分显示有一些预填充方块的案例。这些计算时间将与下表 2 中 D-Wave 量子退火机上的计算时间进行比较。我们在两个系统上运行了相同的案例。

表 1 的上半部分显示了没有任何方块具有预设值的数独。因此求解器具有最大的自由度,并且可以避免由于“特别难/容易的*方值选择”而导致的任何偶然的经典与量子偏差。

在 MIP 模型中,解算器必须决定 n⁶比特的 0 或 1 值,并且还必须注意满足 4 种类型的约束,其中每一种都出现 n⁴时间。(见下文的模型变量和约束将使这一点变得清楚。)这就是为什么 solve_model 列的时间随着 n 的增加而快速增加的原因。

表 1 的下半部分报告了相同大小的数独的计算时间,但是有些方块有预先填充的值。与上面没有预设值相比,这有时更难(例如,对于 n=6),但有时更容易(例如,对于 n=7),有时极其困难。是的,80 小时后还没有结果,而对于没有预先填充方块的情况,n=8 只需要 6s,没有报告错误!

2.我们在量子计算机上解决了超级数独

我们参加了 IBM 的量子计算课程和 D-Wave 的课程,D-Wave 的硬件(和软件)实现套件显然看起来最有前景,主要因素是 D-Wave 芯片使用量子退火模型,包含多达 5000 个量子位,而 IBM、谷歌和其他使用量子门模型的量子计算机大约为 50 到 60 个量子位。

然后,我们环顾四周,看是否有人在我们之前解决过元数独问题,有几个人解决过。

2.0 以前的工作与我们在这里的工作

2.0.1 来自 D-Wave 的在线代码:适用于大小为(33)(3*3)的数独游戏

D-Wave 本身已经在https://github.com/dwave-examples/sudoku在线发布了代码。我们对此进行了测试,它正确地解决了提供的 problem.txt 文件中给出的一个(33)(33)数独案例。代码的编写方式依赖于参数 n,所以理论上可以求解任意(nn)(nn)个数独。然而,当我们对 n > 3 进行测试时,它总是返回无效的解决方案。

2.0.2 文章解释了在大小为(22)(2*2)的数独游戏上与经典模拟退火相比的量子优势

在https://towardsdatascience . com/solving-sudoku-with-a-quantum-power-up-5b B4 f 64 f 3944上,Julian Hatski 描述了在 D-Wave 纯量子(因此 QPU,和非混合)机器上的量子退火如何比在(22)(22)数独上的某个经典模拟退火算法快大约 5 倍。他和我们一样,体验到标准的(33)(33)数独还不能自动嵌入 QPU。

2.0.3.展示 4x4 数独实验的文章

Eyan Fosythe 的这篇中型文章解释了如何用基于门模型的量子计算机来解决一个有 16 个方格的数独(因此是(22)(2*2)个方格)。返回的解决方案并不总是有效的,并且由于基于该模型的量子计算机中缺乏更多的量子位,将它扩展到更大的数独目前是不可能的。Eyan 提到,具有 m 个未定方格的数独的经典复杂度是 O(N^m 阶,并且一个重要的理论结果是,量子计算已经被证明的复杂度是 o 阶(log(n)),因此证明了指数加速。注意,它根本不依赖于 m!学术出版物此处和此处显示了最多 16 个方格的棋盘的相同实际结果。

2.0.4 本文:与 MIP Gurobi 求解时间相比,按比例增加并使用混合求解器

我们打算将 D-Wave 系统用于更大的数独游戏,最多可达(88)(8*8),并将求解时间与我们在使用混合整数规划(MIP)求解器的经典计算机上得到的结果进行比较。我们使用 Gurobi ,在我们的实验中,它是解决这类问题最快的可用解算器。可能有专门解决数独的算法比 Gurobi 更快得到结果,guro bi 的算法专门解决一般的 MIP 问题,但它们需要大量的开发时间。我们认为从以下观点来看,比较一个普通的量子解算器(用曲波模型)和一个普通的经典解算器(用 MIP 模型)是最公*的。

(1)经典 MIP 模型和量子曲波算法的开发时间差不多(如果用最新的带 add_variable,add_linear_constraint 的 D-Wave 海洋库)。

(2)使用的财务成本是相似的(传统的 1 PC,在 D-Wave 课程期间 10 分钟的“云”量子时间,课程费用为 700 美元)。

(3)所以如果上面的(1)和(2)是相似的,并且求解时间对于量子来说比经典更好,那么就有一个非常实际和具体的量子优势

2.1 将 MIP 约束转换为曲波的目标函数项:一般原则

我们必须将数独 MIP 模型转换成其二次无约束二进制优化(曲波)等价模型形式,这是能够编程一个 d-wave 量子退火机器所需的格式。

执行转换代数

曲波格式只允许一个目标(函数),不像 MIP 模型,不直接允许约束。通过众所周知的拉格朗日乘数原理,约束条件可以转换成目标函数的形式。所以 a 说线性约束 f( b )=c,用bMIP 问题中一些二元变量的一个向量,转换成一个项𝜆 (f( b )-c)。当(f( b )-c)的最小化(因此,f( b )=c)比其他目标函数项的最小化更重要时,𝜆是一个权重,并且可以被选择为高于目标中其他项的值。

当 f( b )在 b 中的每个 b 中是线性的时,很容易求出表达式(f( b )-c)。为了节省时间、精力和避免错误,可以使用 Wolfram Alpha 来完成。例如,约束 b1+b2+b3=1 转换为(b1+b2+b3-1),并且可以通过这个链接由 WolframAlpha 展开。这将返回表达式的扩展形式:B1+B2+B3+2 B1 B2+2 B1 B3+2 B2 B3-2 B1-2 B2-2 B3+1。

现在,因为任何二进制值 b 的*方等于二进制变量 b 本身(因为 1 =1,0 =0),我们可以将此简化为(2 B1 B2+2 B1 B3+2 B2 B3)+(-B1-B2-B3)+1,可以看到这个表达式由二进制变量交叉项中的二次项加上二进制变量中的线性项组成。

一般来说,注意,也可以将 f( b ) ≤ c 形式的不等式约束转换为 f(b)+c’* b’= c,其中 b’是新引入的二元变量,然后可以将其转换为目标函数项(f(b)+c’* b’-c),该目标函数项可以类似于由线性项和叉积项组成的表达式来计算,然后转换为曲波问题

因此,MIP 问题中的任何线性约束都可以在其曲波形式的目标函数中转换成线性和二次项。

2.1.2 构造曲波矩阵

量子计算机需要矩阵形式的曲波。(这实际上类似于 MIP 求解器 API 早期的 MPS 格式。)如果 q 是在曲波问题中使用的量子比特的数量,则曲波矩阵的维数是 q*q。它的对角线包含线性项 bi 的系数,右上三角形包含项 bi bj 的系数,其中 i <j. fact="" one="" can="" also="" supply="" a="" symmetric="" matrix="" where="" the="" i="">j 个元素将在 D 波机器消耗它之前被加到 i</j.>

现在,随着对这种曲波矩阵编码的理解,基于曲波的量子退火计算机的物理工作如下。一般来说,自然界以及量子系统的物理学都力求最小的能量,这对应于最小化目标函数。正的曲波系数希望与该系数的二进制(+bi)或二进制乘积(+bi * bj)为零,因为整个目标表示编码系统的能量,并且将被最小化,而负的系数将使后面的(bi 或 bi * bj)为 1。比其他系数大的系数会比其他系数更努力地推动它们的项。同样地,( 1)单个项(形状为 bi,因此在对角线上)可以被上推或下推,交叉项(bi * bj,非对角线)(表示约束)可以被上推或下推,并且相关的重要性可以被“加权”。

更正式地说,下面表示目标函数的表达式被最小化。

量子退火机器的能量函数,也称为“哈密顿量”。这是“量子自然将为我们最小化的表达。bi 是量子比特(量子比特),cii (ci)是对角线上的曲波元素,cij 是对角线外的曲波矩阵元素。因此,“c”系数构成了“量子程序”,“b”构成了量子比特硬件。

“I”是量子位索引的集合。所以#(I)是问题中的量子比特数,也就是 n⁶.bi 是量子位,其值必须确定。ci 和 cij 是固定系数。曲波矩阵由 ci 和 cij 常数组成,代表编码问题。

请记住,如上所述,MIP 问题中的 MIP 目标和每个约束被转换成一个表达式,该表达式对 cii 和 cij 值有贡献。对于每个表达式,可以选择权重。

可能会出现这样的问题,即对于每个约束,是否总能找到正确的权重,并且似乎已经证明情况并非如此。然而,在实践中,对于相当多的问题,似乎可以通过对这些权重进行一些实验来达到对所有约束的满足。对于没有预先填充方块的 n≤7 的数独游戏,我们发现这在所有约束的所有权重(拉格朗日参数值)都相等的情况下工作得很好。对于具有预先填充的正方形的情况,对于 QPU 上的[1,2]中的 n,我们必须将固定正方形满意度约束的权重设置为比所有其他约束的权重更高的数字,并且对于[3,..7]在混合 D-Wave 系统上。弄清楚这一点需要实验时间,而这是经典 MIP 求解器所不需要的,在经典 MIP 求解器中,约束不需要用户指定的权重。

2.2 将 MIP 约束转换为曲波:数独应用的目标函数项

总的来说,对于 MIP 模型,a #(R)行* #(C)列大小的数独要用 N =[1]中的#(N)个数来填充..#N],其中#N=#R=#C 并且 D=#(S)其中 D =#N:

一个超级数独 MIP 模型,可以在经典计算机上由 Gurobi 等 MIP 求解器直接求解。它需要被转换成 D 波量子退火模型的曲波模型

前 3 个约束共同确保 N 中的每个数字在每行和每列只出现一次。第四个约束强制 N 中每个数字的唯一性,每个子正方形只出现一次。最后一个约束强加了每*方的预设值(如果有的话)。

对于子板约束,在标准数独中,D=3,S=[0,1,2]。

对于预设的正方形,f(r,c)是一个将一些(行,列)索引映射到正方形应该包含的值的函数。不是所有的行和方块都有预设值,因为这太容易解决了。dom(f(r,c))是 f 的定义域,所以我们有预设值的(r,c)对的集合。对于 quantum 版本,模型只包含二进制文件,最后一个约束被省略。用于填充正方形的整数值(n+1)是以经典方式在优化后计算的。

注意,这里 b 的索引仍然是相对简单的公式,因为行和列的偏移量为 0。

对于前 4 个约束,我们可以看到每种类型都有 n⁴(对于经典的 99 数独,n=3),因为#(R)=#(C)=#(N)=#(S)#(S)=n,例如对于第一种类型,我们有#(R)*#(C)=n *n 个约束。因此,除了方形预设约束,我们总共有 4 个 n⁴约束。

我们确实可以看到,利用 2.1 节所述的一般原理,上述所有约束都可以转化为曲波形式。

在以一种非常机械的方式应用了这些规则之后,我们得到了我们的曲波模型,下面的 Python 代码反映了这一点。我们相信,从代码的注释中可以清楚地看到上述应用于数独的过程。

2.3 构建曲波的 Python 代码

下面的代码包含了所有经典和量子解数的函数。

笔记本的开头定义了所有的函数,经典的和量子的。该笔记本包含在接下来的 4 个笔记本中,每个笔记本都运行一系列的数独测试。

参见https://gist . github . com/PeterSels/0ef 625 b 0340598 FDE 4 F2 b 6 F3 A8 e 5d 6的完全可执行(和已执行)笔记本

所有执行的案例分为 4 类:(无/有预设方块)*(有 guro bi/有 D-Wave)。为了保持代码大小和执行时间小且模块化,我们通过命令%run QuantumSudokuLib.py 将这 4 种情况中的每一种放在一个单独的笔记本中,该笔记本包括上面的笔记本。

(1)没有预先填充的方块,古典古罗比:

第一次测试开始-4 的笔记本。

有关测试运行的完整要点,包括代码和测试结果输出,请参见https://gist . github . com/PeterSels/139 f 8477133 c 4604 dcac 8399 e 231788 e。

我们可以运行[1,..8]这里做实验。

(2)没有预先填充的方块,量子 D 波

测试运行的笔记本要点见https://gist . github . com/PeterSels/8364118 A8 F3 d 1275 a 69 eafe 290 ff 1d 96。

在这种情况下,我们可以对[1]中的 n 进行实验..5],但不是重复我们之前运行的[6,7]实验中的 n。我们的量子时间用完了。

但是我们依赖 Python 代码的输出日志(在将它插入笔记本之前)。我们在这里引用这三个日志。如果有足够的时间,笔记本中的代码应该会重新生成类似的结果。

我们的对数为 n=6,没有预设的方格,量子

我们在 GitHub 上发布了整个日志,这样你可以验证它是否正确。总结如下:

(ocean) $ time python helper_functions.py sudokuDim6.json dwave
...
is_correct check done.
Sudoku correctly solved. :)
tests: ['solver'] done
real    22m4.531s
user    0m20.908s
sys     0m2.179s
(ocean) $

因此,从“实际 22m4.531s”中可以看出,对于 n=6,这花费了 22 分钟多一点。“数独正确解决了。😃”表示返回的解经过检查(在传统计算机上)并且确实有效。

我们又做了一次实验,n=6,在 22 分 50 秒内又得到了一个有效解。完整日志显示在 GitHub 的中,包括摘要:

(ocean) $ time python helper_functions.py sudokuDim6.json dwave
...
is_correct check done.
Sudoku correctly solved. :)
tests: ['solver'] done
real    22m20.279s
user    0m23.123s
sys     0m2.560s
(ocean) $

我们的对数为 n=7,没有预设的方格,量子

完整日志在 GitHub 的这里,有摘要:

(ocean) $ time python helper_functions.py sudokuDim7.json dwave
...
Sudoku correctly solved. :)
tests: ['solver'] done
real    44m28.992s
user    1m27.995s
sys     0m7.025s
(ocean) $

所以“真实的 44m28.992s”表示 n=7 用了 44 分半钟。“数独正确解决了。😃”表示返回的解经过检查(在传统计算机上)并且确实有效。

我们还有一个 n=8 的老实验。对于那一个,之后(只!)20 分 50 秒,我们收到了一个来自混合方法的无效数独解。请注意,这不是硬件或软件的错误,但 D-Wave 系统返回的(有时是多个)解是具有低能量的解,但它可能不总是具有绝对最低能量的解,因为量子采样的物理过程是一个随机(因此是非确定性的)过程。具有非绝对最小能量的解对应于这样一个解,其中一些目标函数项而非完全最小化(到零),对应于略微违反约束

解决无效解决方案这一问题的方法是在一次运行中多次读取或重新运行整个过程。然而,我们通过我们的 D-Wave 量子开发人员和培训时间预算来做到这一点。

(3)一些预先填充的方块,古典古罗比:

测试运行的笔记本要点见https://gist . github . com/PeterSels/104002759 f 94 ea 45 C1 DD 8684d 98 f1 d 27。

我们可以运行[1,..7]这里做实验。但是 n=8 的情况甚至在 80 小时后也没有给出结果。

(4)一些预先填充的方块,量子 D 波

测试运行的笔记本要点见https://gist . github . com/PeterSels/ff 076 c 92 e 8d 006 a 95d 4605 ab 818 a 0 ef。

我们可以在[1]中运行 n 个案例..5],但是对于[6,7,8]中的 n,我们账户上的量子时间用完了。

2.4.在 D-Wave 系统上拟合/嵌入曲波

我们的 MIP 模型以及我们的量子曲波模型使用 n⁶ (qu)比特用于(nn)(nn)个正方形的数独。这是因为对于每个方块,我们需要一个介于 1 和 nn 之间的数字。因此,我们为 1 到 nn 中的每个数字 N 构建一个完整的(nn)(nn)数独*面,如果数字 N 被决定出现在最终数独中的那个位置,则该*面在特定的方块中保持布尔设置为真。因此,由于 4⁶ = 4096,一个具有 5000 个量子比特的 QPU 应该能够容纳一个大小为(44)(44)的数独的所有 4096 个量子比特,当然还有一个大小为(33)(33)的数独,这只需要 3⁶ = 729 个量子比特。然而,必须找到问题实例图在 D 波量子芯片图上的嵌入的函数似乎在这方面失败了,这就是为什么我们必须对 n≥3 使用 D 波混合方法。

我们量子数独实验的 2.5 个结果

与经典情况相同范围的数独大小的量子计算时间显示在下表的“D-Wave total (s)”列中。请注意“QPU”(对于纯量子处理单元,对于[1,2]中的 n)和 n≥3 的“混合”方法,其中问题被分解,然后映射到经典和量子计算机的组合。

表 2:我们在 D-Wave 的量子和混合系统上实现的 D-Wave 曲波模型中每个数独案例的计算时间。1e99 代表还没有结果。model_build 时间和 find_embedding 时间很短。模型求解时间占优势。三个阶段的时间是这三列的总和,因此是总持续时间。上半部分显示没有任何预填充方块的案例,而下半部分显示有一些预填充方块的案例。这些计算时间与上表 1 中在传统机器上运行 Gurobi 的时间进行了比较。我们办了同样的案子。

对于 n 的每个值,总 D 波时间是 model_build、find_embedding 和 model_solve 列的总和。最值得注意的是,当 n 值较低时,量子解算器较慢,而当 n ≥ 6 时,量子解算器变得较快。量子计算时间缩减从那里开始。在 n=6 时,我们的时间减少了 31.2%,在 n=7 时,时间减少了 82.9%,这是一个明显而巨大的量子优势

我们报告了一些文件,您可以在下面的表 3 中验证我们获得的结果。

表 3:该表显示了实现它的每个案例的一个或多个文件。所有文件都可以在 GitHub 上找到并下载。

3.经典时间与量子时间的可视化

为了对比例有更好的感觉,我们把我们的结果放到下图的一些图表中。左边的两个图表在垂直轴上具有以秒为单位的线性时间,右边的一对图表在垂直轴上具有对数时间刻度。上半部分代表没有预设方块的数独,下半部分代表有预设方块的数独。蓝色表示经典 MIP Gurobi,红色表示量子/混合曲波 D 波。

图 3:对于每个数独案例,我们展示了经典(蓝色)和量子/混合(红色)之间的计算时间比较。在数独游戏中,上半部分没有预先填充的方块。下半部分预先填充了一些方块。左半部分在垂直轴上具有以秒为单位的线性时间。右半部分在垂直轴上有以秒为单位的时间记录。左上图中 dim=6 和 dim=7 的情况清楚地显示了 31%和 82%的时间节省,这表明实现了量子价值或量子优势。左下部分显示,对于预先填充方块的超级数独,我们还没有取得量子优势,但我们的帐户上缺乏足够的量子计算来完成 n=6 和 n=7 的情况。右半部分仅放在垂直对数刻度上,以便能够放大计算时间短的情况。

在左上角,因为时间是以秒为单位,所以比例保持不变。请注意,当从 n=6 到 n=7 时,变量的数量从 6⁶=46656 到 7⁶=117649 大约增加了 2.5 倍,约束的数量从 4 * 6⁴ =5184 增加到 4 * 7⁴=9604,大约增加了 1.8 倍。所以,不严格地说,我们可以说问题的 复杂度大致上升了一个因子2.5 * 1.8 =4.7

古罗比的求解时间从 6 的 1924 秒到 7 的 15596 秒,增加了 8.1 倍。因此,粗略地说,2 个问题的复杂性加倍导致 3 个在经典系统 上解决时间加倍。

D-Wave 的混合设置解决同样 2 倍问题复杂性的时间从 n=6 的 1324s 到 n=7 的 2669s,所以几乎完全一样 只有 1 个 在量子系统上解决时间加倍

右边的图表显示了对数刻度上的垂直轴,以便在较低的 n 下,在较低的时间内获得更高的分辨率。

注意,不管垂直刻度是以秒为单位还是以对数(秒)为单位,水*轴实际上是被高度压缩的。实际上,考虑一下,如果我们将横轴放在基本问题复杂性方面,我们应该设置一个与#变量#约束成比例的标度~ n⁶ * 4 n⁴,相当于 n ⁰.这将导致一个更加“宽而*”的曲线。*

注意,所报道的 D 波混合时间仍然具有经典计算成分,其可能仍然比它们的量子同胞成分随着 n 的增加而增加得更厉害。拥有一个纯量子设备,其中 n≥8 的数独可以快速嵌入,这将是下一个可以实现的量子数独解决的圣杯!

4.结论

对于超级/元数独问题,D-Wave 纯量子芯片(称为量子处理单元或 QPU)今天拥有多达 5000 个量子位,可以嵌入 n=2 大小的小数独。但是,对于这些小问题,还没有实现的量子优势。

D-Wave 混合方法在经典和量子芯片上分解问题,可以嵌入更大的问题(n≥3),我们可以尝试的两个最大的问题,对于数独维度 6 和 7 确实显示出显著的量子优势(分别为 31.2%和 82.9%)。据我们所知,这是第一次在量子机器上演示元数独。

请注意,寻找问题图在表示量子芯片(或混合系统)的图上的“嵌入”(代码中的函数 find_embedding)是经典的,也需要时间,并且该时间随着大小 n 而增加。随着 n 的增加,希望混合方法的量子子系统不会上升太多或根本不会上升,并且经典时间分量不会支配总时间。

如果我们可以在 D-Wave 机器上安排额外的量子时间,我们就可以在目前的系统上再次尝试 n≥8 的数独。我们也很好奇,当经典的嵌入-寻找功能变得更好(更适合 QPU)时,以及当具有更多量子位的 D-Wave 芯片在不久的将来发布时,会发生什么。

脚注:

  1. 像 Gurobi 这样的经典 MIP 解算器被构造成确定性的。这意味着,如果输入相同并且机器相同(或者等效地,内核数量、线程数量和操作系统相同),它们将总是返回相同的答案(如果可行,则为解决方案)。这并不意味着在选择某个问题实例时,好运气坏运气被排除。例如,在我们的模型上运行 Gurobi v9.1.0,对于一个大小为(88)(88)的数独游戏,在没有任何预填充方块的情况下,我们发现它在 6 秒内全部解决,而没有预填充方块的(77)(77)的较小情况需要 15596 秒。
  2. 随着 n 的增加,O(n ⁰)比 O(exp(n))上升得更慢,但不管怎样,它上升得很快。

5.从你自己的电脑上运行量子 D 波机器…免费

本文中完整的 Python jupyter 笔记本都可以在 GitHub 这里获得。 pip install 应该安装这里需要的所有库,因为它会查看包含所有需求的提供文件 requirements.txt 。然后,您可以通过调整had _ guro bihad _ dwave来运行您自己的笔记本电脑,以适应您所拥有的软件和许可证。您可以在 D-Wave 设置自己的免费 leap 账户。使用 pip 安装 gurobipy (包含在 pip 安装中)您可以安装一个版本的 Gurobi,它可以解决许多变量或约束的小问题。对于更大的,你需要一个许可证。

这 5 个笔记本 gists 包含所有代码,但也包含我们生成的所有交错输出,可从本文上面提到的链接获得。

最棒的是,你可以免费获得一分钟的 D-Wave 量子时间(考虑到小问题是在毫秒内解决的,这已经很多了),如果你注册为开发者并公开发布你的代码,比如在 GitHub 上发布,每个月更新

所以现在你可以避免因试图自己解决数独而患上癫痫症。

彼得·塞尔斯和爱德华·穆里尔,2021 年 8 月 31 日星期二。

这里提到的 GitHub 上的所有代码和 gists 都是由本文作者创建的,所有测试都是由他们运行的。

完全披露:这篇文章不是由 D-Wave 赞助的,我们也没有收到 D-Wave 的任何付款。我们承认是他们技术的热情用户,因为他们使我们能够更快地解决大的计算挑战。

版权 2021 逻辑上你的 BV 。

迎接 SQL 挑战

原文:https://towardsdatascience.com/acing-the-sql-challenge-d8b8feb0a041?source=collection_archive---------4-----------------------

通过使用一个框架来帮助您解决技术难题,从而赢得下一次 DA 面试

照片由戴恩·托普金在 Unsplash 上拍摄

如果你是一名数据分析师,目前正在找工作,你可能需要准备技术面试,最常见的形式是 SQL 挑战。结构化查询语言(SQL)是数据分析的基础。它是与数据库通信的语言,有助于检索、清理和分析信息。因此,招聘委员会想知道候选人使用 SQL 查询数据库的舒适程度是很自然的。

在这篇文章中,我不会分享 SQL 挑战的什么(我需要知道什么?应该准备哪些问题?有哪些资源可以帮我准备?)而是如何思考:我应该如何思考这个问题?怎么分解?我如何向面试官传达潜在的挑战?有时候,有一个参考框架来处理困难的情况比重复经历困难的情况要好。这篇文章就是要给你一个参考框架。

好了,说够了,让我们开始吧!😄

我从哪里开始?

在进入问题之前,问自己以下问题:

作者图片

我能相信这些数据吗?

通常,数据集不会以一个整洁的小包的形式提供给分析人员——你会看到两次记录的电子邮件地址、大量的空值、拼写错误等。对数据表示怀疑。有重复的值吗?是否有信息缺失?我需要从最终输出中排除异常值吗?我是否应该对数据执行转换(例如,删除一系列数字中的破折号)?虽然在面试中清理数据不是你的工作,但是你要确保你有所有的拼图来解决你被问到的问题。不要假设你正在处理的数据是原始的。在现实生活中,从来都不是。

**--identifying duplicate values**SELECT column_name, COUNT(*)
FROM table_name
GROUP BY column_name
HAVING COUNT(*) > 1**--identifying blank values** SELECT column_name
FROM table_name
WHERE column_name IS NULL**/*transforming a column that contains 
SSN information (can be both a series
of digits only or a series of digits
and dashes)*/**
SELECT 
    ssn, 
    REPLACE(ssn, '-', '') AS transformed_ssn
FROM table_name

我应该做哪些假设?

虽然数据争论是一个重要的步骤,但你可能有 30 到 60 分钟来解决这个挑战。考虑到时间限制,做出假设并继续前进是很重要的。确保明确传达你将做出的假设。如果你不确定自己的假设是否正确,可以问面试官你的思路是否正确。您不希望在分析过程中走得太远,却发现自己没有做出正确的假设(或者没有意识到这一点,结果与预期结果相差甚远)。

有什么问题需要解决?

这就是你的大局。想想你试图解决的问题。虽然 SQL 挑战可能会要求您做 x 或 y,但您实际被要求做的是什么?同样,确保向面试官重述问题。这有助于两个原因:(1)你展示了你的沟通技巧;(2)确保你和面试官在同一条线上。

如何分解这个问题?

这就是面试的精髓(也可能是你为什么还在读这篇文章的原因!).您将花费大约三分之二的时间在这里,建立您的逻辑,分析数据并测试它,以确保它运行并返回预期的输出。提醒一句:不要每 5 秒钟就按一次“运行”按钮,希望输出能帮助你解决问题。真正坐下来解决问题,做自己的查询解释器,一行行地运行,了解每一步会发生什么。

这一步实际上取决于您被问到的问题,但是您可以使用以下框架来帮助您完成 SQL 挑战:隔离,排名,构建

作者形象

孤立的

第一步是隔离解决难题所需的不同部分。一个困难的 SQL 挑战可能看起来令人望而生畏。这就是为什么将它分解成更小的单元很重要,这些单元更容易自己解决。为此,您需要查看问题并确定这些单位是什么。

军阶

下一部分是确定如何对每个要解决的单元进行优先排序。在把每一个都隔离成易于处理的小块之后,你应该先处理哪一个?为什么?一个要记住的小技巧:开始一般,结束具体。首先获取您需要的数据,然后进行聚合。

建设

最后一步是为您已经确定的每个单元构建逻辑。此时,您已经编写了伪代码,可能是一些 SQL 来探索数据并了解如何解决问题。现在是编写查询构建块的时候了。这就是您所有 SQL 知识派上用场的地方:CASE 语句、JOIN 类型、窗口函数、通用表表达式(cte)和子查询都是您可以随身携带的好工具。

我卡住了——我该如何继续?

您可能不知道如何继续。去过那里,做过那个。首先,放松。深呼吸。当面对复杂的问题时,一个失控的大脑不会有太大的好处。第二,记住面试是一次对话。面试官想知道当一个困难的情况摆在你面前时,你会有什么反应。你会坚持还是放弃?在寻求指导之前,您会寻求帮助还是试图自己解决问题?你的思维过程是什么?

如果您卡住了,以下是一些可以帮助您的提示:

作者形象

让面试官知道

确保让面试官知道你卡住了。告诉他们在哪里以及为什么。它会有所帮助,原因有几个:(1)您可能最终会回答自己的问题——沟通挑战可以帮助您识别一条您可能最初错过的重要信息,但它可以帮助您解决您正在处理的问题(2)您没有浪费时间茫然地盯着屏幕或白板(疫情时代之前!)不知道如何继续(3)你表现出谦逊和合作的意愿,这是你在任何角色中的关键品质。

提问

没有一个数据分析师能提供这项工作所需的所有答案和技术。阿达成功的一个重要因素是能够提出好的问题。在面试中,你想通过问一些澄清的问题来展示你的好奇心和解决问题的能力。你不会因此受到惩罚。然而,对你问的问题要有策略。如果你因为不知道 SELECT 语句的基本结构而陷入困境,你可能应该在参加面试之前复习一下基础知识。

大声说出来

解决挑战性问题的一种方法是大声说话。您可以使用淘汰过程来了解如何继续挑战。“我应该在桌面上进行自我加入吗?可能不会,我不需要用不同的方式从同一个表中获取相同的信息。使用 CTE 获取我需要的信息并加入其中怎么样?可能,但我没有说明我被要求做的两种聚合。”等等。这将有助于你缩小解决方案的范围,同时让面试官看到你是怎么想的,以及如果你仍然陷入困境,该给出什么样的提示。

结论

框架是一种很好的方式来组织您的思想,并指导您完成复杂的 SQL 挑战。要了解其他分析师如何处理 SQL 问题,您可以查看蒂娜·黄的 SQL Sundays 播放列表。在 5 到 10 分钟的视频中,她逐步演示了如何解决 SQL 挑战。

虽然使用框架会有所帮助,但你仍然需要大量的练习才能在技术面试中胜出。以下是准备技术面试的绝佳资源:“如何应对数据科学面试:SQL”、、【你必须准备的 SQL 面试问题】、、、【破解 SQL 面试】你可以使用 Leetcode 、 InterviewQuery 、 Codewars 、 Stratascratch 等*台练习 SQL 挑战。

在我的下一篇文章中,我将一步一步地介绍 SQL 挑战——敬请期待!

本帖最后编辑于 2021 年 10 月 8 日。这里表达的观点仅属于我自己,并不代表我的雇主的观点。

使用 API、Python 和 Tableau 获取和分析美国的通货膨胀数据

原文:https://towardsdatascience.com/acquire-and-analyze-inflation-data-in-the-us-with-an-api-python-and-tableau-ae81944bcbb0?source=collection_archive---------12-----------------------

数据、通货膨胀、数据分析、Python 和 Tableau

使用 Python 和美国劳工统计局数据 API 检索消费者价格指数数据。将数据加载到 Tableau 中,与系列 I 美国储蓄债券初始综合利率进行比较。

莎伦·麦卡琴在 Unsplash 上的照片

介绍

2021 年 8 月初,美国劳工统计局(BLS)报告称,截至 2021 年 7 月,整个秋季的消费者价格指数 (CPI)同比增长 5.4%。根据 BLS 的说法,CPI“是对城市消费者购买一篮子消费品和服务的*均价格变化的衡量”通胀基准上次超过这一水*是在 2008 年 7 月,当时达到 5.6%。

CPI 是一种用来衡量长期通胀(和通缩)的指标。这是一个经济指标,衡量消费者的购买力随着时间的推移。

所有项目的消费价格指数(CPI),12 个月百分比变化,按年份。作者截图。

虽然 BLS 的消费物价指数网页以各种方式描述数据,BLS 也提供许多数据工具来访问和查看数据。本文将向您展示如何使用 BLS 数据 API 和 Python 来获取 CPI 数据。它还将显示一个在 Tableau 中创建的图表,以比较 CPI 值和 I 系列美国储蓄债券的通胀率。

示范项目

本文描述了我用来获取 CPI 通胀数据和 I 系列美国储蓄债券利率的过程,以便在数据分析项目中使用这些数据:

  1. 编写一个使用 BLS 数据 API 从 BLS 服务器获取 CPI 数据的 Python 程序。API 将返回 JSON 结构中的数据,程序将把这些数据写入文件。
  2. 创建一个 Google Sheets 电子表格,其中包含美国财政部在其 TreasuryDirect.gov 网站上发布的 I 系列储蓄债券利息数据。
  3. 使用 Tableau 公共数据可视化工具集创建一个混合 CPI 和储蓄债券利率数据集的仪表板,并以可视化方式显示数据。
  4. 将 Tableau 可视化(如下面显示的仪表板)发布到 Tableau 公共网站。

使用 Tableau Public 创建的示例“第一系列美国储蓄债券初始利率和年通货膨胀率”仪表板。信用——作者。

BLS 数据 API 概述

BLS 提供了两个版本的公共数据 API。2.0 版本需要注册,并允许用户更频繁地访问更多数据。它还允许用户在请求中添加计算和年*均值。1.0 版本更简单,对公众开放,无需注册。我将展示如何使用 API 的 2.0 版本,因为它提供了比 1.0 版本更好的优势:

  • 它可以检索 20 年的数据,而不是 10 年。
  • 它可以根据 CPI 原始值计算周期性通货膨胀率(以 1、3、6 和 12 个月为间隔)。

BLS 数据 API 版本 1.0 和 2.0 的功能和限制。

虽然这里描述的项目使用 Python 编程语言,但 BLS 数据 API 支持许多语言和环境,包括:

  • C#
  • Java 语言(一种计算机语言,尤用于创建网站)
  • 服务器端编程语言(Professional Hypertext Preprocessor 的缩写)
  • 稀有
  • Ruby/Ruby on Rails
  • 斯堪的纳维亚航空公司
  • 矩阵实验室
  • 朱莉娅
  • UNIX 命令语言

BLS 数据系列

这里描述的项目使用 CPI 数据,但是程序员和数据分析师可以使用 BLS 数据 API 来检索许多其他类型的数据。BLS Top Picks 页面提供了一个流行数据系列的列表。CPI 是一个价格指数。BLS 还提供就业、薪酬和生产率数据集。

流行的 BLS 价格指数数据集。作者截图。

在这次演示中,我将使用“所有城市消费者的 CPI…—cuur 0000 sa 0”数据系列。点击页面的[检索]按钮,返回如下所示的数据。

BLS 网站上的 CPI 查询工具。作者截图。

注册 BLS 数据 API 2.0 版

要使用 BLS 数据 API 2.0 版的全部功能,请使用您的组织名称(或个人姓名)和电子邮件地址注册一个密钥。如果请求成功,BLS 将通过电子邮件向您发送密钥值。

BLS 数据 API 2.0 版注册表。作者截图。

获取 CPI 数据并将其写入文件的 Python 代码

您可以从 Github 中的 bls_data_api 项目的 BLS 数据 API 下载示例 Python 代码来获取 CPI 数据。代码如下所示,包含以下两个源文件:

c_bls_data_api.py —该文件中的 c_bls_data_api 类是一个简单的 Python 类,可用于通过 bls 数据 api 从大多数可用数据集中检索数据。

get_bls_cpi_data.py —该文件中的代码为 bls 数据 API 构建输入参数(作为 JSON 结构),以请求 2002 年到 2021 年的 cpi 数据。然后,它使用数据 api 参数和要将返回的 JSON 数据文件写入的文件名调用 c_bls_data_api 类的构造函数。

c_bls_data_api.py 类

这个类有两个函数,构造函数 init()和 get_report()。请查看下面代码中的注释,以了解它们所做工作的摘要。

在 get_report()函数中,注意对 requests.post()的调用包括 BLS 数据 API 的以下基本 URL:

' https://API . bls . gov/public API/v2/time series/data/'

URL 后面是数据(这些参数指定将要检索的数据)和头(指示 post()函数其输出将采用 JSON 格式)。

get_bls_cpi_data.py 文件

这个文件是主控制器。它只是打印程序已经启动,构建调用 c_bls_data_api 构造函数所需的参数,调用构造函数,并打印程序已经完成。在这种情况下,' CUUR0000SA0 '的 seriesid表示程序将检索 CPI 数据。

在对 json.dumps()的调用中,确保将“PasteYourKeyHere”替换为您在注册使用 BLS 数据 API 2.0 版时收到的注册密钥。

运行程序并检查输出

我在 Microsoft Visual Studio 中创建了这个 Python 项目。您可以使用您喜欢的 Python 环境。

加载程序后,请参见文件 c_bls_data_api.py 的第 15 行中对 c_bls_data_api()类构造函数的调用。请注意,该示例将输出文件设置为“D:/project _ data/CPI/CPI _ data _ report . JSON”。将驱动器、文件夹和输出文件名更改为您喜欢的任何值。

运行程序,并根据需要进行故障排除。工作时,它将创建一个名为 cpi_data_report.json 的输出文件,其中包含从 2002 年到 2021 年的 cpi 数据。在编辑器中打开 JSON 文件。它应该类似于下面的代码片段。

请注意,对于 year 字段中的每一年, periodName 字段包含月份的名称。百分比变化部分的字段 12 包含过去 12 个月的 CPI 百分比变化。这个值就是年通货膨胀率。

摘自 cpi_data_report.json 文件,由示例 Python 程序创建,该程序使用 BLS 数据 API 获取 cpi 数据。信用——作者。

获取 I 系列储蓄债券利息数据

在我运行 Python 程序来获取 CPI 数据并将其写入 JSON 文件后,我在 Google Sheets 中创建了一个电子表格来记录 I 系列美国储蓄债券的初始复合利率。

摘自 2002 年至 2021 年每年 5 月至 10 月和 11 月至 4 月发行的系列 I 美国储蓄债券的初始复合利率文件。信用——作者。

债券的复利确定如下:

  • 每年 5 月和 11 月,确定未来 6 个月内发行的债券的综合年利率。
  • 复利由固定利率加上通货膨胀率组成。固定利率在债券有效期内保持不变,而通货膨胀率每六个月调整一次。

我无法找到 Tableau 可以随时下载的美国储蓄债券利率表,所以我手动将利率从 TreasuryDirect 网站上的 I 债券利率图表 PDF 文件(见下面的摘录)转录到名为I 系列储蓄债券利率的 Google Sheets 文件。您可以复制这个公共文件以在 Tableau 中使用。

摘自财政部指令系列一美国储蓄债券利率表。红线以上的数字代表债券发行时的初始综合利率。作者截图。

Tableau Public 中的通货膨胀率和系列 I 利率仪表板

Tableau Public 是功能强大的 Tableau 数据可视化软件的免费版本。为了比较和查看 I 系列美国储蓄债券的年通胀率和初始复合利率的趋势,我将 JSON 文件和利率电子表格(如上所述)导入 Tableau Public。然后,我创建了一个复合条形图/折线图,如下所示,它描述了这些数据。

虽然 BLS 每月都会发布新的 CPI 数据,但财政部会在 5 月和 11 月调整 I 系列债券的利率。为了比较这两个值,下面的图表只显示了五月和十一月的值。

你可以在这里查看仪表盘。请随意安装 Tableau Public 并复制一份仪表盘供您使用。

使用 Tableau Public 创建的示例“第一系列美国储蓄债券初始利率和年通货膨胀率”仪表板。信用——作者。

摘要

经济学家和其他人使用 CPI 数据来衡量美国消费者的购买力。虽然本文描述了一个使用 BLS 数据 API 2.0 版获取数据的 Python 程序和一个 Tableau Public dashboard 来比较 CPI 和 Series I 储蓄债券初始综合利率,但是 CPI 指数有多种用途。例如,它可用于以下目的:

  • 来衡量美元的购买力。
  • 供政府机构、企业和消费者用来对经济做出明智的决策。
  • 美国政府可以用它来决定政府项目的资格,如社会保障。
  • 政府机构和企业可以把它作为决定员工工资的一个因素。

资源

如何购买 I 系列美国储蓄债券以抵御通胀

劳动统计局数据 API

美国财政部国库指令

W3schools Python JSON 教程

Tableau Public

使用 Python 和 Tableau 获取和分析天气和气候数据

原文:https://towardsdatascience.com/acquire-and-analyze-weather-and-climate-data-with-python-and-tableau-4878e8759152?source=collection_archive---------1-----------------------

美国国家海洋和大气管理局(NOAA)存储了大量的天气和气候数据。了解如何编写 Python 程序来调用 API 来检索数据,并使用 Tableau Public 或其他可视化工具对其进行分析。

戏剧性的云。照片由 Unsplash 上的 NOAA 提供。

天气和气候数据是宝贵的资源,不仅可以预测天气,还可以用于行业、政府和个人生活中的许多目的。将数据分析和数据科学技术应用于这些数据以通知和支持决策的机会几乎是无穷无尽的。

NOAA 的国家环境信息中心 (NCEI)是世界上最广泛的天气和气候数据收集中心。它的数据库包含超过 37pb 的大气、海岸、海洋和地球物理数据。本文描述了数据、如何下载其数据文件,以及使用调用其数据服务 API 的 Python 程序获取数据的说明。它还演示了一个 Tableau 公共仪表板,以可视化使用 API 检索的一组示例风数据。

天气和气候数据的使用

天气和气候数据服务于社会的多种需求。以下是一些例子:

  • 农业 —农民可以利用天气数据来决定何时种植和收获作物,施用化肥和除草剂,等等。
  • 过敏 —天气在过敏季节起着重要作用,尤其是对那些与花粉和其他植物材料有关的过敏。
  • 建筑和道路施工 —天气可能影响室外施工作业。
  • 土木工程 —设计桥梁、道路和隧道等结构的工程师必须意识到天气对这些结构及其材料的短期和长期影响。
  • 气候学 —气候科学家使用天气和气候数据来了解过去、现在和潜在的未来气候。
  • 服装和时尚——我们穿的服装种类随着季节和天气条件的变化而变化。有些人根据季节选择他们的风格和颜色。
  • 应急管理 —应急管理人员使用天气和气候数据来确定灾难性事件的潜在风险,如野火、龙卷风、飓风和洪水。
  • 法医气象学 —法医气象学家分析天气数据,拼凑过去的天气事件。
  • 林业和土地管理 —林业工作者使用天气和气候数据来管理森林,了解干旱的影响,降低火灾风险,等等。例如,美国林务局运营着一个广泛的自动气象站网络。
  • 人口迁移 —天气和气候是人们用来帮助他们决定居住地的因素。
  • 户外娱乐——户外活动,如徒步旅行、航海、滑雪、露营、钓鱼和打猎,因季节和天气而异。人们评估历史气候和天气数据以及当前条件和预测,以选择户外活动的最佳时间。
  • 产品销售和营销 —例如,零售商使用天气数据来确定何时在商店中储备某些类型的商品,如泳衣或滑雪板。
  • 运输 —运输可能会受到天气的影响。例如,在冬天可能结冰的内陆水道上用驳船装运谷物和其他散装货物会受到天气的影响。
  • 旅游和旅行 —人们依靠天气和气候数据来计划去他们选择的目的地的短期和长期旅行。
  • 波浪活动和水动力影响 —来自安装在浮标上的气象仪器的数据可以帮助预测波浪和天气对海岸线和海滩的影响。
  • 天气预报 —气象学家使用气候和天气数据来帮助他们预测未来的天气。

数据概述

NCEI 是美国环境数据的主要权威。它管理着大量的大气、海岸、地球物理和海洋研究数据的档案。

NCEI 管理着各种各样的数据产品,其中很多都是向公众开放的。不胜枚举,超出了本文的范围,下面是其数据产品类别的一些示例:

  • 气温和大气特性
  • 北极和海冰
  • 生态系统和自然资源
  • 地磁学
  • 自然灾害、灾难和恶劣天气
  • 海洋气候
  • 沉淀
  • 太空天气
  • 美国和地区气候

下载天气和气候数据

除了应用程序编程接口(API),NCEI 还提供了查找、请求和下载天气和气候数据的工具。

找到一个电台,订购并下载其数据

位于美国和世界各地的气象观测站收集了由 NCEI 管理的大部分气象数据。导航至 数据工具:查找电台 页面,按城市、县、州、邮政编码或国家搜索电台。

在下面的例子中,我使用 Find a Statio n 工具来搜索加利福尼亚州圣何塞的一个位置、每日摘要类别、日期范围 2000-01-01 到 2020-12-31 以及风数据类别。请注意地图上加利福尼亚州弗里蒙特和圣何塞的观测站符号。

数据工具:找一个站。作者捕获的图像。

当我点击圣何塞的车站标志时,弹出一个车站详情窗口,如下图所示。请注意“GHCND:.”右侧的 ID 值的组成部分该值“USW00023293”是圣何塞国际机场观测站的唯一标识符。稍后将在调用 NCEI 数据服务 API 时使用该 ID,以通过编程方式检索该气象站捕获的气象数据。

气象观测站详情。作者捕获的图像。

要开始检索此数据,请单击[添加到购物车]按钮。然后,单击屏幕右上角的[购物车(免费数据)…]按钮。

数据购物车按钮。作者捕获的图像。

购物车:每日摘要页面上,选择“自定义 GHCN-每日 CSV”格式。此选项将导致下载逗号分隔值(CSV)文件中的风数据。文件格式类似于 Python 程序在调用数据服务 API 后保存的 CSV 文件。

查看搜索值,包括“日期范围”准备就绪后,单击[继续]按钮。

购物车:每日汇总页。作者捕获的图像。

自定义选项:每日摘要页面上,进行如下图所示的选择。注意“标准”的单位值将以英里每小时(MPH)为单位返回风速值。选择“公制”将返回以米每秒为单位的风速值。

本文后面还将使用“*均风速(AWND)”数据类型来演示 Tableau Public 中数据的可视化。“最快 2 分钟风速(WSF2)”和“最快 5 分钟风速(WSF5)”数据类型仅用于演示。

“AWND”、“WSF2”和“WSF5”数据类型值将在稍后调用数据服务 API 时使用。

自定义选项:每日摘要页面。作者捕获的图像。

出现查看订单页面时,查看您的选择并输入两次您的电子邮件地址。准备好后,点击[提交订单]按钮。在几秒钟或几分钟内,NCEI 将向您发送第一封确认订单提交的电子邮件和第二封确认订单完成的电子邮件。完成电子邮件包含下载符合您选择标准的数据文件的链接。

气候数据在线请求电子邮件主题行。作者捕获的图像。

打开第二封“订单完成…”电子邮件。单击[下载]链接下载数据文件。

部分气候数据在线请求完成电子邮件。点击[下载]按钮下载数据文件。作者捕获的图像。

在文本编辑器中打开下载的 CSV 文件。它应该类似于下面显示的文件。注意,第一行中的列名(NCEI 称之为“数据类型”)对应于后续行中逗号分隔的数据值。

下载的每日风力数据 CSV 文件示例。作者捕获的图像。

其他数据搜索工具集

搜索观测站并选择和下载其数据是从 NCEI 数据集中检索数据的多种方法之一。使用 气候数据在线 页面上的链接探索其他方法。

气候数据在线页面。图片由作者提供。

NOAA 还提供了一站式数据搜索*台,可以交互式地查找和查看各种数据。一些数据可供下载。

NOAA 一站式数据搜索*台主页。作者捕获的图像。

用 Python 调用 Access 数据服务 API

NCEI 提供了四个 RESTful APIs 来获取天气和气候数据。本文描述了如何使用数据服务 API 来获取几个气象站的每日汇总数据。

数据服务 API 根据发送到 web 服务器的参数和预定义的 URL 检索数据。请参见简短的数据服务 API 文档了解其工作原理。

URL 和参数

要使用数据服务 API,请将参数追加到此预定义的 URL:

https://www.ncei.noaa.gov/access/services/data/v1

下一节中描述的示例代码将查询 daily-summaries 数据集,以检索 2000 年 1 月 1 日至 2020 年 12 月 31 日期间美国几个地点每天的日*均风速值。API 返回 AWND 和其他风速值,单位为英里/小时(MPH)。要检索所需的数据,请将这些参数附加到上面显示的 URL 中:

  • 数据集 —“每日汇总”数据集提供汇总的每日天气数据,包括风数据。
  • 数据类型 —我们对本例中的日*均风速(‘AWND’)感兴趣。但是为了将来可能的使用,该参数值被设置为获得最快的 2 分钟风速(“WSF2”)和最快的 5 秒风速(“WSF5”)。要获得这三种类型,请将 dataTypes 参数值设置为“AWND,WSF2,WSF5”
  • —在本例中,我们感兴趣的是这些站的日*均风速:芝加哥奥黑尔国际机场、罗彻斯特国际机场(明尼苏达州)和圣何塞国际机场。在逗号分隔的列表中向 API 提供这些工作站的标识符:“USW00094846、USW00014925、USW00023293”。在 数据工具中搜索电台 id:如本文前一节所述,查找电台 页面。
  • 开始日期 —将检索从 2000 年 1 月 1 日到 2020 年 12 月 31 日的记录。因此,在本例中,将设置值“2000–01–01”。
  • 结束日期 —因为我们对 2020 年的数据感兴趣,所以将该值设置为“2020–12–31”。
  • 边界框 —设置边界框值,从坐标内包含的地理位置选择数据。它包括四个逗号分隔的数字。南北从-90 度到 90 度,东西从-180 度到 180 度。对于此示例,将 boundingBox 设置为' 90,-180,-90,180 '。
  • 单位 —数值为“公制”或“标准”对于*均风速数据类型,“标准”值将以英里/小时为单位返回风速。

以下是将参数附加到基本 URL 后得到的完整 URL:

https://www.ncei.noaa.gov/access/services/data/v1/?dataset = daily-summaries&data types = AWND,WSF2,WSF5 & stations=USW00094846,USW00014925,usw 00023293&start date = 2000-01-01&end date = 2020-12-31&bounding box = 90,-180,-90,180 & units=standard

Python 代码

类 c_ncei_data_service_api

文件 c_ncei_data_service_api.py 定义了 c_ncei_data_service_api 类。以下部分描述了它的功能。

init()构造函数

当程序创建 c_ncei_data_service_api 类的实例时,会调用 init()构造函数。它接受这些输入参数:

  • 数据集 —包含所需数据的 NCEI 数据集的名称。
  • data_types —从数据集中返回的字段。它由逗号分隔的字段名称列表组成。
  • —这些是感兴趣的观测站的唯一标识符。该参数由逗号分隔的工作站 id 列表组成。
  • 开始日期时间 —要检索的数据的第一个日期。
  • 结束日期时间 —检索数据的最后日期。
  • bounding_box —参见上一节对 boundingBox 的描述。

该函数执行以下步骤:

  1. 设置变量 self。_base_api_url 设置为 NCEI 服务数据 api 的基本 url 的值。
  2. 使用输入参数调用 self.call_api()来检索请求的数据。

c_ncei_data_service_api 类模块顶部 init()函数的定义。注意“import requests”指令,这是使用 requests.get()向 NCEI 数据服务 API 提交请求所必需的。

注意:默认情况下,对 URL 的调用将返回 CSV 格式的数据。请参阅文档,了解为检索 JSON 和其他类型的数据而设置的参数。

call_api()函数

call_api()函数从指定的 NCEI 数据集中检索数据。它执行以下步骤:

  1. 向基本 URL 追加参数以创建 full_url 变量。请注意,除了函数的输入参数之外,它还设置了 API 的“单位”参数。
  2. 用 requests.get()函数提交 URL。产生的数据集(如果有)将被返回到“响应”变量中。
  3. 将“response.text”变量返回到构造函数。

c_ncei_data_service_api 类模块中的 call_api()函数。该函数使用 requests.data()提交 NCEI 数据服务 API 请求的完整 URL。

get_data()函数

get_data()函数将数据集数据返回给它的调用者。

c_ncei_data_service_api 类模块中的 get_data()函数。

write_data_file()函数

函数的作用是:写 URL 调用返回的数据,并保存在 self 中。_dataset 变量转换为文本文件。它执行以下步骤:

  1. 以写入模式打开参数中指定的文件。
  2. 把价值写在自我里。_dataset 变量添加到文件中。
  3. 关闭文件。

c_nei_data_service_api 类模块内的 write_data_file()函数。

控制器模块

控制器模块导入 c_ncei_data_service_api 模块,并执行以下步骤:

  1. 使用 init()构造函数描述中描述的参数创建 c_ncei_data_service_api 类的实例。此步骤将从 NCEI 数据集中检索数据。
  2. 将检索到的数据打印到显示器上。
  3. 将检索到的数据写入指定的文件。

控制器模块创建并调用 c_ncei_data_service_api 类的一个实例。然后,它将从 API 返回的数据打印到屏幕上,并将其写入文件。

可能的类和程序改进

我开发 c_ncei_data_service_api 类和控制器模块是为了演示和学习的目的。以下是一些添加功能并使模块更加健壮和适合生产的想法:

  • 添加错误处理以从错误中正常恢复,并在需要时重试部分代码。
  • 将有关程序操作的信息,如开始和结束的日期和时间、错误信息、输入参数以及检索到的记录数量写入一个日志文件
  • 修改 call_api()函数来处理更多的输入参数,比如想要的输出数据格式(CSV、JSON、PDF 等)。

运行程序

运行控制器模块以创建 c_ncei_data_service_api 的实例,从 ncei 数据服务 api 检索所需的数据,显示数据,并将其写入文件。输出文件应该类似于下面显示的输出 weather_data.csv 文件中的示例。第一行包含列标题,而后面的行包含数据。

通过调用 NCEI 数据服务 API 检索 CSV 文件。作者捕获的图像。

其他 NCEI 原料药

虽然本文探索了数据服务 API 的使用,但 NCEI 也提供了这些 API:

  • 搜索服务 API —基于一组参数发现数据集和数据。
  • 访问支持服务 API —基于一组参数发现关于数据集的元数据和属性。
  • 访问订单服务 API —根据一组参数检索以前订单的信息。

在访问页面了解更多关于 NCEI 数据集的信息。它提供了数据发现工具、数据访问信息和开发人员工具的链接,包括 API、地图服务目录、气候数据 web 服务和官方 NOAA GitHub 知识库。

分析 Tableau Public 中的数据

伊利诺伊州的芝加哥被称为“风城”我住在明尼苏达州东南部,那也是一个多风的地方。为了直观地比较芝加哥地区和明尼苏达州东南部最大的城市罗切斯特的日*均风速,我在 Tableau Public 中加载了用数据服务 API 检索的数据。在那里,我创建了一个https://public.tableau.com/profile/randall.runtsch#!/vizhome/DailyAverageWindspeedforSelectU_S_Locations/WindbyLocation日*均风速的仪表盘。我儿子住在加州圣何塞附*,所以圣何塞国际机场的风速也会显示出来。

结果令我吃惊。罗切斯特国际机场(明尼苏达州)的风速一直高于芝加哥奥黑尔国际机场。这两个机场的风力都比圣何塞国际机场大得多。

从 2000 年到 2020 年,这些位置的日*均风速为英里每小时:

  • 罗切斯特国际机场(明尼苏达州)——11.31 英里/小时
  • 芝加哥奥黑尔国际机场——9.52 英里/小时
  • 圣何塞国际机场——6.44 英里/小时

2000 年至 2020 年三个地点的日*均风速。作者捕获的图像。

仪表板还显示了年、月、年和季节的日*均风速。北半球的气象季节定义如下。

  • 春天——三月、四月和五月。
  • 夏季——六月、七月和八月。
  • 秋季——九月、十月和十一月。
  • 冬季——十二月、一月和二月。

资料显示,春天和冬天是罗切斯特和芝加哥风最大的季节,夏天最*静。圣何塞全年风力相对较小。

2000 年至 2020 年三个地点按季节的日*均风速。作者捕获的图像。

为本文准备的仪表板图代表了 Tableau Public、Tableau 和 Microsoft Power BI 等工具中数据可视化的一小部分可能性。

摘要

天气和气候数据是宝贵的资产,数据分析师和数据科学家可以利用这些资产为个人和组织提供信息,并支持各方面的决策。美国国家海洋和大气管理局的 NCEI 服务拥有超过 37pb 的数据,管理着巨大的资产。它还提供了各种用户友好的搜索和下载工具,以及一组 API,使数据对任何人都可用。

您可以随意使用和修改 c_ncei_data_service_api Python 类和控制器模块来查询各种天气数据集,以满足您的需求。通过 API 和程序访问数据提供了一种将天气和气候数据集成到数据分析或数据科学解决方案、网站或软件应用程序中的方法。

Randy Runtsch 是一名作家、数据工程师、数据分析师、程序员、摄影师和自行车手。他和妻子住在美国明尼苏达州东南部。

Randy 撰写了大量关于利用公共数据集中的数据的文章。参见最*的文章, 使用 Data.gov 上编目的公共数据集来推动数据科学项目 ,以了解在data.gov上编目的 280,000+政府数据集的收集情况。

如何用 Python 和 Tableau 获取和分析 analytics.usa.gov 的数据

原文:https://towardsdatascience.com/acquiring-and-analyzing-data-from-analytics-usa-gov-with-python-and-tableau-b61870ea065c?source=collection_archive---------25-----------------------

analytics.usa.gov 免费提供的数据提供了人们如何在网上与美国政府互动的见解。本文向您展示了如何通过下载以及使用 Python 程序和 API 来访问站点的报告。

什么是 analytics.usa.gov?

analytics.usa.gov 提供了人们如何与美国政府在线互动的数据。美国总务管理局(GSA)的数字分析计划(DAP)运营该网站。它的数据提供了关于公众如何访问大约 400 个行政部门域名上的5700 个政府网站的洞察。

美国政府的 analytics.usa.gov 网站提供关于公众访问大约 5,700 个面向公众的政府网站的公开报告。作者捕获的图像。

这篇文章描述了公众可以从 analytics.usa.gov 下载的政府网站使用数据。它还展示了如何使用 Python 程序和 API 以 JSON 流的形式检索数据。最后,它展示了几个用于分析数据子集的 Tableau 公共仪表板。

可用数据集

用户可以下载下面列出的数据集,作为 CSV 或 JSON 文件。他们还可以调用测试 API 来检索数据。本文稍后将演示如何从 Python 程序调用 API。

参与机构的访问量和流量来源

报告每日更新

  • 过去 30 天内对所有域的访问
  • 昨天下载量最高的
  • 过去 30 天的主要流量来源
  • 过去 30 天的热门退出页面

报告每 5 分钟更新一次

  • 人们在某个时间点访问的所有页面
  • 某一时间点的在线总人数

参与机构的访客人口统计

报告每日更新

  • 语言
  • 台式机/手机/*板电脑
  • 网络浏览器
  • Internet Explorer 的版本
  • 操作系统
  • Windows 版本
  • 操作系统和浏览器(组合)
  • Windows 和浏览器(组合)
  • Windows 和 IE(组合)
  • 屏幕尺寸
  • 设备型号

报告每 5 分钟更新一次

  • 每个国家的游客
  • 每个城市的游客

使用 Python 和 API 访问数据

DAP 已经开发了analytics.usa.gov API来以编程的方式检索 JSON 流形式的报告。在测试阶段,我发现这个 API 在一个简单的测试中运行良好。要使用 API,请通过提交一个请求表单来注册一个密钥,如下所示,其中包含您的姓名和电子邮件地址。当您按下[注册]按钮时,表单将立即返回 API 密钥。

程序员必须申请一个 API 密钥来使用 analytics.usa.gov API 检索报告。作者拍摄的图片。

文件 openapi.yaml 记录了 api 规范。YAML 代表 YAML 不是标记语言。用代码编辑器或文本编辑器打开 YAML 文件。

程序设计环境

我用这些免费工具在我的 Windows 10 PC 上编写并执行了这个程序:

  • Python 3 . 9 . 2——Python 3 的任何版本都可能工作。
  • Microsoft Visual Studio Communityfor Windows——我的大部分代码都是用 Visual Studio 编写的。但是任何支持 Python 的编辑器或集成开发环境(IDE)都应该可以工作。注意,Visual Studio 的 Macintosh 版本不支持 Python。

代码逻辑

下面的示例程序执行这些步骤来调用 API,以 JSON 流的形式下载一个报告,并将其保存到一个文件中:

  1. 调用 c_analytics_usa_gov_api 类的构造函数。指定所需的报告名称和 JSON 输出文件名。
  2. 打开 JSON 输出文件进行写入。
  3. 调用 API 来检索报告。
  4. 将报告数据流写入 JSON 文件。
  5. 关闭 JSON 文件。

Python 模块

该程序使用请求和 json Python 模块。要安装这些模块,请从命令行调用这些命令,或者如果支持,在您的开发工具中调用这些命令:

  • pip 安装请求
  • pip 安装 json

控制器模块

控制器模块文件 call_analytics_usa_gov_api.py 是程序入口点。注意对 c_analytics_usa_gov_api()的调用。

c 类 _ 分析 _ 美国 _ 政府 _ 应用编程接口

c_analytics_usa_gov_api 类由控制器实例化。它执行上面代码逻辑部分中列出的步骤。

数据使用理念

虽然 analytics.usa.gov 的可用数据可能对政府开发人员和部门管理人员最有帮助,但我想到了这两种用途:

  • 确定访问美国政府网站的最流行的操作系统和浏览器。由于美国政府如此庞大,这些数字可能表明它们在美国的一般使用情况。
  • 从事特定行业(例如会计或税务处理)的人员可能会发现昨天的总下载量报告有助于分析经常访问的政府服务。

数据分析仪表板示例

为了演示 analytics.usa.gov 报告的使用,我用免费的 Tableau Public 商业智能和数据可视化工具开发了几个仪表板。仪表盘的数据来源是 OS &浏览器(组合)CSV 和桌面/移动/*板 CSV 报表。因为 CSV 文件的结构是表格形式的,所以在 Tableau 中很容易处理。

我很惊讶地得知,如下图所示,iOS(iphone)是用于访问政府网站的头号操作系统。

这个交互式的 Tableau 公共仪表板显示了通过操作系统和网络浏览器访问政府网站的情况。由作者创建的仪表板和捕获的图像。

下面的仪表盘显示,访问政府网站的浏览器和操作系统的顶级组合是 Safari 和 iOS、Chrome 和 Windows、Chrome 和 Android。

该 Tableau 公共仪表板显示了通过操作系统和网络浏览器组合访问政府网站的情况。由作者创建的仪表板和捕获的图像。

如下图所示,移动设备(智能手机)对政府网站的访问超过了台式电脑。这些信息表明,web 开发人员可能希望确保他们设计的网站能够像在桌面上一样在移动设备上显示页面。

这个交互式的 Tableau 公共仪表板显示了桌面电脑、移动设备(智能手机)和*板电脑对政府网站的访问。由作者创建的仪表板和捕获的图像。

把所有的放在一起

如你所知,analytics.usa.gov 提供了关于公众访问大约 5,700 个美国政府网站的各种报告。大多数报告都可以 CSV 或 JSON 格式下载。

analytics.usa.gov API使用 Python 或其他语言编写的程序能够轻松下载 JSON 报告。它还支持按机构过滤。

由于美国政府网站的流量如此之大,analytics.usa.gov 上的报告可能会为 web 和应用程序开发人员提供一些见解。有了这些可以代表整个美国的数据,他们可以识别广泛使用的操作系统、浏览器和*台。也许您可以想到数据的其他用途,以促进理解和支持决策。

关于作者

Randy Runtsch 是一名数据分析师、软件开发人员、作家、摄影师、自行车手和冒险家。他和妻子住在美国明尼苏达州东南部。

关注 Randy 即将发表的关于公共数据集的文章,以推动数据分析见解和决策、编程、数据分析、摄影、自行车旅行等。你可以在 shootproof.com 和 shutterstock.com看到他的一些照片。

来自 4 种数据分析的可行见解

原文:https://towardsdatascience.com/actionable-insights-from-descriptive-diagnostic-predictive-prescriptive-data-analytics-drivetrain-approach-f4e08828cc7?source=collection_archive---------9-----------------------

TT 先生在 Unsplash 上的照片

数据分析,行业笔记

使用动力系统方法收集数据和提取可行见解的系统方法。

“让我们收集所有我们能收集的数据,稍后我们会收集更多的见解。”你以前听过这个吗?

这种方法很少奏效。在极少数情况下,当它确实有点作用时,相对于收集、处理和存储大量数据的成本,投资回报率非常低。当你以一个目标开始时,分析会产生更好的回报。

此外,并不是所有的分析都是*等的。有趣的数据很有趣。但是能指导你下一步行动的可操作的见解更有价值。

动力传动系统方法 ( 讲座视频)提供了一种产生可操作见解的系统方法。它有四个步骤:

  1. 定义目标:从定义你的目标开始。
  2. 指定杠杆:指定你控制的输入,你可以拉动来影响结果的杠杆。
  3. 收集数据:找出你需要收集哪些数据来测量拉动这些杠杆的效果。
  4. 确定行动:分析数据,建立统计模型,计算要达到预期的结果,应该移动哪个杠杆,移动多少。

本文将应用驱动方法来解决问题:从一个目标开始收集和分析数据,并确定实现该目标的行动。

定义目标

动力传动系统方法的第一步是定义目标。业务问题和目标最初可能是模糊的,但是要精炼,使它们清晰可量化。

就拿这个问题来说吧:我想让我的作品通过社交媒体接触到更多的人。我想在 LinkedIn 上建立一个受众群。为了最大化我努力的结果,我想找到我的哪些内容效果最好。

目标是在 LinkedIn 上撰写吸引关注者的技术文章。换句话说,我的目标是确定我的帖子(在我的专业领域)的特征,这些特征能产生最大的追随者增长。

关键绩效指标(KPI)

一旦定义了目标,下一个任务就是指定一个或多个 KPI 来衡量实现该目标的绩效。所以让我们来理解一个 LinkedIn 帖子的生命周期。

当你在 LinkedIn 上发布一些东西时,它会出现在你的一些关注者的新闻源中。如果他们与你的帖子互动,LinkedIn 会显示给他们的关注者和你的更多关注者。

一篇文章的典型受众漏斗如下:

  • 追随者:这是漏斗的入口尺寸。更多的关注者意味着会有更多潜在的人看到帖子并与之互动。
  • 浏览量:在你的订阅源中看到帖子的关注者的分数或倍数。
  • 喜欢:一些关注者可能会觉得这个帖子足够有趣,从而喜欢上它。
  • 分享和评论:一些人可能会发现与他们的追随者分享和评论帖子很有帮助。
  • 新关注者:随着越来越多的人与帖子互动,更多即时圈子之外的人会看到它。他们可能会查看你的个人资料,并可能决定跟随它。

社交媒体帖子的漏斗。作者图片

成功的内容有三个指标:浏览量、参与度(喜欢、分享、评论)和新关注者。

观点和参与是有价值的。然而,新的追随者扩大了下一篇文章的漏斗入口。所以我认为这是社交媒体帖子成功吸引受众的最重要的衡量标准。

指定杠杆

下一步是问:你能控制什么,能改变什么来影响结果?

“上帝,请赐予我*静去接受我不能改变的事情,赐予我勇气去改变我能改变的事情,赐予我智慧去分辨两者的不同。”

在 LinkedIn 帖子的例子中,我控制的杠杆是:

  • 何时发帖:发帖的日期和时间。
  • 我多久发一次帖子:帖子的频率。
  • 我在帖子里写什么:领域、主题、内容复杂度、长度、结构、嵌入媒体(如图片、视频、文档、链接)。

有关于“何时”(周二到周四,上午到中午)和“多长时间”(每个工作日最多一次)在 LinkedIn 上发帖的研究。一些研究建议不要在帖子中包含链接。当然,有几个帖子提供了撰写杀手级 Linkedin 帖子的技巧。

虽然这些研究集中在公司网页上的营销帖子,但结果和提示对个人来说似乎也是明智的。但其适用性取决于题材、受众、地域等。因此,当我采纳一些建议(例如,每天最多发一篇文章)时,我想知道哪些方法对我有用。

收集数据

在过去的两个月里,我发布了 53 次。对于每个帖子,我记录了 KPI 和“杠杆”特征:

  • 发帖时的关注者,以及
  • 发帖 24 小时后的浏览量、点赞量、分享量、评论量和关注量。

对于每个帖子,KPI 是以下元组:(Followers_₀、Likes_₂₄、Shares_₂₄、Comments_₂₄、Followers_₂₄)

在大数据时代,这些数据少得可笑。虽然我会继续收集更多的数据,但我不会很快有“大数据”,因为我每天最多发一篇帖子。我想探索:

  • 从少量数据中收集可行的见解是否可行?
  • 我需要收集之前没有意识到的其他特征(杠杆)或 KPI 吗?
  • 如何在 Excel 或 Google Sheets 中进行数据分析?当我每天记录更多数据时,它可以作为一个具有最新分析的仪表板。

使用小数据集还有助于解释分析中的细微差别。

我的 LinkedIn 帖子的原始数据。图片由作者提供。

4 种数据分析

在我们开始分析数据和确定行动之前,让我们了解四种类型的数据分析:

  • 描述性分析: 发生了什么
  • 诊断分析: 为什么会发生?
  • 预测分析:如果会发生什么
  • 规定性分析: 如何使之发生?

描述性和诊断性分析是关于检查过去,而预测性和规范性分析是关于规划未来。

描述性分析

这是最常见的分析,从过去的事件中回答了根本问题:发生了什么?

在描述性分析中,我们沿着不同的维度聚集数据,并识别特定的模式或趋势。

大多数企业都有跟踪重要指标的仪表板。例如:

  • 各种产品在不同地理市场的月度和季度销售数量是多少?
  • 一个产品的销量是在增加还是在减少?
  • 不同地区的库存水*如何,是上升还是下降?

诊断分析

分析学的下一步是分析一个趋势并回答: 为什么 会发生?

在诊断分析中,我们向下钻取并进行根本原因分析。我们想找到是什么推动了一种趋势。因此,我们对数据进行切片,以识别异常值,隔离模式,并揭示相关性。

商业智能(BI)产品就是为了做到这一点。例如:

  • 确定推动盈利产品销售的客户群的特征。
  • 比较产品在不同客户群中的表现。
  • 比较不同产品在一个客户群中的表现。
  • 解释为什么会这样。是因为产品意识还是因为激烈的竞争?还是说这是该产品类别的总体趋势?

预测分析

有了模式和相关性的知识,分析就进展到预测:如果发生的可能性有多大?**

在预测分析中,我们使用回归分析、时间序列预测和其他多元统计建模技术。目标是在未来给定的时间点估计一些可量化的变量。

这是诊断分析的一大进步。它涉及到更复杂的预测分析:

  • 对产品线的需求
  • 客户群的收入潜力
  • 来自即将到来的活动的收入增长
  • 下一个财政年度的利润预测

规定性分析

一旦了解了过去,人们就可以预测未来,目标就转移到塑造未来上:如何让它发生?**

在规定分析中,我们进行“假设”分析来估计我们控制的移动杠杆的影响。然后,我们比较可用的替代方案,选择最佳的行动方案。

这是最具挑战性的级别,需要高级分析和数据科学技能。它是决定资源分配以实现利润最大化的游戏规则改变者。例如:

  • 哪些产品的产量需要增加,增加多少?
  • 每种产品在不同地区应该有多少库存?
  • 选择什么样的产品活动,瞄准哪些客户群?
  • 哪些产品或服务需要价格调整,调整幅度是多少?

大多数组织都没有达到这个成熟度级别。这需要一种数据驱动的决策文化来在这一层面运作。从一开始,您就需要开始考虑目标、需要什么数据、如何收集这些数据,并执行之前级别的数据分析以达到这一级别。

****四种类型的数据分析:描述性、诊断性、预测性和规范性。图片由作者根据Creative Commons BY-NC-ND 4.0 International许可发布。

确定行动

让我们回到动力传动系统的方法。最后一步是分析数据并提取可操作的见解。概括一下:

  • ****杠杆:嵌入媒体,帖子类型,域,工作日
  • ****关键绩效指标:浏览量、参与度(喜欢、分享、评论)和追随者增长

如果您查看原始数据,KPI 的两个方面非常突出:

  • KPI 的范围非常不同。
  • 随着追随者的增长,所有 KPI 也在增长,这使得它们随着时间的推移变得不可比拟。

将 KPI 转换为“每个关注者”基础,并计算浏览量、点赞数、分享数、评论数和关注者增长数的百分比,可以解决该数据集的两个问题:

  • 每个关注者的浏览量(V/F): (Views_₂₄ / Followers_₀)
  • 每个关注者的点赞数(左/右): 100 * (Likes_₂₄ / Followers_₀)
  • 每追随者股份(S/F): 100 * (Shares_₂₄ / Followers_₀)
  • 每个关注者的评论(C/F): 100 * (Comments_₂₄ / Followers_₀)
  • 跟随者成长(F+): 100 * (Followers_₂₄ - Followers_₀) / Followers_₀

下面的仪表板显示了一些描述性分析。它有跨职位的杠杆分布、各种杠杆的 KPI 聚合,以及一些随时间变化的特征。

对于聚合,我选择了中位数而不是总和,因为杠杆在帖子中的分布并不均匀。

从因果关系上看,它告诉我们:

  • gif、URL 预览(即带有链接但没有其他媒体的帖子)和 pdf 是表现最好的媒体类型
  • 愿景、演示、白皮书和营销是表现最好的职位类型
  • 编程、启动和微服务是表现最好的主题领域
  • 周一、周二和周五是最好的,周三是最糟糕的工作日

然而,一项仔细的评估显示,许多突出的特点只出现在少数职位上。例如,只有:

  • 两个帖子带有 gif,两个带有 URL 预览
  • 愿景和营销各一个帖子
  • 编程、启动和微服务各一篇

一半以上的帖子是关于 ML/DS/AI 的,并且有图片信息图。如果在这么多天里关注者增加了 65%,那么这些帖子一定有所贡献。

这是否意味着,如果我只在 vision for programming 上发布 gif,追随者的增长将会翻倍(因为每个的指数大约是 ML/DS/AI 图像信息图的两倍)?

由于统计数据不是算术数据,因此在解释分析数据时会有细微差别。

****对我的 LinkedIn 帖子的描述性分析。图片由作者根据Creative Commons BY-NC-ND 4.0 International许可发布。

让我们试着从诊断分析中得到一些答案。

我的第一个问题是:

  • KPI 之间的相关性如何?
  • 我应该只关注追随者的增长吗?
  • “每个追随者”是正确的方法吗?或者我应该跟随漏斗,考虑每个关注者的观点,每个观点的喜欢,每个喜欢的分享,等等。?

强相关 KPI 之间的相关性(𝞺)。

因此,我绘制了所有这些潜在的模型特征的直方图,并计算了它们与追随者增长的相关性(最重要的 KPI)。

如下图所示,所有这些特征都遵循正态分布。观点、喜欢和分享与追随者增长(F+)和相互之间有很强的相关性。另一方面,评论和 F+没有很强的相关性。

****诊断分析:潜在模型特征的直方图、分布和相关性。图片由作者创作,在知识共享 BY-NC-ND 4.0 国际许可下发布。

接下来,我想识别性能帖子。因此,我通过添加强相关 KPI 的标准化值(即 F+、V/F、L/F 和 S/F)创建了一个分数。

对于标准化值,*均值(𝞵)为 0,标准差(𝞼)为 1。由于得分是四个 KPI 的总和,值为 4 或更高(即𝞵+𝞼)的职位位于前 16%的表现突出者中。

下图是所有帖子的分数。右边的方框图用于识别异常值。金黄色代表总分,浅蓝色代表 F+。

有 7 个帖子的得分在 4 分以上,但其中两个是异常值。除了这 7 个中的一个,所有人的追随者增长分数都在跑赢大盘的范围内。

有 3 篇帖子(A、B 和 C)超过了关注者增长分数,但总分数低于 4。其中一个 C,综合得分为负。

****LinkedIn 帖子的关注者计数和绩效得分,用方框图来识别异常值。图片由作者根据Creative Commons BY-NC-ND 4.0 International许可发布。

下一步是深入预测分析。但是目前的数据不足以计算杠杆和分数之间的点-双列相关或进行线性回归。所以我决定检查这 10 个帖子:

  • 异常值: 岗位 1 ,岗位 2
  • 跑赢大盘: 岗位 3 ,岗位 4 ,岗位 5 ,岗位 6
  • 超越参与度,但追随者增长一般: 排名第七
  • 参与度一般,但增长优于跟随者: 帖子 A ,帖子 B
  • 怪招: 帖 C

我的观察是:

  • ****离群值:岗位 1 和岗位 2 分别具有高价值的形象和资源。甚至 Post 3 也是一个异常值,因为它共享一个 URL,众所周知这会减少浏览量。
  • Wierd: 帖子 C 和帖子 B 记录了高追随者增长,因为前一个帖子是离群值。我观察到 LinkedIn 持续显示非常高性能的帖子长达 3 天。
  • ****参与度一般,但表现优于跟随者增长:贴出我演讲的幻灯片。似乎这副牌吸引了人们去追随,但没有足够的吸引力去喜欢或分享。太奇怪了。
  • ****超越参与度,但追随者*均增长:第 7 篇帖子是一篇关于复杂主题的长文。我可以看到它是有用的,但太复杂了,无法跟踪和寻求更多的信息。
  • ****优于:帖子 4、5、6(以及帖子 A)处于中等长度(130-180 字)和中等复杂性的最佳位置。

可行的见解

虽然还需要更多的数据,但根据总体趋势和对这 10 篇文章的仔细研究,我打算这样做:

  • 千万不要错过周一发帖,周三放轻松。
  • 所有表现突出(和异常)的帖子都在大数据和 DS/ML/AI 中,所以要加倍下注。
  • 尝试更多的 gif,看看它是否能提高*均水*,这将把离群值转化为优于大盘的值。
  • 使用更多的信息图、列表条、备忘单和白皮书,因为它们表现良好,并且在数据中出现的频率相当高。

我还需要收集更多数据,尝试预测性和规范性分析。

警告

这些见解可能不是通用的,可能只适用于我的内容类型。此外,数据中存在偏差,因为我已经遵循了传统的最佳实践:

  • 写作是为了提供价值
  • 使用简单的语言
  • 将它格式化以便于阅读
  • 包括视觉丰富的媒体
  • 不要嵌入链接

摘要

动力驱动方法和四种数据分析为提取可行的见解提供了一个良好的框架。但请记住,数据分析和数据科学是实验性的,可能需要多次迭代才能正确。

如果您喜欢,请:

最初发表于T5【ML4Devs.com】**

在增强算法中激活早期停止以减轻过度拟合

原文:https://towardsdatascience.com/activate-early-stopping-in-boosting-algorithms-to-mitigate-overfitting-9c1b12cc6729?source=collection_archive---------16-----------------------

助推技术

机器学习中的助推算法——第八部分

图片来自皮克斯拜的克里斯蒂安·里德

在第七部分中,我已经提到过在提升算法中很容易发生过度拟合。过拟合是 boosting 技术的主要缺点之一。

提前停止 是一种特殊的技术,可用于减轻 boosting 算法中的过拟合。它在算法的训练阶段使用。

提前停止在 boosting 算法中有多有效?

在 boosting 中,在每个 boosting 轮(迭代)中添加一个新树。新树试图纠正树在前几轮中所犯的错误。

顾名思义,提前停止在由 n_estimators 给出的指定提升回合之前的某处停止算法的训练过程。可以通过绘制学习曲线来监控停止点。

(图片由作者提供)

我们通过提供训练和验证数据来计算训练和验证分数(通常,RMSE 用于回归,对数损失用于分类),然后将它们与增强回合数进行绘图。有一个点,验证分数没有进一步提高,并开始变得更差,而训练分数仍然继续提高。这是过度拟合开始和模型训练应该停止的地方。

根据迭代或推进轮次来确定该点的价值是非常重要的。在此之前,验证分数在每次迭代中都会提高。在这一点上,增强的模型在看不见的数据上概括得很好。在这一点之后,模型往往会过度拟合。

默认情况下,提前停止不是由升压算法本身激活的。要激活 XGBoost、LightGBM 和 CatBoost 等 boosting 算法中的提前停止,我们应该在 boosting 模型的 fit() 方法或 train() 函数中的参数early _ stopping _ rounds中指定一个整数值。

.fit(***early_stopping_rounds=int***)
#OR
.train(***early_stopping_rounds=int***)

整数值表示模型对看不见的数据进行良好概括的提升回合。如前所述,这可以通过监控学习曲线来发现。

使用 CatBoost 执行提前停止

CatBoost 是一个强大的升压算法。它有两个很好的特性,是其他 boosting 算法所没有的。它可以直接处理分类特征。另一个是我们可以通过在 fit() 方法或者 train() 函数中将 plot 自变量设置为True来轻松生成学习曲线。这就是我们在这里使用 CatBoost 实现提前停止的原因。

现在,我们在heart _ disease数据集上构建 CatBoost 分类模型,并通过创建学习曲线来监控学习过程。除了训练数据,我们还应该为 fit() 方法中的 eval_set 参数提供验证(测试)数据。这里,我们使用“对数损失”作为我们模型的评估指标。对数损失值越低,预测概率与实际值的偏差就越小。因此,日志损失值越低越好。

监控 CatBoost 的学习过程

(图片由作者提供)

模型在看不见的数据上概括得很好的地方用绿点标出。可以通过运行以下命令获得 X 坐标:

**cb.get_best_iteration()**

这将返回 42,这意味着模型在第 42 次迭代时对看不见的数据进行了很好的概括。之后,模型开始过度拟合。我们可以为early _ stopping _ roundsargument提供这个值来激活提前停止。**

*cb.fit(X_test, y_test,
       ***early_stopping_rounds=42***)*

当您再次运行模型时,它将在第 42 轮提升(迭代)时停止训练,尽管我们已经在 n_estimators 中指定了 550 轮提升!

关键要点

我们已经讨论了如何实现针对 CatBoost 算法的早期停止,该算法具有内置功能来监控学习过程。但是,我们也可以将早期停止与 AdaBoost、梯度增强、XGBoost 和 LightGBM 等其他增强算法结合使用。下面是一些将早期停止应用于这些算法的具体想法。

想法 1:创建学习曲线来监控学习过程

使用其内置的 参数,很容易为 CatBoost 创建针对增强回合的学习曲线。对于其他算法,您需要手动创建学习曲线。

想法二:激活提前停车

XGBoost、LightGBM 和 CatBoost 在 fit() 方法或 train() 函数中有一个参数叫做early _ stopping _ rounds。您可以指定一个小于 n_estimators 中的值的整数值来激活提前停止。AdaBoost 和 Gradient Boosting 中没有这样的内置参数。要激活 AdaBoost 和梯度增强的提前停止,您可以监控学习过程,找到模型开始过度拟合的点(如果有),并在 n_estimators 参数中设置该值。然后,需要用新的 n_estimators 值重新执行算法。**

想法三:寻找是否有机会提前停止

不是所有的增压模型都有机会提前停止。通过查看学习曲线,您可以很容易地找到这一点。具有以下学习曲线的模型即使在 5000 次助推轮后也没有提前停止的机会!

没有机会提前停止(图片由作者提供)

想法 4:选择正确的 API

对于 XGBoost 和 LightGBM 这样的 boosting 算法,有两个 API:Scikit-learn API 和 Learning API。Scikit-learn API 使用通用的 fit() 方法进行训练,而 Learning API 使用自己的 train() 函数进行训练。举个例子,

**import lightgbmlgbm = lightgbm.LGBMRegressor()#Training: Scikit-learn API
lgbm.fit(X_train, y_train)#Training: Learning API
lightgbm.train(**params=...,
               train_set=...,
               valid_sets=...**)**

最简单和推荐的是 Scikit-learn API。在这些 API 和算法中,同一个参数可能有不同的名称。

想法 5:随机化你的数据

由于训练/测试数据分割过程的随机性,输出可能会有很大变化。我建议您在拆分之前对数据进行洗牌,并为训练集使用尽可能多的数据。我还建议您在不同的 random_state 值下多次运行该算法,并查看输出。

今天的帖子到此结束。我总是尽我最大的努力来写和组织我的内容,以一种你可以从中获得最大收益的方式。应该有很多方法来进一步改善我的内容,你可能有很好的想法。所以,

如果你有任何反馈,请告诉我。

与此同时,你可以通过下面的链接注册成为会员,以获得我写的每一个故事的全部信息,我会收到你的一部分会员费。

****https://rukshanpramoditha.medium.com/membership

还有,再也不要错过我的一个故事。订阅获取这样的故事:

https://rukshanpramoditha.medium.com/subscribe

非常感谢你一直以来的支持!下一个故事再见。祝大家学习愉快!

特别感谢 Pixabay 上的 Christian Riedl ,为我提供了这篇文章的封面图片。

鲁克山·普拉莫迪塔
2021–11–08****

深度学习中的激活函数

原文:https://towardsdatascience.com/activation-functions-in-deep-neural-networks-aae2a598f211?source=collection_archive---------22-----------------------

入门

神经网络中激活函数的理论指南,以及为什么我们首先需要它们。

来源:https://unsplash.com/photos/dQejX2ucPBs

在这本详细的指南中,我将解释深度学习中激活功能的所有知识。特别是什么是激活函数,为什么我们在实现神经网络时必须使用它们。

简答:我们必须使用激活函数,如 ReLu、sigmoid 和 tanh,以便为神经网络添加非线性属性。这样,网络可以模拟数据中更复杂的关系和模式。

但是让我们在下面更详细地讨论这一点。

目录

  1. 重述:正向传播
  2. 神经网络是一个函数
  3. 为什么我们需要激活功能?
  4. 不同种类的激活功能(sigmoid、tanh、ReLU、leaky ReLU、softmax)
  5. 我们应该使用哪些激活功能?
  6. 带回家的信息

1.重述:向前传播

为了理解激活函数的重要性,我们必须首先回顾神经网络如何计算预测/输出。这通常被称为正向传播。在前向传播期间,神经网络接收输入向量 x 并输出预测向量 y

那是怎么回事?

请考虑以下具有一个输入、一个输出和三个隐藏层的神经网络:

图 1 前馈神经网络的示意图。来源;作者的形象。

网络的每一层都通过所谓的权重矩阵与下一层相连。我们总共有 4 个权重矩阵W1W2W3W4

给定输入向量 x ,我们用第一权重矩阵 W1 计算点积,并将激活函数应用于该点积的结果。结果是一个新的矢量 h1 ,它代表第一层中神经元的值。该向量 h1 被用作下一层的新输入向量,在此再次执行相同的操作。如此重复,直到我们得到最终的输出向量 y ,它被认为是神经网络的预测。

整组操作可以由下面的等式表示,其中 σ 表示任意的激活函数:

情商。1 正向传播。

关于神经网络及其具体工作方式的更多细节,请参考我的另一篇文章什么是深度学习以及它是如何工作的?

2.神经网络是一个函数

在这一点上,我想和你讨论另一种可以用来描述神经网络的解释。我们可以简单地称之为函数,而不是将神经网络视为节点和边的集合。

就像任何常规的数学函数一样,神经网络执行从输入 x 到输出 y 的映射。

对于一个输入 x 计算一个输出 y 的概念想必你已经知道了。这是一个常见的数学函数的概念。在数学上,我们可以定义一个函数 f(x) 如下:

Eq2。基础数学的例子。功能。

该函数有三个输入值【x1】x2【x3】abc 是取一定值的函数参数。给定输入 x1x2x3 ,该函数计算出一个输出 y

在基本层面上,这正是神经网络的工作方式。我们取一个特征向量 x 放入神经网络,神经网络计算一个输出 y

也就是说,我们可以将神经网络视为一种功能,而不是将神经网络视为节点和连接的简单集合。该函数将我们之前单独查看的所有计算合并为一个单一的链式计算:

情商。3 神经网络作为一种功能。

在上面的例子中,我们考虑的简单数学函数有参数 abc ,它可以强有力地确定输入×输入 的输出值 y

在神经网络的情况下,相应函数的参数是权重。这意味着我们在训练神经网络期间的目标是找到一组特定的权重或参数,以便给定特征向量 x ,我们可以计算对应于实际目标值 y_hat 的预测 y

或者换句话说,我们正试图建立一个可以模拟我们训练数据的函数。

你可能会问自己的一个问题是,我们可以总是对数据建模吗?我们是否总能找到定义一个函数的权重,该函数可以为给定的特征 x 计算特定的预测 y ?答案是否定的。只有在特征 x 和标签 y 之间存在数学依赖关系时,我们才能对数据建模。

这种数学依赖的复杂程度可能不同。在大多数情况下,当我们看数据时,我们人类永远无法用我们的眼睛看到这种关系。然而,如果在特征和标签之间存在某种数学相关性,我们可以确定在神经网络的训练期间,网络将识别这种相关性并调整其权重,从而可以在训练数据中对这种相关性进行建模。或者换句话说,这样可以实现从输入特征 x 到输出 y 的数学映射。

3.为什么我们需要激活函数?

激活函数的目的是向函数添加某种非线性属性,该函数是神经网络。没有激活函数,神经网络只能执行从输入 x 到输出 y 的线性映射。为什么会这样呢?

如果没有激活函数,向前传播期间唯一的数学运算将是输入向量和权重矩阵之间的点积。

由于单个点积是线性运算,所以连续的点积只不过是一个接一个重复的多个线性运算。而连续的线性运算可以认为是单一的线性运算。

为了能够计算真正有趣的东西,神经网络必须能够逼*从输入特征到输出标签的非线性关系。通常,我们试图从中学习的数据越复杂,特征到基础事实标签的映射就越非线性。

没有任何激活功能的神经网络将无法在数学上实现如此复杂的映射,也无法解决我们希望网络解决的任务。

4.不同种类的激活功能

在这一点上,我们应该讨论深度学习中使用的不同激活函数以及它们的优缺点

4.1 乙状结肠

几年前,你可能遇到的最常见的激活函数是 sigmoid 函数。sigmoid 函数将输入映射到 0 和 1 之间的范围:

图 2 Sigmoid 函数。来源;作者的形象。

sigmoid 激活函数定义如下:

情商。4 数学。s 形函数的定义。

实际上,sigmoid 非线性最*已经失宠,很少使用。它有两个主要缺点:

乙状结肠杀死梯度

第一个是 Sigmoids 饱和并杀死梯度。乙状结肠的一个非常不理想的特征是神经元的激活在 0 或 1 的尾部饱和(蓝色区域):

来源;作者的形象。

对于这些蓝色区域,sigmoid 函数的导数变得非常小(意味着:大的负或正输入值)。在这种情况下,接*零的导数将使得损失函数的梯度非常小,这阻止了权重的更新,从而阻止了整个学习过程。

乙状结肠非零居中

sigmoid 激活的另一个不希望的特性是函数的输出不是以零为中心的。通常,这使得神经网络的训练更加困难和不稳定。

请考虑一个由【w1】w2: 加权的具有输入 x1x2 的乙状结肠神经元 y

【x1】x2 是具有 sigmoid 激活的前一隐藏层的输出。所以 x1x2 总是正的,因为乙状结肠不是以零为中心的。根据整个表达式的梯度y = x1 * w1+x2 * w2相对于 w1w2 的梯度对于 w1w2 总是为正,对于 w1w2总是为负

通常最佳梯度下降步骤需要增加 w1 和减少 w2 。所以既然 x1x2 总是正的我们就不能同时增减权重,而只能同时增减所有权重。因此,最终,我们将需要更多的步骤。

4.2 Tanh 激活功能

深度学习中使用的另一个非常常见的激活函数是 Tanh 函数。下图显示了 tangens 双曲线非线性:

图 3 双曲正切函数。来源;作者的图像。

该函数根据以下等式将一个实数值映射到范围[-1,1]:

情商。5 数学。Tanh 函数的定义。

与 sigmoid 函数一样,神经元对较大的负值和正值饱和,函数的导数变为零(蓝色区域)。但与 sigmoid 不同,它的输出以零为中心。

因此,在实践中,双曲正切非线性总是优于 sigmoid 非线性。

4.3 整流线性装置— ReLU

在过去几年里,整流线性单元或简单的整流单元变得非常流行。激活的阈值简单地为零: R(x) = max(0,x) 或者更准确地说:

情商。6 数学。ReLU 函数的定义。

对于大于零的输入,我们得到线性映射:

图 4 ReLU。来源;作者的图像。

使用 ReLU 有几个优点和缺点:

  • (+) 实际上,与其他激活函数相比,ReLU 加速了梯度下降向损失函数全局最小值的收敛。这是由于它的线性、不饱和特性。
  • (+) 而其他激活函数(tanh 和 sigmoid)涉及计算量非常大的运算,如指数运算等。另一方面,ReLU 可以通过简单地将值向量的阈值设定为零来容易地实现。
  • (-) 不幸的是 ReLU 激活功能也有问题。因为对于低于零的输入值,该函数的输出为零,所以网络的神经元在训练期间可能非常脆弱,甚至可能“死亡”。这是什么意思?在权重更新期间,可能会发生(不必但仍然可以)以这样的方式调整权重,使得对于某些神经元,输入总是小于零。这意味着这些神经元的隐藏值始终为零,对训练过程没有贡献。这意味着从该点开始,流经这些 ReLU 神经元的梯度也将为零。我们说神经元“死了”。例如,观察到多达 20–50%的使用 ReLU 激活的整个神经网络可能是“死的”,这是非常常见的。或者换句话说,这些神经元永远不会在训练期间使用的整个数据集中激活。

4.4 泄漏的 ReLU

Leaky ReLu 只不过是 ReLu 激活函数的一个改进版本。如前一节所述,通过使用 ReLU,我们可能会“杀死”我们神经网络中的一些神经元,这些神经元将再也不会对任何数据进行激活,这是非常常见的。

漏 ReLU 就是为了解决这个问题而定义的。与“普通”ReLU 相反,在“普通”ReLU 中,对于低于零的输入值,所有输出都为零,在泄漏 ReLU 的情况下,我们在函数中添加一个小的线性分量:

泄漏的 ReLU 激活看起来如下:

图 5 泄漏的 ReLU。来源;作者的图像。

基本上,我们已经用一条非水*的线性线代替了表示零值的水*线。这条直线的斜率可以通过参数 α 乘以输入 x 来调整。

使用泄漏 ReLU 和替换水*线的优点是我们避免了零梯度。因为在这种情况下,我们不再有总是为零的“死亡”神经元导致我们的梯度变为零。

4.5 Softmax 激活功能

最后,我想介绍一下 softmax 激活功能。这个激活功能相当独特。

Softmax 仅在最后一层应用,并且仅在我们希望神经网络在分类任务期间预测概率得分时应用。

简单来说,softmax 激活函数强制输出神经元的值取 0 到 1 之间的值,因此它们可以表示概率得分。

我们必须考虑的另一件事是,当我们将输入要素分类为不同的类时,这些类是互斥的。这意味着每个特征向量 x 只属于一个类别。这意味着作为狗的图像的特征向量不能以 50%的概率表示狗类,也不能以 50%的概率表示猫类。这个特征向量必须以 100%的概率代表狗类

此外, 在互斥类的情况下,所有输出神经元上的概率分数总和必须为 1。 只有这样神经网络才代表了一个合适的概率分布。一个反例是一个神经网络,它以 80%的概率将狗的图像分类到狗类,以 60%的概率分类到猫类。

幸运的是,softmax 函数不仅强制输出到零和 out 之间的范围,而且该函数还确保所有可能类的输出总和为 1。现在让我们看看 softmax 函数是如何工作的。

来源;作者的图像。

假设输出层中的神经元接收输入向量 z ,该向量是当前层的权重矩阵与前一层的输出之间的点积的结果。具有 softmax 激活的输出层中的神经元接收单个值 z1 ,其是向量 z 中的条目,并输出值 y_1

当我们使用 softmax 激活时,输出层中神经元的每个单个输出根据以下等式计算:

情商。7 数学。Softmax 函数的定义。

可以看到,特定神经元的每个值 y 不仅取决于神经元接收的值 z ,还取决于向量 z 中的所有值。这使得一个输出神经元的每一个值 y 都是一个介于 0 和 1 之间的概率值。所有输出神经元的概率预测总和为 1。

这样,输出神经元现在表示互斥类标签上的概率分布。

5.我们应该使用哪些激活功能?

我将用最好的答案来回答这个问题:视情况而定。_(ツ)_/

具体来说,取决于你试图解决的问题和你所期望的输出的取值范围。

例如,如果您希望您的神经网络预测大于 1 的值,那么 tanh 或 sigmoid 不适合在输出层使用,我们必须使用 ReLU 来代替。

另一方面,如果我们期望输出值在范围[0,1]或[-1,1]内,那么 ReLU 不是输出层的好选择,我们必须使用 sigmoid 或 tanh。

如果您执行分类任务,并希望神经网络预测互斥类标签的概率分布,则应在最后一层使用 softmax 激活函数。

然而,关于隐藏层,作为一个经验法则,我强烈建议你总是使用 ReLU 作为这些层的激活。

带回家的信息

  • 激活函数给神经网络增加了非线性特性。这样,网络可以模拟更复杂的数据
  • ReLU 通常应该用作隐藏层中的激活函数
  • 关于输出层,我们必须始终考虑预测的期望值范围
  • 对于分类任务,我建议在输出层专门使用 softmax 激活

你可能错过的激活功能

原文:https://towardsdatascience.com/activation-functions-you-might-have-missed-79d72fc080a5?source=collection_archive---------8-----------------------

提示和技巧

你应该“嗖嗖”一下这些新发明,还是继续使用老掉牙的东西?

如今,机器学习领域的科学进步速度是无与伦比的。很难跟上时代,除非是在一个狭窄的领域。时不时会冒出一篇新论文,声称已经取得了一些最先进的成果。这些新发明中的大多数从未成为默认的首选方法,有时是因为它们没有最初希望的那么好,但有时只是因为它们最终在新出版物的洪流中被淹没了。

错过一些金块是多么可惜啊!别害怕,我会保护你的。我最*浏览了一些相对较新的关于神经网络构建模块之一的论文:激活函数。让我们来看看几个最有前途的,看看他们为什么好,什么时候使用它们。但在此之前,我们将快速浏览一下常用的激活,以了解它们解决或产生了什么问题。如果您能区分 PReLU 和 RReLU,请随意向下滚动前两个部分。

为什么还要激活?

在每个神经网络的单元内,单元的输入与一些权重参数 W 相乘,添加一个偏差 b ,并且结果被馈送到一个函数中,称为激活函数。它的输出又是传递给下一层单元的单元输出。

神经网络单元的内部。图片由作者提供。

激活函数原则上可以是任何函数,只要它不是线性的。为什么?如果我们使用线性激活(包括一个身份函数,意味着根本没有激活),我们的网络将有效地成为一个简单的线性回归模型,无论我们使用多少层和单元。这是因为线性组合的线性组合可以表示为一个线性方程。

这种网络将具有有限的学习能力,因此需要引入非线性。

经典激活函数

让我们快速看一下五个最常用的激活函数。在这里,它们是使用 numpy 实现的。

经典激活函数:numpy 实现。图片由作者提供。

这是它们的样子:

经典激活函数:图。图片由作者提供。

让我简短地讨论一下它们。

在历史上,sigmoid 或逻辑激活是第一个取代早期网络中阶跃函数的激活。根据科学,这大致是用于激活我们生物大脑中神经元的功能。这是一个游戏改变者,因为 sigmoid 的定义明确的非零导数允许使用梯度下降来训练神经网络。从那以后,sigmoid 已经被网络隐藏层中的其他函数所取代,尽管它仍然被用作二元分类任务的最终预测层。

双曲正切(tanh) 在形状上与 sigmoid 非常相似,但是它取值在-1 和 1 之间,而不是 0 和 1 之间。因此,它的输出更集中在零附*,这有助于加速收敛,尤其是在训练的早期。

然而,sigmoid 和 tanh 都有一个共同的问题:它们都是饱和函数。当输入非常大或非常小时,斜率接*零,使得梯度消失,学习缓慢。因此需要非饱和激活。一个成功的故事属于 r 有限线性单元(ReLU) 函数,它不会对正值饱和。它的计算速度很快,由于没有最大值,它防止了消失梯度问题。不过它有一个缺点,被称为将死。问题是 ReLU 对任何负值都输出零。如果网络的权重达到这样的值,当与输入相乘时,它们总是产生负值,那么整个重新激活的单元继续产生零。如果许多神经元像这样死亡,网络的学习能力就会受损。

为了缓解日益严重的 ReLU 问题,已经有人提议对 ReLU 进行一些升级。 Leaky ReLU 对负值有一个小但非零的斜率,确保神经元不会死亡。这种激活函数的一些奇特变体包括随机化的泄漏 ReLU (RReLU) ,其中这个小斜率是在训练时随机选择的,或者参数化的泄漏 ReLU(PReLU),其中斜率被认为是网络的参数之一,并通过梯度下降来学习。

最后,指数线性单位(ELU) 诞生了,击败了所有真正的变种。它吸收了所有世界的精华:负值的非零梯度消除了死亡神经元的问题,就像在 leaky ReLU 中一样,负值使输出更接*零,就像在 tanh 中一样,最重要的是,eLU 在零附*是*滑的,这加快了收敛速度。但是它也有自己的问题:指数函数的使用使得计算相对较慢。

为了方便起见,以下是经典激活的概述:

经典激活函数的比较。由作者编译。

现在让我们来看看最*的一些发明吧!

缩放的 ELU (SELU)

Klambauer 等人在 2017 年的一篇论文中介绍了比例 ELUSELU 激活。顾名思义,它是 ELU 的缩放版本,在下面的公式中选择了两个缩放常数,例如在 TensorFlow 和 Pytorch 实现中。

SELU 函数有一个奇特的性质。该论文的作者表明,如果正确初始化,如果所有隐藏层都是 SELU 激活的,密集的前馈网络将会自我归一化。这意味着每个图层的输出将大致具有等于零的*均值和等于一的标准差,这有助于防止消失或爆炸梯度问题,并允许构建深度网络。该论文在 UCI 机器学习知识库、药物发现基准甚至天文学任务的 120 多个任务上评估了这种自规范化网络,发现它们明显优于传统的前馈网络。

高斯误差线性单位

Hendrycks & Gimpel 在2016 年的一篇论文中提出了高斯误差线性单元,或 GELU,。该函数只是将其输入与该输入的正态分布累积密度函数相乘。由于这种计算非常慢,所以在实践中经常使用一种更快的*似值,这种*似值只有第四位小数不同。

与 ReLU 系列的激活相反,GELU 根据输入值对其进行加权,而不是根据符号对其进行阈值处理。作者针对 ReLU 和 ELU 函数评估了 GELU 激活,发现所有考虑的计算机视觉、自然语言处理和语音任务的性能都有所提高。

嗖嗖

由 Ramachandran 等人于 2017 年在谷歌大脑发明的 Swish 激活功能非常简单:它只是将输入乘以自己的 sigmoid。它在形状上非常类似于 GELU 函数。

该论文的作者注意到,尽管已经提出了许多其他激活,ReLU 仍然是最广泛采用的,主要是因为使用这些新奇事物的收益不一致。因此,他们评估 Swish 的方法是,在针对 ReLU 进行优化的网络架构中,简单地将它作为 ReLU 的替代。他们发现了显著的性能提升,并建议使用 Swish 作为 ReLU 的替代方案。

Swish 的论文还包含了一个有趣的讨论,关于是什么让激活函数变好的。作者指出,上无界、下有界、非单调和*滑是 Swish 如此出色的原因。你可能已经注意到 GELU 也有所有这些属性,我们稍后将讨论的最后一个激活也是如此。看起来这是激活研究的方向。

米什

激活是迄今为止讨论过的发明中最新的一个。它是由 Misra 在2019 年的一篇论文中提出的。米什受到了 Swish 的启发,并已被证明在各种计算机视觉任务中胜过它。

引用原始论文,Mish 是“通过对使 Swish 如此有效的特征进行系统分析和实验而发现的”。Mish 似乎是库存中最好的激活,但请记住,原始论文只在计算机视觉任务上测试了它。

使用哪个激活?

在他的精彩著作《用 Scikit-Learn 和 TensorFlow 实践机器学习》中,Geron 陈述了以下一般规则:

SELU > ELU >泄漏的 ReLU > ReLU

但是有一些问题。如果网络的架构阻止它自我正常化,那么 ELU 可能是比 SELU 更好的选择。其次,如果速度是重要的,(漏)ReLU 将是一个比缓慢的 eLU 更好的选择。但是,这本书没有讨论最*提出的激活。

有一次,我和我的同事,一位前谷歌员工讨论我当时正在做的一个网络架构。他给我的第一条建议是用 Swishes 代替 ReLUs。这并没有改变游戏规则,但尽管如此,性能还是提高了。

基于这一点和我的其他经验,我建议在选择激活时使用以下主观决策树,假设架构的其余部分是固定的。

如何选择激活,作者。

来源

  • Geron A .,2019,第二版,使用 Scikit-Learn 和 TensorFlow 进行机器学习:构建智能系统的概念、工具和技术
  • deepdrive.pl 的图像分类教程(波兰语)
  • 2016,丹·亨德里克斯&凯文·金佩尔,高斯误差线性单位(GELUs)
  • 2017,Prajit Ramachandran,Barret Zoph,Quoc V. Le,Swish:一个自门控激活函数
  • 2017,君特·克兰鲍尔,托马斯·安特辛纳,安德里亚斯·迈尔,塞普·霍克雷特,自归一化神经网络
  • 2019,迪甘塔·米斯拉,米什:一个自正则化的非单调激活函数

感谢阅读!

如果你喜欢这篇文章,为什么不订阅电子邮件更新我的新文章呢?并且通过 成为媒介会员 ,可以支持我的写作,获得其他作者和我自己的所有故事的无限访问权限。

需要咨询?你可以问我任何事情,也可以在这里 为我预约 1:1

你也可以试试我的其他文章。不能选择?从这些中选择一个:

</6-useful-probability-distributions-with-applications-to-data-science-problems-2c0bee7cef28>

7+强化学习竞赛将于 2022 年结束

原文:https://towardsdatascience.com/active-and-upcoming-reinforcement-learning-competitions-8ed3c4fb14ab?source=collection_archive---------23-----------------------

一份正在进行的年度竞赛清单,适合通过强化学习获得实践机会(同时赢得一两个奖项)。

sk 在 Unsplash 上拍照

强化学习 (RL) 是机器学习的一个子域,涉及代理通过与他们的环境交互来学习做出决策。虽然像 Kaggle 这样的流行竞赛*台主要适合监督学习问题,但 RL 竞赛更难获得。

在这篇文章中,我整理了 7 个适合 RL 的正在进行的年度比赛。

对于不一定是为 RL 量身定制的 AI 比赛,你可能会感兴趣的是列表 14 个活跃的 AI 游戏比赛

1. AWS DeepRacer (2018 年——正在进行的比赛)

AWS DeepRacer 联赛流(作者截图)

AWS DeepRacer 是一款对初学者友好的 3D 赛车模拟器,旨在帮助开发者入门 RL。参与者可以在亚马逊 SageMaker 上训练模型(前 10 个小时是免费的),并以正在进行的 AWS DeepRacer 联盟的形式参加每月的比赛。

AWS DeepRacer 联赛以计时赛的形式进行(尽管还存在其他挑战,如短兵相接的比赛)。顶级赛车手赢得奖品,包括商品、定制和前往拉斯维加斯参加锦标赛杯 AWS re:invent 的付费旅行。参与者还可以赢得或花 399 美元购买一辆 1/18 比例的赛车,在现实世界中测试他们的模型。

2.人工智能竞技场 (2016 年——正在进行的比赛)

AI Arena 网站(作者截图)

你可能还记得 AlphaStar 在 2019 年达到特级大师地位并击败两名世界顶级星际争霸 2 玩家的时候。星际争霸 2 最初是由暴雪在 2017 年开源的,以加速高度复杂环境中的人工智能研究。

你仍然可以在 AI 竞技场 的社区参与训练星际争霸 2 中的深层 RL 特工。他们运行一个持续的排名阶梯,在那里你可以与其他团队直接竞争。比赛是 24/7 直播到 Twitch,偶尔有社区流事件。

对于原版星际争霸,你也可以查看:

  • SCHNAIL :人类 vs 人工智能比赛
  • SSCAIT :学生星际 AI 锦标赛

3. Bomberland (2020 年——正在进行的比赛)

图片作者。

炸弹人 是我们自己基于经典主机游戏《炸弹人》打造的机器学习竞赛。参与者建立代理人,导航 2D 网格世界收集皮卡和放置炸丨药放倒对手。参与者与其他团队面对面竞争,并在实时排行榜上排名。

Bomberland 环境对于开箱即用的机器学习来说是具有挑战性的,需要规划、实时决策以及在对抗和合作游戏中导航。

比赛目前正在直播,顶级团队赢得的奖品包括 1000 美元的现金奖金池、定制商品以及 2022 年 3 月举行的决赛 Twitch livestream 上的一个专题节目。

4.*地 (2019 —,年度比赛)

*地 是一年一度的竞赛,是 NeurIPS 2020 的一部分。它旨在解决在复杂的铁路网络上有效管理密集交通的问题。目标是构建最佳时间表,使所有列车的要求到达时间的延迟最小化。

2021 年的比赛目前正在 AICrowd *台上进行。根据在受控环境中累积的总奖励对提交的内容进行评估和排名。鼓励 RL 方法,为 RL 提交提供单独的奖励途径。往年的奖品有无人机和 VR 头戴设备。

5.米纳尔 (2019 年——年度比赛)

MineRL 关注样本高效深度 RL 算法的开发,该算法可以使用《我的世界》的人类演示来解决分层、稀疏的奖励环境。

参与者可以访问《我的世界》超过 6000 万帧记录的人类球员数据的大型模仿学习数据集。目标是开发能够完成任务的系统,例如获得钻石、建造房屋、寻找洞穴等。

该比赛从 2019 年至 2021 年一直作为 NeurIPS 的一部分在 AICrowd 上进行。奖品包括合著作品和超过 10,000 美元的现金。

6.网络黑客 (2020 年——年度比赛)

NetHack 是在 AICrowd 上举办的 NeurIPS 2021 的另一项年度比赛。团队竞争建立最好的代理来玩 NetHack,一个 ASCII 渲染的单人地牢爬行游戏。NetHack 的特点是程序生成的关卡,有数百个复杂的场景,这使得它成为当前最先进的 RL 的一个极具挑战性的环境。

像 Flatland 和 MineRL 一样,提交的内容在一个排行榜上根据受控测试环境中的分数进行排名。今年的比赛设有 20,000 美元的现金奖金池。鼓励 RL 方法,但也接受非 RL 方法。

7.编译馆 (2021 —,排行榜)

CompilerGym 其实是一个将强化学习应用于编译器优化的工具包,而不是竞赛。但是,用户可以向公共回购排行榜提交算法以及他们的报告和结果。

奖励:竞争*台和会议

我将正在进行的或定期进行的比赛列为该列表的优先项目。跟踪跑步比赛的另一个好方法是跟踪他们参加的比赛*台和会议。这里有一些值得你关注的:

  • AICrowd :管理 ML 竞赛和 RL 竞赛的组合。
  • Kaggle :主要是监督 ML/数据科学比赛,但也有特色的模拟比赛可以很好的解决 RL 的问题。
  • NeurIPS :每年一次的大会,有各种机器学习比赛的比赛赛道。
  • IEEE CoGs :有竞赛赛道的年度会议,专门针对游戏方面的研究。

结束语

我希望这个列表能帮助你找到一个有趣的竞赛来检验和练习强化学习。随着新的比赛来来去去,我会努力保持这个列表的更新。祝你好运!

主动学习在统计学和 R 中应用的探索性研究

原文:https://towardsdatascience.com/active-learning-an-exploratory-study-of-its-application-in-statistics-and-r-65713ccdad16?source=collection_archive---------7-----------------------

我们如何利用少量的标记数据集并实现最大化?

介绍

在这篇文章中,我们的目标是在 R 中实现一些基线主动学习策略,在一个著名的数据集 Iris,上进行实验,强调一些见解,并提出统计领域中主动学习的未来方向。

什么是主动学习?在机器学习的许多现实情况下,未标记的数据可以以很低的成本获得。尽管如此,仍缺乏标记数据,手动标记这些数据既昂贵又耗时。这推动了主动学习的发展,在主动学习中,学习算法可以交互式地查询 oracle(用户或领域专家)以给新数据贴上合适的标签。在统计学文献中,主动学习也被称为“最优实验设计”。

主动机器学习。鸣谢:受张懿主动学习幻灯片的启发。

主动学习的一个著名例子(鸣谢:图片来自 Burr Settles' 主动学习)

在过去的十年中,许多成功的主动学习查询技术被开发出来,并被评估为具有竞争力。但是几乎都是基于 Python 环境的(比如包 modAL 和 Libact ),主要用于计算机科学行业。

在一般的数据科学领域,R 也是一种常用的语言,尤其是统计学家。可惜没有可用的主动学习的 R 包(一个老的,“ activelearning ”,5 年前就过时了)。当 R and R 工作室为统计学习构建一个用户友好*台时,我们想看看 R 是否能同样使主动学习变得*易*人。

更重要的是,我们认为主动学习可以是一个跨学科的领域,邀请统计学家做出贡献。在我们开始实验之前,我们想快速概括以下关于主动学习的统计术语:

采样。我们将介绍两种常见的基线抽样方法,包括随机抽样。

最优实验设计。主动学习旨在达到最小的实验成本。

回归模型。我们将使用逻辑回归模型在 Iris 数据集上执行分类任务。

D 数据集和预处理

为了清晰和简单,我们将使用一个著名的机器学习数据集: Iris 。Iris flower 数据集是由著名的统计学家和遗传学家罗纳德·艾尔默·费希尔爵士引入的多元数据集。鸢尾包含三个类别标签: setosa、virginicaversicolor。每个类别标签有 50 个数据条目。每个条目有四个关于花瓣和萼片的宽度和长度组合的特征。

鸢尾花的形态测量。来源

Iris 类别标签和特征的插图。来源

降维

为了构造二元分类问题,我们首先对虹膜数据集进行主成分分析。前两个主成分解释了 95.81%的方差。此外,它显示了" setosa "群体与其他两个群体之间的明显区别。LFDA 图也证实了这一发现。有两个完全分离的类,意义会小一些。因此,我们从“versicolor”(绿色)和“virginica”(蓝色)组中选择数据条目来构建二元分类问题。

虹膜上的 PCA 和 LFDA 图(来源:安迪的 GitHub 教程

变量选择

我们希望选择两个特征,并使用二维图来说明主动学习如何实现可视化。“花瓣。长度”和“花瓣。宽度”是理想的选择,因为它们对于“杂色”(红色)和“海滨”(绿色)组来说有适度的交叉。

Iris 上的特写图(来源:安迪的 GitHub 教程)

最后,我们有一个适当的预处理数据集用于主动学习。我们在整个数据集上训练一个逻辑回归分类器,并使用这个决策边界作为基础事实。这两个组不能使用线性决策边界完全分开。

(来源:安迪的 GitHub 教程)

模拟

我们将这 100 个点分成两部分:池和测试集(80:20)。然后,我们将池分为被标记的初始训练集和未标记的池(10:70)。数据集的两种分割都依赖于随机状态。

我们通过在这 10 个点上训练初始逻辑回归分类器来开始主动学习过程。迭代 0 的结果(测试集在右图中标记为黄色点)表明决策边界偏离地面真值很多,这是合理的,因为我们只从一个小的集合开始。

在主动学习的每次迭代中,我们基于不同的查询策略查询一个点,将其添加到训练集并重新训练 logistic 回归分类器。我们将使用以下两种基本策略:不确定性采样:我们选择置信度最小的点,即最接*当前决策边界的点,以及随机采样:我们从无标签池中随机查询该点。

不确定抽样

对于通过不确定性采样策略进行查询的迭代 1 至 3,蓝色菱形符号标记每次迭代中查询的点。我们可以看到,预测线与最初查询的样本相比变化很大。这符合不确定性抽样的逻辑,因为我们期望它带来最多的信息,并极大地改变我们的模型。

主动学习(不确定性)迭代 1 到 3

然而,我们也注意到一些被查询的样本可能实际上并不有用。例如,第二个查询样本使预测边界变得更差,并降低了分类精度。

主动学习(不确定性)迭代 10 和 30

在迭代 10 中,逻辑回归的决策边界接*地面真实。在第 30 次迭代中,中心点、关键点和信息量最大的点都被查询,预测边界几乎是固定的。我们使用一个较小的训练集来实现一个相当好的分类模型。

随意采样

我们使用随机抽样策略进行了类似的实验。初始状态不会改变。但是,每次迭代查询哪个点和不确定性采样完全不同。迭代 1 至 3 和 10 以及 30 的类似曲线也在下面给出。

主动学习(随机)迭代 1 到 3 次

主动学习(随机)迭代 10 和 30

我们可以看到点是随机选取的(蓝色菱形点),决策边界没有太大变化。即使在第 10 次迭代中,预测边界看起来仍然远离实际情况。显然,随机采样比不确定性采样收敛得更慢,并且需要更多时间才能达到相同的分类精度水*。

洞察力:不确定性与随机性

随机采样并不保证是最优的,因为它并不关注所查询的实例是否为训练的分类器提供了新的信息。由于它是任意的,实现起来相当快速和简单,随机抽样通常被用作不同查询策略的最常见基准。问题是,不确定性抽样总是比随机抽样好吗?

事实上,随机抽样是一种合理的竞争策略,没有任何主动学习方法可以防止比随机抽样更差的表现。尽管普遍认为应该存在*均来说至少与随机采样一样好的主动学习技术,并且在大多数情况下应该优于随机采样。然而,这经常与来自真实世界环境的经验评估相矛盾。

这仍然是一个悬而未决的问题。在过去的十年中,大多数研究论文集中在提出新的、新奇的和*衡的主动学习技术。而有限的工作试图研究为什么随机抽样实际上如此具有竞争性。在主动学习领域,寻找一种安全又有效的主动学习方法仍然是一个具有挑战性的问题。

主动学习:R 与 Python

我们还在 Python 中实现了类似的主动学习工作流。由于列表和 Pandas.dataframe 操作的简明性,它只需要大约 1/4 的代码。不足为奇的是,无论是从最终的结果还是见解来看,都没有显著的差异。此外, ggplot2matplotlib 都让可视化变得简单。

Python 中主动学习的例子(来源: Andy 的 GitHub 教程)

尽管我们的实验很简单,并且基于一个玩具数据集,但是与 Python 相比,用 R 实现这些主动学习技术看起来并没有那么残忍。在 KDD2018 研讨会“使用 R 和 Python 进行大规模的主动学习和迁移学习”中,作者还使用 R 和 Python 提供了两个主动学习的优秀示例。他们声称“我们的练习将强调这些语言之间的互操作性,以便我们可以使用两种环境来实现共同的目标”。

那么为什么不是 R ?如果我们回到我们推论的起源,这个问题是可以解释的:主动学习仍然是一个没有建立安全技术的成长领域。不能保证比随机抽样更好,解释和使用随机性仍然是一个公开的问题。大多数开发的方法都声称克服了这种限制,但是当使用不同的真实世界数据集和/或分类模型在 Python 中进行测试时,通常表现出矛盾。在这种情况下,不太需要在 R 中实现相同的实验来获得令人沮丧的支持。

另一方面,我们仍然看到在 R 中引入主动学习并进一步邀请统计人员做出贡献的巨大潜力。目前,R 中没有可用的主动学习包。实施一些有代表性的主动学习方法并将其引入 R 社区可以成为统计学硕士和博士生贡献的一个极好的主题。从最初的尝试来看,我们没有发现它有什么特别棘手的地方。同时,由于主动学习属于最优实验设计,我们相信有经验的统计学家可以帮助解决主动学习中的开放性问题,例如我们之前讨论的随机抽样问题。主动学习仍然是一个不断发展的领域,跨学科合作的前景令人振奋。

摘要

在这个简短的演示中,我们用两个基线方法开发了一个简单的 R 主动学习管道,灵感来自于几乎所有现有的主动学习方法都是基于 Python 环境的背景。首先,我们形象化地展示了不同的主动学习方法是如何工作的,以及分类器在每次查询迭代中是如何改进的。尽管有这些观察,我们提出了一些在 R 社区发展主动学习的有希望的方向,并留下一些开放的问题来鼓励统计学家做出跨学科的贡献。

杂项(其他来源)

所有的脚本和源代码都可以在我的 GitHub repo 中找到。此外,我为初学者提供了一个简短的演讲(也有幻灯片)来快速学习主动学习。如果你喜欢这些材料,请留下一颗星,非常感谢!

大规模主动学习—构建强大的数据统一框架

原文:https://towardsdatascience.com/active-learning-at-scale-building-a-robust-data-unification-framework-fd9084a139d5?source=collection_archive---------16-----------------------

通常,这与模型无关,甚至与数据本身无关,而是与持续运转的引擎有关。

作者图片

Nauto 是先进驾驶辅助系统的领先供应商,该系统改善了当今商业车队和未来自动驾驶汽车的安全性。为此,我们每月处理万亿字节的驾驶数据,这些数据是由安装在挡风玻璃上的设备从世界各地的车辆上收集的。这些数据用于不断改进支持我们车辆安全堆栈的模型,从部署到我们设备的实时预测碰撞警报,到运行在云上的安全分析。数据驱动一切。

除了为驾驶员提供即时的安全价值,我们的功能还在塑造他们自身发展方面发挥着重要作用。

如果我们想提高车辆检测向前行驶碰撞预警(FCW),我们首先要考虑的是 FCW 触发的误报。行人和 PCW 也是如此。随着时间的推移,每个功能都建立了自己的定制数据集,包括相关示例和有趣的边缘案例,然后在训练过程中反馈到底层模型中。这一闭环形成了一个非常强大的数据引擎的基础,推动我们所有功能的持续改进。

问题是

问题是,多个功能通常由一个型号提供。对我们来说,一个单一的多类物体探测器的权力尾随,FCW 和 PCW。虽然从计算的角度来看这很棒,但这让训练变得有点复杂。

让我们以 FCW 为例。假设它已经部署了一段时间,并且已经收集了相当大的涉及领头车辆的风险事件数据集。我们注意到,它的误报主要源于未能定位形状奇怪的车辆,因此我们对这些事件进行采样,用高质量的车辆边界框对它们进行注释,并建立一批由 50k 图像组成的新训练数据。

问题是,我们不能简单地将这批新车辆添加到现有的多类数据集中。这样做会不公*地惩罚正确检测的模型,比如说行人或红灯,在一个只为车辆标记的例子中。该模型最终通过一个损失函数进行优化,该函数将其预测与地面真实情况进行比较。在这个例子中,损失函数不会区分不存在的对象和只是碰巧没有被标记的对象。我们不能只是将一堆部分标记的数据集连接在一起,否则会导致不公*、混乱的训练。

幸运的是,我们有几个选择。

注释所有数据集的所有类。

最显而易见的解决方案就是手工给所有东西贴上标签。如果我们的模型检测到行人、车辆和交通信号,那么每一批新的训练数据都必须在整个类别分类中进行注释——不管它来自哪个特征。

第一个问题是可扩展性。在 Nauto,我们的核心物体检测器可检测 5 个主要任务中的 20 多个类别,并且还在不断增加。使用这种方法,我们不仅需要通过车辆标注工作流运行单批 FCW 数据,还需要运行行人、交通信号、车道检测等数据。工作流程也是如此。

总的注释工作量随着以下因素的变化而成倍增加:

 **#_annotations = (#_examples) x (#_tasks)**

这很快变得不切实际,尤其是当你考虑到当我们决定增加一个新任务时会发生什么,比如交通锥检测。不仅新的交通锥数据需要用我们所有 5 个现有任务的类进行注释,而且我们现有数据集中的每一个例子都必须用交通锥进行反向标记

作者图片

第二个问题是无关紧要。我们来自 FCW 的新一批 50k 图像可能会包含许多形状奇怪的车辆的有趣例子,这将大大提高车辆检测。但是很有可能不会有很多行人。即使有,它也肯定不会包含那么多相关的边缘案例,比如形状怪异的行人——因为这些图像来自 FCW,而不是 PCW。然而,我们必须通过两个注释工作流运行这些 50k 图像。

在每个标记任务的预算和资源有限的情况下,这种强力方法会在除了一个检测任务之外与所有检测任务都不相关的例子上快速吃掉我们的整个标记带宽。

因为总注释的数量成倍增长,而相关的、特定于任务的注释的数量呈线性增长,所以随着时间的推移,随着我们添加更多的任务,不相关注释的整体比例只会增长。

利用自动标记。

一个更具可扩展性的解决方案是利用我们现有的模型来填补缺失的标签。在我们新的一批 FCW 数据中,我们将只手动标记相关的车辆类别,并调用我们现有的检测器集合来填充行人和交通信号类别。

最棒的是,这些“自动贴标机”不受我们的生产模式在设备上面临的任何限制。它们可以运行在强大的云 GPU 上,它们可以离线运行而没有延迟限制,它们可以利用在某个时间点之前和之后收集的数据。他们也可以是专家;如果这意味着比多任务模型更好的性能,那么每个任务都可以有自己专门的自动标注器。

作者图片

相对于强力方法的优势是显而易见的;人类可以专注于为每个任务中最相关的示例制作高质量的标签,而机器可以填充剩余的不太相关的数据。有了本月标记 10 万张车辆和行人图像的预算,我们可以用有趣的车辆标记 5 万张 FCW 的例子和用有趣的行人标记 5 万张 PCW 的例子——而不是全部花在前者上。剩下的就交给我们的模特了。

缺点是我们在标签中引入了噪声。虽然人类不是完美的贴标机,但模型通常不太一致。使用这种方法,我们的数据集将总是包含有噪声的、机器制造的标签的子集。

此外,对于每一个添加的新任务,所有任务中噪声标签与干净标签的比例都会增加。

这是因为我们实际上并没有降低第一种方法的乘法复杂度,只是简单地将负载从人转移到机器。用“人”代替“相关的”,用“机器”代替“不相关的”,关系就清楚了。

这里有一个例子。假设我们希望将新的锥形检测任务合并到现有的 100k 图像的车辆和行人数据集,因此我们添加了一批新的手动标记有交通锥的 10k 图像。现在,我们必须对新 10k 批次中缺失的车辆行人进行机器标记。但是我们还必须对原始数据集的所有 100k 张图像中未标记的交通锥进行同样的处理。最终,我们增加了训练集中人类标签的数量——但没有将机器标签的数量增加一个数量级。

使用部分损失函数。

也许最优雅的方法不是将部分标记的数据建模为与我们的损失函数兼容,而是将我们的损失函数建模为与部分标记的数据兼容。

作者图片

这样的损失函数需要在每个例子中区分不存在的对象和只是碰巧没有被标记的对象。然后,它将简单地反向传播被标记的类的损失。对于一个给定的例子,对一个碰巧未被标记的物体的任何正确检测都不会受到不公*的惩罚。

修改损失函数而非数据的明显优势在于,我们将前两种方法所面临的复杂性从乘法缩减为加法。

有了我们新的一批 FCW 数据,我们只需给车辆贴上标签就可以了!当这些示例在训练期间被采样时,损失函数将仅针对其车辆预测惩罚模型,而不是其他。当添加新的检测任务时,我们不需要用新标签回填现有数据集。我们的数据集 100%相关,100%无噪声。

唯一的挑战是如何建立这样一个损失函数。令人惊讶的是,很少有文献涉及这个主题,开源代码就更少了。还有一些问题需要考虑,例如如何对损失进行归一化,由于一些例子被最低限度地标记,而另一些例子被高度标记,损失的幅度现在可能会有很大差异。

构建数据统一框架

考虑到这一点,我在四月份的目标是构建一个框架来支持我们数据的快速增长的复杂性。我们在 Nauto 的团队一直在积极进行持续的模型改进,但当时我们特别积极——准备将 3 个全新的检测任务集成到我们的核心对象检测器中。

作为该模型的所有者,我刚刚开始意识到我现有的工作流变得不可扩展的速度有多快。到那时,我已经利用自动标记来统一我们的数据集,并且刚刚完成了我的第一个部分损失函数的工作版本。但是我仍然手动操作。我没有正式的流程来跟踪这些部分数据集、最终的统一数据集或用作自动标注器的模型。每当我们需要合并一批新的带标签的数据时,我就想方设法弄清楚什么需要用什么来自动标记,并手动安排推理作业。

我真正想要的是一个灵活、用户友好的框架,它能够:

  • 支持部分损耗&自动贴标。
  • 抽象出统一过程的复杂性。
  • 跟踪和维护我们不断增长的特定任务数据集、自动贴标机和统一数据集。

我最后整理出来的东西大概是这样的:

作者图片

我将简要介绍一下核心部分:

组件数据集

这些是部分标记的特定于任务的数据集,构成了统一框架的构建块。在统一过程中,我们不仅可以指定包含哪些任务,还可以指定包含哪些任务的哪些批次。

当一批新的 PCW 数据从行人标签队列中出来时,我们只需将其注册在配置文件的“行人”部分。现在可以统一了!

自动贴标机

如果选择自动贴标作为统一方法,这些是可供我们使用的专业型号。对于每项任务,我们必须从一组训练好的模型中挑选一个自动贴标机,并使用其预先优化的阈值集或用新值覆盖它们。在数据统一过程中,这些阈值将决定哪些模型预测将被用作基本事实,哪些将被丢弃。

注意,对于我们从组件数据集中包含的每个任务,我们还必须选择一个相应的自动贴标机。例如,我们不能选择车辆:[b6]行人:[B1–4,b5]【T3]作为数据集,而只能选择一个车辆自动贴标机,因为车辆:b6* 将无法填充其缺少的行人标签。*

作者图片

根据设计,每项任务的最准确、最*训练的模型将总是被推到堆栈的顶部。每个模型还会列出本身被训练的数据。这两种方法可确保我们始终在任何时间点最大限度地提高机器标签的准确性,并确保我们完全了解最终生成这些机器标签的原始训练数据。注意,我们甚至可以使用过去在统一数据上训练的生产模型作为当前迭代的自动标注器。

编制资料

要编译新的统一数据集,只需指定要包含的所需组件数据集、统一方法(部分丢失或自动标记)、要用作自动标记器的模型(如果选择该选项)以及输出路径。就是这样!该框架将统一数据,并以 TFrecords 的形式将其转储出来,以便立即进行生产模型培训。

然而,根据所选择的统一方法,幕后发生的事情会有很大的不同。

在部分丢失的情况下,组件数据集基本上只是被连接和丢弃。唯一的警告是,对于每个示例,标记的类都被记录下来并注册在 TFrecords 中。这是为了以后,当训练循环提取该特定示例时,它将知道只反向传播属于该组标记类的检测的损失,而不惩罚其他任何东西。

作者图片

相比之下,自动标注由于其复杂性而更加复杂。对于每个组件数据集,我们必须使用自动贴标机为除数据集所属任务之外的所有任务运行推理。假设我们想要统一跨越 4 个任务的 5 个组件数据集(因此有 4 个自动贴标机)。对于每个组件,3 个独立的自动贴标机必须运行推理来生成缺失的标签,总共 5 x 3 个推理作业。更一般地说,推理工作负载的比例为:

 **#_inference_jobs = (#_component_datasets) x (#_tasks — 1)**

这应该感觉很熟悉,因为它基本上重新表述了完全人为标记的方法的复杂性等式。令我难以置信的是,即使对于在服务器级 GPU 上一分钟生成 1000 个预测的模型,仅通过少数几个任务就可以感受到这种工作负载的巨大规模。我最*在 5 个任务上编译了大约 100k 个示例,花了几个 GPU 小时才完成。想象一下用人力来做这件事吧!

结果

当我开始这个项目时,我的第一个问题是——我相信你现在也有了——哪种方法会产生更好的模型?由于有多少变量在起作用,这实际上是一个相当复杂的问题:与组件数据集的数量相比的任务数量、自动标注器的准确性、使用的阈值、损失函数的实现等等。我还没有足够的时间进行足够多的控制实验来真正回答这个问题,所以我不会假装回答。但是我将分享我的一些有限的发现,我觉得这些发现很有趣——我希望你也会感兴趣。

从理论的角度来看,我几乎可以肯定,部分损失将严格优于自动标记。部分损失允许 100%无噪声的、人类标记的数据集,该数据集应该训练比被有噪声的机器标签污染的模型更准确的模型。从实用的角度来看,它还有在几分钟而不是几小时内编译的好处。

这就是为什么我如此惊讶地发现事实正好相反:

试验 1:在行人&车辆的实验数据集上与基线相比较的统一方法。这里,基线运行使用部分标记数据的默认损失。图片作者。

首先要注意的是,在对部分标注的数据集进行训练时,使用部分损失函数比默认损失的精度高得多。这看起来很棒,有几个原因。首先,它验证了整个框架旨在解决的中心问题:在部分标签的数据集上进行天真的训练是次优的,因为它不公*地惩罚了对未标记对象的正确预测。从实践的角度来看,这也验证了我的部分损失函数的实现——到目前为止,我只进行了最低限度的测试。

有趣的是,在所有三个类别中,自动标记的表现都优于部分损失。出于好奇,我做了更深入的研究:

试验 1:部分损失&自动标记基线的改善,以及每类自动标记比率。图片作者。

在这里,我绘制了每个类别的“自动标记比率”——嘈杂的机器标签与干净的人类标签的比率。虽然自动贴标在所有类别中都优于部分损失,但随着机器贴标比例的增加,其领先优势逐渐缩小。对于行人,机器标签比例最低的类别(8%),自动标签领先超过 2% F1。但是对于其他车型,一个机器标签比例更高的级别(21%),差距缩小到 0.67% F1。一个假设是,自动标注的比例越大,拥有完整标注相对于部分标注的好处就越小,这是因为地面真实中的噪声越来越大。很自然的问题是,如果自动贴标率足够高,领先优势是否会翻转。

试验 2:在具有 5 个任务的实验数据集上比较统一方法。为了保持一致,只显示了两个原始任务(车辆&行人检测)。图片作者。

原来答案是肯定的!通过将数据集从 2 个任务扩展到 5 个,我能够显著提高所有类的自动标记率。在新的试验中,在所有类别中,部分损失最终胜过自动标记。

虽然这一发现确实为我们的假设增加了一些支持,但它也提出了一些其他问题。例如,为什么部分损失销售线索不会随着自动标签比率的提高而增加?部分损失在自动标签百分比最低的行人类别中领先 4%,在自动标签百分比超过两倍的其他车辆类别中仅领先 1%。如果我们的假设是真的,那么我们不应该也看到部分损失的好处随着噪音数据集的增加变得更加明显吗?

一种解释是,我们忽略了一个重要的变量:自动贴标机本身。自动标注数据集中的噪声是自动标注器的精度和它对地面真实数据集贡献的标注分数的函数。考虑到这一点,当我们考虑到我的行人自动贴标机远不如我的车辆自动贴标机准确时,我们的发现就更有意义了。这部分是因为行人检测在 Nauto 是一项更新的任务,部分是因为行人比车辆更难定位。

我们可能还忽略了另一个相关变量:数据集大小。第一个实验数据集相当小,迄今为止,行人的人类标签份额最小,其次是车辆,然后是其他车辆。第二个数据集要大得多,最明显的是包含了大量的普通标签。有人可能会说,在第一次试验中,自动标记为缺乏标签的行人任务提供了巨大的好处——增加了标签的总数,并使其更接*收敛。到第二次试验时,由于人类标签的基础更加坚实,这种好处缩小了,事实上,由行人自动贴标机引入的越来越多的噪音超过了这种好处。

前进

显而易见,现在仍有大量未解决的研究问题有待探索。令人欣慰的是,这样一个统一的框架使得这类实验运行起来没有痛苦,并且随着时间的推移可以跟踪。最棒的是,因为统一过程本身被抽象掉了,我们可以在不中断或复杂化用户工作流的情况下修改不同的优化。以下是我希望今后能够实现的一些改进:

软自动标记

实际上有第三种统一方法。我们可以用置信度来衡量任何自动标签,而不是像对待人类标签一样对待它。这将对象标签从二进制[0 或 1]变为连续的[0 到 1],其中人类标签将始终被赋予权重 1,而机器标签将属于低于该权重的分布。

这种方法背后的直觉是,并非所有的自动标签都是*等的;有的会比较自信从而准确,有的会不太自信从而吵闹。虽然默认的“硬”自动标记将对所有高于阈值的机器预测一视同仁,但“软”方法将根据准确的可能性来调整每个预测。因此,在训练过程中,错过权重为 0.95 的自动标记对象的模型将受到惩罚,就像它错过了人类标记的对象一样。相比之下,错过 0.45 权重的自动标签的模型将不会受到几乎同样严厉的惩罚,因为标签不可靠的可能性更大。

我们仍然可以实现阈值来过滤垃圾预测,但是选择不再像标签不再是二元的那样重要。我们还可以在分配权重时实现一个归一化函数,以考虑不同模型体系结构中置信度得分分布的变化。

这种方法感觉很有前途,因为它允许我们利用我们的自动贴标机产生的高质量、有用的注释,同时以一种机制来减轻嘈杂、有害的标签的影响。

贮藏

目前,每次编译新的统一数据集时,都是从头开始。对于自动标记,这可能是一种浪费,因为我们的数据会随着时间的推移而逐渐增加;很有可能新编译的大部分预定推理作业之前已经运行过。解决方案是简单地将每个推理作业缓存为完全注释数据的构建块——使用自动标注器的 id 和组件数据集作为签名。如果将来安排了完全相同的签名,我们只需从缓存中提取,而不是重新运行推理。

以存储少量文本注释为代价,这样的缓存可以节省我们大量的时间——将编译新的自动标记数据集的周转时间从几小时缩短到几分钟。

并行化

同样,自动标记过程可以很容易地在许多 GPU 上并行化——通过批处理或推理作业。这应该是不言自明的,实现起来也很简单,所以我就不赘述了。同样,好处是缩短了编译时间,以便尽快开始培训。

最后的想法

我最初开始这个项目只是为了自动化一个很快变得不可扩展的手动任务:将越来越多的特定于任务的数据集统一到我们的模型可以在上训练的东西中。现在回想起来,如果不在 6 个月前投资这样一个框架,我不可能支持 3 个新探测任务的启动。从这个意义上说,我已经看到这项投资的回报了。

作者图片

展望未来,我希望这个统一框架能够支持主动学习引擎,推动我们不断改进现有功能并推出新功能。在这个扩展的循环中,我们不仅在重复我们收集的数据和部署的模型,还在重复我们统一这些数据的过程,以及推动这一过程的幕后模型。关键是这个过程是健壮的、自文档化的,并且是固有的迭代。Nauto 必须能够继续以积极的步伐扩展其安全产品和人工智能能力——不受规模和复杂性问题的限制。

在 AI 领域,持续改进是必须的,而数据是这一切的核心。拥有一个驱动高效数据收集和数据监管的引擎至关重要。当我开始我的职业生涯时,我假设人工智能是关于建立最好的模型。然后我开始意识到这是关于建立最好的数据。但是我现在开始意识到这实际上是关于建立最好的过程。因为一旦你有了一个使迭代变得毫不费力的过程,其他的一切都会随之而来。

(贝叶斯)神经网络的主动学习

原文:https://towardsdatascience.com/active-learning-for-bayesian-neural-networks-b8471212850f?source=collection_archive---------25-----------------------

杰瑞米·拉帕克在 Unsplash 上的照片

训练机器学习模型可能很难,尤其是在使用神经网络时。有时候,即使是最好的超参数和最干净的数据也达不到我们想要看到的结果。在这一点上,需要额外的训练数据,并且也可能提高模型的性能。毕竟,收敛速度主要取决于观察数据点的数量,对吗?现在可以选择向模型中扔更多的数据,并希望得到最好的结果,但是有一种更有效的方法来完成这个数据选择任务。在机器学习中,这被称为主动学习。

主动学习方法指导数据选择过程。它们添加最少的数据点,同时最大限度地提高模型的训练效果。把主动学习方法想象成一个神谕,告诉你应该在哪些额外的数据点上训练模型。主动训练模型可以证明将额外数据点的数量以指数方式减少(!)量(相比只是随机加点)。这非常强大,在很多情况下比你想象的更有用。我们将在下面讨论一些例子。

在这篇博文中,你将了解到:

  • 最常用的主动学习框架(基于资源库)
  • 主动学习有用的应用场景
  • (贝叶斯)神经网络与高斯过程的联系
  • 一种适用于所有神经网络的优雅主动学习技术

这项技术的想法源于这篇论文。在我的论文中,我使用了他们的方法,甚至改进了它(一点点)。这是我尝试分享我在过去一年中所学到的东西。我会解释更多关于我的贡献,并在后续文章中提供数学公式。

!我论文中的示例代码可以从 GitHub 获得。!
!你可以在这个链接下找到我的论文。!

主动学习框架

让我们首先了解在主动学习中我们想要解决哪个问题。(我们考虑基于池的变体,有关更广泛的概述,您可以查看第 2 章此处。)一般来说,我们首先在一些训练数据上训练一个模型。**主动学习方法然后选择额外的数据来丰富训练数据。**最后,恢复模型训练。

考虑下面的 GIF 作为例子。在第一帧中,我们得到了一些标记的训练点(黑点)。标有的意味着我们不仅知道 x 轴上的位置,还知道 y 轴上底层函数的真实值。我们在第二帧(黑线)的这些训练点上拟合一个神经网络。到目前为止,这是监督回归。**

现在主动学习开始了。为此,我们需要一组未标记的数据点,称为池。未标记的数据通常很容易获得:想想没有描述的图像,或者在这种情况下只是 x 轴上的随机数(用蓝色表示)。主动学习方法从池中选择最有希望的数据点。它们被标记(label=y 值)并添加到训练数据(蓝点)中。最后,在所有数据点上对模型进行训练,这在这种情况下会带来很大的改进。

回归任务的主动学习:在初始网络(黑线)在一些点上被训练之后,从池(蓝色)中选择额外的点,添加到训练数据并用于改进模型。作者 GIF

什么时候适用主动学习?

当然,有可能为池中的点获得附加标签是必不可少的。这听起来很难实现,但事实上它比你想象的更加可行。

经典的例子是图像分类。在这里,一个未标记的数据点是一个图像,你可以简单地自己对它进行分类。

主动学习也适用于真正的大数据。有时,对所有可用数据进行培训已经花费了太多时间。在这种情况下,您可以从一个小的子集开始,让主动学习方法决定大集合中的哪些数据是相关的。我在分子数据集上使用这个想法取得了一些成功,在这个数据集上我训练了一只 T21。

另一个主要的例子是应用程序,标签可以在运行时计算。当使用神经网络对工程或材料设计的复杂过程进行建模时,这种情况经常发生。在这种情况下,标签是(耗时的)计算机模拟的结果,而主动学习有助于战略性地投资计算资源。

在我的论文中,我考虑了的这项工作,其中一个偏微分方程(PDE)用一个神经网络来求解,标签可以通过运行另一个算法来获得。

什么是贝叶斯神经网络和高斯过程?

为了理解有目的的主动学习技术,我们必须简要地谈论贝叶斯神经网络(BNNs)和高斯过程(GPs)。两者都是非常有趣的机器学习模型。最后,最终的技术可以用于任何可以使用 Dropout 的神经网络。

经典(左)和贝叶斯神经网络(左)。在贝叶斯版本中,权重是分布。这是这篇论文 [1]中的一个可视化图,它介绍了一种有效训练贝叶斯网络的方法,称为反向传播贝叶斯。

贝叶斯神经网络是经典的前馈神经网络,其中权重被建模为分布。您仍然可以获取一个输入向量,并通过 BNN 对其进行馈送,但结果将是一个分布,而不是单个值。换句话说,**如果你给网络一个输入,BNN 会给每个可能的输出分配一个概率。**训练有素的 BNN 会给很可能正确的标签以概率,给极不可能正确的标签以甚至零概率。

这使得 BNN 成为一个概率模型,并且我们可以从网络中获得额外的信息。例如,如果网络很难在 label_Alabel_B 之间做出决定,它可以为这两者返回 50%的概率,而通常它必须选择一个标签,并且我们不知道决策过程中涉及的不确定性。

高斯过程也是概率机器学习模型。在像时间序列预测这样的许多应用中,它们的核函数被用来合并像领域知识这样的附加信息。然而,由于拟合过程涉及计算上昂贵的操作,它们往往不能扩展到更大的数据问题。为了了解更多,我推荐看一看这本关于⁵.的书

20 多年前,R.M.Neal 发现了贝叶斯神经网络和高斯过程之间的联系。他证明了当单层随机神经网络的层宽度取无穷大时,单层随机神经网络收敛到一个 GP。在过去的几年里,几篇论文(李等人、马修斯等人)给出了多层网络的类似结果。

为什么这对主动学习有意思?

因为这种联系允许我们通过用高斯过程*似它来为一般的神经网络定义一种很好的主动学习方法。

假设我们已经在一些训练数据上训练了一个(贝叶斯)神经网络,并且想要知道池中的哪些未标记点应该被标记以改进模型。我们希望选择网络具有高度不确定性的点。当我们将这些点添加到训练数据中时,不确定性可能会降低,预测总体上会变得更好。

主动学习:具有最高网络方差的点被添加到训练数据中。添加这样的点减少了网络的不确定性,并且可以从整体上改善网络的预测。图片作者。

高斯过程有一个很好的特性,那就是它们完全由它们的均值和协方差定义。为了用 GP 逼*网络,我们因此必须计算训练和池点的网络均值和协方差。在贝叶斯网络的情况下,权重是分布,均值和协方差可以通过从权重分布中抽取样本 并计算向前传递来估计。对于非贝叶斯网络,可以使用 Dropout 来代替。根据这篇论文 ⁴的研究,对辍学进行抽样实际上大致相当于贝叶斯方法。

估计的*均值和协方差完全定义了神经网络的高斯过程*似。该过程为池中的每个点定义所谓的后验方差这个方差正是主动学习所需的不确定性的度量:如果池中的一个点具有高方差,则网络对其预测具有高不确定性,应该选择该点。

在将来自池的一堆高方差点添加到训练数据之后,恢复网络训练,并且模型的质量应该提高。这种在增加点数和重新训练网络之间的切换通常要重复几次。

(该论文还讨论了一种加速该过程并确保所选点多样性的方法。我将在后续文章中谈到这一点。)

加州住房数据集的结果(回归)

一个 BNN 在来自 sklearn 的加州住房数据集上的训练进度,*均超过 10 次运行。图片作者。

这里你可以看到主动学习方法和随机选点的比较。我在 sklearn 的加州住房数据集上训练了一个有两层 100 个神经元的 BNN。训练从 500 个随机点开始,执行 10 次主动学习迭代,每次从大约 20.000 个实例的池中增加另外 250 个点。你可以看到主动学习方法(绿色)比仅仅选择随机点(红色)更快也更稳定地收敛了网络

结论

主动学习在很多情况下是有用的。它为训练机器学习模型提供了高效和有效的数据选择方法。

在这篇文章中,你已经了解了一般神经网络的主动学习技术。该技术利用高斯过程来计算具有高度网络不确定性的数据点。它的动机是贝叶斯神经网络和高斯过程之间的联系,但也可以用于任何使用辍学的网络。在接下来的文章中,我将解释如何改进主动学习方法,并更多地了解数学细节。

谢谢你看了我的第一篇博文!我希望你喜欢阅读它,并欢迎任何建设性的反馈:)

参考

我的论文、GitHub&LinkedIn
【1】Tsymbalov 等人、
Dropout as a Bayes Approximation:表示深度学习中的模型不确定性、https://arxiv.org/abs/1506.02142
【2】Lee 等人、
深度神经网络 as Gaussian Processes、https://arxiv.org/abs/1711.00165【3】Matthews 等人、 辍学作为贝叶斯*似:表示深度学习中的模型不确定性,https://arxiv.org/abs/1506.02142
【5】c . e .拉斯姆森,C. K. I .威廉姆斯
,机器学习的高斯过程,http://www.gaussianprocess.org/gpml/

使用 Nvidia 转移学习工具包的主动学习教程

原文:https://towardsdatascience.com/active-learning-tutorial-with-the-nvidia-transfer-learning-toolkit-b41489985713?source=collection_archive---------29-----------------------

如何使用主动学习和英伟达 TLT 从快速原型到生产就绪对象检测系统

每个机器学习项目中最大的挑战之一是在训练机器学习模型之前,对收集的数据进行整理和注释。通常,神经网络需要如此多的数据,以至于简单地注释所有样本对于中小型公司来说成为不可逾越的障碍。本教程展示了如何仅基于一小部分可用数据制作一个原型,然后通过主动学习迭代改进它,直到模型可以生产。

主动学习描述了一个只有一小部分可用数据被注释的过程。然后,在该子集上训练机器学习模型,并且使用来自该模型的预测来选择要注释的下一批数据。由于训练神经网络可能需要大量时间,因此使用预训练模型并根据可用数据点对其进行微调是有意义的。这就是 Nvidia Transfer Learning Toolkit 发挥作用的地方。该工具包提供了大量预训练的计算机视觉模型和功能,用于训练和评估深度神经网络。

接下来的部分将是关于使用英伟达 TLT 在 MinneApple 数据集上构建一个水果检测模型,并使用来自 Lightly 的主动学习功能迭代改进该模型,这是一个计算机视觉数据监管*台。

来自 MinneApple 数据集的示例图像。

为什么要水果检测?

准确检测和计数水果是自动化收获过程的关键一步。果实计数可用于预测预期产量,从而及早发现低产年份。此外,水果检测数据集中的图像通常包含大量目标,因此需要更长的时间来注释,这反过来又增加了每幅图像的成本。这使得主动学习的好处更加明显。

为什么是明尼阿波利斯?

MinneApple 由 670 张果园中苹果的高分辨率图像组成,每个苹果都标有一个边界框。少量的图片使它非常适合快速浏览教程。

我们开始吧

本教程跟随它的 Github 对应部分。如果您想亲自体验本教程,可以随意克隆存储库并进行尝试。

上传数据集

要用轻做主动学习,首先需要把你的数据集上传到*台上。命令lightly-magic训练自监督模型以获得良好的图像表示,然后将图像连同图像表示一起上传到*台。由于自我监督,这一步不需要标签,因此您可以立即开始处理原始数据。如果想跳过训练,可以设置trainer.max_epochs=0。在下面的命令中,用*台上的令牌替换MY_TOKEN

将数据集嵌入并上传到 Lightly web-app 的命令。

出于隐私原因,也可以上传缩略图,甚至只是元数据,而不是完整的图像。更多信息见此链接。

上传完成后,您可以在 Lightly *台中直观地浏览您的数据集。你可能会发现不同的图像群。摆弄一下,看看你能得到什么样的见解。

在 Lightly web-app 中探索您的数据集。

初始取样

现在,让我们选择一批初始图像进行注释和训练。

Lightly 提供了不同的采样策略,其中最突出的是CORESETRANDOM采样。RANDOM采样将很好地保留数据集的基本分布,而CORESET最大化数据集的异质性。在 Lightly Platform 中探索我们的数据集时,我们注意到许多不同的集群。因此,我们选择CORESET采样来确保每个聚类都在训练数据中有所表示。

要进行初始采样,您可以使用 Github 库中提供的脚本,或者您可以编写自己的 Python 脚本。该脚本应该包括以下步骤。

创建一个 API 客户端来与 Lightly API 通信。

创建一个主动学习代理,作为进行主动学习的界面。

最后,创建一个采样配置,进行一个主动学习查询,并使用一个助手函数将带注释的图像移动到data/train目录中。

query将在 Lightly *台中自动创建一个名为initial-selection的新标签。

训练和推理

现在我们已经有了带注释的训练数据,让我们在上面训练一个对象检测模型,看看效果如何!使用 Nvidia Transfer Learning Toolkit 从命令行训练 YOLOv4 对象检测器。迁移学习最酷的一点是,你不必从头开始训练一个模型,因此需要更少的带注释的图像来获得好的结果。

首先从 Nvidia 注册表下载一个预先训练的对象检测模型。

从 NGC 英伟达下载 ResNet-18 检查点的命令。

在采样的训练数据上微调对象检测器就像下面的命令一样简单。确保用你从 Nvidia 账户获得的 API 令牌替换你的 _KEY。

命令在所选图像上训练水果检测模型。

既然您已经对数据集上的对象检测器进行了微调,那么您可以进行推断,看看它的工作情况如何。

对整个数据集进行推断的好处是,您可以轻松地找出模型对哪些图像表现不佳或有很多不确定性。

命令使用训练好的水果检测模型进行推理。

下面你可以看到两个训练后的例子图像。很明显,该模型在未标记的图像上表现不佳。因此,向训练数据集添加更多样本是有意义的。

来自训练集和未标记集的图像示例。该模型在图像中缺少来自未标记数据的多个苹果。这意味着这个模型对于生产来说还不够精确。

主动学习步骤

您可以使用上一步的推论来确定哪些图像导致了模型问题。使用 Lightly,您可以轻松地选择这些图像,同时确保您的训练数据集不会充斥着重复的图像。

本节将介绍如何选择图像来完善您的训练数据集。您可以再次使用active_learning_query.py脚本,但这一次您必须指出已经存在一组预先选择的图像,并将脚本指向存储推理的位置。

注意,n_samples参数表示主动学习查询后的样本总数。最初的选择包含 100 个样本,我们希望将另外 100 个样本添加到标记集。因此,我们设置n_samples=200

使用CORAL代替CORESET作为采样方法。CORAL同时最大化样本数据中主动学习得分的多样性和总和。

该脚本的工作方式与之前非常相似,但有一个显著的不同:这一次,所有推断的标签都被加载并用于计算每个样本的主动学习分数。

脚本的其余部分与初始选择几乎相同:

再培训

您可以在新的数据集上重新训练我们的对象检测器,以获得更好的模型。为此,您可以使用与前面相同的命令。如果要从最后一个检查点继续训练,请确保用 resume_model_path 替换 specs 文件中的 pretrain_model_path。

如果你对重新训练后的表现仍然不满意,你可以再次重复训练、预测和主动学习步骤——这就是所谓的主动学习循环。由于所有三个步骤都是作为脚本实现的,迭代花费很少的精力,并且是持续改进模型的一个很好的方法。

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Philipp Wirth
机器学习工程师
lightly.ai

使用检测器的主动学习 2

原文:https://towardsdatascience.com/active-learning-using-detectron2-922a13982564?source=collection_archive---------33-----------------------

厌倦了给所有数据贴标签?了解有关模型预测和嵌入如何帮助您选择正确数据的更多信息。

监督机器学习需要有标签的数据。在自动驾驶等计算机视觉应用中,标记一帧图像的成本高达 10 美元。新的互联设备和更便宜的传感器的快速增长导致新数据不断增加。给所有东西贴标签再也不可能了。事实上,许多公司只标注了他们收集的数据的 0.1%到 1%。但是找到正确的 0.1%的数据就像大海捞针,不知道针长什么样。那么,如何才能做到高效呢?

解决这个问题的一个方法是主动学习。当进行主动学习时,我们使用预训练的模型,并使用模型预测来选择下一批数据进行标记。有不同的算法可以帮助您根据模型预测选择正确的数据。例如,众所周知的不确定性采样方法基于低模型置信度选择新数据。让我们假设一个场景,我们有两张猫的图片,一张是模型 60%确定是猫,另一张是模型 90%确定有猫。我们现在将选择模型只有 60%置信度的图像。我们本质上选择了“更难”的例子。
通过主动学习,我们重复这个预测和选择过程,直到达到我们的目标指标。

来自 Comma10k 的示例图像,具有在 MS COCO 上训练的具有 ResNet-50 主干的更快 R-CNN 模型的模型预测。

在这篇文章中,我们不会详细讨论主动学习是如何工作的。有很多关于主动学习的好资源。相反,我们将关注如何通过使用 Lightly 的主动学习特性,用几行代码来使用主动学习。轻飘飘是一个计算机视觉的数据策展*台。它利用自我监督学习和主动学习的最新进展来帮助您处理未标记的数据集。

数据集:从 COCO 女士到 Comma10k

如今,使用预先训练好的模型,并使用迁移学习在新任务中对其进行微调是非常常见的。因为我们对物体检测感兴趣,所以我们使用了一个来自可可小姐的预训练模型。它由超过 100k 个标记图像组成,是一个非常常见的数据集,用于图像分割、对象检测或关键点/姿态估计的迁移学习。

我们的目标是使用主动学习来使用 COCO 预训练模型,并在自动驾驶的数据集上对其进行微调。对于这个传输任务,我们使用的是 Comma10k 数据集。来自仓库:“这是从逗号舰队捕获的 10,000 png 真实驾驶。这是麻省理工学院的许可证,没有学术限制或任何东西。”

您可能已经注意到,Comma10k 数据集有用于训练“segnets”(语义分段网络)的注释。但是,没有我们转移任务所需的边界框注释。因此,我们必须添加缺少的注释。我们将使用主动学习来挑选前 100 张图像,并首先对它们进行注释,而不是对所有 10k 图像进行注释,我们预计这 100 张图像在模型改进方面的回报最高。

让我们看看主动学习如何帮助我们选择前 100 幅图像进行标注。

我们开始吧

本文基于在 Comma10k 教程上使用 Detectron2 主动学习。如果你想自己运行代码,还有一个现成的 Google Colab 笔记本。

主动学习工作真的很难。许多公司未能恰当地实施主动学习,从中得到很少甚至没有价值。其中一个主要原因是他们只关注不确定性抽样。不确定采样是主动学习算法的两大类别之一。在下图中,你会发现右侧有两种主动学习方法。

知识象限—右栏是主动学习。(参见使用 PyTorch 进行主动学习)

不确定性抽样可能是最常见的方法。您根据模型预测可信度低的地方选择新样本。

Lightly *台支持不确定性采样和分集采样算法。

第二种方法是多样性抽样。您可以使用它来使数据集多样化。我们挑选视觉上/语义上彼此不同的图像。

不确定性抽样可用于各种评分(最小置信度、边际、熵……)。
对于多样性采样,轻度使用 coreset 算法,轻度使用从其开源自我监督学习框架获得的嵌入。

然而,还有更多。

Lightly 有另一种称为 CORAL 的主动学习算法(CORESETAactiveLearning),它使用多样性和不确定性采样的组合。

目标是通过选择具有低模型置信度的图像来克服单个方法的局限性,但同时确保它们在视觉上彼此不同。

让我们看看如何利用主动学习和 Lightly *台。

嵌入并上传数据集

让我们从创建嵌入并将数据集上传到 Lightly *台开始。稍后,我们将在 CORAL 算法的多样化部分使用嵌入。

您可以使用 lightly Python 包轻松训练、嵌入和上传数据集。
首先,我们需要安装软件包。为此,我们建议使用 pip。确保您处于 Python3.6+环境中。如果你在 Windows 上,你应该创建一个 conda 环境。

在 shell 中运行以下命令,轻松安装最新版本的:

现在我们已经轻松安装了,我们可以运行命令行命令lightly-magic来训练、嵌入和上传我们的数据集。您需要向命令传递一个令牌和一个 dataset_id 参数。在创建一个新的数据集后,您可以在 Lightly *台中找到这两者。

用于训练、嵌入和上传数据集到 Lightly *台的命令行界面命令

一旦运行了lightly-magic CLI 命令,您应该会在 Lightly *台中看到上传的数据集。您可以查看数据集的 2d 可视化效果。你能看到形成白天和黑夜图像的两个星团吗?

Lightly *台上 Comma10k 数据集的 2D 可视化

主动学习工作流程

现在,我们已经将数据集上传到带有嵌入的 Lightly *台,我们可以开始主动学习工作流了。我们感兴趣的部分是,你有一个训练好的模型,并准备好对未标记的数据进行预测。我们从创建一个ActiveLearningAgent开始。这个代理将帮助我们管理未标记的图像,并确保我们与*台的接口正确。

创建 ActiveLearningAgent 的代码。代理将用于以正确的顺序获取文件名,并上传模型预测。

在我们的例子中,我们还没有一个模型。让我们从磁盘中加载它,并让它准备好对未标记的数据运行预测。

从检查点加载 detectron2 模型的代码。

最后,我们可以使用我们预先训练的模型,对未标记的数据进行预测。重要的是,我们使用与 Lightly *台上相同的单个文件顺序。我们可以简单地通过迭代al_agent.query_set来做到这一点,它包含一个按正确顺序排列的文件名列表。

基于主动学习代理的 query_set 运行模型预测的代码。

为了上传预测,我们需要将它们转化为分数。因为我们正在处理一个“物体检测”问题,所以我们使用了ScorerObjectDetection

计算主动学习分数的代码。

我们终于准备好查询第一批图像了。

查询前 100 个图像进行标记

为了基于模型预测和我们在 Lightly *台上的嵌入来查询数据,我们可以使用代理的.query(...)方法。我们可以将它传递给一个SamplerConfig对象来描述我们想要运行的采样算法及其参数。

创建 SamplerConfig 并执行查询的代码。

在查询了新的 100 幅图像后,我们可以使用主动学习代理的added_set简单地访问它们的文件名。

我们现在可以打印新选择的图像的前 3 个文件名进行标记。

恭喜你,你完成了你的(第一次)主动学习迭代!
现在你可以标记这 100 张图片,并用它们训练你的模型。主动学习通常是在一个连续的反馈循环中完成的。在使用新数据训练您的模型后,您将进行另一次迭代,并预测+选择另一批图像进行标记。

我希望你对如何在你的下一个计算机视觉项目中使用主动学习有一个很好的想法。欲了解更多信息,请查看使用 Comma10k 上的 Detectron2 的主动学习教程。

Igor Susmelj,联合创始人
淡淡地

原帖已发布于此:https://www . lightly . ai/post/active-learning-using-detectron 2

成对比较的主动采样

原文:https://towardsdatascience.com/active-sampling-for-pairwise-comparisons-476c2dc18231?source=collection_archive---------38-----------------------

作者图片

国际象棋、网球或任何其他有两个竞争对手的游戏的爱好者经常面临这个问题——如何将球员配对,以便在尽可能少的比赛中确定球员的排名?

类似的问题发生在许多行业,如酒店、餐饮服务、教育,这些行业的实体将被放入消费者偏好/技能量表,同时尽可能少地进行评估。

成对比较是排名和规模推断的常见选择。然而,成对比较的一个缺点是大量可能的配对。因此,自然的问题是——我们如何在获得尽可能多的关于实体在一个尺度上的相对位置的信息的同时,最大限度地减少比较的次数。例如,在网球比赛中,我和费德勒搭档不如他和德约科维奇搭档,因为我们比赛的结果是显而易见的。正如你可能注意到的,玩家对游戏的满意度也很重要,因为

这篇文章基于论文“通过*似消息传递和信息增益最大化进行成对比较的主动采样”,并附带了代码,请随意查看!方法叫 ASAP!

过去做了什么?

通常有两种不同的方法。

基于排序:使用简单的启发法,技能或质量条件相似的应该配对。这种方法的一个众所周知的例子是瑞士国际象棋锦标赛系统,在该系统中,在第一轮中,棋手被随机配对,每个棋手参加完全相同数量的游戏,在锦标赛的后期阶段,具有可比较数量的赢和输的棋手被配对。

信息增益:这里成对比较的结果通常映射到一维尺度,并且形成降低尺度中不确定性的条件对。ASAP 就属于这一类!

管道

大多数用于成对比较的主动采样方法遵循类似的管道。

用于成对比较的主动采样算法的示例管道。图片作者。

数据:我们从目前收集的数据开始,这些将是成对比较的结果。

刻度:然后数据被映射到刻度上。基于信息增益的方法假设一个规模模型,例如正态分布的玩家技能,如在著名的 TrueSkill 算法中(瑟斯通案例 V 假设),基于排序的方法使用一个规模的代理,例如条件的排名。大多数信息增益方法侧重于尺度的*似推断,以提高计算效率。ASAP 不使用*似推断,大大提高了推断分数的准确性。

配对选择:一旦秤可用,它将用于选择下一个要执行的比较。与其他方法不同,我们关注的是算法中这一部分的计算节省。

实验:选择下一对条件并输入到实验中,它可以是一个国际象棋游戏或一个问卷。

数据更新:我们得到结果后,数据被更新。

标度推断

对于规模推断,ASAP 使用 TrueSkill 算法。有关该算法的直观和详细的解释,请查看这篇文章。鉴于目前收集的成对比较的结果,我们对正态分布的得分变量感兴趣。得分变量的后验分布为我们提供了得分变量均值的估计,以及得分变量的标准差(置信度/标准误差)。

TrueSkill 使用和积算法,通过矩匹配进行期望传播。该算法是迭代的,对于分数推断的总复杂度为 k*O(n+t ),其中 n 是条件的数量,t 是到目前为止收集的比较的数量,k 是要执行的迭代的数量。更多的迭代产生更好的结果,然而,对于实时应用来说,比较次数 t 和比较条件 n 的增加可能是非常昂贵的。由于这个原因,大多数方法*似于后一种方法。

预期信息增益

一旦秤可用,我们就可以选择进行下一次比较,这将最大程度地提高秤的精确度。

预期信息增益的计算(EIG)。图片作者。

阶段 1: 我们从目前收集到的配对开始。在成对比较矩阵(上图中带数字的正方形)中,每个条目都是相对于相应列中的条件,相应行中的条件被选择的次数。以条件二和条件三为例,条件二赢了 3 次,条件三赢了 1 次。

第二阶段:现在我们模拟每一对条件下所有可能的比较结果。让我们再来看看条件二和条件三。我们模拟了两人赢在最上面,三人赢在最下面的结果。

第三阶段:然后我们推断每一个可能的模拟结果的规模

阶段 4: 接着是新的分数分布与具有 KL 散度的原始量表的比较。为了从配对中获得期望的信息增益,我们计算关于结果概率的期望。

对所有可能的条件组合重复这一过程,正如你可以想象的那样,计算量非常大。

保存计算

计算所有可能配对的期望信息增益是昂贵的,我们通过两种方式来提高速度:

  1. 我们只计算对的子集的期望信息增益
  2. 基于最小生成树选择批量比较

EIG 评价精选

选择性 EIG 评估,评估概率。相距甚远的情况下,EIG 被评估的概率较低。图片作者。

为了减少预期信息增益评估的数量,我们基于标度中条件的距离来计算预期信息增益评估的概率。

对于较低的概率,将为较远的条件计算期望的信息增益,而对于较远的条件,将计算较高的概率。你可以在报纸上找到更多的细节。

批处理模式

C1、C2、C3 和 C4 的可能成对条件比较图。图片作者。

在批处理模式中,算法建议不执行一个比较,而是一组接下来可能的比较,允许运行算法更少的次数。批处理模式在众包实验中也非常有用,我们可以在工人中分配批处理。

在批处理模式中,我们将所有条件视为顶点,无向边是潜在的比较。这些由预期信息增益的倒数加权。增益大的地方,权重小。

然后,我们选择具有最小生成树的批次——选择具有最小公共权重的边,或者具有最大信息增益的边。这个想法在之前就已经被探索过了,并且显示出也能提高结果的准确性。

估价

为了评估性能,我们运行蒙特卡罗模拟。

运行各种主动采样策略的结果。图片作者。

这里,y 轴是均方根误差,x 轴是迄今为止在标准试验中进行的比较次数。

我们可以看到三类具有可比性能的方法——基于排序的方法性能最差,其次是基于*似标度推断的方法。最好的执行方法是 ASAP,为此我们计算完整的后验更新,从而得到非常精确的比例。

实验努力

ASAP 获得的更高精度如何转化为实验时间?考虑一个目标精度为 0.15 RMSE 的实验室实验。如果需要 5 秒钟来获得两两比较的结果,那么在实验室中需要花费多少时间。

最佳方法在 20 和 200 种条件下的实验工作量(达到 0.15 rmse 精度所需的总时间)。图片作者。

对于 asap 的 20 个条件,大约 40 分钟将在实验室中花费。对于性能第二好的方法,大约需要两个小时的实验室时间。在 200 种情况下,ASAP 的时间转换为 9.5 小时,第二种最佳方法的时间转换为 14 小时。

摘要

由于在分数分布的计算中的完整海报更新,我们的方法实现了最先进的准确性,其他方法依赖于部分(*似)更新。

我们通过仅评估条件子集的期望信息增益,使该方法在计算上可行,从而将计算成本降低高达 80%。

我们还选择了一批条件,使算法特别适合众包实验。

查看纸和码!

喜欢作者?保持联系!

我错过了什么吗?不要犹豫,直接在 LinkedIn 或 Twitter 上给我留言、评论或发消息吧!

Python 中 walrus 运算符的实际应用(+示例)

原文:https://towardsdatascience.com/actual-practical-uses-for-the-walrus-operator-in-python-examples-b13ea7baaa6b?source=collection_archive---------26-----------------------

提高性能还是仅仅是语法上的好处?

海象仅仅是糖做的还是有更多的成分?(图片由马里·梅德在像素上拍摄)

快速坦白:自从在 Python 3.8 中引入以来,我从来没有这么频繁地使用过 walrus 操作符。当它第一次被介绍时,我认为它是一种句法糖,并且找不到使用它的理由。在本文中,我们将了解它是否仅仅提高了我们代码的可读性,或者是否有更多的意义。我们将通过这个模糊操作符的一些实际用例,让您的生活更轻松。在本文结束时,您将:

  • 理解海象操作员做什么
  • 知道怎么用吗
  • 识别使用 walrus 运算符的情况。

0.什么是海象运营商?

让我们从头开始。海象算子长这样:=。它允许你在同一个表达式中既赋值又返回一个变量。查看下面的代码块

beerPrice = 9.99
print(beerPrice)

在第 1 行,我们使用= 操作符将值 9.99 赋给一个名为‘beer price’的变量。然后,在第 2 行,我们打印变量。使用 walrus 运算符,我们可以一次完成这两项操作:

print(beerPrice := 9.99)

现在我们都打印出啤酒价格,我们已经设置为 9.99,此外,我们可以将变量用于其他用途。轻松点。现在让我们看看为什么我们需要这个功能,以及它对我们的代码意味着什么。

1.walrus 操作员的用例

在这一部分中,我们将应用运算符。我将尝试用一个尽可能类似真实应用程序的项目来说明这一点。在我看来,这比“foo”和“bar”的例子要好一些。

让我们让这家伙工作吧(图片由美国国家海洋和大气管理局发布)

我已经确定了一些情况,在这些情况下,walrus 操作符可能是实用的。首先简单介绍一下我们的项目,然后我们将讨论每种情况。

设置

我们是一家出于分析目的分析书籍的公司。我们已经建立了一个很好的 API ,允许用户向我们发送书籍。API 将图书文件保存到磁盘,之后我们可以分析它们的内容。

1.读取文件

我们的第一个目标是读取文本文件。请记住,我们不知道书籍的尺寸;人们可能会给我们发几十亿字节的百科全书!由于这个原因,我们想把这本书分成几部分来读。

""" The inferior non-walrussy way """openedBook = open('c:/bookDirectory/lotr_1.txt')
longWordCount:int = 0
while True:
    chunk = openedBook.read(8192)
    if (chunk == ''):
        break
    longWordCount += count_long_words(chunk=chunk)
print(longWordCount)

在这段代码中,我们以 8192 字节的块读取一本书。我们将它发送给一个计算超过 10 个字符的单词的函数。注意,我们必须检查块是否包含数据。如果我们不这样做,那么 while 循环就不会终止,我们就会被卡住。让我们看看如何使用 walrus 改进这段代码。

""" Walrus power! """openedBook = open(os.path.join(booksFolder, book))
longWordCount: int = 0
while chunk := openedBook.read(8192):
    longWordCount += count_long_words(chunk=chunk)
print(longWordCount)

你会注意到我们的代码现在干净多了。魔术在第五行。我们将打开的书的内容分配给块,并使用它来确定我们是否应该循环。好多了!

2.匹配正则表达式模式

假设我们的客户是一名图书管理员,他想给这本书增加一个难度等级。为了了解难度,我们将分析这篇课文。我们在阅读这本书时使用了以前用过的组块,现在我们将使用 RegEx(正则表达式)来查找一些困难的单词,我们将这些单词定义为包含 q 或 x 的单词。

# The Old way
openedBook = open(os.path.join(booksFolder, book))
while chunk := openedBook.read(8192):
    match = re.findall("\w*[xXqQ]\w*", chunk)
    if (match == []):
        continue
    print(len(list(set(match))))

在上面的代码中,我们找到了与第 4 行定义的特定正则表达式匹配的所有单词(\w*[xXqQ]\w*的意思是:找到包含 X、X、Q 或 Q 的所有单词)。这个函数默认返回一个空列表,所以我们必须检查我们是否在第 5 行和第 6 行找到了什么。最后,我们打印出唯一匹配数的计数。

# Walrus way
openedBook = open(os.path.join(booksFolder, book))
while chunk := openedBook.read(8192):
    if ((match := re.findall(pattern, chunk)) != []):
        print(len(list(set(match))))

当我们使用 walrus 操作符时,我们可以执行 regex findall 并将其结果赋给 match 变量,如果有匹配的话!尽管性能提高了一点点(3.1 毫秒),但这样做最能提高可读性。

3.列表理解中的共享子表达式

下一步:我们要分析我们在上面的正则表达式部分中发现的所有难词。我们将首先对每个单词进行词干处理,检查词干是否超过 8 个字符,如果是这样:保留词干。顺便说一下,词干是动词的词根:playing→ play,plays→ play,am,are,is → be 等。在本文中,我们不会深入讨论这是如何工作的,只是假设我们有一个名为stem_word()的词干函数。我们可以通过三种方式做到这一点:

常规方式 这种方式使用一个标准进行循环。最大的缺点是由于操作的数量,这是非常慢的。关于可读性:一个简单的操作需要很多行。

my_matches = []
for w in matches:
    s = stem_word(w)
    if (len(s)) >= 10:
        my_matches.append(s)
print('l', my_matches)

懒惰的方式 让我们对这一点更深入一点,使用列表理解。优势在于我们将之前需要的 5 行代码减少到了一行。我们还大大提高了性能;这种方式比传统方式大约快 25%。缺点:我们必须调用两次昂贵的 stem_word()函数。这是不可接受的低效。

fmatches = [stem_word(w) for w in matches if len(stem_word(w)) >= 8]

有了我们钟爱的操作符,我们可以将前面两者结合起来:我们不仅将所有代码放在一行中,通过列表理解来增强可读性和性能,而且我们只需调用一次昂贵的 stem_word()函数。

smatches = [s for w in matches if len(s := stem_word(w)) >= 8]

4.重用一个计算成本很高的值

一旦一个单词被词干化,我们就想把它翻译成荷兰语、德语和西班牙语。假设我们有翻译单词的功能。这里的主要问题是,stem_word()函数非常昂贵,但是我们需要这个函数的结果来将其翻译成四种语言(英语和其他三种)。对于 walrus 操作符,它看起来像这样:

word = 'diving'
translations = [s := stem_word(word), translate_dutch(s), translate_german(s), translate_spanish(s)]

请注意,我们构建了一个只调用一次 stem_word()函数的列表,将它存储到变量s中,然后使用该变量调用翻译函数。我们最终得到了一个包含四种语言的翻译词干的数组!

5.从字典中检索

假设我们有一本关于当前用户的字典,如下所示。

userdata = {
    'firstname': 'mike',
    'lastname': 'huls',
    'beaverage': 'coffee'
}

我们想从字典中检索一个值,所以我们需要提供一个键。我们不确定哪些键存在,这取决于用户提供的数据。最安全、最快捷、最常规的方法是:

age = settings.get(key)
if (age):
    print(age)

我们使用字典对象上的 get 方法。如果键不存在,它要么返回键值,要么不返回。让我们看看如何应用 walrus 操作符。

if (age := settings.get(key)):
    print(age)

同样,我们可以将设置年龄变量与检查值是否存在的表达式结合起来。

把所有的都集合起来→什么时候去海象

看一下我们所有的例子,我们得出结论,它们可以总结为两种情况:

  1. 如果存在,则分配一个值(1、2 和 5)
  2. 在 iterable (3 和 4)中重复使用一个计算量很大的值

第一类在性能上稍有提高。多亏了 walrus 操作符,我们可以减少语句的数量,因为我们可以将变量赋值和检查变量是否存在结合起来。然而,主要的改进在于代码的可读性;减少线的数量。

第二个类提供了改进的可读性和性能。这样做的主要原因是我们使用了列表理解,并且 walrus 操作符只允许我们调用一次昂贵的函数。

这只北极熊现在知道如何控制他的海象了

结论

walrus 操作符在性能上有一点改进,但主要是为了编写更易读、更简洁的代码。有一些特定的情况是 walrus 可以解决的,比如在 list comprehensions 中调用一个昂贵的函数两次,但是这种情况可以通过实现一个传统的循环来轻松避免。尽管如此,当“赋值 if exists”(情况 1)时,我已经开始使用 walrus 操作符来增强我的代码的可读性。在我的日常工作中,详细描述重用昂贵的计算值的另一种情况相当少见;我通常会像之前描述的那样避免这些情况。

我希望我能对这个有争议的运营商有所帮助。请让我知道您是否有任何使用案例,在这些案例中,这个操作符通过留下评论而大放异彩。编码快乐!

迈克

又及:喜欢我正在做的事吗?跟我来!

Ad2Vec:市场的相似列表推荐器

原文:https://towardsdatascience.com/ad2vec-similar-listings-recommender-for-marketplaces-d98f7b6e8f03?source=collection_archive---------30-----------------------

罗斯·乔伊纳在 Unsplash 上的照片

介绍

如今,产品推荐可以说是电子商务网站或移动应用程序最重要的组成部分。公司可以通过改进他们的推荐,轻松提高他们*台上的点击率(CTR)这一关键业务指标。因此,我认为推荐是数据科学团队有机会通过对产品产生深远影响来提高他们在企业中的知名度的最佳领域。

这是一个关于我们的新推荐方法对 eCG(易贝分类集团)市场*台的影响的故事。

目录

一、问题陈述:

  • 我们的市场*台上有页面、推荐者和广告类型的定义
  • 我们当前的推荐系统是如何工作的?
  • 为什么我们需要一个新的推荐人?

二。我们的方式和方法:

  • Word2Vec 有什么用?
  • 在推荐器上下文中如何使用 Word2Vec 算法?
  • 高级方法
  • 我们的方法论
  • 一个推荐问题如何优化 Word2Vec 的参数?

三世。模型评估和抽查结果:

  • 如何比较新的推荐系统和现有系统的性能?

四。其他未来使用案例:

  • User2Vec:更丰富的用户推荐
  • 简单的产品分类
  • 个性化搜索排名

问题陈述

页面类型

在我们的市场*台中,有两种不同的页面类型向用户显示推荐:

  • 首页:【为你】 feed 所在的页面。在这个提要中,我们向用户展示了与他们最*在*台上访问的内容相关的产品。简单来说,我们获取用户查看的最后 5 个广告(列表),然后从我们的推荐系统中检索与这 5 个广告相似的广告。
  • 查看项目页面(VIP): 这是一个页面,其中列出了特定广告的所有详细信息。在该页面的右下方,有一个名为“其他浏览过的”的广告列表组件,我们在其中为该特定广告推荐了前 5 个相似的广告。

推荐者类型

两种不同的算法在产品中运行,以生成这些广告推荐。

  • 基于内容的推荐系统(CBR): 基于广告的属性
  • 基于行为的推荐器(BBR): 基于用户的点击行为

广告列表类型

这些算法中的每一个都旨在解决关于我们*台上不同广告类型的推荐问题:

  • 新发布的(新鲜)广告:

由于市场是高度动态的*台,用户每天都会添加大量的新广告,因此在*台上发布的许多新鲜或新的广告还根本没有被浏览过。这是在名为“冷启动问题”的推荐系统中最受欢迎的挑战之一。我们有基于内容的推荐器来解决这个问题。该算法获取新发布广告的属性,如图像、大小、位置、价格,然后通过与其他现有广告的属性进行比较来获取最相似的广告。

  • 现有广告:

我们*台上的另一个广告类型是不久前添加的,因此有几个用户查看过。为了给这种类型的广告提供推荐,我们利用用户的行为浏览数据,而不是像基于内容的推荐那样使用广告属性。大体上,我们采用用户广告矩阵,并将其输入我们基于行为的推荐系统:协同过滤算法,最终得到类似的商品推荐。

我们目前的推荐系统是如何工作的?

对于一个特定的广告,我们首先尝试从 BBR 获取所有的推荐。如果有足够数量的广告从这个推荐器返回,那么我们只使用这些广告向我们的用户展示,否则我们通过从 CBR 获取更多的推荐来填充它们。这里值得一提的是,我们只是在寻求改善 BBR。因此,我们仍然需要 CBR 为这些新广告提出建议。

这篇文章是关于我们寻找比目前基于行为的推荐方法更好的方法——协同过滤的旅程。

为什么我们需要一个新的推荐人?

在我们当前的 BBR 中,协同过滤算法只把用户的广告视图作为一个整体来考虑,而没有考虑它的时序或时间方面。我们相信,我们的用户在我们的市场*台上旅行时,会倾向于*距离观看更多类似的广告。因此,在我们的例子中,广告视图的时间戳属性非常重要。我们希望更多地关注解决这个问题,同时通过从广告视图的共现到广告视图的接*来发现新的方法。

我们的方式和方法

Word2Vec 有什么用?

你们很多人可能听说过 Word2Vec,这是最流行的 NLP 算法之一。背后的逻辑简单而有力,并且依赖于一个假设,即出现在相似上下文中的单词可能具有相似的含义。根据上下文窗口的大小,通过从文本中提取成对的单词来生成训练数据。然后,使用该训练数据训练单层神经网络,最后使用隐含层权重作为单词嵌入。

如何可能使用 Word2Vec 算法作为推荐器?

在推荐上下文中使用单词 2Vec 也很流行,特别是对于电子商务*台,用户可以在会话期间访问不同的项目/产品。这是因为电子商务*台上用户的物品访问顺序在结构上类似于句子词序。换句话说,该算法将假设如果两个广告与其他相似的广告被共同访问(在单词的情况下是上下文相似性),那么这两个广告将被该算法定义为“相似广告”。最终,相似的广告将具有非常接*的嵌入(数字向量),并且来自不同子类别的广告将最终具有在余弦相似性空间中彼此远离的嵌入。

高级方法

下面,您将看到我们在荷兰*台 Marktplaats 上针对计算机和软件类别解释的方法的高级概述。

I:用户观看历史:用户在*台上的最*广告观看的序列

II:神经网络模型拟合:使用从用户观看历史生成的广告对来训练具有单个隐藏层的神经网络。

III:广告嵌入空间:使用神经网络中的隐藏层权重将*台上的每个直播广告嵌入到代表性的数字向量中

我们方法的高级概述

我们的方法论

现在,是时候深入了解实施过程的细节了。旅程从为每个用户生成一系列最*观看的广告开始。在生成这些序列时,我们只考虑了过去 45 天内的广告浏览量。这个时间框架已经被我们当前的协同过滤算法使用了一段时间,这就是为什么我们也坚持我们的新方法的确切时间间隔。我们将实现的其余部分分成 5 个不同的步骤。

第一步:首先,我们从这些序列中过滤出连续重复的广告。这是一个重要的应用步骤,因为我们的用户在*台上的旅程中倾向于重复查看相同的广告,这可能会导致在下一阶段为我们的模型生成训练数据时创建许多对相同的广告。

第二步:在第二个数据清理步骤中,我们还从这些用户的广告浏览序列中删除了非直播广告。这也是更好地嵌入直播广告的必要步骤。这是因为所有非直播广告都以这样的方式扭曲了嵌入生成过程,不久前发布的直播广告与非直播广告一起被访问,但相对较新的直播广告将没有机会与这些非直播广告一起被访问,因为它们已经从*台中移除。该算法会将这种情况解释为这两个广告组之间的差异,尽管这不一定是真的。最终,这可能会阻止模型为当前的直播广告产生高质量的嵌入。

第三步:接下来,我们进入第三步,从这些经过清理的用户旅程中生成广告对。回想一下,在给定窗口大小参数的情况下,这些广告对是通过沿着用户旅程滑动“上下文窗口”来生成的。

在下图中,你会看到前三步的总结。

方法—前 3 步

第四步:在第四步中,我们将过去 45 天的用户旅程的整个数据集分成两部分:训练数据集和验证数据集。我们以这样一种方式完成,前 44 天用于为模型生成训练数据,后 1 天用于为验证数据集生成广告对。请记住,为您的验证集选择一个晚于训练集的时间段是至关重要的,以便从该过程中获得最佳结果。

在这个阶段,你可能会想到一个问题:

问:“为什么我们首先需要一个验证集?”

答:这是因为我们需要调整下面列出的几个参数,以找到最佳模型:

  • 窗口大小:我们在其中生成广告对的输入广告周围的上下文窗口的大小
  • 向量大小:广告嵌入的维度(数字向量)
  • 采样率:设置一个阈值来修剪那些序列中出现很多的广告。换句话说,在受欢迎和不受欢迎的广告之间取得*衡。
  • 时期数:整个训练数据的通过次数

这里值得一提的是,我们使用了 H2O 的 Word2Vec 算法,通过苏打水包将其集成到我们的 Spark 管道中。因为 H2O 的 Word2Vec 算法有更多的参数需要调整,而且比它的 SparkML 对手快得多,所以我们决定用那个。但是,我们在前面的步骤中使用了 SparkSQL 和 Spark Data Frame API 来生成这些广告视图序列。

第五步:在第五步也是最后一步,我们对参数组合进行网格搜索,为每个类别选择最佳模型。我们使用准确性度量来测量每个模型在验证数据集对上的性能。我们用每对广告中的第一个广告输入模型,然后获取该特定广告的前 5 个推荐。如果这两个广告中的第二个是前 5 个推荐广告中的一个,那么我们称之为“成功”(1),否则称之为“失败”(0)。该模型通过在余弦相似性空间中使用强力 kNN 来获取特定广告的前 5 个推荐。

下图描述了第 4 步和第 5 步。

方法—最后 3 步

模型评估和抽查结果

这个项目的最终目标是最终得到一个优于我们当前基于行为的推荐协同过滤(CF)的算法。因此,在这个评估步骤中,我们进行了一些抽查,以比较当前推荐器与我们的新方法 Ad2Vec 的性能。为了公*起见,在整个实验过程中,我们尽可能系统地进行抽查。

我们如何比较新的推荐系统 Ad2Vec 和当前的协同过滤系统的性能?

每类:

  1. 随机挑选 10 个广告,比较从当前推荐者和新推荐者那里获得的推荐。
  2. 从上一步的 10 个广告中找出 3 个广告,从中我们可以很容易地看出这两个推荐者的表现差异。(注:对于某些广告,两种算法的表现一样好。)
  3. 对于上一步中的 3 个广告,从当前和新算法中提取前 3 个推荐。
  4. 将结果可视化,以便于比较

在下面的图片中,你会看到一些来自不同类别的案例。令人惊讶的是,在这个实验中,我们甚至没有遇到一个案例,在这个案例中,当前推荐器(CF)给出的推荐比 Ad2Vec 更相关。

经www.marktplaats.com许可拍摄的广告截图

经www.marktplaats.com许可拍摄的广告截图

经www.marktplaats.com许可拍摄的广告截图

其他未来使用案例

Ad2Vec 模型的主要结果是*台上所有直播广告的一组嵌入,类似的项目/广告将在余弦空间中具有类似的嵌入。有了这些信息,我们可以在不同的用例中使用与推荐完全相同的结果。

以下是我们将在后续步骤中考虑的 3 个使用案例列表:

用例 1:User 2 vec——更丰富的用户推荐

我们可以通过对用户在*台上的整个旅程中的所有广告的嵌入进行*均来为用户生成嵌入,而不是只考虑用户观看的最后 5 个广告并相应地生成用户推荐。通过这种方式,用户和广告嵌入将采用完全相同的格式,因此我们可以通过在广告嵌入空间中搜索特定用户的嵌入来获取最相关的广告。在下图中,我们应用了上述逻辑,并在一个示例案例中生成了特定于用户的推荐。

经www.marktplaats.com许可拍摄的广告截图

用例 2:简洁的产品分类

在市场*台上,所有的广告都是由用户发布和管理的,因此,产品分类很容易失控。这个问题背后有许多不同的原因。例如,我们的卖家有时无法在*台上找到单独的产品类别来销售他们的商品,基本上不得不将其发布在错误的类别中,或者他们可能会意外地将广告发布在错误的类别中。最终,所有这些都导致我们的买家有一个组织混乱的*台。

然而,我们可以通过对属于某个类别的所有广告的嵌入进行聚类来发现该类别中的异常值。通过这种方式,我们可以有机会纠正他们的类别,或者向*台建议一个关于产品组的全新类别。

在下图中,由于没有专门针对【收银机系统】的子类别,我们的用户不得不在不同的子类别中发布完全相同的产品类型:“监视器和显示器”、“台式电脑”、“软件|其他”和“其他计算机和软件”。这种情况很容易被我们新的 Ad2Vec 算法捕获,让我们有机会对产品进行更整洁的分类,从而改善我们*台上的买家体验。

经 www.marktplaats.com许可拍摄的广告截图

用例 3:个性化搜索排名

因为我们能够创建除广告嵌入之外的用户嵌入,所以我们可以通过简单地比较用户嵌入和搜索结果中列出的广告之间的相似性来遵循逻辑对任何搜索结果进行排名。

Joshua Golde 在 Unsplash 上拍摄的照片

结论

在本文中,我们想分享如何将流行的 NLP 算法 Word2Vec 转换成市场推荐器的方法。因为结果表明这种方法可以是对早期推荐器的改进。此外,您可以将相同的模型用于不同的目的,从而对您的业务产生深远的影响。希望您发现本文中的一些想法对您的项目和业务也有价值。

AdaBoost 机器学习算法:如何提高难以预测案例的性能

原文:https://towardsdatascience.com/adaboost-algorithm-remarkably-capable-but-with-one-interesting-limitation-cf95905bf8a0?source=collection_archive---------20-----------------------

机器学习

对自适应 Boosting 算法及其与其他基于决策树的机器学习算法的区别的直观解释

自适应升压(AdaBoost)。图片由作者提供。

介绍

机器学习算法的数量随着时间不断增加。如果你想成为一名成功的数据科学家,你必须了解它们之间的区别。

这个故事是我深入研究不同算法、它们如何工作以及如何用 Python 构建它们的系列文章的一部分。

故事涵盖以下主题:

  • AdaBoost 所属的算法类别
  • 单个决策树、随机森林和 AdaBoost 之间模型预测的可视化比较。
  • 解释 AdaBoost 与其他算法的不同之处
  • Python 代码示例

AdaBoost 属于哪一类算法?

AdaBoost 和它的另一个基于树的算法“朋友”一样,属于机器学习的监督分支。虽然它可以用于分类和回归问题,但我在这个故事中只关注分类方面。

旁注,由于神经网络独特的机器学习方法,我已经将它们归为一类。然而,它们可以用于解决广泛的问题,包括但不限于分类和回归。下图是互动所以一定要点击👇在不同的类别上对进行放大并揭示更多的

机器学习算法分类。由作者创建的交互式图表。

如果你喜欢数据科学和机器学习 ,请 订阅 每当我发布一个新的故事,你都会收到一封电子邮件。

决策树 vs 随机森林 vs AdaBoost

让我们先来比较一下这三个模型的预测概率面。他们都使用相同的澳大利亚天气数据:

  • 目标(又名因变量):“明天下雨”。可能值:1(是,下雨)和 0(否,不下雨);
  • 特征(又名自变量):今天“下午 3 点的湿度”,今天“阵风速度”。注意,我们仅使用两个特征来使我们能够容易地可视化结果。

以下是模型预测*面。请注意,如果您想复制这些图表,可以在本文的最后部分使用 Python 代码。

1。决策树 (1 棵树,max _ depth = 3); 2。随机森林 (500 棵树,max _ depth = 3); 3。AdaBoost (50 棵树,max_depth=1)。图片由作者提供。

解释

让我们解释可视化,看看它们告诉我们这些算法的区别。上图中的 z 轴是明天下雨的概率。同时,细白线是判定边界,即下雨的概率= 0.5。

在深入 AdaBoost 之前,我们现在将快速回顾一下购物车和随机森林。

1.单一决策树(CART)

CART 是标准决策树算法的首字母缩写,代表分类和回归树。在这个例子中,我们建立了一个决策树,它有 3 层,8 个叶子。以下是可供参考的精确树:

购物车决策树。图片由作者提供。

这棵树上的每一片叶子都给了我们明天下雨的可能性,这是下雨的情况数量与叶子内观察到的总数量之间的比率。例如,左下角的叶子给出了明天下雨的概率为 6% (2,806 / 46,684)。

每个叶子对应于 3D 预测图中的*面,而树中的分裂是阶跃变化。请参见下图。

CART 决策树及其相应的预测。图片由作者提供。

如你所见,这是一个非常简单的树,只给出了 8 种不同的概率。这些叶子中的 5 个导致明天没有雨的预测(概率< 0.5), while the remainder 3 leaves suggest it will rain tomorrow (probability > 0.5)。

如果你想更深入地了解 CART 算法的机制,你可以在这里参考我之前的故事:

2.随机森林

首先要注意的是,在我们的例子中,随机森林使用相同的 CART 算法作为它的基本估计量。但是,有几个主要区别:

  • 它构建许多随机树并组合来自每个单独树的预测以生成最终预测。
  • 它使用引导(替换采样)从原始数据中创建许多样本。这些样本保持相同的大小,但有不同的观察分布。
  • 最后,使用特征随机性来最小化树之间的相关性。这是通过在每个节点分裂时仅使特征的随机子集可用于算法来实现的。

最后,随机森林创建了许多树(在我们的例子中有 500 棵树),并根据每棵树的预测来计算总体概率。这就是为什么与单棵树相比,预测*面表面更*滑(即,它具有许多小台阶而不是几个大台阶)。

随机森林预测*面。图片由作者提供。

你可以在我的独立故事中找到更多关于随机森林的细节:

3.adaboost 算法

最后,我们到达这个故事的主题。

像随机森林一样,我们使用 CART 作为自适应 Boosting 算法中的基本估计器。然而,如果需要,AdaBoost 也可以使用其他估计器。

AdaBoost 的核心原理是将一系列弱学习器,如决策树桩,拟合到反复修改的数据版本上。决策树桩是只有一层深度的决策树,即它只由一个根节点和两个(或更多)叶子组成。以下是我们的 AdaBoost 模型中 3 个独立决策问题的示例:

三个决策难题。图片由作者提供。

类似于随机森林,来自所有弱学习者(在这种情况下,树桩)的预测通过加权多数投票来组合,以产生最终预测。然而,主要的区别在于这些弱学习者是如何产生的。

提升迭代包括对每个训练样本(观察值)应用权重。最初,这些权重在所有观察值中是相等的,因此第一步在原始数据上训练弱学习者。

将此与我们的示例联系起来,这意味着第一个决策树桩(第一次拆分)与使用单一决策树方法得到的结果相同:

单一决策树与 AdaBoost 中的第一个决策树桩。图片作者作者。

对于每个连续的迭代,样本权重被单独修改,并且学习算法被重新应用于重新加权的数据。在前一步骤中被错误预测的那些训练示例的权重增加了。与此同时,那些被正确预测到的重量会减少。因此,每一个后来的弱学习者因此被迫集中注意力于前一个学习者错过的例子。

最后,将所有弱学习者组合成一个最终预测会产生一个更“*坦”的预测分布。这是因为该算法故意降低了最有把握的例子的权重,并将重点转移到更难分类的例子上。因此,我们将模型预测显示在下图中。

AdaBoost 预测*面。图片由作者提供。

注意,你添加的弱学习者(stumps)越多,预测分布就变得越“*坦”。

预测分布

另一种可视化预测分布的方法是使用简单的频率线图。不出所料,

  • 单一决策树很少有间隔预测。
  • 随机森林显示了更加均匀的预测分布。
  • AdaBoost 的所有预测都位于决策边界附*(0.5)。

表演

虽然这三种方法产生了非常不同的概率分布,但最终的分类结果非常相似。性能可以通过多种方式进行评估,但为了简单起见,我在这里只显示准确性(测试样本):

  • 单一决策树:82.843%
  • 随机森林:83.202%
  • AdaBoost: 83.033%

虽然通过一些额外的超参数优化可以略微提高性能,但上述结果的相似性告诉我们,我们已经非常接*于提取所用特征中包含的最大信息。

AdaBoost 限制

AdaBoost 的最终“*坦”概率分布是其主要限制。根据您的使用情况,这对您来说可能不是问题。比方说,如果你只关心分配正确的类,那么预测概率就不那么重要了。

但是,如果您更关心概率本身,您可能希望使用随机森林,它为您提供了 9%或 78%等概率预测,如上面的降雨预测建模所示。这与 AdaBoost 相反,AdaBoost 的所有预测都接* 50%。

Python 章节

现在我们已经知道了 AdaBoost 的工作原理,并且理解了它与其他基于树的建模方法的不同之处,让我们来构建一个模型。

设置

我们将使用以下数据和库:

  • 来自 Kaggle 的澳大利亚天气数据
  • Scikit-learn 库用于将数据拆分成训练测试样本,构建 AdaBoost 模型和模型评估
  • Plotly 用于数据可视化
  • 用于数据操作的熊猫和 Numpy

让我们导入所有的库:

然后我们从 Kaggle 获取澳大利亚的天气数据,你可以按照这个链接下载:https://www . ka ggle . com/jsphyg/weather-dataset-rattle-package。

我们接收数据并推导出一些新的变量用于模型中。

一小段 Kaggle 的澳大利亚天气数据做了一些修改。图片由作者提供。

接下来,让我们按照以下步骤构建一个模型:

  • 步骤 1-选择模型特征(自变量)和模型目标(因变量)
  • 步骤 2 —将数据分为训练样本和测试样本
  • 步骤 3-设置模型参数并训练(拟合)模型
  • 步骤 4-使用我们的模型预测训练和测试数据上的类别标签
  • 步骤 5-生成模型摘要统计数据

上述代码生成以下总结模型性能的输出。

AdaBoost 模型性能。图片来自作者。

与训练数据相比,该模型在测试数据上具有相似的性能。评估者的数量是 50,这意味着最终的模型由 50 个不同的决策树桩组成。

最后,正如承诺的那样,下面是生成 3D 预测*面图的代码:

结论

我真诚地希望这个故事能帮助你为你的用例选择正确的算法。感谢您的阅读,您可以在自己的数据科学项目中随意使用上述代码和材料。

干杯!👏
索尔·多比拉斯

如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加入媒介是:

https://solclover.com/membership

你可能喜欢的相关故事:

从头开始

原文:https://towardsdatascience.com/adaboost-from-scratch-37a936da3d50?source=collection_archive---------2-----------------------

构建数据科学中最流行的“现成”算法之一的 Python 实现

Javier Allegue Barros 在 Unsplash 上拍摄的照片

有个同事曾经跟我说过,一个算法,直到你能在 NumPy 上从头开始写,你才算真正理解了它。这种说法可能很大胆,但打开一本关于机器学习的教科书或论文,并试图将数学转化为代码,仍然有一些美好的东西。这是我开始做这篇文章背后的工作的全部动机,在这篇文章中,我描述了如何构建您自己的 AdaBoost 算法实现。我们的算法版本来自《统计学习的要素 (TESL),第 10 章【1】。

AdaBoost 是 Ada 的缩写,已经成为数据科学中最流行的“现成”算法之一。它已经成为 Kaggle 竞赛中获胜解决方案的一部分(有时与其年轻的堂兄弟 XGBoost 和 Light GBM 结合使用),现在它甚至成为人脸检测问题的一部分。它是由 Freund 和 Shapire 在 1996 年提出的[2]。

一个小小的警告:本文的目的不是详细推导和解释 AdaBoost 的数学——已经有很多这样的好帖子了。相反,这篇文章是关于算法的实现如何在幕后工作的。它是为那些想了解 AdaBoost 的现成实现是做什么的人准备的,比如 Python 的 Scikit-learn 或 r 的 Adabag 上的那个。最后,我希望它也能启发你构建其他算法的实现,以了解它们的更多信息!

在本文的其余部分,我将遵循 TESL 第 10 章中的符号和公式。我们将实施 AdaBoost。M1 算法,在 Friedman 等人(2000) [3]中称为“离散 AdaBoost”,在 TESL 中称为算法 10.1。所有代码示例都是用 Python 编写的。你可以在 Github 库中找到代码。

升压概述

AdaBoost 算法基于“增强”的概念。boosting 背后的思想是,使用投票机制,一组“弱”分类器可以组成一个健壮的分类器。弱分类器只能产生比投掷(公*的)硬币稍微好一点的结果。换句话说,如果通过随机猜测一个二进制标签,我们将有 50%的机会是正确的,那么弱分类器将是正确的,比如说,55%(或者任何其他接* 50%的数字)。

使用 boosting,我们在样本的连续修改版本上训练一系列弱分类器。让我们举一个例子来看看这是如何工作的。假设我们有一个有五个观察值的样本。每个观察值被标记为-1 或 1,因此我们的标记是 y = [1,1,-1,-1] 。我们也有一些解释变量 x. 在第一轮提升中,我们训练一个弱分类器 G₁(x) ,它产生下面的预测: G₁(x) = [1,-1,-1,1,-1]。我们可以看到第二个和第四个观察值被错误分类了。在第二轮提升中,我们将使用一些权重对样本中的每个观察值进行加权 wᵢ.我们将设置 wᵢ ,使得这两个错误分类的观察值在新分类器 G(x) 的学习过程中比其他三个具有更大的影响。新的分类器现在可能会错过一些以前分类良好的观察结果,但它会更好地预测困难的观察结果。

在重复上述过程 M 次之后,我们将得到一组 M 个弱分类器,我们可以将它们组合成最终的健壮元分类器 G(x)。该元分类器将根据加权多数投票为每个观察值分配一个预测,如下式所示。

我们最后的分类器。资料来源:统计学习的要素。10

看到在多数表决中每个弱分类器权重α 表示。这些不是我们在每一轮助推中应用于每个观察的权重,我们称之为 wᵢ (我知道,这么多权重!).

弱分类器

请记住,我们粗略地将弱分类器定义为只能产生比随机猜测稍好的结果的分类器。这个定义的更正式的版本是分类器的错误率小于但接* 50%。在这种情况下,样本内错误率就是总样本量中错误分类的观察值的数量(即yᵢg(xᵢ】),如下所示。

样本内误差率。资料来源:统计学习的要素。10

许多算法可以作为弱分类器,但在 AdaBoost 的情况下,我们通常使用“树桩”;也就是说,决策树只包含两个终端节点。直观地说,在二元分类问题中,树桩会试图通过数据集的多个解释变量中的一个来分割样本。正如你所想象的,通常这不足以简单地分离类,尤其是在复杂的数据集中。

现在,如果我们对相同的数据训练一个决策树分类器 1000 次,我们将总是得到相同的切割(对于给定的随机种子,如果你使用*似启发式)。在画线时,决策树会最小化一个基于目标值分布的指标,通常是基尼系数或来自结果类别的信息增益。这就是我们的观察权重 wᵢ 发挥作用的地方。在每一次 boosting 迭代中,我们告诉我们的 stump 在估计它最小化的度量时对每个观察值进行不同的加权。这样,在每次迭代中,我们都会得到不同的决策树。

在本文中,我们不会详细讨论决策树(事实上,我在算法中使用了 Scikit-learn 实现),但是如果您想了解更多关于决策树的知识,我建议您阅读 TESL 的第 9、10 和 15 章。

编写我们的算法

是时候回顾一下了。为了解决二元分类问题,我们的 AdaBoost 算法将通过一系列提升迭代来拟合一系列弱分类器(树桩)。这些分类器将形成元分类器,该元分类器将基于加权多数投票机制产生预测。在每一次提升迭代中,我们将给予那些在前一次迭代中被错误分类的观察更多的权重。我们可以将这个过程形式化,如下面的算法所示。人们可以证明, αw 的公式来自最小化指数损失函数。解释有点长,超出了本文的范围,但是你可以在第 10.4 节的 TESL 中找到。

资料来源:统计学习的要素。10

我们将通过识别独立的流程块来开始我们的实现,我们可以在步骤 2 的循环之外对这些独立的流程块进行编码。步骤 2(b)、2(c)和 2(d)包含在每次迭代中重复的操作,所以我们将它们定义为 Python 函数。让我们看看怎么做。

请注意,这些函数与算法无关。人们可以用 compute_error 函数计算任何分类器的错误率。类似地,我们可以为其他上下文估计 αw

是时候定义我们的 AdaBoost 分类器了。为此,我们将构建一个名为 AdaBoost 的 Python 类,它将由几个方法组成,以适应模型并进行预测。它还将包含关于我们拟合的模型的其他相关信息,例如弱分类器的序列和它们在最终投票中的权重,以及训练和预测误差。下面的代码片段显示了我们的类的初始化和 fit 方法:

的。 fit() 方法的结构与典型的 Scikit-learn 类非常相似。作为必要的参数,它以数组形式的独立变量矩阵 X 和带有目标变量的向量 y 。目标变量必须是二进制的,并且必须进行编码,使其值为-1 或 1(这使得投票更容易)。增强舍入参数是可选的,默认值为 100。

AdaBoost 的步骤 1 和 2。对于循环,M1 算法在内被特征化。开始时的 if 语句在第一轮中将每个观察值的权重初始化为 1/N(步骤 1),然后在拟合树桩并计算出该迭代的 α 后更新它们(步骤 2(d))。该方法的输出是一组树桩、alphas 和训练错误,我们将其存储起来以供在预测方法中进一步使用。算法的步骤 3 在一个单独的方法中定义,我们称之为。预测()。**

类似于。合体()法,。predict() 将解释变量的类似数组的矩阵作为参数。然后,它为每个观察值和树桩计算一个预测值。这些数据存储在一个数据帧中,该数据帧将用于该过程的多数表决部分,以计算每个观察的最终预测。

测试我们的算法

我们现在已经定义了 AdaBoost 的实现,但是我们如何知道它能工作呢?为了找到答案,我们将在 Spambase 数据集上进行测试,这是一个由 4,601 封电子邮件组成的集合,根据它们是否是垃圾邮件进行标记。自变量由每封电子邮件中的术语和字符频率组成。这个数据集可以在加州大学欧文分校的公共存储库中找到,你可以在这里下载。它还被用于 TESL 的几个章节,包括关于 AdaBoost 的章节,因此我们可以将我们的实现与其他经过验证的算法进行比较。

就像在 TESL 中一样,为了确保我们的训练集尽可能相似,我们不会对解释变量应用任何清理或特征工程。TESL 没有说明它的随机种子,所以我们不能复制训练/测试分裂。然而,我们仍然可以使用相同的集合大小,使得至少两种算法都在相同数量的观察值上被训练。下面的代码片段显示了我们如何读取和分割数据:

我们的 AdaBoost 类在这里实现非常简单。我们只需要将训练集传递给。fit() 方法和测试设置为预测()【方法:

就是这样!如果你在你的机器上尝试上述步骤,你会发现你会得到 5.6%的错误率。相比之下,在 TESL 的第 10.8 章中,他们使用梯度推进得到的错误率为 4.5%,使用加法逻辑回归得到的错误率为 5.5%,使用 CART 树得到的错误率为 8.7%,使用 MARS 得到的错误率为 5.5%。请注意,我们使用的不是完全相同的样本,而是相同数量的观察值。但还不错,对吧?

作为第二个测试,您还可以将这个定制实现与 Scikit-learn 的实现进行比较。我们上面产生的一组预测产生了 93.99%的 ROC-AUC 分数。在相同的数据集上使用 Scikit-learn,我得到了 92.79%。由于随机种子和*似试探法,数字可能略有不同,但它真的很接*!

回到树桩

记住 AdaBoost 适合一组弱分类器。为了了解这在实践中意味着什么,让我们来看看上面训练的每个树桩的错误率。在下面的图表中,我们可以看到大多数树桩在训练集上的错误率非常接*,但低于 0.5。

来源:作者创作

决策树的一个众所周知的特性是它们倾向于过度拟合训练数据。我们的树桩也不例外,如下图所示。其实很多比乱猜还要烂。然而,他们的组合只有 5.6%的错误率!

主要外卖

本文的目标是介绍如何用 Python 构建 AdaBoost 分类算法的自定义实现。为此,我们遵循了的第十章《统计学习的要素》。在这一过程中,我们也给出了 boosting 的高级概述,boosting 是一种将弱学习者结合到一个健壮的元算法中的技术。

我希望这是有用的,并启发您构建自己的自定义实现。这不仅是一种有趣的学习方式,而且非常有效!正如纳西姆·n·塔勒布所说:“我自己学到的东西我仍然记得”[5]。

喜欢吗?您可以访问这个 Github 库中的代码。

参考

[1] Hastie,t .等人(2009),《统计学习的要素》,第二版, DOI 10.1007/b94608_10,施普林格科学+商业媒体有限责任公司。

[2] Freund,y .和 Schapire,R. (1996),用新的 Boosting 算法进行的实验,机器学习:第十三届国际会议论文集,可在 http://rob.schapire.net/papers/FreundSc96.pdf获得

[3]弗里德曼 J,哈斯蒂 T,蒂布希拉尼 R (2000 年)。加法逻辑回归:助推的统计学观点。统计年鉴,28 卷 2 期,337–407 页。

[4]杜瓦和格拉夫(2019 年)。UCI 机器学习知识库[http://archive . ics . UCI . edu/ml]。加州欧文:加州大学信息与计算机科学学院。

[5]纳西姆·尼古拉斯·塔勒布(2016),《普洛克罗斯特斯之床:哲学和实践格言》。

Adaboost:直觉和解释

原文:https://towardsdatascience.com/adaboost-intuition-and-explanation-9c4e67034879?source=collection_archive---------33-----------------------

Adaboost 是最流行的提升算法之一。看看引擎盖下面,看看发生了什么事。

Ashkan Forouzani 在 Unsplash 上的照片

Boosting 是机器学习工具包中的一个重要工具。这是一种集成方法——一种结合多个模型来创建更好模型的机器学习技术。Boosting 在机器学习领域应用广泛,AdaBoost 是最受欢迎的 boosting 算法之一。让我们来了解一下它是如何工作的。

一个直观的故事

假设你是一名医科学生,你正在看 x 光片,以确定某人是否患有罕见疾病——这是一个二元分类问题。因为这是一种罕见的复杂疾病,整个国家只有一个专家。这位专家无法准确地说出如何对 x 光片进行分类,因为太复杂了,无法写下来。相反,他可以通过给出经验法则来帮助你。例如,他可能会说“如果 x 射线显示高对比度,患者更有可能患有该疾病”或“如果 x 射线显示更多的血管,患者不太可能患有该疾病”。随着时间的推移,通过结合这些经验法则,你开始对病人进行越来越好的分类。

在你学会任何经验法则之前,你什么都不知道。因此,你有同等的机会对每张 x 光片进行分类。然而,一旦你学会了一些规则,你可能会注意到,一些 x 射线通常会被你所学的规则正确分类,而另一些通常会被错误分类。更重视你一直错误分类的 x 光片似乎是明智的。你要求医生开始提供针对这些困难的 x 射线的经验法则,而不是一般的经验法则。

我们刚刚描述的故事是对 AdaBoost 工作原理的一个隐喻。我们学习多个弱分类器,将它们组合起来得到一个更强的分类器。在学习之初,我们什么都不知道,所以我们对学习什么规则没有偏好。稍后,我们将重点放在帮助分类我们遇到困难的数据点的规则上。

数学公式

以下是 AdaBoost 算法的形式符号:

资料来源:Freund 和 Schapire,1999 年加强免疫简介

在我们的故事中,我们假设一个二元分类问题。训练集用(x_i,y_i)表示,取自某个父分布。该算法总共有 T 个时间步长。对于每个时间步长 t,我们为每个训练示例 I 定义一个权重 D_t(i)。该权重确定该特定训练示例的“硬度”, AdaBoost 将为较难的示例赋予较高的权重。一开始(t = 1)我们不知道哪些例子比较难,所以我们把所有的权重都设为相等。

训练的每一步都是这样的。首先,我们根据硬度权重在训练集上定义的分布来训练一个“弱分类器”。直觉上,我们正在确保我们的弱分类器更重视硬数据,因为我们目前在这些数据上有麻烦。每个弱分类器对应于我们故事中医生给出的一个经验法则。粗略地说,“弱分类器”是比机会更好的分类器。数学上“弱”的精确定义需要更多的理论。为了理解 AdaBoost,我们的粗略定义已经足够好了。

一旦我们有了一个弱分类器,我们计算它在训练集上的误差,表示为ϵ_t(第二个要点)。请注意,该误差是用硬度权重加权的。然后我们计算α_t(第三个要点)。注意,训练误差越小,αt 越大。还要注意,根据“弱分类器”的定义,ϵ_t 至多为 0.5,所以α_t 总是正的。接下来,我们分别根据 e^(-α_t 因子或 e^(α_t 因子对训练数据的分类是正确的还是错误的,对训练数据进行重新加权。注意,由于α_t 总是正的,e^(-α_t) <1 and e^(α_t) > 1 总是。因此,如果数据分类正确,其权重会降低,如果数据分类不正确,其权重会增加。这就是“AdaBoost”这个名字的由来——AdaBoost 代表“自适应增强”,在这个上下文中“自适应”意味着改变我们刚才描述的权重。

随着时间的推移,一直被错误分类的数据将获得越来越高的权重。然后激励算法学习能够对困难数据进行分类的弱分类器。通过这种方式,Adaboost 可以确保覆盖所有数据。

在 T 个时间步之后,我们将所有弱分类器的加权和作为我们的最终答案。权重是α_t。这是因为较低的ϵ_t 对应于较高的α_ t——我们更信任误差较低的分类器,而不是误差较高的分类器。我们的最终分类器有多好?原来这个分类器是一个“强”分类器。同样,像弱分类器一样,“强”的正确定义需要更多的理论。但是粗略地说,一个“强分类器”是一个有足够的时间和数据可以得到任意小误差的分类器。

我们必须澄清一件重要的事情。我们说过最终的分类器很强。回想一下,我们运行 AdaBoost 迭代测试的训练集是从一些父分布中提取的。那么,最终的分类器是只对训练集有效,还是对整个父代分布有效呢?事实证明,答案是两者皆有。理论结果如下。这些结果的证明,以及“强”和“弱”的更严格定义,可以在这里找到。

  • 训练集误差随着 Adaboost 迭代次数 t 呈指数下降。因此,我们可以通过运行更多迭代来使训练集误差任意小。
  • 泛化误差(父分布上的误差)随着训练集大小的*方根而减小。因此,我们可以通过增加训练集的大小来使泛化误差任意小。

重述

我们已经了解了 Adaboost 背后的直觉,并讲述了它可能如何使用的故事。然后我们看了形式算法,讨论了最重要的部分。最后,我们陈述了主要的理论结果:Adaboost 将弱分类器转化为强分类器。我希望您在阅读完本文后,能够更好地理解 Adaboost 的工作原理。欢迎任何反馈,感谢阅读!

AdaHessian:用于深度学习的二阶优化器

原文:https://towardsdatascience.com/adahessian-a-second-order-optimizer-for-deep-learning-2fc76b29bcbb?source=collection_archive---------24-----------------------

思想和理论

阿达赫森在向最小值前进。(图片由作者提供)

深度学习中使用的优化器大多是(随机)梯度下降法。他们只考虑损失函数的梯度。相比之下,二阶方法也考虑了损失函数的曲率。有了它,就可以计算更好的更新步长(至少在理论上)。只有少数二阶方法可用于深度学习,其中之一是姚等人在 2020 年发表的 AdaHessian 。作者提供了 PyTorch 实现。

在其最基本的形式中,二阶方法需要计算包含 N×N 个元素的 Hessian 矩阵,其中 N 是神经网络中参数(权重)的数量。这对于大多数模型来说是不可行的。AdaHessian 包含了一些有趣的技术来解决这个问题。然而,乍看起来它们可能很复杂。本文将介绍这些技术,它们可以有效地计算 Hessian 矩阵的*似值。

动机

梯度下降仅使用其一阶导数来模拟损失函数:该算法在负梯度的方向上采取足够小的步长(由学习速率控制),从而损失值降低。损失函数的曲率信息(在 Hessian 矩阵中收集的二阶导数)被忽略。

图 1 显示了当前位置的损失函数(绿色)和梯度(红色)。左图显示了梯度与损失函数局部精确匹配的情况。右图显示了当向负梯度方向移动时损失函数向上的情况。虽然在左图中应用较大的更新步长可能有意义,但在右图中需要较小的更新步长,以避免超过最小值。

图 1:损失函数 f(w)(绿色)及其在 w=-1 处的梯度(红色)。(图片由作者提供)

牛顿更新步骤

牛顿的方法就是这样处理的:它同时考虑了当前位置的梯度和曲率。它用二次模型对损失函数 f(w)(w 是模型的参数或权重)进行局部建模。更新步骤推导如下(公式见图 2):

  • 使用泰勒多项式计算二次模型 m
  • g 是梯度,H 是海森矩阵
  • 为了找到模型 m 的最小值,计算模型的导数,将其设置为零,并求解更新步长δw
  • 这给出了牛顿更新,其中负梯度被 Hessian 的逆缩放和旋转

图 2:牛顿法的导出更新步骤。(图片由作者提供)

梯度和 Hessian 都可以用 PyTorch 这样的深度学习框架来计算,这是应用牛顿方法所需的一切。然而,对于具有 N 个参数的神经网络模型,Hessian 矩阵由 N×N 个元素组成,这对于典型模型是不可行的。AdaHessian 用一个对角矩阵来*似 Hessian 矩阵,它只包含 N 个元素(与梯度向量大小相同)。

计算黑森的对角线

我们现在有了牛顿更新公式,我们把海森*似法限制在一个对角矩阵上。让我们看看它是如何计算的。

哈钦森方法

图 3 示出了 Hutchinson 方法的公式,其计算 Hessian 的对角元素:

  • 通过为每个元素抛硬币来创建一个随机向量 z,并为头部设置+1,为尾部设置-1,因此在 2D 的例子中,z 可以是(1,-1)
  • 计算矩阵向量乘积
  • 将 z 元素(用⊙表示)乘以上一步的结果 z⊙(H z)
  • 计算期望值(或在实际实现中使用 z 向量的多个实例的*均值)

图 3: Hutchinson 计算 h 对角线的方法

这乍一看很奇怪。我们已经需要 H 来获得 H 的对角元素——这听起来不是很聪明。但事实证明我们只需要知道 H z(一个向量)的结果,这个结果很容易计算,所以我们从来不需要知道全 Hessian 矩阵的实际元素。

但是哈钦森的方法是如何工作的呢?当写下 2D 的例子时(图 4 ),很容易看出。逐元素乘法意味着逐行乘以向量。检查 z⊙(H z)的结果显示其中有 z₁(和 z₂)的项和 z₁ z₂的项。在计算多次试验的 z⊙(H z)时,z₁(和 z₂)总是+1,而 z₁ z₂在 50%的试验中给出+1,在另外 50%的试验中给出-1(只需写下所有可能的乘积:1 1,1 (-1),(-1) 1,(-1) (-1))。当计算多次试验的*均值时,包含 z₁ z₂的项趋向于零,留给我们的是 h 的对角元素的向量

图 4:哈钦森在 2D 案例中的方法。(图片由作者提供)

矩阵矢量积

只剩下一个问题:我们没有在 Hutchinson 方法中使用的 Hessian 矩阵 H。然而,正如已经提到的,我们实际上并不需要黑森。如果我们有 H z 的结果就足够了。它是在 PyTorch 的自动微分功能的帮助下计算的:如果我们采用 PyTorch 已经计算的梯度,乘以 z,并对参数向量 w 进行微分,我们会得到与直接计算 H z 相同的结果。因此,我们可以在不知道 H 的元素的情况下计算 H z。图 5 显示了为什么这是正确的:再次对梯度求导得到 Hessian,z 被视为常数。

图 5:我们用 PyTorch 的自动微分法(左)和 Hutchinson 方法所需的矩阵向量乘积 H z(右)计算的结果相等。(图片由作者提供)

把所有的放在一起

我们现在有了 Hessian 的梯度和对角线值,所以我们可以直接应用牛顿更新步骤。然而,AdaHessian 遵循与 Adam 优化器类似的方法:它在多个时间步长上求*均值,以获得对梯度和 Hessian 的更*滑的估计。

单个更新步骤如下所示:

  • 计算当前梯度
  • 计算当前对角 Hessian *似
  • 通过将其与早期值混合来*均梯度
  • 通过将它与早期的值混合来*均 Hessian,并注意对角线元素是正的(否则,我们可能会以上升的方向结束移动)
  • 计算牛顿更新步骤,包括学习率参数,以避免过大的步骤导致发散

在图 6 中,一个简单的二次函数用梯度下降和 AdaHessian 最小化。这里,AdaHessian 是不带动量使用的。在这个玩具示例中,与梯度下降相比,它收敛得更快,并且不需要调整学习速率。当然,最小化二次函数有利于二阶优化器。

图 6:二次函数最小值的三个步骤。左:具有适当学习速率的梯度下降。右图:使用对角海森*似的牛顿方法(右图)。(图片由作者提供)

结论

AdaHessian 通过(1)使用对角线*似,(2)利用 Hutchinson 的方法和(PyTorch 中包含的自动微分函数解决了计算 Hessian 的任务。

链接:

  • 论文
  • 原 PyTorch 实现
  • 另一个 PyTorch 实现,具有简化的接口
  • 对 2D 函数进行分析的代码
  • 代码分析所描述的 Hessian 计算

Adaline 神经网络:梯度下降的起源

原文:https://towardsdatascience.com/adaline-neural-networks-the-origin-of-gradient-descent-783ed05d7c18?source=collection_archive---------7-----------------------

神经网络系列

神经网络系列—第 2 章

序言注释

这个故事是我正在创作的关于神经网络系列的一部分。本章致力于一种被称为自适应线性单元 (adaline)的神经网络,其创建归功于感知机网络之后不久的伯纳德·维德罗和泰德·霍夫。虽然 adaline 和感知器都是受麦卡洛克和皮茨神经元的启发,但两个网络之间有一些微妙但重要的差异,其中一些已经建立了当前神经网络架构中训练算法的基础。

Adaline 神经元

Ted Hoff 是 Widrow 的博士生(有趣的事实:他也是英特尔的第 12 号员工)。他们在此期间的合作导致了 adaline neuron 的工作,并于 1960 年出版。他们设计了一个受先前神经元架构启发的逻辑电路后,专门为这项任务制造了一个小型机器,以测试他们的提议。该机器如下图所示。

来源:https://isl.stanford.edu/~widrow/papers/t1960anadaptive.pdf

并入该机器的架构在于具有单个神经元,一些输入连接到该神经元(包括偏置节点)。每个连接都有一个权重 w ( i,j) ,其中 i 标识连接来自的输入, j 是连接去往的神经元。至于偏置节点,我们可以认为是一个输入为 1 的特殊节点。假设有 m 个输入节点和 n 个神经元,一个更一般的 adaline 的神经网络架构可以用以下方式形成:

您可能已经从我以前的文章中熟悉了这个符号。唯一不同的是 f(z) 现在是线性激活函数,意思是 f(z)=z 。然而,为了分类的目的,原始文件详述了一个额外的步骤,其中应用了一个不同的阈值函数,以便获得一个类别/类作为输出。

训练 adaline 网络

训练过程背后的推理仍然与感知器相同:每个权重 w ( i,j) 需要以这样一种方式更新,即它将在下一次迭代中增加正确预测的输出数量——我们将这个更新值称为δ(I,j) 。然而,这个更新变量是以不同的方式计算的,使用一种称为梯度下降的算法。

梯度下降

梯度下降是一种算法,用于找到最小化整个网络预测误差的一组权重 W 。为了实现这一点,我们定义了所谓的误差函数(也称为损失函数或成本函数)【J(W),并且我们迭代地试图找到该函数的全局最小值。
假设有一个图,其中我们可以描述误差函数【W】如何基于权重值变化,如下所示:

根据权重值 W 绘制成本函数 J(W)

在上图中,当 w 为 9 时,我们目前的误差大约为 20。然而,可以看出,当 w 为 5 时,网络的误差最小。梯度下降解决的挑战是如何从当前点到产生最低误差的权重值。
梯度下降找到最小值的方法是(使用正确的数学术语)计算权重的偏导数。通俗地说,梯度下降背后的直觉在下面的动画中有所说明:

在每次迭代中,我们计算偏导数,以便知道我们应该朝哪个方向走。这个方向是由绿线给出的——它是我们所在的 w 处的函数的切线。这条线斜率是在 w 处的导数。如果斜率为正,如上图所示, w 将在下一次迭代中减少,反之如果斜率为负, w 将增加。根据下面的公式定义每次迭代的更新值,其中 w 表示权重矩阵,是以与感知器相同的方式确定步长的学习率系数,剩余部分是成本函数相对于权重的偏导数:

在另一个机会,我将奉献一篇完整的文章,梯度下降算法及其所有变种。现在,如果你想要一个替代的解释,吴恩达在他的一门机器学习课程中为提供了一个关于它如何工作的伟大直觉。

让我们将梯度下降用于 adaline 训练。在最初的 adaline 论文中,作者指出:

包括电*在内的所有增益都将改变相同的绝对幅度,使得误差为零。这是通过在将误差减小 1/17 的量的方向上改变每个增益(可以是正的或负的)来实现的。(…)收敛由小误差(自适应前)表示,围绕稳定的均方根误差有小波动。

因此,他们的目标是通过找到这样做的方向来减少误差,以便获得最佳增益(这只是一个不同的术语,他们称之为增益,我们称之为权重)。使用的成本函数是均方根误差( RMSE )。在本文中,我将使用 MSE 来代替,因为它非常相似,更容易解释背后的数学,并且它符合相同的目的。

有了成本函数,我们就可以计算在每次迭代中需要应用于每个权重的权重更新公式。下面的截图总结了为 adaline network 提出更新公式的整个过程。这是取自我的渐变下降笔记本。

adaline 训练中使用的最终权重更新公式为:

其中 w 标识单个权重,为学习率系数, y 为预测输出 ,t 为期望输出, x 表示单个输入。

Adaline vs 感知器

现在让我们对 adaline 和感知器进行比较,以了解它们的异同:

  • 培训阶段

在架构方面,有一个明显的区别:感知机使用阈值函数,而 adaline 使用线性激活函数,这将在训练方面具有理论意义。感知器根据感知器规则更新其权重,当一个或多个样本在训练中被错误预测时,改变它们的值。至于 adaline,权重更新将基于梯度下降算法进行,即使在整个训练中所有的例子都被正确预测,它们也可能发生。这是因为 y 不再是一个分类变量,最小化是在一个损失函数上完成的,该损失函数是一个表示什么应该是正确权重的代理。但是,最后的更新公式非常相似。

你可能会问自己:如果我们最终得到了几乎相同的公式,为什么对梯度下降如此大惊小怪?梯度下降变得如此重要的原因是因为它可以推广到其他更复杂的架构(公*地说,这不是唯一的原因,但现在让我们保持简单)。例如,我们将在本系列的后面看到感知器规则不能应用于多层网络。你必须考虑的唯一事情是,为了使用梯度下降,你的激活函数必须是可微的,这不是阈值函数的情况。

  • 预测阶段

至于预测阶段,感知器和 adaline 网络非常相似。它们都解决分类问题,并且它们都受到相同的限制,因为它们只解决线性可分问题(在感知器文章中解释)。从理论角度来看,主要区别在于激活函数。但是 adaline 的线性激活函数暗示了f(z)= z,从分类的角度来看是多余的一步(这个函数的输出是连续变量,分类问题期望的输出是分类变量)。这就是为什么最初的 adaline 论文提到存在量化器来将输出转换为两个值之一(-1 或 1)。这个额外的激活函数被称为符号函数。

最终注释

在本文中,我们介绍了 adaline 网络,将其与感知器进行了比较,并确定梯度下降算法是该提案引入的主要创新。然而,该算法需要考虑一些因素,以确保我们在训练过程结束时找到最优的权重集。这是我们将在下一章详述的事情。敬请期待!

感谢阅读!你喜欢这篇文章吗?非常感谢你的反馈,🗣。你可以随时通过 TwitterLinkedIn 联系我,或者如果你对下一章的最新消息感兴趣,就在 Medium 上关注我😀。

一些相关阅读:

  • 我关于梯度下降的笔记本可以在这里找到;
  • https://pabloinsente.github.io/the-adaline
  • https://arjunkathuria.com/ml/Adaline/
  • https://sebastianraschka . com/FAQ/docs/linear-gradient-derivative . html
  • https://towards data science . com/introduction-to-neural-networks-part-1-3bb 27 A8 d 314 a作者瑞秋·萨尔希