TowardsDataScience-博客中文翻译-2022-二十八-

TowardsDataScience 博客中文翻译 2022(二十八)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

如何为数据科学项目生成文档字符串

原文:https://towardsdatascience.com/how-to-generate-docstrings-for-data-science-projects-bb78c56fd539

在几秒钟内生成清晰且格式良好的 python 文档字符串

照片由凯蒂·赫尔Unsplash 拍摄

介绍

"我 6 个月前写了这个函数,现在我不记得它是做什么的了!"这听起来熟悉吗?在赶时间的过程中,我们经常忽略了好的文档(又名 docstrings)对于我们创建的类、方法和函数的重要性。

那么什么是 docstrings 呢?

文档字符串也称为文档字符串,是描述 python 类、函数或方法的字符串文字。这里有一个 Google docstring 格式的函数的 docstring 的例子。

def add_two_values(x:int, y:int = 0) -> int:
    """Add two values and return the sum. Args:
        x (int): first value
        y (int, optional): second value. Defaults to 0. Raises:
        TypeError: x and y must be integers Returns:
        int: summation of x and y
    """ if not all([isinstance(i, int) for i in [x,y]]):
        raise TypeError('inputs must be integer')
    else:
        z = x + y return z

上面的 docstring 提供了对add_two_values函数的一般描述,随后是对输入参数xy、输出z和引发的错误的描述。Docstrings 为试图使用您开发的类、函数或方法的开发人员提供了指南。

在本文中,我们将研究常见的 python docstring 格式,以及如何使用 autoDocstring 和 VSCode 为 python 函数、类和类方法生成自动化的 docstring。

常见的 Python 文档字符串格式

下面是一些常用的 python docstring 格式[1]。通常,文档字符串格式包括以下元素:

  • 对该函数功能的描述
  • 参数:说明和数据类型
  • 返回值:说明和数据类型
  • 出现的错误的描述

谷歌

def abc(a: int, c = [1,2]):
    """_summary_ Args:
        a (int): _description_
        c (list, optional): _description_. Defaults to [1,2]. Raises:
        AssertionError: _description_ Returns:
        _type_: _description_
    """
    if a > 10:
        raise AssertionError("a is more than 10") return c

NumPy

def abc(a: int, c = [1,2]):
    """_summary_ Parameters
    ----------
    a : int
        _description_
    c : list, optional
        _description_, by default [1,2] Returns
    -------
    _type_
        _description_ Raises
    ------
    AssertionError
        _description_
    """
    if a > 10:
        raise AssertionError("a is more than 10") return c

狮身人面像

def abc(a: int, c = [1,2]):
    """_summary_ :param a: _description_
    :type a: int
    :param c: _description_, defaults to [1,2]
    :type c: list, optional
    :raises AssertionError: _description_
    :return: _description_
    :rtype: _type_
    """
    if a > 10:
        raise AssertionError("a is more than 10") return c

PEP257

def abc(a: int, c = [1,2]):
    """_summary_ Arguments:
        a -- _description_ Keyword Arguments:
        c -- _description_ (default: {[1,2]}) Raises:
        AssertionError: _description_ Returns:
        _description_
    """
    if a > 10:
        raise AssertionError("a is more than 10") return c

在 VsCode 中生成自动文档字符串

在本节中,我们将通过示例演示如何在 VSCode 中生成自动化的 docstring。

设置

要在 VSCode 中生成自动化的 docstring,我们需要

  1. 虚拟代码
  2. 安装了 autoDocstring VSCode 扩展
  3. Python 3.5 及以上版本

VSCode 设置

autoDocstring 允许我们从 VSCode 的用户设置中选择一系列常用的 Docstring 格式。

作者图片

对于其余的例子,我们将使用默认的 Google docstring 格式。

函数的文档字符串

让我们写一个简单的函数将两个整数值相加。

def add_two_values(x, y): return x + y

要生成 docstring,将光标放在函数定义正下方的行中(即在def关键字下方),并执行以下任一步骤:

  1. 用三个双引号或三个单引号开始 docstring,然后按下Enter
  2. windows 使用键盘快捷键CTRL+SHIFT+2,mac 使用CMD+SHIFT+2
  3. 使用 VsCode 命令面板中的Generate Docstring

作者 GIF

这将以如下方式填充函数体。

def add_two_values(x, y):
    """_summary_ Args:
        x (_type_): _description_
        y (_type_): _description_ Returns:
        _type_: _description_
    """
    return x + y

_summary__type__description_是占位符,我们需要用实际的描述来替换它们。

autoDocString 可以通过从类型提示推断参数类型来自动填充_type_占位符。让我们在函数中包含参数和返回值的类型提示。

def add_two_values(x:int, y:int)->int: return x + y

生成 docstring 后,函数体将按以下方式填充。

def add_two_values(x:int, y:int)->int:
    """_summary_ Args:
        x (int): _description_
        y (int): _description_ Returns:
        int: _description_
    """
    return x + y

请注意,_type_占位符现在填充了参数和返回值的数据类型。

大多数 docstring 格式还包括对出现的错误的描述。如果xy参数不是整数,我们就抛出一个TypeError

def add_two_values(x:int, y:int)->int: if not all([isinstance(i, int) for i in [x,y]]):
        raise TypeError('inputs must be integer')
    else:
        return x + y

新生成的 docstring 将包含一个描述出现的错误的子部分。这是我们在替换了_description__summary_占位符后得到的结果。

def add_two_values(x:int, y:int)->int:
    """Add two values and return their sum. Args:
        x (int): first value
        y (int): second value Raises:
        TypeError: input values must be integers Returns:
        int: sum of input values
    """
    if not all([isinstance(i, int) for i in [x,y]]):
        raise TypeError('inputs must be integer')
    else:
        return x + y

类和类方法的 Docstring

类似的方法可以扩展到类和类方法 docstrings。

作者 GIF

结论

在本文中,我们研究了以下内容:

  1. 文档字符串的重要性
  2. 常见的文档字符串格式
  3. 使用 AutoDocString 在 VsCode 中自动生成文档字符串

文档字符串是任何代码的重要组成部分,因为它有助于开发人员理解函数、类和模块的整体功能。想象一下,如果 scikit-learn、pandas 和 NumPy 等数据科学库没有 docstrings,会有多混乱!快乐记录!

加入 Medium 阅读更多这样的文章!

https://medium.com/@edwin.tan/membership

参考

[1]https://github . com/NilsJPWerner/autoDocstring/tree/master/docs

如何生成免费的数据质量报告

原文:https://towardsdatascience.com/how-to-generate-free-data-quality-reports-cdf5cf3fc56b

使用最新的开源工具 re_cloud

照片由张秀坤在 Unsplash 上跳舞

人们如此频繁地谈论数据质量是有原因的——它很重要!如果你没有高质量的数据,你的矿也没有任何数据。您的数据质量直接决定了您对业务洞察的质量。

在实施数据质量计划时,您应该始终关注您的源数据。当您在源处关注数据时,您可以在问题进入下游数据模型之前捕捉到它们。这确保了业务团队看到的是已经测试过的数据,知道他们在使用这些数据时是可靠的。

数据质量的很大一部分也是为了确保这个源数据及其下游数据模型按预期更新。业务团队需要知道他们什么时候会得到他们需要的数据,以及他们需要的节奏。数据必须是新的,见解才能准确。

re_data 是一款开源工具,可以轻松测量数据质量。它允许您设置不同的警报,以便在数据出现异常时通知您。我最喜欢跟踪的一些指标是新鲜度、方差和数据量。re_data 还允许您轻松地设置 Slack 和电子邮件提醒,以便您在最常用的地方得到通知。

我最近了解到 re_data 也有一个云产品,可以帮助您在一个地方收集所有的数据质量报告。让我们更深入地探讨一下这个问题!

re_cloud 是什么?

re_cloud 是一个用户界面,允许您存储和协作来自 re_data、其他开源工具和定制数据工具的数据质量报告。它将您所有最重要的信息整合在一个位置,让您能够全面了解您的数据。您只需下载由外部工具生成的 HTML 报告,或者从您的本地环境生成报告,并将它们上传到云中的一个中心位置。

re_cloud 集成了许多数据工具,如远大前程熊猫Trino ,以及 Postgres、Redshift、Bigquery 和 Snowflake 等数据仓库。在本教程中,我将带您在 re_cloud 中集中 re_data 报告和 dbt 文档。

将您的报告放在一个地方的好处

在我们进入教程之前,让我们来讨论一下为什么你想要所有的数据质量报告都在一个地方。我希望你考虑一下你的云数据平台。这充当了您的单一真实来源——从您所有不同数据源获取数据的位置。数据团队和业务利益相关者知道,他们可以依靠这个云数据平台来获得最准确、最新的数据。

这与为您的数据源和 dbt 模型上最重要的数据质量信息提供一个中心位置的想法是一样的。数据团队不必检查单个工具中的仪表板和指标,也不知道该依赖哪一个,而是可以导航到一个真实的来源。在这里,他们可以获得从接收到编排的整个数据生态系统的整体视图。

re_cloud takes 还将 dbt 文档与这些质量报告一起部署。将您的文档放在这些报告旁边可以节省您在两个 ui 之间切换的时间和精力。因为文档是在产品中构建的,所以您可以很容易地将预期与您的数据管道中正在发生的事情进行比较。

查看 dbt 模型沿袭是 dbt docs 和 re_data 一起部署的一个特性,它允许您测量质量警报对下游数据模型的影响。看到写在一个列上的 dbt 测试可以让你理解什么样的列值应该和什么样的列值进行比较。当试图解决一个严重的生产问题时,像这样的小事可以节省大量时间。

我开始使用 re_data 的原因之一是因为它使查看全貌变得非常容易。我看到了我想看到的信息,而且仅仅是这些,因为该工具使我能够轻松地将警报发送到我想要的位置。现在,他们更进一步,不仅允许你查看他们的提醒,还允许你查看来自其他工具的提醒。

如何设置云

请记住,re_data 假设您是 dbt 用户。云产品直接与 dbt 项目和可选的 re_data 一起工作。首先,你需要安装 re_cloud Python 包。

pip install re_cloud

接下来,你需要在 re_cloud 平台上生成一个 API key。请确保首先创建一个帐户,然后您可以导航到右上角的您的用户资料。单击“帐户设置”,然后单击“Api 密钥”。这里将有一个访问密钥,您可以复制。

作者图片

我们将把它输入到你已经设置了 re_data 的 YAML 文件中。如果还没有为 re_data 创建文件,我建议将它放在一个单独的 re_data.yml 文件中。带有 api 键的 re_cloud 块应该如下所示:

作者图片

一定要将这个 yaml 文件保存在~/中。re_data/ directory。这将确保 re_data 在正确的位置查找。

在 re_cloud 中生成报告

现在我们已经准备好开始生成一些报告了!

dbt 文档

让我们从生成 dbt 文档开始。如果您还不知道,dbt 有一个特性,您可以在一个格式良好的 UI 中填充 YAML 文件中定义的信息。这充当了一个干净的数据目录,数据团队甚至业务团队的用户可以查看关于源或模型的更多细节。它还显示模型沿袭和应用于不同数据资产的测试。要生成这些文档,您可以运行以下命令:

dbt docs generate

然后,要将它们上传到 re_cloud,请运行以下命令:

re_cloud upload dbt-docs

请记住,您需要在这里安装 dbt-core。由于某种原因,我没有,这个命令失败了。您可以通过运行以下命令来安装 dbt-core:

pip install dbt-core 

运行这个命令并再次运行 re_data 命令后,我得到一条消息,表明我的 dbt 文档已经成功上传到 re_cloud。

作者图片

如果您导航到 re_cloud,您应该会看到您的报告已上传。

作者图片

如果您单击顶部块,dbt 文档将在一个单独的选项卡中打开。现在,您可以进一步探索您的 dbt 项目、表、列定义等等!

作者图片

re_data

现在让我们为 re_data 包生成一个报告。我使用 re_data 测试我的大多数关键指标,如数据量和新鲜度,所以这对我上传到 re_cloud 非常重要。首先,要生成报告,请运行以下命令:

re_data overview generate 

然后,要将报告上传到 UI,请运行:

re_cloud upload re-data

您应该得到另一个状态代码 200,这意味着成功,就像您对 dbt 文档所做的那样。

作者图片

当您导航到 UI 时,现在应该看到两个块——一个用于 dbt_docs,另一个用于 re_data_overview。

作者图片

单击 re_data_overview 块后,您将看到 re_data 的主要特性,如警报、沿袭、测试、表格和指标。这为您提供了友好、直观的数据质量信息。

作者图片

计划您的云报告(_ u)

我建议创建一个系统,让您团队中的某个人每周生成 re_cloud 报告,并将它们上传到 re_cloud。更好的是,您可以自动执行这些命令,直接在您的数据管道中运行,确保 re_cloud 每天更新。

就我个人而言,我使用提督来编排我的数据管道。使用这个工具可以很容易地设置任务之间的依赖关系。当我的模型每天早上运行完毕时,我已经使用 Prefect 触发了我的日常 re_data 测试。为此,我在我的提督流中运行以下命令:

dbt_task(command=’dbt run -m re_data’, task_args={“name”: “re_data monitoring”})

为了在 re_cloud 中生成和上传报告,我们将使用在本地 CLI 上运行的相同命令。但是,这一次我们将把它们包含在 Prefect 流的 dbt_task 中。

这看起来像这样:

Generate_re_data = trigger_dbt_cli_command(
        "re_data overview generate"
    )

Generate_dbt_docs = trigger_dbt_cli_command(
        "dbt docs generate"
    )

Upload_re_to_re_cloud = trigger_dbt_cli_command(
        "re_cloud upload re-data"
    )

Upload_docs_to_re_cloud = trigger_dbt_cli_command(
        "re_cloud upload dbt-docs"
    )

这里,我在两个独立的任务中生成 re_data 报告和 dbt 文档。然后我用两个不同的命令上传它们,我已经把它们分配给了两个变量 upload_re_to_re_cloudupload_docs_to_re_cloud

请记住,在 Prefect 等编排工具中设置依赖关系非常重要。您不希望在生成报告之前运行 re_cloud upload 命令,因此可以将这两个生成任务设置为上游依赖项。

使用 Prefect 为该任务设置上游依赖项如下所示:

Re_data_upload = Upload_re_to_re_cloud(wait_for=[generate_re_data])

dbt_docs_upload = Upload_docs_to_re_cloud(wait_for=[generate_dbt_docs])

当您直接在数据管道中实现这些命令时,一切都会无缝运行。您知道,当您的管道每天早上运行时,re_cloud 中也会有更新的数据质量报告等着您。

结论

拥有一个像 re_cloud 这样的中心位置是跟踪整个数据堆栈的数据质量的一个很好的方法,不管使用什么工具。一个中心位置可以让您全面了解数据的状态,让您可以轻松地比较不同的报告,并找出任何低标准的原因。

使用像 re_cloud 这样的工具在你的公司内建立透明的文化;每个人都可以了解数据质量,而不仅仅是数据团队。像这样的工具让非技术人员更容易理解他们每天使用的数据。这是一个强大的工具,可以将数据和业务团队团结在一个共同的目标上。

更多关于产生高质量数据的信息,请查看我的免费每周时事通讯关于分析工程。

如何用稳定的扩散模型从文本生成图像

原文:https://towardsdatascience.com/how-to-generate-images-from-text-with-stable-diffusion-models-ea9d1cb92f9b

图片由作者提供。由拥抱脸创作的 colab 笔记本代码生成。

快速介绍使用拥抱脸的扩散包文本到图像的生成

在这篇文章中,我将向你展示如何使用 Hugging Face 的扩散器包,使用稳定的扩散模型开始文本到图像的生成。

从 DALLE 到稳定扩散

不久前,我获得了 OpenAI 的 DALLE-2 模型,它允许你从文本中创建令人惊叹的图像。所以,我开始摆弄它,并产生了一些相当惊人的图像。

图片由作者提供。用 DALL-E 2 生成。

然而,我的学分用完了,所以我决定寻找替代品,并通过拥抱脸看到了这篇不可思议的文章,

https://huggingface.co/blog/stable_diffusion

这解释了如何使用他们的diffusers包运行稳定的扩散模型。

因此,让我们深入研究如何使用diffusers从文本生成图像!

用稳定的扩散管道从文本生成图像

先说第一件事, 步骤用 ***diffusers*** 包从文本中生成图片有:

  1. 确保你有 GPU 访问权限
  2. 安装要求
  3. 在 Google Colab 上启用外部小部件(适用于 Colab 笔记本)
  4. 使用您的用户令牌登录拥抱脸
  5. 初始化
  6. 将管线移动到 GPU
  7. 用 Pytorch 的 **autocast** 模块运行推理

因此,对于这个项目,由于我或多或少地通过拥抱脸 来跟随 colab 笔记本,我们将假设您可以访问具有 GPU 启用 的 colab 笔记本。我们开始吧!

1.确保您有 GPU 访问权限

!nvidia-smi# My Output

图片由作者提供。

好的,太好了!现在我们知道我们可以访问 GPU,让我们设置这个项目的要求。

2.安装要求

本项目有 5 个主要要求:

  • diffusers==0.2.4 —运行管道的主要软件包
  • transformers —拥抱 Face 的套装中有许多预先训练好的文本、音频和视频模型
  • scipy —科学计算的 Python 包
  • ftfy —用于处理 unicode 问题的 Python 包
  • ipywidgets>=7,<8 —用于在笔记本上构建小部件的包
  • torch — Pytorch 包(在 colab 不用安装)
  • pillow —用于处理图像的 Python 包(如果您在 colab 中,则无需安装)

要在 Google Colab 中安装您实际需要的所有东西,只需运行:

!pip install diffusers==0.2.4!pip install transformers scipy ftfy!pip install "ipywidgets>=7,<8"

3.在 Google Colab 上启用外部小部件(适用于 Colab 笔记本电脑)

# enabling widgets (to be able to login to hugging face)from google.colab import outputoutput.enable_custom_widget_manager()

4.使用您的用户令牌登录拥抱脸

# login to huggin face (get an access token etc...)from huggingface_hub import notebook_loginnotebook_login()

您应该会看到一个小部件,您将从拥抱脸输入您的访问令牌。输入之后,您应该会看到类似这样的内容:

# Expected OutputLogin successful Your token has been saved to /root/.huggingface/token **Authenticated through git-credential store but this isn't the helper defined on your machine. You might have to re-authenticate when pushing to the Hugging Face Hub. Run the following command in your terminal in case you want to set this credential helper as the default  git config --global credential.helper store**

5.初始化StableDiffusionPipeline

import torchfrom diffusers import StableDiffusionPipelinepipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4", revision="fp16", torch_dtype=torch.float16, use_auth_token=True)

在这里,就像在他们的 colab 笔记本中一样,我们使用v1-4模型,我们将为其下载权重。一旦完成,我们就可以进入下一步。请随意试用其他型号进行比较!

6.将管道移动到 GPU

pipe = pipe.to("cuda")

7.使用 Pytorch 的autocast模块运行推理

from torch import autocastprompt = "photo of a panda surfing"with autocast("cuda"):
  image = pipe(prompt)["sample"][0] image.save(f"panda_surfer.png")image

输出

图片由作者提供。由拥抱脸创作的 colab 笔记本代码生成。

我们可以清楚地看到,结果令人难以置信。显然你会发现你得到的结果有一些可变性,但是 有一些参数你可以调整,比如 ***guidance_scale*** 、步数和设置随机种子 (用于确定性输出),这将帮助你得到更一致的结果。

最后的想法和建议

在官方 colab 笔记本 by 抱脸,(本文主要来源)他们有关于稳定扩散的清晰而简单的解释,以及让你更深入了解这个话题的资源,所以我推荐你去看看!我会给出一些额外的建议,看看这些资源:

如果你喜欢视频形式,请点击这里查看我的 Youtube 视频:

如果你喜欢这篇文章,加入媒体关注订阅我的时事通讯。还有,订阅我的 youtube 频道Tiktok推特LinkedInInstagram 上和我联系!谢谢,下次再见!😃

参考

如何在几秒钟内生成稳定扩散的图像

原文:https://towardsdatascience.com/how-to-generate-images-with-stable-diffusion-for-pennies-and-the-limitations-of-this-approach-d1cd4b4a4166

以及局限性(今天!)的这种方法

一个潜在的文本到图像扩散模型稳定扩散的作者已经发布了该模型的权重,并且它在标准 GPU 上运行非常容易和便宜。这篇文章向你展示了如何用很少的钱生成图像(生成 30-50 张图像大约需要 65 美分)。

启动一个顶点 AI 笔记本

稳定扩散模型是用 Pytorch 编写的,如果您有超过 10 GB 的 RAM 和相当现代的 GPU,它会工作得最好。

在 Google Cloud 上,打开链接【https://console.cloud.google.com/vertex-ai/workbench 进入顶点 AI 工作台

在谷歌云中创建 PyTorch 笔记本

然后,创建一个新的顶点人工智能 Pytorch 笔记本电脑与英伟达特斯拉 T4。接受默认值。当我做这件事的时候,这个例子的成本是每小时 65 美分。

请记住,一旦使用完笔记本,请将其停止或删除。区别?如果你停止笔记本,你将被收取磁盘费(一个月几分钱,但它允许你下次更快地启动)。如果你删除了笔记本,你将不得不重新开始。在这两种情况下,您都不必为 GPU 付费,这是 65 美分/小时费用的主要部分。

注意:如果你无法访问谷歌云,找到你可以访问的带 GPU 的笔记本环境——也许是 AWS Sagemaker,或者谷歌 Colab Pro。免费的 Google Colab 不够强大。

当实例启动时,执行下一步。

注册一个拥抱脸账户

重量被释放在拥抱脸枢纽,所以你将需要创建一个帐户,并接受下重量被释放的条款。请通过以下方式完成:

克隆我的笔记本并创建 token.txt

我很方便地将本文中的代码放在了 GitHub 上,所以只需克隆我的笔记本:

在这个存储库中:

https://github.com/lakshmanok/lakblogs

并打开笔记本stable diffusion/stable _ diffusion . ipynb

右键单击导航窗格并创建一个新的文本文件。将其命名为 token.txt,并将您的访问令牌(来自上一节)粘贴到该文件中。

安装软件包

笔记本的第一个单元只是安装需要的 Python 包(逐个运行笔记本中的单元):

pip install --upgrade --quiet diffusers transformers scipy

使用笔记本上的按钮重新启动 IPython 内核:

读取访问令牌

还记得您粘贴到 token.txt 中的访问令牌吗?我们来读一下:

**with** open('token.txt') **as** ifp:
    access_token **=** ifp**.**readline()
    print('Read a token of length {}'**.**format( len(access_token) ))

加载模型权重

要加载模型权重,请使用名为“扩散器”的拥抱面库:

**def** load_pipeline(access_token):
    **import** torch
    **from** diffusers **import** StableDiffusionPipeline

    model_id **=** "CompVis/stable-diffusion-v1-4"
    device **=** "cuda"

    pipe **=** StableDiffusionPipeline**.**from_pretrained(model_id, 
                       torch_dtype**=**torch**.**float16, 
                       revision**=**"fp16", 
                       use_auth_token**=**access_token)
    pipe **=** pipe**.**to(device)
    **return** pipe

我在这里使用了一个稍微差一点的模型版本,这样它可以执行得更快。阅读 Huggingface 文档了解其他选项。

为文本提示创建图像

要为文本提示创建图像,只需调用上面创建的管道,传入文本提示。

**def** generate_image(pipe, prompt):
    **from** torch **import** autocast
    **with** autocast("cuda"):
        image **=** pipe(prompt**.**lower(), guidance_scale**=**7.5)["sample"][0]  

    outfilename **=** prompt**.**replace(' ', '_') **+** '.png'
    image**.**save(outfilename)
    **return** outfilename

在这里,我传入提示“光头佬很容易被机器人打动”:

outfilename **=** generate_image(pipeline, prompt**=**"Bald guy being easily impressed by a robot")

秃子很容易被机器人打动

这花了不到一分钟的时间,对于演示文稿、故事板等来说已经足够好了。不错吧,嗯?

仅限于其训练集

人工智能模型受限于它们被训练的内容。让我们传递一个文化参考,它不太可能已经看到很多培训数据:

outfilename **=** generate_image(pipeline, prompt**=**"Robots in the style of Hindu gods creating new images")

结果呢?

印度教神风格的机器人创造新形象

嗯,它选择了甘尼萨的姿势,赋予他机器般的四肢,并使用西藏转经筒作为图像。这里没有魔法——ML 模型只是简单地复述他们在训练数据集中看到的一点一滴,这就是正在发生的事情。

我在这里的文化参考是上帝搅动牛奶的海洋,它完全飞过模特的头顶:

谷歌图片搜索了解所有关于搅拌牛奶海洋的印度创世神话

让我们看看是否可以通过传递允许 Google 图片搜索检索所有这些图片的特定术语来明确地帮助模型唤起它的记忆:

outfilename = generate_image(pipeline, prompt="Robots churning the ocean of milk to create the world")

这看起来像是机器人搅拌牛奶的海洋吗?

那也没用。印度教创世神话一定不是用于训练模型的数据集的一部分。

其他限制

所以文化参考是过时的。还有什么?该模型不会生成真实的人脸或文字符号——我会让您尝试这些。

此外,这些仅仅是今天的限制。造成这些限制的原因是模型训练数据集的大小。很难约束一个在非常大的数据集上训练的模型不回想起不可避免会在那里发现的有毒内容。这就是为什么公开发布的模型可能是在一个较小的语料库上训练的。

尽管如此,不要忽视我们在稳定扩散方面取得的进展——图像生成过去需要很大的马力。但是我们现在可以在普通的 GPU 和 15 GB 的内存上实现。这本质上是云函数的领域——你可以很容易地想象将我上面的代码放入云函数,这样它就成为一个图像生成 API,并在你的应用中使用它。

结论

最后,下面是模型生成的一些图片以及生成它的提示:

火星漫游者玩游戏

斯蒂芬·库里踢足球

你能够在几秒钟内生成与文本提示相对应的图像,这有多酷?

我的笔记本在 GitHub 上的位置是https://GitHub . com/lakshmanok/lak blogs/blob/main/stable diffusion/stable _ diffusion . ipynb

尽情享受吧!

如何使用人工智能在您的笔记本电脑上生成令人惊叹的艺术

原文:https://towardsdatascience.com/how-to-generate-stunning-art-on-your-laptop-using-ai-a28192cbb49

如何使用稳定扩散从自然语言的描述中创建逼真的图像,而无需 GPU。

一个戴着画家帽子的机器人正在白色画布上画一座山。数字艺术——稳定扩散生成的图像

当我还是个孩子的时候,我总是钦佩那些能画出任何想到的东西的人。我可以连续几个小时观察它们,因为它们会在纸上形成看似随意的线条。不幸的是,我没有这种天赋。

随着时间的流逝,今天人工智能可以帮助我实现我脑海中的想法。这是两码事,而且这个过程一点也不令人满意。但这是我在纸上表达想法的一种方式。

当 OpenAI 允许我进入 DALL E 2 私人测试程序时,我非常兴奋。然而,缺点是我可以用它做什么的限制,我可以使用它的次数,价格标签,以及我不能以任何方式控制软件的想法。

然后,稳定扩散来到了方。与 DALL E 2 非常相似,Stable Diffusion 是一个开源的 AI 系统,它从自然语言的描述中创建了逼真的图像和艺术。它结合了概念、属性和风格来创建独特的照片或现有图片的设备变体。好消息是你现在可以在你的笔记本电脑上运行它。

这个故事展示了你如何能在 10 分钟之内在你的系统上创造出令人难以置信的艺术,,即使你没有 GPU 设备。我将指导您完成安装过程;您所需要的只是访问一台运行 Python 并安装了 Git 的机器。最后,你将能够用自然语言与模型交流你想画的东西,然后坐下来享受回报。

Learning Rate 是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每个月的第一个星期六收到我关于最新人工智能新闻和文章的更新和想法。订阅这里

什么是稳定扩散

我们说过,稳定扩散是一种潜在扩散模型(LDM ),它从自然语言的描述中创造出现实的图像和艺术。它是由 Stability AILMU 慕尼黑开发的,得到了 Eleuther AILAION 社区的支持。

稳定扩散从像 Open AI 的 DALL E 2 或 Google BrainImagen 这样的项目中汲取灵感,并在 LAION-Aesthetics 上进行训练,这是 LAION 5B 即将发布的子集。

稳定扩散作为一个开源项目在 GitHub 上提供。由于其非常宽松的许可证,它让数十亿人能够创造令人惊叹的图像。

设置您的环境

现在我们有了这个项目的一些背景,让我们把它投入工作。该过程的第一步是设置您将在其中工作的 Python 环境。

稳定的扩散伴随着如何创造一个迷你康达环境的说明。如果您熟悉使用一个environment.yaml文件创建 conda 环境,您可以很好地使用它。然而,我更喜欢使用用venv构建的简单 Python 虚拟环境,用pip安装包。

我的机器是 Ubuntu 22.04 系统,带 Python 3.8.10。为此,你至少需要 Python 3.8.5。所以,首先,克隆存储库:

git clone [https://github.com/dpoulopoulos/stable-diffusion.git](https://github.com/dpoulopoulos/stable-diffusion.git) -b [feature-dimpo-local-deployment](https://github.com/dpoulopoulos/stable-diffusion/tree/feature-dimpo-local-deployment)

注意,这不是原来的稳定扩散库。这是我为了稍微修改代码而创建的一个 fork。这些修改允许你运行项目,即使你不能访问 GPU。该项目的原始代码位于https://github.com/CompVis/stable-diffusion

进入项目目录并创建一个 Python 虚拟环境:

cd stable-diffusion && python3 -m venv venv

接下来,激活您的虚拟环境并安装项目所需的pip版本:

source venv/bin/activate && pip3 install --upgrade pip=20.3

正如我们所说的,稳定的扩散伴随着 conda 环境,您可以使用它来安装依赖项。我不会使用它,所以我需要创建一个单独的requirements.txt文件。

如果您已经克隆了我在第一步中提供的分支,那么您不需要运行这一步。资源库中已经存在一个requirements.txt文件。如果没有,请使用下面的命令创建一个:

cat << EOF > requirements.txt
numpy==1.19.2
--extra-index-url [https://download.pytorch.org/whl/cpu](https://download.pytorch.org/whl/cpu)
torch==1.11.0+cpu
torchvision==0.12.0+cpu
albumentations==0.4.3
diffusers
opencv-python==4.1.2.30
pudb==2019.2
invisible-watermark
imageio==2.9.0
imageio-ffmpeg==0.4.2
pytorch-lightning==1.4.2
omegaconf==2.1.1
test-tube>=0.7.5
streamlit>=0.73.1
einops==0.3.0
torch-fidelity==0.3.0
transformers==4.19.2
torchmetrics==0.6.0
kornia==0.6
-e git+https://github.com/CompVis/taming-transformers.git@master#egg=taming-transformers
-e git+https://github.com/openai/CLIP.git@main#egg=clip
EOF

现在,我可以在我的虚拟环境中安装项目的依赖项了:

pip3 install -r requirements.txt

最后,我需要安装稳定的扩散库本身:

pip3 install -e .

获取模型

现在我已经设置了环境,我需要获得模型权重。模型权重的检查点由 Hugging Face 托管,要下载它们,您需要一个帐户。所以,去他们的页面上创建一个。别忘了事后核实你的电子邮件!

下一步是下载模型。前往此地址:https://hugging face . co/CompVis/stable-diffusion-v-1-4-original同意分享您的联系方式:

作者截图

现在下载模型。您将在那里看到两个检查点文件:一个sd-v1-4.ckpt和一个sd-v1-4-full-ema.ckptema代表指数移动平均线,是恢复训练的一个检查点。出于我们的目的,我们想要下载更小的sd-v1-4.ckpt用于推理,尽管也有使用ema的方法。然而,这不是在这里讨论的事情。让我们把事情简单化。

作者截图

根据您的互联网连接,下载模型需要大约 5-10 分钟。毕竟是~4GB。当这个过程完成后,在您的项目的主目录中创建一个stable-diffusion-v1文件夹来放置它:

mkdir models/ldm/stable-diffusion-v1

将模型移动到stable-diffusion-v1文件夹中,并将其重命名为model.ckpt:

mv /path/to/sd-v1-4.ckpt models/ldm/stable-diffusion-v1/model.ckpt

运行模型

至此,您已经万事俱备了。要创建您的第一件令人惊叹的艺术品,请运行以下命令:

python3 scripts/txt2img.py --prompt "An astronaut riding a horse, painted by Pablo Picasso." --plms --n_iter 5 --n_samples 1

此时,该项目将下载它使用的几个预训练模型的权重,如剪辑编码器和核心变压器。要有耐心。另外,请注意,如果您无法访问 GPU,此步骤将会失败。但是不用担心,继续下一节,看看如何在没有 GPU 的情况下生成相同的图像。

这将生成“一个骑着马的宇航员,由巴勃罗·毕加索绘制”的图像。过程结束时,您会在一个名为outputs的文件夹中找到结果。在那里,你会看到五个图像。这是因为您指示模型使用--n_iter 5生成五个样本。

这是我得到的结果:

毕加索画的骑着马的宇航员——稳定扩散生成的图像

这很令人吃惊,你不同意吗?

没有 GPU?没问题!

如果没有 GPU,上面的脚本就不会运行。不幸的是,该项目要求你有一个 GPU 设备和 CUDA 来运行它。

然而,乐趣并不需要止于此。第一步我给你提供的库和分支也可以在 CPU 上运行稳定扩散。你付出的代价是需要一点时间来完成。根据您的系统不同,可能需要 30 多分钟才能完成。但是,嘿,如果有人给你画像,你会等多久?

要在 CPU 上运行它,只需给之前执行的命令添加一个--config标志,并指向一个不同的配置文件:

python3 scripts/txt2img.py --prompt "An astronaut riding a horse, painted by Pablo Picasso." --plms --n_iter 5 --n_samples 1 --config configs/stable-diffusion/v1-inference-cpu.yaml

摘要

与 DALL E 2 非常相似,Stable Diffusion 是一个开源的 AI 系统,它从自然语言的描述中创建了逼真的图像和艺术。它结合了概念、属性和风格来创建独特的图像或现有图片的设备变体。

这个故事演示了如何在不到 10 分钟的时间内,在您的系统上创建令人难以置信的艺术作品,即使您没有 GPU 设备。最好的部分是,这是一个软件,你可以控制和运行,每当你想产生一个图像,你可以把文字。只要考虑你所产生的东西就行了!

关于作者

我的名字是 Dimitris Poulopoulos ,我是一名为 Arrikto 工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。

如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请在 Twitter 上关注我的 MediumLinkedIn@james2pl

所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。

如何用不到 10 行代码为任何因果推理项目生成合成数据

原文:https://towardsdatascience.com/how-to-generate-synthetic-data-for-any-causal-inference-project-in-less-than-10-lines-of-code-158688a89349

如果 99%的人接种了疫苗,1%的人出现反应,2%的人得病,你如何生成有代表性的合成数据?

穆菲德·马吉纳Unsplash 上拍摄的照片

介绍

在“原因之书”中,Judea Pearl 使用了一个疫苗接种、反应、天花和死亡的例子来描述和解释“因果关系的阶梯”,这促使我用 Python 实现这个例子,但我无法找到一种方法来生成我需要开始使用的测试数据。

https://www.amazon.co.uk/Book-Why-Science-Cause-Effect/dp/0241242630

在我们深入研究合成数据生成之前,请考虑…

通过我的推荐链接加入 Medium(如果你使用此链接注册,我将收取一定比例的费用)。

每当我发表新故事时,订阅一封免费电子邮件。

快速浏览我之前的文章

下载我的免费战略数据驱动决策框架

访问我的数据科学网站— 数据博客

背景

Pearl 提出了疫苗接种计划、反应(副作用)、疾病发展以及疾病和副作用导致的死亡之间的假设关系的因果图,如下所示…

作者图片

珀尔接着描述了一项假设调查的结果如下…

  1. 在 100 万名儿童中,990,000 人(99%)接种了疫苗
  2. 在接种疫苗的人中,9900 人(990000 人中的 1%)有反应
  3. 在那些有反应的人中,99 人(9900 人中的 1%)死于该反应
  4. 在没有接种疫苗的人群中,有 200 人(10000 人中的 2%)感染了天花
  5. 在患天花的人中,40 人(200 人中的 20%)死于这种疾病

根据 Pearl 提出的因果影响图和假设调查的统计数据,我推测我的第一步是创建一个数据集,将调查表示为一只熊猫DataFrame,因此我在互联网上寻找创建数据的方法。

我找到了 scikit-learn 库,用于生成“blob”和“分类”数据,我还找到了像 fakerSDV 这样的库,但我找不到任何东西来生成适合作为因果或概率模型输入的二进制数据集。

鉴于我在网上找不到任何合适的东西,并且我需要一些数据来开始我的因果推理之旅,我开始编写代码,可以自己创建任何合成的二进制数据集…

程序性解决方案

基本要求是-

  1. 创建一个具有正确行数和特征数的空白DataFrame
  2. 用代表假设调查的 5 个结果中的每一个的值更新DataFrame

创造空的DataFrame非常简单

作者图片

下一步是实施这一规则——通过将 990,000 或 99%的行的Vaccination? = 0更改为Vaccination? = 1,实现“在 100 万儿童中,990,000 (99%)接种了疫苗”。

这被证明是非常困难的。我的第一个想法是使用DataFrame.sample(990000)进行采样并更新值,但是更新并没有应用到底层的DataFrame上,所以这是行不通的。

经过一些实验,这是我想出的解决方案…

…为了确保代码正常工作…

1    990000
0     10000
Name: Vaccination?, dtype: int64

到目前为止,一切顺利。下一步是实施这一规则——“在接种疫苗的人中,有 9900 人(99 万人中的 1%)出现反应”。这有点复杂,因为它需要两个阶段-

  1. 选择Vaccination? == 1所在的行
  2. 为这些选定行中的 9900 行(或 1%)设置Reaction? = 1

经过更多的反复试验,这是我开发的解决方案…

…为了测试它…

Vaccination?  Reaction?  Smallpox?  Death?
1             0          0          0         980100
0             0          0          0          10000
1             1          0          0           9900
dtype: int64

现在,寻找解决方案的艰苦工作已经结束,实现所有 5 个规则的整个数据集只需几行代码就可以生成…

…为了验证解决方案…

作者图片

面向对象编程(OOP)解决方案

程序性解决方案为生成合成二进制数据集提供了一个体面的实现,该数据集将用作因果和概率项目的输入,但它可以重写为 OOP 解决方案,以减少代码重复并最大化代码重用…

为假设的天花例子创建我们的合成数据集变得非常直接…

作者图片

如果你想下载二进制数据生成器的完整版本,包括全面的文档,请前往 GitHub 中的这个要点。

结论

因果推理是一个热门话题,支持和告知机器学习和人工智能这一分支的图书馆和文章的数量正在呈指数增长。

然而,创建项目以测试因果推理解决方案的第一步是创建一些合成数据,并且没有库或文章为数据创建提供模板。

本文探讨了这个问题的背景,提供了一个生成合成数据的过程化解决方案,还提供了一个面向对象的解决方案,可以轻松地重用它来生成合成数据,以测试任何因果推理问题。

如果你喜欢这篇文章,请考虑…

通过我的推荐链接加入媒体(如果你使用这个链接注册,我将收取一定比例的费用)。

https://grahamharrison-86487.medium.com/membership

每当我发表一个新故事时,订阅一封免费电子邮件

快速浏览一下我之前的文章

下载我的免费战略数据驱动决策框架

访问我的数据科学网站— 数据博客

如何找工作用 Julia(发展最快的语言)编程

原文:https://towardsdatascience.com/how-to-get-a-job-programming-in-julia-7f24a2ee563f

作者图片

我通过电子邮件和直接信息收到的最常见的问题之一是:“嘿,我真的很喜欢用 Julia 编程,我如何才能找到一份全职做这个的工作?”

在本帖中,我们将讨论如果你是 Julia 社区的一员(即使你昨天才开始使用这种语言),并且你想全职使用 Julia 找一份工作,你应该做的一些事情。我们将讨论三个要点:

  • 建立你的茱莉亚网络🕸
  • 创建内容🎥 📝
  • 做出技术贡献📦

如果你有兴趣听到招聘 Julia 开发者的公司的消息,请收听 Twitter Spaces 的录音,并查看本文的结尾,我将在这里列出一些在 Julia 生态系统中招聘的公司:

我还想补充一个简短的声明,这里提出的想法只是可能方法的一小部分。使用 Julia 找工作真的有很多不同的方法,所以我希望这篇文章可以对一种可能的方法提供独特的视角。如果你有不同的做法,请分享!让我们帮助人们找到工作。

编辑:我和我的合著者很高兴地告诉大家,我们的新书《茱莉亚速成班》已经开始预售了:

https://logankilpatrick.gumroad.com/l/juliacrashcourse

为什么是朱莉娅·⁉️

在我们深入了解使用 Julia 找工作的技巧之前,有必要从高层次了解一下为什么 Julia 是一个有助于你找到工作的技术主题。首先,公司通常对雇佣能带来新观点的人感兴趣。朱莉娅可以是那个新鲜的视角!此外,在 Julia 生态系统中有如此多的机会做出你在其他地方可能找不到的重大贡献,这可能会带来许多你可能没有的机会。最后,朱莉娅最适合解决的问题是在未来几年将有巨大就业潜力增长的领域。所有这些都是为了说,在我看来,如果你想让自己与众不同,Julia 是最好的学习和贡献语言(即使你没有被 all Julia 公司聘用或只使用 Julia)。

建立你的茱莉亚网络🕸

就像在任何领域找工作一样,你认识的人越多,你就越有可能遇到一个惊人的机会。朱莉娅社区也是如此。但是你如何开始建立你的人际网络呢?根据我的经验,最简单的方法是对语言和社区做出高质量的贡献。人们尊重那些进来并提供价值的人(这不仅仅适用于 Julia 社区)。

在本文的后半部分,我们将更多地讨论对社区做出贡献的具体方式,但是让我们继续关注这里的网络部分。每年最好的社交机会就是 JuliaCon。由于正在进行的疫情,JuliaCon 在线,这意味着你有机会与成千上万的用户和开发者免费交流!JuliaCon 以社交活动和各种技术讲座为特色。要记住的重要事情是参加技术讲座,并试图理解人们使用 Julia 的目的。没有什么比问一个有趣的、经过深思熟虑的问题更能告诉别人你关心他们的工作了。如果你很害羞,没有必要做直播,你可以随时给别人发消息或在话语上发帖。

看看上面的视频,了解一下 JuliaCon 是什么样的,以及你为什么想参加。

除了与 JuliaCon 网站上的 Julia 社区联系之外,你还可以在 Slack、Zulip、Discord、Twitter、Discourse 等网站上闲逛。你可以在 JuliaLang 网站上找到所有的社区论坛:https://julialang.org/community/。同样,要记住的重要事情是在这些平台上的对话中提供价值。一旦你做到了这一点,花一分钟和别人打招呼并介绍自己就变得容易多了,因为你们已经建立了关系。

创建内容🎥 📝

在今天的情况下,你可以为一个问题创造一些真正有趣的技术解决方案,但是如果没有人发现它,它最终不会提供任何价值。这说明开发者越来越需要创造技术内容,分享他们创造或学习的酷东西。我会注意到,你不需要从头开始构建一些东西来共享它。我开始在所有地方的堆栈溢出上“创建内容”。我会去搜索最流行的 Python 标记的问题,并在 Julia 的上下文中问同样的问题。如果我能找到答案,我会张贴出来,否则,我会张贴问题的链接,并试图获得帮助。这不仅让我学到了很多东西,还建立了我在社区中的信誉。

人们喜欢好的博客文章,Julia 社区也不例外。同样,你不需要创造一些新的技术解决方案来写一篇文章。我最近为初学者写了一篇关于 5 个 Julia 项目的文章:

</5-julia-projects-for-beginners-easy-ideas-to-get-started-coding-in-julia-938b823a0a08>

这篇文章同样没有介绍任何突破性的东西,但仍然有望为刚刚加入社区的人提供价值。分享这些文章的最佳地点是 Twitter 上的 JuliaLang 标签和官方账户的标签。

更广泛地说,为什么创作这样的内容能帮助你找到工作?一个最大的原因是它增加了你作为贡献者的知名度。这使得社区中的其他人更加了解你所做的工作,并且当机会来临的时候,有可能代表你提出建议。最重要的是,就像开源一样,这种类型的内容会给你一个公开的跟踪记录。当你参加 xyz 公司招聘 Julia developers 的面试时,你可以指出你的开源工作以及技术内容,在许多情况下,它们比编码更好地展示了你的思维过程。

创建技术内容的另一个地方是 YouTube。Julia Language 运营着一个拥有数百个视频的社区频道。如果你举办一个关于 Julia 的研讨会,或者想要录制一个关于使用软件包的视频教程,这个频道是一个发布内容的好地方。如果你对此感兴趣,请联系我。有人在自己的频道上这样做的一个很好的例子是:

https://www.youtube.com/c/juliafortalentedamateurs

你可以创造的另一种有影响力的内容是朱莉娅的书。现在还没有足够多写得好的书,但是作为写书的人可以在很多年里获得回报。你不需要使用 Julia 年,甚至不需要有博士学位。其中一个非常成功的例子是 Ahan Sengupta 的书《Julia 算法小书:培养 Julia 编程流畅性的练习册》,这本书是在 Ahan 上高中时出版的:

https://www.amazon.com/Little-Book-Julia-Algorithms-programming/dp/1838173609/ref=sr_1_1?crid=161EFXY9Y23PK&keywords=little+book+of+julia+algorithms&qid=1642512816&sprefix=little+book+of+julia+algorthms%2Caps%2C131&sr=8-1

当我读这本书的时候,我被它的质量震惊了,也对阿汉所做的工作印象深刻。有如此多的机会在邻近领域写书,这为 Julia 社区提供了真正的价值,也为你作为作者打开了许多机会。

关于这个主题,我要注意的最后一件事是,写作和教程创建过程也会给你的技术工作带来好处,因为文档在开源领域至关重要,你写得越好,你的文档就越好,越多的人会从中受益。

做出技术贡献📦

虽然这可能是最直接、最有据可查的方法,但我把它作为最后一个主要想法,以强调这样一个事实:你不需要在 Julia 社区做出很深的技术贡献就能找到工作。我个人在自己的生活中遇到了很多很酷的机会,我不是这门语言的核心贡献者,也没有编写过像 DataFrames.jl 这样的基础 Julia 包。

尽管如此,你所做的技术工作仍然应该提供价值并建立你的记录。创建 Julia 包是最好的方法之一。生态系统中仍然有相对较少(但不断增长)的软件包,因此有许多空白需要填补。如果您想了解如何创建包,请查看本教程:

虽然这个视频有点过时,但它介绍了创建第一个 Julia 包所需的所有机制。但是你不需要从头创建一个,为现有的项目做贡献是非常有价值的。朝这个方向开始的最佳方式是尝试在您感兴趣的领域中找到软件包。对我来说,这往往是机器学习,所以我总是在寻找帮助 Flux.jl 的地方。

如果你知道一个你想帮忙的包,但是不知道从哪里开始,找一个有贡献的指南。如果没有,这可能是一个很好的机会来帮助创造一个!你也可以在 GitHub 上的回购网址后添加“/contribute”来查看适合新贡献者的问题:https://github.com/FluxML/Flux.jl/contribute请注意,这可能是一个小的子集,但希望它仍然会给你提供你可能能够帮助的地方的类型的背景。

如果你已经有了一个 Julia 包,建立你的声誉和技术技能的一个方法是指导一个谷歌代码暑期班的学生。这样做有很多好处,如果你能成功地帮助一个学生,它真的能突出你的技术理解。如果你想了解更多这方面的知识和成为优秀导师的方法,请查看:

还有这篇关于话语参与的帖子:https://Discourse . Julia lang . org/t/seeking-Julia-mentors-and-projects-for-gsoc-2022/74328

在 JuliaLang 网站上,我们刚刚完成了生态系统贡献指南的第一版。本页讨论了许多你可以在 Julia 社区产生影响的技术和非技术方法。查看页面了解更多:【https://julialang.org/contribute/

我能在哪里工作?🧐

现在你知道了获得这份工作需要知道的东西,下一个问题是去哪里申请?以下是招聘 Julia developers 的地点的非详尽列表:

如果我错过了一个,请评论下面公司的链接!

如何获得技术实习——详细指南

原文:https://towardsdatascience.com/how-to-get-a-technical-internship-a-detailed-guide-ecd4e1b68154

熟悉导航技术领域的三步流程。

照片由戴恩·托普金Unsplash 上拍摄

大学三年级的秋天,我只是想在压力下不崩溃地完成我的课程。与此同时,我的一些同学已经在感恩节和圣诞节前进行了正式的暑期实习。那些没有敲定任何事情的人仍然有许多面试在等着他们。最后,有几个幸运的人收到了多份工作邀请,他们正试图做出决定。

与此同时,我是一个坐以待毙的人,甚至不知道如何开始这个过程。我稍微处于劣势,因为我的正式专业是应用数学(相对于数据科学或计算机科学),其部门资源并没有真正专注于实习场景。

尽管如此,我知道我需要在即将到来的夏天进行一次技术实习,因为这是我在决定是否继续读研之前体验工业的最后机会。接下来的几个月忙得不可开交——尽管我最终得到了一份实习工作,但直到今年 3 月,这个过程才彻底结束。

获得技术实习是许多人都面临的一项任务,拥有某种描述如何完成这一过程的指南会有所帮助。在本文中,我根据自己应对这一挑战的经验,概述了获得技术实习的三个步骤。在这样做的时候,我将讨论你应该消除的常见误解,以及你可以采取的具体步骤,以最大化你的成功机会。虽然我将从一个在大学三年级经历过这个过程的人的角度来说,但我在这里谈论的技巧和诀窍是普遍适用的。

让我们开始吧。

1.准备阶段

不出所料,这是整个实习寻找过程中最艰巨的阶段。技术实习很难获得,很大一部分归结于你做的准备。然而,这不仅仅是学习你想要的工作的材料和做一些练习题。完整的准备经历有许多不同的方面——我在下面讨论其中的一些。

照片由杰瑞米·比德尔Unsplash 拍摄

申请,申请,申请

限制人们成功找到实习机会的一个重要因素是他们的申请率。申请人的数量多得离谱,大多数公司会忽略你的申请,原因无非是因为他们有成千上万的申请要整理,根本没有人力去仔细查看每一份申请。

因此,为了应对这一点,在寻找实习机会时,你应该尽可能多地申请。我说的是超过 50 或 100 家公司。这些数字可能看起来很大(当我第一次从别人那里得知这些数字时,我也很震惊),但在某些方面,它们是必要的。我认识一些有才华的人,他们申请了多达 200 份实习工作,即便如此,如果运气好的话,也能收到 10-15 份回复。

现在,我不是说你应该盲目地申请而不考虑其他任何事情。应用程序的质量当然很重要,我将在接下来讨论这个问题。然而,也不要在数量上吝啬——这很重要。

修改你的简历

考虑到简历的信息已经变得如此广泛,令人惊讶的是仍有多少人用平庸的简历申请实习。这是我自己犯下的罪行。

让我们搞清楚一件事:你的简历很重要。如果人类在看,这很重要,因为他们需要能够快速理解和消化它;如果机器在处理它,这也很重要,因为它需要能够准确有效地提取相关信息。

因此,考虑到这一点,我将提供一份你的简历应该具备的重要特征的列表,这些特征来自各种来源,包括多次成功获得技术实习机会的人以及大学就业中心的专家:

  • 确保字体足够大,便于阅读(至少 11 磅)。
  • 如果你有大学文凭,没有必要包括你的高中教育。
  • 没有必要包括你的平均成绩。
  • 使用项目符号。
  • 用动作动词描述你在之前的职位上完成了贡献了。不要仅仅通过谷歌搜索列出标准的工作职责。
  • 项目,项目,项目!这些可以说是你简历中最重要的部分——我采访过的一些行业技术人员甚至建议把它们放在经验和教育之前。这应该包括你在以前的职位上做过的项目、班级项目和个人项目。同样,使用动作动词。
  • 把“爱好和兴趣”从简历中去掉。说真的。招聘人员有 10 秒钟的时间来确定你是否具备作为一名机器学习实习生取得成功的统计和计算技能——他们不在乎你是否喜欢在夏天背包旅行。
  • 最后,就结构而言,你的简历不需要超级花哨;它只需要是可理解的。内容优先于审美。

提交一份高质量的简历将会增加你从你申请的公司得到回应的机会——为此付出一些努力。

努力学习——半心半意的练习是不会成功的

技术类实习竞争激烈。因此,在最终面试前的几周或几个月里,你需要刻苦学习。

这意味着超越你在课堂、训练营或在线课程中学到的东西。具体来说,你需要在有限的时间内解决与你的领域相关的复杂问题。时间限制是大多数人的困扰,因为他们不习惯在这种压力下工作(尤其是如果他们已经离开学校几年的话)。我不是说这是一个完美的系统,但它就是这样,你需要暂时调整。

通过一个具体的例子可以很好地理解这一点。这里有两个:

  • 数据科学:它可能会因职位而异(例如机器学习与数据工程),但一般来说,你应该准备好回答关于统计、概率和类似主题的严格的理论问题[1]。没有捷径——你需要解决很多问题,而且需要经常做。对于有形的资源,请查看《数据科学面试 》一书
  • 计算机科学:CS 实习的筛选过程将更侧重于传统的编程难题。即使在面试之前,公司也倾向于通过在线编码挑战来筛选候选人。你需要在有限的时间内通过一系列问题的测试用例。凭经验我可以告诉你,这些挑战非常困难。为了做好准备,使用 LeetCode ,它模拟这些挑战并给你现实的实践(付费版本甚至允许你访问顶级公司使用的特定过去的挑战——如果你负担得起,这可能是值得投资的额外好处)。

全心全意地投入学习——你无法回避这些面试需要培养的特定技能。唯一的办法就是通过。

你没迟到

这个技巧很短,但是非常重要。11 月中旬,当我的一些同行已经获得实习机会时,我开始恐慌,认为我的机会渺茫。

这根本不是真的。公司有不同的招聘时间表,你可以在新的一年获得夏季或秋季的实习机会。例如,我直到三月份才拿到我的。

所以,如果二月来临时,某个随机的、毫无头绪的朋友告诉你申请实习已经太晚了,忽略他们,无论如何都要去做。

不要气馁(第一部分)

获得技术实习的准备阶段是艰苦的,你的耐心将受到多次考验。冒名顶替综合症一定会在某个时候袭来,让你质疑自己的能力,考虑放弃。

当这种情况发生时,休息几天,然后提醒自己当初为什么要开始。这对每个人来说都很难——你在 LinkedIn 上看到的吹嘘自己在谷歌和脸书实习的人只是在展示精彩片段。几乎可以肯定,这个过程对他们来说也是艰难的,但是他们成功了,因为他们坚持不懈。你也可以。

2.面试阶段

好吧,你去面试了。接下来呢?这一阶段的成功很大程度上取决于你在到达这里之前做了多少准备(即上面的第一阶段)。我不会重复同样的提示。然而,在你走了这么远之后,还有不要把事情搞砸的问题。为了帮助你避免这种情况,我会告诉你一些具体的技巧,你可以在下次技术面试中运用。

照片由克里斯蒂娜@ wocintechchat.comUnsplash 上拍摄

练习你的演讲技巧

这是技术上的准备,但我把它放在这里,因为它与实际面试中发生的事情非常相关。

了解材料最多只是进行一场杀手级面试的一半。另一半是以一种可理解的、有效的方式传达你所知道的信息。如果你不能向面试官传达任何信息,那么你有多优秀也没用。

学习这项技能的最好方法是通过模拟面试。拿一块白板,找一个朋友,模拟一次面试。一些重要的事情要记住:

  • 确保你在现实的时间限制下练习。
  • 上网找一些和具体工作(甚至公司)相关的真实面试问题来练习。
  • 让你的朋友打断你,问你一些困难的问题,这样你可以练习快速思考。
  • 提高你具体的沟通技巧——包括清晰地说话,进行有意义的眼神交流,展示自信的肢体语言。

尽可能多地这样做——会有回报的。面试好是一门可以通过实践学习和培养的技能。

专注于你所知道的

申请人中一个常见的误解是,你必须提供一个完美的解决方案,才能被考虑录用。这不是真的。

面试官主要对你的思维过程和方法感兴趣——所以如果你搞砸了什么或者不知道问题的答案,不要惊慌。深呼吸,慢慢来。

当你回答问题时,不要纠结于你正在纠结的信息。在面试中,集中展示你所知道的一切。大多数面试官都不是混蛋,如果他们感觉到你的想法是对的,他们会鼓励你并给你提示。此外,接受这些暗示并采取行动不会影响你获得工作的机会,尤其是在申请实习的时候。

准时出现

这一个是相当不言自明的。你的面试官已经为你留出了一个特定的时间段,有固定数量的问题,如果你迟到了,也不能保证你能够延长这个时间段或者重新安排。

没有面试=没有实习。所以要准时。

向面试官寻求反馈

从长远来看,这是一种被低估的提高面试技巧的方法。无论你的面试进展顺利还是不顺利,之后花点时间向面试官寻求一些反馈。他们通常非常有经验(无论是作为面试官还是被面试者),他们能对你的表现提供你可能看不到的见解。

你会学到你应该继续做什么,你会学到你需要做什么不同。如果你进入了下一轮,你可以应用反馈来打击他们。如果面试不像你希望的那样顺利,你可以在下一家公司运用你学到的东西。

不要气馁(第二部分)

在面试阶段的中间——尤其是前几次不成功的时候——通常是人们经历第二轮冒名顶替综合症的时候。建议和以前一样——深呼吸,坚持下去。我在这里包括这一部分只是为了提醒你,有这种感觉是正常的,你的感觉是有效的。承认它们,但不要放弃。

3.要约阶段

Cytonn 摄影Unsplash 上拍照

谈判技巧

我绝不是谈判大师,但我尝试着整理了以下三个实用技巧。肯定有一些方法可以提高你得到的工作机会(听起来没有权利或自命不凡),你应该好好利用它们。

  1. 如果你从另一家公司得到了一份更好的工作,你可以用它作为与当前公司谈判的筹码。有些人建议撒谎,假装你有其他更好的机会,即使你没有,因为谁会知道呢?请不要这样做。我不能肯定地说谎言会抓住你——但是如果它抓住了,后果将是可怕的。如果你诚实地经历这个过程,你会对自己感觉更好。
  2. 你甚至可以利用现有的机会获得更多的面试。如果你在等你梦想中的公司的回复,你可以给他们发一份现有的工作邀请。下面是一个如何做到这一点的具体例子,由纳曼·辛格在 LinkedIn 上提供。
  3. 如果你有公司需要的有市场需求的特定技能,在谈判时引用它们。如果你向他们展示他们需要你,你就增加了获得更好工作的机会。

确保你知道你要做什么

当你得到一份工作时,这通常是一个激动万分的时刻。很容易陷入这些情绪中,并投入到可能不适合你的实习中。

我犯了这个错误。我实习的那家公司筛选程序很差,当我真正开始工作时,我根本不知道自己在做什么。它涉及到密集的系统编程——在面试过程中一次也没有提到,也是我不擅长的话题。

可悲的是,许多公司都是如此。技术职位的筛选过程通常是有缺陷的,被塑造成适合大多数公司实行的标准面试结构。在做出承诺之前,做好自己的研究并确认这份工作适合你是非常重要的,否则你以后会很痛苦。

不要气馁(第三部分)

令人惊讶的是,许多人在工作结束时也会感到气馁。为什么?他们开始将自己的提议与朋友和同事收到的进行比较。如果你开始这样做,立即停止。你的成功并不取决于与他人的关系。

这是你的时刻。好好享受吧。

最后的想法和总结

在这篇文章中,我试图收集一些技巧,详细说明获得技术实习的过程。它们对我和其他人都有帮助,我希望它们对你也有帮助。

这里有一个快速的“备忘单”来回顾一下:

  • 准备阶段
    ——申请,申请,申请
    ——修改你的简历
    ——勤奋学习——不要半心半意的练习
    ——你没有迟到
    ——不要气馁(第一部分)
  • 面试阶段 ——练习你的演讲技巧
    ——专注于你所知道的
    ——准时到场
    ——向面试官寻求反馈
    ——不要气馁(第二部分)
  • 出价阶段
    -谈判技巧
    -确保你知道你会得到什么
    -不要气馁(第三部分)

祝你好运,下次再见!

想擅长 Python? 获取独家,免费获取我简单易懂的指南 。想在介质上无限阅读故事?用我下面的推荐链接注册!

https://murtaza5152-ali.medium.com/?source=entity_driven_subscription-607fa603b7ce---------------------------------------

我叫穆尔塔扎·阿里,是华盛顿大学研究人机交互的博士生。我喜欢写关于教育、编程、生活以及偶尔的随想。

参考

[1]https://www . simpli learn . com/tutorials/data-science-tutorial/data-science-interview-questions
【2】https://www . LinkedIn . com/feed/update/urn:李:活动:69127143799956228096/

如何从客户反馈中获得可行的见解

原文:https://towardsdatascience.com/how-to-get-actionable-insights-from-customer-feedback-a922ec5b37e1

神奇的公式:收集->理解->模型->跟踪

五星,任何严肃产品的目标。在 Unsplash 上由 Towfiqu barbhuiya 拍摄的照片。

开放式评论形式的用户反馈是产品成功的关键部分,但由于从数据中获得洞察力的棘手性质,它往往没有得到充分利用。在本文中,我们详细阐述了企业应该跟踪的用户反馈的类型,通过理解反馈获得的见解的典型应用,以及从原始反馈到持续可行的见解的神奇公式。

什么是用户反馈?

这里将用户反馈特指用户对产品留下的开放式评论。一个简单的用户反馈的例子是“我喜欢这个蛋糕,但是很失望我不能把它也留下来。”—鲍勃。请注意,我们排除了其他类型的用户反馈,如数字数据(如竖起大拇指和竖起大拇指),因为这些通常不太常见,而且更容易处理。

用户反馈可以有多种形式和大小,一些在技术产品中常见的关键反馈包括:

  • 产品内错误报告:许多产品给用户一种方法,如果系统崩溃或者用户导航到了意想不到的地方,用户可以留下反馈。
  • 产品内反馈:产品可以在特定位置要求更一般的反馈,或者总是在网站菜单中给用户一个选项。
  • 社交媒体:由于社交媒体的广泛渗透,在网上找到关于产品的反馈很常见。你可以追踪 Twitter 上的特定标签,监控公司的脸书或 Instagram 个人资料,或者查看高管的帖子。
  • 内部反馈:许多在公司内部工作的人会对产品的表现有一个看法,从这些人那里获得反馈也很重要。
  • 用户研究:公司可以通过用户研究主动寻求用户反馈,这通常包括招聘个人和直接提问。

可以看到有许多不同类型的反馈。这些方法在数量和用途上各不相同,列表顶部的方法通常是最可行的。

一般来说,反馈应该在团队目标的背景下考虑。例如,如果你的团队正在构建一个新的结账体验,你会想要关注结账漏斗周围的反馈,这是一个实用问题的例子。或者,你也可以看看可能会改变你对产品看法的反馈,比如关于购物体验的总体反馈,一个战略问题的例子。你应该考虑实际的和战略性的反馈。

为什么用户反馈很重要?

史蒂夫·乔布斯有一句名言“人们不知道他们想要什么,直到你展示给他们看。这就是我从不依赖市场的原因”(来源),那么我们为什么要在乎用户反馈呢?虽然用户并不总是知道他们想要什么,这可能是真的,但往往有许多许多有用的信息隐藏在噪音中。

这些见解可以:

  • 告知产品方向:如果用户一直在要求一个特定的功能,或者要求你添加更多类型的内容,那么产品很可能会从听从他们的建议中受益。史蒂夫·乔布斯有一句名言“人们不知道他们想要什么,直到你展示给他们看”,但肯定有听取用户反馈显示出巨大产品收益的情况。
  • 识别 bug:当出现问题时,用户通常很乐意抱怨。监控用户反馈是快速洞察产品潜在问题的好方法。
  • 了解产品情绪:产品团队会经常问自己,我们做得怎么样?有很多方法可以回答这个问题,包括对类似产品进行基准测试和查看保留指标,但一个同样有效的方法是通过用户反馈来了解产品情感。这可以帮助你知道什么时候你可能需要更多的投资来打造一个更好的产品,或者你是否可以投入大量的营销费用。

投资用户反馈的一些关键成果包括:

  • 自助式仪表盘:整个公司的用户都可以使用仪表盘来深入了解反馈。
  • 定期报告:对反馈数据有一个很好的理解可以导致报告的自动生成,这可以大大减少实际理解反馈并从中获得洞察力的时间。
  • 可扩展数据集:可由全公司员工使用的数据集。

产生洞察力的神奇公式

为了将原始数据转化为见解并增加商业价值,我们希望遵循以下神奇公式:

集合->-了解- >模型- >追踪

首先,我们需要收集数据。

  1. 确定您想要使用的关键数据源,其中一些已在上面描述过。
  2. 在接触任何数据之前,问自己一些用户隐私问题:我们有充分的理由查看用户数据吗?我们会侵犯任何用户隐私吗?在现代技术中,用户隐私是最重要的,所以这应该是你首先想到的。
  3. 将所有数据集中到一个地方,最好使用自动化管道。对于内部产品数据,这应该相对容易,但是对于外部数据,这意味着更复杂的数据导入,需要进行大量的数据检查。

接下来,我们应该开始了解反馈是什么样的,以及如何使用它。

  1. 对于您的产品领域,确定用户可能使用的关键字,例如,如果您正在经营一家服装电子商务商店,这些关键字可能是:“合身”、“时尚”、“昂贵”、“难看”等。尽量把总数控制在十个以内。
  2. 从总体人群中抽取至少 100 条反馈,并与上一步中确定的术语进行简单的文本匹配。
  3. 手动扫描采样反馈。它们都属于已经想到的类别吗?类别是否与内容相符?对于那些缺少一个类别的人,是否应该添加一个新的类别来捕捉这一点?
  4. 你可以重复上面的三个步骤,直到你对反馈满意为止。
  5. 绘制与您的关键字匹配的报告数量,您是否看到了一致的模式,是否有任何产品发布前后的增长?与产品发布和已知缺陷的关联可以帮助确认报告与您感兴趣的内容相关联。
  6. 检查音量是否足够大,是否有用。为了获得有意义的反馈,你应该争取每天找到几百份报告。当然,如果你只有这么多,你可以用更少的来工作,但是很难发现快速的变化。

建模是可选步骤。通过以上步骤,我们已经在获得良好见解的道路上走得很好,但是我们可以通过应用一些经典的数据科学技术获得更多见解:

  1. 创建一些文字云作为快速浏览收到的反馈的替代方法。
  2. 进行情感分析了解用户对你的产品是积极还是消极。
  3. 运行主题建模算法,对用户反馈的主题有更灵活的理解

最后,我们希望确保跟踪我们的反馈:

  1. 这应包括完成上述分析并将时间序列添加到仪表板中。
  2. 设置异常检测以便在指标出现重大变化时发出警报。这可以是您在上面的理解和建模阶段确定的关键指标的简单百分比变化,或者您可以使用更复杂的算法,如 ARIMA 或 Meta 的 Prophet
  3. 如果可能的话,最好创建自动报告来总结长期趋势,比如季度报告。您总是需要一些手工工作,但是设置查询并使其尽可能容易操作是很重要的。

这样,我们现在有了一个运行良好的洞察生成用户反馈机器!

讨论

如果我们不谈论使用用户反馈数据的一些困难,那就是失职了:

  • 用户反馈通常是有偏见的:如果人们对某件事不满意,那么他们更有可能对此大喊大叫,如果他们没有为此大惊小怪。这可能会导致你实际收到的反馈被严重夸大,既有抱怨负面体验的用户,也有喜欢你产品的强烈拥护者。没有解决这个问题的灵丹妙药,所以重要的是所有的分析都要注意这一点。
  • 用户反馈嘈杂:反馈来自人,人在接触到你的产品时,情况大相径庭。一个特性可能会被一个用户喜欢,而被另一个用户讨厌。为此,从不同的来源获取尽可能多的数据非常重要。另一个重要的方法是看得比平均值更深,而不仅仅是平均值,看评论的实际分布——是否有一些非常负面的评级的人改变了平均值?

如果这让你兴奋不已,但你目前无法访问任何客户数据,你可以在 Kaggle 上使用这个数据集,它拥有来自一家女性电子商务服装零售商的 2 万多条样本客户评论。还有一个很棒的入门笔记本,它会带你完成上面描述的许多步骤。

根据一家女性电子商务服装零售商的评论创建的 Wordcloud 样本( Nick Brooks,2019 )

感谢阅读,当然,欢迎在评论中提出任何反馈!

如何更快更高效地进行编程—机器学习—数据分析

原文:https://towardsdatascience.com/how-to-get-faster-in-programming-machine-learning-data-analysis-ce141910d52c

步伐是提高数据科学家工作效率的关键因素

菲尔·里德在 Unsplash 上的照片

作为一名数据科学家,你为什么应该加快编程速度?

数据分析技术上是一个搜索问题。你的速度越快,你可以探索的数据就越多,这样你找到有价值的东西的机会就越大。对于机器学习模型开发,我们也可以说同样的话。我们在技术上搜索几乎无限的模型空间,以找出预处理步骤、预测器、超参数等的最佳组合。这两项任务有一个巨大的共同点——编程!

那么如何提高编码速度呢?

我们可以将编码任务分解成 4 个子部分;

  1. 打字
  2. 文本编辑
  3. 研究
  4. 设计代码逻辑——就此结束吧,除了花数百个小时学习算法和数据结构之外,我没有太多的建议来提高这个项目的速度。

打字

这个不一定是代码相关的,但是如果你每天打字几个小时,那么你最好开始学习触摸打字,如果你还没有做的话。特别是,如果你的打字速度低于 50 字/分钟——这对一个每天花很多时间打字的人来说确实是一个很低的数字——我建议开始每天练习 30 分钟——事实证明一致性是关键,就像所有需要肌肉记忆的事情一样。开始的时候会有点痛,但是大概需要 10-15 天才能达到现在的速度。

几年前我用过 www.typingclub.com T2,对它的界面和功能非常满意。它不是完全免费的,尽管有很多免费网站可供你搜索。

文本编辑

在我看来,这是编写代码时的一项关键任务,因为在编写代码时,你并不是真的在做常规的打字工作——至少你不应该这样做。我们正在做的是在文件中上下移动,复制一些东西,粘贴到一些东西上面,改变一些参数等等。与写帖子或文章相比,它涉及更多的重复性任务。因此,我们可以在重复的任务中使用快捷方式。

代码完成工具

开始使用 Kite 或 Jedi 或其他代码完成工具(由于某些原因,Kite 目前不允许新的下载)。如果你一直没有这样做,你可能会想从手动挡汽车转向自动挡汽车。根据我的经验,Kite 似乎工作得很好。它还有一个“跟随光标”选项,可以自动显示您正在使用的功能的文档。

Vim & IdeaVim

IdeaVim 是 IDEs 的一个插件,我发现将 IdeaVim 集成到我的工作流程中有很大的好处。根据我的经验,我认为它使我的编码速度至少提高了 10%,尽管我认为自己是中级 vim 用户。

vim 的问题在于陡峭的学习曲线。这需要一点时间来适应,但绝对让我觉得更喜欢用键盘说话,而不是打字。因此,这无疑使开发体验变得更加有趣!

我在下面附上我的 vim 备忘单。这不是一个详尽的列表,尽管它包含了最常见的命令。对于那些对 Vim 一点都不熟悉的人,我建议将它作为一种语言来使用,首先理解操作符、动作、文本对象等概念,以及如何将它们组合起来与编辑器进行交流。

我的 Vim 备忘单

模式
Esc —开始命令模式
i —开始插入模式
v —开始视觉模式

运算符 y —复制(猛拉)
x —剪切
d —删除
D —删除不包括新行字符
c —更改(删除&开始插入模式)
p —粘贴
~ —交换小写&>—缩进
gu —转换为小写
gU —转换为大写
自定义运算符—环绕 ys —添加环绕
cs —更改环绕
ds —删除环绕
S —以可视方式添加环绕
自定义运算符—注释 自定义操作符—ReplaceWithRegister gr —Go replace
自定义操作符— Exchange cx —在第一次使用时,定义要交换的第一个{motion}。 在第二次使用时,定义第二个{运动}并执行交换。
cxx —选择当前行作为交换元素之一
X —视觉模式的 CX
cxc—清除任何等待交换的动作

运动

e —转到当前单词的末尾,包括最后一个字符。
w —转到下一个单词的开头,包括其第一个字符。
W —转到下一个单词的开头,单词仅由空格分隔,标点符号被视为单词的一部分。
b —转到当前单词的开头
^ —转到当前行的第一个非空白字符
0 —转到当前行的开头
$ —转到当前行的结尾,包括最后一个字符。
f —转到字符
F —转到后面的字符
t —转到字符 T 前一位—转到后面的字符前一位
H —转到顶行
M —转到中间行
L —转到最低行
% —转到下一个括号/大括号
zt的匹配项—滚动页面使光标停留在页面顶部
zz —如此滚动页面 在页面中间
zb —滚动页面使光标停留在页面底部
<ctrl-o> —转到光标的上一个位置
<ctrl-i> —按 ctrl + o
<ctrl-B>后转到光标的下一个位置—上一整页
<ctrl-F> —下一整页
<ctrl-U> —上半页
<ctrl-D> —下半页

文本对象

aw —一字
iw —内字
aW —一字
iW —内字
ap —一段
ip —内段
ab —一个括号
iv —内括号
at —一个标签
it —内标签
自定义文本对象— Argtextobj aa —一个函数的自变量
iaai —缩进(包括上面一行)
ii —内缩进
aI —缩进(包括上面和下面一行)

下面是来自乐仁昌演讲的一个简单的如何说维姆语的例子

Vim 语法结构

PS:请将您的 caps lock 键映射到 ESC。你不会后悔的。—建议 Microsoft PowerToys for Windows 用户将其映射到操作系统级别。

研究

这可能会耗费大量的时间,尤其是如果你对你所使用的语言的基本操作不太熟悉的话。我主要使用 Python,并且肯定会建议对以下操作非常熟悉,如果你需要对这些操作进行谷歌搜索,那么你可能会浪费一些时间,因为几乎可以肯定的是,每个数据分析、机器学习任务都需要至少执行以下一些任务。

需要掌握的 Python 基本操作/功能

  • 列表理解
  • 词典理解
  • 过滤数据帧
  • 分组依据、聚合、自定义聚合和任何类型的汇总计算
  • 日期、时间、日期时间和时区对象以及如何操作它们
  • 转换数据帧列的数据类型
  • 在不同的数据类型之间转换,例如从 2 个单独的列表转换为元组列表等。Ex: [1,2,3],[“a”,“b”,“c”]→[(1,“a”),(2,“b”),(3,“c”)]
  • 融合和旋转数据框
  • 函数式编程类型操作—映射、应用、应用映射函数
  • 编写交叉验证循环
  • 几个小提示。
    -保留分类的、数字的列名和/或概念上相似的列名的单独列表,这样你就不必每次都去选择列并试图过滤相似的列。
    -给你的列命名,不要加空格,用“.”来访问它们符号,因为它比 df["column"]符号方便得多。

记录更高级的操作 为你在堆栈溢出等情况下搜索的任务创建一个非常简单的例子。花了你 10 多分钟。将它们保存在一个地方—概念、OneNote 等。几乎可以肯定的是,你将来还会需要这些代码,用一个简单的例子把它们写下来,下次会更容易记住,如果你不记得了,去记笔记找出答案会比去网上容易得多。比如说;下面是我笔记中的一段代码示例,用于将函数作为多线程操作运行。

快速访问文档&函数签名 ide 通常有一个快捷方式来调出文档或函数签名——py charm 有<ctrl-q><ctrl-p>,jupyter notebooks 有<ctrl-shift>——我建议熟悉这些快捷方式,如果你记不住参数名称等,可以先试一试。而不是直接进行谷歌搜索。

设计代码逻辑

正如我上面提到的,除了学习算法和数据结构,阅读和理解 GitHub、Kaggle 等其他人写的代码,我真的没有太多建议。这可以帮助你找到更好的代码设计方法。

结论

在我看来,在这四个要素(打字—代码编辑—研究—代码设计)上做得更好,一定会让你成为一个更有能力、更有生产力的数据科学家。大约两年前,我开始在这些元素上投入时间,并认为这完全值得花时间和精力。如果你还有什么要补充的,我很乐意听到并尝试一下。

如何在 2022 年开始使用 Kaggle(即使你很害怕)

原文:https://towardsdatascience.com/how-to-get-started-on-kaggle-in-2022-even-if-you-are-terrified-8e073853ac46

你的大师之路

照片由 皮特菲舍尔 Pixabay

噢,这个地方太棒了。看看这些卡格勒人。要学的东西太多了。这些比赛听起来非常有趣,甚至谷歌似乎也在这里举办比赛。我发誓我会粉碎它。

让我看看这些金色的笔记本。哇,这是大师写的。听起来很奢侈。这家伙似乎知道那么多该死的的事情。我从没见过这么酷的数据科学家。让我们看看他的简介——是的,他是一名火箭科学家。

我在想什么?我不能和那个竞争。在我让自己难堪之前,我该走了。是啊,没错。我会在 Coursera 上再学习几年,然后回来给他们看。

这很好地总结了我第一次在 Kaggle 上设置键盘时的感受,我相信很多人也是如此。当你意识到你不是只是足够好与大人物一起玩的时候,你的胃会有一种可怕的下沉感——不知道你是否会像他们一样。

如果我一直仰卧着,痛苦地思考,我肯定不会获得硕士学位。我只需要迈出第一步,然后想办法解决剩下的问题。

对于初学者来说,这第一步是最重要的一步。如果做错了,你就又回到了骗子综合症,它告诉你,你根本不可能与这些专业人士竞争。

今天,我将向你展示你应该如何分阶段迈出这第一步,这将使你在 Kaggle 上很快获得成功。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

步骤 1:我必须提到的繁琐的设置

一旦你创建了你的账户并成为新手(卡格勒的最低等级),你就离成为正式的卡格勒只有几英寸之遥了。

你所要做的就是参加比赛,赢得你的贡献者徽章。几乎所有 Kaggle 用户的 40%是贡献者,甚至更大比例是新手。

当然,如果你是一个初学者,参加一些 Kaggle 的官方免费课程来让你的技能达到标准并不丢人。我建议先参加的 ML 入门课程,因为它将解释 ML 的基础知识,并在你第一次参加比赛时握住你的手。

第二步:首先成为社区的一部分。

许多人以错误的方式加入了 Kaggle。随着每个人都将 Kaggle 作为一个竞赛平台,大多数人都感到越来越大的压力,要立即加入他们,成为一名“Kaggler”

没有什么比这更偏离事实了。

感觉你必须马上参加比赛是一个巨大的陷阱,如果你还没有发展出正确的技能,你会很痛苦,因为 Kaggle 是残酷的竞争对手。即使是最小的挑战也会吸引许多熟练的专家。

那么解决办法是什么呢?

首先成为社区的一部分。感觉你是这个群体中的一员,这样你就消除了你的冒名顶替综合症,并且可以对自己说:“我是一个卡格勒。”

你是怎么做到的?

你开始看笔记本。很多。被所有人。我建议挑一个你感兴趣的比赛(建议见下面几节),按 upvotes 的多少排序笔记本列表。

作者截图

你向下滚动,打开票数最低的笔记本。通常,这些都是新手写的,需要和你一样多的支持和反馈。

一旦你开始和评论区的作者交流(他们很有可能会回复每一条评论),你就和他们建立了联系。一旦你对他们的一些笔记本发表了评论,他们很可能会再次关注你。

现在,在每个笔记本里,都有一些待办事项。

首先,至少留下一条评论。它可以是任何东西——代码编写的方式(干净,遵循最佳实践),作者如何解释他的思维过程,数据可视化的质量,或者笔记本的任何可以想象的方面。

你也可以到处提出改进的建议。如果作者知道的比你多,也说出来,告诉他们你学到了新的东西。

我的一个笔记本上的一条评论

如果你不太了解作者在说什么,叉上笔记本,开始修补每一个代码单元。阅读关于未知函数的文档和教程,直到你理解每一行是做什么的。

一旦你在 10-20 个笔记本上重复这个过程,你会发现在同样的时间内,你学到的东西比在一个课程中学到的要多得多。

最棒的是,现在你不仅仅是一个无名小卒——你认识并关注许多 Kagglers,如果你对他们的工作留下了足够好的反馈和赞赏,他们可能也会记得你。

第三步:了解 Kaggle hotness 系统的工作原理及其进展系统。

您必须查看 Kaggle docs 上的这一页,以了解如何达到每个等级:

有四个类别,每一个都需要不同程度的努力和技能来获得大师头衔。比赛和数据集的 GMs 是最难的。

你可能不需要军衔,这很好。但是,如果你想建立良好的关系,扩大你的网络,获得一个头衔是获得信誉的一个可靠途径。

最值得尊敬的头衔是竞赛或笔记本中的硕士和硕士(至少在我看来是这样)。尽管如此,任何通用汽车的头衔总是足以赢得许多人的尊重和钦佩。

Kaggle 的 hotness 系统类似于 LinkedIn(但没有二级和三级关系的复杂性)。

如果你制作内容,它通常会显示在你的追随者的 feed 上,以符合他们的偏好。如果他们与你的作品互动,这将同样显示在他们的追随者的饲料。因此,更多的追随者意味着更广泛的影响。

笔记本电脑在竞争中的排名也发生了变化,不是基于投票数,而是基于有多少人对其进行了评论。

第四步:选择比赛

现在,你准备好了。一切都是为了这个——选择和参加比赛。

即使你是初学者,我也不推荐这些入门比赛:

几乎所有初学者都是从这些开始上 Kaggle 的,所以它们已经非常饱和了。此外,有很多抄袭,因为人们只是从以前的获奖者那里抄袭顶级解决方案,以提升排行榜。

如果你发现笔记本上有成千上万的 upvotes,不要感到惊讶——这些比赛自 Kaggle 诞生以来就一直存在,人们有时间以各种可以想象的方式探索他们的数据集。

相反,像我一样,从每月的表格游戏系列(TPS)比赛开始。它们比入门 comps 稍微难一点,但是有趣多了,而且有更大的能力教你一些新东西。

由于他们的初级性质,他们吸引了很少的大师,但仍然很难获胜(我还没有做到)。

赢得比赛的终极 4 周工作流程

首先,让我们定义一下“比赛中的成功”

对我来说,如果我的分数在提交的第一名的 1%以内,我会很高兴。比如我很积极参与的 9 月 TPS,我的 ROC AUC 是 0.81708,而第一名是 0.81775。我以 0.0067 的差距获得了第 332 名。

大多数时候,即使使用简单的模型和一点点超参数调整,您也可以达到最高分。但是要到达顶端,你必须做大量繁琐的工作和实验。

这是获胜的必要条件,至少在 TPS 竞赛中是如此。

特色赛和代码赛(有奖金)不一样。它们有运行时间和资源限制。例如,有些人不接受训练时间超过 8 小时的解决方案,以保持其实用性,以防主持人希望在未来生产其中一些。

不管是哪种类型的竞争,你都可以采取一些步骤来保证成功。我将在 TPS 竞赛的情况下概述它们,但是你总是可以根据竞赛的持续时间来扩展这些想法。

因此,要想在 TPS 或任何 Kaggle 竞赛中取得好成绩,你应该这样分配时间:

第一周:探索性数据分析。它的重要性是不可否认的,它将是你以后如何提出解决方案的一个组成部分。

你应该特别注意数据中的特征,以及如何将它们归一化(不同的分布需要不同的算法来实现)。EDA 还为您提供了可能的功能工程想法,这是您成功的另一个重要部分。

在第一周,你还应该制定一个验证策略。用一个模型建立一个基线分数( XGBoost 比较流行),看看是否可以用其他方法提高。

第二周:车型选择。现在,您使用默认的超参数尝试不同的模型,看看哪一个模型的得分最高。它可以是基于树的,如 XGBoost,也可以是线性模型,如逻辑或线性回归。

我也推荐大家根据自己的直觉和从 EDA 中得到的知识去翻翻 Sklearn 中一些比较稀有的模型。你可能会发现一两个惊喜,甚至比基于树的模型给你更高的分数。

你必须根据他们的训练和测试分数通过交叉验证来判断这些模型(关键词链接到相关教程)。

第三周:特征工程。现在,我们知道了所有总经理通往高层的秘方。特征工程不是你在课程中学到的东西,关于它有很多可以说的,但简单来说:

特征工程是关于塑造和转换数据集,以便模型可以从中学习尽可能多的信息。

FE 在表格和时间序列比赛中尤为重要。

每次更改数据时(添加新列、修改现有列等)。),您应该运行您在第 2 周找到的最佳模型,看看这一变化是否会提高您的分数。

第 4 周:超参数调优:现在你已经添加了新的、有趣的特性,是时候从你的潜在模型中榨取每一点性能了。

您将需要一个良好的调优框架。我特别喜欢 Optuna ,其他很多 Kagglers 也是。

一旦优化了最佳模型,就可以生成预测并打包提交。或者你可以将多个模型组合成一个整体来进一步提高你的分数。

集合解决方案在现实世界中几乎没有用,因为它们非常昂贵,但是你会看到 Kaggle 中充满了它们。在排行榜的第 50 百分位以上,人们经常使用合奏。你可以在这里了解更多。

最后,所有这些步骤都是迭代的,可以根据您的需求进行更改。你可以随时回到其中任何一个,延长或缩短完成每一步所需的时间。

步骤 5:开始出版笔记本——成功的支柱(可选)

如果有一件事能保证让你出名,那就是出版高质量的辅导笔记本。

即使有许多高技能的科学家在竞争中击败它,你会发现没有多少人能以一种水晶般清晰的方式向他人解释他们的工作。

这就是为什么我在笔记本上轻松获得硕士学位的原因:

我截图。

我只需要创造 22 个笔记本就能获得 11 枚金牌(离特级大师还差 4 枚),这是一个比大多数人都要高的金牌/笔记本比率。在我发表之前,我已经写了相当长一段时间的数据科学教程,所以我有很多写技术内容的练习。

事实上,除了懒惰和其他承诺,没有什么能阻止我获得我的第一个 GM 头衔:

在过去的几个月里,我一直不活动。(截图很明显是我发的)。

你还会发现,最好和最受欢迎的总经理是那些赢得竞争并以专业而又易懂的方式向大众概述其解决方案的人。

写笔记本迫使你写干净的代码,并对你想向他人解释的主题进行研究:

我截图

该社区吞噬了好的笔记本——对于我的任何一个典型的黄金笔记本,我都会收到 20-40 个“谢谢”和反馈意见,而我在 Medium 上的文章几乎没有几个,尽管通常有数千人阅读它们。

结论

卡格尔大师头衔绝对是一种威望。它们在你的 LinkedIn 标题上看起来很耀眼,会让你的简历增色不少。

但是 Kaggle 最好的地方总是它的社区。它不仅是最突出的在线数据平台,而且其他行业的程序员也尚未形成如此惊人的社区,拥有如此多的熟练专家。不管你的排名如何,成为其中的一部分会比课程和书本更能拓展你的知识和人脉。

https://ibexorigin.medium.com/membership https://ibexorigin.medium.com/subscribe

在 LinkedIn(领英)或 Twitter(T2)上与我进行友好的交谈。或者你可以读我的另一个故事。这些怎么样:

</22-2-built-in-python-libraries-you-didnt-know-existed-p-guarantee-8-275685dbdb99> </8-booming-data-science-libraries-you-must-watch-out-in-2022-cec2dbb42437> </6-pandas-mistakes-that-silently-tell-you-are-a-rookie-b566a252e60d> </7-cool-python-packages-kagglers-are-using-without-telling-you-e83298781cf4> </25-pandas-functions-you-didnt-know-existed-p-guarantee-0-8-1a05dcaad5d0>

如何充分利用 GrowthBook

原文:https://towardsdatascience.com/how-to-get-the-most-out-of-growthbook-82feb792ad4c

图片来源

简化 A/B 测试的开源方法

GrowthBook 是一款用于 AB 测试的开源工具,提供了特性标记功能和分析工具。分析工具是本文的重点,它位于数据仓库的顶层,通过 SQL 查询与您正在收集的任何现有用户数据进行交互。这种灵活性是 GrowthBook 对我们的主要吸引力之一,因为这意味着我们能够直接分析我们的实验对我们的业务 KPI 的影响。

作为开源软件,你可以非常灵活地配置 GrowthBook,不管它是有效的还是无效的!)给你。在本文中,我将介绍我们如何配置我们的 GrowthBook 实例,以形成我们在 Typeform 的自助式实验平台的基础,并包括我关于确保健壮性、可用性和效率的顶级技巧。

数据源

数据源本质上是您的数据仓库的 SQL 视图,它将您的实验特征标记拉入 GrowthBook

设置 GrowthBook 时最重要的事情是决定数据源的结构。需要注意的是,指标与特定的数据源相关联,您不能在不同数据源上定义的实验之间共享这些指标。

我们使用 GrowthBook 来分析通过 Iterable 发起的在线和电子邮件活动,我们希望在两者中使用相同的 KPI。其中一个最新版本(1.3.0)允许每个数据源有多个查询,这允许我们在一个数据源下公开多种类型的实验,从而在它们之间共享指标。

我们已经按照标识符 id 对数据源进行了分区:

  • user_idaccount_id为已登录用户
  • form_uid为新表格功能
  • 公共网站访问者的匿名 cookie id。

我们的主要 KPI 类似地在标识符之间划分,因此这对我们很有用。

韵律学

指标被定义为 SQL 查询,可以从数据仓库的任何地方获取数据

GrowthBook 的一个巨大优势是通过 UI 将指标定义为 SQL 查询,您可以查询数据仓库中的任何表。

作者图片

您可以直接通过 GrowthBook 中的 SQL 定义指标,或者直接从您的数据仓库中提取任何预定义的指标。这是一种类似于 Eppo 的方法,但在优化方面比有明显的优势,因为它将指标定义交给了数据团队。

在 Typeform,我们是 dbt 的忠实粉丝,有许多 dbt 模型来定义不同的指标和 KPI,我们的数据仓库环境会随着时间的推移而发展。GrowthBook 使保持用于实验的指标与其他业务保持同步变得非常容易。

公制标签

每个指标都可以进行标记,这些标记可用于过滤和搜索指标目录,以找到您正在寻找的指标。我特别喜欢这个功能,因为我是要求为不同的应用程序提供不同颜色标签的用户之一(在 1.2.0 版中引入)!

作者图片

我们使用各种不同的标签,但我们有所有指标都必须有的强制标签,这些标签划分了我们的指标目录,以提高可搜索性。

标识符 ID: 用于定位和特征标记的标识符类型。指标只在其中一个上定义,每个指标都链接到特定的数据源。

作者图片

产品: Typeform 也有一个名为 Videoask 的产品,它有自己的一套指标和数据源。

作者图片

版本控制: GrowthBook 不支持正确的版本控制,但我们引入了版本控制标签,让我们的用户知道对指标执行了哪些检查。这使我们能够确保我们的所有指标都与我们的数据仓库保持一致,并帮助我们在 GrowthBook 引入新功能时采用它们。

作者图片

护栏

我们正致力于标准化护栏指标,并将其应用于所有实验。这将确保我们不会无意中对我们的 KPI 产生负面影响。GrowthBook 允许您通过标签将指标添加到实验中,因此有一个护栏标签意味着我们可以轻松确保我们正在监控那些最重要的指标。

作者图片

自定义标识符类型

标识符类型是用于在控件和变量之间划分受众的实体,可以是用户 id、匿名 cookie id 或位置。

版本 1.3.0 引入了自定义标识符类型,允许您选择如何称呼在功能标记中使用的标识符。在以前的版本中,你有两个选择:user_idanonymous_user_id。我们不得不在其中一个上别名我们的其他 id,这引起了很多混乱。

我们目前正在从数字account_id迁移到字母数字account_uid(显然我们用完了数字_(ツ)_/),所以能够明确地标记哪个正在被使用是非常有用的。伟大的新功能!

动态日期范围

2021 年 11 月,GrowthBook 引入了日期的 SQL 占位符。这些允许您将日期过滤器应用到一个由特定实验日期填充的指标。对于我们来说,当从通常包含数亿行的分区表中查询数据时,这一点尤其重要。下面是分区键day上的过滤器示例:

WHERE day BETWEEN DATE('{{ startDate }}') AND DATE('{{ endDate }}')

这里需要注意的是startDateendDate都是时间戳而不是日期,因此我们必须使用DATE()函数来匹配分区。此外,在评估指标时,endDate被替换为实验结束的时间戳加上转换窗口。如果您在数据源查询中添加了一个endDate,那么实验的实际结束日期将被用来过滤分配给您的实验。

状态更新

我们面临的一个挑战是预测和防止指标被打破,以减少利益相关者之间的摩擦。指标出现问题有两个主要原因:

  • 我们数据仓库的变化。我们有一个非常活跃的 dbt 环境来计算我们的 KPI,这些 KPI 通常会随着业务需求的变化而迁移。
  • SQL 中的拼写错误。当将 sql 从 DataGrip 复制到 GrowthBook 或意外编辑现有指标的 sql 时,很容易出现输入错误。

GrowthBook 开源的一个非常好的特性是,你可以下载一个 config.yml 文件,其中包含来自 GrowthBook 实例的所有 sql 查询。我们有一个 Databricks 笔记本,每天早上运行,对每个指标的 sql 查询运行各种测试。

我们可以检查:

  • 表名在数据仓库中可用
  • 表格已用最新数据更新
  • 度量定义中的 SQL 错误

如果出现问题,将向我们的#growthbook slack 渠道发送 slack 通知,供任何分析师挑选和解决。

作者图片

在 Typeform 中,我们实际上是自托管的,所以所有这些都可以在 MongoDB 中使用,当您通过 UI 添加指标时,MongoDB 会自动更新。如果您不是自托管的,那么您必须手动下载 config.yml。

结论

GrowthBook 允许我们在 Typeform 创建一个用户友好、健壮和可靠的实验平台。在这篇文章中,我已经浏览了我的(当前的)顶级技巧,以充分利用 GrowthBook 必须提供的功能。

作者与 GrowthBook 没有任何关系,只是该产品的狂热粉丝!

如何提高您的数据科学领导技能

原文:https://towardsdatascience.com/how-to-grow-your-data-science-leadership-skills-dccbfe7378f7

作为一名行业数据科学家,领导者需要具备哪些条件?对于某些从业者来说,领导力意味着管理人和产品;对于其他人来说,重点可能是开发帮助公司成功的工作流程和实践。甚至可以两者兼而有之!不管你的角色的具体定义是什么,你的工作可能需要与多个学科的同行和利益相关者一起适应快速变化的需求。这不是一个容易掌握的技能,但幸运的是,这是我们可以培养的。

本周,我们选择了几篇关于领导力的文章,这些文章结合了高层次的原则和务实的见解。无论你是哪种类型的数据科学领导者,他们都将激励你反思、重新考虑你的方法,并尝试新的工具和想法。让我们开始吧。

  • 承认领导是辛苦的 这很关键。流行文化会让我们相信,领导者是确定性和果断的同义词。克里斯·沃什的帖子是对这种看法急需的解毒剂。它邀请我们克服决策职位带来的不适,并解决数据科学经理面临的具体挑战。
  • 很少有事情比打下一个坚实的基础 更重要。对于 Salma Bakouk 来说,从零开始建立一个数据团队是一个试错的过程,外部指导很少。她分享了自己一路走来学到的经验教训,尤其是在与公司目标和数据成熟度阶段保持高度一致方面,并为正在处理类似任务的人提供了路线图。
  • 补充技能的重要性 。从不同的方向解决类似的问题, Marie Lefevre 为负责开发公司数据堆栈的从业者提供了具体的建议。对于 Marie 来说,运行良好的数据操作可以平衡数据工程师、数据分析师和数据经理的技能组合。

克里斯汀在 Unsplash 上的照片

  • 帮助数据领导者脱颖而出的特质 。作为谷歌的首席决策科学家, Cassie Kozyrkov 有机会深入思考是什么让一些数据分析师变得伟大,而另一些人却在努力超越他们的工作。在她的最新文章中,她将自己的想法提炼为 10 个不同的元素,你可以努力在职业生涯中成长和前进。
  • 让自己(和你的团队)为变革做好准备 。在一个快速发展的领域,成为一名有效的领导者意味着你可以知道形势何时变化,并且知道你的团队应该如何适应。 Barr Moses 认为我们正在脱离大数据的主导地位,并为希望确保其堆栈和工作流为未来做好准备的数据专家提供了可行的想法。
  • 成长就是认真对待反馈 。杰森·庄最近庆祝了他作为一名研究生数据科学家的一周年纪念日,并写下了经历他的首次绩效评估的经历。不过,他的观点适用于组织结构图上上下下的人:他强调倾听反馈的关键技能,包括(如果不是特别的话)让我们意识到自己缺点的细节。

如果我们收集的关于领导力的文章让你陷入沉思,那太好了:花点时间去消化。如果你还有心情阅读其他主题的优秀读物,那么,你可以看看:

致我们所有的读者:我们感谢你的支持,你对数据科学和优秀写作的热情,以及你决定成为我们社区的一员。特别感谢那些已经跨越并成为中级会员的人,这有助于我们和我们的作者与你们分享更多的伟大。

直到下一个变量,

TDS 编辑

如何在 Wordle 中猜对

原文:https://towardsdatascience.com/how-to-guess-well-in-wordle-d21167aae444

从另外 1300 万个世界扑克游戏中吸取的教训

图片作者。

这是我上一篇文章的后续文章,前一篇文章是关于如何用最好的词来开始你的文章。现在我们有了一些好的开始词,值得看看如何进行下一次猜测。有没有猜下一个单词的好策略或者什么都行?你应该如何看待 Wordle 提供的不同形式的反馈?是关注目标词中已知的字母更重要,还是关注被排除的字母更重要?还是两者都有?字母的位置呢?如果我想不出一个词来满足 Wordle 的所有提示,这有什么关系吗?忽略一些提示安全吗?

结果将再次基于对大量模拟游戏(超过 1300 万游戏和近 7000 万猜测)的分析,这一次我将调整模拟器,以更像人类的方式进行游戏。

TLDR;

下文有很多细节,但主要结果可以总结如下:

  • Wordle 为其玩家提供了 4 种不同类型的反馈,以帮助限制猜测(正确/不正确的字母和正确/不正确的位置),虽然没有必要为了成功而注意所有这些限制,但一般来说,如果玩家想要在大多数时间内成功,他们需要满足大多数猜测中的 4 个中的 3 个。
  • 在用于选择新猜测的约束条件的数量和找到目标单词的可能性之间有很强的正相关性;使用更多的限制大大提高了你的胜算,并以一种可预测的方式减少了你需要的回合数。
  • 并非所有约束都是同等创建的,尤其是在与其他约束结合使用时。我们提出证据来支持错误字母约束作为一种特别重要的约束类型,而错误位置约束作为一种不太重要的约束类型。前者提供了不能从任何其他约束中获得的关于目标单词的信息,而后者提供的信息通常可以从其他约束中获得。
  • 实际上,这意味着当选择下一个猜测时,您应该始终努力确保它不包括已知在目标单词中不存在的字母——它应该满足不正确字母约束——并且您应该优先满足正确字母和/或正确位置约束而不是不正确 位置约束。

简要概述

除非你没有注意,否则你会听说过 Wordle,并且可能也尝试过。简而言之,Wordle 是一个简单的单词查找谜题,玩家每天有 6 次机会猜测一个新的 5 个字母的目标单词(每个人都得到同一个单词),这些天数百万人在 Twitter 上分享他们的进展,这帮助 Wordle 成为病毒。

一个 Wordle 游戏和反馈的例子。图片作者。

每次猜测后,玩家会收到多达 3 条颜色编码的反馈,如下所示:

  1. 您的猜测中的字母在目标单词中,但位置不正确(黄色);
  2. 您的猜测中的字母在目标单词中,并且在正确的目标单词位置(绿色);
  3. 您猜测的目标单词中缺少的字母(灰色)。

总的来说,这 3 条反馈实际上提供了 4 条不同的信息:(1) 正确的字母;不正确的字母;(3)(字母正确);以及(4) 正确字母的错误位置。稍后,当我们考虑如何使用这个反馈来约束和引导我们的猜测时,这将是很重要的。

模拟世界:疯狂模式**

很明显,我自己并没有玩几百万个 Wordle 游戏,但是我的笔记本电脑有。在我的前一篇文章中,我描述了我是如何建立一个 Wordle 模拟器,并用它来模拟超过一百万个 Wordle 游戏,以找到最好的单词作为开场猜测;大多数人都有一个他们喜欢用来开始游戏的常用词,但有些词比其他词更好。

值得注意的是,我的模拟器没有使用确切的 Wordle 词表——是的,我知道这已经变得可用,因为一些人已经设法从 Wordle 源代码中提取了它——因为我没有使用它的许可。相反,我使用的是开源的等价物。我不认为这会对结果产生实质性的影响,至少在我使用的模拟尺度下不会。

在我之前的帖子中,我也提到我的模拟器玩起来像一个强大的玩家。我认为这至少有两个重要原因:

  • 首先,在识别与 Wordle 的各种字母约束相匹配的单词时,模拟器具有完美的回忆能力;虽然对计算机来说很简单,但超出了我们大多数人的能力。
  • 第二,当猜测一个新单词时,模拟器应用所有可用的约束/提示,以便最大限度地排除不能作为目标的单词。**

大多数人不能这么努力地玩,或者不仔细地玩,我们经常做出不满足所有可用约束的猜测。例如,当很难想到满足所有可用约束的单词时,满足某些约束的单词可能会出现在脑海中。在上面的游戏中,第三个猜测' DROLL '是这样的一个例子:' R '已知被排除在目标之外,我们还知道目标中也有一个' N '。然而,这是一个有用的猜测,因为它揭示了目标的新信息。

Wordle 有一个'硬模式'——你可以在玩之前在游戏的设置中选择它——,它坚持认为“任何透露的提示都必须在随后的猜测中使用”,虽然从我所见这仅适用于正确的字母正确的位置,因为在硬模式中允许' DROLL ,即使' R 不正确。但是,在硬模式下不允许使用'破坏,因为第 4 个字母必须是' L '。“模式”这个名称可能有点误导。它并没有改变游戏本身,而是迫使玩家更加仔细地思考一个猜测,坚持每个新的猜测至少满足一些已经知道的提示(正确的字母和位置,如果有的话)。然而,它似乎并没有强迫你尊重其他的约束——不正确的位置或不正确的字母——所以也许应该有一个'疯狂的'模式,在这个模式中,这些信息也必须得到满足。对此,我的模拟器玩的是'神经病模式!

模拟世界:人类模式

为了产生一个更像人类的游戏模拟,我们需要抛弃这种疯狂的模式,采用一种更放松的方法来应用约束。如前所述,根据其 3 种类型的反馈,将 Wordle 视为提供 4 种不同类型的约束是有用的:

  1. 正确字母 —你知道在目标单词中的字母集合;这些正是你一路上收集到的黄色字母。
  2. 错误字母 —你知道目标单词中没有的字母集合;你收集的灰色信件。
  3. 正确位置 —目标单词中位置已知的正确字母的子集;绿色字母。
  4. 错误位置 —位置未知的正确字母及其错误位置的子集;表示没有对应绿色字母的黄色字母

默认情况下,我的模拟器将所有这些约束条件应用到每个新猜测的搜索中。为了模拟更像人类的游戏,我们应该允许这些约束在游戏中有选择地打开或关闭。例如,如果正确字母约束是上的,那么模拟器将选择下一个包括目标单词中所有已知字母的猜测。但是,如果正确字母约束为,那么在选择下一个猜测时,该约束将被忽略;猜测可能包含一些正确的字母—这可能是偶然发生的,或者是因为使用的其他约束可能支持猜测—或者它可能产生一个没有正确字母的单词,只要它与其他约束兼容。**

这 4 个约束有 16 种(2x2x2x2)可能的开/关配置。如果所有的约束都被关闭,那么模拟器将有效地以非导向的方式猜测,因此我们将忽略这个配置,因为它不符合合理的游戏玩法。这给我们留下了 15 种可能的配置。

为了评估这 15 种配置中的每一种,我们使用所有 2500 个可能的目标词和 392 个一词和两词起始/种子集来运行我们的模拟器;在我之前的帖子中,这些种子被认为是高质量的起始词。总共模拟了 1360 万场游戏和>6900 万轮游戏,基于每场游戏 15 分钟,相当于大约 388 人一年的游戏时间。我们将尝试阐明的关键问题包括:

  1. 随着回合的展开,这些限制如何影响游戏的进行?对于不同数量的约束,在每一轮中识别出多少个正确的字母或正确的位置?将可用的单词缩减为最终的猜测有多好?
  2. 使用的约束条件的数量如何影响游戏成功的可能性(成功率)和每局游戏的平均回合数(游戏长度)?**
  3. 哪些约束组合更有可能导致游戏成功?一些约束类型比其他的更有价值还是更没有价值?一些约束类型应该比其他的更有优先权吗?

约束的数量如何影响游戏?

在我们考虑具体的约束组合之前,让我们先来看看所使用的约束数量和游戏性之间的关系。使用 1、2、3 或 4(全部)约束如何影响典型游戏的每一轮?如果我们使用更多的约束,我们会从更多的反馈中获益吗?如果使用更多的约束,是否更有效地减少了目标候选词的数量?

图一。按回合分析博弈;作者图表。

在图 1(a-d)的图表中,我们看到不同类型的反馈(正确/不正确的字母和正确/不正确的位置)是如何随着使用不同数量的约束的游戏展开而累积的。不足为奇的是,在每一轮游戏之后,学习到了更多的信息,但是学习的速度不同,这取决于所使用的约束条件的数量。例如,在图 1(c)中,我们看到,当使用 2 个约束时,我们在 6 次猜测之后学习了 2-3 个正确的字母位置,但是当使用 3 个约束时,我们在仅仅 3 次猜测之后学习了超过 3 个正确的目标单词字母位置;也就是说,与使用 2 个约束相比,当使用 3 个约束时,我们在一半的猜测次数中获得甚至更多的正确位置信息。

请注意,当使用更多约束时,可能的目标单词候选项的数量减少得更快;图 1(f)。例如,当仅使用单个约束时,则平均而言,潜在目标单词匹配的集合减少到大约 600 个可能的单词,使得成功的可能性非常小。对于 2 个或更多的约束,情况会有很大的改善,3 个或 4 个约束可以将潜在目标词的集合减少到最多几个词,4 个、5 个或 6 个。

越多越好

如果使用更多的约束意味着获得更多的提示和更有效地减少可能的目标词集,那么这可能会转化为更高的成功率和更短的游戏?图 2 显示情况确实如此。虽然只依赖单一约束不是一个可行的策略——它导致不到 10%的成功机会——但使用两个约束可以显著提高成功的机会,达到 40%以上。如果我们想在大多数游戏中获胜,那么我们需要平均每次猜测使用两个以上的约束条件;3 个约束意味着成功率> 80%,使用所有可用的约束(我们的疯狂模式)导致 96%的成功>

图二。成功率和游戏时长受平均次数的约束;作者的图表。

并非所有约束都是同等创建的

因此,使用更多的约束会有所帮助,但是使用哪些约束有关系吗?2 或 3 个约束的每一组都和其他组一样好吗?

在下文中,我们将使用 1 和 0 的 4 位数字符串来表示约束的特定配置;1 表示使用/打开约束,0 表示不使用/关闭约束,1 或 0 的位置表示特定的约束,基于上面使用的顺序(正确的字母, 不正确的字母,正确的位置,不正确的位置))。例如,1111 表示使用了所有约束(疯狂模式),而 1010 表示使用了正确字母正确位置约束(硬模式的最小形式)。

图 3。成功率,游戏长度和每个约束配置的总排名分数。单个约束配置根据其约束数量进行排序和颜色编码(蓝色= 1 个约束;灰色= 2 个约束;橙色/鲑鱼= 3 个约束条件;红色= 4 个约束)。在(a)和(b)中,对于给定数量的约束,平均成功率和游戏长度显示为水平虚线。在(c)中,对于给定数量的约束,最好和最差的配置分别用' * '和'-'标记;作者的图表。

图 3(a&b)显示了 15 个约束配置中每一个的平均成功率和游戏长度,根据使用的约束数量进行排序(和颜色编码)。例如,我们可以看到前 4 个(单约束)配置(蓝色)的成功率非常低(通常不到 20%)—事实上,仅使用错误位置约束(0001)永远不会成功—对于少数成功的游戏,它们通常平均需要至少 5 或 6 次猜测。当我们使用 2 个约束时,成功率会提高,但显然不是所有的 2 约束配置都同样有效。例如,0110 ( 字母不正确位置正确)配置的成功率接近 90%,相比之下,1100 ( 字母正确字母不正确)的成功率略高于 60%,0101 ( 字母不正确位置不正确)的成功率不到 20%。

我们能从这些结果模式中学到什么?我们能识别哪些约束比其他约束更好或更差吗?为了做到这一点,我们首先通过计算成功率和游戏时间的平均(标准化)等级来产生每个配置的总分数,以产生图 3(c)所示的等级分数;将成功率游戏时长转换成一个值是可取的,因为可以合理地想象玩家会希望优化游戏的这两个方面,我们使用排名是因为这些原始衡量标准依赖于不同的尺度。不足为奇的是,平均等级分数随着所使用的约束的数量而增加,并且总的来说,1111 配置(疯狂模式)具有最高的等级分数,这意味着它具有成功率和游戏长度的最佳组合。但是是不是有些个体的约束比其他的更好呢?

第一个线索是注意具有最高等级的配置如何得分(0100、0110 和 1110;在图 3(c)中用' * '标记),对于给定数量的约束,所有的使用不正确的字母约束(第二位数字是 1)。此外,最低等级的配置(0001、0011 和 1011;均标有'-')。这是唯一的约束条件。其他约束有时出现在最高等级的配置中,但是它们并不出现在所有的配置中,并且它们也出现在一些最低等级的配置中。这表明不正确的位置约束可能在文字游戏中起着重要作用。

还要注意的是,对于给定的约束编号,不正确位置约束是从不出现在顶级配置(“*”),但是它总是出现在最低级别配置(“-”)。同样,这是唯一一个为真的约束,表明这个约束可能没有发挥特别重要的作用,尤其是当其他约束可用时。

最有用的约束?

我们可以通过将使用给定约束的配置的平均等级分数与不使用该约束的配置的平均等级分数进行比较来对此进行量化。在图 4 中,我们针对每个数量的约束(1-3)分别给出了结果。例如,在图 4(b)中,我们可以看到,当在双约束配置中使用不正确字母约束( on )时,平均等级分数为 0.6,而当不使用时( off )平均等级分数仅为 0.42。换句话说,使用不正确字母约束的双约束配置比不使用它的双约束配置执行得更好。相比之下,我们还可以看到,与不使用错误位置约束的其他 2 约束配置相比,使用错误位置约束会导致较差的性能;这并不是说不正确位置约束本身是一个不好的约束,而是说,如果你只能想到符合两个约束的猜测,那么不正确位置不应该是其中之一。这两种效应对于 3 约束配置也很明显。事实上,在图 4(c)中,我们可以看到不正确的字母约束是唯一的约束,与不使用时相比,它的使用提高了等级分数。

图 5。每个约束打开和关闭时的平均等级分数;作者图表。

为了量化上述内容,我们可以将等级分数(有约束和无约束)中的每一个差异转换为相对优势分数,如图 5 所示;为了计算约束 c 的相对优势,我们将使用 c 时的等级分数除以不使用 c 时的等级分数。在图 5(b)中,我们看到不正确字母约束享有大约 0.4 的相对优势分数,这表明与不使用它的配置相比,使用它的配置在等级分数上经历了 40% 的提高。在所有配置中,字母不正确约束的平均相对优势得分最高,而位置不正确约束的平均相对优势得分最低。事实上,不正确位置约束具有净负相对优势分数——它的使用导致更差的等级分数——这表明其他约束应该优先于它。

图 5。每种约束类型的相对优势分数;作者图表。

以上有一个重要的微妙之处需要强调。并不是说不正确的字母约束保证比任何其他约束更有帮助——不正确的字母约束在这个意义上不是最好的约束——相反,我们是说将其他约束一起使用是一个重要的约束。当用户不能想出满足所有可用约束的猜测,但可以想到满足某些约束的单词时,这可能会表现出来。例如,也许他们有一个满足正确字母约束和正确位置约束的单词和一个满足正确字母错误字母约束的不同单词。在这种情况下,这里的结果表明,在其他条件相同的情况下,第二个词将是更好的选择。

为什么会这样呢?一种解释是正确字母正确位置约束不是互斥的,因为它们都涉及已知存在于目标单词中的字母。错误字母约束是不同的,因为它是关于在目标单词中是而不是的字母。因此,与正确字母正确位置约束相比,正确字母错误字母约束的组合在目标单词上提供了更加多样的 视角

类似的逻辑可以解释为什么不正确的位置约束被证明价值较低:相对于其他约束,它没有给表带来多少新信息。在早期,当知道的正确字母很少,并且知道一两个不正确的位置对于限制对好的猜测的搜索不是很有用时,它也可能是有限的使用。

结论

我们该如何看待这一切?这是大量的数据分析,但它能告诉我们任何新的、有用的或可行的东西吗?这对我的下一个 Wordle 游戏意味着什么?

  1. 我们已经量化了在玩 Worldle 时使用尽可能多的约束的好处,但也许这是不言而喻的。
  2. 一点不太明显的是,如果我们想在大多数游戏中成功,我们可能需要在大多数猜测中满足至少 3 个约束条件。但是哪三个限制呢?
  3. 呈现的结果建议应该包括不正确字母约束,因为它提供了对目标单词的独特视角。
  4. 结果还表明,如有必要,可以排除不正确位置约束,因为相对于其他约束,它仅提供有限的附加信息。

因此,在玩你的下一个 Wordle 游戏时,如果你想不出一个能满足你目前为止对目标单词的所有了解的猜测,那么试试下面的方法:

  • 如果你知道任何正确的位置,那么使用它们并优先考虑不正确的字母约束来帮助找到你的下一个单词,如果你能试着使用正确的字母约束。
  • 如果没有任何正确位置,则优先考虑错误字母正确字母约束。
  • 如果你甚至没有任何正确的字母,那就看看我之前的帖子吧,因为你需要更好的起始词来保证你至少在前一两次猜测中得到正确的字母。

现在做一些说明。以上是基于模拟,而不是真实的游戏,但至少有很多模拟,游戏可能是相当现实的,尤其是我们没有放松限制。它还使用了一个关于玩家如何使用约束的非常简单的模型:他们要么打开,要么关闭。这并不理想,因为玩家可能会根据情况改变他们的约束使用:当选择一个猜测时,他们会尽可能多地使用约束。在以后的帖子中,我可能会看看这是如何改变事情的,但现在,以上至少应该为完善你自己的 Wordle 策略提供一些帮助。

如何处理真实数据集

原文:https://towardsdatascience.com/how-to-handle-a-real-dataset-2dc2de5b1dec

使用您的数据更进一步的指南

弗兰基·查马基在 Unsplash 上拍摄的照片

最近,有很多关于数据质量及其对模型性能的影响的讨论。主要是因为这个演示强调了这个主题——以模型为中心与以数据为中心,这个主题在这个以前的文章中已经讨论过了。

然而,简单地说,您在项目初始阶段的努力,更具体地说,当您需要深入研究可用数据并决定使用什么和如何使用时,会直接转化为以后的模型性能,比实际的模型调优更是如此。这一阶段被称为数据预处理,是评估数据质量的地方。

然而数据质量到底是什么?

数据科学的数据质量

普遍的共识将其定义为你的数据有多准确、可靠和最新。然而,我敢说,这些数据中有多少与你的问题相关,有多少实际上被转化了。

此时,您可能想知道:我们如何保证我们的数据有质量?

和数据科学中的其他事情一样:这要看情况!

尽管如此,了解数据科学生命周期是如何展开的,并理解如何构建您的数据以满足其阶段需求以及项目成熟度的细微差别是一个很好的开始。

尽管如此,由于这不仅高度依赖于您的用例,而且意味着要有很好的业务理解,所以达到数据质量的最快、最常见的方法是清除垃圾。这通常意味着删除重复项、填充缺失值、处理异常值、删除不正确的属性值等等。

然而,这是数据争论的面包和黄油。我们需要做的是开始将它带到另一个层次,让我们以需要的方式处理真实数据,为此,我们将讨论几个主题,帮助您达到这个新的层次。

克劳迪奥·施瓦茨在 Unsplash 上拍摄的照片

知识

首先也是最重要的,理解问题。说真的,误解一个问题/任务会像滚雪球一样越滚越大。

如果可能的话,研究你正在处理的业务的来龙去脉,或者至少找一个了解它的人来彻底验证它。如果两者都没有,那么,做好准备吧,你正在经历一场疯狂的旅行,任何事情都有可能发生。

最起码把你想解决的问题框好。这不仅能帮你解决问题,还能让你更好地解释你拥有的数据相对于需求的优势和劣势。

通过这样做,您将能够当场预先验证您的决策,或者了解数据中甚至数据接收中是否存在需要尽早修复的错误。

一个很好的例子是,没有适当的商业知识评估的数据如何变得毫无价值甚至更糟:可能造成伤害,在这篇关于为什么为对抗新冠肺炎而开发的人工智能工具失败的文章中进行了解释。

来源

一旦正确设置并理解了框架,就该了解数据是如何到达您手中的了。这时候你可能会感谢有一个数据工程师在你身边。

验证数据接收需要很长时间。

有一次,在一个项目中,我发现我们的二元目标特征可能有第三种含义。仅仅是因为我们偶然发现了两个具有相同时间戳(相同毫秒)但目标值不同的事件。

经过彻底的调查和与一些开发人员的交谈,我们发现他们在数据库中使用了相同的状态,也就是几年前我们用来定义目标值的状态,来发起一个特性请求。

这意味着重新设计一条管道,当时已经进行了两个月的工作,最终我们设法在一周内解决了这个难题,但是如果我们一开始就坐下来问一些有意义的问题,所有这些令人头疼的问题和时间损失都是可以避免的,例如:

我们如何收集这些特征?

我们能保证它们没有其他含义吗?如果是这样,我们如何过滤它们?

我们什么时候收集?它与我们需要跟踪/登记的事件一致吗?

前两个主题直接影响您的 ETL 和探索阶段,因为它们将定义您的现实中有多少被正确地转化为您的数据,这会影响您的发现,以及您的 ETL 需要如何形成。

偏置

偏见不是来自 AI 算法,而是来自人。

卡西科兹尔科夫

您选择的任何算法都会传播您数据中的任何偏差,因此在建模阶段的数据预处理过程中处理这些偏差是至关重要的。

首先问问你自己你的模型会产生什么错误,它的影响是什么,你能做什么来避免它们/处理它们。

没有没有错误的模型,总是会有假阳性,或者简单的坏预测。然而,在早期批评并努力解决偏见大有裨益。

想想世界上一些最大的人工智能玩家在人脸识别算法方面众所周知的问题。如果从一开始,开发人员/决策者就问自己,他们的数据集是否恰当地代表了所有的种族,这种情况就不会发生,许多严重影响生活的问题也会避免。

简单地根据所有种族采样数据,或者收集更多的数据,直到所有种族都得到平等的代表,就可以解决问题(事情就是这样结束的)。

如果你想争取公平,努力消除你对自己决定的后果的无知。

T5【卡西科兹尔科夫】T6

我对这个特定话题的建议是,首先了解存在哪些类型的偏见,以及它们是如何起作用的。然而,这是一个自我发现的旅程,所以不要期望这个话题有一个防弹的解决方案。然而,事实上你已经开始关注它了,这让你走上了正确的道路。

采样

这是我为你准备的几个兔子洞。

显然,采样意味着平衡类,或者甚至像上面的例子一样平衡特征表示。

然而,这个话题有些曲折:

您是否考虑过,您是根据固定的时间窗口对真实事件进行采样(收集),而捕捉您想要在模型中引入的差异的现实是基于其他单位的,例如货币。

换句话说,你应该重新考虑如何采样频率,以及它们是否适合你的用例。诸如固定层位法三重屏障法等技术可用于解决这一问题。

不仅如此,你有没有想过你的样本可以有其他样本的信息?

这可以被称为“溢出”样本问题,这种情况经常发生在金融市场这样的场景中,其中样本基本上是交叉相关的。

尽管如此,即使在这种混乱的情况下,你也可以通过独特性来衡量观察结果,以帮助你。

马科斯·洛佩斯·德·普拉多的演讲涵盖并解释了这些及其他注意事项。

不管您的问题是什么,花时间评估更适合您的用例的采样策略,而不是相反。

虽然您可能认为这是不相关的,但在模型开发之前和之后进行适当的采样对监控其在生产中的表现大有帮助。否则,你怎么能确定一个不可预测的世界事件(如新冠肺炎疫情)是你的模型漂移的原因呢?

结论

最后,实现卓越的数据质量是一门艺术,这里所涵盖的只是冰山一角,还有其他主题,如多变量时间序列、将需要它自己的整篇文章,只是为了了解如何处理它们。

然而,如果你不仅开始质疑自己的数据(数据来自哪里,如何处理,以及如何收集),而且开始质疑自己(是否有我引入的无意识偏见),你将会在无意中开始提高数据的质量。除此之外,对于数据科学的不同阶段,你总是可以指望有用的开放存储库来保证数据质量,比如 ydata-quality显然是

法比亚娜 是 CDOy data

用改进的数据加速 AI。

YData 为数据科学团队提供第一个数据开发平台。

如何处理多个时间序列的自回归模型

原文:https://towardsdatascience.com/how-to-handle-autoregressive-model-over-multiple-time-series-4604fdd96e2b

使用工厂模式设计代码,避免数据泄露

管道有时会变得复杂。波兰 2022。(作者供图)。

介绍

当涉及到数据准备时,自回归模型是“更难”实现的模型之一。由于模型预计会产生每日或每小时的预测,数据集本身预计会随着每个新的观察结果而增长和扩展,这需要模型进行定期的再训练。因此,处理数据成为一个高度动态的过程,必须格外小心,以确保在任何给定的时间点都不会出现数据泄漏

令人惊讶的是,但不幸的是,大多数关于自回归的教程更多地强调模型和算法,而不是太关注数据准备方面的事情。由于他们的目标是解释自回归概念(他们做得很好,例如:机器学习大师或[第 1 篇](/time series-from-scratch-autoregression-theory-and-implementation-f8c614f738f2),第 2 篇来自《走向数据科学》),数据准备的处理仅限于单变量或多变量时间序列。Tensorflow.org提供了更广泛的解释,尽管他们的方法不容易扩展到 多个多变量 时间序列的情况。

在本文中,我将向您展示如何利用工厂模式来封装不同抽象层次的逻辑,而又不丧失代码的灵活性。为了演示,我将使用与 Tensorflow 教程中使用的相同的数据集( Jena Climate Dataset )由 Max Planck Institute 提供。然而,为了使事情变得复杂一点,我将创建一些带有随机扰动的数据副本,以模拟我们的模型的任务是预测几个地理位置的天气的情况。此外,包含随机间隔“来来去去”的观察值的时间序列数据集并不少见。为了从数据集中获得尽可能多的训练示例,我还将考虑这一事实。

让数据更真实一点…

为简单起见,我将跳过处理特征生成的部分,集中在T (degC)栏。假设我们的模型的任务是在给定firstlastminmax温度的情况下预测几个城市的mean温度。当然,您可以将相同的推理扩展到数据集中的所有列,或者选择不同的目标(例如,从过去的平均温度预测平均温度)。一切都取决于你。然而,我在这里关注的是从多个多维系列中构建训练示例,特别注意避免数据泄露和“类似生产”的性质,新的观察结果每天都会出现。

获取数据

让我们从获取数据并按每天的时间间隔重新采样开始。

import numpy as np
import pandas as pd
import tensorflow as tf

zip_path = tf.keras.utils.get_file(
    origin="https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip",
    fname="jena_climate_2009_2016.csv.zip",
    extract=True,
)
csv_path, _ = os.path.splitext(zip_path)

df = pd.read_csv(csv_path) \
    .assign(date=lambda x: pd.to_datetime(x["Date Time"])) \
    .set_index("date") \
    .get(["T (degC)"]) \
    .resample("D") \
    .aggregate(["first", "last", "min", "max", "mean"])

df.columns = [c[1] for c in df.columns]

创建了[first, last, min, max]列之后,让我们使用烛台来显示数据。

图一。蜡烛代表温度的每日变化。蓝线描绘了平均温度,这是我们的目标。(图片由作者提供)。

嘲笑这个案子

现在,是时候模拟一个更现实的场景了,在这个场景中,数据可用性并不理想。

np.random.seed(42)

CITIES = [
    "London", "Oslo", "Warsaw", "Copenhagen", "Amsterdam", "Dublin",
    "Brussels", "Stockholm", "Prague", "Paris", "Rome", "Budapest",
    "Lisbon", "Vienna", "Madrid", "Riga", "Berlin", "Belgrade", "Sofia",
]

series = {}
for city in CITIES:
    X = df.copy()
    X += 0.75 * X.std() * np.random.randn()

    bounds = np.random.randint(0, len(X), size=2)
    bounds = sorted(bounds)
    slc = slice(*bounds)
    X = X.iloc[slc]

    series[city] = X

经过这…修改后,我们的数据如下所示:

图二。热图显示目标值,即平均温度。(图片由作者提供)。

这不就是数据在现实中的表现吗?如您所见,根据城市的不同,我们的可用性也有所不同。尤其是在伦敦,我们对序列长度的选择可能是有限的。

生成样本

在自回归中,一种常见的方法是使用滚动窗口,该窗口将沿时间维度滑动,并将其分为历史未来子序列。随着窗口向前移动(这里,步长为一天),每次获得一个新的(X, y)对。然后将这些对输入模型进行训练。

定义窗口时,需要考虑两个因素。首先,窗口的历史部分决不能进入不应该观察数据的时间区域。否则,数据泄漏是超过保证!反之,窗口的未来部分可以进入其中。但是,对于训练、验证和测试子集,我们应该确保数据存在,以便可以将预测值与真实值进行比较。在推断过程中,它是不同的。从技术上讲,今天不可能观察明天的数字。但是当太阳再次升起的时候,我们可以比较这些预测。

其次,时间“地平线”将不断向前移动。对于模型的训练来说,这意味着我们的历史数据集在增长,时间范围也应该推至未来。

正如你所看到的,整个形势相当活跃。除非设计合理,否则代码会很快失去透明性并导致错误。

解决办法

解决问题的关键是把责任分配给不同的阶层。例如,将系列分成训练和测试部分不应该是滚动窗口逻辑的一部分。类似地,一旦窗口滚动,它应该只生成数据样本,而不需要关心日期。

想一想,可以辨析一下下面的责任链。

  1. 首先,有一些存储参数的配置文件是有用的。通常,我会有两个独立的文件,比如development.iniproduction.ini以及一个get_config函数。
  2. 一旦加载了常量,让我们使用一个TimeSplitter类来计算时间间隔并给出边界日期。这些日期将定义培训、测试和验证部分的开始和结束。
  3. 日期实际上告诉了滚动窗口应该在哪里运行。然而,如前所述,我们不希望他们管理时间。滚动窗口只会生成样本,这就是工厂模式的用武之地。让我们用一个WindowFactory类来消费边界并创建Window对象。
  4. 最后,根据需要,我们可以构造不同种类的Window(例如,有或没有步长、平均窗口等。).尽管如此,一旦工厂类将日期转换成索引,每个Window将只被给予一个时间序列块来翻转并生成(X, y)对。

常数

开始之前,让我们就几个参数达成一致。

development.ini

[constants]
horizon = 2022-02-28
test_split_days = 30
val_split_days = 90
history_days = 21
future_days = 7

为了澄清约定:horizon定义了数据集的最终“盲化”。它应该是“今天”,除此之外还不存在任何观察。在生产中,该参数预计每天更新。然后,分别在区间[-inf,h-91]、[h-90,h-31]和[h-30,h]上定义训练集、验证集和测试集。最后,在这个场景中,Window需要支持在已知过去 21 天的情况下,对未来 7 天进行预测的模型。

我将离开实施get_config...一旦我们读取了数据,下一步就是:

时间分离器

from typing import Optional, Text, Tuple, TypeVar

import pandas as pd

TS = TypeVar("TS")

class TimeSplitter:
    def __init__(
        self,
        horizon: Text,
        val_split_days: int,
        test_split_days: int,
        history_days: int,
        future_days: int,
    ) -> TS:
        self.horizon = pd.Timestamp(horizon)
        self.val_split_days = pd.Timedelta(val_split_days, unit="days")
        self.test_split_days = pd.Timedelta(test_split_days, unit="days")
        self.history_days = pd.Timedelta(history_days, unit="days")
        self.future_days = pd.Timedelta(future_days, unit="days")

        # here you can put additional assertion logic such as non-negative days, etc.

    @property
    def _test_upto(self) -> pd.Timestamp:
        return self.horizon

    @property
    def _test_from(self) -> pd.Timestamp:
        return self.horizon - self.test_split_days - self.history_days

    @property
    def _validation_upto(self) -> pd.Timestamp:
        return self.horizon - self.test_split_days - pd.Timedelta(1, unit="days")

    @property
    def _validation_from(self) -> pd.Timestamp:
        return self.horizon - self.val_split_days - self.history_days

    @property
    def _train_upto(self) -> pd.Timestamp:
        return self.horizon - self.val_split_days - pd.Timedelta(1, unit="days")

    @property
    def _train_from(self) -> None:
        return None  # defined only for consistency

    def get_boundaries(self, subset: Optional[Text] = "training") -> Tuple[pd.Timestamp]:
        if subset == "training":
            return self._train_from, self.train_upto
        elif subset == "validation":
            return self._validation_from, self._validation_upto
        elif subset == "test":
            return self._test_from, self._test_upto
        else:
            raise NotImplementedError(f"Requested subset '{subset}' is not supported.")

如前所述,TimeSplitter的唯一目标是找出界限。通过额外的逻辑,我们可以针对导致病态结果的情况引入断言、警告或错误。此外,我们可以用一个Enum类替换if-else语句,将选择限制在几个预定义的选项中。这可能会超出本文的范围,所以让我们继续实现工厂类。

窗户工厂

现在,该上工厂课了。一旦计算出日期时间界限,我们希望该类使用这些信息来修剪序列并生成窗口。

class WindowFactory:
    def __init__(
        self,
        history_days: int,
        future_days: int,
        first_allowed_date: Optional[pd.Timestamp] = None,
        last_allowed_date: Optional[pd.Timestamp] = None,
    ) -> WF:
        self.hdays = history_days
        self.fdays = future_days
        self.lower_date = first_allowed_date
        self.upper_date = last_allowed_date

    def __repr__(self) -> Text:
        lower = self.lower_date or "-inf"
        upper = self.upper_date or "+inf"
        interval = f"['{lower}':'{upper}']"
        shape = f"({self.hdays}, {self.fdays})"
        name = self.__class__.__name__

        return f"{name}(interval={interval}, shape={shape})"

    def create(self, df: pd.DataFrame) -> Optional[W]:
        t0 = self.lower_date if self.lower_date is pd.NaT else None
        t1 = self.upper_date if self.upper_date is pd.NaT else None
        slc = slice(t0, t1)
        chunk = df.loc[slc]

        if (width := self.hdays + self.fdays) > len(chunk):
            print(f"Not possible to spawn a window of width={width}.")
            return None

        return Window(
            chunk,
            history_days=self.hdays,
            future_days=self.fdays,
        )

有几种方法可以实现该类。核心功能由.create方法提供。它期望一个时间序列作为一个pd.DataFrame,它的目标是正确地分割输入数据。这里,我们利用了数据帧中的索引是pd.DateTimeIndex对象的事实。然而,如果我们使用 plain numpy,想法将是相同的。

如果需要,该方法还可以扩展到支持不同种类的窗口。在我们的版本中,我们只使用一种类型的Window,所以不需要其他输入参数。

最后,我们引入__repr__方法来显示工厂在时间间隔和窗口形状方面的“能力”。纯粹是为了调试和可读性。

窗户

那么如何定义Window?毕竟,日期时间和索引管理已经完成,我们需要的只是一个产生样本的对象。

W = TypeVar("W")

class Window:
    def __init__(
        self,
        chunk: pd.DataFrame,
        history_days: int,
        future_days: int,
    ) -> W:
        self.X = chunk.to_numpy()
        self.hdays = history_days
        self.fdays = future_days

    @property
    def width(self) -> int:
        return self.hdays + self.fdays

    def __len__(self) -> int:
        return len(self.X) - self.width + 1

    def __repr__(self) -> Text:
        name = self.__class__.__name__
        iters = f"iters: {len(iters)}"

        return f"{name}[{iters}]({self.hdays, self.fdays})"

    def get_generator(self) -> Generator[np.ndarray, None, None]:
        for idx in range(len(self)):
            slc = slice(idx, idx + self.width)

            yield self.X[slc]

.get_generator方法是不言自明的。它通过以一天为步长在时间维度上滚动来给出时间序列的片段。这里,__len__方法用于表示Window将产生的样本数。例如,如果序列包含 5 条记录,窗口的宽度是 2,它应该滚动 4 次(因此最后是+ 1)。

但是等等!

生成器不会产生(X, y)对,对吗?正确。

不过,形成对子很容易。稍加修改,我们可以重新定义生成器方法:

def get_sample_pairs(self) -> Generator[np.ndarray, None, None]:
    for idx in range(len(self)):
        slc_X = slice(idx, idx + self.hdays)
        slc_y = slice(idx + self.hdays, idx + self.width)

        yield (self.X[slc_X, :4], self.X[slc_y, -1])

tf.data 版本

但是,如果您选择使用 Keras,您可能会发现用包含对的tf.data.Dataset对象替换生成器并将其传递到模型中是很有用的。为了实现这一点,让我们通过再添加一个方法来使Window对象可调用。

 def __call__(self) -> tf.data.Dataset:
        generator = lambda: self.get_generator()
        signature = tf.TensorSpec(
            shape=(self.width, 5),
            dtype=tf.float32,
            name=self.__class__.__name__,
        )
        ds = tf.data.Dataset.from_generator(
            generator,
            output_signature=signature,
        )
        ds = ds.map(lambda tensor: [
            tensor[:self.hdays, :4],
            tensor[self.hdays:self.width, -1:],
        ])

        return ds

使用这种方法的缺点是,我们创建了一个惰性加载机制,只是为了急切地消耗数据。另一方面,使用tf.data为我们提供了很多有用的函数(如prefetchshufflebatchconcatenate),使得数据在后期的处理更加容易。

整个流程

让我们重新审视我们的解决方案,并借助实现的逻辑创建完整的训练、测试和验证数据集。

# from config...
horizon = "2014-01-01"
test_split_days = 30
val_split_days = 90
history_days = 21
future_days = 7

def get_window_factory(splitter, name):
    bounds = splitter.get_boundaries(name)

    return WindowFactory(
        history_days=history_days,
        future_days=future_days,
        first_allowed_observation_date=bounds[0],
        last_allowed_observation_date=bounds[1],
    )

def get_dataset(factory, series):
    windows = {}
    for city, X in series.items():
        window = factory.create(X)
        if window is None:
            print("City skipped:", city)
            continue

        windows[city] = window

    _, window = windows.popitem()
    ds = window()
    for window in windows.values():
        _ds = window()
        ds = ds.concatenate(_ds)

    return ds

if __name__ == "__main__":
    splitter = TimeSplitter(
        horizon=horizon,
        test_split_days=test_split_days,
        val_split_days=val_split_days,
        history_days=21,
        future_days=7,
    )

    training_factory = get_window_factory(splitter, "training")
    validation_factory = get_window_factory(splitter, "validation")
    test_factory = get_window_factory(splitter, "test")

    ds_train = get_dataset(training_factory, series)
    df_val = get_dataset(validation_factory, series)
    df_test = get_dataset(test_factory, series)

结论

这就是了!一旦我们加载了常量并使用TimeSplitter分割了日期,我们就分别为每个数据集创建了三个工厂。然后使用tf.data.Datasets对象生成并收集样本。然而,我们选择参数化代码,过程保持不变,尽管如果数据集太窄(或Window的宽度太大),我们可能最终只有几个样本。

为了验证这种方法,您可以断言样本总数。

count_1 = len([x for x in ds.as_numpy_iterator()])
count_2 = sum([len(w) for w in windows.values()])

assert count_1 == count_2

这段代码当然可以改进。然而,正如您所看到的,这种方法使用起来很简单,代码应该很容易维护。它也适用于任何一般的多变量 T2 时间序列。这完全取决于你如何想象(X, y)-对的样子(例如标量,向量,张量,...)?尽管如此,通过应用这个简单的模式,您几乎可以将数据准备代码从实际模型中完全分离出来,允许您快速迭代您的想法,而不用担心数据泄漏会在您的结果中出现。

*本文使用了马克斯·普朗克研究所在 Creative Common License 下的数据集。

原载于https://zerowithdot.com/multi-time-series-data-generator/

如何处理 PostgreSQL 中的日期和时间差异

原文:https://towardsdatascience.com/how-to-handle-date-and-time-difference-in-postgresql-615f26ba0b84

SQL 提示

当没有 DATE_DIFF()函数可用时,让您的生活更轻松的 3 个技巧

乔恩·泰森在 Unsplash 上的照片

潜在客户 A 于 2022 年 1 月 20 日上午 8 点注册了贵公司的服务。她在 2022 年 2 月 3 日下午 4 点取消了订阅。她成为你们公司的客户多久了?

要回答这个问题,你需要计算两个时间点之间的差异。不考虑这种特定情况下最相关的时间尺度(差异是否应该用周来表示?几天内?几个小时?),必须有一个函数来帮助您轻松地找到两个事件之间过去了多长时间——在本例中,是潜在客户注册和取消订阅之间的时间。

在我以前的工作经验中,我曾经通过使用直接连接到我们数据库的 Google BigQuery 控制台来获得这类问题的答案。在 Google BigQuery 中,查询是用标准 SQL 编写的。足够方便的是,有一个易于实现的公式来计算两个时间点的差值 : DATE_DIFF()

但是,在 PostgreSQL 中没有与 DATE_DIFF() 直接等价的。因此,我们必须找到现有功能的正确组合,以获得我们真正需要的输出。关于这个话题, PostgreSQL 的文档非常广泛,但是我必须承认我对列出的所有公式有些困惑。

摘自 PostgreSQL 文档

看似简单的事情结果比我想象的稍微复杂一些,所以我想我可以和你分享以下 3 个正确处理 PostgreSQL 日期差异的技巧。

让我们通过引言中提到的例子来详细研究它们。在这个例子中,假设我们定义了两个输入变量:start _ date 和 end_date。我们想要得到的输出是这两个日期时间的差值:

  • 以天为单位
  • 以小时计

作者举例

#1 —避免一连串的 DATE_PART()函数

我曾经遇到的第一个技巧来自 SQLines :

SQLines 中提取

他们建议创建一个用户定义的函数,或者,如果您只有编写一些声明性 SQL ( SELECT...)的权限或技能,建议的解决方案是使用一系列的 DATE_PART()函数。在我们的示例中,我们将编写以下代码来获取天数和小时数的差异:

这将导致以下输出:

提示#1 的输出—作者的代码和屏幕截图

计算是正确的,并且输出是容易解释的。然而,我认为这种方法有两个缺点。

首先,所需的那段代码不紧凑。为了获得更好的代码可读性,必须确保代码正确缩进,以便读者理解哪个“日期部分”对应于计算的哪个部分。在我们的例子中,我们只进行到小时刻度,但是如果我们想计算秒的差异,我们将添加两个额外的 DATE_PART 函数。

第二,多次调用函数 DATE_PART()会导致在执行段代码时可能会损失性能。当对相同的输出实现各种选项时,必须确保比较两个查询在应用于相同数据集时的性能。

#2—从年龄开始()

在 PostgreSQL 中,函数 AGE()将为您的问题提供详细的答案:这两个事件之间经过了多长时间?输出以文本行的形式显示两个时间点之间的差异。

输出将如下所示:

技巧#2 的输出—作者的代码和屏幕截图

根据您的数据输入和您正在处理的用例,您可能会对这种方法感到满意。特别是,如果您用函数 AGE()给出的输出来回答最终用户的需求,可能就没有必要使输出过于复杂。

#3 —使用 EXTRACT(EPOCH FROM())提升级别

如果您确定所有值都包含在给定的日期和时间范围内,请保持简单。只要坚持使用 AGE()函数,并结合 EXTRACT() 即可。这适用于以下以天数表示的差异。但是仔细看看以小时为单位的输出差异:

提示#2 的不当使用输出—作者的代码和屏幕截图

正如您可能注意到的,第二个查询的问题是,我们试图返回两天之间的时间差异。在这里,AGE()函数并不合适:它返回以小时为单位的差值…不考虑日期!

在这种情况下——无论如何,如果您有疑问——您应该使用 EXTRACT()函数和 EPOCH 参数的组合。让我们最后一次以我们的例子来证明:

输出将如下所示:

技巧#3 的输出—作者的代码和屏幕截图

成功了!与使用选项#1 编写的代码相比,有两个优点:

  1. 代码更加简洁
  2. 天数的差异以更详细的级别表示(默认情况下,有两位小数)

结论

在适用的地方保持简单

在相关的地方使它变得复杂

本文的目的是收集有用的技巧来处理 PostgreSQL 中的日期和时间差异。您无需一次应用所有这些功能——只需选择最适合您自己的用例即可。

在 PostgreSQL 中使用其他函数来轻松处理日期和时间吗?我很乐意听到他们,并在评论区分享我们的最佳实践!

你喜欢读这篇文章吗? 成为会员 加入一个不断成长的充满好奇心的社区吧!

https://marie-lefevre.medium.com/membership

如何在 Python 中处理大型数据集

原文:https://towardsdatascience.com/how-to-handle-large-datasets-in-python-1f077a7e7ecf

CSV、Pickle、Parquet、Feather 和 HDF5 的比较

图片由作者提供。

经过这么长时间,当 Kaggle 最终推出一个新的表格数据竞赛时,起初,每个人都很兴奋。直到他们不在了。当 Kagglers 发现数据集有 50 GB 大时,社区开始讨论如何处理这样大的数据集[4]。

CSV 文件格式需要很长时间来读写大型数据集,并且除非明确告知,否则不会记住数据类型。

除了通过减少数据类型来减少所需的磁盘空间,问题是在工作会话之间以何种格式保存修改的数据集[4]。CSV 文件格式需要很长时间来读写大型数据集,并且除非明确告知,否则不会记住列的数据类型。本文探讨了处理大型数据集的 CSV 文件格式的四种替代方案:Pickle、Feather、Parquet 和 HDF5。此外,我们将看看这些压缩文件格式。

本文探索了 pandas 库的可选文件格式。现在,你可能会想“在处理大型数据集时,为什么还要使用熊猫呢?”这是一个合理的问题。虽然像 Datatable 这样的 pandas 的替代品在读取和写入 CSV 文件时会更快,但 pandas 的优势在于它为数据处理提供了很大的灵活性。此外,pandas 支持开箱即用地读写许多文件格式。同样,像 Datatables 这样的替代方法只支持 CSV、Jay、XLSX 和纯文本格式[3]。

你可以在我的 Kaggle 笔记本里找到代码。

基准设置

出于基准测试的目的,我们将创建一个虚构的数据集。这个虚构的数据集包含每种数据类型的一列,但有以下例外:本例中省略了数据类型为float16categorical的列,因为 parquet 不支持float16,而带有format = "table"的 HDF5 不支持categorical。为了减少时间噪声以提高可比性,这个虚构的数据集包含 10,000,000 行,并且几乎有 1GB 如[8]所示。

用于基准测试的虚构数据集的头(图片由作者通过 Kaggle 提供)

数据的特征会影响读写时间,例如数据类型、数据帧的宽度(列数)与长度(行数)。但是,这超出了本文的范围。对于进一步的阅读,我推荐以下资源:

https://www.architecture-performance.fr/ap_blog/loading-data-into-a-pandas-dataframe-a-performance-study/

文件格式概述

在这一节中,我们将简要介绍每种文件格式的一些关键特征:简短描述、文件扩展名、使用的压缩和 pandas 读写方法。

逗号分隔值 (CSV)

使用逗号分隔值的文本文件。文件扩展名为.csv

在本文中,我们将使用 gzip 压缩。

# Reading
df = pd.read_csv(file_name, 
                 dtype = {...})# Writing
df.to_csv(file_name, 
          index = False,
          compression = ...) # None or "gzip" 

泡菜

[pickle](https://docs.python.org/3/library/pickle.html#module-pickle)模块实现了用于序列化和反序列化 Python 对象结构的二进制协议。[7]

文件扩展名是.pkl

在本文中,我们将使用 gzip 压缩。

# Reading
df = pd.read_pickle(file_name)# Writing
df.to_pickle(file_name, 
             compression = ...) # None or "gzip"

镶木地板

Apache Parquet 是一种列存储格式,适用于 Hadoop 生态系统中的任何项目,无论选择的是数据处理框架、数据模型还是编程语言。[2]

文件扩展名为.parquet

在本文中,我们将使用 pyarrow 引擎和 gzip 压缩。

# Reading
df = pd.read_parquet(file_name)# Writing
df.to_parquet(file_name, 
              engine = "pyarrow", 
              compression = ...) # None or "gzip"

羽毛

Feather 是一种用于存储箭头表或数据框(来自 Python 或 R 等语言)的可移植文件格式,它在内部利用了箭头 IPC 格式。Feather 是在 Arrow 项目早期创建的,作为 Python (pandas)和 r[1]的快速、语言无关的数据帧存储的概念证明

文件扩展名是.feather

由于 gzip 压缩不适用于 feather 格式,我们将使用 zstd 压缩。

# Reading
df = pd.read_feather(file_name)# Writing
df.to_feather(file_name, 
              compression = ...) # None or "zstd"

分层数据格式(HDF5)

HDF5 是一种用于存储和管理数据的数据模型、库和文件格式。它支持无限多种数据类型,专为灵活高效的 I/O 以及大量复杂数据而设计。HDF5 具有可移植性和可扩展性,允许应用在使用 HDF5 的过程中不断发展。[5]

文件扩展名为.h5

HDF5 有两种格式选项:

  • "fixed",哪个写字快【6】
  • "table",速度较慢,但提供了“灵活的操作,如搜索/选择数据子集”[6]

为了读写 HDF5 文件,你需要安装tables

由于 gzip 压缩不适用于 feather 格式,我们将使用 zlib 压缩。

# Reading
df = pd.read_hdf(file_name)# Writing
df.to_hdf(file_name, 
          key = "df", 
          format = ..., # "fixed" or "table"
          complib = ..., # None or "zlib"
          complevel = 9)

比较

本节根据写入时间、文件大小、读取时间和各种特征(如可读性、一致性、预期存储时间和可移植性以及在小型数据集上的性能)来比较这五种文件格式。

写作时代

下面,您可以看到为每种文件格式编写文件所需的时间。实心黑条表示未压缩文件的写入时间,而散列条表示压缩文件的写入时间。

不同文件格式的写入时间比较(图片由作者通过 Kaggle 提供)

首先,让我们解决房间里的大象:压缩增加了任何文件格式的写入时间。但这并不奇怪,因为数据压缩是写入过程中的一项额外任务。

此外,我们可以进行以下观察:

  • 正如所料,对于 CSV,写入时间最长
  • 羽毛和拼花有最快的 未压缩的写入时间
  • Feather 对于未压缩和压缩的文件都有最快的写入时间
  • 不出所料, HDF5 搭配 **format = "fixed"** **format = "table"**快,但搭配压缩 HDF5 搭配format = "fixed"format = "table"差不多

文件大小

下面,您可以看到每种文件格式的结果文件大小。实心黑条表示未压缩文件的文件大小,而散列条表示压缩文件的文件大小。

不同文件格式的文件大小比较(图片由作者通过 Kaggle 提供)

我们可以做出如下观察:

  • 不出所料,压缩文件比未压缩文件小
  • CSV 是最大的文件
  • 拼花是最小的未压缩文件
  • **format = "table"** 的拼花和 HDF5 是最小的压缩文件

阅读时间

下面,您可以看到每种文件格式读取文件所需的时间。实心黑条表示未压缩文件的读取时间,而散列条表示压缩文件的读取时间。

不同文件格式的阅读时间对比(图片由作者通过 Kaggle 提供)

我们可以做出如下观察:

  • 正如所料,对于 CSV,读数需要较长的时间
  • Pickle 和 HDF5 带 **format = "fixed"** 未压缩和压缩的文件都有最快的读取时间
  • 不出所料, HDF5 与 **format = "fixed"** **format = "table"**更快,同样具有压缩性

多方面的

除了读写时间和文件大小之外,我们还应该关注更多的特性:可读性、一致性、预期存储时间和可移植性,以及小数据集的性能。

人类可读性

CSV 是人类可读的唯一文件格式。所有可选的文件格式都是二进制格式,因此人类无法阅读。

一致性

除非你明确告诉.read_csv()方法用哪种数据类型来读取每一列,否则 CSV 文件格式不会记住数据类型。这需要预先了解数据类型,也是一项额外的工作。

如果读取方法中没有明确列出数据类型,这会导致所需存储空间增加,因为所有整数都被读取为int64,所有浮点都被读取为float64,而datetime64[ns]categorical被读取为object。在下面,您可以看到原始数据帧和读写 CSV 文件后的数据帧:

CSV 文件读写前后的列数据类型比较(图片由作者通过 Kaggle 提供)

正如您所看到的,由于将较小的数据类型转换为较大的数据类型,所需的内存使用增加了。

预期储存时间和便携性

泡菜和羽毛旨在短期储存[7,8,9]。Pickle 用于在工作会话之间保存 Python 对象,因此仅受 Python 支持。Feather 旨在 Python 和 R [9]之间交换数据。Pickle 和 Feather 也不能保证版本之间的稳定性[7,9]。

小数据集上的性能

尽管本文关注的是大型数据集,但值得一提的是对于小型数据集,HDF5 格式的读写时间很短。如下图所示,如果数据集小于 2 MB,读取 HDF5 文件所需的时间甚至比 CSV 文件还要长。

不同文件格式在不同文件大小下的读写时间比较(图片由作者通过 Kaggle 提供)

下表总结了这一部分的比较:

CSV、Pickle、Parquet、Feather 和 HDF5 的对比(图片由作者提供)

结论

正如所料,CSV 文件格式在读取和写入文件时都是最慢的。除非您正在优化文件大小,否则所有替代方案大约只有 CSV 文件格式的一半。

不幸的是,这个价值 100 万美元的问题有一个不令人满意的答案:

"哪种格式是处理大型数据集的最佳格式?"

—“这取决于您的使用情形,但可能不是 CSV”

这里是我试图为这个答案的“视情况而定”部分提供更多的细节。我很想听听你在这方面的意见。

试图提供一个选择最佳文件格式的粗略指南(图片由作者提供)

尽管有缺点,CSV 还是被广泛使用。看起来,它是人类可读的,而不是二进制文件格式,这一事实使它成为一种直观的文件格式,您可以快速打开并查看它,而不会有任何麻烦。因此,除非您正在处理数千兆字节的数据,否则 CSV 仍然是一个可接受的选项。

“CSV 毕竟没那么差。别管了!”

喜欢这个故事吗?

要阅读更多来自我和其他作家的故事,请在 Medium 上注册。报名时可以用我的 推荐链接 支持我。我将收取佣金,不需要你额外付费。

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

LinkedIn 上找我 Kaggle

参考

[1] Apache Arrow,“羽毛文件格式”。apache.org。https://arrow.apache.org/docs/python/feather.html(2022 年 7 月 25 日访问)

[2]阿帕奇拼花地板,“概述”。apache.org。https://parquet.apache.org/docs/overview/(2022 年 7 月 25 日访问)

[3]数据表,“datatable.fread()”。datatable . readthe docs . io .https://datatable . readthe docs . io/en/latest/API/dt/fread . html(2022 年 7 月 25 日访问)

[4] C. Deotte,“如何减少数据量”。kaggle.com。https://www . ka ggle . com/competitions/amex-default-prediction/discussion/328054(2022 年 7 月 25 日访问)

[5]HDF 小组,“HDF5”。hdfgroup.org。https://portal.hdfgroup.org/display/HDF5/HDF5(2022 年 7 月 25 日访问)

[6]“熊猫”,“熊猫。DataFrame.to_hdf "。pydata.org。https://pandas . pydata . org/pandas-docs/stable/reference/API/pandas。data frame . to _ hdf . html(2022 年 7 月 25 日访问)

[7]“Python”,“pickle — Python 对象序列化。”python.org。https://docs.python.org/3/library/pickle.html(2022 年 7 月 25 日访问)

[8]“stack overflow”,“羽毛和拼花有什么区别?”。stackoverflow.com。https://stack overflow . com/questions/48083405/feather-and-parquet 之间的区别是什么

[9] H. Wickham,“Feather:一种用于 R 和 Python 的快速磁盘上数据帧格式,由 Apache Arrow 提供支持”。rstudio.com。https://www.rstudio.com/blog/feather/(2022 年 7 月 25 日访问)

医学时间序列研究中缺失数据的处理

原文:https://towardsdatascience.com/how-to-handle-missing-data-in-medical-time-series-studies-e23c8e3e6451

简单有效的方法——专为递归神经网络设计——经受住了广泛的学术评估的考验

图片来源:pixabay.com

背景

大量医疗数据本质上是时间序列数据——心电图、体温监测、血压监测、定期护士体检等等。在这些医学图表的趋势、模式、峰值和谷值中,蕴藏着大量有价值的信息,等待被发现。医疗行业需要对医疗时间序列数据进行有效分析,这被认为是提高医疗质量、优化资源利用和降低整体医疗成本的关键。

医学时间序列分析的一种有前途的形式是通过递归神经网络(RNN)。近年来,RNN 因其建模能力和消费可变长度输入序列的能力而受到医学研究人员的欢迎。研究人员通常将时间序列数据分成均匀的时间步长,如 1 小时/时间步长或 1 天/时间步长。一个时间步长内的所有数据点将通过平均或其他聚合方案进行聚合。这有两个好处。首先,它减少了时间序列数据序列的长度。第二,考虑到原始原始数据点通常在时间上间隔不规则的事实,它归一化了时间上下文。经过这一预处理步骤后,数据基本上可以供 RNN 使用了。但是有一个没有答案的问题:如果在一个给定的时间步长内没有数据会怎样?

上述问题在医疗环境中很重要,因为缺失的医疗数据通常不是随机缺失的。数据的缺失本身具有临床意义。例如,医院工作人员可能会停止测量被认为已经稳定的病人的体温。或者,患者的情况可能需要一种不同的测量方法来取代以前的测量方法。因此,通常的零填充或插补方法往往会产生次优的性能。

在这篇博文中,我们将回顾 3 种简单的方法来处理 RNN 时间序列研究中缺失的医学数据。后一种方法建立在前一种方法的基础上,具有更高的复杂性。因此,强烈建议按照出现的顺序阅读。

简单缺失编码

让我们假设每个时间步的输入变量是带有下标tx。变量有d维度,用上标d表示。图 1 (a)显示了输入的图解,并对d=1进行了简化。深色阴影部分是缺少的数据。我们应用向前插补,用它们最近的观察值来填充它们。向前插补是有意义的,因为一旦医院工作人员认为指标稳定,他们通常会停止进一步测量,在这种情况下,最近观察到的值可以作为未来实际值的替代值结转。

由这篇研究论文提出的简单缺失编码方法建议,我们应该显式编码给定数据点实际上是估算的而不是实际观察到的。这种显式编码向 RNN 提供信号,以考虑数据的缺失。图 1 (b)中显示了一个示例,其中m表示缺少x,其中1表示存在,0表示不存在(如公式 1 中所定义)。输入是xm的串联。

图 1:编码缺失。深色是缺少值的地方,因此必须进行估算。

公式 1:思念。

这种方法在那篇研究论文中提出的实验中产生了有意义的改进。您的里程可能因数据集而异。但是这是一个非常简单直观的想法,值得一试。

时间距离编码

为了构建上述方法,本文提出,除了对缺失进行显式编码之外,还要对一个值与最近观测值之间的时间距离进行显式编码。现在,输入是所有三个值编码的串联,即输入x、缺失信号m和时间距离值δ。请参见公式 2 和图 2 中的图示。

公式 2:时间距离。

图 2:编码缺失和时间距离。深色是缺少值的地方,因此必须进行估算。

实验表明,该方法在丢失率显式编码的基础上有了很大的提高。

引入衰变

为了再次建立在上述方法的基础上,同一篇论文提出了估算值的衰减机制。回想一下,我们应用了向前插补来结转最近观察到的值。但是如果失踪期延长了呢?我们应该无限期地沿用那些旧的观察值吗?如果我们想一想真实世界的场景:医院工作人员停止跟踪一个指标,因为他们认为它是稳定的。该指标值可能仍在正常范围的远端,但相信它最终会回到一个良好的中间值。这意味着,在没有观察到的数据的情况下,我们有很好的理由相信当前的度量值将徘徊一段时间,但最终会“衰减”回良好的医疗默认值。

衰减因子γ由权重矩阵W和偏差b确定,应用于时间距离δ(见公式 3),然后馈送到在1结束的反向exp函数。Wb跨时间步长共享,并在培训期间共同学习。

公式 3:衰变因子。

形式上,在任何给定的时间步t,如果观察到x,我们使用x。否则,我们使用最后一次在t’观察到的值,衰减到x的经验平均值。RNN 的最终输入见公式 4。

公式 4:对 RNN 的最终投入。

该论文还将类似的衰减机制应用于他们的 RNN 模型的隐藏状态,这产生了最好的结果。但是因为我们正在讨论 RNN 输入的原始数据的处理,我们不会深入讨论这个问题。

结论

在这篇博文中,我们介绍了医学时间序列数据研究的背景。我们提出了 3 种为 RNNs 设计的简单方法,旨在明确编码缺失数据的临床意义作为模型的输入,根据提出的论文,这可以产生更好的结果。希望这是一篇快速阅读的文章,它能为你自己的分析项目带来一些好的想法。

如何处理优化问题

原文:https://towardsdatascience.com/how-to-handle-optimization-problems-daf97b3c248c

Unsplash 上的 CHUTTERSNAP 拍摄

带有解决方案和代码的简单示例

变量、约束和目标

为了定义一个优化问题,你需要三样东西:变量、约束和目标。变量可以取不同的值,规划求解将试图找到变量的最佳值。约束是不允许的事情或界限,通过正确设置它们,你肯定会找到一个在现实生活中可以实际使用的解决方案。目标是你在最优化问题中的目标,这是你想要最大化或最小化的。如果现在还不完全清楚的话,这里有一个更全面的介绍。不要犹豫继续,因为示例将引导您并更详细地解释概念。

代码示例

想象你是一个小包裹递送公司的 CEO。该公司发现交付流程可以改进。他们希望首先交付最有价值的包裹组合,并为每次旅行确定最短的路线。他们最不想改进的就是任务的划分。一些员工抱怨,因为他们想更频繁地送货,而不是分拣包裹。

如果您想自己尝试这些示例,您需要一个安装了以下包的工作 python 环境: pyomopandasnumpy 。您还应该下载一个像 cbc 或 glpk 这样的解算器,并在可执行路径中使用它。一些关于列表理解python 编程的知识会很有帮助,不在本文讨论范围之内。

示例 1:选择要交付的包裹

包裹的价值越高,这个包裹对顾客就越重要。快递公司有一张表格,上面列有包裹及其价值和重量:

每个包裹的包装号,包括价值和重量。

该公司希望选择总价值最高且总重量小于 600 的包裹(这是送货车可以处理的最大重量)。应该选择哪些包?目标很明确:我们希望最大化所选包的总价值。约束条件是所选包裹的总重量应小于或等于 600。我们可以将变量定义为每个包的二进制变量,如果没有选择包,则等于零,如果选择了包,则等于一。

开始编程吧。

首先,我们导入包,加载表并从表中提取数据(这使得下一部分中的代码可读性更好):

import numpy as np
import pandas as pd
import pyomo.environ as pyo
from pyomo.opt import SolverFactory
import time# load dataframe with package details
data = pd.read_excel('package_details.xlsx')# extracting the indici, weights and values from the dataframe
indici = list(data.index.values)
weights = data['Weight'].values
values = data['Value'].values

现在我们可以开始使用 pyomo:

# create a concrete model
model = pyo.ConcreteModel()# define the VARIABLES (in the end 0=not selected, 1=selected)
model.x = pyo.Var(indici, within=pyo.Binary)
x = model.x# define the CONSTRAINT, the total weight should be less than 600
model.weight_constraint = pyo.Constraint(expr= sum([x[p]*weights[p] for p in indici]) <= 600)# define the OBJECTIVE, we want to maximize the value of the selected packages
model.objective = pyo.Objective(expr= sum([x[p]*values[p] for p in indici]), sense=pyo.maximize)# print the complete model
model.pprint()

回想一下,该变量是一个二元决策变量,将等于 0(未选择)或 1(已选择)。该约束确保所选包装的总重量不超过 600。为此,我们应该用包裹的重量乘以x变量,然后将这些值相加。该目标计算所选包的值的总和(将x与一个包的值相乘并求和),我们希望最大化该目标(sense=pyo.maximize)。model.pprint()显示已定义的模型:

仅此而已!现在是时候调用求解器了,它会给出我们应该选择的包:

# replace the executable path by your own
opt = SolverFactory('cbc', executable='C:\cbc\\bin\cbc.exe')
results = opt.solve(model)

几秒钟之内,求解器就找到了最优解!我们可以在原始数据框架中添加一个解决方案列。

solution = [int(pyo.value(model.x[p])) for p in indici]
data['solution'] = solution

添加了解决方案列。

能不能把这个问题改成选择最大数量的包,而不是所选包的最大总值?

问题解决了,让我们继续下一个!

斯蒂芬·门罗在 Unsplash 拍摄的照片

示例 2:确定交付选定包裹的顺序

为了尽可能快地递送选定的包裹,我们想走最短的路线。我们从取货点开始,我们想在那里结束去取新的包裹。我们如何对这个问题建模并使用优化来解决它?这个问题比上一个问题稍微难一点。让我们定义目标、约束和变量。

目标是最小化路线的总距离。约束条件是:我们要从取货点开始,到取货点结束,每个包裹都要投递,所以我们需要访问所有的地址至少一次。我们还需要确保创建一条完整的路线,而不是多条小路线。最后但同样重要的是,变量。我们用二进制变量创建一个 from,to 矩阵,其中 1 表示选择了这条路,0 表示没有选择。如果我们从地址 6 到地址 2。

对于这个问题,我们需要一个距离矩阵。在下面的矩阵中检查从地址 6 到地址 2 的距离是否等于 16。地址 0 是我们的起点(也是终点)。我们需要交付 8 个包裹,由其他 8 个地址代表。

距离矩阵。

创建随机距离矩阵的代码:

import random
import pandas as pdindici = range(9)
distances = pd.DataFrame(index=indici, columns=indici)for from_ in indici:
   for to in indici:
      if from_ == to:
         distances.loc[from_, to] = 0
      elif pd.isna(distances.loc[from_, to]):
         dist = random.choice(range(1, 30))
         distances.loc[from_, to] = dist
         distances.loc[to, from_] = dist

首先,我们声明模型、地址(列出距离矩阵的索引值)和变量:

model = pyo.ConcreteModel()addresses = distances.index# declaring the VARIABLE matrix, again with only binary values
model.x = pyo.Var(addresses, addresses, within=pyo.Binary)
x = model.x

在这个例子中,变量是一个矩阵:我们通过对地址循环两次来创建它。所以x[2,3]对应的是从地址 2 到地址 3 的路由。

现在是时候声明约束了。这次我们将使用约束列表,因为我们想要同时添加多个约束。

第一个约束列表将保存我们往返于同一个地址的值。我们不想激活它们,所以我们设置所有的变量值,其中 from 和 to 点都等于零:

model.diagonal = pyo.ConstraintList()
for a in addresses:
   model.diagonal.add(expr= x[a, a] == 0)

下一个约束是关于访问每个地址一次。这意味着每个地址都应该恰好是一个“收件人”地址和一个“发件人”地址。

model.visit_once = pyo.ConstraintList()
for a in addresses:
   model.visit_once.add(expr=sum([x[a, to] for to in addresses])==1)
   model.visit_once.add(expr=sum([x[fr, a] for fr in addresses])==1)

而最后的约束:我们不想绕圈子,我们要完整的路线!所以如果我们从地址 0 旅行到地址 5,我们不想从地址 5 旅行到地址 0!这两条路线中的任何一条都不应该被激活,所以x[0, 5] + x[5, 0] <= 1。这个约束确保我们得到一个完整的路线,而不是多个较小的路线。查看米勒-塔克-泽姆林公式,了解该约束的解释。这里我们引入一个叫做u的虚拟变量。

n = len(addresses)
model.u = pyo.Var(addresses, within=pyo.NonNegativeIntegers, bounds=(1, n))
u = model.umodel.no_circles = pyo.ConstraintList()
for a1 in range(1, n):
   for a2 in range(1, n):
      if a1 != a2:
         model.no_circles.add(expr= u[a1]-u[a2]+x[a1,a2]*n <= n-1)

约束,检查!对于目标,我们希望最小化激活路线的距离总和。我们对地址组合进行循环,并将 x 的值乘以路由的距离。这些值的总和给出了总距离。这一次我们需要呼叫pyo.minimize,因为我们想把总距离减到最小。

# declaring the OBJECTIVEsum_of_distances = sum([x[a1, a2]*distances.loc[a1, a2] for a1 in addresses for a2 in addresses])model.obj = pyo.Objective(expr=sum_of_distances, sense=pyo.minimize)

现在是解决问题的时候了。调用求解器并打印结果:

opt = SolverFactory('cbc', executable='C:\cbc\\bin\cbc.exe')
results = opt.solve(model)print(pyo.value(model.obj)) # gives 62 (for this distance matrix)solution = []
for a1 in addresses:
   solution.append([pyo.value(model.x[a1, a2]) for a2 in addresses])

目标的值是 62,因此该路由的总距离等于 62。在你的情况下,它可能是另一个数,因为你可能有另一个距离矩阵。解决方案矩阵如下所示:

每行有一个 1,每列也有一个 1。所以我们每个地址都去一次。要使这个解决方案更具可读性,请使用以下代码:

def print_route(solution):
   sol_ind = list(np.where(np.array(solution[i]) == 1)[0][0] for i in range(len(solution)))
   one_dict = {k:sol_ind[k] for k, _ in enumerate(sol_ind)} sol_str = '0 -> '
   nxt = one_dict[0]
   sol_str += str(nxt)
   while True: 
      nxt = one_dict[nxt]
      sol_str += ' -> '
      sol_str += str(nxt)
      if nxt == 0:
         break print(sol_str)print_route(solution)

结果:

解决方案印刷精美。在拾取点(地址 0)开始和结束。

因此,从起点(起点,地址 0),我们去地址 2,地址 8,地址 5,地址 4,等等,直到我们回到了起点。我们递送了所有包裹,我们可以肯定这是可用的最短路线之一!

注意:这个问题是旅行商问题的变种。

你已经解决了两个问题,很好!让我们继续最后一个!

安妮·斯普拉特在 Unsplash 上的照片

示例 3:任务划分

最后一个问题是关于任务分工。目前,你有六名员工,你想让他们保持快乐和精力充沛。但同时,工作是需要做的!那么,你如何才能同时完成这两项任务,完成工作,并让员工开心呢?简单,你创建另一个优化模型!您定义需要完成的任务,如清洁、分拣包裹、递送包裹和在服务中心。在接下来的一个月里,你要定义每项任务需要多少次轮班,以及每次轮班需要多长时间。这给出了您需要员工工作的总小时数,您希望给每个员工相同的工作时间,执行他们喜欢的任务。

# no of shifts needed for the upcoming month
DELIVERIES = 45
SORTING = 20
SERVICE_CENTER = 20
CLEANING = 10task = {'DELIVERY': DELIVERIES, 'SORT': SORTING, 'SERVICE': SERVICE_CENTER, 'CLEAN': CLEANING}# time needed for every shift
time_p_shift = {'DELIVERY': 8, 'SORT': 4, 'SERVICE': 6, 'CLEAN': 3}# total time needed 
total_hours = sum([task[k]*timepershift[k] for k in task.keys()])

接下来,你定义你的员工,让他们决定他们喜欢做什么样的轮班。

employees = {'John':['DELIVERY', 'CLEAN'], 'Jack':['DELIVERY'], 'Joshua':['SORT', 'CLEAN'], 'Janice':['DELIVERY', 'SERVICE'], 'Joyce':['DELIVERY', 'CLEAN', 'SERVICE', 'SORT'], 'Joy':['CLEAN', 'SERVICE', 'SORT']}emp_list = employees.keys()

约翰喜欢送货和打扫卫生,而乔伊喜欢打扫卫生,呆在服务台,整理包裹(她可能没有驾照)。现在您可以计算每个人应该工作的平均小时数,您将在目标中使用该值:

avg_hours_pp = total_hours/len(emp_list)final_df = pd.DataFrame(index=emp_list, columns=task.keys())

final_df最终将获得最佳值:

final_df 将在稍后接收最佳变量值。

约翰这个月应该有六个送货班。

数据处理完后,我们就可以开始建模了。我们使用员工和任务创建一个变量矩阵。

model = pyo.ConcreteModel()model.Employees = pyo.Set(initialize=emp_list)
model.Tasks = pyo.Set(initialize=task.keys())# define the VARIABLE matrix x using the employees and the tasks
model.x = pyo.Var(model.Employees, model.Tasks, within=pyo.Integers, bounds=(0, None))# define the hours of work per task
model.hours = pyo.Param(model.Tasks, initialize=time_p_shift)

我们希望每个班次都有人,因此我们需要添加约束条件,以确保我们有足够的人员来完成每项任务:

model.shifts_needed = pyo.ConstraintList()
for t in model.Tasks:
   model.shifts_needed.add(expr= sum([model.x[employee, t] for employee in model.Employees]) == task[t])

我们希望排除人们不想做的某些任务:

model.excluded = pyo.ConstraintList()
for employee in model.Employees:
   incl = employees[employee]
   excl_tasks = list(task.keys()-incl)
   for t in excl_tasks:
      model.excluded.add(expr= model.x[employee, t] == 0)

我们的目标是给所有员工同等数量的工作,只分配他们想做的任务。我们如何才能做到这一点?我们之前计算了平均小时数。我们希望最大限度地缩短从人们收到信息的时间到avg_hours_pp的绝对距离。因为如果这个距离等于零,每个人得到的功都是一样的。

计算绝对距离是可能的,但不像使用abs()那么简单。Pyomo 处理不了绝对函数,因为问题变得非线性了。因此,我们在这里引入两个新变量:model.posdelta表示与avg_hours_pp的正距离,而model.negdelta表示负距离。使用约束列表,我们设置这些变量值:

model.posdelta = pyo.Var(model.Employees, bounds=(0, None))
model.negdelta = pyo.Var(model.Employees, bounds=(0, None))# defining the variables posdelta en negdelta using CONSTRAINTLIST
model.distance_from_avg = pyo.ConstraintList()
for employee in model.Employees:
   model.distance_from_avg.add(expr= sum([model.x[employee, t]*model.hours[t] for t in model.Tasks]) + model.posdelta[employee] - model.negdelta[employee] == avg_hours_pp)# defining the OBJECTIVE, minimize posdelta + negdelta
model.obj = pyo.Objective(expr= pyo.summation(model.posdelta) + pyo.summation(model.negdelta), sense=pyo.minimize)

是时候调用求解器并显示结果了:

opt = SolverFactory('cbc', executable='C:\cbc\\bin\cbc.exe')
results = opt.solve(model)def create_result_frame(model, df):
   solution = pd.DataFrame(np.reshape(pyo.value(model.x[:, :]), (df.shape[0], df.shape[1])), index=emp_list, columns=task.keys())
   solution = solution.astype('int')
   return solutionsolution = create_result_frame(model, final_df)

solution数据帧看起来像这样:

它告诉我们每个人应该轮班多少次。最重要的问题是:任务是否平均分配?

for emp in model.Employees:
   print(f'{emp}:', int(sum([pyo.value(model.x[emp, t])*pyo.value(model.hours[t]) for t in model.Tasks])), 'hours')

是的,每个人的工作量都差不多!

如果你想了解更多关于处理绝对值、线性化和其他高级概念的信息,请看这里

结论

我们在本帖中处理的问题是整数线性规划的例子。这是一种在许多不同行业中使用的技术,具有强大的功能。如果你的问题变得更大,像 CBC 这样的开源求解器将需要很长时间才能运行。你可能想切换到商业解算器,如 GurobiCPLEX 。如果你想让你的优化技巧更上一层楼,我可以推荐这个 Udemy 课程

有关系的

别忘了 订阅 如果你想在我发表新文章时收到电子邮件。

如何处理异常值、异常值和偏差

原文:https://towardsdatascience.com/how-to-handle-outliers-anomalies-and-skews-2673ab0dea85

数据科学是关于发现模式并从分析中提取有意义的见解。然而,正如任何从业者都知道的,数据喜欢偶尔扔给我们一个曲线球:一个奇怪的峰值,一个意外的下降,或者(喘息!)一个形状奇特的星团。

本周,我们将注意力转向那些不和谐的时刻,当事情(和我们的图表)没有我们希望的那么顺利。我们精选的亮点涵盖了处理不规则性和应对不可预测性的不同方法。

  • 寻找离群值,正确的方法 。正如亨尼·德·哈德所观察到的,“在大多数项目中,数据将包含多个维度,这使得肉眼很难发现异常值。”Hennie 展示了如何利用 Cook 的距离、DBSCAN 和隔离森林来识别需要额外审查的数据点,而不是依赖我们容易出错的观察能力。
  • 如何将数据偏斜的潜在危险降到最低 。在过去的几年里,偏见一直是数据和 ML 专业人士的热门词汇。 Adam Brownell 邀请我们将偏见视为“产生一种伤害的偏差”,并带领我们通过三种策略在自然语言处理模型的背景下有效地测量它。

詹妮弗·博伊尔在 Unsplash 上的照片

  • 对抗性训练来救援? 异常检测在计算机视觉中尤其困难,在这种情况下,小数据量和通常有限的图像种类使得模型训练成为一种挑战。尤金妮亚·阿内洛(Eugenia Anello)的有益解释者带领我们通过一种新颖的方法 GANomaly,它利用生成对抗网络的力量来解决以前方法的缺点。
  • 保持线性回归的异常值。要实际演示稳健的线性算法,以及如何使用它们处理数据中潜伏的异常值,你应该看看埃里克·莱文森最近的教程。它涵盖了 Huber 回归、随机样本一致性(RANSAC)回归和 Theil-Sen 回归,并在同一数据集上对它们的性能进行了基准测试。

对于其他主题的顶级文章,我们在下面收集了一些我们最近喜欢的文章。不要害怕:这里没有局外人,只有持续启发性的讨论。

我们喜欢与您分享伟大的数据科学成果,您的支持——包括您的媒体会员——让这一切成为可能。谢谢大家!

直到下一个变量,

TDS 编辑

如何在 C++中堆一棵树

原文:https://towardsdatascience.com/how-to-heapify-a-tree-in-c-e5abe494097d

用 C++构建堆的初学者指南

照片由像素上的 Pixabay 拍摄

在计算机科学中,堆是一种树形数据结构,其特殊性质是几乎完全满足堆性质的二进制结构。该属性对应于最大堆和最小堆。最大堆是一种数据结构,其中每个子节点小于或等于其父节点。最小堆是类似类型的数据结构,其中每个子节点大于或等于其父节点。当这些约束被放在树数据结构上时,我们最终得到的是长度相对较短的树。这使得在树中搜索值的过程更快。让我们考虑下面的最大堆:

作者创建的图像

在树的顶部,我们有一个值为 90 的根节点。最大堆的属性是根节点具有最大值。此外,每个节点的值小于或等于其父节点。我们看到 90 是树中最大的值。此外,在第二层,我们看到小于 90 的值 79 和 72,然后是小于 79 的值 30 和 65,依此类推。

相反,看看下面的 min 堆的例子:

作者创建的图像

如果我们将根处的值与根下每个节点处的值进行比较,我们会发现 12 是树中的最小值。在下面的级别,我们有 20 和 29,它们都大于 12,以此类推。

堆树的任务是重新排列树的元素,使其具有最小或最大堆的属性。具体来说,max-heapify 是这样一个过程,它采用一个表示为二叉树的数组,并记录每个节点的值,使得子节点小于或等于父节点,从而满足最大堆:

作者创建的图像

Min-heapify 是记录每个节点的值的过程,使得子节点大于或等于父节点,满足最小堆:

作者创建的图像

由于堆数据结构的有利属性,堆化是有用的。使树满足堆属性可以加速许多算法任务,这些任务在软件工程中非常重要。例如,堆数据结构可用于查找顺序统计信息。顺序统计对应于项目集合中的第 k 个最小(或最大)值。这在一些任务中有应用,例如快速找到一个数组的中间值。

堆数据结构也可以用于查找和跟踪数组中的最小值/最大值。这对于为客户安排优先级队列中的任务非常有用,在优先级队列中,问题花费时间最短的客户将被优先考虑。这可以缩短所有客户的平均等待时间。堆也用在图形算法中,例如用于寻找最短路径的 Djiktra 算法。这可用于基础设施规划任务,如建立道路网络、电线或输油管道。

理解如何实现堆数据结构是每个数据科学家的一项重要技能。此外,理解堆数据结构的基本应用可以使它成为跨各种软件工程应用的许多算法任务的强大工具。

堆一棵二叉树

堆化是将二叉树转换成堆数据结构的过程。要了解这是如何实现的,让我们考虑以下阵列:

array_in = [3, 5, 8, 10, 17, 11, 13, 19, 22, 24, 29]

这个数组有相应的完整二叉树:

作者创建的图像

我们可以定义一个 heapify 函数,它将数组作为输入,并将其转换为最大或最小堆。让我们考虑把这个二叉树转换成一个 max 堆。我们需要做的第一件事是找到不是叶子的最后一个节点。叶子是没有任何子节点的节点。我们看到 11、13、19、22、24 和 29 都是叶子,因为它们不指向任何子节点:

作者创建的图像

此外,从左到右读取每个树级别中的节点,我们看到最后一个非叶节点是 17。这也是最后一个节点的父节点:

作者创建的图像

我们可以通过取节点数量的一半的底值-1:

最后一个非叶节点的索引=的下限(节点数)/2–1。

在我们的示例中,有 11 个节点,因此最后一个非叶节点的索引是:

最后一个非叶节点的索引= floor of(11)/2–1 = 5.5-1 = floor of 4.5 = 4.0。

所以最后一个非叶节点的索引是 4,它的值是 17(记住我们从索引值 0 开始)。

我们想从二叉树中建立一个最大堆。我们可以通过以相反的顺序将节点堆到最后一个非叶节点[3,5,8,10,17]来做到这一点。我们以相反的级别顺序应用 heapify 操作,这意味着从右到左,在每个级别我们将每个子节点与其父节点进行比较。对于 max-heapify,如果子节点大于其父节点,则交换值。例如,我们通过将 17 与其最右边的子代 29 的值交换来开始 heapify 操作,因为子代大于父代:

作者创建的图像

然后我们移动到下一个节点,从左到右,比较 24 和 29。这满足了 max-heap 属性,因此我们接着将 22 与 10 进行比较。因为 10 在父节点上并且小于 22,所以它不满足堆属性,所以我们交换:

作者创建的图像

然后我们移动到下一个节点。因为 19 小于 22,所以它满足 max- heap,所以我们继续下一个级别。我们从 13 开始,和它的父母比较。它不满足堆属性,所以我们交换 8 和 13:

作者创建的图像

要交换的下一个节点值是 5 和 29,然后是 5 和 24:

作者创建的图像

然后我们交换 3 和 29,3 和 24,然后 3 和 17:

作者创建的图像

让我们编写一些实现这种堆化逻辑的 c++代码。让我们创建一个名为 heapify_code.cpp 的. cpp 文件。

vi heapify_code.cpp

让我们从包含开始,它允许我们写入标准输入/输出流。

#include <iostream>

让我们定义一个名为 heapify 的函数,它返回 void:

void heapify(){}

该函数将接受一个整数数组输入。我们把整数数组叫做 array_in。它还需要一个整数 subtree_root_index 作为子树根的索引。数组的大小也需要一个整数 array_size:

void heapify(int array_in[], int index, int array_size){}

接下来,我们需要在函数范围内定义一些变量。让我们初始化一个名为 maximum _ value 的变量。让我们也为左边和右边的孩子初始化变量。对于左边的孩子,索引是 2subtree_root_index +1,右边的孩子是 2subtree_root_index +2。

void heapify(int array_in[], int array_size, int subtree_root_index){int largest_value = subtree_root_index;int left = 2*subtree_root_index + 1;int right = 2*subtree_root_index + 2;}

接下来让我们添加逻辑来检查左边的子元素是否大于根元素。如果左孩子大于根,我们重新定义 maximum _ value 为左孩子。在这个逻辑中,我们还需要确保左边子元素的索引小于数组的大小:

void heapify(int array_in[], int array_size, int subtree_root_index){
…//code truncated for clarityif (left < array_size && array_in[left] > array_in[largest_value])
{
largest_value = left;
}}

接下来,我们需要添加逻辑来检查右孩子是否大于根。和前面的检查一样,如果右孩子大于根,我们将 maximum _ value 重新定义为右孩子。我们还需要确保右孩子的索引小于 array_size:

void heapify(int array_in[], int array_size, int subtree_root_index){
…//code truncated for clarityif (left < array_size && array_in[left] > array_in[largest_value])
{
largest_value = left;
}if (right < array_size && array_in[right] > array_in[largest_value]){
largest_value = right;
}}

最后,我们需要检查最大值是否等于根的值。如果不是,我们用最大值交换根的值:

void heapify(int array_in[], int array_size, int subtree_root_index){
…//code truncated for clarityif (largest_value != subtree_root_index )
{
swap(array_in[subtree_root_index], array_in[largest_value];
}}

最后我们在 maximum _ value 不等于 subtree_root_index 的条件下递归调用子树上的堆函数:

void heapify(int array_in[], int array_size, int subtree_root_index){…//code truncated for clarityif (largest_value != subtree_root_index )
{
swap(array_in[subtree_root_index], array_in[largest_value]
heapify(array_in, array_size, subtree_root_index);
}}

完整的功能如下:

void heapify(int array_in[], int array_size, int subtree_root_index){
int largest_value = subtree_root_index;
int left = 2*subtree_root_index + 1;
int right = 2*subtree_root_index + 2;if (left < array_size && array_in[left] > array_in[largest_value])
{
largest_value = left;
}if (right < array_size && array_in[right] > array_in[largest_value]){
largest_value = right;
}if (largest_value != subtree_root_index )
{
swap(array_in[subtree_root_index], array_in[largest_value]
heapify(array_in, array_size, largest_value);
}}

建堆

现在我们已经写完了 heapify 函数,我们可以写另一个函数,允许我们在给定一个输入数组的情况下构造一个堆。该函数将一个数组及其大小作为输入,并在一个 for 循环中从最后一个节点叶节点开始调用数组上的 heapify 函数。我们将该函数称为构造函数:

voidconstruct_heap(int array_in[], int array_size){}

让我们定义一个名为 last_non_leaf_node 的变量,它是 array_size/2 -1:

voidconstruct_heap(int array_in[], int array_size)
{
int last_non_leaf_node = (array_size/2) -1;
}

接下来,我们可以从最后一个叶节点开始以相反的顺序循环,迭代地将索引减 1,并使用索引的每个值调用 heapify 函数:

voidconstruct_heap(int array_in[], int array_size){int last_non_leaf_node = (array_size/2) -1;for (int subtree_root_index = last_non_leaf_node; subtree_root_index >=0; subtree_root_index-=1)
{
heapify(array_in, array_size, subtree_root_index);
}}

接下来,让我们定义一个打印函数,它将允许我们打印出堆中的值:

void print_heap(int array_in[], int array_size){cout << "Printing values at each node in heap" << endl;for (int index = 0; index < array_size; index+=1)
{
cout<< array_in[index] << endl;
}}

现在我们可以定义我们的主函数,它将作为执行 heapify、construct_heap 和 print_heap 函数的驱动程序代码。让我们定义我们之前使用的数组,array_in = [3,5,8,10,17,11,13,19,22,24,29],它有相应的树表示:

作者创建的图像

int main(){int array_in[] = { 3, 5, 8, 10, 17, 11, 13, 19, 22, 24, 29};
int array_size = sizeof(array_in) / sizeof(array_in[0]);
construct_heap(array_in, array_size);
print_heap(array_in, array_size);}

让我们编译我们的脚本:

g++ heapify_code.cpp

并运行我们编译好的脚本:

./a.out

我们应该得到以下输出:

作者截图

它的数组表示为 heap = [29,24,13,22,17,11,8,19,10,5,3],我们执行的转换如下:

作者创建的图像

这篇文章中使用的代码可以在 GitHub 上获得。

结论

堆一棵树是很重要的,因为它允许我们从堆数据结构的有利属性中获益。堆是一种基本的数据结构,具有诸如最小/最大搜索、顺序统计和查找最短路径的应用。堆数据结构可以显著加快这些算法任务的速度。当您需要从一个项目集合中重复选择最大或最小值时,这通常是有用的,优先级队列和订单统计就是这种情况。

本帖原载于 内置博客 。原片可以在这里找到https://builtin.com/software-engineering-perspectives/heapify-heap-tree-cpp?i=5350fc7a-62c7-4937-b206-20e00f021c6f&utm_source=transactional&utm_medium=email&utm_campaign=Built-In-Email

如何从 Github 语言统计中忽略 Jupyter 笔记本

原文:https://towardsdatascience.com/how-to-ignore-jupyter-notebook-from-github-language-stats-6ec7004b885a

不要让这些文件掩盖了项目中其他重要的语言

如果你和我一样是 Github 用户,你可能知道在你的库的右边有一个很棒的小部分:语言。

语言统计—作者截图

这一部分列出了项目中涉及的编程语言以及它们的使用百分比:这给出了栈和开发人员使用的不同技术的粗略概念。

如果你想知道这些数据是如何计算的,Github 的工程师们开源了一个 Ruby 库来做这项工作:它叫做语言学家

为什么这个部分甚至有用?

除了给出正在使用的编程语言的分类,这个语言统计部分还提供了一种 Github 索引您的项目的方法,通过按语言搜索的特性可以发现您的项目。

按关键字和编程语言搜索—作者截图

jupyter 笔记本和语言统计的问题

当你在一个 Python 项目中有很多笔记本时,在计算语言统计数据时会考虑到它们。由于这些文件有膨胀的元数据行数,它们通常出现在顶部,遮蔽了项目中涉及的重要语言。

下面是在我的一个项目中发生的事情:我有一个笔记本文件夹作为我的代码库的一部分,其中的文件提交给 Git 是有意义的,因为它们共享了该库的使用示例。

当 Github 编辑统计数据时,它给出了这个不切实际的细目,仅仅因为 Jupyter 笔记本不是纯文本文件,而是大量的元数据。

用户截图

解决方案💡

在稍微钻研了一下语言学家的文档后,我找到了一个快速解决方法:只需在.gitattributes文件中添加笔记本文件夹作为linguist-vendored

基本上,将这一行添加到.gitattributes并提交该文件:

notebooks/** linguist-vendored

通过这样做,Github 将在计算统计数据时忽略notebooks文件夹中的文件(这基本上适用于您想要忽略的任何类型的文件)

在推送代码之后,语言统计更新,显示 Shell、Makefile 和 Dockerfile:我用来编写脚本、打包和部署我的库的三个工具。

用户截图

仅此而已!😃

新到中?您可以每月订阅 5 美元,并解锁各种主题的无限文章(技术、设计、创业……)您可以通过点击我的推荐链接支持我

https://ahmedbesbes.medium.com/membership

Unsplashcharlesdeluvio 拍摄的照片

如何实现和评估来自 scikit-learn 的决策树分类器

原文:https://towardsdatascience.com/how-to-implement-and-evaluate-decision-tree-classifiers-from-scikit-learn-36ef7f037a78

UCL 数据科学学会研讨会 13:什么是决策树,决策树的实现,可视化和评估

吉利·斯图尔特在 Unsplash 上拍摄的照片

今年,作为 UCL 数据科学协会的科学负责人,该协会将在整个学年举办一系列 20 场研讨会,主题包括 Python(数据科学家工具包)简介和机器学习方法。每个人的目标是创建一系列的小博客文章,这些文章将概述主要观点,并为任何希望跟进的人提供完整研讨会的链接。所有这些都可以在我们的 GitHub 资源库中找到,并将在全年更新新的研讨会和挑战。

本系列的第十三个研讨会是 Python 数据科学研讨会系列的一部分,涵盖了 Sklearn 中的决策树分类器。在本次研讨会中,我们将介绍什么是决策树、实现模型、可视化模型以及评估模型。一如既往,这篇博客文章是整个研讨会的总结,可以在这里找到这里我们还将讨论什么是分类器,从模型中提取特征重要性,以及如何通过网格搜索来改进模型。

如果您错过了我们之前的任何研讨会,您可以在这里找到:

什么是决策树

决策树遵循树状结构(因此得名),其中节点代表特定属性,分支代表决策规则,叶节点代表结果。我们稍后将展示这个结构,这样你就能明白我们的意思,但你可以想象它就像你在高中数学中画的决策树之一,只是规模要复杂得多。该算法本身的工作原理是根据每个节点的不同属性分割数据,同时试图减少选择度量(通常是基尼指数)。本质上,决策树分类器的目标是根据属性分割数据,同时能够将数据准确地分类到预定义的组中(我们的目标变量)。

决策树实现

对于这个决策树实现,我们将使用来自sklearn的 iris 数据集,它相对容易理解并且易于实现。来自scikit-learn的决策树分类器的好处是目标变量可以是分类的也可以是数字的。为了清楚起见,我们使用单个的花名作为实现的类别,这使得可视化和理解输入变得容易。

有了正确格式的数据,我们可以创建决策树,这样我们就可以尝试预测不同流的分类。从scikit-learn导入必要的函数后,我们可以在限制树的范围的同时设置一个max_depth = 3来限制过度拟合的可能性。这意味着这棵树沿着一个树枝最多可以做三次分裂。这可以在我们的训练数据集上实现,如下所示:

from sklearn.tree import DecisionTreeClassifierclf = DecisionTreeClassifier(max_depth =3, random_state = 42)
clf.fit(X_train, y_train)

可视化决策树

在某些情况下,当我们的实现并不复杂时,我们可能想要理解算法是如何运行的。这是使用决策树分类器的好处之一,因为当您的数据有限或实现有限时,我们可以实际看到树是如何形成的。这可以通过两种主要方式实现:

  1. 为树形图
#import relevant packages
from sklearn import tree
import matplotlib.pyplot as plt#plt the figure, setting a black background
plt.figure(figsize=(30,10), facecolor ='k')
#create the tree plot
a = tree.plot_tree(clf,
                   #use the feature names stored
                   feature_names = feature_names,
                   #use the class names stored
                   class_names = labels,
                   rounded = True,
                   filled = True,
                   fontsize=14)
#show the plot
plt.show()

作者图片

  1. 作为基于文本的图表
#import relevant functions
from sklearn.tree import export_text#export the decision rules
tree_rules = export_text(clf,
                        feature_names = list(feature_names))#print the result
print(tree_rules)#out:
|--- PetalLengthCm <= 2.45
|   |--- class: Iris-setosa
|--- PetalLengthCm >  2.45
|   |--- PetalWidthCm <= 1.75
|   |   |--- PetalLengthCm <= 5.35
|   |   |   |--- class: Iris-versicolor
|   |   |--- PetalLengthCm >  5.35
|   |   |   |--- class: Iris-virginica
|   |--- PetalWidthCm >  1.75
|   |   |--- PetalLengthCm <= 4.85
|   |   |   |--- class: Iris-virginica
|   |   |--- PetalLengthCm >  4.85
|   |   |   |--- class: Iris-virginica

从这里我们可以看到,第一次分割是基于花瓣长度,如果一朵花的花瓣长度小于 2.45 厘米,该算法会将其识别为 Iris-Setosa(上图中的橙色框)。那些花瓣长度比这更长的花瓣则继续进一步分裂以获得更精确的分类。我们还可以看到max_depth超参数的位置,因为沿着一个分支的最大分裂数是 3,这意味着我们可以很容易地将结果可视化。

决策树评估

虽然我们可以看到模型如何根据训练数据进行训练,但我们最感兴趣的是模型如何处理看不见的数据(我们的测试数据集)。为此,我们可以对测试数据运行训练好的模型,看看它能预测什么。这可以通过以下方式实现:

test_pred_decision_tree = clf.predict(test_x)

然后,我们可以看到模型在各种方面的表现。可视化这种性能(尤其是分类)的最佳方式之一是通过混淆矩阵。通过在一个轴上显示预测值,在另一个轴上显示实际值,我们可以直观地看到预测标签和真实标签是如何匹配的。这有助于确定我们在哪里可能得到假阳性或假阴性,从而确定算法的执行情况。

#import the relevant packages
from sklearn import metrics
import seaborn as sns
import matplotlib.pyplot as plt#get the confusion matrix
confusion_matrix = metrics.confusion_matrix(test_lab,  
                                            test_pred_decision_tree)#turn this into a dataframe
matrix_df = pd.DataFrame(confusion_matrix)#plot the result
ax = plt.axes()
sns.set(font_scale=1.3)
plt.figure(figsize=(10,7))
sns.heatmap(matrix_df, annot=True, fmt="g", ax=ax, cmap="magma")#set axis titles
ax.set_title('Confusion Matrix - Decision Tree')
ax.set_xlabel("Predicted label", fontsize =15)
ax.set_xticklabels(['']+labels)
ax.set_ylabel("True Label", fontsize=15)
ax.set_yticklabels(list(labels), rotation = 0)plt.show()

作者图片

我们在这里可以看到,在测试数据集上,只有一个值未能从 Iris-virginca 类中预测出来,而算法建议这应该是 Iris-versicolor。

这很好,但是这到底意味着什么呢?当我们的数据集中有许多不同的类时,又该怎么办呢?为此,我们可以使用scikit-learn库中的内置指标来提取分类报告,以告诉我们算法的执行情况。我们可以这样做:

print(metrics.classification_report(test_lab,
                                    test_pred_decision_tree))#out:                 precision    recall  f1-score   support

    Iris-setosa       1.00      1.00      1.00        23
Iris-versicolor       0.95      1.00      0.97        19
 Iris-virginica       1.00      0.94      0.97        18

       accuracy                           0.98        60
      macro avg       0.98      0.98      0.98        60
   weighted avg       0.98      0.98      0.98        60

在这里,我们可以看到每个组和整体的精度(我们预测某个类中有多少值在该类中)、召回率(每个类中有多少值被赋予了正确的标签)和 f1 得分(精度和召回率的加权平均值)的主要指标。您使用此模型的目标是什么,以及您的实现在哪里增加了价值,这将取决于您对误报还是漏报更感兴趣,您最重视哪个指标。

这里,准确度分数是真阳性和真阴性在分配的标签总数中的分数:

总和(对角线)/总和(所有方框)

当数据中的目标变量类平衡良好时,这是一个很好的度量。

精度分数告诉我们,我们预测的某个类中有多少值实际上在该类中。这意味着它为我们提供了关于假阳性的信息(不是阳性但被标记为阳性的样本)。这被分配为:

真阳性(对角线上的数字)/所有阳性(列和)

每堂课。当您担心错误预测该类中的某个值时,这很有用。

Recall 告诉我们每个类中有多少值被分配了正确的标签。这给了我们关于假阴性的信息。对于任何类别,这等于:

真正数(对角线上的数字)/所有赋值(行和)

并且在假阴性成本高的情况下是有用的度量,例如在癌症筛查中。

最后,F1 分数是精度和召回率的加权平均值,1 为最好,0 为最差。这使用调和平均值,而不是算术平均值,因此该值更接近较小的数字。这防止了在两个参数中的一个非常高而另一个很低的情况下高估模型的性能。这在您不太关心精确度或召回率,但关心每个类的性能的情况下很有用。

为什么要使用决策树?

使用决策树的优势在于:

  • 它们很容易解释(取决于数据的大小和树的深度)
  • 他们可以通过scikit-learn处理数字和分类数据
  • 它们可以限制模型中不良预测的影响
  • 您可以提取它们的结构,以便能够可视化它们是如何工作的

然而,使用决策树也有缺点或不足之处,它们是:

  • 当一个阶级在我们的目标预测器中占优势时,他们会挣扎
  • 当允许数据无休止地增长时,它们可能会使你的数据溢出
  • 数据的微小变化可能会产生非常不同的结果

这些只是在您实现决策树时需要记住的事情,因为它们在实践中非常有用,并且可以与其他分类算法(如 k-最近邻或随机森林)一起使用,以帮助做出关于分类的决策。

因此,您可以轻松地用 Python 实现和评估决策树。在实践本身中,提供了关于分类器、评估指标、特征重要性以及如何通过调整超参数来改进模型的更多信息,这些信息都可以在这里找到。

如果您想了解我们协会的更多信息,请随时关注我们的社交网站:

脸书:https://www.facebook.com/ucldata

insta gram:https://www.instagram.com/ucl.datasci/

领英:https://www.linkedin.com/company/ucldata/

如果你想了解来自 UCL 数据科学协会和其他优秀作者的最新消息,请随时使用我下面的推荐代码注册 medium。

https://philip-wilkinson.medium.com/membership

我的其他媒体文章可在以下网址找到:

如何用 Qiskit 和 Mitiq 实现量子错误缓解

原文:https://towardsdatascience.com/how-to-implement-quantum-error-mitigation-with-qiskit-and-mitiq-e2f6a933619c

了解如何实现 Clifford 数据回归

量子机器学习要不要入门?看看 动手量子机器学习用 Python

作者图片

量子错误缓解对于挖掘当今量子计算的潜力至关重要。首先,我们今天拥有的量子位元受到环境中噪音的困扰,最终摧毁了任何有意义的计算。第二,绝不是说,我们没有足够的物理量子位捆绑成容错的逻辑量子位。

我们今天能做的最好的事情就是减少噪声对计算的影响。这就是量子误差缓解的意义所在。

最近,IBM 宣布了它的第二个量子科学奖。他们在寻找量子模拟问题的解决方案。他们想让我们用 Trotterization 来模拟一个三粒子海森堡模型哈密顿量。然而,主要的挑战是处理不可避免的噪音,因为他们希望我们在他们的 7 量子位雅加达系统上解决这个问题。

但是在我们可以在真正的量子计算机上解决这个问题之前,让我们首先看看我们如何用 Qiskit 实现一个量子错误减轻方法。在我之前的帖子中,我介绍了由 P. Czarnik 等人开发的 Clifford 数据回归(CDR)方法,Clifford 量子电路数据的误差缓解,Quantum 5,592 (2021) 。在这种最近的和有前途的误差减轻方法中,我们创建了一个机器学习模型,通过使用来自量子电路的数据,我们可以用它来预测和减轻噪声,我们可以经典地模拟量子电路。

我们使用 qi skit(IBM quantum 开发库)和 Mitiq(在量子计算机上实现错误缓解技术的 Python 工具包)。

Mitiq 为 CDR 方法提供了一个 API,它们可以很好地与 Qiskit 集成。所以,这应该是小菜一碟,不是吗?

我们先来看看 Mitiq 对 CDR 的介绍。乍一看,它们清楚地描述了我们需要做什么。这是一个四步程序:

  1. 定义一个量子电路
  2. 定义遗嘱执行人
  3. 可观察量
  4. (近克利福德)模拟器

然而,当我们仔细观察时,我们发现他们的例子使用了 Google 的 Cirq 库。

因此,我们需要修改代码以适应 Qiskit API。

定义一个量子电路

我们需要定义的量子电路代表了我们旨在解决的问题,例如 IBM 要求我们提供的哈密顿模拟。然而,我们坚持使用 Mitiq 提供的例子。这是一个两量子位电路,仅由 Clifford 门和绕 z 轴的旋转组成(𝑅𝑍).克利福德门很容易在经典计算机上模拟——这是 CDR 方法的先决条件。

下面的列表描述了 quantum 电路对 Qiskit 的修改。

这里没什么特别的事。在 for 循环中,我们在量子位上应用了一些任意的量子门。这些主要是旋转(rzrx和纠结cx)。对于 CDR 方法的应用,该电路的细节并不重要。如上所述,让我们假设它们代表了手头的问题。

与 Mitiq 的例子类似,我们多次应用一系列门来增加整个电路的长度。事实上,如果我们期待使用 Trotterization 来解决哈密顿模拟,这种结构会很方便,因为 Trotterization 建立在一系列量子门的重复上。

最后,本例的重要区别在于电路中包含的测量。在 Qiskit 中,我们需要明确指定何时“查看”我们的量子位。

定义遗嘱执行人

下一步,我们需要定义一个执行者。这是一个将我们的量子电路作为输入并返回 Mitiq QuantumResult 的函数。听起来很容易。然而,细节决定成败。

当我们查看示例代码时,我们看到它使用了从 mitiq.interface.mitiq_cirq 导入的 Mitiq 函数 compute_density_matrix。显然,它返回了密度矩阵。这是一个描述量子态的矩阵。

遗憾的是,当我们查看 Mitiq 的 API 文档时,已经没有这样的函数了。这个例子似乎有点过时了。看一下实际的源代码就可以证实这个假设。现在已经没有这个功能了。

相反,Mitiq 现在提供了四个与 Cirq 相关的函数:executeexecute_with_depolarizing_noiseexecute_with_shotsexecute_with_shots_and_depolarizing_noise

Qiskit 接口也是如此。这里有executeexecute_with_noiseexecute_with_shotsexecute_with_shots_and_noise

问题是:我们应该使用哪一个?

在 Mitiq 的例子中,他们说他们增加了单量子位去极化噪声。因此,我们当然希望创建一个带噪声的执行程序。但是,我们需要多次拍摄吗?

答案是:是的,我们有!在最初的例子中,它们返回最终的密度矩阵——一种量子状态的表示。如果我们只运行一次电路(没有镜头),我们将无法创建这样的矩阵。

所以,这是我们要用的函数:

mitiq.interface.mitiq_qiskit.qiskit_utils.execute_with_shots_and_noise(circuit, obs, noise_model, shots, seed=None)Simulates the evolution of the noisy circuit and returns the statistical estimate of the expectation value of the observable.Parameters
   circuit (QuantumCircuit) – The input Qiskit circuit.
   obs (ndarray) – The observable to measure as a NumPy array
   noise – The input Qiskit noise model
   shots (int) – The number of measurements.
   seed (Optional[int]) – Optional seed for qiskit simulator.
   noise_model (NoiseModel) –Return type float
Returns The expectation value of obs as a float.

你注意到什么了吗?对,这个函数返回一个浮点数,而不是一个密度矩阵。此外,该函数需要一个obs参数。这是一个可观察到的 NumPy 数组。我们将在下一步创造可观察的。所以,让我们把遗嘱执行人的定义推迟一秒钟。

可观察量

一般来说,可观察的东西是我们可以测量的。但是,让我们不要过多地进入物理细节。相反,让我们从概念的角度来看。

量子位是一个二维系统,如下图所示。可视化的极点描绘了基础状态|0⟩和|1⟩.箭头是量子态矢量。接近极点(基态)表示振幅,其平方是测量量子位为 0 或 1 的概率。简单地说,量子态向量越接近基态|1⟩,量子位被测量为 1 的概率就越高。

作者图片

到目前为止一切顺利。然而,量子态的振幅是复数。复数是一个二维数字,有实部和虚部,如下图所示。

作者图片

这有效地将量子位变成了我们通常表示为布洛赫球的三维结构。尽管如此,对极点的接近程度决定了测量概率。

作者图片

球体是同质的。一点特别之处都没有。代表|0⟩和|1⟩的极点的定义是任意的。我们可以在球体表面定义另外两个相对的点,并询问测量量子位元的机率。下图描绘了两个这样的点。

作者图片

实际上,这是一个我们通过整个球体的旋转指定的可观测值。旋转球体两极的点成为我们观察量子位元所得到的测量值。

Mitiq 提供了一个 API 来指定一个可观察对象。它需要一个PauliStrings的列表。这些表示布洛赫球的旋转。在 Mitiq 例子中,我们有两个量子位。第一个PauliString在两个量子位上应用 Z 门(绕 Z 轴翻转)。第二个PauliString在第一个量子位上应用绕 x 轴的旋转-1.75(这比等于𝜋(约 3.14)的圆的一半多一点)。

当我们看可观测的时候,我们可以看到它输出了复合旋转。

Z(0)*Z(1) + (-1.75+0j)*X(0)

所以,有了我们可以观察到的东西,让我们回到执行者。

定义一个执行者——再访

execute_with_noise_and_shots 函数要求可观察对象为 NumPy 数组。我们通过调用可观察对象的matrix函数来获得这种表示。

接下来,我们需要指定一个噪声模型。noise_model 告诉模拟器将哪种噪声添加到模拟中。

Qiskit 提供了噪声包来创建自定义的噪声模型。我们用它以一定的概率在单量子位和双量子位门上添加误差。这意味着,每当我们应用一个特定种类的门时,我们将以指定的概率得到一个被破坏的量子比特状态。

最后,我们需要指定我们想要运行电路的镜头数。任何超过 1000 张的照片都可以。

(近克利福德)模拟器

最后一个组件是一个无噪声模拟器。几乎和遗嘱执行人差不多。唯一的区别是它不应该有任何噪音。我们可以简单地使用execute_with_shots函数。

运行 CDR

我们准备好运行 CDR 了。我们可以原样使用示例代码的其余部分。我们只需要插入我们创建的函数。

我们首先计算无噪声结果。

ideal_measurement =  0.6259272372946627

然后,我们计算未减轻的噪声结果。

unmitigated_measurement =  0.48027121352169094

接下来,我们计算来自 CDR 的减轻的结果。

mitigated_measurement =  0.6076182171631638

最后,我们比较结果。

Error (unmitigated): 0.14565602377297177
Error (mitigated with CDR): 0.018309020131498932
Relative error (unmitigated): 0.23270440251572316
Relative error (mitigated with CDR): 0.029251035968066913
Error reduction with CDR: 87.4%.

结论

结果显示,CDR 减少了噪声引起的几乎 90%的误差。

Mitiq 帮助我们几乎开箱即用地使用 CDR。我们根本不需要费心去实现它。然而,准备使用 API 的代码有点棘手,因为这个例子似乎已经过时了。

量子机器学习要不要入门?看看 动手量子机器学习用 Python

免费获取前三章这里

如何轻松将任何 ML/DL 性能提高 10%

原文:https://towardsdatascience.com/how-to-improve-any-ml-dl-performance-by-10-easily-90dbbd01a4b3

使用神经网络智能的超参数调整教程。

在本文结束时,你将能够使用微软的 NNI 库进行超参数调整,在我看来,这是深度学习的最佳超参数优化库之一,它有一个 web 界面来可视化你的实验。

NNI 网络界面(作者)

简介

构建深度学习模型需要构建架构,架构由不同的超参数组成,如学习速率、批量、层数、层中单元数等。因此,选择正确的超参数对于获得高精度的分数是非常重要的。幸运的是,有一些策略可以找到使模型性能最大化的超参数的最佳组合。

超参数优化技术

有几种技术可以用来寻找最佳的超参数组合。我将在下面列出其中的一些。

  • 手动搜索 —我们手动改变超参数的值,并试图找到最佳组合。

建议:适用于模型太大,需要太多时间训练的情况。然而,这一过程既繁琐又耗时。通常不能保证找到最佳组合。

  • 网格搜索— 联系搜索空间中超参数的所有组合。

建议:在搜索空间较小或者模型不太大的情况下可以应用。它最终会找到超参数的最佳组合。但是,太费时间了。例如,如果我们有一个由 3 个超参数组成的搜索空间,每个超参数有 5 个搜索值,我们将得到 5 =125 个组合。

  • 随机搜索 —尝试从搜索空间中随机选择超参数。

建议:这可能会有意想不到的效果。当模型不需要太多训练,并且您有很好的计算资源时,它可以被应用。但是,在搜索空间较大的情况下,这也很耗时。

  • 树形结构 Parzen 估计器(TPE) -是一种黑盒优化技术,它根据历史测量值顺序构建模型以逼近超参数的性能。

建议:如果你的计算资源有限或者模型太大,这是最好的选择之一。它显示了令人敬畏的结果,总的来说,比随机搜索要好。

我将在我们的培训中使用 TPE 进行超参数优化。

分类问题

我这篇文章的目标不是构建一个复杂的架构,因此,为了简单起见,我将在流行的 FashionMNIST 数据集上做一个简单的分类问题,该数据集有 10 个类,我将更多地关注超参数调优。因此,我将使用 Pytorch 官方教程中的代码,稍微修改一下,然后应用 NNI。

设置

  • 打开命令行/终端

确保安装了 python。否则,安装即可。

python -V              #Windows
python3 --version      #Unix/MacoS
python -m venv hyper_env    #Windows
python3 -m venv hyper_env   #Unix/MacoS
  • 激活虚拟环境
hyper_env\scripts\activate         #Windows
source hyper_env/bin/activate      #Unix/MacOS
pip3 install torch torchvision torchaudio   #Windows/Macpip3 install torch torchvision torchaudio — extra-index-url [https://download.pytorch.org/whl/cpu](https://download.pytorch.org/whl/cpu)        #Linux
  • 安装 NNI
pip install nni

一切准备就绪后,让我们打开 Visual Studio 代码并创建四个文件。

作者照片

然后选择 hyper_env 环境的 python 解释器(Ctrl+Shift+P)

来源:https://code.visualstudio.com/docs/python/environments

注意:如果你看不到 python 解释器,按 E 进入解释器路径..手动添加并浏览(C:\ Users \ gkere \ hyper _ env \ Scripts \ python . exe)

文件

mnist _ without _ nni . py-->它使用初始超参数训练基线模型

search.py 和 mnist _ nni . py-->它搜索超参数并查看 web 界面可视化。

mnist _ bestparams . py-->具有最佳搜索超参数的最终文件。

1.具有初始超参数的模型性能(基线)

  • mnist_without_nni.py

10 个时期后的结果:准确度:77.3%,平均损失:0.649939(初始模型准确度)

2.NNI 超参数搜索

第一步

  • 搜索. py

在这个文件中,我们设置了实验的搜索空间和配置。

关于类型的说明:

  • 选择:变量值为选项之一。
  • 对数均匀:变量值根据对数均匀分布从一个范围【低,高】中抽取
  • 均匀:变量值从范围【低,高】均匀采样

关于配置的说明:

  • trial_command :在 Mac 上使用 python3,在 Windows 上使用 python
  • max_trial_number :要运行的实验数量。一般来说,TPE 需要至少 20 次热身。
  • trial_gpu_number :大于零时需要 CUDA。

第二步

创建 mnist _ nni . py-文件与 mnist_without_nni.py 相同,但有 4 行修改:

添加:

nni.report_intermediate_result(test_acc)nni.report_final_result(test_acc)params = nni.get_next_parameter()

移除:

params = {‘batch_size’: 32,’hidden_size1': 128,’hidden_size2': 128, ‘lr’: 0.001,’momentum’: 0.5}

创建这些文件后,只需运行 search.py 文件并打开 localhosthttp://localhost:8080/

一旦所有试验完成,你会得到一个实验结果列表。

实验结果(作者照片)

在该图中,显示了代表具有不同超参数优化的单独训练的试验的排序列表。

结果:找到最佳搜索超参数

params = {"batch_size": 32, "hidden_size1": 128, "hidden_size2": 256, "lr": 0.04585081360744873, "momentum": 0.5363521578821588}

超参数(作者)

调试:

  • 如果试用失败,请检查查看试用错误(试用详细信息->选择失败的试用->日志->Vie 试用错误)以查看详细的错误。
  • 如果试验成功,但默认度量没有显示数据,请检查测试集的准确性分数的数据类型,并确保它返回 float 数据类型。

3.最佳超参数模型性能

运行 mnist _ bestparams . py-->它与 mnist_without_nni.py 相同,但我只是用最佳搜索的参数交换了初始参数。

哇哦。!!!!!!!,结果令人着迷。

10 个周期后的结果:准确率: 87.5% ,平均损失:0.350102

与初始模型相比提高了 10%,从 77.3%提高到 87.5%。

结论

建立深度学习/机器学习模型具有挑战性。主要任务之一是构建一个好的架构,但是超参数也是需要考虑的重要方面。结果表明,超参数优化比初始模型提高了 10%。此外,如上所述,不同的优化技术各有优缺点。在本文中,我使用了 TPE,这是对于资源数量有限的大型模型的最佳方法之一。我喜欢 NNI 图书馆,不仅因为它有内置的算法,可以做超参数调整,而且因为它有一个很好的网络界面来可视化你的实验结果。

如果你想了解更多关于应用数据科学的知识,这里是我的新 YouTube 频道— AI Academy with Friends

https://www.youtube.com/channel/UCvlF0PPaQ2GAuqYKJT4UpJQ

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

如果你想看我即将发布的关于黑盒模型解释和更多内容的帖子,你可以关注我的 中的 来保持更新。

https://medium.com/@gkeretchashvili

我以前的文章:

如何利用 ARMA 改进时间序列分析中的 AR 预测

原文:https://towardsdatascience.com/how-to-improve-ar-predictions-using-arma-for-time-series-analysis-483b84984490

学会使用 ARMA 模型做出比 AR 模型更好的预测

努尔·尤尼斯在 Unsplash 上的照片

在我之前的一篇指南中,我们介绍了如何使用时间序列数据,使用自回归模型对未来进行预测。在本帖中,我们将尝试用另一种方法来提高我们预测的准确性。

请务必查看之前关于实现自回归模型的文章,您可以在下面的链接中找到该文章。

在那篇文章中,我们通过绘制和分析数据的 ACF 图,得出了 AR 模型的最佳阶数。对于这种方法,我们将使用 pmdarima 库来为数据集寻找最佳模型和订单。您稍后将会看到,这将意味着从 AR 模型向 ARMA 模型的转变,ARMA 模型中集成了一个移动平均组件。

数据集

我们将使用澳大利亚墨尔本市 10 年间的日最低温度的相同数据,正如我在关于自回归的文章中发现的那样。这些数据的原始记录归澳大利亚气象局所有。

一个表格的屏幕截图,包括前 4 行数据和标题—由作者创建

如果你对本指南中的编码感兴趣,那么我在 Github gist [1]中提供了数据集

代码部分

在我们开始编写任何代码之前,我首先导入所需的库,因为我是在 Google 协作笔记本上编写的,所以我将首先使用 pip 来安装我想要使用的特定版本。

pip install statsmodels==0.13.1

在另一间牢房里。

pip install pmdarima

现在,我们可以导入我们需要的库和函数,以及将数据读取到 pandas 数据框架中,并将其分成训练和测试数据。

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from pmdarima import auto_arimadf = pd.read_csv('australia_temp_data.csv', index_col='Date', parse_dates=True)df_train = df['Temp'].iloc[:-5]
df_test = df['Temp'].iloc[-5:]

在上一篇文章中,我们旨在创建一个自回归模型,只是为了尝试和了解它,因此我们创建了一个 ACF 图,它将为我们的模型提供一个 AR 阶数的指标。

在本指南中,我们将让 pmdarima 分析我们的数据,并决定哪种模型最适合我们的需求。我们可以用下面的代码做到这一点。

model = auto_arima(df_train, start_P=0, start_q=0, stepwise=True, trace=True)

这将提供以下输出(如果您设置可选参数 trace=True)

对我们的数据运行 auto_arima 的输出屏幕截图—由作者创建

这里你可以看到这个函数在尝试不同的 ARMA 模型,(注意 I 阶总是 0,因此它是 ARMA 而不是 ARIMA)。该函数的目标是最小化你在上面截图的每一行中看到的 AIC 值。

AIC 值的绝对值本身没有任何意义,但是它们相对于彼此具有意义,并且我们采用提供最低 AIC 值的一组顺序。在这种情况下,这将是一个 ARIMA(3,0,1)模型,(这实际上是一个 ARMA(3,1)模型)。

运行auto_arima的结果保存在变量model中,我们可以用它来预测未来的值。

先前 AR 模型的结果

在我们继续进行预测之前,让我们先来看看上一篇文章的结果,这样我们就有东西可以比较了。当然,你可以通过查阅那篇文章找到那些结果是如何实现的详细代码,但是为了便于阅读,我在这里也包含了一个摘要版本。这段代码延续了当前文章T3 处的代码。****

from statsmodels.tsa.ar_model import AutoRegAR_model = AutoReg(df_train, lags=22).fit()forecasts = model.forecast(5).tolist()fig = plt.subplots(figsize=(12,8))
plt.plot(forecasts, color="green")
plt.plot(df_test.tolist(), color="blue")
plt.xticks(np.arange(0,6,1))
plt.yticks(np.arange(12.5,17,0.5))
plt.legend(["AR forecasts", "Actual test values"])
plt.show()

这提供了下面的情节。

该图显示了前一篇文章中 AR 模型的预测,紧挨着实际测试值—由作者创建

使用 ARMA(3,1)模型创建新的预测

现在,让我们尝试用上面创建的新 ARMA(3,1)模型来改进这些预测。

predictions = model.predict(n_periods=(len(df_test)))

我们还可以将这些预测值绘制在测试值旁边,以直观地了解准确性。

fig = plt.subplots(figsize=(12,8))
plt.plot(predictions, color='orange')
plt.plot(df_test.tolist())
plt.xticks(np.arange(0,6,1))
plt.yticks(np.arange(12.5,17,0.5))
plt.legend(["ARMA(3, 1) predictions", "Actual test value"])
plt.show()

显示 ARMA(3,1)模型预测值与实际测试值的关系图-由作者创建

如您所见,橙色线看起来比之前图中的绿线更接近蓝色测试值。让我们一起来看一下这三行,这样会更清楚。

AR 预测和实际测试值旁边的 ARMA(3,1)预测-由作者创建

现在很明显,ARMA(3,1)预测更接近实际测试温度。为了进行数值比较,我们可以计算两个不同预测的均方误差以及数据集的平均值。

from sklearn.metrics import mean_squared_errorprint('AR model MSE', mean_squared_error(test_values, forecasts))
print('ARMA(3, 1) MSE', mean_squared_error(test_values,predictions))
print(df.Temp.mean())

打印两个 MSE 值和温度平均值的结果截图—由作者创建

从这些结果中我们可以看出,AR 模型的预测值平均与测试数据中的实际温度相差约 1.18 摄氏度,而 ARMA(3,1)模型的预测值相差约 1.01 度。

与整个数据集上大约 11.18 的平均温度相比,我认为这两个模型都做得很好。

摘要

总结本文,可以说我们通过在模型中引入 MA 分量成功地改进了对未来气温的预测。这可以通过使用 pmdarima 库的 auto_arima 函数找到最适合的模型类型及其相应的订单。

我希望你喜欢阅读这篇文章,并学到一些有用的东西!

感谢阅读。

信用

[1](数据来源经 Jason Brownlee 许可)——Jason Brownlee,用 Python 进行时间序列预测的自回归模型,机器学习掌握,可从https://machinelingmastery . com/auto regression-Models-Time-Series-Forecasting-Python/获取,2021 年 12 月 20 日。

如何通过列传播提高分层 SQL 表结构的性能

原文:https://towardsdatascience.com/how-to-improve-performance-in-a-hierarchical-sql-table-structure-with-column-propagation-3b8cacdc87a9

列传播作为分层表结构上缓慢查询的解决方案

谢尔盖·佐尔金在 Unsplash 上拍摄的照片

本文将展示在处理分层数据结构时,列传播如何成为提高查询性能的一种简单方法。

我们将通过一个基于数据驱动项目的真实场景来实现这一点,该项目涉及一个为体育行业的初创公司开发的实时数据网站。您将了解到作为分层 SQL 表结构中固有的性能问题的解决方案的列传播的所有知识。我们开始吧。

语境

我和我的团队最近为足球迷开发了一个有数百万页面的网站。该网站的理念是成为足球支持者的权威资源,尤其是在博彩方面。数据库和应用程序架构并不特别复杂。这是因为调度程序负责定期重新计算复杂数据并将其存储在表中,这样查询就不必涉及 SQL 聚合。所以,真正的挑战在于非功能性需求,比如性能和页面加载时间。

应用领域

体育行业中有几家数据提供商,每一家都为其客户提供不同的数据集。具体来说,足球行业有四种类型的数据:

  1. 履历数据:身高、身高、年龄、效力过的球队、获得的奖杯、获得的个人奖项以及足球运动员和教练。
  2. 历史数据:过去比赛的结果以及那些比赛中发生的事件,比如进球、助攻、黄牌、红牌、传球等。
  3. 当前和未来数据:当前赛季的比赛结果和这些比赛中发生的事件,以及未来比赛的表格。
  4. 直播数据:正在进行的比赛的实时结果和直播事件。

我们的网站涉及所有这些类型的数据,特别关注 SEO 原因的历史数据和支持投注的实时数据。

分层表结构

我不能与你分享整个数据结构,因为我签署了一个 NDA。与此同时,理解足球赛季的结构就足以理解这个现实世界的场景。

详细地说,足球提供商通常如下组织一个赛季中的比赛数据:

  • 季节:有起止日期,一般持续一个日历年
  • 比赛:甲 a 比赛所属。一个竞争的例子存在于一个赛季中。在这里了解更多关于足球比赛如何运作的
  • 阶段:与比赛相关的阶段(如资格赛阶段、淘汰赛阶段、决赛阶段)。每个比赛都有自己的规则,许多比赛只有一个阶段。
  • :与阶段相关联的组(例如,A 组、B 组、C 组、…)。有些比赛,如世界杯,涉及不同的小组,每个小组都有自己的团队。大多数比赛只有一个普通组。
  • :从逻辑角度对应一天的比赛。它通常持续一周,并涵盖一个小组中所有球队的比赛(例如,MLS 有 17 场主场比赛和 17 场客场比赛;因此,它有 34 匝)。
  • 两个足球队之间的比赛。

如下面的 ER 模式所示,这 5 个表代表一个分层数据结构:

用于表示足球数据的分层数据结构的 ER 模式

技术、规格和性能要求

我们在 Node.js 中开发了后端,用 Express 4.17.2Sequelize 6.10 作为 ORM ( 对象关系映射)。前端是一个用 TypeScript 开发的 Next.js 12 应用。至于数据库,我们决定选择 AWS 托管的 Postgres 服务器。

该网站运行在 AWS Elastic Beanstalk 上,前端有 12 个实例,后端有 8 个实例,目前每天有 1 到 5 千人观看。我们客户的目标是在一年内达到 6 万的日浏览量。因此,网站必须准备好在不降低性能的情况下托管数百万的月用户。

该网站应该在性能,搜索引擎优化和可访问性在谷歌灯塔测试得分 80+。此外,加载时间应该总是少于 2 秒,最好在几百毫秒的量级。真正的挑战在于此,因为该网站包含超过 200 万个页面,预渲染这些页面需要数周时间。此外,大多数页面上显示的内容不是静态的。因此,我们选择了增量静态再生方法。当一个访问者点击了一个从来没有人访问过的页面时,Next.js 使用从后端公开的 API 中检索到的数据来生成这个页面。然后,Next.js 根据页面的重要性缓存页面 30 秒或 60 秒。

因此,后端必须以极快的速度为服务器端生成过程提供所需的数据。

为什么查询层次表很慢

现在让我们来看看为什么分层表结构会对性能构成挑战。

1.连接查询很慢

分层数据结构中的一个常见场景是,您希望根据与层次结构中更高层的对象相关联的参数来过滤树叶。例如,您可能希望检索某个特定赛季的所有比赛。在这种情况下,由于叶表Game没有直接连接到Season,所以您必须执行一个查询,该查询涉及的连接数量与层次结构中的元素数量一样多。

因此,您可能最终会编写以下查询:

SELECT GA.* FROM `Game` GA LEFT JOIN `Turn` T on GA.`turnId` = T.`id` LEFT JOIN `Group` G on T.`groupId` = G.`id` LEFT JOIN `Phase` P on G.`phaseId` = P.`id` LEFT JOIN `Competition` C on P.`competitionId` = C.`id` LEFT JOIN `Season` S on C.`seasonId` = S.`id` WHERE S.id = 5

这个查询(显示在 Arctype 中)的性能会很慢

这样的查询很慢。每个连接执行一个笛卡尔积操作,这需要时间并可能产生数千条记录。因此,层次数据结构越长,性能就越差。

此外,如果您想检索所有数据,而不仅仅是Game表中的列,由于笛卡尔积的性质,您将不得不处理数千行数百列的数据。这可能会变得混乱,但这正是 ORM 发挥作用的地方。

2.ORM 数据解耦和转换需要时间

当通过 ORM 查询数据库时,您通常对检索应用程序级表示的数据感兴趣。原始数据库级表示在应用程序级可能没有用。因此,当大多数高级 orm 执行查询时,它们从数据库中检索所需的数据,并将其转换成应用程序级别的表示。这个过程包括两个步骤:数据解耦和数据转换。

在后台,来自连接查询的原始数据首先被解耦,然后在应用程序级别被转换成各自的表示。因此,当处理所有数据时,具有数百列的数千条记录成为一个小型数据集,每条记录都具有在数据模型类中定义的属性。因此,包含从数据库中提取的原始数据的数组将成为一组Game对象。每个Game对象将有一个包含其各自的Turn实例的转弯字段。然后,Turn对象将有一个组字段存储其各自的Group对象,依此类推。

生成这种转换后的数据是您愿意接受的开销。处理杂乱的原始数据具有挑战性,并且会导致代码味道。另一方面,这个在幕后发生的过程需要时间,你不能忽视它。当原始记录有数千行时尤其如此,因为处理存储数千个元素的数组总是很棘手。

换句话说,层次表结构上的普通连接查询在数据库层和应用层都很慢。

作为解决方案的列传播

解决方案是在分层结构中将列从父列传播到子列,以避免这种性能问题。我们来了解一下原因。

为什么应该在分层数据库中传播列

当分析上面的连接查询时,很明显问题在于对叶表Game应用过滤器。你必须经历整个层级。但是既然 Game 是层次结构中最重要的元素,为什么不直接添加seasonIdcompetitionIdphaseIdgroupId列呢?这就是列传播的意义所在!

通过将外键列直接传播给子列,可以避免所有的连接。现在,您可以用下面的查询替换上面的查询:

SELECT * FROM `Game` GA WHERE GA.seasonId = 5

更快的查询,如 Arctype 所示

可以想象,这个查询比原来的查询快得多。此外,它直接返回您感兴趣的内容。因此,您现在可以忽略 ORM 数据解耦和转换过程了。

注意,列传播涉及到数据复制,应该谨慎使用。但是在深入研究如何优雅地实现它之前,让我们看看应该传播哪些列。

如何选择要传播的列

您应该向下传播层次结构中较高的实体的每一列,这可能对筛选有用。例如,这涉及到外部键。此外,您可能希望传播用于过滤数据的枚举列,或者使用来自父代的聚合数据生成列,以避免连接。

列传播的三大方法

当我的团队选择列传播方法时,我们考虑了三种不同的实现方法。下面我们来一一分析。

1.创建实体化视图

我们在层次表结构中实现列传播的第一个想法是创建一个包含所需列的物化视图。物化视图存储查询的结果,并且它通常表示复杂查询(例如上面给出的连接查询)的行和/或列的子集。

对于物化查询,您可以定义何时生成视图。然后,数据库会将它存储在磁盘上,并使它像普通表一样可用。尽管生成查询可能很慢,但您可以尽量少启动它。因此,物化视图代表了一种快速的解决方案。

另一方面,在处理动态数据时,物化视图并不是最好的方法。这是因为实例化视图可能不是最新的。它存储的数据取决于您决定何时生成视图或刷新视图。此外,包含大量数据的物化视图会占用大量的磁盘空间,这可能会带来问题,并增加存储成本。

2.定义虚拟视图

另一个可能的解决方案是使用虚拟视图。同样,虚拟视图是存储查询结果的表。实体化视图的不同之处在于,这次您的数据库不将查询结果存储在磁盘上,而是将其保存在内存中。因此,虚拟视图总是最新的,用实时数据解决问题。

另一方面,数据库必须在每次访问视图时执行生成查询。因此,如果生成查询需要时间,那么涉及视图的整个过程必然会很慢。虚拟视图是一个强大的工具,但是考虑到我们的性能目标,我们不得不寻找另一个解决方案。

3.使用触发器

SQL 触发器允许您在数据库中发生特定事件时自动启动查询。换句话说,触发器使您能够跨数据库同步数据。因此,通过在层次结构表中定义所需的列并让自定义触发器更新它们,您可以轻松地实现列传播。

可以想象,触发器会增加性能开销。这是因为每次它们等待的事件发生时,您的数据库都会执行它们。但是执行查询需要时间和内存。所以,触发是有代价的。另一方面,这种成本通常可以忽略不计,尤其是与虚拟或物化视图的缺点相比。

触发器的问题是定义它们可能需要一些时间。同时,您可以只处理这个任务一次,并在需要时更新它们。因此,触发器允许您轻松优雅地实现列传播。此外,由于我们采用了列传播并使用触发器来实现它,我们已经设法满足了客户定义的性能需求。

最后的想法

层次结构在数据库中很常见,如果处理不当,可能会导致应用程序出现性能问题和效率低下。这是因为它们需要长连接查询和 ORM 数据处理,这既慢又耗时。幸运的是,您可以通过在层次中将列从父列传播到子列来避免这一切。我希望这个真实的案例研究能够帮助您构建更好更快的应用程序!

原载于 2022 年 6 月 1 日https://arctype.com

如何通过专家模型的集合提高扩散模型的性能

原文:https://towardsdatascience.com/how-to-improve-performance-of-a-diffusion-model-by-an-ensemble-of-expert-models-97e7cfd4c47f

NVIDIA 基于系综的扩散模型的全面解释和评论

在本文中,我们将介绍扩散模型领域的最新进展,称为 eDiff-I [1]。这是一个扩散模型的集合,其性能似乎优于所有其他最新技术(例如 DALL-E2 和稳定扩散模型)。本文将基于早期的概念(例如,扩散模型稳定扩散模型)。请随意查看我之前关于这些话题的帖子。

图 1:描述在不同噪声水平下训练的扩散模型集合的二叉树图(来源:作者)

简介

扩散模型(DM)已被证明在生成高度详细的语义丰富的图像方面是成功的,其取代了对抗模型的性能。这种成功的主要原因可以归因于它们在大型和多样化数据集上的良好伸缩能力。如果我们回顾最先进的技术,我们很快就会意识到,大比例的模型比手工制作的模型表现得更好。这意味着如果我们想进一步扩大扩散模型的规模,我们就必须增加模型的大小。这将成倍增加训练这种模型的内存和计算需求。它还会增加推理时间,从而使这些模型无法用于大多数应用领域。因此,扩展解决方案还必须考虑资源限制。

文本到图像的话语标记语倾向于表现出一种时间动态,从而在训练的不同阶段表现不同。而在较早时间步长的训练(即,反向扩散过程)中,当输入更接近高斯噪声时,给予文本输入优先权;然而,在后面的时间步骤中,模型的焦点转移到视觉特征,并忽略来自提示的文本输入。这意味着在最终时间步生成的图像可能不会产生文本提示所需的对象/特征的精确图像。从图 2 中可以看出,在较早的时间步骤中生成的图像更接近文本描述,但是在后来的采样中它们偏离文本太多。

图 2:在去噪的最后阶段忽略文本提示的变化,而在去噪过程的早期阶段切换时覆盖文本输入的扩散过程的描述。(来源:[1])

一个解决办法可能是培训一批专家学者,每个专家学者都专门研究生成过程中的特定阶段。这样可以更好地控制生成过程。然而,这将极大地增加集合模型的训练成本,因为每个时间步长将需要训练具有不同参数的不同降噪模型。解决这个问题的一种方法是在所有时间步训练一个具有共享权重的模型用于大量迭代,然后使用它作为集合中专家降噪模型的初始化器,该集合被训练用于较少的迭代。这是由 eDiff-I 作者使用的方法,以便缩放和改进基于扩散模型的图像生成领域的最新成果[1]。

专家组&编码器

eDiff-I 提出使用一组专家降噪器——每个专家降噪器专门用于扩散过程的特定阶段,从而提高图像生成的整体性能。此外,它还使用编码器的集合(剪辑文本、剪辑图像、T5 文本)。[1]已经观察到,使用不同类型的文本/图像编码器存在一些折衷。例如,CLIP 倾向于图像的总体外观,而忽略精细的细节(例如,对象和特征)。T5 编码器偏爱那些生成的图像,这些图像具有提示所要求的相同对象,但是它忽略了全局观点(即,在上下文中的集成)。除了文本编码器, eDiff-I 还使用一个剪辑图像嵌入编码器进行图像到图像的生成。这对于需要图像调节作为图像生成的先决条件的任务(例如,风格转换任务)是有用的。

能量&采样函数公式:

eDiff-I 是一个扩散模型,因此它遵循与其他标准扩散模型相同的能量函数。然而,作者对其进行了修改,以将文本/图像嵌入作为 denoiser 函数的一个条件。更具体地说,得分函数和降噪函数已经被定制以反映这种条件。

图 3:能量函数解释。(来源:作者)

除了能量函数,扩散过程的另一个重要部分是采样方法。扩散过程中的典型采样器由一个得分函数组成,该函数将扩散过程导向高密度数据。这样的得分函数可以通过求解一个常微分方程(ODE)【3,4】得到。 eDiff-I 遵循来自[2]的 ODE 求解和得分函数计算方法,如下图 4 所示。

图 4:得分函数公式作为 ODE 解决方案的说明(来源:作者)

降噪函数是扩散过程的关键。基于自动编码器的扩散模型使用神经网络来预测和去除输入图像中的噪声。由于输入 x = y + n 是干净信号 y 和噪声 n ~ N( 0σ 2 I )的组合,其幅度根据噪声水平σ变化很大。出于这个原因,一个常见的做法是不直接将 D θ表示为神经网络,而是训练一个不同的网络 F θ,从该网络导出Dθ(θ=xσ****Fθ)。并且为了克服噪声幅度的波动,神经网络被预处理以预测缩放到单位方差的噪声水平。然而,这在大σ时不起作用,因为网络必须仔细微调其输出,以补偿信号中已经存在的噪声。换句话说,网络误差被放大了σ倍。在这种情况下,直接预测 D 比预测 F 要容易得多。因此,更好的方法是自适应地将信号与噪声混合。在[2]中,提出了这样的自适应降噪公式,eDiff-I借鉴并定制了它自己的降噪公式。

图 5:去噪函数公式说明。(来源:作者)

降噪功能为图像生成过程中的采样提供了基础。[2]给出了采样过程的完整算法,如图 6 所示。

图 6:扩散模型的采样算法(来源:[2])

培训流程

扩散模型使用前一节中解释的去噪采样函数来生成图像。在引言中指出,这种去噪过程在去噪过程的后面的时间步骤中经常错过来自文本提示的指令。因此,提出的解决方案是生成一个专家去噪模型的集合,而不是单一的扩散模型。然而,从头开始训练所有 denoiser 模型是没有效率的,并且是对资源的浪费。因此,作者采用了一种有效的基于二叉查找树的集成训练方法。单个基本模型首先被训练 500K 次迭代,然后用于初始化二叉树中的其他模型,该二叉树探索噪声的搜索空间。在树的每一层,噪声分布被分割成两个范围段,并且在每个噪声范围上单独训练新的模型。随着树的深度增加,模型的数量也增加,从而指数地增加了计算和存储需求,因此,树仅增长到边缘,而中间层被合并以具有单个共享网络。这种策略最终在集合中产生三组模型:低噪声专家高噪声专家中噪声专家(图 1)。二叉树的早期级别的模型被训练更长时间(例如,> 100K 次迭代),并且对于树的较深级别的模型,训练逐渐减少。

浏览结果

eDiff-I 提出了一组专家去噪模型,而不是单一模型(例如 DALL-E 或稳定扩散模型)。他们证明了基准数据集上的结果优于其他扩散模型。

图 7:文本到图像生成的 eDiff-I 结果(来源:[1])。

除了文本到图像的生成之外,该模型对于其他应用也是有用的(例如,风格转换和语义地图呈现)。在语义地图绘制的情况下,它们提供了一种称为“用文字绘画”的独特解决方案,由此语义标签地图与文本提示一起输入,从而允许定制生成逼真的图像,该图像保持语义标签地图和文本提示提供的语义结构。

图 8:使用 eDiff-I 的带字绘画的示例结果(来源:[1])

最终想法

在这篇文章中,我们回顾和解释了在基于扩散模型的图像生成领域的最新进展。NVIDIA 新提出的方法( eDiff-I )似乎很强大,但是,一旦开源实现变得可用,除了内存占用之外,看到推理&微调的计算成本将是有趣的。

订阅更多内容:

https://azad-wolf.medium.com/subscribe

成为 Patreon 会员:

https://www.patreon.com/azadlab

关注推特更新:

https://www.twitter.com/@azaditech

在子栈上找到我:

https://azadwolf.substack.com

参考文献:

[1] Balaji et. al., “*eDiff-I*: Text-to-Image Diffusion Models with Ensemble of Expert Denoisers “, arXiv:2211.01324, 2022[2] Tero Karras, Miika Aittala, Timo Aila, Samuli Laine,” Elucidating the Design Space of Diffusion-Based Generative Models”, arXiv:2206.00364 [cs.CV], 2022[3] Aapo Hyvärinen, “Estimation of Non-Normalized Statistical Models by Score Matching”, The Journal of Machine Learning Research, volume 6, 2005[4] Pascal Vincent, “A connection between score matching and denoising autoencoders”, Neural Computation, Volume 23, Issue 7, 2011

如何改进递归时间序列预测

原文:https://towardsdatascience.com/how-to-improve-recursive-time-series-forecasting-ff5b90a98eeb

无需深度学习的递归方法的简单而有效的演变

半切口袋妖怪Unsplash 上拍摄的照片

当处理时间序列预测问题时,标准的基准方法是递归方法。它可以很容易地在任何机器学习模型上使用,它需要很低的假设,并且很容易解释。

递归预测包括创建目标序列的滞后特征,并在其上拟合机器学习模型。当预测未来的进一步步骤时,先前步骤的预测用于创建新的滞后特征。由于在预测时目标的未来值是未知的,因此使用之前预测的值似乎是实际值的良好近似值。

实践中的递归时间序列预测。图片由作者摘自 GitHub

在实践中,我们要求一个模型预测未来的多个时间点,这个模型只被训练预测未来的一个时间点。这可能导致次优和不受控制的预测。这就像我们在准备一场马拉松,训练自己每次训练只跑 5 公里。通过这种方式,我们可以跑完马拉松的第一段,但也有可能在比赛结束时遇到一些困难。我们假设跑前 5 公里就像跑最后 5 公里。

实践中的递归时间序列预测(紧凑方式)。图片由作者摘自 GitHub

预测时间序列的多个步骤比只预测第一步更复杂。我们应该采取适当的谨慎措施使其发挥作用,而不是希望重复上一步的预测。出于这些原因,我开发了 tspiral一个 python 包,用 scikit-learn 估值器进行时间序列预测。它提供了递归预测的一个非常有效的实现,也提供了一些很好的替代方案,这些将在本文的下一部分介绍。

递归基线

假设我们正在进行一项简单的预测任务。我们必须提前几个时间步预测一个类似正弦的信号。

模拟数据。训练测试再分配(图片由作者提供)。

乍一看,这似乎是一项容易的任务。该系列遵循一个循环模式,存在一个规则的噪音水平。让我们看看递归预测是如何工作的。

tspiral 提供递归预测非常简单。我们必须像处理受监督的表格任务一样管理数据。在我们的例子中,不需要外生特性(相反,我们可以随时通过它们)。我们可以简单地使用目标来构建模型,因为滞后特征是根据它自动构建的。

递归预测(图片由作者提供)。

根据测试数据生成的预测证实了我们的担忧。递归预测在开始的几个步骤看起来不错,但是到最后往往会消失。在第一方面,这种缓慢衰退背后的主要原因是预测误差的增加幅度,这产生了糟糕的滞后特征。另一方面,学习到的模型参数不适合长期预测

超越递归方法

作为递归方法的替代方法,我们有许多其他技术可供选择。

从最著名的一个开始,要考虑直接进场。它包括为我们想要预测的每个时间步安装一个单独的估计器。

实践中的直接时间序列预测。图片由作者摘自 GitHub

与递归预测相比,它建立了独立的估计器,专门用于预测具有不同延迟水平的目标。在我们的模拟环境中,它取得了很好的效果。预测不会随着时间的推移而消失,而且似乎会保持稳定,直到预测期结束。

直接预测(图片由作者提供)。

我们的另一个选择是堆叠方法。堆叠是机器学习中众所周知的技术。它包括根据其他估计器之前(在不同的数据分区上)生成的预测来拟合估计器。时间序列生态系统中堆叠方法的应用极其简单和自然。我们只需小心地生成预测,并在最新部分的训练数据上堆叠预测,以保持时间相关性。

实践中的堆叠时间序列预测。图片由作者摘自 GitHub

在测试数据的第一部分,我们注意到叠加的预测值和观察值之间有很大的匹配。随着时间的推移,预测失去了它的力量,趋于平缓,就像在递归场景中一样。消失场景是通过递归建模在幕后生成的,因为堆叠是基于递归预测操作的。叠加的作用是试图通过调整整个预测范围内的预测来减轻递归方法的衰退。

堆叠预测(图片由作者提供)。

我们要分析的最后一种方法是修正方法。它可以被看作是直接方法和递归方法的混合,也可以被看作是堆叠方法的一种发展。代替训练多个预测器的可能性,我们用单个模型在不同的滑动窗口训练束上生成递归预测。以这种方式生成的预测随后在时间步长级别上进行调整,以适应多个估计值。希望生成一个修正的(即修正的)最终预测。

实践中的修正时间序列预测。图片由作者取自 GitHub

校正后的预测非常好地遵循正弦模式,显示出与我们模拟场景中的直接方法一样好。

修正后的预测(图片由作者提供)。

摘要

在这篇文章中,我们研究了一些有价值的预测技术,作为经典递归时间序列预测的替代方法。他们似乎都很有前途。它们的有效性肯定与研究案例相关,并且必须被验证并与递归基准进行比较。所有这些都可以使用 tspiral 库作为标准的 scikit-learn 估算器来访问。这使我们能够像处理表格监督任务一样处理任何时间序列问题,而不需要学习新的语法,同时利用基于 scikit-learn 构建的所有工具的优势。

查看我的 GITHUB 回购

保持联系: Linkedin

如何通过内存优化提高训练绩效

原文:https://towardsdatascience.com/how-to-increase-training-performance-through-memory-optimization-1000d30351c8

充分利用 GPU 内存的技巧

alevision.coUnsplash 上拍照

优化深度神经网络(DNN)训练工作负载的运行时性能的关键之一是最大限度地利用训练实例的资源。GPU 或其他训练加速器的资源尤其如此,它们通常是训练设备中最昂贵的组件。在这篇文章中,我们将重点关注 GPU(或替代训练加速器)的内存利用率。关于培训绩效优化的更多建议,请务必查看我们的其他博客帖子(例如此处此处)。为了简单起见,每当我们提到 GPU 内存的时候,我们更泛指任何训练加速器的内存,包括 GPU、谷歌云 TPU哈瓦那高迪等。

GPU 内存优化最基本的例子是增加批量大小,以尽可能将内存利用率提高到接近 100%。一般来说(但不总是),你的整体训练吞吐量会增加。这是因为存在与每个训练步骤相关联的固定成本操作,例如 GPU 内核加载和梯度共享。这些是固定成本,因为它们不依赖于批量大小。因此,这些操作的每个样品的成本会随着批量的增加而降低。

请注意,还有其他因素,如内存对齐,可能会发挥作用,因此不能保证总吞吐量会增加。但绝对值得一试。还要记住,即使在调整训练批大小时吞吐量确实增加了,也不能保证收敛速度(作为历元数的函数)保持不变。通常,这可以通过适当调整一些优化器设置来控制(参见此处的在数据分布式培训的背景下对该主题的讨论】,但并非总是如此。作为一个极端的例子,考虑这样一种情况:批处理的大小等于整个数据集的大小。增加批量大小不会给每个训练步骤增加任何额外的信息,因此,整个训练步骤的数量不会减少。

这篇文章的重点是 GPU 内存已经被充分利用的情况,我们正在寻求在不改变模型的架构或收敛能力的情况下减少内存消耗,以便释放内存用于其他用途。有许多众所周知的降低内存消耗的技术。在本帖中,我们将回顾其中的一小部分,包括混合精度训练、激活检查点和基于零的分布式训练(使用 FSDP)。我们有意省略了一些技术,因为它们的性能损失相对较高(例如 CPU 卸载),或者缺乏通用性(例如 float8 量化——在撰写本文时)。

这篇文章将包括几个使用 py torch(1.12 版)和 tensor flow(2.8 版)的代码片段。这些实现示例不应以任何方式被视为任何官方 API 文档和/或教程的替代。特别是,我们将使用的一些 API 仍被认为是实验性的,可能会进行修订和优化。请务必了解最新最棒的内存优化 API 产品。

动机——为什么您应该关注内存优化

在这一节中,我们提供了一些优化内存利用率的情况,这意味着可以显著提高训练的运行时性能。

训练大型模型

需要优化内存利用率的一个最常见的情况是,训练模型过于庞大,以至于它们根本不适合单个 GPU。深度学习的一些最新进展依赖于极大模型的使用,这些模型的大小有数十亿个参数。训练这样的模型不是一件简单的事情,通常需要先进的模型分发策略、大量的 GPU 和足够的创造力。在过去的几年中,已经创建了许多库来解决这个独特的挑战(包括 deepspeedfairscaleGSPMD 等等)。在这些解决方案中,内存优化是一个关键因素。

值得注意的是,虽然内存优化的主题经常在大型模型训练的上下文中出现,但在其他场景中,内存优化可能非常有益。在我们看来,熟悉这篇文章中讨论的技术是很重要的,即使你不是在训练一个大型模型

增加批量

您可以增加训练批次大小的程度受到 GPU 中可用内存量的限制。你越能优化你的内存使用,你就越能释放内存来增加你的批处理大小。虽然对于大多数模型来说,大批量是一种奢侈,因为它可以增加您的整体训练量,但对于一些模型来说,大批量是至关重要的。例如,使用对比损失的模型,一种结合了大量正面和负面例子的损失,已被证明从特别大的批量中受益匪浅。

提高 GPU 性能

内存优化可以提高训练吞吐量的另一种方式是通过提高 GPU 性能。一般来说,当 GPU 在更少的内存上运行时,它需要更少的计算能力。这是优化内存使用影响 GPU 性能的最明显的方式。然而,内存优化还有其他方法可以提高 GPU 利用率。

示例-内存对齐:你的模型映射到加速器内存的方式高度依赖于组成它的张量的具体大小,这并不奇怪。批量大小、线性图层中的要素数量或卷积图层中的过滤器数量的微小变化都会对张量的映射方式产生重大影响。在大多数情况下,当 ML 工程师构建他们的深度学习模型时,他们(理所当然地)主要关心这些变化如何影响模型收敛。它们不考虑这种内存对齐问题,而是严重依赖 SW 堆栈以最佳方式将张量映射到内存。然而,有时结果映射会导致加速器计算能力的次优使用。例如,未能遵循谷歌云 TPU 编程的性能指南可能会导致大量内存填充,这相当于 TPU 计算能力的巨大浪费。调整模型参数可以改善内存对齐,减少填充量,并提高吞吐量。我们在下面展示了一个详细的例子。

希望我们已经让你相信了优化你的 GPU 内存的价值。在下一节中,我们将回顾实现这一点的几种方法。

内存优化方法

有很多技术都属于 GPU 内存优化的范畴。在这一节中,我们将重点介绍一些能够提供有意义的好处,同时又相对容易编程的工具。我们将使用流行的 timm 库,基于 PyTorch 1.12 中大约 13 亿个参数的分类模型,演示我们在玩具视觉转换器 (ViT)上讨论的方法的实现。

在下面的代码块中,我们使用标准 PyTorch 数据分布 API,分布式数据并行 (DDP)在一个伪数据集上训练我们的模型。有关 DDP 的详细信息,请参考官方文件

import time, os
import torch
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.utils.data import Dataset
from timm.models.vision_transformer import VisionTransformer# A fake dataset
class FakeDataset(Dataset):
  def __len__(self):
    return 1000000 def __getitem__(self, index):
    rand_image = torch.randn([3, 224, 224], dtype=torch.float32)
    label = torch.tensor(data=[index % 1000], dtype=torch.int64)
    return rand_image, label# build a ViT model using timm
def build_model():
  model_args ={
            "img_size": 224,
            "patch_size": 14,
            "embed_dim": 2560,
            "mlp_ratio": 4.0,
            "num_heads": 16,
            "depth": 16
        }
  return VisionTransformer(**model_args)# DDP setup
def setup(rank, world_size):
  os.environ['MASTER_ADDR'] = os.environ.get('MASTER_ADDR',
                                             'localhost')
  os.environ['MASTER_PORT'] = os.environ.get('MASTER_PORT',
                                             str(2222))
  dist.init_process_group('nccl', rank=rank,
                          world_size=world_size)# wrap the model with DDP
def wrap_model(model,local_rank):
  from torch.nn.parallel import DistributedDataParallel as DDP
  model.to(torch.cuda.current_device())
  model = DDP(model,device_ids=[local_rank])
  return model# standard training loop
def train(local_rank, world_size):
  setup(local_rank, world_size)
  torch.cuda.set_device(local_rank) dataset = FakeDataset()
  model = build_model()
  model = wrap_model(model, local_rank)
  **batch_size = 10 # per GPU batch size**
  optimizer = torch.optim.Adam(model.parameters())
  data_loader = torch.utils.data.DataLoader(dataset,
                          batch_size=batch_size, num_workers=16)
  loss_function = torch.nn.CrossEntropyLoss()
  t0 = time.perf_counter()
  summ = 0
  count =0
  for idx, (inputs, target) in enumerate(data_loader, start=1):
    inputs = inputs.to(torch.cuda.current_device())
    targets = torch.squeeze(target.to(torch.cuda.current_device()),
                            -1)
    optimizer.zero_grad()
    outputs = model(inputs)
    loss = loss_function(outputs, targets)
    loss.backward()
    optimizer.step() if torch.distributed.get_rank() == 0:
      batch_time = time.perf_counter() - t0
      print(f'step: {idx}: step time is {batch_time}')
      if idx > 1: # skip first step
        summ += batch_time
        count += 1
      t0 = time.perf_counter() if torch.distributed.get_rank() == 0:
    print(f'average step time: {summ/count}')
  dist.destroy_process_group()if __name__ == '__main__':
  gpus_per_machine = torch.cuda.device_count()
  mp.spawn(fn=train,
           args=(gpus_per_machine,),
           nprocs=gpus_per_machine,
           join=True)

我们现在将回顾一些内存优化方法,并展示如何将它们应用到上面的脚本中。

混合精度

在 PyTorch 和 TensorFlow 等流行的训练框架中使用的默认浮点类型是 float32,它使用 32 位表示。许多平台支持 1 位精度浮点。使用这些较低精度的浮点可以将浮点张量的内存利用率减半。由于在训练期间执行的绝大多数操作都是浮点操作,因此对内存节省的影响可能是显著的。同时,出于精度或性能的考虑,有些操作最好留在 float32 中。PyTorch 和 TensorFlow 都支持使用混合精度模式的选项,在这种模式下,16 位和 32 位浮点数串联使用(细节取决于实现)。有两种低精度浮点格式,float16 和 bfloat16 。Bfloat16 有许多属性使它成为机器学习的首选格式;然而,它只在相对较新的平台上受支持。

在下面的代码块中,我们演示了训练循环所需的简单更改,以便将 PyTorch 的自动混合精度 (AMP)支持与 bfloat16 一起使用。注意,使用 float16 时,需要一个额外的梯度缩放步骤。

for idx, (inputs, target) in enumerate(data_loader, start=1):
    inputs = inputs.to(torch.cuda.current_device())
    targets = torch.squeeze(target.to(torch.cuda.current_device()),
                            -1)
    optimizer.zero_grad()
    **with torch.cuda.amp.autocast(dtype=torch.bfloat16)**:
      outputs = model(inputs)
      loss = loss_function(outputs, targets)
    loss.backward()
    optimizer.step()

有关混合精度的更多信息,请务必查看 PyTorchtensor flowAPI 的文档,同时密切关注每个 API 的详细信息。另外,请看这篇强烈推荐的博文

激活检查点

在标准训练步骤的正向传递期间,所有中间激活张量都存储在存储器中,并用于计算反向传递期间的梯度更新。使用激活检查点时,只有指定激活的张量输出存储在内存中。从存储的激活检查点重新计算所有其他激活(使用适当的转发段)。这种技术以重复部分正向传递为代价来减少内存,即增加 GPU 操作的数量。这意味着使用激活检查点可能会增加您的步骤时间,从而降低您的吞吐量。!).然而,在许多情况下,通过利用释放的内存来增加批处理大小,总体吞吐量(每秒采样数)实际上可能会增加。

在下面的代码块中,我们演示了使用 PyTorch 检查点 API 来包装具有激活检查点支持的 timm 转换器块。然后,我们使用专用的 timm VisionTransformer 构造函数参数传入增强的 Transformer 块。

def build_model():
  model_args ={
            "img_size": 224,
            "patch_size": 14,
            "embed_dim": 2560,
            "mlp_ratio": 4.0,
            "num_heads": 16,
            "depth": 16
        }
  from timm.models.vision_transformer import Block
  import torch.nn as nn
  from torch.utils.checkpoint import checkpoint
  class CKPTBlock(nn.Module):
    def __init__(self, dim, num_heads, mlp_ratio=4.,
                 qkv_bias=False, drop=0., attn_drop=0.,
                 init_values=None, drop_path=0.,
                 act_layer=nn.GELU, norm_layer=nn.LayerNorm):
      super().__init__()
      self.block = Block(dim, num_heads, mlp_ratio,
                         qkv_bias, drop, attn_drop,
                         init_values, drop_path,
                         act_layer, norm_layer) def forward(self, x):
      return checkpoint(self.block,x) model_args['block_fn'] = CKPTBlock
  return VisionTransformer(**model_args)

如文档中所述,使用激活检查点可能会对依赖随机生成的变量的图层(例如,丢弃图层)和在正向传递过程中收集统计数据的图层(例如,批量规范化图层)产生影响。在采用激活检查点之前,应该仔细研究和解决这些问题。更多细节参见 FairScale 关于激活检查点的文档。

零冗余优化器()

零冗余优化器( ZeRO )指的是本文中描述的技术集合,用于优化内存利用率,以支持超大型模型的训练。在本帖中,我们将演示一种技术,通常称为 ZeRO3。

ZeRO3 是一种执行数据分布式训练的技术,它取代了标准的数据分布方案(如 PyTorch 中的 DDP 和 TensorFlow 中的 MirroredStrategy )。在标准的数据分发方案中,每个 GPU 都保留自己的模型副本。通过在所有 GPU 之间共享梯度来确保模型之间的一致性。这需要高度的冗余。ZeRO3 建议通过在所有 GPU 上分割模型来消除这种冗余。因此,每个单独的参数将驻留在单个 GPU 上,并由单个 GPU 拥有和更新,而不是所有的 GPU。与标准方案一样,完整的训练步骤将在独立的本地批处理中在每个 GPU 上执行。当 GPU 达到存储在 gpu_j 上的参数 _i 时,它将需要从 gpu_j 中提取其权重来执行所需的计算,但它随后会立即删除权重,以便它不会占用任何内存。这在向前和向后传球中都发生。一旦计算出梯度更新,GPU 需要将它们传达给它们各自参数的所有者。

N 个 GPU 上使用 ZeRO3 时,每个型号只存储该型号的 1/N 分之一。潜在的内存节省与 GPU 的数量成线性关系,不受训练批次大小的影响。特别要注意的是,ZeRO3 内存节省仅适用于多 GPU 场景。不利的一面是,ZeRO3 需要 GPU 之间多 50%的网络通信来更新参数。ZeRO3 以相对较小的网络通信增加为代价,为内存节省提供了一个实质性的机会。关于这些计算的更多细节,参见零文件

ZeRO3 的实现:zero 3 的实现有很多,包括在 deepspeedfairscale 中。在 1.11 版本中,PyTorch 发布了他们自己的 ZeRO3 实现,名为fullyshardeddata parallel(FSDP)。有关分区和 FSDP API 的更多详细信息,请参见基础高级 FSDP 教程,以及本概述

在下面的代码块中,我们演示了使用 FSDP 时如何包装我们的模型。该代码在很大程度上依赖于官方教程,详细内容请参考这些教程。该代码包括用于以混合精度和激活检查点配置 FSDP 的控件。(注意,在撰写本文时,激活检查点需要 PyTorch 的夜间版本。)

我要感谢 Less WrightHamid Shojanazeri 对使用 FSDP API 的指导。

def wrap_model(model, local_rank):
  from functools import partial
  from timm.models.vision_transformer import Block
  from torch.distributed.fsdp import (
      FullyShardedDataParallel as FSDP,
      MixedPrecision,
      ShardingStrategy
  )
  from torch.distributed.fsdp.wrap import (    
      transformer_auto_wrap_policy
  ) **mixed_prec = True
  ckpt_act = True** bfSixteen = MixedPrecision(
      param_dtype=torch.bfloat16,
      reduce_dtype=torch.bfloat16,
      buffer_dtype=torch.bfloat16,
  ) mp_policy = bfSixteen if mixed_prec else None my_auto_wrap_policy = partial(transformer_auto_wrap_policy,
                                transformer_layer_cls={Block,}) model = FSDP(model,
               auto_wrap_policy=my_auto_wrap_policy,
               mixed_precision=mp_policy,
               device_id=torch.cuda.current_device(),
               sharding_strategy=ShardingStrategy.FULL_SHARD) if ckpt_act: # requires pytorch nightly
    from torch.distributed.algorithms.\
        _checkpoint.checkpoint_wrapper import (
      checkpoint_wrapper,
      CheckpointImpl,
      apply_activation_checkpointing_wrapper
    )
    check_fn = lambda submodule: isinstance(submodule, Block)
    non_reentrant_wrapper = partial(
        checkpoint_wrapper,
        offload_to_cpu=False,
        checkpoint_impl=CheckpointImpl.NO_REENTRANT)
    apply_activation_checkpointing_wrapper(
        model, checkpoint_wrapper_fn=non_reentrant_wrapper,
        check_fn=check_fn)
  return model

如上所述,ZeRO3 只是众多模型分片技术中的一种。您可能会发现,对于您的特定目的,一种不同的模型分片方法,或者多种方法的某种组合,更加合适。其他此类方法包括流水线并行,其中一个模型被分割成连续的分片,每个分片在一个单独的 GPU 上运行;以及张量并行,其中特定的层/张量被分割到多个 GPU 上。查看这篇概述,它调查了一些技术并提出了一个选择最佳选项的标准。

实验

在 GPU 上增加批量大小(PyTorch)

为了展示我们所讨论的不同技术的价值,我们在一个 Amazon EC2 p4.24xlarge 实例(有 8 个 GPU)上运行了上面分享的 PyTorch 脚本。在下表中,我们总结了每次试验能够达到的批量大小,以及由此产生的训练速度(每秒样本数)。

GPU 上的性能结果(按作者)

虽然使用混合精度只能适度增加批量大小,但它可以显著提高训练速度。另一方面,激活检查点可以大大增加批量大小,但对训练速度来说代价很小。当结合使用 FSDP 和混合精度时,接收到最大吞吐量。当结合所有三种技术时,得到最大的批量。

请记住,根据项目的具体情况,比较结果可能会有很大差异。在得出任何结论之前,一定要进行自己的详细评估。

重要提示(承蒙Less Wright):我们在这个实验中的目标是评估不同的内存优化方法对我们最大限度地增加批处理大小的能力的影响,而不会遇到内存不足(OOM)故障。但是,您应该知道,在 PyTorch 中以这种方式最大化内存利用率有时会产生负面影响,例如内存分配失败和重试,这反过来会降低您的训练吞吐量。不幸的是,在撰写本文时,这些重试是在后台执行的,不会通知用户。如果你怀疑这可能发生在你身上,一定要看看这个教程。

增加 TPU (PyTorch/XLA)的批量

在我们的下一个实验中,我们展示了如何应用我们讨论的方法来增加云 TPU v3–8 VM上 PyTorch 模型的训练批量。在进入实验细节之前,先做一些介绍性的评论:

  1. 在 TPU 的 PyTorch 训练需要对你的剧本做一些修改。最值得注意的是,它需要 py torch/XLA python 库。你可以查看 TPU 文档了解更多细节。
  2. 在撰写本文时,PyTorch/XLA 支持低精度(16 位)浮点,但不支持 PyTorch 支持的自动混合精度(AMP)。如果您需要混合使用低精度和全精度浮点,您将需要手动应用它。
  3. FSDP 对 PyTorch/XLA 的支持在 1.12 版本中发布。尽管 torch-xla 版本提供了与 PyTorch FSDP 类似的特性集,但在撰写本文时,具体的 API 和使用流程是不同的。更多细节见 API
  4. torch-xla 中 FSDP 的使用在这个了不起的 github 项目(由 Ronghang Hu 提供)中的视觉转换器上演示,我们在实验中使用了它。

我们通过使用以下命令行参数运行上述项目中的 run_vit_training.py 脚本,训练了一个大约 8 亿参数的视觉传递:

python3 run_vit_training.py \
 --embed_dim 2048 \
 --num_heads 16 \
 --num_blocks 16 \
 --batch_size 256 \
 --log_step_interval 1\
 --fake_data\
#--run_without_fsdp\
#--no_grad_ckpt\

我们使用 run_without_fsdpno_grad_ckpt 标志来分别控制 fsdp 和激活检查点的使用。低浮点精度设置是通过 XLA _ 使用 _BF16 环境变量控制的。

结果,包括我们能够达到的批量大小和由此产生的产量,可以在下表中找到。

TPU 的绩效结果(按作者)

我们再次警告不要从这些结果中得出任何关于你自己项目的结论。如前所述,我们可以看到内存优化技术非常有效。使用 bfloat16 不仅可以增加批量大小,还可以提高训练吞吐量。ZeRO3 和激活检查点为增加批量大小提供了进一步的机会,而总体吞吐量的成本适中。

非常感谢 Vaibhav Singh 关于在云 TPU 上使用 FSDP 的指导。

改进 TPU 上的内存对齐(TensorFlow)

在这个基于 TensorFlow 的实验中,我们展示了使用混合精度对 TPU 记忆比对和模型训练速度的影响。

在下面的代码块中,我们定义了一个简单的卷积模型,该模型被训练来对公共的 flowers 数据集执行分类。关于在云 TPU 上构建和运行 TensorFlow 模型的详细信息,请查看官方教程以及这篇博文

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras import mixed_precision**local_batch_size = 64 # 128** batch_size = 8*local_batch_sizeimage_size = 331
n_layers = 7
**n_filters = 64****# Uncomment to use mixed
#mixed_precision.set_global_policy('mixed_bfloat16')**tpu = tf.distribute.cluster_resolver.TPUClusterResolver()
tf.config.experimental_connect_to_cluster(tpu)
tf.tpu.experimental.initialize_tpu_system(tpu)
strategy = tf.distribute.TPUStrategy(tpu)with strategy.scope():
  inputs = keras.Input(shape=(image_size,image_size,3), 
                       name='frame')
  x = layers.Conv2D(n_filters, 3, activation='relu', 
                    padding='same', name=f'conv_0')(inputs)
  for i in range(1,n_layers):
    x = layers.Conv2D(n_filters, 3, activation='relu', 
                      padding='same', name=f'conv_{i}')(x)
  x = layers.Flatten()(x)
  x = layers.Dense(5, name='dense_logits')(x)
  outputs = layers.Activation('softmax', dtype='float32', 
                              name='predictions')(x)
  model = keras.Model(inputs=inputs, outputs=outputs)
  model.compile(loss='categorical_crossentropy',
                  optimizer='adam')def parse_tfrecord(example):
  features = {
    "image": tf.io.FixedLenFeature([], tf.string),
    "class": tf.io.FixedLenFeature([], tf.int64),
    "one_hot_class": tf.io.VarLenFeature(tf.float32),
  }
  example = tf.io.parse_single_example(example, features)
  decoded = tf.image.decode_jpeg(example['image'], channels=3)
  normalized = tf.cast(decoded, tf.float32) / 255.0
  image_tensor = tf.reshape(normalized, [image_size,image_size, 3])
  one_hot_class = tf.reshape(tf.sparse.to_dense(
                                    example['one_hot_class']), [5])
  return image_tensor, one_hot_classp = 'gs://flowers-public/tfrecords-jpeg-331x331/flowers00-230.tfrec'
dataset = tf.data.TFRecordDataset([p],  
  num_parallel_reads=tf.data.AUTOTUNE)\
  .map(parse_tfrecord, num_parallel_calls=tf.data.AUTOTUNE)\
  .batch(batch_size).repeat().prefetch(tf.data.AUTOTUNE)model.fit(dataset)

请注意,在上面显示的脚本中,我们将每层的过滤器(通道)数量设置为 64,并将本地批处理大小设置为 64。如文档中所述,TPU 会将通道大小或批量大小填充为可被 128 整除的数字。因此,我们可以预期这些张量的分配会导致 2 倍的填充开销。

下图显示了使用云 TPU 分析器捕获的填充(蓝色)和未填充(红色)TPU 内存利用率。

TensorBoard 中的 TPU 内存配置文件(作者)

正如所料,填充开销很大,大约是 1.63 倍,相当于近 40%的计算浪费。这个问题最简单的解决方案是将本地批处理大小加倍到 128。不幸的是,在 TPUv3 上运行时,这导致了 TPU OOM 异常。这就是混合精度来拯救。通过将脚本配置为使用混合精度,我们能够减少内存占用,从而允许增加批处理大小。这不仅减少了填充开销,还将训练吞吐量提高了 3 倍以上。

下图显示了应用混合精度并将本地批处理大小加倍后的内存配置文件:

TensorBoard 中的 TPU 内存配置文件(作者)

实验结果总结在下表中:

TPU 的绩效结果(按作者)

摘要

要在现代深度学习领域取得成功,需要熟练掌握各种工具,以应对与优化使用培训资源相关的各种挑战。在这篇文章中,我们回顾了几种强大的技术,用于优化你的训练工作负载的 GPU 内存利用率。我们表明,这些技术不仅能使你显著扩大批量,还能使你的训练量显著增加。

如何用 Python 中的 Bulk API 索引 Elasticsearch 文档

原文:https://towardsdatascience.com/how-to-index-elasticsearch-documents-with-the-bulk-api-in-python-b5bb01ed3824

了解有效地对大量文档进行索引的不同方法

图片由 PublicDomainPictures 在 Pixabay 拍摄

当我们需要创建一个 Elasticsearch 索引时,数据源通常是不规范的,不能直接导入。原始数据可以存储在数据库、原始 CSV/XML 文件中,甚至可以从第三方 API 获得。在这种情况下,我们需要对数据进行预处理,使其能够与批量 API 一起工作。在本教程中,我们将演示如何用简单的 Python 代码从 CSV 文件中索引 Elasticsearch 文档。本地的 Elasticsearch bulk API 和来自helpers模块的 API 都将被使用。您将学习如何在不同场合使用合适的工具来索引 Elasticsearch 文档。

准备

像往常一样,我想提供建立一个演示系统和环境的所有技术细节,您可以在其中直接运行代码片段。自己运行代码是理解代码和逻辑的最佳方式。

请使用此[docker-compose.yaml](https://gist.github.com/lynnkwong/a1e3bfdd6b25c98baab525afb25ac2f6#file-401fd3fff829-docker-compose-1-yaml)通过 Docker 设置一个本地的 Elasticsearch 服务器。要了解如何在 Docker 上运行 Elasticsearch 和 Kibana,请查看这篇文章

然后我们需要创建一个虚拟环境并安装 Elasticsearch Python 客户端库,其版本与 Elasticsearch Docker 映像的版本兼容。我们将安装最新的版本 8 客户端。

入门 Elasticsearch 最好用最新版本。另一方面,如果你想将你的 Elasticsearch 库从版本 7 升级到版本 8,请看看这篇文章,这很可能会为你节省很多代码更新的精力。

用 Python 创建索引

我们将创建相同的latops-demo索引,如本文中的所示。然而,语法会有所不同,因为我们在这个例子中使用的是 Elasticsearch 8。首先,我们将使用 Elasticsearch 客户端直接创建一个索引。此外,settingsmappings将作为顶级参数传递,而不是通过body参数传递,如本文所解释的。

配置可以在这里找到,创建索引的命令是:

现在索引已经创建好了,我们可以开始向它添加文档了。

使用原生 Elasticsearch 批量 API

当你有一个小数据集要加载时,使用原生 Elasticsearch [bulk](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk-api-request) API 会很方便,因为语法与原生 Elasticsearch 查询相同,后者可以直接在开发控制台中运行。你不需要学习任何新的东西。

将要加载的数据文件(作者创建的虚拟数据)可以从此链接下载。将其另存为laptops_demo.csv,将在下面的 Python 代码中使用:

注意,我们使用csv库方便地从 CSV 文件中读取数据。可以看出,原生批量 API 的语法非常简单,可以跨不同语言使用(包括开发工具控制台),如官方文档所示。

使用批量助手

如上所述,原生bulk API 的一个问题是,所有的数据在被索引之前都需要被加载到内存中。当我们有一个大的数据集时,这可能是有问题的和非常低效的。为了解决这个问题,我们可以使用 bulk helper,它可以从迭代器或生成器中索引 Elasticsearch 文档。因此,它不需要先将所有数据加载到内存中,这在内存方面非常有效。然而,语法有点不同,我们很快就会看到。

在我们使用 bulk helper 索引文档之前,我们应该删除索引中的文档,以确认 bulk helper 确实能够成功工作:

然后,我们可以运行以下代码,用 bulk helper 将数据加载到 Elasticsearch:

事实上,代码比使用原生的bulk API 更简单。我们只需要指定要索引的文档,而不是要执行的操作。从技术上来说,你可以用_op_type参数指定其他动作,比如deleteupdate等,虽然这些并不常用。

特别是对于 bulk helper,会创建一个生成器来生成要索引的文档。请注意,我们应该调用该函数来实际创建一个生成器对象。使用生成器,我们不需要首先将所有文档加载到内存中。相反,它们是动态生成的,因此不会消耗太多内存。如果您需要更细粒度的控制,您可以使用[parallel_bulk](https://elasticsearch-py.readthedocs.io/en/master/helpers.html#elasticsearch.helpers.parallel_bulk),它使用线程来加速索引过程。

在这篇文章中,介绍了用 Python 批量索引文档的两种不同方法。分别使用本机批量 API 和批量助手。前者适用于不消耗大量内存的小数据集,而后者适用于加载量很大的大数据集。有了这两个工具,您可以方便地为各种数据集在 Python 中索引文档。

相关文章:

如何从 Azure 数据湖获取和使用数据

原文:https://towardsdatascience.com/how-to-ingest-and-consume-data-from-azure-data-lake-e66b56406b08

摄入/消费模式分析,包括三角洲湖 PoC

克林特·王茂林Unsplash 上拍摄

1.介绍

许多公司考虑建立一个企业数据湖。这个想法是将数据存储在一个集中的存储库中。数据湖的主要利益相关者是以下两个实体:

  • 数据生产者:接收数据到数据湖的实体。这通常是指不直接从数据湖中获利的实体,他们更喜欢一种无需太多开销的简单数据获取方式(类似于“一劳永逸”)
  • 数据消费者:使用数据创造商业价值的实体。这通常是从数据湖中获益最多的实体,并且更喜欢无需太多返工就可以轻松使用数据(数据被正确分区,而不是许多小文件,等等)

在这篇博文中,第 2 章讨论了四种不同的数据摄取模式。随后,第三章阐述了两种消费模式。在第 4 章中,使用 ADF 和 delta lake 讨论了使用 git repo [adf-deltalake-ingestion-consumption](https://github.com/rebremer/adf-deltalake-ingestion-consumption)的概念验证,另请参见下图。最后,在第五章得出结论。

1.建筑概念验证—作者图片

2.数据生产者:摄取模式

在本章中,使用以下两个维度来区分四种类型的摄取模式:

  • 原始数据与日终聚合:如果使用原始数据,所有源数据都将被接收到目标中。如果使用日终,源数据将以有意义的完整形式聚合到目标
  • 快照与增量:在使用快照的情况下,所有源数据每天都被接收到目标中。在使用增量情况下,只有变异的源数据被接收到目标中。

在本章的剩余部分,我们将讨论这四种模式,它们是上述两个维度的组合。为了进一步阐明,使用了一个示例数据集,其中在第一天生产卡 1 和 2,然后在第二天在卡 1 上完成两个卡交易,见下文。

2.0.示例数据集

在接下来的段落中,我们将从正反两方面讨论这些模式。

2.1 模式 P1:原始数据-快照

在快照模式中,每天都发送完整的原始数据集。对于上面的数据集,这意味着第 1 天和第 2 天的数据如下。

2.1 .模式 P1:原始数据—快照

利弊分析如下:

  • (pro)数据生产者最容易采用的模式;只需要进行数据转储,而不需要跟踪更改
  • (不)对大型数据集不可行;每天发送数据集的成本很高。大型数据集也会影响性能(复制时间)。备份也是如此。
  • (缺点)数据消费者需要跟踪变化。由于数据消费者对数据的了解通常比数据生产者少,这很容易出错。当数据被复制到消费者自己的环境中时,这尤其具有挑战性(如果不进行复制,而是使用数据虚拟化,delta lake 可以提供帮助)

2.2 模式 P2:原始数据—delta

在增量模式中,插入新数据并更新现有数据。对于不可变的数据集,总是会插入新数据,因为不会发生更新。如果数据集是可变的,那么可以进行更新。在这种情况下,关键是源和目标中都有一个唯一的 ID,以便可以匹配数据。对于示例数据集,模式 2 可以如下应用(仅插入):

2.2.模式 P2:原始数据-增量

利弊分析如下:

  • (亲)更高效的模式。发送大型数据集没有成本,性能可能会更好,复制大型数据集时出错/超时的可能性更小。
  • (缺点)数据消费者必须能够使用所有以前的数据增量。如果缺少一个增量,数据集就会损坏。
  • (专业)数据消费者可以在自己的环境中轻松识别变更并进行更新。三角洲也可以通过 ADF 数据流和三角洲湖泊轻松处理。

2.3 模式 P3:一天结束—快照

在一天结束时的快照模式中,目标不是同步原始数据源和数据接收器。相反,会在一天结束时创建并发送一个聚合。这可能是因为以下原因:

  • 消费者只对最终结果感兴趣(而对导致这个最终结果的 N 个突变不感兴趣)

对于示例数据集,消费者可能只对卡的 total_amount 感兴趣,见下文。

2.3.模式 P3:一天结束-快照

利弊分析如下:

  • (不利)由于消费者只能获得汇总数据,因此会发生数据丢失。
  • (pro)数据模式可能更有效,例如,如果数据消费者只对最终结果感兴趣,而对导致最终结果的 N 个突变不感兴趣。

2.4 模式 P4:一天结束— delta

模式 4:一天结束—增量几乎类似于 2a 一天结束—快照,但只发送突变的数据。对于示例数据集,这意味着:

2.4.模式 P4:一天结束-快照

模式 3 和模式 4 的利弊分析基本相同。唯一的区别是,在聚合仍然很大的情况下,增量可能更有效。

2.5 结论

这四种模式各有利弊。然而,对于企业数据湖的标准化来说,使用模式 P2:原始数据—增量作为缺省值可能是个好主意。原因如下:

  • 当所有原始数据从源发送到目标时,不会发生数据丢失。生产者很难预测消费者需要什么样的聚合。相反,消费者可以自己决定他们需要什么样的聚合。数据湖中的多个区域也有所帮助,其中一个着陆区域用于接收所有原始数据,一个瓶装区域用于创建多个聚合以供使用
  • 增量是一种更具成本效益的模式,因为需要拷贝的数据较少。对于大型数据集,增量甚至可能是唯一可行的解决方案。

3.数据消费者:消费模式

在本章中,两种不同的消费模式讨论如下:

  • 复制数据:消费者将数据从数据湖复制到他们自己的环境中
  • 虚拟化数据:消费者直接使用数据湖中的数据

在接下来的两段中,我们将讨论每种消费模式的利弊。

3.2 模式 C1:虚拟化数据

在数据虚拟化模式中,消费者直接在数据湖上查询,数据不会复制到他们自己的环境中。

  • (亲)单一来源的事实,没有重复的数据创建
  • (亲)消费者容易介入的模式。如果消费者没有太多的技术知识,只想创建一些(Power BI)报告,这一点尤其如此
  • (支持)Delta lake 可用于简化使用 SQL 对存储帐户的查询
  • (不利)对于有强烈性能需求(SLA)的团队不可行
  • (缺点)将企业数据湖数据与不属于数据湖的数据(例如,位于消费者自己的 SQL 环境中的数据)连接起来可能很困难

3.2 模式 C2:复制数据

在复制数据模式中,消费者将数据从企业数据湖卸载到自己的环境中。

  • (赞成)消费者完全控制数据。如果客户有严格的性能要求(为 24x7 网站提供服务)或严格的 SLA(为数据湖提供服务的团队可能无法在凌晨 03:00 回答问题),这一点尤为重要
  • (缺点)复制可能需要很长时间,尤其是当大型数据集必须复制到消费者自己的环境中时
  • (缺点)消费者需要具备技术知识来设置自己的环境(ADF、数据库、网络等)。

3.3 结论

这两种模式各有利弊。然而,对于企业数据湖的标准化,使用模式 C1:默认虚拟化数据可能是个好主意。这可以解释如下:

  • 防止了数据不必要的复制,并且是最具成本效益的。
  • 还可以利用 Delta lake 来简化数据消耗,这将在下一章中详述。
  • 如果使用了 delta lake,而消费者仍然希望将数据复制到自己的环境中,则可以使用 ADF 从 delta lake 复制数据

4.ADF、Delta Lake 和 Spark:概念验证

在本章中,使用以下体系结构构建概念验证:

  • 数据生产者:来自 SQLDB 的数据使用流向 delta lake 的 ADF 数据流获取。使用上面讨论的四种模式(原始数据与聚合数据、完整快照与增量增量)获取数据
  • 数据消费者:一旦数据被接收到 delta lake,消费者就可以使用 Databricks 和 Synapse 笔记本使用 Spark 查询数据。如果消费者想要将数据复制到自己的环境中,则创建两条 ADF 管道,可以将快照或最新增量复制到自己的环境中

另请参见下图:

4.建筑概念验证—作者图片

项目可以在 git repo [adf-deltalake-ingestion-consumption](https://github.com/rebremer/adf-deltalake-ingestion-consumption)中找到。为运行 PoC 执行以下步骤:

  1. 替换变量并运行[scripts/deploy_resources.sh](https://github.com/rebremer/adf-deltalake-ingestion-consumption/blob/main/scripts/deploy_resources.sh)来部署 ADF 和 deltalake。
  2. 运行不同的生产者管道将数据接收到三角洲湖
  3. 消费者类型 1:创建一个 Databricks 工作区或 Synapse 工作区,并运行[notebooks](https://github.com/rebremer/adf-deltalake-ingestion-consumption/tree/main/notebooks)来查询 delta lake 上的数据
  4. 消费者类型 2:运行消费者管道,将数据消费到自己的存储帐户

5.结论

许多公司考虑建立一个企业数据湖。数据湖的主要利益相关者是数据生产者和数据消费者。数据生产者通常在寻找一种轻松获取数据的方式,而数据生产者是从数据中创造商业价值的实体。在这篇博文中,作者提出了以下观点:

  • 生产者应该将原始数据存储到数据湖中,并在增量中完成此操作。基本原理是原始数据可防止数据丢失,增量数据具有成本效益且可扩展
  • 消费者应直接从数据湖中查询数据,并在那里建立数据产品。基本原理是这样可以防止数据重复,并且具有成本效益。可能的例外是,当消费者需要更高的性能/更高的 SLA 时(例如,为 24x7 网站提供服务),可以将数据复制到自己的环境中
  • Delta lake 可以帮助消费者轻松查询数据,而 Data Factory 支持 delta as sink,可以帮助生产者以 Delta lake 格式自动添加数据。这在这次 git 回购 : [adf-deltalake-ingestion-consumption](https://github.com/rebremer/adf-deltalake-ingestion-consumption)中得到了实践

如何使用 Flask-SQLAlchemy 将虚拟数据插入数据库

原文:https://towardsdatascience.com/how-to-insert-dummy-data-into-databases-using-flask-sqlalchemy-9c59efab4527

通过构建您的烧瓶项目

Flask 是一个伟大的 python web 框架,因为它极其轻量级易于设置灵活。许多网站,包括网飞、Airbnb 和 Reddit 等热门网站,都是使用 Flask 构建的。

Flask 的灵活性部分是由于这个框架的核心是非常基础的。这个包只提供了一些基本的功能,比如路由、渲染模板和部署应用程序。为了获得更强大的功能,Flask 提供了一些扩展建议,比如用于用户会话管理的flask-login、用于创建 web 表单的flask-wtf和用于数据库管理的flask-sqlalchemy,正如标题所示,我们将在本文中讨论这些。

然而,这种灵活性的一个缺点是,有时初学者可能不知道实现某个功能的最佳实践。虽然有许多优秀的教程详细介绍了如何添加各种扩展来加速开发过程,但有时会有某些功能被遗漏。

特别是在自己开发网站的时候,我发现找不到任何满足我使用 Flask-SQLAlchemy 插入哑数据要求的教程。因此,当我最终发现这个问题时,我认为写一篇文章来分享我所面临的困难以及我最终是如何解决它们的会很好。但首先,我们来介绍一下 Flask-SQLAlchemy。

Flask-SQLAlchemy 是一个 Flask 扩展,它为 Flask 应用添加了对 SQLAlchemy 的支持。SQLAlchemy 是一个对象关系映射器,它基本上允许我们将 SQL 表视为 python 类,将这些表中的行视为这些类的实例。它的美妙之处在于,我们可以为 CRUD 操作编写 python 代码而不是 SQL 代码,而且无论我们最终使用什么样的数据库,我们都不需要修改这些代码!

你可能想知道,当我们已经有 SQLAlchemy 时,为什么还要使用 Flask-SQLAlchemy。事实上,有可能同时使用烧瓶和 SQLAlchemy,如这里的所示。然而,Flask-SQLAlchemy 的主要优势在于,它简化了完成像建立数据库连接这样的常见任务所需的代码量,并且它可以很好地与任何 Flask 应用程序集成。

文章中指出的主要缺点是在 Flask 应用程序之外加载数据变得有些棘手。然而,我发现这只是当 Flask 项目没有正确构建时的问题。一个简单的重构可以很容易地让我们编写一个外部脚本来加载数据,并有许多其他的好处,稍后将简要讨论。

事不宜迟,我将首先演示当 Flask 项目没有正确构建时所面临的挑战,然后我将向您展示我发现的构建项目的最有效的方法。这个项目的代码可以在这里找到。

注意:这不是一个完整的教程,所以我假设读者对 Flask 和 Flask-SQLAlchemy 有基本的了解。好的教程可以在这里 找到

为了演示如何在 Flask 应用程序之外插入虚拟数据,我将使用一个非常简单的只有一个视图的应用程序。由于大多数应用程序将处理用户帐户,其详细信息存储在数据库中,我将创建一个应用程序,在主页上显示所有用户的详细信息,如下所示:

每个用户都存储在一个由models.py中的User类定义的用户表中,还有一些我们需要的方法,比如创建新用户和获取显示在主页上的用户详细信息。

不可取的做事方法

我发现许多教程的问题是,它们经常把大部分(如果不是整个应用程序)放在一个文件中。我的意思是,他们将从同一个文件中初始化应用程序、创建视图和运行服务器:

项目结构非常简单,如下所示:

/project
  main.py
  models.py
  database.db
  create_users.py
  /static
    css
      style.css
  /templates
    users.html

虽然这可能很快很容易,但是随着项目变得更大更复杂,这个main.py文件将变得越来越难以维护。

当我们想在数据库中插入虚拟数据来测试我们的应用程序时,我们也会遇到一个很大的挑战。当然,我可以将创建更多用户的代码放在main.py中,并在app.run()之前运行:

然而,每次我们想创建一个新用户时,我们都必须重启服务器,用一个单独的文件来创建新用户更有意义。

不幸的是,如果我们试图这样做:

我们得到一个错误,因为models.pymain.py进口,T3 也从models.py进口!

做事情的明智方法

确保加载外部数据时出现最小问题(以及其他开发问题)的最佳方式是拥有一个良好的项目结构,允许灵活性模块化。我建议采用类似如下的结构:

/project
  main.py
  /src
    __init__.py
    config.py
    /users
      routes.py
    /models
      models.py
    /database
      database.db
      create_users.py
    /static
      css
        style.css
    /templates
      users.html

现在,我将介绍项目的重要部分,让您大致了解不同部分是如何协同工作的。

init。py,main.py,config.py

__init__.py是创建你的应用程序的地方,以及它的配置和像 Flask-SQLAlchemy 这样的扩展的添加。您可能会注意到,我们不是先创建应用程序,然后将应用程序传递给SQLAlchemy构造函数(这在许多教程中都有),而是全局定义SQLAlchemy对象,然后在init_app()函数中初始化它。然后我们在app.app_context()中运行db.create_all()函数。技术细节超出了本文的范围,但是app_context()允许我们稍后使用外部脚本向数据库添加数据。

main.py导入init_app()功能,初始化应用程序,并运行它。这是您要运行以启动服务器的文件。

config.py将配置定义为一个类,由__init__.py导入。这很有用,因为我们可以为不同的用途创建不同的配置,例如开发、测试和生产,使用环境变量轻松地在它们之间切换。例如,我们可能使用 Sqlite 数据库(database.db)进行开发,但是如果我们想要在生产服务器上部署,我们可以使用引用 Postgres 数据库的生产配置。

routes.py,create_user.py

routes.py是我们定义主页视图的地方,该视图只显示一个包含我们用户详细信息的表格。我们使用蓝图,它允许更多的模块化应用。

create_user.py真是我们一直在等着看的。这是我们使用脚本自动将数据插入数据库的地方,而不必运行应用服务器。我们导入了init_app()函数和User类,并使用app_context()来创建新用户!

瞧啊。没有错误。

结论

总之,我向您展示了一个更好的项目结构如何允许我们创建一个外部脚本来使用 Flask-SQLAlchemy 将虚拟数据插入到数据库中。虽然这可能需要更多的时间来设置,但从长远来看,其好处绝对是值得的。例如,通过使用蓝图,我们可以分离应用程序不同部分的逻辑,从而使代码更易于阅读和维护。此外,如果我们想为我们的应用程序添加一个具有独特逻辑的新部分,我们可以在一个新文件中创建一个新的蓝图,而不是将我们所有的代码都放在同一个文件中。或者,如果我们想在数据库中创建一个新表,我们可以在一个单独的文件中定义一个新模型,以及数据库的逻辑。

如何在 Windows 上安装中央轨道

原文:https://towardsdatascience.com/how-to-install-center-track-on-windows-10a109ef7f75

最先进的姿态估计,内置跟踪器触手可及

CenterTrack 的检测。雷尼尔·里道在 Unsplash 上拍摄的照片

最近,我受雇开发一个需要实时姿态估计的 MVP。前几年,占主导地位的技术是 CMU 的 OpenPose,尽管有点麻烦,但一旦你设法正确设置,它就能很好地工作。备选方案包括 CenterNetAlphaPosePoseNet 。总的来说,所有这些技术都缺少内置的跟踪器。快进到 2020 年,CenterNet 背后的同一批作者推出了center track——一个姿势估计网络,包括跟踪作为其问题公式化的一部分。

对于门外汉来说,追踪就是将帧连接起来,创造一个历史。每当我们检测到一个人,我们就给它一个 ID,在所有后续帧中,每当我们看到这个人,我们就应该给它相同的 ID。换句话说,跟踪确保我们知道视频中谁是谁。例如,假设你有一个监控摄像头发现了一个罪犯。追踪器让我们可以查询这个人在视频中出现的时间和地点。

作为参考,CenterTrack 中的追踪器是基于数据关联的极简在线追踪器,很像排序。简单地说,它只使用过去和现在的数据(而不是未来的)。此外,它将其自身限制为仅使用过去检测的位置/姿态来建立先前和当前帧姿态之间的相似性矩阵。因此,没有使用图像/视觉特征。最后,分配算法将先前姿态的 id 与当前姿态进行匹配。默认情况下,它使用贪婪的分配策略。

与以前的方法相比,使用 CenterTrack 的主要优势除了其更高的准确性之外,还在于不必滚动您的跟踪器实现或依赖 OpenCV 的缓慢且过时的跟踪 API。此外,与 OpenPose 不同,它是基于 Python 的,并获得了麻省理工学院的许可。

关于限制,尽管在姿势估计方面是最先进的,但它的跟踪器对你来说可能有点太小了,所以你可能仍然想在它上面滚动一些自定义跟踪作为备份。例如,作为一个基于关联的跟踪器,它在分配 id 时不使用视觉信息。因此,它不能处理闭塞或重入。

在 Windows 上运行。

源代码仅适用于 Linux。然而,我们可以带着一点爱在 Windows 上运行它。在这里,我将列出我为使它工作所采取的步骤以及它们的基本原理。我将坚持使用这种格式,为您提供自己处理任何问题的工具,因为移植库充其量只是一种黑客行为。

总结:幸运的是,代码库并不严重依赖于 Linux 特性。大部分工作是为 Windows 端口( DCNv2 )替换 Linux 依赖项,并在我们的系统中获得 Python (3.8)、CUDA (11.1)和 PyTorch (1.8)的正确版本。自始至终,我们混合使用 conda 和 pip 命令来安装所有必需的依赖项。

免责声明:将知识库移植到 Windows 后,我只用过它进行推断(网络摄像头和视频)。我并不认为这一过程完全适用于定制数据集或计算数据集指标的培训。

我们开始吧:

第一步:使用 Python 3.8 构建 conda 环境。你爱怎么叫都行。不要忘记激活它!

conda create -y --name centertrack python=3.8

conda activate *centertrack*

第二步:获得合适的 CUDA 工具包(11.1),一些加速 API,Git,和一个工作的 C++编译器。

conda install -y cudatoolkit=11.1 mkl mkl-devel mkl-include tbb intel-openmp blas freetype zlib git cxx-compiler -c conda-forge

第三步:从现在开始,我们做任何事情都要用画中画。以我的经验来看,conda 在获取原生库方面非常出色,比如 CUDA,但是在获取我们需要的 Python 东西方面却很糟糕。所以我们从更新我们的基础设施开始,然后从它的官方库安装 PyTorch 1.8。

pip install -U pip setuptools wheel

pip install torch==1.8.2+cu111 torchvision==0.9.2+cu111 -f [https://download.pytorch.org/whl/lts/1.8/torch_lts.html](https://download.pytorch.org/whl/lts/1.8/torch_lts.html)

第四步:克隆 CenterTrack 存储库并使用 pip 安装 requirements.txt 文件(pip install -r requirements.txt)。最后,在资源库根目录下创建一个名为“models”的文件夹,并从官方资源库下载您需要的模型。如果你正在寻找姿势估计,向下滚动到末尾,下载 coco_pose_tracking。

第五步: CenterTrack 将 DCNv2 代码库用于可变形卷积。但是,这个存储库包含一个 Linux 版本的子模块。相反,我们应该下载这个库,DCNv2 的一个 Windows 端口。将这个 repo 克隆到src/lib/model/networks/,使用终端导航到它(不要忘记激活 conda 环境!)和run python setup.py build develop

第六步:测试您的安装。这里有一个片段,您可以在存储库根目录的终端上使用。如有必要,请确保更改型号名称。

python src/demo.py tracking,multi_pose --load_model models/coco_pose.pth --demo webcam

这是一个简单的教程。将来,我可能会写更多关于跟踪以及它如何帮助创建容错系统的内容。与此同时,我刚刚发表了一篇关于组合人工智能模型如何显著恶化您的性能的文章。在处理视频和流时,您可以减轻这些问题的方法之一是通过跟踪。

他的一切都是为了现在。如果你对这篇文章有任何问题,请随时评论或与我联系。你也可以订阅我的收件箱,以便在我发表文章的时候得到通知

如果你是中新,我强烈推荐订阅。对于数据和 IT 专业人士来说,中型文章是 StackOverflow 的完美搭档,对于新手来说更是如此。注册时请考虑使用我的会员链接。

感谢阅读:)

如何在 Mac Book M1 上并排安装 Miniconda x86_64 和苹果 M1

原文:https://towardsdatascience.com/how-to-install-miniconda-x86-64-apple-m1-side-by-side-on-mac-book-m1-a476936bfaf0

迷你康达 x86_64 &迷你康达苹果 M1 并排在 Mac 图书 M1

PC:作者

如果你是一名使用苹果 Mac M1 的 Python 开发人员/ ML 工程师/数据科学家,你可能知道没有 arm64 项目依赖分布的痛苦🥲。一种解决方法是通过启用了 rosetta2 的终端使用包管理器,比如 Anaconda3/Miniconda3。

但幸运的是,现在苹果 M1 得到了 Anaconda 的官方支持,你可以下载并用苹果的硅片为你的 Mac 安装 Anaconda3/Miniconda3。但是作为一名 ML 工程师,我想保留 Miniconda3 的两种风格(x86_64 &苹果 M1 ),因为我正在为这两种架构进行产品开发。

如何让 Miniconda3 x86_64 & Miniconda3 苹果 M1 并排,甚至有可能吗?

答案是“是的”,这花了我一些时间⏰想出一种便捷的方法。所以我决定把它写在这里,这样对很多像我一样的人会有用。

先决条件: Rosetta2 使能端子。

安装 Miniconda3 x86_64

打开启用 rosetta2 的终端,

  1. 检查您的终端是否支持 rosetta2
$ uname -m
x86_64

如果你得到x86_64,那么你在一个 rosetta2 使能的终端上

2.下载 Miniconda3 x86_64 bash 安装程序

$ wget [https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh](https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh)

3.运行安装程序

$ sh ./Miniconda3-latest-MacOSX-x86_64.sh

4.它会提示一个审查许可协议,按输入继续

PC:作者

5.然后继续按回车键,直到你得到下面的提示。一旦你得到它,输入 yes 并按 回车 继续

PC:作者

6.接下来,它会提示您安装路径

PC:作者

在这里键入`/Users/[your user name]/miniconda3-intel``(让我们把这个路径称为 Miniconda x86_64 路径)或者您喜欢的任何路径,主要思想是您应该保留 Miniconda Apple M1 的默认安装路径(只是为了区分两个安装)

7.它将下载基本包并在指定路径安装 Miniconda x86_64。一旦完成,就会提示是否运行conda init.

PC:作者

当你得到这个提示时,输入 no 并按下 进入。我们不想给你的终端启动脚本添加 conda 初始化器(例如.bashrc.zshrc或其他)

现在我们已经成功安装了 Miniconda3 x86_64。接下来,我们需要以同样的方式安装迷你康达苹果 M1,除了一些变化。

安装 Miniconda3 苹果 M1

打开一个终端(没有 rosetta2 的终端)

  1. 检查您的终端是否未启用 rosetta2(默认 M1 终端)
$ uname -m
arm64

如果你得到arm64,那么你在一个默认的终端上

2.下载 Miniconda3 x86_64 bash 安装程序

$ wget [https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh](https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh)

3.然后进行类似于前面的安装过程(从步骤 3步骤 5 )。

4.当它提示安装路径时,我会推荐安装在默认路径Users/[your user name]/miniconda3/。如果没有,请使用不同的路径。(让我们把这条路径称为迷你康达苹果 M1 路径)。

5.安装完成后,会提示是否运行 conda init,键入 no 并按 进入

为两个安装配置 conda init

通常当我们运行conda init时,它会根据我们使用的 shell 类型在终端启动文件中添加一些 shell 命令。

但是这里我们不能简单地在同一个文件中添加 x86_64 和苹果 M1 的 init。基于终端会话的架构激活正确的 **conda installtion** 需要更智能一点。

您可以简单地在.zshrc或您正在使用的任何 shell 启动脚本上做任何事情。但是让我告诉你我是如何干净利落地做到的。

  1. 为 conda init 创建自定义启动脚本
$ mkdir ~/.custrc/ && touch ~/.custrc/.condarc

2.打开并在脚本中添加 conda init 函数

init_conda() {
   # >>> conda initialize >>> conda_path_m1="/Users/mathanraj/miniconda3"
   __conda_setup="$('${conda_path_m1}/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
   if [ $? -eq 0 ]; then
      eval "$__conda_setup"
   else
      if [ -f "${conda_path_m1}/etc/profile.d/conda.sh" ]; then
          . "${conda_path_m1}/etc/profile.d/conda.sh"
      else
          export PATH="${conda_path_m1}/bin:$PATH"
      fi
   fi
   unset __conda_setup# <<< conda initialize <<<
}init_conda_intel() {
   # >>> conda initialize >>> conda_path_intel="/Users/mathanraj/miniconda3-intel"
   __conda_setup="$('${conda_path_intel}/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
   if [ $? -eq 0 ]; then
      eval "$__conda_setup"
   else
      if [ -f "${conda_path_intel}/etc/profile.d/conda.sh" ]; then
          . "${conda_path_intel}/etc/profile.d/conda.sh"
      else
          export PATH="${conda_path_intel}/bin:$PATH"
      fi
   fi
   unset __conda_setup
   # <<< conda initialize <<<
}

这里,

  • conda_path_m1是我为苹果 M1 公司安装 Miniconda 的地方
  • conda_path_intel是我为 x86_64 安装 Miniconda 的地方

根据您安装 Miniconda Apple M1 和 x86_64 的位置,相应地替换路径。

3.打开并添加下面几行到你的 shell 启动脚本中,在我的例子中是.zshrc

$ open ~/.zshrc

增加

# init conda based on arch
source ~/.custrc/.condarc
if [[ $(uname -m) == 'x86_64' ]]; then
    init_conda_intel
    echo "conda x86_64 is activated"
else
    init_conda
    echo "conda m1 is activated"
fi

这会给你的终端行为增加小智能。基本上,它只是根据终端会话的架构配置合适的 conda 安装。

就这样,现在关闭所有正在运行的终端会话并尝试

  • 打开 rosetta2 enabled 终端,会得到“康达 x86_64 已激活”。如果打印conda env list

PC:作者

  • 打开默认终端(不带 rosetta2),会得到“康达 m1 已激活”。如果你打印conda env list

PC:作者

注意:如果仔细观察,它会打印两种情况下所有可用的 conda 环境。但是,当它来自支持 rosetta2 的终端时,请注意,仅打印 miniconda3-intel 环境下的名称,miniconda3-intel 下的基本路径将带有 (*) 符号。miniconda3-m1 也是如此。

希望你觉得超级有帮助。

没有什么是不可能的,让我们做吧…🎉

如何安装 Spark NLP

原文:https://towardsdatascience.com/how-to-install-spark-nlp-5fcd36fab378

环境设置

如何让 Spark NLP 在您的本地计算机上工作的分步教程

照片由西格蒙德Unsplash 上拍摄

Apache Spark 是一个用于快速和通用数据处理的开源框架。它提供了一个统一的引擎,可以以快速和分布式的方式运行复杂的分析,包括机器学习。

Spark NLP 是一个 Apache Spark 模块,为 Spark 应用程序提供高级自然语言处理(NLP)功能。它可以用于构建复杂的文本处理管道,包括标记化、句子分割、词性标注、解析和命名实体识别。

尽管描述如何安装 Spark NLP 的文档非常清楚,但有时您可能会在安装时遇到困难。出于这个原因,在本文中,我尝试描述一个逐步的过程来使 Spark NLP 在您的计算机上工作。

要安装 Spark NLP,您应该安装以下工具:

  • 计算机编程语言
  • Java 语言(一种计算机语言,尤用于创建网站)
  • 斯卡拉
  • 阿帕奇火花
  • PySpark
  • 火花 NLP。

1 条蟒蛇

您已经按照技术要求一节中描述的步骤安装了 Python。所以,我们可以从第二步开始安装软件,Java。

2 Java

Spark NLP 构建在 Apache Spark 之上,可以安装在任何支持 Java 8 的操作系统上。通过在终端中运行以下命令,检查您是否安装了 Java 8:

java –version

如果已经安装了 Java,您应该会看到以下输出:

openjdk version “1.8.0_322”
OpenJDK Runtime Environment (build 1.8.0_322-bre_2022_02_28_15_01-b00)OpenJDK 64-Bit Server VM (build 25.322-b00, mixed mode)

如果没有安装 Java 8,可以从这个链接下载 Java 8,按照向导进行操作。

Ubuntu 中,可以通过包管理器安装openjdk-8:

sudo apt-get install openjdk-8-jre

在 Mac OS 中,可以通过brew安装openjdk-8:

brew install openjdk@8

如果安装了另一个版本的 Java,可以下载 Java 8,如前所述,然后将JAVA_HOME环境变量设置为 Java 8 目录的路径。

3 斯卡拉

Apache Spark 需要 scala 2.12 或 2.13 才能正常工作。您可以按照此处 描述的步骤安装 scala 2.12.15。

安装完成后,您可以通过运行以下命令来验证 scala 是否正常工作:

scala -version

4 阿帕奇 Spark

你可以从 Apache Spark 的官方网站下载,这里是。Apache Spark 有很多版本。个人安装了 3.1.2 版本,这里

您下载这个包,然后,您可以提取它,并把它放在文件系统中您想要的任何地方。然后,您需要将 spark 目录中包含的 bin 目录的路径添加到PATH环境变量中。在 Unix 中,您可以导出PATH变量:

export PATH=$PATH:/path/to/spark/bin

然后,导出SPARK_HOME环境变量以及 spark 目录的路径。在 Unix 中,您可以按如下方式导出SPARK_HOME变量:

export SPARK_HOME=”/path/to/spark”

要检查 Apache Spark 是否安装正确,可以运行以下命令:

spark-shell

外壳应该打开:

Welcome to____ __/ __/__ ___ _____/ /___\ \/ _ \/ _ `/ __/ ‘_//___/ .__/\_,_/_/ /_/\_\ version 3.1.2/_/Using Scala version 2.12.15 (OpenJDK 64-Bit Server VM, Java 1.8.0_322)Type in expressions to have them evaluated.Type :help for more information.scala>

要退出 shell,可以使用 Ctrl+C。

5 PySpark 和 Spark NLP

PySpark 和 Spark NLP 是两个 Python 库,可以通过 pip 安装:

pip install pyspark
pip install spark-nlp

现在 Spark NLP 应该已经在你的电脑上准备好了!

摘要

恭喜你!您刚刚在计算机上安装了 Spark NLP!你已经安装了 Java,Scala,Apache Spark,Spark NLP,PySpark!

现在是玩 Spark NLP 的时候了。网上有很多教程。建议你从以下几本笔记本开始:

你也可以查看这个教程,它解释了如何将 Spark NLP 与 Comet 集成,Comet 是一个用来监控机器学习实验的平台

如果你读到这里,对我来说,今天已经很多了。谢谢!你可以在这个链接阅读我的趋势文章。

相关文章

https://medium.datadriveninvestor.com/how-to-restore-the-original-layout-of-a-text-document-after-a-manipulation-in-python-8f3de41e8e95

如何解读任何机器学习预测

原文:https://towardsdatascience.com/how-to-interpret-any-machine-learning-prediction-64ff43020214

人工智能|可解释性|数据科学

将黑盒模型转换成玻璃盒子

威廉·冈克尔在 Unsplash 上拍摄的照片

局部可解释模型不可知解释(LIME)是 Ribeiro 等人[1]开发的 Python 项目,用于解释任何监督机器学习(ML)模型的预测。

大多数 ML 算法是黑盒;我们无法正确理解它们是如何进行特定预测的。这是人工智能的一个巨大缺点,随着人工智能(AI)变得越来越普遍,理解“的重要性这是为什么?'是不断增加的。

在本帖中,我们将讨论 LIME 项目如何工作以及为什么工作。我们还将通过一个使用真实数据集的示例来进一步理解 LIME 的结果。

理解机器学习的基础

在我们能够理解并真正欣赏 LIME 的牛逼之前,我们必须先了解 ML 的基本直觉。

任何被监督的问题都可以归结为两个主要特征:𝒙(我们的特征)和𝑦(我们的目标)。我们想建立一个模型ƒ(𝒙)来生成一个预测𝑦'每当我们提供一些样本𝒙'.

在训练期间,ML 模型不断地调整映射函数ƒ(𝒙的权重),这使得该模型成为一个黑箱,因为理解这些权重如何变化并不容易。

理解任何 ML 模型的预测归结为理解所述模型背后的映射函数。

理解模型可解释性类型

模型可解释性有两种主要类型:

1.全球解释

给定一个模型,使用整个训练数据集生成全局解释。全局解释显示了整体特征对模型的重要性。对于每个特性,全局解释通常会回答这个问题:“总的来说,这个特性对有多重要?”

2.当地解释

当地的解释直接基于单一的观察。利用局部解释,我们试图理解为什么会对特定样本产生特定的预测。对于任何给定的样本,本地解释通常会回答这个问题:“哪个特征对这个特定的预测影响最大?”

在这篇文章的其余部分,我们将集中讨论当地的解释。

石灰的直觉

LIME 试图通过采样实例来近似模型的映射函数ƒ(𝒙) (称为输入扰动)。通俗地说,LIME 生成了一堆合成样本𝒙',这些样本与原始实例𝒙.非常接近然后,LIME 将𝒙'传递给原始模型,并记录各自的预测。这个过程使 LIME 能够确定不同的输入波动是如何影响的。在过程的最后,对于给定的样本𝒙,LIME 将能够通过确定每个特征的单独影响来近似预测。因此,LIME 能够通过了解哪些要素对预测的贡献最大来解释特定的预测。

概括起来

  • 𝒙'石灰样品实例
  • LIME 使用𝒙'生成一组预测𝑦'使用ƒ(𝒙)
  • LIME 比较预测与原始预测的接近程度,并对它们进行加权。
  • LIME 使用权重来确定哪些特征对单个预测最有影响。

潜得更深

如前所述,莱姆的整个想法是试图解释ƒ(𝒙).LIME 通过代理模型实现了这一点。替代模型 g 是用于解释另一种预测算法的结果的任何模型。一般来说,g 会是一个更简单、更易解释的模型(比如决策树或线性模型)。我们可以正式定义代理模型集合为 G,使得 G∈G

但是,LIME 如何选择使用哪个 g 来解释原始模型呢?

LIME 考虑了两个主要的决定因素:

警告:好听的话传入

  1. 局部保真度,用 L(f,g,π)表示——也称为保真度函数
  2. 复杂度,用ω(g)表示

什么是地方忠信?

我们有两个部分:

  • 本地

我们已经讨论过了。局部简单意味着我们一次只关注一个特定的预测,而不是整体考虑。

  • 忠诚

就像暗示的那样,这是对我们选择的 g 能够多精确地跟随原始模型的度量。g 的预测越接近于,g 被认为越忠实于。我们把两个预测的‘接近’称为接近度,数学上定义为π。

简单吧?

什么是复杂性?

向一个 5 岁的孩子解释 2+2 比解释∫ tan(𝒙).容易为什么?因为 2+2 背后的‘映射函数’比积分简单多了。

g 背后的主要动机是解读。因此,g 必须是可解释的。g 越简单,它就变得越容易解释。

根据被评估模型的类型,复杂性有不同的度量方法。例如,在决策树中,复杂性可以直接由树的深度给出(树越深,越复杂,越难解释)。在线性模型中,复杂性可以用非零权重的数量来衡量。

LIME 试图最小化复杂性,最大化忠实性。

保真度函数 L(f,g,π) 可以由任何损失函数定义。LIME 使用平方损失距离函数。损失函数也根据要解释的模型的类型而变化(图像分类器将需要与表格不同的损失函数)。

这主要是石灰项目的要点。还有更多的内容,所以如果你喜欢这篇文章,我强烈推荐阅读[1]。

现在,让我们用一些 Python 例子来体验一下吧!

Python 中的工作时间示例

首先,我们需要使用 pip 安装 LIME。你可以在[2]中找到 LIME 的源代码。

pip install lime

我们将使用 Scikit-learn [3]提供给我们的 iris 数据集作为示例来演示软件包的用法。

首先,我们需要导入我们需要的不同的包。

# imports
import numpy as np
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

我们也可以进口石灰如下:

from lime.lime_tabular import LimeTabularExplainer

我们的问题有一个监督的表格结构。因此,我们需要导入 LimeTabularExplainer。此外,当使用石灰时,设置 NumPy 的随机种子可能是个好主意。LIME 利用 NumPy 作为其后端;因此,将随机种子设置为我们选择的数量将确保我们可以获得可重复的实验。我们可以使用以下方式设置随机种子:

np.random.seed(1)

然后,我们创建一个助手函数,它接受我们的训练和测试集,训练一个基本的 RandomForestClassifier,并计算出它的准确度分数。这里的目标不是构建最健壮的模型,而是为我们的解释获得一个基础模型。

我们从 Scikit-learn 获取数据集,对其进行分割,并按如下方式训练我们的模型:

接下来,我们需要生成我们的 LIME explainer 函数。这里我们需要指定训练数据、特征名、类标签,以及是否离散化连续变量。

现在我们可以为任何我们想要的预测生成一个解释。在这一步,我们开始控制要显示的最有影响力的特征的数量。这可以是介于 1 和数据集中要素数量之间的任意整数值。

针对三种不同的预测运行最后这段代码,我们得到:

作者图片

作者图片

作者图片

在可视化的左侧,我们得到了每一类的预测概率分布。在右边,我们得到了对该预测最有影响的前 2 个(我们在初始化上面的 explainer 函数时指定的)特征以及它们各自的值。在图的中心,我们得到每个有影响的特征的条件(基于扰动的输入)及其强度(即,对模型的贡献/影响)。

例如,在第一次预测中,模型以 99%的置信度预测样本为杂色。这个分数的 24%是因为花瓣长度大于 1.58 厘米,另外 14%的影响是因为花瓣宽度大于 0.3 厘米

结论

而且真的是这样!这个包的美妙之处在于它严格遵循了我们刚刚讨论过的“代码模板”。即使在解释图像或文本分类器时。唯一不同的部分是导入所需的解释器(在我们的例子中,我们使用 LimeTabularExplainer,因为我们想要解释表格数据)。

要记住的一个重要方面是,解释器函数只能和它试图逼近的原始模型一样好。因此,当在野外时,一定要确保使用交叉验证对模型进行稳健的训练,并进行适当的验证。此外,LIME 还可用于评估任何给定 ML 模型的稳健性。

LIME 是对可解释人工智能世界的惊人介绍。LIME 和领域都在不断成长和成熟,这使得现在是开始将 XAI 纳入数据建模管道的最佳时机。

你喜欢这篇文章吗?如果是的话,也许你可以考虑成为会员来支持我和你其他喜欢的作家。

https://david-farrugia.medium.com/membership

参考

[1]里贝罗,M.T .,辛格,s .和盖斯特林,c .,2016 年 8 月。“我为什么要相信你?”解释任何分类器的预测。第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集(第 1135-1144 页)。

[2]https://github.com/marcotcr/lime

[3]https://sci kit-learn . org/stable/auto _ examples/datasets/plot _ iris _ dataset . html

想给我买杯咖啡吗?

https://paypal.me/itsdavidfarrugia?country.x=MT&locale.x=en_US

想联系吗?

我很想听听你对这个话题的想法,或者其他什么。如果你想联系我,请给我发电子邮件到 davidfarrugia53@gmail.com。

Linkedin——Twitter

用贝叶斯方法解释新冠肺炎快速家庭测试结果:概率模拟第 1-2 部分

原文:https://towardsdatascience.com/how-to-interpret-covid-19-rapid-home-test-results-using-bayes-probability-simulation-part-1-2-edfb1d1bc224

你参加过新冠肺炎家庭测试并试图解释结果吗?让我们用一些贝叶斯方法来回答这个问题,并通过使用 Python 模拟场景来验证答案。

疾控中心Unsplash 拍摄的照片

这篇文章是我上一篇概率文章第一部分的延续。(这是一个临时帖子,我将在稍后发布该系列的第 2 部分)。

背景

让我们假设有一种叫做的罕见疾病,它影响了总人口的 1%。并且说有一种检测这种疾病的最快速的测试方法,无论是阳性还是阴性测试都有 95%的准确率。

  • 现在,如果你用这种最快的方法检测出阳性,你真的得了这种病的可能性有多大?
  • 答案是 ~16%为什么会这样?为了更好地理解,让我们看看下面的新冠肺炎例子。

介绍

当我们都开始认为新冠肺炎已经得到控制时,人数又开始增加了。仅在美国,每天就有超过 10 万例阳性病例被报道。

来源,2022 年 5 月 25 日。美国 cdc.gov 每日更新

上周,我密切接触的一个人的 COVID 19 检测呈阳性。我决定接受新冠肺炎快速家庭测试,这样我就可以自我隔离,如果我是阳性的话[ 接受测试的理由 ]。做完测试后,我想知道如何解释结果,我想你们中的很多人可能会有同样的问题。所以,让我们试着用概率来回答这个问题,并用蒙特卡罗模拟来验证这个答案。

免责声明:我的职业是工程师和数据科学家,没有医学专业知识。这篇文章更多的是关于数据和概率,并不打算提供任何形式的医学建议。请参考最新的疾病预防控制中心指南或向你的医生咨询医学专业知识。

注意:这篇文章假设读者对概率和贝叶斯定理有所了解。如果没有,我会推荐你阅读我的最后一篇文章。

新冠肺炎测试

资料来源:cdc.gov(NAATs)

自测 是一种快速测试,可以在家里或任何地方进行,易于使用,并能快速得出结果。 在本帖中,我们将重点关注我是如何试图解读我的快速家庭测试结果的。

请参考 CDC 的在家或任何地方自测链接,获取官方指导。

让我们深入研究一下

我参加了智能拭子新冠肺炎快速测试。

照片由史蒂夫·诺玛克斯Unsplash 上拍摄

根据检测试剂盒和网站中的信息,他们声称在他们的临床研究中,该检测正确识别了约 85%的阳性样本和约 98%的阴性样本。

  • 我们来试着理解一下是什么意思;

图片由作者提供

图片由作者提供

  • 更高的灵敏度意味着更低的假阴性,更高的特异性意味着更低的假阳性。
  • 根据疾病和控制措施,政府或 CDC 可能会制定一些准则,规定一项测试获得大规模批准的最低允许灵敏度和特异性数字,他们还可能会优先考虑一个数字。(例如,FPs 可能会增加医疗保健系统的负担,而 FNs 可能会增加传播)。

现在回到主要问题:“给定某个测试结果,我感染的概率是多少?”

这些数字可能看起来类似于敏感性和特异性数字,但它们实际上是不同的(看分母)。

*注: 在 DS 社区,我们也知道灵敏度为召回,PPV 为精准。

  • 让我们假设你得了一种罕见的疾病 X ,这只影响 1%的人口。您可以从这个数字开始,作为您的先验(或预测试)概率。
  • 你也可以用新的信息更新这种概率:例如,如果你与患有这种疾病的人有密切接触,或者如果这种疾病在你的家族中传播,或者如果考虑到你目前的健康状况,你更容易患这种疾病,等等..
  • 然后,比方说,你决定做个测试。根据测试结果,你可以进一步更新你患这种疾病的概率。敏感度和特异度数字有助于您确定在获得测试结果后,您应该增加或减少先前患病概率的可能性因素。

图片由作者提供

你明白了,对吧?

**我们将假设我们在进行快速测试之前已经计算了一个良好的先验,并将只关注在获得测试结果后更新概率。

  • 贝叶斯定理可以帮助我们计算这个似然因子,更新我们的先验。

测试后概率=基于测试结果的可能性∫测试前概率

用更专业的术语来说就是。

我们有兴趣知道左边的值,即 PPV。等式右边的第一部分是可能性部分。请注意,这个比率基本上是计算如果您有 Covid19,获得阳性测试结果的机会与您获得阳性测试结果的总机会的比率(** 记住,由于测试可能有假阳性,这个分母将包括两种情况→当您有 Covid19 时获得阳性,以及当您没有 Covid19 时获得阳性)。

您能看出特异性和敏感性数字将如何影响上述似然比以及更新因子吗?

分解上式的成分,

上述等式中最难得到也是最有争议的数字是 P(你有 Covid19) → 预测试概率(也称为先验或患病率)。这取决于各种因素,很难确定,我们将在后面讨论。

  • 为了举例计算,基于我上面提到的条件,我们暂时用 P(我有 Covid19) = 1 0% 作为保守估计。从而 P(我没有 Covid19) = 90%。
  • 将所有的数字放在上面的等式中,

  • 我的检测结果为阴性,因此,鉴于我的预测试估计正确 ,我患 Covid19、** 的几率仅为 1.67%。**

我在这里做的其他假设是:

  • 我按照试剂盒上的说明正确地进行了自我测试。
  • 我是在密切接触后 5 到 7 天(疾控中心推荐)做的测试。
  • 检测试剂盒上报告的灵敏度和特异性数据对每个人都是正确有效的,并且随着时间的推移保持不变。
  • 请注意,如果您有症状,您应该在症状出现的 7 天内进行测试。[ 来源

回到这篇文章的主题——模拟

也许上面的解释和计算完全有道理,没有任何混乱。或者也许你确实计算了数字,但不确定它们是否正确?

这就是模拟场景将有所帮助的地方。在我们的上一篇中,我们已经建立了如何模拟某个概率问题的基础。让我们在这里使用相同的框架。

模拟得出的答案与我们之前的计算相符。

  • 为了更确定我的测试结果,我实际上做了两次测试(系列抗原测试),两次测试之间有 36 个小时的间隔。
  • 两个结果都是否定的,因此,我实际上拥有 Covid19 的几率只有 0.29% (同样,假设我们的假设为真)。*

让我们从结果中验证灵敏度和特异性数字。请注意,当我们计算这些数字与上述数字相比时,分母是如何变化的。

它们与我们提供的输入数字相匹配,这是意料之中的。

**请参考 这个站点和算法由疾控中心 设定你应该根据抗原检测结果的阳性或阴性采取什么行动。也可以参考https://www.cdc.gov/coronavirus/2019-ncov/lab/faqs.html#Interpreting-Results-of-Diagnostic-Tests

此外,如果您的检测结果呈阳性,并且在更长时间内持续呈阳性,请查看http://can-i-stop-isolating-if-im-still-testing-positive-for-the-virus/*。*****

先验(预测试概率)

正如我们之前看到的,在评估 Covid19 抗原测试的结果时,需要考虑以下因素→测试灵敏度和特异性,以及预测试概率(其中取决于covid 19 感染在社区和个人临床环境中的流行程度)。[ 来源****

如果社区中的感染流行率高,受试者有症状,并且替代诊断的可能性低,则预测试概率通常被认为高。

如果社区中的感染率较低,且被测试者无症状,且未与新冠肺炎患者有过密切接触,则预测试概率通常被认为较低。

  • 计算 Covid19 先验的一种方法是检查您所在地区报告的病例数。或者阳性测试占总测试的比例也是一个可以考虑的选项。例如,你可以在这里找到纽约市的号码,在这里找到整个美国的号码,在这里找到的号码。
  • 因此,如果你在纽约,你可以使用 9%作为你有 Covid 的开始之前的估计。
  • 上述数字可以根据其他因素进行更新,如您的健康状况或暴露程度。例如,这项研究指出,如果你暴露于 Covid,你将有大约 2.6%的机会被诊断为 Covid(似乎很低,对吗?).
  • **请注意,以上数值仍为估计值。至少我找不到可靠的消息来源有把握地说,如果你来自 XYZ 地区并符合 ABC 参数,这是你患 Covid19 的先验概率。CDC 确实有 社区层面的信息 ,但那是在类别上,而不是数字上。

因此,考虑到这种不确定性,让我们在给定某项测试的某些灵敏度和特异性数的情况下,在可能的先验概率[0 到 1]的整个范围内,计算具有 Covid19 的人的测试后概率(PPV 和 1 - NPV)。

例如,在我的情况下,考虑到我的健康状况、密切接触和其他因素,如果我假设我的预测试概率在 10%至 30%之间,我的单一阴性测试结果将使我患 Covid19 的概率在 1.7%至 6%之间(2 次阴性测试为 0.3%至 1%)。

在 Streamlit 上查看全交互图(*见黑暗模式)。

稍微摆弄一下交互式图表,试着理解这三个主要因素——检测的灵敏度和特异性以及预测试概率——如何影响您在检测结果为阳性(或阴性)的情况下实际患病的概率。

结论

  • 估计先验概率至关重要。较高的先验会降低你对非常准确的阴性测试的信心,而非常低的先验会降低你对非常准确的阳性测试的信心。
  • 高度敏感的测试具有较低的假阴性。
  • 类似地,高度特异性的测试具有较低的假阳性。
  • 上面的两个值决定了一个因子,通过这个因子,你将在测试后更新你先前的感染信念。
  • 两次得到阴性结果会让你对没有感染更有信心,尤其是当敏感度数值很高的时候。 如果您继续出现症状,您应该向您的医务人员寻求后续护理。
  • 如果你得到阳性结果,你很有可能感染了,特别是对于高度特异性的测试,你应该遵循 CDC 的指导方针来决定什么对你最好。

参考

Covid 数据跟踪每周回顾

Covid 测试概述

如何解释自检结果

解释诊断测试的结果

抗原检测指南

为什么在新冠肺炎时代前后测概率很重要

如何用 Python 解释线性回归、套索、决策树(易)

原文:https://towardsdatascience.com/how-to-interpret-machine-learning-models-part-1-easy-978ddade7ada

最重要的特性(特性重要性)是什么?为什么模型会做出这个特定的决定?

1.介绍

在这篇文章中,我将尝试解释线性回归、Lasso 和决策树模型,这些模型本身都是可以解释的。我将分析全局可解释性——分析总体预测的最重要特征,以及局部可解释性——解释个别预测结果。

机器学习模型用于银行交易中的欺诈和风险检测、语音助手、推荐系统、聊天机器人、自动驾驶汽车、社交网络分析等应用中。然而,有时很难解释它们,因为算法代表了一个黑盒(例如神经网络),人类很难理解为什么模型做出了特定的决定。所以我们需要额外的技术来分析黑盒决策。

来源:作者照片

2.什么是可解释性?

可解释性是人类能够理解决策原因的程度[Miller,Tim 2017]。

我们可以互换使用可解释性可解释性。然而,术语解释用于解释单个预测,而非整个模型。如上所述,一些算法很容易解释,然而,在算法预测准确性和可解释性之间存在粗略的相关性。模型越复杂,解释力就越弱。

作者照片

3.为什么可解释性很重要?

以下是几个原因:

  • 解释为什么模型做出特定的决定。
  • 建立对关键应用程序模型的信任。
  • 调试和改进模型。

4.线性回归、套索和要素重要性

4.1 线性回归

线性模型预测是特征输入的加权和。

y' = W0 + W1x1 + W2x2 + … +WnXn

其中 Wj 为特征,W0 为截距。

使用线性模型时,数据集上有一些约束:

  • 线性:目标变量是输入特征的线性组合。
  • 正态性:给定目标变量,假设特征遵循正态分布。
  • 同方差:假设误差项的方差在整个特征空间上是恒定的
  • 独立性:每个实例都独立于任何其他实例。
  • 无多重共线性:输入要素的相关性应较弱,否则会影响预测。

实用建议:如果只有几个特征,线性模型就不错。

问题:当我们拥有很多功能时会发生什么?线性回归发现很难处理它们并相应地解释特征。这就是为什么我们可以使用套索功能选择。

4.2 套索

Lasso 是采用 L1 正则化的线性回归,负责使用惩罚权重进行要素选择,这意味着模型的大权重会缩小,小权重会变为零。alpha 参数定义权重的惩罚。

:如果想了解更多关于线性回归或者套索的内容,可以参考我之前关于线性模型的文章。

4.3 特征在线性回归和套索中的重要性

特征重要性是其 t 统计量的绝对值。因此,如果特性的权重增加,其重要性也会增加。然而,如果标准误差增加(我们不太确定正确的值),重要性就会降低。

t 统计公式

4.4 线性模型解释评价

用线性来解释对人们来说更简单自然。因此,如果线性回归或 Lasso 是数据的良好预测器,这意味着数据满足上面提到的大多数重要约束,那么解释将是真实的。在另一种情况下,如果数据中存在非线性相互作用,线性模型将越不准确,因此,解释将越不真实。

5.决策树和特征重要性

5.1 决策树

当数据不是线性的、要素和结果之间的关系是非线性的或者存在多重共线性时,线性回归模型会失败,因此输入要素会相互影响。这就是为什么在这种情况下可以使用基于树的算法。

决策树背后的直觉是,数据根据某些临界值被分割成不同的子集,预测结果是每个叶节点。

注意:如果你想了解更多关于决策树的知识,请参考我之前关于基于树的方法的文章。

5.2 决策树中的特征重要性:

解释起来很容易。决策树的总体特征重要性可以通过以下方式计算。浏览所有分割,并注意每个要素分割相对于父节点减少了多少方差(对于回归)或基尼指数(对于分类)。

5.3 决策树解释评估:

预测的真实性取决于树的预测性能。对短树的解释非常简单和通用,因为对于每一次分裂,实例要么落入一片叶子,要么落入另一片叶子。二元决策很容易理解。

6。总结

作者照片

使用 Python 实现可解释性

GitHub 代码可用:此处

在这一节中,我将向您展示线性回归、Lasso 和决策树解释的实际实现。全局解释表示每个特征对于总体预测的重要性。局部解释试图帮助我们理解机器学习模型的个体预测。

来自 Kaggle 的数据集:医疗费用个人数据集

共 7 项功能:

  • 年龄:保险承包人年龄
  • 性别:保险签约人性别,女,男
  • BMI :身体质量指数,提供对身体的了解,体重相对于身高相对较高或较低,体重的客观指数(kg / m ^ 2)使用身高与体重的比率,理想值为 18.5 至 24.9
  • 儿童:健康保险覆盖的儿童人数/受抚养人人数
  • 吸烟者:吸烟
  • 地区:受益人在美国的居住区域,东北、东南、西南、西北。
  • 费用:由健康保险支付的个人医疗费用

我们的目标是建立一个预测个体承包商费用的 ML 模型,然后解释结果。

第 0 步:导入库

**import** pandas **as** pd
**import** numpy **as** np
**import** matplotlib.pyplot **as** plt
**import** statsmodels.api **as** sm
**from** sklearn.linear_model **import** LinearRegression,Lasso
**from** sklearn.preprocessing **import** MinMaxScaler, StandardScaler, LabelEncoder,OneHotEncoder
**from** sklearn.metrics **import** mean_squared_error, mean_absolute_error, r2_score
**from** sklearn.model_selection **import** train_test_split,GridSearchCV
**from** sklearn.pipeline **import** Pipeline
**from** sklearn.tree **import** DecisionTreeRegressor
**from** sklearn **import** tree

1。线性回归:

步骤 1 :导入数据预处理数据——对分类列进行编码,并进行标准缩放。

# 1\. import data
data **=** pd**.**read_csv("insurance.csv")# 2\. categorical encoding
data_linear_reg **=** pd**.**get_dummies(data,columns**=**['sex', 'smoker','region'], drop_first**=True**)# 3\. scalling
col_names **=** ['age', 'bmi']
features **=** data_linear_reg[col_names]
scaler **=** StandardScaler()**.**fit(features**.**values)
features **=** scaler**.**transform(features**.**values)
data_linear_reg[col_names] **=** features# 4.train test split
x_train, x_test, y_train, y_test **=** train_test_split(data_linear_reg**.**drop(columns**=**["charges"]), data_linear_reg["charges"], test_size**=**0.2, random_state**=**42)#5\. linear regression model 
linear_reg **=** sm**.**OLS(y_train, x_train)**.**fit()

第二步:预测结果

**def** pred_result(pred,y_test):
  score_MSE **=** round(mean_squared_error(pred, y_test))
  score_MAE **=** round(mean_absolute_error(pred, y_test))
  score_r2score **=** round(r2_score(pred, y_test),2)
  print(f"MSE: {score_MSE} | MAE: {score_MAE} | R2score: {score_r2score}")linear_pred **=** linear_reg**.**predict(x_test)
pred_result(linear_pred,y_test)

Out[]:MSE:46124128 | MAE:5032 | R2 score:0.67

如您所见,均方误差为 46124128,平均绝对误差为 5032,R2 分数为 0.67。

第三步:全局可解释性

err **=** linear_reg**.**params **-** linear_reg**.**conf_int()[0]
coef_df **=** pd**.**DataFrame({'coef': round(linear_reg**.**params),
                        'Standard Error': round(linear_reg**.**bse),
                        't_Stats': round(linear_reg**.**tvalues,1),
                        'error': round(err)
                       })**.**reset_index()**.**rename(columns**=**{"index":"columns"})
coef_df

Coef -代表特征的权重。

标准误差:砝码的标准误差。

t_Stats :每个特征的 t 统计量。

误差:权重与其第一置信区间水平之差。

Coef(权重)背后的直觉:

  • 数字特征(例如:年龄):年龄增加 1 岁,在所有其他特征保持不变的情况下,预测费用数增加 3598。
  • 分类特征(例如:吸烟者):在所有其他特征保持不变的情况下,当一个人吸烟时,收费值比不吸烟的人高 25153。
coef_df**.**plot(y**=**'coef', x**=**'columns', kind**=**'bar', color**=**'none', yerr**=**'error', legend**=False**, figsize**=**(14,6))
plt**.**scatter(x**=**np**.**arange(coef_df**.**shape[0]), s**=**100, y**=**coef_df['coef'], color**=**'green')
plt**.**axhline(y**=**0, linestyle**=**'--', color**=**'black', linewidth**=**1)
plt**.**title("Coefficient and Standard error")
plt**.**grid()
plt**.**yticks(fontsize**=**15)
plt**.**xticks(fontsize**=**15)
plt**.**show()

作者照片

我们可以在图中观察每个特征的权重和标准误差。值得注意的是,标准误差可以忽略,因为它们很小,这意味着模型确定每个特征的权重。

plt**.**figure(figsize**=**(14,6))
plt**.**bar(linear_reg**.**tvalues**.**keys(), abs(linear_reg**.**tvalues**.**values))
plt**.**title("Feature Importance",fontsize**=**25)
plt**.**ylabel("t-statistic (absolute value)",fontsize**=**18)
plt**.**grid()
plt**.**xticks(rotation**=**90,fontsize**=**15)
plt**.**yticks(range( 0,int(max(round(linear_reg**.**tvalues)))**+**5,5) ,fontsize**=**15)
plt**.**show()

作者照片

如上所述,可以使用 t 统计量来测量线性回归特征的重要性。所以基于线性回归最重要的特征吸烟者 _ 是(它定义了这个人是否吸烟)。第二个最重要的特征是年龄。最不重要的特征是性别 _ 男性体重指数

步骤 4:局部可解释性

让我们检查一个单独的预测(例如,第 5 个样本点)和它的预测是什么。

forth_sample **=** x_test**.**iloc[4]
forth_sample

print("predicted: ",int(linear_reg**.**predict(forth_sample**.**values)))
print("actual: ",int(y_test**.**iloc[4]))

Out[]:预测:28147 实际:33750

:该样本点性别为男性,吸烟。想象一下如果那个人不吸烟会有什么预测?

forth_sample**.**values[4] **=** 0 # make a person non-smoker
print("predicted non smoker: ",int(linear_reg**.**predict(forth_sample**.**values)))

Out[]:预计不吸烟人数:2994 人

print("difference : ", 28147 **-** 2994 ) *# same as smoker_yer weight.*

Out[]:差额:25153

注意:正如我们从特征重要性图中看到的,smoker_yes 特征是线性回归模型中最重要的特征。事实确实如此。第五种情况的预测是 28 147,而当我们改变它的值并使一个人不吸烟时,预测值变成 2 994。差 25153 与吸烟者体重相同 _ 是特征!

2.套索

步骤 1:导入数据预处理数据—对分类列进行编码并进行标准缩放。

data **=** pd**.**read_csv("insurance.csv")data_lasso **=** pd**.**get_dummies(data,columns**=**['sex', 'smoker','region'], drop_first**=True**)col_names **=** ['age', 'bmi']
features **=** data_lasso[col_names]
scaler **=** StandardScaler()**.**fit(features**.**values)
features **=** scaler**.**transform(features**.**values)
data_lasso[col_names] **=** featuressearch **=** GridSearchCV(Lasso(),
                      {'alpha':np**.**arange(0.1,200,1)},
                      cv **=** 5, scoring**=**"neg_mean_squared_error",verbose**=**0
                      )x_train, x_test, y_train, y_test **=** train_test_split(data_lasso**.**drop(columns**=**["charges"]), data_lasso["charges"], test_size**=**0.2, random_state**=**42)search**.**fit(x_train,y_train)search**.**best_params_

Out[ ]: {'alpha': 74.1}

alpha 参数定义了权重惩罚能力。如果它很高,权重就变成了 0。在这种情况下,我进行了交叉验证的网格搜索,以找到最佳的 alpha 参数,在这种情况下是 74.1。

lasso_reg **=** Lasso(alpha **=** 74.1)
lasso_reg**.**fit(x_train,y_train)

第二步:预测结果

lasso_pred **=** lasso_reg**.**predict(x_test)
pred_result(lasso_pred, y_test)

Out[]:MSE:34153021 | MAE:4237 | R2 score:0.69

步骤 3:全局可解释性

coefficients **=** lasso_reg**.**coef_
importance **=** np**.**abs(coefficients)plt**.**figure(figsize**=**(14,6))
plt**.**bar(x_train**.**columns, importance)
plt**.**title("Feature Importance (Lasso)",fontsize**=**25)
plt**.**ylabel("t-statistic (absolute value)",fontsize**=**18)
plt**.**grid()
plt**.**xticks(rotation**=**90,fontsize**=**15)
plt**.**show()

作者照片

结果显示,套索使得性别 _ 男性,地域 _ 西北,地域 _ 西南特征权重到为零地域 _ 西南特征和子特征(几乎为零)。所以,模型几乎用 3 个特征:年龄、bmi、吸烟者 _ 是作为预测指标。和之前一样,smoker_yes 特征最重要,其次是年龄和 bmi 特征。值得一提的是,仅使用这 3 个特征,该模型比使用所有特征的简单线性回归做出了更好的预测。

步骤 4:本地可解释性

forth_sample **=** x_test**.**iloc[4]
lasso_reg**.**coef_print("predicted: ",int(lasso_reg**.**predict([forth_sample**.**values])))
print("actual: ",int(y_test**.**iloc[4]))

预测:26662
实际:33750

3.决策图表

步骤 1:导入数据预处理数据—对分类列进行编码并进行标准缩放。

data **=** pd**.**read_csv("insurance.csv")
encoder **=** LabelEncoder()
data[['age','sex','smoker','region']] **=** data[['age','sex','smoker','region']]**.**apply(encoder**.**fit_transform)
data_tree **=** data**.**copy()tree_reg **=** DecisionTreeRegressor(random_state**=**42,max_leaf_nodes**=**5) *# max_leaf_node =5 for simlicity*x_train, x_test, y_train, y_test **=** train_test_split(data_tree**.**drop(columns**=**["charges"]), data_tree["charges"], test_size**=**0.2, random_state**=**42)tree_reg**.**fit(x_train,y_train)

为了简单起见,我将 max_leaf_nodes 设置为 5,以便更好地查看可视化效果。

第二步:预测结果

tree_pred **=** tree_reg**.**predict(x_test)
pred_result(tree_pred, y_test)

MSE:26368109 | MAE:3325 | R2 score:0.8

结果远比简单的线性回归和套索要好

步骤 3:全局可解释性

importance **=** tree_reg**.**feature_importances_
plt**.**figure(figsize**=**(14,6))**for** i,v **in** enumerate(importance):
	print('Feature: %0d, Score: %.5f' **%** (i,v))
*# plot feature importance*
plt**.**bar(x_train**.**columns, importance)
plt**.**yticks(fontsize**=**15)
plt**.**show()

作者照片

如决策树特征重要性图所示,最重要的特征吸烟者,其次是 bmi 和年龄。这些都是和以前一样重要的特性。同样值得注意的是,特征重要性分数的总和是 1。

步骤 4:本地可解释性

forth_sample **=** x_test**.**iloc[4]
print("predicted: ",int(tree_reg**.**predict([forth_sample**.**values])))
print("actual: ",int(y_test**.**iloc[4]))

出[]:预测:36691 实际:33750

这个个人预测的解释是如此简单。正如我们看到的,第 5 个样本点预测是 36691。我们可以在下面直观地检查为什么我们会得到这样的结果。

**from** sklearn.tree **import** export_graphviz
**from** IPython.display **import** Image
**from** subprocess **import** call
export_graphviz(tree_reg, out_file**=**'tree.dot', 
                feature_names **=** x_train**.**columns,
                rounded **=** **True**, proportion **=** **False**, 
                precision **=** 2, filled **=** **True**)
call(['dot', '-Tpng', 'tree.dot', '-o', 'tree.png', '-Gdpi=600']) *# Convert to png using system command (requires Graphviz)*
Image(filename **=** 'tree.png')

作者照片

在右侧,我们可以看到第 5 个样本特征值。吸烟者=1,bmi=31.92,年龄=1。如果我们沿着树从上到下,我们可以很容易地评估预测。

结论:

所以我建立了线性回归、套索和决策树的可解释性。当我们改变机器学习算法时,可解释性和最重要的特征会改变,因为它们的性质不同。

在下面的文章中,我将使用部分依赖图、累积局部效应、置换特征重要性和许多其他方法来解释更复杂的 ML 方法。

如果你想了解更多关于应用数据科学的信息,这里是我的新 YouTube 频道——AI 学院与朋友

https://www.youtube.com/channel/UCvlF0PPaQ2GAuqYKJT4UpJQ

您可以在 上关注我,为即将到来的文章保持更新。

https://medium.com/@gkeretchashvili

参考

[1]克里斯托弗·莫尔纳尔,可解释机器学习 (2022)

[2]马勒·杨奇煜,可解释性与可解释性 (2019)

[3] Will Koehrsen,如何使用 Scikit-Learn 在 Python 中可视化来自随机森林的决策树 (2018)

[4] Sklearn 线性模型

如何解释 Logistic 回归中分类变量的比值比

原文:https://towardsdatascience.com/how-to-interpret-the-odds-ratio-with-categorical-variables-in-logistic-regression-5bb38e3fc6a8

参考类别说明及选择正确的类别

德克斯·伊齐基尔Unsplash 上拍摄的照片

逻辑回归是一个非常流行的机器学习模型,一直是许多文章和博客的焦点。虽然有一些使用相对简单的数据的精彩例子,但我很难找到一篇使用分类变量作为特征的综合文章。

为什么每个变量的一个类别在统计输出中被省略?我如何解释回归系数,即“对数优势比”,一个特定类别的变量?

我将通过涵盖以下主题来揭开这一神秘面纱:

虚拟变量概述

什么是参考类别,如何选择一个

如何解释虚拟变量的比值比

我将使用 Python 和 statsmodels 包(有很好的统计输出)以及一个开源的自行车旅行数据集,该数据集包含纽约市的城市自行车数据和大量派生的分类变量。从行程持续时间特性中,我生成了一个布尔目标变量,表示自行车行程是否超过 20 分钟,我已经武断地决定这是一次“长”行程。我们将研究哪些分类特征会显著增加或减少自行车旅行超过 20 分钟的几率。

我们开始吧!

处理分类数据—你好虚拟变量

数据变量可以是连续的(介于理论最小值和最大值之间的测量值,如年龄、体重)或分类的/离散的(固定值或分类,如工作日、性别)。分类数据不能直接用于机器学习算法,因此需要进行预处理。

分类变量可以转换成数字的虚拟变量,这是一种更好的格式。这是数据被转置的地方,因此每个类别由一组二进制特征表示,指示该类别在每行数据中的存在与否。两种流行的方法是熊猫 get_dummies() 和 s cikit-learn 的 OneHotEncoder() 。在这篇文章中,我将重点介绍 pd.get_dummies 方法。

为了避免多重共线性(变量之间的相关性),大多数模型都要求从数据中删除一个哑变量。这是如何工作的?因为每行至少有一个特性类别的值(假设您已经处理了丢失的值!),如果特性的每个虚拟变量都是 0,那么默认情况下,最后一个类别必须是 1。因此,可以删除一个虚拟变量。

那么我们如何删除一个虚拟变量呢?

“drop _ first”参数可能不是你的朋友

我学会了在使用 pd.get_dummies()创建虚拟变量时总是使用“drop_first=True”参数。这是在线学习平台涵盖的概念之一,但似乎从未深入到你使用它时实际发生的细节。

我注意到我不能选择哪个类别被删除。默认情况下,它总是删除按字母顺序排列的类别。这违背了所有的数据科学逻辑——当然,类别很重要,而且肯定有一些数据驱动的逻辑来挑选哪一个没有通过最终筛选?

让我们来回答第一个问题。为什么删除类别很重要?

参考类别

被丢弃的类别被称为引用类别。当您解释您的模型的结果时,该类别将与所有其他类别进行比较。

考虑到这一点,有必要通过将逻辑回归模型与您的数据相拟合来回想您试图回答的问题。在我们的例子中,一次自行车旅行是否会超过 20 分钟,你想确定事件发生的几率是多少?相对于其他类别,例如一周中的某一天,您是否对特定类别的效果感兴趣?(后面更有解读!)

因此,参考类别应该是允许更容易解释的类别,也是您最关心的类别。从数学上来说,这可能是在您的数据中具有最大代表性的类别,即代表“标准”的类别。同样,它也可能是在您的数据中意外出现的类别。

可视化你的数据可以帮助你做出决定。要素类别的频率或百分比的简单条形图有助于了解它们在数据中的分布情况。它还会揭示你可能想要研究的任何有趣或意想不到的模式。

现在让我们考虑一下我们的纽约自行车旅行数据。我已经从每次自行车旅行的开始时间中获得了额外的特征;“工作日”,七个类别代表一周中的某一天,“日类型”表示旅行发生在工作日还是周末。对于那些骑自行车观光的人来说,你可能会认为周末(周六和周日)是骑自行车旅行时间较长的日子。事实上,我们下面的探索性可视化显示,周六的自行车旅行超过 20 分钟的比例似乎略高。

图片由作者提供,在 matplotlib 中创建。

如果您的研究问题旨在解决一周中的某一天对自行车旅行超过 20 分钟是否有影响,您可以将参考类别设置为“周末”,以证实您的怀疑,即工作日自行车旅行超过 20 分钟的几率明显高于周末超过 20 分钟的几率。或者,您可以将您的参考类别设置为一周中的某一天,以评估相对于您选择作为参考类别的那一天,其他日子对赔率的影响。

其他一些挑选参考类别的策略可以在这里找到。

手动选择正确的参考类别

因此,我们认为,有能力选择作为参考的类别是非常重要的。那么,我们如何绕过讨厌的默认 drop_first 参数,选择我们自己的参数呢?

幸运的是,你可以使用一些工具来选择合适的丢弃方式。以下代码显示了一个快速示例函数,用于确定数据集中具有最高值计数的类别,然后从数据中删除这些类别,并将它们用作引用类别。使用相同的方法,您可以修改函数来选择拥有数据集中最常见属性以外的属性的类别,以用作引用。

作者代码

太好了,现在我们有了最常见类别的列表。现在我们可以把这些从虚拟变量的数据框架中去掉。

作者代码

太好了!现在我们已经用虚拟变量准备好了数据,我们知道哪些是参考类别。我们准备运行逻辑回归!

到赔率比

我已经略微谈到了对比值比的解释,但是让我们再深入一点。在我们将逻辑回归模型拟合到我们的数据之后,查看 statsmodels 的输出是有帮助的。

statsmodel 逻辑回归输出,图片由作者提供。

在这里,您可以看到左侧列出的所有特性,包括虚拟变量(省略了参考类别!)及其相应的统计数据。让我们分别关注第一列和第四列中的系数(coef)和 P 值(P>|z)。

该系数代表的对数优势比。由于这篇文章有一个很棒的解释,我不会在这里赘述,但它值得做一个高层次的总结。

几率是某件事情发生的概率超过它没有发生的概率,记为(p/(1-p ))。如果自行车旅行超过 20 分钟的概率是 25%,那么这个概率是 0.25/(1-. 25)= 0.33。所以在 100 次自行车旅行中,有 33 次会超过 20 分钟。

比值比是两个比值之间的比率或比较,以观察它们在不同情况或条件下如何变化。特征的比值比是条件 1 中自行车旅行超过 20 分钟的比值,与条件 2 中自行车旅行超过 20 分钟的比值。

正的比值比表明该事件更有可能发生,而负的比值比表明该事件不太可能发生。

注意,系数是对数比值比。对数优势比的“对数”部分就是优势比的对数,因为逻辑回归使用对数函数来解决回归问题。仅仅使用比值比要容易得多,所以我们必须取对数比值比的指数 (np.exp())来得到比值比。

对于分类特征或预测因素,比值比比较每个预测因素类别相对于参考类别的事件发生几率,假设所有其他变量保持不变。

好了,理论完成后,让我们来看几个例子,看看这在实践中是如何工作的。

注意。我们的引用类别是每个特性中最常见的,在我们的例子中是:

  • [user _ type]=‘订户’(另一个选项是‘客户’,我假设是指付费乘车的非订户)
  • 【性别】=‘男性’
  • 【日类型】=‘工作日’
  • 【30 岁以下】=‘30 岁以上’
  • 【工作日】=‘星期三’

如果所有其他变量保持不变,给定优势比 exp(1.66) = 5.28 ,如果您是客户,则乘车超过 20 分钟的几率是订户的 5 倍。(也许他们是在充分利用他们的车,因为他们不是固定的付费用户!)

如果所有其他变量都不变,给定 exp(0.32) = 1.37 的比值比,如果你是女性,那么骑行超过 20 分钟的几率比男性高 37%。

如果所有其他变量都保持不变,给定优势比 exp(-0.07) = 0.92 ,如果你的年龄在 30 岁以下,那么骑行超过 20 分钟的几率比 30 岁以上的人低 8%。

在工作日或周末,如果所有其他变量保持不变,超过 20 分钟的乘车几率几乎不变,给定的几率比为 exp(0.002) = 1.003

所以,我们有它!我希望这有助于解释更多关于在逻辑回归中使用分类特征的问题,并且 1)你应该关心你使用的参考类别,2)你有选择的权力,3)对于分类变量来说,优势比并不是很难把握。

你可以在我的 GitHub 库这里看到我的全部代码。感谢阅读:)

如何面试正在面试你数据工作的公司

原文:https://towardsdatascience.com/how-to-interview-the-company-that-is-interviewing-you-for-data-jobs-3b4fcce77c03

利用面试最后 5 分钟的指导方针

照片由西格蒙德Unsplash 拍摄

1。背景——面试不是单向的选择

开始一份新工作既令人兴奋又让人害怕。在我之前的博客里,我讲过一个 4 步法在面试中谈你的项目 。对于许多寻找新角色的人来说,开始新角色就像买了一个“神秘盒子”——在你打开盒子之前,你不知道里面是什么。尤其是对于像数据科学家、数据工程和数据分析师这样的数据工作来说,“典型的工作日”可能会有很大的不同——对于同一行业甚至同一公司的角色来说。即使你有相同的头衔,你使用的工具,需要的技能,以及项目使用的数据种类也因团队而异。因此,了解你需要什么和你的工作是至关重要的。

我怀疑没有人会喜欢惊讶地发现新工作与他们想象的相去甚远,尤其是以一种不受欢迎的方式。许多人努力准备在面试中展示自己最好的一面,以给公司留下深刻印象,但许多经验不足的候选人通常会忽略一点:评估和面试公司,而不仅仅是让公司评估你。

2.什么时候?

现在我们知道我们想在面试中更多地了解这个职位,下一个问题是我们什么时候可以对公司进行面试?通常,在面试中,最后 5-10 分钟是被面试者向面试官提问的时间。很高兴能得到我们需要的关于新工作的答案。如果你认为这个时间不够或者没有机会完成这一步,我建议你提出来,要求一些时间来完成你的采访部分。

3.谁啊。

大多数人可能认为未来的经理是提问的最佳人选,但我不建议你在考虑面试人员时有这样的限制。每个人都有自己的角色和观点,但每个人都可能因为自己的立场而有所偏颇。因此,你应该学会根据受访者的角色问什么问题。在讨论什么是好问题之前,我们先来了解一下面试官的角色是如何决定你的问题内容的:

作者图片

人力资源(部)

人力资源筛选通常是大多数数据工作的第一次面试。对话通常是关于一些一般性的问题,比如你目前的工作状况、签证状况、换工作的动机、面试过程等等。我建议你问更多关于面试过程的细节问题,而不是公司文化。我不是说你不应该“面试”人力资源,我的意思是问人力资源关于公司文化不如弄清楚你会有什么样的面试以及如何准备面试,因为在对话中与人力资源的时间有限。

未来经理

没有好经理的支持,很难有成功的职业生涯。然而,在一些面试中(新毕业生或普通员工),你可能没有机会和你未来的经理交谈——事实是,在这次面试中,你可能不知道谁会是你的经理。

对于直接招聘过程,经理可能是决定你的报价的最重要的人。他/她是最能帮助你在新角色中成长的人。所以,在面试中,他/她是一个很好的资源来了解团队的大范围,以及对你工作的期望。你需要确保你能接受他的管理风格,以便将来共事。

未来的同事

同一个团队的同事可能是你在工作中互动最多的人。他们通常已经在团队中呆了一段时间,熟悉团队的运作方式,以及你的新角色的日常生活。你想从他们那里了解的是球队的氛围和文化。

未来的商业伙伴

他们通常会在“小组面试”阶段与你交谈。他们的角色可能是您的 LOB 合作伙伴(业务线)、内部客户、产品经理、项目经理等。他们的工作会受到你的影响,但他们不一定和你在同一个团队,也不一定了解 data/ML。因为他们依靠你的工作来完成他们的工作,他们会对你的表现有所期待。

其他面试官

在你的新工作中,你很少或永远不会再与面试官共事,这种情况并不少见。这些人可以是你团队之外的其他员工、另一个姐妹团队的经理或部门主管。虽然你们两个都知道你们以后不会有太多的互动,但我仍然认为它们是了解这个部门或公司本身的很好的资源。

总之,我鼓励你向每一个面试你的人提出有价值的问题,无论是你未来的老板、同事、商业伙伴,还是另一个团队中永远不会在新工作中与你共事的人。

4.怎么会?

接下来要讨论的重要事情是什么问题好问。虽然每个人在工作中可能会有不同的衡量标准,但我建议从以下几个方面来评估这份工作:

作者图片

4.1 技术要求

如上所述,根据角色的不同,实际工作可能会有很大的不同。如果面试官在面试中没有提到这些问题,你可能会问这些问题:

  • 这个角色最大的挑战是什么?

问谁?
询问未来的经理和同事,因为他们可能会提供不同的观点。你也可以问问未来的商业伙伴。
问这个问题我们想学什么?对于经理来说,这个答案表明了他/她对你工作的期望——他/她需要员工好好处理的领域。对于未来的同事,他们的回答代表了这份工作的潜在痛点,从中你可以预测什么可能会让你生气。例如,如果他们的答案是“为 ML 模型获取干净的数据”。那么你知道伟大的数据清理技能对于这份工作是必要的。

如果这份工作需要你和商业伙伴密切合作,你可以问他们这个问题。与经理类似,他们会对经常合作的人设定期望。

  • 常用的工具有哪些?更具体地说,是什么编程语言(例如 Python R,SAS)。他们使用什么云服务(例如 Google cloud 或 AWS)?什么样的数据库/数据湖(如雪花、Qubole)?

问谁?
未来的同事。如果你不能从未来的同事那里得到答案,你也可以问未来的经理。
我们通过问这些问题想了解什么?职位描述通常会列出理想候选人的技能。但有时描述要么太笼统,要么列出 100 项技能。确认所需的技能永远不会有坏处,而且知道你目前的技能组合是否能满足这些技能也很关键。此外,问这个问题可以帮助你找出缺少什么,这样你就可以在新工作的第一天开始改进。

4.2 工作程序

你想确定你会喜欢新工作的工作节奏,这样你就会对日常生活有所了解。以下是一些可以问的好问题:

  • 这部作品中有多少与人的互动?

问谁?
未来的经理、同事和商业伙伴。
我们问这个问题是想了解什么?
数据工作需要与他人频繁互动。有些角色可能需要与客户、商业伙伴和同事等不同的人进行多次会面,因此您只有有限的时间来专注于开发 ML 模型或数据产品。在某些角色中,您可能会与来自不同背景的技术人员合作(例如,数据科学家与数据工程师一起工作),其他角色需要与非技术人员一起工作,以提供业务见解或数据产品。也有可能你独自工作,只向你的经理汇报。问这个问题可以帮助你了解你每天/每周的例行工作,看看你是否喜欢这种工作方式。当面试官是你未来的同事时,你也可以问一个相关的问题,比如“典型的一天是什么样的?”

  • 那里的工作生活平衡如何?

问谁?
未来的同事和其他不在你团队中的员工。
我们问这个问题是想了解什么?
不管你是喜欢保持忙碌,还是想要一些时间享受生活,你都应该经常问这个问题。这是一个比问“下班后我们多久需要工作一次”更好的问题。

4.3 行政信息

许多人忽略了它,但它很重要。世界每天都在变化。即使你是团队中最好的员工,也不要期望永远呆在原地。公司重组、领导层变动、政策调整……这些都会对员工个人产生巨大影响。保持警惕,做好准备,甚至在踏进公司之前。

  • 团队结构是什么样的?

问谁?
未来的经理和同事。
我们问这个问题是想了解什么?
这个团队是新成立的吗,你会是那里的第一个数据科学家吗?这个团队的扩大是因为更多的资金随着许多激动人心的新项目而来吗?还是团队在招人,因为最近有几个人走了?是的,团队的结构很重要,你可以想象在一个新的团队和一个成熟的团队中工作是非常不同的。

你可能还想了解这个团队中的其他人。例如,对于一个中级数据科学家角色,我建议你询问团队中是否有其他 d。有为数据模型做管道工作的数据工程师吗?是每个人都有技术背景的数据科学团队,还是你将是团队中唯一支持所有其他非技术人员的 DS?

为什么会有这些问题?我认为它们与你的职业目标高度相关。当我还是一名初级员工时,我想在一个有高级 DS 的团队中工作,我可以向他们学习。我想在一个成熟的团队中工作,那里的人有经验,知道做事的最佳方式。每个人都有不同的职业目标,所以要确保新工作能适合你的需求。

  • 团队坐在公司的什么位置?

问谁?
未来的经理,可能是同事和商业伙伴。
问这个问题我们想学什么?
我们问这个问题是想看看这个团队是一个“成本中心”还是一个“利润中心”。成本中心,也称为收入中心,是公司内部的一个小组或部门,其职能有助于业务运营,但不直接产生收入。利润中心是公司中直接产生收入和利润的部门。

与数据相关的角色可以位于成本中心或收入中心。一些公司依靠 ML 或其他数据产品以各种方式产生利润,因此创造这些产品的团队是这些公司的核心。此外,一些公司建立他们的人工智能或人工智能部门来支持他们的核心业务。换句话说,这些公司用传统的方式经营他们的业务,ML 是好东西,但不是必需的。我并不是不鼓励你在成本中心工作,但我认为如果你想减少因一些不可预测的情况而被解雇的可能性,在成本中心工作的风险要比在利润中心高。

4.4 自我发展

  • 公司提供了哪些增长机会?

问谁?
未来的经理和同事。
我们问这个问题是想了解什么?我认为在评估这份工作时,了解未来的发展机会是很重要的。工作不仅仅是用工作来换取金钱;这也是为了积累经验和成长。尤其是因为数据工作需要终生学习,30 年后我们不太可能在工作中使用同样的工具和技术。我建议你问问团队或公司是否提供在线学习平台,如 LinkedIn learning 或 DataCamp,以及他们是否鼓励员工参加研讨会和会议。如果你打算获得另一个学位,你也可以问问他们是否有学费资助。

5.请尽量避免问这些问题

  • 关于金钱和利益的问题。

无论你多么急切地想知道薪水,不要在面试中讨论,尤其是和未来的经理。你可以在人力资源筛选时讨论这个问题,也可以在得到工作机会后再和经理讨论。

  • 我在面试中搞砸了吗?

我明白当你认为自己没有展现出最好的一面时,你可能会感觉很糟糕,但尽量不要在面试的最后 5 分钟问这个问题。面试官有他们的判断,你可能认为你搞砸了,但也许你比其他候选人做得更好。或者面试官问你一些具有挑战性的问题来测试你如何应对高压。不要表现出你对得到这份工作没有信心,永远不要!

总结——也是关于你的!

对大多数人来说,找到你的下一份理想工作从来都不是小菜一碟。请记住,工作是一个双向选择,不仅仅是公司找到它需要的东西,还包括找到一个你乐意工作、学习、成长和成为更好的自己的地方

感谢您的阅读,我希望这篇博客对您的数据求职有所帮助, 这里还有一篇关于数据面试的博客,您可能会对 感兴趣。我希望你能得到一个好的报价。祝你好运!

💖喜欢这个故事吗?请随时订阅 DS 和 ML 粉丝的邮件列表,并成为媒介会员!🤩

这篇博客最初发表在我的个人网站上。

参考
【1】https://www . indeed . com/career-advice/career-development/profit-center-vs-cost-center

如何凭直觉发现检察官的谬误(并进行更好的假设检验)

原文:https://towardsdatascience.com/how-to-intuit-the-prosecutors-fallacy-and-run-better-hypothesis-tests-2d8561bfc5a6

面向商业领域的数据科学家和分析师

廷杰伤害律师事务所Unsplash 上的照片

被告与犯罪现场发现的 DNA 匹配的可能性只有百万分之一。所以被告是有罪的。听起来还好吗?不是的!

仅仅基于这一证据,被告很有可能是无辜的,这是不直观但非常有启发性的检察官谬误所描述的逻辑陷阱。

当我们理解了这一点,我们就开始在广告、媒体和人们的日常决策中处处看到它。它也是正确解释 p 值的一个常见困难的基础,对此获得更好的直觉会使我们如何在商业环境中进行假设检验变得更加清晰。

再举一个例子。您因严重疾病进行的医学测试呈阳性。当你回忆起测试的准确率为 95%时,你感到一阵恐慌。然而,你真正的机会可能比这大得多——也许你真的有 10%的机会。这怎么可能呢?

学习目标

本文的第一个目标是对检察官的谬误作一个总体介绍,并用通俗易懂的语言解释它,针对使其难以直观理解的原因。如果你没有遇到过它或者对它的概念不清楚,那么无论你走哪条路,它都是一个很好的生活工具,我希望你会像我一样发现学习它的乐趣。

文章的第二部分将探讨在使用假设检验时,检察官的谬误如何在 p 值的解释中发挥作用,并针对执业数据专业人员。如果你很难解释为什么 p 值不是你的零假设为假的概率,而是你得到的结果与给定零假设时观察到的结果一样极端的概率,这是值得理解的——继续读下去。

理解检察官的谬误

附件 A

所以被告与犯罪现场的 DNA 匹配的几率是百万分之一。这是一个高度准确的 DNA 测试,已经有一个阳性匹配。然而,无论这一证据看起来多么令人信服,仅凭这一点并不能证明被告有罪。不是因为这个概率中还有少量的不确定性(从来没有绝对的确定性),而是因为给出无罪证据的概率给出无罪证据的概率不一样。

为了理解这意味着什么,让我们首先假设我们正在一个 1000 万人口的城市中寻找罪犯(加上一个罪犯)。而且有 100%的把握,真正的罪犯的 DNA 会与犯罪现场的 DNA 相匹配。

把这些数字放在一个表格里,我们得到这个:

作者图片

现在,我们被告知,只有百万分之一的机会,一个无辜的人会得到 DNA 匹配。因此,如果我们要测试这个城市所有的 1000 万人,我们希望其中有 10 人匹配。

将此添加到表格中:

作者图片

现在看看所有无辜的人,他们的 DNA 都符合这个场景。事实上,无罪匹配的数量比正确有罪匹配的数量多十倍!这是 10 次假阳性对 1 次真阳性。

用百分比表示,那么整个城市给出证据的有罪概率是 1 / (1 + 10) = 9.1%。仅根据这一 DNA 证据,现在看起来被告有 1–9.1% = 90.9%的无罪几率,这与检察官最初声称的 0.0001%的无罪几率形成了鲜明对比。

作者图片

最初声明的含义是,由于只有百万分之一的无辜者会与 DNA 匹配,而被告与 DNA 匹配,他们有罪的概率是 1–0.000001,这几乎是必然的。但是这种逻辑是有缺陷的,尤其是当概率适用的人群很大的时候;我们从数据中得出的结论可能会像这个例子一样发生戏剧性的转变。DNA 匹配无罪的概率不能与 DNA 匹配无罪的概率相混淆。

那是不是说我们在刑事审判中对 DNA 证据无能为力?我们可以,但这里的关键是要明白,需要有其他理由相信被告有罪。如果我们仅仅依靠 DNA 匹配,我们就会暴露在虚假的匹配面前,但是如果我们已经对某人有了其他的怀疑,那么这个额外的证据将是非常令人信服的。我们还可以使用 DNA 来缩小嫌疑人的范围,以帮助集中调查(根据对金州杀手的追捕),但这不是决定性的,这与我们将在第二部分探讨的假设检验中使用 p 值有重要的相似之处。

这里值得一提的是,检察官谬论的一个延伸是辩护人谬论,其中错误地认为,一项指控被告有罪的证据应该被放弃,因为它可以与许多其他证据相匹配。这被用于 OJ Simpson 的审判中,辩护律师认为,与 OJ 匹配的现场血液样本(400 分之一的匹配率)也可以与洛杉矶数以千计的其他人匹配,因此不是有用的证据。这是对检察官谬论的曲解,证据是有用的,因为它是与其他证据一起考虑的,尽管它本身并不具有决定性。

附件 B

这是你一直害怕的消息。您很健康,但已接受了一种罕见疾病的筛查,您接受的“95%准确率”测试呈阳性。你感到麻木。但是你应该吗?

在这里,我们首先遇到“准确性”意味着什么的问题,在医学测试中,术语特异性 用于定义准确性的两个不同方面:

  • 敏感度:患病者被正确识别为患病的可能性(真实阳性率)
  • 特异性:未患病者被正确识别为未患病的可能性(真实阴性率)

对于本例,我们将假设 95%的准确度适用于灵敏度特异性。我们假设这种疾病会影响 1/1000 的人口。

因此,在 1000 万人口中,我们预计会有 10,000 人患有这种疾病。把这些数字放在一个表格里,我们就有了这幅图:

作者图片

另一种可能更直观的表达方式是使用决策树:

作者图片

有了这些数字,假设你刚刚进行了阳性测试(并且没有其他理由相信你患有这种疾病),你患有这种疾病的几率为 9500/(9500+499500)= 1.87%。

即使这种疾病在人群中流行了 10 倍,在得到阳性检测后,你患这种疾病的可能性也只有 16.1%。最重要的是,将测试的特异性提高到 99%,你的几率仍然是 49%。(在澳大利亚,COVID 家用快速抗原检测试剂盒必须经过认证,灵敏度为> 80%,特异性为> 98%)。

最初的 95%的“准确性”测量没有给你足够的关于患该疾病的实际概率的信息,因为你错过了关于该疾病在人群中的流行率的信息,因此错过了你患该疾病的先前可能性。

如果您患有某种疾病,那么您获得阳性检测结果的概率(95%)与您在检测结果中患有该疾病的概率是不同的,为了对您患该疾病的可能性做出任何判断,您首先需要知道您患该疾病的可能性有多大,而不管检测结果如何(ABC 使用真实世界 COVID 情景的精彩评论此处)。

先验概率和随着新信息(如 COVID 测试结果)的出现而更新概率的想法在贝叶斯框架中被正式化,著名的贝叶斯公式为我们刚刚通过列联表说明的内容提供了一条捷径。这是改天的话题。

检察官的谬误是如何进入假设检验的

从这一点来说,我假设你有一些假设检验的背景知识,并有一些概念的工作知识,如检验统计,零假设和 p 值。这个可能是下一个去的好地方,如果你不感兴趣的话。

本节的重点将是对 p 值有一个更好的直觉,特别是 p 值是而不是零假设为真的概率;p 值 0.05 是而不是零假设为真的概率为 5%,或者替代假设为真的概率为 95%。更确切地说,这是得到观察到的结果的概率(或者更极端的情况),假设零假设,这种差异很难凭直觉理解,更不用说在现实世界中组织测试时帮助他人理解了。

有关系吗?

首先,这种措辞上的差异真的有关系吗?实际上,这不是一回事吗?事实并非如此,原因来自于同样的区分,这些区分使得检察官的谬论成为一个陷阱,并带来严重的实际后果。

不理解这种差异的危险在于,我们可能会从我们的测试结果中得出毫无根据的结论,就像检察官对被告的无辜提出错误的主张一样。

具体来说,当我们认为可以:

  • 在多个区段重复测试,直到我们的 p 值低于 0.05
  • 将我们最初的测试结果分成几个子集,并指出任何 p 值低于 0.05 的结果都是有意义的

附件 C

想象一下,你是一家超市,在你的网站上测试可口可乐的广告,并把你的在线客户分成两部分,在 A/B 测试中,一半看到广告,另一半看不到。您仔细计算了所需的样本量,并让数据累积起来,但在测试结束时,您失望地发现两组之间的可乐销售没有显著差异。

但是,你想,如果它引起了某些客户群体的共鸣呢?所以你去探索不同的细目分类,并开始注意到各处 p < 0.05 的结果:住在纽卡斯尔的顾客,倾向于价值产品的退休者,购买大量奶酪的人…

营销人员变得兴奋起来。也许我们在这里有所发现。是的,纽卡斯尔的人们会对可口可乐的广告反应良好,这是有道理的,因为我们目前正在那里的市中心做一个大型广告牌广告,它已经在顾客的脑海中浮现了。让我们加倍努力,继续在网上锁定这个群体。

这是一种错误的推理,类似于检察官从人群中随机挑选人,直到出现阳性 DNA 匹配,并声称有罪,尽管实际可能性为 9.1%。事实上,似乎有证据支持这个(广告牌)是确认偏差;如果我们去寻找正当理由,我们经常会找到,但仅仅因为事后看来它们是合理的,并不意味着它们是相关的。注意不要后理性化。

为了解开这个问题,我们将再次使用列联表。再次从我们的第一个例子的数字,阴影部分基本上是什么 p 值代表。

作者图片

但是我们真正感兴趣的是:

作者图片

那么为什么我们不能只测量这个呢?原因很简单,当我们进行假设检验时,我们没有办法测量底部“有罪”框的数量。我们所能做的最好的事情就是通过收集样本数据来填写最上面一行,然后做出一个推论。

如果我们确实观察到了与 p 值为 0.05 的广告的“显著”差异,那么将此转换为我们的可口可乐广告 A/B 测试示例,我们可能会得到如下结果:

作者图片

这与双重否定相混淆,但最上面一行是说,如果可口可乐的广告真的对销售没有影响,我们只能获得 100 次中的 5 次(或者更极端)销售结果。考虑到无效假设,这是一个非常令人惊讶的结果。

但关键的是,这并没有说可口可乐的广告是否真的对销售有影响(在替代假设下的真实效果)。为了获得一个位置,我们需要在左下角的框中输入一个数字,这不是我们可以通过 A/B 测试或任何其他方式收集的数据。

为了帮助我们理解为什么 0.05 便士的价值与可口可乐广告的效果没有直接关系,让我们试着输入一些假设的数字。

这里能放什么?先说‘1’吧。这是一个任意的数字,只对上面的方框中的“5”有意义,但我们遵循的逻辑与我们在前面的例子中用来说明检察官谬误的逻辑相同。

作者图片

所以现在,尽管 p 值为 0.05,我们得到可口可乐广告产生差异的概率仅为 1 / (1+5) = 17%。

现在让我们试着输入一个更大的数字;比如说 45 英尺。这给了我们一个概率,广告产生了 45 / (45+5) = 90%的差异。同样的 p 值,我们可以从数据中得出两个截然相反的结论。

作者图片

但是,抛出这些没有基于真实、可测量数据的假设数字有什么意义呢?这是这次讨论的关键,也是在现实世界中更好地实践假设检验的关键。你在这里输入的数字代表你之前对假设的信心。

数字越高,你的信心越高。我们通过在这里插入不同的数字来证明,p 值 0.05 和我们假设为真的概率没有关系。如果测试一开始就是一次登月,即使有有利的 p 值,你仍然有理由持怀疑态度。先前的定罪在假设检验中很重要

如前所述,贝叶斯思维模型提供了一种数学处理这种先验信念的方法,但是 p 值和置信区间的频率主义模型是当今商业世界中 A/B 测试的事实标准,这种推理中的陷阱经常被忽视。p 值不能取代人类推理的需要,我们必须从假设中的一些先验信念开始,测试结果和 p 值才是有用的。如果这变得不直观,回想一下检察官的例子。

把所有的放在一起

  1. p 值并不能说明假设是否成立。不要纯粹根据测试是否通过了某个 p 值阈值来下结论。
  2. p 值是观察到结果的概率或更极端的情况,假设为零假设。这不同于给定证据的零假设的概率。检察官的谬论说明了为什么这种区分很重要。
  3. A/B 测试的 p 值有助于验证我们的假设,如果我们首先有充分的理由相信它的话。
  4. 不要去寻找有吸引力的 p 值,并根据它们进行逆向推理。如果您发现某个细分市场的 p 值出乎意料地低,最好的办法是使用特定于该细分市场的新测试来验证它。

在商业决策中使用 p 值

当在商业世界中用 p 值进行假设检验时,要清楚它们的正确用法,并准备好解释它,但不要觉得你需要强烈反对 p 值的每一次滥用才能成为一个好的顾问。

我们在需要快速做出决策且数据不完善的环境中工作,因此,如果决策者需要根据不可靠的数据不时凭直觉做出决策,请不要犹豫;毕竟,自信是等式的一部分。

因此,即使在你知道正确的做法是重新运行测试的情况下,如果这样做的成本超过了继续决策的成本,那么它可能没有很好的实际意义。明确你的立场,但没有必要在每个决定上都力求严谨。

进一步阅读

统计艺术将 p 值描述为“弱证据”(即决策中的一个因素,但远非唯一因素),并就我们如何在其他证据之上构建强有力的案例提供了一些很好的评论。

例如,在法庭上,不同的证据可以被逐项列出,每个证据被赋予不同的可能性比率(如果被告有罪,证据的概率/如果被告无罪,证据的概率),有可能将它们相乘,以量化案件的实力,尽管英国法院没有这样做,因为这是陪审团的作用。

关于回答问题和声称发现从经验中学习贝叶斯方法的章节充满了像这样的伟大的现实世界的例子和权衡证据的不同思想流派。

我还从系列讲座中获得了一些灵感,称之为扯淡,特别是关于“ P 值和检察官的谬误”的讲座。

如何在笔记本上与汉密尔顿迭代

原文:https://towardsdatascience.com/how-to-iterate-with-hamilton-in-a-notebook-8ec0f85851ed

对于那些不知道的人来说, Hamilton 是一个通用的微框架,用于指定数据流,例如指定 Pandas 转换。它帮助你构建你的代码库,并改进你的代码,例如,你总是用 Hamilton 编写单元可测试转换代码。它通过引入一种范式来做到这一点,在这种范式中,函数必须以自以为是的、声明性的方式来编写。参见这篇 TDS 帖子获取更广泛的介绍。

使用 Hamilton 的一个开发含义是,它迫使您从一开始就将 python 函数组织成模块。如果在笔记本中迭代是您的开发方式,那么在笔记本环境中使用 Hamilton 似乎很困难。在本帖中,我将解释如何在笔记本上舒适地迭代汉密尔顿 DAG。

步骤 1 —安装 Jupyter & Hamilton

我假设您已经设置了这个步骤。但是以防万一你没有:

pip install notebook
pip install sf-hamilton

然后,要启动笔记本服务器,应该是:

jupyter notebook

步骤 2—设置文件

  1. 启动你的 Jupyter 笔记本。
  2. 转到您希望笔记本和 Hamilton 功能模块所在的目录。
  3. 创建一个或多个 python 文件。通过“新建>文本文件”来完成。它将打开一个“文件”编辑器视图。给文件命名并给它一个.py扩展名。保存之后,您会看到 jupyter 现在提供了 python 语法高亮显示。保持此选项卡打开,以便您可以翻回到它来编辑此文件。
  4. 启动将在另一个浏览器选项卡中使用的笔记本。

步骤 3——迭代的基本过程

概括地说,您将在选项卡之间来回切换。您将向汉密尔顿函数 python 模块中添加函数,然后将该模块导入/重新导入到笔记本中以获得更改。然后,您将像往常一样使用 Hamilton 来运行和执行事物,并使用笔记本来执行您使用笔记本执行的所有标准事物。

让我们看一个例子。

这是我添加到我们的哈密尔顿函数模块的一个函数。我将模块命名为some_functions.py(显然选择一个更适合您情况的名称)。

import pandas as pddef avg_3wk_spend(spend: pd.Series) -> pd.Series:
    """Rolling 3 week average spend."""
    print("foo") # will use this to prove it reloaded!
    return spend.rolling(3).mean()

下面是我在笔记本上设置的内容,以便能够使用 Hamilton 并导入该模块:

单元格 1:这只是导入了我们需要的基本东西。

import importlibimport pandas as pdfrom hamilton import driver

单元格 2:导入您的汉密尔顿功能模块

# import your hamilton function module(s) here
import some_functions

单元格 3:每当你对some_functions.py做出更改并保存时,运行这个单元格

# use this to reload the module after making changes to it.
importlib.reload(some_functions)

这样做的目的是重新加载模块,从而确保代码是最新的,以供您使用。

单元格 4:使用汉密尔顿

config = {}
dr = driver.Driver(config, some_functions)
input_data = {'spend': pd.Series([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])}
df = dr.execute(['avg_3wk_spend'], inputs=input_data)

运行该单元后,您应该会看到作为输出打印的foo

好的,现在让我们说我们正在迭代我们的哈密尔顿函数。在另一个浏览器选项卡中,转到您的 Hamilton 功能模块(本例中为some_functions.py),将print("foo")更改为其他内容,例如print("foo-bar").保存文件——它看起来应该是这样的:

def avg_3wk_spend(spend: pd.Series) -> pd.Series:
    """Rolling 3 week average spend."""
    print("foo-bar")
    return spend.rolling(3).mean()

回到笔记本,重新运行单元 3 和单元 4。您现在应该会看到一个不同的输出,例如foo-bar

恭喜你!你刚刚用 Jupyter 笔记本成功迭代了 Hamilton!

总结一下,在我看来事情是这样结束的:

  • 下面是我的some_functions.py文件的样子:

作者图片

  • 我的笔记本看起来是这样的:

作者图片

帮助:我正在使用谷歌 Colab,我不能做到以上几点

自从1.8.0发布以来,你现在可以用你的驱动程序内联定义函数来构建 DAG。我们强烈建议只有在绝对必要的时候才使用这种方法——用这种方法构建代码非常容易。

例如,假设我们想要添加一个函数来计算avg_3wk_spend的对数,而不是将其添加到some_functions.py,我们可以直接在笔记本中执行以下步骤:

# Step 1 - define function
import numpy as npdef log_avg_3wk_spend(avg_3wk_spend: pd.Series) -> pd.Series:
    “””Simple function taking the logarithm of spend over signups.”””
    return np.log(avg_3wk_spend)

然后我们必须创建一个“临时 python 模块”来存放它。我们通过导入ad_hoc_utils然后调用create_temporary_module函数,传入我们想要的函数,并为我们正在创建的模块提供一个名称。

# Step 2 - create a temporary module to house all notebook functions
from hamilton import ad_hoc_utils
temp_module = ad_hoc_utils.create_temporary_module(
     log_avg_3wk_spend, module_name='function_example')

现在,您可以像对待 python 模块一样对待temp_module,并将其传递给驱动程序,像平常一样使用 Hamilton:

# Step 3 - add the module to the driver and continue as usual
dr = driver.Driver(config, some_functions, temp_module) 
df = dr.execute(['avg_3wk_spend', 'log_avg_3wk_spend'], inputs=input_data)

这种方法的注意事项:

使用“临时 python 模块”不会通过在 Spark 上使用 Ray、Dask 或 Pandas 来实现计算的缩放。所以我们建议只将这种方法用于开发目的。

提示:你可以直接导入函数

将 Hamilton 函数放入一个模块的好处是,在另一个上下文中重用它非常容易。例如另一个笔记本,或者直接。

例如,很容易直接使用笔记本中的功能,就像这样:

some_functions.avg_3wk_spend(pd.Series([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))

它调用我们在some_functions.py模块中定义的avg_3wk_spend函数。

提示:您可以使用 ipython magic 来自动加载代码

并排打开 Python 模块和 Jupyter 笔记本,然后将% auto reload ipython magic添加到笔记本以自动重新加载单元格:

from hamilton.driver import Driver

# load extension
%load_ext autoreload
# configure autoreload to only affect specified files
%autoreload 1  
# import & specify my_module to be reloaded 
# i.e. this is the data transformation module that I have open in other tab
%aimport my_module  

hamilton_driver = Driver({}, my_module)
hamilton_driver.execute(['desired_output1', 'desired_output2'])

然后,您将遵循以下流程:

  1. 在 open python 模块中编写数据转换
  2. 在笔记本中,实例化一个 Hamilton 驱动程序,并用一小部分数据测试 DAG。
  3. 由于%autoreload,每次执行 Hamilton DAG 时,都会使用最新的更改重新导入模块。这种方法防止了无序的笔记本执行,并且函数总是驻留在干净的地方。py 文件。

鸣谢: Thierry Jean 的博客文章提供了这最后一个技巧。

最后

感谢你阅读这篇文章。我们很乐意帮助您成功使用汉密尔顿。欢迎在我们的 github 知识库中留下问题/评论(我们也很喜欢⭐️!),或者加入我们的 slack 服务器寻求帮助,或者提供建议/改进。

如何用 GitHub Pages 和 Jekyll 启动你的个人网站

原文:https://towardsdatascience.com/how-to-launch-your-personal-website-with-github-pages-and-jekyll-7b653db43ec0

一个完整的一步一步的指南,自动化繁重的工作,让您专注于内容

照片由斯科特·格雷厄姆Unsplash 上拍摄

建立自己的网站是脱颖而出的好方法,也是在网上建立个人品牌的好方法。在这篇文章中,我将分享一个逐步建立和启动一个看起来干净、专业且易于维护的网站的指南。您将学习如何:

  • 使用静态站点生成器 Jekyll 在本地构建您的站点,
  • 在网站托管服务 GitHub Pages 上托管您的网站,
  • 将您的站点连接到您选择的自定义域,并
  • 添加动态内容,例如来自您的 Twitter 订阅源的内容。

最重要的是,有了这个设置,你可以在简单的 Markdown 中完成所有的内容创建,而 Jekyll 则负责将你的文字转换成 html。(关于演示,请查看我自己的网站这里。)

让我们开始吧。

1.安装 Jekyll

Jekyll 是一个将 markdown 文件转换成 html 的 Ruby 应用程序。为了使用 Jekyll,你首先需要安装 Ruby。在苹果电脑上,你可以用自制软件做到这一点:

brew install chruby ruby-install xz
ruby-install ruby

从技术上来说,你刚才做的是先安装chruby,它只是一个简单的小 shell 脚本,然后用chruby安装最新版本的ruby。现在运行以下命令来配置您的环境(最好将这些行添加到您的。巴沙尔或者。zshrc):

source /opt/homebrew/opt/chruby/share/chruby/chruby.sh
source /opt/homebrew/opt/chruby/share/chruby/auto.sh
chruby ruby-3.1.2

现在你可以在你的 shell 中使用 Ruby 的包管理器gem。执行以下命令:

gem install Jekyll

去安装哲基尔。就是这样!

👉不是 Mac 用户?Jekyll 也可以安装在 Windows、Ubuntu 或其他 Linux 系统上。查看此处的说明

2 .建立一个新的 git repo 并在本地构建您的站点

首先,你需要在 GitHub 上创建一个账户,如果你还没有的话。然后,您创建一个新的 repo,它可以命名为“site”,并将其克隆到您的本地计算机上:

git clone git@github.com:<your username>/site.git

site目录中,你现在可以运行:

jekyll new --skip-bundle . --force

这初始化了一个新的 Jekyll 项目,并创建了一堆文件,您将使用这些文件来创建您的网站,最重要的是:

  • Gemfile包含执行 Jekyll 所需的 gem 依赖关系,
  • 是 Jekyll 配置,它决定了你的站点的外观
  • index.md是你网站的首页。这是您添加第一个内容的地方。

接下来,您需要对代码做以下两个小的更改:

  1. Gemfile里面,注释掉了这一行:
#gem "jekyll", "~> 4.2.2"

改为添加这一行:

gem "github-pages", "~> 227", group: :jekyll_plugins

👉这条线到底是做什么的?这告诉您的 Ruby 编译器,不要直接用 Jekyll 构建站点,而应该用 GitHub Pages Ruby gem 来构建,它拥有在 GitHub Pages 中运行 Jekyll 的所有依赖项。

2.在_congig.yml里面,注释掉这两行:

#baseurl: "" 
#url: ""

这是因为 Github 页面会在构建过程中自动设置这些 URL。

最后,跑

bundle install

这将在本地构建 html 网站,使用来自Gemfile的依赖项、_config.yml中的 Jekyll 配置和目录中 Markdown 文件的内容。

3.在本地测试你的站点

运行以下命令:

bundle exec jekyll serve

这将输出一个本地 URL。将此粘贴到您的浏览器中以预览网站。如果您得到错误消息“无法加载这样的文件— webrick”,只需运行bundle add webrick; bundle install。这将 webrick 包(一个 HTTP 服务器工具包)的依赖性添加到了 Gemfile 中。

每次您保存对 markdown 文件的更改时,Jekyll 都会自动更新网站,您只需刷新浏览器即可查看更改。

👉不想记住这个命令?只需运行echo 'bundle exec jekyll serve' > dryrun.sh。现在你可以简单地运行bash dryrun.sh来测试你的站点

4.部署站点

提交所有本地更改并将它们推送到 github:

git add .
git commit -m 'first commit'
git push origin master

在您的 GitHub repo 页面上,请访问:

Settings → Code and automation → Pages → Build and deployment → Deploy from branch

并选择要部署的分支(如主)。现在,GitHub 将运行自己版本的 Jekyll 来构建和部署您的站点。如果您使用site作为回购的名称,您的网站现在将托管在:

https://www.<your username>.github.io/site

每次您向存储库中推送新内容时,这些内容都会在几分钟内自动部署到生产环境中。

👉想要立即强制重建一个站点吗?单击“已部署”链接,然后单击“重新运行所有作业”。

5.添加自定义域

自定义域名更短,更容易让人记住,这可以为您的网站带来更多流量。以下是添加自定义域的方法:

  • https://domains.google.com查看你想要的域名是否可用。如果有,就购买。它应该花费你大约一个月一美元左右。
  • 在 google 域上,在 DNS 设置下,您需要添加两条记录,一条A记录和一条CNAME记录。在 A 记录中,列出这 4 个 IP 地址(指向 GitHub 的服务器):
185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
  • 在《CNAME 记录》中,简单地写着<your username>.github.io

现在,在 GitHub 上,进入设置→页面→自定义域,添加你的自定义域,点击“保存”。您的 Google 域名现在已连接到您的 GitHub 页面。

👉设置正确的 DNS 配置可能有点棘手。需要故障排除帮助吗?点击查看特伦特杨的帖子

6.内容,内容,内容

我自己网站上的 Twitter 小部件演示

一旦你的网站建立并运行,就有无限的可能性来添加更多的内容。以下是一些想法:

  • 添加一个 Twitter 小部件,列出您最近的推文。只需将这段代码添加到您的index.md中:
<a class="twitter-timeline" href="https://twitter.com/elonmusk?ref_src=twsrc%5Etfw">Tweets by elonmusk</a> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

(当然,你会想把 *elonmusk* 换成你自己的 Twitter 句柄。)

  • 从 Gumroad 添加您的电子书或课程。在 Gumroad 上,转到您网站上想要嵌入的产品,然后导航到共享→嵌入→模态叠加,简单地将代码复制粘贴到您的index.md下面是它在我的网站上的样子。
  • 添加一个小部件,显示您的最近的博客文章的提要。
  • 使用 Jekyll 帖子把你的网站变成一个个人博客

最后,一个好的实践是使用分支来开发你的站点:当添加一个新的特性时,在一个单独的分支中完成。然后,在 GitHub 上,可以尝试从新的分支部署站点。如果新特性破坏了您的站点,您可以快速将部署分支回滚到master

快乐创作!

📫 订阅 把我的下一篇文章直接发到你的收件箱。
💪
成为中等会员 并解锁无限权限。
🐦关注我上
LinkedInTwitter

如何以正确的方式学习复杂的话题

原文:https://towardsdatascience.com/how-to-learn-complex-topics-the-right-way-97ca39c4db3e

在最近的一次 Q & A 中,高级数据科学家安尼·马杜尔卡观察到“有大量内容适合初学者,也有大量内容适合研究人员,但对于中级专家来说,这些内容显得分散而杂乱。”我们牢记这一点。本周,我们将重点介绍一系列最近发表的帖子,这些帖子在解决高级和小众主题方面做得特别好,同时保持可访问性。它们非常适合那些有一定经验的从业者——他们希望拓宽自己的技能和知识。

我们开始吧!(如果你想听更多阿尼对 ML 职业挑战和其他话题的见解,请查看他的完整采访。)

Dinh PhamUnsplash 上拍摄的照片

  • 充分利用图和网络 如果你很想了解应用于图形的中心性度量和划分技术, Angel Das 的新解释器是一个很好的起点——它涵盖了深入社交网络分析和谱聚类之前的一些必要基础知识。
  • SHAP 价值观一站式指南 。阅读时间约为 80 分钟, Reza Bagheri 的《SHAP 价值观介绍》与其说是一篇博客文章,不如说是一个你在学习过程中可以多次查阅的资源。它深入 SHAP 图书馆的引擎盖下,展示了它是如何工作的,以及它如何应用于机器学习项目。

无论是现在,明天,还是下一次你有一个安静的时刻,我们希望你选择探索我们最近发表的其他几篇优秀文章。我们认为你不会后悔的。

如果你喜欢 TDS,欣赏我们作者的作品,可以考虑成为的媒体会员——它不仅支持作者,还为你的阅读乐趣打开我们的全部文章档案。

直到下一个变量,

TDS 编辑

如果想完成目标,如何学习数据科学

原文:https://towardsdatascience.com/how-to-learn-data-science-if-you-want-to-accomplish-your-goals-619b16552d77

我向你展示如何从头开始规划你的旅程,这样你就有希望释放你的潜力

Unsplash 上的奥克萨娜 V 拍摄的照片

目录

  1. 学数据科学有可能吗?
  2. 从哪里开始学习
  3. 如何创建学习地图
  4. 我的学习地图会是什么样子?
  5. 开始项目之前…
  6. 统计???
  7. 项目执念
  8. 如何有效利用项目
  9. 这需要多长时间?
  10. 关于目标的重要说明
  11. 附录

我喜欢定期更新自己的建议,告诉自己如何从零开始学习数据科学。数据领域变化很快,随着我自身知识的增长,我认为重新评估我推荐的方法很重要。

自从我之前努力传授这种智慧以来,我对学习数据科学的建议已经发生了变化。在这篇文章中,我给你我最新的方法,告诉你我将如何学习这个领域,并从中获得乐趣。作为免责声明,我不认为学习数据科学有一种“正确”的方法。不同的事情适合不同的人,你自己的尝试对你在任何职业中的成功都是不可或缺的。请务必阅读到最后,因为我回答了我在这个话题上最常被问到的问题:学习数据科学需要多长时间?

如果您喜欢视频格式,请点击此处观看:

学数据科学有可能吗?

首先,我想揭穿你可以“学习数据科学”的想法这意味着数据科学是一门静态学科,可以完整地学习。无论好坏,数据科学都在不断发展壮大。我不知道任何一个人,包括我自己,有可能了解整个领域。学习数据科学是一个旅程,而不是目的地,带着这种心态来学习可以让这个过程变得更加愉快。我看到很多学生被这个领域的巨大所淹没。如果你的目标是学习整个领域,这将是完全压倒性的。另一方面,如果你专注于一次只学一点点,并在头脑中有具体的小目标的情况下增长你的知识,这就变得容易管理了。

从哪里开始学习

话虽如此,让我们直接进入我想改变我以前的方法。回想起来,我对最开始的建议是非常模糊的。我通常会说类似“学习足够的 Python 和统计学来开始项目。”虽然这是个不错的建议,但这一次我想深入了解你应该如何开始这个学习过程。

作者图片

真正的第一步是了解该领域的组成部分,并为自己制定一个学习计划来导航旅程。如果我们没有任何明确的方向就跳进海里开始游泳,我们真的很容易累坏,可能会放弃。另一方面,如果我们有一张地图和一个明确的目标,我们至少知道我们正在进入什么。在做任何其他事情之前,您需要为您的数据科学学习创建此地图。真正酷的部分是,通过创建这个地图,你还会学到很多关于数据科学领域的知识。

作者图片

如何创建学习地图

那么,我该如何创建地图呢?有两种方法可以做到这一点,这两种方法在高空作业的水平上有所不同。最简单的方法是参加一个为你准备的在线课程或证书。这就是在线课程的巨大好处:它们可以为你规划出完整的学习路径,所以你只需要跟着走就行了。另一方面,它们要花钱。如果你愿意花时间为自己创建这个路线图,所有的信息都是免费的。明确一点,这里没有对错。不管你是否决定付钱给一个组织,做对你来说值得的事情。如果课程是你的速度,我在下面的附录中有 365 DataScience 的折扣代码;如果没有,我已经包含了一些链接到我最喜欢的免费资源。

下一个方法是查看多个在线课程、大学课程和其他资源,并大致了解它们是如何规划道路的。大多数付费课程让你了解课程的结构。然后,您可以基于您在那里看到的类和概念制定自己的路线图。通过这样做,您还可以感觉到该领域需要什么技能和技术。有趣的是,你可以看到什么是最有趣的,最吸引你的,并据此调整你的路线图。这对以后真的很重要。

我的学习地图会是什么样子?

好了,让我们为自己设定一个学习计划。我鼓励你在这里做你自己的研究,并根据你的兴趣和能力进行调整。

如果我为自己制定一个学习计划,我几乎肯定会从学习 Python 开始。编码语言允许你构建东西。如果你能建造东西,你几乎可以把你正在做的任何东西应用到实际问题中。我认为学习编程就像构建我的工具集一样。我可以赤手空拳搭建一个棚子,但是用锤子和电钻要容易得多。Python 是我的动力工具。我个人几乎总是觉得,与数学相比,编程是阻碍我提高学习速度的原因。需要说明的是,数学非常重要,我个人不会首先关注它。

对于编程,我会确保自己对变量、循环和函数等基础知识有扎实的理解。我也会非常专注于学习如何使用像 pandas 这样的导入库。事实上,我建议尽可能多的浏览熊猫文档。在我看来,为数据科学编码并不是真正的编码。你更多地利用其他人为特定目的而构建的工具。例如,我认为对熊猫的深刻理解会比对纯 Python 的非凡理解更好地服务于大多数数据科学家。我在下面的附录中包含了一些学习 Python 的免费和付费资源。另外,如果你对我学习编码的方法感兴趣,看看我写的这篇关于这个问题的文章

在您开始项目之前…

以前,我会告诉你在此之后立即开始项目。在这篇文章中,我会为大多数人推荐一个额外的步骤。我收到了大量的反馈,说大多数人在学习了这些基本技能后,不知道从哪里开始做项目。有一个很好的解决方法。看看别人的项目。你可以去 Kaggle 看看其他人做过的项目。你可以看到他们所有的代码和他们留下的关于他们思维过程的评论。对我来说,这绝对是一座金矿。你可以坐在前排观看杰出的数据科学家如何解决问题。我肯定不聪明,但这里有一个我走过泰坦尼克号数据集的视频:

当开始做项目时,它们不一定是原创的。你可以像其他人一样进行完全相同的分析,仍然可以学到一些东西。一个典型的学习会议可能就是你在屏幕的一半上有别人的项目,然后一行一行地输入,在屏幕的另一半上运行。当你这样做的时候,你可以改变参数,尝试不同的视觉效果,看看它是如何工作的。很明显,你不应该把这项工作的功劳据为己有,也不应该把它作为自己的作品发表,但是你绝对可以通过这种方式从中学习。许多人认为他们用这种方法学不到任何东西,但我个人就是这么做的,这是最近让我走得最远的一件事。

当你浏览这些不同的练习册时。您将不可避免地开始看到您不熟悉的不同工具、算法和技术。你应该记下这些,并研究它们是什么。

统计???

好了,现在你开始熟悉这个过程了。我建议开始熟悉一些您将使用的统计数据和算法。你需要对统计学有一个坚实的基础理解(例如,集中趋势,概率论等。)、线性代数和微积分(你可能会等一会儿再看这个)。开始了解分类、回归和聚类算法之间的区别,并开始思考可以用这些算法解决的问题类型。有没有你看到的可以应用这些算法的数据集?你有没有可以在这些类别中找到答案的问题?

项目困扰

这就是项目成为我学习的主要焦点的地方。我会做尽可能多的项目。我会用我自己的数据,用我能找到的任何数据,在 Kaggle 上做。在下面的附录中,我添加了一些数据科学项目的视频播放列表。

我的数据教授朋友说,学习数据科学的最好方法是做数据科学,我非常同意。项目是你做真正的数据科学的第一个地方。早些时候,我提到反思数据科学的哪些部分让你感到兴奋非常重要。这就是它发挥关键作用的地方。在早期阶段,你应该把你的项目集中在你感兴趣的事情上。对一个项目来说,你能做的最重要的事情就是在这个项目上取得进展。如果你对这个话题或你正在使用的技术足够兴奋,你就尽可能地增加了你学到更多东西的机会。

如何有效地利用项目

在学习了 Python 的基础知识并做了一些项目之后,世界真的是你的了。我建议多做一些专注于技能的项目,这些技能与你自己的旅程相关。比如在大多数公司,SQL 真的很重要。如果你的目标是找一份工作,那就非常值得去做。我没有从 SQL 开始,因为我认为与 Python 相比,它非常容易学习,如果你能学习 Python,你应该能很快学会 SQL。如果你对图像分析着迷,你可能应该将你的学习和项目导向深度学习或其他一些技术。

正如你所知道的,在某个时间点之后,你真的需要调整你的计划来适应你的确切兴趣和能力。你可能不想听到这些,但这是你需要为自己做的事情。

作者图片

这就是事情的全部。如果我想在这之后学习一项新的技能或技术,我会仔细阅读并尝试尽快应用。你的项目和工作成为你过去如何使用许多算法或技术的参考。

随着您的成长,您的迭代循环变得更加紧密,您希望将更多的精力放在良好的学习习惯上。我创建了#66DaysOfData 来帮助在这个过程中保持好习惯。欢迎你随时加入这个项目,我在附录中留下了一些关于它的链接。

这需要多长时间?

你们中的大多数人可能想知道:这个过程需要多长时间?这是一个非常困难的问题。说实话,我认为你可以在短短 3 个月内很好地了解基础知识并做项目。不过,大多数人可能需要 6 个月左右的时间。我真的不建议太专注于需要多长时间。这是一个终身学习的过程,所以只要掌握了知识,3 个月,6 个月,1 年,甚至 5 年都不重要。

关于目标的重要说明

我想结束的一件事是目标的概念。当你创建路线图时,开始思考你的学习目标。你想学习什么概念,想做什么分析?大多数人学习数据科学不应该只是为了了解材料,而应该是你想要使用这些技能来实现的东西。当你学习的时候记住这些事情,但是不要害怕做出相应的调整。如果你一开始对这个领域知之甚少,你怎么可能设定准确的目标呢?随着你在这个领域的不断成长,你的目标设定、你的项目和你的学习必须不断发展。我看到很多人感到失望,当他们真的不知道他们实际上开始要做什么的时候,他们没有完成他们开始要做的事情。

这可能是一些额外的工作,但我建议再次阅读这篇文章,思考你的学习计划。在下面分享你的计划和目标,这样我们就可以互相问责了!

如果您喜欢这篇文章,请记得在 Medium 上关注我以获取更多类似内容,并注册我的简讯以获取我的内容创作和数据科学行业其他学习资源的每周更新!此外,考虑通过注册会员来支持我和成千上万的其他作家

非常感谢您的阅读,祝您在数据科学之旅中好运!

附录

学习数据科学的资源:

学习编程的资源:

熊猫文献:https://pandas.pydata.org/docs/

数据科学项目播放列表:

# 66 days ofdata:【https://www.youtube.com/watch?v=qV_Al...】T4

如何学习来自多个领域的不平衡数据

原文:https://towardsdatascience.com/how-to-learn-imbalanced-data-arising-from-multiple-domains-7d0c0d6e3c17

多领域长尾识别、非平衡领域推广及超越(ECCV 2022)

给大家介绍一下我们的新工作,已经被 ECCV 2022 接受: 关于多领域长尾识别、不平衡领域泛化和超越 。顾名思义,这项工作的问题是,当存在来自多个域的数据,并且每个域都可能存在(潜在不同的)数据不平衡时,如何学习一个健壮的模型。现有的处理不平衡数据/长尾分布的方法只针对单域,即数据来源于同一个域;然而,自然数据可能来自 不同的,其中一个域中的少数类可能有来自其他域的大量实例。有效地利用来自不同领域的数据可能会提高所有领域的长尾学习的性能。本文推广了传统不平衡分类问题的范式,将其从域推广到多域

我们首先提出 领域类可迁移性图 ,量化了数据不平衡情况下不同领域类对之间的可迁移性。在这个图中,每个节点指的是一个域类对,每个边指的是嵌入空间中两个域类对之间的距离。我们证明了可迁移性图决定了跨领域不平衡学习的性能。受此启发,我们设计了 BoDA ,一个理论上跟踪可转移性统计量上限的损失函数,以提高模型性能。我们构建了五个新的多域不平衡数据集,并对大约 20 个算法进行了比较。代码、数据和模型已经在 GitHub 上开源:https://github.com/YyzHarry/multi-domain-imbalance

背景和动机

现实世界中的数据经常表现出标签不平衡,而不是在类之间均匀的标签分布,事实上,数据本质上是不平衡的:少数类包含大量实例,而许多其他类只有少量实例。为了处理这种现象,已经提出了许多解决数据不平衡的方法。更详细的回顾可以在我的上一篇文章中找到。

但是,现有的不平衡数据学习的解决方案主要考虑的是单域的情况,即所有样本来自同一数据分布。然而,在现实中,同一任务的数据可能来自不同的域。例如,下图显示了 Terra Incognita,这是一个为野生动物识别&分类收集的真实数据集。左图是在不同地点设立的相机陷阱,以及捕捉到的野生动物样本;右图显示了(部分)不同摄像机位置获得的具体数据分布及其拍摄效果。我们可以清楚地看到,即使是同样的野生动物分类任务,不同相机的参数、拍摄背景、光照强度等。 完全不同;即不同相机陷阱之间存在一个畴隙。而且由于有些动物只出现在特定的位置,这进一步导致了对于一个摄像机(域)的数据不平衡,甚至存在对于某些类别的 无数据 (比如位置 100 对于类别 0 和 1 几乎没有数据)。然而,由于不同摄像机捕获的标签分布通常差异很大,这也意味着其他属性域可能具有这些类别中的许多样本-例如,位置 46 具有更多类别 1 数据。这表明我们可以利用多域数据来解决 各域 内部固有的数据不平衡。

未知领域数据集。即使是同样的野生动物分类任务,参数、拍摄背景、光照强度等。不同相机的拍摄效果可能完全不同。每个相同的摄像机获得的数据也是极不平衡的;再者,不同相机拍摄到的标签分布也大相径庭,不匹配。但它也说明了我们可以利用多域数据来解决每个域中固有的数据不平衡。(图片由作者提供)

同样,在其他实际应用中也会出现类似的情况。例如,在视觉识别问题中,来自“照片图像的少数类可以用来自“草图图像的潜在丰富样本来补充。同样,在自动驾驶中,“真实生活中的少数事故类别可以通过“模拟中产生的事故来丰富。此外,在医学诊断中,来自不同人群的数据可以相互增强,来自一个机构的少数群体样本可以用来自其他机构的实例来丰富。在上面的例子中,不同的数据类型充当不同的域,这样的多域数据可以用来解决每个域中固有的数据不平衡。

因此,在本工作中,我们将多域长尾识别(MDLT) 问题公式化为从多域不平衡数据中学习,每个域都有其自己的不平衡标签分布,并推广到在 所有域类对 上平衡的测试集。MDLT 的目标是从多个不同领域的不平衡数据中学习,解决标签不平衡域转移跨域的不同标签分布,并推广到所有域的整个类别集。

多域长尾识别(MDLT)从多域不平衡数据中学习,解决跨域的标签不平衡、域移位和发散标签分布,并推广到所有域类对。(图片由作者提供)

多领域不平衡学习的挑战

然而,我们注意到,MDLT 带来了不同于其单一领域对手的新挑战。

(I) 首先,每个域的 标签分布很可能与其他域的 不同。例如,在上面的 gif 图中,“照片”和“漫画”域名呈现出不平衡的标签分布;然而,“漫画”中的“马”类比“照片”中的样本要多得多。除了域内数据不平衡之外,这还带来了跨域的不同标签分布的挑战

(二)二、多域数据内在涉及。简单地将不同的领域作为一个整体来对待,并应用传统的数据不平衡方法不太可能产生最好的结果,因为领域差距可以任意大。**

(III) 第三,MDLT 自然地激发了 内的 域间的——即概括为域内缺失类(gif 图右部),以及没有训练数据的 新域 ,其中后一种情况通常表示为域概括(DG)******

综上所述,与传统的单领域不平衡分类相比,MDLT 面临着新的困难和挑战。那么,应该怎么做多领域不平衡学习呢?在接下来的两节中,我们将从整体建模、激励示例、观察到的现象、理论推导,到最终损失函数的设计,逐步分析这个问题,并最终在 MDLT 任务上提高模型性能。

领域类可转移图

这里我们首先提出一组定义来模拟 MDLT 问题。我们认为,与单领域不平衡学习相反,在单领域不平衡学习中,人们关心的基本单元是 T21,在 MDLT,基本单元自然地转化为领域类对。

那么当我们从“领域类对”入手,就可以衡量它们之间的可转移性(相似性),可转移性定义为嵌入空间中不同领域类对之间的距离:

(图片由作者提供)

直观上,两个领域类对之间的 可转移性 是它们的学习表示之间的平均距离,表征它们在特征空间中的接近程度。默认选择 d 作为欧氏距离,但也可以表示( d,c )的高阶统计量。例如,马氏距离使用协方差。那么,基于可转移性,我们可以进一步定义 可转移性图:****

(图片由作者提供)

在可转移性图中,每个节点表示一个领域类对,每个表示嵌入空间中两个领域类对之间的距离(即可转移性)。此外,我们可以使用多维标度(MDS)在 2D 空间中可视化该图。**

可转移性图的总体框架。(a)为所有域类对计算分布统计,由此我们生成完整的可转移性矩阵。(b) MDS 用于将图形投影到 2D 空间中进行可视化。(c)我们定义了(α,β,γ)可转移性统计量来进一步描述整个可转移性图。(图片由作者提供)

具体来说,如上面的图(a)(b)所示,对于每个域类对,我们可以计算特征统计(均值、协方差等)。)属于这个域类对的所有数据。然后对于不同的域类对,我们进一步计算对之间的可转移性,从中生成一个完整的可转移性图,用矩阵表示(图 a)。然后,我们可以使用多维标度(MDS)在 2D 平面上可视化这种相似性。在图 b 中,我们可以看到不同的域用不同的颜色标记,每个点代表一个域类对,它的大小代表包含的数据量,数字代表具体的类别;而它们之间的距离可以看作是可转移性。很明显,我们希望同号(也就是同一个类别)的域类对靠得更近,而不同类别的域类对离得更远。这种关系可以进一步抽象为三种可转移性统计量:异域同类 ( α )、异类同域* ( β )、以及异类异域 ( γ )😗**

(图片由作者提供)

到目前为止,我们已经对 MDLT 进行了建模和数学定义。接下来,我们将进一步探讨可转移性(统计数据)和最终 MDLT 性能之间的关系。

在 MDLT,什么是好的代表?

分散的标签分布妨碍了可转移的特征

MDLT 必须处理跨域标签分布之间的差异。为了理解这个问题的含义,我们从一个例子开始。

激励范例。我们构建了数字-MLT ,一个双域玩具 MDLT 数据集,它结合了两个数字数据集:MNIST-M 和 SVHN。任务是 10 类数字分类。我们手动改变每个域类对的样本数量,以模拟不同的标签分布,并针对每种情况使用经验风险最小化(ERM)来训练普通的 ResNet-18。我们保持所有测试集的平衡和一致。结果揭示了有趣的观察。当跨域的每个域的标签分布是平衡的相同的时,尽管存在域间隙,但这并不禁止模型学习高准确度(90.5%)的区别特征,如图 a 所示。如果标签分布是不平衡的相同的,如图 b 所示,ERM 仍然能够在两个域中对齐相似的类,其中多数类(例如类 9)在可转移性方面比少数类(例如类 9)更接近相比之下,当标签都是跨域的不平衡不匹配时,如图 c 所示,学习到的特征是 不再可转移 ,导致跨域的间隙和最差的准确度。这是因为跨域的发散标签分布产生了不期望的捷径;该模型可以通过简单地分离两个域来最小化分类损失。**

当数字的标号比例变化时,可转移性图形的演变模式——MLT。(a)两个域的标签分布是平衡且相同的。(b)两个域的标签分布不平衡但相同。两个域的标签分布是不平衡和发散的。(图片由作者提供)

可转移的特征是可取的。结果表明,需要可转移特征跨( d,c )对,尤其是出现不平衡时。特别地,跨域的同一类之间的可转移性链接应该大于域内或跨域的不同类之间的可转移性链接。这可以通过( α,β,γ )可转移性统计来捕获,如下所示。**

可迁移性统计特征概括

激励的例子。同样,我们使用具有不同标签分布的数字-MLT 。我们考虑三种不平衡类型来组成不同的标签配置:(1) 统一(即平衡标签),(2) 前向-LT ,其中标签在类 id 上呈现长尾,以及(3) 后向-LT ,其中标签相对于类 id 是反向长尾。对于每种配置,我们用不同的超参数训练 20 个 ERM 模型。然后,我们计算每个模型的( α,β,γ )统计量,并绘制其相对于(β+γ)——α的分类精度。**

(β+γ)α数量与不同数字标签配置测试准确度之间的对应关系-MLT。每个图表示两个域的特定标记分布(例如,( a)对域 1 采用“统一”,对域 2 采用“统一”)。每个点对应一个使用不同超参数的 ERM 训练模型。(图片由作者提供)

它揭示了多个有趣的发现:(1)α,β,γ 统计数据表征了一个模特在 MDLT 的表现。特别是,(β+γ)α量在整个范围和每种标签配置中与测试性能表现出非常强的相关性。 (2) 数据不平衡增加了学习较少可转移特征的风险。然而,随着标签变得不平衡(图 b、c)和进一步发散(图 d、e),模型学习不可转移特征(即较低的(β+γ)——α)的机会增加,导致性能大幅下降。****

限制可转移性统计的损失

我们利用上述发现来设计一个特别适合 MDLT 的新损失函数。我们将首先引入损失函数,然后证明它最小化( α,β,γ )统计量的上界。我们从一个简单的损失开始,这个损失是由公制学习目标激发的。我们将这种损失称为 L_{DA},因为它旨在实现域类分布对齐,即跨域对齐同一类的特征:

(图片由作者提供)

直观上,这种损失解决了 标签发散 ,因为共享同一类的( d,c )对将被拉近,反之亦然。也与( α,β,γ )统计有关,因为分子代表 跨域对 ( α ),分母代表 跨类对 ( β,γ )。

但是,并没有解决标签不平衡的问题。注意( α,β,γ )是以方式定义的,与每个( d,c )的样本数无关。然而,给定一个不平衡的数据集,大多数样本将来自多数域类对,这将主导损失并导致少数对被忽略。****

平衡域级分布比对。为了解决( d,c )对之间的数据不平衡,我们将损耗修改为 BoDA 损耗:

(图片由作者提供)

BoDA 通过因子 1/N_{d,c} 缩放原始的 d ,该因子是域类对中的样本数( d,c )。因此,它通过引入一个平衡的 距离度量来抵消不平衡的域类对的影响。对于博达,我们有以下定理:

(图片由作者提供)

请参考我们的论文了解证明细节。定理 1 具有以下有趣的含义:

  1. BoDA 上界( α,β,γ )以期望的形式统计,自然转化为更好的性能 。通过最小化 BoDA,我们保证一个 α (吸引相同阶层)和 、γ (分开不同阶层),这是在 MDLT 推广的必要条件。**
  2. 常数因子对应于各成分对可转移性图形 的贡献大小。放大 exp( ) 的论点,我们观察到目标与α(β 1/| D |+γ(| D | 1)/| D |)成正比。根据定义 3,我们注意到 α 总结了相同类别的数据相似性,而后一个表达式使用 βγ加权平均值总结了不同类别的数据相似性*,其中它们的权重与关联域的数量成比例。*******

针对数据不平衡的校准导致更好的传输

BoDA 的工作原理是鼓励 特征跨 域转移相似的类,也就是说,如果( d,c 和(d′,c )在不同的域中引用同一个类,那么我们希望将它们的特征互相转移。但是少数领域类对自然会有更差的特征估计,这是由于数据稀缺、以及强迫其他对转移给它们会损害学习。因此,当在嵌入空间中拉近两个域类对时,我们希望少数的(d,c* )转移到多数的中,而不是相反。*****

这里有很多细节,我就直接跳过了。在我们的论文中给出了详细的激励示例和解释。结论是通过给 BoDA 增加一个校准项,可以通过两个域类对的**相对样本大小来控制转移度😗*****

(图片由作者提供)

基准 MDLT 数据集和实验

为了支持多领域不平衡学习方法的实际评估,并促进未来的研究,我们从现有的多领域数据集筛选了五个 MDLT 基准:

(图片由作者提供)

此外,我们选择了 ~20 种算法,涵盖了多领域学习、分布式鲁棒优化、不变特征学习、元学习、不平衡学习等多个类别。作为基线比较,以及每个算法的优化超参数。这样的过程确保了比较是最佳对最佳的,并且超参数对于所有算法都是优化的。**

在评估期间,我们报告跨域的平均**准确度;我们还报告了域上最差的**精度,并将所有域类对进一步划分为多射(超过 100 个训练样本的对)、中射(20∾100 个训练样本的对)、少射(20 个训练样本以下的对)和零射(没有训练数据的对),并报告结果******

实验:由于实验很多,这里只展示有代表性的结果(所有结果请参考论文)。首先,BoDA 在所有数据集上始终保持最佳平均准确度。它还在大多数情况下实现了最佳** 最坏精度。此外,在某些数据集上(例如,OfficeHome-MLT),MDL 方法表现更好(例如,CORAL),而在其他数据集上(例如,TerraInc-MLT),不平衡方法实现更高的增益(例如,CRT);然而,不考虑数据集,BoDA 优于所有方法,突出了其对于 MDLT 任务的有效性。最后,与 ERM 相比,BoDA 略微提高了平均和多次拍摄的性能,而大大提高了中镜头、少镜头和零镜头对的性能。******

(图片由作者提供)

理解博达的分析:我们对博达进行进一步分析。我们绘制了通过 BoDA 学习的可迁移性图,并在不同的跨域标签分布下与 ERM 进行了比较。从下图可以看出,博达学习了一个更平衡的特征空间来区分不同的类别。当标签分布平衡相同时,ERM 和博达都能学习到好的特性;当标签开始不平衡 (b,c),甚至不匹配跨域(d,e)时,ERM 学习到的可迁移性图中有一个明显的域缺口;相比之下,博达总能学习到一个平衡的对齐的特征空间。因此,更好的学习特征转化为更好的精度(9.5%的绝对精度增益)。****

(图片由作者提供)

超越 MDLT:不平衡的领域泛化

领域泛化(DG)是指从多个领域学习,并泛化到看不见的领域。由于学习域的标签分布自然不同,甚至可能在每个域中存在类别不平衡,我们研究 BoDA 是否可以提高 DG 的性能。请注意,我们为 MDLT 调整的所有数据集都是 DG 的标准基准,这证实了数据不平衡是 DG 中的固有问题,但被过去的工作忽略了。

(图片由作者提供)

我们按照标准的 DG 评估测试 BoDA。上表揭示了以下发现:首先, BoDA 单独使用可以在五个数据集中的四个上改善当前的 SOTA,并实现显著的平均性能增益。此外,与当前的 SOTA 相结合,博达在所有数据集上进一步显著提高了结果,表明标签不平衡与现有的 DG 特定算法正交。最后,与 MDLT 相似,增益取决于数据集内不平衡的严重程度 TerraInc 显示出跨域的最严重的标注不平衡,而 BoDA 在这方面的增益最高。这些有趣的结果揭示了标签不平衡如何影响分布外泛化,并强调了整合标签不平衡对于实际 DG 算法设计的重要性

结束语

作为本文的总结,我们提出了(1)一个称为多域长尾识别(MDLT)的新任务,( 2)一个新的理论上保证损失函数 BoDA 来建模和改进 MDLT,以及(3)五个新基准来促进未来对多域不平衡数据的研究。此外,我们发现标签不平衡影响分布外泛化,实际和稳健的 DG 算法设计也需要纳入标签不平衡的重要性。最后,我附上了几个与本文相关的链接;感谢阅读!

代号:https://github.com/YyzHarry/multi-domain-imbalance

项目页面:http://mdlt.csail.mit.edu/

如何轻松学习新的编程语言

原文:https://towardsdatascience.com/how-to-learn-new-programming-languages-easily-1e6e29d3898a

学习任何新的编程语言——例如 Python、Java 和 Go

阿诺·弗朗西斯卡在 Unsplash 上的照片

经历了在大学学习编程语言,通过各种电子学习平台,并在极少的指导下投入到研究生项目中(包括教授自己开发的超级利基“编码语言”),我注意到不同编程语言的共同之处。

如果你已经知道至少一种编程语言,那么对比其他语言会让你更容易掌握。如果你没有——希望这篇文章将“学习如何编码”的抽象概念分解成更小的基本块。

这篇文章将涉及不同类型的编程语言,如何接近一种(新的)编程语言,编程语言的基本组成部分,以及最后如何设置您的笔记本电脑并运行代码!这些都将用 Python、Java 和 Go 中的例子来解释。

目录

  1. 声明式与命令式编程范例
  2. 编译语言与解释语言
  3. 打印和注释
  4. 数据类型
  5. 条件和循环
  6. 功能和类别
  7. 进口
  8. 设置和运行代码

声明式与命令式编程范例

了解编程范式的类型可以让我们知道编程语言的用途,以及代码是如何组织和执行的。

有两种编程范例——声明式和命令式。

  • 说明性:描述 程序做什么;一组结果
  • 命令式:描述程序应该怎么做;指令系统

声明式编程范例的子集包括函数式数学式逻辑式反应式编程。它试图执行操作,但不控制操作如何发生或操作的执行顺序。

命令式编程范例的子集包括过程式面向对象的编程。它试图控制操作发生的顺序。

由于 Go 是一种过程化编程语言(我们后面会看到这是什么意思),所以它是命令式编程。而 Python 和 Java 是多范式语言,这意味着它们根据您的编程需求支持声明式和命令式编程范式。

编译语言与解释语言

理解代码执行的幕后发生了什么

编译语言和解释语言的区别在于代码是如何执行的。

Go 是编译型语言,Python 是解释型语言,而 Java 是编译和解释并重;它首先被编译成中间形式,然后由解释器解释。

在我们运行代码的最后一节,我们将看到运行编译语言与运行解释语言有什么不同。

定义和描述编程语言还有其他方法,但我发现了解编程范式和代码如何执行就足以让我充分了解编程语言。

还有其他类型的比较,下面的列表并不详尽,

  • 弱类型与强类型 :弱类型允许数据类型之间的隐式转换,而强类型不允许
  • 静态与动态类型 :静态类型在编译时执行类型检查,而动态类型在运行时执行类型检查
  • 高级vs .低级 语言:高级语言面向用户,低级语言面向机器
  • 通用vs .特定领域 语言:通用语言可以解决多个领域的问题,而特定领域语言是专门为解决一个领域的问题而创建的

现在,让我们深入了解编程语言的基本组成部分!

疾控中心Unsplash 上拍照

打印和注释

任何编程语言的第一行代码

您可能熟悉术语print("Hello World"),打印很重要,因为它不仅跟踪您正在执行的操作,而且有助于调试代码错误,例如打印中间变量以检查它们是否有错。

另一方面,注释对代码没有任何作用,但是允许你在代码中添加注释来解释代码在做什么。这有助于您和他人更好地理解代码。

下面是用 Python、Java 和 Go 注释和打印的代码片段。

图 Python、Java 和 Go 中的注释和打印——作者图片

关于打印和注释的更多主题:

  • 注释的类型,即行内注释与块注释
  • 打印不同的数据类型(见下一节)
  • (Python)使用 f 字符串打印

数据类型

任何编程语言的支柱

数据类型是任何编程语言的支柱,因为每个变量和对象都是一种数据类型。不同的数据类型可以执行不同的操作,并且有不同的方式与它们交互。例如,您可以从一组数字中获取最大值,但不能从单个数字中获取最大值。

有三种不同的数据类型—简单、复杂和用户定义的。简单数据类型代表单个值,比如描述数字或文本的变量。复杂数据类型由多种现有的数据类型组成,比如一个数字序列或者将一个数字映射到一个单词(例如,在电话簿中)。某些编程语言支持用户定义的数据类型,您可以在其中创建自己的数据结构。

图 2a: Python 数据类型—作者图片

在 Python 中,上图是所有数据类型的列表,并提供了示例。由于 Python 是一种弱类型语言,我们可以将它赋给一个变量,而不用定义它的类型。举个例子,

图 2b:用 Python 实例化变量——作者图片

图 3a: Java 数据类型——作者图片

Java 是一种强类型语言;当初始化一个新变量时,必须指定变量的类型,有时甚至是变量的大小。

图 3b:用 Java 实例化变量——作者图片

图 4a: Go 数据类型—按作者分类的图片

与 Java 类似,Go 是一种强类型语言,但是 Go 不需要显式地指定变量类型。Go 在如何创建新变量方面也有所不同;它定义了所有以关键字var开始的变量。或者,为了避免使用关键字var,可以使用数学表达式:=。下面是一些如何在 Go 中实例化变量的例子,

图 4b:用 Go-Image 按作者实例化变量

除了知道不同的数据类型之外,区分数据类型是可变的还是不可变的(如果它的值在创建后可以改变)或者它们是否被索引以知道何时选择每种数据类型是很重要的。一开始,接触多种数据类型可能会令人望而生畏。我发现将我关于数据类型的笔记组织成三个不同的部分是有益的——构造新变量、查询变量和转换变量。

关于数据类型的更多主题:

  • 构造加载外部文件,即从 JSON 文件初始化字典
  • 构造】简单数据类型之间的转换,如十进制到整数,日期到字符串
  • [ Query 从复杂或用户定义的数据类型中检索项目
  • [ 转换 ]将项目前置或附加到复杂数据类型
  • [ 转换 ]替换可变数据类型中的项目
  • [ 转换 ]排序或反转复杂的数据类型,如列表、字典
  • [ 转换字符串操作,即改变大小写、提取字符或子串、删除前导或尾随空格、拆分字符串

条件句和循环

基于条件控制代码流,或者重复一个代码,直到满足条件

了解了数据类型并实例化了一些变量之后,很自然地想要控制代码流或者修改变量(或者变量中的每一项)。为了控制代码流,我们可以只在满足某些条件的情况下执行一组指令,并相应地指导代码流。为了修改变量中的每一项,我们通过变量迭代,这可以使用循环来完成。

有一些常见的条件和循环,注意不是所有的编程语言都支持下面列出的所有类型的条件和循环,

  • If-else 条件:执行一个任务 如果 满足一个条件, else 执行另一个任务或者什么都不做
  • 切换情况:在一种情况下执行一项任务,在另一种情况下执行另一项任务。这类似于 if-else 语句,只是条件的计算结果是一个值而不是布尔值(真或假)
  • For 循环:执行任务 for 复变量中的每一项
  • While loop:在 一个条件满足时执行一个任务 (当心无限循环!)

图 Python、Java 和 Go 中的条件句——作者图片

关于条件句的更多主题:

  • 不同数据类型的数学条件或更复杂的条件检查
  • 为复杂数据类型实现 for 循环,即迭代列表
  • 创建一个变量范围并为其实现一个循环
  • 使用枚举器并为其实现一个循环

函数和类

对一系列操作进行分组,并重用它们

函数和类是最常见的代码,因为函数式编程使用函数,而面向对象编程使用类。

对于任何函数,都需要指明输入的名称。对于某些(更严格的)编程语言,还需要提供输入和预期输出的数据类型。作为面向对象的编程,类将几个相关的函数结合在一起。类内的函数被称为类 方法

图 Python 中的函数和类——作者图片

在 Python 中,函数用关键字def定义(第 1 行),输出用关键字return返回(第 4 行)。不需要指定输出的数据类型。

图 Java 中的类——作者图片

Java 里是面向对象编程,文件名必须跟在类名后面;类别MyClass必须包含在MyClass.java中。如果文件被执行,只有main功能(第 6 行)会运行。

在定义一个类方法时,需要定义输入和输出变量的数据类型,并且有一个可见性修饰符(private/public/protected)和其他隐式参数(static/final)的概念,这将不在本文中讨论。

图 8:Go 中的类——按作者分类的图片

在 Go 中,类似于 Java,也是面向对象编程但是对文件名没有限制。执行该文件时,只会运行main功能(第 10 行)。

由于在执行.go文件时只运行main函数,所以函数通常被顺序地缝合在一起,形成过程。因此,正如本文开头提到的,Go 遵循过程化编程范式。

关于函数和类的更多主题:

  • 类方法与类对象
  • 类中的构造函数、析构函数
  • (Python)类方法与静态方法
  • (Java)可见性修饰符和其他隐式参数
  • 继承:将一个类扩展到另一个类
  • 断言:确保满足条件
  • 异常处理:控制出现错误时会发生什么

进口

使用内置包、外部包或其他文件中的代码

单个文件中的代码可能无法涵盖您需要的所有内容,您将需要依赖于包或文件中的现有代码,这些代码由他人或您自己编写,通过导入它们来实现。

有三种类型的导入—从内置包、外部包或其他文件导入。导入在代码开始时完成,因为您需要在使用它们之前导入包。

从内置包和外部包导入遵循相同的过程,只是需要额外的步骤来安装外部包。

图 9:在 Python 中导入——按作者分类的图片

在 Python 中,常用pipconda安装程序。外部包可以在终端上用命令pip install package-nameconda install package-name安装,用上面的例子导入。

图 10:用 Java 导入——作者图片

在 Java 中,通过在各自的 Maven 或 Gradle 文件中添加包的详细信息,可以用 Maven 或 Gradle 安装外部包。上面显示了一些用 Java 执行导入的例子。

图 11:在 Go 中导入—按作者排序的图像

在 Go 中,可以在命令行用go get package-name安装外部包。同一文件夹中的所有代码都属于同一个包,因此不需要导入。但是,您需要用上面的例子导入内置或外部的包。

设置和运行代码

学习理论后迈出第一步

终于,你准备好开始编码和运行一些代码了!

要进行设置,您需要下载编程语言本身,本文末尾提供了链接。你还需要下载一个 IDE(集成开发环境)来运行代码。你可以把 IDE 看作是一个运行代码的漂亮界面,否则你就需要使用命令行界面,这对初学者来说并不友好。一些 IDE 可以运行多种编程语言,所以你只需要下载一个 IDE。

就个人而言,我不喜欢将我的 IDE 与多种编程语言混合在一起。这是我的设计,

  • Python: PyCharm(重载),Sublime Text(轻量级)
  • Java: IntelliJ 理念
  • Go: Visual Studio 代码,终端

要运行代码,可以在 IDE 上(推荐)或通过命令行界面运行代码。

图 12:在 PyCharm 中运行 Python 作者图片

要运行 Python 代码,您可以点击 Ctrl-Enter 或 Ctrl-B 按钮,或者将其复制并粘贴到 Python 控制台——这取决于您的 IDE。

图 13:在 IntelliJ IDEA 中运行 Java 作者图片

要运行 Java 代码,您需要先构建代码,以便在运行它们之前将.java文件编译成.class文件。这个额外的步骤是因为 Java 既是编译语言又是解释语言,正如前面的章节所解释的。

图 14:在 Visual Studio 代码中运行 Go——作者图片

要运行 Go 代码,您可以使用命令行界面并运行go run file-name.go来编译和执行代码。

或者,如果您只想在没有任何安装的情况下玩玩,您可以使用在线 IDE。

在本文的最后有 Python、Java 和 Go 的在线 IDE 的链接。虽然在线 ide 很方便,但是它们不能执行复杂的任务,比如安装和导入某些外部包,或者在多个文件中编写代码。

恭喜你,你现在知道如何学习编程语言了,从理解编程语言的类型和组成编程语言的基本组件,到如何设置和运行代码。希望通过 Python、Java 和 Go 的例子,您可以看到编码语法和约定之间的相似之处和(一些)不同之处——一旦我们找到相似之处,学习其他语言就更容易了!不要担心混淆语法,是的,它会发生,谢天谢地,好的 ide 可以在你运行代码之前发现并反映这些错误。

要掌握一门编程语言,最好是每天通过做一个简单的任务或项目来练习。

最后,除了经常练习编程语言,我认为编码是一种“思维方式”。例如,给定一个大项目,适当地组织你的代码而不是从上到下顺序运行它或者硬编码组件是很重要的。幸运的是,这种“思维方式”可以通过遵循编码最佳实践来加以利用(您可以将其视为一组推荐的规则)。遵循编码最佳实践可以使您的代码更加优雅、模块化和易于理解。有需求的话可以出续集;)

*💔-tips-for-writing-clean-codes-beyond-coding-best-practices-c53b04120c3> *

相关链接

计算机编程语言

Java 语言(一种计算机语言,尤用于创建网站)

如何用 5 种简单的方法提升你的熊猫技能

原文:https://towardsdatascience.com/how-to-level-up-your-pandas-skills-in-5-easy-ways-223208ce18cc

用熊猫提升你的数据科学技能的 5 种方法

图片由翻腾 926

Pandas 是一个用于数据科学的强大而通用的 Python 库。在学习如何将 Python 用于数据科学应用时,它通常是您最先遇到的库之一。它可以用来加载数据,可视化数据和操作数据,以适应您正在进行的项目的目标。

然而,许多人没有超越如何使用库的基础,并且没有利用一些更高级和有趣的特性。

在这篇文章中,我们将介绍 5 个你以前可能没有遇到过的特性,这些特性将使你在使用这个库时更有效率。

加载库和数据

对于本文中使用的所有示例,我们将使用的数据是作为 Xeek 和 FORCE 2020 (Bormann 等人,2020) 举办的机器学习竞赛的一部分的测井数据的子集。该数据在此处https://zenodo.org/record/4351156#.Y4iZHC-l0eY**公开,并根据 挪威政府数据公开许可证(NLOD) 2.0 获得许可。**

然而,这里显示的所有方法和示例都可以应用于加载到 pandas 中的任何数据集。

首先,我们首先需要导入 pandas 库,为了方便起见,通常简称为pd

然后,我们将使用read_csv()函数将 csv 文件读入数据帧。

import pandas as pd
df = pd.read_csv('data/Xeek_train_subset_clean.csv')
df

当我们查看数据帧时,我们可以看到有 12 列数据混合了文本和数值。

来自 Xeek Force 2020 机器学习竞赛的测井数据的数据帧。图片由作者提供。

现在已经完成了,我们现在可以继续 5 种方法来提高你与熊猫的数据科学技能。

更改默认熊猫绘图库

在进行探索性数据分析时,我们通常希望快速绘制出我们的数据。你可以使用 matplotlib 构建一个情节,然而,我们可以使用 pandas 通过几行代码来完成。

一旦你加载了数据,你就可以调用 dataframe,然后调用.plot方法。

例如,如果我们采用 GR 列并绘制直方图,如下所示:

df.GR.plot(kind='hist', bins=30)

这将返回以下图:

熊猫使用的伽玛射线直方图。plot()函数。图片由作者提供。

返回的图像非常简单,缺乏交互性。

从 pandas 版本 0.25 可以改变使用哪个绘图库。例如,代替 matplotlib,你可以为 plotly 切换这个。 Plotly 允许以高效的方式生成非常强大的交互式数据可视化。

有关如何使用 Plotly 生成另一种类型的散点图的更多信息,您可能有兴趣浏览我以前的文章:

要更改当前实例的默认绘图库,您需要更改 pandas 的plotting.backend选项。

pd.options.plotting.backend = "plotly"

一旦你完成了,你就可以像以前一样调用相同的代码

df.GR.plot(kind='hist', bins=30)

生成的绘图现在是交互式的,并在探索数据集时提供了更好的用户体验。

将 pandas 后端绘图选项更改为 plotly 后的伽马射线直方图。图片由作者提供。

您还可以使用其他类型的图,包括散点图,方法是稍微修改一下代码,如下所示:

df.plot(kind='scatter', x='NPHI', y='RHOB', color='GR')

当执行上面的代码时,您会得到下面的图:

改变熊猫后端绘图选项后创建的交互式散点图。图片由作者提供。

链接操作

将多个方法链接或连接在一起是一种长期实践的编程技术,可以提高代码的可读性。

它是在一行中一个接一个地调用对象上的方法的过程,而不是分别对对象应用这些方法。这有助于您流程的多个阶段。

例如,如果要加载数据,请将列更改为小写,然后删除缺失值(nan ),可以这样做:

df = pd.read_csv('data/Xeek_train_subset_clean.csv')
df = df.rename(columns=str.lower)
df = df.dropna()

然而,更有效的方法是像这样链接操作:

df = pd.read_csv('data/Xeek_train_subset_clean.csv').rename(columns=str.lower).dropna()

有时这一行可能会变得很长,所以您可能希望通过将它分成多行来提高可读性。

如本堆栈溢出问题所示,这可以使用行继续符(\)来完成。

df = pd.read_csv('data/Xeek_train_subset_clean.csv')\
        .rename(columns=str.lower)\
        .dropna()

或者使用圆括号,就像另一个 StackOverflow 问题中建议的那样,这样就不需要换行字符了。

df = (pd.read_csv('data/Xeek_train_subset_clean.csv')
        .rename(columns=str.lower)
        .dropna())

查询()

我们在处理数据时经常做的一项常见任务是基于单个或多个条件对数据进行过滤。您可以使用以下代码来实现这一点:

df[df.GR > 100]

然而,使用 熊猫查询 函数会产生一段可读性更好的代码,尤其是当事情变得稍微复杂一些的时候。

例如,如果要查找 GR(伽马射线)列包含值大于 100 的所有行,可以像这样调用查询方法:

df.query("GR > 100")

它返回下面的 dataframe 对象。

使用 pandas 查询方法过滤伽马射线大于 100 API 的行后的 Dataframe。图片由作者提供。

如果您想要组合多个条件,也可以使用逻辑。

df.query("GR > 100 and GR < 110")

它返回一个更小的数据帧,只有 7,763 行

使用 pandas 查询方法过滤伽马射线大于 100 API 但小于 110 API 的行后的数据帧。图片由作者提供。

如果你想寻找一个特定的字符串值,比如这个数据集中的无水石膏,你需要修改我们的查询方法,把几个方法连接在一起。

df.query("LITH.str.contains('Anhydrite')")

这将返回其中 LITH 列包含单词 Anhydrite 的任何行

使用 pandas 查询方法过滤 LITH 包含硬石膏的行后的 Dataframe。图片由作者提供。

如果字符串包含特殊字符,例如我们的数据帧中的井列包含反斜杠和破折号,也可以使用这种方法:

df.query("WELL.str.contains('15/9-13') and GROUP.str.contains('ZECHSTEIN GP.')")

使用 pandas 查询方法筛选组中包含 Zechstein Gp 的行后的 Dataframe。井名是 15/9–13。图片由作者提供。

eval()

Python 中的 eval()方法是一个强大的工具,可以对同一数据帧中的列计算任意 Python 表达式。

这意味着您可以通过提供字符串表达式从数据帧中提取列并执行算术计算。

例如,您可以从 GR 列中减去值 100:

df.eval('GR-100')

它返回

结果用 eval 方法进行简单计算后。图片由作者提供。

如果您想将这个计算放在一个新的列中,您需要调用pd.eval并传递目标数据帧后面的表达式。

pd.eval('GR_TEST = df.GR - 100', target=df)

使用 pd.eval 添加基于简单表达式的新列后的 Dataframe。图片由作者提供。

岩石物理学中的常见计算是计算地层中粘土的体积。要进行这种计算,您只需扩展以下表达式:

pd.eval('CLAYVOL = ((df.GR - 20)/(200-10))', target=df)

这会创建一个名为CLAYVOL的新列

使用 pd.eval 方法根据伽马射线柱计算粘土体积后的数据帧。图片由作者提供。

如果您正在进行适当的岩石物理分析,您将需要考虑基于多个地层或深度范围的选定参数。上面举例说明了进行计算的一种快速方法。

地图()

如果我们需要匹配某个对象(如字典)中的值,或者用另一个值替换数据帧中的值,我们可以使用 映射功能

此函数只能应用于数据框架中的单个列或 Pandas 系列。

使用这个数据示例,我们可以创建一个新列,其中包含基于文本字符串的数字代码。这可以通过使用另一个数据帧或字典来实现。

如果使用字典作为参考,您首先需要创建一个或加载一个。这个例子使用了一个快速创建的简单例子。

lith_dict = {'Shale':1,
 'Sandstone':2,
 'Sandstone/Shale':3,
 'Limestone':4,
 'Tuff':5,
 'Marl':6,
 'Anhydrite':7,
 'Dolomite':8,
 'Chalk':9,
 'Coal':10,
 'Halite':11}

接下来,您将创建一个新列,例如,LITH_CODE。

然后调用 LITH 列并应用.map函数,它包含上面创建的字典。

df['LITH_CODE'] = df['LITH'].map(lith_dict)

当您调用 dataframe 时,您现在有了一个新列,该列的岩性代码映射到正确的岩性。

Dataframe 在使用 map 函数后,根据 string 的内容创建一个新的岩性代码列。图片由作者提供。

摘要

Pandas 是一个令人难以置信的图书馆,允许用户以非常直观的方式可视化、转换和分析数据。本文介绍了一些鲜为人知的特性和方法,如果您刚刚开始数据科学之旅,其中许多可能对您来说是新的。了解这些将有助于您利用熊猫的力量来提高您的数据分析技能。

感谢阅读。在你走之前,你一定要订阅我的内容,把我的文章放到你的收件箱里。 你可以在这里做!或者,您可以* 注册我的简讯 免费获取更多内容,直接发送到您的收件箱。***

其次,你可以通过注册成为会员来获得完整的媒介体验,并支持我和成千上万的其他作家。每月只需花费你 5 美元,你就可以接触到所有精彩的媒体文章,也有机会通过写作赚钱。如果你用 我的链接 报名,你直接用你的一部分费用支持我,不会多花你多少钱。如果你这样做了,非常感谢你的支持!

参考

博尔曼,彼得,奥桑德,彼得,迪里布,法哈德,曼拉尔,投降,&迪辛顿,彼得。(2020).机器学习竞赛 FORCE 2020 井测井和岩相数据集[数据集]。芝诺多。https://doi.org/10.5281/zenodo.4351156

如何升级你的终端游戏

原文:https://towardsdatascience.com/how-to-level-up-your-terminal-game-db7b44e31e65

提高效率的 6 个命令行实用程序

作者图片

对于许多新开发人员来说,使用终端或命令行可能会显得低效甚至过时。然而, shell 是任何开发人员可用的最有用的工具之一。在这篇文章中,我将向你展示六个有用的工具来升级你的终端游戏!

***Table of Contents*****1\. xclip
2\. croc
3\. zoxide
4\. htop
5\. entr
6\. fzf** 

1.复制/粘贴

当我说“复制/粘贴”时,您可能会立即想到 Ctrl-C 和 Ctrl-V,但是您知道吗,您还可以使用命令行以编程方式将数据复制/粘贴到系统的剪贴板,而无需使用任何键盘快捷键。

如果您使用的是基于 Linux 的操作系统(或 Windows 上的 WSL),您可以使用 xclip 实用程序从命令行与剪贴板进行交互。你可以使用你系统的包管理器来安装 xclip(比如 Ubuntu 上的apt,或者 Arch 上的pacman)。

运行xclip -o将会显示你剪贴板的当前内容,你可以把它导入另一个程序,重定向到一个文件,等等。

同时,通过管道将文本输入到命令xclip中会导致文本被复制到您的剪贴板中。(旁注:xclip 旨在与 X11 窗口系统一起使用。如果你用的是 Wayland,你应该安装wl-clipboard,它提供wl-copywl-paste

如果你在 MacOS 上,你可以使用相应的pbcopypbpaste命令来代替。在 Windows 上,如果您没有使用 WSL,您可以使用clip.exe(对应于copy)和/或 Powershell 命令Get-ClipboardSet-Clipboard

无论您使用什么操作系统,我都建议您在 shell 配置文件中使用别名复制/粘贴命令,如下例所示。如果您正在使用 bash,您可能希望将您的别名添加到~/.bashrc(或者对于 zsh,添加到~/.zshrc)。您可以通过运行echo $SHELL来检查您当前使用的是什么 shell。

# Example copy/paste alias for Linux
alias paste='xclip -o'
alias copy='xclip -c'# Example copy/paste alias for MacOS
alias paste=pbpaste
alias copy=pbcopy

现在,您可以运行如下命令:

paste > file        # paste clipboard into a file
cat file | copy     # copy file contents to clipboard
paste | croc send  # send clipboard contents using croc

2.鳄鱼

Croc 是一个有用的跨平台工具,可以在两台计算机之间安全地传输数据(比如文件或文本)。不用再发送 zip 文件或者摆弄 Dropbox——如果你需要发送文件给某人,在大多数情况下,croc 更简单(可能)更快。

唯一的要求是发送方和接收方的系统上都安装了 croc。Croc 可能可以从您最喜欢的包管理器获得——更具体的安装说明可以在项目的 github 页面上找到。

以下是 Croc 的使用示例:

$ croc send file.dat
Sending 'file.dat' (0 B)
Code is: <code-phrase>

在第二台计算机上,键入croc <code-phrase>将提示您接受传输的数据,如下所示:

Accept 'file.dat' (0 B)? (Y/n)

使用 croc 发送文本同样简单——您可以通过管道将文本输入到 croc 中,也可以手动键入文本,如下所示:

$ echo "Hello from croc!" | croc send
# or
$ croc send --text "Hello from croc!"

如果这还不够,croc 允许支持多种加密/哈希算法、可恢复传输和代理!在我看来,croc 是一个非常有用的工具,可以放在你的工具箱里。

3.佐西德

Zoxide 与我之前提到的其他工具有所不同。它旨在通过帮助您更快地遍历文件系统来改善命令行体验。

Zoxide 允许你进入一个目录而不用给出完整的路径。相反,Zoxide 会考虑你过去的历史,并根据你提供的名字来判断你想去哪里。本质上,佐希德只是一个“更聪明的”cd

Zoxide 支持所有主要的 shells,并且可能从您最喜欢的包管理器中获得。你可以在它的 Github 页面上找到安装说明和更高级的使用技巧。

这里有一个如何使用 Zoxide 的例子。注意:Zoxide 提供了命令z,但是由于肌肉记忆,我更喜欢别名它而不是cd

$ z /opt/local/lib  # changes your directory like normal
$ z ~               # jumps to home directory like normal
$ z lib             # will automatically jump /opt/local/lib
$ z ..              # go up one directory
$ z l               # may also jump to /opt/local/lib

使用 Zoxide 时,运行z <something>会根据 Zoxide 的匹配算法将目录更改为排名最高的选择。Zoxide 既考虑了一个目录被访问的频率,也考虑了它上次被访问的时间。

比如多次进入目录/opt/local/lib,就会增加它的“分数”。现在,如果你从你的主目录运行z lib,Zoxide 会直接把你带到/opt/local/lib。事实上,你甚至不需要完全输入lib。Zoxide 使用模糊字符串匹配,所以即使运行z l也能把你带到正确的地方。

我个人认为 Zoxide 很有用,因为它允许我跳转到不同项目的目录,而不必记住它们在我系统中的确切位置。只要我知道一个目录的名称(或者它的前 3 个字符),我就可以到达那里。

4.htop

Htop 是终端的资源监视器和进程管理器。

Htop 可以使用你最喜欢的软件包管理器来安装。最新版本和源代码可以在它的 Github 上找到。

来自https://htop.dev/screenshots.html的 htop 官方截图

下面是 htop 允许您做的事情的快速列表:

  • 查看每个内核的 CPU 负载、内存使用情况(包括交换)、正常运行时间等
  • 显示哪些进程使用了最高数量的 CPU/内存
  • 按名称或 PID 搜索流程
  • 用你选择的中断终止进程(比如 SIGINT,SIGKILL,SIGTERM 等)

Htop 同时支持键盘和鼠标——如果你不需要的话,就不必学习快捷键。此外,通过树形视图,您可以看到哪些进程是其他进程的子进程,这非常有趣。我主要使用 htop 来监控系统负载和杀死行为不当的进程(在我自己的系统和远程服务器上)。

5.引入线

Entr 是一个实用程序,允许您在每次文件更改时重新运行命令。这允许您用一个简单的终端命令实现自己的 ad-hoc 实时重载服务器。Entr 应该可以从你最喜欢的包管理器中获得(或者如果你想手动安装它,请看它的主页这里)。

使用 entr 的方法是在标准输入中提供一个文件名列表,以及每当这些文件之一发生变化时运行的命令。举例来说,假设我们有一个简单的 Python 项目,我们想在源代码发生变化时重新运行该程序。

这可以用一行代码来完成:

$ find . -name *.py | entr python main.py

如上所述,find命令用于生成当前目录中扩展名为py的所有文件的列表,然后该列表通过管道传输到entr,每当检测到其中一个文件发生变化时,它就会重新运行main.py

如果我们需要更复杂的行为,我们可以简单地添加一个 Makefile 并告诉 entr 要构建哪个目标。例如,给定一个假设的 C 项目,我们可能希望运行下面的代码,让 Make 处理重新编译 C 文件的复杂性。

$ find src/ | entr make

Entr 还允许您在命令中使用已更改文件的名称。例如,运行ls | entr echo /_将监控当前目录中的每个文件,并在检测到变化时打印出文件的路径。

如果你想了解更多关于 entr 的知识,可以查看主页[这里](https://ls *.rb | entr -r ruby main.rb)。您将找到更多的例子,以及特殊命令行标志的文档。

6.fzf

我将用一个伟大的交互式实用程序来结束这篇文章。Fzf 是一个模糊查找器,允许您从列表中交互式地选择一个选项。它还具有很好的外壳集成和可配置性。

Fzf 可以从几乎所有的包管理器中获得,但是你也可以用 git 安装它(指令在这里)。

默认情况下,运行fzf将为位于当前目录或其子目录中的每个文件显示一个交互式选择器(相当于find .)。这本身就很有用——如果你想交互式地选择一个文件进行编辑,只需运行vim $(fzf)。通过输入搜索词,可以缩小 fzf 提供的选择范围。然后,你可以按<回车>来选择选项。

使用 fzf 选择要编辑的文件

您可以使用 fzf 从任何列表中选择一个项目。使用 fzf,您可以轻松地编写 shell 脚本,以交互方式检查 git 提交、选择要终止的进程、选择要安装的包等。可能性是无穷的,你可以在网上找到很多有用的脚本。

下面显示了来自 fzf 示例 wikifcoc脚本。

使用 fzf 检验 git 提交

更不用说,fzf 还有许多更高级的特性,比如命令的 shell 完成、预览窗口、vim/tmux 集成等等。关于这些信息,我建议通读该项目的 Github。

Git 仓库

https://github.com/schollz/croc https://github.com/ajeetdsouza/zoxide https://github.com/htop-dev/htop https://github.com/eradman/entr https://github.com/junegunn/fzf

结论

不要小看终端!命令行是一些最简单但最有用的工具的家园!

如何利用零方数据获得更深刻的见解

原文:https://towardsdatascience.com/how-to-leverage-zero-party-data-for-greater-insights-f4de0e2801d6

用一个简单的 Python 演示。

Unsplash 上拍摄的 ThisisEngineering RAEng

第三方数据是推动现代营销和分析的最重要的燃料。它是来自公司外部的数据,无论是来自客户、供应商还是其他来源。

这对于清楚地了解您的业务表现以及如何改进非常重要。无论你何时访问一个应用程序,从跟踪 cookies 到社交媒体登录,这些数据通常都会在后台自动收集。

但在当今数据驱动的世界中,另一种类型的数据变得越来越重要:零方数据。零方数据由 Forrester Research 创造,是客户“有意和主动与品牌分享”的数据

在本文中,我们将讨论为什么零方数据很重要,并通过 Python 中的一个示例演示如何使用它来提高机器学习模型的准确性。

为什么零方数据很重要

“数据是新的石油”这句老生常谈的话今天仍然适用。你拥有的数据越多,你就能更好地洞察你的业务和客户。零方数据是一个有价值的信息来源。

零方数据的优势之一是它总是最新的。它总是最新的,因为客户自愿与您共享它。这与第三方数据形成对比,如果不定期更新,第三方数据可能会过时(甚至被欺诈性地收集)。

零派对数据的另一个优势是它更加个人化和相关。因为客户是自愿分享的,所以更有可能与他们的兴趣和需求相关。这与第三方数据形成对比,第三方数据可能与您的客户不太相关,甚至无关。

数量与机器学习的准确性相关

不仅如此,你有越多的数据来推动机器学习算法,它们就能更好地工作。虽然这种并不总是的情况,但今天最先进的模型,从 OpenAI 的 GPT-3 到悟道 2.0,都依赖于惊人的数据量。

机器学习对企业越来越重要,因为它可以帮助你自动化客户细分和线索评分等任务。

但重要的不仅仅是数量。数据的质量也很重要。这是零方数据的亮点,因为它比第三方数据更有可能是高质量的。

如何获得零方数据

现在你知道了为什么零方数据如此重要,那么你该如何着手获取它呢?这里有一些建议。

向你的顾客索要。

获得零方数据的最好方法之一就是直接向你的客户索要。您可以通过多种方式做到这一点,例如通过调查或要求他们与您分享联系信息。

传统的方式是通过弹窗“询问”,甚至是隐性的批准进行用户追踪。虽然第三方数据收集工具运行从脸书像素HotjarMixpanel 的色域,但零方数据收集是较新的。有了 involve.me 这样的工具,就可以通过小测验、调查、计算器等形式获得零方数据。

为分享提供奖励。

另一种获得零方数据的方法是提供激励让客户与你分享。这可以是折扣、奖励或其他特别优惠的形式。

实用指南:用零方数据构建预测模型

既然您已经理解了零方数据的重要性,那么您实际上如何将它合并到您的预测建模中呢?让我们看一个 Python 中的简单例子,比较和对比使用零方数据和传统数据的结果。

我们将使用银行客户调查—定期存款营销数据集,这是一个 UCI ML 数据集,包含银行电话营销数据,如年龄、工作、婚姻状况、教育、余额、住房和个人贷款状况。目标是预测客户是否会认购定期存款。

第一步是导入必要的库。

import pandas as pd
import numpy as np
import sklearn
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

现在,让我们导入数据集。

df = pd.read_csv('bank_customer_survey.csv')

由于我们的数据集充满了非数值,让我们对其进行编码。

df['y'] = df['y'].astype(int)
df = df.apply(LabelEncoder().fit_transform)

首先,我们将使用通用的、预先包含的第三方数据构建一个模型。

X = df # our input data
y = pd.DataFrame(X.pop(‘y’))X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
scaler = MinMaxScaler()X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
logreg = LogisticRegression()logreg.fit(X_train, y_train)print(‘Accuracy of Logistic regression classifier on training set: {:.2f}’.format(logreg.score(X_train, y_train)))
print(‘Accuracy of Logistic regression classifier on test set: {:.2f}’.format(logreg.score(X_test, y_test)))

我们得到以下输出:

Accuracy of Logistic regression classifier on training set: 0.89
Accuracy of Logistic regression classifier on test set: 0.89

换句话说,我们可以使用逻辑回归分类器以 89%的准确率预测客户是否会订阅定期存款。

现在,在添加了一些零方数据之后,是时候构建相同的模型了。出于演示目的,我制作了一个综合专栏,向客户提出一个调查问题,并给出一个自愿回答(零方数据的示例):

“未来 5 年要不要买房?”

我们可以伪随机地将我们的合成列添加到数据框架中,其中“是”的答案与购买定期存款相关联,这在现实世界的数据中可能会发生。

dfNo = df[df['y']==0]
dfYes = df[df['y']==1]lstYes = [0,1,1,1,1]
dfYes[“Do you want to buy a house in the next 5 years?”] = np.random.choice(lstYes, size=len(dfYes))lstNo = [0,0,0,0,1]
dfNo[“Do you want to buy a house in the next 5 years?”] = np.random.choice(lstNo, size=len(dfNo))dfZeroPartyData = dfNo.append(dfYes)

现在,让我们重建我们的模型。

X = dfZeroPartyData # our input data
y = pd.DataFrame(X.pop(‘y’))X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)logreg = LogisticRegression()
logreg.fit(X_train, y_train)print(‘Accuracy of Logistic regression classifier on training set: {:.2f}’.format(logreg.score(X_train, y_train)))
print(‘Accuracy of Logistic regression classifier on test set: {:.2f}’.format(logreg.score(X_test, y_test)))

我们得到以下输出:

Accuracy of Logistic regression classifier on training set: 0.92
Accuracy of Logistic regression classifier on test set: 0.92

换句话说,我们使用逻辑回归分类器以 92%的准确率预测了客户是否会订阅定期存款。通过添加零方数据,我们将准确率提高了 3%。鉴于数据生成的随机性,您可能会得到不同的结果。

当然,这只是一个使用合成数据的演示示例,但这些好处每天都在现实世界中实现,企业使用零方数据或客户有意和主动与品牌分享的数据来建立更好的模型。

代码

请参见这个 Google Colab 文件获取完整代码,并在评论中随意提出任何问题!

发现数据失真

原文:https://towardsdatascience.com/how-to-lie-with-data-c58df403bdce

艾萨克·史密斯在 Unsplash 上拍摄的照片

批判性评估图表和数字的演练

介绍

数据分析团队的目标是帮助他们的组织基于数据和见解做出业务决策。

经过几个月的艰苦工作,通过稳健设计的数据管道收集了跨多个部门的组织数据,然后小心翼翼地将它们存储在精心设计的数据库中,您的数据分析师现在终于可以分析它们了,希望发现的任何见解都可以促使管理层做出一些突破性的决策,并帮助组织实现其业务目标。

反正就是这个愿景。

然而,我们(数据分析师)想要传达的和他们(观众)最终得到的是两回事。

有时,这种错位可能是有意的。但更多的时候,它们是偶然的。

这篇文章旨在成为一系列文章中的第一篇,这些文章强调了一个人在展示数据时可能“误导”他人的方式(无论是无意的还是其他的),以及受众在解释数据时可以做得更好的方式(通过意识到这是如何做到的)。

这背后的大部分灵感来自丹尼尔·J·莱维汀的作品,他的书《谎言实地指南》[1]中,作者通过大量的数据误报案例以及如何做到这一点。这本书,以及我在研究这个主题时发现的许多其他后续资源,构成了本文和后续文章中将要分享的内容的基础。

现在,我们将把重点放在人们可以摆弄图表的最明显的方式上——它的轴。

玩斧子

我想不言而喻,当一个人拿到图表时,他首先应该看的是坐标轴和图例。

为用户将数据点与值相关联提供了重要的参考信息,尤其是当数据点没有在图表中直接标记时。— [4]

在这一节中,我们将探讨一些技术,这些技术可以用来误导他人如何通过摆弄轴来解释数据。

1。未标记图表/坐标轴

如前所述,如果没有任何标签或轴,读者将很难联想或比较呈现的图表。

为了开始我们对数据虚假陈述的研究,考虑下面一个假设的公司— ACME 的例子:

ACME 的市场份额(图片由作者提供)

在上图中,我们可以看到,与市场上的其他公司相比,ACME 拥有 56%的最大市场份额。

但是差别到底有多大呢?

标签的缺失——在本例中是 Y 轴——使得读者无法理解 ACME 相对于其竞争对手的优势有多大。

2.截断轴

如前所述,Y 轴通常用来显示事物在 X 轴上变化的幅度(通常是时间,或者一些类别)。

然而,为了额外强调 Y 轴上的增加或减少(例如,目的可能是强调在某人的领导下事情有了多大的改善),可以选择通过截断 Y 轴来改变它们(即。通过移除一部分 Y 值直到与我们相关的点)。

考虑下面的图表。

两张图表都显示了不同时间段的销售数字。然而,左边的更讨人喜欢。(图片由作者提供)

这两个图表都是使用相同的数据集创建的,其中绘制了一家公司在 2008 年至 2013 年期间的销售数据。

然而,左边的这个看起来更讨人喜欢——因为随着时间的推移,它显示出一条漂亮的上升曲线。与此同时,右边的图表显示,随着时间的推移,没有发生太大的变化——基本上没有任何进展。

怎么会这样呢?

不同之处在于 Y 轴的设置方式。放大的那个(通过截断 Y 轴)放大了 2.299B 到 2.300B 之间的值,因此从一个不经意的观察者的角度来看,随着时间的推移,改进似乎是显著的。

右边的图表从 0 开始,到 2.5 亿结束,因为对于这种规模的企业(即数十亿)——以每年 10,000 件的增量进行销售可能是我们不想宣扬的事情。然而——这是实际上需要发送给管理层的信息。

那么我们需要总是确保我们看到的任何图表的 Y 轴都固定在 0 吗?

在[7]中,塞思·朗认为这要视情况而定。根据具体情况,微小的差异实际上可能会产生重大影响,并且可能需要数据分析师在 Y 轴上放大,以便向受众清楚地表明,随着时间的推移,情况确实发生了变化。

考虑下面的例子,我们有两个图表描述了一个虚构国家的隔夜政策利率(OPR)。左边的是 Y 轴被截断,而右边的是 Y 轴从 0 开始。

一个虚构国家的隔夜政策利率。左边的图表截断了 Y 轴。右边的图表有一个完整的 Y 轴。(图片由作者提供)

在这种情况下,利率值的微小差异可能会转化为每月贷款/融资付款的巨大差异,我们可以清楚地看到左侧的图表更受欢迎,因为它清晰地展示了利率随时间的差异(与右侧相反)。

3.轴中数据的不连续性

在我们之前的例子中,我们展示了我们可以通过有选择地放大销售数字的 Y 轴来误导观众,以强调我们试图强调的价值。

通过使用不连续的 Y 轴,对销售收入进行另一种尝试。(图片由作者提供)

现在,让我们使用前面示例中的相同销售数据。从前面的教训中,我们知道一个更有说服力的图表应该从 Y 轴的 0 开始。

然而,我们上面的新图表没有在 Y 轴上使用相同的刻度,而是在刻度中引入了一个不连续点,在 2.3B 标记开始的每个刻度处使用 5000,而不是在每个刻度处表示 100 米。

通过这样做,我们现在能够(向不经意的观察者)证明我们的销售数字随着时间呈指数增长。

真是厚颜无耻。

4.双 Y 轴

双 Y 轴本质上是一种在同一图表上绘制两组观察值的绘图技术。这种技术的危险在于,如果分析师为了证明一个观点而调整轴线(或者让它完全消失),它可能会误导观众。

让我们考虑一个例子。现在是 2017 年,假设我们需要根据即将到来的 2018 年业务计划的预测销售收入来证明我们的营销费用。

(左):营销支出似乎高于收入。(右图):收入似乎高于营销支出。(图片由作者提供)

在上面的图表中,我们现有的困境描绘在左边;我们的预计营销支出远远高于我们的预计收入。当描绘在同一个 Y 轴上时,可以立即看出差异。事情看起来对我们不太有利。

在右图中,我们引入了另一个 Y 轴来表示我们的收入数字。这样,我们的收入数字终于出现在我们的营销支出之上。我们的商业计划现在“看起来”比以前更加坚实。

一个更极端的、真实的例子,关于人们如何试图逃避玩双 Y 轴可以参考[8],其中代表 Jason Chaffetz 试图指出,计划生育(一个非政府组织)在 7 年期间增加了堕胎数量,减少了癌症筛查和预防服务。最初的图表似乎支持他的观点,如果不是因为数字线本身不应该交叉,如果绘制在相同的 Y 轴上的话。

不过,返回到双 Y 轴——在构建图表时,这种技术本身并不令人不快(在某些情况下,它确实有它的用途)。然而,在应用它时,需要注意不要误导观众。

5.累积的

现在是 2018 年底(在我们的假设故事中),我们未能达到我们的收入目标。我们的经理完全无视我们的收入数字,安排了一次市场简报会,我们将在会上向市场分析师和投资者简要介绍公司今年的表现。

让我们试着深入挖掘我们的月销售收入。

我公司 2018 年月度营收。(图片由作者提供)

以上表明,我们在 2018 年上半年一直做得相对较好,但自 2018 年 8 月以来走下坡路。对我们产品的需求急剧下降,而且没有回升的迹象,这肯定会吓坏市场、投资者和我们未来的客户。

我们如何描绘一幅更积极的画面,并改变叙事?

输入累积图。

月收入累积图。(图片由作者提供)

虽然上图仍然显示收入增长率在下降,但对于普通观众来说,我们的销售收入确实在增加。总而言之,积极的一面!

事实上,这种方法正是苹果公司[2]在 2013 年的演示中使用过的。在那次演讲中,蒂姆·库克展示了一段时间内 iPhone 的累计销量——从一个不经意的观察者的角度来看,这似乎表明苹果一切都很顺利。然而,分析每个季度的数据显示了一个不同的故事,iPhone 的销售在过去几个季度实际上一直停滞不前。

摘要

在本文中,我们通过几个例子说明了如何通过摆弄图表的坐标轴来歪曲数据。

我们涵盖了:

  1. 未标记图表/坐标轴
  2. 截断轴
  3. 轴中数据的不连续性
  4. 双 Y 轴
  5. 累积的

有些技术非常明显,很容易被发现。其他的(如双 Y 轴)对于未受过训练的人和不习惯定期阅读图表的人来说可能需要一段时间才能理解。

这篇文章背后的想法,如果还不明显的话,就是不鼓励数据失实。更确切地说,写这篇文章是希望我们能更好地了解数据和图表是如何适应演讲者的叙述的。

请记住,误传往往是偶然的。虽然有时,他们可能是故意的。

理解了这一点,我们就能更好地解读任何对我们有利的图表。希望我们现在能更好地质疑我们在图表中看到的东西,而不是图表中实际显示的东西。

参考

[1]https://www . Amazon . com/Field-Guide-Lies-Critical-Information/DP/1524702528

[2]https://www . tech junkie . com/Tim-cook-trying-prove-needness-chart/

[3]https://www . calling bullshit . org/tools/tools _ missinging _ axes . html

[4]https://xd gov . github . io/data-design-standards/components/axes

[5]https://www . statistics show to . com/probability-and-statistics/descriptive-statistics/missinging-graphs/

[6]https://www.heap.io/blog/how-to-lie-with-data-visualization

[7]https://technaverbascripta . WordPress . com/2014/04/16/lie-with-data-visualizations-is-it-missing-to-truncate-the-y-axis/

[8]https://www . vox . com/2015/9/29/9417845/planned-parenthood-terrible-chart

绝对初学者如何用 Python 做数据库连接

原文:https://towardsdatascience.com/how-to-make-a-database-connection-in-python-for-absolute-beginners-e2bfd8e4e52

连接 MS SQL Server、MySQL、Oracle 和许多其他数据库的 3 个步骤(+示例)

连接时间(图片由马库斯·乌尔本斯Unsplash 上拍摄)

使用 Python,我们可以自动编写和执行 SQL。但是要做到这一点,我们需要 Python 能够与数据库通信。在本文中,我们将重点关注使用名为pyodbc的包,通过 ODBC 协议与关系数据库进行通信。阅读完本文后,你将能够在你的 Python 应用程序中编写和执行 SQL。我们来编码吧!

在开始之前..

让我们定义一下这篇文章的范围。

Postgres 用户?

有许多数据库符合 ODBC 和 pyodbc,在本文中我们将使用 MS SQL。如果您正在使用 PostgreSQL,那么请查看下面的文章,了解更优化的方法。

https://mikehuls.medium.com/creating-a-python-postgresql-connection-for-absolute-beginners-501b97f73de1

生成 SQL 查询

本文重点介绍如何使用 pyodbc 创建与数据库的连接。然后可以使用这个连接来执行 SQL。有些数据库使用不同的语法:

  • MS SQL Server
    SELECT TOP 1 colname FROM tablename LIMIT 10
  • PostgreSQLT2

这意味着您必须为特定的数据库编写 SQL 语句。

有一种与数据库无关的方法,可以用更 Pythonic 化的方式定义查询,然后针对某个数据库进行编译。这将为那个数据库生成特定的 SQL,这样您就不会受限于您当前使用的数据库的特定内容。这意味着,如果你将来决定从 MySQL 转换到 Postgres,你不必修改你的代码。

我正在写这篇文章,所以请务必关注我

关于 pyodbc 和 odbc 协议

关于我们正在使用的软件包及其工作原理的一些背景知识。Pyodbc 是一个允许您与(关系)数据库通信的包。它使用开放式数据库通信协议。这个协议定义了客户端(就像您的 Python 脚本)和数据库如何通信。

您可以将这种通信协议与 HTTP 协议进行比较,HTTP 协议有助于计算机之间通过 internet 进行通信:客户端知道如何请求资源,服务器知道如何响应,客户端知道响应是什么样的,因此它们可以使用这些信息。同样,客户端可以使用 ODBC 协议与数据库通信。

连接到数据库—代码部分

我们将经历几个简单的步骤。我们需要使用我们的凭证来创建一个连接字符串。用那根线我们可以建立联系。在连接上,您可以创建一个我们将用来执行查询的游标。首先做一些准备:

准备:依赖性

首先,让我们创建一个虚拟环境,并安装我们唯一的依赖项。

pip install pyodbc

第一步。收集我们的凭证

这是我们检索数据库凭证的地方。在下面的例子中,我们尽可能以最安全的方式处理我们的凭证:我们从环境中加载它们,这样我们的应用程序就可以访问它们,而无需将它们硬编码到我们的脚本中。

import pyodbc

driver: str = 'ODBC Driver 17 for SQL Server'
username = os.environ.get("SQLSERVER_USER")
password = os.environ.get("SQLSERVER_PASS")
host = os.environ.get("SQLSERVER_HOST")
port = os.environ.get("SQLSERVER_PORT")
database = os.environ.get("SQLSERVER_DB")

通过学习如何应用下面文章中的env files来防止您的密码泄露:

第二步。创建连接字符串

Pyodbc 需要一个包含我们的凭据的格式化字符串来连接到数据库。在下面的例子中,我们使用 f 字符串来创建连接字符串,同时保持代码的整洁。

password = "}}".join(password.split("}"))

constring = f"DRIVER={driver};" \
            f"SERVER={host};" \
            f"DATABASE={database};" \
            f"UID={username};" \
            f"PWD={{{password}}};" \
            f"port={port};"

修复密码..
password发生了一些诡异的事情。首先,我们将密码中的所有}花括号折叠起来,然后我们再次用花括号将它括起来。这是因为密码可能包含一些奇怪的字符,例如/\{};。用花括号把它们括起来可以避免所有的错误。我们不希望我们的密码中的任何花括号被转义,所以我们将它们加倍,以便“避免转义”。

有点奇怪,但这显然是它的工作方式。还要注意,这不仅适用于密码,也适用于任何参数,所以如果您的用户名包含特殊字符,您也可以使用这种技术。

产生的连接字符串如下所示(注意,my_}password现在被正确地翻译成了{my_}}password})。

DRIVER=ODBC Driver 17 for SQL Server;SERVER=my_host;DATABASE=my_database;UID=my_username;PWD={my_}}password};port=my_port;

第三步。连接

这是最简单的部分,我们将创建一个连接(通常每个应用程序有一个连接)。然后我们在连接上创建一个光标。游标用于迭代查询产生的结果集。处理完结果集后,关闭光标。

cnxn:pyodbc.Connection = pyodbc.connect(constring)cursor:pyodbc.Cursor = cnxn.cursor()
try:
    cursor.execute("SELECT @@VERSION")
    print(cursor.fetchone())
except Exception as e:
    print(f"Connection could not be established: {e}")
finally:
    cursor.close()

接下来,我们可以使用光标执行一些 SQL,在本例中,我们打印出 SQL Server 数据库的版本。如果有任何失败,我们打印出错误,并且在任何情况下,我们关闭我们的光标。

有一种更短、更好的方法可以做到这一点:

with cnxn.cursor() as cursor:
    try:
        cursor.execute("SELECT @@VERSION")
        print(cursor.fetchone())
    except Exception as e:
        print(f"Connection could not be established: {e}")

使用上下文管理器(with部分)会使光标自动关闭。此外,它将提交(您必须commit插入;看下面的例子)你在try块中执行的任何东西。如果它检测到错误,它将回滚所有查询。请注意,这仅适用于使用autocommit=False(默认设置)创建连接的情况。

https://medium.com/geekculture/understanding-python-context-managers-for-absolute-beginners-4873b6249f16

额外收获:示例查询

这里有一些示例查询可以帮助您。

查询 1:选择记录

使用cursor.fetchone()检索单个行。

with cnxn.cursor() as cursor:
    cursor.execute("SELECT * FROM INFORMATION_SCHEMA.TABLES")
    for row in cursor.fetchall():
        print(row)

查询 2:选择记录;转换为字典列表,其中每个字典为一行

with cnxn.cursor() as cursor:
    cursor.execute("SELECT * FROM INFORMATION_SCHEMA.TABLES")
    colnames = [col[0] for col in cursor.description]
    coltypes = [col[1] for col in cursor.description]
    for rowvalues in cursor.fetchall():
        # convert types
        rowvalues = [coltypes[i](rowvalues[i]) for i in range(len(coltypes))]
        # make dicts from the colnames and rowvalues
        row = dict(zip(colnames, rowvalues))
        print(row)

查询 3:常规插入

因为我们在上下文管理器块中(即with),所以如果没有错误发生,执行将被提交。光标也会自动关闭。

with cnxn.cursor() as cursor:
    cursor.execute("INSERT INTO med.mytable (name, age)  VALUES (?,?)", "mike", 32)

[## SQL —在一条语句中插入、删除和更新:用 MERGE 同步表

towardsdatascience.com](/sql-insert-delete-and-update-in-one-statement-sync-your-tables-with-merge-14814215d32c)

查询 4:回滚插入

前两个被插入,然后#3 失败,所以#1 和# 2 再次回滚。数据库里不会有 a 先生,b 先生,c 先生的踪迹。

with cnxn.cursor() as cursor:
    cursor.execute("INSERT INTO med.mytable (name, age)  VALUES (?,?)", "mr. a", 44)
    cursor.execute("INSERT INTO med.mytable (name, age)  VALUES (?,?)", "mr. b", 33)
    cursor.execute("INSERT INTO med.mytable (name, age)  VALUES (?,?)", "mr. c", 55, "toomany")

查询 5:超快速插入

上面的插入将一次插入一行。使用下面的选项,我们可以为多行创建一条语句,从而大大提高插入速度。

with cnxn.cursor() as cursor:
    cursor.fast_executemany = True
    SQL = "INSERT INTO med.mytable (name, age)  VALUES (?,?)"
    values = [
        ('mr. y', 21),
        ('mr. x', 98)
    ]
    cursor.executemany(SQL, values)

阅读下面的文章,了解fast_executemany的内部工作原理。

重要的

为了防止 SQL 注入攻击,一定要清理放入 SQL 语句中的变量,尤其是在允许用户输入语句的情况下。这一点被 这部 XKCD 著名漫画 诠释得很漂亮。

后续步骤

现在您的脚本可以连接到数据库了,您可以开始编写 SQL 了。比如你可以用 5 行代码 做一个 API。通过这种方式,您可以为用户提供对数据库的受控访问,定义用户可以请求哪些信息。

请务必查看 此链接 以获得许多有用查询的详细概述。最后,下面的文章详细介绍了如何实现数据库迁移。这使得以编程方式设计和版本控制数据库成为可能。

结论

我希望已经阐明了如何用 pyodbc 连接到您的数据库,并使用它来执行一些 SQL。我希望一切都像我希望的那样清楚,但如果不是这样,请让我知道我能做些什么来进一步澄清。与此同时,请查看我的关于各种编程相关主题的其他文章:

编码快乐!

—迈克

附注:喜欢我正在做的事吗? 跟我来!

https://mikehuls.medium.com/membership

如何在几分钟内制作一个免费的、无服务器的交互式仪表板

原文:https://towardsdatascience.com/how-to-make-a-free-serverless-interactive-dashboard-in-minutes-e6ce5a1088e0

我向你保证,你可以像制作相同口径的标准图像一样快地制作这个仪表盘。这将比你的 Matplotlib 或 ggplot 图更好看。

阿里·乌本Unsplash 上拍摄的照片

与其给同事发送可视化效果,为什么不发送仪表板呢?想给你的老板留下深刻印象,请他或她在浏览器中打开其中一个。

我知道你在想什么,这听起来像是要付出更多的努力——其实不然。

你甚至可以像发送图片一样,用一个简单的文件发送它。

我将在这里向您展示一个非常简单的方法,甚至给您一个将来使用的模板。你可以在几分钟内做出一个来。

最棒的是,打开它只需要一个网络浏览器。幸运的是,每个人都有一个。

那么我们要怎么做呢?

我们将在一个 HTML 文件中完成这一切。是的,HTML。HTML,借助于 chart.js ,一个极其用户友好的图表框架。

当然,我们也会用到一些 JavaScript,但是如果你不知道 JavaScript,不用担心,我会给你提供模板,你会做得很好的。

您几乎不需要自己编写 JavaScript 代码。我们将使用 chart.js cdn 将所有内容保存在一个文件中,对任何其他用户都没有要求。

我也将向你展示如何毫不费力地设计它。

我们要创造什么?

我们将创建一个仪表板—一组交互式图表和可视化。我们希望这一切都在一个地方,我们希望它很容易被任何人看到和理解。因此,它必须是用户友好的和交互式的。

这正是我们要创造的。

仪表板 GIF —由作者创建的仪表板和 GIF。

如您所见,这里有条形图、圆环图、饼图和折线图的示例。任何你能想到的情节,我们都可以很容易地添加进去。图类型的完整列表可在此处找到仪表盘是完全交互式的,可以在所有主流浏览器中打开。

如果您使用 bootstrap,它也可以完美地扩展到移动设备,我也将向您展示这一点。

由作者创作。

一个简单的热身例子

我将从一个极其简单的例子开始。我们将从只有一个图形的仪表板开始,仍然是交互式的,但只有一个完整的页面图形。

由作者创建。

创造这一点非常容易,这个例子可以作为你进一步观想的模板。这是代码。

由作者创建—保存此文件并在浏览器中打开它。

如你所见,它非常简单,只有两个 HTML 元素和几行 JS。让我们从头开始。第 1–5 行是你以前没见过的,标准的 HTML 文件开头,告诉计算机所需的编码和视窗设置。第 6 行很重要,是 chart.js cdn(内容交付网络)。cdn 实际上是从原始服务器分发内容的服务器网络。我喜欢把它想象成从网上导入一个包。没有这条线什么都不会起作用,所以不要忘记它。

在第 10 行,我们进入了 HTML 主体,如前所述,我们只有两个标签——一个标题和一个画布。如果你不想要,你甚至不需要标题,但有标题总是好的。所以在第 10 行,我们有一个简单的标题标签,带有一些内联样式,使其为红色并居中。简单明了。

第 11-13 行是 HTML 最重要的部分,实际上是唯一重要的部分。它只不过是一个画布标签,包装在一个 div 中。canvas 标签用于动态绘制图形,几乎总是由 JS 脚本完成。我们给 canvas 标签一个 id“my chart ”,这样我们可以在以后隔离它。这就是 HTML 的全部内容。

现在来构建图表,正如前面提到的,我们正在使用 chart.js 框架。但是首先,我们需要指定我们的数据。我做了一个非常简单的例子,在一个数组中使用了三个观察值,可以在第 15 行看到。

第 16–29 行是奇迹发生的地方。这是几乎所有 chart.js 图表的样子。我们在第 16 行使用 getElementById 方法将我们的图形附加到我们已经创建的 canvas 标记上,下面几行创建了绘图。首先我们必须指定我们想要使用哪种类型的图表— 这里是所有的例子。显然,这仅限于您输入的数据类型。然后我们输入标签和数据。我已经创建了数据,所以我可以引用这个变量,或者我可以在里面指定数组,就像我对颜色所做的那样。如果颜色数组的长度与数据数组的长度不匹配,它将继续从头开始循环。我把 options 选项留为空,但是在里面只是向您展示如何合并它,您可以在那里指定诸如响应之类的东西。全部选项都在这里。

仅此而已。真的就这么简单。你可以复制这个文件,改变数据和标签,你就有了我们自己的交互式可视化,你可以把它发送给任何你想要的人。它非常容易操作,要制作一个饼图,只需将“线”改为“饼”。在浏览器中打开 HTML 文件,任何人都可以随意摆弄你的图形。请注意,它不会加载到 outlook 预览中,它必须在浏览器中。这里是文件。

虽然我不认为这是一个仪表板,但是我们需要更多的图表。让我告诉你怎么做。

完整的仪表板

基本上,我在这里做的是完全相同的,但只是多了几个图,多了一点风格,并引导图表对齐我们想要的位置。让我们直接进入代码。它看起来远不止如此,它实际上是一个简单的例子,用一些引导包复制并粘贴了四次。

由作者创建—看起来比实际复杂。基本上就是第一个例子复制了 4 次。

第一部分和以前一样,除了我们增加了第 7 行和第 8 行,第 7 行是我为一些额外的样式选择的 google 字体,第 8 行是 bootstrap 样式表,它将帮助我们稍后轻松地设计和定位我们的项目。

正文标签的开头也几乎相同,除了我们在副标题中添加了一个 H3 标签。我还为它们添加了一些额外的样式,让它们看起来更漂亮——使用我之前导入的谷歌字体

第 19 到 32 行是 bootstrap 发挥作用地方。在这里,我们希望一些元素并排,即我们的饼图和圆环图。我意识到他们对这些数据做了完全相同的事情,但我只是用它们来说明如何水平而不是垂直堆叠图。

由作者创建。

我不打算详细介绍 Bootstrap 的网格系统是如何工作的,尽管拿 5 来读读吧——这是网络定位的一个新发现。用 Bootstrap 自己的话说:“Bootstrap 的网格系统使用一系列容器、行和列来布局和对齐内容。它采用 flexbox 制造,反应灵敏。屏幕被有效地分成 12 个垂直列,你可以在特定的屏幕尺寸上为每个对象分配一些列。

因此,在我们的容器元素中,我们有一个包含两个元素的行,这两个元素在中等大小的屏幕上被分配了 12 列中的 6 列。这些元素和以前一样是画布标签。

所以我们有一个图表,在一排两个图表之上,在一个单独的图表之上。

其余代码与简单示例完全相同,只是复制和粘贴。在我们的简单示例中,我们可以复制并粘贴图表,更改它们的类型和 ID,将它们封装在一些引导程序中,这样我们就有了一个仪表板。简单。

你可以把仪表板做得简单或复杂,可能性是无限的。随意复制代码,给你的同事留下深刻印象。

感谢阅读,我希望这能帮助你。

If I’ve inspired you to join medium I would be really grateful if you did it through this [link](https://jamesasher4994.medium.com/membership) — it will help to support me to write better content in the future.If you want to learn more about data science, become a certified data scientist, or land a job in data science, then checkout [365 data science](https://365datascience.pxf.io/c/3458822/791349/11148) through my [affiliate link.](https://365datascience.pxf.io/c/3458822/791349/11148)

这是我写的其他一些东西:

如何用 PyTorch 制作用于时间序列预测的转换器

原文:https://towardsdatascience.com/how-to-make-a-pytorch-transformer-for-time-series-forecasting-69e073d4061e

这篇文章将向你展示如何一步一步地将时序转换器架构图转换成 PyTorch 代码

变电站。图片由 WikimediaImages 提供。

变压器模型在许多时间序列预测问题中表现出了最先进的性能[1][2][3]。

在本文中,您将学习如何在 PyTorch 中为时间序列预测编写一个 transformer 架构。具体来说,我们将对论文“时间序列预测的深度转换模型:流感流行案例” [2]中使用的架构进行编码,我们将使用他们的架构图作为出发点。

因此,我将一步一步地展示如何对图中的每个组件进行编码。通过这种方式,您将学习解释 transformer 架构图并将其转换为代码的通用技巧。

我将解释这个过程,就好像您以前从未实现过 transformer 模型一样。然而,我确实假设你对 PyTorch 和机器学习有基本的了解。最终的结果将是一个我们称之为TimeSeriesTransformer的类,在这个类中所有的东西都聚集在一起。

我还将解释模型的forward()方法的输入必须是什么,以及如何创建它们。

值得注意的是,没有一个转换器模型架构。存在几种不同的变压器架构。由此自然得出结论,例如,当我说编码器由 x、y、z 组成时,我指的是我们在本文中实现的 transformer 架构的编码器,而不是某种通用的 transformer 编码器。

这是我们将在本文中实现的架构图:

图一。图片作者:吴,格林,本&奥巴尼恩,2020 [2]

请注意,虽然该图仅描述了两个编码器层和两个解码器层,但作者实际上在每个层中都使用了四个层[2]。

下面的表 1 给出了构建图 1 中的时序转换器架构所需的所有组件的概述,以及使用什么类来制作每个组件。如您所见,我们只需要实现一个定制类。PyTorch 中提供了其他所有内容。耶!

表 1。时序转换器组件概述。图片由 Kasper Groes 阿尔宾 Ludvigsen。

起初让我困惑的是,在图 1 中,输入层和位置编码层被描述为编码器的一部分,而在解码器端,输入层和线性映射层被描述为解码器的一部分。

在最初的 transformer 论文[4]中,情况并非如此,其中输入层、位置编码层和线性层被描述为与编码器和解码器分离(参见下面的图 2)。

为了与最初的 transformer 文件保持一致,我将在这篇文章中说,编码器和解码器仅由 n 个堆叠的编码器或解码器层组成,我将把其他层视为编码器和解码器之外的独立层。此外,根据最初的 transformer 论文[4],我不会将“添加和规范化”操作称为层。

图二。在最初的 transformer 论文中,输入层和位置编码层被描述为与编码器和解码器分离,这与[2]相反。瓦斯瓦尼等人的图片 2017 [4]

该员额的其余部分结构如下:

  1. 首先,我们将在名为TimeSeriesTransformer的课程中了解如何制作变压器的每个组件,以及如何将它们组装在一起
  2. 然后,我将展示如何为模型创建输入

我将不提供组件内部工作的详细描述,因为这些在别处已经解释得很清楚了(例如[5][6])。

当你读完这篇文章后,你可能想学习如何在推理过程中使用时间序列转换器:

1.分解变压器架构

让我们将图中所示的转换器架构分解成它的组成部分。

1.1。编码器输入层

图片作者吴,格林,本&奥巴尼恩,2020 2

编码器输入层简单地实现为神经网络。线性()层。in_features参数必须等于作为模型输入的变量数量。在一个单变量时间序列预测问题中,in_features = 1out_features参数必须是d_model,它是一个在【4】中具有值512的超参数。

下面是TimeSeriesTransformer类中的代码:

1.2。位置编码层

图片作者吴,格林,本&奥巴尼恩,2020 2

最初的 transformer 论文的作者非常简洁地描述了位置编码层的作用以及为什么需要它:

由于我们的模型不包含递归和卷积,为了让模型利用序列的顺序,我们必须注入一些关于序列中记号的相对或绝对位置的信息

下面是将位置编码器实现为一个类的一种方法。

下面是如何在TimeSeriesTransformer类中使用PositionalEncoder类:

如您所见,dim_val是作为d_model参数提供的。这很重要,因为编码器输入层产生大小为dim_val的输出。

1.3。编码器层

图片作者吴,格林,本&奥巴尼恩,2020 2

请注意,虽然该图仅描述了两个编码器层,但作者实际上使用了四个编码器层[2]。

[2]使用的编码器层与 PyTorch Transformer 库所基于的[4]使用的编码器层相同,因此我们可以简单地使用 PyTorch 来创建编码器层。

这样做的方法是首先制作一个对象,我们可以称之为encoder_layer,用torch.nn.TransformerEncoderLayer这样:

encoder_layer = torch.nn.TransformerEncoderLayer(d_model, nhead, batch_first=True)

通过使用torch.nn.TransformerEncoderLayer,该层将自动具有如上所述的自我关注层和前馈层,以及中间的“添加&正常化”。注意,没有必要使encoder_layer成为TimeSeriesTransformer类的实例属性,因为它只是作为参数传递给nn.TransformerEncoder

然后像这样将encoder_layer对象作为参数传递给torch.nn.TransformerEncoder,以便堆叠 4 个相同的编码器层:

self.encoder = torch.nn.TransformerEncoder(encoder_layer, num_layers=4, norm=None)

注意normnn.TransformerEncoder中的一个可选参数,当使用标准nn.TransformerEncoderLayer类时传递一个标准化对象是多余的,因为nn.TransformerEncoderLayer已经在每一层后标准化了。可选参数用于不包括标准化的自定义编码器层[7]。

下面是编码器代码在TimeSeriesTransformer类中的一个片段。

1.4.解码器输入层

图片作者吴,格林,本&奥巴尼恩,2020 2

解码器输入层只是一个线性层,就像编码器输入层一样。in_features参数必须等于作为模型输入的变量的数量。在一个单变量时间序列预测问题中,in_features = 1out_features参数必须是d_model,它是一个在【4】中具有值512的超参数。我们将使用这个值,因为[2]没有指定它。

下面是TimeSeriesTransformer类中的代码:

1.5.解码器层

图片作者吴,格林,本&奥巴尼恩,2020 2

注意,尽管该图仅描绘了两个解码器层。作者实际上使用了四个解码器层[2]。

解码器的制作方式与编码器完全相同,根据[2],其中num_layers为 4。

[2]没有指定他们使用多少头,所以我们将按照[4]使用nheads=8

这里有一个片段展示了解码器代码放在TimeSeriesTransformer类中时的样子。

1.6.线性映射层

图片作者吴,格林,本&奥巴尼恩,2020 2

尽管这一层被称为“线性映射层”,但除了参数值之外,它实际上与编码器和解码器输入层相同:

in_features必须等于输出序列长度乘以 d_model,以适应解码器的输出。

out_features必须等于目标序列长度,因为线性映射层是变压器模型的最后一层。因此,如果您的时间序列数据集由每小时的数据点组成,并且您想要预测未来 24 小时,out_features必须是 24。

下面是TimeSeriesTransformer类中的代码:

组装变压器模型

既然我们已经看到了如何对图中所示的构成 transformer 模型的每个组件进行编码,我们将把它们放在一个类中。参数的默认值是[2]中使用的值。

初始化转换器模型

既然我们已经看到了如何编写TimeSeriesTransformer类,我还想快速展示如何初始化模型以及什么值作为参数传递。模型的实现方式,只有input_sizedec_seq_lenmax_seq_len是必需的,其余都有默认值。

2.如何创建变压器模型的输入

正如在TimeSeriesTransformer类中看到的,我们模型的forward()方法接受 4 个参数作为输入。在这一节中,我将解释如何创建这四个对象。

这些输入是:

  1. src
  2. trg
  3. src_mask
  4. trg_mask

2.1.如何为时序转换器模型创建 src 和 trg

让我们先仔细看看srctrg是如何为时序变压器模型制作的。

src是编码器输入,是“源”的简称。src只是整个序列中连续数据点的子集。src的长度决定了您的模型在进行预测时会考虑多少过去的数据点。如果数据集的分辨率为每小时,则一天有 24 个数据点,如果您希望模型基于过去两天的数据进行预测,则src的长度应为 48。

trg是解码器输入。Trg 是“target”的缩写,但这有点误导,因为它不是实际的目标序列,而是由src的最后一个数据点和实际目标序列中除最后一个数据点以外的所有数据点组成的序列。这就是为什么人们有时称 trg 序列为“右移”。trg的长度必须等于实际目标序列的长度【2】。你有时会看到术语tgt被用作同义词。

以下是对数据点srctrg必须包含的内容的简明解释:

在典型的训练设置中,我们训练模型从 10 个跟踪的每周数据点预测 4 个未来的每周 ILI 比率。也就是说,给定编码器输入(x1,x2,…,x10)和解码器输入(x10,…,x13),解码器的目标是输出(x11,…,x14)。 ([2]第 5 页)

给定一个序列,这里有一个函数产生srctrg以及实际的目标序列trg_ysrctrg对象被输入到模型中,而trg_y是目标序列,当计算损失时,模型的输出与该目标序列进行比较。给get_src_trg()函数的sequence必须是整个数据集的子序列,长度为 input _ sequence _ length+target _ sequence _ length。

下面是创建srctrgtrg_y的函数:

2.2.屏蔽变压器中的解码器输入

我们现在已经看到了如何生成我们的模型的forward()方法所需要的前两个输入。现在让我们考虑我们的模型的forward()方法需要的最后两个输入:src_masktrg_mask

但首先你应该知道在变形金刚的上下文中有两种类型的屏蔽:

  1. 填充蒙版。当使用不同长度的序列(句子通常具有不同的长度)时,短于所选最大序列长度(这是一个可以具有任何值的超参数,例如 50)的序列将用填充标记填充。填充标记必须被屏蔽,以防止模型关注这些标记。
  2. 解码器输入屏蔽(又名“前瞻屏蔽”)。这种类型的屏蔽防止解码器在“考虑”令牌 t 具有什么“含义”时关注未来的令牌。

在这篇文章中,我们不会填充我们的序列,因为我们将以这样一种方式实现我们的自定义数据集类,即所有序列都具有相同的长度。因此,在我们的例子[8]中不需要填充屏蔽,也没有必要屏蔽编码器输入[9]

然而,我们需要使用解码器输入屏蔽,因为这种类型的屏蔽总是必要的。

回想一下,解码器接收两个输入:

  1. 编码器输出
  2. 解码器输入

这两个都需要屏蔽。

为了屏蔽这些输入,我们将为模型的forward()方法提供两个屏蔽张量:

  1. src_mask这会屏蔽编码器输出
  2. trg_mask这会屏蔽解码器输入

在我们的例子中,src_mask将需要具有以下尺寸:

[目标序列长度,编码器序列长度]

并且trg_mask将需要具有大小:

[目标序列长度,目标序列长度]

以下是生成遮罩的方法:

以下是如何使用遮罩作为模型的输入:

时间序列转换器的完整示例

我已经创建了这个回购,它包含了一个完整的例子和一些时间序列数据。repo 还包含用时序转换器模型运行推理的代码,我的文章“如何用 PyTorch 时序转换器运行推理”中描述了这些代码

就是这样!我希望你喜欢这篇文章🤞

请留下评论让我知道你的想法。如果您有任何问题或建议,我将非常高兴收到您的来信🙌

关注更多与时间序列预测相关的帖子。我也写绿色软件工程和数据科学对环境的影响,比如这里的和这里的🍀

请随时在 LinkedIn 上与我联系。

参考

[1]https://arxiv.org/abs/2109.12218

[2]https://arxiv.org/abs/2001.08317

https://arxiv.org/abs/2012.07436

https://arxiv.org/pdf/1706.03762.pdf

[5]https://towards data science . com/how-to-code-the-transformer-in-py torch-24 db 27 c 8 F9 EC # 1b3f

[6]http://jalammar.github.io/illustrated-transformer/

https://github.com/pytorch/pytorch/issues/24930

[8]https://github.com/huggingface/transformers/issues/4083

[9]https://medium . com/analytics-vid hya/masking-in-transformers-self-attention-mechanism-bad 3c 9 EC 235 c

如何用计算机视觉让一只 AI 狗吃掉你的作业

原文:https://towardsdatascience.com/how-to-make-an-ai-dog-eat-your-homework-with-computer-vision-1866ada7ac08

OpenCV 和 Python 中一个有趣的项目,利用了面部特征检测

charlesdeluvioUnsplash 上拍摄的照片

虽然学习如何使用人工智能工具来应对复杂的挑战很重要,但我想向你展示它们如何让你发挥创造力,享受乐趣,并将任何事情变成现实。在这种情况下,我们正在为自己没有按时完成工作找一个经典的童年借口:我的狗把它吃了。

项目范围

我们希望你的笔记本电脑上有一只狗。使用你的笔记本电脑的网络摄像头,狗会盯着你的脸。如果你分心了(例如,你把目光从电脑上移开了)或者因为你的努力工作而昏昏欲睡了(例如,你的眼睛闭上了),你的新宠物狗会开始对你吠叫,让你重新开始工作或者叫醒你。如果你仍然没有开始工作,它会吃掉你的作业(也就是删除你应该在做的文件)。

本项目为:

  • 一个有趣的笑话
  • 一个强有力的方法让你继续工作
  • 学习 Python 和 OpenCV 中的面部特征检测、音频回放和系统文件操作的好方法。

如何打造你的爱犬

设置

首先,打开一个新的 Python3 文件。使用您选择的软件包管理器安装cv2send2trashplaysound(我喜欢 pip)。

https://github . com/NP into/opencv/tree/master/data/Haar cascades下载这两个让 OpenCV 检测面部特征的文件,包括睁眼和闭眼:haarcascade_eye_tree_eyeglasses.xmlhaarcascade_frontalface_alt.xml。将它们放在您的项目目录中。

在 Python 文件的顶部,导入我们下载的三个库和两个文件:

*import* cv2
*from* send2trash *import* send2trash
*from* playsound *import* playsoundeye_cascPath = '{PATH}/haarcascade_eye_tree_eyeglasses.xml'  *#eye detect model*face_cascPath = '{PATH}/haarcascade_frontalface_alt.xml'  *#face detect model*

还要定义两个全局变量,我们稍后将使用它们来跟踪用户闭上眼睛的帧数以及他们收到的没有受到惩罚的警告数。

frames_closed = 0 # number of frames the user's eyes are not detected as open
warnings = 0 # number of warning the user has received without their homework being eaten

"狗的行为

为了让我们的 Python 脚本感觉像一只狗,我们需要它吠叫!由于我们将使用的面部特征检测不是 100%万无一失的,我们需要对用户宽容一点,所以我们将实现一个警告系统。每次警告,狗都会叫,三次警告后,它会吃掉你的作业(这个功能我们很快就会实现!).要让狗叫,可以在任何你想要的音频文件上使用playsound库(如果你没有,试试这个网站轻松获得免费声音)。

注意功能开始时global的使用。在 Python 中,这有时对于访问全局变量而不是定义同名的局部变量是必要的。使用面向对象技术可以更容易地避免这种情况,但是因为这是一个快速脚本,所以我们可以接受有点混乱。尽量不要在大型项目中使用这种方法,因为它会很快变得一团糟。

def warn(): global warnings warnings += 1 playsound("./BARKS_WITH_ECHO_SPg.wav") *if* warnings >= 3: delete_hw(hw_path)

饮食行为

现在我们将编写代码,最终让你的狗吃你的作业。

首先,我们想使用 Python 内置的input函数获取用户正在处理的文件。这只是要求用户在运行脚本的终端中输入一个字符串。

hw_path = input("Whatcha working on? ")

然后使用send2trash库定义函数删除或吃掉作业。我使用这个库是因为它允许用户在需要的时候从系统垃圾中恢复他们的文件,但是如果你想冷酷无情,你可以使用os.remove()来代替。os库还有很多其他操作系统文件的简单函数,所以值得以后的项目学习。

如果用户给了我们一个无效的路径,我们也使用我们的warn()函数,我们用tryexcept检查,当send2trash接收到一个无效的路径时,捕捉到它给出的异常。再次注意前面讨论过的global的使用(这开始显示当多个变量被修改时它是如何变得混乱的!).

def delete_hw(path): global frames_closed global warnings frames_closed = 0 warnings = 0 *try*: send2trash(path) *except* Exception *as* e: print("THAT'S NOT A VALID PATH YOU LITTLE CHEAT: " + str(e)) warn()

现在我们有了主要的“狗吃了你的作业”功能。

给我们的狗一个大脑:计算机视觉和面部特征检测

如果我们的眼睛或闭上或不看我们的电脑(基本上,不工作),我们希望狗在三次警告后吃我们的作业,所以是时候用 OpenCV 实现我们程序的主要逻辑了。

用 OpenCV 提供的构造函数加载我们下载的文件。这使用文件中的数据来形成用于检测面部和睁开的眼睛的分类器。这些 xml 文件包含识别不同特性的数据,如本文所述。本质上,图像的不同区域是用不同方向的矩形选取的。当按顺序排列时(“层叠”,正如您可能在函数名中看到的),它们形成了一个粗略的决策树,可以有效地检测我们是否在查看文件的功能。我们使用 OpenCV 提供的标准分类器文件,因为面部特征检测是一项常见的任务,但如果你想修改这个项目,也可以用这个算法训练你自己的分类器文件!

faceCascade = cv2.CascadeClassifier(face_cascPath)
eyeCascade = cv2.CascadeClassifier(eye_cascPath)

用 OpenCV 的给定函数触发网络摄像头。有多种类型的参数可以传入这个构造函数,但是为了方便起见,我选择传入我的相机的设备索引。具体来说,我传入了索引 0,它总是选择设备的主摄像头。传入 1 将选择第二台摄像机,传入 2 将选择第三台摄像机,依此类推。因为如果你不知道索引并不好,所以也有其他的构造函数可用。

cap = cv2.VideoCapture(0)

然后有一个 while 循环来运行每一帧。大致步骤如下:

  1. 当程序运行时,从网络摄像头捕捉每一帧的图像。
  2. 如果有图像,将其转换为灰度。这是必要的,因为 OpenCV 中的detectMultiScale函数期望灰度图像,因为颜色信息实际上对算法没有任何帮助。你可以很容易地在黑白电影里认出一张脸,不是吗?形状最重要,这也是 xml 文件包含数据的目的。
  3. 使用我们的人脸模型 xml 文件,使用上面提到的 Haar 级联算法来检测图像中是否有人脸。
  4. 如果有一张脸,在屏幕上的图像周围画一个矩形,这样我们就可以看到它在工作。在循环结束时在窗口中显示图像。这并没有给项目增加任何功能,但是这是一个很好的视觉效果。
  5. 同样,使用我们的眼睛模型来检查人脸中是否有睁开的眼睛,使用与检测人脸相同的技术。
  6. 相应地更新frames_closed,如果一行中有太多关闭的框架,那么我们必须warn()用户。

代码如下:

*while* 1: ret, img = cap.read() *if* ret: frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = faceCascade.detectMultiScale( frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), *# flags = cv2.CV_HAAR_SCALE_IMAGE* ) *if* len(faces) > 0: *for* (x, y, w, h) *in* faces: cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) frame_tmp = img[faces[0][1]:faces[0][1] + faces[0][3], faces[0][0]:faces[0][0] + faces[0][2]:1, :] frame = frame[faces[0][1]:faces[0][1] + faces[0][3], faces[0][0]:faces[0][0] + faces[0][2]:1] eyes = eyeCascade.detectMultiScale( frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), *# flags = cv2.CV_HAAR_SCALE_IMAGE* ) *if* len(eyes) == 0: print('no eyes!!!') frames_closed += 1 *else*: print('eyes!!!') frames_closed = 0 frame_tmp = cv2.resize(frame_tmp, (400, 400), interpolation=cv2.INTER_LINEAR) cv2.imshow('Face Recognition', frame_tmp) *else*: print('no face!!!') frames_closed += 1 *if* frames_closed >= 60: frames_closed = 0 warn()    waitkey = cv2.waitKey(1) *if* waitkey == ord('q') or waitkey == ord('Q'): cv2.destroyAllWindows() *break*

包裹

运行程序时应该看到的示例。

现在你应该有一只功能正常的人工智能狗,如果你不集中注意力,它会吃你的作业。希望这篇教程对你在 OpenCV 和 Python 中的面部特征检测有所帮助。我也希望你能从中发现一些幽默!一个主观上有用的工具…最重要的是,我希望这能激发你对代码的兴趣,让你的想象力自由驰骋——软件不仅仅是功利的。如果结合并正确使用,即使像这样简单的工具也是非常强大的。

面部识别风险

需要警惕的一点是面部检测的风险。这可能是对隐私的严重侵犯——幸运的是,这个简单的脚本不存储任何数据,所有处理都在本地完成。如果要修改的话,用户的隐私应该得到保护。此外,算法在不同种族、性别等方面的表现可能存在偏差。所以要注意这一点。

请在评论中告诉我任何想法或问题。我很高兴地指出我写的更多关于狂野的想法和艺术与科技相遇的文章!

如何用 Python 制作动画和赛车条形图

原文:https://towardsdatascience.com/how-to-make-animated-and-racing-bar-plots-in-python-c5c7c3c648f7

Unsplash 上由卡兰·史密斯拍摄的照片

完整的工作代码

条形图是非常基本和常见的。所有的绘图库都有条形图选项。这篇文章将集中在动画酒吧情节。我将分享一些动画条形图的代码。如果你以前没看过,你可能会喜欢。

我试图简单地介绍它们,以便于理解。我总是喜欢从基本情节开始。在这里,我从受这一页启发的两个情节开始。

我不得不使用下面的命令在我的 anaconda 环境中安装“ImageMagick ”,因为我想保存这些图并上传到这里。你可能想保存你的动画情节,以便上传或在其他地方展示。

conda install -c conda-forge imagemagick

这些是一些必要的进口:

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
from matplotlib.animation import FuncAnimation

这是一个基本的动画条形图的完整代码。我将在代码和可视化部分之后解释代码:

%matplotlib qt
fig = plt.figure(figsize=(8,6))
axes = fig.add_subplot(1,1,1)
axes.set_ylim(0, 120)
plt.style.use("seaborn")lst1=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ]
lst2=[0, 5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 100]def animate(i):
    y1=lst1[i]
    y2=lst2[i]

    plt.bar(["one", "two"], [y1,y2], color = ["red", "blue"])

plt.title("Intro to Animated Bar Plot", fontsize = 14)
anim = FuncAnimation(fig, animate, frames = len(lst1)-1)
anim.save("bar1.gif", writer="imagemagick")

作者图片

现在让我们看看代码是如何工作的。首先,我为两个条形创建了两个列表。

这里的 animate 函数获取两个列表的元素,并使用两个列表 y1 和 y2 创建两个名为“one”和“two”的条形。

FuncAnimation 函数实际上创建了动画。它采用动画函数和数据长度。

为了保存该图,我们需要为该图提供一个名称。这里我用了一个很普通的名字,‘bar 1 . gif’。它使用我们一开始安装的“imagemagick”来编写情节。

这个和第一个差不多,这里有更多的小节。

%matplotlib qt
fig = plt.figure(figsize=(8,6))
plt.style.use("seaborn")
axes = fig.add_subplot(1,1,1)
axes.set_ylim(0, 100)l1=[i if i<20 else 20 for i in range(100)]
l2=[i if i<85 else 85 for i in range(100)]
l3=[i if i<30 else 30 for i in range(100)]
l4=[i if i<65 else 65 for i in range(100)]palette = list(reversed(sns.color_palette("seismic", 4).as_hex()))y1, y2, y3, y4 = [], [], [], []
def animate(i):
    y1=l1[i]
    y2=l2[i]
    y3=l3[i]
    y4=l4[i]

    plt.bar(["one", "two", "three", "four"], sorted([y1, y2, y3, y4]), color=palette)

plt.title("Animated Bars", color=("blue"))
anim = FuncAnimation(fig, animate, frames = len(l1)-1, interval = 1)
anim.save("bar2.gif", writer="imagemagick")

作者图片

注意这里我在开头包含了 axes.set_ylim。如果不设置 y 轴限制,绘图将如下所示:

作者图片

几个月前,我在社交媒体上看到了一个关于 Covid 死亡的动画条形图,并决定检查如何做到这一点。我在这里分享这个情节。

在接下来的图中,我将使用这个超市数据集。请随意从这里下载数据集:

https://www.kaggle.com/datasets/vivek468/superstore-dataset-final

作者在页面描述中提到,仅允许将该数据集用于教育目的。

让我们导入数据集并查看列:

df = pd.read_csv("Superstore.csv", encoding='cp1252')
df.columns

输出:

Index(['Row ID', 'Order ID', 'Order Date', 'Ship Date', 'Ship Mode',
       'Customer ID', 'Customer Name', 'Segment', 'Country', 'City', 'State', 'Postal Code', 'Region', 'Product ID', 'Category', 'Sub-Category', 'Product Name', 'Sales', 'Quantity', 'Discount', 'Profit'], dtype='object')

如你所见,数据集相当大。但是在接下来的图中,我们将只使用“订单日期”、“利润”和“州”列。

地块将按每个州按月统计总销售额。

我们需要为此进行一些数据准备。因为我们将为此使用 bar_chart_race 函数,并且该函数需要特定格式的数据用于绘图。

首先,“订单日期”列需要采用“日期时间”格式。

df['Order Date'] = pd.to_datetime(df['Order Date'])

我将使用 pivot_table 函数将每个州的销售数据作为列:

pv = df.pivot_table("Sales", index = "Order Date", columns = ["State"], aggfunc = np.sum)

以下是部分输出:

它给了我们这么多空值,因为每天的销售数据是不可用的。请注意,“订单日期”列现在是索引。

我将用零填充这些空值。此外,我按照“订单日期”对数据集进行排序

pv.sort_index(inplace=True, ascending=True)
pv = pv.fillna(0)

现在,我们用零替换了所有的空值。

正如我之前提到的,我想按月查看每个州的销售额。因此,我将省略日期部分,只保留“订单日期”中的月和年部分。

pv['month_year'] = pv.index.strftime('%Y-%m')
pv_month = pv.set_index("month_year")

稍后您将看到数据集。

如果我们想得到每月的数据,我们必须对 month_year 数据使用 group by。

pv_month.reset_index()
pv_monthgr = pv_month.groupby('month_year').sum()

作者图片

这是数据集现在的样子。我们有每个州的月度销售数据。要使用 bar_chart_race 函数,需要有这种格式的数据集。

我应该提醒你,渲染这些图比渲染普通的条形图要花更多的时间。当我为这个教程做这些的时候,有时会卡住。我让我的电脑休息了一会儿,然后回来重启我的内核,然后它运行得更快了。但是,总的来说需要更长的时间。

这是基本的柱状图。我使用过滤器列颜色参数为真,这样它就不会重复酒吧的颜色。

import bar_chart_race as bcr
bcr.bar_chart_race(df = pv_monthgr, filename = "by_month.gif", filter_column_colors = True, 
cmap = "prism", 
title = "Sales By Months")

作者图片

可以看到默认情况下是降序排列的。每个月各州的顺序都在变化。但它移动得如此之快,以至于你甚至很难看清美国的名字。在右下角,它显示月份。

在接下来的剧情中,我们会看到一些改进。period_length 参数控制速度。我用了 2500,挺高的。因此,它将显示一个月,比默认时间长很多。

有一个 n_bars 参数来指定我们希望在一帧中看到多少条。我定在 10 点。因此,我们将看到基于每月销售额的前 10 个州。“fixed_max”参数将 x 轴固定为总的最大销售额。所以它不会在每一帧都改变。

bcr.bar_chart_race(df=pv_monthgr,filename="bar_race3.gif", filter_column_colors=True, 
cmap='prism', 
sort = 'desc', 
n_bars = 10, 
fixed_max = True, 
period_length = 2500, 
title='Sales By Months', 
figsize=(10, 6)))

作者图片

在下一个情节中,我们将在情节中增加一条信息。每一帧都展示了一个月的情节。右下角会显示当月的销售总额。

为此,我添加了一个名为 summary 的函数。我还包含了一些更多的样式参数。酒吧标签大小,酒吧风格,使其有点透明,并给出一个边界。我们还添加了一个垂直条,显示每个月的平均销售额。每个月的平均销售额都不同。所以,垂直杆会继续移动。

def summary(values, ranks):
    total_sales = int(round(values.sum(), -2))
    s = f'Total Sales - {total_sales:,.0f}'
    return {'x': .99, 'y': .1, 's': s, 'ha': 'right', 'size': 8}bcr.bar_chart_race(df=pv_monthgr,
filename="bar_race4.gif", filter_column_colors=True,
                   cmap='prism', sort = 'desc', n_bars = 15,
                   fixed_max = True, steps_per_period=3, period_length = 1500,
                   bar_size = 0.8,
                   period_label={'x': .99, 'y':.15, 'ha': 'right', 'color': 'coral'},
                   bar_label_size = 6, tick_label_size = 10,
                   bar_kwargs={'alpha':0.4, 'ec': 'black', 'lw': 2.5},
                   title='Sales By Months',
                   period_summary_func=summary,
                   perpendicular_bar_func='mean',
                   figsize=(7, 5)
                  )

作者图片

这将是我添加另一个函数的最后一个图,该函数将添加一个自定义函数来添加条形中的第 90 个分位数。steps_per_period 等于 3 意味着需要三个步骤才能转到下一帧。如果您注意到右下角标签中的月份发生了变化,那么条形移动了三次,您可以看到它们是如何重叠并慢慢改变位置的。

def func(values, ranks):
    return values.quantile(0.9)bcr.bar_chart_race(df=pv_monthgr,filename="bar_race5.gif", filter_column_colors=True,
                   cmap='prism', sort = 'desc', n_bars = 15,
                   steps_per_period=3, period_length = 2000,
                   bar_size = 0.8,
                   period_label={'x': .99, 'y':.15, 'ha': 'right', 'color': 'coral'},
                   bar_label_size = 6, tick_label_size = 10,
                   bar_kwargs={'alpha':0.4, 'ec': 'black', 'lw': 2.5},
                   title='Sales By Months',
                   period_summary_func=summary,
                   perpendicular_bar_func=func,
                   figsize=(7, 5)
                  )

作者图片

如果你喜欢竖条而不是横条,请使用 orientation='v '。我更喜欢单杠。

要了解更多关于可用于修改图的不同参数的信息,请访问此链接

请随意为摘要或垂直栏尝试更多的样式选项或不同的功能。

您可能还想尝试标签和刻度的不同颜色、字体和字体大小

结论

尽管有些人可能会认为简单的条形图能更清楚地显示信息。我也同意这一点。但尽管如此,在收藏中有一些像这样有趣的情节还是不错的。你可以看到每个月各州的排名是如何根据销售数据变化的,以及平均销售额或第 90 个分位数是如何移动的。使用静止图无法感受到这种类型的变化。此外,如果你有一些有趣的情节,它抓住了注意力。

请随时关注我在推特,和脸书页面,并查看我的 YouTube 频道

更多阅读

</30-very-useful-pandas-functions-for-everyday-data-analysis-tasks-f1eae16409af> </20-very-commonly-used-functions-of-pyspark-rdd-90b8271c25b2> https://pub.towardsai.net/an-overview-of-the-major-sql-query-clauses-and-most-commonly-used-functions-60720e2a20d7

如何用神经风格转移制作艺术形象

原文:https://towardsdatascience.com/how-to-make-artistic-images-with-neural-style-transfer-345a376d56cf

用 python 实现名画风格到图像的转换

机器学习的深度学习子领域在图像处理中特别有用。卷积神经网络是深度学习的子单元之一,它通过使用卷积层为用户提供灵活的访问,卷积层呈现图像内容的几个特征。这些功能可以由开发者配置用于许多领域,例如图像分类和识别标题下的对象检测和图像分割。本文解释了神经风格转移,这是指使用预训练的模型 VGG-19 在保留图像内容的同时转移图像的风格。图 1 是用文森特·梵高的名画《星夜》和作者的一张照片创作的。

图一。作者与星夜的图像,作者的图像

神经类型转移

为了让主题更容易理解,提醒 CNN 一些要知道的基本事情是有好处的。卷积神经网络(CNN),顾名思义,使用卷积过程,通过基本的数学像素运算来过滤图像。这种过滤揭示了图像的各种特征(边缘、纹理、颜色等。),从而为模型提供了一个更有意义、更轻松的学习过程。

所构建的 CNN 架构按照它所遵循的层次来提取图像的特征,换句话说,网络是分层学习特征的。这些提取的特征还提供了关于图像细节的信息。例如,当低层去除边缘、像素和纹理时,高层学习关于图像的形状和更多技术特征。

图二。一个充满活力的足球运动员的作者的形象,由翁贝特·波丘尼绘画,作者的形象

《足球运动员的活力》,意大利画家翁贝特·波丘尼未来主义时期的最佳作品之一,1913 年。根据博乔尼的观点,没有必要为了在画中描绘一个人而画一个人。由于这个原因,他通过描绘演员来关注动作,因此只有他的腿是可见的。

使用上述方法将神经网络转移与以下过程混合:

图像:

将导入两个图像:内容图像和样式图像。内容形象,顾名思义就是受风格形象影响的主要形象。样式图像是提供内容图像的图像。需要低层特征,因为样式图像是一个馈线。另一方面,内容图像需要网络的更高层特征来维持其属性。

网络:

使用 imagenet 权重构建 VGG-19 预训练模型。原始论文的作者建议使用 VGG-19。通过尝试/构建不同的模型也可以获得独特的结果。特征地图必须提供最佳结果,因为这里研究的是提取图像的特征。VGG-19 被推荐为标准。使用该网络提取内容图像和样式图像属性。

提取更高层的特征,以便保留内容图像的主要属性。这些层可以是 conv4_2 和/或 conv5_2。当然,尝试不同的组合会产生明显不同的视觉效果。对于风格图像,通过以各种方式使用低特征,即 conv1_1、conv2_1、conv3_1、conv4_1 和 conv5_1 组合,获得各种视觉结果。

损失

:内容损失:是指利用网络从内容图像和生成图像中提取的特征之间的相似性。

风格损失:风格损失表示风格损失风格图像和生成图像之间激活层相关性的相似性。这里,生成的图像和样式图像之间的相关性通过 gram 矩阵找到。

Gram Matrix: 相关值,表示风格图像与生成图像的相似度,是本题的关键点之一。使用卷积层提取图像的各种特征。这些特征是边缘、点、曲线、线条、纹理、颜色分布等。相关性确定这些特征之间的关系,并且更新样式损失值以在样式图像和生成的图像中保持这种关系。更具体地说,如图 1 所示,星夜表中的太阳(黄色圆圈)在生成的图像中也显示为黄色圆圈。已经确定黄色和具有 gram 矩阵的圆之间存在关系,并且已经尝试通过减少风格损失将这种关系转移到生成的图像。

总损失:总损失计算为如上所述获得的样式损失+内容损失。

图 3。样式传递算法,[来源](http://L. A. Gatys, A. S. Ecker, and M. Bethge, "Image Style Transfer Using Convolutional Neural Networks.")

图 3 显示了原始论文的风格转换算法(计算损失)。这篇文章可以从下面的参考文献部分获得。以下代码块包括使用 Python 中的 Tensorflow 实现神经样式转换:

结论

神经风格转移最令人愉快的方面是,通过超参数调整获得了各种视觉结果,而不是结果的一致性。这里获得的各种结果是通过改变

  • content_weight=1e4,
  • style_weight=1e2,
  • content _ layers =[' block 5 _ con v2 ']
  • style_layers = ['block1_conv1 ',' block2_conv1 ',' block3_conv1 ',' block4_conv1 ',' block5_conv1']

上面代码块中的超参数和结果如图 4 和图 5 所示。可以看出,以高风格损失权重开始的图像的纹理更倾向于内容图像。另一方面,图 5 所示的图像以低风格损失权重开始,趋向于风格图像,这意味着与图 4 相比,从风格图像提取的特征被更好地转移。

图 4。从高 style_weight(1.0)开始的过程,图片由作者提供

如上所述,指示生成的图像和内容&风格图像之间的相似性的损失值的初始值被改变,并且以学习速率完成具有梯度下降的训练过程。虽然图像传输的波段范围是用初始损失值设置的,但传输速度是由 learning_rate 决定的。此外,如上所述,从中提取特征的内容层和样式层也显示了图像的属性被转移了多少(哪些特征)。

图 4。从低 style_weight(1e2)开始的过程,由作者创建图像

通过用不同的值尝试这些超参数,可以使用上面的代码块直观地观察每个时期的进度。

参考

  • 长度使用卷积神经网络的图像风格转换。
  • 长度 A. Gatys,A. S. Ecker,M. Bethge,《艺术风格的神经算法》,2015。

https://ibrahimkovan.medium.com/machine-learning-guideline-959da5c6f73d

如何在不编码的情况下用 Python 实现基本的可视化

原文:https://towardsdatascience.com/how-to-make-basic-visualizations-in-python-without-coding-f1da689d838e

使用 Mitosheet,只需几次点击即可创建可视化效果

弗兰克·布施在 Unsplash 上的照片

箱线图、直方图和条形图等可视化工具有助于我们探索和更好地理解数据。然而,用 Seaborn 或 Pandas 创建情节可能会花费很多时间(更不用说 Matplotlib)。

这样的库对于创建高度可定制的好看的可视化效果很好,但是当你赶时间并且你的情节的美学不是优先考虑的时候,有一个替代方案可以节省你的时间——米托。

在本文中,我将向您展示如何使用米托库来创建数据可视化,只需点击几下鼠标。

装置

为了在不编码的情况下实现可视化,我们需要安装米托(你需要 Python 3.6 或更高版本,还有 JupyterLab )

要安装米托,请打开新的终端或命令提示符,并运行以下命令(如果可能,请将其安装在新的虚拟环境中):

python -m pip install mitoinstaller
python -m mitoinstaller install

如果您已经安装了米托,请运行以下命令,确保您安装了最新版本的 mitoinstaller:

python -m pip install mitoinstaller --upgrade

然后,实际运行升级过程:

python -m mitoinstaller upgrade

在这之后,重启 JupyterLab 内核,并刷新浏览器页面以加载新版本的米托。要查看最近更新中的新内容,请查看官方文档

用 mitosheet 创建数据框架

要用米托创建一个数据帧,我们只需要import mitosheet并通过键入mitosheet.sheet()来启动它。

**import** mitosheet
mitosheet.sheet()

上面的代码将创建一个有丝分裂表。现在,我们可以继续导入数据集。

在本指南中,我们将使用 Google Drive 上的一个“students performance _ id”CSV 文件,它是我自己使用随机数据生成的。

要使用米托导入该数据集,请单击“导入”按钮,然后选择 CSV 文件,如下所示:

作者图片

注意:用米托对数据框架进行修改后,检查下面的单元格,查看由米托自动生成的代码。如果是图形,你可以点击右下角的“复制图形代码”按钮。

箱线图

箱线图有助于我们了解数据是如何分布的。这显示了最小值、第一个四分位数(Q1)、中值、第三个四分位数(Q3)和最大值。为了容易地看到这些值,我们必须创建一个交互式箱线图。有了米托,我们只需要几次点击就可以创建一个箱线图。

让我们为数学成绩、阅读成绩和写作成绩创建一个箱线图。为此,单击“图表”按钮,然后在“图表类型”选项中选择“方框”。在此之后,将您想要的列添加到 X 轴或 Y 轴,以分别获得水平或垂直箱线图。

作者图片

创建的箱线图是交互式的,因此您可以通过将鼠标悬停在图上来查看其背后的值。

记住,您可以复制米托生成的图形代码。这是我得到的代码:

柱状图

直方图表示数字数据的分布。我们来看看数学成绩是怎么分布的。

要用米托制作柱状图,点击“图表”按钮,然后在“图表类型”选项中选择“柱状图”。在这之后,在 X 轴上添加列,以防你想要得到如下所示的垂直直方图。

作者图片

在直方图中,我们可以看到大多数学生(由最高的柱表示)在数学考试中获得了 65 到 69 之间的分数。

条形图

条形图显示分类数据,条形的权重与其代表的值成比例。

要使用这个数据集制作柱状图,我们首先需要创建一个数据透视表。对于本例,我们将在“种族/民族”列(分组列)中对数学成绩和阅读成绩进行分组,这样我们就可以看到每组的平均成绩。

要用米托创建数据透视表,请按照下列步骤操作。

作者图片

现在我们有了数据透视表,我们可以按照下面的步骤为这个数据透视表创建一个条形图:

作者图片

额外收获:更改任何单个单元格的值

你可以和米托一起做更多的事情。例如,您可以像使用 Microsoft Excel 一样更改任何单个单元格的值。

假设我们想要更改 id 为 1 的学生的数学成绩:

作者图片

如上所示,如果你向下滚动,你会看到米托自动生成的熊猫代码。

如果你想知道米托的其他特色,看看下面的指南。

https://frankandrade.ck.page/bd063ff2d3

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

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

如何用 Python 制作 gif

原文:https://towardsdatascience.com/how-to-make-gifs-in-python-664d15ed4256

在数据分析中使用 gif,发现它们严肃的一面

照片由格雷格·拉科齐Unsplash 上拍摄

多亏了社交媒体,你可能已经非常熟悉 gif 了。在短短的几帧中,他们传达了非常具体的反应,只有图片才能传达。gif 在交流数据时也有类似的效果。

GIF 或图形交换格式是一种流行的图像格式,因为它们是被许多应用程序接受的紧凑、计算成本低的文件。本质上,gif 是把一堆图片串在一起,就像一本动画书。这种类似“动画书”的格式是展示多个图表趋势的理想方式。通过在帧之间快速移动,它们以静态图无法传达的方式揭示了数据中的趋势和模式。

图片作者。

密码

这个项目的回购可以在这里找到。

从现有图像创建 GIF

首先,加载数据。本文使用来自bokeh库的人口数据集。

下面是数据集的结构:

图片作者。

接下来,创建filter_loc,一个基于国家过滤数据集的函数。

现在,创建一个函数来绘制数据集中每年的人口密度。这个函数创建构成 GIF 的图(或帧)。

使用一个循环来调用make_plot的所有年份的利息。尽管数据集包括预测数据,但该 GIF 仅使用过去几年的数据。

把这些单独的图像串在一起,生成一个 GIF。

瞧啊。

图片作者。

创建 GIF 而不输出多个图像

在上面的例子中,代码输出静态图,然后将它们编译成 GIF。但是,可能会有不希望输出图的情况。例如,如果 GIF 有 1000 帧会怎样?如果 GIF 捕获了所有相关信息,为什么还要浪费存储空间呢?

matplotlib可以将一个函数作为输入并创建一个 GIF,而不是将文件名列表作为输入。使用函数消除了保存单个帧的需要。

首先,初始化绘图,这样函数就可以在以后覆盖。

接下来,定义run,这个函数为 GIF 创建不同的框架。

GIF vs 静态图

gif 在很短的时间内显示大量数据,在某些情况下比静态图更有优势。为了说明这一点,将美国人口密度 GIF 与下面的静态图进行比较。两者显示了完全相同的信息。然而,GIF 更清楚地显示了人口是如何趋向于均匀分布的。

作者图片

一图多 gif

如果您想比较多个国家多年的人口分布情况,该怎么办?在一张图上绘制多个 gif 可以更容易地比较图表。

首先,创建必要的框架。

接下来,创建一个具有多个轴的图形。在适当的轴上绘制上面创建的框架。

这是成品:

图片作者。

上图并排绘制了三幅 gif 图,以说明阿富汗、印度和美国人口分布的差异。选择这三个国家是因为它们有不同的经济和生活水平。

由于高生育率和低存活率,阿富汗的人口分布偏向年轻人。印度的分布逐渐变得更加均匀。美国的图表显示了代表婴儿潮一代的聚类,但总体而言,趋向于均匀分布。

结论

感谢您阅读我的文章。我希望这篇文章能启发你考虑使用 gif 来整合数据和说明趋势。如果你喜欢我的内容,请考虑关注我。此外,欢迎所有反馈。我总是渴望学习新的或更好的做事方法。请随时留下您的评论或联系我 katyhagerty19@gmail.com。

如果你喜欢我的写作,请考虑关注我。你也可以通过订阅 Medium 来支持我和其他作家。通过订阅我下面的推荐链接,我收到了部分费用。不过, 没有额外的费用给你 。谢谢你。

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

如何创建优秀的模式

原文:https://towardsdatascience.com/how-to-make-great-schemas-4940e4951a44

创建精心制作的模式的技巧和诀窍

来自作者的架构

解释数据资产很难。有很多工具、技术细节和术语。

然而,所有底层的工程和科学系统通常尊重某种建筑——某种设计。

这就是我们创建模式的原因。

解释机器学习模型。分享软件架构。记录我们的管道。

创建模式是采用系统的一个重要标志。你将在文档中、在卡片组中使用它,或者支持进一步想法的发展。

然而,将大型系统总结成一个图形资产并不容易。创建具有良好美感的精心制作的模式绝对是一项技能。

让我们深入了解一些设计有用且漂亮的模式的技巧吧!

拿起笔和纸

在深入研究软件、颜色或形状之前,最好先离开。

先拿一支笔和一张纸。

你不需要专注于某件特定的事情。第一步是把你的思维地图写在纸上。

如果有些东西看起来很奇怪,不要擦掉它。在另一张纸上开始新的草稿。

保留你所有的草稿。事后记录你的过程会是很好的材料。

当你认为你有一个好的计划时,开始把这些部分组织起来。写一份清晰的草稿,所有的元素都要有条理。

您是否拥有概述您的系统所需的所有项目?

您需要将您的模式分成许多部分吗?

我自己的一份草稿——描述 Google Cloud Run 服务和用例。

关注关键项目

人类的思维在看图像时肯定更专注。

这就是我们制作模式的原因,不是吗?

为了增强我们的模式,我们应该使用适当的图形资产。

有时我们的系统依赖于一个子系统:一个数据库,一个工具,或者一个我们想要抽象的复杂元素。使用徽标或简单的图像来描述这些子系统是很有用的。

为了制作一个好的图表,我们应该使用分辨率高、背景透明的标志。

这会让你的图表更加流畅,更容易理解。

花点时间来选择图像。不要使用拙劣的通用标志…

根据重要性使用不同的元素大小也是一个好主意。如果子系统细节很重要,请创建另一个模式。不要超载的东西。你的观众注意力有限。

想想你想展示的“尺度”。是不是一个全局图式,概括一个大系统?还是需要纹路细节的东西?支持技术文档?

在这个例子中有很多不同的资产。使用适当的徽标(来自 AWS 资产)有助于目标受众了解该工具,并带来每个子元素的上下文信息。(来源于作者:你不需要管弦)。

关注细节

伟大的模式是详细的。

以下是一些可以添加到模式的不同元素中的详细信息:

👉上下文框

添加灯箱可能是增强模式的良好开端。使用虚线将元素组合在一起也是一个好主意。它带来了背景。

你可能更喜欢使用浅灰色或浅色,因为这里的目的只是为了帮助元素区分。

作者图片

👉填充

在方框和箭头之间添加空格!你的模式将更容易阅读。

作者图片

👉圆角(可选)

根据你想要的设计,你应该喜欢把你的元素的角弄圆一点。

这可能只是当今的一种趋势,但由于这个小技巧,大画面往往会变得柔和。

作者图片

👉颜色

花点时间在颜色上。

太多的颜色和你的计划是失败的。

不够,根本不会看…

通常最多保留两三种颜色就很好了。你可以用精心挑选的颜色来强调某些部分。保持二阶元素为黑色或浅灰色。

🖇️是信息图表中色彩的绝佳指南。

👉上下文注释

有时,您可能希望添加一些注释,以方便读者理解。仅仅添加一个小箭头和一些文本通常就能达到目的。

来源于作者—raw stats 之后:用数据嵌入探索控球风格。

👉对准

这是基本的。

确保所有元素都相互对齐。你计划的中心。

在你的模式周围留一些空白。

👉背景

这可能取决于最终的支持,但你会喜欢使用白色背景或透明的。

不要使用背景图片。

👉导出格式

有不同的导出格式。以下是一些基本注意事项:

  • JPEG:如果你不需要透明背景和低文件大小。
  • PNG:如果需要透明背景。
  • SVG:如果您希望以后能够编辑和调整您的模式——没有损失。

👉字体

最多保持一到两种字体。但是,可以随意使用不同的大小来扩展您的模式。不要犹豫加粗你的重要文本。

🖇️我把我喜欢的字体保存在 GitHub 上

👉字幕

总是在你的模式中添加标题,或者引用一个源,或者描述整个系统。它帮助读者理解上下文。

工具作业

通常,一支笔和一张纸是你要使用的第一个工具。它们是开始构建模式的最便宜、最简单的工具。

我个人用的是一款卓越平板。它是电子墨水,具有云同步和分层等强大功能。我可以在任何地方工作,更容易地制作不同的草稿版本。

我非凡的平板电脑

当你有了初稿,你就可以去软件世界了。有许多工具可以创建模式。以下是一些最好的例子:

👉 draw.io :大概是我最喜欢的一个。您可以轻松地编辑您的模式,以不同的格式导出,并同步到 GitHub。有许多形状和功能可以将你的元素组合在一起。

https://www.draw.io/

👉tldraw.com:比 draw.io 简单一点,但你只需点击几下就能做出漂亮的模式。

它具有创建不同风格的灵活模式的强大功能。

https://www.tldraw.com/

👉 Figma :这个工具更多的是用于设计用户界面,但是它有很大的特性可以创建模式。

一大优点:可以添加交互性和动作(制作 gif?).

👉Adobe Photoshop/Illustrator:如果想要完全定制,使用合适的图形工具会是一个不错的选择。你想做什么都可以。时间是唯一的限制。

我希望这些技巧能帮助您深入了解如何制作精心制作的模式。

这些都是简单的技巧,但这就是优秀模式的不同之处:

  • 先拿一支笔和一张纸!
  • 考虑你的受众和你的方案的上下文。
  • 按照一些简单的指导方针,用一些软件来设计和创建模式,使你的模式流畅易懂。

如果你有任何问题或者只是想聊聊天,请不要犹豫联系我👋。

我是一名数据运营工程师,曾在新闻、零售、职业体育和音乐等多个行业工作过。我明白了,分享我们自己的经历是帮助他人和发展自己的一种强有力的方式。如果你也有这种想法,并且你正在寻找伟大的数据资源,请 订阅我的简讯——从工程师的角度。

如何用 Python 制作带 AI 的迷因

原文:https://towardsdatascience.com/how-to-make-memes-with-ai-in-python-986944bce5b4

制作于 makememe.ai图片Felix Koutchinski 根据 Unsplash 许可

最近 Makememe.ai产品搜索日的产品。用户提供一个简单的描述,应用程序将其转化为一个可以与朋友分享的快速笑声。

Makememe.ai 使用 OpenAI 的 GPT-3 ,来执行自然语言任务,将用户的文本转换成 meme。我们将通过 Python 代码和高级人工智能系统来学习如何用人工智能创造迷因!

该项目现在在 Github 上开源。随意叉回购,并尝试建立在它之上。如果你想投稿,你需要注册获得 OpenAI API 访问权限,并且在分叉或克隆库之前请阅读 OpenAI 的上线政策

先验模因创新

Imgflip 的创始人 Dylan Wenzlau 创造了一个人工智能系统来生成模因。迪伦从 Imgflip 用户的 1 亿条公共迷因说明中提取信息,构建了一个用于文本生成的深度卷积网络。在应用程序中,用户从 48 个可用的迷因中选择一个迷因,人工智能会生成文本覆盖在迷因上。这款应用只需点击几下就能创造出有趣的迷因。用户可以提供一些上下文(迷因的主题等)。)供人工智能用来创造迷因。

Imgfip 系统的高级示意图。由 Josh Bickett 在 lucid.app 上创建。图片由作者提供。

迪伦·温兹劳开发的人工智能创造的迷因

罗伯特·a·冈萨维斯创造了一个人工智能迷因系统,叫做人工智能迷因。他让任何人都可以在 colab 笔记本上获得代码。

用户输入一个搜索查询,会收到 10 个与搜索匹配的 meme 图片选项。用户从 10 幅图像中选择一幅。然后,人工智能系统生成 10 个可能的字幕,用户选择他们最喜欢的。

AI-Memer 系统的高层图。由 Josh Bickett 在 lucid.app 上创建。图片由作者提供。

Makememe.ai 的方法——“提示一个模因”

该应用采取了一种不同的方法,可以被描述为“促进一种模因”。用户提供一个输入——关于他们想要的模因是什么的描述。然后,用户按下“制作迷因”按钮。用户没有选择图像或文本。人工智能系统选择一幅图像,并将描述修改成迷因标题。然后将标题覆盖在图片上,形成最终的迷因。

Makememe.ai 的系统高层图。由 Josh Bickett 在 lucid.app 上创建。图片由作者提供。

示例用户输入 : “但愿办公室有新一季”

例子模因:

制作于 makememe.ai图片SigmundUnsplash 许可下拍摄

它是如何工作的

我们将一步一步地走下去,一路上检查迷因。

这里讨论的所有 Python 代码都在 Github 库 中,代码主要驻留在make . py文件中。如果你想在本地运行这个项目并亲自尝试,克隆代码并查看的自述文件了解如何在你的电脑上运行它。

该项目建立在 Python 的 Flask 框架之上。我们不会涉及技术栈,所以如果概念不熟悉,我强烈推荐科里·谢弗的 Youtube 系列 Python Flask 教程:全功能 Web 应用

获取迷因描述(用户输入)

第一步是从网页上抓取模因描述。下面是网站描述的一个例子。

带有用户描述的 makememe.ai 主页图片。图片由作者提供。

当用户按下“Make Meme”按钮时,python 代码触发make()函数并传入参数description在我看来,开源项目是最好的项目。

def make(description):
    user_input = description

选择一个与描述相符的迷因

人工智能需要选择一个最符合描述的迷因。目前在项目目录中有 20 个图像选项供人工智能选择— [./static/meme_pics](https://github.com/joshbickett/makememe_ai/tree/main/makememe/static/meme_pics)

语义搜索

为了选择最好的模因,我们需要找到一个模因的意义与用户在描述中试图传达的内容相一致的模因。为此,我们使用一种叫做 语义搜索 的方法。OpenAI 有一个端点进行语义搜索。OpenAI 在下面描述了它的工作原理。

搜索端点( /search )允许您对一组文档进行语义搜索。这意味着您可以提供一个查询,比如一个自然语言问题或一个语句,并且所提供的文档将根据它们与输入查询的语义相关程度进行评分和排序。

语义学是语言学和逻辑学的一个分支,研究意义。因此语义搜索发现两个短语或文档在意义上有多接近。

每个迷因图像都有自己的描述,可以与用户的描述进行比较。语义搜索比较两个短语。

短语一—用户描述: 在我看来,开源项目是最好的项目

****短语二——每个模因被贴上标签的描述

在我们的例子中,当使用语义搜索时,人工智能将选择下面的模因模板。这个模因被贴上了描述标签— “这是我的观点。改变主意能看出和用户描述的相似度吗?我们将仔细检查代码,看看它是如何被选中的。

用来创造迷因的图像。图片Felix Koutchinski 根据 Unsplash 许可证拍摄。

对于语义搜索,我们创建了一个名为documentsarray来保存对迷因的 20 个描述。注意这个描述——"This is my opinion. Change my mind."——在数组中是第 11 位。变量documents使用 OpenAI 的命名约定作为其 语义搜索 端点。搜索可以在更长的文本字符串上执行,比如文档,这就是命名约定的原因。

documents = ["sad", "indifferent", "waiting", "they don't know", "pompous", "this is better than that", "poor fix", "no responsibility", "ineffective solution", **"This is my opinion. Change my mind."**, "accurate depiction", "equal", "distracting", "three levels increasing", "stay away from", "ruin", "scary", "The subject has a strong preference for one option over another", "something is missing and I wish it was still here", "when not good"]

既然 meme 的描述已经设置在document变量中,我们可以将它们与用户的描述进行比较,以选择最合适的图像。

下面的函数传入三个参数。在语义搜索** API 请求中发送documents数组和user_input。该搜索根据用户输入评估所有 20 个模因描述,并提供得分字典。高分意味着短语之间的语义相似度高。user_id是为了 OpenAI 进行的 AI 安全研究而传入的。**

response = GPT.search_request(documents, user_input, user_id)

现在,response有了一个分数字典,索引与documents数组中的模因相匹配。

接下来,我们创建一个名为best_result的 python 字典来保存我们的结果,因为我们要寻找得分最高的迷因。

best_result = {
    "index": -1,
    "score": 0
}

我们使用一个for循环来遍历response中的每个key-value对,并将最佳得分保存在我们之前创建的best_result字典中。当我们循环通过response时,如果新分数比前一循环周期保存的分数更好,我们将保存新分数。在for循环完成后,我们就有了在best_result字典中得分最高的迷因。在我们的例子中,这个模因叫做这是我的看法。改变主意**

**for d in response['data']:
     if d["score"] > best_result["score"]:
          best_result["score"] = d["score"]
          best_result["index"] = d["document"]**

下面是for循环代码运行时 Mac 终端的截图。我们为response打印key-value对,并找到最佳的语义搜索分数。评分10.388最高所以带有描述的 meme——“这是我的看法。改变我的想法”——被选中。**

http://127.0.0.1:5000/ 本地运行项目时来自我终端的截图。图片由作者提供。**

我们将从best_result中选择的迷因保存在一个名为meme_description的变量中。现在,我们已经选择了一个迷因图片来使用!

**meme_description = documents[best_result["index"]]**

将描述修改成合适的迷因标题

现在我们已经选择了迷因,我们需要添加一些文本,以确保它能够发出笑声。我们将介绍 GPT-3 提示完成是如何帮助我们的。以下是 OpenAI 在他们的文档中所说的。

完成点是我们 API 的中心。它为我们的模型提供了一个非常灵活和强大的简单接口。您输入一些文本作为提示,模型将生成一个文本完成,试图匹配您给它的任何上下文或模式。

我们浏览了为这个项目创建的一个提示,以及我们如何通过一种叫做“少量学习”的方法获得迷因所需的标题。

Makememe.ai 在一个名为generate_meme()的函数中调用完成端点。该函数采用user_inputmeme_description变量。这里user_id再次被传递到完成端点,用于 OpenAI 的 AI 安全研究。

**meme = generate_meme(user_input, meme_description, user_id)**

让我们研究一下这个函数,看看发生了什么。我们有一个数组,看起来类似于我们之前看到的documents数组,但是有一点小小的不同。memes数组包含 20 个类,而不是我们之前在documents中看到的字符串。我创建了每个类,所以它有一个人工智能提示与之相关联。如果选择了一个迷因(在我们的例子中是[Change_My_Mind](https://github.com/joshbickett/makememe_ai/blob/main/makememe/generator/prompts/types/change_my_mind.py)),自定义提示将帮助解析user_input以适应迷因的固有设计(并且有趣)。当我们查看提示时,这将更有意义。

****def generate_meme(user_input, meme_description, user_id):** memes = [They_Dont_Know, Indifferent, Poor_Fix, Sad, Waiting,   
        Is_Better, Three_Levels_Increasing, Pompous,     
        No_Responsibility, Ineffective_Solution, **Change_My_Mind**, 
        Accurate_Depiction, Equal, Distracting, Stay_Away_From,     
        Ruin, Scary, Strong_Preference, Missing_Something, 
        When_Not_Good]**

我们循环遍历这个数组中的每个迷因。每个类都有一个名为description的静态变量,它对应于我们之前看到的documents数组。例如,[Change_My_Mind](https://github.com/joshbickett/makememe_ai/blob/main/makememe/generator/prompts/types/change_my_mind.py)类有一个对"This is my opinion. Change my mind."的描述。相比之下,我们之前选择的meme_description具有相同的值。通过将meme_description与这些类中的描述进行比较,我们可以发现它们何时相等。如果类描述meme.description与所选的 meme meme_description匹配,那么我们将输入这个if语句,并使用该特定meme类的提示。

**for meme in memes:
    if meme_description == meme.description:**

现在我们在if语句中,并且在作用域中有了正确的meme类,我们将创建这个类的一个实例。我们用该类的一个实例覆盖了我们的meme变量(可以很容易地创建一个新变量)。这里的f-string将追加[Change_My_Mind](https://github.com/joshbickett/makememe_ai/blob/main/makememe/generator/prompts/types/change_my_mind.py)(),这样语句就变成了eval('Change_My_Mind()'),它将创建这个类的一个实例。

**meme = eval(f'{meme.name}()')** 

GPT-3 提示

接下来,我们使用 OpenAI 的完成端点。我们发送一个自定义提示,GPT 3 将完成它,将用户的文本输入修改成适合迷因的迷因标题。下面是我们选择的迷因的提示示例。我们将逐步介绍提示符如何解析用户的文本。

**###
**Message:** Chocolate chip cookies are the best cookies. Try to change my mind.
**Meme:**{"opinion":" Chocolate chip cookies are the best cookies. Change my mind."}
###
**Message:** Learning to code is one of the most rewarding experiences. Change my mind.
**Meme:**{"opinion":"Learning to code is one of the most rewarding experiences. Change my mind."}
###
**Message:** In my opinion, Daft Punk is the greatest electronic band to exist.
**Meme:**{"opinion":"Daft Punk is the greatest electronic band to ever exist. Change my mind."}
###**

在提示中,我们使用一种叫做少量学习的方法,为给定的文本输入(消息:)提供我们想要的输出(模因:)的例子。示例为模型提供了我们目标的上下文。当模型看到Message: ~put our text here~时,它将尝试完成文本meme: ~some json here~

让我们发送从用户输入中获得的新示例。在我们的代码中,我们在提示后面添加了append_example()

**meme.append_example(user_input)**

我们提示的底部现在在Message:之后有了我们的例子。该模型将在Meme:之后基于从少数镜头示例中学习到的内容来完成文本。

###有两个用途。首先,这三个字符作为stop令牌。基本上,人工智能需要知道何时停止提供新文本。其次,它给出了新示例开始和结束的模型上下文。

**...
###
Message: In my opinion, open-source projects are the best projects
Meme:**

我们现在将提示发送到**completion** API 端点,并从模型获得响应。

**response = GPT.completion_request(prompt, user_id)**

下面是我们可能会收到的完成的示例。

**{"opinion":"Open-sourced projects are the best project. Change my mind."}**

我选择 JSON 格式让 AI 来完成,因为它很容易用 Python 来解析。这在后面的步骤中会更有意义。我们可以很容易地不使用 JSON,响应可以简单地是文本,比如Open-sourced projects are the best project. Change my mind

模型注意到所有的例子都以Change my mind结尾,并且它正确地遵循了这个模式。

注意这里没有###字符。这是因为我们告诉 API 在到达###时停止生成。模型用 JSON 文本进行响应,其中包含下一步要使用的 meme 标题。

如果你还没有使用过提示,我推荐注册open ai 并尝试操场环境。

将迷因标题覆盖在所选图像上

我们现在将上一步中的迷因标题文本覆盖在我们从语义搜索中选择的图片上。我们使用一个名为Pillow的 Python 库,它可以编辑图像并在图像上绘制文本。

json.loads()方法将来自 API 的文本转换成我们可以使用的 JSON 对象。

我们之前实例化的meme对象有一个将文本绘制到 meme 上的create()方法。

**response = json.loads(response)                
image_name = meme.create(response)**

我们示例中的create()方法可以在[Change_My_Mind](https://github.com/joshbickett/makememe_ai/blob/main/makememe/generator/prompts/types/change_my_mind.py)[.py](https://github.com/joshbickett/makememe_ai/blob/main/makememe/generator/prompts/types/they_dont_know.py)中找到。首先,该方法用Pillow库的Image类打开[change_my_mind.jpg](https://github.com/joshbickett/makememe_ai/blob/main/makememe/static/meme_pics/change_my_mind.jpg)。我们将图像定义为base,因为它是绘制文本的基础。

**Image.open(f"makememe/static/meme_pics/{self.name.lower()}.jpg").convert("RGBA") as base:**

我们使用我的自定义类Image_Manager将文本添加到带有add_text()的图像中。我们传递将要写入文本的base图像。我们传递附加信息,如textposition,font_size。对于每一个定制类,比如Change_My_Mind,文本positionfont_size与特定 meme 的格式对齐。对于我们选择的迷因,position=(190,200)190x文本位置,200y文本位置。如果文本放在错误的地方,迷因可能没有意义或不好笑,所以每个迷因类都向add_text()发送特定的细节。

**overlay_image = Image_Manager.add_text(base=base, text=meme_text['opinion'], position=(190,200), font_size=60, text_color="black", wrapped_width=22)**

前一步给了我们一个overlay_image,它有一个透明的背景,但包含了迷因文本。我们在原始的base迷因图像上添加了透明的overlay_imageImage类有一个名为alpha_composite()的函数来做覆盖。叠加步骤的输出图像我们称之为out,这就是最终的模因!

**out = Image.alpha_composite(base, overlay_image)**

我们为网站创建了一个image_name来引用和展示迷因。我们将用户创建的所有模因保存在makememe/static/creations目录下。最后,我们将名为out的模因图像保存到file_location

**image_name = f'{date}.jpg'                
file_location = f'makememe/static/creations/{image_name}'
out.save(file_location)**

我们做到了!我们使用语义搜索来选择符合用户描述的模因图像。然后,我们使用 GPT-3 提示完成将用户的描述修改成一个幽默的迷因标题,并与我们选择的迷因保持一致。最后,我们给迷因图片添加了迷因标题。下面是我们最后的创作!

制作于 makememe.ai图片Felix Koutchinski 根据 Unsplash 许可

你如何参与这个项目

为开源项目做贡献是了解软件开发和人工智能系统的好方法。我鼓励任何感兴趣的人尝试改进 Github 上的项目。实现你的想法,玩得开心!

有一个喜欢的迷因,但在项目的 20 个支持的迷因下没有看到?欢迎大家叉库加迷因。一旦你为一个新的迷因准备好代码,做一个拉请求(PR)。我将查看拉取请求,并确认该 meme 是否可以添加到网站。如果你对添加一个 meme 的指导方针有疑问,请联系我,邮箱: josh@makememe.aiDM 我上 Twitter

将 AI GIF memes 等创意带入生活!

如果您有任何技术或一般问题,请随时通过 josh@makememe.ai 联系我。如果您在代码中遇到任何问题,我很乐意帮助您解决它并提供想法!

项目更新

通过在 Twitter 上关注我来了解项目的最新进展,我在 Twitter 上发布人工智能迷因并从事其他有趣的人工智能项目!

感谢

我要感谢奥斯汀·Damiani 和乌达拉·阿贝塞克拉对这个项目的帮助!

2023 年如何一边学数据科学一边赚钱

原文:https://towardsdatascience.com/how-to-make-money-while-learning-data-science-in-2023-8f1e898d2db5

采取以下 5 个步骤,让你的收入在一年内翻倍。

Unsplash 上由 Austin Distel 拍摄的照片

2020 年 1 月开始自学数据科学。那时,我唯一的目标是在这个领域找到一份全职工作。

然而,尽管数据科学家的薪酬很高,但要爬上公司的阶梯,靠一份朝九晚五的工作积累财富,需要很长时间。

因此,我开始寻找不同的方法在公司工作之外应用我的数据科学技能。因为我的全职工作是灵活的,允许我远程工作,我每天有大约 3 到 4 个小时的空闲时间来创造一份兼职收入。

现在,我已经成功地在全职工作之外建立了多个收入来源,每月为我提供大约 3,000 至 3,500 美元。

这些收入流很多都是被动的,也就是说我不用主动投入时间和精力就能赚到。

在本文中,我将向您展示我是如何做到的。如果你是一名数据科学家或者渴望成为一名数据科学家,你可以利用这些想法来将你的技能组合货币化。

1.在线写作

我收入的很大一部分来自在线写作。这包括创建数据科学教程、技巧和建议。2020 年 5 月开始在 Medium 上写博客。

在平台上建立了受众之后,我已经被雇主们接洽,为他们的品牌撰写自由撰稿人的文章。在过去的两年里,我为六家不同的公司创建了各种博客文章、教程、白皮书和 SEO 内容。

外卖:

答)刚开始写

开始分享你所知道的,你不必是一个主题专家。事实上,根据 Fast 联合创始人雷切尔·托马斯的说法。AI,你最适合帮助落后你一步的人。

这意味着,如果你刚刚学到一个概念,它在你的脑海中仍然是新鲜的。你可以很容易地简化这一点,并向该领域的另一个初学者解释——并且能够比一个已经忘记初学者是什么样子的专家做得更好。

b)推销自己

要成长为一名内容创作者,你需要推销自己。创建一个引人注目的 LinkedIn 个人资料,并在平台上分享你的文章。定期发布帖子,加入数据科学小组,并与该领域的其他专业人士联系。

增加你在数据世界的联系会增加你的博客浏览量,增加你获得有偿写作的机会。

2.联盟营销

在自学数据科学时,我参加了 Udemy、Coursera 和 Datacamp 上的许多在线课程。我会将这些课程推荐给希望我就如何成为数据科学家提供建议的同事和同行。

过了一段时间,我意识到我可以通过与他人分享我的学习之路来获得报酬。联盟营销允许出版商使用联盟链接与其他人分享课程。如果有人使用他们的链接购买程序,出版商会得到一小笔佣金。

外卖:

为你已经做的事情获得报酬

甚至在我的内容包含附属链接之前,我会在我写的几乎每篇博文中分享学习材料。唯一不同的是,我现在可以得到报酬了。事实上,根据 Affise 的一项民意调查,超过 25%的分支机构每年在81,000 美元到 200,000 美元之间

虽然我从联盟营销中只赚到其中的一小部分(每次发布我每月大约 100-200 美元),但这对许多博客来说是一个巨大的收入来源,绝对是你应该考虑添加到你的内容中的东西。

然而,记住要合乎道德,只推销你消费过并从中受益的产品。你也必须是透明的,并清楚地向读者披露附属链接的使用。

3.进行市场调查

作为一名数据科学家,这听起来可能是一种非常规的赚钱方式,但请听我说完。

我的第一份全职数据科学工作是在营销分析领域。在这个职位上,我学会了应用数据科学技术来创建个性化的客户定位策略,并推动营销成功。

我写了一篇关于在营销领域应用数据科学技术的文章,这引起了一位雇主的注意,他正在寻找一位与我拥有相同技能的自由职业者。他在 LinkedIn 上联系了我,我现在在这家公司签了合同。

外卖:

a)选择一个利基

因为我在营销分析领域工作了一段时间,所以我熟悉这个行业面临的一些最大的挑战。我也知道如何用数据来解决它们。

这是我的专长。很难找到一个人拥有和我一样的综合技能,这使我成为这份自由职业的有力竞争者。

如果你是一名有抱负的数据科学家,我建议在开始时选择一个专业领域。这可以是金融、营销、医疗保健、保险或任何你喜欢做的事情。

数据科学家的价值在于解决问题的能力。如果你能在一个特定的行业做到这一点,你就比其他数据科学家有竞争优势。

我可以自信地说,我得到的工作不适合没有领域经验的人,即使他们有数据科学的硕士学位或博士学位。

b)建立在线形象

我得到这个角色只是因为雇主在浏览平台时发现了我的中等个人资料。我和其他营销数据科学家一起工作过,他们中的许多人比我更有经验,更了解这个领域。

不管怎样,我得到了这份工作,因为雇主先找到了我——多亏了我的博客帖子和社交媒体。

如果你没有时间写关于你工作的文章,我建议你至少创建一个作品集网站,里面包含你技能的总结。在 LinkedIn 和其他社交媒体平台上包含该网站的链接,这样潜在的雇主在招聘空缺职位时可以很容易地找到你。

如果你还没有,读一下这个指南,了解如何创建一个作品集网站。

4.创建课程和研讨会

我举办过关于数据收集和分析等主题的研讨会,教非技术专业的学生处理数据。这需要几个小时的准备,因为我必须熟悉我所教的每一个概念,并确保我没有犯任何错误。

成为一名教师最大的好处是,教学巩固了我对这门学科的理解,极大地提高了我向该领域的初学者分解复杂概念的能力。

外卖:

教你所知道的

我大约在两到三年前开始学习数据科学,在这个领域我算不上专家。然而,在这段时间里,我学到了很多东西,可以把它教给一群人,他们将从学习我的技能中受益。

例如,作为一名在数据科学和营销领域工作过的人,我非常适合向营销人员传授数据素养技能。我还可以教数据科学家关于营销分析的知识,这样他们可以获得领域知识,并有可能在行业中找到工作。

即使你是一个正在学习阶段的有抱负的数据科学家,你也可以通过与他人分享你所知道的来获得额外的收入。通常情况下,当你结合了很多人都没有的一套独特的技能时,效果会更好。

例如,“Python 入门”课程可能不会激起学生的兴趣,因为类似的程序在互联网上比比皆是。然而,“金融 Python 入门”课程更专业,可能会吸引一群对预测股市感兴趣的观众。

YouTube 、 UdemyPluralsightthinkfic是一些你可以用来建立和分享在线课程的平台。

5.其他自由职业任务

此外,我还从事自由职业者的数据科学工作,比如为客户收集数据、建立模型和创建仪表板。虽然大多数自由职业者都信赖 Upwork 和 Fiverr 这样的平台,但我的大部分工作机会都来自 Medium、LinkedIn 和我的网站。

以下是一些让我获得自由职业的文章:

  1. 使用 Python 进行客户细分:我最终为客户构建了一个 K 均值聚类模型,并在幻灯片中展示了我的结果。
  2. 如何用 Python 收集 Twitter 数据:我指导客户端使用 Python API 收集 Twitter 数据。
  3. 使用 Python 的完整数据分析项目:我对客户的产品进行了类似的竞争分析。

外卖:

建设项目:当雇主想雇佣一名自由职业者时,他们通常会在互联网上寻找从事类似项目的人。建立项目并经常发布会增加你被关注和找到工作的几率。

结论

无论您处于数据科学之旅的哪个阶段,您都可以从今天开始构建多种在线收入来源。

从在线写作和教授你所知道的开始。这可以在 Medium 这样的发布平台上完成。你甚至可以使用像 WixWordpress 这样的网络开发服务来创建自己的博客网站。

然后,在数据科学中选择一个专业领域。我建议在这个领域找一份全职工作,因为这会给你提供在别处学不到的行业经验。

最后,利用你的领域经验和数据科学技能扩展到自由职业和课程创建。您还可以提供咨询会议,并在您所在的地区举办数据科学研讨会。

"取得成功的秘诀在于开始行动。"——马克·吐温

如何在 VSCode 中充分利用 Python 调试器

原文:https://towardsdatascience.com/how-to-make-most-of-your-python-debugger-in-vscode-9e05dfce533f

PYTHON 调试

在处理大型项目时,观察变量、使用条件断点、调用堆栈、异常断点等

快速脉冲检查—还在使用 *print()* 语句调试您的代码吗?嘿,承认你知道也没什么丢人的。如果有效,就有效(特别是对于较小的脚本)!

话虽如此,但在处理较大的项目时,这不是一个可持续的解决方案——涉及大量第三方包、实用程序文件夹、目录、子目录——很容易失去对代码流的跟踪。

这是学习 VS 代码必须为调试代码提供的所有细节背后的主要动机。在这里与你分享相同的!

VSCode 调试器的基础

为了简洁起见,我将保持事情简单,并讨论足够的细节,让你开始。要了解更多信息,请随时查看他们的官方文档。

虚拟项目

我们将进行一个虚拟项目。目前,它包含一个hello.py脚本和一个包含 5 个音频文件的小型虚拟audio_data 数据集。你可以在 Github 的这里找到

https://github.com/V-Sher/medium_debugger

作为健全性检查,运行脚本以查看终端中的输出。

hello.py

启动配置

让我们继续创建一个launch.json文件。详细步骤请参考此处的文档

启动配置

这将在您的项目中创建一个新的.vscode文件夹,并将包含launch.json文件,登记所有的调试设置细节。现在,我们将使用默认值。

让我们开始调试

要检查特定行的代码状态,我们必须向它添加一个断点。这些通常会在编辑器页边空白处显示为红色实心圆圈。例如,我在for循环中添加了一个断点(见下图)。

在脚本的第 X 行添加一个断点将会执行所有代码,直到第 X 行,代码执行将会在第 X 行停止,以便您检查代码的状态。换句话说,直到您点击调试工具栏中的继续(或任何其他)按钮,X 行的代码才会被执行。

在 hello.py 中的 for 循环处添加断点

现在,我们可以通过点击绿色的 play 按钮开始调试脚本了(上图中的Python:Current File)。这将弹出一个浮动的调试工具栏(见下图)。

浮动调试工具栏

Pro 提示:在开始调试之前,确保在编辑器中打开了正确的文件,因为默认情况下,调试器将开始调试当前活动的文件。

开始调试过程后,您将看到以下内容:

需要注意的几件事:

  • 在左边,Variables选项卡填充了一些局部和全局变量。
  • 在右边,脚本中添加第一个断点的那一行用黄色突出显示。
  • 调试器尚未处理添加断点的那一行。(到目前为止的一切都已经处理完毕,这就是为什么你会看到os模块是Variables选项卡的一部分。)

从现在开始,作为调试工具栏的一部分,您有几个调试选项:

  • 继续按钮将调试器从当前断点(或红色填充圆)带到下一个红色填充圆(因为在我们的例子中有一个for循环,下一个断点将再次在for循环)。
  • Step Over 按钮将调试器从代码的当前行带到下一行(在我们的例子中,是print语句)。
  • 单步执行按钮将带您进入当前断点中定义的任何功能(在我们的例子中是enumerate()listdir())。
  • 重启停止按钮非常直观。

继续按钮

点击调试工具栏中的继续按钮将执行所有操作,直到下一个断点。由于我们在 for 循环中,下一个断点实际上将与当前断点相同。

让我们尝试这样做,看看我们会得到什么!

注意:如果我们在 for 循环的 *print* 语句中添加了一个断点,调试器接下来将会在这里停止。)

需要注意的几件事:

  • 在左边,local变量已经被更新,现在我们可以在*for* 循环中看到当前迭代的ifile的值。你甚至可以将鼠标悬停在脚本中的这些变量上来查看它们的值。
  • 调试器现在突出显示脚本中的下一个断点(与上面讨论的for循环相同)。
  • 在终端中,我们可以从print语句中看到部分结果(来自迭代i=0)。

现在,我们可以继续点击继续选项,我们将看到local变量ifile更新为各自的值,以及相关的print语句。但是,如果for循环本身相当复杂,我们想要深入研究并调试它,该怎么办呢?

为了进行试验,我们必须暂时停止调试器(使用 debug 工具栏中的 stop 按钮),并对脚本本身进行一些更改。我们现在将使用os.path.abspath()打印绝对路径,而不是打印文件名,我已经将它打包到一个名为get_abspath()的(无用)函数中。此外,还将从文件名中提取发言者 id。

hello.py

如前所述:

  • 我们在for循环处设置断点。
  • 启动调试器,点击继续按钮一次以查看本地和全局变量更新到0PA_T_0000001.flac以及终端中的单个print语句。

现在,假设我们想要检查for循环内部发生了什么。一种方法是设置另一个断点,或者我们可以(而不是点击继续按钮)选择调试工具栏中的跳过按钮。

跳过按钮

顾名思义,调试器已经单步执行到断点后的下一行(用黄色突出显示)。

需要注意的几件事:

  • 终端中不会有任何print语句。为什么?因为该行代码还没有被调试器处理!您必须点击继续(或前进 越过)按钮才能看到输出。
  • 为了检查这个迭代的speaker_id的值,我们可以再次点击跳过按钮,你会看到一个名为speaker_id的新的局部变量被创建(调试器会跳到下一行并高亮显示它——见下图)。

  • 我们仍然无法检查由get_abspath()方法返回的内容。解决方案:设置断点!
    注意:不要在 *def get_abspath()* 行设置断点,而是在函数定义内设置断点(见下图)。

一旦设置了断点,您可以再次单击跳过按钮,调试器现在将停留在函数内的return语句处(见下图)。我们可以看到局部变量现在已经更新为,只有反映了函数接收到的filename参数。先前的变量如ifilespeaker_id现在已经成为全局变量的一部分。

这是检查函数定义是否接收正确参数的好方法。然而,我们仍然不知道get_abspath()将返回的实际值。

这是以前的我在代码中使用print语句的地方!

相反,我们可以利用调试器中的观察功能。输入要观察/获取其值的表达式,然后按 Enter 键(见下图)。瞧,你可以看到表达式的实际值!

Watch 功能通常用于观察变量值在整个代码中如何变化,因此得名 watch。例如,您可以使用它来跟踪64x64x3输入图像如何通过卷积(和其他层)以在典型的卷积神经网络(CNN)中给出单个输出。

从现在开始,您可以使用 Continue 和 Step Over 按钮以及 Watch 功能来完成代码导航/调试。

一旦完成,就该对代码做更多的修改了。我们将重组代码并将get_abspath()hello.py移到新的abs.py 脚本中,该脚本将驻留在新创建的utils文件夹中。断点仍将保留在函数内的return语句处。

快速更新代码以在hello.py内导入方法(如果您对来回导入模块感到紧张,请随意查看我的 python 导入文章)。

hello.py

现在尝试以通常的方式调试hello.py脚本,即使第二个断点(在abs.py内)不在当前活动的脚本中(即hello.py,调试器仍将工作。

步入/退出按钮

一旦进入abs.py的断点,出于好奇,你也会对检查标准库函数os.path.abspath()的内部工作感兴趣。这意味着你必须进入这个功能,我们可以使用调试工具栏中的进入按钮。

理想情况下,这应该将调试器引入到os模块内的函数定义中。然而,你会看到它不会发生?
为什么? —默认情况下,调试仅限于用户编写的代码!

为了能够调试非用户编写的代码,在launch.json中描述的配置内将justMyCode设置为False

启动. json

现在尝试重启调试器,当调试器到达return断点时,使用进入按钮来探索abspath()。一旦进入,您可以随时使用步出按钮——比方说,您认为您不想进一步探索了——调试器将返回到您进入之前的位置,在我们的例子中是abs.py中的return语句。

条件断点

假设您已经通过查看最初的几个for循环迭代理解了调试器是如何工作的。显然,等待它完成所有迭代没有多大意义。相反,我们可以让它在不碰到断点的情况下运行,比如说,直到它到达最后一次迭代。

这就是条件断点发挥作用的地方!让我们看看如何做到这一点。(为了简单起见,我们将禁用abs.py中的断点。)

  • 右键单击for循环中的断点,选择编辑断点。
  • 从下拉菜单中选择表达式并设置为i == len(os.listdir(“audio_data”)) — 1
  • 按回车键。

现在,当您重新启动调试器时,它将自动跳过前四次迭代,并在i=4处触发断点,如下图所示。

Pro 提示 1:您还可以根据命中次数指定要触发的断点。

命中次数是指调试器命中特定断点的次数。

例如,您可能想只为最后几个文件触发断点(可能是因为您想详细检查它们)。您可以从下拉菜单中选择 点击次数 (而不是 表达式 )并将其设置为 *>3* 。这意味着断点仅在前三次出现后触发,因此我们在终端中看到三个打印语句,分别对应于 *i=0* *i=1* *i=2*

专家提示 2:我们甚至可以在每次遇到断点时记录一条消息(到调试控制台)。为此,从下拉菜单中选择 日志消息 (而不是 表达式 )并将其设置为要在花括号内评估的一些纯文本和/或表达式。举个简单的例子,我们将通过设置日志消息为 *Updated i. i = {i}* 来记录断点被命中时 *i* 的更新值。

调用栈

通常,在处理大型项目时,很容易忘记代码流。由于有很多断点,您可能会奇怪自己是如何出现在这个文件中的,更重要的是,您是从哪里出现在这里的!

由于堆栈遵循先进后出的顺序,VSCode 的调用堆栈非常适合在调试期间跟踪断点。

使用显示调用层次结构的调用堆栈窗口,VSCode 调试器可以在这方面提供一些帮助。

为了展示该实用程序,我们将通过在utils目录中引入upper.py来使当前项目稍微大一点。

upper.py

让我们快速更新abs.py以使用to_upper()功能:

abs.py

总而言之,我们将在项目中设置四个断点(见下图):

  • hello.py的第四行
  • abs.py的第 5 行和第 6 行
  • upper.py的第 2 行

展示 VSCode 中调用堆栈功能的示例

尽管这看起来像是一个微不足道的例子,但我们可以通过以下方式来了解呼叫层次结构:

  • 启动调试器(确保活动屏幕包含hello.py)并点击继续按钮,直到到达upper.py中的断点。
  • 看一下调用堆栈窗口(见下图):

需要注意的几件事:

  • 在调用栈的最顶端是模块(即to_upper())和文件名(upper.py)以及包含当前断点的行号(在我们的例子中是第 2 行)。
  • 第二个位置是调用当前断点的文件/行号(在我们的例子中是abs.py,第 5 行)。
  • 第三个位置是初始模块(hello.py在第 6 行),它调用了abs.py中的get_abspath(),后者调用了当前模块(upper.py)中的to_upper())。

希望这是有意义的,不会成为那种我知道你知道我知道你知道…东西!

额外收获:异常断点

良好的编程实践使用 try-catch 块强制使用错误处理。因此,调试器可能会跳过它们,代码不会中断。但是,如果您想在抛出和/或引发异常时显式停止调试器,该怎么办呢?

调试期间的异常断点有助于突出显示任何可能因为在 catch 块中被捕获而未被注意到的错误。

为了演示这一点,让我们最后一次修改代码,并加入一些 try-except 块。

hello.py

如果您运行这个独立的脚本(没有调试器),它将运行得很好,没有任何错误!即使在没有找到x时遇到问题,也会因为 except 块中的pass而被静默处理。

话虽如此,在这种情况下破解 VSCode 似乎还是有用的。为此,请转到断点窗口,确保勾选了引发的异常旁边的复选框(默认情况下会触发未捕获的异常)。

断点异常

现在,当您尝试在调试模式下运行hello.py时,代码将在 try 块处中断。

断点异常

结论

调试是我根据帕累托 80:20 法则学到的技能之一。学习它的各个方面可能需要一段时间,但是一旦掌握了,它就可以应用到你将要从事的所有项目中。需要注意的一点是,在调试器运行时,我们可以设置/编辑任意多的断点,但是,我们不能改变代码本身。我们必须首先停止调试器,进行更改,然后再次启动调试器。

一如既往,如果有更简单的方法来做/解释本文中提到的一些事情,一定要让我知道。一般来说,避免不请自来的破坏性/垃圾/敌意评论!

直到下一次✨

我喜欢写循序渐进的初学者指南、操作指南、面试问题、ML/AI 中使用的解码术语等。如果你想完全访问我的所有文章(以及其他媒体上的文章),那么你可以注册使用 我的链接**这里* *

* *

如何让熊猫的功能更有用

原文:https://towardsdatascience.com/how-to-make-pandas-functions-more-useful-25649f71cc21

充分利用它。

亚历杭德罗·皮涅罗·阿梅里奥在 Unsplash 上的照片

Pandas 可以说是数据科学生态系统中最常用的库。它的功能使复杂的数据清理和分析任务变得简单易行。

然而,我们经常使用熊猫功能的默认设置,这使我们无法充分利用它们。在大多数情况下,参数使函数更灵活或更强大。

此外,通过正确使用参数,我们可以在一个步骤中完成一个包含多个步骤的任务。因此,我们的代码变得更加高效和干净。

在本文中,我们将通过一些例子来展示使用参数的额外好处。让我们从导入库和创建示例数据帧开始。

import pandas as pd
import numpy as np
import random# create a DataFrame with mock data
pg = ["A","B","C","D","E","F","G"]
sales = np.arange(1,1000)df = pd.DataFrame({"product_group":random.choices(pg, weights=[12,10,8,5,1,1,1],k=300),
"product_code":np.arange(1000,1300),
"sales_qty":random.choices(sales, k=300)})# add some missing values
df.loc[150:170, "product_group"] = np.nan
df.loc[210:230, "sales_qty"] = np.nan

df 前五行(图片由作者提供)

DataFrame 包含一些产品及其产品组,以及随机生成的销售数量值。

假设我们想要计算每组中产品的数量。最简单的方法是 value_counts 函数。

df["product_group"].value_counts()**# output**
A    88
B    69
C    56
D    37
F    11
E     9
G     9
Name: product_group, dtype: int64

product group 列中应该有一些缺失的值,但是我们在输出中看不到它们。原因是 value_counts 函数默认情况下会忽略缺失的值。

在某些任务中忽略缺失值可能会产生误导。我们总是可以使用 isna 函数来检查丢失的值。然而,value_counts 函数能够为我们提供关于缺失值的信息。我们只需要使用 dropna 参数。

df["product_group"].value_counts(dropna=False)**# output**
A      88
B      69
C      56
D      37
NaN    21
F      11
E       9
G       9
Name: product_group, dtype: int64

有 21 种产品的产品组信息缺失。

让我们快速看一下上一个例子的输出。a 组有 88 个产品。

A 组拥有最多的产品,但是 A 在整个数据框架中的百分比份额是多少?我们可以用一个简单的数学运算来计算它,但是有一个更简单的方法:规范化参数。

df["product_group"].value_counts(normalize=True, dropna=False)**# output** A      0.293333
B      0.230000
C      0.186667
D      0.123333
NaN    0.070000
F      0.036667
E      0.030000
G      0.030000
Name: product_group, dtype: float64

A 组占整个产品系列的 29%。

normalize 参数对于许多任务来说很方便。假设我们正在处理一项任务,并且希望只包含产品组,以涵盖整个产品系列的 75%。通过使用 value_counts 和 cumsum 函数,我们可以轻松找到范围内的产品组,如下所示:

df["product_group"].value_counts(normalize=True).cumsum()**# output** A    0.315412
B    0.562724
C    0.763441
D    0.896057
F    0.935484
E    0.967742
G    1.000000
Name: product_group, dtype: float64

所有产品中的 76%属于产品组 A、B 或 c。您可能已经注意到百分比份额与上一个示例不同。原因是我们这次忽略了缺失的值。

根据数量对观察值(即行)进行排序是一项非常常见的任务,可以使用 Pandas 的 sort_values 函数来完成。让我们根据销售量对行进行降序排序。

df = df.sort_values(by="sales_qty", ascending=False)df.head()

df 前五行(图片由作者提供)

行被排序,但是它们的索引保持与原始数据帧中的相同。在许多情况下,这可能不是问题,但是有一个合适的索引总是更好。我们可以使用 reset_index 函数更新索引,但是 sort_values 函数有一个用于此任务的参数: ignore_index

df = df.sort_values(by="sales_qty", ascending=False, ignore_index=True)df.head()

df 前五行(图片由作者提供)

现在看起来好多了。

组合多个数据帧的 concat 函数也有 ignore_index 参数。

groupby 是数据分析中最常用的 Pandas 函数之一。它根据给定列中的不同值对行进行分组。然后,我们可以计算每个组的合计值。

例如,我们可以计算每组的平均销售量,如下所示:

df.groupby("product_group").agg(avg_sales=("sales_qty","mean"))**# output**

(图片由作者提供)

输出是数据帧,组显示为索引。但是,将组作为数据帧中的一列更好也更实用。当我们有嵌套组时(即,当按多列分组时),这尤其有用。

我们可以使用 reset_index 函数将索引中的组移到新列中。但是,groupby 函数为此提供了一个参数: as_index

df.groupby("product_group", as_index=False).agg(avg_sales=("sales_qty","mean"))**# output**

(图片由作者提供)

我觉得现在好多了。稍后我们可能需要使用 group 列。

我们已经看到了一些改变函数行为的参数。它们帮助我们调整功能以更好地满足我们的需求或添加新功能。

有几个参数使函数更加灵活、实用和有用。我强烈建议在使用函数之前检查参数。

你可以成为 媒介会员 解锁我的全部写作权限,外加其余媒介。如果你已经是了,别忘了订阅https://sonery.medium.com/subscribe如果你想在我发表新文章时收到电子邮件。

*https://sonery.medium.com/membership

感谢您的阅读。如果您有任何反馈,请告诉我。*

如何充分利用地理空间数据

原文:https://towardsdatascience.com/how-to-make-the-most-of-geospatial-data-b044c8d0c55c

空间数据将我们居住的物理世界与应用程序、设备和算法联系起来,帮助我们导航(有时是字面上的)我们的日常生活。本周我们有一个丰富的推荐阅读阵容,涵盖了非常广泛的主题,但让我们从最近的三篇文章开始,这些文章专注于地理空间数据的强大用例。

  • 学习如何用 Python 制作漂亮的地图。谁不爱好看的地图?我们当然有。如果你遵循亚当·赛明顿的指导,你将会在不需要任何专门工具或代码的情况下制作 3D 地形图。
  • 汇集空间数据和图像分割技术Elliot Humphrey 带领我们完成了一个巧妙的项目,该项目利用地形数据和转移学习来训练一个模型,以检测夏威夷的煤渣锥(一种基本火山)。然后,可以将得到的分割掩模转换成真实数据集,用于进一步分析。
  • 道路距离数据有助于降低与铅管 相关的风险。弗林特水危机(以及其他许多鲜为人知的案例)凸显了检测和更换住宅区铅管的必要性。 Dashiell Young-Saver 和队友 Javiera Astudillo、Max Cembalest 和 Kevin Hare 解释了他们如何开发一个包含空间信息的模型,以更好地预测房屋的铅暴露。

杰克·安斯蒂在 Unsplash 上的照片

对探索地理空间数据各种应用之外的其他主题感兴趣吗?从深度潜水到实践教程,2022 年有了一个梦幻般的开始——这里只是过去几周的几个亮点:

感谢您加入我们为期一周的学习和探索。如果你正在做一个有趣的项目或实验,或者想教读者一项新的数据科学技能,考虑在 TDS 上写下它。

直到下一个变量,
TDS 编辑

如何充分利用 Pydantic

原文:https://towardsdatascience.com/how-to-make-the-most-of-pydantic-aa374d5c12d

探索数据契约验证技术、与 JSON 模式更高的互操作性以及简化的数据模型处理。

Pydantic 已经成为定义和使用数据类型的规则改变者。这使得代码更加可读健壮,同时感觉像是语言的自然扩展。

它是一个易于使用的工具,帮助开发人员验证并基于给定的定义解析数据,所有这些都与 Python 的类型提示完全集成。主要的用例包括读取应用程序配置、检查 API 请求以及创建任何可能需要作为内部构建块的数据结构。

pydantic 模型的示例。图片由作者提供。

虽然有些读者可能已经熟悉这些定义,但我们将探索不同的技术来:

  • 通过正确持有数据契约,使我们对 Pydantic 的使用更安全、更易于调试。
  • 利用 JSON 模式实现更高的互操作性。
  • 使用 Python 的内置函数简化数据模型处理。

以安全的方式解析数据

JSON 是网络语言。大多数数据科学家和工程师偶然发现了一个文件或 API,他们希望在安全地处理其数据之前从该文件或 API 获得一致的结构。

让我们想象一下,我们正在从一个 API 中检索数据,这个 API 作为一个目录。然后,对于特定的端点,我们期望数据契约如下:

{
    "name": string,
    "age": integer,
    "address": {
        "city": string,
        "zip_code": string,
        "number": integer
    }
}

该结构用地址的嵌套定义定义了一个 cat 条目。因此,定义一个 Pydantic 模型来解决这个问题可能看起来像下面的代码:

请注意,我们很容易就能找到几款与我们的合同相符的车型。在这个场景中,定义只需要一个嵌套层次,但是 Pydantic 允许任何数量的模型的直接组合。

下一步是使用这些模式解析给定的数据,将原始 JSON 转换成我们可以快速使用的特定 Python 对象。

所有字段都被转换成 Python 解释器和 ide 已知的属性,这是一个巨大的帮助。

到目前为止,我们已经走上了幸福的道路。然而,经验丰富的开发人员计划得更远。如果 API 开始发送不同的数据怎么办?当一切都自动化时,团队需要确保他们能够快速发现问题并安全地对它们做出反应。让我们看看,如果在没有更新定义的情况下合同破裂会发生什么:

Pydantic 来救援了!由于age字段被定义为一个int,但是我们收到了一个str,这个代码片段将引发一个ValidationError。对于其他类型的不一致,也将抛出相同的验证异常,比如缺失字段(如果没有定义为Optional)。

违反合同

如果发生完全相反的情况呢?如果 API 开始添加越来越多的不属于合同的字段,并且这种情况没有得到正确的监控,我们可能会遗漏一些隐藏的错误。

该代码片段将完美运行,并且data对象将只包含已定义的字段,尽管这隐藏了一些不一致。但是仅仅因为在一段特定的代码中没有异常或日志,就不能保证整个过程按预期工作。

虽然这是 Pydantic 中的默认行为,但我们可以调整配置,禁止将任何额外的字段发送到类定义:

当解析带有额外字段的数据时,类配置的这个小变化现在会抛出一个ValidationError:

ValidationError: 2 validation errors for CatRequest
key
  extra fields not permitted (type=value_error.extra)
key2
  extra fields not permitted (type=value_error.extra)

互用性

那些研究数据网格的人应该已经接触过这个术语了。当把我们孤立的平台和团队分解成更小的领域时,我们必须在不同的系统之间共享全局数据定义。

由于技术上的实施可能是不可能的,治理团队需要确保多语言架构能够安全地共享并从构建单一事实来源的集中且唯一的模式发展而来。

实现语言无关解决方案的一种方式是将数据结构定义为 JSON 模式。幸运的是,这并没有把 Pydantic 从等式中去掉,因为有一个很棒的项目可以帮助开发人员将 JSON 模式直接转换成 Pydantic 模型。

让我们重复上面的例子,并用它构建一个 JSON 模式:

{
    "$id": "[https://catz.org/schema/api/data/catRequest.json](https://catz.org/schema/api/data/catRequest.json)",
    "$schema": "[http://json-schema.org/draft-07/schema#](http://json-schema.org/draft-07/schema#)",
    "title": "CatRequest",
    "description": "Cat API request definition.",
    "type": "object",
    "definitions": {
      "address": {
        "description": "Defines the city, code and number.",
        "type": "object",
        "properties": {
            "city": {
                "description": "Cat's city",
                "type": "string"
            },
            "zip_code": {
                "description": "Postal code",
                "type": "string"
            },
            "number": {
                "description": "House number",
                "type": "integer"
            }
        },
        "additionalProperties": false
      }
    },
    "properties": {
      "name": {
        "description": "Cat's name.",
        "type": "string"
      },
      "age": {
        "description": "Cat's age, in cat years.",
        "type": "integer"
      },
      "address": {
        "description": "Where does the cat live.",
        "$ref": "#/definitions/address"
      }
    },
    "required": ["name"],
    "additionalProperties": false
}

这里我们定义了我们的CatRequest模式,不仅提供了它的属性:nameageaddress,还提供了一次性写下嵌套定义的能力。

JSON 模式的两个重要特征是:

  • 能够通过传递一组required字段名来选择哪些字段是强制的和可选的。为了便于说明,我们只选择了name作为必备。
  • 使用additionalProperties,开发人员可以很容易地控制这些定义不会变成键值转储。定义一个契约只有在我们能确保它成立时才有帮助。

现在让我们使用datamodel-codegen CLI 将模式转换成 Pydantic 类:

$ pip install datamodel-code-generator$ datamodel-codegen --input cat.json --input-file-type jsonschema --output cat.py

它将模型的定义存储在cat.py中,不仅添加了配置,还在Optional和字段描述中进行了适当的输入。

JSON 模式是我们在 OpenMetadata 的集中式模式的关键。有了像 datamodel-codegen 这样的工具,我们就可以在用多种语言构建的代码的不同模块中使用相同的定义。

单一调度

通常只有一种处理方法,管道必须为每个数据模型运行不同的逻辑。然后,开发人员经常陷入 if-else 狂潮,使得代码触发所有的复杂性警报。

如果有更好的方法呢?如果内置到 Python 里呢?singledispatch室内装潢师和皮丹蒂奇是天造地设的一对。该函数是 functools 模块中的一个强大工具,通过注册每种数据类型的特定行为,帮助维护一个更具可伸缩性的代码库。

作者图片

单个调度是 Python 实现函数重载的方式,即调用单个函数,该函数将根据它接收的参数知道运行哪个内部逻辑。但是,注意singledispatch只考虑第一个参数的类型。幸运的是,我们可以通过使用 Pydantic 模型将所有需要的数据打包到这个参数中。

使用这种方法,我们可以快速创建和测试响应特定数据需求的单个功能,轻松地将新模型集成到循环中,并有一个清晰直接的方法来处理多个数据源。

结论

Pydantic 是在 Python 生态系统中创建了 before 和 after 的工具之一。它不仅通过极大地提高代码质量和可读性使开发人员的生活变得更加轻松,而且它还是现代框架的基础,如 FastAPI

在本帖中,我们看到了以下最佳实践:

  • 能够跟踪数据契约中添加或缺少字段的任何变化。
  • 使用 JSON 模式在分布式系统中集成数据定义,同时仍然使用 Pydantic for Python 代码库。
  • 应用singledispatch装饰器来设计更容易阅读、测试和缩放的处理流水线。

如何充分利用你作为 TDS 作者的经历

原文:https://towardsdatascience.com/how-to-make-the-most-of-your-experience-as-a-tds-author-b1e056be63f1

最后更新于 2023 年 1 月

我们的资源和常见问题快速指南

杰斯·贝利在 Unsplash 上的照片

作为 TDS 的编辑,我们知道我们的许多作者都有关于写作和出版过程的类似问题,快速访问您需要的信息可以帮助简化您的写作工作流程。

下面,我们为作者收集了一些最有用的(也是最常用的)资源和链接——我们希望它们能让你的 TDS 之旅更顺利。如果您对我们在此未涉及的主题有任何疑问,我们还添加了如何联系我们团队的信息。

我在哪里可以找到关于 TDS 指南的最新信息?

我们很高兴你问了!随着数据科学、机器学习和人工智能领域的发展,我们的编辑指南和最佳实践也在发展。如果你对帖子的任何方面(图片使用、数据集许可、文章引用——或其他任何东西,真的)不确定,你可以在这里找到我们政策的最新版本:

如果您已经有一段时间没有和我们一起发布了,我们最近更新了我们的指南:

我们还创建或更新了这些常见问题:

如果您认为我们的资源中缺少某个问题或主题,请告诉我们!

对我们的编辑团队有什么期望

无论我们决定发布还是拒绝您的最新投稿,我们都会仔细审阅您发送给我们的每一篇文章,并尽可能快地完成(作为一个小团队,我们有时可能需要几天时间来回复,但通常我们的周转时间要比这快得多)。我们旨在与您分享具体的反馈,告诉您如何改进您的写作或编辑您的文章,以符合我们的编辑指南。我们偶尔也会依靠我们的志愿编辑助理的主题专业知识,他们可以就特定主题提供更详细的技术信息。我们作为出版物的成功和你们作为 TDS 作者的成功是携手并进的。

我们通过确保每篇文章符合 Medium 的发布标准,并在 TDS 的大型社交媒体账户上推广,帮助我们发布的每篇文章获得尽可能多的受众。

每天,我们还会在我们的编辑精选深度挖掘页面,以及我们的策划专栏上刊登一些我们最好的文章。您可以通过订阅我们的每周新闻简报获得我们的最新功能、编辑推荐和来自我们团队的更新。我们建议浏览我们精心挑选的文章——它们是很好的读物,它们也可以让你更好地了解在 TDS 上表现良好的文章类型,以及我们的团队认为特别引人注目的文章类型。

我如何发展我的受众?

作者在 TDS 上发表文章有很多原因,但找到一个读者并与更广泛的社区分享你的见解是我们大多数贡献者的共同目标。

我们最成功的作者写信息丰富的原创文章。它们涵盖了对我们当前和未来的数据专业人士受众至关重要的主题。或许最重要的是:他们始终如一地这样做。如果有一个关键因素可以扩大你的影响力,那就是:养成写作习惯。无论是每周,每月,还是不同的节奏,找到一个适合你的节奏并坚持下去。有规律的出版节奏会培养读者的忠诚度,他们会知道你下一篇文章的时间;你的写作习惯变成了他们的阅读习惯。

许多作者有时觉得他们没有什么可写的,或者围绕他们的主题的每个可能的角度都已经被涵盖了。那从来不是真的!如果你需要灵感,我们很乐意提供一些关于产生文章主题的想法。

等式的另一边是确保你发表的文章被阅读——这是传播消息和推广你的工作发挥作用的地方。如果你不确定从哪里开始,我们在我们的作家工作室:推广的艺术分享有用的建议和策略。

我如何通过在媒体上写作赚钱?

作者将他们在 TDS 上的工作转化为多种收入来源和职业机会。对于任何有兴趣直接将他们的文章货币化的人来说,可以加入媒介合作伙伴计划,作家可以根据媒介成员在他们的帖子上花费的时间以及他们产生的推荐会员数量来赚钱。

:合作伙伴计划完全由 Medium 运营;TDS 团队无法获得或控制您的收入。

Medium 经常在自己的博客上分享平台新闻和给作者的建议,所以订阅 Creators Hub3 分钟阅读,你永远不会错过更新。

有疑问?

无论您是想询问此处未涉及的主题、在发布过程中遇到的问题,还是想与我们分享任何其他信息,您都可以访问联系我们页面,找到各种联系方式。

如何使您的数据模型模块化

原文:https://towardsdatascience.com/how-to-make-your-data-models-modular-71b21cdf5208

通过这些步骤避免高度耦合的系统和意外的生产错误

照片由 T.J. BreshearsUnsplash 拍摄

发现生产中的某些东西坏了,这是每个工程师最可怕的噩梦。更糟糕的是,当一个简单的变化打破了一切。当这种情况发生时,很有可能你的系统是高度交织在一起的,这里的一个调整可能会引起那边的多米诺骨牌效应。

没有改变是安全的!你永远不知道它最终会影响到什么。

这正是我们在构建数据模型时想要避免的。您不希望它们紧密耦合,这样您就可以在不破坏整个管道的情况下,在必要时轻松地进行调试和更改。

在头脑中用模块化构建你的数据模型是这个问题的解决方案。模块化数据模型彼此独立存在。它们就像一个更大的拼图中的几块。这些部分共同创造了一些美丽的东西,并向您展示了全貌。然而,每个拼图块仍然可以被拉出并独立存在,而不会破坏整个图像。

我们希望我们的数据模型是拼图块,可以轻松地移除、更改和添加,而不会对数据管道产生任何性能影响。

我们如何做到这一点?它从重新评估您当前的数据模型以及如何重写它们以使其更加模块化开始。

为每个原始数据源创建基本模型。

任何数据模型都不应该直接引用原始数据。您总是希望在您的数据仓库中保留一份原始数据的副本。这样,万一您的数据遭到破坏,您可以随时恢复到原始副本。

基础模型的存在是为了保护您的原始数据不被以任何方式转换。它们通常是数据仓库中位于原始数据源之上的视图,因此它们不占用任何存储空间。他们引用原始数据,但也改变其基本特征,使其更清晰,便于分析工程师使用。

基本型号包括:

  • 数据类型转换
  • 列名更改
  • 时区转换
  • 简单 case when 语句

基本模型不应该包括任何花哨的计算、连接或聚合。它们只是原始数据的标准化版本,便于您在下游的数据模型中引用。

例如,假设您有一个原始数据源,如下所示:

select 
  id,
  user_id, 
  created_date,
  source
from web_traffic.first_visits

为了在我的下游模型中更容易理解和引用,我将使用 dbt 为其编写一个基本模型,如下所示:

select 
  id AS first_visit_id,
  user_id, 
  CAST(created_date AS date) AS created_date,
  created_date::timestamp_ntz AS created_at,
  source AS referrer_source
from {{ source('web_traffic', 'first_visits') }}

我指定id也引用表名,以便将来的连接更容易阅读。

我将created_date转换为一个实际的日期,并使用该列将其转换为正确的时间戳类型并重命名。

最后,我更改了source列的名称,使其更具描述性。

识别数据模型之间的公共代码。

现在,您已经为每个原始数据源创建了一个基本模型,您希望更深入地研究已经存在的更复杂的数据模型。如果您没有使用像 dbt 这样的转换工具,那么您有可能为每个模型编写了很长的 SQL 代码文件。仔细阅读每一个文件,看看是否能找到在多个不同文件中重复的代码。

这种重复的代码可能是多次使用的货币换算计算、映射代码或频繁连接在一起的表。

我们来看两个独立的模型。

第一个是寻找 10 月份纽约州的所有促销订单。

# model looking for all promo orders to the state of New York in the month of October 
with order_information_joined AS (
  select
    orders.order_id,
    orders.ordered_at, 
    order_types.order_type_name, 
    order_addresses.city, 
    states.state_name
  from orders 
  left join order_types 
    on orders.order_type_id = order_types.order_type_id 
  left join order_addresses 
    on orders.order_address_id = order_addresses on order_address_id 
  left join states 
    on order_addresses.state_id = states.state_id 
) 

select 
  order_id 
from order_information_joined 
where '10-01-2022' <= CAST(ordered_at AS date) <= '10-31-2022' 
  and order_type_name = 'promo' 
  and state_name = 'New York'

第二个是查找 2022 年的订购单数量。

# model finding the number of subscription orders placed in 2022
with subscription_orders AS (
  select * 
  from orders 
  where order_type_id=1
),

order_information_joined AS (
  select
    orders.order_id,
    orders.ordered_at, 
    order_types.order_type_name, 
    order_addresses.city, 
    states.state_name
  from subscription_orders 
  left join order_types 
    on orders.order_type_id = order_types.order_type_id 
  left join order_addresses 
    on orders.order_address_id = order_addresses on order_address_id 
  left join states 
    on order_addresses.state_id = states.state_id 
)

select count(*) from order_information_joined where YEAR(ordered_at)=2022

这些模型有什么共同点?两者一起加入ordersorder_typesorder_addressesstates表。因为这段代码至少使用了两次,所以将它作为自己的模型编写可能是一个有用的查询。这样,无论何时需要它,它都可以简单地在某人正在编写的另一个模型中被引用。

另外,请注意第二个模型在将订单表连接到其他表之前是如何过滤订单表的。在我们的新模型中,我们不想这样做,因为这样会限制我们使用模型的范围。相反,当引用新模型时,您将能够过滤order_type_id

将此代码编写为它自己的数据模型。

既然您已经确定了在多个数据模型中重复的代码,那么您想要将它转换成它自己的数据模型。这就是为什么你的模型是模块化的!

通过将重复的代码转换成自己的模型,您可以节省计算成本和运行时间。这样写的话,你的模型会运行得更快!您不再多次运行相同的代码,而是只运行一次,然后在不同的模型中引用它的输出。

确保取出任何特定于某个数据模型的代码片段。例如,您可能会为新用户筛选一个模型,但所有其他模型都会查看所有用户。不要在这个模块化数据模型中包含过滤器,而是将它添加到引用模块化模型的特定模型的代码中。

我们的目标是让这些片段变得不特定和可重用。当你再次引用时,总会有空间添加细节。

另一件需要注意的事情——确保给模型起一个描述性的名字。您希望其他人能够阅读模型的名称并知道它是做什么的。这样,他们也可以在他们的代码中引用它,而不是重新编写代码。编写模块化数据模型的一大好处是减少了数据团队工作之间的冗余。模块化模型使得使用你的队友已经写好的代码变得容易,节省了你的时间和精力!

如果我们看上面的例子,我会把数据模型叫做order_details_joined_location。这意味着我将不同的订单相关表连接到位置相关表。该模型将如下所示:

select
    orders.order_id,
    orders.user_id, 
    orders.product_quantity,
    orders.ordered_at, 
    order_types.order_type_id, 
    order_types.order_type_name, 
    order_address.street_line_1, 
    order_address.street_line_2, 
    order_addresses.city,
    order_address.zipcode,
    order_address.country,
    states.state_id,
    states.state_name
  from orders 
  left join order_types 
    on orders.order_type_id = order_types.order_type_id 
  left join order_addresses 
    on orders.order_address_id = order_addresses on order_address_id 
  left join states 
    on order_addresses.state_id = states.state_id

请注意,我是如何包含每个表中的所有列,而不仅仅是之前使用的特定模型中的列。这为模型的使用提供了更大的灵活性。

在其他模型中引用此模型。

现在,在您取出共享代码并使其成为自己的数据模型之后,您可以在原来的两个模型中引用这个新模型。 dbt 通过允许您使用一个简单的{{ ref() }}函数来调用其他数据模型,使这变得很容易。

重写第一个模型以引用我们的新order_details_joined_location 模型,如下所示:

select 
  order_id 
from {{ ref('order_details_joined_location') }}
where '10-01-2022' <= CAST(ordered_at AS date) <= '10-31-2022' 
  and order_type_name = 'promo' 
  and state_name = 'New York'

第二个应该是这样的:

select 
  count(*)
from {{ ref('order_details_joined_location') }}
  where order_type_id=1
  and YEAR(ordered_at)=2022

现在我们有了两个简单的模型,它们产生与以前相同的输出,但是引用了另一个模型,该模型现在可以用于许多其他模型。

结论

模块化是一组能够经受时间考验的数据模型的关键特征。当数据模型模块化时,您可以降低计算成本,减少运行整个管道所需的时间,并通过创建协作编码流程使您的团队生活更轻松。数据建模的未来是模块化。 dbt 成为如此流行的数据转换工具是有原因的!他们了解这种需求,并能很好地解决问题。

关于分析工程的更多信息,请订阅我的免费每周简讯,在那里我分享学习资源、教程、最佳实践等等。

看看我的第一本电子书,分析工程基础知识,一本全方位的分析工程入门指南。

如何让你的数据科学代码评审更好

原文:https://towardsdatascience.com/how-to-make-your-data-science-code-reviews-better-13ac090560d2

从主持代码评审中吸取的经验教训

Artem Sapegin 在 Unsplash 上拍摄的照片

对于许多开发人员来说,代码评审可能是有压力的,尤其是如果你以前没有做过的话。反过来,它们在数据科学中越来越常见,尤其是当我们开始与更多面向软件的个人合作时。在不同的数据科学和工程团队中工作,让我在审查其他人的工作时,看到了哪些工作得好,哪些工作得不好。当然,并不是每个团队都以同样的方式进行代码评审,但是我想分享一些共同的经验以及我如何从这些评审中获得价值。

开发标准实践

无论是编程风格指南还是命名约定,您都需要为您的团队开发一套标准的编码实践。制定这一标准并经常引用它将有助于您的数据科学家符合预期。

我在我工作过的团队中发现,如果没有为人们制定的实践标准,每个人都会创建自己的标准,每个人的编码风格都是不同的。我不是说我们不能有自己的风格;看到人们编码方式的差异是很好的,但是命名约定和变量定义等项目可能会有很大的不同。因此,制定一个标准可以提供一些一致性,使代码更具可读性和可维护性。

当我作为团队领导专注于工具和 ML 实践时,我花了一个月的时间为我们的团队开发标准实践。这些实践包括所有我们期望的命名约定,创建功能性和面向对象代码的编码风格指南,以及代码评审的过程。这组文档被我们的团队很好地使用,并且经常被新的数据科学家引用。这是如何发展的基本原则。将这些文档视为您入职的起点和经验丰富的成员的参考。

查看编码标准的另一个原因包括对您将使用的编码范例的类型进行描述。我经常看到数据科学家更倾向于脚本或函数式编程。函数式编程有助于数据科学,也是我经常看到的团队采用的范例。对于我合作过的数据科学团队来说尤其如此,他们知道编码的基础,但不是软件开发人员。

总结您的更改

在数据科学家入职并开始开发他们的代码后,他们打开拉请求以批准他们的更改和添加。当我在以前的角色中主持代码审查时,我首先要求数据科学家总结他们的变化。这听起来可能有点奇怪,因为不是每个团队都这样做,但是概述你的变化是一个很好的反思工具。

当你坐下来打开你的拉请求时,花几分钟写一下你的代码。首先,您应该记录您对代码的添加、删除和更改。这个拉取请求解决了什么问题,你是如何解决的?如果您自己都不能回答这些问题,那么您的代码审查人员应该如何回答呢?

给自己一些思考的时间来总结你的变更,这有助于评审者理解你的代码,并给你时间来理解你在这个拉请求中所做的事情。通常,花几分钟时间反思我的工作可以让我在进行代码评审之前看到我可以做出的错误或更改。

这种类型的文档有帮助的另一个原因是为了可追溯性。例如,如果一位经理或客户问你六个月以后,你什么时候以及为什么做出了改变,你能回答吗?大概不会。彻底跟踪您的存储库中已经发生的变更,并记录这些变更为什么会发生,这为您回顾过去提供了一个很好的方法。当然,你永远不知道接下来谁会需要查看这些变化,或者为什么。因此,请准备好手头的文档。

分享知识和提出问题

您的代码审查可能脱机或正在开会;这取决于球队如何运行他们的。但无论形式如何,这都是分享知识和提问的时间。这是您向其他数据科学家、软件工程师和其他人学习的时间。当有人对你的代码发表评论时,确保你理解他们为什么留下评论。

  • 他们会推荐一个 bug 补丁吗?
  • 他们是否陈述了要遵循的最佳实践?
  • 他们有没有指出一种更好的方式来格式化你的代码或者重新设计一个函数?
  • 你的工作中有新的算法、技术或数据需要考虑吗?

不管他们提出了什么,让他们澄清他们的评论,这样你就可以从中学习。一旦你理解了你的评审者在要求什么,你需要知道这是否是批准拉取请求所必需的,或者是不需要实现的“思考的食粮”类型的变更。我经常看到代码评审者分享一些想法,这些想法不需要被实现,但是在某种程度上是有教育意义的,可以和你分享技术和新的想法。

不要浪费时间。相反,从中学到尽可能多的东西,并在你的下一个任务中使用这些知识。

不要独占所有权

我喜欢代码审查以及与其他数据科学家和软件工程师合作的部分是当人们愿意接受其他人添加到他们工作中的时候。我不认为代码应该由公司中开发它的人“拥有”。代码不是你的;这是公司,所以不要霸占所有权或领土。

每个人都应该觉得他们可以在代码库的不同部分工作,并互相学习。总有一些东西可以从研究你的代码的其他人那里学到,并且让更多的人熟悉代码库。例如,如果只有一个人拥有代码,然后他们离开了,现在你要花更多的时间去理解他们离开后的工作。当有人在那里和你一起工作,并教你他们当时为什么做出编码决策时,学习起来更容易。

当讨论 ML 算法的设计决策时,尽可能从你的队友那里学习代码是至关重要的。当您查看这些代码时,您可以向他们询问他们所创建的特性,他们使用什么数据分析来得出结论,他们如何检查输出的指标,等等。举行这些知识传授会议并向他人学习是有益的。所以不要强占所有权;相反,注重协作和创新。

成为代码评审员

在我工作过的团队中,并不是每个人都是代码审查者。通常,这是由高级数据科学家和软件工程师来完成的。虽然我可以理解为什么让一个更资深的成员来评审你的代码是有帮助的,但是我认为至少有一个中级或初级人员来评审代码也是很好的。让他们审查其他人的代码,并学会给出可靠的反馈。

在以前的工作中,我经常邀请一两个低年级学生加入我们的评审。我们的评审是在一个会议上进行的,个人可以亲自讨论他们的结果和代码。在一次会议结束时,一名初级数据科学家找到我,告诉我他们看到其他人编写代码感到很欣慰。这让他们意识到他们知道的比他们想象的要多,并让他们看到其他人的代码是如何实现的。结果,随着时间的推移,这个人开始对自己的编码能力更加自信,并开始根据他的学习给出反馈。

向从未做过评论的人公开你的评论是一次很好的学习经历。不要觉得他们不能做出贡献,因为他们比你新。每个人都需要从某个地方开始,越快越好。

最后的想法

代码审查可能是一种紧张的,有时甚至是可怕的经历,但是它们不一定是这样的。学会与你的团队合作开发一个安全开放的环境,允许协作和知识共享。

  1. 为你的团队开发标准实践。这为经验丰富的团队成员提供了很好的参考,并允许新人更快入职。
  2. 总结你的变化。花时间反思你的工作可以帮助你发现错误或你可以做出的改变。这也让其他人更容易知道从你的代码中能得到什么。
  3. 分享知识,提出问题。这是你学习的时间!与你的队友分享知识和想法,并乐于提问。确保你澄清了你不清楚的评论。
  4. 不要霸占所有权。代码不应该属于一个人。相反,每个人都应该感觉到他们可以学习并为代码库的不同部分做出贡献。培养创新和协作的文化。
  5. 成为一名代码评审员。无论你是初级、中级还是高级,你都应该参与点评。代码评审是建立信心、学习和发展反馈能力的好方法。

什么帮助你改进了代码评审?你有什么经验教训想要分享吗?

感谢阅读!我希望你喜欢阅读我所学到的东西。如果你愿意,你可以通过使用这个链接成为一个媒介会员来支持我的写作。

如何让你的数据科学项目脱颖而出

原文:https://towardsdatascience.com/how-to-make-your-data-science-projects-stand-out-d9e0eb6bb3df

增加收入以显示业务影响

图片来自 PixabayStorme22k

数据科学家的工作竞争越来越激烈,能够从众多申请者中脱颖而出将增加你被录用的机会。数据科学项目组合是展示你的知识的好方法,特别是对于有抱负的数据科学家,但是招聘经理如何知道这个项目的价值呢?添加收入估计可以帮助您的项目脱颖而出,因为它向招聘经理展示了您知道如何将数据科学成果与业务影响联系起来。今天,我想讨论如何评估数据科学项目的收入影响。

建立基线

第一步是建立基线收入。您使用的输入将因公司的业务模式而异。一种方法是使用漏斗分析来确定收入计算的最佳输入。

下面是一家电子商务公司的简单收入计算。

示例 1 作者创建的电子商务收入计算

我假设网站每月有 100,000 个访问者(单元格 B1)。如果你的项目使用真实公司的数据,试着为你的收入计算找到实际的数字,使它更加真实。比如我用的美国电商转化率 3% ( cell B2)。订单数量(单元格 B3)的计算方法是 100,000 个访问者(单元格 B1)乘以 3%的转化率(单元格 B2)。

将结果与业务影响联系起来

现在,让我们将您的数据科学项目与业务影响联系起来。提高普通 KPI(如转换率或流失率)的项目很容易联系起来,因为它们对收入有直接影响。

然而,这种关系并不总是简单明了的。例如,情感分析项目如何帮助提高收入?情绪分析有助于公司了解客户投诉,从而提高客户保留率,进而增加终身收入。

挑战自我,弄清楚您的数据科学项目如何帮助提高业务 KPI,以将影响联系起来。

计算收入

假设你的数据科学项目将转化率从 3%提高到了 4%。这意味着每月收入增加了 50,000 美元,增幅为 33%。显示你的项目增加了 1%的转化率不会得到太多的关注,但增加 33%的收入肯定会脱颖而出。

示例 2 作者创建的电子商务收入计算

让我们尝试另一个产品推荐项目的例子,该项目增加了每个订单平均购买的两件商品。下面,我们将第 4 行到第 6 行中的输入添加到收入计算中,以估计影响。

示例 3 作者创建的电子商务收入计算

假设平均订单值为 50 美元(单元格 B6 ),计算方法是每个订单 5 件商品(单元格 B4 ),每件商品 10 美元(单元格 B5 ),每个订单再增加 2 件商品将使平均订单值达到 70 美元。与第一个示例类似,显示您的项目将每个订单的平均项目从 5 个增加到 7 个,不如添加您的项目将每月收入增加 60,000 美元,即增加 40%。

最终想法

我已经展示了几个如何将数据科学项目结果与收入影响联系起来的示例,但投入会因项目而异。为您的收入计算找到合适的输入是展示您知道如何将数据科学结果与业务绩效联系起来的另一种方式。在讨论为您的投资组合创建哪些数据科学项目时,请考虑结果如何与收入相关联,以帮助您决定最具业务影响力的项目。

你可能也会喜欢…

https://medium.datadriveninvestor.com/how-data-scientists-can-develop-business-acumen-870eb55866e6

如何向公众展示你的模型

原文:https://towardsdatascience.com/how-to-make-your-models-available-to-the-public-be782dcb9942

解释如何使用 Docker、Flask 和 Gunicorn 在线部署您的模型

MLOps 作为交叉文氏图[ CC BY-SA 4.0 ]

介绍

端到端的机器学习解决方案是将人工智能带入生产并使其可供大众消费和使用的重要方式。但今天,大多数人工智能从业者只是简单地做预处理,训练,评估和调优阶段,并将剩下的部分留给 DevOps 工程师。

因此,一个名为 MLOps 的新开发领域已经成为主流。重点已经从简单的培训和评估转移到将信息技术引入并整合到生产流程中。

在个人层面上,知道如何将你的模型公之于众是人工智能从业者技能组合中的一个重要工具。

在本文中,我们将探索如何使用 Keras、Flask、GunicornDocker 以简单高效的方式执行 MLOps 循环的一小部分。

如果你想跳过并直接进入代码,点击这里进入 GitHub 库。

本教程涵盖了哪些内容?

  1. 使用Keras及其现成组件创建一个定制模型
  2. 准备推理管道
  3. 开发一个简单的Flask应用程序来公开用于推理的模型
  4. 使用Gunicorn定义一个Dockerfile
  5. 建立我们的形象
  6. 定义一个简单的 Github Actions 工作流,在每次将图像推送到存储库时构建图像

1)使用 Keras 创建自定义模型

例如,我们将使用 Keras Functional API 和 ImageNet 上预训练的keras.applications的现成MobileNetV2模型创建一个简单的模型。

导入标题

本教程需要tensorflowkerasFlaskPILos。如果使用虚拟环境,您可以使用下面的requirements.txt文件来准备您的 env。

  • tensorflow:用于矩阵运算和 keras 后端
  • keras:用于高级深度学习建模 API,获取预训练模型
  • Flask:用于构建简单的 API 进行推理
  • PIL:用于处理图像
  • os:用于设置环境变量
import tensorflow **as** tf
from tensorflow import keras
from flask import Flask
from flask import request**,** jsonify
from PIL import Image
import os

设置选项

由于 GPU 是一种很难获得的资源,我们设置了一个 Tensorflow 标志,以便首先使任何 CUDA 设备不可见。如果你能在 GPU 上运行你的容器,请随意跳过这一行。

os**.**environ**[**'CUDA_VISIBLE_DEVICES'**]** **=** '-1'

模型定义

这个模型是使用 Keras Functional API 制作的。我们用一个简单的keras.Input来接受任何大小的彩色(RGB)图像。
输入通过以下层传递:

  • keras.layers.Resizing:用于将图像张量大小调整为 224x224x3 张量。
  • keras.layers.Rescaling:用于将图像张量值从[0,255]范围重新缩放到[0,1]范围。
  • keras.applications.MobileNetV2:用于从 Keras 导入 MobileNetV2 实例(在 ImageNet 上预训练)。
image_input **=** keras**.**Input**(**shape**=(None,None,**3**))**x **=** keras**.**layers**.**Resizing**(**height**=**224**,** width**=**224**,** interpolation**=**'lanczos3'**,** crop_to_aspect_ratio**=False)(**image_input**)**x **=** keras**.**layers**.**Rescaling**(**scale**=**1.**/**255**,** offset**=**0.0**)(**x**)**mobilenet **=** keras**.**applications**.**MobileNetV2**(**
    alpha**=**1.0**,**
    include_top**=True,**
    weights**=**"imagenet"**,**
    input_tensor**=**image_input**,**
    classes**=**1000**,**
    classifier_activation**=**"softmax"
**)**model_output **=** mobilenet**(**x**)**model **=** keras**.**Model**(**inputs**=**image_input**,** outputs**=**model_output**)**

需求文件

Gunicorn用于将 API 部署到多个工作线程上,以增加计算消耗为代价降低延迟。使用 Gunicorn 是因为它实现了 WSGI。在生产环境中,像 NGINXApache Web Server 这样的前端服务器用于托管静态网页和负载平衡器,Gunicorn 在该层后面运行以实现功能。

Flask**==**2.0**.**3
Pillow**==**9.2**.**0
tensorflow**==**2.9**.**1
gunicorn**==**20.1**.**0

2)准备推理管道

我们定义了一个简单的函数,它接受一个tf.Tensor,并在模型中运行它,以返回一个最终的前 5 名预测字典结果。

推理功能

使用之前准备好的函数来推断作为tf.Tensor接受的图像。然后提取张量的numpy值,以获得每个类别的所有置信度得分。
这个 numpy 数组然后被传递到keras.applications.imagenet_utils.decode_predictions以获得前 5 个预测。

**def** **inference(**image**:** tf**.**Tensor**):**
    y **=** model**(**image**).**numpy**()**
    preds **=** keras**.**applications**.**imagenet_utils**.**decode_predictions**(**y**,** top**=**5**)**
    result **=** **{**i**[**1**]** **:** *str***(**i**[**2**])** **for** i **in** preds**[**0**]}**
    result **=** **{**k**:** v **for** k**,** v **in** *sorted***(**result**.**items**(),** key**=lambda** item**:** item**[**1**])}**
    **return** result

3)制作一个简单的 Flask 应用程序来公开模型以进行推理

现在,我们在路线//inference上定义两个简单的端点。

  • / (GET):第一个端点充当健康检查,以确保 API 启动并运行。
  • /inference (POST):第二个端点接受一个图像作为带有参数名image的表单字段,并返回一个带有置信度得分和 ImageNet 类名的字典。

烧瓶应用程序定义

app是稍后将由 Gunicorn 使用的 WSGI callable 的名称。要了解 WSGI 是什么,请查看下面有趣的链接部分。

app **=** Flask**(***__name__***)**

健康检查端点的定义

为了测试 API 是否启动并运行,我们只需在这个端点上点击一个 GET 请求来获得预期的输出。

@app**.**route**(**"/"**,** methods**=[**'GET'**])**
**def** **health_check():**
    result **=** **{**
        'outcome'**:**'endpoint working successfully'
    **}**
    **return** jsonify**(**result**)**

推理端点的定义

这里,我们接受一个POST请求,从请求中发送的文件中提取image参数。这以文件流格式存储,然后传递到PIL.Image.open以准备图像。最后,我们执行一些简单的预处理,将PIL图像转换为tf.Tensor图像,并准备一批 1 个图像传递给我们的推理函数。然后,返回的结果被传递到jsonify中进行响应准备和执行。

@app**.**route**(**"/inference"**,** methods**=[**'POST'**])**
**def** **perform_inference():**
    image **=** request**.**files**[**'image'**]**
    pil_img **=** Image**.**open**(**image**.**stream**)**
    tensor **=** keras**.**preprocessing**.**image**.**img_to_array**(**pil_img**)**
    tensor **=** tf**.**expand_dims**(**tensor**,** axis**=**0**)**
    result **=** inference**(**tensor**)**
    **return** jsonify**(**result**)**

4)定义一个使用 Gunicorn 进行部署的 Dockerfile

现在,我们已经完成了模型的定义,并使用一个简单的 Flask 应用程序为推断做好了准备。这里,我们开始编写一个Dockerfile和一个.dockerignore来构建一个定制的 Docker 映像。

FROM ubuntu**:**20.04RUN apt**-**get update **&&** apt**-**get install **-**y \
git \
curl \
ca**-**certificates \
python3 \
python3**-**pip \
sudo \
**&&** rm **-**rf **/**var**/**lib**/**apt**/**lists**/***RUN useradd **-**m docker_runnerRUN chown **-**R docker_runner**:**docker_runner **/**home**/**docker_runnerCOPY **--**chown**=**docker_runner ***.*** **/**home**/**docker_runner**/**flask_app**/**keras**-**docker**-**trial**/**USER docker_runnerWORKDIR **/**home**/**docker_runner**/**flask_app**/**keras**-**docker**-**trialENV PATH**=**"${PATH}:/home/docker_runner/.local/bin"RUN pip install **--**no**-**cache**-***dir* **-**r requirements**.**txtENTRYPOINT **[**"gunicorn"**,** "--bind"**,** "0.0.0.0:5000"**,** "--workers=4"**,** "app:app"**]**EXPOSE 5000

Dockerfile 文件

  • 第一行从 Docker Hub 中提取ubuntu:20.04图像,准备一个容器,其中包含库存 Ubuntu 20.04 Focal Fossa。
  • 第一个RUN命令下载并安装我们稍后需要的几个基本包。
  • 下一个RUN命令添加一个名为 docker_runner 的用户,并为该用户创建一个主目录(使用-m 选项)。
  • 下一个RUN命令更改目录所有权,并以递归方式为所有文件和子目录指定 docker_runner 作为其主目录的所有者(使用-R 选项)。
  • COPY命令将 Dockerfile 所在的当前存储库中的所有文件移动到容器的目标目录中。
  • USER命令用于将当前活动用户更改为docker_runner
  • WORKDIR命令用于将当前活动目录更改为/home/docker_runner/flask_app/keras-docker-trial
  • ENV命令用于设置 PATH 环境变量,并将我们用户的/.local/bin目录添加到其中。
  • RUN命令现在用于安装所有的需求,并且在安装时不使用任何缓存的目录或它们的 SHA 散列。
  • ENTRYPOINT命令用于使用gunicorn开始 API 部署。我们绑定本地主机的端口 5000,并为此任务启动 4 个 workers。我们将 WSGI callable 指定为app:app左侧的app。如果你在步骤 3 中更改了 Flask 应用程序的名称,那么你应该将这部分更改为{your_app_name}:app
  • EXPOSE命令用于让容器监听端口 5000。

。dockerignore

我们只是忽略了__pycache__/目录,因为它从 CPython 生成中间文件。

__pycache__**/**

5)建立我们的形象

我们现在构建我们的图像,并给它分配一个标签keras-docker-trial

docker build **.** **-**t keras**-**docker**-**trial **--**file Dockerfile

6)定义一个简单的 GitHub Actions 工作流,以便在每次将图像推送到存储库时构建它

在这里,作为一个额外的步骤,我们使用 GitHub Actions 来构建我们的映像,作为每次对任何分支进行推送或者如果 PR 被合并到存储库中的测试。只有当您在 GitHub 上为您的模型准备一个存储库时,才需要添加这个。

  • name:为工作流程指定一个名称。
  • on:定义何时使用工作流的触发器。
  • env:设置环境变量。
  • jobs:定义作为当前工作流的一部分运行的不同命令和工作流动作。
  • runs-on:定义哪个 GitHub 托管的 runner 用于执行工作流。
  • actions/checkout@v3:用于从仓库中签出代码。
  • Build Docker Image:从存储库中存在的 Dockerfile 文件构建映像。
name**:** Docker CIon**:**
  push**:**
  pull_request**:**
    types**:** **[**'opened'**,** 'reopened'**]**env**:**
  BUILD_CONFIGURATION**:** Releasejobs**:**
  job1**:**
    runs**-**on**:** ubuntu**-**latest
    steps**:**
      **-** name**:** Check**-**out the pushed code
        uses**:** actions**/**checkout@v3 **-** name**:** Build Docker image
        run**:** docker build **.** **-**t keras**-**docker**-**trial **--**file Dockerfile

测试管道

上面,我们已经定义了模型,并使用 Docker 和 Gunicorn 部署了它。您可以通过下面的 Postman API Explorer 找到一些部署及其预测的示例截图。

终端命令

获取健康检查请求

获取推理请求

通过邮递员请求发送的金鱼图像(根据 CC BY-SA 4.0 许可)

结论

上面,我们已经完成了一个简单的 Keras 模型的开发,它通过 Docker 的部署和一个用于 CI(持续集成)的 GitHub Actions 工作流。

未来范围

这只是作为一个简单的 MLOps 管道的一部分可以完成的工作的一小部分。CML(连续机器学习)和 DVC(数据版本控制)是两个重要的概念,是每个自我维持的机器学习工作流的一个组成部分,可以进一步探索。有趣的链接部分提供了相关资源。

参考

1.) Docker Hub 文档
2。) Keras 应用文档
3。) Gunicorn 文档

有趣的链接

1.)什么是 CML?
2。)什么是 DVC?
3。)什么是 WSGI (Web 服务器网关接口)?
4。)详细博客什么是 MLOps?

如何从 DEV 到 PRD 管理 Azure 数据工厂

原文:https://towardsdatascience.com/how-to-manage-azure-data-factory-from-dev-to-prd-ab7c8a2d10ae

使用 Azure DevOps 和 Azure Data Factory CI/CD 实用程序

管理从 DEV 到 PRD 的数据工厂管道—照片由 Ricardo Gomez AngelUnsplash 上拍摄

1.介绍

在软件项目中,开发/TST/UAT 环境被用来开发和测试代码。之后,代码被发布到 PRD 环境中。Azure 数据工厂(ADF)项目遵循相同的分阶段方法。但是,需要注意以下 ADF 挑战:

  • ADF 项目只能作为一个整体部署,而不是部署单个管道。在这种情况下,应该防止未经测试的代码最终进入生产环境。
  • ADF 支持分支和拉请求,但是很难检查 JSON 中的变化。审查变更只能在 ADF 本身中完成,要么使用 DEV 中的不同分支,要么在 TST 中运行
  • ADF 管道不能孤立测试,但是,通过固定数据源和 pytest 库,可以实现单元和集成测试。见我之前的博客

在这篇 blogpost 和 git repo [azure-data-factory-cicd-feature-release](https://github.com/rebremer/azure-data-factory-cicd-feature-release)中,讨论了如何优化 ADF 的发布周期,以防止未经测试的代码最终进入生产,另请参见下面的概述。

1.从 DEV 到 PRD 管理 ADF 按作者分类的图片

在此,主要观点如下:

  • 多个开发人员使用 1 个 ADF 实例来创建功能。每个功能都有自己的分支。如果有太多的开发人员在同一个 ADF 实例上工作(> 10),可以决定为一组开发人员创建一个新的实例。
  • 一旦一个特性准备好进行测试,它就会使用 ARM 模板部署到自己的 ADF 实例中。如果需要测试 N 个特性,这将导致 N 个 ADF 实例。这样,一个新的特性可以被孤立地测试,而不必先合并到主分支中。
  • 一旦一个特性成功,它就被合并到主分支,随后,主分支被自动部署到 UAT 环境中。在 UAT 环境中,可以进行集成测试。也可以决定合并到一个专用的 UAT(预发布)分支,即在 UAT 测试成功后合并到 main。
  • 一旦集成测试成功,主分支将部署到 PRD。请注意,部署到 PRD 总是发生在主分支,而不是特性分支。这是为了防止在 PRD 部署之后发生合并冲突,在最坏的情况下,这会导致撤销 PRD 中已经存在的特性。

在这篇博客的剩余部分,我们将讨论部署到不同环境的详细过程。最后,注意这篇博客遵循了 MSFT 推荐的新 ADF CI/CD 流程。在这个流程中,NPM Azure Data Factory utilities库而不是 ADF publish 按钮被用来传播到不同的环境。

2.偏差

在本博客的剩余部分,使用以下步骤部署项目:

  • 2.1 先决条件
  • 2.2 设置 Azure DevOps 项目
  • 2.3 设置 ADF 开发实例
  • 2.4 在 ADF 开发中创建特征分支

2.1 先决条件

本教程需要以下资源:

随后,转到 Azure 门户并创建一个资源组,所有 Azure 资源都将部署在该资源组中。这也可以使用以下 Azure CLI 命令来完成:

az group create -n <<your resource group>> -l <<your location>>

2.2 创建 Azure DevOps 项目

Azure DevOps 是一个工具,可以持续地构建、测试和部署你的代码到任何平台和云。创建新项目后,单击存储库文件夹并选择导入以下存储库:

另见下图,其中使用本博客的 git repo 创建了一个 devops repo:

2.2.1 将存储库添加到您的 Azure DevOps 项目,image by author

随后,需要服务连接来访问资源组 fom Azure DevOps 中的资源。转到项目设置,服务连接,然后选择 Azure 资源管理器,另见下图。

2.2.2 将存储库添加到您的 Azure DevOps 项目,image by author

选择服务主体身份验证,并将范围限制到您之前创建的资源组,另请参见下图。

2.2.3 按作者将范围限制到资源组、图像

2.3 设置 ADF 开发实例

在这一段中,创建了用于开发的 Azure 数据工厂。此 ADF 开发实例应使用在步骤 2.2 中创建的 Azure DevOps git repo。

  • 在这个链接中,解释了如何在门户中创建 Azure 数据工厂实例
  • 在这个链接中,解释了如何将代码库添加到 ADF 中。确保添加了 devops 项目 git repo 2.2。

或者,Azure CLI 也可以用来创建数据工厂,包括添加代码库,见这里。请参见下面链接到 Azure DevOps git repo 的成功部署的 ADF 实例:

2.3 Azure 数据工厂实例链接到 Azure DevOps

2.4 在 ADF 开发中创建特征分支

一切就绪后,就可以开始开发了。软件开发的最佳实践是从主分支创建开发分支。在这个开发分支中,特性是由开发人员创建的。

在这篇博客中,关键是新的分支是在 Azure DevOps 中创建的,而不是 ADF 本身。这是因为 Azure DevOps Pipeline yml 文件也应该包含在新分支中(ADF 不会这样做)。转到您的 Azure DevOps 项目,选择分支并创建新分支,另请参见下文。

2.4 在 Azure DevOps 中创建新分支

开发人员现在也可以在 ADF 中找到分支,并可以在分支中开始编码。当一个开发人员完成他的代码后,他的分支将被其他开发人员审查和测试。这将在下一小节中讨论。

3.测验(test)

在这一章中,检查了一个特性分支,并将其部署到 ADF 实例中进行测试。执行以下步骤:

  • 3.1 创建拉动式请求(PR)
  • 3.2 将功能分支部署到新的 ADF TST 实例

3.1 创建拉动式请求(PR)

在开发人员完成其分支后,应创建一个 PR,以便其他人可以查看。转到 Azure DevOps 项目,转到分支,选择您的功能分支,然后选择新的拉请求,见下文

4.1 创建拉式请求

填写表格,并填写负责审查变更的开发人员的姓名。将向这些开发人员发送一封电子邮件通知他们。

3.2 将功能分支部署到新的 ADF TST 实例

正如介绍中所讨论的,很难从 JSON 中回顾 ADF 管道的变化。请购单应始终在 ADF 实例中审查。有三种不同的方法可以做到这一点,如下所示:

  • 转到 ADF 开发实例,选择分支并查看更改。测试可能是一个挑战,因为分支机构仍然处于开发环境中
  • 将更改部署到现有的通用 ADF TST 实例。将代码部署到现有管道将覆盖现有 ADF 实例。
  • 将更改部署到具有功能分支名称的新的专用 ADF TST 实例。变更也可以单独测试。

本小节采用了新的专用 ADF TST 实例方法。转到你的 Azure DevOps 项目,转到你的 repo,找到[azure-pipelines-release.yml](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-feature.yml)并修改值以指向你的工作区,也见下文。

variables:
  adfdev : "<<your dev ADF instance>>"
  adftst : $(Build.SourceBranchName)
  subiddev: "<<your dev subscription id>>"
  subidtst: "<<your tst subscription id>>"
  rgdev : "<<your dev resource group>>"
  rgtst : "<<your tst resource group>>"
  location : "<<your location>>"
  AzureServiceConnectionId: "<<your AzureServiceConnectionId>>"

现在,在 DevOps 项目中选择管道,然后单击“新建管道”。转到向导,选择您之前创建的 Azure Repos Git 和 git repo。在“配置”选项卡中,选择“现有的 Azure Pipelines YAML 文件”,然后选择可以在 git repo 中找到的[azure-pipelines-release.yml](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-feature.yml),也见下文。

一旦创建了管道,它就会立即运行,当运行成功时,一个新的数据工厂实例就会以特性分支的名称创建。在一个特征分支被正确地检查和测试之后,可以决定再次将它合并到主分支。这将在下一段讨论。

4.UAT 和珠三角

在本博客的剩余部分,使用以下步骤部署项目:

  • 4.1 将特征分支合并到主分支
  • 4.2 将主要分支部署到 UAT 民主同盟军
  • 4.3 将主要分支部署到 ADF PRD

4.1 将特征分支合并到主分支

在特征分支被审查和测试正确后,它将再次与主分支合并。选择拉动请求,添加备注并将 PR 标记为完成,另请参见下图。

4.1 关闭 PR,将特征分支合并到主分支

特征分支现在合并到主分支。下一步,将在主要分支机构的 UAT 环境中运行回归测试。那将在下一段讨论。

4.2 将主要分支部署到 UAT 民主同盟军

主要分支始终是部署到珠三角。这样做是为了确保只有一个代码库在生产中使用。然而,在将一个特性合并到 main 之后,首先要运行几个回归测试,以确保 main 分支不包含冲突的变更。在这一段中,主要分支部署到了 UAT。

转到你的 Azure DevOps 项目,转到你的 repo,找到[azure-pipelines-release.txt](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-main.txt),调整值指向你的工作区,也见下文

variables:
  adfdev : "<<your dev ADF instance>>"
  adfuat : "<<your uat ADF instance>>"
  subiddev: "<<your dev subscription id>>"
  subiduat: "<<your uat subscription id>>"
  rgdev : "<<your dev resource group>>"
  rguat : "<<your uat resource group>>"
  location : "<<your location>>"
AzureServiceConnectionId: "<<your AzureServiceConnectionId>>"

现在采取第 3.2 节中描述的类似步骤来创建和运行管道。另外两点意见:

  • [azure-pipelines-release.yml](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-feature.yml) 包含以下代码片段:trigger: main。这意味着每当主分支中有变化时(例如,当一个特征分支被合并时),流水线就运行,并且测试可以被执行。
  • 创建 Azure DevOps 管道以部署到 UAT 只需一次

当测试成功执行后,代码就可以部署到 PRD 中了。这将在下一章讨论

4.3 将主要分支部署到 ADF PRD

当回归测试在 UAT 成功时,主分支机构准备在珠三角部署。这可以简单地通过在 4.2 中部署的管道中添加一个[deploy ADF to PRD](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-feature.yml#L72) 任务来完成。关于回归测试和部署到 PRD 的两个附加备注:

  • 自动测试 ADF 可能是一个挑战。在我之前的博客如何为 Azure 数据工厂构建单元测试中,广泛讨论了如何使用 DevOps 和 pytest 建立测试框架
  • 为了防止版本自动部署到 PRD,可以在管道中添加一个手动验证步骤。这在我之前的博客中也讨论过,可以在附带的 azure 管道示例中找到

5.结论

在一个典型的软件项目中, DEV/TST/UAT 环境被用来开发和测试代码。之后,它被释放到珠江三角洲环境中。Azure 数据工厂(ADF)管道遵循相同的发布周期。然而,ADF 项目只能作为一个整体进行部署,并且存在未经测试的代码被部署到生产环境中的风险。在这个博客和 git repo [azure-data-factory-cicd-feature-release](https://github.com/rebremer/azure-data-factory-cicd-feature-release)中,描述了如何管理 ADF 发布,另请参见下面的概述。

5.从 DEV 到 PRD 管理 ADF 按作者分类的图片

如何在苹果硅 M1 Mac 上管理 Conda 环境

原文:https://towardsdatascience.com/how-to-manage-conda-environments-on-an-apple-silicon-m1-mac-1e29cb3bad12

使用 conda 管理 ARM64 和 x86 Python 环境

简·kopřiva 在 Unsplash 上的照片

本文描述了如何使用 conda 管理 ARM64 和 x86 Python 环境。要使用 pyenv(我的首选工具)和虚拟环境完成同样的事情,请参见我的文章

如果您使用 Python 的时间足够长,您最终将需要使用不同的 Python 版本来管理环境。当开始新项目时,你会想要利用最新的特性( Python 3.10 最近发布了!),但是您还需要维护使用以前版本的旧项目。作为一名数据科学家,我经常遇到这个问题——我经常回到旧的项目和代码,所以我需要一种简单的方法来管理使用不同 Python 版本的多个环境。

这就是康达的用武之地。Conda 是一个非常流行的包和环境管理工具(我们将讨论环境管理方面)。它允许您为不同的项目维护单独的环境——每个环境可以包含不同的包、不同的包版本,甚至不同的 Python 版本——并且可以快速轻松地在它们之间切换。

注意:本文面向 Mac 用户,尤其是 Apple Silicon Mac 用户,但基本的 conda 指令将在所有平台上工作。

使用 conda 创建 Python 环境

按照这些说明安装 conda 并开始使用环境。

1.安装康达

有几种口味的康达可用,其中一些描述如下。按照超链接查找安装说明。每个安装程序都将为您提供相同的环境管理工具。如果你不确定要安装哪个,就选 Miniforge。

  • Miniforge(我的推荐) : 一个社区驱动的项目,支持多种系统架构。它创建了类似于 Miniconda 的最小 conda 环境(见下一个要点)。
  • Miniconda:conda 官方最小安装程序。它创建了最小的 conda 环境,而没有自动安装任何软件包。
  • Anaconda :原康达分布。它会自动将大量的 Python 包安装到新的 conda 环境中,因此它倾向于创建大型且臃肿的环境。我不推荐蟒蛇。

2.创造康达环境

创造康达环境非常容易。要使用特定版本的 Python(在本例中为 Python 3.9)创建一个新的 conda 环境,请从您的终端运行以下代码:

conda create -n myenv python=3.9

这将创建一个名为myenv的新 conda 环境。要激活 conda 环境,运行conda activate myenv(您可以通过conda env list查看您所有 conda 环境的列表)。一旦环境被激活,你可以使用conda installpip install安装 Python 包——conda install更彻底地管理包版本的依赖关系,你必须使用pip install来安装不能通过 conda 获得的包。

管理 conda 环境的完整文档链接此处

苹果硅苹果电脑的其他挑战

上述步骤几乎总是足够了。然而,在较新的苹果电脑上(就我个人而言,我用的是 M1 MacBook Air ),你可能会在安装某些软件包时遇到问题。当苹果从英特尔芯片转到他们内部的苹果硅芯片时,他们从 x86 架构变成了 ARM64 架构。这在很大程度上是一件好事——你在日常使用中会注意到的唯一区别是,新芯片比旧芯片更快、更高效。

不幸的是,您可能偶尔会遇到包兼容性问题。苹果的 ARM64 架构尚不支持一些 Python 包——例如,我在使用 ortools 包时就遇到了这个问题。您将在安装期间得到错误,并且您将不能在您的代码中使用这个包。最终,当开发人员为他们的包添加 ARM64 支持时,这个问题应该会消失,但与此同时,您必须找到另一个解决方案。

幸运的是,conda 提供了一个简单的短期解决方案:您可以在 Apple Silicon Mac 上轻松创建 x86 架构的 conda 环境。很简单,不需要安装任何额外的软件。

使用 x86 架构创建 conda 环境

如果您需要使用只在 x86 架构上工作的包,只需遵循这些步骤。首先尝试前面的步骤,只有在遇到软件包安装问题时才到这里来。否则,您会牺牲性能而没有任何好处。

1.安装 conda(如果您还没有安装的话)

遵循与上一节中步骤 1 相同的说明。您不需要安装一个单独版本的 conda 来处理 x86 环境。

2.创造康达环境

这是指令有点不同的地方,但只是一点点不同。我们只需要告诉 conda,我们希望我们的环境使用 x86 架构,而不是原生的 ARM64 架构。我们可以通过下面几行代码来实现,这些代码创建并激活一个名为myenv_x86的新 conda 环境:

CONDA_SUBDIR=osx-64 conda create -n myenv_x86 python=3.9
conda activate myenv_x86
conda config --env --set subdir osx-64

第一行创建环境。我们简单地设置CONDA_SUBDIR环境变量来指示 conda 应该使用 x86 Python 可执行文件创建 en environment。第二行激活环境,第三行确保 conda 将 x86 版本的 Python 包安装到环境中。

我在我的~/.zshrc文件中创建了一个简单的 shell 函数,这样我就不需要在每次创建新的 x86 环境时记住确切的命令。

### add this to ~/.zshrc (or ~/.bashrc if you're using Bash)create_x86_conda_environment () {
  # create a conda environment using x86 architecture
  # first argument is environment name, all subsequent arguments will be passed to `conda create`
  # example usage: create_x86_conda_environment myenv_x86 python=3.9

  CONDA_SUBDIR=osx-64 conda create -n $@
  conda activate $1
  conda config --env --set subdir osx-64
}

就是这样!一旦您创建了 x86 环境,它的工作方式与使用默认系统架构的常规 conda 环境完全相同。只需开始安装软件包,您就可以开始了!

结论

如果你是 Apple Silicon Mac 用户,你可能偶尔会遇到软件包安装问题。最终,在开发人员有足够的时间将 ARM64 支持添加到他们的包中后,这些问题应该会消失,但对于一些利基包来说,这可能需要几年的时间。同时,本文演示了如何使用 conda 创建与不支持 ARM64 的包兼容的环境。希望这篇文章能帮你省去一些故障排除!

Python 版本管理可能很棘手,但 conda 提供了一个很好的解决方案。我喜欢的另一个工具是 pyenv(与虚拟环境相结合)——详情见我的文章这里。如果你有另一个你更喜欢的工具,我很乐意听听它!

成为媒体会员访问成千上万作家的故事!

如何有效管理数据项目和团队

原文:https://towardsdatascience.com/how-to-manage-data-projects-and-teams-effectively-baf02025a367

重新评估我们的工作方式从来都不是一个坏主意。无论你是一名从事投资组合项目的学生,一名管理端到端管道的经验丰富的 ML 工程师,还是一名负责整个数据团队成功的高管,都是如此。

这可能是你最终拒绝的多余的一步。也许你决定修改每周团队电话会议的形式,或者进行最后一次质量检查,这需要几分钟,但偶尔可以节省几个小时。您的里程可能(并且很可能)会因团队和学科而异,但想法是相同的:您的工作流几乎肯定可以从一些调整和简化中受益。

为了帮助你用一些具体的想法开始这个旅程,我们选择了最近在数据科学、领导力和项目管理的交叉点上的几个杰出人物。尽情享受吧!

  • 如何解决你的数据科学项目 。离群值、缺失值、不平衡的数据集:迟早,你会在最糟糕的时候遇到这些。杰森·庄用一本关于你作为一名数据科学家可能遇到的一些最常见问题的入门书挽救了局面,并提出了“一个关于如何正确处理[它们]以及它们各自的权衡的框架”
  • 新领导角色的挑战与回报CJ Sullivan 回顾了一个重大的职业转变:从技术行业到滑雪行业,从一名个人贡献者到成为数据科学总监。她的文章揭示了这种变化可以教会我们如何领导他人,以及如何调整我们向非技术利益相关者传达工作价值的方式。
  • 路线图里有什么? 弄清楚如何实现我们为自己设定的目标可能需要一个漫长的试错过程,但首先要实现正确的目标更为棘手。 Marie Lefevre 阐述了定义良好的路线图对数据团队的好处,并分享了一个创建路线图的框架,该框架将为您提供“战略性思考而非操作性思考”的空间

Artem Kostelnyuk 在 Unsplash 上拍摄的照片

  • 构建健壮数据平台的重要性 。缩小数据对企业的潜在价值和实际影响之间的差距通常可以归结为将正确的工具放在正确的人手中。Mahdi Karabiben 探讨了数据目录目前对利益相关者的(许多)限制,并主张减少 ui,增加 API,推动更大的数据可访问性。
  • 要做出正确的决策,你需要找到正确的指标 。"你如何严谨、科学地研究那些你无法轻易定义的概念?"在你收集和分析数据之前,Cassie Kozyrkov 让我们注意到一项艰巨的任务,那就是对我们要测量的现象提出一个清晰、可行的想法。
  • 为什么数据项目通过迭代和共情蓬勃发展 。数据科学家是问题解决者;正如泰勒·詹森解释的那样,更好地理解他们内部客户的目标至少与对算法和统计的深刻理解同等重要(如果不是更重要的话)。Taylor 建议借用设计思维的原则——从移情到原型——对数据团队来说是一个强有力的举措。

当你让这些关于团队和项目管理的想法渗透进来的时候,我们希望你也可以花一些时间阅读一些我们最近发表的优秀文章。

  • 我们欢迎 Anna Rogers 的第一份 TDS 贡献——在生成式人工智能工具的背景下,对原创性和归因的发人深省的反思。
  • 人工智能生成的艺术也是 Danie Theron 研究稳定扩散图像的视觉输出中的性别、肤色和交叉偏见的首选。
  • 关于正则表达式以及如何在 Python 中使用它们的全面的一站式资源,请不要错过 Susan Maina 的最新文章。
  • 如果你的数据科学职业还处于早期阶段, Arunn Thevapalan 的第一篇 TDS 帖子为你进入提供了一张有用的路线图。
  • Furcy Pin 关于 Hadoop 生态系统的详细历史是一个有用的提醒,告诉我们大数据实际上是多么新(相对而言)。
  • 最近科技领域的裁员潮对人工智能的未来意味着什么? Wouter van Heeswijk 博士怀疑人工智能冬天是否即将来临。

感谢您支持我们发表的作品。如果你想产生最大的影响,考虑成为的中层成员。

直到下一个变量,

TDS 编辑

如何在不使用熊猫的情况下在 Python 中操作和分析数据

原文:https://towardsdatascience.com/how-to-manipulate-and-analyze-data-in-python-without-using-pandas-f22e0788c471

使用基本的内置 Python 函数分析未来人口增长

照片由贾科莫·卡拉Unsplash 拍摄

如果你正在使用 Python 并且想要做数据分析,你可能会使用 Pandas 库。这是有原因的,因为 Pandas 是一个快速灵活的数据处理和分析工具。然而,对于刚接触 python 的人来说,我发现回到 Python 的基本构建块进行数据分析是有用的,可以帮助我更好地学习 Python 进行基本的数据讨论。所以作为一个 Python 练习,我将在不使用 Pandas 库的情况下用 Python 做数据分析。我们将根据联合国提供的数据分析未来的人口增长。

我们将分析表格数据,这意味着我们将处理存储在二维列表中的数据。为了操作 2D 列表,我们将大量使用简单的嵌套 for 循环、索引和内置 python 函数,如 min()、max()、sort()和 append()。您将在使用 Pandas 或其他库的工作流程中使用的工具。

数据*是从 Gapminder 下载的。完整的数据集包含了 197 个国家从 1800 年到 2100 年的年度预测。我使用了从 2020 年到 2100 年所有 197 个国家的数据子集,时间间隔为 5 年。

数据集和代码可以在这个 Github repo 中找到。

导入数据

正如您在结果中看到的,数据存储在一个二维列表中,其中每一行都是列表中的一个元素。该表采用宽格式,其中每一“行”是一个国家,每一年是一“列”。这意味着列表中的每个列表都包含每个国家的所有人口信息。

创建汇总表

我们将通过创建一个汇总表来开始分析人口数据集,该表包含每个国家的最高和最低预期人口信息,以及从现在到 2100 年的相对人口变化。我们将创建一个名为pop_exp_dev的表,其中包含以下各列:

  • 国家
  • 最低预测人口
  • 最低预测人口年份
  • 最高预测人口
  • 最高预测人口年份
  • 2020 年至 2100 年人口的相对变化

我们通过几个步骤创建这个表。

  • 首先,我们需要将人口数据转换为整数值。我们通过使用嵌套的 for 循环来实现这一点。外部循环遍历每一行,内部循环遍历行中的每一项,并将每一项从字符串转换为整数。我们从索引 1 开始外部循环,因为我们不需要转换包含列名的第一行。我们还从索引 1 开始内部循环,因为每行的第一个值包含国家名称。
  • 我们创建一个空列表pop_exp_dev,在其中存储新的值。
  • 为了找到新值,我们使用 for-loops 来遍历行,以找到最高和最低值,并将它们追加到新表中。我们还找到了它们的索引值,这样我们就可以识别和附加这些值的年份。
  • 最后,我们希望找到 2020-2100 年期间以百分比表示的预期人口变化。我们用公式pop _ 2100-pop _ 2020/pop _ 2020 * 100来计算

作者图片

我们现在有一个表格,其中有一些人口数据的摘要。在 2D 列表中查看数据看起来不是很舒服,所以为了便于说明,我展示了如果您以表格形式查看我们创建的表时的样子。

作者图片

可视化子集列表

从这张表中,我们可以画出几幅图来显示预期的人口数量。把 197 个国家都标在一个情节里很快会让情节太长,很难读懂。相反,我们可以将表格的一部分分成子集,绘制更小的图。在这里,我们将把人口增长最快和人口下降最快的国家划分为一个图,将所有欧洲国家划分为另一个图。

最大人口增长和最大人口下降子集

对于第一个图,我们简单地按照相对变化的值对 2D 列表进行排序,该值存储在列 6(索引 5)中。我们使用 sorted()来做到这一点,并将一个 lambda 函数传递给 key 参数。

作者图片

该图显示,我们可以预期看到非洲国家人口增长最多,欧洲国家人口下降最多,但牙买加除外,它将是所有国家中人口下降最多的国家。

作者图片

欧洲的子集国家

为了创建欧洲国家的子集,我们手动创建一个包含欧洲所有国家的列表,并循环遍历pop_exp_dev列表,以查找与 Europ 列表中的国家相匹配的任何元素。

作者图片

创建一个水平柱状图,我们可以看到大多数欧洲国家预计到 2100 年人口会下降。

作者图片

将表格标准化,以比较国家之间的人口发展

由于一些国家人口多,一些国家人口少,很难比较它们的人口发展情况。我们可以通过归一化人口值来解决这个问题。为此,我们将 2020 年设定为一个指数年,所有其他年份都将与该指数年相关联。每一年的人口数除以指数年的人口数,再乘以 100。

作者图片

正如您在结果中看到的,2020 年被设置为索引年,值为 100。其他年份的人口以相对于 2020 年人口的百分比变化表示。

人口数据标准化后,我们可以通过对列表进行子集化来选择要绘制的国家,如前所示。这里,我们绘制了澳大利亚、日本、摩尔多瓦、瑞典、英国和美国的人口发展图。在这些国家中,澳大利亚预计将出现最大的人口增长,其次是美国、瑞典和英国。日本和摩尔多瓦的人口预计都将下降。

作者图片

结论

对于处理杂乱的数据或进行更高级的分析,我无疑会使用熊猫。事实上,我不建议任何人在实际工作流程中采用这种变通方法,因为这远不是分析数据的最佳方式。例如,为了编写高效的代码,最好是避免 For 循环并对操作进行矢量化。尽管如此,我发现对人口数据进行这种简单的分析有助于我更好地掌握 python 的基本功能,比如如何通过使用简单的或嵌套的 for 循环来访问二维列表中的某些项目和元素。以及如何使用 for-loops 创建项目并将其追加到新的二维列表。我希望这些例子对你有用!

*本文使用的数据基于联合国通过【GAPMINDER.ORG、CC-BY LICENSE 提供的免费资料

</5-common-misinterpretations-of-the-p-value-aacaa6dcfddd>

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

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

如何最大化数据分析的价值

原文:https://towardsdatascience.com/how-to-maximize-the-value-of-your-data-analysis-309059dcd243

在最近一篇关于数据集市的好处的文章中,Vicky Yu 强调了一个令人惊讶的统计数据:就在几年前,数据科学家将花费高达 80%的工作时间来争论和清理数据。即使这一比例现在有所下降(正如一些调查所显示的),但留给分析和洞察的时间仍然相对较少。这让人不禁想问:难道不应该是数据专业人员工作的核心吗?

本周,我们转向数据分析的关键领域(尽管有时讨论不足),并分享最近的几篇文章,这些文章关注分析师应该如何工作,以及他们如何充分利用有限的时间和强大的技能。

爱丽丝·迪特里希在 Unsplash 上拍摄的照片

  • 难道我们做探索性数据分析全错了?“EDA 不是一个人可以执行的特定指令集——它是一种对数据进行思考的方式,也是一种练习好奇心的方式。”Viyaleta Apgar 最近的帖子发人深省,邀请我们重新评估我们进行分析的方式,避免在没有反思我们自己的假设、偏见和盲点的情况下仓促行事。
  • 一瞥医疗保健数据分析师的日常经历 。以数据为中心的工作在不同的行业和工作场所看起来会有显著的不同,这就是为什么了解从业者的真实生活经历是如此有用。 Rashi Desai 慷慨地分享了她对医疗行业数据分析工作的第一手印象,并消除了一些常见的误解。

想在本周探索更多的话题吗?我们当然希望如此!以下是一些我们认为你会喜欢的近期杰出作品:

您的支持对我们非常重要,无论是阅读和参与我们作者的作品,与您的朋友和同事分享,还是成为媒体成员。谢谢大家!

直到下一个变量,

TDS 编辑

如何度量异常值概率

原文:https://towardsdatascience.com/how-to-measure-outlier-probability-b7a990e819cc

一种计算点为异常值的概率的方法

照片由 卢卡斯T5转自 像素

离群值对于数据科学家来说是个大问题。它们是数据集中的“奇怪点”,必须对其进行检查,以验证它们是错误还是真实现象。有几种算法可以帮助我们检测异常值,但我们有时需要测量某个点是异常值的概率,而不是 0-1 值。让我们看看一个可能的方法。

什么是离群值?

异常值实际上有几种定义。一般来说,它是一个离它所属的数据集的分布中心太远的点。这些点实际上是“奇怪的”,如果我们想用那个数据集填充我们的模型,就必须提前检查。机器学习模型可能不总是能够直接处理异常值,它们的存在可能会显著影响训练。

这就是为什么我们首先需要将一个点标记为离群点,然后检查它是否必须被删除。

如何检测异常值

有几种算法可以帮助我们检测异常值。四分位数范围是单变量数据集最常用的方法(例如,在箱线图的计算中使用)。多元数据集可能受益于高斯包络线或隔离森林。这些算法中的每一个都对数据集的每个点应用一个标签,如果该点不是异常值,则该标签为 0,否则为 1。

但是如果我们需要知道一个点是异常值的概率会发生什么呢?我们可以使用一个有用的工具来达到这个目的。

自举

关注我的出版物的人都知道我喜欢 bootstrap。这是数据科学家可以使用的最有用的统计工具之一。它允许我们计算测量的精度,并且异常值的检测实际上是一种测量。因此,让我们看看 bootstrap 的一种可能用途,根据给定的数据集计算某个点是异常值的概率。

这个想法是对我们的数据集进行重采样,对于每个生成的样本,检查每个点是否是异常值。您选择的算法无关紧要,所以您可以随意使用您喜欢的任何过程。然后使用从数据集生成的新样本再次重复该过程。由于数据集已经改变,一些原始点可能不再是异常值,而其他点可能由于同样的原因已经变成异常值。

根据需要多次重复该过程,并为每个原始点计算被标记为异常值的样本分数。这是你的概率。

那么,正式的程序是:

  1. 对于数据集的每个点,如果该点不是异常值,则计算等于 0 的标签,否则计算等于 1 的标签
  2. 使用替换对整个数据集进行重新采样,并创建一个相同大小的新数据集
  3. 重复步骤 1 和 2 数百次
  4. 计算生成的样本中标签的平均值

Python 中的一个例子

现在,让我们看看如何使用 Python 编程语言来计算异常值的概率。对于这个例子,我将使用我在本文的中谈到的 IQR 方法。

首先,我们导入 NumPy。

import numpy as np

然后,让我们用一个正态分布生成的 30 个伪随机数来模拟一个数据集。

np.random.seed(0) 
x = np.random.normal(size=30)

众所周知,正态分布中出现大数(即大于 3)的概率很低。让我们添加一个人为的异常值,例如 5。

x = np.append(x,5)

正态随机变量具有大于 5 的值的概率是 0.000000287,因此我们可以说,这样的点,如果出现在从正态分布生成的数据集中,一定会引起一些怀疑。那么这是一个异常值。

现在让我们写一个函数,对于一个给定的点和数组,如果该点是一个离群点,则给我们 1,否则给我们 0。

def check_outlier(value, array): 
    q1 = np.quantile(array,0.25) 
    q3 = np.quantile(array,0.75) 
    iqr = q3-q1 
    return int(value > q3+1.5*iqr or value < q1-1.5*iqr)

让我们将此函数作为地图应用于原始数据集,并检查结果。

result = np.array(list(map(lambda t: check_outlier(t,x),x))).reshape(1,-1)

正如我们所看到的,所有的点都是“好”的,最后一点被正确地标记为异常值。

现在让我们应用 bootstrap 来计算概率。让我们记住这些步骤:对数据集重新采样,计算每个点现在是否是异常值,重复数百次(本例中为 500 次),然后计算我们的点被标记为异常值的数据集的比例。

n = 500 
result = None 
for i in range(n): 
    new_x = np.random.choice(x,replace=True, size=len(x)) 
    outliers = np.array(list(map(
        lambda t: check_outlier(t,new_x),x))).reshape(1,-1)     if result is None: 
        result = outliers 
    else: 
        result = np.concatenate((result,outliers))

概率可以计算为 0-1 标签的平均值。

scores = np.apply_along_axis(np.mean,0,result)

现在让我们看看每个点及其分数:

np.concatenate((x.reshape(-1,1),scores.reshape(-1,1)),1)

正如我们所见,-2.55298982 被认为是一个异常值,有 69.6%的概率。这很现实,因为这个数字对于正态分布来说很“奇怪”,尽管它不像 5 那样“太奇怪”,5 被认为是 98.6%概率的异常值。所以,我们可以说这些分数其实是有意义的。

总的想法是按照分数降序排列我们的值。得分最高的记录很可能是异常值。

结论

在本文中,我提出了一种算法,对数据集的每条记录应用一个分数,该分数表示它是异常值的概率。这个过程的主要成分是自举技术。该算法适用于您使用的任何异常值识别技术,甚至可用于多元数据集。由于离群值的定义相当主观,我认为计算分数而不是 0-1 标签可能有助于数据科学家从我们的数据中提取更多信息。

原载于 2022 年 3 月 15 日【https://www.yourdatateacher.com】

如何衡量你的数据团队的投资回报率?

原文:https://towardsdatascience.com/how-to-measure-the-roi-of-your-data-team-9c60a939f247

并证明在数据人员、数据工具等方面的支出是合理的..适当地

衡量数据团队的投资回报率—图片来自 Castor

I .为什么衡量您的数据团队的投资回报率如此重要?

衡量数据团队投资回报率的重要性—来自 Castor 的图片

我感到困惑的是,尽管数据团队花了很多时间来量化一切,但他们仍然很难量化自己的表现。

问题是,如果不能证明数据团队对业务有重大的、可衡量的影响,他们就不能放弃。原因很简单。数据团队需要相应的投资来高效运作。我们知道投资通常需要充分的理由。出于这个简单的原因,如果你能证明你的数据团队的经济影响,你将永远只能协商预算,投资工具壮大你的数据团队。你可能已经知道了。问题是:如何衡量这种影响?

这件事已经有人考虑过了。事实上, Benn StancilMikkel dengseBarry McCardel 已经提出了三个有见地的框架来衡量数据团队的 ROI。

通过与 Clearbit 的数据主管 Julie Beynon 和 Khan Acadamy 的数据主管 Kelli Hill 的讨论,我们试图了解这些框架在实践中是如何应用的。这有助于我们确定可行的步骤,使您能够以简单而有意义的方式衡量数据团队的投资回报率,同时考虑到您团队的规模和成熟度。

二。为什么衡量数据团队的投资回报率如此困难?

  • 数据团队相对较新,或者至少比财务、营销和工程团队新。因此,还没有确定的衡量数据 ROI 的最佳实践。尽管已经出现了各种框架来衡量数据团队的 ROI,但是还没有普遍的方法来这样做。
  • 数据团队以一种非常独特的方式运作。他们通常支持其他团队,如营销、财务或工程团队,以影响绩效。因此,他们会间接影响业务,这就是为什么还不能 100%确定应该跟踪哪些 KPI 来评估他们的绩效。
  • 最后,数据团队需要考虑的相关 KPI 集根据特定行业、团队的规模和成熟度而有所不同。这也使得很难建立一种通用的衡量绩效的方式。

三。衡量您的数据团队的投资回报——来自数据领导者的重要提示。

A.数据团队的两个关键阶段及其各自的 KPI

I)阶段 1:清理数据

“干净的数据是我的第一个投资回报”,引自 Julie Beynon

新数据团队的首要任务是获得干净、可用和可信的数据。如果没有这一点,数据就无法影响企业的整体绩效。在数据团队的早期阶段,你需要确保数据是好的,你的工作是润色你的数据,直到它处于最佳状态。自然地,您将测量的第一个 KPIs 指标与数据质量相关联。数据质量是一个总括术语,涵盖了影响数据是否可用于预期用途的所有因素。因此,您测量的第一个数据 ROI 与您能否从干净的数据中获得答案紧密相关。以下是确保您的数据至少 80%良好的最重要的衡量要素。关于数据质量维度的更多内容,【Metaplane 的这篇文章是一个很好的资源。

数据质量测量及其相关指标—来自 Castor 的图片

  1. 精度

准确性与你拥有的数据是否描述现实有关。例如,如果您这个月在数据仓库中销售的商品数量与销售团队报告的实际数量不一致,那么您就遇到了准确性问题。

衡量准确性的关键指标:“当与参考集比较时,您的数据集匹配的程度,与其他数据一致的程度,通过规则的程度,以及对数据错误进行分类的阈值的程度。”(凯文胡,2021 )

2.完整性

完整性与你的数据描述现实的完整程度有关。完整性的两个层次如下:首先,您需要查看您的数据模型有多完整。其次,你应该看看数据本身相对于数据模型有多完整。

衡量完整性的关键指标:“针对映射的验证程度、空数据值的数量、缺失数据、满足的约束的数量。”(凯文胡,2021 )

3.一致性

一致性是指你的数据内部是否一致。当不同值的聚合与应该聚合的数字不一致时,数据就是不一致的。例如,如果每月的利润与每月的收入和成本数字不一致,那么就存在一致性问题。一致性检查的一个例子是 Codd 的引用完整性约束。

衡量一致性的关键指标:“通过检查的次数,以跟踪值或实体的唯一性,以及参照完整性是否得到维护。”(凯文·胡,2021 )

4.可靠性

可靠性与数据用户是否认为您仓库中的数据是真实的有关。当你有足够的血统和质量保证时,你的数据可以被认为是可靠的。如果您的销售团队认为由于技术问题,产品的使用不能反映真实的使用情况,那么您就面临着数据可靠性的问题。一个数据目录通常可以帮助你快速获得数据可靠性的证明。

衡量可靠性的关键指标:“验证最终用户系统中数据的请求数量、认证数据产品的数量、最终用户可用谱系的全面性、使用系统的用户数量。”(凯文胡,2021 )

5.可用性

这指的是数据能否被顺利访问和理解。当数据易于理解并以明确的方式正确解释时,数据可用性就很好。当一个外观仪表板很难理解时,你就有一个可用性问题。总的来说,用元数据丰富你的数据(即记录你的数据)使它在移动中变得可用和容易解释。

衡量可用性的关键指标:“以不同方式呈现数据的请求数量,数据集的文档化水平,使用系统的用户数量。”(凯文胡,2021 )

第二阶段:运作化

一旦您掌握了干净、可靠的数据,提高性能的下一步就是进行运营分析。这种方法包括让“运营”团队可以访问数据,用于运营用例(销售、营销,..).我们将它与将存储在仓库中的数据仅用于报告和商业智能的更经典的方法区分开来。运营分析不是使用数据来影响长期战略,而是为业务的日常运营提供战略信息。简而言之,就是让公司的数据发挥作用,让组织中的每个人都能做出更明智、更快速的决策。

运营分析—将数据从您的仓库推送到运营工具。图片来自 Castor

这是数据团队发展过程中非常自然的一步。收集数据的最终目的是提高组织的效率和决策。接下来,您应该衡量如何将数据交给其他团队,以便他们能够以独立的方式使用数据。这意味着将数据推入运营工具,以便销售或营销团队可以在他们的活动中有效地使用这些数据。逆向 ETL 工具非常适合数据操作化,允许你自动将数据从你的仓库推到其他团队的操作工具中。

数据操作化有两个好处,可以让您提高投资回报率。首先,它允许其他团队做出更有效的、数据驱动的决策。其次,这解放了分析团队,让他们能够进行更深入、更有意义的数据分析。当分析可以脱离基本的报告、向其他团队提供数据事实和回答问题时,他们可以专注于我们真正需要分析师技能的事情。

但是,您如何衡量自己在自助服务中推出数据的能力呢?

Clearbit 的数据主管 Julie Beynon 建议从你为其他团队解决问题的数量来考虑这个问题。您可以专门查看特定类别中请求数量的减少情况。例如,数据团队可能会收到很多关于归属的请求。将相关数据放在营销团队手中,应该会导致后者在这类问题上对数据团队的依赖减少,最终将归因相关请求的数量降至零。衡量数据可操作性的一个好方法是查看不同类别中请求数量的减少。你能从列表中剔除的问题越多,你的数据就越容易操作。

这个想法也出现在 HEX 提出的一个著名的数据 ROI 框架中。该框架认为,如果您的数据团队真正提供了价值,其他职能部门(如营销或财务)的领导会强烈主张代表您对团队进行更多投资。相反,如果你的合作伙伴不愿意为你辩护,你可能没有将你的数据操作化。也就是说,其他团队没有从你的工作中受益,或者你不允许他们独立处理数据。

B.不同的子团队有不同的 ROI。

我们已经确定,您应该根据数据团队所处的阶段查看不同的指标。但不是这样。数据团队由子团队组成,这些子团队应该根据不同的 KPI 指标进行评估。我们区分以下两个主要的子团队:工程和分析。这些子团队中的每一个都有不同的目标,并以不同的方式影响业务,因此为什么他们应该被不同地评估。

在一篇关于衡量数据工作投资回报率的非常酷的文章中,Mikkel dengse介绍了系统人员和 KPI 人员之间的区别。我们把这种区别变得更简单,我们只从工程(系统人员)和分析(KPI 人员)的角度来谈。

系统人员与 KPI 人员—图片来自 Mikkel Dengsoe

I)工程(系统)

数据工程团队的目标是构建可靠的基础架构,以确保分析人员能够访问可信数据。因此,以下指标最适合用于衡量他们的绩效

乘数效应

工程师的工作不会直接影响顶级 KPI。他们工作的独特之处在于,它起到了“乘数效应”的作用,让分析团队工作得更快、更有效率。例如,如果数据工程师可以让 dbt 移动得更快,分析工程师也可以移动得更快,并建立更多的数据模型。如果没有工程团队,数据分析师和数据科学家将花费 70%-80%的时间清理数据。拥有一个强大的工程团队可以提高分析团队的绩效,这反过来会积极影响其他团队的绩效。

但是如何衡量乘数效应呢?嗯,数据工程功能通过向其他团队提供干净、可靠的数据,允许其他人更快地行动。因此,衡量数据工程师绩效的关键指标是数据质量数据正常运行时间

数据质量

我们已经在第一部分中详细介绍了数据质量包含的组件。在更一般的情况下,数据质量可以通过数据问题触发的事件数量来衡量。我们可以将数据事件定义为包括内部警报、失败的测试以及外部消费者提出的相关问题。

数据正常运行时间

数据正常运行时间可以定义为数据集按时交付的时间相对于预期频率或 SLA 要求的百分比。

预期频率指的是数据集的预期更新频率。这通常是每天、每小时或实时的。

SLA(服务水平协议)要求是由数据生产者和消费者之间的 SLA 协议规定的频率条款,规定数据必须在何时更新。例如,SLA 可能会规定一个绝对时间,如早上 7:00,或者一个相对时间,如每 3 小时一次。

基础设施成本节约

我们最初惊讶地听到,在 KhanAcademy 的数据团队中,在衡量分析工程团队的绩效时,通常会考虑基础架构成本节约。让我们思考一下,为什么这种测量会有启发性。

除了向其他团队提供干净可靠的数据,数据工程师还负责良好的数据管理。这包括清理表格、归档不必要的表格,以及充分利用云所提供的优势。事实证明,良好的数据管理可以在存储成本方面节省大量资金。类似地,数据工程师通常寻求自动化流程或使其更高效。这节省了时间和金钱。因此,基础设施成本的节约是表现良好的数据工程团队的自然结果。从这个意义上说,在衡量你的团队的表现时,这是一个非常有趣的指标。当然,你需要保持谨慎,并且总是在引擎盖下寻找成本下降的原因。你的团队是更有效率了(好现象)还是他们只是处理的数据比以前少了(不好了)?不管答案是什么,这个数字除了非常容易测量之外,还会告诉你一些事情。

II)分析(关键绩效指标)

分析团队以不同的方式工作。他们对业务 KPI 有更直接的影响,或者至少他们更接近决策。评估他们的表现应该考虑到这一点。

在分析方面,真正重要的是从提出问题到给出答案之间的周转时间。分析的工作是为关键问题提供快速答案,从而启发企业的决策。目标是最小化从提出问题到分析师给出答案之间的时间,并且测量这个时间应该给出团队表现的一个很好的指示。这个框架最初是由 Benn Stancil 提出的,并被证明在 KhanAcamedy 的数据团队中运行良好。

以这种方式衡量分析性能的好处在于,它鼓励分析师将工作重点放在现实生活的决策上,避免他们迷失在探索性的数据分析中。

你的分析团队关注什么?这说明了您业务中的大量数据投资回报率。很简单,如果你的团队花了大部分时间为其他团队(营销、财务等)答题,这意味着你的数据没有被操作化。其他团队完全依赖分析团队解决数据问题,而您无法实现数据自助服务。这也意味着你的分析团队花了太多时间运行,解决日常业务问题和基本报告,而不是构建并专注于更深层次的分析。尽管这一指标无法充分衡量,但它让您很好地了解了自己在数据之旅中的位置。这也有助于您确定应该关注哪些指标。如果您的数据没有完全可操作化,您可能应该在数据质量上花费更多时间,确保您拥有干净的&可信数据。

结论

这些思考带给我们一个甜蜜的结论和一个相对简单的解决数据 ROI 难题的方法。一旦您理解了您的数据团队当前面临的挑战(数据质量或数据可操作性),确定您应该关注的用于测量性能的指标就非常简单了。我们试图通过这个很酷的地图让事情变得更简单。下面是怎么读的。您的数据团队相对年轻,您还没有解决数据质量问题?这意味着你处于第一阶段。您应该关注数据准确性一致性正常运行时间等指标来评估工程职能的绩效,同时您应该关注文档工作和数据可用性来衡量数据分析师的绩效。就这么简单。

衡量数据团队投资回报率的指南针—来自 Castor 的图片。

关于我们

我们写了利用数据资产时涉及的所有过程:从现代数据堆栈到数据团队组成,再到数据治理。我们的博客涵盖了从数据中创造有形价值的技术和非技术层面。

想去看看卡斯特吗?联系我们,我们将向您展示一个演示。

原载于https://www.castordoc.com

如何用 Python 将大型 CSV 文件合并成单个文件

原文:https://towardsdatascience.com/how-to-merge-large-csv-files-into-a-single-file-with-python-c66696f595ff

深入 Python,学习如何使用几行代码自动完成合并大块 CSV 或 Excel 文件等任务。

照片由 Pexels 的 Adriano Brodbeck 拍摄

建议的点播课程:

你们中的许多人联系我,询问用 Python 自动化 Excel(以及一般的电子表格)任务的宝贵资源。 下面我分享四门我会推荐的课程:

希望你也会发现它们有用!现在欣赏:D 的文章

介绍

信不信由你,在 2022 年仍然有公司雇佣外部数据顾问使用小的 Python 脚本来执行需要最小努力的任务(甚至对于新手)。

“…到 2022 年,仍然会有公司雇佣外部数据顾问来执行任务,这些任务只需使用一个小的 Python 脚本就能轻松完成。”

有趣的是,同样的顾问假装使用一些黑魔法来完成简单的工作,并收取令人难以置信的高费用。这笔钱绝对可以更明智地投资。

例如,想象一下这个场景:一个大型销售团队每个月必须合并来自不同部门的多个 CSV 或 Excel 文件,以创建一个统一的绩效报告。

尽管这些文件通常具有相似的格式,但有时它们非常大,以至于手动复制和粘贴甚至不是一个选项,还可能导致错误或丢失数据。

如果这听起来很熟悉,并且您希望学习如何使用 Python 来自动化这些任务,那么您就来对地方了!

实际上,在这个简短的教程中,我将向您展示如何用最少的 Python 代码将大型 CSV 或 Excel 文件合并成一个文件,甚至不用打开任何原始文件。

所以请继续关注,在这篇文章的结尾,我将与您分享一些额外的内容。

资料组

文件夹中,您将找到 CSV 格式的 5 个模拟销售文件 ,我将在本教程的下一步中使用它们。

每个文件都正好包括一百万行,并且具有相同数量的列。例如,如果您打开sales_recors_n1.csv文件,您将会遇到以下格式:

sales_records_n1.csv file.中前 20 行的示例

一旦你将文件下载到你的笔记本电脑上的一个特定目录,它的内容可以使用os Python 包中的listdir()方法列出。

这个方法,要求你把准确的path传递到目录,如下所示:

import ospath = “/Users/anbento/Documents/sales/sales_csv/”os.listdir(path)**Out[1]:**['sales_records_n5.csv',
 'sales_records_n4.csv',
 'sales_records_n1.csv',
 'sales_records_n3.csv',
 'sales_records_n2.csv']

注意这个方法如何返回一个 Python 列表,其中包含了sales_csv目录中的所有文件。这是有利的,因为对象可以用于迭代读取文件。

# 1 合并多个 CSV 文件

第一步的目标是使用 Python 将 5 个 CSV 文件合并到一个包含 500 万行的独特数据集中。为了做到这一点,我将利用ospandas包。

实现这一点的完整 Python 脚本如下:

现在,让我一步一步地解释代码中发生了什么:

1。首先,我正在导入所需的 Python 包,并将path指定给 CSV 文件。我建议您将所有想要合并的 CSV 文件保存在同一个文件夹中。这会让你的生活更轻松。

2。然后,我通过将path附加到每个遵循特定命名约定的文件上来创建一个file_list(在本例中是所有以 sales_records_n开头的文件)。根据名称选择文件有时很重要,因为您的工作目录可能还包含许多不相关的文件。注意列表理解是如何被用来生成file_list的。

这是我打印file_list内容时得到的结果:

print(file_list)**Output:**['/Users/anbento/Documents/sales/sales_csv/sales_records_n5.csv', '/Users/anbento/Documents/sales/sales_csv/sales_records_n4.csv', '/Users/anbento/Documents/sales/sales_csv/sales_records_n1.csv', '/Users/anbento/Documents/sales/sales_csv/sales_records_n3.csv', '/Users/anbento/Documents/sales/sales_csv/sales_records_n2.csv']

现在,所有文件都附带了路径,可以解析了。

然而,请记住这个列表是无序的,所以如果用来合并文件的顺序对你来说很重要,你将需要在遍历列表时使用函数。

3。此时,我首先创建一个空的csv_list。然后,我用 pandas 的read_csv()方法迭代解析file_list中的每个 CSV 文件,并将这些数据集附加到csv_list

请注意,当read_csv()用于解析 CSV 时,数据集被自动转换为 pandas df,因此csv_list现在包括 5 个单独的 pandas df。但是,在解析文件的同时,我还链接了以下命令:

assign(File_Name = os.path.basename(file))

这是在每个 DF 中创建了一个新的列,其中的包含了原始 CSV 文件的名称,这样,一旦文件被合并,您将确切地知道哪个文件来自哪个文件。

4。通过在csv_list上应用concat()方法,文件最终被合并成一个唯一的csv_merged熊猫 DF。添加ignore_index = True意味着将为csv_merged生成一个全新的有序索引。

5。最后一步是将csv_merged从 pandas DF 转换回 CSV 文件(名为sales_records_full.csv),该文件位于同一目录。这是通过to_csv()命令实现的。在这种情况下,index=False意味着不应添加包含索引的列。

这就是了!你现在应该看到合并后的文件(包括附加栏 File_Name)出现在目录中:

os.listdir(path)**Output:**['sales_records_full.csv',
 'sales_records_n1.csv',
 'sales_records_n2.csv',
 'sales_records_n3.csv',
 'sales_records_n4.csv',
 'sales_records_n5.csv']

除去包导入,只需要 7 行代码和几秒钟的运行时间就可以达到这个结果。

# 2 合并多个 Excel 文件

但是如果您希望合并大的 Excel 文件呢?

代码的差异很小:您只需在解析文件时用read_excel()替换方法read_csv(),在将sales_records_full.xlsx写回目录时用to_excel()替换to_csv()

包括上述变化的完整 Python 脚本如下:

如果你想边做边学,我建议你下载其他文件夹中的文件。运行代码后,您应该会获得类似于以下内容的合并文件:

sales_records_full.xlsx file中前 20 行的示例

正如你所看到的,独立于你的文件的扩展名,过程是完全一样的,只要你能把文件转换成 pandas DFs。

# 3 好处:将大文件分割成小文件

如果你一直读到教程的这一点,你应该得到一些额外的内容!

例如,现在让我们假设你正面临着与目前所描述的相反的问题:

您正在处理一个包含 500 万行的非常大的 CSV 或 Excel 文件,并且您希望将它拆分成多个较小的文件,这样您就可以更快地打开它们并显示它们的内容。怎么做呢?

这是另一个简单的任务,因为您可以简单地用read_csv()方法读取原始 CSV 文件,以 dataframe 格式(df)保存它,然后对行索引使用切片——比方说——将第一个 1M 行选择到一个更小的df_1 DF 中。

可以重复该过程以生成多个较小的文件,如下所示:

结论

在这篇简短的教程中,我展示了使用 Python 将多个大文件合并成一个唯一文件是多么直观。

一种可能的策略(本文中描述的策略)是简单地将它们转换成 pandas 文件,然后将它们连接起来,生成一个独特的文件。

这个过程是与扩展名无关的,前提是文件可以用 pandas 解析,并且总共只需要 7 行代码,这使得它成为刚刚学习用 Python 编程的人自动化的绝佳候选。

但是你呢?你知道在 Python 中合并多个文件的其他更有效的方法吗?欢迎在评论中分享你的知识,😄

你可能也喜欢

</10-algorithms-to-solve-before-your-python-coding-interview-feb74fb9bc27> 💔-ways-to-compute-a-weighted-average-in-python-4e066de7a719> 💔-ways-to-iterate-over-python-dictionaries-using-for-loops-14e789992ce5>

给我的读者一个提示

这个帖子包括附属链接,如果你购买的话,我可以免费给你一点佣金。

如何合并熊猫数据帧

原文:https://towardsdatascience.com/how-to-merge-pandas-dataframes-221e49c41bec

对熊猫数据帧执行左、右、内和反连接

安德斯·吉尔登在 Unsplash 上拍摄的照片

介绍

通常,我们可能必须将 pandas 数据帧合并在一起,以便基于最终服务于我们正在进行的任务的目的的一些逻辑,构建包含来自相关方的列和行的新数据帧。

在今天的文章中,我们将展示如何合并熊猫数据帧,并执行LEFTRIGHTINNEROUTERFULLANTI连接。Pandas 合并相当于 SQL 中的连接,我们将采用 SQL 风格的方法来解释合并,因为这将有助于新来者跟上。更具体地说,我们将展示如何表演

  • 左连接(也称为左外连接)
  • 右连接(也称为右外连接)
  • 内部连接
  • 完全外部连接
  • 左反连接(又名左排除连接)
  • 右反联接(又名右排除联接)
  • 完全反联接

除了不同的连接/合并类型,在下面的部分中,我们还将介绍如何

  • 在单个列上合并(在两个 dfs 上具有相同的名称)
  • 在多列上合并
  • 合并不同名称的列
  • 重命名联接中使用的共有列名
  • 仅从联接所涉及的数据框架中选择一些列

首先,让我们创建几个将在本教程中使用的数据框架,以演示我们今天将讨论的各种连接类型。

import pandas as pd df1 = pd.DataFrame(
    [
       (1, 345, 'B', True),
       (2, 100, 'C', False),
       (3, 300, 'B', False),
       (4, 151, 'A', False),
       (5, 212, 'A', True),
       (6, 121, 'C', False),
       (7, 333, 'B', True),
       (8, 456, 'C', True),
    ],
    columns=['id', 'value', 'colC', 'colD']
)df2 = pd.DataFrame(
    [
       (1, 111, 10.1, 3),
       (9, 56, 3.33, 10),
       (10, 17, 18.0, 8),
       (3, 567, 19.1, 4),
       (11, 98, 2.1, 1),
       (6, 31, 3.14, 12),
    ],
    columns=['id', 'value', 'colE', 'colF']
)print(df1)
 ***id  value colC   colD*** *0   1    345    B   True
1   2    100    C  False
2   3    300    B  False
3   4    151    A  False
4   5    212    A   True
5   6    121    C  False
6   7    333    B   True
7   8    456    C   True*print(df2)
 ***id  value   colE  colF*** *0   1    111  10.10     3
1   9     56   3.33    10
2  10     17  18.00     8
3   3    567  19.10     4
4  11     98   2.10     1
5   6     31   3.14    12*

内部连接

两个 pandas 数据帧之间的内部连接将产生一组记录,这些记录在指定的连接列中具有共同的值。

内部连接:使用两个帧的关键点的交集

对两个数据帧执行内部连接时选择的记录—来源:作者

为了使用单个列在两个数据帧之间执行内部连接,我们只需要在调用merge()时提供on参数。

df1.merge(df2, on='id')

注意,默认情况下,[merge()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.merge.html)方法执行内部连接(how='inner'),因此您不必显式指定连接类型。输出将包含在df1df2中具有共同 id 的所有记录:

 ***id  value_x colC   colD  value_y   colE  colF*** *0   1      345    B   True      111  10.10     3
1   3      300    B  False      567  19.10     4
2   6      121    C  False       31   3.14    12*

左连接(也称为左外连接)

左联接(或左外联接)将在指定的联接列上,从左数据帧中取出所有记录,以及从右数据帧中取出与左数据帧具有匹配值的记录。

结果中包含的右侧数据帧记录中的任何缺失值将被替换为NaN

左侧外部连接:仅使用左侧帧中的关键点

对两个数据帧执行左连接时选择的记录-来源:作者

要在两个熊猫数据帧之间执行左连接,现在需要在调用merge()时指定how='left'

df1.merge(df2, on='id', how='left')

如上所述,得到的数据帧将包含左侧数据帧中的每条记录,以及右侧数据帧中与连接列匹配的这些记录的相应值。这些记录的结果中与右侧数据帧中的记录不匹配的其余列值将被替换为NaN s。

 ***id  value_x colC   colD  value_y   colE  colF*** *0   1      345    B   True    111.0  10.10   3.0
1   2      100    C  False      NaN    NaN   NaN
2   3      300    B  False    567.0  19.10   4.0
3   4      151    A  False      NaN    NaN   NaN
4   5      212    A   True      NaN    NaN   NaN
5   6      121    C  False     31.0   3.14  12.0
6   7      333    B   True      NaN    NaN   NaN
7   8      456    C   True      NaN    NaN   NaN*

右连接(也称为右外连接)

右联接(或右外联接)将在指定的联接列上,从右数据帧中取出所有记录,以及从左数据帧中取出与右数据帧具有匹配值的记录。

包含在结果中的左侧数据帧记录中的任何缺失值将被替换为NaN

右侧外部连接:仅使用右侧帧中的关键点

对两个数据帧执行右连接时选择的记录-来源:作者

要在两个熊猫数据帧之间执行左连接,现在需要在调用merge()时指定how='right'

df1.merge(df2, on='id', how='right')

df1df2数据帧之间右连接的结果如下所示。

 ***id  value_x colC   colD  value_y   colE  colF*** *0   1    345.0    B   True      111  10.10     3
1   9      NaN  NaN    NaN       56   3.33    10
2  10      NaN  NaN    NaN       17  18.00     8
3   3    300.0    B  False      567  19.10     4
4  11      NaN  NaN    NaN       98   2.10     1
5   6    121.0    C  False       31   3.14    12*

完全外部连接

完整的外部连接基本上包括来自左右数据帧的所有记录。这种类型的连接将使用两个帧中的键——对于任何缺失的行,将插入NaN值。

完全外部连接:使用两个帧的键的联合

对两个数据帧执行完全外部连接时选择的记录—来源:作者

要在两个 pandas 数据帧之间执行完整的外部连接,现在需要在调用merge()时指定how='outer'

df1.merge(df2, on='id', how='outer')

使用我们的两个示例框架的完整外部连接的输出如下所示。

 ***id  value_x colC   colD  value_y   colE  colF*** *0    1    345.0    B   True    111.0  10.10   3.0
1    2    100.0    C  False      NaN    NaN   NaN
2    3    300.0    B  False    567.0  19.10   4.0
3    4    151.0    A  False      NaN    NaN   NaN
4    5    212.0    A   True      NaN    NaN   NaN
5    6    121.0    C  False     31.0   3.14  12.0
6    7    333.0    B   True      NaN    NaN   NaN
7    8    456.0    C   True      NaN    NaN   NaN
8    9      NaN  NaN    NaN     56.0   3.33  10.0
9   10      NaN  NaN    NaN     17.0  18.00   8.0
10  11      NaN  NaN    NaN     98.0   2.10   1.0*

左反连接(又名左排除连接)

左反连接将包含左框架中键没有出现在右框架中的所有记录。

左侧反连接:仅使用左侧帧中不出现在右侧帧中的关键点

对两个数据帧执行左反连接时选择的记录—来源:作者

熊猫的左反加入可以分两步进行。第一步,我们需要用indicator=True执行一个左外连接:

指标 *bool* *str* ,默认 *False*

如果是True,在输出数据帧中添加一个名为'_merge'的列,其中包含每行的源信息。通过提供字符串参数,可以为该列指定一个不同的名称。对于合并键仅出现在左侧数据帧中的观察,该列将具有值为'left_only'Categorical类型;对于合并键仅出现在右侧数据帧中的观察,该列将具有值为'right_only'的类型;如果观察的合并键同时出现在两个数据帧中,则该列将具有值为'both'的类型。

— Python 文档

df1.merge(df2, on='id', how='left', indicator=True) ***id  value_x colC   colD  value_y   colE  colF     _merge*** *0   1      345    B   True    111.0  10.10   3.0       both
1   2      100    C  False      NaN    NaN   NaN  left_only
2   3      300    B  False    567.0  19.10   4.0       both
3   4      151    A  False      NaN    NaN   NaN  left_only
4   5      212    A   True      NaN    NaN   NaN  left_only
5   6      121    C  False     31.0   3.14  12.0       both
6   7      333    B   True      NaN    NaN   NaN  left_only
7   8      456    C   True      NaN    NaN   NaN  left_only*

在第二步中,我们只需要query()上一个表达式的结果,以便只保留来自左侧框架的行,并过滤掉那些也出现在右侧框架中的行。

如果我们将这两个步骤结合在一起,得到的表达式将是

df1.merge(df2, on='id', how='left', indicator=True) \
    .query('_merge == "left_only"') \
    .drop('_merge', 1)

以及相应的结果

 ***id  value_x colC   colD  value_y  colE  colF*** *1   2      100    C  False      NaN   NaN   NaN
3   4      151    A  False      NaN   NaN   NaN
4   5      212    A   True      NaN   NaN   NaN
6   7      333    B   True      NaN   NaN   NaN
7   8      456    C   True      NaN   NaN   NaN*

右反联接(又名右排除联接)

类似地,右反连接将包含右框架的所有记录,这些记录的键没有出现在左框架中。

右侧反连接:仅使用右侧帧中不出现在左侧帧中的关键点

对两个数据帧执行右反连接时选择的记录—来源:作者

熊猫的右反加入可以分两步进行。第一步,我们需要用indicator=True执行一个右外连接:

指示器 *bool* *str* ,默认 *False*

如果是*True*,则向输出数据帧添加一个名为*'_merge'*的列,其中包含每行的源信息。通过提供字符串参数,可以为该列指定一个不同的名称。对于合并关键字只出现在左侧数据帧中的观察,该列将具有值为*'left_only'*Categorical类型;对于合并关键字只出现在右侧数据帧中的观察,该列将具有值为*'right_only'*的类型;如果观察的合并关键字同时出现在两个数据帧中,则该列将具有值*'both'*

— Python 文档

df1.merge(df2, on='id', how='right', indicator=True) ***id  value_x colC   colD  value_y   colE  colF      _merge*** *0   1    345.0    B   True      111  10.10     3        both
1   9      NaN  NaN    NaN       56   3.33    10  right_only
2  10      NaN  NaN    NaN       17  18.00     8  right_only
3   3    300.0    B  False      567  19.10     4        both
4  11      NaN  NaN    NaN       98   2.10     1  right_only
5   6    121.0    C  False       31   3.14    12        both*

在第二步中,我们只需要query()上一个表达式的结果,以便只保留来自右帧的行,并过滤掉那些同时出现在左帧中的行。

如果我们将这两个步骤结合在一起,得到的表达式将是

df1.merge(df2, on='id', how='right', indicator=True) \
  .query('_merge == "right_only"') \
  .drop('_merge', 1)

使用我们的示例数据帧得到的帧将是

 ***id  value_x colC colD  value_y   colE  colF*** *1   9      NaN  NaN  NaN       56   3.33    10
2  10      NaN  NaN  NaN       17  18.00     8
4  11      NaN  NaN  NaN       98   2.10     1*

完全反联接

完整的反连接将包含没有任何公共键的左帧和右帧的所有记录。

完全反连接:取两帧密钥的对称差

对两个数据帧执行完全反连接时选择的记录—来源:作者

同样,这可以像我们讨论的前两种反连接类型一样分两步执行。

df1.merge(df2, on='id', how='outer', indicator=True) \
  .query('_merge != "both"') \
  .drop('_merge', 1)

使用我们的示例帧的结果如下所示。

 ***id  value_x colC   colD  value_y   colE  colF*** *1    2    100.0    C  False      NaN    NaN   NaN
3    4    151.0    A  False      NaN    NaN   NaN
4    5    212.0    A   True      NaN    NaN   NaN
6    7    333.0    B   True      NaN    NaN   NaN
7    8    456.0    C   True      NaN    NaN   NaN
8    9      NaN  NaN    NaN     56.0   3.33  10.0
9   10      NaN  NaN    NaN     17.0  18.00   8.0
10  11      NaN  NaN    NaN     98.0   2.10   1.0*

更改同名列的后缀

还要注意如何分别使用_x_y自动重命名同名的列。您可以通过向suffixes参数提供所需的值来更改默认值。举个例子,

df1.merge(df2, on='id', **suffixes=('_df1', '_df2'**))

现在,参与连接的左右数据帧中的每一列都将具有指定的后缀。

 **id  value_df1 colC   colD  value_df2   colE  colF** *0   1        345    B   True        111  10.10     3
1   3        300    B  False        567  19.10     4
2   6        121    C  False         31   3.14    12*

合并不同的列名

现在让我们考虑另一个用例,其中我们想要合并两个 pandas 数据帧的列没有相同的名称。在这种情况下,我们不提供on参数,而是必须提供left_onright_on参数来指定在将左右数据帧合并在一起时要考虑的列。

作为一个例子,假设我们想要分别基于idcolF列合并df1df2。以下命令将完成这一任务:

df1.merge(df2, left_on='id', right_on='colF')

得到的数据帧如下所示

 ***id_x  value_x colC   colD  id_y  value_y  colE  colF***
*0     1      345    B   True    11       98   2.1     1
1     3      300    B  False     1      111  10.1     3
2     4      151    A  False     3      567  19.1     4
3     8      456    C   True    10       17  18.0     8*

在多列上合并

如果您想要合并多个列,您可以简单地将所有想要的列作为一个列表传递到on参数中:

df1.merge(df2, on=['colA', 'colB', ..])

如果左框架和右框架中的列有不同的名称,那么您可以再次使用right_onleft_on参数:

df1.merge(df2, left_on=['colA', 'colB'], right_on=['colC', 'colD])

从所涉及的数据帧中仅选择一些列

现在假设我们想使用左外连接将框架df1df2合并在一起,选择df1中的所有列,但只选择df2中的列colE

为此,在将帧传递给merge()方法时,可以简单地使用df2列的子集。

df1.merge(df2[['id', 'colE']], on='id')

这将从右侧框架中排除除colE之外的所有列:

 ***id  value colC   colD   colE*** *0   1    345    B   True  10.10
1   3    300    B  False  19.10
2   6    121    C  False   3.14*

最后的想法

在本教程中,我们讨论了合并熊猫数据帧以及如何执行左外、右外、内、全外、左反、右反全反连接。

此外,我们还讨论了一些其他用例,包括如何连接不同名称的列,甚至是多个列。此外,我们还展示了如何更改具有相同名称的列名的后缀,以及如何在执行合并后只从左侧或右侧数据帧中选择列的子集。

每当你想在熊猫数据帧之间执行一些连接时,你可以使用这篇文章作为备忘单,因此可以自由地保存这篇文章或在你的浏览器上创建一个书签!

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

相关文章你可能也喜欢

[## 熊猫中的 loc 与 iloc

towardsdatascience.com](/loc-vs-iloc-in-pandas-92fc125ed8eb)

如何合并熊猫数据帧

原文:https://towardsdatascience.com/how-to-merge-pandas-dataframes-35afe8b1497c

如何避免丢失有价值的数据点(包括备忘单)

合并的熊猫(图片由作者提供)

合并两个数据帧时的一个常见陷阱是无意中丢失了有价值的数据点。有时,您需要用第二个数据集中的附加信息来扩展您的初始数据集。为此,您可以将两个数据集读入 pandas 数据帧,然后用.merge()方法将它们组合成一个数据帧。但是,根据您合并它们的方式,您最终可能会得到比预期更少或更多的数据点。

但是,根据您合并它们的方式,您最终可能会得到比预期更少或更多的数据点。

本文将介绍合并两个数据帧的四种最常见的方法。由于合并 pandas 数据帧类似于 SQL 连接,我们将使用它们作为类比[1]。也就是说,我们将展示如何进行:

  • 左外部联接(熊猫:“左”)
  • 右外部联接(熊猫:“右”)
  • 完全外部连接(熊猫:“外部”)
  • 内部联接(熊猫:“内部”)

此外,我们将向您展示如何验证您的结果。

基本原则

为了解释这些概念,我们将使用下面两个最小的虚构数据集。在这个例子中,我们为动物园中的熊猫准备了两张桌子。第一个表包含动物园的位置信息。第二个表包含关于哪只熊猫在哪个动物园的信息。

左侧数据帧 df1(蓝色)和右侧数据帧 df2(黄色)(图片由作者提供)

在下面的例子中,数据帧被着色以说明哪个条目来自哪个数据帧。当合并两个数据帧时,您将它们称为“左”和“右”数据帧。在本例中,df1是左边的数据帧,颜色为蓝色。df2是右边的数据框,用黄色标出。如果合并的数据帧中的一个条目来自两个数据帧,它将用绿色行背景指示。

  • 左侧数据框:df1,以蓝色着色
  • 右侧数据框:df2,用黄色着色
  • 关键列:合并df1df2的公共列。在本例中,键列是“zoo_id”。
  • 合并的数据帧:df_merged,左边的行为蓝色,右边的行为黄色,右边的行为绿色

让我们来看看.merge()方法及其必要参数。这种方法比下面讨论的参数更多。然而,我们将只涉及与本文相关的内容。您可以参考文档[2]了解更多参数。

DataFrame.merge(right, 
                how = "...", 
                on = None, 
                indicator = False,
                ...)

首先,从左边的数据帧df1调用.merge()方法,第一个参数是右边的数据帧df2

df_merged = df1.merge(df2)

您也可以合并两个数据帧,如下所示,其中第一个参数是左侧数据帧,第二个参数是右侧数据帧:

df_merged = pd.merge(df1, df2)

虽然.merge()方法足够智能,可以找到要合并的公共键列,但我建议用参数on显式定义它。这不仅让你的代码可读性更好,还加快了执行时间。

df_merged = df1.merge(df2,
                      on = "zoo_id")

如果键列在两个数据帧中没有相同的名称,可以使用参数on_lefton_right代替on

df_merged = df1.merge(df2,
                      on_left = "key1",
                      on_right = "key2")

为了指示合并的数据帧中的一行来自哪个数据帧,我们将使用参数indicator = True。该选项将在合并的数据框架中创建一个新列“_merge”,如下例所示。对于合并数据帧的常规用法,可以省略 **indicator** 参数。

完全外部连接(熊猫:“外部”)

如果你想拍下每只熊猫和每个动物园的全景,该怎么办?

完全外部连接(图片由作者提供)

为此,您可以在 SQL speak [1]中使用完整的外部连接。

SELECT *
FROM df1
**FULL OUTER JOIN** df2
  ON df1.zoo_id = df2.zoo_id;

在熊猫身上,你可以使用how = "outer"【2】。

df_merged = df1.merge(df2, 
                      on = "zoo_id", 
                      how = **"outer"**,
                      indicator = True)

下面,您可以看到通过键列匹配两个数据框中每一行的各种可能性。值 101、102 和 103 出现在两个数据帧的两个键列中。如果两个数据帧都匹配,则在两个数据帧的相交处会出现一个绿点。

然而,值 104 仅出现在左侧数据帧的关键字列中,而值 105 仅出现在右侧数据帧的关键字列中。不匹配的行在与称为“不匹配”的线的相交处分别用蓝色或黄色点表示。

完整的外部联接包含下图中的所有点。

如果你想拍下每只熊猫和每个动物园的全景,该怎么办?

DataFrame 与“外部”合并(图片由作者提供)

作为健全性检查,合并数据帧的预期长度应该大于或等于较长数据帧的长度。合并的数据帧df_merged总共有七行:如列_merge所示,两个都有四行,一个只从左边,两个只从右边。

绿色行不包含空值,而蓝色和黄色行包含缺失值。由于绿色行来自两个数据帧,因此每列都有一个值。然而,因为左边的数据帧df2不包含任何与zoo_id = 104一起生活在动物园中的熊猫,所以第 4 行的列panda_name是 nan。黄色的第 5 行和第 6 行也是如此,因为df1不包含任何关于带有zoo_id = 105的动物园的信息。

内部联接(熊猫:“内部”)

但是,如果你只想看看饲养熊猫的动物园呢?

内部连接(图片由作者提供)

为此,您可以在 SQL speak [1]中使用内部连接。

SELECT *
FROM df1
**INNER JOIN** df2
  ON df1.zoo_id = df2.zoo_id;

在熊猫身上,你会用how = "inner"【2】。

df_merged = df1.merge(df2, 
                      on = "zoo_id", 
                      how = **"inner"**,
                      indicator = True)

在下图中,您可以再次看到完全外部连接所描述的匹配。但是,内部连接只考虑绿点,这表示两个数据帧的两个键列中都存在一个值。不匹配的值(完全外部连接中的蓝色和黄色点)被排除在外,如上图所示。

但是,如果你只想看看饲养熊猫的动物园呢?

DataFrame 与“inner”合并(图片由作者提供)

作为健全性检查,合并数据帧的预期长度应该长于或等于较短数据帧的长度。合并的数据帧df_merged总共有四行:如列_merge中所示,两者都有四行。

左外部联接(熊猫:“左”)

现在,假设您想知道每个动物园都有哪些熊猫。有了这些信息,你可以计算出每个动物园有多少只熊猫。

左外部连接(图片由作者提供)

为此,您可以在 SQL speak [1]中使用左外连接。

SELECT *
FROM df1
**LEFT OUTER JOIN** df2
  ON df1.zoo_id = df2.zoo_id;

在熊猫身上,你可以用how = "left"【2】。

df_merged = df1.merge(df2, 
                      on = "zoo_id", 
                      how = **"left"**,
                      indicator = True)

在下图中,您可以再次看到完全外部连接所描述的匹配。然而,左外连接只考虑绿点和蓝点,如上图所示。右侧数据框中不匹配的值(完全外部连接中的黄点)将被排除。

假设您想要计算每个动物园有多少只熊猫。

DataFrame 与“左”合并(图片由作者提供)

作为健全性检查,合并数据帧的预期长度应长于或等于左侧数据帧的长度。合并的数据帧df_merged总共有 5 行:如列_merge所示,两边各 4 行,左边 1 行。

右外部联接(熊猫:“右”)

最后,假设您想知道每只熊猫生活在哪个动物园。

右外部连接(图片由作者提供)

为此,您可以在 SQL speak [1]中使用右外连接。

SELECT *
FROM df1
**RIGHT OUTER JOIN** df2
  ON df1.zoo_id = df2.zoo_id;

在熊猫身上,你可以用how = "right"【2】。

df_merged = df1.merge(df2, 
                      on = "zoo_id", 
                      how = **"right"**,
                      indicator = True)

在下图中,您可以再次看到完全外部连接所描述的匹配。然而,一个右外连接只考虑绿色和黄色的点,如上面的 panda Venn 图所示。左侧数据框中不匹配的值(完全外部连接中的蓝点)将被排除。

假设您想知道每只熊猫生活在哪个动物园。

DataFrame 与“右”合并(图片由作者提供)

作为健全性检查,合并的数据帧的预期长度应该比右数据帧的长度长或等于右数据帧的长度合并后的数据帧df_merged总共有六行:如_merge列所示,四行来自两边,两行仅来自右边。

结论

这篇文章(字面上)演示了如何用.merge()方法合并两个熊猫数据帧。也就是说,我们研究了如何在 pandas 中执行最常见的 SQL 连接类型:全外部连接、内部连接、左外部连接和右外部连接。

下面你可以找到这篇文章的直观摘要:

如何合并熊猫数据帧的备忘单(图片由作者提供)

喜欢这个故事吗?

要阅读更多来自我和其他作家的故事,请在 Medium 上注册。报名时可以用我的 推荐链接 支持我。我将收取佣金,不需要你额外付费。

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

LinkedIn 上找我 Kaggle

参考

[1]“熊猫 1.4.2 文档”,“与 SQL 的比较。”pandas.pydata.org。https://pandas . pydata . org/docs/getting _ started/comparison/comparison _ with _ SQL . html # join(2022 年 7 月 13 日访问)

[2]“pandas 1 . 4 . 2 文档”,“pandas . data frame . merge .”pandas.pydata.org。https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.merge.html(2022 年 7 月 13 日访问)

如何测试你的人工智能系统

原文:https://towardsdatascience.com/how-to-mess-up-testing-your-ai-system-36d97ec56fe7

避免典型的数据科学新手错误

当与机器学习(ML)人工智能(AI) 一起工作时,保持头脑清醒的一个好方法是像老师一样思考。毕竟, ML/AI 的重点是你让你的(机器)学生通过给出例子而不是明确的指令来学习一项任务

正如任何老师都会提醒你的:如果你想用例子来教学,例子必须是好的。任务越复杂,你需要的例子就越多。如果你想相信你的学生已经学会了这个任务,测试必须是好的。

Husniati SalmaUnsplash 上拍摄的照片

如果你想用例子来教学,例子必须是好的。如果你想信任你的学生,测试必须是好的。

这就是为什么测试在 ML/AI 中极其重要,但不幸的是这并不总是容易的。让我们来看看两种使测试变得一团糟的经典方法:一种是初学者的错误,另一种更阴险一些——大多数从业者至少已经上当一次了。

初学者犯的错误

想象一下,我正计划训练一个人工智能图像识别系统来对香蕉的照片以及我的两只猫赫胥黎和特斯拉的照片进行分类。

由于从头开始构建一个图像识别系统需要数千张照片,所以上面七张图像中的每一张都是 10,000 张类似照片的占位符。

我们将把这 70,000 张图像输入到一个人工智能算法中,并训练我们的模型。我们看到了相当不错的培训表现,但是我们的解决方案真的有效吗?

我们不知道,直到我们测试它…所以我们来测试一下吧!

注意到我们选择的 60,000 张测试图片有什么问题吗?

他们看起来非常眼熟,不是吗?也许我们在哪里见过他们?

忽略我们内心的警钟,我们将提交它们而不贴标签,看看我们的系统是否已经学会应用正确的标签。瞧,它以 100% 的准确率执行任务

没有任何测试错误…所以我们没有任何问题,对不对?这个系统是 100%可信的吧?不对!

知道我们的系统是否值得信赖的唯一方法是检查它是否能够应对相关的新情况,而这与我们所做的正好相反。我们只给了它旧的数据。那里有 60,000 个错误!我们应该更清楚地知道不要重复使用我们的训练数据,但因为我们搞砸了我们的测试程序,我们的人工智能解决方案可能只是记住了它的胜利之路。

我们刚刚做的是用人类大学生已经看过的例子来测试他们的机器等价物。我们怎么知道他们没有记住答案?我们没有。像这样的考试绝对没有证据表明我们的学生能够概括并在未来的例子中表现良好……这是机器学习的全部意义,而不是机器通过查找表记忆(你不需要 ML/AI 来做这件事)。

记忆的麻烦在于它只对过去有效,对未来无效。

无论你认为用人类学生已经看过的例子来测试他们是多么愚蠢,机器学生的情况更糟。由于机器学习和人工智能解决方案的复杂性,如果没有原始的、未使用的数据集,很难检测到过度拟合和记忆。计算机对数据有非常好的记忆力——这就是它们的用途。我的电脑已经记住了你现在正在读的文章的每一个字,而你可怜的作者甚至不能在文章发表 5 分钟后再现它。

由于机器学习和人工智能解决方案的复杂性,如果没有原始的、未使用的数据集,很难检测到过度拟合和记忆。

如果你允许的话,计算机当然可以记住它们找到完美解决方案的方法。唉,记忆的麻烦在于它只对过去有效,对未来无效。如果我们只对过去感兴趣,我们就不会使用机器学习。(此处解释。)

由于机器学习和人工智能解决方案的复杂性,如果没有原始的、未使用的数据集,很难检测到过度拟合和记忆。在我的课程中了解更多:http://bit.ly/mfml_049

当你建立机器学习解决方案时,你的目标是你能得到的最忠实和准确的未来模拟器。

这就是为什么一个更好的测试集应该是由系统不可能记住的例子组成的。换句话说,全新的数据。这是对未来数据的更准确的模拟…你的目标是你能得到的最忠实和准确的未来模拟。让我们用 40,000 张新图片进行测试吧!

我们表现如何?

从技术上来说,事情将会变得非常糟糕,因为这个类是少数。在像我们这样不平衡的数据集中,你更有可能看到所有东西都被贴上多数标签的失败。或者随机标签。但是香蕉是一个有趣的词,所以请原谅我。

原来我们的制度就是一堆臭垃圾。提示悲伤的长号!

因为我们使用新数据进行测试,所以系统无法通过过度拟合和记忆来作弊,所以我们能够发现它的真实性能(或缺乏性能)。

揭开我们的零

顺便说一句,0% 准确率作为分数很诡异。一个由 70,000 个可靠的相关训练图像组成的数据集掌握在专家手中,不太可能导致如此糟糕的测试性能。鉴于目前可用的工具,特别是如果你使用云提供商的人工智能解决方案,如谷歌云的 AutoML Vision ,你必须非常努力地尝试才能做得如此糟糕。

在测试数据中获得 0%通常意味着在训练我们的系统时,除了无辜的“我们真的有”no-idea-what-we-being-that-training-our-system 之外,还有一些错误。像 0%这样的精度实际上很难达到。你不太可能遇到这些情况,因为即使是随机猜测也会给你比 0%更好的结果,当你的数据中没有有用的模式时,随机猜测是许多算法默认的。这表明出现了灾难性的错误,至少像输入的测试数据集与训练集的格式或领域不同一样糟糕。比如尝试输入你的纳税申报表的截图,而不是 4 万张猫的照片。

我告诉你这些不是因为你需要知道如何处理 0%类型的结果(检查测试集的源、元数据和模式),而是因为获得比零更好的性能是标准的。这不是你的项目好运的预兆,也不是庆祝你的未孵化小鸡的理由;真正的胜利是一个分数超过了合理的预定基准,通常这个数字至少比随机猜测要好一点。

避免新手的错误

确保你总是在原始的数据上测试,并且从来没有被 ML/AI 系统或者构建它的团队看到过。这就是你如何避免过度拟合的方法,你可以把这种情况想象成学生记住了考试的问题和答案。

总是使用原始数据进行测试。

为了确保您在原始数据上进行测试,周围必须有原始数据。你是怎么得到它的?一种方法是做出坚定的承诺——包括预算和计划!—在未来收集更多数据…这有时说起来容易做起来难。如果你不断有新的数据流入,你应该感到幸运,对于我们这些为拥有面向用户应用的公司工作的人来说,这是一种太容易被视为理所当然的特权;不是每个人都有这样丰富的数据。

照片由 Unsplash 上的 regularguy.eth 修改而来

如果你不能在需要的时候廉价地收集大量数据,那就养成在每个项目开始时解决测试问题的习惯,方法是分割你的数据并将其中一些数据锁起来,直到对你的数据解决方案的性能进行最终统计评估的时候。不幸的是,许多其他方面值得尊敬的公司和团队搬起石头砸了自己的脚,因为他们未能分割数据,然后测试他们的训练数据,推出垃圾系统,并为他们的错误付出高昂的代价。

即使新数据丰富且易于收集,我也不会过分强调组织通过良好的数据访问策略建立健康的数据文化的重要性,因此改善数据科学实践的最佳和最快的快速解决方案之一是让团队中的每个人都了解数据拆分的重要性。

数据领导者不是要求每个新手做正确的事情,而是通过将数据分割设计到您的数据访问策略中,或者更好的是,如果您已经运行了一个具有定制基础架构的大型团队,则设计到您的数据科学工具中,从而使他们不可能做错误的事情。

专家犯的错误

现在我们已经讨论了新手的错误,我们已经准备好处理专家的错误,你可以在本系列的第 2 部分中找到:

https://kozyrkov.medium.com/the-mistake-every-data-scientist-has-made-at-least-once-3479002211b4

感谢阅读!YouTube 课程怎么样?

如果你在这里很开心,并且你正在寻找一个为初学者和专家设计的有趣的应用人工智能课程,这里有一个我为你制作的课程:

在这里欣赏整个课程播放列表:【bit.ly/machinefriend

喜欢作者?与凯西·科兹尔科夫联系

让我们做朋友吧!你可以在 TwitterYouTubeSubstackLinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用表格取得联系。

有兴趣尝试图像分类吗?

从这里开始使用 Google Cloud Vision API 和 AutoML Vision:

https://bit.ly/googlecloudvision

如何缓解 Python 中的内存问题

原文:https://towardsdatascience.com/how-to-mitigate-memory-issues-in-python-c791b2c5ce7e

一个小窍门,可以节省你的时间、精力和成本。

Unsplash 上的 Flipsnack 拍摄的照片

最近,由于 Python 中管理内存的方式,我遇到了一个问题,在内存受限的环境中使用 Pandas 数据帧和 Numpy 数组可能会变得很严重。这个问题让我花了两天时间,而不是预计的两个小时来实现一个标准的数据处理任务。真扫兴!

因为我们所有的时间都是很昂贵的,所以我写下了我的学习,这样将来的我,也许你可以避免这个问题,节省时间,成本和精力。你准备好了吗?我的故事来了。

故事

我必须使用一个 AWS 弹性容器服务 (ECS)任务在云中处理一堆拼花文件。我想:没有比这更简单的了,我将使用 Pandas 依次加载每个文件,应用我的机器学习模型,保存结果,我就完成了。没什么特别的,只是一个基本的数据处理任务。我的代码大致如下:

import pandas as pd

class Processor:
  def run(self, file_names: list[str]) -> None: 
    for file_name in file_names:
      data = pd.read_parquet(file_name)
      result = self._process(data)
      self._save(result)

现在,要在 ECS 上做到这一点,您必须编写一个 docker 文件,并设置一个 ECS 任务,相应的容器将在其中运行。在那里,您必须指定想要使用多少 CPU 和多少内存。显然,你走得越高,它就变得越贵,你给的钱就越多。由于我的每个文件只有几百兆大,我想我可以选择一个小的大小,因此不必在 AWS 上花费太多。所以我选择了两个 CPU 和 8g 内存。对我来说,考虑到我的数据量,这听起来已经有点夸张了。但我想保险起见,并认为现在可能会出错吗?

问题是

因此,我满怀信心地部署了我的容器,并开始了 ECS 任务。第一个文件已成功加载和处理。是啊。第二个文件已成功加载和处理。是的。第三次、第四次和第五次也是如此,但之后…

Container exited with code 137\. Reason was OutOfMemoryError: 
Container killed due to memory usage

斯蒂芬·拉德福德在 Unsplash 上拍摄的照片

什么?我没想到会发生这种事。8 Gb 的内存怎么可能不够处理一个只有几百兆大小的文件?更重要的是,由于每个文件的大小完全相同,为什么这个问题只发生在第六个文件之后,而不是直接发生在第一个文件上?关于 Python 中如何管理内存,肯定有什么地方出错了,或者说是我没有考虑到的地方。

所以,我谷歌了一下 Python 中的内存管理,学习了引用计数和垃圾收集的基础知识。简单来说,引用计数就是计算 python 对象在代码中被主动引用的频率。如果一个对象在任何地方都不再被引用,也就是说,它的引用计数器为零,Python 垃圾收集器可以介入并释放这个对象占用的内存。很好,听起来很琐碎。

无效的解决方案

因此,我认为加强这种行为将解决我的问题,我终于可以完成我的任务。那你做了什么?为了将引用计数器减少到零,我在引用数据的变量上使用了**del** 。为了强制垃圾收集器在那之后立即运行,我显式地使用了来自 gc 模块的**collect**函数。有了这个,我的更新版本大致如下

import pandas as pd
import gc

class Processor:
  def run(self, file_names: list[str]) -> None: 
    for file_name in file_names:
      data = pd.read_parquet(file_name)
      result = self._process(data)
      self._save(result)
      del result
      del data
      gc.collect()

怀着非常高的希望,我部署了这个更新版本,启动了容器,等待处理第六个文件。猜猜发生了什么?由于内存使用,容器被杀死。

妈的,一点进步都没有。很明显,在我最基本的代码中还隐藏着一些我无法影响的东西,它们一直占据着我的内存。

那么我们现在应该做些什么来解决这样一个常见的数据工程问题呢?选择更多的内存并进一步增加杰夫·贝索斯的财富是唯一的出路吗?幸运的是,这个问题的答案是 不是 。有一种方法应该总是有效的,尽管感觉有点粗糙。

工作解决方案

为了确保在一个函数完成后释放内存或其他资源,您所要做的就是在不同的进程中执行该函数。当该进程完成时,操作系统 (OS)释放该进程已经获得的所有资源。这总是独立于底层操作系统工作。需要注意的是,启动一个进程会降低整体性能。

在 Python 的进程中运行函数的一种方式是通过标准的多处理模块。然而,这要求函数及其所有参数都是可选择的。参见这个网站获取可供选择的类型列表。在我的例子中,情况并非如此,因为我想运行一个类的方法,使用默认的 pickle 库是不可选择的。该死的。

幸运的是,有一个名为 loky 的不错的第三方库,它使用了引擎盖下的 cloudpickle 模块,几乎可以腌制任何东西。太好了!

有了这些,我的最终解决方案看起来像

import pandas as pd
import gc
from loky import get_reusable_executor
# I only need one workere as I don't want to do multiprocessing
executor = get_reusable_executor(max_workers=1)

class Processor:
  def _execute(self, file_name:str) -> None:
    data = pd.read_parquet(file_name)
    result = self._process(data)
    self._save(result)

  def run(self, file_names: list[str]) -> None: 
    for file_name in file_names:
      executor.submit(self._execute, file_name).result() 

这里你可以看到我已经为 循环拉出了的内部部分,在这里数据被加载、处理并存储到一个单独的函数中。这个函数我现在使用 loky executor 在一个专用的进程中运行这个函数,它确保了一旦完成就释放内存。这样,我的任务成功地处理了所有文件,我甚至能够进一步减少所需的内存量。最后,

照片由雷·轩尼诗Unsplash 上拍摄

包裹

在我的短文中,我谈到了 Python 应用程序中没有释放内存的问题。在像 AWS ECS 这样内存受限的环境中运行时,这个问题可能会很严重。通过将一个函数的执行放在一个专用的进程中,您可以确保在函数完成时释放内存等资源。希望,这对你以后有所帮助。

感谢您关注这篇文章。一如既往,如果有任何问题、意见或建议,请随时联系我或关注我,无论是在 Medium 还是通过 LinkedIn

如何使用 Python 和 AssemblyAI 调节音频数据

原文:https://towardsdatascience.com/how-to-moderate-audio-data-using-python-and-assemblyai-a5eab9910730

一个超越转录的特征

杰森·罗斯韦尔在 Unsplash 上的照片

在我之前的博客文章中,我浏览了 AssemblyAI API,涵盖了它的一些有趣特性,并展示了如何将其嵌入到 Streamlit 应用程序中,以便转录 Youtube 视频并自动检测其中的关键时刻(感兴趣吗?代码可在 Github 上获得。

如果你不熟悉 AssemblyAI,我鼓励你看看这篇文章。

但用几句话概括一下,AssemblyAI 是一个最先进的语音到文本 API,它不仅转录音频文件,还提供人工智能驱动的算法来理解转录本并从中获得洞察力。

在本帖中,我们将把音频内容调节作为这些人工智能支持的功能之一。**

我们会明白适度意味着什么,以及为什么它对互联网公司真的很重要。然后,我们将看到 AssemblyAI 如何从音频的角度解决这个问题:我们将检查代码,并一如既往地将其应用于特定的用例。

事不宜迟,让我们开始吧!🏊

内容适度—为什么很重要?

随着互联网不断增加用户生成的内容,如脸书帖子、Youtube 视频、抖音短片等,控制和调节这些数据的需求对于保护用户变得至关重要。

内容审核是每个平台都要处理的一项严肃任务,有时还会遇到困难:从检测 Youtube 视频中的色情内容,到检测 Twitter 上的仇恨言论,再到发现论坛中的脏话。

但内容审核可能更加微妙,因此可能适用于其他环境:确保视频在政治上中立,删除儿童节目中的酒精或赌博等敏感话题,监管教育平台的内容,评估客户和公司之间的互动,检测广告,显然还有更多。

如果你管理一个内容平台,无论是社交网络、儿童教育网站、企业论坛还是客户支持渠道,你都可能希望以某种形式使用内容审核。

如果您希望调节的数据是音频或视频格式,AssemblyAI 可以帮助您解决这个问题。

AssemblyAI 如何处理内容审核?

如果您想使用内容审核特性,您必须将 **content_safety**参数添加到 POST 请求的头中,并将其值设置为**True**。不要担心,我们将在下面的代码部分介绍这一点。

将此标志设置为**True**将告诉 API 检查是否提到了以下一些话题。

作者截图

该列表实际上更长,甚至包括以下主题:

  • 恐怖主义和武器
  • 敏感的社会问题
  • 亵渎
  • NSFW 内容

当 AssemblyAI 在音频文件中发现其中一个主题时,它会赋予它一个置信度得分严重性得分,以及原始文件中相应的时间戳。

这里有一个例子:

  • 一个置信度得分是一个介于 0 和 1 之间的浮点数。它表示算法在检测给定对象时的置信度。可以解释为概率得分。高置信度表示该算法对其预测非常有把握。
  • 严重性分数也是一个介于 0 和 1 之间的浮点数。反映出讨论的话题有多严肃和激烈。例如,自行车撞车和飓风都是事故,但前者远没有后者严重。

内容适度和严重性分数的实际使用案例

如果你关注美国和世界最近发生的事情,你可能已经注意到仇恨言论和仇恨犯罪充斥着新闻。

由于已经创建了许多 Youtube 内容来讨论这一全球性问题,我认为挑选一个视频示例并通过 AssemblyAI 来检查内容审核算法的行为会很有趣。

在这篇文章中,我决定分析下面这个视频,在这个视频中,青少年分享了他们在互联网上被仇恨言论和骚扰的经历。

AssemblyAI 可能会很容易地用仇恨言论标记这个视频。

但是它赋予每个标记部分的严重性分数是多少呢?它提供了一些见解吗?

这就是有趣的地方。让我们开始吧。

如果你想重现下面的步骤,你需要一个 AssemblyAI 账户。无需输入信用卡,您可以免费创建一个https://app.assemblyai.com/signup

我将把这一节分成几个小部分,这样您就可以理解并轻松地重新运行代码。

👉从 Youtube 视频下载音频

我们首先从下载 Youtube 视频的音频文件开始。我们可以通过编程的方式做到这一点,所以没有必要去网上使用一些可疑的网站。

你可以通过安装 Pytube 包非常容易地做到这一点。

***pip install git+**[**https://github.com/baxterisme/pytube**](https://github.com/baxterisme/pytube)*

接下来你要做的就是导入Youtube类,给它传递视频的 URL,提取音频流并通过提供输出文件夹调用下载方法。

如果您运行这个脚本,您将得到以下输出:

作者截图

👉上传音频文件到 AssemblyAI

在转录之前,AssemblyAI 需要通过 URL 访问音频文件。我们可以上传我们在 S3 的文件并提供一个链接,但是为了这个教程,我们将直接上传文件到 AssemblyAI 服务器。

为了能够上传一个音频文件到 AssemblyAI,我们需要使用 API 密匙。

但是首先,让我们把它从代码中隐藏起来,放在一个.env文件中。

***API_KEY=<YOUR API KEY GOES HERE>***

然后我们将使用**python-dotenv**包将其作为环境变量加载。

***pip install python-dotenv***

现在,要上传一个文件,推荐的方法是首先将它分成每个 5MB 的块,并将这些块放入一个生成器中,我们将这些块作为数据负载传递给查询:这就是下面的脚本所做的。

**read_file** 函数负责分割文件,**upload**函数负责发送 POST 请求。

如果您运行此代码,您将获得上传 URL。

作者截图

👉提交转录作业

一旦获得上传 URL,就可以用它向 AssemblyAI 提交转录作业。

激活内容审核发生在这一步。

为此,您必须将**content_safety**参数设置为**True**,并将其作为 JSON 有效负载传递给查询。

提交作业后,它将通过一个队列,您将获得一个重新传输 id。

您不会立即得到结果,因为转录是一个 异步任务。

作者截图

👉获取转录

一旦转录完成(您可以随时从界面检查处理队列),您可以使用转录 id 并获取结果。

这是一个稍微不同的端点上的简单 GET 请求。

如果您运行这段代码,您将获得以下 JSON 输出——您可以查看 AssemblyAI 文档来了解这些字段。

这是输出文本。你可以自己查一下:转录质量惊人。

现在,如果你仔细观察,你会注意到一个**content_safety_labels**键,它包括视频中被标记为hate_speech的不同部分。

每个部分都由相应的文本、分类标签以及置信度和严重性分数来表示。

👉解释严重性分数

我并不惊讶 AssemblyAI 在整个文本中发现了仇恨言论。这显然是视频的中心话题。

然而,我发现有趣的是严重性分数。让我们来看看。

下面是音频中被标记为高严重性分数的部分:

这是另一个被标记为低严重性分数的问题。

在两个片段中,置信度得分都很高。

但是,由于讨论主题的方式不同,严重性分数也不同。

  • 第一部分(高度严重)分享了一些青少年在网上面临反犹太主义和仇恨言论时的痛苦和苦难的戏剧性个人经历。
  • 第二部分(低严重性)更加中性。发言的少年给出了他所看到的仇恨言论的正式定义。

严重性分数是一个有趣的指标,您可以使用它来确定您希望分析和管理的部分的优先级。它帮助你放大关键的部分,丢弃那些更中性的部分。

如果你想玩代码,可以在 Github 上找到。

参考资料:

感谢阅读🙏

如果您已经做到这一步,我想感谢您的时间,并希望我已经阐明了 AssemblyAI 的内容审核特性。

您可以在不同的上下文中使用内容审核来管理数据,也可以通过将它用作主题建模工具来重新调整它的用途。

今天就这些了。下次见!👋

新到中?您可以每月订阅 5 美元,并解锁各种主题的无限文章(技术、设计、创业……)。您可以通过点击我的推荐链接来支持我

*https://ahmedbesbes.medium.com/membership

Unsplash 上的 Karsten Winegeart 拍摄*

如何大规模监控数据湖的健康状况

原文:https://towardsdatascience.com/how-to-monitor-data-lake-health-status-at-scale-d0eb058c85aa

配套的 GitHub 库:【Spark 手把手的远大前程

带着巨大的期望和火花构建数据质量工作流

马库斯·温克勒Unsplash 上拍摄

介绍

Mediaset ,数据湖是每个想要获得一些公司见解或激活数据的人日常使用的基本工具。

根据定义,数据湖是"一个集中的存储库,可以存储任何规模的所有结构化和非结构化数据。您可以本地存储来自源的数据,而不必在运行时转换它们。这允许您保留大量的原始数据,您可以在以后使用不同类型的分析来激活这些数据。

访问数据湖的 Mediaset 员工数量正在上升,随着数据湖的增长,我们接收和保存的产品和数据的数量也在增加。随着用户和归档数据量的增加,管理数据湖的复杂性也在增加。

这是一个关键点,事实上,如果没有实现数据质量和数据治理系统,数据湖可能会变成一个数据沼泽:一个没有组织和精确元数据的数据存储,以使检索变得容易 " ( Integrate.io )。

数据沼泽可能会很快出现,并给希望实施高级分析解决方案的数据驱动型公司带来问题。如果对数据进行严密管理,并执行持续的数据健康状态检查,Data Lake 有可能为公司提供一个准确的、改变游戏规则的业务洞察工具。

全面控制数据湖中的持久数据,并知道会从数据湖中得到什么,以防止它变成数据沼泽,变得越来越重要和相关。

为此,我们实施了数据质量工作流,以支持不同的业务部门完成数据验证的高要求任务,跟踪数据运行状况、漂移和异常情况。这有助于人们不断评估摄取的和转换的数据,增强数据的可靠性和数据驱动产品的总体质量。

该工作流是围绕开源框架 [Great Expectations](http://helps data teams eliminate pipeline debt, through data testing, documentation) (GE)构建的,该框架将自己定义为“一个共享的、开放的数据质量标准,帮助数据团队始终知道对新数据有什么期望。“GE 是一个 python 包,它使我们能够编写测试并评估数据质量。它的简单性和可定制性允许我们轻松地将其与 ETL 管道集成,以验证我们从输入和输出数据中期望的得到满足。

在本文中,我们介绍了 Mediaset 的数据质量工作流的体系结构。我们列出了促使我们构建它的关键点以及整个涉及的技术堆栈。

Mediaset 的数据湖:一个实际的用例

Mediaset 是意大利和西班牙领先的私营电视出版商,是真正的观众领导者,拥有五个公共网络和 30 多个免费和付费主题频道。

每天,数百万人观看视频点播和直播,阅读文章,收听 Mediaset 服务提供的广播节目。人们通过不同的设备与媒体集属性进行交互:智能手机、网络浏览器、智能电视和互联网电视。所有这些视频浏览量、页面浏览量和点击量都来自 Mediaset 系统,以了解我们的客户(那些接受简介的客户)喜欢看、读和听什么,并提高产品的总体质量。

在过去几年中,Mediaset 决定投入资源设计和构建一个数据湖,以存储用户通过公司提供的几个平台和服务与其设备进行交互时产生的所有数据。

为了勾勒出 Mediaset 工作的总体环境和数量级,我们提供了由Mediaset Business Digital(MBD)提供的摘要信息,该业务部门负责客户开发、数据接收和第一层数据转换的提供:

  • 媒体集数据湖每天存储约 100 千兆字节的客户端生成的原生数据及其与媒体集属性和平台(流媒体平台、新闻网站、博客和电台)的交互;
  • 获取几种类型的数据:点击流、页面浏览量、视频浏览量、视频播放器互动、营销活动结果、服务台票证、社交媒体反馈等等;
  • 数据湖存储从客户端获取的原始数据和 ETL 管道的输出,由业务和数据分析师用于数据探索任务,由数据科学家用于机器学习模型训练;
  • 从第一天起,当一个新的平台、服务或资产出现时,数据就存储在数据湖中,以后当业务需求精确时再激活它们。

大数据,大责任

随着数据湖的发展,存储数据量的增加,以及每天查询和激活数据的人数的增加,控制数据湖健康状态的必要性开始出现。

更具体地说,遇到的临界点有四个:

  1. 验证已发布的客户端(移动应用程序、智能电视应用程序和网站)正在正确跟踪所有事件(点击、查看和操作),因此存储在数据湖中的所有数据都是正确和可信的。否则,必须将任何发现的问题通知开发团队,以便尽快解决。
  2. 扩展 ETL 管道单元测试,检查实现的转换是否返回您期望的输出。
  3. 监控所有管道或所有服务是否启动并运行,跟踪每天的数据量变化。
  4. 检测机器学习模型中涉及的数据集中的数据漂移或数据退化,防止错误预测或误导性预测。

这些要点促使 Mediaset 业务数字部门开发了一个能够监控数据湖健康状态的数据质量工作流程。

这个过程中涉及的主要工具是 Great Expectations (GE),它提供了采用 Spark 作为执行引擎的可能性,非常适合当前的 Mediaset 数据堆栈。GE 也是一个开源项目,拥有巨大的社区支持,被设计成可扩展和完全可定制的。

数据质量工作流概述

注意:这不是一个“远大前程简介”教程,而是我们实现的监控数据湖健康状态的架构的概述,以及我们如何使用 GE 来完成这项任务。

该工作流已经开发并与基于 Amazon Web Services (AWS)的当前媒体集数据堆栈集成。涉及的主要服务有:

  • 亚马逊 S3:“一种对象存储服务,提供业界领先的可扩展性、数据可用性、安全性和性能”(AWS))。这是中央数据湖存储器,所有接收和转换的数据都存储在这里。
  • AWS Glue Data Catalog:“提供了跨多种数据源和数据格式的统一元数据库。它提供了与亚马逊 S3、亚马逊雅典娜和亚马逊 EMR 的开箱即用集成”( AWS )。
  • 亚马逊 EMR:“一个托管集群平台,简化在 AWS 上运行大数据框架,如 Apache Spark,以处理和分析海量数据”( AWS )。Amazon EMR 代表了 MBD 单元所采用的 ETL 工作的领先 AWS 服务;这与作为数据协调器的 Airflow 相结合,使我们能够开发和安排日常转换例程。
  • 亚马逊 Athena: “一种交互式查询服务,可以使用标准 SQL 轻松分析存储在亚马逊 S3 的数据”( AWS )。

数据质量工作流架构(图片由作者提供)

实施的数据质量工作流程(参见上述架构)包括五个步骤。

1。数据质量套件开发

一切都从这里开始,从本地开发环境开始,这允许你开发 GE 称之为 的期望套件 ,一组规则(期望)描述你对数据集的期望。该环境由一个 Docker 映像组成,该映像运行一个带有 PySpark 的 Jupyter notebook 实例和您需要的所有 python 包。一旦您获得了想要评估的数据子集(原始数据或经过处理的数据),您就可以在笔记本上编写数据必须满足的所有期望,并以 JSON 文件的形式生成期望套件。

基于 docker 的开发环境也在定制期望开发期间支持你;您可以使用 Docker 映像作为远程 python 解释器,在您最喜欢的 IDE 中对所有期望进行编码和测试。

开发定制期望的可能性代表了 GE 为我们的工作流程提供的最重要的特征之一。这些类型的期望确实允许我们测试甚至是最复杂的多列条件,给予细致的数据验证。

奖金:检查仓库中三个定制期望类型的代码:单列、对列和多列。它还包括单元测试以及使用 PyCharm 使用所提供的 Docker 映像运行它们的步骤。

2。套件部署

一旦套件准备就绪(文档化和测试),提交到 git 存储库的主分支将触发一个持续集成管道,该管道将编译好的期望套件和所有定制的期望 python 模块复制到一个 S3 桶中。CI 管道还负责生成最新的 GE 数据文档,并将其存储在专用的 S3 存储桶中。

3。数据验证运行

是时候真正评估这些数据有多好了。如上所述,我们采用 Airflow 作为数据编排器,其中我们实现了几个数据质量 Dag。详细来说,对于原始数据,我们有专门运行验证作业的专用 DAG(这种 DAG 涉及的OperatorsSensors的顺序见下图);

验证原始数据质量的气流 DAG 结构(图片由作者提供)

处理数据时,我们将验证气流任务附加到转换任务(见下图)以使整个处理层保持一致:如果转换生成质量较差的数据,我们会收到警报,以便我们可以中断所有后续任务(见步骤 4)。

验证处理数据质量的气流 DAG 结构(图片由作者提供)

验证作业获取先前开发和部署的期望套件和定制期望作为输入。数据验证输出是一个 JSON 文件,在 S3 上以原始格式存储后,通过气流PythonOperator进行解析,并作为分区的拼花文件保存在数据湖中。最后,AWS Glue 数据目录中的元数据用新的分区进行了更新,使得数据质量验证结果可以用 Amazon Athena 进行查询。

额外收获:在配套的资源库中,你可以找到一个现成的“验证你的数据”作业,你可以快速运行它来模拟我们在这一步用 Amazon EMR 实现的东西(即 Docker 容器运行一个spark-submit命令来执行数据验证 python 模块)。

4。数据验证结果分析

我们决定将 Apache 超集集成到数据质量工作流中,以探索验证结果,并使其可视化尽可能有影响力。Superset 是一个开源的数据探索和可视化平台,能够连接到现代数据库(包括 Amazon Athena),易于掌握,内置丰富的可视化情节。由于其简单性,超集使我们能够专注于核心任务,例如设计定制指标和通过交互式仪表板可视化见解来评估我们的数据质量,而不是工具本身(参见下面的截图以获得样本超集数据质量仪表板)。

用于评估数据的指标示例如下:

  • 数据量
  • 不成功的期望百分比
  • 至少有一个不成功预期的所有列的列表
  • 每列的错误记录的百分比
  • 第一个 n 预期不成功的每列的意外值。

超集最后提供了两个对工作流有用的关键特性:

  • 警报 在达到 SQL 条件时被触发,发送一个关于 Slack 的通知或电子邮件。您可以为您想要监控的 KPI 设置阈值(,例如,“今天和昨天运行之间的不成功预期数的变化必须低于 10%”,,当条件不满足时,将发送通知警报。
  • 报告 按计划发送,允许您分析与上周相关的验证结果,以更有条理、更清晰的方式传达结果。

“超集数据质量仪表板”的示例—仪表板由以下部分组成:a) 左上角的数据量直方图,按媒体集属性分组;b)在右上角的环形图上,显示每个媒体集属性的不成功预期数;c)对于每个数据集列,列出不成功的期望、用于评估被检查列的补充列(在多列期望的情况下)以及有问题的属性的数量的表格;d)折线图,按属性分组,显示所选列的每日(上个月)不成功记录的百分比-期望值。(图片由作者提供)

5。数据文件

该工作流程的最后一步是发布数据文档网站,该网站之前由 Great Expectations 通过 CI pipeline 触发器生成。Data Docs 包含属于每一列的所有期望的完整列表,以及由表和套件组织的已实现规则的描述。除了为每个期望套件提供文档外,【Great Expectations Data Docs 还允许我们与非技术人员分享为每个表开发的检查,从而更容易讨论可能的和未来的套件增强。

结论

在本文中,我们向您展示了基于 Great Expectations 实现的工作流,它赋予 Mediaset 持续监控数据湖健康状态的能力。这防止了数据湖变成数据沼泽,保持了数据的高可靠性,提高了所有涉及数据的项目的质量。

一旦部署了数据质量工作流程,不同 Mediaset 业务部门的开发人员只需专注于 Expectation Suites 开发和(显然是)数据质量警报和报告分析。

本地开发环境为所有业务单元提供了一个舒适的地方来开发它们的套件,因此,在监视它们权限内的数据时是独立的。每个业务单位都能够拒绝自己的需求,并通过本地和定制的期望使它们达到更高的期望。

开发环境结合了云的能力和弹性,以及 EMR 等服务,允许在任何规模上应用期望,包括原始数据和处理后的数据,主动监控我们每天摄取并保存在我们心爱的数据湖中的内容。在这种情况下,EMR 集群的成本将取决于您想要评估的数据集的大小、套件中包含的预期数量以及已经实现的自定义预期的复杂性。

套件中所有控件的组织-每表,以及数据文档的自动生成,为所有用户提供了一种简单的方式来检查期望套件所覆盖的表的列表,并查阅为每一列实现的逻辑。

最后,可视化工具允许数据验证结果分析民主化,使得那些希望在使用数据之前对表或数据湖进行状态检查的非技术人员也可以访问这些结果。

感谢您阅读我们的作品!
如果您有问题或反馈,请随时给我发送连接

承认

感谢来自 Mediaset 的 NicolaDanieleFabio 、来自 Coveo 的 Jacopo 和来自 Tecton 的 Danny 对本文和 Github 资源库的评论和建议。

参考

如何在 Python 中规范化数据

原文:https://towardsdatascience.com/how-to-normalize-data-in-python-bfde370ca4b6

在本文中,我们将探索如何在 Python 中规范化数据

Marcin JozwiakUnsplash 上拍摄的照片

目录

  • 介绍
  • 什么是正常化
  • 标准化示例
  • 如何在 Python 中规范化数据
  • 结论

介绍

许多机器学习模型的特征工程的第一步是确保数据被适当地缩放。

一些模型,如线性回归、KNN 和 SVM,会受到不同比例要素的严重影响。

而诸如决策树、bagging 和 boosting 算法之类的其他算法通常不需要任何数据缩放。

特征比例对上述模型的影响程度较高,并且具有较大范围值的特征将在算法决策中发挥更大的作用,因为它们产生的影响对输出具有更大的影响。

在这种情况下,我们转向特征缩放,以帮助我们找到所有这些特征的共同水平,以便在训练模型时平等地评估。

两种最流行的特征缩放技术是:

  1. Z 分数标准化
  2. 最小-最大归一化

在本文中,我们将讨论如何使用 Python 执行数据的最小-最大规范化。

为了继续学习本教程,我们需要以下两个 Python 库:sklearn 和 pandas。

如果您没有安装它们,请打开“命令提示符”(在 Windows 上)并使用以下代码安装它们:

pip install sklearn
pip install pandas

什么是正常化

在统计学和机器学习中,数据的最小-最大归一化是将原始数据范围转换为 0 到 1 之间的范围的过程。

产生的归一化值代表 0-1 范围内的原始数据。

这将允许我们一起比较多个特征,并获得更多相关信息,因为现在所有数据将处于相同的比例。

在最小-最大归一化中,对于每个要素,其最小值被转换为 0,最大值被转换为 1。基于相对于要素的最小值和最大值的原始值,介于两者之间的所有值都被缩放到 0-1 范围内。

假设你有一个数字数组 A = [v_1,v_2,…,v_i]

我们先来求数组的最小值和最大值: min(A)max(A)

然后,使用最小值和最大值,我们将使用以下公式将每个原始值 v_i 转换为最小-最大归一化值v’_ I:

图像由

标准化示例

在这一节中,我们将看一个简单的数据规范化的例子。

考虑以下具有不同苹果价格的数据集:

作者图片

绘制数据集应该是这样的:

作者图片

在这里,我们看到重量与价格相比有更大的变化,但看起来是这样,因为数据的不同尺度。

价格范围在 2 美元到 5 美元之间,而重量范围在 250 克到 800 克之间。

让我们将这些数据正常化!

从重量特征开始:

作者图片

并对价格功能进行同样的操作:

作者图片

并将这两个特征组合成一个数据集:

作者图片

我们现在可以看到,数据集中要素的比例非常相似,并且在可视化数据时,点之间的分布会更小:

作者图片

该图看起来几乎相同,唯一的区别是每个轴的比例。

现在让我们看看如何使用 Python 重现这个例子!

如何在 Python 中规范化数据

让我们首先创建一个我们在上面的例子中使用的数据帧:

您应该得到:

 weight  price
0     300      3
1     250      2
2     800      5

一旦我们准备好数据,我们就可以使用 MinMaxScaler() 类及其方法(来自 sklearn 库)来规范化数据:

您应该得到:

[[0.09090909 0.33333333]
 [0\.         0\.        ]
 [1\.         1\.        ]]

如您所见,上面的代码返回了一个数组,所以最后一步是将其转换为 dataframe:

您应该得到:

 weight     price
0  0.090909  0.333333
1  0.000000  0.000000
2  1.000000  1.000000

这与我们手动计算的示例中的结果相同。

结论

在本教程中,我们讨论了如何在 Python 中规范化数据。

数据标准化是许多机器学习算法中数据预处理的重要步骤。

这通常是一个必需的预处理步骤,用于缩放输入数据中要素的范围,以确保范围较大的要素不会通过影响距离度量来消除模型的所有可解释性。

是否对数据进行规范化的决定主要取决于您正在构建的模型,因为有些模型很容易受到数据范围的影响(OLS、SVM 等),而有些模型则不受影响(逻辑回归、基于树的模型等)。

如果你有任何问题或对一些编辑有建议,请随时在下面留下评论,并查看更多我的机器学习文章。

原载于 2022 年 5 月 5 日 https://pyshark.com**的

如何(不)让一个机器学习项目失败

原文:https://towardsdatascience.com/how-to-not-fail-a-machine-learning-project-bc35a473ee1e

在一万次实验后得到的教训

四个月是很长的时间。但是,十个月也是如此。一般来说,四周以后的事情都是将来的事情。这种情况对于机器学习项目来说可能是福也可能是祸。幸事,因为我们有充足的时间来完成这个项目。这是一个诅咒,因为我们还没有开始(或继续工作)。

编辑#1 (Mai 2022):在为单个项目运行了一万多个实验之后,我已经包含了更多的经验教训。适应它们,享受更快的进步。

编辑# 2(2022 年 6 月):我更新了这篇文章,思考清洁的标签管道如何让生活变得更容易。

斯科特·格雷厄姆Unsplash 上拍照

因此,长期追求项目本身就是一门艺术。谢天谢地,我们很少需要从头开始;在我们之前的人经常已经走了这条路。通过从他们的错误中学习,并改进他们认为有用的东西,我们可以很好地处理令人生畏的项目。因此,第一步是找到需要改进的地方。在这里,芭芭拉·奥克利的数字头脑帮助我养成了列出当天所学课程的习惯。

担心这听起来很老套,通常只有通过我们犯的错误(或只是避免的错误),我们才能在下一次做得更好。但是,带着这种心态,我们不可避免地会发现我们可以改进的地方。在从事机器学习项目半年后,我发现有很多东西需要学习。

为了帮助其他读者和从业者避免我的事故,我现在将介绍我学到的最重要的经验。当然,这并不是说如果你犯了同样的错误,你就会不可避免地失败。此外,如果你设法避开它们,也不会自动成功。相反,通过尽可能多的学习,看看什么能与你的经历产生共鸣,你会大大增加成功的机会。

其余的分为两类。第一个,机器学习,列出了与实践实际的 ML 任务相关的经验教训。第二个是 general,列出了适用于任何大型项目的要点。

机器学习

不要过度优化

好代码是好的,更快的好代码更好。但仅限于某一点。在这一点上,花费在优化代码上的额外时间并没有转化为同等增加的回报。很明显,没有硬门槛;这取决于项目。然而,我相信许多从业者都熟悉类似的情况。

使用专用的实验跟踪软件

如果您有几个实验,通过记录具体的配置来手动跟踪它们是可行的。然而,这种方法不能很好地扩展。手动跟踪所有实验的结果,除了几十个实验外,没有什么效果。在这里,我推荐使用专用的追踪软件。就我个人而言,我已经使用权重&偏差很长时间了,并开始称赞这个奇妙的用户界面。除了记录结果之外,这样的系统可以被设置来跟踪特定实验的输入。反过来,这些特性使得复制结果变得更加容易。

开始时使用较少的数据集

在《T2:一个没有电子邮件的世界》一书中,卡尔·纽波特介绍了“做得更少但更好”的理念(参见第 215 页和第 227 页)。我们可以将相同的概念用于机器学习项目。当涉及到测试新想法(用于研究)时,我们通常希望尽可能全面地评估它们。虽然这是合理的,但它并不适用于每个阶段。一开始,最好处理好几个核心数据集,而不是勉强支持几十个。在项目持续期间,您可以决定添加额外的数据集。

明确地做 EDA

这是我几年前采用的一个有缺陷的方法。我训练了一个神经网络来分类音频数据。然而,不是检查数据——也就是说,查看标签分布、频率、持续时间等。—我使用了一种更不结构化、更容易出错的方法。我手动实验了不同的超参数,希望能偶然找到一个好的集合。显然,这种试错过程只在极少数情况下有效。相比之下,通过进行探索性数据分析,我们可以在早期获得对数据集的更多见解,并从长期来看节省时间和成本。

考虑将数据复制到 pod

这一点适用于 a)使用 Docker(或任何其他容器管理软件)和 b)有一个缓慢的文件系统的情况。如果这些需求适用于您的情况,您可以考虑在实验之前将数据复制到容器中。但是,您必须平衡复制的额外开销和由此减少的训练时间。中间路线是从文件系统中读取第一个数据迭代,然后将其缓存到临时磁盘(查看由 SSD 或 RAM 支持的 EmptyDir)。

自动化图像构建

这个场景很熟悉:在本地,您已经更改了您的设置,但是这反映在您的容器中了吗?在训练过程中意识到缺少依赖是很烦人的。因此,每次您在本地更新一些包时,让它触发一个映像构建过程。或者,您可以手动启动一个脚本,在没有您监督的情况下在后台执行。

提前确定要跟踪的指标

只有当您事先决定了要根据什么标准来评定特定配置的成功程度时,才可能进行评定。一旦实验开始,就没有太多的选择来改变指标。因此,如果您在开始时花时间仔细评估度量标准并在每次运行时收集它们,这是值得的。为了以后的想法更加安全:存储每个实验的基础事实和预测。有了这些数据,您可以在以后计算其他数据。

保存预测和实际数据

即使在您决定了要跟踪的度量标准之后,您可能仍然会到达这样一个点,这时您会想:拥有这个额外的度量标准会有所帮助。最愚蠢的选择是添加后重启所有实验;这可能会花费您数月的计算时间和数千美元。更好的方法是做好准备,至少将测试数据集上的预测与真实数据保存在一起。然后,一旦您需要进一步了解您的模型的性能,您可以计算它们。您甚至可以更进一步,在训练期间保存预测-背景-事实对(这可能会导致额外的磁盘空间和暂停训练),以更详细地分析训练进度。通过仅捕获子集或以某一频率对数据进行下采样是一个很好的解决方案。

为超参数优化做准备

KerasTuner、Optuna、Weights & Biases、Ray-Tune:为你的问题集寻找最优超参数的工具数量很多。如果你计划在(遥远的)晚些时候做它们,你可以早点做。通常,优化框架通过字典或类似的结构提供下一组参数。因此,如果您将代码设计为从字典中加载超参数,那么更改参数就像传递不同的配置一样简单。尽早考虑这一点可以减少准备框架时的开销。

检查你的训练

2022 年 3 月 11 日,来自世界各地的 900 多名研究人员开始训练世界上最大的开源语言模型。运行在 384 A100 Nvidia GPUs 上,训练估计需要三个月甚至更长时间(你可以在这里跟踪进度)。在如此高的风险下,如果培训因为任何原因失败,那么将会付出异常高昂的代价。因此,定期检查训练状态以避免失去进展是很重要的。这就是相关工程师所做的,即使经常进行检查点检查,也总是有硬件故障的可能性。当然,失去七个小时的进度会很痛苦,但这比重新开始要好得多。

有一小部分

杰瑞米·霍华德和瑞秋·托马斯(Rachel Thomas)创立了机器学习研究公司 fast.ai,让每个人都可以使用神经网络。与此相关的是,Howard 还提供了 ImageNet 数据集,这是极其庞大的 ImageNet 数据集的一个可管理的子集。这个数据集,ImageNet,在过去的几年里可能受到了最多的关注。原因有二。第一个原因是它作为一个具有挑战性的基准的地位,由每年的比赛推动。第二个原因是庞大的规模。这个数据集在磁盘上占用超过 250 GB,通常需要快速加速器来在合理的时间内处理数据集。这就是上面提到的 Imagenette 发挥作用的地方。拥有一个小的子集可以让你更快地评估新的想法。

简化并行化

如果幸运的话,您可以使用不止一个加速器,那么提前为并行化准备好代码就成为了一种潜在的方法。在 TensorFlow 中,通过将所有创建变量的例程包装到一个策略对象中来实现这一点。这在目前会稍微多花些精力,但是从长远来看,会使你的代码分发更加容易。换句话说,如果您提前知道将会有更多的加速器可用,那么为并行化做准备是值得的。

使用显著性测试

我们假设以下情况。您已经试验了两种配置,现在比较结果。第一次运行达到了 75%的准确率,而第二次运行达到了 79%。查看此指标只能表明第二种配置更好。然而,问题是,它真的更好吗,还是只是运气好?我们可以通过运行显著性测试来研究这个案例。在这里,你比较两个想法。想法一是没有区别,想法二说有区别(为了我们的目的:不指明方向)。我们现在可以使用各种测试来详细检查这些假设,并最终得出结论,我们的实验之间的差异在统计上是相关的。我推荐 Statology 网站,那里有大量与数据分析相关的动手教程。

检查回归

2 月 23 日,我在 UrbanSound8K 数据集上训练了一个 ResNet152。该数据集被分成 10 个折叠,一个折叠花费了 100 个训练时期的大约 30 分钟。总的来说,对完整数据集的训练花费了 300 分钟或 5 个小时。两个月后,一个纪元花了 15 分钟。

发生了什么事?事实证明,这种情况是一种倒退。观察二月份的实验,我注意到验证分数大大低于训练分数。为了减少这种差异,当时,我决定添加音频增强。因为我之前曾经使用过音频库库(甚至构建了一个 GUI 来可视化转换),所以我再次依赖于它的特性。这个库提供了几种与音频相关的变换,如音高移位或时移。添加这个功能后,我检查了验证分数是否增加了。看到情况确实如此,我把注意力放在了其他任务上。

然而,正如我在两个月后发现的那样,并且正如文档中清楚描述的那样,转换在 CPU 上运行,并且当时只在单个样本上运行。这个细节被证明是一个巨大的瓶颈,特别是考虑到相当大的 UrbanSound8K 数据集。因此,长话短说,我决定在 pure TensorFlow 中重新实现关键的增强,并让它们处理批量数据。这些修改将单个历元减少到大约 30 秒。所以这次旅行的寓意是:a)检查整个数据管道,b)不要盲目地添加很酷的东西。

监控您的数据管道

去年,我有机会读了凯瑟琳·尼尔森和汉尼斯·哈普克的《构建机器学习管道》。在他们高度实用(且相关)的书中,他们涵盖了建立自动化模型部署管道的过程。尽管他们使用 TensorFlow 扩展库作为核心管道工具,但他们的想法和技巧并不局限于这个框架。该信息是与机器学习项目相关的点,也适用于任何 ML 数据管道。例如,一个小的形状误差或标准化操作可能会造成严重后果。此外,正如前一点所言,任何进一步的转变都会影响管道的速度。因此,定期检查管道的吞吐量是有好处的,至少在添加了关键操作(如扩充)之后。

有一个干净和批准的标签过程

数据是我们训练模型的核心。如果我们幸运的话,我们的数据集可能是高质量的,并且对于分类或类似的任务特别重要,已经被标记了。如果不是这样,那么我们经常不得不从头开始设计一个标签管道或者修改现有的代码。在这两种情况下,有一个干净的和批准的管道是很重要的。我说的干净认可是什么意思?首先,对我们来说,干净是复杂、混乱的反义词。我们必须避免编写分散在多个文件中并且难以理解的代码。理想情况下,管道是完全自动化的,只需要很少的人工干预。这就引出了第二点,认可。管道可以非常快速地创建,但是它的质量才是最重要的。如果我们的标签过程有问题,我们使用的数据可能会造成伤害。我们可以通过与同事和主题专家讨论我们的管道来防止这种情况并提高质量。与他们交流有助于我们纠正错误,并导致一个更全面的、可接受的管道。

一般

不要陷入完美主义

通常,我们会沉浸在当下。另一个改进的想法突然出现在我们的脑海中,在我们注意到之前,我们已经花了一个小时深入代码库。尽管这听起来很好,但请将这些适时的步骤保持到最后。尤其是在开始的时候,专注于构建核心。

首先实现核心功能

在一个项目的开始,你有这个真的长的(假想的)待办事项清单。这种情况可能会让人不知所措,导致我们不按特定的顺序实现特性。这种方法当然是不可持续的;结果往往取决于几个核心特性。所以还是先把重点放在这些上,以后再进一步补充比较好。

记录你的经验教训

很可能,这个项目不会是你的最后一个。这很好!不太好的是重蹈覆辙。为了下次做得更好一点,记下学到的教训会有所帮助。为每个项目准备一张纸,当你意识到有些事情本可以变得更容易时,添加一个条目。你浓缩了你的经验,下次就有了一个定制的、倒排的入门清单。

更多的时间不一定有帮助

番茄工作法的发明强调了一个事实:如果时间有限,我们可以像放松约束时一样高效。机器学习领域不是离群值。只允许固定的时间去创造价值会让你自己承受交付的压力。令人惊讶的是,在短短 25 分钟内完成项目,然后休息 5 分钟,可以提高工作效率。尝试这种方法,这是我从对数字的头脑中得到的,看看你能在哪里应用它。

实践不收尾的艺术

让我们考虑以下情况:你训练一个神经网络来分类花的图像。仔细观察准确度分数,您会发现有改进的空间,因此您开始选择另一个优化器并增加批量大小。与此同时,你的同事发现,对植物进行分类可以完全跳过;你决定使用预先训练好的网络。但是完美主义现在控制了你。在您放弃(现在已经过时的)任务之前,您想要证明您可以达到出色的测试结果。最后,你可能会对一个不再存在的问题有一个很好的解决方案。对于参与的每一方来说,这都不是一个令人满意的局面。所以,坚持完成过时的任务。

坚持今天的任务清单

这个是短的。一般来说,避免迷失在一个单独的子任务中,而是努力一个接一个地处理待办事项。推荐阅读 Cal Newport 的深度作品(尤其是第 223 页 ff。)了解更多信息。

订购每日任务列表

这是一个简单的技巧。根据任务的重要性排序,你会进步得更快。通过最后处理最不重要的,你将会在主要特性上花费大部分的时间和认知资源。

不要让每天的任务清单超负荷

这需要实验和自我反省来预先粗略评估你在一次工作会议中能处理多少。我经常添加另一个东西,它堆积成很长的列表。在开始的时候,坚持先列出较短的清单,然后随着你的学习不断扩展。从心理学上来说,看到一个明确的待办事项列表的效果是非常令人满意的。相比之下,一天结束时还没有完成的任务会让人失去动力。

定期与共创者交流

爱因斯坦效应(参见数字思维,第 17 页)指出,一旦你达成了一个解决问题的方法,你就会非常倾向于坚持下去,并减少对替代解决方案的关注。我们在日常生活中经历过这种现象,例如当我们寻找钥匙时,疯狂地在我们认为最有可能最快的地方搜索。然而,我们更容易接受其他想法,因为我们不会一时冲动,这有助于推断出钥匙可能就在我们的口袋里。类似的情况也可能出现在你以自我为中心相信你的方法的项目中。虽然停止自己的解决方案需要自信,但获得同行的智慧输入会让你更快地前进。

接受建设性的批评

你很少单独做一个项目,几乎每次你都会受到外界的影响。这种影响不能来自同事,也可以来自视频讲座或博客条目(如本文)。不管是哪种情况,建设性的意见可以推动我们前进,指出我们错过的东西。诚然,让自己的想法受到批评需要自信,但如果这种反馈来自那些已经有过这种经历的人,那么这种反馈的力量将是指数级的。你们都尊重提出想法的人,通过考虑他们的意见并根据自己的问题进行调整,你们会进步得更快。

下班后保护你

作家兼计算机科学教授 Cal Newport 在他的书数字极简主义中建议用高质量的活动来培养一个人的闲暇时间(第 165 页及以下)。这个想法也与机器学习项目有关。在这里,不一定是你投入的原始小时数,而是在加州新港所花费的时间,这种时间被称为深度工作状态。然而,很明显,认知资源是有限的;我们需要时间充电。这种充电最好用手来完成,而不是用大脑。

与其花更多的时间粘在屏幕上,我们应该争取更多的手动操作。这种方法的美妙之处在于,它利用了芭芭拉·奥克利在《数字思维》中描述的分散注意力。当我们不在的时候,似乎没有做任何与项目相关的事情,我们的思想可以漫游并发展创造性的想法。

不要一次追求太多的项目

做这个;那样做;在那里工作:我们(不得不)从同一个领域并行运行的项目越多(也就是说,不是一个来自象棋,另一个来自机器学习),我们就越容易被对我们注意力的持续需求所淹没。在一定程度上,这样的情况可以刺激我们的大脑;我们从不同的角度受益。然而,杂交利润有一个门槛,即当我们开始从一项活动跳到另一项活动时。这种情况干扰了我们和工作之间的距离,因为我们已经在同一领域做下一件事了。为了让我们的大脑有喘息的空间,我们应该限制同时进行的项目数量。

从多个角度解决问题

你被一个具有挑战性的问题困住了吗?尝试在集中思考和分散思考之间交替进行。我从芭芭拉·奥克利的《数字思维》中了解到这一点,该书详细解释了这些模式。要点是,默认情况下,我们只使用(并且通常知道)聚焦的那个。当你全神贯注于一个问题并尝试多种方法时,这种模式是活跃的。然而,我们可能会因为卡住而卡住;它是一个圆。通过进一步集中,我们只是增加了另一个无限循环的迭代。对我们有帮助的是发散思维。在投入大量的密集(精神)工作后,你让学到的见解在你的大脑中来回跳动。这就像打弹球一样(这个类比是芭芭拉·奥克利做的):你付出足够的努力让球滚动起来,让你的大脑缓冲器完成剩下的工作。例如,我们可以通过散步和让我们的思维漫游来激活这种模式。

富有成效,而不是忙碌

生产率正在取得显著进步;忙碌是发明方法来隐藏你的不进步。

使用项目管理工具

在较大的组织中,通常已经有一个规定如何组织项目的过程。如果不是这样,或者你是唯一的成员,考虑使用专用的项目管理软件。起初,学习另一种工具听起来需要更多的工作。然而,那只是暂时的。巧妙组织你的工作可以释放你的认知资源,原因有三:

  1. 您可以在一个地方收集所有与项目相关的数据,无需再疯狂地搜索信息。
  2. 所有(即将到来的)步骤在任何时候都是清晰的,给你方向。
  3. 通过更新整个工具,您可以直观地看到进度。

如果你不喜欢数字工具,你可以使用白板或黑板来复制一般的想法,并手动跟踪你的进度。如果这个话题听起来很有趣,看看吉姆·本森&的个人看板和加州纽波特的一个没有电子邮件的世界(尤其是第五章以后)。

使用 Python 进行数值积分

原文:https://towardsdatascience.com/how-to-numerically-integrate-dynamics-problems-w-python-85d9783aa088

Python 中数值积分方程和可视化结果的简单方法

阿诺·弗朗西斯卡在 Unsplash 上的照片

无论你是工程师、物理学家,还是一个动力学爱好者,你都有可能接触过常微分方程形式的运动方程。对于那些不熟悉的人来说,常微分方程是由一个独立变量的一个或多个函数及其导数组成的方程。在动力学问题中,独立变量通常是时间,或 t ,方程通常与目标质量的位置、速度和加速度相关。

虽然解析求解具有挑战性,而且通常是不可能的,但使用数值方法可以以很高的精度近似求解常微分方程。在计算机时代之前,这是一项艰巨的任务,但我们已经走过了漫长的道路,所以不要担心。现在,大多数编程语言都有可用的 ODE 解算器。通常,他们甚至有不止一个解算器,所以不缺少选项。Python 本身有许多选项可供选择,但是在本演示中我们将集中讨论其中一个。

单摆问题[图片由作者提供]

在整篇文章中,我们将使用单摆作为例子来指导我们完成这个过程。质量 m (见下面的方程)的运动方程相对简单,所以它可以作为一个很好的例子。然而,代码的原理对于所有的运动方程都是一样的,所以你可以用它来解决各种各样的问题。

如果你对这个方程是如何推导出来的感兴趣,请阅读下面的链接。

https://medium.com/@zackfizell10/using-lagrangian-mechanics-to-solve-dynamics-problems-663460cbf94e

在我们深入研究代码之前,最好先了解一下 ode 求解器是如何工作的。在这个特殊的例子中,我们要解决一个初值问题,或者说 IVP。对于 IVP,ODE 求解器从初始时间和初始条件开始(稍后将介绍),逐步通过一个时间间隔,并在每个时间步长计算一个解。这是一个高层次的解释,所以如果你想了解更多,我鼓励你做你的研究。

常微分方程求解器要求我们的运动方程建立为一个一阶微分方程系统。在当前状态下,由于对 ϕ 的二阶时间导数,我们的运动方程是二阶微分方程。为了改变这一点,我们对 y₁y₂ 进行了“变量改变”,将得到两个一阶微分方程。我们的新方程组是:

现在我们有了新的微分方程组,下一步是定义一个起点,或者初始条件。它们采用上述等式中的 y 向量的形式。我们还不需要y’向量;我们稍后会用到它。我们的初始条件通常是起始位置和速度。在我们的例子中,它是我们的初始角度, ϕ ,以及它的角速度。

我们可以任意将角度设置为 15 或π/12 弧度,将角速度设置为 0 弧度每秒(您可以更改这些值,但您的结果将与文章底部的图不同)。我们的 y 向量上的下标 0 表示初始时间。

从代码开始,我们需要从 Python 导入必要的包。NumPy 是一个非常强大的 Python 包,用于科学计算。为了便于调用,我们将其定义为 np 。此外,我们需要来自 SciPy 包的 odeint 函数。这将用于对我们的 ode 进行数值积分。最后,我们需要从 Matplotlib 中包含 Pyplot 来可视化我们解决的系统。和 NumPy 一样,为了方便调用,我们将 Pyplot 定义为 plt

# Importing Packages
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt

接下来,我们需要为 odeint 函数定义几个参数。在我们的代码中,它有三个输入:模型(或者我们新的一阶微分方程,y’向量),初始条件,以及我们想要积分的时间数组。先定义我们的模型函数, model(t,y) 。下面是我们代码中的内容:

  • g =重力常数(9.81 米/秒)
  • l =无质量杆的长度(1 米)
  • y =当前时间步长下我们的角度和角速率的向量(在文章前面定义)
  • dydt =矢量 y 的时间导数(在文章前面有定义)
# Model
def model(y,t):
    g = 9.81
    l = 1 phi = y[0]
    phi_dot = y[1]
    phi_ddot = -g/l*np.sin(phi)
    dydt = [phi_dot, phi_ddot]
    return dydt

我们的 odeint 函数需要的第二项是我们的初始条件。我们已经说明了这些是什么,所以让我们也说明我们感兴趣的时间间隔。假设我们想观察摆的质量在 20 秒内的表现。我们可以使用来自 NumPy ( np )的 linspace 函数来创建一个从 0 到 20 秒的时间点数组。我使用了 1000 的增量来确保我从 ODE 解算器得到一个平滑的输出。使用的增量越多,结果就越精确。在某种程度上,增量的数量不会带来什么好处,所以在未来的项目中使用它时,请使用您的最佳判断。

# Initial Conditions
y0 = [np.pi/12, 0]# Time Array
t = np.linspace(0, 20, 1000)

最后,我们只需要用我们的模型、初始条件和时间数组运行 ODE 求解器。我们应该将它设置为等于另一个变量, sol ,这样我们就可以使用 Pyplot ( plt )来操纵可视化数据。我们可以通过索引 sol 的第一和第二列的整体(例如,对于第一列 sol[:,0]),来提取我们的角度和角速率时间历史。历史是以弧度为单位的,所以为了更好的理解,我们可以把它转换成度数。

# Solving ODE
sol = odeint(model, y0, t)
phi_radians = sol[:, 0]
phidot_radians_s = sol[:, 1]# Converting Radians to Degrees
phi_degrees = phi_radians*180/np.pi
phidot_degrees_s = phidot_radians_s*180/np.pi

为了可视化数据,我们可以使用 plt 来创建我们感兴趣的数据的图表。使用 Pyplot 有很多定制选项,所以如果你不喜欢默认设置,你可以很容易地改变你的线条和绘图的外观。

# Plotting Results
plt.plot(t, phi_degrees)
plt.title('$\Phi$(t)')
plt.xlabel('Time [s]')
plt.ylabel('$\Phi$ [$^o$]')
plt.show()

X = np.sin(phi_radians)
Y = -np.cos(phi_radians)
plt.plot(X, Y)
plt.title('Spatial Motion')
plt.xlabel('X [m]')
plt.ylabel('Y [m]')
plt.axis('equal')
plt.show()

运行完所有代码后,您的绘图应该如下所示:

角度时间历程[图片由作者提供]

钟摆质量的运动[图片由作者提供]

我们的两个图显示了我们的质量如何在选定的时间间隔内移动。第一张图显示了ϕ在我们的时间间隔内是如何演变的。因为我们看到的是一个没有摩擦力的支点,我们期望质量在最大角度的+/-之间振荡,这个角度恰好是我们的起始角度 15 度(因为我们没有初始角速度)。第二个图显示了质量在 20 秒间隔内的轨迹。直觉上,这个运动是有意义的,所以我们可以合理地假设我们的 ODE 求解器和方程设置正确。

这就是这个例子的全部内容。如果你有任何问题,请随时评论。我非常乐意帮忙。如果这以任何方式帮助了你,请给它一个赞并跟随。谢谢大家!

如何通过创建跑步管理器来组织和跟踪您的 PyTorch 培训

原文:https://towardsdatascience.com/how-to-organize-and-track-your-pytorch-training-by-creating-a-run-manager-878cc830ea90

如果您正在寻找一种方法来组织、管理和记录培训过程中的步骤和操作,并且不想使用 PyTorch Lightning,请不要再找了

Marcel strau 在 Unsplash 上拍摄的照片

我们将按照培训设置的经典层次结构,将培训经理的逻辑分为几个阶段:

  • 最高级的阶段是训练运行,它涵盖了一组超参数(时期数、模型配置、学习率、优化器等)的整个训练。)
  • 接下来,我们有时期,这个阶段代表整个数据集通过我们的模型的一次通过
  • 对于每个时期,我们有两个步骤:训练步骤和验证步骤。在训练步骤中,我们通过前向和后向传递执行实际学习,在验证中,我们计算保留样本的选择指标。

作为的额外收获,我还将向您展示一种从可用值列表中生成每个运行参数集的方法(提示:笛卡尔乘积)。

培训过程

首先,让我们定义一个已经使用管理器的培训流程,这样我们就有了一个应该如何使用它的示例,这将有助于我们稍后定义实际功能。

运行管理器

接下来,让我们考虑我们希望我们的管理器收集和记录什么信息,以便我们对运行管理器的样子有一个概念:

  • 我们想知道当前的纪元和运行
  • 每个时期的平均损失
  • 每个时期的精确度(我们可以使用其他指标:F1、精确度、召回率、MSE、MAE 等。)
  • 纪元和运行花了多长时间
  • 把所有事情都记录到 tensorboard 上也不错

对于损失和精度,我们想把它们分开成训练和验证,这样可以更好的了解模型的真实表现。

运行和新纪元的开始

正如我在本文开始时提到的,我们有两个主要循环,外部循环通过创建定义特定运行的集合来遍历所有超参数的组合(我们将立即看到如何生成它们),内部循环遍历多个时期(也是一个潜在的超参数),这是学习发生的部分。

因此,我们需要在新的运行和新的时期开始时通知运行管理器,以便相应地对数据进行分组,并重置基于状态的变量。

奖金

在机器学习模型的训练过程中,一些参数是不可微的,并且在更高的水平上定义学习过程。我们称之为超参数。

通常,没有办法确定它们的最佳价值,所以我们只能全部尝试(免责声明:有一些方法可以改进搜索,但这超出了本文的范围)。

简而言之,我们的任务是从我们为超参数提出的值中生成所有可能的组合,这些组合定义了每次运行。为此,我们将使用 python 的内置 itertools 包中的产品函数:

from **itertools** import **product**h_params = {
    "**lr**": [0.001, 0.0001],
    "**num_epochs**": [10, 50]
}**runs** = []
for **run** in **product**(*h_params.values()):
    **runs**.append(**run**)

纪元和运行结束

接下来,我们将在一个步骤中涵盖几个阶段,所有阶段都是相互关联的,这样会更有意义。

前面我们已经看到了表示一个运行和一个时期开始的方法。在每个时期,我们必须迭代整个数据集,由于与计算和收敛优化相关的各种原因,我们分批进行(小批量随机梯度下降)。因此,我们必须将与此步骤相关的一些信息记录到我们的运行管理器中,这将帮助我们计算整个时期的总损失和准确性。

一旦纪元结束,我们必须计算上述指标,将它们保存到本地集合并记录到 Tensorboard。我们将有两个子步骤,分别用于培训和验证:

最后

一旦一切完成,您将有很好的 tensorboard 图来分析模型的性能和每个时期的记录历史,您可以将它们打包到 pandas 数据帧中或作为 CSV 或 JSON 保存到磁盘。

结论

这里给出的训练过程是非常普通的,但是,它表明通过使用 RunManager 类型的模块,您可以有一个更清晰和更容易理解的代码。

正如我在文章开头提到的,你应该检查 Pytorch 闪电。

感谢您的阅读,我希望您会发现这篇文章很有帮助,如果您想了解最新的编程和机器学习新闻以及一些优质的模因:),您可以在 Twitter 这里关注我,或者在 LinkedIn 这里联系我。

参考

如何将配置文件传递给 Kubernetes Pod

原文:https://towardsdatascience.com/how-to-pass-a-configuration-file-to-a-kubernetes-pod-61c1bcd286a5

数据工程

使用 Kubernetes ConfigMap 和 Secrets 来存储整个配置文件以在运行时传递给 pod,从而改进您的 DevOps 和 MLOps 项目

照片由卡里姆·曼吉拉Unsplash 上拍摄

Kubernetes 是一个帮助管理容器化应用程序的系统。它可以帮助您扩展应用程序,并确保它们平稳运行。您甚至可以使用 Kubernetes 来改进管理和部署数据科学项目的方式。

使用 Kubernetes 时可能遇到的一个问题是如何在运行时将配置文件传递给 pod。例如,您的 pod 包含一个通过某些凭据连接到外部服务的服务,这些凭据存储在一个文件中,如下图所示:

作者图片

问题是您希望在运行时将配置文件保存到 Pod 1,而不是每次都重建映像。

在本教程中,我将通过一个ConfigMa p 或一个Secret向你展示如何做到这一点。

文章组织如下:

  • 库伯内特斯的ConfigMap是什么
  • 如何使用ConfigMap将配置文件传递给 pod
  • 库伯内特斯有什么秘密
  • 如何使用Secret将配置文件传递给 pod。

1 Kubernetes 中的配置图是什么

ConfigMap 是一个 Kubernetes 资源,它允许您将特定于环境的配置数据从容器映像中分离出来。

这确保了您的应用程序可以轻松地在环境之间移动,而不必重新构建容器映像。

此外,使用ConfigMap可以帮助您避免在容器映像中硬编码敏感信息,比如数据库密码。

您可以在.yaml文件中定义自己的ConfigMap,如下所示:

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config-map
data:
  key1 : value1
  key2 : value2

您可以使用部署的.yaml文件中ConfigMap的值。关于ConfigMap的更多细节,可以参考 Kubernetes 官方文档

2 如何使用配置映射将配置文件传递给 pod

您可以使用一个ConfigMap来存储一个完整的配置文件,它可以作为一个文件挂载到您的 pod 中。您可以按如下方式进行。

首先,将配置文件添加到您的ConfigMap .yaml文件中:

**apiVersion**: v1
**kind**: ConfigMap
**metadata**:
  **name**: my-config-map
**data**:
  **file.conf**: |
     param1=value1
     param2=value2
     paramN=valueN

在前面的例子中,我们已经添加了file.conf,它可以存储连接到服务 b 所需的所有参数

现在,您可以在部署中使用ConfigMap,如下所示。

**apiVersion**: v1
**kind**: Deployment
**metadata**:
  **name**: my-deployment
**spec**:
  **containers**:
     ...
     **volumeMounts**:
     - **name**: config
       **mountPath**: "path/in/the/pod/where/to/mount/the/file"
       **subPath**: file.conf**volumes**:
  - **name**: config
  **configMap**:
    **name**: my-config-map
    **items**:
    - **key**: "file.conf"
    **path**: "file.conf"

volumeMounts部分,我们指定了 pod 中挂载文件的路径。我们还可以指定子路径,它只包含要挂载的文件。如果我们省略这一部分,我们可以挂载整个目录。

在 volumes 部分,我们指定了ConfigMap使用的细节。key标识ConfigMap中的名称,而path标识要在 pod 中创建的文件的名称。

3 库伯内特斯有什么秘密

Kubernetes 中的一个Secret是一个包含敏感信息的对象,比如密码、API 密钥和证书。机密用于存储和管理这些敏感信息。

秘密是加密的,只能由需要使用它们的 pod 解密。这确保了只有需要访问敏感信息的 pod 才能这样做。秘密是保持 Kubernetes 集群安全的重要部分。

Kubernetes secrets 使用加密的值,您可以在命令行终端中创建这些值,如下所示:

**echo** -n "my_secret" | **base64**

然后,您可以将前面操作的结果复制到。yaml储存你秘密的文件。您可以在.yaml文件中定义自己的Secret,如下所示:

**apiVersion**: v1
**data**:
  **username**: my_encoded_username
  **password**: my_encoded_password
**kind**: Secret
**metadata**:
  **name**: my_secret
**type**: Opaque

您可以使用部署的.yaml文件中ConfigMap的值。关于Secret的更多细节,可以参考 Kubernetes 官方文档

4 如何使用Secret将配置文件传递给 pod

传递给 pod 的配置文件可能包含一些敏感的信息,比如用户名和密码。在这种情况下,您不能使用ConfigMap来存储数据。相反,你可以使用一个Secret

其原理与ConfigMap相同:首先将整个配置文件作为一个秘密存储,然后将其作为一个卷挂载到 pod 中。

这是秘密的代码:

---**apiVersion**: v1
**stringData**:
  **file.conf**: |-
     username=demo
     password=my_plain_password
**kind**: Secret
**metadata**:
  **name**: my_secret
**type**: Opaque

您会注意到密码没有加密。然而,当你创建这个秘密时,Kubernetes 会为你加密,并以加密对象的形式分发。

当您想要在部署中使用该密码时,请按以下步骤操作:

**apiVersion**: v1
**kind**: Deployment
**metadata**:
  **name**: my-deployment
**spec**:
  **containers**:
     ...
     **volumeMounts**:
     - **name**: secret-file
       **mountPath**: "path/in/the/pod/where/to/mount/the/file"
       **subPath**: file.conf**volumes**:
  - **name**: secret-file
  **secret**:
     **secretName**: my_secret

摘要

恭喜你!您刚刚学习了如何在运行时将配置文件传递给 Kubernetes pod。您可以同时使用配置映射和密码。

当您想要传递通用参数时,配置映射非常有用。相反,如果你想传递明智的信息,你可以使用一个秘密。

如果你读到这里,对我来说,今天已经很多了。谢谢!你可以在这里阅读更多关于我的信息。

您可能也对解决以下问题感兴趣:

  • 如何删除 Docker 中的图像
  • 从基础映像重建映像
  • 将一些配置文件传递给 Docker 容器
  • 在 linux/arm64 架构上运行 linux/amd64 镜像。

阅读这篇文章来学习如何进行。

您想从媒体社区探索 DevOps 上的其他内容吗?

你可以阅读我的精选列表:

Angelica Lo Duca

当归罗杜卡

DevOps

View list5 stories

保持联系!

离开前…

你有没有想过用实验平台来改进你的 DevOps 系统?你可以在这里学习怎么做:)

如何通过 AWS 机器学习专业考试

原文:https://towardsdatascience.com/how-to-pass-the-aws-machine-learning-speciality-exam-b00bf0f811ed

为什么以及如何尝试认证

考虑考 AWS 机器学习专业认证?我在 2022 年 10 月参加了考试,没有找到太多关于它的更新信息。这篇文章旨在帮助你决定是否参加考试,以及如果你决定参加考试,如何投入时间。

资料来源:pixabay.com

我们开始吧!🚀

决定是否参加考试

为了看看机器学习专业考试是否适合你,让我们看看参加考试的理由和我建议的先决条件。

为什么要考这个?

  1. 如果你想给自己一个期限来了解更多关于 AWS 的数据工程和机器学习产品,请报名参加这个测试。如果你为考试而学习,并尝试这些服务,你将获得这些领域的知识。
  2. 如果您通过了测试,您将向其他人展示您对 AWS 及其在数据领域的产品有所了解。包含代码(以及附带的博客帖子)的单个项目是展示您技能的一个很好的方式。但是很难展示与云产品范围相匹配的技能广度。通过云提供商认证测试表明您拥有广泛的云技术知识。

先决条件

  1. 我建议你在参加这个考试之前了解一些数据科学知识。如果你想学习数据科学,为这个考试而学习并不是达到目的的理想方式。我建议通过训练营、学位课程或严格的自学更深入地研究数据科学。
  2. 熟悉 AWS。我建议在此之前参加云从业者认证考试或另一个 AWS 认证考试。点击查看所有 AWS 考试
  3. 擅长做选择题是有帮助的。要在工作记忆中保持一个问题的从句和答案的细微差别,需要大量的注意力。
  4. 你需要有能力和意愿支付 300 美元的测试费。我建议你把这笔钱看作是帮助你学习材料的一种投资,不管你是否通过考试。

我为什么要参加考试?

我过去参加并通过了一些云提供商的测试。几年前参加过谷歌云认证专业数据工程师考试。我进一步了解了 GCP 及其数据工程产品。当我今年夏天患有 COVID 并被隔离时,我准备并参加了 AWS 认证开发人员助理考试。这是我那次考试的学习笔记。我不会向大多数数据专业人员推荐它。

我可以很好地集中注意力,进入测试作者的头脑,并且是排除法的狂热使用者。尽管我通过了我参加的每一项云提供商测试,但我对任何一项测试的结果都没有信心。我发现美国高等教育入学考试——SAT、ACT、GRE、GMAT 和 LSAT 更容易一些——我敢说,更有趣。

我参加了 AWS 机器学习考试,因为我想了解更多关于 AWS 数据工程和数据科学的内容。我也发现像这样的测试是一个很好的挑战。我不必担心费用,因为我的雇主提督慷慨地提供学习津贴。所以我决定放手一搏。

我给了自己几天时间来学习 AWS 专用材料并参加测试。我是 10 月 14 日报名考试的。我希望把我的考试安排在接下来的一两天,但是没有空位了。所有这些都是说你可能无法安排明天的考试。

我读了一些关于这个测试的资料,尝试了十个官方样题,然后开始看 PluralSight 视频。我用 3 个小时的时间看了大概 5 个小时的视频。

我的 PluralSight 观看历史截图。作者图片

具体细节

先从亚马逊的考试指南说起。它对将要发生的事情有一个很好的概述。

位置

你可以远程或亲自参加考试。我远程拍摄的。如果是远程办公,确保你已经清理了除了键盘、鼠标和电脑以外的所有东西。你需要有一扇门把你和其他人隔开,并有一个安静的地方工作。监考人会通过摄像头监控。

该考试提供英语、日语、韩语和简体中文版本。

问题

在 100 到 1000 分的范围内,你需要 750 分。该测试由 65 个问题组成,问题类型细分如下:

  • 20%数据工程
  • 24%探索性数据分析
  • 36%建模
  • 20%的机器学习实现和操作

请注意,15 个问题是未来考试的练习题,不会得分。

所有问题都是选择题或多选题。多重回答只是指有几个必选答案的多项选择。多个响应是粗略。三分之二正确是没有价值的。呃。至少问题会告诉你选择的答案数量。😐

AWS 机器学习专业认证考试很熊。如果你没有通过考试,不要感到一点点不好。

准备

你以前的经验水平,你有多少时间准备,你对通过考试的重视程度,以及你参加这种考试的方式都会影响到你的学习计划。

服务和主题的范围很大。这是考试指南中的列表。请注意,本考试指南适用于 2.0 版 MLS-C01:

Analytics:
 Amazon Athena
 Amazon EMR
 Amazon Kinesis Data Analytics
 Amazon Kinesis Data Firehose
 Amazon Kinesis Data Streams
 Amazon QuickSight

Compute:
 AWS Batch
 Amazon EC2

Containers:
 Amazon Elastic Container Registry (Amazon ECR)
 Amazon Elastic Container Service (Amazon ECS)
 Amazon Elastic Kubernetes Service (Amazon EKS)

Database:
 AWS Glue
 Amazon Redshift

Internet of Things (IoT):
 AWS IoT Greengrass

Machine Learning:
 Amazon Comprehend
 AWS Deep Learning AMIs (DLAMI)
 AWS DeepLens
 Amazon Forecast
 Amazon Fraud Detector
 Amazon Lex
 Amazon Polly
 Amazon Rekognition
 Amazon SageMaker
 Amazon Textract
 Amazon Transcribe
 Amazon Translate

Management and Governance:
 AWS CloudTrail
 Amazon CloudWatch
Networking and Content Delivery:
 Amazon VPC
Security, Identity, and Compliance:
 AWS Identity and Access Management (IAM)

Serverless:
 AWS Fargate
 AWS Lambda

Storage:
 Amazon Elastic File System (Amazon EFS)
 Amazon FSx
 Amazon S3

AWS 关于数据科学主题的问题(如缺失值的处理)相当棘手,即使您熟悉这些内容。关于此类主题的文献并不固定,问题有时缺乏细微差别。同样,除非你是 AWS 机器学习和数据工程服务的专家,并且是一名优秀的应试者,否则我会确保你对数据科学有很强的理解。

AWS 关于生产中的数据工程和机器学习的问题非常关注亚马逊的产品。

对于云考试,我喜欢集中一周左右的时间,然后参加考试。

要学习的关键内容

确保您了解一些最流行的 AWS 服务:EC2、S3 和 Lambda。您也希望熟悉基本的 AWS 概念,如 VPC 和 IAM。这条来自西蒙·霍尔夫的关于 AWS VPC 概念的推特帖子是我见过的最好的综述。

我对云提供商测试的启发是这样的:当公司在测试领域有一项它引以为豪的特殊服务时——通常是无服务器的——你可以期待看到关于它的问题。此外,你可以期待它很可能是一个问题的正确答案的一部分。这些公司想让你用他们的新玩意。🪄

花点时间了解雅典娜、奥罗拉、Kineses、Glue 和 Sagemaker,如果你遇到困难,就准备和他们一起走。特别是, SageMaker 包含了大量的数据科学服务,所以要确保你对它了如指掌。Kinesis 和 Glue 是亚马逊的特殊数据工程产品,每个产品都有多个子部分。

我建议您阅读关键服务的文档,使用它们,并确保您理解它们。我建议记笔记,并写出要点的摘要。我喜欢用抽认卡作为间隔重复系统的一部分。在这一期我的数据牛逼简讯中,我谈了一点关于使用 Anki 闪存卡的事情。🧠

外部资源

为了了解测试中的技术,我在 Pluralsight 上观看了上面列出的视频。此外,我还阅读了各种各样的博客帖子,以帮助我理解这些服务是如何工作的,以及它们是如何相互比较的。

一位云专家 (ACG)是我用来帮助准备 GCO 数据工程师考试的。我在这里写了关于的那段经历。我认为他们的材料是高质量的。虽然 Pluralsight 购买了 ACG,但截至 2022 年 10 月底,您仍需为这两项服务付费。我和 ACG 进行了一次模拟测试,结果相当不错。我会从 ACG 开始——我从 Pluralsight 开始,因为我的公司在那里有订阅。

我不喜欢通过视频学习,但我发现它们对我看过的云计算测试很有帮助。我只是把速度提高到我能忍受的最快水平,同时仍然记笔记并把它们敲出来。

官方 AWS 文档

一件棘手的事情是找到针对考试的最新学习材料。Pluralsight 视频和 2022 年 10 月的 ACG 实践考试已经有两年了。

没有更新的实践材料是困难的,因为云服务在不断更新他们的技术。例如,我使用的学习材料谈到了你必须如何为你的运动流选择多少碎片。但是,现在您可以在设置流时选择一个可伸缩的模式。这也是真正的医生是花时间的好地方的另一个原因。值得一提的是,我了解到 AWS 产品在测试前一般会存在至少六个月。

使用 AWS 服务

我鼓励你使用考试中涉及的每一项主要技术。这有助于你的测试,也有助于现实世界的影响。别忘了把东西关掉,这样你就不会收到讨厌的账单了!

确保您首先设置了计费警报!我最近给乔治敦大学统计系的学生讲授了一门介绍云计算和 AWS 的课程,我很确定这是我认为最有价值的事情。

我花了大约 20 美元尝试一些东西,其中大部分是偶然的。感谢上帝的计费警报!

模拟测试

亚马逊提供的免费 10 题模拟测试很好地展示了你将在真实考试中看到的问题类型。我建议你早点参加,这样你就能知道考试是什么样的了。

您可以从备考网站购买额外的测试。我拿了一个,如果我有更多的时间,我会拿另一个。我强烈建议尽可能多的服用。然而,应该对问题和结果持保留态度。很难复制测试中问题的感觉和内容,部分原因是模拟测试可能会过时。

考试日

时间

想想水和测试前的浴室之旅。

你有三个小时来参加考试。这应该有足够的时间来仔细研究所有 65 个问题。我完成了考试,还剩下大约一个小时。

你可以标记问题以便以后复习,我也这样做了。对于这个测试,我没有回头看一个以上的问题,我认为我在测试的其他地方学到了有用的信息。

在游戏中保持积极

这是一个令人羞愧的测试。最大的障碍可能是你头脑中的一个小声音,说你不会做得很好,因为你正在努力寻找答案。保持乐观并坚持下去。这样做会让你处于成功的最佳位置。对于大量的实验性问题,您可能会错过一串答案,但仍然有可能通过测试。

保持积极的态度,缩小你的答案选择,选择你认为最有可能的答案,然后继续滚动。

结果

完事后,深呼吸,出去散散步。你很努力,尽了最大努力。学习的过程是最重要的,而不是目的地。尽量不要担心你做得如何,因为你现在无法改变它。🙂

您应该在考试后一天左右通过电子邮件收到您的通过/失败测试结果。你可以通过电子邮件链接查看你的得分。个别问题不予公布。我明白为什么,但是看不到你错过的东西有点烦。

包装

您已经了解了是否要参加 AWS 机器学习专业考试认证以及如何准备。如果你决定投资时间,我祝你好运!

如果你考了,我很想听听你的经历!欢迎在评论中分享。

如果你觉得这篇文章有用,请在社交媒体上分享,这样其他人也可以找到它。🎉

我写关于数据、云、Python 和其他技术主题的文章,所以如果你对这些感兴趣,请关注我

资料来源:pixabay.com

学习愉快!🚀

如何在机器学习项目上表现得更好

原文:https://towardsdatascience.com/how-to-perform-better-on-machine-learning-projects-de9ac9a5dfdf

问三个问题,下次会更好

马特·霍华德Unsplash 上拍照

喜剧演员克里斯·洛克一小步一小步地提出新颖的想法。在获得巨大成功的演出之前,他尽可能多的晚上呆在小型喜剧俱乐部,尝试新的笑话。当然大部分都是不了了之,观众嘲笑他。但在这一百个失败的想法中,不可避免地会有一小撮火花。这个过程就是克里斯·洛克如何为他的新节目做准备的,长达一年的时间每天苦读一小时的(高超的)娱乐节目。因为:戏后是戏前。

我们可以从 Rock 的创作过程中学到很多东西:纪律、谦逊,以及接触挑剔甚至敌对的观众。然而,我想挑出三个问题,我们可以在结束一个(机器学习)项目后使用。这三个问题是我学到了什么?下次要避免什么?,还有我下一次又该怎么做?回答这三个问题可以让我们在下一个项目中表现得更好。而且,因为即使是很小的改进也是复合的,习惯性地检查它们会给我们很大的动力。唉,对于第一个问题。

我学到了什么?

当克里斯·洛克测试他的新笑话时,经常看到他拿着一个记事本,潦草地记下观众的反应。Rock 的仔细分析让他看到了自己需要修改的地方。同样,我们问我学到了什么?首先是因为答案构成了后续步骤的基础。我们正在寻找一个诚实的评估我们所有的经验和行动,作为该项目的一部分。为了更具体,让我参考上一篇文章中的一个例子。在一个 TFRecord 数据集的基础上实现了一个增强例程之后,我的模型的性能有了很大的提高,正如损失和准确性分数所衡量的那样。满足于这种提升,我没有进一步考虑输入管道,而是将注意力集中在其他特性上。后来,我注意到增强步骤引入了一个严重的瓶颈,将每个时期的时间从 1 分钟增加到了惊人的 15 分钟

让我们一起来分析一下这个事件,看看我们能从中学到什么:

  1. 对模型预测能力的单一关注掩盖了严重的瓶颈。因此,我们得到的教训是,我们不仅要监控主要的性能指标(损失、准确性等)。)还要检查次要指标(管道吞吐量、硬件利用率等)。).
  2. 我用的增强包明确说明了所有操作都是在 CPU 上执行的。虽然我记得读过这篇文章,但我认为我没有考虑到这个事实的影响。因此,第二个教训是,我们不应该盲目地添加酷的东西。
  3. 我们还应该关注我们在执行增强程序时所学到的东西。在这种情况下,从 TFRecord 格式中读取数据,并通过定制的预处理管道传递它。因此,第三个经验是如何从这种特定格式读取数据并对其进行预处理。

从这个事件中,我们至少可以学到三点:检查二级指标,添加新特性时要小心,以及预处理来自 TFRecords 的数据。用我们所有的经验重复这种细致的分析,我们会为下一个项目找到许多有用的指示。

然后,在编制了一份(冗长的)清单后,我们可以回答第二个问题。

下次应该避免什么?

在记录了我们在前面步骤中的失误和正确决策后,我们将列表分为两类。第一类,避免,包含我们下次应该避免的所有事件/教训。

从这个例子中,我们已经可以将两个项目归入这个类别。第一点是,我们不应该盲目地关注单个指标的值。第二点是,我们不应该仅仅因为我们认为功能很酷就添加它们。

为了澄清这一类别,让我再举一个例子,来自之前的帖子。对于神经网络,我们可以优化无数的参数。学习率就是其中之一。因为我试着变聪明,我认为让学习率在整个训练过程中变化会很聪明。在搜索相关研究后,我找到了莱斯利·史密斯关于循环学习率的论文。这个很酷的特性让我很兴奋,我马上开始在培训中实现它。然而,经过几天的编码和参数优化,我意识到我并不真正需要这个项目的这个特性。此外,让学习率变化引入了额外的超参数,增加了项目的复杂性。最后,我完全放弃了调度策略。

通过分析这一事件,我们可以重新发现以前的教训:不要盲目地添加酷的东西。这是很自然的事情;许多事件可以提供类似的教训。除此之外,我们还可以找到第二个相关的提示:不要在错误的时间和地点迷失在细节中。我小心翼翼地调整了学习速度,并重构了示例中的大部分底层代码。不幸的是,由于所有的劳动都是徒劳的,投入的时间都花在了错误的地方(次要特征),最终都浪费了。因此,这一课符合避免的类别。

在整个项目中,我们可能做了一些对整体进度没有好处的事情。然而,通过把它们都归入避免类别,我们为我们未来的职业生涯建立了一个强大的资源。更好的是,在下一步中,我们编制了一个推荐行动的列表,作为指导方针。

下一次我应该做什么?

对于喜剧演员克里斯·洛克来说,在挑剔的观众面前尝试他的笑话也有积极的一面,告诉他应该重复哪一个。他可能会认为他们是他的一些草图的绝对烟花,只看到他们被忽视。但是,他的一些看似二流的笑话让观众捧腹大笑;他可以把这些笑话蚀刻出来。

在我们的案例中,对项目的仔细分析可以让我们找到相似的见解。因此,通过回答前一个问题填充的避免类别有一个兄弟,即重复类别。此类别包含所有对项目进展有积极贡献或可用作未来项目蓝图的经验和行动。从给出的两个例子中,我们也可以得出积极的指示。

一个是,在 TFRecord 管道上实现了增强技术之后,我们可以重用我们的知识,并在下一次构建类似的设置。换句话说,我们可以写下:使用 TFRecord 格式存储数据,并在其上构建一个管道。第二个指示是将我们的注意力、精力和时间——这些都是非常重要的资源——集中在核心特征上,就像学习率的例子告诉我们的那样。只有在建立了一个坚实的基础之后,我们才能进入细节。

和以前一样,重复类别给了我们一个方便的想法列表,我们可以遵循它来提高我们在项目中的表现。

TL;速度三角形定位法(dead reckoning)

完成一个项目后,分析它并收集所有的经验教训。把它们分成避免下一次的和重复的。

作为结束语,我想强调的是,我们已经可以在项目期间实施这个拟议的问答计划,而不仅仅是在项目结束之后。通过这样做,我们可以在旅途中优化我们的性能,避免重复错误,将它们转化为可操作的指令。

如何在 Python 中使用 SQLAlchemy 高效地执行批量插入

原文:https://towardsdatascience.com/how-to-perform-bulk-inserts-with-sqlalchemy-efficiently-in-python-23044656b97d

学习用 Python 高效地将大量记录插入数据库的不同方法

图片由 Pixabay 中的 PublicDomainPictures 提供

使用 SQLAlchemy 通过普通 SQL 查询对象关系映射器(ORM) 与关系数据库交互非常方便。然而,当涉及到批量插入时,也就是说,将大量记录插入到一个表中,我们可能经常会遇到性能问题。在本帖中,我们将介绍批量插入的不同方法,并通过实践教程比较它们的性能。您将对这些方法有更好的理解,并可以选择最适合您实际情况的方法。

安装 SQLAlchemy

为了使它成为可以跟随的实践教程,我们需要在我们的计算机上安装所需的库。建议在虚拟环境中安装软件包,这样就不会弄乱你的系统库。我们将使用 conda 创建一个虚拟环境,因为我们可以在虚拟环境中安装特定版本的 Python:

为本教程安装的软件包:

  • SQLAlchemy —将用于与数据库交互的主包。
  • MySQL client—MySQL 数据库的高性能驱动程序。如果您在安装 mysqlclient 或使用它时遇到一些问题,您可以安装 PyMySQL ,它没有系统依赖性问题。如果需要使用 PyMySQL 作为驱动程序,请查看这篇文章。
  • 密码术 —由 SQLAlchemy 用于认证。
  • ipython —用于更方便地执行交互式 python 代码。

设置本地 MySQL 服务器

在本教程中,我们将使用本地 MySQL 服务器,而不是 SQLite,以使其更类似于实际用例。可以使用 Docker 方便地设置服务器:

请注意,MySQL Docker 容器附带了一个卷,因此即使容器重新启动,数据也可以持久保存。此外,root 密码被指定为一个环境变量,因此可以在以后用于身份验证。最后,为容器分配了一个高端口(13306 ),因此它不会与其他现有的 MySQL 服务器发生潜在冲突。

设置数据库连接

现在让我们设置数据库连接元数据,它将在即将引入的测试中使用。两个上下文管理器被创建,分别产生一个[Session](https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.Session)和一个[Connection](https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Connection)对象。Session对象将用于执行 orm 模型的操作,而Connection对象用于处理 SQLAlchemy 核心 API 或直接执行普通 SQL 查询。一些清理工作也在上下文管理器中完成,因此我们可以连续运行多个测试。有关 SQLAlchemy 引擎、连接和会话的更详细介绍,请查看这篇文章

设置数据库连接元数据的代码片段如下:

警报:

  • 应该使用127.0.0.1而不是localhost作为上面 DB URL 中的主机名,否则,可能会出现连接问题。

为测试创建一个 ORM 类

我们将创建一个简单的customers表,它有两个字段,即idname,其中id的主键默认自动递增。顺便说一下,这个表将位于上面 DB URL 中指定的data模式中。该表的 ORM 类如下所示。该表将在上下文管理器创建会话或连接时创建,并将在cleanup参数为True时删除。

逐个添加 ORM 对象

现在让我们用不同的方法将大量记录添加到表中,并比较它们的性能。第一个是Session.add(),当您使用 ORM 与数据库交互时,这是非常常用的。

我们将首先向数据库添加 20,000 条记录,但不指定主键:

该测试功能大约需要 5 秒钟。所花费的时间会因电脑的性能而异,并且每次运行时会略有不同。如果太快或太慢,可以微调num参数。如果你想检查数据库中插入的数据,设置cleanupFalse

对于 ORM,有一个快捷方法Session.add_all(),它将 ORM 实例列表作为参数:

使用Session.add()Session.add_all()的性能应该非常相似,因为数据直到运行Session.commit()才保存到数据库,而运行Session.commit()是真正的时间限制步骤。

实际上,用 5 秒钟插入 20,000 条记录可能是应用程序的一个主要性能问题。如果数据库位于远程服务器上,情况可能会更严重。低性能有两个主要原因:

  • 需要为每条记录创建一个 ORM 实例。
  • 由于 ORM 的工作单元设计,主键和其他默认值需要返回到 ORM 实例。

第二个更有影响力,如果我们为创建的 ORM 实例提供主键,就可以证明这一点:

警报:

  • 如果主键是自动递增的,并且是像这里这样显式指定的,则它不能为零,否则数据可能无法成功插入。你可以试着把id=idx+1改成id=idx,看看自己是否也会这样。

事实证明,如果提供主键,性能可以得到显著提高。这太棒了!然而,这并不是使用 SQLAlchemy 执行批量插入的最有效的方式,有时它可能不适用于指定主键,所以请耐心等待。

使用 Session.bulk _ save _ 对象

SQLAlchemy 有一些专门为批量操作设计的方法。对于批量插入,有Session.bulk_save_objects()Session.bulk_insert_mappings()Session.bulk_save_objects()将 ORM 实例列表作为参数,类似于Session.add_all(),而Session.bulk_insert_mappings()将映射/字典列表作为参数。我们这里用Session.bulk_save_objects(),后面用Session.bulk_insert_mappings()

在开始使用它之前,我们应该知道Session.bulk_save_objects()的两个主要注意事项:

  • 大多数 ORM 的好处,比如外键关系和属性的自动更新,对于通过这种方法传递的 ORM 实例是不可用的。如果我们想有这些好处,那么就不应该用这种方法,而应该用Session.add_all()来代替。
  • 我们不应该返回插入的 ORM 实例的主键,否则,性能会大大降低。如果我们需要返回主键,我们也应该使用Session.add_all()来代替。

在下面的代码片段中,我们将执行三个测试并比较它们的性能:

  • 使用返回主键的Session.bulk_save_objects()
  • 使用Session.bulk_save_objects()而不返回主键。
  • 使用Session.bulk_save_objects()并明确指定主键。

当运行这三个测试时,它表明当返回主键时,性能确实急剧下降。然而,与Session.add_all()的情况不同,是否为 ORM 实例指定主键并没有多大关系。

使用 bulk_insert_objects

另一个用于批量插入的 SQLAlchemy 方法是Session.bulk_insert_mappings()。顾名思义,映射列表(Python 中的字典)作为该方法的参数传递。直接使用映射的好处是避免创建 ORM 实例的开销,这通常不是问题,但是当需要创建和保存大量 ORM 实例时,这就变得很重要了。

在下面的代码片段中,我们将执行两个测试并比较它们的性能:

  • 使用没有指定主键的Session.bulk_insert_mappings()
  • 使用指定主键的Session.bulk_insert_mappings()

以上测试速度极快。如果没有指定主键,它比Session.bulk_save_objects()快两倍,而【】又比Session.add_all()快五倍。此外,与Session.bulk_save_objects()类似,如果为要保存的映射指定了主键,也没有多大关系。

使用 SQLAlchemy 核心 API

SQLAlchemy ORM 模型建立在核心 API 之上。如果性能是唯一的目标,我们应该使用直接插入的核心 API,避免 ORM 模型的所有开销。

我们可以使用 SQL 表达式语言来访问 SQLAlchemy 的核心 API。使用 SQL 表达式语言的好处是能够直接访问核心 API,从而实现高性能,同时提供适用于所有类型的关系数据库的后端/数据库中立语言。我们将在下一节介绍普通 MySQL 查询的直接用法。

我们可以使用 ORM 类的__table__属性来访问提供[Insert](https://docs.sqlalchemy.org/en/14/core/dml.html#sqlalchemy.sql.expression.Insert)结构的底层[Table](https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.Table)对象。类似于Session.bulk_insert_mappings(),映射/字典列表可以传递给Insert构造。然而,一个 SQLAlchemy [Connection](https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Connection)对象用于执行插入表达式,而不是一个[Session](https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.Session)对象。

在下面的代码片段中,我们将执行两个测试并比较它们的性能:

  • 使用核心 API 插入没有主键的字典列表。
  • 使用核心 API 插入指定了主键的字典列表。

上面的测试甚至比使用Session.bulk_insert_mappings()还要快,但比快不了多少,因为这里完全避免了使用 ORM 模型的开销。此外,如果为要保存的映射指定了主键,也没有多大关系。

使用普通 SQL 查询

如果你是一个只想处理普通 SQL 查询而根本不想处理核心 API 或 ORM 的守旧派,你可以使用Connection.exec_driver_sql()来执行批量插入,它直接利用底层 DBAPI,与使用上面所示的核心 API 具有相同的性能:

如果你想了解更多关于在 SQLAlchemy 中执行普通 SQL 查询的信息,请查看这篇文章。

所有例子的代码都可以在这里找到。一旦安装了库并设置了 MySQL 服务器,就可以直接运行它。

在本文中,介绍了批量插入的不同 SQLAlchemy 方法。以简单易懂的方式介绍了它们的代码,并系统地比较了它们的性能。

总之,如果您使用普通的 SQL 查询,您不需要担心 SQLAlchemy 的性能,因为它直接调用底层的 DBAPI。应该优化的是查询本身。

如果你坐在中间,不使用普通的 SQL 查询或 ORM 模型,而是使用所谓的表达式语言,你可以使用直接访问核心 API 的Insert构造来执行批量插入,这也非常有效。

最后,如果您使用 ORM 模型,并且希望在插入后访问 ORM 实例的更新状态,那么您应该使用Session.add_all()。如果可能,请提供主键,因为这样可以显著提高性能。另一方面,如果您使用 ORM 模型,并且不需要访问更新的数据,您可以使用与核心 API 效率相当的Session.bulk_insert_mappings()

相关文章:

如何在 NLP 项目中执行数据扩充

原文:https://towardsdatascience.com/how-to-perform-data-augmentation-in-nlp-projects-5c4b86c25035

利用文本攻击库进行数据扩充的简单方法

图片由 Gerd AltmannPixabay 拍摄

在机器学习中,为了实现强大的模型性能,拥有大量数据是至关重要的。使用一种称为数据扩充的方法,您可以为您的机器学习项目创建更多数据。数据扩充是一组技术,用于管理在现有数据基础上自动生成高质量数据的过程。

在计算机视觉应用中,增强方法非常普遍。例如,如果你正在做一个计算机视觉项目(例如图像分类),你可以对每张图像应用许多技术:移动、修改颜色强度、缩放、旋转、裁剪等等。

如果您的 ML 项目有一个很小的数据集,或者希望减少机器学习模型中的过度拟合,建议您可以应用数据扩充方法。

“我们没有更好的算法。我们只是有更多的数据。”-彼得诺威格

在自然语言处理(NLP)领域,语言所具有的高度复杂性使得扩充文本变得困难。扩充文本数据的过程更具挑战性,不像有些人预期的那样简单。

在本文中,您将学习如何使用名为 TextAttack 的库来改进自然语言处理的数据。

什么是 TextAttack?

TextAttack 是一个 Python 框架,由 QData 团队构建,目的是在自然语言处理中进行对抗性攻击、对抗性训练和数据扩充。TextAttack 具有可独立用于各种基本自然语言处理任务的组件,包括句子编码、语法检查和单词替换。

TextAttack 擅长执行以下三个功能:

  1. 对抗性攻击(Python: **textattack.Attack**,Bash: **textattack attack**)。
  2. 数据增强(Python: **textattack.augmentation.Augmenter**,Bash: **textattack augment**)。
  3. 模型训练(Python: **textattack.Trainer**,Bash: **textattack train**)。

注意:对于本文,我们将关注如何使用 TextAttack 库进行数据扩充。

如何安装 TexAttack

要使用这个库,请确保您的环境中有 python 3.6 或更高版本。

运行以下命令安装 textAttack。

pip install textattack

注意:一旦安装了 TexAttack,就可以通过 python 模块或命令行运行它。

文本数据的数据扩充技术

TextAttack 库有各种增强技术,您可以在 NLP 项目中使用这些技术来添加更多的文本数据。以下是您可以应用的一些技巧:

1。它通过将字符替换成其他字符来扩充单词。

from textattack.augmentation import CharSwapAugmentertext = "I have enjoyed watching that movie, it was amazing."charswap_aug = CharSwapAugmenter()charswap_aug.augment(text)

[“我很喜欢看那部电影,太棒了。”]

增强器将单词“电影”换成了“om vie”

2。DeletionAugmenter 它通过删除文本的某些部分来扩充文本,以生成新的文本。

from textattack.augmentation import DeletionAugmentertext = "I have enjoyed watching that movie, it was amazing."deletion_aug = DeletionAugmenter()deletion_aug.augment(text)

[“我看过了,太棒了。”]

这种方法删除了单词“享受”来创建新的扩充文本。

3。EasyDataAugmenter 这是用不同方法的组合来扩充文本,例如

  • 随机交换单词在句子中的位置。
  • 从句子中随机删除单词。
  • 在随机位置随机插入随机单词的随机同义词。
  • 随机用同义词替换单词。
from textattack.augmentation import EasyDataAugmentertext = "I was billed twice for the service and this is the second time it has happened"eda_aug = EasyDataAugmenter()eda_aug.augment(text)

['我为这项服务开了两次账单,这是第二次',T25'我为一项服务开了两次账单,这是第二次',T26'我为这项服务开了两次账单,这是第二次',T27'我为这项服务开了两次账单,这是第二次']

正如您从增强文本中看到的,它根据应用的方法显示了不同的结果。例如,在第一个扩充文本中,最后一个单词已经从“发生”修改为“发生”

4。它可以通过用 WordNet 词库中的同义词替换文本来扩充文本。

from textattack.augmentation import WordNetAugmentertext = "I was billed twice for the service and this is the second time it has happened"wordnet_aug = WordNetAugmenter()wordnet_aug.augment(text)

['我为这项服务开了两次账单,这是第二次了']

该方法将单词“发生”改为“经过”,以创建新的增强文本。

5。创建自己的增强器textattack.transformationstextattack.constraints导入变换和约束允许你从头开始构建自己的增强器。以下是使用WordSwapRandomCharacterDeletion算法生成字符串扩充的示例:

from textattack.transformations import WordSwapRandomCharacterDeletion
from textattack.transformations import CompositeTransformation
from textattack.augmentation import Augmentermy_transformation = CompositeTransformation([WordSwapRandomCharacterDeletion()])
augmenter = Augmenter(transformation=my_transformation, transformations_per_example=3)text = 'Siri became confused when we reused to follow her directions.'augmenter.augment(text)

[“当我们再次听从她的指示时,Siri 变得困惑起来。”当 e 重复使用她的指示时,Siri 变得很困惑,
“当我们重复使用 Siri 来遵循 hr 的指示时,它变得很困惑。”]

实施WordSwapRandomCharacterDeletion方法后,输出显示不同的增强文本。例如,在第一个扩充文本中,该方法随机移除单词“ confused”中的字符“o”

结论

在本文中,您已经了解了数据扩充对于您的机器学习项目的重要性。此外,您还学习了如何使用 TextAttack 库对文本数据执行数据扩充。

据我所知,这些技术是完成 NLP 项目任务的最有效的方法。希望它们能对你的工作有所帮助。

您还可以尝试使用 TextAttack 库中其他可用的增强技术,例如:

  • 嵌入增强器
  • 检查表增强器
  • 克莱尔增强器

如果你学到了新的东西或者喜欢阅读这篇文章,请分享给其他人看。在那之前,下期帖子再见!

你也可以在 Twitter @Davis_McDavid 上找到我。

最后一件事:在以下链接中阅读更多类似的文章

https://medium.com/geekculture/how-to-speed-up-model-training-with-snapml-b2e24b546fe5 https://medium.com/geekculture/top-5-cloud-migration-strategies-you-need-to-know-fb1d92ed3c8a https://medium.com/geekculture/top-5-reasons-why-companies-are-moving-to-the-cloud-c3a609332125

本文首发于 此处

如何在 QGis 中执行探索性数据分析

原文:https://towardsdatascience.com/how-to-perform-exploratory-data-analysis-in-qgis-8333731b9dfa

地理数据,探索性数据分析

关于如何使用 QGis 执行地理数据 EDA 的教程,以 CSV 格式提供。

安妮·斯普拉特在 Unsplash 上的照片

数据科学家可能不得不处理地理数据。在这种情况下,除了传统的数据浏览方法,您还可以使用特定的工具来管理地理数据。

在这篇文章中,我描述了如何使用 QGis 对地理数据集进行初步探索。作为一个例子,我使用的数据集与出租车司机的流动性有关,可在链接获得,并由【1,2】发布。

文章组织如下:

  • 安装和配置 QGis
  • 加载 T-Drive 数据集
  • 在 QGis 中执行 EDA。

1 安装和配置 QGis

QGis 是一个非常流行的处理地理数据的开源工具。你可以从的官方网站下载,然后按照步骤安装。请注意,安装需要硬盘上大约 1GB 的可用空间。

安装后,您可以启动它。您应该会看到如下图所示的窗口:

作者图片

现在,您可以启用快速地图服务插件,它允许您在地图上可视化数据。单击插件菜单→管理和安装插件。在搜索栏中,编写 QuickMapServices,然后单击安装它。

安装后,您可以在 Web 菜单→ QuickMapServices 下访问它,如下图所示:

作者图片

例如,您可以选择开放街道地图(OSM) → OSM 标准。QGis 窗口的中央部分应该会出现一幅地图:

作者图片

您可以通过传统的缩放按钮缩放图像,如下所示:

作者图片

您可以通过点击屏幕右下方的按钮来更改系统的当前地理坐标,如下图所示:

作者图片

单击它后,会打开一个窗口,允许您选择系统。如果您的数据集包含经度和纬度的地理坐标,您应该选择 WGS 84 EPSG:4326

2 加载 T-Drive 数据集

T-Drive 数据集包含大约 10K 出租车的一周轨迹。该数据集中的总点数约为 1500 万。在这个例子中,我使用了这个数据集的一个摘录,大约有 1M 的点。我已经提取了这个链接提供的样本:从第 6 部分到第 14 部分。结果,我下载了 551 个文件,涉及 551 辆出租车。

首先,我将 551 个文件合并成一个 CSV 文件,作为 QGis 的输入。为了合并文件,我使用 Python 熊猫库。

首先,我加载所需的库:

import pandas as pd
import glob
import os

我将使用globos库来检索要合并的文件列表。我把所有的文件合并到一个名为source的目录中。

我加载了一个样本数据集,以查看它的结构。由于数据集不包含任何标题,我还设置了标题:

df = pd.read_csv('source/39.txt', names=['id', 'date', 'lat', 'lng'])
df.head()

作者图片

我在源目录中检索文件列表:

files = os.path.join("source/", "*.txt")
files = glob.glob(files)

现在,我读取每个文件,并将其添加到一个列表中:

li = []
for file in files:
    df = pd.read_csv(file, index_col=None, names=['id', 'date', 'lat', 'lng'])
    li.append(df)

我将列表中的所有文件连接起来,构建一个 Pandas 数据帧:

df = pd.concat(li, axis=0, ignore_index=True)

数据帧包含 985,972 行。我把它保存到一个文件中:

df.to_csv('source/merged.csv')

数据集已准备好导入 QGis!

3 在 QGis 中执行 EDA

要在 QGis 中加载数据集,我选择图层菜单,然后添加图层→添加分隔文本图层。一个窗口打开。在文件名文本输入下,我选择了merged.csv文件。

在几何图形定义下,我选择 X 字段(纬度)和 Y 字段(经度)。我还确保几何图形 CRS 是 EPSG-4326 WG84。

我点击添加→关闭。

您应该会看到地图上的点,如下图所示:

作者图片

图中显示有很多错误!数据集应该包含北京的点,但有些点在非洲,有些在欧洲,还有北京以外的其他地方。对于一个假设性的分析,我应该去掉那些点。

我在地图上执行以下操作:

  • 按颜色显示出租车
  • 显示一辆出租车。

3.1 按颜色显示出租车

在窗口的左侧,有一个已加载层的列表。我右键单击 merged,然后选择 Properties。在符号系统菜单下,我单击单个符号,然后分类。在值文本输入中,我选择 id。然后,我单击分类按钮→应用→确定。

如果我缩放地图,应该会看到类似下图的内容:

作者图片

如果我进一步放大地图,我会看到分布在道路上的出租车:

作者图片

3.2 显示一辆出租车

我右键单击合并层,并选择过滤器。一个窗口打开,我选择 id = 2034,然后测试,检查是否有任何结果。我点击确定。

如果我更改地图的缩放和平移级别,我应该可以看到这些点:

作者图片

我可以为每个点添加一个标签,方法是右键单击合并的层,然后选择属性→标签→无标签→单个标签→值。我选择了日期字段,以标签的形式查看日期。然后,我单击应用→确定。

现在我看到每个点附近的日期:

作者图片

通过添加另一个过滤器,我可以继续按日期对点进行分组的分析。在这种情况下,我应该更新标签部分,如前所述。我应该选择一个日期,而不是 id。

摘要

恭喜你!您刚刚学习了一些关于如何开始使用 QGis 的基本概念,并使用它对地理数据执行非常初步的探索性数据分析。

QGis 很强大,你只要测试一下,试试其他功能就行了!

如果你读到这里,对我来说,今天已经很多了。谢谢!你可以在这个链接阅读我的趋势文章。

参考

[1]袁静,郑宇,谢星,和孙广忠.用物理世界的知识驾驶。2011 年美国纽约州 KDD 市第 17 届 ACM SIGKDD 知识发现和数据挖掘国际会议。ACM。【2】、、、、谢、、邢、、。T-drive:基于滑行轨迹的驾驶方向。第 18 届 SIGSPATIAL 地理信息系统进展国际会议论文集,GIS '10,第 99-108 页,纽约,纽约州,美国,2010 年。ACM。

相关文章

您想从头开始构建地图吗?

阅读这篇文章

如何使用 FFT 进行快速乘法运算

原文:https://towardsdatascience.com/how-to-perform-fast-multiplications-in-science-using-the-fft-b751fafc2bac

当前的深度学习工作流依赖于成千上万的整数乘法,因此获得高效的乘法性能现在至关重要。

照片由 Unsplash 上的 Gsightfotos 拍摄

乘法运算是许多科学和数据科学应用中的核心。这种操作的复杂性不是线性的,因此在时间上对其进行缩放可能是一项难以实现的任务。当前的深度学习工作流依赖于成千上万的整数乘法,并且这个数字随着 DL 架构的复杂性或训练模型的可用数据而增长。因此,如今获得高效的乘法性能至关重要。本文展示了如何使用 20 世纪最重要的信号发现快速傅立叶变换来执行整数乘法。

不仅深度学习卷积依赖于整数乘法,其他科学和计算应用,如高倍渲染分形图像和公钥密码学,都依赖于整数乘法。经典的向量乘法复杂度为 O(N),其中 N 是位数。几乎可以说,O(logN)以上的任何复杂度都很难在众核平台上扩展,这意味着尽管我们的云基础设施中的计算单元数量增加了,但它将成为我们计算的瓶颈。任何编译器优化,以及其他性能技术,如平铺或缓存策略,都是无用的,除非降低二次复杂度。有可能降低传统乘法运算的复杂性吗?是的,它是。

一切都是关于多项式的

在解释如何降低乘法运算的复杂度之前,我先给大家演示一下任意一个基数为 x 的整数都可以分解成一个多项式系数向量。生成的多项式由一组系数描述,原始整数通过计算基数为 x: 的多项式来构建

作者图片

系数的个数等于位数;也就是多项式的大小。这被称为系数表示。请记住,在数学课中,两个多项式的乘积会产生第三个大小为 2N、的多项式,这个过程称为矢量卷积。

上面我声称任何具有 N 位数的整数都可以分解成一个大小为 N、的多项式,并且两个大小为 N 的多项式的乘积是另一个大小为 2N 的多项式。下一个问题是知道如何执行多项式乘法:

作者图片

正如我在上面的图片中指出的,卷积两个多项式的自然方法是利用分配特性,逐项相乘,然后通过添加相同多项式次数的系数来减少冗余项。这就是我之前提到的经典乘法,有 O(N)步。然而,看看我在图像上标记的点。每个点都有坐标(I,P(i)),其中 P(i)是 x=i 时 P(x)的值。任何次数为 d 的多项式都由平面上的 d+1 个点定义,这称为值表示。FFT 乘法背后的思想是对至少 d+1 个点(x_i,A(x_i))和(x_i,B(x_i))的 A(x)和 B(x)进行采样,然后简单地将函数值一个接一个地相乘(成对乘积),以便获得两个多项式的值表示:

与系数表示乘法相比,值表示乘法大大减少了所执行的运算的数量。因此,想法是从系数表示变为值表示,以成对的方式执行乘法,并且将值表示变换回系数表示。在理解如何做之前,我们需要更多的概念。

虚拟离散傅立叶变换

好了,在更新了我们的多项式知识之后,我们现在能够深入信号世界了。如果你从来没有听说过傅立叶变换,你只需要知道信号可以分解为其他信号的总和。时域图显示信号幅度如何随时间变化,而频域图显示信号如何位于一个频率范围内的每个频带内:

作者图片

傅立叶变换将任何信号分解成复杂的正弦和余弦波的总和。虽然它可以应用于连续波和离散波,但我在本文中只关注离散波,也就是离散傅立叶变换(DFT)。DFT 是允许从一个域转换到另一个域的函数,FFT 是一种非常高效地计算 DFT 的算法,但我们将在稍后讨论。

作者图片

现在我们对多项式和 DFT 有了一个整体的概念,所以我们可以继续我们的乘法问题。我们说过:

因此,想法是从系数表示变为值表示,以成对的方式执行乘法,并且将值表示变换回系数表示。

理解 FFT 的直观方法

也许你在想,DFT 可以帮助你从一种表示转换到另一种表示。你是对的,让我们看看为什么。我们说过,我们至少需要对 d+1 个点进行采样,以获得精确定义多项式的多项式值。有一些技巧可能有助于进一步减少样本评估的数量:

作者图片

如果我们能够应用一些多项式性质,我们可以减少我们需要的样本评估的数量。请记住,在偶数多项式中,P(-x)=P(x)是正确的,这意味着它关于 y 轴对称。让我们把多项式 P(x)分解成偶数多项式:P(x)=P_e(x) + x*P_o(x):

作者图片

在这种情况下,点 -k 的多项式求值重用了 k 的多项式求值:

作者图片

这意味着我们可以改为评估 n/2 点(互补的 n/2 点是即时获得的),这进一步减少了运算次数。在这一点上,你可能在考虑一个递归过程,你是对的。我们可以如下直观地构建这个过程。对于给定的多项式 P(x)n 个点(实际上是 n/2 个成对点),我们一方面变换 P(x)=P_e(x )+x*P_o(x)并在 n/2 个正点上递归求 P_e 多项式;并且还在相同的 n/2 正点上递归地评估 P_o。在得到他们的结果后,很容易得到对剩余的 n/2 负面点的 P(x)评价:

作者图片

下一个要回答的问题是我们选择哪 n 个点来评估我们的多项式。我们能选择任意一组对数吗?不,我们不能:

  1. 我们将一半的点传递到下一个递归层次。该算法假设多项式在每次递归调用时都有正负成对的求值点。但是,每个点都是平方的,最后都是正的。有没有一个数即使在平方时也能保持符号不变?答案是复数 i
  2. 除此之外,每一个递归层次都依赖于这样一个事实,即接收点的后一半与前一半相等,但符号相反。这最终成为一个方程组,递归的底层将有一个值为 1 的单点。有不同的方法可以解决这个问题,但是最直接的方法是使用单位的 N 次方根(找到当被提升到某个正整数 N 次幂时产生 1 的)。

假设我们的 n 等于 12,求解单位的 12 次方根给出以下几点来评价:

来源 aski tians

请注意,我们将有 2 的幂级递归,因此很容易找到 n 作为大于 d+1,的 2 的最小幂,即使我们只计算其中的 n/2 。好消息是,我们刚刚完成了最重要的信号处理算法!这种算法被称为快速傅立叶变换

让我们将所有这些放入一个伪代码中:

可还原的 Youtube 频道

由于 FFT,我们已经获得了应用离散傅立叶变换的每个多项式的值表示,并且这是在仅仅 O(logN) 复杂度下完成的。为了将两个多项式在值表示中相乘,我们只需对每个点上的函数求值进行成对乘法,其中成对乘法意味着将向量成对地、逐个元素地相乘,这在计算上来说是非常便宜的。

大整数乘法的 Strassen FFT 算法

这个算法是由 Strassen 和 Schö nhage 在 1971 年发明的,但是在本文的这一点上,你将能够很容易地理解它。

如果我们想将两个大整数 AB 相乘,大小为 N,我们首先将它们转换成以 x 为基数的多项式系数表示。我们将得到的系数分别存储到矢量 ab 中。根据卷积定理,如果 c 是两个输入向量 abc = a b ,那么 c 的离散傅里叶变换(DFT)等于每个输入向量的 DFT 变换的两两两相乘, DFT(c) = DFT(a)DFT(b)

因此, c 向量也可以作为该成对乘法的离散傅立叶逆变换(IDFT)来获得, c = IDFT(DFT(a)DFT(b))。

如果输入向量不具有相同的长度, M < N ,则最短的一个用零填充,直到 M = N 。最后,系数必须归一化到与表示整数的基数相同的基数,这一步通常称为“T4”,称为进位传播。这很重要,因为由于成对乘法的性质,在逆 FFT 之后, c 的每个元素将容纳比基数 x 大的整数。下图显示了进位传播方法的一个示例,其中元素最终保留在基数为 10 的中。

作者图片

计算方法

在实现 Strassen 算法时,大多数现有库不使用复数域中的 FFT。在复数域中,整数系数被转换成复数。在执行逆 FFT 运算后,最终得到类似于 14.999878 的值,而不是 15 。相比之下,大多数实现使用有限域 Z=pZ ,其中素数 p. 在这种情况下,希望使用一个 p 数来最小化模运算的延迟,并且在大多数情况下为此选择费马素数

然而,除了找到单位的第 n 个根之外,有限域还有几个重要的限制:

-最大值必须适合该字段,即 (n/2)(x-1) < p
-乘入 Z=pZ 必须取模 p ,因此快速取模 p 运算符的存在是可取的(就像蒙哥马利约简算法)。

传统上,有限域上的实现不如复数域上的实现有效,因为需要不同的模运算。在最近的这篇论文中,我们已经证明了 Strassen 算法和 FFT 在复数域上的运行比其他方法更好,并且它非常适合 GPU 架构。我们还从数学上证明了对少于 50 万位数的整数使用它是安全的(尽管是在复数上工作)。

这里要理解的重要主题是,尽管经典乘法对于小尺寸运算可以执行得很好,但其复杂性从不存在。当增加位数时,尽管进行了平铺等优化,性能还是会下降,因为它的 O(N)。取而代之的是 Strassen 算法,wit h O(Nlog N (log log N)) 在统计所有涉及的运算时,要快得多。下图描绘了实/复 FFT Strassen 实现(通过两个不同的库 ID/CuFFT)与经典算法的基于平铺的实现的性能对比:

作者图片

Adrian Perez 在伯克利实验室从事研究,拥有超级计算并行算法的博士学位。你可以在他的 中简介 中查看更多关于他的西班牙语和英语内容。

参考书目

迭格斯等人。GPU 上高效的高精度整数乘法。国际高性能计算应用杂志 (2022)。

如何在数据科学项目中执行功能选择

原文:https://towardsdatascience.com/how-to-perform-feature-selection-in-a-data-science-project-591ba96f86eb

特征选择的四种方法和整个过程,并附有 Python 示例

弗拉季斯拉夫·巴比延科在 Unsplash 上的照片

特征选择是数据科学项目的重要组成部分。当您处理(非常)大的数据集时,您应该始终问自己两个问题:

  1. 这些特征代表什么?
  2. 这些特性都重要吗?

第二个问题的答案将我们引向特性选择;事实上,您不希望在数据框中包含无意义的要素:这是对计算的浪费。

在这篇文章中,我们将看到四种功能选择的方法,我还将描述一个功能选择的过程(一般来说,你很难只应用下面的方法之一来做功能选择的工作)。

1.相关矩阵

相关矩阵帮助我们找到特征和标签之间的线性关系,甚至特征本身之间的线性关系。当一些特征高度相关时,我们可以决定丢弃它们,因为当两个特征高度相关时,它们对结果有相同的影响。

那么,让我们看看我们能做些什么,用相关矩阵。下面,一个取自我的一个项目的例子;假设我们有一个数据框架“df”(数据集细节无关紧要);让我们创建它的相关矩阵:

import matplotlib.pyplot as plt
import seaborn as sns#figure size
plt.figure(figsize=(20, 10))#heat map for correlation coefficient
sns.heatmap(df.corr(), annot=True, fmt="0.1")

相关矩阵。图片作者。

有许多相关的特征;例如:

  • 基线值和直方图模式
  • 基线值和直方图中值
  • 直方图模式、istogram 均值和直方图中值
  • 直方图 _ 宽度和直方图 _ 最小值

让我们只关注相关性,而不是这些特征(和标签)代表什么;我想看看这些变量之间可能的相关性的图示:

#creating a subtdataframe
a = df[['baseline value', 'histogram_mode', 'histogram_median', 'histogram_mean', 'histogram_width', 'histogram_min']]#creating a unique plot with the regressions
g = sns.PairGrid(a)
g = g.map_upper(sns.regplot, scatter_kws={'alpha':0.15}, line_kws={'color': 'red'})

具有上述特征回归线的散点图。作者图片,

因此,从图表中可以看出,上述特征确实是高度相关的;所以,我可以选择删除一部分。例如,通过交叉各种图形,我选择消除以下特征
(消除更多特征会导致一些数据丢失,因为它们都是相互交叉的):

  • 直方图 _ 最小值
  • 直方图 _ 平均值

2.套索回归

如果您正在处理线性回归问题,执行特征选择的另一种方法是应用套索正则化模型

在这种类型的正则化中,与线性模型相关的一些系数可以变为零,并且可以从模型中消除。这意味着 Lasso 回归模型也执行要素选择。如果你想知道更多的细节,我已经在这里写了一篇专门的文章。

3.互信息方法

前面看到的方法是在整个数据集上执行的。这个和下面的方法必须在分割数据集上执行(你可以在这里看到关于主题的有趣讨论)。最后一条评论是最重要的一条)。

让我们考虑一下本教程第 1 点中看到的数据集,并考虑我们刚刚分割了数据集。现在,我们有:

#mutual information selecting all features
mutual = SelectKBest(score_func=mutual_info_classif, k='all')#learn relationship from training data
mutual.fit(X_train, y_train)# transform train input data
X_train_mut = mutual.transform(X_train)# transform test input data
X_test_mut = mutual.transform(X_test)#printing scores of the features
for i in range(len(mutual.scores_)):
    print('Feature %d: %f' % (i, mutual.scores_[i]))------------------->>>Feature 0: 0.124999
Feature 1: 0.139990
Feature 2: 0.031640
Feature 3: 0.092322
Feature 4: 0.066883
Feature 5: 0.002289
Feature 6: 0.008455
Feature 7: 0.194067
Feature 8: 0.222438
Feature 9: 0.144378
Feature 10: 0.034891
Feature 11: 0.118958
Feature 12: 0.025970
Feature 13: 0.033416
Feature 14: 0.015075
Feature 15: 0.108909
Feature 16: 0.085122
Feature 17: 0.103669
Feature 18: 0.000000

因此,这种方法利用评分方法,在某种程度上赋予特征以重要性。让我们用图表来看一下:

#plot the scores
plt.bar([i for i in range(len(mutual.scores_))], mutual.scores_)
plt.show()

互信息法评分。图片作者。

在结论中,我们将讨论何时使用这种方法。

4.方差分析 f 检验

让我们考虑和以前一样的数据集;我们刚刚拆分了数据,因此可以直接应用该方法:

# configure to select all features
an = SelectKBest(score_func=f_classif, k='all')# learn relationship from training data
an.fit(X_train, y_train)# transform train input data
X_train_an = an.transform(X_train)# transform test input data
X_test_an = an.transform(X_test)#printing scores of the features
for i in range(len(an.scores_)):
    print('Feature %d: %f' % (i, mutual.scores_[i]))------------------->>>Feature 0: 0.117919
Feature 1: 0.176444
Feature 2: 0.006887
Feature 3: 0.089149
Feature 4: 0.064985
Feature 5: 0.054356
Feature 6: 0.090783
Feature 7: 0.144446
Feature 8: 0.191335
Feature 9: 0.200292
Feature 10: 0.081927
Feature 11: 0.096509
Feature 12: 0.000000
Feature 13: 0.042977
Feature 14: 0.105467
Feature 15: 0.027062
Feature 16: 0.072015
Feature 17: 0.198037
Feature 18: 0.018785

甚至在这里用图形显示:

# plot the scores
plt.bar([i for i in range(len(an.scores_))], an.scores_)
plt.show()

方差分析 f 检验法得分。图片作者。

如你所见,这种方法和互信息方法在特征重要性方面的结果确实不同;我们将在下一段中看到何时选择一个,何时选择另一个。

特征选择和结论的过程

要选择特征,您可以遵循以下过程:

  1. 绘制相关矩阵,对整个数据集进行计算,并决定是否有一些可以消除的特征(我们说的是高度相关的特征。用回归线画一个散点图来确定线性路径,就像我上面做的那样)。
  2. 仅当问题是回归时,才选择套索回归变量。要使用的模型是线性的,并且存在“大量”要素。
  3. 将数据集分成训练集和测试集,然后在互信息和 Anova f-test 之间选择一种方法。
    Anova f-test 能够“感觉到”特征之间的线性相关性,而互信息“感觉到”任何类型的相关性,特别是“感觉到”非线性相关性(也可在此处阅读文档)。在上面看到的情况下,考虑到使用相关矩阵获得的结果以及随后使用线性回归图消除两个特征,那么,一致地,互信息比 Anova f-test 指示更好,这是对于这种类型的问题真正重要的特征。

我们一起连线吧!

中等

LINKEDIN (向我发送连接请求)

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

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

如何对公司财报电话会议进行情感分析

原文:https://towardsdatascience.com/how-to-perform-sentiment-analysis-on-earnings-call-of-companies-122275f47e26

利用 Python 和人工智能部署情感分析来分析公司的收益电话

杰里米·贝赞格在 Unsplash 上的照片

识别特定句子主体背后的情感情绪非常重要,尤其是当它涉及大型科技巨头时。情感分析是自然语言处理的一个重要组成部分,小型和大型科技公司和企业都需要并使用它来了解客户的观点。

公司的收益电话会议通常是一个电话会议或网络直播,在这里上市公司讨论其特定报告期的财务结果。在这种情况下,大部分的关键点被讨论,使用它我们可以有一个公司的关键成功的轮廓。因此,利用人工智能解决这样一个问题来分析情绪,可以为任何公司创造一个奇妙的轮廓。

在本文中,我们将借助 Python 脚本和 AssemblyAI 平台部署一个项目,对公司的收益电话进行情绪分析。如果观众不熟悉类似的 NLP 任务,我建议通过下面提供的链接查看我以前的一篇文章,这篇文章介绍了部署优化的语音到文本 web 应用程序的概念。

公司盈利预测情绪分析项目:

在这个项目中,我们将利用 Python 脚本、AssemblyAI 平台和 streamlit 框架来开发一个用于项目部署的网站。对于这个项目,我们将使用三个独立的文件。在第一个文件中,我们将存储从 AssemblyAI 网站获得的配置 API 密钥。我们将创建第二个文件,用于下载和保存特定的 YouTube 文件。最后,我们将在最终的 Python 文件中开发情感分析的主要网站和计算。

API 密钥的配置:

为了开始这个项目,我建议检查一下 AssemblyAI 平台。在这里,您可以获得一个 API 密钥,通过它我们可以对公司的收益电话执行情绪分析项目。如果您还没有帐户,可以遵循简单的注册流程。只要你登录,你就可以在你的 AssemblyAI 账户的右边访问你的免费 API 密匙。将它复制并放入 Python 文件 configure.py.

auth_key = "Enter Your API Key Here"

保存音频数据:

在下一个 Python 文件中,我们将保存从 YouTube 下载的音频数据。在这一节中,我们将导入 youtube_dl 库,如果您还没有这个库,可以用一个简单的 pip install 命令安装它。一旦库被导入,我们将创建一个包含所有基本参数的变量。我们将下载 mp3 格式的音频数据,并以最佳音频格式保存。如下面的代码块所示,可以完成这个操作。

import youtube_dlydl_opts = {
   'format': 'bestaudio/best',
   'postprocessors': [{
       'key': 'FFmpegExtractAudio',
       'preferredcodec': 'mp3',
       'preferredquality': '192',
   }],
   'ffmpeg-location': './',
   'outtmpl': "./%(id)s.%(ext)s",
}

一旦我们声明了必要的参数,我们就可以创建一个函数来帮助我们将所需的 YouTube 视频保存为最好的音频文件 mp3 格式。我们将获得这个想法,去掉任何空格,并传递 id 来提取信息。一旦视频文件被下载,它将被存储在当前的工作目录。你可以随心所欲地改变路径。下面的代码代表了下面的函数。

def save_audio(link):
  _id = link.strip() def get_vid(_id):
    with youtube_dl.YoutubeDL(ydl_opts) as ydl:
      return ydl.extract_info(_id) # download the audio of the YouTube video locally
  meta = get_vid(_id)
  save_location = meta['id'] + ".mp3" print('Saved mp3 to', save_location) return save_location

我们可以将这个文件保存为 save_audio.py ,并从下一节开始继续构建主应用程序。

导入基本库:

在创建了两个主要的 Python 文件之后,我们可以继续创建名为 app.py 的主文件,用于开发网站界面和相应地计算情感分析。我们将首先导入项目的所有必要需求,包括我们之前创建的两个 Python 文件。

import streamlit as st
from save_audio import save_audio
from configure import auth_key
import pandas as pd
from time import sleep
import urllib.request
import plotly.express as px
import plotly.graph_objects as go
from urllib.request import urlopen
from bs4 import BeautifulSoup
import json
import requests

每一个库都将被用来创建网站,提供统计图表,用于分析公司报告的各种参数。

设置所有必需的元素:

在这一节中,我们将设置所有必要的需求,这些需求对于查看用于情绪分析的各种图表是必要的,包括所需变量的初始化。首先,让我们创建端点并相应地初始化头部。转录端点包含 AssemblyAI 平台的位置,音频数据的转录在该位置可用。类似地,我们也有一个上传端点和带有 AssemblyAI 授权 API 密钥的头分配。

## AssemblyAI endpoints and headers
transcript_endpoint = "[https://api.assemblyai.com/v2/transcript](https://api.assemblyai.com/v2/transcript)"
upload_endpoint = '[https://api.assemblyai.com/v2/upload'](https://api.assemblyai.com/v2/upload')headers_auth_only = {'authorization': auth_key}
headers = {
   "authorization": auth_key,
   "content-type": "application/json"
}

一旦我们初始化了所需的参数,最好是设置一些与情感分析的目的相关的解释。我们可以利用 streamlit 库中可用的标题、说明和副标题来创建网站的一些主要元素。

## App explanation
st.title('Sentiment analysis of earning calls')
st.caption('With this app you can analyse the sentiment of earnings calls by providing a YouTube link to its recording.')
st.subheader('Submit a video link or choose one of the pre-determined ones to analyse.')st.subheader('Submit a video link or choose one of the pre-determined ones to analyse.')

在下一步中,我们将创建一个文本输入栏,用户可以在其中输入一个指向特定公司收益电话会议的特定链接。所提供链接的数据(通常是 YouTube 视频)将以最佳音频格式下载,并保存在本地工作目录中。一旦数据被下载,我们将把数据以块的形式上传到 AssemblyAI 网站,并获得上传的音频 URL。我们还指定了一个默认链接,允许我们访问 Amazon 的一个收益电话会议。

# Get link from user
video_url = st.text_input(label='Earnings call link', value="[https://www.youtube.com/watch?v=UA-ISgpgGsk](https://www.youtube.com/watch?v=UA-ISgpgGsk)")# Save audio locally
save_location = save_audio(video_url)## Upload audio to AssemblyAI
CHUNK_SIZE = 5242880def read_file(filename):
 with open(filename, 'rb') as _file:
  while True:
   data = _file.read(CHUNK_SIZE)
   if not data:
    break
   yield dataupload_response = requests.post(
 upload_endpoint,
 headers=headers_auth_only, data=read_file(save_location)
)audio_url = upload_response.json()['upload_url']
print('Uploaded to', audio_url)

现在我们已经完成了将音频数据上传到 AssemblyAI 网站,我们可以开始转录音频文件了。我们将提供上传的音频 URL,并将情感分析的条件指定为真。设置好这些参数后,我们就可以继续接收副本响应和副本 id 了。最后,设置用于执行转录的轮询端点。

## Start transcription job of audio file
data = {
 'audio_url': audio_url,
 'sentiment_analysis': 'True',
}transcript_response = requests.post(transcript_endpoint, json=data, headers=headers)
print(transcript_response)transcript_id = transcript_response.json()['id']
polling_endpoint = transcript_endpoint + "/" + transcript_idprint("Transcribing at", polling_endpoint)

作者图片

我们可以检查程序的完成状态,并在 While 循环的帮助下等待转录过程完成。一旦转录过程完成,我们可以获得我们可以显示给用户查看的抄本。但是对于这一步,我们将只存储收到的副本响应的文本。

## Waiting for transcription to be done
status = 'submitted'
while status != 'completed':
 print('not ready yet')
 sleep(1)
 polling_response = requests.get(polling_endpoint, headers=headers)
 transcript = polling_response.json()['text']
 status = polling_response.json()['status']

一旦我们完成了本节中提到的所有步骤,我们就可以进入下一节,可视化通过对上传的数据执行情感分析而获得的结果。

通过可视化分析众多组件:

作者图片

一旦从音频文件的转录中创建了转录,我们就获得了可以显示的文本数据。我们可以在网站的侧边栏展示它们。我们还将获得情感分析结果,并将它们转换成 pandas 数据框架,以便更容易对其进行分析。

# Display transcript
print('creating transcript')
st.sidebar.header('Transcript of the earnings call')
st.sidebar.markdown(transcript)print(json.dumps(polling_response.json(), indent=4, sort_keys=True))## Sentiment analysis response 
sar = polling_response.json()['sentiment_analysis_results']## Save to a dataframe for ease of visualization
sen_df = pd.DataFrame(sar)
print(sen_df.head())

我们可以借助美汤库获得视频的标题,并在网站上展示。我们还将打印句子的总数,并相应地显示信息。

## Get the title of this video
with urlopen(video_url) as url:
    s = url.read()
    soup = BeautifulSoup(s)
    title = soup.title.stringst.header(title)## Visualizations
st.markdown("### Number of sentences: " + str(sen_df.shape[0]))grouped = pd.DataFrame(sen_df['sentiment'].value_counts()).reset_index()
grouped.columns = ['sentiment','count']
print(grouped)col1, col2 = st.columns(2)

让我们创建第一个条形图,以了解收益电话数据的句子中涉及的积极、中性或消极情绪的数量。您可以使用下面代码块中指定的参数来绘制图形,也可以选择使用不同的配色方案和其他类似的功能。

# Display number of positive, negative and neutral sentiments
fig = px.bar(grouped, x='sentiment', y='count', color='sentiment', color_discrete_map={"NEGATIVE":"firebrick","NEUTRAL":"navajowhite","POSITIVE":"darkgreen"})fig.update_layout(
 showlegend=False,
    autosize=False,
    width=400,
    height=500,
    margin=dict(
        l=50,
        r=50,
        b=50,
        t=50,
        pad=4
    )
)col1.plotly_chart(fig)

条形图可能并不总是指示分析任何问题所需的真实感知。因此,我们将使用一个指标来表示我们是否有更多的积极或消极的回应。我们将计算情绪得分,如下面的代码块所示,并分析指标。向上的箭头表示肯定的指示,而否定的指示将通过向下的指示器表示。查看上图有更直观的理解。

## Display sentiment score
pos_perc = grouped[grouped['sentiment']=='POSITIVE']['count'].iloc[0]*100/sen_df.shape[0]
neg_perc = grouped[grouped['sentiment']=='NEGATIVE']['count'].iloc[0]*100/sen_df.shape[0]
neu_perc = grouped[grouped['sentiment']=='NEUTRAL']['count'].iloc[0]*100/sen_df.shape[0]sentiment_score = neu_perc+pos_perc-neg_percfig = go.Figure()fig.add_trace(go.Indicator(
    mode = "delta",
    value = sentiment_score,
    domain = {'row': 1, 'column': 1}))fig.update_layout(
 template = {'data' : {'indicator': [{
        'title': {'text': "Sentiment score"},
        'mode' : "number+delta+gauge",
        'delta' : {'reference': 50}}]
                         }},
    autosize=False,
    width=400,
    height=500,
    margin=dict(
        l=20,
        r=50,
        b=50,
        pad=4
    )
)col2.plotly_chart(fig)

最后,我们还将创建一个散点图,以便更好地可视化情感。如下面的代码片段所示,可以创建这种可视化。

## Display negative sentence locations
fig = px.scatter(sar, y='sentiment', color='sentiment', size='confidence', hover_data=['text'], color_discrete_map={"NEGATIVE":"firebrick","NEUTRAL":"navajowhite","POSITIVE":"darkgreen"})fig.update_layout(
 showlegend=False,
    autosize=False,
    width=800,
    height=300,
    margin=dict(
        l=50,
        r=50,
        b=50,
        t=50,
        pad=4
    )
)st.plotly_chart(fig)

完成所有这些可视化后,我们现在对一家公司的盈利预测背后的情绪有了一个简单的理解。我们可以预测他们对未来的乐观程度。

最终设置:

作者图片

请注意,以下项目的运行时间取决于许多因素。根据系统类型、上传速度和其他因素,每个用户获得结果的速度可能有所不同,通常需要几分钟。

对于最后的设置,我建议查看下面的 GitHub 链接,它涵盖了成功部署以下项目所需的全部代码和需求。我还建议查看下面的视频教程,它以简洁的方式涵盖了以下主题,涵盖了与该项目相关的大多数复杂细节。

结论:

照片由腾雅特Unsplash 上拍摄

自然语言处理的很大一部分涉及大量原始数据的处理。人工智能最难完成的任务之一是分析情感的真实情绪,并理解语言的语义。AI 有时可能很难区分讽刺和其他条件语句。然而,现代 AI 正在迎头赶上,我们可以预测这些复杂的情感分析模式。

在本文中,我们探索了使用 Python 脚本和 AssemblyAI 平台生成高质量结果的实用性。我们在 YouTube 上下载了一段公司财报电话会议的视频,并开始对其进行情绪分析。我们能够从统计可视化中获得一份相当不错的报告,从而得出对未来公司销售的总体乐观和悲观反应。

如果你想在我的文章发表后第一时间得到通知,请点击下面的链接订阅邮件推荐。如果你希望支持其他作者和我,请订阅下面的链接。

https://bharath-k1297.medium.com/membership

如果你对这篇文章中提到的各点有任何疑问,请在下面的评论中告诉我。我会尽快给你回复。

看看我的一些与本文主题相关的文章,你可能也会喜欢阅读!

谢谢你们坚持到最后。我希望你们都喜欢这篇文章。祝大家有美好的一天!

如何使用 OpenAI 的 Whisper 执行语音到文本转换并将任何语音翻译成英语

原文:https://towardsdatascience.com/how-to-perform-speech-to-text-and-translate-any-speech-to-english-with-openais-whisper-50e3a366cbca

如何使用前沿的 NLP 模型进行音频转录到文本和机器翻译。

介绍

OpenAI 是人工智能领域的纯粹玩家,并向社区提供了许多人工智能模型,包括、 CLIP 等。

由 OpenAI 开源的 Whisper 模型被认为在英语语音识别中已经接近人类水平的鲁棒性和准确性。

本文将尝试向您介绍使用 HugginFaces Transformers 框架,通过 OpenAI 的 Whisper 将长段音频转换成文本信息的所有步骤。

在这篇文章的结尾,你将能够把英语和非英语的音频翻译成文本。

OpenAI 的耳语— Kézako?

已经开发了耳语模型来研究用于语音识别和翻译任务的语音处理系统的能力。他们有能力将语音音频转录成文本。

根据 680,000 小时的标记音频数据进行训练,作者报告称这是监督语音识别领域有史以来最大的一次训练。此外,通过对一系列中等大小的模型进行训练来评估模型的性能,这些模型基于对应于完整数据集大小的 0.5%、1%、2%、4%和 8%的二次抽样版本的数据,如下所示。

原始训练数据的 5 个不同的二次抽样版本(图片由作者提供)

逐步实施

本节涵盖了从安装和导入相关模块到实施音频转录和翻译案例的所有步骤。

安装和初始化

首先,您需要在计算机上安装 Python 和 Whisper 库,最新的稳定版本可以使用 Python 包管理器pip安装,如下所示:

!pip install git+https://github.com/openai/whisper.git 

现在,我们需要安装并导入用于音频和视频处理的ffmpeg模块。根据您的操作系统,安装过程可能有所不同。

由于我用的是 MAC,下面是相应的流程:

# Installation for MAC
brew install ffmpeg

请参考适合您情况的正确代码片段

# on Ubuntu or Debian
sudo apt update && sudo apt install ffmpeg

# on Windows using Chocolatey (https://chocolatey.org/)
choco install ffmpeg

# on Windows using Scoop (https://scoop.sh/)
scoop install ffmpeg

如果您不想为所有这些配置费心,该怎么办呢?

→在这种情况下,Google collab 可以拯救你的生命,它还提供了一个免费的 GPU,你可以按如下方式访问:

在 Google Colab 上使用 GPU 的运行时配置(图片来自作者)

使用nvidia-smi我们可以有关于分配给你的 GPU 的信息,这是我的。

!nvidia-smi

我的 Google Colab 上的 GPU 信息(图片由作者提供)

一旦您安装了所有的东西,您就可以导入模块并加载模型了。在我们的例子中,我们将使用具有 1550M 参数的大型模型,并且需要大约 10g 字节的 VRAM 存储器。无论您使用的是 CPU 还是 GPU,处理时间都可能会更长或更快。

# Import the libraries 
import whisper
import torch
import os

# Initialize the device
device = "cuda" if torch.cuda.is_available() else "cpu"

# Load the model 
whisper_model = whisper.load_model("large", device=device)
  • load_model()函数中,我们使用了之前行中初始化的device。默认情况下,如果没有另外指定,新创建的张量是在 CPU 上创建的。

现在是开始提取音频文件的时候了…

音频转录

本节说明了 Whisper 在录制不同语言的音频方面的优势。

这一部分的一般工作流程如下。

文章的语音转文本工作流(图片由作者提供)

前两步是用下面的助手函数执行的。但在此之前,我们需要使用下面的pip语句安装[pytube](https://pytube.io/en/latest/)库,以便从 YouTube 下载音频。

# Install the module
!pip install pytube

# Import the module
from pytube import YouTube

然后,我们可以如下实现助手函数:

def video_to_audio(video_URL, destination, final_filename):

  # Get the video
  video = YouTube(video_URL)

  # Convert video to Audio
  audio = video.streams.filter(only_audio=True).first()

  # Save to destination
  output = audio.download(output_path = destination)

  _, ext = os.path.splitext(output)
  new_file = final_filename + '.mp3'

  # Change the name of the file
  os.rename(output, new_file)

该函数有三个参数:

  • video_URLYouTube 视频的完整网址。
  • destination保存最终音频的位置。
  • final_filename最终音频的名称。

最后,我们可以使用功能下载视频并将其转换为音频。

英语转录

这里使用的视频是来自激励 Quickie 的 YouTube 上的 30 秒激励演讲。只有前 17 秒对应于真实的语音,而语音的其余部分是噪声。

# Video to Audio
video_URL = 'https://www.youtube.com/watch?v=E9lAeMz1DaM'
destination = "."
final_filename = "motivational_speech"
video_to_audio(video_URL, destination, final_filename)

# Audio to text
audio_file = "motivational_speech.mp3"
result = whisper_model.transcribe(audio_file)

# Print the final result
print(result["text"])
  • videoURL是励志演讲的链接。
  • destination是我当前文件夹对应的.
  • motivational_speech将是音频的最终名称。
  • whisper_model.transcribe(audio_file)将模型应用于音频文件以生成转录。
  • transcribe()功能通过滑动 30 秒窗口对音频进行预处理,并执行自回归序列到序列方法对每个窗口进行预测。
  • 最后,print()语句生成以下结果。
I don't know what that dream is that you have. 
I don't care how disappointing it might have been as you've 
been working toward that dream. 
But that dream that you're holding in your mind that it's possible.

下面是相应的视频,你可以播放来检查之前的输出。

非英语转录

除了英语,Whisper 还可以处理非英语语言。让我们来看看 YouTube 上对阿拉萨内·德拉马纳·瓦塔拉的采访。

与前面的方法类似,我们获取视频,将其转换为音频并获取内容。

URL = "https://www.youtube.com/watch?v=D8ztTzHHqiE"
destination = "."
final_filename = "discours_ADO"
video_to_audio(URL, destination, final_filename)

# Run the test
audio_file = "discours_ADO.mp3"
result_ADO = whisper_model.transcribe(audio_file)

# Show the result
print(result_ADO["text"])

→视频讨论:

阿拉萨内总统在 YouTube 上关于法郎 CFA 的讨论

→来自print()语句的模型结果。

下面是最终的结果,结果是令人兴奋的🤯。唯一被拼错的信息是“法郎 CFA ”,而模型将其识别为“前线 CFA”😀。

Le Front CFA, vous l'avez toujours défendu, bec et ongle, est-ce que vous 
continuez à le faire ou est-ce que vous pensez qu'il faut peut-être changer 
les choses sans rentrer trop dans les tailles techniques? Monsieur Perelman, 
je vous dirais tout simplement qu'il y a vraiment du n'importe quoi dans ce 
débat. Moi, je ne veux pas manquer de modestie, mais j'ai été directeur des 
études de la Banque Centrale, j'ai été vice-gouverneur, j'ai été gouverneur 
de la Banque Centrale, donc je peux vous dire que je sais de quoi je parle. 
Le Front CFA, c'est notre monnaie, c'est la monnaie des pays membres et nous 
l'avons acceptée et nous l'avons développée, nous l'avons modifiée. J'étais 
là quand la reforme a eu lieu dans les années 1973-1974, alors tout ce débat 
est un nonsense. Maintenant, c'est notre monnaie. J'ai quand même eu à 
superviser la gestion monétaire et financière de plus de 120 pays dans le 
monde quand j'étais au Fonds Monétaire International. Mais je suis bien placé 
pour dire que si cette monnaie nous pose problème, écoutez, avec les autres 
chefs d'État, nous prendrons les décisions, mais cette monnaie est solide, 
elle est appropriée. Les taux de croissance sont parmi les plus élevés sur le 
continent africain et même dans le monde. Le Côte d'Ivoire est parmi les dix 
pays où le taux de croissance est le plus élevé. Donc c'est un nonsense, 
tout simplement, de la démagogie et je ne souhaite même pas continuer ce débat 
sur le Front CFA. C'est la monnaie des pays africains qui ont librement 
consenti et accepté de se mettre ensemble. Bien sûr, chacun de nous aurait pu 
avoir sa monnaie, mais quel serait l'intérêt? Pourquoi les Européens ont 
décidé d'avoir une monnaie commune et que nous les Africains ne serons pas en 
mesure de le faire? Nous sommes très fiers de cette monnaie, elle marche bien, 
s'il y a des adaptations à faire, nous le ferons de manière souveraine.

非英语翻译成英语

除了语音识别、口语识别和语音活动识别之外,Whisper还能够执行从任何语言到英语的语音翻译。

在这最后一部分,我们将生成以下喜剧法语视频的英语转录。

来自 YouTube 的漫画视频

这个过程与我们上面看到的没有太大的变化。主要变化是在transcribe()功能中使用了task参数。

URL = "https://www.youtube.com/watch?v=hz5xWgjSUlk"
final_filename = "comic"
video_to_audio(URL, destination, final_filename)

# Run the test
audio_file = "comic.mp3"
french_to_english = whisper_model.transcribe(audio_file, task = 'translate')

# Show the result
print(french_to_english["text"])
  • task=’translate’意味着我们正在执行一项翻译任务。下面是最终结果。
I was asked to make a speech. I'm going to tell you right away, 
ladies and gentlemen, that I'm going to speak without saying anything. 
I know, you think that if he has nothing to say, he would better shut up. 
It's too easy. It's too easy. Would you like me to do it like all those who 
have nothing to say and who keep it for themselves? Well, no, ladies and 
gentlemen, when I have nothing to say, I want people to know. I want to make 
others enjoy it, and if you, ladies and gentlemen, have nothing to say, well, 
we'll talk about it. We'll talk about it, I'm not an enemy of the colloquium. 
But tell me, if we talk about nothing, what are we going to talk about? Well, 
about nothing. Because nothing is not nothing, the proof is that we can 
subtract it. Nothing minus nothing equals less than nothing. So if we can find 
less than nothing, it means that nothing is already something. We can buy 
something with nothing by multiplying it. Well, once nothing, it's nothing. 
Twice nothing, it's not much. But three times nothing, for three times nothing,
we can already buy something. And for cheap! Now, if you multiply three times 
nothing by three times nothing, nothing multiplied by nothing equals nothing, 
three multiplied by three equals nine, it's nothing new. Well, let's talk 
about something else, let's talk about the situation, let's talk about the 
situation without specifying which one. If you allow me, I'll briefly go over 
the history of the situation, whatever it is. A few months ago, remember, 
the situation, not to be worse than today's, was not better either. Already, 
we were heading towards the catastrophe and we knew it. We were aware of it, 
because we should not believe that the person in charge of yesterday was more 
ignorant of the situation than those of today. Besides, they are the same. 
Yes, the catastrophe where the pension was for tomorrow, that is to say that 
in fact it should be for today, by the way. If my calculations are right, 
but what do we see today? That it is still for tomorrow. So I ask you the 
question, ladies and gentlemen, is it by always putting the catastrophe that 
we could do the day after tomorrow, that we will avoid it? I would like to 
point out that if the current government is not capable of taking on the 
catastrophe, it is possible that the opposition will take it.

结论

恭喜🎉!您刚刚学习了如何执行语音到文本转换,并且已经应用了机器翻译!从这个模型中可以解决很多用例。

如果你喜欢阅读我的故事,并希望支持我的写作,考虑成为一个媒体成员。每月支付 5 美元,你就可以无限制地阅读媒体上的故事。

欢迎在 MediumTwitterYouTube 上关注我,或者在 LinkedIn 上跟我打招呼。讨论人工智能、人工智能、数据科学、自然语言处理和人工智能是一种乐趣!

附加材料

GitHub 之私语

通过大规模弱监督的鲁棒语音识别

如何在 Pandas 中执行 SQL 风格的左|右|内|外连接

原文:https://towardsdatascience.com/how-to-perform-sql-flavored-left-right-inner-outer-join-in-pandas-8cc1ea2f622c

SQL 到 Pandas 翻译初学者指南:连接

图片来自 PixabayAlexa

在数据分析领域,我们很少遇到幸运的情况,我们需要的所有数据都驻留在一个表中,并且是现成的格式。相反,我们经常需要从多个表中获取数据,并将它们放入一个数据集中进行分析。这种数据管理过程通常被称为数据合并/连接/串联。

如果您来自 SQL 领域,您可能已经熟悉处理数据合并的 SQL 概念。具体来说,SQL 将两个或多个表横向合并为‘join’,纵向合并为‘union’的过程。在这篇文章中,我们将专门讨论如何使用 pandas 的pandas.DataFrame.merge方法在 python 中执行 SQL 风格的‘join’。我们将在另一篇文章中讨论如何在 pandas 中执行 SQL 的' union '查询。

使用公共键水平合并/连接两个数据集有四种基本方法:左连接、右连接、内连接和外连接。让我们使用以下两个样本数据集进行演示。

import pandas as pd
import numpy as npdf_left = pd.DataFrame({'Student_ID': ['001', '002', '003', '004','005'],
        'Gender': ['F', 'M','F', 'F','M'],
        'race/ethnicity': ['Group A', 'Group B','Group D', 'Group E','Group E']})df_right = pd.DataFrame({'Student_ID': ['002', '003', '005', '006','007'],
        'Math': [77, 46,83, 53,65],
        'Reading': [91, 62,88, 56,72],
        'Writing': [49, 90 ,67, 66,59]})

这里我们有两个数据帧,分别称为“df_left”和“df_right”。“df_left”数据帧有一个 Student_ID 列和每个学生的性别和种族/民族信息。“df_right”数据框架还有一个“Student_ID”列,以及每个学生的数学、阅读和写作成绩。我们希望合并这两个表(水平方向),这样我们就可以在一个数据集中拥有关于一个学生的所有信息,以便进行后续分析。

作者图片

左连接

left join 操作保留左表(df_left)中的所有记录,并且只引入右表中与公共关键字(‘Student _ ID’)匹配的记录。对于右表中没有公共关键字匹配的记录,合并后的表中这些记录的值为“NaN”。

作者图片

为了在 python 中执行左连接,我们可以使用 Pandas 的dataframe.merge()方法。on参数接受键列,how参数接受连接的类型(左、右等。)

df_left.merge(df_right, on='Student_ID', how='left')

右连接

与左连接相反,右连接操作保留右表(df_right)中的所有记录,并且只引入左表中通过公共键匹配的记录。对于左表中没有与公共关键字匹配的记录,合并后的表中这些记录的值将为“NaN”。

作者图片

我们可以通过将how参数指定为how='right',使用下面的代码在 python 中执行右连接:

df_left.merge(df_right, on='Student_ID', how='right')

内部连接

与 left join 和 right join 不同, inner join 仅通过公共键(Student_ID)获取两个表的交集。任何没有公共 Student _ IDs 的记录都将从合并的表中删除,如下所示。

作者图片

我们可以使用下面的代码在 python 中执行内部连接:

df_left.merge(df_right, on='Student_ID', how='inner')

外部连接

外部连接(也称为完全外部连接),从两个表中获取所有的 Student _ IDs,并为没有公共关键字匹配的字段插入 NaN(缺失值)。

我们可以使用下面的代码在 python 中执行完整的外部连接:

df_left.merge(df_right, on='Student_ID', how='outer')

仅在列的子集中合并

默认情况下,上面显示的代码片段将通过您选择的任何类型的连接合并左表和右表,并包括两个表中的所有列。如果您只想在合并时包含右表中的“阅读”列,该怎么办?

嗯,在合并之前,您总是可以对表的列进行子集化。例如,如果我们想用一个左连接从右表中引入“Reading”列,我们可以这样做。很简单,不是吗?

df_left.merge(df_right[['Student_ID','Reading']], on='Student_ID', how='left')

作者图片

用不同的“键列”名称联接

在前面的例子中,您可能已经注意到,两个表中的公共键列具有完全相同的列名“Student_ID”。如果两个表中的键列有不同的名称会怎样?

那么,您可以选择重命名其中一个表的键列,使其与另一个表同名,并使用上面所示的相同代码片段。用不同的键列名执行连接的另一种方法是使用left_onright_on作为参数而不是on来显式指定键列的名称。

例如,假设左边表的键列名是“Student_ID ”,而右边表的键列名是“ID”。若要执行内部联接,可以使用以下代码:

df_left.merge(df_right, left_on='Student_ID', right_on='ID', how='inner')

作者图片

在多个键上合并

有时您可能需要在多个键上连接两个表。您可以简单地在on参数中指定一个您想要用来连接两个表的键列表:

df_left.merge(df_right, on=['key1', 'key2'...],how='left')

或者,如果键列有不同的名称,可以使用left_onright_on参数:

df_left.merge(df_right, left_on=['leftkey1', 'leftkey2'], right_on=['rightkey1', 'rightkey2'],how='left')

合并表格是数据分析领域中最常见的数据管理任务之一。我希望本教程有助于理解 SQL 风格的连接的基本类型以及如何使用Pandas来实现它们。如前所述,本教程只教你如何基于一个或多个公共键水平合并两个表。为了垂直合并/堆叠表(相当于 SQL 中的‘UNION’操作),我们需要使用不同的pandas函数,我们将在另一篇文章中讨论这个主题。感谢阅读,我希望你喜欢这个简短的教程。

数据源:本教程中使用的样本数据集是作者创建的。

你可以通过这个推荐链接注册 Medium 会员(每月 5 美元)来获得我的作品和 Medium 的其他内容。通过这个链接注册,我将收到你的一部分会员费,不需要你额外付费。谢谢大家!

如何在亚马逊上挑选产品(使用贝叶斯统计帮助你决定)

原文:https://towardsdatascience.com/how-to-pick-products-on-amazon-using-bayesian-statistics-to-help-you-decide-c67335c13a42

贝叶斯推理用于决策的案例研究

图片由作者提供。

我们很多人在亚马逊购物时都会遇到的一个问题是:我如何比较两个评分?亚马逊评级为我们提供了两条重要的信息:评级的分布(多少是五星、四星、三星、二星或一星)以及每个产品收到了多少评论。比较分布非常简单:我们可以比较两个产品的平均评分,然后决定。然而,我们如何合并评论的数量呢?这重要吗?

比方说,我想买一台电脑显示器,正在亚马逊上搜索。我找到了两个我喜欢的显示器。Monitor 1 的平均评分为 4.5,有 3130 个评论者。

图片由作者提供。

Monitor 2 平均评分 4.7,但是 172 个评论者。

图片由作者提供。

我们如何在两者之间做出选择?凭直觉,我们知道评论越多的产品越受欢迎(这是证明产品质量的另一个信号)。我们中的一些人可能还意识到,更多的评论(3130 对 172)意味着你看到的平均评级更“可靠”。换句话说,更多的评级意味着,通过信息的众包,我们更接近该产品的“真实”平均水平。然而,我们如何理解评级数量对平均值可靠性的重要性呢?

回答这个问题的一个方法是使用贝叶斯推理来尝试推断我们产品的“真实”评级分布。这有什么帮助?贝叶斯推理将允许我们为评级分布创建一个初始模型,并用我们拥有的数据更新该模型。一旦我们根据所有可用的数据“训练”了我们的模型,我们就可以看到模型的方差是如何根据用于训练它的数据量而变化的。如果你想详细了解如何用 Python 进行贝叶斯推理,请看看我写的另一篇文章这里

想出一个模型

决策策略

对于我们的问题,什么是合适的模型?这就是数据科学家满足主观的,几乎是艺术的需求的地方:数据科学家必须从他们自己的经验和直觉中识别模式。

我们首先要回到我们的目标:能够做出更好的决策。在这个阶段,我们可能还会问“更好的决策”是什么意思。在博弈论中,有一些不同的互斥策略来最大化“回报”,在这种情况下,这是我们对产品的评级(应该与我们的满意度相关)。例如,我们有保守的“极小极大”策略。“最小最大”意味着最小化最大的伤害。换句话说,我们问自己:最坏的情况是什么,哪种策略会把我们带到最好的最坏情况?如果我们知道我们会失败,哪种选择会导致最小的伤害?在选择亚马逊产品的背景下,我们可以创建一个受 minimax 启发的策略,在这个策略中,我们避免选择风险最高的产品,我们给出的评级是 1。

相反,乐观主义者的策略是“最大化”。对于这一战略,我们寻求的是能让我们看到最佳可能情景的选项。受 Maximax 启发的一个乐观策略是,同时考虑两种产品,选择最有可能被我们评为 5 分的产品。

最后,我们可能会采取一种平衡的策略,我们中的许多人可能已经熟悉了:最高期望值。“最高期望值”策略相当于简单地选择平均评级最高的策略。如果我们有一个平均值为 4.5 的产品,另一个平均值为 4.7,那么如果我们用过去的分数来预测我们可能如何评价该产品,我们只需选择 4.7。诺贝尔奖得主、行为经济学之父丹尼尔·卡内曼提倡使用最高期望值策略。他认为,人类倾向于狭隘地框定决策,这导致我们根据自己的感受变得悲观或乐观。相反,如果我们努力宽泛地构建我们的决定,并相信统计数据,我们会意识到,最终我们的幸运和不幸会相互抵消,结果会回归均值。如果我们在一生中购买几种产品,过于乐观或过于悲观都会导致我们错过:期望值是我们最好的猜测。因此,通过这个镜头,预期值是最佳长期策略。

然而,在采取任何策略之前,我们总是必须考虑特定决策的细微差别。我认为,在亚马逊购物的情况下,你真正想要的是找到最适合你需求的产品,特别是因为你可以退货并换另一件产品。这意味着,在这种情况下,我们可能会严重低估得到我们真正不喜欢的产品的风险,因为我们可以把它退回去。因此,我们专注于寻找最有可能让我们完全满意的产品。

因此,让我们说,我们的策略是找到一种方法来最大限度地提高我们将产品评为 5/5 的概率。为此,我们将利用我们的数据,创建一个描述评级分布的模型。有了这个模型,我们就可以预测一个新的评级将获得五个可能级别中的每一个级别的概率。更重要的是,通过贝叶斯推理模型,我们还将通过了解我们模型参数的分布来更好地了解这些预测背后的不确定性。

假设我们的模型是一个包含五个元素的简单向量,对应于产品在每个可能评级中的百分比(或概率)。对于产品一,这将是[0.73,0.14,0.06,0.03,0.04]。更进一步,为了能够结合不确定性的概念以及它与评级的的关系,我们不仅想知道参数现在看起来是什么,还想知道它们看起来是如何分布的。我们希望这些参数(五个百分比中的每一个)都像钟形曲线一样,这样我们就知道我们可以期望概率偏离均值多远。

幸运的是,有两种分布可以帮助我们实现这一点:多项式分布和狄利克雷分布。多项式分布采用“单纯形”向量,即元素介于 0 和 1 之间且相加为 1 的向量,以及多个事件。它输出一个相同大小的向量,其整数值与该输入向量相关。所以,如果我们这样做:

α~多项式(n = 50 个等级,概率= [0.73,0.14,0.06,0.03,0.04])

我们可以得到这样的结果:

[32, 10, 3, 1, 4].这就好像我们在模拟 50 个人给出评级,概率与我们的单纯形输入向量相关。

在 Python 中:

这非常类似于我们对亚马逊产品评级的用例。如果我们知道向量 p 看起来像什么,我们可以模拟,例如,100 个人会如何评价这个产品。注意,我们想要的是相反的东西:我们想要获取每个类别有多少人投票的信息,并得出五个百分比/概率向量的分布。这就是狄利克雷分布的用武之地。

狄利克雷分布接受向量并输出概率向量的样本,即具有与α相同数量的输入的单纯形向量。因此,如果我们将向量[32,10,3,1,4]输入到狄利克雷分布中,我们可能会对概率向量[0.73,0.14,0.06,0.03,0.04]进行采样。即:

p ~狄利克雷([32,10,3,1,4])

输出类似于[0.73,0.14,0.06,0.03,0.04]的值。

在 Python 中:

我们可以看到多项分布和狄利克雷分布看起来是多么的吻合。事实上,它们在统计学中有一个特殊的名字:它们被称为“共轭先验”。这是因为当我们使用狄利克雷分布作为先验,使用多项式作为贝叶斯推断的似然函数时,后验分布也将是狄利克雷分布。此外,后验概率可以根据我们的数据进行分析计算。维基百科有一个非常有用的现有共轭先验列表,以及我们如何基于共轭先验对计算后验概率。

贝叶斯推理

贝叶斯推理的第一步是定义先验分布、似然分布和后验分布。简单回顾一下,贝叶斯推理遵循贝叶斯定理:

P(B|A)=P(A|B)*P(B)P(A)

其中:

P(A|B) =可能性

P(B) =先验

P(A) =证据

P(B|A) =后验概率

对于这个模型,我们想要找出我们的概率向量 p 的后验分布。

我们的可能性将遵循多项式分布:请注意,可能性分布总是反映实际数据的分布,但它们并不相同。根据多项式分布,数据以某个参数 p 分布。然而,在给定一组不同的建议参数 p 的情况下,似然函数接收观察到的数据并输出其观察到的概率。因此,在似然函数中,我们计算每组参数 p 的概率,而不是观察特定数据的概率。请参考我的旧文章进行更深入的探究。

我们的先验将遵循狄利克雷分布。基于我们现有的知识,我们创建一个对我们有意义的先验(或者,也许,我们通过保持它的一致性,通过使用参数,例如α =[1,1,1,1,1]来创建一个无信息的先验)。如果我们从这个无信息的先验中采样,我们将不会得到模型参数看起来的好结果(我们可能会得到类似于[0.12,0.2,0.35,0.18,0.15]的结果,我们知道这并不接近现实)。这就是为什么我们需要进行贝叶斯推理:根据可能性函数和我们看到的数据来修改这个先验,从而创建一个更接近现实的后验。

共轭先验技巧

正如我提到的,使用共轭先验的两大优势(事实上,幸运地发现我们的情况是共轭先验的自然发生)是:( a)后验将遵循与先验相同的分布;( b)后验易于分析计算。为了计算多项式/狄利克雷共轭先验的后验概率,我们需要做的就是将我们观察到的数据添加到我们的狄利克雷分布中的α向量的元素中。

让我们说,我们基于直觉创建的狄利克雷先验是:

p ~狄利克雷(α = [1,1,1,1,1])

对于后验概率,我们的新α计算如下:

New α = α+Xn,其中 Xn 是我们观察到的数据的向量(即我们的产品在每个类别中的投票数)。

因此,如果我们观察 Xn=[5000,300,100,50,3],其中 5000 是五星评级的数量,以此类推,我们的 new 将简单地为[5001,301,101,51,4]。因此,我们的后路是:

p~狄利克雷(α = [5001,301,101,51,4])

使用我们的技巧

现在我们可以用我们的技巧来解决我们的问题了。首先,我们必须选择我们的先验。我们可能会倾向于,对于质量不错的亚马逊产品,即我们可能会考虑购买的产品,大多数评论通常是 5 分制,分数越来越小。我们可能还会注意到,愤怒的客户通常给出 1 的频率比给出 2 的频率更高,并且 1 的频率比 2 的频率更高。这些模式有助于引导我们形成先验(记住,这是我们在不看数据的情况下对产品评级分布的倾向)。

假设我们得出以下先验:[50,40,30,20,25]。太好了!如果我们愿意,我们甚至可以使用统计软件从这个先验中取样(我喜欢使用 python 中的 scipy.stats 库)。然而,我们希望比前任做得更好。因为我们使用共轭先验技巧,我们可以很容易地得出后验:我们只需将数据添加到我们的先验中!我们从上面来看一下 monitor 1 的评分数据:2285,438,188,94,125。按照上面我给出的公式,我们的后验概率就是两个向量的简单相加:

所以我们的后验是向量[2335,478,218,114,150]。我们的全部后路依次是:

p ~狄利克雷([2335,478,218,114,150])

从后面取样

现在我们有了后路,我们该怎么做?记住,后验概率是模型参数的分布。在这种情况下,后验概率描述了有多少产品评论属于这五个类别中的每一个类别。如果我们使用我们的模型得到一个样本,它看起来是这样的:

我们可以将此结果理解为 72%的评级预计为 5s,15%为 4s,6%为 3s,4%为 2s,4%为 1s。然而,贝叶斯方法的用途是对参数的多种可能性进行采样,并查看这些参数的分布。

让我们只关注 5 级类别。假设我们想从后验样本中抽取 1000 个样本,并观察其分布情况:

图片由作者提供。

这时我们开始看到使用贝叶斯推理的好处。我们不仅知道五的概率的平均值,即我们的最佳猜测,而且我们还知道我们对这一断言有多大的把握。请注意 95%的置信区间:它表明,对于我们测量的 95%的样本,我们期望我们的描述性统计(平均值)位于这些边界内。置信区间最终将由我们拥有的数据量决定:我们将看到,对于狄利克雷分布(以及大多数分布),我们拥有的数据越多,置信区间就越小。

然而,在我们研究置信区间如何变化之前,我们可以先看看其余类别的分布。我写了一些代码来从后面取样,然后创建一个我称之为‘柱状图’的东西:

当我们想一次比较几个不同类别的分布时,柱形图很有用。另一个不错的选择是箱线图。对于柱状图,我们使用点和点的密度,而不是使用条和条的高度来表示密度。柱状图中的每个点代表一个采样数据。请看从我们的后部取样 100 个样本得到的柱状图:

图片由作者提供。

注意,我在这个推论中使用了一个无偏先验([1,1,1,1,1])。等级为 5 的紫色列显示大多数样本如何接近平均值(该列上的水平黑线)。随着我们越来越接近 99%的置信区间边界(水平绿线),这些点变得越来越稀疏。对于其余的列,这一点不太明显,但仍然成立。

上面的这个图表是针对 monitor 1 的,这个 monitor 有 3130 个亚马逊评分(或者换句话说,我们用来填充贝叶斯模型的 3130 个数据点)。如果我们做同样的过程,并绘制后验样本,为一个产品少得多的评级?如果我们为 2 号监视器运行这个管道会怎么样?这是我们会看到的图表:

图片由作者提供。

看到置信区间比以前宽了吗?为什么这是如此不同?关键是,对于这个模型,由于我们只有 172 个评级,这就是我们的狄利克雷看起来的样子(假设一个[1,1,1,1,1]的无信息先验)。如果我们稍微偏置先验,比方说通过输入先验为[10,5,4,2,3],我们改变了明显的平均值:

图片由作者提供。

在这种情况下,先验并没有帮助减少每个类别中的方差(方差已经相当小了),所以我们可能希望使用无偏的先验。

假设这台显示器有 20 个评级,而不是 172 个评级(遵循我们在 172 个数据中看到的相同比率),会怎么样?

在这种情况下,我们将获得更宽的置信区间:

图片由作者提供。

现在我们可以开始看到,均值的不确定性要大得多,置信区间也很大。这里有一点哲学上的题外话:我们的模型的目的是看起来像我们的数据,还是我们的模型的目的是了解现实?人们可能希望我们的模型看起来和我们的数据一模一样,这样就创建了一个“好”的模型。但当我们的数据微不足道时,我们不得不怀疑它。对于 monitor 2,在假设的 20 个评级的情况下,我们可能会因为我们的模型不能捕捉类别的平均值而感到不安,而是为我们的可能性创建这些大的区间。然而,我们也必须对数据本身持怀疑态度:数据根本就不够。我们用这些数据计算的任何方法都可能仅仅因为随机性而有偏差。我们应该相信我们对只有 20 个评论者的 5 星评价持怀疑态度的直觉:该产品根本没有经过足够多的人的测试,随着更多评论的出现,我们看到的每个类别的百分比可能会发生很大变化。

那么,我提出的下一个问题是:多少人是足够的人?什么时候我们可以说我们可以信任我们的模型?

研究收敛速度

向模型的“真实”参数收敛是每个机器学习模型的目标。假设这些参数在本质上保持相对恒定,那么一个好的模型,只要有合适的数据量,就能够接近这些值。类似地,我们可以想到,一个产品的“真实”平均值是如何通过相当多的投票/评级来估算的。

我们可以研究这种收敛性的一种方法是用不同数量的数据(或评论)模拟我们的模型。简而言之,我们可以跟踪我们的模型的标准偏差(或方差)如何随着评论数量的增加而变化。这正是我接下来做的,看看这个图表:

图片由作者提供。

同样,我计算的标准差是我们五个参数的后验样本的标准差(五个不同的平均值,每个评级类别一个)。这是使用来自监视器 1 的数据。随着评级数量从 0 增加到 30,我们可以看到标准差急剧下降。从那一点开始,斜率逐渐变小,我们的标准差下降得更慢。这表明,经过 30 次左右的评论后,我们的模型对评级的分布有了一个很好的想法,随着评论的增加,应该没有什么变化。这也意味着,我们不需要大量的评论就能很好地把握这两种产品中哪一种更值得购买。

做出购买决定

现在我们已经拥有了所有的统计工具,我们应该选择最初的两个监视器中的哪一个呢?让我们在同一张图中看看我们的模型的 5 个类别评级的分布情况:

作者图片

关于这个图表的第一个注意事项:我绘制了两个“柱状图”。一个用于左边的监视器 1 的 5s 百分比的后验分布,同样的事情用于右边的监视器 2。您可能注意到的第一件事是,monitor 2 的方差要高得多。平均值也是如此:监测 2 的平均抽样概率为 5,约为预期的 0.87,而监测 1 为 0.73。

让我们回到我们的决策策略:我主张采用 maximax 启发的策略。这个策略意味着试图最大化我们最好情况的机会:购买一个产品,并得出结论,这是一个 5 星级产品。因此,我们只能关注“5”评级栏。如果我们比较这两个显示器的模型结果,其中一个肯定是更好的选择:显示器二,尽管它的总体方差和不确定性更高,但似乎具有持续更高的 5 评级概率。我们还可以通过提出以下问题对此进行量化:对于我们对每个总体进行抽样的每个平均值,监测 2 的样本比监测 1 的样本大的频率是多少?在上面的例子中,答案是 100%。对于较大的样本,我们可能会看到异常值,使这个数字下降到 99%或更低,但结论是相当简单的:几乎总是显示器 2 是更好的购买。

验证监视器 2 更好的另一个简单方法是简单地注意监视器 2 的 99%置信区间的下限(大约 0.8)高于监视器 1 的 99%置信区间的上限(大约 0.75)。

偏见和障碍

通常,在您将模型投入生产后,您最终会意识到存在影响结果的偏差,并且随着时间的推移,您的模型的准确性似乎会降低。这可能与直觉相反:随着时间和数据的增加,你会期望模型变得更好。然而,只有当我们的人口,即我们正在分析的数据保持不变时,准确性的提高才有望实现。在亚马逊评级的情况下,我们可能有一个“有偏见的”人群:

  • 我要指出的第一个偏差是,对于产品的早期采用者来说,可能存在抽样偏差。购买评分很少或没有评分的产品的人可能始终比后期采用者更宽容,他们持怀疑态度,等待别人先尝试。
  • 第二个偏见是评论者的偏见:在亚马逊上发布评论的是谁?我们能期望评论者群体准确代表购买产品的人群吗?我要说的是,情况可能并非如此。对产品有强烈感觉的人可能会有偏见:喜欢产品的人肯定会称赞它,讨厌它的人肯定会表达他们的感受。对一个产品不冷不热的人可能不会费心去回顾它。

对于购买决策,我上面提出的第二种偏见可能不是障碍(这种偏见对于亚马逊上的所有产品应该是一致的),但第一种偏见应该是。对于第一个偏见,我们正在寻找一个不同的原因来解释为什么评论数量少可能是一个问题:早期采用者可能倾向于宽容(或者他们可能是额外的怀疑)。对这一问题的深入探究将包括对这些类型的偏见以及应对这些偏见的工具/策略的分析。

结论

我写这篇文章的目的是展示我们如何在决策中考虑样本的数量,以及这个数量所隐含的信心。我展示了我们如何使用贝叶斯推理来构建亚马逊评级系统的模型,以及我们如何绘制我们的信心如何随着评级数量的增加而变化。有了这些信息,我们就可以做出更明智的决策。

感谢您的阅读,如果您对本文有任何想法、批评或问题,请留言或直接联系我。

机器学习如何挑选最好的显卡

原文:https://towardsdatascience.com/how-to-pick-the-best-graphics-card-for-machine-learning-32ce9679e23b

五金器具

加快你的训练,更快地迭代

Unsplash 上由娜娜杜瓦拍摄的照片

在处理机器学习时,尤其是在处理深度学习和神经网络时,最好使用显卡来处理,而不是 CPU。当涉及到神经网络时,即使是非常基本的 GPU 也会胜过 CPU。

但是应该买哪个 GPU 呢?有很多选择,它可以很快变得混乱和昂贵。因此,我将尝试指导您考虑相关因素,以便您可以根据您的预算和特定的建模要求做出明智的选择。

为什么 GPU 比 CPU 更适合机器学习?

CPU(中央处理器)是计算机的主力,重要的是它非常灵活。它可以处理来自各种程序和硬件的指令,而且处理速度非常快。为了在这种多任务环境中脱颖而出,CPU 拥有少量灵活快速的处理单元(也称为核心)。

GPU(图形处理单元)更专业一点,在多任务处理方面没有那么灵活。它旨在并行执行大量复杂的数学计算,从而提高吞吐量。这是通过拥有更多更简单的内核来实现的,有时是数千个,以便可以同时处理许多计算。

图片由 Ahmed Gad 来自 Pixabay

这种并行执行多个计算的要求非常适合:

  • 图形渲染 —移动的图形对象需要不断计算其轨迹,这需要大量不断重复的并行数学计算。
  • 机器和深度学习 —大量矩阵/张量计算,使用 GPU 可以并行处理。
  • 任何可以拆分并行运行的数学计算类型。

我认为我见过的最好的总结是在 Nvidia 自己的博客上:

表格作者,灵感来自 nvidia.com

张量处理单元(TPU)

随着人工智能和机器/深度学习的蓬勃发展,现在甚至有了更专业的处理核心,称为张量核心。这些在执行张量/矩阵计算时更快更有效。机器/深度学习所涉及的数学类型到底需要什么。

虽然有专用的图形处理器,但一些最新的图形处理器也包括许多张量核,这一点您将在本文后面看到。

英伟达 vs AMD

这将是一个很短的部分,因为这个问题的答案肯定是:英伟达****

你可以使用 AMD GPUs 进行机器/深度学习,但在撰写本文时,Nvidia 的 GPU 具有更高的兼容性,并且通常更好地集成到 TensorFlow 和 PyTorch 等工具中。

我从自己的经验中知道,试图将 AMD GPU 与 TensorFlow 一起使用需要使用额外的工具( ROCm ),这往往有点复杂,有时会留给你一个不是最新版本的 TensorFlow/PyTorch,这样你就可以让卡工作了。

这种情况可能会在未来得到改善,但如果你想要一个没有麻烦的体验,最好现在就坚持使用 Nvidia。

GPU 特性

挑选一款既符合您的预算,又能够完成您想要的机器学习任务的 GPU,基本上可以归结为四个主要因素的平衡:

  1. GPU 有多少 RAM?
  2. GPU 有多少个 CUDA 和/或张量核?
  3. 卡采用什么芯片架构?
  4. 您的功耗要求是什么(如果有)?

接下来的小节将会研究这些领域中的每一个,希望能让你更好地理解对你来说什么是重要的。

GPU RAM

这个问题的答案是,多多益善!我知道这很有帮助…

这实际上取决于你在建模什么,以及那些模型有多大。例如,如果您正在处理图像、视频或音频,那么根据定义,您将处理相当大量的数据,GPU RAM 将是一个极其重要的考虑因素。

总是有办法解决内存不足的问题(例如,减少批处理大小)。但是,您希望限制为了避开内存需求而在代码上花费的时间,因此很好地平衡您的需求是至关重要的。

图片来自 Pixabay

作为一般经验法则,我建议如下:

****4GB——我会考虑的绝对最小值,只要你不处理过于复杂的模型,或者大量的图像、视频或音频,这在大多数情况下都会很好。如果你刚刚起步,想在不倾家荡产的情况下尝试一下,那就太棒了。对 CPU 的改进仍然是日以继夜的。

8GB —我会说这是一个很好的中间地带。您可以在不触及 RAM 限制的情况下完成大部分任务,但在处理更复杂的图像、视频或音频模型时会遇到问题。

12GB —我认为这是最理想的,但并不荒谬。您可以处理大多数较大的模型,甚至是那些处理图像、视频或音频的模型。

12GB+ —越多越好,您将能够处理更大的数据集和更大的批量。然而,超过 12GB 后,价格才真正开始上涨。

以我的经验来看,如果成本相同,一般来说,最好是选择一个“更慢”的内存更大的卡。请记住,GPU 的优势是高吞吐量,这在很大程度上依赖于可用的 RAM 来通过 GPU 馈送数据。

CUDA 核心和张量核心

这真的很简单。CUDA 核心/张量核心越多越好。

其他项目,如 RAM 和芯片架构(见下一节),可能应该首先考虑,然后从缩小的选择中查看具有最高数量 CUDA/tensor 内核的卡。

对于机器/深度学习,张量核比 CUDA 核更好(更快、更高效)。这是因为它们是为机器/深度学习领域所需的计算而精确设计的。

事实上,这并不重要,CUDA 内核已经足够快了。如果你能得到一张也包含张量核的卡片,那是一个很好的加分项,只是不要太在意它。

接下来,您会看到“CUDA”被频繁提及,这可能会让人感到困惑,因此总结如下:

  • CUDA 内核 —这些是显卡上的物理处理器,通常有数千个。
  • CUDA 11 —数字可能会改变,但这是指为使显卡工作而安装的软件/驱动程序。新版本定期发布,它可以像其他软件一样安装。
  • CUDA 世代(或计算能力) —这描述了图形卡在其世代特征方面的能力。这在硬件中是固定的,因此只能通过升级到新卡来改变。它通过数字和代号来区分。例子:3 . x[开普勒],5 . x[麦克斯韦],6 . x[帕斯卡],7 . x[图灵]和 8 . x[安培]。

芯片架构

这实际上比你想象的更重要。正如我前面提到的,在这一点上,我们基本上放弃了 AMD,所以在几代芯片架构方面,我们只有 Nvidia。

ManuelUnsplash 上拍照

要注意的主要是芯片组的“计算能力,有时被称为“CUDA 一代”。这对于每张卡来说是固定的,所以一旦你买了卡,你就被卡的计算能力所束缚。

了解卡的计算能力非常重要,原因有两个:

  1. 显著的功能改进
  2. 反对

显著的功能改进

让我们从一个显著的特性改进开始。混合精度训练:

使用精度低于 32 位浮点的数字格式有很多好处。首先,它们需要更少的内存,能够训练和部署更大的神经网络。其次,它们需要更少的内存带宽,从而加快了数据传输操作。第三,在精度降低的情况下,数学运算运行得更快,尤其是在支持该精度的张量核 GPU 上。混合精度训练实现了所有这些好处,同时确保与全精度训练相比,不会损失特定任务的精度。它通过识别需要完全精度的步骤,并仅对这些步骤使用 32 位浮点,而对其他所有步骤使用 16 位浮点来实现这一点。**

-Nvidia 学习性能文档

如果您的 GPU 具有 7.x(图灵)或更高的计算能力,则只能使用混合精度训练。这基本上是 RTX 20 系列或更新,或 RTX,“T”或“A”系列台式机/服务器。

当考虑新的显卡时,混合精度训练是如此有利的主要原因是它降低了 RAM 的使用,所以通过使用稍微新一点的卡,可以降低对 RAM 的要求。

贬值

然后,我们转向天平的另一端。

如果你有特别高的内存需求,但没有足够的钱买高端卡,那么你可能会选择二手市场上的旧型号 GPU。

然而,这也有相当大的负面影响……这张牌是生命的终结。

这方面的一个主要例子是特斯拉 K80,它有 4992 个 CUDA 内核24GB 内存。它最初在 2014 年的零售价约为 7000.00 美元。我刚刚在英国的 e-bay 上看了一下,它的价格从 130.00 英镑(150 美元/欧元)到 170.00 英镑(195 美元/欧元)不等!这么小的价格却有这么多内存。

然而,也有相当大的负面影响。K80 的计算能力为 3.7(开普勒),从 CUDA 11 开始(当前的 CUDA 版本为 11),该功能已被弃用。这意味着该卡已经寿终正寝,不能在未来的 CUDA 驱动程序中使用。真的很遗憾,但是要记住,因为这很诱人。

显卡与工作站/服务器卡

Nvidia 基本上把他们的卡分成两部分。有消费级显卡,然后是针对台式机/服务器的卡(即专业卡)。

这两个部分之间显然存在差异,但要记住的主要一点是,对于相同的规格(RAM、CUDA 内核、架构),消费级显卡通常会更便宜。然而,专业卡通常具有更好的构建质量和更低的能耗。

图片由 Elias Gamez像素上拍摄

看看更高端(也非常贵)的专业卡,你也会注意到它们有很多内存(例如,RTX A6000 有 48GB,A100 有 80GB!).这是因为它们通常直接针对 3D 建模、渲染和机器/深度学习专业市场,这些市场需要高水平的 RAM。同样,如果你有这样的需求,你可能不需要建议该买什么!

总的来说,你可能最好坚持消费图形市场,因为你会得到更好的交易。

建议

最后,我想我会根据预算和需求提出一些建议。我把它分成三个部分:

  • 低预算
  • 中等预算
  • 高预算

请记住,高预算不考虑任何超出高端消费显卡的东西。如果你真的有很高的预算,你应该考虑专业卡系列,如 Nvidia A 系列卡,其成本可能高达数千美元。

我已经在低预算部分包括了一张卡,它只能在二手市场上买到。这主要是因为我认为在低预算部分,值得考虑二手卡。

娜娜杜瓦Unsplash 上的照片

我还在组合中加入了专业桌面系列卡(T600、A2000 和 A4000)。你会注意到,有些规格比同类消费显卡稍差,但功耗明显更好,这可能是一些人关心的问题。

低预算(低于 220 英镑—250 欧元/美元)

中等预算(低于 440 英镑—500 欧元/美元)

高预算(低于 1050 英镑—1200 欧元/美元)

其他选项

如果你认为获得显卡的费用和麻烦不适合你,你可以随时利用 Google Colab ,它让你免费使用 GPU。

请记住,这是有时间限制的,如果你使用 GPU 太长时间,他们会把你踢出去,回到 CPU 上。如果 GPU 不活动的时间太长,可能在你写代码的时候,它也会把 GPU 收回来。GPU 也是自动分配的,所以你不能挑选你想要的确切的 GPU。

在撰写本文时,以下 GPU 可通过 Colab 获得:

****注意:我在文章的前面提到 K80 有 24GB 的 RAM 和 4992 个 CUDA 内核,确实如此。然而,K80 是一个不寻常的野兽,因为它基本上是两个 K40 卡栓在一起。这意味着,当您在 Colab 中使用 K80 时,您实际上可以访问一半的卡,因此只有 12GB 和 2496 个 CUDA 核心。

结论

有很多选择,这可能会非常混乱。希望您在阅读完这篇文章后,对什么适合您的特定需求有了更好的了解。

你认为有没有特别值得一提的显卡?请在评论中告诉我。

如果你觉得这篇文章有趣或有用,记得关注我,或者注册我的简讯获取更多类似的内容。

如果你还没有,你也可以考虑订阅媒体。你的会员费不仅直接支持我,也支持你所阅读的其他作家。你还可以完全不受限制地访问媒体上的每个故事。

使用我的推荐链接注册会给我一点回扣,对你的会员资格没有影响,所以如果你选择这样做,谢谢你。

**https://medium.com/@maclayton/membership **

如何从 K 倍交叉验证中绘制混淆矩阵

原文:https://towardsdatascience.com/how-to-plot-a-confusion-matrix-from-a-k-fold-cross-validation-b607317e9874

实践教程

如何从 K 倍交叉验证中绘制混淆矩阵

绘制 k 倍交叉验证评估中涉及的所有折叠的组合混淆矩阵

照片由 JJ 英Unsplash

背景

当评估机器学习模型的性能时,通常将数据分成训练集和测试集,例如通过采样 80%的数据用于训练,20%用于测试。

该模型适合训练数据,然后可以使用一系列指标进行评估和调整,包括准确度、精确度、召回率、f1 分数等。

最终,机器学习模型将根据测试数据进行性能评估,这些测试数据被放在一边并从训练中排除,因为根据模型建立过程中未使用的新数据进行评估可以更好地表明这些模型在现实世界中的表现。

然而,这种方法有时会有问题。在我参加的 Kaggle 比赛中,我经常欣喜地发现,我的最新算法在我保留的测试数据中表现如此之好,结果却在 Kaggle 验证数据中进行了测试,结果发现性能很差。

这到底是怎么回事?好吧,在那些 Kaggle 比赛中,我绞尽脑汁也没能爬上领先的位置,我得出结论,我只是幸运地选择了测试数据的样本,并在性能上得了高分。

这就是 k 倍交叉验证的用武之地。

交叉验证不是抽取 20%的数据用于测试,剩下的 80%用于训练,而是多次抽取数据,每次抽取不同的一组数据用于测试和训练。它可以被形象化如下:

作者图片

注意:实际上褶皱并不像这样整洁干净。上图给人的印象是,训练数据和测试数据都是连续的(即,这些行彼此紧邻),但实际情况并非如此。

scikit-learn库中,我在第一个“测试数据”块中可视化的行集实际上是从整个数据集中采样的,但为了学习交叉验证是如何工作的,简化的可视化更容易理解。

这些数据被分成 5 个“折叠”,这可以在 Python 中使用scikit-learn库实现,如下所示

作者图片

请注意:我从 ka ggle(https://www . ka ggle . com/nica potato/womens-ecommerce-clothing-reviews)选择了一个数据集,该数据集获得了“CC0: Public Domain”许可,这意味着“你可以复制、修改、分发和执行该作品,即使是出于商业目的,都无需请求许可”(详见https://creativecommons.org/publicdomain/zero/1.0/)。

KFold的调用创建了分为训练集和测试集的 5 个“折叠”数据,对cross_val_score的调用执行以下操作

  1. 迭代 5 次折叠中的每一次
  2. 对于每个折叠,使模型适合为训练保留的 4/5 的数据
  3. 针对为测试保留的 1/5 数据评估模型的性能

cv_results.mean()的调用计算所有 5 次折叠的性能平均值,作为一个单一的数字,比单一的训练/测试分割方法更有可能给出生产性能的更好指示。

问题是

我发现交叉验证的一个问题是,我喜欢为我的分类机器学习算法绘制一个混淆矩阵,以帮助我可视化性能,但没有直接和即时的方法来做到这一点。

如果我执行了单个训练/测试分割,我将使模型适合训练数据,然后我可以使用模型来预测测试数据的类别,并将这些类别与实际类别一起传递到混淆矩阵中。

然而,当使用交叉验证时,模型拟合发生在cross_val_score内部。我们的RandomForestClassifiermodel实例还没有安装,即使安装了,到底应该用什么数据来评估它呢?

事实证明,有一种相对简单的方法来产生一组预测的和实际的类,然后可以在混淆矩阵中使用这些类来可视化算法的性能和有效性。

1.导入库

完成这项任务还需要几个库…

2.计算预测类别和实际类别

该解决方案的核心部分是通过定义一个名为cross_val_predict的帮助函数来计算折叠数据的实际和预测类别(即分类),该函数执行以下操作

  1. 获取机器学习算法的本地副本(model)以避免更改传入的副本
  2. 围绕 5 个交叉验证数据折叠进行迭代(假设n_splits=5)。
  3. 对于 5 次分裂中的每一次—

a.从培训功能、培训目标、测试功能和测试目标的数据中提取行

b.将实际目标分类附加到actual_classes

c.使用从当前文件夹中提取的训练数据来拟合机器学习模型

d.使用拟合模型预测当前文件夹中测试数据的目标分类

e.将当前文件夹测试数据的预测类别追加到predicted_classes

然后,helper 函数返回可用于绘制混淆矩阵的完整的实际和预测类(分类)集。

3.想象混乱矩阵

plot_confusion_matrix助手函数使用sklearn.metrix.confusion_matrix来计算矩阵,然后由一个叫heatmap的人用一种很好的格式来显示矩阵,这有助于通过可视化来全面理解算法的性能。

4.调用助手函数

定义了两个辅助函数后,只需依次调用它们来计算实际类和预计类,然后显示混淆矩阵。

作者图片

91%的总体交叉验证准确度看起来性能良好,但是复合混淆矩阵的可视化显示,虽然该算法在预测Review Sentiment何时为Positive时表现良好,但在预测NeutralNegative分类时表现差得多。

结论

Abhisek Thakur 是一位数据科学家,也是世界上第一位 Kaggle 四重大师,他将交叉验证定义为…

“构建机器学习模型过程中的一个步骤,帮助我们确保我们的模型准确地拟合数据,并确保我们不会过度拟合”

他继续说道…

“交叉验证是建立机器学习模型的第一步,也是最重要的一步。如果你有一个好的交叉验证方案,其中验证数据代表训练和现实世界的数据,你将能够建立一个良好的高度可推广的机器学习模型。”

来自世界领先的数据科学家的这一强烈建议导致了这样的结论:k 倍交叉验证是一种比简单的训练/测试分割更好的方法,因此本文通过可视化和示例来解释交叉验证。

人们注意到,使用scikit-learn库中的cross_val_score进行交叉验证的一个缺点是,没有直接的方法来可视化混淆矩阵中的结果,并且示例中使用的数据显示了混淆矩阵是多么有用,尤其是在数据不平衡的情况下。

然后,文章提供了一个名为cross_val_predict的帮助函数的代码和解释,该函数通过访问折叠的索引并构建实际和预测的类来解决这个问题,然后使用plot_confusion_matrix函数在混淆矩阵中有效地可视化结果。

K-fold 交叉验证是构建准确的机器学习算法的核心步骤,提取和可视化实际和预测的分类对于理解结果和优化性能非常有用。

感谢您的阅读!

如果你喜欢读这篇文章,为什么不看看我在 https://grahamharrison-86487.medium.com/的其他文章呢?此外,我很乐意听到您对这篇文章、我的任何其他文章或任何与数据科学和数据分析相关的内容的看法。

如果你想联系我讨论这些话题,请在 LinkedIn 上找我—https://www.linkedin.com/in/grahamharrison1或者发邮件给我ghar rison @ Lincoln college . AC . uk

如果你想通过订阅来支持作者和全世界 1000 个为文章写作做出贡献的人,请使用这个链接——https://grahamharrison-86487.medium.com/membership(注意:如果你使用这个链接注册,作者将收到一定比例的费用)。

如何在 Tableau 仪表板上绘制自定义地图图像,仅需 3 个简单步骤,无需计算

原文:https://towardsdatascience.com/how-to-plot-a-custom-map-image-on-tableau-dashboard-in-just-3-easy-steps-no-calculations-required-8db0d41680c4

提示:查看一个专门为所有 Tableau 用户创建的网络应用

作为一个仪表板工具,ableau 为用户提供了广泛的图表选项。Tableau 中最令人印象深刻的功能之一无疑是其用于渲染地理空间数据集的内置底图服务:

作者截图|使用 Tableau 的内置底图服务显示新加坡老年人口的地图

但是,例如,当 Tableau 的内置地图服务都无法显示您的仪表板试图捕捉的细节(例如,街道名称、建筑足迹、某些地形和水体)时,则有必要转向其他方式来呈现这些要素。

因此,与其依赖任何其他与 Tableau 兼容的底图服务文件进行导入,还不如绘制自定义背景地图图像:

作者插图|根据特定的相应地理坐标绘制背景图像地图

一个开源实用工具— 链接到 Web 应用

对于我遇到的过去几个地理空间用例,作为一种处理仪表板的默认地图服务无法呈现所需地理特征的情况的方法,我转而寻求一种解决方法,即通过部署 web 功能来导出任何自定义地图图像以及输入 Tableau 的背景图像导入功能所需的相应坐标值。执行此解决方法的 3 个步骤将在下一节中说明。

步骤总结—总共 3 个步骤

第一步。(1)小故障(2)渲染的备份链接处导航至网络应用。选择标签 [🌐Spatial⇢CSV] 在上面的导航栏中,滚动到底部,将显示以下内容或类似内容:

作者截图|部署到 tableau 实用程序应用程序上的自定义地图图像功能

第二步。根据,随意更改输入字段中的自定义底图 url(注意:自定义底图 URL 必须遵循 slippy 地图切片格式— {z}/{x}/{y}。png)切换到您选择的底图:

作者插图|底图 url 从左侧(openstreetmap)切换到右侧(onemap)

第三步。最后,在缩放和平移到您想要的地图视图后,继续选择绿色按钮— 【导出地图图像】和(非常重要!)请注意导出地图图像时的坐标:

作者插图|在左侧,图像导出时要注意的坐标值位于 web 应用程序的底部。|在右边,这些坐标然后被直接输入到 Tableau 的背景图像导入功能中。

继续选择您保存的图像,并基于本文开头显示的背景地图图像,在指定正确的坐标后,最终结果应该类似于下图:

作者插图|请注意,上一个屏幕截图中的相同背景图像被用作背景,用于在仪表板上呈现行驶路线的地理坐标

现在你知道了!祝贺成功绘制地图图像!❤希望你觉得这篇文章有用,如果你想了解更多地理信息系统(GIS)、数据分析& Web 应用相关的内容,请随时关注我的媒体。会非常感激—😀

— 🌮请给我买一份玉米卷🎀˶❛◡❛)

https://geek-cc.medium.com/membership

要了解更多 Tableau 技巧和变通方法,请随意查看下面的文章列表:

</5-lesser-known-tableau-tips-tricks-hacks-with-use-case-demo-463f98fbdc7e>

如何在地图上绘制路线

原文:https://towardsdatascience.com/how-to-plot-a-route-on-a-map-fb900a7f6605

巴黎城市漫步。图片作者。

python 中带有代码示例的教程。

对于某些项目来说,在地图上绘制路线可能会很有用。在这里你可以找到你需要的所有信息:包、API 和代码示例。最终,您可以创建漂亮的交互式地图。

安装和准备工作

我们将使用 geopyfolio,这两个包都是为使用 python 处理地理空间数据而设计的。首先,使用 conda 或 pip 安装软件包:

# conda
conda install -c conda-forge folium
conda install -c conda-forge geopy# pip
pip install folium
pip install geopy

除了这些包之外,您还需要能够调用一个 API 来给出多行线段的路径坐标。做这件事的 API 是路线和方向 API 。您可以在 RapidAPI 上创建一个帐户,并订阅路线和方向 API。RapidAPI 免费计划包括每月 30 000 次免费通话,这是一个不错的开始。还有其他(更商业化的)选项可用,如 ArcGIS谷歌地图方向,所以选择适合你的情况。

检索两点之间的路线数据

本节末尾的代码使用了我前面提到的路线和方向 API 。获得两点之间的方向真的很容易:您需要指定两点的纬度和经度。如果您的数据集包含没有经纬度值的地址,不要担心,转换它们很容易。这个过程称为地理编码。使用 geopy,其工作方式如下:

from geopy.geocoders import Nominatimdef get_lat_long_from_address(address):
   locator = Nominatim(user_agent='myGeocoder')
   location = locator.geocode(address)
   return location.latitude, location.longitude# example
address = 'Zeeweg 94, 2051 EC Overveen'
get_lat_long_from_address(address)
>>> (52.4013046, 4.5425025)

在路线和方向 API 中,您还可以指定想要使用的交通方式:驾车、卡车、自行车、步行或公交。

要调用 API,您需要一个 API 键。订阅后,您可以在这里找到它:

快速 API 键,见黄色箭头。图片作者。

调用 API 获取从第一个地址到第二个地址的方向:

import requestsdef get_directions_response(lat1, long1, lat2, long2, mode='drive'):
   url = "https://route-and-directions.p.rapidapi.com/v1/routing"
   key = "**YOUR-API-KEY**"
   host = "route-and-directions.p.rapidapi.com"
   headers = {"X-RapidAPI-Key": key, "X-RapidAPI-Host": host}
   querystring = {"waypoints":f"{str(lat1)},{str(long1)}|{str(lat2)},{str(long2)}","mode":mode}
   response = requests.request("GET", url, headers=headers, params=querystring)
   return responseresponse = get_directions_response(52.4013, 4.5425, 52.402, 4.5426)

response变量是这样的(点击放大):

API 的回应,点击放大。图片作者。

对于我们的路线绘图,我们需要几何图形:它包含了我们必须在其间画线的所有坐标,这将在地图上创建路线。

请注意,响应还包含驾驶员指示,如:‘进入环形交叉路口,从第二个出口进入 zee weg/N200。’很酷,不是吗?您可以将它们用于导航目的。

现在我们可以用数据来可视化路线了!

使用 leav 创建路线图

下面的函数使用两点之间的路径创建地图。输入是我们从对路线和方向 API 的 API 调用中收到的响应。我们从响应中提取坐标。然后我们添加标记(起点和终点)并用PolyLine画线。该脚本的一个重要部分创建了最佳缩放,这确保了您的路线将始终在地图的中心。为此,我们使用最小和最大纬度和经度值以及fit_bounds

import foliumdef create_map(response):
   # use the response
   mls = response.json()['features'][0]['geometry']['coordinates']
   points = [(i[1], i[0]) for i in mls[0]] m = folium.Map() # add marker for the start and ending points
   for point in [points[0], points[-1]]:
      folium.Marker(point).add_to(m) # add the lines
   folium.PolyLine(points, weight=5, opacity=1).add_to(m) # create optimal zoom
   df = pd.DataFrame(mls[0]).rename(columns={0:'Lon', 1:'Lat'})[['Lat', 'Lon']]
   sw = df[['Lat', 'Lon']].min().values.tolist()
   ne = df[['Lat', 'Lon']].max().values.tolist()
   m.fit_bounds([sw, ne])
   return mm = create_map(response)

如果你在笔记本上工作,你可以打电话给m,你会看到:

第一条路线绘制在一张漂亮的交互式图表上!图片作者。

漂亮!另一种方法是将图像保存为 html 格式,并在浏览器中打开:

m.save('./route_map.html')

添加地址

功能的改进可以是添加更多的地址。让我们沿着巴黎的亮点创建一个城市漫步。

首先我们指定我们的地址:

# touristic route through Paris (Eiffel Tower, Arc de Triomphe, ...)
address1 = '5 Avenue Anatole France, 75007 Paris, France'
address2 = 'Place Charles de Gaulle, 75008 Paris, France'
address3 = '60 Avenue des Champs-Élysées, 75008 Paris, France'
address4 = "Place de l'Opéra, 75009 Paris, France"        
address5 = 'Rue de Rivoli, 75001 Paris, France'
address6 = '10 Bd du Palais, 75001 Paris, France'
address7 = '3 Rue Guynemer, 75006 Paris, France'
address8 = '33 Avenue du Maine, 75015 Paris, France' addresses = [address1, address2, address3, address4, address5, address6, address7, address8]

我们需要坐标,而不是地址,所以我们使用之前创建的get_lat_long_from_address函数创建一个包含纬度和经度的列表:

lat_lons = [get_lat_long_from_address(addr) for addr in addresses]

然后,我们用get_directions_response函数调用 API 来获取点之间的方向:

responses = []for n in range(len(lat_lons)-1):
   lat1, lon1, lat2, lon2 = lat_lons[n][0], lat_lons[n][1], lat_lons[n+1][0], lat_lons[n+1][1]
   response = get_directions_response(lat1, lon1, lat2, lon2, mode='walk')
   responses.append(response)

现在我们更改create_map函数来处理多个响应:

def create_map(responses, lat_lons):
   m = folium.Map()
   df = pd.DataFrame() # add markers for the places we visit
   for point in lat_lons:
      folium.Marker(point).add_to(m) # loop over the responses and plot the lines of the route
   for response in responses:
      mls = response.json()['features'][0]['geometry']['coordinates']
      points = [(i[1], i[0]) for i in mls[0]]

      # add the lines
      folium.PolyLine(points, weight=5, opacity=1).add_to(m) temp = pd.DataFrame(mls[0]).rename(columns={0:'Lon', 1:'Lat'})[['Lat', 'Lon']]
      df = pd.concat([df, temp]) # create optimal zoom
   sw = df[['Lat', 'Lon']].min().values.tolist()
   sw = [sw[0]-0.0005, sw[1]-0.0005]
   ne = df[['Lat', 'Lon']].max().values.tolist()
   ne = [ne[0]+0.0005, ne[1]+0.0005]
   m.fit_bounds([sw, ne])
   return mm = create_map(responses, lat_lons)

m看起来是这样的:

游览巴黎。点击放大。图片作者。

这里一个有趣的附加功能是通过优化计算所有地址之间的最短或最快路线。以下文章中的更多信息(示例 2):

结论

在这篇文章中,您学习了使用 follow、geopy 和 route and directions API 在交互式地图上创建路线。你可以以多种不同的方式使用地图,比如在 flask 应用程序中使用或者与 plotly 结合使用来进行很酷的交互。您也可以决定将地图保存为代码为m.save('./route_map.html')的 html 文件。这使得嵌入文件成为可能:<iframe src="route_map.html" height=”500" width="500"></iframe>

感谢阅读!

别忘了 订阅 如果你想在我发表新文章时收到电子邮件。

如何作为一名有抱负的数据科学家实践文档

原文:https://towardsdatascience.com/how-to-practice-documentation-as-an-aspiring-data-scientist-1de9c4f2f843

想想你参与的最后一个项目。你还记得你在那个项目中采取的每一步吗?从每一个数据操作步骤到你所结合的机器学习技术?现在试着回忆一下之前项目的步骤。你记得那里所有的步骤吗?那之前的项目怎么样?还是几个月前的那个?

如果你不能记住每一步,那也没关系(如果你能记住,那就令人印象深刻了)!随着你做的项目越来越多,你开始只记得最近的项目。但是,这些先前的项目有一些有用的步骤,可以纳入未来的项目。以前的一些项目现在可能不再适用,你需要做一个替代版本。但是如何记住哪些步骤是有用的呢?您如何知道不要从您以前的版本中重复过时的步骤?这就是文档发挥作用的地方。

在本文中,您将了解到:

  1. 什么是文档。
  2. 作为一名有抱负的数据科学家,您可以开始创建什么类型的文档。

照片由西格蒙德Unsplash 上拍摄

什么是文档?

文档是为跟踪项目中包含的步骤和规则而创建的一组文档。这包括分析和软件产品。以下是一些你可以开始写的即时文档类型:

  1. 处理数据的步骤。
  2. 特征工程步骤
  3. 数据字典

这些只是文档的几个用例。但它们都是为了记录和将来参考。不仅是同事的未来参考,也是未来的你。将来在相关项目或其新版本中引用这些文档的人。

那么如何开始练习文档呢?

照片由布拉登·科拉姆Unsplash 拍摄

第一步

从你做过的任何项目开始。这可能是你的第一个项目,你最近的项目,或者介于两者之间的任何项目。如果本地有此项目,请在项目文件夹中创建一个单独的文件夹,并将其标记为“Documentation”。您的文件夹结构应该如下所示:

图片来自作者

如果你的代码只在 Github 上,你可以创建一个专用的“文档文件夹”,然后使用项目名称作为标签在里面创建文件夹。

第二步

为文档的第一页创建一个 Word 文档。根据代码的类型,您可以从以下内容开始:

处理数据的步骤

厄尔·威尔考克斯在 Unsplash 上的照片

作为一名有抱负的数据科学家,这将是你最常做的事情。列出这些步骤有助于跟踪如何为项目中的数据管道处理数据,或者如何处理数据以进行分析。这些步骤可以以段落的形式列出,或者更好的是以列表的形式列出。这也是您可以列出任何必要的数据集和合并的地方。

例如,假设你正在分析 2020 年以后的股票。假设您正在处理的数据包括 2020 年之前的数据,那么您必须过滤掉这些数据。写下“分析是针对从 2020 年开始的数据集 A 中的股票”或“过滤数据集 A 中大于或等于 2020 年的数据”是你可以在描述这个过滤步骤的文档中写的句子。

特征工程步骤

照片由Isis franaUnsplash 拍摄

与数据操作步骤类似,特征工程步骤是您应该创建的另一个文档。您将在此包括的一些项目有:

  1. 数据转换步骤,如标准化或规范化。还包括你将在流程的哪个阶段执行这些步骤
  2. 正在创建要素的数据以及这些步骤。
  3. 根据分类特征创建的虚拟列。
  4. 流程结束时创建的所有新功能。

记住,机器学习模型经不起时间的考验,即使你具备所有的特征。但是有时模型会因为功能问题而无法站立。功能可能会发生巨大变化,甚至变得几乎不可用。在考虑如何实现潜在的功能替代方案时,回顾功能工程文档应该是首先要参考的项目之一。

数据字典

刘易斯·基冈Unsplash 上拍摄的照片

这是一个解释数据集中每个变量是什么的列表。这对于用于分析的数据集或创建的新数据集非常有用。这可以被构造成表格。表格结构是优选的,因为它更有组织性。数据字典至少应该列出列名和该列中数据的描述。但是您也可以添加其他详细信息,例如数据类型,如果数据是有限的和离散的,则可以取值(即“1”、“2”、“3”或二进制),以及关于数据的规则的任何链接。

以下是加州教育部网站上的几个基本数据字典示例:

最后的想法

感谢阅读!这些是有抱负的数据科学家可以开始为他/她的数据科学项目创建文档的直接方法。在我目前的职位上,还有其他文件,如:

  1. 至少每年发生一次的数据请求的规则。这类似于操作数据的步骤,但是包括请求的目的、可能不止一个数据集的使用、数据请求的期望格式以及将数据请求传递给谁。你可以把这些写成段落和列表的混合体。
  2. 一个项目概述页面。这是项目经理会制作的页面。作为一名有抱负的数据科学家,这对于组织项目任务和计划任务非常有用。该页面将包括项目的概述、项目的利益相关者和用户,以及项目的时间表。时间表对你练习创建完成特定任务的时间表特别有用。例如,如果您正在创建一个机器学习模型,列出您将何时完成诸如特征工程和模型评估之类的任务将被包括在时间表中。

你还在等什么?去找一个你做过的项目,写一些文档!

格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片

如果你喜欢在媒体上阅读,并愿意进一步支持我,你可以使用我的推荐链接注册一个媒体会员。这样做可以用你的会费的一部分在经济上支持我,我将不胜感激。

如果你有任何问题,请随时在 Linkedin 和 Twitter 上发表评论或联系我们。对 Twitter 上的 DM 开放。如果你喜欢这篇文章,也可以看看我下面的其他相关文章:

</11-tips-for-you-from-my-data-science-journey-df884faa9f3> </7-reasons-you-should-blog-during-your-data-science-journey-4f542b05dab1>

直到下一次,

约翰·德杰苏斯

如何用共形分位数回归预测风险比例区间

原文:https://towardsdatascience.com/how-to-predict-risk-proportional-intervals-with-conformal-quantile-regression-175775840dc4

这种算法-由斯坦福大学学者于 2019 年发表-结合了分位数回归和保形预测。下面是如何用 Python 实现的。

[图片由作者提供]

我们公司要求你建立一个模型来预测拍卖物品的销售价格。该公司的目标是私下购买这些物品,并以更高的价格出售(根据您的模型预测)。

现在,假设你有两件东西:西班牙艺术家胡安·米罗的一幅画和一栋位于三藩市的房子。您的模型做出以下预测:

预测模型做出的点预测。[图片由作者提供]

你的公司可以用 75 万美元买下这幅画,也可以用 75 万美元买下这处房产。他们应该买哪一个?你的预测不足以回答这个问题。

例如,假设米罗艺术品的价格最近波动很大,而旧金山的房地产市场却相当稳定。因此,如果您可以预测可能的销售价格的区间,而不是单个值,您将获得如下结果:

区间预测(95%置信度)。红十字是预测点。[图片由作者提供]

在同样的置信度(95%)下,与米罗画作相关的区间更宽,这意味着与三藩市的财产相比,这个物体本来就有更大的风险。因此,根据你公司的风险厌恶程度,你可能更愿意买房子,即使它与较低的预期利润相关。

这种输出,即预测区间,其长度实际上与和预测相关的风险成比例,可以通过一种叫做共形分位数回归(CQR)的算法获得。

在本文中,我将解释 CQR 是如何工作的,以及如何用 Python 实现它。

什么是 CQR

共形分位数回归是由斯坦福学者团队在 2019 中提出的算法,在一篇自题论文中(链接)。

来自 ArXiv 的纸头截图。[ 链接

顾名思义,共形分位数回归是共形预测和分位数回归的并集。这是一种尝试,从两种方法中取长补短。

如果你读了我以前的一篇关于 Python 的 MAPIE 库的文章,你已经知道了关于保形预测的主要批评:预测的区间有恒定的(或者只是稍微变化的)宽度。

另一方面,分位数回归模型(如随机森林)在新数据的错误预测百分比方面可能不太精确。

共形预测和分位数回归的利弊。[图片由作者提供]

但是在深入研究 CQR 之前,让我们先回顾一下什么是分位数回归。

我们所说的分位数回归是什么意思?

为了形象化起见,我将使用单变量模型——这意味着只有一个特征——但请记住,相同的推理适用于任何数量的特征。假设我们有一项任务,根据个人的年龄来预测他们的收入。我将使用 Python 中生成的一些假数据:

假数据点。[图片由作者提供]

当您在默认模式下使用来自 Scikit-learn、XGBoost、LightGBM、CatBoost 或 Keras 等流行 Python 库的预测模型时,您是在隐式预测目标变量的平均值,给定观察到的特性。例如:

from sklearn.ensemble import GradientBoostingRegressorGradientBoostingRegressor().fit(X_train, y_train).predict(X_test)

这将是结果:

梯度推进回归器(默认模式)对虚假数据进行的预测。[图片由作者提供]

然而,所有的库也都配备了来预测目标值的特定分位数。这是通过改变损失类型实现的。例如,对于 Scikit-learn 的 GradientBoostingRegressor,这可以通过设置loss="quantile"alpha=quantile来实现,其中quantile是一个介于 0 和 1 之间的数字,它是您想要预测的分位数。例如:

from sklearn.ensemble import GradientBoostingRegressorGradientBoostingRegressor(loss="quantile", alpha=.95).fit(X_train, y_train).predict(X_test)

对不同的分位数重复这一过程会产生以下预测:

通过梯度推进回归器(设置不同的分位数)对虚假数据进行预测。[图片由作者提供]

现在的问题是,这些分位数预测在新数据上往往不准确。为了弥补这一点,CQR 对分位数回归预测的区间应用了一个修正因子。

CQR 在实践中是如何工作的?

共形分位数回归是一种旨在校正您的分位数回归模型提供的区间的方法,以使新数据上观察到的错误数量非常接近您设置的容差。容差——通常称为alpha——是你愿意接受的错误百分比(即超出预测区间的观察值)。

CQR 需要三组数据:

  • 训练数据:分位数回归模型学习的数据。
  • 校准数据:CQR 校准间隔的数据。
  • 测试数据:评估区间优劣的数据。

该算法包括 6 个步骤。

共形分位数回归算法。[图片由作者提供]

具体来说,这些步骤是:

  1. 对训练数据拟合分位数回归模型。
  2. 使用上一步获得的模型预测校准数据的间隔。
  3. 根据上一步获得的校准数据和间隔计算一致性分数
  4. 从上一点获得的一致性分数分布中获得 1- alpha分位数。
  5. 使用步骤 1 中获得的模型对测试数据进行预测。
  6. 通过将第 4 步获得的分位数减去(加上)第 5 点获得的预测值,计算区间的左(右)端。

如果有些步骤一开始看起来有点晦涩,不要担心。整个算法只用几行 Python 代码就能翻译出来。

注意:作为分位数回归模型,我将使用来自skgardenRandomForestQuantileRegressor,但是您可以使用分位数损失用任何回归模型替换它。

import numpy as np
from skgarden import RandomForestQuantileRegressoralpha = .05**# 1\. Fit quantile regression model on training data** model = RandomForestQuantileRegressor().fit(X_train, y_train)**# 2\. Make prediction on calibration data**
y_cal_interval_pred = np.column_stack([
    model.predict(X_cal, quantile=(alpha/2)*100), 
    model.predict(X_cal, quantile=(1-alpha/2)*100)])**# 3\. Compute conformity scores on calibration data** y_cal_conformity_scores = np.maximum(
    y_cal_interval_pred[:,0] - y_cal, 
    y_cal - y_cal_interval_pred[:,1])**# 4\. Get 1-alpha quantile from the distribution of conformity scores
#    Note: this is a single number**
quantile_conformity_scores = np.quantile(
    y_cal_conformity_scores, 1-alpha)**# 5\. Make prediction on test data** y_test_interval_pred = np.column_stack([
    model.predict(X_test, quantile=(alpha/2)*100), 
    model.predict(X_test, quantile=(1-alpha/2)*100)])**# 6\. Compute left (right) end of the interval by
#    subtracting (adding) the quantile to the predictions**
y_test_interval_pred_cqr = np.column_stack([
    y_test_interval_pred[:,0] - quantile_conformity_scores,
    y_test_interval_pred[:,1] + quantile_conformity_scores])

如您所见,该算法围绕校准数据计算的一致性分数(步骤 3)。但是符合性分数的意义是什么?

一致性分数表示每个观察值和最近的区间极值之间的(带符号)距离。符号由点的位置给出,无论它落在区间内还是区间外。当点位于区间内时,一致性分数的符号为负,当点位于区间外时,符号为正。因此,只有当该点恰好位于一个区间极值上时,得分为零。

例如,让我们取一个介于 2 和 8 之间的预测区间。对于目标变量的一些不同值,这些将是各自的一致性分数:

不同观察值在 2 到 8 之间的一致性分数。红叉是[作者图片]

但是计算一致性分数的分位数并把它加在区间两边有什么意义呢?

我给你举两个例子。

假设一致性分数的分位数是 1000 美元,给定alpha =5%。这意味着 95%的观测值距离相应的间隔不超过 1000 美元。因此,通过将两边的所有间隔扩大 1000 美元,我们期望实现 95%的观测值将落在它们的间隔内的目标。

如果一致性分数的分位数是负的,这也是有效的。例如,给定一个-500 美元的分位数,这意味着区间太宽。事实上,通过将两边的所有间隔“削减”500 美元,我们将再次获得期望的错误数量。

真实数据上的 CQR

不幸的是,我不知道有哪个 Python 包能够像 Scikit-learn 那样方便用户地执行一致化分位数回归。然而, MAPIE 的作者最近表示,他们正在他们的库中实现它,当这种情况发生时,我将更新这一段。

无论如何,好消息是实现 CQR 非常容易,因为它只需要几行代码。

作为一个例子,我将使用“钻石”数据集,它可以从 Seaborn 包中下载,使用 BSD 许可证。目标是预测每颗钻石的售价(从 326 美元到 18,823 美元不等),特征是钻石的一些特征,如克拉、颜色、长度、宽度、深度等。例如,这些是数据集的前 5 颗钻石:

钻石数据集的前 5 个观察值。[图片由作者提供]

对于这个实验,我将把alpha设置为 5%。

比较 CQR、分位数回归和简单保形预测的性能很有意思。我们可以使用上面看到的代码来获得分位数回归预测(y_test_interval_pred)和 CQR 预测(y_test_interval_pred_cqr)。此外,让我们使用 MAPIE 来获得简单的保形间隔:

from sklearn.ensemble import RandomForestRegressor
from mapie import MapieRegressorestimator = RandomForestRegressor().fit(X_train, y_train)mapie = MapieRegressor(estimator=estimator, cv="prefit").fit(X_cal, y_cal)y_test_interval_pred_mapie = mapie.predict(X_test, alpha=.05)[1].reshape(-1,2)

我们将使用的性能指标非常简单:

  • 误覆盖率,即超出预测区间的测试观测值的百分比。希望该数值尽可能接近用户设定的容差,在这种情况下为 5%。
  • 平均区间长度,区间宽度的平均值。希望间隔的长度尽可能小,因此越小越好。

这些是结果:

比较 MAPIE(简单保形预测)、RandomForestQuantileRegressor(分位数回归)和 CQR。[图片由作者提供]

MAPIE 有许多错误(4.99%),非常接近我们设置的容差(5%),但是间隔的平均长度相当高(2,327.28 美元)。

相反,随机森林分位数回归器产生了紧密的区间(平均为 1,173.41 美元),但这是无用的,因为误差百分比(17.71%)远远高于容差。

CQR 是三个中最好的。事实上,它的误报率(4.98%)非常接近容差(5%),并且与 MAPIE 相比间隔更小(1,763.41 美元对 2,327.28 美元)。

此外,我们已经看到 MAPIE(“prefit”模式)产生等长的间隔,所以在这种情况下,所有预测的间隔正好是 2,327.28 $宽。CQR 怎么样?让我们看看 CQR 得出的区间长度的一些分位数:

CQR 预测的区间长度的一些百分位数。[图片由作者提供]

正如我们所希望的,有一个广泛的可变性,反映了这样一个事实,即时间间隔实际上与每个钻石价格相关的风险成比例。

关于很多数据集的更多例子,可以参考上面提到的斯坦福学者的论文。但是,总的来说,我们展示的结果是一个经验证据,表明 CQR 实际上将最佳的共形预测和最佳的分位数回归结合在一起

感谢您的阅读!我希望你喜欢这篇文章。如果你愿意, 在 Linkedin 上加我

机器学习中如何准备 K 重交叉验证的数据

原文:https://towardsdatascience.com/how-to-prepare-data-for-k-fold-cross-validation-in-machine-learning-924a44ec322c

作者图片

交叉验证是第一个用来避免过度拟合和数据泄漏的技术,当我们想要在我们的数据上训练一个预测模型的时候。

它的功能是必不可少的,因为它允许我们以一种安全的方式对我们的数据进行功能和逻辑测试——也就是说,避免这些过程污染我们的验证数据。

如果我们想做预处理、特征工程或其他转换,我们必须首先正确地划分我们的数据。

这确保了我们的验证数据实际上代表了我们的训练集,并且(可能)也代表了我们还没有的真实世界的数据。

因此,如果我们能够创建一个数据集并对我们的数据进行适当的划分,那么我们就可以相对确定我们从训练中观察到的结果实际上是可用的并且是无偏差的。

如何为交叉验证准备数据

正如我在关于交叉验证以及如何在 Python 中应用它的文章中所写的,其中一个基本步骤是根据折叠(数据集部分)对目标变量进行分层。

这样做是为了防止可能的类不平衡对模型的性能产生负面影响。

例如,在二元分类的情况下,可能 80%的类别是肯定的,而只有 20%是否定的。训练模型而不考虑这种不平衡可能会导致不可靠的结果。

有一些数据平衡技术,但是我们不会在本文中涉及它们。相反,我将解释如何使用 Python、Pandas 和 Sklearn 创建一个带有额外列的数据集,该列将指示数据集中的一行属于哪个文件夹。

对于数据集的每个样本,我们将指出它属于哪个折叠,以便我们可以在每个折叠上测试我们的算法,使我们的评估总体上更加稳健。

让我们看看如何在 Python 中应用这个过程。

让我们从导入基本库开始

import pandas as pd
from sklearn import model_selection

假设我们的训练数据在路径为./data/dataset_train.csv的文件中,让我们用 Pandas 导入它,并创建一个名为 fold 的列,我们用值-1 初始化它。这是因为我们的折叠值将从 0 开始。

# import our training dataset
df = pd.read_csv("./data/dataset_train.csv")

# define a new column named 'fold'
df["fold"] = -1

通常数据集是混洗的——我们使用.sample进行推理。我们将使用参数frac=1告诉 Pandas 获取整个数据集并随机采样。事实上,这将以简单有效的方式打乱数据集的每一行。

df = df.sample(frac=1).reset_index(drop=True)

既然我们已经打乱了数据集,我们可以定义我们的目标变量,将其传递给sklearn.model_selection.StratifiedKFold来对数据集进行分层。我们将使用一个任意的数字 5 作为我们的折叠。

一旦创建了对象,我们就遍历数据集的每一行,并将 Sklearn 生成的部分应用于之前具有常数值-1 的列。

完成后,我们保存数据集。

y = df["target"].values

# we initialize the kfold object with 5 slices
kf = model_selection.StratifiedKFold(n_splits=5)

# populate the fold column
for fold, (train_idx, valid_idx) in enumerate(kf.split(X=df, y=y)):
    df.loc[valid_idx, "fold"] = fold

# save the dataset
df.to_csv("./data/dataset_train_folds.csv")

现在我们有了一个数据集,除了它最初拥有的列之外,现在还有一个额外的列来指示要在其上执行验证的折叠。

让我们看看整个剧本。

import pandas as pd
from sklearn import model_selection

if __name__ == "__main__":

    # import our training dataset
    df = pd.read_csv("./data/dataset_train.csv")

    # define a new column named 'fold'
    df["fold"] = -1

    # shuffle the dataset
    df = df.sample(frac=1).reset_index(drop=True)

    # initialize the target variable y
    y = df["target"].values

    # we initialize the kfold object with 5 slices
    kf = model_selection.StratifiedKFold(n_splits=5)

    # populate the fold column
    for fold, (train_idx, valid_idx) in enumerate(kf.split(X=df, y=y)):
        df.loc[valid_idx, "fold"] = fold

    # save the dataset
    df.to_csv("./data/dataset_train_folds.csv")

现在我们可以运行这个脚本,只需简单地更改数据集在磁盘上的路径,就可以创建一个带有验证折叠的副本

这种方法是完全可扩展的,几乎可以用于任何机器学习问题。

结论

在这篇简短的文章中,我与你分享了一段代码,我可能会在每个机器学习项目中使用

事实上,在即将到来的项目中不使用它对我来说会很奇怪。它适用于传统的机器学习,也适用于深度学习。

一旦数据被分割成多个折叠,我们就可以遍历每个折叠,一次一个折叠地测试我们的假设。这是强大的。

如果您想支持我的内容创作活动,请随时关注我下面的推荐链接,并加入 Medium 的会员计划。我将收到你投资的一部分,你将能够以无缝的方式访问 Medium 的大量数据科学文章。

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

我希望我对你的教育有所贡献。下次见!👋

如何准备大科技数据科学面试

原文:https://towardsdatascience.com/how-to-prepare-for-big-tech-data-science-interviews-aec7a764d8f7

如果你知道如何恰当地准备,大型科技面试就不必令人生畏

泰·高在 Unsplash 上拍摄的照片

可以说,准备大型科技面试最简单的部分是你已经完成的:学习工作所需的技能。

现在到了困难的部分——准备面试本身。

魅力和诱惑的阴云一直笼罩着大型科技公司——想想 Meta(前脸书)、亚马逊、苹果、网飞、Alphabet(前谷歌)等等——难怪许多崭露头角的数据科学家将这些公司作为他们在行业中的第一份工作。

然而,有一种误解认为大型技术面试比一般的面试更难。大多数大型科技公司倾向于采用相同的面试流程,随着候选人素质的变化,面试流程会逐年变化。你听说的困难来自于这些公司比其他公司更有选择性,这导致了高拒绝率。

所以在准备这些面试的时候,你不需要担心被问到一个不可能的问题(除非那天面试官觉得特别辣)。相反,你必须专注于解决技术面试中常见的一系列标准问题,尤其是如何从数百名非常合格的求职者中脱颖而出。

了解现实和竞争格局

大型技术面试准备过程的第一步是对你进入面试过程后将面临的情况有一个清晰的了解。

你很容易被为这些公司工作的梦想分散注意力,包括免费沙拉吧、现场健身房和带狗进办公室的想法。

当你赢得了几场 Kaggle 比赛,做了一些让你所在地区的小企业受益的公益工作时,你也很容易对自己的能力过于自信。

然而,有几件事你需要记住,这样你才能很好地审视面试过程的现实和你将进入的竞争环境。

没有现实世界的问题解决技能,数据科学技能就什么都不是

随着人才库逐年扩大,大型科技公司不得不从能够解决现实世界数据科学问题的候选人中筛选出能够解决数据科学问题的候选人。

你在大学或网上遇到的问题相当干净,有明确的问题要回答,有人帮你找到路,简单的数据集似乎可以自我分析。

相比之下,在一家大型科技公司的技术面试中,你被要求解决的问题将涉及使用你所学的算法、心智模型和解决问题的技能来解决没有明确限制的问题。

你的一些竞争对手可能有多年的行业经验,他们利用这些经验来完善自己的思维过程,这样他们就可以在睡梦中解决这些现实世界的问题。这意味着你必须上升到他们的水平,改变你的思维方式来支持同样的解决问题的能力。

你的竞争对手可能有几年的行业经验和相应的学历

现在好像大家都是本科学历,从五岁就开始编码了。

无论你处于数据科学之旅的哪个阶段,无论是你的第一次大型技术面试还是第六次面试,你的重点都不应该是在纯粹的技能上超越竞争对手(因为让我们面对现实吧,每个人在这个阶段都有天赋),而是应该在你知道自己擅长的领域超越他们。

人们很容易陷入对竞争对手的思考。然而,你无法控制他们的技能,表现,教育,或者过去的经验,这意味着你所能做的就是关注自己。

因此,重点应该是优化你拥有的使你在竞争中脱颖而出的技能,并提炼你与他们共有的技术技能。

如果你要转行,这个过程中最难的部分将是迈出第一步

招聘人员给出的简历不会超过他们的时间 7.4 秒,当你试图改变职业时,很难通过这扇门。

虽然你的简历可以尽可能地面向数据科学领域的工作,但招聘人员可能不会看到重要的潜在细节,即在所有不太相关的工作经历中,你会是一个多么出色的候选人。

招聘过程中弥漫着一定程度的主观性,这意味着同样的公式不会以同样的方式工作两次。这意味着你需要找出向招聘人员传达你资质的最佳方式,并向他们展示(而不是告诉他们)你为什么有资格参加面试。

这里的潜在主题是,要在这个竞争激烈的环境中取得成功,你需要做足功课,弄清楚招聘团队在寻找什么,然后把自己变成他们理想的候选人。

选择您的学习资源

此时,您已经花了几个小时学习数据科学的基础知识。不幸的是,学习并不停留在你可以成功进行数据分析的阶段。

现在,重点是建立心智模型,练习算法,习惯于现实世界的问题解决,并学习如何在做事情的同时传达你正在做的事情。

主要的重点应该是提高你的沟通技巧。互联网上有数百种资源可以帮助你练习构建心智模型、使用算法和解决现实世界的问题。然而,很少有资源可以指导你如何在技术面试中进行交流。

招聘人员正在寻找的是一个能够通过思考过程来解决面试问题的人。虽然许多数据科学家可以低着头坐在电脑前,想出一个有点像样的解决问题的方法,但很少有人能在解决问题时通过他们的思维过程告诉别人。

让候选人脱颖而出的是他们与评估他们的招聘人员恰当沟通的能力。

一旦你决定使用哪些资源来提高你的技能,不管是 Leetcode、Algoexpert 还是 Kaggle,记录下你解决每个问题的过程。这不仅能让你获得完善心智模型、算法使用和解决现实世界问题的经验,还能让你准备好与面试官有效沟通。

招聘人员想知道应聘者是如何思考、推理、分析、解读信息以及与他人合作的。通过大声练习这些技能,你会让你的面试官很好地了解到你会和什么样的人一起工作。

确定你将如何在面试过程中脱颖而出

招聘人员训练有素,能够在一英里之外嗅出谎言。

这意味着,任何参加大型科技面试的人,如果只是为了得到一份工作,而不是真正对这个职位感兴趣,可能会被忽略,而让那些对前景感到兴奋的人优先考虑。

在大型科技面试中脱颖而出的候选人往往会问关于公司最有趣的问题。人们很容易忘记面试是双向的:就像你作为一家新公司的潜在成员接受面试一样,你也应该面试他们,看看为他们工作会是什么样子。通过将你的问题集中在团队和办公室文化上,你会传递出你对为公司工作的兴趣和真诚愿望——更不用说如果一家公司在你的提问后看起来不适合你,你可能会避免一个糟糕的局面。

除了通过问出色的问题让自己脱颖而出,现在是时候确保你能运用简历上列出的每一项技能——尤其是你认为会让你脱颖而出的技能。随着 78%的求职者在招聘过程中撒谎,温习你在简历中列出的所有技能是很重要的。

对于数据科学家来说,可能让你在面试过程中脱颖而出的技能或资产包括商业智能、会说多种语言、高级机器学习或人工智能能力、项目管理技能和创造力。

你可能会注意到,上面列出的许多技能被认为是“软”技能。如上所述,这个阶段的每个人都知道如何编码和进行数据分析。然而,你会惊讶地发现,许多数据科学家并不具备上面列出的许多软技能。对于大型科技公司来说,有晋升潜力的候选人比那些最终会停滞不前的候选人更有价值。

面试计划和策略

现在是你之前所有努力的高潮——计划你的面试策略。

这包括对你在每个大型科技公司可能遇到的不同类型的编码面试有深刻的理解。虽然有些公司是相似的,但其他公司有自己独特的筛选理想候选人的流程。

这个阶段包括准备所有形式的技术和非技术面试,以及了解公司如何组织、运作、计划、配备员工、评估和权衡面试的有限细节。

有了这些信息,你就可以开始计划你的面试策略了。这包括发挥你的长处和短处,这样你就能以最佳状态参加面试。例如,你不希望在你最不警觉的时候安排面试或者连续安排费力的面试而没有休息。

成功的大型科技公司受访者发现,在计划面试时,透明的沟通为他们提供了展示与招聘人员合作和沟通技巧的机会,也让招聘人员知道其他机会可能会增加他们作为候选人的价值。

关键要点

  • 从了解竞争环境的现实开始这个过程——这有助于你清楚地了解你面临的是什么,以及需要准备什么。
  • 选择学习资源,完善你对心智模型、算法、商业智能和编码的使用,也允许你练习交流你的思维过程,以模拟面试过程。
  • 专注于几个将帮助你在竞争中脱颖而出的关键领域——记住,每个人都知道如何在这一点上进行数据分析,所以你应该专注于让你独一无二的软技能或替代资产。
  • 通过彻底了解一家公司如何组织、计划、安排、评估和权衡面试,使用个人策略来计划你的面试,帮助你扬长避短。

订阅将我的故事直接发送到您的收件箱:故事订阅

请成为会员,使用我的推荐链接获得无限制的媒体访问权限(我将收取少量佣金,无需额外费用):媒体会员

如何备考 GCP 专业机器学习工程师考试

原文:https://towardsdatascience.com/how-to-prepare-for-the-gcp-professional-machine-learning-engineer-exam-b1c59967355f

照片由思想目录Unsplash 上拍摄

如何备考 GCP 专业机器学习工程师考试

课程回顾,学习技巧,以及我是如何做到的

所以我决定参加 GCP 专业机器学习工程(PMLE)考试,但我只有两个月的时间来获得足够的认证,使我的公司成为 GCP 的合作伙伴。我知道这将是一个艰难的挑战,但我还是欣然接受了。

在这篇文章中,我将分享帮助我学习和准备考试的东西,以及你不应该浪费时间的东西。阅读像这样的反馈也有助于获得关于考试的不同观点,所以我将从这个伟大的知识库开始,它有许多关于 GCP 和其他认证的帖子。我建议你在开始学习之前先读一读。

像往常一样,这是我的证明:

测试反馈

专业机器学习工程师认证考试被认为是最难的 GCP 认证之一,原因有两个:内容非常广泛,大多数问题都有不止一个正确答案,但只有一个最佳答案。

该测试涵盖了如何使用机器学习技术解决现实世界的商业问题,以及如何在正确的上下文中使用最佳可用解决方案(显然是由 GCP 提供的)。

了解考试涵盖的内容是学习中最重要的部分,因为有了这些信息,你可以在观看课程时专注于什么是重要的。所以你要做的第一件事就是仔细阅读官方 GCP 认证网站。在那里你可以找到考试内容、规则、考试地点和其他重要信息。

另一个很好的起点是做这些由谷歌提供的样题,看看你在测试中会有什么表现。从那里你可以专注于学习,更加关注你不知道的东西。

以往经验推荐

官方考试指南不要求任何先决条件,但是它建议:

3 年以上行业经验,包括 1 年或以上使用谷歌云设计和管理解决方案的经验。

那与我的情况相去甚远。到我参加考试的时候,我已经有了将近一年的云经验(AWS ),而在 GCP 的经验还不到一个月。因此,我将在此给出我对该建议的看法:

岁月不能决定你对某件事了解多少,但有一次有意义的经历可以。在我看来,如果你对任何云都有一些经验,并且了解概念和产品的基础,你就可以开始了。

作为一名机器学习工程师,你需要使用 ML 模型解决问题,为该模型提供数据,并创建持续利用该解决方案产生价值的方法。

在机器学习方面,如果你有建立模型的经验,你将不得不学习得少得多。如果您知道如何区分需要分类、建议或回归模型的问题,并且知道在哪些情况下需要 DNN 或基本线性回归,您将能够使用 GCP 解决方案部分将研究重点放在为模型提供数据和为用户提供预测上。

总结之前的经历部分:

  • 你不需要 3 年以上的经验,但是拥有一些云提供商的经验会节省你学习的时间。
  • 拥有机器学习的经验是必要的,但也足够让你能够使用 ML 来创建商业问题的解决方案。
  • 使用 GCP 的实际操作经验可以通过谷歌提供的一些课程获得,并且足够你参加考试。

如何学习

这项考试的主要知识来源是谷歌设计的一组课程,可在 Coursera 上获得。然而,并不是所有的课程都与考试内容有相同的相关性。这就是为什么我会对它们进行排名,并对下面的每一个进行评论。

首先,在开始上课之前,我有一些值得一提的准备技巧。如果你只关心课程,请随意跳过,但这对我吸收更多相关的东西帮助很大。

学习课程时,你必须记住的主要事情是:

如何使用 GCP 解决方案和 ML 模型解决实际业务问题

你需要了解 GCP 所有的 ML 和数据解决方案,它们是做什么的,它们的优势和劣势是什么,以及每个解决方案的使用案例。

记住:很多问题都可以用不同的方法解决,但结果都很好,测试会一直问你最好的解决方案

所以我有两种方法帮助我在观看课程时了解这些特征:

抽认卡

我使用抽认卡来记住每个解决方案的功能、特点和用例。然后我试着研究了几次,直到我不用看答案就能解释所有的问题。

这是一个非常丰富的技巧,因为你在抽认卡上写了一个简短的解释,锻炼了你总结的能力。然后你试着每隔几天做一次,锻炼你的长期记忆,最后,试着向某人解释一下,看看你是否真的学会了那个概念。

我用过并推荐使用一个免费的抽认卡应用程序。

思维导图

另一个组织主要概念的好方法是创建思维导图。通过这种方式,您可以轻松地将产品和解决方案与业务问题和优势联系起来。

特别是我用了 mind meister ,但是有很多很棒的免费解决方案。

课程

最后,我们来看看谷歌提供的课程及其内容。

备考谷歌云机器学习工程师职业证书

这是准备的主要课程,全神贯注地观看它们是最重要的。

它从 Google Cloud 大数据和机器学习基础 中的一些云基础知识开始,如果你已经在 GCP 使用过数据解决方案,你可以跳过它,否则,你应该这样做,因为它提供了 GCP 数据解决方案的第一视角。这也是仅有的展示数据工程解决方案的课程之一,所以如果你不知道,就去做吧。

第二和第三门课程展示了 GCP 提供的一些 ML 解决方案和 API。记住他们做什么和他们的用例是非常重要的。

第五、第六和第七门课程将深入探讨 ML 解决方案、特征工程和建模产品。

最后三门课程将涵盖如何利用所有最佳实践部署和创建有效的 ML 管道。在我看来,这些才是最重要的课程(生产机器学习系统MLOps 基础、Google Cloud 上的 ML 管道)。

所有这些课程都提供了在真实的 GCP 环境中实施解决方案的实验。它们是学习事物如何工作以及如何设置它们的好方法。

一些实验室会有大的 Jupyter 笔记本,上面有大量的代码。在这些情况下,我的建议是关注代码在做什么,不要担心理解和学习如何自己编码。如果以后你需要自己实现代码,只要去 Google 提供的开放 GitHub 库记住语法就行了。

课程总结:

  • 你应该使用抽认卡、思维导图或其他技术来记住许多关于解决方案的细节。
  • 测试的主要重点是 MLOps 和 ML 管道,但是,不要放弃数据工程知识和机器学习模型特定的问题。
  • 不要关注代码的语法,要关注它的作用和好处。

模拟测试

最后,你做模拟测试。这对于检查你的知识和学习如何阅读问题是至关重要的。

回答问题

这最后一部分决定了你能否通过。考试很大,有 60 道题,120 分钟做,这意味着你每道题有 2 分钟。你必须阅读问题,寻找问题的特征,这将有助于你找到正确的解决方案。我在这里举个例子:

你在一家公共交通公司工作,需要建立一个模型来 估计多条交通路线 的延误时间。预测是 在应用中直接实时提供给用户。 因为不同的季节和人口的增加会影响数据的相关性,你将 每个月重新训练模型 。你想要遵循谷歌推荐的最佳实践。你应该如何 配置预测模型的端到端架构

  • 答:配置 Kubeflow Pipelines,安排从培训到部署模型的多步骤工作流程。
  • B .使用在 BigQuery ML 上训练部署的模型,用 BigQuery 中的调度查询特性触发再训练。
  • C .编写云函数脚本,在 AI 平台上启动由云调度程序触发的培训和部署作业。
  • D .使用 Cloud Composer 以编程方式安排数据流作业,该作业执行从培训到部署模型的工作流。

粗体字是问题最相关的部分。你必须注意细节,比如实时批处理、再训练、部署和架构。最后一点也是最重要的一点,因为他们通常会要求无代码解决方案、无服务器,甚至是对基础架构的完全控制。这将确定解决该特定请求的最佳方案。

在这种情况下,Kubeflow 是唯一能够提供端到端部署和再培训功能的解决方案。所以答案是 a。

另一个好的建议是,在找到问题中最相关的信息后,排除明显错误的答案,这样你就可以有更少的选项来比较。

模拟测试链接

我做了几次模拟测试,但并不完美。所有这些问题都有很多错误答案,但以下是每个问题的链接和评论:

考试题目:这是我做过的最好的模拟考试。网站上没有给出正确的答案,但是,所有的问题都有一个讨论,人们对每种可能性都提出了自己的观点。这是新知识的巨大来源,对我帮助很大。

谷歌样题:既然你已经完成了学习,你应该重温一下你在学习之初做的第一道样题。

还有其他付费备考,但我不能复习,因为我只做了免费的。这些网站通常会提供一些免费的样题,但是我做的那些有着我不同意的奇怪答案。所以你要自担风险。

如果我必须再做一次,我会支付其余的考试题目,并在检查正确答案时只关注讨论。

感谢您的阅读,祝您在成为 GCP 认证专业机器学习工程师的旅途中好运!

如果你想支持我的工作,你可以给我买杯咖啡:

https://www.buymeacoffee.com/cassimiro

如何为生产准备 Scikit-Learn 模型

原文:https://towardsdatascience.com/how-to-prepare-scikit-learn-models-for-production-4aeb83161bc2

利用 FastAPI 和 Docker 服务 scikit-learn 模型

图片来自 Pixabay

介绍

数据科学家花费大量精力收集业务需求,执行探索性数据分析、数据预处理、功能工程、超参数调整和模型评估,结果却让他们的模型停留在本地笔记本电脑环境中。为了释放训练模型的全部价值,模型必须对下游应用程序可用。在本文中,我们将介绍使用 Docker 和 FastAPI 向下游应用程序提供 scikit-learn 机器学习模型的步骤。本质上,我们将训练一个模型,将模型包装成 API,并将应用程序容器化。

Docker 是什么?

Docker 是一个开发、发布和运行应用程序的开放平台。它提供了在松散隔离的环境(称为容器)中打包和运行应用程序的能力。容器是轻量级的,包含运行应用程序所需的一切,因此您不需要依赖主机上当前安装的内容[1]。

什么是 FastAPI?

FastAPI 是一个现代、快速(高性能)的 web 框架,用于基于标准 Python 类型提示使用 Python 3.7+构建 APIs。

本文中的内容按以下顺序涵盖:

  1. 设置
  2. 数据
  3. 项目目录
  4. 火车模型
  5. 使用 FastAPI 创建 API
  6. 本地测试 API
  7. 创建 docker 图像
  8. docker 容器中的测试 API

设置

这是用于演练的设置。

  1. Visual Studio 代码
  2. Docker 桌面
  3. 包装
fastapi>=0.68.0,<0.69.0
pydantic>=1.8.0,<2.0.0
uvicorn>=0.15.0,<0.16.0
numpy==1.23.3
scikit-learn==0.23.2
joblib==1.1.0
pandas==1.4.4

数据

在这个例子中,我们将使用心脏病数据集[3]。任务是在给定患者的各种属性的情况下,预测患者是否患有心脏病。condition是目标变量,其中1表示存在心脏病,0表示不存在心脏病。

作者图片

项目目录

项目目录结构如下:

G:.
│   requirements.txt
│   Dockerfile
│   app.py
|
├───data
│       heart-disease.csv
│
└───model
    │   train.py
    │   heart-disease-v1.joblib
  • [app.py](<http://app.py>):包含 API 逻辑
  • /data:训练数据(heart-disease.csv)保存在该目录下
  • /model:训练好的模型和训练脚本保存在这个目录下
  • [train.py](<http://train.py>) : scikit-learn 模型在这个脚本中被训练
  • Dockerfile:容器化 API 的 Dockerfile
  • requirements.txt:包含 python 包的需求

火车模型

文件名:train.py

为了演示 FasAPI 和 Docker,我们保持培训简单,不包括任何预处理或功能工程。从/data目录中读取数据,用 10 棵树训练一个随机森林分类器。然后,训练好的模型被保存为/model目录中的.joblib文件。

#train.pyfrom os import PathLike
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from joblib import dump
import pandas as pd
import pathlibdf = pd.read_csv(pathlib.Path('data/heart-disease.csv'))
y = df.pop('condition')
X = dfX_train, X_test, y_train, y_test = train_test_split(X,y, test_size = 0.2)print ('Training model.. ')
clf = RandomForestClassifier(n_estimators = 10,
                             max_depth=2,
                             random_state=0)
clf.fit(X_train, y_train)print ('Saving model..')
dump(clf, pathlib.Path('model/heart-disease-v1.joblib'))

创建 API

文件名:app.py

这是大部分活动发生的地方。

导入库

from fastapi import FastAPI
from pydantic import BaseModel
import numpy as np
from joblib import load
import pathlib

创建一个 FastAPI 实例

app = FastAPI(title = 'Heart Disease Prediction')

加载训练好的模型

model = load(pathlib.Path('model/heart-disease-v1.joblib'))

定义请求模型

我们定义 API 所需的输入数据。格式由字段名、数据类型和可选默认值组成。

class InputData(BaseModel):
    age:int=64
    sex:int=1 
    cp:int=3
    trestbps:int=120
    chol:int=267
    fbs:int=0
    restecg:int=0
    thalach:int=99
    exang:int=1
    oldpeak:float=1.8
    slope:int=1
    ca:int=2
    thal:int=2

定义响应模型

我们可以用类似的方式定义响应数据。

class OutputData(BaseModel):
    score:float=0.80318881046519

定义发布请求

@app.post('/score', response_model = OutputData)
def score(data:InputData):
    model_input = np.array([v for k,v in data.dict().items()]).reshape(1,-1)
    result = model.predict_proba(model_input)[:,-1]

    return {'score':result}

上面的代码片段里有很多事情在进行,我们来分解一下。

让我们先来看看@app.post('/score', response_model = OutputData)

  • /score是路线名称。它是 URL 的最后一部分,例如“http://my-url.com/score"”。
  • @app.post表示/score路由接受 post 请求。
  • @app.post('/score')告诉 FastAPI 下面的函数(即def score)负责处理去往/score路线的请求。
  • response_model表示 API 将返回给调用者的格式数据。

@app.post下面我们有score功能。

  • score 函数需要一个data参数,它采用我们之前定义的InputData的格式。
  • score 函数然后解析data并将其转换成一个 numpy 数组
  • 该数组被传递给.predict_proba方法,该方法返回一个介于 0-1 之间的分数。

运行实时服务器

我们可以通过以下方式在本地启动 API。在终端中,在项目根目录下运行:

uvicorn app:app --reload

成功部署的输出如下所示:

INFO:     Will watch for changes in these directories: ['path/to/project']
INFO:     Uvicorn running on <http://127.0.0.1:8000> (Press CTRL+C to quit)
INFO:     Started reloader process [24040] using StatReload
INFO:     Started server process [26612]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

上述代码块中的第二行显示了应用程序被提供的 URL。

自动化 API 文档

基于 API 定义,FastAPI 在 Swagger 和 Redoc UI 中自动生成文档。使用[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs.) 访问 Swagger API 文档。

作者图片

而 Redoc API 文档使用[http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc.)

作者图片

本地测试 API

此时,可以通过 swagger UI、终端或使用 python 来测试 API。

霸气 UI

作者图片

端子

我们可以使用curl通过终端调用 API。score函数所需的data参数通过curl中的-d参数传递。

curl -X 'POST' \\
  '<http://127.0.0.1:8000/score>' \\
  -H 'accept: application/json' \\
  -H 'Content-Type: application/json' \\
  -d '{
  "age": 64,
  "sex": 1,
  "cp": 3,
  "trestbps": 120,
  "chol": 267,
  "fbs": 0,
  "restecg": 0,
  "thalach": 99,
  "exang": 1,
  "oldpeak": 1.8,
  "slope": 1,
  "ca": 2,
  "thal": 2
}'

Python

可以使用 python 的requests包调用 API。score函数所需的data参数通过request.post中的json参数传递。

import requestsbody = {
    "age": 64,
    "sex": 1,
    "cp": 3,
    "trestbps": 120,
    "chol": 267,
    "fbs": 0,
    "restecg": 0,
    "thalach": 99,
    "exang": 1,
    "oldpeak": 1.8,
    "slope": 1,
    "ca": 2,
    "thal": 2
    }response = requests.post(url = '<http://127.0.0.1:8000/score>',
              json = body)print (response.json())
# output: {'score': 0.866490130600765}

创建 Docker 图像

太好了!API 在本地工作。通常,我们可能需要在云环境中部署 API,如 AWS、Azure 或 GCP。实现这一点的方法之一是将您的应用程序容器化。

定义 python 需求

让我们在requirements.txt中定义要求

# requirements.txt
fastapi>=0.68.0,<0.69.0
pydantic>=1.8.0,<2.0.0
uvicorn>=0.15.0,<0.16.0
numpy==1.23.3
scikit-learn==0.23.2
joblib==1.1.0

定义 Dockerfile

#Dockerfile
FROM python:3.8WORKDIR /appCOPY ./requirements.txt ./requirements.txtRUN pip install --no-cache-dir --upgrade -r ./requirements.txtCOPY ./app.py .
COPY ./model ./modelCMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "80"]

does 文件执行以下操作:

  1. 从 Docker hub 获取 python 3.8 图像
  2. 创建一个名为/app的工作目录
  3. requirements.txt复制到工作目录
  4. 安装requirements.txt中定义的软件包
  5. 将代码和模型复制到工作目录中
  6. CMD当容器启动时,在端口 80 上启动服务器

构建 Docker 映像

# at the project root folder
docker build -t fastapiml .

在 Docker 容器中测试

启动码头集装箱

docker run -d --name heart-disease-serving -p 80:80 fastapiml

正在运行的容器将显示在 Docker 桌面中。

作者图片

自动化 API 文档

与之前类似,我们可以使用以下方式访问 API 文档:

  1. 招摇:[http://127.0.0.1/docs](http://127.0.0.1/docs)
  2. Redoc: [http://127.0.0.1/redoc](http://127.0.0.1/redoc)

docker 容器中运行的 API 可以像以前一样以类似的方式进行测试。要么在终端使用 Swagger UI、curl命令,要么使用 python 的requests包。

结论

在本文中,我们讨论了让下游应用程序可以访问机器学习模型的重要性。我们可以通过使用 FastAPI 的 API 来服务这些模型,从而释放机器学习模型的价值。使用 FastAPI 的一个优点是它在 Swagger 中的自动文档,这也允许进行快速测试。我们还演示了如何将 FastAPI 应用程序容器化,从而更容易部署到云中。

加入灵媒阅读更多这样的故事!

参考

[1] Docker 概述| Docker 文档

[2]FastAPI(tiangolo.com)

[3]来自 UCI 机器学习库的心脏病数据集。由 4.0 在 CC 下授权。

作为一名数据分析师如何防止职业倦怠

原文:https://towardsdatascience.com/how-to-prevent-burnout-as-a-data-analyst-1c7c0d9eeffe

一个令人惊讶的简单的个人仪表盘将会创造奇迹!

作为一名数据分析师,您最大的满足感是分析数据,揭示“为什么”以及其他见解,并与业务领导沟通,以适当地转变业务!万岁!

但是这些重大的胜利类似于跑马拉松!需要几天、几周、几个月的迭代数据收集、验证、清理、模型创建、分析、可视化和数据讲述来完成最终目标。

图片来源: unsplash

在这些马拉松比赛中,重要的是让自己保持动力,并确保你不会筋疲力尽!这说起来容易做起来难!

在管理数据分析团队的过程中,我经常看到自我怀疑蔓延到即使是最优秀的人才身上——“我进步不够快”“我对业务的贡献不够。” 马拉松时间越长,战胜自我怀疑,避免倦怠越重要!

我见过的一个非常有效的解决方案是创建你的个人进度仪表板。

个人进度仪表板

只有您可以访问个人进度仪表板(除非您决定共享)。它有三个部分:

  • 产出 KPI:与当月完成的关键任务相关。
  • 时间分配 KPI:通过查看你的日历(或每日时间日志),与你的时间是如何度过的有关。
  • 拦截器 KPI:与重复模式相关,需要您在被拦截时进行上下文切换。

更新和查看仪表板的最佳频率是每月一次——每周一次似乎有点过了,每季度一次又太长,没什么用处。

输出 KPI

仪表板的这一部分重点关注当月完成的任务。目标是简单地捕获所有任务,而不一定是具有业务成果的任务。这些任务通常是战术要求(下午之前需要一份快速营销支出报告)和战略任务(我们之前提到的马拉松)的混合

示例输出 KPI(每月)

  • 完成的数据对话数量 : 使用为业务团队创建的仪表盘/笔记本召开的讲故事会议
  • 更新/标准化的业务指标数量 : 更新/标准化与指标相关的业务逻辑
  • 已完成的临时请求数 : 作为计划外业务团队请求的一部分创建的报告/仪表板/笔记本
  • 、已完成待办任务数 : 已完成计划任务
  • 添加到待办事项中的新业务请求数量:讨论中发现的新业务请求
  • 原型化/更新的数据模型数量 : 创建/更新数据模型/视图
  • :从教程、博客和附带项目中学习新的最佳实践和现代数据堆栈范例**

分析技巧

列出这些任务可以提供一个总体的视角,通常可以解决“我对企业的贡献不够”这一问题分析 KPI 的以下方面:

  • 比较每个 KPI 的 MoM 趋势并思考“为什么”
  • 定义阈值目标,例如您想要完成的数据对话的最小数量,通过在您的每周计划/待办事项列表中跟踪它,使其具有可操作性。
  • 根据 KPI,定义你想多做的任务和不想做的任务。这将帮助你对任务说“不”,或者为你最想完成的任务做更多的志愿者。

时间分布 KPI

仪表板的这一部分需要努力跟踪你在一个月中所花的时间。你可以养成勤勤恳恳地在日历上添加条目的习惯,或者在一天结束时更新每日时间日志。追踪时间从来都不容易,但从长远来看,这绝对是值得的!

示例时间分布 KPI

每月花费在… 上的总时间

  • 计划外请求
  • 更新现有仪表板
  • 调试仪表板/模型/管道
  • 招聘会议
  • 与业务团队
  • 与工程团队一起
  • 指导团队成员
  • 学问

分析技巧

分析花费在以下方面的时间比率:

  • 计划任务与非计划任务
  • 调试仪表板与创建新分析
  • 与业务团队和工程团队的会议时间

在与您团队的整体分析战略保持一致的背景下思考该比率。

拦截器 KPI

对于仪表板的这一部分,请记录您对以下日常任务的体验,评分等级为 1(易于自助服务)到 5(阻碍者):

  • 查找数据集
  • 解释数据集
  • 验证数据集
  • 准备数据集
  • 运行查询
  • 创建数据模型
  • 可视化数据
  • 创建数据故事
  • 操作仪表板/数据模型

分析技巧

跟踪你的系统问题的经验妈妈。该分析可以促使采取行动来提高数据集的质量/文档、数据平台的成熟度、现有工具的现代化需求或针对这些任务的新工具/最佳实践的个人学习。

这里有一些总结技巧,可以让仪表盘上的洞察变得可行,从而提高你的日常效率:

  • 精疲力尽的一个关键原因是当大量的活动没有转化为很大的进步。用阿尔弗雷德·蒙塔佩特的话说:“不要混淆运动和进步。一匹摇马不停地移动,却没有任何进展。”思考仪表板,列出 1-2 个您需要提高活动与进度比率的领域。例如,如果您花费大量时间更新仪表板或调试问题,可能是时候探索更好的技术了。

图片来源: Unsplash

  • 挤出时间来学习——不要把它放在次要位置。现代数据堆栈正在改变我们执行日常分析任务的方式。一些值得注意的范式转变是 ELT (而不是 ETL);分散数据网格;第三方数据的市场反向 ETL用于上下文洞察;度量层将业务定义从 BI 可视化中分离出来;将软件工程原理应用于数据转换;和其他几个人。学习和采用这些范例,尤其是在你的 Blocker KPIs 的背景下,可以帮助提高你的日常效率。
  • 与同事、导师和经理讨论从仪表板分析中获得的见解。这将有助于你发现异常情况(例如,如果你花在工程团队的时间比你的同事多得多),或者与你的经理不一致(例如优先考虑战术任务还是战略任务)。利用您的导师来帮助确定您的 KPI 基准,并在仪表板中设置要跟踪的目标。

总之,作为一名数据分析师,创建一个个人进度仪表板就像一个鞋匠为自己做一双鞋子一样!自省仪表板可以帮助您作为数据分析师显著提高效率!

图片来源: Unsplash

如何防止 Azure 数据块的数据泄露

原文:https://towardsdatascience.com/how-to-prevent-data-exfiltration-from-azure-databricks-c1c55df5c9f2

使用数据块审计日志、日志分析和 Azure Monitor

检测数据泄露—图片由凯文·Ku 在 Unsplash 上提供

1.介绍

Azure Databricks 是企业做数据科学的热门工具。但是,应防止使用数据块来泄漏数据。为此,将为 Azure Databricks 实施一个安全基线网络架构使用 VNET 注入、 安全集群连接Azure AD 条件接收都是实现深度防御的关键。

安全基线的一部分还包括启用审计日志记录。在这篇 blogpost 和 git repo [azure-monitor-detect-exfiltration-databricks](https://github.com/rebremer/azure-monitor-detect-exfiltration-databricks)中,讨论了如何使用 Databricks audit logging 、Log Analytics 工作区中的 kusto 和 Azure Monitor 中的警报规则来防止数据泄露。基本原理如下:

  • 尽管审计日志本身不能保护公司数据失窃,但它可以用来对数据泄漏进行警报和取证。这可以再次用于阻止员工窃取数据(“我们会找到你”)
  • 详细审核日志的设置简单且成本低廉,没有能力设置所有深度防御措施的小型公司也可以使用。

另请参见下面的架构。

1.Azure Databricks 审计日志记录检测泄漏-作者图片

在这篇博文的剩余部分,我们将更详细地解释数据泄漏检测。在第 2 章中,部署了资源并创建了一个简单的警报。在第 3 章中,我们将更详细地讨论 kusto 脚本,并使用 Azure CLI 进行部署。

2.设置数据块数据泄漏检测

在本博客的剩余部分,使用以下步骤部署项目:

  • 2.1 部署资源
  • 2.2 在数据块中启用详细审计日志记录
  • 2.3(可选)使用 Azure 门户创建 Azure Monitor 警报

2.1 部署资源

本教程需要以下资源,并且需要部署这些资源:

2.2 在数据块中启用详细审计日志记录

在此步骤中,启用了 Databricks 中的详细审核日志记录。需要执行以下两个步骤:

  • 配置数据块的诊断日志传送。确保所有日志都归入在 2.1 中创建的日志分析工作区。
  • 在数据块中启用详细审计记录。确保您以 Databricks admin 身份登录,转到 Azure Databricks 管理控制台,单击工作区设置,然后启用详细审计日志****

2.3 (可选)使用 Azure 门户创建 Azure Monitor 警报

在此步骤中,会生成一个简单的警报。在步骤 3.2 中,使用 Azure CLI 部署了完整的 Databricks 渗出脚本,因此可以跳过这一段。需要执行以下步骤:

  • 在 Azure 门户中创建一个新的日志提醒规则。以DatabricksNotebook为查询,以表格行为度量,以 Cound 为聚集类型。作为通知类型,向您自己发送电子邮件。

如果您正确配置了规则,并且在 Databrick notebook 中运行了命令,将在 Databrick notebook 表的日志分析工作区中创建审核日志记录,这将创建一个导致电子邮件的警报。

3.Kusto 数据渗透脚本示例

在本章中,我们将讨论一个数据渗透脚本,然后将其部署到 Azure Monitor。为此,使用了 Azure CLI 脚本。

  • 3.1 解释 Kusto 渗透脚本
  • 3.2 使用 Azure CLI 创建 Azure Monitor 警报

3.1 解释 Kusto 渗透脚本

在脚本[databricksnotebook.kusto](https://github.com/rebremer/azure-monitor-detect-exfiltration-databricks/blob/main/detection/databricksnotebook.kusto)中,使用 kusto 检测到三种不同的数据泄露场景。这些情景可以解释如下:

  • 场景 1。向 dbfs 写入数据:最好不要在 dbfs 上存储数据,参见这里的。这也是因为数据可以通过 dbfs 渗透
  • 场景 2。下载数据集。数据框架可以显示在数据块中,并且是可视化的。还有一个下载按钮,使用户能够在本地存储数据
  • 场景 3:在笔记本中多次显示数据。当使用 display()命令时,只有有限的一组数据被打印到浏览器。然而,用户可以多次执行显示命令,kusto 中窗口可以用于检测这种情况。

场景 2 的示例片段如下所示:

...                         
//                             
// scenario 2: large download
//
let scenario2 = (
DatabricksNotebook
| where ActionName == "downloadPreviewResults" or ActionName == "downloadLargeResults"
| project TimeGenerated, Identity, ActionName, MyJson = parse_json(RequestParams)
| extend type= "scenario 2: large download"                             | project type, TimeGenerated, Identity, ActionName, MyJson.executionTime, notebook_text=MyJson.commandText, count_row=1                             );
...

scenario1a                              
| union scenario1b, scenario2, scenario3a, scenario3b                             | order by TimeGenerated

整个脚本也可以在日志分析工作区中运行进行测试,另请参见下图:

3.1 日志分析工作区中的 Kusto 脚本—按作者分类的图像

3.2 使用 Azure CLI 创建 Azure Monitor 警报

在下面的脚本中,代码被部署 kusto 脚本被部署到 Log Analytics 工作区。

# 0\. Preliminaries
#
# - Chapter 2\. Databricks data exfiltration detection is done# 1\. Set variables
#
$SUB='<<your subscription id>>'
$EMAIL='<<your email address>>'
$LAW_RG='<<your resource group with Log Workspace analytics>>'
$LAW_NAME='<<your Log Workspace Analytics name>>'
$ALERT_GROUP_NAME='dbr_exf_detection_ag'
$ALERT_RULE_NAME='dbr_data_exfiltration'# 2\. Log in
#
az login
az account set --subscription $SUB# 3\. Create Action Group
#
az monitor action-group create -n $ALERT_GROUP_NAME -g $LAW_RG --action email rebremer $EMAIL
$action_id=$(az monitor action-group show -n $ALERT_GROUP_NAME -g $LAW_RG | ConvertFrom-Json).id# 4\. Read Kusto detection file, escape special characters
#
Set-Location deployment
$kusto_script = Get-Content "..\detection\databricksnotebook.kusto" -Raw
$kusto_script = $kusto_script -replace "`r`n", "\n"
$kusto_script = $kusto_script -replace '"', '\"'# 5\. Add Kusto file to ARM template (using ARM params does not work)
#
$arm_data = Get-Content "arm_dbr_exf_script.json.template" -Raw
$arm_data = $arm_data -replace "{dbr_exf_script}", $kusto_script
$arm_data | Out-File -encoding ASCII arm_dbr_exf_script.json# 5\. Create Alert rule using ARM template
#
$law_id="/subscriptions/$SUB/resourcegroups/$LAW_RG/providers/microsoft.operationalinsights/workspaces/$LAW_NAME"
az deployment group create --name AlertDeploymentv4 --resource-group $LAW_RG --template-file arm_dbr_exf_script.json --parameters scheduledqueryrules_dbr_data_exfiltration_name=$alert_rule_name
actionGroups_test_dbrdataexf_ag_externalid=$action_id
workspaces_test_storlogging_law_externalid=$law_id

当一切部署成功时,Azure Monitor 中会创建一个警报规则。

3.2 警报规则成功创建—按作者分类的图像

4.结论

Azure Databricks 是企业做数据科学的热门工具。由于企业通常拥有大量敏感数据,因此应防止数据外泄。应实施 Azure 数据块的安全基线。在这篇 blogpost 和 git repo [azure-monitor-detect-exfiltration-databricks](https://github.com/rebremer/azure-monitor-detect-exfiltration-databricks)中,讨论了如何使用 Databricks 审计日志、日志分析中的 kusto 和 Azure monitor 来扩展安全基线。另请参见下面的架构。

4.Azure Databrisks 审计日志记录检测泄漏-作者图片

如何正确测试您的数据模型

原文:https://towardsdatascience.com/how-to-properly-test-your-data-models-c18b29fcbb61

在表和列中测试的位置和内容

戴维·特拉维斯在 Unsplash 上拍摄的照片

测试是工程世界中最重要的实践之一。在软件工程中,测试可以防止错误进入生产。在数据工程中,测试确保数据被正确地捕获和移动。在分析工程中,它确保您的数据是高质量的,并随时可供业务团队使用。

测试数据模型可以在问题出现在下游模型之前捕捉到数据中的问题。如果没有测试,问题可能几天、几周甚至几个月都不会被发现。我遇到过这样的情况,由于令牌过期,网站后端没有收集数据,导致两周的数据丢失。我也有过由于数据源的模式或数据类型改变而过时的表,导致涉众使用陈旧的数据。测试是确保您对数据保持主动而非被动的唯一方法之一。

作为一项关键的数据治理实践,测试可用于维护高标准,以控制对数据的访问并掩盖客户 PII 信息。这有助于保持数据仓库中的数据安全和准确。

从数据质量的角度来看,源代码和模型级别的测试是覆盖所有基础的关键。当这些测试失败时,设置通知数据集所有者(或任何负责数据质量的人)的警报也很重要。在本文中,我们将讨论好的测试的三个组成部分,以及您想要测试的源和模型的具体属性。

源头测试

在源处进行测试,意味着数据加载到数据仓库的第一点,对于创建一个强大的测试环境是必不可少的。您总是希望测试直接从外部源或摄取工具加载的数据,因为这是您可以捕捉任何问题的最早点。

在第一个数据加载步骤中捕获问题将允许您在问题影响下游数据模型或仪表板之前修复它们。这就像你的水龙头漏水一样——你会想在几滴水后发现它,而不是整个厨房都被淹了。在源代码中进行测试将有助于您做到这一点。

现在,通过测试,你可以看到不同的属性。有些是在表级别,测试将表的特征作为一个整体来看。其他的是列级的,它们查看某一列中的值。让我们逐一讨论一下。

在表级别测试什么

您应该在表级别跟踪的两个主要指标是列数新鲜度

列数

虽然列数是非常基本的,但是加载您期望看到的所有列是很重要的。如果您发现缺少一列,这可能表明您的摄取管道中存在问题,或者外部数据源的模式发生了变化。被提醒丢失的列将允许您在引用丢失的列的下游模型中断之前调查为什么它会丢失。

为了使用 SQL 查找表中的列数,您可以在雪花中运行以下查询:

SELECT COUNT(column_name) AS number_of_columns FROM information_schema.columns WHERE table_name='ad_campaigns'

这将返回表“ad_campaigns”中的列数。您可以使用类似这样的查询来比较实际的列数和预期的列数,并确保数量是相同的。

新鲜

至于新鲜度,这是指表中的数据有多新。如果每天都接收数据,则最新的数据行应该在不超过 24 小时之前接收。如果每周获取数据,则最新的数据行应该在不超过七天前获取。虽然新鲜度取决于组织的需求,但最重要的是桌子的新鲜度符合您的期望。

检查新鲜度最简单的方法是查看最能代表表中一行数据创建时间的时间戳列。例如,对于事件表,这将是event_created_at。对于我们在上面的例子中使用的“ad_campaigns”表,它应该是campaign_created_at。确保这是时间戳列,而不是日期!

现在,您可以通过查看时间戳列中的最新值来了解表有多新。您可以使用以下 SQL 查询来找到它:

SELECT TOP campaign_created_at FROM ad_campaigns ORDER BY campaign_created_at DESC

然后,您可以使用该值来确定该时间和当前时间之间的差异,并将其与您可接受的阈值进行比较。

在列级测试什么

根据列的用途,您应该测试列的几个关键属性。首先,总是测试表中主键的唯一性。主键应该是表中行的唯一标识符。如果它们在一个表中不是唯一的,您可能会遇到意外的重复行或更深层次的问题。

检查这一点的一个简单方法是使用一个简单的计数函数。

SELECT COUNT(campaign_id) FROM ad_campaigns

现在找出不同活动 id 的数量。

SELECT COUNT(DISTINCT campaign_id) FROM ad_campaigns

如果没有重复,计数应该相等。

空值

接下来,您需要测试空值。虽然空值不一定是一件坏事,但是当您需要一个值时,它们就是一件坏事。测试空值将防止您的下游模型产生不正确的结果。NULLs 因搞乱聚合而臭名昭著,所以最好从源头上解决这个问题。

像这样的简单 SQL 查询将为您提供特定列的空值数量:

SELECT COUNT(ad_id) FROM ad_campaigns WHERE ad_id IS NULL

公认的价值观

当值应该映射回映射表中的值时,测试列的可接受值特别有用。例如,“ad_campaigns”表中有一个名为campaign_type_id的列。然后,这个列映射到一个“campaign_types”表,该表有两列:campaign_type_idcampaign_type_name。“ad_campaigns”表中的campaign_type_id列中出现的每个值都必须出现在“campaign_types”表中。

您可以指定该列只接受 1–5 的值,因为这些值是对应映射表中唯一存在的值。如果测试发现campaign_type_id为 6,你就会被提醒去调查。虽然这些问题最初可能不会影响数据质量,但您将开始看到未考虑的值,从而导致数据不正确。

数据类型

最后,检查列的数据类型是否正确。如果列不是预期的数据类型,下游的计算或转换可能会出错。为了对列执行特定的功能,列通常需要某种数据类型。

我还遇到过时间戳列与我预期的时间戳类型不同的问题。令人惊讶的是,这导致了我的 SQL 代码中的比较语句的差异。现在,我总是编写测试来检查列是否是正确的时间戳类型。

测试中间和核心数据模型

中间和核心数据模型是转换源数据的模型。重要的是,不仅要测试源代码,还要测试每个模型。这将帮助您查明错误发生的确切位置。

我经常看到人们在他们的中间模型中省略测试,而只在最终模型中包含它们。这可能会有问题,因为您不知道模型失败的确切时间。在中间模型中添加测试将允许您识别在错误之前通过的最后一个模型,消除了在过程中检查先前模型的需要。

对于分析工程师来说,调试已经是一个巨大的痛苦。测试尽可能小的代码片段将有助于减少调试的麻烦。

对于中间数据模型和核心数据模型,您将希望测试许多与您在源数据中测试的属性相同的属性。在表级别,您应该测试列数和新鲜度。在列级别,测试主键、空值、可接受值和数据类型的唯一性是一个好主意。

主键的唯一性

由于经常使用连接,测试主键的唯一性对于中间和核心模型尤为重要。当在模型的 SQL 代码中使用不正确的连接时,通常会导致创建重复的行。唯一性测试将帮助您发现何时使用了错误的连接,允许您在继续构建模型之前修复它。

行数和列数

如前所述,确保模型中使用正确连接的另一种方法是计算表中的行数和列数。为了更进一步,将这些数字与模型的源表中的数字进行比较。比较模型和源之间的行数将有助于您更好地理解数据是如何转换的。

行之间应该有一对一的关系吗?或者,当连接源表时,是否意味着要创建更多的行?问自己这些问题将有助于你更好地理解你的模型及其目的。这也确保了你测试的质量是正确的。

发信号

如果测试失败时没有人提醒你,测试有什么用?您可以实现任意多的测试,但是如果您没有收到测试失败的通知,您就必须每天手动检查您的模型,不管是否有问题。当决定在您的数据模型上使用的测试类型时,确保您使用那些具有强大警报功能的测试。

我强烈建议寻找具有警告功能的测试。您希望确保您可以设置警报,以便在测试失败时通知正确的人。您还应该确保可以设置提醒,在您最常查看留言的媒体上通知您。

你的团队在哪里来回沟通?你最常看的是什么?

就我个人而言,我总是通过 Slack 和我的团队交流。这是工作日联系我的最佳地点,因此也是发送我的测试警报的最佳地点。

理想情况下,您应该尽可能减少与任何类型的数据质量计划之间的摩擦。你不希望每天都要记得检查产品的用户界面,以确保一切都按预期运行。如果您没有收到警报,您应该能够假设一切都正常工作。

设置警报以通知负责数据质量的人员或拥有特定数据资产的人员也很重要。确保使用该资产最多的团队看到这一点,以便他们可以相应地进行规划。发送给与特定资产没有关联的人的警报基本上是无用的。

例如,如果由于销售团队向数据集添加了新列而导致 Salesforce 集成失败,并且现在您的数据集不符合您在测试中定义的预期,则应通知销售团队解决此问题。

在这种情况下,您将通知数据集的所有者—拥有最多业务上下文的人。您还可以选择通知分析工程师或任何拥有数据质量的人来修复数据集中的问题。我建议两个都报警!

有许多平台可以让你创建提醒,添加描述和标签,以保持它们井井有条。我个人使用 Y42 从一些不同类型的触发器中进行选择,并为您希望得到的警报设置一个规则策略。诸如此类的广泛功能是创建主动数据质量环境的关键。

通过数据测试确保数据质量

当您正确地测试您的源和模型时,当您在上游进行代码更改时,您可以确信下游的数据模型和仪表板是最新的和准确的。这使得团队对他们创造的价值充满信心,并且不害怕做出改变。你知道如果你做了一个错误的改变,你的测试将会失败,并提醒你有一个问题需要解决。

请记住,您需要测试所有不同类型属性的数据,以便清楚地了解数据,并确保数据符合您的预期。正确的测试包括测试列的唯一性、空值、数据类型和可接受值,以及表的新鲜度和计数。实现这些测试是创建高质量数据环境的下一个最佳步骤。

看看我的第一本电子书,分析工程基础知识,一本全方位的分析工程入门指南。

如何用 PyTorch 修剪神经网络

原文:https://towardsdatascience.com/how-to-prune-neural-networks-with-pytorch-ebef60316b91

流行的框架内置了对这一伟大技术的支持,这一技术提高了泛化能力、准确性和推理速度

我一直认为修剪需要单独的模块,但是我最近发现 PyTorch 内置了对它的支持。文档有点缺乏,所以我决定写这篇文章,向你展示一些技巧和窍门!

Wikimedia Commons 上的图片由 Akritasa 提供。作者修改。根据 CC-BY-SA-4.0 获得许可。

什么是修剪?

修剪是一种从神经网络中移除权重或偏差(参数)的技术。如果做得好,这将减少模型的内存占用,提高泛化能力,加快推理速度,并允许用更少的样本进行训练/微调。当然,您不能只是从您的网络中随机删除参数并期望它执行得更好,但是您可以确定哪些参数对您的目标是不必要的并删除它们。不用说,你还应该注意你移除了多少参数:如果你移除了太多,你的网络将会表现得更差,或者如果你阻塞了梯度流(例如,通过从连接层修剪所有参数),你的网络可能会完全失效。

请注意,在训练之后进行修剪是很常见的,一般来说,也可以在训练之前或期间进行修剪。

我应该删除哪些参数?

在前一段中,我有意使用“不必要的”一词来指代可修改的参数。但是是什么使得参数变得不必要呢?这是一个相当复杂的问题,至今仍是一个研究领域。寻找可修剪权重(修剪标准)的最流行的方法有:

  1. Random*: 简单剪枝随机参数。
  2. Magnitude*: 修剪具有最小权重的参数(例如它们的 L2 范数)。
  3. 梯度:根据累积的梯度修剪参数(需要一个反向过程,因此需要数据)。
  4. 信息:利用高阶曲率信息等其他信息进行剪枝。
  5. 学会了:当然,我们也可以训练我们的网络自我修剪(很贵,需要训练)!

*PyTorch 内置了对随机、基于幅度的修剪的支持。这两种方法都出奇地有效,因为它们很容易计算,而且可以在没有任何数据的情况下计算。

修剪的类型

非结构化修剪

非结构化普宁是指修剪参数的单个原子。例如,线性层中的单个权重、卷积层中的单个过滤器像素、自定义层中的一些缩放浮动等。要点是您在没有各自结构的情况下修剪参数,因此命名为非结构化修剪。

结构化剪枝

作为非结构化修剪的替代方法,结构化修剪会删除整个参数结构。这并不意味着它必须是一个完整的参数,但你可以超越删除单个原子,例如,在线性权重中,你可以删除整个行或列,或者,在卷积层中,可以删除整个滤波器(我将感兴趣的读者指向[1],其中我们已经表明,许多公开可用的模型包含一组退化的滤波器,这些滤波器应该是可删除的)。

在实践中,您可以通过非结构化修剪实现更高的修剪率,但这可能不会加速您的模型,因为您仍然需要进行所有的计算。例如,结构化修剪可以修剪整个卷积通道,从而显著降低所需的矩阵乘法次数。目前,有一种趋势是在软件和硬件中支持稀疏张量,因此在未来非结构化修剪可能变得非常重要。

局部与全局修剪

修剪可以发生在每层(局部)或所有多层/所有层(全局)。

PyTorch 中的修剪

PyTorch 中的修剪是如何工作的?

修剪在torch.nn.utils.prune中实现。

有趣的是,PyTorch 不仅仅是简单地将修剪后的参数设置为零。PyTorch 将参数<param>复制到一个名为<param>_original的参数中,并创建一个存储修剪掩码<param>_mask的缓冲区。它还创建了一个模块级的forward_pre_hook(一个在向前传递之前调用的回调函数),将修剪掩码应用于原始权重。

这具有以下结果:打印<param>将打印带有应用掩码的参数,但是通过<module>.parameters()<module>.named_parameters()列出它将显示原始的、未修剪的参数。

这具有以下优点:有可能确定模块是否已经被修剪,并且原始参数是可访问的,这允许对各种修剪技术进行实验。然而,这是以一些内存开销为代价的。

支持哪些 PyTorch 版本?

如果你有 1.4.0 或更高版本,你是好的。

我该如何实施?

支持的选项有点混乱,API 也有点不一致,所以我做了这个概述,希望能澄清一些事情:

py torch 1 . 12 . 1 版支持的修剪技术。图片作者。

局部非结构化剪枝

以下函数可用于本地非结构化修剪:

torch . nn . utils . prune . random _ unstructured(模块,名称,金额)

torch . nn . utils . prune . L1 _ unstructured(模块,名称,金额,重要性分数=无)

只需调用上面的函数,将你的层/模块作为module传递,并将参数的名称传递给name。通常这将是重量偏差amount参数指定要修剪多少。您可以传递一个介于 0 和 1 之间的浮点数作为比率,或者传递一个整数来定义参数的绝对数量。请注意,这些命令可以迭代应用,并且amount始终与剩余(即未删减)参数的数量相关。所以,如果你用amount=0.5反复修剪一个有 12 个条目的参数,第一轮后你会得到 6 个参数,然后是 3 个…

这是一个修剪 40%卷积层权重的示例。请注意 4 个参数是如何设置为零的。

>>> import torch.nn.utils.prune as prune
>>> conv = torch.nn.Conv2d(1, 1, 3)
>>> prune.random_unstructured(conv, name="weight", amount=4)
>>> conv.weight
tensor([[[[-0.0000,  0.0000,  0.2603],           
          [-0.3278,  0.0000,  0.0280],      
          [-0.0361,  0.1409,  0.0000]]]], grad_fn=<MulBackward0>)

由于我们对原子进行操作,所以不支持 L1 规范以外的其他规范。

全局非结构化修剪

如果您想要全局非结构化修剪,命令略有不同:

torch . nn . utils . prune . global _ unstructured(parameters,pruning_method,importance_scores=None,**kwargs)

这里我们需要将parameters作为元组列表传递,这些元组包含要修剪的模块及其参数名。pruning_method=prune.L1Unstuctured似乎是唯一支持的选项。这里有一个来自 PyTorch 文档的例子:

model = ...parameters = (
    (model.conv1, "weight"),
    (model.conv2, "weight"),
    (model.fc1, "weight"),
    (model.fc2, "weight"),
    (model.fc3, "weight"),
)prune.global_unstructured(
    parameters,
    pruning_method=prune.L1Unstructured,
    amount=0.2,
)

如果要修剪特定层类型(例如卷积层)的所有权重,可以按如下方式自动收集它们:

model = ...parameters_to_prune = [
    (module, "weight") for module in filter(lambda m: type(m) == torch.nn.Conv2d, model.modules())
]prune.global_unstructured(
    parameters_to_prune,
    pruning_method=prune.L1Unstructured,
    amount=0.2,
)

当然,您可以根据需要调整过滤器。

局部结构化剪枝

PyTorch 仅支持局部结构化修剪:

torch . nn . utils . prune . ln _ structured(模块,名称,金额,n,dim,importance _ scores =无)

torch . nn . utils . prune . random _ structured(模块、名称、金额、维度)

这些命令与本地非结构化命令非常相似,唯一的区别是您必须定义dim参数。这将定义你的结构的轴。以下是相关维度的助手:

对于torch.nn.Linear

  • 断开一个输入的所有连接:1
  • 断开一个神经元:0

对于torch.nn.Conv2d:

  • 通道(输出一个特征图的内核堆栈):0
  • 神经元(在不同通道中处理相同输入特征图的内核堆栈):1
  • 过滤内核:不支持(需要多轴[2,3]或预先整形,这也不容易)

请注意,与非结构化修剪相反,您实际上可以通过n参数定义使用什么范数。可以在这里找到支持的列表:https://py torch . org/docs/stable/generated/torch . norm . html # torch . norm

下面是一个基于 L2 范数修剪整个通道(在我们的例子中对应于 2 个内核)的例子:

>>> conv = torch.nn.Conv2d(2, 3, 3)
>>> prune.ln_structured(conv, name="weight", amount=1, n=2, dim=0)
>>> conv.weight
tensor([[[[ 0.0000,  0.0000,  0.0000],
          [ 0.0000,  0.0000,  0.0000],
          [ 0.0000, -0.0000, -0.0000]], [[ 0.0000, -0.0000,  0.0000],
          [ 0.0000,  0.0000,  0.0000],
          [ 0.0000,  0.0000, -0.0000]]], [[[ 0.2284,  0.1574, -0.0215],
          [-0.1096,  0.0952, -0.2251],
          [-0.0805, -0.0173,  0.1648]], [[-0.1104,  0.2012, -0.2088],
          [-0.1687,  0.0815,  0.1644],
          [-0.1963,  0.0762, -0.0722]]], [[[-0.1055, -0.1729,  0.2109],
          [ 0.1997,  0.0158, -0.2311],
          [-0.1218, -0.1244,  0.2313]], [[-0.0159, -0.0298,  0.1097],
          [ 0.0617, -0.0955,  0.1564],
          [ 0.2337,  0.1703,  0.0744]]]], grad_fn=<MulBackward0>)

请注意,如果我们删除一个神经元,输出会如何变化:

>>> conv = torch.nn.Conv2d(2, 3, 3)
>>> prune.ln_structured(conv, name="weight", amount=1, n=2, dim=1)
>>> conv.weight
tensor([[[[ 0.0000, -0.0000, -0.0000],
          [-0.0000, -0.0000,  0.0000],
          [-0.0000,  0.0000,  0.0000]], [[-0.1013,  0.1255,  0.0151],
          [-0.1110,  0.2281,  0.0783],
          [-0.0215,  0.1412, -0.1201]]], [[[ 0.0000, -0.0000,  0.0000],
          [ 0.0000, -0.0000,  0.0000],
          [ 0.0000, -0.0000,  0.0000]], [[ 0.0878,  0.2104,  0.0414],
          [ 0.0724, -0.1888,  0.1855],
          [ 0.2354,  0.1313, -0.1799]]], [[[-0.0000, -0.0000, -0.0000],
          [-0.0000, -0.0000,  0.0000],
          [ 0.0000, -0.0000,  0.0000]], [[ 0.1891,  0.0992,  0.1736],
          [ 0.0451,  0.0173,  0.0677],
          [ 0.2121,  0.1194, -0.1031]]]], grad_fn=<MulBackward0>)

自定义基于重要性的修剪

您可能已经注意到,前面的一些函数支持importance_score参数:

torch . nn . utils . prune . L1 _ unstructured(模块,名称,金额,重要性分数=无)

torch . nn . utils . prune . ln _ structured(模块,名称,金额,n,dim,importance _ scores =无)

torch . nn . utils . prune . global _ unstructured(parameters,pruning_method,importance_scores=None,**kwargs)

您可以将一个张量(或global_unstructured的张量列表)传递给那些与您的参数形状相同的函数,并带有您自定义的修剪信息条目。这可作为量值的替代,并为您提供用任何自定义评分来替换它的选项。

例如,让我们实现一种简单的修剪方法,该方法消除了线性层权重张量中的前 5 个条目:

>>> linear = torch.nn.Linear(3, 3)
>>> prune.l1_unstructured(linear, name="weight", amount=5, importance_scores=torch.arange(9).view(3, 3))
>>> linear.weight
tensor([[-0.0000,  0.0000, -0.0000],
        [ 0.0000, -0.0000, -0.1293],
        [ 0.1886,  0.4086, -0.1588]], grad_fn=<MulBackward0>)

助手功能

PyTorch 还提供了几个助手函数。我想展示的第一个是:

torch . nn . utils . prune . is _ prune(模块)

正如您可能已经猜到的,这个函数允许您检查模块中的任何参数是否已经被删除。如果模块被删除,则返回 True。然而,您不能指定要检查哪个参数。

我想展示的最后一个功能是:

torch.nn.utils.prune.remove(模块,名称)

您可能天真地认为这撤销了修剪,但实际情况恰恰相反:它通过删除掩码、原始参数和前向挂钩来应用修剪。最后,将修剪后的张量写入参数。因此,在这样的模块上调用torch.nn.utils.prune.is_pruned(module)将返回 False。

结论

PyTorch 提供了一种内置的方法,可以根据大小或自定义度量对张量随机应用非结构化或结构化修剪。然而,API 有点混乱,文档可以改进。

感谢您阅读本文!如果你喜欢它,请考虑订阅我的更新。如果你有任何问题,欢迎在评论中提出。

参考资料:

[1] P. Gavrikov 和 J. Keuper, CNN 滤波器 DB:训练卷积滤波器的实证研究 (2022),CVPR 2022 Orals

这项工作由德国巴登-符腾堡州科学、研究和艺术部资助,基金号为 32–7545.20/45/1(Q-AMeLiA)。

如何不用写 SQL 查询就能查询 SQL 数据库

原文:https://towardsdatascience.com/how-to-query-sql-databases-without-writing-sql-queries-fad2c06fe1e0

将简单英语中的问题转换成 SQL 查询

鲍比·麦克劳德在 Unsplash 上的照片

介绍

从自然语言生成 SQL 查询的能力可以减少编写精确复杂查询的时间,从而增强精通 SQL 和不精通 SQL 的用户的能力。

作者图片

Ai2Sql 通过 OpenAI 使用 GPT-3 语言模型将简单英语中的问题转换成 Sql 查询。在本文中,我们将了解 Ai2Sql 如何处理各种复杂查询。让我们从使用 Ai2Sql 提供的示例Salary_Payments表开始。该表包含以下列:

  • 身份证明(identification)
  • 员工 id
  • 数量
  • 日期

从简单的英语生成 SQL 语句只需要 4 个简单的步骤。

基本问题

以下问题从单个表中查询。

问题

what is the total salary paid to all employees in the last 3 months?

查询

select sum(amount) from Salary_Payments where date >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH)

答对了。生成的查询汇总了正确的列,并将日期限制为最近 3 个月。

问题

How many employees were paid last month?

查询

select count(*) from Salary_Payments where date between '2019-01-01' and '2019-01-31'

答对了。假设我们现在是在 2019 年 2 月,这个查询将是正确的。

到目前为止,我们一直在查询 Ai2Sql 提供的样本表。让我们通过为 Ai2Sql 提供我们自己的表来使它更具挑战性。我们创建一个新表Sales_Transactions,记录所有雇员的销售交易。该表包含以下列:

  • 身份证明(identification)
  • 员工 id
  • 销售日期
  • 总计 _ 金额
  • 项目代码
  • 项目 _ 描述

问题

What is the total sales in the last month?

查询

select sum(total_amount)
from Sales_Transactions
where sales_date between '2019-01-01' and '2019-01-31'

答对了。假设我们现在是在 2019 年 2 月,这个查询将是正确的。

问题

Which employee has the highest sales amount last month?

查询

select employee_id, sum(total_amount) as total_amount 
from Sales_Transactions 
where sales_date between '2019-01-01' and '2019-01-31' 
group by employee_id
order by total_amount desc 
limit 1

答对了。Ai2Sql 似乎理解Sales_Transaction表的粒度级别。因为表中的每一行都是一个事务,所以在对雇员进行降序排列以找到销售额最高的雇员之前,必须通过对销售额求和来找到每个雇员的总额。

问题

What is the average sales amount per employee in the last month?

查询

select employee_id, avg(total_amount)
from Sales_Transactions 
where sales_date > '2019-01-01' 
group by employee_id

除了日期过滤器之外,一切似乎都没问题。

中级问题

下一个查询需要 Ai2Sql 来计算移动平均值。我们希望找到每月的移动平均销售额。

问题

What is the moving average sales amount?

查询

select avg(total_amount)
from Sales_Transactions
where sales_date between '2019-01-01' and '2019-01-31'

它返回 2019 年 1 月的平均销售额,而不是移动平均值。这个问题被故意措辞模糊。让我们再试一次。

问题

What is the past 12 months rolling average sales amount?

查询

select avg(total_amount)
from Sales_Transactions
where sales_date between date_sub(now(), interval 12 month) and now()

这个查询为我们提供了过去 12 个月的平均销售额,与预期的不太一样,但是我们已经越来越接近了。让我们试着在我们的问题中更具体一些。

问题

What is the 12 months rolling average sales amount for the past 6 months?

查询

select avg(total_amount)
from Sales_Transactions
where sales_date between date_sub(curdate(), interval 6 month) and curdate()

该查询为我们提供了过去 6 个月的平均销售额。很好的尝试,但还没有完全实现。

预先提问

让我们增加一点挑战。我们在Salary_Payments表中添加了几列,现在看起来像这样:

  • 身份证明(identification)
  • 员工 id
  • 部门
  • 标题
  • 数量
  • 日期

以下查询需要连接两个表(Salary_PaymentsSales_Transactions)以产生所需的结果。

问题

Which department had the highest sales amount last month?

查询

select department, sum(total_amount) as total_amount 
from Sales_Transactions 
where sales_date between '2019-01-01' and '2019-01-31' 
group by department 
order by total_amount desc 
limit 1

Ai2Sql 试图从Sales_Transactions中选择department列。然而,该列在所述表中不存在。

让我们用一个更难的问题再试一次。这个问题需要连接两个表和一些数据的上下文。

问题

Which employee did not make any sale in the last month?

查询

select employee_id
from Sales_Transactions
where sales_date < DATE_SUB(CURDATE(), INTERVAL 1 MONTH)

生成的查询提供了上个月至少有一笔销售额的雇员的雇员 id。这与我们的意图相反。

可以回答给定问题的一个可能的查询是识别哪些雇员在上个月从Salary_Payments表中收到了薪水,但是没有出现在Sales_Transaction表中。

让我们问一个在给定的表格中没有答案的问题。

问题

Which employees are married?

查询

select employee_id, first_name, last_name, marital_status
from employees
where marital_status = 'M'

生成的查询从不存在的employee表中读取。

生成问题

Ai2Sql 允许用户生成可以在数据库中查询的问题。下面是产生的一些问题。对于不确定要调查什么业务问题的用户来说,这是一个有用的起点。

1\. What is the total number of transactions?
2\. What is the total quantity sold?
3\. What are the top 10 items most sales?
4\. What are the top 10 items in terms of the quantity sold?
5\. How many transactions were made each day?
6\. How many transactions were made by hour?
7\. What are the top 10 items in terms of revenue?
8\. What are the mean quantity and revenue by date?
9\. What is the mean quantity and revenue by the hour?
10\. What are the mean quantity and revenue by item?
11\. What are the mean quantity and revenue by item per day?
12\. What are the mean quantity

结论

虽然 Ai2Sql 能够为简单的问题生成相当准确的 Sql 语句,但对于需要连接表或更深入地理解数据的复杂问题,仍然有改进的余地。用户可能还会发现用英语表达复杂的问题对于 GPT3 来说是一种挑战。

在当前阶段,在使用 Ai2Sql 时,采取人在循环中的方法将更加实际——人用简单的英语提供一个初始问题,并在使用它们之前验证生成的 Sql 语句。虽然这种方法要求用户具备一定程度的 SQL 能力,但它有助于减少编写 SQL 语句所需的时间,并确保语句的准确性。

  • 加入 Medium 阅读更多这样的故事
  • 关注我获取更多类似的帖子

如何在 Python 中快速匿名化个人姓名

原文:https://towardsdatascience.com/how-to-quickly-anonymize-personal-names-in-python-6e78115a125b

Julian Hochgesang 在 Unsplash 上拍摄的照片。

最终,大多数数据科学家将处理包含个人信息的数据集。个人数据是高度敏感的,此类数据的汇总可能会泄露个人或组织的机密信息。美国联邦贸易委员会(联邦贸易委员会)的保护个人信息指南进一步阐述[1]:

[如果]敏感数据落入坏人之手,可能会导致欺诈、身份盗窃或类似的伤害[导致]失去客户的信任,甚至可能在诉讼中为自己辩护。

联邦贸易委员会保护个人信息指南

因此,未能保护个人数据的数据科学家的职业生涯将会很短暂。幸运的是,Python 中有几个选项可以匿名化姓名并轻松生成虚假的个人数据。遵循下面的示例,并在 链接的 Github 页面 下载完整的 Jupyter 笔记本和代码示例。

场景—考试分数

首先,让我们创建一个场景。假设一位教授有一组最近考试的分数,但他希望在与全班讨论考试趋势时模糊学生的名字。为了方便这个场景,Python 库 Faker 使我们能够生成假数据,以包含名字[2]。生成概念数据集很简单:

# Import Faker
from faker import Faker
faker = Faker()# Test fake data generation
print("The Faker library can generate fake names. By running 'faker.name()', we get:")
faker.name()

这段代码应该提供一个假名字,这个名字会随着每次执行而改变。下面是一个输出示例:

作者截图。

然而,这只能给我们一个名字;要生成一个包含 10 名学生和 10 个随机测试分数的示例数据帧,请运行以下代码:

# Create a list of fake names
fake_names = [faker.name() for x in range (10)]
df = pd.DataFrame(fake_names, columns = ['Student'])# Generate random test scores
import numpy as np
df['TestScore'] = np.random.randint(50, 100, df.shape[0])# Optional - Export to CSV
df.to_csv('StudentTestScores.csv', index=False)

得到的数据帧是:

作者截图。

这将作为学生测试结果数据。对于这个场景,上面随机生成的名字代表学生的真实姓名。

1.通过匿名化实现匿名化 f

AnonymizeDF 是一个 Python 库,能够生成假数据,包括姓名、id、数字、类别等等[3]。下面是一个生成假名字的示例代码块:

# Anonymize DF
from anonymizedf.anonymizedf import anonymize# AnonymizeDF can generate fake names
anon.fake_names("Student")

结果输出是:

作者截图。

AnonymizeDF 还可以创建假的身份证明。下面是一个例子:

anon.fake_ids("Student")

作者截图。

AnonymizeDF 也可以创建类别。这个特性接受列名并给它加上一个数字。下面是一个例子:

anon.fake_categories("Student")

作者截图。

AnonymizeDF 为希望隐藏和匿名用户名的数据科学家提供了一组强大的选项,并且易于使用。但是对于那些寻求其他选择的人来说,还有其他的选择。

2.通过 Faker 匿名

与 AnonymizeDF 类似, Faker 是一个 python 库,它将生成从姓名到地址等范围内的假数据[4]。Faker 非常容易使用:

# Install Faker
from faker import Faker
faker = Faker()Faker.seed(4321)
dict_names = {name: faker.name() for name in df['Student'].unique()}
df['New Student Name'] = df['Student'].map(dict_names)

作者截图。

Faker 还有一些独特的能力,比如创建一个假地址。例如:

print(faker.address())

作者截图。

3.定制的字加扰器

除了使用第三方库,自制解决方案也是一种选择。这些功能包括单词加扰器或用随机单词或数字替换名字的功能。加扰器函数的一个例子如下:

# Scrambler
from random import shuffle# Create a scrambler function
def word_scrambler(word):
    word = list(word)
    shuffle(word)
    return ''.join(word)

使用以下代码将此函数应用于数据帧:

df['ScrambledName'] = df.Student.apply(word_scrambler)
df['ScrambledName'] = df['ScrambledName'].str.replace(" ","")

这会产生以下数据帧:

作者截图。

这种方法有一些限制。首先,事先知道学生姓名的人可以根据打乱的姓名中代表首字母的大写字母推断出谁是谁。第二,这些乱七八糟的字母在外观上不像假名那样干净,也不像假名那样容易理解。进一步的定制可以去除大写字母或生成随机数来代替名字;最合适的选择取决于客户的场景和需求。

4.将所有这些放在一起:匿名化、清理和取消数据框的匿名化

一旦选择了一种技术,将它应用于数据帧、清理帧和存储“密钥”就相当简单了。从一开始就考虑学生考试成绩的原始数据框架:

作者截图。

让我们使用 AnonymizeDF 来创建匿名名称。下面的代码块将:

  • 生成假名。
  • 创建一个包含真实和虚假姓名的 CSV“密钥”。
  • 从原始数据帧中删除真实姓名。
  • 呈现一个干净、匿名的数据框架,在结构上与原始数据框架没有区别。
# Create the Fake Student Names
anon = anonymize(df)
anon.fake_names('Student')# Create a "Key"
dfKey = df[['Student', 'Fake_Student']]
dfKey.to_csv('key.csv')df = df.assign(Student = df['Fake_Student'])
df = df.drop(columns='Fake_Student')

输出是以下数据帧:

作者截图。

解扰这是加载 CSV“密钥”并将原始学生姓名映射到假学生姓名的简单事情:

# Load in the decoder key
dfKey = pd.read_csv('key.csv')# Return to the original Data
df['Student'] = df['Student'].map(dfKey.set_index('Fake_Student')['Student'])

这是它在 Jupyter 笔记本中的样子( 笔记本可在链接的 Github 下载):

作者截图。

结论

数据科学家不可避免地会遇到包含个人信息的数据集,这些信息的保护对于保护个人和组织至关重要。上面强调的简单匿名技术提供了一种快速生成虚假数据作为占位符来保护个人的方法。

但是,对于某些数据集,仅仅匿名化名称可能还不够。诸如地址或个人属性的其他数据点可以允许第三方重建与观察相关联的身份。因此,更复杂的数据集将需要先进的匿名和去识别技术,在某些情况下,合成数据可能是进行分析同时保护个人信息的最佳途径。

参考资料:

[1]联邦贸易委员会,保护个人信息:商业指南 (2016)。

[2] Faker PyPI, Faker 13.0 (2022),Python 包索引。

[3]匿名化 DF,匿名化 df 1.0.1 (2022),Python 包索引。

[4] Faker PyPI, Faker 13.0 (2022),Python 包索引。

如何快速设计先进的 Sklearn 管道

原文:https://towardsdatascience.com/how-to-quickly-design-advanced-sklearn-pipelines-3cc97b59ce16

辅导的

组合 Scikit-Learn 管道中的所有组件,构建定制的生产就绪模型

克林特·帕特森在 Unsplash 上拍摄的照片

本教程将教你如何以及何时使用来自 Sklearn Pipelines 生态系统的所有高级工具来构建定制的、可扩展的、模块化的机器学习模型,这些模型能够轻松部署到生产中。

单独来看,Sklearn Pipelines 工具箱中有许多关于不同组件的内容。我写这篇教程是因为看到所有这些组件如何在一个更复杂的系统中协同工作是非常珍贵的。

我将使用一个具体示例向您展示如何以及何时使用以下组件:

知道如何单独使用它们是很容易的,这也是为什么本教程将会强调何时使用它们以及如何在一个复杂的系统中互换使用

目标

我们将建立一个预测模型来预测下一年的全球平均小麦产量。

主要重点将放在 Sklearn 管道 组件的高级概念上。因此,我们不会在其他数据科学原理上花太多时间。

目录

  • 资料组
  • 管道基础概述
  • 配置
  • 数据准备
  • 建设管道
  • 全球管道。让我们把事情放在一起。
  • 如何使用全球管道

注:如果你只对 Sklearn 管道的高级主题感兴趣,直接跳到构建管道。

资料组

我们使用的是由 Pangaea 提供的公开可用的数据集【1】,该数据集跟踪了从 1981 年到 2016 年各种植物的全球历史年产量。

我们使用这个 GitHub 库找到了数据集。查看更多精彩的公开数据集。

数据集提供了多种类型的作物,但在本例中,我们将只使用小麦。

全球小麦年产量和泛大陆数据集内提供的位置数量[图片由作者提供]。

管道基础概述

这里有一个 Sklearn Pipelines 生态系统使用的主要原则的简短提示。

一切都围绕着管道对象。

一个管道包含多个估算器

一个估算器可以具有以下属性:

  • 从数据中学习→使用 fit() 方法
  • 转换数据→使用 transform() 方法。也被称为变压器(不,不是机器人,它是估计器子类)。
  • 从新数据预测→使用 predict() 方法。也称为预测器

注 1: 我们可以拥有没有 fit() 方法的变形金刚。因此,这些类没有参数化,并且遵循纯函数的原则。通常,这些类型的转换器在进行特征工程时很有帮助(例如,在使用 fit() 方法之前,我们无需学习任何东西就可以将两个不同的列相乘)。

注 2:****管道对象继承了管道中最后一个估算器的方法。

注 3: 如果你想给你的管道添加一个模型,它必须是最后一个元素。我将向您展示如何使用TransformedTargetRegressor对模型预测执行后处理操作的技巧。

配置

将管道呈现为图表

通过将 Sklearn 配置的显示设置为“ diagram,”,我们可以快速将管道可视化为图表。

Sklearn 管道图可视化示例【图片由作者提供】。

常数

下面我们将定义一些在代码中使用的常量。

数据准备

挑选事实真相

因为时间序列预测是一种无监督学习的形式,我们必须使用过去的信息来预测 tₙ的一个数据点。因此,在开始时,我们将把特征和标签作为相同的时间序列。但是在预处理步骤中,我们将使用特征作为过去的数据点,使用标签作为我们想要预测的数据点。

这不是一个时间序列预测帖子。所以,这一步不要想多了。还有,你不用一行一行的读代码。

只需聚焦在大图管道步骤上。了解如何以及何时使用特定 Sklearn 组件的最终目标就足够了。

X, y = yields.copy(), yields.copy()

分割数据:培训和测试

现在,我们将在训练和测试之间拆分数据。您将看到正确使用 Sklearn 管道在新数据上使用您的模型是多么容易。

让我们看看火车测试分裂看起来如何:

*(Starting year of the split, Ending year of the split, number of years within the split)***X_train.index.min(), X_train.index.max(), X_train.index.max() - X_train.index.min() + 1**(1981, 2012, 32)**y_train.index.min(), y_train.index.max(), y_train.index.max() - y_train.index.min() + 1**(1986, 2012, 27)**X_test.index.min(), X_test.index.max(), X_test.index.max() - X_test.index.min() + 1**(2007, 2016, 10)**y_test.index.min(), y_test.index.max(), y_test.index.max() - y_test.index.min() + 1**(2012, 2016, 5)

建设管道

说够了。让我们开始实现实际的管道。

全局管道分为以下子组件:

  1. 平稳性管线(用于特征目标
  2. 特色工程管道
  3. 回归器管道
  4. 目标管道

1.平稳流水线

流水线用于时间序列,使其保持平稳。更具体地说,它将消除周期性,并对不同时间的平均值和方差进行标准化。你可以在这里阅读更多相关内容。

在这一步中,我们将向您展示如何使用以下内容:

我们可以用两种方式来构建管道估算器:

1️⃣继承了 BaseEstimator + TransformerMixin。使用这种方法,管道单元可以从数据中学习,转换数据,并反转转换。以下是受支持接口的简短描述:

  • fit(X,y) —用于从数据中学习
  • transform(X) —用于转换数据
  • fit_transform (X) —学习并转换数据。该函数继承自 TransformerMixin
  • inverse_transform(X) —用于反向变换

注 1: 此语句始终成立:x = = inverse _ transform(transform(x))—接受小容差。

注 2: 目标(如 y)只在 fit()方法中传递。至于 transform()和 inverse_transform(),仅给出特征(例如,X)作为输入。此外,我们不能强制管道访问任何其他属性。

2️⃣编写了一个纯函数,最终被 FunctionTransformer 封装。

当转换不需要有状态(它没有 fit()方法),也不需要对转换进行逆变换(它没有 inverse_transform()方法)时,这种方法是实用的。因此,当您只需要实现 transform()方法时,这很有用。

这必须是一个纯函数(对于输入 A,你总是得到输出 B →它不依赖于外部上下文)。否则,当您的管道变大时,您会遇到奇怪的行为。

注意: 因为我们只实现了一个转换,所以我们只能访问特性(例如 X)。我们无法访问任何其他属性。

作为观察,我们选择为转换编写一个类,即使它不需要实现 fit()方法(例如 LogTransformer)。但是,将转换及其逆转换打包到同一个结构中是一个很好的软件实践。

我们利用 Python functools 模块中的部分函数来配置转换。

如前所述,赋予 FunctionTransformer 的函数应该只接受一个输入,只输出一个值。还有,在构造函数里面配置它不是一个类。因此,使用 partial,我们可以只设置一个函数参数的子集。它将结束我们的初始函数,并在下一次调用时返回另一个函数,该函数只需要未在部分中指定的参数作为输入。

最后,让我们建立管道。我们使用了 make_pipeline() 实用函数,它自动命名每个管道步骤。

stationary_pipeline 的示意图[图片由作者提供]。

以下是如何快速检查您的转换和 inverse_transformation 是否正确执行的方法:

使用 np.allclose(),我们通过接受一个小错误来检查等式。

时间序列经过静态管道处理后的样子示例[图片由作者提供]。

2.特色工程管道

现在让我们做一些特征工程。

注意,你不必理解每个函数的实现。关注结构

对于大多数转换,我们使用了纯函数 + FunctionTransformer 。我们使用这种方法是因为我们对实现 fit()inverse_transform() 不感兴趣。因此,使用这种方法,我们的代码更加简洁。

只有 DropRowsTransformer 是用类实现的,因为它同时需要 fit()inverse _ transformer()

从我的经验来看,在实现数据和特征工程管道时,我通常发现函数转换器更有用、更干净。我不认为继承类并让大多数方法为空是好的做法。

现在让我们进入甜蜜部分,在这里我们将使用:

使用make _ column _ transformer,我们可以在子集上运行不同的操作/流水线。在这个具体的例子中,我们对“mean _ yield”和“locations”列运行了不同的转换。这个操作器的另一个好处是,它为平行中的每一组运行操作。因此,并行计算“mean _ yield”“locations”的特征。

使用 make_union ,我们可以计算平行中的多重特征。在本例中,对于“ mean_yield,”,我们并行计算四个不同的特征:

  • 过去的观察
  • 移动平均数
  • 移动标准偏差
  • 移动中位数

注 1: 同样的原理也适用于“位置”特征。

注 2: 我推荐使用 make_[x] 效用函数。这会让你的生活更轻松。

在下面的代码片段中,您可以看到这些组件的运行。遵循 Sklearn 管道范例,看看我们如何很好地重用了管道中的大多数功能。

另一个基本元素是 memory= "cache" 属性。使用它,所有的步骤都被缓存在本地磁盘上。因此,如果您的输出在新运行时被缓存,它将自动从缓存中读取结果。如果发生变化,它还知道何时使缓存无效。

现在,用最少的努力,通过并行运行所有的转换并缓存管道的输出,你的机器学习管道将会非常快。

特征 _ 工程 _ 管线图。请注意,在笔记本中,图表是交互式的。你有一个下拉菜单,显示每个管道单元的更多细节。

让我们在我们的培训功能上运行功能 _ 工程 _ 管道:

feature_engineered_yields = feature_engineering_pipeline.fit_transform(X_train.copy())

由 feature _ engineering _ pipeline[Image by Author]计算的训练特征。

现在让我们在我们的测试功能上运行它:

feature_engineering_pipeline.transform(X_test.copy())

3.回归器管道

下面你可以看到如何建立最终回归。除了上面介绍的feature _ engineer _ pipeline之外,我们还堆叠了一个缩放器和一个随机森林模型。

您可以观察到模型是添加到管道中的最后一个单元。

4.目标管道

target_pipeline 用于预处理标签和后处理模型的预测

一切都会在一瞬间变得有意义。

全球管道。让我们把事情放在一起。

这里我们将向您展示如何使用TransformedTargetRegressor组件。

TransformedTargetRegressor类采用以下参数:

  • 回归器:将上面定义的回归器 _ 管道作为输入。我们习惯在大多数管道中使用的东西。
  • transformer:target_pipeline 作为输入,后者将预处理标签,当使用管道中定义的 fit()transform() 方法时,模型将使用这些标签作为基础事实。还有,做预测的时候会后处理模型的输出调用inverse _ transform()多牛逼啊?最后,将所有步骤打包成一个逻辑单元的方法。

整个管道的示意图。随着管道变得更加复杂,一个好的可视化将永远是你的朋友[图片由作者提供]。

如何使用全球管道

火车

现在,培训步骤只是一行程序。

pipeline.fit(X=X_train.copy(), y=y_train.copy())

做预测

最棒的是做预测;你还必须打电话给一个俏皮话。调用pipeline . predict(X)就是这样。你有你的预言。

使用 TransformedTargetRegressor,调用 predict 时,预测已经被转换回其初始比例。因此,模型/管道高度紧凑,易于在各种场景中部署:批处理、API、流式、嵌入式等。

另一个有用的特性是,您可以在您的特征和模型上快速使用 GridSearch(或其他技术)。现在,您可以将数据管道中的不同配置视为超参数。因此,您只需几行代码就可以快速体验各种特性。

**y_pred = pipeline.predict(X_test.copy())
y_pred**26    4.026584
0     4.122576
1     4.080378
2     4.174781
3     4.380293
Name: 0, dtype: float64

试验

为了好玩,让我们使用传统的 RMSEMAPE 指标来评估这个模型。

**evaluate(y_test, y_pred)**INFO:sklearn-pipelines:RMSE: 0.147044
INFO:sklearn-pipelines:MAPE: 0.030220

我们可以观察到,它使用一个简单的模型做得很好,根本没有任何微调。在大约 4.0 的范围内,大约 0.13 的 RMSE 已经很不错了。

但是正如几次提到的,本教程是关于利用 Sklearn 管道,而不是建立一个精确的模型。

结论

如果你已经走了这么远,那你就太棒了。现在你知道如何编写专业的 Scikit 管道了。谢谢你看我的文章!

通过一个具体的例子,我们展示了利用 Sklearn 管道及其整个组件堆栈的强大功能:TransformerMixin、BaseEstimator、FunctionTransformer、ColumnTransformer、FeatureUnion、TransformedTargetRegressor。

使用这种方法,我们构建了一个灵活的机器学习管道,我们可以:

  • 轻松地重用转换,并以各种方式组合它们(模块化代码)。
  • 编写干净的、可伸缩的类。
  • 编写高速代码,并行计算所有特性,并缓存整个管道中的中间检查点。
  • 将模型作为简单的类直接部署,无需进一步的预处理/后处理步骤。
  • 对特征/数据管线和模型本身快速执行超参数调整。

关于 Sklearn 管道,你还知道哪些隐藏的宝石?

你可以在我的 GitHub 上找到教程中使用的例子的完整实现。在这个库中,我将不断地推送我将用来撰写各种文章的所有示例。

参考

[1] Iizumi,Toshichika,全球历史收益率数据集 v1.2 和 v1.3 对齐版本。盘古大陆 (2019),补充:饭泉,土肥猪;Sakai,【1981 年至 2016 年 (2020 年)全球主要农作物历史产量数据集,科学数据

如果你喜欢读我的文章,你可以在 LinkedIn 上关注我,了解关于 ML、MLOps 和自由职业者的每周见解。

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

posted @ 2024-10-18 09:29  绝不原创的飞龙  阅读(194)  评论(0)    收藏  举报